From f33727604d0974793b36b523c4e3deba41e44098 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 08:35:27 +0200 Subject: [PATCH 0001/2474] Drop caltrops instantly with gren1/gren2 commands (Fixes #54) --- tfort.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 28837928..aeddc910 100644 --- a/tfort.qc +++ b/tfort.qc @@ -452,8 +452,13 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { if ((self.tfstate & TFSTATE_GRENPRIMED) || (self.tfstate & TFSTATE_GRENTHROWING)) TeamFortress_ThrowGrenade(); - else + else { TeamFortress_PrimeGrenade(inp); + + if ( ((inp == 2 && self.tp_grenade_switch != 1) || (inp == 1 && self.tp_grenade_switch == 1)) + && self.tp_grenades_2 == 10) + TeamFortress_ThrowGrenade(); + } }; void (float inp) TeamFortress_PrimeGrenade = { From 84f121b3573c7bb3df27f58205d147e840f5e149 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 10:09:55 +0200 Subject: [PATCH 0002/2474] Don't show team menu when observing (Fixes #55) --- menu.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/menu.qc b/menu.qc index 8b0d60f7..e2c8730c 100644 --- a/menu.qc +++ b/menu.qc @@ -94,6 +94,9 @@ void (float inp) Menu_Input = }; void (float inp) Menu_Team_Input = { + if (self.classname == "observer") + return; + if (inp == 0) { return; } if (inp == 5) { @@ -118,6 +121,9 @@ void () Menu_Team = { local string t2, t3, t4; local string ta = "\n—‘ Automatically assign team"; + if (self.classname == "observer") + Status_Menu(self, Menu_Team_Input, ""); + local float t1_players = TeamFortress_TeamGetNoPlayers(1); local float t2_players = TeamFortress_TeamGetNoPlayers(2); local float t3_players = TeamFortress_TeamGetNoPlayers(3); From 3d1e44303f058c67af8dc3c510c2fd246e8b10ac Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 11:28:55 +0200 Subject: [PATCH 0003/2474] Increase sniper rifle range (fixes #42) --- weapons.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index 6ced029f..7e6262e8 100644 --- a/weapons.qc +++ b/weapons.qc @@ -787,7 +787,7 @@ void () W_FireSniperRifle = { src_z = self.absmin_z + self.size_z * 0.7; use_this = FALSE; - traceline(src, src + dir * 8092, FALSE, self); + traceline(src, src + dir * 9192, FALSE, self); if (trace_fraction != 1) if (trace_ent != world) if (trace_ent.classname == "player") @@ -797,7 +797,7 @@ void () W_FireSniperRifle = { if (!use_this) { dir = aim(self, 10000); - traceline(src, src + dir * 3072, 0, self); + traceline(src, src + dir * 9192, 0, self); } deathmsg = DMSG_SNIPERRIFLE; dam_mult = 1; From 03cebfbc52323018af8aaee4408279ce7c32d321 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 11:32:28 +0200 Subject: [PATCH 0004/2474] Make grenade sound private (fixes #57) --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index aeddc910..7ae3f00f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -441,7 +441,7 @@ void () GrenadeTimer = { Status_Refresh(self.owner); if (self.heat > 0) { - sound(self.owner, CHAN_AUTO, "zombie/z_fall.wav", 1, ATTN_STATIC); + stuffcmd(self.owner, "play zombie/z_fall.wav\n"); self.nextthink = time + 1.0; } else { dremove(self); From 41009f4b598b193ee2a11c676ebe42739afd324b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 3 Jul 2014 14:17:22 +0200 Subject: [PATCH 0005/2474] Stop printing weapon messages on menu open (fixes #51) --- weapons.qc | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/weapons.qc b/weapons.qc index 7e6262e8..a1e61351 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2097,28 +2097,30 @@ void (float inp) W_ChangeWeapon = { self.impulse = 0; - if (self.noammo == 1) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } else if (self.noammo == 2) { - sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); - return; - } + if (inp != 5) { + if (self.noammo == 1) { + sprint(self, PRINT_HIGH, "Not enough ammo\n"); + return; + } else if (self.noammo == 2) { + sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); + return; + } - if (self.current_weapon != self.next_weapon - || self.weaponmode != self.next_weaponmode) { - self.last_weaponmode = self.weaponmode; - self.last_weapon = self.current_weapon; - self.current_weapon = self.next_weapon; - self.weaponmode = self.next_weaponmode; - } + if (self.current_weapon != self.next_weapon + || self.weaponmode != self.next_weaponmode) { + self.last_weaponmode = self.weaponmode; + self.last_weapon = self.current_weapon; + self.current_weapon = self.next_weapon; + self.weaponmode = self.next_weaponmode; + } - if (self.current_weapon != self.last_weapon - || self.weaponmode != self.last_weaponmode) - W_PrintWeaponMessage(); + if (self.current_weapon != self.last_weapon + || self.weaponmode != self.last_weaponmode) + W_PrintWeaponMessage(); - W_SetCurrentAmmo(); - Status_Refresh(self); + W_SetCurrentAmmo(); + Status_Refresh(self); + } }; void () CycleWeaponNext = { @@ -2185,10 +2187,7 @@ void () ImpulseCommands = { } if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { - if (((self.impulse >= 1) && (self.impulse < 8)) || - (self.impulse == TF_MEDIKIT)) - W_ChangeWeapon(self.impulse); - else if (self.impulse == AXE_IMP) + if (self.impulse >= 1 && self.impulse <= 5) W_ChangeWeapon(self.impulse); else if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); From d7f5c91719bdb5e1889f3cebb3276232bbd265a1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 11:53:18 +0200 Subject: [PATCH 0006/2474] Fix weapon cooldown bug (fixes #45) --- weapons.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index a1e61351..4b5fdff6 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2436,8 +2436,6 @@ void () W_WeaponFrame = { } if (intermission_running) return; - if (self.impulse != 0 && self.has_disconnected == 0) - ImpulseCommands(); if (cease_fire) return; if ((self.is_building != 0 || self.is_detpacking != 0) @@ -2488,6 +2486,9 @@ void () W_WeaponFrame = { if (time < self.attack_finished) return; + if (self.impulse != 0 && self.has_disconnected == 0) + ImpulseCommands(); + if ((!self.button0 && self.fire_held_down) && (self.current_weapon == 32768)) { self.fire_held_down = 0; From f03e69b2732e029a2ea38e2dbf4833a36d476fa9 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 12:40:40 +0200 Subject: [PATCH 0007/2474] Allow engineers and demomen to throw grenades while building/detpacking --- weapons.qc | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/weapons.qc b/weapons.qc index 4b5fdff6..b463a6cd 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2186,6 +2186,17 @@ void () ImpulseCommands = { TeamFortress_SpyGoUndercover(); } + if (!self.is_feigning) { + if (self.impulse == TF_GRENADE_1) + TeamFortress_PrimeGrenade(1); + else if (self.impulse == TF_GRENADE_2) + TeamFortress_PrimeGrenade(2); + else if (self.impulse == TF_GRENADE_PT_1) + TeamFortress_PrimeThrowGrenade(1); + else if (self.impulse == TF_GRENADE_PT_2) + TeamFortress_PrimeThrowGrenade(2); + } + if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { if (self.impulse >= 1 && self.impulse <= 5) W_ChangeWeapon(self.impulse); @@ -2195,14 +2206,6 @@ void () ImpulseCommands = { CycleWeaponPrev(); else if ((self.impulse == TF_WEAPLAST) && (self.last_weapon != 0)) W_ChangeWeapon(self.impulse); - else if (self.impulse == TF_GRENADE_1) - TeamFortress_PrimeGrenade(1); - else if (self.impulse == TF_GRENADE_2) - TeamFortress_PrimeGrenade(2); - else if (self.impulse == TF_GRENADE_PT_1) - TeamFortress_PrimeThrowGrenade(1); - else if (self.impulse == TF_GRENADE_PT_2) - TeamFortress_PrimeThrowGrenade(2); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); else if (self.impulse == TF_DETPACK_5) @@ -2428,18 +2431,21 @@ void () W_WeaponFrame = { Menu_Class(); return; } + + // grenade impulses always possible + if (self.impulse >= 150 && self.impulse <= 155) { + ImpulseCommands(); + return; + } + if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 9) { Menu_Input(self.impulse); return; } } - if (intermission_running) - return; - if (cease_fire) - return; - if ((self.is_building != 0 || self.is_detpacking != 0) - || self.is_feigning != 0) + + if (intermission_running || cease_fire) return; default_fov = stof(infokey(self, "df")); From 7276efe79a8f94fe13bb24c187bfd31b72423776 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 12:41:04 +0200 Subject: [PATCH 0008/2474] Remove some useless sniper weapon code --- sniper.qc | 25 ------------------------- weapons.qc | 1 - 2 files changed, 26 deletions(-) diff --git a/sniper.qc b/sniper.qc index f05b6eef..c2c3e6e2 100644 --- a/sniper.qc +++ b/sniper.qc @@ -2,31 +2,6 @@ // Functions for the SNIPER class and associated weaponry //======================================================== -void () SniperSight_Update; - -void () TeamFortress_SniperWeapon = { - self.impulse = 0; - if (self.tfstate & TFSTATE_RELOADING) - return; - - if (! - ((self.weapons_carried & WEAP_SNIPER_RIFLE) && - (self.weapons_carried & WEAP_AUTO_RIFLE))) - return; - - if (self.ammo_shells < 1) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } - - if (self.current_weapon == WEAP_SNIPER_RIFLE) - self.current_weapon = WEAP_AUTO_RIFLE; - else - self.current_weapon = WEAP_SNIPER_RIFLE; - - W_SetCurrentAmmo(); -}; - void (float zoom_to) TF_zoom = { local float default_fov; local float default_sensitivity; diff --git a/weapons.qc b/weapons.qc index b463a6cd..23a9711c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -25,7 +25,6 @@ void (float messageno) TeamFortress_Message; void () TeamFortress_ShowIDs; void () TeamFortress_ShowTF; -void () TeamFortress_SniperWeapon; void () TeamFortress_AssaultWeapon; void () TeamFortress_IncendiaryCannon; void () TeamFortress_FlameThrower; From 04464e13b97046395a768038c9b68ecaac2dfa9b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 13:30:25 +0200 Subject: [PATCH 0009/2474] Make impulse 1-5 + weapnext + weaplast cancel building (closes #58) --- weapons.qc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index 23a9711c..4475d113 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2179,8 +2179,6 @@ void () ImpulseCommands = { UseSpecialSkill(); if (self.impulse == TF_WEAPLAST) { - if (self.playerclass == PC_ENGINEER && self.is_building == 1) - TeamFortress_EngineerBuildStop(); if (self.playerclass == PC_SPY && self.is_undercover == 2) TeamFortress_SpyGoUndercover(); } @@ -2196,6 +2194,17 @@ void () ImpulseCommands = { TeamFortress_PrimeThrowGrenade(2); } + if (self.is_building == 1) { + if (self.impulse >= 1 && self.impulse <= 5) { + TeamFortress_EngineerBuildStop(); + } else if (self.impulse == TF_WEAPNEXT + || self.impulse == TF_WEAPPREV + || self.impulse == TF_WEAPLAST) { + TeamFortress_EngineerBuildStop(); + self.impulse = 0; + } + } + if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { if (self.impulse >= 1 && self.impulse <= 5) W_ChangeWeapon(self.impulse); From f69d51640769cf279ef89d0aefb132280b89c985 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 20:39:53 +0200 Subject: [PATCH 0010/2474] Fix so Engineer can no longer move while building (fixes #61) --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 7ae3f00f..0180f0a8 100644 --- a/tfort.qc +++ b/tfort.qc @@ -839,7 +839,7 @@ void (entity p) TeamFortress_SetSpeed = { local entity te; stuffcmd(p, "cl_movespeedkey 1\n"); - if (p.tfstate & TFSTATE_CANT_MOVE) { + if (p.tfstate & TFSTATE_CANT_MOVE || p.is_building == 1) { #ifdef STOP_MOUSE_MOVEMENT stuffcmd(p, "m_forward 0\n"); stuffcmd(p, "m_side 0\n"); From e37a51de709237f00bc3e29ad1599787b9f21ef4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 7 Jul 2014 01:09:19 +0200 Subject: [PATCH 0011/2474] Kill grenade timer on death (fixes #60) --- client.qc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/client.qc b/client.qc index 270869e3..bfe64d18 100644 --- a/client.qc +++ b/client.qc @@ -1914,9 +1914,24 @@ void (entity targ, entity attacker) ClientObituary = { local float rnum; local string deathstring; local string deathstring2; + local entity timer; deathstring = ""; deathstring2 = ""; + if (self.StatusGrenTime > 0) { + timer = find(world, classname, "gtimer"); + while (timer != world) { + if (timer.owner == self) { + dremove(timer); + timer = find(world, classname, "gtimer"); + } else { + timer = find(timer, classname, "gtimer"); + } + } + self.StatusGrenTime = 0; + Status_Refresh(self); + } + TF_zoom_reset_death(targ); rnum = random(); From 4402e8d4cb043f50fa35d28911de822e63ce5076 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 7 Jul 2014 01:09:44 +0200 Subject: [PATCH 0012/2474] Make sniper zoom independent of weapon cooldown (fixes #59) --- weapons.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index 4475d113..e48cc7b4 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2440,8 +2440,9 @@ void () W_WeaponFrame = { return; } - // grenade impulses always possible - if (self.impulse >= 150 && self.impulse <= 155) { + // grenade impulses + sniper zoom always possible + if ((self.impulse >= 150 && self.impulse <= 155) + || (self.playerclass == PC_SNIPER && self.impulse == TF_SPECIAL_SKILL)) { ImpulseCommands(); return; } From 6638c270a65e0156d61dcd587ebe8f4597588739 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 15 Jul 2014 16:54:51 +0200 Subject: [PATCH 0013/2474] Add map voting --- client.qc | 8 + defs.h | 9 + progs.src | 1 + qw.qc | 5 + tforthlp.qc | 2 + vote.qc | 747 ++++++++++++++++++++++++++++++++++++++++++++++++++++ weapons.qc | 5 + world.qc | 3 + 8 files changed, 780 insertions(+) create mode 100644 vote.qc diff --git a/client.qc b/client.qc index bfe64d18..bd89b0bc 100644 --- a/client.qc +++ b/client.qc @@ -467,6 +467,11 @@ void () GotoNextMap = { local string sl; local string st; + if (vote_result != string_null) { + changelevel(vote_result); + return; + } + if (nextmap != mapname) { changelevel(nextmap); already_chosen_map = time; @@ -697,6 +702,8 @@ void () execute_changelevel = { other = find(world, classname, "player"); while (other != world) { + if (vote_result != string_null) + sprint(other, PRINT_HIGH, "Next up: ", vote_result); other.takedamage = DAMAGE_NO; other.solid = SOLID_NOT; other.movetype = MOVETYPE_NONE; @@ -1027,6 +1034,7 @@ void () PutClientInServer = { self.invincible_finished = 0; self.effects = 0; self.invincible_time = 0; + self.spawn_time = time; self.reload_shotgun = 0; self.reload_super_shotgun = 0; diff --git a/defs.h b/defs.h index 0d3c0494..b6194269 100644 --- a/defs.h +++ b/defs.h @@ -252,6 +252,11 @@ #define TF_TD_FIRE 16 // Fire damage #define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc +// Classic Fortress stuff +#define CF_MAPVOTE_FORCESHOW 5 // Seconds to force the mapvote menu to be open +#define CF_MAPVOTE_DURATION 180 // Seconds to show map vote menu +#define CF_MAPVOTE_DURATION_DECIDER 120 // Seconds to show map decider menu + /*======================================================*/ /* Toggleable Game Settings */ /*======================================================*/ @@ -347,6 +352,10 @@ #define TF_WEAPLAST 69 +// CF map voting +#define TF_VOTENEXT 70 +#define TF_FORCENEXT 71 + #define TF_CHANGETEAM 98 #define TF_CHANGECLASS 99 // Added to PC_??? to get impulse to use if this clashes with your diff --git a/progs.src b/progs.src index f6c33f25..4f2fdd68 100644 --- a/progs.src +++ b/progs.src @@ -5,6 +5,7 @@ qw.qc debug.qc status.qc menu.qc +vote.qc subs.qc combat.qc items.qc diff --git a/qw.qc b/qw.qc index e95db71a..238f15be 100644 --- a/qw.qc +++ b/qw.qc @@ -33,6 +33,11 @@ typedef void (float) f_void_float; .float zoom_mode; // Autozoom: 0 (off), 2 (2x), 4 (4x) .float zoom_in; // TRUE if player is currently zooming in .float zoom_out; // TRUE if player is currently zooming out +.float has_voted_map; // Map option that player voted for +.float spawn_time; // Time when player spawned +.float menu_time; // Time when vote map menu was first issued +.float vote_next; // TRUE if player has voted for a map vote +.float force_next; // TRUE if player has voted to force next map .float tfstate; // State flags for TeamFortress .entity linked_list; // Used just like chain. Has to be separate so diff --git a/tforthlp.qc b/tforthlp.qc index 7e2746ef..da6b5a09 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -101,6 +101,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); TeamFortress_Alias("discard", TF_DISCARD, 0); TeamFortress_Alias("id", TF_ID, 0); + TeamFortress_Alias("votenext", TF_VOTENEXT, 0); + TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); } else if (self.motd == 55) { TeamFortress_Alias("flaginfo", FLAG_INFO, 0); TeamFortress_Alias("maphelp", TF_HELP_MAP, 0); diff --git a/vote.qc b/vote.qc new file mode 100644 index 00000000..2fc06eab --- /dev/null +++ b/vote.qc @@ -0,0 +1,747 @@ +// MAP VOTING FOR CLASSIC FORTRESS +// =============================== +// Displays a vote menu during the last few minutes of gameplay on a map. + +// functions by order of appearance +void (entity pe_player) Vote_NextMap; +float () Vote_GetNextVotes; +void (entity pe_player) Vote_ForceNext; +float () Vote_GetForceNextVotes; +void () Vote_Check; +void (float pf_decider) Vote_SetupVote; +void (float pf_input) Vote_Input; +void () Vote_MenuOpen; +void () Vote_MenuClose; +void (entity pe_player) Vote_Menu; +void (float pf_input) Vote_RemoveVote; +string () Vote_GetMapList; +void (string ps_maplist) Vote_PopulateVoteList; +string (string ps_map, string ps_maplist) Vote_StripMap; +void () Vote_Reset; +void () Vote_ResetVotes; +void () Vote_ResetMapNames; +float () Vote_GetVoteCount; +float () Vote_GetWinnerCount; +float () Vote_GetWinnerVoteCount; +string () Vote_GetWinner; +string () Vote_GetWinnerList; +string (string ps_maplist) Vote_RandomWinner; +string () Vote_RandomMap; +float (float pf_from, float pf_to) RandomRange; +void () Vote_DropLosers; +float (string ps_list) List_Count; +string (string ps_list, float pf_idx) List_Index; + +// global variables +float vote1_cnt, vote2_cnt, vote3_cnt, vote4_cnt, vote5_cnt; +string vote1_map, vote2_map, vote3_map, vote4_map, vote5_map, vote_result; +float vote_started, vote_update, vote_winnercount, vote_decider, vote_abort; + +// opens the map voting early +// called from weapons.qc:ImpulseCommands() +void (entity pe_player) Vote_NextMap = { + local float f_votes, f_votes_needed; + + if (vote_result != string_null) { + sprint(pe_player, PRINT_HIGH, "Next map has already been voted to ", vote_result, ". Use /forcenext to force next map.\n"); + return; + } + pe_player.vote_next = 1; + + bprint(PRINT_HIGH, pe_player.netname, " wants to start voting for next map\n"); + + f_votes = Vote_GetNextVotes(); + f_votes_needed = floor(TeamFortress_GetNoPlayers() / 2); + if (f_votes >= f_votes_needed) { + Vote_SetupVote(0); + //dprint("[cf/mapvote/votenext]: forcing map vote.\n"); + bprint(PRINT_HIGH, "Commencing vote for next map\n"); + } +}; + +// returns the total amount of vote_next votes +// called from Vote_NextMap() +float () Vote_GetNextVotes = { + local entity e_player; + local float f_count = 0; + + e_player = find(world, classname, "player"); + while (e_player != world) { + if (e_player.vote_next == 1) + f_count = f_count + 1; + e_player = find(e_player, classname, "player"); + } + + return f_count; +}; + +// forces server to change map to next map +// called from weapons.qc:ImpulseCommands() +void (entity pe_player) Vote_ForceNext = { + local float f_votes, f_votes_needed; + + if (vote_result == string_null) { + sprint(pe_player, PRINT_HIGH, "You can't force next map before voting for a new map. Use /votenext to issue a map vote.\n"); + return; + } + + pe_player.force_next = 1; + + bprint(PRINT_HIGH, pe_player.netname, " wants to start playing ", vote_result, " now\n"); + + f_votes = Vote_GetForceNextVotes(); + f_votes_needed = ceil(TeamFortress_GetNoPlayers() / 2); + if (f_votes >= f_votes_needed) { + Vote_SetupVote(0); + //dprint("[cf/mapvote/forcenext]: forcing next map: ", vote_result, "\n"); + bprint(PRINT_HIGH, "Changing level to ", vote_result, "\n"); + changelevel(vote_result); + } +}; + +// returns the total amount of force_next votes +// called from Vote_ForceNext() +float () Vote_GetForceNextVotes = { + local entity e_player; + local float f_count = 0; + + e_player = find(world, classname, "player"); + while (e_player != world) { + if (e_player.force_next == 1) + f_count = f_count + 1; + e_player = find(e_player, classname, "player"); + } + + return f_count; +}; + +// check if voting should start each frame +// called from world.qc:StartFrame() +void () Vote_Check = { + + // only run these checks once a second + if (vote_started >= 0 && (time - vote_update) >= 1 && !vote_abort) { + vote_update = time; + + if ((time + CF_MAPVOTE_DURATION + CF_MAPVOTE_DURATION_DECIDER) > timelimit && vote_started == 0) { + //dprint("[cf/mapvote/check]: setting up map vote.\n"); + Vote_SetupVote(0); + if (!vote_abort) { + bprint(PRINT_HIGH, "Time to vote for what map comes next\n"); + //dprint("[cf/mapvote/check]: opening map vote.\n"); + Vote_MenuOpen(); + } + return; + } + + else if (vote_started > 0) { + + // open/close menus for those eligible + Vote_MenuOpen(); + Vote_MenuClose(); + + // when voting has been going on for CF_MAPVOTE_DURATION seconds or + // if everyone's voted, decide winner or create decider vote + if (((time - vote_started) >= CF_MAPVOTE_DURATION || Vote_GetVoteCount() == TeamFortress_GetNoPlayers()) + && vote_result == string_null) { + + // get winners/tied winners count + if (!vote_winnercount) + vote_winnercount = Vote_GetWinnerCount(); + + // create decider vote if there are more 2 or more winners + if (!vote_decider && vote_winnercount >= 2 && Vote_GetWinnerVoteCount() < TeamFortress_GetNoPlayers()) { + //dprint("[cf/mapvote/check]: setting up decider map vote.\n"); + Vote_SetupVote(1); // 1 = decider vote + if (!vote_abort) { + bprint(PRINT_HIGH, "A winner could not be decided. Vote options have been updated.\n"); + //dprint("[cf/mapvote/check]: opening decider map vote.\n"); + Vote_MenuOpen(); + } + return; + } + + vote_started = -1; + Vote_MenuClose(); // close all open map votes + + // get the winner of the vote + vote_result = strzone(Vote_GetWinner()); + //dprint("[cf/mapvote/check]: next map will be ", vote_result, "\n"); + + // release map names from memory + Vote_ResetMapNames(); + + bprint(PRINT_HIGH, "Voting has ended. The next map will be ", vote_result, "\n"); + } + } + } +}; + +// decides maps should be included in map voting +// called from Vote_Check() +void (float pf_decider) Vote_SetupVote = { + local string s_maplist; + + if (!pf_decider) { + vote_decider = 0; + s_maplist = Vote_GetMapList(); // returns a strzoned string + } else { + vote_decider = 1; + Vote_ResetVotes(); + s_maplist = strzone(Vote_GetWinnerList()); + //dprint("[cf/mapvote/setupvote]: decider votelist: ", s_maplist, "\n"); + } + vote_started = time; + + // set vote*_map variables to randomly selected maps from s_maplist + Vote_PopulateVoteList(s_maplist); + strunzone(s_maplist); + + if (vote1_map == string_null) { + //dprint("[cf/mapvote/setupvote]: no maps found. aborting.\n"); + vote_result = mapname; + vote_abort = 1; + return; + } +}; + +// processes user input from Vote_Menu() +void (float pf_input) Vote_Input = { + local string s_votedfor = ""; + + // don't do anything if user votes on same map twice + if (self.has_voted_map == pf_input) + return; + + // remove vote if user changed his mind + if (self.has_voted_map && pf_input >= 1 && pf_input <= 5) + Vote_RemoveVote(self.has_voted_map); + + if (pf_input == 1) { + if (vote1_map == string_null) { + Vote_Menu(self); + return; + } + s_votedfor = vote1_map; + vote1_cnt = vote1_cnt + 1; + } else if (pf_input == 2) { + if (vote2_map == string_null) { + Vote_Menu(self); + return; + } + s_votedfor = vote2_map; + vote2_cnt = vote2_cnt + 1; + } else if (pf_input == 3) { + if (vote3_map == string_null) { + Vote_Menu(self); + return; + } + s_votedfor = vote3_map; + vote3_cnt = vote3_cnt + 1; + } else if (pf_input == 4) { + if (vote4_map == string_null) { + Vote_Menu(self); + return; + } + s_votedfor = vote4_map; + vote4_cnt = vote4_cnt + 1; + } else if (pf_input == 5) { + s_votedfor = vote5_map; + vote5_cnt = vote5_cnt + 1; + } + + // update menu for all players (with active menus) on input + if (pf_input >= 1 && pf_input <= 5) { + //dprint("[cf/mapvote/voteinput]: ", self.netname, " voted for ", s_votedfor, ".\n"); + sprint(self, PRINT_HIGH, "You voted for ", s_votedfor, "\n"); + self.has_voted_map = pf_input; + if ((time - self.spawn_time) <= CF_MAPVOTE_FORCESHOW) + Vote_Menu(self); + Vote_MenuOpen(); // update + } else + Vote_Menu(self); +}; + +// opens map vote menu for newly spawned players who haven't voted yet +// called from Vote_Input(), Vote_Check() +void () Vote_MenuOpen = { + local entity e_player = find(world, classname, "player"); + + while (e_player != world) { + if (e_player.team_no != 0 && e_player.playerclass != 0) { + if (!e_player.has_voted_map) { + if ((time - e_player.spawn_time) <= CF_MAPVOTE_FORCESHOW) { + if (!e_player.menu_time) { + //dprint("[cf/mapvote/menuopen]: open vote menu for newly spawned ", e_player.netname, ".\n"); + e_player.menu_time = time; + } + Vote_Menu(e_player); + } + } else if (e_player.menu_input == Vote_Input && (time - e_player.menu_time) <= CF_MAPVOTE_FORCESHOW) + Vote_Menu(e_player); + } + e_player = find(e_player, classname, "player"); + } +}; + +// closes map vote menu for anyone who's been alive >CF_MAPVOTE_FORCESHOW seconds +// called from Vote_Check() +void () Vote_MenuClose = { + local entity e_player = find(world, classname, "player"); + + while (e_player != world) { + if (vote_started == -1 && e_player.menu_input == Vote_Input) { + //dprint("[cf/mapvote/menuclose]: vote over, closing vote menu for ", e_player.netname, ".\n"); + Menu_Close(e_player); + } + else if (e_player.menu_input == Vote_Input && (time - e_player.spawn_time) > CF_MAPVOTE_FORCESHOW) { + if ((time - e_player.menu_time) > CF_MAPVOTE_FORCESHOW) { + //dprint("[cf/mapvote/menuclose]: closing vote menu for ", e_player.netname, ".\n"); + e_player.menu_time = 0; + Menu_Close(e_player); + } + } + e_player = find(e_player, classname, "player"); + } +}; + +// shows the map vote menu +// called from Vote_Input(), Menu_Open() +void (entity pe_player) Vote_Menu = { + local string s_choose, s_vote1, s_vote2, s_vote3, s_vote4, s_vote5; + local float f_width, f_timeleft; + + f_timeleft = CF_MAPVOTE_FORCESHOW - (time - pe_player.spawn_time); + + s_choose = strcat("It's time to choose (closes in ", strcat(ftos(ceil(f_timeleft)), "s):\n\n")); + s_vote1 = ""; + s_vote2 = ""; + s_vote3 = ""; + s_vote4 = ""; + s_vote5 = ""; + f_width = strlen(s_vote1); + + if (vote1_map != string_null) { + s_vote1 = strcat("“‘ ", vote1_map); + if (vote1_cnt) + s_vote1 = strcat(s_vote1, strcat(" (", strcat(ftos(vote1_cnt), " votes)"))); + else + s_vote1 = strcat(s_vote1, " "); + + if (strlen(s_vote1) > f_width) f_width = strlen(s_vote1); + } + if (vote2_map != string_null) { + s_vote2 = strcat("”‘ ", vote2_map); + if (vote2_cnt) + s_vote2 = strcat(s_vote2, strcat(" (", strcat(ftos(vote2_cnt), " votes)"))); + else + s_vote2 = strcat(s_vote2, " "); + + if (strlen(s_vote2) > f_width) f_width = strlen(s_vote2); + } + if (vote3_map != string_null) { + if (!vote_decider || vote3_cnt) + s_vote3 = strcat("•‘ ", vote3_map); + if (vote3_cnt) + s_vote3 = strcat(s_vote3, strcat(" (", strcat(ftos(vote3_cnt), " votes)"))); + else + s_vote3 = strcat(s_vote3, " "); + + if (strlen(s_vote3) > f_width) f_width = strlen(s_vote3); + } + if (vote4_map != string_null) { + if (!vote_decider || vote4_cnt) + s_vote4 = strcat("–‘ ", vote4_map); + if (vote4_cnt) + s_vote4 = strcat(s_vote4, strcat(" (", strcat(ftos(vote4_cnt), " votes)"))); + else + s_vote4 = strcat(s_vote4, " "); + + if (strlen(s_vote4) > f_width) f_width = strlen(s_vote4); + } + if (vote5_map != string_null) { + if (!vote_decider || vote5_cnt) + s_vote5 = strcat("—‘ ", vote5_map); + if (vote5_cnt) + s_vote5 = strcat(s_vote5, strcat(" (", strcat(ftos(vote5_cnt), " votes)"))); + else + s_vote5 = strcat(s_vote5, " "); + + if (strlen(s_vote5) > f_width) f_width = strlen(s_vote5); + } + + s_vote1 = strpadr(s_vote1, f_width); + s_vote2 = strpadr(s_vote2, f_width); + s_vote3 = strpadr(s_vote3, f_width); + s_vote4 = strpadr(s_vote4, f_width); + s_vote5 = strpadr(s_vote5, f_width); + + Status_Menu(pe_player, Vote_Input, s_choose, s_vote1, "\n", s_vote2, "\n", s_vote3, "\n", s_vote4, "\n\n", s_vote5, "\n"); +}; + +// removes a vote (if a user changes his mind during first 3 seconds) +// called from Vote_Input() +void (float pf_input) Vote_RemoveVote = { + local string s_map = ""; + + if (pf_input == 1) { + vote1_cnt = vote1_cnt - 1; + s_map = vote1_map; + } else if (pf_input == 2) { + vote2_cnt = vote2_cnt - 1; + s_map = vote2_map; + } else if (pf_input == 3) { + vote3_cnt = vote3_cnt - 1; + s_map = vote3_map; + } else if (pf_input == 4) { + vote4_cnt = vote4_cnt - 1; + s_map = vote4_map; + } else if (pf_input == 5) { + vote5_cnt = vote5_cnt - 1; + s_map = vote5_map; + } + + //dprint("[cf/mapvote/removevote]: removing vote from ", s_map, ".\n"); +}; + +// returns a list of maps from config +// called from Vote_SetupVote() +string () Vote_GetMapList = { + local float f_players = TeamFortress_GetNoPlayers(); + local string s_maplist, s_maplist1, s_maplist2, s_maplist3, s_maplist4; + + if (f_players <= 2) { + //dprint("[cf/mapvote/getmaplist]: using tiny votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_tiny1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_tiny2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_tiny3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_tiny4"), " "); + } else if (f_players <= 4) { + //dprint("[cf/mapvote/getmaplist]: using small votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_small1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_small2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_small3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_small4"), " "); + } else if (f_players <= 6) { + //dprint("[cf/mapvote/getmaplist]: using medium votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_medium1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_medium2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_medium3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_medium4"), " "); + } else if (f_players <= 8) { + //dprint("[cf/mapvote/getmaplist]: using large votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_large1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_large2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_large3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_large4"), " "); + } else if (f_players <= 12) { + //dprint("[cf/mapvote/getmaplist]: using xlarge votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_xlarge1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_xlarge2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_xlarge3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_xlarge4"), " "); + } else if (f_players <= 14) { + //dprint("[cf/mapvote/getmaplist]: using xxl votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_xxl1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_xxl2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_xxl3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_xxl4"), " "); + } else if (f_players <= 16) { + //dprint("[cf/mapvote/getmaplist]: using xxxl votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_xxxl1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_xxxl2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_xxxl3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_xxxl4"), " "); + } else { + //dprint("[cf/mapvote/getmaplist]: using xxxxl votelist.\n"); + s_maplist1 = strcat(infokey(world, "votelist_xxxxl1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_xxxxl2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_xxxxl3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_xxxxl4"), " "); + } + + s_maplist = strzone(strcat(s_maplist1, strcat(s_maplist2, strcat(s_maplist3, s_maplist4)))); + + //dprint("[cf/mapvote/getmaplist]: votelist: ", s_maplist, "\n"); + return s_maplist; +}; + +// populates vote*_map variables +// called from Vote_SetupVote() +void (string ps_maplist) Vote_PopulateVoteList = { + local float f_count, i; + local string s_maplist; + + s_maplist = Vote_StripMap(mapname, ps_maplist); // strip current map from votelist + f_count = List_Count(s_maplist); + + for (i = 0; i < 5; i++) { + local float f_next = RandomRange(0, f_count - 1); + local string s_map = strzone(List_Index(s_maplist, f_next)); + + if (i == 0) { + vote1_map = s_map; + //dprint("[cf/mapvote/populatevotelist]: adding map1: ", vote1_map, "\n"); + } else if (i == 1) { + vote2_map = s_map; + //dprint("[cf/mapvote/populatevotelist]: adding map2: ", vote2_map, "\n"); + } else if (i == 2) { + vote3_map = s_map; + //dprint("[cf/mapvote/populatevotelist]: adding map3: ", vote3_map, "\n"); + } else if (i == 3) { + vote4_map = s_map; + //dprint("[cf/mapvote/populatevotelist]: adding map4: ", vote4_map, "\n"); + } + + s_maplist = Vote_StripMap(s_map, s_maplist); + f_count = List_Count(s_maplist); + } + vote5_map = strzone(mapname); + //dprint("[cf/mapvote/populatevotelist]: adding map5: ", vote5_map, "\n"); +}; + +// strips a map from a given list of maps +// called from Vote_PopulateVoteList() +string (string ps_map, string ps_maplist) Vote_StripMap = { + local float f_count, i; + local string s_maplist, s_tmp; + + s_maplist = ps_maplist; + f_count = List_Count(s_maplist); + + // remove current map from list, strzone hack needed because limited string buffer + s_tmp = strzone(""); + for (i = 0; i < f_count; i++) { + if (List_Index(s_maplist, i) != ps_map) { + local string tmp_old = s_tmp; + local string map = List_Index(s_maplist, i); + s_tmp = strzone(strcat(s_tmp, strcat(map, " "))); + strunzone(tmp_old); + } + } + + return s_tmp; +}; + +// resets map voting +// called from world.qc:worldspawn() +void () Vote_Reset = { + vote_started = 0; + vote_update = 0; + vote_winnercount = 0; + vote_abort = 0; + vote_result = string_null; + + Vote_ResetMapNames(); + Vote_ResetVotes(); +}; + +// resets players' vote status & map vote count +// called from Vote_SetupVote(), Vote_Reset() +void () Vote_ResetVotes = { + local entity e_player; + + e_player = find(world, classname, "player"); + while (e_player != world) { + e_player.has_voted_map = 0; + e_player = find(e_player, classname, "player"); + } + + vote1_cnt = vote2_cnt = vote3_cnt = vote4_cnt = vote5_cnt = 0; +}; + +// resets map names +// called from Vote_Check(), Vote_Reset() +void () Vote_ResetMapNames = { + //dprint("[cf/mapvote/resetmapnames]: resetting map names.\n"); + + if (vote1_map != string_null) { strunzone(vote1_map); vote1_map = string_null; } + if (vote2_map != string_null) { strunzone(vote2_map); vote2_map = string_null; } + if (vote3_map != string_null) { strunzone(vote3_map); vote3_map = string_null; } + if (vote4_map != string_null) { strunzone(vote4_map); vote4_map = string_null; } + if (vote5_map != string_null) { strunzone(vote5_map); vote5_map = string_null; } +} + +// returns the total amount of votes +// called from Vote_Check() +float () Vote_GetVoteCount = { + return (vote1_cnt + vote2_cnt + vote3_cnt + vote4_cnt + vote5_cnt); +}; + +// returns the winner count (>1 if there's a tie) +// called from Vote_Check() +float () Vote_GetWinnerCount = { + local float f_count; + + Vote_DropLosers(); + + f_count = 0; + if (vote1_cnt) f_count = f_count + 1; + if (vote2_cnt) f_count = f_count + 1; + if (vote3_cnt) f_count = f_count + 1; + if (vote4_cnt) f_count = f_count + 1; + if (vote5_cnt) f_count = f_count + 1; + + return f_count; +}; + +// returns the amount of votes on the winning maps +// called from Vote_Check() +float () Vote_GetWinnerVoteCount = { + local float f_count; + + Vote_DropLosers(); + + f_count = 0; + if (vote1_cnt) f_count = f_count + vote1_cnt; + if (vote2_cnt) f_count = f_count + vote2_cnt; + if (vote3_cnt) f_count = f_count + vote3_cnt; + if (vote4_cnt) f_count = f_count + vote4_cnt; + if (vote5_cnt) f_count = f_count + vote5_cnt; + + return f_count; +}; + +// returns the winner based on votes +// called from Vote_Check() +string () Vote_GetWinner = { + local string s_maplist, s_result; + + //dprint("[cf/mapvote/getwinner]: dropping losers.\n"); + Vote_DropLosers(); + + s_maplist = Vote_GetWinnerList(); + + if (s_maplist != string_null) + s_result = Vote_RandomWinner(s_maplist); + else + s_result = Vote_RandomMap(); + + return s_result; +}; + +// returns a list of winners +// called from Vote_SetupVote(), Vote_GetWinner() +string () Vote_GetWinnerList = { + local string s_maplist; + + Vote_DropLosers(); + + s_maplist = ""; + if (vote1_cnt) s_maplist = strcat(s_maplist, strcat(vote1_map, " ")); + if (vote2_cnt) s_maplist = strcat(s_maplist, strcat(vote2_map, " ")); + if (vote3_cnt) s_maplist = strcat(s_maplist, strcat(vote3_map, " ")); + if (vote4_cnt) s_maplist = strcat(s_maplist, strcat(vote4_map, " ")); + if (vote5_cnt) s_maplist = strcat(s_maplist, vote5_map); + + //dprint("[cf/mapvote/getwinnerlist]: winner list: ", s_maplist, "\n"); + return s_maplist; +}; + +// returns a random winner from a list of maps +// called from Vote_GetWinner() +string (string ps_maplist) Vote_RandomWinner = { + local float f_idx, f_count; + local string s_winner; + + f_count = List_Count(ps_maplist) - 1; + f_idx = RandomRange(0, f_count); + s_winner = List_Index(ps_maplist, f_idx); + + //dprint("[cf/mapvote/randomwinner]: random winner: ", s_winner, "\n"); + return s_winner; +}; + +// returns a random map from a list of maps +// called from Vote_PopulateVoteList() +string () Vote_RandomMap = { + local float f_idx, f_count; + local string s_maplist, s_map; + + s_maplist = Vote_GetMapList(); // returns a strzoned string + f_count = List_Count(s_maplist) - 1; + f_idx = RandomRange(0, f_count); + s_map = List_Index(s_maplist, f_idx); + strunzone(s_maplist); + + //dprint("[cf/mapvote/randommap]: drew random map: ", s_map, "\n"); + return s_map; +}; + +// returns a random number between from and to +// called from Vote_GetWinner(), Vote_PopulateVoteList() +float (float from, float to) RandomRange = { + return from + floor(random() * ((to - from) + 1)); +}; + +// sets vote count for all losers to 0 +// called from Vote_GetWinnerCount(), Vote_GetWinnerVoteCount(), Vote_GetWinner(), Vote_GetWinnerList() +void () Vote_DropLosers = { + if (vote2_cnt > vote1_cnt || vote3_cnt > vote1_cnt || vote4_cnt > vote1_cnt || vote5_cnt > vote1_cnt) + vote1_cnt = 0; + if (vote1_cnt > vote2_cnt || vote3_cnt > vote2_cnt || vote4_cnt > vote2_cnt || vote5_cnt > vote2_cnt) + vote2_cnt = 0; + if (vote1_cnt > vote3_cnt || vote2_cnt > vote3_cnt || vote4_cnt > vote3_cnt || vote5_cnt > vote3_cnt) + vote3_cnt = 0; + if (vote1_cnt > vote4_cnt || vote2_cnt > vote4_cnt || vote3_cnt > vote4_cnt || vote5_cnt > vote4_cnt) + vote4_cnt = 0; + if (vote1_cnt > vote5_cnt || vote2_cnt > vote5_cnt || vote3_cnt > vote5_cnt || vote4_cnt > vote5_cnt) + vote5_cnt = 0; +}; + +// returns list item count in list +// called from Vote_PopulateVoteList(), Vote_RandomWinner() +float (string ps_list) List_Count = { + local float i; + local float f_count = 0; + local float f_length = strlen(ps_list); + local string s_previous = " "; + + for (i = 0; i < f_length; i++) { + // set current character + local string s_current = substr(ps_list, i, 1); + + // non-empty space => word + if (s_current != " " && s_previous == " ") + f_count = f_count + 1; + + s_previous = s_current; + } + + return f_count; +}; + +// returns the nth list item in a given list +// called from Vote_PopulateVoteList(), Vote_RandomWinner() +string (string ps_list, float pf_idx) List_Index = { + local float i; + local float f_count = 0; + local float f_start = -1; + local float f_length = strlen(ps_list); + local string s_previous = " "; + + for (i = 0; i < f_length; i++) { + // set current character + local string s_current = substr(ps_list, i, 1); + + // non-empty space => start of word + if (s_current != " " && s_previous == " ") { + if (f_count == pf_idx) + f_start = i; + f_count = f_count + 1; + } + + // empty space => end of word + if (s_current == " " && f_start > -1) { + return substr(ps_list, f_start, i - f_start); + } + + s_previous = s_current; + } + + // if f_start is set it means a list item was found + if (f_start > -1) + return substr(ps_list, f_start, i - f_start); + + return string_null; +}; \ No newline at end of file diff --git a/weapons.qc b/weapons.qc index e48cc7b4..d909fef3 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2166,6 +2166,11 @@ void () PreMatchImpulses; void () DeadImpulses; void () ImpulseCommands = { + if (self.impulse == TF_VOTENEXT) + Vote_NextMap(self); + else if (self.impulse == TF_FORCENEXT) + Vote_ForceNext(self); + if ((self.last_impulse == TF_DETPACK) && self.impulse) TeamFortress_SetDetpack(self.impulse); diff --git a/world.qc b/world.qc index 178f18f3..2f2ead25 100644 --- a/world.qc +++ b/world.qc @@ -160,6 +160,8 @@ void () worldspawn = { localcmd(".cfg\n"); } + Vote_Reset(); + W_Precache(); precache_sound("demon/dland2.wav"); precache_sound("misc/h2ohit1.wav"); @@ -309,6 +311,7 @@ void () StartFrame = { fraglimit = cvar("fraglimit"); deathmatch = cvar("deathmatch"); framecount = framecount + 1; + Vote_Check(); }; entity bodyque_head; From 0670159e50a47f91bc3561690c82e51e2229c664 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 14:07:48 +0200 Subject: [PATCH 0014/2474] Add map specific configurations (closes #48) --- client.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client.qc b/client.qc index bd89b0bc..4a7aa970 100644 --- a/client.qc +++ b/client.qc @@ -469,6 +469,9 @@ void () GotoNextMap = { if (vote_result != string_null) { changelevel(vote_result); + localcmd("exec cfg/maps/"); + localcmd(vote_result); + localcmd(".cfg\n"); return; } From b731cb33dab5c90c0b8ebf8638408a6ef3c7f542 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 19 Jul 2014 19:35:30 +0200 Subject: [PATCH 0015/2474] Clean up map cycle/next map code --- client.qc | 171 ++++-------------------------------------------------- vote.qc | 3 +- 2 files changed, 12 insertions(+), 162 deletions(-) diff --git a/client.qc b/client.qc index 4a7aa970..43f9c999 100644 --- a/client.qc +++ b/client.qc @@ -149,7 +149,7 @@ void () DecodeLevelParms = { if (coop || !deathmatch) toggleflags = toggleflags | TFLAG_CLASS_PERSIST; - nextmap = mapname; + nextmap = strzone(mapname); ent = find(world, classname, "info_tfdetect"); if (ent != world) { @@ -463,64 +463,23 @@ void () TF_MovePlayer = { }; void () GotoNextMap = { - local float nextlevel; - local string sl; - local string st; - - if (vote_result != string_null) { - changelevel(vote_result); - localcmd("exec cfg/maps/"); - localcmd(vote_result); - localcmd(".cfg\n"); - return; - } + if (vote_result != string_null) + nextmap = strzone(vote_result); - if (nextmap != mapname) { + if (nextmap != mapname || vote_result != string_null) { changelevel(nextmap); already_chosen_map = time; } - sl = infokey(world, mapname); - if (sl != string_null) { - nextmap = sl; - already_chosen_map = time; - return; - } - - if (!already_chosen_map) { - - sl = infokey(world, "n"); - nextlevel = stof(sl); - nextlevel = nextlevel + 1; - sl = ftos(nextlevel); - - localcmd("serverinfo n "); - localcmd(sl); - localcmd("\n"); - - st = infokey(world, "cd"); - if (st == string_null) - st = infokey(world, "cycledir"); - - if (st != string_null) { - localcmd("exec "); - localcmd(st); - localcmd("/map"); - } else - localcmd("exec qwmcycle/map"); - - localcmd(sl); - localcmd(".cfg\n"); - already_chosen_map = time; - } - if (infokey(world, "n") == "0") - already_chosen_map = 0; + strunzone(nextmap); // avoid endless intermission by restarting the current map - if (already_chosen_map + 15 < time) { + if ((already_chosen_map + 10) < time) { changelevel(mapname); already_chosen_map = time; } + + intermission_running = 0; }; void () ExitIntermission = { @@ -532,89 +491,12 @@ void () ExitIntermission = { } intermission_exittime = time + 1; - intermission_running = intermission_running + 1; - - if (intermission_running == 2) { - - if (world.model == "maps/e1m7.bsp") { - - WriteByte(MSG_ALL, SVC_CDTRACK); - WriteByte(MSG_ALL, 2); - WriteByte(MSG_ALL, 3); - - if (!cvar("registered")) { - - WriteByte(MSG_ALL, SVC_FINALE); - WriteString(MSG_ALL, - "As the corpse of the monstrous entity\nChthon sinks back into the lava whence\nit rose, you grip the Rune of Earth\nMagic tightly. Now that you have\nconquered the Dimension of the Doomed, \nrealm of Earth Magic, you are ready to\ncomplete your task in..."); - - } else { - - WriteByte(MSG_ALL, SVC_FINALE); - WriteString(MSG_ALL, - "As the corpse of the monstrous entity\nChthon sinks back into the lava whence\nit rose, you grip the Rune of Earth\nMagic tightly. Now that you have\nconquered the Dimension of the Doomed, \nrealm of Earth Magic, you are ready to\ncomplete your task. A..."); - - } - return; - - } else if (world.model == "maps/e2m6.bsp") { - WriteByte(MSG_ALL, SVC_CDTRACK); - WriteByte(MSG_ALL, 2); - WriteByte(MSG_ALL, 3); - - WriteByte(MSG_ALL, SVC_FINALE); - WriteString(MSG_ALL, - "The Rune of Black Magic throbs evilly in\nyour hand and whispers dark thoughts\ninto your brain. You learn the inmost\nlore of the Hell-Mother; Shub-Niggurath!\nYou now know that she is behind all the\nterrible plotting which has led to so\nmuch death..."); - return; - - } else if (world.model == "maps/e3m6.bsp") { - - WriteByte(MSG_ALL, SVC_CDTRACK); - WriteByte(MSG_ALL, 2); - WriteByte(MSG_ALL, 3); - - WriteByte(MSG_ALL, SVC_FINALE); - WriteString(MSG_ALL, - "The charred viscera of diabolic horrors\nbubble viscously as you seize the Rune\nof Hell Magic. Its heat scorches your\nhand, and its terrible secrets blight\nyour mind. Gathering the shreds of your\ncourage, you shake the devil's shackles\nfrom your ..."); - return; - - } else if (world.model == "maps/e4m7.bsp") { - - WriteByte(MSG_ALL, SVC_CDTRACK); - WriteByte(MSG_ALL, 2); - WriteByte(MSG_ALL, 3); - WriteByte(MSG_ALL, SVC_FINALE); - WriteString(MSG_ALL, - "Despite the awful might of the Elder\nWorld, you have achieved the Rune of\nElder Magic, capstone of all types of\narcane wisdom. Beyond good and evil, \nbeyond life and death, the Rune\npulsates, heavy with import. Patient and\npotent, the Elder Being..."); - return; - } - GotoNextMap(); - } - if (intermission_running == 3) { - - if (!cvar("registered")) { - WriteByte(MSG_ALL, SVC_SELLSCREEN); - return; - } - if ((serverflags & 15) == 15) { - WriteByte(MSG_ALL, SVC_FINALE); - WriteString(MSG_ALL, - "Now, you have all four Runes. You sense\ntremendous invisible forces moving to\nunseal ancient barriers. Shub-Niggurath\nhad hoped to use the Runes Herself to\nclear off the Earth, but now instead, \nyou will use them to enter her home and\nconfront he..."); - return; - } - } dprint("Exit intermission\n"); GotoNextMap(); }; void () IntermissionThink = { - local float minp; - local float maxp; - local float currp; - local string sl; - local string st; - if (time < intermission_exittime) return; if ((!self.button0 && !self.button1) && !self.button2) @@ -622,39 +504,6 @@ void () IntermissionThink = { dprint("Intermission think\n"); GotoNextMap(); - - sl = infokey(world, "nmap"); - if (sl != string_null) { - st = infokey(world, "minp"); - minp = stof(st); - st = infokey(world, "maxp"); - maxp = stof(st); - - currp = TeamFortress_GetNoPlayers(); - dprint("MAP CYCLING: Player Counting... "); - if ((currp >= minp) && (currp <= maxp)) { - dprint("within range. Changing maps...\n"); - - st = infokey(world, "cd"); - if (st == string_null) - st = infokey(world, "cycledir"); - if (st != string_null) { - localcmd("exec "); - localcmd(st); - localcmd("/"); - } else - localcmd("exec qwmcycle/"); - - localcmd(sl); - localcmd(".cfg\n"); - } else { - dprint("outside range. Next map.\n"); - already_chosen_map = 0; - } - localcmd("localinfo minp \"\"\n"); - localcmd("localinfo maxp \"\"\n"); - localcmd("localinfo nmap \"\"\n"); - } }; void () PutClientInIntermission = @@ -706,7 +555,7 @@ void () execute_changelevel = { other = find(world, classname, "player"); while (other != world) { if (vote_result != string_null) - sprint(other, PRINT_HIGH, "Next up: ", vote_result); + sprint(other, PRINT_HIGH, "Next up: ", vote_result, "\n"); other.takedamage = DAMAGE_NO; other.solid = SOLID_NOT; other.movetype = MOVETYPE_NONE; @@ -729,7 +578,7 @@ void () changelevel_touch = { bprint(PRINT_HIGH, other.netname, " exited the level\n"); - nextmap = self.map; + nextmap = strzone(self.map); SUB_UseTargets(); if ((self.spawnflags & 1) && (deathmatch == 0)) { diff --git a/vote.qc b/vote.qc index 2fc06eab..df2f5102 100644 --- a/vote.qc +++ b/vote.qc @@ -6,6 +6,7 @@ void (entity pe_player) Vote_NextMap; float () Vote_GetNextVotes; void (entity pe_player) Vote_ForceNext; +void () GotoNextMap; float () Vote_GetForceNextVotes; void () Vote_Check; void (float pf_decider) Vote_SetupVote; @@ -95,7 +96,7 @@ void (entity pe_player) Vote_ForceNext = { Vote_SetupVote(0); //dprint("[cf/mapvote/forcenext]: forcing next map: ", vote_result, "\n"); bprint(PRINT_HIGH, "Changing level to ", vote_result, "\n"); - changelevel(vote_result); + GotoNextMap(); } }; From 33b2bb196c3022c78cacd32d9f63c27386575fd8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 19 Jul 2014 20:55:52 +0200 Subject: [PATCH 0016/2474] Set clip size to 0 while reloading --- status.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/status.qc b/status.qc index 553ca488..d639c820 100644 --- a/status.qc +++ b/status.qc @@ -156,7 +156,10 @@ void (entity pl) RefreshStatusBar = { else sco2 = GreenScoreToString(team4score); - s3 = strcat(strcat(sco1, sco2), ClipSizeToString(pl)); + if ((self.tfstate & TFSTATE_RELOADING)) + s3 = strcat(strcat(sco1, sco2), " ΓΜΙΠ: 0"); + else + s3 = strcat(strcat(sco1, sco2), ClipSizeToString(pl)); s3 = strcat(s3, " Η: "); s3 = strcat(s3, ftos(self.no_grenades_1)); From fd6faf3b96462affccedf118ad558d926e49d45d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 20:02:15 +0200 Subject: [PATCH 0017/2474] Rewrite a lot of reload code --- actions.qc | 239 ++++++++++++++++++++++++++++------------------------- weapons.qc | 116 +++++++------------------- 2 files changed, 156 insertions(+), 199 deletions(-) diff --git a/actions.qc b/actions.qc index 72150694..c1f31aff 100644 --- a/actions.qc +++ b/actions.qc @@ -256,13 +256,14 @@ void () TeamFortress_ID = { }; void () TeamFortress_ReloadCurrentWeapon = { - local float rt; + local float reloadtime; + local float reloadamount; local entity tWeapon; - if (self.tfstate & 2) { + if (self.tfstate & TFSTATE_RELOADING) { return; } - if (self.current_weapon == 128) { + if (self.current_weapon == WEAP_SHOTGUN) { if (self.ammo_shells == 0) { sprint(self, PRINT_HIGH, "Out of shells\n"); return; @@ -275,134 +276,148 @@ void () TeamFortress_ReloadCurrentWeapon = { sprint(self, PRINT_HIGH, "All shells are in the clip\n"); return; } - if (self.reload_shotgun < self.ammo_shells) { + if (self.ammo_shells >= 1) { + if (self.reload_shotgun >= self.ammo_shells) + reloadamount = self.ammo_shells; + else + reloadamount = self.reload_shotgun; Attack_Finished(0.4); - rt = (8 - self.reload_shotgun) / 8; - rt = 2 - 2 * rt; + reloadtime = (8 - reloadamount) / 8; + reloadtime = 2 - 2 * reloadtime; self.reload_shotgun = 0; if (self.ammo_shells < 8) { self.reload_shotgun = 8 - self.ammo_shells; } sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | 2; + self.tfstate = self.tfstate | TFSTATE_RELOADING; + Status_Refresh(self); tWeapon = spawn(); tWeapon.owner = self; tWeapon.classname = "timer"; - tWeapon.nextthink = time + rt; + tWeapon.nextthink = time + reloadtime; tWeapon.think = W_Reload_shotgun; self.weaponmodel = ""; self.weaponframe = 0; } else { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } - } else { - if (self.current_weapon == 256) { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - if (self.reload_super_shotgun == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((16 - self.reload_super_shotgun) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; + } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { + if (self.ammo_shells == 0) { + sprint(self, PRINT_HIGH, "Out of shells\n"); + return; + } + if (self.reload_super_shotgun == 0) { + sprint(self, PRINT_HIGH, "Clip full\n"); + return; + } + if ((16 - self.reload_super_shotgun) == self.ammo_shells) { + sprint(self, PRINT_HIGH, "All shells are in the clip\n"); + return; + } + if (self.ammo_shells >= 2) { + if (self.reload_super_shotgun >= self.ammo_shells) + reloadamount = self.ammo_shells; + else + reloadamount = self.reload_super_shotgun; + Attack_Finished(0.7); + reloadtime = (16 - reloadamount) / 16; + reloadtime = 3 - (3 * reloadtime); + self.reload_super_shotgun = 0; + if (self.ammo_shells < 16) { + self.reload_super_shotgun = 16 - self.ammo_shells; } - if (self.reload_super_shotgun < self.ammo_shells) { - Attack_Finished(0.7); - rt = (16 - self.reload_super_shotgun) / 16; - rt = 3 - (3 * rt); - self.reload_super_shotgun = 0; - if (self.ammo_shells < 16) { - self.reload_super_shotgun = 16 - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | 2; - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + rt; - tWeapon.think = W_Reload_super_shotgun; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); + sprint(self, PRINT_HIGH, "Reloading...\n"); + self.tfstate = self.tfstate | TFSTATE_RELOADING; + Status_Refresh(self); + tWeapon = spawn(); + tWeapon.owner = self; + tWeapon.classname = "timer"; + tWeapon.nextthink = time + reloadtime; + tWeapon.think = W_Reload_super_shotgun; + self.weaponmodel = ""; + self.weaponframe = 0; + } else { + sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); + } + } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { + if (self.ammo_rockets == 0) { + sprint(self, PRINT_HIGH, "Out of grenades\n"); + return; + } + if (self.reload_grenade_launcher == 0) { + sprint(self, PRINT_HIGH, "Clip full\n"); + return; + } + if ((6 - self.reload_grenade_launcher) == + self.ammo_rockets) { + sprint(self, PRINT_HIGH, "All grenades are in the clip\n"); + return; + } + if (self.ammo_rockets >= 1) { + if (self.reload_grenade_launcher >= self.ammo_rockets) + reloadamount = self.ammo_rockets; + else + reloadamount = self.reload_grenade_launcher; + Attack_Finished(0.6); + reloadtime = (6 - reloadamount) / 6; + reloadtime = 4 - 4 * reloadtime; + self.reload_grenade_launcher = 0; + if (self.ammo_rockets < 6) { + self.reload_grenade_launcher = + 6 - self.ammo_rockets; } + sprint(self, PRINT_HIGH, "Reloading...\n"); + self.tfstate = self.tfstate | TFSTATE_RELOADING; + Status_Refresh(self); + tWeapon = spawn(); + tWeapon.owner = self; + tWeapon.classname = "timer"; + tWeapon.nextthink = time + reloadtime; + tWeapon.think = W_Reload_grenade_launcher; + self.weaponmodel = ""; + self.weaponframe = 0; } else { - if (self.current_weapon == 2048) { - if (self.ammo_rockets == 0) { - sprint(self, PRINT_HIGH, "Out of grenades\n"); - return; - } - if (self.reload_grenade_launcher == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((6 - self.reload_grenade_launcher) == - self.ammo_rockets) { - sprint(self, PRINT_HIGH, "All grenades are in the clip\n"); - return; - } - if (self.reload_grenade_launcher < self.ammo_rockets) { - Attack_Finished(0.6); - rt = (6 - self.reload_grenade_launcher) / 6; - rt = 4 - 4 * rt; - self.reload_grenade_launcher = 0; - if (self.ammo_rockets < 6) { - self.reload_grenade_launcher = - 6 - self.ammo_rockets; - } - sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | 2; - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + rt; - tWeapon.think = W_Reload_grenade_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else { - if (self.current_weapon == 8192) { - if (self.ammo_rockets == 0) { - sprint(self, PRINT_HIGH, "Out of rockets\n"); - return; - } - if (self.reload_rocket_launcher == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((4 - self.reload_rocket_launcher) == - self.ammo_rockets) { - sprint(self, PRINT_HIGH, "All rockets are in the clip\n"); - return; - } - if (self.reload_rocket_launcher < self.ammo_rockets) { - Attack_Finished(0.8); - rt = (4 - self.reload_rocket_launcher) / 4; - rt = 5 - (5 * rt); - self.reload_rocket_launcher = 0; - if (self.ammo_rockets < 4) { - self.reload_rocket_launcher = - 4 - self.ammo_rockets; - } - sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | 2; - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + rt; - tWeapon.think = W_Reload_rocket_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } + sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); + } + } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { + if (self.ammo_rockets == 0) { + sprint(self, PRINT_HIGH, "Out of rockets\n"); + return; + } + if (self.reload_rocket_launcher == 0) { + sprint(self, PRINT_HIGH, "Clip full\n"); + return; + } + if ((4 - self.reload_rocket_launcher) == + self.ammo_rockets) { + sprint(self, PRINT_HIGH, "All rockets are in the clip\n"); + return; + } + if (self.ammo_rockets >= 1) { + if (self.reload_rocket_launcher >= self.ammo_rockets) + reloadamount = self.ammo_rockets; + else + reloadamount = self.reload_rocket_launcher; + Attack_Finished(0.8); + reloadtime = (4 - reloadamount) / 4; + reloadtime = 5 - (5 * reloadtime); + self.reload_rocket_launcher = 0; + if (self.ammo_rockets < 4) { + self.reload_rocket_launcher = + 4 - self.ammo_rockets; } + sprint(self, PRINT_HIGH, "Reloading...\n"); + self.tfstate = self.tfstate | TFSTATE_RELOADING; + Status_Refresh(self); + tWeapon = spawn(); + tWeapon.owner = self; + tWeapon.classname = "timer"; + tWeapon.nextthink = time + reloadtime; + tWeapon.think = W_Reload_rocket_launcher; + self.weaponmodel = ""; + self.weaponframe = 0; + } else { + sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } } }; diff --git a/weapons.qc b/weapons.qc index d909fef3..11dcd8d1 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1377,7 +1377,7 @@ void () W_SetCurrentAmmo = { self.currentammo = self.ammo_shells; self.items = self.items | 2048; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_shot.mdl"; self.weaponframe = 0; } @@ -1387,7 +1387,7 @@ void () W_SetCurrentAmmo = { } else if (self.current_weapon == 256) { self.currentammo = self.ammo_shells; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_shot2.mdl"; self.weaponframe = 0; } @@ -1397,7 +1397,7 @@ void () W_SetCurrentAmmo = { } else if (self.current_weapon == 512) { self.currentammo = self.ammo_nails; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_nail.mdl"; self.weaponframe = 0; } @@ -1405,7 +1405,7 @@ void () W_SetCurrentAmmo = { self.weapon = 4; } else if (self.current_weapon == 1024) { self.currentammo = self.ammo_nails; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_nail2.mdl"; self.weaponframe = 0; } @@ -1413,7 +1413,7 @@ void () W_SetCurrentAmmo = { self.weapon = 8; } else if (self.current_weapon == 2048) { self.currentammo = self.ammo_rockets; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rock.mdl"; self.weaponframe = 0; } @@ -1421,7 +1421,7 @@ void () W_SetCurrentAmmo = { self.items = self.items | 1024; } else if (self.current_weapon == 8192) { self.currentammo = self.ammo_rockets; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rock2.mdl"; self.weaponframe = 0; } @@ -1429,7 +1429,7 @@ void () W_SetCurrentAmmo = { self.weapon = 32; } else if (self.current_weapon == 65536) { self.currentammo = self.ammo_cells; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_light.mdl"; self.weaponframe = 0; } @@ -1437,7 +1437,7 @@ void () W_SetCurrentAmmo = { self.weapon = 64; } else if (self.current_weapon == 32) { self.currentammo = self.ammo_shells; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_srifle.mdl"; self.weaponframe = 0; } @@ -1445,7 +1445,7 @@ void () W_SetCurrentAmmo = { self.weapon = 1; } else if (self.current_weapon == 64) { self.currentammo = self.ammo_shells; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_srifle.mdl"; self.weaponframe = 0; } @@ -1453,7 +1453,7 @@ void () W_SetCurrentAmmo = { self.weapon = 2; } else if (self.current_weapon == 32768) { self.currentammo = self.ammo_shells; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_asscan.mdl"; self.weaponframe = 0; } @@ -1461,7 +1461,7 @@ void () W_SetCurrentAmmo = { self.weapon = 32; } else if (self.current_weapon == 4096) { self.currentammo = self.ammo_cells; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rock.mdl"; self.weaponframe = 0; } @@ -1469,7 +1469,7 @@ void () W_SetCurrentAmmo = { self.weapon = 16; } else if (self.current_weapon == 16384) { self.currentammo = self.ammo_rockets; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rock2.mdl"; self.weaponframe = 0; } @@ -1481,7 +1481,7 @@ void () W_SetCurrentAmmo = { self.weaponframe = 0; } else if (self.current_weapon == 262144) { self.currentammo = self.ammo_shells; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_shot.mdl"; self.weaponframe = 0; } @@ -1489,7 +1489,7 @@ void () W_SetCurrentAmmo = { self.weapon = 1; } else if (self.current_weapon == 524288) { self.currentammo = self.ammo_nails; - if (!(self.tfstate & 2)) { + if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rail.mdl"; self.weaponframe = 0; } @@ -1558,7 +1558,7 @@ float () W_CheckNoAmmo = { }; void () W_Reload_shotgun = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 2); + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_shot.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); @@ -1566,7 +1566,7 @@ void () W_Reload_shotgun = { }; void () W_Reload_super_shotgun = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 2); + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_shot2.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); @@ -1574,7 +1574,7 @@ void () W_Reload_super_shotgun = { }; void () W_Reload_grenade_launcher = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 2); + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_rock.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); @@ -1582,7 +1582,7 @@ void () W_Reload_grenade_launcher = { }; void () W_Reload_rocket_launcher = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 2); + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_rock2.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); @@ -1590,86 +1590,28 @@ void () W_Reload_rocket_launcher = { }; float () CheckForReload = { - local entity tWeapon; - if (self.current_weapon == WEAP_SHOTGUN) { - if ((self.reload_shotgun >= 8) && (self.ammo_shells > 0)) { - self.reload_shotgun = 0; - - if (self.ammo_shells < 8) - self.reload_shotgun = 8 - self.ammo_shells; - - sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + 2; - tWeapon.think = W_Reload_shotgun; - self.weaponmodel = ""; - self.weaponframe = 0; - return (1); + if (self.reload_shotgun >= 8 && self.ammo_shells > 0) { + TeamFortress_ReloadCurrentWeapon(); + return 1; } } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - - if (self.reload_super_shotgun > 16) - self.reload_super_shotgun = 16; - - if ((self.reload_super_shotgun >= 16) && (self.ammo_shells > 0)) { - self.reload_super_shotgun = 0; - - if (self.ammo_shells < 16) - self.reload_super_shotgun = 16 - self.ammo_shells; - - sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + 3; - tWeapon.think = W_Reload_super_shotgun; - self.weaponmodel = ""; - self.weaponframe = 0; - return (1); + if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) { + TeamFortress_ReloadCurrentWeapon(); + return 1; } } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) { - self.reload_grenade_launcher = 0; - - if (self.ammo_rockets < 6) - self.reload_grenade_launcher = 6 - self.ammo_rockets; - - sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + 4; - tWeapon.think = W_Reload_grenade_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - return (1); + TeamFortress_ReloadCurrentWeapon(); + return 1; } } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) { - self.reload_rocket_launcher = 0; - - if (self.ammo_rockets < 4) - self.reload_rocket_launcher = 4 - self.ammo_rockets; - - sprint(self, PRINT_HIGH, "Reloading...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + 5; - tWeapon.think = W_Reload_rocket_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - return (1); + TeamFortress_ReloadCurrentWeapon(); + return 1; } } - return (0); + return 0; }; void () player_axe1; From 8a13eaf2dcefc71b0ec5153b51aed5cf2d504982 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 6 Jul 2014 21:26:03 +0200 Subject: [PATCH 0018/2474] Add proper ammo checks before firing your weapon --- weapons.qc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 11dcd8d1..7881cefb 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1544,9 +1544,16 @@ float () W_CheckNoAmmo = { || (self.current_weapon == WEAP_SPANNER) || (self.current_weapon == WEAP_MEDIKIT)) return (1); - else if (self.current_weapon == WEAP_INCENDIARY) { + else if (self.current_weapon == WEAP_SUPER_NAILGUN) { + if (self.currentammo >= 4) + return (1); + } else if (self.current_weapon == WEAP_INCENDIARY) { if (self.currentammo >= 3) return (1); + } else if (self.current_weapon == WEAP_SUPER_SHOTGUN + || self.current_weapon == WEAP_NAILGUN) { + if (self.currentammo >= 2) + return (1); } else if (self.currentammo > 0) return (1); From bd86143e0e52cac843a9ea49d53d5fe168e57dfb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 19 Jul 2014 22:11:57 +0200 Subject: [PATCH 0019/2474] Fix so demoman can't move when setting detpack --- demoman.qc | 5 ++--- tfort.qc | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/demoman.qc b/demoman.qc index c9b812c8..b1f1b1a2 100644 --- a/demoman.qc +++ b/demoman.qc @@ -232,10 +232,9 @@ void () TeamFortress_DetpackSet = { return; } - self.is_detpacking = 0; + self.owner.is_detpacking = 0; Menu_Close(self.owner); - self.owner.tfstate = - (self.owner.tfstate - (self.owner.tfstate & TFSTATE_CANT_MOVE)); + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self.owner); sound(self.owner, CHAN_VOICE, "doors/medtry.wav", 1, ATTN_NORM); oldself = self; diff --git a/tfort.qc b/tfort.qc index 0180f0a8..524becf7 100644 --- a/tfort.qc +++ b/tfort.qc @@ -839,7 +839,7 @@ void (entity p) TeamFortress_SetSpeed = { local entity te; stuffcmd(p, "cl_movespeedkey 1\n"); - if (p.tfstate & TFSTATE_CANT_MOVE || p.is_building == 1) { + if (p.tfstate & TFSTATE_CANT_MOVE || p.is_building == 1 || p.is_detpacking > 0) { #ifdef STOP_MOUSE_MOVEMENT stuffcmd(p, "m_forward 0\n"); stuffcmd(p, "m_side 0\n"); From cb7f3581fbcda9b3cf11e6eb0bba3f399d3e03ba Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 20 Jul 2014 00:17:46 +0200 Subject: [PATCH 0020/2474] Implement free suicides (closes #50) --- client.qc | 112 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/client.qc b/client.qc index 43f9c999..0d999714 100644 --- a/client.qc +++ b/client.qc @@ -622,52 +622,114 @@ void () respawn = { localcmd("restart\n"); }; +float () CloseToSpawnPoint = { + local entity spot = nil; + local entity te = nil; + local float i; + + if (self.team_no == 1) { + spot = find(world, team_str_home, "ts1"); + for(i = 1; i < 30; i++) { + te = findradius(spot.origin, 85); + while (te != world) { + if (te == self) + return 1; + te = te.chain; + } + spot = find(spot, team_str_home, "ts1"); + } + } else if (self.team_no == 2) { + spot = find(world, team_str_home, "ts2"); + for(i = 1; i < 30; i++) { + te = findradius(spot.origin, 85); + while (te != world) { + if (te == self) + return 1; + te = te.chain; + } + spot = find(spot, team_str_home, "ts2"); + } + } else if (self.team_no == 3) { + spot = find(world, team_str_home, "ts3"); + for(i = 1; i < 30; i++) { + te = findradius(spot.origin, 85); + while (te != world) { + if (te == self) + return 1; + te = te.chain; + } + spot = find(spot, team_str_home, "ts3"); + } + } else if (self.team_no == 4) { + spot = find(world, team_str_home, "ts4"); + for(i = 1; i < 30; i++) { + te = findradius(spot.origin, 85); + while (te != world) { + if (te == self) + return 1; + te = te.chain; + } + spot = find(spot, team_str_home, "ts4"); + } + } + + return 0; +}; + void () ClientKill = { local entity te; + local float timeleft; if (self.has_disconnected == 1) return; - if (self.suicide_time > time) - return; if (self.deadflag) return; if (self.playerclass == PC_UNDEFINED) return; - TF_zoom_reset_death(self); - - // players can't suicide again for 10 seconds - self.suicide_time = time + 5 + random() * 5; + if (self.suicide_time > time) { + timeleft = self.suicide_time - time; + sprint(self, PRINT_HIGH, "You have to wait ", ftos(ceil(timeleft)), " more seconds to suicide\n"); + return; + } - bprint(PRINT_MEDIUM, self.netname, " suicides\n"); + TF_zoom_reset_death(self); set_suicide_frame(); self.modelindex = modelindex_player; - // If infected, give the medic a frag - if (self.tfstate & TFSTATE_INFECTED) { - te = find(world, classname, "timer"); - while (te) { - if ((te.owner == self) && (te.think == BioInfection_Decay)) { - logfrag(te, self); - TF_AddFrags(te.enemy, 1); - } - te = find(te, classname, "timer"); - } - } else - logfrag(self, self); - - TF_AddFrags(self, -1); - self.weaponmodel = ""; self.view_ofs = '0 0 -8'; self.movetype = MOVETYPE_NONE; - TeamFortress_RemoveTimers(); - TeamFortress_SetupRespawn(TRUE); + + // players can't suicide again for 10 seconds + self.suicide_time = time + 5 + random() * 5; + + if (!(self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint())) { + bprint(PRINT_MEDIUM, self.netname, " suicides\n"); + + // If infected, give the medic a frag + if (self.tfstate & TFSTATE_INFECTED) { + te = find(world, classname, "timer"); + while (te) { + if ((te.owner == self) && (te.think == BioInfection_Decay)) { + logfrag(te, self); + TF_AddFrags(te.enemy, 1); + } + te = find(te, classname, "timer"); + } + } else + logfrag(self, self); + + TF_AddFrags(self, -1); + TeamFortress_SetupRespawn(TRUE); + self.th_die(); + } else { + TeamFortress_SetupRespawn(FALSE); + } self.health = -1; - self.th_die(); self.deadflag = DEAD_RESPAWNABLE; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; self.takedamage = 0; From 3482c4aeca73eb1e4772c91960302f7fe2bfb061 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 20 Jul 2014 00:34:25 +0200 Subject: [PATCH 0021/2474] Add hook_out field to silence error messages (fixes #29) --- qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/qw.qc b/qw.qc index 238f15be..969bf27f 100644 --- a/qw.qc +++ b/qw.qc @@ -19,6 +19,7 @@ typedef void (float) f_void_float; .float tp_grenades_2; // 2nd type of grenades being carried .float tp_grenade_switch; // Set to 1 if +gren1 and +gren2 switch places +.float hook_out; // Dummy field for hook to silence error messages .float got_aliases; // TRUE if the player has TeamFortress aliases .float cheat_check; // Time when we'll next check for team cheats .float is_removed; // TRUE if the entity has been removed From cad6489bcf76e48b799c68b2f02fb94e35ccd5e7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 21 Jul 2014 15:55:41 +0200 Subject: [PATCH 0022/2474] Changing class as a newspawn will now change class instantly --- tfort.qc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index 524becf7..543f69e8 100644 --- a/tfort.qc +++ b/tfort.qc @@ -8,6 +8,8 @@ void () TeamFortress_Regenerate; void () TeamFortress_CheckforCheats; void () TeamFortress_RegenerateCells; +float () CloseToSpawnPoint; + void () UseSpecialSkill = { local vector src; @@ -72,8 +74,12 @@ void () TeamFortress_ChangeClass = { return; } self.nextpc = self.impulse - 100; - sprint(self, PRINT_HIGH, "After dying, you will return as a "); - TeamFortress_PrintClassName(self, self.nextpc, self.tfstate & 8); + if (self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint() && self.suicide_time <= time) { + ClientKill(); + } else { + sprint(self, PRINT_HIGH, "After dying, you will return as a "); + TeamFortress_PrintClassName(self, self.nextpc, self.tfstate & 8); + } self.immune_to_check = time + 10; return; } From a76a88e48d300edad0deb31d2e856630c4b833b8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 21 Jul 2014 16:02:41 +0200 Subject: [PATCH 0023/2474] Priming a grenade will now make it impossible to suicide or change class for 10 seconds --- tfort.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tfort.qc b/tfort.qc index 543f69e8..2db706b7 100644 --- a/tfort.qc +++ b/tfort.qc @@ -501,6 +501,7 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "Grenade"; if (self.no_grenades_1 > 0) { + self.suicide_time = time + 10; self.no_grenades_1 = self.no_grenades_1 - 1; if (gtype == 6) { newmis = spawn(); @@ -562,6 +563,7 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "Grenade"; if (self.no_grenades_2 > 0) { + self.suicide_time = time + 10; self.no_grenades_2 = self.no_grenades_2 - 1; if (gtype == 6) { newmis = spawn(); From 56e2c0c3981b131e18eace6a9cbef20062553869 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 21 Jul 2014 16:11:40 +0200 Subject: [PATCH 0024/2474] Disallow choosing team/class during intermission (fixes #66) --- tfort.qc | 3 +++ tforttm.qc | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tfort.qc b/tfort.qc index 2db706b7..7d4ef640 100644 --- a/tfort.qc +++ b/tfort.qc @@ -49,6 +49,9 @@ void () TeamFortress_ChangeClass = { local entity spot; local entity te; + if ((intermission_running != 0) || (intermission_exittime > time)) + return; + if (self.playerclass != 0) { if ((deathmatch != 3) && (cb_prematch_time < time)) return; diff --git a/tforttm.qc b/tforttm.qc index d9a7e50e..2f780728 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -118,6 +118,9 @@ float (float tno) TeamFortress_TeamSet = { local float tc; local string team; + if ((intermission_running != 0) || (intermission_exittime > time)) + return (0); + if (tno == 1) team = "blue team"; else if (tno == 2) From cc5d959ce9c248661d78482c7597ec6cd6a032b8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 21 Jul 2014 16:14:59 +0200 Subject: [PATCH 0025/2474] Add alias for class menu (closes #26) --- defs.h | 1 + tforthlp.qc | 1 + 2 files changed, 2 insertions(+) diff --git a/defs.h b/defs.h index b6194269..3d4f1c4e 100644 --- a/defs.h +++ b/defs.h @@ -322,6 +322,7 @@ /*======================================================*/ /* Impulse Defines */ /*======================================================*/ +#define TF_CLASSMENU 5 #define TF_WEAPNEXT 10 #define TF_WEAPPREV 12 // Alias check to see whether they already have the aliases diff --git a/tforthlp.qc b/tforthlp.qc index da6b5a09..d5f0cc16 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -66,6 +66,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("randompc", TF_CHANGEPC + PC_RANDOM, 0); TeamFortress_Alias("is_aliased", TF_ALIAS_CHECK, 0); } else if (self.motd == 25) { + TeamFortress_Alias("menu", TF_CLASSMENU, 0); TeamFortress_Alias("weapnext", TF_WEAPNEXT, 0); TeamFortress_Alias("weapprev", TF_WEAPPREV, 0); TeamFortress_Alias("weaplast", TF_WEAPLAST, 0); From 8b1f813173aa4825110facdbf4370310c9a5105b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 21 Jul 2014 21:32:09 +0200 Subject: [PATCH 0026/2474] Clean up ChangeClass code --- client.qc | 3 +-- menu.qc | 17 +++-------------- tfort.qc | 21 +++++++++------------ tforttm.qc | 6 ++---- weapons.qc | 4 ++-- 5 files changed, 17 insertions(+), 34 deletions(-) diff --git a/client.qc b/client.qc index 0d999714..e147206a 100644 --- a/client.qc +++ b/client.qc @@ -965,8 +965,7 @@ void () PutClientInServer = { if (self.playerclass == 0) { if (TeamFortress_TeamIsCivilian(self.team_no)) { - self.impulse = 1; - TeamFortress_ChangeClass(); + TeamFortress_ChangeClass(11); } } if ((deathmatch == 3) && (self.nextpc != 0)) { diff --git a/menu.qc b/menu.qc index e2c8730c..0df69204 100644 --- a/menu.qc +++ b/menu.qc @@ -23,7 +23,7 @@ float (float tno) TeamFortress_TeamIsCivilian; float (float tno) TeamFortress_TeamGetNoPlayers; float () TeamFortress_GetNoPlayers; -void () TeamFortress_ChangeClass; +void (float inp) TeamFortress_ChangeClass; void (entity p) TeamFortress_SetSkin; void (float timer) TeamFortress_SetDetpack; @@ -190,19 +190,8 @@ void () Menu_Team = { }; void (float inp) Menu_Class_Input = { - local float new_class; - new_class = 0; - - if ((inp > 10) || (inp < 1)) - return; - - self.impulse = inp + 100; - - if (self.playerclass != 0) - new_class = 1; - - TeamFortress_ChangeClass(); - self.impulse = 0; + if (inp > 0 && inp <= 10) + TeamFortress_ChangeClass(inp); }; void () Menu_Class = { diff --git a/tfort.qc b/tfort.qc index 7d4ef640..96259877 100644 --- a/tfort.qc +++ b/tfort.qc @@ -45,7 +45,7 @@ void () UseSpecialSkill = { } }; -void () TeamFortress_ChangeClass = { +void (float inp) TeamFortress_ChangeClass = { local entity spot; local entity te; @@ -60,23 +60,23 @@ void () TeamFortress_ChangeClass = { sprint(self, PRINT_HIGH, "You cannot change class\n"); return; } - if (!IsLegalClass(self.impulse - 100)) { + if (!IsLegalClass(inp)) { sprint(self, PRINT_HIGH, "Your team cannot play that class\n"); TeamFortress_DisplayLegalClasses(); return; } - if ((spy_off == 1) && ((self.impulse - 100) == 8)) { + if ((spy_off == 1) && (inp == 8)) { sprint(self, PRINT_HIGH, "The spy class has been disabled on the server by the administrator\n"); return; } - if (ClassIsRestricted(self.team_no, (self.impulse - 100))) { + if (ClassIsRestricted(self.team_no, inp)) { sprint(self, PRINT_HIGH, "Your team already has enough of that class\n"); return; } - self.nextpc = self.impulse - 100; + self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint() && self.suicide_time <= time) { ClientKill(); } else { @@ -99,26 +99,23 @@ void () TeamFortress_ChangeClass = { sprint(self, PRINT_HIGH, "You have no lives left\n"); return; } - if (!IsLegalClass((self.impulse - 100)) && (self.impulse != 1)) { + if (!IsLegalClass(inp) && (inp != 11)) { sprint(self, PRINT_HIGH, "You cannot play that class on this map\n"); TeamFortress_DisplayLegalClasses(); return; } - if ((spy_off == 1) && ((self.impulse - 100) == 8)) { + if ((spy_off == 1) && (inp == 8)) { sprint(self, PRINT_HIGH, "The spy class has been disabled on the server by the administrator\n"); return; } - if (ClassIsRestricted(self.team_no, (self.impulse - 100))) { + if (ClassIsRestricted(self.team_no, inp)) { sprint(self, PRINT_HIGH, "Your team has enough of that class\n"); return; } TeamFortress_ExecClassScript(self); - if (self.impulse != 1) - self.playerclass = self.impulse - 100; - else - self.playerclass = 11; + self.playerclass = inp; self.nextpc = 0; self.takedamage = 2; diff --git a/tforttm.qc b/tforttm.qc index 2f780728..a38d92a6 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -177,8 +177,7 @@ float (float tno) TeamFortress_TeamSet = { SetTeamName(self); if (self.playerclass == 0) { if (TeamFortress_TeamIsCivilian(self.team_no)) { - self.impulse = 1; - TeamFortress_ChangeClass(); + TeamFortress_ChangeClass(11); } } return (1); @@ -204,8 +203,7 @@ float (float tno) TeamFortress_TeamSet = { SetTeamName(self); if (self.playerclass == 0) { if (TeamFortress_TeamIsCivilian(self.team_no)) { - self.impulse = 1; - TeamFortress_ChangeClass(); + TeamFortress_ChangeClass(11); } } return (1); diff --git a/weapons.qc b/weapons.qc index 7881cefb..445844dd 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2286,8 +2286,8 @@ void () DeadImpulses = { TeamFortress_SetZoom2x(); else if (self.impulse == TF_SHOWLEGALCLASSES) TeamFortress_DisplayLegalClasses(); - else if ((self.impulse > 100) && (self.impulse <= (100 + 10))) { - TeamFortress_ChangeClass(); + else if ((self.impulse > 100) && (self.impulse <= 110)) { + TeamFortress_ChangeClass(self.impulse - 100); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGETEAM) && (deathmatch == 3) && (cb_prematch_time < time)) { Menu_Team(); From e5f6580df560802a1302f63df8891d6377790139 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 21 Jul 2014 21:32:59 +0200 Subject: [PATCH 0027/2474] Fix so randompc class can be chosen from menu (fixes #62) --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 445844dd..193fb26d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2402,7 +2402,7 @@ void () W_WeaponFrame = { } if (self.menu_input) { - if (self.impulse > 0 && self.impulse <= 9) { + if (self.impulse > 0 && self.impulse <= 10) { Menu_Input(self.impulse); return; } From e00c2da483b0b57848d7dc1995f437c778801195 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 21 Jul 2014 21:40:58 +0200 Subject: [PATCH 0028/2474] Class change echo no longer echoes (random) if currently playing randompc --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 96259877..0dc35ca4 100644 --- a/tfort.qc +++ b/tfort.qc @@ -81,7 +81,7 @@ void (float inp) TeamFortress_ChangeClass = { ClientKill(); } else { sprint(self, PRINT_HIGH, "After dying, you will return as a "); - TeamFortress_PrintClassName(self, self.nextpc, self.tfstate & 8); + TeamFortress_PrintClassName(self, self.nextpc, 0); } self.immune_to_check = time + 10; return; From 5aef8147eb705b49994584c3cac59f2550723932 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 22 Jul 2014 17:45:34 +0200 Subject: [PATCH 0029/2474] Clean up Dispenser code --- engineer.qc | 140 ++++++++++++++++++++++++++++++++++++++++++++++------ menu.qc | 75 +++------------------------- 2 files changed, 134 insertions(+), 81 deletions(-) diff --git a/engineer.qc b/engineer.qc index 843172c8..d704f86b 100644 --- a/engineer.qc +++ b/engineer.qc @@ -9,6 +9,9 @@ void () EMPGrenadeExplode; void () TeamFortress_FinishedBuilding; void () Dispenser_Die; void () CheckDistance; +void (entity disp) Engineer_Dispenser_InsertAmmo; +void (entity disp) Engineer_Dispenser_InsertArmor; +void (entity disp) Engineer_Dispenser_Repair; float (entity obj, entity builder) CheckArea; void () LaserBolt_Think = { @@ -613,21 +616,14 @@ void () Dispenser_Die = { void (entity disp) Engineer_UseDispenser = { local entity dist_checker; - local string st; - sprint(self, PRINT_HIGH, "Dispenser has "); - st = ftos(disp.health); - sprint(self, PRINT_HIGH, st, " health\n"); - st = ftos(disp.ammo_shells); - sprint(self, PRINT_HIGH, st, " shells, "); - st = ftos(disp.ammo_nails); - sprint(self, PRINT_HIGH, st, " nails, "); - st = ftos(disp.ammo_rockets); - sprint(self, PRINT_HIGH, st, " rockets\n"); - st = ftos(disp.ammo_cells); - sprint(self, PRINT_HIGH, st, " cells, and "); - st = ftos(disp.armorvalue); - sprint(self, PRINT_HIGH, st, " armor\n"); + sprint(self, PRINT_HIGH, "Dispenser has ", ftos(disp.health), " health and current stock:\n"); + sprint(self, PRINT_HIGH, ftos(disp.ammo_shells), " shells, "); + sprint(self, PRINT_HIGH, ftos(disp.ammo_nails), " nails, "); + sprint(self, PRINT_HIGH, ftos(disp.ammo_rockets), " rockets, "); + sprint(self, PRINT_HIGH, ftos(disp.ammo_cells), " cells and "); + sprint(self, PRINT_HIGH, ftos(disp.armorvalue), " armor\n"); + self.building = disp; Menu_EngineerFix_Dispenser(); dist_checker = spawn(); @@ -638,6 +634,122 @@ void (entity disp) Engineer_UseDispenser = { dist_checker.nextthink = time + 0.3; }; +void (entity disp) Engineer_Dispenser_InsertAmmo = { + local float ammo, shells, nails, rockets, cells; + + ammo = (20 * 2); + if (ammo > self.ammo_shells) { + ammo = self.ammo_shells; + } + if (ammo > (400 - disp.ammo_shells)) { + ammo = (400 - disp.ammo_shells); + } + self.ammo_shells = (self.ammo_shells - ammo); + disp.ammo_shells = (disp.ammo_shells + ammo); + shells = ammo; + ammo = (20 * 2); + if (ammo > self.ammo_nails) { + ammo = self.ammo_nails; + } + if (ammo > (600 - disp.ammo_nails)) { + ammo = (600 - disp.ammo_nails); + } + self.ammo_nails = (self.ammo_nails - ammo); + disp.ammo_nails = (disp.ammo_nails + ammo); + nails = ammo; + ammo = (10 * 2); + if (ammo > self.ammo_rockets) { + ammo = self.ammo_rockets; + } + if (ammo > (300 - disp.ammo_rockets)) { + ammo = (300 - disp.ammo_rockets); + } + self.ammo_rockets = (self.ammo_rockets - ammo); + disp.ammo_rockets = (disp.ammo_rockets + ammo); + rockets = ammo; + ammo = (10 * 2); + if (ammo > self.ammo_cells) { + ammo = self.ammo_cells; + } + if (ammo > (400 - disp.ammo_cells)) { + ammo = (400 - disp.ammo_cells); + } + self.ammo_cells = (self.ammo_cells - ammo); + disp.ammo_cells = (disp.ammo_cells + ammo); + cells = ammo; + + if ((shells + nails + rockets + cells) > 0) { + W_SetCurrentAmmo(); + sprint(self, PRINT_HIGH, "You inserted "); + if (shells > 0) + sprint(self, PRINT_HIGH, ftos(shells), " shells"); + if (nails > 0) { + if (shells > 0 && (rockets > 0 || cells > 0)) + sprint(self, PRINT_HIGH, ", "); + else if (shells > 0) + sprint(self, PRINT_HIGH, " and "); + sprint(self, PRINT_HIGH, ftos(nails), " nails"); + } + if (rockets > 0) { + if ((shells > 0 || nails > 0) && cells > 0) + sprint(self, PRINT_HIGH, ", "); + else if (shells > 0 || nails > 0) + sprint(self, PRINT_HIGH, " and "); + sprint(self, PRINT_HIGH, ftos(rockets), " rockets"); + } + if (cells > 0) { + if (shells > 0 || nails > 0 || rockets > 0) + sprint(self, PRINT_HIGH, " and "); + sprint(self, PRINT_HIGH, ftos(cells), " cells"); + } + sprint(self, PRINT_HIGH, " into Dispenser\n"); + } +}; + +void (entity disp) Engineer_Dispenser_InsertArmor = { + local float armor; + + armor = (40 * 2); + if (armor > self.armorvalue) { + armor = self.armorvalue; + } + if (armor > (500 - disp.armorvalue)) { + armor = (500 - disp.armorvalue); + } + self.armorvalue = (self.armorvalue - armor); + disp.armorvalue = (disp.armorvalue + armor); + + if (self.armorvalue == 0) { + self.armortype = 0; + self.armorclass = 0; + self.items = (self.items - (self.items & ((IT_ARMOR1 | IT_ARMOR2) | IT_ARMOR3))); + } + + if (armor > 0) + sprint(self, PRINT_HIGH, "You inserted ", ftos(armor), " armor into Dispenser\n"); + else if (disp.armorvalue == BUILD_DISPENSER_MAX_ARMOR) + sprint(self, PRINT_HIGH, "Your Dispenser cannot carry more armor\n"); +}; + +void (entity disp) Engineer_Dispenser_Repair = { + local float metalcost, healamount; + + if (disp.health == disp.max_health) + return; + + metalcost = ceil((disp.max_health - disp.health) / 5); + if (metalcost > self.ammo_cells) + metalcost = self.ammo_cells; + self.ammo_cells = self.ammo_cells - metalcost; + + healamount = floor(metalcost * 5); + disp.health = disp.health + healamount; + + if (metalcost > 0) + sprint(self, PRINT_HIGH, "You repaired your Dispenser with ", ftos(healamount), + " health at the cost of ", ftos(metalcost), " cells\n"); +}; + void (entity gun) Engineer_UseSentryGun = { local entity dist_checker; local string st; diff --git a/menu.qc b/menu.qc index 0df69204..59c514eb 100644 --- a/menu.qc +++ b/menu.qc @@ -30,6 +30,9 @@ void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; void (float type) TeamFortress_DropAmmo; +void (entity disp) Engineer_Dispenser_InsertAmmo; +void (entity disp) Engineer_Dispenser_InsertArmor; +void (entity disp) Engineer_Dispenser_Repair; void (entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage; @@ -614,80 +617,18 @@ void () Menu_Engineer = { }; void (float inp) Menu_EngineerFix_Dispenser_Input = { - local float metalcost; - local float am; - - if ((self.classname != "player") || (self.building == world)) { + if (self.classname != "player" || self.building == world) return; - } + if (inp == 1) { - am = (20 * 2); - if (am > self.ammo_shells) { - am = self.ammo_shells; - } - if (am > (400 - self.building.ammo_shells)) { - am = (400 - self.building.ammo_shells); - } - self.ammo_shells = (self.ammo_shells - am); - self.building.ammo_shells = (self.building.ammo_shells + am); - am = (20 * 2); - if (am > self.ammo_nails) { - am = self.ammo_nails; - } - if (am > (600 - self.building.ammo_nails)) { - am = (600 - self.building.ammo_nails); - } - self.ammo_nails = (self.ammo_nails - am); - self.building.ammo_nails = (self.building.ammo_nails + am); - am = (10 * 2); - if (am > self.ammo_rockets) { - am = self.ammo_rockets; - } - if (am > (300 - self.building.ammo_rockets)) { - am = (300 - self.building.ammo_rockets); - } - self.ammo_rockets = (self.ammo_rockets - am); - self.building.ammo_rockets = (self.building.ammo_rockets + am); - am = (10 * 2); - if (am > self.ammo_cells) { - am = self.ammo_cells; - } - if (am > (400 - self.building.ammo_cells)) { - am = (400 - self.building.ammo_cells); - } - self.ammo_cells = (self.ammo_cells - am); - self.building.ammo_cells = (self.building.ammo_cells + am); + Engineer_Dispenser_InsertAmmo(self.building); } else if (inp == 2) { - am = (40 * 2); - if (am > self.armorvalue) { - am = self.armorvalue; - } - if (am > (500 - self.building.armorvalue)) { - am = (500 - self.building.armorvalue); - } - self.armorvalue = (self.armorvalue - am); - self.building.armorvalue = (self.building.armorvalue + am); + Engineer_Dispenser_InsertArmor(self.building); } else if (inp == 3) { - metalcost = - ((self.building.max_health - - self.building.health) / 5); - if (metalcost > self.ammo_cells) { - metalcost = self.ammo_cells; - } - self.ammo_cells = (self.ammo_cells - metalcost); - self.building.health = - (self.building.health + (metalcost * 5)); + Engineer_Dispenser_Repair(self.building); } self.building = world; - bound_other_ammo(self); - if (self.armorvalue == 0) { - self.armortype = 0; - self.armorclass = 0; - self.items = - (self.items - (self.items & ((8192 | 16384) | 32768))); - } - W_SetCurrentAmmo(); }; void () Menu_EngineerFix_Dispenser = { From 07da5d45c2d1e7f9c64a0f44be6616c33b10177a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 22 Jul 2014 17:55:49 +0200 Subject: [PATCH 0030/2474] Engineer now repairs Dispenser on spanner hit --- engineer.qc | 2 ++ menu.qc | 13 +++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/engineer.qc b/engineer.qc index d704f86b..444ed8d0 100644 --- a/engineer.qc +++ b/engineer.qc @@ -617,6 +617,8 @@ void () Dispenser_Die = { void (entity disp) Engineer_UseDispenser = { local entity dist_checker; + Engineer_Dispenser_Repair(disp); + sprint(self, PRINT_HIGH, "Dispenser has ", ftos(disp.health), " health and current stock:\n"); sprint(self, PRINT_HIGH, ftos(disp.ammo_shells), " shells, "); sprint(self, PRINT_HIGH, ftos(disp.ammo_nails), " nails, "); diff --git a/menu.qc b/menu.qc index 59c514eb..c457b969 100644 --- a/menu.qc +++ b/menu.qc @@ -624,8 +624,6 @@ void (float inp) Menu_EngineerFix_Dispenser_Input = { Engineer_Dispenser_InsertAmmo(self.building); } else if (inp == 2) { Engineer_Dispenser_InsertArmor(self.building); - } else if (inp == 3) { - Engineer_Dispenser_Repair(self.building); } self.building = world; @@ -633,8 +631,8 @@ void (float inp) Menu_EngineerFix_Dispenser_Input = { void () Menu_EngineerFix_Dispenser = { local string s_action = "Dispenser maintenance:\n\n"; - local string s_ammo, s_armor, s_repair; - local string s_nothing = "\n—‘ Nothing "; + local string s_ammo, s_armor; + local string s_nothing = "\n—‘ Nothing \n\n"; if ((self.ammo_shells > 0 && self.building.ammo_shells < 400) || (self.ammo_nails > 0 && self.building.ammo_nails < 600) @@ -649,12 +647,7 @@ void () Menu_EngineerFix_Dispenser = { else s_armor = "\n"; - if (self.building.health < self.building.max_health) - s_repair = "•‘ Repair \n"; - else - s_repair = "\n"; - - Status_Menu(self, Menu_EngineerFix_Dispenser_Input, s_action, s_ammo, s_armor, s_repair, s_nothing); + Status_Menu(self, Menu_EngineerFix_Dispenser_Input, s_action, s_ammo, s_armor, s_nothing); }; void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { From 70f14a744ecf71c5896cef881dff6ac60140fc07 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 23 Jul 2014 19:09:46 +0200 Subject: [PATCH 0031/2474] Clean up Sentry Gun code --- engineer.qc | 120 ++++++++++++++++++++++++++++++++++++++++++++++------ menu.qc | 90 ++++++--------------------------------- 2 files changed, 121 insertions(+), 89 deletions(-) diff --git a/engineer.qc b/engineer.qc index 444ed8d0..fd17d3e4 100644 --- a/engineer.qc +++ b/engineer.qc @@ -12,6 +12,10 @@ void () CheckDistance; void (entity disp) Engineer_Dispenser_InsertAmmo; void (entity disp) Engineer_Dispenser_InsertArmor; void (entity disp) Engineer_Dispenser_Repair; +void (entity disp) Engineer_SentryGun_ShowMenu; +void (entity disp) Engineer_SentryGun_InsertAmmo; +void (entity disp) Engineer_SentryGun_Upgrade; +void (entity disp) Engineer_SentryGun_Repair; float (entity obj, entity builder) CheckArea; void () LaserBolt_Think = { @@ -753,22 +757,38 @@ void (entity disp) Engineer_Dispenser_Repair = { }; void (entity gun) Engineer_UseSentryGun = { - local entity dist_checker; - local string st; - sprint(self, PRINT_HIGH, "Level "); - st = ftos(gun.weapon); - sprint(self, PRINT_HIGH, st, " Sentry gun has "); - st = ftos(floor(gun.health)); - sprint(self, PRINT_HIGH, st, " health, "); - st = ftos(floor(gun.ammo_shells)); - sprint(self, PRINT_HIGH, st, " shells"); + sprint(self, PRINT_HIGH, ftos(gun.weapon), " sentry gun has "); + + if (gun.health == gun.max_health) + sprint(self, PRINT_HIGH, "max health"); + else + sprint(self, PRINT_HIGH, ftos(floor(gun.health)), " health"); + + if (gun.weapon < 3) + sprint(self, PRINT_HIGH, " and "); + else + sprint(self, PRINT_HIGH, ", "); + + if (gun.ammo_shells == gun.maxammo_shells) + sprint(self, PRINT_HIGH, "max shells"); + else + sprint(self, PRINT_HIGH, ftos(floor(gun.ammo_shells)), " shells"); + if (gun.weapon == 3) { - st = ftos(floor(gun.ammo_rockets)); - sprint(self, PRINT_HIGH, ", ", st, " rockets"); + if (gun.ammo_rockets == gun.maxammo_rockets) + sprint(self, PRINT_HIGH, " and max rockets"); + else + sprint(self, PRINT_HIGH, " and ", ftos(floor(gun.ammo_rockets)), " rockets"); } sprint(self, PRINT_HIGH, "\n"); - self.building = gun; + + Engineer_SentryGun_ShowMenu(self.building); +}; + +void (entity gun) Engineer_SentryGun_ShowMenu = { + local entity dist_checker; + dist_checker = spawn(); dist_checker.classname = "timer"; dist_checker.owner = self; @@ -778,6 +798,82 @@ void (entity gun) Engineer_UseSentryGun = { Menu_EngineerFix_SentryGun(); }; +void (entity gun) Engineer_SentryGun_InsertAmmo = { + local float shells = 0, rockets = 0; + + shells = 40; + if (shells > self.ammo_shells) + shells = self.ammo_shells; + if (shells > (gun.maxammo_shells - gun.ammo_shells)) + shells = gun.maxammo_shells - gun.ammo_shells; + self.ammo_shells = self.ammo_shells - shells; + gun.ammo_shells = gun.ammo_shells + shells; + + if (gun.weapon == 3) { + rockets = 20; + if (rockets > self.ammo_rockets) + rockets = self.ammo_rockets; + if (rockets > (gun.maxammo_rockets - gun.ammo_rockets)) + rockets = gun.maxammo_rockets - gun.ammo_rockets; + self.ammo_rockets = self.ammo_rockets - rockets; + gun.ammo_rockets = gun.ammo_rockets + rockets; + } + + if ((shells + rockets) > 0) { + W_SetCurrentAmmo(); + sprint(self, PRINT_HIGH, "You insert "); + if (shells > 0) + sprint(self, PRINT_HIGH, ftos(floor(shells)), " shells"); + if (rockets > 0) { + if (shells > 0) + sprint(self, PRINT_HIGH, " and "); + sprint(self, PRINT_HIGH, ftos(floor(rockets)), " rockets"); + } + sprint(self, PRINT_HIGH, " into sentry gun\n"); + } +}; + +void (entity gun) Engineer_SentryGun_Upgrade = { + if (self.ammo_cells < 130) + return; + + self.ammo_cells = self.ammo_cells - 130; + gun.weapon = gun.weapon + 1; + gun.max_health = gun.max_health * 1.2; + gun.health = gun.max_health; + gun.maxammo_shells = gun.maxammo_shells * 1.2; + if (gun.weapon == 2) { + sound(gun, 3, "weapons/turrset.wav", 1, 1); + gun.think = lvl2_sentry_stand; + gun.skin = 1; + } else { + sound(gun, 3, "weapons/turrset.wav", 1, 1); + gun.think = lvl3_sentry_stand; + gun.skin = 2; + } + sprint(self, PRINT_HIGH, "You upgrade the sentry gun to level "); + sprint(self, PRINT_HIGH, ftos(gun.weapon), "\n"); +}; + +void (entity gun) Engineer_SentryGun_Repair = { + local float metalcost, healamount; + + metalcost = ceil((gun.max_health - gun.health) / 5); + if (metalcost > self.ammo_cells) + metalcost = self.ammo_cells; + self.ammo_cells = self.ammo_cells - metalcost; + + healamount = floor(metalcost * 5); + gun.health = gun.health + healamount; + + if (gun.health > gun.max_health) + gun.health = gun.max_health; + + if (metalcost > 0) + sprint(self, PRINT_HIGH, "Sentry Gun repaired for ", ftos(healamount), + " health using ", ftos(metalcost), " cells\n"); +}; + void (entity gunhead) CheckSentry = { local vector dist; local entity gunbase; diff --git a/menu.qc b/menu.qc index c457b969..14ca7858 100644 --- a/menu.qc +++ b/menu.qc @@ -33,6 +33,9 @@ void (float type) TeamFortress_DropAmmo; void (entity disp) Engineer_Dispenser_InsertAmmo; void (entity disp) Engineer_Dispenser_InsertArmor; void (entity disp) Engineer_Dispenser_Repair; +void (entity disp) Engineer_SentryGun_InsertAmmo; +void (entity disp) Engineer_SentryGun_Upgrade; +void (entity disp) Engineer_SentryGun_Repair; void (entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage; @@ -682,86 +685,19 @@ void () Menu_EngineerFix_SentryGun_Rotate = { }; void (float inp) Menu_EngineerFix_SentryGun_Input = { - local float am; - local float metalcost; - local string st; - - if (self.building.real_owner.has_sentry == 0) { + if (!self.building.real_owner.has_sentry || self.building.real_owner != self + || self.classname != "player" || self.building == world) return; - } - if ((self.classname != "player") || (self.building == world)) { - return; - } - if (inp == 1) { - am = (20 * 2); - if (am > self.ammo_shells) { - am = self.ammo_shells; - } - if (am > - (self.building.maxammo_shells - self.building.ammo_shells)) { - am = (self.building.maxammo_shells - - self.building.ammo_shells); - } - self.ammo_shells = (self.ammo_shells - am); - self.building.ammo_shells = (self.building.ammo_shells + am); - if (self.building.weapon == 3) { - am = (10 * 2); - if (am > self.ammo_rockets) { - am = self.ammo_rockets; - } - if (am > - (self.building.maxammo_rockets - - self.building.ammo_rockets)) { - am = (self.building.maxammo_rockets - - self.building.ammo_rockets); - } - self.ammo_rockets = (self.ammo_rockets - am); - self.building.ammo_rockets = (self.building.ammo_rockets + am); - } - } else { - if (((self.building.weapon < 3) && (inp == 2)) && - (self.ammo_cells >= 130)) { - self.ammo_cells = self.ammo_cells - 130; - self.building.weapon = self.building.weapon + 1; - self.building.max_health = self.building.max_health * 1.2; - self.building.health = self.building.max_health; - self.building.maxammo_shells = - self.building.maxammo_shells * 1.2; - if (self.building.weapon == 2) { - sound(self.building, 3, "weapons/turrset.wav", 1, 1); - self.building.think = lvl2_sentry_stand; - self.building.skin = 1; - } else { - sound(self.building, 3, "weapons/turrset.wav", 1, 1); - self.building.think = lvl3_sentry_stand; - self.building.skin = 2; - } - sprint(self, PRINT_HIGH, - "You upgrade the sentry gun to level "); - st = ftos(self.building.weapon); - sprint(self, PRINT_HIGH, st, "\n"); - } else if (inp == 3) { - metalcost = - ((self.building.max_health - self.building.health) / 5); - if (metalcost > self.ammo_cells) { - metalcost = self.ammo_cells; - } - self.ammo_cells = self.ammo_cells - metalcost; - self.building.health = self.building.health + metalcost * 5; - } else if (inp == 4) { - if (self.building.real_owner == self) - Menu_EngineerFix_SentryGun_Rotate(); - } - } - bound_other_ammo(self); - if (self.armorvalue == 0) { - self.armortype = 0; - self.armorclass = 0; - self.items = - (self.items - (self.items & ((8192 | 16384) | 32768))); + if (inp == 1) { + Engineer_SentryGun_InsertAmmo(self.building); + } else if (inp == 2 && self.building.weapon < 3 && self.ammo_cells >= 130) { + Engineer_SentryGun_Upgrade(self.building); + } else if (inp == 3) { + Engineer_SentryGun_Repair(self.building); + } else if (inp == 4) { + Menu_EngineerFix_SentryGun_Rotate(); } - W_SetCurrentAmmo(); }; void () Menu_EngineerFix_SentryGun = { From 89d41a85a573a7a545cb45cb9b6760840d847321 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 23 Jul 2014 19:10:22 +0200 Subject: [PATCH 0032/2474] Engineer now upgrades > repairs > restocks Sentry Gun on spanner hit --- engineer.qc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/engineer.qc b/engineer.qc index fd17d3e4..7a005bf1 100644 --- a/engineer.qc +++ b/engineer.qc @@ -757,6 +757,24 @@ void (entity disp) Engineer_Dispenser_Repair = { }; void (entity gun) Engineer_UseSentryGun = { + if (gun.weapon < 3 && self.ammo_cells >= 130) { + Engineer_SentryGun_Upgrade(gun); + return; + } + + if (gun.health < gun.max_health && self.ammo_cells > 0) { + Engineer_SentryGun_Repair(gun); + return; + } + + if (gun.ammo_shells < gun.maxammo_shells || (gun.weapon == 3 + && gun.ammo_rockets < gun.maxammo_rockets)) { + if (self.ammo_shells > 0 || (gun.weapon == 3 && self.ammo_rockets > 0)) { + Engineer_SentryGun_InsertAmmo(gun); + return; + } + } + sprint(self, PRINT_HIGH, "Level "); sprint(self, PRINT_HIGH, ftos(gun.weapon), " sentry gun has "); From c475429e52ceb2e8e2605bf768cb9272a0f4f533 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 24 Jul 2014 21:32:13 +0200 Subject: [PATCH 0033/2474] Make Engineer build menu update (destroy/dismantle) while moving --- engineer.qc | 2 +- menu.qc | 62 ++++++++++++++++++++++++++++++++--------------------- qw.qc | 1 + weapons.qc | 2 +- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/engineer.qc b/engineer.qc index 7a005bf1..8f5191fe 100644 --- a/engineer.qc +++ b/engineer.qc @@ -243,7 +243,7 @@ void () TeamFortress_EngineerBuild = { "You don't have enough metal to \nbuild anything.\n\n"); return; } - Menu_Engineer(); + Menu_Engineer(self); } else if (self.is_building == 1) { TeamFortress_EngineerBuildStop(); } diff --git a/menu.qc b/menu.qc index 14ca7858..4fe056b1 100644 --- a/menu.qc +++ b/menu.qc @@ -73,7 +73,8 @@ void () Menu_Demoman_Cancel; void (float inp) Menu_Demoman_Input; void (float inp) Menu_Demoman_Cancel_Input; -void () Menu_Engineer; +void (entity player) Menu_Engineer; +void () Menu_Engineer_Update; void () Menu_EngineerFix_Dispenser; void () Menu_EngineerFix_SentryGun; @@ -572,51 +573,64 @@ void (float inp) Menu_Engineer_Input = { }; -void () Menu_Engineer = { - local entity te; - local string s_action = "Action:\n\n"; - local string s_sentry, s_disp, s_dsentry, s_ddisp; +void (entity player) Menu_Engineer = { + local entity te, dist_checker; + local string s_action = "Action:\n\n"; + local string s_sentry = "\n"; + local string s_disp = "\n"; + local string s_dsentry = "\n"; + local string s_ddisp = "\n"; local string s_nothing = "\n—‘ Nothing "; - if (self.has_sentry) { + if (player.has_sentry) { s_sentry = "\n"; s_dsentry = "•‘ Destroy sentry gun \n"; - te = findradius(self.origin, 70); + te = findradius(player.origin, 70); while (te) { if (te.classname == "building_sentrygun") { - if (te.real_owner == self) + if (te.real_owner == player) s_dsentry = "•‘ Dismantle sentry gun\n"; } te = te.chain; } - } else { - if (self.ammo_cells >= 130) - s_sentry = "“‘ Build sentry gun \n"; - else - s_sentry = "\n"; - s_dsentry = "\n"; + } else if (player.ammo_cells >= 130) { + s_sentry = "“‘ Build sentry gun \n"; } - if (self.has_dispenser) { - s_disp = "\n"; + if (player.has_dispenser) { s_ddisp = "–‘ Destroy dispenser \n"; - te = findradius(self.origin, 70); + te = findradius(player.origin, 70); while (te) { if (te.classname == "building_dispenser") { - if (te.real_owner == self) + if (te.real_owner == player) s_ddisp = "–‘ Dismantle dispenser \n"; } te = te.chain; } - } else { - if (self.ammo_cells >= 100) + } else if (player.ammo_cells >= 100) { s_disp = "”‘ Build dispenser \n"; - else - s_disp = "\n"; - s_ddisp = "\n"; } - Status_Menu(self, Menu_Engineer_Input, s_action, s_sentry, s_disp, s_dsentry, s_ddisp, s_nothing); + if ((player.has_dispenser || player.has_sentry) && !player.has_menutimer) { + player.has_menutimer = 1; + dist_checker = spawn(); + dist_checker.classname = "menu_timer"; + dist_checker.owner = player; + dist_checker.think = Menu_Engineer_Update; + dist_checker.nextthink = time + 0.3; + } + + Status_Menu(player, Menu_Engineer_Input, s_action, s_sentry, s_disp, s_dsentry, s_ddisp, s_nothing); +}; + +void () Menu_Engineer_Update = { + if (self.owner.menu_input == Menu_Engineer_Input) { + Menu_Engineer(self.owner); + self.nextthink = time + 0.3; + } else { + self.owner.has_menutimer = 0; + dremove(self); + } }; void (float inp) Menu_EngineerFix_Dispenser_Input = { diff --git a/qw.qc b/qw.qc index 969bf27f..4a7c89ee 100644 --- a/qw.qc +++ b/qw.qc @@ -29,6 +29,7 @@ typedef void (float) f_void_float; .float is_feigning; // TRUE for a SPY if they're feigning death .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float has_disconnected; // TRUE if the player has disconnected +.float has_menutimer; // TRUE if the player has an active menu timer .float current_fov; // Player's current field of view .float zoom_level; // Start zooming to this fov next frame .float zoom_mode; // Autozoom: 0 (off), 2 (2x), 4 (4x) diff --git a/weapons.qc b/weapons.qc index 193fb26d..f88d4d94 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1503,7 +1503,7 @@ void () W_SetCurrentAmmo = { // refresh engineer build menu when ammo updated if (self.menu_input == Menu_Engineer_Input) - Menu_Engineer(); + Menu_Engineer(self); }; float () W_BestWeapon = { From c1085a91a19b76b6996768ebb6eef411e2277110 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 24 Jul 2014 21:34:52 +0200 Subject: [PATCH 0034/2474] Fix so Engineer can move if stopping a build process --- engineer.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engineer.qc b/engineer.qc index 8f5191fe..79a3a8cb 100644 --- a/engineer.qc +++ b/engineer.qc @@ -253,7 +253,7 @@ void () TeamFortress_EngineerBuildStop = { local entity te; sprint(self, PRINT_HIGH, "You stop building\n"); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); te = find(world, netname, "build_timer"); while (te) { From bd62a0769b62777a05e2484ceb18d003d19ce72a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 24 Jul 2014 21:35:21 +0200 Subject: [PATCH 0035/2474] Increase distance for dismantling Dispenser and Sentry Gun --- menu.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/menu.qc b/menu.qc index 4fe056b1..77881e96 100644 --- a/menu.qc +++ b/menu.qc @@ -535,7 +535,7 @@ void (float inp) Menu_Engineer_Input = { TeamFortress_Build(1); if (inp == 3 && self.has_sentry) { - te = findradius(self.origin, 70); + te = findradius(self.origin, 100); while (te) { if (te.classname == "building_sentrygun") { if (te.real_owner == self){ @@ -554,7 +554,7 @@ void (float inp) Menu_Engineer_Input = { } if (inp == 4 && self.has_dispenser) { - te = findradius(self.origin, 70); + te = findradius(self.origin, 100); while (te) { if (te.classname == "building_dispenser") { if (te.real_owner == self) { @@ -585,7 +585,7 @@ void (entity player) Menu_Engineer = { if (player.has_sentry) { s_sentry = "\n"; s_dsentry = "•‘ Destroy sentry gun \n"; - te = findradius(player.origin, 70); + te = findradius(player.origin, 100); while (te) { if (te.classname == "building_sentrygun") { if (te.real_owner == player) @@ -599,7 +599,7 @@ void (entity player) Menu_Engineer = { if (player.has_dispenser) { s_ddisp = "–‘ Destroy dispenser \n"; - te = findradius(player.origin, 70); + te = findradius(player.origin, 100); while (te) { if (te.classname == "building_dispenser") { if (te.real_owner == player) From 56afcaedd8f73d69843ce9861a27066364c6b48a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 24 Jul 2014 22:08:37 +0200 Subject: [PATCH 0036/2474] Fix Sentry Gun menu bug from commit 70f14a744ecf71c5896cef881dff6ac60140fc07 --- engineer.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/engineer.qc b/engineer.qc index 79a3a8cb..8c41d9aa 100644 --- a/engineer.qc +++ b/engineer.qc @@ -801,6 +801,7 @@ void (entity gun) Engineer_UseSentryGun = { } sprint(self, PRINT_HIGH, "\n"); + self.building = gun; Engineer_SentryGun_ShowMenu(self.building); }; From 365dc3a7886748ea993f0ea58cbf835089b663c6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 24 Jul 2014 22:09:14 +0200 Subject: [PATCH 0037/2474] Change Sentry Gun menu to only contain rotation (closes #68) --- menu.qc | 68 ++++++++++----------------------------------------------- 1 file changed, 11 insertions(+), 57 deletions(-) diff --git a/menu.qc b/menu.qc index 77881e96..63bde710 100644 --- a/menu.qc +++ b/menu.qc @@ -667,80 +667,34 @@ void () Menu_EngineerFix_Dispenser = { Status_Menu(self, Menu_EngineerFix_Dispenser_Input, s_action, s_ammo, s_armor, s_nothing); }; -void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { +void (float inp) Menu_EngineerFix_SentryGun_Input = { if (inp == 1) { - sprint(self, PRINT_HIGH, "Rotating 90 degrees to the left...\n"); - self.building.waitmin = anglemod(self.building.waitmin + 90); - self.building.waitmax = anglemod(self.building.waitmax + 90); - } else if (inp == 2) { sprint(self, PRINT_HIGH, "Rotating 45 degrees to the left...\n"); self.building.waitmin = anglemod(self.building.waitmin + 45); self.building.waitmax = anglemod(self.building.waitmax + 45); + } else if (inp == 2) { + sprint(self, PRINT_HIGH, "Rotating 180 degrees...\n"); + self.building.waitmin = anglemod(self.building.waitmin + 180); + self.building.waitmax = anglemod(self.building.waitmax + 180); } else if (inp == 3) { sprint(self, PRINT_HIGH, "Rotating 45 degrees to the right...\n"); self.building.waitmin = anglemod(self.building.waitmin - 45); self.building.waitmax = anglemod(self.building.waitmax - 45); - } else if (inp == 4) { - sprint(self, PRINT_HIGH, "Rotating 90 degrees to the right...\n"); - self.building.waitmin = anglemod(self.building.waitmin - 90); - self.building.waitmax = anglemod(self.building.waitmax - 90); } }; -void () Menu_EngineerFix_SentryGun_Rotate = { +void () Menu_EngineerFix_SentryGun = { local string action = "Rotate sentry gun:\n\n"; - local string rot_90l = "“‘ 90 degrees left \n"; - local string rot_45l = "”‘ 45 degrees left \n"; - local string rot_45r = "•‘ 45 degrees right\n"; - local string rot_90r = "–‘ 90 degrees right\n"; - local string nothing = "\n—‘ Nothing "; - - Status_Menu(self, Menu_EngineerFix_SentryGun_Rotate_Input, action, rot_90l, rot_45l, rot_45r, rot_90r, nothing); -}; + local string rotl = "“‘ 45 degrees left \n"; + local string rot180 = "”‘ 180 degrees \n"; + local string rotr = "•‘ 45 degrees right\n"; + local string nothing = "\n—‘ Nothing \n"; -void (float inp) Menu_EngineerFix_SentryGun_Input = { if (!self.building.real_owner.has_sentry || self.building.real_owner != self || self.classname != "player" || self.building == world) return; - if (inp == 1) { - Engineer_SentryGun_InsertAmmo(self.building); - } else if (inp == 2 && self.building.weapon < 3 && self.ammo_cells >= 130) { - Engineer_SentryGun_Upgrade(self.building); - } else if (inp == 3) { - Engineer_SentryGun_Repair(self.building); - } else if (inp == 4) { - Menu_EngineerFix_SentryGun_Rotate(); - } -}; - -void () Menu_EngineerFix_SentryGun = { - local string action = "Sentry gun maintenance:\n\n"; - local string putammo, upgrade, repair, rotate; - local string nothing = "\n—‘ Nothing "; - - if ((self.ammo_shells > 0 && self.building.ammo_shells < self.building.maxammo_shells) - || (self.ammo_rockets > 0 && self.building.weapon == 3 && self.building.ammo_rockets < self.building.maxammo_rockets)) - putammo = "“‘ Insert ammo\n"; - else - putammo = "\n"; - - if (self.building.weapon < 3 && self.ammo_cells >= 130) - upgrade = "”‘ Upgrade \n"; - else - upgrade = "\n"; - - if (self.building.health < self.building.max_health) - repair = "•‘ Repair \n"; - else - repair = "\n"; - - if (self.building.real_owner == self) - rotate = "–‘ Rotate \n"; - else - rotate = "\n"; - - Status_Menu(self, Menu_EngineerFix_SentryGun_Input, action, putammo, upgrade, repair, rotate, nothing); + Status_Menu(self, Menu_EngineerFix_SentryGun_Input, action, rotl, rot180, rotr, nothing); }; void (float inp) Menu_Dispenser_Input = { From b9128d16202764e5a12e063877b6a11fd5e16816 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 09:19:29 +0200 Subject: [PATCH 0038/2474] Further improve Dispenser code --- engineer.qc | 99 ++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/engineer.qc b/engineer.qc index 8c41d9aa..325b9417 100644 --- a/engineer.qc +++ b/engineer.qc @@ -630,6 +630,14 @@ void (entity disp) Engineer_UseDispenser = { sprint(self, PRINT_HIGH, ftos(disp.ammo_cells), " cells and "); sprint(self, PRINT_HIGH, ftos(disp.armorvalue), " armor\n"); + if ((!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells) + || (disp.ammo_shells == BUILD_DISPENSER_MAX_SHELLS && disp.ammo_nails == BUILD_DISPENSER_MAX_NAILS + && disp.ammo_rockets == BUILD_DISPENSER_MAX_ROCKETS && disp.ammo_cells == BUILD_DISPENSER_MAX_CELLS)) + && (!self.armorvalue || disp.armorvalue == BUILD_DISPENSER_MAX_ARMOR)) { + CenterPrint(self, "\n\nThere's nothing to do"); + return; + } + self.building = disp; Menu_EngineerFix_Dispenser(); dist_checker = spawn(); @@ -641,52 +649,43 @@ void (entity disp) Engineer_UseDispenser = { }; void (entity disp) Engineer_Dispenser_InsertAmmo = { - local float ammo, shells, nails, rockets, cells; + local float shells, nails, rockets, cells; - ammo = (20 * 2); - if (ammo > self.ammo_shells) { - ammo = self.ammo_shells; - } - if (ammo > (400 - disp.ammo_shells)) { - ammo = (400 - disp.ammo_shells); - } - self.ammo_shells = (self.ammo_shells - ammo); - disp.ammo_shells = (disp.ammo_shells + ammo); - shells = ammo; - ammo = (20 * 2); - if (ammo > self.ammo_nails) { - ammo = self.ammo_nails; - } - if (ammo > (600 - disp.ammo_nails)) { - ammo = (600 - disp.ammo_nails); - } - self.ammo_nails = (self.ammo_nails - ammo); - disp.ammo_nails = (disp.ammo_nails + ammo); - nails = ammo; - ammo = (10 * 2); - if (ammo > self.ammo_rockets) { - ammo = self.ammo_rockets; - } - if (ammo > (300 - disp.ammo_rockets)) { - ammo = (300 - disp.ammo_rockets); - } - self.ammo_rockets = (self.ammo_rockets - ammo); - disp.ammo_rockets = (disp.ammo_rockets + ammo); - rockets = ammo; - ammo = (10 * 2); - if (ammo > self.ammo_cells) { - ammo = self.ammo_cells; - } - if (ammo > (400 - disp.ammo_cells)) { - ammo = (400 - disp.ammo_cells); - } - self.ammo_cells = (self.ammo_cells - ammo); - disp.ammo_cells = (disp.ammo_cells + ammo); - cells = ammo; + shells = 40; + if (shells > self.ammo_shells) + shells = self.ammo_shells; + if (shells > (BUILD_DISPENSER_MAX_SHELLS - disp.ammo_shells)) + shells = (BUILD_DISPENSER_MAX_SHELLS - disp.ammo_shells); + self.ammo_shells = (self.ammo_shells - shells); + disp.ammo_shells = (disp.ammo_shells + shells); + + nails = 40; + if (nails > self.ammo_nails) + nails = self.ammo_nails; + if (nails > (BUILD_DISPENSER_MAX_NAILS - disp.ammo_nails)) + nails = (BUILD_DISPENSER_MAX_NAILS - disp.ammo_nails); + self.ammo_nails = (self.ammo_nails - nails); + disp.ammo_nails = (disp.ammo_nails + nails); + + rockets = 20; + if (rockets > self.ammo_rockets) + rockets = self.ammo_rockets; + if (rockets > (BUILD_DISPENSER_MAX_ROCKETS - disp.ammo_rockets)) + rockets = (BUILD_DISPENSER_MAX_ROCKETS - disp.ammo_rockets); + self.ammo_rockets = (self.ammo_rockets - rockets); + disp.ammo_rockets = (disp.ammo_rockets + rockets); + + cells = 20; + if (cells > self.ammo_cells) + cells = self.ammo_cells; + if (cells > (BUILD_DISPENSER_MAX_CELLS - disp.ammo_cells)) + cells = (BUILD_DISPENSER_MAX_CELLS - disp.ammo_cells); + self.ammo_cells = (self.ammo_cells - cells); + disp.ammo_cells = (disp.ammo_cells + cells); if ((shells + nails + rockets + cells) > 0) { W_SetCurrentAmmo(); - sprint(self, PRINT_HIGH, "You inserted "); + sprint(self, PRINT_HIGH, "You insert "); if (shells > 0) sprint(self, PRINT_HIGH, ftos(shells), " shells"); if (nails > 0) { @@ -708,19 +707,19 @@ void (entity disp) Engineer_Dispenser_InsertAmmo = { sprint(self, PRINT_HIGH, " and "); sprint(self, PRINT_HIGH, ftos(cells), " cells"); } - sprint(self, PRINT_HIGH, " into Dispenser\n"); + sprint(self, PRINT_HIGH, " into dispenser\n"); } }; void (entity disp) Engineer_Dispenser_InsertArmor = { local float armor; - armor = (40 * 2); + armor = 80; if (armor > self.armorvalue) { armor = self.armorvalue; } - if (armor > (500 - disp.armorvalue)) { - armor = (500 - disp.armorvalue); + if (armor > (BUILD_DISPENSER_MAX_ARMOR - disp.armorvalue)) { + armor = (BUILD_DISPENSER_MAX_ARMOR - disp.armorvalue); } self.armorvalue = (self.armorvalue - armor); disp.armorvalue = (disp.armorvalue + armor); @@ -732,9 +731,9 @@ void (entity disp) Engineer_Dispenser_InsertArmor = { } if (armor > 0) - sprint(self, PRINT_HIGH, "You inserted ", ftos(armor), " armor into Dispenser\n"); + sprint(self, PRINT_HIGH, "You insert ", ftos(armor), " armor into dispenser\n"); else if (disp.armorvalue == BUILD_DISPENSER_MAX_ARMOR) - sprint(self, PRINT_HIGH, "Your Dispenser cannot carry more armor\n"); + sprint(self, PRINT_HIGH, "Dispenser cannot carry more armor\n"); }; void (entity disp) Engineer_Dispenser_Repair = { @@ -752,8 +751,8 @@ void (entity disp) Engineer_Dispenser_Repair = { disp.health = disp.health + healamount; if (metalcost > 0) - sprint(self, PRINT_HIGH, "You repaired your Dispenser with ", ftos(healamount), - " health at the cost of ", ftos(metalcost), " cells\n"); + sprint(self, PRINT_HIGH, "Dispenser repaired for ", ftos(healamount), + " health using ", ftos(metalcost), " cells\n"); }; void (entity gun) Engineer_UseSentryGun = { From 3b6de350e8b7ec85bb68d1ff948c7baf1564931a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 09:22:31 +0200 Subject: [PATCH 0039/2474] Remove grenades from disconnected players (fixes #69) --- client.qc | 7 +++++++ tfort.qc | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index e147206a..96d2c78d 100644 --- a/client.qc +++ b/client.qc @@ -1808,6 +1808,13 @@ void () ClientDisconnect = { } te = find(te, classname, "detpack"); } + te = find(world, classname, "grenade"); + while (te) { + if (te.owner == self) { + dremove(te); + } + te = find(te, classname, "grenade"); + } if (clanbattle && (self.tf_id != 0)) { te = spawn(); te.classname = "ghost"; diff --git a/tfort.qc b/tfort.qc index 0dc35ca4..ba6752b8 100644 --- a/tfort.qc +++ b/tfort.qc @@ -645,7 +645,7 @@ void () TeamFortress_GrenadePrimed = { local entity user; user = self.owner; - if (!(user.tfstate & 1024) && !user.deadflag) { + if (!(user.tfstate & 1024) && !user.deadflag && !user.has_disconnected) { self.nextthink = time + 0.1; if (!self.think) dremove(self); From f92e0fd61ee95133a0fdbccc06c6674711ffee3b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 23:23:10 +0200 Subject: [PATCH 0040/2474] Improve Engineer messages --- engineer.qc | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/engineer.qc b/engineer.qc index 325b9417..ab99cabf 100644 --- a/engineer.qc +++ b/engineer.qc @@ -239,8 +239,7 @@ void () TeamFortress_EngineerBuild = { if (self.is_building == 0) { if (((self.ammo_cells < 100) && !self.has_dispenser) && !self.has_sentry) { - CenterPrint(self, - "You don't have enough metal to \nbuild anything.\n\n"); + Status_Print(self, "\n\n\n\n\n\n\n", "Not enough metal to build anything"); return; } Menu_Engineer(self); @@ -341,8 +340,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.origin = self.origin + v_forward; if (objtobuild == 1) { if (self.has_dispenser) { - sprint(self, PRINT_HIGH, - "You can only have one dispenser\n"); + sprint(self, PRINT_HIGH, "You can only have one dispenser\n"); return; } tmp1 = '-16 -16 0'; @@ -352,8 +350,7 @@ void (float objtobuild) TeamFortress_Build = { btime = time + 2; } else if (objtobuild == 2) { if (self.has_sentry) { - sprint(self, PRINT_HIGH, - "You can only have one sentry gun\n"); + sprint(self, PRINT_HIGH, "You can only have one sentry gun\n"); return; } tmp1 = '-16 -16 0'; @@ -368,7 +365,7 @@ void (float objtobuild) TeamFortress_Build = { return; } if (!(self.flags & 512)) { - CenterPrint(self, "You cannot build in the air\n\n"); + Status_Print(self, "\n\n\n\n\n\n\n", "You cannot build in the air"); return; } self.is_building = 1; @@ -570,8 +567,7 @@ void () T_Dispenser = { return; } if ((other.team_no != 0) && (other.team_no != self.team_no)) { - centerprint(self.real_owner, - "Enemies are using your dispenser!\n"); + Status_Print(self.real_owner, "\n\n\n\n\n\n\n", "Enemies are using your dispenser!"); } if ((other.building == world) && (other.building_wait < time)) { other.building = self; @@ -634,7 +630,7 @@ void (entity disp) Engineer_UseDispenser = { || (disp.ammo_shells == BUILD_DISPENSER_MAX_SHELLS && disp.ammo_nails == BUILD_DISPENSER_MAX_NAILS && disp.ammo_rockets == BUILD_DISPENSER_MAX_ROCKETS && disp.ammo_cells == BUILD_DISPENSER_MAX_CELLS)) && (!self.armorvalue || disp.armorvalue == BUILD_DISPENSER_MAX_ARMOR)) { - CenterPrint(self, "\n\nThere's nothing to do"); + Status_Print(self, "\n\n\n\n\n\n\n", "There's nothing to do"); return; } @@ -751,8 +747,7 @@ void (entity disp) Engineer_Dispenser_Repair = { disp.health = disp.health + healamount; if (metalcost > 0) - sprint(self, PRINT_HIGH, "Dispenser repaired for ", ftos(healamount), - " health using ", ftos(metalcost), " cells\n"); + Status_Print(self, "\n\n\n\n\n\n\n", ftos(healamount), " hp repaired"); }; void (entity gun) Engineer_UseSentryGun = { @@ -818,6 +813,7 @@ void (entity gun) Engineer_SentryGun_ShowMenu = { void (entity gun) Engineer_SentryGun_InsertAmmo = { local float shells = 0, rockets = 0; + local string ammo = ""; shells = 40; if (shells > self.ammo_shells) @@ -839,15 +835,16 @@ void (entity gun) Engineer_SentryGun_InsertAmmo = { if ((shells + rockets) > 0) { W_SetCurrentAmmo(); - sprint(self, PRINT_HIGH, "You insert "); + ammo = "You insert "; if (shells > 0) - sprint(self, PRINT_HIGH, ftos(floor(shells)), " shells"); + ammo = strcat(ammo, strcat(ftos(floor(shells)), " shells")); if (rockets > 0) { if (shells > 0) - sprint(self, PRINT_HIGH, " and "); - sprint(self, PRINT_HIGH, ftos(floor(rockets)), " rockets"); + ammo = strcat(ammo, " and "); + ammo = strcat(ammo, strcat(ftos(floor(rockets)), " rockets")); } - sprint(self, PRINT_HIGH, " into sentry gun\n"); + ammo = strcat(ammo, " into sentry gun"); + Status_Print(self, "\n\n\n\n\n\n\n", ammo); } }; @@ -869,8 +866,7 @@ void (entity gun) Engineer_SentryGun_Upgrade = { gun.think = lvl3_sentry_stand; gun.skin = 2; } - sprint(self, PRINT_HIGH, "You upgrade the sentry gun to level "); - sprint(self, PRINT_HIGH, ftos(gun.weapon), "\n"); + Status_Print(self, "\n\n\n\n\n\n\n", "Upgraded to level ", ftos(gun.weapon)); }; void (entity gun) Engineer_SentryGun_Repair = { @@ -888,8 +884,7 @@ void (entity gun) Engineer_SentryGun_Repair = { gun.health = gun.max_health; if (metalcost > 0) - sprint(self, PRINT_HIGH, "Sentry Gun repaired for ", ftos(healamount), - " health using ", ftos(metalcost), " cells\n"); + Status_Print(self, "\n\n\n\n\n\n\n", ftos(healamount), " hp repaired"); }; void (entity gunhead) CheckSentry = { @@ -899,8 +894,7 @@ void (entity gunhead) CheckSentry = { gunbase = gunhead.trigger_field; dist = gunbase.origin - gunhead.origin; if (vlen(dist) > 15) { - bprint(PRINT_MEDIUM, self.real_owner.netname, - "'s sentry gun malfunctioned\n"); + bprint(PRINT_MEDIUM, self.real_owner.netname, "'s sentry gun malfunctioned\n"); Sentry_Die(); } }; From 591233d575414d97d550011b85ee01a2cfa58266 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 23:23:34 +0200 Subject: [PATCH 0041/2474] Only try to repair a sentry gun with health below maximum --- engineer.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engineer.qc b/engineer.qc index ab99cabf..539a4414 100644 --- a/engineer.qc +++ b/engineer.qc @@ -617,7 +617,10 @@ void () Dispenser_Die = { void (entity disp) Engineer_UseDispenser = { local entity dist_checker; - Engineer_Dispenser_Repair(disp); + if (disp.health < disp.max_health) { + Engineer_Dispenser_Repair(disp); + return; + } sprint(self, PRINT_HIGH, "Dispenser has ", ftos(disp.health), " health and current stock:\n"); sprint(self, PRINT_HIGH, ftos(disp.ammo_shells), " shells, "); From b62493701ac47777ef4821c152f1b59fad996496 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 23:24:05 +0200 Subject: [PATCH 0042/2474] Improve Spy messages --- spy.qc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spy.qc b/spy.qc index 255fc9ed..aac1193d 100644 --- a/spy.qc +++ b/spy.qc @@ -595,7 +595,7 @@ void () TeamFortress_SpyUndercoverThink = { TeamFortress_SetSkin(self.owner); } TeamFortress_SpyCalcName(self.owner); - CenterPrint(self.owner, "You are now disguised\n"); + Status_Print(self.owner, "\n\n\n\n\n\n\n", "You are now disguised"); self.owner.is_undercover = 1; } } @@ -1057,6 +1057,7 @@ void () TranquiliserTimer = { void (entity spy) Spy_RemoveDisguise = { local string st; local float tc; + local float coverblown = 0; if (invis_only != 1) { if (spy.playerclass == 8) { @@ -1068,11 +1069,13 @@ void (entity spy) Spy_RemoveDisguise = { st = ftos(tc); stuffcmd(spy, st); stuffcmd(spy, "\n"); + coverblown = 1; } if (spy.undercover_skin != 0) { spy.immune_to_check = time + 10; spy.undercover_skin = 0; spy.skin = 0; + coverblown = 1; } spy.is_undercover = 0; Status_Refresh(self); @@ -1080,6 +1083,7 @@ void (entity spy) Spy_RemoveDisguise = { TeamFortress_SpyCalcName(spy); } } else if (spy.is_undercover) { + coverblown = 1; spy.is_undercover = 0; spy.modelindex = modelindex_player; if (spy.items & 524288) { @@ -1089,4 +1093,6 @@ void (entity spy) Spy_RemoveDisguise = { } Status_Refresh(self); } + if (coverblown) + Status_Print(self, "\n\n\n\n\n\n\n", "You blew your cover!"); }; From 62a2f510f404c82e3b9a52892bd9cc7d993a1cce Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 23:28:14 +0200 Subject: [PATCH 0043/2474] Improve status bar code --- status.qc | 113 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/status.qc b/status.qc index d639c820..a67a572b 100644 --- a/status.qc +++ b/status.qc @@ -96,15 +96,12 @@ void (entity pl) RefreshStatusBar = { local string s1; // will be used for grenade timers local string s2; // class line local string s3; // score & clip - local string sco1, sco2; + local string st1, st2, st3, st4; // status bar columns 1-4 local float height; local float i; local float win, sec; pad = ""; - s1 = "\n\n"; - s2 = "\n"; - s3 = "\n"; if (pl.StatusStringLines > 0 && pl.StatusStringTime <= time && !pl.menu_input) { if (pl.StatusString) @@ -127,69 +124,75 @@ void (entity pl) RefreshStatusBar = { for (i = 0; i < height; i++) pad = strcat(pad, "\n"); + pad = strzone(pad); + // status line 1 column 1 - grenade timer + st1 = ""; if (pl.StatusGrenTime > 0) - s1 = strcat("Explosion in ", strcat(ftos(pl.StatusGrenTime), "...\n\n")); - + st1 = strcat("Explosion in ", strcat(ftos(pl.StatusGrenTime), "...")); + // status line 1 + s1 = strcat(st1, "\n\n"); + s1 = strzone(s1); + + // status line 2 column 1 - class specific information + st1 = ""; + if (pl.playerclass == PC_SCOUT) + st1 = strcat(ScannerToString(pl), RangeToString(pl)); + else if (pl.playerclass == PC_DEMOMAN && self.is_detpacking) + st1 = strcat(strcat("Setting detpack in ", ftos(self.is_detpacking)), "..."); + else if (pl.playerclass == PC_SPY) + st1 = DisguiseToString(pl); + else if (pl.playerclass == PC_ENGINEER && self.has_sentry) + st1 = SentryDetailsToString(pl); + if (pl.playerclass == PC_ENGINEER && self.is_building) + st1 = "Building..."; + // status line 2 + s2 = strpadr(st1, 42); + s2 = strcat(s2, "\n"); + s2 = strzone(s2); + + // status line 3 column 1 - team 1 score win = TeamFortress_TeamGetWinner(); sec = TeamFortress_TeamGetSecond(); - if (win == 0) - sco1 = BlueScoreToString(team1score); + st1 = strcat(BlueScoreToString(team1score), " "); else if (win == 1) - sco1 = BlueScoreToString(team1score); + st1 = strcat(BlueScoreToString(team1score), " "); else if (win == 2) - sco1 = RedScoreToString(team2score); + st1 = strcat(RedScoreToString(team2score), " "); else if (win == 3) - sco1 = YellowScoreToString(team3score); + st1 = strcat(YellowScoreToString(team3score), " "); else - sco1 = GreenScoreToString(team4score); - + st1 = GreenScoreToString(team4score); + // status line 3 column 2 - team 2 score if (sec == 0) - sco2 = RedScoreToString(team2score); + st2 = RedScoreToString(team2score); else if (sec == 1) - sco2 = BlueScoreToString(team1score); + st2 = BlueScoreToString(team1score); else if (sec == 2) - sco2 = RedScoreToString(team2score); + st2 = RedScoreToString(team2score); else if (sec == 3) - sco2 = YellowScoreToString(team3score); + st2 = YellowScoreToString(team3score); else - sco2 = GreenScoreToString(team4score); - - if ((self.tfstate & TFSTATE_RELOADING)) - s3 = strcat(strcat(sco1, sco2), " ΓΜΙΠ: 0"); + st2 = GreenScoreToString(team4score); + // status line 3 column 3 - clip size + if (self.tfstate & TFSTATE_RELOADING) + st3 = " Γμιπ: 0"; else - s3 = strcat(strcat(sco1, sco2), ClipSizeToString(pl)); - - s3 = strcat(s3, " Η: "); - s3 = strcat(s3, ftos(self.no_grenades_1)); - s3 = strcat(s3, "/"); - s3 = strcat(s3, ftos(self.no_grenades_2)); - - if (pl.playerclass == PC_SCOUT) { - - s2 = strcat(strcat(ScannerToString(pl), RangeToString(pl)), "\n"); - - } else if (pl.playerclass == PC_DEMOMAN) { - - if (self.is_detpacking) { - s2 = strcat(strpadr(strcat(strcat(" setting detpack in ", ftos(self.is_detpacking)), "..."), 39), "\n"); - } - - } else if (pl.playerclass == PC_SPY) { - - s2 = DisguiseToString(pl); - - } else if (pl.playerclass == PC_ENGINEER) { - - if (self.has_sentry) - s2 = strcat(SentryHealthToString(pl), SentryDetailsToString(pl)); - else if (self.is_building) - s2 = " building \n"; - } + st3 = ClipSizeToString(pl); + // status line 3 column 4 - grenade count + st4 = strcat(" Ηςεξ: ", strcat(strcat(ftos(self.no_grenades_1), "/"), ftos(self.no_grenades_2))); + // status line 3 + s3 = strcat(st1, st2); + s3 = strcat(s3, st3); + s3 = strcat(s3, st4); + s3 = strpadr(s3, 42); + s3 = strcat(s3, "\n"); + s3 = strzone(s3); centerprint(pl, pl.StatusString, pad, s1, s2, s3); pl.StatusRefreshTime = time + 1.5; + strunzone(pad); strunzone(s1); strunzone(s2); strunzone(s3); }; string(float num) NumberToString1000 = @@ -205,7 +208,7 @@ string(float num) BlueScoreToString = if (num > 999) num = 999; - return strcat(" Blue:", strpadl(ftos(floor(num)), 3)); + return strcat("Βμυε:", strpadl(ftos(floor(num)), 3)); }; string(float num) RedScoreToString = @@ -213,7 +216,7 @@ string(float num) RedScoreToString = if (num > 999) num = 999; - return strcat(" Red :", strpadl(ftos(floor(num)), 3)); + return strcat("εδ :", strpadl(ftos(floor(num)), 3)); }; string(float num) YellowScoreToString = @@ -221,7 +224,7 @@ string(float num) YellowScoreToString = if (num > 999) num = 999; - return strcat(" Yell:", strpadl(ftos(floor(num)), 3)); + return strcat("Ωεμμ:", strpadl(ftos(floor(num)), 3)); }; string(float num) GreenScoreToString = @@ -229,7 +232,7 @@ string(float num) GreenScoreToString = if (num > 999) num = 999; - return strcat(" Gren:", strpadl(ftos(floor(num)), 3)); + return strcat("Ηςεξ:", strpadl(ftos(floor(num)), 3)); }; string(entity pl) ClipSizeToString = @@ -258,7 +261,7 @@ string(entity pl) ClipSizeToString = if (num > 99) num = 99; - return strcat(" ΓΜΙΠ:", strpadl(ftos(floor(num)), 2)); + return strcat(" Γμιπ:", strpadl(ftos(floor(num)), 2)); }; string(float num) TeamToString = @@ -277,7 +280,7 @@ string(float num) ClassToString = if (num == 3) return "Soldier"; if (num == 4) return "Demoman"; if (num == 5) return "Medic"; - if (num == 6) return "Hvy Wpns"; + if (num == 6) return "HWGuy"; if (num == 7) return "Pyro"; if (num == 8) return "Spy"; if (num == 9) return "Engineer"; From 3082680fa36ba258cb69617f9e6b5ae7e15ad468 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 23:28:40 +0200 Subject: [PATCH 0044/2474] Improve sentry gun status bar (closes #67) --- status.qc | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/status.qc b/status.qc index a67a572b..9c9ea2e0 100644 --- a/status.qc +++ b/status.qc @@ -12,7 +12,6 @@ string(entity pl) RangeToString; string(entity pl) ScannerToString; string(entity pl) DisguiseToString; string(entity pl) SentryDetailsToString; -string(entity pl) SentryHealthToString; void (entity pl, string...count) Status_Print = { @@ -357,34 +356,25 @@ string(entity pl) ScannerToString = string(entity pl) SentryDetailsToString = { local entity te; + local string ammo = ""; + local string shells = ""; + local string rockets = ""; + local string hp = ""; te = find(world, classname, "building_sentrygun"); while (te) { if (te.real_owner == self) { - if (te.ammo_shells == 0) { - if ((te.ammo_rockets == 0) && (te.weapon == 3)) - return (" no ammo \n"); - else - return (" no shells \n"); - } else if ((te.ammo_rockets == 0) && (te.weapon == 3)) - return (" no rockets \n"); - else - return (" \n"); + hp = strcat(strpadl(ftos(floor(te.health)), 4), " hp"); + shells = ftos(floor(te.ammo_shells)); + if (te.weapon == 3) { + rockets = ftos(floor(te.ammo_rockets)); + ammo = strcat(" Αννο: ", strcat(shells, strcat("/", rockets))); + } else { + ammo = strcat(" Αννο: ", shells); + } + return strcat("Σεξτςω:", strcat(hp, strcat(strpadr(ammo, 12), strcat(" Μεφεμ: ", ftos(te.weapon))))); } te = find(te, classname, "building_sentrygun"); } - return (" \n"); -}; - -string(entity pl) SentryHealthToString = -{ - local entity te; - - te = find(world, classname, "building_sentrygun"); - while (te) { - if (te.real_owner == self) - return strcat("SENTRY:", strpadl(ftos(floor(te.health)), 4)); - te = find(te, classname, "building_sentrygun"); - } - return ("SENTRY: 0 health"); -}; + return (""); +}; \ No newline at end of file From 2e07e94f3f0a1c031de94f9ec9d1cb9d3d6d8274 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 25 Jul 2014 23:29:01 +0200 Subject: [PATCH 0045/2474] Improve disguise status bar --- status.qc | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/status.qc b/status.qc index 9c9ea2e0..058a6815 100644 --- a/status.qc +++ b/status.qc @@ -292,20 +292,23 @@ string(float num) ClassToString = string(entity pl) DisguiseToString = { - local string st; + local string st = ""; + + if (pl.is_undercover == 1) { + st = "Υξδεςγοφες: "; + if (pl.undercover_team) { + st = strcat(st, TeamToString(pl.undercover_team)); + st = strcat(st, " "); + } + if (pl.undercover_skin) + st = strcat(st, ClassToString(pl.undercover_skin)); + } else if (pl.is_undercover == 2) { + st = "Going undercover..."; + } else if (invis_only) { + st = "Υξδεςγοφες"; + } - if (pl.is_undercover == 0) - return ("\n"); - if (pl.is_undercover == 2) - return ("going undercover \n"); - if (invis_only) - return ("undercover \n"); - - st = TeamToString(pl.undercover_team); - st = strcat(st, " "); - st = strcat(st, ClassToString(pl.undercover_skin)); - st = strpadr(st, 39); - return strcat(st, "\n"); + return st; }; string(entity pl) RangeToString = From 13bc9d9a048ad6bf9cb86302ea3cb855e9d99de4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 26 Jul 2014 00:06:15 +0200 Subject: [PATCH 0046/2474] Add repair/restock sounds (closes #72) --- engineer.qc | 9 +++++++-- world.qc | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/engineer.qc b/engineer.qc index 539a4414..12ae65c2 100644 --- a/engineer.qc +++ b/engineer.qc @@ -749,8 +749,10 @@ void (entity disp) Engineer_Dispenser_Repair = { healamount = floor(metalcost * 5); disp.health = disp.health + healamount; - if (metalcost > 0) + if (metalcost > 0) { Status_Print(self, "\n\n\n\n\n\n\n", ftos(healamount), " hp repaired"); + sound(self, 3, "items/r_item2.wav", 1, 1); + } }; void (entity gun) Engineer_UseSentryGun = { @@ -848,6 +850,7 @@ void (entity gun) Engineer_SentryGun_InsertAmmo = { } ammo = strcat(ammo, " into sentry gun"); Status_Print(self, "\n\n\n\n\n\n\n", ammo); + sound(self, 3, "edge/backpack.wav", 1, 1); } }; @@ -886,8 +889,10 @@ void (entity gun) Engineer_SentryGun_Repair = { if (gun.health > gun.max_health) gun.health = gun.max_health; - if (metalcost > 0) + if (metalcost > 0) { Status_Print(self, "\n\n\n\n\n\n\n", ftos(healamount), " hp repaired"); + sound(self, 3, "items/r_item2.wav", 1, 1); + } }; void (entity gunhead) CheckSentry = { diff --git a/world.qc b/world.qc index 2f2ead25..2b5a3b4f 100644 --- a/world.qc +++ b/world.qc @@ -163,6 +163,7 @@ void () worldspawn = { Vote_Reset(); W_Precache(); + precache_sound("edge/backpack.wav"); precache_sound("demon/dland2.wav"); precache_sound("misc/h2ohit1.wav"); precache_sound("items/itembk2.wav"); From f2d0d20d19e96171fbf79b4ccc35141aae9cb914 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 26 Jul 2014 00:13:06 +0200 Subject: [PATCH 0047/2474] Rename grenade timer sound (closes #71) --- tfort.qc | 2 +- world.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index ba6752b8..543aca5c 100644 --- a/tfort.qc +++ b/tfort.qc @@ -447,7 +447,7 @@ void () GrenadeTimer = { Status_Refresh(self.owner); if (self.heat > 0) { - stuffcmd(self.owner, "play zombie/z_fall.wav\n"); + stuffcmd(self.owner, "play items/grentimer.wav\n"); self.nextthink = time + 1.0; } else { dremove(self); diff --git a/world.qc b/world.qc index 2b5a3b4f..78084c54 100644 --- a/world.qc +++ b/world.qc @@ -290,7 +290,7 @@ void () worldspawn = { precache_sound2("misc/b2.wav"); precache_sound2("misc/b3.wav"); precache_sound2("misc/b4.wav"); - precache_sound("zombie/z_fall.wav"); + precache_sound("items/grentimer.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); From 78fa759e0ce92e268b44aabaf275aeb2aaf8ac19 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 26 Jul 2014 22:35:05 +0200 Subject: [PATCH 0048/2474] Implement quick slots (closes #9) --- defs.h | 7 +++ player.qc | 2 - qw.qc | 6 +- tfort.qc | 11 +++- tforthlp.qc | 8 +++ weapons.qc | 162 +++++++++++++++++++++------------------------------- 6 files changed, 94 insertions(+), 102 deletions(-) diff --git a/defs.h b/defs.h index 3d4f1c4e..cd27b77b 100644 --- a/defs.h +++ b/defs.h @@ -333,6 +333,12 @@ #define FLAG_INFO 23 #define HOOK_IMP2 39 +// Quick weapon impulses +#define TF_QUICKSLOT1 31 +#define TF_QUICKSLOT2 32 +#define TF_QUICKSLOT3 33 +#define TF_QUICKSLOT4 34 + // Axe #define AXE_IMP 40 @@ -351,6 +357,7 @@ #define TF_CAM_FADETOWHITE 61 #define TF_CAM_FADEFROMWHITE 62 +#define TF_QUICKLAST 68 #define TF_WEAPLAST 69 // CF map voting diff --git a/player.qc b/player.qc index 29c544d1..80ba0168 100644 --- a/player.qc +++ b/player.qc @@ -496,8 +496,6 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { self.tfstate = self.tfstate - (self.tfstate & 2048); TeamFortress_SetSpeed(self); if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { - self.last_weapon = self.current_weapon; - self.last_weaponmode = self.weaponmode; self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_GetSlot(); W_SetCurrentAmmo(); diff --git a/qw.qc b/qw.qc index 4a7c89ee..0c968ac9 100644 --- a/qw.qc +++ b/qw.qc @@ -125,8 +125,10 @@ float coop; .float weapons_carried; // the weapons the player is carrying .float current_weapon; // the weapon the player is using .float current_weaponslot; // the currently equipped weaponslot -.float last_weapon; -.float last_weaponmode; +.float last_weaponslot; // the last equipped weaponslot +.float slast_weaponslot; // the second last equipped weaponslot +.float queue_weaponslot; // the weaponslot to switch to when possible +.float quick_weapon; // TRUE if the player is using a quick weapon slot .float next_weapon; // used by weapon slots to communicate which weapon to select .float next_weaponmode; // used by weapon slots to communicate which weapon mode to select diff --git a/tfort.qc b/tfort.qc index 543aca5c..4df43f8b 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1335,8 +1335,7 @@ void () TeamFortress_SetEquipment = { self.current_weapon = 0; self.current_weaponslot = 1; self.weaponmode = 0; - self.last_weapon = 0; - self.last_weaponmode = 0; + self.last_weaponslot = 1; } self.tf_items = 0; @@ -2509,6 +2508,14 @@ void (string halias, float himpulse1, float himpulse2) TeamFortress_Alias = { stuffcmd(self, "\"\n"); }; +void (string halias, string commands) TeamFortress_AliasString = { + stuffcmd(self, "alias "); + stuffcmd(self, halias); + stuffcmd(self, " \""); + stuffcmd(self, commands); + stuffcmd(self, "\"\n"); +}; + void () TeamFortress_Regenerate = { if (self.owner.playerclass == PC_MEDIC) { self.nextthink = time + PC_MEDIC_REGEN_TIME; diff --git a/tforthlp.qc b/tforthlp.qc index d5f0cc16..9318bd45 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -90,6 +90,14 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); + TeamFortress_AliasString("+slot1", "impulse 31;+attack"); + TeamFortress_AliasString("-slot1", "-attack;impulse 68"); + TeamFortress_AliasString("+slot2", "impulse 32;+attack"); + TeamFortress_AliasString("-slot2", "-attack;impulse 68"); + TeamFortress_AliasString("+slot3", "impulse 33;+attack"); + TeamFortress_AliasString("-slot3", "-attack;impulse 68"); + TeamFortress_AliasString("+slot4", "impulse 34;+attack"); + TeamFortress_AliasString("-slot4", "-attack;impulse 68"); TeamFortress_Alias("showscores", TF_TEAM_SCORES, 0); TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); TeamFortress_Alias("query", TF_STATUS_QUERY, 0); diff --git a/weapons.qc b/weapons.qc index f88d4d94..3fba5034 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1026,8 +1026,6 @@ void () W_FireLightning = { local float cells; if (self.ammo_cells < 1) { - self.last_weapon = self.current_weapon; - self.last_weaponmode = self.weaponmode; self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_GetSlot(); W_SetCurrentAmmo(); @@ -1235,8 +1233,6 @@ void (float ox) W_FireSpikes = { return; } if (self.ammo_nails < 1) { - self.last_weapon = self.current_weapon; - self.last_weaponmode = self.weaponmode; self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_GetSlot(); W_SetCurrentAmmo(); @@ -1891,11 +1887,6 @@ float (float inp) W_AmmoSlot = { }; void () W_WeaponSlot1 = { - self.next_weaponmode = 0; - - if (! W_AmmoSlot(1)) - return; - if (self.playerclass == PC_SCOUT) self.next_weapon = WEAP_NAILGUN; else if (self.playerclass == PC_SNIPER) @@ -1914,16 +1905,9 @@ void () W_WeaponSlot1 = { self.next_weapon = WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) self.next_weapon = WEAP_LASER; - - self.current_weaponslot = 1; }; void () W_WeaponSlot2 = { - self.next_weaponmode = 0; - - if (! W_AmmoSlot(2)) - return; - if (self.playerclass == PC_SCOUT) self.next_weapon = WEAP_SHOTGUN; else if (self.playerclass == PC_SNIPER) @@ -1939,22 +1923,15 @@ void () W_WeaponSlot2 = { self.next_weaponmode = 1; } else if (self.playerclass == PC_PYRO) self.next_weapon = WEAP_INCENDIARY; - - self.current_weaponslot = 2; }; void () W_WeaponSlot3 = { - self.next_weaponmode = 0; - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) { sprint(self, PRINT_HIGH, "No weapon\n"); return; } - if (! W_AmmoSlot(3)) - return; - if (self.playerclass == PC_SNIPER || self.playerclass == PC_SPY) self.next_weapon = WEAP_NAILGUN; @@ -1964,111 +1941,95 @@ void () W_WeaponSlot3 = { || self.playerclass == PC_HVYWEAP || self.playerclass == PC_PYRO) self.next_weapon = WEAP_SHOTGUN; - - self.current_weaponslot = 3; }; void () W_WeaponSlot4 = { - self.next_weaponmode = 0; - if (self.weapons_carried & WEAP_MEDIKIT) self.next_weapon = WEAP_MEDIKIT; else if (self.weapons_carried & WEAP_SPANNER) self.next_weapon = WEAP_SPANNER; else self.next_weapon = WEAP_AXE; - - self.current_weaponslot = 4; -}; - -float () W_AmmoLast = { - if ((self.last_weapon == WEAP_SNIPER_RIFLE - || self.next_weapon == WEAP_AUTO_RIFLE - || self.next_weapon == WEAP_SHOTGUN - || self.next_weapon == WEAP_SUPER_SHOTGUN - || self.next_weapon == WEAP_ASSAULT_CANNON - || self.next_weapon == WEAP_TRANQ) - && self.ammo_shells < 1) - self.noammo = 1; - else if (self.last_weapon == WEAP_SUPER_SHOTGUN && self.ammo_shells < 2) - self.noammo = 1; - else if (self.last_weapon == WEAP_NAILGUN && self.ammo_nails < 2) - self.noammo = 1; - else if (self.last_weapon == WEAP_SUPER_NAILGUN && self.ammo_nails < 4) - self.noammo = 1; - else if (self.last_weapon == WEAP_LASER && self.ammo_nails < 1) - self.noammo = 1; - else if ((self.last_weapon == WEAP_GRENADE_LAUNCHER - || self.last_weapon == WEAP_ROCKET_LAUNCHER) - && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.last_weapon == WEAP_FLAMETHROWER && self.ammo_cells < 1) - self.noammo = 1; - else if (self.last_weapon == WEAP_INCENDIARY && self.ammo_rockets < 3) - self.noammo = 1; - else if (self.last_weapon == WEAP_ASSAULT_CANNON && self.ammo_cells < 7) - self.noammo = 2; - - if (self.noammo > 0) - return 0; - else - return 1; }; void (float inp) W_ChangeWeapon = { - if (self.tfstate & TFSTATE_RELOADING) + if (self.playerclass == 0) return; - if (inp == 1) - W_WeaponSlot1(); - else if (inp == 2) - W_WeaponSlot2(); - else if (inp == 3) - W_WeaponSlot3(); - else if (inp == 4) - W_WeaponSlot4(); - else if (inp == 5) { + if (inp == 5) { if (self.playerclass == PC_ENGINEER) TeamFortress_EngineerBuild(); - else if (self.playerclass == PC_SCOUT) { + else if (self.playerclass == PC_SCOUT) Menu_Scout(); - } else if (self.playerclass == PC_SPY) + else if (self.playerclass == PC_SPY) TeamFortress_SpyGoUndercover(); else if (self.playerclass == PC_DEMOMAN) TeamFortress_DetpackMenu(); - } else if (inp == TF_WEAPLAST) { - if (W_AmmoLast()) { - self.next_weapon = self.last_weapon; - self.next_weaponmode = self.last_weaponmode; - } + return; } - self.impulse = 0; + // queue next weapon (in case of attack/reload in progress) + if (!self.queue_weaponslot) { + if (inp == TF_WEAPLAST) + self.queue_weaponslot = TF_WEAPLAST; + else if (inp < 5 && !(self.quick_weapon && (self.tfstate & TFSTATE_RELOADING))) + self.queue_weaponslot = inp; + } - if (inp != 5) { + // don't do anything yet if still reloading + if (self.tfstate & TFSTATE_RELOADING) { + return; + } + + // don't do anything without a weapon queue + if (!self.queue_weaponslot) + return; + + // check for ammo + if (! W_AmmoSlot(self.queue_weaponslot)) { if (self.noammo == 1) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); + self.queue_weaponslot = 0; return; } else if (self.noammo == 2) { sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); + self.queue_weaponslot = 0; return; } + } - if (self.current_weapon != self.next_weapon - || self.weaponmode != self.next_weaponmode) { - self.last_weaponmode = self.weaponmode; - self.last_weapon = self.current_weapon; - self.current_weapon = self.next_weapon; - self.weaponmode = self.next_weaponmode; - } + if (self.queue_weaponslot == TF_WEAPLAST) { + self.queue_weaponslot = self.last_weaponslot; + if (self.quick_weapon) + self.last_weaponslot = self.slast_weaponslot; + } - if (self.current_weapon != self.last_weapon - || self.weaponmode != self.last_weaponmode) - W_PrintWeaponMessage(); + self.next_weaponmode = 0; + if (self.queue_weaponslot == 1) + W_WeaponSlot1(); + else if (self.queue_weaponslot == 2) + W_WeaponSlot2(); + else if (self.queue_weaponslot == 3) + W_WeaponSlot3(); + else if (self.queue_weaponslot == 4) + W_WeaponSlot4(); - W_SetCurrentAmmo(); - Status_Refresh(self); + if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { + if (!(self.quick_weapon && inp == TF_WEAPLAST)) { + self.slast_weaponslot = self.last_weaponslot; + self.last_weaponslot = self.current_weaponslot; + } + self.current_weaponslot = self.queue_weaponslot; + self.current_weapon = self.next_weapon; + self.weaponmode = self.next_weaponmode; + if (!self.quick_weapon) + W_PrintWeaponMessage(); } + + W_SetCurrentAmmo(); + Status_Refresh(self); + self.quick_weapon = 0; + self.queue_weaponslot = 0; }; void () CycleWeaponNext = { @@ -2162,11 +2123,17 @@ void () ImpulseCommands = { if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { if (self.impulse >= 1 && self.impulse <= 5) W_ChangeWeapon(self.impulse); - else if (self.impulse == TF_WEAPNEXT) + else if (self.impulse >= 31 && self.impulse <= 34) { + self.quick_weapon = 1; + W_ChangeWeapon((self.impulse - 30)); + } else if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); else if (self.impulse == TF_WEAPPREV) CycleWeaponPrev(); - else if ((self.impulse == TF_WEAPLAST) && (self.last_weapon != 0)) + else if (self.impulse == TF_QUICKLAST) { + self.quick_weapon = 1; + W_ChangeWeapon(TF_WEAPLAST); + } else if (self.impulse == TF_WEAPLAST && self.last_weaponslot != 0) W_ChangeWeapon(self.impulse); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); @@ -2385,6 +2352,9 @@ void () W_WeaponFrame = { local float zoomkey = stof(infokey(self, "zk")); local float instazoom = stof(infokey(self, "zi")); + if (self.queue_weaponslot) + W_ChangeWeapon(self.queue_weaponslot); + if (self.impulse == TF_CHANGETEAM) { Menu_Team(); return; From a8e68e9c533e19d569f25b081ef68b072e036b7b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 27 Jul 2014 20:42:38 +0200 Subject: [PATCH 0049/2474] Fix issues with remembering last weapon during quick slot fire --- qw.qc | 1 + weapons.qc | 43 ++++++++++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/qw.qc b/qw.qc index 0c968ac9..61baac56 100644 --- a/qw.qc +++ b/qw.qc @@ -129,6 +129,7 @@ float coop; .float slast_weaponslot; // the second last equipped weaponslot .float queue_weaponslot; // the weaponslot to switch to when possible .float quick_weapon; // TRUE if the player is using a quick weapon slot +.float quick_weaponchange; // TRUE if attempting to change weapon (during quick fire) when not yet ready .float next_weapon; // used by weapon slots to communicate which weapon to select .float next_weaponmode; // used by weapon slots to communicate which weapon mode to select diff --git a/weapons.qc b/weapons.qc index 3fba5034..046bc25b 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1969,17 +1969,21 @@ void (float inp) W_ChangeWeapon = { } // queue next weapon (in case of attack/reload in progress) - if (!self.queue_weaponslot) { + if (!self.queue_weaponslot || self.queue_weaponslot != inp) { + // set quick_weaponchange when player tries to change weapon during quick weapon fire/reload + if (((self.tfstate & TFSTATE_RELOADING) || time < self.attack_finished) && self.quick_weapon) { + if (inp == TF_WEAPLAST) + self.quick_weaponchange = 1; + } if (inp == TF_WEAPLAST) self.queue_weaponslot = TF_WEAPLAST; else if (inp < 5 && !(self.quick_weapon && (self.tfstate & TFSTATE_RELOADING))) self.queue_weaponslot = inp; } - // don't do anything yet if still reloading - if (self.tfstate & TFSTATE_RELOADING) { + // don't do anything yet if still reloading or attack in progress + if (self.tfstate & TFSTATE_RELOADING || time < self.attack_finished) return; - } // don't do anything without a weapon queue if (!self.queue_weaponslot) @@ -1998,8 +2002,10 @@ void (float inp) W_ChangeWeapon = { } } + // queue last weaponslot if (self.queue_weaponslot == TF_WEAPLAST) { self.queue_weaponslot = self.last_weaponslot; + // use second last weapon when switching back from quick fire if (self.quick_weapon) self.last_weaponslot = self.slast_weaponslot; } @@ -2014,11 +2020,15 @@ void (float inp) W_ChangeWeapon = { else if (self.queue_weaponslot == 4) W_WeaponSlot4(); - if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { + if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode || self.quick_weapon) { + // set last weapons when not using quick fire if (!(self.quick_weapon && inp == TF_WEAPLAST)) { self.slast_weaponslot = self.last_weaponslot; self.last_weaponslot = self.current_weaponslot; } + // set last weapon to second last when changing weapons during quick attack/reload + if (self.quick_weaponchange && !self.quick_weapon) + self.last_weaponslot = self.slast_weaponslot; self.current_weaponslot = self.queue_weaponslot; self.current_weapon = self.next_weapon; self.weaponmode = self.next_weaponmode; @@ -2029,6 +2039,7 @@ void (float inp) W_ChangeWeapon = { W_SetCurrentAmmo(); Status_Refresh(self); self.quick_weapon = 0; + self.quick_weaponchange = 0; self.queue_weaponslot = 0; }; @@ -2121,19 +2132,11 @@ void () ImpulseCommands = { } if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { - if (self.impulse >= 1 && self.impulse <= 5) - W_ChangeWeapon(self.impulse); - else if (self.impulse >= 31 && self.impulse <= 34) { - self.quick_weapon = 1; - W_ChangeWeapon((self.impulse - 30)); - } else if (self.impulse == TF_WEAPNEXT) + if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); else if (self.impulse == TF_WEAPPREV) CycleWeaponPrev(); - else if (self.impulse == TF_QUICKLAST) { - self.quick_weapon = 1; - W_ChangeWeapon(TF_WEAPLAST); - } else if (self.impulse == TF_WEAPLAST && self.last_weaponslot != 0) + else if (self.impulse == TF_WEAPLAST && self.last_weaponslot != 0) W_ChangeWeapon(self.impulse); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); @@ -2352,6 +2355,16 @@ void () W_WeaponFrame = { local float zoomkey = stof(infokey(self, "zk")); local float instazoom = stof(infokey(self, "zi")); + if (self.impulse >= 1 && self.impulse <= 5) { + self.quick_weapon = 0; + W_ChangeWeapon(self.impulse); + } else if (self.impulse >= 31 && self.impulse <= 34) { + self.quick_weapon = 1; + W_ChangeWeapon((self.impulse - 30)); + } else if (self.impulse == TF_QUICKLAST) { + self.quick_weapon = 1; + W_ChangeWeapon(TF_WEAPLAST); + } if (self.queue_weaponslot) W_ChangeWeapon(self.queue_weaponslot); From 132df986334df6c1bf2e1db3a38fe8f306984efd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 27 Jul 2014 20:44:02 +0200 Subject: [PATCH 0050/2474] Add +det255 alias --- tforthlp.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tforthlp.qc b/tforthlp.qc index 9318bd45..6382589f 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -133,6 +133,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-det20", TF_DETPACK_STOP, 0); TeamFortress_Alias("+det50", TF_DETPACK_50, 0); TeamFortress_Alias("-det50", TF_DETPACK_STOP, 0); + TeamFortress_Alias("+det255", TF_DETPACK, 255); + TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); } else if (self.motd == 85) { TeamFortress_Alias("clan1", 82, 0); TeamFortress_Alias("clan2", 83, 0); From 7dddb4b30d1d359870ee7931097f95c67612c732 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 27 Jul 2014 20:55:11 +0200 Subject: [PATCH 0051/2474] Add spaces after green winning team in status bar --- status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.qc b/status.qc index 058a6815..8c6d4a1a 100644 --- a/status.qc +++ b/status.qc @@ -162,7 +162,7 @@ void (entity pl) RefreshStatusBar = { else if (win == 3) st1 = strcat(YellowScoreToString(team3score), " "); else - st1 = GreenScoreToString(team4score); + st1 = strcat(GreenScoreToString(team4score), " "); // status line 3 column 2 - team 2 score if (sec == 0) st2 = RedScoreToString(team2score); From ef80895b8bfec48b18442334efabc24ae7264236 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 27 Jul 2014 21:34:42 +0200 Subject: [PATCH 0052/2474] Add /classhelp command (closes #25) --- defs.h | 3 + help.qc | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++ progs.src | 1 + tforthlp.qc | 1 + weapons.qc | 3 + 5 files changed, 173 insertions(+) create mode 100644 help.qc diff --git a/defs.h b/defs.h index cd27b77b..281af7d2 100644 --- a/defs.h +++ b/defs.h @@ -328,6 +328,9 @@ // Alias check to see whether they already have the aliases #define TF_ALIAS_CHECK 13 +// Class help alias +#define TF_CLASSHELP 14 + // CTF Support Impulses #define HOOK_IMP1 22 #define FLAG_INFO 23 diff --git a/help.qc b/help.qc new file mode 100644 index 00000000..ed777342 --- /dev/null +++ b/help.qc @@ -0,0 +1,165 @@ +// CLASS HELP FOR CLASSIC FORTRESS +// =============================== +// Shows class bindings for each class. + +// functions by order of appearance +void () Help_Show; +void () Help_ShowScout; +void () Help_ShowSniper; +void () Help_ShowSoldier; +void () Help_ShowDemoman; +void () Help_ShowMedic; +void () Help_ShowHWGuy; +void () Help_ShowPyro; +void () Help_ShowSpy; +void () Help_ShowEngineer; + +// global variables +// + +// shows a list of key bindings and aliases for current class +// called from weapons.qc:ImpulseCommands() +void () Help_Show = { + if (self.playerclass == PC_SCOUT) + Help_ShowScout(); + if (self.playerclass == PC_SNIPER) + Help_ShowSniper(); + if (self.playerclass == PC_SOLDIER) + Help_ShowSoldier(); + if (self.playerclass == PC_DEMOMAN) + Help_ShowDemoman(); + if (self.playerclass == PC_MEDIC) + Help_ShowMedic(); + if (self.playerclass == PC_HVYWEAP) + Help_ShowHWGuy(); + if (self.playerclass == PC_PYRO) + Help_ShowPyro(); + if (self.playerclass == PC_SPY) + Help_ShowSpy(); + if (self.playerclass == PC_ENGINEER) + Help_ShowEngineer(); +}; + +void () Help_ShowScout = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Scout:\n"); + sprint(self, PRINT_HIGH, "± - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, "² - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "ε - Toggle Scanner on/off\n"); + sprint(self, PRINT_HIGH, "ζ - Throw Caltrop Canisters\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Concussion Grenade\n"); + sprint(self, PRINT_HIGH, "\nClass aliases for Scout:\n"); + sprint(self, PRINT_HIGH, "αυτοσγαξ - Toggle Scanner on/off\n"); + sprint(self, PRINT_HIGH, "σγαξσουξδ - Toggle Scanner sound on/off\n"); + sprint(self, PRINT_HIGH, "σγαξε - Toggle scanning of enemies on/off\n"); + sprint(self, PRINT_HIGH, "σγαξζ - Toggle scanning of friendlies on/off\n"); +}; + +void () Help_ShowSniper = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Sniper:\n"); + sprint(self, PRINT_HIGH, "± - Equip Sniper Rifle\n"); + sprint(self, PRINT_HIGH, "² - Equip Sniper Rifle on Full Auto\n"); + sprint(self, PRINT_HIGH, "³ - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "ε - Set autozoom mode / zoom toggle\n"); + sprint(self, PRINT_HIGH, "ζ - Throw Flare\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "\nClass aliases for Sniper:\n"); + sprint(self, PRINT_HIGH, "ϊοοντοηημε - Change autozoom mode / zoom toggle\n"); + sprint(self, PRINT_HIGH, "ϊοονσετ²ψ - Set autozoom to 2x / zoom to 2x\n"); + sprint(self, PRINT_HIGH, "ϊοονσετ΄ψ - Set autozoom to 4x / zoom to 4x\n"); + sprint(self, PRINT_HIGH, "ϊοονσετοζζ - Turn off autozoom / zoom out\n"); + sprint(self, PRINT_HIGH, "\nSettings for Sniper:\n"); + sprint(self, PRINT_HIGH, "ϊλ Ό±―°Ύ - Toggle zoom upon pressing special key on/off\n"); + sprint(self, PRINT_HIGH, "ϊι Ό±―°Ύ - Zoom instantly (not smoothly) on/off\n"); + sprint(self, PRINT_HIGH, "ϊς Ό±―°Ύ - Reverse zoom order on/off\n"); + sprint(self, PRINT_HIGH, "ϊ²ψ ΌζοφΎ - Set fov used for 2x zoom mode (default 40)\n"); + sprint(self, PRINT_HIGH, "ϊ΄ψ ΌζοφΎ - Set fov used for 4x zoom mode (default 20)\n"); + sprint(self, PRINT_HIGH, "Usage: setinfo \n"); +}; + +void () Help_ShowSoldier = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Soldier:\n"); + sprint(self, PRINT_HIGH, "± - Equip Rocket Launcher\n"); + sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "ζ - Prime/throw Nail Grenade\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); +}; + +void () Help_ShowDemoman = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Demolitions Man:\n"); + sprint(self, PRINT_HIGH, "± - Equip Grenade Launcher\n"); + sprint(self, PRINT_HIGH, "² - Equip Pipebomb Launcher\n"); + sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "΅ - Detpack menu\n"); + sprint(self, PRINT_HIGH, "ε - Detonate pipebombs\n"); + sprint(self, PRINT_HIGH, "ζ - Prime/throw Mirv Grenade\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "\nClass aliases for Demolitions Man:\n"); + sprint(self, PRINT_HIGH, "δετπιπε - Detonate pipebombs\n"); + sprint(self, PRINT_HIGH, "«δετ΅ - Place detpack with 5 second timer\n"); + sprint(self, PRINT_HIGH, "«δετ²° - Place detpack with 20 second timer\n"); + sprint(self, PRINT_HIGH, "«δετ΅° - Place detpack with 50 second timer\n"); + sprint(self, PRINT_HIGH, "«δετ²΅΅ - Place detpack with 255 second timer\n"); +}; + +void () Help_ShowMedic = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Combat Medic:\n"); + sprint(self, PRINT_HIGH, "± - Equip Super Nailgun\n"); + sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Medikit\n"); + sprint(self, PRINT_HIGH, "ζ - Prime/throw Concussion Grenade\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); +}; + +void () Help_ShowHWGuy = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Heavy Weapons Guy:\n"); + sprint(self, PRINT_HIGH, "± - Equip Assault Cannon\n"); + sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "ζ - Prime/throw Mirv Grenade\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); +}; + +void () Help_ShowPyro = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Pyro:\n"); + sprint(self, PRINT_HIGH, "± - Equip Flamethrower\n"); + sprint(self, PRINT_HIGH, "² - Equip Incendiary Cannon\n"); + sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "ζ - Prime/throw Napalm Grenade\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); +}; + +void () Help_ShowSpy = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Spy:\n"); + sprint(self, PRINT_HIGH, "± - Equip Tranquiliser Gun\n"); + sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "³ - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Knife\n"); + sprint(self, PRINT_HIGH, "΅ - Disguise menu\n"); + sprint(self, PRINT_HIGH, "ε - Silently feign death\n"); + sprint(self, PRINT_HIGH, "ζ - Prime/throw Gas Grenade\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "\nClass aliases for Spy:\n"); + sprint(self, PRINT_HIGH, "ζειηξ - Feign death\n"); + sprint(self, PRINT_HIGH, "σζειηξ - Silently feign death\n"); +}; + +void () Help_ShowEngineer = { + sprint(self, PRINT_HIGH, "\nDefault bindings for Engineer:\n"); + sprint(self, PRINT_HIGH, "± - Equip Railgun\n"); + sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "΄ - Equip Spanner\n"); + sprint(self, PRINT_HIGH, "΅ - Build/destroy menu\n"); + sprint(self, PRINT_HIGH, "ζ - Prime/throw EMP Grenade\n"); + sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "\nClass aliases for Engineer:\n"); + sprint(self, PRINT_HIGH, "δετδισπεξσες - Detonate Dispenser\n"); + sprint(self, PRINT_HIGH, "δετσεξτςω - Detonate Sentry Gun\n"); +}; diff --git a/progs.src b/progs.src index 4f2fdd68..d75276c7 100644 --- a/progs.src +++ b/progs.src @@ -6,6 +6,7 @@ debug.qc status.qc menu.qc vote.qc +help.qc subs.qc combat.qc items.qc diff --git a/tforthlp.qc b/tforthlp.qc index 6382589f..58dd0885 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -64,6 +64,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("spy", TF_CHANGEPC + PC_SPY, 0); TeamFortress_Alias("engineer", TF_CHANGEPC + PC_ENGINEER, 0); TeamFortress_Alias("randompc", TF_CHANGEPC + PC_RANDOM, 0); + TeamFortress_Alias("classhelp", TF_CLASSHELP, 0); TeamFortress_Alias("is_aliased", TF_ALIAS_CHECK, 0); } else if (self.motd == 25) { TeamFortress_Alias("menu", TF_CLASSMENU, 0); diff --git a/weapons.qc b/weapons.qc index 046bc25b..f1cf31e9 100644 --- a/weapons.qc +++ b/weapons.qc @@ -39,6 +39,7 @@ void () SniperSight_Create; void (float zoom_level) TF_zoom; +void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void () TeamFortress_ID; @@ -2246,6 +2247,8 @@ void () PreMatchImpulses = { void () DeadImpulses = { if (self.impulse == TF_SHOWTF) TeamFortress_ShowTF(); + else if (self.impulse == TF_CLASSHELP) + Help_Show(); else if (self.impulse == TF_ZOOMTOGGLE) TeamFortress_ZoomToggle(); else if (self.impulse == TF_ZOOMOFF) From 6e68ec0a56acf13b35a629fdefec6b599bb4aad0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 27 Jul 2014 21:36:41 +0200 Subject: [PATCH 0053/2474] Fix menu input bug introduced with commit a8e68e9c533e19d569f25b081ef68b072e036b7b --- weapons.qc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/weapons.qc b/weapons.qc index f1cf31e9..4a8dbb7d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2358,6 +2358,13 @@ void () W_WeaponFrame = { local float zoomkey = stof(infokey(self, "zk")); local float instazoom = stof(infokey(self, "zi")); + if (self.menu_input) { + if (self.impulse > 0 && self.impulse <= 10) { + Menu_Input(self.impulse); + return; + } + } + if (self.impulse >= 1 && self.impulse <= 5) { self.quick_weapon = 0; W_ChangeWeapon(self.impulse); @@ -2387,13 +2394,6 @@ void () W_WeaponFrame = { return; } - if (self.menu_input) { - if (self.impulse > 0 && self.impulse <= 10) { - Menu_Input(self.impulse); - return; - } - } - if (intermission_running || cease_fire) return; From e12984ce3456afaafdf1c72338ea1532cc51805e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 27 Jul 2014 22:15:29 +0200 Subject: [PATCH 0054/2474] Add option to disable grenade timer and timer sound (closes #35) --- tfort.qc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tfort.qc b/tfort.qc index 4df43f8b..081c9654 100644 --- a/tfort.qc +++ b/tfort.qc @@ -447,7 +447,8 @@ void () GrenadeTimer = { Status_Refresh(self.owner); if (self.heat > 0) { - stuffcmd(self.owner, "play items/grentimer.wav\n"); + if (!stof(infokey(self.owner, "nts"))) + stuffcmd(self.owner, "play items/grentimer.wav\n"); self.nextthink = time + 1.0; } else { dremove(self); @@ -630,12 +631,14 @@ void (float inp) TeamFortress_PrimeGrenade = { } } - timer = spawn(); - timer.nextthink = time + 0.8; - timer.think = GrenadeTimer; - timer.heat = 4; - timer.owner = self; - timer.classname = "gtimer"; + if (!stof(infokey(self, "nt"))) { + timer = spawn(); + timer.nextthink = time + 0.8; + timer.think = GrenadeTimer; + timer.heat = 4; + timer.owner = self; + timer.classname = "gtimer"; + } } tGrenade.think = TeamFortress_GrenadePrimed; From bb111a573032781db04fa79daae32987d862079d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 10:21:27 +0200 Subject: [PATCH 0055/2474] Rename team 1/2 to blue/red (closes #74) --- tfortmap.qc | 4 ++-- tforttm.qc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 3b1b11a6..89bb00ab 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2302,7 +2302,7 @@ void () item_flag_team2 = { precache_sound("ogre/ogwake.wav"); precache_sound("boss2/pop2.wav"); self.classname = "item_tfgoal"; - self.netname = "Team 1 Flag"; + self.netname = "Blue Flag"; self.broadcast = " ΗΟΤ the enemy team's flag!\n"; self.deathtype = "You've got the enemy flag!\n"; self.noise = "ogre/ogwake.wav"; @@ -2377,7 +2377,7 @@ void () item_flag_team1 = { precache_sound("ogre/ogwake.wav"); precache_sound("boss2/pop2.wav"); self.classname = "item_tfgoal"; - self.netname = "Team 2 Flag"; + self.netname = "Red Flag"; self.broadcast = " ΗΟΤ the enemy team's flag!\n"; self.deathtype = "You've got the enemy flag!\n"; self.noise = "ogre/ogwake.wav"; diff --git a/tforttm.qc b/tforttm.qc index a38d92a6..0d8ba520 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -563,7 +563,7 @@ string(float tno) TeamFortress_TeamGetColorString = return ("DarkGreen"); if (col == YELLOW) return ("Yellow"); - return ("DarkBlue"); + return ("Blue"); }; void (entity Player) TeamFortress_TeamShowMemberClasses = { From d0a60f49986c19a7c8556b5bf426b79643d9f47a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 10:46:36 +0200 Subject: [PATCH 0056/2474] Change some hwguy tfstates to understandable constants --- client.qc | 9 +++------ weapons.qc | 27 ++++++++++++++------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/client.qc b/client.qc index 96d2c78d..1cd55afc 100644 --- a/client.qc +++ b/client.qc @@ -1270,13 +1270,11 @@ void () PlayerJump = { else sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } - if (self.fire_held_down && - (self.current_weapon == WEAP_ASSAULT_CANNON)) { + if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { stuffcmd(self, "v_idlescale 0\n"); self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); - self.tfstate = - self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); self.weaponframe = 0; self.heat = 0; @@ -1295,8 +1293,7 @@ void () PlayerJump = { sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); - if (self.fire_held_down && - (self.current_weapon == WEAP_ASSAULT_CANNON)) { + if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { stuffcmd(self, "v_idlescale 0\n"); sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); diff --git a/weapons.qc b/weapons.qc index 4a8dbb7d..f2048dbf 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1338,7 +1338,8 @@ void () W_SetCurrentAmmo = { if ((self.health <= 0) || (self.current_weapon == 0)) return; - if ((self.current_weapon == 32768) && (self.tfstate & 65536)) + if ((self.current_weapon == WEAP_ASSAULT_CANNON) + && (self.tfstate & TFSTATE_CANT_MOVE)) return; player_run(); @@ -1448,7 +1449,7 @@ void () W_SetCurrentAmmo = { } self.items = self.items | 256; self.weapon = 2; - } else if (self.current_weapon == 32768) { + } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { self.currentammo = self.ammo_shells; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_asscan.mdl"; @@ -1510,8 +1511,8 @@ float () W_BestWeapon = { if (((self.ammo_cells >= 1) && (it & 65536)) && (self.waterlevel <= 1)) return (65536); else if (((self.ammo_cells >= 7) && (self.ammo_shells >= 1)) && - (it & 32768)) - return (32768); + (it & WEAP_ASSAULT_CANNON)) + return (WEAP_ASSAULT_CANNON); else if ((self.ammo_cells >= 1) && (it & 4096)) return (4096); else if ((self.ammo_nails >= 2) && (it & 1024)) @@ -2445,9 +2446,9 @@ void () W_WeaponFrame = { ImpulseCommands(); if ((!self.button0 && self.fire_held_down) && - (self.current_weapon == 32768)) { + (self.current_weapon == WEAP_ASSAULT_CANNON)) { self.fire_held_down = 0; - self.tfstate = self.tfstate - (self.tfstate & 65536); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); player_run(); } @@ -2489,8 +2490,8 @@ void () W_WeaponFrame = { TeamFortress_SetSpeed(self); } } - } else if (self.current_weapon == 32768) { - if (self.flags & 512) { + } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { + if (self.flags & FL_ONGROUND) { SuperDamageSound(); W_Attack(); } else { @@ -2503,15 +2504,15 @@ void () W_WeaponFrame = { } } else if (self.playerclass == 0) { self.weaponmode = 0; - } else if (self.tfstate & 2048) { - if (self.current_weapon != 32768) { + } else if (self.tfstate & TFSTATE_AIMING) { + if (self.current_weapon != WEAP_ASSAULT_CANNON) { W_Attack(); } - self.tfstate = self.tfstate - 2048; + self.tfstate = self.tfstate - TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.heat = 0; - } else if (self.tfstate & 65536) { - self.tfstate = self.tfstate - 65536; + } else if (self.tfstate & TFSTATE_CANT_MOVE) { + self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); self.heat = 0; } From d3f53f250e54000f0938acddedb1dee09c9b2b23 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 10:47:06 +0200 Subject: [PATCH 0057/2474] Stop spamming assault cannon error messages in air (fixes #52) --- client.qc | 6 ++++-- qw.qc | 3 +++ weapons.qc | 6 +++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 1cd55afc..1e152021 100644 --- a/client.qc +++ b/client.qc @@ -1295,8 +1295,10 @@ void () PlayerJump = { if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { stuffcmd(self, "v_idlescale 0\n"); - sprint(self, PRINT_MEDIUM, - "You cannot fire the assault cannon without your feet on the ground...\n"); + if (self.antispam_cannon_air < time) { + sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); + self.antispam_cannon_air = time + 3; + } self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); diff --git a/qw.qc b/qw.qc index 61baac56..e06f2f4c 100644 --- a/qw.qc +++ b/qw.qc @@ -330,6 +330,9 @@ float already_chosen_map; .float FlashTime; .float nailpos; +// anti spam +.float antispam_cannon_air; // message shown while trying to fire assault cannon while in the air + // status bar stuff .string StatusString; // current centerprint text (strzone'd!) .float StatusStringLines; // how many lines the centerprint is diff --git a/weapons.qc b/weapons.qc index f2048dbf..91077f9b 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2494,9 +2494,9 @@ void () W_WeaponFrame = { if (self.flags & FL_ONGROUND) { SuperDamageSound(); W_Attack(); - } else { - sprint(self, PRINT_MEDIUM, - "You cannot fire the assault cannon without your feet on the ground...\n"); + } else if (self.antispam_cannon_air < time) { + sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); + self.antispam_cannon_air = time + 3; } } else { SuperDamageSound(); From 39f30cbe82007b65cbbbb55542b79c93ce0c9182 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 10:48:19 +0200 Subject: [PATCH 0058/2474] Don't switch to last weapon if no ammo (introduced in commit 78fa759e0ce92e268b44aabaf275aeb2aaf8ac19) --- weapons.qc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/weapons.qc b/weapons.qc index 91077f9b..3620cd0c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1991,6 +1991,14 @@ void (float inp) W_ChangeWeapon = { if (!self.queue_weaponslot) return; + // queue last weaponslot + if (self.queue_weaponslot == TF_WEAPLAST) { + self.queue_weaponslot = self.last_weaponslot; + // use second last weapon when switching back from quick fire + if (self.quick_weapon) + self.last_weaponslot = self.slast_weaponslot; + } + // check for ammo if (! W_AmmoSlot(self.queue_weaponslot)) { if (self.noammo == 1) { @@ -2004,14 +2012,6 @@ void (float inp) W_ChangeWeapon = { } } - // queue last weaponslot - if (self.queue_weaponslot == TF_WEAPLAST) { - self.queue_weaponslot = self.last_weaponslot; - // use second last weapon when switching back from quick fire - if (self.quick_weapon) - self.last_weaponslot = self.slast_weaponslot; - } - self.next_weaponmode = 0; if (self.queue_weaponslot == 1) W_WeaponSlot1(); From a4c0e25ecc65d3dcab4bd63f5521045fd6e97344 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 11:22:17 +0200 Subject: [PATCH 0059/2474] Improve sniper zoom code (fixes #19) --- qw.qc | 5 +++ sniper.qc | 96 ++++++++++++++++++++++++++---------------------------- weapons.qc | 32 +++++++++--------- 3 files changed, 69 insertions(+), 64 deletions(-) diff --git a/qw.qc b/qw.qc index e06f2f4c..82d5cf5a 100644 --- a/qw.qc +++ b/qw.qc @@ -30,11 +30,16 @@ typedef void (float) f_void_float; .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer +.float default_sensitivity; // Player's default (non-zoomed) sensitivity +.float default_fov; // Player's default (non-zoomed) fov .float current_fov; // Player's current field of view .float zoom_level; // Start zooming to this fov next frame .float zoom_mode; // Autozoom: 0 (off), 2 (2x), 4 (4x) .float zoom_in; // TRUE if player is currently zooming in .float zoom_out; // TRUE if player is currently zooming out +.float reversezoom; // Reverse zoom order +.float instazoom; // Zoom instantly without smoothness +.float zoomkey; // Zoom using special key, not +attack .float has_voted_map; // Map option that player voted for .float spawn_time; // Time when player spawned .float menu_time; // Time when vote map menu was first issued diff --git a/sniper.qc b/sniper.qc index c2c3e6e2..539c41f4 100644 --- a/sniper.qc +++ b/sniper.qc @@ -3,13 +3,13 @@ //======================================================== void (float zoom_to) TF_zoom = { - local float default_fov; - local float default_sensitivity; + self.default_fov = stof(infokey(self, "df")); + self.default_sensitivity = stof(infokey(self, "ds")); + self.reversezoom = stof(infokey(self, "zr")); + self.zoomkey = stof(infokey(self, "zk")); + self.instazoom = stof(infokey(self, "zi")); - default_fov = stof(infokey(self, "df")); - default_sensitivity = stof(infokey(self, "ds")); - - if (default_fov == 0) + if (self.default_fov == 0) return; if (zoom_to != self.current_fov) { @@ -18,24 +18,25 @@ void (float zoom_to) TF_zoom = { stuffcmd(self, ftos(zoom_to)); stuffcmd(self, "\n"); - if (default_sensitivity > 0) { + if (self.default_sensitivity > 0) { stuffcmd(self, "sensitivity "); - stuffcmd(self, ftos(default_sensitivity * zoom_to / default_fov)); + stuffcmd(self, ftos(self.default_sensitivity * zoom_to / self.default_fov)); stuffcmd(self, "\n"); } } }; void (entity pl) TF_zoom_reset = { - local float default_sensitivity = stof(infokey(pl, "ds")); - local float default_fov = stof(infokey(pl, "df")); - local float zoomkey = stof(infokey(pl, "zk")); - local float reversezoom = stof(infokey(pl, "zr")); - - pl.current_fov = default_fov; - if (zoomkey) { - pl.zoom_level = default_fov; - if (reversezoom) { + pl.default_sensitivity = stof(infokey(pl, "ds")); + pl.default_fov = stof(infokey(pl, "df")); + pl.reversezoom = stof(infokey(self, "zr")); + pl.zoomkey = stof(infokey(self, "zk")); + pl.instazoom = stof(infokey(self, "zi")); + + pl.current_fov = pl.default_fov; + if (pl.zoomkey) { + pl.zoom_level = pl.default_fov; + if (pl.reversezoom) { if (pl.zoom_mode == 2) pl.zoom_mode = 0; else if (pl.zoom_mode == 4) @@ -48,39 +49,40 @@ void (entity pl) TF_zoom_reset = { pl.zoom_in = 0; pl.zoom_out = 0; - if (default_fov > 0) { + if (pl.default_fov > 0) { stuffcmd(pl, "fov "); stuffcmd(pl, ftos(pl.current_fov)); stuffcmd(pl, "\n"); } - if (default_sensitivity > 0) { + if (pl.default_sensitivity > 0) { stuffcmd(pl, "sensitivity "); - stuffcmd(pl, ftos(default_sensitivity)); + stuffcmd(pl, ftos(pl.default_sensitivity)); stuffcmd(pl, "\n"); } }; void (entity pl) TF_zoom_reset_death = { - local float default_sensitivity = stof(infokey(pl, "ds")); - local float default_fov = stof(infokey(pl, "df")); - - default_fov = stof(infokey(pl, "df")); - default_sensitivity = stof(infokey(pl, "ds")); - - pl.current_fov = default_fov; + pl.default_sensitivity = stof(infokey(pl, "ds")); + pl.default_fov = stof(infokey(pl, "df")); + pl.reversezoom = stof(infokey(self, "zr")); + pl.zoomkey = stof(infokey(self, "zk")); + pl.instazoom = stof(infokey(self, "zi")); + + pl.zoom_level = pl.default_fov; + pl.current_fov = pl.default_fov; pl.zoom_in = 0; pl.zoom_out = 0; - if (default_fov > 0) { + if (pl.default_fov > 0) { stuffcmd(pl, "fov "); stuffcmd(pl, ftos(pl.current_fov)); stuffcmd(pl, "\n"); } - if (default_sensitivity > 0) { + if (pl.default_sensitivity > 0) { stuffcmd(pl, "sensitivity "); - stuffcmd(pl, ftos(default_sensitivity)); + stuffcmd(pl, ftos(pl.default_sensitivity)); stuffcmd(pl, "\n"); } }; @@ -140,56 +142,52 @@ void () SniperSight_Create = { void () TeamFortress_ZoomToggle = { local float zoom4x; local float zoom2x; - local float default_fov; - local float zoomkey = stof(infokey(self, "zk")); - local float instazoom = stof(infokey(self, "zi")); - local float reversezoom = stof(infokey(self, "zr")); if (self.playerclass != PC_SNIPER) return; zoom4x = (stof(infokey(self, "z4x")) > 0) ? stof(infokey(self, "z4x")) : 20; zoom2x = (stof(infokey(self, "z2x")) > 0) ? stof(infokey(self, "z2x")) : 40; - default_fov = stof(infokey(self, "df")); + self.default_fov = stof(infokey(self, "df")); - if (default_fov == 0) { + if (self.default_fov == 0) { sprint(self, PRINT_HIGH, "Use \"setinfo df \" to set default fov to use sniper zoom. Use \"setinfo ds \" to set default sensitivity for sensitivity scaling.\n"); return; } - if ( (self.zoom_mode == 0 && reversezoom == 0) - || (self.zoom_mode == 2 && reversezoom == 1)) { + if ( (self.zoom_mode == 0 && self.reversezoom == 0) + || (self.zoom_mode == 2 && self.reversezoom == 1)) { self.zoom_mode = 4; self.zoom_level = zoom4x; - if (zoomkey == 1) + if (self.zoomkey == 1) sprint(self, PRINT_HIGH, "4x zoom\n"); else sprint(self, PRINT_HIGH, "4x autozoom selected\n"); } - else if ( (self.zoom_mode == 4 && reversezoom == 0) - || (self.zoom_mode == 0 && reversezoom == 1)) { + else if ( (self.zoom_mode == 4 && self.reversezoom == 0) + || (self.zoom_mode == 0 && self.reversezoom == 1)) { self.zoom_mode = 2; self.zoom_level = zoom2x; - if (zoomkey == 1) + if (self.zoomkey == 1) sprint(self, PRINT_HIGH, "2x zoom\n"); else sprint(self, PRINT_HIGH, "2x autozoom selected\n"); } - else if ( (self.zoom_mode == 2 && reversezoom == 0) - || (self.zoom_mode == 4 && reversezoom == 1)) { + else if ( (self.zoom_mode == 2 && self.reversezoom == 0) + || (self.zoom_mode == 4 && self.reversezoom == 1)) { self.zoom_mode = 0; - self.zoom_level = default_fov; - if (zoomkey == 1) + self.zoom_level = self.default_fov; + if (self.zoomkey == 1) sprint(self, PRINT_HIGH, "No zoom\n"); else sprint(self, PRINT_HIGH, "Autozoom off\n"); } - if (instazoom == 1 && zoomkey == 1) + if (self.instazoom == 1 && self.zoomkey == 1) TF_zoom(self.zoom_level); - else if (self.zoom_level < self.current_fov && instazoom != 1) + else if (self.zoom_level < self.current_fov && self.instazoom != 1) self.zoom_in = 1; - else if (self.zoom_level > self.current_fov && instazoom != 1) + else if (self.zoom_level > self.current_fov && self.instazoom != 1) self.zoom_out = 1; }; diff --git a/weapons.qc b/weapons.qc index 3620cd0c..d8a1d164 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2103,8 +2103,14 @@ void () ImpulseCommands = { self.impulse = 0; return; } - if (self.impulse == TF_SPECIAL_SKILL) + if (self.impulse == TF_SPECIAL_SKILL) { + if (self.playerclass == PC_SNIPER) { + self.reversezoom = stof(infokey(self, "zr")); + self.zoomkey = stof(infokey(self, "zk")); + self.instazoom = stof(infokey(self, "zi")); + } UseSpecialSkill(); + } if (self.impulse == TF_WEAPLAST) { if (self.playerclass == PC_SPY && self.is_undercover == 2) @@ -2355,9 +2361,6 @@ void () DeadImpulses = { void () W_WeaponFrame = { local vector tv; local float set_fov; - local float default_fov; - local float zoomkey = stof(infokey(self, "zk")); - local float instazoom = stof(infokey(self, "zi")); if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 10) { @@ -2398,12 +2401,11 @@ void () W_WeaponFrame = { if (intermission_running || cease_fire) return; - default_fov = stof(infokey(self, "df")); - if (self.zoom_level == 0) - self.zoom_level = default_fov; + if (self.zoom_level == 0 || self.zoom_mode == 0) + self.zoom_level = self.default_fov; // zoom in/out with zoomkey enabled - if (self.zoom_level > 0 && self.zoom_level != self.current_fov && zoomkey == 1) { + if (self.zoom_level > 0 && self.zoom_level != self.current_fov && self.zoomkey == 1) { if (self.zoom_in == 1) { if ((self.current_fov - 20) <= self.zoom_level) { set_fov = self.zoom_level; @@ -2428,10 +2430,10 @@ void () W_WeaponFrame = { } // zoom out with zoomkey disabled - if (!(self.tfstate & TFSTATE_AIMING) && zoomkey != 1) { - if (self.current_fov != default_fov) { - if ((self.current_fov + 20) >= default_fov || instazoom == 1) - set_fov = default_fov; + if (!(self.tfstate & TFSTATE_AIMING) && self.zoomkey != 1) { + if (self.current_fov != self.default_fov) { + if ((self.current_fov + 20) >= self.default_fov || self.instazoom == 1) + set_fov = self.default_fov; else set_fov = self.current_fov + 20; @@ -2460,9 +2462,9 @@ void () W_WeaponFrame = { } // zoom in with zoomkey disabled - if (self.current_fov != self.zoom_level && zoomkey != 1) { + if (self.current_fov != self.zoom_level && self.zoomkey != 1) { if (self.zoom_out == 1) { - if ((self.current_fov + 20) >= self.zoom_level || instazoom == 1) { + if ((self.current_fov + 20) >= self.zoom_level || self.instazoom == 1) { set_fov = self.zoom_level; self.zoom_out = 0; } @@ -2470,7 +2472,7 @@ void () W_WeaponFrame = { set_fov = self.current_fov + 20; } else { - if ((self.current_fov - 20) <= self.zoom_level || instazoom == 1) { + if ((self.current_fov - 20) <= self.zoom_level || self.instazoom == 1) { set_fov = self.zoom_level; self.zoom_in = 0; } From 5ca1535b01b19ad4408355f547f3941bfdba57cc Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 11:44:04 +0200 Subject: [PATCH 0060/2474] Move grenade timer removal to appropriate function --- client.qc | 15 --------------- tfort.qc | 12 ++++++++++++ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/client.qc b/client.qc index 1e152021..085ea169 100644 --- a/client.qc +++ b/client.qc @@ -1841,24 +1841,9 @@ void (entity targ, entity attacker) ClientObituary = { local float rnum; local string deathstring; local string deathstring2; - local entity timer; deathstring = ""; deathstring2 = ""; - if (self.StatusGrenTime > 0) { - timer = find(world, classname, "gtimer"); - while (timer != world) { - if (timer.owner == self) { - dremove(timer); - timer = find(world, classname, "gtimer"); - } else { - timer = find(timer, classname, "gtimer"); - } - } - self.StatusGrenTime = 0; - Status_Refresh(self); - } - TF_zoom_reset_death(targ); rnum = random(); diff --git a/tfort.qc b/tfort.qc index 081c9654..212c4b39 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1850,6 +1850,18 @@ void () TeamFortress_RemoveTimers = { te = find(te, classname, "timer"); } + te = find(world, classname, "timer"); + while (te != world) { + if (te.owner == self) { + dremove(te); + te = find(world, classname, "gtimer"); + } else { + te = find(te, classname, "gtimer"); + } + } + self.StatusGrenTime = 0; + Status_Refresh(self); + te = find(world, classname, "grentimer"); while (te != world) { if ((te.owner == self) && (te.no_active_napalm_grens <= 0)) { From a5dfc2abfab33b93ac8fa5fad6137d36f90aebca Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 18:25:52 +0200 Subject: [PATCH 0061/2474] Allow HWGuy to fire while moving (closes #73) --- player.qc | 34 +++++++++++++++------------------- weapons.qc | 18 ++++++++---------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/player.qc b/player.qc index 80ba0168..510a7493 100644 --- a/player.qc +++ b/player.qc @@ -344,9 +344,7 @@ void () player_nail2 =[104, player_nail1] { void () player_assaultcannonup1 =[103, player_assaultcannonup2] { if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | 2048; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & 65536); + self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.count = 1; self.heat = 0; @@ -375,9 +373,7 @@ void () player_assaultcannonup1 =[103, player_assaultcannonup2] { void () player_assaultcannonup2 =[103, player_assaultcannonup1] { if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | 2048; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & 65536); + self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.count = 1; self.heat = 0; @@ -407,7 +403,7 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { void () player_assaultcannon1 =[103, player_assaultcannon2] { local string st; - if (vlen(self.velocity) < 50) { + if (vlen(self.velocity) <= 90) { muzzleflash(); sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); @@ -420,10 +416,16 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { W_FireAssaultCannon(); stuffcmd(self, "v_idlescale "); - if (self.heat < 5) { - st = ftos(self.heat * 4); + if (vlen(self.velocity) < 50) { + if (self.heat < 5) + st = ftos(self.heat * 4); + else + st = "20"; } else { - st = "20"; + if (self.heat < 5) + st = ftos(self.heat * 8); + else + st = "40"; } stuffcmd(self, st); stuffcmd(self, "\n"); @@ -439,9 +441,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { } if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { stuffcmd(self, "v_idlescale 0\n"); - self.tfstate = self.tfstate | 2048; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & 65536); + self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.weaponframe = 0; self.count = 1; @@ -472,9 +472,7 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { } if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { stuffcmd(self, "v_idlescale 0\n"); - self.tfstate = self.tfstate | 2048; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & 65536); + self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.weaponframe = 0; self.count = 1; @@ -491,9 +489,7 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { if (self.count >= 15) { self.heat = 0; self.fire_held_down = 0; - self.tfstate = self.tfstate - (self.tfstate & 65536); - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & 2048); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); TeamFortress_SetSpeed(self); if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { self.current_weapon = W_BestWeapon(); diff --git a/weapons.qc b/weapons.qc index d8a1d164..0c2340d9 100644 --- a/weapons.qc +++ b/weapons.qc @@ -888,7 +888,11 @@ void () W_FireAssaultCannon = { self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_ASSAULTCANNON; - FireBullets(5, dir, '0.1 0.1 0'); + + if (vlen(self.velocity) < 50) + FireBullets(5, dir, '0.1 0.1 0'); + else + FireBullets(5, dir, '0.2 0.2 0'); }; void () s_explode1 =[0, s_explode2] { @@ -1338,10 +1342,6 @@ void () W_SetCurrentAmmo = { if ((self.health <= 0) || (self.current_weapon == 0)) return; - if ((self.current_weapon == WEAP_ASSAULT_CANNON) - && (self.tfstate & TFSTATE_CANT_MOVE)) - return; - player_run(); self.items = self.items - (self.items & (256 | 512 | 1024 | 2048)); @@ -1736,7 +1736,7 @@ void () W_Attack = { self.ammo_cells = self.ammo_cells - 7; self.heat = 1; self.immune_to_check = time + 5; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); player_assaultcannonup1(); } @@ -2450,7 +2450,7 @@ void () W_WeaponFrame = { if ((!self.button0 && self.fire_held_down) && (self.current_weapon == WEAP_ASSAULT_CANNON)) { self.fire_held_down = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); TeamFortress_SetSpeed(self); player_run(); } @@ -2507,9 +2507,7 @@ void () W_WeaponFrame = { } else if (self.playerclass == 0) { self.weaponmode = 0; } else if (self.tfstate & TFSTATE_AIMING) { - if (self.current_weapon != WEAP_ASSAULT_CANNON) { - W_Attack(); - } + W_Attack(); self.tfstate = self.tfstate - TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.heat = 0; From f8b9380979d0e20c2bd54797d7f6abf0a1049101 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 28 Jul 2014 18:26:56 +0200 Subject: [PATCH 0062/2474] Make HWGuy susceptible to concussion grenade while firing cannon (closes #76) --- scout.qc | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/scout.qc b/scout.qc index cb2e7527..c200f8d3 100644 --- a/scout.qc +++ b/scout.qc @@ -308,23 +308,20 @@ void () ConcussionGrenadeTimer = { pos = pointcontents(src); if ((self.owner.flags & 512) || (self.owner.flags & 16)) { - if (!((self.owner.tfstate & TFSTATE_CANT_MOVE) - && (self.owner.current_weapon == WEAP_ASSAULT_CANNON))) { - if (self.owner.is_feigning == 0) { - makevectors(self.owner.v_angle); - stumble = crandom() * self.health; - if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { - if ((crandom() < 0)) { - self.owner.velocity_x = - self.owner.velocity_y + stumble; - self.owner.velocity_y = - self.owner.velocity_x + stumble; - } else { - self.owner.velocity_x = - -1 * self.owner.velocity_y + stumble; - self.owner.velocity_y = - -1 * self.owner.velocity_x + stumble; - } + if (self.owner.is_feigning == 0) { + makevectors(self.owner.v_angle); + stumble = crandom() * self.health; + if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { + if ((crandom() < 0)) { + self.owner.velocity_x = + self.owner.velocity_y + stumble; + self.owner.velocity_y = + self.owner.velocity_x + stumble; + } else { + self.owner.velocity_x = + -1 * self.owner.velocity_y + stumble; + self.owner.velocity_y = + -1 * self.owner.velocity_x + stumble; } } } From 840c2f15c1d2fbcc2fc711a2c23d5344a837f9cd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 29 Jul 2014 21:26:33 +0200 Subject: [PATCH 0063/2474] Dropflag now works (fixes #46) --- defs.h | 2 +- tforthlp.qc | 2 +- tfortmap.qc | 6 ++---- weapons.qc | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/defs.h b/defs.h index 281af7d2..72892825 100644 --- a/defs.h +++ b/defs.h @@ -472,7 +472,7 @@ // other impulses #define TF_SHOW_IDS 186 -#define TF_DROPITEMS 194 +#define TF_DROPFLAG 194 /*======================================================*/ /* Colors */ diff --git a/tforthlp.qc b/tforthlp.qc index 58dd0885..5e8c3123 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -105,7 +105,7 @@ void () TeamFortress_MOTD = { } else if (self.motd == 45) { TeamFortress_Alias("dropkey", TF_DROPKEY, 0); TeamFortress_Alias("dropammo", TF_DROP_AMMO, 0); - TeamFortress_Alias("dropitems", TF_DROPITEMS, 0); + TeamFortress_Alias("dropflag", TF_DROPFLAG, 0); TeamFortress_Alias("showloc", TF_DISPLAYLOCATION, 0); TeamFortress_Alias("special", TF_SPECIAL_SKILL, 0); TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); diff --git a/tfortmap.qc b/tfortmap.qc index 89bb00ab..966f2af6 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2186,7 +2186,7 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { setmodel(Item, Item.mdl); } setsize(Item, Item.goal_min, Item.goal_max); - Item.owner = P; + Item.owner = world; if (PAlive == 1) { makevectors(P.v_angle); if (P.v_angle_x) { @@ -2544,9 +2544,7 @@ void () DropGoalItems = { te = find(world, classname, "item_tfgoal"); while (te) { if (te.owner == self) - if (te.goal_activation & 4096) - tfgoalitem_RemoveFromPlayer(te, self, 2); - + tfgoalitem_drop(te, 1, self); te = find(te, classname, "item_tfgoal"); } dremove(newmis); diff --git a/weapons.qc b/weapons.qc index 0c2340d9..820d8ad3 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2182,7 +2182,7 @@ void () ImpulseCommands = { TeamFortress_ID(); else if (self.impulse == TF_SHOW_IDS) TeamFortress_ShowIDs(); - else if ((self.playerclass != 0) && (self.impulse == 194)) + else if ((self.playerclass != 0) && (self.impulse == TF_DROPFLAG)) DropGoalItems(); else if (self.impulse == TF_PB_DETONATE) TeamFortress_DetonatePipebombs(); From bed57ea4a9b8d9037f0ee4dba0209eecebc412ff Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 29 Jul 2014 21:43:58 +0200 Subject: [PATCH 0064/2474] Fix flaginfo message when flag is at capture point (fixes #75) --- tfortmap.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index 966f2af6..1c44375a 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2237,7 +2237,7 @@ void (entity Item) tfgoalitem_checkgoalreturn = { }; void (entity Goal, entity Player, entity Item) DisplayItemStatus = { - if (Item.goal_state == 1) { + if (Item.goal_state == 1 && Item.owner != world) { if ((Goal.team_str_carried != string_null) || (Goal.non_team_str_carried != string_null)) { if (Player.team_no == Item.owned_by) { From 8f5c0394b358b5e1f16c1cdf80f2e5d0c443cca5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 29 Jul 2014 23:05:53 +0200 Subject: [PATCH 0065/2474] Properly remove queued spy disguise when cancelling disguise (fixes #78) --- spy.qc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/spy.qc b/spy.qc index aac1193d..097417e2 100644 --- a/spy.qc +++ b/spy.qc @@ -494,7 +494,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { }; void () TeamFortress_SpyGoUndercover = { - local entity te; + local entity te, timer; if (self.effects & (8 | 4)) { sprint(self, PRINT_MEDIUM, "You cannot disguise while glowing\n"); @@ -518,7 +518,7 @@ void () TeamFortress_SpyGoUndercover = { sprint(self, PRINT_HIGH, "Going undercover...\n"); self.is_undercover = 2; te = spawn(); - te.classname = "timer"; + te.classname = "spytimer"; te.owner = self; te.think = TeamFortress_SpyUndercoverThink; te.nextthink = time + 4; @@ -529,6 +529,15 @@ void () TeamFortress_SpyGoUndercover = { } else { sprint(self, PRINT_HIGH, "You stop going undercover\n"); self.is_undercover = 0; + timer = find(world, classname, "spytimer"); + while (timer != world) { + if (timer.owner == self) { + dremove(timer); + timer = find(world, classname, "spytimer"); + } else { + timer = find(timer, classname, "spytimer"); + } + } } }; @@ -618,7 +627,7 @@ void (float class) TeamFortress_SpyChangeSkin = { sprint(self, PRINT_HIGH, "Going undercover...\n"); self.is_undercover = 2; te = spawn(); - te.classname = "timer"; + te.classname = "spytimer"; te.owner = self; te.think = TeamFortress_SpyUndercoverThink; te.nextthink = time + 4; @@ -649,7 +658,7 @@ void (float teamno) TeamFortress_SpyChangeColor = { sprint(self, PRINT_HIGH, "Going undercover...\n"); self.is_undercover = 2; te = spawn(); - te.classname = "timer"; + te.classname = "spytimer"; te.owner = self; te.think = TeamFortress_SpyUndercoverThink; te.nextthink = time + 4; From 7acb42c728d6fd06ef4c3e1606d1cacc812126f2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 29 Jul 2014 23:14:39 +0200 Subject: [PATCH 0066/2474] Improve disguise messages (fixes #79) --- spy.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spy.qc b/spy.qc index 097417e2..6b5e27ca 100644 --- a/spy.qc +++ b/spy.qc @@ -586,15 +586,15 @@ void () TeamFortress_SpyUndercoverThink = { } else { self.owner.immune_to_check = time + 10; if (self.skin != 0) { - sprint(self.owner, PRINT_HIGH, "Skin set to "); + sprint(self.owner, PRINT_HIGH, "Disguised as "); TeamFortress_PrintClassName(self.owner, self.skin, 0); self.owner.undercover_skin = self.skin; TeamFortress_SetSkin(self.owner); } if (self.team != 0) { - sprint(self.owner, PRINT_HIGH, "Colors set to team "); - st = ftos(self.team); - sprint(self.owner, PRINT_HIGH, st, "\n"); + sprint(self.owner, PRINT_HIGH, "Disguised as "); + st = TeamFortress_TeamGetColorString(self.team); + sprint(self.owner, PRINT_HIGH, st, " Team\n"); self.owner.undercover_team = self.team; stuffcmd(self.owner, "color "); tc = TeamFortress_TeamGetColor(self.team) - 1; From 650aa5d7244ab05136cfb5c98a6059c363fcfc01 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 29 Jul 2014 23:25:17 +0200 Subject: [PATCH 0067/2474] Move menu stuff out of ChangeWeapon function --- weapons.qc | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/weapons.qc b/weapons.qc index 820d8ad3..bae2c47e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1958,18 +1958,6 @@ void (float inp) W_ChangeWeapon = { if (self.playerclass == 0) return; - if (inp == 5) { - if (self.playerclass == PC_ENGINEER) - TeamFortress_EngineerBuild(); - else if (self.playerclass == PC_SCOUT) - Menu_Scout(); - else if (self.playerclass == PC_SPY) - TeamFortress_SpyGoUndercover(); - else if (self.playerclass == PC_DEMOMAN) - TeamFortress_DetpackMenu(); - return; - } - // queue next weapon (in case of attack/reload in progress) if (!self.queue_weaponslot || self.queue_weaponslot != inp) { // set quick_weaponchange when player tries to change weapon during quick weapon fire/reload @@ -2369,7 +2357,18 @@ void () W_WeaponFrame = { } } - if (self.impulse >= 1 && self.impulse <= 5) { + if (self.impulse == 5) { + if (self.playerclass == PC_ENGINEER) + TeamFortress_EngineerBuild(); + else if (self.playerclass == PC_SCOUT) + Menu_Scout(); + else if (self.playerclass == PC_SPY) + TeamFortress_SpyGoUndercover(); + else if (self.playerclass == PC_DEMOMAN) + TeamFortress_DetpackMenu(); + } + + if (self.impulse >= 1 && self.impulse <= 4) { self.quick_weapon = 0; W_ChangeWeapon(self.impulse); } else if (self.impulse >= 31 && self.impulse <= 34) { From dbbb10b0f1e5e960ee6408fd8061b9763db1cbdb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 29 Jul 2014 23:25:51 +0200 Subject: [PATCH 0068/2474] Change to appropriate weapon after cancelling build (fixes #77) --- weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index bae2c47e..e07b8987 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2119,11 +2119,12 @@ void () ImpulseCommands = { if (self.is_building == 1) { if (self.impulse >= 1 && self.impulse <= 5) { TeamFortress_EngineerBuildStop(); + W_ChangeWeapon(self.impulse); } else if (self.impulse == TF_WEAPNEXT || self.impulse == TF_WEAPPREV || self.impulse == TF_WEAPLAST) { TeamFortress_EngineerBuildStop(); - self.impulse = 0; + W_ChangeWeapon(self.impulse); } } From a52abd7fa9041ebcbc9e0833a8c5ad09092a5c28 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 01:04:17 +0200 Subject: [PATCH 0069/2474] Add detpack countdown to status bar --- demoman.qc | 4 ++++ qw.qc | 1 + status.qc | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/demoman.qc b/demoman.qc index b1f1b1a2..f747be75 100644 --- a/demoman.qc +++ b/demoman.qc @@ -402,6 +402,8 @@ void () TeamFortress_DetpackDisarm = { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 65536); TF_AddFrags(self.owner, 1); TeamFortress_SetSpeed(self.owner); + self.enemy.owner.detpack_left = 0; + Status_Refresh(self.enemy.owner); dremove(self.enemy.oldenemy); dremove(self.enemy); @@ -415,6 +417,8 @@ void () TeamFortress_DetpackCountDown = { CheckBelowBuilding(self.enemy); self.nextthink = time + 1; self.health = self.health - 1; + self.owner.detpack_left = self.health; + Status_Refresh(self.owner); if (self.health < 10) { diff --git a/qw.qc b/qw.qc index 82d5cf5a..09d7cd32 100644 --- a/qw.qc +++ b/qw.qc @@ -45,6 +45,7 @@ typedef void (float) f_void_float; .float menu_time; // Time when vote map menu was first issued .float vote_next; // TRUE if player has voted for a map vote .float force_next; // TRUE if player has voted to force next map +.float detpack_left; // Seconds left to detpack explosion .float tfstate; // State flags for TeamFortress .entity linked_list; // Used just like chain. Has to be separate so diff --git a/status.qc b/status.qc index 8c6d4a1a..734224cc 100644 --- a/status.qc +++ b/status.qc @@ -8,6 +8,7 @@ string(float num) RedScoreToString; string(float num) YellowScoreToString; string(float num) GreenScoreToString; string(entity pl) ClipSizeToString; +string(entity pl) DetpackToString; string(entity pl) RangeToString; string(entity pl) ScannerToString; string(entity pl) DisguiseToString; @@ -139,6 +140,8 @@ void (entity pl) RefreshStatusBar = { st1 = strcat(ScannerToString(pl), RangeToString(pl)); else if (pl.playerclass == PC_DEMOMAN && self.is_detpacking) st1 = strcat(strcat("Setting detpack in ", ftos(self.is_detpacking)), "..."); + else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) + st1 = DetpackToString(pl); else if (pl.playerclass == PC_SPY) st1 = DisguiseToString(pl); else if (pl.playerclass == PC_ENGINEER && self.has_sentry) @@ -311,6 +314,19 @@ string(entity pl) DisguiseToString = return st; }; +string(entity pl) DetpackToString = +{ + local string st = ""; + + if (pl.detpack_left) { + st = "Δετπαγλ: "; + st = strcat(st, ftos(pl.detpack_left)); + st = strcat(st, " seconds left"); + } + + return st; +}; + string(entity pl) RangeToString = { local entity te; From 95b06a3ff6a267b53e51bb23bd3f25ba17ec7a4e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 01:05:25 +0200 Subject: [PATCH 0070/2474] General improvements of status bar --- status.qc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/status.qc b/status.qc index 734224cc..b5db9876 100644 --- a/status.qc +++ b/status.qc @@ -137,16 +137,16 @@ void (entity pl) RefreshStatusBar = { // status line 2 column 1 - class specific information st1 = ""; if (pl.playerclass == PC_SCOUT) - st1 = strcat(ScannerToString(pl), RangeToString(pl)); - else if (pl.playerclass == PC_DEMOMAN && self.is_detpacking) + st1 = ScannerToString(pl); + else if (pl.playerclass == PC_DEMOMAN && pl.is_detpacking) st1 = strcat(strcat("Setting detpack in ", ftos(self.is_detpacking)), "..."); else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) st1 = DetpackToString(pl); else if (pl.playerclass == PC_SPY) st1 = DisguiseToString(pl); - else if (pl.playerclass == PC_ENGINEER && self.has_sentry) + else if (pl.playerclass == PC_ENGINEER && pl.has_sentry) st1 = SentryDetailsToString(pl); - if (pl.playerclass == PC_ENGINEER && self.is_building) + if (pl.playerclass == PC_ENGINEER && pl.is_building) st1 = "Building..."; // status line 2 s2 = strpadr(st1, 42); @@ -179,16 +179,15 @@ void (entity pl) RefreshStatusBar = { st2 = GreenScoreToString(team4score); // status line 3 column 3 - clip size if (self.tfstate & TFSTATE_RELOADING) - st3 = " Γμιπ: 0"; + st3 = "Γμιπ: 0"; else st3 = ClipSizeToString(pl); // status line 3 column 4 - grenade count st4 = strcat(" Ηςεξ: ", strcat(strcat(ftos(self.no_grenades_1), "/"), ftos(self.no_grenades_2))); // status line 3 s3 = strcat(st1, st2); - s3 = strcat(s3, st3); - s3 = strcat(s3, st4); - s3 = strpadr(s3, 42); + s3 = strpadr(s3, 21); + s3 = strcat(s3, strpadl(strcat(st3, st4), 19)); s3 = strcat(s3, "\n"); s3 = strzone(s3); @@ -258,12 +257,12 @@ string(entity pl) ClipSizeToString = pl.reload_rocket_launcher = (4 - pl.ammo_rockets); num = (4 - pl.reload_rocket_launcher); } else - return (" "); + return (""); if (num > 99) num = 99; - return strcat(" Γμιπ:", strpadl(ftos(floor(num)), 2)); + return strcat("Γμιπ: ", strpadl(ftos(floor(num)), 2)); }; string(float num) TeamToString = From 361b5ad399b87df67e407401b220818c075a0a5d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 01:05:57 +0200 Subject: [PATCH 0071/2474] Improved Spy status bar --- status.qc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/status.qc b/status.qc index b5db9876..56919057 100644 --- a/status.qc +++ b/status.qc @@ -301,11 +301,28 @@ string(entity pl) DisguiseToString = if (pl.undercover_team) { st = strcat(st, TeamToString(pl.undercover_team)); st = strcat(st, " "); + } else { + st = strcat(st, TeamToString(pl.team_no)); + st = strcat(st, " "); } if (pl.undercover_skin) st = strcat(st, ClassToString(pl.undercover_skin)); + else + st = strcat(st, "Spy"); } else if (pl.is_undercover == 2) { - st = "Going undercover..."; + if (pl.undercover_team) { + st = "Υξδεςγοφες: "; + st = strcat(st, TeamToString(pl.undercover_team)); + st = strcat(st, " (Spy)"); + } else if (pl.undercover_skin) { + st = "Υξδεςγοφες: "; + st = strcat(st, "("); + st = strcat(st, TeamToString(pl.team_no)); + st = strcat(st, ") "); + st = strcat(st, ClassToString(pl.undercover_skin)); + } else { + st = strcat(st, "Going undercover..."); + } } else if (invis_only) { st = "Υξδεςγοφες"; } From 2eca30d0d4385d6053e5974daf77e156cc310c87 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 01:06:26 +0200 Subject: [PATCH 0072/2474] Improved Scout status bar (closes #80) --- status.qc | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/status.qc b/status.qc index 56919057..d62688a6 100644 --- a/status.qc +++ b/status.qc @@ -360,32 +360,51 @@ string(entity pl) RangeToString = if (num <= 0) return (""); - if (num > 100) - return ("100+ M"); + if (num > 99) + return ("99+ m"); - return strcat(strpadr(ftos(floor(num)), 2), " M"); + return strcat(strpadl(ftos(floor(num)), 3), " m"); }; string(entity pl) ScannerToString = { local entity te; - local string st; + local string st, scanfor = "", range = ""; + local float pad; te = find(world, netname, "scanner"); while ((te != world) && (te.owner != pl)) te = find(te, netname, "scanner"); if (pl.ScannerOn != 1) - return ("Scanner off"); + return ("Σγαξξες: off"); if (te.health > 0) { - st = TeamToString(te.team_no); + st = "Σγαξξες: "; + st = strcat(st, TeamToString(te.team_no)); st = strcat(st, " "); st = strcat(st, ClassToString(te.playerclass)); - st = strpadr(st, 18); - return strcat(st, " Range : "); - } else - return (" No Blips. "); + st = strpadr(st, 26); + range = "αξηε: "; + range = strcat(range, RangeToString(pl)); + pad = 40 - strlen(range); + st = strpadr(st, pad); + st = strcat(st, range); + } else { + st = "Σγαξξες: on"; + st = strcat(st, " Σγαξξιξη: "); + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) + scanfor = "team"; + if (self.tf_items_flags & NIT_SCANNER_ENEMY) { + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) + scanfor = strcat(scanfor, ", "); + scanfor = strcat(scanfor, "enemy"); + } + if (!strlen(scanfor)) + scanfor = "nothing"; + st = strcat(st, scanfor); + } + return st; }; string(entity pl) SentryDetailsToString = From e2633a3aa422920f3e9f2e9b93f0407b611df75c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 01:06:36 +0200 Subject: [PATCH 0073/2474] Improved Engineer status bar --- status.qc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/status.qc b/status.qc index d62688a6..dd5a1753 100644 --- a/status.qc +++ b/status.qc @@ -414,11 +414,12 @@ string(entity pl) SentryDetailsToString = local string shells = ""; local string rockets = ""; local string hp = ""; + local string st = ""; te = find(world, classname, "building_sentrygun"); while (te) { if (te.real_owner == self) { - hp = strcat(strpadl(ftos(floor(te.health)), 4), " hp"); + hp = strcat(strpadl(ftos(floor(te.health)), 3), " hp"); shells = ftos(floor(te.ammo_shells)); if (te.weapon == 3) { rockets = ftos(floor(te.ammo_rockets)); @@ -426,7 +427,10 @@ string(entity pl) SentryDetailsToString = } else { ammo = strcat(" Αννο: ", shells); } - return strcat("Σεξτςω:", strcat(hp, strcat(strpadr(ammo, 12), strcat(" Μεφεμ: ", ftos(te.weapon))))); + st = strcat("Σεξτςω: ", strcat(hp, ammo)); + st = strpadr(st, 32); + st = strcat(st, strcat("Μεφεμ: ", ftos(te.weapon))); + return st; } te = find(te, classname, "building_sentrygun"); } From ab70e80b47737609a9afdcba56306868899adedc Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 10:27:08 +0200 Subject: [PATCH 0074/2474] Show detpack placement timer in status bar --- demoman.qc | 7 ++++++- status.qc | 11 ++++++++--- tfort.qc | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/demoman.qc b/demoman.qc index f747be75..3c805757 100644 --- a/demoman.qc +++ b/demoman.qc @@ -171,6 +171,7 @@ void (float timer) TeamFortress_SetDetpack = { } self.is_detpacking = 3; + self.detpack_left = timer; self.ammo_detpack = self.ammo_detpack - 1; self.immune_to_check = time + 10; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; @@ -179,6 +180,7 @@ void (float timer) TeamFortress_SetDetpack = { self.weaponmodel = ""; self.weaponframe = 0; + Status_Refresh(self); TeamFortress_SetSpeed(self); self.pausetime = time + 3; @@ -214,8 +216,10 @@ void () TeamFortress_DetpackStop = { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); self.is_detpacking = 0; + self.detpack_left = 0; self.current_weapon = self.weapon; + Status_Refresh(self); W_SetCurrentAmmo(); TeamFortress_SetSpeed(self); self.pausetime = time; @@ -241,6 +245,7 @@ void () TeamFortress_DetpackSet = { self = self.owner; self.is_detpacking = 0; self.current_weapon = self.weapon; + Status_Refresh(self); W_SetCurrentAmmo(); self = oldself; @@ -416,8 +421,8 @@ void () TeamFortress_DetpackCountDown = { cd = ftos(self.health); CheckBelowBuilding(self.enemy); self.nextthink = time + 1; - self.health = self.health - 1; self.owner.detpack_left = self.health; + self.health = self.health - 1; Status_Refresh(self.owner); if (self.health < 10) { diff --git a/status.qc b/status.qc index dd5a1753..f32a06cc 100644 --- a/status.qc +++ b/status.qc @@ -138,8 +138,6 @@ void (entity pl) RefreshStatusBar = { st1 = ""; if (pl.playerclass == PC_SCOUT) st1 = ScannerToString(pl); - else if (pl.playerclass == PC_DEMOMAN && pl.is_detpacking) - st1 = strcat(strcat("Setting detpack in ", ftos(self.is_detpacking)), "..."); else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) st1 = DetpackToString(pl); else if (pl.playerclass == PC_SPY) @@ -334,7 +332,14 @@ string(entity pl) DetpackToString = { local string st = ""; - if (pl.detpack_left) { + if (pl.is_detpacking) { + st = "Δετπαγλ: "; + st = strcat(st, ftos(pl.detpack_left)); + st = strcat(st, " ("); + st = strcat(st, ftos(pl.is_detpacking)); + st = strcat(st, ")"); + st = strcat(st, " seconds left"); + } else if (pl.detpack_left) { st = "Δετπαγλ: "; st = strcat(st, ftos(pl.detpack_left)); st = strcat(st, " seconds left"); diff --git a/tfort.qc b/tfort.qc index 212c4b39..f32f7cc3 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1362,6 +1362,7 @@ void () TeamFortress_SetEquipment = { self.is_undercover = 0; self.is_feigning = 0; self.is_unabletospy = 0; + self.detpack_left = 0; self.ammo_medikit = 0; self.maxammo_medikit = 0; From 07b14eacf38d6fdf3388ced02d9cb70f798cb6eb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 10:28:03 +0200 Subject: [PATCH 0075/2474] Show what team/class the Spy is changing disguise to in status bar --- qw.qc | 2 ++ spy.qc | 11 +++++++++++ status.qc | 34 ++++++++++++++++++---------------- tfort.qc | 2 ++ tfortmap.qc | 5 ++++- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/qw.qc b/qw.qc index 09d7cd32..cf94b59c 100644 --- a/qw.qc +++ b/qw.qc @@ -46,6 +46,8 @@ typedef void (float) f_void_float; .float vote_next; // TRUE if player has voted for a map vote .float force_next; // TRUE if player has voted to force next map .float detpack_left; // Seconds left to detpack explosion +.float disguise_skin; // The skin the spy is changing to +.float disguise_team; // The team the spy is changing to .float tfstate; // State flags for TeamFortress .entity linked_list; // Used just like chain. Has to be separate so diff --git a/spy.qc b/spy.qc index 6b5e27ca..bf398c8f 100644 --- a/spy.qc +++ b/spy.qc @@ -529,6 +529,8 @@ void () TeamFortress_SpyGoUndercover = { } else { sprint(self, PRINT_HIGH, "You stop going undercover\n"); self.is_undercover = 0; + self.disguise_skin = 0; + self.disguise_team = 0; timer = find(world, classname, "spytimer"); while (timer != world) { if (timer.owner == self) { @@ -589,6 +591,7 @@ void () TeamFortress_SpyUndercoverThink = { sprint(self.owner, PRINT_HIGH, "Disguised as "); TeamFortress_PrintClassName(self.owner, self.skin, 0); self.owner.undercover_skin = self.skin; + self.owner.disguise_skin = 0; TeamFortress_SetSkin(self.owner); } if (self.team != 0) { @@ -618,6 +621,7 @@ void (float class) TeamFortress_SpyChangeSkin = { if (class == 8) { sprint(self, PRINT_HIGH, "Skin reset\n"); self.undercover_skin = 0; + self.disguise_skin = 0; TeamFortress_SetSkin(self); if (self.undercover_team == 0) { self.is_undercover = 0; @@ -626,6 +630,8 @@ void (float class) TeamFortress_SpyChangeSkin = { } sprint(self, PRINT_HIGH, "Going undercover...\n"); self.is_undercover = 2; + self.disguise_skin = class; + self.disguise_team = 0; te = spawn(); te.classname = "spytimer"; te.owner = self; @@ -644,6 +650,7 @@ void (float teamno) TeamFortress_SpyChangeColor = { sprint(self, PRINT_HIGH, "Colors reset\n"); self.immune_to_check = time + 10; self.undercover_team = 0; + self.disguise_team = 0; stuffcmd(self, "color "); tc = TeamFortress_TeamGetColor(self.team_no) - 1; st = ftos(tc); @@ -657,6 +664,8 @@ void (float teamno) TeamFortress_SpyChangeColor = { } sprint(self, PRINT_HIGH, "Going undercover...\n"); self.is_undercover = 2; + self.disguise_skin = 0; + self.disguise_team = teamno; te = spawn(); te.classname = "spytimer"; te.owner = self; @@ -1073,6 +1082,7 @@ void (entity spy) Spy_RemoveDisguise = { if (spy.undercover_team != 0) { spy.immune_to_check = time + 10; spy.undercover_team = 0; + spy.disguise_team = 0; stuffcmd(spy, "color "); tc = TeamFortress_TeamGetColor(spy.team_no) - 1; st = ftos(tc); @@ -1083,6 +1093,7 @@ void (entity spy) Spy_RemoveDisguise = { if (spy.undercover_skin != 0) { spy.immune_to_check = time + 10; spy.undercover_skin = 0; + spy.disguise_skin = 0; spy.skin = 0; coverblown = 1; } diff --git a/status.qc b/status.qc index f32a06cc..159c4ef7 100644 --- a/status.qc +++ b/status.qc @@ -293,34 +293,36 @@ string(float num) ClassToString = string(entity pl) DisguiseToString = { local string st = ""; + local string skin = ""; + local string team = ""; if (pl.is_undercover == 1) { st = "Υξδεςγοφες: "; if (pl.undercover_team) { st = strcat(st, TeamToString(pl.undercover_team)); st = strcat(st, " "); - } else { - st = strcat(st, TeamToString(pl.team_no)); - st = strcat(st, " "); } if (pl.undercover_skin) st = strcat(st, ClassToString(pl.undercover_skin)); - else - st = strcat(st, "Spy"); } else if (pl.is_undercover == 2) { - if (pl.undercover_team) { - st = "Υξδεςγοφες: "; - st = strcat(st, TeamToString(pl.undercover_team)); - st = strcat(st, " (Spy)"); + if (pl.disguise_team) { + team = strcat(team, "("); + team = strcat(team, TeamToString(pl.disguise_team)); + team = strcat(team, ") "); + } else if (pl.undercover_team) { + team = strcat(team, TeamToString(pl.undercover_team)); + team = strcat(team, " "); + } + if (pl.disguise_skin) { + skin = strcat(skin, "("); + skin = strcat(skin, ClassToString(pl.disguise_skin)); + skin = strcat(skin, ")"); } else if (pl.undercover_skin) { - st = "Υξδεςγοφες: "; - st = strcat(st, "("); - st = strcat(st, TeamToString(pl.team_no)); - st = strcat(st, ") "); - st = strcat(st, ClassToString(pl.undercover_skin)); - } else { - st = strcat(st, "Going undercover..."); + skin = strcat(skin, ClassToString(pl.undercover_skin)); } + st = "Υξδεςγοφες: "; + st = strcat(st, team); + st = strcat(st, skin); } else if (invis_only) { st = "Υξδεςγοφες"; } diff --git a/tfort.qc b/tfort.qc index f32f7cc3..ae879644 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1362,6 +1362,8 @@ void () TeamFortress_SetEquipment = { self.is_undercover = 0; self.is_feigning = 0; self.is_unabletospy = 0; + self.disguise_skin = 0; + self.disguise_team = 0; self.detpack_left = 0; self.ammo_medikit = 0; diff --git a/tfortmap.qc b/tfortmap.qc index 1c44375a..a131ece0 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1930,8 +1930,11 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { } } if ((AP.playerclass == PC_SPY) && - (Item.goal_result & TFGR_REMOVE_DISGUISE)) + (Item.goal_result & TFGR_REMOVE_DISGUISE)) { AP.is_unabletospy = 1; + AP.disguise_skin = 0; + AP.disguise_team = 0; + } DoResults(Item, AP, 1); DoItemGroupWork(Item, AP); From 26fd9a49bc6278ce7330e07fda4917870f574a9f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 10:28:47 +0200 Subject: [PATCH 0076/2474] Remove all flag effects from player when dropping flag (fixes #82) --- tfortmap.qc | 115 +++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index a131ece0..5bf0b104 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -33,6 +33,7 @@ void (entity Goal, entity Player) RemoveResults; void () tfgoal_timer_tick; void () tfgoalitem_remove; +void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer; void (entity Item, float PAlive, entity P) tfgoalitem_drop; void (entity Item) tfgoalitem_checkgoalreturn; @@ -1979,66 +1980,14 @@ void () ReturnItem = { void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { local entity te; - local float lighton; - local float slowon; - local float key1on; - local float key2on; - local float spyoff; local entity DelayReturn; if (Item == world) { objerror("error: tfgoalitem_RemoveFromPlayer(): Item == world"); return; } - lighton = 0; - slowon = 0; - key1on = 0; - key2on = 0; - spyoff = 0; - te = find(world, classname, "item_tfgoal"); - while (te) { - if ((te.owner == AP) && (te != Item)) { - if (te.goal_activation & 1) - lighton = 1; - - if (te.goal_activation & 2) - slowon = 1; - - if (te.items & 131072) - key1on = 1; - - if (te.items & 262144) - key2on = 1; - - if (te.goal_result & 16) - spyoff = 1; - } - te = find(te, classname, "item_tfgoal"); - } - if (!lighton) { - if (AP.invincible_finished > (time + 3)) { - lighton = 1; - } else if (AP.super_damage_finished > (time + 3)) { - lighton = 1; - } - } - if (!lighton) { - AP.effects = AP.effects - (AP.effects & 8); - AP.effects = AP.effects - (AP.effects & 64); - AP.effects = AP.effects - (AP.effects & 128); - } - if (Item.goal_activation & 512) - Item.effects = Item.effects | 8; - - if (!spyoff) - AP.is_unabletospy = 0; - - if (!key1on) - AP.items = AP.items - (AP.items & 131072); - - if (!key2on) - AP.items = AP.items - (AP.items & 262144); + tfgoalitem_RemoveEffectsFromPlayer(Item, AP); te = find(world, classname, "player"); while (te != world) { @@ -2118,6 +2067,59 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { objerror("Invalid method passed into tfgoalitem_RemoveFromPlayer\n"); }; +void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { + local entity te; + local float lighton = 0; + local float slowon = 0; + local float key1on = 0; + local float key2on = 0; + local float spyoff = 0; + + te = find(world, classname, "item_tfgoal"); + while (te) { + if ((te.owner == AP) && (te != Item)) { + if (te.goal_activation & 1) + lighton = 1; + + if (te.goal_activation & 2) + slowon = 1; + + if (te.items & 131072) + key1on = 1; + + if (te.items & 262144) + key2on = 1; + + if (te.goal_result & 16) + spyoff = 1; + } + te = find(te, classname, "item_tfgoal"); + } + if (!lighton) { + if (AP.invincible_finished > (time + 3)) { + lighton = 1; + } else if (AP.super_damage_finished > (time + 3)) { + lighton = 1; + } + } + if (!lighton) { + AP.effects = AP.effects - (AP.effects & 8); + AP.effects = AP.effects - (AP.effects & 64); + AP.effects = AP.effects - (AP.effects & 128); + } + if (Item.goal_activation & 512) + Item.effects = Item.effects | 8; + + if (!spyoff) + AP.is_unabletospy = 0; + + if (!key1on) + AP.items = AP.items - (AP.items & 131072); + + if (!key2on) + AP.items = AP.items - (AP.items & 262144); +}; + void () tfgoalitem_dropthink = { local float pos; @@ -2189,7 +2191,6 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { setmodel(Item, Item.mdl); } setsize(Item, Item.goal_min, Item.goal_max); - Item.owner = world; if (PAlive == 1) { makevectors(P.v_angle); if (P.v_angle_x) { @@ -2207,6 +2208,7 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { Item.nextthink = time + 5; Item.think = tfgoalitem_dropthink; } + Item.owner = world; }; void () tfgoalitem_remove = { @@ -2546,9 +2548,12 @@ void () DropGoalItems = { newmis.origin = self.origin + v_forward; te = find(world, classname, "item_tfgoal"); while (te) { - if (te.owner == self) + if (te.owner == self) { + tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); + } te = find(te, classname, "item_tfgoal"); } dremove(newmis); + TeamFortress_SetSpeed(self); }; From bdbf608403110db013bdc05ce11c38c5f01e4e13 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 11:34:40 +0200 Subject: [PATCH 0077/2474] Reset detpack status bar timer when detpack explodes --- demoman.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/demoman.qc b/demoman.qc index 3c805757..f1472a5e 100644 --- a/demoman.qc +++ b/demoman.qc @@ -296,6 +296,7 @@ void () TeamFortress_DetpackExplode = { local entity te; local vector org; + self.owner.detpack_left = 0; bprint(PRINT_MEDIUM, "FIRE IN THE HOLE!\n"); sound(self, CHAN_WEAPON, "weapons/detpack.wav", 1, ATTN_NONE); From 9a57315111857d2f7487a21234b411924fe40710 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 11:36:16 +0200 Subject: [PATCH 0078/2474] Add flag indicator and max clip size to status bar (+ general improvements) --- status.qc | 91 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/status.qc b/status.qc index 159c4ef7..3669c33f 100644 --- a/status.qc +++ b/status.qc @@ -8,6 +8,7 @@ string(float num) RedScoreToString; string(float num) YellowScoreToString; string(float num) GreenScoreToString; string(entity pl) ClipSizeToString; +float(entity pl) GetClipSize; string(entity pl) DetpackToString; string(entity pl) RangeToString; string(entity pl) ScannerToString; @@ -113,7 +114,7 @@ void (entity pl) RefreshStatusBar = { height = floor(stof(infokey(pl, "sb"))); if (height > 300) height = 300; - height = height - pl.StatusStringLines - 4; + height = height - pl.StatusStringLines - 3; // no sbar can be displayed if (height <= 0 || pl.playerclass == PC_UNDEFINED) { @@ -127,11 +128,19 @@ void (entity pl) RefreshStatusBar = { pad = strzone(pad); // status line 1 column 1 - grenade timer - st1 = ""; if (pl.StatusGrenTime > 0) - st1 = strcat("Explosion in ", strcat(ftos(pl.StatusGrenTime), "...")); + st1 = strcat("Ηςεξαδε: ", strcat(ftos(pl.StatusGrenTime), " seconds")); + else + st1 = ""; + // flag carrier info + if (pl.items & IT_KEY1) + st2 = "Γαςςωιξη Ζμαη"; + else + st2 = " "; // status line 1 - s1 = strcat(st1, "\n\n"); + s1 = strpadr(st1, 27); + s1 = strcat(s1, st2); + s1 = strcat(s1, "\n"); s1 = strzone(s1); // status line 2 column 1 - class specific information @@ -155,15 +164,16 @@ void (entity pl) RefreshStatusBar = { win = TeamFortress_TeamGetWinner(); sec = TeamFortress_TeamGetSecond(); if (win == 0) - st1 = strcat(BlueScoreToString(team1score), " "); + st1 = BlueScoreToString(team1score); else if (win == 1) - st1 = strcat(BlueScoreToString(team1score), " "); + st1 = BlueScoreToString(team1score); else if (win == 2) - st1 = strcat(RedScoreToString(team2score), " "); + st1 = RedScoreToString(team2score); else if (win == 3) - st1 = strcat(YellowScoreToString(team3score), " "); + st1 = YellowScoreToString(team3score); else - st1 = strcat(GreenScoreToString(team4score), " "); + st1 = GreenScoreToString(team4score); + st1 = strcat(st1, " "); // status line 3 column 2 - team 2 score if (sec == 0) st2 = RedScoreToString(team2score); @@ -176,16 +186,18 @@ void (entity pl) RefreshStatusBar = { else st2 = GreenScoreToString(team4score); // status line 3 column 3 - clip size - if (self.tfstate & TFSTATE_RELOADING) - st3 = "Γμιπ: 0"; - else + if (self.tfstate & TFSTATE_RELOADING) { + st3 = "Γμιπ: 0/"; + st3 = strcat(st3, strpadr(ftos(GetClipSize(pl)), 3)); + } else { st3 = ClipSizeToString(pl); + } // status line 3 column 4 - grenade count - st4 = strcat(" Ηςεξ: ", strcat(strcat(ftos(self.no_grenades_1), "/"), ftos(self.no_grenades_2))); + st4 = strcat("Ηςεξ: ", strcat(strcat(ftos(self.no_grenades_1), "/"), ftos(self.no_grenades_2))); // status line 3 s3 = strcat(st1, st2); - s3 = strpadr(s3, 21); - s3 = strcat(s3, strpadl(strcat(st3, st4), 19)); + s3 = strpadr(s3, 19); + s3 = strcat(s3, strpadl(strcat(st3, st4), 21)); s3 = strcat(s3, "\n"); s3 = strzone(s3); @@ -236,31 +248,52 @@ string(float num) GreenScoreToString = string(entity pl) ClipSizeToString = { - local float num; + local string st; + local float num, max; + max = GetClipSize(pl); if (pl.current_weapon == WEAP_SHOTGUN) { - if ((8 - pl.reload_shotgun) > pl.ammo_shells) - pl.reload_shotgun = 8 - pl.ammo_shells; - num = 8 - pl.reload_shotgun; + if ((max - pl.reload_shotgun) > pl.ammo_shells) + pl.reload_shotgun = max - pl.ammo_shells; + num = max - pl.reload_shotgun; } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { - if ((16 - pl.reload_super_shotgun) > pl.ammo_shells) - pl.reload_super_shotgun = 16 - pl.ammo_shells; - num = (16 - pl.reload_super_shotgun); + if ((max - pl.reload_super_shotgun) > pl.ammo_shells) + pl.reload_super_shotgun = max - pl.ammo_shells; + num = (max - pl.reload_super_shotgun); } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { - if ((6 - pl.reload_grenade_launcher) > pl.ammo_rockets) - pl.reload_grenade_launcher = (6 - pl.ammo_rockets); - num = (6 - pl.reload_grenade_launcher); + if ((max - pl.reload_grenade_launcher) > pl.ammo_rockets) + pl.reload_grenade_launcher = (max - pl.ammo_rockets); + num = (max - pl.reload_grenade_launcher); } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { - if ((4 - pl.reload_rocket_launcher) > pl.ammo_rockets) - pl.reload_rocket_launcher = (4 - pl.ammo_rockets); - num = (4 - pl.reload_rocket_launcher); + if ((max - pl.reload_rocket_launcher) > pl.ammo_rockets) + pl.reload_rocket_launcher = (max - pl.ammo_rockets); + num = (max - pl.reload_rocket_launcher); } else return (""); if (num > 99) num = 99; - return strcat("Γμιπ: ", strpadl(ftos(floor(num)), 2)); + st = "Γμιπ: "; + st = strcat(st, strpadl(ftos(floor(num)), 2)); + st = strcat(st, "/"); + st = strcat(st, strpadr(ftos(max), 3)); + + return st; +}; + +float(entity pl) GetClipSize = +{ + if (pl.current_weapon == WEAP_SHOTGUN) + return 8; + else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) + return 16; + else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) + return 6; + else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) + return 4; + else + return 0; }; string(float num) TeamToString = From 50e8ef7b55034eb4d29ae42a4229285b02404ecf Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 11:36:39 +0200 Subject: [PATCH 0079/2474] Force status bar refresh when picking up/losing flag --- tfortmap.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tfortmap.qc b/tfortmap.qc index 5bf0b104..6278b010 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1937,6 +1937,7 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { AP.disguise_team = 0; } + Status_Refresh(AP); DoResults(Item, AP, 1); DoItemGroupWork(Item, AP); }; @@ -2118,6 +2119,8 @@ void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { if (!key2on) AP.items = AP.items - (AP.items & 262144); + + Status_Refresh(AP); }; void () tfgoalitem_dropthink = { From 3497f7b8157c190f09c2a46d7af45d65606db5f7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 11:44:14 +0200 Subject: [PATCH 0080/2474] Don't show the same teams in status bar scorelist (fixes #81) --- status.qc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/status.qc b/status.qc index 3669c33f..8956c3af 100644 --- a/status.qc +++ b/status.qc @@ -175,8 +175,12 @@ void (entity pl) RefreshStatusBar = { st1 = GreenScoreToString(team4score); st1 = strcat(st1, " "); // status line 3 column 2 - team 2 score - if (sec == 0) - st2 = RedScoreToString(team2score); + if (sec == 0) { + if (win < 2) + st2 = RedScoreToString(team2score); + else + st2 = BlueScoreToString(team1score); + } else if (sec == 1) st2 = BlueScoreToString(team1score); else if (sec == 2) From ba70bf1cc5d0c181e1ef78bf53ea08fe13f157fd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 12:38:13 +0200 Subject: [PATCH 0081/2474] Clean up SetCurrentAmmo() function --- weapons.qc | 112 +++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 64 deletions(-) diff --git a/weapons.qc b/weapons.qc index e07b8987..4eb65ddb 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1344,10 +1344,10 @@ void () W_SetCurrentAmmo = { player_run(); - self.items = self.items - (self.items & (256 | 512 | 1024 | 2048)); + self.items = self.items - (self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS)); self.weapon = 0; - if (self.current_weapon == 16) { + if (self.current_weapon == WEAP_AXE) { self.currentammo = 0; if (self.playerclass == 8) { if (self.weaponmode == 0) @@ -1356,143 +1356,127 @@ void () W_SetCurrentAmmo = { self.weaponmodel = "progs/v_knife2.mdl"; } else self.weaponmodel = "progs/v_axe.mdl"; - self.weaponframe = 0; - - } else if (self.current_weapon == 1) { - - self.currentammo = 0; - self.weaponmodel = "progs/v_grap.mdl"; - self.weaponframe = 0; - - } else if (self.current_weapon == 8) { - + } else if (self.current_weapon == WEAP_SPANNER) { self.currentammo = self.ammo_cells; self.weaponmodel = "progs/v_span.mdl"; self.weaponframe = 0; - - } else if (self.current_weapon == 128) { - + } else if (self.current_weapon == WEAP_SHOTGUN) { self.currentammo = self.ammo_shells; - self.items = self.items | 2048; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_shot.mdl"; self.weaponframe = 0; } - self.items = self.items | 256; - self.weapon = 1; - - } else if (self.current_weapon == 256) { - + self.items = self.items | IT_SHELLS; + self.weapon = IT_SHOTGUN; + } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { self.currentammo = self.ammo_shells; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_shot2.mdl"; self.weaponframe = 0; } - self.items = self.items | 256; - self.weapon = 2; - - } else if (self.current_weapon == 512) { - + self.items = self.items | IT_SHELLS; + self.weapon = IT_SUPER_SHOTGUN; + } else if (self.current_weapon == WEAP_NAILGUN) { self.currentammo = self.ammo_nails; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_nail.mdl"; self.weaponframe = 0; } - self.items = self.items | 512; - self.weapon = 4; - } else if (self.current_weapon == 1024) { + self.items = self.items | IT_NAILS; + self.weapon = IT_NAILGUN; + } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { self.currentammo = self.ammo_nails; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_nail2.mdl"; self.weaponframe = 0; } - self.items = self.items | 512; - self.weapon = 8; - } else if (self.current_weapon == 2048) { + self.items = self.items | IT_NAILS; + self.weapon = IT_SUPER_NAILGUN; + } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { self.currentammo = self.ammo_rockets; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rock.mdl"; self.weaponframe = 0; } - self.weapon = 16; - self.items = self.items | 1024; - } else if (self.current_weapon == 8192) { + self.weapon = IT_GRENADE_LAUNCHER; + self.items = self.items | IT_ROCKETS; + } else if (self.current_weapon == WEAP_PIPEBOMB_LAUNCHER) { self.currentammo = self.ammo_rockets; if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_rock2.mdl"; + self.weaponmodel = "progs/v_rock.mdl"; self.weaponframe = 0; } - self.items = self.items | 1024; - self.weapon = 32; - } else if (self.current_weapon == 65536) { - self.currentammo = self.ammo_cells; + self.weapon = IT_GRENADE_LAUNCHER; + self.items = self.items | IT_ROCKETS; + } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { + self.currentammo = self.ammo_rockets; if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_light.mdl"; + self.weaponmodel = "progs/v_rock2.mdl"; self.weaponframe = 0; } - self.items = self.items | 2048; - self.weapon = 64; - } else if (self.current_weapon == 32) { + self.items = self.items | IT_ROCKETS; + self.weapon = IT_ROCKET_LAUNCHER; + } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { self.currentammo = self.ammo_shells; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_srifle.mdl"; self.weaponframe = 0; } - self.items = self.items | 256; - self.weapon = 1; - } else if (self.current_weapon == 64) { + self.items = self.items | IT_SHELLS; + self.weapon = IT_SHOTGUN; + } else if (self.current_weapon == WEAP_AUTO_RIFLE) { self.currentammo = self.ammo_shells; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_srifle.mdl"; self.weaponframe = 0; } - self.items = self.items | 256; - self.weapon = 2; + self.items = self.items | IT_SHELLS; + self.weapon = IT_SUPER_SHOTGUN; } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { self.currentammo = self.ammo_shells; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_asscan.mdl"; self.weaponframe = 0; } - self.items = self.items | 256; - self.weapon = 32; - } else if (self.current_weapon == 4096) { + self.items = self.items | IT_SHELLS; + self.weapon = IT_ROCKET_LAUNCHER; + } else if (self.current_weapon == WEAP_FLAMETHROWER) { self.currentammo = self.ammo_cells; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rock.mdl"; self.weaponframe = 0; } - self.items = self.items | 2048; - self.weapon = 16; - } else if (self.current_weapon == 16384) { + self.items = self.items | IT_CELLS; + self.weapon = IT_GRENADE_LAUNCHER; + } else if (self.current_weapon == WEAP_INCENDIARY) { self.currentammo = self.ammo_rockets; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rock2.mdl"; self.weaponframe = 0; } - self.items = self.items | 1024; - self.weapon = 32; - } else if (self.current_weapon == 4) { + self.items = self.items | IT_ROCKETS; + self.weapon = IT_ROCKET_LAUNCHER; + } else if (self.current_weapon == WEAP_MEDIKIT) { self.currentammo = self.ammo_medikit; self.weaponmodel = "progs/v_medi.mdl"; self.weaponframe = 0; - } else if (self.current_weapon == 262144) { + } else if (self.current_weapon == WEAP_TRANQ) { self.currentammo = self.ammo_shells; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_shot.mdl"; self.weaponframe = 0; } - self.items = self.items | 256; - self.weapon = 1; - } else if (self.current_weapon == 524288) { + self.items = self.items | IT_SHELLS; + self.weapon = IT_SHOTGUN; + } else if (self.current_weapon == WEAP_LASER) { self.currentammo = self.ammo_nails; if (!(self.tfstate & TFSTATE_RELOADING)) { self.weaponmodel = "progs/v_rail.mdl"; self.weaponframe = 0; } - self.items = self.items | 512; - self.weapon = 1; + self.items = self.items | IT_NAILS; + self.weapon = IT_SHOTGUN; } else { self.currentammo = 0; self.weaponmodel = ""; From 40fd5300430585ace4970e42e6bb8e7a0cb8170e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 13:27:05 +0200 Subject: [PATCH 0082/2474] Remove pipebomb launcher stuff from SetCurrentAmmo() function --- weapons.qc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/weapons.qc b/weapons.qc index 4eb65ddb..d38ec376 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1401,14 +1401,6 @@ void () W_SetCurrentAmmo = { } self.weapon = IT_GRENADE_LAUNCHER; self.items = self.items | IT_ROCKETS; - } else if (self.current_weapon == WEAP_PIPEBOMB_LAUNCHER) { - self.currentammo = self.ammo_rockets; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_rock.mdl"; - self.weaponframe = 0; - } - self.weapon = IT_GRENADE_LAUNCHER; - self.items = self.items | IT_ROCKETS; } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { self.currentammo = self.ammo_rockets; if (!(self.tfstate & TFSTATE_RELOADING)) { From 64ddcf7b7ba1e4eeb1de49e440d4cf463b80eba2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 30 Jul 2014 13:40:07 +0200 Subject: [PATCH 0083/2474] Minor status bar fix --- status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.qc b/status.qc index 8956c3af..89ccd95c 100644 --- a/status.qc +++ b/status.qc @@ -156,7 +156,7 @@ void (entity pl) RefreshStatusBar = { if (pl.playerclass == PC_ENGINEER && pl.is_building) st1 = "Building..."; // status line 2 - s2 = strpadr(st1, 42); + s2 = strpadr(st1, 40); s2 = strcat(s2, "\n"); s2 = strzone(s2); From 671566b846b32a932de42c6d84c200c6ed0d421d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 2 Aug 2014 11:29:33 +0200 Subject: [PATCH 0084/2474] Improve sniper zoom (closes #34 and #83) --- client.qc | 9 ++- defs.h | 5 +- qw.qc | 9 +-- sniper.qc | 183 +++++++++++++++++++++------------------------------- tforthlp.qc | 5 +- weapons.qc | 113 +++++++------------------------- 6 files changed, 106 insertions(+), 218 deletions(-) diff --git a/client.qc b/client.qc index 085ea169..95d2553d 100644 --- a/client.qc +++ b/client.qc @@ -42,8 +42,7 @@ entity(float ino) Finditem; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer; void () CTF_FlagCheck; -void (entity pl) TF_zoom_reset; -void (entity pl) TF_zoom_reset_death; +void (entity pl) Sniper_ZoomReset; string nextmap; @@ -693,7 +692,7 @@ void () ClientKill = { return; } - TF_zoom_reset_death(self); + Sniper_ZoomReset(self); set_suicide_frame(); self.modelindex = modelindex_player; @@ -1019,7 +1018,7 @@ void () PutClientInServer = { self.th_pain = player_pain; self.th_die = PlayerDie; self.height = 0; - TF_zoom_reset(self); + Sniper_ZoomReset(self); self.deadflag = 0; self.pausetime = 0; @@ -1844,7 +1843,7 @@ void (entity targ, entity attacker) ClientObituary = { deathstring = ""; deathstring2 = ""; - TF_zoom_reset_death(targ); + Sniper_ZoomReset(targ); rnum = random(); if ((cb_prematch_time + 3) > time) diff --git a/defs.h b/defs.h index 72892825..7233a303 100644 --- a/defs.h +++ b/defs.h @@ -387,9 +387,8 @@ // Sniper Zoom impulses #define TF_ZOOMTOGGLE 113 -#define TF_ZOOMOFF 114 -#define TF_ZOOM4X 115 -#define TF_ZOOM2X 116 +#define TF_ZOOMIN 114 +#define TF_ZOOMOUT 115 // Help impulses #define TF_DISPLAYLOCATION 118 diff --git a/qw.qc b/qw.qc index cf94b59c..bf305730 100644 --- a/qw.qc +++ b/qw.qc @@ -28,18 +28,15 @@ typedef void (float) f_void_float; .float is_detpacking; // TRUE for a DEMOMAN if they're setting a detpack .float is_feigning; // TRUE for a SPY if they're feigning death .float is_unabletospy; // TRUE for a SPY if they can't go undercover +.float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer .float default_sensitivity; // Player's default (non-zoomed) sensitivity .float default_fov; // Player's default (non-zoomed) fov .float current_fov; // Player's current field of view .float zoom_level; // Start zooming to this fov next frame -.float zoom_mode; // Autozoom: 0 (off), 2 (2x), 4 (4x) -.float zoom_in; // TRUE if player is currently zooming in -.float zoom_out; // TRUE if player is currently zooming out -.float reversezoom; // Reverse zoom order -.float instazoom; // Zoom instantly without smoothness -.float zoomkey; // Zoom using special key, not +attack +.float zoom_fov; // The default fov to zoom in to when pressing special button +.float zoom_last; // The last used zoom fov by the player - zoom to this when toggling zoom .float has_voted_map; // Map option that player voted for .float spawn_time; // Time when player spawned .float menu_time; // Time when vote map menu was first issued diff --git a/sniper.qc b/sniper.qc index 539c41f4..bccca415 100644 --- a/sniper.qc +++ b/sniper.qc @@ -2,17 +2,19 @@ // Functions for the SNIPER class and associated weaponry //======================================================== -void (float zoom_to) TF_zoom = { +void (float zoom_to) Sniper_Zoom = { self.default_fov = stof(infokey(self, "df")); self.default_sensitivity = stof(infokey(self, "ds")); - self.reversezoom = stof(infokey(self, "zr")); - self.zoomkey = stof(infokey(self, "zk")); - self.instazoom = stof(infokey(self, "zi")); + self.zoom_fov = stof(infokey(self, "zf")); if (self.default_fov == 0) return; - if (zoom_to != self.current_fov) { + if (zoom_to >= self.default_fov) + Sniper_ZoomReset(self); + else if (zoom_to != self.current_fov) { + if (zoom_to < self.default_fov) + self.zoom_last = zoom_to; self.current_fov = zoom_to; stuffcmd(self, "fov "); stuffcmd(self, ftos(zoom_to)); @@ -26,32 +28,16 @@ void (float zoom_to) TF_zoom = { } }; -void (entity pl) TF_zoom_reset = { +void (entity pl) Sniper_ZoomReset = { pl.default_sensitivity = stof(infokey(pl, "ds")); pl.default_fov = stof(infokey(pl, "df")); - pl.reversezoom = stof(infokey(self, "zr")); - pl.zoomkey = stof(infokey(self, "zk")); - pl.instazoom = stof(infokey(self, "zi")); - - pl.current_fov = pl.default_fov; - if (pl.zoomkey) { - pl.zoom_level = pl.default_fov; - if (pl.reversezoom) { - if (pl.zoom_mode == 2) - pl.zoom_mode = 0; - else if (pl.zoom_mode == 4) - pl.zoom_mode = 2; - } else if (pl.zoom_mode == 2) - pl.zoom_mode = 4; - else if (pl.zoom_mode == 4) - pl.zoom_mode = 0; - } - pl.zoom_in = 0; - pl.zoom_out = 0; + + pl.is_zooming = 0; if (pl.default_fov > 0) { + pl.current_fov = pl.default_fov; stuffcmd(pl, "fov "); - stuffcmd(pl, ftos(pl.current_fov)); + stuffcmd(pl, ftos(pl.default_fov)); stuffcmd(pl, "\n"); } @@ -62,29 +48,71 @@ void (entity pl) TF_zoom_reset = { } }; -void (entity pl) TF_zoom_reset_death = { - pl.default_sensitivity = stof(infokey(pl, "ds")); - pl.default_fov = stof(infokey(pl, "df")); - pl.reversezoom = stof(infokey(self, "zr")); - pl.zoomkey = stof(infokey(self, "zk")); - pl.instazoom = stof(infokey(self, "zi")); +void () Sniper_ZoomToggle = { + local float magnification = 0; + local float zoom_to = 0; - pl.zoom_level = pl.default_fov; - pl.current_fov = pl.default_fov; - pl.zoom_in = 0; - pl.zoom_out = 0; + if (self.playerclass != PC_SNIPER) + return; - if (pl.default_fov > 0) { - stuffcmd(pl, "fov "); - stuffcmd(pl, ftos(pl.current_fov)); - stuffcmd(pl, "\n"); + self.default_fov = stof(infokey(self, "df")); + self.default_sensitivity = stof(infokey(self, "ds")); + self.zoom_fov = stof(infokey(self, "zf")); + + if (self.default_fov == 0) { + sprint(self, PRINT_HIGH, "Use \"setinfo df \" to set default fov to use sniper zoom. Use \"setinfo ds \" to set default sensitivity for sensitivity scaling.\n"); + return; } - if (pl.default_sensitivity > 0) { - stuffcmd(pl, "sensitivity "); - stuffcmd(pl, ftos(pl.default_sensitivity)); - stuffcmd(pl, "\n"); + if (self.is_zooming) { + self.is_zooming = 0; + zoom_to = self.default_fov; + sprint(self, PRINT_HIGH, "Zoomed out\n"); + } else { + self.is_zooming = 1; + if (self.zoom_last && self.zoom_last < self.default_fov) + zoom_to = self.zoom_last; + else if (self.zoom_fov) + zoom_to = self.zoom_fov; + else + zoom_to = 30; + + magnification = floor(self.default_fov / zoom_to); + sprint(self, PRINT_HIGH, ftos(magnification), "x zoom\n"); } + + Sniper_Zoom(zoom_to); +}; + +void (float zoom_in) Sniper_ZoomAdjust = { + local float zoom_to = 0; + local float zoom_steps = 0; + + if (self.playerclass != PC_SNIPER || !self.is_zooming) + return; + + zoom_steps = stof(infokey(self, "zs")); + if (!zoom_steps) + zoom_steps = 5; + + if (self.default_fov == 0) { + sprint(self, PRINT_HIGH, "Use \"setinfo df \" to set default fov to use sniper zoom. Use \"setinfo ds \" to set default sensitivity for sensitivity scaling.\n"); + return; + } + + if (zoom_in) + zoom_to = self.current_fov - zoom_steps; + else + zoom_to = self.current_fov + zoom_steps; + + if (zoom_to <= 10) + zoom_to = 10; + else if (zoom_to >= self.default_fov) + zoom_to = self.default_fov; + + self.zoom_last = zoom_to; + + Sniper_Zoom(zoom_to); }; void () SniperSight_Update = { @@ -138,70 +166,3 @@ void () SniperSight_Create = { sight.think = SniperSight_Update; sight.nextthink = time + 0.05; }; - -void () TeamFortress_ZoomToggle = { - local float zoom4x; - local float zoom2x; - - if (self.playerclass != PC_SNIPER) - return; - - zoom4x = (stof(infokey(self, "z4x")) > 0) ? stof(infokey(self, "z4x")) : 20; - zoom2x = (stof(infokey(self, "z2x")) > 0) ? stof(infokey(self, "z2x")) : 40; - self.default_fov = stof(infokey(self, "df")); - - if (self.default_fov == 0) { - sprint(self, PRINT_HIGH, "Use \"setinfo df \" to set default fov to use sniper zoom. Use \"setinfo ds \" to set default sensitivity for sensitivity scaling.\n"); - return; - } - - if ( (self.zoom_mode == 0 && self.reversezoom == 0) - || (self.zoom_mode == 2 && self.reversezoom == 1)) { - self.zoom_mode = 4; - self.zoom_level = zoom4x; - if (self.zoomkey == 1) - sprint(self, PRINT_HIGH, "4x zoom\n"); - else - sprint(self, PRINT_HIGH, "4x autozoom selected\n"); - } - else if ( (self.zoom_mode == 4 && self.reversezoom == 0) - || (self.zoom_mode == 0 && self.reversezoom == 1)) { - self.zoom_mode = 2; - self.zoom_level = zoom2x; - if (self.zoomkey == 1) - sprint(self, PRINT_HIGH, "2x zoom\n"); - else - sprint(self, PRINT_HIGH, "2x autozoom selected\n"); - } - else if ( (self.zoom_mode == 2 && self.reversezoom == 0) - || (self.zoom_mode == 4 && self.reversezoom == 1)) { - self.zoom_mode = 0; - self.zoom_level = self.default_fov; - if (self.zoomkey == 1) - sprint(self, PRINT_HIGH, "No zoom\n"); - else - sprint(self, PRINT_HIGH, "Autozoom off\n"); - } - - if (self.instazoom == 1 && self.zoomkey == 1) - TF_zoom(self.zoom_level); - else if (self.zoom_level < self.current_fov && self.instazoom != 1) - self.zoom_in = 1; - else if (self.zoom_level > self.current_fov && self.instazoom != 1) - self.zoom_out = 1; -}; - -void () TeamFortress_SetZoomOff = { - self.zoom_mode = 0; - sprint(self, PRINT_HIGH, "Autozoom off\n"); -} - -void () TeamFortress_SetZoom2x = { - self.zoom_mode = 2; - sprint(self, PRINT_HIGH, "2x autozoom selected\n"); -} - -void () TeamFortress_SetZoom4x = { - self.zoom_mode = 4; - sprint(self, PRINT_HIGH, "4x autozoom selected\n"); -} diff --git a/tforthlp.qc b/tforthlp.qc index 5e8c3123..a98c1173 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -49,9 +49,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("inv", TF_INVENTORY, 0); TeamFortress_Alias("showtf", TF_SHOWTF, 0); TeamFortress_Alias("zoomtoggle", TF_ZOOMTOGGLE, 0); - TeamFortress_Alias("zoomsetoff", TF_ZOOMOFF, 0); - TeamFortress_Alias("zoomset4x", TF_ZOOM4X, 0); - TeamFortress_Alias("zoomset2x", TF_ZOOM2X, 0); + TeamFortress_Alias("zoomin", TF_ZOOMIN, 0); + TeamFortress_Alias("zoomout", TF_ZOOMOUT, 0); TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); TeamFortress_Alias("changeclass", TF_CHANGECLASS, 0); TeamFortress_Alias("scout", TF_CHANGEPC + PC_SCOUT, 0); diff --git a/weapons.qc b/weapons.qc index d38ec376..67f28b0d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -37,17 +37,15 @@ void () PipebombTouch; void () SniperSight_Create; -void (float zoom_level) TF_zoom; +void (float zoom_to) Sniper_Zoom; void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void () TeamFortress_ID; void () TeamFortress_ReloadCurrentWeapon; -void () TeamFortress_ZoomToggle; -void () TeamFortress_SetZoomOff; -void () TeamFortress_SetZoom4x; -void () TeamFortress_SetZoom2x; +void () Sniper_ZoomToggle; +void (float zoom_in) Sniper_ZoomAdjust; void () TeamFortress_StatusQuery; void () TeamFortress_SpyGoUndercover; void () TeamFortress_DetpackMenu; @@ -2067,14 +2065,8 @@ void () ImpulseCommands = { self.impulse = 0; return; } - if (self.impulse == TF_SPECIAL_SKILL) { - if (self.playerclass == PC_SNIPER) { - self.reversezoom = stof(infokey(self, "zr")); - self.zoomkey = stof(infokey(self, "zk")); - self.instazoom = stof(infokey(self, "zi")); - } + if (self.impulse == TF_SPECIAL_SKILL) UseSpecialSkill(); - } if (self.impulse == TF_WEAPLAST) { if (self.playerclass == PC_SPY && self.is_undercover == 2) @@ -2221,14 +2213,6 @@ void () DeadImpulses = { TeamFortress_ShowTF(); else if (self.impulse == TF_CLASSHELP) Help_Show(); - else if (self.impulse == TF_ZOOMTOGGLE) - TeamFortress_ZoomToggle(); - else if (self.impulse == TF_ZOOMOFF) - TeamFortress_SetZoomOff(); - else if (self.impulse == TF_ZOOM4X) - TeamFortress_SetZoom4x(); - else if (self.impulse == TF_ZOOM2X) - TeamFortress_SetZoom2x(); else if (self.impulse == TF_SHOWLEGALCLASSES) TeamFortress_DisplayLegalClasses(); else if ((self.impulse > 100) && (self.impulse <= 110)) { @@ -2324,9 +2308,6 @@ void () DeadImpulses = { }; void () W_WeaponFrame = { - local vector tv; - local float set_fov; - if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 10) { Menu_Input(self.impulse); @@ -2367,53 +2348,28 @@ void () W_WeaponFrame = { return; } - // grenade impulses + sniper zoom always possible - if ((self.impulse >= 150 && self.impulse <= 155) - || (self.playerclass == PC_SNIPER && self.impulse == TF_SPECIAL_SKILL)) { - ImpulseCommands(); - return; - } - if (intermission_running || cease_fire) return; - if (self.zoom_level == 0 || self.zoom_mode == 0) - self.zoom_level = self.default_fov; - - // zoom in/out with zoomkey enabled - if (self.zoom_level > 0 && self.zoom_level != self.current_fov && self.zoomkey == 1) { - if (self.zoom_in == 1) { - if ((self.current_fov - 20) <= self.zoom_level) { - set_fov = self.zoom_level; - self.zoom_in = 0; - } - else - set_fov = self.current_fov - 20; - TF_zoom(set_fov); - } else if (self.zoom_out == 1) { - if ((self.current_fov + 20) >= self.zoom_level) { - set_fov = self.zoom_level; - self.zoom_out = 0; - } - else - set_fov = self.current_fov + 20; - TF_zoom(set_fov); - } else - TF_zoom(self.zoom_level); - } else if (self.zoom_level == self.current_fov) { - self.zoom_in = 0; - self.zoom_out = 0; + // grenade impulses always possible + if (self.impulse >= 150 && self.impulse <= 155) { + ImpulseCommands(); + return; } - // zoom out with zoomkey disabled - if (!(self.tfstate & TFSTATE_AIMING) && self.zoomkey != 1) { - if (self.current_fov != self.default_fov) { - if ((self.current_fov + 20) >= self.default_fov || self.instazoom == 1) - set_fov = self.default_fov; - else - set_fov = self.current_fov + 20; - - TF_zoom(set_fov); + if (self.playerclass == PC_SNIPER) { + if (self.impulse == TF_SPECIAL_SKILL) { + Sniper_ZoomToggle(); + self.impulse = 0; + return; + } else if (self.impulse == TF_ZOOMIN || (self.is_zooming && self.impulse == TF_WEAPPREV)) { + Sniper_ZoomAdjust(1); + self.impulse = 0; + return; + } else if (self.impulse == TF_ZOOMOUT || (self.is_zooming && self.impulse == TF_WEAPNEXT)) { + Sniper_ZoomAdjust(0); + self.impulse = 0; + return; } } @@ -2433,33 +2389,10 @@ void () W_WeaponFrame = { if (self.button0 && !self.fire_held_down) { if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { - if (self.heat < 400) { + if (self.heat < 400) self.heat = self.heat + 3; - } - - // zoom in with zoomkey disabled - if (self.current_fov != self.zoom_level && self.zoomkey != 1) { - if (self.zoom_out == 1) { - if ((self.current_fov + 20) >= self.zoom_level || self.instazoom == 1) { - set_fov = self.zoom_level; - self.zoom_out = 0; - } - else - set_fov = self.current_fov + 20; - } - else { - if ((self.current_fov - 20) <= self.zoom_level || self.instazoom == 1) { - set_fov = self.zoom_level; - self.zoom_in = 0; - } - else - set_fov = self.current_fov - 20; - } - - TF_zoom(set_fov); - } } else { - tv = self.velocity; + local vector tv = self.velocity; tv_z = 0; if (vlen(tv) <= 50) { SniperSight_Create(); From 96ea6502f7faa7306f18cbeb569820adf1e74cb8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 2 Aug 2014 11:45:59 +0200 Subject: [PATCH 0085/2474] Update Sniper class help for improved Sniper zoom --- help.qc | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/help.qc b/help.qc index ed777342..720f0173 100644 --- a/help.qc +++ b/help.qc @@ -61,20 +61,18 @@ void () Help_ShowSniper = { sprint(self, PRINT_HIGH, "² - Equip Sniper Rifle on Full Auto\n"); sprint(self, PRINT_HIGH, "³ - Equip Nailgun\n"); sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "ε - Set autozoom mode / zoom toggle\n"); + sprint(self, PRINT_HIGH, "ε - Toggle zoom mode\n"); + sprint(self, PRINT_HIGH, "νχθεεμυπ - Zoom in (while in zoom mode)\n"); + sprint(self, PRINT_HIGH, "νχθεεμδοχξ - Zoom out (while in zoom mode)\n"); sprint(self, PRINT_HIGH, "ζ - Throw Flare\n"); sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Sniper:\n"); - sprint(self, PRINT_HIGH, "ϊοοντοηημε - Change autozoom mode / zoom toggle\n"); - sprint(self, PRINT_HIGH, "ϊοονσετ²ψ - Set autozoom to 2x / zoom to 2x\n"); - sprint(self, PRINT_HIGH, "ϊοονσετ΄ψ - Set autozoom to 4x / zoom to 4x\n"); - sprint(self, PRINT_HIGH, "ϊοονσετοζζ - Turn off autozoom / zoom out\n"); + sprint(self, PRINT_HIGH, "ϊοοντοηημε - Toggle zoom mode\n"); + sprint(self, PRINT_HIGH, "ϊοονιξ  - Zoom in (for adjusting zoom while in zoom mode)\n"); + sprint(self, PRINT_HIGH, "ϊοονουτ - Zoom out (for adjusting zoom while in zoom mode)\n"); sprint(self, PRINT_HIGH, "\nSettings for Sniper:\n"); - sprint(self, PRINT_HIGH, "ϊλ Ό±―°Ύ - Toggle zoom upon pressing special key on/off\n"); - sprint(self, PRINT_HIGH, "ϊι Ό±―°Ύ - Zoom instantly (not smoothly) on/off\n"); - sprint(self, PRINT_HIGH, "ϊς Ό±―°Ύ - Reverse zoom order on/off\n"); - sprint(self, PRINT_HIGH, "ϊ²ψ ΌζοφΎ - Set fov used for 2x zoom mode (default 40)\n"); - sprint(self, PRINT_HIGH, "ϊ΄ψ ΌζοφΎ - Set fov used for 4x zoom mode (default 20)\n"); + sprint(self, PRINT_HIGH, "ϊζ ΌζοφΎ - The default zoom fov which zoomtoggle zooms to (default 30)\n"); + sprint(self, PRINT_HIGH, "ϊσ ΌζοφΎ - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); sprint(self, PRINT_HIGH, "Usage: setinfo \n"); }; From 0f94eb4b3a7052c15b0e8b7941cdfcf3c2881c57 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 2 Aug 2014 12:11:41 +0200 Subject: [PATCH 0086/2474] Caltrops no longer explode in your hand --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index ae879644..6d89a49e 100644 --- a/tfort.qc +++ b/tfort.qc @@ -653,7 +653,7 @@ void () TeamFortress_GrenadePrimed = { if (!self.think) dremove(self); - if (time > self.heat) + if (time > self.heat && self.weapon != GR_TYPE_CALTROP) TeamFortress_ExplodePerson(); return; From 6c8805de4c6d39ca5eb6bd940d2ca3bb9070fd52 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 2 Aug 2014 12:41:07 +0200 Subject: [PATCH 0087/2474] Add class count to class menu (closes #30) --- menu.qc | 42 ++++++++++++++++++++++++++++++------------ tforttm.qc | 24 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/menu.qc b/menu.qc index 63bde710..1346235e 100644 --- a/menu.qc +++ b/menu.qc @@ -49,6 +49,7 @@ void (float tno, entity ignore, string st) teamsprint; void () Menu_Team; void () Menu_Class; +string (float pc, float tno) TeamFortress_ClassGetNoPlayersString; void () Menu_Drop; void () PlayerObserverMode; void () Menu_Scout; @@ -204,22 +205,41 @@ void (float inp) Menu_Class_Input = { void () Menu_Class = { local entity AD; local string s_select = "Select class:\n\n"; - local string s_scout = "“‘ Scout \n"; - local string s_sniper = "”‘ Sniper \n"; - local string s_soldier = "•‘ Soldier \n"; - local string s_demoman = "–‘ Demoman \n"; - local string s_medic = "—‘ Medic \n"; - local string s_hwguy = "˜‘ HWGuy \n"; - local string s_pyro = "™‘ Pyro \n"; - local string s_spy; - local string s_engineer = "›‘ Engineer\n"; - local string s_randompc = "’‘ RandomPC"; + local string s_scout = "“‘ Scout "; + local string s_sniper = "”‘ Sniper "; + local string s_soldier = "•‘ Soldier "; + local string s_demoman = "–‘ Demoman "; + local string s_medic = "—‘ Medic "; + local string s_hwguy = "˜‘ HWGuy "; + local string s_pyro = "™‘ Pyro "; + local string s_spy = "š‘ Spy "; + local string s_engineer = "›‘ Engineer "; + local string s_randompc = "’‘ RandomPC "; if (self.menu_input == Menu_Class_Input) { Menu_Input(0); return; } + local string count_sc = TeamFortress_ClassGetNoPlayersString(PC_SCOUT, self.team_no); + local string count_sn = TeamFortress_ClassGetNoPlayersString(PC_SNIPER, self.team_no); + local string count_so = TeamFortress_ClassGetNoPlayersString(PC_SOLDIER, self.team_no); + local string count_de = TeamFortress_ClassGetNoPlayersString(PC_DEMOMAN, self.team_no); + local string count_me = TeamFortress_ClassGetNoPlayersString(PC_MEDIC, self.team_no); + local string count_hw = TeamFortress_ClassGetNoPlayersString(PC_HVYWEAP, self.team_no); + local string count_py = TeamFortress_ClassGetNoPlayersString(PC_PYRO, self.team_no); + local string count_sp = TeamFortress_ClassGetNoPlayersString(PC_SPY, self.team_no); + local string count_en = TeamFortress_ClassGetNoPlayersString(PC_ENGINEER, self.team_no); + s_scout = strcat(s_scout, strcat(count_sc, "\n")); + s_sniper = strcat(s_sniper, strcat(count_sn, "\n")); + s_soldier = strcat(s_soldier, strcat(count_so, "\n")); + s_demoman = strcat(s_demoman, strcat(count_de, "\n")); + s_medic = strcat(s_medic, strcat(count_me, "\n")); + s_hwguy = strcat(s_hwguy, strcat(count_hw, "\n")); + s_pyro = strcat(s_pyro, strcat(count_py, "\n")); + s_spy = strcat(s_spy, strcat(count_sp, "\n")); + s_engineer = strcat(s_engineer, strcat(count_en, "\n")); + AD = find(world, classname, "info_tfdetect"); if (AD) { if (self.team_no == 1) { @@ -251,8 +271,6 @@ void () Menu_Class = { else { if (spy_off == 1) s_spy = "\n"; - else - s_spy = "š‘ Spy \n"; Status_Menu(self, Menu_Class_Input, s_select, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_randompc); } }; diff --git a/tforttm.qc b/tforttm.qc index 0d8ba520..85eb8b64 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -395,6 +395,30 @@ float (float tno) TeamFortress_TeamGetNoPlayers = { return (size_team); }; +float (float pc, float tno) TeamFortress_ClassGetNoPlayers = { + local float class_count; + local entity search; + class_count = 0; + + search = find(world, classname, "player"); + while (search != world) { + if (search.playerclass == pc && search.team_no == tno) + class_count = class_count + 1; + search = find(search, classname, "player"); + } + return (class_count); +}; + +string (float pc, float tno) TeamFortress_ClassGetNoPlayersString = { + local float class_count; + + class_count = TeamFortress_ClassGetNoPlayers(pc, tno); + if (class_count == 1) + return "1 player "; + + return strcat(ftos(class_count), " players"); +}; + float () TeamFortress_GetNoPlayers = { local float nump; local entity search; From 86dcda32e1f908e41834a6e3f0925ce9ad62d28c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 2 Aug 2014 14:36:51 +0200 Subject: [PATCH 0088/2474] Remove birthday sound precaches --- world.qc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/world.qc b/world.qc index 78084c54..9d24a24f 100644 --- a/world.qc +++ b/world.qc @@ -286,10 +286,6 @@ void () worldspawn = { precache_sound2("speech/saveme2.wav"); precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); - precache_sound2("misc/b1.wav"); - precache_sound2("misc/b2.wav"); - precache_sound2("misc/b3.wav"); - precache_sound2("misc/b4.wav"); precache_sound("items/grentimer.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); From d5c1672976f46e18b20e7102195f77752ffa5967 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 12:50:44 +0200 Subject: [PATCH 0089/2474] Improve weapon slots (closes #90) --- client.qc | 4 +- defs.h | 2 +- qw.qc | 6 +-- tfort.qc | 5 ++- weapons.qc | 120 +++++++++++++++++++++++++++-------------------------- 5 files changed, 70 insertions(+), 67 deletions(-) diff --git a/client.qc b/client.qc index 95d2553d..7e0ebbca 100644 --- a/client.qc +++ b/client.qc @@ -1009,9 +1009,9 @@ void () PutClientInServer = { SetTeamName(self); W_SetCurrentAmmo(); if (self.current_weaponslot && self.last_playerclass == self.playerclass) - W_ChangeWeapon(self.current_weaponslot); + W_ChangeWeapon(self.current_weaponslot, 0); else - W_ChangeWeapon(1); + W_ChangeWeapon(1, 0); self.last_playerclass = self.playerclass; self.attack_finished = time + 0.3; diff --git a/defs.h b/defs.h index 7233a303..7cd45f2b 100644 --- a/defs.h +++ b/defs.h @@ -360,7 +360,7 @@ #define TF_CAM_FADETOWHITE 61 #define TF_CAM_FADEFROMWHITE 62 -#define TF_QUICKLAST 68 +#define TF_QUICKSTOP 68 #define TF_WEAPLAST 69 // CF map voting diff --git a/qw.qc b/qw.qc index bf305730..d692cb7c 100644 --- a/qw.qc +++ b/qw.qc @@ -29,6 +29,7 @@ typedef void (float) f_void_float; .float is_feigning; // TRUE for a SPY if they're feigning death .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in +.float is_quickfiring; // TRUE for a player if they're using the quick slots .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer .float default_sensitivity; // Player's default (non-zoomed) sensitivity @@ -130,11 +131,10 @@ float coop; .float weapons_carried; // the weapons the player is carrying .float current_weapon; // the weapon the player is using .float current_weaponslot; // the currently equipped weaponslot +.float real_weaponslot; // the actual equipped weaponslot (during a quick slot attack) .float last_weaponslot; // the last equipped weaponslot -.float slast_weaponslot; // the second last equipped weaponslot .float queue_weaponslot; // the weaponslot to switch to when possible -.float quick_weapon; // TRUE if the player is using a quick weapon slot -.float quick_weaponchange; // TRUE if attempting to change weapon (during quick fire) when not yet ready +.float queue_last_weaponslot; // the weaponslot to set as last weaponslot when possible .float next_weapon; // used by weapon slots to communicate which weapon to select .float next_weaponmode; // used by weapon slots to communicate which weapon mode to select diff --git a/tfort.qc b/tfort.qc index 6d89a49e..e2f42bb3 100644 --- a/tfort.qc +++ b/tfort.qc @@ -190,7 +190,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(1); + W_ChangeWeapon(1, 0); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; @@ -1336,9 +1336,10 @@ void () TeamFortress_SetEquipment = { self.weapons_carried = 0; if (self.last_playerclass != self.playerclass) { self.current_weapon = 0; - self.current_weaponslot = 1; self.weaponmode = 0; + self.current_weaponslot = 1; self.last_weaponslot = 1; + self.real_weaponslot = 1; } self.tf_items = 0; diff --git a/weapons.qc b/weapons.qc index 67f28b0d..10845fdd 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1928,39 +1928,45 @@ void () W_WeaponSlot4 = { self.next_weapon = WEAP_AXE; }; -void (float inp) W_ChangeWeapon = { +void (float slot) W_WeaponSlot = { + self.next_weaponmode = 0; + if (slot == 1) + W_WeaponSlot1(); + else if (slot == 2) + W_WeaponSlot2(); + else if (slot == 3) + W_WeaponSlot3(); + else if (slot == 4) + W_WeaponSlot4(); +}; + +void (float inp, float quick) W_ChangeWeapon = { if (self.playerclass == 0) return; // queue next weapon (in case of attack/reload in progress) if (!self.queue_weaponslot || self.queue_weaponslot != inp) { - // set quick_weaponchange when player tries to change weapon during quick weapon fire/reload - if (((self.tfstate & TFSTATE_RELOADING) || time < self.attack_finished) && self.quick_weapon) { - if (inp == TF_WEAPLAST) - self.quick_weaponchange = 1; - } - if (inp == TF_WEAPLAST) - self.queue_weaponslot = TF_WEAPLAST; - else if (inp < 5 && !(self.quick_weapon && (self.tfstate & TFSTATE_RELOADING))) + if (inp == TF_WEAPLAST && !quick) { + self.queue_weaponslot = self.last_weaponslot; + } else if (inp == TF_WEAPLAST && quick && !self.is_quickfiring) { + if (!(self.tfstate & TFSTATE_RELOADING) && time >= self.attack_finished) { + self.queue_weaponslot = self.real_weaponslot; + self.current_weaponslot = self.queue_weaponslot; + } + } else if (inp < 5 && !quick) { + if (is_quickfiring) + self.queue_last_weaponslot = self.real_weaponslot; self.queue_weaponslot = inp; + } else if (inp < 5 && quick) { + if (!(self.tfstate & TFSTATE_RELOADING) && time >= self.attack_finished) + self.queue_weaponslot = inp; + } } // don't do anything yet if still reloading or attack in progress - if (self.tfstate & TFSTATE_RELOADING || time < self.attack_finished) - return; - - // don't do anything without a weapon queue - if (!self.queue_weaponslot) + if ((self.tfstate & TFSTATE_RELOADING) || time < self.attack_finished) return; - // queue last weaponslot - if (self.queue_weaponslot == TF_WEAPLAST) { - self.queue_weaponslot = self.last_weaponslot; - // use second last weapon when switching back from quick fire - if (self.quick_weapon) - self.last_weaponslot = self.slast_weaponslot; - } - // check for ammo if (! W_AmmoSlot(self.queue_weaponslot)) { if (self.noammo == 1) { @@ -1974,37 +1980,31 @@ void (float inp) W_ChangeWeapon = { } } - self.next_weaponmode = 0; - if (self.queue_weaponslot == 1) - W_WeaponSlot1(); - else if (self.queue_weaponslot == 2) - W_WeaponSlot2(); - else if (self.queue_weaponslot == 3) - W_WeaponSlot3(); - else if (self.queue_weaponslot == 4) - W_WeaponSlot4(); + W_WeaponSlot(self.queue_weaponslot); - if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode || self.quick_weapon) { - // set last weapons when not using quick fire - if (!(self.quick_weapon && inp == TF_WEAPLAST)) { - self.slast_weaponslot = self.last_weaponslot; + // don't update current/last weapon information if next weapon is the same as current + if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { + if (quick) { + self.real_weaponslot = self.current_weaponslot; + } else { + self.real_weaponslot = self.queue_weaponslot; self.last_weaponslot = self.current_weaponslot; } - // set last weapon to second last when changing weapons during quick attack/reload - if (self.quick_weaponchange && !self.quick_weapon) - self.last_weaponslot = self.slast_weaponslot; + if (self.queue_last_weaponslot) + self.last_weaponslot = self.queue_last_weaponslot; self.current_weaponslot = self.queue_weaponslot; self.current_weapon = self.next_weapon; self.weaponmode = self.next_weaponmode; - if (!self.quick_weapon) + + // only print out weapon messages for non-quick weapons + if (!quick) W_PrintWeaponMessage(); } W_SetCurrentAmmo(); Status_Refresh(self); - self.quick_weapon = 0; - self.quick_weaponchange = 0; self.queue_weaponslot = 0; + self.queue_last_weaponslot = 0; }; void () CycleWeaponNext = { @@ -2024,7 +2024,7 @@ void () CycleWeaponNext = { break; } } - W_ChangeWeapon(next); + W_ChangeWeapon(next, 0); }; void () CycleWeaponPrev = { @@ -2044,7 +2044,7 @@ void () CycleWeaponPrev = { break; } } - W_ChangeWeapon(next); + W_ChangeWeapon(next, 0); }; void () PreMatchImpulses; @@ -2087,12 +2087,12 @@ void () ImpulseCommands = { if (self.is_building == 1) { if (self.impulse >= 1 && self.impulse <= 5) { TeamFortress_EngineerBuildStop(); - W_ChangeWeapon(self.impulse); + W_ChangeWeapon(self.impulse, 0); } else if (self.impulse == TF_WEAPNEXT || self.impulse == TF_WEAPPREV || self.impulse == TF_WEAPLAST) { TeamFortress_EngineerBuildStop(); - W_ChangeWeapon(self.impulse); + W_ChangeWeapon(self.impulse, 0); } } @@ -2102,7 +2102,7 @@ void () ImpulseCommands = { else if (self.impulse == TF_WEAPPREV) CycleWeaponPrev(); else if (self.impulse == TF_WEAPLAST && self.last_weaponslot != 0) - W_ChangeWeapon(self.impulse); + W_ChangeWeapon(self.impulse, 0); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); else if (self.impulse == TF_DETPACK_5) @@ -2187,9 +2187,9 @@ void () ImpulseCommands = { void () PreMatchImpulses = { if (((self.impulse >= 1) && (self.impulse < 8)) || (self.impulse == TF_MEDIKIT)) - W_ChangeWeapon(self.impulse); + W_ChangeWeapon(self.impulse, 0); else if (self.impulse == AXE_IMP) - W_ChangeWeapon(self.impulse); + W_ChangeWeapon(self.impulse, 0); else if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); else if (self.impulse == TF_WEAPPREV) @@ -2326,18 +2326,20 @@ void () W_WeaponFrame = { TeamFortress_DetpackMenu(); } + if (self.impulse == TF_QUICKSTOP) + self.is_quickfiring = 0; + if (self.impulse >= 1 && self.impulse <= 4) { - self.quick_weapon = 0; - W_ChangeWeapon(self.impulse); - } else if (self.impulse >= 31 && self.impulse <= 34) { - self.quick_weapon = 1; - W_ChangeWeapon((self.impulse - 30)); - } else if (self.impulse == TF_QUICKLAST) { - self.quick_weapon = 1; - W_ChangeWeapon(TF_WEAPLAST); - } - if (self.queue_weaponslot) - W_ChangeWeapon(self.queue_weaponslot); + self.is_quickfiring = 0; + W_ChangeWeapon(self.impulse, 0); + } else if (self.impulse >= 31 && self.impulse <= 34 && !(self.tfstate & TFSTATE_RELOADING)) { + self.is_quickfiring = 1; + W_ChangeWeapon((self.impulse - 30), 1); + } else if (self.queue_weaponslot) + W_ChangeWeapon(self.queue_weaponslot, 0); + else if (self.real_weaponslot != self.current_weaponslot + && time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) + W_ChangeWeapon(TF_WEAPLAST, 1); if (self.impulse == TF_CHANGETEAM) { Menu_Team(); From 3aadc4cd77fc5f7fdeb3c50f50f29ea66f8462ba Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 21:45:16 +0200 Subject: [PATCH 0090/2474] Increase clip ammo as weapon reloads --- actions.qc | 31 ++++++++++++++++++++++++++++--- qw.qc | 3 +++ status.qc | 6 ++++-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/actions.qc b/actions.qc index c1f31aff..01a909de 100644 --- a/actions.qc +++ b/actions.qc @@ -2,6 +2,8 @@ // Non Class-Specific Impulse Commands //======================================================== +void () TeamFortress_ClipTick; + void () TeamFortress_Discard = { newmis = spawn(); if ((self.playerclass == PC_SCOUT) @@ -256,9 +258,9 @@ void () TeamFortress_ID = { }; void () TeamFortress_ReloadCurrentWeapon = { - local float reloadtime; - local float reloadamount; - local entity tWeapon; + local float reloadtime = 0; + local float reloadamount = 0; + local entity tWeapon, tClip; if (self.tfstate & TFSTATE_RELOADING) { return; @@ -282,6 +284,7 @@ void () TeamFortress_ReloadCurrentWeapon = { else reloadamount = self.reload_shotgun; Attack_Finished(0.4); + self.reload_clipsize = (8 - reloadamount); reloadtime = (8 - reloadamount) / 8; reloadtime = 2 - 2 * reloadtime; self.reload_shotgun = 0; @@ -320,6 +323,7 @@ void () TeamFortress_ReloadCurrentWeapon = { else reloadamount = self.reload_super_shotgun; Attack_Finished(0.7); + self.reload_clipsize = (16 - reloadamount); reloadtime = (16 - reloadamount) / 16; reloadtime = 3 - (3 * reloadtime); self.reload_super_shotgun = 0; @@ -359,6 +363,7 @@ void () TeamFortress_ReloadCurrentWeapon = { else reloadamount = self.reload_grenade_launcher; Attack_Finished(0.6); + self.reload_clipsize = (6 - reloadamount); reloadtime = (6 - reloadamount) / 6; reloadtime = 4 - 4 * reloadtime; self.reload_grenade_launcher = 0; @@ -399,6 +404,7 @@ void () TeamFortress_ReloadCurrentWeapon = { else reloadamount = self.reload_rocket_launcher; Attack_Finished(0.8); + self.reload_clipsize = (4 - reloadamount); reloadtime = (4 - reloadamount) / 4; reloadtime = 5 - (5 * reloadtime); self.reload_rocket_launcher = 0; @@ -420,6 +426,25 @@ void () TeamFortress_ReloadCurrentWeapon = { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } } + if (reloadamount && reloadtime) { + self.reload_time = time + reloadtime; + self.reload_tick = reloadtime / reloadamount; + tClip = spawn(); + tClip.owner = self; + tClip.classname = "timer"; + tClip.nextthink = time + self.reload_tick; + tClip.think = TeamFortress_ClipTick; + } +}; + +void () TeamFortress_ClipTick = { + if (time < self.owner.reload_time) { + self.owner.reload_clipsize = self.owner.reload_clipsize + 1; + Status_Refresh(self.owner); + self.nextthink = time + self.owner.reload_tick; + } else { + dremove(self); + } }; void (float messageno) TeamFortress_Message = { diff --git a/qw.qc b/qw.qc index d692cb7c..fb522c15 100644 --- a/qw.qc +++ b/qw.qc @@ -149,6 +149,9 @@ float coop; .float reload_super_shotgun; .float reload_grenade_launcher; .float reload_rocket_launcher; +.float reload_tick; // how often the status bar should be refreshed during reload +.float reload_time; // when the reload will finish +.float reload_clipsize; // how much ammo is currently in the reloading clip // Assault Cannon .float heat; diff --git a/status.qc b/status.qc index 89ccd95c..b4fe215e 100644 --- a/status.qc +++ b/status.qc @@ -190,8 +190,10 @@ void (entity pl) RefreshStatusBar = { else st2 = GreenScoreToString(team4score); // status line 3 column 3 - clip size - if (self.tfstate & TFSTATE_RELOADING) { - st3 = "Γμιπ: 0/"; + if (pl.tfstate & TFSTATE_RELOADING) { + st3 = "Γμιπ: "; + st3 = strcat(st3, strpadl(ftos(pl.reload_clipsize), 2)); + st3 = strcat(st3, "/"); st3 = strcat(st3, strpadr(ftos(GetClipSize(pl)), 3)); } else { st3 = ClipSizeToString(pl); From 0d62faf104bd6d8fb170c59768d702169ee1fc0d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 21:47:15 +0200 Subject: [PATCH 0091/2474] Add kill streak and caps to status bar --- client.qc | 1 + qw.qc | 2 ++ status.qc | 37 ++++++++++++++++++++++++++++--------- tfort.qc | 5 +++++ tfortmap.qc | 1 + 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/client.qc b/client.qc index 7e0ebbca..81747f04 100644 --- a/client.qc +++ b/client.qc @@ -559,6 +559,7 @@ void () execute_changelevel = { other.solid = SOLID_NOT; other.movetype = MOVETYPE_NONE; other.modelindex = 0; + other.caps = 0; other = find(other, classname, "player"); } if (!clan_scores_dumped) { diff --git a/qw.qc b/qw.qc index fb522c15..da365e3a 100644 --- a/qw.qc +++ b/qw.qc @@ -46,6 +46,8 @@ typedef void (float) f_void_float; .float detpack_left; // Seconds left to detpack explosion .float disguise_skin; // The skin the spy is changing to .float disguise_team; // The team the spy is changing to +.float fragstreak; // Frag streak +.float caps; // Caps during this game .float tfstate; // State flags for TeamFortress .entity linked_list; // Used just like chain. Has to be separate so diff --git a/status.qc b/status.qc index b4fe215e..9ed55fd6 100644 --- a/status.qc +++ b/status.qc @@ -128,17 +128,36 @@ void (entity pl) RefreshStatusBar = { pad = strzone(pad); // status line 1 column 1 - grenade timer - if (pl.StatusGrenTime > 0) - st1 = strcat("Ηςεξαδε: ", strcat(ftos(pl.StatusGrenTime), " seconds")); - else + if (pl.StatusGrenTime > 0) { + st1 = strcat("Ηςεξαδε: ", ftos(pl.StatusGrenTime)); + if (pl.fragstreak > 1 && pl.caps) + st1 = strcat(st1, " sec"); + else + st1 = strcat(st1, " seconds"); + } else st1 = ""; - // flag carrier info - if (pl.items & IT_KEY1) - st2 = "Γαςςωιξη Ζμαη"; - else - st2 = " "; + // status line 1 column 3 - kill streak & caps + if (pl.fragstreak > 1) { + st2 = "Λιμμ στςεαλ: "; + st2 = strcat(st2, strpadl(ftos(pl.fragstreak),2)); + } else + st2 = ""; + if (pl.caps) { + if (pl.fragstreak > 1) + st2 = strcat(st2, " "); + st3 = "Γαπσ: "; + st3 = strcat(st3, strpadl(ftos(pl.caps),2)); + } else + st3 = ""; + st2 = strcat(st2, st3); // status line 1 - s1 = strpadr(st1, 27); + if (pl.fragstreak > 1 && pl.caps) { + st2 = strpadl(st2, 25); + s1 = strpadr(st1, 15); + } else { + st2 = strpadl(st2, 20); + s1 = strpadr(st1, 20); + } s1 = strcat(s1, st2); s1 = strcat(s1, "\n"); s1 = strzone(s1); diff --git a/tfort.qc b/tfort.qc index e2f42bb3..b2e3b35a 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1366,6 +1366,7 @@ void () TeamFortress_SetEquipment = { self.disguise_skin = 0; self.disguise_team = 0; self.detpack_left = 0; + self.fragstreak = 0; self.ammo_medikit = 0; self.maxammo_medikit = 0; @@ -2673,6 +2674,10 @@ void (entity pl, float fr) TF_AddFrags = { return; pl.real_frags = pl.real_frags + fr; + if (fr == 1) { + pl.fragstreak = pl.fragstreak + 1; + Status_Refresh(pl); + } if (!pl.team_no) return; diff --git a/tfortmap.qc b/tfortmap.qc index 6278b010..ca8227db 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -683,6 +683,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player.team_no > 0) { TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count); TeamFortress_TeamShowScores(2); + Player.caps = Player.caps + 1; } } } From 25e594eab789a8a4cbbe0f26691a0d5218b87afd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 21:48:28 +0200 Subject: [PATCH 0092/2474] Allow HWGuy to shoot his weapon in the air --- client.qc | 11 ----------- weapons.qc | 8 -------- 2 files changed, 19 deletions(-) diff --git a/client.qc b/client.qc index 81747f04..481b1836 100644 --- a/client.qc +++ b/client.qc @@ -1294,19 +1294,8 @@ void () PlayerJump = { sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { - stuffcmd(self, "v_idlescale 0\n"); - if (self.antispam_cannon_air < time) { - sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); - self.antispam_cannon_air = time + 3; - } self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.count = 1; - self.heat = 0; - player_assaultcannondown1(); } if (old_grens != 1) { te = find(world, classname, "timer"); diff --git a/weapons.qc b/weapons.qc index 10845fdd..dd9af552 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2403,14 +2403,6 @@ void () W_WeaponFrame = { TeamFortress_SetSpeed(self); } } - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (self.flags & FL_ONGROUND) { - SuperDamageSound(); - W_Attack(); - } else if (self.antispam_cannon_air < time) { - sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); - self.antispam_cannon_air = time + 3; - } } else { SuperDamageSound(); W_Attack(); From 17ffe883f087c2da0da81a13e9ad2260f60af589 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 22:37:41 +0200 Subject: [PATCH 0093/2474] Add a special for HWGuy to spin his Assault Cannon without firing --- defs.h | 4 +++- player.qc | 4 ++-- status.qc | 11 +++++++++++ tforthlp.qc | 2 ++ weapons.qc | 16 ++++++++++++++++ 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/defs.h b/defs.h index 7cd45f2b..edf3c444 100644 --- a/defs.h +++ b/defs.h @@ -233,7 +233,7 @@ #define TFSTATE_BURNING 512 // Is on fire #define TFSTATE_GRENTHROWING 1024 // is throwing a grenade #define TFSTATE_AIMING 2048 // is using the laser sight -//unused 4096 +#define TFSTATE_HALT 4096 // this state will stop hwguy from shooting assault cannon #define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire #define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating #define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised @@ -418,6 +418,8 @@ #define TF_GRENADE_PT_2 155 // Prime and throw grenade type 2 (two clicks) // Impulses for new items +#define TF_HALT 157 // Stop firing Assault Cannon +#define TF_UNHALT 158 // Resume firing Assault Cannon #define TF_SCAN 159 // Scanner Pre-Impulse #define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies #define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies diff --git a/player.qc b/player.qc index 510a7493..cdd85318 100644 --- a/player.qc +++ b/player.qc @@ -403,7 +403,7 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { void () player_assaultcannon1 =[103, player_assaultcannon2] { local string st; - if (vlen(self.velocity) <= 90) { + if (vlen(self.velocity) <= 90 && !(self.tfstate & TFSTATE_HALT)) { muzzleflash(); sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); @@ -453,7 +453,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { void () player_assaultcannon2 =[104, player_assaultcannon1] { stuffcmd(self, "v_idlescale 0\n"); - if (vlen(self.velocity) < 20) { + if (vlen(self.velocity) < 30 && !(self.tfstate & TFSTATE_HALT)) { if (self.weaponframe == 2) { self.weaponframe = 4; } else { diff --git a/status.qc b/status.qc index 9ed55fd6..6ffd5980 100644 --- a/status.qc +++ b/status.qc @@ -10,6 +10,7 @@ string(float num) GreenScoreToString; string(entity pl) ClipSizeToString; float(entity pl) GetClipSize; string(entity pl) DetpackToString; +string(entity pl) AssaultCannonToString; string(entity pl) RangeToString; string(entity pl) ScannerToString; string(entity pl) DisguiseToString; @@ -168,6 +169,8 @@ void (entity pl) RefreshStatusBar = { st1 = ScannerToString(pl); else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) st1 = DetpackToString(pl); + else if (pl.playerclass == PC_HVYWEAP) + st1 = AssaultCannonToString(pl); else if (pl.playerclass == PC_SPY) st1 = DisguiseToString(pl); else if (pl.playerclass == PC_ENGINEER && pl.has_sentry) @@ -408,6 +411,14 @@ string(entity pl) DetpackToString = return st; }; +string(entity pl) AssaultCannonToString = +{ + if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_HALT)) + return "Ασσαυμτ Γαξξοξ Μογλεδ"; + else + return ""; +}; + string(entity pl) RangeToString = { local entity te; diff --git a/tforthlp.qc b/tforthlp.qc index a98c1173..eab32354 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -135,6 +135,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-det50", TF_DETPACK_STOP, 0); TeamFortress_Alias("+det255", TF_DETPACK, 255); TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); + TeamFortress_Alias("+halt", TF_HALT, 0); + TeamFortress_Alias("-halt", TF_UNHALT, 0); } else if (self.motd == 85) { TeamFortress_Alias("clan1", 82, 0); TeamFortress_Alias("clan2", 83, 0); diff --git a/weapons.qc b/weapons.qc index dd9af552..3440414c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2359,6 +2359,22 @@ void () W_WeaponFrame = { return; } + // hwguy assault cannon special + if (self.playerclass == PC_HVYWEAP) { + if ((self.impulse == TF_SPECIAL_SKILL || self.impulse == TF_HALT) && !(self.tfstate & TFSTATE_HALT)) { + self.tfstate = self.tfstate | TFSTATE_HALT; + Status_Refresh(self); + self.impulse = 0; + return; + } + else if ((self.impulse == TF_SPECIAL_SKILL || self.impulse == TF_UNHALT) && (self.tfstate & TFSTATE_HALT)) { + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_HALT); + Status_Refresh(self); + self.impulse = 0; + return; + } + } + if (self.playerclass == PC_SNIPER) { if (self.impulse == TF_SPECIAL_SKILL) { Sniper_ZoomToggle(); From 9fc5e6b27998787b9904bfe2716945b6390fffe7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 22:37:52 +0200 Subject: [PATCH 0094/2474] Fix Sentry Gun rotation menu bug (fixes #98) --- engineer.qc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/engineer.qc b/engineer.qc index 12ae65c2..301121d2 100644 --- a/engineer.qc +++ b/engineer.qc @@ -766,12 +766,11 @@ void (entity gun) Engineer_UseSentryGun = { return; } - if (gun.ammo_shells < gun.maxammo_shells || (gun.weapon == 3 - && gun.ammo_rockets < gun.maxammo_rockets)) { - if (self.ammo_shells > 0 || (gun.weapon == 3 && self.ammo_rockets > 0)) { - Engineer_SentryGun_InsertAmmo(gun); - return; - } + if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) + || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets + && self.ammo_rockets > 0)) { + Engineer_SentryGun_InsertAmmo(gun); + return; } sprint(self, PRINT_HIGH, "Level "); From 369546f7e32f32b21170447a8b8b8179f7ebf6a0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 22:38:04 +0200 Subject: [PATCH 0095/2474] Turn down volume of HWGuy Assault Cannon spinning/winding down --- player.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/player.qc b/player.qc index cdd85318..3bd6ae08 100644 --- a/player.qc +++ b/player.qc @@ -430,7 +430,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { stuffcmd(self, st); stuffcmd(self, "\n"); } else { - sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 1, ATTN_NORM); + sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); if (self.weaponframe == 2) self.weaponframe = 0; @@ -484,7 +484,7 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { void () player_assaultcannondown1 =[103, player_assaultcannondown1] { if (self.count == 1) { - sound(self, 1, "weapons/asscan3.wav", 1, 1); + sound(self, 1, "weapons/asscan3.wav", 0.8, 1); } if (self.count >= 15) { self.heat = 0; From 91733a19d8526c8982938415a7d9a54c11a9c3c0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 22:38:35 +0200 Subject: [PATCH 0096/2474] Change grenade count in status bar from x/y to x+y --- status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.qc b/status.qc index 6ffd5980..c329b815 100644 --- a/status.qc +++ b/status.qc @@ -221,7 +221,7 @@ void (entity pl) RefreshStatusBar = { st3 = ClipSizeToString(pl); } // status line 3 column 4 - grenade count - st4 = strcat("Ηςεξ: ", strcat(strcat(ftos(self.no_grenades_1), "/"), ftos(self.no_grenades_2))); + st4 = strcat("Ηςεξ: ", strcat(strcat(ftos(pl.no_grenades_1), "+"), ftos(pl.no_grenades_2))); // status line 3 s3 = strcat(st1, st2); s3 = strpadr(s3, 19); From 254d2ce0398b853a42de2b47e27e8e368b0c2694 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 22:39:11 +0200 Subject: [PATCH 0097/2474] Increase HWGuy accuracy --- player.qc | 2 +- weapons.qc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/player.qc b/player.qc index 3bd6ae08..1933cd4d 100644 --- a/player.qc +++ b/player.qc @@ -416,7 +416,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { W_FireAssaultCannon(); stuffcmd(self, "v_idlescale "); - if (vlen(self.velocity) < 50) { + if (vlen(self.velocity) < 30) { if (self.heat < 5) st = ftos(self.heat * 4); else diff --git a/weapons.qc b/weapons.qc index 3440414c..c74589d5 100644 --- a/weapons.qc +++ b/weapons.qc @@ -888,9 +888,9 @@ void () W_FireAssaultCannon = { deathmsg = DMSG_ASSAULTCANNON; if (vlen(self.velocity) < 50) - FireBullets(5, dir, '0.1 0.1 0'); + FireBullets(5, dir, '0.075 0.075 0'); else - FireBullets(5, dir, '0.2 0.2 0'); + FireBullets(5, dir, '0.15 0.15 0'); }; void () s_explode1 =[0, s_explode2] { From 767b2d982398fc7ecc6beddfc4fd647fe061872e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 22:39:27 +0200 Subject: [PATCH 0098/2474] Improve map voting code (closes #70) --- defs.h | 5 +- vote.qc | 318 ++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 198 insertions(+), 125 deletions(-) diff --git a/defs.h b/defs.h index edf3c444..7e81b7ae 100644 --- a/defs.h +++ b/defs.h @@ -253,9 +253,10 @@ #define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc // Classic Fortress stuff -#define CF_MAPVOTE_FORCESHOW 5 // Seconds to force the mapvote menu to be open +#define CF_MAPVOTE_FORCESHOW 10 // Seconds to force the mapvote menu to be open +#define CF_MAPVOTE_FINISH 5 // Seconds before timelimit to close all voting #define CF_MAPVOTE_DURATION 180 // Seconds to show map vote menu -#define CF_MAPVOTE_DURATION_DECIDER 120 // Seconds to show map decider menu +#define CF_MAPVOTE_DURATION_DECIDER 90 // Seconds to show map decider menu /*======================================================*/ /* Toggleable Game Settings */ diff --git a/vote.qc b/vote.qc index df2f5102..ccc0c6f9 100644 --- a/vote.qc +++ b/vote.qc @@ -11,7 +11,7 @@ float () Vote_GetForceNextVotes; void () Vote_Check; void (float pf_decider) Vote_SetupVote; void (float pf_input) Vote_Input; -void () Vote_MenuOpen; +void (float force) Vote_MenuOpen; void () Vote_MenuClose; void (entity pe_player) Vote_Menu; void (float pf_input) Vote_RemoveVote; @@ -43,6 +43,9 @@ float vote_started, vote_update, vote_winnercount, vote_decider, vote_abort; void (entity pe_player) Vote_NextMap = { local float f_votes, f_votes_needed; + if (!pe_player.team_no || !pe_player.playerclass) + return; + if (vote_result != string_null) { sprint(pe_player, PRINT_HIGH, "Next map has already been voted to ", vote_result, ". Use /forcenext to force next map.\n"); return; @@ -55,7 +58,7 @@ void (entity pe_player) Vote_NextMap = { f_votes_needed = floor(TeamFortress_GetNoPlayers() / 2); if (f_votes >= f_votes_needed) { Vote_SetupVote(0); - //dprint("[cf/mapvote/votenext]: forcing map vote.\n"); + //dprint("[", ftos(time), "/cf/mapvote/votenext]: forcing map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for next map\n"); } }; @@ -68,7 +71,7 @@ float () Vote_GetNextVotes = { e_player = find(world, classname, "player"); while (e_player != world) { - if (e_player.vote_next == 1) + if (e_player.vote_next == 1 && e_player.team_no && e_player.playerclass) f_count = f_count + 1; e_player = find(e_player, classname, "player"); } @@ -94,7 +97,7 @@ void (entity pe_player) Vote_ForceNext = { f_votes_needed = ceil(TeamFortress_GetNoPlayers() / 2); if (f_votes >= f_votes_needed) { Vote_SetupVote(0); - //dprint("[cf/mapvote/forcenext]: forcing next map: ", vote_result, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/forcenext]: forcing next map: ", vote_result, "\n"); bprint(PRINT_HIGH, "Changing level to ", vote_result, "\n"); GotoNextMap(); } @@ -119,45 +122,60 @@ float () Vote_GetForceNextVotes = { // check if voting should start each frame // called from world.qc:StartFrame() void () Vote_Check = { + local float closetime = timelimit - CF_MAPVOTE_FINISH; + local float decidertime_force = closetime - CF_MAPVOTE_FORCESHOW; + local float decidertime = closetime - CF_MAPVOTE_DURATION_DECIDER; + local float votetime_force = decidertime - CF_MAPVOTE_FORCESHOW; + local float votetime = decidertime - CF_MAPVOTE_DURATION; // only run these checks once a second if (vote_started >= 0 && (time - vote_update) >= 1 && !vote_abort) { vote_update = time; - if ((time + CF_MAPVOTE_DURATION + CF_MAPVOTE_DURATION_DECIDER) > timelimit && vote_started == 0) { - //dprint("[cf/mapvote/check]: setting up map vote.\n"); + if (time >= votetime && vote_started == 0) { + //dprint("[", ftos(time), "/cf/mapvote/check]: setting up map vote.\n"); Vote_SetupVote(0); - if (!vote_abort) { - bprint(PRINT_HIGH, "Time to vote for what map comes next\n"); - //dprint("[cf/mapvote/check]: opening map vote.\n"); - Vote_MenuOpen(); - } + bprint(PRINT_HIGH, "Time to vote for what map comes next\n"); + //dprint("[", ftos(time), "/cf/mapvote/check]: opening map vote.\n"); + Vote_MenuOpen(0); return; } - else if (vote_started > 0) { + // only try to force show vote menu if player is not newly spawned + if (vote_started > 0 && (time - self.spawn_time) > CF_MAPVOTE_FORCESHOW) { + if (time >= votetime_force && time < decidertime) + Vote_MenuOpen(1); + else if (time >= decidertime_force && time < closetime) + Vote_MenuOpen(2); + } + + if (vote_started > 0) { // open/close menus for those eligible - Vote_MenuOpen(); + Vote_MenuOpen(0); Vote_MenuClose(); - // when voting has been going on for CF_MAPVOTE_DURATION seconds or + // when voting has been going on for CF_MAPVOTE_DURATION(_DECIDER) seconds or // if everyone's voted, decide winner or create decider vote - if (((time - vote_started) >= CF_MAPVOTE_DURATION || Vote_GetVoteCount() == TeamFortress_GetNoPlayers()) + if ((((!vote_decider && time >= decidertime) || (vote_decider && time >= closetime)) + || Vote_GetVoteCount() == TeamFortress_GetNoPlayers()) && vote_result == string_null) { + //dprint("[", ftos(time), "/cf/mapvote/check]: dropping losers.\n"); + Vote_DropLosers(); + // get winners/tied winners count if (!vote_winnercount) vote_winnercount = Vote_GetWinnerCount(); // create decider vote if there are more 2 or more winners if (!vote_decider && vote_winnercount >= 2 && Vote_GetWinnerVoteCount() < TeamFortress_GetNoPlayers()) { - //dprint("[cf/mapvote/check]: setting up decider map vote.\n"); + //dprint("[", ftos(time), "/cf/mapvote/check]: setting up decider map vote.\n"); Vote_SetupVote(1); // 1 = decider vote if (!vote_abort) { bprint(PRINT_HIGH, "A winner could not be decided. Vote options have been updated.\n"); - //dprint("[cf/mapvote/check]: opening decider map vote.\n"); - Vote_MenuOpen(); + //dprint("[", ftos(time), "/cf/mapvote/check]: opening decider map vote.\n"); + Vote_MenuOpen(0); } return; } @@ -166,8 +184,8 @@ void () Vote_Check = { Vote_MenuClose(); // close all open map votes // get the winner of the vote - vote_result = strzone(Vote_GetWinner()); - //dprint("[cf/mapvote/check]: next map will be ", vote_result, "\n"); + vote_result = Vote_GetWinner(); // returns a strzoned string + //dprint("[", ftos(time), "/cf/mapvote/check]: next map will be ", vote_result, "\n"); // release map names from memory Vote_ResetMapNames(); @@ -188,9 +206,9 @@ void (float pf_decider) Vote_SetupVote = { s_maplist = Vote_GetMapList(); // returns a strzoned string } else { vote_decider = 1; + s_maplist = Vote_GetWinnerList(); // returns a strzoned string Vote_ResetVotes(); - s_maplist = strzone(Vote_GetWinnerList()); - //dprint("[cf/mapvote/setupvote]: decider votelist: ", s_maplist, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/setupvote]: decider votelist: ", s_maplist, "\n"); } vote_started = time; @@ -199,7 +217,7 @@ void (float pf_decider) Vote_SetupVote = { strunzone(s_maplist); if (vote1_map == string_null) { - //dprint("[cf/mapvote/setupvote]: no maps found. aborting.\n"); + //dprint("[", ftos(time), "/cf/mapvote/setupvote]: no maps found. aborting.\n"); vote_result = mapname; vote_abort = 1; return; @@ -253,29 +271,49 @@ void (float pf_input) Vote_Input = { // update menu for all players (with active menus) on input if (pf_input >= 1 && pf_input <= 5) { - //dprint("[cf/mapvote/voteinput]: ", self.netname, " voted for ", s_votedfor, ".\n"); + //dprint("[", ftos(time), "/cf/mapvote/voteinput]: ", self.netname, " voted for ", s_votedfor, ".\n"); sprint(self, PRINT_HIGH, "You voted for ", s_votedfor, "\n"); self.has_voted_map = pf_input; - if ((time - self.spawn_time) <= CF_MAPVOTE_FORCESHOW) + if ((time - self.menu_time) <= CF_MAPVOTE_FORCESHOW) Vote_Menu(self); - Vote_MenuOpen(); // update + Vote_MenuOpen(0); // update } else Vote_Menu(self); }; // opens map vote menu for newly spawned players who haven't voted yet // called from Vote_Input(), Vote_Check() -void () Vote_MenuOpen = { +void (float force) Vote_MenuOpen = { + local float closetime = timelimit - CF_MAPVOTE_FINISH; + local float decidertime_force = closetime - CF_MAPVOTE_FORCESHOW; + local float decidertime = closetime - CF_MAPVOTE_DURATION_DECIDER; + local float votetime_force = decidertime - CF_MAPVOTE_FORCESHOW; local entity e_player = find(world, classname, "player"); while (e_player != world) { - if (e_player.team_no != 0 && e_player.playerclass != 0) { - if (!e_player.has_voted_map) { - if ((time - e_player.spawn_time) <= CF_MAPVOTE_FORCESHOW) { - if (!e_player.menu_time) { - //dprint("[cf/mapvote/menuopen]: open vote menu for newly spawned ", e_player.netname, ".\n"); + if (e_player.team_no && e_player.playerclass) { + if (!e_player.has_voted_map && e_player.health) { + if (((time - e_player.spawn_time) <= CF_MAPVOTE_FORCESHOW || (time - e_player.menu_time) <= CF_MAPVOTE_FORCESHOW) + && !force) { + //dprint("[", ftos(time), "/cf/mapvote/menuopen]: open vote menu for newly spawned ", e_player.netname, ".\n"); + if (e_player.menu_time < (time - CF_MAPVOTE_FORCESHOW)) e_player.menu_time = time; + Vote_Menu(e_player); + } else if (force == 1) { + if (e_player.menu_input != Vote_Input) { + //dprint("[", ftos(time), "/cf/mapvote/menuopen]: forcing vote menu on ", e_player.netname, ".\n"); + sprint(e_player, PRINT_HIGH, "You haven't voted yet, please vote\n"); } + if (e_player.menu_time < (time - CF_MAPVOTE_FORCESHOW) && e_player.menu_time < votetime_force) + e_player.menu_time = time; + Vote_Menu(e_player); + } else if (force == 2) { + if (e_player.menu_input != Vote_Input) { + //dprint("[", ftos(time), "/cf/mapvote/menuopen]: forcing decider vote menu on ", e_player.netname, ".\n"); + sprint(e_player, PRINT_HIGH, "You haven't voted yet, please vote\n"); + } + if (e_player.menu_time < (time - CF_MAPVOTE_FORCESHOW) && e_player.menu_time < decidertime_force) + e_player.menu_time = time; Vote_Menu(e_player); } } else if (e_player.menu_input == Vote_Input && (time - e_player.menu_time) <= CF_MAPVOTE_FORCESHOW) @@ -285,19 +323,18 @@ void () Vote_MenuOpen = { } }; -// closes map vote menu for anyone who's been alive >CF_MAPVOTE_FORCESHOW seconds +// closes map vote menu when vote is over or for anyone who's been alive >CF_MAPVOTE_FORCESHOW seconds // called from Vote_Check() void () Vote_MenuClose = { local entity e_player = find(world, classname, "player"); while (e_player != world) { if (vote_started == -1 && e_player.menu_input == Vote_Input) { - //dprint("[cf/mapvote/menuclose]: vote over, closing vote menu for ", e_player.netname, ".\n"); + //dprint("[", ftos(time), "/cf/mapvote/menuclose]: vote over, closing vote menu for ", e_player.netname, ".\n"); Menu_Close(e_player); - } - else if (e_player.menu_input == Vote_Input && (time - e_player.spawn_time) > CF_MAPVOTE_FORCESHOW) { + } else if (e_player.menu_input == Vote_Input && (time - e_player.menu_time) > CF_MAPVOTE_FORCESHOW) { if ((time - e_player.menu_time) > CF_MAPVOTE_FORCESHOW) { - //dprint("[cf/mapvote/menuclose]: closing vote menu for ", e_player.netname, ".\n"); + //dprint("[", ftos(time), "/cf/mapvote/menuclose]: closing vote menu for ", e_player.netname, ".\n"); e_player.menu_time = 0; Menu_Close(e_player); } @@ -310,77 +347,98 @@ void () Vote_MenuClose = { // called from Vote_Input(), Menu_Open() void (entity pe_player) Vote_Menu = { local string s_choose, s_vote1, s_vote2, s_vote3, s_vote4, s_vote5; - local float f_width, f_timeleft; - - f_timeleft = CF_MAPVOTE_FORCESHOW - (time - pe_player.spawn_time); - - s_choose = strcat("It's time to choose (closes in ", strcat(ftos(ceil(f_timeleft)), "s):\n\n")); - s_vote1 = ""; - s_vote2 = ""; - s_vote3 = ""; - s_vote4 = ""; - s_vote5 = ""; - f_width = strlen(s_vote1); + local string s_tmp1, s_tmp2, s_tmp3, s_tmp4, s_tmp5; + local float f_width = 0, f_timeleft = 0; + local float closetime = timelimit - CF_MAPVOTE_FINISH; + local float decidertime_force = closetime - CF_MAPVOTE_FORCESHOW; + local float decidertime = closetime - CF_MAPVOTE_DURATION_DECIDER; + local float votetime_force = decidertime - CF_MAPVOTE_FORCESHOW; + local float votetime = decidertime - CF_MAPVOTE_DURATION; + + if ((time < closetime && (pe_player.menu_time + CF_MAPVOTE_FORCESHOW) >= decidertime_force) + || (time < decidertime_force && (pe_player.menu_time + CF_MAPVOTE_FORCESHOW) >= decidertime_force)) + f_timeleft = closetime - time; + else if ((time < decidertime && (pe_player.menu_time + CF_MAPVOTE_FORCESHOW) >= decidertime) + || (time < votetime_force && (pe_player.menu_time + CF_MAPVOTE_FORCESHOW) >= votetime_force)) + f_timeleft = decidertime - time; + else if ((time >= decidertime && time < closetime) || (time >= votetime && time < decidertime)) + f_timeleft = CF_MAPVOTE_FORCESHOW - (time - pe_player.menu_time); + else if (time - pe_player.menu_time < CF_MAPVOTE_FORCESHOW) + f_timeleft = CF_MAPVOTE_FORCESHOW - (time - pe_player.menu_time); + + s_choose = strzone(strcat("Vote for next map (closes in ", strcat(ftos(floor(f_timeleft - 0.1)), "s):\n\n"))); + s_tmp1 = strzone(""); + s_tmp2 = strzone(""); + s_tmp3 = strzone(""); + s_tmp4 = strzone(""); + s_tmp5 = strzone(""); if (vote1_map != string_null) { - s_vote1 = strcat("“‘ ", vote1_map); + strunzone(s_tmp1); + s_tmp1 = strcat("“‘ ", vote1_map); if (vote1_cnt) - s_vote1 = strcat(s_vote1, strcat(" (", strcat(ftos(vote1_cnt), " votes)"))); + s_tmp1 = strzone(strcat(s_tmp1, strcat(" (", strcat(ftos(vote1_cnt), " votes)")))); else - s_vote1 = strcat(s_vote1, " "); + s_tmp1 = strzone(strcat(s_tmp1, " ")); - if (strlen(s_vote1) > f_width) f_width = strlen(s_vote1); + if (strlen(s_tmp1) > f_width) f_width = strlen(s_tmp1); } if (vote2_map != string_null) { - s_vote2 = strcat("”‘ ", vote2_map); + strunzone(s_tmp2); + s_tmp2 = strcat("”‘ ", vote2_map); if (vote2_cnt) - s_vote2 = strcat(s_vote2, strcat(" (", strcat(ftos(vote2_cnt), " votes)"))); + s_tmp2 = strzone(strcat(s_tmp2, strcat(" (", strcat(ftos(vote2_cnt), " votes)")))); else - s_vote2 = strcat(s_vote2, " "); + s_tmp2 = strzone(strcat(s_tmp2, " ")); - if (strlen(s_vote2) > f_width) f_width = strlen(s_vote2); + if (strlen(s_tmp2) > f_width) f_width = strlen(s_tmp2); } if (vote3_map != string_null) { + strunzone(s_tmp3); if (!vote_decider || vote3_cnt) - s_vote3 = strcat("•‘ ", vote3_map); + s_tmp3 = strcat("•‘ ", vote3_map); if (vote3_cnt) - s_vote3 = strcat(s_vote3, strcat(" (", strcat(ftos(vote3_cnt), " votes)"))); + s_tmp3 = strzone(strcat(s_tmp3, strcat(" (", strcat(ftos(vote3_cnt), " votes)")))); else - s_vote3 = strcat(s_vote3, " "); + s_tmp3 = strzone(strcat(s_tmp3, " ")); - if (strlen(s_vote3) > f_width) f_width = strlen(s_vote3); + if (strlen(s_tmp3) > f_width) f_width = strlen(s_tmp3); } if (vote4_map != string_null) { + strunzone(s_tmp4); if (!vote_decider || vote4_cnt) - s_vote4 = strcat("–‘ ", vote4_map); + s_tmp4 = strcat("–‘ ", vote4_map); if (vote4_cnt) - s_vote4 = strcat(s_vote4, strcat(" (", strcat(ftos(vote4_cnt), " votes)"))); + s_tmp4 = strzone(strcat(s_tmp4, strcat(" (", strcat(ftos(vote4_cnt), " votes)")))); else - s_vote4 = strcat(s_vote4, " "); + s_tmp4 = strzone(strcat(s_tmp4, " ")); - if (strlen(s_vote4) > f_width) f_width = strlen(s_vote4); + if (strlen(s_tmp4) > f_width) f_width = strlen(s_tmp4); } if (vote5_map != string_null) { + strunzone(s_tmp5); if (!vote_decider || vote5_cnt) - s_vote5 = strcat("—‘ ", vote5_map); + s_tmp5 = strcat("—‘ ", vote5_map); if (vote5_cnt) - s_vote5 = strcat(s_vote5, strcat(" (", strcat(ftos(vote5_cnt), " votes)"))); + s_tmp5 = strzone(strcat(s_tmp5, strcat(" (", strcat(ftos(vote5_cnt), " votes)")))); else - s_vote5 = strcat(s_vote5, " "); + s_tmp5 = strzone(strcat(s_tmp5, " ")); - if (strlen(s_vote5) > f_width) f_width = strlen(s_vote5); + if (strlen(s_tmp5) > f_width) f_width = strlen(s_tmp5); } - s_vote1 = strpadr(s_vote1, f_width); - s_vote2 = strpadr(s_vote2, f_width); - s_vote3 = strpadr(s_vote3, f_width); - s_vote4 = strpadr(s_vote4, f_width); - s_vote5 = strpadr(s_vote5, f_width); + s_vote1 = strzone(strpadr(s_tmp1, f_width)); + s_vote2 = strzone(strpadr(s_tmp2, f_width)); + s_vote3 = strzone(strpadr(s_tmp3, f_width)); + s_vote4 = strzone(strpadr(s_tmp4, f_width)); + s_vote5 = strzone(strpadr(s_tmp5, f_width)); Status_Menu(pe_player, Vote_Input, s_choose, s_vote1, "\n", s_vote2, "\n", s_vote3, "\n", s_vote4, "\n\n", s_vote5, "\n"); + strunzone(s_choose); strunzone(s_vote1); strunzone(s_vote2); strunzone(s_vote3); strunzone(s_vote4); strunzone(s_vote5); + strunzone(s_tmp1); strunzone(s_tmp2); strunzone(s_tmp3); strunzone(s_tmp4); strunzone(s_tmp5); }; -// removes a vote (if a user changes his mind during first 3 seconds) +// removes a vote (if a user changes his mind) // called from Vote_Input() void (float pf_input) Vote_RemoveVote = { local string s_map = ""; @@ -402,7 +460,7 @@ void (float pf_input) Vote_RemoveVote = { s_map = vote5_map; } - //dprint("[cf/mapvote/removevote]: removing vote from ", s_map, ".\n"); + //dprint("[", ftos(time), "/cf/mapvote/removevote]: removing vote from ", s_map, ".\n"); }; // returns a list of maps from config @@ -412,49 +470,49 @@ string () Vote_GetMapList = { local string s_maplist, s_maplist1, s_maplist2, s_maplist3, s_maplist4; if (f_players <= 2) { - //dprint("[cf/mapvote/getmaplist]: using tiny votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using tiny votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_tiny1"), " "); s_maplist2 = strcat(infokey(world, "votelist_tiny2"), " "); s_maplist3 = strcat(infokey(world, "votelist_tiny3"), " "); s_maplist4 = strcat(infokey(world, "votelist_tiny4"), " "); } else if (f_players <= 4) { - //dprint("[cf/mapvote/getmaplist]: using small votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using small votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_small1"), " "); s_maplist2 = strcat(infokey(world, "votelist_small2"), " "); s_maplist3 = strcat(infokey(world, "votelist_small3"), " "); s_maplist4 = strcat(infokey(world, "votelist_small4"), " "); } else if (f_players <= 6) { - //dprint("[cf/mapvote/getmaplist]: using medium votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using medium votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_medium1"), " "); s_maplist2 = strcat(infokey(world, "votelist_medium2"), " "); s_maplist3 = strcat(infokey(world, "votelist_medium3"), " "); s_maplist4 = strcat(infokey(world, "votelist_medium4"), " "); } else if (f_players <= 8) { - //dprint("[cf/mapvote/getmaplist]: using large votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using large votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_large1"), " "); s_maplist2 = strcat(infokey(world, "votelist_large2"), " "); s_maplist3 = strcat(infokey(world, "votelist_large3"), " "); s_maplist4 = strcat(infokey(world, "votelist_large4"), " "); } else if (f_players <= 12) { - //dprint("[cf/mapvote/getmaplist]: using xlarge votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xlarge votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_xlarge1"), " "); s_maplist2 = strcat(infokey(world, "votelist_xlarge2"), " "); s_maplist3 = strcat(infokey(world, "votelist_xlarge3"), " "); s_maplist4 = strcat(infokey(world, "votelist_xlarge4"), " "); } else if (f_players <= 14) { - //dprint("[cf/mapvote/getmaplist]: using xxl votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xxl votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_xxl1"), " "); s_maplist2 = strcat(infokey(world, "votelist_xxl2"), " "); s_maplist3 = strcat(infokey(world, "votelist_xxl3"), " "); s_maplist4 = strcat(infokey(world, "votelist_xxl4"), " "); } else if (f_players <= 16) { - //dprint("[cf/mapvote/getmaplist]: using xxxl votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xxxl votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_xxxl1"), " "); s_maplist2 = strcat(infokey(world, "votelist_xxxl2"), " "); s_maplist3 = strcat(infokey(world, "votelist_xxxl3"), " "); s_maplist4 = strcat(infokey(world, "votelist_xxxl4"), " "); } else { - //dprint("[cf/mapvote/getmaplist]: using xxxxl votelist.\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xxxxl votelist.\n"); s_maplist1 = strcat(infokey(world, "votelist_xxxxl1"), " "); s_maplist2 = strcat(infokey(world, "votelist_xxxxl2"), " "); s_maplist3 = strcat(infokey(world, "votelist_xxxxl3"), " "); @@ -463,7 +521,7 @@ string () Vote_GetMapList = { s_maplist = strzone(strcat(s_maplist1, strcat(s_maplist2, strcat(s_maplist3, s_maplist4)))); - //dprint("[cf/mapvote/getmaplist]: votelist: ", s_maplist, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: votelist: ", s_maplist, "\n"); return s_maplist; }; @@ -473,32 +531,35 @@ void (string ps_maplist) Vote_PopulateVoteList = { local float f_count, i; local string s_maplist; - s_maplist = Vote_StripMap(mapname, ps_maplist); // strip current map from votelist + s_maplist = Vote_StripMap(mapname, ps_maplist); // strip current map from votelist, returns a strzoned string f_count = List_Count(s_maplist); - for (i = 0; i < 5; i++) { + for (i = 0; i < 4; i++) { local float f_next = RandomRange(0, f_count - 1); - local string s_map = strzone(List_Index(s_maplist, f_next)); + local string s_map = List_Index(s_maplist, f_next); // returns a strzoned string if (i == 0) { vote1_map = s_map; - //dprint("[cf/mapvote/populatevotelist]: adding map1: ", vote1_map, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map1: ", vote1_map, "\n"); } else if (i == 1) { vote2_map = s_map; - //dprint("[cf/mapvote/populatevotelist]: adding map2: ", vote2_map, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map2: ", vote2_map, "\n"); } else if (i == 2) { vote3_map = s_map; - //dprint("[cf/mapvote/populatevotelist]: adding map3: ", vote3_map, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map3: ", vote3_map, "\n"); } else if (i == 3) { vote4_map = s_map; - //dprint("[cf/mapvote/populatevotelist]: adding map4: ", vote4_map, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map4: ", vote4_map, "\n"); } - s_maplist = Vote_StripMap(s_map, s_maplist); + local string s_tmp = s_maplist; + s_maplist = Vote_StripMap(s_map, s_maplist); // returns a strzoned string f_count = List_Count(s_maplist); + strunzone(s_tmp); } vote5_map = strzone(mapname); - //dprint("[cf/mapvote/populatevotelist]: adding map5: ", vote5_map, "\n"); + strunzone(s_maplist); + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map5: ", vote5_map, "\n"); }; // strips a map from a given list of maps @@ -513,12 +574,13 @@ string (string ps_map, string ps_maplist) Vote_StripMap = { // remove current map from list, strzone hack needed because limited string buffer s_tmp = strzone(""); for (i = 0; i < f_count; i++) { - if (List_Index(s_maplist, i) != ps_map) { + local string map = List_Index(s_maplist, i); // returns a strzoned string + if (map != ps_map) { local string tmp_old = s_tmp; - local string map = List_Index(s_maplist, i); s_tmp = strzone(strcat(s_tmp, strcat(map, " "))); strunzone(tmp_old); } + strunzone(map); } return s_tmp; @@ -554,7 +616,7 @@ void () Vote_ResetVotes = { // resets map names // called from Vote_Check(), Vote_Reset() void () Vote_ResetMapNames = { - //dprint("[cf/mapvote/resetmapnames]: resetting map names.\n"); + //dprint("[", ftos(time), "/cf/mapvote/resetmapnames]: resetting map names.\n"); if (vote1_map != string_null) { strunzone(vote1_map); vote1_map = string_null; } if (vote2_map != string_null) { strunzone(vote2_map); vote2_map = string_null; } @@ -574,8 +636,6 @@ float () Vote_GetVoteCount = { float () Vote_GetWinnerCount = { local float f_count; - Vote_DropLosers(); - f_count = 0; if (vote1_cnt) f_count = f_count + 1; if (vote2_cnt) f_count = f_count + 1; @@ -591,8 +651,6 @@ float () Vote_GetWinnerCount = { float () Vote_GetWinnerVoteCount = { local float f_count; - Vote_DropLosers(); - f_count = 0; if (vote1_cnt) f_count = f_count + vote1_cnt; if (vote2_cnt) f_count = f_count + vote2_cnt; @@ -608,15 +666,12 @@ float () Vote_GetWinnerVoteCount = { string () Vote_GetWinner = { local string s_maplist, s_result; - //dprint("[cf/mapvote/getwinner]: dropping losers.\n"); - Vote_DropLosers(); - s_maplist = Vote_GetWinnerList(); if (s_maplist != string_null) - s_result = Vote_RandomWinner(s_maplist); + s_result = Vote_RandomWinner(s_maplist); // returns a strzoned string else - s_result = Vote_RandomMap(); + s_result = Vote_RandomMap(); // returns a strzoned string return s_result; }; @@ -626,16 +681,34 @@ string () Vote_GetWinner = { string () Vote_GetWinnerList = { local string s_maplist; - Vote_DropLosers(); - - s_maplist = ""; - if (vote1_cnt) s_maplist = strcat(s_maplist, strcat(vote1_map, " ")); - if (vote2_cnt) s_maplist = strcat(s_maplist, strcat(vote2_map, " ")); - if (vote3_cnt) s_maplist = strcat(s_maplist, strcat(vote3_map, " ")); - if (vote4_cnt) s_maplist = strcat(s_maplist, strcat(vote4_map, " ")); - if (vote5_cnt) s_maplist = strcat(s_maplist, vote5_map); + s_maplist = strzone(""); + if (vote1_cnt) { + local string s_tmp = s_maplist; + s_maplist = strzone(strcat(s_maplist, strcat(vote1_map, " "))); + strunzone(s_tmp); + } + if (vote2_cnt) { + local string s_tmp = s_maplist; + s_maplist = strzone(strcat(s_maplist, strcat(vote2_map, " "))); + strunzone(s_tmp); + } + if (vote3_cnt) { + local string s_tmp = s_maplist; + s_maplist = strzone(strcat(s_maplist, strcat(vote3_map, " "))); + strunzone(s_tmp); + } + if (vote4_cnt) { + local string s_tmp = s_maplist; + s_maplist = strzone(strcat(s_maplist, strcat(vote4_map, " "))); + strunzone(s_tmp); + } + if (vote5_cnt) { + local string s_tmp = s_maplist; + s_maplist = strzone(strcat(s_maplist, vote5_map)); + strunzone(s_tmp); + } - //dprint("[cf/mapvote/getwinnerlist]: winner list: ", s_maplist, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/getwinnerlist]: winner list: ", s_maplist, "\n"); return s_maplist; }; @@ -647,9 +720,9 @@ string (string ps_maplist) Vote_RandomWinner = { f_count = List_Count(ps_maplist) - 1; f_idx = RandomRange(0, f_count); - s_winner = List_Index(ps_maplist, f_idx); + s_winner = List_Index(ps_maplist, f_idx); // returns a strzoned string - //dprint("[cf/mapvote/randomwinner]: random winner: ", s_winner, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/randomwinner]: random winner: ", s_winner, "\n"); return s_winner; }; @@ -662,10 +735,10 @@ string () Vote_RandomMap = { s_maplist = Vote_GetMapList(); // returns a strzoned string f_count = List_Count(s_maplist) - 1; f_idx = RandomRange(0, f_count); - s_map = List_Index(s_maplist, f_idx); + s_map = List_Index(s_maplist, f_idx); // returns a strzoned string strunzone(s_maplist); - //dprint("[cf/mapvote/randommap]: drew random map: ", s_map, "\n"); + //dprint("[", ftos(time), "/cf/mapvote/randommap]: drew random map: ", s_map, "\n"); return s_map; }; @@ -733,16 +806,15 @@ string (string ps_list, float pf_idx) List_Index = { } // empty space => end of word - if (s_current == " " && f_start > -1) { - return substr(ps_list, f_start, i - f_start); - } + if (s_current == " " && f_start > -1) + return strzone(substr(ps_list, f_start, i - f_start)); s_previous = s_current; } // if f_start is set it means a list item was found if (f_start > -1) - return substr(ps_list, f_start, i - f_start); + return strzone(substr(ps_list, f_start, i - f_start)); - return string_null; + return strzone(string_null); }; \ No newline at end of file From 6a5bef1e1ba380845250aa5cd174fea04471c191 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 22:58:07 +0200 Subject: [PATCH 0099/2474] Fix HWGuy movement bug (fixes #99) --- weapons.qc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/weapons.qc b/weapons.qc index c74589d5..16f5d58e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2397,14 +2397,16 @@ void () W_WeaponFrame = { if (self.impulse != 0 && self.has_disconnected == 0) ImpulseCommands(); - if ((!self.button0 && self.fire_held_down) && + if ((self.button0 && self.fire_held_down) && + (self.current_weapon == WEAP_ASSAULT_CANNON)) { + player_assaultcannonup1(); + } else if ((!self.button0 && self.fire_held_down) && (self.current_weapon == WEAP_ASSAULT_CANNON)) { self.fire_held_down = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); TeamFortress_SetSpeed(self); player_run(); - } - if (self.button0 && !self.fire_held_down) { + } else if (self.button0 && !self.fire_held_down) { if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) From 7516993b961b3bd041b4b141f759620282632753 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 4 Aug 2014 23:01:06 +0200 Subject: [PATCH 0100/2474] Improve missing cell error message for HWGuy --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 16f5d58e..83b3f813 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1705,7 +1705,7 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { if (self.ammo_cells < 7) sprint(self, PRINT_MEDIUM, - "Insufficient cells to power up the assault cannon\n"); + "Not enough cells to power up the Assault Cannon\n"); else { self.ammo_cells = self.ammo_cells - 7; self.heat = 1; From adab6d00048f8052cf7714702ec1967583e066c0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 08:13:23 +0200 Subject: [PATCH 0101/2474] Stop spamming detpack messages when weapon is on cooldown (fixes #89) --- demoman.qc | 10 ++++++++-- qw.qc | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/demoman.qc b/demoman.qc index f1472a5e..0b83897f 100644 --- a/demoman.qc +++ b/demoman.qc @@ -98,14 +98,20 @@ void () TeamFortress_DetpackMenu = { local entity detpack; if (self.ammo_detpack <= 0) { - sprint(self, PRINT_HIGH, "You do not have any detpacks left\n"); + if (time >= self.antispam_detpack) { + sprint(self, PRINT_HIGH, "You do not have any detpacks left\n"); + self.antispam_detpack = time + 3; + } return; } detpack = find(world, classname, "detpack"); while (detpack) { if (detpack.owner == self) { - sprint(self, PRINT_HIGH, "You can only have one detpack active at a time\n"); + if (time >= self.antispam_detpack) { + sprint(self, PRINT_HIGH, "You can only have one detpack active at a time\n"); + self.antispam_detpack = time + 3; + } return; } detpack = find(detpack, classname, "detpack"); diff --git a/qw.qc b/qw.qc index da365e3a..4aadf70a 100644 --- a/qw.qc +++ b/qw.qc @@ -341,7 +341,7 @@ float already_chosen_map; .float nailpos; // anti spam -.float antispam_cannon_air; // message shown while trying to fire assault cannon while in the air +.float antispam_detpack; // don't spam detpack messages // status bar stuff .string StatusString; // current centerprint text (strzone'd!) From c1718b6ff512494262b7f39cc346d8681e25c469 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 08:13:51 +0200 Subject: [PATCH 0102/2474] Reset menu timeout when spawning (fixes #100) --- tfort.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tfort.qc b/tfort.qc index b2e3b35a..352be144 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1367,6 +1367,7 @@ void () TeamFortress_SetEquipment = { self.disguise_team = 0; self.detpack_left = 0; self.fragstreak = 0; + self.menu_time = 0; self.ammo_medikit = 0; self.maxammo_medikit = 0; From c496d5de643782f65208a2d1535fac064a615d56 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 08:48:55 +0200 Subject: [PATCH 0103/2474] Add drop flag message to /dropflag (fixes #88) --- tfortmap.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tfortmap.qc b/tfortmap.qc index ca8227db..15bdca4c 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2555,6 +2555,12 @@ void () DropGoalItems = { if (te.owner == self) { tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); + if (self.team_no == 1) + bprint(PRINT_HIGH, self.netname, " δςοππεδ ςεδ§σ ζμαη\n"); + else if (self.team_no == 2) + bprint(PRINT_HIGH, self.netname, " δςοππεδ βμυε§σ ζμαη\n"); + else + bprint(PRINT_HIGH, self.netname, " δςοππεδ τθε εξενω§σ ζμαη\n"); } te = find(te, classname, "item_tfgoal"); } From b479b336f96cf26834b07fe79d375ce190e141df Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 09:06:02 +0200 Subject: [PATCH 0104/2474] Allow /votenext and /forcenext while dead --- client.qc | 9 +++++++++ weapons.qc | 5 ----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 481b1836..88454f6e 100644 --- a/client.qc +++ b/client.qc @@ -1407,6 +1407,15 @@ void () CheckWaterJump = { }; void () PlayerPreThink = { + if (self.impulse == TF_VOTENEXT) { + Vote_NextMap(self); + self.impulse = 0; + } + else if (self.impulse == TF_FORCENEXT) { + Vote_ForceNext(self); + self.impulse = 0; + } + if (self.is_feigning && (self.waterlevel == 1)) { self.watertype = -3; self.waterlevel = 3; diff --git a/weapons.qc b/weapons.qc index 83b3f813..f3f1d84a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2051,11 +2051,6 @@ void () PreMatchImpulses; void () DeadImpulses; void () ImpulseCommands = { - if (self.impulse == TF_VOTENEXT) - Vote_NextMap(self); - else if (self.impulse == TF_FORCENEXT) - Vote_ForceNext(self); - if ((self.last_impulse == TF_DETPACK) && self.impulse) TeamFortress_SetDetpack(self.impulse); From 459432250f260d6032c9263e9caeb98b5bd300cb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 09:12:57 +0200 Subject: [PATCH 0105/2474] Add votes left message and only count active players (closes #91) --- tforttm.qc | 16 ++++++++++++++++ vote.qc | 28 ++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/tforttm.qc b/tforttm.qc index 85eb8b64..e4dbf67e 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -433,6 +433,22 @@ float () TeamFortress_GetNoPlayers = { return (nump); }; +float () TeamFortress_GetNoActivePlayers = { + local float nump; + local entity search; + nump = 0; + + search = find(world, classname, "player"); + while (search != world) { + if (search.netname != string_null) { + if (search.team_no && search.playerclass) + nump = nump + 1; + } + search = find(search, classname, "player"); + } + return (nump); +}; + float (float tno) TeamFortress_TeamGetMaxPlayers = { if (tno == 1) return (team1maxplayers); diff --git a/vote.qc b/vote.qc index ccc0c6f9..67f96b0c 100644 --- a/vote.qc +++ b/vote.qc @@ -3,6 +3,7 @@ // Displays a vote menu during the last few minutes of gameplay on a map. // functions by order of appearance +float () TeamFortress_GetNoActivePlayers; void (entity pe_player) Vote_NextMap; float () Vote_GetNextVotes; void (entity pe_player) Vote_ForceNext; @@ -41,7 +42,7 @@ float vote_started, vote_update, vote_winnercount, vote_decider, vote_abort; // opens the map voting early // called from weapons.qc:ImpulseCommands() void (entity pe_player) Vote_NextMap = { - local float f_votes, f_votes_needed; + local float f_votes, f_votes_needed, f_votes_left; if (!pe_player.team_no || !pe_player.playerclass) return; @@ -55,11 +56,17 @@ void (entity pe_player) Vote_NextMap = { bprint(PRINT_HIGH, pe_player.netname, " wants to start voting for next map\n"); f_votes = Vote_GetNextVotes(); - f_votes_needed = floor(TeamFortress_GetNoPlayers() / 2); + f_votes_needed = ceil(TeamFortress_GetNoActivePlayers() / 2); + f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(0); //dprint("[", ftos(time), "/cf/mapvote/votenext]: forcing map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for next map\n"); + } else { + if (f_votes_left == 1) + bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed\n"); + else + bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed\n"); } }; @@ -82,7 +89,10 @@ float () Vote_GetNextVotes = { // forces server to change map to next map // called from weapons.qc:ImpulseCommands() void (entity pe_player) Vote_ForceNext = { - local float f_votes, f_votes_needed; + local float f_votes, f_votes_needed, f_votes_left; + + if (!pe_player.team_no || !pe_player.playerclass) + return; if (vote_result == string_null) { sprint(pe_player, PRINT_HIGH, "You can't force next map before voting for a new map. Use /votenext to issue a map vote.\n"); @@ -94,12 +104,18 @@ void (entity pe_player) Vote_ForceNext = { bprint(PRINT_HIGH, pe_player.netname, " wants to start playing ", vote_result, " now\n"); f_votes = Vote_GetForceNextVotes(); - f_votes_needed = ceil(TeamFortress_GetNoPlayers() / 2); + f_votes_needed = ceil(TeamFortress_GetNoActivePlayers() / 2); + f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(0); //dprint("[", ftos(time), "/cf/mapvote/forcenext]: forcing next map: ", vote_result, "\n"); bprint(PRINT_HIGH, "Changing level to ", vote_result, "\n"); GotoNextMap(); + } else { + if (f_votes_left == 1) + bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed\n"); + else + bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed\n"); } }; @@ -158,7 +174,7 @@ void () Vote_Check = { // when voting has been going on for CF_MAPVOTE_DURATION(_DECIDER) seconds or // if everyone's voted, decide winner or create decider vote if ((((!vote_decider && time >= decidertime) || (vote_decider && time >= closetime)) - || Vote_GetVoteCount() == TeamFortress_GetNoPlayers()) + || Vote_GetVoteCount() == TeamFortress_GetNoActivePlayers()) && vote_result == string_null) { //dprint("[", ftos(time), "/cf/mapvote/check]: dropping losers.\n"); @@ -169,7 +185,7 @@ void () Vote_Check = { vote_winnercount = Vote_GetWinnerCount(); // create decider vote if there are more 2 or more winners - if (!vote_decider && vote_winnercount >= 2 && Vote_GetWinnerVoteCount() < TeamFortress_GetNoPlayers()) { + if (!vote_decider && vote_winnercount >= 2 && Vote_GetWinnerVoteCount() < TeamFortress_GetNoActivePlayers()) { //dprint("[", ftos(time), "/cf/mapvote/check]: setting up decider map vote.\n"); Vote_SetupVote(1); // 1 = decider vote if (!vote_abort) { From b896ec14a2dcc4185b6e4589796242f066c2fa2a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 11:09:55 +0200 Subject: [PATCH 0106/2474] Add dropped flag centerprints for team/enemy --- tfortmap.qc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index 15bdca4c..f11e4718 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2544,7 +2544,7 @@ void (entity P) ForceRespawn = { }; void () DropGoalItems = { - local entity te; + local entity te, search; newmis = spawn(); makevectors(self.v_angle); @@ -2561,6 +2561,18 @@ void () DropGoalItems = { bprint(PRINT_HIGH, self.netname, " δςοππεδ βμυε§σ ζμαη\n"); else bprint(PRINT_HIGH, self.netname, " δςοππεδ τθε εξενω§σ ζμαη\n"); + + Status_Print(self, "\n\n\n", "You dropped the flag!"); + search = find(world, classname, "player"); + while (search) { + if ((search.team_no == self.team_no) && (self.team_no != 0)) { + if (search != self) + Status_Print(search, "\n\n\n", self.netname, " dropped the enemy flag!"); + } else { + Status_Print(search, "\n\n\n", "The enemy dropped your flag!"); + } + search = find(search, classname, "player"); + } } te = find(te, classname, "item_tfgoal"); } From c4c65fd7cebf7892a0f236e82b4721a79255072f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 16:04:01 +0200 Subject: [PATCH 0107/2474] Add Sniper Rifle reload (closes #96) --- actions.qc | 39 +++++++++++++++++++++++++++++++++++++++ client.qc | 6 ++++++ defs.h | 1 + qw.qc | 1 + sniper.qc | 2 +- status.qc | 8 ++++++++ weapons.qc | 22 +++++++++++++++++++++- 7 files changed, 77 insertions(+), 2 deletions(-) diff --git a/actions.qc b/actions.qc index 01a909de..7ad37571 100644 --- a/actions.qc +++ b/actions.qc @@ -343,6 +343,45 @@ void () TeamFortress_ReloadCurrentWeapon = { } else { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } + } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { + if (self.ammo_shells == 0) { + sprint(self, PRINT_HIGH, "Out of shells\n"); + return; + } + if (self.reload_sniper_rifle == 0) { + sprint(self, PRINT_HIGH, "Clip full\n"); + return; + } + if ((16 - self.reload_sniper_rifle) == self.ammo_shells) { + sprint(self, PRINT_HIGH, "All shells are in the clip\n"); + return; + } + if (self.ammo_shells >= 1) { + if (self.reload_super_shotgun >= self.ammo_shells) + reloadamount = self.ammo_shells; + else + reloadamount = self.reload_sniper_rifle; + Attack_Finished(1.5); + self.reload_clipsize = (1 - reloadamount); + reloadtime = (1 - reloadamount) / 1; + reloadtime = 4 - (4 * reloadtime); + self.reload_sniper_rifle = 0; + if (self.ammo_shells < 1) { + self.reload_sniper_rifle = 1 - self.ammo_shells; + } + sprint(self, PRINT_HIGH, "Reloading...\n"); + self.tfstate = self.tfstate | TFSTATE_RELOADING; + Status_Refresh(self); + tWeapon = spawn(); + tWeapon.owner = self; + tWeapon.classname = "timer"; + tWeapon.nextthink = time + reloadtime; + tWeapon.think = W_Reload_sniper_rifle; + self.weaponmodel = ""; + self.weaponframe = 0; + } else { + sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); + } } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { if (self.ammo_rockets == 0) { sprint(self, PRINT_HIGH, "Out of grenades\n"); diff --git a/client.qc b/client.qc index 88454f6e..0fe06171 100644 --- a/client.qc +++ b/client.qc @@ -358,6 +358,12 @@ void () DecodeLevelParms = { else if (st == "off") invis_only = FALSE; + st = infokey(world, "sr"); + if (st == string_null) + st = infokey(world, "sniperreload"); + if (st != "off") + toggleflags = toggleflags | TFLAG_SNIPERRELOAD; + st = infokey(world, "rd"); if (st == string_null) st = infokey(world, "respawn_delay"); diff --git a/defs.h b/defs.h index 7e81b7ae..aea2c619 100644 --- a/defs.h +++ b/defs.h @@ -279,6 +279,7 @@ #define TFLAG_FULLTEAMSCORE 2048 #define TFLAG_FLAGEMU 4096 #define TFLAG_WARSTANDARD 8192 +#define TFLAG_SNIPERRELOAD 16384 // Sniper reload enabled #define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn #define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn diff --git a/qw.qc b/qw.qc index 4aadf70a..fe10a428 100644 --- a/qw.qc +++ b/qw.qc @@ -149,6 +149,7 @@ float coop; // variables used for reloading .float reload_shotgun; .float reload_super_shotgun; +.float reload_sniper_rifle; .float reload_grenade_launcher; .float reload_rocket_launcher; .float reload_tick; // how often the status bar should be refreshed during reload diff --git a/sniper.qc b/sniper.qc index bccca415..e3002350 100644 --- a/sniper.qc +++ b/sniper.qc @@ -147,7 +147,7 @@ void () SniperSight_Update = { void () SniperSight_Create = { local entity sight; - if (self.has_disconnected == TRUE) + if (self.has_disconnected == TRUE || (self.tfstate & TFSTATE_RELOADING)) return; self.tfstate = self.tfstate | TFSTATE_AIMING; diff --git a/status.qc b/status.qc index c329b815..b719d7a5 100644 --- a/status.qc +++ b/status.qc @@ -288,6 +288,12 @@ string(entity pl) ClipSizeToString = if ((max - pl.reload_super_shotgun) > pl.ammo_shells) pl.reload_super_shotgun = max - pl.ammo_shells; num = (max - pl.reload_super_shotgun); + } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { + if (!(toggleflags & TFLAG_SNIPERRELOAD)) + return (""); + if ((max - pl.reload_sniper_rifle) > pl.ammo_shells) + pl.reload_sniper_rifle = max - pl.ammo_shells; + num = (max - pl.reload_sniper_rifle); } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { if ((max - pl.reload_grenade_launcher) > pl.ammo_rockets) pl.reload_grenade_launcher = (max - pl.ammo_rockets); @@ -316,6 +322,8 @@ float(entity pl) GetClipSize = return 8; else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) return 16; + else if (pl.current_weapon == WEAP_SNIPER_RIFLE) + return 1; else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) return 6; else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) diff --git a/weapons.qc b/weapons.qc index f3f1d84a..39ca0bdf 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1552,6 +1552,14 @@ void () W_Reload_super_shotgun = { Status_Refresh(self.owner); }; +void () W_Reload_sniper_rifle = { + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); + self.owner.weaponmodel = "progs/v_srifle.mdl"; + sprint(self.owner, PRINT_LOW, "Finished reloading\n"); + dremove(self); + Status_Refresh(self.owner); +}; + void () W_Reload_grenade_launcher = { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_rock.mdl"; @@ -1579,6 +1587,11 @@ float () CheckForReload = { TeamFortress_ReloadCurrentWeapon(); return 1; } + } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { + if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && (toggleflags & TFLAG_SNIPERRELOAD)) { + TeamFortress_ReloadCurrentWeapon(); + return 1; + } } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) { TeamFortress_ReloadCurrentWeapon(); @@ -1694,8 +1707,15 @@ void () W_Attack = { sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.flags & FL_ONGROUND) { + if (CheckForReload() == TRUE) + return; player_shot1(); W_FireSniperRifle(); + if (toggleflags & TFLAG_SNIPERRELOAD) { + self.reload_sniper_rifle = self.reload_sniper_rifle + 1; + Status_Refresh(self); + CheckForReload(); + } Attack_Finished(1.5); } } else if (self.current_weapon == WEAP_AUTO_RIFLE) { @@ -2402,7 +2422,7 @@ void () W_WeaponFrame = { TeamFortress_SetSpeed(self); player_run(); } else if (self.button0 && !self.fire_held_down) { - if (self.current_weapon == WEAP_SNIPER_RIFLE) { + if (self.current_weapon == WEAP_SNIPER_RIFLE && !(self.tfstate & TFSTATE_RELOADING)) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) self.heat = self.heat + 3; From 17499f7d86bc842eb8cddef869ea99feadf17fbd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 5 Aug 2014 19:12:13 +0200 Subject: [PATCH 0108/2474] Fix caltrop canister pickup message (fixes #101) --- items.qc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/items.qc b/items.qc index fce23589..a5034468 100644 --- a/items.qc +++ b/items.qc @@ -815,9 +815,13 @@ float () GetGrenadePossibility = { } if ((other.tp_grenades_2 != 0) && (other.no_grenades_2 < maxg)) { other.no_grenades_2 = other.no_grenades_2 + 1; - sprint(other, 2, "You found a "); + sprint(other, PRINT_HIGH, "You found a "); PrintGrenadeType(other, other.tp_grenades_2); - sprint(other, 2, " grenade\n"); + if (other.tp_grenades_2 == GR_TYPE_CALTROP) { + sprint(other, PRINT_HIGH, " canister\n"); + } else { + sprint(other, PRINT_HIGH, " grenade\n"); + } return (1); } } From afcf74da89419eba1e50e1445d9bce26adc9b4bb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 6 Aug 2014 09:46:51 +0200 Subject: [PATCH 0109/2474] Improve W_GetSlot() function and add W_BestWeaponSlot() for simpler code --- client.qc | 2 +- player.qc | 2 +- weapons.qc | 45 +++++++++++++++++++++++++++------------------ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/client.qc b/client.qc index 0fe06171..1c22444a 100644 --- a/client.qc +++ b/client.qc @@ -1471,7 +1471,7 @@ void () PlayerPreThink = { if (((time > self.attack_finished) && (self.currentammo == 0)) && (self.weapon > 16)) { self.weapon = W_BestWeapon(); - self.current_weaponslot = W_GetSlot(); + self.current_weaponslot = W_BestWeaponSlot(); W_SetCurrentAmmo(); } }; diff --git a/player.qc b/player.qc index 1933cd4d..4c77eb29 100644 --- a/player.qc +++ b/player.qc @@ -493,7 +493,7 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { TeamFortress_SetSpeed(self); if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_GetSlot(); + self.current_weaponslot = W_BestWeaponSlot(); W_SetCurrentAmmo(); W_PrintWeaponMessage(); return; diff --git a/weapons.qc b/weapons.qc index 39ca0bdf..4ed9eedf 100644 --- a/weapons.qc +++ b/weapons.qc @@ -86,7 +86,8 @@ void () TeamFortress_HelpMap; void () BioInfection_Decay; void () BioInfection_MonsterDecay; -float () W_GetSlot; +float (float weap) W_GetSlot; +float () W_BestWeaponSlot; void () W_FireFlame; void () W_FireIncendiaryCannon; void () W_FireTranq; @@ -1030,7 +1031,7 @@ void () W_FireLightning = { if (self.ammo_cells < 1) { self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_GetSlot(); + self.current_weaponslot = W_BestWeaponSlot(); W_SetCurrentAmmo(); W_PrintWeaponMessage(); return; @@ -1237,7 +1238,7 @@ void (float ox) W_FireSpikes = { } if (self.ammo_nails < 1) { self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_GetSlot(); + self.current_weaponslot = W_BestWeaponSlot(); W_SetCurrentAmmo(); W_PrintWeaponMessage(); return; @@ -1511,6 +1512,14 @@ float () W_BestWeapon = { return (0); }; +float () W_BestWeaponSlot = { + local float weap; + + weap = W_BestWeapon(); + + return W_GetSlot(weap); +}; + float () W_CheckNoAmmo = { if ((self.current_weapon == WEAP_AXE) || (self.current_weapon == WEAP_SPANNER) @@ -1530,7 +1539,7 @@ float () W_CheckNoAmmo = { return (1); self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_GetSlot(); + self.current_weaponslot = W_BestWeaponSlot(); W_SetCurrentAmmo(); W_PrintWeaponMessage(); return (0); @@ -1785,30 +1794,30 @@ void () W_PrintWeaponMessage = { sprint(self, PRINT_MEDIUM, "Sniper rifle on fully automatic mode\n"); }; -float () W_GetSlot = { - if (self.current_weapon == WEAP_ROCKET_LAUNCHER - || self.current_weapon == WEAP_SUPER_NAILGUN - || self.current_weapon == WEAP_SNIPER_RIFLE - || self.current_weapon == WEAP_FLAMETHROWER - || self.current_weapon == WEAP_TRANQ - || self.current_weapon == WEAP_LASER - || self.current_weapon == WEAP_ASSAULT_CANNON) { +float (float weap) W_GetSlot = { + if (weap == WEAP_ROCKET_LAUNCHER + || weap == WEAP_SUPER_NAILGUN + || weap == WEAP_SNIPER_RIFLE + || weap == WEAP_FLAMETHROWER + || weap == WEAP_TRANQ + || weap == WEAP_LASER + || weap == WEAP_ASSAULT_CANNON) { return 1; - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN - || self.current_weapon == WEAP_AUTO_RIFLE - || self.current_weapon == WEAP_INCENDIARY) { + } else if (weap == WEAP_SUPER_SHOTGUN + || weap == WEAP_AUTO_RIFLE + || weap == WEAP_INCENDIARY) { return 2; - } else if (self.current_weapon == WEAP_SHOTGUN) { + } else if (weap == WEAP_SHOTGUN) { if (self.playerclass == PC_SCOUT) return 2; else return 3; - } else if (self.current_weapon == WEAP_NAILGUN) { + } else if (weap == WEAP_NAILGUN) { if (self.playerclass == PC_SCOUT) return 1; else return 3; - } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { + } else if (weap == WEAP_GRENADE_LAUNCHER) { if (self.weaponmode == 0) return 1; else From 800fec1729877cc631d0e902a47702f104c9c26e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 6 Aug 2014 09:47:15 +0200 Subject: [PATCH 0110/2474] Add map specific configurations in /cfg/maps/ --- world.qc | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/world.qc b/world.qc index 9d24a24f..54a0ed43 100644 --- a/world.qc +++ b/world.qc @@ -147,15 +147,8 @@ void () worldspawn = { st = infokey(world, "exec_map_cfgs"); if (st == "on") { - - st = infokey(world, "cycledir"); - if (st != string_null) { - localcmd("exec "); - localcmd(st); - localcmd("/"); - } else - localcmd("exec qwmcycle/"); - + localcmd("exec fortress.cfg\n"); + localcmd("exec cfg/maps/"); localcmd(mapname); localcmd(".cfg\n"); } From 1eaab9da79475bcd379f9fee13fede3353dc47a3 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 7 Aug 2014 23:17:13 +0200 Subject: [PATCH 0111/2474] Keep track of current weapon when running out of ammo (fixes #97) --- weapons.qc | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/weapons.qc b/weapons.qc index 4ed9eedf..de94fb13 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1969,6 +1969,13 @@ void (float slot) W_WeaponSlot = { W_WeaponSlot4(); }; +void () W_AmmoError = { + if (self.noammo == 1) + sprint(self, PRINT_HIGH, "Not enough ammo\n"); + else if (self.noammo == 2) + sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); +}; + void (float inp, float quick) W_ChangeWeapon = { if (self.playerclass == 0) return; @@ -1998,15 +2005,9 @@ void (float inp, float quick) W_ChangeWeapon = { // check for ammo if (! W_AmmoSlot(self.queue_weaponslot)) { - if (self.noammo == 1) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - self.queue_weaponslot = 0; - return; - } else if (self.noammo == 2) { - sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); - self.queue_weaponslot = 0; - return; - } + W_AmmoError(); + self.queue_weaponslot = 0; + return; } W_WeaponSlot(self.queue_weaponslot); @@ -2362,8 +2363,15 @@ void () W_WeaponFrame = { } else if (self.queue_weaponslot) W_ChangeWeapon(self.queue_weaponslot, 0); else if (self.real_weaponslot != self.current_weaponslot - && time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) - W_ChangeWeapon(TF_WEAPLAST, 1); + && time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) { + if (W_AmmoSlot(self.real_weaponslot)) + W_ChangeWeapon(TF_WEAPLAST, 1); + else { + W_AmmoError(); + self.real_weaponslot = W_BestWeaponSlot(); + W_ChangeWeapon(self.real_weaponslot, 0); + } + } if (self.impulse == TF_CHANGETEAM) { Menu_Team(); From 00d3e196b6aa9ddfbd3f096ff92d0dec2e05b09d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 7 Aug 2014 23:30:24 +0200 Subject: [PATCH 0112/2474] Remove grenades and grenade timers when game ends (fixes #87) --- client.qc | 16 +++++++++------- tfort.qc | 38 ++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/client.qc b/client.qc index 1c22444a..cd3397bf 100644 --- a/client.qc +++ b/client.qc @@ -17,6 +17,9 @@ float (float pc) IsLegalClass; void () SetupTeamEqualiser; void () CeaseFire_think; +void () RemoveGrenadeTimers; +void () RemoveGrenades; + void (entity eng) Engineer_RemoveBuildings; void (string halias, float himpulse1, float himpulse2) TeamFortress_Alias; @@ -1413,6 +1416,11 @@ void () CheckWaterJump = { }; void () PlayerPreThink = { + if (time >= timelimit) { + RemoveGrenadeTimers(); + RemoveGrenades(); + } + if (self.impulse == TF_VOTENEXT) { Vote_NextMap(self); self.impulse = 0; @@ -1811,13 +1819,7 @@ void () ClientDisconnect = { } te = find(te, classname, "detpack"); } - te = find(world, classname, "grenade"); - while (te) { - if (te.owner == self) { - dremove(te); - } - te = find(te, classname, "grenade"); - } + RemoveGrenades(); if (clanbattle && (self.tf_id != 0)) { te = spawn(); te.classname = "ghost"; diff --git a/tfort.qc b/tfort.qc index 352be144..a3b5b985 100644 --- a/tfort.qc +++ b/tfort.qc @@ -45,6 +45,24 @@ void () UseSpecialSkill = { } }; +void () RemoveGrenadeTimers = { + local entity te = find(world, classname, "gtimer"); + while (te != world) { + if (te.owner == self) + dremove(te); + te = find(te, classname, "gtimer"); + } +}; + +void () RemoveGrenades = { + local entity te = find(world, classname, "grenade"); + while (te) { + if (te.owner == self) + dremove(te); + te = find(te, classname, "grenade"); + } +}; + void (float inp) TeamFortress_ChangeClass = { local entity spot; local entity te; @@ -621,15 +639,7 @@ void (float inp) TeamFortress_PrimeGrenade = { else { tGrenade.heat = time + 3 + 0.8; - timer = find(world, classname, "gtimer"); - while (timer != world) { - if (timer.owner == self) { - dremove(timer); - timer = find(world, classname, "gtimer"); - } else { - timer = find(timer, classname, "gtimer"); - } - } + RemoveGrenadeTimers(); if (!stof(infokey(self, "nt"))) { timer = spawn(); @@ -1856,15 +1866,7 @@ void () TeamFortress_RemoveTimers = { te = find(te, classname, "timer"); } - te = find(world, classname, "timer"); - while (te != world) { - if (te.owner == self) { - dremove(te); - te = find(world, classname, "gtimer"); - } else { - te = find(te, classname, "gtimer"); - } - } + RemoveGrenadeTimers(); self.StatusGrenTime = 0; Status_Refresh(self); From 8bcfdbc297ecb7a8e7936f86d28da28493539787 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 8 Aug 2014 00:33:01 +0200 Subject: [PATCH 0113/2474] Add option to spawn with full armor and ammo (closes #102) --- client.qc | 6 ++ defs.h | 1 + tfort.qc | 230 ++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 177 insertions(+), 60 deletions(-) diff --git a/client.qc b/client.qc index cd3397bf..6402c587 100644 --- a/client.qc +++ b/client.qc @@ -367,6 +367,12 @@ void () DecodeLevelParms = { if (st != "off") toggleflags = toggleflags | TFLAG_SNIPERRELOAD; + st = infokey(world, "sf"); + if (st == string_null) + st = infokey(world, "spawnfull"); + if (st == "on") + toggleflags = toggleflags | TFLAG_SPAWNFULL; + st = infokey(world, "rd"); if (st == string_null) st = infokey(world, "respawn_delay"); diff --git a/defs.h b/defs.h index aea2c619..87138698 100644 --- a/defs.h +++ b/defs.h @@ -280,6 +280,7 @@ #define TFLAG_FLAGEMU 4096 #define TFLAG_WARSTANDARD 8192 #define TFLAG_SNIPERRELOAD 16384 // Sniper reload enabled +#define TFLAG_SPAWNFULL 32768 // Spawn fully stocked #define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn #define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn diff --git a/tfort.qc b/tfort.qc index a3b5b985..b6c2c019 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1397,10 +1397,23 @@ void () TeamFortress_SetEquipment = { if (self.playerclass == PC_SCOUT) { self.weapons_carried = self.weapons_carried | PC_SCOUT_WEAPONS; - self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET; - self.ammo_nails = PC_SCOUT_INITAMMO_NAIL; - self.ammo_shells = PC_SCOUT_INITAMMO_SHOT; - self.ammo_cells = PC_SCOUT_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_SCOUT_MAXAMMO_ROCKET; + self.ammo_nails = PC_SCOUT_MAXAMMO_NAIL; + self.ammo_shells = PC_SCOUT_MAXAMMO_SHOT; + self.ammo_cells = PC_SCOUT_MAXAMMO_CELL; + self.armortype = PC_SCOUT_MAXARMORTYPE; + self.armorvalue = PC_SCOUT_MAXARMOR; + } else { + self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET; + self.ammo_nails = PC_SCOUT_INITAMMO_NAIL; + self.ammo_shells = PC_SCOUT_INITAMMO_SHOT; + self.ammo_cells = PC_SCOUT_INITAMMO_CELL; + self.armortype = PC_SCOUT_INITARMORTYPE; + self.armorvalue = PC_SCOUT_INITARMOR; + } + self.maxammo_rockets = PC_SCOUT_MAXAMMO_ROCKET; self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL; self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT; @@ -1422,8 +1435,6 @@ void () TeamFortress_SetEquipment = { self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY; self.armorclass = self.armorclass | 0; - self.armortype = PC_SCOUT_INITARMORTYPE; - self.armorvalue = PC_SCOUT_INITARMOR; self.armor_allowed = PC_SCOUT_MAXARMORTYPE; self.maxarmor = PC_SCOUT_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1434,10 +1445,23 @@ void () TeamFortress_SetEquipment = { self.items = self.items | IT_SHOTGUN | IT_NAILGUN; } else if (self.playerclass == PC_SNIPER) { self.weapons_carried = self.weapons_carried | PC_SNIPER_WEAPONS; - self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET; - self.ammo_nails = PC_SNIPER_INITAMMO_NAIL; - self.ammo_shells = PC_SNIPER_INITAMMO_SHOT; - self.ammo_cells = PC_SNIPER_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_SNIPER_MAXAMMO_ROCKET; + self.ammo_nails = PC_SNIPER_MAXAMMO_NAIL; + self.ammo_shells = PC_SNIPER_MAXAMMO_SHOT; + self.ammo_cells = PC_SNIPER_MAXAMMO_CELL; + self.armortype = PC_SNIPER_MAXARMORTYPE; + self.armorvalue = PC_SNIPER_MAXARMOR; + } else { + self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET; + self.ammo_nails = PC_SNIPER_INITAMMO_NAIL; + self.ammo_shells = PC_SNIPER_INITAMMO_SHOT; + self.ammo_cells = PC_SNIPER_INITAMMO_CELL; + self.armortype = PC_SNIPER_INITARMORTYPE; + self.armorvalue = PC_SNIPER_INITARMOR; + } + self.maxammo_rockets = PC_SNIPER_MAXAMMO_ROCKET; self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL; self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT; @@ -1450,8 +1474,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_SNIPER_TF_ITEMS; self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS; - self.armortype = PC_SNIPER_INITARMORTYPE; - self.armorvalue = PC_SNIPER_INITARMOR; self.armor_allowed = PC_SNIPER_MAXARMORTYPE; self.maxarmor = PC_SNIPER_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1462,10 +1484,23 @@ void () TeamFortress_SetEquipment = { self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN; } else if (self.playerclass == PC_SOLDIER) { self.weapons_carried = self.weapons_carried | PC_SOLDIER_WEAPONS; - self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET; - self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL; - self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT; - self.ammo_cells = PC_SOLDIER_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET; + self.ammo_nails = PC_SOLDIER_MAXAMMO_NAIL; + self.ammo_shells = PC_SOLDIER_MAXAMMO_SHOT; + self.ammo_cells = PC_SOLDIER_MAXAMMO_CELL; + self.armortype = PC_SOLDIER_MAXARMORTYPE; + self.armorvalue = PC_SOLDIER_MAXARMOR; + } else { + self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET; + self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL; + self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT; + self.ammo_cells = PC_SOLDIER_INITAMMO_CELL; + self.armortype = PC_SOLDIER_INITARMORTYPE; + self.armorvalue = PC_SOLDIER_INITARMOR; + } + self.maxammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET; self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL; self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT; @@ -1478,8 +1513,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_SOLDIER_TF_ITEMS; self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS; - self.armortype = PC_SOLDIER_INITARMORTYPE; - self.armorvalue = PC_SOLDIER_INITARMOR; self.armor_allowed = PC_SOLDIER_MAXARMORTYPE; self.maxarmor = PC_SOLDIER_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1491,10 +1524,23 @@ void () TeamFortress_SetEquipment = { items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_DEMOMAN) { self.weapons_carried = self.weapons_carried | PC_DEMOMAN_WEAPONS; - self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET; - self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL; - self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT; - self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET; + self.ammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; + self.ammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; + self.ammo_cells = PC_DEMOMAN_MAXAMMO_CELL; + self.armortype = PC_DEMOMAN_MAXARMORTYPE; + self.armorvalue = PC_DEMOMAN_MAXARMOR; + } else { + self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET; + self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL; + self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT; + self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL; + self.armortype = PC_DEMOMAN_INITARMORTYPE; + self.armorvalue = PC_DEMOMAN_INITARMOR; + } + self.maxammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET; self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; @@ -1510,8 +1556,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_detpack = PC_DEMOMAN_MAXAMMO_DETPACK; self.armorclass = self.armorclass | PC_DEMOMAN_INITARMORCLASS; - self.armortype = PC_DEMOMAN_INITARMORTYPE; - self.armorvalue = PC_DEMOMAN_INITARMOR; self.armor_allowed = PC_DEMOMAN_MAXARMORTYPE; self.maxarmor = PC_DEMOMAN_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1521,10 +1565,23 @@ void () TeamFortress_SetEquipment = { self.items = self.items | IT_SHOTGUN | IT_GRENADE_LAUNCHER; } else if (self.playerclass == PC_MEDIC) { self.weapons_carried = self.weapons_carried | PC_MEDIC_WEAPONS; - self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET; - self.ammo_nails = PC_MEDIC_INITAMMO_NAIL; - self.ammo_shells = PC_MEDIC_INITAMMO_SHOT; - self.ammo_cells = PC_MEDIC_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_MEDIC_MAXAMMO_ROCKET; + self.ammo_nails = PC_MEDIC_MAXAMMO_NAIL; + self.ammo_shells = PC_MEDIC_MAXAMMO_SHOT; + self.ammo_cells = PC_MEDIC_MAXAMMO_CELL; + self.armortype = PC_MEDIC_MAXARMORTYPE; + self.armorvalue = PC_MEDIC_MAXARMOR; + } else { + self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET; + self.ammo_nails = PC_MEDIC_INITAMMO_NAIL; + self.ammo_shells = PC_MEDIC_INITAMMO_SHOT; + self.ammo_cells = PC_MEDIC_INITAMMO_CELL; + self.armortype = PC_MEDIC_INITARMORTYPE; + self.armorvalue = PC_MEDIC_INITARMOR; + } + self.maxammo_rockets = PC_MEDIC_MAXAMMO_ROCKET; self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL; self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT; @@ -1537,8 +1594,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_MEDIC_TF_ITEMS; self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS; - self.armortype = PC_MEDIC_INITARMORTYPE; - self.armorvalue = PC_MEDIC_INITARMOR; self.armor_allowed = PC_MEDIC_MAXARMORTYPE; self.maxarmor = PC_MEDIC_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1558,10 +1613,23 @@ void () TeamFortress_SetEquipment = { self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_SUPER_NAILGUN; } else if (self.playerclass == PC_HVYWEAP) { self.weapons_carried = self.weapons_carried | PC_HVYWEAP_WEAPONS; - self.ammo_rockets = PC_HVYWEAP_INITAMMO_ROCKET; - self.ammo_nails = PC_HVYWEAP_INITAMMO_NAIL; - self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT; - self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET; + self.ammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; + self.ammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; + self.ammo_cells = PC_HVYWEAP_MAXAMMO_CELL; + self.armortype = PC_HVYWEAP_MAXARMORTYPE; + self.armorvalue = PC_HVYWEAP_MAXARMOR; + } else { + self.ammo_rockets = PC_HVYWEAP_INITAMMO_ROCKET; + self.ammo_nails = PC_HVYWEAP_INITAMMO_NAIL; + self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT; + self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL; + self.armortype = PC_HVYWEAP_INITARMORTYPE; + self.armorvalue = PC_HVYWEAP_INITARMOR; + } + self.maxammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET; self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; @@ -1574,8 +1642,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_HVYWEAP_TF_ITEMS; self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS; - self.armortype = PC_HVYWEAP_INITARMORTYPE; - self.armorvalue = PC_HVYWEAP_INITARMOR; self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE; self.maxarmor = PC_HVYWEAP_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1587,10 +1653,23 @@ void () TeamFortress_SetEquipment = { items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_PYRO) { self.weapons_carried = self.weapons_carried | PC_PYRO_WEAPONS; - self.ammo_rockets = PC_PYRO_INITAMMO_ROCKET; - self.ammo_nails = PC_PYRO_INITAMMO_NAIL; - self.ammo_shells = PC_PYRO_INITAMMO_SHOT; - self.ammo_cells = PC_PYRO_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_PYRO_MAXAMMO_ROCKET; + self.ammo_nails = PC_PYRO_MAXAMMO_NAIL; + self.ammo_shells = PC_PYRO_MAXAMMO_SHOT; + self.ammo_cells = PC_PYRO_MAXAMMO_CELL; + self.armortype = PC_PYRO_MAXARMORTYPE; + self.armorvalue = PC_PYRO_MAXARMOR; + } else { + self.ammo_rockets = PC_PYRO_INITAMMO_ROCKET; + self.ammo_nails = PC_PYRO_INITAMMO_NAIL; + self.ammo_shells = PC_PYRO_INITAMMO_SHOT; + self.ammo_cells = PC_PYRO_INITAMMO_CELL; + self.armortype = PC_PYRO_INITARMORTYPE; + self.armorvalue = PC_PYRO_INITARMOR; + } + self.maxammo_rockets = PC_PYRO_MAXAMMO_ROCKET; self.maxammo_nails = PC_PYRO_MAXAMMO_NAIL; self.maxammo_shells = PC_PYRO_MAXAMMO_SHOT; @@ -1603,8 +1682,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_PYRO_TF_ITEMS; self.armorclass = self.armorclass | PC_PYRO_INITARMORCLASS; - self.armortype = PC_PYRO_INITARMORTYPE; - self.armorvalue = PC_PYRO_INITARMOR; self.armor_allowed = PC_PYRO_MAXARMORTYPE; self.maxarmor = PC_PYRO_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1616,10 +1693,23 @@ void () TeamFortress_SetEquipment = { items | IT_SHOTGUN | IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_CIVILIAN) { self.weapons_carried = self.weapons_carried | PC_CIVILIAN_WEAPONS; - self.ammo_rockets = PC_CIVILIAN_INITAMMO_ROCKET; - self.ammo_nails = PC_CIVILIAN_INITAMMO_NAIL; - self.ammo_shells = PC_CIVILIAN_INITAMMO_SHOT; - self.ammo_cells = PC_CIVILIAN_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_CIVILIAN_MAXAMMO_ROCKET; + self.ammo_nails = PC_CIVILIAN_MAXAMMO_NAIL; + self.ammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; + self.ammo_cells = PC_CIVILIAN_MAXAMMO_CELL; + self.armortype = PC_CIVILIAN_MAXARMORTYPE; + self.armorvalue = PC_CIVILIAN_MAXARMOR; + } else { + self.ammo_rockets = PC_CIVILIAN_INITAMMO_ROCKET; + self.ammo_nails = PC_CIVILIAN_INITAMMO_NAIL; + self.ammo_shells = PC_CIVILIAN_INITAMMO_SHOT; + self.ammo_cells = PC_CIVILIAN_INITAMMO_CELL; + self.armortype = PC_CIVILIAN_INITARMORTYPE; + self.armorvalue = PC_CIVILIAN_INITARMOR; + } + self.maxammo_rockets = PC_CIVILIAN_MAXAMMO_ROCKET; self.maxammo_nails = PC_CIVILIAN_MAXAMMO_NAIL; self.maxammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; @@ -1632,8 +1722,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_CIVILIAN_TF_ITEMS; self.armorclass = self.armorclass | PC_CIVILIAN_INITARMORCLASS; - self.armortype = PC_CIVILIAN_INITARMORTYPE; - self.armorvalue = PC_CIVILIAN_INITARMOR; self.armor_allowed = PC_CIVILIAN_MAXARMORTYPE; self.maxarmor = PC_CIVILIAN_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1643,10 +1731,23 @@ void () TeamFortress_SetEquipment = { self.items = 0; } else if (self.playerclass == PC_SPY) { self.weapons_carried = self.weapons_carried | PC_SPY_WEAPONS; - self.ammo_rockets = PC_SPY_INITAMMO_ROCKET; - self.ammo_nails = PC_SPY_INITAMMO_NAIL; - self.ammo_shells = PC_SPY_INITAMMO_SHOT; - self.ammo_cells = PC_SPY_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_SPY_MAXAMMO_ROCKET; + self.ammo_nails = PC_SPY_MAXAMMO_NAIL; + self.ammo_shells = PC_SPY_MAXAMMO_SHOT; + self.ammo_cells = PC_SPY_MAXAMMO_CELL; + self.armortype = PC_SPY_MAXARMORTYPE; + self.armorvalue = PC_SPY_MAXARMOR; + } else { + self.ammo_rockets = PC_SPY_INITAMMO_ROCKET; + self.ammo_nails = PC_SPY_INITAMMO_NAIL; + self.ammo_shells = PC_SPY_INITAMMO_SHOT; + self.ammo_cells = PC_SPY_INITAMMO_CELL; + self.armortype = PC_SPY_INITARMORTYPE; + self.armorvalue = PC_SPY_INITARMOR; + } + self.maxammo_rockets = PC_SPY_MAXAMMO_ROCKET; self.maxammo_nails = PC_SPY_MAXAMMO_NAIL; self.maxammo_shells = PC_SPY_MAXAMMO_SHOT; @@ -1659,8 +1760,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_SPY_TF_ITEMS; self.armorclass = self.armorclass | PC_SPY_INITARMORCLASS; - self.armortype = PC_SPY_INITARMORTYPE; - self.armorvalue = PC_SPY_INITARMOR; self.armor_allowed = PC_SPY_MAXARMORTYPE; self.maxarmor = PC_SPY_MAXARMOR; if (self.last_playerclass != self.playerclass) @@ -1679,10 +1778,23 @@ void () TeamFortress_SetEquipment = { } } else if (self.playerclass == PC_ENGINEER) { self.weapons_carried = self.weapons_carried | PC_ENGINEER_WEAPONS; - self.ammo_rockets = PC_ENGINEER_INITAMMO_ROCKET; - self.ammo_nails = PC_ENGINEER_INITAMMO_NAIL; - self.ammo_shells = PC_ENGINEER_INITAMMO_SHOT; - self.ammo_cells = PC_ENGINEER_INITAMMO_CELL; + + if ((toggleflags & TFLAG_SPAWNFULL)) { + self.ammo_rockets = PC_ENGINEER_MAXAMMO_ROCKET; + self.ammo_nails = PC_ENGINEER_MAXAMMO_NAIL; + self.ammo_shells = PC_ENGINEER_MAXAMMO_SHOT; + self.ammo_cells = PC_ENGINEER_MAXAMMO_CELL; + self.armortype = PC_ENGINEER_MAXARMORTYPE; + self.armorvalue = PC_ENGINEER_MAXARMOR; + } else { + self.ammo_rockets = PC_ENGINEER_INITAMMO_ROCKET; + self.ammo_nails = PC_ENGINEER_INITAMMO_NAIL; + self.ammo_shells = PC_ENGINEER_INITAMMO_SHOT; + self.ammo_cells = PC_ENGINEER_INITAMMO_CELL; + self.armortype = PC_ENGINEER_INITARMORTYPE; + self.armorvalue = PC_ENGINEER_INITARMOR; + } + self.maxammo_rockets = PC_ENGINEER_MAXAMMO_ROCKET; self.maxammo_nails = PC_ENGINEER_MAXAMMO_NAIL; self.maxammo_shells = PC_ENGINEER_MAXAMMO_SHOT; @@ -1695,8 +1807,6 @@ void () TeamFortress_SetEquipment = { self.tf_items = PC_ENGINEER_TF_ITEMS; self.armorclass = self.armorclass | PC_ENGINEER_INITARMORCLASS; - self.armortype = PC_ENGINEER_INITARMORTYPE; - self.armorvalue = PC_ENGINEER_INITARMOR; self.armor_allowed = PC_ENGINEER_MAXARMORTYPE; self.maxarmor = PC_ENGINEER_MAXARMOR; if (self.last_playerclass != self.playerclass) From 14c5c002cdc81b81465c4f8e3a35c8ebdc1ddf72 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 8 Aug 2014 00:40:29 +0200 Subject: [PATCH 0114/2474] Remove message from discarded packs (fixes #104) --- tfort.qc | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/tfort.qc b/tfort.qc index b6c2c019..81bc25d0 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2284,29 +2284,10 @@ void () TeamFortress_AmmoboxTouch = { return; if (self.weapon == 0) { - sprint(other, PRINT_HIGH, "You got "); - if (self.ammo_shells > 0) { - other.ammo_shells = other.ammo_shells + self.ammo_shells; - quantity = ftos(self.ammo_shells); - sprint2(other, PRINT_HIGH, quantity, " shells "); - } - if (self.ammo_nails > 0) { - other.ammo_nails = other.ammo_nails + self.ammo_nails; - quantity = ftos(self.ammo_nails); - sprint2(other, PRINT_HIGH, quantity, " nails "); - } - if (self.ammo_rockets > 0) { - other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; - quantity = ftos(self.ammo_rockets); - sprint2(other, PRINT_HIGH, quantity, " rockets "); - } - if (self.ammo_cells > 0) { - other.ammo_cells = other.ammo_cells + self.ammo_cells; - quantity = ftos(self.ammo_cells); - sprint2(other, PRINT_HIGH, quantity, " cells "); - } - sprint3(other, PRINT_HIGH, " from ", self.enemy.netname, - "'s discarded pack\n"); + other.ammo_shells = other.ammo_shells + self.ammo_shells; + other.ammo_nails = other.ammo_nails + self.ammo_nails; + other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; + other.ammo_cells = other.ammo_cells + self.ammo_cells; } else if (self.weapon == 1) { if (other.ammo_shells >= TeamFortress_GetMaxAmmo(other, 256)) return; From a92fd3a04018935727cddd06b0ad89637a67eb0a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 13 Aug 2014 09:55:31 +0200 Subject: [PATCH 0115/2474] Implement Dispenser auto-stock (#93) --- engineer.qc | 212 +++++++++++++++++++++++++++++++++++++++++++--------- qw.qc | 9 +++ tfort.qc | 60 +++++++++++++++ 3 files changed, 246 insertions(+), 35 deletions(-) diff --git a/engineer.qc b/engineer.qc index 301121d2..8c5adb87 100644 --- a/engineer.qc +++ b/engineer.qc @@ -411,38 +411,180 @@ void (entity bld) CheckBelowBuilding = { } }; -void () DispenserThink = { - CheckBelowBuilding(self); +void (entity disp) Dispenser_AmmoTick = { if (self.disptimer > 3) { - self.ammo_shells = - self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS / 20); - self.ammo_cells = - self.ammo_cells + rint(BUILD_DISPENSER_MAX_CELLS / 20); - self.ammo_nails = - self.ammo_nails + rint(BUILD_DISPENSER_MAX_NAILS / 20); - self.ammo_rockets = - self.ammo_rockets + rint(BUILD_DISPENSER_MAX_ROCKETS / 20); - self.armorvalue = - self.armorvalue + rint(BUILD_DISPENSER_MAX_ARMOR / 20); - if (self.ammo_shells > BUILD_DISPENSER_MAX_SHELLS) { + self.ammo_shells = self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS / 150); + self.ammo_cells = self.ammo_cells + rint(BUILD_DISPENSER_MAX_CELLS / 150); + self.ammo_nails = self.ammo_nails + rint(BUILD_DISPENSER_MAX_NAILS / 150); + self.ammo_rockets = self.ammo_rockets + rint(BUILD_DISPENSER_MAX_ROCKETS / 150); + self.armorvalue = self.armorvalue + rint(BUILD_DISPENSER_MAX_ARMOR / 150); + + if (self.ammo_shells > BUILD_DISPENSER_MAX_SHELLS) self.ammo_shells = BUILD_DISPENSER_MAX_SHELLS; - } - if (self.ammo_nails > BUILD_DISPENSER_MAX_NAILS) { + if (self.ammo_nails > BUILD_DISPENSER_MAX_NAILS) self.ammo_nails = BUILD_DISPENSER_MAX_NAILS; - } - if (self.ammo_rockets > BUILD_DISPENSER_MAX_ROCKETS) { + if (self.ammo_rockets > BUILD_DISPENSER_MAX_ROCKETS) self.ammo_rockets = BUILD_DISPENSER_MAX_ROCKETS; - } - if (self.ammo_cells > BUILD_DISPENSER_MAX_CELLS) { + if (self.ammo_cells > BUILD_DISPENSER_MAX_CELLS) self.ammo_cells = BUILD_DISPENSER_MAX_CELLS; - } - if (self.armorvalue > BUILD_DISPENSER_MAX_ARMOR) { + if (self.armorvalue > BUILD_DISPENSER_MAX_ARMOR) self.armorvalue = BUILD_DISPENSER_MAX_ARMOR; - } + self.disptimer = 0; } + self.disptimer = self.disptimer + 1; - self.nextthink = time + 3; +} + +float (entity disp, entity pl) Dispenser_GiveShells = { + local float ammo; + + if (!pl.need_shells) + return 0; + + ammo = (pl.maxammo_shells * pl.deff) / 7; + + if (ammo > disp.ammo_shells) + ammo = disp.ammo_shells; + + if ((ammo + pl.ammo_shells) > pl.maxammo_shells) + ammo = pl.maxammo_shells - pl.ammo_shells; + + disp.ammo_shells = disp.ammo_shells - ammo; + pl.ammo_shells = pl.ammo_shells + ammo; + + return ammo; +} + +float (entity disp, entity pl) Dispenser_GiveNails = { + local float ammo; + + if (!pl.need_nails) + return 0; + + ammo = (pl.maxammo_nails * pl.deff) / 7; + + if (ammo > disp.ammo_nails) + ammo = disp.ammo_nails; + + if ((ammo + pl.ammo_nails) > pl.maxammo_nails) + ammo = pl.maxammo_nails - pl.ammo_nails; + + disp.ammo_nails = disp.ammo_nails - ammo; + pl.ammo_nails = pl.ammo_nails + ammo; + + return ammo; +} + +float (entity disp, entity pl) Dispenser_GiveRockets = { + local float ammo; + + if (!pl.need_rockets) + return 0; + + ammo = (pl.maxammo_rockets * pl.deff) / 7; + + if (ammo > disp.ammo_rockets) + ammo = disp.ammo_rockets; + + if ((ammo + pl.ammo_rockets) > pl.maxammo_rockets) + ammo = pl.maxammo_rockets - pl.ammo_rockets; + + disp.ammo_rockets = disp.ammo_rockets - ammo; + pl.ammo_rockets = pl.ammo_rockets + ammo; + + return ammo; +} + +float (entity disp, entity pl) Dispenser_GiveCells = { + local float ammo; + + if (!pl.need_cells) + return 0; + + ammo = (pl.maxammo_cells * pl.deff) / 7; + + if (ammo > disp.ammo_cells) + ammo = disp.ammo_cells; + + if ((ammo + pl.ammo_cells) > pl.maxammo_cells) + ammo = pl.maxammo_cells - pl.ammo_cells; + + disp.ammo_cells = disp.ammo_cells - ammo; + pl.ammo_cells = pl.ammo_cells + ammo; + + return ammo; +} + +float (entity disp, entity pl) Dispenser_GiveArmor = { + local float armor; + + armor = (pl.maxarmor * pl.deff) / 7; + + pl.armortype = pl.armor_allowed; + + if (armor > disp.armorvalue) + armor = disp.armorvalue; + + if ((armor + pl.armorvalue) > pl.maxarmor) + armor = pl.maxarmor - pl.armorvalue; + + disp.armorvalue = disp.armorvalue - armor; + pl.armorvalue = pl.armorvalue + armor; + + return armor; +} + +void (entity disp, entity pl) Dispenser_StockPlayer = { + local float shells, nails, rockets, cells, armor; + + // 10 second cooldown for engineers who recently used the dispenser + if ((time - pl.dimmune) < 10) + return; + + // reset dispenser efficiency if >1.2 second has passed since last dispenser use + if ((time - pl.duse) > 1.2) + pl.deff = 0; + + // set dispenser efficiency (increase with time => just passing by gives less ammo/armor) + if (!pl.deff || pl.deff >= 4) + pl.deff = 1; + else + pl.deff = pl.deff * 2; + + // give engineers full armor/ammo instantly + if (pl.playerclass == PC_ENGINEER) { + pl.dimmune = time; + pl.deff = 7; + } + + shells = Dispenser_GiveShells(disp, pl); + nails = Dispenser_GiveNails(disp, pl); + rockets = Dispenser_GiveRockets(disp, pl); + cells = Dispenser_GiveCells(disp, pl); + armor = Dispenser_GiveArmor(disp, pl); + + // only play dispenser restock sound if something was given + if ((shells + nails + rockets + cells + armor) > 0) + sound(pl, 3, "items/r_item1.wav", 0.7, 1); + + pl.duse = time; +}; + +void (entity disp) Dispenser_FindPlayers = { + local entity te = findradius(disp.origin, 60); + while (te != world) { + if (te.classname == "player" && te.team_no == disp.team_no) + Dispenser_StockPlayer(disp, te); + te = te.chain; + } +} + +void () DispenserThink = { + CheckBelowBuilding(self); + Dispenser_AmmoTick(self); + Dispenser_FindPlayers(self); + self.nextthink = time + 0.4; }; void () TeamFortress_FinishedBuilding = { @@ -474,7 +616,7 @@ void () TeamFortress_FinishedBuilding = { oldself.health = 150; oldself.disptimer = 1; oldself.think = DispenserThink; - oldself.nextthink = time + 3; + oldself.nextthink = time + 0.4; oldself.th_die = Dispenser_Die; oldself.mdl = "progs/disp.mdl"; oldself.team_no = self.team_no; @@ -563,12 +705,12 @@ void () T_Dispenser = { local entity oldself; local entity dist_checker; - if (other.classname != "player") { + // don't show menu to players of same team + if (other.classname != "player" || other.team_no == self.team_no || !other.team_no) return; - } - if ((other.team_no != 0) && (other.team_no != self.team_no)) { - Status_Print(self.real_owner, "\n\n\n\n\n\n\n", "Enemies are using your dispenser!"); - } + + Status_Print(self.real_owner, "\n\n\n", "Enemies are using your dispenser!"); + if ((other.building == world) && (other.building_wait < time)) { other.building = self; dist_checker = spawn(); @@ -623,11 +765,11 @@ void (entity disp) Engineer_UseDispenser = { } sprint(self, PRINT_HIGH, "Dispenser has ", ftos(disp.health), " health and current stock:\n"); - sprint(self, PRINT_HIGH, ftos(disp.ammo_shells), " shells, "); - sprint(self, PRINT_HIGH, ftos(disp.ammo_nails), " nails, "); - sprint(self, PRINT_HIGH, ftos(disp.ammo_rockets), " rockets, "); - sprint(self, PRINT_HIGH, ftos(disp.ammo_cells), " cells and "); - sprint(self, PRINT_HIGH, ftos(disp.armorvalue), " armor\n"); + sprint(self, PRINT_HIGH, ftos(disp.ammo_shells), " shells, "); + sprint(self, PRINT_HIGH, ftos(disp.ammo_nails), " nails, "); + sprint(self, PRINT_HIGH, ftos(disp.ammo_rockets), " rockets, "); + sprint(self, PRINT_HIGH, ftos(disp.ammo_cells), " cells and "); + sprint(self, PRINT_HIGH, ftos(floor(disp.armorvalue)), " armor\n"); if ((!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells) || (disp.ammo_shells == BUILD_DISPENSER_MAX_SHELLS && disp.ammo_nails == BUILD_DISPENSER_MAX_NAILS @@ -730,7 +872,7 @@ void (entity disp) Engineer_Dispenser_InsertArmor = { } if (armor > 0) - sprint(self, PRINT_HIGH, "You insert ", ftos(armor), " armor into dispenser\n"); + sprint(self, PRINT_HIGH, "You insert ", ftos(floor(armor)), " armor into dispenser\n"); else if (disp.armorvalue == BUILD_DISPENSER_MAX_ARMOR) sprint(self, PRINT_HIGH, "Dispenser cannot carry more armor\n"); }; diff --git a/qw.qc b/qw.qc index fe10a428..c30341fa 100644 --- a/qw.qc +++ b/qw.qc @@ -60,6 +60,10 @@ typedef void (float) f_void_float; .float maxammo_nails; .float maxammo_cells; .float maxammo_rockets; +.float need_shells; +.float need_nails; +.float need_rockets; +.float need_cells; .float items_allowed; .float armor_allowed; .float maxarmor; @@ -159,6 +163,11 @@ float coop; // Assault Cannon .float heat; +// Dispenser +.float deff; // Dispenser efficiency +.float dimmune; // Immune to dispenser stocking +.float duse; // Time of last dispenser usage + // Team Color Cheat Checking .float immune_to_check; diff --git a/tfort.qc b/tfort.qc index 81bc25d0..4c768940 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1414,6 +1414,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_SCOUT_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 1; + self.need_rockets = 0; + self.need_cells = 0; + self.maxammo_rockets = PC_SCOUT_MAXAMMO_ROCKET; self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL; self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT; @@ -1462,6 +1468,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_SNIPER_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 1; + self.need_rockets = 0; + self.need_cells = 0; + self.maxammo_rockets = PC_SNIPER_MAXAMMO_ROCKET; self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL; self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT; @@ -1501,6 +1513,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_SOLDIER_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 0; + self.need_rockets = 1; + self.need_cells = 0; + self.maxammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET; self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL; self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT; @@ -1541,6 +1559,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_DEMOMAN_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 0; + self.need_rockets = 1; + self.need_cells = 0; + self.maxammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET; self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; @@ -1582,6 +1606,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_MEDIC_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 1; + self.need_rockets = 0; + self.need_cells = 0; + self.maxammo_rockets = PC_MEDIC_MAXAMMO_ROCKET; self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL; self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT; @@ -1630,6 +1660,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_HVYWEAP_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 0; + self.need_rockets = 0; + self.need_cells = 1; + self.maxammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET; self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; @@ -1670,6 +1706,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_PYRO_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 0; + self.need_rockets = 1; + self.need_cells = 1; + self.maxammo_rockets = PC_PYRO_MAXAMMO_ROCKET; self.maxammo_nails = PC_PYRO_MAXAMMO_NAIL; self.maxammo_shells = PC_PYRO_MAXAMMO_SHOT; @@ -1710,6 +1752,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_CIVILIAN_INITARMOR; } + // dispenser needs + self.need_shells = 0; + self.need_nails = 0; + self.need_rockets = 0; + self.need_cells = 0; + self.maxammo_rockets = PC_CIVILIAN_MAXAMMO_ROCKET; self.maxammo_nails = PC_CIVILIAN_MAXAMMO_NAIL; self.maxammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; @@ -1748,6 +1796,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_SPY_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 1; + self.need_rockets = 0; + self.need_cells = 0; + self.maxammo_rockets = PC_SPY_MAXAMMO_ROCKET; self.maxammo_nails = PC_SPY_MAXAMMO_NAIL; self.maxammo_shells = PC_SPY_MAXAMMO_SHOT; @@ -1795,6 +1849,12 @@ void () TeamFortress_SetEquipment = { self.armorvalue = PC_ENGINEER_INITARMOR; } + // dispenser needs + self.need_shells = 1; + self.need_nails = 1; + self.need_rockets = 0; + self.need_cells = 1; + self.maxammo_rockets = PC_ENGINEER_MAXAMMO_ROCKET; self.maxammo_nails = PC_ENGINEER_MAXAMMO_NAIL; self.maxammo_shells = PC_ENGINEER_MAXAMMO_SHOT; From 1b1448fd7ba5ec4b4d674e18c06a79e677e8ddb0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 13 Aug 2014 10:05:52 +0200 Subject: [PATCH 0116/2474] Increase Dispenser restock rate depending on player count (#93) --- engineer.qc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/engineer.qc b/engineer.qc index 8c5adb87..df79182a 100644 --- a/engineer.qc +++ b/engineer.qc @@ -412,12 +412,17 @@ void (entity bld) CheckBelowBuilding = { }; void (entity disp) Dispenser_AmmoTick = { + local float rate; + + // set restock rate (scales with players on team) + rate = 1.5 * (TeamFortress_TeamGetNoPlayers(disp.team_no) - 1); + if (self.disptimer > 3) { - self.ammo_shells = self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS / 150); - self.ammo_cells = self.ammo_cells + rint(BUILD_DISPENSER_MAX_CELLS / 150); - self.ammo_nails = self.ammo_nails + rint(BUILD_DISPENSER_MAX_NAILS / 150); - self.ammo_rockets = self.ammo_rockets + rint(BUILD_DISPENSER_MAX_ROCKETS / 150); - self.armorvalue = self.armorvalue + rint(BUILD_DISPENSER_MAX_ARMOR / 150); + self.ammo_shells = self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS * rate / 300); + self.ammo_cells = self.ammo_cells + rint(BUILD_DISPENSER_MAX_CELLS * rate / 300); + self.ammo_nails = self.ammo_nails + rint(BUILD_DISPENSER_MAX_NAILS * rate / 300); + self.ammo_rockets = self.ammo_rockets + rint(BUILD_DISPENSER_MAX_ROCKETS * rate / 300); + self.armorvalue = self.armorvalue + rint(BUILD_DISPENSER_MAX_ARMOR * rate / 300); if (self.ammo_shells > BUILD_DISPENSER_MAX_SHELLS) self.ammo_shells = BUILD_DISPENSER_MAX_SHELLS; From 13bef35998e95b3f4cb2fd4c37ca2896eca4b7a0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 13 Aug 2014 10:07:24 +0200 Subject: [PATCH 0117/2474] Increase rockets effect on Dispenser explosions (closes #93) --- engineer.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engineer.qc b/engineer.qc index df79182a..19be0706 100644 --- a/engineer.qc +++ b/engineer.qc @@ -736,9 +736,9 @@ void () Dispenser_Explode = { if (self.real_owner.has_disconnected != 1) { deathmsg = 39; - sdmg = 25 + self.ammo_rockets * 1.5 + self.ammo_cells; - if (sdmg > 250) { - sdmg = 250; + sdmg = 45 + self.ammo_rockets * 3 + self.ammo_cells; + if (sdmg > 350) { + sdmg = 350; } T_RadiusDamage(self, self.real_owner, sdmg, self); } From c0699b1e2a0a10e3c417e591ffc520ec3c697915 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 13 Aug 2014 11:18:12 +0200 Subject: [PATCH 0118/2474] Fix stuck spawning and telefragging (by hifi) (closes #16) --- client.qc | 94 ++++++++++++++++++++++++++--------------------------- tfort.qc | 1 + tfortmap.qc | 6 ++-- 3 files changed, 50 insertions(+), 51 deletions(-) diff --git a/client.qc b/client.qc index 6402c587..92ff25fa 100644 --- a/client.qc +++ b/client.qc @@ -755,10 +755,27 @@ entity lastspawn_team2; entity lastspawn_team3; entity lastspawn_team4; +float (vector orig) CheckSpawnPoint = +{ + local entity at_spot; + + at_spot = findradius(orig, 60); + while (at_spot != world) { + if ((at_spot.classname == "player") && (at_spot.deadflag == 0)) { + if (at_spot.team_no == self.team_no) + return 0; + else + return 1; + } + at_spot = at_spot.chain; + } + + return 1; +}; + entity(float team_num) FindTeamSpawnPoint = { local entity spot; - local entity at_spot; local float spot_found; local float attempts; @@ -774,14 +791,7 @@ entity(float team_num) FindTeamSpawnPoint = if (spot == world) return (world); - at_spot = findradius(spot.origin, 40); - spot_found = 1; - while (at_spot != world) { - if ((at_spot.classname == "player") && - (at_spot.deadflag == 0)) - spot_found = 0; - at_spot = at_spot.chain; - } + spot_found = CheckSpawnPoint(spot.origin); if (!Activated(spot, self)) spot_found = 0; if (spot_found || (attempts >= 30)) { @@ -799,14 +809,7 @@ entity(float team_num) FindTeamSpawnPoint = spot = find(world, team_str_home, "ts2"); if (spot == world) return (world); - at_spot = findradius(spot.origin, 40); - spot_found = 1; - while (at_spot != world) { - if ((at_spot.classname == "player") && - (at_spot.deadflag == 0)) - spot_found = 0; - at_spot = at_spot.chain; - } + spot_found = CheckSpawnPoint(spot.origin); if (!Activated(spot, self)) spot_found = 0; if (spot_found || (attempts >= 30)) { @@ -824,14 +827,7 @@ entity(float team_num) FindTeamSpawnPoint = spot = find(world, team_str_home, "ts3"); if (spot == world) return (world); - at_spot = findradius(spot.origin, 40); - spot_found = 1; - while (at_spot != world) { - if ((at_spot.classname == "player") && - (at_spot.deadflag == 0)) - spot_found = 0; - at_spot = at_spot.chain; - } + spot_found = CheckSpawnPoint(spot.origin); if (!Activated(spot, self)) spot_found = 0; if (spot_found || (attempts >= 30)) { @@ -849,14 +845,7 @@ entity(float team_num) FindTeamSpawnPoint = spot = find(world, team_str_home, "ts4"); if (spot == world) return (world); - at_spot = findradius(spot.origin, 40); - spot_found = 1; - while (at_spot != world) { - if ((at_spot.classname == "player") && - (at_spot.deadflag == 0)) - spot_found = 0; - at_spot = at_spot.chain; - } + spot_found = CheckSpawnPoint(spot.origin); if (!Activated(spot, self)) spot_found = 0; if (spot_found || (attempts >= 30)) { @@ -871,11 +860,9 @@ entity(float team_num) FindTeamSpawnPoint = void (entity e) ValidateUser = { }; -entity()SelectSpawnPoint = +entity () SelectSpawnPoint = { local entity spot; - local entity at_spot; - local float spot_found; local float attempts; if (self.team_no != 0) { @@ -900,16 +887,7 @@ entity()SelectSpawnPoint = attempts = 0; while ((spot != world) && (attempts < 100)) { attempts = attempts + 1; - at_spot = findradius(spot.origin, 40); - spot_found = 1; - while (at_spot) { - if ((at_spot.classname == "player") && - (at_spot.deadflag == 0)) { - spot_found = 0; - } - at_spot = at_spot.chain; - } - if (spot_found || (attempts >= 10)) { + if (CheckSpawnPoint(spot.origin) || (attempts >= 10)) { lastspawn = spot; return (spot); } @@ -939,6 +917,24 @@ void () TeamFortress_SetHealth; void () TeamFortress_SetEquipment; void () player_touch; +// moves the client forward if spawn point is occupied +void () CheckClientSpawn = { + local float attempts; + local vector orig = self.origin; + attempts = 0; + + while (!CheckSpawnPoint(self.origin) && attempts < 30) { + makevectors(self.angles); + self.origin = self.origin + v_forward * 60; + attempts = attempts + 1; + } + + if (attempts == 30) { + dprint("Warning: Could not find a safe spawn point for player!\n"); + self.origin = orig; + } +}; + void () PutClientInServer = { local float oldclass; local entity spot; @@ -1040,13 +1036,15 @@ void () PutClientInServer = { self.pausetime = 0; spot = SelectSpawnPoint(); - if (self.playerclass != 0) - spawn_tdeath(spot.origin, self); self.observer_list = spot; self.origin = spot.origin + '0 0 1'; self.angles = spot.angles; self.fixangle = 1; + CheckClientSpawn(); + + if (self.playerclass != 0) + spawn_tdeath(self.origin, self); if ((spot.classname == "info_player_teamspawn") && (cb_prematch_time < time)) { diff --git a/tfort.qc b/tfort.qc index 4c768940..f24e0350 100644 --- a/tfort.qc +++ b/tfort.qc @@ -147,6 +147,7 @@ void (float inp) TeamFortress_ChangeClass = { self.origin = spot.origin + '0 0 1'; self.angles = spot.angles; self.fixangle = 1; + CheckClientSpawn(); setmodel(self, string_null); modelindex_null = self.modelindex; diff --git a/tfortmap.qc b/tfortmap.qc index f11e4718..a90e9436 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2497,13 +2497,13 @@ void (entity P) ForceRespawn = { oldself = self; self = P; spot = SelectSpawnPoint(); - if (self.playerclass != 0) { - spawn_tdeath(spot.origin, self); - } self.observer_list = spot; self.origin = spot.origin + '0 0 1'; self.angles = spot.angles; self.fixangle = 1; + CheckClientSpawn(); + if (self.playerclass != 0) + spawn_tdeath(self.origin, self); if ((spot.classname == "info_player_teamspawn") && (cb_prematch_time < time)) { if (spot.items != 0) { From 9cd42498fbd37ff46d8f502e23a076fe07095b0e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 13 Aug 2014 11:52:13 +0200 Subject: [PATCH 0119/2474] Flag no longer stays in air if aiming down when dropping it (fixes #106) --- tfortmap.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index a90e9436..ac1cd318 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2197,7 +2197,7 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { setsize(Item, Item.goal_min, Item.goal_max); if (PAlive == 1) { makevectors(P.v_angle); - if (P.v_angle_x) { + if (P.v_angle_x < 25) { Item.velocity = (v_forward * 400) + (v_up * 200); } else { Item.velocity = aim(P, 10000); From f6e6f14a70d85aa35742131dd27f4f6c49ab6aab Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 13 Aug 2014 14:02:58 +0200 Subject: [PATCH 0120/2474] Dispenser now restocks even if Engineer is only team member --- engineer.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engineer.qc b/engineer.qc index 19be0706..9f11e53f 100644 --- a/engineer.qc +++ b/engineer.qc @@ -415,7 +415,7 @@ void (entity disp) Dispenser_AmmoTick = { local float rate; // set restock rate (scales with players on team) - rate = 1.5 * (TeamFortress_TeamGetNoPlayers(disp.team_no) - 1); + rate = 1 + 0.5 * (TeamFortress_TeamGetNoPlayers(disp.team_no) - 1); if (self.disptimer > 3) { self.ammo_shells = self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS * rate / 300); From 54d8145432e071773b22acb208ca998e0d9f3b77 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 13 Aug 2014 14:22:47 +0200 Subject: [PATCH 0121/2474] Swap credits order --- tforthlp.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tforthlp.qc b/tforthlp.qc index eab32354..a9158fb0 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -24,7 +24,7 @@ void () TeamFortress_MOTD = { st1 = strcat(strcat(st1, "\n"), st2); } } else { - st1 = "Welcome to Classic Fortress\nby hifi & Empezar\n==================================\ngithub.com/classic-fortress"; + st1 = "Welcome to Classic Fortress\nby Empezar & hifi\n==================================\ngithub.com/classic-fortress"; } sprint(self, PRINT_HIGH, st1); From 50d995126072eb01a9e62f4e534cb28e187dabbf Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 14 Aug 2014 21:37:18 +0200 Subject: [PATCH 0122/2474] Fix bioweapon death message (fixes #107) --- client.qc | 13 ++++++++----- defs.h | 4 ++-- tfort.qc | 2 +- weapons.qc | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/client.qc b/client.qc index 92ff25fa..8454ee41 100644 --- a/client.qc +++ b/client.qc @@ -1849,10 +1849,8 @@ void () ClientDisconnect = { void (entity targ, entity attacker) ClientObituary = { local float rnum; - local string deathstring; - local string deathstring2; - deathstring = ""; - deathstring2 = ""; + local string deathstring = ""; + local string deathstring2 = ""; Sniper_ZoomReset(targ); @@ -1952,6 +1950,8 @@ void (entity targ, entity attacker) ClientObituary = { " detonates an ammo box too close to him\n"; else if (deathmsg == DMSG_DETPACK) deathstring = " set the detpack and forgot to run\n"; + else if (deathmsg == DMSG_BIOWEAPON) + deathstring = " died impossibly!\n"; else if (deathmsg == DMSG_ROCKETL) { if (rnum) deathstring = " becomes bored with life\n"; @@ -2080,7 +2080,10 @@ void (entity targ, entity attacker) ClientObituary = { } else if (deathmsg == DMSG_DETPACK_DIS) { deathstring = " cut the red wire of "; deathstring2 = "'s detpack\n"; - } else if (deathmsg == DMSG_MEDIKIT_ATT) { + } else if (deathmsg == DMSG_BIOWEAPON) { + deathstring = " dies from "; + deathstring2 = "'s mysterious tropical disease\n"; + } else if (deathmsg == DMSG_BIOWEAPON_ATT) { deathstring = " escapes infection from "; deathstring2 = " by dying first\n"; } else if (deathmsg == DMSG_GRENADEL) { diff --git a/defs.h b/defs.h index 87138698..d14f0245 100644 --- a/defs.h +++ b/defs.h @@ -1055,8 +1055,8 @@ #define DMSG_GREN_MIRV 10 #define DMSG_GREN_PIPE 11 #define DMSG_DETPACK 12 -// unused 13 -#define DMSG_MEDIKIT_ATT 14 +#define DMSG_BIOWEAPON 13 +#define DMSG_BIOWEAPON_ATT 14 #define DMSG_FLAME 15 #define DMSG_DETPACK_DIS 16 #define DMSG_AXE 17 diff --git a/tfort.qc b/tfort.qc index f24e0350..bd99bbe0 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2650,7 +2650,7 @@ void () BioInfection_Decay = { te = te.chain; } self.nextthink = time + 3; - deathmsg = 13; + deathmsg = DMSG_BIOWEAPON; TF_T_Damage(self.owner, self, self.enemy, 8, TF_TD_IGNOREARMOUR, TF_TD_OTHER); SpawnBlood(self.owner.origin, 30); diff --git a/weapons.qc b/weapons.qc index de94fb13..4903fa6e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -521,7 +521,7 @@ void () W_FireMedikit = { // musn't be on their team, so we infect them trace_ent.axhitme = 1; SpawnBlood(org, 20); - deathmsg = DMSG_MEDIKIT_ATT; + deathmsg = DMSG_BIOWEAPON_ATT; T_Damage(trace_ent, self, self, 10); if (trace_ent.playerclass == PC_MEDIC) From 82954ca21f0622bf2d25af4210297557b343ea0a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 14 Aug 2014 21:40:19 +0200 Subject: [PATCH 0123/2474] Add instruction on how to vote for next map (closes #108) --- vote.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vote.qc b/vote.qc index 67f96b0c..6fe144ab 100644 --- a/vote.qc +++ b/vote.qc @@ -64,9 +64,9 @@ void (entity pe_player) Vote_NextMap = { bprint(PRINT_HIGH, "Commencing vote for next map\n"); } else { if (f_votes_left == 1) - bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed\n"); + bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed (/votenext)\n"); else - bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed\n"); + bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed (/votenext)\n"); } }; From 8e70676cf4c21865ff8da165e3250f86d9ca86f6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 16 Aug 2014 11:57:59 +0200 Subject: [PATCH 0124/2474] Improve weapon slot code (fixes #109 and #110) --- client.qc | 4 +- qw.qc | 14 +++- tfort.qc | 3 +- weapons.qc | 230 ++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 179 insertions(+), 72 deletions(-) diff --git a/client.qc b/client.qc index 8454ee41..dad9ee73 100644 --- a/client.qc +++ b/client.qc @@ -1021,9 +1021,9 @@ void () PutClientInServer = { SetTeamName(self); W_SetCurrentAmmo(); if (self.current_weaponslot && self.last_playerclass == self.playerclass) - W_ChangeWeapon(self.current_weaponslot, 0); + W_ChangeWeapon(self.current_weaponslot); else - W_ChangeWeapon(1, 0); + W_ChangeWeapon(1); self.last_playerclass = self.playerclass; self.attack_finished = time + 0.3; diff --git a/qw.qc b/qw.qc index c30341fa..d47a9846 100644 --- a/qw.qc +++ b/qw.qc @@ -30,6 +30,7 @@ typedef void (float) f_void_float; .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float is_quickfiring; // TRUE for a player if they're using the quick slots +.float has_quickfired; // TRUE for a player that has stopped quick firing (until weapon is ready) .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer .float default_sensitivity; // Player's default (non-zoomed) sensitivity @@ -71,6 +72,7 @@ typedef void (float) f_void_float; .float maxstrafespeed; // Maximum side speed .float weaponmode; // Used for multiple mode weapons +.float last_weaponmode; // Last weapon's weapon mode .float motd; // Used to display MOTD .f_void_float menu_input; @@ -136,14 +138,22 @@ float coop; /*==============================================*/ .float weapons_carried; // the weapons the player is carrying .float current_weapon; // the weapon the player is using +.float last_weapon; // the last weapon the player was using .float current_weaponslot; // the currently equipped weaponslot -.float real_weaponslot; // the actual equipped weaponslot (during a quick slot attack) .float last_weaponslot; // the last equipped weaponslot .float queue_weaponslot; // the weaponslot to switch to when possible -.float queue_last_weaponslot; // the weaponslot to set as last weaponslot when possible +.float queue_weaponstate; // the weaponstate to load when possible .float next_weapon; // used by weapon slots to communicate which weapon to select .float next_weaponmode; // used by weapon slots to communicate which weapon mode to select +// weapon states +.float weaponstate_current_weaponslot; +.float weaponstate_last_weaponslot; +.float weaponstate_current_weapon; +.float weaponstate_last_weapon; +.float weaponstate_weaponmode; +.float weaponstate_last_weaponmode; + .float ammo_medikit; // Ammo used for the medikit .float maxammo_medikit; .float ammo_detpack; // Ammo used for the detpack diff --git a/tfort.qc b/tfort.qc index bd99bbe0..64c7af48 100644 --- a/tfort.qc +++ b/tfort.qc @@ -209,7 +209,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(1, 0); + W_ChangeWeapon(1); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; @@ -1350,7 +1350,6 @@ void () TeamFortress_SetEquipment = { self.weaponmode = 0; self.current_weaponslot = 1; self.last_weaponslot = 1; - self.real_weaponslot = 1; } self.tf_items = 0; diff --git a/weapons.qc b/weapons.qc index 4903fa6e..36a50e94 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1779,6 +1779,14 @@ void () W_Attack = { } }; +float () WeaponReady = { + if (time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) { + return 1; + } + + return 0; +} + void () W_PrintWeaponMessage = { if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { if (self.weaponmode == GL_NORMAL) @@ -1976,65 +1984,102 @@ void () W_AmmoError = { sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); }; -void (float inp, float quick) W_ChangeWeapon = { - if (self.playerclass == 0) +void () W_WeaponState_Save = { + if (!WeaponReady()) return; - // queue next weapon (in case of attack/reload in progress) - if (!self.queue_weaponslot || self.queue_weaponslot != inp) { - if (inp == TF_WEAPLAST && !quick) { - self.queue_weaponslot = self.last_weaponslot; - } else if (inp == TF_WEAPLAST && quick && !self.is_quickfiring) { - if (!(self.tfstate & TFSTATE_RELOADING) && time >= self.attack_finished) { - self.queue_weaponslot = self.real_weaponslot; - self.current_weaponslot = self.queue_weaponslot; - } - } else if (inp < 5 && !quick) { - if (is_quickfiring) - self.queue_last_weaponslot = self.real_weaponslot; - self.queue_weaponslot = inp; - } else if (inp < 5 && quick) { - if (!(self.tfstate & TFSTATE_RELOADING) && time >= self.attack_finished) - self.queue_weaponslot = inp; - } + self.weaponstate_current_weaponslot = self.current_weaponslot; + self.weaponstate_last_weaponslot = self.last_weaponslot; + self.weaponstate_current_weapon = self.current_weapon; + self.weaponstate_last_weapon = self.last_weapon; + self.weaponstate_weaponmode = self.weaponmode; + self.weaponstate_last_weaponmode = self.last_weaponmode; +} + +void (float swap) W_WeaponState_Load = { + if (!swap) { + self.current_weaponslot = self.weaponstate_current_weaponslot; + self.last_weaponslot = self.weaponstate_last_weaponslot; + self.current_weapon = self.weaponstate_current_weapon; + self.last_weapon = self.weaponstate_last_weapon; + self.weaponmode = self.weaponstate_weaponmode; + self.last_weaponmode = self.weaponstate_last_weaponmode; + } else { + self.current_weaponslot = self.weaponstate_last_weaponslot; + self.last_weaponslot = self.weaponstate_current_weaponslot; + self.current_weapon = self.weaponstate_last_weapon; + self.last_weapon = self.weaponstate_current_weapon; + self.weaponmode = self.weaponstate_last_weaponmode; + self.last_weaponmode = self.weaponstate_weaponmode; } + self.queue_weaponstate = 0; - // don't do anything yet if still reloading or attack in progress - if ((self.tfstate & TFSTATE_RELOADING) || time < self.attack_finished) + W_WeaponState_Save(); + W_SetCurrentAmmo(); + Status_Refresh(self); +} + +float () W_WeaponState_Check = { + if (self.current_weaponslot == self.weaponstate_current_weaponslot + && self.last_weaponslot == self.weaponstate_last_weaponslot) + return 1; + else + return 0; +} + +void (float inp) W_ChangeWeapon = { + if (inp < 1 || inp > 4) + return; + + if (self.playerclass == 0) + return; + + // queue next weapon if queue is not empty or has changed + if (!self.queue_weaponslot || inp != self.queue_weaponslot) + self.queue_weaponslot = inp; + + // halt if weapon is not ready to be fired + if (!WeaponReady()) return; // check for ammo - if (! W_AmmoSlot(self.queue_weaponslot)) { + if (! W_AmmoSlot(inp)) { W_AmmoError(); self.queue_weaponslot = 0; return; } - W_WeaponSlot(self.queue_weaponslot); + W_WeaponSlot(inp); // don't update current/last weapon information if next weapon is the same as current if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { - if (quick) { - self.real_weaponslot = self.current_weaponslot; - } else { - self.real_weaponslot = self.queue_weaponslot; - self.last_weaponslot = self.current_weaponslot; - } - if (self.queue_last_weaponslot) - self.last_weaponslot = self.queue_last_weaponslot; + self.last_weaponslot = self.current_weaponslot; self.current_weaponslot = self.queue_weaponslot; + self.last_weapon = self.current_weapon; self.current_weapon = self.next_weapon; + self.last_weaponmode = self.weaponmode; self.weaponmode = self.next_weaponmode; - // only print out weapon messages for non-quick weapons - if (!quick) + if (!self.is_quickfiring) W_PrintWeaponMessage(); } + if (!self.is_quickfiring && !self.has_quickfired) + W_WeaponState_Save(); + W_SetCurrentAmmo(); Status_Refresh(self); self.queue_weaponslot = 0; - self.queue_last_weaponslot = 0; +}; + +void () CycleWeaponLast = { + if (!self.last_weaponslot) + return; + + if (!self.is_quickfiring) + W_ChangeWeapon(self.last_weaponslot); + else + W_WeaponState_Load(1); }; void () CycleWeaponNext = { @@ -2042,8 +2087,6 @@ void () CycleWeaponNext = { if (self.weaponmodel == string_null || self.current_weapon == 0) return; - if (self.tfstate & TFSTATE_RELOADING) - return; next = 0; for (slot = 1; slot <= 4; slot++) { @@ -2054,7 +2097,7 @@ void () CycleWeaponNext = { break; } } - W_ChangeWeapon(next, 0); + W_ChangeWeapon(next); }; void () CycleWeaponPrev = { @@ -2062,8 +2105,6 @@ void () CycleWeaponPrev = { if (self.weaponmodel == string_null || self.current_weapon == 0) return; - if (self.tfstate & TFSTATE_RELOADING) - return; next = 0; for (slot = 1; slot <= 4; slot++) { @@ -2074,7 +2115,7 @@ void () CycleWeaponPrev = { break; } } - W_ChangeWeapon(next, 0); + W_ChangeWeapon(next); }; void () PreMatchImpulses; @@ -2112,12 +2153,12 @@ void () ImpulseCommands = { if (self.is_building == 1) { if (self.impulse >= 1 && self.impulse <= 5) { TeamFortress_EngineerBuildStop(); - W_ChangeWeapon(self.impulse, 0); + W_ChangeWeapon(self.impulse); } else if (self.impulse == TF_WEAPNEXT || self.impulse == TF_WEAPPREV || self.impulse == TF_WEAPLAST) { TeamFortress_EngineerBuildStop(); - W_ChangeWeapon(self.impulse, 0); + W_ChangeWeapon(self.impulse); } } @@ -2126,8 +2167,6 @@ void () ImpulseCommands = { CycleWeaponNext(); else if (self.impulse == TF_WEAPPREV) CycleWeaponPrev(); - else if (self.impulse == TF_WEAPLAST && self.last_weaponslot != 0) - W_ChangeWeapon(self.impulse, 0); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); else if (self.impulse == TF_DETPACK_5) @@ -2212,9 +2251,9 @@ void () ImpulseCommands = { void () PreMatchImpulses = { if (((self.impulse >= 1) && (self.impulse < 8)) || (self.impulse == TF_MEDIKIT)) - W_ChangeWeapon(self.impulse, 0); + W_ChangeWeapon(self.impulse); else if (self.impulse == AXE_IMP) - W_ChangeWeapon(self.impulse, 0); + W_ChangeWeapon(self.impulse); else if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); else if (self.impulse == TF_WEAPPREV) @@ -2349,44 +2388,103 @@ void () W_WeaponFrame = { TeamFortress_SpyGoUndercover(); else if (self.playerclass == PC_DEMOMAN) TeamFortress_DetpackMenu(); + + self.impulse = 0; + return; + } + + if (self.impulse == TF_WEAPLAST) { + + // change to last weapon now + if (WeaponReady()) + CycleWeaponLast(); + // change to weaponstate (prior to quick fire) when weapon is ready + else if (self.is_quickfiring) + self.queue_weaponstate = 2; + // change to last weapon when weapon is ready + else + self.queue_weaponslot = self.last_weaponslot; } - if (self.impulse == TF_QUICKSTOP) + // when +slotX bind is released, this gets issued + if (self.impulse == TF_QUICKSTOP && self.is_quickfiring) { + + self.has_quickfired = 1; + self.impulse = 0; + + } + + // unset quick firing variables when quick weapon has finished firing + if (self.is_quickfiring && self.has_quickfired && WeaponReady()) { + self.is_quickfiring = 0; + self.has_quickfired = 0; + + } + + // slot 1-4 binds + if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady()) { - if (self.impulse >= 1 && self.impulse <= 4) { + // load weapon state if current state doesn't match stored state + if (!W_WeaponState_Check()) + W_WeaponState_Load(0); + + // obviously not quickfiring if we're changing weapon self.is_quickfiring = 0; - W_ChangeWeapon(self.impulse, 0); - } else if (self.impulse >= 31 && self.impulse <= 34 && !(self.tfstate & TFSTATE_RELOADING)) { + self.has_quickfired = 0; + W_ChangeWeapon(self.impulse); + + // regular attack (both +attack and -attack) + } else if (!self.impulse && !self.is_quickfiring) { + + // load weapon state if current state doesn't match + // stored state, if weapon is ready + if (!W_WeaponState_Check() && WeaponReady() && !(self.tfstate & TFSTATE_AIMING)) + W_WeaponState_Load(0); + + // +slot1-4 quick fire + } else if (self.impulse >= 31 && self.impulse <= 34) { + self.is_quickfiring = 1; - W_ChangeWeapon((self.impulse - 30), 1); - } else if (self.queue_weaponslot) - W_ChangeWeapon(self.queue_weaponslot, 0); - else if (self.real_weaponslot != self.current_weaponslot - && time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) { - if (W_AmmoSlot(self.real_weaponslot)) - W_ChangeWeapon(TF_WEAPLAST, 1); - else { - W_AmmoError(); - self.real_weaponslot = W_BestWeaponSlot(); - W_ChangeWeapon(self.real_weaponslot, 0); - } + self.has_quickfired = 0; + + if (WeaponReady()) + W_ChangeWeapon((self.impulse - 30)); + + // change weapon if queue_weaponslot has been set + } else if (self.queue_weaponslot > 0) { + + W_ChangeWeapon(self.queue_weaponslot); + + // load weapon state + } else if (self.queue_weaponstate && WeaponReady()) { + + // load weaponstate saved from before quick fire started + if (self.queue_weaponstate == 1) + W_WeaponState_Load(0); + + // load swapped weaponstate + else + W_WeaponState_Load(1); + } if (self.impulse == TF_CHANGETEAM) { Menu_Team(); + self.impulse = 0; return; } if (self.impulse == TF_CHANGECLASS) { Menu_Class(); + self.impulse = 0; return; } if (intermission_running || cease_fire) return; - // grenade impulses always possible - if (self.impulse >= 150 && self.impulse <= 155) { + // class specials and grenade impulses always possible + if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= 150 && self.impulse <= 155)) { ImpulseCommands(); return; } @@ -2423,7 +2521,7 @@ void () W_WeaponFrame = { } } - if (time < self.attack_finished) + if (!WeaponReady()) return; if (self.impulse != 0 && self.has_disconnected == 0) @@ -2439,7 +2537,7 @@ void () W_WeaponFrame = { TeamFortress_SetSpeed(self); player_run(); } else if (self.button0 && !self.fire_held_down) { - if (self.current_weapon == WEAP_SNIPER_RIFLE && !(self.tfstate & TFSTATE_RELOADING)) { + if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) self.heat = self.heat + 3; From c75660109532132462c90406194d72737bb417f8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 16 Aug 2014 12:33:31 +0200 Subject: [PATCH 0125/2474] Increase time to let caltrops fly before being removed (fixes #111) --- scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scout.qc b/scout.qc index c200f8d3..613cc74d 100644 --- a/scout.qc +++ b/scout.qc @@ -65,7 +65,7 @@ void () CaltropScatterThink = { } } self.heat = self.heat + 1; - if (self.heat > 10) { + if (self.heat > 50) { remove(self); return; } From 5f9f2ba61ac97063e8dc35ed86f49671816b6ebe Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 16 Aug 2014 13:12:30 +0200 Subject: [PATCH 0126/2474] Fixed Sniper/HWGuy special --- weapons.qc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/weapons.qc b/weapons.qc index 36a50e94..24f40fe7 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2483,12 +2483,6 @@ void () W_WeaponFrame = { if (intermission_running || cease_fire) return; - // class specials and grenade impulses always possible - if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= 150 && self.impulse <= 155)) { - ImpulseCommands(); - return; - } - // hwguy assault cannon special if (self.playerclass == PC_HVYWEAP) { if ((self.impulse == TF_SPECIAL_SKILL || self.impulse == TF_HALT) && !(self.tfstate & TFSTATE_HALT)) { @@ -2521,6 +2515,12 @@ void () W_WeaponFrame = { } } + // class specials and grenade impulses always possible + if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= 150 && self.impulse <= 155)) { + ImpulseCommands(); + return; + } + if (!WeaponReady()) return; From 7ab31236c147db66e06e2d24c68085a2e613ffef Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 17 Aug 2014 08:06:56 +0200 Subject: [PATCH 0127/2474] Remember Scanner status across deaths (fixes #113) --- tfort.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index 64c7af48..4e7aa928 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1353,8 +1353,10 @@ void () TeamFortress_SetEquipment = { } self.tf_items = 0; - if (self.playerclass != PC_SCOUT) + if (self.playerclass != PC_SCOUT) { self.tf_items_flags = 0; + self.ScannerOn = 0; + } self.armorclass = 0; self.impulse = 0; @@ -1435,7 +1437,6 @@ void () TeamFortress_SetEquipment = { self.tp_grenades_2 = GR_TYPE_CALTROP; self.tf_items = PC_SCOUT_TF_ITEMS; - self.ScannerOn = 0; if (self.tf_items_flags <= 0) self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY; From f5d29e5c77d56dd5bd572943455029aad5e62084 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 17 Aug 2014 09:41:58 +0200 Subject: [PATCH 0128/2474] Implement quick reload aliases (closes #112) --- actions.qc | 67 ++++++-- client.qc | 4 +- defs.h | 10 +- demoman.qc | 4 +- engineer.qc | 12 +- items.qc | 10 +- menu.qc | 4 +- player.qc | 2 +- pyro.qc | 4 +- scout.qc | 8 +- spy.qc | 2 +- tfort.qc | 8 +- tforthlp.qc | 4 + tfortmap.qc | 4 +- weapons.qc | 449 +++++++++++++++++++++++++++++----------------------- 15 files changed, 347 insertions(+), 245 deletions(-) diff --git a/actions.qc b/actions.qc index 7ad37571..0536f4d2 100644 --- a/actions.qc +++ b/actions.qc @@ -43,7 +43,7 @@ void () TeamFortress_Discard = { if (newmis.ammo_cells) { self.ammo_cells = 0; } - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); sound(self, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); newmis.enemy = self; newmis.health = time; @@ -257,7 +257,7 @@ void () TeamFortress_ID = { } }; -void () TeamFortress_ReloadCurrentWeapon = { +void (float weap) TeamFortress_ReloadWeapon = { local float reloadtime = 0; local float reloadamount = 0; local entity tWeapon, tClip; @@ -265,7 +265,7 @@ void () TeamFortress_ReloadCurrentWeapon = { if (self.tfstate & TFSTATE_RELOADING) { return; } - if (self.current_weapon == WEAP_SHOTGUN) { + if (weap == WEAP_SHOTGUN) { if (self.ammo_shells == 0) { sprint(self, PRINT_HIGH, "Out of shells\n"); return; @@ -291,7 +291,7 @@ void () TeamFortress_ReloadCurrentWeapon = { if (self.ammo_shells < 8) { self.reload_shotgun = 8 - self.ammo_shells; } - sprint(self, PRINT_HIGH, "Reloading...\n"); + sprint(self, PRINT_HIGH, "Reloading Shotgun...\n"); self.tfstate = self.tfstate | TFSTATE_RELOADING; Status_Refresh(self); tWeapon = spawn(); @@ -304,7 +304,7 @@ void () TeamFortress_ReloadCurrentWeapon = { } else { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { + } else if (weap == WEAP_SUPER_SHOTGUN) { if (self.ammo_shells == 0) { sprint(self, PRINT_HIGH, "Out of shells\n"); return; @@ -330,7 +330,7 @@ void () TeamFortress_ReloadCurrentWeapon = { if (self.ammo_shells < 16) { self.reload_super_shotgun = 16 - self.ammo_shells; } - sprint(self, PRINT_HIGH, "Reloading...\n"); + sprint(self, PRINT_HIGH, "Reloading Super Shotgun...\n"); self.tfstate = self.tfstate | TFSTATE_RELOADING; Status_Refresh(self); tWeapon = spawn(); @@ -343,7 +343,7 @@ void () TeamFortress_ReloadCurrentWeapon = { } else { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } - } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { + } else if (weap == WEAP_SNIPER_RIFLE) { if (self.ammo_shells == 0) { sprint(self, PRINT_HIGH, "Out of shells\n"); return; @@ -369,7 +369,7 @@ void () TeamFortress_ReloadCurrentWeapon = { if (self.ammo_shells < 1) { self.reload_sniper_rifle = 1 - self.ammo_shells; } - sprint(self, PRINT_HIGH, "Reloading...\n"); + sprint(self, PRINT_HIGH, "Reloading Sniper Rifle...\n"); self.tfstate = self.tfstate | TFSTATE_RELOADING; Status_Refresh(self); tWeapon = spawn(); @@ -382,7 +382,7 @@ void () TeamFortress_ReloadCurrentWeapon = { } else { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } - } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { + } else if (weap == WEAP_GRENADE_LAUNCHER) { if (self.ammo_rockets == 0) { sprint(self, PRINT_HIGH, "Out of grenades\n"); return; @@ -410,7 +410,7 @@ void () TeamFortress_ReloadCurrentWeapon = { self.reload_grenade_launcher = 6 - self.ammo_rockets; } - sprint(self, PRINT_HIGH, "Reloading...\n"); + sprint(self, PRINT_HIGH, "Reloading Grenade Launcher...\n"); self.tfstate = self.tfstate | TFSTATE_RELOADING; Status_Refresh(self); tWeapon = spawn(); @@ -423,7 +423,7 @@ void () TeamFortress_ReloadCurrentWeapon = { } else { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } - } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { + } else if (weap == WEAP_ROCKET_LAUNCHER) { if (self.ammo_rockets == 0) { sprint(self, PRINT_HIGH, "Out of rockets\n"); return; @@ -451,7 +451,7 @@ void () TeamFortress_ReloadCurrentWeapon = { self.reload_rocket_launcher = 4 - self.ammo_rockets; } - sprint(self, PRINT_HIGH, "Reloading...\n"); + sprint(self, PRINT_HIGH, "Reloading Rocket Launcher...\n"); self.tfstate = self.tfstate | TFSTATE_RELOADING; Status_Refresh(self); tWeapon = spawn(); @@ -476,6 +476,49 @@ void () TeamFortress_ReloadCurrentWeapon = { } }; +void () TeamFortress_ReloadCurrentWeapon = { + TeamFortress_ReloadWeapon(self.current_weapon); +}; + +void (float slot) TeamFortress_ReloadSlot = { + local float weap = 0; + + if (slot < 1 || slot > 3) + return; + + if (slot == 1) + weap = W_WeaponSlot1(); + else if (slot == 2) + weap = W_WeaponSlot2(); + else if (slot == 3) + weap = W_WeaponSlot3(); + + TeamFortress_ReloadWeapon(weap); +}; + +void () TeamFortress_ReloadNext = { + local float slot, weap = 0; + + // reload current slot first + slot = W_GetSlot(self.current_weapon); + weap = W_WeaponSlot1(); + if (CheckForAmmo(weap)) + TeamFortress_ReloadWeapon(weap); + + // then go through each slot + for (slot = 1; slot < 4; slot++) { + if (slot == 1) + weap = W_WeaponSlot1(); + else if (slot == 2) + weap = W_WeaponSlot2(); + else if (slot == 3) + weap = W_WeaponSlot3(); + + if (CheckForAmmo(weap)) + TeamFortress_ReloadWeapon(weap); + } +}; + void () TeamFortress_ClipTick = { if (time < self.owner.reload_time) { self.owner.reload_clipsize = self.owner.reload_clipsize + 1; diff --git a/client.qc b/client.qc index dad9ee73..d24004b5 100644 --- a/client.qc +++ b/client.qc @@ -1019,7 +1019,7 @@ void () PutClientInServer = { stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); if (self.current_weaponslot && self.last_playerclass == self.playerclass) W_ChangeWeapon(self.current_weaponslot); else @@ -1484,7 +1484,7 @@ void () PlayerPreThink = { (self.weapon > 16)) { self.weapon = W_BestWeapon(); self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); } }; diff --git a/defs.h b/defs.h index d14f0245..f8b83a87 100644 --- a/defs.h +++ b/defs.h @@ -370,6 +370,13 @@ #define TF_VOTENEXT 70 #define TF_FORCENEXT 71 +// Reload impulses +#define TF_RELOAD_SLOT1 73 +#define TF_RELOAD_SLOT2 74 +#define TF_RELOAD_SLOT3 75 +#define TF_RELOAD_NEXT 76 +#define TF_RELOAD 173 + #define TF_CHANGETEAM 98 #define TF_CHANGECLASS 99 // Added to PC_??? to get impulse to use if this clashes with your @@ -442,9 +449,6 @@ // Ammo Drop impulse #define TF_DROP_AMMO 172 -// Reload impulse -#define TF_RELOAD 173 - // drop/pass commands #define TF_DROPKEY 175 diff --git a/demoman.qc b/demoman.qc index 0b83897f..ad7049ba 100644 --- a/demoman.qc +++ b/demoman.qc @@ -226,7 +226,7 @@ void () TeamFortress_DetpackStop = { self.current_weapon = self.weapon; Status_Refresh(self); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); TeamFortress_SetSpeed(self); self.pausetime = time; }; @@ -252,7 +252,7 @@ void () TeamFortress_DetpackSet = { self.is_detpacking = 0; self.current_weapon = self.weapon; Status_Refresh(self); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = oldself; newmis = spawn(); diff --git a/engineer.qc b/engineer.qc index 9f11e53f..2ca77bd9 100644 --- a/engineer.qc +++ b/engineer.qc @@ -215,7 +215,7 @@ void () EMPGrenadeExplode = { } oldself = self; self = te; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = oldself; } else { te.think = SUB_Remove; @@ -265,7 +265,7 @@ void () TeamFortress_EngineerBuildStop = { } self.is_building = 0; self.current_weapon = self.weapon; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); } float (entity obj, entity builder) CheckArea = { @@ -702,7 +702,7 @@ void () TeamFortress_FinishedBuilding = { newmis.maxammo_shells = 100; newmis.maxammo_rockets = 20; } - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = oldself; }; @@ -830,7 +830,7 @@ void (entity disp) Engineer_Dispenser_InsertAmmo = { disp.ammo_cells = (disp.ammo_cells + cells); if ((shells + nails + rockets + cells) > 0) { - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); sprint(self, PRINT_HIGH, "You insert "); if (shells > 0) sprint(self, PRINT_HIGH, ftos(shells), " shells"); @@ -985,7 +985,7 @@ void (entity gun) Engineer_SentryGun_InsertAmmo = { } if ((shells + rockets) > 0) { - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); ammo = "You insert "; if (shells > 0) ammo = strcat(ammo, strcat(ftos(floor(shells)), " shells")); @@ -1084,7 +1084,7 @@ void (entity eng, string bld) DestroyBuilding = { self = eng; self.ammo_cells = self.ammo_cells + 100; bound_other_ammo(self); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = oldself; } if (te.real_owner.building == te) { diff --git a/items.qc b/items.qc index a5034468..11183ab4 100644 --- a/items.qc +++ b/items.qc @@ -262,7 +262,7 @@ void () health_touch = { self.think = SUB_regen; } activator = other; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); SUB_UseTargets(); } } @@ -398,7 +398,7 @@ void () armor_touch = { } oldself = self; self = other; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = oldself; } value = other.maxarmor; @@ -662,7 +662,7 @@ void () weapon_touch = { stemp = self; self = other; Deathmatch_Weapon(old, new); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = stemp; if (leave) return; @@ -895,7 +895,7 @@ void () ammo_touch = { sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); stemp = self; self = other; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = stemp; } Respawn_Item(self, other); @@ -1372,7 +1372,7 @@ void () BackpackTouch = { stuffcmd(other, "bf\n"); dremove(self); self = other; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); }; void () DropBackpack = { diff --git a/menu.qc b/menu.qc index 1346235e..ba3374eb 100644 --- a/menu.qc +++ b/menu.qc @@ -40,7 +40,7 @@ void (entity disp) Engineer_SentryGun_Repair; void (entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage; -void () W_SetCurrentAmmo; +void (entity pl) W_SetCurrentAmmo; void (entity p) bound_other_ammo; float (float v) anglemod; @@ -782,7 +782,7 @@ void (float inp) Menu_Dispenser_Input = { self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)); } - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); } }; diff --git a/player.qc b/player.qc index 4c77eb29..c35af1e6 100644 --- a/player.qc +++ b/player.qc @@ -494,7 +494,7 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); W_PrintWeaponMessage(); return; } diff --git a/pyro.qc b/pyro.qc index adf89686..6cee8979 100644 --- a/pyro.qc +++ b/pyro.qc @@ -691,7 +691,7 @@ void () TeamFortress_IncendiaryCannon = { return; } self.current_weapon = WEAP_INCENDIARY; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); }; void () TeamFortress_FlameThrower = { @@ -703,5 +703,5 @@ void () TeamFortress_FlameThrower = { return; } self.current_weapon = WEAP_FLAMETHROWER; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); }; diff --git a/scout.qc b/scout.qc index 613cc74d..a1873992 100644 --- a/scout.qc +++ b/scout.qc @@ -386,7 +386,7 @@ void () TeamFortress_Scan = { sprint(self.owner, PRINT_HIGH, "Not enough cells to run scanner\n"); self.owner.ammo_cells = 0; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self.owner.ScannerOn = 0; dremove(self); return; @@ -394,7 +394,7 @@ void () TeamFortress_Scan = { if (scancost > self.owner.ammo_cells) { scanrange = self.owner.ammo_cells * 20; scancost = self.owner.ammo_cells; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); } scen = 0; scfr = 0; @@ -414,7 +414,7 @@ void () TeamFortress_Scan = { if (self.owner.ammo_cells < 0) { self.owner.ammo_cells = 0; } - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); scanrange = scanrange * 25; list = T_RadiusScan(self.owner, scanrange, scen, scfr); } @@ -503,7 +503,7 @@ void () TeamFortress_Scan = { self.nextthink = time + 2; return; } - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self.nextthink = time + 2; return; }; diff --git a/spy.qc b/spy.qc index bf398c8f..5fb2e03f 100644 --- a/spy.qc +++ b/spy.qc @@ -389,7 +389,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { self.movetype = 3; self.is_feigning = 0; self.current_weapon = self.weapon; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self.tfstate = self.tfstate - (self.tfstate & 65536); TeamFortress_SetSpeed(self); if (self.weapon <= 16) { diff --git a/tfort.qc b/tfort.qc index 4e7aa928..0bf0b311 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1917,7 +1917,7 @@ void () TeamFortress_SetEquipment = { else if (self.armortype >= 0.3) self.items = self.items | IT_ARMOR1; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); }; float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { @@ -2293,7 +2293,7 @@ void (float type) TeamFortress_DropAmmo = { } self.ammo_cells = self.ammo_cells - ammo; } - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); newmis = spawn(); newmis.aflag = ammo; newmis.weapon = type; @@ -2380,7 +2380,7 @@ void () TeamFortress_AmmoboxTouch = { stuffcmd(other, "bf\n"); dremove(self); self = other; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); }; void () TeamFortress_AssaultWeapon = { @@ -2408,7 +2408,7 @@ void () TeamFortress_AssaultWeapon = { return; } self.current_weapon = WEAP_ASSAULT_CANNON; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); }; void () TeamFortress_ExplodePerson = { diff --git a/tforthlp.qc b/tforthlp.qc index a9158fb0..37a71b61 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -72,6 +72,10 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("weaplast", TF_WEAPLAST, 0); TeamFortress_Alias("detpipe", TF_PB_DETONATE, 0); TeamFortress_Alias("reload", TF_RELOAD, 0); + TeamFortress_Alias("reload1", TF_RELOAD_SLOT1, 0); + TeamFortress_Alias("reload2", TF_RELOAD_SLOT2, 0); + TeamFortress_Alias("reload3", TF_RELOAD_SLOT3, 0); + TeamFortress_Alias("reloadnext", TF_RELOAD_NEXT, 0); TeamFortress_Alias("autoscan", TF_SCAN, 0); TeamFortress_Alias("scansound", TF_SCAN_SOUND, 0); TeamFortress_Alias("scan10", TF_SCAN, 0); diff --git a/tfortmap.qc b/tfortmap.qc index ac1cd318..57077112 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -817,7 +817,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { oldself = self; self = Player; TeamFortress_CheckClassStats(); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = oldself; } if ((Player.playerclass == PC_SPY) && @@ -1013,7 +1013,7 @@ void (entity Goal, entity Player) RemoveResults = { oldself = self; self = Player; TeamFortress_CheckClassStats(); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); self = oldself; }; diff --git a/weapons.qc b/weapons.qc index 24f40fe7..707157b9 100644 --- a/weapons.qc +++ b/weapons.qc @@ -44,6 +44,8 @@ void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void () TeamFortress_ID; void () TeamFortress_ReloadCurrentWeapon; +void (float slot) TeamFortress_ReloadSlot; +void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; void (float zoom_in) Sniper_ZoomAdjust; void () TeamFortress_StatusQuery; @@ -86,6 +88,7 @@ void () TeamFortress_HelpMap; void () BioInfection_Decay; void () BioInfection_MonsterDecay; +void (entity pl, float swap) W_WeaponState_Load; float (float weap) W_GetSlot; float () W_BestWeaponSlot; void () W_FireFlame; @@ -303,7 +306,7 @@ void () W_FireSpanner = { WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); } return; } @@ -1032,14 +1035,14 @@ void () W_FireLightning = { if (self.ammo_cells < 1) { self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); W_PrintWeaponMessage(); return; } if (self.waterlevel > 1) { cells = self.ammo_cells; self.ammo_cells = 0; - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); deathmsg = DMSG_LIGHTNING; T_RadiusDamage(self, self, 35 * cells, world); return; @@ -1239,7 +1242,7 @@ void (float ox) W_FireSpikes = { if (self.ammo_nails < 1) { self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); W_PrintWeaponMessage(); return; } @@ -1337,146 +1340,146 @@ void () superspike_touch = { dremove(self); }; -void () W_SetCurrentAmmo = { - if ((self.health <= 0) || (self.current_weapon == 0)) +void (entity pl) W_SetCurrentAmmo = { + if ((pl.health <= 0) || (pl.current_weapon == 0)) return; player_run(); - self.items = self.items - (self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS)); - self.weapon = 0; + pl.items = pl.items - (pl.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS)); + pl.weapon = 0; - if (self.current_weapon == WEAP_AXE) { - self.currentammo = 0; - if (self.playerclass == 8) { - if (self.weaponmode == 0) - self.weaponmodel = "progs/v_knife.mdl"; + if (pl.current_weapon == WEAP_AXE) { + pl.currentammo = 0; + if (pl.playerclass == 8) { + if (pl.weaponmode == 0) + pl.weaponmodel = "progs/v_knife.mdl"; else - self.weaponmodel = "progs/v_knife2.mdl"; + pl.weaponmodel = "progs/v_knife2.mdl"; } else - self.weaponmodel = "progs/v_axe.mdl"; - self.weaponframe = 0; - } else if (self.current_weapon == WEAP_SPANNER) { - self.currentammo = self.ammo_cells; - self.weaponmodel = "progs/v_span.mdl"; - self.weaponframe = 0; - } else if (self.current_weapon == WEAP_SHOTGUN) { - self.currentammo = self.ammo_shells; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_shot.mdl"; - self.weaponframe = 0; + pl.weaponmodel = "progs/v_axe.mdl"; + pl.weaponframe = 0; + } else if (pl.current_weapon == WEAP_SPANNER) { + pl.currentammo = pl.ammo_cells; + pl.weaponmodel = "progs/v_span.mdl"; + pl.weaponframe = 0; + } else if (pl.current_weapon == WEAP_SHOTGUN) { + pl.currentammo = pl.ammo_shells; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_shot.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_SHELLS; - self.weapon = IT_SHOTGUN; - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - self.currentammo = self.ammo_shells; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_shot2.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_SHELLS; + pl.weapon = IT_SHOTGUN; + } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { + pl.currentammo = pl.ammo_shells; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_shot2.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_SHELLS; - self.weapon = IT_SUPER_SHOTGUN; - } else if (self.current_weapon == WEAP_NAILGUN) { - self.currentammo = self.ammo_nails; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_nail.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_SHELLS; + pl.weapon = IT_SUPER_SHOTGUN; + } else if (pl.current_weapon == WEAP_NAILGUN) { + pl.currentammo = pl.ammo_nails; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_nail.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_NAILS; - self.weapon = IT_NAILGUN; - } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { - self.currentammo = self.ammo_nails; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_nail2.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_NAILS; + pl.weapon = IT_NAILGUN; + } else if (pl.current_weapon == WEAP_SUPER_NAILGUN) { + pl.currentammo = pl.ammo_nails; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_nail2.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_NAILS; - self.weapon = IT_SUPER_NAILGUN; - } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - self.currentammo = self.ammo_rockets; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_rock.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_NAILS; + pl.weapon = IT_SUPER_NAILGUN; + } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { + pl.currentammo = pl.ammo_rockets; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_rock.mdl"; + pl.weaponframe = 0; } - self.weapon = IT_GRENADE_LAUNCHER; - self.items = self.items | IT_ROCKETS; - } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { - self.currentammo = self.ammo_rockets; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_rock2.mdl"; - self.weaponframe = 0; + pl.weapon = IT_GRENADE_LAUNCHER; + pl.items = pl.items | IT_ROCKETS; + } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { + pl.currentammo = pl.ammo_rockets; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_rock2.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_ROCKETS; - self.weapon = IT_ROCKET_LAUNCHER; - } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { - self.currentammo = self.ammo_shells; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_srifle.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_ROCKETS; + pl.weapon = IT_ROCKET_LAUNCHER; + } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { + pl.currentammo = pl.ammo_shells; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_srifle.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_SHELLS; - self.weapon = IT_SHOTGUN; - } else if (self.current_weapon == WEAP_AUTO_RIFLE) { - self.currentammo = self.ammo_shells; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_srifle.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_SHELLS; + pl.weapon = IT_SHOTGUN; + } else if (pl.current_weapon == WEAP_AUTO_RIFLE) { + pl.currentammo = pl.ammo_shells; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_srifle.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_SHELLS; - self.weapon = IT_SUPER_SHOTGUN; - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - self.currentammo = self.ammo_shells; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_asscan.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_SHELLS; + pl.weapon = IT_SUPER_SHOTGUN; + } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { + pl.currentammo = pl.ammo_shells; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_asscan.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_SHELLS; - self.weapon = IT_ROCKET_LAUNCHER; - } else if (self.current_weapon == WEAP_FLAMETHROWER) { - self.currentammo = self.ammo_cells; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_rock.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_SHELLS; + pl.weapon = IT_ROCKET_LAUNCHER; + } else if (pl.current_weapon == WEAP_FLAMETHROWER) { + pl.currentammo = pl.ammo_cells; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_rock.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_CELLS; - self.weapon = IT_GRENADE_LAUNCHER; - } else if (self.current_weapon == WEAP_INCENDIARY) { - self.currentammo = self.ammo_rockets; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_rock2.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_CELLS; + pl.weapon = IT_GRENADE_LAUNCHER; + } else if (pl.current_weapon == WEAP_INCENDIARY) { + pl.currentammo = pl.ammo_rockets; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_rock2.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_ROCKETS; - self.weapon = IT_ROCKET_LAUNCHER; - } else if (self.current_weapon == WEAP_MEDIKIT) { - self.currentammo = self.ammo_medikit; - self.weaponmodel = "progs/v_medi.mdl"; - self.weaponframe = 0; - } else if (self.current_weapon == WEAP_TRANQ) { - self.currentammo = self.ammo_shells; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_shot.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_ROCKETS; + pl.weapon = IT_ROCKET_LAUNCHER; + } else if (pl.current_weapon == WEAP_MEDIKIT) { + pl.currentammo = pl.ammo_medikit; + pl.weaponmodel = "progs/v_medi.mdl"; + pl.weaponframe = 0; + } else if (pl.current_weapon == WEAP_TRANQ) { + pl.currentammo = pl.ammo_shells; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_shot.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_SHELLS; - self.weapon = IT_SHOTGUN; - } else if (self.current_weapon == WEAP_LASER) { - self.currentammo = self.ammo_nails; - if (!(self.tfstate & TFSTATE_RELOADING)) { - self.weaponmodel = "progs/v_rail.mdl"; - self.weaponframe = 0; + pl.items = pl.items | IT_SHELLS; + pl.weapon = IT_SHOTGUN; + } else if (pl.current_weapon == WEAP_LASER) { + pl.currentammo = pl.ammo_nails; + if (!(pl.tfstate & TFSTATE_RELOADING)) { + pl.weaponmodel = "progs/v_rail.mdl"; + pl.weaponframe = 0; } - self.items = self.items | IT_NAILS; - self.weapon = IT_SHOTGUN; + pl.items = pl.items | IT_NAILS; + pl.weapon = IT_SHOTGUN; } else { - self.currentammo = 0; - self.weaponmodel = ""; - self.weaponframe = 0; + pl.currentammo = 0; + pl.weaponmodel = ""; + pl.weaponframe = 0; } // refresh engineer build menu when ammo updated - if (self.menu_input == Menu_Engineer_Input) - Menu_Engineer(self); + if (pl.menu_input == Menu_Engineer_Input) + Menu_Engineer(pl); }; float () W_BestWeapon = { @@ -1540,7 +1543,7 @@ float () W_CheckNoAmmo = { self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); W_PrintWeaponMessage(); return (0); }; @@ -1550,6 +1553,7 @@ void () W_Reload_shotgun = { self.owner.weaponmodel = "progs/v_shot.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); + W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); }; @@ -1558,6 +1562,7 @@ void () W_Reload_super_shotgun = { self.owner.weaponmodel = "progs/v_shot2.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); + W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); }; @@ -1566,6 +1571,7 @@ void () W_Reload_sniper_rifle = { self.owner.weaponmodel = "progs/v_srifle.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); + W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); }; @@ -1574,6 +1580,7 @@ void () W_Reload_grenade_launcher = { self.owner.weaponmodel = "progs/v_rock.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); + W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); }; @@ -1582,6 +1589,7 @@ void () W_Reload_rocket_launcher = { self.owner.weaponmodel = "progs/v_rock2.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); + W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); }; @@ -1615,6 +1623,36 @@ float () CheckForReload = { return 0; }; +float (float weap) CheckForAmmo = { + if (weap == WEAP_SHOTGUN) { + if (self.reload_shotgun >= 1 && self.ammo_shells > 0) { + TeamFortress_ReloadCurrentWeapon(); + return 1; + } + } else if (weap == WEAP_SUPER_SHOTGUN) { + if (self.reload_super_shotgun >= 2 && self.ammo_shells > 0) { + TeamFortress_ReloadCurrentWeapon(); + return 1; + } + } else if (weap == WEAP_SNIPER_RIFLE) { + if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && (toggleflags & TFLAG_SNIPERRELOAD)) { + TeamFortress_ReloadCurrentWeapon(); + return 1; + } + } else if (weap == WEAP_GRENADE_LAUNCHER) { + if ((self.reload_grenade_launcher >= 1) && (self.ammo_rockets > 0)) { + TeamFortress_ReloadCurrentWeapon(); + return 1; + } + } else if (weap == WEAP_ROCKET_LAUNCHER) { + if ((self.reload_rocket_launcher >= 1) && (self.ammo_rockets > 0)) { + TeamFortress_ReloadCurrentWeapon(); + return 1; + } + } + return 0; +}; + void () player_axe1; void () player_axeb1; void () player_axec1; @@ -1779,8 +1817,8 @@ void () W_Attack = { } }; -float () WeaponReady = { - if (time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) { +float (entity pl) WeaponReady = { + if (time >= pl.attack_finished && !(pl.tfstate & TFSTATE_RELOADING)) { return 1; } @@ -1899,82 +1937,87 @@ float (float inp) W_AmmoSlot = { return 1; }; -void () W_WeaponSlot1 = { +float () W_WeaponSlot1 = { if (self.playerclass == PC_SCOUT) - self.next_weapon = WEAP_NAILGUN; + return WEAP_NAILGUN; else if (self.playerclass == PC_SNIPER) - self.next_weapon = WEAP_SNIPER_RIFLE; + return WEAP_SNIPER_RIFLE; else if (self.playerclass == PC_SOLDIER) - self.next_weapon = WEAP_ROCKET_LAUNCHER; + return WEAP_ROCKET_LAUNCHER; else if (self.playerclass == PC_DEMOMAN) - self.next_weapon = WEAP_GRENADE_LAUNCHER; + return WEAP_GRENADE_LAUNCHER; else if (self.playerclass == PC_MEDIC) - self.next_weapon = WEAP_SUPER_NAILGUN; + return WEAP_SUPER_NAILGUN; else if (self.playerclass == PC_HVYWEAP) - self.next_weapon = WEAP_ASSAULT_CANNON; + return WEAP_ASSAULT_CANNON; else if (self.playerclass == PC_PYRO) - self.next_weapon = WEAP_FLAMETHROWER; + return WEAP_FLAMETHROWER; else if (self.playerclass == PC_SPY) - self.next_weapon = WEAP_TRANQ; + return WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) - self.next_weapon = WEAP_LASER; + return WEAP_LASER; + return 0; }; -void () W_WeaponSlot2 = { +float () W_WeaponSlot2 = { if (self.playerclass == PC_SCOUT) - self.next_weapon = WEAP_SHOTGUN; + return WEAP_SHOTGUN; else if (self.playerclass == PC_SNIPER) - self.next_weapon = WEAP_AUTO_RIFLE; + return WEAP_AUTO_RIFLE; else if (self.playerclass == PC_SOLDIER || self.playerclass == PC_MEDIC || self.playerclass == PC_HVYWEAP || self.playerclass == PC_SPY || self.playerclass == PC_ENGINEER) - self.next_weapon = WEAP_SUPER_SHOTGUN; + return WEAP_SUPER_SHOTGUN; else if (self.playerclass == PC_DEMOMAN) { - self.next_weapon = WEAP_GRENADE_LAUNCHER; - self.next_weaponmode = 1; + return WEAP_GRENADE_LAUNCHER; // weaponmode = 1 (pipebomb launcher) } else if (self.playerclass == PC_PYRO) - self.next_weapon = WEAP_INCENDIARY; + return WEAP_INCENDIARY; + return 0; }; -void () W_WeaponSlot3 = { +float () W_WeaponSlot3 = { if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) { sprint(self, PRINT_HIGH, "No weapon\n"); - return; + return 0; } if (self.playerclass == PC_SNIPER || self.playerclass == PC_SPY) - self.next_weapon = WEAP_NAILGUN; + return WEAP_NAILGUN; else if (self.playerclass == PC_SOLDIER || self.playerclass == PC_DEMOMAN || self.playerclass == PC_MEDIC || self.playerclass == PC_HVYWEAP || self.playerclass == PC_PYRO) - self.next_weapon = WEAP_SHOTGUN; + return WEAP_SHOTGUN; + return 0; }; -void () W_WeaponSlot4 = { +float () W_WeaponSlot4 = { if (self.weapons_carried & WEAP_MEDIKIT) - self.next_weapon = WEAP_MEDIKIT; + return WEAP_MEDIKIT; else if (self.weapons_carried & WEAP_SPANNER) - self.next_weapon = WEAP_SPANNER; + return WEAP_SPANNER; else - self.next_weapon = WEAP_AXE; + return WEAP_AXE; }; void (float slot) W_WeaponSlot = { self.next_weaponmode = 0; if (slot == 1) - W_WeaponSlot1(); - else if (slot == 2) - W_WeaponSlot2(); + self.next_weapon = W_WeaponSlot1(); + else if (slot == 2) { + self.next_weapon = W_WeaponSlot2(); + if (self.next_weapon == WEAP_GRENADE_LAUNCHER) + self.next_weaponmode = 1; + } else if (slot == 3) - W_WeaponSlot3(); + self.next_weapon = W_WeaponSlot3(); else if (slot == 4) - W_WeaponSlot4(); + self.next_weapon = W_WeaponSlot4(); }; void () W_AmmoError = { @@ -1984,44 +2027,44 @@ void () W_AmmoError = { sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); }; -void () W_WeaponState_Save = { - if (!WeaponReady()) +void (entity pl) W_WeaponState_Save = { + if (!WeaponReady(pl)) return; - self.weaponstate_current_weaponslot = self.current_weaponslot; - self.weaponstate_last_weaponslot = self.last_weaponslot; - self.weaponstate_current_weapon = self.current_weapon; - self.weaponstate_last_weapon = self.last_weapon; - self.weaponstate_weaponmode = self.weaponmode; - self.weaponstate_last_weaponmode = self.last_weaponmode; + pl.weaponstate_current_weaponslot = pl.current_weaponslot; + pl.weaponstate_last_weaponslot = pl.last_weaponslot; + pl.weaponstate_current_weapon = pl.current_weapon; + pl.weaponstate_last_weapon = pl.last_weapon; + pl.weaponstate_weaponmode = pl.weaponmode; + pl.weaponstate_last_weaponmode = pl.last_weaponmode; } -void (float swap) W_WeaponState_Load = { +void (entity pl, float swap) W_WeaponState_Load = { if (!swap) { - self.current_weaponslot = self.weaponstate_current_weaponslot; - self.last_weaponslot = self.weaponstate_last_weaponslot; - self.current_weapon = self.weaponstate_current_weapon; - self.last_weapon = self.weaponstate_last_weapon; - self.weaponmode = self.weaponstate_weaponmode; - self.last_weaponmode = self.weaponstate_last_weaponmode; + pl.current_weaponslot = pl.weaponstate_current_weaponslot; + pl.last_weaponslot = pl.weaponstate_last_weaponslot; + pl.current_weapon = pl.weaponstate_current_weapon; + pl.last_weapon = pl.weaponstate_last_weapon; + pl.weaponmode = pl.weaponstate_weaponmode; + pl.last_weaponmode = pl.weaponstate_last_weaponmode; } else { - self.current_weaponslot = self.weaponstate_last_weaponslot; - self.last_weaponslot = self.weaponstate_current_weaponslot; - self.current_weapon = self.weaponstate_last_weapon; - self.last_weapon = self.weaponstate_current_weapon; - self.weaponmode = self.weaponstate_last_weaponmode; - self.last_weaponmode = self.weaponstate_weaponmode; - } - self.queue_weaponstate = 0; - - W_WeaponState_Save(); - W_SetCurrentAmmo(); - Status_Refresh(self); + pl.current_weaponslot = pl.weaponstate_last_weaponslot; + pl.last_weaponslot = pl.weaponstate_current_weaponslot; + pl.current_weapon = pl.weaponstate_last_weapon; + pl.last_weapon = pl.weaponstate_current_weapon; + pl.weaponmode = pl.weaponstate_last_weaponmode; + pl.last_weaponmode = pl.weaponstate_weaponmode; + } + pl.queue_weaponstate = 0; + + W_WeaponState_Save(pl); + W_SetCurrentAmmo(pl); + Status_Refresh(pl); } -float () W_WeaponState_Check = { - if (self.current_weaponslot == self.weaponstate_current_weaponslot - && self.last_weaponslot == self.weaponstate_last_weaponslot) +float (entity pl) W_WeaponState_Check = { + if (pl.current_weaponslot == pl.weaponstate_current_weaponslot + && pl.last_weaponslot == pl.weaponstate_last_weaponslot) return 1; else return 0; @@ -2039,7 +2082,7 @@ void (float inp) W_ChangeWeapon = { self.queue_weaponslot = inp; // halt if weapon is not ready to be fired - if (!WeaponReady()) + if (!WeaponReady(self)) return; // check for ammo @@ -2065,9 +2108,9 @@ void (float inp) W_ChangeWeapon = { } if (!self.is_quickfiring && !self.has_quickfired) - W_WeaponState_Save(); + W_WeaponState_Save(self); - W_SetCurrentAmmo(); + W_SetCurrentAmmo(self); Status_Refresh(self); self.queue_weaponslot = 0; }; @@ -2079,7 +2122,7 @@ void () CycleWeaponLast = { if (!self.is_quickfiring) W_ChangeWeapon(self.last_weaponslot); else - W_WeaponState_Load(1); + W_WeaponState_Load(self, 1); }; void () CycleWeaponNext = { @@ -2169,6 +2212,14 @@ void () ImpulseCommands = { CycleWeaponPrev(); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); + else if (self.impulse == TF_RELOAD_SLOT1) + TeamFortress_ReloadSlot(1); + else if (self.impulse == TF_RELOAD_SLOT2) + TeamFortress_ReloadSlot(2); + else if (self.impulse == TF_RELOAD_SLOT3) + TeamFortress_ReloadSlot(3); + else if (self.impulse == TF_RELOAD_NEXT) + TeamFortress_ReloadNext(); else if (self.impulse == TF_DETPACK_5) TeamFortress_SetDetpack(5); else if (self.impulse == TF_DETPACK_20) @@ -2396,7 +2447,7 @@ void () W_WeaponFrame = { if (self.impulse == TF_WEAPLAST) { // change to last weapon now - if (WeaponReady()) + if (WeaponReady(self)) CycleWeaponLast(); // change to weaponstate (prior to quick fire) when weapon is ready else if (self.is_quickfiring) @@ -2415,7 +2466,7 @@ void () W_WeaponFrame = { } // unset quick firing variables when quick weapon has finished firing - if (self.is_quickfiring && self.has_quickfired && WeaponReady()) { + if (self.is_quickfiring && self.has_quickfired && WeaponReady(self)) { self.is_quickfiring = 0; self.has_quickfired = 0; @@ -2423,11 +2474,11 @@ void () W_WeaponFrame = { } // slot 1-4 binds - if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady()) { + if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady(self)) { // load weapon state if current state doesn't match stored state - if (!W_WeaponState_Check()) - W_WeaponState_Load(0); + if (!W_WeaponState_Check(self)) + W_WeaponState_Load(self, 0); // obviously not quickfiring if we're changing weapon self.is_quickfiring = 0; @@ -2439,8 +2490,8 @@ void () W_WeaponFrame = { // load weapon state if current state doesn't match // stored state, if weapon is ready - if (!W_WeaponState_Check() && WeaponReady() && !(self.tfstate & TFSTATE_AIMING)) - W_WeaponState_Load(0); + if (!W_WeaponState_Check(self) && WeaponReady(self) && !(self.tfstate & TFSTATE_AIMING)) + W_WeaponState_Load(self, 0); // +slot1-4 quick fire } else if (self.impulse >= 31 && self.impulse <= 34) { @@ -2448,7 +2499,7 @@ void () W_WeaponFrame = { self.is_quickfiring = 1; self.has_quickfired = 0; - if (WeaponReady()) + if (WeaponReady(self)) W_ChangeWeapon((self.impulse - 30)); // change weapon if queue_weaponslot has been set @@ -2457,15 +2508,15 @@ void () W_WeaponFrame = { W_ChangeWeapon(self.queue_weaponslot); // load weapon state - } else if (self.queue_weaponstate && WeaponReady()) { + } else if (self.queue_weaponstate && WeaponReady(self)) { // load weaponstate saved from before quick fire started if (self.queue_weaponstate == 1) - W_WeaponState_Load(0); + W_WeaponState_Load(self, 0); // load swapped weaponstate else - W_WeaponState_Load(1); + W_WeaponState_Load(self, 1); } @@ -2521,7 +2572,7 @@ void () W_WeaponFrame = { return; } - if (!WeaponReady()) + if (!WeaponReady(self)) return; if (self.impulse != 0 && self.has_disconnected == 0) From c48828f3591a55ecd24d8485f982682e8cd61650 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 17 Aug 2014 10:57:40 +0200 Subject: [PATCH 0129/2474] Add message to show all clips are full when using reloadnext --- actions.qc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/actions.qc b/actions.qc index 0536f4d2..7cf65a2d 100644 --- a/actions.qc +++ b/actions.qc @@ -497,13 +497,15 @@ void (float slot) TeamFortress_ReloadSlot = { }; void () TeamFortress_ReloadNext = { - local float slot, weap = 0; + local float slot, reload = 0, weap = 0; // reload current slot first slot = W_GetSlot(self.current_weapon); weap = W_WeaponSlot1(); - if (CheckForAmmo(weap)) + if (CheckForAmmo(weap)) { TeamFortress_ReloadWeapon(weap); + reload = 1; + } // then go through each slot for (slot = 1; slot < 4; slot++) { @@ -514,9 +516,14 @@ void () TeamFortress_ReloadNext = { else if (slot == 3) weap = W_WeaponSlot3(); - if (CheckForAmmo(weap)) + if (CheckForAmmo(weap)) { TeamFortress_ReloadWeapon(weap); + reload = 1; + } } + + if (!reload) + sprint(self, PRINT_HIGH, "All clips full\n"); }; void () TeamFortress_ClipTick = { From ecf8e48d8c97d783df9daac96a21c7dbb9ecb13d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 17 Aug 2014 11:12:24 +0200 Subject: [PATCH 0130/2474] Display correct clip size in status bar while reloading other than equipped weapon --- actions.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/actions.qc b/actions.qc index 7cf65a2d..d3ce204a 100644 --- a/actions.qc +++ b/actions.qc @@ -517,6 +517,7 @@ void () TeamFortress_ReloadNext = { weap = W_WeaponSlot3(); if (CheckForAmmo(weap)) { + self.current_weapon = weap; TeamFortress_ReloadWeapon(weap); reload = 1; } From 155065b7dcac2a13f53c326bb938ea228ea8b6ed Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 17 Aug 2014 11:36:47 +0200 Subject: [PATCH 0131/2474] Add 0.5 second cooldown on detpipe command --- demoman.qc | 3 +++ qw.qc | 1 + weapons.qc | 1 + 3 files changed, 5 insertions(+) diff --git a/demoman.qc b/demoman.qc index ad7049ba..e0f3f5bf 100644 --- a/demoman.qc +++ b/demoman.qc @@ -20,6 +20,9 @@ void () TeamFortress_DetpackCountDown; void () TeamFortress_DetonatePipebombs = { local entity e; + if (time < self.pipecooldown) + return; + e = find(world, classname, "pipebomb"); while (e != world) { if (e.owner == self) diff --git a/qw.qc b/qw.qc index d47a9846..95b6030a 100644 --- a/qw.qc +++ b/qw.qc @@ -45,6 +45,7 @@ typedef void (float) f_void_float; .float vote_next; // TRUE if player has voted for a map vote .float force_next; // TRUE if player has voted to force next map .float detpack_left; // Seconds left to detpack explosion +.float pipecooldown; // Time when detpipe command can be issued .float disguise_skin; // The skin the spy is changing to .float disguise_team; // The team the spy is changing to .float fragstreak; // Frag streak diff --git a/weapons.qc b/weapons.qc index 707157b9..d43b328f 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1165,6 +1165,7 @@ void () W_FireGrenade = { newmis.touch = GrenadeTouch; newmis.nextthink = time + 2.5; } else { + self.pipecooldown = time + 0.5; ExplodeOldestPipebomb(); newmis.classname = "pipebomb"; newmis.skin = 2; From a87768718e0a6727ed757d6885a411beb3892a42 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 18 Aug 2014 09:14:50 +0200 Subject: [PATCH 0132/2474] Fix no weapon message when using reloadnext as Scout or Engineer (fixes #117) --- actions.qc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/actions.qc b/actions.qc index d3ce204a..31bea4ca 100644 --- a/actions.qc +++ b/actions.qc @@ -490,8 +490,11 @@ void (float slot) TeamFortress_ReloadSlot = { weap = W_WeaponSlot1(); else if (slot == 2) weap = W_WeaponSlot2(); - else if (slot == 3) + else if (slot == 3) { + if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + return; weap = W_WeaponSlot3(); + } TeamFortress_ReloadWeapon(weap); }; @@ -513,8 +516,11 @@ void () TeamFortress_ReloadNext = { weap = W_WeaponSlot1(); else if (slot == 2) weap = W_WeaponSlot2(); - else if (slot == 3) + else if (slot == 3) { + if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + break; weap = W_WeaponSlot3(); + } if (CheckForAmmo(weap)) { self.current_weapon = weap; From 05866ede7047066e22a2550e9be9c4d2be0cfca6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 18 Aug 2014 09:15:07 +0200 Subject: [PATCH 0133/2474] Fix remaining status bar reload clip issues --- actions.qc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/actions.qc b/actions.qc index 31bea4ca..6409b727 100644 --- a/actions.qc +++ b/actions.qc @@ -496,6 +496,7 @@ void (float slot) TeamFortress_ReloadSlot = { weap = W_WeaponSlot3(); } + self.current_weapon = weap; TeamFortress_ReloadWeapon(weap); }; @@ -504,10 +505,10 @@ void () TeamFortress_ReloadNext = { // reload current slot first slot = W_GetSlot(self.current_weapon); - weap = W_WeaponSlot1(); - if (CheckForAmmo(weap)) { - TeamFortress_ReloadWeapon(weap); + if (CheckForAmmo(self.current_weapon)) { + TeamFortress_ReloadWeapon(self.current_weapon); reload = 1; + return; } // then go through each slot @@ -526,6 +527,7 @@ void () TeamFortress_ReloadNext = { self.current_weapon = weap; TeamFortress_ReloadWeapon(weap); reload = 1; + break; } } From 667ebdbb5b95bf50e65327c0d77723c75e6270de Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 18 Aug 2014 09:15:23 +0200 Subject: [PATCH 0134/2474] Add default class config used when exec_class is on --- tfort.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tfort.qc b/tfort.qc index 0bf0b311..c1e0b8d5 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2876,6 +2876,7 @@ void (entity p) TeamFortress_ExecClassScript = { st = infokey(p, "exec_class"); if (st == "on") { + stuffcmd(p, "exec classes/default.cfg\n"); if (p.playerclass == PC_SCOUT) stuffcmd(p, "exec classes/scout.cfg\n"); else if (p.playerclass == PC_SNIPER) From 7ed8ef76b3e085e567ac37a625a1b3f5c9659d1f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 18 Aug 2014 09:27:56 +0200 Subject: [PATCH 0135/2474] Fix bug with repeating 'All x are in the clip' messages --- weapons.qc | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/weapons.qc b/weapons.qc index d43b328f..f6c1353e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1626,30 +1626,20 @@ float () CheckForReload = { float (float weap) CheckForAmmo = { if (weap == WEAP_SHOTGUN) { - if (self.reload_shotgun >= 1 && self.ammo_shells > 0) { - TeamFortress_ReloadCurrentWeapon(); + if (self.reload_shotgun >= 1 && self.ammo_shells > self.reload_shotgun) return 1; - } } else if (weap == WEAP_SUPER_SHOTGUN) { - if (self.reload_super_shotgun >= 2 && self.ammo_shells > 0) { - TeamFortress_ReloadCurrentWeapon(); + if (self.reload_super_shotgun >= 2 && self.ammo_shells > self.reload_super_shotgun) return 1; - } } else if (weap == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && (toggleflags & TFLAG_SNIPERRELOAD)) { - TeamFortress_ReloadCurrentWeapon(); + if (self.reload_sniper_rifle >= 1 && self.ammo_shells > self.reload_sniper_rifle && (toggleflags & TFLAG_SNIPERRELOAD)) return 1; - } } else if (weap == WEAP_GRENADE_LAUNCHER) { - if ((self.reload_grenade_launcher >= 1) && (self.ammo_rockets > 0)) { - TeamFortress_ReloadCurrentWeapon(); + if (self.reload_grenade_launcher >= 1 && self.ammo_rockets > self.reload_grenade_launcher) return 1; - } } else if (weap == WEAP_ROCKET_LAUNCHER) { - if ((self.reload_rocket_launcher >= 1) && (self.ammo_rockets > 0)) { - TeamFortress_ReloadCurrentWeapon(); + if (self.reload_rocket_launcher >= 1 && self.ammo_rockets > self.reload_rocket_launcher) return 1; - } } return 0; }; From 98292c94b02b17ce9b2129a41d831e9098ef4e6a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 18 Aug 2014 09:35:40 +0200 Subject: [PATCH 0136/2474] Save weapon state when changing class (fixes #119) --- tfort.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tfort.qc b/tfort.qc index c1e0b8d5..0d7be82c 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1347,9 +1347,12 @@ void () TeamFortress_SetEquipment = { self.weapons_carried = 0; if (self.last_playerclass != self.playerclass) { self.current_weapon = 0; + self.last_weapon = 0; self.weaponmode = 0; + self.last_weaponmode = 0; self.current_weaponslot = 1; self.last_weaponslot = 1; + W_WeaponState_Save(self); } self.tf_items = 0; From a4a17a6899494e6d8d8b9a38b8ef2a3549a54250 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 18 Aug 2014 09:45:09 +0200 Subject: [PATCH 0137/2474] Add some constants to caltrop code --- scout.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scout.qc b/scout.qc index a1873992..53857b7f 100644 --- a/scout.qc +++ b/scout.qc @@ -24,11 +24,11 @@ void () CanisterTouch = }; void () CaltropTouch = { - if ((other.classname != "player") || !(other.flags & 512) || + if ((other.classname != "player") || !(other.flags & FL_ONGROUND) || other.deadflag) return; - if ((teamplay & 16) && (other != self.owner) + if ((teamplay & TEAMPLAY_NOEXPLOSIVE) && (other != self.owner) && (other.team_no == self.owner.team_no) && (self.owner.team_no != 0)) return; @@ -44,7 +44,7 @@ void () CaltropTouch = { void () CaltropScatterThink = { self.nextthink = time + 0.2; if (self.velocity == '0 0 0') { - if (self.flags & 512) { + if (self.flags & FL_ONGROUND) { self.nextthink = time + 10 + random() * 5; self.think = SUB_Remove; self.solid = SOLID_TRIGGER; From ba81d194b29928d1dc726b14b3c7f4525fd276cf Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 18 Aug 2014 10:41:40 +0200 Subject: [PATCH 0138/2474] Fix ammo drain bug and improve bestweapon code (fixes #121) --- weapons.qc | 117 ++++++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/weapons.qc b/weapons.qc index f6c1353e..a1920b2c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -10,6 +10,9 @@ void () SuperDamageSound; void () ConcussionGrenadeTimer; void () OldConcussionGrenadeTimer; +void () W_ChangeToBestWeapon; +void (float slot) W_WeaponSlot; +void (entity pl) W_WeaponState_Save; void () W_PrintWeaponMessage; void () button_fire; @@ -1033,10 +1036,7 @@ void () W_FireLightning = { local float cells; if (self.ammo_cells < 1) { - self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(self); - W_PrintWeaponMessage(); + W_ChangeToBestWeapon(); return; } if (self.waterlevel > 1) { @@ -1241,10 +1241,7 @@ void (float ox) W_FireSpikes = { return; } if (self.ammo_nails < 1) { - self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(self); - W_PrintWeaponMessage(); + W_ChangeToBestWeapon(); return; } sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); @@ -1487,33 +1484,32 @@ float () W_BestWeapon = { local float it; it = self.weapons_carried; - if (((self.ammo_cells >= 1) && (it & 65536)) && (self.waterlevel <= 1)) - return (65536); - else if (((self.ammo_cells >= 7) && (self.ammo_shells >= 1)) && - (it & WEAP_ASSAULT_CANNON)) - return (WEAP_ASSAULT_CANNON); - else if ((self.ammo_cells >= 1) && (it & 4096)) - return (4096); - else if ((self.ammo_nails >= 2) && (it & 1024)) - return (1024); - else if ((self.ammo_shells >= 2) && (it & 256)) - return (256); - else if ((self.ammo_nails >= 1) && (it & 524288)) - return (524288); - else if ((self.ammo_nails >= 1) && (it & 512)) - return (512); - else if ((self.ammo_shells >= 1) && (it & 128)) - return (128); - else if ((self.ammo_shells >= 1) && (it & 262144)) - return (262144); - else if (it & 4) - return (4); - else if (it & 8) - return (8); - else if (it & 16) - return (16); - - return (0); + if ((self.ammo_cells >= 1 && it & WEAP_LIGHTNING) && self.waterlevel <= 1) + return WEAP_LIGHTNING; + else if ((self.ammo_cells >= 7 && self.ammo_shells >= 1) && it & WEAP_ASSAULT_CANNON) + return WEAP_ASSAULT_CANNON; + else if (self.ammo_cells >= 1 && it & WEAP_FLAMETHROWER) + return WEAP_FLAMETHROWER; + else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) + return WEAP_SUPER_NAILGUN; + else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) + return WEAP_SUPER_SHOTGUN; + else if (self.ammo_nails >= 1 && it & WEAP_LASER) + return WEAP_LASER; + else if (self.ammo_nails >= 1 && it & WEAP_NAILGUN) + return WEAP_NAILGUN; + else if (self.ammo_shells >= 1 && it & WEAP_SHOTGUN) + return WEAP_SHOTGUN; + else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) + return WEAP_TRANQ; + else if (it & WEAP_MEDIKIT) + return WEAP_MEDIKIT; + else if (it & WEAP_SPANNER) + return WEAP_SPANNER; + else if (it & WEAP_AXE) + return WEAP_AXE; + + return 0; }; float () W_BestWeaponSlot = { @@ -1524,29 +1520,38 @@ float () W_BestWeaponSlot = { return W_GetSlot(weap); }; -float () W_CheckNoAmmo = { - if ((self.current_weapon == WEAP_AXE) - || (self.current_weapon == WEAP_SPANNER) - || (self.current_weapon == WEAP_MEDIKIT)) - return (1); - else if (self.current_weapon == WEAP_SUPER_NAILGUN) { - if (self.currentammo >= 4) - return (1); - } else if (self.current_weapon == WEAP_INCENDIARY) { - if (self.currentammo >= 3) - return (1); - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN - || self.current_weapon == WEAP_NAILGUN) { - if (self.currentammo >= 2) - return (1); - } else if (self.currentammo > 0) - return (1); - - self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_BestWeaponSlot(); +void () W_ChangeToBestWeapon = { + local float slot = W_BestWeaponSlot(); + + W_WeaponSlot(slot); + + //self.last_weaponslot = self.current_weaponslot; + //self.last_weapon = self.current_weapon; + //self.last_weaponmode = self.weaponmode; + self.current_weaponslot = slot; + self.current_weapon = self.next_weapon; + self.weaponmode = self.next_weaponmode; W_SetCurrentAmmo(self); + W_WeaponState_Save(self); W_PrintWeaponMessage(); - return (0); +} + +float () W_CheckNoAmmo = { + if (self.current_weapon == WEAP_AXE || self.current_weapon == WEAP_SPANNER + || self.current_weapon == WEAP_MEDIKIT) + return 1; + else if (self.current_weapon == WEAP_SUPER_NAILGUN && self.currentammo >= 4) + return 1; + else if (self.current_weapon == WEAP_INCENDIARY && self.currentammo >= 3) + return 1; + else if ((self.current_weapon == WEAP_SUPER_SHOTGUN || self.current_weapon == WEAP_NAILGUN) + && self.currentammo >= 2) + return 1; + else if (self.currentammo > 0) + return 1; + + W_ChangeToBestWeapon(); + return 0; }; void () W_Reload_shotgun = { From 7fdcf786cfcc716cf5a857be95b090b442b0527e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 19 Aug 2014 09:09:25 +0200 Subject: [PATCH 0139/2474] Add /forcenext description to forcenext message (closes #126) --- vote.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vote.qc b/vote.qc index 6fe144ab..c4d6b242 100644 --- a/vote.qc +++ b/vote.qc @@ -113,9 +113,9 @@ void (entity pe_player) Vote_ForceNext = { GotoNextMap(); } else { if (f_votes_left == 1) - bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed\n"); + bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed (/forcenext)\n"); else - bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed\n"); + bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed (/forcenext)\n"); } }; From 98443d5ff1c601ce2568f815d8fb757d8e8776d6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 19 Aug 2014 09:59:58 +0200 Subject: [PATCH 0140/2474] Add /votetrick and /voterace for trick/race maps (closes #125) --- client.qc | 9 +++- defs.h | 4 +- qw.qc | 2 + tforthlp.qc | 2 + vote.qc | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 155 insertions(+), 8 deletions(-) diff --git a/client.qc b/client.qc index d24004b5..095afde6 100644 --- a/client.qc +++ b/client.qc @@ -1428,8 +1428,13 @@ void () PlayerPreThink = { if (self.impulse == TF_VOTENEXT) { Vote_NextMap(self); self.impulse = 0; - } - else if (self.impulse == TF_FORCENEXT) { + } else if (self.impulse == TF_VOTETRICK) { + Vote_TrickMap(self); + self.impulse = 0; + } else if (self.impulse == TF_VOTERACE) { + Vote_RaceMap(self); + self.impulse = 0; + } else if (self.impulse == TF_FORCENEXT) { Vote_ForceNext(self); self.impulse = 0; } diff --git a/defs.h b/defs.h index f8b83a87..66065f8e 100644 --- a/defs.h +++ b/defs.h @@ -368,7 +368,9 @@ // CF map voting #define TF_VOTENEXT 70 -#define TF_FORCENEXT 71 +#define TF_VOTETRICK 71 +#define TF_VOTERACE 72 +#define TF_FORCENEXT 73 // Reload impulses #define TF_RELOAD_SLOT1 73 diff --git a/qw.qc b/qw.qc index 95b6030a..af71772c 100644 --- a/qw.qc +++ b/qw.qc @@ -43,6 +43,8 @@ typedef void (float) f_void_float; .float spawn_time; // Time when player spawned .float menu_time; // Time when vote map menu was first issued .float vote_next; // TRUE if player has voted for a map vote +.float vote_trick; // TRUE if player has voted for a trick map vote +.float vote_race; // TRUE if player has voted for a race map vote .float force_next; // TRUE if player has voted to force next map .float detpack_left; // Seconds left to detpack explosion .float pipecooldown; // Time when detpipe command can be issued diff --git a/tforthlp.qc b/tforthlp.qc index 37a71b61..251906d4 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -115,6 +115,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("discard", TF_DISCARD, 0); TeamFortress_Alias("id", TF_ID, 0); TeamFortress_Alias("votenext", TF_VOTENEXT, 0); + TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); + TeamFortress_Alias("voterace", TF_VOTERACE, 0); TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); } else if (self.motd == 55) { TeamFortress_Alias("flaginfo", FLAG_INFO, 0); diff --git a/vote.qc b/vote.qc index c4d6b242..3397228a 100644 --- a/vote.qc +++ b/vote.qc @@ -5,7 +5,11 @@ // functions by order of appearance float () TeamFortress_GetNoActivePlayers; void (entity pe_player) Vote_NextMap; +void (entity pe_player) Vote_TrickMap; +void (entity pe_player) Vote_RaceMap; float () Vote_GetNextVotes; +float () Vote_GetTrickVotes; +float () Vote_GetRaceVotes; void (entity pe_player) Vote_ForceNext; void () GotoNextMap; float () Vote_GetForceNextVotes; @@ -17,6 +21,8 @@ void () Vote_MenuClose; void (entity pe_player) Vote_Menu; void (float pf_input) Vote_RemoveVote; string () Vote_GetMapList; +string () Vote_GetTrickList; +string () Vote_GetRaceList; void (string ps_maplist) Vote_PopulateVoteList; string (string ps_map, string ps_maplist) Vote_StripMap; void () Vote_Reset; @@ -70,6 +76,68 @@ void (entity pe_player) Vote_NextMap = { } }; +// opens the map voting for trick maps +// called from weapons.qc:ImpulseCommands() +void (entity pe_player) Vote_TrickMap = { + local float f_votes, f_votes_needed, f_votes_left; + + if (!pe_player.team_no || !pe_player.playerclass) + return; + + if (vote_result != string_null) { + sprint(pe_player, PRINT_HIGH, "Next map has already been voted to ", vote_result, ". Use /forcenext to force next map.\n"); + return; + } + pe_player.vote_trick = 1; + + bprint(PRINT_HIGH, pe_player.netname, " wants to vote for a trick map\n"); + + f_votes = Vote_GetTrickVotes(); + f_votes_needed = ceil(TeamFortress_GetNoActivePlayers() / 2); + f_votes_left = f_votes_needed - f_votes; + if (f_votes >= f_votes_needed) { + Vote_SetupVote(2); + //dprint("[", ftos(time), "/cf/mapvote/votetrick]: forcing trick map vote.\n"); + bprint(PRINT_HIGH, "Commencing vote for trick map\n"); + } else { + if (f_votes_left == 1) + bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed (/votetrick)\n"); + else + bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed (/votetrick)\n"); + } +}; + +// opens the map voting for race maps +// called from weapons.qc:ImpulseCommands() +void (entity pe_player) Vote_RaceMap = { + local float f_votes, f_votes_needed, f_votes_left; + + if (!pe_player.team_no || !pe_player.playerclass) + return; + + if (vote_result != string_null) { + sprint(pe_player, PRINT_HIGH, "Next map has already been voted to ", vote_result, ". Use /forcenext to force next map.\n"); + return; + } + pe_player.vote_race = 1; + + bprint(PRINT_HIGH, pe_player.netname, " wants to vote for a race map\n"); + + f_votes = Vote_GetRaceVotes(); + f_votes_needed = ceil(TeamFortress_GetNoActivePlayers() / 2); + f_votes_left = f_votes_needed - f_votes; + if (f_votes >= f_votes_needed) { + Vote_SetupVote(3); + //dprint("[", ftos(time), "/cf/mapvote/voterace]: forcing race map vote.\n"); + bprint(PRINT_HIGH, "Commencing vote for race map\n"); + } else { + if (f_votes_left == 1) + bprint(PRINT_HIGH, ftos(f_votes_left), " more vote needed (/voterace)\n"); + else + bprint(PRINT_HIGH, ftos(f_votes_left), " more votes needed (/voterace)\n"); + } +}; + // returns the total amount of vote_next votes // called from Vote_NextMap() float () Vote_GetNextVotes = { @@ -86,6 +154,38 @@ float () Vote_GetNextVotes = { return f_count; }; +// returns the total amount of vote_trick votes +// called from Vote_TrickMap() +float () Vote_GetTrickVotes = { + local entity e_player; + local float f_count = 0; + + e_player = find(world, classname, "player"); + while (e_player != world) { + if (e_player.vote_trick == 1 && e_player.team_no && e_player.playerclass) + f_count = f_count + 1; + e_player = find(e_player, classname, "player"); + } + + return f_count; +}; + +// returns the total amount of vote_race votes +// called from Vote_RaceMap() +float () Vote_GetRaceVotes = { + local entity e_player; + local float f_count = 0; + + e_player = find(world, classname, "player"); + while (e_player != world) { + if (e_player.vote_race == 1 && e_player.team_no && e_player.playerclass) + f_count = f_count + 1; + e_player = find(e_player, classname, "player"); + } + + return f_count; +}; + // forces server to change map to next map // called from weapons.qc:ImpulseCommands() void (entity pe_player) Vote_ForceNext = { @@ -213,18 +313,24 @@ void () Vote_Check = { }; // decides maps should be included in map voting +// pf_type: 0 = normal vote, 1 = decider vote, 2 = trick vote, 3 = race vote // called from Vote_Check() -void (float pf_decider) Vote_SetupVote = { +void (float pf_type) Vote_SetupVote = { local string s_maplist; + vote_decider = 0; - if (!pf_decider) { - vote_decider = 0; + if (pf_type == 0) { s_maplist = Vote_GetMapList(); // returns a strzoned string - } else { + } else if (pf_type == 1) { vote_decider = 1; s_maplist = Vote_GetWinnerList(); // returns a strzoned string Vote_ResetVotes(); - //dprint("[", ftos(time), "/cf/mapvote/setupvote]: decider votelist: ", s_maplist, "\n"); + } else if (pf_type == 2) { + s_maplist = Vote_GetTrickList(); // returns a strzoned string + Vote_ResetVotes(); + } else { + s_maplist = Vote_GetRaceList(); // returns a strzoned string + Vote_ResetVotes(); } vote_started = time; @@ -541,6 +647,36 @@ string () Vote_GetMapList = { return s_maplist; }; +// returns a list of trick maps from config +// called from Vote_SetupVote() +string () Vote_GetTrickList = { + local string s_maplist, s_maplist1, s_maplist2, s_maplist3, s_maplist4; + + s_maplist1 = strcat(infokey(world, "votelist_trick1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_trick2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_trick3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_trick4"), " "); + s_maplist = strzone(strcat(s_maplist1, strcat(s_maplist2, strcat(s_maplist3, s_maplist4)))); + + //dprint("[", ftos(time), "/cf/mapvote/gettricklist]: trick votelist: ", s_maplist, "\n"); + return s_maplist; +}; + +// returns a list of race maps from config +// called from Vote_SetupVote() +string () Vote_GetRaceList = { + local string s_maplist, s_maplist1, s_maplist2, s_maplist3, s_maplist4; + + s_maplist1 = strcat(infokey(world, "votelist_race1"), " "); + s_maplist2 = strcat(infokey(world, "votelist_race2"), " "); + s_maplist3 = strcat(infokey(world, "votelist_race3"), " "); + s_maplist4 = strcat(infokey(world, "votelist_race4"), " "); + s_maplist = strzone(strcat(s_maplist1, strcat(s_maplist2, strcat(s_maplist3, s_maplist4)))); + + //dprint("[", ftos(time), "/cf/mapvote/getracelist]: trick votelist: ", s_maplist, "\n"); + return s_maplist; +}; + // populates vote*_map variables // called from Vote_SetupVote() void (string ps_maplist) Vote_PopulateVoteList = { From 5d7079ff3788aadb234b866d9d30bf1656847df1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 19 Aug 2014 10:01:08 +0200 Subject: [PATCH 0141/2474] Change reload impulses (collided with vote impulses) --- defs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index 66065f8e..3f731445 100644 --- a/defs.h +++ b/defs.h @@ -373,10 +373,10 @@ #define TF_FORCENEXT 73 // Reload impulses -#define TF_RELOAD_SLOT1 73 -#define TF_RELOAD_SLOT2 74 -#define TF_RELOAD_SLOT3 75 -#define TF_RELOAD_NEXT 76 +#define TF_RELOAD_NEXT 80 +#define TF_RELOAD_SLOT1 81 +#define TF_RELOAD_SLOT2 82 +#define TF_RELOAD_SLOT3 83 #define TF_RELOAD 173 #define TF_CHANGETEAM 98 From 207fc39f97f335a575fe6657104e3058dd172223 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 19 Aug 2014 10:05:31 +0200 Subject: [PATCH 0142/2474] Spy can no longer move while feigning (fixes #124) --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index a1920b2c..88b44641 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2609,7 +2609,7 @@ void () W_WeaponFrame = { self.tfstate = self.tfstate - TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.heat = 0; - } else if (self.tfstate & TFSTATE_CANT_MOVE) { + } else if (self.tfstate & TFSTATE_CANT_MOVE && !self.is_feigning) { self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); self.heat = 0; From 0d37980576e3b317095854096f6922f0a8dba539 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 19 Aug 2014 10:32:31 +0200 Subject: [PATCH 0143/2474] Make concussion grenade primary grenade for Scout again --- defs.h | 8 ++++---- tfort.qc | 30 ++++++++++++++++-------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/defs.h b/defs.h index 3f731445..338e7a2f 100644 --- a/defs.h +++ b/defs.h @@ -697,10 +697,10 @@ #define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned #define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned #define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned -#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CONCUSSION // <- 1st Type of Grenade this class has -#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_FLASH // <- 2nd Type of Grenade this class has -#define PC_SCOUT_GRENADE_INIT_1 3 // Number of grenades of Type 1 this class has when respawned -#define PC_SCOUT_GRENADE_INIT_2 2 // Number of grenades of Type 2 this class has when respawned +#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_FLASH // <- 1st Type of Grenade this class has +#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has +#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned +#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned #define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has #define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range diff --git a/tfort.qc b/tfort.qc index 0d7be82c..af1a0f39 100644 --- a/tfort.qc +++ b/tfort.qc @@ -321,8 +321,6 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, "Grenade type 1: "); if (self.tp_grenades_1 == GR_TYPE_NORMAL) sprint(self, PRINT_HIGH, "Normal ("); - else if (self.tp_grenades_1 == GR_TYPE_CONCUSSION) - sprint(self, PRINT_HIGH, "Concussion ("); else if (self.tp_grenades_1 == GR_TYPE_NAIL) sprint(self, PRINT_HIGH, "Nail ("); else if (self.tp_grenades_1 == GR_TYPE_MIRV) @@ -335,6 +333,10 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, "Hallucinogenic ("); else if (self.tp_grenades_1 == GR_TYPE_EMP) sprint(self, PRINT_HIGH, "EMP ("); + else if (self.tp_grenades_2 == GR_TYPE_CALTROP) + sprint(self, PRINT_HIGH, "Caltrop ("); + else if (self.tp_grenades_2 == GR_TYPE_FLASH) + sprint(self, PRINT_HIGH, "Flash ("); else sprint(self, PRINT_HIGH, "BUG ("); @@ -345,10 +347,8 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, "Grenade type 2: "); if (self.tp_grenades_2 == GR_TYPE_NORMAL) sprint(self, PRINT_HIGH, "Normal ("); - else if (self.tp_grenades_2 == GR_TYPE_CALTROP) - sprint(self, PRINT_HIGH, "Caltrop ("); - else if (self.tp_grenades_2 == GR_TYPE_FLASH) - sprint(self, PRINT_HIGH, "Flash ("); + else if (self.tp_grenades_1 == GR_TYPE_CONCUSSION) + sprint(self, PRINT_HIGH, "Concussion ("); else if (self.tp_grenades_2 == GR_TYPE_NAIL) sprint(self, PRINT_HIGH, "Nail ("); else if (self.tp_grenades_2 == GR_TYPE_MIRV) @@ -481,8 +481,8 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { else { TeamFortress_PrimeGrenade(inp); - if ( ((inp == 2 && self.tp_grenade_switch != 1) || (inp == 1 && self.tp_grenade_switch == 1)) - && self.tp_grenades_2 == 10) + if ( ((inp == 1 && self.tp_grenade_switch != 1) || (inp == 2 && self.tp_grenade_switch == 1)) + && self.tp_grenades_1 == GR_TYPE_CALTROP) TeamFortress_ThrowGrenade(); } }; @@ -517,6 +517,10 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "Gas grenade"; else if (self.tp_grenades_1 == 8) gs = "EMP grenade"; + else if (self.tp_grenades_1 == 9) + gs = "Flash grenade"; + else if (self.tp_grenades_1 == 10) + gs = "Caltrop canister"; else gs = "Grenade"; @@ -577,8 +581,6 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "EMP grenade"; else if (self.tp_grenades_2 == 9) gs = "Flash grenade"; - else if (self.tp_grenades_2 == 10) - gs = "Caltrop canister"; else gs = "Grenade"; @@ -1432,12 +1434,12 @@ void () TeamFortress_SetEquipment = { self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1; self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2; - self.tp_grenades_1 = GR_TYPE_CONCUSSION; - if (old_grens == 1) - self.tp_grenades_2 = GR_TYPE_FLASH; + self.tp_grenades_1 = GR_TYPE_FLASH; else - self.tp_grenades_2 = GR_TYPE_CALTROP; + self.tp_grenades_1 = GR_TYPE_CALTROP; + + self.tp_grenades_2 = GR_TYPE_CONCUSSION; self.tf_items = PC_SCOUT_TF_ITEMS; From 59fd37daa85a4e1546a641c6b695a5b5874b011e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 19 Aug 2014 21:41:41 +0200 Subject: [PATCH 0144/2474] Spy now drops backpack when feigning (not sfeign) (closes #129) --- items.qc | 2 +- spy.qc | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/items.qc b/items.qc index 11183ab4..5e11a6db 100644 --- a/items.qc +++ b/items.qc @@ -1329,7 +1329,7 @@ void () item_artifact_super_damage = { void () BackpackTouch = { local string s; - if (other.classname != "player") + if (other.classname != "player" || other.is_feigning) return; if (other.health <= 0) return; diff --git a/spy.qc b/spy.qc index 5fb2e03f..5e2b2453 100644 --- a/spy.qc +++ b/spy.qc @@ -3,6 +3,7 @@ void (entity spy) TeamFortress_SpyCalcName; void () TeamFortress_SpyUndercoverThink; void () GasGrenadeMakeGas; void () T_TranqDartTouch; +void () Spy_DropBackpack; void () spy_diea1 =[50, spy_diea2] { }; @@ -447,6 +448,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { self.movetype = 6; if (issilent == 0) { DeathSound(); + Spy_DropBackpack(); } self.angles_x = 0; self.angles_z = 0; @@ -1116,3 +1118,32 @@ void (entity spy) Spy_RemoveDisguise = { if (coverblown) Status_Print(self, "\n\n\n\n\n\n\n", "You blew your cover!"); }; + +void () Spy_DropBackpack = { + if ((cb_prematch_time + 3) > time) + return; + + newmis = spawn(); + newmis.origin = self.origin - '0 0 24'; + + newmis.ammo_shells = 0; + newmis.ammo_nails = 0; + newmis.ammo_rockets = 0; + newmis.ammo_cells = 0; + + newmis.armorvalue = 0; + + newmis.velocity_z = 300; + newmis.velocity_x = -100 + random() * 200; + newmis.velocity_y = -100 + random() * 200; + + newmis.flags = FL_ITEM; + newmis.solid = SOLID_TRIGGER; + newmis.movetype = MOVETYPE_TOSS; + setmodel(newmis, "progs/backpack.mdl"); + setsize(newmis, '-16 -16 0', '16 16 56'); + newmis.touch = BackpackTouch; + + newmis.nextthink = time + 120; + newmis.think = SUB_Remove; +}; From f728b13067055264fd3dea1d9d3f494940df4521 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 09:23:52 +0200 Subject: [PATCH 0145/2474] Add death message to Spy feign (closes #128) --- client.qc | 927 ++++++++++++++++++++++++++++------------------------- qw.qc | 1 + spy.qc | 3 + weapons.qc | 3 + 4 files changed, 493 insertions(+), 441 deletions(-) diff --git a/client.qc b/client.qc index 095afde6..c423e122 100644 --- a/client.qc +++ b/client.qc @@ -1852,531 +1852,576 @@ void () ClientDisconnect = { self.StatusString = string_null; }; -void (entity targ, entity attacker) ClientObituary = { +string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { + local string s_deathstring = "", s_deathstring2 = "\n"; local float rnum; - local string deathstring = ""; - local string deathstring2 = ""; - - Sniper_ZoomReset(targ); rnum = random(); - if ((cb_prematch_time + 3) > time) - return; - if (targ.classname == "player") { - if (attacker.classname == "teledeath") { - bprint(PRINT_MEDIUM, targ.netname, " was telefragged by ", - attacker.owner.netname, "\n"); + if (pe_target.classname == "player") { + if (pe_attacker.classname == "teledeath2") { + return strcat("Satan's power deflects ", + strcat(pe_target.netname, "'s telefrag\n")); + } + if (pe_attacker.classname == "teledeath") { + return strcat(pe_target.netname, + strcat(" was telefragged by ", + strcat(pe_attacker.netname, "\n"))); + } + if (pf_deathmsg == 37) { + return strcat(pe_attacker.netname, " shoots his teammate one too many times\n"); + } + if (pe_attacker.classname == "player" || pe_attacker.classname == "bot") { + if (pe_target == pe_attacker) { + + if (pf_deathmsg == DMSG_GREN_HAND) { + + if (pe_target.playerclass == PC_SNIPER) + s_deathstring = " got splattered by his own grenade\n"; + else if (pe_target.playerclass == PC_SOLDIER) + s_deathstring = " sat on his own grenade\n"; + else if (pe_target.playerclass == PC_DEMOMAN) + s_deathstring = " got to know his grenade too well\n"; + else if (pe_target.playerclass == PC_MEDIC) + s_deathstring = " caught the end of his own grenade\n"; + else if (pe_target.playerclass == PC_HVYWEAP) + s_deathstring = " got too close to his own grenade\n"; + else if (pe_target.playerclass == PC_PYRO) + s_deathstring = " let his own grenade get the best of him\n"; + else if (pe_target.playerclass == PC_SPY) + s_deathstring = " tiptoed over his own grenade\n"; + else if (pe_target.playerclass == PC_ENGINEER) + s_deathstring = " stared at his grenade too long\n"; + else + s_deathstring = " grenades himself\n"; - if ((attacker.owner.team_no != targ.team_no) || - (attacker.owner.team_no < 1)) - TF_AddFrags(attacker.owner, 1); + return strcat(pe_target.netname, s_deathstring); - return; - } - if (attacker.classname == "teledeath2") { - bprint(PRINT_MEDIUM, "Satan's power deflects ", targ.netname, - "'s telefrag\n"); - TF_AddFrags(targ, -1); - logfrag(targ, targ); - return; - } - if (deathmsg == 37) { - bprint(PRINT_MEDIUM, targ.netname, - " shoots his teammate one too many times\n"); - return; - } - if ((attacker.classname == "info_tfgoal") || - (attacker.classname == "item_tfgoal")) { - if (attacker.deathtype != "") { - bprint(PRINT_MEDIUM, targ.netname, attacker.deathtype); - } - logfrag(targ, targ); - return; - } - if ((attacker.classname == "player") || - (attacker.classname == "bot")) { - if (targ == attacker) { - // killed self - TF_AddFrags(attacker, -1); + } else if (pf_deathmsg == DMSG_GREN_NAIL) { - bprint(PRINT_MEDIUM, targ.netname); - - if (deathmsg == DMSG_GREN_HAND) { - if (targ.playerclass == PC_SNIPER) - deathstring = - " got splattered by his own grenade\n"; - else if (targ.playerclass == PC_SOLDIER) - deathstring = " sat on his own grenade\n"; - else if (targ.playerclass == PC_DEMOMAN) - deathstring = - " got to know his grenade too well\n"; - else if (targ.playerclass == PC_MEDIC) - deathstring = - " caught the end of his own grenade\n"; - else if (targ.playerclass == PC_HVYWEAP) - deathstring = - " got too close to his own grenade\n"; - else if (targ.playerclass == PC_PYRO) - deathstring = - " let his own grenade get the best of him\n"; - else if (targ.playerclass == PC_SPY) - deathstring = " tiptoed over his own grenade\n"; - else if (targ.playerclass == PC_ENGINEER) - deathstring = " stared at his grenade too long\n"; - else - deathstring = " grenades himself\n"; - } else if (deathmsg == DMSG_GREN_NAIL) - deathstring = " hammers himself\n"; - else if (deathmsg == DMSG_GREN_MIRV) { - if (targ.playerclass == PC_DEMOMAN) - deathstring = " practiced his own Mirv dance\n"; - else if (targ.playerclass == PC_HVYWEAP) - deathstring = - " allowed his Mirv to turn against him\n"; - else - deathstring = " goes to pieces\n"; - } else if (deathmsg == DMSG_GREN_PIPE) - deathstring = - " ambushes himself with his own pipebombs\n"; - else if (deathmsg == 40) - deathstring = " tried to juggle his own pipebombs\n"; - else if (deathmsg == DMSG_GREN_GAS) - deathstring = " chokes on his own gas\n"; - else if (deathmsg == DMSG_GREN_EMP) - deathstring = " explodes his ammo and body\n"; - else if (deathmsg == 41) - deathstring = - " stepped on too many of his own caltrops\n"; - else if (deathmsg == DMSG_GREN_FLASH) - deathstring = " is charred by his own flash grenade\n"; - else if (deathmsg == DMSG_GREN_EMP_AMMO) - deathstring = - " detonates an ammo box too close to him\n"; - else if (deathmsg == DMSG_DETPACK) - deathstring = " set the detpack and forgot to run\n"; - else if (deathmsg == DMSG_BIOWEAPON) - deathstring = " died impossibly!\n"; - else if (deathmsg == DMSG_ROCKETL) { - if (rnum) - deathstring = " becomes bored with life\n"; + return strcat(pe_target.netname, " hammers himself\n"); + + } else if (pf_deathmsg == DMSG_GREN_MIRV) { + + if (pe_target.playerclass == PC_DEMOMAN) + s_deathstring = " practiced his own Mirv dance\n"; + else if (pe_target.playerclass == PC_HVYWEAP) + s_deathstring = " allowed his Mirv to turn against him\n"; else - deathstring = " checks if his weapon is loaded\n"; - } else if (deathmsg == DMSG_INCENDIARY) - deathstring = - " chars himself with an incendiary rocket\n"; - else if (deathmsg == DMSG_GRENADEL) - deathstring = " tries to put the pin back in\n"; - else if (deathmsg == DMSG_FLAME) - deathstring = " torches himself\n"; - else if ((deathmsg == DMSG_LIGHTNING) && - (targ.waterlevel > 1)) { - bprint(PRINT_MEDIUM, " discharges into the water\n"); - return; - } else if (deathmsg == 38) - deathstring = - " gets too friendly with his sentry gun\n"; - else if (deathmsg == 39) - deathstring = " dispenses with himself\n"; - - bprint(PRINT_MEDIUM, deathstring); - return; - } else if ((teamplay && (attacker.team_no == targ.team_no)) && - (attacker.team_no > 0)) { - // killed a team member - TF_AddFrags(attacker, -1); + s_deathstring = " goes to pieces\n"; - if (targ.undercover_team == 0) - attacker.teamkills = attacker.teamkills + 1; + return strcat(pe_target.netname, s_deathstring); + + } else if (pf_deathmsg == DMSG_GREN_PIPE) { - deathstring2 = "\n"; + return strcat(pe_target.netname, " ambushes himself with his own pipebombs\n"); + + } + + else if (pf_deathmsg == 40) + s_deathstring = " tried to juggle his own pipebombs\n"; + else if (pf_deathmsg == DMSG_GREN_GAS) + s_deathstring = " chokes on his own gas\n"; + else if (pf_deathmsg == DMSG_GREN_EMP) + s_deathstring = " explodes his ammo and body\n"; + else if (pf_deathmsg == 41) + s_deathstring = " stepped on too many of his own caltrops\n"; + else if (pf_deathmsg == DMSG_GREN_FLASH) + s_deathstring = " is charred by his own flash grenade\n"; + else if (pf_deathmsg == DMSG_GREN_EMP_AMMO) + s_deathstring = " detonates an ammo box too close to him\n"; + else if (pf_deathmsg == DMSG_DETPACK) + s_deathstring = " set the detpack and forgot to run\n"; + else if (pf_deathmsg == DMSG_BIOWEAPON) + s_deathstring = " died impossibly!\n"; + else if (pf_deathmsg == DMSG_ROCKETL) { + if (rnum) + s_deathstring = " becomes bored with life\n"; + else + s_deathstring = " checks if his weapon is loaded\n"; + } else if (pf_deathmsg == DMSG_INCENDIARY) + s_deathstring = " chars himself with an incendiary rocket\n"; + else if (pf_deathmsg == DMSG_GRENADEL) + s_deathstring = " tries to put the pin back in\n"; + else if (pf_deathmsg == DMSG_FLAME) + s_deathstring = " torches himself\n"; + else if (pf_deathmsg == DMSG_LIGHTNING && pe_target.waterlevel > 1) + s_deathstring = " discharges into the water\n"; + else if (pf_deathmsg == 38) + s_deathstring = " gets too friendly with his sentry gun\n"; + else if (pf_deathmsg == 39) + s_deathstring = " dispenses with himself\n"; + + return strcat(pe_target.netname, s_deathstring); + + } else if ((teamplay && (pe_attacker.team_no == pe_target.team_no)) && (pe_attacker.team_no > 0)) { if (rnum < 0.25) - deathstring = " mows down teammate "; + s_deathstring = " mows down teammate "; else if (rnum < 0.5) - deathstring = " checks his glasses after killing "; + s_deathstring = " checks his glasses after killing "; else if (rnum < 0.75) { - deathstring = " gets a frag for the other team with "; - deathstring2 = "'s death\n"; + s_deathstring = " gets a frag for the other team with "; + s_deathstring2 = "'s death\n"; } else - deathstring = " killed his supposed friend "; + s_deathstring = " killed his supposed friend "; - if (deathmsg == DMSG_MEDIKIT) { - bprint(PRINT_MEDIUM, targ.netname, - " didn't survive the operation by ", - attacker.netname, "\n"); - return; - } + if (pf_deathmsg == DMSG_MEDIKIT) + return strcat(pe_target.netname, + strcat(" didn't survive the operation by ", + strcat(pe_attacker.netname, "\n"))); + + return strcat(pe_attacker.netname, + strcat(s_deathstring, + strcat(pe_target.netname, s_deathstring2))); - bprint(PRINT_MEDIUM, attacker.netname, deathstring, - targ.netname, deathstring2); - CheckAutoKick(attacker); - return; } else { - TF_AddFrags(attacker, 1); - logfrag(attacker, targ); - if (deathmsg == DMSG_GREN_HAND) { - if (attacker.playerclass == PC_SNIPER) { - deathstring = " got up-close and personal with "; - deathstring2 = "'s grenade\n"; - } else if (attacker.playerclass == PC_SOLDIER) { - deathstring = " played catch with "; - deathstring2 = "'s grenade\n"; - } else if (attacker.playerclass == PC_DEMOMAN) { - deathstring = " received a pineapple enema from "; - deathstring2 = "\n"; - } else if (attacker.playerclass == PC_MEDIC) { - deathstring = " fetched "; - deathstring2 = "'s pineapple\n"; - } else if (attacker.playerclass == PC_HVYWEAP) { - deathstring = " caught too much shrapnel from "; - deathstring2 = "'s grenade\n"; - } else if (attacker.playerclass == PC_PYRO) { - deathstring = " tried to pick up "; - deathstring2 = "'s hot potato\n"; - } else if (attacker.playerclass == PC_SPY) { - deathstring = " thought "; - deathstring2 = - " was tossing him a spare grenade\n"; - } else if (attacker.playerclass == PC_ENGINEER) { - deathstring = - " stops to ponder the technical details of "; - deathstring2 = "'s grenade\n"; + if (pf_deathmsg == DMSG_GREN_HAND) { + if (pe_attacker.playerclass == PC_SNIPER) { + s_deathstring = " got up-close and personal with "; + s_deathstring2 = "'s grenade\n"; + } else if (pe_attacker.playerclass == PC_SOLDIER) { + s_deathstring = " played catch with "; + s_deathstring2 = "'s grenade\n"; + } else if (pe_attacker.playerclass == PC_DEMOMAN) { + s_deathstring = " received a pineapple enema from "; + s_deathstring2 = "\n"; + } else if (pe_attacker.playerclass == PC_MEDIC) { + s_deathstring = " fetched "; + s_deathstring2 = "'s pineapple\n"; + } else if (pe_attacker.playerclass == PC_HVYWEAP) { + s_deathstring = " caught too much shrapnel from "; + s_deathstring2 = "'s grenade\n"; + } else if (pe_attacker.playerclass == PC_PYRO) { + s_deathstring = " tried to pick up "; + s_deathstring2 = "'s hot potato\n"; + } else if (pe_attacker.playerclass == PC_SPY) { + s_deathstring = " thought "; + s_deathstring2 = " was tossing him a spare grenade\n"; + } else if (pe_attacker.playerclass == PC_ENGINEER) { + s_deathstring = " stops to ponder the technical details of "; + s_deathstring2 = "'s grenade\n"; } else { - deathstring = " surfs on a grenade from "; - deathstring2 = "\n"; + s_deathstring = " surfs on a grenade from "; + s_deathstring2 = "\n"; } - } else if (deathmsg == DMSG_GREN_NAIL) { - deathstring = " gets flayed by "; - deathstring2 = "'s nail grenade\n"; - } else if (deathmsg == DMSG_GREN_MIRV) { - if (attacker.playerclass == PC_DEMOMAN) { - deathstring = " does a dance on "; - deathstring2 = "'s Mirv grenade\n"; + + } else if (pf_deathmsg == DMSG_GREN_NAIL) { + s_deathstring = " gets flayed by "; + s_deathstring2 = "'s nail grenade\n"; + } else if (pf_deathmsg == DMSG_GREN_MIRV) { + if (pe_attacker.playerclass == PC_DEMOMAN) { + s_deathstring = " does a dance on "; + s_deathstring2 = "'s Mirv grenade\n"; } else { - deathstring = " gets spammed by "; - deathstring2 = "'s Mirv grenade\n"; + s_deathstring = " gets spammed by "; + s_deathstring2 = "'s Mirv grenade\n"; } - } else if (deathmsg == DMSG_GREN_PIPE) { - deathstring = " is caught by "; - deathstring2 = "'s pipebomb trap\n"; - } else if (deathmsg == 40) { - deathstring = " fell victim to "; - deathstring2 = "'s fireworks\n"; - } else if (deathmsg == DMSG_GREN_GAS) { - deathstring = " gags on "; - deathstring2 = "'s noxious gasses\n"; - } else if (deathmsg == DMSG_GREN_EMP) { - deathstring = "'s ammo detonates him as "; - deathstring2 = "'s EMP fries it\n"; - } else if (deathmsg == 41) { - deathstring = " stepped on too many of "; - deathstring2 = "'s caltrops\n"; - } else if (deathmsg == DMSG_GREN_FLASH) { - deathstring = " is charred by "; - deathstring2 = "'s flash grenade\n"; - } else if (deathmsg == DMSG_GREN_EMP_AMMO) { - deathstring = " stands near some ammo as "; - deathstring2 = "'s EMP nukes it\n"; - } else if (deathmsg == DMSG_DETPACK) { - deathstring = " reaches orbit via "; - deathstring2 = "'s detpack\n"; - } else if (deathmsg == DMSG_DETPACK_DIS) { - deathstring = " cut the red wire of "; - deathstring2 = "'s detpack\n"; - } else if (deathmsg == DMSG_BIOWEAPON) { - deathstring = " dies from "; - deathstring2 = "'s mysterious tropical disease\n"; - } else if (deathmsg == DMSG_BIOWEAPON_ATT) { - deathstring = " escapes infection from "; - deathstring2 = " by dying first\n"; - } else if (deathmsg == DMSG_GRENADEL) { - deathstring = " eats "; - deathstring2 = "'s pineapple\n"; - if (targ.health < -40) { - deathstring = " was gibbed by "; - deathstring2 = "'s grenade\n"; + } else if (pf_deathmsg == DMSG_GREN_PIPE) { + s_deathstring = " is caught by "; + s_deathstring2 = "'s pipebomb trap\n"; + } else if (pf_deathmsg == 40) { + s_deathstring = " fell victim to "; + s_deathstring2 = "'s fireworks\n"; + } else if (pf_deathmsg == DMSG_GREN_GAS) { + s_deathstring = " gags on "; + s_deathstring2 = "'s noxious gasses\n"; + } else if (pf_deathmsg == DMSG_GREN_EMP) { + s_deathstring = "'s ammo detonates him as "; + s_deathstring2 = "'s EMP fries it\n"; + } else if (pf_deathmsg == 41) { + s_deathstring = " stepped on too many of "; + s_deathstring2 = "'s caltrops\n"; + } else if (pf_deathmsg == DMSG_GREN_FLASH) { + s_deathstring = " is charred by "; + s_deathstring2 = "'s flash grenade\n"; + } else if (pf_deathmsg == DMSG_GREN_EMP_AMMO) { + s_deathstring = " stands near some ammo as "; + s_deathstring2 = "'s EMP nukes it\n"; + } else if (pf_deathmsg == DMSG_DETPACK) { + s_deathstring = " reaches orbit via "; + s_deathstring2 = "'s detpack\n"; + } else if (pf_deathmsg == DMSG_DETPACK_DIS) { + s_deathstring = " cut the red wire of "; + s_deathstring2 = "'s detpack\n"; + } else if (pf_deathmsg == DMSG_BIOWEAPON) { + s_deathstring = " dies from "; + s_deathstring2 = "'s mysterious tropical disease\n"; + } else if (pf_deathmsg == DMSG_BIOWEAPON_ATT) { + s_deathstring = " escapes infection from "; + s_deathstring2 = " by dying first\n"; + } else if (pf_deathmsg == DMSG_GRENADEL) { + s_deathstring = " eats "; + s_deathstring2 = "'s pineapple\n"; + if (pe_target.health < -40) { + s_deathstring = " was gibbed by "; + s_deathstring2 = "'s grenade\n"; } - } else if (deathmsg == DMSG_ROCKETL) { - deathstring = " rides "; - deathstring2 = "'s rocket\n"; - if (targ.health < -40) { - deathstring = " was gibbed by "; - deathstring2 = "'s rocket\n"; + } else if (pf_deathmsg == DMSG_ROCKETL) { + s_deathstring = " rides "; + s_deathstring2 = "'s rocket\n"; + if (pe_target.health < -40) { + s_deathstring = " was gibbed by "; + s_deathstring2 = "'s rocket\n"; } - } else if (deathmsg == DMSG_FLAME) { + } else if (pf_deathmsg == DMSG_FLAME) { if (rnum < 0.2) { - deathstring = " is burnt up by "; - deathstring2 = "'s flame\n"; + s_deathstring = " is burnt up by "; + s_deathstring2 = "'s flame\n"; } else if (rnum < 0.4) { - deathstring = " is fried by "; - deathstring2 = "'s fire\n"; + s_deathstring = " is fried by "; + s_deathstring2 = "'s fire\n"; } else if (rnum < 0.6) { - deathstring = " feels "; - deathstring2 = "'s fire of wrath\n"; + s_deathstring = " feels "; + s_deathstring2 = "'s fire of wrath\n"; } else if (rnum < 0.8) { - deathstring = " is reduced to ashes by "; - deathstring2 = "\n"; + s_deathstring = " is reduced to ashes by "; + s_deathstring2 = "\n"; } else { - deathstring = " is grilled by "; - deathstring2 = "'s flame\n"; + s_deathstring = " is grilled by "; + s_deathstring2 = "'s flame\n"; } - } else if (deathmsg == DMSG_AXE) { - deathstring2 = "\n"; - if (attacker.playerclass == PC_SPY) - deathstring = " was knife-murdered by "; - else if (attacker.playerclass == PC_SCOUT) - deathstring = "'s mellon was split by "; - else if (attacker.playerclass == PC_SNIPER) - deathstring = " was put on the chop block by "; - else if (attacker.playerclass == PC_SOLDIER) { - deathstring = " was sliced and diced by "; - deathstring2 = "'s blade\n"; - } else if (attacker.playerclass == PC_DEMOMAN) { - deathstring = - " is split from crotch to sternum by "; - deathstring2 = "'s axe swing\n"; - } else if (attacker.playerclass == PC_HVYWEAP) - deathstring = - " is split in two with a powerful axe blow from "; - else if (attacker.playerclass == PC_PYRO) { - deathstring = "'s death put another notch on "; - deathstring2 = "'s axe\n"; + } else if (pf_deathmsg == DMSG_AXE) { + s_deathstring2 = "\n"; + if (pe_attacker.playerclass == PC_SPY) + s_deathstring = " was knife-murdered by "; + else if (pe_attacker.playerclass == PC_SCOUT) + s_deathstring = "'s mellon was split by "; + else if (pe_attacker.playerclass == PC_SNIPER) + s_deathstring = " was put on the chop block by "; + else if (pe_attacker.playerclass == PC_SOLDIER) { + s_deathstring = " was sliced and diced by "; + s_deathstring2 = "'s blade\n"; + } else if (pe_attacker.playerclass == PC_DEMOMAN) { + s_deathstring = " is split from crotch to sternum by "; + s_deathstring2 = "'s axe swing\n"; + } else if (pe_attacker.playerclass == PC_HVYWEAP) + s_deathstring = " is split in two with a powerful axe blow from "; + else if (pe_attacker.playerclass == PC_PYRO) { + s_deathstring = "'s death put another notch on "; + s_deathstring2 = "'s axe\n"; } else - deathstring = " was ax-murdered by "; - } else if (deathmsg == DMSG_SPANNER) { - deathstring = " was spanner-murdered by "; - deathstring2 = "\n"; - } else if (deathmsg == DMSG_SHOTGUN) { - if (attacker.playerclass == PC_SCOUT) { - deathstring = " got too close to "; - deathstring2 = "'s muzzleflash\n"; - } else if (attacker.playerclass == PC_SOLDIER) { - deathstring = " practices being "; - deathstring2 = "'s clay pigeon\n"; - } else if (attacker.playerclass == PC_DEMOMAN) { - deathstring = " was on the receiving end of "; - deathstring2 = "'s shotgun barrel\n"; - } else if (attacker.playerclass == PC_MEDIC) { - deathstring = " was fed a lead diet by "; - deathstring2 = "\n"; - } else if (attacker.playerclass == PC_HVYWEAP) { - deathstring = " got blasted by "; - deathstring2 = "'s last resort\n"; - } else if (attacker.playerclass == PC_PYRO) { - deathstring = " got more than a powderburn from "; - deathstring2 = "'s shotgun blast\n"; + s_deathstring = " was ax-murdered by "; + } else if (pf_deathmsg == DMSG_SPANNER) { + s_deathstring = " was spanner-murdered by "; + s_deathstring2 = "\n"; + } else if (pf_deathmsg == DMSG_SHOTGUN) { + if (pe_attacker.playerclass == PC_SCOUT) { + s_deathstring = " got too close to "; + s_deathstring2 = "'s muzzleflash\n"; + } else if (pe_attacker.playerclass == PC_SOLDIER) { + s_deathstring = " practices being "; + s_deathstring2 = "'s clay pigeon\n"; + } else if (pe_attacker.playerclass == PC_DEMOMAN) { + s_deathstring = " was on the receiving end of "; + s_deathstring2 = "'s shotgun barrel\n"; + } else if (pe_attacker.playerclass == PC_MEDIC) { + s_deathstring = " was fed a lead diet by "; + s_deathstring2 = "\n"; + } else if (pe_attacker.playerclass == PC_HVYWEAP) { + s_deathstring = " got blasted by "; + s_deathstring2 = "'s last resort\n"; + } else if (pe_attacker.playerclass == PC_PYRO) { + s_deathstring = " got more than a powderburn from "; + s_deathstring2 = "'s shotgun blast\n"; } else { - deathstring = " chewed on "; - deathstring2 = "'s boomstick\n"; + s_deathstring = " chewed on "; + s_deathstring2 = "'s boomstick\n"; } - } else if (deathmsg == DMSG_SSHOTGUN) { - if (attacker.playerclass == PC_SOLDIER) { - deathstring = " was turned into swiss cheese by "; - deathstring2 = "'s buckshot\n"; - } else if (attacker.playerclass == PC_MEDIC) { - deathstring = " got a double-dose of "; - deathstring2 = "'s buckshot\n"; - } else if (attacker.playerclass == PC_HVYWEAP) { - deathstring = " unfortunately forgot "; - deathstring2 = " carried a super-shotgun\n"; - } else if (attacker.playerclass == PC_SPY) { - deathstring = " gets ventilated by "; - deathstring2 = "'s super-shotgun blast\n"; - } else if (attacker.playerclass == PC_ENGINEER) { - deathstring = "'s body got chuck full of "; - deathstring2 = "'s lead pellets\n"; + } else if (pf_deathmsg == DMSG_SSHOTGUN) { + if (pe_attacker.playerclass == PC_SOLDIER) { + s_deathstring = " was turned into swiss cheese by "; + s_deathstring2 = "'s buckshot\n"; + } else if (pe_attacker.playerclass == PC_MEDIC) { + s_deathstring = " got a double-dose of "; + s_deathstring2 = "'s buckshot\n"; + } else if (pe_attacker.playerclass == PC_HVYWEAP) { + s_deathstring = " unfortunately forgot "; + s_deathstring2 = " carried a super-shotgun\n"; + } else if (pe_attacker.playerclass == PC_SPY) { + s_deathstring = " gets ventilated by "; + s_deathstring2 = "'s super-shotgun blast\n"; + } else if (pe_attacker.playerclass == PC_ENGINEER) { + s_deathstring = "'s body got chuck full of "; + s_deathstring2 = "'s lead pellets\n"; } else { - deathstring = " ate 2 loads of "; - deathstring2 = "'s buckshot\n"; + s_deathstring = " ate 2 loads of "; + s_deathstring2 = "'s buckshot\n"; } - } else if (deathmsg == DMSG_NAILGUN) { - if (attacker.playerclass == PC_SCOUT) { - deathstring = " caught one too many nails from "; - deathstring2 = "\n"; - } else if (attacker.playerclass == PC_SNIPER) { - deathstring = " ran into "; - deathstring2 = "'s nails\n"; - } else if (attacker.playerclass == PC_SPY) { - deathstring = " was turned into "; - deathstring2 = "'s pin-cushion\n"; + } else if (pf_deathmsg == DMSG_NAILGUN) { + if (pe_attacker.playerclass == PC_SCOUT) { + s_deathstring = " caught one too many nails from "; + s_deathstring2 = "\n"; + } else if (pe_attacker.playerclass == PC_SNIPER) { + s_deathstring = " ran into "; + s_deathstring2 = "'s nails\n"; + } else if (pe_attacker.playerclass == PC_SPY) { + s_deathstring = " was turned into "; + s_deathstring2 = "'s pin-cushion\n"; } else { - deathstring = " was nailed by "; - deathstring2 = "\n"; + s_deathstring = " was nailed by "; + s_deathstring2 = "\n"; } - } else if (deathmsg == DMSG_SNAILGUN) { - deathstring = " was punctured by "; - deathstring2 = "\n"; - } else if (deathmsg == DMSG_LIGHTNING) { - deathstring = " accepts "; - if (attacker.waterlevel > 1) - deathstring2 = "'s discharge\n"; + } else if (pf_deathmsg == DMSG_SNAILGUN) { + s_deathstring = " was punctured by "; + s_deathstring2 = "\n"; + } else if (pf_deathmsg == DMSG_LIGHTNING) { + s_deathstring = " accepts "; + if (pe_attacker.waterlevel > 1) + s_deathstring2 = "'s discharge\n"; else - deathstring2 = "'s shaft\n"; - } else if (deathmsg == DMSG_SNIPERRIFLE) { + s_deathstring2 = "'s shaft\n"; + } else if (pf_deathmsg == DMSG_SNIPERRIFLE) { if (rnum <= 0.3) { - deathstring = " takes a bullet in the chest from "; - deathstring2 = "\n"; + s_deathstring = " takes a bullet in the chest from "; + s_deathstring2 = "\n"; } else { - deathstring = " succumbs to sniperfire from "; - deathstring2 = "\n"; + s_deathstring = " succumbs to sniperfire from "; + s_deathstring2 = "\n"; } - } else if (deathmsg == DMSG_SNIPERHEADSHOT) { + } else if (pf_deathmsg == DMSG_SNIPERHEADSHOT) { if (rnum <= 0.5) { - deathstring = " gets a third eye from "; - deathstring2 = "\n"; + s_deathstring = " gets a third eye from "; + s_deathstring2 = "\n"; } else { - deathstring = " gets his head blown off by "; - deathstring2 = "\n"; + s_deathstring = " gets his head blown off by "; + s_deathstring2 = "\n"; } - } else if (deathmsg == DMSG_SNIPERLEGSHOT) { + } else if (pf_deathmsg == DMSG_SNIPERLEGSHOT) { if (rnum <= 0.5) { - deathstring = " is made legless by "; - deathstring2 = "\n"; + s_deathstring = " is made legless by "; + s_deathstring2 = "\n"; } else { - deathstring = " gets his legs blown off by "; - deathstring2 = "\n"; + s_deathstring = " gets his legs blown off by "; + s_deathstring2 = "\n"; } - } else if (deathmsg == DMSG_AUTORIFLE) { - deathstring = " collects "; - deathstring2 = "'s bullet spray.\n"; - } else if (deathmsg == DMSG_ASSAULTCANNON) { - deathstring = " gets sawn in half by "; - deathstring2 = "\n"; - } else if (deathmsg == DMSG_BACKSTAB) { - deathstring = " gets knifed from behind by "; - deathstring2 = "\n"; - } else if (deathmsg == DMSG_TRANQ) { - deathstring = " is put to sleep by "; - deathstring2 = "\n"; - } else if (deathmsg == DMSG_LASERBOLT) { - deathstring = " gets a hole in his heart from "; - deathstring2 = "'s railgun\n"; - } else if (deathmsg == DMSG_INCENDIARY) { - deathstring = " gets well done by "; - deathstring2 = "'s incendiary rocket\n"; - } else if (deathmsg == 38) { - deathstring = " gets destroyed by "; - deathstring2 = "'s exploding sentrygun\n"; - } else if (deathmsg == 39) { - deathstring = - " didn't insert the correct change into "; - deathstring2 = "'s dispenser.\n"; + } else if (pf_deathmsg == DMSG_AUTORIFLE) { + s_deathstring = " collects "; + s_deathstring2 = "'s bullet spray.\n"; + } else if (pf_deathmsg == DMSG_ASSAULTCANNON) { + s_deathstring = " gets sawn in half by "; + s_deathstring2 = "\n"; + } else if (pf_deathmsg == DMSG_BACKSTAB) { + s_deathstring = " gets knifed from behind by "; + s_deathstring2 = "\n"; + } else if (pf_deathmsg == DMSG_TRANQ) { + s_deathstring = " is put to sleep by "; + s_deathstring2 = "\n"; + } else if (pf_deathmsg == DMSG_LASERBOLT) { + s_deathstring = " gets a hole in his heart from "; + s_deathstring2 = "'s railgun\n"; + } else if (pf_deathmsg == DMSG_INCENDIARY) { + s_deathstring = " gets well done by "; + s_deathstring2 = "'s incendiary rocket\n"; + } else if (pf_deathmsg == 38) { + s_deathstring = " gets destroyed by "; + s_deathstring2 = "'s exploding sentrygun\n"; + } else if (pf_deathmsg == 39) { + s_deathstring = " didn't insert the correct change into "; + s_deathstring2 = "'s dispenser.\n"; } - if ((attacker.has_disconnected == 1) || - (attacker.netname == string_null)) { - deathstring = " died."; - deathstring2 = "\n"; + if (pe_attacker.has_disconnected == 1 || pe_attacker.netname == string_null) { + s_deathstring = " died."; + s_deathstring2 = "\n"; } - bprint(PRINT_MEDIUM, targ.netname, deathstring, - attacker.netname, deathstring2); + + return strcat(pe_target.netname, + strcat(s_deathstring, + strcat(pe_attacker.netname, s_deathstring2))); + } - return; - } else if (attacker.classname == "building_sentrygun") { - if (targ == attacker.real_owner) { - if (deathmsg == DMSG_SENTRYGUN_ROCKET) - deathstring = " intercepts his sentry gun's rocket\n"; - else if (deathmsg == DMSG_SENTRYGUN_BULLET) - deathstring = - " crossed his sentry gun's line of fire\n"; - - bprint(PRINT_MEDIUM, targ.netname, deathstring); - } else if ((teamplay && (attacker.team_no == targ.team_no)) && - (attacker.team_no > 0)) { - bprint(PRINT_MEDIUM, targ.netname, - " obstructs his team's sentry gun\n"); + + } else if (pe_attacker.classname == "building_sentrygun") { + + if (pe_target == pe_attacker.real_owner) { + + if (pf_deathmsg == DMSG_SENTRYGUN_ROCKET) + s_deathstring = " intercepts his sentry gun's rocket\n"; + else if (pf_deathmsg == DMSG_SENTRYGUN_BULLET) + s_deathstring = " crossed his sentry gun's line of fire\n"; + + return strcat(pe_target.netname, s_deathstring); + + } else if ((teamplay && (pe_attacker.team_no == pe_target.team_no)) && (pe_attacker.team_no > 0)) { + + return strcat(pe_target.netname, " obstructs his team's sentry gun\n"); + } else { - TF_AddFrags(attacker.real_owner, 1); - logfrag(attacker.real_owner, targ); - if (deathmsg == DMSG_SENTRYGUN_ROCKET) { - deathstring = " hates "; - deathstring2 = "'s sentry gun\n"; - } else if (deathmsg == DMSG_SENTRYGUN_BULLET) { - deathstring = " is mown down by "; - deathstring2 = "'s sentry gun\n"; + if (pf_deathmsg == DMSG_SENTRYGUN_ROCKET) { + s_deathstring = " hates "; + s_deathstring2 = "'s sentry gun\n"; + } else if (pf_deathmsg == DMSG_SENTRYGUN_BULLET) { + s_deathstring = " is mown down by "; + s_deathstring2 = "'s sentry gun\n"; } - bprint(PRINT_MEDIUM, targ.netname, deathstring, - attacker.real_owner.netname, deathstring2); + + return strcat(pe_target.netname, + strcat(s_deathstring, + strcat(pe_attacker.real_owner.netname, s_deathstring2))); + } + } else { - logfrag(targ, targ); - TF_AddFrags(targ, -1); - rnum = targ.watertype; - bprint(PRINT_MEDIUM, targ.netname); + rnum = pe_target.watertype; if (rnum == -3) { if (random() < 0.5) - deathstring = " sleeps with the fishes\n"; + s_deathstring = " sleeps with the fishes\n"; else - deathstring = " sucks it down\n"; + s_deathstring = " sucks it down\n"; } else if (rnum == -4) { if (random() < 0.5) - deathstring = " gulped a load of slime\n"; + s_deathstring = " gulped a load of slime\n"; else - deathstring = " can't exist on slime alone\n"; + s_deathstring = " can't exist on slime alone\n"; } else if (rnum == -5) { - if (targ.health < -15) - deathstring = " burst into flames\n"; + if (pe_target.health < -15) + s_deathstring = " burst into flames\n"; else if (random() < 0.5) - deathstring = " turned into hot slag\n"; + s_deathstring = " turned into hot slag\n"; else - deathstring = " visits the Volcano God\n"; - } else if (attacker.classname == "explo_box") - deathstring = " blew up\n"; - else if ((attacker.solid == SOLID_BSP) && (attacker != world)) - deathstring = " was squished\n"; - else if (targ.deathtype == "falling") { - targ.deathtype = string_null; - deathstring = " fell to his death\n"; - } else if ((attacker.classname == "trap_shooter") - || (attacker.classname == "trap_spikeshooter")) - deathstring = " was spiked\n"; - else if (attacker.classname == "fireball") - deathstring = " ate a lavaball\n"; - else if (attacker.classname == "trigger_changelevel") - deathstring = " tried to leave\n"; + s_deathstring = " visits the Volcano God\n"; + } else if (pe_attacker.classname == "explo_box") + s_deathstring = " blew up\n"; + else if ((pe_attacker.solid == SOLID_BSP) && (pe_attacker != world)) + s_deathstring = " was squished\n"; + else if (pe_target.deathtype == "falling") { + s_deathstring = " fell to his death\n"; + } else if ((pe_attacker.classname == "trap_shooter") + || (pe_attacker.classname == "trap_spikeshooter")) + s_deathstring = " was spiked\n"; + else if (pe_attacker.classname == "fireball") + s_deathstring = " ate a lavaball\n"; + else if (pe_attacker.classname == "trigger_changelevel") + s_deathstring = " tried to leave\n"; else - deathstring = " died\n"; + s_deathstring = " died\n"; + + return strcat(pe_target.netname, s_deathstring); - bprint(PRINT_MEDIUM, deathstring); } - } else if (targ.classname == "building_sentrygun") { + + } else if (pe_target.classname == "building_sentrygun") { + + if (pe_attacker.classname == "teledeath") { + return strcat(pe_target.real_owner.netname, + strcat("'s sentrygun was telefragged by ", + strcat(pe_attacker.owner.netname, "\n"))); + } + if (pe_attacker.classname == "player") { + if (pe_attacker == pe_target.real_owner) { + return strcat(pe_target.real_owner.netname, " destroys his sentrygun\n"); + } + return strcat(pe_target.real_owner.netname, + strcat("'s sentrygun was destroyed by ", + strcat(pe_attacker.netname, "\n"))); + } + + } + + return ""; +}; + +void (entity targ, entity attacker) ClientObituary = { + local string deathstring; + + Sniper_ZoomReset(targ); + + if ((cb_prematch_time + 3) > time) + return; + + deathstring = GetDeathMessage(targ, attacker, deathmsg); + bprint(PRINT_MEDIUM, deathstring); + + if (targ.classname == "player") { if (attacker.classname == "teledeath") { - bprint(PRINT_MEDIUM, targ.real_owner.netname, - "'s sentrygun was telefragged by ", - attacker.owner.netname, "\n"); - return; + + if (attacker.owner.team_no != targ.team_no || attacker.owner.team_no < 1) + TF_AddFrags(attacker.owner, 1); + } - if (attacker.classname == "player") { - if (attacker == targ.real_owner) { - bprint(PRINT_MEDIUM, targ.real_owner.netname, - " destroys his sentrygun\n"); + if (attacker.classname == "teledeath2") { + + TF_AddFrags(targ, -1); + logfrag(targ, targ); + + } + if (attacker.classname == "info_tfgoal" || attacker.classname == "item_tfgoal") { + + if (attacker.deathtype != "") + bprint(PRINT_MEDIUM, targ.netname, attacker.deathtype); + + logfrag(targ, targ); + + } + if (attacker.classname == "player" || attacker.classname == "bot") { + + if (targ == attacker) { + + // killed self + TF_AddFrags(attacker, -1); return; - } - bprint(PRINT_MEDIUM, targ.real_owner.netname, - "'s sentrygun was destroyed by ", attacker.netname, - "\n"); - if ((attacker.team_no > 0) && - (attacker.team_no == targ.real_owner.team_no)) { + } else if ((teamplay && attacker.team_no == targ.team_no) && attacker.team_no > 0) { + + // killed a team member TF_AddFrags(attacker, -1); - attacker.teamkills = attacker.teamkills + 1; + + if (targ.undercover_team == 0) + attacker.teamkills = attacker.teamkills + 1; + CheckAutoKick(attacker); - } else + return; + + } else { + TF_AddFrags(attacker, 1); + logfrag(attacker, targ); + + } + + } else if (attacker.classname == "building_sentrygun") { + + if (targ != attacker.real_owner) { + + TF_AddFrags(attacker.real_owner, 1); + logfrag(attacker.real_owner, targ); + + } + + } else { + + logfrag(targ, targ); + TF_AddFrags(targ, -1); - return; } + + } else if (targ.classname == "building_sentrygun") { + + if (attacker.team_no > 0 && attacker.team_no == targ.real_owner.team_no) { + + TF_AddFrags(attacker, -1); + attacker.teamkills = attacker.teamkills + 1; + CheckAutoKick(attacker); + + } else { + + TF_AddFrags(attacker, 1); + + } + } else if (targ.classname == "building_dispenser") { - if ((attacker.team_no > 0) && - (attacker.team_no == targ.real_owner.team_no)) { + + if (attacker.team_no > 0 && attacker.team_no == targ.real_owner.team_no) { TF_AddFrags(attacker, -1); attacker.teamkills = attacker.teamkills + 1; CheckAutoKick(attacker); } + } + }; diff --git a/qw.qc b/qw.qc index af71772c..fda9722a 100644 --- a/qw.qc +++ b/qw.qc @@ -342,6 +342,7 @@ float num_world_flames; .float undercover_team; .float undercover_skin; .string undercover_name; +.entity attacked_by; // Used by spy feign death to produce a fake death message float live_camera; .float camdist; diff --git a/spy.qc b/spy.qc index 5e2b2453..54330088 100644 --- a/spy.qc +++ b/spy.qc @@ -354,6 +354,7 @@ void () spy_upaxe9 =[41, spy_upaxe9] { }; void (float issilent) TeamFortress_SpyFeignDeath = { + local string deathstring; local float i; local float j; local entity at_spot; @@ -449,6 +450,8 @@ void (float issilent) TeamFortress_SpyFeignDeath = { if (issilent == 0) { DeathSound(); Spy_DropBackpack(); + deathstring = GetDeathMessage(self, self.attacked_by, deathmsg); + bprint(PRINT_MEDIUM, deathstring); } self.angles_x = 0; self.angles_z = 0; diff --git a/weapons.qc b/weapons.qc index 88b44641..91dacf06 100644 --- a/weapons.qc +++ b/weapons.qc @@ -682,6 +682,9 @@ void (float damage, vector dir) TraceAttack = { blood_org = org; AddMultiDamage(trace_ent, damage); + if (trace_ent.playerclass == PC_SPY) + trace_ent.attacked_by = self; + } else puff_count = puff_count + 1; }; From c0058d8d6b6e899266e3d1680680ddee4259e0da Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 09:28:00 +0200 Subject: [PATCH 0146/2474] Make feign Spy class special instead of sfeign --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index af1a0f39..00da0c27 100644 --- a/tfort.qc +++ b/tfort.qc @@ -21,7 +21,7 @@ void () UseSpecialSkill = { else if (self.playerclass == PC_DEMOMAN) self.impulse = TF_PB_DETONATE; else if (self.playerclass == PC_SPY) - self.impulse = TF_SPY_SILENT_DIE; + self.impulse = TF_SPY_DIE; else if (self.playerclass == PC_ENGINEER) self.impulse = TF_ENGINEER_DETDISP; else if (self.playerclass == PC_UNDEFINED) { From 6dfd337e4d2f54c8b67773e6daa064bdbb14d4a5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 09:44:28 +0200 Subject: [PATCH 0147/2474] Keep class menu open if user selects illegal class (fixes #131) --- menu.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/menu.qc b/menu.qc index ba3374eb..a0c0d475 100644 --- a/menu.qc +++ b/menu.qc @@ -23,6 +23,7 @@ float (float tno) TeamFortress_TeamIsCivilian; float (float tno) TeamFortress_TeamGetNoPlayers; float () TeamFortress_GetNoPlayers; +float (float pc) IsLegalClass; void (float inp) TeamFortress_ChangeClass; void (entity p) TeamFortress_SetSkin; @@ -198,8 +199,10 @@ void () Menu_Team = { }; void (float inp) Menu_Class_Input = { - if (inp > 0 && inp <= 10) - TeamFortress_ChangeClass(inp); + if (!inp || inp > 10 || !IsLegalClass(inp)) + Menu_Class(); + + TeamFortress_ChangeClass(inp); }; void () Menu_Class = { From 17f9c16957ff2f57edb9c8a490bc154adaea36d6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 09:47:43 +0200 Subject: [PATCH 0148/2474] Allow /saveme during reload (fixes #132) --- weapons.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/weapons.qc b/weapons.qc index 91dacf06..a4ec1b82 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2571,6 +2571,12 @@ void () W_WeaponFrame = { return; } + // medic /saveme + if (self.impulse == TF_MEDIC_HELPME) { + ImpulseCommands(); + return; + } + if (!WeaponReady(self)) return; From 5ee54f726cc83770dd8c0f35af80108ba0802933 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 13:51:02 +0200 Subject: [PATCH 0149/2474] Change feign in Spy menu to silent --- menu.qc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/menu.qc b/menu.qc index a0c0d475..ef891a00 100644 --- a/menu.qc +++ b/menu.qc @@ -354,7 +354,7 @@ void (float inp) Menu_Spy_Input = { } else if (inp == 2) { Menu_Spy_Color(); } else if (inp == 3) { - TeamFortress_SpyFeignDeath(0); + TeamFortress_SpyFeignDeath(1); if (self.is_feigning) { Menu_Spy(); } @@ -365,26 +365,26 @@ void (float inp) Menu_Spy_Input = { void () Menu_Spy = { local string s_action = "Action:\n\n"; - local string s_skin = "“‘ Change skin \n"; - local string s_color = "”‘ Change color \n"; + local string s_skin = "“‘ Change skin \n"; + local string s_color = "”‘ Change color \n"; local string s_feign, s_reset; - local string s_nothing = "\n—‘ Nothing "; + local string s_nothing = "\n—‘ Nothing "; if (self.effects & (8 | 4) || self.is_unabletospy == 1) { return; } if (self.is_feigning) - s_feign = "•‘ Stop feigning \n"; + s_feign = "•‘ Stop feigning \n"; else - s_feign = "•‘ Start feigning\n"; + s_feign = "•‘ Start feigning (silent)\n"; if (self.undercover_team != 0 && self.undercover_skin != 0) - s_reset = "–‘ Reset disguise\n"; + s_reset = "–‘ Reset disguise \n"; else if (self.undercover_team != 0) - s_reset = "–‘ Reset color \n"; + s_reset = "–‘ Reset color \n"; else if (self.undercover_skin != 0) - s_reset = "–‘ Reset skin \n"; + s_reset = "–‘ Reset skin \n"; else s_reset = "\n"; From 648b53aadbb5e854625844ddd3fa31ca634aae1b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 14:05:20 +0200 Subject: [PATCH 0150/2474] Allow spies to feign while in air (closes #134) --- client.qc | 4 ++++ spy.qc | 9 +++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/client.qc b/client.qc index c423e122..e5684c3e 100644 --- a/client.qc +++ b/client.qc @@ -1439,6 +1439,10 @@ void () PlayerPreThink = { self.impulse = 0; } + if (self.is_feigning && (self.flags & FL_ONGROUND) && !(self.tfstate & TFSTATE_CANT_MOVE)) { + self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + } if (self.is_feigning && (self.waterlevel == 1)) { self.watertype = -3; self.waterlevel = 3; diff --git a/spy.qc b/spy.qc index 54330088..9e6b9a2b 100644 --- a/spy.qc +++ b/spy.qc @@ -392,7 +392,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { self.is_feigning = 0; self.current_weapon = self.weapon; W_SetCurrentAmmo(self); - self.tfstate = self.tfstate - (self.tfstate & 65536); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); if (self.weapon <= 16) { spy_upaxe1(); @@ -419,10 +419,6 @@ void (float issilent) TeamFortress_SpyFeignDeath = { sprint(self, PRINT_HIGH, "You cannot feign right now\n"); return; } - if (!(self.flags & 512) && (self.waterlevel == 0)) { - sprint(self, PRINT_HIGH, "You cannot feign in the air\n"); - return; - } at_spot = findradius(self.origin, 64); while (at_spot != world) { if (((at_spot.classname == "player") && (self != at_spot)) && @@ -434,7 +430,8 @@ void (float issilent) TeamFortress_SpyFeignDeath = { at_spot = at_spot.chain; } self.immune_to_check = time + 5; - self.tfstate = self.tfstate | 65536; + if (self.flags & FL_ONGROUND) + self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); self.is_feigning = 1; Attack_Finished(0.8); From 28e137d4a427e25fa087be62dd5a65f3fa011406 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 18:17:45 +0200 Subject: [PATCH 0151/2474] Add option to drop normal grenades in backpack (closes #135) --- client.qc | 6 +++++ items.qc | 75 +++++++++++++++++++++++++++++++++++-------------------- qw.qc | 1 + 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/client.qc b/client.qc index e5684c3e..d9841d6f 100644 --- a/client.qc +++ b/client.qc @@ -348,6 +348,12 @@ void () DecodeLevelParms = { if (st == "on") old_grens = TRUE; + st = infokey(world, "dg"); + if (st == string_null) + st = infokey(world, "drop_grenades"); + if (st == "on") + drop_grenades = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/items.qc b/items.qc index 5e11a6db..64d4021d 100644 --- a/items.qc +++ b/items.qc @@ -758,29 +758,56 @@ void (entity pl, float typ) PrintGrenadeType = { st = ""; if (typ == 1) { - st = "Normal"; + st = "normal"; } else if (typ == 2) { - st = "Concussion"; + st = "concussion"; } else if (typ == 3) { - st = "Nail"; + st = "nail"; } else if (typ == 4) { - st = "Mirv"; + st = "mirv"; } else if (typ == 5) { - st = "Napalm"; + st = "napalm"; } else if (typ == 6) { - st = "Flare"; + st = "flare"; } else if (typ == 7) { - st = "Gas"; + st = "gas"; } else if (typ == 8) { st = "EMP"; } else if (typ == 10) { - st = "Caltrop"; + st = "caltrop"; } else if (typ == 9) { - st = "Flash"; + st = "flash"; } sprint(pl, PRINT_HIGH, st); }; +void (entity pe_player, float pf_grenade_type, float pf_count) PrintFoundGrenade = { + local float f_count = pf_count; + + if (!f_count) + return; + + if (pe_player.no_grenades_1 >= 4) + return; + + if (f_count > 1) + f_count = 4 - pe_player.no_grenades_1; + + sprint(pe_player, PRINT_HIGH, "You found "); + if (f_count > 1) + sprint(pe_player, PRINT_HIGH, ftos(f_count), " "); + else + sprint(pe_player, PRINT_HIGH, "a "); + PrintGrenadeType(pe_player, pf_grenade_type); + if (pf_grenade_type == GR_TYPE_CALTROP) + sprint(pe_player, PRINT_HIGH, " canister"); + else + sprint(pe_player, PRINT_HIGH, " grenade"); + if (f_count > 1) + sprint(pe_player, PRINT_HIGH, "s"); + sprint(pe_player, PRINT_HIGH, "\n"); +}; + float () GetGrenadePossibility = { local float maxg; @@ -797,13 +824,7 @@ float () GetGrenadePossibility = { } if ((other.tp_grenades_1 != 0) && (other.no_grenades_1 < maxg)) { other.no_grenades_1 = other.no_grenades_1 + 1; - sprint(other, PRINT_HIGH, "You found a "); - PrintGrenadeType(other, other.tp_grenades_1); - if (other.tp_grenades_1 == GR_TYPE_CALTROP) { - sprint(other, PRINT_HIGH, " canister\n"); - } else { - sprint(other, PRINT_HIGH, " grenade\n"); - } + PrintFoundGrenade(other, other.tp_grenades_1, 1); return (1); } } else { @@ -815,13 +836,7 @@ float () GetGrenadePossibility = { } if ((other.tp_grenades_2 != 0) && (other.no_grenades_2 < maxg)) { other.no_grenades_2 = other.no_grenades_2 + 1; - sprint(other, PRINT_HIGH, "You found a "); - PrintGrenadeType(other, other.tp_grenades_2); - if (other.tp_grenades_2 == GR_TYPE_CALTROP) { - sprint(other, PRINT_HIGH, " canister\n"); - } else { - sprint(other, PRINT_HIGH, " grenade\n"); - } + PrintFoundGrenade(other, other.tp_grenades_2, 1); return (1); } } @@ -1340,6 +1355,10 @@ void () BackpackTouch = { other.ammo_nails = other.ammo_nails + self.ammo_nails; other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; other.ammo_cells = other.ammo_cells + self.ammo_cells; + if (drop_grenades && other.playerclass != PC_SCOUT) { + PrintFoundGrenade(other, other.tp_grenades_1, self.no_grenades_1); + other.no_grenades_1 = min(4, (other.tp_grenades_1 + self.no_grenades_1)); + } bound_other_ammo(other); sprint(other, PRINT_LOW, "You get "); if (self.ammo_shells) { @@ -1379,10 +1398,10 @@ void () DropBackpack = { if ((cb_prematch_time + 3) > time) return; - if (! - (self.ammo_shells + self.ammo_nails + self.ammo_rockets + - self.ammo_cells)) - return; + if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) { + if (!(drop_grenades && (self.no_grenades_1 + self.no_grenades_2))) + return; + } newmis = spawn(); newmis.origin = self.origin - '0 0 24'; @@ -1391,6 +1410,8 @@ void () DropBackpack = { newmis.ammo_nails = self.ammo_nails; newmis.ammo_rockets = self.ammo_rockets; newmis.ammo_cells = self.ammo_cells; + if (drop_grenades) + newmis.no_grenades_1 = self.no_grenades_1; newmis.armorvalue = self.armorvalue; diff --git a/qw.qc b/qw.qc index fda9722a..17d6045f 100644 --- a/qw.qc +++ b/qw.qc @@ -394,6 +394,7 @@ float old_grens; float invis_only; float flagem_checked; float cease_fire; +float drop_grenades; .float teamkills; From 6f05376e689af1613c089851fff3cf00d58a5b2b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 18:20:31 +0200 Subject: [PATCH 0152/2474] Only drop primed normal grenades upon death --- tfort.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 00da0c27..262540ed 100644 --- a/tfort.qc +++ b/tfort.qc @@ -685,7 +685,10 @@ void () TeamFortress_GrenadePrimed = { newmis.classname = "grenade"; makevectors(user.v_angle); if (user.deadflag) { - newmis.velocity = '0 0 200'; + if (self.weapon == GR_TYPE_NORMAL) + newmis.velocity = '0 0 200'; + else + return; } else if (user.v_angle_x) { newmis.velocity = v_forward * 600 + v_up * 200 + crandom() * v_right * 10 + From aa5e9fdc43a901865896d076ac2466ffae494224 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 19:28:43 +0200 Subject: [PATCH 0153/2474] Disable movement in air when feigned (fixes #136) --- spy.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spy.qc b/spy.qc index 9e6b9a2b..e2955023 100644 --- a/spy.qc +++ b/spy.qc @@ -449,6 +449,12 @@ void (float issilent) TeamFortress_SpyFeignDeath = { Spy_DropBackpack(); deathstring = GetDeathMessage(self, self.attacked_by, deathmsg); bprint(PRINT_MEDIUM, deathstring); + if (!(self.flags & FL_ONGROUND)) { + stuffcmd(self, "cl_backspeed 0\n"); + stuffcmd(self, "cl_forwardspeed 0\n"); + stuffcmd(self, "cl_sidespeed 0\n"); + self.maxspeed = 0; + } } self.angles_x = 0; self.angles_z = 0; From 3406ebdd2ecf391bed7d8b08b7d4caa38d291c8b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 19:31:16 +0200 Subject: [PATCH 0154/2474] Add anti spam feign timer (3 seconds) --- qw.qc | 1 + spy.qc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/qw.qc b/qw.qc index 17d6045f..18c3f142 100644 --- a/qw.qc +++ b/qw.qc @@ -366,6 +366,7 @@ float already_chosen_map; // anti spam .float antispam_detpack; // don't spam detpack messages +.float antispam_feign; // don't spam feign deaths // status bar stuff .string StatusString; // current centerprint text (strzone'd!) diff --git a/spy.qc b/spy.qc index e2955023..db121841 100644 --- a/spy.qc +++ b/spy.qc @@ -415,7 +415,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { "You cannot get up while someone is standing on you\n"); } } else { - if (self.is_unabletospy == 1) { + if (self.is_unabletospy == 1 || (time - self.antispam_feign) < 3) { sprint(self, PRINT_HIGH, "You cannot feign right now\n"); return; } @@ -429,6 +429,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { } at_spot = at_spot.chain; } + self.antispam_feign = time; self.immune_to_check = time + 5; if (self.flags & FL_ONGROUND) self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; From cecbd4b59ca2190709ffec406a453dd162ad5bb7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 20:55:37 +0200 Subject: [PATCH 0155/2474] Allow all grenades to be dropped but add option to limit each type (closes #137) --- client.qc | 16 +++++++++ items.qc | 100 ++++++++++++++++++++++++++++++++++++------------------ qw.qc | 2 ++ 3 files changed, 85 insertions(+), 33 deletions(-) diff --git a/client.qc b/client.qc index d9841d6f..9f907dbb 100644 --- a/client.qc +++ b/client.qc @@ -354,6 +354,22 @@ void () DecodeLevelParms = { if (st == "on") drop_grenades = TRUE; + st = infokey(world, "dg1"); + if (st == string_null) + st = infokey(world, "drop_gren1"); + if (st != string_null) + drop_gren1 = stof(st); + else + drop_gren1 = -1; + + st = infokey(world, "dg2"); + if (st == string_null) + st = infokey(world, "drop_gren2"); + if (st != string_null) + drop_gren2 = stof(st); + else + drop_gren2 = -1; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/items.qc b/items.qc index 64d4021d..8ad3e898 100644 --- a/items.qc +++ b/items.qc @@ -781,21 +781,32 @@ void (entity pl, float typ) PrintGrenadeType = { sprint(pl, PRINT_HIGH, st); }; -void (entity pe_player, float pf_grenade_type, float pf_count) PrintFoundGrenade = { - local float f_count = pf_count; - - if (!f_count) - return; +float (float pf_grenade_number, float pf_grenade_type) GetMaxGrenades = { + if (pf_grenade_number == 1) { + if (pf_grenade_type == GR_TYPE_NAIL) { + return 2; + } + if (pf_grenade_type == GR_TYPE_CALTROP) { + return 3; + } + } else { + if (pf_grenade_type == GR_TYPE_NAIL) { + return 2; + } + if (pf_grenade_type == GR_TYPE_CONCUSSION) { + return 3; + } + } + return 4; +} - if (pe_player.no_grenades_1 >= 4) +void (entity pe_player, float pf_grenade_type, float pf_grenade_count) PrintFoundGrenade = { + if (!pf_grenade_count) return; - if (f_count > 1) - f_count = 4 - pe_player.no_grenades_1; - sprint(pe_player, PRINT_HIGH, "You found "); - if (f_count > 1) - sprint(pe_player, PRINT_HIGH, ftos(f_count), " "); + if (pf_grenade_count > 1) + sprint(pe_player, PRINT_HIGH, ftos(pf_grenade_count), " "); else sprint(pe_player, PRINT_HIGH, "a "); PrintGrenadeType(pe_player, pf_grenade_type); @@ -803,7 +814,7 @@ void (entity pe_player, float pf_grenade_type, float pf_count) PrintFoundGrenade sprint(pe_player, PRINT_HIGH, " canister"); else sprint(pe_player, PRINT_HIGH, " grenade"); - if (f_count > 1) + if (pf_grenade_count > 1) sprint(pe_player, PRINT_HIGH, "s"); sprint(pe_player, PRINT_HIGH, "\n"); }; @@ -812,35 +823,24 @@ float () GetGrenadePossibility = { local float maxg; if (random() < 0.500) { - return (0); + return 0; } - maxg = 4; if (random() < 0.500) { - if (other.tp_grenades_1 == 3) { - maxg = 2; - } - if (other.tp_grenades_1 == 10) { - maxg = 3; - } + maxg = GetMaxGrenades(1, other.tp_grenades_1); if ((other.tp_grenades_1 != 0) && (other.no_grenades_1 < maxg)) { other.no_grenades_1 = other.no_grenades_1 + 1; PrintFoundGrenade(other, other.tp_grenades_1, 1); - return (1); + return 1; } } else { - if (other.tp_grenades_2 == 3) { - maxg = 2; - } - if (other.tp_grenades_2 == 2) { - maxg = 3; - } + maxg = GetMaxGrenades(1, other.tp_grenades_2); if ((other.tp_grenades_2 != 0) && (other.no_grenades_2 < maxg)) { other.no_grenades_2 = other.no_grenades_2 + 1; PrintFoundGrenade(other, other.tp_grenades_2, 1); - return (1); + return 1; } } - return (0); + return 0; }; void () ammo_touch = { @@ -1343,6 +1343,7 @@ void () item_artifact_super_damage = { void () BackpackTouch = { local string s; + local float maxg, giveg; if (other.classname != "player" || other.is_feigning) return; @@ -1356,8 +1357,25 @@ void () BackpackTouch = { other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; other.ammo_cells = other.ammo_cells + self.ammo_cells; if (drop_grenades && other.playerclass != PC_SCOUT) { - PrintFoundGrenade(other, other.tp_grenades_1, self.no_grenades_1); - other.no_grenades_1 = min(4, (other.tp_grenades_1 + self.no_grenades_1)); + + // give grenade type 1 + maxg = GetMaxGrenades(1, other.tp_grenades_1); + if ((other.no_grenades_1 + self.no_grenades_1) >= maxg) + giveg = maxg - other.no_grenades_1; + else + giveg = self.no_grenades_1; + other.no_grenades_1 = other.no_grenades_1 + giveg; + PrintFoundGrenade(other, other.tp_grenades_1, giveg); + + // give grenade type 2 + maxg = GetMaxGrenades(2, other.tp_grenades_2); + if ((other.no_grenades_2 + self.no_grenades_2) >= maxg) + giveg = maxg - other.no_grenades_2; + else + giveg = self.no_grenades_2; + other.no_grenades_2 = other.no_grenades_2 + giveg; + PrintFoundGrenade(other, other.tp_grenades_2, giveg); + } bound_other_ammo(other); sprint(other, PRINT_LOW, "You get "); @@ -1410,8 +1428,24 @@ void () DropBackpack = { newmis.ammo_nails = self.ammo_nails; newmis.ammo_rockets = self.ammo_rockets; newmis.ammo_cells = self.ammo_cells; - if (drop_grenades) - newmis.no_grenades_1 = self.no_grenades_1; + if (drop_grenades) { + if (drop_gren1 == -1) + newmis.no_grenades_1 = self.no_grenades_1; + else if (drop_gren1 > 0) { + if (self.no_grenades_1 <= drop_gren1) + newmis.no_grenades_1 = self.no_grenades_1; + else + newmis.no_grenades_1 = drop_gren1; + } + if (drop_gren2 == -1) + newmis.no_grenades_2 = self.no_grenades_2; + else if (drop_gren2 > 0) { + if (self.no_grenades_2 <= drop_gren2) + newmis.no_grenades_2 = self.no_grenades_2; + else + newmis.no_grenades_2 = drop_gren2; + } + } newmis.armorvalue = self.armorvalue; diff --git a/qw.qc b/qw.qc index 18c3f142..270171db 100644 --- a/qw.qc +++ b/qw.qc @@ -396,6 +396,8 @@ float invis_only; float flagem_checked; float cease_fire; float drop_grenades; +float drop_gren1; +float drop_gren2; .float teamkills; From ba42c05dd7328557a96808214369601e27fa5340 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 22:42:26 +0200 Subject: [PATCH 0156/2474] Fix spy feign death message (fixes #139) --- combat.qc | 3 +++ qw.qc | 3 ++- spy.qc | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/combat.qc b/combat.qc index 2f09c8d3..2d728ed7 100644 --- a/combat.qc +++ b/combat.qc @@ -444,6 +444,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (no_damage == TRUE) return; + if (targ.playerclass == PC_SPY) + targ.feignmsg = deathmsg; + if (targ.armorvalue < 1) { targ.armorclass = 0; targ.armorvalue = 0; diff --git a/qw.qc b/qw.qc index 270171db..cea6889a 100644 --- a/qw.qc +++ b/qw.qc @@ -342,7 +342,8 @@ float num_world_flames; .float undercover_team; .float undercover_skin; .string undercover_name; -.entity attacked_by; // Used by spy feign death to produce a fake death message +.entity attacked_by; // Used by spy feign death to produce a fake death message +.float feignmsg; // Stores the death message to be used when feigning float live_camera; .float camdist; diff --git a/spy.qc b/spy.qc index db121841..53429309 100644 --- a/spy.qc +++ b/spy.qc @@ -448,7 +448,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { if (issilent == 0) { DeathSound(); Spy_DropBackpack(); - deathstring = GetDeathMessage(self, self.attacked_by, deathmsg); + deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); bprint(PRINT_MEDIUM, deathstring); if (!(self.flags & FL_ONGROUND)) { stuffcmd(self, "cl_backspeed 0\n"); From 7dcb14c38aebb0047fe2a9dca71fb2d342c757bb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 22:43:08 +0200 Subject: [PATCH 0157/2474] Load weapon states before and after feign (fixes #140) --- spy.qc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/spy.qc b/spy.qc index 53429309..b7a13833 100644 --- a/spy.qc +++ b/spy.qc @@ -390,14 +390,10 @@ void (float issilent) TeamFortress_SpyFeignDeath = { self.view_ofs = '0 0 22'; self.movetype = 3; self.is_feigning = 0; - self.current_weapon = self.weapon; + W_WeaponState_Load(self, 0); W_SetCurrentAmmo(self); self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); - if (self.weapon <= 16) { - spy_upaxe1(); - return; - } if (i == 1) { spy_upb1(); } else if (i == 2) { @@ -438,8 +434,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { Attack_Finished(0.8); self.invisible_finished = 0; self.modelindex = modelindex_player; - self.weapon = self.current_weapon; - self.current_weapon = 0; + W_WeaponState_Save(self); self.weaponmodel = ""; self.weaponframe = 0; setsize(self, '-16 -16 -24', '16 16 -16'); From ae0708442d1e7a2dd132490d22e71c71667cca42 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 20 Aug 2014 22:43:28 +0200 Subject: [PATCH 0158/2474] Stop Spy from firing gun while feigned (fixes #138) --- weapons.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/weapons.qc b/weapons.qc index a4ec1b82..b0573f46 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2443,6 +2443,9 @@ void () W_WeaponFrame = { return; } + if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL) + return; + if (self.impulse == TF_WEAPLAST) { // change to last weapon now From a2383b2f77cb9b2129254ee819e7bb031c632eb4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 22 Aug 2014 23:23:48 +0200 Subject: [PATCH 0159/2474] Fix toggling of class menu (fixes #144) --- menu.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index ef891a00..e45dc417 100644 --- a/menu.qc +++ b/menu.qc @@ -199,7 +199,10 @@ void () Menu_Team = { }; void (float inp) Menu_Class_Input = { - if (!inp || inp > 10 || !IsLegalClass(inp)) + if (!inp) + return; + + if (inp > 10 || !IsLegalClass(inp)) Menu_Class(); TeamFortress_ChangeClass(inp); From 8b34f99567fdada197c64abccd1f0b0dfaa549e2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 23 Aug 2014 00:15:34 +0200 Subject: [PATCH 0160/2474] Track feign messages more reliably (fixes #143) --- combat.qc | 3 +++ weapons.qc | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/combat.qc b/combat.qc index 2d728ed7..8bbb57ad 100644 --- a/combat.qc +++ b/combat.qc @@ -409,6 +409,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (no_damage == 0) targ.health = (targ.health - take); + if (targ.playerclass == PC_SPY) + targ.attacked_by = attacker; + if ((attacker.classname == "player") && ((targ.classname == "player") || (targ.classname == "building_sentrygun") diff --git a/weapons.qc b/weapons.qc index b0573f46..0bbeec04 100644 --- a/weapons.qc +++ b/weapons.qc @@ -682,9 +682,6 @@ void (float damage, vector dir) TraceAttack = { blood_org = org; AddMultiDamage(trace_ent, damage); - if (trace_ent.playerclass == PC_SPY) - trace_ent.attacked_by = self; - } else puff_count = puff_count + 1; }; From 2f4611d43f31d39fa5483bad494fb1a5cb31dfc7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 23 Aug 2014 00:26:10 +0200 Subject: [PATCH 0161/2474] Remove buggy 'move through target' function of the Railgun --- engineer.qc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/engineer.qc b/engineer.qc index 2ca77bd9..59139f8d 100644 --- a/engineer.qc +++ b/engineer.qc @@ -29,8 +29,7 @@ void () LaserBolt_Think = { }; //========================================================================= -// Laserbolt touch function. Just moves through the player and comes out -// the other side. +// Laserbolt touch function. void () LaserBolt_Touch = { local vector org; @@ -49,13 +48,6 @@ void () LaserBolt_Touch = { SpawnBlood(org, 15); deathmsg = DMSG_LASERBOLT; TF_T_Damage(other, self, self.enemy, 25, 2, TF_TD_ELECTRICITY); - self.velocity = self.oldorigin; - self.owner = other; - setmodel(self, string_null); - self.touch = SUB_Null; - self.nextthink = time + 0.1; - self.think = LaserBolt_Think; - return; } else { WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_SPIKE); From e7e670e8aa26c1ddec457761795cc8bfd8f97d4e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 24 Aug 2014 22:18:44 +0200 Subject: [PATCH 0162/2474] Include self harm messages in feign death messages (closes #146) --- combat.qc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/combat.qc b/combat.qc index 8bbb57ad..1f81a1ac 100644 --- a/combat.qc +++ b/combat.qc @@ -397,6 +397,12 @@ void (entity targ, entity inflictor, entity attacker, float damage, } + + if (targ.playerclass == PC_SPY) { + targ.attacked_by = attacker; + targ.feignmsg = deathmsg; + } + if (T_flags & TF_TD_NOTSELF) if (targ == attacker) return; @@ -409,9 +415,6 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (no_damage == 0) targ.health = (targ.health - take); - if (targ.playerclass == PC_SPY) - targ.attacked_by = attacker; - if ((attacker.classname == "player") && ((targ.classname == "player") || (targ.classname == "building_sentrygun") @@ -447,9 +450,6 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (no_damage == TRUE) return; - if (targ.playerclass == PC_SPY) - targ.feignmsg = deathmsg; - if (targ.armorvalue < 1) { targ.armorclass = 0; targ.armorvalue = 0; From d9fe089d9a311247c817b2aa35365c095ea1f593 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 24 Aug 2014 22:29:42 +0200 Subject: [PATCH 0163/2474] Improve efficiency of PlayerPreThink() --- client.qc | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/client.qc b/client.qc index 9f907dbb..0697128b 100644 --- a/client.qc +++ b/client.qc @@ -1447,28 +1447,22 @@ void () PlayerPreThink = { RemoveGrenades(); } - if (self.impulse == TF_VOTENEXT) { - Vote_NextMap(self); - self.impulse = 0; - } else if (self.impulse == TF_VOTETRICK) { - Vote_TrickMap(self); - self.impulse = 0; - } else if (self.impulse == TF_VOTERACE) { - Vote_RaceMap(self); - self.impulse = 0; - } else if (self.impulse == TF_FORCENEXT) { - Vote_ForceNext(self); - self.impulse = 0; + if (self.impulse) { + if (self.impulse == TF_VOTENEXT) { + Vote_NextMap(self); + self.impulse = 0; + } else if (self.impulse == TF_VOTETRICK) { + Vote_TrickMap(self); + self.impulse = 0; + } else if (self.impulse == TF_VOTERACE) { + Vote_RaceMap(self); + self.impulse = 0; + } else if (self.impulse == TF_FORCENEXT) { + Vote_ForceNext(self); + self.impulse = 0; + } } - if (self.is_feigning && (self.flags & FL_ONGROUND) && !(self.tfstate & TFSTATE_CANT_MOVE)) { - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - } - if (self.is_feigning && (self.waterlevel == 1)) { - self.watertype = -3; - self.waterlevel = 3; - } if (self.cheat_level > 0) { self.cheat_level = self.cheat_level - 1; } @@ -1499,14 +1493,24 @@ void () PlayerPreThink = { if (self.deadflag == 1) { return; } - if (!self.is_feigning) { + if (self.is_feigning) { + if ((self.flags & FL_ONGROUND) && !(self.tfstate & TFSTATE_CANT_MOVE)) { + self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + } + if (self.waterlevel) { + if (self.waterlevel == 1) { + self.watertype = -3; + self.waterlevel = 3; + } + self.velocity_z = -100; + } + } else { if (self.button2) { PlayerJump(); } else { - self.flags = self.flags | 4096; + self.flags = self.flags | FL_JUMPRELEASED; } - } else if (self.waterlevel) { - self.velocity_z = -100; } if ((time < self.pausetime) || (cease_fire == 1)) { self.velocity = '0 0 0'; From ebc8ce7aeb79177cd8d7d2c23ca8e0321b18b95f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 25 Aug 2014 00:12:04 +0200 Subject: [PATCH 0164/2474] Clean up Spy feign code --- spy.qc | 188 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 111 insertions(+), 77 deletions(-) diff --git a/spy.qc b/spy.qc index b7a13833..0a844cfc 100644 --- a/spy.qc +++ b/spy.qc @@ -353,47 +353,65 @@ void () spy_upaxe9 =[41, spy_upaxe9] { player_stand1(); }; +float (entity pe_player) Spy_CheckArea = { + local entity at_spot = findradius(self.origin, 64); + while (at_spot != world) { + if (at_spot.mdl == "progs/detpack.mdl" + || at_spot.mdl == "progs/turrbase.mdl" + || at_spot.mdl == "progs/turrgun.mdl" + || at_spot.mdl == "progs/disp.mdl") + return 1; + else if (at_spot.classname == "player") { + if (at_spot.deadflag == 0 && self != at_spot) + return 2; + if (self != at_spot && at_spot.is_feigning == 1) + return 3; + } + at_spot = at_spot.chain; + } + return 0; +}; + void (float issilent) TeamFortress_SpyFeignDeath = { local string deathstring; + local float area_check; local float i; - local float j; - local entity at_spot; local entity te; if (self.is_feigning) { - at_spot = findradius(self.origin, 64); - i = 1; - j = 0; - while (at_spot != world) { - if (at_spot.mdl == "progs/detpack.mdl") { - j = 1; - } else if (at_spot.mdl == "progs/turrbase.mdl") { - j = 1; - } else if (at_spot.mdl == "progs/turrgun.mdl") { - j = 1; - } else if (at_spot.mdl == "progs/disp.mdl") { - j = 1; - } else - if (((at_spot.classname == "player") && - (at_spot.deadflag == 0)) && (self != at_spot)) { - j = 2; - } - if (j > 0) { - i = 0; - } - at_spot = at_spot.chain; - } - if (i == 1) { - i = 1 + floor(random() * 5); + + // check area for obstructing entities + area_check = Spy_CheckArea(self); + + // nothing on top => unfeign + if (!area_check) { + + // set player velocity to 0 self.velocity = '0 0 0'; + + // set size of player model setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); + + // set view height self.view_ofs = '0 0 22'; - self.movetype = 3; - self.is_feigning = 0; + + // set movetype to walk + self.movetype = MOVETYPE_WALK; + + // load saved weapon state and set current ammo W_WeaponState_Load(self, 0); W_SetCurrentAmmo(self); + + // allow spy to move again self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); + + // unset feign variables + self.is_feigning = 0; + self.feign_areachecked = 0; + + // set revive animation + i = 1 + floor(random() * 5); if (i == 1) { spy_upb1(); } else if (i == 2) { @@ -403,97 +421,113 @@ void (float issilent) TeamFortress_SpyFeignDeath = { } else { spy_upe1(); } - } else if (j == 1) { - sprint(self, PRINT_HIGH, - "You cannot get up with something on top of you\n"); + + // something is on top of spy + } else if (area_check == 1) { + sprint(self, PRINT_HIGH, "You cannot get up with something on top of you\n"); } else { - sprint(self, PRINT_HIGH, - "You cannot get up while someone is standing on you\n"); + sprint(self, PRINT_HIGH, "You cannot get up while someone is standing on you\n"); } } else { - if (self.is_unabletospy == 1 || (time - self.antispam_feign) < 3) { + + // don't feign if not allowed or spam timer is active + if (self.is_unabletospy == 1 || time < self.antispam_feign) { sprint(self, PRINT_HIGH, "You cannot feign right now\n"); return; } - at_spot = findradius(self.origin, 64); - while (at_spot != world) { - if (((at_spot.classname == "player") && (self != at_spot)) && - (at_spot.is_feigning == 1)) { - sprint(self, PRINT_HIGH, - "You cannot feign on top of another spy\n"); - return; - } - at_spot = at_spot.chain; + + // check area for feigned spy on thr ground + area_check = Spy_CheckArea(self); + if (area_check == 3) { + sprint(self, PRINT_HIGH, "You cannot feign on top of another spy\n"); + return; } - self.antispam_feign = time; + + // stop spy from attempting feign for 3 seconds + self.antispam_feign = time + 3; + + // don't check for team color cheat for 5 seconds self.immune_to_check = time + 5; + + // stop spy from moving if on the ground if (self.flags & FL_ONGROUND) self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); + + // set spy feign variables self.is_feigning = 1; + Attack_Finished(0.8); self.invisible_finished = 0; + + // set precached model index self.modelindex = modelindex_player; + + // set size of player model + setsize(self, '-16 -16 -24', '16 16 -16'); + + // set weapon state and remove weapon viewmodel W_WeaponState_Save(self); self.weaponmodel = ""; self.weaponframe = 0; - setsize(self, '-16 -16 -24', '16 16 -16'); + + // set view height to ground self.view_ofs = '0 0 4'; - self.movetype = 6; + + // set movetype to toss + self.movetype = MOVETYPE_TOSS; + + // do extra stuff if feign is not silent feign if (issilent == 0) { + // make a death sound DeathSound(); + + // drop an empty backpack Spy_DropBackpack(); + + // print feign message deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); bprint(PRINT_MEDIUM, deathstring); - if (!(self.flags & FL_ONGROUND)) { - stuffcmd(self, "cl_backspeed 0\n"); - stuffcmd(self, "cl_forwardspeed 0\n"); - stuffcmd(self, "cl_sidespeed 0\n"); + + // set movement speed to 0 if currently in the air to disable manipulation of trajectory + if (!(self.flags & FL_ONGROUND)) self.maxspeed = 0; - } } - self.angles_x = 0; - self.angles_z = 0; - if (self.weapon <= 16) { + + // die with axe equipped if carrying axe, medikit or spanner + if (self.weapon <= WEAP_AXE) { spy_die_ax1(); return; } + + // drop flag if spy is carrying it te = find(world, classname, "item_tfgoal"); while (te) { if (te.owner == self) { - if (!(te.goal_activation & 256) || - (self.has_disconnected == 1)) { + if (!(te.goal_activation & TFGI_KEEP) || self.has_disconnected == 1) tfgoalitem_RemoveFromPlayer(te, self, 0); - } if (CTF_Map == 1) { if (te.goal_no == 1) - bprint(PRINT_HIGH, self.netname, - " ΜΟΣΤ the ΒΜΥΕ flag!\n"); + bprint(PRINT_HIGH, self.netname, " ΜΟΣΤ the ΒΜΥΕ flag!\n"); else if (te.goal_no == 2) - bprint(PRINT_HIGH, self.netname, - " ΜΟΣΤ the ΕΔ flag!\n"); + bprint(PRINT_HIGH, self.netname, " ΜΟΣΤ the ΕΔ flag!\n"); } } te = find(te, classname, "item_tfgoal"); } + + // randomize death animation i = 1 + floor((random() * 6)); - if (i == 1) { + if (i == 1) spy_diea1(); - } else { - if (i == 2) { - spy_dieb1(); - } else { - if (i == 3) { - spy_diec1(); - } else { - if (i == 4) { - spy_died1(); - } else { - spy_diee1(); - } - } - } - } + else if (i == 2) + spy_dieb1(); + else if (i == 3) + spy_diec1(); + else if (i == 4) + spy_died1(); + else + spy_diee1(); } }; From 2a79e1515e8d8f3ee83c619ef8b52961b0d095b7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 25 Aug 2014 00:12:45 +0200 Subject: [PATCH 0165/2474] Move spy if landing feigned on entities (fixes #142) --- client.qc | 21 ++++++++++++++++++--- qw.qc | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index 0697128b..20a7f201 100644 --- a/client.qc +++ b/client.qc @@ -8,6 +8,8 @@ float modelindex_eyes; float modelindex_player; float modelindex_null; +float (entity pe_player) Spy_CheckArea; + void () TeamFortress_CheckTeamCheats; void (entity Viewer, float pc, float rpc) TeamFortress_PrintClassName; void () TeamFortress_RemoveTimers; @@ -1494,9 +1496,22 @@ void () PlayerPreThink = { return; } if (self.is_feigning) { - if ((self.flags & FL_ONGROUND) && !(self.tfstate & TFSTATE_CANT_MOVE)) { - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); + if (self.flags & FL_ONGROUND) { + // check area for entities - if found, bounce player forward + if (!self.feign_areachecked) { + local float check_area = Spy_CheckArea(self); + if (check_area == 1 || check_area == 3) { + self.velocity = aim(self, 10000); + self.velocity = self.velocity * 200; + self.velocity_z = 200; + } else { + self.feign_areachecked = 1; + if (!(self.tfstate & TFSTATE_CANT_MOVE)) { + self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + } + } + } } if (self.waterlevel) { if (self.waterlevel == 1) { diff --git a/qw.qc b/qw.qc index cea6889a..7b96b4bf 100644 --- a/qw.qc +++ b/qw.qc @@ -50,6 +50,7 @@ typedef void (float) f_void_float; .float pipecooldown; // Time when detpipe command can be issued .float disguise_skin; // The skin the spy is changing to .float disguise_team; // The team the spy is changing to +.float feign_areachecked; // TRUE if area around spy has been checked for entities when feigned .float fragstreak; // Frag streak .float caps; // Caps during this game From 9b2d3d8587757a484c05b1ca26a3646172579e26 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 25 Aug 2014 23:48:35 +0200 Subject: [PATCH 0166/2474] Add knockback to Flamethrower (closes #148) --- pyro.qc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyro.qc b/pyro.qc index 6cee8979..97f7f1fc 100644 --- a/pyro.qc +++ b/pyro.qc @@ -415,7 +415,7 @@ void () WorldFlame_touch = { void () Flamer_stream_touch = { local entity flame; - local vector vtemp; + local vector vtemp, dir; if (other.classname == "fire") { return; @@ -423,6 +423,12 @@ void () Flamer_stream_touch = { if (other != world) { if ((other.takedamage == 2) && (other.health > 0)) { deathmsg = DMSG_FLAME; + + // knockback target + dir = other.origin - (self.absmin + self.absmax) * 0.5; + dir = normalize(dir); + other.velocity = other.velocity + dir * 300; + TF_T_Damage(other, self, self.owner, 10, TF_TD_NOTTEAM, TF_TD_FIRE); if (cb_prematch_time > time) { From e741ab5c89944cddd84fba86e490400f88b9fb32 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 26 Aug 2014 00:15:40 +0200 Subject: [PATCH 0167/2474] Feigned Spy sandwitch no longer gets drawn to roof (fixes #142) --- spy.qc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/spy.qc b/spy.qc index 0a844cfc..88bfaf51 100644 --- a/spy.qc +++ b/spy.qc @@ -361,10 +361,10 @@ float (entity pe_player) Spy_CheckArea = { || at_spot.mdl == "progs/turrgun.mdl" || at_spot.mdl == "progs/disp.mdl") return 1; - else if (at_spot.classname == "player") { - if (at_spot.deadflag == 0 && self != at_spot) + else if (at_spot.classname == "player" && self != at_spot) { + if (!at_spot.is_feigning && at_spot.deadflag == 0) return 2; - if (self != at_spot && at_spot.is_feigning == 1) + else if (at_spot.is_feigning) return 3; } at_spot = at_spot.chain; @@ -425,7 +425,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { // something is on top of spy } else if (area_check == 1) { sprint(self, PRINT_HIGH, "You cannot get up with something on top of you\n"); - } else { + } else if (area_check == 2) { sprint(self, PRINT_HIGH, "You cannot get up while someone is standing on you\n"); } } else { @@ -436,7 +436,7 @@ void (float issilent) TeamFortress_SpyFeignDeath = { return; } - // check area for feigned spy on thr ground + // check area for feigned spy on the ground area_check = Spy_CheckArea(self); if (area_check == 3) { sprint(self, PRINT_HIGH, "You cannot feign on top of another spy\n"); @@ -450,9 +450,10 @@ void (float issilent) TeamFortress_SpyFeignDeath = { self.immune_to_check = time + 5; // stop spy from moving if on the ground - if (self.flags & FL_ONGROUND) + if (self.flags & FL_ONGROUND) { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); + TeamFortress_SetSpeed(self); + } // set spy feign variables self.is_feigning = 1; From bc9330f0abc6035426ba7e27d50b1048bff04dec Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 26 Aug 2014 00:39:37 +0200 Subject: [PATCH 0168/2474] Reset weaponstate on spawn if randompc (fixes #147) --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 262540ed..e6d80696 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1350,7 +1350,7 @@ void () TeamFortress_SetEquipment = { self.items = 0; self.weapons_carried = 0; - if (self.last_playerclass != self.playerclass) { + if (self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; self.last_weapon = 0; self.weaponmode = 0; From 40dd1980a1d1e2720cee8589b457ebe0c7049e19 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 26 Aug 2014 18:01:39 +0200 Subject: [PATCH 0169/2474] Do not set velocity to 0 when unfeigning (fixes #149) --- spy.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/spy.qc b/spy.qc index 88bfaf51..f8cd17ff 100644 --- a/spy.qc +++ b/spy.qc @@ -386,9 +386,6 @@ void (float issilent) TeamFortress_SpyFeignDeath = { // nothing on top => unfeign if (!area_check) { - // set player velocity to 0 - self.velocity = '0 0 0'; - // set size of player model setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); From 856610a77249bd2808886945b968a1a279650cc3 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 00:10:13 +0200 Subject: [PATCH 0170/2474] Rewrite code to populate voting lists (fixes #130) --- vote.qc | 325 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 181 insertions(+), 144 deletions(-) diff --git a/vote.qc b/vote.qc index 3397228a..4fb3d978 100644 --- a/vote.qc +++ b/vote.qc @@ -20,10 +20,7 @@ void (float force) Vote_MenuOpen; void () Vote_MenuClose; void (entity pe_player) Vote_Menu; void (float pf_input) Vote_RemoveVote; -string () Vote_GetMapList; -string () Vote_GetTrickList; -string () Vote_GetRaceList; -void (string ps_maplist) Vote_PopulateVoteList; +void (float pf_type) Vote_PopulateVoteList; string (string ps_map, string ps_maplist) Vote_StripMap; void () Vote_Reset; void () Vote_ResetVotes; @@ -34,7 +31,6 @@ float () Vote_GetWinnerVoteCount; string () Vote_GetWinner; string () Vote_GetWinnerList; string (string ps_maplist) Vote_RandomWinner; -string () Vote_RandomMap; float (float pf_from, float pf_to) RandomRange; void () Vote_DropLosers; float (string ps_list) List_Count; @@ -316,28 +312,17 @@ void () Vote_Check = { // pf_type: 0 = normal vote, 1 = decider vote, 2 = trick vote, 3 = race vote // called from Vote_Check() void (float pf_type) Vote_SetupVote = { - local string s_maplist; vote_decider = 0; - if (pf_type == 0) { - s_maplist = Vote_GetMapList(); // returns a strzoned string - } else if (pf_type == 1) { + // set vote*_map variables to randomly selected maps from appropriate map list + Vote_PopulateVoteList(pf_type); + + if (pf_type == 1) { vote_decider = 1; - s_maplist = Vote_GetWinnerList(); // returns a strzoned string - Vote_ResetVotes(); - } else if (pf_type == 2) { - s_maplist = Vote_GetTrickList(); // returns a strzoned string - Vote_ResetVotes(); - } else { - s_maplist = Vote_GetRaceList(); // returns a strzoned string - Vote_ResetVotes(); } + Vote_ResetVotes(); vote_started = time; - // set vote*_map variables to randomly selected maps from s_maplist - Vote_PopulateVoteList(s_maplist); - strunzone(s_maplist); - if (vote1_map == string_null) { //dprint("[", ftos(time), "/cf/mapvote/setupvote]: no maps found. aborting.\n"); vote_result = mapname; @@ -585,110 +570,179 @@ void (float pf_input) Vote_RemoveVote = { //dprint("[", ftos(time), "/cf/mapvote/removevote]: removing vote from ", s_map, ".\n"); }; -// returns a list of maps from config -// called from Vote_SetupVote() -string () Vote_GetMapList = { - local float f_players = TeamFortress_GetNoPlayers(); - local string s_maplist, s_maplist1, s_maplist2, s_maplist3, s_maplist4; - - if (f_players <= 2) { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using tiny votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_tiny1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_tiny2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_tiny3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_tiny4"), " "); - } else if (f_players <= 4) { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using small votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_small1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_small2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_small3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_small4"), " "); - } else if (f_players <= 6) { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using medium votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_medium1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_medium2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_medium3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_medium4"), " "); - } else if (f_players <= 8) { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using large votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_large1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_large2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_large3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_large4"), " "); - } else if (f_players <= 12) { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xlarge votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_xlarge1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_xlarge2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_xlarge3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_xlarge4"), " "); - } else if (f_players <= 14) { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xxl votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_xxl1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_xxl2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_xxl3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_xxl4"), " "); - } else if (f_players <= 16) { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xxxl votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_xxxl1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_xxxl2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_xxxl3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_xxxl4"), " "); - } else { - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: using xxxxl votelist.\n"); - s_maplist1 = strcat(infokey(world, "votelist_xxxxl1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_xxxxl2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_xxxxl3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_xxxxl4"), " "); - } - - s_maplist = strzone(strcat(s_maplist1, strcat(s_maplist2, strcat(s_maplist3, s_maplist4)))); - - //dprint("[", ftos(time), "/cf/mapvote/getmaplist]: votelist: ", s_maplist, "\n"); - return s_maplist; -}; - -// returns a list of trick maps from config -// called from Vote_SetupVote() -string () Vote_GetTrickList = { - local string s_maplist, s_maplist1, s_maplist2, s_maplist3, s_maplist4; - - s_maplist1 = strcat(infokey(world, "votelist_trick1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_trick2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_trick3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_trick4"), " "); - s_maplist = strzone(strcat(s_maplist1, strcat(s_maplist2, strcat(s_maplist3, s_maplist4)))); - - //dprint("[", ftos(time), "/cf/mapvote/gettricklist]: trick votelist: ", s_maplist, "\n"); - return s_maplist; -}; - -// returns a list of race maps from config +// populates vote*_map variables // called from Vote_SetupVote() -string () Vote_GetRaceList = { - local string s_maplist, s_maplist1, s_maplist2, s_maplist3, s_maplist4; - - s_maplist1 = strcat(infokey(world, "votelist_race1"), " "); - s_maplist2 = strcat(infokey(world, "votelist_race2"), " "); - s_maplist3 = strcat(infokey(world, "votelist_race3"), " "); - s_maplist4 = strcat(infokey(world, "votelist_race4"), " "); - s_maplist = strzone(strcat(s_maplist1, strcat(s_maplist2, strcat(s_maplist3, s_maplist4)))); +void (float pf_type) Vote_PopulateVoteList = { + local float f_count, f_count1, f_count2, f_count3, f_count4, f_count5, f_count6, f_count7, f_count8, f_next, rand, i; + local float f_range1, f_range2, f_range3, f_range4, f_range5, f_range6, f_range7, f_range8; + local string s_maplist1 = "", s_maplist2 = "", s_maplist3 = "", s_maplist4 = "", s_maplist5 = "", s_maplist6 = "", s_maplist7 = "", s_maplist8 = "", s_map; + local string s_tmp, s_tmp1, s_tmp2, s_tmp3, s_tmp4, s_tmp5, s_tmp6, s_tmp7, s_tmp8; - //dprint("[", ftos(time), "/cf/mapvote/getracelist]: trick votelist: ", s_maplist, "\n"); - return s_maplist; -}; + // initialize trick map variables + s_tmp5 = strzone(""); + s_tmp6 = strzone(""); + s_tmp7 = strzone(""); + s_tmp8 = strzone(""); + + // regular map vote + if (pf_type <= 1) { + + local float f_players = TeamFortress_GetNoPlayers(); + + if (f_players <= 2) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using tiny votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_tiny1")); + s_tmp2 = strzone(infokey(world, "votelist_tiny2")); + s_tmp3 = strzone(infokey(world, "votelist_tiny3")); + s_tmp4 = strzone(infokey(world, "votelist_tiny4")); + } else if (f_players <= 4) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using small votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_small1")); + s_tmp2 = strzone(infokey(world, "votelist_small2")); + s_tmp3 = strzone(infokey(world, "votelist_small3")); + s_tmp4 = strzone(infokey(world, "votelist_small4")); + } else if (f_players <= 6) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using medium votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_medium1")); + s_tmp2 = strzone(infokey(world, "votelist_medium2")); + s_tmp3 = strzone(infokey(world, "votelist_medium3")); + s_tmp4 = strzone(infokey(world, "votelist_medium4")); + } else if (f_players <= 8) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using large votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_large1")); + s_tmp2 = strzone(infokey(world, "votelist_large2")); + s_tmp3 = strzone(infokey(world, "votelist_large3")); + s_tmp4 = strzone(infokey(world, "votelist_large4")); + } else if (f_players <= 12) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using xlarge votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_xlarge1")); + s_tmp2 = strzone(infokey(world, "votelist_xlarge2")); + s_tmp3 = strzone(infokey(world, "votelist_xlarge3")); + s_tmp4 = strzone(infokey(world, "votelist_xlarge4")); + } else if (f_players <= 14) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using xxl votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_xxl1")); + s_tmp2 = strzone(infokey(world, "votelist_xxl2")); + s_tmp3 = strzone(infokey(world, "votelist_xxl3")); + s_tmp4 = strzone(infokey(world, "votelist_xxl4")); + } else if (f_players <= 16) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using xxxl votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_xxxl1")); + s_tmp2 = strzone(infokey(world, "votelist_xxxl2")); + s_tmp3 = strzone(infokey(world, "votelist_xxxl3")); + s_tmp4 = strzone(infokey(world, "votelist_xxxl4")); + } else { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using xxxxl votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_xxxxl1")); + s_tmp2 = strzone(infokey(world, "votelist_xxxxl2")); + s_tmp3 = strzone(infokey(world, "votelist_xxxxl3")); + s_tmp4 = strzone(infokey(world, "votelist_xxxxl4")); + } -// populates vote*_map variables -// called from Vote_SetupVote() -void (string ps_maplist) Vote_PopulateVoteList = { - local float f_count, i; - local string s_maplist; + // trick vote + } else if (pf_type == 2) { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using trick votelist.\n"); + strunzone(s_tmp5); strunzone(s_tmp6); strunzone(s_tmp7); strunzone(s_tmp8); + s_tmp1 = strzone(infokey(world, "votelist_trick1")); + s_tmp2 = strzone(infokey(world, "votelist_trick2")); + s_tmp3 = strzone(infokey(world, "votelist_trick3")); + s_tmp4 = strzone(infokey(world, "votelist_trick4")); + s_tmp5 = strzone(infokey(world, "votelist_trick5")); + s_tmp6 = strzone(infokey(world, "votelist_trick6")); + s_tmp7 = strzone(infokey(world, "votelist_trick7")); + s_tmp8 = strzone(infokey(world, "votelist_trick8")); + + // race vote + } else { + //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: using race votelist.\n"); + s_tmp1 = strzone(infokey(world, "votelist_race1")); + s_tmp2 = strzone(infokey(world, "votelist_race2")); + s_tmp3 = strzone(infokey(world, "votelist_race3")); + s_tmp4 = strzone(infokey(world, "votelist_race4")); + } + vote_started = time; - s_maplist = Vote_StripMap(mapname, ps_maplist); // strip current map from votelist, returns a strzoned string - f_count = List_Count(s_maplist); + // filter out current map from map lists + s_maplist1 = Vote_StripMap(mapname, s_tmp1); + s_maplist2 = Vote_StripMap(mapname, s_tmp2); + s_maplist3 = Vote_StripMap(mapname, s_tmp3); + s_maplist4 = Vote_StripMap(mapname, s_tmp4); + s_maplist5 = Vote_StripMap(mapname, s_tmp5); + s_maplist6 = Vote_StripMap(mapname, s_tmp6); + s_maplist7 = Vote_StripMap(mapname, s_tmp7); + s_maplist8 = Vote_StripMap(mapname, s_tmp8); + + // calculate odds for each maplist + f_count1 = List_Count(s_maplist1); + f_count2 = List_Count(s_maplist2); + f_count3 = List_Count(s_maplist3); + f_count4 = List_Count(s_maplist4); + f_count5 = List_Count(s_maplist5); + f_count6 = List_Count(s_maplist6); + f_count7 = List_Count(s_maplist7); + f_count8 = List_Count(s_maplist8); + f_count = f_count1 + f_count2 + f_count3 + f_count4 + f_count5 + f_count6 + f_count7 + f_count8; + f_range1 = f_count1 / f_count * 100; + f_range2 = f_range1 + (f_count2 / f_count * 100); + f_range3 = f_range2 + (f_count3 / f_count * 100); + f_range4 = f_range3 + (f_count4 / f_count * 100); + f_range5 = f_range4 + (f_count5 / f_count * 100); + f_range6 = f_range5 + (f_count6 / f_count * 100); + f_range7 = f_range6 + (f_count7 / f_count * 100); + f_range8 = f_range7 + (f_count8 / f_count * 100); for (i = 0; i < 4; i++) { - local float f_next = RandomRange(0, f_count - 1); - local string s_map = List_Index(s_maplist, f_next); // returns a strzoned string + + rand = random() * 100; + if (rand <= f_range1) { + f_count1 = f_count1 - 1; + f_next = RandomRange(0, f_count1); + s_map = List_Index(s_maplist1, f_next); // returns a strzoned string + s_tmp = s_maplist1; + s_maplist1 = Vote_StripMap(s_map, s_maplist1); + } else if (rand <= f_range2) { + f_count2 = f_count2 - 1; + f_next = RandomRange(0, f_count2); + s_map = List_Index(s_maplist2, f_next); // returns a strzoned string + s_tmp = s_maplist2; + s_maplist2 = Vote_StripMap(s_map, s_maplist2); + } else if (rand <= f_range3) { + f_count3 = f_count3 - 1; + f_next = RandomRange(0, f_count3); + s_map = List_Index(s_maplist3, f_next); // returns a strzoned string + s_tmp = s_maplist3; + s_maplist3 = Vote_StripMap(s_map, s_maplist3); + } else if (rand <= f_range4) { + f_count4 = f_count4 - 1; + f_next = RandomRange(0, f_count4); + s_map = List_Index(s_maplist4, f_next); // returns a strzoned string + s_tmp = s_maplist4; + s_maplist4 = Vote_StripMap(s_map, s_maplist4); + } else if (rand <= f_range5) { + f_count5 = f_count5 - 1; + f_next = RandomRange(0, f_count5); + s_map = List_Index(s_maplist5, f_next); // returns a strzoned string + s_tmp = s_maplist5; + s_maplist5 = Vote_StripMap(s_map, s_maplist5); + } else if (rand <= f_range6) { + f_count6 = f_count6 - 1; + f_next = RandomRange(0, f_count6); + s_map = List_Index(s_maplist6, f_next); // returns a strzoned string + s_tmp = s_maplist6; + s_maplist6 = Vote_StripMap(s_map, s_maplist6); + } else if (rand <= f_range7) { + f_count7 = f_count7 - 1; + f_next = RandomRange(0, f_count7); + s_map = List_Index(s_maplist7, f_next); // returns a strzoned string + s_tmp = s_maplist7; + s_maplist7 = Vote_StripMap(s_map, s_maplist7); + } else { + f_count8 = f_count8 - 1; + f_next = RandomRange(0, f_count8); + s_map = List_Index(s_maplist8, f_next); // returns a strzoned string + s_tmp = s_maplist8; + s_maplist8 = Vote_StripMap(s_map, s_maplist8); + } if (i == 0) { vote1_map = s_map; @@ -704,29 +758,28 @@ void (string ps_maplist) Vote_PopulateVoteList = { //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map4: ", vote4_map, "\n"); } - local string s_tmp = s_maplist; - s_maplist = Vote_StripMap(s_map, s_maplist); // returns a strzoned string - f_count = List_Count(s_maplist); strunzone(s_tmp); } vote5_map = strzone(mapname); - strunzone(s_maplist); //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map5: ", vote5_map, "\n"); + strunzone(s_maplist1); strunzone(s_maplist2); strunzone(s_maplist3); strunzone(s_maplist4); + strunzone(s_maplist5); strunzone(s_maplist6); strunzone(s_maplist7); strunzone(s_maplist8); + strunzone(s_tmp1); strunzone(s_tmp2); strunzone(s_tmp3); strunzone(s_tmp4); + strunzone(s_tmp5); strunzone(s_tmp6); strunzone(s_tmp7); strunzone(s_tmp8); }; // strips a map from a given list of maps // called from Vote_PopulateVoteList() string (string ps_map, string ps_maplist) Vote_StripMap = { local float f_count, i; - local string s_maplist, s_tmp; + local string s_tmp; - s_maplist = ps_maplist; - f_count = List_Count(s_maplist); + f_count = List_Count(ps_maplist); // remove current map from list, strzone hack needed because limited string buffer s_tmp = strzone(""); for (i = 0; i < f_count; i++) { - local string map = List_Index(s_maplist, i); // returns a strzoned string + local string map = List_Index(ps_maplist, i); // returns a strzoned string if (map != ps_map) { local string tmp_old = s_tmp; s_tmp = strzone(strcat(s_tmp, strcat(map, " "))); @@ -823,7 +876,7 @@ string () Vote_GetWinner = { if (s_maplist != string_null) s_result = Vote_RandomWinner(s_maplist); // returns a strzoned string else - s_result = Vote_RandomMap(); // returns a strzoned string + s_result = mapname; // returns a strzoned string return s_result; }; @@ -878,22 +931,6 @@ string (string ps_maplist) Vote_RandomWinner = { return s_winner; }; -// returns a random map from a list of maps -// called from Vote_PopulateVoteList() -string () Vote_RandomMap = { - local float f_idx, f_count; - local string s_maplist, s_map; - - s_maplist = Vote_GetMapList(); // returns a strzoned string - f_count = List_Count(s_maplist) - 1; - f_idx = RandomRange(0, f_count); - s_map = List_Index(s_maplist, f_idx); // returns a strzoned string - strunzone(s_maplist); - - //dprint("[", ftos(time), "/cf/mapvote/randommap]: drew random map: ", s_map, "\n"); - return s_map; -}; - // returns a random number between from and to // called from Vote_GetWinner(), Vote_PopulateVoteList() float (float from, float to) RandomRange = { From 1dc4f234f8d270b1372548d3d057cf306c186711 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 00:24:06 +0200 Subject: [PATCH 0171/2474] Ignore repeated /voteX commands (fixes #150) --- vote.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vote.qc b/vote.qc index 4fb3d978..c6867f9a 100644 --- a/vote.qc +++ b/vote.qc @@ -46,7 +46,7 @@ float vote_started, vote_update, vote_winnercount, vote_decider, vote_abort; void (entity pe_player) Vote_NextMap = { local float f_votes, f_votes_needed, f_votes_left; - if (!pe_player.team_no || !pe_player.playerclass) + if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_next) return; if (vote_result != string_null) { @@ -77,7 +77,7 @@ void (entity pe_player) Vote_NextMap = { void (entity pe_player) Vote_TrickMap = { local float f_votes, f_votes_needed, f_votes_left; - if (!pe_player.team_no || !pe_player.playerclass) + if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_trick) return; if (vote_result != string_null) { @@ -108,7 +108,7 @@ void (entity pe_player) Vote_TrickMap = { void (entity pe_player) Vote_RaceMap = { local float f_votes, f_votes_needed, f_votes_left; - if (!pe_player.team_no || !pe_player.playerclass) + if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_race) return; if (vote_result != string_null) { From c69781dc1ec2a59449b713a9ca6f6ba1f6dcd084 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 00:24:22 +0200 Subject: [PATCH 0172/2474] Only allow one active /voteX (fixes #151) --- vote.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vote.qc b/vote.qc index c6867f9a..efd8c590 100644 --- a/vote.qc +++ b/vote.qc @@ -54,6 +54,8 @@ void (entity pe_player) Vote_NextMap = { return; } pe_player.vote_next = 1; + pe_player.vote_trick = 0; + pe_player.vote_race = 0; bprint(PRINT_HIGH, pe_player.netname, " wants to start voting for next map\n"); @@ -85,6 +87,8 @@ void (entity pe_player) Vote_TrickMap = { return; } pe_player.vote_trick = 1; + pe_player.vote_race = 0; + pe_player.vote_next = 0; bprint(PRINT_HIGH, pe_player.netname, " wants to vote for a trick map\n"); @@ -116,6 +120,8 @@ void (entity pe_player) Vote_RaceMap = { return; } pe_player.vote_race = 1; + pe_player.vote_trick = 0; + pe_player.vote_next = 0; bprint(PRINT_HIGH, pe_player.netname, " wants to vote for a race map\n"); From aa4f9510527b2de61af0243c528aada0c0c12645 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 00:26:35 +0200 Subject: [PATCH 0173/2474] Don't allow /voteX commands during active votes (fixes #152) --- vote.qc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/vote.qc b/vote.qc index efd8c590..d0de5bde 100644 --- a/vote.qc +++ b/vote.qc @@ -49,6 +49,11 @@ void (entity pe_player) Vote_NextMap = { if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_next) return; + if (vote_started > 0) { + sprint(pe_player, PRINT_HIGH, "There is already a vote in progress.\n"); + return; + } + if (vote_result != string_null) { sprint(pe_player, PRINT_HIGH, "Next map has already been voted to ", vote_result, ". Use /forcenext to force next map.\n"); return; @@ -82,6 +87,11 @@ void (entity pe_player) Vote_TrickMap = { if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_trick) return; + if (vote_started > 0) { + sprint(pe_player, PRINT_HIGH, "There is already a vote in progress.\n"); + return; + } + if (vote_result != string_null) { sprint(pe_player, PRINT_HIGH, "Next map has already been voted to ", vote_result, ". Use /forcenext to force next map.\n"); return; @@ -115,6 +125,11 @@ void (entity pe_player) Vote_RaceMap = { if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_race) return; + if (vote_started > 0) { + sprint(pe_player, PRINT_HIGH, "There is already a vote in progress.\n"); + return; + } + if (vote_result != string_null) { sprint(pe_player, PRINT_HIGH, "Next map has already been voted to ", vote_result, ". Use /forcenext to force next map.\n"); return; From e0e2d66014a57d5daddfcfb82b2a341f06738e6c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 00:47:37 +0200 Subject: [PATCH 0174/2474] Do not reset weapon model when restocking while feigned (fixes #153) --- spy.qc | 8 ++++---- weapons.qc | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/spy.qc b/spy.qc index f8cd17ff..883885e8 100644 --- a/spy.qc +++ b/spy.qc @@ -395,6 +395,10 @@ void (float issilent) TeamFortress_SpyFeignDeath = { // set movetype to walk self.movetype = MOVETYPE_WALK; + // unset feign variables + self.is_feigning = 0; + self.feign_areachecked = 0; + // load saved weapon state and set current ammo W_WeaponState_Load(self, 0); W_SetCurrentAmmo(self); @@ -403,10 +407,6 @@ void (float issilent) TeamFortress_SpyFeignDeath = { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); - // unset feign variables - self.is_feigning = 0; - self.feign_areachecked = 0; - // set revive animation i = 1 + floor(random() * 5); if (i == 1) { diff --git a/weapons.qc b/weapons.qc index 0bbeec04..e75ad6e6 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1475,6 +1475,11 @@ void (entity pl) W_SetCurrentAmmo = { pl.weaponframe = 0; } + if (pl.is_feigning) { + pl.weaponmodel = ""; + pl.weaponframe = 0; + } + // refresh engineer build menu when ammo updated if (pl.menu_input == Menu_Engineer_Input) Menu_Engineer(pl); From b7593a3acf2353a17077ca02cc51cd6ecb69039f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 01:03:08 +0200 Subject: [PATCH 0175/2474] Set menu start time if not set (fixes #154) --- vote.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vote.qc b/vote.qc index d0de5bde..9eeb0c34 100644 --- a/vote.qc +++ b/vote.qc @@ -424,7 +424,7 @@ void (float force) Vote_MenuOpen = { if (((time - e_player.spawn_time) <= CF_MAPVOTE_FORCESHOW || (time - e_player.menu_time) <= CF_MAPVOTE_FORCESHOW) && !force) { //dprint("[", ftos(time), "/cf/mapvote/menuopen]: open vote menu for newly spawned ", e_player.netname, ".\n"); - if (e_player.menu_time < (time - CF_MAPVOTE_FORCESHOW)) + if (!e_player.menu_time || e_player.menu_time < (time - CF_MAPVOTE_FORCESHOW)) e_player.menu_time = time; Vote_Menu(e_player); } else if (force == 1) { From 8669f323f87d0c5dc2ba8bbe474f7e89decacdf5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 22:21:00 +0200 Subject: [PATCH 0176/2474] Implement auto ID (closes #123) --- actions.qc | 245 +++++++++++++++++++++++------------------------------ client.qc | 11 +++ qw.qc | 4 + spect.qc | 2 +- status.qc | 13 ++- tfort.qc | 27 ++++++ 6 files changed, 159 insertions(+), 143 deletions(-) diff --git a/actions.qc b/actions.qc index 6409b727..fb7e8e3c 100644 --- a/actions.qc +++ b/actions.qc @@ -110,151 +110,116 @@ void () TeamFortress_SaveMe = { } }; -void () TeamFortress_ID = { - local vector src; - local string st; - local string cls; - - src = self.origin + v_forward * 10; - src_z = self.absmin_z + self.size_z * 0.7; - - traceline(src, src + v_forward * 2048, 0, self); - if ((trace_ent != world) && (trace_ent.origin != world.origin)) { - if ((trace_ent.classname == "player") && (trace_ent.health > 0)) { - if (trace_ent.is_feigning && (self.team_no != 0) && - (self.team_no != trace_ent.team_no)) { - return; - } - self.StatusRefreshTime = time + 1.5; - if (((self.team_no != 0) && - (self.team_no == trace_ent.team_no)) - || (self.classname == "observer")) { - cls = TeamFortress_GetClassName(trace_ent.playerclass); - if (self.playerclass == PC_MEDIC) { - st = NumberToString1000(trace_ent.health); - centerprint(self, "\n\n\n\n", trace_ent.netname, - "\nFriendly ", cls, "\n", st, " health\n"); - return; - } else if (self.playerclass == PC_ENGINEER) { - st = NumberToString1000(trace_ent.armorvalue); - centerprint(self, "\n\n\n\n", trace_ent.netname, - "\nFriendly ", cls, "\n", st, " armor\n"); +void (entity pe_player) CF_Identify = { + local vector v_source; + local string s_id_string, s_class = "", s_name = ""; + local float f_health = 0, f_armor = 0, f_friendly = 0, f_fakefriendly = 0; + + v_source = pe_player.origin + v_forward * 10; + v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; + + traceline(v_source, v_source + v_forward * 2048, 0, pe_player); + if (trace_ent != world) { + + // show as friendly if target is on your team or disguised as your team + if (pe_player.team_no) { + if (pe_player.team_no == trace_ent.team_no) + f_friendly = 1; + else if (pe_player.team_no == trace_ent.undercover_team) + f_fakefriendly = 1; + } + + // alive player is found + if (trace_ent.classname == "player" && trace_ent.health) { + + // set class and name + s_class = TeamFortress_GetClassName(trace_ent.playerclass); + s_name = trace_ent.netname; + + // set health if you're a medic + if (pe_player.playerclass == PC_MEDIC) + f_health = trace_ent.health; + + // set armor if you're an engineer + else if (pe_player.playerclass == PC_ENGINEER) + f_armor = trace_ent.armorvalue; + + // target is an enemy spy + if (trace_ent.playerclass == PC_SPY && !f_friendly) { + + // don't identify feigning enemy spies + if (trace_ent.is_feigning) return; - } - centerprint(self, "\n\n\n\n", trace_ent.netname, - "\nFriendly ", cls); - return; - } - if (trace_ent.playerclass == 8) { - cls = TeamFortress_GetClassName(trace_ent.undercover_skin); - if ((self.team_no != 0) && - (self.team_no == trace_ent.undercover_team)) { - if (self.playerclass == 5) { - st = NumberToString1000(trace_ent.health); - if (trace_ent.undercover_skin != 0) { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, - "\nFriendly ", cls, "\n", st, - " health\n"); - } else { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, - "\nFriendly Spy\n", st, - " health\n"); - } - return; - } else { - if (self.playerclass == 9) { - st = NumberToString1000(trace_ent.armorvalue); - if (trace_ent.undercover_skin != 0) { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, - "\nFriendly ", cls, "\n", st, - " armor\n"); - } else { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, - "\nFriendly Spy\n", st, - " armor\n"); - } - return; - } else { - st = NumberToString1000(trace_ent.armorvalue); - if (trace_ent.undercover_skin != 0) { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, - "\nFriendly ", cls); - } else { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, - "\nFriendly Spy\n"); - } - return; - } - } - } - if (trace_ent.undercover_name != string_null) { - if (trace_ent.undercover_skin != 0) { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, "\nEnemy ", - cls); - } else { - centerprint(self, "\n\n\n\n", - trace_ent.undercover_name, - "\nEnemy Spy"); - } - } else { - if (trace_ent.undercover_skin != 0) { - centerprint(self, "\n\n\n\n", trace_ent.netname, - "\nEnemy ", cls); - } else { - centerprint(self, "\n\n\n\n", trace_ent.netname, - "\nEnemy Spy"); - } - } - } else { - cls = TeamFortress_GetClassName(trace_ent.playerclass); - centerprint(self, "\n\n\n\n", trace_ent.netname, - "\nEnemy ", cls); + + // use undercover name if available + if (trace_ent.undercover_name != string_null) + s_name = trace_ent.undercover_name; + + // set class to undercover skin + if (trace_ent.undercover_skin) + s_class = TeamFortress_GetClassName(trace_ent.undercover_skin); + } + + // dispenser is found + } else if (trace_ent.classname == "building_dispenser") { + + if (self == trace_ent.real_owner) + s_name = "Your dispenser"; + else + s_name = strcat(trace_ent.real_owner.netname, "'s dispenser"); + + s_class = ""; + + // sentry gun is found + } else if (trace_ent.classname == "building_sentrygun" || trace_ent.classname == "building_sentrygun_base") { + + if (self == trace_ent.real_owner) + s_name = "Your sentry gun"; + else + s_name = strcat(trace_ent.real_owner.netname, "'s sentry gun"); + + s_class = ""; + + } + + // set name (+ health/armor) + if (f_health && (f_friendly || f_fakefriendly)) { + s_id_string = strcat(s_name, " ("); + s_id_string = strcat(s_id_string, ftos(f_health)); + s_id_string = strcat(s_id_string, " hp)\n"); + } else if (f_armor && (f_friendly || f_fakefriendly)) { + s_id_string = strcat(s_name, " ("); + s_id_string = strcat(s_id_string, ftos(f_armor)); + s_id_string = strcat(s_id_string, " armor)\n"); } else { - if (trace_ent.classname == "building_dispenser") { - self.StatusRefreshTime = time + 1.5; - if (self == trace_ent.real_owner) { - centerprint(self, "\n\n\n\nYour Dispenser"); - } else { - centerprint(self, "\n\n\n\nDispenser made by ", - trace_ent.real_owner.netname); - } - } else { - if ((trace_ent.classname == "building_sentrygun") || - (trace_ent.classname == "building_sentrygun_base")) { - self.StatusRefreshTime = time + 1.5; - if (self == trace_ent.real_owner) { - centerprint(self, "\n\n\n\nYour SentryGun"); - } else { - if (!teamplay) { - centerprint(self, - "\n\n\n\nSentrygun made by\n", - trace_ent.real_owner.netname); - } else { - if (((self.team_no != 0) && - (self.team_no == trace_ent.team_no)) || - (self.playerclass == 0)) { - centerprint(self, - "\n\n\n\nFriendly Sentrygun made by\n", - trace_ent.real_owner.netname); - } else { - centerprint(self, - "\n\n\n\nEnemy Sentrygun made by\n", - trace_ent.real_owner.netname); - } - } - } - } - } + s_id_string = strcat(s_name, "\n"); } + + // set friendly/enemy + if (f_friendly || f_fakefriendly) + s_id_string = strcat(s_id_string, "Friendly"); + else + s_id_string = strcat(s_id_string, "Hostile"); + + // set class + if (s_class != "") { + s_id_string = strcat(s_id_string, " "); + s_id_string = strcat(s_id_string, s_class); + } + + pe_player.ident_time = time + 0.5; + + // don't update memory when the id string is the same + if (pe_player.ident_string == s_id_string) + return; + + // refresh status bar + pe_player.ident_string = strzone(s_id_string); + Status_Refresh(pe_player); + } + }; void (float weap) TeamFortress_ReloadWeapon = { diff --git a/client.qc b/client.qc index 20a7f201..9f8a93c8 100644 --- a/client.qc +++ b/client.qc @@ -36,6 +36,7 @@ void () PreMatch_Think; void () DumpClanScores; +void () AutoId; void (entity p) SetTeamName; void () autokick_think; @@ -963,6 +964,7 @@ void () PutClientInServer = { local float oldclass; local entity spot; local entity te; + local entity timer; self.touch = player_touch; self.classname = "player"; @@ -1131,6 +1133,15 @@ void () PutClientInServer = { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } + + // start autoid timer + if (stof(infokey(self, "ai"))) { + timer = spawn(); + timer.nextthink = time + 0.3; + timer.think = AutoId; + timer.owner = self; + timer.classname = "aitimer"; + } }; void () info_player_start = { diff --git a/qw.qc b/qw.qc index 7b96b4bf..675a363d 100644 --- a/qw.qc +++ b/qw.qc @@ -60,6 +60,10 @@ typedef void (float) f_void_float; .entity observer_list; // Used by undefined classes, see TF_MovePlayer +// Identify variables +.string ident_string; // Status bar string for identify +.float ident_time; // The time when last identify found a player + // Playerclass handling variables .float maxammo_shells; .float maxammo_nails; diff --git a/spect.qc b/spect.qc index 6eea89cf..effd6dcb 100644 --- a/spect.qc +++ b/spect.qc @@ -76,7 +76,7 @@ void () SpectatorImpulseCommand = { } } else if (self.impulse == TF_ID) - TeamFortress_ID(); + CF_Identify(self); else if (self.impulse == TF_HELP_MAP) diff --git a/status.qc b/status.qc index b719d7a5..abc6732b 100644 --- a/status.qc +++ b/status.qc @@ -15,6 +15,7 @@ string(entity pl) RangeToString; string(entity pl) ScannerToString; string(entity pl) DisguiseToString; string(entity pl) SentryDetailsToString; +string(float pc) TeamFortress_GetClassName; void (entity pl, string...count) Status_Print = { @@ -99,6 +100,7 @@ void (entity pl) RefreshStatusBar = { local string s2; // class line local string s3; // score & clip local string st1, st2, st3, st4; // status bar columns 1-4 + local string ident; local float height; local float i; local float win, sec; @@ -115,7 +117,7 @@ void (entity pl) RefreshStatusBar = { height = floor(stof(infokey(pl, "sb"))); if (height > 300) height = 300; - height = height - pl.StatusStringLines - 3; + height = height - pl.StatusStringLines - 6; // no sbar can be displayed if (height <= 0 || pl.playerclass == PC_UNDEFINED) { @@ -229,7 +231,14 @@ void (entity pl) RefreshStatusBar = { s3 = strcat(s3, "\n"); s3 = strzone(s3); - centerprint(pl, pl.StatusString, pad, s1, s2, s3); + // identify + if (pl.ident_string != string_null && time < pl.ident_time) { + ident = strcat(pl.ident_string, "\n\n"); + } else { + ident = "\n\n\n"; + } + + centerprint(pl, pl.StatusString, pad, ident, s1, s2, s3); pl.StatusRefreshTime = time + 1.5; strunzone(pad); strunzone(s1); strunzone(s2); strunzone(s3); }; diff --git a/tfort.qc b/tfort.qc index e6d80696..7de16f03 100644 --- a/tfort.qc +++ b/tfort.qc @@ -7,9 +7,26 @@ void () TeamFortress_ExplodePerson; void () TeamFortress_Regenerate; void () TeamFortress_CheckforCheats; void () TeamFortress_RegenerateCells; +void (entity pe_player) CF_Identify; float () CloseToSpawnPoint; +void () AutoId = { + + if (time > self.ident_time || !self.ident_time) { + + // remove ident string from memory + if (self.ident_string != string_null) { + strunzone(self.ident_string); + self.ident_string = string_null; + } + + CF_Identify(self.owner); + } + + self.nextthink = time + 0.1; +}; + void () UseSpecialSkill = { local vector src; @@ -45,6 +62,15 @@ void () UseSpecialSkill = { } }; +void () RemoveAutoIdTimer = { + local entity te = find(world, classname, "aitimer"); + while (te != world) { + if (te.owner == self) + dremove(te); + te = find(te, classname, "aitimer"); + } +}; + void () RemoveGrenadeTimers = { local entity te = find(world, classname, "gtimer"); while (te != world) { @@ -2045,6 +2071,7 @@ void () TeamFortress_RemoveTimers = { te = find(te, classname, "timer"); } + RemoveAutoIdTimer(); RemoveGrenadeTimers(); self.StatusGrenTime = 0; Status_Refresh(self); From 3f7b021ccfce025fea993ee048e459349949b1f8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 22:22:49 +0200 Subject: [PATCH 0177/2474] Replace some instances of TeamFortress_ID() --- weapons.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/weapons.qc b/weapons.qc index e75ad6e6..df546714 100644 --- a/weapons.qc +++ b/weapons.qc @@ -45,7 +45,7 @@ void (float zoom_to) Sniper_Zoom; void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; -void () TeamFortress_ID; +void (entity pe_player) CF_Identify; void () TeamFortress_ReloadCurrentWeapon; void (float slot) TeamFortress_ReloadSlot; void () TeamFortress_ReloadNext; @@ -2252,7 +2252,7 @@ void () ImpulseCommands = { else if (self.impulse == TF_GRENADE_SWITCH) TeamFortress_GrenadeSwitch(); else if (self.impulse == TF_ID) - TeamFortress_ID(); + CF_Identify(); else if (self.impulse == TF_SHOW_IDS) TeamFortress_ShowIDs(); else if ((self.playerclass != 0) && (self.impulse == TF_DROPFLAG)) @@ -2314,7 +2314,7 @@ void () PreMatchImpulses = { if (self.impulse == TF_INVENTORY) TeamFortress_Inventory(); else if (self.impulse == TF_ID) - TeamFortress_ID(); + CF_Identify(); else if (self.impulse == FLAG_INFO) { if (CTF_Map == TRUE) TeamFortress_CTF_FlagInfo(); From 4c63337069fc5e2364ccbe2f2dd9171a65cf8639 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 27 Aug 2014 23:50:32 +0200 Subject: [PATCH 0178/2474] Rename feign death function name --- menu.qc | 4 ++-- spy.qc | 2 +- weapons.qc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/menu.qc b/menu.qc index e45dc417..0f42b407 100644 --- a/menu.qc +++ b/menu.qc @@ -4,7 +4,7 @@ void (float class) TeamFortress_SpyChangeSkin; void (float teamno) TeamFortress_SpyChangeColor; -void (float issilent) TeamFortress_SpyFeignDeath; +void (float issilent) CF_Spy_FeignDeath; void (entity spy) Spy_RemoveDisguise; @@ -357,7 +357,7 @@ void (float inp) Menu_Spy_Input = { } else if (inp == 2) { Menu_Spy_Color(); } else if (inp == 3) { - TeamFortress_SpyFeignDeath(1); + CF_Spy_FeignDeath(1); if (self.is_feigning) { Menu_Spy(); } diff --git a/spy.qc b/spy.qc index 883885e8..816bd863 100644 --- a/spy.qc +++ b/spy.qc @@ -372,7 +372,7 @@ float (entity pe_player) Spy_CheckArea = { return 0; }; -void (float issilent) TeamFortress_SpyFeignDeath = { +void (float issilent) CF_Spy_FeignDeath = { local string deathstring; local float area_check; local float i; diff --git a/weapons.qc b/weapons.qc index df546714..e42fd426 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2274,10 +2274,10 @@ void () ImpulseCommands = { else if ((self.impulse == TF_SPY_SPY) && (self.playerclass == PC_SPY)) TeamFortress_SpyGoUndercover(); else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) - TeamFortress_SpyFeignDeath(0); + CF_Spy_FeignDeath(0); else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) - TeamFortress_SpyFeignDeath(1); + CF_Spy_FeignDeath(1); else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); From 5f5fd9e2251ebf61c08b725d31a905e9a5ecad3f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 00:08:12 +0200 Subject: [PATCH 0179/2474] Properly identify your own dispensers/sentry guns --- actions.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions.qc b/actions.qc index fb7e8e3c..03116950 100644 --- a/actions.qc +++ b/actions.qc @@ -164,7 +164,7 @@ void (entity pe_player) CF_Identify = { // dispenser is found } else if (trace_ent.classname == "building_dispenser") { - if (self == trace_ent.real_owner) + if (pe_player == trace_ent.real_owner) s_name = "Your dispenser"; else s_name = strcat(trace_ent.real_owner.netname, "'s dispenser"); @@ -174,7 +174,7 @@ void (entity pe_player) CF_Identify = { // sentry gun is found } else if (trace_ent.classname == "building_sentrygun" || trace_ent.classname == "building_sentrygun_base") { - if (self == trace_ent.real_owner) + if (pe_player == trace_ent.real_owner) s_name = "Your sentry gun"; else s_name = strcat(trace_ent.real_owner.netname, "'s sentry gun"); From c52ed197ffaab1f08854efae5a3cd3d70651aa05 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 18:47:30 +0200 Subject: [PATCH 0180/2474] Merge change skin with change team and add quick aliases for disguises (closes #122) --- defs.h | 18 ++- menu.qc | 112 ++++++------------ qw.qc | 2 + spy.qc | 332 +++++++++++++++++++++++++++++++++------------------- status.qc | 14 ++- tforthlp.qc | 14 +++ weapons.qc | 48 ++++++-- 7 files changed, 331 insertions(+), 209 deletions(-) diff --git a/defs.h b/defs.h index 338e7a2f..5da7d1fd 100644 --- a/defs.h +++ b/defs.h @@ -403,9 +403,25 @@ #define TF_ZOOMOUT 115 // Help impulses +#define TF_HELP_MAP 117 #define TF_DISPLAYLOCATION 118 #define TF_STATUS_QUERY 119 -#define TF_HELP_MAP 131 + +// Disguise impulses +#define TF_DISGUISE_RESET 120 +#define TF_DISGUISE_SCOUT 121 +#define TF_DISGUISE_SNIPER 122 +#define TF_DISGUISE_SOLDIER 123 +#define TF_DISGUISE_DEMOMAN 124 +#define TF_DISGUISE_MEDIC 125 +#define TF_DISGUISE_HWGUY 126 +#define TF_DISGUISE_PYRO 127 +#define TF_DISGUISE_ENGINEER 128 +#define TF_DISGUISE_BLUE 129 +#define TF_DISGUISE_RED 130 +#define TF_DISGUISE_YELLOW 131 +#define TF_DISGUISE_GREEN 132 +#define TF_DISGUISE_ENEMY 133 // Information impulses #define TF_INVENTORY 135 diff --git a/menu.qc b/menu.qc index 0f42b407..699e24cd 100644 --- a/menu.qc +++ b/menu.qc @@ -2,8 +2,8 @@ // This file handles all menu functions and displays. //====================================================== -void (float class) TeamFortress_SpyChangeSkin; -void (float teamno) TeamFortress_SpyChangeColor; +void (entity pe_player, float pf_class) CF_Spy_ChangeSkin; +void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor; void (float issilent) CF_Spy_FeignDeath; void (entity spy) Spy_RemoveDisguise; @@ -56,17 +56,11 @@ void () PlayerObserverMode; void () Menu_Scout; void () Menu_Spy; void () Menu_Spy_Skin; -void () Menu_Spy_Skin_1; -void () Menu_Spy_Skin_2; -void () Menu_Spy_Skin_3; void () Menu_Spy_Color; void (float inp) Menu_Scout_Input; void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; -void (float inp) Menu_Spy_Skin_1_Input; -void (float inp) Menu_Spy_Skin_2_Input; -void (float inp) Menu_Spy_Skin_3_Input; void (float inp) Menu_Spy_Color_Input; void () Menu_Demoman; @@ -368,7 +362,7 @@ void (float inp) Menu_Spy_Input = { void () Menu_Spy = { local string s_action = "Action:\n\n"; - local string s_skin = "“‘ Change skin \n"; + local string s_skin = "“‘ Disguise \n"; local string s_color = "”‘ Change color \n"; local string s_feign, s_reset; local string s_nothing = "\n—‘ Nothing "; @@ -382,88 +376,48 @@ void () Menu_Spy = { else s_feign = "•‘ Start feigning (silent)\n"; - if (self.undercover_team != 0 && self.undercover_skin != 0) + if (self.undercover_team && self.undercover_skin) s_reset = "–‘ Reset disguise \n"; - else if (self.undercover_team != 0) + else if (self.undercover_team) s_reset = "–‘ Reset color \n"; - else if (self.undercover_skin != 0) + else if (self.undercover_skin) s_reset = "–‘ Reset skin \n"; else s_reset = "\n"; - Status_Menu(self, Menu_Spy_Input, s_action, s_skin, s_color, s_feign, s_reset, s_nothing); + Status_Menu(self, Menu_Spy_Input, s_action, s_skin, s_last, s_feign, s_reset, s_nothing); }; void (float inp) Menu_Spy_Skin_Input = { - if (inp == 1) { - Menu_Spy_Skin_1(); - } else if (inp == 2) { - Menu_Spy_Skin_2(); - } else if (inp == 3) { - Menu_Spy_Skin_3(); - } -}; - -void () Menu_Spy_Skin = { - local string s_disguise = "Disguise as:\n\n"; - local string s_scsnso = "“‘ Scout / Sniper / Soldier\n"; - local string s_demehw = "”‘ Demoman / Medic / HWGuy \n"; - local string s_pyspen = "•‘ Pyro / Spy / Engineer \n"; - local string s_nothing = "\n—‘ Nothing \n"; - - Status_Menu(self, Menu_Spy_Skin_Input, s_disguise, s_scsnso, s_demehw, s_pyspen, s_nothing); -}; - -void (float inp) Menu_Spy_Skin_1_Input = { - if (inp > 0 && inp < 4) - TeamFortress_SpyChangeSkin(inp); -} - -void () Menu_Spy_Skin_1 = { - local string s_disguise = "Disguise as:\n\n"; - local string s_scout = "“‘ Scout \n"; - local string s_sniper = "”‘ Sniper \n"; - local string s_soldier = "•‘ Soldier\n"; - local string s_nothing = "\n—‘ Nothing\n"; - - Status_Menu(self, Menu_Spy_Skin_1_Input, s_disguise, s_scout, s_sniper, s_soldier, s_nothing); -} - -void (float inp) Menu_Spy_Skin_2_Input = { - local float classnum; - classnum = inp + 3; - - if (inp > 0 && inp < 4) - TeamFortress_SpyChangeSkin(classnum); -} - -void () Menu_Spy_Skin_2 = { - local string s_disguise = "Disguise as:\n\n"; - local string s_demoman = "“‘ Demoman\n"; - local string s_medic = "”‘ Medic \n"; - local string s_hwguy = "•‘ HWGuy \n"; - local string s_nothing = "\n—‘ Nothing\n"; - - Status_Menu(self, Menu_Spy_Skin_2_Input, s_disguise, s_demoman, s_medic, s_hwguy, s_nothing); -} + if (inp == 0) + return; -void (float inp) Menu_Spy_Skin_3_Input = { - local float classnum; - classnum = inp + 6; + CF_Spy_ChangeSkin(self, inp); - if (inp > 0 && inp < 4) - TeamFortress_SpyChangeSkin(classnum); -} + if (number_of_teams > 2) + Menu_Spy_Color(); + else if (self.team_no == 1) + CF_Spy_ChangeColor(self, 2); + else + CF_Spy_ChangeColor(self, 1); -void () Menu_Spy_Skin_3 = { - local string s_disguise = "Disguise as:\n\n"; - local string s_pyro = "“‘ Pyro \n"; - local string s_spy = "”‘ Spy \n"; - local string s_engineer = "•‘ Engineer\n"; - local string s_nothing = "\n—‘ Nothing \n"; +}; - Status_Menu(self, Menu_Spy_Skin_3_Input, s_disguise, s_pyro, s_spy, s_engineer, s_nothing); -} +void () Menu_Spy_Skin = { + local string s_disguise = "Disguise as enemy:\n\n"; + local string s_scout = "“‘ Scout \n"; + local string s_sniper = "”‘ Sniper \n"; + local string s_soldier = "•‘ Soldier \n"; + local string s_demoman = "–‘ Demoman \n"; + local string s_medic = "—‘ Medic \n"; + local string s_hwguy = "˜‘ HWGuy \n"; + local string s_pyro = "™‘ Pyro \n"; + local string s_spy = "š‘ Spy (reset)\n"; + local string s_engineer = "›‘ Engineer \n"; + local string s_nothing = "\n’‘ Nothing \n"; + + Status_Menu(self, Menu_Spy_Skin_Input, s_disguise, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_nothing); +}; void (float inp) Menu_Spy_Color_Input = { local float color = stof(infokey(self, "bottomcolor")); @@ -477,7 +431,7 @@ void (float inp) Menu_Spy_Color_Input = { else if (inp == 4 && color == 3) Menu_Spy_Color(); else if (inp > 0 && inp <= number_of_teams) - TeamFortress_SpyChangeColor(inp); + CF_Spy_ChangeColor(self, inp); }; void () Menu_Spy_Color = { diff --git a/qw.qc b/qw.qc index 675a363d..cb2029c0 100644 --- a/qw.qc +++ b/qw.qc @@ -49,7 +49,9 @@ typedef void (float) f_void_float; .float detpack_left; // Seconds left to detpack explosion .float pipecooldown; // Time when detpipe command can be issued .float disguise_skin; // The skin the spy is changing to +.float queue_skin; // The skin the spy will change to after team disguise is finished .float disguise_team; // The team the spy is changing to +.float queue_team; // The team the spy will change to after skin disguise is finished .float feign_areachecked; // TRUE if area around spy has been checked for entities when feigned .float fragstreak; // Frag streak .float caps; // Caps during this game diff --git a/spy.qc b/spy.qc index 816bd863..8af63889 100644 --- a/spy.qc +++ b/spy.qc @@ -1,6 +1,6 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer; void (entity spy) TeamFortress_SpyCalcName; -void () TeamFortress_SpyUndercoverThink; +void () CF_Spy_UndercoverThink; void () GasGrenadeMakeGas; void () T_TranqDartTouch; void () Spy_DropBackpack; @@ -529,54 +529,248 @@ void (float issilent) CF_Spy_FeignDeath = { } }; -void () TeamFortress_SpyGoUndercover = { - local entity te, timer; +void () CF_Spy_GoUndercover = { + local entity e_timer; - if (self.effects & (8 | 4)) { + if (self.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) { sprint(self, PRINT_MEDIUM, "You cannot disguise while glowing\n"); return; } - if (self.is_unabletospy == 1) { + + if (self.is_unabletospy) { sprint(self, PRINT_HIGH, "You cannot go undercover right now\n"); return; } + if (invis_only == 1) { - if ((self.is_undercover == 1) || (self.items & 524288)) { - self.items = self.items - 524288; + + if (self.is_undercover == 1 || self.items & IT_INVISIBILITY) { + + self.items = self.items - IT_INVISIBILITY; self.invisible_finished = 0; self.invisible_time = 0; self.is_undercover = 0; self.modelindex = modelindex_player; + } else if (self.is_undercover == 2) { + sprint(self, PRINT_HIGH, "You stop going undercover\n"); + self.is_undercover = 0; + } else if (self.ammo_cells > 1) { + sprint(self, PRINT_HIGH, "Going undercover...\n"); + self.is_undercover = 2; - te = spawn(); - te.classname = "spytimer"; - te.owner = self; - te.think = TeamFortress_SpyUndercoverThink; - te.nextthink = time + 4; + + // create a timer for 4 seconds + e_timer = spawn(); + e_timer.classname = "spytimer"; + e_timer.owner = self; + e_timer.think = CF_Spy_UndercoverThink; + e_timer.nextthink = time + 4; } + Status_Refresh(self); + } else if (self.is_undercover != 2) { + Menu_Spy(); + } else { + sprint(self, PRINT_HIGH, "You stop going undercover\n"); + self.is_undercover = 0; self.disguise_skin = 0; self.disguise_team = 0; - timer = find(world, classname, "spytimer"); - while (timer != world) { - if (timer.owner == self) { - dremove(timer); - timer = find(world, classname, "spytimer"); + + // remove disguise timers belonging to self + e_timer = find(world, classname, "spytimer"); + while (e_timer != world) { + if (e_timer.owner == self) { + dremove(e_timer); + e_timer = find(world, classname, "spytimer"); } else { - timer = find(timer, classname, "spytimer"); + e_timer = find(e_timer, classname, "spytimer"); } } + + } + +}; + +void () CF_Spy_UndercoverThink = { + local float f_team_color; + local string s_team, s_class; + + // stop if player is not a spy + if (self.owner.playerclass != PC_SPY) + return; + + // stop if spy is not going undercover + if (self.owner.is_undercover != 2) + return; + + // make spy invisible if invis_only is turned on + if (invis_only == 1) { + + self.owner.items = self.owner.items | IT_INVISIBILITY; + self.owner.frame = 0; + self.owner.modelindex = modelindex_eyes; + self.owner.is_undercover = 1; + + } else { + + // don't check for color cheating for next 10 seconds + self.owner.immune_to_check = time + 10; + + if (self.skin) { + self.owner.undercover_skin = self.skin; + self.owner.disguise_skin = 0; + self.owner.queue_skin = 0; + self.owner.is_undercover = 1; + TeamFortress_SetSkin(self.owner); + + if (self.owner.queue_team) { + CF_Spy_ChangeColor(self.owner, self.owner.queue_team); + } else { + s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); + s_class = TeamFortress_GetClassName(self.owner.undercover_skin); + sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); + } + + } else if (self.team) { + self.owner.undercover_team = self.team; + + // tell client to change color + f_team_color = TeamFortress_TeamGetColor(self.team) - 1; + stuffcmd(self.owner, "color "); + stuffcmd(self.owner, ftos(f_team_color)); + stuffcmd(self.owner, "\n"); + self.owner.queue_team = 0; + self.owner.is_undercover = 1; + TeamFortress_SetSkin(self.owner); + + if (self.owner.queue_skin) { + CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin); + } else { + s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); + s_class = TeamFortress_GetClassName(self.owner.undercover_skin); + sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); + } + } + + TeamFortress_SpyCalcName(self.owner); + + } + + Status_Refresh(self.owner); + dremove(self); + +}; + +void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { + local entity e_timer; + + // stop if you're already disguised as the requested skin + if (pe_player.undercover_skin == pf_class) + return; + + // stop if you're glowing + if (pe_player.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) + return; + + // stop if you're unable to spy + if (pe_player.is_unabletospy) + return; + + // reset skin if skin is set to spy + if (pf_class == PC_SPY) { + sprint(pe_player, PRINT_HIGH, "Skin reset\n"); + pe_player.undercover_skin = 0; + pe_player.disguise_skin = 0; + TeamFortress_SetSkin(pe_player); + if (!pe_player.undercover_team) + pe_player.is_undercover = 0; + return; + } + + // queue skin change if currently going undercover + if (pe_player.is_undercover == 2) { + pe_player.queue_skin = pf_class; + return; } + + // prepare disguise + if (!pe_player.undercover_team) + sprint(pe_player, PRINT_HIGH, "Going undercover...\n"); + pe_player.is_undercover = 2; + pe_player.disguise_skin = pf_class; + pe_player.disguise_team = 0; + + // disguise timer, finishes in 4 seconds + e_timer = spawn(); + e_timer.classname = "spytimer"; + e_timer.owner = pe_player; + e_timer.think = CF_Spy_UndercoverThink; + e_timer.nextthink = time + 4; + e_timer.skin = pf_class; + TeamFortress_SetSkin(pe_player); +}; + +void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { + local entity e_timer; + local float f_team_color = TeamFortress_TeamGetColor(pf_team_no) - 1; + + // stop if you're already disguised as the requested skin + if (pe_player.undercover_team == pf_team_no) + return; + + // stop if you're glowing + if (pe_player.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) + return; + + // stop if you're unable to spy + if (pe_player.is_unabletospy) + return; + + // reset team if team is set to home team + if (pf_team_no == pe_player.team_no) { + sprint(pe_player, PRINT_HIGH, "Colors reset\n"); + pe_player.immune_to_check = time + 10; + pe_player.undercover_team = 0; + pe_player.disguise_team = 0; + stuffcmd(pe_player, "color "); + stuffcmd(pe_player, ftos(f_team_color)); + stuffcmd(pe_player, "\n"); + if (!pe_player.undercover_skin) + pe_player.is_undercover = 0; + TeamFortress_SetSkin(pe_player); + return; + } + + // queue team change if currently going undercover + if (pe_player.is_undercover == 2) { + pe_player.queue_team = pf_team_no; + return; + } + + // prepare disguise + if (!pe_player.undercover_skin) + sprint(pe_player, PRINT_HIGH, "Going undercover...\n"); + pe_player.is_undercover = 2; + pe_player.disguise_skin = 0; + pe_player.disguise_team = pf_team_no; + + // disguise timer, finishes in 4 seconds + e_timer = spawn(); + e_timer.classname = "spytimer"; + e_timer.owner = pe_player; + e_timer.think = CF_Spy_UndercoverThink; + e_timer.nextthink = time + 4; + e_timer.team = pf_team_no; }; void (entity spy) TeamFortress_SpyCalcName = { @@ -608,108 +802,6 @@ void (entity spy) TeamFortress_SpyCalcName = { } }; -void () TeamFortress_SpyUndercoverThink = { - local float tc; - local string st; - - if (self.owner.playerclass != 8) { - return; - } - if (self.owner.is_undercover == 2) { - if (invis_only == 1) { - self.owner.items = self.owner.items | 524288; - self.owner.frame = 0; - self.owner.modelindex = modelindex_eyes; - self.owner.is_undercover = 1; - } else { - self.owner.immune_to_check = time + 10; - if (self.skin != 0) { - sprint(self.owner, PRINT_HIGH, "Disguised as "); - TeamFortress_PrintClassName(self.owner, self.skin, 0); - self.owner.undercover_skin = self.skin; - self.owner.disguise_skin = 0; - TeamFortress_SetSkin(self.owner); - } - if (self.team != 0) { - sprint(self.owner, PRINT_HIGH, "Disguised as "); - st = TeamFortress_TeamGetColorString(self.team); - sprint(self.owner, PRINT_HIGH, st, " Team\n"); - self.owner.undercover_team = self.team; - stuffcmd(self.owner, "color "); - tc = TeamFortress_TeamGetColor(self.team) - 1; - st = ftos(tc); - stuffcmd(self.owner, st); - stuffcmd(self.owner, "\n"); - TeamFortress_SetSkin(self.owner); - } - TeamFortress_SpyCalcName(self.owner); - Status_Print(self.owner, "\n\n\n\n\n\n\n", "You are now disguised"); - self.owner.is_undercover = 1; - } - } - Status_Refresh(self.owner); - dremove(self); -}; - -void (float class) TeamFortress_SpyChangeSkin = { - local entity te; - - if (class == 8) { - sprint(self, PRINT_HIGH, "Skin reset\n"); - self.undercover_skin = 0; - self.disguise_skin = 0; - TeamFortress_SetSkin(self); - if (self.undercover_team == 0) { - self.is_undercover = 0; - } - return; - } - sprint(self, PRINT_HIGH, "Going undercover...\n"); - self.is_undercover = 2; - self.disguise_skin = class; - self.disguise_team = 0; - te = spawn(); - te.classname = "spytimer"; - te.owner = self; - te.think = TeamFortress_SpyUndercoverThink; - te.nextthink = time + 4; - te.skin = class; - TeamFortress_SetSkin(self); -}; - -void (float teamno) TeamFortress_SpyChangeColor = { - local entity te; - local string st; - local float tc; - - if (teamno == self.team_no) { - sprint(self, PRINT_HIGH, "Colors reset\n"); - self.immune_to_check = time + 10; - self.undercover_team = 0; - self.disguise_team = 0; - stuffcmd(self, "color "); - tc = TeamFortress_TeamGetColor(self.team_no) - 1; - st = ftos(tc); - stuffcmd(self, st); - stuffcmd(self, "\n"); - if (self.undercover_skin == 0) { - self.is_undercover = 0; - } - TeamFortress_SetSkin(self); - return; - } - sprint(self, PRINT_HIGH, "Going undercover...\n"); - self.is_undercover = 2; - self.disguise_skin = 0; - self.disguise_team = teamno; - te = spawn(); - te.classname = "spytimer"; - te.owner = self; - te.think = TeamFortress_SpyUndercoverThink; - te.nextthink = time + 4; - te.team = teamno; -}; - void () GasGrenadeTouch = { sound(self, 1, "weapons/bounce.wav", 1, 1); if (self.velocity == '0 0 0') diff --git a/status.qc b/status.qc index abc6732b..f144ffbe 100644 --- a/status.qc +++ b/status.qc @@ -386,15 +386,25 @@ string(entity pl) DisguiseToString = if (pl.disguise_team) { team = strcat(team, "("); team = strcat(team, TeamToString(pl.disguise_team)); - team = strcat(team, ") "); + if (!pl.queue_skin) + team = strcat(team, ") "); + } else if (pl.queue_team) { + team = strcat(team, "("); + team = strcat(team, TeamToString(pl.queue_team)); + team = strcat(team, " "); } else if (pl.undercover_team) { team = strcat(team, TeamToString(pl.undercover_team)); team = strcat(team, " "); } if (pl.disguise_skin) { - skin = strcat(skin, "("); + if (!pl.queue_team) + skin = strcat(skin, "("); skin = strcat(skin, ClassToString(pl.disguise_skin)); skin = strcat(skin, ")"); + } else if (pl.queue_skin) { + skin = strcat(skin, " "); + skin = strcat(skin, ClassToString(pl.queue_skin)); + skin = strcat(skin, ")"); } else if (pl.undercover_skin) { skin = strcat(skin, ClassToString(pl.undercover_skin)); } diff --git a/tforthlp.qc b/tforthlp.qc index 251906d4..76d566e3 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -118,6 +118,20 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); TeamFortress_Alias("voterace", TF_VOTERACE, 0); TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); + TeamFortress_Alias("dreset", TF_DISGUISE_RESET, 0); + TeamFortress_Alias("dscout", TF_DISGUISE_SCOUT, 0); + TeamFortress_Alias("dsniper", TF_DISGUISE_SNIPER, 0); + TeamFortress_Alias("dsoldier", TF_DISGUISE_SOLDIER, 0); + TeamFortress_Alias("ddemoman", TF_DISGUISE_DEMOMAN, 0); + TeamFortress_Alias("dmedic", TF_DISGUISE_MEDIC, 0); + TeamFortress_Alias("dhwguy", TF_DISGUISE_HWGUY, 0); + TeamFortress_Alias("dpyro", TF_DISGUISE_PYRO, 0); + TeamFortress_Alias("dengineer", TF_DISGUISE_ENGINEER, 0); + TeamFortress_Alias("dblue", TF_DISGUISE_BLUE, 0); + TeamFortress_Alias("dred", TF_DISGUISE_RED, 0); + TeamFortress_Alias("dyellow", TF_DISGUISE_YELLOW, 0); + TeamFortress_Alias("dgreen", TF_DISGUISE_GREEN, 0); + TeamFortress_Alias("denemy", TF_DISGUISE_ENEMY, 0); } else if (self.motd == 55) { TeamFortress_Alias("flaginfo", FLAG_INFO, 0); TeamFortress_Alias("maphelp", TF_HELP_MAP, 0); diff --git a/weapons.qc b/weapons.qc index e42fd426..452ae1c9 100644 --- a/weapons.qc +++ b/weapons.qc @@ -52,7 +52,7 @@ void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; void (float zoom_in) Sniper_ZoomAdjust; void () TeamFortress_StatusQuery; -void () TeamFortress_SpyGoUndercover; +void () CF_Spy_GoUndercover; void () TeamFortress_DetpackMenu; void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; @@ -2180,7 +2180,7 @@ void () ImpulseCommands = { if (self.impulse == TF_WEAPLAST) { if (self.playerclass == PC_SPY && self.is_undercover == 2) - TeamFortress_SpyGoUndercover(); + CF_Spy_GoUndercover(); } if (!self.is_feigning) { @@ -2252,7 +2252,7 @@ void () ImpulseCommands = { else if (self.impulse == TF_GRENADE_SWITCH) TeamFortress_GrenadeSwitch(); else if (self.impulse == TF_ID) - CF_Identify(); + CF_Identify(self); else if (self.impulse == TF_SHOW_IDS) TeamFortress_ShowIDs(); else if ((self.playerclass != 0) && (self.impulse == TF_DROPFLAG)) @@ -2272,13 +2272,47 @@ void () ImpulseCommands = { else if ((self.impulse == 197) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_teleporter_entrance"); else if ((self.impulse == TF_SPY_SPY) && (self.playerclass == PC_SPY)) - TeamFortress_SpyGoUndercover(); + CF_Spy_GoUndercover(); else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) CF_Spy_FeignDeath(0); else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) CF_Spy_FeignDeath(1); - else if ((self.impulse == TF_DEMOMAN_DETPACK) && + else if (self.impulse == TF_DISGUISE_RESET && self.playerclass == PC_SPY) { + CF_Spy_ChangeSkin(self, 8); + CF_Spy_ChangeColor(self, self.team_no); + } else if (self.impulse == TF_DISGUISE_SCOUT && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 1); + else if (self.impulse == TF_DISGUISE_SNIPER && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 2); + else if (self.impulse == TF_DISGUISE_SOLDIER && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 3); + else if (self.impulse == TF_DISGUISE_DEMOMAN && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 4); + else if (self.impulse == TF_DISGUISE_MEDIC && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 5); + else if (self.impulse == TF_DISGUISE_HWGUY && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 6); + else if (self.impulse == TF_DISGUISE_PYRO && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 7); + else if (self.impulse == TF_DISGUISE_ENGINEER && self.playerclass == PC_SPY) + CF_Spy_ChangeSkin(self, 9); + else if (self.impulse == TF_DISGUISE_BLUE && self.playerclass == PC_SPY) + CF_Spy_ChangeColor(self, 1); + else if (self.impulse == TF_DISGUISE_RED && self.playerclass == PC_SPY) + CF_Spy_ChangeColor(self, 2); + else if (self.impulse == TF_DISGUISE_YELLOW && self.playerclass == PC_SPY) + CF_Spy_ChangeColor(self, 3); + else if (self.impulse == TF_DISGUISE_GREEN && self.playerclass == PC_SPY) + CF_Spy_ChangeColor(self, 4); + else if (self.impulse == TF_DISGUISE_ENEMY && self.playerclass == PC_SPY) { + if (number_of_teams > 2) + Menu_Spy_Color(); + else if (self.team_no == 1) + CF_Spy_ChangeColor(self, 2); + else + CF_Spy_ChangeColor(self, 1); + } else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); else if ((self.impulse == TF_ENGINEER_BUILD) && @@ -2314,7 +2348,7 @@ void () PreMatchImpulses = { if (self.impulse == TF_INVENTORY) TeamFortress_Inventory(); else if (self.impulse == TF_ID) - CF_Identify(); + CF_Identify(self); else if (self.impulse == FLAG_INFO) { if (CTF_Map == TRUE) TeamFortress_CTF_FlagInfo(); @@ -2437,7 +2471,7 @@ void () W_WeaponFrame = { else if (self.playerclass == PC_SCOUT) Menu_Scout(); else if (self.playerclass == PC_SPY) - TeamFortress_SpyGoUndercover(); + CF_Spy_GoUndercover(); else if (self.playerclass == PC_DEMOMAN) TeamFortress_DetpackMenu(); From aeb50acf22969d509bcef7487b7444357423d579 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 18:58:52 +0200 Subject: [PATCH 0181/2474] Implement last disguise (closes #114) --- defs.h | 1 + menu.qc | 8 ++++++-- qw.qc | 2 ++ spy.qc | 11 +++++++++++ tforthlp.qc | 1 + 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/defs.h b/defs.h index 5da7d1fd..d4b71d3b 100644 --- a/defs.h +++ b/defs.h @@ -422,6 +422,7 @@ #define TF_DISGUISE_YELLOW 131 #define TF_DISGUISE_GREEN 132 #define TF_DISGUISE_ENEMY 133 +#define TF_DISGUISE_LAST 134 // Information impulses #define TF_INVENTORY 135 diff --git a/menu.qc b/menu.qc index 699e24cd..3d5773bc 100644 --- a/menu.qc +++ b/menu.qc @@ -62,6 +62,7 @@ void (float inp) Menu_Scout_Input; void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; void (float inp) Menu_Spy_Color_Input; +void () CF_Spy_DisguiseLast; void () Menu_Demoman; void () Menu_Demoman_Cancel; @@ -349,7 +350,7 @@ void (float inp) Menu_Spy_Input = { if (inp == 1) { Menu_Spy_Skin(); } else if (inp == 2) { - Menu_Spy_Color(); + CF_Spy_DisguiseLast(); } else if (inp == 3) { CF_Spy_FeignDeath(1); if (self.is_feigning) { @@ -363,7 +364,7 @@ void (float inp) Menu_Spy_Input = { void () Menu_Spy = { local string s_action = "Action:\n\n"; local string s_skin = "“‘ Disguise \n"; - local string s_color = "”‘ Change color \n"; + local string s_last = "”‘ Last disguise \n"; local string s_feign, s_reset; local string s_nothing = "\n—‘ Nothing "; @@ -371,6 +372,9 @@ void () Menu_Spy = { return; } + if (!self.last_skin && !self.last_team) + s_last = "\n"; + if (self.is_feigning) s_feign = "•‘ Stop feigning \n"; else diff --git a/qw.qc b/qw.qc index cb2029c0..b8a513b0 100644 --- a/qw.qc +++ b/qw.qc @@ -50,8 +50,10 @@ typedef void (float) f_void_float; .float pipecooldown; // Time when detpipe command can be issued .float disguise_skin; // The skin the spy is changing to .float queue_skin; // The skin the spy will change to after team disguise is finished +.float last_skin; // The last skin the spy disguised as .float disguise_team; // The team the spy is changing to .float queue_team; // The team the spy will change to after skin disguise is finished +.float last_team; // The last team the spy disguised as .float feign_areachecked; // TRUE if area around spy has been checked for entities when feigned .float fragstreak; // Frag streak .float caps; // Caps during this game diff --git a/spy.qc b/spy.qc index 8af63889..7e5c7c2f 100644 --- a/spy.qc +++ b/spy.qc @@ -601,6 +601,15 @@ void () CF_Spy_GoUndercover = { }; +void () CF_Spy_DisguiseLast = { + if (self.last_skin) { + CF_Spy_ChangeSkin(self, self.last_skin); + } + if (self.last_team) { + CF_Spy_ChangeColor(self, self.last_team); + } +}; + void () CF_Spy_UndercoverThink = { local float f_team_color; local string s_team, s_class; @@ -628,6 +637,7 @@ void () CF_Spy_UndercoverThink = { if (self.skin) { self.owner.undercover_skin = self.skin; + self.owner.last_skin = self.skin; self.owner.disguise_skin = 0; self.owner.queue_skin = 0; self.owner.is_undercover = 1; @@ -643,6 +653,7 @@ void () CF_Spy_UndercoverThink = { } else if (self.team) { self.owner.undercover_team = self.team; + self.owner.last_team = self.team; // tell client to change color f_team_color = TeamFortress_TeamGetColor(self.team) - 1; diff --git a/tforthlp.qc b/tforthlp.qc index 76d566e3..c9a0ddaa 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -132,6 +132,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dyellow", TF_DISGUISE_YELLOW, 0); TeamFortress_Alias("dgreen", TF_DISGUISE_GREEN, 0); TeamFortress_Alias("denemy", TF_DISGUISE_ENEMY, 0); + TeamFortress_Alias("dlast", TF_DISGUISE_LAST, 0); } else if (self.motd == 55) { TeamFortress_Alias("flaginfo", FLAG_INFO, 0); TeamFortress_Alias("maphelp", TF_HELP_MAP, 0); From 67bb4262a4a0a360a37a9292c322988049dbf328 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 19:07:41 +0200 Subject: [PATCH 0182/2474] Cosmetic fixes for Menu_Spy_Input() --- menu.qc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/menu.qc b/menu.qc index 3d5773bc..b104669f 100644 --- a/menu.qc +++ b/menu.qc @@ -336,14 +336,12 @@ void () Menu_Scout = { void (float inp) Menu_Spy_Input = { if ((inp == 1) || (inp == 2)) { - if (self.effects & (8 | 4)) { - sprint(self, PRINT_HIGH, - "You cannot go undercover while glowing\n"); + if (self.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) { + sprint(self, PRINT_HIGH, "You cannot go undercover while glowing\n"); return; } - if (self.is_unabletospy == 1) { - sprint(self, PRINT_HIGH, - "You cannot go undercover right now\n"); + if (self.is_unabletospy) { + sprint(self, PRINT_HIGH, "You cannot go undercover right now\n"); return; } } From a50fd0a05c7fb369cce5216c29f8b40587426605 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 19:17:27 +0200 Subject: [PATCH 0183/2474] Don't show your own team in disguise list --- menu.qc | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/menu.qc b/menu.qc index b104669f..eb724116 100644 --- a/menu.qc +++ b/menu.qc @@ -430,7 +430,7 @@ void (float inp) Menu_Spy_Color_Input = { Menu_Spy_Color(); else if (inp == 3 && color == 12) Menu_Spy_Color(); - else if (inp == 4 && color == 3) + else if (inp == 4 && color == 11) Menu_Spy_Color(); else if (inp > 0 && inp <= number_of_teams) CF_Spy_ChangeColor(self, inp); @@ -449,15 +449,22 @@ void () Menu_Spy_Color = { sprint(self, PRINT_HIGH, "No color changing allowed in deathmatch\n"); return; } + + // don't display your own team + if (color == 13) + s_blue = "\n"; + else if (color == 4) + s_red = "\n"; + else if (color == 12) + s_yellow = "\n"; + else if (color == 11) + s_green = "\n"; + self.menu_input = nil; if (number_of_teams == 1) sprint(self, PRINT_HIGH, "There is no other team\n"); - else if (number_of_teams == 2) { - if (color == 4) - Status_Menu(self, Menu_Spy_Color_Input, s_disguise, s_blue, "\n", s_nothing, "\n\n"); - else - Status_Menu(self, Menu_Spy_Color_Input, s_disguise, "\n", s_red, s_nothing, "\n\n"); - } + else if (number_of_teams == 2) + Status_Menu(self, Menu_Spy_Color_Input, s_disguise, s_blue, s_red, s_nothing, "\n\n"); else if (number_of_teams == 3) Status_Menu(self, Menu_Spy_Color_Input, s_disguise, s_blue, s_red, s_yellow, s_nothing, "\n"); else From 33cf7c2d9b41f63d841c77d8e1b25b91b32c3db2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 19:22:30 +0200 Subject: [PATCH 0184/2474] Hide spy from disguise list if not disguised --- menu.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/menu.qc b/menu.qc index eb724116..d11104fb 100644 --- a/menu.qc +++ b/menu.qc @@ -418,6 +418,9 @@ void () Menu_Spy_Skin = { local string s_engineer = "›‘ Engineer \n"; local string s_nothing = "\n’‘ Nothing \n"; + if (!self.undercover_skin) + s_spy = "\n"; + Status_Menu(self, Menu_Spy_Skin_Input, s_disguise, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_nothing); }; From abde852dafc71880c9f4864aa5d3dfef0226e124 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 19:59:02 +0200 Subject: [PATCH 0185/2474] Print proper disguise messages when cancelling an ongoing disguise --- spy.qc | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/spy.qc b/spy.qc index 7e5c7c2f..e98d7b40 100644 --- a/spy.qc +++ b/spy.qc @@ -531,6 +531,7 @@ void (float issilent) CF_Spy_FeignDeath = { void () CF_Spy_GoUndercover = { local entity e_timer; + local string s_class, s_team; if (self.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) { sprint(self, PRINT_MEDIUM, "You cannot disguise while glowing\n"); @@ -580,11 +581,33 @@ void () CF_Spy_GoUndercover = { } else { - sprint(self, PRINT_HIGH, "You stop going undercover\n"); + // set undercover class if spy had the time to change class + if (self.undercover_skin) + s_class = TeamFortress_GetClassName(self.undercover_skin); + else + s_class = "Spy"; + + // set undercover team if spy had the time to change team + if (self.undercover_team) + s_team = TeamFortress_TeamGetColorString(self.undercover_team); + else + s_team = TeamFortress_TeamGetColorString(self.team_no); + + // show what's left of the disguise + if (self.undercover_skin || self.undercover_team) { + sprint(self, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); + self.is_undercover = 1; + self.last_skin = self.undercover_skin; + self.last_team = self.undercover_team; + } else { + sprint(self, PRINT_HIGH, "You stop going undercover\n"); + self.is_undercover = 0; + } - self.is_undercover = 0; self.disguise_skin = 0; self.disguise_team = 0; + self.queue_skin = 0; + self.queue_team = 0; // remove disguise timers belonging to self e_timer = find(world, classname, "spytimer"); @@ -597,6 +620,8 @@ void () CF_Spy_GoUndercover = { } } + Status_Refresh(self); + } }; @@ -646,7 +671,10 @@ void () CF_Spy_UndercoverThink = { if (self.owner.queue_team) { CF_Spy_ChangeColor(self.owner, self.owner.queue_team); } else { - s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); + if (self.owner.undercover_team) + s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); + else + s_team = TeamFortress_TeamGetColorString(self.owner.team_no); s_class = TeamFortress_GetClassName(self.owner.undercover_skin); sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); } @@ -702,6 +730,7 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { sprint(pe_player, PRINT_HIGH, "Skin reset\n"); pe_player.undercover_skin = 0; pe_player.disguise_skin = 0; + pe_player.queue_skin = 0; TeamFortress_SetSkin(pe_player); if (!pe_player.undercover_team) pe_player.is_undercover = 0; @@ -753,6 +782,7 @@ void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { pe_player.immune_to_check = time + 10; pe_player.undercover_team = 0; pe_player.disguise_team = 0; + pe_player.queue_team = 0; stuffcmd(pe_player, "color "); stuffcmd(pe_player, ftos(f_team_color)); stuffcmd(pe_player, "\n"); From 0919a41748af96af07999d22d3bd0f9ca1d16095 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 19:59:23 +0200 Subject: [PATCH 0186/2474] Add dlast alias for last disguise --- weapons.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 452ae1c9..ba58d5a2 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2312,7 +2312,9 @@ void () ImpulseCommands = { CF_Spy_ChangeColor(self, 2); else CF_Spy_ChangeColor(self, 1); - } else if ((self.impulse == TF_DEMOMAN_DETPACK) && + } else if (self.impulse == TF_DISGUISE_LAST && self.playerclass == PC_SPY) + CF_Spy_DisguiseLast(); + else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); else if ((self.impulse == TF_ENGINEER_BUILD) && From 659830884eb4a422f997c56b5fcc443bb99213ca Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 21:52:08 +0200 Subject: [PATCH 0187/2474] Allow Spy to open Spy menu while disguising --- menu.qc | 46 ++++++++++++++----- spy.qc | 132 ++++++++++++++++++++++++++--------------------------- weapons.qc | 15 +++--- 3 files changed, 109 insertions(+), 84 deletions(-) diff --git a/menu.qc b/menu.qc index d11104fb..dddf4273 100644 --- a/menu.qc +++ b/menu.qc @@ -5,6 +5,8 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin; void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor; void (float issilent) CF_Spy_FeignDeath; +void () CF_Spy_Invisible; +void () CF_Spy_DisguiseStop; void (entity spy) Spy_RemoveDisguise; @@ -54,7 +56,7 @@ string (float pc, float tno) TeamFortress_ClassGetNoPlayersString; void () Menu_Drop; void () PlayerObserverMode; void () Menu_Scout; -void () Menu_Spy; +void (entity pe_player) Menu_Spy; void () Menu_Spy_Skin; void () Menu_Spy_Color; @@ -346,54 +348,74 @@ void (float inp) Menu_Spy_Input = { } } if (inp == 1) { - Menu_Spy_Skin(); - } else if (inp == 2) { + if (invis_only) + CF_Spy_Invisible(); + else if (self.is_undercover == 2) + CF_Spy_DisguiseStop(); + else + Menu_Spy_Skin(); + } else if (inp == 2 && !invis_only) { CF_Spy_DisguiseLast(); } else if (inp == 3) { CF_Spy_FeignDeath(1); if (self.is_feigning) { - Menu_Spy(); + Menu_Spy(self); } } else if (inp == 4) { Spy_RemoveDisguise(self); } }; -void () Menu_Spy = { +void (entity pe_player) Menu_Spy = { local string s_action = "Action:\n\n"; local string s_skin = "“‘ Disguise \n"; local string s_last = "”‘ Last disguise \n"; local string s_feign, s_reset; local string s_nothing = "\n—‘ Nothing "; - if (self.effects & (8 | 4) || self.is_unabletospy == 1) { + if (pe_player.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT) || pe_player.is_unabletospy == 1) { return; } - if (!self.last_skin && !self.last_team) + if (invis_only) + s_skin = "“‘ Go invisible \n"; + else if (pe_player.is_undercover == 2) + s_skin = "“‘ Stop disguising \n"; + + if ((!pe_player.last_skin && !pe_player.last_team) || invis_only) s_last = "\n"; - if (self.is_feigning) + if (pe_player.is_feigning) s_feign = "•‘ Stop feigning \n"; else s_feign = "•‘ Start feigning (silent)\n"; - if (self.undercover_team && self.undercover_skin) + if (pe_player.undercover_team && pe_player.undercover_skin) s_reset = "–‘ Reset disguise \n"; - else if (self.undercover_team) + else if (pe_player.undercover_team) s_reset = "–‘ Reset color \n"; - else if (self.undercover_skin) + else if (pe_player.undercover_skin) s_reset = "–‘ Reset skin \n"; else s_reset = "\n"; - Status_Menu(self, Menu_Spy_Input, s_action, s_skin, s_last, s_feign, s_reset, s_nothing); + Status_Menu(pe_player, Menu_Spy_Input, s_action, s_skin, s_last, s_feign, s_reset, s_nothing); }; void (float inp) Menu_Spy_Skin_Input = { if (inp == 0) return; + if (self.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) { + sprint(self, PRINT_MEDIUM, "You cannot disguise while glowing\n"); + return; + } + + if (self.is_unabletospy) { + sprint(self, PRINT_HIGH, "You cannot go undercover right now\n"); + return; + } + CF_Spy_ChangeSkin(self, inp); if (number_of_teams > 2) diff --git a/spy.qc b/spy.qc index e98d7b40..6351ec7e 100644 --- a/spy.qc +++ b/spy.qc @@ -529,101 +529,99 @@ void (float issilent) CF_Spy_FeignDeath = { } }; -void () CF_Spy_GoUndercover = { +void () CF_Spy_Invisible = { local entity e_timer; - local string s_class, s_team; if (self.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) { - sprint(self, PRINT_MEDIUM, "You cannot disguise while glowing\n"); + sprint(self, PRINT_MEDIUM, "You cannot become invisible while glowing\n"); return; } if (self.is_unabletospy) { - sprint(self, PRINT_HIGH, "You cannot go undercover right now\n"); + sprint(self, PRINT_HIGH, "You cannot become invisible right now\n"); return; } - if (invis_only == 1) { + if (self.is_undercover == 1 || self.items & IT_INVISIBILITY) { - if (self.is_undercover == 1 || self.items & IT_INVISIBILITY) { + self.items = self.items - IT_INVISIBILITY; + self.invisible_finished = 0; + self.invisible_time = 0; + self.is_undercover = 0; + self.modelindex = modelindex_player; - self.items = self.items - IT_INVISIBILITY; - self.invisible_finished = 0; - self.invisible_time = 0; - self.is_undercover = 0; - self.modelindex = modelindex_player; + } else if (self.is_undercover == 2) { - } else if (self.is_undercover == 2) { + sprint(self, PRINT_HIGH, "You become visible again\n"); - sprint(self, PRINT_HIGH, "You stop going undercover\n"); + self.is_undercover = 0; - self.is_undercover = 0; + } else if (self.ammo_cells > 1) { - } else if (self.ammo_cells > 1) { + sprint(self, PRINT_HIGH, "Going invisible...\n"); - sprint(self, PRINT_HIGH, "Going undercover...\n"); + self.is_undercover = 2; - self.is_undercover = 2; + // create a timer for 4 seconds + e_timer = spawn(); + e_timer.classname = "spytimer"; + e_timer.owner = self; + e_timer.think = CF_Spy_UndercoverThink; + e_timer.nextthink = time + 4; + } - // create a timer for 4 seconds - e_timer = spawn(); - e_timer.classname = "spytimer"; - e_timer.owner = self; - e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 4; - } + Status_Refresh(self); - Status_Refresh(self); +}; - } else if (self.is_undercover != 2) { +void () CF_Spy_DisguiseStop = { + local entity e_timer; + local string s_class, s_team; - Menu_Spy(); + if (!self.is_undercover) + return; - } else { + // set undercover class if spy had the time to change class + if (self.undercover_skin) + s_class = TeamFortress_GetClassName(self.undercover_skin); + else + s_class = "Spy"; - // set undercover class if spy had the time to change class - if (self.undercover_skin) - s_class = TeamFortress_GetClassName(self.undercover_skin); - else - s_class = "Spy"; + // set undercover team if spy had the time to change team + if (self.undercover_team) + s_team = TeamFortress_TeamGetColorString(self.undercover_team); + else + s_team = TeamFortress_TeamGetColorString(self.team_no); + + // show what's left of the disguise + if (self.undercover_skin || self.undercover_team) { + sprint(self, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); + self.is_undercover = 1; + self.last_skin = self.undercover_skin; + self.last_team = self.undercover_team; + } else { + sprint(self, PRINT_HIGH, "You stop going undercover\n"); + self.is_undercover = 0; + } - // set undercover team if spy had the time to change team - if (self.undercover_team) - s_team = TeamFortress_TeamGetColorString(self.undercover_team); - else - s_team = TeamFortress_TeamGetColorString(self.team_no); - - // show what's left of the disguise - if (self.undercover_skin || self.undercover_team) { - sprint(self, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); - self.is_undercover = 1; - self.last_skin = self.undercover_skin; - self.last_team = self.undercover_team; + self.disguise_skin = 0; + self.disguise_team = 0; + self.queue_skin = 0; + self.queue_team = 0; + + // remove disguise timers belonging to self + e_timer = find(world, classname, "spytimer"); + while (e_timer != world) { + if (e_timer.owner == self) { + dremove(e_timer); + e_timer = find(world, classname, "spytimer"); } else { - sprint(self, PRINT_HIGH, "You stop going undercover\n"); - self.is_undercover = 0; + e_timer = find(e_timer, classname, "spytimer"); } - - self.disguise_skin = 0; - self.disguise_team = 0; - self.queue_skin = 0; - self.queue_team = 0; - - // remove disguise timers belonging to self - e_timer = find(world, classname, "spytimer"); - while (e_timer != world) { - if (e_timer.owner == self) { - dremove(e_timer); - e_timer = find(world, classname, "spytimer"); - } else { - e_timer = find(e_timer, classname, "spytimer"); - } - } - - Status_Refresh(self); - } + Status_Refresh(self); + }; void () CF_Spy_DisguiseLast = { @@ -706,6 +704,8 @@ void () CF_Spy_UndercoverThink = { } Status_Refresh(self.owner); + if (self.owner.menu_input == Menu_Spy_Input) + Menu_Spy(self.owner); dremove(self); }; diff --git a/weapons.qc b/weapons.qc index ba58d5a2..7a3bda57 100644 --- a/weapons.qc +++ b/weapons.qc @@ -52,7 +52,7 @@ void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; void (float zoom_in) Sniper_ZoomAdjust; void () TeamFortress_StatusQuery; -void () CF_Spy_GoUndercover; +void () CF_Spy_DisguiseStop; void () TeamFortress_DetpackMenu; void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; @@ -2180,7 +2180,7 @@ void () ImpulseCommands = { if (self.impulse == TF_WEAPLAST) { if (self.playerclass == PC_SPY && self.is_undercover == 2) - CF_Spy_GoUndercover(); + CF_Spy_DisguiseStop(); } if (!self.is_feigning) { @@ -2271,9 +2271,12 @@ void () ImpulseCommands = { DestroyBuilding(self, "building_teleporter_exit"); else if ((self.impulse == 197) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_teleporter_entrance"); - else if ((self.impulse == TF_SPY_SPY) && (self.playerclass == PC_SPY)) - CF_Spy_GoUndercover(); - else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) + else if ((self.impulse == TF_SPY_SPY) && (self.playerclass == PC_SPY)) { + if (invis_only) + CF_Spy_Invisible(); + else + Menu_Spy_Skin(); + } else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) CF_Spy_FeignDeath(0); else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) @@ -2473,7 +2476,7 @@ void () W_WeaponFrame = { else if (self.playerclass == PC_SCOUT) Menu_Scout(); else if (self.playerclass == PC_SPY) - CF_Spy_GoUndercover(); + Menu_Spy(self); else if (self.playerclass == PC_DEMOMAN) TeamFortress_DetpackMenu(); From a4b82a5276a3e5eb4f86cecb9fff9526af23401c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 21:52:32 +0200 Subject: [PATCH 0188/2474] Shut down Spy menu when picking up enemy flag --- tfortmap.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tfortmap.qc b/tfortmap.qc index 57077112..15b047be 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1938,6 +1938,10 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { AP.disguise_team = 0; } + // disable spy menu + if (AP.menu_input == Menu_Spy_Input || AP.menu_input == Menu_Spy_Skin_Input || AP.menu_input == Menu_Spy_Color_Input) + AP.menu_input = nil; + Status_Refresh(AP); DoResults(Item, AP, 1); DoItemGroupWork(Item, AP); From e664086511c4b92316efb5aa7b9b893ccc7d451c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 22:01:13 +0200 Subject: [PATCH 0189/2474] Allow Engineer menu and 1-4 keys during building --- menu.qc | 8 ++++++++ weapons.qc | 19 +++++-------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/menu.qc b/menu.qc index dddf4273..feef6f30 100644 --- a/menu.qc +++ b/menu.qc @@ -537,6 +537,14 @@ void (float inp) Menu_Engineer_Input = { local float dismantle_dispenser; local entity te; + if (inp == 5) + return; + + if (self.is_building) { + Menu_Engineer(self); + return; + } + dismantle_sentrygun = 0; dismantle_dispenser = 0; diff --git a/weapons.qc b/weapons.qc index 7a3bda57..386fca50 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2181,6 +2181,9 @@ void () ImpulseCommands = { if (self.impulse == TF_WEAPLAST) { if (self.playerclass == PC_SPY && self.is_undercover == 2) CF_Spy_DisguiseStop(); + else if (self.playerclass == PC_ENGINEER && self.is_building) + TeamFortress_EngineerBuildStop(); + CycleWeaponLast(); } if (!self.is_feigning) { @@ -2194,18 +2197,6 @@ void () ImpulseCommands = { TeamFortress_PrimeThrowGrenade(2); } - if (self.is_building == 1) { - if (self.impulse >= 1 && self.impulse <= 5) { - TeamFortress_EngineerBuildStop(); - W_ChangeWeapon(self.impulse); - } else if (self.impulse == TF_WEAPNEXT - || self.impulse == TF_WEAPPREV - || self.impulse == TF_WEAPLAST) { - TeamFortress_EngineerBuildStop(); - W_ChangeWeapon(self.impulse); - } - } - if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); @@ -2472,7 +2463,7 @@ void () W_WeaponFrame = { if (self.impulse == 5) { if (self.playerclass == PC_ENGINEER) - TeamFortress_EngineerBuild(); + Menu_Engineer(self); else if (self.playerclass == PC_SCOUT) Menu_Scout(); else if (self.playerclass == PC_SPY) @@ -2517,7 +2508,7 @@ void () W_WeaponFrame = { } // slot 1-4 binds - if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady(self)) { + if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady(self) && !self.is_building) { // load weapon state if current state doesn't match stored state if (!W_WeaponState_Check(self)) From cbe3b9838fd12d9ae113a8735c14a135ee7c2773 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 22:32:23 +0200 Subject: [PATCH 0190/2474] Update status bar immediately when disguising --- spy.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spy.qc b/spy.qc index 6351ec7e..a4c035f6 100644 --- a/spy.qc +++ b/spy.qc @@ -758,6 +758,8 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { e_timer.nextthink = time + 4; e_timer.skin = pf_class; TeamFortress_SetSkin(pe_player); + + Status_Refresh(pe_player); }; void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { @@ -812,6 +814,8 @@ void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { e_timer.think = CF_Spy_UndercoverThink; e_timer.nextthink = time + 4; e_timer.team = pf_team_no; + + Status_Refresh(pe_player); }; void (entity spy) TeamFortress_SpyCalcName = { From 23e46b0f04c148f4cba54c12ce84faf79534bdfe Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 22:32:46 +0200 Subject: [PATCH 0191/2474] Fix typo which caused weaplast to stop functioning --- weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 386fca50..74e648e6 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2181,9 +2181,10 @@ void () ImpulseCommands = { if (self.impulse == TF_WEAPLAST) { if (self.playerclass == PC_SPY && self.is_undercover == 2) CF_Spy_DisguiseStop(); - else if (self.playerclass == PC_ENGINEER && self.is_building) + else if (self.playerclass == PC_ENGINEER && self.is_building) { TeamFortress_EngineerBuildStop(); CycleWeaponLast(); + } } if (!self.is_feigning) { From 17e53f3b50c243d6ad7e70084acfef0c1295188e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 28 Aug 2014 22:34:37 +0200 Subject: [PATCH 0192/2474] Don't change weapon when canceling disguise with weaplast --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 74e648e6..22b8f56a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2479,7 +2479,7 @@ void () W_WeaponFrame = { if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL) return; - if (self.impulse == TF_WEAPLAST) { + if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { // change to last weapon now if (WeaponReady(self)) From ede456287708fcacb9ad07f5f73f99d0c856592f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 08:41:44 +0200 Subject: [PATCH 0193/2474] Fix crash when detonating buildings (fixes #160) --- combat.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/combat.qc b/combat.qc index 1f81a1ac..0a56ed17 100644 --- a/combat.qc +++ b/combat.qc @@ -53,6 +53,9 @@ float (entity targ, entity inflictor) CanDamage = { void (entity targ, entity attacker) Killed = { local entity oself; + if (attacker == world) + attacker = targ; + oself = self; self = targ; if (self.health < -99) From b5a292bb41727d2269610e63b161b91276e6d546 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 09:20:35 +0200 Subject: [PATCH 0194/2474] Check for autoid setinfo on every spawn --- client.qc | 13 ++----------- qw.qc | 1 + tfort.qc | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/client.qc b/client.qc index 9f8a93c8..2b6ee2c3 100644 --- a/client.qc +++ b/client.qc @@ -36,7 +36,6 @@ void () PreMatch_Think; void () DumpClanScores; -void () AutoId; void (entity p) SetTeamName; void () autokick_think; @@ -940,6 +939,7 @@ entity () SelectSpawnPoint = void () PlayerDie; void () TeamFortress_SetHealth; void () TeamFortress_SetEquipment; +void () TeamFortress_StartTimers; void () player_touch; // moves the client forward if spawn point is occupied @@ -964,7 +964,6 @@ void () PutClientInServer = { local float oldclass; local entity spot; local entity te; - local entity timer; self.touch = player_touch; self.classname = "player"; @@ -1041,6 +1040,7 @@ void () PutClientInServer = { TeamFortress_SetHealth(); TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); + TeamFortress_StartTimers(); stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); @@ -1133,15 +1133,6 @@ void () PutClientInServer = { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } - - // start autoid timer - if (stof(infokey(self, "ai"))) { - timer = spawn(); - timer.nextthink = time + 0.3; - timer.think = AutoId; - timer.owner = self; - timer.classname = "aitimer"; - } }; void () info_player_start = { diff --git a/qw.qc b/qw.qc index b8a513b0..26227e1f 100644 --- a/qw.qc +++ b/qw.qc @@ -55,6 +55,7 @@ typedef void (float) f_void_float; .float queue_team; // The team the spy will change to after skin disguise is finished .float last_team; // The last team the spy disguised as .float feign_areachecked; // TRUE if area around spy has been checked for entities when feigned +.float autoid_timer; // TRUE if player has an active autoid timer .float fragstreak; // Frag streak .float caps; // Caps during this game diff --git a/tfort.qc b/tfort.qc index 7de16f03..0c2a26d2 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2044,6 +2044,25 @@ void (entity Viewer, float pc, float rpc) TeamFortress_PrintClassName = { sprint(Viewer, PRINT_HIGH, "\n"); }; +void () TeamFortress_StartTimers = { + local entity timer; + + // start autoid timer + if (stof(infokey(self, "ai"))) { + if (!self.autoid_timer) { + timer = spawn(); + timer.nextthink = time + 0.3; + timer.think = AutoId; + timer.owner = self; + timer.classname = "aitimer"; + self.autoid_timer = 1; + } + } else if (self.autoid_timer) { + RemoveAutoIdTimer(); + self.autoid_timer = 0; + } +} + void () TeamFortress_RemoveTimers = { local entity te; From 449c5f753c22c280092cfeb7a59e63b1be0ff96b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 09:56:02 +0200 Subject: [PATCH 0195/2474] Don't allow spy to jump while feigned (fixes #141) --- client.qc | 1 + spy.qc | 1 + 2 files changed, 2 insertions(+) diff --git a/client.qc b/client.qc index 2b6ee2c3..7bba4faa 100644 --- a/client.qc +++ b/client.qc @@ -1509,6 +1509,7 @@ void () PlayerPreThink = { } else { self.feign_areachecked = 1; if (!(self.tfstate & TFSTATE_CANT_MOVE)) { + self.movetype = MOVETYPE_NONE; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } diff --git a/spy.qc b/spy.qc index a4c035f6..2281f263 100644 --- a/spy.qc +++ b/spy.qc @@ -404,6 +404,7 @@ void (float issilent) CF_Spy_FeignDeath = { W_SetCurrentAmmo(self); // allow spy to move again + self.movetype = MOVETYPE_WALK; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); From cb8edfc9f7afcba3e7e2aa1e217f61fb82d05dcd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 10:47:04 +0200 Subject: [PATCH 0196/2474] Show max health/ammo for Medic/Engineer on identify (closes #159) --- actions.qc | 37 +++++++++++++++++++++++++++---------- status.qc | 4 ++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/actions.qc b/actions.qc index 03116950..cc3026ea 100644 --- a/actions.qc +++ b/actions.qc @@ -112,8 +112,8 @@ void () TeamFortress_SaveMe = { void (entity pe_player) CF_Identify = { local vector v_source; - local string s_id_string, s_class = "", s_name = ""; - local float f_health = 0, f_armor = 0, f_friendly = 0, f_fakefriendly = 0; + local string s_id_string = "", s_class = "", s_name = ""; + local float f_health = 0, f_maxhealth = 0, f_armor = 0, f_maxarmor = 0, f_friendly = 0, f_fakefriendly = 0; v_source = pe_player.origin + v_forward * 10; v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; @@ -137,12 +137,16 @@ void (entity pe_player) CF_Identify = { s_name = trace_ent.netname; // set health if you're a medic - if (pe_player.playerclass == PC_MEDIC) + if (pe_player.playerclass == PC_MEDIC) { f_health = trace_ent.health; + f_maxhealth = trace_ent.max_health; + } // set armor if you're an engineer - else if (pe_player.playerclass == PC_ENGINEER) + else if (pe_player.playerclass == PC_ENGINEER) { f_armor = trace_ent.armorvalue; + f_maxarmor = trace_ent.maxarmor; + } // target is an enemy spy if (trace_ent.playerclass == PC_SPY && !f_friendly) { @@ -183,17 +187,30 @@ void (entity pe_player) CF_Identify = { } - // set name (+ health/armor) + // set name + health (if medic) if (f_health && (f_friendly || f_fakefriendly)) { - s_id_string = strcat(s_name, " ("); + + s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_health)); - s_id_string = strcat(s_id_string, " hp)\n"); + s_id_string = strcat(s_id_string, "/"); + s_id_string = strcat(s_id_string, ftos(f_maxhealth)); + s_id_string = strcat(s_id_string, " hp\n"); + + // set name + armor (if engineer) } else if (f_armor && (f_friendly || f_fakefriendly)) { - s_id_string = strcat(s_name, " ("); + + s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_armor)); - s_id_string = strcat(s_id_string, " armor)\n"); + s_id_string = strcat(s_id_string, "/"); + s_id_string = strcat(s_id_string, ftos(f_maxarmor)); + s_id_string = strcat(s_id_string, " armor\n"); + + // just set name (if other class) } else { - s_id_string = strcat(s_name, "\n"); + + s_id_string = strcat("\n", s_name); + s_id_string = strcat(s_id_string, "\n"); + } // set friendly/enemy diff --git a/status.qc b/status.qc index f144ffbe..1f59df68 100644 --- a/status.qc +++ b/status.qc @@ -117,7 +117,7 @@ void (entity pl) RefreshStatusBar = { height = floor(stof(infokey(pl, "sb"))); if (height > 300) height = 300; - height = height - pl.StatusStringLines - 6; + height = height - pl.StatusStringLines - 7; // no sbar can be displayed if (height <= 0 || pl.playerclass == PC_UNDEFINED) { @@ -235,7 +235,7 @@ void (entity pl) RefreshStatusBar = { if (pl.ident_string != string_null && time < pl.ident_time) { ident = strcat(pl.ident_string, "\n\n"); } else { - ident = "\n\n\n"; + ident = "\n\n\n\n"; } centerprint(pl, pl.StatusString, pad, ident, s1, s2, s3); From 78c6fdc93eddf3a5fe67d52ac7147bf9daff17f3 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 11:16:07 +0200 Subject: [PATCH 0197/2474] Make initialization of autoid more reliable --- qw.qc | 1 - tfort.qc | 15 +++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/qw.qc b/qw.qc index 26227e1f..b8a513b0 100644 --- a/qw.qc +++ b/qw.qc @@ -55,7 +55,6 @@ typedef void (float) f_void_float; .float queue_team; // The team the spy will change to after skin disguise is finished .float last_team; // The last team the spy disguised as .float feign_areachecked; // TRUE if area around spy has been checked for entities when feigned -.float autoid_timer; // TRUE if player has an active autoid timer .float fragstreak; // Frag streak .float caps; // Caps during this game diff --git a/tfort.qc b/tfort.qc index 0c2a26d2..2f3ad437 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2049,17 +2049,12 @@ void () TeamFortress_StartTimers = { // start autoid timer if (stof(infokey(self, "ai"))) { - if (!self.autoid_timer) { - timer = spawn(); - timer.nextthink = time + 0.3; - timer.think = AutoId; - timer.owner = self; - timer.classname = "aitimer"; - self.autoid_timer = 1; - } - } else if (self.autoid_timer) { RemoveAutoIdTimer(); - self.autoid_timer = 0; + timer = spawn(); + timer.nextthink = time + 0.3; + timer.think = AutoId; + timer.owner = self; + timer.classname = "aitimer"; } } From ccfc11d7f3008608ae6a1000b91550c68cded1e7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 11:34:21 +0200 Subject: [PATCH 0198/2474] Engineers now see health of friendly sentry guns (closes #158) --- actions.qc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/actions.qc b/actions.qc index cc3026ea..8ca8d549 100644 --- a/actions.qc +++ b/actions.qc @@ -113,7 +113,7 @@ void () TeamFortress_SaveMe = { void (entity pe_player) CF_Identify = { local vector v_source; local string s_id_string = "", s_class = "", s_name = ""; - local float f_health = 0, f_maxhealth = 0, f_armor = 0, f_maxarmor = 0, f_friendly = 0, f_fakefriendly = 0; + local float f_health = 0, f_maxhealth = 0, f_armor = 0, f_maxarmor = 0, f_friendly = 0, f_fakefriendly = 0, f_sentryhealth = 0, f_maxsentryhealth = 0; v_source = pe_player.origin + v_forward * 10; v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; @@ -180,9 +180,15 @@ void (entity pe_player) CF_Identify = { if (pe_player == trace_ent.real_owner) s_name = "Your sentry gun"; - else + else { s_name = strcat(trace_ent.real_owner.netname, "'s sentry gun"); + if (pe_player.team_no == trace_ent.team_no) { + f_sentryhealth = trace_ent.health; + f_maxsentryhealth = trace_ent.max_health; + } + } + s_class = ""; } @@ -205,6 +211,15 @@ void (entity pe_player) CF_Identify = { s_id_string = strcat(s_id_string, ftos(f_maxarmor)); s_id_string = strcat(s_id_string, " armor\n"); + // set name + health (if sentry + engineer) + } else if (f_maxsentryhealth) { + + s_id_string = strcat(s_name, "\n"); + s_id_string = strcat(s_id_string, ftos(floor(f_sentryhealth))); + s_id_string = strcat(s_id_string, "/"); + s_id_string = strcat(s_id_string, ftos(floor(f_maxsentryhealth))); + s_id_string = strcat(s_id_string, " health\n"); + // just set name (if other class) } else { From cd0247105d04f0a176cc9d048fb816689f4e9bd0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 11:35:02 +0200 Subject: [PATCH 0199/2474] Show armor on teammates (if engineer) even if 0 --- actions.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions.qc b/actions.qc index 8ca8d549..068d72ec 100644 --- a/actions.qc +++ b/actions.qc @@ -194,7 +194,7 @@ void (entity pe_player) CF_Identify = { } // set name + health (if medic) - if (f_health && (f_friendly || f_fakefriendly)) { + if (f_maxhealth && (f_friendly || f_fakefriendly)) { s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_health)); @@ -203,7 +203,7 @@ void (entity pe_player) CF_Identify = { s_id_string = strcat(s_id_string, " hp\n"); // set name + armor (if engineer) - } else if (f_armor && (f_friendly || f_fakefriendly)) { + } else if (f_maxarmor && (f_friendly || f_fakefriendly)) { s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_armor)); From cdd0589a515f2c5c3802986f9b7e50723d9173bd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 16:29:18 +0200 Subject: [PATCH 0200/2474] Add autoid options and load autoid settings every 5 seconds (closes #157) --- actions.qc | 23 ++++++++++++++++++++--- defs.h | 4 +++- qw.qc | 2 ++ spect.qc | 2 +- tfort.qc | 29 +++++++++++++++++++---------- tforthlp.qc | 2 ++ weapons.qc | 10 +++++++--- 7 files changed, 54 insertions(+), 18 deletions(-) diff --git a/actions.qc b/actions.qc index 068d72ec..73b0e54b 100644 --- a/actions.qc +++ b/actions.qc @@ -110,7 +110,7 @@ void () TeamFortress_SaveMe = { } }; -void (entity pe_player) CF_Identify = { +void (entity pe_player, float f_type) CF_Identify = { local vector v_source; local string s_id_string = "", s_class = "", s_name = ""; local float f_health = 0, f_maxhealth = 0, f_armor = 0, f_maxarmor = 0, f_friendly = 0, f_fakefriendly = 0, f_sentryhealth = 0, f_maxsentryhealth = 0; @@ -123,10 +123,27 @@ void (entity pe_player) CF_Identify = { // show as friendly if target is on your team or disguised as your team if (pe_player.team_no) { - if (pe_player.team_no == trace_ent.team_no) + + if (pe_player.team_no == trace_ent.team_no) { + + // ignore teammates if type is set to enemies only + if (f_type == 3) + return; + f_friendly = 1; - else if (pe_player.team_no == trace_ent.undercover_team) + + } else if (pe_player.team_no == trace_ent.undercover_team) { + + // ignore teammates if type is set to enemies only + if (f_type == 3) + return; + f_fakefriendly = 1; + + // ignore enemies if type is set to team only + } else if (f_type == 2) + return; + } // alive player is found diff --git a/defs.h b/defs.h index d4b71d3b..8363f348 100644 --- a/defs.h +++ b/defs.h @@ -495,7 +495,9 @@ #define TF_DISCARD 184 // ID Player impulse -#define TF_ID 185 +#define TF_ID 190 +#define TF_ID_TEAM 191 +#define TF_ID_ENEMY 192 // other impulses #define TF_SHOW_IDS 186 diff --git a/qw.qc b/qw.qc index b8a513b0..63f503ad 100644 --- a/qw.qc +++ b/qw.qc @@ -67,6 +67,8 @@ typedef void (float) f_void_float; // Identify variables .string ident_string; // Status bar string for identify .float ident_time; // The time when last identify found a player +.float autoid_type; // 0 = ignore noone, 1 = ignore teammates, 2 = ignore enemies +.float autoid_time; // Time when autoid settings were last checked // Playerclass handling variables .float maxammo_shells; diff --git a/spect.qc b/spect.qc index effd6dcb..8f455eb3 100644 --- a/spect.qc +++ b/spect.qc @@ -76,7 +76,7 @@ void () SpectatorImpulseCommand = { } } else if (self.impulse == TF_ID) - CF_Identify(self); + CF_Identify(self, self.autoid_type); else if (self.impulse == TF_HELP_MAP) diff --git a/tfort.qc b/tfort.qc index 2f3ad437..a4eb5656 100644 --- a/tfort.qc +++ b/tfort.qc @@ -7,12 +7,24 @@ void () TeamFortress_ExplodePerson; void () TeamFortress_Regenerate; void () TeamFortress_CheckforCheats; void () TeamFortress_RegenerateCells; -void (entity pe_player) CF_Identify; +void (entity pe_player, float f_ignore) CF_Identify; float () CloseToSpawnPoint; void () AutoId = { + // ready autoid settings every 5 seconds + if (time > self.owner.autoid_time) { + self.owner.autoid_type = stof(infokey(self.owner, "ai")); + self.owner.autoid_time = time + 5; + } + + // try autoid again in 5 seconds if currently turned off + if (!self.owner.autoid_type) { + self.nextthink = time + 5; + return; + } + if (time > self.ident_time || !self.ident_time) { // remove ident string from memory @@ -21,7 +33,7 @@ void () AutoId = { self.ident_string = string_null; } - CF_Identify(self.owner); + CF_Identify(self.owner, self.owner.autoid_type); } self.nextthink = time + 0.1; @@ -2048,14 +2060,11 @@ void () TeamFortress_StartTimers = { local entity timer; // start autoid timer - if (stof(infokey(self, "ai"))) { - RemoveAutoIdTimer(); - timer = spawn(); - timer.nextthink = time + 0.3; - timer.think = AutoId; - timer.owner = self; - timer.classname = "aitimer"; - } + timer = spawn(); + timer.nextthink = time + 0.3; + timer.think = AutoId; + timer.owner = self; + timer.classname = "aitimer"; } void () TeamFortress_RemoveTimers = { diff --git a/tforthlp.qc b/tforthlp.qc index c9a0ddaa..68f0928d 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -114,6 +114,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); TeamFortress_Alias("discard", TF_DISCARD, 0); TeamFortress_Alias("id", TF_ID, 0); + TeamFortress_Alias("idteam", TF_ID_TEAM, 0); + TeamFortress_Alias("idenemy", TF_ID_ENEMY, 0); TeamFortress_Alias("votenext", TF_VOTENEXT, 0); TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); TeamFortress_Alias("voterace", TF_VOTERACE, 0); diff --git a/weapons.qc b/weapons.qc index 22b8f56a..7f60b7cf 100644 --- a/weapons.qc +++ b/weapons.qc @@ -45,7 +45,7 @@ void (float zoom_to) Sniper_Zoom; void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; -void (entity pe_player) CF_Identify; +void (entity pe_player, float f_ignore) CF_Identify; void () TeamFortress_ReloadCurrentWeapon; void (float slot) TeamFortress_ReloadSlot; void () TeamFortress_ReloadNext; @@ -2244,7 +2244,11 @@ void () ImpulseCommands = { else if (self.impulse == TF_GRENADE_SWITCH) TeamFortress_GrenadeSwitch(); else if (self.impulse == TF_ID) - CF_Identify(self); + CF_Identify(self, 1); + else if (self.impulse == TF_ID_TEAM) + CF_Identify(self, 2); + else if (self.impulse == TF_ID_ENEMY) + CF_Identify(self, 3); else if (self.impulse == TF_SHOW_IDS) TeamFortress_ShowIDs(); else if ((self.playerclass != 0) && (self.impulse == TF_DROPFLAG)) @@ -2345,7 +2349,7 @@ void () PreMatchImpulses = { if (self.impulse == TF_INVENTORY) TeamFortress_Inventory(); else if (self.impulse == TF_ID) - CF_Identify(self); + CF_Identify(self, 0); else if (self.impulse == FLAG_INFO) { if (CTF_Map == TRUE) TeamFortress_CTF_FlagInfo(); From 92074c86016aa60ab4455258fdcb8423fa120f16 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 29 Aug 2014 16:33:58 +0200 Subject: [PATCH 0201/2474] Typo fix --- tfort.qc | 2 +- weapons.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index a4eb5656..00a6688f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -7,7 +7,7 @@ void () TeamFortress_ExplodePerson; void () TeamFortress_Regenerate; void () TeamFortress_CheckforCheats; void () TeamFortress_RegenerateCells; -void (entity pe_player, float f_ignore) CF_Identify; +void (entity pe_player, float f_type) CF_Identify; float () CloseToSpawnPoint; diff --git a/weapons.qc b/weapons.qc index 7f60b7cf..eddc1b8f 100644 --- a/weapons.qc +++ b/weapons.qc @@ -45,7 +45,7 @@ void (float zoom_to) Sniper_Zoom; void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; -void (entity pe_player, float f_ignore) CF_Identify; +void (entity pe_player, float f_type) CF_Identify; void () TeamFortress_ReloadCurrentWeapon; void (float slot) TeamFortress_ReloadSlot; void () TeamFortress_ReloadNext; From 46e4a5aa6e43c57e558789c290f09494a1317e9a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 08:41:52 +0200 Subject: [PATCH 0202/2474] Remove prime timer when dying (fixes #156) --- tfort.qc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tfort.qc b/tfort.qc index 00a6688f..a5173f7b 100644 --- a/tfort.qc +++ b/tfort.qc @@ -84,12 +84,23 @@ void () RemoveAutoIdTimer = { }; void () RemoveGrenadeTimers = { - local entity te = find(world, classname, "gtimer"); + local entity te; + + te = find(world, classname, "gtimer"); while (te != world) { if (te.owner == self) dremove(te); te = find(te, classname, "gtimer"); } + + if (self.health <= 0) { + te = find(world, classname, "primetimer"); + while (te != world) { + if (te.owner == self) + dremove(te); + te = find(te, classname, "primetimer"); + } + } }; void () RemoveGrenades = { @@ -699,7 +710,7 @@ void () TeamFortress_GrenadePrimed = { local entity user; user = self.owner; - if (!(user.tfstate & 1024) && !user.deadflag && !user.has_disconnected) { + if (!(user.tfstate & TFSTATE_GRENTHROWING) && !user.deadflag && !user.has_disconnected) { self.nextthink = time + 0.1; if (!self.think) dremove(self); @@ -709,7 +720,7 @@ void () TeamFortress_GrenadePrimed = { return; } - if (!(user.tfstate & 1)) + if (!(user.tfstate & TFSTATE_GRENPRIMED)) dprint("GrenadePrimed logic error\n"); user.tfstate = user.tfstate - (user.tfstate & TFSTATE_GRENPRIMED); From e3b5c4d6cfd389dd1bbfc4154007f0fa9e741794 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 09:24:54 +0200 Subject: [PATCH 0203/2474] Recalculate odds for map lists when filling vote list (fixes #155) --- vote.qc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vote.qc b/vote.qc index 9eeb0c34..54a12764 100644 --- a/vote.qc +++ b/vote.qc @@ -779,6 +779,17 @@ void (float pf_type) Vote_PopulateVoteList = { //dprint("[", ftos(time), "/cf/mapvote/populatevotelist]: adding map4: ", vote4_map, "\n"); } + // recalculate odds + f_count = f_count1 + f_count2 + f_count3 + f_count4 + f_count5 + f_count6 + f_count7 + f_count8; + f_range1 = f_count1 / f_count * 100; + f_range2 = f_range1 + (f_count2 / f_count * 100); + f_range3 = f_range2 + (f_count3 / f_count * 100); + f_range4 = f_range3 + (f_count4 / f_count * 100); + f_range5 = f_range4 + (f_count5 / f_count * 100); + f_range6 = f_range5 + (f_count6 / f_count * 100); + f_range7 = f_range6 + (f_count7 / f_count * 100); + f_range8 = f_range7 + (f_count8 / f_count * 100); + strunzone(s_tmp); } vote5_map = strzone(mapname); From 8fb55402c4dbbe78b62ec1d6a9801ce53b8cdc0b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 10:36:34 +0200 Subject: [PATCH 0204/2474] Improve PlayerPreThink efficiency --- client.qc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/client.qc b/client.qc index 7bba4faa..61e5df2d 100644 --- a/client.qc +++ b/client.qc @@ -1238,10 +1238,11 @@ void () NextLevel = { }; void () CheckRules = { - if (timelimit && (time >= timelimit)) - NextLevel(); - else if (fraglimit && (self.frags >= fraglimit)) + if ((timelimit && time >= timelimit) || (fraglimit && self.frags >= fraglimit)) { NextLevel(); + RemoveGrenadeTimers(); + RemoveGrenades(); + } }; void () PlayerDeathThink = { @@ -1446,11 +1447,6 @@ void () CheckWaterJump = { }; void () PlayerPreThink = { - if (time >= timelimit) { - RemoveGrenadeTimers(); - RemoveGrenades(); - } - if (self.impulse) { if (self.impulse == TF_VOTENEXT) { Vote_NextMap(self); @@ -1478,7 +1474,10 @@ void () PlayerPreThink = { if (self.view_ofs == '0 0 0') { return; } + + // Check if timelimit/fraglimit has been met CheckRules(); + if (self.playerclass != 0) { WaterMove(); } From b450c6b15e2aee4a48b98431f16f48da5e2bf5a4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 10:37:25 +0200 Subject: [PATCH 0205/2474] Properly change weapon when current weapon runs out of ammo (fixes #133) --- client.qc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client.qc b/client.qc index 61e5df2d..268fc4cc 100644 --- a/client.qc +++ b/client.qc @@ -1532,11 +1532,10 @@ void () PlayerPreThink = { if ((time < self.pausetime) || (cease_fire == 1)) { self.velocity = '0 0 0'; } - if (((time > self.attack_finished) && (self.currentammo == 0)) && - (self.weapon > 16)) { - self.weapon = W_BestWeapon(); - self.current_weaponslot = W_BestWeaponSlot(); + if (time > self.attack_finished && !self.currentammo && self.weapon > WEAP_AXE) { + W_ChangeWeapon(W_BestWeaponSlot()); W_SetCurrentAmmo(self); + W_WeaponState_Save(self); } }; From fd86cac14dd006e6462cc3ded7ec5dacbf289805 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 11:08:01 +0200 Subject: [PATCH 0206/2474] Don't autoid non player/buildings (fixes #166) --- actions.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/actions.qc b/actions.qc index 73b0e54b..da9341db 100644 --- a/actions.qc +++ b/actions.qc @@ -208,6 +208,10 @@ void (entity pe_player, float f_type) CF_Identify = { s_class = ""; + } else { + + return; + } // set name + health (if medic) From ccb2cde659065dc223a852ada54622c28c63de0a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 11:55:14 +0200 Subject: [PATCH 0207/2474] Update same target ids in status bar instantly --- actions.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/actions.qc b/actions.qc index da9341db..db8e8698 100644 --- a/actions.qc +++ b/actions.qc @@ -264,8 +264,10 @@ void (entity pe_player, float f_type) CF_Identify = { pe_player.ident_time = time + 0.5; // don't update memory when the id string is the same - if (pe_player.ident_string == s_id_string) + if (pe_player.ident_string == s_id_string) { + Status_Refresh(pe_player); return; + } // refresh status bar pe_player.ident_string = strzone(s_id_string); From d82fe7a142423c1391270565be2fb3d2ebb2ca9c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 12:19:53 +0200 Subject: [PATCH 0208/2474] Only set attacker to target when target is sentry gun or dispenser (fixes #168) --- combat.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/combat.qc b/combat.qc index 0a56ed17..34489ee8 100644 --- a/combat.qc +++ b/combat.qc @@ -53,7 +53,7 @@ float (entity targ, entity inflictor) CanDamage = { void (entity targ, entity attacker) Killed = { local entity oself; - if (attacker == world) + if (attacker == world && (targ.classname == "building_dispenser" || targ.classname == "building_sentrygun")) attacker = targ; oself = self; From d33f22d7e65771b6ee02d9a17b591f63ed4cf623 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 12:31:18 +0200 Subject: [PATCH 0209/2474] Don't identify targets through water surface (fixes #167) --- actions.qc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/actions.qc b/actions.qc index db8e8698..7121f7d8 100644 --- a/actions.qc +++ b/actions.qc @@ -121,6 +121,14 @@ void (entity pe_player, float f_type) CF_Identify = { traceline(v_source, v_source + v_forward * 2048, 0, pe_player); if (trace_ent != world) { + // don't identify targets above water if player is under water + if (pe_player.waterlevel == 3 && !trace_ent.waterlevel) + return; + + // don't identify targets under water if player is above water + if (pe_player.waterlevel < 3 && trace_ent.waterlevel == 3) + return; + // show as friendly if target is on your team or disguised as your team if (pe_player.team_no) { From 2a8ed6684d10103cb28d437976a68914324af736 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 13:40:51 +0200 Subject: [PATCH 0210/2474] Bring back class menu when chosen class is restricted (fixes #169) --- menu.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index feef6f30..3c9975c2 100644 --- a/menu.qc +++ b/menu.qc @@ -8,6 +8,8 @@ void (float issilent) CF_Spy_FeignDeath; void () CF_Spy_Invisible; void () CF_Spy_DisguiseStop; +float (float tno, float pc) ClassIsRestricted; + void (entity spy) Spy_RemoveDisguise; void (entity eng, string bld) DestroyBuilding; @@ -199,7 +201,7 @@ void (float inp) Menu_Class_Input = { if (!inp) return; - if (inp > 10 || !IsLegalClass(inp)) + if (inp > 10 || !IsLegalClass(inp) || ClassIsRestricted(self.team_no, inp)) Menu_Class(); TeamFortress_ChangeClass(inp); From d767f0036e16d2c0a26c6432886278e2c7bc949c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 30 Aug 2014 13:41:16 +0200 Subject: [PATCH 0211/2474] Don't print out restricted classes on class menu --- menu.qc | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/menu.qc b/menu.qc index 3c9975c2..2dece257 100644 --- a/menu.qc +++ b/menu.qc @@ -235,15 +235,44 @@ void () Menu_Class = { local string count_py = TeamFortress_ClassGetNoPlayersString(PC_PYRO, self.team_no); local string count_sp = TeamFortress_ClassGetNoPlayersString(PC_SPY, self.team_no); local string count_en = TeamFortress_ClassGetNoPlayersString(PC_ENGINEER, self.team_no); - s_scout = strcat(s_scout, strcat(count_sc, "\n")); - s_sniper = strcat(s_sniper, strcat(count_sn, "\n")); - s_soldier = strcat(s_soldier, strcat(count_so, "\n")); - s_demoman = strcat(s_demoman, strcat(count_de, "\n")); - s_medic = strcat(s_medic, strcat(count_me, "\n")); - s_hwguy = strcat(s_hwguy, strcat(count_hw, "\n")); - s_pyro = strcat(s_pyro, strcat(count_py, "\n")); - s_spy = strcat(s_spy, strcat(count_sp, "\n")); - s_engineer = strcat(s_engineer, strcat(count_en, "\n")); + + // only print classes that are allowed + if (IsLegalClass(PC_SCOUT) && !ClassIsRestricted(self.team_no, PC_SCOUT)) + s_scout = strcat(s_scout, strcat(count_sc, "\n")); + else + s_scout = "\n"; + if (IsLegalClass(PC_SNIPER) && !ClassIsRestricted(self.team_no, PC_SNIPER)) + s_sniper = strcat(s_sniper, strcat(count_sn, "\n")); + else + s_sniper = "\n"; + if (IsLegalClass(PC_SOLDIER) && !ClassIsRestricted(self.team_no, PC_SOLDIER)) + s_soldier = strcat(s_soldier, strcat(count_so, "\n")); + else + s_soldier = "\n"; + if (IsLegalClass(PC_DEMOMAN) && !ClassIsRestricted(self.team_no, PC_DEMOMAN)) + s_demoman = strcat(s_demoman, strcat(count_de, "\n")); + else + s_demoman = "\n"; + if (IsLegalClass(PC_MEDIC) && !ClassIsRestricted(self.team_no, PC_MEDIC)) + s_medic = strcat(s_medic, strcat(count_me, "\n")); + else + s_medic = "\n"; + if (IsLegalClass(PC_HVYWEAP) && !ClassIsRestricted(self.team_no, PC_HVYWEAP)) + s_hwguy = strcat(s_hwguy, strcat(count_hw, "\n")); + else + s_hwguy = "\n"; + if (IsLegalClass(PC_PYRO) && !ClassIsRestricted(self.team_no, PC_PYRO)) + s_pyro = strcat(s_pyro, strcat(count_py, "\n")); + else + s_pyro = "\n"; + if (IsLegalClass(PC_SPY) && !ClassIsRestricted(self.team_no, PC_SPY)) + s_spy = strcat(s_spy, strcat(count_sp, "\n")); + else + s_spy = "\n"; + if (IsLegalClass(PC_ENGINEER) && !ClassIsRestricted(self.team_no, PC_ENGINEER)) + s_engineer = strcat(s_engineer, strcat(count_en, "\n")); + else + s_engineer = "\n"; AD = find(world, classname, "info_tfdetect"); if (AD) { From e498a11cba7e1730960507b63e30cded29b404f6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 11:59:34 +0200 Subject: [PATCH 0212/2474] Rewrite class menu code (closes #170) --- client.qc | 4 +- menu.qc | 287 +++++++++++++++++++++++++++++++++++++++-------------- tfort.qc | 4 +- tforttm.qc | 194 +++++++++++++++--------------------- 4 files changed, 295 insertions(+), 194 deletions(-) diff --git a/client.qc b/client.qc index 268fc4cc..10a24a2a 100644 --- a/client.qc +++ b/client.qc @@ -39,7 +39,7 @@ void () DumpClanScores; void (entity p) SetTeamName; void () autokick_think; -float (float tno, float pc) ClassIsRestricted; +float (float pf_team_no, float pf_class) CF_ClassIsRestricted; void (entity AD) ParseTFDetect; entity(float ino) Finditem; @@ -1021,7 +1021,7 @@ void () PutClientInServer = { self.playerclass = 1 + floor(random() * (10 - 1)); while (!IsLegalClass(self.playerclass) || (self.playerclass == oldclass) - || ClassIsRestricted(self.team_no, self.playerclass)) { + || CF_ClassIsRestricted(self.team_no, self.playerclass)) { self.playerclass = 1 + floor(random() * (10 - 1)); } self.tfstate = TFSTATE_RANDOMPC; diff --git a/menu.qc b/menu.qc index 2dece257..2d83ce61 100644 --- a/menu.qc +++ b/menu.qc @@ -8,7 +8,9 @@ void (float issilent) CF_Spy_FeignDeath; void () CF_Spy_Invisible; void () CF_Spy_DisguiseStop; -float (float tno, float pc) ClassIsRestricted; +float (float pf_team_no, float pf_class) CF_GetClassRestriction; +float (float pf_team_no, float pf_class) CF_GetClassPlayers; +float (float pf_team_no, float pf_class) CF_ClassIsRestricted; void (entity spy) Spy_RemoveDisguise; @@ -201,112 +203,245 @@ void (float inp) Menu_Class_Input = { if (!inp) return; - if (inp > 10 || !IsLegalClass(inp) || ClassIsRestricted(self.team_no, inp)) + // keep showing menu if class is invalid + if (inp > 9 || !IsLegalClass(inp) || CF_ClassIsRestricted(self.team_no, inp)) Menu_Class(); + // don't try to change class if class is forbidden + if (!IsLegalClass(inp) || CF_GetClassRestriction(self.team_no, inp) == -1) + return; + TeamFortress_ChangeClass(inp); }; void () Menu_Class = { - local entity AD; - local string s_select = "Select class:\n\n"; - local string s_scout = "“‘ Scout "; - local string s_sniper = "”‘ Sniper "; - local string s_soldier = "•‘ Soldier "; - local string s_demoman = "–‘ Demoman "; - local string s_medic = "—‘ Medic "; - local string s_hwguy = "˜‘ HWGuy "; - local string s_pyro = "™‘ Pyro "; - local string s_spy = "š‘ Spy "; - local string s_engineer = "›‘ Engineer "; - local string s_randompc = "’‘ RandomPC "; + local float f_max, f_players, f_class, f_gap = 4; + local string s_string; if (self.menu_input == Menu_Class_Input) { Menu_Input(0); return; } - local string count_sc = TeamFortress_ClassGetNoPlayersString(PC_SCOUT, self.team_no); - local string count_sn = TeamFortress_ClassGetNoPlayersString(PC_SNIPER, self.team_no); - local string count_so = TeamFortress_ClassGetNoPlayersString(PC_SOLDIER, self.team_no); - local string count_de = TeamFortress_ClassGetNoPlayersString(PC_DEMOMAN, self.team_no); - local string count_me = TeamFortress_ClassGetNoPlayersString(PC_MEDIC, self.team_no); - local string count_hw = TeamFortress_ClassGetNoPlayersString(PC_HVYWEAP, self.team_no); - local string count_py = TeamFortress_ClassGetNoPlayersString(PC_PYRO, self.team_no); - local string count_sp = TeamFortress_ClassGetNoPlayersString(PC_SPY, self.team_no); - local string count_en = TeamFortress_ClassGetNoPlayersString(PC_ENGINEER, self.team_no); - - // only print classes that are allowed - if (IsLegalClass(PC_SCOUT) && !ClassIsRestricted(self.team_no, PC_SCOUT)) - s_scout = strcat(s_scout, strcat(count_sc, "\n")); - else - s_scout = "\n"; - if (IsLegalClass(PC_SNIPER) && !ClassIsRestricted(self.team_no, PC_SNIPER)) - s_sniper = strcat(s_sniper, strcat(count_sn, "\n")); - else - s_sniper = "\n"; - if (IsLegalClass(PC_SOLDIER) && !ClassIsRestricted(self.team_no, PC_SOLDIER)) - s_soldier = strcat(s_soldier, strcat(count_so, "\n")); - else - s_soldier = "\n"; - if (IsLegalClass(PC_DEMOMAN) && !ClassIsRestricted(self.team_no, PC_DEMOMAN)) - s_demoman = strcat(s_demoman, strcat(count_de, "\n")); - else - s_demoman = "\n"; - if (IsLegalClass(PC_MEDIC) && !ClassIsRestricted(self.team_no, PC_MEDIC)) - s_medic = strcat(s_medic, strcat(count_me, "\n")); - else - s_medic = "\n"; - if (IsLegalClass(PC_HVYWEAP) && !ClassIsRestricted(self.team_no, PC_HVYWEAP)) - s_hwguy = strcat(s_hwguy, strcat(count_hw, "\n")); - else - s_hwguy = "\n"; - if (IsLegalClass(PC_PYRO) && !ClassIsRestricted(self.team_no, PC_PYRO)) - s_pyro = strcat(s_pyro, strcat(count_py, "\n")); - else - s_pyro = "\n"; - if (IsLegalClass(PC_SPY) && !ClassIsRestricted(self.team_no, PC_SPY)) - s_spy = strcat(s_spy, strcat(count_sp, "\n")); - else - s_spy = "\n"; - if (IsLegalClass(PC_ENGINEER) && !ClassIsRestricted(self.team_no, PC_ENGINEER)) - s_engineer = strcat(s_engineer, strcat(count_en, "\n")); - else - s_engineer = "\n"; - - AD = find(world, classname, "info_tfdetect"); - if (AD) { + // print map specific class menu + local entity e_info = find(world, classname, "info_tfdetect"); + if (e_info) { if (self.team_no == 1) { - if (AD.noise1 != string_null) { - Status_Menu(self, Menu_Class_Input, AD.noise1); + if (e_info.noise1 != string_null) { + Status_Menu(self, Menu_Class_Input, e_info.noise1); return; } } else if (self.team_no == 2) { - if (AD.noise2 != string_null) { - Status_Menu(self, Menu_Class_Input, AD.noise2); + if (e_info.noise2 != string_null) { + Status_Menu(self, Menu_Class_Input, e_info.noise2); return; } } else if (self.team_no == 3) { - if (AD.noise3 != string_null) { - Status_Menu(self, Menu_Class_Input, AD.noise3); + if (e_info.noise3 != string_null) { + Status_Menu(self, Menu_Class_Input, e_info.noise3); return; } } else if (self.team_no == 4) { - if (AD.noise4 != string_null) { - Status_Menu(self, Menu_Class_Input, AD.noise4); + if (e_info.noise4 != string_null) { + Status_Menu(self, Menu_Class_Input, e_info.noise4); return; } } } + // prepare class strings + local string s_select = "Select class:\n\n"; + local string s_scout = "“‘ Scout "; + local string s_sniper = "”‘ Sniper "; + local string s_soldier = "•‘ Soldier "; + local string s_demoman = "–‘ Demoman "; + local string s_medic = "—‘ Medic "; + local string s_hwguy = "˜‘ HWGuy "; + local string s_pyro = "™‘ Pyro "; + local string s_spy = "š‘ Spy "; + local string s_engineer = "›‘ Engineer"; + local string s_randompc = "’‘ RandomPC"; + + // put together class strings + f_class = PC_SCOUT; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_scout = strzone(strcat(s_scout, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_scout = strzone("\n"); + + f_class = PC_SNIPER; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_sniper = strzone(strcat(s_sniper, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_sniper = strzone("\n"); + + f_class = PC_SOLDIER; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_soldier = strzone(strcat(s_soldier, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_soldier = strzone("\n"); + + f_class = PC_DEMOMAN; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_demoman = strzone(strcat(s_demoman, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_demoman = strzone("\n"); + + f_class = PC_MEDIC; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_medic = strzone(strcat(s_medic, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_medic = strzone("\n"); + + f_class = PC_HVYWEAP; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_hwguy = strzone(strcat(s_hwguy, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_hwguy = strzone("\n"); + + f_class = PC_PYRO; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_pyro = strzone(strcat(s_pyro, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_pyro = strzone("\n"); + + f_class = PC_SPY; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_spy = strzone(strcat(s_spy, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_spy = strzone("\n"); + + f_class = PC_ENGINEER; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_engineer = strzone(strcat(s_engineer, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_engineer = strzone("\n"); + + f_class = PC_RANDOM; + f_max = CF_GetClassRestriction(self.team_no, f_class); + f_players = CF_GetClassPlayers(self.team_no, f_class); + if (IsLegalClass(f_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_randompc = strzone(strcat(s_randompc, s_string)); + } else if (!IsLegalClass(f_class) || f_max == -1) + s_randompc = strzone("\n"); + + // print out class menu self.menu_input = nil; if (TeamFortress_TeamIsCivilian(self.team_no)) Status_Print(self, "Your team can only be civilians\n"); - else { - if (spy_off == 1) - s_spy = "\n"; + else Status_Menu(self, Menu_Class_Input, s_select, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_randompc); - } + + strunzone(s_scout); strunzone(s_sniper); strunzone(s_soldier); strunzone(s_demoman); strunzone(s_medic); + strunzone(s_hwguy); strunzone(s_pyro); strunzone(s_spy); strunzone(s_engineer); strunzone(s_randompc); }; void (float inp) Menu_Drop_Input = { diff --git a/tfort.qc b/tfort.qc index a5173f7b..38589a3c 100644 --- a/tfort.qc +++ b/tfort.qc @@ -138,7 +138,7 @@ void (float inp) TeamFortress_ChangeClass = { "The spy class has been disabled on the server by the administrator\n"); return; } - if (ClassIsRestricted(self.team_no, inp)) { + if (CF_ClassIsRestricted(self.team_no, inp)) { sprint(self, PRINT_HIGH, "Your team already has enough of that class\n"); return; @@ -177,7 +177,7 @@ void (float inp) TeamFortress_ChangeClass = { "The spy class has been disabled on the server by the administrator\n"); return; } - if (ClassIsRestricted(self.team_no, inp)) { + if (CF_ClassIsRestricted(self.team_no, inp)) { sprint(self, PRINT_HIGH, "Your team has enough of that class\n"); return; } diff --git a/tforttm.qc b/tforttm.qc index e4dbf67e..e278e170 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -884,124 +884,90 @@ float (float tno) TeamFortress_TeamIsCivilian = { return (0); }; -float (float tno, float pc) ClassIsRestricted = { - local float num; - local float max; - local entity te; - local string st; - max = 0; +float (float pf_team_no, float pf_class) CF_GetClassRestriction = { + local float f_max = 0, f_players = TeamFortress_TeamGetNoPlayers(pf_team_no); + local string s_string; + + // set maximum number based on settings + if (pf_class == PC_SCOUT) { + s_string = infokey(world, "cr_scout"); + f_max = stof(s_string); + } else if (pf_class == PC_SNIPER) { + s_string = infokey(world, "cr_sniper"); + f_max = stof(s_string); + } else if (pf_class == PC_SOLDIER) { + s_string = infokey(world, "cr_soldier"); + f_max = stof(s_string); + } else if (pf_class == PC_DEMOMAN) { + s_string = infokey(world, "cr_demoman"); + f_max = stof(s_string); + } else if (pf_class == PC_MEDIC) { + s_string = infokey(world, "cr_medic"); + f_max = stof(s_string); + } else if (pf_class == PC_HVYWEAP) { + s_string = infokey(world, "cr_hwguy"); + f_max = stof(s_string); + } else if (pf_class == PC_PYRO) { + s_string = infokey(world, "cr_pyro"); + f_max = stof(s_string); + } else if (pf_class == PC_SPY) { + if (spy_off) + return -1; + s_string = infokey(world, "cr_spy"); + f_max = stof(s_string); + } else if (pf_class == PC_ENGINEER) { + s_string = infokey(world, "cr_engineer"); + f_max = stof(s_string); + } else if (pf_class == PC_RANDOM) { + s_string = infokey(world, "cr_randompc"); + f_max = stof(s_string); + } + + if (f_max == 0 || f_players < f_max) + return f_players; + + return f_max; +}; - if (tno == 0) { - return (0); - } - if (pc == 1) { - st = infokey(world, "cr_sc"); - if (st == string_null) { - st = infokey(world, "cr_scout"); - } - max = stof(st); - } else { - if (pc == 2) { - st = infokey(world, "cr_sn"); - if (st == string_null) { - st = infokey(world, "cr_sniper"); - } - max = stof(st); - } else { - if (pc == 3) { - st = infokey(world, "cr_so"); - if (st == string_null) { - st = infokey(world, "cr_soldier"); - } - max = stof(st); - } else { - if (pc == 4) { - st = infokey(world, "cr_de"); - if (st == string_null) { - st = infokey(world, "cr_demoman"); - } - max = stof(st); - } else { - if (pc == 5) { - st = infokey(world, "cr_me"); - if (st == string_null) { - st = infokey(world, "cr_medic"); - } - max = stof(st); - } else { - if (pc == 6) { - st = infokey(world, "cr_hw"); - if (st == string_null) { - st = infokey(world, "cr_hwguy"); - } - max = stof(st); - } else { - if (pc == 7) { - st = infokey(world, "cr_py"); - if (st == string_null) { - st = infokey(world, "cr_pyro"); - } - max = stof(st); - } else { - if (pc == 8) { - st = infokey(world, "cr_sp"); - if (st == string_null) { - st = infokey(world, "cr_spy"); - } - max = stof(st); - } else { - if (pc == 9) { - st = infokey(world, "cr_en"); - if (st == string_null) { - st = infokey(world, - "cr_engineer"); - } - max = stof(st); - } else { - if (pc == 10) { - st = infokey(world, "cr_ra"); - if (st == string_null) { - st = infokey(world, - "cr_random"); - } - max = stof(st); - } - } - } - } - } - } - } - } - } - } - if (max > 0) { - num = 0; - te = find(world, classname, "player"); - while (te) { - if (te.team_no == tno) { - if (pc == 10) { - if (te.tfstate & 8) { - num = num + 1; - } - } else { - if ((te.playerclass == pc) || (te.nextpc == pc)) { - if (!(te.tfstate & 8)) { - num = num + 1; - } - } - } +float (float pf_team_no, float pf_class) CF_GetClassPlayers = { + local float f_playing = 0; + local entity e_find; + + if (!pf_team_no) + return 0; + + // get amount of players currently playing + e_find = find(world, classname, "player"); + while (e_find) { + if (e_find.team_no == pf_team_no) { + if (pf_class == PC_RANDOM) { + if (e_find.tfstate & TFSTATE_RANDOMPC) + f_playing = f_playing + 1; + } else if (e_find.playerclass == pf_class || e_find.nextpc == pf_class) { + if (!(e_find.tfstate & TFSTATE_RANDOMPC)) + f_playing = f_playing + 1; } - te = find(te, classname, "player"); - } - if (num >= max) { - return (1); } + e_find = find(e_find, classname, "player"); } - if (max == -1) { - return (1); - } - return (0); + + return f_playing; + +}; + +float (float pf_team_no, float pf_class) CF_ClassIsRestricted = { + local float f_playing, f_max; + + if (!pf_team_no) + return 0; + + f_max = CF_GetClassRestriction(pf_team_no, pf_class); + f_playing = CF_GetClassPlayers(pf_team_no, pf_class); + + if ((f_max > 0 && f_playing >= f_max) || f_max == -1) + return 1; + + return 0; }; void (float tno, entity ignore, string st) teamsprint = { From 16315481196e74b0385d4d462c25a884aec8e3bc Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 12:13:41 +0200 Subject: [PATCH 0213/2474] Improve class menu code --- menu.qc | 205 +++++++++----------------------------------------------- 1 file changed, 33 insertions(+), 172 deletions(-) diff --git a/menu.qc b/menu.qc index 2d83ce61..4fd98ae3 100644 --- a/menu.qc +++ b/menu.qc @@ -214,10 +214,30 @@ void (float inp) Menu_Class_Input = { TeamFortress_ChangeClass(inp); }; -void () Menu_Class = { - local float f_max, f_players, f_class, f_gap = 4; +string (float pf_class, string ps_class) Menu_Class_ClassString = { local string s_string; + local float f_gap = 4; + local float f_max = CF_GetClassRestriction(self.team_no, pf_class); + local float f_players = CF_GetClassPlayers(self.team_no, pf_class); + + if (IsLegalClass(pf_class) && f_max >= 0) { + if (f_players < 10) + s_string = strpadl(ftos(f_players), (1 + f_gap)); + else + s_string = strpadl(ftos(f_players), f_gap); + s_string = strcat(s_string, " / "); + if (f_max < 10) + s_string = strpadr(s_string, (5 + f_gap)); + s_string = strcat(s_string, ftos(f_max)); + s_string = strcat(s_string, "\n"); + s_string = strzone(strcat(ps_class, s_string)); + } else + s_string = strzone("\n"); + + return strzone(s_string); +}; +void () Menu_Class = { if (self.menu_input == Menu_Class_Input) { Menu_Input(0); return; @@ -262,176 +282,17 @@ void () Menu_Class = { local string s_engineer = "›‘ Engineer"; local string s_randompc = "’‘ RandomPC"; - // put together class strings - f_class = PC_SCOUT; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_scout = strzone(strcat(s_scout, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_scout = strzone("\n"); - - f_class = PC_SNIPER; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_sniper = strzone(strcat(s_sniper, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_sniper = strzone("\n"); - - f_class = PC_SOLDIER; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_soldier = strzone(strcat(s_soldier, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_soldier = strzone("\n"); - - f_class = PC_DEMOMAN; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_demoman = strzone(strcat(s_demoman, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_demoman = strzone("\n"); - - f_class = PC_MEDIC; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_medic = strzone(strcat(s_medic, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_medic = strzone("\n"); - - f_class = PC_HVYWEAP; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_hwguy = strzone(strcat(s_hwguy, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_hwguy = strzone("\n"); - - f_class = PC_PYRO; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_pyro = strzone(strcat(s_pyro, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_pyro = strzone("\n"); - - f_class = PC_SPY; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_spy = strzone(strcat(s_spy, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_spy = strzone("\n"); - - f_class = PC_ENGINEER; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_engineer = strzone(strcat(s_engineer, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_engineer = strzone("\n"); - - f_class = PC_RANDOM; - f_max = CF_GetClassRestriction(self.team_no, f_class); - f_players = CF_GetClassPlayers(self.team_no, f_class); - if (IsLegalClass(f_class) && f_max >= 0) { - if (f_players < 10) - s_string = strpadl(ftos(f_players), (1 + f_gap)); - else - s_string = strpadl(ftos(f_players), f_gap); - s_string = strcat(s_string, " / "); - if (f_max < 10) - s_string = strpadr(s_string, (5 + f_gap)); - s_string = strcat(s_string, ftos(f_max)); - s_string = strcat(s_string, "\n"); - s_randompc = strzone(strcat(s_randompc, s_string)); - } else if (!IsLegalClass(f_class) || f_max == -1) - s_randompc = strzone("\n"); + // put together class strings - all strings are strzoned + s_scout = Menu_Class_ClassString(PC_SCOUT, s_scout); + s_sniper = Menu_Class_ClassString(PC_SNIPER, s_sniper); + s_soldier = Menu_Class_ClassString(PC_SOLDIER, s_soldier); + s_demoman = Menu_Class_ClassString(PC_DEMOMAN, s_demoman); + s_medic = Menu_Class_ClassString(PC_MEDIC, s_medic); + s_hwguy = Menu_Class_ClassString(PC_HVYWEAP, s_hwguy); + s_pyro = Menu_Class_ClassString(PC_PYRO, s_pyro); + s_spy = Menu_Class_ClassString(PC_SPY, s_spy); + s_engineer = Menu_Class_ClassString(PC_ENGINEER, s_engineer); + s_randompc = Menu_Class_ClassString(PC_RANDOM, s_randompc); // print out class menu self.menu_input = nil; From 3052158740954ec94bcba7d875f0183b83686d1b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 12:47:19 +0200 Subject: [PATCH 0214/2474] Rewrite team menu code --- menu.qc | 90 +++++++++++++++++++++++---------------------------------- 1 file changed, 36 insertions(+), 54 deletions(-) diff --git a/menu.qc b/menu.qc index 4fd98ae3..6d1a1c90 100644 --- a/menu.qc +++ b/menu.qc @@ -125,20 +125,31 @@ void (float inp) Menu_Team_Input = { } }; -void () Menu_Team = { - local string ch = "Select team:\n\n"; - local string t1 = "“‘ Blue team "; - local string t2, t3, t4; - local string ta = "\n—‘ Automatically assign team"; +string (float pf_team_no, string ps_team) Menu_Team_TeamString = { + local string s_string = ""; + local float f_gap = 2; + local float f_players = TeamFortress_TeamGetNoPlayers(pf_team_no); + + if (number_of_teams >= pf_team_no) { + s_string = strpadl(ftos(f_players), f_gap); + if (f_players < 10) { + s_string = strpadl(s_string, (1 + f_gap)); + if (f_players == 1) + s_string = strcat(s_string, " player \n"); + else + s_string = strcat(s_string, " players\n"); + } else + s_string = strcat(s_string, " players\n"); + s_string = strcat(ps_team, s_string); + } + + return strzone(s_string); +}; +void () Menu_Team = { if (self.classname == "observer") Status_Menu(self, Menu_Team_Input, ""); - local float t1_players = TeamFortress_TeamGetNoPlayers(1); - local float t2_players = TeamFortress_TeamGetNoPlayers(2); - local float t3_players = TeamFortress_TeamGetNoPlayers(3); - local float t4_players = TeamFortress_TeamGetNoPlayers(4); - // allow toggling team menu using any method to show it if (self.menu_input == Menu_Team_Input) { Menu_Input(0); @@ -150,53 +161,24 @@ void () Menu_Team = { return; } - t2 = ""; - t3 = ""; - t4 = ""; - - if (number_of_teams > 1) - t2 = "”‘ Red team "; - - if (number_of_teams > 2) - t3 = "•‘ Yellow team "; - - if (number_of_teams > 3) - t4 = "–‘ Green team "; - - t1 = strcat(t1, strpadl(ftos(t1_players), 2)); - if (t1_players == 1) - t1 = strcat(t1, " player \n"); - else - t1 = strcat(t1, " players\n"); - - if (strlen(t2) > 0) { - t2 = strcat(t2, strpadl(ftos(t2_players), 2)); - if (t2_players == 1) - t2 = strcat(t2, " player \n"); - else - t2 = strcat(t2, " players\n"); - } else - ta = strcat(ta, "\n"); + // prepare team strings + local string s_select = "Select team:\n\n"; + local string s_blue = "“‘ Blue team "; + local string s_red = "”‘ Red team "; + local string s_yellow = "•‘ Yellow team"; + local string s_green = "–‘ Green team "; + local string s_auto = "—‘ Auto-assign team"; - if (strlen(t3) > 0) { - t3 = strcat(t3, strpadl(ftos(t3_players), 2)); - if (t3_players == 1) - t3 = strcat(t3, " player \n"); - else - t3 = strcat(t3, " players\n"); - } else - ta = strcat(ta, "\n"); + // put together team strings + s_blue = Menu_Team_TeamString(1, s_blue); + s_red = Menu_Team_TeamString(2, s_red); + s_yellow = Menu_Team_TeamString(3, s_yellow); + s_green = Menu_Team_TeamString(4, s_green); + s_auto = strpadr(s_auto, (strlen(s_blue) - 1)); - if (strlen(t4) > 0) { - t4 = strcat(t4, strpadl(ftos(t4_players), 2)); - if (t4_players == 1) - t4 = strcat(t4, " player \n"); - else - t4 = strcat(t4, " players\n"); - } else - ta = strcat(ta, "\n"); + Status_Menu(self, Menu_Team_Input, s_select, s_blue, s_red, s_yellow, s_green, "\n", s_auto); - Status_Menu(self, Menu_Team_Input, ch, t1, t2, t3, t4, ta); + strunzone(s_blue); strunzone(s_red); strunzone(s_yellow); strunzone(s_green); }; void (float inp) Menu_Class_Input = { From c302f3523ea4d38d26baa2633213de4f2d776a6c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 12:47:31 +0200 Subject: [PATCH 0215/2474] Fix minor class menu bug --- menu.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/menu.qc b/menu.qc index 6d1a1c90..ca6f32d6 100644 --- a/menu.qc +++ b/menu.qc @@ -197,7 +197,7 @@ void (float inp) Menu_Class_Input = { }; string (float pf_class, string ps_class) Menu_Class_ClassString = { - local string s_string; + local string s_string = "\n"; local float f_gap = 4; local float f_max = CF_GetClassRestriction(self.team_no, pf_class); local float f_players = CF_GetClassPlayers(self.team_no, pf_class); @@ -213,8 +213,7 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { s_string = strcat(s_string, ftos(f_max)); s_string = strcat(s_string, "\n"); s_string = strzone(strcat(ps_class, s_string)); - } else - s_string = strzone("\n"); + } return strzone(s_string); }; From d05a3556bffc6a722871f2b3eee24b8f19de863e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 14:37:35 +0200 Subject: [PATCH 0216/2474] Only add extra space in max count if team players > 9 --- menu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index ca6f32d6..a4eee8e7 100644 --- a/menu.qc +++ b/menu.qc @@ -208,7 +208,7 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { else s_string = strpadl(ftos(f_players), f_gap); s_string = strcat(s_string, " / "); - if (f_max < 10) + if (f_max < 10 && TeamFortress_TeamGetNoPlayers(self.team_no) >= 10) s_string = strpadr(s_string, (5 + f_gap)); s_string = strcat(s_string, ftos(f_max)); s_string = strcat(s_string, "\n"); From b3707264fa5087f5c0829774dffaf066b8c0126f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 14:53:15 +0200 Subject: [PATCH 0217/2474] Show disabled classes as disabled in class menu --- menu.qc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/menu.qc b/menu.qc index a4eee8e7..efa52f6d 100644 --- a/menu.qc +++ b/menu.qc @@ -197,8 +197,8 @@ void (float inp) Menu_Class_Input = { }; string (float pf_class, string ps_class) Menu_Class_ClassString = { - local string s_string = "\n"; - local float f_gap = 4; + local string s_string; + local float f_gap = 5; local float f_max = CF_GetClassRestriction(self.team_no, pf_class); local float f_players = CF_GetClassPlayers(self.team_no, pf_class); @@ -213,6 +213,12 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { s_string = strcat(s_string, ftos(f_max)); s_string = strcat(s_string, "\n"); s_string = strzone(strcat(ps_class, s_string)); + } else { + if (TeamFortress_TeamGetNoPlayers(self.team_no) >= 10) + s_string = strpadr(ps_class, (12 + f_gap - 3)); + else + s_string = strpadr(ps_class, (12 + f_gap - 3)); + s_string = strcat(s_string, "disabled\n"); } return strzone(s_string); From 32a9b5c70a88279e57a54b7164626b2fe806746a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 17:54:07 +0200 Subject: [PATCH 0218/2474] Implement medic aura and regenerating cells (closes #115 and #162) --- defs.h | 10 ++++- medic.qc | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ progs.src | 1 + qw.qc | 5 +++ status.qc | 25 +++++++++++++ tfort.qc | 46 ++++++++--------------- weapons.qc | 3 ++ 7 files changed, 167 insertions(+), 31 deletions(-) create mode 100644 medic.qc diff --git a/defs.h b/defs.h index 8363f348..7d9a81f9 100644 --- a/defs.h +++ b/defs.h @@ -348,6 +348,9 @@ // Axe #define AXE_IMP 40 +// Medic functions +#define TF_MEDIC_AURA_TOGGLE 41 + // Camera Impulse #define TF_CAM_TARGET 50 #define TF_CAM_ZOOM 51 @@ -819,7 +822,7 @@ #define PC_MEDIC_WEAPONS WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN #define PC_MEDIC_MAXAMMO_SHOT 75 #define PC_MEDIC_MAXAMMO_NAIL 150 -#define PC_MEDIC_MAXAMMO_CELL 50 +#define PC_MEDIC_MAXAMMO_CELL 100 #define PC_MEDIC_MAXAMMO_ROCKET 25 #define PC_MEDIC_MAXAMMO_MEDIKIT 100 #define PC_MEDIC_INITAMMO_SHOT 50 @@ -834,6 +837,11 @@ #define PC_MEDIC_TF_ITEMS 0 #define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. #define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. +#define PC_MEDIC_AURA_HEAL_TIME 1 // Number of seconds between each aura heal. +#define PC_MEDIC_AURA_HEAL_AMOUNT 5 // Amount of health given per aura heal. +#define PC_MEDIC_AURA_RANGE 120 // The aura's range +#define PC_MEDIC_CELL_REGEN_TIME 0.5 // Number of seconds between each cell regen. +#define PC_MEDIC_CELL_REGEN_AMOUNT 5 // Amount of cells regenerated each cell regen. // Class Details for HVYWEAP #define PC_HVYWEAP_SKIN 2 diff --git a/medic.qc b/medic.qc new file mode 100644 index 00000000..e16be3a6 --- /dev/null +++ b/medic.qc @@ -0,0 +1,108 @@ +// COMBAT MEDIC FUNCTIONS +// ====================== + +// functions by order of appearance +void () CF_Medic_AuraToggle; + +// initializes the medic healing aura +// called from weapons.qc:ImpulseCommands() +void () CF_Medic_AuraToggle = { + if (self.aura_active) { + self.aura_active = 0; + sprint(self, PRINT_HIGH, "Healing aura turned off\n"); + } + else { + self.aura_active = 1; + sprint(self, PRINT_HIGH, "Healing aura turned on\n"); + } + Status_Refresh(self); +}; + +float (entity pe_target) CF_Medic_AuraHealPlayer = { + local float f_healamount = 0; + + if (pe_target.health < pe_target.max_health) { + f_healamount = min(PC_MEDIC_AURA_HEAL_AMOUNT, (pe_target.max_health - pe_target.health)); + pe_target.health = pe_target.health + f_healamount; + } + + return f_healamount; +}; + +// heals the team players around the medic every second +// called from tfort.qc:TeamFortress_SetEquipment() +void () CF_Medic_AuraFindPlayers = { + local float f_healamount = 0; + local float f_healtotal = 0; + local float f_healcount = 0; + local entity e_find; + + self.nextthink = time + PC_MEDIC_AURA_HEAL_TIME; + + if (!self.owner.aura_active || self.owner.ammo_cells < 100) + return; + + e_find = findradius(self.owner.origin, PC_MEDIC_AURA_RANGE); + while (e_find != world) { + if (e_find.classname == "player" && e_find.team_no == self.owner.team_no) { + f_healamount = CF_Medic_AuraHealPlayer(e_find); + f_healtotal = f_healtotal + f_healamount; + if (f_healamount) + f_healcount = f_healcount + 1; + } + e_find = e_find.chain; + } + + if (f_healtotal) { + sound(self.owner, 3, "items/r_item2.wav", 1, 1); + if (time < self.owner.aura_healtime) + self.owner.aura_healamount = self.owner.aura_healamount + f_healtotal; + else + self.owner.aura_healamount = f_healtotal; + self.owner.aura_healtime = time + 3; + self.owner.aura_healcount = f_healcount; + Status_Refresh(self.owner); + } else if (time >= self.owner.aura_healtime && self.owner.aura_healcount) { + self.owner.aura_healcount = 0; + self.owner.aura_healamount = 0; + self.owner.aura_healtime = 0; + } +}; + +// increases the medic's cells two times per second +// called from tfort.qc:TeamFortress_SetEquipment() +void () CF_Medic_RegenerateCells = { + self.nextthink = time + PC_MEDIC_CELL_REGEN_TIME; + + if (self.owner.ammo_cells < 100) { + self.owner.ammo_cells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); + + // refresh status bar if cells just hit 100 + if ((self.owner.ammo_cells + PC_MEDIC_CELL_REGEN_AMOUNT) > 100) + Status_Refresh(self.owner); + } +}; + +// regenerates the medic's health +// called from tfort.qc:TeamFortress_SetEquipment() +void () CF_Medic_Regenerate = { + self.nextthink = time + PC_MEDIC_REGEN_TIME; + + if (self.owner.has_disconnected == 1) { + dremove(self); + return; + } + + if (self.owner.health >= self.owner.max_health || self.owner.ammo_medikit) + return; + + if (self.owner.ammo_medikit < PC_MEDIC_REGEN_AMOUNT) { + self.owner.health = self.owner.health + self.owner.ammo_medikit; + self.owner.ammo_medikit = 0; + } else { + self.owner.health = self.owner.health + PC_MEDIC_REGEN_AMOUNT; + self.owner.ammo_medikit = self.owner.ammo_medikit - PC_MEDIC_REGEN_AMOUNT; + } + if (self.owner.health > self.owner.max_health) + self.owner.health = self.owner.max_health; +} \ No newline at end of file diff --git a/progs.src b/progs.src index d75276c7..41466369 100644 --- a/progs.src +++ b/progs.src @@ -29,6 +29,7 @@ scout.qc sniper.qc tsoldier.qc demoman.qc +medic.qc pyro.qc spy.qc engineer.qc diff --git a/qw.qc b/qw.qc index 63f503ad..8e489146 100644 --- a/qw.qc +++ b/qw.qc @@ -55,6 +55,11 @@ typedef void (float) f_void_float; .float queue_team; // The team the spy will change to after skin disguise is finished .float last_team; // The last team the spy disguised as .float feign_areachecked; // TRUE if area around spy has been checked for entities when feigned +.float aura_active; // TRUE if medic aura is active +.float aura_healamount; // Amount of health given to other players +.float aura_healcount; // Amount of players given health +.float aura_healtime; // Aura healing status will be shown in status bar until this time +.float regen_time; // Time when the medic last regenerated cells .float fragstreak; // Frag streak .float caps; // Caps during this game diff --git a/status.qc b/status.qc index 1f59df68..6163fde2 100644 --- a/status.qc +++ b/status.qc @@ -10,6 +10,7 @@ string(float num) GreenScoreToString; string(entity pl) ClipSizeToString; float(entity pl) GetClipSize; string(entity pl) DetpackToString; +string(entity pl) AuraToString; string(entity pl) AssaultCannonToString; string(entity pl) RangeToString; string(entity pl) ScannerToString; @@ -171,6 +172,8 @@ void (entity pl) RefreshStatusBar = { st1 = ScannerToString(pl); else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) st1 = DetpackToString(pl); + else if (pl.playerclass == PC_MEDIC) + st1 = AuraToString(pl); else if (pl.playerclass == PC_HVYWEAP) st1 = AssaultCannonToString(pl); else if (pl.playerclass == PC_SPY) @@ -438,6 +441,28 @@ string(entity pl) DetpackToString = return st; }; +string(entity pl) AuraToString = +{ + local string st = "Θεαμιξη Αυςα: "; + + if (pl.aura_active) { + if (time < pl.aura_healtime && pl.aura_healcount) { + st = strcat(st, ftos(pl.aura_healcount)); + st = strcat(st, " players healed for "); + st = strcat(st, ftos(pl.aura_healamount)); + st = strcat(st, " hp"); + } + else if (pl.ammo_cells < 100) + st = strcat(st, "recharging"); + else + st = strcat(st, "on"); + } else { + st = strcat(st, "off"); + } + + return st; +}; + string(entity pl) AssaultCannonToString = { if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_HALT)) diff --git a/tfort.qc b/tfort.qc index 38589a3c..e1176688 100644 --- a/tfort.qc +++ b/tfort.qc @@ -4,7 +4,7 @@ void (entity Player, float Armorclass) TeamFortress_DescribeArmor; void () TeamFortress_AmmoboxTouch; void () TeamFortress_ExplodePerson; -void () TeamFortress_Regenerate; +void () CF_Medic_Regenerate; void () TeamFortress_CheckforCheats; void () TeamFortress_RegenerateCells; void (entity pe_player, float f_type) CF_Identify; @@ -49,6 +49,8 @@ void () UseSpecialSkill = { self.impulse = TF_ZOOMTOGGLE; else if (self.playerclass == PC_DEMOMAN) self.impulse = TF_PB_DETONATE; + else if (self.playerclass == PC_MEDIC) + self.impulse = TF_MEDIC_AURA_TOGGLE; else if (self.playerclass == PC_SPY) self.impulse = TF_SPY_DIE; else if (self.playerclass == PC_ENGINEER) @@ -1692,7 +1694,19 @@ void () TeamFortress_SetEquipment = { te = spawn(); te.nextthink = time + PC_MEDIC_REGEN_TIME; - te.think = TeamFortress_Regenerate; + te.think = CF_Medic_Regenerate; + te.owner = self; + te.classname = "timer"; + + te = spawn(); + te.nextthink = time + PC_MEDIC_CELL_REGEN_TIME; + te.think = CF_Medic_RegenerateCells; + te.owner = self; + te.classname = "timer"; + + te = spawn(); + te.nextthink = time + PC_MEDIC_AURA_HEAL_TIME; + te.think = CF_Medic_AuraFindPlayers; te.owner = self; te.classname = "timer"; @@ -2760,34 +2774,6 @@ void (string halias, string commands) TeamFortress_AliasString = { stuffcmd(self, "\"\n"); }; -void () TeamFortress_Regenerate = { - if (self.owner.playerclass == PC_MEDIC) { - self.nextthink = time + PC_MEDIC_REGEN_TIME; - - if (self.owner.has_disconnected == 1) { - dremove(self); - return; - } - if (self.owner.health >= self.owner.max_health) - return; - - if (self.owner.ammo_medikit == 0) - return; - - if (self.owner.ammo_medikit < PC_MEDIC_REGEN_AMOUNT) { - self.owner.health = - self.owner.health + self.owner.ammo_medikit; - self.owner.ammo_medikit = 0; - } else { - self.owner.health = self.owner.health + PC_MEDIC_REGEN_AMOUNT; - self.owner.ammo_medikit = - self.owner.ammo_medikit - PC_MEDIC_REGEN_AMOUNT; - } - if (self.owner.health > self.owner.max_health) - self.owner.health = self.owner.max_health; - } -}; - void () TeamFortress_RegenerateCells = { if (self.owner.playerclass == PC_SPY) { self.nextthink = time + PC_SPY_CELL_REGEN_TIME; diff --git a/weapons.qc b/weapons.qc index eddc1b8f..b89a4ec5 100644 --- a/weapons.qc +++ b/weapons.qc @@ -54,6 +54,7 @@ void (float zoom_in) Sniper_ZoomAdjust; void () TeamFortress_StatusQuery; void () CF_Spy_DisguiseStop; void () TeamFortress_DetpackMenu; +void () CF_Medic_AuraToggle; void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; @@ -2257,6 +2258,8 @@ void () ImpulseCommands = { TeamFortress_DetonatePipebombs(); else if (self.impulse == TF_DETPACK_STOP) TeamFortress_DetpackStop(); + else if (self.impulse == TF_MEDIC_AURA_TOGGLE) + CF_Medic_AuraToggle(); else if ((self.impulse == TF_ENGINEER_DETSENTRY) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_sentrygun"); From c1db47fca96c5e11661e77a23f7034ddbad765c2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 18:48:54 +0200 Subject: [PATCH 0219/2474] Change the way medikit heals (closes #163) --- medic.qc | 13 ++++++++++--- weapons.qc | 41 ++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/medic.qc b/medic.qc index e16be3a6..8f4eb458 100644 --- a/medic.qc +++ b/medic.qc @@ -61,6 +61,9 @@ void () CF_Medic_AuraFindPlayers = { self.owner.aura_healamount = f_healtotal; self.owner.aura_healtime = time + 3; self.owner.aura_healcount = f_healcount; + self.owner.ammo_cells = self.owner.ammo_cells - f_healtotal; + if (self.owner.current_weapon == WEAP_MEDIKIT) + self.owner.currentammo = self.owner.ammo_cells; Status_Refresh(self.owner); } else if (time >= self.owner.aura_healtime && self.owner.aura_healcount) { self.owner.aura_healcount = 0; @@ -75,11 +78,15 @@ void () CF_Medic_RegenerateCells = { self.nextthink = time + PC_MEDIC_CELL_REGEN_TIME; if (self.owner.ammo_cells < 100) { - self.owner.ammo_cells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); - // refresh status bar if cells just hit 100 - if ((self.owner.ammo_cells + PC_MEDIC_CELL_REGEN_AMOUNT) > 100) + if ((self.owner.ammo_cells + PC_MEDIC_CELL_REGEN_AMOUNT) > 100) { + self.owner.ammo_cells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); Status_Refresh(self.owner); + } else { + self.owner.ammo_cells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); + } + if (self.owner.current_weapon == WEAP_MEDIKIT) + self.owner.currentammo = self.owner.ammo_cells; } }; diff --git a/weapons.qc b/weapons.qc index b89a4ec5..e7c34f9d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -490,33 +490,27 @@ void () W_FireMedikit = { } return; } - if ((healam > 0) && - (trace_ent.health < trace_ent.max_health)) { + if (trace_ent.health < (trace_ent.max_health + 50)) { - sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, - ATTN_NORM); - trace_ent.axhitme = 1; - SpawnBlood(org, 20); - T_Heal(trace_ent, healam, 0); - - } else if ((trace_ent.health >= trace_ent.max_health) - && (trace_ent.health < - (trace_ent.max_health + 50))) { + if (self.ammo_cells >= 50) { + healam = trace_ent.max_health - trace_ent.health + 50; + self.ammo_cells = 0; + sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); + } + else { + healam = min(10, ((trace_ent.max_health + 50) - trace_ent.health)); + self.ammo_cells = self.ammo_cells - min(self.ammo_cells, 5); + sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); + } - healam = 5; - if (healam > (self.ammo_medikit * 5)) - healam = self.ammo_medikit * 5; + if (self.current_weapon == WEAP_MEDIKIT) + self.currentammo = self.owner.ammo_cells; - if (healam > 0) { - sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, - ATTN_NORM); - T_Heal(trace_ent, healam, 1); - self.ammo_medikit = - self.ammo_medikit - rint(healam / 5); + T_Heal(trace_ent, healam, 1); + if (trace_ent.health > trace_ent.max_health) { if (!(trace_ent.items & IT_SUPERHEALTH)) { - trace_ent.items = - trace_ent.items | IT_SUPERHEALTH; + trace_ent.items = trace_ent.items | IT_SUPERHEALTH; newmis = spawn(); newmis.nextthink = time + 5; newmis.think = item_megahealth_rot; @@ -1451,9 +1445,10 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_MEDIKIT) { - pl.currentammo = pl.ammo_medikit; + pl.currentammo = pl.ammo_cells; pl.weaponmodel = "progs/v_medi.mdl"; pl.weaponframe = 0; + pl.items = pl.items | IT_CELLS; } else if (pl.current_weapon == WEAP_TRANQ) { pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { From 9ecba75371d489f8c8e366d330f53a98932deaa5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 19:36:02 +0200 Subject: [PATCH 0220/2474] Force menu when voting early (closes #173) --- vote.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vote.qc b/vote.qc index 54a12764..27fb50ab 100644 --- a/vote.qc +++ b/vote.qc @@ -69,6 +69,7 @@ void (entity pe_player) Vote_NextMap = { f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(0); + Vote_MenuOpen(1); //dprint("[", ftos(time), "/cf/mapvote/votenext]: forcing map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for next map\n"); } else { @@ -107,6 +108,7 @@ void (entity pe_player) Vote_TrickMap = { f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(2); + Vote_MenuOpen(1); //dprint("[", ftos(time), "/cf/mapvote/votetrick]: forcing trick map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for trick map\n"); } else { @@ -145,6 +147,7 @@ void (entity pe_player) Vote_RaceMap = { f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(3); + Vote_MenuOpen(1); //dprint("[", ftos(time), "/cf/mapvote/voterace]: forcing race map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for race map\n"); } else { From 38cf6f7b6a397cacd598423d69a94b0b143384f8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 20:42:36 +0200 Subject: [PATCH 0221/2474] Don't pick up useless ammo from discarded packs (closes #172) --- actions.qc | 8 ++-- qw.qc | 1 + tfort.qc | 115 +++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/actions.qc b/actions.qc index 7121f7d8..76647a37 100644 --- a/actions.qc +++ b/actions.qc @@ -7,15 +7,15 @@ void () TeamFortress_ClipTick; void () TeamFortress_Discard = { newmis = spawn(); if ((self.playerclass == PC_SCOUT) - || (self.playerclass == PC_SPY) - || (self.playerclass == PC_ENGINEER)) { + || (self.playerclass == PC_ENGINEER) + || (self.playerclass == PC_MEDIC)) { newmis.ammo_rockets = self.ammo_rockets; } else if ((self.playerclass == PC_SNIPER) - || (self.playerclass == PC_MEDIC)) { + || (self.playerclass == PC_SPY)) { newmis.ammo_rockets = self.ammo_rockets; newmis.ammo_cells = self.ammo_cells; } else if ((self.playerclass == PC_SOLDIER) - || (self.playerclass == PC_DEMOMAN)) { + || (self.playerclass == PC_DEMOMAN)) { newmis.ammo_cells = self.ammo_cells; newmis.ammo_nails = self.ammo_nails; } else if (self.playerclass == PC_HVYWEAP) { diff --git a/qw.qc b/qw.qc index 8e489146..ff8dbc4a 100644 --- a/qw.qc +++ b/qw.qc @@ -62,6 +62,7 @@ typedef void (float) f_void_float; .float regen_time; // Time when the medic last regenerated cells .float fragstreak; // Frag streak .float caps; // Caps during this game +.entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types .float tfstate; // State flags for TeamFortress .entity linked_list; // Used just like chain. Has to be separate so diff --git a/tfort.qc b/tfort.qc index e1176688..4b2af59f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1439,6 +1439,7 @@ void () TeamFortress_SetEquipment = { self.detpack_left = 0; self.fragstreak = 0; self.menu_time = 0; + self.nopickup = world; self.ammo_medikit = 0; self.maxammo_medikit = 0; @@ -2426,42 +2427,96 @@ void () TeamFortress_AmmoboxTouch = { return; if (other.health <= 0) return; + if (other.nopickup == self) + return; if (self.weapon == 0) { - other.ammo_shells = other.ammo_shells + self.ammo_shells; - other.ammo_nails = other.ammo_nails + self.ammo_nails; - other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; - other.ammo_cells = other.ammo_cells + self.ammo_cells; - } else if (self.weapon == 1) { - if (other.ammo_shells >= TeamFortress_GetMaxAmmo(other, 256)) - return; - other.ammo_shells = other.ammo_shells + self.aflag; - self.netname = "shells"; - } else if (self.weapon == 2) { - if (other.ammo_nails >= TeamFortress_GetMaxAmmo(other, 512)) - return; - other.ammo_nails = other.ammo_nails + self.aflag; - self.netname = "nails"; - } else if (self.weapon == 3) { - if (other.ammo_rockets >= TeamFortress_GetMaxAmmo(other, 1024)) - return; - other.ammo_rockets = other.ammo_rockets + self.aflag; - self.netname = "rockets"; - } else if (self.weapon == 4) { - if (other.ammo_cells >= TeamFortress_GetMaxAmmo(other, 2048)) - return; - other.ammo_cells = other.ammo_cells + self.aflag; - self.netname = "cells"; - } - bound_other_ammo(other); - if (self.weapon > 0) { + if ((other.playerclass == PC_SCOUT) + || (other.playerclass == PC_ENGINEER)) { + if (!(self.ammo_shells + self.ammo_nails + self.ammo_cells)) { + other.nopickup = self; + return; + } + other.ammo_shells = other.ammo_shells + self.ammo_shells; + self.ammo_shells = 0; + other.ammo_nails = other.ammo_nails + self.ammo_nails; + self.ammo_nails = 0; + other.ammo_cells = other.ammo_cells + self.ammo_cells; + self.ammo_cells = 0; + } else if ((other.playerclass == PC_SNIPER) + || (other.playerclass == PC_SPY) + || (other.playerclass == PC_MEDIC)) { + if (!(self.ammo_shells + self.ammo_nails)) { + other.nopickup = self; + return; + } + other.ammo_shells = other.ammo_shells + self.ammo_shells; + self.ammo_shells = 0; + other.ammo_nails = other.ammo_nails + self.ammo_nails; + self.ammo_nails = 0; + } else if ((other.playerclass == PC_SOLDIER) + || (other.playerclass == PC_DEMOMAN)) { + if (!(self.ammo_shells + self.ammo_rockets)) { + other.nopickup = self; + return; + } + other.ammo_shells = other.ammo_shells + self.ammo_shells; + self.ammo_shells = 0; + other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; + self.ammo_rockets = 0; + } else if (other.playerclass == PC_HVYWEAP) { + if (!(self.ammo_shells + self.ammo_cells)) { + other.nopickup = self; + return; + } + other.ammo_shells = other.ammo_shells + self.ammo_shells; + self.ammo_shells = 0; + other.ammo_cells = other.ammo_cells + self.ammo_cells; + self.ammo_cells = 0; + } else if (other.playerclass == PC_PYRO) { + if (!(self.ammo_shells + self.ammo_rockets + self.ammo_cells)) { + other.nopickup = self; + return; + } + other.ammo_shells = other.ammo_shells + self.ammo_shells; + self.ammo_shells = 0; + other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; + self.ammo_rockets = 0; + other.ammo_cells = other.ammo_cells + self.ammo_cells; + self.ammo_cells = 0; + } + other.nopickup = self; + if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) + dremove(self); + } else { + if (self.weapon == 1) { + if (other.ammo_shells >= TeamFortress_GetMaxAmmo(other, 256)) + return; + other.ammo_shells = other.ammo_shells + self.aflag; + self.netname = "shells"; + } else if (self.weapon == 2) { + if (other.ammo_nails >= TeamFortress_GetMaxAmmo(other, 512)) + return; + other.ammo_nails = other.ammo_nails + self.aflag; + self.netname = "nails"; + } else if (self.weapon == 3) { + if (other.ammo_rockets >= TeamFortress_GetMaxAmmo(other, 1024)) + return; + other.ammo_rockets = other.ammo_rockets + self.aflag; + self.netname = "rockets"; + } else if (self.weapon == 4) { + if (other.ammo_cells >= TeamFortress_GetMaxAmmo(other, 2048)) + return; + other.ammo_cells = other.ammo_cells + self.aflag; + self.netname = "cells"; + } quantity = ftos(self.aflag); - sprint(other, PRINT_LOW, "You picked up ", quantity, " ", - self.netname, "\n"); + sprint(other, PRINT_LOW, "You picked up ", quantity, " ", self.netname, "\n"); + dremove(self); } + bound_other_ammo(other); sound(other, 3, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); - dremove(self); self = other; W_SetCurrentAmmo(self); }; From a35f75087984500efc28b3a83e21db02e6369bb6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 20:43:52 +0200 Subject: [PATCH 0222/2474] Regenerate cells (medic) only once a second --- defs.h | 4 ++-- status.qc | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/defs.h b/defs.h index 7d9a81f9..ca805674 100644 --- a/defs.h +++ b/defs.h @@ -840,8 +840,8 @@ #define PC_MEDIC_AURA_HEAL_TIME 1 // Number of seconds between each aura heal. #define PC_MEDIC_AURA_HEAL_AMOUNT 5 // Amount of health given per aura heal. #define PC_MEDIC_AURA_RANGE 120 // The aura's range -#define PC_MEDIC_CELL_REGEN_TIME 0.5 // Number of seconds between each cell regen. -#define PC_MEDIC_CELL_REGEN_AMOUNT 5 // Amount of cells regenerated each cell regen. +#define PC_MEDIC_CELL_REGEN_TIME 1 // Number of seconds between each cell regen. +#define PC_MEDIC_CELL_REGEN_AMOUNT 10 // Amount of cells regenerated each cell regen. // Class Details for HVYWEAP #define PC_HVYWEAP_SKIN 2 diff --git a/status.qc b/status.qc index 6163fde2..24eebecd 100644 --- a/status.qc +++ b/status.qc @@ -452,7 +452,9 @@ string(entity pl) AuraToString = st = strcat(st, ftos(pl.aura_healamount)); st = strcat(st, " hp"); } - else if (pl.ammo_cells < 100) + else if (pl.ammo_cells < 50) + st = strcat(st, "out of power"); + else if (pl.ammo_cells < 95) st = strcat(st, "recharging"); else st = strcat(st, "on"); From ce41c4f81ba74951923f8b2356de2190f0c5216a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 20:44:22 +0200 Subject: [PATCH 0223/2474] Medic aura active from 50 cells and upward --- medic.qc | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/medic.qc b/medic.qc index 8f4eb458..843a1f3b 100644 --- a/medic.qc +++ b/medic.qc @@ -39,7 +39,7 @@ void () CF_Medic_AuraFindPlayers = { self.nextthink = time + PC_MEDIC_AURA_HEAL_TIME; - if (!self.owner.aura_active || self.owner.ammo_cells < 100) + if (!self.owner.aura_active || self.owner.ammo_cells < 50) return; e_find = findradius(self.owner.origin, PC_MEDIC_AURA_RANGE); @@ -62,29 +62,34 @@ void () CF_Medic_AuraFindPlayers = { self.owner.aura_healtime = time + 3; self.owner.aura_healcount = f_healcount; self.owner.ammo_cells = self.owner.ammo_cells - f_healtotal; - if (self.owner.current_weapon == WEAP_MEDIKIT) - self.owner.currentammo = self.owner.ammo_cells; Status_Refresh(self.owner); } else if (time >= self.owner.aura_healtime && self.owner.aura_healcount) { self.owner.aura_healcount = 0; self.owner.aura_healamount = 0; self.owner.aura_healtime = 0; } + + self.owner.ammo_cells = self.owner.ammo_cells - 5; + if (self.owner.current_weapon == WEAP_MEDIKIT) + self.owner.currentammo = self.owner.ammo_cells; }; // increases the medic's cells two times per second // called from tfort.qc:TeamFortress_SetEquipment() void () CF_Medic_RegenerateCells = { + local float f_newcells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); + self.nextthink = time + PC_MEDIC_CELL_REGEN_TIME; if (self.owner.ammo_cells < 100) { + self.owner.ammo_cells = f_newcells; + // refresh status bar if cells just hit 100 - if ((self.owner.ammo_cells + PC_MEDIC_CELL_REGEN_AMOUNT) > 100) { - self.owner.ammo_cells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); + if (f_newcells >= 100) Status_Refresh(self.owner); - } else { - self.owner.ammo_cells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); - } + else if (f_newcells >= 50 && f_newcells < 60) + Status_Refresh(self.owner); + if (self.owner.current_weapon == WEAP_MEDIKIT) self.owner.currentammo = self.owner.ammo_cells; } From a1daca92e00ccf7674196271d2b6a771ba30cbaa Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 20:45:41 +0200 Subject: [PATCH 0224/2474] Allow discard during reload (fixes #175) --- weapons.qc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/weapons.qc b/weapons.qc index e7c34f9d..f85a9441 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2217,8 +2217,7 @@ void () ImpulseCommands = { TeamFortress_SetDetpack(50); else if (self.impulse == TF_DROP_AMMO) { Menu_Drop(); - } else if (self.impulse == TF_DISCARD) - TeamFortress_Discard(); + } } if (self.impulse == TF_INVENTORY) @@ -2561,12 +2560,12 @@ void () W_WeaponFrame = { Menu_Team(); self.impulse = 0; return; - } - if (self.impulse == TF_CHANGECLASS) { + } else if (self.impulse == TF_CHANGECLASS) { Menu_Class(); self.impulse = 0; return; - } + } else if (self.impulse == TF_DISCARD) + TeamFortress_Discard(); if (intermission_running || cease_fire) return; From 3097b334a1da7bbd0e42a87cce9e315b78cf5fff Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 22:59:37 +0200 Subject: [PATCH 0225/2474] Medic no longer heals himself (fixes #177) --- medic.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/medic.qc b/medic.qc index 843a1f3b..9e564ff6 100644 --- a/medic.qc +++ b/medic.qc @@ -44,7 +44,7 @@ void () CF_Medic_AuraFindPlayers = { e_find = findradius(self.owner.origin, PC_MEDIC_AURA_RANGE); while (e_find != world) { - if (e_find.classname == "player" && e_find.team_no == self.owner.team_no) { + if (e_find != self.owner && e_find.classname == "player" && e_find.team_no == self.owner.team_no) { f_healamount = CF_Medic_AuraHealPlayer(e_find); f_healtotal = f_healtotal + f_healamount; if (f_healamount) From eae084cc92736bd3d0b560c8c5250a3c83928c9b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 23:03:27 +0200 Subject: [PATCH 0226/2474] Fix telefrag death message (fixes #176) --- client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 10a24a2a..51d53184 100644 --- a/client.qc +++ b/client.qc @@ -1912,7 +1912,7 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage if (pe_attacker.classname == "teledeath") { return strcat(pe_target.netname, strcat(" was telefragged by ", - strcat(pe_attacker.netname, "\n"))); + strcat(pe_attacker.owner.netname, "\n"))); } if (pf_deathmsg == 37) { return strcat(pe_attacker.netname, " shoots his teammate one too many times\n"); From a0765abf3422d4d4ab89ae157d6c3c0810685f47 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 23:09:49 +0200 Subject: [PATCH 0227/2474] Don't knockback dispenser or sentry gun (fixes #178) --- pyro.qc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyro.qc b/pyro.qc index 97f7f1fc..0d41d5b7 100644 --- a/pyro.qc +++ b/pyro.qc @@ -425,9 +425,11 @@ void () Flamer_stream_touch = { deathmsg = DMSG_FLAME; // knockback target - dir = other.origin - (self.absmin + self.absmax) * 0.5; - dir = normalize(dir); - other.velocity = other.velocity + dir * 300; + if (other.classname != "building_sentrygun" && other.classname != "building_dispenser") { + dir = other.origin - (self.absmin + self.absmax) * 0.5; + dir = normalize(dir); + other.velocity = other.velocity + dir * 300; + } TF_T_Damage(other, self, self.owner, 10, TF_TD_NOTTEAM, TF_TD_FIRE); From 87ecd9154a45bad4d03bf7055e40008f508cbb8b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 23:36:46 +0200 Subject: [PATCH 0228/2474] Add more suiting concussion grenade self explosion message for Medic (closes #174) --- tfort.qc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tfort.qc b/tfort.qc index 4b2af59f..fbdcc3cb 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2644,9 +2644,14 @@ void () TeamFortress_ExplodePerson = { else if (self.owner.playerclass == PC_DEMOMAN) bprint3(PRINT_MEDIUM, "Ack! ", self.owner.netname, "! The grenade is your friend for another reason!\n"); - else if (self.owner.playerclass == PC_MEDIC) - bprint3(PRINT_MEDIUM, "No ", self.owner.netname, - "! Assist your own suicide some other time!\n"); + else if (self.owner.playerclass == PC_MEDIC) { + if (self.weapon == GR_TYPE_CONCUSSION) + bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, + ", eating a concussion grenade is bad!\n"); + else + bprint3(PRINT_MEDIUM, "No ", self.owner.netname, + "! Assist your own suicide some other time!\n"); + } else if (self.owner.playerclass == PC_HVYWEAP) bprint3(PRINT_MEDIUM, "Hey ", self.owner.netname, ", you're not THAT heavy!\n"); From 521e756e31a55b9d393e54d4ccd0ca92a6ee9e96 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 23:40:28 +0200 Subject: [PATCH 0229/2474] Remove prime timer when spawning instead of when dying (fixes #182) --- client.qc | 8 ++++++++ tfort.qc | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/client.qc b/client.qc index 51d53184..34413cfc 100644 --- a/client.qc +++ b/client.qc @@ -997,6 +997,14 @@ void () PutClientInServer = { if (! self.last_playerclass) self.last_playerclass = self.playerclass; + // remove prime timers to avoid getting an old grenade in your face + te = find(world, classname, "primetimer"); + while (te != world) { + if (te.owner == self) + dremove(te); + te = find(te, classname, "primetimer"); + } + DecodeLevelParms(); if (self.playerclass == 0) { diff --git a/tfort.qc b/tfort.qc index fbdcc3cb..0dc79b6b 100644 --- a/tfort.qc +++ b/tfort.qc @@ -94,15 +94,6 @@ void () RemoveGrenadeTimers = { dremove(te); te = find(te, classname, "gtimer"); } - - if (self.health <= 0) { - te = find(world, classname, "primetimer"); - while (te != world) { - if (te.owner == self) - dremove(te); - te = find(te, classname, "primetimer"); - } - } }; void () RemoveGrenades = { From 0ddc46ead3340912c2d892b678f8a2f1b155e694 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 23:53:03 +0200 Subject: [PATCH 0230/2474] Add anti spam protection againts Assault Cannon cell missing message (fixes #181) --- qw.qc | 1 + tfort.qc | 9 ++++----- weapons.qc | 14 +++++++++----- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/qw.qc b/qw.qc index ff8dbc4a..fb89ea57 100644 --- a/qw.qc +++ b/qw.qc @@ -385,6 +385,7 @@ float already_chosen_map; // anti spam .float antispam_detpack; // don't spam detpack messages .float antispam_feign; // don't spam feign deaths +.float antispam_assault_cannon; // don't spam assault cannon messages // status bar stuff .string StatusString; // current centerprint text (strzone'd!) diff --git a/tfort.qc b/tfort.qc index 0dc79b6b..a3d2ae81 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2521,8 +2521,7 @@ void () TeamFortress_AssaultWeapon = { return; if (self.heat > 0) { - sprint(self, PRINT_HIGH, - "The assault cannon is still overheated\n"); + sprint(self, PRINT_HIGH, "The Assault Cannon is still overheated\n"); return; } @@ -2531,9 +2530,9 @@ void () TeamFortress_AssaultWeapon = { return; } - if (self.ammo_cells < 6) { - sprint(self, PRINT_HIGH, - "Not enough cells to power the assault cannon\n"); + if (self.ammo_cells < 7 && time >= self.antispam_assault_cannon) { + sprint(self, PRINT_HIGH, "Not enough cells to power the Assault Cannon\n"); + self.antispam_assault_cannon = time + 3; return; } self.current_weapon = WEAP_ASSAULT_CANNON; diff --git a/weapons.qc b/weapons.qc index f85a9441..511a253d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1767,10 +1767,12 @@ void () W_Attack = { W_FireAutoRifle(); Attack_Finished(0.1); } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (self.ammo_cells < 7) - sprint(self, PRINT_MEDIUM, - "Not enough cells to power up the Assault Cannon\n"); - else { + if (self.ammo_cells < 7) { + if (time >= self.antispam_assault_cannon) { + sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); + self.antispam_assault_cannon = time + 3; + } + } else { self.ammo_cells = self.ammo_cells - 7; self.heat = 1; self.immune_to_check = time + 5; @@ -2020,8 +2022,10 @@ void (float slot) W_WeaponSlot = { void () W_AmmoError = { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); - else if (self.noammo == 2) + else if (self.noammo == 2 && time >= self.antispam_assault_cannon) { sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); + self.antispam_assault_cannon = time + 3; + } }; void (entity pl) W_WeaponState_Save = { From b2161bd1943d0c912b0f66b305c7add9df20cecc Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 31 Aug 2014 23:55:42 +0200 Subject: [PATCH 0231/2474] Properly change weapon when Assault Cannon runs out of cells (fixes #180) --- weapons.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/weapons.qc b/weapons.qc index 511a253d..d1f6b11a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -10,6 +10,7 @@ void () SuperDamageSound; void () ConcussionGrenadeTimer; void () OldConcussionGrenadeTimer; +void (float inp) W_ChangeWeapon; void () W_ChangeToBestWeapon; void (float slot) W_WeaponSlot; void (entity pl) W_WeaponState_Save; @@ -1772,6 +1773,9 @@ void () W_Attack = { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); self.antispam_assault_cannon = time + 3; } + W_ChangeWeapon(W_BestWeaponSlot()); + W_SetCurrentAmmo(self); + W_WeaponState_Save(self); } else { self.ammo_cells = self.ammo_cells - 7; self.heat = 1; From f5b47bae97af5a35aabfb383006e07a595991df6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 1 Sep 2014 08:55:35 +0200 Subject: [PATCH 0232/2474] Update team and class menus every 0.5 seconds (closes #184 and #185) --- menu.qc | 65 +++++++++++++++++++++++++++++++++++++++++++++-------- tforthlp.qc | 2 +- weapons.qc | 8 +++---- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/menu.qc b/menu.qc index efa52f6d..f3de3840 100644 --- a/menu.qc +++ b/menu.qc @@ -54,8 +54,8 @@ float (float v) anglemod; void (float tno, entity ignore, string st) teamsprint; -void () Menu_Team; -void () Menu_Class; +void (float update) Menu_Team; +void (float update) Menu_Class; string (float pc, float tno) TeamFortress_ClassGetNoPlayersString; void () Menu_Drop; void () PlayerObserverMode; @@ -116,12 +116,23 @@ void (float inp) Menu_Team_Input = { } else if ((number_of_teams == 0) && (inp <= 4)) { TeamFortress_TeamSet(inp); } else { - Menu_Team(); + Menu_Team(0); return; } if ((self.playerclass == 0) && (self.lives != 0)) { - Menu_Class(); + Menu_Class(0); + } +}; + +void () Menu_Team_Update = { + if (self.owner.menu_input == Menu_Team_Input) { + self.nextthink = time + 0.5; + self = self.owner; + Menu_Team(1); + } else { + self.owner.has_menutimer = 0; + dremove(self); } }; @@ -146,12 +157,14 @@ string (float pf_team_no, string ps_team) Menu_Team_TeamString = { return strzone(s_string); }; -void () Menu_Team = { +void (float update) Menu_Team = { + local entity timer; + if (self.classname == "observer") Status_Menu(self, Menu_Team_Input, ""); // allow toggling team menu using any method to show it - if (self.menu_input == Menu_Team_Input) { + if (!update && self.menu_input == Menu_Team_Input) { Menu_Input(0); return; } @@ -176,6 +189,16 @@ void () Menu_Team = { s_green = Menu_Team_TeamString(4, s_green); s_auto = strpadr(s_auto, (strlen(s_blue) - 1)); + // update menu every 0.5 seconds + if (!self.has_menutimer) { + self.has_menutimer = 1; + timer = spawn(); + timer.classname = "menu_timer"; + timer.owner = self; + timer.think = Menu_Team_Update; + timer.nextthink = time + 0.5; + } + Status_Menu(self, Menu_Team_Input, s_select, s_blue, s_red, s_yellow, s_green, "\n", s_auto); strunzone(s_blue); strunzone(s_red); strunzone(s_yellow); strunzone(s_green); @@ -187,7 +210,7 @@ void (float inp) Menu_Class_Input = { // keep showing menu if class is invalid if (inp > 9 || !IsLegalClass(inp) || CF_ClassIsRestricted(self.team_no, inp)) - Menu_Class(); + Menu_Class(0); // don't try to change class if class is forbidden if (!IsLegalClass(inp) || CF_GetClassRestriction(self.team_no, inp) == -1) @@ -196,6 +219,17 @@ void (float inp) Menu_Class_Input = { TeamFortress_ChangeClass(inp); }; +void () Menu_Class_Update = { + if (self.owner.menu_input == Menu_Class_Input) { + self.nextthink = time + 0.5; + self = self.owner; + Menu_Class(1); + } else { + self.owner.has_menutimer = 0; + dremove(self); + } +}; + string (float pf_class, string ps_class) Menu_Class_ClassString = { local string s_string; local float f_gap = 5; @@ -224,8 +258,11 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { return strzone(s_string); }; -void () Menu_Class = { - if (self.menu_input == Menu_Class_Input) { +void (float update) Menu_Class = { + local entity timer; + + // allow toggling team menu using any method to show it + if (!update && self.menu_input == Menu_Class_Input) { Menu_Input(0); return; } @@ -281,6 +318,16 @@ void () Menu_Class = { s_engineer = Menu_Class_ClassString(PC_ENGINEER, s_engineer); s_randompc = Menu_Class_ClassString(PC_RANDOM, s_randompc); + // update menu every 0.5 seconds + if (!self.has_menutimer) { + self.has_menutimer = 1; + timer = spawn(); + timer.classname = "menu_timer"; + timer.owner = self; + timer.think = Menu_Class_Update; + timer.nextthink = time + 0.5; + } + // print out class menu self.menu_input = nil; if (TeamFortress_TeamIsCivilian(self.team_no)) diff --git a/tforthlp.qc b/tforthlp.qc index 68f0928d..08366a71 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -174,7 +174,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); } else if (self.motd == 400 && self.team_no == 0) { - Menu_Team(); + Menu_Team(0); } self.motd = self.motd + 1; diff --git a/weapons.qc b/weapons.qc index d1f6b11a..2095ff27 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2375,10 +2375,10 @@ void () DeadImpulses = { TeamFortress_ChangeClass(self.impulse - 100); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGETEAM) && (deathmatch == 3) && (cb_prematch_time < time)) { - Menu_Team(); + Menu_Team(0); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGECLASS) && (deathmatch == 3) && (cb_prematch_time < time)) { - Menu_Class(); + Menu_Class(0); } else if (self.is_admin == 1) { if (self.impulse == 193) Admin_CeaseFire(); @@ -2565,11 +2565,11 @@ void () W_WeaponFrame = { } if (self.impulse == TF_CHANGETEAM) { - Menu_Team(); + Menu_Team(0); self.impulse = 0; return; } else if (self.impulse == TF_CHANGECLASS) { - Menu_Class(); + Menu_Class(0); self.impulse = 0; return; } else if (self.impulse == TF_DISCARD) From 96a1637efd8610a428a9486aa77b4137542b3523 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 1 Sep 2014 09:07:20 +0200 Subject: [PATCH 0233/2474] Bioweapon now does 7 damage per second (closes #164) --- medic.qc | 63 +++++++++++++++++++++++++++++++++++++++++++++++- tfort.qc | 71 ------------------------------------------------------ weapons.qc | 2 +- 3 files changed, 63 insertions(+), 73 deletions(-) diff --git a/medic.qc b/medic.qc index 9e564ff6..1afe0f89 100644 --- a/medic.qc +++ b/medic.qc @@ -117,4 +117,65 @@ void () CF_Medic_Regenerate = { } if (self.owner.health > self.owner.max_health) self.owner.health = self.owner.max_health; -} \ No newline at end of file +} + +void () BioInfection_Decay = { + local entity te; + local entity Bio; + + if ((teamplay & TFSTATE_INFECTED) && self.owner.team_no == self.enemy.team_no && self.owner.team_no) { + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_INFECTED); + dremove(self); + return; + } else if (self.invincible_finished > time) { + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_INFECTED); + dremove(self); + return; + } + + // stop infection timer if no longer infected or if medic + if (!(self.owner.tfstate & TFSTATE_INFECTED) || self.owner.playerclass == PC_MEDIC) { + dremove(self); + return; + } + + // poison teammates that come too close + te = findradius(self.owner.origin, 80); + while (te != world && te != self.owner) { + if (te.classname == "player" && te.deadflag == 0 && te.playerclass) { + if (!(te.tfstate & TFSTATE_INFECTED)) { + if (te.playerclass != PC_MEDIC) { + if (!((teamplay & TEAMPLAY_NOEXPLOSIVE) && self.owner.team_no == self.enemy.team_no && self.owner.team_no)) { + Bio = spawn(); + Bio.nextthink = 2; + Bio.think = BioInfection_Decay; + Bio.owner = te; + Bio.classname = "timer"; + Bio.enemy = self.enemy; + + te.tfstate = te.tfstate | TFSTATE_INFECTED; + te.infection_team_no = self.owner.infection_team_no; + + sprint(te, PRINT_MEDIUM, "You have been infected by ", self.owner.netname, "\n"); + sprint(self.owner, PRINT_MEDIUM, "You have infected ", te.netname, "\n"); + } + } + } + } + te = te.chain; + } + self.nextthink = time + 1; + deathmsg = DMSG_BIOWEAPON; + TF_T_Damage(self.owner, self, self.enemy, 8, TF_TD_IGNOREARMOUR, TF_TD_OTHER); + SpawnBlood(self.owner.origin, 30); +}; + +void () BioInfection_MonsterDecay = { + self.nextthink = time + 2; + + T_Damage(self.enemy, self, self.owner, 5); + SpawnBlood(self.enemy.origin, 20); + + if (self.enemy.health < 1) + dremove(self); +}; diff --git a/tfort.qc b/tfort.qc index a3d2ae81..389bc3d0 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2728,77 +2728,6 @@ void () TeamFortress_DisplayDetectionItems = { } }; -void () BioInfection_Decay = { - local entity te; - local entity Bio; - - if ((teamplay & 16) && (self.owner.team_no == self.enemy.team_no) && - (self.owner.team_no != 0)) { - self.owner.tfstate = - self.owner.tfstate - (self.owner.tfstate & 16); - dremove(self); - return; - } else if (self.invincible_finished > time) { - self.owner.tfstate = - self.owner.tfstate - (self.owner.tfstate & 16); - dremove(self); - return; - } - if (!(self.owner.tfstate & TFSTATE_INFECTED) || - (self.owner.playerclass == PC_MEDIC)) { - dremove(self); - return; - } - te = findradius(self.owner.origin, 80); - while ((te != world) && (te != self.owner)) { - if ((te.classname == "player") && (te.deadflag == 0) && - (te.playerclass != 0)) { - if (!(te.tfstate & TFSTATE_INFECTED)) { - if (te.playerclass != PC_MEDIC) { - if (! - ((teamplay & 16) && - (self.owner.team_no == self.enemy.team_no) - && (self.owner.team_no != 0))) { - - Bio = spawn(); - Bio.nextthink = 2; - Bio.think = BioInfection_Decay; - Bio.owner = te; - Bio.classname = "timer"; - Bio.enemy = self.enemy; - - te.tfstate = te.tfstate | TFSTATE_INFECTED; - te.infection_team_no = - self.owner.infection_team_no; - - sprint(te, PRINT_MEDIUM, - "You have been infected by ", - self.owner.netname, "\n"); - sprint(self.owner, PRINT_MEDIUM, - "You have infected ", te.netname, "\n"); - } - } - } - } - te = te.chain; - } - self.nextthink = time + 3; - deathmsg = DMSG_BIOWEAPON; - TF_T_Damage(self.owner, self, self.enemy, 8, TF_TD_IGNOREARMOUR, - TF_TD_OTHER); - SpawnBlood(self.owner.origin, 30); -}; - -void () BioInfection_MonsterDecay = { - self.nextthink = time + 2; - - T_Damage(self.enemy, self, self.owner, 5); - SpawnBlood(self.enemy.origin, 20); - - if (self.enemy.health < 1) - dremove(self); -}; - void (string halias, float himpulse1, float himpulse2) TeamFortress_Alias = { local string imp; diff --git a/weapons.qc b/weapons.qc index 2095ff27..993aecf0 100644 --- a/weapons.qc +++ b/weapons.qc @@ -537,7 +537,7 @@ void () W_FireMedikit = { BioInfection = spawn(); BioInfection.classname = "timer"; BioInfection.owner = trace_ent; - BioInfection.nextthink = time + 2; + BioInfection.nextthink = time + 1; BioInfection.think = BioInfection_Decay; BioInfection.enemy = self; trace_ent.infection_team_no = self.team_no; From f814a102f349ec36f2e8fe1d2ff4d738fef38554 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 1 Sep 2014 09:07:36 +0200 Subject: [PATCH 0234/2474] Fix memory bug related to class menu --- menu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index f3de3840..d20ef755 100644 --- a/menu.qc +++ b/menu.qc @@ -246,7 +246,7 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { s_string = strpadr(s_string, (5 + f_gap)); s_string = strcat(s_string, ftos(f_max)); s_string = strcat(s_string, "\n"); - s_string = strzone(strcat(ps_class, s_string)); + s_string = strcat(ps_class, s_string); } else { if (TeamFortress_TeamGetNoPlayers(self.team_no) >= 10) s_string = strpadr(ps_class, (12 + f_gap - 3)); From 51a96a06cc6f6932db0ff6aecc69abe36807da08 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 1 Sep 2014 09:52:33 +0200 Subject: [PATCH 0235/2474] Add /togglevote to toggle the map voting on/off at any time (closes #186) --- client.qc | 1 + defs.h | 1 + qw.qc | 1 + tforthlp.qc | 1 + vote.qc | 21 ++++++++++++++++++++- weapons.qc | 3 ++- 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index 34413cfc..987f604c 100644 --- a/client.qc +++ b/client.qc @@ -985,6 +985,7 @@ void () PutClientInServer = { self.effects = 0; self.invincible_time = 0; self.spawn_time = time; + self.vote_close = 0; self.reload_shotgun = 0; self.reload_super_shotgun = 0; diff --git a/defs.h b/defs.h index ca805674..e6b6a711 100644 --- a/defs.h +++ b/defs.h @@ -374,6 +374,7 @@ #define TF_VOTETRICK 71 #define TF_VOTERACE 72 #define TF_FORCENEXT 73 +#define TF_TOGGLEVOTE 74 // Reload impulses #define TF_RELOAD_NEXT 80 diff --git a/qw.qc b/qw.qc index fb89ea57..0e76fa37 100644 --- a/qw.qc +++ b/qw.qc @@ -46,6 +46,7 @@ typedef void (float) f_void_float; .float vote_trick; // TRUE if player has voted for a trick map vote .float vote_race; // TRUE if player has voted for a race map vote .float force_next; // TRUE if player has voted to force next map +.float vote_close; // TRUE if player has closed the map vote, resets on spawn .float detpack_left; // Seconds left to detpack explosion .float pipecooldown; // Time when detpipe command can be issued .float disguise_skin; // The skin the spy is changing to diff --git a/tforthlp.qc b/tforthlp.qc index 08366a71..7e821fd0 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -120,6 +120,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); TeamFortress_Alias("voterace", TF_VOTERACE, 0); TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); + TeamFortress_Alias("togglevote", TF_TOGGLEVOTE, 0); TeamFortress_Alias("dreset", TF_DISGUISE_RESET, 0); TeamFortress_Alias("dscout", TF_DISGUISE_SCOUT, 0); TeamFortress_Alias("dsniper", TF_DISGUISE_SNIPER, 0); diff --git a/vote.qc b/vote.qc index 27fb50ab..b65981d8 100644 --- a/vote.qc +++ b/vote.qc @@ -158,6 +158,25 @@ void (entity pe_player) Vote_RaceMap = { } }; +// opens/closes the currently active vote menu +// called from weapons.qc:ImpulseCommands() +void (entity pe_player) Vote_ToggleMenu = { + if (vote_started > 0 && !vote_abort) { + if (pe_player.menu_input != Vote_Input) { + //dprint("[", ftos(time), "/cf/mapvote/togglemenu]: toggling map vote on for ", pe_player.netname, ".\n"); + pe_player.menu_time = time; + pe_player.vote_close = 0; + Vote_Menu(pe_player); + } else { + //dprint("[", ftos(time), "/cf/mapvote/togglemenu]: toggling map vote off for ", pe_player.netname, ".\n"); + pe_player.vote_close = 1; + Menu_Close(pe_player); + } + } else { + sprint(pe_player, PRINT_HIGH, "There is no active map vote\n"); + } +} + // returns the total amount of vote_next votes // called from Vote_NextMap() float () Vote_GetNextVotes = { @@ -423,7 +442,7 @@ void (float force) Vote_MenuOpen = { while (e_player != world) { if (e_player.team_no && e_player.playerclass) { - if (!e_player.has_voted_map && e_player.health) { + if (!e_player.has_voted_map && e_player.health && !e_player.vote_close) { if (((time - e_player.spawn_time) <= CF_MAPVOTE_FORCESHOW || (time - e_player.menu_time) <= CF_MAPVOTE_FORCESHOW) && !force) { //dprint("[", ftos(time), "/cf/mapvote/menuopen]: open vote menu for newly spawned ", e_player.netname, ".\n"); diff --git a/weapons.qc b/weapons.qc index 993aecf0..5bb01da5 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2189,7 +2189,8 @@ void () ImpulseCommands = { TeamFortress_EngineerBuildStop(); CycleWeaponLast(); } - } + } else if (self.impulse == TF_TOGGLEVOTE) + Vote_ToggleMenu(self); if (!self.is_feigning) { if (self.impulse == TF_GRENADE_1) From 5763c433719858711ccdc769da6a574ad2fa7b80 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 1 Sep 2014 10:47:16 +0200 Subject: [PATCH 0236/2474] Stop forcing vote menu when voting early (no longer needed due to togglevote command) --- vote.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/vote.qc b/vote.qc index b65981d8..6607deb1 100644 --- a/vote.qc +++ b/vote.qc @@ -69,7 +69,6 @@ void (entity pe_player) Vote_NextMap = { f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(0); - Vote_MenuOpen(1); //dprint("[", ftos(time), "/cf/mapvote/votenext]: forcing map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for next map\n"); } else { @@ -108,7 +107,6 @@ void (entity pe_player) Vote_TrickMap = { f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(2); - Vote_MenuOpen(1); //dprint("[", ftos(time), "/cf/mapvote/votetrick]: forcing trick map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for trick map\n"); } else { @@ -147,7 +145,6 @@ void (entity pe_player) Vote_RaceMap = { f_votes_left = f_votes_needed - f_votes; if (f_votes >= f_votes_needed) { Vote_SetupVote(3); - Vote_MenuOpen(1); //dprint("[", ftos(time), "/cf/mapvote/voterace]: forcing race map vote.\n"); bprint(PRINT_HIGH, "Commencing vote for race map\n"); } else { From 1dd61acd8de5f4f4ee8cd6f0bc718a1397bcb141 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 3 Sep 2014 09:07:39 +0200 Subject: [PATCH 0237/2474] Implement Scout dash (closes #187) --- client.qc | 6 ++++++ defs.h | 4 ++++ qw.qc | 1 + scout.qc | 37 +++++++++++++++++++++++++++++++++++++ tfort.qc | 2 +- tforthlp.qc | 1 + weapons.qc | 7 +++++-- 7 files changed, 55 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index 987f604c..114c2bda 100644 --- a/client.qc +++ b/client.qc @@ -397,6 +397,12 @@ void () DecodeLevelParms = { if (st == "on") toggleflags = toggleflags | TFLAG_SPAWNFULL; + st = infokey(world, "sd"); + if (st == string_null) + st = infokey(world, "scoutdash"); + if (st != "off") + toggleflags = toggleflags | TFLAG_SCOUTDASH; + st = infokey(world, "rd"); if (st == string_null) st = infokey(world, "respawn_delay"); diff --git a/defs.h b/defs.h index e6b6a711..177b973d 100644 --- a/defs.h +++ b/defs.h @@ -281,6 +281,7 @@ #define TFLAG_WARSTANDARD 8192 #define TFLAG_SNIPERRELOAD 16384 // Sniper reload enabled #define TFLAG_SPAWNFULL 32768 // Spawn fully stocked +#define TFLAG_SCOUTDASH 65536 // Scout dash enabled #define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn #define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn @@ -450,6 +451,9 @@ #define TF_GRENADE_PT_1 154 // Prime and throw grenade type 1 (two clicks) #define TF_GRENADE_PT_2 155 // Prime and throw grenade type 2 (two clicks) +// Scout dash +#define TF_DASH 157 // Initialize a forward bunnyhop for Scout + // Impulses for new items #define TF_HALT 157 // Stop firing Assault Cannon #define TF_UNHALT 158 // Resume firing Assault Cannon diff --git a/qw.qc b/qw.qc index 0e76fa37..0bceb7ce 100644 --- a/qw.qc +++ b/qw.qc @@ -61,6 +61,7 @@ typedef void (float) f_void_float; .float aura_healcount; // Amount of players given health .float aura_healtime; // Aura healing status will be shown in status bar until this time .float regen_time; // Time when the medic last regenerated cells +.float dash_cooldown; // Cooldown for Scout dash .float fragstreak; // Frag streak .float caps; // Caps during this game .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types diff --git a/scout.qc b/scout.qc index 53857b7f..4a721160 100644 --- a/scout.qc +++ b/scout.qc @@ -16,6 +16,43 @@ void (entity inflictor, entity attacker, float bounce, entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; +void () CF_Scout_Dash = { + local float f_velocity; + local float f_addvelocity; + local float f_scoutmax = (PC_SCOUT_MAXSPEED * 2); + + // check if dash is allowed in rules and if cooldown has ended + if (!(toggleflags & TFLAG_SCOUTDASH) || time < self.dash_cooldown) + return; + + // determine current speed + f_velocity = floor(fabs(self.velocity_x) + fabs(self.velocity_z)); + + // add different speeds depending on current speed + if (f_velocity < 500) + f_addvelocity = floor(f_scoutmax - f_velocity); + else if (f_velocity < f_scoutmax) + f_addvelocity = floor(min(200, (f_scoutmax - f_velocity))); + else + f_addvelocity = 100; + + // calculate new velocity + makevectors(self.angles); + self.velocity = self.velocity + v_forward * f_addvelocity; + + // add jump height (and jump sound) if player is on ground + if (self.flags & FL_ONGROUND) { + sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + self.velocity_z = 250; + + // if player is falling (z velocity < 0) then reset falling speed to 0 + } else if (self.velocity_z < 0) + self.velocity_z = 0; + + // only allow dash to be used every 3 seconds + self.dash_cooldown = time + 3; +} + void () CanisterTouch = { sound(self, 1, "weapons/tink1.wav", 1, 1); diff --git a/tfort.qc b/tfort.qc index 389bc3d0..aa97e32f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -44,7 +44,7 @@ void () UseSpecialSkill = { self.impulse = 0; if (self.playerclass == PC_SCOUT) - self.impulse = TF_SCAN; + self.impulse = TF_DASH; else if (self.playerclass == PC_SNIPER) self.impulse = TF_ZOOMTOGGLE; else if (self.playerclass == PC_DEMOMAN) diff --git a/tforthlp.qc b/tforthlp.qc index 7e821fd0..5a403342 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -76,6 +76,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("reload2", TF_RELOAD_SLOT2, 0); TeamFortress_Alias("reload3", TF_RELOAD_SLOT3, 0); TeamFortress_Alias("reloadnext", TF_RELOAD_NEXT, 0); + TeamFortress_Alias("dash", TF_DASH, 0); TeamFortress_Alias("autoscan", TF_SCAN, 0); TeamFortress_Alias("scansound", TF_SCAN_SOUND, 0); TeamFortress_Alias("scan10", TF_SCAN, 0); diff --git a/weapons.qc b/weapons.qc index 5bb01da5..cc59900d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -53,6 +53,7 @@ void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; void (float zoom_in) Sniper_ZoomAdjust; void () TeamFortress_StatusQuery; +void () CF_Scout_Dash; void () CF_Spy_DisguiseStop; void () TeamFortress_DetpackMenu; void () CF_Medic_AuraToggle; @@ -2257,6 +2258,8 @@ void () ImpulseCommands = { TeamFortress_ShowIDs(); else if ((self.playerclass != 0) && (self.impulse == TF_DROPFLAG)) DropGoalItems(); + else if (self.impulse == TF_DASH) + CF_Scout_Dash(); else if (self.impulse == TF_PB_DETONATE) TeamFortress_DetonatePipebombs(); else if (self.impulse == TF_DETPACK_STOP) @@ -2617,8 +2620,8 @@ void () W_WeaponFrame = { return; } - // medic /saveme - if (self.impulse == TF_MEDIC_HELPME) { + // medic /saveme, scout /dash + if (self.impulse == TF_MEDIC_HELPME || self.impulse == TF_DASH) { ImpulseCommands(); return; } From 8a0205cabb75285ba0f00ae229705f8866e192f2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 3 Sep 2014 09:08:31 +0200 Subject: [PATCH 0238/2474] Merge some impulse checks --- weapons.qc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/weapons.qc b/weapons.qc index cc59900d..e8577e1b 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2258,6 +2258,8 @@ void () ImpulseCommands = { TeamFortress_ShowIDs(); else if ((self.playerclass != 0) && (self.impulse == TF_DROPFLAG)) DropGoalItems(); + else if (self.impulse == TF_DISCARD) + TeamFortress_Discard(); else if (self.impulse == TF_DASH) CF_Scout_Dash(); else if (self.impulse == TF_PB_DETONATE) @@ -2576,8 +2578,7 @@ void () W_WeaponFrame = { Menu_Class(0); self.impulse = 0; return; - } else if (self.impulse == TF_DISCARD) - TeamFortress_Discard(); + } if (intermission_running || cease_fire) return; @@ -2620,8 +2621,8 @@ void () W_WeaponFrame = { return; } - // medic /saveme, scout /dash - if (self.impulse == TF_MEDIC_HELPME || self.impulse == TF_DASH) { + // /saveme, /dash, /discard + if (self.impulse == TF_MEDIC_HELPME || self.impulse == TF_DASH || self.impulse == TF_DISCARD) { ImpulseCommands(); return; } From 33ae8f06f709ffcfeea2f41958ba718330e982f5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 3 Sep 2014 09:08:56 +0200 Subject: [PATCH 0239/2474] Move toggle scanner into scanner menu --- menu.qc | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/menu.qc b/menu.qc index d20ef755..a881102f 100644 --- a/menu.qc +++ b/menu.qc @@ -364,10 +364,12 @@ void () Menu_Drop = { void (float inp) Menu_Scout_Input = { if (inp == 1) - self.impulse = TF_SCAN_ENEMY; + self.impulse = TF_SCAN; else if (inp == 2) - self.impulse = TF_SCAN_FRIENDLY; + self.impulse = TF_SCAN_ENEMY; else if (inp == 3) + self.impulse = TF_SCAN_FRIENDLY; + else if (inp == 4) self.impulse = TF_SCAN_SOUND; else self.impulse = 0; @@ -375,26 +377,31 @@ void (float inp) Menu_Scout_Input = { void () Menu_Scout = { local string s_action = "Scanner settings:\n\n"; - local string s_scane, s_scanf, s_scansound; + local string s_scan, s_scane, s_scanf, s_scansound; local string s_nothing = "\n—‘ Nothing \n\n"; + if (!self.ScannerOn) + s_scan = "“‘ Turn Scanner on \n"; + else + s_scan = "“‘ Turn Scanner off \n"; + if (self.tf_items_flags & NIT_SCANNER_ENEMY) - s_scane = "“‘ Do not scan for enemies \n"; + s_scane = "”‘ Do not scan for enemies \n"; else - s_scane = "“‘ Scan for enemies \n"; + s_scane = "”‘ Scan for enemies \n"; if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) - s_scanf = "”‘ Do not scan for friendlies\n"; + s_scanf = "•‘ Do not scan for friendlies\n"; else - s_scanf = "”‘ Scan for friendlies \n"; + s_scanf = "•‘ Scan for friendlies \n"; if (self.tf_items_flags & 4) - s_scansound = "•‘ Turn off scan sound \n"; + s_scansound = "–‘ Turn off scan sound \n"; else - s_scansound = "•‘ Turn on scan sound \n"; + s_scansound = "–‘ Turn on scan sound \n"; - Status_Menu(self, Menu_Scout_Input, s_action, s_scane, s_scanf, s_scansound, s_nothing); + Status_Menu(self, Menu_Scout_Input, s_action, s_scan, s_scane, s_scanf, s_scansound, s_nothing); }; void (float inp) Menu_Spy_Input = { From 7c61dcb796f0fd8a70aed59c9504ab88dde9f50e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 5 Sep 2014 20:41:14 +0200 Subject: [PATCH 0240/2474] Fix quick slot override when placing detpacks (fixes #188) --- weapons.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index e8577e1b..e680b709 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2524,7 +2524,8 @@ void () W_WeaponFrame = { } // slot 1-4 binds - if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady(self) && !self.is_building) { + if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady(self) + && !self.is_building && !self.is_detpacking) { // load weapon state if current state doesn't match stored state if (!W_WeaponState_Check(self)) @@ -2544,7 +2545,8 @@ void () W_WeaponFrame = { W_WeaponState_Load(self, 0); // +slot1-4 quick fire - } else if (self.impulse >= 31 && self.impulse <= 34) { + } else if (self.impulse >= 31 && self.impulse <= 34 + && !self.is_building && !self.is_detpacking) { self.is_quickfiring = 1; self.has_quickfired = 0; From 3c22dd4b9f7987a1ec9f274a150758907a8d7740 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 5 Sep 2014 21:04:03 +0200 Subject: [PATCH 0241/2474] Nerf dash --- scout.qc | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/scout.qc b/scout.qc index 4a721160..14ca383c 100644 --- a/scout.qc +++ b/scout.qc @@ -18,8 +18,6 @@ entity(entity scanner, float scanrange, float enemies, void () CF_Scout_Dash = { local float f_velocity; - local float f_addvelocity; - local float f_scoutmax = (PC_SCOUT_MAXSPEED * 2); // check if dash is allowed in rules and if cooldown has ended if (!(toggleflags & TFLAG_SCOUTDASH) || time < self.dash_cooldown) @@ -28,29 +26,13 @@ void () CF_Scout_Dash = { // determine current speed f_velocity = floor(fabs(self.velocity_x) + fabs(self.velocity_z)); - // add different speeds depending on current speed - if (f_velocity < 500) - f_addvelocity = floor(f_scoutmax - f_velocity); - else if (f_velocity < f_scoutmax) - f_addvelocity = floor(min(200, (f_scoutmax - f_velocity))); - else - f_addvelocity = 100; - - // calculate new velocity - makevectors(self.angles); - self.velocity = self.velocity + v_forward * f_addvelocity; - - // add jump height (and jump sound) if player is on ground - if (self.flags & FL_ONGROUND) { + // only dash if walking or slower + if (f_velocity <= 448 && (self.flags & FL_ONGROUND)) { + makevectors(self.angles); + self.velocity = v_forward * 540; + self.velocity_z = 190; sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); - self.velocity_z = 250; - - // if player is falling (z velocity < 0) then reset falling speed to 0 - } else if (self.velocity_z < 0) - self.velocity_z = 0; - - // only allow dash to be used every 3 seconds - self.dash_cooldown = time + 3; + } } void () CanisterTouch = From 5eb26a41c2829fdfbc01bd3dbbe36eea95ff5e38 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 5 Sep 2014 21:04:28 +0200 Subject: [PATCH 0242/2474] Don't allow dash when concussed or with leg damage --- qw.qc | 1 + scout.qc | 7 +++++++ tfort.qc | 2 ++ 3 files changed, 10 insertions(+) diff --git a/qw.qc b/qw.qc index 0bceb7ce..ee73571f 100644 --- a/qw.qc +++ b/qw.qc @@ -30,6 +30,7 @@ typedef void (float) f_void_float; .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float is_quickfiring; // TRUE for a player if they're using the quick slots +.float is_concussed; // TRUE for a player who is affected by concussion grenade .float has_quickfired; // TRUE for a player that has stopped quick firing (until weapon is ready) .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer diff --git a/scout.qc b/scout.qc index 14ca383c..9d24be66 100644 --- a/scout.qc +++ b/scout.qc @@ -23,6 +23,10 @@ void () CF_Scout_Dash = { if (!(toggleflags & TFLAG_SCOUTDASH) || time < self.dash_cooldown) return; + // don't dash if scout is concussed or have damaged legs + if (self.leg_damage || self.is_concussed) + return; + // determine current speed f_velocity = floor(fabs(self.velocity_x) + fabs(self.velocity_z)); @@ -287,6 +291,7 @@ void () ConcussionGrenadeTimer = { if (self.owner.invincible_finished > time) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); self.owner.fixangle = 0; + self.owner.is_concussed = 0; dremove(self); return; } @@ -347,6 +352,7 @@ void () ConcussionGrenadeTimer = { } if (self.health <= 0) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); + self.owner.is_concussed = 0; dremove(self); } }; @@ -597,6 +603,7 @@ void (entity inflictor, entity attacker, float bounce, te.classname = "timer"; te.owner = head; te.health = 750; + self.owner.is_concussed = 1; } } } diff --git a/tfort.qc b/tfort.qc index aa97e32f..1828e787 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1425,6 +1425,7 @@ void () TeamFortress_SetEquipment = { self.is_undercover = 0; self.is_feigning = 0; self.is_unabletospy = 0; + self.is_concussed = 0; self.disguise_skin = 0; self.disguise_team = 0; self.detpack_left = 0; @@ -2088,6 +2089,7 @@ void () TeamFortress_RemoveTimers = { local entity te; self.leg_damage = 0; + self.is_concussed = 0; self.is_undercover = 0; self.is_building = 0; self.building = world; From b35da9441f5a9d5fc347ba6a730bc4af9e124740 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 6 Sep 2014 22:23:55 +0200 Subject: [PATCH 0243/2474] Zoomtoggle command now works --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index e680b709..61b96da7 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2602,7 +2602,7 @@ void () W_WeaponFrame = { } if (self.playerclass == PC_SNIPER) { - if (self.impulse == TF_SPECIAL_SKILL) { + if (self.impulse == TF_ZOOMTOGGLE) { Sniper_ZoomToggle(); self.impulse = 0; return; From 3385b77aca661c3046a2e8ad28ebf778bdfa333d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 6 Sep 2014 22:36:02 +0200 Subject: [PATCH 0244/2474] Add /aura command for Medic --- tforthlp.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tforthlp.qc b/tforthlp.qc index 5a403342..69d0d371 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -84,6 +84,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("scan100", TF_SCAN, 0); TeamFortress_Alias("scanf", TF_SCAN_FRIENDLY, 0); TeamFortress_Alias("scane", TF_SCAN_ENEMY, 0); + TeamFortress_Alias("aura", TF_MEDIC_AURA_TOGGLE, 0); } else if (self.motd == 35) { TeamFortress_Alias("primeone", TF_GRENADE_1, 0); TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); From cff9a779f41375d5a874b9c1eeb6335de61bb397 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 6 Sep 2014 23:01:28 +0200 Subject: [PATCH 0245/2474] Add /locktoggle command for HWGuy --- defs.h | 5 ++--- player.qc | 4 ++-- status.qc | 2 +- tforthlp.qc | 5 +++-- weapons.qc | 13 +++++-------- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/defs.h b/defs.h index 177b973d..ab17ca83 100644 --- a/defs.h +++ b/defs.h @@ -233,7 +233,7 @@ #define TFSTATE_BURNING 512 // Is on fire #define TFSTATE_GRENTHROWING 1024 // is throwing a grenade #define TFSTATE_AIMING 2048 // is using the laser sight -#define TFSTATE_HALT 4096 // this state will stop hwguy from shooting assault cannon +#define TFSTATE_LOCK 4096 // this state will stop hwguy from shooting assault cannon #define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire #define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating #define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised @@ -455,8 +455,7 @@ #define TF_DASH 157 // Initialize a forward bunnyhop for Scout // Impulses for new items -#define TF_HALT 157 // Stop firing Assault Cannon -#define TF_UNHALT 158 // Resume firing Assault Cannon +#define TF_LOCK 157 // Toggle Assault Cannon spinning #define TF_SCAN 159 // Scanner Pre-Impulse #define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies #define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies diff --git a/player.qc b/player.qc index c35af1e6..95664caf 100644 --- a/player.qc +++ b/player.qc @@ -403,7 +403,7 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { void () player_assaultcannon1 =[103, player_assaultcannon2] { local string st; - if (vlen(self.velocity) <= 90 && !(self.tfstate & TFSTATE_HALT)) { + if (vlen(self.velocity) <= 90 && !(self.tfstate & TFSTATE_LOCK)) { muzzleflash(); sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); @@ -453,7 +453,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { void () player_assaultcannon2 =[104, player_assaultcannon1] { stuffcmd(self, "v_idlescale 0\n"); - if (vlen(self.velocity) < 30 && !(self.tfstate & TFSTATE_HALT)) { + if (vlen(self.velocity) < 30 && !(self.tfstate & TFSTATE_LOCK)) { if (self.weaponframe == 2) { self.weaponframe = 4; } else { diff --git a/status.qc b/status.qc index 24eebecd..dba90cbf 100644 --- a/status.qc +++ b/status.qc @@ -467,7 +467,7 @@ string(entity pl) AuraToString = string(entity pl) AssaultCannonToString = { - if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_HALT)) + if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_LOCK)) return "Ασσαυμτ Γαξξοξ Μογλεδ"; else return ""; diff --git a/tforthlp.qc b/tforthlp.qc index 69d0d371..761ebd14 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -161,8 +161,9 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-det50", TF_DETPACK_STOP, 0); TeamFortress_Alias("+det255", TF_DETPACK, 255); TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); - TeamFortress_Alias("+halt", TF_HALT, 0); - TeamFortress_Alias("-halt", TF_UNHALT, 0); + TeamFortress_Alias("locktoggle", TF_LOCK, 0); + TeamFortress_Alias("+lock", TF_LOCK, 0); + TeamFortress_Alias("-lock", TF_LOCK, 0); } else if (self.motd == 85) { TeamFortress_Alias("clan1", 82, 0); TeamFortress_Alias("clan2", 83, 0); diff --git a/weapons.qc b/weapons.qc index 61b96da7..4e72d29e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2587,14 +2587,11 @@ void () W_WeaponFrame = { // hwguy assault cannon special if (self.playerclass == PC_HVYWEAP) { - if ((self.impulse == TF_SPECIAL_SKILL || self.impulse == TF_HALT) && !(self.tfstate & TFSTATE_HALT)) { - self.tfstate = self.tfstate | TFSTATE_HALT; - Status_Refresh(self); - self.impulse = 0; - return; - } - else if ((self.impulse == TF_SPECIAL_SKILL || self.impulse == TF_UNHALT) && (self.tfstate & TFSTATE_HALT)) { - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_HALT); + if (self.impulse == TF_LOCK) { + if (self.tfstate & TFSTATE_LOCK) + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); + else + self.tfstate = self.tfstate | TFSTATE_LOCK; Status_Refresh(self); self.impulse = 0; return; From 5c39949755f7512fc4b4ae4976ebc744b758ab7a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 00:47:47 +0200 Subject: [PATCH 0246/2474] Fix impulse collision between lock and dash --- defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defs.h b/defs.h index ab17ca83..26a4267f 100644 --- a/defs.h +++ b/defs.h @@ -455,7 +455,7 @@ #define TF_DASH 157 // Initialize a forward bunnyhop for Scout // Impulses for new items -#define TF_LOCK 157 // Toggle Assault Cannon spinning +#define TF_LOCK 158 // Toggle Assault Cannon spinning #define TF_SCAN 159 // Scanner Pre-Impulse #define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies #define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies From 3820e3e9a582c15e06d899e9de34fe73a0f1f01e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 20:59:56 +0200 Subject: [PATCH 0247/2474] Add setting for dropping grenades on ground and renamed backpack grenade setting --- client.qc | 6 ++++++ items.qc | 6 +++--- qw.qc | 1 + tfort.qc | 9 +++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index 114c2bda..31a316a7 100644 --- a/client.qc +++ b/client.qc @@ -356,6 +356,12 @@ void () DecodeLevelParms = { if (st == "on") drop_grenades = TRUE; + st = infokey(world, "dgp"); + if (st == string_null) + st = infokey(world, "drop_grenpack"); + if (st == "on") + drop_grenpack = TRUE; + st = infokey(world, "dg1"); if (st == string_null) st = infokey(world, "drop_gren1"); diff --git a/items.qc b/items.qc index 8ad3e898..7190336b 100644 --- a/items.qc +++ b/items.qc @@ -1356,7 +1356,7 @@ void () BackpackTouch = { other.ammo_nails = other.ammo_nails + self.ammo_nails; other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; other.ammo_cells = other.ammo_cells + self.ammo_cells; - if (drop_grenades && other.playerclass != PC_SCOUT) { + if (drop_grenpack && other.playerclass != PC_SCOUT) { // give grenade type 1 maxg = GetMaxGrenades(1, other.tp_grenades_1); @@ -1417,7 +1417,7 @@ void () DropBackpack = { return; if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) { - if (!(drop_grenades && (self.no_grenades_1 + self.no_grenades_2))) + if (!(drop_grenpack && (self.no_grenades_1 + self.no_grenades_2))) return; } @@ -1428,7 +1428,7 @@ void () DropBackpack = { newmis.ammo_nails = self.ammo_nails; newmis.ammo_rockets = self.ammo_rockets; newmis.ammo_cells = self.ammo_cells; - if (drop_grenades) { + if (drop_grenpack) { if (drop_gren1 == -1) newmis.no_grenades_1 = self.no_grenades_1; else if (drop_gren1 > 0) { diff --git a/qw.qc b/qw.qc index ee73571f..8eafc807 100644 --- a/qw.qc +++ b/qw.qc @@ -418,6 +418,7 @@ float invis_only; float flagem_checked; float cease_fire; float drop_grenades; +float drop_grenpack; float drop_gren1; float drop_gren2; diff --git a/tfort.qc b/tfort.qc index 1828e787..4e2d1598 100644 --- a/tfort.qc +++ b/tfort.qc @@ -94,6 +94,15 @@ void () RemoveGrenadeTimers = { dremove(te); te = find(te, classname, "gtimer"); } + + if (!drop_grenades) { + te = find(world, classname, "primetimer"); + while (te != world) { + if (te.owner == self) + dremove(te); + te = find(te, classname, "primetimer"); + } + } }; void () RemoveGrenades = { From cb735617218c8c3f16d1ab0fbc64e13e79e66b26 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 21:33:36 +0200 Subject: [PATCH 0248/2474] Add option for grenade timers --- client.qc | 8 ++++++++ qw.qc | 1 + tfort.qc | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 31a316a7..212bf63b 100644 --- a/client.qc +++ b/client.qc @@ -378,6 +378,14 @@ void () DecodeLevelParms = { else drop_gren2 = -1; + st = infokey(world, "gt"); + if (st == string_null) + st = infokey(world, "grentimers"); + if (st == "off") + grentimers = FALSE; + else + grentimers = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index 8eafc807..4b217848 100644 --- a/qw.qc +++ b/qw.qc @@ -421,6 +421,7 @@ float drop_grenades; float drop_grenpack; float drop_gren1; float drop_gren2; +float grentimers; .float teamkills; diff --git a/tfort.qc b/tfort.qc index 4e2d1598..fb298020 100644 --- a/tfort.qc +++ b/tfort.qc @@ -695,7 +695,7 @@ void (float inp) TeamFortress_PrimeGrenade = { RemoveGrenadeTimers(); - if (!stof(infokey(self, "nt"))) { + if (grentimers && !stof(infokey(self, "nt"))) { timer = spawn(); timer.nextthink = time + 0.8; timer.think = GrenadeTimer; From a75e2bf427a66a0778cd54027d90d25dafe8a5fe Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 21:41:24 +0200 Subject: [PATCH 0249/2474] Add option for extended identify information --- actions.qc | 23 +++++++++++++++-------- client.qc | 8 ++++++++ qw.qc | 1 + 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/actions.qc b/actions.qc index 76647a37..7ca00203 100644 --- a/actions.qc +++ b/actions.qc @@ -227,8 +227,10 @@ void (entity pe_player, float f_type) CF_Identify = { s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_health)); - s_id_string = strcat(s_id_string, "/"); - s_id_string = strcat(s_id_string, ftos(f_maxhealth)); + if (id_extended) { + s_id_string = strcat(s_id_string, "/"); + s_id_string = strcat(s_id_string, ftos(f_maxhealth)); + } s_id_string = strcat(s_id_string, " hp\n"); // set name + armor (if engineer) @@ -236,18 +238,23 @@ void (entity pe_player, float f_type) CF_Identify = { s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_armor)); - s_id_string = strcat(s_id_string, "/"); - s_id_string = strcat(s_id_string, ftos(f_maxarmor)); + if (id_extended) { + s_id_string = strcat(s_id_string, "/"); + s_id_string = strcat(s_id_string, ftos(f_maxarmor)); + } s_id_string = strcat(s_id_string, " armor\n"); // set name + health (if sentry + engineer) } else if (f_maxsentryhealth) { s_id_string = strcat(s_name, "\n"); - s_id_string = strcat(s_id_string, ftos(floor(f_sentryhealth))); - s_id_string = strcat(s_id_string, "/"); - s_id_string = strcat(s_id_string, ftos(floor(f_maxsentryhealth))); - s_id_string = strcat(s_id_string, " health\n"); + if (id_extended) { + s_id_string = strcat(s_id_string, ftos(floor(f_sentryhealth))); + s_id_string = strcat(s_id_string, "/"); + s_id_string = strcat(s_id_string, ftos(floor(f_maxsentryhealth))); + s_id_string = strcat(s_id_string, " health"); + } + s_id_string = strcat(s_id_string, "\n"); // just set name (if other class) } else { diff --git a/client.qc b/client.qc index 212bf63b..8698da4a 100644 --- a/client.qc +++ b/client.qc @@ -386,6 +386,14 @@ void () DecodeLevelParms = { else grentimers = TRUE; + st = infokey(world, "ie"); + if (st == string_null) + st = infokey(world, "id_extended"); + if (st == "off") + id_extended = FALSE; + else + id_extended = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index 4b217848..302656e7 100644 --- a/qw.qc +++ b/qw.qc @@ -422,6 +422,7 @@ float drop_grenpack; float drop_gren1; float drop_gren2; float grentimers; +float id_extended; .float teamkills; From 3de71e8ca0bf9b8ed93544dfc24edf4f45b51f86 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 21:47:27 +0200 Subject: [PATCH 0250/2474] Add option for remembering current/last weapon across deaths --- client.qc | 8 ++++++++ qw.qc | 1 + tfort.qc | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 8698da4a..88b46434 100644 --- a/client.qc +++ b/client.qc @@ -394,6 +394,14 @@ void () DecodeLevelParms = { else id_extended = TRUE; + st = infokey(world, "rw"); + if (st == string_null) + st = infokey(world, "remember_weapon"); + if (st == "off") + remember_weapon = FALSE; + else + remember_weapon = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index 302656e7..e52fa8d7 100644 --- a/qw.qc +++ b/qw.qc @@ -423,6 +423,7 @@ float drop_gren1; float drop_gren2; float grentimers; float id_extended; +float remember_weapon; .float teamkills; diff --git a/tfort.qc b/tfort.qc index fb298020..fcf19ff6 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1401,7 +1401,7 @@ void () TeamFortress_SetEquipment = { self.items = 0; self.weapons_carried = 0; - if (self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { + if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; self.last_weapon = 0; self.weaponmode = 0; From db21e3159dd53167b4ac43487922b9303e10e499 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 21:58:20 +0200 Subject: [PATCH 0251/2474] Add option for picking up discardable ammo from discarded packs --- client.qc | 8 ++++++++ qw.qc | 1 + tfort.qc | 14 +++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 88b46434..d99a6bc4 100644 --- a/client.qc +++ b/client.qc @@ -402,6 +402,14 @@ void () DecodeLevelParms = { else remember_weapon = TRUE; + st = infokey(world, "da"); + if (st == string_null) + st = infokey(world, "discammo_pickup"); + if (st == "off") + discammo_pickup = FALSE; + else + discammo_pickup = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index e52fa8d7..cb9240b1 100644 --- a/qw.qc +++ b/qw.qc @@ -424,6 +424,7 @@ float drop_gren2; float grentimers; float id_extended; float remember_weapon; +float discammo_pickup; .float teamkills; diff --git a/tfort.qc b/tfort.qc index fcf19ff6..74afc7e7 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2433,7 +2433,19 @@ void () TeamFortress_AmmoboxTouch = { return; if (self.weapon == 0) { - if ((other.playerclass == PC_SCOUT) + if (discammo_pickup) { + other.ammo_shells = other.ammo_shells + self.ammo_shells; + other.ammo_nails = other.ammo_nails + self.ammo_nails; + other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; + other.ammo_cells = other.ammo_cells + self.ammo_cells; + dremove(self); + bound_other_ammo(other); + sound(other, 3, "weapons/lock4.wav", 1, 1); + stuffcmd(other, "bf\n"); + self = other; + W_SetCurrentAmmo(self); + return; + } else if ((other.playerclass == PC_SCOUT) || (other.playerclass == PC_ENGINEER)) { if (!(self.ammo_shells + self.ammo_nails + self.ammo_cells)) { other.nopickup = self; From 85459170d20a1fd64fcd1194ad0fb859d8c6ea30 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 22:27:21 +0200 Subject: [PATCH 0252/2474] Add option for universal dropflag --- client.qc | 6 ++++++ qw.qc | 1 + tfortmap.qc | 42 ++++++++++++++++++++++++------------------ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/client.qc b/client.qc index d99a6bc4..d696841c 100644 --- a/client.qc +++ b/client.qc @@ -410,6 +410,12 @@ void () DecodeLevelParms = { else discammo_pickup = TRUE; + st = infokey(world, "od"); + if (st == string_null) + st = infokey(world, "old_dropflag"); + if (st == "on") + old_dropflag = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index cb9240b1..d5993cdd 100644 --- a/qw.qc +++ b/qw.qc @@ -425,6 +425,7 @@ float grentimers; float id_extended; float remember_weapon; float discammo_pickup; +float old_dropflag; .float teamkills; diff --git a/tfortmap.qc b/tfortmap.qc index 15b047be..1523493d 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2557,25 +2557,31 @@ void () DropGoalItems = { te = find(world, classname, "item_tfgoal"); while (te) { if (te.owner == self) { - tfgoalitem_RemoveEffectsFromPlayer(te, self); - tfgoalitem_drop(te, 1, self); - if (self.team_no == 1) - bprint(PRINT_HIGH, self.netname, " δςοππεδ ςεδ§σ ζμαη\n"); - else if (self.team_no == 2) - bprint(PRINT_HIGH, self.netname, " δςοππεδ βμυε§σ ζμαη\n"); - else - bprint(PRINT_HIGH, self.netname, " δςοππεδ τθε εξενω§σ ζμαη\n"); - - Status_Print(self, "\n\n\n", "You dropped the flag!"); - search = find(world, classname, "player"); - while (search) { - if ((search.team_no == self.team_no) && (self.team_no != 0)) { - if (search != self) - Status_Print(search, "\n\n\n", self.netname, " dropped the enemy flag!"); - } else { - Status_Print(search, "\n\n\n", "The enemy dropped your flag!"); + if (old_dropflag) { + if (te.goal_activation & 4096) + tfgoalitem_RemoveFromPlayer(te, self, 2); + } + else { + tfgoalitem_RemoveEffectsFromPlayer(te, self); + tfgoalitem_drop(te, 1, self); + if (self.team_no == 1) + bprint(PRINT_HIGH, self.netname, " δςοππεδ ςεδ§σ ζμαη\n"); + else if (self.team_no == 2) + bprint(PRINT_HIGH, self.netname, " δςοππεδ βμυε§σ ζμαη\n"); + else + bprint(PRINT_HIGH, self.netname, " δςοππεδ τθε εξενω§σ ζμαη\n"); + + Status_Print(self, "\n\n\n", "You dropped the flag!"); + search = find(world, classname, "player"); + while (search) { + if ((search.team_no == self.team_no) && (self.team_no != 0)) { + if (search != self) + Status_Print(search, "\n\n\n", self.netname, " dropped the enemy flag!"); + } else { + Status_Print(search, "\n\n\n", "The enemy dropped your flag!"); + } + search = find(search, classname, "player"); } - search = find(search, classname, "player"); } } te = find(te, classname, "item_tfgoal"); From 44a714389c423361bac521352c539ae1d1f686a1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 22:39:33 +0200 Subject: [PATCH 0253/2474] Add option for showing ticking clip ammo during reload --- client.qc | 8 ++++++++ qw.qc | 1 + status.qc | 5 ++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index d696841c..81e26f53 100644 --- a/client.qc +++ b/client.qc @@ -416,6 +416,14 @@ void () DecodeLevelParms = { if (st == "on") old_dropflag = TRUE; + st = infokey(world, "rc"); + if (st == string_null) + st = infokey(world, "reload_cliptick"); + if (st == "off") + reload_cliptick = FALSE; + else + reload_cliptick = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index d5993cdd..b11dac2f 100644 --- a/qw.qc +++ b/qw.qc @@ -426,6 +426,7 @@ float id_extended; float remember_weapon; float discammo_pickup; float old_dropflag; +float reload_cliptick; .float teamkills; diff --git a/status.qc b/status.qc index dba90cbf..507c4bb7 100644 --- a/status.qc +++ b/status.qc @@ -219,7 +219,10 @@ void (entity pl) RefreshStatusBar = { // status line 3 column 3 - clip size if (pl.tfstate & TFSTATE_RELOADING) { st3 = "Γμιπ: "; - st3 = strcat(st3, strpadl(ftos(pl.reload_clipsize), 2)); + if (reload_cliptick) + st3 = strcat(st3, strpadl(ftos(pl.reload_clipsize), 2)); + else + st3 = strcat(st3, " 0"); st3 = strcat(st3, "/"); st3 = strcat(st3, strpadr(ftos(GetClipSize(pl)), 3)); } else { From b78c8a837e37e59e527cef2254dac48d5cb25862 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 23:08:32 +0200 Subject: [PATCH 0254/2474] Add option for increased sniper rifle range --- client.qc | 6 ++++++ qw.qc | 1 + weapons.qc | 11 +++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index 81e26f53..72364c5a 100644 --- a/client.qc +++ b/client.qc @@ -424,6 +424,12 @@ void () DecodeLevelParms = { else reload_cliptick = TRUE; + st = infokey(world, "os"); + if (st == string_null) + st = infokey(world, "old_sniperrange"); + if (st == "on") + old_sniperrange = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index b11dac2f..702878f9 100644 --- a/qw.qc +++ b/qw.qc @@ -427,6 +427,7 @@ float remember_weapon; float discammo_pickup; float old_dropflag; float reload_cliptick; +float old_sniperrange; .float teamkills; diff --git a/weapons.qc b/weapons.qc index 4e72d29e..8bb14b2a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -789,7 +789,11 @@ void () W_FireSniperRifle = { src_z = self.absmin_z + self.size_z * 0.7; use_this = FALSE; - traceline(src, src + dir * 9192, FALSE, self); + + if (old_sniperrange) + traceline(src, src + dir * 8092, FALSE, self); + else + traceline(src, src + dir * 9192, FALSE, self); if (trace_fraction != 1) if (trace_ent != world) if (trace_ent.classname == "player") @@ -799,7 +803,10 @@ void () W_FireSniperRifle = { if (!use_this) { dir = aim(self, 10000); - traceline(src, src + dir * 9192, 0, self); + if (old_sniperrange) + traceline(src, src + dir * 3072, 0, self); + else + traceline(src, src + dir * 9192, 0, self); } deathmsg = DMSG_SNIPERRIFLE; dam_mult = 1; From d84ca851ac18b8725ce2be4f7b25a6be8ed16ecd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 23:08:53 +0200 Subject: [PATCH 0255/2474] Fix Sniper special to once again be zoomtoggle --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 8bb14b2a..e849bbbe 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2606,7 +2606,7 @@ void () W_WeaponFrame = { } if (self.playerclass == PC_SNIPER) { - if (self.impulse == TF_ZOOMTOGGLE) { + if (self.impulse == TF_SPECIAL_SKILL || self.impulse == TF_ZOOMTOGGLE) { Sniper_ZoomToggle(); self.impulse = 0; return; From 8c292764b0a8b97c75ac384b3e42aeb68543e015 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 23:17:29 +0200 Subject: [PATCH 0256/2474] Add option for detpipe limit --- client.qc | 16 ++++++++++++++++ qw.qc | 2 ++ weapons.qc | 13 +++++++------ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/client.qc b/client.qc index 72364c5a..90e58eb9 100644 --- a/client.qc +++ b/client.qc @@ -430,6 +430,22 @@ void () DecodeLevelParms = { if (st == "on") old_sniperrange = TRUE; + st = infokey(world, "dl"); + if (st == string_null) + st = infokey(world, "detpipe_limit"); + if (st != string_null) + detpipe_limit = stof(st); + else + detpipe_limit = -1; + + st = infokey(world, "dw"); + if (st == string_null) + st = infokey(world, "detpipe_limit_world"); + if (st != string_null) + detpipe_limit_world = stof(st); + else + detpipe_limit_world = -1; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index 702878f9..dd7b11c0 100644 --- a/qw.qc +++ b/qw.qc @@ -428,6 +428,8 @@ float discammo_pickup; float old_dropflag; float reload_cliptick; float old_sniperrange; +float detpipe_limit; +float detpipe_limit_world; .float teamkills; diff --git a/weapons.qc b/weapons.qc index e849bbbe..9a95a08a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1131,11 +1131,9 @@ void () GrenadeTouch = { void () ExplodeOldestPipebomb = { local entity pipe; - local entity oldest; - local float numpipes; - - numpipes = 0; - oldest = world; + local entity oldest = world; + local float numpipes = 0; + local float numpipes_total = 0; pipe = find(world, classname, "pipebomb"); while (pipe != world) { @@ -1144,10 +1142,13 @@ void () ExplodeOldestPipebomb = { if (oldest == world || oldest.nextthink > pipe.nextthink) oldest = pipe; } + numpipes_total = numpipes_total + 1; pipe = find(pipe, classname, "pipebomb"); } - if (numpipes >= 6 && oldest != world) { + if (((numpipes >= detpipe_limit && detpipe_limit >= 0) + || (numpipes_total >= detpipe_limit_world && detpipe_limit_world >= 0)) + && oldest != world) { oldest.nextthink = time + 0.5; } }; From eb5fed2c6752bc7be84f0a5ae6b4b75813383bcf Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 23:24:45 +0200 Subject: [PATCH 0257/2474] Add option for old pipe cooldown --- client.qc | 6 ++++++ qw.qc | 1 + weapons.qc | 5 ++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 90e58eb9..dd5751b6 100644 --- a/client.qc +++ b/client.qc @@ -446,6 +446,12 @@ void () DecodeLevelParms = { else detpipe_limit_world = -1; + st = infokey(world, "op"); + if (st == string_null) + st = infokey(world, "old_pipecooldown"); + if (st == "on") + old_pipecooldown = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index dd7b11c0..5b12c308 100644 --- a/qw.qc +++ b/qw.qc @@ -430,6 +430,7 @@ float reload_cliptick; float old_sniperrange; float detpipe_limit; float detpipe_limit_world; +float old_pipecooldown; .float teamkills; diff --git a/weapons.qc b/weapons.qc index 9a95a08a..f7bfaec2 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1170,7 +1170,10 @@ void () W_FireGrenade = { newmis.touch = GrenadeTouch; newmis.nextthink = time + 2.5; } else { - self.pipecooldown = time + 0.5; + if (old_pipecooldown) + self.pipecooldown = time + 0.8; + else + self.pipecooldown = time + 0.5; ExplodeOldestPipebomb(); newmis.classname = "pipebomb"; newmis.skin = 2; From bf493100fefedf42aa236d3196c2c2eacc717823 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 23:29:53 +0200 Subject: [PATCH 0258/2474] Add option for allowing medic aura --- client.qc | 8 ++++++++ medic.qc | 3 +++ qw.qc | 1 + status.qc | 36 +++++++++++++++++++++--------------- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/client.qc b/client.qc index dd5751b6..67d8473f 100644 --- a/client.qc +++ b/client.qc @@ -452,6 +452,14 @@ void () DecodeLevelParms = { if (st == "on") old_pipecooldown = TRUE; + st = infokey(world, "ma"); + if (st == string_null) + st = infokey(world, "medicaura"); + if (st == "off") + medicaura = FALSE; + else + medicaura = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/medic.qc b/medic.qc index 1afe0f89..a83fbc19 100644 --- a/medic.qc +++ b/medic.qc @@ -7,6 +7,9 @@ void () CF_Medic_AuraToggle; // initializes the medic healing aura // called from weapons.qc:ImpulseCommands() void () CF_Medic_AuraToggle = { + if (!medicaura) + return; + if (self.aura_active) { self.aura_active = 0; sprint(self, PRINT_HIGH, "Healing aura turned off\n"); diff --git a/qw.qc b/qw.qc index 5b12c308..61ada88a 100644 --- a/qw.qc +++ b/qw.qc @@ -431,6 +431,7 @@ float old_sniperrange; float detpipe_limit; float detpipe_limit_world; float old_pipecooldown; +float medicaura; .float teamkills; diff --git a/status.qc b/status.qc index 507c4bb7..d11e2737 100644 --- a/status.qc +++ b/status.qc @@ -446,23 +446,29 @@ string(entity pl) DetpackToString = string(entity pl) AuraToString = { - local string st = "Θεαμιξη Αυςα: "; - - if (pl.aura_active) { - if (time < pl.aura_healtime && pl.aura_healcount) { - st = strcat(st, ftos(pl.aura_healcount)); - st = strcat(st, " players healed for "); - st = strcat(st, ftos(pl.aura_healamount)); - st = strcat(st, " hp"); + local string st; + + if (medicaura) { + st = "Θεαμιξη Αυςα: "; + + if (pl.aura_active) { + if (time < pl.aura_healtime && pl.aura_healcount) { + st = strcat(st, ftos(pl.aura_healcount)); + st = strcat(st, " players healed for "); + st = strcat(st, ftos(pl.aura_healamount)); + st = strcat(st, " hp"); + } + else if (pl.ammo_cells < 50) + st = strcat(st, "out of power"); + else if (pl.ammo_cells < 95) + st = strcat(st, "recharging"); + else + st = strcat(st, "on"); + } else { + st = strcat(st, "off"); } - else if (pl.ammo_cells < 50) - st = strcat(st, "out of power"); - else if (pl.ammo_cells < 95) - st = strcat(st, "recharging"); - else - st = strcat(st, "on"); } else { - st = strcat(st, "off"); + st = ""; } return st; From bfb05a47a7d4ef41fde03a991b0864b8b739d360 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 7 Sep 2014 23:35:59 +0200 Subject: [PATCH 0259/2474] Add option for old bioweapon damage --- client.qc | 6 ++++++ medic.qc | 5 ++++- qw.qc | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 67d8473f..7911eea6 100644 --- a/client.qc +++ b/client.qc @@ -460,6 +460,12 @@ void () DecodeLevelParms = { else medicaura = TRUE; + st = infokey(world, "ob"); + if (st == string_null) + st = infokey(world, "old_biodamage"); + if (st == "on") + old_biodamage = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/medic.qc b/medic.qc index a83fbc19..ca2eb778 100644 --- a/medic.qc +++ b/medic.qc @@ -167,7 +167,10 @@ void () BioInfection_Decay = { } te = te.chain; } - self.nextthink = time + 1; + if (old_biodamage) + self.nextthink = time + 3; + else + self.nextthink = time + 1; deathmsg = DMSG_BIOWEAPON; TF_T_Damage(self.owner, self, self.enemy, 8, TF_TD_IGNOREARMOUR, TF_TD_OTHER); SpawnBlood(self.owner.origin, 30); diff --git a/qw.qc b/qw.qc index 61ada88a..29e67edd 100644 --- a/qw.qc +++ b/qw.qc @@ -432,6 +432,7 @@ float detpipe_limit; float detpipe_limit_world; float old_pipecooldown; float medicaura; +float old_biodamage; .float teamkills; From 00c0357b4eb0ad9e022f4789e99eb54e224126dd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 8 Sep 2014 12:26:45 +0200 Subject: [PATCH 0260/2474] Add option for old spanner behaviour --- client.qc | 6 +++++ engineer.qc | 30 +++++++++++------------ menu.qc | 69 +++++++++++++++++++++++++++++++++++++++++++++++++---- qw.qc | 1 + 4 files changed, 86 insertions(+), 20 deletions(-) diff --git a/client.qc b/client.qc index 7911eea6..ef821715 100644 --- a/client.qc +++ b/client.qc @@ -466,6 +466,12 @@ void () DecodeLevelParms = { if (st == "on") old_biodamage = TRUE; + st = infokey(world, "os"); + if (st == string_null) + st = infokey(world, "old_spanner"); + if (st == "on") + old_spanner = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/engineer.qc b/engineer.qc index 59139f8d..82adb22a 100644 --- a/engineer.qc +++ b/engineer.qc @@ -756,7 +756,7 @@ void () Dispenser_Die = { void (entity disp) Engineer_UseDispenser = { local entity dist_checker; - if (disp.health < disp.max_health) { + if (disp.health < disp.max_health && !old_spanner) { Engineer_Dispenser_Repair(disp); return; } @@ -895,21 +895,21 @@ void (entity disp) Engineer_Dispenser_Repair = { }; void (entity gun) Engineer_UseSentryGun = { - if (gun.weapon < 3 && self.ammo_cells >= 130) { - Engineer_SentryGun_Upgrade(gun); - return; - } - - if (gun.health < gun.max_health && self.ammo_cells > 0) { - Engineer_SentryGun_Repair(gun); - return; - } - if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) - || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets - && self.ammo_rockets > 0)) { - Engineer_SentryGun_InsertAmmo(gun); - return; + // automate tasks if old_spanner setting is disabled + if (!old_spanner) { + if (gun.weapon < 3 && self.ammo_cells >= 130) { + Engineer_SentryGun_Upgrade(gun); + return; + } else if (gun.health < gun.max_health && self.ammo_cells > 0) { + Engineer_SentryGun_Repair(gun); + return; + } else if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) + || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets + && self.ammo_rockets > 0)) { + Engineer_SentryGun_InsertAmmo(gun); + return; + } } sprint(self, PRINT_HIGH, "Level "); diff --git a/menu.qc b/menu.qc index a881102f..76a749e5 100644 --- a/menu.qc +++ b/menu.qc @@ -729,6 +729,8 @@ void (float inp) Menu_EngineerFix_Dispenser_Input = { Engineer_Dispenser_InsertAmmo(self.building); } else if (inp == 2) { Engineer_Dispenser_InsertArmor(self.building); + } else if (inp == 3 && old_spanner) { + Engineer_Dispenser_Repair(self.building); } self.building = world; @@ -736,7 +738,7 @@ void (float inp) Menu_EngineerFix_Dispenser_Input = { void () Menu_EngineerFix_Dispenser = { local string s_action = "Dispenser maintenance:\n\n"; - local string s_ammo, s_armor; + local string s_ammo, s_armor, s_repair; local string s_nothing = "\n—‘ Nothing \n\n"; if ((self.ammo_shells > 0 && self.building.ammo_shells < 400) @@ -752,10 +754,15 @@ void () Menu_EngineerFix_Dispenser = { else s_armor = "\n"; - Status_Menu(self, Menu_EngineerFix_Dispenser_Input, s_action, s_ammo, s_armor, s_nothing); + if (old_spanner && self.building.health < self.building.max_health) + s_repair = "•‘ Repair \n"; + else + s_repair = "\n"; + + Status_Menu(self, Menu_EngineerFix_Dispenser_Input, s_action, s_ammo, s_armor, s_repair, s_nothing); }; -void (float inp) Menu_EngineerFix_SentryGun_Input = { +void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { if (inp == 1) { sprint(self, PRINT_HIGH, "Rotating 45 degrees to the left...\n"); self.building.waitmin = anglemod(self.building.waitmin + 45); @@ -771,7 +778,7 @@ void (float inp) Menu_EngineerFix_SentryGun_Input = { } }; -void () Menu_EngineerFix_SentryGun = { +void () Menu_EngineerFix_SentryGun_Rotate = { local string action = "Rotate sentry gun:\n\n"; local string rotl = "“‘ 45 degrees left \n"; local string rot180 = "”‘ 180 degrees \n"; @@ -782,7 +789,59 @@ void () Menu_EngineerFix_SentryGun = { || self.classname != "player" || self.building == world) return; - Status_Menu(self, Menu_EngineerFix_SentryGun_Input, action, rotl, rot180, rotr, nothing); + Status_Menu(self, Menu_EngineerFix_SentryGun_Rotate_Input, action, rotl, rot180, rotr, nothing); +}; + +void (float inp) Menu_EngineerFix_SentryGun_Input = { + if (!self.building.real_owner.has_sentry || self.building.real_owner != self + || self.classname != "player" || self.building == world) + return; + + if (inp == 1) { + Engineer_SentryGun_InsertAmmo(self.building); + } else if (inp == 2 && self.building.weapon < 3 && self.ammo_cells >= 130) { + Engineer_SentryGun_Upgrade(self.building); + } else if (inp == 3) { + Engineer_SentryGun_Repair(self.building); + } else if (inp == 4) { + Menu_EngineerFix_SentryGun_Rotate(); + } +}; + +void () Menu_EngineerFix_SentryGun = { + + // only show this menu if old_spanner setting is enabled, otherwise show rotate menu + if (!old_spanner) { + Menu_EngineerFix_SentryGun_Rotate(); + return; + } + + local string action = "Sentry gun maintenance:\n\n"; + local string putammo, upgrade, repair, rotate; + local string nothing = "\n—‘ Nothing "; + + if ((self.ammo_shells > 0 && self.building.ammo_shells < self.building.maxammo_shells) + || (self.ammo_rockets > 0 && self.building.weapon == 3 && self.building.ammo_rockets < self.building.maxammo_rockets)) + putammo = "“‘ Insert ammo\n"; + else + putammo = "\n"; + + if (self.building.weapon < 3 && self.ammo_cells >= 130) + upgrade = "”‘ Upgrade \n"; + else + upgrade = "\n"; + + if (self.building.health < self.building.max_health) + repair = "•‘ Repair \n"; + else + repair = "\n"; + + if (self.building.real_owner == self) + rotate = "–‘ Rotate \n"; + else + rotate = "\n"; + + Status_Menu(self, Menu_EngineerFix_SentryGun_Input, action, putammo, upgrade, repair, rotate, nothing); }; void (float inp) Menu_Dispenser_Input = { diff --git a/qw.qc b/qw.qc index 29e67edd..a87466a9 100644 --- a/qw.qc +++ b/qw.qc @@ -433,6 +433,7 @@ float detpipe_limit_world; float old_pipecooldown; float medicaura; float old_biodamage; +float old_spanner; .float teamkills; From 6c392c40b5ae79930b62d971e79aa51e780783b4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 8 Sep 2014 12:37:58 +0200 Subject: [PATCH 0261/2474] Add option for old railgun behaviour --- client.qc | 6 ++++++ engineer.qc | 11 +++++++++++ qw.qc | 1 + 3 files changed, 18 insertions(+) diff --git a/client.qc b/client.qc index ef821715..962724d5 100644 --- a/client.qc +++ b/client.qc @@ -472,6 +472,12 @@ void () DecodeLevelParms = { if (st == "on") old_spanner = TRUE; + st = infokey(world, "or"); + if (st == string_null) + st = infokey(world, "old_railgun"); + if (st == "on") + old_railgun = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/engineer.qc b/engineer.qc index 82adb22a..f6183b69 100644 --- a/engineer.qc +++ b/engineer.qc @@ -48,6 +48,17 @@ void () LaserBolt_Touch = { SpawnBlood(org, 15); deathmsg = DMSG_LASERBOLT; TF_T_Damage(other, self, self.enemy, 25, 2, TF_TD_ELECTRICITY); + + // create a new projectile on other side of target if old_railgun is enabled + if (old_railgun) { + self.velocity = self.oldorigin; + self.owner = other; + setmodel(self, string_null); + self.touch = SUB_Null; + self.nextthink = time + 0.1; + self.think = LaserBolt_Think; + return; + } } else { WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_SPIKE); diff --git a/qw.qc b/qw.qc index a87466a9..eb405e56 100644 --- a/qw.qc +++ b/qw.qc @@ -434,6 +434,7 @@ float old_pipecooldown; float medicaura; float old_biodamage; float old_spanner; +float old_railgun; .float teamkills; From 43fca1470d60d16fa33c37d378282773d49f6840 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 8 Sep 2014 12:38:20 +0200 Subject: [PATCH 0262/2474] Make 6 the default max detpipes per demoman --- client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 962724d5..9b4e4e67 100644 --- a/client.qc +++ b/client.qc @@ -436,7 +436,7 @@ void () DecodeLevelParms = { if (st != string_null) detpipe_limit = stof(st); else - detpipe_limit = -1; + detpipe_limit = 6; st = infokey(world, "dw"); if (st == string_null) From abe00ba17e20932a627ab0fbb0c17322111e82e1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 8 Sep 2014 19:17:15 +0200 Subject: [PATCH 0263/2474] Add option for old dispenser behaviour --- client.qc | 6 ++++++ engineer.qc | 41 ++++++++++++++++++++++++++++------------- qw.qc | 1 + 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/client.qc b/client.qc index 9b4e4e67..b20dd0b3 100644 --- a/client.qc +++ b/client.qc @@ -478,6 +478,12 @@ void () DecodeLevelParms = { if (st == "on") old_railgun = TRUE; + st = infokey(world, "od"); + if (st == string_null) + st = infokey(world, "old_dispenser"); + if (st == "on") + old_dispenser = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/engineer.qc b/engineer.qc index f6183b69..10399400 100644 --- a/engineer.qc +++ b/engineer.qc @@ -420,12 +420,20 @@ void (entity disp) Dispenser_AmmoTick = { // set restock rate (scales with players on team) rate = 1 + 0.5 * (TeamFortress_TeamGetNoPlayers(disp.team_no) - 1); - if (self.disptimer > 3) { - self.ammo_shells = self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS * rate / 300); - self.ammo_cells = self.ammo_cells + rint(BUILD_DISPENSER_MAX_CELLS * rate / 300); - self.ammo_nails = self.ammo_nails + rint(BUILD_DISPENSER_MAX_NAILS * rate / 300); - self.ammo_rockets = self.ammo_rockets + rint(BUILD_DISPENSER_MAX_ROCKETS * rate / 300); - self.armorvalue = self.armorvalue + rint(BUILD_DISPENSER_MAX_ARMOR * rate / 300); + if ((old_dispenser && self.disptimer > 23) || (!old_dispenser && self.disptimer > 3)) { + if (old_dispenser) { + self.ammo_shells = self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS / 20); + self.ammo_cells = self.ammo_cells + rint(BUILD_DISPENSER_MAX_CELLS / 20); + self.ammo_nails = self.ammo_nails + rint(BUILD_DISPENSER_MAX_NAILS / 20); + self.ammo_rockets = self.ammo_rockets + rint(BUILD_DISPENSER_MAX_ROCKETS / 20); + self.armorvalue = self.armorvalue + rint(BUILD_DISPENSER_MAX_ARMOR / 20); + } else { + self.ammo_shells = self.ammo_shells + rint(BUILD_DISPENSER_MAX_SHELLS * rate / 225); + self.ammo_cells = self.ammo_cells + rint(BUILD_DISPENSER_MAX_CELLS * rate / 225); + self.ammo_nails = self.ammo_nails + rint(BUILD_DISPENSER_MAX_NAILS * rate / 225); + self.ammo_rockets = self.ammo_rockets + rint(BUILD_DISPENSER_MAX_ROCKETS * rate / 225); + self.armorvalue = self.armorvalue + rint(BUILD_DISPENSER_MAX_ARMOR * rate / 225); + } if (self.ammo_shells > BUILD_DISPENSER_MAX_SHELLS) self.ammo_shells = BUILD_DISPENSER_MAX_SHELLS; @@ -556,7 +564,7 @@ void (entity disp, entity pl) Dispenser_StockPlayer = { // set dispenser efficiency (increase with time => just passing by gives less ammo/armor) if (!pl.deff || pl.deff >= 4) - pl.deff = 1; + pl.deff = 0.5; else pl.deff = pl.deff * 2; @@ -591,8 +599,11 @@ void (entity disp) Dispenser_FindPlayers = { void () DispenserThink = { CheckBelowBuilding(self); Dispenser_AmmoTick(self); - Dispenser_FindPlayers(self); - self.nextthink = time + 0.4; + + if (!old_dispenser) + Dispenser_FindPlayers(self); + + self.nextthink = time + 0.3; }; void () TeamFortress_FinishedBuilding = { @@ -624,7 +635,7 @@ void () TeamFortress_FinishedBuilding = { oldself.health = 150; oldself.disptimer = 1; oldself.think = DispenserThink; - oldself.nextthink = time + 0.4; + oldself.nextthink = time + 0.3; oldself.th_die = Dispenser_Die; oldself.mdl = "progs/disp.mdl"; oldself.team_no = self.team_no; @@ -713,11 +724,15 @@ void () T_Dispenser = { local entity oldself; local entity dist_checker; - // don't show menu to players of same team - if (other.classname != "player" || other.team_no == self.team_no || !other.team_no) + if (other == world) + return; + + // don't show menu to players of same team (if new dispenser behaviour) + if (!old_dispenser && (other.classname != "player" || other.team_no == self.team_no || !other.team_no)) return; - Status_Print(self.real_owner, "\n\n\n", "Enemies are using your dispenser!"); + if (other.team_no && other.team_no != self.team_no) + Status_Print(self.real_owner, "\n\n\n", "Enemies are using your dispenser!"); if ((other.building == world) && (other.building_wait < time)) { other.building = self; diff --git a/qw.qc b/qw.qc index eb405e56..43445b93 100644 --- a/qw.qc +++ b/qw.qc @@ -435,6 +435,7 @@ float medicaura; float old_biodamage; float old_spanner; float old_railgun; +float old_dispenser; .float teamkills; From d5eab6ff3f1e578a5eac81eaf7c794a7122e9400 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 8 Sep 2014 19:17:33 +0200 Subject: [PATCH 0264/2474] Add rockets to Engineer ammo need list (for auto dispenser stock) --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 74afc7e7..78442530 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1926,7 +1926,7 @@ void () TeamFortress_SetEquipment = { // dispenser needs self.need_shells = 1; self.need_nails = 1; - self.need_rockets = 0; + self.need_rockets = 1; self.need_cells = 1; self.maxammo_rockets = PC_ENGINEER_MAXAMMO_ROCKET; From f819c65a3d3bf45a991ecb6e0c8f84972c591518 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 8 Sep 2014 23:38:24 +0200 Subject: [PATCH 0265/2474] Add option for old medikit --- actions.qc | 3 +++ client.qc | 8 +++++++- medic.qc | 8 ++++++-- qw.qc | 1 + weapons.qc | 39 ++++++++++++++++++++++++++++++++++++--- 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/actions.qc b/actions.qc index 7ca00203..52e07bb3 100644 --- a/actions.qc +++ b/actions.qc @@ -25,6 +25,9 @@ void () TeamFortress_Discard = { newmis.ammo_nails = self.ammo_nails; } + if (self.playerclass == PC_MEDIC && !medicaura && old_medikit) + newmis.ammo_cells = self.ammo_cells; + if (! (((newmis.ammo_shells + newmis.ammo_nails) + newmis.ammo_rockets) + newmis.ammo_cells)) { diff --git a/client.qc b/client.qc index b20dd0b3..222e34c1 100644 --- a/client.qc +++ b/client.qc @@ -410,7 +410,7 @@ void () DecodeLevelParms = { else discammo_pickup = TRUE; - st = infokey(world, "od"); + st = infokey(world, "odf"); if (st == string_null) st = infokey(world, "old_dropflag"); if (st == "on") @@ -460,6 +460,12 @@ void () DecodeLevelParms = { else medicaura = TRUE; + st = infokey(world, "om"); + if (st == string_null) + st = infokey(world, "old_medikit"); + if (st == "on") + old_medikit = TRUE; + st = infokey(world, "ob"); if (st == string_null) st = infokey(world, "old_biodamage"); diff --git a/medic.qc b/medic.qc index ca2eb778..eed0f67d 100644 --- a/medic.qc +++ b/medic.qc @@ -73,7 +73,7 @@ void () CF_Medic_AuraFindPlayers = { } self.owner.ammo_cells = self.owner.ammo_cells - 5; - if (self.owner.current_weapon == WEAP_MEDIKIT) + if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) self.owner.currentammo = self.owner.ammo_cells; }; @@ -82,6 +82,10 @@ void () CF_Medic_AuraFindPlayers = { void () CF_Medic_RegenerateCells = { local float f_newcells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); + // don't regenerate cells if not using aura or new medikit + if (!medicaura && old_medikit) + return; + self.nextthink = time + PC_MEDIC_CELL_REGEN_TIME; if (self.owner.ammo_cells < 100) { @@ -93,7 +97,7 @@ void () CF_Medic_RegenerateCells = { else if (f_newcells >= 50 && f_newcells < 60) Status_Refresh(self.owner); - if (self.owner.current_weapon == WEAP_MEDIKIT) + if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) self.owner.currentammo = self.owner.ammo_cells; } }; diff --git a/qw.qc b/qw.qc index 43445b93..0ce2f141 100644 --- a/qw.qc +++ b/qw.qc @@ -432,6 +432,7 @@ float detpipe_limit; float detpipe_limit_world; float old_pipecooldown; float medicaura; +float old_medikit; float old_biodamage; float old_spanner; float old_railgun; diff --git a/weapons.qc b/weapons.qc index f7bfaec2..9a93a370 100644 --- a/weapons.qc +++ b/weapons.qc @@ -492,7 +492,37 @@ void () W_FireMedikit = { } return; } - if (trace_ent.health < (trace_ent.max_health + 50)) { + if (old_medikit) { + + if (healam > 0 && trace_ent.health < trace_ent.max_health) { + + sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); + trace_ent.axhitme = 1; + SpawnBlood(org, 20); + T_Heal(trace_ent, healam, 0); + + } else if (trace_ent.health >= trace_ent.max_health && trace_ent.health < (trace_ent.max_health + 50)) { + + healam = 5; + if (healam > (self.ammo_medikit * 5)) + healam = self.ammo_medikit * 5; + + if (healam > 0) { + sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); + T_Heal(trace_ent, healam, 1); + self.ammo_medikit = self.ammo_medikit - rint(healam / 5); + + if (!(trace_ent.items & IT_SUPERHEALTH)) { + trace_ent.items = trace_ent.items | IT_SUPERHEALTH; + newmis = spawn(); + newmis.nextthink = time + 5; + newmis.think = item_megahealth_rot; + newmis.owner = trace_ent; + } + } + } + + } else if (trace_ent.health < (trace_ent.max_health + 50)) { if (self.ammo_cells >= 50) { healam = trace_ent.max_health - trace_ent.health + 50; @@ -1458,10 +1488,13 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_MEDIKIT) { - pl.currentammo = pl.ammo_cells; + if (!old_medikit) { + pl.currentammo = pl.ammo_cells; + pl.items = pl.items | IT_CELLS; + } else + pl.currentammo = 0; pl.weaponmodel = "progs/v_medi.mdl"; pl.weaponframe = 0; - pl.items = pl.items | IT_CELLS; } else if (pl.current_weapon == WEAP_TRANQ) { pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { From 02932e00723a6400f282216eae983b7ee0129aaf Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 8 Sep 2014 23:49:24 +0200 Subject: [PATCH 0266/2474] Add option for flamethrower knockback --- client.qc | 8 ++++++++ pyro.qc | 12 +++++++----- qw.qc | 2 ++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 222e34c1..17221142 100644 --- a/client.qc +++ b/client.qc @@ -490,6 +490,14 @@ void () DecodeLevelParms = { if (st == "on") old_dispenser = TRUE; + st = infokey(world, "fk"); + if (st == string_null) + st = infokey(world, "flame_knockback"); + if (st == "off") + flame_knockback = FALSE; + else + flame_knockback = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/pyro.qc b/pyro.qc index 0d41d5b7..2f1fc66a 100644 --- a/pyro.qc +++ b/pyro.qc @@ -424,11 +424,13 @@ void () Flamer_stream_touch = { if ((other.takedamage == 2) && (other.health > 0)) { deathmsg = DMSG_FLAME; - // knockback target - if (other.classname != "building_sentrygun" && other.classname != "building_dispenser") { - dir = other.origin - (self.absmin + self.absmax) * 0.5; - dir = normalize(dir); - other.velocity = other.velocity + dir * 300; + if (flame_knockback) { + // knockback target + if (other.classname != "building_sentrygun" && other.classname != "building_dispenser") { + dir = other.origin - (self.absmin + self.absmax) * 0.5; + dir = normalize(dir); + other.velocity = other.velocity + dir * 300; + } } TF_T_Damage(other, self, self.owner, 10, TF_TD_NOTTEAM, diff --git a/qw.qc b/qw.qc index 0ce2f141..9260aa9e 100644 --- a/qw.qc +++ b/qw.qc @@ -434,6 +434,8 @@ float old_pipecooldown; float medicaura; float old_medikit; float old_biodamage; +float flame_knockback; + float old_spanner; float old_railgun; float old_dispenser; From f607214acf9c3ad09565be3695c116c51075a00a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 00:04:39 +0200 Subject: [PATCH 0267/2474] Add option for bigger dispenser explosions --- client.qc | 8 ++++++++ engineer.qc | 13 ++++++++++--- qw.qc | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index 17221142..110e864a 100644 --- a/client.qc +++ b/client.qc @@ -498,6 +498,14 @@ void () DecodeLevelParms = { else flame_knockback = TRUE; + st = infokey(world, "de"); + if (st == string_null) + st = infokey(world, "disp_explosion"); + if (st == "off") + disp_explosion = FALSE; + else + disp_explosion = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/engineer.qc b/engineer.qc index 10399400..fc276d9c 100644 --- a/engineer.qc +++ b/engineer.qc @@ -754,9 +754,16 @@ void () Dispenser_Explode = { if (self.real_owner.has_disconnected != 1) { deathmsg = 39; - sdmg = 45 + self.ammo_rockets * 3 + self.ammo_cells; - if (sdmg > 350) { - sdmg = 350; + if (disp_explosion) { + sdmg = 45 + self.ammo_rockets * 3 + self.ammo_cells; + if (sdmg > 350) { + sdmg = 350; + } + } else { + sdmg = 25 + self.ammo_rockets * 3 + self.ammo_cells; + if (sdmg > 250) { + sdmg = 250; + } } T_RadiusDamage(self, self.real_owner, sdmg, self); } diff --git a/qw.qc b/qw.qc index 9260aa9e..a0c48d81 100644 --- a/qw.qc +++ b/qw.qc @@ -435,6 +435,7 @@ float medicaura; float old_medikit; float old_biodamage; float flame_knockback; +float disp_explosion; float old_spanner; float old_railgun; From 2f5f18142bae34f5d58486af3e2616d480bc7813 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 01:17:02 +0200 Subject: [PATCH 0268/2474] Add option for Assault Cannon lock --- client.qc | 8 ++++++++ qw.qc | 1 + weapons.qc | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 110e864a..e91874a2 100644 --- a/client.qc +++ b/client.qc @@ -506,6 +506,14 @@ void () DecodeLevelParms = { else disp_explosion = TRUE; + st = infokey(world, "cl"); + if (st == string_null) + st = infokey(world, "cannon_lock"); + if (st == "off") + cannon_lock = FALSE; + else + cannon_lock = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index a0c48d81..1b5d0a42 100644 --- a/qw.qc +++ b/qw.qc @@ -436,6 +436,7 @@ float old_medikit; float old_biodamage; float flame_knockback; float disp_explosion; +float cannon_lock; float old_spanner; float old_railgun; diff --git a/weapons.qc b/weapons.qc index 9a93a370..9bf082ef 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2631,7 +2631,7 @@ void () W_WeaponFrame = { // hwguy assault cannon special if (self.playerclass == PC_HVYWEAP) { - if (self.impulse == TF_LOCK) { + if (self.impulse == TF_LOCK && cannon_lock) { if (self.tfstate & TFSTATE_LOCK) self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); else From f45c3c6d037d520156d0c0e8cb7d8c5ff5a10726 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 01:17:21 +0200 Subject: [PATCH 0269/2474] Add option for firing Assault Cannon while in air --- client.qc | 28 ++++++++++++++++++++++++++-- qw.qc | 2 ++ weapons.qc | 9 +++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/client.qc b/client.qc index e91874a2..c17d3a36 100644 --- a/client.qc +++ b/client.qc @@ -514,6 +514,14 @@ void () DecodeLevelParms = { else cannon_lock = TRUE; + st = infokey(world, "ca"); + if (st == string_null) + st = infokey(world, "cannon_air"); + if (st == "off") + cannon_air = FALSE; + else + cannon_air = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; @@ -1491,8 +1499,24 @@ void () PlayerJump = { sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); + if (!cannon_air) { + if (self.antispam_cannon_air < time) { + sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); + self.antispam_cannon_air = time + 3; + } + self.tfstate = self.tfstate | TFSTATE_AIMING; + TeamFortress_SetSpeed(self); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + TeamFortress_SetSpeed(self); + self.weaponframe = 0; + self.count = 1; + self.heat = 0; + player_assaultcannondown1(); + stuffcmd(self, "v_idlescale 0\n"); + } else { + self.tfstate = self.tfstate | TFSTATE_AIMING; + TeamFortress_SetSpeed(self); + } } if (old_grens != 1) { te = find(world, classname, "timer"); diff --git a/qw.qc b/qw.qc index 1b5d0a42..c6d1025d 100644 --- a/qw.qc +++ b/qw.qc @@ -389,6 +389,7 @@ float already_chosen_map; .float antispam_detpack; // don't spam detpack messages .float antispam_feign; // don't spam feign deaths .float antispam_assault_cannon; // don't spam assault cannon messages +.float antispam_cannon_air; // don't spam assault cannon air messages // status bar stuff .string StatusString; // current centerprint text (strzone'd!) @@ -437,6 +438,7 @@ float old_biodamage; float flame_knockback; float disp_explosion; float cannon_lock; +float cannon_air; float old_spanner; float old_railgun; diff --git a/weapons.qc b/weapons.qc index 9bf082ef..98b38348 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2701,8 +2701,13 @@ void () W_WeaponFrame = { } } } else { - SuperDamageSound(); - W_Attack(); + if (self.flags & FL_ONGROUND || cannon_air) { + SuperDamageSound(); + W_Attack(); + } else if (self.antispam_cannon_air < time) { + sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); + self.antispam_cannon_air = time + 3; + } } } else if (self.playerclass == 0) { self.weaponmode = 0; From 602c65a0ae188f5e77b5d680a6c5e3dd75fef380 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:01:18 +0200 Subject: [PATCH 0270/2474] Merge nts with nt setinfo (closes #189) --- tfort.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index 78442530..272f7038 100644 --- a/tfort.qc +++ b/tfort.qc @@ -517,7 +517,7 @@ void () GrenadeTimer = { Status_Refresh(self.owner); if (self.heat > 0) { - if (!stof(infokey(self.owner, "nts"))) + if (!stof(infokey(self.owner, "nt"))) stuffcmd(self.owner, "play items/grentimer.wav\n"); self.nextthink = time + 1.0; } else { @@ -695,7 +695,8 @@ void (float inp) TeamFortress_PrimeGrenade = { RemoveGrenadeTimers(); - if (grentimers && !stof(infokey(self, "nt"))) { + local float notimers = stof(infokey(self, "nt")); + if (grentimers && notimers != 1) { timer = spawn(); timer.nextthink = time + 0.8; timer.think = GrenadeTimer; From ca7607ca949716decb992026ce0f7206fe9334f6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:02:55 +0200 Subject: [PATCH 0271/2474] Add slot1-4 aliases (closes #190) --- tforthlp.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tforthlp.qc b/tforthlp.qc index 761ebd14..a4dd9b12 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -96,6 +96,10 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); + TeamFortress_Alias("slot1", 1, 0); + TeamFortress_Alias("slot2", 2, 0); + TeamFortress_Alias("slot3", 3, 0); + TeamFortress_Alias("slot4", 4, 0); TeamFortress_AliasString("+slot1", "impulse 31;+attack"); TeamFortress_AliasString("-slot1", "-attack;impulse 68"); TeamFortress_AliasString("+slot2", "impulse 32;+attack"); From a368cdb4b2b69bd88016d8baf7fe0ce58d13ed0c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:07:55 +0200 Subject: [PATCH 0272/2474] Weaplast cancels detpack (fixes #191) --- weapons.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/weapons.qc b/weapons.qc index 98b38348..0d4b6030 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2233,6 +2233,9 @@ void () ImpulseCommands = { else if (self.playerclass == PC_ENGINEER && self.is_building) { TeamFortress_EngineerBuildStop(); CycleWeaponLast(); + } else if (self.playerclass == PC_DEMOMAN && self.is_detpacking) { + TeamFortress_DetpackStop(); + CycleWeaponLast(); } } else if (self.impulse == TF_TOGGLEVOTE) Vote_ToggleMenu(self); From 0ffc0d9d943676edfb82ebb74ba1d70d7e5a4e3f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:10:59 +0200 Subject: [PATCH 0273/2474] Allow dropflag during reload (fixes #198) --- weapons.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index 0d4b6030..20a8c43d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2667,8 +2667,9 @@ void () W_WeaponFrame = { return; } - // /saveme, /dash, /discard - if (self.impulse == TF_MEDIC_HELPME || self.impulse == TF_DASH || self.impulse == TF_DISCARD) { + // /saveme, /dash, /discard, /dropflag + if (self.impulse == TF_MEDIC_HELPME || self.impulse == TF_DASH || self.impulse == TF_DISCARD + || self.impulse == TF_DROPFLAG) { ImpulseCommands(); return; } From ed7193bf09da1e97c2eec627251f80c8c39aea33 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:18:18 +0200 Subject: [PATCH 0274/2474] Swap last disguise team when changing team as Spy (fixes #197) --- tforttm.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tforttm.qc b/tforttm.qc index e278e170..68f8e498 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -185,6 +185,9 @@ float (float tno) TeamFortress_TeamSet = { if (!self.deadflag) { ClientKill(); } + // swap colors for spy last disguise + if (self.playerclass == PC_SPY && self.undercover_team == tno) + self.last_team = self.team_no; bprint(PRINT_HIGH, self.netname, " has joined the "); bprint(PRINT_HIGH, team, "\n"); stuffcmd(self, "color "); From f801853fb0f744e81ff36b2c83b9255e39ee8145 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:20:33 +0200 Subject: [PATCH 0275/2474] Only allow dash for Scout (fixes #195) --- scout.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scout.qc b/scout.qc index 9d24be66..1136bf88 100644 --- a/scout.qc +++ b/scout.qc @@ -19,6 +19,9 @@ entity(entity scanner, float scanrange, float enemies, void () CF_Scout_Dash = { local float f_velocity; + if (self.playerclass != PC_SCOUT) + return; + // check if dash is allowed in rules and if cooldown has ended if (!(toggleflags & TFLAG_SCOUTDASH) || time < self.dash_cooldown) return; From d8dc3aa669900478a7f8d0b4104553f153c10856 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:33:49 +0200 Subject: [PATCH 0276/2474] Add build cancel menu for Engineer (closes #194) --- engineer.qc | 4 ++++ menu.qc | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/engineer.qc b/engineer.qc index fc276d9c..87ceba91 100644 --- a/engineer.qc +++ b/engineer.qc @@ -16,6 +16,7 @@ void (entity disp) Engineer_SentryGun_ShowMenu; void (entity disp) Engineer_SentryGun_InsertAmmo; void (entity disp) Engineer_SentryGun_Upgrade; void (entity disp) Engineer_SentryGun_Repair; +void () Menu_Engineer_Cancel; float (entity obj, entity builder) CheckArea; void () LaserBolt_Think = { @@ -266,6 +267,7 @@ void () TeamFortress_EngineerBuildStop = { te = find(te, netname, "build_timer"); } } + Menu_Close(self); self.is_building = 0; self.current_weapon = self.weapon; W_SetCurrentAmmo(self); @@ -380,6 +382,7 @@ void (float objtobuild) TeamFortress_Build = { self.weaponframe = 0; TeamFortress_SetSpeed(self); Status_Refresh(self); + Menu_Engineer_Cancel(); newmis.owner = self; newmis.classname = "timer"; @@ -621,6 +624,7 @@ void () TeamFortress_FinishedBuilding = { self.current_weapon = self.weapon; Status_Refresh(self); TeamFortress_SetSpeed(self); + Menu_Close(self); if (oldself.weapon == 1) { self.has_dispenser = TRUE; sprint(self, PRINT_HIGH, "You finish building the dispenser\n"); diff --git a/menu.qc b/menu.qc index 76a749e5..4f0eea8c 100644 --- a/menu.qc +++ b/menu.qc @@ -43,6 +43,8 @@ void (entity disp) Engineer_Dispenser_Repair; void (entity disp) Engineer_SentryGun_InsertAmmo; void (entity disp) Engineer_SentryGun_Upgrade; void (entity disp) Engineer_SentryGun_Repair; +void () Menu_Engineer_Cancel; +void () TeamFortress_EngineerBuildStop; void (entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage; @@ -935,3 +937,17 @@ void () Menu_Dispenser = { Status_Menu(self, Menu_Dispenser_Input, s_action, s_ammo, s_armor, s_nothing); }; + +void (float inp) Menu_Engineer_Cancel_Input = { + if (inp == 1) + TeamFortress_EngineerBuildStop(); + else + Menu_Engineer_Cancel(); +} + +void () Menu_Engineer_Cancel = { + local string s_build = "Building...\n\n"; + local string s_cancel = "“‘ Cancel!\n\n\n\n\n"; + + Status_Menu(self, Menu_Engineer_Cancel_Input, s_build, s_cancel); +} From 903202128b72329350a750e0d7854abaee43de0c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 21:44:38 +0200 Subject: [PATCH 0277/2474] Only allow aura command for Medics --- medic.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/medic.qc b/medic.qc index eed0f67d..ccb6aa57 100644 --- a/medic.qc +++ b/medic.qc @@ -7,7 +7,7 @@ void () CF_Medic_AuraToggle; // initializes the medic healing aura // called from weapons.qc:ImpulseCommands() void () CF_Medic_AuraToggle = { - if (!medicaura) + if (!medicaura || self.playerclass != PC_MEDIC) return; if (self.aura_active) { From 4cd669968145c17507e2d8bd9699618129f7c741 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 22:56:35 +0200 Subject: [PATCH 0278/2474] Fix spy jump bug (if feigned on ground) --- spy.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spy.qc b/spy.qc index 2281f263..cad82cb4 100644 --- a/spy.qc +++ b/spy.qc @@ -447,8 +447,12 @@ void (float issilent) CF_Spy_FeignDeath = { // don't check for team color cheat for 5 seconds self.immune_to_check = time + 5; + // set movetype to toss + self.movetype = MOVETYPE_TOSS; + // stop spy from moving if on the ground if (self.flags & FL_ONGROUND) { + self.movetype = MOVETYPE_NONE; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } @@ -473,9 +477,6 @@ void (float issilent) CF_Spy_FeignDeath = { // set view height to ground self.view_ofs = '0 0 4'; - // set movetype to toss - self.movetype = MOVETYPE_TOSS; - // do extra stuff if feign is not silent feign if (issilent == 0) { // make a death sound From 9ec737a4ba7642a06d2cf9e7b7fa4ebe02187d8b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 9 Sep 2014 23:50:51 +0200 Subject: [PATCH 0279/2474] Don't remove gas grenades except when disconnecting and changing teams (fixes #199) --- client.qc | 2 ++ spy.qc | 6 +++--- tfort.qc | 11 +++++++++++ tforttm.qc | 2 ++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index c17d3a36..225af850 100644 --- a/client.qc +++ b/client.qc @@ -20,6 +20,7 @@ void () SetupTeamEqualiser; void () CeaseFire_think; void () RemoveGrenadeTimers; +void () RemoveGasTimers; void () RemoveGrenades; void (entity eng) Engineer_RemoveBuildings; @@ -2041,6 +2042,7 @@ void () ClientDisconnect = { sound(self, 4, "player/tornoff2.wav", 1, ATTN_NONE); self.has_disconnected = 1; TeamFortress_RemoveTimers(); + RemoveGasTimers(); Engineer_RemoveBuildings(self); te = find(world, classname, "detpack"); while (te) { diff --git a/spy.qc b/spy.qc index cad82cb4..44787651 100644 --- a/spy.qc +++ b/spy.qc @@ -864,7 +864,7 @@ void () GasGrenadeExplode = { te = spawn(); te.think = GasGrenadeMakeGas; te.nextthink = time + 0.1; - te.classname = "grentimer"; + te.classname = "gastimer"; te.heat = 0; te.origin = self.origin; te.owner = self.owner; @@ -901,7 +901,7 @@ void () GasGrenadeMakeGas = { self.owner.no_active_gas_grens = self.owner.no_active_gas_grens + 1; if (self.owner.no_active_gas_grens > 2) { - te = find(world, classname, "grentimer"); + te = find(world, classname, "gastimer"); while (te) { if ((te.owner == self.owner) && (te.no_active_gas_grens == 1)) { @@ -909,7 +909,7 @@ void () GasGrenadeMakeGas = { te.think = RemoveGrenade; te.nextthink = time + 0.1; } - te = find(te, classname, "grentimer"); + te = find(te, classname, "gastimer"); } } self.no_active_gas_grens = self.owner.no_active_gas_grens; diff --git a/tfort.qc b/tfort.qc index 272f7038..a52796e0 100644 --- a/tfort.qc +++ b/tfort.qc @@ -105,6 +105,17 @@ void () RemoveGrenadeTimers = { } }; +void () RemoveGasTimers = { + local entity te; + + te = find(world, classname, "gastimer"); + while (te != world) { + if (te.owner == self) + dremove(te); + te = find(te, classname, "gastimer"); + } +}; + void () RemoveGrenades = { local entity te = find(world, classname, "grenade"); while (te) { diff --git a/tforttm.qc b/tforttm.qc index 68f8e498..998f24d6 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -188,6 +188,8 @@ float (float tno) TeamFortress_TeamSet = { // swap colors for spy last disguise if (self.playerclass == PC_SPY && self.undercover_team == tno) self.last_team = self.team_no; + // remove existing gas grenades + RemoveGasTimers(); bprint(PRINT_HIGH, self.netname, " has joined the "); bprint(PRINT_HIGH, team, "\n"); stuffcmd(self, "color "); From 4c29a9fff732b0a23d3c210470f0ce9e37f4b537 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 10 Sep 2014 00:08:31 +0200 Subject: [PATCH 0280/2474] Force kill when changing teams --- client.qc | 4 ++-- defs.qc | 2 +- tfort.qc | 2 +- tforttm.qc | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 225af850..c795d119 100644 --- a/client.qc +++ b/client.qc @@ -872,7 +872,7 @@ float () CloseToSpawnPoint = { return 0; }; -void () ClientKill = { +void (float force) ClientKill = { local entity te; local float timeleft; @@ -883,7 +883,7 @@ void () ClientKill = { if (self.playerclass == PC_UNDEFINED) return; - if (self.suicide_time > time) { + if (self.suicide_time > time && !force) { timeleft = self.suicide_time - time; sprint(self, PRINT_HIGH, "You have to wait ", ftos(ceil(timeleft)), " more seconds to suicide\n"); return; diff --git a/defs.qc b/defs.qc index 9a5a540a..86c63645 100644 --- a/defs.qc +++ b/defs.qc @@ -60,7 +60,7 @@ void () StartFrame; void () PlayerPreThink; // Called every frame before physics are run void () PlayerPostThink; // Called every frame after physics are run -void () ClientKill; // Player entered the suicide command +void (float force) ClientKill; // Player entered the suicide command void () ClientConnect; // called when a player connects to a server void () PutClientInServer; // call after setting the parm1... parms void () ClientDisconnect; // called when a player disconnects from a server diff --git a/tfort.qc b/tfort.qc index a52796e0..cec1845e 100644 --- a/tfort.qc +++ b/tfort.qc @@ -158,7 +158,7 @@ void (float inp) TeamFortress_ChangeClass = { } self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint() && self.suicide_time <= time) { - ClientKill(); + ClientKill(0); } else { sprint(self, PRINT_HIGH, "After dying, you will return as a "); TeamFortress_PrintClassName(self, self.nextpc, 0); diff --git a/tforttm.qc b/tforttm.qc index 998f24d6..15437a1b 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -183,7 +183,7 @@ float (float tno) TeamFortress_TeamSet = { return (1); } if (!self.deadflag) { - ClientKill(); + ClientKill(1); } // swap colors for spy last disguise if (self.playerclass == PC_SPY && self.undercover_team == tno) From b4077721d0e37633a5f4a91cafeda4979ca948df Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 10 Sep 2014 00:08:52 +0200 Subject: [PATCH 0281/2474] Allow changing class several times --- tfort.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tfort.qc b/tfort.qc index cec1845e..c245b8d1 100644 --- a/tfort.qc +++ b/tfort.qc @@ -159,6 +159,7 @@ void (float inp) TeamFortress_ChangeClass = { self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint() && self.suicide_time <= time) { ClientKill(0); + self.suicide_time = time; } else { sprint(self, PRINT_HIGH, "After dying, you will return as a "); TeamFortress_PrintClassName(self, self.nextpc, 0); From e985fa68d3c5bc34c178a2bc004391e4706ebdc9 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 13:15:51 +0200 Subject: [PATCH 0282/2474] Add option for allowing movement with Assault Cannon --- client.qc | 6 ++++++ player.qc | 11 +++++++++++ qw.qc | 1 + 3 files changed, 18 insertions(+) diff --git a/client.qc b/client.qc index c795d119..973d6d9f 100644 --- a/client.qc +++ b/client.qc @@ -523,6 +523,12 @@ void () DecodeLevelParms = { else cannon_air = TRUE; + st = infokey(world, "cm"); + if (st == string_null) + st = infokey(world, "cannon_move"); + if (st == "on") + cannon_move = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/player.qc b/player.qc index 95664caf..e30d63d5 100644 --- a/player.qc +++ b/player.qc @@ -414,6 +414,11 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { SuperDamageSound(); + self.tfstate = self.tfstate | TFSTATE_AIMING; + if (!cannon_move) + self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + W_FireAssaultCannon(); stuffcmd(self, "v_idlescale "); if (vlen(self.velocity) < 30) { @@ -442,6 +447,8 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { stuffcmd(self, "v_idlescale 0\n"); self.tfstate = self.tfstate | TFSTATE_AIMING; + if (!cannon_move) + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); self.weaponframe = 0; self.count = 1; @@ -473,6 +480,8 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { stuffcmd(self, "v_idlescale 0\n"); self.tfstate = self.tfstate | TFSTATE_AIMING; + if (!cannon_move) + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); self.weaponframe = 0; self.count = 1; @@ -490,6 +499,8 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { self.heat = 0; self.fire_held_down = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); + if (!cannon_move) + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { self.current_weapon = W_BestWeapon(); diff --git a/qw.qc b/qw.qc index c6d1025d..014e5bdd 100644 --- a/qw.qc +++ b/qw.qc @@ -439,6 +439,7 @@ float flame_knockback; float disp_explosion; float cannon_lock; float cannon_air; +float cannon_move; float old_spanner; float old_railgun; From db648d11d7eaa081bddfa54bb28a598d8d37879a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:04:23 +0200 Subject: [PATCH 0283/2474] Allow Assault Cannon air fire by default --- client.qc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client.qc b/client.qc index 973d6d9f..08f49c2c 100644 --- a/client.qc +++ b/client.qc @@ -518,9 +518,7 @@ void () DecodeLevelParms = { st = infokey(world, "ca"); if (st == string_null) st = infokey(world, "cannon_air"); - if (st == "off") - cannon_air = FALSE; - else + if (st == "on") cannon_air = TRUE; st = infokey(world, "cm"); From cd6a34591dac1848871ec6a61c23b47a74bf3992 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:05:12 +0200 Subject: [PATCH 0284/2474] Add option for making Assault Cannon spin while moving --- client.qc | 8 ++++++++ player.qc | 3 ++- qw.qc | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 08f49c2c..7785f39f 100644 --- a/client.qc +++ b/client.qc @@ -527,6 +527,14 @@ void () DecodeLevelParms = { if (st == "on") cannon_move = TRUE; + st = infokey(world, "cms"); + if (st == string_null) + st = infokey(world, "cannon_movespin"); + if (st == "off") + cannon_movespin = FALSE; + else + cannon_movespin = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/player.qc b/player.qc index e30d63d5..235cea93 100644 --- a/player.qc +++ b/player.qc @@ -403,7 +403,8 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { void () player_assaultcannon1 =[103, player_assaultcannon2] { local string st; - if (vlen(self.velocity) <= 90 && !(self.tfstate & TFSTATE_LOCK)) { + if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) <= 30) + && !(self.tfstate & TFSTATE_LOCK)) { muzzleflash(); sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); diff --git a/qw.qc b/qw.qc index 014e5bdd..5c00a459 100644 --- a/qw.qc +++ b/qw.qc @@ -440,6 +440,7 @@ float disp_explosion; float cannon_lock; float cannon_air; float cannon_move; +float cannon_movespin; float old_spanner; float old_railgun; From d9e1a0eda62af1a9f6b037fe9863c05dcff74403 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:06:00 +0200 Subject: [PATCH 0285/2474] Add option for making HWGuy susceptible to conc grenades while firing Assault Cannon --- client.qc | 8 ++++++++ qw.qc | 1 + scout.qc | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 7785f39f..6ebd8f25 100644 --- a/client.qc +++ b/client.qc @@ -535,6 +535,14 @@ void () DecodeLevelParms = { else cannon_movespin = TRUE; + st = infokey(world, "cc"); + if (st == string_null) + st = infokey(world, "cannon_conc"); + if (st == "off") + cannon_conc = FALSE; + else + cannon_conc = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index 5c00a459..dbc76239 100644 --- a/qw.qc +++ b/qw.qc @@ -441,6 +441,7 @@ float cannon_lock; float cannon_air; float cannon_move; float cannon_movespin; +float cannon_conc; float old_spanner; float old_railgun; diff --git a/scout.qc b/scout.qc index 1136bf88..b518bc6f 100644 --- a/scout.qc +++ b/scout.qc @@ -335,7 +335,7 @@ void () ConcussionGrenadeTimer = { pos = pointcontents(src); if ((self.owner.flags & 512) || (self.owner.flags & 16)) { - if (self.owner.is_feigning == 0) { + if (!self.owner.is_feigning && !(self.owner.current_weapon == WEAP_ASSAULT_CANNON && !cannon_conc && self.owner.button0)) { makevectors(self.owner.v_angle); stumble = crandom() * self.health; if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { From a49836a7acead650a70878c8e4fe63216e619bac Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:26:05 +0200 Subject: [PATCH 0286/2474] Improve dash code --- scout.qc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scout.qc b/scout.qc index b518bc6f..92420751 100644 --- a/scout.qc +++ b/scout.qc @@ -17,8 +17,6 @@ entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; void () CF_Scout_Dash = { - local float f_velocity; - if (self.playerclass != PC_SCOUT) return; @@ -30,11 +28,8 @@ void () CF_Scout_Dash = { if (self.leg_damage || self.is_concussed) return; - // determine current speed - f_velocity = floor(fabs(self.velocity_x) + fabs(self.velocity_z)); - // only dash if walking or slower - if (f_velocity <= 448 && (self.flags & FL_ONGROUND)) { + if (vlen(self.velocity) <= 450 && (self.flags & FL_ONGROUND)) { makevectors(self.angles); self.velocity = v_forward * 540; self.velocity_z = 190; From 61df227fae9f91f022b57284a2f37d847c07269c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:26:21 +0200 Subject: [PATCH 0287/2474] Remove useless weaponframe code --- weapons.qc | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/weapons.qc b/weapons.qc index 20a8c43d..42dc5d7a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2680,16 +2680,7 @@ void () W_WeaponFrame = { if (self.impulse != 0 && self.has_disconnected == 0) ImpulseCommands(); - if ((self.button0 && self.fire_held_down) && - (self.current_weapon == WEAP_ASSAULT_CANNON)) { - player_assaultcannonup1(); - } else if ((!self.button0 && self.fire_held_down) && - (self.current_weapon == WEAP_ASSAULT_CANNON)) { - self.fire_held_down = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); - TeamFortress_SetSpeed(self); - player_run(); - } else if (self.button0 && !self.fire_held_down) { + if (self.button0 && !self.fire_held_down) { if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) @@ -2704,7 +2695,7 @@ void () W_WeaponFrame = { TeamFortress_SetSpeed(self); } } - } else { + } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { if (self.flags & FL_ONGROUND || cannon_air) { SuperDamageSound(); W_Attack(); @@ -2712,6 +2703,9 @@ void () W_WeaponFrame = { sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); self.antispam_cannon_air = time + 3; } + } else { + SuperDamageSound(); + W_Attack(); } } else if (self.playerclass == 0) { self.weaponmode = 0; From 0e4a37c1a716824b23a4d55a333457f9c0b1933a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:48:16 +0200 Subject: [PATCH 0288/2474] Add option for Assault Cannon accuracy as per TF 2.8/2.9 --- client.qc | 6 ++++++ qw.qc | 1 + weapons.qc | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 6ebd8f25..0d303111 100644 --- a/client.qc +++ b/client.qc @@ -543,6 +543,12 @@ void () DecodeLevelParms = { else cannon_conc = TRUE; + st = infokey(world, "cac"); + if (st == string_null) + st = infokey(world, "cannon_accuracy"); + if (st != string_null) + cannon_accuracy = stof(st); + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index dbc76239..000dc4fa 100644 --- a/qw.qc +++ b/qw.qc @@ -442,6 +442,7 @@ float cannon_air; float cannon_move; float cannon_movespin; float cannon_conc; +float cannon_accuracy; float old_spanner; float old_railgun; diff --git a/weapons.qc b/weapons.qc index 42dc5d7a..f10052cf 100644 --- a/weapons.qc +++ b/weapons.qc @@ -928,7 +928,11 @@ void () W_FireAssaultCannon = { dir = aim(self, 100000); deathmsg = DMSG_ASSAULTCANNON; - if (vlen(self.velocity) < 50) + if (cannon_accuracy == 1) + FireBullets(5, dir, '0 0 0'); + else if (cannon_accuracy == 2) + FireBullets(5, dir, '0.1 0.1 0'); + else if (vlen(self.velocity) < 50) FireBullets(5, dir, '0.075 0.075 0'); else FireBullets(5, dir, '0.15 0.15 0'); From dc40e6272f6e533f6f49c19a1118bbd2c0aac850 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:48:24 +0200 Subject: [PATCH 0289/2474] Picking up backpacks no longer messes up adjusted movement speeds --- weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index f10052cf..b905c76c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1384,7 +1384,8 @@ void (entity pl) W_SetCurrentAmmo = { if ((pl.health <= 0) || (pl.current_weapon == 0)) return; - player_run(); + if (!(self.tfstate & TFSTATE_AIMING) && !(self.tfstate & TFSTATE_CANT_MOVE)) + player_run(); pl.items = pl.items - (pl.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS)); pl.weapon = 0; From 1f5b66f2ea484cc0102b4dbb4f300115735d7365 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 14:57:26 +0200 Subject: [PATCH 0290/2474] Change some defaults --- client.qc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 0d303111..0bdad879 100644 --- a/client.qc +++ b/client.qc @@ -518,21 +518,23 @@ void () DecodeLevelParms = { st = infokey(world, "ca"); if (st == string_null) st = infokey(world, "cannon_air"); - if (st == "on") + if (st == "off") + cannon_air = FALSE; + else cannon_air = TRUE; st = infokey(world, "cm"); if (st == string_null) st = infokey(world, "cannon_move"); - if (st == "on") + if (st == "off") + cannon_move = FALSE; + else cannon_move = TRUE; st = infokey(world, "cms"); if (st == string_null) st = infokey(world, "cannon_movespin"); - if (st == "off") - cannon_movespin = FALSE; - else + if (st == "on") cannon_movespin = TRUE; st = infokey(world, "cc"); From 84a4679b1ff7195cf266bafe57a9217fbc89d09a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 15:14:02 +0200 Subject: [PATCH 0291/2474] Add option for allowing feign death while airborne --- client.qc | 8 ++++++++ qw.qc | 1 + spy.qc | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/client.qc b/client.qc index 0bdad879..e93384db 100644 --- a/client.qc +++ b/client.qc @@ -551,6 +551,14 @@ void () DecodeLevelParms = { if (st != string_null) cannon_accuracy = stof(st); + st = infokey(world, "fa"); + if (st == string_null) + st = infokey(world, "feign_air"); + if (st == "off") + feign_air = FALSE; + else + feign_air = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index 000dc4fa..83d2da8a 100644 --- a/qw.qc +++ b/qw.qc @@ -443,6 +443,7 @@ float cannon_move; float cannon_movespin; float cannon_conc; float cannon_accuracy; +float feign_air; float old_spanner; float old_railgun; diff --git a/spy.qc b/spy.qc index 44787651..030924b5 100644 --- a/spy.qc +++ b/spy.qc @@ -434,6 +434,12 @@ void (float issilent) CF_Spy_FeignDeath = { return; } + // don't allow feign if spy is in air and air feigning is disallowed + if (!feign_air && !(self.flags & FL_ONGROUND)) { + sprint(self, PRINT_HIGH, "You cannot feign while you are airborne\n"); + return; + } + // check area for feigned spy on the ground area_check = Spy_CheckArea(self); if (area_check == 3) { From 38fa833fe5f490efd8fdd420e4d88f48f2198c0d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 15:16:43 +0200 Subject: [PATCH 0292/2474] Add option for dropping a fake backpack when feigning death --- client.qc | 8 ++++++++ qw.qc | 1 + spy.qc | 5 +++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index e93384db..b740c8a7 100644 --- a/client.qc +++ b/client.qc @@ -559,6 +559,14 @@ void () DecodeLevelParms = { else feign_air = TRUE; + st = infokey(world, "fp"); + if (st == string_null) + st = infokey(world, "feign_pack"); + if (st == "off") + feign_pack = FALSE; + else + feign_pack = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index 83d2da8a..e21901ca 100644 --- a/qw.qc +++ b/qw.qc @@ -444,6 +444,7 @@ float cannon_movespin; float cannon_conc; float cannon_accuracy; float feign_air; +float feign_pack; float old_spanner; float old_railgun; diff --git a/spy.qc b/spy.qc index 030924b5..418af82f 100644 --- a/spy.qc +++ b/spy.qc @@ -488,8 +488,9 @@ void (float issilent) CF_Spy_FeignDeath = { // make a death sound DeathSound(); - // drop an empty backpack - Spy_DropBackpack(); + // drop an empty backpack (if this is not disabled in settings) + if (feign_pack) + Spy_DropBackpack(); // print feign message deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); From 5eeea1ef0c264571c63419ccc4940693dea25da0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 15:18:41 +0200 Subject: [PATCH 0293/2474] Add option for printing fake death message when feigning death --- client.qc | 8 ++++++++ qw.qc | 1 + spy.qc | 8 +++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index b740c8a7..7db6614f 100644 --- a/client.qc +++ b/client.qc @@ -567,6 +567,14 @@ void () DecodeLevelParms = { else feign_pack = TRUE; + st = infokey(world, "fm"); + if (st == string_null) + st = infokey(world, "feign_msg"); + if (st == "off") + feign_msg = FALSE; + else + feign_msg = TRUE; + st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; diff --git a/qw.qc b/qw.qc index e21901ca..a4df47b6 100644 --- a/qw.qc +++ b/qw.qc @@ -445,6 +445,7 @@ float cannon_conc; float cannon_accuracy; float feign_air; float feign_pack; +float feign_msg; float old_spanner; float old_railgun; diff --git a/spy.qc b/spy.qc index 418af82f..8f908b31 100644 --- a/spy.qc +++ b/spy.qc @@ -492,9 +492,11 @@ void (float issilent) CF_Spy_FeignDeath = { if (feign_pack) Spy_DropBackpack(); - // print feign message - deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); - bprint(PRINT_MEDIUM, deathstring); + // print feign message (if this is not disabled in settings) + if (feign_msg) { + deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); + bprint(PRINT_MEDIUM, deathstring); + } // set movement speed to 0 if currently in the air to disable manipulation of trajectory if (!(self.flags & FL_ONGROUND)) From 5a593a67cb1e2fe905c92721c978c80431db9fa1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 15:45:37 +0200 Subject: [PATCH 0294/2474] Improve code for some settings --- client.qc | 28 ++++++++++++++++------------ defs.h | 3 --- qw.qc | 3 +++ scout.qc | 2 +- status.qc | 2 +- tfort.qc | 20 ++++++++++---------- weapons.qc | 6 +++--- 7 files changed, 34 insertions(+), 30 deletions(-) diff --git a/client.qc b/client.qc index 7db6614f..7faba8ea 100644 --- a/client.qc +++ b/client.qc @@ -583,28 +583,32 @@ void () DecodeLevelParms = { if (st == string_null) st = infokey(world, "spyinvis"); - if ((st == "on") || (toggleflags & TFLAG_SPYINVIS)) - invis_only = TRUE; - else if (st == "off") - invis_only = FALSE; + st = infokey(world, "sd"); + if (st == string_null) + st = infokey(world, "scoutdash"); + if (st == "off") + scoutdash = FALSE; + else + scoutdash = TRUE; st = infokey(world, "sr"); if (st == string_null) st = infokey(world, "sniperreload"); - if (st != "off") - toggleflags = toggleflags | TFLAG_SNIPERRELOAD; + if (st == "off") + sniperreload = FALSE; + else + sniperreload = TRUE; st = infokey(world, "sf"); if (st == string_null) st = infokey(world, "spawnfull"); if (st == "on") - toggleflags = toggleflags | TFLAG_SPAWNFULL; + spawnfull = TRUE; - st = infokey(world, "sd"); - if (st == string_null) - st = infokey(world, "scoutdash"); - if (st != "off") - toggleflags = toggleflags | TFLAG_SCOUTDASH; + if ((st == "on") || (toggleflags & TFLAG_SPYINVIS)) + invis_only = TRUE; + else if (st == "off") + invis_only = FALSE; st = infokey(world, "rd"); if (st == string_null) diff --git a/defs.h b/defs.h index 26a4267f..bca67702 100644 --- a/defs.h +++ b/defs.h @@ -279,9 +279,6 @@ #define TFLAG_FULLTEAMSCORE 2048 #define TFLAG_FLAGEMU 4096 #define TFLAG_WARSTANDARD 8192 -#define TFLAG_SNIPERRELOAD 16384 // Sniper reload enabled -#define TFLAG_SPAWNFULL 32768 // Spawn fully stocked -#define TFLAG_SCOUTDASH 65536 // Scout dash enabled #define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn #define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn diff --git a/qw.qc b/qw.qc index a4df47b6..f0eb85f6 100644 --- a/qw.qc +++ b/qw.qc @@ -446,6 +446,9 @@ float cannon_accuracy; float feign_air; float feign_pack; float feign_msg; +float scoutdash; +float sniperreload; +float spawnfull; float old_spanner; float old_railgun; diff --git a/scout.qc b/scout.qc index 92420751..c75b817f 100644 --- a/scout.qc +++ b/scout.qc @@ -21,7 +21,7 @@ void () CF_Scout_Dash = { return; // check if dash is allowed in rules and if cooldown has ended - if (!(toggleflags & TFLAG_SCOUTDASH) || time < self.dash_cooldown) + if (!scoutdash || time < self.dash_cooldown) return; // don't dash if scout is concussed or have damaged legs diff --git a/status.qc b/status.qc index d11e2737..c1f8f06e 100644 --- a/status.qc +++ b/status.qc @@ -304,7 +304,7 @@ string(entity pl) ClipSizeToString = pl.reload_super_shotgun = max - pl.ammo_shells; num = (max - pl.reload_super_shotgun); } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { - if (!(toggleflags & TFLAG_SNIPERRELOAD)) + if (!sniperreload) return (""); if ((max - pl.reload_sniper_rifle) > pl.ammo_shells) pl.reload_sniper_rifle = max - pl.ammo_shells; diff --git a/tfort.qc b/tfort.qc index c245b8d1..2cef6890 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1474,7 +1474,7 @@ void () TeamFortress_SetEquipment = { if (self.playerclass == PC_SCOUT) { self.weapons_carried = self.weapons_carried | PC_SCOUT_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_SCOUT_MAXAMMO_ROCKET; self.ammo_nails = PC_SCOUT_MAXAMMO_NAIL; self.ammo_shells = PC_SCOUT_MAXAMMO_SHOT; @@ -1527,7 +1527,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_SNIPER) { self.weapons_carried = self.weapons_carried | PC_SNIPER_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_SNIPER_MAXAMMO_ROCKET; self.ammo_nails = PC_SNIPER_MAXAMMO_NAIL; self.ammo_shells = PC_SNIPER_MAXAMMO_SHOT; @@ -1572,7 +1572,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_SOLDIER) { self.weapons_carried = self.weapons_carried | PC_SOLDIER_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET; self.ammo_nails = PC_SOLDIER_MAXAMMO_NAIL; self.ammo_shells = PC_SOLDIER_MAXAMMO_SHOT; @@ -1618,7 +1618,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_DEMOMAN) { self.weapons_carried = self.weapons_carried | PC_DEMOMAN_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET; self.ammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; self.ammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; @@ -1665,7 +1665,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_MEDIC) { self.weapons_carried = self.weapons_carried | PC_MEDIC_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_MEDIC_MAXAMMO_ROCKET; self.ammo_nails = PC_MEDIC_MAXAMMO_NAIL; self.ammo_shells = PC_MEDIC_MAXAMMO_SHOT; @@ -1731,7 +1731,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_HVYWEAP) { self.weapons_carried = self.weapons_carried | PC_HVYWEAP_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET; self.ammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; self.ammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; @@ -1777,7 +1777,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_PYRO) { self.weapons_carried = self.weapons_carried | PC_PYRO_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_PYRO_MAXAMMO_ROCKET; self.ammo_nails = PC_PYRO_MAXAMMO_NAIL; self.ammo_shells = PC_PYRO_MAXAMMO_SHOT; @@ -1823,7 +1823,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_CIVILIAN) { self.weapons_carried = self.weapons_carried | PC_CIVILIAN_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_CIVILIAN_MAXAMMO_ROCKET; self.ammo_nails = PC_CIVILIAN_MAXAMMO_NAIL; self.ammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; @@ -1867,7 +1867,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_SPY) { self.weapons_carried = self.weapons_carried | PC_SPY_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_SPY_MAXAMMO_ROCKET; self.ammo_nails = PC_SPY_MAXAMMO_NAIL; self.ammo_shells = PC_SPY_MAXAMMO_SHOT; @@ -1920,7 +1920,7 @@ void () TeamFortress_SetEquipment = { } else if (self.playerclass == PC_ENGINEER) { self.weapons_carried = self.weapons_carried | PC_ENGINEER_WEAPONS; - if ((toggleflags & TFLAG_SPAWNFULL)) { + if (spawnfull) { self.ammo_rockets = PC_ENGINEER_MAXAMMO_ROCKET; self.ammo_nails = PC_ENGINEER_MAXAMMO_NAIL; self.ammo_shells = PC_ENGINEER_MAXAMMO_SHOT; diff --git a/weapons.qc b/weapons.qc index b905c76c..55edf715 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1663,7 +1663,7 @@ float () CheckForReload = { return 1; } } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && (toggleflags & TFLAG_SNIPERRELOAD)) { + if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) { TeamFortress_ReloadCurrentWeapon(); return 1; } @@ -1689,7 +1689,7 @@ float (float weap) CheckForAmmo = { if (self.reload_super_shotgun >= 2 && self.ammo_shells > self.reload_super_shotgun) return 1; } else if (weap == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > self.reload_sniper_rifle && (toggleflags & TFLAG_SNIPERRELOAD)) + if (self.reload_sniper_rifle >= 1 && self.ammo_shells > self.reload_sniper_rifle && sniperreload) return 1; } else if (weap == WEAP_GRENADE_LAUNCHER) { if (self.reload_grenade_launcher >= 1 && self.ammo_rockets > self.reload_grenade_launcher) @@ -1806,7 +1806,7 @@ void () W_Attack = { return; player_shot1(); W_FireSniperRifle(); - if (toggleflags & TFLAG_SNIPERRELOAD) { + if (sniperreload) { self.reload_sniper_rifle = self.reload_sniper_rifle + 1; Status_Refresh(self); CheckForReload(); From 823e8b3014ffb5ed18a35be1820f6680254210b7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 15:50:22 +0200 Subject: [PATCH 0295/2474] Add faithful setting which enables/disables a bunch of settings which alter gameplay --- client.qc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/client.qc b/client.qc index 7faba8ea..36d4e969 100644 --- a/client.qc +++ b/client.qc @@ -627,6 +627,45 @@ void () DecodeLevelParms = { ent.nextthink = time + autoteam_time; ent.think = autoteam_think; } + + st = infokey(world, "faithful"); + if (st == "on") { + spawnfull = FALSE; + drop_grenades = FALSE; + drop_grenpack = FALSE; + drop_gren1 = 0; + drop_gren2 = 0; + grentimers = FALSE; + id_extended = FALSE; + remember_weapon = FALSE; + discammo_pickup = TRUE; + old_dropflag = TRUE; + reload_cliptick = FALSE; + scoutdash = FALSE; + sniperreload = FALSE; + old_sniperrange = FALSE; + detpipe_limit = 7; + detpipe_limit_world = 7; + old_pipecooldown = TRUE; + medicaura = FALSE; + old_medikit = TRUE; + old_biodamage = TRUE; + cannon_lock = FALSE; + cannon_air = TRUE; + cannon_move = TRUE; + cannon_movespin = TRUE; + cannon_conc = TRUE; + cannon_accuracy = 1; + flame_knockback = FALSE; + old_spanner = TRUE; + old_railgun = TRUE; + old_dispenser = TRUE; + disp_explosion = FALSE; + feign_air = FALSE; + feign_pack = FALSE; + feign_msg = FALSE; + } + } if (parm11) From c035c607c86f25f8876ee3611d8c03bedec0985a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 11 Sep 2014 23:59:37 +0200 Subject: [PATCH 0296/2474] The drop_grenades FALSE setting no longer disables grenades --- client.qc | 2 ++ tfort.qc | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client.qc b/client.qc index 36d4e969..e0f68571 100644 --- a/client.qc +++ b/client.qc @@ -20,6 +20,7 @@ void () SetupTeamEqualiser; void () CeaseFire_think; void () RemoveGrenadeTimers; +void () RemovePrimeTimers; void () RemoveGasTimers; void () RemoveGrenades; @@ -1502,6 +1503,7 @@ void () CheckRules = { if ((timelimit && time >= timelimit) || (fraglimit && self.frags >= fraglimit)) { NextLevel(); RemoveGrenadeTimers(); + RemovePrimeTimers(); RemoveGrenades(); } }; diff --git a/tfort.qc b/tfort.qc index 2cef6890..e425e7aa 100644 --- a/tfort.qc +++ b/tfort.qc @@ -86,17 +86,17 @@ void () RemoveAutoIdTimer = { }; void () RemoveGrenadeTimers = { - local entity te; - - te = find(world, classname, "gtimer"); + local entity te = find(world, classname, "gtimer"); while (te != world) { if (te.owner == self) dremove(te); te = find(te, classname, "gtimer"); } +}; +void () RemovePrimeTimers = { if (!drop_grenades) { - te = find(world, classname, "primetimer"); + local entity te = find(world, classname, "primetimer"); while (te != world) { if (te.owner == self) dremove(te); @@ -2137,6 +2137,7 @@ void () TeamFortress_RemoveTimers = { RemoveAutoIdTimer(); RemoveGrenadeTimers(); + RemovePrimeTimers(); self.StatusGrenTime = 0; Status_Refresh(self); From f9a1ec398488d688c9ce51155fea99e44f6fd24e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 12 Sep 2014 00:01:29 +0200 Subject: [PATCH 0297/2474] Change defaults for configuration settings (closes #201) --- client.qc | 130 +++++++++++++++++++++++++++++++++++++++++++----------- qw.qc | 1 + world.qc | 3 +- 3 files changed, 106 insertions(+), 28 deletions(-) diff --git a/client.qc b/client.qc index e0f68571..b40373cc 100644 --- a/client.qc +++ b/client.qc @@ -307,6 +307,7 @@ void () DecodeLevelParms = { } else clanbattle = FALSE; + // automatically assign team [off] st = infokey(world, "a"); if (st == string_null) st = infokey(world, "autoteam"); @@ -319,67 +320,92 @@ void () DecodeLevelParms = { autoteam_time = stof(st); } - st = infokey(world, "akt"); + // auto kick team killers [4 tks per 60 seconds] + st = infokey(world, "akk"); if (st == string_null) - st = infokey(world, "autokick_time"); - autokick_time = stof(st); - if (autokick_time != 0) { - st = infokey(world, "akk"); + st = infokey(world, "autokick_kills"); + autokick_kills = stof(st); + if (autokick_kills) { + st = infokey(world, "akt"); if (st == string_null) - st = infokey(world, "autokick_kills"); - autokick_kills = stof(st); + st = infokey(world, "autokick_time"); + autokick_time = stof(st); + } else { + autokick_kills = 4; + autokick_time = 60; } + // execute map configs [on] + st = infokey(world, "exec_map_cfgs"); + if (st == "off") + exec_map_cfgs = FALSE; + else + exec_map_cfgs = TRUE; + + // show team cap frags for all team members [off] st = infokey(world, "t"); if (st == string_null) st = infokey(world, "teamfrags"); if (st == "on") toggleflags = toggleflags | TFLAG_TEAMFRAGS; - else if (st == "off") + else toggleflags = toggleflags - (toggleflags & TFLAG_TEAMFRAGS); + // every team member carry the total frags for the team [off] st = infokey(world, "fts"); if (st == string_null) st = infokey(world, "fullteamscore"); if (st == "on") toggleflags = toggleflags | TFLAG_FULLTEAMSCORE; + else + toggleflags = toggleflags - (toggleflags & TFLAG_FULLTEAMSCORE); + // use old concussion, gas and flash grenades [off] st = infokey(world, "og"); - if (st == string_null) - st = infokey(world, "old_grenades"); if (st == string_null) st = infokey(world, "old_grens"); if (st == "on") old_grens = TRUE; + else + old_grens = FALSE; + // drop primed hand grenades to ground when dying [on] st = infokey(world, "dg"); if (st == string_null) st = infokey(world, "drop_grenades"); - if (st == "on") + if (st == "off") + drop_grenades = FALSE; + else drop_grenades = TRUE; + // drop grenades in backpack upon death [on] st = infokey(world, "dgp"); if (st == string_null) st = infokey(world, "drop_grenpack"); - if (st == "on") + if (st == "off") + drop_grenpack = FALSE; + else drop_grenpack = TRUE; + // maximum grenades type 1 to drop in backpack [1] st = infokey(world, "dg1"); if (st == string_null) st = infokey(world, "drop_gren1"); if (st != string_null) drop_gren1 = stof(st); else - drop_gren1 = -1; + drop_gren1 = 1; + // maximum grenades type 2 to drop in backpack [0] st = infokey(world, "dg2"); if (st == string_null) st = infokey(world, "drop_gren2"); if (st != string_null) drop_gren2 = stof(st); else - drop_gren2 = -1; + drop_gren2 = 0; + // display grenade timer in status bar [on] st = infokey(world, "gt"); if (st == string_null) st = infokey(world, "grentimers"); @@ -388,6 +414,7 @@ void () DecodeLevelParms = { else grentimers = TRUE; + // show sentry gun health + misc extras in id string [on] st = infokey(world, "ie"); if (st == string_null) st = infokey(world, "id_extended"); @@ -396,6 +423,7 @@ void () DecodeLevelParms = { else id_extended = TRUE; + // remember weapon across deaths [on] st = infokey(world, "rw"); if (st == string_null) st = infokey(world, "remember_weapon"); @@ -404,20 +432,25 @@ void () DecodeLevelParms = { else remember_weapon = TRUE; + // pick up discardable ammo in discarded backpacks [off] st = infokey(world, "da"); if (st == string_null) st = infokey(world, "discammo_pickup"); - if (st == "off") - discammo_pickup = FALSE; - else + if (st == "on") discammo_pickup = TRUE; + else + discammo_pickup = FALSE; + // use old tf style dropflag (map decides on/off) [off] st = infokey(world, "odf"); if (st == string_null) st = infokey(world, "old_dropflag"); if (st == "on") old_dropflag = TRUE; + else + old_dropflag = FALSE; + // show ticking clip ammo in sbar when reloading [on] st = infokey(world, "rc"); if (st == string_null) st = infokey(world, "reload_cliptick"); @@ -426,12 +459,16 @@ void () DecodeLevelParms = { else reload_cliptick = TRUE; + // use old tf sniper range (shorter) [off] st = infokey(world, "os"); if (st == string_null) st = infokey(world, "old_sniperrange"); if (st == "on") old_sniperrange = TRUE; + else + old_sniperrange = FALSE; + // maximum amount of pipebombs per demoman [6] st = infokey(world, "dl"); if (st == string_null) st = infokey(world, "detpipe_limit"); @@ -440,6 +477,7 @@ void () DecodeLevelParms = { else detpipe_limit = 6; + // maximum amount of pipebombs in game [unlimited] st = infokey(world, "dw"); if (st == string_null) st = infokey(world, "detpipe_limit_world"); @@ -448,12 +486,16 @@ void () DecodeLevelParms = { else detpipe_limit_world = -1; + // use old tf pipebomb cooldown (0.8 seconds) [off] st = infokey(world, "op"); if (st == string_null) st = infokey(world, "old_pipecooldown"); if (st == "on") old_pipecooldown = TRUE; + else + old_pipecooldown = FALSE; + // allow medic aura [on] st = infokey(world, "ma"); if (st == string_null) st = infokey(world, "medicaura"); @@ -462,36 +504,52 @@ void () DecodeLevelParms = { else medicaura = TRUE; + // use old tf style medikit (don't insta-heal max+50) [off] st = infokey(world, "om"); if (st == string_null) st = infokey(world, "old_medikit"); if (st == "on") old_medikit = TRUE; + else + old_medikit = FALSE; + // use old tf style bioweapon (less damage) [off] st = infokey(world, "ob"); if (st == string_null) st = infokey(world, "old_biodamage"); if (st == "on") old_biodamage = TRUE; + else + old_biodamage = FALSE; + // use old tf style spanner (non-automated) [off] st = infokey(world, "os"); if (st == string_null) st = infokey(world, "old_spanner"); if (st == "on") old_spanner = TRUE; + else + old_spanner = FALSE; + // use old tf style railgun (penetrate target) [off] st = infokey(world, "or"); if (st == string_null) st = infokey(world, "old_railgun"); if (st == "on") old_railgun = TRUE; + else + old_railgun = FALSE; + // use old tf style dispenser (non-auto stocking) [off] st = infokey(world, "od"); if (st == string_null) st = infokey(world, "old_dispenser"); if (st == "on") old_dispenser = TRUE; + else + old_dispenser = FALSE; + // enable flamethrower knockback [on] st = infokey(world, "fk"); if (st == string_null) st = infokey(world, "flame_knockback"); @@ -500,6 +558,7 @@ void () DecodeLevelParms = { else flame_knockback = TRUE; + // bigger dispenser explosions [on] st = infokey(world, "de"); if (st == string_null) st = infokey(world, "disp_explosion"); @@ -508,6 +567,7 @@ void () DecodeLevelParms = { else disp_explosion = TRUE; + // allow assault cannon lock mechanism [on] st = infokey(world, "cl"); if (st == string_null) st = infokey(world, "cannon_lock"); @@ -516,6 +576,7 @@ void () DecodeLevelParms = { else cannon_lock = TRUE; + // allow assault cannon fire in air [on] st = infokey(world, "ca"); if (st == string_null) st = infokey(world, "cannon_air"); @@ -524,6 +585,7 @@ void () DecodeLevelParms = { else cannon_air = TRUE; + // allow movement while firing assault cannon [on] st = infokey(world, "cm"); if (st == string_null) st = infokey(world, "cannon_move"); @@ -532,12 +594,17 @@ void () DecodeLevelParms = { else cannon_move = TRUE; + // make assault cannon spin while moving [off] st = infokey(world, "cms"); if (st == string_null) st = infokey(world, "cannon_movespin"); - if (st == "on") + if (st == "on") { cannon_movespin = TRUE; + cannon_move = TRUE; // required for this to work + } else + cannon_movespin = FALSE; + // make hwguy susceptible to concussion grenade while firing assault cannon [on] st = infokey(world, "cc"); if (st == string_null) st = infokey(world, "cannon_conc"); @@ -546,12 +613,14 @@ void () DecodeLevelParms = { else cannon_conc = TRUE; + // assault cannon accuracy (0 = cf, 1 = tf 2.8, 2 = tf 2.9) [0] st = infokey(world, "cac"); if (st == string_null) st = infokey(world, "cannon_accuracy"); if (st != string_null) cannon_accuracy = stof(st); + // allow feign death in air [on] st = infokey(world, "fa"); if (st == string_null) st = infokey(world, "feign_air"); @@ -560,6 +629,7 @@ void () DecodeLevelParms = { else feign_air = TRUE; + // drop an empty backpack when feigning death [on] st = infokey(world, "fp"); if (st == string_null) st = infokey(world, "feign_pack"); @@ -568,6 +638,7 @@ void () DecodeLevelParms = { else feign_pack = TRUE; + // print fake death message when feigning death [on] st = infokey(world, "fm"); if (st == string_null) st = infokey(world, "feign_msg"); @@ -576,14 +647,23 @@ void () DecodeLevelParms = { else feign_msg = TRUE; + // allow spy [on] st = infokey(world, "spy"); if (st == "off") spy_off = TRUE; + else + spy_off = FALSE; + // enable spy invisibility [off] st = infokey(world, "s"); if (st == string_null) st = infokey(world, "spyinvis"); + if ((st == "on") || (toggleflags & TFLAG_SPYINVIS)) + invis_only = TRUE; + else if (st == "off") + invis_only = FALSE; + // allow scout dash [on] st = infokey(world, "sd"); if (st == string_null) st = infokey(world, "scoutdash"); @@ -592,6 +672,7 @@ void () DecodeLevelParms = { else scoutdash = TRUE; + // enable sniper rifle reload [on] st = infokey(world, "sr"); if (st == string_null) st = infokey(world, "sniperreload"); @@ -600,26 +681,23 @@ void () DecodeLevelParms = { else sniperreload = TRUE; + // spawn with full ammo/armor [off] st = infokey(world, "sf"); if (st == string_null) st = infokey(world, "spawnfull"); if (st == "on") spawnfull = TRUE; + else + spawnfull = FALSE; - if ((st == "on") || (toggleflags & TFLAG_SPYINVIS)) - invis_only = TRUE; - else if (st == "off") - invis_only = FALSE; - + // delay respawning by this many seconds [0] st = infokey(world, "rd"); if (st == string_null) st = infokey(world, "respawn_delay"); respawn_delay_time = stof(st); if (respawn_delay_time) toggleflags = toggleflags | TFLAG_RESPAWNDELAY; - - if ((toggleflags & TFLAG_RESPAWNDELAY) && - (respawn_delay_time == 0)) + if ((toggleflags & TFLAG_RESPAWNDELAY) && !respawn_delay_time) respawn_delay_time = RESPAWN_DELAY_TIME; if (toggleflags & TFLAG_AUTOTEAM) { diff --git a/qw.qc b/qw.qc index f0eb85f6..65a906bb 100644 --- a/qw.qc +++ b/qw.qc @@ -413,6 +413,7 @@ float last_id; .float tf_id; +float exec_map_cfgs; float spy_off; float old_grens; float invis_only; diff --git a/world.qc b/world.qc index 54a0ed43..155e4f44 100644 --- a/world.qc +++ b/world.qc @@ -145,8 +145,7 @@ void () worldspawn = { ("QW TF must be run with a gamedir or sv_gamedir of \"fortress\".\n"); } - st = infokey(world, "exec_map_cfgs"); - if (st == "on") { + if (exec_map_cfgs) { localcmd("exec fortress.cfg\n"); localcmd("exec cfg/maps/"); localcmd(mapname); From ab567c425f372cee5f14d06bd4303eb37939147d Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 10:05:12 +0200 Subject: [PATCH 0298/2474] Close class menu when selecting randompc (fixes #203) --- menu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index 4f0eea8c..7d92cb3b 100644 --- a/menu.qc +++ b/menu.qc @@ -211,7 +211,7 @@ void (float inp) Menu_Class_Input = { return; // keep showing menu if class is invalid - if (inp > 9 || !IsLegalClass(inp) || CF_ClassIsRestricted(self.team_no, inp)) + if (inp > 10 || !IsLegalClass(inp) || CF_ClassIsRestricted(self.team_no, inp)) Menu_Class(0); // don't try to change class if class is forbidden From c18beceaa4267857e7247fa7c8ecfbb3fd8b46e7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 10:53:51 +0200 Subject: [PATCH 0299/2474] Pressing '0' in disguise menu now closes menu (fixes #205) --- menu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index 7d92cb3b..f789cd5d 100644 --- a/menu.qc +++ b/menu.qc @@ -473,7 +473,7 @@ void (entity pe_player) Menu_Spy = { }; void (float inp) Menu_Spy_Skin_Input = { - if (inp == 0) + if (inp == 10) return; if (self.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT)) { From 508a8ba3524f53fc586a5a1c40d23bf33860230f Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 11:02:59 +0200 Subject: [PATCH 0300/2474] Load map execution settings in world.qc instead of client.qc (fixes #206) --- client.qc | 7 ------- world.qc | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client.qc b/client.qc index b40373cc..4fa5eb1e 100644 --- a/client.qc +++ b/client.qc @@ -335,13 +335,6 @@ void () DecodeLevelParms = { autokick_time = 60; } - // execute map configs [on] - st = infokey(world, "exec_map_cfgs"); - if (st == "off") - exec_map_cfgs = FALSE; - else - exec_map_cfgs = TRUE; - // show team cap frags for all team members [off] st = infokey(world, "t"); if (st == string_null) diff --git a/world.qc b/world.qc index 155e4f44..79e33cf3 100644 --- a/world.qc +++ b/world.qc @@ -145,6 +145,13 @@ void () worldspawn = { ("QW TF must be run with a gamedir or sv_gamedir of \"fortress\".\n"); } + // get map config execution settings + st = infokey(world, "exec_map_cfgs"); + if (st == "off") + exec_map_cfgs = FALSE; + else + exec_map_cfgs = TRUE; + if (exec_map_cfgs) { localcmd("exec fortress.cfg\n"); localcmd("exec cfg/maps/"); From 16cf2ff5089c8c3f16d478937a5e6f0b39bf99ea Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 11:03:35 +0200 Subject: [PATCH 0301/2474] Make spy invisibility work with Classic Fortress (fixes #202) --- client.qc | 4 +-- defs.h | 2 +- menu.qc | 11 +++++--- qw.qc | 1 + spy.qc | 16 +++++++++--- status.qc | 78 ++++++++++++++++++++++++++++++------------------------- 6 files changed, 68 insertions(+), 44 deletions(-) diff --git a/client.qc b/client.qc index 4fa5eb1e..f7cc63e5 100644 --- a/client.qc +++ b/client.qc @@ -651,9 +651,9 @@ void () DecodeLevelParms = { st = infokey(world, "s"); if (st == string_null) st = infokey(world, "spyinvis"); - if ((st == "on") || (toggleflags & TFLAG_SPYINVIS)) + if (st == "on") invis_only = TRUE; - else if (st == "off") + else invis_only = FALSE; // allow scout dash [on] diff --git a/defs.h b/defs.h index bca67702..24ead0ae 100644 --- a/defs.h +++ b/defs.h @@ -274,7 +274,7 @@ #define TFLAG_TEAMFRAGS 128 // Individual Frags, or Frags = TeamScore #define TFLAG_FIRSTENTRY 256 // Used to determine the first time toggleflags is set // in a map. Cannot be toggled by players. -#define TFLAG_SPYINVIS 512 // Spy invisible only +// unused 512 #define TFLAG_GRAPPLE 1024 // Grapple on/off #define TFLAG_FULLTEAMSCORE 2048 #define TFLAG_FLAGEMU 4096 diff --git a/menu.qc b/menu.qc index f789cd5d..9bd9454e 100644 --- a/menu.qc +++ b/menu.qc @@ -447,9 +447,14 @@ void (entity pe_player) Menu_Spy = { return; } - if (invis_only) - s_skin = "“‘ Go invisible \n"; - else if (pe_player.is_undercover == 2) + if (invis_only) { + if (pe_player.is_undercover == 1) + s_skin = "“‘ Become visible \n"; + else if (pe_player.is_undercover == 2) + s_skin = "“‘ Stop going invisible \n"; + else + s_skin = "“‘ Go invisible \n"; + } else if (pe_player.is_undercover == 2) s_skin = "“‘ Stop disguising \n"; if ((!pe_player.last_skin && !pe_player.last_team) || invis_only) diff --git a/qw.qc b/qw.qc index 65a906bb..edf62ba1 100644 --- a/qw.qc +++ b/qw.qc @@ -63,6 +63,7 @@ typedef void (float) f_void_float; .float aura_healtime; // Aura healing status will be shown in status bar until this time .float regen_time; // Time when the medic last regenerated cells .float dash_cooldown; // Cooldown for Scout dash +.float undercover_timer; // Seconds left until disguised .float fragstreak; // Frag streak .float caps; // Caps during this game .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types diff --git a/spy.qc b/spy.qc index 8f908b31..9117e443 100644 --- a/spy.qc +++ b/spy.qc @@ -578,7 +578,8 @@ void () CF_Spy_Invisible = { e_timer.classname = "spytimer"; e_timer.owner = self; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 4; + e_timer.nextthink = time + 1; + self.undercover_timer = 4; } Status_Refresh(self); @@ -648,6 +649,14 @@ void () CF_Spy_UndercoverThink = { local float f_team_color; local string s_team, s_class; + // keep track of seconds left to + if (self.owner.undercover_timer > 1) { + self.owner.undercover_timer = self.owner.undercover_timer - 1; + self.nextthink = time + 1; + Status_Refresh(self.owner); + return; + } + // stop if player is not a spy if (self.owner.playerclass != PC_SPY) return; @@ -657,7 +666,7 @@ void () CF_Spy_UndercoverThink = { return; // make spy invisible if invis_only is turned on - if (invis_only == 1) { + if (invis_only) { self.owner.items = self.owner.items | IT_INVISIBILITY; self.owner.frame = 0; @@ -766,8 +775,9 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 4; + e_timer.nextthink = time + 1; e_timer.skin = pf_class; + pe_player.undercover_timer = 4; TeamFortress_SetSkin(pe_player); Status_Refresh(pe_player); diff --git a/status.qc b/status.qc index c1f8f06e..6f64b620 100644 --- a/status.qc +++ b/status.qc @@ -381,44 +381,52 @@ string(entity pl) DisguiseToString = local string team = ""; if (pl.is_undercover == 1) { - st = "Υξδεςγοφες: "; - if (pl.undercover_team) { - st = strcat(st, TeamToString(pl.undercover_team)); - st = strcat(st, " "); + if (self.items & IT_INVISIBILITY) { + st = "Ιξφισιβμε"; + } else { + st = "Υξδεςγοφες: "; + if (pl.undercover_team) { + st = strcat(st, TeamToString(pl.undercover_team)); + st = strcat(st, " "); + } + if (pl.undercover_skin) + st = strcat(st, ClassToString(pl.undercover_skin)); } - if (pl.undercover_skin) - st = strcat(st, ClassToString(pl.undercover_skin)); } else if (pl.is_undercover == 2) { - if (pl.disguise_team) { - team = strcat(team, "("); - team = strcat(team, TeamToString(pl.disguise_team)); - if (!pl.queue_skin) - team = strcat(team, ") "); - } else if (pl.queue_team) { - team = strcat(team, "("); - team = strcat(team, TeamToString(pl.queue_team)); - team = strcat(team, " "); - } else if (pl.undercover_team) { - team = strcat(team, TeamToString(pl.undercover_team)); - team = strcat(team, " "); - } - if (pl.disguise_skin) { - if (!pl.queue_team) - skin = strcat(skin, "("); - skin = strcat(skin, ClassToString(pl.disguise_skin)); - skin = strcat(skin, ")"); - } else if (pl.queue_skin) { - skin = strcat(skin, " "); - skin = strcat(skin, ClassToString(pl.queue_skin)); - skin = strcat(skin, ")"); - } else if (pl.undercover_skin) { - skin = strcat(skin, ClassToString(pl.undercover_skin)); + if (invis_only) { + st = "Ιξφισιβμε in "; + st = strcat(st, ftos(pl.undercover_timer)); + st = strcat(st, " seconds"); + } else { + if (pl.disguise_team) { + team = strcat(team, "("); + team = strcat(team, TeamToString(pl.disguise_team)); + if (!pl.queue_skin) + team = strcat(team, ") "); + } else if (pl.queue_team) { + team = strcat(team, "("); + team = strcat(team, TeamToString(pl.queue_team)); + team = strcat(team, " "); + } else if (pl.undercover_team) { + team = strcat(team, TeamToString(pl.undercover_team)); + team = strcat(team, " "); + } + if (pl.disguise_skin) { + if (!pl.queue_team) + skin = strcat(skin, "("); + skin = strcat(skin, ClassToString(pl.disguise_skin)); + skin = strcat(skin, ")"); + } else if (pl.queue_skin) { + skin = strcat(skin, " "); + skin = strcat(skin, ClassToString(pl.queue_skin)); + skin = strcat(skin, ")"); + } else if (pl.undercover_skin) { + skin = strcat(skin, ClassToString(pl.undercover_skin)); + } + st = "Υξδεςγοφες: "; + st = strcat(st, team); + st = strcat(st, skin); } - st = "Υξδεςγοφες: "; - st = strcat(st, team); - st = strcat(st, skin); - } else if (invis_only) { - st = "Υξδεςγοφες"; } return st; From 25ed8ce313d2a864e6960435fab49664b6940c79 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 11:41:19 +0200 Subject: [PATCH 0302/2474] Allow disguise as enemy spy --- menu.qc | 8 +++----- spy.qc | 10 ++++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/menu.qc b/menu.qc index 9bd9454e..a5dd5818 100644 --- a/menu.qc +++ b/menu.qc @@ -491,7 +491,8 @@ void (float inp) Menu_Spy_Skin_Input = { return; } - CF_Spy_ChangeSkin(self, inp); + if (self.skin != inp) + CF_Spy_ChangeSkin(self, inp); if (number_of_teams > 2) Menu_Spy_Color(); @@ -511,13 +512,10 @@ void () Menu_Spy_Skin = { local string s_medic = "—‘ Medic \n"; local string s_hwguy = "˜‘ HWGuy \n"; local string s_pyro = "™‘ Pyro \n"; - local string s_spy = "š‘ Spy (reset)\n"; + local string s_spy = "š‘ Spy \n"; local string s_engineer = "›‘ Engineer \n"; local string s_nothing = "\n’‘ Nothing \n"; - if (!self.undercover_skin) - s_spy = "\n"; - Status_Menu(self, Menu_Spy_Skin_Input, s_disguise, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_nothing); }; diff --git a/spy.qc b/spy.qc index 9117e443..4296ab80 100644 --- a/spy.qc +++ b/spy.qc @@ -693,7 +693,10 @@ void () CF_Spy_UndercoverThink = { s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); else s_team = TeamFortress_TeamGetColorString(self.owner.team_no); - s_class = TeamFortress_GetClassName(self.owner.undercover_skin); + if (self.owner.undercover_skin) + s_class = TeamFortress_GetClassName(self.owner.undercover_skin); + else + s_class = "Spy"; sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); } @@ -714,7 +717,10 @@ void () CF_Spy_UndercoverThink = { CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin); } else { s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); - s_class = TeamFortress_GetClassName(self.owner.undercover_skin); + if (self.owner.undercover_skin) + s_class = TeamFortress_GetClassName(self.owner.undercover_skin); + else + s_class = "Spy"; sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); } } From 8e6a13008114e40820dbc4defe7962a7625da4e8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 11:56:15 +0200 Subject: [PATCH 0303/2474] Only count team pipebombs towards total --- weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 55edf715..194c5dcc 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1176,7 +1176,8 @@ void () ExplodeOldestPipebomb = { if (oldest == world || oldest.nextthink > pipe.nextthink) oldest = pipe; } - numpipes_total = numpipes_total + 1; + if (pipe.owner.team_no == self.team_no) + numpipes_total = numpipes_total + 1; pipe = find(pipe, classname, "pipebomb"); } From 43a598c2b3b71be64bc908563e72368769c24f1e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 12:13:43 +0200 Subject: [PATCH 0304/2474] Give appropriate error message to player changing class to current class --- tfort.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tfort.qc b/tfort.qc index e425e7aa..49f5b68c 100644 --- a/tfort.qc +++ b/tfort.qc @@ -136,6 +136,12 @@ void (float inp) TeamFortress_ChangeClass = { if ((deathmatch != 3) && (cb_prematch_time < time)) return; + if (self.playerclass == inp) { + sprint(self, PRINT_HIGH, "You are already playing as a "); + TeamFortress_PrintClassName(self, inp, 0); + return; + } + if (TeamFortress_TeamIsCivilian(self.team_no)) { sprint(self, PRINT_HIGH, "You cannot change class\n"); return; From d9772b2bbce6c06277e15239a43c518f28970fa6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 12:33:42 +0200 Subject: [PATCH 0305/2474] Don't rebind number keys to impulse 1-10 --- tforthlp.qc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tforthlp.qc b/tforthlp.qc index a4dd9b12..a7427307 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -146,16 +146,6 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("flaginfo", FLAG_INFO, 0); TeamFortress_Alias("maphelp", TF_HELP_MAP, 0); TeamFortress_Alias("showids", TF_SHOW_IDS, 0); - stuffcmd(self, "bind 1 \"impulse 1\"\n"); - stuffcmd(self, "bind 2 \"impulse 2\"\n"); - stuffcmd(self, "bind 3 \"impulse 3\"\n"); - stuffcmd(self, "bind 4 \"impulse 4\"\n"); - stuffcmd(self, "bind 5 \"impulse 5\"\n"); - stuffcmd(self, "bind 6 \"impulse 6\"\n"); - stuffcmd(self, "bind 7 \"impulse 7\"\n"); - stuffcmd(self, "bind 8 \"impulse 8\"\n"); - stuffcmd(self, "bind 9 \"impulse 9\"\n"); - stuffcmd(self, "bind 0 \"impulse 10\"\n"); } else if (self.motd == 75) { TeamFortress_Alias("+det5", TF_DETPACK_5, 0); TeamFortress_Alias("-det5", TF_DETPACK_STOP, 0); From e0a121a5d3c97d92c88b7f67deef1e32ce245e58 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 13:08:06 +0200 Subject: [PATCH 0306/2474] Add 5 second cooldown to medikit before regenerating cells --- defs.h | 1 + medic.qc | 6 ++++++ qw.qc | 1 + weapons.qc | 1 + 4 files changed, 9 insertions(+) diff --git a/defs.h b/defs.h index 24ead0ae..45c75653 100644 --- a/defs.h +++ b/defs.h @@ -843,6 +843,7 @@ #define PC_MEDIC_AURA_RANGE 120 // The aura's range #define PC_MEDIC_CELL_REGEN_TIME 1 // Number of seconds between each cell regen. #define PC_MEDIC_CELL_REGEN_AMOUNT 10 // Amount of cells regenerated each cell regen. +#define PC_MEDIC_CELL_REGEN_CD 5 // Seconds to cooldown cell regeneration after healing with medikit. // Class Details for HVYWEAP #define PC_HVYWEAP_SKIN 2 diff --git a/medic.qc b/medic.qc index ccb6aa57..f0f21447 100644 --- a/medic.qc +++ b/medic.qc @@ -86,6 +86,12 @@ void () CF_Medic_RegenerateCells = { if (!medicaura && old_medikit) return; + // skip this regen tick if on cooldown + if (time <= self.owner.regen_cooldown) { + self.nextthink = time + 1; + return; + } + self.nextthink = time + PC_MEDIC_CELL_REGEN_TIME; if (self.owner.ammo_cells < 100) { diff --git a/qw.qc b/qw.qc index edf62ba1..9aad4591 100644 --- a/qw.qc +++ b/qw.qc @@ -62,6 +62,7 @@ typedef void (float) f_void_float; .float aura_healcount; // Amount of players given health .float aura_healtime; // Aura healing status will be shown in status bar until this time .float regen_time; // Time when the medic last regenerated cells +.float regen_cooldown; // Time to cooldown cell regeneration after using medikit heal .float dash_cooldown; // Cooldown for Scout dash .float undercover_timer; // Seconds left until disguised .float fragstreak; // Frag streak diff --git a/weapons.qc b/weapons.qc index 194c5dcc..90d05c3c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -527,6 +527,7 @@ void () W_FireMedikit = { if (self.ammo_cells >= 50) { healam = trace_ent.max_health - trace_ent.health + 50; self.ammo_cells = 0; + self.regen_cooldown = time + PC_MEDIC_CELL_REGEN_CD; sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); } else { From 5ff5c86bbbda93786922af04fbe1879e600079b8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 13:08:37 +0200 Subject: [PATCH 0307/2474] Fix typo in medikit code setting current ammo --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 90d05c3c..ef561bc4 100644 --- a/weapons.qc +++ b/weapons.qc @@ -537,7 +537,7 @@ void () W_FireMedikit = { } if (self.current_weapon == WEAP_MEDIKIT) - self.currentammo = self.owner.ammo_cells; + self.currentammo = self.ammo_cells; T_Heal(trace_ent, healam, 1); From fc3225cd958b3242d8ac97717831ec9172b5fe03 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 13:08:51 +0200 Subject: [PATCH 0308/2474] Refresh status bar when using medikit --- weapons.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/weapons.qc b/weapons.qc index ef561bc4..beaf675d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -539,6 +539,7 @@ void () W_FireMedikit = { if (self.current_weapon == WEAP_MEDIKIT) self.currentammo = self.ammo_cells; + Status_Refresh(self); T_Heal(trace_ent, healam, 1); if (trace_ent.health > trace_ent.max_health) { From 16be29b46468da45254de7fe646b90f92d9ad545 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 14:40:57 +0200 Subject: [PATCH 0309/2474] Don't show auto team in team menu if already assigned a team --- menu.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/menu.qc b/menu.qc index a5dd5818..e1fd9d1b 100644 --- a/menu.qc +++ b/menu.qc @@ -191,6 +191,10 @@ void (float update) Menu_Team = { s_green = Menu_Team_TeamString(4, s_green); s_auto = strpadr(s_auto, (strlen(s_blue) - 1)); + // don't show auto team if already assigned a team + if (self.team_no) + s_auto = ""; + // update menu every 0.5 seconds if (!self.has_menutimer) { self.has_menutimer = 1; From ba853953d70165b7f2ce09c7096a9aba5821adf5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 14:44:20 +0200 Subject: [PATCH 0310/2474] Show appropriate error message to player playing randompc trying to change class to randompc --- tfort.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tfort.qc b/tfort.qc index 49f5b68c..5a0ebde6 100644 --- a/tfort.qc +++ b/tfort.qc @@ -140,6 +140,9 @@ void (float inp) TeamFortress_ChangeClass = { sprint(self, PRINT_HIGH, "You are already playing as a "); TeamFortress_PrintClassName(self, inp, 0); return; + } else if (inp == 10 && (self.tfstate & TFSTATE_RANDOMPC)) { + sprint(self, PRINT_HIGH, "You are already playing as random player class\n"); + return; } if (TeamFortress_TeamIsCivilian(self.team_no)) { From 93d8bcd2e4a1d6d60522ebcb6638bf22f7a91149 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 13 Sep 2014 14:57:37 +0200 Subject: [PATCH 0311/2474] Close class menu if selected class is current class --- menu.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/menu.qc b/menu.qc index e1fd9d1b..0c4d7dac 100644 --- a/menu.qc +++ b/menu.qc @@ -222,6 +222,10 @@ void (float inp) Menu_Class_Input = { if (!IsLegalClass(inp) || CF_GetClassRestriction(self.team_no, inp) == -1) return; + // close menu if selected class is current class + if (self.playerclass == inp || (inp == 10 && (self.tfstate & TFSTATE_RANDOMPC))) + Menu_Close(self); + TeamFortress_ChangeClass(inp); }; From bab3e61930efaa7617afea1c2e4531874fe9e1da Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 14 Sep 2014 08:04:17 +0200 Subject: [PATCH 0312/2474] Destroy Engineer buildings when switching team (fixes #208) --- tforttm.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tforttm.qc b/tforttm.qc index 15437a1b..5839dc50 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -185,6 +185,9 @@ float (float tno) TeamFortress_TeamSet = { if (!self.deadflag) { ClientKill(1); } + // remove engineer buildings + if (self.playerclass == PC_ENGINEER) + Engineer_RemoveBuildings(self); // swap colors for spy last disguise if (self.playerclass == PC_SPY && self.undercover_team == tno) self.last_team = self.team_no; From 4b8144d05fb0473f7ea6973968a446470ef21202 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 14 Sep 2014 08:23:22 +0200 Subject: [PATCH 0313/2474] Allow player one free team switch during first 10 seconds of life --- client.qc | 8 ++++---- defs.qc | 2 +- tfort.qc | 2 +- tforttm.qc | 5 ++++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/client.qc b/client.qc index f7cc63e5..51311b30 100644 --- a/client.qc +++ b/client.qc @@ -1039,7 +1039,7 @@ float () CloseToSpawnPoint = { return 0; }; -void (float force) ClientKill = { +void (float force, float free) ClientKill = { local entity te; local float timeleft; @@ -1069,7 +1069,9 @@ void (float force) ClientKill = { // players can't suicide again for 10 seconds self.suicide_time = time + 5 + random() * 5; - if (!(self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint())) { + if (free) { + TeamFortress_SetupRespawn(FALSE); + } else { bprint(PRINT_MEDIUM, self.netname, " suicides\n"); // If infected, give the medic a frag @@ -1088,8 +1090,6 @@ void (float force) ClientKill = { TF_AddFrags(self, -1); TeamFortress_SetupRespawn(TRUE); self.th_die(); - } else { - TeamFortress_SetupRespawn(FALSE); } self.health = -1; diff --git a/defs.qc b/defs.qc index 86c63645..373b72a5 100644 --- a/defs.qc +++ b/defs.qc @@ -60,7 +60,7 @@ void () StartFrame; void () PlayerPreThink; // Called every frame before physics are run void () PlayerPostThink; // Called every frame after physics are run -void (float force) ClientKill; // Player entered the suicide command +void (float force, float free) ClientKill; // Player entered the suicide command void () ClientConnect; // called when a player connects to a server void () PutClientInServer; // call after setting the parm1... parms void () ClientDisconnect; // called when a player disconnects from a server diff --git a/tfort.qc b/tfort.qc index 5a0ebde6..3f48e148 100644 --- a/tfort.qc +++ b/tfort.qc @@ -167,7 +167,7 @@ void (float inp) TeamFortress_ChangeClass = { } self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint() && self.suicide_time <= time) { - ClientKill(0); + ClientKill(0, 1); self.suicide_time = time; } else { sprint(self, PRINT_HIGH, "After dying, you will return as a "); diff --git a/tforttm.qc b/tforttm.qc index 5839dc50..3d5e009f 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -183,7 +183,10 @@ float (float tno) TeamFortress_TeamSet = { return (1); } if (!self.deadflag) { - ClientKill(1); + if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) + ClientKill(1, 1); + else + ClientKill(1, 0); } // remove engineer buildings if (self.playerclass == PC_ENGINEER) From 9217eb707bb26cde3936563683829f84570c262c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 14 Sep 2014 08:51:42 +0200 Subject: [PATCH 0314/2474] Don't allow free suicide if thrown grenade --- client.qc | 4 +++- qw.qc | 2 ++ tfort.qc | 6 +++--- tforttm.qc | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/client.qc b/client.qc index 51311b30..4a37eea6 100644 --- a/client.qc +++ b/client.qc @@ -1069,7 +1069,7 @@ void (float force, float free) ClientKill = { // players can't suicide again for 10 seconds self.suicide_time = time + 5 + random() * 5; - if (free) { + if (free && !self.has_throwngren && (self.has_changedteam || self.nextpc)) { TeamFortress_SetupRespawn(FALSE); } else { bprint(PRINT_MEDIUM, self.netname, " suicides\n"); @@ -1310,6 +1310,8 @@ void () PutClientInServer = { self.invincible_time = 0; self.spawn_time = time; self.vote_close = 0; + self.has_throwngren = FALSE; + self.has_changedteam = FALSE; self.reload_shotgun = 0; self.reload_super_shotgun = 0; diff --git a/qw.qc b/qw.qc index 9aad4591..5f909c0a 100644 --- a/qw.qc +++ b/qw.qc @@ -32,6 +32,8 @@ typedef void (float) f_void_float; .float is_quickfiring; // TRUE for a player if they're using the quick slots .float is_concussed; // TRUE for a player who is affected by concussion grenade .float has_quickfired; // TRUE for a player that has stopped quick firing (until weapon is ready) +.float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) +.float has_changedteam; // TRUE for a player that has changed team .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer .float default_sensitivity; // Player's default (non-zoomed) sensitivity diff --git a/tfort.qc b/tfort.qc index 3f48e148..e95da730 100644 --- a/tfort.qc +++ b/tfort.qc @@ -166,7 +166,7 @@ void (float inp) TeamFortress_ChangeClass = { return; } self.nextpc = inp; - if (self.health == self.max_health && (self.spawn_time + 10) > time && self.nextpc && CloseToSpawnPoint() && self.suicide_time <= time) { + if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { ClientKill(0, 1); self.suicide_time = time; } else { @@ -597,7 +597,7 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "Grenade"; if (self.no_grenades_1 > 0) { - self.suicide_time = time + 10; + self.has_throwngren = TRUE; self.no_grenades_1 = self.no_grenades_1 - 1; if (gtype == 6) { newmis = spawn(); @@ -657,7 +657,7 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "Grenade"; if (self.no_grenades_2 > 0) { - self.suicide_time = time + 10; + self.has_throwngren = TRUE; self.no_grenades_2 = self.no_grenades_2 - 1; if (gtype == 6) { newmis = spawn(); diff --git a/tforttm.qc b/tforttm.qc index 3d5e009f..c9aea857 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -182,12 +182,14 @@ float (float tno) TeamFortress_TeamSet = { } return (1); } + self.has_changedteam = TRUE; if (!self.deadflag) { if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) ClientKill(1, 1); else ClientKill(1, 0); } + self.has_changedteam = FALSE; // remove engineer buildings if (self.playerclass == PC_ENGINEER) Engineer_RemoveBuildings(self); From 83558fc0f7d0e6604db0710305ca9e47b03ed1e4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 14 Sep 2014 20:54:29 +0200 Subject: [PATCH 0315/2474] Allow /saveme while feigned --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index beaf675d..a1c07d94 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2546,7 +2546,7 @@ void () W_WeaponFrame = { return; } - if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL) + if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL && self.impulse != TF_MEDIC_HELPME) return; if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { From d9a555842b1a2b4d2a4f06a8c4692e5da627c07a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 14 Sep 2014 20:54:59 +0200 Subject: [PATCH 0316/2474] Only drop flag with /dropflag if player is glowing (fixes #210) --- tfortmap.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index 1523493d..7e53d02a 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2561,7 +2561,7 @@ void () DropGoalItems = { if (te.goal_activation & 4096) tfgoalitem_RemoveFromPlayer(te, self, 2); } - else { + else if (self.effects & EF_DIMLIGHT) { tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); if (self.team_no == 1) From 3c441d2f54a7cbbc3e2996bbf8674145bdf60475 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 17 Sep 2014 14:19:57 +0200 Subject: [PATCH 0317/2474] Auto id every 0.3 seconds instead of 0.1 --- tfort.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index e95da730..691f1d9b 100644 --- a/tfort.qc +++ b/tfort.qc @@ -13,7 +13,7 @@ float () CloseToSpawnPoint; void () AutoId = { - // ready autoid settings every 5 seconds + // read autoid settings every 5 seconds if (time > self.owner.autoid_time) { self.owner.autoid_type = stof(infokey(self.owner, "ai")); self.owner.autoid_time = time + 5; @@ -36,7 +36,7 @@ void () AutoId = { CF_Identify(self.owner, self.owner.autoid_type); } - self.nextthink = time + 0.1; + self.nextthink = time + 0.3; }; void () UseSpecialSkill = { From 6a461b667904f80f0feda15957b3402ecd7649d3 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 17 Sep 2014 17:34:40 +0200 Subject: [PATCH 0318/2474] Don't initialize autoid vars if no target found --- actions.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions.qc b/actions.qc index 52e07bb3..776df219 100644 --- a/actions.qc +++ b/actions.qc @@ -115,14 +115,14 @@ void () TeamFortress_SaveMe = { void (entity pe_player, float f_type) CF_Identify = { local vector v_source; - local string s_id_string = "", s_class = "", s_name = ""; - local float f_health = 0, f_maxhealth = 0, f_armor = 0, f_maxarmor = 0, f_friendly = 0, f_fakefriendly = 0, f_sentryhealth = 0, f_maxsentryhealth = 0; v_source = pe_player.origin + v_forward * 10; v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; traceline(v_source, v_source + v_forward * 2048, 0, pe_player); if (trace_ent != world) { + local string s_id_string = "", s_class = "", s_name = ""; + local float f_health = 0, f_maxhealth = 0, f_armor = 0, f_maxarmor = 0, f_friendly = 0, f_fakefriendly = 0, f_sentryhealth = 0, f_maxsentryhealth = 0; // don't identify targets above water if player is under water if (pe_player.waterlevel == 3 && !trace_ent.waterlevel) From cbbad3b53ee32a564bcbafe6e900a72833a2bdc7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 17 Sep 2014 17:35:07 +0200 Subject: [PATCH 0319/2474] Do some damage with medikit and spanner to press buttons (fixes #211) --- weapons.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index a1c07d94..aa79b6b5 100644 --- a/weapons.qc +++ b/weapons.qc @@ -319,8 +319,9 @@ void () W_FireSpanner = { trace_ent.axhitme = 1; SpawnBlood(org, 20); deathmsg = DMSG_SPANNER; - TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, - TF_TD_OTHER); + TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); + } else { + TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); } } else { sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); @@ -575,6 +576,8 @@ void () W_FireMedikit = { BioInfection.enemy = self; trace_ent.infection_team_no = self.team_no; } + } else { + TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); } } else { // hit wall From b0a5e2a6a070861f745a7f7b80c6e9f0a99c79a1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 17 Sep 2014 18:00:39 +0200 Subject: [PATCH 0320/2474] Split /locktoggle into /lock and /unlock --- defs.h | 5 +++-- tforthlp.qc | 7 ++++--- weapons.qc | 8 ++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/defs.h b/defs.h index 45c75653..33c7bebe 100644 --- a/defs.h +++ b/defs.h @@ -449,10 +449,11 @@ #define TF_GRENADE_PT_2 155 // Prime and throw grenade type 2 (two clicks) // Scout dash -#define TF_DASH 157 // Initialize a forward bunnyhop for Scout +#define TF_DASH 156 // Initialize a forward bunnyhop for Scout // Impulses for new items -#define TF_LOCK 158 // Toggle Assault Cannon spinning +#define TF_LOCKON 157 // Turn Assault Cannon fire on +#define TF_LOCKOFF 158 // Turn Assault Cannon fire off #define TF_SCAN 159 // Scanner Pre-Impulse #define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies #define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies diff --git a/tforthlp.qc b/tforthlp.qc index a7427307..3e30d886 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -155,9 +155,10 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-det50", TF_DETPACK_STOP, 0); TeamFortress_Alias("+det255", TF_DETPACK, 255); TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); - TeamFortress_Alias("locktoggle", TF_LOCK, 0); - TeamFortress_Alias("+lock", TF_LOCK, 0); - TeamFortress_Alias("-lock", TF_LOCK, 0); + TeamFortress_Alias("lock", TF_LOCKON, 0); + TeamFortress_Alias("unlock", TF_LOCKOFF, 0); + TeamFortress_Alias("+lock", TF_LOCKON, 0); + TeamFortress_Alias("-lock", TF_LOCKOFF, 0); } else if (self.motd == 85) { TeamFortress_Alias("clan1", 82, 0); TeamFortress_Alias("clan2", 83, 0); diff --git a/weapons.qc b/weapons.qc index aa79b6b5..7255fd19 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2645,11 +2645,11 @@ void () W_WeaponFrame = { // hwguy assault cannon special if (self.playerclass == PC_HVYWEAP) { - if (self.impulse == TF_LOCK && cannon_lock) { - if (self.tfstate & TFSTATE_LOCK) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); - else + if (cannon_lock && (self.impulse == TF_LOCKON || self.impulse == TF_LOCKOFF)) { + if (self.impulse == TF_LOCKON) self.tfstate = self.tfstate | TFSTATE_LOCK; + else if (self.impulse == TF_LOCKOFF) + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); Status_Refresh(self); self.impulse = 0; return; From e4b79d91a975a1082a8a01e9f6d53bda833ec2ce Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 17 Sep 2014 18:00:53 +0200 Subject: [PATCH 0321/2474] Make /special work for HWGuy --- tfort.qc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 691f1d9b..ecef655f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -51,7 +51,15 @@ void () UseSpecialSkill = { self.impulse = TF_PB_DETONATE; else if (self.playerclass == PC_MEDIC) self.impulse = TF_MEDIC_AURA_TOGGLE; - else if (self.playerclass == PC_SPY) + else if (self.playerclass == PC_HVYWEAP) { + if (self.tfstate & TFSTATE_LOCK) + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); + else + self.tfstate = self.tfstate | TFSTATE_LOCK; + Status_Refresh(self); + self.impulse = 0; + return; + } else if (self.playerclass == PC_SPY) self.impulse = TF_SPY_DIE; else if (self.playerclass == PC_ENGINEER) self.impulse = TF_ENGINEER_DETDISP; From c819187a84c566e8180ab8dfa4589fb721b2ff5b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 17 Sep 2014 18:12:36 +0200 Subject: [PATCH 0322/2474] Don't allow free (manual) suicides when changing class (fixes #212) --- client.qc | 3 +-- qw.qc | 1 + tfort.qc | 2 ++ tforttm.qc | 8 ++++---- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/client.qc b/client.qc index 4a37eea6..000887fb 100644 --- a/client.qc +++ b/client.qc @@ -1069,7 +1069,7 @@ void (float force, float free) ClientKill = { // players can't suicide again for 10 seconds self.suicide_time = time + 5 + random() * 5; - if (free && !self.has_throwngren && (self.has_changedteam || self.nextpc)) { + if (free && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { TeamFortress_SetupRespawn(FALSE); } else { bprint(PRINT_MEDIUM, self.netname, " suicides\n"); @@ -1311,7 +1311,6 @@ void () PutClientInServer = { self.spawn_time = time; self.vote_close = 0; self.has_throwngren = FALSE; - self.has_changedteam = FALSE; self.reload_shotgun = 0; self.reload_super_shotgun = 0; diff --git a/qw.qc b/qw.qc index 5f909c0a..b138a994 100644 --- a/qw.qc +++ b/qw.qc @@ -34,6 +34,7 @@ typedef void (float) f_void_float; .float has_quickfired; // TRUE for a player that has stopped quick firing (until weapon is ready) .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team +.float has_changedclass; // TRUE for a player that has changed class .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer .float default_sensitivity; // Player's default (non-zoomed) sensitivity diff --git a/tfort.qc b/tfort.qc index ecef655f..0e6f8d4d 100644 --- a/tfort.qc +++ b/tfort.qc @@ -175,7 +175,9 @@ void (float inp) TeamFortress_ChangeClass = { } self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { + self.has_changedclass = 1; ClientKill(0, 1); + self.has_changedclass = 0; self.suicide_time = time; } else { sprint(self, PRINT_HIGH, "After dying, you will return as a "); diff --git a/tforttm.qc b/tforttm.qc index c9aea857..8079bf38 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -182,14 +182,14 @@ float (float tno) TeamFortress_TeamSet = { } return (1); } - self.has_changedteam = TRUE; if (!self.deadflag) { - if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) + if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { + self.has_changedteam = 1; ClientKill(1, 1); - else + self.has_changedteam = 0; + } else ClientKill(1, 0); } - self.has_changedteam = FALSE; // remove engineer buildings if (self.playerclass == PC_ENGINEER) Engineer_RemoveBuildings(self); From d0fe7646f754b6f256d25505623284a74fc3df10 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 18 Sep 2014 00:52:29 +0200 Subject: [PATCH 0323/2474] Detonate pipebombs when dying even if weapon is on cooldown (fixes #183) --- demoman.qc | 4 ++-- tfort.qc | 2 +- weapons.qc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/demoman.qc b/demoman.qc index e0f3f5bf..78a1e83c 100644 --- a/demoman.qc +++ b/demoman.qc @@ -17,10 +17,10 @@ void () TeamFortress_DetpackTouch; void () TeamFortress_DetpackDisarm; void () TeamFortress_DetpackCountDown; -void () TeamFortress_DetonatePipebombs = { +void (float force) TeamFortress_DetonatePipebombs = { local entity e; - if (time < self.pipecooldown) + if (time < self.pipecooldown && !force) return; e = find(world, classname, "pipebomb"); diff --git a/tfort.qc b/tfort.qc index 0e6f8d4d..5661d14b 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2196,7 +2196,7 @@ void () TeamFortress_RemoveTimers = { te = find(te, classname, "detpack"); } - TeamFortress_DetonatePipebombs(); + TeamFortress_DetonatePipebombs(1); if (self.has_disconnected == 1) { te = find(world, classname, "grenade"); while (te) { diff --git a/weapons.qc b/weapons.qc index 7255fd19..5332951c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -61,7 +61,7 @@ void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; -void () TeamFortress_DetonatePipebombs; +void (float force) TeamFortress_DetonatePipebombs; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; @@ -2321,7 +2321,7 @@ void () ImpulseCommands = { else if (self.impulse == TF_DASH) CF_Scout_Dash(); else if (self.impulse == TF_PB_DETONATE) - TeamFortress_DetonatePipebombs(); + TeamFortress_DetonatePipebombs(0); else if (self.impulse == TF_DETPACK_STOP) TeamFortress_DetpackStop(); else if (self.impulse == TF_MEDIC_AURA_TOGGLE) From 940136a9e83bbaf882491f6bb0dd8aa44864c356 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 19 Sep 2014 08:52:19 +0200 Subject: [PATCH 0324/2474] Implement option to stock full health/armor (closes #213) --- client.qc | 10 ++++++++++ qw.qc | 1 + tfortmap.qc | 26 ++++++++++++++++++-------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/client.qc b/client.qc index 000887fb..d27a1e66 100644 --- a/client.qc +++ b/client.qc @@ -683,6 +683,15 @@ void () DecodeLevelParms = { else spawnfull = FALSE; + // stock full ammo/armor [on] + st = infokey(world, "stf"); + if (st == string_null) + st = infokey(world, "stockfull"); + if (st == "off") + stockfull = FALSE; + else + stockfull = TRUE; + // delay respawning by this many seconds [0] st = infokey(world, "rd"); if (st == string_null) @@ -703,6 +712,7 @@ void () DecodeLevelParms = { st = infokey(world, "faithful"); if (st == "on") { spawnfull = FALSE; + stockfull = FALSE; drop_grenades = FALSE; drop_grenpack = FALSE; drop_gren1 = 0; diff --git a/qw.qc b/qw.qc index b138a994..95a00280 100644 --- a/qw.qc +++ b/qw.qc @@ -455,6 +455,7 @@ float feign_msg; float scoutdash; float sniperreload; float spawnfull; +float stockfull; float old_spanner; float old_railgun; diff --git a/tfortmap.qc b/tfortmap.qc index 7e53d02a..9aa44a16 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -690,7 +690,10 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (addb) { if (Player.health > 0) { if (Goal.health > 0) { - T_Heal(Player, Goal.health, 0); + if (stockfull) + T_Heal(Player, Player.max_health, 0); + else + T_Heal(Player, Goal.health, 0); } if (Goal.health < 0) { if ((0 - Player.health) > Goal.health) { @@ -703,15 +706,22 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } } if (Player.health > 0) { - if (Goal.armortype > 0) { - Player.armortype = Goal.armortype; - } else if (Goal.armorvalue > 0) { - Player.armortype = Player.armor_allowed; + if (stockfull) { + if (Goal.armortype > 0) + Player.armortype = Player.armor_allowed; + else if (Goal.armorvalue > 0) + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.maxarmor; + } else { + if (Goal.armortype > 0) + Player.armortype = Goal.armortype; + else if (Goal.armorvalue > 0) + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.armorvalue + Goal.armorvalue; } - Player.armorvalue = Player.armorvalue + Goal.armorvalue; - if (Goal.armorclass > 0) { + if (Goal.armorclass > 0) Player.armorclass = Goal.armorclass; - } + Player.ammo_shells = Player.ammo_shells + Goal.ammo_shells; Player.ammo_nails = Player.ammo_nails + Goal.ammo_nails; Player.ammo_rockets = Player.ammo_rockets + Goal.ammo_rockets; From a2bf41d3f11933dc8eecb769ff9d968bfe9b8d01 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 19 Sep 2014 09:51:27 +0200 Subject: [PATCH 0325/2474] Skip cell regeneration cooldown if healing players who used /saveme (closes #207) --- actions.qc | 1 + client.qc | 1 + defs.h | 1 + qw.qc | 1 + weapons.qc | 3 ++- 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/actions.qc b/actions.qc index 776df219..f4d89837 100644 --- a/actions.qc +++ b/actions.qc @@ -111,6 +111,7 @@ void () TeamFortress_SaveMe = { } te = find(te, classname, "player"); } + self.saveme_time = time; }; void (entity pe_player, float f_type) CF_Identify = { diff --git a/client.qc b/client.qc index d27a1e66..4c26e40b 100644 --- a/client.qc +++ b/client.qc @@ -1321,6 +1321,7 @@ void () PutClientInServer = { self.spawn_time = time; self.vote_close = 0; self.has_throwngren = FALSE; + self.saveme_time = 0; self.reload_shotgun = 0; self.reload_super_shotgun = 0; diff --git a/defs.h b/defs.h index 33c7bebe..af224237 100644 --- a/defs.h +++ b/defs.h @@ -845,6 +845,7 @@ #define PC_MEDIC_CELL_REGEN_TIME 1 // Number of seconds between each cell regen. #define PC_MEDIC_CELL_REGEN_AMOUNT 10 // Amount of cells regenerated each cell regen. #define PC_MEDIC_CELL_REGEN_CD 5 // Seconds to cooldown cell regeneration after healing with medikit. +#define PC_MEDIC_SAVEME_GRACE 5 // Seconds after which /saveme gives grace period to medikit (no cell regeneration cooldown) // Class Details for HVYWEAP #define PC_HVYWEAP_SKIN 2 diff --git a/qw.qc b/qw.qc index 95a00280..8cce4415 100644 --- a/qw.qc +++ b/qw.qc @@ -66,6 +66,7 @@ typedef void (float) f_void_float; .float aura_healtime; // Aura healing status will be shown in status bar until this time .float regen_time; // Time when the medic last regenerated cells .float regen_cooldown; // Time to cooldown cell regeneration after using medikit heal +.float saveme_time; // Time when player issued /saveme command .float dash_cooldown; // Cooldown for Scout dash .float undercover_timer; // Seconds left until disguised .float fragstreak; // Frag streak diff --git a/weapons.qc b/weapons.qc index 5332951c..94c3fcef 100644 --- a/weapons.qc +++ b/weapons.qc @@ -528,7 +528,8 @@ void () W_FireMedikit = { if (self.ammo_cells >= 50) { healam = trace_ent.max_health - trace_ent.health + 50; self.ammo_cells = 0; - self.regen_cooldown = time + PC_MEDIC_CELL_REGEN_CD; + if (trace_ent.saveme_time <= (time - PC_MEDIC_SAVEME_GRACE)) + self.regen_cooldown = time + PC_MEDIC_CELL_REGEN_CD; sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); } else { From 17c106f39dafae631c433fc7ed7a6522e69ea0eb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 19 Sep 2014 22:38:26 +0200 Subject: [PATCH 0326/2474] Only change current weapon when reloading a slot if reload is needed (fixes #215) --- actions.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/actions.qc b/actions.qc index f4d89837..14e2b52f 100644 --- a/actions.qc +++ b/actions.qc @@ -318,6 +318,7 @@ void (float weap) TeamFortress_ReloadWeapon = { return; } if (self.ammo_shells >= 1) { + self.current_weapon = weap; if (self.reload_shotgun >= self.ammo_shells) reloadamount = self.ammo_shells; else @@ -357,6 +358,7 @@ void (float weap) TeamFortress_ReloadWeapon = { return; } if (self.ammo_shells >= 2) { + self.current_weapon = weap; if (self.reload_super_shotgun >= self.ammo_shells) reloadamount = self.ammo_shells; else @@ -396,6 +398,7 @@ void (float weap) TeamFortress_ReloadWeapon = { return; } if (self.ammo_shells >= 1) { + self.current_weapon = weap; if (self.reload_super_shotgun >= self.ammo_shells) reloadamount = self.ammo_shells; else @@ -436,6 +439,7 @@ void (float weap) TeamFortress_ReloadWeapon = { return; } if (self.ammo_rockets >= 1) { + self.current_weapon = weap; if (self.reload_grenade_launcher >= self.ammo_rockets) reloadamount = self.ammo_rockets; else @@ -477,6 +481,7 @@ void (float weap) TeamFortress_ReloadWeapon = { return; } if (self.ammo_rockets >= 1) { + self.current_weapon = weap; if (self.reload_rocket_launcher >= self.ammo_rockets) reloadamount = self.ammo_rockets; else @@ -535,7 +540,6 @@ void (float slot) TeamFortress_ReloadSlot = { weap = W_WeaponSlot3(); } - self.current_weapon = weap; TeamFortress_ReloadWeapon(weap); }; From c2b6f0ce98b08a892ad37951afa5aca3603070ea Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 22 Sep 2014 15:01:26 +0200 Subject: [PATCH 0327/2474] Updated /inv command (fixes #192) --- tfort.qc | 162 ++++++++++++++++++++++++++----------------------------- 1 file changed, 77 insertions(+), 85 deletions(-) diff --git a/tfort.qc b/tfort.qc index 5661d14b..08aa9553 100644 --- a/tfort.qc +++ b/tfort.qc @@ -381,125 +381,117 @@ void () TeamFortress_DisplayLegalClasses = { }; void () TeamFortress_Inventory = { - local entity tg; - local string ac; - local float col; - - col = TeamFortress_TeamGetColor(self.team_no); - sprint(self, PRINT_HIGH, "You are in team "); - ac = ftos(self.team_no); - sprint(self, PRINT_HIGH, ac, ", color "); - ac = ftos(col); - sprint(self, PRINT_HIGH, ac, ".\n"); - if (self.lives != -1) { - ac = ftos(self.lives); - sprint(self, PRINT_HIGH, "You have got ", ac); - if (self.lives == 1) - sprint(self, PRINT_HIGH, " life.\n"); - else - sprint(self, PRINT_HIGH, " lives.\n"); + local entity en; + local string st; + local float fl; + + st = TeamFortress_TeamGetColorString(self.team_no); + sprint(self, PRINT_HIGH, st, " team\n"); + + if (self.playerclass == PC_SPY) { + if (self.undercover_team || self.undercover_skin) { + sprint(self, PRINT_HIGH, "Disguised as "); + if (self.undercover_team != 0) + st = TeamFortress_TeamGetColorString(self.undercover_team); + else if (self.team_no == 1) + st = "Blue"; + else if (self.team_no == 2) + st = "Red"; + else if (self.team_no == 3) + st = "Yellow"; + else if (self.team_no == 4) + st = "Green"; + sprint(self, PRINT_HIGH, st); + if (self.undercover_skin != 0) + st = TeamFortress_GetClassName(self.undercover_skin); + else + st = "Spy"; + sprint(self, PRINT_HIGH, " ", st, "\n"); + } } - if (self.no_grenades_1 > 0) { - sprint(self, PRINT_HIGH, "Grenade type 1: "); + + fl = self.no_grenades_1; + if (fl > 0) { + sprint(self, PRINT_HIGH, ftos(fl)); if (self.tp_grenades_1 == GR_TYPE_NORMAL) - sprint(self, PRINT_HIGH, "Normal ("); + sprint(self, PRINT_HIGH, " normal grenade"); else if (self.tp_grenades_1 == GR_TYPE_NAIL) - sprint(self, PRINT_HIGH, "Nail ("); + sprint(self, PRINT_HIGH, " nail grenade"); else if (self.tp_grenades_1 == GR_TYPE_MIRV) - sprint(self, PRINT_HIGH, "Mirv ("); + sprint(self, PRINT_HIGH, " mirv grenade"); else if (self.tp_grenades_1 == GR_TYPE_NAPALM) - sprint(self, PRINT_HIGH, "Napalm ("); + sprint(self, PRINT_HIGH, " napalm grenade"); else if (self.tp_grenades_1 == GR_TYPE_FLARE) - sprint(self, PRINT_HIGH, "Flare ("); + sprint(self, PRINT_HIGH, " flare"); else if (self.tp_grenades_1 == GR_TYPE_GAS) - sprint(self, PRINT_HIGH, "Hallucinogenic ("); + sprint(self, PRINT_HIGH, " hallucinogenic grenade"); else if (self.tp_grenades_1 == GR_TYPE_EMP) - sprint(self, PRINT_HIGH, "EMP ("); - else if (self.tp_grenades_2 == GR_TYPE_CALTROP) - sprint(self, PRINT_HIGH, "Caltrop ("); - else if (self.tp_grenades_2 == GR_TYPE_FLASH) - sprint(self, PRINT_HIGH, "Flash ("); - else - sprint(self, PRINT_HIGH, "BUG ("); + sprint(self, PRINT_HIGH, " EMP grenade"); + else if (self.tp_grenades_1 == GR_TYPE_CALTROP) + sprint(self, PRINT_HIGH, " caltrop canister"); + else if (self.tp_grenades_1 == GR_TYPE_FLASH) + sprint(self, PRINT_HIGH, " flash grenade"); - ac = ftos(self.no_grenades_1); - sprint(self, PRINT_HIGH, ac, ")\n"); + if (fl > 1) + sprint(self, PRINT_HIGH, "s"); + sprint(self, PRINT_HIGH, "\n"); } - if (self.no_grenades_2 > 0) { - sprint(self, PRINT_HIGH, "Grenade type 2: "); + + fl = self.no_grenades_2; + if (fl > 0) { + sprint(self, PRINT_HIGH, ftos(fl)); if (self.tp_grenades_2 == GR_TYPE_NORMAL) - sprint(self, PRINT_HIGH, "Normal ("); - else if (self.tp_grenades_1 == GR_TYPE_CONCUSSION) - sprint(self, PRINT_HIGH, "Concussion ("); + sprint(self, PRINT_HIGH, " normal grenade"); + else if (self.tp_grenades_2 == GR_TYPE_CONCUSSION) + sprint(self, PRINT_HIGH, " concussion grenade"); else if (self.tp_grenades_2 == GR_TYPE_NAIL) - sprint(self, PRINT_HIGH, "Nail ("); + sprint(self, PRINT_HIGH, " nail grenade"); else if (self.tp_grenades_2 == GR_TYPE_MIRV) - sprint(self, PRINT_HIGH, "Mirv ("); + sprint(self, PRINT_HIGH, " mirv grenade"); else if (self.tp_grenades_2 == GR_TYPE_NAPALM) - sprint(self, PRINT_HIGH, "Napalm ("); + sprint(self, PRINT_HIGH, " napalm grenade"); else if (self.tp_grenades_2 == GR_TYPE_FLARE) - sprint(self, PRINT_HIGH, "Flare ("); + sprint(self, PRINT_HIGH, " flare"); else if (self.tp_grenades_2 == GR_TYPE_GAS) - sprint(self, PRINT_HIGH, "Hallucinogenic ("); + sprint(self, PRINT_HIGH, " hallucinogenic grenade"); else if (self.tp_grenades_2 == GR_TYPE_EMP) - sprint(self, PRINT_HIGH, "EMP ("); + sprint(self, PRINT_HIGH, " EMP grenade"); else if (self.tp_grenades_2 == GR_TYPE_FLASH) - sprint(self, PRINT_HIGH, "Flash ("); - else - sprint(self, PRINT_HIGH, "BUG ("); + sprint(self, PRINT_HIGH, " flash grenade"); - ac = ftos(self.no_grenades_2); - sprint(self, PRINT_HIGH, ac, ")\n"); + if (fl > 1) + sprint(self, PRINT_HIGH, "s"); + sprint(self, PRINT_HIGH, "\n"); } if (self.tf_items & NIT_SCANNER) - sprint(self, PRINT_HIGH, "Scanner. "); + sprint(self, PRINT_HIGH, "Scanner"); + + if (self.weapons_carried & WEAP_MEDIKIT) + sprint(self, PRINT_HIGH, "Medikit"); - if (self.weapons_carried & WEAP_MEDIKIT) { - sprint(self, PRINT_HIGH, "Medikit ("); - ac = ftos(self.ammo_medikit); - sprint(self, PRINT_HIGH, ac, ") "); - } if (self.weapons_carried & WEAP_DETPACK) { if (self.ammo_detpack > 0) { - ac = ftos(self.ammo_detpack); - sprint(self, PRINT_HIGH, ac, " Detpack"); + st = ftos(self.ammo_detpack); + sprint(self, PRINT_HIGH, st, " detpack"); if (self.ammo_detpack > 1) sprint(self, PRINT_HIGH, "s"); - sprint(self, PRINT_HIGH, ". "); } } - tg = find(world, classname, "item_tfgoal"); - while (tg) { - if (tg.owner == self) { - sprint(self, PRINT_HIGH, tg.netname, ". "); - } - tg = find(tg, classname, "item_tfgoal"); + + if (self.playerclass == PC_SPY && invis_only) { + sprint(self, PRINT_HIGH, "Invisibility device"); } + if (self.armorvalue > 0) TeamFortress_DescribeArmor(self, self.armorclass); - if (!invis_only) { - if ((self.playerclass == PC_SPY) && (invis_only == 0)) { - sprint(self, PRINT_HIGH, "Skin: "); - if (self.undercover_skin != 0) - TeamFortress_PrintClassName(self, self.undercover_skin, 0); - else - sprint(self, PRINT_HIGH, "Spy\n"); - sprint(self, PRINT_HIGH, "Colors: "); - if (self.undercover_team != 0) - ac = ftos(self.undercover_team); - else if (self.team_no == 1) - ac = "Blue"; - else if (self.team_no == 2) - ac = "Red"; - else if (self.team_no == 3) - ac = "Yellow"; - else if (self.team_no == 4) - ac = "Green"; - sprint(self, PRINT_HIGH, ac); + en = find(world, classname, "item_tfgoal"); + while (en) { + if (en.owner == self) { + sprint(self, PRINT_HIGH, en.netname, "\n"); } + en = find(en, classname, "item_tfgoal"); } - sprint(self, PRINT_HIGH, "\n"); }; void () TeamFortress_ShowTF = { From dd082c17c962c08eb7c2e001d4cbf4cd449a1de5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 22 Sep 2014 19:01:47 +0200 Subject: [PATCH 0328/2474] Remove some useless code in inventory code --- tfort.qc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tfort.qc b/tfort.qc index 08aa9553..4d51fc05 100644 --- a/tfort.qc +++ b/tfort.qc @@ -393,14 +393,6 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, "Disguised as "); if (self.undercover_team != 0) st = TeamFortress_TeamGetColorString(self.undercover_team); - else if (self.team_no == 1) - st = "Blue"; - else if (self.team_no == 2) - st = "Red"; - else if (self.team_no == 3) - st = "Yellow"; - else if (self.team_no == 4) - st = "Green"; sprint(self, PRINT_HIGH, st); if (self.undercover_skin != 0) st = TeamFortress_GetClassName(self.undercover_skin); From 4c4c52281856806e4d4ba3de778bb658c51f7b7c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 25 Sep 2014 13:37:13 +0200 Subject: [PATCH 0329/2474] Remove detpack countdown timers upon disconnect (fixes #216) --- client.qc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/client.qc b/client.qc index 4c26e40b..a98179c1 100644 --- a/client.qc +++ b/client.qc @@ -2237,6 +2237,19 @@ void () ClientDisconnect = { } te = find(te, classname, "detpack"); } + te = find(world, classname, "countdown_timer"); + while (te) { + if (te.owner == self) { + if (te.weaponmode == 1) { + TeamFortress_SetSpeed(te.enemy); + dremove(te.oldenemy); + dremove(te.observer_list); + } + dremove(te); + te = world; + } + te = find(te, classname, "countdown_timer"); + } RemoveGrenades(); if (clanbattle && (self.tf_id != 0)) { te = spawn(); From 574503569ee5d0e9bb02c455901739ddc3f13a46 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 25 Sep 2014 18:19:53 +0200 Subject: [PATCH 0330/2474] Only give armor to player if goal has armor (closes #221) --- tfortmap.qc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 9aa44a16..890e8d18 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -707,11 +707,13 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } if (Player.health > 0) { if (stockfull) { - if (Goal.armortype > 0) + if (Goal.armortype > 0) { Player.armortype = Player.armor_allowed; - else if (Goal.armorvalue > 0) + Player.armorvalue = Player.maxarmor; + } else if (Goal.armorvalue > 0) { Player.armortype = Player.armor_allowed; - Player.armorvalue = Player.maxarmor; + Player.armorvalue = Player.maxarmor; + } } else { if (Goal.armortype > 0) Player.armortype = Goal.armortype; From 70b8469e02fdeb1f8d9457c86bd57beabd58fbfb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 2 Oct 2014 22:52:10 +0200 Subject: [PATCH 0331/2474] Engineer can no longer be moved while building (fixes #223) --- engineer.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engineer.qc b/engineer.qc index 87ceba91..0c976f6f 100644 --- a/engineer.qc +++ b/engineer.qc @@ -376,6 +376,7 @@ void (float objtobuild) TeamFortress_Build = { self.is_building = 1; self.immune_to_check = time + 5; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + self.movetype = MOVETYPE_NONE; self.weapon = self.current_weapon; self.current_weapon = 0; self.weaponmodel = ""; @@ -621,6 +622,7 @@ void () TeamFortress_FinishedBuilding = { oldself.real_owner = self; self.is_building = FALSE; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.movetype = MOVETYPE_WALK; self.current_weapon = self.weapon; Status_Refresh(self); TeamFortress_SetSpeed(self); From 7d3746e4eda87ab0a9cb67c06b8088f7e5096367 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 2 Oct 2014 22:53:19 +0200 Subject: [PATCH 0332/2474] Improve status bar code for Scout and Engineer --- engineer.qc | 1 + qw.qc | 1 + status.qc | 84 +++++++++++++++++++++++++++++++---------------------- 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/engineer.qc b/engineer.qc index 0c976f6f..c5bb0626 100644 --- a/engineer.qc +++ b/engineer.qc @@ -686,6 +686,7 @@ void () TeamFortress_FinishedBuilding = { newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.mdl = "progs/turrgun.mdl"; + self.sentry_ent = newmis; sound(oldself, 3, "weapons/turrset.wav", 1, 1); newmis.solid = SOLID_BBOX; setmodel(newmis, newmis.mdl); diff --git a/qw.qc b/qw.qc index 8cce4415..431c2116 100644 --- a/qw.qc +++ b/qw.qc @@ -156,6 +156,7 @@ float coop; .entity real_owner; .float has_dispenser; // TRUE for an ENGINEER if he has a dispenser .float has_sentry; // TRUE for an ENGINEER if he has a sentry +.entity sentry_ent; // Contains sentry gun entity .float real_frags; // Used to store the players frags when TeamFrags is On diff --git a/status.qc b/status.qc index 6f64b620..021c3618 100644 --- a/status.qc +++ b/status.qc @@ -495,20 +495,24 @@ string(entity pl) RangeToString = local entity te; local float num; + if (!pl.ScannerOn) { + return ""; + } + te = find(world, netname, "scanner"); - while ((te != world) && (te.owner != pl)) + while ((te != world) && (te.owner != pl)) { te = find(te, netname, "scanner"); + } - if (pl.ScannerOn != 1) - return (""); - else - num = te.health; + num = te.health; - if (num <= 0) - return (""); + if (num <= 0) { + return ""; + } - if (num > 99) - return ("99+ m"); + if (num > 99) { + return "99+ m"; + } return strcat(strpadl(ftos(floor(num)), 3), " m"); }; @@ -516,15 +520,19 @@ string(entity pl) RangeToString = string(entity pl) ScannerToString = { local entity te; - local string st, scanfor = "", range = ""; + local string st = ""; + local string scanfor = ""; + local string range = ""; local float pad; te = find(world, netname, "scanner"); - while ((te != world) && (te.owner != pl)) + while ((te != world) && (te.owner != pl)) { te = find(te, netname, "scanner"); + } - if (pl.ScannerOn != 1) - return ("Σγαξξες: off"); + if (pl.ScannerOn != 1) { + return "Σγαξξες: off"; + } if (te.health > 0) { st = "Σγαξξες: "; @@ -540,46 +548,52 @@ string(entity pl) ScannerToString = } else { st = "Σγαξξες: on"; st = strcat(st, " Σγαξξιξη: "); - if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) + + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { scanfor = "team"; + } + if (self.tf_items_flags & NIT_SCANNER_ENEMY) { - if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { scanfor = strcat(scanfor, ", "); + } + scanfor = strcat(scanfor, "enemy"); } - if (!strlen(scanfor)) + + if (!strlen(scanfor)) { scanfor = "nothing"; + } + st = strcat(st, scanfor); } + return st; }; string(entity pl) SentryDetailsToString = { - local entity te; local string ammo = ""; local string shells = ""; local string rockets = ""; local string hp = ""; local string st = ""; - te = find(world, classname, "building_sentrygun"); - while (te) { - if (te.real_owner == self) { - hp = strcat(strpadl(ftos(floor(te.health)), 3), " hp"); - shells = ftos(floor(te.ammo_shells)); - if (te.weapon == 3) { - rockets = ftos(floor(te.ammo_rockets)); - ammo = strcat(" Αννο: ", strcat(shells, strcat("/", rockets))); - } else { - ammo = strcat(" Αννο: ", shells); - } - st = strcat("Σεξτςω: ", strcat(hp, ammo)); - st = strpadr(st, 32); - st = strcat(st, strcat("Μεφεμ: ", ftos(te.weapon))); - return st; + if (self.has_sentry) { + hp = strcat(strpadl(ftos(floor(self.sentry_ent.health)), 3), " hp"); + shells = ftos(floor(self.sentry_ent.ammo_shells)); + + if (self.sentry_ent.weapon == 3) { + rockets = ftos(floor(self.sentry_ent.ammo_rockets)); + ammo = strcat(" Αννο: ", strcat(shells, strcat("/", rockets))); + } else { + ammo = strcat(" Αννο: ", shells); } - te = find(te, classname, "building_sentrygun"); + + st = strcat("Σεξτςω: ", strcat(hp, ammo)); + st = strpadr(st, 32); + st = strcat(st, strcat("Μεφεμ: ", ftos(self.sentry_ent.weapon))); } - return (""); -}; \ No newline at end of file + + return st; +}; From 558242d31e415a1aec4f1a566270043103fa2ff9 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 5 Oct 2014 23:49:46 +0200 Subject: [PATCH 0333/2474] Refactor settings code --- client.qc | 460 ++++++++++++++++-------------------------------------- qw.qc | 2 + 2 files changed, 138 insertions(+), 324 deletions(-) diff --git a/client.qc b/client.qc index a98179c1..24dc9643 100644 --- a/client.qc +++ b/client.qc @@ -126,7 +126,33 @@ void () autokick_think = { dremove(self); }; +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { + local string st; + + st = infokey(world, ps_short); + if (st == string_null) { + st = infokey(world, ps_setting); + } + + if (st == "on") { + return TRUE; + } else if (st == "off") { + return FALSE; + } else if (stof(st) != 0) { + return stof(st); + } else if (ps_default == "on") { + return TRUE; + } else if (ps_default == "off") { + return FALSE; + } else if (stof(ps_default) != 0) { + return stof(ps_default); + } + + return 0; +}; + void () DecodeLevelParms = { + local float fl; local string st; local entity ent; @@ -225,21 +251,14 @@ void () DecodeLevelParms = { local float autoteam_time; autoteam_time = 30; - st = infokey(world, "c"); - if (st == string_null) - st = infokey(world, "clan"); - - if (st == "on") { + clanbattle = CF_GetSetting("c", "clan", "off"); + if (clanbattle) { - clanbattle = TRUE; clan_scores_dumped = 0; game_locked = 0; - st = infokey(world, "pm"); - if (st == string_null) - st = infokey(world, "prematch"); - - cb_prematch_time = time + stof(st) * 60; + cb_prematch_time = CF_GetSetting("pm", "prematch", "0"); + cb_prematch_time = time + cb_prematch_time * 60; if (timelimit && ((time + timelimit) < cb_prematch_time)) { @@ -258,11 +277,7 @@ void () DecodeLevelParms = { } - st = infokey(world, "cft"); - if (st == string_null) - st = infokey(world, "ceasefire_time"); - - cb_ceasefire_time = stof(st); + cb_ceasefire_time = CF_GetSetting("cft", "ceasefire_time", "0"); if (cb_ceasefire_time != 0) { cb_ceasefire_time = time + cb_ceasefire_time * 60; @@ -297,410 +312,165 @@ void () DecodeLevelParms = { te.nextthink = time + 5; } - st = infokey(world, "lg"); - if (st == string_null) - st = infokey(world, "locked_game"); - - if (st == "on") - game_locked = TRUE; + game_locked = CF_GetSetting("lg", "locked_game", "off"); } else clanbattle = FALSE; // automatically assign team [off] - st = infokey(world, "a"); - if (st == string_null) - st = infokey(world, "autoteam"); - if (st == "on") + fl = CF_GetSetting("a", "autoteam", "off"); + if (fl > 1) { toggleflags = toggleflags | TFLAG_AUTOTEAM; - else if (st == "off") - toggleflags = toggleflags - (toggleflags & TFLAG_AUTOTEAM); - else if (stof(st) != 0) { + autoteam_time = fl; + } else if (fl) { toggleflags = toggleflags | TFLAG_AUTOTEAM; - autoteam_time = stof(st); + } else { + toggleflags = toggleflags - (toggleflags & TFLAG_AUTOTEAM); } // auto kick team killers [4 tks per 60 seconds] - st = infokey(world, "akk"); - if (st == string_null) - st = infokey(world, "autokick_kills"); - autokick_kills = stof(st); - if (autokick_kills) { - st = infokey(world, "akt"); - if (st == string_null) - st = infokey(world, "autokick_time"); - autokick_time = stof(st); - } else { - autokick_kills = 4; - autokick_time = 60; - } + autokick_kills = CF_GetSetting("akk", "autokick_kills", "4"); + autokick_time = CF_GetSetting("akt", "autokick_time", "60"); // show team cap frags for all team members [off] - st = infokey(world, "t"); - if (st == string_null) - st = infokey(world, "teamfrags"); - if (st == "on") + if (CF_GetSetting("t", "teamfrags", "off")) { toggleflags = toggleflags | TFLAG_TEAMFRAGS; - else + } else { toggleflags = toggleflags - (toggleflags & TFLAG_TEAMFRAGS); + } // every team member carry the total frags for the team [off] - st = infokey(world, "fts"); - if (st == string_null) - st = infokey(world, "fullteamscore"); - if (st == "on") + if (CF_GetSetting("fts", "fullteamscore", "off")) { toggleflags = toggleflags | TFLAG_FULLTEAMSCORE; - else + } else { toggleflags = toggleflags - (toggleflags & TFLAG_FULLTEAMSCORE); + } // use old concussion, gas and flash grenades [off] - st = infokey(world, "og"); - if (st == string_null) - st = infokey(world, "old_grens"); - if (st == "on") - old_grens = TRUE; - else - old_grens = FALSE; + old_grens = CF_GetSetting("og", "old_grens", "off"); // drop primed hand grenades to ground when dying [on] - st = infokey(world, "dg"); - if (st == string_null) - st = infokey(world, "drop_grenades"); - if (st == "off") - drop_grenades = FALSE; - else - drop_grenades = TRUE; + drop_grenades = CF_GetSetting("dg", "drop_grenades", "on"); // drop grenades in backpack upon death [on] - st = infokey(world, "dgp"); - if (st == string_null) - st = infokey(world, "drop_grenpack"); - if (st == "off") - drop_grenpack = FALSE; - else - drop_grenpack = TRUE; + drop_grenpack = CF_GetSetting("dgp", "drop_grenpack", "on"); // maximum grenades type 1 to drop in backpack [1] - st = infokey(world, "dg1"); - if (st == string_null) - st = infokey(world, "drop_gren1"); - if (st != string_null) - drop_gren1 = stof(st); - else - drop_gren1 = 1; + drop_gren1 = CF_GetSetting("dg1", "drop_gren1", "1"); // maximum grenades type 2 to drop in backpack [0] - st = infokey(world, "dg2"); - if (st == string_null) - st = infokey(world, "drop_gren2"); - if (st != string_null) - drop_gren2 = stof(st); - else - drop_gren2 = 0; + drop_gren2 = CF_GetSetting("dg2", "drop_gren2", "0"); // display grenade timer in status bar [on] - st = infokey(world, "gt"); - if (st == string_null) - st = infokey(world, "grentimers"); - if (st == "off") - grentimers = FALSE; - else - grentimers = TRUE; + grentimers = CF_GetSetting("gt", "grentimers", "on"); // show sentry gun health + misc extras in id string [on] - st = infokey(world, "ie"); - if (st == string_null) - st = infokey(world, "id_extended"); - if (st == "off") - id_extended = FALSE; - else - id_extended = TRUE; + id_extended = CF_GetSetting("ie", "id_extended", "on"); // remember weapon across deaths [on] - st = infokey(world, "rw"); - if (st == string_null) - st = infokey(world, "remember_weapon"); - if (st == "off") - remember_weapon = FALSE; - else - remember_weapon = TRUE; + remember_weapon = CF_GetSetting("rw", "remember_weapon", "on"); // pick up discardable ammo in discarded backpacks [off] - st = infokey(world, "da"); - if (st == string_null) - st = infokey(world, "discammo_pickup"); - if (st == "on") - discammo_pickup = TRUE; - else - discammo_pickup = FALSE; + discammo_pickup = CF_GetSetting("da", "discammo_pickup", "off"); // use old tf style dropflag (map decides on/off) [off] - st = infokey(world, "odf"); - if (st == string_null) - st = infokey(world, "old_dropflag"); - if (st == "on") - old_dropflag = TRUE; - else - old_dropflag = FALSE; + old_dropflag = CF_GetSetting("odf", "old_dropflag", "off"); // show ticking clip ammo in sbar when reloading [on] - st = infokey(world, "rc"); - if (st == string_null) - st = infokey(world, "reload_cliptick"); - if (st == "off") - reload_cliptick = FALSE; - else - reload_cliptick = TRUE; + reload_cliptick = CF_GetSetting("rc", "reload_cliptick", "on"); // use old tf sniper range (shorter) [off] - st = infokey(world, "os"); - if (st == string_null) - st = infokey(world, "old_sniperrange"); - if (st == "on") - old_sniperrange = TRUE; - else - old_sniperrange = FALSE; + old_sniperrange = CF_GetSetting("os", "old_sniperrange", "off"); // maximum amount of pipebombs per demoman [6] - st = infokey(world, "dl"); - if (st == string_null) - st = infokey(world, "detpipe_limit"); - if (st != string_null) - detpipe_limit = stof(st); - else - detpipe_limit = 6; + detpipe_limit = CF_GetSetting("dl", "detpipe_limit", "6"); // maximum amount of pipebombs in game [unlimited] - st = infokey(world, "dw"); - if (st == string_null) - st = infokey(world, "detpipe_limit_world"); - if (st != string_null) - detpipe_limit_world = stof(st); - else - detpipe_limit_world = -1; + detpipe_limit_world = CF_GetSetting("dw", "detpipe_limit_world", "-1"); // use old tf pipebomb cooldown (0.8 seconds) [off] - st = infokey(world, "op"); - if (st == string_null) - st = infokey(world, "old_pipecooldown"); - if (st == "on") - old_pipecooldown = TRUE; - else - old_pipecooldown = FALSE; + old_pipecooldown = CF_GetSetting("op", "old_pipecooldown", "off"); // allow medic aura [on] - st = infokey(world, "ma"); - if (st == string_null) - st = infokey(world, "medicaura"); - if (st == "off") - medicaura = FALSE; - else - medicaura = TRUE; + medicaura = CF_GetSetting("ma", "medicaura", "on"); // use old tf style medikit (don't insta-heal max+50) [off] - st = infokey(world, "om"); - if (st == string_null) - st = infokey(world, "old_medikit"); - if (st == "on") - old_medikit = TRUE; - else - old_medikit = FALSE; + old_medikit = CF_GetSetting("om", "old_medikit", "off"); // use old tf style bioweapon (less damage) [off] - st = infokey(world, "ob"); - if (st == string_null) - st = infokey(world, "old_biodamage"); - if (st == "on") - old_biodamage = TRUE; - else - old_biodamage = FALSE; + old_biodamage = CF_GetSetting("ob", "old_biodamage", "off"); // use old tf style spanner (non-automated) [off] - st = infokey(world, "os"); - if (st == string_null) - st = infokey(world, "old_spanner"); - if (st == "on") - old_spanner = TRUE; - else - old_spanner = FALSE; + old_spanner = CF_GetSetting("os", "old_spanner", "off"); // use old tf style railgun (penetrate target) [off] - st = infokey(world, "or"); - if (st == string_null) - st = infokey(world, "old_railgun"); - if (st == "on") - old_railgun = TRUE; - else - old_railgun = FALSE; + old_railgun = CF_GetSetting("or", "old_railgun", "off"); // use old tf style dispenser (non-auto stocking) [off] - st = infokey(world, "od"); - if (st == string_null) - st = infokey(world, "old_dispenser"); - if (st == "on") - old_dispenser = TRUE; - else - old_dispenser = FALSE; + old_dispenser = CF_GetSetting("od", "old_dispenser", "off"); // enable flamethrower knockback [on] - st = infokey(world, "fk"); - if (st == string_null) - st = infokey(world, "flame_knockback"); - if (st == "off") - flame_knockback = FALSE; - else - flame_knockback = TRUE; + flame_knockback = CF_GetSetting("fk", "flame_knockback", "on"); // bigger dispenser explosions [on] - st = infokey(world, "de"); - if (st == string_null) - st = infokey(world, "disp_explosion"); - if (st == "off") - disp_explosion = FALSE; - else - disp_explosion = TRUE; + disp_explosion = CF_GetSetting("de", "disp_explosion", "on"); // allow assault cannon lock mechanism [on] - st = infokey(world, "cl"); - if (st == string_null) - st = infokey(world, "cannon_lock"); - if (st == "off") - cannon_lock = FALSE; - else - cannon_lock = TRUE; + cannon_lock = CF_GetSetting("cl", "cannon_lock", "on"); // allow assault cannon fire in air [on] - st = infokey(world, "ca"); - if (st == string_null) - st = infokey(world, "cannon_air"); - if (st == "off") - cannon_air = FALSE; - else - cannon_air = TRUE; + cannon_air = CF_GetSetting("ca", "cannon_air", "on"); // allow movement while firing assault cannon [on] - st = infokey(world, "cm"); - if (st == string_null) - st = infokey(world, "cannon_move"); - if (st == "off") - cannon_move = FALSE; - else - cannon_move = TRUE; + cannon_move = CF_GetSetting("cm", "cannon_move", "on"); // make assault cannon spin while moving [off] - st = infokey(world, "cms"); - if (st == string_null) - st = infokey(world, "cannon_movespin"); - if (st == "on") { - cannon_movespin = TRUE; + cannon_movespin = CF_GetSetting("cms", "cannon_movespin", "off"); + if (cannon_movespin) { cannon_move = TRUE; // required for this to work - } else - cannon_movespin = FALSE; + } // make hwguy susceptible to concussion grenade while firing assault cannon [on] - st = infokey(world, "cc"); - if (st == string_null) - st = infokey(world, "cannon_conc"); - if (st == "off") - cannon_conc = FALSE; - else - cannon_conc = TRUE; + cannon_conc = CF_GetSetting("cc", "cannon_conc", "on"); // assault cannon accuracy (0 = cf, 1 = tf 2.8, 2 = tf 2.9) [0] - st = infokey(world, "cac"); - if (st == string_null) - st = infokey(world, "cannon_accuracy"); - if (st != string_null) - cannon_accuracy = stof(st); + cannon_accuracy = CF_GetSetting("cac", "cannon_accuracy", "0"); // allow feign death in air [on] - st = infokey(world, "fa"); - if (st == string_null) - st = infokey(world, "feign_air"); - if (st == "off") - feign_air = FALSE; - else - feign_air = TRUE; + feign_air = CF_GetSetting("fa", "feign_air", "on"); // drop an empty backpack when feigning death [on] - st = infokey(world, "fp"); - if (st == string_null) - st = infokey(world, "feign_pack"); - if (st == "off") - feign_pack = FALSE; - else - feign_pack = TRUE; + feign_pack = CF_GetSetting("fp", "feign_pack", "on"); // print fake death message when feigning death [on] - st = infokey(world, "fm"); - if (st == string_null) - st = infokey(world, "feign_msg"); - if (st == "off") - feign_msg = FALSE; - else - feign_msg = TRUE; + feign_msg = CF_GetSetting("fm", "feign_msg", "on"); - // allow spy [on] - st = infokey(world, "spy"); - if (st == "off") - spy_off = TRUE; - else - spy_off = FALSE; + // turn off spy [off] + spy_off = CF_GetSetting("spy", "spy", "off"); // enable spy invisibility [off] - st = infokey(world, "s"); - if (st == string_null) - st = infokey(world, "spyinvis"); - if (st == "on") - invis_only = TRUE; - else - invis_only = FALSE; + invis_only = CF_GetSetting("s", "spyinvis", "off"); // allow scout dash [on] - st = infokey(world, "sd"); - if (st == string_null) - st = infokey(world, "scoutdash"); - if (st == "off") - scoutdash = FALSE; - else - scoutdash = TRUE; + scoutdash = CF_GetSetting("sd", "scoutdash", "on"); // enable sniper rifle reload [on] - st = infokey(world, "sr"); - if (st == string_null) - st = infokey(world, "sniperreload"); - if (st == "off") - sniperreload = FALSE; - else - sniperreload = TRUE; + sniperreload = CF_GetSetting("sr", "sniperreload", "on"); // spawn with full ammo/armor [off] - st = infokey(world, "sf"); - if (st == string_null) - st = infokey(world, "spawnfull"); - if (st == "on") - spawnfull = TRUE; - else - spawnfull = FALSE; + spawnfull = CF_GetSetting("sf", "spawnfull", "off"); // stock full ammo/armor [on] - st = infokey(world, "stf"); - if (st == string_null) - st = infokey(world, "stockfull"); - if (st == "off") - stockfull = FALSE; - else - stockfull = TRUE; + stockfull = CF_GetSetting("stf", "stockfull", "on"); // delay respawning by this many seconds [0] - st = infokey(world, "rd"); - if (st == string_null) - st = infokey(world, "respawn_delay"); - respawn_delay_time = stof(st); - if (respawn_delay_time) + respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); + if (respawn_delay_time) { toggleflags = toggleflags | TFLAG_RESPAWNDELAY; - if ((toggleflags & TFLAG_RESPAWNDELAY) && !respawn_delay_time) + } + if ((toggleflags & TFLAG_RESPAWNDELAY) && !respawn_delay_time) { respawn_delay_time = RESPAWN_DELAY_TIME; + } if (toggleflags & TFLAG_AUTOTEAM) { toggleflags = toggleflags - (toggleflags & TFLAG_AUTOTEAM); @@ -709,10 +479,50 @@ void () DecodeLevelParms = { ent.think = autoteam_think; } - st = infokey(world, "faithful"); + st = infokey(world, "default"); if (st == "on") { + server_default = TRUE; + old_grens = FALSE; + drop_grenades = TRUE; + drop_grenpack = TRUE; + drop_gren1 = 1; + drop_gren2 = 0; + grentimers = TRUE; + id_extended = TRUE; + remember_weapon = TRUE; + discammo_pickup = FALSE; + old_dropflag = FALSE; + reload_cliptick = TRUE; + scoutdash = TRUE; + sniperreload = TRUE; + old_sniperrange = FALSE; + detpipe_limit = 6; + detpipe_limit_world = -1; + old_pipecooldown = FALSE; + medicaura = TRUE; + old_medikit = FALSE; + old_biodamage = FALSE; + cannon_lock = TRUE; + cannon_air = TRUE; + cannon_move = TRUE; + cannon_movespin = FALSE; + cannon_conc = TRUE; + cannon_accuracy = 0; + flame_knockback = TRUE; + old_spanner = FALSE; + old_railgun = FALSE; + old_dispenser = FALSE; + disp_explosion = TRUE; + feign_air = TRUE; + feign_pack = TRUE; + feign_msg = TRUE; spawnfull = FALSE; - stockfull = FALSE; + stockfull = TRUE; + } + + st = infokey(world, "faithful"); + if (st == "on") { + server_faithful = TRUE; drop_grenades = FALSE; drop_grenpack = FALSE; drop_gren1 = 0; @@ -746,6 +556,8 @@ void () DecodeLevelParms = { feign_air = FALSE; feign_pack = FALSE; feign_msg = FALSE; + spawnfull = FALSE; + stockfull = FALSE; } } diff --git a/qw.qc b/qw.qc index 431c2116..2c6515e1 100644 --- a/qw.qc +++ b/qw.qc @@ -458,6 +458,8 @@ float scoutdash; float sniperreload; float spawnfull; float stockfull; +float server_default; +float server_faithful; float old_spanner; float old_railgun; From 8c706a68b1ce098219f22b59bf13a191be0e7474 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 5 Oct 2014 23:50:13 +0200 Subject: [PATCH 0334/2474] Show all settings in /showtf (closes #193) --- tfort.qc | 180 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 154 insertions(+), 26 deletions(-) diff --git a/tfort.qc b/tfort.qc index 4d51fc05..78c63688 100644 --- a/tfort.qc +++ b/tfort.qc @@ -486,42 +486,170 @@ void () TeamFortress_Inventory = { } }; +void (string ps_description, float pf_setting, string ps_last, float pf_bool) CF_PrintSetting = { + local string st; + + st = strpadr(ps_description, 40); + + if (!pf_bool) { + st = strcat(st, ftos(pf_setting)); + } else if (pf_setting) { + st = strcat(st, "on"); + } else { + st = strcat(st, "off"); + } + + if (strlen(ps_last) > 0) { + st = strcat(st, " "); + st = strcat(st, ps_last); + } + + st = strcat(st, "\n"); + + sprint(self, PRINT_HIGH, st); +}; + void () TeamFortress_ShowTF = { local string st; - if (toggleflags & TFLAG_CLASS_PERSIST) - sprint(self, PRINT_HIGH, "Class persistence on\n"); - else - sprint(self, PRINT_HIGH, "Class persistence off\n"); + sprint(self, PRINT_HIGH, "\nThis server is running Classic Fortress "); + sprint(self, PRINT_HIGH, VER); + sprint(self, PRINT_HIGH, "\n\n"); + + sprint(self, PRINT_HIGH, "== Team Fortress ==\n"); + if (autokick_kills) { + sprint(self, PRINT_HIGH, "Kick teamkillers "); + sprint(self, PRINT_HIGH, ftos(autokick_kills)); + sprint(self, PRINT_HIGH, " kills / "); + sprint(self, PRINT_HIGH, ftos(autokick_time)); + sprint(self, PRINT_HIGH, " secs\n"); + } else { + sprint(self, PRINT_HIGH, "Kick teamkillers off\n"); + } - if (toggleflags & TFLAG_CHEATCHECK) - sprint(self, PRINT_HIGH, "Cheat checking on\n"); - else - sprint(self, PRINT_HIGH, "Cheat checking off\n"); + if (toggleflags & TFLAG_CLASS_PERSIST) { + sprint(self, PRINT_HIGH, "Class persistence on\n"); + } else { + sprint(self, PRINT_HIGH, "Class persistence off\n"); + } - if (toggleflags & TFLAG_AUTOTEAM) - sprint(self, PRINT_HIGH, "Autoteam on\n"); - else - sprint(self, PRINT_HIGH, "Autoteam off\n"); + if (toggleflags & TFLAG_CHEATCHECK) { + sprint(self, PRINT_HIGH, "Cheat checking on\n"); + } else { + sprint(self, PRINT_HIGH, "Cheat checking off\n"); + } - if (toggleflags & TFLAG_RESPAWNDELAY) + if (toggleflags & TFLAG_AUTOTEAM) { + sprint(self, PRINT_HIGH, "Autoteam on\n"); + } else { + sprint(self, PRINT_HIGH, "Autoteam off\n"); + } + + sprint(self, PRINT_HIGH, "Respawn delay "); + if (toggleflags & TFLAG_RESPAWNDELAY) { st = ftos(respawn_delay_time); - else - st = "No"; + } else { + st = "off"; + } sprint(self, PRINT_HIGH, st); - if (st != "No") - sprint(self, PRINT_HIGH, " second"); - sprint(self, PRINT_HIGH, " Respawn delay\n"); + if (st != "off") { + sprint(self, PRINT_HIGH, " seconds"); + } + sprint(self, PRINT_HIGH, "\n"); - if (toggleflags & TFLAG_TEAMFRAGS) - sprint(self, PRINT_HIGH, "Teamfrags on\n"); - else - sprint(self, PRINT_HIGH, "Teamfrags off\n"); + if (toggleflags & TFLAG_TEAMFRAGS) { + sprint(self, PRINT_HIGH, "Teamfrags on\n"); + } else { + sprint(self, PRINT_HIGH, "Teamfrags off\n"); + } - if (toggleflags & TFLAG_FULLTEAMSCORE) - sprint(self, PRINT_HIGH, "Full teamscore on\n"); - else - sprint(self, PRINT_HIGH, "Full teamscore off\n"); + if (toggleflags & TFLAG_FULLTEAMSCORE) { + sprint(self, PRINT_HIGH, "Full teamscore on\n"); + } else { + sprint(self, PRINT_HIGH, "Full teamscore off\n"); + } + + sprint(self, PRINT_HIGH, "\n== Classic Fortress ==\n"); + CF_PrintSetting("Spawn with full health/armor", spawnfull, "", 1); + CF_PrintSetting("Stock players with full health/armor", stockfull, "", 1); + CF_PrintSetting("Old dropflag behaviour", old_dropflag, "", 1); + CF_PrintSetting("Remember weapon", remember_weapon, "", 1); + CF_PrintSetting("Pick up discarded ammo", discammo_pickup, "", 1); + CF_PrintSetting("Reload clip tick", reload_cliptick, "", 1); + CF_PrintSetting("ID extras", id_extended, "", 1); + CF_PrintSetting("Old grenades", old_grens, "", 1); + CF_PrintSetting("Drop grenades on ground", drop_grenades, "", 1); + CF_PrintSetting("Drop grenades in pack", drop_grenpack, "", 1); + if (drop_grenpack) { + CF_PrintSetting("- Grenades type 1", drop_gren1, "", 0); + CF_PrintSetting("- Grenades type 2", drop_gren2, "", 0); + } + CF_PrintSetting("Grenade timers", grentimers, "", 1); + + sprint(self, PRINT_HIGH, "\n== Scout ==\n"); + CF_PrintSetting("Scout dash ability", scoutdash, "", 1); + + sprint(self, PRINT_HIGH, "\n== Sniper ==\n"); + CF_PrintSetting("Sniper reload", sniperreload, "", 1); + CF_PrintSetting("Old sniper rifle range", old_sniperrange, "", 1); + + sprint(self, PRINT_HIGH, "\n== Demolitions Man ==\n"); + if (detpipe_limit > 0) { + CF_PrintSetting("Pipebomb limit (per demoman)", detpipe_limit, "", 0); + } else if (detpipe_limit == 0) { + sprint(self, PRINT_HIGH, "Pipebomb limit (per demoman): 0 (disallow)\n"); + } else { + sprint(self, PRINT_HIGH, "Pipebomb limit (per demoman): unlimited\n"); + } + if (detpipe_limit_world > 0) { + CF_PrintSetting("Pipebomb limit (team)", detpipe_limit_world, "", 0); + } else if (detpipe_limit_world == 0) { + sprint(self, PRINT_HIGH, "Pipebomb limit (team): 0 (disallow)\n"); + } else { + sprint(self, PRINT_HIGH, "Pipebomb limit (team): unlimited\n"); + } + CF_PrintSetting("Old pipebomb cooldown", old_pipecooldown, "", 1); + + sprint(self, PRINT_HIGH, "\n== Combat Medic ==\n"); + CF_PrintSetting("Medic aura ability", medicaura, "", 1); + CF_PrintSetting("Old medikit behaviour", old_medikit, "", 1); + CF_PrintSetting("Old bioweapon damage", old_sniperrange, "", 1); + + sprint(self, PRINT_HIGH, "\n== Heavy Weapons Guy ==\n"); + CF_PrintSetting("Assault Cannon lock ability", cannon_lock, "", 1); + CF_PrintSetting("Allow Assault Cannon in air", cannon_air, "", 1); + if (!cannon_movespin) { + CF_PrintSetting("Allow Assault Cannon while moving", cannon_move, "", 1); + } + CF_PrintSetting("Spin Assault Cannon while moving", cannon_movespin, "", 1); + CF_PrintSetting("Allow Assault Cannon concussion", cannon_conc, "", 1); + if (cannon_movespin == 0) { + sprint(self, PRINT_HIGH, "Assault Cannon accuracy: CF style\n"); + } else if (cannon_movespin == 1) { + sprint(self, PRINT_HIGH, "Assault Cannon accuracy: TF 2.8 style\n"); + } else { + sprint(self, PRINT_HIGH, "Assault Cannon accuracy: TF 2.9 style\n"); + } + + sprint(self, PRINT_HIGH, "\n== Pyro ==\n"); + CF_PrintSetting("Flamethrower knockback", flame_knockback, "", 1); + + sprint(self, PRINT_HIGH, "\n== Engineer ==\n"); + CF_PrintSetting("Old spanner behaviour", old_spanner, "", 1); + CF_PrintSetting("Old railgun behaviour", old_railgun, "", 1); + CF_PrintSetting("Old dispenser behaviour", old_dispenser, "", 1); + CF_PrintSetting("Bigger dispenser explosions", disp_explosion, "", 1); + + sprint(self, PRINT_HIGH, "\n== Spy ==\n"); + CF_PrintSetting("Allow feign death while airborne", feign_air, "", 1); + CF_PrintSetting("Drop feign backpack", feign_pack, "", 1); + CF_PrintSetting("Print feign death message", feign_msg, "", 1); + + if (server_faithful) { + sprint(self, PRINT_HIGH, "\nThis server is running faithful Team Fortress settings.\n"); + } else if (server_default) { + sprint(self, PRINT_HIGH, "\nThis server is running default Classic Fortress settings.\n"); + } }; void () TeamFortress_GrenadePrimed; From bd0ab4ea463e037215a3d4471c18a8716b2101af Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 9 Oct 2014 13:54:05 +0200 Subject: [PATCH 0335/2474] Stop team menu from being closed prematurely (fixes #225) --- menu.qc | 6 ++++-- tforthlp.qc | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/menu.qc b/menu.qc index 0c4d7dac..802793f1 100644 --- a/menu.qc +++ b/menu.qc @@ -111,7 +111,9 @@ void (float inp) Menu_Team_Input = { if (inp == 0) { return; - } if (inp == 5) { + } + + if (inp == 5) { TeamFortress_TeamPutPlayerInTeam(); } else if ((inp <= number_of_teams) && (inp > 0)) { TeamFortress_TeamSet(inp); @@ -822,7 +824,7 @@ void (float inp) Menu_EngineerFix_SentryGun_Input = { }; void () Menu_EngineerFix_SentryGun = { - + // only show this menu if old_spanner setting is enabled, otherwise show rotate menu if (!old_spanner) { Menu_EngineerFix_SentryGun_Rotate(); diff --git a/tforthlp.qc b/tforthlp.qc index 3e30d886..0b7f6c0e 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -173,7 +173,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); } else if (self.motd == 400 && self.team_no == 0) { - Menu_Team(0); + Menu_Team(1); } self.motd = self.motd + 1; From 6bca52bb00bdf52a9bfadc8367ed08104637c2e3 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 9 Oct 2014 13:54:35 +0200 Subject: [PATCH 0336/2474] Refactor some team code --- tforttm.qc | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/tforttm.qc b/tforttm.qc index 8079bf38..9175ddee 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -113,13 +113,9 @@ void (entity p) SetTeamName = { stuffcmd(p, "\n"); }; -float (float tno) TeamFortress_TeamSet = { - local string st; +float (float tno) CF_TeamIsValid = { local float tc; - local string team; - - if ((intermission_running != 0) || (intermission_exittime > time)) - return (0); + local string team, st; if (tno == 1) team = "blue team"; @@ -133,24 +129,52 @@ float (float tno) TeamFortress_TeamSet = { if (teamplay < 1) { sprint(self, PRINT_HIGH, "Teamplay is not on, so teams are inactive\n"); - return (0); + return 0; } + if ((tno > number_of_teams) && (number_of_teams != 0)) { sprint(self, PRINT_HIGH, "There can be only "); st = ftos(number_of_teams); sprint(self, PRINT_HIGH, st, " teams on this map\n"); - return (0); + return 0; } + if (self.team_no == tno) { sprint(self, PRINT_HIGH, "You're already in the "); sprint(self, PRINT_HIGH, team, "\n"); - return (0); + return 0; } + tc = TeamFortress_TeamGetNoPlayers(tno); if (tc >= TeamFortress_TeamGetMaxPlayers(tno)) { sprint(self, PRINT_HIGH, "That team is full, pick another\n"); + return 0; + } + + return 1; +} + +float (float tno) TeamFortress_TeamSet = { + local string st; + local float tc; + local string team; + + if ((intermission_running != 0) || (intermission_exittime > time)) return (0); + + if (!CF_TeamIsValid) { + return 0; } + + if (tno == 1) + team = "blue team"; + else if (tno == 2) + team = "red team"; + else if (tno == 3) + team = "yellow team"; + else + team = "green team"; + if (TeamFortress_TeamGetColor(tno) == 0) { TeamFortress_TeamSetColor(tno); if (TeamFortress_TeamGetColor(tno) == 0) { From 33771e6e0eadd9e3b051cacfce989e8bb8e997f1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 12 Oct 2014 08:52:28 +0200 Subject: [PATCH 0337/2474] Made grenade timer into a long sound (closes #226) --- tfort.qc | 10 +++++----- world.qc | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tfort.qc b/tfort.qc index 78c63688..065d47c2 100644 --- a/tfort.qc +++ b/tfort.qc @@ -656,14 +656,11 @@ void () TeamFortress_GrenadePrimed; void () GrenadeTimer = { self.heat = self.heat - 1; + self.nextthink = time + 1; self.owner.StatusGrenTime = self.heat; Status_Refresh(self.owner); - if (self.heat > 0) { - if (!stof(infokey(self.owner, "nt"))) - stuffcmd(self.owner, "play items/grentimer.wav\n"); - self.nextthink = time + 1.0; - } else { + if (!self.heat) { dremove(self); } }; @@ -846,6 +843,9 @@ void (float inp) TeamFortress_PrimeGrenade = { timer.heat = 4; timer.owner = self; timer.classname = "gtimer"; + if (!notimers) { + stuffcmd(self, "play grentimer\n"); + } } } diff --git a/world.qc b/world.qc index 79e33cf3..9eb73902 100644 --- a/world.qc +++ b/world.qc @@ -285,7 +285,7 @@ void () worldspawn = { precache_sound2("speech/saveme2.wav"); precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); - precache_sound("items/grentimer.wav"); + precache_sound("grentimer.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); From ea7415774c1cf4e3b7865e1db125299c8458fbe5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 13 Oct 2014 14:43:41 +0200 Subject: [PATCH 0338/2474] Engineer can now walk after cancelling build (fixes #230) --- engineer.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/engineer.qc b/engineer.qc index c5bb0626..bcdee982 100644 --- a/engineer.qc +++ b/engineer.qc @@ -257,6 +257,7 @@ void () TeamFortress_EngineerBuildStop = { sprint(self, PRINT_HIGH, "You stop building\n"); self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; + self.movetype = MOVETYPE_WALK; TeamFortress_SetSpeed(self); te = find(world, netname, "build_timer"); while (te) { From ba2dba47832b488bc274d6b2e2335e242267b9a9 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 23 Oct 2014 08:42:02 +0200 Subject: [PATCH 0339/2474] Regenerate Medic health with 50 or more cells (fixes #231) --- medic.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/medic.qc b/medic.qc index f0f21447..f9044af6 100644 --- a/medic.qc +++ b/medic.qc @@ -118,7 +118,8 @@ void () CF_Medic_Regenerate = { return; } - if (self.owner.health >= self.owner.max_health || self.owner.ammo_medikit) + // only regen if 50 or more cells + if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < 50) return; if (self.owner.ammo_medikit < PC_MEDIC_REGEN_AMOUNT) { From c919d880c42b85e4bf214d8fba5aed60dc7a2030 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 23 Oct 2014 14:56:08 +0200 Subject: [PATCH 0340/2474] Draw sprite when Sniper bullet hits wall (fixes #228) --- weapons.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/weapons.qc b/weapons.qc index 94c3fcef..3c5cd4d5 100644 --- a/weapons.qc +++ b/weapons.qc @@ -800,6 +800,8 @@ void (vector direction, float damage) FireSniperBullet = { if (trace_fraction != 1) TraceAttack(damage, direction); + FireBullets(1, direction, '0 0 0'); + ApplyMultiDamage(); }; @@ -908,6 +910,8 @@ void () W_FireSniperRifle = { if (trace_fraction != 1) TraceAttack(self.heat * dam_mult, dir); + FireBullets(1, dir, '0 0 0'); + ApplyMultiDamage(); }; From e7b020a2570609b12ff276c714414fe76a21a76a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 23 Oct 2014 14:58:20 +0200 Subject: [PATCH 0341/2474] Increase kickback for automatic weapons (fixes looping kickback bug) --- weapons.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index 3c5cd4d5..73a6cda7 100644 --- a/weapons.qc +++ b/weapons.qc @@ -796,6 +796,8 @@ void (vector direction, float damage) FireSniperBullet = { src_z = self.absmin_z + self.size_z * 0.7; ClearMultiDamage(); + KickPlayer(-3, self); + traceline(src, src + direction * 4096, FALSE, self); if (trace_fraction != 1) TraceAttack(damage, direction); @@ -1281,7 +1283,7 @@ void () W_FireSuperSpikes = { newmis.weapon = DMSG_SNAILGUN; setmodel(newmis, "progs/s_spike.mdl"); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); - KickPlayer(-2, self); + KickPlayer(-3, self); }; void (float ox) W_FireSpikes = { @@ -1307,7 +1309,7 @@ void (float ox) W_FireSpikes = { } dir = aim(self, 1000); launch_spike(self.origin + '0 0 16' + v_right * ox, dir); - KickPlayer(-2, self); + KickPlayer(-3, self); }; .float hit_z; From 02181d4c95b6bbf18cbda69b0dc7aea0ff861e50 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 24 Oct 2014 11:04:30 +0200 Subject: [PATCH 0342/2474] Don't return flag if flag is already returned (fixes #233) --- tfortmap.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tfortmap.qc b/tfortmap.qc index 890e8d18..3ffded79 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1962,6 +1962,9 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { void () ReturnItem = { local entity te; + if (self.enemy.origin == self.enemy.oldorigin) + return; + self.enemy.goal_state = 2; if ((self.enemy.goal_activation & 8192) && (self.enemy.classname == "item_tfgoal")) From bfa77e1180b2714dd7b847558c14330f324067aa Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 24 Oct 2014 11:12:49 +0200 Subject: [PATCH 0343/2474] Disable map voting during clan battle --- vote.qc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/vote.qc b/vote.qc index 6607deb1..7c50f1a1 100644 --- a/vote.qc +++ b/vote.qc @@ -46,6 +46,9 @@ float vote_started, vote_update, vote_winnercount, vote_decider, vote_abort; void (entity pe_player) Vote_NextMap = { local float f_votes, f_votes_needed, f_votes_left; + if (clanbattle) + return; + if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_next) return; @@ -84,6 +87,9 @@ void (entity pe_player) Vote_NextMap = { void (entity pe_player) Vote_TrickMap = { local float f_votes, f_votes_needed, f_votes_left; + if (clanbattle) + return; + if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_trick) return; @@ -122,6 +128,9 @@ void (entity pe_player) Vote_TrickMap = { void (entity pe_player) Vote_RaceMap = { local float f_votes, f_votes_needed, f_votes_left; + if (clanbattle) + return; + if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_race) return; @@ -158,6 +167,10 @@ void (entity pe_player) Vote_RaceMap = { // opens/closes the currently active vote menu // called from weapons.qc:ImpulseCommands() void (entity pe_player) Vote_ToggleMenu = { + + if (clanbattle) + return; + if (vote_started > 0 && !vote_abort) { if (pe_player.menu_input != Vote_Input) { //dprint("[", ftos(time), "/cf/mapvote/togglemenu]: toggling map vote on for ", pe_player.netname, ".\n"); @@ -227,6 +240,9 @@ float () Vote_GetRaceVotes = { void (entity pe_player) Vote_ForceNext = { local float f_votes, f_votes_needed, f_votes_left; + if (clanbattle) + return; + if (!pe_player.team_no || !pe_player.playerclass) return; @@ -1057,4 +1073,4 @@ string (string ps_list, float pf_idx) List_Index = { return strzone(substr(ps_list, f_start, i - f_start)); return strzone(string_null); -}; \ No newline at end of file +}; From 265a32d3f91dd12f993ea162b7733952a0702c8c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 25 Oct 2014 14:47:16 +0200 Subject: [PATCH 0344/2474] Fix bug where flag does not respawn --- tfortmap.qc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 3ffded79..393a78d1 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1962,9 +1962,6 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { void () ReturnItem = { local entity te; - if (self.enemy.origin == self.enemy.oldorigin) - return; - self.enemy.goal_state = 2; if ((self.enemy.goal_activation & 8192) && (self.enemy.classname == "item_tfgoal")) @@ -1980,9 +1977,13 @@ void () ReturnItem = { setmodel(self.enemy, self.enemy.mdl); setorigin(self.enemy, self.enemy.origin); - sound(self.enemy, 2, "items/itembk2.wav", 1, 1); tfgoalitem_checkgoalreturn(self.enemy); + if (self.enemy.origin == self.enemy.oldorigin) + return; + + sound(self.enemy, 2, "items/itembk2.wav", 1, 1); + if (self.weapon != 2) { if ((self.enemy.noise3 != string_null) || (self.enemy.noise4 != string_null)) { From e6b44046f86c977ece5fe9ac883bf160437155ce Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 26 Oct 2014 08:41:05 +0100 Subject: [PATCH 0345/2474] Make Medic self-regen behaviour respect old_medikit --- medic.qc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/medic.qc b/medic.qc index f9044af6..91b03527 100644 --- a/medic.qc +++ b/medic.qc @@ -118,9 +118,14 @@ void () CF_Medic_Regenerate = { return; } - // only regen if 50 or more cells - if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < 50) + // only regen if 50 or more cells with new medikit + if (!old_medikit) { + if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < 50) { + return; + } + } else if (self.owner.health >= self.owner.max_health || self.owner.ammo_medikit) { return; + } if (self.owner.ammo_medikit < PC_MEDIC_REGEN_AMOUNT) { self.owner.health = self.owner.health + self.owner.ammo_medikit; From 95cbd84bcddbb7fa1a7b1a414445024319e851e4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 26 Oct 2014 09:16:32 +0100 Subject: [PATCH 0346/2474] Remove flamer flames when they enter water (fixes #229) --- weapons.qc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/weapons.qc b/weapons.qc index 73a6cda7..b7077935 100644 --- a/weapons.qc +++ b/weapons.qc @@ -951,21 +951,51 @@ void () W_FireAssaultCannon = { }; void () s_explode1 =[0, s_explode2] { + if (self.classname == "flamerflame") { + if (pointcontents(self.origin) < -1) { + dremove(self); + } + } }; void () s_explode2 =[1, s_explode3] { + if (self.classname == "flamerflame") { + if (pointcontents(self.origin) < -1) { + dremove(self); + } + } }; void () s_explode3 =[2, s_explode4] { + if (self.classname == "flamerflame") { + if (pointcontents(self.origin) < -1) { + dremove(self); + } + } }; void () s_explode4 =[3, s_explode5] { + if (self.classname == "flamerflame") { + if (pointcontents(self.origin) < -1) { + dremove(self); + } + } }; void () s_explode5 =[4, s_explode6] { + if (self.classname == "flamerflame") { + if (pointcontents(self.origin) < -1) { + dremove(self); + } + } }; void () s_explode6 =[5, SUB_Remove] { + if (self.classname == "flamerflame") { + if (pointcontents(self.origin) < -1) { + dremove(self); + } + } }; void () BecomeExplosion = { From 4b543d87d0ad38cdb8ab3ef61c21dd95d2b8e89c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 26 Oct 2014 09:40:38 +0100 Subject: [PATCH 0347/2474] Check if something is in the way of the flag before picking it up (fixes #227) --- tfortmap.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tfortmap.qc b/tfortmap.qc index 393a78d1..470200c5 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1837,6 +1837,11 @@ void () item_tfgoal_touch = { if (other == self.owner) return; + // check if a wall or something is in the way of the flag + traceline(other.origin, self.origin, TRUE, world); + if (trace_fraction < 1) + return; + if (CTF_Map == 1) { if (self.goal_no == 1) { if (self.origin != self.oldorigin) { From 3c3ed8096b8ed5d86667350a95bf1b7e0fc1fb79 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 26 Oct 2014 10:49:05 +0100 Subject: [PATCH 0348/2474] Execute cfg/default.cfg instead of fortress.cfg on map change --- world.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world.qc b/world.qc index 9eb73902..10f2d217 100644 --- a/world.qc +++ b/world.qc @@ -153,7 +153,7 @@ void () worldspawn = { exec_map_cfgs = TRUE; if (exec_map_cfgs) { - localcmd("exec fortress.cfg\n"); + localcmd("exec cfg/default.cfg\n"); localcmd("exec cfg/maps/"); localcmd(mapname); localcmd(".cfg\n"); From 8788b2be88d73163132840e30be856412f2579f0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 26 Oct 2014 11:48:47 +0100 Subject: [PATCH 0349/2474] Play fire sound on player when burning (fixes #234) --- pyro.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyro.qc b/pyro.qc index 2f1fc66a..77325e3e 100644 --- a/pyro.qc +++ b/pyro.qc @@ -523,13 +523,12 @@ void () Napalm_touch = { (other.team_no == self.owner.team_no)) { return; } + sound(other, CHAN_VOICE, "ambience/fire1.wav", 1, ATTN_NORM); CenterPrint(other, "You are on fire!\n"); stuffcmd(other, "bf\n"); } if (other.numflames < 1) { flame = FlameSpawn("1", other); - sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, - ATTN_NORM); } else { flame = FlameSpawn("3", other); if (flame == world) { From 770086e07ec99085b680bc99eb3e8edb9bb3ea57 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 08:48:30 +0100 Subject: [PATCH 0350/2474] Flamer flames extinquish effect respect faithful setting and play a sound upon entering water --- weapons.qc | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/weapons.qc b/weapons.qc index b7077935..05a55cda 100644 --- a/weapons.qc +++ b/weapons.qc @@ -950,50 +950,62 @@ void () W_FireAssaultCannon = { FireBullets(5, dir, '0.15 0.15 0'); }; +void (entity pe_flame) CF_ExtinguishFlame = { + local float rn; + + rn = random(); + if (rn < 0.5) { + sound(pe_flame, CHAN_VOICE, "misc/water1.wav", 1, ATTN_NORM); + } else { + sound(pe_flame, CHAN_VOICE, "misc/water2.wav", 1, ATTN_NORM); + } + dremove(pe_flame); +}; + void () s_explode1 =[0, s_explode2] { - if (self.classname == "flamerflame") { + if (!server_faithful && self.classname == "flamerflame") { if (pointcontents(self.origin) < -1) { - dremove(self); + CF_ExtinguishFlame(self); } } }; void () s_explode2 =[1, s_explode3] { - if (self.classname == "flamerflame") { + if (!server_faithful && self.classname == "flamerflame") { if (pointcontents(self.origin) < -1) { - dremove(self); + CF_ExtinguishFlame(self); } } }; void () s_explode3 =[2, s_explode4] { - if (self.classname == "flamerflame") { + if (!server_faithful && self.classname == "flamerflame") { if (pointcontents(self.origin) < -1) { - dremove(self); + CF_ExtinguishFlame(self); } } }; void () s_explode4 =[3, s_explode5] { - if (self.classname == "flamerflame") { + if (!server_faithful && self.classname == "flamerflame") { if (pointcontents(self.origin) < -1) { - dremove(self); + CF_ExtinguishFlame(self); } } }; void () s_explode5 =[4, s_explode6] { - if (self.classname == "flamerflame") { + if (!server_faithful && self.classname == "flamerflame") { if (pointcontents(self.origin) < -1) { - dremove(self); + CF_ExtinguishFlame(self); } } }; void () s_explode6 =[5, SUB_Remove] { - if (self.classname == "flamerflame") { + if (!server_faithful && self.classname == "flamerflame") { if (pointcontents(self.origin) < -1) { - dremove(self); + CF_ExtinguishFlame(self); } } }; @@ -2597,7 +2609,7 @@ void () W_WeaponFrame = { // change to weaponstate (prior to quick fire) when weapon is ready else if (self.is_quickfiring) self.queue_weaponstate = 2; - // change to last weapon when weapon is ready + // change to last weapon when weapon is ready else self.queue_weaponslot = self.last_weaponslot; } From 4be0fa8ed3984b145728882e2254920ef8f57282 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 09:13:53 +0100 Subject: [PATCH 0351/2474] Reorder aliases and remove scan10/30/100 aliases (#235) --- tforthlp.qc | 154 ++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 76 deletions(-) diff --git a/tforthlp.qc b/tforthlp.qc index 0b7f6c0e..2917c7f3 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -14,7 +14,6 @@ void () TeamFortress_MOTD = { local string ya; if (self.motd == 5) { - stuffcmd(self, "is_aliased\n"); sprint(self, PRINT_HIGH, "\nClassic Fortress ", VER, "\n\n"); st1 = infokey(world, "motd1"); @@ -46,13 +45,24 @@ void () TeamFortress_MOTD = { return; } - TeamFortress_Alias("inv", TF_INVENTORY, 0); - TeamFortress_Alias("showtf", TF_SHOWTF, 0); - TeamFortress_Alias("zoomtoggle", TF_ZOOMTOGGLE, 0); - TeamFortress_Alias("zoomin", TF_ZOOMIN, 0); - TeamFortress_Alias("zoomout", TF_ZOOMOUT, 0); + TeamFortress_Alias("menu", TF_CLASSMENU, 0); + TeamFortress_Alias("slot1", 1, 0); + TeamFortress_Alias("slot2", 2, 0); + TeamFortress_Alias("slot3", 3, 0); + TeamFortress_Alias("slot4", 4, 0); + TeamFortress_AliasString("+slot1", "impulse 31;+attack"); + TeamFortress_AliasString("-slot1", "-attack;impulse 68"); + TeamFortress_AliasString("+slot2", "impulse 32;+attack"); + TeamFortress_AliasString("-slot2", "-attack;impulse 68"); + TeamFortress_AliasString("+slot3", "impulse 33;+attack"); + TeamFortress_AliasString("-slot3", "-attack;impulse 68"); + TeamFortress_AliasString("+slot4", "impulse 34;+attack"); + TeamFortress_AliasString("-slot4", "-attack;impulse 68"); + } else if (self.motd == 30) { TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); TeamFortress_Alias("changeclass", TF_CHANGECLASS, 0); + TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); + TeamFortress_Alias("classhelp", TF_CLASSHELP, 0); TeamFortress_Alias("scout", TF_CHANGEPC + PC_SCOUT, 0); TeamFortress_Alias("sniper", TF_CHANGEPC + PC_SNIPER, 0); TeamFortress_Alias("soldier", TF_CHANGEPC + PC_SOLDIER, 0); @@ -63,29 +73,41 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("spy", TF_CHANGEPC + PC_SPY, 0); TeamFortress_Alias("engineer", TF_CHANGEPC + PC_ENGINEER, 0); TeamFortress_Alias("randompc", TF_CHANGEPC + PC_RANDOM, 0); - TeamFortress_Alias("classhelp", TF_CLASSHELP, 0); + } else if (self.motd == 40) { + TeamFortress_Alias("query", TF_STATUS_QUERY, 0); + TeamFortress_Alias("inv", TF_INVENTORY, 0); + TeamFortress_Alias("showtf", TF_SHOWTF, 0); + TeamFortress_Alias("showscores", TF_TEAM_SCORES, 0); + TeamFortress_Alias("flaginfo", FLAG_INFO, 0); + TeamFortress_Alias("maphelp", TF_HELP_MAP, 0); + TeamFortress_Alias("showids", TF_SHOW_IDS, 0); + TeamFortress_Alias("id", TF_ID, 0); + TeamFortress_Alias("idteam", TF_ID_TEAM, 0); + TeamFortress_Alias("idenemy", TF_ID_ENEMY, 0); TeamFortress_Alias("is_aliased", TF_ALIAS_CHECK, 0); - } else if (self.motd == 25) { - TeamFortress_Alias("menu", TF_CLASSMENU, 0); + } else if (self.motd == 50) { + TeamFortress_Alias("votenext", TF_VOTENEXT, 0); + TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); + TeamFortress_Alias("voterace", TF_VOTERACE, 0); + TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); + TeamFortress_Alias("togglevote", TF_TOGGLEVOTE, 0); + TeamFortress_Alias("dropkey", TF_DROPKEY, 0); + TeamFortress_Alias("dropammo", TF_DROP_AMMO, 0); + TeamFortress_Alias("dropflag", TF_DROPFLAG, 0); + TeamFortress_Alias("showloc", TF_DISPLAYLOCATION, 0); + TeamFortress_Alias("special", TF_SPECIAL_SKILL, 0); + TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); + TeamFortress_Alias("discard", TF_DISCARD, 0); + } else if (self.motd == 60) { TeamFortress_Alias("weapnext", TF_WEAPNEXT, 0); TeamFortress_Alias("weapprev", TF_WEAPPREV, 0); TeamFortress_Alias("weaplast", TF_WEAPLAST, 0); - TeamFortress_Alias("detpipe", TF_PB_DETONATE, 0); TeamFortress_Alias("reload", TF_RELOAD, 0); TeamFortress_Alias("reload1", TF_RELOAD_SLOT1, 0); TeamFortress_Alias("reload2", TF_RELOAD_SLOT2, 0); TeamFortress_Alias("reload3", TF_RELOAD_SLOT3, 0); TeamFortress_Alias("reloadnext", TF_RELOAD_NEXT, 0); - TeamFortress_Alias("dash", TF_DASH, 0); - TeamFortress_Alias("autoscan", TF_SCAN, 0); - TeamFortress_Alias("scansound", TF_SCAN_SOUND, 0); - TeamFortress_Alias("scan10", TF_SCAN, 0); - TeamFortress_Alias("scan30", TF_SCAN, 0); - TeamFortress_Alias("scan100", TF_SCAN, 0); - TeamFortress_Alias("scanf", TF_SCAN_FRIENDLY, 0); - TeamFortress_Alias("scane", TF_SCAN_ENEMY, 0); - TeamFortress_Alias("aura", TF_MEDIC_AURA_TOGGLE, 0); - } else if (self.motd == 35) { + } else if (self.motd == 70) { TeamFortress_Alias("primeone", TF_GRENADE_1, 0); TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); @@ -96,37 +118,35 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); - TeamFortress_Alias("slot1", 1, 0); - TeamFortress_Alias("slot2", 2, 0); - TeamFortress_Alias("slot3", 3, 0); - TeamFortress_Alias("slot4", 4, 0); - TeamFortress_AliasString("+slot1", "impulse 31;+attack"); - TeamFortress_AliasString("-slot1", "-attack;impulse 68"); - TeamFortress_AliasString("+slot2", "impulse 32;+attack"); - TeamFortress_AliasString("-slot2", "-attack;impulse 68"); - TeamFortress_AliasString("+slot3", "impulse 33;+attack"); - TeamFortress_AliasString("-slot3", "-attack;impulse 68"); - TeamFortress_AliasString("+slot4", "impulse 34;+attack"); - TeamFortress_AliasString("-slot4", "-attack;impulse 68"); - TeamFortress_Alias("showscores", TF_TEAM_SCORES, 0); - TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); - TeamFortress_Alias("query", TF_STATUS_QUERY, 0); - } else if (self.motd == 45) { - TeamFortress_Alias("dropkey", TF_DROPKEY, 0); - TeamFortress_Alias("dropammo", TF_DROP_AMMO, 0); - TeamFortress_Alias("dropflag", TF_DROPFLAG, 0); - TeamFortress_Alias("showloc", TF_DISPLAYLOCATION, 0); - TeamFortress_Alias("special", TF_SPECIAL_SKILL, 0); - TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); - TeamFortress_Alias("discard", TF_DISCARD, 0); - TeamFortress_Alias("id", TF_ID, 0); - TeamFortress_Alias("idteam", TF_ID_TEAM, 0); - TeamFortress_Alias("idenemy", TF_ID_ENEMY, 0); - TeamFortress_Alias("votenext", TF_VOTENEXT, 0); - TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); - TeamFortress_Alias("voterace", TF_VOTERACE, 0); - TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); - TeamFortress_Alias("togglevote", TF_TOGGLEVOTE, 0); + } else if (self.motd == 80) { + TeamFortress_Alias("dash", TF_DASH, 0); + TeamFortress_Alias("autoscan", TF_SCAN, 0); + TeamFortress_Alias("scansound", TF_SCAN_SOUND, 0); + TeamFortress_Alias("scanf", TF_SCAN_FRIENDLY, 0); + TeamFortress_Alias("scane", TF_SCAN_ENEMY, 0); + TeamFortress_Alias("zoomtoggle", TF_ZOOMTOGGLE, 0); + TeamFortress_Alias("zoomin", TF_ZOOMIN, 0); + TeamFortress_Alias("zoomout", TF_ZOOMOUT, 0); + } else if (self.motd == 90) { + TeamFortress_Alias("detpipe", TF_PB_DETONATE, 0); + TeamFortress_Alias("+det5", TF_DETPACK_5, 0); + TeamFortress_Alias("-det5", TF_DETPACK_STOP, 0); + TeamFortress_Alias("+det20", TF_DETPACK_20, 0); + TeamFortress_Alias("-det20", TF_DETPACK_STOP, 0); + TeamFortress_Alias("+det50", TF_DETPACK_50, 0); + TeamFortress_Alias("-det50", TF_DETPACK_STOP, 0); + TeamFortress_Alias("+det255", TF_DETPACK, 255); + TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); + } else if (self.motd == 100) { + TeamFortress_Alias("aura", TF_MEDIC_AURA_TOGGLE, 0); + TeamFortress_Alias("lock", TF_LOCKON, 0); + TeamFortress_Alias("unlock", TF_LOCKOFF, 0); + TeamFortress_Alias("+lock", TF_LOCKON, 0); + TeamFortress_Alias("-lock", TF_LOCKOFF, 0); + TeamFortress_Alias("disguise", TF_SPY_SPY, 0); + TeamFortress_Alias("feign", TF_SPY_DIE, 0); + TeamFortress_Alias("sfeign", TF_SPY_SILENT_DIE, 0); + } else if (self.motd == 110) { TeamFortress_Alias("dreset", TF_DISGUISE_RESET, 0); TeamFortress_Alias("dscout", TF_DISGUISE_SCOUT, 0); TeamFortress_Alias("dsniper", TF_DISGUISE_SNIPER, 0); @@ -135,6 +155,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dmedic", TF_DISGUISE_MEDIC, 0); TeamFortress_Alias("dhwguy", TF_DISGUISE_HWGUY, 0); TeamFortress_Alias("dpyro", TF_DISGUISE_PYRO, 0); + } else if (self.motd == 120) { TeamFortress_Alias("dengineer", TF_DISGUISE_ENGINEER, 0); TeamFortress_Alias("dblue", TF_DISGUISE_BLUE, 0); TeamFortress_Alias("dred", TF_DISGUISE_RED, 0); @@ -142,36 +163,17 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dgreen", TF_DISGUISE_GREEN, 0); TeamFortress_Alias("denemy", TF_DISGUISE_ENEMY, 0); TeamFortress_Alias("dlast", TF_DISGUISE_LAST, 0); - } else if (self.motd == 55) { - TeamFortress_Alias("flaginfo", FLAG_INFO, 0); - TeamFortress_Alias("maphelp", TF_HELP_MAP, 0); - TeamFortress_Alias("showids", TF_SHOW_IDS, 0); - } else if (self.motd == 75) { - TeamFortress_Alias("+det5", TF_DETPACK_5, 0); - TeamFortress_Alias("-det5", TF_DETPACK_STOP, 0); - TeamFortress_Alias("+det20", TF_DETPACK_20, 0); - TeamFortress_Alias("-det20", TF_DETPACK_STOP, 0); - TeamFortress_Alias("+det50", TF_DETPACK_50, 0); - TeamFortress_Alias("-det50", TF_DETPACK_STOP, 0); - TeamFortress_Alias("+det255", TF_DETPACK, 255); - TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); - TeamFortress_Alias("lock", TF_LOCKON, 0); - TeamFortress_Alias("unlock", TF_LOCKOFF, 0); - TeamFortress_Alias("+lock", TF_LOCKON, 0); - TeamFortress_Alias("-lock", TF_LOCKOFF, 0); - } else if (self.motd == 85) { + TeamFortress_Alias("build", TF_ENGINEER_BUILD, 0); + TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); + TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); + } else if (self.motd == 130) { TeamFortress_Alias("clan1", 82, 0); TeamFortress_Alias("clan2", 83, 0); TeamFortress_Alias("clan3", 84, 0); TeamFortress_Alias("clan4", 85, 0); TeamFortress_Alias("clan5", 86, 0); - } else if (self.motd == 95) { - TeamFortress_Alias("disguise", TF_SPY_SPY, 0); - TeamFortress_Alias("feign", TF_SPY_DIE, 0); - TeamFortress_Alias("sfeign", TF_SPY_SILENT_DIE, 0); - TeamFortress_Alias("build", TF_ENGINEER_BUILD, 0); - TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); - TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); + } else if (self.motd == 140) { + stuffcmd(self, "is_aliased\n"); } else if (self.motd == 400 && self.team_no == 0) { Menu_Team(1); } From 82c25a7df2bd5cc7bac6402f611c1f3f773d51b3 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 12:19:00 +0100 Subject: [PATCH 0352/2474] Improve scanf/scane code (#235) --- weapons.qc | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/weapons.qc b/weapons.qc index 05a55cda..b430d82d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2536,39 +2536,42 @@ void () DeadImpulses = { self.tf_items_flags = self.tf_items_flags | 4; sprint(self, PRINT_HIGH, "on\n"); } - } else if ((self.playerclass == 1) && (self.impulse == TF_SCAN_ENEMY)) { + } else if ((self.playerclass == PC_SCOUT) && (self.impulse == TF_SCAN_ENEMY)) { sprint(self, PRINT_HIGH, "Scanning for: "); if (self.tf_items_flags & NIT_SCANNER_ENEMY) { self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_ENEMY; - if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { sprint(self, PRINT_HIGH, "Friendlies only\n"); - else + } else { sprint(self, PRINT_HIGH, "Nothing\n"); + } } else { self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY; - if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { sprint(self, PRINT_HIGH, "Friendlies and enemies\n"); - else + } else { sprint(self, PRINT_HIGH, "Enemies only\n"); + } + Status_Refresh(self); } - } else if ((self.playerclass == 1) && - (self.impulse == TF_SCAN_FRIENDLY)) { + } else if ((self.playerclass == PC_SCOUT) && (self.impulse == TF_SCAN_FRIENDLY)) { sprint(self, PRINT_HIGH, "Scanning for: "); if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { - self.tf_items_flags = - self.tf_items_flags - NIT_SCANNER_FRIENDLY; - if (self.tf_items_flags & NIT_SCANNER_ENEMY) + self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_FRIENDLY; + if (self.tf_items_flags & NIT_SCANNER_ENEMY) { sprint(self, PRINT_HIGH, "Enemies only\n"); - else + } else { sprint(self, PRINT_HIGH, "Nothing\n"); + } } else { - self.tf_items_flags = - self.tf_items_flags | NIT_SCANNER_FRIENDLY; - if (self.tf_items_flags & NIT_SCANNER_ENEMY) + self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_FRIENDLY; + if (self.tf_items_flags & NIT_SCANNER_ENEMY) { sprint(self, PRINT_HIGH, "Friendlies and enemies\n"); - else + } else { sprint(self, PRINT_HIGH, "Friendlies only\n"); + } } + Status_Refresh(self); } else if (self.impulse == TF_ALIAS_CHECK) { sprint(self, PRINT_HIGH, "Aliases checked\n"); self.got_aliases = 1; From 7a7fe9d3c719a51a09aa6baf24c34bdcd82a8dc7 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 12:24:26 +0100 Subject: [PATCH 0353/2474] Remove TeamFortress_Message command (clan sounds) (closes #235) --- actions.qc | 31 ------------------------------- tforthlp.qc | 6 ------ weapons.qc | 12 ------------ 3 files changed, 49 deletions(-) diff --git a/actions.qc b/actions.qc index 14e2b52f..6ab17aff 100644 --- a/actions.qc +++ b/actions.qc @@ -587,34 +587,3 @@ void () TeamFortress_ClipTick = { dremove(self); } }; - -void (float messageno) TeamFortress_Message = { - local entity te; - local string wstr; - - wstr = infokey(world, "clanmsgs"); - if (wstr != "on") - return; - - if (self.last_saveme_sound > time) - return; - - self.last_saveme_sound = time + 3; - if (messageno == 1) - wstr = "play clan1.wav\n"; - else if (messageno == 2) - wstr = "play clan2.wav\n"; - else if (messageno == 3) - wstr = "play clan3.wav\n"; - else if (messageno == 4) - wstr = "play clan4.wav\n"; - else if (messageno == 5) - wstr = "play clan5.wav\n"; - - te = find(world, classname, "player"); - while (te) { - if ((te.team_no == self.team_no) && (self.team_no != 0)) - stuffcmd(te, wstr); - te = find(te, classname, "player"); - } -}; diff --git a/tforthlp.qc b/tforthlp.qc index 2917c7f3..f8464959 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -167,12 +167,6 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); } else if (self.motd == 130) { - TeamFortress_Alias("clan1", 82, 0); - TeamFortress_Alias("clan2", 83, 0); - TeamFortress_Alias("clan3", 84, 0); - TeamFortress_Alias("clan4", 85, 0); - TeamFortress_Alias("clan5", 86, 0); - } else if (self.motd == 140) { stuffcmd(self, "is_aliased\n"); } else if (self.motd == 400 && self.team_no == 0) { Menu_Team(1); diff --git a/weapons.qc b/weapons.qc index b430d82d..37e3b15b 100644 --- a/weapons.qc +++ b/weapons.qc @@ -24,8 +24,6 @@ void () DropGoalItems; void () TeamFortress_DisplayLegalClasses; -void (float messageno) TeamFortress_Message; - void () TeamFortress_ShowIDs; void () TeamFortress_ShowTF; @@ -2341,16 +2339,6 @@ void () ImpulseCommands = { TeamFortress_Inventory(); else if ((self.playerclass != 0) && (self.impulse == TF_MEDIC_HELPME)) TeamFortress_SaveMe(); - else if ((self.playerclass != 0) && (self.impulse == 82)) - TeamFortress_Message(1); - else if ((self.playerclass != 0) && (self.impulse == 83)) - TeamFortress_Message(2); - else if ((self.playerclass != 0) && (self.impulse == 84)) - TeamFortress_Message(3); - else if ((self.playerclass != 0) && (self.impulse == 85)) - TeamFortress_Message(4); - else if ((self.playerclass != 0) && (self.impulse == 86)) - TeamFortress_Message(5); else if (self.impulse == TF_GRENADE_T) TeamFortress_ThrowGrenade(); else if (self.impulse == TF_GRENADE_SWITCH) From 405d7228ad45a6c224bbe91e8c933f443e337254 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 12:40:52 +0100 Subject: [PATCH 0354/2474] Remove weapon selection code from prematchimpulses --- weapons.qc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/weapons.qc b/weapons.qc index 37e3b15b..e0447a34 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2442,12 +2442,7 @@ void () ImpulseCommands = { }; void () PreMatchImpulses = { - if (((self.impulse >= 1) && (self.impulse < 8)) || - (self.impulse == TF_MEDIKIT)) - W_ChangeWeapon(self.impulse); - else if (self.impulse == AXE_IMP) - W_ChangeWeapon(self.impulse); - else if (self.impulse == TF_WEAPNEXT) + if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); else if (self.impulse == TF_WEAPPREV) CycleWeaponPrev(); From 829a55a79d617f53210869f747decba1ee777a86 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 12:41:01 +0100 Subject: [PATCH 0355/2474] Make use of classmenu macro --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index e0447a34..fbf7bc5e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2570,7 +2570,7 @@ void () W_WeaponFrame = { } } - if (self.impulse == 5) { + if (self.impulse == TF_CLASSMENU) { if (self.playerclass == PC_ENGINEER) Menu_Engineer(self); else if (self.playerclass == PC_SCOUT) From a8727a596d2af3c011aaf1bb8a104c12bbf5697e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 14:57:39 +0100 Subject: [PATCH 0356/2474] Add alias for showing legal classes --- tforthlp.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tforthlp.qc b/tforthlp.qc index f8464959..50e0c0eb 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -62,6 +62,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); TeamFortress_Alias("changeclass", TF_CHANGECLASS, 0); TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); + TeamFortress_Alias("legalclasses", TF_SHOWLEGALCLASSES, 0); TeamFortress_Alias("classhelp", TF_CLASSHELP, 0); TeamFortress_Alias("scout", TF_CHANGEPC + PC_SCOUT, 0); TeamFortress_Alias("sniper", TF_CHANGEPC + PC_SNIPER, 0); From cd7bd35cf5ffb4df59f6dba72d482ed20ed7a3dc Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 15:17:23 +0100 Subject: [PATCH 0357/2474] Improve quick slot code --- weapons.qc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/weapons.qc b/weapons.qc index fbf7bc5e..c47ee2d9 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2638,14 +2638,22 @@ void () W_WeaponFrame = { W_WeaponState_Load(self, 0); // +slot1-4 quick fire - } else if (self.impulse >= 31 && self.impulse <= 34 + } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && !self.is_building && !self.is_detpacking) { self.is_quickfiring = 1; self.has_quickfired = 0; - if (WeaponReady(self)) - W_ChangeWeapon((self.impulse - 30)); + if (WeaponReady(self)) { + if (self.impulse == TF_QUICKSLOT1) + W_ChangeWeapon(1); + else if (self.impulse == TF_QUICKSLOT2) + W_ChangeWeapon(2); + else if (self.impulse == TF_QUICKSLOT3) + W_ChangeWeapon(3); + else if (self.impulse == TF_QUICKSLOT4) + W_ChangeWeapon(4); + } // change weapon if queue_weaponslot has been set } else if (self.queue_weaponslot > 0) { From c13ae43f277cdbf8be70719597d9ac9451c6804e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 19:43:10 +0100 Subject: [PATCH 0358/2474] Reorder and clean up impulses --- defs.h | 441 ++++++++++++++++++++++++++++++---------------------- tforthlp.qc | 20 +-- weapons.qc | 4 +- 3 files changed, 268 insertions(+), 197 deletions(-) diff --git a/defs.h b/defs.h index af224237..6e0206ed 100644 --- a/defs.h +++ b/defs.h @@ -321,192 +321,263 @@ // through the playerclass. /*======================================================*/ -/* Impulse Defines */ +/* Impulse Defines */ /*======================================================*/ -#define TF_CLASSMENU 5 -#define TF_WEAPNEXT 10 -#define TF_WEAPPREV 12 -// Alias check to see whether they already have the aliases -#define TF_ALIAS_CHECK 13 - -// Class help alias -#define TF_CLASSHELP 14 - -// CTF Support Impulses -#define HOOK_IMP1 22 -#define FLAG_INFO 23 -#define HOOK_IMP2 39 - -// Quick weapon impulses -#define TF_QUICKSLOT1 31 -#define TF_QUICKSLOT2 32 -#define TF_QUICKSLOT3 33 -#define TF_QUICKSLOT4 34 - -// Axe -#define AXE_IMP 40 - -// Medic functions -#define TF_MEDIC_AURA_TOGGLE 41 - -// Camera Impulse -#define TF_CAM_TARGET 50 -#define TF_CAM_ZOOM 51 -#define TF_CAM_ANGLE 52 -#define TF_CAM_VEC 53 -#define TF_CAM_PROJECTILE 54 -#define TF_CAM_PROJECTILE_Z 55 -#define TF_CAM_REVANGLE 56 -#define TF_CAM_OFFSET 57 -#define TF_CAM_DROP 58 -#define TF_CAM_FADETOBLACK 59 -#define TF_CAM_FADEFROMBLACK 60 -#define TF_CAM_FADETOWHITE 61 -#define TF_CAM_FADEFROMWHITE 62 - -#define TF_QUICKSTOP 68 -#define TF_WEAPLAST 69 - -// CF map voting -#define TF_VOTENEXT 70 -#define TF_VOTETRICK 71 -#define TF_VOTERACE 72 -#define TF_FORCENEXT 73 -#define TF_TOGGLEVOTE 74 - -// Reload impulses -#define TF_RELOAD_NEXT 80 -#define TF_RELOAD_SLOT1 81 -#define TF_RELOAD_SLOT2 82 -#define TF_RELOAD_SLOT3 83 -#define TF_RELOAD 173 - -#define TF_CHANGETEAM 98 -#define TF_CHANGECLASS 99 -// Added to PC_??? to get impulse to use if this clashes with your -// own impulses, just change this value, not the PC_?? -#define TF_CHANGEPC 100 -// The next few impulses are all the class selections -//PC_SCOUT 101 -//PC_SNIPER 102 -//PC_SOLDIER 103 -//PC_DEMOMAN 104 -//PC_MEDIC 105 -//PC_HVYWEAP 106 -//PC_PYRO 107 -//PC_RANDOM 108 -//PC_CIVILIAN 109 // Cannot be used -//PC_SPY 110 -//PC_ENGINEER 111 - -// Sniper Zoom impulses -#define TF_ZOOMTOGGLE 113 -#define TF_ZOOMIN 114 -#define TF_ZOOMOUT 115 - -// Help impulses -#define TF_HELP_MAP 117 -#define TF_DISPLAYLOCATION 118 -#define TF_STATUS_QUERY 119 - -// Disguise impulses -#define TF_DISGUISE_RESET 120 -#define TF_DISGUISE_SCOUT 121 -#define TF_DISGUISE_SNIPER 122 -#define TF_DISGUISE_SOLDIER 123 -#define TF_DISGUISE_DEMOMAN 124 -#define TF_DISGUISE_MEDIC 125 -#define TF_DISGUISE_HWGUY 126 -#define TF_DISGUISE_PYRO 127 -#define TF_DISGUISE_ENGINEER 128 -#define TF_DISGUISE_BLUE 129 -#define TF_DISGUISE_RED 130 -#define TF_DISGUISE_YELLOW 131 -#define TF_DISGUISE_GREEN 132 -#define TF_DISGUISE_ENEMY 133 -#define TF_DISGUISE_LAST 134 - -// Information impulses -#define TF_INVENTORY 135 -#define TF_SHOWTF 136 -#define TF_SHOWLEGALCLASSES 137 - -// Team Impulses -#define TF_TEAM_1 140 // Join Team 1 -#define TF_TEAM_2 141 // Join Team 2 -#define TF_TEAM_3 142 // Join Team 3 -#define TF_TEAM_4 143 // Join Team 4 -#define TF_TEAM_CLASSES 144 // Impulse to display team classes -#define TF_TEAM_SCORES 145 // Impulse to display team scores -#define TF_TEAM_LIST 146 // Impulse to display the players in each team. - -// Grenade Impulses -#define TF_GRENADE_1 150 // Prime grenade type 1 -#define TF_GRENADE_2 151 // Prime grenade type 2 -#define TF_GRENADE_T 152 // Throw primed grenade -#define TF_GRENADE_SWITCH 153 // Switch grenade mode 1/2 -#define TF_GRENADE_PT_1 154 // Prime and throw grenade type 1 (two clicks) -#define TF_GRENADE_PT_2 155 // Prime and throw grenade type 2 (two clicks) - -// Scout dash -#define TF_DASH 156 // Initialize a forward bunnyhop for Scout - -// Impulses for new items -#define TF_LOCKON 157 // Turn Assault Cannon fire on -#define TF_LOCKOFF 158 // Turn Assault Cannon fire off -#define TF_SCAN 159 // Scanner Pre-Impulse -#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies -#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies -#define TF_SCAN_SOUND 162 // Toggle scanner sound -#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) -#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) -#define TF_DETPACK_5 165 // Detpack set to 5 seconds -#define TF_DETPACK_20 166 // Detpack set to 20 seconds -#define TF_DETPACK_50 167 // Detpack set to 50 seconds -#define TF_DETPACK 168 // Detpack Pre-Impulse -#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack -#define TF_PB_DETONATE 170 // Detonate Pipebombs - -// Special skill -#define TF_SPECIAL_SKILL 171 - -// Ammo Drop impulse -#define TF_DROP_AMMO 172 - -// drop/pass commands -#define TF_DROPKEY 175 - -// Select Medikit -#define TF_MEDIKIT 176 - -// Spy Impulses -#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color -#define TF_SPY_DIE 178 // Feign Death -#define TF_SPY_SILENT_DIE 199 // silent feign death - -// Engineer Impulses -#define TF_ENGINEER_BUILD 179 -#define TF_ENGINEER_SANDBAG 180 -#define TF_ENGINEER_DETDISP 187 -#define TF_ENGINEER_DETSENTRY 188 - -// Demoman Impulses -#define TF_DEMOMAN_DETPACK 189 - -// Medic!! -#define TF_MEDIC_HELPME 181 - -// Discard impulse -#define TF_DISCARD 184 - -// ID Player impulse -#define TF_ID 190 -#define TF_ID_TEAM 191 -#define TF_ID_ENEMY 192 - -// other impulses -#define TF_SHOW_IDS 186 -#define TF_DROPFLAG 194 +#define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) +#define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) +#define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) +#define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_CLASSMENU 5 // Brings up class menu +// unused 6 +// unused 7 +// unused 8 +// unused 9 +// unused 10 +#define TF_WEAPNEXT 11 // Selects the next weapon slot +#define TF_WEAPPREV 12 // Selects the previous weapon slot +#define TF_WEAPLAST 13 // Selects the last used weapon slot +#define TF_GRENADE_1 14 // Prime grenade type 1 +#define TF_GRENADE_2 15 // Prime grenade type 2 +#define TF_GRENADE_T 16 // Throw primed grenade +#define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) +#define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) +#define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 +#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon +#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon +#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon +#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon +#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped +#define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 +#define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 +#define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 +#define TF_RELOAD 28 // Reload current weapon +#define TF_RELOAD_NEXT 29 // Reload next weapon with a non-full clip +#define TF_SPECIAL_SKILL 30 // Class special +#define TF_DROPFLAG 31 // Drop flag +#define TF_DROPKEY 32 // Drop key +#define TF_DISCARD 33 // Discard useless ammo +#define TF_DROP_AMMO 34 // Drop an ammo box on the ground +#define TF_MEDIC_HELPME 35 // Alert players around you that you are in need of medical attention +#define TF_INVENTORY 36 // Displays current inventory +#define FLAG_INFO 37 // Displays current flag location +#define TF_ID 38 // Identify player/object in front of player +#define TF_ID_TEAM 39 // Identify team player/object in front of player +#define TF_ID_ENEMY 40 // Identify enemy player/object in front of player +#define TF_DASH 41 // Scout: Initialize a forward bunnyhop +#define TF_SCAN 42 // Scout: Toggle Scanner on/off +#define TF_SCAN_ENEMY 43 // Scout: Toggle scanning of enemies +#define TF_SCAN_FRIENDLY 44 // Scout: Toggle scanning of friendlies +#define TF_SCAN_SOUND 45 // Scout: Toggle scanner sound +#define TF_ZOOMTOGGLE 46 // Sniper: Toggle zoom mode on/off +#define TF_ZOOMIN 47 // Sniper: Zoom in (while zoom mode is on) +#define TF_ZOOMOUT 48 // Sniper: Zoom out (while zoom mode is on) +#define TF_DEMOMAN_DETPACK 49 // Demoman: Bring up detpack menu +#define TF_DETPACK 50 // Demoman: Detpack Pre-Impulse +#define TF_DETPACK_STOP 51 // Demoman: Impulse to stop setting detpack +#define TF_DETPACK_5 52 // Demoman: Detpack set to 5 seconds +#define TF_DETPACK_20 53 // Demoman: Detpack set to 20 seconds +#define TF_DETPACK_50 54 // Demoman: Detpack set to 50 seconds +#define TF_PB_DETONATE 55 // Demoman: Detonate Pipebombs +#define TF_MEDIC_AURA_TOGGLE 56 // Medic: Toggle Healing Aura on/off +#define TF_LOCKON 57 // HWGuy: Turn Assault Cannon fire on +#define TF_LOCKOFF 58 // HWGuy: Turn Assault Cannon fire off +#define TF_SPY_DIE 59 // Spy: Feign death +#define TF_SPY_SILENT_DIE 60 // Spy: Silent feign death +#define TF_SPY_SPY 61 // Spy: Bring up disguise menu +#define TF_DISGUISE_ENEMY 62 // Spy: Disguise as enemy team +#define TF_DISGUISE_LAST 63 // Spy: Use last disguise +#define TF_DISGUISE_RESET 64 // Spy: Reset disguise +#define TF_DISGUISE_SCOUT 65 // Spy: Disguise as Scout +#define TF_DISGUISE_SNIPER 66 // Spy: Disguise as Sniper +#define TF_DISGUISE_SOLDIER 67 // Spy: Disguise as Soldier +#define TF_DISGUISE_DEMOMAN 68 // Spy: Disguise as Demoman +#define TF_DISGUISE_MEDIC 69 // Spy: Disguise as Medic +#define TF_DISGUISE_HWGUY 70 // Spy: Disguise as HWGuy +#define TF_DISGUISE_PYRO 71 // Spy: Disguise as Pyro +#define TF_DISGUISE_ENGINEER 72 // Spy: Disguise as Engineer +#define TF_DISGUISE_BLUE 73 // Spy: Disguise as blue team +#define TF_DISGUISE_RED 74 // Spy: Disguise as red team +#define TF_DISGUISE_YELLOW 75 // Spy: Disguise as yellow team +#define TF_DISGUISE_GREEN 76 // Spy: Disguise as green team +#define TF_ENGINEER_BUILD 77 // Engineer: Bring up build menu for Engineer +#define TF_ENGINEER_DETDISP 78 // Engineer: Detonate dispenser for Engineer +#define TF_ENGINEER_DETSENTRY 79 // Engineer: Detonate sentry gun for Engineer +// unused 80 +// unused 81 +// unused 82 +// unused 83 +// unused 84 +// unused 85 +// unused 86 +// unused 87 +// unused 88 +// unused 89 +// unused 90 +// unused 91 +// unused 92 +// unused 93 +// unused 94 +// unused 95 +// unused 96 +// unused 97 +// unused 98 +// unused 99 +#define TF_CHANGETEAM 100 // Bring up team selection menu +#define TF_TEAM_1 101 // Join team 1 +#define TF_TEAM_2 102 // Join team 2 +#define TF_TEAM_3 103 // Join team 3 +#define TF_TEAM_4 104 // Join team 4 +#define TF_DISPLAYLOCATION 105 // Displays current location and angles (for developers) +#define TF_SHOWTF 106 // Displays server settings and mod version +#define TF_SHOWLEGALCLASSES 107 // Show what classes are allowed by current map +#define TF_SHOW_IDS 108 // Show ids of connected players +#define TF_ALIAS_CHECK 109 // Check if client has gotten all the aliases +#define TF_CHANGECLASS 110 // Bring up class selection menu +#define TF_CHANGEPC_SCOUT 111 // Change class to Scout +#define TF_CHANGEPC_SNIPER 112 // Change class to Sniper +#define TF_CHANGEPC_SOLDIER 113 // Change class to Soldier +#define TF_CHANGEPC_DEMOMAN 114 // Change class to Demoman +#define TF_CHANGEPC_MEDIC 115 // Change class to Medic +#define TF_CHANGEPC_HVYWEAP 116 // Change class to HWGuy +#define TF_CHANGEPC_PYRO 117 // Change class to Pyro +#define TF_CHANGEPC_SPY 118 // Change class to Spy +#define TF_CHANGEPC_ENGINEER 119 // Change class to Engineer +#define TF_CHANGEPC_RANDOM 120 // Change class to RandomPC +#define TF_HELP_MAP 121 // Displays current map objectives +#define TF_CLASSHELP 122 // Class help alias +#define TF_TEAM_CLASSES 123 // Display team classes +#define TF_TEAM_LIST 124 // Display the players in each team +#define TF_TEAM_SCORES 125 // Display team scores +#define TF_STATUS_QUERY 126 // Displays current team balance and equilization ratios +// unused 127 +// unused 128 +// unused 129 +#define TF_TOGGLEVOTE 130 // Toggle vote menu on/off +#define TF_VOTENEXT 131 // Vote to start voting for next map +#define TF_VOTETRICK 132 // Vote to start voting for a trick map +#define TF_VOTERACE 133 // Vote to start voting for a race map +#define TF_FORCENEXT 134 // Vote to force a change to voted map +// unused 135 +// unused 136 +// unused 137 +// unused 138 +// unused 139 +// unused 140 +// unused 141 +// unused 142 +// unused 143 +// unused 144 +// unused 145 +// unused 146 +// unused 147 +// unused 148 +// unused 149 +// unused 150 +// unused 151 +// unused 152 +// unused 153 +// unused 154 +// unused 155 +// unused 156 +// unused 157 +// unused 158 +// unused 159 +// unused 160 +// unused 161 +// unused 162 +// unused 163 +// unused 164 +// unused 165 +// unused 166 +// unused 167 +// unused 168 +// unused 169 +// unused 170 +// unused 171 +// unused 172 +// unused 173 +// unused 174 +// unused 175 +// unused 176 +// unused 177 +// unused 178 +// unused 179 +// unused 180 +// unused 181 +// unused 182 +// unused 183 +// unused 184 +// unused 185 +// unused 186 +// unused 187 +// unused 188 +// unused 189 +// unused 190 +// unused 191 +// unused 192 +// unused 193 +// unused 194 +// unused 195 +// unused 196 +// unused 197 +// unused 198 +// unused 199 +// unused 200 +// unused 201 +// unused 202 +// unused 203 +// unused 204 +// unused 205 +// unused 206 +// unused 207 +// unused 208 +// unused 209 +// unused 210 +// unused 211 +// unused 212 +// unused 213 +// unused 214 +// unused 215 +// unused 216 +// unused 217 +// unused 218 +// unused 219 +// unused 220 +// unused 221 +// unused 222 +// unused 223 +// unused 224 +// unused 225 +// unused 226 +// unused 227 +// unused 228 +// unused 229 +// unused 230 +// unused 231 +// unused 232 +// unused 233 +// unused 234 +// unused 235 +// unused 236 +// unused 237 +// unused 238 +// unused 239 +// unused 240 +// unused 241 +// unused 242 +// unused 243 +// unused 244 +// unused 245 +// unused 246 +// unused 247 +// unused 248 +// unused 249 +// unused 250 +// unused 251 +// unused 252 +// unused 253 +// unused 254 +// unused 255 /*======================================================*/ /* Colors */ diff --git a/tforthlp.qc b/tforthlp.qc index 50e0c0eb..2618dbe2 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -64,16 +64,16 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); TeamFortress_Alias("legalclasses", TF_SHOWLEGALCLASSES, 0); TeamFortress_Alias("classhelp", TF_CLASSHELP, 0); - TeamFortress_Alias("scout", TF_CHANGEPC + PC_SCOUT, 0); - TeamFortress_Alias("sniper", TF_CHANGEPC + PC_SNIPER, 0); - TeamFortress_Alias("soldier", TF_CHANGEPC + PC_SOLDIER, 0); - TeamFortress_Alias("demoman", TF_CHANGEPC + PC_DEMOMAN, 0); - TeamFortress_Alias("medic", TF_CHANGEPC + PC_MEDIC, 0); - TeamFortress_Alias("hwguy", TF_CHANGEPC + PC_HVYWEAP, 0); - TeamFortress_Alias("pyro", TF_CHANGEPC + PC_PYRO, 0); - TeamFortress_Alias("spy", TF_CHANGEPC + PC_SPY, 0); - TeamFortress_Alias("engineer", TF_CHANGEPC + PC_ENGINEER, 0); - TeamFortress_Alias("randompc", TF_CHANGEPC + PC_RANDOM, 0); + TeamFortress_Alias("scout", TF_CHANGEPC_SCOUT, 0); + TeamFortress_Alias("sniper", TF_CHANGEPC_SNIPER, 0); + TeamFortress_Alias("soldier", TF_CHANGEPC_SOLDIER, 0); + TeamFortress_Alias("demoman", TF_CHANGEPC_DEMOMAN, 0); + TeamFortress_Alias("medic", TF_CHANGEPC_MEDIC, 0); + TeamFortress_Alias("hwguy", TF_CHANGEPC_HVYWEAP, 0); + TeamFortress_Alias("pyro", TF_CHANGEPC_PYRO, 0); + TeamFortress_Alias("spy", TF_CHANGEPC_SPY, 0); + TeamFortress_Alias("engineer", TF_CHANGEPC_ENGINEER, 0); + TeamFortress_Alias("randompc", TF_CHANGEPC_RANDOM, 0); } else if (self.motd == 40) { TeamFortress_Alias("query", TF_STATUS_QUERY, 0); TeamFortress_Alias("inv", TF_INVENTORY, 0); diff --git a/weapons.qc b/weapons.qc index c47ee2d9..8b73fed7 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2467,8 +2467,8 @@ void () DeadImpulses = { Help_Show(); else if (self.impulse == TF_SHOWLEGALCLASSES) TeamFortress_DisplayLegalClasses(); - else if ((self.impulse > 100) && (self.impulse <= 110)) { - TeamFortress_ChangeClass(self.impulse - 100); + else if ((self.impulse >= TF_CHANGEPC_SCOUT) && (self.impulse <= TF_CHANGEPC_RANDOM)) { + TeamFortress_ChangeClass(self.impulse - TF_CHANGEPC_SCOUT + 1); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGETEAM) && (deathmatch == 3) && (cb_prematch_time < time)) { Menu_Team(0); From 247868a53a6906c6ba6120db2c22ae3356713f2a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 19:43:31 +0100 Subject: [PATCH 0359/2474] Add specific team selection aliases --- tforthlp.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tforthlp.qc b/tforthlp.qc index 2618dbe2..3d7fc799 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -60,6 +60,10 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("-slot4", "-attack;impulse 68"); } else if (self.motd == 30) { TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); + TeamFortress_Alias("teamblue", TF_TEAM_1, 0); + TeamFortress_Alias("teamred", TF_TEAM_2, 0); + TeamFortress_Alias("teamyellow", TF_TEAM_3, 0); + TeamFortress_Alias("teamgreen", TF_TEAM_4, 0); TeamFortress_Alias("changeclass", TF_CHANGECLASS, 0); TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); TeamFortress_Alias("legalclasses", TF_SHOWLEGALCLASSES, 0); From b073f1a15816852357bc624f005757bc04d76aad Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 22:46:22 +0100 Subject: [PATCH 0360/2474] Spy now falls to ground after having feigned on a player's head (fixes #236) --- spy.qc | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/spy.qc b/spy.qc index 4296ab80..a34e2d66 100644 --- a/spy.qc +++ b/spy.qc @@ -354,14 +354,14 @@ void () spy_upaxe9 =[41, spy_upaxe9] { }; float (entity pe_player) Spy_CheckArea = { - local entity at_spot = findradius(self.origin, 64); + local entity at_spot = findradius(pe_player.origin, 64); while (at_spot != world) { if (at_spot.mdl == "progs/detpack.mdl" || at_spot.mdl == "progs/turrbase.mdl" || at_spot.mdl == "progs/turrgun.mdl" || at_spot.mdl == "progs/disp.mdl") return 1; - else if (at_spot.classname == "player" && self != at_spot) { + else if (at_spot.classname == "player" && pe_player != at_spot) { if (!at_spot.is_feigning && at_spot.deadflag == 0) return 2; else if (at_spot.is_feigning) @@ -372,11 +372,40 @@ float (entity pe_player) Spy_CheckArea = { return 0; }; +void () CF_Spy_AirThink = { + local float area_check = 0; + + // only do stuff when spy is no longer moving + if (!self.owner.velocity) { + + // if spy is in the air, set movetype to walk (so he falls to ground) + if (!(self.owner.flags & FL_ONGROUND)) { + self.owner.movetype = MOVETYPE_WALK; + TeamFortress_SetSpeed(self.owner); + } + + // if spy is on ground and an entity is not nearby, set movetype to none (so he can't move) + else if (self.owner.flags & FL_ONGROUND) { + area_check = Spy_CheckArea(self.owner); + if (area_check == 0) { + self.owner.movetype = MOVETYPE_NONE; + self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self.owner); + dremove(self); + return; + } + } + + } + + self.nextthink = time + 0.1; +}; + void (float issilent) CF_Spy_FeignDeath = { local string deathstring; local float area_check; local float i; - local entity te; + local entity te, spy; if (self.is_feigning) { @@ -392,9 +421,6 @@ void (float issilent) CF_Spy_FeignDeath = { // set view height self.view_ofs = '0 0 22'; - // set movetype to walk - self.movetype = MOVETYPE_WALK; - // unset feign variables self.is_feigning = 0; self.feign_areachecked = 0; @@ -461,6 +487,15 @@ void (float issilent) CF_Spy_FeignDeath = { self.movetype = MOVETYPE_NONE; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); + } else { + // this timer starts when the spy is not on the ground + // e.g. resting on a player's head, and will make sure + // the spy falls to the ground when possible + spy = spawn(); + spy.classname = "airtimer"; + spy.owner = self; + spy.think = CF_Spy_AirThink; + spy.nextthink = time + 0.1; } // set spy feign variables From 1b74cf070592d6d8d4046d47a09983a400244b72 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 23:12:05 +0100 Subject: [PATCH 0361/2474] Allow building in water (closes #238) --- client.qc | 5 +++++ engineer.qc | 13 ++++++++++--- qw.qc | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index 24dc9643..def7d999 100644 --- a/client.qc +++ b/client.qc @@ -415,6 +415,9 @@ void () DecodeLevelParms = { // bigger dispenser explosions [on] disp_explosion = CF_GetSetting("de", "disp_explosion", "on"); + // allow building in water [on] + build_water = CF_GetSetting("bw", "build_water", "on"); + // allow assault cannon lock mechanism [on] cannon_lock = CF_GetSetting("cl", "cannon_lock", "on"); @@ -513,6 +516,7 @@ void () DecodeLevelParms = { old_railgun = FALSE; old_dispenser = FALSE; disp_explosion = TRUE; + build_water = TRUE; feign_air = TRUE; feign_pack = TRUE; feign_msg = TRUE; @@ -553,6 +557,7 @@ void () DecodeLevelParms = { old_railgun = TRUE; old_dispenser = TRUE; disp_explosion = FALSE; + build_water = FALSE; feign_air = FALSE; feign_pack = FALSE; feign_msg = FALSE; diff --git a/engineer.qc b/engineer.qc index bcdee982..960d6e14 100644 --- a/engineer.qc +++ b/engineer.qc @@ -370,9 +370,16 @@ void (float objtobuild) TeamFortress_Build = { dremove(newmis); return; } - if (!(self.flags & 512)) { - Status_Print(self, "\n\n\n\n\n\n\n", "You cannot build in the air"); - return; + if (!(self.flags & FL_ONGROUND)) { + if (!build_water && self.waterlevel) { + sprint(self, PRINT_HIGH, "You cannot build in the water\n"); + dremove(newmis); + return; + } else if (!self.waterlevel) { + sprint(self, PRINT_HIGH, "You cannot build in the air\n"); + dremove(newmis); + return; + } } self.is_building = 1; self.immune_to_check = time + 5; diff --git a/qw.qc b/qw.qc index 2c6515e1..65d25b5d 100644 --- a/qw.qc +++ b/qw.qc @@ -445,6 +445,7 @@ float old_medikit; float old_biodamage; float flame_knockback; float disp_explosion; +float build_water; float cannon_lock; float cannon_air; float cannon_move; From 620d0cbfb7ea922a086f2f75d7cfb6e98849102a Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 23:12:16 +0100 Subject: [PATCH 0362/2474] Remove some trailing spaces --- qw.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qw.qc b/qw.qc index 65d25b5d..e5895439 100644 --- a/qw.qc +++ b/qw.qc @@ -308,9 +308,9 @@ float coop; .float all_active; -.float item_list; // Used to keep track of which goalitems are +.float item_list; // Used to keep track of which goalitems are // affecting the player at any time. - // GoalItems use it to keep track of their own + // GoalItems use it to keep track of their own // mask to apply to a player's item_list float item_list_bit; // Global, used to determine what the bit of From caf0415fa8517a772485318b4ebf03a3ea8493d0 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 27 Oct 2014 23:25:47 +0100 Subject: [PATCH 0363/2474] Buildings no longer burn underwater (fixes #237) --- pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyro.qc b/pyro.qc index 77325e3e..0ebbd0c9 100644 --- a/pyro.qc +++ b/pyro.qc @@ -289,7 +289,7 @@ void () FlameFollow = { setmodel(self, self.model); } } - if (self.enemy.waterlevel > 1) { + if ((self.enemy.waterlevel > 1) || (self.enemy.classname != "player" && self.enemy.waterlevel > 0)) { sound(self, 2, "misc/vapeur2.wav", 1, 1); self.enemy.numflames = self.enemy.numflames - 1; FlameDestroy(self); From 225bd748990b3c433353c031d7d0d0eb6a10dcb5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 28 Oct 2014 12:10:40 +0100 Subject: [PATCH 0364/2474] Remove Spy AirTimer when Spy is dead (fixes #239) --- spy.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spy.qc b/spy.qc index a34e2d66..d9c17023 100644 --- a/spy.qc +++ b/spy.qc @@ -375,6 +375,9 @@ float (entity pe_player) Spy_CheckArea = { void () CF_Spy_AirThink = { local float area_check = 0; + if (self.owner.deadflag >= 2) + dremove(self); + // only do stuff when spy is no longer moving if (!self.owner.velocity) { From 01ed460934b3d73af13232a0de10e6ec3c6fef28 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 28 Oct 2014 12:29:20 +0100 Subject: [PATCH 0365/2474] Improve air feign code (fixes #236) --- spy.qc | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/spy.qc b/spy.qc index d9c17023..2bd085aa 100644 --- a/spy.qc +++ b/spy.qc @@ -375,30 +375,30 @@ float (entity pe_player) Spy_CheckArea = { void () CF_Spy_AirThink = { local float area_check = 0; - if (self.owner.deadflag >= 2) + if ((self.owner.deadflag >= 2) || (self.owner.playerclass != PC_SPY) || (!self.owner.is_feigning)) { dremove(self); + return; + } // only do stuff when spy is no longer moving if (!self.owner.velocity) { - // if spy is in the air, set movetype to walk (so he falls to ground) - if (!(self.owner.flags & FL_ONGROUND)) { - self.owner.movetype = MOVETYPE_WALK; - TeamFortress_SetSpeed(self.owner); - } - // if spy is on ground and an entity is not nearby, set movetype to none (so he can't move) - else if (self.owner.flags & FL_ONGROUND) { + if (self.owner.flags & FL_ONGROUND) { area_check = Spy_CheckArea(self.owner); if (area_check == 0) { self.owner.movetype = MOVETYPE_NONE; self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self.owner); - dremove(self); - return; } } + // if spy is in the air, set movetype to walk (so he falls to ground) + else { + self.owner.movetype = MOVETYPE_WALK; + } + + TeamFortress_SetSpeed(self.owner); + } self.nextthink = time + 0.1; @@ -485,21 +485,13 @@ void (float issilent) CF_Spy_FeignDeath = { // set movetype to toss self.movetype = MOVETYPE_TOSS; - // stop spy from moving if on the ground - if (self.flags & FL_ONGROUND) { - self.movetype = MOVETYPE_NONE; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - } else { - // this timer starts when the spy is not on the ground - // e.g. resting on a player's head, and will make sure - // the spy falls to the ground when possible - spy = spawn(); - spy.classname = "airtimer"; - spy.owner = self; - spy.think = CF_Spy_AirThink; - spy.nextthink = time + 0.1; - } + // this timer will make sure the spy falls + // to the ground when possible + spy = spawn(); + spy.classname = "airtimer"; + spy.owner = self; + spy.think = CF_Spy_AirThink; + spy.nextthink = time + 0.1; // set spy feign variables self.is_feigning = 1; From 9efe65ed545b50ac224566d617f85fb3aa3afbbb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 28 Oct 2014 13:33:45 +0100 Subject: [PATCH 0366/2474] Knockback from Flamethrower now relates to Pyro view angle instead of flame balls --- pyro.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyro.qc b/pyro.qc index 0ebbd0c9..c689a73a 100644 --- a/pyro.qc +++ b/pyro.qc @@ -427,9 +427,8 @@ void () Flamer_stream_touch = { if (flame_knockback) { // knockback target if (other.classname != "building_sentrygun" && other.classname != "building_dispenser") { - dir = other.origin - (self.absmin + self.absmax) * 0.5; - dir = normalize(dir); - other.velocity = other.velocity + dir * 300; + makevectors(self.owner.angles); + other.velocity = other.velocity + v_forward * 300; } } From caff7b3a3ed70f694ee8a6ff758c250f7f4f23d2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 30 Oct 2014 20:38:40 +0100 Subject: [PATCH 0367/2474] Make Flamethrower knockback tied to flameball velocity vector (fixes #240) --- pyro.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyro.qc b/pyro.qc index c689a73a..336b001c 100644 --- a/pyro.qc +++ b/pyro.qc @@ -427,8 +427,7 @@ void () Flamer_stream_touch = { if (flame_knockback) { // knockback target if (other.classname != "building_sentrygun" && other.classname != "building_dispenser") { - makevectors(self.owner.angles); - other.velocity = other.velocity + v_forward * 300; + other.velocity = other.velocity + self.velocity / 2; } } From d9e1eaaee9a02c170dd71bd661d0ad6e888fec11 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 30 Oct 2014 23:42:50 +0100 Subject: [PATCH 0368/2474] Make flag model hover above ground --- tfortmap.qc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 470200c5..c028a4a3 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -172,12 +172,14 @@ void (entity Goal) UpdateAbbreviations = || (Goal.mdl == "progs/w_s_key.mdl")) { Goal.mdl = "progs/tf_flag.mdl"; + Goal.origin_z = Goal.origin_z + 6; Goal.skin = 1; } else if ((Goal.mdl == "progs/b_g_key.mdl") || (Goal.mdl == "progs/m_g_key.mdl") || (Goal.mdl == "progs/w_g_key.mdl")) { Goal.mdl = "progs/tf_flag.mdl"; + Goal.origin_z = Goal.origin_z + 6; Goal.skin = 2; } } @@ -2343,8 +2345,10 @@ void () item_flag_team2 = { if (toggleflags & TFLAG_WARSTANDARD) self.mdl = "progs/tf_stan.mdl"; - else + else { self.mdl = "progs/tf_flag.mdl"; + self.origin_z = self.origin_z + 6; + } self.skin = 0; setmodel(self, self.mdl); @@ -2418,8 +2422,10 @@ void () item_flag_team1 = { if (toggleflags & TFLAG_WARSTANDARD) self.mdl = "progs/tf_stan.mdl"; - else + else { self.mdl = "progs/tf_flag.mdl"; + self.origin_z = self.origin_z + 6; + } setmodel(self, self.mdl); self.skin = 1; From dabee300dc0ec318a5684fe3ee75888470b0db29 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 30 Oct 2014 23:57:29 +0100 Subject: [PATCH 0369/2474] Rudimentary flag on back support (will need revision) --- tfortmap.qc | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index c028a4a3..d696fd3a 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1825,8 +1825,26 @@ void () tfgoal_timer_tick = { } }; +void () CF_FlagFollowPlayer = { + if ((self.owner.goal_state == 1) && (self.real_owner.items & (IT_KEY1 | IT_KEY2))) { + makevectors(self.real_owner.angles); + self.owner.origin = self.real_owner.origin - v_forward * 20 - v_right * 5 + v_up * 10; + self.owner.angles = self.real_owner.angles + '0 0 16'; + if (self.owner.mdl == "progs/tf_flag.mdl") { + self.owner.origin_z = self.owner.origin_z + 6; + } else { + self.owner.origin_z = self.owner.origin_z - 6; + } + setorigin(self.owner, self.owner.origin); + setmodel(self.owner, self.owner.mdl); + self.nextthink = time + 0.1; + } else { + dremove(self); + } +}; + void () item_tfgoal_touch = { - local entity te; + local entity te, flw; if (other.classname != "player") return; @@ -1844,6 +1862,12 @@ void () item_tfgoal_touch = { if (trace_fraction < 1) return; + flw = spawn(); + flw.real_owner = other; + flw.owner = self; + flw.think = CF_FlagFollowPlayer; + flw.nextthink = time + 0.1; + if (CTF_Map == 1) { if (self.goal_no == 1) { if (self.origin != self.oldorigin) { From acd22b3bcebbf1623a84168836035fd8de5fe590 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 2 Nov 2014 06:57:59 +0100 Subject: [PATCH 0370/2474] Fix grenade impulses in weapons.qc (fixes #241) --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 8b73fed7..e793792e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2716,7 +2716,7 @@ void () W_WeaponFrame = { } // class specials and grenade impulses always possible - if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= 150 && self.impulse <= 155)) { + if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= TF_GRENADE_1 && self.impulse <= TF_GRENADE_SWITCH)) { ImpulseCommands(); return; } From 792de9608212e59640a9e52e2c91524c26a6cf9b Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 6 Nov 2014 20:00:29 +0100 Subject: [PATCH 0371/2474] Fix impulses in aliases (fixes #243) --- tforthlp.qc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tforthlp.qc b/tforthlp.qc index 3d7fc799..a03560ee 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -46,18 +46,18 @@ void () TeamFortress_MOTD = { } TeamFortress_Alias("menu", TF_CLASSMENU, 0); - TeamFortress_Alias("slot1", 1, 0); - TeamFortress_Alias("slot2", 2, 0); - TeamFortress_Alias("slot3", 3, 0); - TeamFortress_Alias("slot4", 4, 0); - TeamFortress_AliasString("+slot1", "impulse 31;+attack"); - TeamFortress_AliasString("-slot1", "-attack;impulse 68"); - TeamFortress_AliasString("+slot2", "impulse 32;+attack"); - TeamFortress_AliasString("-slot2", "-attack;impulse 68"); - TeamFortress_AliasString("+slot3", "impulse 33;+attack"); - TeamFortress_AliasString("-slot3", "-attack;impulse 68"); - TeamFortress_AliasString("+slot4", "impulse 34;+attack"); - TeamFortress_AliasString("-slot4", "-attack;impulse 68"); + TeamFortress_Alias("slot1", TF_SLOT1, 0); + TeamFortress_Alias("slot2", TF_SLOT2, 0); + TeamFortress_Alias("slot3", TF_SLOT3, 0); + TeamFortress_Alias("slot4", TF_SLOT4, 0); + TeamFortress_AliasString("+slot1", "impulse 20;+attack"); + TeamFortress_AliasString("-slot1", "-attack;impulse 24"); + TeamFortress_AliasString("+slot2", "impulse 21;+attack"); + TeamFortress_AliasString("-slot2", "-attack;impulse 24"); + TeamFortress_AliasString("+slot3", "impulse 22;+attack"); + TeamFortress_AliasString("-slot3", "-attack;impulse 24"); + TeamFortress_AliasString("+slot4", "impulse 23;+attack"); + TeamFortress_AliasString("-slot4", "-attack;impulse 24"); } else if (self.motd == 30) { TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); TeamFortress_Alias("teamblue", TF_TEAM_1, 0); From 37d4931a3021aab6e3501d19815f2de3fea30f64 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 5 Dec 2014 14:18:47 +0100 Subject: [PATCH 0372/2474] Drop ammo when no discard ammo left (closes #247) --- actions.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/actions.qc b/actions.qc index 6ab17aff..09ada00e 100644 --- a/actions.qc +++ b/actions.qc @@ -28,10 +28,9 @@ void () TeamFortress_Discard = { if (self.playerclass == PC_MEDIC && !medicaura && old_medikit) newmis.ammo_cells = self.ammo_cells; - if (! - (((newmis.ammo_shells + newmis.ammo_nails) + newmis.ammo_rockets) + - newmis.ammo_cells)) { + if (!(newmis.ammo_shells + newmis.ammo_nails + newmis.ammo_rockets + newmis.ammo_cells)) { dremove(newmis); + Menu_Drop(); return; } if (newmis.ammo_shells) { From 7ba8a8c5a18e2d26c8122ba94610bd0fe380bacc Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 5 Dec 2014 14:19:29 +0100 Subject: [PATCH 0373/2474] Improve drop ammo menu. --- menu.qc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/menu.qc b/menu.qc index 802793f1..816b6f28 100644 --- a/menu.qc +++ b/menu.qc @@ -366,6 +366,20 @@ void () Menu_Drop = { local string s_cells = "–‘ Cells \n"; local string s_nothing = "\n—‘ Nothing"; + if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) { + sprint(self, PRINT_HIGH, "Not enough ammo\n"); + return; + } + + if (!self.ammo_shells) + s_shells = "\n"; + if (!self.ammo_nails) + s_nails = "\n"; + if (!self.ammo_rockets) + s_rockets = "\n"; + if (!self.ammo_cells) + s_cells = "\n"; + self.menu_input = nil; if (self.playerclass == PC_ENGINEER) s_drop = "Drop or make:\n\n"; From 2c24f162ef8ebb3a0a1341d80276e9bf09591572 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 14 Feb 2015 09:21:02 +0100 Subject: [PATCH 0374/2474] Set last weaponslot to secondary when joining (closes #248) --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 065d47c2..3d7cfb78 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1551,7 +1551,7 @@ void () TeamFortress_SetEquipment = { self.weaponmode = 0; self.last_weaponmode = 0; self.current_weaponslot = 1; - self.last_weaponslot = 1; + self.last_weaponslot = 2; W_WeaponState_Save(self); } From 9a3109ace84d35cf4273fcd846203e5efd0fd2cc Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 24 Mar 2015 16:28:57 +0100 Subject: [PATCH 0375/2474] Make pipebomb launcher, tranquilizer, flamethrower and incendiary cannon separate models (closes #38). --- weapons.qc | 16 +++++++++++----- world.qc | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/weapons.qc b/weapons.qc index e793792e..1838cdde 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1492,7 +1492,10 @@ void (entity pl) W_SetCurrentAmmo = { } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_rock.mdl"; + if (pl.weaponmode == 0) + pl.weaponmodel = "progs/v_rock.mdl"; + else + pl.weaponmodel = "progs/v_pipe.mdl"; pl.weaponframe = 0; } pl.weapon = IT_GRENADE_LAUNCHER; @@ -1532,7 +1535,7 @@ void (entity pl) W_SetCurrentAmmo = { } else if (pl.current_weapon == WEAP_FLAMETHROWER) { pl.currentammo = pl.ammo_cells; if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_rock.mdl"; + pl.weaponmodel = "progs/v_flame.mdl"; pl.weaponframe = 0; } pl.items = pl.items | IT_CELLS; @@ -1540,7 +1543,7 @@ void (entity pl) W_SetCurrentAmmo = { } else if (pl.current_weapon == WEAP_INCENDIARY) { pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_rock2.mdl"; + pl.weaponmodel = "progs/v_irock.mdl"; pl.weaponframe = 0; } pl.items = pl.items | IT_ROCKETS; @@ -1556,7 +1559,7 @@ void (entity pl) W_SetCurrentAmmo = { } else if (pl.current_weapon == WEAP_TRANQ) { pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_shot.mdl"; + pl.weaponmodel = "progs/v_tranq.mdl"; pl.weaponframe = 0; } pl.items = pl.items | IT_SHELLS; @@ -1688,7 +1691,10 @@ void () W_Reload_sniper_rifle = { void () W_Reload_grenade_launcher = { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_rock.mdl"; + if (self.owner.weaponmode == 0) + self.owner.weaponmodel = "progs/v_rock.mdl"; + else + self.owner.weaponmodel = "progs/v_pipe.mdl"; sprint(self.owner, PRINT_LOW, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); diff --git a/world.qc b/world.qc index 10f2d217..ca499767 100644 --- a/world.qc +++ b/world.qc @@ -227,9 +227,13 @@ void () worldspawn = { precache_model("progs/s_bubble.spr"); precache_model("progs/s_explod.spr"); precache_model("progs/v_axe.mdl"); + precache_model("progs/v_tranq.mdl"); precache_model("progs/v_shot.mdl"); precache_model("progs/v_nail.mdl"); precache_model("progs/v_rock.mdl"); + precache_model("progs/v_pipe.mdl"); + precache_model("progs/v_flame.mdl"); + precache_model("progs/v_irock.mdl"); precache_model("progs/v_shot2.mdl"); precache_model("progs/v_nail2.mdl"); precache_model("progs/v_rock2.mdl"); From 90a20e75e0d3563f6dd7e28af06411f1ab69e27e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 24 Mar 2015 18:45:01 +0100 Subject: [PATCH 0376/2474] Fix flag slanting bug (closes #245). --- tfortmap.qc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index d696fd3a..ea19a88b 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1828,8 +1828,8 @@ void () tfgoal_timer_tick = { void () CF_FlagFollowPlayer = { if ((self.owner.goal_state == 1) && (self.real_owner.items & (IT_KEY1 | IT_KEY2))) { makevectors(self.real_owner.angles); - self.owner.origin = self.real_owner.origin - v_forward * 20 - v_right * 5 + v_up * 10; - self.owner.angles = self.real_owner.angles + '0 0 16'; + self.owner.origin = self.real_owner.origin - v_forward * 25 - v_right * 0 + v_up * 10; + self.owner.angles = self.real_owner.angles + '0 90 16'; if (self.owner.mdl == "progs/tf_flag.mdl") { self.owner.origin_z = self.owner.origin_z + 6; } else { @@ -2609,10 +2609,13 @@ void () DropGoalItems = { while (te) { if (te.owner == self) { if (old_dropflag) { - if (te.goal_activation & 4096) + if (te.goal_activation & 4096) { + te.angles = '0 0 0'; tfgoalitem_RemoveFromPlayer(te, self, 2); + } } else if (self.effects & EF_DIMLIGHT) { + te.angles = '0 0 0'; tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); if (self.team_no == 1) From eac824742de2e307ae4a160f989b72f8e087c3fb Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 24 Mar 2015 19:03:02 +0100 Subject: [PATCH 0377/2474] Flag no longer slants when dropped upon death. --- tfortmap.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index ea19a88b..58f9f822 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2041,6 +2041,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { } tfgoalitem_RemoveEffectsFromPlayer(Item, AP); + Item.angles = '0 0 0'; te = find(world, classname, "player"); while (te != world) { @@ -2610,7 +2611,6 @@ void () DropGoalItems = { if (te.owner == self) { if (old_dropflag) { if (te.goal_activation & 4096) { - te.angles = '0 0 0'; tfgoalitem_RemoveFromPlayer(te, self, 2); } } From e092045837fafbb0c07726f523dc3e1275ac35a1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 24 Mar 2015 19:58:42 +0100 Subject: [PATCH 0378/2474] Drop flag when spy feigns. --- menu.qc | 3 +++ spy.qc | 16 ++++++++-------- tfortmap.qc | 3 +-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/menu.qc b/menu.qc index 816b6f28..7c4fc704 100644 --- a/menu.qc +++ b/menu.qc @@ -528,6 +528,9 @@ void (float inp) Menu_Spy_Skin_Input = { }; void () Menu_Spy_Skin = { + if (self.is_unabletospy == 1) + return; + local string s_disguise = "Disguise as enemy:\n\n"; local string s_scout = "“‘ Scout \n"; local string s_sniper = "”‘ Sniper \n"; diff --git a/spy.qc b/spy.qc index 2bd085aa..1688c31f 100644 --- a/spy.qc +++ b/spy.qc @@ -457,8 +457,8 @@ void (float issilent) CF_Spy_FeignDeath = { } } else { - // don't feign if not allowed or spam timer is active - if (self.is_unabletospy == 1 || time < self.antispam_feign) { + // don't feign spam timer is active + if (time < self.antispam_feign) { sprint(self, PRINT_HIGH, "You cannot feign right now\n"); return; } @@ -533,12 +533,6 @@ void (float issilent) CF_Spy_FeignDeath = { self.maxspeed = 0; } - // die with axe equipped if carrying axe, medikit or spanner - if (self.weapon <= WEAP_AXE) { - spy_die_ax1(); - return; - } - // drop flag if spy is carrying it te = find(world, classname, "item_tfgoal"); while (te) { @@ -555,6 +549,12 @@ void (float issilent) CF_Spy_FeignDeath = { te = find(te, classname, "item_tfgoal"); } + // die with axe equipped if carrying axe, medikit or spanner + if (self.weapon <= WEAP_AXE) { + spy_die_ax1(); + return; + } + // randomize death animation i = 1 + floor((random() * 6)); if (i == 1) diff --git a/tfortmap.qc b/tfortmap.qc index 58f9f822..c974d37a 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1974,8 +1974,7 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { return; } } - if ((AP.playerclass == PC_SPY) && - (Item.goal_result & TFGR_REMOVE_DISGUISE)) { + if ((AP.playerclass == PC_SPY) && (Item.goal_result & TFGR_REMOVE_DISGUISE)) { AP.is_unabletospy = 1; AP.disguise_skin = 0; AP.disguise_team = 0; From 7087951eb8ff842365c4d62c5e5c5b1acb360415 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Tue, 24 Mar 2015 22:51:08 +0100 Subject: [PATCH 0379/2474] Don't allow buildings to be placed on top of entities like elevators (closes #200). --- engineer.qc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/engineer.qc b/engineer.qc index 960d6e14..9c2ab320 100644 --- a/engineer.qc +++ b/engineer.qc @@ -339,6 +339,14 @@ void (float objtobuild) TeamFortress_Build = { tmp1 = '0 0 0'; tmp2 = '0 0 0'; + tmp1 = self.origin + normalize(v_forward) * 64; + tmp2 = self.origin + normalize(v_forward) * 64 - normalize(v_up) * 128; + traceline(tmp1, tmp2, 1, world); + if (trace_ent != world) { + sprint(self, PRINT_HIGH, "You cannot build here\n"); + return; + } + newmis = spawn(); makevectors(self.v_angle); v_forward_z = 0; From 934ed944f384efa3854b1f85c6b38bd30391369e Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Wed, 25 Mar 2015 00:16:32 +0100 Subject: [PATCH 0380/2474] Improve error check for Engineer buildings (closes #249). --- engineer.qc | 73 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/engineer.qc b/engineer.qc index 9c2ab320..15042a5c 100644 --- a/engineer.qc +++ b/engineer.qc @@ -17,6 +17,7 @@ void (entity disp) Engineer_SentryGun_InsertAmmo; void (entity disp) Engineer_SentryGun_Upgrade; void (entity disp) Engineer_SentryGun_Repair; void () Menu_Engineer_Cancel; +void () CF_CheckBuilding; float (entity obj, entity builder) CheckArea; void () LaserBolt_Think = { @@ -254,14 +255,26 @@ void () TeamFortress_EngineerBuild = { void () TeamFortress_EngineerBuildStop = { local entity te; + local vector dist; - sprint(self, PRINT_HIGH, "You stop building\n"); self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_WALK; TeamFortress_SetSpeed(self); te = find(world, netname, "build_timer"); while (te) { if (te.owner == self) { + dist = self.origin - te.origin; + if (vlen(dist) > 128) { + sprint(self, PRINT_HIGH, "Your building disappeared\n"); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, te.origin_x); + WriteCoord(MSG_MULTICAST, te.origin_y); + WriteCoord(MSG_MULTICAST, te.origin_z); + multicast(te.origin, MULTICAST_PHS); + } else { + sprint(self, PRINT_HIGH, "You stop building\n"); + } dremove(te); te = world; } else { @@ -335,26 +348,39 @@ void (float objtobuild) TeamFortress_Build = { local float btime; local vector tmp1; local vector tmp2; + local entity oldmis; btime = 0; tmp1 = '0 0 0'; tmp2 = '0 0 0'; - tmp1 = self.origin + normalize(v_forward) * 64; - tmp2 = self.origin + normalize(v_forward) * 64 - normalize(v_up) * 128; + newmis = spawn(); + makevectors(self.v_angle); + v_forward_z = 0; + v_forward = normalize(v_forward) * 64; + newmis.origin = self.origin + v_forward; + + tmp1 = newmis.origin; + tmp2 = newmis.origin - normalize(v_up) * 128; traceline(tmp1, tmp2, 1, world); if (trace_ent != world) { sprint(self, PRINT_HIGH, "You cannot build here\n"); + dremove(newmis); + return; + } + + tmp1 = self.origin; + tmp2 = self.origin - normalize(v_up) * 128; + traceline(tmp1, tmp2, 1, world); + if (trace_ent != world) { + sprint(self, PRINT_HIGH, "You can only build while standing on solid ground\n"); + dremove(newmis); return; } - newmis = spawn(); - makevectors(self.v_angle); - v_forward_z = 0; - v_forward = normalize(v_forward) * 64; - newmis.origin = self.origin + v_forward; if (objtobuild == 1) { if (self.has_dispenser) { sprint(self, PRINT_HIGH, "You can only have one dispenser\n"); + dremove(newmis); return; } tmp1 = '-16 -16 0'; @@ -365,6 +391,7 @@ void (float objtobuild) TeamFortress_Build = { } else if (objtobuild == 2) { if (self.has_sentry) { sprint(self, PRINT_HIGH, "You can only have one sentry gun\n"); + dremove(newmis); return; } tmp1 = '-16 -16 0'; @@ -416,6 +443,36 @@ void (float objtobuild) TeamFortress_Build = { setsize(newmis, tmp1, tmp2); setorigin(newmis, newmis.origin); newmis.flags = newmis.flags - (newmis.flags & 512); + + oldmis = newmis; + newmis = spawn(); + newmis.owner = self; + newmis.enemy = oldmis; + newmis.classname = "timer"; + newmis.netname = "buildcheck_timer"; + newmis.nextthink = time + 0.3; + newmis.think = CF_CheckBuilding; +}; + +void () CF_CheckBuilding = { + local vector dist; + local entity timer = self; + local entity building = self.enemy; + self = self.owner; + + if (self.is_building == 0) { + dremove(timer); + return; + } + + dist = self.origin - building.origin; + if (vlen(dist) > 128) { + TeamFortress_EngineerBuildStop(); + dremove(timer); + return; + } + + timer.nextthink = time + 0.3; }; void (entity bld) CheckBelowBuilding = { From db784888167932ed5175b85c9571d97be6217af2 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 27 Mar 2015 00:20:47 +0100 Subject: [PATCH 0381/2474] Add class tips (closes #244). --- client.qc | 7 + defs.h | 2 +- qw.qc | 4 + status.qc | 479 +++++++++++++++++++++++++++++++++++++++++++++++++++- tfort.qc | 2 + tforthlp.qc | 1 + weapons.qc | 7 + 7 files changed, 498 insertions(+), 4 deletions(-) diff --git a/client.qc b/client.qc index def7d999..c70f178c 100644 --- a/client.qc +++ b/client.qc @@ -466,6 +466,9 @@ void () DecodeLevelParms = { // stock full ammo/armor [on] stockfull = CF_GetSetting("stf", "stockfull", "on"); + // display class tips [on] + classtips = CF_GetSetting("ct", "classtips", "on"); + // delay respawning by this many seconds [0] respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (respawn_delay_time) { @@ -522,6 +525,7 @@ void () DecodeLevelParms = { feign_msg = TRUE; spawnfull = FALSE; stockfull = TRUE; + classtips = TRUE; } st = infokey(world, "faithful"); @@ -563,6 +567,7 @@ void () DecodeLevelParms = { feign_msg = FALSE; spawnfull = FALSE; stockfull = FALSE; + classtips = FALSE; } } @@ -1139,6 +1144,8 @@ void () PutClientInServer = { self.vote_close = 0; self.has_throwngren = FALSE; self.saveme_time = 0; + self.display_tip = 0; + self.tip_type = 0; self.reload_shotgun = 0; self.reload_super_shotgun = 0; diff --git a/defs.h b/defs.h index 6e0206ed..856c492e 100644 --- a/defs.h +++ b/defs.h @@ -449,7 +449,7 @@ #define TF_TEAM_LIST 124 // Display the players in each team #define TF_TEAM_SCORES 125 // Display team scores #define TF_STATUS_QUERY 126 // Displays current team balance and equilization ratios -// unused 127 +#define TF_NEXTTIP 127 // Shows the next general/class tip // unused 128 // unused 129 #define TF_TOGGLEVOTE 130 // Toggle vote menu on/off diff --git a/qw.qc b/qw.qc index e5895439..ccafb6d1 100644 --- a/qw.qc +++ b/qw.qc @@ -46,6 +46,9 @@ typedef void (float) f_void_float; .float has_voted_map; // Map option that player voted for .float spawn_time; // Time when player spawned .float menu_time; // Time when vote map menu was first issued +.float display_tip; // Last class tip displayed +.float tip_type; // Whether the tip displayed is a general tip (1) or class tip (2) +.float tip_time; // Time when players last requested to see a tip .float vote_next; // TRUE if player has voted for a map vote .float vote_trick; // TRUE if player has voted for a trick map vote .float vote_race; // TRUE if player has voted for a race map vote @@ -459,6 +462,7 @@ float scoutdash; float sniperreload; float spawnfull; float stockfull; +float classtips; float server_default; float server_faithful; diff --git a/status.qc b/status.qc index 021c3618..efb92a8f 100644 --- a/status.qc +++ b/status.qc @@ -18,6 +18,470 @@ string(entity pl) DisguiseToString; string(entity pl) SentryDetailsToString; string(float pc) TeamFortress_GetClassName; +string (float class) CF_GetRandomClassTip { + local string tiptype = ""; + local string line1 = ""; + local string line2 = ""; + local string line3 = ""; + local string result = ""; + local float showtips; + local float rand; + + if (!self.tip_type) { + rand = random(); + if (rand >= 0.8) + self.tip_type = 1; + else + self.tip_type = 2; + } + + if (self.tip_type == 1) { + // general tip + tiptype = "Ηεξεςαμ τιπ:\n"; + + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 14); + if (self.display_tip == 1) { + line1 = "Team work is the key to victory."; + } else if (self.display_tip == 2) { + line1 = "Bunny hopping is easy to learn but hard"; + line2 = "to master. It is vital for success."; + } else if (self.display_tip == 3) { + line1 = "Have a grenade (mouse2 & f) ready to"; + line2 = "throw before entering combat. Timing is"; + line3 = "key."; + } else if (self.display_tip == 4) { + line1 = "Jump as a hand grenade (mouse2) explodes"; + line2 = "in your hand to perform a grenade jump."; + } else if (self.display_tip == 5) { + line1 = "Reload your current weapon (r) and"; + line2 = "secondary weapons (g) whenever you get"; + line3 = "the chance."; + } else if (self.display_tip == 6) { + line1 = "Swing your melee weapon (4) to show your"; + line2 = "teammates that you're not a spy."; + } else if (self.display_tip == 7) { + line1 = "Kill the enemy demolitions man to"; + line2 = "destroy his pipe trap."; + } else if (self.display_tip == 8) { + line1 = "Discard (x) unneeded ammo to reduce the"; + line2 = "damage taken from EMP grenades."; + } else if (self.display_tip == 9) { + line1 = "Call your medic (v) for health or your"; + line2 = "engineer for armor."; + } else if (self.display_tip == 10) { + line1 = "Learn your class special (e) and class"; + line2 = "menu (5)."; + } else if (self.display_tip == 11) { + line1 = "Type /classhelp in the console at any"; + line2 = "time to get help with your class."; + } else if (self.display_tip == 12) { + line1 = "Throw the flag (z) to teammates or a"; + line2 = "better position."; + } else if (self.display_tip == 13) { + line1 = "When your flag is about to get captured,"; + line2 = "reset your defence to stop chain"; + line3 = "captures."; + } else if (self.display_tip == 14) { + line1 = "Throw the flag (c) to give it to a team"; + line2 = "mate or gain valuable meters before"; + line3 = "you're fragged."; + } + } + } else { + // class tip + tiptype = "Γμασσ Τιπ:\n"; + + if (class == PC_SCOUT) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 19); + if (self.display_tip == 1) { + line1 = "The scout is an excellent attacking"; + line2 = "class due to his speed and"; + line3 = "manoeuvrability."; + } else if (self.display_tip == 2) { + line1 = "Expose enemy spies by touching them."; + } else if (self.display_tip == 3) { + line1 = "Disarm detpacks by standing on them."; + } else if (self.display_tip == 4) { + line1 = "With its faster rate of fire, and"; + line2 = "greater accuracy, the shotgun (2)"; + line3 = "is more useful over long distances."; + } else if (self.display_tip == 5) { + line1 = "Drop caltrops (mouse2) to slow the"; + line2 = "enemy down."; + } else if (self.display_tip == 6) { + line1 = "The caltrop canister's (mouse2) slowing"; + line2 = "effect can be reversed by a medic or by"; + line3 = "picking up health."; + } else if (self.display_tip == 7) { + line1 = "Use concussion grenades (f) to blast"; + line2 = "enemies away from you and to slow them"; + line3 = "down."; + } else if (self.display_tip == 8) { + line1 = "The concussion grenade (f) effect is"; + line2 = "active for up to 19 seconds."; + } else if (self.display_tip == 9) { + line1 = "The concussion grenade (f) blast"; + line2 = "effect is stronger toward the outside"; + line3 = "of its blast radius."; + } else if (self.display_tip == 10) { + line1 = "Concussion grenade (f) blasts will"; + line2 = "penetrate walls. Use this to your"; + line3 = "advantage."; + } else if (self.display_tip == 11) { + line1 = "The medic recovers from concussion"; + line2 = "grenade (f) effect twice as fast as"; + line3 = "other classes."; + } else if (self.display_tip == 12) { + line1 = "Throw a concussion grenade (f) then"; + line2 = "position yourself for the perfect"; + line3 = "concussion grenade jump."; + } else if (self.display_tip == 13) { + line1 = "Concussion grenade (f) jumps can be"; + line2 = "chained for great distances."; + } else if (self.display_tip == 14) { + if (scoutdash) { + line1 = "The scout can perform a speed jump (e)."; + line2 = "This is great for initiating a bunny"; + line3 = "hop."; + } else { + self.display_tip = 0; + } + } else if (self.display_tip == 15) { + if (scoutdash) { + line1 = "To maintain the speed from dash (e), use"; + line2 = "strafe buttons and keep jumping."; + } else { + self.display_tip = 0; + } + } else if (self.display_tip == 16) { + line1 = "The scanner (5) can reveal the"; + line2 = "location of other players and the flag."; + } else if (self.display_tip == 17) { + line1 = "Use the scanner menu (5) to choose from"; + line2 = "which team to scan for players."; + } else if (self.display_tip == 18) { + line1 = "The scanner (5) can detect items and"; + line2 = "players through walls."; + } else if (self.display_tip == 19) { + line1 = "The scanner (5) consumes 2 cells every"; + line2 = "other second while active."; + } + } + } else if (class == PC_SNIPER) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 9); + if (self.display_tip == 1) { + line1 = "Position yourself strategically so you"; + line2 = "can easily take cover from incoming"; + line3 = "fire."; + } else if (self.display_tip == 2) { + line1 = "The sniper rifle (1) does more damage"; + line2 = "the longer you hold down fire (mouse1)."; + } else if (self.display_tip == 3) { + line1 = "Use full auto mode sniper rifle (2) to"; + line2 = "pick off a weak enemy."; + } else if (self.display_tip == 4) { + line1 = "Head shots with the sniper rifle (1)"; + line2 = "deal double damage."; + } else if (self.display_tip == 5) { + line1 = "Leg shots with the sniper rifle (1)"; + line2 = "slow your enemy."; + } else if (self.display_tip == 6) { + line1 = "Throw flares (f) to illuminate a dark"; + line2 = "area."; + } else if (self.display_tip == 7) { + line1 = "Zoom in (e) to get a better view of"; + line2 = "your enemies."; + } else if (self.display_tip == 8) { + line1 = "Use the mouse wheel to adjust zoom"; + line2 = "while zoomed in."; + } else if (self.display_tip == 9) { + line1 = "Your mouse sensitivity will"; + line2 = "automatically adjust to your zoom level."; + } + } + } else if (class == PC_SOLDIER) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 7); + if (self.display_tip == 1) { + line1 = "Use cover to take out a sentry gun with"; + line2 = "your rockets from distance."; + } else if (self.display_tip == 2) { + line1 = "Add a rocket jump to your grenade jump"; + line2 = "for even more distance and speed."; + } else if (self.display_tip == 3) { + line1 = "Rocket jump off surfaces for a big"; + line2 = "bunny hopping boost."; + } else if (self.display_tip == 4) { + line1 = "With its faster rate of fire, and"; + line2 = "greater accuracy, the shotgun (3) is"; + line3 = "more useful over long distances."; + } else if (self.display_tip == 5) { + line1 = "Use the super shotgun (2) to slow an"; + line2 = "incoming enemy and the rocket launcher"; + line3 = "to finish them off."; + } else if (self.display_tip == 6) { + line1 = "Use the super shotgun (2) at very close"; + line2 = "range to avoid splash damage."; + } else if (self.display_tip == 7) { + line1 = "Use a nail grenade (f) to clear a small"; + line2 = "room or block a bottle neck."; + } + } + } else if (class == PC_DEMOMAN) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 6); + if (self.display_tip == 1) { + line1 = "When your flag is out, cover it in pipe"; + line2 = "grenades (2). Detonate (e) before the"; + line3 = "enemy touches it."; + } else if (self.display_tip == 2) { + line1 = "Your grenade launcher (1) and pipe"; + line2 = "launcher (2) share a clip. Reload (r)"; + line3 = "often."; + } else if (self.display_tip == 3) { + line1 = "Lay your pipe grenades (2) in a"; + line2 = "bottleneck and keep out of the way."; + line3 = "Detonate them with (e)."; + } else if (self.display_tip == 4) { + line1 = "With its faster rate of fire, and"; + line2 = "greater accuracy, the shotgun (3) is"; + line3 = "more useful over long distances."; + } else if (self.display_tip == 5) { + line1 = "Use your MIRV grenades (f) to clear a"; + line2 = "room or block a bottleneck."; + } else if (self.display_tip == 6) { + line1 = "On some maps, lay your detonation"; + line2 = "pack (5) near areas blocked by grates"; + line3 = "to open them."; + } + } + } else if (class == PC_MEDIC) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 12); + if (self.display_tip == 1) { + line1 = "The medic recovers from the effects of a"; + line2 = "concussion grenade (f) twice as fast as"; + line3 = "other classes."; + } else if (self.display_tip == 2) { + line1 = "The medic recovers from status effects"; + line2 = "twice as fast as other classes."; + } else if (self.display_tip == 3) { + line1 = "With its faster rate of fire, and"; + line2 = "greater accuracy, the shotgun (3) is"; + line3 = "more useful over long distances."; + } else if (self.display_tip == 4) { + line1 = "The super shotgun (2) does the most"; + line2 = "damage at close ranges."; + } else if (self.display_tip == 5) { + line1 = "Use your medikit (4) on teammates to"; + line2 = "heal status effects and give them super"; + line3 = "health."; + } else if (self.display_tip == 6) { + line1 = "Use your medikit (4) on enemies to"; + line2 = "infect them with a deadly and contagious"; + line3 = "virus."; + } else if (self.display_tip == 7) { + line1 = "Use concussion grenades (f) to blast"; + line2 = "enemies away from you and to slow them"; + line3 = "down."; + } else if (self.display_tip == 8) { + line1 = "The concussion grenade (f) blast effect"; + line2 = "is stronger toward the outside of its"; + line3 = "blast radius."; + } else if (self.display_tip == 9) { + line1 = "Concussion grenade (f) blasts will"; + line2 = "penetrate walls. Use this to your"; + line3 = "advantage."; + } else if (self.display_tip == 10) { + line1 = "Throw a concussion grenade (f) then"; + line2 = "position yourself for the perfect"; + line3 = "concussion grenade jump."; + } else if (self.display_tip == 11) { + line1 = "Concussion jumps can be chained for"; + line2 = "great distances."; + } else if (self.display_tip == 12) { + line1 = "Use your healing aura (e) to slowly"; + line2 = "heal nearby teammates over time."; + } + } + } else if (class == PC_HVYWEAP) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 8); + if (self.display_tip == 1) { + line1 = "A bunny hopping heavy weapons guy is"; + line2 = "very tough to stop with weapons."; + } else if (self.display_tip == 2) { + line1 = "The heavy weapons guy is too heavy to"; + line2 = "grenade jump very far."; + } else if (self.display_tip == 3) { + line1 = "Avoid concussion grenades, they stop you"; + line2 = "from standing still, reducing your"; + line3 = "accuracy."; + } else if (self.display_tip == 4) { + line1 = "The assault cannon takes (1) a while to"; + line2 = "spin up, use your class special (e) to"; + line3 = "keep it spinning."; + } else if (self.display_tip == 5) { + line1 = "Stand still to increase the accuracy of"; + line2 = "your assault cannon (1)."; + } else if (self.display_tip == 6) { + line1 = "With its faster rate of fire, and"; + line2 = "greater accuracy, the shotgun (3) is"; + line3 = "more useful over long distances."; + } else if (self.display_tip == 7) { + line1 = "The super shotgun (2) does the most"; + line2 = "damage at close ranges."; + } else if (self.display_tip == 8) { + line1 = "MIRV grenades (f) are a powerful way to"; + line2 = "clear a room or block a bottleneck."; + } + } + } else if (class == PC_PYRO) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 6); + if (self.display_tip == 1) { + line1 = "Use the flame thrower (1) to set your"; + line2 = "enemies on fire, causing them to lose"; + line3 = "health over time."; + } else if (self.display_tip == 2) { + line1 = "Use the flame thrower (1) to knock back"; + line2 = "your enemies."; + } else if (self.display_tip == 3) { + line1 = "The flame thrower (1) does not work"; + line2 = "underwater."; + } else if (self.display_tip == 4) { + line1 = "With its faster rate of fire, and"; + line2 = "greater accuracy, the shotgun (3) is"; + line3 = "more useful over long distances."; + } else if (self.display_tip == 5) { + line1 = "Napalm grenades (f) are useful for"; + line2 = "clearing a small room or blocking off a"; + line3 = "bottleneck."; + } else if (self.display_tip == 6) { + line1 = "The pyro's kevlar armor makes him immune"; + line2 = "to being burned."; + } + } + } else if (class == PC_SPY) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 11); + if (self.display_tip == 1) { + line1 = "Watch out for scouts, they will reveal"; + line2 = "your true identity if they touch you."; + } else if (self.display_tip == 2) { + line1 = "Using your weapon or picking up the flag"; + line2 = "will reveal your true identity."; + } else if (self.display_tip == 3) { + line1 = "The spy can throw grenades (mouse2 & f)"; + line2 = "without revealing his true identity."; + } else if (self.display_tip == 4) { + line1 = "The tranquiliser gun (1) slows your"; + line2 = "enemies down."; + } else if (self.display_tip == 5) { + line1 = "The super shotgun (2) does the most"; + line2 = "damage at close ranges."; + } else if (self.display_tip == 6) { + line1 = "With its faster rate of fire, and"; + line2 = "greater accuracy, the shotgun (3) is"; + line3 = "more useful over long distances."; + } else if (self.display_tip == 7) { + line1 = "Knife (4) your enemy in the back for"; + line2 = "3x damage."; + } else if (self.display_tip == 8) { + line1 = "The gas grenade (f) will annoy your"; + line2 = "enemies, causing them to hallucinate."; + } else if (self.display_tip == 9) { + line1 = "The spy can disguise (5) his team and"; + line2 = "class. Sneak past the enemy defences."; + } else if (self.display_tip == 10) { + line1 = "An enemy sentry gun won't shoot you"; + line2 = "while you are disguised (5)."; + } else if (self.display_tip == 11) { + line1 = "Use feign death (e) to fool your"; + line2 = "enemies of your demise."; + } + } + } else if (class == PC_ENGINEER) { + while (strlen(line1) == 0) { + if (!self.display_tip) + self.display_tip = ceil(random() * 11); + if (self.display_tip == 1) { + line1 = "Watch out for spies. A sentry gun will"; + line2 = "not shoot an enemy spy disguised as a"; + line3 = "teammate."; + } else if (self.display_tip == 2) { + line1 = "The railgun (1) is accurate on long"; + line2 = "distances. Use it on stationary objects."; + } else if (self.display_tip == 3) { + line1 = "The super shotgun (2) does the most"; + line2 = "damage at close ranges."; + } else if (self.display_tip == 4) { + line1 = "Use the spanner (4) on your sentry guns"; + line2 = "to upgrade, repair, restock or rotate"; + line3 = "them."; + } else if (self.display_tip == 5) { + line1 = "Use the spanner (4) on your teammates"; + line2 = "to repair their armor."; + } else if (self.display_tip == 6) { + line1 = "Use the spanner (4) on your dispensers"; + line2 = "to add ammo and armor."; + } else if (self.display_tip == 7) { + line1 = "The EMP grenade (f) will explode any"; + line2 = "nearby ammo including pipebombs on the"; + line3 = "ground."; + } else if (self.display_tip == 8) { + line1 = "The engineer can build (5) sentry guns"; + line2 = "and ammo / armor dispensers."; + } else if (self.display_tip == 9) { + line1 = "Build (5) your dispenser in a defensive"; + line2 = "position and detonate (e) it when an"; + line3 = "enemy is nearby."; + } else if (self.display_tip == 10) { + line1 = "The more ammo in your dispenser, the"; + line2 = "more damage it does when it is"; + line3 = "detonated (e)."; + } else if (self.display_tip == 11) { + line1 = "Rockets and cells will give the most"; + line2 = "blast damage from a detonated (e)"; + line3 = "dispenser."; + } else if (self.display_tip == 12) { + line1 = "A sentry gun can be upgraded to level 3,"; + line2 = "giving it the ability to fire rockets."; + } else if (self.display_tip == 13) { + line1 = "A sentry gun cannot be built on a moving"; + line2 = "platform."; + } + } + } + } + + showtips = !stof(infokey(self, "dt")); + if (showtips && classtips && self.display_tip) { + result = strcat(tiptype, line1); + result = strcat(result, "\n"); + result = strcat(result, line2); + result = strcat(result, "\n"); + result = strcat(result, line3); + result = strcat(result, "\n\n\n"); + } else { + result = "\n\n\n\n\n\n"; + } + + return strzone(result); +}; + void (entity pl, string...count) Status_Print = { local float i, lines, len; @@ -100,6 +564,7 @@ void (entity pl) RefreshStatusBar = { local string s1; // will be used for grenade timers local string s2; // class line local string s3; // score & clip + local string ct; // class tip local string st1, st2, st3, st4; // status bar columns 1-4 local string ident; local float height; @@ -118,7 +583,7 @@ void (entity pl) RefreshStatusBar = { height = floor(stof(infokey(pl, "sb"))); if (height > 300) height = 300; - height = height - pl.StatusStringLines - 7; + height = height - pl.StatusStringLines - 13; // no sbar can be displayed if (height <= 0 || pl.playerclass == PC_UNDEFINED) { @@ -131,6 +596,14 @@ void (entity pl) RefreshStatusBar = { pad = strcat(pad, "\n"); pad = strzone(pad); + // class tip + if (((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) { + ct = CF_GetRandomClassTip(pl.playerclass); + } else { + pl.display_tip = 0; + ct = strzone("\n\n\n\n\n\n"); + } + // status line 1 column 1 - grenade timer if (pl.StatusGrenTime > 0) { st1 = strcat("Ηςεξαδε: ", ftos(pl.StatusGrenTime)); @@ -244,9 +717,9 @@ void (entity pl) RefreshStatusBar = { ident = "\n\n\n\n"; } - centerprint(pl, pl.StatusString, pad, ident, s1, s2, s3); + centerprint(pl, pl.StatusString, pad, ident, ct, s1, s2, s3); pl.StatusRefreshTime = time + 1.5; - strunzone(pad); strunzone(s1); strunzone(s2); strunzone(s3); + strunzone(pad); strunzone(ct); strunzone(s1); strunzone(s2); strunzone(s3); }; string(float num) NumberToString1000 = diff --git a/tfort.qc b/tfort.qc index 3d7cfb78..ecf4f91a 100644 --- a/tfort.qc +++ b/tfort.qc @@ -298,6 +298,7 @@ void (float inp) TeamFortress_ChangeClass = { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } + self.spawn_time = time; }; void () TeamFortress_DisplayLegalClasses = { @@ -577,6 +578,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Pick up discarded ammo", discammo_pickup, "", 1); CF_PrintSetting("Reload clip tick", reload_cliptick, "", 1); CF_PrintSetting("ID extras", id_extended, "", 1); + CF_PrintSetting("Display class tips", classtips, "", 1); CF_PrintSetting("Old grenades", old_grens, "", 1); CF_PrintSetting("Drop grenades on ground", drop_grenades, "", 1); CF_PrintSetting("Drop grenades in pack", drop_grenpack, "", 1); diff --git a/tforthlp.qc b/tforthlp.qc index a03560ee..909326f5 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -91,6 +91,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("idenemy", TF_ID_ENEMY, 0); TeamFortress_Alias("is_aliased", TF_ALIAS_CHECK, 0); } else if (self.motd == 50) { + TeamFortress_Alias("nexttip", TF_NEXTTIP, 0); TeamFortress_Alias("votenext", TF_VOTENEXT, 0); TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); TeamFortress_Alias("voterace", TF_VOTERACE, 0); diff --git a/weapons.qc b/weapons.qc index 1838cdde..89f11b5d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2291,6 +2291,13 @@ void () ImpulseCommands = { if (self.impulse == TF_SPECIAL_SKILL) UseSpecialSkill(); + if (self.impulse == TF_NEXTTIP) { + self.display_tip = 0; + self.tip_type = 0; + self.tip_time = time; + Status_Refresh(self); + } + if (self.impulse == TF_WEAPLAST) { if (self.playerclass == PC_SPY && self.is_undercover == 2) CF_Spy_DisguiseStop(); From 876249ea9121bdfe966ee80822664d622a58c7c5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 27 Mar 2015 00:53:18 +0100 Subject: [PATCH 0382/2474] Use different skins for each team (closes #161). --- tfort.qc | 528 ++++++++++++++++++++++++------------------------------- 1 file changed, 233 insertions(+), 295 deletions(-) diff --git a/tfort.qc b/tfort.qc index ecf4f91a..4c5b5520 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1197,10 +1197,8 @@ string(entity p) TeamFortress_GetSkin = local float tn; local float pc; local string st; + local string skin = "base"; - if ((p.playerclass == 11) || (p.team_no == 0)) { - return ("base"); - } tn = p.team_no; pc = p.playerclass; if (p.playerclass == 8) { @@ -1215,306 +1213,246 @@ string(entity p) TeamFortress_GetSkin = if (pc == 1) { st = infokey(world, "sk_t4_scout"); if (st != string_null) { - return (st); + skin = st; } - return ("tf_scout"); - } else { - if (pc == 2) { - st = infokey(world, "sk_t4_sniper"); - if (st != string_null) { - return (st); - } - return ("tf_snipe"); - } else { - if (pc == 3) { - st = infokey(world, "sk_t4_soldier"); - if (st != string_null) { - return (st); - } - return ("tf_sold"); - } else { - if (pc == 4) { - st = infokey(world, "sk_t4_demoman"); - if (st != string_null) { - return (st); - } - return ("tf_demo"); - } else { - if (pc == 5) { - st = infokey(world, "sk_t4_medic"); - if (st != string_null) { - return (st); - } - return ("tf_medic"); - } else { - if (pc == 6) { - st = infokey(world, "sk_t4_hwguy"); - if (st != string_null) { - return (st); - } - return ("tf_hwguy"); - } else { - if (pc == 7) { - st = infokey(world, "sk_t4_pyro"); - if (st != string_null) { - return (st); - } - return ("tf_pyro"); - } else { - if (pc == 8) { - st = infokey(world, "sk_t4_spy"); - if (st != string_null) { - return (st); - } - return ("tf_spy"); - } else { - if (pc == 9) { - st = infokey(world, - "sk_t4_engineer"); - if (st != string_null) { - return (st); - } - return ("tf_eng"); - } - } - } - } - } - } - } + skin = "gren_sco"; + } else if (pc == 2) { + st = infokey(world, "sk_t4_sniper"); + if (st != string_null) { + skin = st; + } + skin = "gren_sni"; + } else if (pc == 3) { + st = infokey(world, "sk_t4_soldier"); + if (st != string_null) { + skin = st; } + skin = "gren_sol"; + } else if (pc == 4) { + st = infokey(world, "sk_t4_demoman"); + if (st != string_null) { + skin = st; + } + skin = "gren_dem"; + } else if (pc == 5) { + st = infokey(world, "sk_t4_medic"); + if (st != string_null) { + skin = st; + } + skin = "gren_med"; + } else if (pc == 6) { + st = infokey(world, "sk_t4_hwguy"); + if (st != string_null) { + skin = st; + } + skin = "gren_hwg"; + } else if (pc == 7) { + st = infokey(world, "sk_t4_pyro"); + if (st != string_null) { + skin = st; + } + skin = "gren_pyr"; + } else if (pc == 8) { + st = infokey(world, "sk_t4_spy"); + if (st != string_null) { + skin = st; + } + skin = "gren_spy"; + } else if (pc == 9) { + st = infokey(world, + "sk_t4_engineer"); + if (st != string_null) { + skin = st; + } + skin = "gren_eng"; + } else if (pc == 11) { + skin = "gren_civ"; } - } else { - if (tn == 3) { - if (pc == 1) { - st = infokey(world, "sk_t3_scout"); - if (st != string_null) { - return (st); - } - return ("tf_scout"); - } else { - if (pc == 2) { - st = infokey(world, "sk_t3_sniper"); - if (st != string_null) { - return (st); - } - return ("tf_snipe"); - } else { - if (pc == 3) { - st = infokey(world, "sk_t3_soldier"); - if (st != string_null) { - return (st); - } - return ("tf_sold"); - } else { - if (pc == 4) { - st = infokey(world, "sk_t3_demoman"); - if (st != string_null) { - return (st); - } - return ("tf_demo"); - } else { - if (pc == 5) { - st = infokey(world, "sk_t3_medic"); - if (st != string_null) { - return (st); - } - return ("tf_medic"); - } else { - if (pc == 6) { - st = infokey(world, "sk_t3_hwguy"); - if (st != string_null) { - return (st); - } - return ("tf_hwguy"); - } else { - if (pc == 7) { - st = infokey(world, "sk_t3_pyro"); - if (st != string_null) { - return (st); - } - return ("tf_pyro"); - } else { - if (pc == 8) { - st = infokey(world, - "sk_t3_spy"); - if (st != string_null) { - return (st); - } - return ("tf_spy"); - } else { - if (pc == 9) { - st = infokey(world, - "sk_t3_engineer"); - if (st != string_null) { - return (st); - } - return ("tf_eng"); - } - } - } - } - } - } - } - } + } else if (tn == 3) { + if (pc == 1) { + st = infokey(world, "sk_t3_scout"); + if (st != string_null) { + skin = st; } - } else { - if (tn == 2) { - if (pc == 1) { - st = infokey(world, "sk_t2_scout"); - if (st != string_null) { - return (st); - } - return ("tf_scout"); - } else { - if (pc == 2) { - st = infokey(world, "sk_t2_sniper"); - if (st != string_null) { - return (st); - } - return ("tf_snipe"); - } else { - if (pc == 3) { - st = infokey(world, "sk_t2_soldier"); - if (st != string_null) { - return (st); - } - return ("tf_sold"); - } else { - if (pc == 4) { - st = infokey(world, "sk_t2_demoman"); - if (st != string_null) { - return (st); - } - return ("tf_demo"); - } else { - if (pc == 5) { - st = infokey(world, "sk_t2_medic"); - if (st != string_null) { - return (st); - } - return ("tf_medic"); - } else { - if (pc == 6) { - st = infokey(world, "sk_t2_hwguy"); - if (st != string_null) { - return (st); - } - return ("tf_hwguy"); - } else { - if (pc == 7) { - st = infokey(world, - "sk_t2_pyro"); - if (st != string_null) { - return (st); - } - return ("tf_pyro"); - } else { - if (pc == 8) { - st = infokey(world, - "sk_t2_spy"); - if (st != string_null) { - return (st); - } - return ("tf_spy"); - } else { - if (pc == 9) { - st = infokey(world, - "sk_t2_engineer"); - if (st != string_null) { - return (st); - } - return ("tf_eng"); - } - } - } - } - } - } - } - } - } - } else { - if (pc == 1) { - st = infokey(world, "sk_t1_scout"); - if (st != string_null) { - return (st); - } - return ("tf_scout"); - } else { - if (pc == 2) { - st = infokey(world, "sk_t1_sniper"); - if (st != string_null) { - return (st); - } - return ("tf_snipe"); - } else { - if (pc == 3) { - st = infokey(world, "sk_t1_soldier"); - if (st != string_null) { - return (st); - } - return ("tf_sold"); - } else { - if (pc == 4) { - st = infokey(world, "sk_t1_demoman"); - if (st != string_null) { - return (st); - } - return ("tf_demo"); - } else { - if (pc == 5) { - st = infokey(world, "sk_t1_medic"); - if (st != string_null) { - return (st); - } - return ("tf_medic"); - } else { - if (pc == 6) { - st = infokey(world, "sk_t1_hwguy"); - if (st != string_null) { - return (st); - } - return ("tf_hwguy"); - } else { - if (pc == 7) { - st = infokey(world, - "sk_t1_pyro"); - if (st != string_null) { - return (st); - } - return ("tf_pyro"); - } else { - if (pc == 8) { - st = infokey(world, - "sk_t1_spy"); - if (st != string_null) { - return (st); - } - return ("tf_spy"); - } else { - if (pc == 9) { - st = infokey(world, - "sk_t1_engineer"); - if (st != string_null) { - return (st); - } - return ("tf_eng"); - } - } - } - } - } - } - } - } - } + skin = "yell_sco"; + } else if (pc == 2) { + st = infokey(world, "sk_t3_sniper"); + if (st != string_null) { + skin = st; + } + skin = "yell_sni"; + } else if (pc == 3) { + st = infokey(world, "sk_t3_soldier"); + if (st != string_null) { + skin = st; + } + skin = "yell_sol"; + } else if (pc == 4) { + st = infokey(world, "sk_t3_demoman"); + if (st != string_null) { + skin = st; + } + skin = "yell_dem"; + } else if (pc == 5) { + st = infokey(world, "sk_t3_medic"); + if (st != string_null) { + skin = st; + } + skin = "yell_med"; + } else if (pc == 6) { + st = infokey(world, "sk_t3_hwguy"); + if (st != string_null) { + skin = st; + } + skin = "yell_hwg"; + } else if (pc == 7) { + st = infokey(world, "sk_t3_pyro"); + if (st != string_null) { + skin = st; + } + skin = "yell_pyr"; + } else if (pc == 8) { + st = infokey(world, + "sk_t3_spy"); + if (st != string_null) { + skin = st; + } + skin = "yell_spy"; + } else if (pc == 9) { + st = infokey(world, + "sk_t3_engineer"); + if (st != string_null) { + skin = st; + } + skin = "yell_eng"; + } else if (pc == 11) { + skin = "yell_civ"; + } + } else if (tn == 2) { + if (pc == 1) { + st = infokey(world, "sk_t2_scout"); + if (st != string_null) { + skin = st; + } + skin = "red_sco"; + } else if (pc == 2) { + st = infokey(world, "sk_t2_sniper"); + if (st != string_null) { + skin = st; + } + skin = "red_sni"; + } else if (pc == 3) { + st = infokey(world, "sk_t2_soldier"); + if (st != string_null) { + skin = st; + } + skin = "red_sol"; + } else if (pc == 4) { + st = infokey(world, "sk_t2_demoman"); + if (st != string_null) { + skin = st; + } + skin = "red_dem"; + } else if (pc == 5) { + st = infokey(world, "sk_t2_medic"); + if (st != string_null) { + skin = st; + } + skin = "red_med"; + } else if (pc == 6) { + st = infokey(world, "sk_t2_hwguy"); + if (st != string_null) { + skin = st; + } + skin = "red_hwg"; + } else if (pc == 7) { + st = infokey(world, + "sk_t2_pyro"); + if (st != string_null) { + skin = st; + } + skin = "red_pyr"; + } else if (pc == 8) { + st = infokey(world, + "sk_t2_spy"); + if (st != string_null) { + skin = st; + } + skin = "red_spy"; + } else if (pc == 9) { + st = infokey(world, + "sk_t2_engineer"); + if (st != string_null) { + skin = st; + } + skin = "red_eng"; + } else if (pc == 11) { + skin = "red_civ"; + } + } else if (tn == 1) { + if (pc == 1) { + st = infokey(world, "sk_t1_scout"); + if (st != string_null) { + skin = st; + } + skin = "blue_sco"; + } else if (pc == 2) { + st = infokey(world, "sk_t1_sniper"); + if (st != string_null) { + skin = st; + } + skin = "blue_sni"; + } else if (pc == 3) { + st = infokey(world, "sk_t1_soldier"); + if (st != string_null) { + skin = st; + } + skin = "blue_sol"; + } else if (pc == 4) { + st = infokey(world, "sk_t1_demoman"); + if (st != string_null) { + skin = st; + } + skin = "blue_dem"; + } else if (pc == 5) { + st = infokey(world, "sk_t1_medic"); + if (st != string_null) { + skin = st; + } + skin = "blue_med"; + } else if (pc == 6) { + st = infokey(world, "sk_t1_hwguy"); + if (st != string_null) { + skin = st; + } + skin = "blue_hwg"; + } else if (pc == 7) { + st = infokey(world, + "sk_t1_pyro"); + if (st != string_null) { + skin = st; + } + skin = "blue_pyr"; + } else if (pc == 8) { + st = infokey(world, + "sk_t1_spy"); + if (st != string_null) { + skin = st; + } + skin = "blue_spy"; + } else if (pc == 9) { + st = infokey(world, + "sk_t1_engineer"); + if (st != string_null) { + skin = st; } + skin = "blue_eng"; + } else if (pc == 11) { + skin = "blue_civ"; } } - return ("base"); + return skin; }; void (entity p) TeamFortress_SetSkin = { From 6f814bcdd5afef77d6d55f1ffce7d37af588c7dd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 29 Mar 2015 13:54:51 +0200 Subject: [PATCH 0383/2474] Don't show ammo types that can't be dropped in dropammo menu. --- menu.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/menu.qc b/menu.qc index 7c4fc704..dc6f3a1c 100644 --- a/menu.qc +++ b/menu.qc @@ -371,13 +371,13 @@ void () Menu_Drop = { return; } - if (!self.ammo_shells) + if (self.ammo_shells < 20) s_shells = "\n"; - if (!self.ammo_nails) + if (self.ammo_nails < 20) s_nails = "\n"; - if (!self.ammo_rockets) + if (self.ammo_rockets < 10) s_rockets = "\n"; - if (!self.ammo_cells) + if (self.ammo_cells < 10) s_cells = "\n"; self.menu_input = nil; From 1711e5f29982fef9dc07860b6c10c7fc28028fda Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 3 Apr 2015 14:15:13 +0200 Subject: [PATCH 0384/2474] Add sniper power to status bar (closes #250). --- client.qc | 5 +++++ qw.qc | 3 +++ status.qc | 22 ++++++++++++++++++++++ tfort.qc | 1 + weapons.qc | 11 ++++++++++- 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index c70f178c..c3c7627c 100644 --- a/client.qc +++ b/client.qc @@ -469,6 +469,9 @@ void () DecodeLevelParms = { // display class tips [on] classtips = CF_GetSetting("ct", "classtips", "on"); + // display sniper rifle power in status bar [on] + sniperpower = CF_GetSetting("sp", "sniperpower", "on"); + // delay respawning by this many seconds [0] respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (respawn_delay_time) { @@ -526,6 +529,7 @@ void () DecodeLevelParms = { spawnfull = FALSE; stockfull = TRUE; classtips = TRUE; + sniperpower = TRUE; } st = infokey(world, "faithful"); @@ -568,6 +572,7 @@ void () DecodeLevelParms = { spawnfull = FALSE; stockfull = FALSE; classtips = FALSE; + sniperpower = FALSE; } } diff --git a/qw.qc b/qw.qc index ccafb6d1..5d33e735 100644 --- a/qw.qc +++ b/qw.qc @@ -72,6 +72,8 @@ typedef void (float) f_void_float; .float saveme_time; // Time when player issued /saveme command .float dash_cooldown; // Cooldown for Scout dash .float undercover_timer; // Seconds left until disguised +.float power_time; // The time when sniper power in status bar was last updated +.float power_full; // Whether sniper power has reached full power or not .float fragstreak; // Frag streak .float caps; // Caps during this game .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types @@ -463,6 +465,7 @@ float sniperreload; float spawnfull; float stockfull; float classtips; +float sniperpower; float server_default; float server_faithful; diff --git a/status.qc b/status.qc index efb92a8f..b80cbb51 100644 --- a/status.qc +++ b/status.qc @@ -9,6 +9,7 @@ string(float num) YellowScoreToString; string(float num) GreenScoreToString; string(entity pl) ClipSizeToString; float(entity pl) GetClipSize; +string(entity pl) SniperPowerToString; string(entity pl) DetpackToString; string(entity pl) AuraToString; string(entity pl) AssaultCannonToString; @@ -643,6 +644,8 @@ void (entity pl) RefreshStatusBar = { st1 = ""; if (pl.playerclass == PC_SCOUT) st1 = ScannerToString(pl); + else if (pl.playerclass == PC_SNIPER && (pl.tfstate & TFSTATE_AIMING)) + st1 = SniperPowerToString(pl); else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) st1 = DetpackToString(pl); else if (pl.playerclass == PC_MEDIC) @@ -905,6 +908,25 @@ string(entity pl) DisguiseToString = return st; }; +string(entity pl) SniperPowerToString = +{ + local string st = ""; + + if (!sniperpower) + return st; + + if (pl.heat) { + st = "Ποχες: "; + st = strcat(st, ftos(pl.heat)); + st = strcat(st, " dmg"); + if (pl.power_full) { + st = strcat(st, " (max)"); + } + } + + return st; +}; + string(entity pl) DetpackToString = { local string st = ""; diff --git a/tfort.qc b/tfort.qc index 4c5b5520..0686b3b7 100644 --- a/tfort.qc +++ b/tfort.qc @@ -594,6 +594,7 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "\n== Sniper ==\n"); CF_PrintSetting("Sniper reload", sniperreload, "", 1); CF_PrintSetting("Old sniper rifle range", old_sniperrange, "", 1); + CF_PrintSetting("Sniper Rifle power in status bar", sniperpower, "", 1); sprint(self, PRINT_HIGH, "\n== Demolitions Man ==\n"); if (detpipe_limit > 0) { diff --git a/weapons.qc b/weapons.qc index 89f11b5d..de5a758c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2750,8 +2750,16 @@ void () W_WeaponFrame = { if (self.button0 && !self.fire_held_down) { if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { - if (self.heat < 400) + if (self.heat < 400) { self.heat = self.heat + 3; + if ((sniperpower) && (self.power_time < (time - 0.3))) { + self.power_time = time; + Status_Refresh(self); + } + } else if ((sniperpower) && (!self.power_full)) { + self.power_full = 1; + Status_Refresh(self); + } } else { local vector tv = self.velocity; tv_z = 0; @@ -2759,6 +2767,7 @@ void () W_WeaponFrame = { SniperSight_Create(); self.heat = 50; self.tfstate = self.tfstate | 2048; + self.power_full = 0; TeamFortress_SetSpeed(self); } } From ad61fb4b7ce7c16ae9354401074828038fdc25d6 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Thu, 9 Apr 2015 20:40:09 +0200 Subject: [PATCH 0385/2474] Change old_sniperrange to TRUE for faithful setting. --- client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.qc b/client.qc index c3c7627c..5e520758 100644 --- a/client.qc +++ b/client.qc @@ -547,7 +547,7 @@ void () DecodeLevelParms = { reload_cliptick = FALSE; scoutdash = FALSE; sniperreload = FALSE; - old_sniperrange = FALSE; + old_sniperrange = TRUE; detpipe_limit = 7; detpipe_limit_world = 7; old_pipecooldown = TRUE; From 830105ddebfed77ac97e58a2d81c3512a52ae267 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Fri, 10 Apr 2015 14:12:20 +0200 Subject: [PATCH 0386/2474] Add sniper rifle reload percentage (closes #251). --- actions.qc | 7 +++---- client.qc | 5 +++++ qw.qc | 2 ++ status.qc | 17 +++++++++++------ tfort.qc | 1 + weapons.qc | 27 ++++++++++++++++++++------- 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/actions.qc b/actions.qc index 09ada00e..677017a5 100644 --- a/actions.qc +++ b/actions.qc @@ -404,9 +404,8 @@ void (float weap) TeamFortress_ReloadWeapon = { reloadamount = self.reload_sniper_rifle; Attack_Finished(1.5); self.reload_clipsize = (1 - reloadamount); - reloadtime = (1 - reloadamount) / 1; - reloadtime = 4 - (4 * reloadtime); self.reload_sniper_rifle = 0; + self.reload_sniper_ticks = 0; if (self.ammo_shells < 1) { self.reload_sniper_rifle = 1 - self.ammo_shells; } @@ -416,8 +415,8 @@ void (float weap) TeamFortress_ReloadWeapon = { tWeapon = spawn(); tWeapon.owner = self; tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_sniper_rifle; + tWeapon.nextthink = time + 1; // this will tick four times before finishing reload + tWeapon.think = W_Reload_sniper_rifle_tick; self.weaponmodel = ""; self.weaponframe = 0; } else { diff --git a/client.qc b/client.qc index 5e520758..872a788a 100644 --- a/client.qc +++ b/client.qc @@ -472,6 +472,9 @@ void () DecodeLevelParms = { // display sniper rifle power in status bar [on] sniperpower = CF_GetSetting("sp", "sniperpower", "on"); + // display sniper rifle reload percentage status bar [on] + sniperreloadpercent = CF_GetSetting("rp", "sniperreloadpercent", "on"); + // delay respawning by this many seconds [0] respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (respawn_delay_time) { @@ -530,6 +533,7 @@ void () DecodeLevelParms = { stockfull = TRUE; classtips = TRUE; sniperpower = TRUE; + sniperreloadpercent = TRUE; } st = infokey(world, "faithful"); @@ -573,6 +577,7 @@ void () DecodeLevelParms = { stockfull = FALSE; classtips = FALSE; sniperpower = FALSE; + sniperreloadpercent = FALSE; } } diff --git a/qw.qc b/qw.qc index 5d33e735..b7ce05f1 100644 --- a/qw.qc +++ b/qw.qc @@ -204,6 +204,7 @@ float coop; .float reload_tick; // how often the status bar should be refreshed during reload .float reload_time; // when the reload will finish .float reload_clipsize; // how much ammo is currently in the reloading clip +.float reload_sniper_ticks; // used to indicate when sniper rifle (with only 1 clip) will be reloaded // Assault Cannon .float heat; @@ -466,6 +467,7 @@ float spawnfull; float stockfull; float classtips; float sniperpower; +float sniperreloadpercent; float server_default; float server_faithful; diff --git a/status.qc b/status.qc index b80cbb51..49bc1bd5 100644 --- a/status.qc +++ b/status.qc @@ -695,12 +695,17 @@ void (entity pl) RefreshStatusBar = { // status line 3 column 3 - clip size if (pl.tfstate & TFSTATE_RELOADING) { st3 = "Γμιπ: "; - if (reload_cliptick) - st3 = strcat(st3, strpadl(ftos(pl.reload_clipsize), 2)); - else - st3 = strcat(st3, " 0"); - st3 = strcat(st3, "/"); - st3 = strcat(st3, strpadr(ftos(GetClipSize(pl)), 3)); + if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { + st3 = strcat(st3, strpadl(ftos(25 * pl.reload_sniper_ticks), 3)); + st3 = strcat(st3, "% "); + } else { + if (reload_cliptick) + st3 = strcat(st3, strpadl(ftos(pl.reload_clipsize), 2)); + else + st3 = strcat(st3, " 0"); + st3 = strcat(st3, "/"); + st3 = strcat(st3, strpadr(ftos(GetClipSize(pl)), 3)); + } } else { st3 = ClipSizeToString(pl); } diff --git a/tfort.qc b/tfort.qc index 0686b3b7..d85d8137 100644 --- a/tfort.qc +++ b/tfort.qc @@ -595,6 +595,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Sniper reload", sniperreload, "", 1); CF_PrintSetting("Old sniper rifle range", old_sniperrange, "", 1); CF_PrintSetting("Sniper Rifle power in status bar", sniperpower, "", 1); + CF_PrintSetting("Reload percentage in status bar", sniperreloadpercent, "", 1); sprint(self, PRINT_HIGH, "\n== Demolitions Man ==\n"); if (detpipe_limit > 0) { diff --git a/weapons.qc b/weapons.qc index de5a758c..7aa73c88 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1680,15 +1680,28 @@ void () W_Reload_super_shotgun = { Status_Refresh(self.owner); }; -void () W_Reload_sniper_rifle = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_srifle.mdl"; - sprint(self.owner, PRINT_LOW, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); +void (entity pl) W_Reload_sniper_rifle = { + pl.reload_sniper_ticks = 0; + pl.tfstate = pl.tfstate - (pl.tfstate & TFSTATE_RELOADING); + pl.weaponmodel = "progs/v_srifle.mdl"; + sprint(pl, PRINT_LOW, "Finished reloading\n"); + W_WeaponState_Load(pl, 0); + Status_Refresh(pl); }; +void () W_Reload_sniper_rifle_tick = { + self.owner.reload_sniper_ticks = self.owner.reload_sniper_ticks + 1; + + if (self.owner.reload_sniper_ticks >= 4) { + W_Reload_sniper_rifle(self.owner); + dremove(self); + return; + } + + Status_Refresh(self.owner); + self.nextthink = time + 1; +} + void () W_Reload_grenade_launcher = { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); if (self.owner.weaponmode == 0) From 5439a8c6f86308c4a40fcda64403db575605f368 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 11 Apr 2015 09:11:06 +0200 Subject: [PATCH 0387/2474] Move (local) map configs to map/ directory. --- tfort.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index d85d8137..b8d01dce 100644 --- a/tfort.qc +++ b/tfort.qc @@ -3050,8 +3050,8 @@ void (entity p) TeamFortress_ExecMapScript = { st = infokey(p, "exec_map"); if (st == "on") { - stuffcmd(p, "exec mapdefault.cfg\n"); - stuffcmd(p, "exec "); + stuffcmd(p, "exec maps/default.cfg\n"); + stuffcmd(p, "exec maps/"); stuffcmd(p, mapname); stuffcmd(p, ".cfg\n"); } From 4b390c86d801c987c1ce61bf4e46d0e4158e38ab Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 11 Apr 2015 09:18:29 +0200 Subject: [PATCH 0388/2474] Change setinfo em/ec to 0/1 instead of off/on. --- tfort.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index b8d01dce..42ea574f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -3019,7 +3019,7 @@ void (entity p) TeamFortress_ExecClassScript = { if (st == string_null) st = infokey(p, "exec_class"); - if (st == "on") { + if (st == "1") { stuffcmd(p, "exec classes/default.cfg\n"); if (p.playerclass == PC_SCOUT) stuffcmd(p, "exec classes/scout.cfg\n"); @@ -3049,7 +3049,7 @@ void (entity p) TeamFortress_ExecMapScript = { if (st == string_null) st = infokey(p, "exec_map"); - if (st == "on") { + if (st == "1") { stuffcmd(p, "exec maps/default.cfg\n"); stuffcmd(p, "exec maps/"); stuffcmd(p, mapname); From bd1ebda595359e7aeccde3f50d28cbfe5b0c277c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 12 Apr 2015 10:36:00 +0200 Subject: [PATCH 0389/2474] Add build status in status bar (closes #252). --- client.qc | 7 ++++++- engineer.qc | 14 ++++++++++++++ qw.qc | 10 +++++++--- status.qc | 17 ++++++++++++++++- tfort.qc | 1 + 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 872a788a..9aa6d42d 100644 --- a/client.qc +++ b/client.qc @@ -472,9 +472,12 @@ void () DecodeLevelParms = { // display sniper rifle power in status bar [on] sniperpower = CF_GetSetting("sp", "sniperpower", "on"); - // display sniper rifle reload percentage status bar [on] + // display sniper rifle reload percentage in status bar [on] sniperreloadpercent = CF_GetSetting("rp", "sniperreloadpercent", "on"); + // display build status in status bar [on] + buildstatus = CF_GetSetting("bs", "buildstatus", "on"); + // delay respawning by this many seconds [0] respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (respawn_delay_time) { @@ -534,6 +537,7 @@ void () DecodeLevelParms = { classtips = TRUE; sniperpower = TRUE; sniperreloadpercent = TRUE; + buildstatus = TRUE; } st = infokey(world, "faithful"); @@ -578,6 +582,7 @@ void () DecodeLevelParms = { classtips = FALSE; sniperpower = FALSE; sniperreloadpercent = FALSE; + buildstatus = FALSE; } } diff --git a/engineer.qc b/engineer.qc index 15042a5c..537bdd30 100644 --- a/engineer.qc +++ b/engineer.qc @@ -283,6 +283,7 @@ void () TeamFortress_EngineerBuildStop = { } Menu_Close(self); self.is_building = 0; + self.building_percentage = 0; self.current_weapon = self.weapon; W_SetCurrentAmmo(self); } @@ -388,6 +389,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.mdl = "progs/disp.mdl"; newmis.netname = "dispenser"; btime = time + 2; + self.dispenser_ticks = 0; } else if (objtobuild == 2) { if (self.has_sentry) { sprint(self, PRINT_HIGH, "You can only have one sentry gun\n"); @@ -399,6 +401,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.mdl = "progs/turrbase.mdl"; newmis.netname = "sentrygun"; btime = time + 5; + self.sentry_ticks = 0; } if (CheckArea(newmis, self) == 0) { sprint(self, PRINT_HIGH, "Not enough room to build here\n"); @@ -472,6 +475,16 @@ void () CF_CheckBuilding = { return; } + if (building.weapon == 2) { + self.sentry_ticks = self.sentry_ticks + 0.3; + self.building_percentage = ceil((self.sentry_ticks / 5) * 100); + } else if (building.weapon == 1) { + self.dispenser_ticks = self.dispenser_ticks + 0.3; + self.building_percentage = ceil((self.dispenser_ticks / 2) * 100); + } + + Status_Refresh(self); + timer.nextthink = time + 0.3; }; @@ -694,6 +707,7 @@ void () TeamFortress_FinishedBuilding = { oldself.owner = world; oldself.real_owner = self; self.is_building = FALSE; + self.building_percentage = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); self.movetype = MOVETYPE_WALK; self.current_weapon = self.weapon; diff --git a/qw.qc b/qw.qc index b7ce05f1..252732cb 100644 --- a/qw.qc +++ b/qw.qc @@ -73,14 +73,17 @@ typedef void (float) f_void_float; .float dash_cooldown; // Cooldown for Scout dash .float undercover_timer; // Seconds left until disguised .float power_time; // The time when sniper power in status bar was last updated -.float power_full; // Whether sniper power has reached full power or not +.float power_full; // Whether sniper power has reached full power or not +.float sentry_ticks; // Used to indicate when engineer's sentry gun is finished building +.float dispenser_ticks; // Used to indicate when engineer's dispenser is finished building +.float building_percentage; // The building percentage shown in status bar .float fragstreak; // Frag streak .float caps; // Caps during this game -.entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types +.entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types .float tfstate; // State flags for TeamFortress .entity linked_list; // Used just like chain. Has to be separate so - // it doesn't interfere with chain. See T_RadiusScan + // it doesn't interfere with chain. See T_RadiusScan .entity observer_list; // Used by undefined classes, see TF_MovePlayer @@ -468,6 +471,7 @@ float stockfull; float classtips; float sniperpower; float sniperreloadpercent; +float buildstatus; float server_default; float server_faithful; diff --git a/status.qc b/status.qc index 49bc1bd5..06572ea0 100644 --- a/status.qc +++ b/status.qc @@ -17,6 +17,7 @@ string(entity pl) RangeToString; string(entity pl) ScannerToString; string(entity pl) DisguiseToString; string(entity pl) SentryDetailsToString; +string(entity pl) BuildingToString; string(float pc) TeamFortress_GetClassName; string (float class) CF_GetRandomClassTip { @@ -657,7 +658,7 @@ void (entity pl) RefreshStatusBar = { else if (pl.playerclass == PC_ENGINEER && pl.has_sentry) st1 = SentryDetailsToString(pl); if (pl.playerclass == PC_ENGINEER && pl.is_building) - st1 = "Building..."; + st1 = BuildingToString(pl); // status line 2 s2 = strpadr(st1, 40); s2 = strcat(s2, "\n"); @@ -1097,3 +1098,17 @@ string(entity pl) SentryDetailsToString = return st; }; + +string(entity pl) BuildingToString = +{ + local string st = ""; + + if (!buildstatus) + return "Building..."; + + st = "Βυιμδιξη: "; + st = strcat(st, ftos(pl.building_percentage)); + st = strcat(st, "%"); + + return st; +}; diff --git a/tfort.qc b/tfort.qc index 42ea574f..1407aa31 100644 --- a/tfort.qc +++ b/tfort.qc @@ -643,6 +643,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Old railgun behaviour", old_railgun, "", 1); CF_PrintSetting("Old dispenser behaviour", old_dispenser, "", 1); CF_PrintSetting("Bigger dispenser explosions", disp_explosion, "", 1); + CF_PrintSetting("Build status in status bar", buildstatus, "", 1); sprint(self, PRINT_HIGH, "\n== Spy ==\n"); CF_PrintSetting("Allow feign death while airborne", feign_air, "", 1); From 0c1f0a1ef27748e46fde93cafdd2dba273ee06cd Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 13 Apr 2015 19:51:14 +0200 Subject: [PATCH 0390/2474] Indicate when the engineer can make ammo on dropammo menu. --- menu.qc | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/menu.qc b/menu.qc index dc6f3a1c..e869fc13 100644 --- a/menu.qc +++ b/menu.qc @@ -360,26 +360,40 @@ void (float inp) Menu_Drop_Input = { void () Menu_Drop = { local string s_drop; - local string s_shells = "“‘ Shells \n"; - local string s_nails = "”‘ Nails \n"; - local string s_rockets = "•‘ Rockets\n"; - local string s_cells = "–‘ Cells \n"; - local string s_nothing = "\n—‘ Nothing"; + local string s_shells = "“‘ Shells \n"; + local string s_nails = "”‘ Nails \n"; + local string s_rockets = "•‘ Rockets \n"; + local string s_cells = "–‘ Cells \n"; + local string s_nothing = "\n—‘ Nothing "; if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); return; } - if (self.ammo_shells < 20) + if (self.ammo_shells < DROP_SHELLS) s_shells = "\n"; - if (self.ammo_nails < 20) + if (self.ammo_nails < DROP_NAILS) s_nails = "\n"; - if (self.ammo_rockets < 10) + if (self.ammo_rockets < DROP_ROCKETS) s_rockets = "\n"; - if (self.ammo_cells < 10) + if (self.ammo_cells < DROP_CELLS) s_cells = "\n"; + if (self.playerclass == PC_ENGINEER) { + if ((self.ammo_shells < DROP_SHELLS) && ((self.ammo_cells / AMMO_COST_SHELLS) > (DROP_SHELLS - self.ammo_shells))) + s_shells = "“‘ Shells (make) \n"; + if ((self.ammo_nails < DROP_NAILS) && ((self.ammo_cells / AMMO_COST_NAILS) > (DROP_NAILS - self.ammo_nails))) + s_nails = "”‘ Nails (make) \n"; + if ((self.ammo_rockets < DROP_ROCKETS) && ((self.ammo_cells / AMMO_COST_ROCKETS) > (DROP_ROCKETS - self.ammo_rockets))) + s_rockets = "•‘ Rockets (make)\n"; + if (self.ammo_cells < DROP_CELLS) + s_cells = "\n"; + } + + if (s_shells == "\n" && s_nails == "\n" && s_rockets == "\n" && s_cells == "\n") + return; + self.menu_input = nil; if (self.playerclass == PC_ENGINEER) s_drop = "Drop or make:\n\n"; From ae7e94b429a0337963e27132c9beb14d6a2b7b6c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 13 Apr 2015 19:51:34 +0200 Subject: [PATCH 0391/2474] Update dropammo menu when picking up ammo (closes #255). --- weapons.qc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/weapons.qc b/weapons.qc index 7aa73c88..55aa1ab5 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1434,6 +1434,8 @@ void () superspike_touch = { }; void (entity pl) W_SetCurrentAmmo = { + entity oldself; + if ((pl.health <= 0) || (pl.current_weapon == 0)) return; @@ -1586,6 +1588,12 @@ void (entity pl) W_SetCurrentAmmo = { // refresh engineer build menu when ammo updated if (pl.menu_input == Menu_Engineer_Input) Menu_Engineer(pl); + else if (pl.menu_input == Menu_Drop_Input) { + oldself = self; + self = pl; + Menu_Drop(); + self = oldself; + } }; float () W_BestWeapon = { From 6b8894554264172350a83c920bb837687ad78293 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 13 Apr 2015 22:10:02 +0200 Subject: [PATCH 0392/2474] Play stock sound when picking up map backpacks (closes #259). --- tfortmap.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tfortmap.qc b/tfortmap.qc index c974d37a..461abf62 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -832,6 +832,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { self = Player; TeamFortress_CheckClassStats(); W_SetCurrentAmmo(self); + sound(self, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); self = oldself; } if ((Player.playerclass == PC_SPY) && From 40ae607f33cead5016675b0151785d5d4489e3f5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Mon, 13 Apr 2015 22:15:59 +0200 Subject: [PATCH 0393/2474] Don't animate incendiary cannon when ammo is insufficient (closes #257). --- qw.qc | 1 + weapons.qc | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/qw.qc b/qw.qc index 252732cb..9042e95d 100644 --- a/qw.qc +++ b/qw.qc @@ -406,6 +406,7 @@ float already_chosen_map; .float antispam_feign; // don't spam feign deaths .float antispam_assault_cannon; // don't spam assault cannon messages .float antispam_cannon_air; // don't spam assault cannon air messages +.float antispam_incendiary_cannon; // don't spam incendiary cannon messages // status bar stuff .string StatusString; // current centerprint text (strzone'd!) diff --git a/weapons.qc b/weapons.qc index 55aa1ab5..4c3dedf5 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1922,9 +1922,14 @@ void () W_Attack = { else Attack_Finished(0.15); } else if (self.current_weapon == WEAP_INCENDIARY) { - player_rocket1(); - W_FireIncendiaryCannon(); - Attack_Finished(1.2); + if (self.ammo_rockets >= 3) { + player_rocket1(); + W_FireIncendiaryCannon(); + Attack_Finished(1.2); + } else if (time >= self.antispam_incendiary_cannon) { + sprint(self, PRINT_HIGH, "Not enough ammo\n"); + self.antispam_incendiary_cannon = time + 3; + } } else if (self.current_weapon == WEAP_MEDIKIT) { sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); From 6bf8d1d5b853791b98deab6ccb1c5094adaafc71 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 21 Jun 2015 21:30:33 +0900 Subject: [PATCH 0394/2474] syntax change for FTEQCC compatibility --- menu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index e869fc13..53556a32 100644 --- a/menu.qc +++ b/menu.qc @@ -98,7 +98,7 @@ void (entity pl) Menu_Close = void (float inp) Menu_Input = { - local f_void_float tmp = self.menu_input; + var f_void_float tmp; tmp = self.menu_input; self.menu_input = nil; self.impulse = 0; tmp(inp); From cd15853d47f58c428e28237f6a6b9c4984c1212c Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 21 Jun 2015 14:56:52 +0200 Subject: [PATCH 0395/2474] Change initial health to 100 for all classes. * Adjust armor values for affected classes so this change has no/little effect on gameplay. --- client.qc | 5 ++ defs.h | 34 +++++----- qw.qc | 1 + tfort.qc | 200 +++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 183 insertions(+), 57 deletions(-) diff --git a/client.qc b/client.qc index 9aa6d42d..357402bd 100644 --- a/client.qc +++ b/client.qc @@ -478,6 +478,9 @@ void () DecodeLevelParms = { // display build status in status bar [on] buildstatus = CF_GetSetting("bs", "buildstatus", "on"); + // use old init/max hp/armor [off] + old_hp_armor = CF_GetSetting("oh", "old_hp_armor", "off"); + // delay respawning by this many seconds [0] respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (respawn_delay_time) { @@ -538,6 +541,7 @@ void () DecodeLevelParms = { sniperpower = TRUE; sniperreloadpercent = TRUE; buildstatus = TRUE; + old_hp_armor = FALSE; } st = infokey(world, "faithful"); @@ -583,6 +587,7 @@ void () DecodeLevelParms = { sniperpower = FALSE; sniperreloadpercent = FALSE; buildstatus = FALSE; + old_hp_armor = TRUE; } } diff --git a/defs.h b/defs.h index 856c492e..4cd7c389 100644 --- a/defs.h +++ b/defs.h @@ -774,11 +774,11 @@ /*======================================================================*/ // Class Details for SCOUT #define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. -#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level +#define PC_SCOUT_MAXHEALTH 100 // Maximum Health Level #define PC_SCOUT_MAXSPEED 450 // Maximum movement speed #define PC_SCOUT_MAXSTRAFESPEED 450 // Maximum strafing movement speed -#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class -#define PC_SCOUT_INITARMOR 25 // Armor level when respawned +#define PC_SCOUT_MAXARMOR 25 // Maximum Armor Level, of any armor class +#define PC_SCOUT_INITARMOR 0 // Armor level when respawned #define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption #define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned #define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class @@ -803,10 +803,10 @@ // Class Details for SNIPER #define PC_SNIPER_SKIN 5 -#define PC_SNIPER_MAXHEALTH 90 +#define PC_SNIPER_MAXHEALTH 100 #define PC_SNIPER_MAXSPEED 300 #define PC_SNIPER_MAXSTRAFESPEED 300 -#define PC_SNIPER_MAXARMOR 50 +#define PC_SNIPER_MAXARMOR 40 #define PC_SNIPER_INITARMOR 0 #define PC_SNIPER_MAXARMORTYPE 0.3 #define PC_SNIPER_INITARMORTYPE 0.3 @@ -855,11 +855,11 @@ // Class Details for DEMOLITION MAN #define PC_DEMOMAN_SKIN 1 -#define PC_DEMOMAN_MAXHEALTH 90 +#define PC_DEMOMAN_MAXHEALTH 100 #define PC_DEMOMAN_MAXSPEED 280 #define PC_DEMOMAN_MAXSTRAFESPEED 280 -#define PC_DEMOMAN_MAXARMOR 120 -#define PC_DEMOMAN_INITARMOR 50 +#define PC_DEMOMAN_MAXARMOR 110 +#define PC_DEMOMAN_INITARMOR 40 #define PC_DEMOMAN_MAXARMORTYPE 0.6 #define PC_DEMOMAN_INITARMORTYPE 0.6 #define PC_DEMOMAN_ARMORCLASSES 31 // ALL @@ -883,11 +883,11 @@ // Class Details for COMBAT MEDIC #define PC_MEDIC_SKIN 3 -#define PC_MEDIC_MAXHEALTH 90 +#define PC_MEDIC_MAXHEALTH 100 #define PC_MEDIC_MAXSPEED 320 #define PC_MEDIC_MAXSTRAFESPEED 320 -#define PC_MEDIC_MAXARMOR 100 -#define PC_MEDIC_INITARMOR 50 +#define PC_MEDIC_MAXARMOR 90 +#define PC_MEDIC_INITARMOR 40 #define PC_MEDIC_MAXARMORTYPE 0.6 #define PC_MEDIC_INITARMORTYPE 0.3 #define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION @@ -973,11 +973,11 @@ // Class Details for SPY #define PC_SPY_SKIN 22 -#define PC_SPY_MAXHEALTH 90 +#define PC_SPY_MAXHEALTH 100 #define PC_SPY_MAXSPEED 300 #define PC_SPY_MAXSTRAFESPEED 300 -#define PC_SPY_MAXARMOR 100 -#define PC_SPY_INITARMOR 25 +#define PC_SPY_MAXARMOR 90 +#define PC_SPY_INITARMOR 15 #define PC_SPY_MAXARMORTYPE 0.6 #define PC_SPY_INITARMORTYPE 0.6 #define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION @@ -1003,11 +1003,11 @@ // Class Details for ENGINEER #define PC_ENGINEER_SKIN 22 // Not used anymore -#define PC_ENGINEER_MAXHEALTH 80 +#define PC_ENGINEER_MAXHEALTH 100 #define PC_ENGINEER_MAXSPEED 300 #define PC_ENGINEER_MAXSTRAFESPEED 300 -#define PC_ENGINEER_MAXARMOR 50 -#define PC_ENGINEER_INITARMOR 25 +#define PC_ENGINEER_MAXARMOR 30 +#define PC_ENGINEER_INITARMOR 5 #define PC_ENGINEER_MAXARMORTYPE 0.6 #define PC_ENGINEER_INITARMORTYPE 0.3 #define PC_ENGINEER_ARMORCLASSES 31 // ALL diff --git a/qw.qc b/qw.qc index 9042e95d..75ce9bcb 100644 --- a/qw.qc +++ b/qw.qc @@ -479,6 +479,7 @@ float server_faithful; float old_spanner; float old_railgun; float old_dispenser; +float old_hp_armor; .float teamkills; diff --git a/tfort.qc b/tfort.qc index 1407aa31..49c499bf 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1169,25 +1169,55 @@ void (entity p) TeamFortress_SetSpeed = { void () TeamFortress_SetHealth = { if (self.playerclass == PC_SCOUT) { - self.max_health = PC_SCOUT_MAXHEALTH; + if (old_hp_armor) + self.max_health = 75; + else + self.max_health = PC_SCOUT_MAXHEALTH; } else if (self.playerclass == PC_SNIPER) { - self.max_health = PC_SNIPER_MAXHEALTH; + if (old_hp_armor) + self.max_health = 90; + else + self.max_health = PC_SNIPER_MAXHEALTH; } else if (self.playerclass == PC_SOLDIER) { - self.max_health = PC_SOLDIER_MAXHEALTH; + if (old_hp_armor) + self.max_health = 100; + else + self.max_health = PC_SOLDIER_MAXHEALTH; } else if (self.playerclass == PC_DEMOMAN) { - self.max_health = PC_DEMOMAN_MAXHEALTH; + if (old_hp_armor) + self.max_health = 90; + else + self.max_health = PC_DEMOMAN_MAXHEALTH; } else if (self.playerclass == PC_MEDIC) { - self.max_health = PC_MEDIC_MAXHEALTH; + if (old_hp_armor) + self.max_health = 90; + else + self.max_health = PC_MEDIC_MAXHEALTH; } else if (self.playerclass == PC_HVYWEAP) { - self.max_health = PC_HVYWEAP_MAXHEALTH; + if (old_hp_armor) + self.max_health = 100; + else + self.max_health = PC_HVYWEAP_MAXHEALTH; } else if (self.playerclass == PC_PYRO) { - self.max_health = PC_PYRO_MAXHEALTH; + if (old_hp_armor) + self.max_health = 100; + else + self.max_health = PC_PYRO_MAXHEALTH; } else if (self.playerclass == PC_CIVILIAN) { - self.max_health = PC_CIVILIAN_MAXHEALTH; + if (old_hp_armor) + self.max_health = 50; + else + self.max_health = PC_CIVILIAN_MAXHEALTH; } else if (self.playerclass == PC_SPY) { - self.max_health = PC_SPY_MAXHEALTH; + if (old_hp_armor) + self.max_health = 90; + else + self.max_health = PC_SPY_MAXHEALTH; } else if (self.playerclass == PC_ENGINEER) { - self.max_health = PC_ENGINEER_MAXHEALTH; + if (old_hp_armor) + self.max_health = 80; + else + self.max_health = PC_ENGINEER_MAXHEALTH; } else { self.max_health = 1; self.takedamage = DAMAGE_NO; @@ -1554,14 +1584,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.ammo_cells = PC_SCOUT_MAXAMMO_CELL; self.armortype = PC_SCOUT_MAXARMORTYPE; - self.armorvalue = PC_SCOUT_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 50; + else + self.armorvalue = PC_SCOUT_MAXARMOR; } else { self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET; self.ammo_nails = PC_SCOUT_INITAMMO_NAIL; self.ammo_shells = PC_SCOUT_INITAMMO_SHOT; self.ammo_cells = PC_SCOUT_INITAMMO_CELL; self.armortype = PC_SCOUT_INITARMORTYPE; - self.armorvalue = PC_SCOUT_INITARMOR; + if (old_hp_armor) + self.armorvalue = 25; + else + self.armorvalue = PC_SCOUT_INITARMOR; } // dispenser needs @@ -1591,7 +1627,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | 0; self.armor_allowed = PC_SCOUT_MAXARMORTYPE; - self.maxarmor = PC_SCOUT_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 50; + else + self.maxarmor = PC_SCOUT_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_NAILGUN; @@ -1607,14 +1646,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.ammo_cells = PC_SNIPER_MAXAMMO_CELL; self.armortype = PC_SNIPER_MAXARMORTYPE; - self.armorvalue = PC_SNIPER_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 50; + else + self.armorvalue = PC_SNIPER_MAXARMOR; } else { self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET; self.ammo_nails = PC_SNIPER_INITAMMO_NAIL; self.ammo_shells = PC_SNIPER_INITAMMO_SHOT; self.ammo_cells = PC_SNIPER_INITAMMO_CELL; self.armortype = PC_SNIPER_INITARMORTYPE; - self.armorvalue = PC_SNIPER_INITARMOR; + if (old_hp_armor) + self.armorvalue = 0; + else + self.armorvalue = PC_SNIPER_INITARMOR; } // dispenser needs @@ -1636,7 +1681,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS; self.armor_allowed = PC_SNIPER_MAXARMORTYPE; - self.maxarmor = PC_SNIPER_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 50; + else + self.maxarmor = PC_SNIPER_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SNIPER_RIFLE; @@ -1652,14 +1700,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.ammo_cells = PC_SOLDIER_MAXAMMO_CELL; self.armortype = PC_SOLDIER_MAXARMORTYPE; - self.armorvalue = PC_SOLDIER_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 200; + else + self.armorvalue = PC_SOLDIER_MAXARMOR; } else { self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET; self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL; self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT; self.ammo_cells = PC_SOLDIER_INITAMMO_CELL; self.armortype = PC_SOLDIER_INITARMORTYPE; - self.armorvalue = PC_SOLDIER_INITARMOR; + if (old_hp_armor) + self.armorvalue = 100; + else + self.armorvalue = PC_SOLDIER_INITARMOR; } // dispenser needs @@ -1681,7 +1735,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS; self.armor_allowed = PC_SOLDIER_MAXARMORTYPE; - self.maxarmor = PC_SOLDIER_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 200; + else + self.maxarmor = PC_SOLDIER_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_ROCKET_LAUNCHER; @@ -1698,14 +1755,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_MAXAMMO_CELL; self.armortype = PC_DEMOMAN_MAXARMORTYPE; - self.armorvalue = PC_DEMOMAN_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 120; + else + self.armorvalue = PC_DEMOMAN_MAXARMOR; } else { self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET; self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL; self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL; self.armortype = PC_DEMOMAN_INITARMORTYPE; - self.armorvalue = PC_DEMOMAN_INITARMOR; + if (old_hp_armor) + self.armorvalue = 50; + else + self.armorvalue = PC_DEMOMAN_INITARMOR; } // dispenser needs @@ -1730,7 +1793,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_DEMOMAN_INITARMORCLASS; self.armor_allowed = PC_DEMOMAN_MAXARMORTYPE; - self.maxarmor = PC_DEMOMAN_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 120; + else + self.maxarmor = PC_DEMOMAN_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_GRENADE_LAUNCHER; @@ -1745,14 +1811,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.ammo_cells = PC_MEDIC_MAXAMMO_CELL; self.armortype = PC_MEDIC_MAXARMORTYPE; - self.armorvalue = PC_MEDIC_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 100; + else + self.armorvalue = PC_MEDIC_MAXARMOR; } else { self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET; self.ammo_nails = PC_MEDIC_INITAMMO_NAIL; self.ammo_shells = PC_MEDIC_INITAMMO_SHOT; self.ammo_cells = PC_MEDIC_INITAMMO_CELL; self.armortype = PC_MEDIC_INITARMORTYPE; - self.armorvalue = PC_MEDIC_INITARMOR; + if (old_hp_armor) + self.armorvalue = 50; + else + self.armorvalue = PC_MEDIC_INITARMOR; } // dispenser needs @@ -1774,7 +1846,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS; self.armor_allowed = PC_MEDIC_MAXARMORTYPE; - self.maxarmor = PC_MEDIC_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 100; + else + self.maxarmor = PC_MEDIC_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SUPER_NAILGUN; @@ -1811,14 +1886,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_MAXAMMO_CELL; self.armortype = PC_HVYWEAP_MAXARMORTYPE; - self.armorvalue = PC_HVYWEAP_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 300; + else + self.armorvalue = PC_HVYWEAP_MAXARMOR; } else { self.ammo_rockets = PC_HVYWEAP_INITAMMO_ROCKET; self.ammo_nails = PC_HVYWEAP_INITAMMO_NAIL; self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL; self.armortype = PC_HVYWEAP_INITARMORTYPE; - self.armorvalue = PC_HVYWEAP_INITARMOR; + if (old_hp_armor) + self.armorvalue = 150; + else + self.armorvalue = PC_HVYWEAP_INITARMOR; } // dispenser needs @@ -1840,7 +1921,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS; self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE; - self.maxarmor = PC_HVYWEAP_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 300; + else + self.maxarmor = PC_HVYWEAP_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SUPER_SHOTGUN; @@ -1857,14 +1941,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_PYRO_MAXAMMO_SHOT; self.ammo_cells = PC_PYRO_MAXAMMO_CELL; self.armortype = PC_PYRO_MAXARMORTYPE; - self.armorvalue = PC_PYRO_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 150; + else + self.armorvalue = PC_PYRO_MAXARMOR; } else { self.ammo_rockets = PC_PYRO_INITAMMO_ROCKET; self.ammo_nails = PC_PYRO_INITAMMO_NAIL; self.ammo_shells = PC_PYRO_INITAMMO_SHOT; self.ammo_cells = PC_PYRO_INITAMMO_CELL; self.armortype = PC_PYRO_INITARMORTYPE; - self.armorvalue = PC_PYRO_INITARMOR; + if (old_hp_armor) + self.armorvalue = 50; + else + self.armorvalue = PC_PYRO_INITARMOR; } // dispenser needs @@ -1886,7 +1976,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_PYRO_INITARMORCLASS; self.armor_allowed = PC_PYRO_MAXARMORTYPE; - self.maxarmor = PC_PYRO_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 150; + else + self.maxarmor = PC_PYRO_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_FLAMETHROWER; @@ -1903,14 +1996,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; self.ammo_cells = PC_CIVILIAN_MAXAMMO_CELL; self.armortype = PC_CIVILIAN_MAXARMORTYPE; - self.armorvalue = PC_CIVILIAN_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 0; + else + self.armorvalue = PC_CIVILIAN_MAXARMOR; } else { self.ammo_rockets = PC_CIVILIAN_INITAMMO_ROCKET; self.ammo_nails = PC_CIVILIAN_INITAMMO_NAIL; self.ammo_shells = PC_CIVILIAN_INITAMMO_SHOT; self.ammo_cells = PC_CIVILIAN_INITAMMO_CELL; self.armortype = PC_CIVILIAN_INITARMORTYPE; - self.armorvalue = PC_CIVILIAN_INITARMOR; + if (old_hp_armor) + self.armorvalue = 0; + else + self.armorvalue = PC_CIVILIAN_INITARMOR; } // dispenser needs @@ -1932,7 +2031,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_CIVILIAN_INITARMORCLASS; self.armor_allowed = PC_CIVILIAN_MAXARMORTYPE; - self.maxarmor = PC_CIVILIAN_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 0; + else + self.maxarmor = PC_CIVILIAN_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_AXE; @@ -1947,14 +2049,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SPY_MAXAMMO_SHOT; self.ammo_cells = PC_SPY_MAXAMMO_CELL; self.armortype = PC_SPY_MAXARMORTYPE; - self.armorvalue = PC_SPY_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 100; + else + self.armorvalue = PC_SPY_MAXARMOR; } else { self.ammo_rockets = PC_SPY_INITAMMO_ROCKET; self.ammo_nails = PC_SPY_INITAMMO_NAIL; self.ammo_shells = PC_SPY_INITAMMO_SHOT; self.ammo_cells = PC_SPY_INITAMMO_CELL; self.armortype = PC_SPY_INITARMORTYPE; - self.armorvalue = PC_SPY_INITARMOR; + if (old_hp_armor) + self.armorvalue = 25; + else + self.armorvalue = PC_SPY_INITARMOR; } // dispenser needs @@ -1976,7 +2084,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_SPY_INITARMORCLASS; self.armor_allowed = PC_SPY_MAXARMORTYPE; - self.maxarmor = PC_SPY_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 100; + else + self.maxarmor = PC_SPY_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_TRANQ; @@ -2000,14 +2111,20 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.ammo_cells = PC_ENGINEER_MAXAMMO_CELL; self.armortype = PC_ENGINEER_MAXARMORTYPE; - self.armorvalue = PC_ENGINEER_MAXARMOR; + if (old_hp_armor) + self.armorvalue = 50; + else + self.armorvalue = PC_ENGINEER_MAXARMOR; } else { self.ammo_rockets = PC_ENGINEER_INITAMMO_ROCKET; self.ammo_nails = PC_ENGINEER_INITAMMO_NAIL; self.ammo_shells = PC_ENGINEER_INITAMMO_SHOT; self.ammo_cells = PC_ENGINEER_INITAMMO_CELL; self.armortype = PC_ENGINEER_INITARMORTYPE; - self.armorvalue = PC_ENGINEER_INITARMOR; + if (old_hp_armor) + self.armorvalue = 25; + else + self.armorvalue = PC_ENGINEER_INITARMOR; } // dispenser needs @@ -2029,7 +2146,10 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_ENGINEER_INITARMORCLASS; self.armor_allowed = PC_ENGINEER_MAXARMORTYPE; - self.maxarmor = PC_ENGINEER_MAXARMOR; + if (old_hp_armor) + self.maxarmor = 50; + else + self.maxarmor = PC_ENGINEER_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_LASER; From 8e29062593dcf1ce9fd340840a209b9730f8d6ef Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 21 Jun 2015 14:57:39 +0200 Subject: [PATCH 0396/2474] Reduce max cells and cell regen for Medic. The reason for this is that the Medic can easily turn into a "cell throwing machine" that aids Engineers in the field. This is not the purpose of the Medic's regenerated cells. --- defs.h | 4 ++-- medic.qc | 27 ++++++++++++++++++--------- status.qc | 4 ++-- weapons.qc | 4 ++-- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/defs.h b/defs.h index 4cd7c389..fae2bd96 100644 --- a/defs.h +++ b/defs.h @@ -895,7 +895,7 @@ #define PC_MEDIC_WEAPONS WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN #define PC_MEDIC_MAXAMMO_SHOT 75 #define PC_MEDIC_MAXAMMO_NAIL 150 -#define PC_MEDIC_MAXAMMO_CELL 100 +#define PC_MEDIC_MAXAMMO_CELL 50 #define PC_MEDIC_MAXAMMO_ROCKET 25 #define PC_MEDIC_MAXAMMO_MEDIKIT 100 #define PC_MEDIC_INITAMMO_SHOT 50 @@ -914,7 +914,7 @@ #define PC_MEDIC_AURA_HEAL_AMOUNT 5 // Amount of health given per aura heal. #define PC_MEDIC_AURA_RANGE 120 // The aura's range #define PC_MEDIC_CELL_REGEN_TIME 1 // Number of seconds between each cell regen. -#define PC_MEDIC_CELL_REGEN_AMOUNT 10 // Amount of cells regenerated each cell regen. +#define PC_MEDIC_CELL_REGEN_PERCENT 10 // Percentage of max cells regenerated each cell regen. #define PC_MEDIC_CELL_REGEN_CD 5 // Seconds to cooldown cell regeneration after healing with medikit. #define PC_MEDIC_SAVEME_GRACE 5 // Seconds after which /saveme gives grace period to medikit (no cell regeneration cooldown) diff --git a/medic.qc b/medic.qc index 91b03527..0221ebcb 100644 --- a/medic.qc +++ b/medic.qc @@ -42,7 +42,7 @@ void () CF_Medic_AuraFindPlayers = { self.nextthink = time + PC_MEDIC_AURA_HEAL_TIME; - if (!self.owner.aura_active || self.owner.ammo_cells < 50) + if (!self.owner.aura_active || self.owner.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) return; e_find = findradius(self.owner.origin, PC_MEDIC_AURA_RANGE); @@ -72,7 +72,7 @@ void () CF_Medic_AuraFindPlayers = { self.owner.aura_healtime = 0; } - self.owner.ammo_cells = self.owner.ammo_cells - 5; + self.owner.ammo_cells = self.owner.ammo_cells - ceil(PC_MEDIC_MAXAMMO_CELL / 20); if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) self.owner.currentammo = self.owner.ammo_cells; }; @@ -80,7 +80,8 @@ void () CF_Medic_AuraFindPlayers = { // increases the medic's cells two times per second // called from tfort.qc:TeamFortress_SetEquipment() void () CF_Medic_RegenerateCells = { - local float f_newcells = self.owner.ammo_cells + min(PC_MEDIC_CELL_REGEN_AMOUNT, (100 - self.owner.ammo_cells)); + local entity oldself; + local float f_newcells = self.owner.ammo_cells + min(ceil(PC_MEDIC_MAXAMMO_CELL * (PC_MEDIC_CELL_REGEN_PERCENT / 100)), ceil(PC_MEDIC_MAXAMMO_CELL - self.owner.ammo_cells)); // don't regenerate cells if not using aura or new medikit if (!medicaura && old_medikit) @@ -94,18 +95,26 @@ void () CF_Medic_RegenerateCells = { self.nextthink = time + PC_MEDIC_CELL_REGEN_TIME; - if (self.owner.ammo_cells < 100) { + if (self.owner.ammo_cells < PC_MEDIC_MAXAMMO_CELL) { self.owner.ammo_cells = f_newcells; - // refresh status bar if cells just hit 100 - if (f_newcells >= 100) + // refresh status bar if cells just hit max + if (f_newcells >= PC_MEDIC_MAXAMMO_CELL) Status_Refresh(self.owner); - else if (f_newcells >= 50 && f_newcells < 60) + else if (f_newcells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2) && f_newcells < ceil(PC_MEDIC_MAXAMMO_CELL / 2 + PC_MEDIC_MAXAMMO_CELL / 10)) Status_Refresh(self.owner); if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) self.owner.currentammo = self.owner.ammo_cells; } + + // Update drop ammo menu if cells are + if ((self.owner.menu_input == Menu_Drop_Input) && (self.owner.ammo_cells >= DROP_CELLS)) { + oldself = self; + self = self.owner; + Menu_Drop(); + self = oldself; + } }; // regenerates the medic's health @@ -118,9 +127,9 @@ void () CF_Medic_Regenerate = { return; } - // only regen if 50 or more cells with new medikit + // only regen if half of max or more cells with new medikit if (!old_medikit) { - if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < 50) { + if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { return; } } else if (self.owner.health >= self.owner.max_health || self.owner.ammo_medikit) { diff --git a/status.qc b/status.qc index 06572ea0..81c11a06 100644 --- a/status.qc +++ b/status.qc @@ -967,9 +967,9 @@ string(entity pl) AuraToString = st = strcat(st, ftos(pl.aura_healamount)); st = strcat(st, " hp"); } - else if (pl.ammo_cells < 50) + else if (pl.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) st = strcat(st, "out of power"); - else if (pl.ammo_cells < 95) + else if (pl.ammo_cells < floor(PC_MEDIC_MAXAMMO_CELL * 0.95)) st = strcat(st, "recharging"); else st = strcat(st, "on"); diff --git a/weapons.qc b/weapons.qc index 4c3dedf5..599b499c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -523,7 +523,7 @@ void () W_FireMedikit = { } else if (trace_ent.health < (trace_ent.max_health + 50)) { - if (self.ammo_cells >= 50) { + if (self.ammo_cells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { healam = trace_ent.max_health - trace_ent.health + 50; self.ammo_cells = 0; if (trace_ent.saveme_time <= (time - PC_MEDIC_SAVEME_GRACE)) @@ -532,7 +532,7 @@ void () W_FireMedikit = { } else { healam = min(10, ((trace_ent.max_health + 50) - trace_ent.health)); - self.ammo_cells = self.ammo_cells - min(self.ammo_cells, 5); + self.ammo_cells = self.ammo_cells - min(self.ammo_cells, ceil((PC_MEDIC_MAXAMMO_CELL / 20))); sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); } From ed196dca592356e7ded4c2f37f86d40fe021eae4 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sun, 21 Jun 2015 14:58:51 +0200 Subject: [PATCH 0397/2474] Add *.patch to .gitignore. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 55ae4690..97a65c12 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ *.lno *.exe *.log -*.bat \ No newline at end of file +*.bat +*.patch From d51630b3c993c5b843d6f9c37e89b615cc85c09d Mon Sep 17 00:00:00 2001 From: drzel Date: Mon, 22 Jun 2015 17:00:08 +0900 Subject: [PATCH 0398/2474] add variables to function parm defs for gmqcc compatibility --- qw.qc | 2 +- sentry.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qw.qc b/qw.qc index 9042e95d..13755a84 100644 --- a/qw.qc +++ b/qw.qc @@ -1,7 +1,7 @@ #include "defs.h" void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate; -typedef void (float) f_void_float; +typedef void (float n) f_void_float; //=========================================================================== // TEAMFORTRESS Defs diff --git a/sentry.qc b/sentry.qc index cf1797bd..cce61644 100644 --- a/sentry.qc +++ b/sentry.qc @@ -9,7 +9,7 @@ void () Sentry_Rotate; float () Sentry_FindTarget; void () Sentry_FoundTarget; void () Sentry_HuntTarget; -void (entity, float) Sentry_Pain; +void (entity e, float f) Sentry_Pain; void () Sentry_Die; float () Sentry_Fire; void () Sentry_MuzzleFlash; From e99abe4788ba6d7f547f0ac4ee8eb48bc26320ec Mon Sep 17 00:00:00 2001 From: drzel Date: Mon, 22 Jun 2015 17:00:08 +0900 Subject: [PATCH 0399/2474] add variables to function parm defs for gmqcc compatibility --- qw.qc | 2 +- sentry.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qw.qc b/qw.qc index 75ce9bcb..db0f55dd 100644 --- a/qw.qc +++ b/qw.qc @@ -1,7 +1,7 @@ #include "defs.h" void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate; -typedef void (float) f_void_float; +typedef void (float n) f_void_float; //=========================================================================== // TEAMFORTRESS Defs diff --git a/sentry.qc b/sentry.qc index cf1797bd..cce61644 100644 --- a/sentry.qc +++ b/sentry.qc @@ -9,7 +9,7 @@ void () Sentry_Rotate; float () Sentry_FindTarget; void () Sentry_FoundTarget; void () Sentry_HuntTarget; -void (entity, float) Sentry_Pain; +void (entity e, float f) Sentry_Pain; void () Sentry_Die; float () Sentry_Fire; void () Sentry_MuzzleFlash; From 459c24a6523473a3b707c56cae37e5b3599b0ba5 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 4 Jul 2015 12:46:46 +0200 Subject: [PATCH 0400/2474] Remove batch files from gitignore. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 97a65c12..57d2a32e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ *.lno *.exe *.log -*.bat *.patch From c8752ee09fcab0000c34a4ef6deebd3d7ee6aaf8 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 4 Jul 2015 12:46:57 +0200 Subject: [PATCH 0401/2474] Remove unused dir variable. --- pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyro.qc b/pyro.qc index 336b001c..7a046566 100644 --- a/pyro.qc +++ b/pyro.qc @@ -415,7 +415,7 @@ void () WorldFlame_touch = { void () Flamer_stream_touch = { local entity flame; - local vector vtemp, dir; + local vector vtemp; if (other.classname == "fire") { return; From 9caedfdca543c47113e071adb1837ebd0e8a6a27 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 4 Jul 2015 12:47:13 +0200 Subject: [PATCH 0402/2474] Add gametype serverinfo. This will allow the Classic Fortress client to filter out non-CF servers, since they are not playable anyway. --- world.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/world.qc b/world.qc index ca499767..8d87e362 100644 --- a/world.qc +++ b/world.qc @@ -135,6 +135,7 @@ void () worldspawn = { localcmd("serverinfo cf_rev \""); localcmd(REV); localcmd("\"\n"); + localcmd("serverinfo gametype \"cfortress\"\n"); st = infokey(world, "*sv_gamedir"); if ((st != string_null) && (st != "fortress")) From d180916389829643e6d83df02942764166dc09d1 Mon Sep 17 00:00:00 2001 From: Niclas Lindstedt Date: Sat, 4 Jul 2015 12:47:57 +0200 Subject: [PATCH 0403/2474] Add Windows build batch file. --- gmqcc.bat | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 gmqcc.bat diff --git a/gmqcc.bat b/gmqcc.bat new file mode 100644 index 00000000..8f6504bd --- /dev/null +++ b/gmqcc.bat @@ -0,0 +1,9 @@ +@echo off +for /f "delims=" %%i in ('git rev-parse --short HEAD') do set output=%%i +@echo on +gmqcc -std=fteqcc -fvariadic-args -funtyped-nil -DVER=\"%output%\" -DREV=\"%output%\" +@cp qwprogs.dat "C:\Users\Niclas\Dropbox\Projects\Classic Fortress\Game\server\fortress\qwprogs.dat" +@taskkill /f /im mvdsv.exe 2>nul +@taskkill /f /im ezquake-dev.exe 2>nul +@cd "C:\Users\Niclas\Dropbox\Projects\Classic Fortress\Game\server" +@call "cmd /c start mvdsv.exe" From 1ba3fa38601215aed143b0dfbf1b9ddfd94a0563 Mon Sep 17 00:00:00 2001 From: drzel Date: Fri, 11 Sep 2015 12:52:01 +1000 Subject: [PATCH 0404/2474] add compile instructions to README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ce5ea35d..e2372015 100644 --- a/README.md +++ b/README.md @@ -55,4 +55,8 @@ Classic Fortress v0.1 beta * Fixed broken ammo display. * Fixed endless intermission bug. * Fixed bug where players got stuck in intermission mode upon map change and hence could not respawn. -* Major code cleanup and rewrites. \ No newline at end of file +* Major code cleanup and rewrites. + +=== Compile === +Compile with GMQCC: +gmqcc -std=gmqcc -fftepp From 1d98ddae4bda30dd2096b82f4a23e86fe45ba90a Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 20 Sep 2015 14:56:05 +1000 Subject: [PATCH 0405/2474] disable map voting in clan mode --- vote.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vote.qc b/vote.qc index 7c50f1a1..9ceb649b 100644 --- a/vote.qc +++ b/vote.qc @@ -290,6 +290,10 @@ float () Vote_GetForceNextVotes = { // check if voting should start each frame // called from world.qc:StartFrame() void () Vote_Check = { + + if (clanbattle) + return; + local float closetime = timelimit - CF_MAPVOTE_FINISH; local float decidertime_force = closetime - CF_MAPVOTE_FORCESHOW; local float decidertime = closetime - CF_MAPVOTE_DURATION_DECIDER; From 1f1ae4c72d0ce9e1110496d0f6965eb921256702 Mon Sep 17 00:00:00 2001 From: drzel Date: Mon, 21 Sep 2015 21:18:05 +1000 Subject: [PATCH 0406/2474] dropammo menu is now togglable --- actions.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/actions.qc b/actions.qc index 677017a5..8b37d999 100644 --- a/actions.qc +++ b/actions.qc @@ -28,11 +28,16 @@ void () TeamFortress_Discard = { if (self.playerclass == PC_MEDIC && !medicaura && old_medikit) newmis.ammo_cells = self.ammo_cells; + if (!(newmis.ammo_shells + newmis.ammo_nails + newmis.ammo_rockets + newmis.ammo_cells)) { dremove(newmis); - Menu_Drop(); + if (self.menu_input != Menu_Drop_Input) + Menu_Drop(); + else + Menu_Close(self); return; } + if (newmis.ammo_shells) { self.ammo_shells = 0; } From ae8961706af495006f476179490375defac966c0 Mon Sep 17 00:00:00 2001 From: drzel Date: Mon, 25 Apr 2016 20:59:47 +1000 Subject: [PATCH 0407/2474] reduce dash height to min, add dash.wav --- scout.qc | 4 ++-- world.qc | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scout.qc b/scout.qc index c75b817f..28821fe2 100644 --- a/scout.qc +++ b/scout.qc @@ -32,8 +32,8 @@ void () CF_Scout_Dash = { if (vlen(self.velocity) <= 450 && (self.flags & FL_ONGROUND)) { makevectors(self.angles); self.velocity = v_forward * 540; - self.velocity_z = 190; - sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + self.velocity_z = 181; + sound(self, CHAN_BODY, "dash.wav", 1, ATTN_NORM); } } diff --git a/world.qc b/world.qc index 8d87e362..c7a8998f 100644 --- a/world.qc +++ b/world.qc @@ -168,6 +168,7 @@ void () worldspawn = { precache_sound("misc/h2ohit1.wav"); precache_sound("items/itembk2.wav"); precache_sound("player/plyrjmp8.wav"); + precache_sound("dash.wav"); precache_sound("player/land.wav"); precache_sound("player/land2.wav"); precache_sound("player/drown1.wav"); From bb03ccd4688d488a4ac98a559f35f886f4a8308e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 6 May 2018 21:17:40 +1000 Subject: [PATCH 0408/2474] Put newline after items in command --- tfort.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tfort.qc b/tfort.qc index 49c499bf..3e5ccbed 100644 --- a/tfort.qc +++ b/tfort.qc @@ -457,10 +457,10 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, "\n"); } if (self.tf_items & NIT_SCANNER) - sprint(self, PRINT_HIGH, "Scanner"); + sprint(self, PRINT_HIGH, "Scanner\n"); if (self.weapons_carried & WEAP_MEDIKIT) - sprint(self, PRINT_HIGH, "Medikit"); + sprint(self, PRINT_HIGH, "Medikit\n"); if (self.weapons_carried & WEAP_DETPACK) { if (self.ammo_detpack > 0) { @@ -468,11 +468,12 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, st, " detpack"); if (self.ammo_detpack > 1) sprint(self, PRINT_HIGH, "s"); + sprint(self, PRINT_HIGH, "\n"); } } if (self.playerclass == PC_SPY && invis_only) { - sprint(self, PRINT_HIGH, "Invisibility device"); + sprint(self, PRINT_HIGH, "Invisibility device\n"); } if (self.armorvalue > 0) From 034df1786b31415e6d1a091c0df36299f969d3ac Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 18 Jun 2018 23:56:01 +1000 Subject: [PATCH 0409/2474] Make NG and SNG nail velocity 1500 units instead of 1000. --- tsoldier.qc | 1 + weapons.qc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tsoldier.qc b/tsoldier.qc index b404c9a2..77623476 100644 --- a/tsoldier.qc +++ b/tsoldier.qc @@ -63,6 +63,7 @@ void () NailGrenadeLaunchNail = { deathmsg = DMSG_GREN_NAIL; launch_spike(self.origin, v_forward); + newmis.velocity = v_forward * 1000; newmis.touch = superspike_touch; newmis.weapon = DMSG_GREN_NAIL; diff --git a/weapons.qc b/weapons.qc index 599b499c..765a3699 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1307,7 +1307,7 @@ void (vector org, vector dir) launch_spike = { setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin(newmis, org); - newmis.velocity = dir * 1000; + newmis.velocity = dir * 1500; }; void () W_FireSuperSpikes = { From 45c3e17f948c313eb5fc0ec9e8ecf3bf2530c55e Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 19 Jun 2018 22:43:07 +1000 Subject: [PATCH 0410/2474] Change nailgun velocity to a toggle. Add nailgun original rate of fire and damage. Add toggle for nailgun rate of fire. --- client.qc | 11 +++++++++++ player.qc | 10 ++++++++++ qw.qc | 3 +++ tfort.qc | 4 ++-- weapons.qc | 38 ++++++++++++++++++++++++++++---------- 5 files changed, 54 insertions(+), 12 deletions(-) diff --git a/client.qc b/client.qc index 357402bd..4f4236a2 100644 --- a/client.qc +++ b/client.qc @@ -497,6 +497,13 @@ void () DecodeLevelParms = { ent.think = autoteam_think; } + // fortress one + // use old 1000 unit velocity for nailguns + old_ng_velocity = CF_GetSetting("ongv", "old_ng_velocity", "off"); + + // use old ROF for nailguns + old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); + st = infokey(world, "default"); if (st == "on") { server_default = TRUE; @@ -542,6 +549,8 @@ void () DecodeLevelParms = { sniperreloadpercent = TRUE; buildstatus = TRUE; old_hp_armor = FALSE; + old_ng_velocity = FALSE; + old_ng_rof = FALSE; } st = infokey(world, "faithful"); @@ -588,6 +597,8 @@ void () DecodeLevelParms = { sniperreloadpercent = FALSE; buildstatus = FALSE; old_hp_armor = TRUE; + old_ng_velocity = TRUE; + old_ng_rof = TRUE; } } diff --git a/player.qc b/player.qc index 235cea93..b4d74a3d 100644 --- a/player.qc +++ b/player.qc @@ -339,6 +339,16 @@ void () player_nail2 =[104, player_nail1] { if (self.weaponframe == 9) { self.weaponframe = 1; } + if (!old_ng_rof) { + SuperDamageSound(); + if (self.nailpos == 0) { + W_FireSpikes(4); + self.nailpos = 1; + } else { + W_FireSpikes(-4); + self.nailpos = 0; + } + } Attack_Finished(0.2); }; diff --git a/qw.qc b/qw.qc index db0f55dd..e69ce2a0 100644 --- a/qw.qc +++ b/qw.qc @@ -481,6 +481,9 @@ float old_railgun; float old_dispenser; float old_hp_armor; +float old_ng_velocity; +float old_ng_rof; + .float teamkills; float autokick_time; diff --git a/tfort.qc b/tfort.qc index 3e5ccbed..4a136b53 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2355,10 +2355,10 @@ void () TeamFortress_RemoveTimers = { if (CTF_Map == 1) { if (te.goal_no == 1) { bprint(PRINT_HIGH, self.netname, - " ΜΟΣΤ the ΒΜΥΕ flag!\n"); + " οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); } else if (te.goal_no == 2) { bprint(PRINT_HIGH, self.netname, - " ΜΟΣΤ the ΕΔ flag!\n"); + " οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); } } } diff --git a/weapons.qc b/weapons.qc index 765a3699..e24b34c3 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1307,7 +1307,10 @@ void (vector org, vector dir) launch_spike = { setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin(newmis, org); - newmis.velocity = dir * 1500; + if (old_ng_velocity) + newmis.velocity = dir * 1000; + else + newmis.velocity = dir * 1500; }; void () W_FireSuperSpikes = { @@ -1315,7 +1318,10 @@ void () W_FireSuperSpikes = { sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); - self.ammo_nails = self.ammo_nails - 4; + if (old_ng_rof) + self.ammo_nails = self.ammo_nails - 4; + else + self.ammo_nails = self.ammo_nails - 2; self.currentammo = self.ammo_nails; dir = aim(self, 1000); launch_spike(self.origin + '0 0 16', dir); @@ -1330,7 +1336,7 @@ void (float ox) W_FireSpikes = { local vector dir; makevectors(self.v_angle); - if ((self.ammo_nails >= 4) && + if (((self.ammo_nails >= 4) || ((self.ammo_nails >= 2) && !old_ng_rof)) && (self.current_weapon == WEAP_SUPER_NAILGUN)) { W_FireSuperSpikes(); return; @@ -1340,7 +1346,7 @@ void (float ox) W_FireSpikes = { return; } sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); - if (self.ammo_nails == 1) { + if ((self.ammo_nails == 1) || !old_ng_rof) { self.ammo_nails = self.ammo_nails - 1; self.currentammo = self.ammo_nails; } else { @@ -1369,12 +1375,18 @@ void () spike_touch = { if (other.takedamage) { spawn_touchblood(9); deathmsg = self.weapon; - if (self.owner.classname == "grenade") + if (self.owner.classname == "grenade") { TF_T_Damage(other, self, self.owner.owner, 9, TF_TD_NOTTEAM, TF_TD_NAIL); - else - TF_T_Damage(other, self, self.owner, 18, TF_TD_NOTTEAM, + } else { + if (old_ng_rof) { + TF_T_Damage(other, self, self.owner, 18, TF_TD_NOTTEAM, + TF_TD_NAIL); + } else { + TF_T_Damage(other, self, self.owner, 9, TF_TD_NOTTEAM, TF_TD_NAIL); + } + } } else { WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); if (self.classname == "wizspike") @@ -1411,10 +1423,16 @@ void () superspike_touch = { if (other.takedamage) { spawn_touchblood(18); deathmsg = self.weapon; - if (deathmsg == DMSG_GREN_NAIL) + if (deathmsg == DMSG_GREN_NAIL) { ndmg = 40; - else - ndmg = 26; + } + else { + if (old_ng_rof) { + ndmg = 13; + } else { + ndmg = 26; + } + } if (self.owner.classname == "grenade") TF_T_Damage(other, self, self.owner.owner, ndmg, TF_TD_NOTTEAM, From 5cf2ab7aeff449d68ca2b660b0b378ab4ce45e3d Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 26 Jul 2018 20:41:02 +1000 Subject: [PATCH 0411/2474] change fixed velocity to item that can be defined in serverinfo --- client.qc | 6 +++--- qw.qc | 2 +- weapons.qc | 5 +---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/client.qc b/client.qc index 4f4236a2..de6f6403 100644 --- a/client.qc +++ b/client.qc @@ -499,7 +499,7 @@ void () DecodeLevelParms = { // fortress one // use old 1000 unit velocity for nailguns - old_ng_velocity = CF_GetSetting("ongv", "old_ng_velocity", "off"); + ng_velocity = CF_GetSetting("ngv", "ng_velocity", "1500"); // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); @@ -549,7 +549,7 @@ void () DecodeLevelParms = { sniperreloadpercent = TRUE; buildstatus = TRUE; old_hp_armor = FALSE; - old_ng_velocity = FALSE; + ng_velocity = 1500; old_ng_rof = FALSE; } @@ -597,7 +597,7 @@ void () DecodeLevelParms = { sniperreloadpercent = FALSE; buildstatus = FALSE; old_hp_armor = TRUE; - old_ng_velocity = TRUE; + ng_velocity = 1000; old_ng_rof = TRUE; } diff --git a/qw.qc b/qw.qc index e69ce2a0..d59cbc12 100644 --- a/qw.qc +++ b/qw.qc @@ -481,7 +481,7 @@ float old_railgun; float old_dispenser; float old_hp_armor; -float old_ng_velocity; +float ng_velocity; float old_ng_rof; .float teamkills; diff --git a/weapons.qc b/weapons.qc index e24b34c3..64cd2a22 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1307,10 +1307,7 @@ void (vector org, vector dir) launch_spike = { setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin(newmis, org); - if (old_ng_velocity) - newmis.velocity = dir * 1000; - else - newmis.velocity = dir * 1500; + newmis.velocity = dir * ng_velocity; }; void () W_FireSuperSpikes = { From 31fa772cf6f81197a55078de27b493bf1869c480 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 26 Jul 2018 20:56:57 +1000 Subject: [PATCH 0412/2474] Make ng/sng damage a serverinfo variable. Fix bug that was making SNG double damage on new ROF and half damage on old ROF --- client.qc | 2 ++ qw.qc | 2 ++ weapons.qc | 8 ++++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client.qc b/client.qc index de6f6403..eaa5a6e9 100644 --- a/client.qc +++ b/client.qc @@ -500,6 +500,8 @@ void () DecodeLevelParms = { // fortress one // use old 1000 unit velocity for nailguns ng_velocity = CF_GetSetting("ngv", "ng_velocity", "1500"); + ng_damage = CF_GetSetting("ngd", "ng_damage", "9"); + sng_damage = CF_GetSetting("sngd", "sng_damage", "13"); // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); diff --git a/qw.qc b/qw.qc index d59cbc12..3d329f0d 100644 --- a/qw.qc +++ b/qw.qc @@ -482,6 +482,8 @@ float old_dispenser; float old_hp_armor; float ng_velocity; +float ng_damage; +float sng_damage; float old_ng_rof; .float teamkills; diff --git a/weapons.qc b/weapons.qc index 64cd2a22..bea92352 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1377,10 +1377,10 @@ void () spike_touch = { TF_TD_NAIL); } else { if (old_ng_rof) { - TF_T_Damage(other, self, self.owner, 18, TF_TD_NOTTEAM, + TF_T_Damage(other, self, self.owner, ng_damage * 2, TF_TD_NOTTEAM, TF_TD_NAIL); } else { - TF_T_Damage(other, self, self.owner, 9, TF_TD_NOTTEAM, + TF_T_Damage(other, self, self.owner, ng_damage, TF_TD_NOTTEAM, TF_TD_NAIL); } } @@ -1425,9 +1425,9 @@ void () superspike_touch = { } else { if (old_ng_rof) { - ndmg = 13; + ndmg = sng_damage * 2; } else { - ndmg = 26; + ndmg = sng_damage; } } From 97169f41279242d7aa10ef692028a9e7cb7ce561 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 29 Jul 2018 15:50:46 +1000 Subject: [PATCH 0413/2474] remove multiplier of damage if old rof is used --- weapons.qc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/weapons.qc b/weapons.qc index bea92352..7552e5a2 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1376,13 +1376,8 @@ void () spike_touch = { TF_T_Damage(other, self, self.owner.owner, 9, TF_TD_NOTTEAM, TF_TD_NAIL); } else { - if (old_ng_rof) { - TF_T_Damage(other, self, self.owner, ng_damage * 2, TF_TD_NOTTEAM, - TF_TD_NAIL); - } else { - TF_T_Damage(other, self, self.owner, ng_damage, TF_TD_NOTTEAM, - TF_TD_NAIL); - } + TF_T_Damage(other, self, self.owner, ng_damage, TF_TD_NOTTEAM, + TF_TD_NAIL); } } else { WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); @@ -1424,11 +1419,7 @@ void () superspike_touch = { ndmg = 40; } else { - if (old_ng_rof) { - ndmg = sng_damage * 2; - } else { - ndmg = sng_damage; - } + ndmg = sng_damage; } if (self.owner.classname == "grenade") From db5f19bf998ba15477f414dd9d5030f9c9dc2d97 Mon Sep 17 00:00:00 2001 From: Nathan Shorter <7834850+greatn8@users.noreply.github.com> Date: Thu, 2 Aug 2018 18:48:16 +1000 Subject: [PATCH 0414/2474] Update pyro.qc reduce pyro knockback if not sentry gun or dispenser new velocity addition adjusted by factor of 100 --- pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyro.qc b/pyro.qc index 7a046566..4124f7ee 100644 --- a/pyro.qc +++ b/pyro.qc @@ -427,7 +427,7 @@ void () Flamer_stream_touch = { if (flame_knockback) { // knockback target if (other.classname != "building_sentrygun" && other.classname != "building_dispenser") { - other.velocity = other.velocity + self.velocity / 2; + other.velocity = other.velocity + self.velocity / 200; } } From 57e7cc6fe487ef5f9f46062f47851feb0aca0d1c Mon Sep 17 00:00:00 2001 From: Nathan Shorter <7834850+greatn8@users.noreply.github.com> Date: Thu, 2 Aug 2018 20:03:31 +1000 Subject: [PATCH 0415/2474] Update pyro.qc factor 10 change only --- pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyro.qc b/pyro.qc index 4124f7ee..23123a28 100644 --- a/pyro.qc +++ b/pyro.qc @@ -427,7 +427,7 @@ void () Flamer_stream_touch = { if (flame_knockback) { // knockback target if (other.classname != "building_sentrygun" && other.classname != "building_dispenser") { - other.velocity = other.velocity + self.velocity / 200; + other.velocity = other.velocity + self.velocity / 20; } } From 522843a8e7ffe17bd49740e4665fa1aca1570e4e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 10 Aug 2018 18:57:48 +1000 Subject: [PATCH 0416/2474] Update README to explain how to disable gren timers without using ClassicFortress ezQuake fork --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b109a6e..e2efaf86 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ New features * Auto ID feature (cf\_autoid 1 = on, 2 = teammates only, 3 = enemies only). * Show friendly Sentry Gun health in /id for Engineers. * Show max health and max armor in /id for Medics and Engineers. -* Grenade timers (disable with /cf\_notimers 1 = no timers, 2 = no timer sound). +* Grenade timers (disable with `setinfo nt 1` for no timers, or `setinfo nt 2` for no timer sound). * Grenade slot switching (/grenswitch). * Prime/throw grenades with one button (/gren1 and /gren2). * Weapon slots (1-4) where 1 is always primary and 4 is always melee. From cd013060fa2096c57137d05b67e9df985258cd82 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 10 Aug 2018 23:52:55 +1000 Subject: [PATCH 0417/2474] Don't show motd or select team menu for observer --- menu.qc | 3 ++- tforthlp.qc | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/menu.qc b/menu.qc index 53556a32..06fad610 100644 --- a/menu.qc +++ b/menu.qc @@ -165,7 +165,8 @@ void (float update) Menu_Team = { local entity timer; if (self.classname == "observer") - Status_Menu(self, Menu_Team_Input, ""); + /* Status_Menu(self, Menu_Team_Input, ""); */ + return; // allow toggling team menu using any method to show it if (!update && self.menu_input == Menu_Team_Input) { diff --git a/tforthlp.qc b/tforthlp.qc index 909326f5..829ddff8 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -9,6 +9,9 @@ void (float inp) MOTD_Input = { }; void () TeamFortress_MOTD = { + if (self.classname == "observer") + return; + local string st1; local string st2; local string ya; From 2b24a66d1bfdd7e0abc302df7fafc05424ca4ace Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 16 Aug 2018 23:53:59 +1000 Subject: [PATCH 0418/2474] Make compilable with fteqcc (due to a bug in compiler) --- status.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/status.qc b/status.qc index 81c11a06..ece3d978 100644 --- a/status.qc +++ b/status.qc @@ -787,7 +787,7 @@ string(entity pl) ClipSizeToString = num = (max - pl.reload_super_shotgun); } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { if (!sniperreload) - return (""); + return ""; if ((max - pl.reload_sniper_rifle) > pl.ammo_shells) pl.reload_sniper_rifle = max - pl.ammo_shells; num = (max - pl.reload_sniper_rifle); @@ -800,7 +800,7 @@ string(entity pl) ClipSizeToString = pl.reload_rocket_launcher = (max - pl.ammo_rockets); num = (max - pl.reload_rocket_launcher); } else - return (""); + return ""; if (num > 99) num = 99; From c4e45b015324cd0c3e3f7a3d1b9592e00238060f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 17 Aug 2018 00:55:10 +1000 Subject: [PATCH 0419/2474] Update readme --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index e2efaf86..aa82a332 100644 --- a/README.md +++ b/README.md @@ -127,8 +127,4 @@ Engineer Compilation ------ -Compile with GMQCC: - -```bash -$ gmqcc -std=gmqcc -fftepp -``` +Compile with [FTEQCC](https://sourceforge.net/projects/fteqw/) From 025c4c7d445f496ee633683994bc3f192047088b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 29 Aug 2018 19:15:46 +1000 Subject: [PATCH 0420/2474] Allow underwater detpacks --- demoman.qc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/demoman.qc b/demoman.qc index 78a1e83c..29e763ed 100644 --- a/demoman.qc +++ b/demoman.qc @@ -158,9 +158,12 @@ void (float timer) TeamFortress_SetDetpack = { } at_spot = at_spot.chain; } - if (!(self.flags & FL_ONGROUND)) { - sprint(self, PRINT_HIGH, "You cannot set detpacks in the air\n"); - return; + + if (!self.waterlevel) { + if (!(self.flags & FL_ONGROUND)) { + sprint(self, PRINT_HIGH, "You cannot set detpacks in the air\n"); + return; + } } te = find(world, classname, "detpack"); From e61614abb785740465810e699b830e80d483f874 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 29 Aug 2018 23:51:32 +1000 Subject: [PATCH 0421/2474] Don't allow building during prematch --- engineer.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/engineer.qc b/engineer.qc index 537bdd30..7648747f 100644 --- a/engineer.qc +++ b/engineer.qc @@ -346,6 +346,11 @@ float (entity obj, entity builder) CheckArea = { }; void (float objtobuild) TeamFortress_Build = { + if (cb_prematch_time > time) { + sprint(self, PRINT_MEDIUM, "You cannot build during prematch\n"); + return; + } + local float btime; local vector tmp1; local vector tmp2; From 20a6ba11d6a1673858f364a221205083581d907b Mon Sep 17 00:00:00 2001 From: gmtandi Date: Wed, 5 Sep 2018 10:57:32 -0300 Subject: [PATCH 0422/2474] Fix for building with fteqcc --- vote.qc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/vote.qc b/vote.qc index 9ceb649b..da4edb43 100644 --- a/vote.qc +++ b/vote.qc @@ -956,30 +956,31 @@ string () Vote_GetWinner = { // called from Vote_SetupVote(), Vote_GetWinner() string () Vote_GetWinnerList = { local string s_maplist; + local string s_tmp; s_maplist = strzone(""); if (vote1_cnt) { - local string s_tmp = s_maplist; + s_tmp = s_maplist; s_maplist = strzone(strcat(s_maplist, strcat(vote1_map, " "))); strunzone(s_tmp); } if (vote2_cnt) { - local string s_tmp = s_maplist; + s_tmp = s_maplist; s_maplist = strzone(strcat(s_maplist, strcat(vote2_map, " "))); strunzone(s_tmp); } if (vote3_cnt) { - local string s_tmp = s_maplist; + s_tmp = s_maplist; s_maplist = strzone(strcat(s_maplist, strcat(vote3_map, " "))); strunzone(s_tmp); } if (vote4_cnt) { - local string s_tmp = s_maplist; + s_tmp = s_maplist; s_maplist = strzone(strcat(s_maplist, strcat(vote4_map, " "))); strunzone(s_tmp); } if (vote5_cnt) { - local string s_tmp = s_maplist; + s_tmp = s_maplist; s_maplist = strzone(strcat(s_maplist, vote5_map)); strunzone(s_tmp); } From 0dea33605b4eb73b52b387d5c54b3f71390121de Mon Sep 17 00:00:00 2001 From: gmtandi Date: Wed, 5 Sep 2018 12:19:26 -0300 Subject: [PATCH 0423/2474] added demo recording (localinfo serverdemo on) --- clan.qc | 24 ++++++++++++++++++++++++ defs.qc | 13 +++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/clan.qc b/clan.qc index 30f13555..e3864684 100644 --- a/clan.qc +++ b/clan.qc @@ -38,6 +38,30 @@ void () PreMatch_Think = { if (game_locked) bprint(PRINT_HIGH, "Game is now locked\n"); + + if (infokey (world, "serverdemo") == "on") + { + calltimeofday (); + + localcmd ("record \""); + localcmd (ftos (tod_day)); // day + localcmd ("-"); + localcmd (ftos (tod_mon)); // month + localcmd ("-"); + localcmd (ftos (tod_year)); // year + localcmd ("_"); + localcmd (ftos (tod_hour)); // hour + localcmd ("-"); + localcmd (ftos (tod_min)); // minute + localcmd ("-"); + localcmd (ftos (tod_sec)); // second + + localcmd ("_["); + localcmd (mapname); + localcmd ("]"); + localcmd ("\"\n"); + } + team4score = 0; team3score = 0; team2score = 0; diff --git a/defs.qc b/defs.qc index 373b72a5..4303dac0 100644 --- a/defs.qc +++ b/defs.qc @@ -423,8 +423,17 @@ float (float x, float y) pow = #97; float (string s) strlen = #114; string (string s1, string s2) strcat = #115; string (string s, float start, float count) substr = #116; -string (string s) strzone = #118; -void (string s) strunzone = #119; +string (string s, ...) strzone = #118; +void (string s, ...) strunzone = #119; + +void() calltimeofday = #231; // force server to call mod function timeofday + +//In order to make it more useful, this header includes a timeofday function which just grabs the values for you to use in your qc code straight after calling calltimeofday. +float tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; + +//This function is to facilitate use, and need not be modified. +void(float s, float mi, float h, float d, float mo, float y, string tmp_timeofday) timeofday = +{ tod_sec = s; tod_min = mi; tod_hour = h; tod_day = d; tod_mon = mo; tod_year = y; }; //============================================================================ From 9539ecb0a75858d3abdb5521dad42289a8de80eb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 8 Sep 2018 22:59:12 +1000 Subject: [PATCH 0424/2474] Update docs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index aa82a332..6179c2b8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ Classic Fortress v0.9 beta New features ------ +* Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. * Map vote (4 random maps + current map) during last few minutes of game (shown for newly spawned or toggled with /togglevote). * Force early map vote using /votenext, /votetrick (trick maps) and /voterace (race maps). * Force map switch to the voted map early using /forcenext. From 32ee96141c8a23a1a255878b55fb20195490894c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 8 Sep 2018 23:58:42 +1000 Subject: [PATCH 0425/2474] Ignore compiler --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 57d2a32e..0214f2f2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.exe *.log *.patch +fteqcc64 From 719d3f177bc407851feb92f3551cac4ae0345449 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 9 Sep 2018 15:14:53 +1000 Subject: [PATCH 0426/2474] Update Makefile to use fteqcc64 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dd8a2f3d..cb154967 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ ifndef REV endif all: - gmqcc -std=fteqcc -fvariadic-args -funtyped-nil -DVER=\"$(VER)\" -DREV=\"$(REV)\" + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" clean: rm -f $(TARGET) qwprogs.lno files.dat progdefs.h From 89ee55045996c1e66a42ff676285bf50461af35f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 9 Sep 2018 16:00:46 +1000 Subject: [PATCH 0427/2474] Don't override sounds with backpack noise --- tfortmap.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index 461abf62..c974d37a 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -832,7 +832,6 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { self = Player; TeamFortress_CheckClassStats(); W_SetCurrentAmmo(self); - sound(self, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); self = oldself; } if ((Player.playerclass == PC_SPY) && From 9f790084ccdf4b171197da4558de9c22e6245be6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 10 Sep 2018 00:21:26 +1000 Subject: [PATCH 0428/2474] Gas don't go through walls --- spy.qc | 88 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/spy.qc b/spy.qc index 1688c31f..78b2923c 100644 --- a/spy.qc +++ b/spy.qc @@ -972,53 +972,55 @@ void () GasGrenadeMakeGas = { self.nextthink = time + 0.75; te = findradius(self.origin, 200); while (te != world) { - if (((te.classname == "player") && (te.deadflag == 0)) && - (te.has_disconnected != 1)) { - deathmsg = 24; - TF_T_Damage(te, world, self.owner, 10, (1 | 2), 0); - if (te.tfstate & 16384) { - timer = find(world, classname, "timer"); - while (((timer.owner != te) || - (timer.think != HallucinationTimer)) && - (timer != world)) { - timer = find(timer, classname, "timer"); - } - if (timer != world) { - timer.health = timer.health + 25; - if (old_grens == 1) { - if (timer.health < 100) { - timer.health = 100; - } - timer.nextthink = time + 0.5; - } else { - if (timer.health < 150) { - timer.health = 150; + if (CanDamage(te, self)) { + if (((te.classname == "player") && (te.deadflag == 0)) && + (te.has_disconnected != 1)) { + deathmsg = 24; + TF_T_Damage(te, world, self.owner, 10, (1 | 2), 0); + if (te.tfstate & 16384) { + timer = find(world, classname, "timer"); + while (((timer.owner != te) || + (timer.think != HallucinationTimer)) && + (timer != world)) { + timer = find(timer, classname, "timer"); + } + if (timer != world) { + timer.health = timer.health + 25; + if (old_grens == 1) { + if (timer.health < 100) { + timer.health = 100; + } + timer.nextthink = time + 0.5; + } else { + if (timer.health < 150) { + timer.health = 150; + } + timer.nextthink = time + 0.3; } - timer.nextthink = time + 0.3; } - } - } else { - if (old_grens == 1) { - stuffcmd(te, "v_cshift 50 25 50 -50\n"); - sprint(te, PRINT_HIGH, "Far out man!\n"); } else { - sprint(te, PRINT_HIGH, - "Run for cover! They are everywhere!\n"); + if (old_grens == 1) { + stuffcmd(te, "v_cshift 50 25 50 -50\n"); + sprint(te, PRINT_HIGH, "Far out man!\n"); + } else { + sprint(te, PRINT_HIGH, + "Run for cover! They are everywhere!\n"); + } + te.tfstate = te.tfstate | TFSTATE_HALLUCINATING; + timer = spawn(); + if (old_grens == 1) + timer.nextthink = time + 0.5; + else + timer.nextthink = time + 0.3; + timer.think = HallucinationTimer; + timer.classname = "timer"; + timer.owner = te; + if (old_grens == 1) + timer.health = 100; + else + timer.health = 150; + timer.team_no = self.team_no; } - te.tfstate = te.tfstate | TFSTATE_HALLUCINATING; - timer = spawn(); - if (old_grens == 1) - timer.nextthink = time + 0.5; - else - timer.nextthink = time + 0.3; - timer.think = HallucinationTimer; - timer.classname = "timer"; - timer.owner = te; - if (old_grens == 1) - timer.health = 100; - else - timer.health = 150; - timer.team_no = self.team_no; } } te = te.chain; From 43e27db921c98ad6d9e1d87b86bebaaf672aabaa Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 10 Sep 2018 18:09:42 +1000 Subject: [PATCH 0429/2474] Update readme regarding localinfo stockfull --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6179c2b8..4eb4c1b8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ Classic Fortress v0.9 beta New features ------ +* Option for packs to fully restock health and armour of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. * Map vote (4 random maps + current map) during last few minutes of game (shown for newly spawned or toggled with /togglevote). * Force early map vote using /votenext, /votetrick (trick maps) and /voterace (race maps). From 8a877ca1180df2c37fca539ed2fc123120a9be92 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 10 Sep 2018 18:20:05 +1000 Subject: [PATCH 0430/2474] Add todo at cap point in code --- tfortmap.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tfortmap.qc b/tfortmap.qc index c974d37a..a3a8e7c6 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -683,6 +683,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player == AP) { if (Goal.count > 0) { if (Player.team_no > 0) { + // TODO: Restock player TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count); TeamFortress_TeamShowScores(2); Player.caps = Player.caps + 1; From c6a94dd7adeeede98b40e1b2aad6fd6eb7f9781d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Sep 2018 15:25:00 +1000 Subject: [PATCH 0431/2474] Fix clan auto demo timestamp --- clan.qc | 1 - defs.qc | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clan.qc b/clan.qc index e3864684..37c5b4f0 100644 --- a/clan.qc +++ b/clan.qc @@ -1,4 +1,3 @@ - void () PreMatch_Think = { local float time_left; local string st; diff --git a/defs.qc b/defs.qc index 4303dac0..3a6e203b 100644 --- a/defs.qc +++ b/defs.qc @@ -423,8 +423,8 @@ float (float x, float y) pow = #97; float (string s) strlen = #114; string (string s1, string s2) strcat = #115; string (string s, float start, float count) substr = #116; -string (string s, ...) strzone = #118; -void (string s, ...) strunzone = #119; +string (string s, ...) strzone = #118; +void (string s, ...) strunzone = #119; void() calltimeofday = #231; // force server to call mod function timeofday @@ -433,7 +433,7 @@ float tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; //This function is to facilitate use, and need not be modified. void(float s, float mi, float h, float d, float mo, float y, string tmp_timeofday) timeofday = -{ tod_sec = s; tod_min = mi; tod_hour = h; tod_day = d; tod_mon = mo; tod_year = y; }; +{ tod_sec = s; tod_min = mi; tod_hour = h; tod_day = d; tod_mon = (mo + 1); tod_year = y; }; //============================================================================ From c30ce4cbb9780cd7f70de71da492eeb17e31f7e0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Sep 2018 19:09:28 +1000 Subject: [PATCH 0432/2474] Update compile instructions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 4eb4c1b8..f0f32aa0 100644 --- a/README.md +++ b/README.md @@ -130,3 +130,9 @@ Engineer Compilation ------ Compile with [FTEQCC](https://sourceforge.net/projects/fteqw/) + +Ensure that `fteqcc64` is available in `$PATH` and: + +``` +$ make +``` From 69c8eda536cc01552070a60237667d706509eedd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Sep 2018 20:10:01 +1000 Subject: [PATCH 0433/2474] Reindent --- tfortmap.qc | 172 ++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index a3a8e7c6..17ba5b7e 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -166,17 +166,17 @@ void (entity Goal) UpdateAbbreviations = flagem_checked = 1; } if ((toggleflags & TFLAG_FLAGEMU) && - !(toggleflags & TFLAG_WARSTANDARD)) { + !(toggleflags & TFLAG_WARSTANDARD)) { if ((Goal.mdl == "progs/b_s_key.mdl") - || (Goal.mdl == "progs/m_s_key.mdl") - || (Goal.mdl == "progs/w_s_key.mdl")) { + || (Goal.mdl == "progs/m_s_key.mdl") + || (Goal.mdl == "progs/w_s_key.mdl")) { Goal.mdl = "progs/tf_flag.mdl"; Goal.origin_z = Goal.origin_z + 6; Goal.skin = 1; } else if ((Goal.mdl == "progs/b_g_key.mdl") - || (Goal.mdl == "progs/m_g_key.mdl") - || (Goal.mdl == "progs/w_g_key.mdl")) { + || (Goal.mdl == "progs/m_g_key.mdl") + || (Goal.mdl == "progs/w_g_key.mdl")) { Goal.mdl = "progs/tf_flag.mdl"; Goal.origin_z = Goal.origin_z + 6; @@ -185,14 +185,14 @@ void (entity Goal) UpdateAbbreviations = } if (toggleflags & TFLAG_WARSTANDARD) { if ((Goal.mdl == "progs/b_s_key.mdl") - || (Goal.mdl == "progs/m_s_key.mdl") - || (Goal.mdl == "progs/w_s_key.mdl")) { + || (Goal.mdl == "progs/m_s_key.mdl") + || (Goal.mdl == "progs/w_s_key.mdl")) { Goal.mdl = "progs/tf_stan.mdl"; Goal.skin = 1; } else if ((Goal.mdl == "progs/b_g_key.mdl") - || (Goal.mdl == "progs/m_g_key.mdl") - || (Goal.mdl == "progs/w_g_key.mdl")) { + || (Goal.mdl == "progs/m_g_key.mdl") + || (Goal.mdl == "progs/w_g_key.mdl")) { Goal.mdl = "progs/tf_stan.mdl"; Goal.skin = 2; @@ -289,10 +289,10 @@ float () CheckExistence = { return (FALSE); } if ((self.ex_skill_min && (self.ex_skill_min != -1)) && - (skill < self.ex_skill_min)) { + (skill < self.ex_skill_min)) { return (FALSE); } else if ((self.ex_skill_max && (self.ex_skill_max != -1)) && - (skill > self.ex_skill_max)) { + (skill > self.ex_skill_max)) { return (FALSE); } return (TRUE); @@ -585,7 +585,7 @@ void (entity Goal) InactivateGoal = { if (Goal.goal_state == 1) { if (Goal.search_time == 0) { if ((Goal.goal_activation & 8192) && - (Goal.classname == "item_tfgoal")) + (Goal.classname == "item_tfgoal")) Goal.solid = SOLID_BBOX; else Goal.solid = SOLID_TRIGGER; @@ -600,7 +600,7 @@ void (entity Goal) RestoreGoal = { if (Goal.goal_state == 3) { if (Goal.search_time == 0) { if ((Goal.goal_activation & 8192) && - (Goal.classname == "item_tfgoal")) { + (Goal.classname == "item_tfgoal")) { Goal.solid = 2; } else { Goal.solid = 1; @@ -661,11 +661,11 @@ float (entity Goal, entity Player, entity AP) IsAffectedBy = { } } if ((Goal.maxammo_shells != 0) && - (Player.team_no == Goal.maxammo_shells)) { + (Player.team_no == Goal.maxammo_shells)) { return (1); } if ((Goal.maxammo_nails != 0) && - (Player.team_no != Goal.maxammo_shells)) { + (Player.team_no != Goal.maxammo_shells)) { return (1); } return (0); @@ -683,7 +683,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player == AP) { if (Goal.count > 0) { if (Player.team_no > 0) { - // TODO: Restock player + // TODO: Restock player TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count); TeamFortress_TeamShowScores(2); Player.caps = Player.caps + 1; @@ -701,10 +701,10 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Goal.health < 0) { if ((0 - Player.health) > Goal.health) { TF_T_Damage(Player, Goal, Goal, (Player.health + 1), 1, - 0); + 0); } else { TF_T_Damage(Player, Goal, Goal, (0 - Goal.health), 1, - 0); + 0); } } } @@ -745,11 +745,11 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.no_grenades_2 = 4; } if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > 2)) { + (Player.no_grenades_1 > 2)) { Player.no_grenades_1 = 2; } if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > 2)) { + (Player.no_grenades_2 > 2)) { Player.no_grenades_2 = 2; } if (Player.ammo_detpack > Player.maxammo_detpack) { @@ -760,7 +760,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { while (te) { if (te.owner == Player) { if ((te.impulse == TF_GRENADE_2) && - (Player.no_grenades_2 <= 0)) { + (Player.no_grenades_2 <= 0)) { Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_GRENPRIMED); @@ -769,7 +769,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { (Player.tfstate & TFSTATE_GRENTHROWING); dremove(te); } else if ((te.impulse == TF_GRENADE_1) && - (Player.no_grenades_1 <= 0)) { + (Player.no_grenades_1 <= 0)) { Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_GRENPRIMED); @@ -826,7 +826,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.lives = Player.lives + Goal.lives; if (Goal.frags) { if ((Goal.goal_effects == TFGE_AP) || - !(toggleflags & TFLAG_FULLTEAMSCORE)) + !(toggleflags & TFLAG_FULLTEAMSCORE)) TF_AddFrags(Player, Goal.frags); } oldself = self; @@ -836,7 +836,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { self = oldself; } if ((Player.playerclass == PC_SPY) && - (Goal.goal_result & TFGR_REMOVE_DISGUISE)) { + (Goal.goal_result & TFGR_REMOVE_DISGUISE)) { self.immune_to_check = time + 10; Spy_RemoveDisguise(Player); } @@ -854,7 +854,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { te = find(world, classname, "item_tfgoal"); while (te) { if ((te.group_no == Goal.remove_item_group) && - (te.owner == AP)) { + (te.owner == AP)) { oldte = te; te = find(te, classname, "item_tfgoal"); tfgoalitem_RemoveFromPlayer(oldte, Player, 1); @@ -924,7 +924,7 @@ void (entity Goal, entity Player) RemoveResults = { Player.armorclass - (Player.armorclass & Goal.armorclass); if (Goal.frags) { if ((Goal.goal_effects == TFGE_AP) || - !(toggleflags & TFLAG_FULLTEAMSCORE)) + !(toggleflags & TFLAG_FULLTEAMSCORE)) TF_AddFrags(Player, Goal.frags); } Player.ammo_shells = Player.ammo_shells - Goal.ammo_shells; @@ -943,10 +943,10 @@ void (entity Goal, entity Player) RemoveResults = { Player.no_grenades_2 = 4; if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > 2)) + (Player.no_grenades_1 > 2)) Player.no_grenades_1 = 2; if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > 2)) + (Player.no_grenades_2 > 2)) Player.no_grenades_2 = 2; if (Player.ammo_detpack > Player.maxammo_detpack) @@ -957,7 +957,7 @@ void (entity Goal, entity Player) RemoveResults = { while (te) { if (te.owner == Player) { if ((te.impulse == TF_GRENADE_2) && - (Player.no_grenades_2 <= 0)) { + (Player.no_grenades_2 <= 0)) { Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_GRENPRIMED); @@ -966,7 +966,7 @@ void (entity Goal, entity Player) RemoveResults = { (Player.tfstate & TFSTATE_GRENTHROWING); dremove(te); } else if ((te.impulse == TF_GRENADE_1) && - (Player.no_grenades_1 <= 0)) { + (Player.no_grenades_1 <= 0)) { Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_GRENPRIMED); @@ -1100,7 +1100,7 @@ float (entity Goal, entity AP) APMeetsCriteria = { te = Finditem(Goal.if_item_has_moved); if (te) { if ((te.goal_state != TFGS_ACTIVE) && - (te.origin == te.oldorigin)) + (te.origin == te.oldorigin)) return (0); } } @@ -1108,7 +1108,7 @@ float (entity Goal, entity AP) APMeetsCriteria = { te = Finditem(Goal.if_item_hasnt_moved); if (te) { if ((te.goal_state == TFGS_ACTIVE) || - (te.origin != te.oldorigin)) + (te.origin != te.oldorigin)) return (0); } } @@ -1118,7 +1118,7 @@ float (entity Goal, entity AP) APMeetsCriteria = { te = find(world, classname, "item_tfgoal"); while ((te != world) && !gotone) { if ((te.group_no == Goal.has_item_from_group) && - (te.owner == AP)) + (te.owner == AP)) gotone = 1; te = find(te, classname, "item_tfgoal"); } @@ -1129,7 +1129,7 @@ float (entity Goal, entity AP) APMeetsCriteria = { te = find(world, classname, "item_tfgoal"); while ((te != world) && !gotone) { if ((te.group_no == Goal.hasnt_item_from_group) && - (te.owner == AP)) + (te.owner == AP)) return (0); te = find(te, classname, "item_tfgoal"); } @@ -1541,32 +1541,32 @@ void (entity Goal, entity AP, float addb) DoResults = { winners = random(); if (winners < 0.1) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\nFlee!"); + "You got the enemy flag!\n\nFlee!"); } else { if (winners < 0.2) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\nHead for home!"); + "You got the enemy flag!\n\nHead for home!"); } else { if (winners < 0.6) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\nReturn to base!"); + "You got the enemy flag!\n\nReturn to base!"); } else { if (winners < 0.7) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\n"); + "You got the enemy flag!\n\n"); } else { if (winners < 0.8) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\n"); + "You got the enemy flag!\n\n"); } else { if (winners < 0.95) { CenterPrint2(te, - "\n\n\n", - "You got the enemy flag!\n\n"); + "\n\n\n", + "You got the enemy flag!\n\n"); } else { CenterPrint2(te, - "\n\n\n", - "Is that a flag in your pocket\nor a you just happy to see me?"); + "\n\n\n", + "Is that a flag in your pocket\nor a you just happy to see me?"); } } } @@ -1575,11 +1575,11 @@ void (entity Goal, entity AP, float addb) DoResults = { } } else { CenterPrint2(te, "\n\n\n", - "Your team ΗΟΤ the ΕΞΕΝΩ flag!!"); + "Your team ΗΟΤ the ΕΞΕΝΩ flag!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your flag has been ΤΑΛΕΞ!!"); + "Your flag has been ΤΑΛΕΞ!!"); } te = find(te, classname, "player"); } @@ -1594,33 +1594,33 @@ void (entity Goal, entity AP, float addb) DoResults = { winners = random(); if (winners < 0.1) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\nFlee!"); + "You got the enemy flag!\n\nFlee!"); } else { if (winners < 0.2) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\nHead for home!"); + "You got the enemy flag!\n\nHead for home!"); } else { if (winners < 0.6) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\nReturn to base!"); + "You got the enemy flag!\n\nReturn to base!"); } else { if (winners < 0.7) { CenterPrint2(te, "\n\n\n", - "You got the enemy flag!\n\n"); + "You got the enemy flag!\n\n"); } else { if (winners < 0.8) { CenterPrint2(te, - "\n\n\n", - "You got the enemy flag!\n\nRed's dead baby, Red's dead..."); + "\n\n\n", + "You got the enemy flag!\n\nRed's dead baby, Red's dead..."); } else { if (winners < 0.95) { CenterPrint2(te, - "\n\n\n", - "You got the enemy flag!\n\n"); + "\n\n\n", + "You got the enemy flag!\n\n"); } else { CenterPrint2(te, - "\n\n\n", - "Is that a flag in your pocket\nor a you just happy to see me?"); + "\n\n\n", + "Is that a flag in your pocket\nor a you just happy to see me?"); } } } @@ -1629,11 +1629,11 @@ void (entity Goal, entity AP, float addb) DoResults = { } } else { CenterPrint2(te, "\n\n\n", - "Your team ΗΟΤ the ΕΞΕΝΩ flag!!"); + "Your team ΗΟΤ the ΕΞΕΝΩ flag!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your flag has been ΤΑΛΕΞ!!"); + "Your flag has been ΤΑΛΕΞ!!"); } te = find(te, classname, "player"); } @@ -1646,19 +1646,19 @@ void (entity Goal, entity AP, float addb) DoResults = { if (te.team_no == 2) { if (te == AP) { CenterPrint2(te, "\n\n\n", - "You ΓΑΠΤΥΕΔ the flag!!"); + "You ΓΑΠΤΥΕΔ the flag!!"); } else { CenterPrint2(te, "\n\n\n", - "Your flag was ΓΑΠΤΥΕΔ!!"); + "Your flag was ΓΑΠΤΥΕΔ!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your team ΓΑΠΤΥΕΔ the flag!!"); + "Your team ΓΑΠΤΥΕΔ the flag!!"); } te = find(te, classname, "player"); } bprint(PRINT_HIGH, AP.netname, - " ΓΑΠΤΥΕΔ the ΕΔ flag!\n"); + " ΓΑΠΤΥΕΔ the ΕΔ flag!\n"); AP.items = AP.items - (AP.items & IT_KEY2); } else { if (Goal.goal_no == 4) { @@ -1667,19 +1667,19 @@ void (entity Goal, entity AP, float addb) DoResults = { if (te.team_no == 1) { if (te == AP) { CenterPrint2(te, "\n\n\n", - "You ΓΑΠΤΥΕΔ the flag!!"); + "You ΓΑΠΤΥΕΔ the flag!!"); } else { CenterPrint2(te, "\n\n\n", - "Your flag was ΓΑΠΤΥΕΔ!!"); + "Your flag was ΓΑΠΤΥΕΔ!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your team ΓΑΠΤΥΕΔ the flag!!"); + "Your team ΓΑΠΤΥΕΔ the flag!!"); } te = find(te, classname, "player"); } bprint(PRINT_HIGH, AP.netname, - " ΓΑΠΤΥΕΔ the ΒΜΥΕ flag!\n"); + " ΓΑΠΤΥΕΔ the ΒΜΥΕ flag!\n"); AP.items = AP.items - (AP.items & IT_KEY1); } } @@ -1703,7 +1703,7 @@ void (entity Goal, entity AP, float addb) DoResults = { } else { if (AP.team_no == te.team_no) { if ((Goal.owners_team_broadcast != string_null) && - (te.team_no == Goal.owned_by)) { + (te.team_no == Goal.owned_by)) { CenterPrint2(te, "\n\n\n", Goal.owners_team_broadcast); } else { if (Goal.team_broadcast != string_null) { @@ -1711,33 +1711,33 @@ void (entity Goal, entity AP, float addb) DoResults = { } } if ((Goal.netname_owners_team_broadcast != string_null) && - (te.team_no == Goal.owned_by)) { + (te.team_no == Goal.owned_by)) { sprint(te, PRINT_HIGH, AP.netname, - Goal.netname_owners_team_broadcast); + Goal.netname_owners_team_broadcast); } else { if (Goal.netname_team_broadcast != string_null) { sprint(te, PRINT_HIGH, AP.netname, - Goal.netname_team_broadcast); + Goal.netname_team_broadcast); } } } else { if ((Goal.owners_team_broadcast != string_null) && - (te.team_no == Goal.owned_by)) { + (te.team_no == Goal.owned_by)) { CenterPrint2(te, "\n\n\n", Goal.owners_team_broadcast); } else { if (Goal.non_team_broadcast != string_null) { CenterPrint2(te, "\n\n\n", - Goal.non_team_broadcast); + Goal.non_team_broadcast); } } if ((Goal.netname_owners_team_broadcast != string_null) && - (te.team_no == Goal.owned_by)) { + (te.team_no == Goal.owned_by)) { sprint(te, PRINT_HIGH, AP.netname, - Goal.netname_owners_team_broadcast); + Goal.netname_owners_team_broadcast); } else { if (Goal.netname_non_team_broadcast != string_null) { sprint(te, PRINT_HIGH, AP.netname, - Goal.netname_non_team_broadcast); + Goal.netname_non_team_broadcast); } } } @@ -1879,10 +1879,10 @@ void () item_tfgoal_touch = { while (te != world) { if (te.team_no == 1) { CenterPrint2(te, "\n\n\n", - "Your flag was ΕΤΥΞΕΔ!!"); + "Your flag was ΕΤΥΞΕΔ!!"); } else { CenterPrint2(te, "\n\n\n", - "The ΕΞΕΝΩ flag was ΕΤΥΞΕΔ!!"); + "The ΕΞΕΝΩ flag was ΕΤΥΞΕΔ!!"); } te = find(te, classname, "player"); } @@ -1910,10 +1910,10 @@ void () item_tfgoal_touch = { while (te != world) { if (te.team_no == 2) { CenterPrint(te, - "\n\n\n Your flag was ΕΤΥΞΕΔ!!"); + "\n\n\n Your flag was ΕΤΥΞΕΔ!!"); } else { CenterPrint(te, - "\n\n\n The ΕΞΕΝΩ flag was ΕΤΥΞΕΔ!!"); + "\n\n\n The ΕΞΕΝΩ flag was ΕΤΥΞΕΔ!!"); } te = find(te, classname, "player"); } @@ -1995,7 +1995,7 @@ void () ReturnItem = { self.enemy.goal_state = 2; if ((self.enemy.goal_activation & 8192) && - (self.enemy.classname == "item_tfgoal")) + (self.enemy.classname == "item_tfgoal")) self.enemy.solid = 2; else self.enemy.solid = 1; @@ -2017,7 +2017,7 @@ void () ReturnItem = { if (self.weapon != 2) { if ((self.enemy.noise3 != string_null) || - (self.enemy.noise4 != string_null)) { + (self.enemy.noise4 != string_null)) { te = find(world, classname, "player"); while (te) { if (te.team_no == self.enemy.owned_by) @@ -2058,7 +2058,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { if (Item.netname_team_drop != string_null) { sprint(te, PRINT_HIGH, AP.netname, - Item.netname_team_drop); + Item.netname_team_drop); } } else { if (Item.non_team_drop != string_null) @@ -2066,7 +2066,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { if (Item.netname_non_team_drop != string_null) { sprint(te, PRINT_HIGH, AP.netname, - Item.netname_non_team_drop); + Item.netname_non_team_drop); } } te = find(te, classname, "player"); @@ -2300,7 +2300,7 @@ void (entity Item) tfgoalitem_checkgoalreturn = { void (entity Goal, entity Player, entity Item) DisplayItemStatus = { if (Item.goal_state == 1 && Item.owner != world) { if ((Goal.team_str_carried != string_null) || - (Goal.non_team_str_carried != string_null)) { + (Goal.non_team_str_carried != string_null)) { if (Player.team_no == Item.owned_by) { sprint(Player, PRINT_HIGH, Goal.team_str_carried); } else { @@ -2317,7 +2317,7 @@ void (entity Goal, entity Player, entity Item) DisplayItemStatus = { } else { if (Item.origin != Item.oldorigin) { if ((Goal.team_str_moved != string_null) || - (Goal.non_team_str_moved != string_null)) { + (Goal.non_team_str_moved != string_null)) { if (Player.team_no == Item.owned_by) { sprint(Player, PRINT_HIGH, Goal.team_str_moved); } else { @@ -2327,7 +2327,7 @@ void (entity Goal, entity Player, entity Item) DisplayItemStatus = { } } else { if ((Goal.team_str_home != string_null) || - (Goal.non_team_str_home != string_null)) { + (Goal.non_team_str_home != string_null)) { if (Player.team_no == Item.owned_by) { sprint(Player, PRINT_HIGH, Goal.team_str_home); } else { @@ -2561,7 +2561,7 @@ void (entity P) ForceRespawn = { if (self.playerclass != 0) spawn_tdeath(self.origin, self); if ((spot.classname == "info_player_teamspawn") && - (cb_prematch_time < time)) { + (cb_prematch_time < time)) { if (spot.items != 0) { te = Finditem(spot.items); if (te) { From 9ffb5129a0ecef64ae81f4cc9db052eb57d96430 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Sep 2018 20:33:39 +1000 Subject: [PATCH 0434/2474] Add localinfo stock_on_cap --- README.md | 1 + client.qc | 5 ++++ qw.qc | 1 + tfort.qc | 1 + tfortmap.qc | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f0f32aa0..71a0d6a8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ Classic Fortress v0.9 beta New features ------ +* Option for to fully restock player on cap. `localinfo stockoncap on`. * Option for packs to fully restock health and armour of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. * Map vote (4 random maps + current map) during last few minutes of game (shown for newly spawned or toggled with /togglevote). diff --git a/client.qc b/client.qc index eaa5a6e9..8ef44092 100644 --- a/client.qc +++ b/client.qc @@ -466,6 +466,9 @@ void () DecodeLevelParms = { // stock full ammo/armor [on] stockfull = CF_GetSetting("stf", "stockfull", "on"); + // stock full ammo/armor [on] + stock_on_cap = CF_GetSetting("soc", "stockoncap", "on"); + // display class tips [on] classtips = CF_GetSetting("ct", "classtips", "on"); @@ -546,6 +549,7 @@ void () DecodeLevelParms = { feign_msg = TRUE; spawnfull = FALSE; stockfull = TRUE; + stock_on_cap = TRUE; classtips = TRUE; sniperpower = TRUE; sniperreloadpercent = TRUE; @@ -594,6 +598,7 @@ void () DecodeLevelParms = { feign_msg = FALSE; spawnfull = FALSE; stockfull = FALSE; + stock_on_cap = FALSE; classtips = FALSE; sniperpower = FALSE; sniperreloadpercent = FALSE; diff --git a/qw.qc b/qw.qc index 3d329f0d..42db4111 100644 --- a/qw.qc +++ b/qw.qc @@ -469,6 +469,7 @@ float scoutdash; float sniperreload; float spawnfull; float stockfull; +float stock_on_cap; float classtips; float sniperpower; float sniperreloadpercent; diff --git a/tfort.qc b/tfort.qc index 4a136b53..eb9fae06 100644 --- a/tfort.qc +++ b/tfort.qc @@ -574,6 +574,7 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "\n== Classic Fortress ==\n"); CF_PrintSetting("Spawn with full health/armor", spawnfull, "", 1); CF_PrintSetting("Stock players with full health/armor", stockfull, "", 1); + CF_PrintSetting("Stock player on cap", stock_on_cap, "", 1); CF_PrintSetting("Old dropflag behaviour", old_dropflag, "", 1); CF_PrintSetting("Remember weapon", remember_weapon, "", 1); CF_PrintSetting("Pick up discarded ammo", discammo_pickup, "", 1); diff --git a/tfortmap.qc b/tfortmap.qc index 17ba5b7e..fec9eb53 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -683,10 +683,76 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player == AP) { if (Goal.count > 0) { if (Player.team_no > 0) { - // TODO: Restock player TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count); TeamFortress_TeamShowScores(2); Player.caps = Player.caps + 1; + + if (stock_on_cap) { + if (Player.health > 0) { + T_Heal(Player, Player.max_health, 0); + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.maxarmor; + + + Player.ammo_shells = Player.ammo_shells + Goal.ammo_shells; + Player.ammo_nails = Player.ammo_nails + Goal.ammo_nails; + Player.ammo_rockets = Player.ammo_rockets + Goal.ammo_rockets; + Player.ammo_cells = Player.ammo_cells + Goal.ammo_cells; + Player.ammo_medikit = Player.ammo_medikit + Goal.ammo_medikit; + Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack; + Player.no_grenades_1 = + Player.no_grenades_1 + Goal.no_grenades_1; + Player.no_grenades_2 = + Player.no_grenades_2 + Goal.no_grenades_2; + + if (Player.no_grenades_1 > 4) { + Player.no_grenades_1 = 4; + } + if (Player.no_grenades_2 > 4) { + Player.no_grenades_2 = 4; + } + if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && + (Player.no_grenades_1 > 2)) { + Player.no_grenades_1 = 2; + } + if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && + (Player.no_grenades_2 > 2)) { + Player.no_grenades_2 = 2; + } + if (Player.ammo_detpack > Player.maxammo_detpack) { + Player.ammo_detpack = Player.maxammo_detpack; + } + if (Player.tfstate & TFSTATE_GRENPRIMED) { + te = find(world, classname, "primer"); + while (te) { + if (te.owner == Player) { + if ((te.impulse == TF_GRENADE_2) && + (Player.no_grenades_2 <= 0)) { + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENPRIMED); + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENTHROWING); + dremove(te); + } else if ((te.impulse == TF_GRENADE_1) && + (Player.no_grenades_1 <= 0)) { + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENPRIMED); + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENTHROWING); + dremove(te); + } + te = world; + } else { + te = find(te, classname, "primer"); + } + } + } + } + } } } } From 76a1d7582210da1f73e61559b7e96ebcd116083e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Sep 2018 20:38:55 +1000 Subject: [PATCH 0435/2474] Consistenly camelcase localinfo stock_on_cap --- README.md | 2 +- client.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71a0d6a8..936dbc9f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Classic Fortress v0.9 beta New features ------ -* Option for to fully restock player on cap. `localinfo stockoncap on`. +* Option for to fully restock player on cap. `localinfo stock_on_cap on`. * Option for packs to fully restock health and armour of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. * Map vote (4 random maps + current map) during last few minutes of game (shown for newly spawned or toggled with /togglevote). diff --git a/client.qc b/client.qc index 8ef44092..6ce4f465 100644 --- a/client.qc +++ b/client.qc @@ -467,7 +467,7 @@ void () DecodeLevelParms = { stockfull = CF_GetSetting("stf", "stockfull", "on"); // stock full ammo/armor [on] - stock_on_cap = CF_GetSetting("soc", "stockoncap", "on"); + stock_on_cap = CF_GetSetting("soc", "stock_on_cap", "on"); // display class tips [on] classtips = CF_GetSetting("ct", "classtips", "on"); From 46c3e2595f09ff20af2564210a258d39d97750e6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Sep 2018 22:28:01 +1000 Subject: [PATCH 0436/2474] Fix stock_on_cap --- client.qc | 2 +- tfortmap.qc | 91 +++++++++++++---------------------------------------- 2 files changed, 23 insertions(+), 70 deletions(-) diff --git a/client.qc b/client.qc index 6ce4f465..fcb93fd7 100644 --- a/client.qc +++ b/client.qc @@ -466,7 +466,7 @@ void () DecodeLevelParms = { // stock full ammo/armor [on] stockfull = CF_GetSetting("stf", "stockfull", "on"); - // stock full ammo/armor [on] + // stock on cap [on] stock_on_cap = CF_GetSetting("soc", "stock_on_cap", "on"); // display class tips [on] diff --git a/tfortmap.qc b/tfortmap.qc index fec9eb53..8b17f41f 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -686,73 +686,6 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count); TeamFortress_TeamShowScores(2); Player.caps = Player.caps + 1; - - if (stock_on_cap) { - if (Player.health > 0) { - T_Heal(Player, Player.max_health, 0); - Player.armortype = Player.armor_allowed; - Player.armorvalue = Player.maxarmor; - - - Player.ammo_shells = Player.ammo_shells + Goal.ammo_shells; - Player.ammo_nails = Player.ammo_nails + Goal.ammo_nails; - Player.ammo_rockets = Player.ammo_rockets + Goal.ammo_rockets; - Player.ammo_cells = Player.ammo_cells + Goal.ammo_cells; - Player.ammo_medikit = Player.ammo_medikit + Goal.ammo_medikit; - Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack; - Player.no_grenades_1 = - Player.no_grenades_1 + Goal.no_grenades_1; - Player.no_grenades_2 = - Player.no_grenades_2 + Goal.no_grenades_2; - - if (Player.no_grenades_1 > 4) { - Player.no_grenades_1 = 4; - } - if (Player.no_grenades_2 > 4) { - Player.no_grenades_2 = 4; - } - if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > 2)) { - Player.no_grenades_1 = 2; - } - if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > 2)) { - Player.no_grenades_2 = 2; - } - if (Player.ammo_detpack > Player.maxammo_detpack) { - Player.ammo_detpack = Player.maxammo_detpack; - } - if (Player.tfstate & TFSTATE_GRENPRIMED) { - te = find(world, classname, "primer"); - while (te) { - if (te.owner == Player) { - if ((te.impulse == TF_GRENADE_2) && - (Player.no_grenades_2 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); - dremove(te); - } else if ((te.impulse == TF_GRENADE_1) && - (Player.no_grenades_1 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); - dremove(te); - } - te = world; - } else { - te = find(te, classname, "primer"); - } - } - } - } - } } } } @@ -890,10 +823,30 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } } Player.lives = Player.lives + Goal.lives; + if (Goal.frags) { - if ((Goal.goal_effects == TFGE_AP) || - !(toggleflags & TFLAG_FULLTEAMSCORE)) + if ((Goal.goal_effects == TFGE_AP) || !(toggleflags & TFLAG_FULLTEAMSCORE)) { TF_AddFrags(Player, Goal.frags); + if (stock_on_cap) { + if (Player.health > 0) { + T_Heal(Player, Player.max_health, 0); + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.maxarmor; + + Player.ammo_shells = Player.maxammo_shells; + Player.ammo_nails = Player.maxammo_nails; + Player.ammo_rockets = Player.maxammo_rockets; + Player.ammo_cells = Player.maxammo_cells; + Player.ammo_medikit = Player.maxammo_medikit; + Player.ammo_detpack = Player.maxammo_detpack; + + Player.no_grenades_1 = GetMaxGrenades(1, Player.tp_grenades_1); + Player.no_grenades_2 = GetMaxGrenades(2, Player.tp_grenades_2); + + Player.ammo_detpack = Player.maxammo_detpack; + } + } + } } oldself = self; self = Player; From 808344b6c7beb945e940bab224fcd22cbcd91dc2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Sep 2018 22:38:01 +1000 Subject: [PATCH 0437/2474] Remove duplication --- tfortmap.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 8b17f41f..32a410bd 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -842,8 +842,6 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.no_grenades_1 = GetMaxGrenades(1, Player.tp_grenades_1); Player.no_grenades_2 = GetMaxGrenades(2, Player.tp_grenades_2); - - Player.ammo_detpack = Player.maxammo_detpack; } } } From 395b5907720e6c12ed249a582f6a044b802302f7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Sep 2018 10:27:57 +1000 Subject: [PATCH 0438/2474] Heal status effects on cap --- tfortmap.qc | 77 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 32a410bd..cc82cbbc 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -827,25 +827,72 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Goal.frags) { if ((Goal.goal_effects == TFGE_AP) || !(toggleflags & TFLAG_FULLTEAMSCORE)) { TF_AddFrags(Player, Goal.frags); - if (stock_on_cap) { - if (Player.health > 0) { - T_Heal(Player, Player.max_health, 0); - Player.armortype = Player.armor_allowed; - Player.armorvalue = Player.maxarmor; - - Player.ammo_shells = Player.maxammo_shells; - Player.ammo_nails = Player.maxammo_nails; - Player.ammo_rockets = Player.maxammo_rockets; - Player.ammo_cells = Player.maxammo_cells; - Player.ammo_medikit = Player.maxammo_medikit; - Player.ammo_detpack = Player.maxammo_detpack; - - Player.no_grenades_1 = GetMaxGrenades(1, Player.tp_grenades_1); - Player.no_grenades_2 = GetMaxGrenades(2, Player.tp_grenades_2); + } + + if (stock_on_cap) { + if (Player.health > 0) { + T_Heal(Player, Player.max_health, 0); + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.maxarmor; + + Player.ammo_shells = Player.maxammo_shells; + Player.ammo_nails = Player.maxammo_nails; + Player.ammo_rockets = Player.maxammo_rockets; + Player.ammo_cells = Player.maxammo_cells; + Player.ammo_medikit = Player.maxammo_medikit; + Player.ammo_detpack = Player.maxammo_detpack; + + Player.no_grenades_1 = GetMaxGrenades(1, Player.tp_grenades_1); + Player.no_grenades_2 = GetMaxGrenades(2, Player.tp_grenades_2); + + te = find(Player, classname, "timer"); + + if (te.think == ConcussionGrenadeTimer || te.think == OldConcussionGrenadeTimer) { + if (old_grens == TRUE) { + stuffcmd(Player, "v_idlescale 0\nfov 90\n"); + } + dremove(te); + } + + if (Player.tfstate & TFSTATE_HALLUCINATING) { + if (te.think == HallucinationTimer) { + if (old_grens == TRUE) { + stuffcmd(trace_ent, "v_cshift; wait; bf\n"); + } + dremove(te); + } + } + + if (Player.tfstate & TFSTATE_TRANQUILISED) { + if (te.think == TranquiliserTimer) { + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_TRANQUILISED); + TeamFortress_SetSpeed(Player); + dremove(te); + } + } + + if (Player.tfstate & TFSTATE_INFECTED) { + Player.tfstate = + trace_ent.tfstate - + (trace_ent.tfstate & TFSTATE_INFECTED); + } + + if (Player.numflames > 0) { + sound(Player, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); + Player.numflames = 0; + } + + if (Player.FlashTime > 0) { + te = find(Player, netname, "flashtimer"); + Player.FlashTime = 0; + dremove(te); } } } } + oldself = self; self = Player; TeamFortress_CheckClassStats(); From 7e82321a92e19d62ab294f7d18473e4e926c7fbb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Sep 2018 10:48:39 +1000 Subject: [PATCH 0439/2474] Fix flash gren healing on cap --- tfortmap.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index cc82cbbc..23e40e24 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -885,8 +885,9 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } if (Player.FlashTime > 0) { - te = find(Player, netname, "flashtimer"); Player.FlashTime = 0; + stuffcmd(Player, "v_cshift; wait; bf\n"); + te = find(Player, netname, "flashtimer"); dremove(te); } } From c58331aa9fa2d5af877651bb688faeddf14d94b1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Sep 2018 12:11:40 +1000 Subject: [PATCH 0440/2474] Don't show score in status bar --- status.qc | 89 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/status.qc b/status.qc index ece3d978..6c904fe5 100644 --- a/status.qc +++ b/status.qc @@ -571,7 +571,7 @@ void (entity pl) RefreshStatusBar = { local string ident; local float height; local float i; - local float win, sec; + /* local float win, sec; */ pad = ""; @@ -665,57 +665,64 @@ void (entity pl) RefreshStatusBar = { s2 = strzone(s2); // status line 3 column 1 - team 1 score - win = TeamFortress_TeamGetWinner(); - sec = TeamFortress_TeamGetSecond(); - if (win == 0) - st1 = BlueScoreToString(team1score); - else if (win == 1) - st1 = BlueScoreToString(team1score); - else if (win == 2) - st1 = RedScoreToString(team2score); - else if (win == 3) - st1 = YellowScoreToString(team3score); - else - st1 = GreenScoreToString(team4score); - st1 = strcat(st1, " "); - // status line 3 column 2 - team 2 score - if (sec == 0) { - if (win < 2) - st2 = RedScoreToString(team2score); - else - st2 = BlueScoreToString(team1score); - } - else if (sec == 1) - st2 = BlueScoreToString(team1score); - else if (sec == 2) - st2 = RedScoreToString(team2score); - else if (sec == 3) - st2 = YellowScoreToString(team3score); - else - st2 = GreenScoreToString(team4score); - // status line 3 column 3 - clip size + /* win = TeamFortress_TeamGetWinner(); */ + /* sec = TeamFortress_TeamGetSecond(); */ + /* if (win == 0) */ + /* st1 = BlueScoreToString(team1score); */ + /* else if (win == 1) */ + /* st1 = BlueScoreToString(team1score); */ + /* else if (win == 2) */ + /* st1 = RedScoreToString(team2score); */ + /* else if (win == 3) */ + /* st1 = YellowScoreToString(team3score); */ + /* else */ + /* st1 = GreenScoreToString(team4score); */ + /* // status line 3 column 2 - team 2 score */ + /* if (sec == 0) { */ + /* if (win < 2) */ + /* st2 = RedScoreToString(team2score); */ + /* else */ + /* st2 = BlueScoreToString(team1score); */ + /* } */ + /* else if (sec == 1) */ + /* st2 = BlueScoreToString(team1score); */ + /* else if (sec == 2) */ + /* st2 = RedScoreToString(team2score); */ + /* else if (sec == 3) */ + /* st2 = YellowScoreToString(team3score); */ + /* else */ + /* st2 = GreenScoreToString(team4score); */ + st1 = ""; + st2 = ""; + + // status line 3 column 2 - clip size if (pl.tfstate & TFSTATE_RELOADING) { - st3 = "Γμιπ: "; + st2 = "Γμιπ: "; if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { - st3 = strcat(st3, strpadl(ftos(25 * pl.reload_sniper_ticks), 3)); - st3 = strcat(st3, "% "); + st2 = strcat(st2, strpadl(ftos(25 * pl.reload_sniper_ticks), 3)); + st2 = strcat(st2, "% "); } else { if (reload_cliptick) - st3 = strcat(st3, strpadl(ftos(pl.reload_clipsize), 2)); + st2 = strcat(st2, strpadl(ftos(pl.reload_clipsize), 2)); else - st3 = strcat(st3, " 0"); - st3 = strcat(st3, "/"); - st3 = strcat(st3, strpadr(ftos(GetClipSize(pl)), 3)); + st2 = strcat(st2, " 0"); + st2 = strcat(st2, "/"); + st2 = strcat(st2, strpadr(ftos(GetClipSize(pl)), 3)); } } else { - st3 = ClipSizeToString(pl); + st2 = ClipSizeToString(pl); } - // status line 3 column 4 - grenade count - st4 = strcat("Ηςεξ: ", strcat(strcat(ftos(pl.no_grenades_1), "+"), ftos(pl.no_grenades_2))); + + // status line 3 column 3 - grenade 1 count + st3 = strcat("Ηςεξ±: ", ftos(pl.no_grenades_1)); + + // status line 3 column 4 - grenade 2 count + st4 = strcat("Ηςεξ²: ", ftos(pl.no_grenades_2)); + // status line 3 s3 = strcat(st1, st2); s3 = strpadr(s3, 19); - s3 = strcat(s3, strpadl(strcat(st3, st4), 21)); + s3 = strcat(s3, strpadl(strcat(st3, strcat(" ", st4)), 21)); s3 = strcat(s3, "\n"); s3 = strzone(s3); From 0b28e7509696b3b2773acfe57a6d20241866731c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Sep 2018 20:20:26 +1000 Subject: [PATCH 0441/2474] WIP --- tfortmap.qc | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index 23e40e24..0658ec34 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -204,6 +204,10 @@ void (entity Goal) UpdateAbbreviations = }; void () TF_PlaceItem = { + dprint("=========TF_PlaceItem=========\n"); + eprint(self); + dprint("=========TF_PlaceItem=========\n"); + local float oldz; self.flags = FL_ITEM; @@ -223,9 +227,26 @@ void () TF_PlaceItem = { self.movetype = 0; self.oldorigin = self.origin; - if (self.goal_activation & TFGI_ITEMGLOWS) + if (self.goal_activation & TFGI_ITEMGLOWS) { self.effects = self.effects | EF_DIMLIGHT; + if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { + if (self.skin == 1.0) { + self.effects = self.effects | EF_BLUE; + } + if (self.skin == 2.0) { + self.effects = self.effects | EF_RED; + } + if (self.skin == 3.0) { + self.effects = self.effects | EF_RED; + self.effects = self.effects | EF_MUZZLEFLASH; + } + if (self.skin == 4.0) { + self.effects = self.effects | EF_MUZZLEFLASH; + } + } + } + if (item_list_bit == 0) item_list_bit = 1; @@ -234,6 +255,26 @@ void () TF_PlaceItem = { }; void () TF_StartItem = { + dprint("=========TF_StartItem=========\n"); + eprint(self); + dprint("=========TF_StartItem=========\n"); + if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { + self.effects = self.effects | EF_DIMLIGHT; + + if (self.skin == 1.0) { + self.effects = self.effects | EF_BLUE; + } + if (self.skin == 2.0) { + self.effects = self.effects | EF_RED; + } + if (self.skin == 3.0) { + self.effects = self.effects | EF_RED; + self.effects = self.effects | EF_MUZZLEFLASH; + } + if (self.skin == 4.0) { + self.effects = self.effects | EF_MUZZLEFLASH; + } + } UpdateAbbreviations(self); self.nextthink = time + 0.2; self.think = TF_PlaceItem; @@ -242,6 +283,10 @@ void () TF_StartItem = { }; void () TF_PlaceGoal = { + dprint("=========TF_PlaceGoal=========\n"); + eprint(self); + dprint("=========TF_PlaceGoal=========\n"); + local float oldz; if (self.classname != "info_tfgoal_timer") { @@ -254,6 +299,7 @@ void () TF_PlaceGoal = { self.classname = "info_tfgoal"; } if (self.goal_activation & 2048) { + self.movetype = MOVETYPE_TOSS; self.origin_z = self.origin_z + 6; oldz = self.origin_z; @@ -272,6 +318,10 @@ void () TF_PlaceGoal = { }; void () TF_StartGoal = { + dprint("=========TF_StartGoal=========\n"); + eprint(self); + dprint("=========TF_StartGoal=========\n"); + UpdateAbbreviations(self); self.nextthink = time + 0.2; self.think = TF_PlaceGoal; @@ -2022,7 +2072,13 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { Item.solid = 0; if (Item.goal_activation & TFGI_GLOW) { AP.effects = AP.effects | EF_DIMLIGHT; + + if (Goal.mdl == "progs/tf_flag.mdl" || Goal.mdl == "progs/tf_stan.mdl" ) { + AP.effects = Goal.effects; + Goal.effects = 0; + } } + if (Item.goal_activation & TFGI_SLOW) TeamFortress_SetSpeed(AP); @@ -2294,6 +2350,30 @@ void () tfgoalitem_droptouch = { }; void (entity Item, float PAlive, entity P) tfgoalitem_drop = { + dprint("=========tfgoalitem_drop=========\n"); + eprint(Item); + dprint("==================\n"); + eprint(P); + dprint("=========tfgoalitem_drop=========\n"); + + if (Item.model == "progs/tf_flag.mdl" || Item.model == "progs/tf_stan.mdl") { + Item.effects = self.effects | EF_DIMLIGHT; + + if (Item.skin == 1.0) { + Item.effects = Item.effects | EF_BLUE; + } + if (Item.skin == 2.0) { + Item.effects = Item.effects | EF_RED; + } + if (Item.skin == 3.0) { + Item.effects = Item.effects | EF_RED; + Item.effects = Item.effects | EF_MUZZLEFLASH; + } + if (Item.skin == 4.0) { + Item.effects = Item.effects | EF_MUZZLEFLASH; + } + } + Item.origin = Item.owner.origin; setorigin(Item, Item.origin); Item.camangle = Item.owner.origin - '0 0 8'; @@ -2665,6 +2745,11 @@ void (entity P) ForceRespawn = { }; void () DropGoalItems = { + dprint("=========TF_DropGoalItems=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("=========TF_DropGoalItems=========\n"); + local entity te, search; newmis = spawn(); From 6a510ffaf93cde8742b6a5de863d159ed4fba80e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Sep 2018 22:34:47 +1000 Subject: [PATCH 0442/2474] Only apply cap restock to capping player --- tfortmap.qc | 94 +++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 23e40e24..80c96251 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -830,65 +830,67 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } if (stock_on_cap) { - if (Player.health > 0) { - T_Heal(Player, Player.max_health, 0); - Player.armortype = Player.armor_allowed; - Player.armorvalue = Player.maxarmor; + if (Player == AP) { + if (Player.health > 0) { + T_Heal(Player, Player.max_health, 0); + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.maxarmor; - Player.ammo_shells = Player.maxammo_shells; - Player.ammo_nails = Player.maxammo_nails; - Player.ammo_rockets = Player.maxammo_rockets; - Player.ammo_cells = Player.maxammo_cells; - Player.ammo_medikit = Player.maxammo_medikit; - Player.ammo_detpack = Player.maxammo_detpack; + Player.ammo_shells = Player.maxammo_shells; + Player.ammo_nails = Player.maxammo_nails; + Player.ammo_rockets = Player.maxammo_rockets; + Player.ammo_cells = Player.maxammo_cells; + Player.ammo_medikit = Player.maxammo_medikit; + Player.ammo_detpack = Player.maxammo_detpack; - Player.no_grenades_1 = GetMaxGrenades(1, Player.tp_grenades_1); - Player.no_grenades_2 = GetMaxGrenades(2, Player.tp_grenades_2); + Player.no_grenades_1 = GetMaxGrenades(1, Player.tp_grenades_1); + Player.no_grenades_2 = GetMaxGrenades(2, Player.tp_grenades_2); - te = find(Player, classname, "timer"); - - if (te.think == ConcussionGrenadeTimer || te.think == OldConcussionGrenadeTimer) { - if (old_grens == TRUE) { - stuffcmd(Player, "v_idlescale 0\nfov 90\n"); - } - dremove(te); - } + te = find(Player, classname, "timer"); - if (Player.tfstate & TFSTATE_HALLUCINATING) { - if (te.think == HallucinationTimer) { + if (te.think == ConcussionGrenadeTimer || te.think == OldConcussionGrenadeTimer) { if (old_grens == TRUE) { - stuffcmd(trace_ent, "v_cshift; wait; bf\n"); + stuffcmd(Player, "v_idlescale 0\nfov 90\n"); } dremove(te); } - } - if (Player.tfstate & TFSTATE_TRANQUILISED) { - if (te.think == TranquiliserTimer) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_TRANQUILISED); - TeamFortress_SetSpeed(Player); - dremove(te); + if (Player.tfstate & TFSTATE_HALLUCINATING) { + if (te.think == HallucinationTimer) { + if (old_grens == TRUE) { + stuffcmd(trace_ent, "v_cshift; wait; bf\n"); + } + dremove(te); + } } - } - if (Player.tfstate & TFSTATE_INFECTED) { - Player.tfstate = - trace_ent.tfstate - - (trace_ent.tfstate & TFSTATE_INFECTED); - } + if (Player.tfstate & TFSTATE_TRANQUILISED) { + if (te.think == TranquiliserTimer) { + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_TRANQUILISED); + TeamFortress_SetSpeed(Player); + dremove(te); + } + } - if (Player.numflames > 0) { - sound(Player, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); - Player.numflames = 0; - } + if (Player.tfstate & TFSTATE_INFECTED) { + Player.tfstate = + trace_ent.tfstate - + (trace_ent.tfstate & TFSTATE_INFECTED); + } + + if (Player.numflames > 0) { + sound(Player, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); + Player.numflames = 0; + } - if (Player.FlashTime > 0) { - Player.FlashTime = 0; - stuffcmd(Player, "v_cshift; wait; bf\n"); - te = find(Player, netname, "flashtimer"); - dremove(te); + if (Player.FlashTime > 0) { + Player.FlashTime = 0; + stuffcmd(Player, "v_cshift; wait; bf\n"); + te = find(Player, netname, "flashtimer"); + dremove(te); + } } } } From 6fdedea719430bd54bd41ed0a82e6bfaa1860782 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 19 Sep 2018 01:27:55 +1000 Subject: [PATCH 0443/2474] Restock scout with 4 cuss on cap --- items.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/items.qc b/items.qc index 7190336b..8d50fce3 100644 --- a/items.qc +++ b/items.qc @@ -793,9 +793,6 @@ float (float pf_grenade_number, float pf_grenade_type) GetMaxGrenades = { if (pf_grenade_type == GR_TYPE_NAIL) { return 2; } - if (pf_grenade_type == GR_TYPE_CONCUSSION) { - return 3; - } } return 4; } From 06aa886f0b1400b1b35455fbb59ea9a0c9aa0dcd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 25 Sep 2018 20:47:30 +1000 Subject: [PATCH 0444/2474] Update FTEQCC url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 936dbc9f..ca814bba 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Engineer Compilation ------ -Compile with [FTEQCC](https://sourceforge.net/projects/fteqw/) +Compile with [FTEQCC](http://fte.triptohell.info/downloads) Ensure that `fteqcc64` is available in `$PATH` and: From 1854bc037944dd0c9930cb7f62e9e817ceb5baf2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 26 Sep 2018 01:15:39 +1000 Subject: [PATCH 0445/2474] WIP --- tfortmap.qc | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 15fd5ffc..fc0790d7 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -204,10 +204,6 @@ void (entity Goal) UpdateAbbreviations = }; void () TF_PlaceItem = { - dprint("=========TF_PlaceItem=========\n"); - eprint(self); - dprint("=========TF_PlaceItem=========\n"); - local float oldz; self.flags = FL_ITEM; @@ -227,26 +223,9 @@ void () TF_PlaceItem = { self.movetype = 0; self.oldorigin = self.origin; - if (self.goal_activation & TFGI_ITEMGLOWS) { + if (self.goal_activation & TFGI_ITEMGLOWS) self.effects = self.effects | EF_DIMLIGHT; - if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { - if (self.skin == 1.0) { - self.effects = self.effects | EF_BLUE; - } - if (self.skin == 2.0) { - self.effects = self.effects | EF_RED; - } - if (self.skin == 3.0) { - self.effects = self.effects | EF_RED; - self.effects = self.effects | EF_MUZZLEFLASH; - } - if (self.skin == 4.0) { - self.effects = self.effects | EF_MUZZLEFLASH; - } - } - } - if (item_list_bit == 0) item_list_bit = 1; @@ -2067,25 +2046,22 @@ void () item_tfgoal_touch = { }; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { + Item.effects = 0; + Item.owner = AP; if (Item.mdl != string_null) { setmodel(Item, string_null); } Item.solid = 0; if (Item.goal_activation & TFGI_GLOW) { - AP.effects = AP.effects | EF_DIMLIGHT; - - if (Goal.mdl == "progs/tf_flag.mdl" || Goal.mdl == "progs/tf_stan.mdl" ) { - AP.effects = Goal.effects; - Goal.effects = 0; - } + AP.effects = EF_DIMLIGHT; } if (Item.goal_activation & TFGI_SLOW) TeamFortress_SetSpeed(AP); if (Item.goal_activation & TFGI_ITEMGLOWS) - Item.effects = Item.effects - (Item.effects | EF_DIMLIGHT); + Item.effects = EF_DIMLIGHT; if (Item.items & IT_KEY1) AP.items = AP.items | IT_KEY1; @@ -2284,8 +2260,8 @@ void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { AP.effects = AP.effects - (AP.effects & 64); AP.effects = AP.effects - (AP.effects & 128); } - if (Item.goal_activation & 512) - Item.effects = Item.effects | 8; + /* if (Item.goal_activation & 512) */ + /* Item.effects = Item.effects | 8; */ if (!spyoff) AP.is_unabletospy = 0; From f58a0a7a3b001570dabf3f3a0addc78dc71ad354 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 3 Oct 2018 15:22:51 +1000 Subject: [PATCH 0446/2474] WIP --- docs/tfentref.txt | 1273 ++++++++++++++++++++++ docs/tfortmap.txt | 1648 +++++++++++++++++++++++++++++ versions.txt => docs/versions.txt | 0 tfortmap.qc | 80 +- 4 files changed, 2993 insertions(+), 8 deletions(-) create mode 100644 docs/tfentref.txt create mode 100644 docs/tfortmap.txt rename versions.txt => docs/versions.txt (100%) diff --git a/docs/tfentref.txt b/docs/tfentref.txt new file mode 100644 index 00000000..71d9d518 --- /dev/null +++ b/docs/tfentref.txt @@ -0,0 +1,1273 @@ +---------------------------------------------------------------------------- +The New TeamFortress Entity Reference Sheet TF Version 2.6 +---------------------------------------------------------------------------- + +This is a reference sheet for people who're trying to read/debug the +entities on their TF map. It's simply a quick description of every variable +for all the TF entities. It's simply a quick-reference. For full details, +see the tfortmap.txt file. + +Print this out, and keep it by you whenever you're reading through someone +else's .map file to see how they did something :) Also get Raistlan's EntEd +which supports TeamFortress Entities at http://www.lockandload.com/ented/ + +Robin (walker@netspace.net.au) | Network (network@lockandload.com) +---------------------------------------------------------------------------- + +GLOSSARY +-------- +AP : Activating Player. The player who activated a Goal/Trigger, or picked + up the GoalItem. + +APA : Any Player Affected. Any player who is affected by the current + Goal/Trigger/Item's activation. + + +INDEX +-------- + I. : DETECTION ENTITY VARIABLES (info_tfdetect) + II. : TEAM SPAWNPOINT VARIABLES (info_player_teamspawn) +III. : GOAL VARIABLES (info_tfgoal) + IV. : GOALITEM VARIABLES (item_tfgoal) + V. : TIMER GOAL VARIABLES (info_tfgoal_timer) + VI. : OTHER QUAKE ENTITY VARIABLES +VII. : VARIABLE ABBREVIATION LIST + + +============================================================================ +DETECTION ENTITY VARIABLES (info_tfdetect) +============================================================================ + +broadcast The TF version string. e.g. "TeamFortress v2.6" + +impulse Initial Toggleflags status. Bitfields: (Unspecified = OFF) + 1 : ClasSkin Off/On + 2 : ClassPersistence Off/On + 4 : CheatChecking Off/On + 8 : FortressMap Off/On + 16 : RespawnDelay See tfortmap.txt + 32 : RespawnDelay See tfortmap.txt + 64 : AutoTeam Off/On + 128 : Individual Frags Off/On + +message Commands that are localcmd'd into the server when the map + first starts. e.g. "sv_gravity 300\nsv_friction 0.1\n" + Be sure to end all commands with '\n'. + +ammo_shells Max number of lives for each player in Team 1. +ammo_nails Max number of lives for each player in Team 2. +ammo_rockets Max number of lives for each player in Team 3. +ammo_cells Max number of lives for each player in Team 4. + (0 = Unlimited number of lives) + +ammo_medikit Maximum number of players allowed in Team 1. +ammo_detpack Maximum number of players allowed in Team 2. +maxammo_medikit Maximum number of players allowed in Team 3. +maxammo_detpack Maximum number of players allowed in Team 4. + (0 = Unlimited number of players) + +maxammo_shells Illegal Classes for Team 1. +maxammo_nails Illegal Classes for Team 2. +maxammo_rockets Illegal Classes for Team 3. +maxammo_cells Illegal Classes for Team 4. + -1 : Civilian Only. (Cannot Specify Others) + 1 : No Scout + 2 : No Sniper + 4 : No Soldier + 8 : No Demolitions Man + 16 : No Combat Medic + 32 : No Heavy Weapons Guy + 64 : No Pyro + 128 : No Random PlayerClass + 256 : No Spy + 512 : No Engineer + +hook_out If 1, the grappling hook cannot be used on this map. + Else, this does not need to be specified. + +display_item_status1 On FlagInfo command, display this GoalItem status +display_item_status2 On FlagInfo command, display this GoalItem status +display_item_status3 On FlagInfo command, display this GoalItem status +display_item_status4 On FlagInfo command, display this GoalItem status + +team_str_home String displayed to the owners of an Item + in an Item Status if the Item is at it's origin. + If not the owner of the Item, non_team_str_home + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is in it's base" + +team_str_moved String displayed to the owners of an Item in an + Item Status if the Item is not at it's origin. + If not the owner of the Item, non_team_str_moved + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is lying around" + +team_str_carried String displayed to the owners of an Item in an Item + Status if the Item is being carried by a player. The + player's name is appended to the String. If not the + owner of the Item, non_team_str_carried will be used. + Refer to the "owned_by" variable for GoalItems. + e.g. "Your flag is being carried by" < players's_name> + +non_team_str_home String displayed to everyone except the owners of an + Item in an Item Status if the Item is at it's origin. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is in it's base" + +non_team_str_moved String displayed to everyone except the owners of an + Item in an Item Status if the Item is not at it's origin. + If they are owner of the Item, team_str_moved will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is lying around" + +non_team_str_carried String displayed to everyone except the owners of an + Item in an Item Status if the Item is being carried by a + player. The player's name is appended to the String. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is being carried by" < player's_name> + +team_broadcast String that replaces the Team Menu. + (Line breaks should be used: \n) + +non_team_broadcast String that is displayed in the Map Help command. + (Line breaks could be used: \n) + +noise1 String that replaces the Class Menu for Team 1. +noise2 String that replaces the Class Menu for Team 2. +noise3 String that replaces the Class Menu for Team 3. +noise4 String that replaces the Class Menu for Team 4. + (Line breaks should be used: \n) + + +============================================================================ +TEAM SPAWNPOINT VARIABLES (info_player_teamspawn) +============================================================================ + +netname The name of the spawn point. (A reference) + +goal_no Unique ID number of this spawn. + +group_no ID Number of the spawn group this spawn belongs to. + +team_no Only players on this team spawn here. + +items GoalItem ID is given to the first player who + spawn here. + +axhitme Goal removes this GoalItem from APA that has it. + +message A String displayed to the first player who + spawns here. + +goal_activation Bitfields: + 1 : Give the GoalItem in "items" to every player who + spawns here instead of just the first player. + 2 : Display the "message" to every player who spawns + here instead of just the first player. + +goal_effects Bitfields: + 1 : The spawnpoint removes itself after the first + player has spawned here. + +activate_goal_no Activate this Goal. + +items_allowed AP needs this GoalItem to meet this Goal's criteria. + +has_item_from_group AP must have GoalItem from group "group_no". + +playerclass AP must be this playerclass to meet this Goal's criteria. + You can not add these up, you can only specify one player + class. Bitfields: + 1 : Only allow a Scout to activate + 2 : Only allow a Sniper to activate + 3 : Only allow a Soldier to activate + 4 : Only allow a Demolition Man to activate + 5 : Only allow a Medic to activate + 6 : Only allow a Heavy Weapons Guy to activate + 7 : Only allow a Pyro to activate + 8 : Only allow a Spy to activate + 9 : Only allow an Engineer to activate + +if_goal_is_active This Goal must be in ACTIVE state. +if_goal_is_inactive This Goal must be in INACTIVE state. +if_goal_is_removed This Goal must be in REMOVED state. +if_group_is_active All Goals in this Group must be in ACTIVE state. +if_group_is_inactive All Goals in this Group must be in INACTIVE state. +if_group_is_removed All Goals in this Group must be in REMOVED state. +if_item_has_moved This GoalItem must not have moved from it's origin, + and must not be being carried. +if_item_hasnt_moved This GoalItem must have moved from it's origin, + or be being carried. + +target Activate any Goal/Quake Trigger with this targetname + +killtarget Remove any Goal/Quake Trigger with this targetname + +goal_state The initial state of this entity. The default + (nothing specified) is Inactive the same as if + you specified a value of 2. Bitfields: + 1 : Active (Already On) + 2 : Inactive (Ready to be used) + 3 : Removed (Unmanipulatable until restored) + +ex_skill_min This entity is removed when the map starts if the game's "skill" + variable is >= to this value. To specify a skill of 0, use + -1 instead. + +ex_skill_max This entity is removed when the map starts if the game's "skill" + variable is <= to this value. To specify a skill of 0, use + -1 instead. + +count Specified score given to the AP's team. + +increase_team1 Specified score given to team 1 +increase_team2 Specified score given to team 2 +increase_team3 Specified score given to team 3 +increase_team4 Specified score given to team 4 + +noise WAV file played when this Goal is activated. + +lives Added to APA's lives. + +health Added to APA's health. + +armortype The APA's armortype is set to the Goals "armortype". + Armortype Bitfields: + 0.3 : Green + 0.6 : Yellow + 0.8 : Red + +armorvalue APA's armorvalue is set to this value. (0-250) + +armorclass APA's armorclass is set to this type(s). + 1 : Shell Resistant + 2 : Nail Resistant + 4 : Explosion Resistant + 8 : Electricity Resistant + 16 : Fire Resistant + +frags Added to APA's frags. + +ammo_shells Added this number of shells to the APA's ammo supply. +ammo_nails Added this number of nails to the APA's ammo supply. +ammo_rockets Added this number of rockets to the APA's ammo supply. +ammo_cells Added this number of cells to the APA's ammo supply. +ammo_detpack Added this number of det packs to the APA's supply. +ammo_medikit Added this number of medikits to the APA's supply. + +no_grenades_1 Added to APA's number of type 1 TF grenades. +no_grenades_2 Added to APA's number of type 2 TF grenades. + +invincible_finished Number of seconds of invincibility APA gets. +invisible_finished Number of seconds of invisibility APA gets. +super_damage_finished Number of seconds of quad APA gets. +radsuit_finished Number of seconds of radsuit APA gets. + +activate_goal_no Activate this Goal. +inactivate_goal_no Inactivate this Goal. +remove_goal_no Remove this Goal. +restore_goal_no Restore this Goal. + +activate_group_no Activate all Goals in this GoalGroup. +inactivate_group_no Inactivate all Goals in this GoalGroup. +remove_group_no Remove all Goals in this GoalGroup. +restore_group_no Restore all Goals in this GoalGroup. + +remove_item_group Removes a GoalItems APA has from GoalGroup + +all_active If all Goals in this GoalGroup are ACTIVE, activate + the Goal in the "last_impulse" variable. + +last_impulse If all Goals in the "all_active" GoalGroup are ACTIVE, + activate this Goal. + +remove_spawnpoint Remove the spawnpoint with this "goal_no". + +restore_spawnpoint Restore the spawnpoint with this "goal_no", if it's + in the REMOVED state. + +remove_spawngroup Remove all spawnpoints with this "group_no". + +restore_spawngroup Restore all spawnpoints with this "group_no", if + they're in the REMOVED state. + + +============================================================================ +GOAL VARIABLES (info_tfgoal) +============================================================================ + +netname The name of the Goal. (A reference) + +goal_no Unique ID number of this goal. + +group_no ID Number of the goal group this goal belongs to. + +owned_by The Team that own this entity. + +goal_state The initial state of this entity. The default + (nothing specified) is Inactive the same as if + you specified a value of 2. Bitfields: + 1 : Active (Already On) + 2 : Inactive (Ready to be used) + 3 : Removed (Unmanipulatable until restored) + +mdl The mdl used by this Goal. (Unspecified = Invisible Goal.) + +skin The number of the skin to be used in the specified model. + +goal_activation Determines how the Goal is activated. Bitfields: + 1 : Activated when touched by a player. + 2 : Activated when touched by a detpack explosion. + 4 : Only activated if the AP fails Criteria. + 2048 : If this bit is set, the Goal drops to the + ground when it first spawns. + +team_no AP must be of this team to meet this Goal's criteria. + +items_allowed AP needs this GoalItem to meet this Goal's criteria. + +has_item_from_group AP must have GoalItem from group "group_no". + +playerclass AP must be this playerclass to meet this Goal's criteria. + You can not add these up, you can only specify one player + class. Bitfields: + 1 : Only allow a Scout to activate + 2 : Only allow a Sniper to activate + 3 : Only allow a Soldier to activate + 4 : Only allow a Demolition Man to activate + 5 : Only allow a Medic to activate + 6 : Only allow a Heavy Weapons Guy to activate + 7 : Only allow a Pyro to activate + 8 : Only allow a Spy to activate + 9 : Only allow an Engineer to activate + +if_goal_is_active This Goal must be in ACTIVE state. +if_goal_is_inactive This Goal must be in INACTIVE state. +if_goal_is_removed This Goal must be in REMOVED state. +if_group_is_active All Goals in this Group must be in ACTIVE state. +if_group_is_inactive All Goals in this Group must be in INACTIVE state. +if_group_is_removed All Goals in this Group must be in REMOVED state. +if_item_has_moved This GoalItem must not have moved from it's origin, + and must not be being carried. +if_item_hasnt_moved This GoalItem must have moved from it's origin, + or be being carried. + +else_goal If the AP fails the Criteria of this entity, then + attempt to activate the Goal with this ID. + +goal_min The minimum bounding box size of a Goal can be set using + this. The default is: "goal_min" "-16 -16 -24" + +goal_max The maximum bounding box size of a Goal can be set using + this. The default is: "goal_max" "16 16 32" + +------------------------------------------- +When this Goal is successfully activated +up, the following variables may be executed +------------------------------------------- + +return_item_no Return this GoalItem, if it's not being carried. + +broadcast Message centerprinted to everyone except the AP. + e.g. "Clean-up on isle 4!" + +message Message centerprinted to AP. + e.g. "You activated this goal!" + +team_broadcast Message centerprinted to players on the AP's team, + except the AP. e.g. "Your team has the enemy flag!" + +non_team_broadcast Message centerprinted to players not on the AP's team. + If there is a "owners_team_broadcast" specified, this + message isn't centerprinted to the owners of the entity. + e.g. "An enemy flag was taken!" + +owners_team_broadcast Gets centerprinted to all the members of the + team that own the goal/item. + e.g. "Your flag was taken!" + +netname_broadcast Broadcast to all players, prepended to the AP's name. + A line break should be used at the end. + e.g. " activated this goal!\n" + +netname_team_broadcast Broadcast to all players on the AP's team, except + the AP, prepended by the AP's name. A line break should + be used at the end. + e.g. " activated your team's goal!\n" + +netname_non_team_broadcast + Broadcast to all players on the AP's team, prepended by the + AP's name. If there is a "netname_owners_team_broadcast" + specified, this message isn't broadcast to the owners of + the entity. A line break should be used at the end. + e.g. " took an enemy flag!\n" + +netname_owners_team_broadcast + Broadcast to all members of the team that own this entity + (see "owned_by" above), prepended by the AP's name. + e.g. " took your flag!\n" + +deathtype Death message appended to the AP's name and broadcasted, if the + AP is killed by the Goal. A line break should be used at the end. + e.g. " was killed by this goal!\n" + +target Activate any Goal/Quake Trigger with this targetname + +killtarget Remove any Goal/Quake Trigger with this targetname + +ex_skill_min This entity is removed when the map starts if the game's "skill" + variable is >= to this value. To specify a skill of 0, use + -1 instead. + +ex_skill_max This entity is removed when the map starts if the game's "skill" + variable is <= to this value. To specify a skill of 0, use + -1 instead. + +goal_effects Determines what players are affected. If nothing is specified + the goal will not effect anybody. Bitfields: + 1 : AP is affected. + 2 : Everyone on the AP's team is affected. + 4 : Everyone not on the AP's team is affected. + 8 : Everyone except the AP is affected. + 16 : Radius effect (see "t_length") does not go + through walls. + 32 : If APA is not in the same environment as the + Goal, don't affect him. Environments are air, + water, slime, lava. e.g. If a Goal is above + some water, and does a radius effect with + "t_length", and a player in the water is within + the radius, he won't be affected if this bit + is set. + 64 : If this bit is set, then instead of just applying + this Goal's results to the group of players + specified by the other "goal_effects" variable, + this Goal checks it's criteria for each player + in the group and then applies it's results + invididually to any of them that pass. + +maxammo_shells All members of this team are affected. + +maxammo_nails All members not of this team are affected. + +t_length Everyone within this radius is affected. To specify whether + the radius should go through walls or not see bit 16 + in "goal_effects" + + +goal_results Determines what results are applied to APA. Bitfields: + 1 : Goal is removed after activation. + 2 : Goals activated by this one apply their + results to the AP. + 4 : Display scores and end the level. + 8 : Activated goals will not apply their results to + the APA + 16 : Disable/Stop the spy's undercover mask. + 32 : This forces APA to simply respawn. The player + doesn't die... just respawns. + +count Specified score given to the AP's team. + +increase_team1 Specified score given to team 1 +increase_team2 Specified score given to team 2 +increase_team3 Specified score given to team 3 +increase_team4 Specified score given to team 4 + +noise WAV file played when this Goal is activated. + +lives Added to APA's lives. + +health Added to APA's health. + +armortype The APA's armortype is set to the Goals "armortype". + Armortype Bitfields: + 0.3 : Green + 0.6 : Yellow + 0.8 : Red + +armorvalue APA's armorvalue is set to this value. (0-250) + +armorclass APA's armorclass is set to this type(s). + 1 : Shell Resistant + 2 : Nail Resistant + 4 : Explosion Resistant + 8 : Electricity Resistant + 16 : Fire Resistant + +frags Added to APA's frags. + +ammo_shells Added this number of shells to the APA's ammo supply. +ammo_nails Added this number of nails to the APA's ammo supply. +ammo_rockets Added this number of rockets to the APA's ammo supply. +ammo_cells Added this number of cells to the APA's ammo supply. +ammo_detpack Added this number of det packs to the APA's supply. +ammo_medikit Added this number of medikits to the APA's supply. + +no_grenades_1 Added to APA's number of type 1 TF grenades. +no_grenades_2 Added to APA's number of type 2 TF grenades. + +invincible_finished Number of seconds of invincibility APA gets. +invisible_finished Number of seconds of invisibility APA gets. +super_damage_finished Number of seconds of quad APA gets. +radsuit_finished Number of seconds of radsuit APA gets. + +items Goal gives this GoalItem to APA. +axhitme Goal removes this GoalItem from APA that has it. + +delay_time If the criteria is meant for activation, the goal waits + this amount of time before activating, in seconds. + +wait Goal stays ACTIVE for this amount of time, in seconds. + +activate_goal_no Activate this Goal. +inactivate_goal_no Inactivate this Goal. +remove_goal_no Remove this Goal. +restore_goal_no Restore this Goal. + +activate_group_no Activate all Goals in this GoalGroup. +inactivate_group_no Inactivate all Goals in this GoalGroup. +remove_group_no Remove all Goals in this GoalGroup. +restore_group_no Restore all Goals in this GoalGroup. + +remove_item_group Removes a GoalItems APA has from GoalGroup + +all_active If all Goals in this GoalGroup are ACTIVE, activate + the Goal in the "last_impulse" variable. + +last_impulse If all Goals in the "all_active" GoalGroup are ACTIVE, + activate this Goal. + +remove_spawnpoint Remove the spawnpoint with this "goal_no". + +restore_spawnpoint Restore the spawnpoint with this "goal_no", if it's + in the REMOVED state. + +remove_spawngroup Remove all spawnpoints with this "group_no". + +restore_spawngroup Restore all spawnpoints with this "group_no", if + they're in the REMOVED state. + +display_item_status1 Display this GoalItem Status when this goal is activated +display_item_status2 Display this GoalItem Status when this goal is activated +display_item_status3 Display this GoalItem Status when this goal is activated +display_item_status4 Display this GoalItem Status when this goal is activated + +team_str_home String displayed to the owners of an Item + in an Item Status if the Item is at it's origin. + If not the owner of the Item, non_team_str_home + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is in it's base" + +team_str_moved String displayed to the owners of an Item in an + Item Status if the Item is not at it's origin. + If not the owner of the Item, non_team_str_moved + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is lying around" + +team_str_carried String displayed to the owners of an Item in an Item + Status if the Item is being carried by a player. The + player's name is appended to the String. If not the + owner of the Item, non_team_str_carried will be used. + Refer to the "owned_by" variable for GoalItems. + e.g. "Your flag is being carried by" < players's_name> + +non_team_str_home String displayed to everyone except the owners of an + Item in an Item Status if the Item is at it's origin. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is in it's base" + +non_team_str_moved String displayed to everyone except the owners of an + Item in an Item Status if the Item is not at it's origin. + If they are owner of the Item, team_str_moved will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is lying around" + +non_team_str_carried String displayed to everyone except the owners of an + Item in an Item Status if the Item is being carried by a + player. The player's name is appended to the String. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is being carried by" < player's_name> + + +============================================================================ +GOALITEM VARIABLES (item_tfgoal) +============================================================================ + +netname The name of the GoalItem. (A reference) + +goal_no Unique ID number of this GoalItem. + +group_no ID Number of the goal group this GoalItem belongs to. + +owned_by The Team that own this entity. + +goal_state The initial state of this item. The default + (nothing specified) is Inactive the same as if + you specified a value of 2. Bitfields: + 1 : Active (Already On) + 2 : Inactive (Ready to be used) + 3 : Removed (Unmanipulatable until restored) + +mdl The mdl used by this GoalItem. (Unspecified = Invisible) + +skin The number of the skin to be used in the specified model. + +goal_activation Bitfields: + 1 : Carrying Player glows. + 2 : Carrying Player moves at half speed. + 4 : Item is dropped when a player with it dies. + 8 : Item is returned when dropped. + 16 : Item is returned when removed from players by a Goal + 32 : Item is returned due to "pausetime" (see below) + 64 : Only activated (picked-up) if AP fails Criteria. + 128 : Enable "pausetime" removing. + 256 : Players keep this item when they die. + 512 : If this Item isn't being carried, it glows dimly. + 1024 : Don't remove the results of this Item when it's + removed from a player. + 2048 : If this bit is set, the GoalItem drops to the + ground when it first spawns. + 8192 : If this bit is set, the GoalItem is Solid while not + being carried by a player. This means it blocks + bullets, grenades, and those that do not pass it's + criteria. Others will simply pick it up. + +playerclass AP must be this playerclass to meet this GoalItem's criteria. + You can not add these up, you can only specify one player + class. Bitfields: + 1 : Only allow a Scout to activate + 2 : Only allow a Sniper to activate + 3 : Only allow a Soldier to activate + 4 : Only allow a Demolition Man to activate + 5 : Only allow a Medic to activate + 6 : Only allow a Heavy Weapons Guy to activate + 7 : Only allow a Pyro to activate + 8 : Only allow a Spy to activate + 9 : Only allow an Engineer to activate + +if_goal_is_active This Goal must be in ACTIVE state. +if_goal_is_inactive This Goal must be in INACTIVE state. +if_goal_is_removed This Goal must be in REMOVED state. +if_group_is_active All Goals in this Group must be in ACTIVE state. +if_group_is_inactive All Goals in this Group must be in INACTIVE state. +if_group_is_removed All Goals in this Group must be in REMOVED state. +if_item_has_moved This GoalItem must not have moved from it's origin, + and must not be being carried. +if_item_hasnt_moved This GoalItem must have moved from it's origin, + or be being carried. + +else_goal If the AP fails the Criteria of this entity, then + attempt to activate the Goal with this ID. + +has_item_from_group AP must have GoalItem from group "group_no" + +goal_min The minimum bounding box size of a GoalItem can be set + using this. The default is: "goal_min" "-16 -16 -24" + +goal_max The maximum bounding box size of a GoalItem can be set + using this. The default is: "goal_max" "16 16 32" + +------------------------------------------- +When this GoalItem is successfully picked +up, the following variables may be executed +------------------------------------------- + +return_item_no Return this GoalItem, if it's not being carried. + +target Activate any Goal/Quake Trigger with this targetname + +killtarget Remove any Goal/Quake Trigger with this targetname + +ex_skill_min This entity is removed when the map starts if the game's "skill" + variable is >= to this value. To specify a skill of 0, use + -1 instead. + +ex_skill_max This entity is removed when the map starts if the game's "skill" + variable is <= to this value. To specify a skill of 0, use + -1 instead. + +goal_effects Determines what players are affected. If nothing is specified + the goal will not effect anybody. Bitfields: + 1 : AP is affected. + 2 : Everyone on the AP's team is affected. + 4 : Everyone not on the AP's team is affected. + 8 : Everyone except the AP is affected. + 16 : Radius effect (see "t_length") does not go + through walls. + 32 : If APA is not in the same environment as the + Goal, don't affect him. Environments are air, + water, slime, lava. e.g. If a Goal is above + some water, and does a radius effect with + "t_length", and a player in the water is within + the radius, he won't be affected if this bit + is set. + 64 : If this bit is set, then instead of just applying + this Goal's results to the group of players + specified by the other "goal_effects" variable, + this Goal checks it's criteria for each player + in the group and then applies it's results + invididually to any of them that pass. + +maxammo_shells All members of this team are affected. + +maxammo_nails All members not of this team are affected. + +t_length Everyone within this radius is affected. To specify whether + the radius should go through walls or not see bit 16 + in "goal_effects" + +impulse When the GoalItem is Returned, activate this Goal. + +pausetime Item is removed if not touched for this time after being + dropped by a dying player. Also, see bit 32 in + "goal_activation" above. N.B. This will not be used if + bit 128 in "goal_activation" is not enabled. + + +maxammo_shells All members of this team are affected. + +maxammo_nails All members not of this team are affected. + +goal_results Determines what results are applied to APA. Bitfields: + 1 : Goal is removed after activation. + 2 : Goals activated by this one apply their + results to the AP. + 4 : Display scores and end the level. + 8 : Activated goals will not apply their results to + the APA + 16 : Disable/Stop the spy's undercover mask. + 32 : This forces APA to simply respawn. The player + doesn't die... just respawns. + 4096 : If this bit is set, any player carrying this + item can drop it using the "dropitems" command. + +count Specified score given to the AP's team. + +increase_team1 Specified score given to team 1 +increase_team2 Specified score given to team 2 +increase_team3 Specified score given to team 3 +increase_team4 Specified score given to team 4 + +noise WAV file played when this Goal is activated. + +lives Added to APA's lives. + +health Added to APA's health. + +armortype The APA's armortype is set to the Goals "armortype". + Armortype Bitfields: + 0.3 : Green + 0.6 : Yellow + 0.8 : Red + +armorvalue APA's armorvalue is set to this value. (0-250) + +armorclass APA's armorclass is set to this type(s). + 1 : Shell Resistant + 2 : Nail Resistant + 4 : Explosion Resistant + 8 : Electricity Resistant + 16 : Fire Resistant + +frags Added to APA's frags. + +ammo_shells Added this number of shells to the APA's ammo supply. +ammo_nails Added this number of nails to the APA's ammo supply. +ammo_rockets Added this number of rockets to the APA's ammo supply. +ammo_cells Added this number of cells to the APA's ammo supply. +ammo_detpack Added this number of det packs to the APA's supply. +ammo_medikit Added this number of medikits to the APA's supply. + +no_grenades_1 Added to APA's number of type 1 TF grenades. +no_grenades_2 Added to APA's number of type 2 TF grenades. + +invincible_finished Number of seconds of invincibility APA gets. +invisible_finished Number of seconds of invisibility APA gets. +super_damage_finished Number of seconds of quad APA gets. +radsuit_finished Number of seconds of radsuit APA gets. + +delay_time If the criteria is meant for activation, the goal waits + this amount of time before activating, in seconds. + +items Goal gives this GoalItem to APA. +axhitme Goal removes this GoalItem from APA that has it. + +distance If all GoalItems in this GoalItem Group are being carried + by players, activate the Goal in the "pain_finished" variable. + +pain_finished If all GoalItems in the GoalItem Group specified in the + "distance" variable are being carried by players, activate + this Goal. + +speed If all GoalItems in this GoalItem Group are being + carried by one player, activate the Goal in the + "attack_finished" variable. + +attack_finished If all GoalItems in the GoalItem Group specified in the "speed" + variable are being carried by one player, activate this Goal. + +noise3 String centerprinted to the all the members of the team + that own this GoalItem whenever it returns. + e.g. "Your flag has been returned to base\n" + +noise4 String centerprinted to the everyone except all the members + of the team that own this GoalItem whenever it returns. + e.g. "An enemy flag has been returned to base\n" + +team_drop Centerprinted to all members of the team that own this Item, + whenever this Item is dropped by a player. + e.g. "Your flag is lying around!\n" + +non_team_drop Centerprinted to all members not in the team that own this + Item, whenever this Item is dropped by a player. + e.g. "An enemy flag is lying around!\n" + +netname_team_drop Broadcast to all members of the team that own this item, + prepended by the name of the player who dropped the item. + A line break should be used at the end. + e.g. " lost your flag!\n" + +netname_non_team_drop Broadcast to all members not in the team that own this item, + prepended by the name of the player who dropped the item. + A line break should be used at the end. + e.g. " lost the enemy flag!\n" + +broadcast Message centerprinted to everyone except the AP. + e.g. "Clean-up on isle 4!" + +message Message centerprinted to AP. + e.g. "You activated this goal!" + +team_broadcast Message centerprinted to players on the AP's team, + except the AP. e.g. "Your team has the enemy flag!" + +non_team_broadcast Message centerprinted to players not on the AP's team. + If there is a "owners_team_broadcast" specified, this + message isn't centerprinted to the owners of the entity. + e.g. "An enemy flag was taken!" + +owners_team_broadcast Gets centerprinted to all the members of the + team that own the goal/item. + e.g. "Your flag was taken!" + +netname_broadcast Broadcast to all players, prepended to the AP's name. + A line break should be used at the end. + e.g. " activated this goal!\n" + +netname_team_broadcast Broadcast to all players on the AP's team, except + the AP, prepended by the AP's name. A line break should + be used at the end. + e.g. " activated your team's goal!\n" + +netname_non_team_broadcast + Broadcast to all players on the AP's team, prepended by the + AP's name. If there is a "netname_owners_team_broadcast" + specified, this message isn't broadcast to the owners of + the entity. A line break should be used at the end. + e.g. " took an enemy flag!\n" + +netname_owners_team_broadcast + Broadcast to all members of the team that own this entity + (see "owned_by" above), prepended by the AP's name. + e.g. " took your flag!\n" + +deathtype Death message appended to the AP's name and broadcasted, if the + AP is killed by the Goal. A line break should be used at the end. + e.g. " was killed by this goal!\n" + +activate_goal_no Activate this Goal. +inactivate_goal_no Inactivate this Goal. +remove_goal_no Remove this Goal. +restore_goal_no Restore this Goal. + +activate_group_no Activate all Goals in this GoalGroup. +inactivate_group_no Inactivate all Goals in this GoalGroup. +remove_group_no Remove all Goals in this GoalGroup. +restore_group_no Restore all Goals in this GoalGroup. + +remove_item_group Removes a GoalItems APA has from GoalGroup + +all_active If all Goals in this GoalGroup are ACTIVE, activate + the Goal in the "last_impulse" variable. + +last_impulse If all Goals in the "all_active" GoalGroup are ACTIVE, + activate this Goal. + +remove_spawnpoint Remove the spawnpoint with this "goal_no". + +restore_spawnpoint Restore the spawnpoint with this "goal_no", if it's + in the REMOVED state. + +remove_spawngroup Remove all spawnpoints with this "group_no". + +restore_spawngroup Restore all spawnpoints with this "group_no", if + they're in the REMOVED state. + +display_item_status1 Display this GoalItem Status when this goal is activated +display_item_status2 Display this GoalItem Status when this goal is activated +display_item_status3 Display this GoalItem Status when this goal is activated +display_item_status4 Display this GoalItem Status when this goal is activated + +team_str_home String displayed to the owners of an Item + in an Item Status if the Item is at it's origin. + If not the owner of the Item, non_team_str_home + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is in it's base" + +team_str_moved String displayed to the owners of an Item in an + Item Status if the Item is not at it's origin. + If not the owner of the Item, non_team_str_moved + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is lying around" + +team_str_carried String displayed to the owners of an Item in an Item + Status if the Item is being carried by a player. The + player's name is appended to the String. If not the + owner of the Item, non_team_str_carried will be used. + Refer to the "owned_by" variable for GoalItems. + e.g. "Your flag is being carried by" < players's_name> + +non_team_str_home String displayed to everyone except the owners of an + Item in an Item Status if the Item is at it's origin. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is in it's base" + +non_team_str_moved String displayed to everyone except the owners of an + Item in an Item Status if the Item is not at it's origin. + If they are owner of the Item, team_str_moved will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is lying around" + +non_team_str_carried String displayed to everyone except the owners of an + Item in an Item Status if the Item is being carried by a + player. The player's name is appended to the String. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is being carried by" < player's_name> + + +============================================================================ +TIMER GOAL VARIABLES (info_tfgoal_timer) +============================================================================ + +goal_effects Determines what players are affected. If nothing is specified + the goal will not effect anybody. Bitfields: + 1 : Illegal for Timer Goals + 2 : Illegal for Timer Goals + 4 : Illegal for Timer Goals + 8 : Illegal for Timer Goals + 16 : Radius effect (see "t_length") does not go + through walls. + 32 : If APA is not in the same environment as the + Goal, don't affect him. Environments are air, + water, slime, lava. e.g. If a Goal is above + some water, and does a radius effect with + "t_length", and a player in the water is within + the radius, he won't be affected if this bit + is set. + 64 : If this bit is set, then instead of just applying + this Goal's results to the group of players + specified by the other "goal_effects" variable, + this Goal checks it's criteria for each player + in the group and then applies it's results + invididually to any of them that pass. + +search_time Period between Timer activations. + +netname The name of the Timer Goal. (A reference) + +goal_no Unique ID number of this Timer Goal. + +group_no ID Number of the goal group this Timer Goal belongs to. + +goal_state The initial state of this entity. The default + (nothing specified) is Inactive the same as if + you specified a value of 2. Bitfields: + 1 : Active (Already On) + 2 : Inactive (Ready to be used) + 3 : Removed (Unmanipulatable until restored) + +items_allowed AP needs this GoalItem to be effected by the results. + +playerclass AP must be this playerclass to meet this Goal's criteria. + You can not add these up, you can only specify one player + class. Bitfields: + 1 : Only allow a Scout to activate + 2 : Only allow a Sniper to activate + 3 : Only allow a Soldier to activate + 4 : Only allow a Demolition Man to activate + 5 : Only allow a Medic to activate + 6 : Only allow a Heavy Weapons Guy to activate + 7 : Only allow a Pyro to activate + 8 : Only allow a Spy to activate + 9 : Only allow an Engineer to activate + +if_goal_is_active This Goal must be in ACTIVE state. +if_goal_is_inactive This Goal must be in INACTIVE state. +if_goal_is_removed This Goal must be in REMOVED state. +if_group_is_active All Goals in this Group must be in ACTIVE state. +if_group_is_inactive All Goals in this Group must be in INACTIVE state. +if_group_is_removed All Goals in this Group must be in REMOVED state. + +if_item_has_moved This GoalItem must not have moved from it's origin, + and must not be being carried. + +if_item_hasnt_moved This GoalItem must have moved from it's origin, + or be being carried. + +has_item_from_group APA will be effected if they have GoalItem + from group "group_no" + +maxammo_shells All members of this team are checked for meeting the criteria. + +maxammo_nails All members not on this team are checked for meeting the + criteria. + +t_length Everyone within this radius is affected. To specify whether + the radius should go through walls or not see bit 16 + in "goal_effects" + +------------------------------------------- +When this Goal is successfully activated +up, the following variables may be executed +------------------------------------------- + +return_item_no Return this GoalItem, if it's not being carried. + +deathtype Death message appended to the AP's name and broadcasted, if the + AP is killed by the Goal. A line break should be used at the end. + e.g. " was killed by this goal!\n" + +target Activate any Goal/Quake Trigger with this targetname + +killtarget Remove any Goal/Quake Trigger with this targetname + +ex_skill_min This entity is removed when the map starts if the game's "skill" + variable is >= to this value. To specify a skill of 0, use + -1 instead. + +ex_skill_max This entity is removed when the map starts if the game's "skill" + variable is <= to this value. To specify a skill of 0, use + -1 instead. + +goal_results Determines what results are applied to APA. Bitfields: + 1 : Goal is removed after activation. + 2 : Goals activated by this one apply their + results to APA. + 4 : Display scores and end the level. + 8 : Activated goals will not apply their results to + the APA + 16 : Disable/Stop the spy's undercover mask. + 32 : This forces APA to simply respawn. The player + doesn't die... just respawns. + 64 : If this bit is set, the results are applied to all the + players that do NOT fit the criteria. + +increase_team1 Specified score given to team 1 +increase_team2 Specified score given to team 2 +increase_team3 Specified score given to team 3 +increase_team4 Specified score given to team 4 + +noise WAV file played when this Goal is activated. + +lives Added to APA's lives. + +health Added to APA's health. + +armortype The APA's armortype is set to the Goals "armortype". + Armortype Bitfields: + 0.3 : Green + 0.6 : Yellow + 0.8 : Red + +armorvalue APA's armorvalue is set to this value. (0-250) + +armorclass APA's armorclass is set to this type(s). + 1 : Shell Resistant + 2 : Nail Resistant + 4 : Explosion Resistant + 8 : Electricity Resistant + 16 : Fire Resistant + +frags Added to APA's frags. + +ammo_shells Added this number of shells to the APA's ammo supply. +ammo_nails Added this number of nails to the APA's ammo supply. +ammo_rockets Added this number of rockets to the APA's ammo supply. +ammo_cells Added this number of cells to the APA's ammo supply. +ammo_detpack Added this number of det packs to the APA's supply. +ammo_medikit Added this number of medikits to the APA's supply. + +no_grenades_1 Added to APA's number of type 1 TF grenades. +no_grenades_2 Added to APA's number of type 2 TF grenades. + +invincible_finished Number of seconds of invincibility APA gets. +invisible_finished Number of seconds of invisibility APA gets. +super_damage_finished Number of seconds of quad APA gets. +radsuit_finished Number of seconds of radsuit APA gets. + +items Goal gives this GoalItem to APA. +axhitme Goal removes this GoalItem from APA that has it. + +delay_time If the criteria is meant for activation, the goal waits + this amount of time before activating, in seconds. + +wait Goal stays ACTIVE for this amount of time, in seconds. + +activate_goal_no Activate this Goal. +inactivate_goal_no Inactivate this Goal. +remove_goal_no Remove this Goal. +restore_goal_no Restore this Goal. + +activate_group_no Activate all Goals in this GoalGroup. +inactivate_group_no Inactivate all Goals in this GoalGroup. +remove_group_no Remove all Goals in this GoalGroup. +restore_group_no Restore all Goals in this GoalGroup. + +all_active If all Goals in this GoalGroup are ACTIVE, activate + the Goal in the "last_impulse" variable. + +last_impulse If all Goals in the "all_active" GoalGroup are ACTIVE, + activate this Goal. + +remove_item_group Removes a GoalItems APA has from GoalGroup + +remove_spawnpoint Remove the spawnpoint with this "goal_no". + +restore_spawnpoint Restore the spawnpoint with this "goal_no", if it's + in the REMOVED state. + +remove_spawngroup Remove all spawnpoints with this "group_no". + +restore_spawngroup Restore all spawnpoints with this "group_no", if + they're in the REMOVED state. + +display_item_status1 Display this GoalItem Status when this goal is activated +display_item_status2 Display this GoalItem Status when this goal is activated +display_item_status3 Display this GoalItem Status when this goal is activated +display_item_status4 Display this GoalItem Status when this goal is activated + +team_str_home String displayed to the owners of an Item + in an Item Status if the Item is at it's origin. + If not the owner of the Item, non_team_str_home + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is in it's base" + +team_str_moved String displayed to the owners of an Item in an + Item Status if the Item is not at it's origin. + If not the owner of the Item, non_team_str_moved + will be used. Refer to the "owned_by" variable + for GoalItems. + e.g. "Your flag is lying around" + +team_str_carried String displayed to the owners of an Item in an Item + Status if the Item is being carried by a player. The + player's name is appended to the String. If not the + owner of the Item, non_team_str_carried will be used. + Refer to the "owned_by" variable for GoalItems. + e.g. "Your flag is being carried by" < players's_name> + +non_team_str_home String displayed to everyone except the owners of an + Item in an Item Status if the Item is at it's origin. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is in it's base" + +non_team_str_moved String displayed to everyone except the owners of an + Item in an Item Status if the Item is not at it's origin. + If they are owner of the Item, team_str_moved will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is lying around" + +non_team_str_carried String displayed to everyone except the owners of an + Item in an Item Status if the Item is being carried by a + player. The player's name is appended to the String. + If they are owner of the Item, team_str_home will be + used. Refer to the "owned_by" variable for GoalItems. + e.g. "The enemy flag is being carried by" < player's_name> + +============================================================================ +OTHER QUAKE ENTITY VARIABLES +============================================================================ + + +func_button / func_door + This works the same as info_tfgoal except for obvious + variables such as "model". Additional Bitfields: + goal_activation 8 : only activated when hit by an engineer's spanner + + +OTHER ENTITIES Most Quake entities work the same as info_tfgoal except + for obvious variables such as "model", "goal_no", and + "goal_activation" fields. So you can limit func_doors to + certain team_nos and so on... + + +============================================================================ +VARIABLE ABBREVIATION LIST +============================================================================ + +Abbreviations can be used in replace of certain full named variables to save +entity space due to many Quake limits. Here is a complete list of all the +variables: + + + Classnames + "i_p_t" for "info_player_teamspawn" + "i_t_g" for "info_tfgoal" + "i_t_t" for "info_tfgoal_timer" + + Floats + "g_a" for "goal_activation" + "g_e" for "goal_effects" + + "h_i_g" for "has_item_from_group" + "r_i_g" for "remove_item_group" + + "a_s" for "ammo_shells" + "a_n" for "ammo_nails" + "a_r" for "ammo_rockets" + "a_c" for "ammo_cells" + + "rv_s_h" for "remove_spawngroup" + "rs_s_h" for "restore_spawngroup" + "rv_gr" for "remove_group_no" + "rs_gr" for "restore_group_no" + "rv_g" for "remove_goal_no" + "rs_g" for "restore_goal_no" + + Strings + "t_s_h" for "team_str_home" + "t_s_m" for "team_str_moved" + "t_s_c" for "team_str_carried" + "n_s_h" for "non_team_str_home" + "n_s_m" for "non_team_str_moved" + "n_s_c" for "non_team_str_carried" + + "b_b" for "broadcast" + "b_t" for "team_broadcast" + "b_n" for "non_team_broadcast" + "b_o" for "owners_team_broadcast" + "n_b" for "netname_broadcast" + "n_t" for "netname_team_broadcast" + "n_n" for "netname_non_team_broadcast" + "n_o" for "netname_owners_team_broadcast" + + "d_t" for "team_drop" + "d_n" for "non_team_drop" + "d_n_t" for "netname_team_drop" + "d_n_n" for "netname_non_team_drop" + +EOF + diff --git a/docs/tfortmap.txt b/docs/tfortmap.txt new file mode 100644 index 00000000..0e313ba2 --- /dev/null +++ b/docs/tfortmap.txt @@ -0,0 +1,1648 @@ +*==============================================================* +* TeamFortress v2.8 tfortmap.txt * +*==============================================================* +Introduction +------------ + +NOTE: If you're interested in seeing what was added since version 2.1, + I suggest you check out the "Summary of Changes" at the bottom + of the file. + +If you haven't read the readme.txt by now, please do. + +This file contains details about making Maps specifically +for TeamFortress. You don't need to know these details to +play the game, even on a TeamFortress Map. + +Beware! This is not for the faint-hearted! + +There are few maps on the WWW page that use these specs to +do interesting things. Don't forget you can simply view the +.bsp file to look at the entities inside the map, so if +you want to see some examples of Goals, etc, I suggest you +look at those maps. + +Oh, and some variables we use for the Goal entities are variables +used for completely different things for other entities. We did +this to preserve variable space. + +Also, this document has been re-hashed so many times that it's +almost certain that I missed updating a bitfield number or +something. If you see anything that looks wierd, or is +contradicted somewhere else in the document, please tell me. + +Finally, The TeamFortress Entity Editor is available on +the WWW page. It's a Windows program that creates goals, items, +etc for you. I suggest you read these specs, and skip over +the Technical Info. Then, just use the Entity Editor to make +your goals. +Reading the Technical Info is good, since it will give you a +better understanding of Goal entities and their uses, but don't +bother trying to remember it all. + +Robin. + +---------------------------------------------------------------------------- +TeamFortressMap Specification +---------------------------------------------------------------------------- +Apart from being a normal map, TeamFortress Maps +have the following changes: + + Auto Detection + Team SpawnPoints + Armor + + Goals + GoalItems + Timer Goals + +If you are only interested in the changes made to the map specs +since the last version, to update your maps etc, then check +out the section entitled "Summary of Changes" + +---------------------------------------------------------------------------- +Notes about using existing Entities +---------------------------------------------------------------------------- +In TeamFortress, we have an Observer mode, where players who haven't +chosen a class, or have run out of lives, are able to cycle through +all the Intermission points to watch the action. +Because of this, make sure you have a few Intermission points at +interesting viewing locations around the map. If you don't have some +of these, Observers won't have much fun. + +---------------------------------------------------------------------------- +Auto Detection +---------------------------------------------------------------------------- +TeamFortress maps will be automatically detected by the TeamFortress patch +if you put an entity in the map with a classname of "info_tfdetect". +This makes TeamFortress automatically turn on the FORTRESSMAP toggleflag, +and turn on teamplay. + +Also, once the TeamFortress map has been detected, the patch will look +for any spawnpoints dedicated to teams (see below). +If it finds any, it will look for the highest team number that is used. +Once found, it will limit anybody attempting to join a team to that +number. +At the moment, Maps are limited to a maximum of 4 teams. +E.g. If the highest team number used by a Team Spawnpoint is 3, then + the patch will only allow players to join teams 1, 2, and 3. + + +The detection entity can also do the following: + - specify a version string in the "broadcast" variable. + This will be compared with the version string for the TeamFortress + patch. If the don't match, a warning will be displayed to the + player that their patch and the map are incompatible. + The version string is in the format as follows: + TeamFortress v2.1 + The string is case sensitive, so make sure you've got it right. + Don't put a \n on the end of it. + + - Set the state of the toggleflags when the map starts up. The + value of the toggleflags should be in the "impulse" variable. + The bits for the toggleflags are: + + Bit 1 (1) : Off - ClasSkin , On - Multiskin + Bit 2 (2) : Off - ClassPersistence Off , On - ClassPersistence On + Bit 3 (4) : Off - CheatChecking Off , On - CheatChecking On + Bit 4 (8) : Off - FortressMap Off , On - FortressMap On + Bit 5 (16) : Off - RespawnDelay Off , On - RespawnDelay (See below) + Bit 6 (32) : Off - RespawnDelay Off , On - RespawnDelay (See below) + Bit 7 (64) : Off - AutoTeam Off , On - AutoTeam On + Bit 8 (128) : Off - Individual Frags , On - Frags = TeamScore + + N.B. FortressMap will be set On automatically by the the + Detection entity anyway, so just ignore that Bit. + + N.B. The RespawnDelay settings takes 2 bits. The value of both of + them determines the level of respawn delay, as follows: + Bit 5 Bit 6 Result + Off Off No Respawn delays + On Off 5 Second respawn delay + Off On 10 Second respawn delay + On On 20 Second respawn delay + + - Specify a string which is then "localcmd"ed. This allows you + to automatically set gravity, friction, etc. + The string should be stored in the "message" variable. + + - Put a limit on the number of lives each player has. When a player + runs out of lives, they are stuck in observer mode for the rest + of the level. + Lives for each player depend on the setting for the team they + belong to. The number of lives players of each team be should + be specified in the following variables: + Team 1 : "ammo_shells" + Team 2 : "ammo_nails" + Team 3 : "ammo_rockets" + Team 4 : "ammo_cells" + If the value of any team is 0, then the players of that team get + infinite lives. + + - Specify any playerclass that is _not_ allowed on this map + for each particular team. + The bits of the four variables are used for this. + The variables are as follows: + Team 1 : "maxammo_shells" + Team 2 : "maxammo_nails" + Team 3 : "maxammo_rockets" + Team 4 : "maxammo_cells" + Also, the "playerclass" variable can be used to restrict classes + for all teams. + The bits for all the variables are as follows: + Bit 1 (1) : No Scout + Bit 2 (2) : No Sniper + Bit 3 (4) : No Soldier + Bit 4 (8) : No Demolitions Man + Bit 5 (16) : No Combat Medic + Bit 6 (32) : No Heavy Weapons Guy + Bit 7 (64) : No Pyro + Bit 8 (128) : No Random PlayerClass + Bit 9 (256) : No Spy + Bit 10(512) : No Engineer + E.g. If the "maxammo_nails" variable is set to 3, then players + in Team 2 will be unable to play Scouts or Snipers. + + Finally, if you want the Team to be a special team for a fancy + map, such as the President in President-Quake, then you can + restrict the team to only play Civilian Class. Do this by setting + the team's variable to "-1". + +Notes: + When using the "message" variable to set do localcmd's, you + can issue more than one command by seperating them with \n + Make sure you end it with a \n too. + E.g. The following changes the gravity and the friction. + "message" "sv_gravity 200\nsv_friction .5\n" + +---------------------------------------------------------------------------- +Team Spawnpoints +---------------------------------------------------------------------------- +There is now a new entity for Team Spawnpoints. Team Spawnpoints are used +to make players only spawn in points designated for their team. Use it +to make players spawn inside their own base/fortress. +The entity is called "info_player_teamspawn", and the "team_no" variable +sets the team_no that owns this spawnpoint. + +Also, spawnpoints allow you to give any player the spawns from this +point a GoalItem. This is done using the following variables: + "items" : Contains the ID of the GoalItem to give + "message" : Message displayed to anyone who spawns on this + point. + +The "goal_activation" of the Spawnpoint determines how the above works: + + 1 : If set, then every player who spawns on this point + will be given a copy of the GoalItem. Otherwise, only + the first player to spawn will be given it. + 2 : If set, then every player who spawns on this point + will have the "message" displayed to them. Otherwise, only + the first player to spawn will be see it. + +Also, the "goal_effects" variable of the spawnpoint sets the re-use +behaviour of the spawnpoint. If it's 1, then the spawnpoint removes +itself after someone has spawned on it. + + +---------------------------------------------------------------------------- +Armor +---------------------------------------------------------------------------- +TeamFortress supports not only armor levels and absorption percentages the +same way Quake does: it also supports armor classes. E.g. Armor can be designed +to prevent particular attack types. +The Armor Types are as follows: + + Kevlar : Better protection against Bullets + Wooden ;) : Better protection against Nails + Blast : Better protection against Explosions + Shock : Better protection against Electricity + Ceramic : Better protection against Fire + +To use these armor types, just create an armor entity on the map as usual, +and set it's "armorclass" variable. The "armorclass" is used as bitfields, +as follows: + Bit 1 (1) : Kevlar + Bit 2 (2) : Wooden + Bit 3 (4) : Blast + Bit 4 (8) : Shock + Bit 5 (16) : Ceramic + +Any combination of armor is legal, but try not to have armor which +is too good. + +---------------------------------------------------------------------------- +Goal Summary / Terminology +---------------------------------------------------------------------------- +Goals are the really fun things you can do with TeamFortressMaps. +A goal is simply an entity you place in a map. It is then handled +in the game based on the flags you give it. They're essentially +more complex triggers. I've kept all the code separate from +the triggers tho, to allow us to toggle the use of them ingame. +The flags and variables set for a Goal allow us to create powerful +maps without changing the QuakeC code at all. +----------- +Goals +----------- +Goals are always in one of the following states: + +ACTIVE : The goal has been activated in some way. + It cannot be touched by a player. + Active goals return to the INACTIVE state based on their + result criteria, or when they're forced into INACTIVE state + by another goal. + +INACTIVE: The goal is not active. + It can be activated by players, and if the players meet the + activation criteria, the goal moves to the ACTIVE state. + +REMOVED : The goal is not active. + It cannot be touched by players. + Removed goals can still be activated by other goals, in which + case they move to the ACTIVE state. + Removed goals can be restored to the INACTIVE by being restored + by another goal. + +Terminology +----------- + +activated : Goal moves to the ACTIVE state +inactivate : If the Goal is in ACTIVE state, it moves to the INACTIVE state +removed : Goal moves to the REMOVED state +restored : If the Goal is in REMOVED state, it moves to the INACTIVE state + +returned : GoalItems can be returned to their starting point, based on + a number of settings. + +Goal Group : A group of goals that can be altered as one. + +Activating Player(AP): The player who either touched the Goal, or set the + detpack which touched the Goal. In the case of GoalItems, + the player that's attempting to pick up the GoalItem. + +Actions +------- +When goals go to ACTIVE state, they can perform various actions. +These include: + + - Increase the score of the team the AP belongs to. + - Display a message to all players + - Display a message just to the AP + + - Alter the details of one or more players, as follows: + - Give the player extra lives (if applicable) + - Alter a player's health/ammo/armor/powerups + - Give the player(s) a GoalItem + - Remove a GoalItem from the player(s) + + The player can be the AP, all the members of a Team the AP is/isn't in, + all the players on the map, everyone but the AP, all the players + within a specified distance from the goal, or everyone in/not in one + particular team. + + - Activate another goal, applying the bonuses of the goal to the AP + - Activate another goal, without applying the bonuses of the goal to the AP + - Inactivate another goal + - Remove another goal + - Restore another goal + + - Activate a goal if all the goals in a goal group are now ACTIVE + - Activate a group of goals + - Inactivate a group of goals + - Remove a group of goals + - Restore a group of goals + + - Display team's scores and End the Level + +Activation +---------- +Goals can be activated in one of the following ways: + + - Touched by a player + - Touched by a detpack explosion + - Activated by another Goal + - Activated by a Goal Group command from another Goal + - Activated by a Quake Trigger + +Additionally, the AP's details can be checked. +This allows you to have goals that are only activated if: + + - The AP is of a particular class + - The AP has a particular GoalItem + - The AP is of a particular team + +Goals can also be activated only if the AP details _don't_ +meet the criteria specified. + +Inactivation +------------ +Goals can be inactivated in one of the following ways: + + - Inactivated after being ACTIVE for a specified time + - Inactivated by another Goal + - Inactivated by a Goal Group command from another Goal + +Also, some goals are marked as Multiple Goals. They return to INACTIVE +state immediately after they become ACTIVE. + +Removal +------- +Goals can be removed in one of the following ways: + + - Removed after being activated + - Removed by another Goal + - Removed by a Goal Group command from another Goal + - Removed by a Quake Trigger + +Restoration +----------- +Goals can be restored in one of the following ways: + + - Restored by a GoalItem when it Returns (See below). + - Restored by another Goal + - Restored by a Goal Group command from another Goal + +---------------------------------------------------------------------------- +GoalItems +---------------------------------------------------------------------------- +GoalItems are items that players can carry around. +GoalItems can be placed directly into a map, where a player +can collect them as usual. +Also, on activation, Goals can give/remove GoalItems from the AP. +The details of players attempting to collect the GoalItems can +also be checked. +This allows you to have GoalItems that can only be picked up if: + + - The Player is of a particular class + - The Player has a particular GoalItem + - The Player is of a particular team + +GoalItems can also be set to only be picked up by players who +meet the AP criteria. + +GoalItems can be returned to their starting position in any of the +following circumstances: + + - When it's dropped by a dying player + - When it's removed from an AP by a Goal activation + - When it's untouched for a specified time + +GoalItems can affect players in the same way Goals can, except that +any modifications done by the GoalItem are permanent, until the +GoalItem is dropped. +E.g. if a GoalItem grants invisibility to any players, they stay +invisible until the GoalItem is dropped/removed. + +Also, when they're picked up by a player, GoalItems can perform the +following actions on Goals: + + - Activate another goal, applying the bonuses of the goal to the AP + - Activate another goal, without applying the bonuses of the goal to the AP + - Inactivate another goal + - Remove another goal + - Restore another goal + + - Activate a group of goals + - Inactivate a group of goals + - Remove a group of goals + - Restore a group of goals + +GoalItems can also belong to Groups. GoalItems groups are kept +separate from Goal Groups. Operations on either of them do not +affect the other type, even if the Group No is the same. +Using GoalItem groups, GoalItems can: + + - Activate a goal if all the Items in a GoalItem group are being + carried by players. + - Activate a goal if all the Items in a GoalItem group are being + carried by one particular player. + +---------------------------------------------------------------------------- +Timer Goals +---------------------------------------------------------------------------- +There is also a special type of goal called a Timer Goal. TG's +have a Timer Delay. TG's start INACTIVE, and then every Timer +Delay seconds they activate, do their results, and inactivate. +They can also be forced to activate by other Goals. They cannot +be activated by player or detpack touches. +N.B. When a TG goes ACTIVE, it does not have any AP, and hence + _cannot_ activate other goals, or apply modifications to + individual players. + +N.B. When a TG is forced to activate by another goal, they reset + their internal timer that decides when they are next going + to activate. + E.g. If a TG with a setting of 5 seconds is forced to activate, + it will reset it's timer, and still activate 5 seconds after + it was forced to activate. + +So, as a quick summary, TG's can have their state altered as +usual by other goals, and when they activate, they can: + + - Display a message to all players + + - Alter the details of one or more players, as follows: + - Give a player extra lives (if applicable) + - Alter a player's health/ammo/armor/powerups + - Give a player a GoalItem + - Remove a player from an AP + + The player can be all the members of a Team, all the players + on the map, or all the players within a specified distance from + the goal. + + - Inactivate another goal + - Remove another goal + - Restore another goal + + - Inactivate a group of goals + - Remove a group of goals + - Restore a group of goals + + - Display team's scores and End the Level + +---------------------------------------------------------------------------- +Standard Quake Triggers and TeamFortress Goals +---------------------------------------------------------------------------- +Quake triggers can be linked into TF Goals and vice versa. +When they are activated, a trigger can affect Goals +in the following ways: + + - Activate a goal, applying the bonuses of the goal to the AP + - Activate a goal, without applying the bonuses of the goal to the AP + - Inactivate another goal + - Remove another goal + - Restore another goal + + - Activate a group of goals + - Inactivate a group of goals + - Remove a group of goals + - Restore a group of goals + +When a Goal is activated, it can affect Quake Triggers +in the following ways: + + - Activate Quake Trigger(s) + - Remove Quake Trigger(s) + +Don't forget that Quake Triggers include Buttons, Doors, +Platforms, Health Boxes, Backpacks, Weapons, Armor, Keys, Sigils, +Monsters, Spikeshooters, Lights, Special Walls, and +Teleporters.. +The 'activation' of any of these things can affect goals +if you want it to. +Triggers Activate when: + + - Collected by a player + Health Boxes, Weapons, Armor, Keys, Sigils, Backpacks + - Touched by a player or hit by a weapon + Buttons, Doors, Platforms, Special Walls,Teleporters + - Killed + Monsters + +Also, Quake Triggers have been enhanced so that any Trigger +can be made to triggered only by a player if: + - The Player is of a particular class + - The Player has a particular GoalItem + - The Player is of a particular team + +This means that if the player does not match the criteria, +the following happens: + - Health Boxes, Weapons, Armor, Keys, Sigils, Backpacks + Player cannot pick them up. + - Buttons, Doors, Platforms, Special Walls, Teleporters + Player cannot activate/open/use them. + - Monsters + Player cannot hurt them. + +The result of 'Activation' of Triggers are as follows: + + - Health Boxes, Weapons, Armor, Keys, Sigils + Bad. These items should never be activated by + Goals or Triggers. They should only be used + to activate other Goals/Triggers. + + - Buttons + The button, if not already depressed, depressed + and sets off whatever it was designed to do. + + - Doors + If the door is a DOOR_TOGGLE type door, it reveres it's + current state. e.g. Opens if it's closed, closes if it's open. + It not, if it's closed, it opens. + + - Platforms + If it has not been triggered before, it will lower. Otherwise, + it does nothing. + + - Special Walls + Changes it's texture. + + - Teleporters + Doesn't do anything. + + - Monsters + Wakes the monster. + +These are a rough guide. You should look at the qc code which handles +trigger activation to see the details. Every Trigger that can be +activated by another trigger/goal has a .use function. +Look inside it to see how activations for that type of Trigger +are handled. + +---------------------------------------------------------------------------- +Order of Actions +---------------------------------------------------------------------------- +You don't really need to know the order in which the actions are applied, +and they're far too complex now to describe them in any useful way. The +only important thing of note is: + + The Group Goal alterations are applied _before_ the single goal + alterations. This is so you can do things like: + Inactivate an entire group, and then activate one goal in that group. + Remove an entire group, and then restore one goal in that group. + +---------------------------------------------------------------------------- +Goal Technical Info +---------------------------------------------------------------------------- +Goal behaviour is entirely defined by the variables of the Goal object +when it is spawned at the start of the level. These variables are set +in the map file. Just add up the flags that you want and set the +variable to that. +E.g. If you want a goal that can be activated by a Player touch(1) and + a detpack explosion(2), you would set the "goal_activation" variable + to 3. + +Don't worry! It's actually fairly easy :) +N.B. Bit descriptions marked with (*) are dangerous, and should + be handled with care. + +The variables of the Goals are handled as follows: + + classname : "info_tfgoal" + broadcast : Message broadcasted when this goal is activated, if any. + Don't forget to put the \n at the end of it. + message : Message displayed to the activating player, if any. + Don't forget to put the \n at the end of it. + deathtype : Message broadcasted if the goal kills the activating + player. It is appended to the name of the player. + E.g. deathtype = " gets killed by a goal!\n" displays + Bro gets killed by a goal! + Not needed if this goal doesn't do damage to a player. + Don't forget to put the \n at the end of it. + target : If set, any Quake Triggers with the same name as this + will be activated. + killtarget : If set, any Quake Triggers with the same name as this + will be removed. + count : Score the team of the player who activates this goal gets. + Use negative numbers for penalty goals. + goal_no : A unique number ID identifying this goal. Used to make + references to this goal in other goals. + group_no : The number of the goal group this goal belongs to. + netname : This isn't used in Quake, but in the TeamFortress + Entity Editor, it's used as the name for this goal. + noise : A .wav file played when the goal is activated. + Make sure it's a .wav file you've got. It's probably + best to use one of Quake's .wavs. + If unspecified, no sound is played. + mdl : The .mdl file used for this item. Make sure it's a .mdl + file you've got. It's probably best to use one of Quake's + .mdls. If unspecified, the Goal is invisible. + +All the following attributes are applied to the attributes of +every player specified by the "goal_effect"(see below). +(e.g. the self.health is added to the health of the player) + lives : Use negative values to remove lives from the player + health : Use negative values to hurt the player + armortype : The player's armortype is set to this value + armorvalue : The player's armorvalue is set to this value + Armortypes are: + 0.3 : Green + 0.6 : Yellow + 0.8 : Red + armorclass : The type of armor the player gets. (See Armor Types above) + frags : Use negative values to lower frag count + ammo_shells : Use negative values to remove ammo + ammo_nails : Use negative values to remove ammo + ammo_rockets : Use negative values to remove ammo + ammo_cells : Use negative values to remove ammo + ammo_medikit : Use negative values to remove ammo + ammo_detpack : Use negative values to remove ammo + +Note A: After applying all these values to the player, the playerclass + limitations of the player are applied. So if you set the health of + the player over that allowed, by his/her playerclass, it will then + be lowered to the max_health for that playerclass. + +Note B: "lives" allows you to give/remove lives from players. This is only + useful if the current map limits the number of lives each player + has. See the Auto Detection section above. + +TeamFortress Grenades can be given/removed to/from the player by setting +the following two variables. + no_grenades_1 : Use negative values to remove grenades + no_grenades_2 : Use negative values to remove grenades + +And finally, the following attributes are added to the global time +and applied to every player specified by the "goal_effect"(see below). +(e.g. if the goal's invincible_finished is 5, then the player will +get invincibility for 5 seconds after activating the goal.) + invincible_finished : Pentagram of Protection + invisible_finished : Ring of Shadows + super_damage_finished : Quad Damage + radsuit_finished : Environmental Suit + +--------------------------- +Goal Activation +--------------------------- +The "goal_activation" of the goals determine how the goal is activated. +The bitfields are as follows: + +Activation Details + 1 : Activated when touched by a player. + 2 : Activated when touched by a detpack explosion. + +AP Details + - If the "items_allowed" variable is non-zero, the AP must be + carrying a GoalItem with an ID of "items_allowed". + - If the "playerclass" variable is non-zero, the AP must be + be of the same class specified in "playerclass". + Classes are: + Scout : 1 + Sniper : 2 + Soldier : 3 + Demolitions Man : 4 + Medic : 5 + Heavy Weapons Guy : 6 + - If the "team_no" variable is non-zero, the AP must belong + to the same team as the number specified in "team_no". + + 4 : This goal is only activated if the AP details above are _not_ met. + + 2048: If this bit is set, the Goal/Item drops to the ground when it + first spawns. + +--------------------------- +Goal Effects +--------------------------- +The "goal_effects" of the goal defines which players are affected by +the activation of the goal. It defaults to 1, so that only the AP is +affected. +The player modifications of this Goal are applied to every player +that matches these criteria. GoalItems will also be given/removed +to/from every one of the players matching the criteria. +The bitfields are as follows: + +Basics + 1 : The AP is affected + 2 : Everyone on the AP's team is affected + 4 : Everyone not on the AP's team is affected + 8 : Everyone except the AP is affected + +Specific Groups + - If the "maxammo_shells" variable is non-zero, then all members of that + team are affected. + - If the "maxammo_nails" variable is non-zero, then all members of any + team except that one are affected. + +Radius + - If the "t_length" variable is non-zero, then everyone within + "t_length" distance of the goal is affected, unless the above + bitfields are in use. + If they are, then the bitfield check is applied only to those + caught in the radius. + E.g. if "t_length" is 50, and "goal_effects" is 4, then everyone + within 50 who isn't on the AP's team is affected. + + 16 : If set, the radius effect is obstructed by walls. + + 32 : If a player who fits one of the other "goal_effects" variables + is not in the same environment as the Goal, don't affect him. + Environments are air, water, slime, lava. + e.g. If a Goal is above some water, and does a radius effect + with "t_length", and a player in the water is within the + radius, he won't be affected if this bit is set. + +Note A: If the Goal gives out a GoalItem, then every player who matches + this criteria will get the GoalItem. This can result in lots of these + GoalItems, so be careful. + +--------------------------- +Goal Results +--------------------------- +The "goal_result" of the goals determine how the goal behaves when it is +activated, and the results of it's activation. It also determines what it +will do to any players that match it's "goal_effects" criteria. +The bitfields are as follows: + +Respawn behaviour + 1 : The goal is immediately removed after it is activated. + + - If the "wait" variable is non-zero, then the Goal stays ACTIVE for + the "wait" seconds, and then inactivates. + If "wait" is -1, the Goal stays active permanently. + +GoalItem behaviour + - If the "items" variable is non-zero, the Goal gives a GoalItem + to the player. The GoalItem it gives is the Item with a GoalNo + of "items". + - If the "axhitme" variable is non-zero, the Goal removes a GoalItem + from the player. The GoalItem it removes is the Item with a GoalNo + of "axhitme". + If the player does not have the GoalItem, nothing happens. + +Goal behaviour + 2 : If this is set, the goals activated by this one apply + their AP modifications. Otherwise, they don't. + + - If the "activate_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is activated. + - If the "inactivate_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is inactivated. + - If the "remove_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is removed. + - If the "restore_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is restored. + +Miscellaneous + 4 : Display teamscores, fire intermission, and end the level + + 8 : GoalItems given out by this Goal don't apply their results. + + 16 : If the player these results are being applied to is a Spy, + reset his/her skin and color. + +---- +Note A: If (1) is not set and their is no "wait" specified, then the + goal is a Multiple Goal. + After it activates, it will automatically inactivate. + This is not always a good idea. When a player runs over an entity, + the touch function will usually be run about 6 or 7 times, so the + player will activate the goal multiple times. If you want a player + to be able to activate it over and over again, make it respawn + every 2-3 seconds. + This is especially dangerous if the goal gives out an item on + activation, since you will end up with a _lot_ of items. + Of course, you may want this for a goal that is activated remotely + by another goal at certain times. + +Note B: When a goal is activated by another goal, _no_ checking is done + based on the "goal_activation" variable of the target goal. It is + simply activated. The AP who activated the original goal is used + as the activator for all the goals, but the stats of an activated + goal are only added to the player's if (2) is set on the goal + that activates it. + GoalItems are always given/removed. + +--------------------------- +Goal Groups +--------------------------- +Goal groups allow you to do operations of multiple goals in one go. +The "group_no" of a Goal defines the ID of goal group it is in. +Any goal group operation affects all goals with the specified ID. +A goal's "goal_group" specifies what operations, if any, it performs +on any goal groups. +Since I've cleaned up the goal group handling to get rid of bitflags +which aren't needed, there are no bits used in the "goal_group" +variable anymore :) +I've left it in anyway, since some may come along later. +Goal Group handling is as follows: + + - If the "all_active" variable is non-zero, then when this goal is activated, + a check is done. If all the goals in the group specified in the "all_active" + variable are ACTIVE, activate a goal with a goal number equal to the + value of the "last_impulse" variable. + + - If the "activate_group_no" variable is non-zero, activate all the + goals in that Group. + - If the "inactivate_group_no" variable is non-zero, inactivate all the + goals in that Group. + - If the "remove_group_no" variable is non-zero, remove all the + goals in that Group. + - If the "restore_group_no" variable is non-zero, restore all the + goals in that Group. + +---- +Note A: When a goal is activated by another goal, _no_ checking is done + based on the "goal_activation" variable of the target goal. It is + simply activated. The AP who activated the original goal is used + as the activator for all the group goals. + Bonuses of goals in groups are _never_ applied to the activating player. + GoalItems are always given/removed. + +---------------------------------------------------------------------------- +Timer Goal Technical Info +---------------------------------------------------------------------------- +Timer Goals are basically identical to Goals, except they are never activated +by players or detpack explosions. They automatically activate every +"search_time" seconds. They can also be activated by other goals and triggers. +The variables of Timer Goals are the same as Goals, except for: + + classname : "info_tfgoal_timer" + + search_time : The time in seconds that this goal activates. + e.g. a search_time of 2 makes this goal activate every + 2 seconds. + +As a result of their method of activation, Timer Goals can _never_ do +anything that requires an AP, and they can't activate any other Goals. +They _can_ do operations on groups of players, such as all the players +on the map, or all the players in a team, etc. +This is done using the "goal_effect" variable in much the same way +as Goals, as follows: +Basics + 1 : Illegal for Timer Goals. + 2 : Illegal for Timer Goals. + 4 : Illegal for Timer Goals. + 8 : Illegal for Timer Goals. + +Specific Groups + - If the "maxammo_shells" variable is non-zero, then all members of that + team are affected. + - If the "maxammo_nails" variable is non-zero, then all members of any + team except that one are affected. + +Radius + - If the "t_length" variable is non-zero, then everyone within + "t_length" distance of the goal is affected, unless the above + bitfields are in use. + If they are, then the bitfield check is applied only to those + caught in the radius. + E.g. if "t_length" is 50, and "goal_effects" is 4, then everyone + within 50 who isn't on the AP's team is affected. + + 16 : If set, the radius effect is obstructed by walls. + + 32 : If a player who fits one of the other "goal_effects" variables + is not in the same environment as the Goal, don't affect him. + Environments are air, water, slime, lava. + e.g. If a Goal is above some water, and does a radius effect + with "t_length", and a player in the water is within the + radius, he won't be affected if this bit is set. + + 64 : If this bit is set, then instead of just applying this Goal's + results to the group of players specified by the other + "goal_effects" variable, this Goal checks it's criteria for + each player in the group and then applies it's results invididually + to any of them that pass. + +Note A : The first 4 bits in the "goal_effects" are illegal for Timer Goals, + and should _never_ be set, because they involve an AP. + +---------------------------------------------------------------------------- +Goal Items Technical Info +---------------------------------------------------------------------------- +GoalItems do not have to be given to a player by a Goal activation. +They can be placed directly into a map. +The variables of the GoalItems are as follows: + + classname : "item_tfgoal" + netname : Name of this GoalItem. + broadcast : Message broadcasted when this goalitem is retrieved, if any. + Don't forget to put the \n at the end of it. + message : Message displayed to a player when they get the Item, if any. + Don't forget to put the \n at the end of it. + noise : A .wav file played when the item is collected. + Make sure it's a .wav file you've got. It's probably + best to use one of Quake's .wavs. + If unspecified, no sound is played. + mdl : The .mdl file used for this item. Make sure it's a .mdl + file you've got. It's probably best to use one of Quake's + .mdls. It defaults to the silver key. + goal_no : A unique number identifying this GoalItem. Used to make + references to this Item in goals. + goal_group : The number of the goalitem group this goal belongs to. + +GoalItems can also modify player details in the same Goals can, using +the "goal_effects" variable (see above). +The tricky bit is that any Player Modifications done by goals are added +when the player first picks the item up, and are _removed_ when the player +loses the item. +E.g. If the item has a health of 40, then the player gets 40 health + added to their health when he/she picks it up. Then, when they + drop it, he/she loses 40 health. +There are two exceptions to this: + + 1. Power-Ups. Items give the players a powerup for the entire time the + player has the item. The time specified in the _finished variable + is ignored: If it's non-zero, then all players the GoalItem specifies + get the power-up while item is still carried. + + 2. GoalItems. Items given/removed by another GoalItem when it's picked up + are not removed/given back when the original GoalItem is dropped/removed. + +With the "goal_effects" variable you can make Items affect more than +one player. This is done exactly as if it was just one person. +E.g. If the Item adds health to everyone, then as soon as any player +picks it up, the modifications are applied to everyone, and as soon as +it's dropped, the modifications are removed from everyone. + +Also, GoalItems can affect Goals in much the same way as other Goals, +as follows: + + - If the "activate_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is activated. + - If the "inactivate_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is inactivated. + - If the "remove_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is removed. + - If the "restore_goal_no" variable is non-zero, then the Goal with + a Goal_No equal to the variable is restored. + + - If the "activate_group_no" variable is non-zero, activate all the + goals in that Group. + - If the "inactivate_group_no" variable is non-zero, inactivate all the + goals in that Group. + - If the "remove_group_no" variable is non-zero, remove all the + goals in that Group. + - If the "restore_group_no" variable is non-zero, restore all the + goals in that Group. + +GoalItems can use the "goal_result" variable. The Bitfields are as follows: + + 2 : Goals activated by this Item don't apply bonuses to the AP. + + 16 : If the player these results are being applied to is a Spy, + reset his/her skin and color. + When a Spy is carrying a GoalItem with this bit set, he/she + will be unable to change skin and color. + +When Goals are activated by a GoalItem, the AP used to activate the Goals +is the Player who picked up the Item. AP Modifications are applied if (512) +is set it the "goal_activation" variable (see below). +GoalItems themselves have various bitfields to depict the GoalItem's +behaviour. The bitfields are stored in the GoalItem's "goal_activation" +variable, and are: + +Carrying Details + 1 : Any player carrying this item will glow. + 2 : Any player carrying this item will move at half-speed. +(*) 4 : When a player carrying this is killed, the item will be dropped + +Returning + 8 : Return the item if dropped by a dying player + 16 : Return the item if removed from a player by a goal activation. + 32 : Return the item if removed from the map by the action of the + (128) (see below). + + - If the "impulse" variable is non-zero, then when the GoalItem + is returned by one of the above, the goal with a Goal No equal to + the "impulse" is restored. + +Pickup Details + - If the "items_allowed" variable is non-zero, the Player must be + carrying a GoalItem with an ID matching the variable. If not, + he/she will not be able to get this item. + - If the "playerclass" variable is non-zero, the Player must be + be of the same class specified in the variable. If not, + he/she will not be able to get this item. + Classes are: + Scout : 1 + Sniper : 2 + Soldier : 3 + Demolitions Man : 4 + Medic : 5 + Heavy Weapons Guy : 6 + - If the "team_no" variable is non-zero, the Player must belong + to the same team as the number specified in the variable. + If not, he/she will not be able to get this item. + + 64 : This GoalItem can only be picked up by a player if they _don't_ + match the player details above. + +Miscellaneous + 128 : If this is set, then, after the goal is dropped by a player, + if it has not been touched for the time specified in the + "pausetime" variable, in seconds, it is removed. + + - If the "distance" variable is non-zero, then, If all GoalItems in the + goalitem group specified by "distance" are being carried by players, + activate a goal, the Goal No of which is specified in "pain_finished". + - If the "speed" variable is non-zero, then, If all GoalItems in the + goalitem group specified by "speed" are being carried by one player, + activate a goal, the Goal No of which is specified in "attack_finished". + + 256 : If a player carrying this Item dies, they keep it, even after + they respawn. + + 512 : If this Item is not being carried by a goal, it glows. + + 1024: When this item is removed from a player, don't remove the + effects this item gave the player. + + 2048: If this bit is set, the Goal/Item drops to the ground when it + first spawns. + + 4096: If this bit is set, any player carrying this item can drop + it using the "dropitems" command. + +---- +Note A: (4) is dangerous. If you have goals giving out this item multiple + times, make sure the item is getting removed somehow, or you could + end up with too many items on the map. + +Note B: The Pickup Details are only used when a player picks up this + item directly. If this item is given to an AP by a goal, these + are ignored. + +Note D: (128) allows you to make items that are untouched for a while + disappear. This should be set if you have Goals that give out + multiple copies of GoalItems that are dropped when players + carrying them are killed. Otherwise you could end up with too many + entities on the map :) + If you have a GoalItem that is only given out once and is dropped + when players with it die, you will probably want to set (128) + and (32), so that if it falls in lava or something, it'll be + returned. + If you don't specify a value, "pausetime" defaults to 2 minutes. + +---------------------------------------------------------------------------- +Quake Triggers that use TeamFortress Goals Technical Details +---------------------------------------------------------------------------- +For Triggers to use Goals, you need to use various variables. +Triggers can use the same AP criteria matching as Goals, as follows: + + - If the "items_allowed" variable is non-zero, the AP must be + carrying a GoalItem with an ID of "items_allowed". + - If the "playerclass" variable is non-zero, the AP must be + be of the same class specified in "playerclass". + Classes are: + Scout : 1 + Sniper : 2 + Soldier : 3 + Demolitions Man : 4 + Medic : 5 + Heavy Weapons Guy : 6 + - If the "team_no" variable is non-zero, the AP must belong + to the same team as the number specified in "team_no". + + +If any of the following variables is not set, or 0, then the effect of that +variable is simply not used. +The variables are: + + activate_goal_no : Activates a goal with a goal_no equal to this. + inactivate_goal_no : Inactivates a goal with a goal_no equal to this. + remove_goal_no : Removes a goal with a goal_no equal to this. + restore_goal_no : Restores a goal with a goal_no equal to this. + + activate_group_no : Activates a group of goals with a goal_group equal to this. + inactivate_group_no : Inactivates a group of goals with a goal_group equal to this. + remove_group_no : Removes a group of goals with a goal_group equal to this. + restore_group_no : Restores a group of goals with a goal_group equal to this. + + +Also: + + - If the "goal_result" variable of the Trigger is 0, then any Goals + activated by this Trigger _don't_ add bonuses to the AP. If it's 2, they do. + + - If the "all_active" variable is non-zero, then when this Trigger is activated, + a check is done. If all the goals in the group specified in the "all_active" + variable are ACTIVE, activate a goal with a goal number equal to the + value of the "last_impulse" variable. + +In all cases, the AP for the goals will be set to the "activator". If the +AP is not a player, then no player-related operations will be performed by +the Goals, or any Goals activated by those Goals. +This stuff is kind of dangerous, if the Trigger isn't activated by a player, +and the Goals your playing with alter other Goals. Just be careful :) + +---------------------------------------------------------------------------- +Summary of Changes +---------------------------------------------------------------------------- +This is a summary of changes in the map specs from TeamFortress v1.3x +to TeamFortress v2.x : + + - All entities, most especially GoalItems, can specify the team + they belong to by putting the team number in the "owned_by" variable. + + - The "goal_state" variable allows you to set the starting state + of a goal. The available states are: + Active 1 + Inactive (default) 2 + Removed 3 + + - Activation criteria for Goals/Items/Timers/Triggers can + now include the Checking of the state of other Goals + The following variables are used: + "if_goal_is_active" : If this is non-zero, the goal will only activate + if the goal with a "goal_no" matching + "if_goal_is_active" is active. + "if_goal_is_inactive" : As above, if the goal is inactive. + "if_goal_is_removed" : As above, if the goal is removed. + + "if_group_is_active" : As above, except that all goals with a "group_no" + matching "if_group_is_active" must be active. + "if_group_is_inactive": As above, if all the group is inactive. + "if_group_is_removed" : As above, if all the group is removed. + + - Upon activation, Goals can now centerprint more intelligently, + as follows: + "broadcast" : Instead of being bprinted, it now gets + centerprinted to everyone, except the AP. + You'll probably want to use "team_broadcast" + and "non_team_broadcast" instead. + "message" : Instead of sprinting to the AP, it now + centerprints. + "team_broadcast" : Gets centerprinted to all of the AP's team, + except the AP. + "non_team_broadcast" : Gets centerprinted to all non-AP-teammembers. + If there is a "owners_team_broadcast" specified, + it isn't centerprinted to members of the team + that own the goal/item. + "owners_team_broadcast" : Gets centerprinted to all the members of the + team that own the goal/item. + + - The detection entity can now supply the Team Menu string, which + effectively allows you to provide names for team. + The string should be put in the detection entity's "team_broadcast" var. + It gets centerprinted when player's are asked to join a team, + so it should be similar to the following format: + + "=== Choose your team ===\n\n1.. Team One \n\n\n\n\n7.. Bind my keys for me!\n\nFor full details on this patch:\nhttp://yallara.cs.rmit.edu.au/~cookj\n" + "=== Choose your team ===\n\n2.. Team One \n2.. Team Two \n\n\n\n\n7.. Bind my keys for me!\n\nFor full details on this patch:\nhttp://yallara.cs.rmit.edu.au/~cookj\n" + "=== Choose your team ===\n\n2.. Team One \n2.. Team Two \n3.. Team Three\n\n\n\n\n7.. Bind my keys for me!\n\nFor full details on this patch:\nhttp://yallara.cs.rmit.edu.au/~cookj\n" + "=== Choose your team ===\n\n3.. Team One \n2.. Team Two \n3.. Team Three\n4.. Team Four \n\n\n\n\n7.. Bind my keys for me!\n\nFor full details on this patch:\nhttp://yallara.cs.rmit.edu.au/~cookj\n" + + Other examples are: + + "=== Choose your team ===\n\n1.. Blue Team \n2.. Red Team \n\n\n\n7.. Bind keys" + "=== Choose your team ===\n\n1.. Attackers \n2.. Defenders \n\n\n\n7.. Bind keys" + + You need to have a team number and choice for every team on your map. + Don't forget that TF determines the number of teams on a map based upon + the Teamspawn points. If there are spawn points for 3 teams, then you + should have three teams in the team menu string. + + N.B. Unfortunately, qbsp prevents you from having large strings, so you + have to be curt. If you get a "Token too large" error when qbsping, + then you've got the string too long. + + - The detection entity can now specify a Map Help string in it's + "non_team_broadcast" variable. + Player's can do the Map Help impulse, and the Map Help string will + be printed. The string can be anything you like, but it should be + a quick description of the goal of the map, such as: + "Havoc: Get into the enemy's castle and destroy their computer room!\n" + + End the string with a \n. + N.B. Unfortunately, qbsp prevents you from having large strings, so you + have to be curt. If you get a "Token too large" error when qbsping, + then you've got the string too long. + + - All Entities can specify whether they exist for different skill + settings, as follows: + "ex_skill_min" : The entity only exists when the skill variable + is >= to this value. + "ex_skill_max" : The entity only exists when the skill variable + is <= to this value. + + N.B. The checking is done in the initial spawning, so if the skill + changes during the level, it will have no effect on the entities. + + You can use this to do so many things, such as making plats move + in different trains at different skill levels, more/less monsters + and ammo and different levels, more secrets at higher levels, etc. + + - Team Spawnpoints can set their "goal_effects" variable to 1, which + makes them remove themselves after someone has spawned on them. + Use this to make a team spawn inside their base initially, and then + spawn throughout the level for the rest of the game. + + - Items now have a ItemGlow flag, which makes the Item glow when it's + not being carried by a player. + The flag is Bit 10 (512) in the Goalitem's "goal_activation" variable. + + - The Detection entity can now restrict the classes available to + members of particular teams, in the following variables: + Team 1 : "maxammo_shells" + Team 2 : "maxammo_nails" + Team 3 : "maxammo_rockets" + Team 4 : "maxammo_cells" + + - The Detection entity can now specify a Class Selection string for + any team. The default string allows them to pick any class, but you + may want to refine it for teams that have a limited selection of + classes. + If you don't supply one, the default will be used. + The strings should be put in following Detection entity variables : + Team 1 String : "noise1" + Team 2 String : "noise2" + Team 3 String : "noise3" + Team 4 String : "noise4" + + The default string looks like this: + + "=== Choose your class ===\n\n1.. Scout \n2.. Sniper \n3.. Soldier \n4.. Demoman \n5.. Medic \n6.. Hvwep \n7.. Pyro \n8.. Spy \n9.. Engineer\n0.. Randompc\n" + + But if you restricted Team 1 to Scout, Demoman, and Medic, you might + want to set the "noise1" variable to: + + "=== Choose your class ===\n\n1.. Scout \n4.. Demoman \n5.. Medic \n" + + N.B. You _MUST_ not alter the numbering of the class. + e.g. Sniper must always be selected with 2, Demoman with 4, etc. + N.B. Unfortunately, qbsp prevents you from having large strings, so you + have to be curt. If you get a "Token too large" error when qbsping, + then you've got the string too long. + + - Any Goal can now specify an 'else' goal. This is a goal which attempts + to activate if this goal fails to activate because it's Criteria + wasn't met. The "goal_no" of the 'else' goal should be specified in + the Goal's "else_goal" variable. 'else' Goals still check their + criteria, the AP being the player who failed the first goal's criteria. + + - The Detection entity can now specify a maximum number of players + for each team. The default is 0, which is unlimited. + The player limits should be put in the following variables of + the Detection Entity : + Team 1 : "ammo_medikit" + Team 2 : "ammo_detpack" + Team 3 : "maxammo_medikit" + Team 4 : "maxammo_detpack" + + N.B. The total number of players _MUST_ be >= 16. This is the total + number of players for the _existing_ teams. + e.g. if you have TeamSpawnpoints for only 2 teams, then the + total number of players allowed in the two teams must be >= 16. + + - Any Goal can now display the status of upto 4 GoalItems when it's + activated. The Goal specifies 6 different strings, which are used + to do the displaying for all the items. + The item's "goal_no" are specified in the following variables: + "display_item_status1" : Item 1 + "display_item_status2" : Item 2 + "display_item_status3" : Item 2 + "display_item_status4" : Item 2 + + The strings are specified in the following variables: + "team_str_home" : Displayed when the item is at the point + it originally spawned at. + "team_str_moved" : Displayed if the item has been moved from + it's original spawning point. + "team_str_carried" : Displayed if the item is being carried. It + is prepended to the carrier's name, or " You" + if the Player is carrying the item. + e.g. "Your flag is being carried by" Bro. + "non_team_str_home" : Displayed when the item is at the point + it originally spawned at. + "non_team_str_moved" : Displayed if the item has been moved from + it's original spawning point. + "non_team_str_carried" : Displayed if the item is being carried. It + is prepended to the carrier's name, or " You" + if the Player is carrying the item. + e.g. "The enemy flag is being carried by" You. + + The "team..." strings are displayed to members of the team that the + GoalItem belongs too. The "non_team..." strings are displayed to anyone + not on the team the GoalItem belongs to. + If the Goalitem does not belong to a team, the "team..." strings + are displayed. + + Finally, if the Detection Entity has these variable set, then when + a player does Impulse 21 (FlagInfo in CTF), then the details of the + items specified by the Detection Entity will be displayed. + + - GoalItems can centerprint messages to players when they return to + their starting point, regardless of how they return. + Two messages should be supplied in the following variables: + "noise3" : Is centerprinted to all the members of the team + that own the item. + "noise4" : Is centerprinted to everyone except the members of + the team that own the item. + + - You can restrict teams to only the Civilian class, for special + purposes. Do it by setting their class restriction variable to "-1". + + - Any Goal can force a GoalItem to return, if it's not being carried, + by specifying an Item No in the "return_item_no" variable. + + - Goals activated by other Goals don't automatically activate like + they used to. Now they check their Criteria before activating. The AP + used is the AP of the first Goal. + N.B. The AP doesn't have to initiate the Criteria checking on + activated goals. E.g. The AP doesn't have to be touching + the Goal which was activated, even if the Goal's "goal_activation" + specifies that it's activated by touch. + + - GoalItems have a flag, which they can check, which tells them if they're + not at their starting position. + You can make any Goal/Item/whatever have part of it's Criteria + check to see if an Item is _not_ at it's origin by putting the + "goal_no" of the item in the "if_item_has_moved" variable. + You can make any Goal/Item/whatever have part of it's Criteria + check to see if an Item _is_ at it's origin by putting the + "goal_no" of the item in the "if_item_hasnt_moved" variable. + + - Goals that give out items can specify whether they want the Items + to apply their results. Usually, the goal that gives out the items + does all the results you want, so you can specify this. + Do it by setting Bit number 4 (8) in the Goal's "goal_result" variable. + + - The Detection Entity can specify that the grappling hook cannot + be used on a map, by setting the Detection Entity's "hook_out" + variable to 1. + + - Any Goal can remove/restore Teamspawnpoints. The variables to use + are: + "remove_spawnpoint" : Remove a spawnpoint with a matching "goal_no" + "restore_spawnpoint" : Restore the matching spawnpoint + "remove_spawngroup" : Remove all spawnpoints with a "group_no" + matching this number. + "restore_spawngoup" : Restore a group of spawnpoints. + + - GoalItems can make console items light up, such as the silver key icon, + when they're being carried. In the "items" variable, just specify a + bitfield. The bit's values are as follows: + + Silver Key : 131072 + Gold Key : 262144 + + Invisibility Icon : 524288 + Invulnerability Icon : 1048576 + Radsuit Icon : 2097152 + Quad Icon : 4194304 + + - GoalItems don't restore a goal when they return, now they activate it. + If you had any GoalItems using the "impulse" variable to restore a Goal + when the GoalItem returns, you'll need to redo the Goalwork. + + - Goals can increase the scores of any specific teams, using the following + variables: + + increase_team1 : Increase the score of team 1 by this value + increase_team2 : Increase the score of team 2 by this value + increase_team3 : Increase the score of team 3 by this value + increase_team4 : Increase the score of team 4 by this value + +------------------------- +Changes from 2.11 to 2.12 + + - Upon activation, Goals can now broadcast even more, + as follows: + + "netname_broadcast" : Gets bprinted to _all_ players, prepended + by the AP's name. + E.g. " got the RED flag" would be bprinted + as "Bro got the Red Flag" + + "netname_team_broadcast" : Gets bprinted to all of the AP's team, + except the AP, with the AP's name prepending + it. + + "netname_non_team_broadcast" : Gets bprinted to all non-AP-teammembers, + prepended by the AP's name. + If there is a "owners_team_broadcast" specified, + it isn't centerprinted to members of the team + that own the goal/item. + + "netname_owners_team_broadcast" : Gets bprinted to all the members of + the team that own the goal/item, prepended by + the AP's name. + +------------------------- +Changes from 2.12 to 2.13 + + - GoalItems can centerprint messages to players when they're dropped by + a dying player. + Two messages should be supplied in the following variables: + "team_drop" : Is centerprinted to all the members of the team + that own the item. + "non_team_drop" : Is centerprinted to everyone except the members of + the team that own the item. + Also, messages can be appended to the name of the player who dropped + the item, and then bprinted. + As follows: + "netname_team_drop" : Gets bprinted to all members of the team + who own the item, prepended by the name of + the player who dropped the item. + "netname_non_team_drop" : Gets bprinted to all players not of the team + who own the item, prepended by the name of + the player who dropped the item. + +------------------------- +Changes from 2.13 to 2.14 + + - A new Bit was added to the "goal_activation" of GoalItems. + As follows: + 1024: When this item is removed from a player, don't remove the + effects this item gave the player. + + E.g. If you've got a GoalItem giving a player 2 frags, when the + GoalItem is removed from the player, the 2 frags won't be + removed. Be Careful with this one. Check all the results you + bestow on the player before using it. + If necessary, have the GoalItem activate another goal which + bestows the effects you want on the player instead. + +------------------------- +Changes from 2.14 to 2.5 + + - A new Bit was added to the "goal_result" of Goals and GoalItems. + As follows: + + 16 : If the player these results are being applied to is a Spy, + reset his/her skin and color. + When a Spy is carrying a GoalItem with this bit set, he/she + will be unable to change skin and color. + + This enables you to have areas where spies cannot go undercover, etc. + It also means you can have the spy unable to change his/her skin/color + when carrying the flag. + To introduce a bit of backwards compatability, the spy cannot disguise + himself when he's dimly lit either, due to carrying a GoalItem with + the first bit of its "goal_activation" set. + Almost all the flags in existing TF maps have this bit set. + + - Goals can work with groups of items more now, using the following + variables: + "has_item_from_group" : More Criteria. Player must be carrying + at least 1 of the items in the group. + + "remove_item_group" : Result. Removes all items belonging to this + group from the Player. + + - A new Bit was added to the "goal_effects" of Goals and GoalItems. + As Follows: + + 32 : If a player who fits one of the other "goal_effects" variables + is not in the same environment as the Goal, don't affect him. + Environments are air, water, slime, lava. + e.g. If a Goal is above some water, and does a radius effect + with "t_length", and a player in the water is within the + radius, he won't be affected if this bit is set. + + - The Spy and Engineer were added to the list of classes the TF Detect + entity can ban. The list is now as follows: + Bit 1 (1) : No Scout + Bit 2 (2) : No Sniper + Bit 3 (4) : No Soldier + Bit 4 (8) : No Demolitions Man + Bit 5 (16) : No Combat Medic + Bit 6 (32) : No Heavy Weapons Guy + Bit 7 (64) : No Pyro + Bit 8 (128) : No Random PlayerClass + Bit 9 (256) : No Spy + Bit 10(512) : No Engineer + + - Since quake has a limit on the size of the entity data in a map, + abbreviations for some of the common entity fields were created. + The Abbreviations are as follows: + Classnames + "i_p_t" for "info_player_teamspawn" + "i_t_g" for "info_tfgoal" + "i_t_t" for "info_tfgoal_timer" + + Common Variables + "g_a" for "goal_activation" + "g_e" for "goal_effects" + + String Variables + "t_s_h" for "team_str_home" + "t_s_m" for "team_str_moved" + "t_s_c" for "team_str_carried" + "n_s_h" for "non_team_str_home" + "n_s_m" for "non_team_str_moved" + "n_s_c" for "non_team_str_carried" + + "b_b" for "broadcast" + "b_t" for "team_broadcast" + "b_n" for "non_team_broadcast" + "b_o" for "owners_team_broadcast" + "n_b" for "netname_broadcast" + "n_t" for "netname_team_broadcast" + "n_n" for "netname_non_team_broadcast" + "n_o" for "netname_owners_team_broadcast" + + "d_t" for "team_drop" + "d_n" for "non_team_drop" + "d_n_t" for "netname_team_drop" + "d_n_n" for "netname_non_team_drop" + + - Goals now affect players who are dead, allowing dead players + to get teamscores when their team captures flags, etc. + + - Goals can use the "delay_time" variable now to delay their activation + for a specific amount of time. + + - Team Spawnpoints can now use Criteria the same way Goals do. + Players can only spawn at spawnpoints that they match the Criteria of. + + - Team Spawnpoints can activate a goal when someone spawns on them, + using the "activate_goal_no" variable. + + - Way back in version 1.3 the "goal_effects" variable was introduced, + to allow goals to affect more than one player. In version 1.21 you + didn't have to specify a "goal_effects" variable... instead, any + goal simply affected it's AP. To allow for backwards compatability, + in all versions since 1.3, any Goal that did not specify a "goal_effects" + field automatically had it's "goal_effects" set to 1, which is affect + AP only. This has become a problem now, since it prevents map-makers + from having goals that have a "goal_effects" of 0. + From this version onwards, the "goal_effects" variable will be left + as it is in the .map file. So, if you have a map which contains any + Goals/Items that do _not_ have a "goal_effects" variable specified, + add it in and set it to 1. + + - Items given by Goals are not set to Active state anymore, so they + can be given out multiple times. + + - An extra bit was added to the "goal_effects" variable for Timer Goals. + The bit will be ignored by any goal/item other than Timers, and is as + follows: + 64 : If this bit is set, then instead of just applying this + Goal's results to the group of players specified by the + other "goal_effects" variable, this Goal checks it's + criteria for each player in the group and then applies it's + results invididually to any of them that pass. + + - An extra bit was added to the "goal_activation" variable of + func_button's and func_door's. + 8 : If this bit is set, then activate this button/door only + when it's hit by an engineer's spanner. + +------------------------- +Changes from 2.5 to 2.6 + + - The Map Debug was cleaned up a lot, most especially in the + Criteria Checking section. + + - A new bit (32) was added to "goal_result" for Goals/etc which forces + anyone affected by the goal to simply respawn. The player doesn't + die... just respawns. + Used in conjunction with TeamSpawns that have criteria and the + enable/disable TeamSpawns capabilities, this can be used to + move an entire team to specific points around the map. + + - An new bit (2048) was added to "goal_activation" for Goals and GoalItems. + 2048: If this bit is set, the Goal/Item drops to the ground when it + first spawns. + + - Another new bit (4096) was added to "goal_activation" for GoalItems. + 4096: If this bit is set, any player carrying this item can drop + it using the "dropitems" command. + + - Yet another bit (8192) was added to "goal_activation" for GoalItems. + 8192: If this bit is set, the GoalItem is Solid while not + being carried by a player. This means it blocks bullets, + grenades. + N.B. It will also block any players that don't pass it's + criteria. Players that do pass the criteria will + simply pick it up. + + - The size of a Goal or GoalItem can now be set using the "goal_min" + and "goal_max" variables to set the min and max bounding box. + If not set, they default to: + "goal_min" "-16 -16 -24" + "goal_max" "16 16 32" + + - More Abbreviations, as follows: + Floats + "h_i_g" for "has_item_from_group" + "r_i_g" for "remove_item_group" + + "a_s" for "ammo_shells" + "a_n" for "ammo_nails" + "a_r" for "ammo_rockets" + "a_c" for "ammo_cells" + + "rv_s_h" for "remove_spawngroup" + "rs_s_h" for "restore_spawngroup" + "rv_gr" for "remove_group_no" + "rs_gr" for "restore_group_no" + "rv_g" for "remove_goal_no" + "rs_g" for "restore_goal_no" + + - The "ex_skill_min" and "ex_skill_max" variables can now + use "-1" to mean 0. This is needed because specifying either + as 0 is the same as not specifying it at all. + E.g. An entity with: + "ex_skill_min" "-1" + "ex_skill_max" "-1" + Would only exist at skill 0. + An entity with: + "ex_skill_min" "-1" + "ex_skill_max" "2" + Would only exist at skill 0, 1, or 2. + + +---------------------------------------------------------------------------- +If you think of any more things goals could do when activated, +please don't hesitate to mail them to me. + +And as a last word, I _really_ suggest that you use the Entity Editor. +I use it myself. It's far too much of a pain mucking about getting all +the right variables set to the right things to bother with doing +it all manually. +Originally, it looked like it would be feasible to do it yourself, +but they've just become far too complex now. + +Have fun! + +Robin. (robin@teamfortress.com) +=---------------------------------------------------------------------------= +TEAMFORTRESS v2.8 20/5/98 +TeamFortress Software Pty. Ltd. +Company WWW: http://www.teamfortress.com/ +TF Web Site: http://www.planetquake.com/teamfortress + diff --git a/versions.txt b/docs/versions.txt similarity index 100% rename from versions.txt rename to docs/versions.txt diff --git a/tfortmap.qc b/tfortmap.qc index fc0790d7..7a31263c 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -204,6 +204,11 @@ void (entity Goal) UpdateAbbreviations = }; void () TF_PlaceItem = { + dprint("\n\n=========TF_PlaceItem=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("=========TF_PlaceItem=========\n\n\n"); + local float oldz; self.flags = FL_ITEM; @@ -234,9 +239,11 @@ void () TF_PlaceItem = { }; void () TF_StartItem = { - dprint("=========TF_StartItem=========\n"); + dprint("\n\n=========TF_StartItem=========\n"); + dprint("=========self=========\n"); eprint(self); - dprint("=========TF_StartItem=========\n"); + dprint("=========TF_StartItem=========\n\n\n"); + if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { self.effects = self.effects | EF_DIMLIGHT; @@ -262,9 +269,10 @@ void () TF_StartItem = { }; void () TF_PlaceGoal = { - dprint("=========TF_PlaceGoal=========\n"); + dprint("\n\n=========TF_PlaceGoal=========\n"); + dprint("=========self=========\n"); eprint(self); - dprint("=========TF_PlaceGoal=========\n"); + dprint("=========TF_PlaceGoal=========\n\n\n"); local float oldz; @@ -297,9 +305,10 @@ void () TF_PlaceGoal = { }; void () TF_StartGoal = { - dprint("=========TF_StartGoal=========\n"); + dprint("\n\n=========TF_StartGoal=========\n"); + dprint("=========self=========\n"); eprint(self); - dprint("=========TF_StartGoal=========\n"); + dprint("=========TF_StartGoal=========\n\n\n"); UpdateAbbreviations(self); self.nextthink = time + 0.2; @@ -328,6 +337,11 @@ float () CheckExistence = { }; void () info_tfdetect = { + dprint("\n\n=========info_tfdetect=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("\n\n=========info_tfdetect=========\n"); + UpdateAbbreviations(self); }; @@ -626,6 +640,13 @@ void (entity Goal) InactivateGoal = { }; void (entity Goal) RestoreGoal = { + dprint("\n\n=========RestoreGoal=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("=========Goal=========\n"); + eprint(Goal); + dprint("=========RestoreGoal=========\n\n\n"); + if (Goal.goal_state == 3) { if (Goal.search_time == 0) { if ((Goal.goal_activation & 8192) && @@ -641,6 +662,23 @@ void (entity Goal) RestoreGoal = { if (Goal.mdl != string_null) { setmodel(Goal, Goal.mdl); } + if (Goal.model == "progs/tf_flag.mdl" || Goal.model == "progs/tf_stan.mdl") { + Goal.effects = self.effects | EF_DIMLIGHT; + + if (Goal.skin == 1.0) { + Goal.effects = Goal.effects | EF_BLUE; + } + if (Goal.skin == 2.0) { + Goal.effects = Goal.effects | EF_RED; + } + if (Goal.skin == 3.0) { + Goal.effects = Goal.effects | EF_RED; + Goal.effects = Goal.effects | EF_MUZZLEFLASH; + } + if (Goal.skin == 4.0) { + Goal.effects = Goal.effects | EF_MUZZLEFLASH; + } + } } }; @@ -1235,6 +1273,12 @@ float (entity Goal, entity AP) APMeetsCriteria = { }; void (entity Goal) SetupRespawn = { + dprint("\n\n=========SetupRespawn=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("=========Goal=========\n"); + eprint(Goal); + dprint("=========SetupRespawn=========\n\n\n"); if (Goal.search_time != 0) { InactivateGoal(Goal); Goal.think = tfgoal_timer_tick; @@ -1256,6 +1300,10 @@ void (entity Goal) SetupRespawn = { }; void () DoRespawn = { + dprint("\n\n=========DoRespawn=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("=========DoRespawn=========\n\n\n"); RestoreGoal(self); InactivateGoal(self); }; @@ -2046,6 +2094,15 @@ void () item_tfgoal_touch = { }; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { + dprint("\n\n=========tfgoalitem_GiveToPlayer=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("=========AP=========\n"); + eprint(AP); + dprint("=========Goal=========\n"); + eprint(Goal); + dprint("\n\n=========tfgoalitem_GiveToPlayer=========\n"); + Item.effects = 0; Item.owner = AP; @@ -2060,8 +2117,8 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { if (Item.goal_activation & TFGI_SLOW) TeamFortress_SetSpeed(AP); - if (Item.goal_activation & TFGI_ITEMGLOWS) - Item.effects = EF_DIMLIGHT; + /* if (Item.goal_activation & TFGI_ITEMGLOWS) */ + /* Item.effects = EF_DIMLIGHT; */ if (Item.items & IT_KEY1) AP.items = AP.items | IT_KEY1; @@ -2090,6 +2147,11 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { }; void () ReturnItem = { + dprint("\n\n=========ReturnItem=========\n"); + dprint("=========self=========\n"); + eprint(self); + dprint("\n\n=========ReturnItem=========\n"); + local entity te; self.enemy.goal_state = 2; @@ -2221,6 +2283,8 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { }; void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { + dprint("\n\n=========tfgoalitem_RemoveEffectsFromPlayer=========\n"); + dprint("\n\n=========tfgoalitem_RemoveEffectsFromPlayer=========\n"); local entity te; local float lighton = 0; local float slowon = 0; From 41440fcd7d469e7ba1cc06d2ef3acde16e8b160a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 14 Oct 2018 01:55:44 +1100 Subject: [PATCH 0447/2474] Make cuss time configurable --- README.md | 3 ++- scout.qc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ca814bba..bca2f8a8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ Classic Fortress v0.9 beta New features ------ -* Option for to fully restock player on cap. `localinfo stock_on_cap on`. +* Option to adjust conussion effect time. `localinfo cusstime`. Default is 750. +* Option to fully restock player on cap. `localinfo stock_on_cap on`. * Option for packs to fully restock health and armour of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. * Map vote (4 random maps + current map) during last few minutes of game (shown for newly spawned or toggled with /togglevote). diff --git a/scout.qc b/scout.qc index 28821fe2..27dfe327 100644 --- a/scout.qc +++ b/scout.qc @@ -600,7 +600,7 @@ void (entity inflictor, entity attacker, float bounce, te.team_no = attacker.team_no; te.classname = "timer"; te.owner = head; - te.health = 750; + te.health = CF_GetSetting("ct", "cusstime", "750"); self.owner.is_concussed = 1; } } From aa133f918d418186d63854d3b46d2e7205679197 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 15 Oct 2018 00:09:56 +1100 Subject: [PATCH 0448/2474] Make the cuss time defined in seconds --- client.qc | 3 +++ qw.qc | 1 + scout.qc | 2 +- tfort.qc | 5 ++++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index fcb93fd7..c40f844c 100644 --- a/client.qc +++ b/client.qc @@ -472,6 +472,9 @@ void () DecodeLevelParms = { // display class tips [on] classtips = CF_GetSetting("ct", "classtips", "on"); + // concussion grenade effect time [19] + cussgrentime = CF_GetSetting("cgt", "cussgrentime", "19"); + // display sniper rifle power in status bar [on] sniperpower = CF_GetSetting("sp", "sniperpower", "on"); diff --git a/qw.qc b/qw.qc index 42db4111..f70effb3 100644 --- a/qw.qc +++ b/qw.qc @@ -471,6 +471,7 @@ float spawnfull; float stockfull; float stock_on_cap; float classtips; +float cussgrentime; float sniperpower; float sniperreloadpercent; float buildstatus; diff --git a/scout.qc b/scout.qc index 27dfe327..b29d55ad 100644 --- a/scout.qc +++ b/scout.qc @@ -600,7 +600,7 @@ void (entity inflictor, entity attacker, float bounce, te.team_no = attacker.team_no; te.classname = "timer"; te.owner = head; - te.health = CF_GetSetting("ct", "cusstime", "750"); + te.health = 40 * cussgrentime; self.owner.is_concussed = 1; } } diff --git a/tfort.qc b/tfort.qc index eb9fae06..7c0d745a 100644 --- a/tfort.qc +++ b/tfort.qc @@ -590,9 +590,12 @@ void () TeamFortress_ShowTF = { } CF_PrintSetting("Grenade timers", grentimers, "", 1); + sprint(self, PRINT_HIGH, "Concussion effect lasts "); + sprint(self, PRINT_HIGH, cussgrentime); + sprint(self, PRINT_HIGH, " seconds"); + sprint(self, PRINT_HIGH, "\n== Scout ==\n"); CF_PrintSetting("Scout dash ability", scoutdash, "", 1); - sprint(self, PRINT_HIGH, "\n== Sniper ==\n"); CF_PrintSetting("Sniper reload", sniperreload, "", 1); CF_PrintSetting("Old sniper rifle range", old_sniperrange, "", 1); From 5cacd40a1dd4297a2d8bfc3c3040c2f03b5bf555 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 15 Oct 2018 00:12:03 +1100 Subject: [PATCH 0449/2474] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bca2f8a8..c4e1f051 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Classic Fortress v0.9 beta New features ------ -* Option to adjust conussion effect time. `localinfo cusstime`. Default is 750. +* Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime`. * Option to fully restock player on cap. `localinfo stock_on_cap on`. * Option for packs to fully restock health and armour of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. From 03ac2686cf200a6fb1c92a443d9f2d228207005c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 16 Oct 2018 23:49:52 +1100 Subject: [PATCH 0450/2474] Fix issue with localinfo cussgrentime not applying to cuss effect while already cussed --- scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scout.qc b/scout.qc index b29d55ad..56c99943 100644 --- a/scout.qc +++ b/scout.qc @@ -578,7 +578,7 @@ void (entity inflictor, entity attacker, float bounce, te.health = 100; te.nextthink = time + 5; } else { - te.health = 750; + te.health = 40 * cussgrentime; te.nextthink = time + 0.25; } } else { From 1d4e82e403d729f1c99ce694ec9b4a180b491060 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 17 Oct 2018 01:14:44 +1100 Subject: [PATCH 0451/2474] Make sure flags glow after being capped --- tfortmap.qc | 104 +++++++++++++++++----------------------------------- 1 file changed, 33 insertions(+), 71 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 7a31263c..235035f2 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -41,8 +41,7 @@ void () ReturnItem; void (entity P) ForceRespawn; -void (entity Goal) UpdateAbbreviations = -{ +void (entity Goal) UpdateAbbreviations = { local string st; if (Goal.has_abbreviated == 0) { @@ -204,11 +203,6 @@ void (entity Goal) UpdateAbbreviations = }; void () TF_PlaceItem = { - dprint("\n\n=========TF_PlaceItem=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========TF_PlaceItem=========\n\n\n"); - local float oldz; self.flags = FL_ITEM; @@ -239,11 +233,6 @@ void () TF_PlaceItem = { }; void () TF_StartItem = { - dprint("\n\n=========TF_StartItem=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========TF_StartItem=========\n\n\n"); - if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { self.effects = self.effects | EF_DIMLIGHT; @@ -269,11 +258,6 @@ void () TF_StartItem = { }; void () TF_PlaceGoal = { - dprint("\n\n=========TF_PlaceGoal=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========TF_PlaceGoal=========\n\n\n"); - local float oldz; if (self.classname != "info_tfgoal_timer") { @@ -305,11 +289,6 @@ void () TF_PlaceGoal = { }; void () TF_StartGoal = { - dprint("\n\n=========TF_StartGoal=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========TF_StartGoal=========\n\n\n"); - UpdateAbbreviations(self); self.nextthink = time + 0.2; self.think = TF_PlaceGoal; @@ -337,11 +316,6 @@ float () CheckExistence = { }; void () info_tfdetect = { - dprint("\n\n=========info_tfdetect=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("\n\n=========info_tfdetect=========\n"); - UpdateAbbreviations(self); }; @@ -640,13 +614,6 @@ void (entity Goal) InactivateGoal = { }; void (entity Goal) RestoreGoal = { - dprint("\n\n=========RestoreGoal=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========Goal=========\n"); - eprint(Goal); - dprint("=========RestoreGoal=========\n\n\n"); - if (Goal.goal_state == 3) { if (Goal.search_time == 0) { if ((Goal.goal_activation & 8192) && @@ -1273,12 +1240,6 @@ float (entity Goal, entity AP) APMeetsCriteria = { }; void (entity Goal) SetupRespawn = { - dprint("\n\n=========SetupRespawn=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========Goal=========\n"); - eprint(Goal); - dprint("=========SetupRespawn=========\n\n\n"); if (Goal.search_time != 0) { InactivateGoal(Goal); Goal.think = tfgoal_timer_tick; @@ -1300,10 +1261,6 @@ void (entity Goal) SetupRespawn = { }; void () DoRespawn = { - dprint("\n\n=========DoRespawn=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========DoRespawn=========\n\n\n"); RestoreGoal(self); InactivateGoal(self); }; @@ -2094,15 +2051,6 @@ void () item_tfgoal_touch = { }; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { - dprint("\n\n=========tfgoalitem_GiveToPlayer=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========AP=========\n"); - eprint(AP); - dprint("=========Goal=========\n"); - eprint(Goal); - dprint("\n\n=========tfgoalitem_GiveToPlayer=========\n"); - Item.effects = 0; Item.owner = AP; @@ -2147,11 +2095,6 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { }; void () ReturnItem = { - dprint("\n\n=========ReturnItem=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("\n\n=========ReturnItem=========\n"); - local entity te; self.enemy.goal_state = 2; @@ -2165,6 +2108,22 @@ void () ReturnItem = { self.enemy.touch = item_tfgoal_touch; self.enemy.origin = self.enemy.oldorigin; + if (self.enemy.model == "progs/tf_flag.mdl" || self.enemy.model == "progs/tf_stan.mdl") { + if (self.enemy.skin == 1.0) { + self.enemy.effects = self.enemy.effects | EF_BLUE; + } + if (self.enemy.skin == 2.0) { + self.enemy.effects = self.enemy.effects | EF_RED; + } + if (self.enemy.skin == 3.0) { + self.enemy.effects = self.enemy.effects | EF_RED; + self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; + } + if (self.enemy.skin == 4.0) { + self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; + } + } + if (self.enemy.mdl != string_null) setmodel(self.enemy, self.enemy.mdl); @@ -2174,6 +2133,22 @@ void () ReturnItem = { if (self.enemy.origin == self.enemy.oldorigin) return; + if (self.enemy.model == "progs/tf_flag.mdl" || self.enemy.model == "progs/tf_stan.mdl") { + if (self.enemy.skin == 1.0) { + self.enemy.effects = self.enemy.effects | EF_BLUE; + } + if (self.enemy.skin == 2.0) { + self.enemy.effects = self.enemy.effects | EF_RED; + } + if (self.enemy.skin == 3.0) { + self.enemy.effects = self.enemy.effects | EF_RED; + self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; + } + if (self.enemy.skin == 4.0) { + self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; + } + } + sound(self.enemy, 2, "items/itembk2.wav", 1, 1); if (self.weapon != 2) { @@ -2283,8 +2258,6 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { }; void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { - dprint("\n\n=========tfgoalitem_RemoveEffectsFromPlayer=========\n"); - dprint("\n\n=========tfgoalitem_RemoveEffectsFromPlayer=========\n"); local entity te; local float lighton = 0; local float slowon = 0; @@ -2392,12 +2365,6 @@ void () tfgoalitem_droptouch = { }; void (entity Item, float PAlive, entity P) tfgoalitem_drop = { - dprint("=========tfgoalitem_drop=========\n"); - eprint(Item); - dprint("==================\n"); - eprint(P); - dprint("=========tfgoalitem_drop=========\n"); - if (Item.model == "progs/tf_flag.mdl" || Item.model == "progs/tf_stan.mdl") { Item.effects = self.effects | EF_DIMLIGHT; @@ -2787,11 +2754,6 @@ void (entity P) ForceRespawn = { }; void () DropGoalItems = { - dprint("=========TF_DropGoalItems=========\n"); - dprint("=========self=========\n"); - eprint(self); - dprint("=========TF_DropGoalItems=========\n"); - local entity te, search; newmis = spawn(); From d5b1c42c20289d1f67d9fb05514a62c5e1562ac7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 17 Oct 2018 19:40:26 +1100 Subject: [PATCH 0452/2474] Make mbases keys glow their own color --- tfortmap.qc | 63 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 235035f2..fce54f04 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -250,6 +250,17 @@ void () TF_StartItem = { self.effects = self.effects | EF_MUZZLEFLASH; } } + + if (self.model == "progs/basrkey.bsp" ) { + self.effects = self.effects | EF_DIMLIGHT; + self.effects = self.effects | EF_RED; + } + + if (self.model == "progs/basbkey.bsp" ) { + self.effects = self.effects | EF_DIMLIGHT; + self.effects = self.effects | EF_BLUE; + } + UpdateAbbreviations(self); self.nextthink = time + 0.2; self.think = TF_PlaceItem; @@ -630,7 +641,7 @@ void (entity Goal) RestoreGoal = { setmodel(Goal, Goal.mdl); } if (Goal.model == "progs/tf_flag.mdl" || Goal.model == "progs/tf_stan.mdl") { - Goal.effects = self.effects | EF_DIMLIGHT; + Goal.effects = Goal.effects | EF_DIMLIGHT; if (Goal.skin == 1.0) { Goal.effects = Goal.effects | EF_BLUE; @@ -646,6 +657,16 @@ void (entity Goal) RestoreGoal = { Goal.effects = Goal.effects | EF_MUZZLEFLASH; } } + + if (Goal.model == "progs/basrkey.bsp" ) { + Goal.effects = Goal.effects | EF_DIMLIGHT; + Goal.effects = Goal.effects | EF_RED; + } + + if (Goal.model == "progs/basbkey.bsp" ) { + Goal.effects = Goal.effects | EF_DIMLIGHT; + Goal.effects = Goal.effects | EF_BLUE; + } } }; @@ -2109,6 +2130,8 @@ void () ReturnItem = { self.enemy.origin = self.enemy.oldorigin; if (self.enemy.model == "progs/tf_flag.mdl" || self.enemy.model == "progs/tf_stan.mdl") { + self.enemy.effects = self.effects | EF_DIMLIGHT; + if (self.enemy.skin == 1.0) { self.enemy.effects = self.enemy.effects | EF_BLUE; } @@ -2124,6 +2147,16 @@ void () ReturnItem = { } } + if (self.enemy.model == "progs/basrkey.bsp" ) { + self.enemy.effects = self.effects | EF_DIMLIGHT; + self.enemy.effects = self.enemy.effects | EF_RED; + } + + if (self.enemy.model == "progs/basbkey.bsp" ) { + self.enemy.effects = self.effects | EF_DIMLIGHT; + self.enemy.effects = self.enemy.effects | EF_BLUE; + } + if (self.enemy.mdl != string_null) setmodel(self.enemy, self.enemy.mdl); @@ -2133,22 +2166,6 @@ void () ReturnItem = { if (self.enemy.origin == self.enemy.oldorigin) return; - if (self.enemy.model == "progs/tf_flag.mdl" || self.enemy.model == "progs/tf_stan.mdl") { - if (self.enemy.skin == 1.0) { - self.enemy.effects = self.enemy.effects | EF_BLUE; - } - if (self.enemy.skin == 2.0) { - self.enemy.effects = self.enemy.effects | EF_RED; - } - if (self.enemy.skin == 3.0) { - self.enemy.effects = self.enemy.effects | EF_RED; - self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; - } - if (self.enemy.skin == 4.0) { - self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; - } - } - sound(self.enemy, 2, "items/itembk2.wav", 1, 1); if (self.weapon != 2) { @@ -2366,7 +2383,7 @@ void () tfgoalitem_droptouch = { void (entity Item, float PAlive, entity P) tfgoalitem_drop = { if (Item.model == "progs/tf_flag.mdl" || Item.model == "progs/tf_stan.mdl") { - Item.effects = self.effects | EF_DIMLIGHT; + Item.effects = Item.effects | EF_DIMLIGHT; if (Item.skin == 1.0) { Item.effects = Item.effects | EF_BLUE; @@ -2383,6 +2400,16 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { } } + if (Item.model == "progs/basrkey.bsp" ) { + Item.effects = Item.effects | EF_DIMLIGHT; + Item.effects = Item.effects | EF_RED; + } + + if (Item.model == "progs/basbkey.bsp" ) { + Item.effects = Item.effects | EF_DIMLIGHT; + Item.effects = Item.effects | EF_BLUE; + } + Item.origin = Item.owner.origin; setorigin(Item, Item.origin); Item.camangle = Item.owner.origin - '0 0 8'; From 5ba20542d0f0e59490d0f78e38e11f67c2aaf4ef Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 23 Oct 2018 00:32:51 +1100 Subject: [PATCH 0453/2474] Use clockwise/anticlockwise for sentry directions --- menu.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/menu.qc b/menu.qc index 06fad610..1cf23415 100644 --- a/menu.qc +++ b/menu.qc @@ -811,7 +811,7 @@ void () Menu_EngineerFix_Dispenser = { void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { if (inp == 1) { - sprint(self, PRINT_HIGH, "Rotating 45 degrees to the left...\n"); + sprint(self, PRINT_HIGH, "Rotating 45 degrees anticlockwise...\n"); self.building.waitmin = anglemod(self.building.waitmin + 45); self.building.waitmax = anglemod(self.building.waitmax + 45); } else if (inp == 2) { @@ -819,7 +819,7 @@ void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { self.building.waitmin = anglemod(self.building.waitmin + 180); self.building.waitmax = anglemod(self.building.waitmax + 180); } else if (inp == 3) { - sprint(self, PRINT_HIGH, "Rotating 45 degrees to the right...\n"); + sprint(self, PRINT_HIGH, "Rotating 45 degrees clockwise...\n"); self.building.waitmin = anglemod(self.building.waitmin - 45); self.building.waitmax = anglemod(self.building.waitmax - 45); } @@ -827,9 +827,9 @@ void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { void () Menu_EngineerFix_SentryGun_Rotate = { local string action = "Rotate sentry gun:\n\n"; - local string rotl = "“‘ 45 degrees left \n"; + local string rotl = "“‘ anticlockwise \n"; local string rot180 = "”‘ 180 degrees \n"; - local string rotr = "•‘ 45 degrees right\n"; + local string rotr = "•‘ clockwise\n"; local string nothing = "\n—‘ Nothing \n"; if (!self.building.real_owner.has_sentry || self.building.real_owner != self From 37f5cd2ff9dfbef7036a2dc55428dfe09accf98d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 23 Oct 2018 00:41:51 +1100 Subject: [PATCH 0454/2474] Increase autoid polling rate by 10x --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 7c0d745a..921f1ac5 100644 --- a/tfort.qc +++ b/tfort.qc @@ -36,7 +36,7 @@ void () AutoId = { CF_Identify(self.owner, self.owner.autoid_type); } - self.nextthink = time + 0.3; + self.nextthink = time + 0.03; }; void () UseSpecialSkill = { From 0c1e335e2be58d8fefa6f0f7a4f9e12622af2ae1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 24 Oct 2018 19:25:51 +1100 Subject: [PATCH 0455/2474] Fix sentry menu spacing --- menu.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/menu.qc b/menu.qc index 1cf23415..3268613b 100644 --- a/menu.qc +++ b/menu.qc @@ -827,10 +827,10 @@ void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { void () Menu_EngineerFix_SentryGun_Rotate = { local string action = "Rotate sentry gun:\n\n"; - local string rotl = "“‘ anticlockwise \n"; - local string rot180 = "”‘ 180 degrees \n"; - local string rotr = "•‘ clockwise\n"; - local string nothing = "\n—‘ Nothing \n"; + local string rotl = "“‘ anticlockwise\n"; + local string rot180 = "”‘ 180 degrees \n"; + local string rotr = "•‘ clockwise \n"; + local string nothing = "\n—‘ Nothing \n"; if (!self.building.real_owner.has_sentry || self.building.real_owner != self || self.classname != "player" || self.building == world) From 14251714ca3f042bfc44fe6d4d453243f7e176d6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 25 Oct 2018 03:29:55 +1100 Subject: [PATCH 0456/2474] Set client side fortressone variable to 1 in fortressone servers to allow client to disable non-fortressone aliases --- client.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/client.qc b/client.qc index c40f844c..f7acd4f0 100644 --- a/client.qc +++ b/client.qc @@ -1988,6 +1988,7 @@ void () ClientConnect = { local string st2; local float got_one; + stuffcmd(self, "set fortressone 1\n"); bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; From 9a8c4a8f0c6a3f6c4ba9260060c0dbd191298348 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 26 Oct 2018 18:05:46 +1100 Subject: [PATCH 0457/2474] fortressone variable not needed --- client.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/client.qc b/client.qc index f7acd4f0..c40f844c 100644 --- a/client.qc +++ b/client.qc @@ -1988,7 +1988,6 @@ void () ClientConnect = { local string st2; local float got_one; - stuffcmd(self, "set fortressone 1\n"); bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; From 1123e8cd19ff0967df1d9345abadd13284329993 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 26 Oct 2018 20:27:39 +1100 Subject: [PATCH 0458/2474] Add fortressone var back in --- client.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/client.qc b/client.qc index c40f844c..f7acd4f0 100644 --- a/client.qc +++ b/client.qc @@ -1988,6 +1988,7 @@ void () ClientConnect = { local string st2; local float got_one; + stuffcmd(self, "set fortressone 1\n"); bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; From ce0d8c7333fe175f4ac3c063c243d543575b00ad Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 27 Oct 2018 02:36:57 +1100 Subject: [PATCH 0459/2474] Advertise fortress_one aliases to client on connect --- world.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/world.qc b/world.qc index c7a8998f..b3ab5f57 100644 --- a/world.qc +++ b/world.qc @@ -117,6 +117,11 @@ void () main = { entity lastspawn; void () worldspawn = { + // Set this variable on connect so the client knows it has access to + // FortressOne aliases. + WriteByte(MSG_INIT, 9/*svc_stufftext*/); + WriteString(MSG_INIT, "set fo_serverscripts 1\n"); + local string st; lastspawn = world; From 17c32bc3e0875d151957f12aa5de28d143b919ea Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 28 Oct 2018 19:27:36 +1100 Subject: [PATCH 0460/2474] Rename to FortressOne Server --- README.md | 2 +- VERSION | 1 + gmqcc.bat | 9 --------- help.qc | 4 ++-- tfort.qc | 6 +++--- tforthlp.qc | 4 ++-- vote.qc | 4 ++-- 7 files changed, 11 insertions(+), 19 deletions(-) create mode 100644 VERSION delete mode 100644 gmqcc.bat diff --git a/README.md b/README.md index c4e1f051..6c1c3656 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Classic Fortress v0.9 beta +FortressOne Server v0.1.0 ========================== New features diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..6e8bf73a --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/gmqcc.bat b/gmqcc.bat deleted file mode 100644 index 8f6504bd..00000000 --- a/gmqcc.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -for /f "delims=" %%i in ('git rev-parse --short HEAD') do set output=%%i -@echo on -gmqcc -std=fteqcc -fvariadic-args -funtyped-nil -DVER=\"%output%\" -DREV=\"%output%\" -@cp qwprogs.dat "C:\Users\Niclas\Dropbox\Projects\Classic Fortress\Game\server\fortress\qwprogs.dat" -@taskkill /f /im mvdsv.exe 2>nul -@taskkill /f /im ezquake-dev.exe 2>nul -@cd "C:\Users\Niclas\Dropbox\Projects\Classic Fortress\Game\server" -@call "cmd /c start mvdsv.exe" diff --git a/help.qc b/help.qc index 720f0173..32df9e65 100644 --- a/help.qc +++ b/help.qc @@ -1,5 +1,5 @@ -// CLASS HELP FOR CLASSIC FORTRESS -// =============================== +// CLASS HELP FOR FORTRESSONE +// ========================== // Shows class bindings for each class. // functions by order of appearance diff --git a/tfort.qc b/tfort.qc index 921f1ac5..0a5aee1a 100644 --- a/tfort.qc +++ b/tfort.qc @@ -514,7 +514,7 @@ void (string ps_description, float pf_setting, string ps_last, float pf_bool) CF void () TeamFortress_ShowTF = { local string st; - sprint(self, PRINT_HIGH, "\nThis server is running Classic Fortress "); + sprint(self, PRINT_HIGH, "\nThis server is running FortressOne "); sprint(self, PRINT_HIGH, VER); sprint(self, PRINT_HIGH, "\n\n"); @@ -571,7 +571,7 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "Full teamscore off\n"); } - sprint(self, PRINT_HIGH, "\n== Classic Fortress ==\n"); + sprint(self, PRINT_HIGH, "\n== FortressOne Server ==\n"); CF_PrintSetting("Spawn with full health/armor", spawnfull, "", 1); CF_PrintSetting("Stock players with full health/armor", stockfull, "", 1); CF_PrintSetting("Stock player on cap", stock_on_cap, "", 1); @@ -658,7 +658,7 @@ void () TeamFortress_ShowTF = { if (server_faithful) { sprint(self, PRINT_HIGH, "\nThis server is running faithful Team Fortress settings.\n"); } else if (server_default) { - sprint(self, PRINT_HIGH, "\nThis server is running default Classic Fortress settings.\n"); + sprint(self, PRINT_HIGH, "\nThis server is running default FortressOne Server settings.\n"); } }; diff --git a/tforthlp.qc b/tforthlp.qc index 829ddff8..9e509c5c 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -17,7 +17,7 @@ void () TeamFortress_MOTD = { local string ya; if (self.motd == 5) { - sprint(self, PRINT_HIGH, "\nClassic Fortress ", VER, "\n\n"); + sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); st1 = infokey(world, "motd1"); if (st1 != string_null) { @@ -26,7 +26,7 @@ void () TeamFortress_MOTD = { st1 = strcat(strcat(st1, "\n"), st2); } } else { - st1 = "Welcome to Classic Fortress\nby Empezar & hifi\n==================================\ngithub.com/classic-fortress"; + st1 = "Welcome to FortressOne\n==================================\nwww.github.com/FortressOne"; } sprint(self, PRINT_HIGH, st1); diff --git a/vote.qc b/vote.qc index da4edb43..53570b80 100644 --- a/vote.qc +++ b/vote.qc @@ -1,5 +1,5 @@ -// MAP VOTING FOR CLASSIC FORTRESS -// =============================== +// MAP VOTING FOR FORTRESSONE +// ========================== // Displays a vote menu during the last few minutes of gameplay on a map. // functions by order of appearance From 111170d3956373f4918dad3bd0ad3a3b6d3ed060 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 1 Nov 2018 20:25:36 +1100 Subject: [PATCH 0461/2474] Restore support for dropitems --- tforthlp.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tforthlp.qc b/tforthlp.qc index 9e509c5c..adcdcf8e 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -103,6 +103,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dropkey", TF_DROPKEY, 0); TeamFortress_Alias("dropammo", TF_DROP_AMMO, 0); TeamFortress_Alias("dropflag", TF_DROPFLAG, 0); + TeamFortress_Alias("dropitems", TF_DROPFLAG, 0); TeamFortress_Alias("showloc", TF_DISPLAYLOCATION, 0); TeamFortress_Alias("special", TF_SPECIAL_SKILL, 0); TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); From 7a8de22d1cacea61b7cee1e43f3c7b84c148354c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 1 Nov 2018 20:30:07 +1100 Subject: [PATCH 0462/2474] Restore TF2.8 paths on loading class cfgs --- README.md | 2 -- tfort.qc | 19 +++++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6c1c3656..ac1cbdc0 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ New features * Free class switch during first 10 seconds after spawning. * Updated class help (bindings, aliases and settings) reachable with /classhelp. * Dropping flag now possible on all maps using /dropflag. -* Class configs are now executed from /fortress/classes/ subdirectory. * Allow team changing. * Any non-valid impulse now closes the active menu. @@ -49,7 +48,6 @@ New features * Fixed endless intermission bug. * Fixed bug where players got stuck in intermission mode upon map change and hence could not respawn. * Major code cleanup and rewrites. -* When using class configs, /fortress/classes/default.cfg gets executed first. * Team player count in team selection menu. * Class player count (and class restrictions) in class selection menu. * Changing teams is now allowed. diff --git a/tfort.qc b/tfort.qc index 0a5aee1a..c5818095 100644 --- a/tfort.qc +++ b/tfort.qc @@ -3146,25 +3146,24 @@ void (entity p) TeamFortress_ExecClassScript = { st = infokey(p, "exec_class"); if (st == "1") { - stuffcmd(p, "exec classes/default.cfg\n"); if (p.playerclass == PC_SCOUT) - stuffcmd(p, "exec classes/scout.cfg\n"); + stuffcmd(p, "exec scout.cfg\n"); else if (p.playerclass == PC_SNIPER) - stuffcmd(p, "exec classes/sniper.cfg\n"); + stuffcmd(p, "exec sniper.cfg\n"); else if (p.playerclass == PC_SOLDIER) - stuffcmd(p, "exec classes/soldier.cfg\n"); + stuffcmd(p, "exec soldier.cfg\n"); else if (p.playerclass == PC_DEMOMAN) - stuffcmd(p, "exec classes/demoman.cfg\n"); + stuffcmd(p, "exec demoman.cfg\n"); else if (p.playerclass == PC_MEDIC) - stuffcmd(p, "exec classes/medic.cfg\n"); + stuffcmd(p, "exec medic.cfg\n"); else if (p.playerclass == PC_HVYWEAP) - stuffcmd(p, "exec classes/hwguy.cfg\n"); + stuffcmd(p, "exec hwguy.cfg\n"); else if (p.playerclass == PC_PYRO) - stuffcmd(p, "exec classes/pyro.cfg\n"); + stuffcmd(p, "exec pyro.cfg\n"); else if (p.playerclass == PC_SPY) - stuffcmd(p, "exec classes/spy.cfg\n"); + stuffcmd(p, "exec spy.cfg\n"); else if (p.playerclass == PC_ENGINEER) - stuffcmd(p, "exec classes/engineer.cfg\n"); + stuffcmd(p, "exec engineer.cfg\n"); } }; From 367a42f674ab347e61af4d8dda6a3213650a8a25 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 14 Nov 2018 23:03:30 +1100 Subject: [PATCH 0463/2474] because we convert q3 info_player_start to info_player_teamspawn, choose a random teamspawn if we can't find info player start --- client.qc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/client.qc b/client.qc index f7acd4f0..9be86a74 100644 --- a/client.qc +++ b/client.qc @@ -1127,6 +1127,10 @@ entity () SelectSpawnPoint = } } spot = find(world, classname, "info_player_start"); + if (!spot) { + spot = find(world, classname, "info_player_teamspawn"); + } + if (!spot) { error("PutClientInServer: no info_player_start on level\n"); } @@ -1345,12 +1349,12 @@ void () PutClientInServer = { } }; -void () info_player_start = { - if (CheckExistence() == FALSE) { - dremove(self); - return; - } -}; +//void () info_player_start = { +// if (CheckExistence() == FALSE) { +// dremove(self); +// return; +// } +//}; void () info_player_start2 = { if (CheckExistence() == FALSE) { From b5571299f5b86a3ec377d0240df38c77b86723e0 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 14 Nov 2018 23:03:48 +1100 Subject: [PATCH 0464/2474] add allowteams field to entities to support q3 --- defs.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/defs.qc b/defs.qc index 3a6e203b..7094ab2e 100644 --- a/defs.qc +++ b/defs.qc @@ -456,3 +456,9 @@ void () SUB_Remove; void (entity targ, entity inflictor, entity attacker, float damage) T_Damage; float (entity e, float healamount, float ignore) T_Heal; // health function float (entity targ, entity inflictor) CanDamage; + + +// +// q3 defs +// +.string allowteams; \ No newline at end of file From 3854cb380ae99fe2abebcc1db702fed8b8cdebce Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 14 Nov 2018 23:04:02 +1100 Subject: [PATCH 0465/2474] support q3 doors --- doors.qc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doors.qc b/doors.qc index cbac2280..ca92a240 100644 --- a/doors.qc +++ b/doors.qc @@ -375,6 +375,13 @@ void () func_door = { self.noise1 = "doors/ddoor2.wav"; self.noise2 = "doors/ddoor1.wav"; } + // q3 fields + if (self.allowteams == "blue") { + self.team_no = 1; + } + if (self.allowteams == "red") { + self.team_no = 2; + } SetMovedir(); self.max_health = self.health; self.solid = SOLID_BSP; From 6b041a70bed976de345ded2e6896b107f3d713da Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 14 Nov 2018 23:04:16 +1100 Subject: [PATCH 0466/2474] support q3f spawns --- tfortmap.qc | 71 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index fce54f04..17b354db 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -361,6 +361,19 @@ void () info_player_teamspawn = { } }; +void () info_player_start = { + if (self.allowteams == "blue") { + self.classname = "info_player_teamspawn"; + self.team_no = 1; + info_player_teamspawn(); + } + if (self.allowteams == "red") { + self.classname = "info_player_teamspawn"; + self.team_no = 2; + info_player_teamspawn(); + } +}; + void () i_p_t = { self.classname = "info_player_teamspawn"; info_player_teamspawn(); @@ -1697,15 +1710,15 @@ void (entity Goal, entity AP, float addb) DoResults = { } } else { CenterPrint2(te, "\n\n\n", - "Your team ΗΟΤ the ΕΞΕΝΩ flag!!"); + "Your team οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½οΏ½ flag!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your flag has been ΤΑΛΕΞ!!"); + "Your flag has been οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } te = find(te, classname, "player"); } - bprint(PRINT_HIGH, AP.netname, " ΗΟΤ the ΒΜΥΕ flag!\n"); + bprint(PRINT_HIGH, AP.netname, " οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); AP.items = AP.items | IT_KEY1; } else { if (Goal.goal_no == 2) { @@ -1751,15 +1764,15 @@ void (entity Goal, entity AP, float addb) DoResults = { } } else { CenterPrint2(te, "\n\n\n", - "Your team ΗΟΤ the ΕΞΕΝΩ flag!!"); + "Your team οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½οΏ½ flag!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your flag has been ΤΑΛΕΞ!!"); + "Your flag has been οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } te = find(te, classname, "player"); } - bprint(PRINT_HIGH, AP.netname, " ΗΟΤ the ΕΔ flag!\n"); + bprint(PRINT_HIGH, AP.netname, " οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); AP.items = AP.items | IT_KEY2; } else { if (Goal.goal_no == 3) { @@ -1768,19 +1781,19 @@ void (entity Goal, entity AP, float addb) DoResults = { if (te.team_no == 2) { if (te == AP) { CenterPrint2(te, "\n\n\n", - "You ΓΑΠΤΥΕΔ the flag!!"); + "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); } else { CenterPrint2(te, "\n\n\n", - "Your flag was ΓΑΠΤΥΕΔ!!"); + "Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your team ΓΑΠΤΥΕΔ the flag!!"); + "Your team οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); } te = find(te, classname, "player"); } bprint(PRINT_HIGH, AP.netname, - " ΓΑΠΤΥΕΔ the ΕΔ flag!\n"); + " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); AP.items = AP.items - (AP.items & IT_KEY2); } else { if (Goal.goal_no == 4) { @@ -1789,19 +1802,19 @@ void (entity Goal, entity AP, float addb) DoResults = { if (te.team_no == 1) { if (te == AP) { CenterPrint2(te, "\n\n\n", - "You ΓΑΠΤΥΕΔ the flag!!"); + "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); } else { CenterPrint2(te, "\n\n\n", - "Your flag was ΓΑΠΤΥΕΔ!!"); + "Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your team ΓΑΠΤΥΕΔ the flag!!"); + "Your team οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); } te = find(te, classname, "player"); } bprint(PRINT_HIGH, AP.netname, - " ΓΑΠΤΥΕΔ the ΒΜΥΕ flag!\n"); + " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); AP.items = AP.items - (AP.items & IT_KEY1); } } @@ -1996,15 +2009,15 @@ void () item_tfgoal_touch = { if (self.origin != self.oldorigin) { if (other.team_no == 1) { bprint(2, other.netname); - bprint(2, " ΕΤΥΞΕΔ the ΒΜΥΕ flag!\n"); + bprint(2, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); te = find(world, classname, "player"); while (te != world) { if (te.team_no == 1) { CenterPrint2(te, "\n\n\n", - "Your flag was ΕΤΥΞΕΔ!!"); + "Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } else { CenterPrint2(te, "\n\n\n", - "The ΕΞΕΝΩ flag was ΕΤΥΞΕΔ!!"); + "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } te = find(te, classname, "player"); } @@ -2027,15 +2040,15 @@ void () item_tfgoal_touch = { if (self.origin != self.oldorigin) { if (other.team_no == 2) { bprint(2, other.netname); - bprint(2, " ΕΤΥΞΕΔ the ΕΔ flag!\n"); + bprint(2, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); te = find(world, classname, "player"); while (te != world) { if (te.team_no == 2) { CenterPrint(te, - "\n\n\n Your flag was ΕΤΥΞΕΔ!!"); + "\n\n\n Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } else { CenterPrint(te, - "\n\n\n The ΕΞΕΝΩ flag was ΕΤΥΞΕΔ!!"); + "\n\n\n The οΏ½οΏ½οΏ½οΏ½οΏ½ flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); } te = find(te, classname, "player"); } @@ -2545,7 +2558,7 @@ void () item_flag_team2 = { precache_sound("boss2/pop2.wav"); self.classname = "item_tfgoal"; self.netname = "Blue Flag"; - self.broadcast = " ΗΟΤ the enemy team's flag!\n"; + self.broadcast = " οΏ½οΏ½οΏ½ the enemy team's flag!\n"; self.deathtype = "You've got the enemy flag!\n"; self.noise = "ogre/ogwake.wav"; @@ -2582,8 +2595,8 @@ void () item_flag_team2 = { dp.items_allowed = 2; dp.goal_no = 3; dp.goal_effects = 3; - dp.broadcast = " ΓΑΠΤΥΕΔ the enemy flag!\n"; - dp.message = "You ΓΑΠΤΥΕΔ the enemy flag!\n"; + dp.broadcast = " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; + dp.message = "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; dp.noise = "boss2/pop2.wav"; dp.goal_result = 2; dp.activate_goal_no = 5; @@ -2622,7 +2635,7 @@ void () item_flag_team1 = { precache_sound("boss2/pop2.wav"); self.classname = "item_tfgoal"; self.netname = "Red Flag"; - self.broadcast = " ΗΟΤ the enemy team's flag!\n"; + self.broadcast = " οΏ½οΏ½οΏ½ the enemy team's flag!\n"; self.deathtype = "You've got the enemy flag!\n"; self.noise = "ogre/ogwake.wav"; @@ -2657,8 +2670,8 @@ void () item_flag_team1 = { dp.items_allowed = 1; dp.goal_no = 4; dp.goal_effects = 3; - dp.broadcast = " ΓΑΠΤΥΕΔ the enemy flag!\n"; - dp.message = "You ΓΑΠΤΥΕΔ the enemy flag!\n"; + dp.broadcast = " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; + dp.message = "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; dp.noise = "boss2/pop2.wav"; dp.goal_result = 2; dp.activate_goal_no = 6; @@ -2800,11 +2813,11 @@ void () DropGoalItems = { tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); if (self.team_no == 1) - bprint(PRINT_HIGH, self.netname, " δςοππεδ ςεδ§σ ζμαη\n"); + bprint(PRINT_HIGH, self.netname, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½\n"); else if (self.team_no == 2) - bprint(PRINT_HIGH, self.netname, " δςοππεδ βμυε§σ ζμαη\n"); + bprint(PRINT_HIGH, self.netname, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½\n"); else - bprint(PRINT_HIGH, self.netname, " δςοππεδ τθε εξενω§σ ζμαη\n"); + bprint(PRINT_HIGH, self.netname, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½\n"); Status_Print(self, "\n\n\n", "You dropped the flag!"); search = find(world, classname, "player"); From 9ff3954a49594c7c4522fee42cb3fdf30a2dad32 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 15 Nov 2018 00:16:27 +1100 Subject: [PATCH 0467/2474] q3 give interpreting WIP --- tfortmap.qc | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tfortmap.qc b/tfortmap.qc index 17b354db..e908a4e5 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -420,6 +420,53 @@ void () info_tfgoal = { TF_StartGoal(); }; +// q3 support +void () func_goalinfo = { + self.classname = "info_tfgoal"; + if (self.allowteams == "blue") { + self.team_no = 1; + } + if (self.allowteams == "red") { + self.team_no = 2; + } + self.mdl = self.model; + self.noise = self.active_all_sound; + self.armortype = "0.8"; + + float comindex, startpos; + comindex = 0; + string searchterm; + searchterm = self.give; + startpos = 0; + // while index is not -1 + while (comindex >= 0) { + // find index of comma + comindex = strstrofs(searchterm, ",", startpos); + // get substring up to the comma + string val; + val = substring(searchterm, startpos, comindex); + // set pos for next loop + startpos = comindex + 1; + + // process val "health=+100" + float eqindex, opindex, len, amt; + eqindex = strstrofs(val, "=", 0); + string givetype, posneg, samt; + givetype = substring(val, 0, eqindex); + opindex = eqindex + 1; + posneg = substring(val, eqindex, opindex); + len = comindex - 1; + samt = substring(val, opindex, len); + amt = stof(samt); + + + } + + + + info_tfgoal(); +} + void () i_t_g = { self.classname = "info_tfgoal"; info_tfgoal(); From b08f4d83f9dd7fc173cd62ed328a2787a1e5976f Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 15 Nov 2018 00:17:14 +1100 Subject: [PATCH 0468/2474] ent references --- q3f_openfire2b working copy.map | 333 ++ stag3.map | 6407 +++++++++++++++++++++++++++++++ 2 files changed, 6740 insertions(+) create mode 100644 q3f_openfire2b working copy.map create mode 100644 stag3.map diff --git a/q3f_openfire2b working copy.map b/q3f_openfire2b working copy.map new file mode 100644 index 00000000..d63c1ae6 --- /dev/null +++ b/q3f_openfire2b working copy.map @@ -0,0 +1,333 @@ +// Game: Quake +// Format: Standard +// entity 0 +{ +"angle" "90" +"classname" "worldspawn" +"team_blue_name" "Blue Team" +"team_red_name" "Red Team" +"author" "Jeremy Raymond" +"message" "Openfire by War|ocK" +"atmosphere" "T=RAIN,B=5 10,C=0.5,G=0.5 2,BV=0,GV=0 100,W=1 2,D=300" + +} + +// entity 3 +{ +"classname" "target_position" +"targetname" "t3" +"origin" "1072 1152 -88" +} + +// entity 65 +{ +"angle" "180" +"classname" "func_goalinfo" +"allowteams" "red" +"flags" "hideactive" +"origin" "-1801 855 223" +"active_all_sound" "sound/misc/am_pkup.wav" +"give" "health=+100,armor=+300,ammo_shells=+100,ammo_bullets=+100,ammo_rockets=+100,ammo_cells=+200,gren1=+2,gren2=+0,ammo_medikit=+100" +"model" "models/objects/backpack/backpack.md3" +"wait" "2" +} + +// entity 93 +{ +"inactivetarget" "redflaghud=~inactive" +"activetarget" "redflaghud=~active" +"carriedtarget" "redflaghud=~carried" +"sparkle" "1.000000 0.392157 0.392157" +"angle" "90" +"classname" "func_goalitem" +"carried_sound" "sound/teamplay/flagtk_red.wav" +"carried_all_sound" "sound/teamplay/flagtk_red.wav" +"carried_message" "~You got the ^1red^* flag! Run for it!" +"carried_all_message" "%N nabbed the ^1red^* flag!" +"groupname" "redflag" +"origin" "-2562 -1154 158" +"allowteams" "blue" +"model" "models/flags/r_flag.md3" +"inactive_all_message" "The ^1red^* flag returned to base!" +"active_all_message" "The ^1red^* flag was dropped in the field!" +"flags" "showcarry,revealagent" +"active_flaginfo" "The ^1Red^* flag has been dropped in the field!" +"inactive_flaginfo" "The ^1Red^* flag is at base." +"carried_flaginfo" "%N is carrying the ^1Red^* flag!" +"wait" "45" +"_color" "1.000000 0.392157 0.392157" +"light" "50" +} +// entity 94 +{ +"classname" "func_goalinfo" +"holding" "blueflag" +"give" "health=+100,armor=+300,ammo_shells=+100,ammo_bullets=+100,ammo_rockets=+100,ammo_cells=+100,gren1=+2,gren2=+2,ammo_medikit=+100,ammo_detpack=+1" +"teamscore" "10" +"origin" "-2513 239 159" +"active_team_sound" "sound/teamplay/flagcap_red.wav" +"active_all_message" "~%N CAPTURED the ^4blue ^*flag!" +"active_sound" "sound/teamplay/flagcap_red.wav" +"activetarget" "blueflag=~inactive,scorer" +"angle" "270" +"active_all_sound" "sound/teamplay/flagcap_red.wav" +} +// entity 95 +{ +"origin" "-352 512 128" +"angle" "315" +"classname" "info_player_intermission" +} +// entity 96 +{ +"origin" "-424 520 136" +"slot" "1" +"inactive_model" "models/flags/r_flag.md3" +"holding" "redflag" +"classname" "func_hud" +} +{ +"scale" ".5" +"targetname" "redflaghud" +"carried_shader" "textures/q3f_hud/red_lost" +"active_shader" "textures/q3f_hud/red_down" +"inactive_shader" "textures/q3f_hud/red_safe" +"slot" "3" +"origin" "-400 520 136" +"classname" "func_hud" +} +// entity 100 +{ +"angle" "270" +"classname" "func_goalitem" +"carried_sound" "sound/teamplay/flagtk_red.wav" +"carried_all_sound" "sound/teamplay/flagtk_red.wav" +"carried_message" "~You got the ^4blue^* flag! Run for it!" +"carried_all_message" "%N nabbed the ^4blue^* flag!" +"groupname" "blueflag" +"origin" "2558 1150 158" +"allowteams" "red" +"model" "models/flags/b_flag.md3" +"inactive_all_message" "The ^4blue^* flag returned to base!" +"active_all_message" "The ^4blue^* flag was dropped in the field!" +"flags" "showcarry,revealagent" +"active_flaginfo" "The ^4Blue^* flag has been dropped in the field!" +"inactive_flaginfo" "The ^4Blue^* flag is at base." +"carried_flaginfo" "%N is carrying the ^4Blue^* flag!" +"wait" "45" +"_color" "0.392157 0.392157 1.000000" +"light" "50" +"sparkle" "0.392157 0.392157 1.000000" +"carriedtarget" "blueflaghud=~carried" +"activetarget" "blueflaghud=~active" +"inactivetarget" "blueflaghud=~inactive" +} +// entity 101 +{ +"activetarget" "redflag=~inactive,scorer" +"active_sound" "sound/teamplay/flagcap_red.wav" +"active_all_message" "~%N CAPTURED the ^1red ^*flag!" +"active_team_sound" "sound/teamplay/flagcap_red.wav" +"origin" "2511 -241 159" +"teamscore" "10" +"give" "health=+100,armor=+300,ammo_shells=+100,ammo_bullets=+100,ammo_rockets=+100,ammo_cells=+100,gren1=+2,gren2=+2,ammo_medikit=+100,ammo_detpack=+1" +"holding" "redflag" +"classname" "func_goalinfo" +"angle" "90" +"active_all_sound" "sound/teamplay/flagcap_red.wav" +} +// entity 102 +{ +"classname" "target_kill" +"targetname" "kill" +"origin" "2433 1150 239" +"checkstate" "t1=inactive" +} +// entity 103 +{ +"allowteams" "red" +"classname" "trigger_multiple" +"target" "kill" +// brush 0 +{ +( 2483 -65535 65535 ) ( 2483 65535 65535 ) ( 2483 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 2477 65535 65535 ) ( 2477 -65535 65535 ) ( 2477 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 -65535 128 ) ( 65535 65535 128 ) ( -65535 -65535 128 ) e2u3/floor1_2 0 0 0 1 1 +} +} +// entity 104 +{ +"targetname" "t1" +"lip" "0" +"wait" "30" +"classname" "func_door" +"angle" "270" +"speed" "9999" +} +// entity 105 +{ +"allowteams" "red" +"activetarget" "t1" +"wait" "30" +"angle" "270" +"classname" "func_button" +// brush 0 +{ +( 2351 -65535 65535 ) ( 2351 65535 65535 ) ( 2351 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 -496 65535 ) ( -65535 -496 65535 ) ( -65535 -496 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( -65535 -504 65535 ) ( 65535 -504 65535 ) ( -65535 -504 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 -65535 144 ) ( 65535 65535 144 ) ( -65535 -65535 144 ) e2u3/floor1_2 0 0 0 1 1 +} +} +// entity 106 +{ +"targetname" "t1" +"lip" "0" +"wait" "30" +"angle" "90" +"classname" "func_door" +"speed" "9999" +} +// entity 107 +{ +"targetname" "t1" +"lip" "0" +"wait" "30" +"speed" "9999" +"angle" "270" +"classname" "func_door" +} +// entity 108 +{ +"speed" "9999" +"classname" "func_door" +"angle" "90" +"wait" "30" +"lip" "0" +"targetname" "t1" +} +// entity 109 +{ +"classname" "func_door" +"angle" "270" +"speed" "9999" +"wait" "30" +"lip" "0" +"targetname" "t1" +} +// entity 110 +{ +"targetname" "t1" +"lip" "0" +"wait" "30" +"angle" "90" +"classname" "func_door" +"speed" "9999" +} +// entity 111 +{ +"checkstate" "t2=inactive" +"origin" "-2433 -1150 239" +"targetname" "kill2" +"classname" "target_kill" +} +// entity 112 +{ +"target" "kill2" +"classname" "trigger_multiple" +"allowteams" "blue" +// brush 0 +{ +( -2477 -65535 65535 ) ( -2477 65535 65535 ) ( -2477 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( -2483 65535 65535 ) ( -2483 -65535 65535 ) ( -2483 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 -65535 128 ) ( 65535 65535 128 ) ( -65535 -65535 128 ) e2u3/floor1_2 0 0 0 1 1 +} +} +// entity 113 +{ +"speed" "9999" +"angle" "270" +"classname" "func_door" +"wait" "30" +"lip" "0" +"targetname" "t2" +} +// entity 114 +{ +"classname" "func_button" +"angle" "90" +"wait" "30" +"activetarget" "t2" +"allowteams" "blue" +// brush 0 +{ +( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( -2351 65535 65535 ) ( -2351 -65535 65535 ) ( -2351 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 504 65535 ) ( -65535 504 65535 ) ( -65535 504 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( -65535 496 65535 ) ( 65535 496 65535 ) ( -65535 496 -65535 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) e2u3/floor1_2 0 0 0 1 1 +( 65535 -65535 144 ) ( 65535 65535 144 ) ( -65535 -65535 144 ) e2u3/floor1_2 0 0 0 1 1 +} +} +// entity 115 +{ +"speed" "9999" +"classname" "func_door" +"angle" "90" +"wait" "30" +"lip" "0" +"targetname" "t2" +} +// entity 116 +{ +"classname" "func_door" +"angle" "270" +"speed" "9999" +"wait" "30" +"lip" "0" +"targetname" "t2" +} +// entity 117 +{ +"targetname" "t2" +"lip" "0" +"wait" "30" +"angle" "90" +"classname" "func_door" +"speed" "9999" +} +// entity 118 +{ +"targetname" "t2" +"lip" "0" +"wait" "30" +"speed" "9999" +"angle" "270" +"classname" "func_door" +} +// entity 119 +{ +"speed" "9999" +"classname" "func_door" +"angle" "90" +"wait" "30" +"lip" "0" +"targetname" "t2" +} + +// entity 207 +{ +"origin" "0 -320 -192" +"noise" "sound/world/curnt2.wav" +"classname" "target_speaker" +"spawnflags" "1" +} + diff --git a/stag3.map b/stag3.map new file mode 100644 index 00000000..abcb7c23 --- /dev/null +++ b/stag3.map @@ -0,0 +1,6407 @@ +// Game: Quake +// Format: Standard +// entity 0 +{ +"message" "stag3\nby lordy with help and stuff from dp!\nbased on the q3f level q3f_2stag2" +"classname" "worldspawn" +"wad" "/home/danni/Games/QuakeDev/wads/stag.wad;../wads/oppose2.wad" +"_sunlight" "0" +// brush 0 +{ +( -2608 -65535 65535 ) ( -2608 65535 65535 ) ( -2608 65535 -65535 ) city4_5 -16 0 90 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 -16 0 180 1 1 +} +// brush 1 +{ +( -224 -65535 65535 ) ( -224 65535 65535 ) ( -224 65535 -65535 ) wiz1_4 -16 -2 90 1 1 +( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) wiz1_4 -16 -2 90 1 1 +( 65247 1680 65535 ) ( -65823 1680 65535 ) ( -65823 1680 -65535 ) wiz1_4 -48 -2 180 1 1 +( -65823 1648 65535 ) ( 65247 1648 65535 ) ( -65823 1648 -65535 ) wiz1_4 -48 -2 180 1 1 +( 65247 65535 -2864 ) ( 65247 -65535 -2864 ) ( -65823 -65535 -2864 ) wiz1_4 -47 -2 180 1 1 +( 65247 -65535 -4000 ) ( 65247 65535 -4000 ) ( -65823 -65535 -4000 ) wiz1_4 -48 -2 180 1 1 +} +// brush 2 +{ +( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) rock5_2 -80 0 90 1 1 +( -2832 65535 65535 ) ( -2832 -65535 65535 ) ( -2832 65535 -65535 ) rock5_2 -80 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 +( 65535 65535 -3472 ) ( 65535 -65535 -3472 ) ( -65535 -65535 -3472 ) rock5_2 -80 0 180 1 1 +( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -80 0 180 1 1 +} +// brush 3 +{ +( -304 -63567 65535 ) ( -304 67503 65535 ) ( -304 67503 -65535 ) metal1_4 -0 -48 180 1 1 +( -880 67503 65535 ) ( -880 -63567 65535 ) ( -880 67503 -65535 ) metal1_4 -0 -48 180 1 1 +( 64655 1664 65535 ) ( -66415 1664 65535 ) ( -66415 1664 -65535 ) metal1_4 -0 -48 -0 1 1 +( -66415 464 65535 ) ( 64655 464 65535 ) ( -66415 464 -65535 ) metal1_4 -0 -48 -0 1 1 +( 64655 67503 -3408 ) ( 64655 -63567 -3408 ) ( -66415 -63567 -3408 ) city4_8 32 -16 -0 1 1 +( 64655 -63567 -3952 ) ( 64655 67503 -3952 ) ( -66415 -63567 -3952 ) metal1_4 -0 -0 -0 1 1 +} +// brush 4 +{ +( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) sfloor4_1 -16 0 180 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) sfloor4_1 -16 -0 180 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -16 -0 -0 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -16 0 0 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -16 -48 0 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -16 0 0 1 1 +} +// brush 5 +{ +( -2944 -65535 65535 ) ( -2944 65535 65535 ) ( -2944 65535 -65535 ) sfloor4_1 -16 0 90 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) sfloor4_1 -16 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) sfloor4_1 -16 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -16 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) sfloor4_1 -16 0 180 1 1 +} +// brush 6 +{ +( -2608 -65535 65535 ) ( -2608 65535 65535 ) ( -2608 65535 -65535 ) city4_5 -16 0 90 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -16 0 180 1 1 +} +// brush 7 +{ +( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) rock5_2 -80 0 90 1 1 +( -2832 65535 65535 ) ( -2832 -65535 65535 ) ( -2832 65535 -65535 ) rock5_2 -80 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) rock5_2 -80 0 180 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) rock5_2 -80 0 180 1 1 +} +// brush 8 +{ +( -2832 -65535 65535 ) ( -2832 65535 65535 ) ( -2832 65535 -65535 ) rock5_2 -80 0 90 1 1 +( -2944 65535 65535 ) ( -2944 -65535 65535 ) ( -2944 65535 -65535 ) rock5_2 -80 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) rock5_2 -80 0 180 1 1 +( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -80 0 180 1 1 +} +// brush 9 +{ +( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) city4_5 -16 0 90 1 1 +( -2608 65535 65535 ) ( -2608 -65535 65535 ) ( -2608 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -16 0 180 1 1 +} +// brush 10 +{ +( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) mmetal1_8 -15 0 0 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) mmetal1_8 -15 0 0 1 1 +( 65535 1312 65535 ) ( -65535 1312 65535 ) ( -65535 1312 -65535 ) mmetal1_8 -15 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) mmetal1_8 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) mmetal1_8 -15 0 180 1 1 +} +// brush 11 +{ +( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal4_4 -16 0 90 1 1 +( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal4_4 -16 0 90 1 1 +( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal4_4 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 -16 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) metal4_4 -16 0 180 1 1 +} +// brush 12 +{ +( -368 -65535 65535 ) ( -368 65535 65535 ) ( -368 65535 -65535 ) city4_8 -16 0 180 1 1 +( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) city4_8 -16 0 180 1 1 +( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) city4_8 -16 0 0 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_8 -16 0 0 1 1 +} +// brush 13 +{ +( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) wizmet1_8 -16 0 90 1 1 +( -2544 65535 65535 ) ( -2544 -65535 65535 ) ( -2544 65535 -65535 ) wizmet1_8 -16 0 90 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 -16 0 180 1 1 +( -65535 1072 65535 ) ( 65535 1072 65535 ) ( -65535 1072 -65535 ) wizmet1_8 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 +} +// brush 14 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -15 0 0 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -15 0 180 1 1 +( -65535 1504 65535 ) ( 65535 1504 65535 ) ( -65535 1504 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 15 +{ +( -3504 -65535 65535 ) ( -3504 65535 65535 ) ( -3504 65535 -65535 ) city4_5 0 0 180 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 0 0 270 1 1 +} +// brush 16 +{ +( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) rock5_2 0 0 180 1 1 +( -3040 65535 65535 ) ( -3040 -65535 65535 ) ( -3040 65535 -65535 ) rock5_2 -79 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -79 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) rock5_2 -79 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) rock5_2 -79 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 -79 0 180 1 1 +} +// brush 17 +{ +( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) rock5_2 0 0 180 1 1 +( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) rock5_2 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 0 0 90 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) rock5_2 0 0 90 1 1 +( 65535 65535 -3472 ) ( 65535 -65535 -3472 ) ( -65535 -65535 -3472 ) rock5_2 0 0 270 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 0 0 270 1 1 +} +// brush 18 +{ +( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) city6_8 0 0 180 1 1 +( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) city6_8 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 0 0 90 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) city6_8 0 0 90 1 1 +( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 0 0 270 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city6_8 0 0 270 1 1 +} +// brush 19 +{ +( -1840 -65535 65535 ) ( -1840 65535 65535 ) ( -1840 65535 -65535 ) metal1_4 0 0 180 1 1 +( -1856 65535 65535 ) ( -1856 -65535 65535 ) ( -1856 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 0 0 270 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 0 0 270 1 1 +} +// brush 20 +{ +( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -16 0 90 1 1 +( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 +} +// brush 21 +{ +( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 +( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -16 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3952.3362112220348 ) ( 65535 65535 -3952.3362112220348 ) ( -65535 -65535 -3952.3362112220348 ) metal1_4 -16 -0 180 1 1 +} +// brush 22 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 -0 90 1 1 +( -1600 65535 65535 ) ( -1600 -65535 65535 ) ( -1600 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -16 0 180 1 1 +} +// brush 23 +{ +( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) sfloor4_1 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +// brush 24 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( -2544 65535 65535 ) ( -2544 -65535 65535 ) ( -2544 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 1520 65535 ) ( 65535 1520 65535 ) ( -65535 1520 -65535 ) wizmet1_8 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 +} +// brush 25 +{ +( -737 -65535 65535 ) ( -737 65535 65535 ) ( -737 65535 -65535 ) wizmet1_8 0 0 180 1 1 +( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) wizmet1_8 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) wizmet1_8 0 0 90 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) wizmet1_8 0 0 90 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 +} +// brush 26 +{ +( 46404 -65535 46276 ) ( 46404 65535 46276 ) ( -46276 65535 -46404 ) *water2 -15 0 180 1 1 +( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) *water2 -15 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) *water2 -15 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *water2 -15 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 +} +// brush 27 +{ +( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) metal4_4 0 0 180 1 1 +( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) metal4_4 -16 0 90 1 1 +( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) metal4_4 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 -16 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal4_4 -16 0 180 1 1 +} +// brush 28 +{ +( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 46404 65535 46276 ) ( 46404 -65535 46276 ) ( -46276 65535 -46404 ) sfloor4_1 -15 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -15 0 180 1 1 +} +// brush 29 +{ +( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) city4_5 0 0 180 1 1 +( -3376 65535 65535 ) ( -3376 -65535 65535 ) ( -3376 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 0 0 270 1 1 +} +// brush 30 +{ +( 56805 65534 -32930 ) ( 56805 -65534 -32930 ) ( -60427 -65534 25685 ) metal1_4 -15 0 180 1 1 +( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3296 ) ( 65535 -65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 +} +// brush 31 +{ +( 56814 65534 -32911 ) ( 56814 -65534 -32911 ) ( -60417 -65534 25704 ) city6_8 -15 16 180 1 1 +( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) city6_8 0 15 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 0 15 90 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) city6_8 -16 15 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 0 15 270 1 1 +} +// brush 32 +{ +( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -16 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 -15 0 180 1 1 +} +// brush 33 +{ +( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 -16 0 0 1 1 +( -1600 65535 65535 ) ( -1600 -65535 65535 ) ( -1600 65535 -65535 ) city4_5 -16 0 0 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 90 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 90 1 1 +} +// brush 34 +{ +( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal5_8 -15 0 0 1 1 +( 65535 1168 65535 ) ( -65535 1168 65535 ) ( -65535 1168 -65535 ) metal5_8 -16 0 180 1 1 +( 65535 65535 -3120 ) ( 65535 -65535 -3120 ) ( -65535 -65535 -3120 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 0 180 1 1 +} +// brush 35 +{ +( -3344 -65535 65535 ) ( -3344 65535 65535 ) ( -3344 65535 -65535 ) metal5_8 0 0 180 1 1 +( 44196 48484 65535 ) ( -48484 -44196 65535 ) ( 44196 48484 -65535 ) metal5_8 16 0 180 1 1 +( -47636 45044 65535 ) ( 45044 -47636 65535 ) ( -47636 45044 -65535 ) metal5_8 16 0 180 1 1 +( 65535 65535 -3120 ) ( 65535 -65535 -3120 ) ( -65535 -65535 -3120 ) metal5_8 -47 32 180 1 1 +( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -47 32 180 1 1 +} +// brush 36 +{ +( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1168 65535 ) ( 65535 1168 65535 ) ( -65535 1168 -65535 ) city4_5 -16 0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 270 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 270 1 1 +} +// brush 37 +{ +( 45140 -47540 65535 ) ( -47540 45140 65535 ) ( -47540 45140 -65535 ) metal5_8 -16 0 180 1 1 +( 63533 65535 -16495 ) ( 63533 -65535 -16495 ) ( -64990 -65535 9209 ) metal5_8 -15 0 180 1 1 +( -48723 43862 65535 ) ( 46302 -46411 65535 ) ( -48723 43862 -65535 ) metal5_8 -16 0 180 1 1 +( 63530 -65535 -16510 ) ( 63530 65535 -16510 ) ( -64994 -65535 9194 ) metal5_8 -15 0 180 1 1 +( -3344 65535 65535 ) ( -3344 -65535 65535 ) ( -3344 65535 -65535 ) metal5_8 -15 0 0 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 +} +// brush 38 +{ +( -2928 -65535 65535 ) ( -2928 65535 65535 ) ( -2928 65535 -65535 ) metal1_3 0 0 180 1 1 +( -2936 65535 65535 ) ( -2936 -65535 65535 ) ( -2936 65535 -65535 ) metal1_3 0 0 180 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) metal1_3 -15 0 180 1 1 +} +// brush 39 +{ +( -2816 -65535 65535 ) ( -2816 65535 65535 ) ( -2816 65535 -65535 ) metal1_3 0 0 180 1 1 +( -2824 65535 65535 ) ( -2824 -65535 65535 ) ( -2824 65535 -65535 ) metal1_3 0 0 180 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) metal1_3 -15 0 180 1 1 +} +// brush 40 +{ +( -2816 -65535 65535 ) ( -2816 65535 65535 ) ( -2816 65535 -65535 ) metal5_8 -15 0 0 1 1 +( -48723 43862 65535 ) ( 46302 -46411 65535 ) ( -48723 43862 -65535 ) metal5_8 -16 0 180 1 1 +( 63530 -65535 -16510 ) ( 63530 65535 -16510 ) ( -64994 -65535 9194 ) metal5_8 -15 0 180 1 1 +( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -16 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 0 180 1 1 +} +// brush 41 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal5_8 -15 0 0 1 1 +( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -16 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 +} +// brush 42 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) sfloor4_1 -47 0 0 1 1 +( 54283 65535 36731 ) ( 54283 -65535 36731 ) ( -53093 -65535 -38432 ) sfloor4_1 -47 0 180 1 1 +( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) sfloor4_1 -47 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -47 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -47 0 180 1 1 +} +// brush 43 +{ +( -2448 -65535 65535 ) ( -2448 65535 65535 ) ( -2448 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +// brush 44 +{ +( -2544 -65535 65535 ) ( -2544 65535 65535 ) ( -2544 65535 -65535 ) metal2_6 0 0 180 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) metal2_6 -15 0 0 1 1 +( 65535 -57182 -32175 ) ( 65535 60049 26440 ) ( -65535 -57182 -32175 ) metal2_6 -15 0 180 1 1 +( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) metal2_6 -15 0 180 1 1 +( 65535 60043 26453 ) ( 65535 -57189 -32162 ) ( -65535 -57189 -32162 ) metal2_6 -15 0 180 1 1 +( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) metal2_6 -15 0 180 1 1 +} +// brush 45 +{ +( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 -0 -0 180 1 1 +( -2496 65535 65535 ) ( -2496 -65535 65535 ) ( -2496 65535 -65535 ) city4_5 -16 -0 90 1 1 +( 65535 1392 65535 ) ( -65535 1392 65535 ) ( -65535 1392 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -16 -0 180 1 1 +} +// brush 46 +{ +( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 0 0 180 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1520 65535 ) ( 65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 180 1 1 +} +// brush 47 +{ +( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 0 0 90 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 48 +{ +( 128 -64815 65535 ) ( 128 66255 65535 ) ( 128 66255 -65535 ) metal1_4 1 -15 -0 1 1 +( -304 66255 65535 ) ( -304 -64815 65535 ) ( -304 66255 -65535 ) metal1_4 1 -15 -0 1 1 +( 65679 1232 65535 ) ( -65391 1232 65535 ) ( -65391 1232 -65535 ) metal1_4 33 -15 180 1 1 +( -65391 880 65535 ) ( 65679 880 65535 ) ( -65391 880 -65535 ) metal1_4 33 -15 180 1 1 +( 65679 66255 -3408 ) ( 65679 -64815 -3408 ) ( -65391 -64815 -3408 ) city4_8 -32 -48 -0 1 1 +( 65679 -64815 -3440 ) ( 65679 66255 -3440 ) ( -65391 -64815 -3440 ) metal1_4 33 33 180 1 1 +} +// brush 49 +{ +( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 2416 65535 ) ( -65535 2416 65535 ) ( -65535 2416 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 1776 65535 ) ( 65535 1776 65535 ) ( -65535 1776 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 -0 180 1 1 +} +// brush 50 +{ +( -2944 -65535 65535 ) ( -2944 65535 65535 ) ( -2944 65535 -65535 ) rock5_2 -80 0 90 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) rock5_2 -80 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 +( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) rock5_2 -80 0 180 1 1 +( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -80 0 180 1 1 +} +// brush 51 +{ +( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 +( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 +( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) metal3_2 -15 0 180 1 1 +( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) city4_5 0 0 270 1 1 +} +// brush 52 +{ +( 60085 -65534 26370 ) ( 60085 65534 26370 ) ( -57147 -65534 -32245 ) city4_8 -16 0 0 1 1 +( -224 -65535 65535 ) ( -224 65535 65535 ) ( -224 65535 -65535 ) city4_8 -16 0 180 1 1 +( -368 65535 65535 ) ( -368 -65535 65535 ) ( -368 65535 -65535 ) city4_8 -16 0 180 1 1 +( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) city4_8 -16 0 0 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) city4_8 -16 0 0 1 1 +( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 +} +// brush 53 +{ +( -224 -65535 65535 ) ( -224 65535 65535 ) ( -224 65535 -65535 ) metal1_4 -15 0 90 1 1 +( 60085 65534 26370 ) ( 60085 -65534 26370 ) ( -57147 -65534 -32245 ) metal1_4 -15 0 180 1 1 +( -304 65535 65535 ) ( -304 -65535 65535 ) ( -304 65535 -65535 ) metal1_4 -15 0 90 1 1 +( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 +} +// brush 54 +{ +( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 60085 65534 26370 ) ( 60085 -65534 26370 ) ( -57147 -65534 -32245 ) metal1_4 -16 0 180 1 1 +( -368 65535 65535 ) ( -368 -65535 65535 ) ( -368 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -16 0 180 1 1 +} +// brush 55 +{ +( -1648 -65535 65535 ) ( -1648 65535 65535 ) ( -1648 65535 -65535 ) city4_5 -15 0 0 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 1504 65535 ) ( -65535 1504 65535 ) ( -65535 1504 -65535 ) city4_5 -15 0 180 1 1 +( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 56 +{ +( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) city4_5 -15 0 0 1 1 +( -1648 65535 65535 ) ( -1648 -65535 65535 ) ( -1648 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 1328 65535 ) ( -65535 1328 65535 ) ( -65535 1328 -65535 ) city4_5 -15 0 180 1 1 +( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 57 +{ +( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -1840 65535 65535 ) ( -1840 -65535 65535 ) ( -1840 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3360 ) ( 65535 65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -15 0 180 1 1 +} +// brush 58 +{ +( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal4_4 -16 0 90 1 1 +( -1744 65535 65535 ) ( -1744 -65535 65535 ) ( -1744 65535 -65535 ) metal4_4 -16 0 90 1 1 +( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal4_4 -16 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal4_4 -16 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal4_4 -16 0 180 1 1 +} +// brush 59 +{ +( -1744 -65535 65535 ) ( -1744 65535 65535 ) ( -1744 65535 -65535 ) metal1_4 -16 0 90 1 1 +( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 +} +// brush 60 +{ +( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) city4_5 -16 0 90 1 1 +( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -16 0 180 1 1 +} +// brush 61 +{ +( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) city4_5 -16 0 90 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3632 ) ( 65535 -65535 -3632 ) ( -65535 -65535 -3632 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -16 0 180 1 1 +} +// brush 62 +{ +( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -2544 65535 65535 ) ( -2544 -65535 65535 ) ( -2544 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 0 180 1 1 +} +// brush 63 +{ +( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) metal3_2 -15 0 0 1 1 +( -1648 65535 65535 ) ( -1648 -65535 65535 ) ( -1648 65535 -65535 ) metal3_2 -15 0 0 1 1 +( 65535 1504 65535 ) ( -65535 1504 65535 ) ( -65535 1504 -65535 ) metal3_2 -15 0 180 1 1 +( -65535 1328 65535 ) ( 65535 1328 65535 ) ( -65535 1328 -65535 ) metal3_2 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal3_2 -15 0 180 1 1 +} +// brush 64 +{ +( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) city4_5 0 0 180 1 1 +( -304 65535 65535 ) ( -304 -65535 65535 ) ( -304 65535 -65535 ) metal1_4 -15 0 90 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3936 ) ( 65535 -65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) metal1_4 -15 0 180 1 1 +} +// brush 65 +{ +( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 -32 0 90 1 1 +( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) metal1_4 -32 -0 90 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -32 0 180 1 1 +( 65535 65535 -3952 ) ( 65535 -65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -32 0 180 1 1 +( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) metal1_4 -32 0 180 1 1 +} +// brush 66 +{ +( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 56054 -65535 -34151 ) ( 56054 65535 -34151 ) ( -59539 -65535 27631 ) metal1_4 -16 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3936 ) ( 65535 -65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3952 ) ( 65535 65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -16 0 180 1 1 +} +// brush 67 +{ +( -3504 -65535 65535 ) ( -3504 65535 65535 ) ( -3504 65535 -65535 ) metal4_4 0 0 180 1 1 +( -3616 65535 65535 ) ( -3616 -65535 65535 ) ( -3616 65535 -65535 ) metal4_4 -0 -0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal4_4 0 0 90 1 1 +( -65535 80 65535 ) ( 65535 80 65535 ) ( -65535 80 -65535 ) metal4_4 -0 -0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 0 0 270 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) metal4_4 0 0 270 1 1 +} +// brush 68 +{ +( -3376 -65535 65535 ) ( -3376 65535 65535 ) ( -3376 65535 -65535 ) *water2 -15 0 0 1 1 +( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) *water2 -15 0 0 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) *water2 -15 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) *water2 -15 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 +} +// brush 69 +{ +( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) rock5_2 0 0 180 1 1 +( -3056 65535 65535 ) ( -3056 -65535 65535 ) ( -3056 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 0 0 90 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 0 0 270 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 0 0 270 1 1 +} +// brush 70 +{ +( -3040 -65535 65535 ) ( -3040 65535 65535 ) ( -3040 65535 -65535 ) metal1_4 0 0 180 1 1 +( -3056 65535 65535 ) ( -3056 -65535 65535 ) ( -3056 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 0 0 90 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 0 0 90 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 0 0 270 1 1 +} +// brush 71 +{ +( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 +} +// brush 72 +{ +( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) wiz1_4 -0 -0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 +( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) wizmet1_8 -15 -0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) wizmet1_8 -15 -0 180 1 1 +} +// brush 73 +{ +( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 +( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 0 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 +( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 0 0 180 1 1 +( -65535 80 65535 ) ( 65535 80 65535 ) ( -65535 80 -65535 ) metal1_4 0 0 180 1 1 +( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 0 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 0 0 180 1 1 +} +// brush 74 +{ +( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 +( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -16 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -16 0 180 1 1 +} +// brush 75 +{ +( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal4_4 0 0 90 1 1 +( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) metal4_4 0 0 90 1 1 +( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal4_4 0 0 270 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal4_4 0 0 270 1 1 +} +// brush 76 +{ +( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 +} +// brush 77 +{ +( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 -15 0 0 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -15 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 78 +{ +( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) city4_5 -15 0 0 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -2976 ) ( 65535 65535 -2976 ) ( -65535 -65535 -2976 ) city4_5 -15 0 180 1 1 +} +// brush 79 +{ +( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) city4_5 0 0 180 1 1 +( -224 65535 65535 ) ( -224 -65535 65535 ) ( -224 65535 -65535 ) metal1_4 -15 0 90 1 1 +( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 +} +// brush 80 +{ +( 45204 -47476 65535 ) ( -47476 45204 65535 ) ( -47476 45204 -65535 ) metal5_8 -15 0 180 1 1 +( -48484 -44196 65535 ) ( 44196 48484 65535 ) ( 44196 48484 -65535 ) metal5_8 -15 0 0 1 1 +( -3344 -65535 65535 ) ( -3344 65535 65535 ) ( -3344 65535 -65535 ) metal5_8 0 0 180 1 1 +( 44036 48644 65535 ) ( -48644 -44036 65535 ) ( 44036 48644 -65535 ) metal5_8 -15 0 0 1 1 +( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) metal5_8 -16 0 180 1 1 +( 65535 65535 -3120 ) ( 65535 -65535 -3120 ) ( -65535 -65535 -3120 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -47 32 180 1 1 +} +// brush 81 +{ +( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) sfloor4_1 -16 -48 180 1 1 +( -2448 65535 65535 ) ( -2448 -65535 65535 ) ( -2448 65535 -65535 ) sfloor4_1 -16 -48 180 1 1 +( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) sfloor4_1 -16 -48 0 1 1 +( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) sfloor4_1 -16 -48 0 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -16 -48 0 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -16 -48 0 1 1 +} +// brush 82 +{ +( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) wall9_8 0 0 180 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) wall9_8 -15 0 0 1 1 +( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) wall9_8 -15 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) wall9_8 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wall9_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wall9_8 -15 0 180 1 1 +} +// brush 83 +{ +( -2448 -65535 65535 ) ( -2448 65535 65535 ) ( -2448 65535 -65535 ) wall9_8 -15 0 0 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) wall9_8 -15 0 0 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wall9_8 -15 0 180 1 1 +( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wall9_8 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wall9_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wall9_8 -15 0 180 1 1 +} +// brush 84 +{ +( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) wall9_8 0 0 180 1 1 +( -2448 65535 65535 ) ( -2448 -65535 65535 ) ( -2448 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wizmet1_8 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wall9_8 -15 0 180 1 1 +} +// brush 85 +{ +( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) city4_5 -16 0 90 1 1 +( -2465 65535 65535 ) ( -2465 -65535 65535 ) ( -2465 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -16 0 180 1 1 +} +// brush 86 +{ +( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) sfloor4_1 -15 0 180 1 1 +} +// brush 87 +{ +( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) city4_5 -16 0 90 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 +} +// brush 88 +{ +( -2544 -65535 65535 ) ( -2544 65535 65535 ) ( -2544 65535 -65535 ) metal5_8 0 0 180 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) metal5_8 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal5_8 0 0 90 1 1 +( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) metal5_8 0 0 90 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 +} +// brush 89 +{ +( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 -16 0 90 1 1 +( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) wizmet1_8 -16 0 90 1 1 +( 65535 1392 65535 ) ( -65535 1392 65535 ) ( -65535 1392 -65535 ) wizmet1_8 -16 0 180 1 1 +( -65535 1072 65535 ) ( 65535 1072 65535 ) ( -65535 1072 -65535 ) wizmet1_8 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 +} +// brush 90 +{ +( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) wizmet1_8 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 +} +// brush 91 +{ +( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 -15 0 0 1 1 +( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -15 0 180 1 1 +( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 92 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) metal3_2 -15 0 0 1 1 +( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) metal3_2 -15 0 0 1 1 +( 65535 1504 65535 ) ( -65535 1504 65535 ) ( -65535 1504 -65535 ) metal3_2 -15 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) metal3_2 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal3_2 -15 0 180 1 1 +} +// brush 93 +{ +( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 +( -737 65535 65535 ) ( -737 -65535 65535 ) ( -737 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 688 65535 ) ( -65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 94 +{ +( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 +( -737 65535 65535 ) ( -737 -65535 65535 ) ( -737 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1440 65535 ) ( 65535 1440 65535 ) ( -65535 1440 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 95 +{ +( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) rock5_2 -79 -0 -0 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) rock5_2 -79 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -79 0 180 1 1 +( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) rock5_2 -79 -0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) rock5_2 -79 0 180 1 1 +( 65535 -65535 -2880 ) ( 65535 65535 -2880 ) ( -65535 -65535 -2880 ) rock5_2 -79 0 180 1 1 +} +// brush 96 +{ +( -4032 -65535 65535 ) ( -4032 65535 65535 ) ( -4032 65535 -65535 ) city4_5 0 0 180 1 1 +( -4048 65535 65535 ) ( -4048 -65535 65535 ) ( -4048 65535 -65535 ) city4_7 48 -0 -0 1 1 +( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 -0 -0 90 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -0 -0 90 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -0 -0 270 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city4_5 -0 -0 270 1 1 +} +// brush 97 +{ +( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) metal1_4 -15 -0 -0 1 1 +( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3952 ) ( 65535 -65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) metal1_4 -15 0 180 1 1 +} +// brush 98 +{ +( 48 -65535 65535 ) ( 48 65535 65535 ) ( 48 65535 -65535 ) metal1_4 -15 -0 -0 1 1 +( -208 65535 65535 ) ( -208 -65535 65535 ) ( -208 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 -15 -0 180 1 1 +( 65535 65535 -3952 ) ( 65535 -65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -15 -0 180 1 1 +( 65535 -65535 -3968 ) ( 65535 65535 -3968 ) ( -65535 -65535 -3968 ) metal1_4 -15 -0 180 1 1 +} +// brush 99 +{ +( 128 -63999 65535 ) ( 128 67071 65535 ) ( 128 67071 -65535 ) metal1_4 48 -48 180 1 1 +( -400 67071 65535 ) ( -400 -63999 65535 ) ( -400 67071 -65535 ) metal1_4 48 -48 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal1_4 48 -48 -0 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 48 -48 -0 1 1 +( 65535 67071 -3952 ) ( 65535 -63999 -3952 ) ( -65535 -63999 -3952 ) metal1_4 48 16 -0 1 1 +( 65535 -63999 -3968 ) ( 65535 67071 -3968 ) ( -65535 -63999 -3968 ) metal1_4 48 16 -0 1 1 +} +// brush 100 +{ +( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) sfloor4_1 -15 0 180 1 1 +} +// brush 101 +{ +( -3376 -65535 65535 ) ( -3376 65535 65535 ) ( -3376 65535 -65535 ) city4_5 -15 0 0 1 1 +( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) city4_5 -15 0 180 1 1 +} +// brush 102 +{ +( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) rock5_2 0 0 180 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) rock5_2 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 0 0 90 1 1 +( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) rock5_2 -0 -0 90 1 1 +( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 0 0 270 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) rock5_2 0 0 270 1 1 +} +// brush 103 +{ +( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) rock5_2 -79 0 0 1 1 +( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) rock5_2 -79 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -79 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) rock5_2 -79 0 180 1 1 +( 65535 65535 -3632 ) ( 65535 -65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -79 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) rock5_2 -79 0 180 1 1 +} +// brush 104 +{ +( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) *lava1 -15 0 0 1 1 +( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) *lava1 -15 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) *lava1 -15 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *lava1 -15 0 180 1 1 +( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) *lava1 -15 0 180 1 1 +( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) *lava1 -15 0 180 1 1 +} +// brush 105 +{ +( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -16 0 90 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 65535 -304 65535 ) ( -65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -16 0 180 1 1 +} +// brush 106 +{ +( -3152 -65535 65535 ) ( -3152 65535 65535 ) ( -3152 65535 -65535 ) metal1_4 0 0 180 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -16 0 180 1 1 +} +// brush 107 +{ +( -3152 -65535 65535 ) ( -3152 65535 65535 ) ( -3152 65535 -65535 ) metal1_4 0 0 180 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3280 ) ( 65535 -65535 -3280 ) ( -65535 -65535 -3280 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 +} +// brush 108 +{ +( -3152 -65535 65535 ) ( -3152 65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 +} +// brush 109 +{ +( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 +} +// brush 110 +{ +( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3296 ) ( 65535 -65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 +} +// brush 111 +{ +( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 55094 65535 35503 ) ( 55094 -65535 35503 ) ( -53962 -65535 -37201 ) metal1_4 -15 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3296 ) ( 65535 65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 +} +// brush 112 +{ +( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 52096 -65535 -40000 ) ( 52096 65535 -40000 ) ( -56960 -65535 32704 ) metal1_4 -15 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 +} +// brush 113 +{ +( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 +} +// brush 114 +{ +( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) metal4_4 -16 0 90 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal4_4 -16 0 90 1 1 +( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal4_4 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 -16 0 180 1 1 +( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) metal4_4 -16 0 180 1 1 +} +// brush 115 +{ +( 56805 65534 -32930 ) ( 56805 -65534 -32930 ) ( -60427 -65534 25685 ) metal1_4 -15 0 180 1 1 +( 59352 65534 27836 ) ( 59352 -65534 27836 ) ( -57880 -65534 -30780 ) metal1_4 -15 0 180 1 1 +( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3232 ) ( 65535 -65535 -3232 ) ( -65535 -65535 -3232 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3296 ) ( 65535 65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 +} +// brush 116 +{ +( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 56843 -65534 -32853 ) ( 56843 65534 -32853 ) ( -60389 -65534 25762 ) metal1_4 -15 0 180 1 1 +( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -15 0 180 1 1 +} +// brush 117 +{ +( 59313 -65534 27912 ) ( 59313 65534 27912 ) ( -57918 -65534 -30703 ) metal1_4 -15 0 180 1 1 +( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 +} +// brush 118 +{ +( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal4_4 0 0 180 1 1 +( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -16 0 180 1 1 +} +// brush 119 +{ +( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal4_4 0 0 180 1 1 +( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -15 0 180 1 1 +} +// brush 120 +{ +( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3360 ) ( 65535 65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -15 0 180 1 1 +} +// brush 121 +{ +( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) metal5_8 0 0 180 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) metal5_8 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal5_8 0 0 90 1 1 +( -65535 416 65535 ) ( 65535 416 65535 ) ( -65535 416 -65535 ) metal5_8 -16 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal5_8 0 0 270 1 1 +} +// brush 122 +{ +( 56054 65535 -34151 ) ( 56054 -65535 -34151 ) ( -59539 -65535 27631 ) metal1_4 -15 0 180 1 1 +( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -15 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 +} +// brush 123 +{ +( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 +( 56094 -65535 -34077 ) ( 56094 65535 -34077 ) ( -59499 -65535 27706 ) metal1_4 -15 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 -0 -0 180 1 1 +( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3040 ) ( 65535 -65535 -3040 ) ( -65535 -65535 -3040 ) wizmet1_8 -15 -0 180 1 1 +} +// brush 124 +{ +( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 0 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city4_5 0 0 90 1 1 +( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) city4_5 -0 -0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 125 +{ +( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) city4_5 0 0 180 1 1 +( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2976 ) ( 65535 -65535 -2976 ) ( -65535 -65535 -2976 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 126 +{ +( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) city4_5 17 16 180 1 1 +( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) city4_5 17 16 180 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 17 16 0 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 17 16 0 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 17 16 -0 1 1 +} +// brush 127 +{ +( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 -0 -0 180 1 1 +( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) city4_5 -16 -0 -0 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -16 -0 90 1 1 +( 65535 -65535 -3408 ) ( 65535 65535 -3408 ) ( -65535 -65535 -3408 ) city4_5 -16 -0 90 1 1 +} +// brush 128 +{ +( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) city4_5 -0 -0 180 1 1 +( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -16 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 -0 -0 180 1 1 +( 65535 65535 -3744 ) ( 65535 -65535 -3744 ) ( -65535 -65535 -3744 ) city4_8 -16 -0 -0 1 1 +( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) city4_5 -0 -0 270 1 1 +} +// brush 129 +{ +( 60085 -65534 26370 ) ( 60085 65534 26370 ) ( -57147 -65534 -32245 ) metal1_4 -15 0 180 1 1 +( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) metal1_4 -15 0 0 1 1 +( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) metal1_4 -15 0 0 1 1 +( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 +( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 +( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 +( 65535 -65535 -3856 ) ( 65535 65535 -3856 ) ( -65535 -65535 -3856 ) metal1_4 -15 0 180 1 1 +} +// brush 130 +{ +( -752 -64335 65535 ) ( -752 66735 65535 ) ( -752 66735 -65535 ) ecop1_1 16 -0 -0 1 1 +( -816 66735 65535 ) ( -816 -64335 65535 ) ( -816 66735 -65535 ) ecop1_1 16 -0 -0 1 1 +( 65023 1072 65535 ) ( -66047 1072 65535 ) ( -66047 1072 -65535 ) ecop1_1 -0 -0 -0 1 1 +( -66047 1008 65535 ) ( 65023 1008 65535 ) ( -66047 1008 -65535 ) ecop1_1 -0 -0 -0 1 1 +( 65023 66735 -3052 ) ( 65023 -64335 -3052 ) ( -66047 -64335 -3052 ) ecop1_1 -0 -16 -0 1 1 +( 65023 -64335 -3056 ) ( 65023 66735 -3056 ) ( -66047 -64335 -3056 ) ecop1_1 -0 -16 -0 1 1 +} +// brush 131 +{ +( -2488 -65535 65535 ) ( -2488 65535 65535 ) ( -2488 65535 -65535 ) sfloor4_1 -15 -0 -0 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) sfloor4_1 -15 -0 180 1 1 +} +// brush 132 +{ +( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 +( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 +( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) city4_5 0 0 180 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 270 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 -16 0 270 1 1 +} +// brush 133 +{ +( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) *water2 -15 0 0 1 1 +( -47636 45044 65535 ) ( 45044 -47636 65535 ) ( -47636 45044 -65535 ) *water2 -15 0 0 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) *water2 -15 0 0 1 1 +( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) *water2 -15 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 +} +// brush 134 +{ +( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) *water2 -15 0 0 1 1 +( 44036 48644 65535 ) ( -48644 -44036 65535 ) ( 44036 48644 -65535 ) *water2 -15 0 0 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) *water2 -15 0 0 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) *water2 -15 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 +} +// brush 135 +{ +( -2488 -65535 65535 ) ( -2488 65535 65535 ) ( -2488 65535 -65535 ) sfloor4_6 48 -0 -0 1 1 +( 54283 65535 36731 ) ( 54283 -65535 36731 ) ( -53093 -65535 -38432 ) sfloor4_1 -47 0 180 1 1 +( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) sfloor4_1 -47 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -47 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -47 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -47 0 180 1 1 +} +// brush 136 +{ +( 54283 -65535 36731 ) ( 54283 65535 36731 ) ( -53093 -65535 -38432 ) *water2 -15 0 180 1 1 +( -3664 65535 65535 ) ( -3664 -65535 65535 ) ( -3664 65535 -65535 ) *water2 -15 0 0 1 1 +( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) *water2 -15 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) *water2 -15 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 +( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 +} +// brush 137 +{ +( 61198 -69207 -8124 ) ( 61198 48024 50491 ) ( -58451 -45277 -55984 ) sfloor4_6 48 0 90 1 1 +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) sfloor4_6 48 0 0 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) sfloor4_6 48 -0 -0 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_6 48 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_6 48 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) sfloor4_6 48 0 90 1 1 +} +// brush 138 +{ +( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 +( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 +( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) city4_5 0 0 180 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 +( 65535 1168 65535 ) ( -65535 1168 65535 ) ( -65535 1168 -65535 ) city4_5 -16 0 90 1 1 +( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) city4_5 -16 0 270 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 270 1 1 +} +// brush 139 +{ +( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) metal5_8 -15 -15 0 1 1 +( -47636 45044 65535 ) ( 45044 -47636 65535 ) ( -47636 45044 -65535 ) metal5_8 -15 -15 0 1 1 +( 65535 -52721 -39062 ) ( 65535 56335 33642 ) ( -65535 -52721 -39062 ) metal5_8 -15 -15 180 1 1 +( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 -15 180 1 1 +} +// brush 140 +{ +( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) metal5_8 -15 -15 0 1 1 +( 44036 48644 65535 ) ( -48644 -44036 65535 ) ( 44036 48644 -65535 ) metal5_8 -15 -15 0 1 1 +( 65535 -55714 34572 ) ( 65535 53341 -38131 ) ( -65535 -55714 34572 ) metal5_8 -15 -15 180 1 1 +( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 -15 180 1 1 +} +// brush 141 +{ +( 73382 -19297 53221 ) ( -19297 73382 53221 ) ( -72806 19873 -53797 ) metal5_8 -15 -15 180 1 1 +( -19969 -72710 53893 ) ( 72710 19969 53893 ) ( 19201 73478 -53125 ) metal5_8 -15 -15 180 1 1 +( 46236 -65535 46444 ) ( 46236 65535 46444 ) ( -46444 65535 -46236 ) metal5_8 -15 -15 180 1 1 +( -3664 65535 65535 ) ( -3664 -65535 65535 ) ( -3664 65535 -65535 ) metal5_8 -15 -15 0 1 1 +( 65535 -52721 -39062 ) ( 65535 56335 33642 ) ( -65535 -52721 -39062 ) metal5_8 -15 -15 180 1 1 +( 65535 -55714 34572 ) ( 65535 53341 -38131 ) ( -65535 -55714 34572 ) metal5_8 -15 -15 180 1 1 +( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 -15 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 -15 180 1 1 +} +// brush 142 +{ +( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 +( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 +( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) city4_5 0 0 180 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 +( 65535 1168 65535 ) ( -65535 1168 65535 ) ( -65535 1168 -65535 ) city4_5 -16 0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 270 1 1 +( 65535 -65535 -3120 ) ( 65535 65535 -3120 ) ( -65535 -65535 -3120 ) city4_5 -16 0 270 1 1 +} +// brush 143 +{ +( -3840 1440 -3055.6818278010733 ) ( -3840 1440 -3071.9626565132116 ) ( -3568 1168 -3135.9615853377113 ) metal5_8 16 0 180 1 1 +( -3760 1168 -3135.9612395957392 ) ( -4032 1440 -3071.9623107712378 ) ( -4032 1440 -3055.6818278010719 ) metal5_8 16 0 180 1 1 +( -3840 1440 -3071.9626565132116 ) ( -4032 1440 -3071.9623107712378 ) ( -3760 1168 -3135.9612395957392 ) metal5_8 -15 32 180 1 1 +( -4032 1440 -3055.6818278010719 ) ( -4032 1440 -3071.9623107712378 ) ( -3840 1440 -3071.9626565132116 ) metal5_8 16 0 90 1 1 +( -3568 1168 -3119.6796958890081 ) ( -3760 1168 -3119.6796958890072 ) ( -4032 1440 -3055.6818278010719 ) metal5_8 -15 32 180 1 1 +( -3568 1168 -3135.9615853377113 ) ( -3760 1168 -3135.9612395957392 ) ( -3760 1168 -3119.6796958890072 ) metal5_8 16 0 90 1 1 +} +// brush 144 +{ +( 45140 -47540 65535 ) ( -47540 45140 65535 ) ( -47540 45140 -65535 ) metal5_8 -16 0 180 1 1 +( 63530 -65535 -16510 ) ( 63530 65535 -16510 ) ( -64994 -65535 9194 ) metal5_8 -15 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 0 180 1 1 +} +// brush 145 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3312 ) ( 65535 -65535 -3312 ) ( -65535 -65535 -3312 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3320 ) ( 65535 65535 -3320 ) ( -65535 -65535 -3320 ) metal1_3 -15 0 180 1 1 +} +// brush 146 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3296 ) ( 65535 -65535 -3296 ) ( -65535 -65535 -3296 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3304 ) ( 65535 65535 -3304 ) ( -65535 -65535 -3304 ) metal1_3 -15 0 180 1 1 +} +// brush 147 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3280 ) ( 65535 -65535 -3280 ) ( -65535 -65535 -3280 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3288 ) ( 65535 65535 -3288 ) ( -65535 -65535 -3288 ) metal1_3 -15 0 180 1 1 +} +// brush 148 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3264 ) ( 65535 -65535 -3264 ) ( -65535 -65535 -3264 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3272 ) ( 65535 65535 -3272 ) ( -65535 -65535 -3272 ) metal1_3 -15 0 180 1 1 +} +// brush 149 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3248 ) ( 65535 -65535 -3248 ) ( -65535 -65535 -3248 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3256 ) ( 65535 65535 -3256 ) ( -65535 -65535 -3256 ) metal1_3 -15 0 180 1 1 +} +// brush 150 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3232 ) ( 65535 -65535 -3232 ) ( -65535 -65535 -3232 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3240 ) ( 65535 65535 -3240 ) ( -65535 -65535 -3240 ) metal1_3 -15 0 180 1 1 +} +// brush 151 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3216 ) ( 65535 -65535 -3216 ) ( -65535 -65535 -3216 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3224 ) ( 65535 65535 -3224 ) ( -65535 -65535 -3224 ) metal1_3 -15 0 180 1 1 +} +// brush 152 +{ +( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 +( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 +( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 +( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) metal1_3 -15 0 180 1 1 +( 65535 -65535 -3208 ) ( 65535 65535 -3208 ) ( -65535 -65535 -3208 ) metal1_3 -15 0 180 1 1 +} +// brush 153 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 +( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) metal5_8 0 0 180 1 1 +( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) metal5_8 -16 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 0 180 1 1 +} +// brush 154 +{ +( -2800 -65535 65535 ) ( -2800 65535 65535 ) ( -2800 65535 -65535 ) city4_5 0 0 180 1 1 +( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) city4_5 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) city4_5 0 0 270 1 1 +} +// brush 155 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -16 0 90 1 1 +( -2800 65535 65535 ) ( -2800 -65535 65535 ) ( -2800 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) city4_5 -16 0 180 1 1 +( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) city4_5 -16 0 180 1 1 +} +// brush 156 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 +( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) metal5_8 0 0 180 1 1 +( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) metal5_8 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 +} +// brush 157 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -15 0 0 1 1 +( -2704 65535 65535 ) ( -2704 -65535 65535 ) ( -2704 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 976 65535 ) ( -65535 976 65535 ) ( -65535 976 -65535 ) city4_5 -16 0 180 1 1 +( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 158 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -16 0 90 1 1 +( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1104 65535 ) ( -65535 1104 65535 ) ( -65535 1104 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 159 +{ +( -2800 -65535 65535 ) ( -2800 65535 65535 ) ( -2800 65535 -65535 ) city4_5 0 0 180 1 1 +( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1104 65535 ) ( 65535 1104 65535 ) ( -65535 1104 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 160 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 +( -2800 65535 65535 ) ( -2800 -65535 65535 ) ( -2800 65535 -65535 ) metal5_8 0 0 180 1 1 +( 65535 1440 65535 ) ( -65535 1440 65535 ) ( -65535 1440 -65535 ) metal5_8 -15 0 180 1 1 +( -65535 1104 65535 ) ( 65535 1104 65535 ) ( -65535 1104 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 +} +// brush 161 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 32 0 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal5_8 -15 32 0 1 1 +( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) metal5_8 -15 32 180 1 1 +( -65535 1440 65535 ) ( 65535 1440 65535 ) ( -65535 1440 -65535 ) metal5_8 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 32 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 32 180 1 1 +} +// brush 162 +{ +( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -16 0 90 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1552 65535 ) ( 65535 1552 65535 ) ( -65535 1552 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city4_5 -16 -0 180 1 1 +} +// brush 163 +{ +( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -0 -0 270 1 1 +} +// brush 164 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +// brush 165 +{ +( -1488 -65535 65535 ) ( -1488 65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 +( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 +} +// brush 166 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) wizmet1_8 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 +} +// brush 167 +{ +( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -16 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) metal5_8 -15 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) metal5_8 -15 0 180 1 1 +} +// brush 168 +{ +( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -16 0 180 1 1 +( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) city4_5 -16 0 180 1 1 +} +// brush 169 +{ +( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -15 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 170 +{ +( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -15 0 180 1 1 +( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 +} +// brush 171 +{ +( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal5_8 -15 0 180 1 1 +( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) metal5_8 -15 0 180 1 1 +} +// brush 172 +{ +( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 +( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1104 65535 ) ( -65535 1104 65535 ) ( -65535 1104 -65535 ) city4_5 -16 0 180 1 1 +( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 +} +// brush 173 +{ +( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +// brush 174 +{ +( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) city4_5 0 0 180 1 1 +( -2465 65535 65535 ) ( -2465 -65535 65535 ) ( -2465 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -16 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 0 0 270 1 1 +} +// brush 175 +{ +( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +// brush 176 +{ +( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) city4_5 0 0 180 1 1 +( -2465 65535 65535 ) ( -2465 -65535 65535 ) ( -2465 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 0 0 90 1 1 +( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 0 0 270 1 1 +} +// brush 177 +{ +( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( -2447 65535 65535 ) ( -2447 -65535 65535 ) ( -2447 65535 -65535 ) wizmet1_8 -15 0 0 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wizmet1_8 -16 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wizmet1_8 -15 0 180 1 1 +} +// brush 178 +{ +( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) city4_5 0 0 180 1 1 +( -2447 65535 65535 ) ( -2447 -65535 65535 ) ( -2447 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 0 0 90 1 1 +( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 0 0 270 1 1 +} +// brush 179 +{ +( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) wizmet1_8 0 0 180 1 1 +( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) wizmet1_8 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wizmet1_8 -16 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wizmet1_8 -15 0 180 1 1 +} +// brush 180 +{ +( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) city4_5 0 0 180 1 1 +( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 608 65535 ) ( -65535 608 65535 ) ( -65535 608 -65535 ) city4_5 -16 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 181 +{ +( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 +( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1328 65535 ) ( -65535 1328 65535 ) ( -65535 1328 -65535 ) city4_5 -16 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 180 1 1 +} +// brush 182 +{ +( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 1328 65535 ) ( 65535 1328 65535 ) ( -65535 1328 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +// brush 183 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +// brush 184 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 +( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 608 65535 ) ( -65535 608 65535 ) ( -65535 608 -65535 ) city4_5 -16 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 +} +// brush 185 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 0 0 180 1 1 +( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 0 0 90 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 186 +{ +( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 +} +// brush 187 +{ +( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 +( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) city4_5 -16 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -3055 ) ( 65535 -65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -15 0 180 1 1 +} +// brush 188 +{ +( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 +( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) city4_5 -16 0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3055 ) ( 65535 65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -16 0 180 1 1 +} +// brush 189 +{ +( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) sfloor4_1 -15 0 180 1 1 +} +// brush 190 +{ +( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 +( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -15 0 180 1 1 +( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) city4_5 -15 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 +} +// brush 191 +{ +( 61198 -69207 -8124 ) ( 61198 48024 50491 ) ( -58451 -45277 -55984 ) city4_5 -15 0 180 1 1 +( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 +( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -15 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3055 ) ( 65535 -65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -15 0 180 1 1 +} +// brush 192 +{ +( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 +( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 +( 65535 -65535 -3055 ) ( 65535 65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -16 0 180 1 1 +} +// brush 193 +{ +( 61106 65535 -23920 ) ( 61106 -65535 -23920 ) ( -63237 -65535 17527 ) sfloor4_1 -15 0 180 1 1 +( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1232 65535 ) ( -65535 1232 65535 ) ( -65535 1232 -65535 ) sfloor4_1 -16 0 180 1 1 +( -65535 864 65535 ) ( 65535 864 65535 ) ( -65535 864 -65535 ) sfloor4_1 -16 0 180 1 1 +( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3408 ) ( 65535 65535 -3408 ) ( -65535 -65535 -3408 ) sfloor4_1 -15 0 180 1 1 +} +// brush 194 +{ +( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 +( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 688 65535 ) ( -65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 +( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 195 +{ +( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 +( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 0 0 90 1 1 +( -65535 1440 65535 ) ( 65535 1440 65535 ) ( -65535 1440 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 196 +{ +( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) city4_5 -15 0 0 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 -15 0 180 1 1 +( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) city4_5 -15 0 180 1 1 +} +// brush 197 +{ +( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) city4_5 -15 0 0 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) city4_5 -15 0 0 1 1 +( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -15 0 180 1 1 +( 65535 -65535 -2960 ) ( 65535 65535 -2960 ) ( -65535 -65535 -2960 ) city4_5 -15 0 180 1 1 +} +// brush 198 +{ +( -1488 -65535 65535 ) ( -1488 65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 +( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) city4_5 -0 -0 180 1 1 +( 65535 2432 65535 ) ( -65535 2432 65535 ) ( -65535 2432 -65535 ) city4_5 -0 -0 90 1 1 +( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -0 -0 270 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 +} +// brush 199 +{ +( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) city4_5 0 0 180 1 1 +( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1776 65535 ) ( -65535 1776 65535 ) ( -65535 1776 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 +} +// brush 200 +{ +( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) sfloor4_1 -15 0 0 1 1 +( 65535 1776 65535 ) ( -65535 1776 65535 ) ( -65535 1776 -65535 ) sfloor4_1 -15 0 180 1 1 +( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) sfloor4_1 -15 0 180 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 -0 180 1 1 +} +// brush 201 +{ +( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 +( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 1776 65535 ) ( -65535 1776 65535 ) ( -65535 1776 -65535 ) city4_5 -16 0 180 1 1 +( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 +} +// brush 202 +{ +( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 0 0 180 1 1 +( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 2192 65535 ) ( -65535 2192 65535 ) ( -65535 2192 -65535 ) city4_5 -16 0 180 1 1 +( -65535 2096 65535 ) ( 65535 2096 65535 ) ( -65535 2096 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 203 +{ +( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 +( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 2192 65535 ) ( -65535 2192 65535 ) ( -65535 2192 -65535 ) city4_5 -16 0 180 1 1 +( -65535 2096 65535 ) ( 65535 2096 65535 ) ( -65535 2096 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 +} +// brush 204 +{ +( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) metal3_2 -15 0 0 1 1 +( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) metal3_2 -15 0 0 1 1 +( 65535 2416 65535 ) ( -65535 2416 65535 ) ( -65535 2416 -65535 ) metal3_2 -15 0 180 1 1 +( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) metal3_2 -15 0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) metal3_2 -15 -0 180 1 1 +( 65535 -65535 -2880 ) ( 65535 65535 -2880 ) ( -65535 -65535 -2880 ) metal3_2 -15 0 180 1 1 +} +// brush 205 +{ +( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 -16 0 90 1 1 +( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) city4_5 -16 0 90 1 1 +( 65535 2432 65535 ) ( -65535 2432 65535 ) ( -65535 2432 -65535 ) city4_5 -16 -0 180 1 1 +( -65535 2416 65535 ) ( 65535 2416 65535 ) ( -65535 2416 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -16 -0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 -0 180 1 1 +} +// brush 206 +{ +( -1088 -65535 65535 ) ( -1088 65535 65535 ) ( -1088 65535 -65535 ) city4_5 -0 -0 180 1 1 +( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 2432 65535 ) ( -65535 2432 65535 ) ( -65535 2432 -65535 ) city4_5 -0 -0 90 1 1 +( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) sky1 16 0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -0 -0 270 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 +} +// brush 207 +{ +( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) wizmet1_8 0 0 180 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 0 0 180 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 0 0 90 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) wizmet1_8 0 0 90 1 1 +( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 +} +// brush 208 +{ +( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) city6_8 -15 0 0 1 1 +( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) city6_8 -15 0 0 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 -15 0 180 1 1 +( -65535 -48 65535 ) ( 65535 -48 65535 ) ( -65535 -48 -65535 ) city6_8 -15 0 180 1 1 +( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 -15 0 180 1 1 +( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) city6_8 -15 0 180 1 1 +} +// brush 209 +{ +( -1856 -65535 65535 ) ( -1856 65535 65535 ) ( -1856 65535 -65535 ) metal1_4 -16 0 90 1 1 +( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -16 0 90 1 1 +( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 +( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 -16 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 +} +// brush 210 +{ +( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) metal3_2 0 0 180 1 1 +( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal3_2 0 0 180 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal3_2 0 0 90 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) metal3_2 0 0 90 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) metal3_2 -15 0 180 1 1 +( 65535 -65535 -2880 ) ( 65535 65535 -2880 ) ( -65535 -65535 -2880 ) metal3_2 -15 0 180 1 1 +} +// brush 211 +{ +( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) rock5_2 -0 -0 180 1 1 +( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) rock5_2 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 0 0 90 1 1 +( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) rock5_2 -0 -0 90 1 1 +( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 0 0 270 1 1 +( 65535 -65535 -3712 ) ( 65535 65535 -3712 ) ( -65535 -65535 -3712 ) rock5_2 -0 -0 270 1 1 +} +// brush 212 +{ +( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) metal4_4 -16 0 90 1 1 +( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal4_4 -16 0 90 1 1 +( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 +( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metal4_4 -16 -0 180 1 1 +( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) metal4_4 -16 0 180 1 1 +( 65535 -65535 -3664 ) ( 65535 65535 -3664 ) ( -65535 -65535 -3664 ) metal4_4 -16 -0 180 1 1 +} +// brush 213 +{ +( -1744 -65695 65535 ) ( -1744 65375 65535 ) ( -1744 65375 -65535 ) metal1_4 -32 -0 180 1 1 +( -1760 65375 65535 ) ( -1760 -65695 65535 ) ( -1760 65375 -65535 ) metal1_4 -32 -0 180 1 1 +( 65631 -160 65535 ) ( -65439 -160 65535 ) ( -65439 -160 -65535 ) metal1_4 16 -0 180 1 1 +( -65439 -320 65535 ) ( 65631 -320 65535 ) ( -65439 -320 -65535 ) metal1_4 16 -0 180 1 1 +( 65631 65375 -3328 ) ( 65631 -65695 -3328 ) ( -65439 -65695 -3328 ) metal1_4 -32 -32 270 1 1 +( 65631 -65695 -3472 ) ( 65631 65375 -3472 ) ( -65439 -65695 -3472 ) metal1_4 -32 -32 270 1 1 +} +// brush 214 +{ +( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) wiz1_4 -0 -0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) wizmet1_8 -15 0 180 1 1 +( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) wizmet1_8 -15 0 180 1 1 +( 65535 65535 -3040 ) ( 65535 -65535 -3040 ) ( -65535 -65535 -3040 ) wizmet1_8 -15 -0 180 1 1 +( 65535 -65535 -3360 ) ( 65535 65535 -3360 ) ( -65535 -65535 -3360 ) wizmet1_8 -15 0 180 1 1 +} +// brush 215 +{ +( 704 -63583 65535 ) ( 704 67487 65535 ) ( 704 67487 -65535 ) metal1_4 48 16 180 1 1 +( 128 67487 65535 ) ( 128 -63583 65535 ) ( 128 67487 -65535 ) metal1_4 48 16 180 1 1 +( 65663 1648 65535 ) ( -65407 1648 65535 ) ( -65407 1648 -65535 ) metal1_4 16 -48 -0 1 1 +( -65407 448 65535 ) ( 65663 448 65535 ) ( -65407 448 -65535 ) metal1_4 16 -48 -0 1 1 +( 65663 67487 -3408 ) ( 65663 -63583 -3408 ) ( -65407 -63583 -3408 ) city4_8 -16 32 -0 1 1 +( 65663 -63583 -3952 ) ( 65663 67487 -3952 ) ( -65407 -63583 -3952 ) metal1_4 16 48 -0 1 1 +} +// brush 216 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3208 ) ( 65359 67951 -3208 ) ( -65711 -63119 -3208 ) metal1_3 32 -0 -0 1 1 +} +// brush 217 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3216 ) ( 65359 -63119 -3216 ) ( -65711 -63119 -3216 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3224 ) ( 65359 67951 -3224 ) ( -65711 -63119 -3224 ) metal1_3 32 -0 -0 1 1 +} +// brush 218 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3232 ) ( 65359 -63119 -3232 ) ( -65711 -63119 -3232 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3240 ) ( 65359 67951 -3240 ) ( -65711 -63119 -3240 ) metal1_3 32 -0 -0 1 1 +} +// brush 219 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3248 ) ( 65359 -63119 -3248 ) ( -65711 -63119 -3248 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3256 ) ( 65359 67951 -3256 ) ( -65711 -63119 -3256 ) metal1_3 32 -0 -0 1 1 +} +// brush 220 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3264 ) ( 65359 -63119 -3264 ) ( -65711 -63119 -3264 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3272 ) ( 65359 67951 -3272 ) ( -65711 -63119 -3272 ) metal1_3 32 -0 -0 1 1 +} +// brush 221 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3280 ) ( 65359 -63119 -3280 ) ( -65711 -63119 -3280 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3288 ) ( 65359 67951 -3288 ) ( -65711 -63119 -3288 ) metal1_3 32 -0 -0 1 1 +} +// brush 222 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3296 ) ( 65359 -63119 -3296 ) ( -65711 -63119 -3296 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3304 ) ( 65359 67951 -3304 ) ( -65711 -63119 -3304 ) metal1_3 32 -0 -0 1 1 +} +// brush 223 +{ +( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3312 ) ( 65359 -63119 -3312 ) ( -65711 -63119 -3312 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3320 ) ( 65359 67951 -3320 ) ( -65711 -63119 -3320 ) metal1_3 32 -0 -0 1 1 +} +// brush 224 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 32 -0 180 1 1 +( 52917 -63119 -38432 ) ( 52917 67951 -38432 ) ( -54459 -63119 36731 ) city4_7 32 48 -0 1 1 +( 65359 560 65535 ) ( -65711 560 65535 ) ( -65711 560 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3450.9930803904022 ) ( 65359 67951 -3450.9930803904022 ) ( -65711 -63119 -3450.9930803904022 ) city4_7 32 48 -0 1 1 +} +// brush 225 +{ +( 64 1680 -3968 ) ( 64 1792 -3952 ) ( 64 1792 -3968 ) metal1_4 -0 -48 -0 1 1 +( -240 1680 -3968 ) ( -240 1792 -3952 ) ( -240 1680 -3952 ) metal1_4 -0 -48 -0 1 1 +( -112 1952 -3968 ) ( 32 1952 -3952 ) ( -112 1952 -3952 ) metal1_4 -16 -48 -0 1 1 +( -112 1664 -3968 ) ( 32 1664 -3952 ) ( 32 1664 -3968 ) metal1_4 -16 -48 -0 1 1 +( -112 1680 -3952 ) ( 32 1792 -3952 ) ( 32 1680 -3952 ) metal1_4 -16 -0 -0 1 1 +( -112 1680 -3968 ) ( 32 1792 -3968 ) ( -112 1792 -3968 ) metal1_4 -16 -0 -0 1 1 +} +// brush 226 +{ +( 272 1664 -3088 ) ( 272 1712 -3072 ) ( 272 1712 -3088 ) wiz1_4 -32 -0 -0 1 1 +( -224 1664 -3088 ) ( -224 1712 -3072 ) ( -224 1664 -3072 ) wiz1_4 -32 -0 -0 1 1 +( -224 1664 -3088 ) ( -192 1664 -3072 ) ( -224 1664 -3072 ) wiz1_4 16 -0 -0 1 1 +( -224 1648 -3088 ) ( -192 1648 -3072 ) ( -192 1648 -3088 ) wiz1_4 16 -0 -0 1 1 +( -224 1664 -2864 ) ( -192 1712 -2864 ) ( -192 1664 -2864 ) wiz1_4 16 32 -0 1 1 +( -224 1664 -3792 ) ( -192 1712 -3792 ) ( -224 1712 -3792 ) wiz1_4 16 32 -0 1 1 +} +// brush 227 +{ +( -736 1632 -3344 ) ( -736 1664 -3328 ) ( -736 1664 -3344 ) city4_5 0 0 0 1 1 +( -880 1632 -3344 ) ( -880 1664 -3328 ) ( -880 1632 -3328 ) city4_5 -0 -0 -0 1 1 +( -784 1664 -3344 ) ( -736 1664 -3328 ) ( -784 1664 -3328 ) city4_5 0 0 0 1 1 +( -784 1648 -3344 ) ( -736 1648 -3328 ) ( -736 1648 -3344 ) city4_5 -0 -0 -0 1 1 +( -784 1632 -3072 ) ( -736 1664 -3072 ) ( -736 1632 -3072 ) city4_5 -0 -0 -0 1 1 +( -784 1632 -3408 ) ( -736 1664 -3408 ) ( -784 1664 -3408 ) city4_5 -0 -0 -0 1 1 +} +// brush 228 +{ +( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 0 0 180 1 1 +( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) metal1_4 0 0 180 1 1 +( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) metal1_4 0 0 90 1 1 +( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 0 0 90 1 1 +( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 0 0 270 1 1 +} +// brush 229 +{ +( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) city4_5 0 0 180 1 1 +( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) city4_5 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 +( -65535 432 65535 ) ( 65535 432 65535 ) ( -65535 432 -65535 ) city4_5 0 0 90 1 1 +( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -15 0 180 1 1 +( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 0 0 270 1 1 +} +// brush 230 +{ +( -448 -64335 65535 ) ( -448 66735 65535 ) ( -448 66735 -65535 ) wiz1_4 48 -0 180 1 1 +( -736 66735 65535 ) ( -736 -64335 65535 ) ( -736 66735 -65535 ) city4_5 -0 -0 -0 1 1 +( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 16 -0 -0 1 1 +( -65535 1648 65535 ) ( 65535 1648 65535 ) ( -65535 1648 -65535 ) city4_5 -16 -0 180 1 1 +( 65535 66735 -2864 ) ( 65535 -64335 -2864 ) ( -65535 -64335 -2864 ) city4_5 -0 -0 90 1 1 +( 65535 -64335 -3408 ) ( 65535 66735 -3408 ) ( -65535 -64335 -3408 ) city4_5 -0 -0 90 1 1 +} +// brush 231 +{ +( 48 448 -3088 ) ( 48 496 -3072 ) ( 48 496 -3088 ) wiz1_4 -32 -0 -0 1 1 +( -448 448 -3088 ) ( -448 496 -3072 ) ( -448 448 -3072 ) wiz1_4 -32 -0 -0 1 1 +( -448 464 -3088 ) ( -416 464 -3072 ) ( -448 464 -3072 ) wiz1_4 48 -0 -0 1 1 +( -448 432 -3088 ) ( -416 432 -3072 ) ( -416 432 -3088 ) wiz1_4 48 -0 -0 1 1 +( -448 448 -2864 ) ( -416 496 -2864 ) ( -416 448 -2864 ) wiz1_4 48 32 -0 1 1 +( -448 448 -3792 ) ( -416 496 -3792 ) ( -448 496 -3792 ) wiz1_4 48 32 -0 1 1 +} +// brush 232 +{ +( 544 1616 -3808 ) ( 544 1664 -3792 ) ( 544 1664 -3808 ) wiz1_4 0 0 0 1 1 +( 448 1616 -3808 ) ( 448 1664 -3792 ) ( 448 1616 -3792 ) wiz1_4 -0 -0 -0 1 1 +( 464 1664 -3808 ) ( 544 1664 -3792 ) ( 464 1664 -3792 ) wiz1_4 0 0 0 1 1 +( 464 1648 -3808 ) ( 544 1648 -3792 ) ( 544 1648 -3808 ) wiz1_4 -0 -0 -0 1 1 +( 464 1616 -3792 ) ( 544 1664 -3792 ) ( 544 1616 -3792 ) wiz1_4 0 0 0 1 1 +( 464 1616 -3952 ) ( 544 1664 -3952 ) ( 464 1664 -3952 ) wiz1_4 -0 -0 -0 1 1 +} +// brush 233 +{ +( -208 416 -3808 ) ( -208 464 -3792 ) ( -208 464 -3808 ) wiz1_4 48 -0 -0 1 1 +( -304 416 -3808 ) ( -304 464 -3792 ) ( -304 416 -3792 ) wiz1_4 48 -0 -0 1 1 +( -288 464 -3808 ) ( -208 464 -3792 ) ( -288 464 -3792 ) wiz1_4 48 -0 -0 1 1 +( -288 448 -3808 ) ( -208 448 -3792 ) ( -208 448 -3808 ) wiz1_4 48 -0 -0 1 1 +( -288 416 -3792 ) ( -208 464 -3792 ) ( -208 416 -3792 ) wiz1_4 48 -48 -0 1 1 +( -288 416 -3952 ) ( -208 464 -3952 ) ( -288 464 -3952 ) wiz1_4 48 -48 -0 1 1 +} +// brush 234 +{ +( 64 384 -3968 ) ( 64 432 -3952 ) ( 64 432 -3968 ) city4_5 -16 -16 -0 1 1 +( 48 384 -3968 ) ( 48 432 -3952 ) ( 48 384 -3952 ) city4_5 -16 -16 -0 1 1 +( 48 432 -3968 ) ( 80 432 -3952 ) ( 48 432 -3952 ) city4_5 -0 -16 -0 1 1 +( 48 160 -3968 ) ( 80 160 -3952 ) ( 80 160 -3968 ) city4_5 -0 -16 -0 1 1 +( 48 384 -3744 ) ( 80 432 -3744 ) ( 80 384 -3744 ) city4_5 -0 16 -0 1 1 +( 48 384 -3968 ) ( 80 432 -3968 ) ( 48 432 -3968 ) city4_5 -0 16 -0 1 1 +} +// brush 235 +{ +( 64 144 -3744 ) ( 64 176 -3728 ) ( 64 176 -3744 ) metal1_4 -0 -0 -0 1 1 +( -208 144 -3744 ) ( -208 176 -3728 ) ( -208 144 -3728 ) metal1_4 -0 -0 -0 1 1 +( -208 432 -3744 ) ( -192 432 -3728 ) ( -208 432 -3728 ) metal1_4 16 -0 -0 1 1 +( -208 144 -3744 ) ( -192 144 -3728 ) ( -192 144 -3744 ) metal1_4 16 -0 -0 1 1 +( -208 144 -3728 ) ( -192 176 -3728 ) ( -192 144 -3728 ) metal1_4 16 -0 -0 1 1 +( -208 144 -3744 ) ( -192 176 -3744 ) ( -208 176 -3744 ) metal1_4 16 -0 -0 1 1 +} +// brush 236 +{ +( 48 160 -3952 ) ( 48 208 -3936 ) ( 48 208 -3952 ) *water2 -16 -0 -0 1 1 +( -848 160 -3952 ) ( -848 208 -3936 ) ( -848 160 -3936 ) *water2 -16 -0 -0 1 1 +( -208 432 -3952 ) ( -160 432 -3936 ) ( -208 432 -3936 ) *water2 32 -0 -0 1 1 +( -208 160 -3952 ) ( -160 160 -3936 ) ( -160 160 -3952 ) *water2 32 -0 -0 1 1 +( -208 160 -3744 ) ( -160 208 -3744 ) ( -160 160 -3744 ) *water2 32 16 -0 1 1 +( -208 160 -3952 ) ( -160 208 -3952 ) ( -208 208 -3952 ) *water2 32 16 -0 1 1 +} +// brush 237 +{ +( 976 1648 -2880 ) ( 976 1664 -2864 ) ( 976 1664 -2880 ) city4_7 -0 -0 -0 1 1 +( 688 1648 -2880 ) ( 688 1664 -2864 ) ( 688 1648 -2864 ) city4_7 0 0 0 1 1 +( 688 1664 -2880 ) ( 720 1664 -2864 ) ( 688 1664 -2864 ) city4_7 0 0 0 1 1 +( 688 1648 -2880 ) ( 720 1648 -2864 ) ( 720 1648 -2880 ) city4_7 0 0 0 1 1 +( 688 1648 -2864 ) ( 720 1664 -2864 ) ( 720 1648 -2864 ) city4_7 0 0 0 1 1 +( 688 1648 -2880 ) ( 720 1664 -2880 ) ( 688 1664 -2880 ) city4_7 0 0 0 1 1 +} +// brush 238 +{ +( 128 1568 -3936 ) ( 128 1648 -3920 ) ( 128 1648 -3936 ) *water2 -0 -0 -0 1 1 +( -304 1568 -3936 ) ( -304 1648 -3920 ) ( -304 1568 -3920 ) *water2 -0 -0 -0 1 1 +( 400 1648 -3936 ) ( 544 1648 -3920 ) ( 400 1648 -3920 ) *water2 -0 -0 -0 1 1 +( 400 464 -3936 ) ( 544 464 -3920 ) ( 544 464 -3936 ) *water2 -0 -0 -0 1 1 +( 400 1568 -3584 ) ( 544 1648 -3584 ) ( 544 1568 -3584 ) *water2 -0 -0 -0 1 1 +( 400 1568 -3952 ) ( 544 1648 -3952 ) ( 400 1648 -3952 ) *water2 -0 -0 -0 1 1 +} +// brush 239 +{ +( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) city4_7 32 -0 180 1 1 +( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) city4_7 32 48 -0 1 1 +} +// brush 240 +{ +( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 63061 67951 17527 ) ( 63061 -63119 17527 ) ( -61282 -63119 -23920 ) sfloor4_6 32 -0 -0 1 1 +( 65359 1248 65535 ) ( -65711 1248 65535 ) ( -65711 1248 -65535 ) sfloor4_6 32 -0 -0 1 1 +( -65711 880 65535 ) ( 65359 880 65535 ) ( -65711 880 -65535 ) sfloor4_6 32 -0 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3408 ) ( 65359 67951 -3408 ) ( -65711 -63119 -3408 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 241 +{ +( -736 928 -2864 ) ( -736 1024 -2848 ) ( -736 1024 -2864 ) sky1 -0 -0 -0 1 1 +( -752 928 -2864 ) ( -752 1024 -2848 ) ( -752 928 -2848 ) sky1 -0 -0 -0 1 1 +( -752 1664 -2864 ) ( -736 1664 -2848 ) ( -752 1664 -2848 ) sky1 192 -0 -0 1 1 +( -752 448 -2864 ) ( -736 448 -2848 ) ( -736 448 -2864 ) sky1 192 -0 -0 1 1 +( -752 928 -2576 ) ( -736 1024 -2576 ) ( -736 928 -2576 ) sky1 192 -0 -0 1 1 +( -752 928 -2864 ) ( -736 1024 -2864 ) ( -752 1024 -2864 ) sky1 192 -0 -0 1 1 +} +// brush 242 +{ +( 976 448 -2864 ) ( 976 464 -2848 ) ( 976 464 -2864 ) sky1 -0 -0 -0 1 1 +( -736 448 -2864 ) ( -736 464 -2848 ) ( -736 448 -2848 ) sky1 -0 -0 -0 1 1 +( 688 464 -2864 ) ( 912 464 -2848 ) ( 688 464 -2848 ) sky1 0 0 0 1 1 +( 688 448 -2864 ) ( 912 448 -2848 ) ( 912 448 -2864 ) sky1 0 0 0 1 1 +( 688 448 -2576 ) ( 912 464 -2576 ) ( 912 448 -2576 ) sky1 -0 -0 -0 1 1 +( 688 448 -2864 ) ( 912 464 -2864 ) ( 688 464 -2864 ) sky1 0 0 0 1 1 +} +// brush 243 +{ +( 976 1648 -2864 ) ( 976 1664 -2848 ) ( 976 1664 -2864 ) sky1 -176 -0 -0 1 1 +( -736 1648 -2864 ) ( -736 1664 -2848 ) ( -736 1648 -2848 ) sky1 -176 -0 -0 1 1 +( 688 1664 -2864 ) ( 912 1664 -2848 ) ( 688 1664 -2848 ) sky1 -0 -0 -0 1 1 +( 688 1648 -2864 ) ( 912 1648 -2848 ) ( 912 1648 -2864 ) sky1 -0 -0 -0 1 1 +( 688 1648 -2576 ) ( 912 1664 -2576 ) ( 912 1648 -2576 ) sky1 -0 48 -0 1 1 +( 688 1648 -2864 ) ( 912 1664 -2864 ) ( 688 1664 -2864 ) sky1 -0 48 -0 1 1 +} +// brush 244 +{ +( 576 -65311 65663 ) ( 576 65759 65663 ) ( 576 65759 -65407 ) sky1 224 -0 180 1 1 +( -752 65759 65663 ) ( -752 -65311 65663 ) ( -752 65759 -65407 ) sky1 224 -0 180 1 1 +( 67007 1664 65663 ) ( -64063 1664 65663 ) ( -64063 1664 -65407 ) sky1 128 -64 90 1 1 +( -64063 448 65663 ) ( 67007 448 65663 ) ( -64063 448 -65407 ) sky1 128 -64 90 1 1 +( 67007 65759 -2576 ) ( 67007 -65311 -2576 ) ( -64063 -65311 -2576 ) sky1 224 64 270 1 1 +( 67007 -65311 -2592 ) ( 67007 65759 -2592 ) ( -64063 -65311 -2592 ) sky1 224 64 270 1 1 +} +// brush 245 +{ +( 3344 -63119 65535 ) ( 3344 67951 65535 ) ( 3344 67951 -65535 ) city4_7 -32 -0 180 1 1 +( 3328 67951 65535 ) ( 3328 -63119 65535 ) ( 3328 67951 -65535 ) city4_7 -32 -0 180 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) city4_7 32 -16 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) city4_7 32 -16 -0 1 1 +} +// brush 246 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 1424 67951 65535 ) ( 1424 -63119 65535 ) ( 1424 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 65359 1696 65535 ) ( -65711 1696 65535 ) ( -65711 1696 -65535 ) metal5r8 32 -0 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal5r8 -0 -0 180 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal5r8 -0 48 90 1 1 +} +// brush 247 +{ +( 2960 -63119 65535 ) ( 2960 67951 65535 ) ( 2960 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 57854 -63118 -30703 ) ( 57854 67950 -30703 ) ( -59377 -63118 27912 ) metal1_4 48 -0 -0 1 1 +( 65471 2416 65535 ) ( -65599 2416 65535 ) ( -65599 2416 -65535 ) metal1_4 48 -48 -0 1 1 +( -65599 2256 65535 ) ( 65471 2256 65535 ) ( -65599 2256 -65535 ) metal1_4 48 -48 -0 1 1 +( 65471 67951 -3136 ) ( 65471 -63119 -3136 ) ( -65599 -63119 -3136 ) metal1_4 48 -0 -0 1 1 +( 65471 -63119 -3200 ) ( 65471 67951 -3200 ) ( -65599 -63119 -3200 ) metal1_4 48 -0 -0 1 1 +} +// brush 248 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 1904 67951 65535 ) ( 1904 -63119 65535 ) ( 1904 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal1_4 32 -16 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 +} +// brush 249 +{ +( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal1_4 48 -0 -0 1 1 +( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -16 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 +} +// brush 250 +{ +( -46580 -63119 46276 ) ( -46580 67951 46276 ) ( 46100 67951 -46404 ) sfloor4_6 32 -0 -0 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 251 +{ +( 3200 -63119 65535 ) ( 3200 67951 65535 ) ( 3200 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 252 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 +( 3200 67951 65535 ) ( 3200 -63119 65535 ) ( 3200 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 253 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) rock5_2 -96 -48 180 1 1 +( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) rock5_2 -96 -48 180 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) rock5_2 96 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -48 -0 1 1 +( 65359 67951 -3632 ) ( 65359 -63119 -3632 ) ( -65711 -63119 -3632 ) rock5_2 96 -64 -0 1 1 +( 65359 -63119 -3648 ) ( 65359 67951 -3648 ) ( -65711 -63119 -3648 ) rock5_2 96 -64 -0 1 1 +} +// brush 254 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) *lava1 -32 -48 180 1 1 +( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) *lava1 -32 -48 180 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) *lava1 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) *lava1 32 -48 -0 1 1 +( 65359 67951 -3520 ) ( 65359 -63119 -3520 ) ( -65711 -63119 -3520 ) *lava1 32 -0 -0 1 1 +( 65359 -63119 -3632 ) ( 65359 67951 -3632 ) ( -65711 -63119 -3632 ) *lava1 32 -0 -0 1 1 +} +// brush 255 +{ +( 2864 -63119 65535 ) ( 2864 67951 65535 ) ( 2864 67951 -65535 ) rock5_2 -96 -48 180 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) rock5_2 96 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -48 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) rock5_2 96 -64 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) rock5_2 96 -64 -0 1 1 +} +// brush 256 +{ +( 160 -63135 65519 ) ( 160 67935 65519 ) ( 160 67935 -65551 ) metal1_4 -0 16 180 1 1 +( 48 67935 65519 ) ( 48 -63135 65519 ) ( 48 67935 -65551 ) city4_7 -0 -16 -0 1 1 +( 65375 1808 65519 ) ( -65695 1808 65519 ) ( -65695 1808 -65551 ) metal1_4 -0 -16 -0 1 1 +( -65695 1664 65519 ) ( 65375 1664 65519 ) ( -65695 1664 -65551 ) metal1_4 -0 -16 -0 1 1 +( 65375 67935 -3776 ) ( 65375 -63135 -3776 ) ( -65695 -63135 -3776 ) metal1_4 -0 -32 -0 1 1 +( 65375 -63135 -3968 ) ( 65375 67935 -3968 ) ( -65695 -63135 -3968 ) metal1_4 -0 -32 -0 1 1 +} +// brush 257 +{ +( 3840 -63119 65535 ) ( 3840 67951 65535 ) ( 3840 67951 -65535 ) rock5_2 -96 -48 180 1 1 +( 1185 67951 65535 ) ( 1185 -63119 65535 ) ( 1185 67951 -65535 ) rock5_2 -96 -48 180 1 1 +( 65343 2192 65535 ) ( -65727 2192 65535 ) ( -65727 2192 -65535 ) rock5_2 112 -48 -0 1 1 +( -65727 1664 65535 ) ( 65343 1664 65535 ) ( -65727 1664 -65535 ) rock5_2 112 -48 -0 1 1 +( 65343 67951 -2864 ) ( 65343 -63119 -2864 ) ( -65727 -63119 -2864 ) rock5_2 112 -64 -0 1 1 +( 65343 -63119 -2880 ) ( 65343 67951 -2880 ) ( -65727 -63119 -2880 ) rock5_2 112 -64 -0 1 1 +} +// brush 258 +{ +( 56054 65535 -34151 ) ( 56054 -65535 -34151 ) ( -59539 -65535 27631 ) metal1_4 -15 0 180 1 1 +( -704 65535 65535 ) ( -704 -65535 65535 ) ( -704 65535 -65535 ) metal1_4 -32 -0 90 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 +( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -32 0 180 1 1 +( 65535 65535 -3936 ) ( 65535 -65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -32 0 180 1 1 +( 65535 -65535 -3952 ) ( 65535 65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -32 0 180 1 1 +} +// brush 259 +{ +( 48 432 -3952 ) ( 48 464 -3936 ) ( 48 464 -3952 ) *water2 -0 -0 -0 1 1 +( -208 432 -3952 ) ( -208 464 -3936 ) ( -208 432 -3936 ) *water2 0 0 0 1 1 +( -208 464 -3952 ) ( -192 464 -3936 ) ( -208 464 -3936 ) *water2 0 0 0 1 1 +( -208 432 -3952 ) ( -192 432 -3936 ) ( -192 432 -3952 ) *water2 0 0 0 1 1 +( -208 432 -3792 ) ( -192 464 -3792 ) ( -192 432 -3792 ) *water2 -0 -0 -0 1 1 +( -208 432 -3952 ) ( -192 464 -3952 ) ( -208 464 -3952 ) *water2 0 0 0 1 1 +} +// brush 260 +{ +( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) city4_5 0 0 180 1 1 +( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) city4_5 -0 -0 180 1 1 +( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 +( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 +( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 0 0 270 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -0 -0 270 1 1 +} +// brush 261 +{ +( -224 1968 -3968 ) ( -224 1984 -3952 ) ( -224 1984 -3968 ) city4_7 16 16 -0 1 1 +( -240 1968 -3968 ) ( -240 1984 -3952 ) ( -240 1968 -3952 ) city4_7 16 16 -0 1 1 +( -336 1968 -3968 ) ( -224 1968 -3952 ) ( -336 1968 -3952 ) city4_7 32 16 -0 1 1 +( -336 1680 -3968 ) ( -224 1680 -3952 ) ( -224 1680 -3968 ) city4_7 32 16 -0 1 1 +( -336 1968 -3776 ) ( -224 1984 -3776 ) ( -224 1968 -3776 ) city4_7 32 -16 -0 1 1 +( -336 1968 -3968 ) ( -224 1984 -3968 ) ( -336 1984 -3968 ) city4_7 32 -16 -0 1 1 +} +// brush 262 +{ +( 64 1952 -3968 ) ( 64 1968 -3952 ) ( 64 1968 -3968 ) city4_7 32 -48 -0 1 1 +( -224 1952 -3968 ) ( -224 1968 -3952 ) ( -224 1952 -3952 ) city4_7 32 -48 -0 1 1 +( -48 1968 -3968 ) ( 64 1968 -3952 ) ( -48 1968 -3952 ) city4_7 -0 -48 -0 1 1 +( -48 1952 -3968 ) ( 64 1952 -3952 ) ( 64 1952 -3968 ) city4_7 -0 -48 -0 1 1 +( -48 1952 -3776 ) ( 64 1968 -3776 ) ( 64 1952 -3776 ) city4_7 -0 -32 -0 1 1 +( -48 1952 -3968 ) ( 64 1968 -3968 ) ( -48 1968 -3968 ) city4_7 -0 -32 -0 1 1 +} +// brush 263 +{ +( 48 1728 -3952 ) ( 48 1808 -3936 ) ( 48 1808 -3952 ) *water2 -0 -0 -0 1 1 +( -224 1728 -3952 ) ( -224 1808 -3936 ) ( -224 1728 -3936 ) *water2 -0 -0 -0 1 1 +( -224 1808 -3952 ) ( -160 1808 -3936 ) ( -224 1808 -3936 ) *water2 16 -0 -0 1 1 +( -224 1648 -3952 ) ( -160 1648 -3936 ) ( -160 1648 -3952 ) *water2 16 -0 -0 1 1 +( -224 1728 -3792 ) ( -160 1808 -3792 ) ( -160 1728 -3792 ) *water2 16 -0 -0 1 1 +( -224 1728 -3952 ) ( -160 1808 -3952 ) ( -224 1808 -3952 ) *water2 16 -0 -0 1 1 +} +// brush 264 +{ +( 640 1824 -3952 ) ( 640 1856 -3936 ) ( 640 1856 -3952 ) *water2 -0 -0 -0 1 1 +( -224 1824 -3952 ) ( -224 1856 -3936 ) ( -224 1824 -3936 ) *water2 -0 -0 -0 1 1 +( -144 1952 -3952 ) ( -32 1952 -3936 ) ( -144 1952 -3936 ) *water2 -0 -0 -0 1 1 +( -144 1808 -3952 ) ( -32 1808 -3936 ) ( -32 1808 -3952 ) *water2 -0 -0 -0 1 1 +( -144 1824 -3792 ) ( -32 1856 -3792 ) ( -32 1824 -3792 ) *water2 -0 -0 -0 1 1 +( -144 1824 -3952 ) ( -32 1856 -3952 ) ( -144 1856 -3952 ) *water2 -0 -0 -0 1 1 +} +// brush 265 +{ +( 64 1680 -3792 ) ( 64 1792 -3776 ) ( 64 1792 -3792 ) metal1_4 -0 -0 -0 1 1 +( -240 1680 -3792 ) ( -240 1792 -3776 ) ( -240 1680 -3776 ) metal1_4 -0 -0 -0 1 1 +( -112 1952 -3792 ) ( 32 1952 -3776 ) ( -112 1952 -3776 ) metal1_4 48 -0 -0 1 1 +( -112 1664 -3792 ) ( 32 1664 -3776 ) ( 32 1664 -3792 ) metal1_4 48 -0 -0 1 1 +( -112 1680 -3776 ) ( 32 1792 -3776 ) ( 32 1680 -3776 ) metal1_4 48 -0 -0 1 1 +( -112 1680 -3792 ) ( 32 1792 -3792 ) ( -112 1792 -3792 ) metal1_4 48 -0 -0 1 1 +} +// brush 266 +{ +( 59481 -63119 27471 ) ( 59481 67951 27471 ) ( -56113 -63119 -34311 ) metal1_4 16 -16 -0 1 1 +( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65391 2032 65535 ) ( -65679 2032 65535 ) ( -65679 2032 -65535 ) metal1_4 16 -0 -0 1 1 +( -65679 1968 65535 ) ( 65391 1968 65535 ) ( -65679 1968 -65535 ) metal1_4 16 -0 -0 1 1 +( 65391 67951 -3936 ) ( 65391 -63119 -3936 ) ( -65679 -63119 -3936 ) metal1_4 16 -16 -0 1 1 +( 65391 -63119 -4000 ) ( 65391 67951 -4000 ) ( -65679 -63119 -4000 ) metal1_4 16 -16 -0 1 1 +} +// brush 267 +{ +( 448 -63119 65535 ) ( 448 67951 65535 ) ( 448 67951 -65535 ) city4_8 -32 -0 180 1 1 +( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65391 1968 65535 ) ( -65679 1968 65535 ) ( -65679 1968 -65535 ) city4_8 -0 -0 -0 1 1 +( -65679 1952 65535 ) ( 65391 1952 65535 ) ( -65679 1952 -65535 ) metal1_4 -0 -0 -0 1 1 +( 65391 67951 -3776 ) ( 65391 -63119 -3776 ) ( -65679 -63119 -3776 ) city4_8 -0 -16 -0 1 1 +( 65391 -63119 -3952 ) ( 65391 67951 -3952 ) ( -65679 -63119 -3952 ) city4_8 -0 -16 -0 1 1 +} +// brush 268 +{ +( 272 -63119 65535 ) ( 272 67951 65535 ) ( 272 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 56971 -63118 -32245 ) ( 56971 67950 -32245 ) ( -60261 -63118 26370 ) metal1_4 32 -0 -0 1 1 +( 65359 1952 65535 ) ( -65711 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 1808 65535 ) ( 65359 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3776 ) ( 65359 -63119 -3776 ) ( -65711 -63119 -3776 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3856 ) ( 65359 67951 -3856 ) ( -65711 -63119 -3856 ) metal1_4 32 -0 -0 1 1 +} +// brush 269 +{ +( 304 -63119 65535 ) ( 304 67951 65535 ) ( 304 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 160 67951 65535 ) ( 160 -63119 65535 ) ( 160 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 65391 1808 65535 ) ( -65679 1808 65535 ) ( -65679 1808 -65535 ) metal1_4 -0 -0 -0 1 1 +( -65679 1648 65535 ) ( 65391 1648 65535 ) ( -65679 1648 -65535 ) metal1_4 -32 -0 180 1 1 +( 65391 67951 -3776 ) ( 65391 -63119 -3776 ) ( -65679 -63119 -3776 ) metal1_4 -0 16 90 1 1 +( 65391 -63119 -3952 ) ( 65391 67951 -3952 ) ( -65679 -63119 -3952 ) metal1_4 -0 16 90 1 1 +} +// brush 270 +{ +( 59481 -63119 27471 ) ( 59481 67951 27471 ) ( -56113 -63119 -34311 ) metal1_4 48 -16 -0 1 1 +( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 48 -0 -0 1 1 +( 65391 1952 65535 ) ( -65679 1952 65535 ) ( -65679 1952 -65535 ) metal1_4 48 -0 -0 1 1 +( -65679 1664 65535 ) ( 65391 1664 65535 ) ( -65679 1664 -65535 ) metal1_4 48 -0 -0 1 1 +( 65391 67951 -3952 ) ( 65391 -63119 -3952 ) ( -65679 -63119 -3952 ) metal1_4 -0 -0 -0 1 1 +( 65391 -63119 -4000 ) ( 65391 67951 -4000 ) ( -65679 -63119 -4000 ) metal1_4 48 -16 -0 1 1 +} +// brush 271 +{ +( 59481 -63119 27471 ) ( 59481 67951 27471 ) ( -56113 -63119 -34311 ) metal1_4 -0 -16 -0 1 1 +( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65391 1968 65535 ) ( -65679 1968 65535 ) ( -65679 1968 -65535 ) metal1_4 -0 -0 -0 1 1 +( -65679 1952 65535 ) ( 65391 1952 65535 ) ( -65679 1952 -65535 ) metal1_4 -0 -0 -0 1 1 +( 65391 67951 -3936 ) ( 65391 -63119 -3936 ) ( -65679 -63119 -3936 ) metal1_4 -0 -16 -0 1 1 +( 65391 -63119 -4000 ) ( 65391 67951 -4000 ) ( -65679 -63119 -4000 ) metal1_4 -0 -16 -0 1 1 +} +// brush 272 +{ +( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -0 -0 1 1 +( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 59363 67951 27631 ) ( 59363 -63119 27631 ) ( -56230 -63119 -34151 ) metal1_4 32 -0 -0 1 1 +( 65359 1952 65535 ) ( -65711 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 1808 65535 ) ( 65359 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 -63119 -3952 ) ( 65359 67951 -3952 ) ( -65711 -63119 -3952 ) metal1_4 32 -0 -0 1 1 +} +// brush 273 +{ +( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -16 -0 1 1 +( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 416 67951 65535 ) ( 416 -63119 65535 ) ( 416 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 1952 65535 ) ( 65359 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -0 -0 1 1 +( 65359 67951 -3360 ) ( 65359 -63119 -3360 ) ( -65711 -63119 -3360 ) metal1_4 32 -16 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -16 -0 1 1 +} +// brush 274 +{ +( 59323 -63119 27706 ) ( 59323 67951 27706 ) ( -56270 -63119 -34077 ) metal1_4 32 -0 -0 1 1 +( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 272 67951 65535 ) ( 272 -63119 65535 ) ( 272 67951 -65535 ) wiz1_4 -0 -0 -0 1 1 +( 65359 1952 65535 ) ( -65711 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 1808 65535 ) ( 65359 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3360 ) ( 65359 -63119 -3360 ) ( -65711 -63119 -3360 ) mmetal1_8 -63 16 180 1 1 +} +// brush 275 +{ +( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -16 -0 1 1 +( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 272 67951 65535 ) ( 272 -63119 65535 ) ( 272 67951 -65535 ) wiz1_4 -0 -0 -0 1 1 +( 65359 1808 65535 ) ( -65711 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) mmetal1_8 -63 16 180 1 1 +( 65359 -63119 -3952.3362112220393 ) ( 65359 67951 -3952.3362112220393 ) ( -65711 -63119 -3952.3362112220393 ) metal1_4 32 -16 -0 1 1 +} +// brush 276 +{ +( 128 1648 -3952 ) ( 128 1664 -3936 ) ( 128 1664 -3952 ) wiz1_4 0 0 0 1 1 +( 48 1648 -3952 ) ( 48 1664 -3936 ) ( 48 1648 -3936 ) wiz1_4 0 0 0 1 1 +( 48 1664 -3952 ) ( 128 1664 -3936 ) ( 48 1664 -3936 ) wiz1_4 0 0 0 1 1 +( 48 1648 -3952 ) ( 128 1648 -3936 ) ( 128 1648 -3952 ) wiz1_4 0 0 0 1 1 +( 48 1648 -3792 ) ( 128 1664 -3792 ) ( 128 1648 -3792 ) wiz1_4 -0 -0 -0 1 1 +( 48 1648 -3952 ) ( 128 1664 -3952 ) ( 48 1664 -3952 ) wiz1_4 0 0 0 1 1 +} +// brush 277 +{ +( 560 -66751 65535 ) ( 560 64319 65535 ) ( 560 64319 -65535 ) wiz1_4 -16 -2 90 1 1 +( 48 64319 65535 ) ( 48 -66751 65535 ) ( 48 64319 -65535 ) wiz1_4 -16 -2 90 1 1 +( 66047 464 65535 ) ( -65023 464 65535 ) ( -65023 464 -65535 ) wiz1_4 -16 -2 180 1 1 +( -65023 432 65535 ) ( 66047 432 65535 ) ( -65023 432 -65535 ) wiz1_4 -16 -2 180 1 1 +( 66047 64319 -2864 ) ( 66047 -66751 -2864 ) ( -65023 -66751 -2864 ) wiz1_4 -15 -2 180 1 1 +( 66047 -66751 -4000 ) ( 66047 64319 -4000 ) ( -65023 -66751 -4000 ) wiz1_4 -16 -2 180 1 1 +} +// brush 278 +{ +( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1744 67951 65535 ) ( 1744 -63119 65535 ) ( 1744 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 +} +// brush 279 +{ +( 1648 -63119 65535 ) ( 1648 67951 65535 ) ( 1648 67951 -65535 ) city4_7 32 -48 180 1 1 +( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 280 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 +( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal5r8 32 -0 -0 1 1 +} +// brush 281 +{ +( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 1648 67951 65535 ) ( 1648 -63119 65535 ) ( 1648 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 282 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 32 -48 180 1 1 +( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 896 65535 ) ( 65359 896 65535 ) ( -65711 896 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 +} +// brush 283 +{ +( 2768 -63119 65535 ) ( 2768 67951 65535 ) ( 2768 67951 -65535 ) rock5_2 32 -0 180 1 1 +( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) rock5_2 32 -0 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) rock5_2 96 112 -0 1 1 +( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) rock5_2 96 112 -0 1 1 +} +// brush 284 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) rock5_2 32 -0 180 1 1 +( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) rock5_2 32 -0 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) rock5_2 96 -0 -0 1 1 +( 65359 67951 -3520 ) ( 65359 -63119 -3520 ) ( -65711 -63119 -3520 ) rock5_2 96 112 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) rock5_2 96 112 -0 1 1 +} +// brush 285 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) sfloor4_6 32 -0 180 1 1 +( 2768 67951 65535 ) ( 2768 -63119 65535 ) ( 2768 67951 -65535 ) sfloor4_6 32 -0 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 48 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) sfloor4_6 32 48 -0 1 1 +} +// brush 286 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) rock5_2 32 -0 180 1 1 +( 2768 67951 65535 ) ( 2768 -63119 65535 ) ( 2768 67951 -65535 ) rock5_2 32 -0 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) rock5_2 96 112 -0 1 1 +( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) rock5_2 96 112 -0 1 1 +} +// brush 287 +{ +( 52917 67951 -38432 ) ( 52917 -63119 -38432 ) ( -54459 -63119 36731 ) sfloor4_6 -0 -0 -0 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) sfloor4_6 -0 -48 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 -0 -48 -0 1 1 +( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) sfloor4_6 -0 -48 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 -0 -0 -0 1 1 +} +// brush 288 +{ +( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) city4_7 32 -16 -0 1 1 +( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city4_7 -32 -0 180 1 1 +( 65359 1792 65535 ) ( -65711 1792 65535 ) ( -65711 1792 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -16 -0 1 1 +} +// brush 289 +{ +( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) city6_8 32 -0 -0 1 1 +( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) city6_8 -32 -48 180 1 1 +( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city6_8 -32 -48 180 1 1 +( 65359 1969 65535 ) ( -65711 1969 65535 ) ( -65711 1969 -65535 ) city6_8 32 -48 -0 1 1 +( -65711 1792 65535 ) ( 65359 1792 65535 ) ( -65711 1792 -65535 ) city6_8 32 -48 -0 1 1 +( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -0 -0 1 1 +} +// brush 290 +{ +( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) rock5_2 -0 -0 180 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) rock5_2 -0 -0 180 1 1 +( 65359 67951 -3520 ) ( 65359 -63119 -3520 ) ( -65711 -63119 -3520 ) rock5_2 64 48 90 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) rock5_2 64 48 90 1 1 +} +// brush 291 +{ +( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -16 -0 1 1 +( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -16 -0 180 1 1 +( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal1_4 32 -16 -0 1 1 +} +// brush 292 +{ +( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city4_7 -32 -48 180 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 1792 65535 ) ( 65359 1792 65535 ) ( -65711 1792 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3360 ) ( 65359 67951 -3360 ) ( -65711 -63119 -3360 ) city4_7 32 -0 -0 1 1 +} +// brush 293 +{ +( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) city6_8 -0 -0 -0 1 1 +( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) city6_8 -32 -48 180 1 1 +( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) city6_8 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) city6_8 32 -48 -0 1 1 +( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -0 -0 1 1 +( 65359 -63119 -3472 ) ( 65359 67951 -3472 ) ( -65711 -63119 -3472 ) city6_8 32 -0 -0 1 1 +} +// brush 294 +{ +( 1568 -63119 65535 ) ( 1568 67951 65535 ) ( 1568 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal1_4 32 -16 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -16 -0 1 1 +} +// brush 295 +{ +( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -16 -0 180 1 1 +( 1184 67951 65535 ) ( 1184 -63119 65535 ) ( 1184 67951 -65535 ) city4_7 -16 -0 180 1 1 +( 65359 2176 65535 ) ( -65711 2176 65535 ) ( -65711 2176 -65535 ) city4_7 -0 48 90 1 1 +( -65711 1969 65535 ) ( 65359 1969 65535 ) ( -65711 1969 -65535 ) city4_7 -0 48 90 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -16 -48 270 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -16 -48 270 1 1 +} +// brush 296 +{ +( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 1184 67951 65535 ) ( 1184 -63119 65535 ) ( 1184 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1969 65535 ) ( -65711 1969 65535 ) ( -65711 1969 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -16 -0 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -16 -0 1 1 +} +// brush 297 +{ +( 1424 -63119 65535 ) ( 1424 67951 65535 ) ( 1424 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2976 ) ( 65359 -63119 -2976 ) ( -65711 -63119 -2976 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 298 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) city4_7 32 -48 180 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -2976 ) ( 65359 67951 -2976 ) ( -65711 -63119 -2976 ) city4_7 32 -0 -0 1 1 +} +// brush 299 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) city4_7 32 -48 180 1 1 +( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) city4_7 32 -0 -0 1 1 +} +// brush 300 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1488 67951 65535 ) ( 1488 -63119 65535 ) ( 1488 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2976 ) ( 65359 -63119 -2976 ) ( -65711 -63119 -2976 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 301 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1488 67951 65535 ) ( 1488 -63119 65535 ) ( 1488 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 +} +// brush 302 +{ +( 2032 -63119 65535 ) ( 2032 67951 65535 ) ( 2032 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1712 67951 65535 ) ( 1712 -63119 65535 ) ( 1712 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 1504 65535 ) ( 65359 1504 65535 ) ( -65711 1504 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 303 +{ +( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) city6_8 -0 16 -0 1 1 +( 60241 67950 25704 ) ( 60241 -63118 25704 ) ( -56990 -63118 -32911 ) city6_8 32 -48 -0 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) city6_8 32 16 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) city6_8 32 -32 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -48 -0 1 1 +} +// brush 304 +{ +( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) rock5_2 -0 -0 180 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 -0 -0 180 1 1 +( 65359 67951 -3472 ) ( 65359 -63119 -3472 ) ( -65711 -63119 -3472 ) rock5_2 64 48 90 1 1 +( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) rock5_2 64 48 90 1 1 +} +// brush 305 +{ +( -208 1664 -3968 ) ( -208 1680 -3952 ) ( -208 1680 -3968 ) metal1_4 0 0 0 1 1 +( -224 1664 -3968 ) ( -224 1680 -3952 ) ( -224 1664 -3952 ) metal1_4 0 0 0 1 1 +( -224 1680 -3968 ) ( -208 1680 -3952 ) ( -224 1680 -3952 ) metal1_4 0 0 0 1 1 +( -224 1664 -3968 ) ( -208 1664 -3952 ) ( -208 1664 -3968 ) metal1_4 0 0 0 1 1 +( -224 1664 -3952 ) ( -208 1680 -3952 ) ( -208 1664 -3952 ) metal1_4 0 0 0 1 1 +( -224 1664 -3968 ) ( -208 1680 -3968 ) ( -224 1680 -3968 ) metal1_4 0 0 0 1 1 +} +// brush 306 +{ +( 3488 -63119 65535 ) ( 3488 67951 65535 ) ( 3488 67951 -65535 ) *water2 32 -48 180 1 1 +( 52917 -63119 -38432 ) ( 52917 67951 -38432 ) ( -54459 -63119 36731 ) *water2 32 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) *water2 32 -48 -0 1 1 +( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) *water2 32 -48 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 +} +// brush 307 +{ +( 3872 1648 -2880 ) ( 3872 1664 -2864 ) ( 3872 1664 -2880 ) city4_7 -0 -0 -0 1 1 +( 3856 1648 -2880 ) ( 3856 1664 -2864 ) ( 3856 1648 -2864 ) city4_7 -0 -0 -0 1 1 +( 3856 1664 -2880 ) ( 3872 1664 -2864 ) ( 3856 1664 -2864 ) city4_7 32 -0 -0 1 1 +( 3856 464 -2880 ) ( 3872 464 -2864 ) ( 3872 464 -2880 ) city4_7 32 -0 -0 1 1 +( 3856 1648 -2864 ) ( 3872 1664 -2864 ) ( 3872 1648 -2864 ) city4_7 32 -0 -0 1 1 +( 3856 1648 -3456 ) ( 3872 1664 -3456 ) ( 3856 1664 -3456 ) city4_7 32 -0 -0 1 1 +} +// brush 308 +{ +( 3583.4505200993262 949 -3138.9172473249582 ) ( 3856 672 -3055.9193792414385 ) ( 3584 944.44800098396217 -3120.3757850958596 ) metal5r8 26.6304 39.1252 180 1 1 +( 3856 672 -3071.9768577734121 ) ( 3856 672 -3055.9193792414385 ) ( 3583.4505200993262 949 -3138.9172473249582 ) metal5r8 32 -16 180 1 1 +( 3664 672 -3071.9772035159772 ) ( 3392 944 -3135.9761323403272 ) ( 3392 944 -3119.9172472754499 ) metal5r8 -32 -0 -0 1 1 +( 3392 944 -3119.9172472754499 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3584 944.44800098396217 -3120.3757850958596 ) metal5r8 32 -16 -0 1 1 +( 3392 944 -3119.9172472754499 ) ( 3856 672 -3055.9193792414385 ) ( 3664 672 -3055.9193792413157 ) metal5r8 32 32 -0 1 1 +( 3584 944.44800098396217 -3120.3757850958596 ) ( 3856 672 -3055.9193792414385 ) ( 3392 944 -3119.9172472754499 ) metal5r8 32 32 -0 1 1 +( 3392 944 -3135.9761323403272 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3392 944 -3119.9172472754499 ) metal5r8 32 -16 -0 1 1 +( 3856 672 -3071.9768577734121 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3664 672 -3071.9772035159772 ) metal5r8 32 32 -0 1 1 +( 3664 672 -3071.9772035159772 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3392 944 -3135.9761323403272 ) metal5r8 32 32 -0 1 1 +( 3664 672 -3055.9193792413157 ) ( 3856 672 -3055.9193792414385 ) ( 3856 672 -3071.9768577734121 ) metal5r8 32 -16 -0 1 1 +} +// brush 309 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal5r8 32 -48 180 1 1 +( 48620 46300 65535 ) ( -44060 -46380 65535 ) ( 48620 46300 -65535 ) city4_7 -0 -0 -0 1 1 +( -65711 944 65535 ) ( 65359 944 65535 ) ( -65711 944 -65535 ) metal5r8 32 -0 -0 1 1 +( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 32 -0 -0 1 1 +} +// brush 310 +{ +( 47372 -42716 65535 ) ( -45308 49964 65535 ) ( -45308 49964 -65535 ) metal5r8 32 -48 180 1 1 +( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 32 -48 180 1 1 +( 48460 46460 65535 ) ( -44220 -46220 65535 ) ( -44220 -46220 -65535 ) metal5r8 32 -48 180 1 1 +( -45532 49740 65535 ) ( 47148 -42940 65535 ) ( -45532 49740 -65535 ) metal5r8 -0 -0 -0 1 1 +( 3168 67951 65535 ) ( 3168 -63119 65535 ) ( 3168 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 65359 1264 65535 ) ( -65711 1264 65535 ) ( -65711 1264 -65535 ) metal5r8 32 -0 -0 1 1 +( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 -0 32 -0 1 1 +( 65434 -63118 -874 ) ( 65434 67950 -874 ) ( -65548 67950 -5649 ) metal5r8 32 -0 -0 1 1 +} +// brush 311 +{ +( 3488 -63119 65535 ) ( 3488 67951 65535 ) ( 3488 67951 -65535 ) metal5r8 32 -0 180 1 1 +( 19895 75025 53994 ) ( -72785 -17655 53994 ) ( 73404 21516 -53023 ) metal5r8 32 48 -0 1 1 +( -73660 21612 53119 ) ( 19020 -71068 53119 ) ( -20151 75121 -53898 ) metal5r8 32 48 -0 1 1 +( -46412 67951 46444 ) ( -46412 -63119 46444 ) ( 46268 67951 -46236 ) metal5r8 32 48 -0 1 1 +( 65359 -51019 -37991 ) ( 65359 58037 34712 ) ( -65711 -51019 -37991 ) metal5r8 32 48 -0 1 1 +( 65359 -54012 33501 ) ( 65359 55044 -39202 ) ( -65711 -54012 33501 ) metal5r8 32 48 -0 1 1 +( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal5r8 32 48 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 48 -0 1 1 +} +// brush 312 +{ +( 48395 -41606 65535 ) ( -46629 48667 65535 ) ( -46629 48667 -65535 ) metal5r8 32 -0 -0 1 1 +( 64818 -63119 9194 ) ( 64818 67951 9194 ) ( -63706 -63119 -16510 ) metal5r8 32 -0 -0 1 1 +( 3168 -63119 65535 ) ( 3168 67951 65535 ) ( 3168 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( -45468 49804 65535 ) ( 47212 -42876 65535 ) ( -45468 49804 -65535 ) metal5r8 -0 -0 -0 1 1 +( 64814 67951 9209 ) ( 64814 -63119 9209 ) ( -63709 -63119 -16495 ) metal5r8 32 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 -0 -0 180 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) metal5r8 -0 48 90 1 1 +} +// brush 313 +{ +( 47308 -42780 65535 ) ( -45372 49900 65535 ) ( -45372 49900 -65535 ) metal5r8 -32 -0 -0 1 1 +( -44220 -46220 65535 ) ( 48460 46460 65535 ) ( -44220 -46220 -65535 ) metal5r8 -32 -0 -0 1 1 +( 3168 67951 65535 ) ( 3168 -63119 65535 ) ( 3168 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 -0 32 -0 1 1 +( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 -0 32 -0 1 1 +} +// brush 314 +{ +( 64818 -63119 9194 ) ( 64818 67951 9194 ) ( -63706 -63119 -16510 ) metal5r8 32 -0 -0 1 1 +( -45468 49804 65535 ) ( 47212 -42876 65535 ) ( -45468 49804 -65535 ) metal5r8 -0 -0 -0 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal5r8 32 -48 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 -0 -0 1 1 +} +// brush 315 +{ +( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) *water2 32 -48 180 1 1 +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) *water2 32 -48 180 1 1 +( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) *water2 32 -48 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) *water2 32 -48 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 +} +// brush 316 +{ +( 47308 -42780 65535 ) ( -45372 49900 65535 ) ( -45372 49900 -65535 ) *water2 32 -48 180 1 1 +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) *water2 32 -48 180 1 1 +( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) *water2 32 -48 180 1 1 +( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) *water2 32 -48 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 +} +// brush 317 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 48620 46300 65535 ) ( -44060 -46380 65535 ) ( 48620 46300 -65535 ) city4_7 -0 -0 -0 1 1 +( -45372 49900 65535 ) ( 47308 -42780 65535 ) ( -45372 49900 -65535 ) city4_7 -0 -0 -0 1 1 +( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) city4_7 -0 48 90 1 1 +} +// brush 318 +{ +( 47460 -42932 65535 ) ( -45220 49748 65535 ) ( 47460 -42932 -65535 ) metal5r8 -15 -15 180 1 -1 +( 3488 67647 65535 ) ( 3488 -63423 65535 ) ( 3488 -63423 -65535 ) metal5r8 -15 -15 180 1 -1 +( -65711 54833 -39062 ) ( -65711 -54223 33642 ) ( 65359 54833 -39062 ) metal5r8 -31 -15 -0 1 1 +( -65711 -63423 -3136 ) ( -65711 67647 -3136 ) ( 65359 67647 -3136 ) metal5r8 -31 -15 -0 1 1 +} +// brush 319 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -48 180 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 608 65535 ) ( -65711 608 65535 ) ( -65711 608 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 320 +{ +( 1344 -63119 65535 ) ( 1344 67951 65535 ) ( 1344 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -48 -0 1 1 +( -65711 784 65535 ) ( 65359 784 65535 ) ( -65711 784 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 321 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -48 180 1 1 +( 1344 67951 65535 ) ( 1344 -63119 65535 ) ( 1344 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 800 65535 ) ( -65711 800 65535 ) ( -65711 800 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 784 65535 ) ( 65359 784 65535 ) ( -65711 784 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 322 +{ +( 1344 -63119 65535 ) ( 1344 67951 65535 ) ( 1344 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 323 +{ +( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) mmetal1_8 -0 -0 180 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 -0 -0 180 1 1 +( 65359 67951 -3071 ) ( 65359 -63119 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 -0 48 90 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 324 +{ +( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 65359 1216 65535 ) ( -65711 1216 65535 ) ( -65711 1216 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 325 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 326 +{ +( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 32 -48 180 1 1 +( 704 67951 65535 ) ( 704 -63119 65535 ) ( 704 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 1216 65535 ) ( -65711 1216 65535 ) ( -65711 1216 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 327 +{ +( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city6_3 32 -48 180 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city6_3 32 -48 180 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city6_3 32 -48 -0 1 1 +( -65711 608 65535 ) ( 65359 608 65535 ) ( -65711 608 -65535 ) city6_3 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city6_3 32 -0 -0 1 1 +} +// brush 328 +{ +( 1472 -63119 65535 ) ( 1472 67951 65535 ) ( 1472 67951 -65535 ) city6_3 32 -48 180 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city6_3 32 -48 180 1 1 +( 65359 784 65535 ) ( -65711 784 65535 ) ( -65711 784 -65535 ) city6_3 32 -48 -0 1 1 +( -65711 608 65535 ) ( 65359 608 65535 ) ( -65711 608 -65535 ) city6_3 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city6_3 32 -0 -0 1 1 +} +// brush 329 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) mmetal1_8 32 -48 -0 1 1 +( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 330 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 +( 1344 67951 65535 ) ( 1344 -63119 65535 ) ( 1344 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) mmetal1_8 -0 -0 180 1 1 +( -65711 800 65535 ) ( 65359 800 65535 ) ( -65711 800 -65535 ) mmetal1_8 -0 -0 180 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 331 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 +} +// brush 332 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 65359 592 65535 ) ( -65711 592 65535 ) ( -65711 592 -65535 ) mmetal1_8 32 -48 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 333 +{ +( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3424 ) ( 65359 67951 -3424 ) ( -65711 -63119 -3424 ) city4_7 32 48 -0 1 1 +} +// brush 334 +{ +( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 1216 65535 ) ( 65359 1216 65535 ) ( -65711 1216 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3424 ) ( 65359 67951 -3424 ) ( -65711 -63119 -3424 ) city4_7 32 -0 -0 1 1 +} +// brush 335 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 336 +{ +( 1344 -63119 65535 ) ( 1344 67951 65535 ) ( 1344 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 784 65535 ) ( 65359 784 65535 ) ( -65711 784 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) city4_7 -0 48 90 1 1 +} +// brush 337 +{ +( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city4_7 32 -48 180 1 1 +( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1504 65535 ) ( 65359 1504 65535 ) ( -65711 1504 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 +} +// brush 338 +{ +( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city4_7 32 -0 180 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 432 65535 ) ( 65359 432 65535 ) ( -65711 432 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city6_3 32 -0 -0 1 1 +( 65359 -63119 -3424 ) ( 65359 67951 -3424 ) ( -65711 -63119 -3424 ) city4_7 32 48 -0 1 1 +} +// brush 339 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -0 180 1 1 +( 1312 67951 65535 ) ( 1312 -63119 65535 ) ( 1312 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 +} +// brush 340 +{ +( -3840 576 -3072 ) ( -3840 576 -3056 ) ( -3568 848 -3120 ) metal5_8 -0 1 -0 1 1 +( -4033 576 -3056 ) ( -4033 576 -3072 ) ( -3763 848 -3136 ) metal5_8 -0 1 -0 1 1 +( -3840 576 -3056 ) ( -4033 576 -3056 ) ( -3763 848 -3120 ) metal5_8 2 -0 -0 1 1 +( -3568 848 -3136 ) ( -3568 848 -3120 ) ( -3763 848 -3120 ) metal5_8 2 1 -0 1 1 +( -3763 848 -3136 ) ( -4033 576 -3072 ) ( -3840 576 -3072 ) metal5_8 2 -0 -0 1 1 +( -3840 576 -3072 ) ( -4033 576 -3072 ) ( -4033 576 -3056 ) metal5_8 2 1 -0 1 1 +} +// brush 341 +{ +( 3857 1536 -3056 ) ( 3857 1536 -3072 ) ( 3587 1264 -3136 ) metal5r8 -0 1 180 1 -1 +( 3664 1536 -3072 ) ( 3664 1536 -3056 ) ( 3392 1264 -3120 ) metal5r8 -0 1 180 1 -1 +( 3587 1264 -3136 ) ( 3857 1536 -3072 ) ( 3664 1536 -3072 ) metal5r8 18 -0 180 1 1 +( 3664 1536 -3072 ) ( 3857 1536 -3072 ) ( 3857 1536 -3056 ) metal5r8 18 1 180 1 -1 +( 3664 1536 -3056 ) ( 3857 1536 -3056 ) ( 3587 1264 -3120 ) metal5r8 18 -0 180 1 1 +( 3392 1264 -3136 ) ( 3392 1264 -3120 ) ( 3587 1264 -3120 ) metal5r8 18 1 180 1 -1 +} +// brush 342 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 343 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 344 +{ +( 52917 67951 -38432 ) ( 52917 -63119 -38432 ) ( -54459 -63119 36731 ) sfloor4_6 -0 -0 -0 1 1 +( 2312 67951 65535 ) ( 2312 -63119 65535 ) ( 2312 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 -0 -0 180 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) sfloor4_6 -0 -0 180 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 -0 48 90 1 1 +( 65359 -63119 -3473.3930207867638 ) ( 65359 67951 -3473.3930207867638 ) ( -65711 -63119 -3473.3930207867638 ) sfloor4_6 -0 48 90 1 1 +} +// brush 345 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) metal5r8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal5r8 32 -0 -0 1 1 +} +// brush 346 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 347 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) metal5r8 32 -48 180 1 1 +( 2368 67951 65535 ) ( 2368 -63119 65535 ) ( 2368 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 65359 1088 65535 ) ( -65711 1088 65535 ) ( -65711 1088 -65535 ) metal5r8 32 -48 -0 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) metal5r8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 +} +// brush 348 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) metal2_6 32 -48 180 1 1 +( 2368 67951 65535 ) ( 2368 -63119 65535 ) ( 2368 67951 -65535 ) metal2_6 -0 -0 -0 1 1 +( 65359 59544 -32284 ) ( 65359 -57688 26332 ) ( -65711 -57688 26332 ) metal2_6 32 -0 -0 1 1 +( 65359 -57694 26319 ) ( 65359 59537 -32296 ) ( -65711 -57694 26319 ) metal2_6 32 -0 -0 1 1 +( -65711 1088 65535 ) ( 65359 1088 65535 ) ( -65711 1088 -65535 ) metal2_6 32 -48 -0 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) metal2_6 32 -0 -0 1 1 +} +// brush 349 +{ +( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 +} +// brush 350 +{ +( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 +} +// brush 351 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city3_2 -0 -0 -0 1 1 +( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) city3_2 -0 -0 -0 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city3_2 -0 -0 180 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) city3_2 -0 -0 180 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) city3_2 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city3_2 32 -0 -0 1 1 +} +// brush 352 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) sfloor4_1 32 -48 180 1 1 +( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) sfloor4_1 32 -48 180 1 1 +( 65359 896 65535 ) ( -65711 896 65535 ) ( -65711 896 -65535 ) sfloor4_1 32 -48 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_1 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) sfloor4_1 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) sfloor4_1 32 -0 -0 1 1 +} +// brush 353 +{ +( -1664 1200 -3352 ) ( -1664 1208 -3344 ) ( -1664 1208 -3352 ) city4_5 -0 -0 -0 1 1 +( -1808 1200 -3352 ) ( -1808 1208 -3344 ) ( -1808 1200 -3344 ) city4_5 0 0 0 1 1 +( -1808 1208 -3352 ) ( -1792 1208 -3344 ) ( -1808 1208 -3344 ) city4_5 0 0 0 1 1 +( -1808 1200 -3352 ) ( -1792 1200 -3344 ) ( -1792 1200 -3352 ) city4_5 0 0 0 1 1 +( -1808 1200 -3344 ) ( -1792 1208 -3344 ) ( -1792 1200 -3344 ) city4_5 0 0 0 1 1 +( -1808 1200 -3472 ) ( -1792 1208 -3472 ) ( -1808 1208 -3472 ) city4_5 -0 -0 -0 1 1 +} +// brush 354 +{ +( -1792 1392 -3360 ) ( -1792 1536 -3344 ) ( -1792 1536 -3360 ) iktkpn17 -0 -0 -0 1 1 +( -1936 1392 -3360 ) ( -1936 1536 -3344 ) ( -1936 1392 -3344 ) iktkpn17 0 0 0 1 1 +( -1936 1536 -3360 ) ( -1808 1536 -3344 ) ( -1936 1536 -3344 ) iktkpn17 0 0 0 1 1 +( -1936 1392 -3360 ) ( -1808 1392 -3344 ) ( -1808 1392 -3360 ) iktkpn17 0 0 0 1 1 +( -1936 1392 -3344 ) ( -1808 1536 -3344 ) ( -1808 1392 -3344 ) iktkpn17 0 0 0 1 1 +( -1936 1392 -3360 ) ( -1808 1536 -3360 ) ( -1936 1536 -3360 ) iktkpn17 0 0 0 1 1 +} +// brush 355 +{ +( 704 -63119 65535 ) ( 704 67951 65535 ) ( 704 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 65359 1216 65535 ) ( -65711 1216 65535 ) ( -65711 1216 -65535 ) mmetal1_8 32 -48 -0 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 356 +{ +( 704 -63119 65535 ) ( 704 67951 65535 ) ( 704 67951 -65535 ) city4_7 32 -48 180 1 1 +( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 357 +{ +( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city6_3 32 -48 180 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city6_3 32 -48 180 1 1 +( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city6_3 32 -48 -0 1 1 +( -65711 -304 65535 ) ( 65359 -304 65535 ) ( -65711 -304 -65535 ) city6_3 32 -48 -0 1 1 +( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city6_3 32 -0 -0 1 1 +( 65359 -63119 -2880 ) ( 65359 67951 -2880 ) ( -65711 -63119 -2880 ) city6_3 32 -0 -0 1 1 +} +// brush 358 +{ +( 1056 -63119 65535 ) ( 1056 67951 65535 ) ( 1056 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 336 65535 ) ( 65359 336 65535 ) ( -65711 336 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 359 +{ +( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) city4_7 32 -0 180 1 1 +( 1056 67951 65535 ) ( 1056 -63119 65535 ) ( 1056 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 432 65535 ) ( 65359 432 65535 ) ( -65711 432 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -16 -0 1 1 +( 65359 -63119 -2960 ) ( 65359 67951 -2960 ) ( -65711 -63119 -2960 ) city4_7 32 -0 -0 1 1 +} +// brush 360 +{ +( 1648 -63119 65535 ) ( 1648 67951 65535 ) ( 1648 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 336 65535 ) ( 65359 336 65535 ) ( -65711 336 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 +} +// brush 361 +{ +( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1184 67951 65535 ) ( 1184 -63119 65535 ) ( 1184 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 16 65535 ) ( -65711 16 65535 ) ( -65711 16 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 -80 65535 ) ( 65359 -80 65535 ) ( -65711 -80 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 362 +{ +( 1056 -63119 65535 ) ( 1056 67951 65535 ) ( 1056 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 16 65535 ) ( -65711 16 65535 ) ( -65711 16 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 -80 65535 ) ( 65359 -80 65535 ) ( -65711 -80 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 363 +{ +( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 912 67951 65535 ) ( 912 -63119 65535 ) ( 912 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 432 65535 ) ( -65711 432 65535 ) ( -65711 432 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 -352 65535 ) ( 65359 -352 65535 ) ( -65711 -352 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 +} +// brush 364 +{ +( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city4_7 32 -0 180 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 -304 65535 ) ( -65711 -304 65535 ) ( -65711 -304 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 -352 65535 ) ( 65359 -352 65535 ) ( -65711 -352 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city4_7 32 -16 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -16 -0 1 1 +} +// brush 365 +{ +( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) sfloor4_1 32 -48 180 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) sfloor4_1 32 -48 180 1 1 +( 65359 432 65535 ) ( -65711 432 65535 ) ( -65711 432 -65535 ) sfloor4_1 32 -48 -0 1 1 +( -65711 -304 65535 ) ( 65359 -304 65535 ) ( -65711 -304 -65535 ) sfloor4_1 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) sfloor4_1 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) sfloor4_1 32 -0 -0 1 1 +} +// brush 366 +{ +( 1328 -63119 65535 ) ( 1328 67951 65535 ) ( 1328 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1312 67951 65535 ) ( 1312 -63119 65535 ) ( 1312 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 352 65535 ) ( -65711 352 65535 ) ( -65711 352 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 -352 65535 ) ( 65359 -352 65535 ) ( -65711 -352 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 +} +// brush 367 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 +( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 592 65535 ) ( -65711 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 +} +// brush 368 +{ +( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 720 65535 ) ( 65359 720 65535 ) ( -65711 720 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 +} +// brush 369 +{ +( 1632 -63119 65535 ) ( 1632 67951 65535 ) ( 1632 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 +( 1456 67951 65535 ) ( 1456 -63119 65535 ) ( 1456 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 +( 65359 1088 65535 ) ( -65711 1088 65535 ) ( -65711 1088 -65535 ) mmetal1_8 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 370 +{ +( 1632 -63119 65535 ) ( 1632 67951 65535 ) ( 1632 67951 -65535 ) mmetal1_8 32 -0 180 1 1 +( 1488 67951 65535 ) ( 1488 -63119 65535 ) ( 1488 67951 -65535 ) mmetal1_8 32 -0 180 1 1 +( 65359 1040 65535 ) ( -65711 1040 65535 ) ( -65711 1040 -65535 ) mmetal1_8 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 371 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -48 180 1 1 +( 1472 67951 65535 ) ( 1472 -63119 65535 ) ( 1472 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 784 65535 ) ( -65711 784 65535 ) ( -65711 784 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 608 65535 ) ( 65359 608 65535 ) ( -65711 608 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 372 +{ +( 2271 -63119 65535 ) ( 2271 67951 65535 ) ( 2271 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 65359 1088 65535 ) ( -65711 1088 65535 ) ( -65711 1088 -65535 ) mmetal1_8 32 -0 -0 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 373 +{ +( 2368 -63119 65535 ) ( 2368 67951 65535 ) ( 2368 67951 -65535 ) mmetal1_8 32 -0 180 1 1 +( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) mmetal1_8 32 -0 180 1 1 +( 65359 1040 65535 ) ( -65711 1040 65535 ) ( -65711 1040 -65535 ) mmetal1_8 32 -0 -0 1 1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 374 +{ +( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 +( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 +} +// brush 375 +{ +( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city4_7 32 -48 180 1 1 +( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 432 65535 ) ( 65359 432 65535 ) ( -65711 432 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 -0 -0 1 1 +} +// brush 376 +{ +( 1744 576 -3360 ) ( 1760 576 -3344 ) ( 1760 576 -3360 ) iktkfl03 -0 -0 -0 1 1 +( 1616 704 -3360 ) ( 1616 736 -3344 ) ( 1616 704 -3344 ) iktkfl03 -0 -0 -0 1 1 +( 1744 704 -3360 ) ( 1760 736 -3360 ) ( 1744 736 -3360 ) iktkfl03 0 0 0 1 1 +( 1744 704 -3344 ) ( 1760 736 -3344 ) ( 1760 704 -3344 ) iktkfl03 0 0 0 1 1 +( 1744 736 -3360 ) ( 1760 736 -3344 ) ( 1744 736 -3344 ) iktkfl03 0 0 0 1 1 +( 1760 704 -3360 ) ( 1760 736 -3344 ) ( 1760 736 -3360 ) iktkfl03 0 0 0 1 1 +} +// brush 377 +{ +( 1632 -63127 65535 ) ( 1632 67943 65535 ) ( 1632 67943 -65535 ) sfloor4_6 8 -0 -0 1 1 +( 1488 67943 65535 ) ( 1488 -63127 65535 ) ( 1488 67943 -65535 ) sfloor4_6 24 -48 180 1 1 +( 65503 912 65535 ) ( -65567 912 65535 ) ( -65567 912 -65535 ) sfloor4_6 -48 -48 -0 1 1 +( -65567 440 65535 ) ( 65503 440 65535 ) ( -65567 440 -65535 ) sfloor4_6 -48 -48 -0 1 1 +( 65503 67943 -3328 ) ( 65503 -63127 -3328 ) ( -65567 -63127 -3328 ) sfloor4_6 -48 -8 -0 1 1 +( 65503 -63127 -3344 ) ( 65503 67943 -3344 ) ( -65567 -63127 -3344 ) sfloor4_6 -48 -8 -0 1 1 +} +// brush 378 +{ +( 2304 1520 -3360 ) ( 2320 1520 -3344 ) ( 2320 1520 -3360 ) iktkfl03 0 0 0 1 1 +( 1488 1520 -3360 ) ( 1488 1536 -3344 ) ( 1488 1520 -3344 ) iktkfl03 -0 -0 -0 1 1 +( 2304 1520 -3472 ) ( 2320 1536 -3472 ) ( 2304 1536 -3472 ) iktkfl03 -0 -0 -0 1 1 +( 2304 1520 -3344 ) ( 2320 1536 -3344 ) ( 2320 1520 -3344 ) iktkfl03 0 0 0 1 1 +( 2304 1536 -3360 ) ( 2320 1536 -3344 ) ( 2304 1536 -3344 ) iktkfl03 0 0 0 1 1 +( 2320 1520 -3360 ) ( 2320 1536 -3344 ) ( 2320 1536 -3360 ) iktkfl03 0 0 0 1 1 +} +// brush 379 +{ +( 1472 912 -3360 ) ( 1488 912 -3344 ) ( 1488 912 -3360 ) iktkfl03 -0 -0 -0 1 1 +( 1472 1520 -3360 ) ( 1472 1536 -3344 ) ( 1472 1520 -3344 ) iktkfl03 0 0 0 1 1 +( 1472 1520 -3472 ) ( 1488 1536 -3472 ) ( 1472 1536 -3472 ) iktkfl03 -0 -0 -0 1 1 +( 1472 1520 -3344 ) ( 1488 1536 -3344 ) ( 1488 1520 -3344 ) iktkfl03 0 0 0 1 1 +( 1472 1536 -3360 ) ( 1488 1536 -3344 ) ( 1472 1536 -3344 ) iktkfl03 0 0 0 1 1 +( 1488 1520 -3360 ) ( 1488 1536 -3344 ) ( 1488 1536 -3360 ) iktkfl03 0 0 0 1 1 +} +// brush 380 +{ +( 2288 896 -3360 ) ( 2320 896 -3344 ) ( 2320 896 -3360 ) iktkfl03 0 0 0 1 1 +( 1472 896 -3360 ) ( 1472 912 -3344 ) ( 1472 896 -3344 ) iktkfl03 -0 -0 -0 1 1 +( 2288 896 -3472 ) ( 2320 912 -3472 ) ( 2288 912 -3472 ) iktkfl03 -0 -0 -0 1 1 +( 2288 896 -3344 ) ( 2320 912 -3344 ) ( 2320 896 -3344 ) iktkfl03 0 0 0 1 1 +( 2288 912 -3360 ) ( 2320 912 -3344 ) ( 2288 912 -3344 ) iktkfl03 0 0 0 1 1 +( 2320 896 -3360 ) ( 2320 912 -3344 ) ( 2320 912 -3360 ) iktkfl03 -0 -0 -0 1 1 +} +} +// entity 1 +{ +"speed" "200" +"sounds" "1" +"wait" "1" +"lip" "0" +"dmg" "500" +"team_no" "1" +"angle" "271" +"classname" "func_door" +// brush 0 +{ +( -2449 -65535 65535 ) ( -2449 65535 65535 ) ( -2449 65535 -65535 ) adoor03_3 0 0 180 1 1 +( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) adoor03_3 0 0 180 1 1 +( 65535 872 65535 ) ( -65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 +( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) adoor03_3 16 0 180 1 1 +( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) adoor03_3 -15 0 180 1 1 +( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) adoor03_3 -15 0 180 1 1 +} +} +// entity 2 +{ +"speed" "200" +"sounds" "1" +"wait" "1" +"lip" "0" +"dmg" "500" +"team_no" "1" +"angle" "90" +"classname" "func_door" +// brush 0 +{ +( -2448 -65535 65535 ) ( -2448 65535 65535 ) ( -2448 65535 -65535 ) adoor03_3 0 0 180 1 1 +( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) adoor03_3 0 0 180 1 1 +( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) adoor03_3 16 0 180 1 1 +( -65535 872 65535 ) ( 65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 +( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) adoor03_3 -15 0 180 1 1 +( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) adoor03_3 -15 0 180 1 1 +} +} +// entity 3 +{ +"speed" "200" +"sounds" "1" +"wait" "1" +"lip" "0" +"dmg" "500" +"health" "0" +"team_no" "1" +"angle" "90" +"classname" "func_door" +// brush 0 +{ +( -2675 -65535 65535 ) ( -2675 65535 65535 ) ( -2675 65535 -65535 ) adoor03_3 0 0 180 1 1 +( -2687 65535 65535 ) ( -2687 -65535 65535 ) ( -2687 65535 -65535 ) adoor03_3 0 0 180 1 1 +( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) adoor03_3 16 0 180 1 1 +( -65535 872 65535 ) ( 65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 +( 65535 65535 -3201 ) ( 65535 -65535 -3201 ) ( -65535 -65535 -3201 ) adoor03_3 -15 0 180 1 1 +( 65535 -65535 -3329 ) ( 65535 65535 -3329 ) ( -65535 -65535 -3329 ) adoor03_3 -15 0 180 1 1 +} +} +// entity 4 +{ +"speed" "200" +"sounds" "1" +"wait" "1" +"lip" "0" +"dmg" "500" +"health" "0" +"team_no" "1" +"angle" "272" +"classname" "func_door" +// brush 0 +{ +( -2675 -65535 65535 ) ( -2675 65535 65535 ) ( -2675 65535 -65535 ) adoor03_3 0 0 180 1 1 +( -2687 65535 65535 ) ( -2687 -65535 65535 ) ( -2687 65535 -65535 ) adoor03_3 0 0 180 1 1 +( 65535 872 65535 ) ( -65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 +( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) adoor03_3 16 0 180 1 1 +( 65535 65535 -3201 ) ( 65535 -65535 -3201 ) ( -65535 -65535 -3201 ) adoor03_3 -15 0 180 1 1 +( 65535 -65535 -3329 ) ( 65535 65535 -3329 ) ( -65535 -65535 -3329 ) adoor03_3 -15 0 180 1 1 +} +} +// entity 5 +{ +"speed" "200" +"sounds" "1" +"wait" "1" +"lip" "0" +"dmg" "500" +"health" "0" +"team_no" "1" +"angle" "357" +"classname" "func_door" +// brush 0 +{ +( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) adoor03_3 0 0 180 1 1 +( -1304 65535 65535 ) ( -1304 -65535 65535 ) ( -1304 65535 -65535 ) adoor03_3 0 0 180 1 1 +( 65535 1682 65535 ) ( -65535 1682 65535 ) ( -65535 1682 -65535 ) adoor03_3 16 0 180 1 1 +( -65535 1668 65535 ) ( 65535 1668 65535 ) ( -65535 1668 -65535 ) adoor03_3 16 0 180 1 1 +( 65535 65535 -2960 ) ( 65535 -65535 -2960 ) ( -65535 -65535 -2960 ) adoor03_3 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) adoor03_3 -15 0 180 1 1 +} +} +// entity 6 +{ +"speed" "200" +"sounds" "1" +"wait" "1" +"lip" "0" +"dmg" "500" +"health" "0" +"team_no" "1" +"angle" "183" +"classname" "func_door" +// brush 0 +{ +( -1304 -65535 65535 ) ( -1304 65535 65535 ) ( -1304 65535 -65535 ) adoor03_3 0 0 180 1 1 +( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) adoor03_3 0 0 180 1 1 +( 65535 1682 65535 ) ( -65535 1682 65535 ) ( -65535 1682 -65535 ) adoor03_3 16 0 180 1 1 +( -65535 1668 65535 ) ( 65535 1668 65535 ) ( -65535 1668 -65535 ) adoor03_3 16 0 180 1 1 +( 65535 65535 -2960 ) ( 65535 -65535 -2960 ) ( -65535 -65535 -2960 ) adoor03_3 -15 0 180 1 1 +( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) adoor03_3 -15 0 180 1 1 +} +} +// entity 7 +{ +"height" "154" +"classname" "func_plat" +// brush 0 +{ +( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) sfloor4_1 0 0 180 1 1 +( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) sfloor4_1 0 0 180 1 1 +( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -16 0 180 1 1 +( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) sfloor4_1 -16 0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) sfloor4_1 -15 0 180 1 1 +( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 +} +} +// entity 8 +{ +"style" "32" +"delay" "2" +"speed" "100" +"angle" "-1" +"classname" "trigger_push" +// brush 0 +{ +( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) city6_8 0 0 180 1 1 +( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city6_8 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 -16 0 180 1 1 +( -65535 416 65535 ) ( 65535 416 65535 ) ( -65535 416 -65535 ) city6_8 -16 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) city6_8 -15 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 -15 0 180 1 1 +} +} +// entity 9 +{ +"style" "32" +"delay" "2" +"speed" "200" +"angle" "183" +"classname" "trigger_push" +// brush 0 +{ +( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) metal3_2 0 0 180 1 1 +( -2096 65535 65535 ) ( -2096 -65535 65535 ) ( -2096 65535 -65535 ) metal3_2 0 0 180 1 1 +( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal3_2 -16 0 180 1 1 +( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal3_2 -16 0 180 1 1 +( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) metal3_2 -15 0 180 1 1 +( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal3_2 -15 0 180 1 1 +} +} +// entity 10 +{ +"origin" "-2632 1472 -3280" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 11 +{ +"origin" "-2632 1392 -3280" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 12 +{ +"origin" "-1392 2352 -2960" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 13 +{ +"origin" "-1312 2352 -2960" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 14 +{ +"origin" "-1232 2352 -2960" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 15 +{ +"origin" "-1408 2288 -2960" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 16 +{ +"origin" "-1184 2288 -2960" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 17 +{ +"origin" "-608 704 -3168" +"light" "3000" +"classname" "light" +} +// entity 18 +{ +"origin" "-992 528 -3008" +"light" "500" +"classname" "light" +} +// entity 19 +{ +"origin" "-1600 704 -2992" +"light" "500" +"classname" "light" +} +// entity 20 +{ +"origin" "-1168 544 -3088" +"light" "500" +"classname" "light" +} +// entity 21 +{ +"origin" "-1296 1648 -2896" +"light" "500" +"classname" "light" +} +// entity 22 +{ +"origin" "-768 1648 -2896" +"light" "500" +"classname" "light" +} +// entity 23 +{ +"origin" "-1792 1648 -2896" +"light" "400" +"classname" "light" +} +// entity 24 +{ +"origin" "-1904 1456 -3088" +"light" "500" +"classname" "light" +} +// entity 25 +{ +"origin" "-1792 1648 -3216" +"light" "500" +"classname" "light" +} +// entity 26 +{ +"origin" "-2432 608 -3216" +"light" "500" +"classname" "light" +} +// entity 27 +{ +"origin" "-2432 1184 -3216" +"light" "500" +"classname" "light" +} +// entity 28 +{ +"origin" "-1824 1184 -3088" +"light" "500" +"classname" "light" +} +// entity 29 +{ +"origin" "-1824 1184 -3216" +"light" "500" +"classname" "light" +} +// entity 30 +{ +"origin" "-1792 1264 -3088" +"light" "500" +"classname" "light" +} +// entity 31 +{ +"origin" "-2160 1184 -3088" +"light" "500" +"classname" "light" +} +// entity 32 +{ +"origin" "-2656 608 -2896" +"light" "500" +"classname" "light" +} +// entity 33 +{ +"origin" "-2656 1184 -2912" +"light" "500" +"classname" "light" +} +// entity 34 +{ +"origin" "-2704 1536 -2896" +"light" "500" +"classname" "light" +} +// entity 35 +{ +"origin" "-2704 480 -3088" +"light" "500" +"classname" "light" +} +// entity 36 +{ +"origin" "-3648 1008 -2896" +"light" "1000" +"classname" "light" +} +// entity 37 +{ +"origin" "-4016 1536 -3080" +"light" "1000" +"classname" "light" +} +// entity 38 +{ +"origin" "-4016 480 -3080" +"light" "1000" +"classname" "light" +} +// entity 39 +{ +"origin" "-3280 1008 -3248" +"light" "500" +"classname" "light" +} +// entity 40 +{ +"origin" "-2704 480 -3216" +"light" "500" +"classname" "light" +} +// entity 41 +{ +"origin" "-2704 1536 -3088" +"light" "500" +"classname" "light" +} +// entity 42 +{ +"origin" "-2704 880 -3312" +"light" "500" +"classname" "light" +} +// entity 43 +{ +"origin" "-3568 672 -3088" +"light" "500" +"classname" "light" +} +// entity 44 +{ +"origin" "-3568 1344 -3088" +"light" "500" +"classname" "light" +} +// entity 45 +{ +"origin" "-3488 176 -2896" +"light" "1000" +"classname" "light" +} +// entity 46 +{ +"origin" "-3088 272 -3248" +"light" "1000" +"classname" "light" +} +// entity 47 +{ +"origin" "-2768 -208 -3152" +"light" "500" +"classname" "light" +} +// entity 48 +{ +"origin" "-2608 -208 -3152" +"light" "500" +"classname" "light" +} +// entity 49 +{ +"origin" "-1800 -216 -3400" +"light" "150" +"classname" "light" +} +// entity 50 +{ +"origin" "-2624 304 -3552" +"light" "500" +"classname" "light" +} +// entity 51 +{ +"origin" "-1392 416 -2896" +"light" "500" +"classname" "light" +} +// entity 52 +{ +"origin" "-2192 320 -3264" +"light" "500" +"classname" "light" +} +// entity 53 +{ +"origin" "-2128 -16 -2896" +"light" "500" +"classname" "light" +} +// entity 54 +{ +"origin" "-1632 416 -3424" +"light" "150" +"classname" "light" +} +// entity 55 +{ +"origin" "-1392 -16 -2896" +"light" "500" +"classname" "light" +} +// entity 56 +{ +"origin" "-1328 240 -3440" +"light" "200" +"classname" "light" +} +// entity 57 +{ +"origin" "-464 224 -3888" +"light" "500" +"classname" "light" +} +// entity 58 +{ +"origin" "-16 816 -3792" +"light" "500" +"classname" "light" +} +// entity 59 +{ +"origin" "-1296 1872 -2896" +"light" "350" +"classname" "light" +} +// entity 60 +{ +"origin" "-1296 2272 -2896" +"light" "350" +"classname" "light" +} +// entity 61 +{ +"origin" "-2560 992 -3216" +"light" "500" +"classname" "light" +} +// entity 62 +{ +"origin" "-2504 1471 -3280" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 63 +{ +"origin" "-48 1023 -3008" +"classname" "info_intermission" +} +// entity 64 +{ +"origin" "-272 991 -3184" +"classname" "info_player_deathmatch" +} +// entity 65 +{ +"origin" "-2504 1391 -3280" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 66 +{ +"origin" "-1152 2351 -2960" +"team_no" "1" +"classname" "info_player_teamspawn" +} +// entity 67 +{ +"origin" "-3504 1007 -3100" +"g_a" "4789" +"owned_by" "1" +"netname" "Blue Flag" +"message" "You have their flag.\nTake it home!\n" +"noise" "ogre/ogwake.wav" +"n_b" " picked up blue's flag.\n" +"items" "131072" +"noise3" "Your flag returned.\n" +"goal_no" "1" +"noise4" "Their flag returned.\n" +"delay" "60" +"pausetime" "60" +"team_no" "2" +"skin" "1" +"mdl" "progs/tf_flag.mdl" +"angle" "135" +"classname" "item_tfgoal" +"team_broadcast" "Your team got their flag.\n" +"non_team_broadcast" "Your flag has been taken!\n" +"d_n_n" " dropped blue's flag.\n" +} +// entity 68 +{ +"origin" "-272 935 -3184" +"classname" "info_player_start" +} +// entity 69 +{ +"origin" "-208 1280 -3168" +"impulse" "196" +"display_item_status1" "1" +"display_item_status2" "2" +"team_str_home" "Your flag is in your base.\n" +"team_str_moved" "Your flag is lying around." +"team_str_carried" "Your flag is being carried by\n" +"non_team_str_home" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is in their base.\n" +"non_team_str_moved" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is lying around." +"non_team_str_carried" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is being carried by\n" +"hook_out" "1" +"non_team_broadcast" "Get the enemy flag and take it to your tower!\n" +"classname" "info_tfdetect" +} +// entity 70 +{ +"origin" "-2656 1104 -3296" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 71 +{ +"origin" "-2656 1040 -3296" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 72 +{ +"origin" "-2656 976 -3296" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 73 +{ +"origin" "-2480 1104 -3296" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 74 +{ +"origin" "-2480 1040 -3296" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 75 +{ +"origin" "-2480 976 -3296" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 76 +{ +"origin" "-1472 2000 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 77 +{ +"origin" "-1472 1936 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 78 +{ +"origin" "-1472 1872 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 79 +{ +"origin" "-1120 2000 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 80 +{ +"origin" "-1120 1936 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 81 +{ +"origin" "-1120 1872 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 82 +{ +"origin" "-784 1040 -3040" +"frags" "10" +"b_o" "Your flag was captured.\n" +"count" "10" +"b_t" "Your team captured their flag.\n" +"g_e" "19" +"n_b" " captured red's flag.\n" +"noise" "items/cap1.wav" +"axhitme" "2" +"message" "You captured their flag.\n" +"items_allowed" "2" +"owned_by" "2" +"target" "cap1" +"g_a" "1" +"classname" "info_tfgoal" +} +// entity 83 +{ +"origin" "1624 2327 -3400" +"light" "150" +"classname" "light" +} +// entity 84 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "tower" +"_tb_id" "419" +// brush 0 +{ +( 560 -63999 65535 ) ( 560 67071 65535 ) ( 560 67071 -65535 ) wiz1_4 -0 -0 180 1 1 +( 12270 67071 64402 ) ( 12270 -63999 64402 ) ( -10507 67071 -64673 ) wiz1_4 -0 -0 180 1 1 +( 65647 -6579 65032 ) ( -65423 -6579 65032 ) ( -65423 8734 -65140 ) wiz1_4 -16 -0 180 1 1 +( -65423 9336 65069 ) ( 65647 9336 65069 ) ( -65423 -5978 -65102 ) wiz1_4 -16 -0 180 1 1 +( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 +( 65647 -63999 -3408 ) ( 65647 67071 -3408 ) ( -65423 -63999 -3408 ) wiz1_4 -0 -16 270 1 1 +} +// brush 1 +{ +( 560 -63999 65535 ) ( 560 67071 65535 ) ( 560 67071 -65535 ) wiz1_4 -0 -0 -0 1 1 +( -74022 20081 52469 ) ( 18657 -72598 52469 ) ( -20513 73590 -54549 ) wiz1_4 -16 -0 180 1 1 +( -46252 47852 65535 ) ( 46428 -44828 65535 ) ( -46252 47852 -65535 ) wiz1_4 -0 -0 180 1 1 +( -47676 67071 44892 ) ( -47676 -63999 44892 ) ( 45004 67071 -47788 ) wiz1_4 -16 -0 180 1 1 +( 288 67071 65535 ) ( 288 -63999 65535 ) ( 288 67071 -65535 ) wiz1_4 -0 -0 180 1 1 +( 65647 9336 65069 ) ( -65423 9336 65069 ) ( -65423 -5978 -65102 ) wiz1_4 -16 -0 180 1 1 +( 65647 -54508 34077 ) ( 65647 54548 -38626 ) ( -65423 -54508 34077 ) wiz1_4 -16 -0 180 1 1 +( -65423 1216 65535 ) ( 65647 1216 65535 ) ( -65423 1216 -65535 ) wiz1_4 -16 -0 180 1 1 +( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 +} +// brush 2 +{ +( 12270 -63999 64402 ) ( 12270 67071 64402 ) ( -10507 67071 -64673 ) wiz1_4 -0 -0 -0 1 1 +( -47676 67071 44892 ) ( -47676 -63999 44892 ) ( 45004 67071 -47788 ) wiz1_4 -16 -0 180 1 1 +( 288 67071 65535 ) ( 288 -63999 65535 ) ( 288 67071 -65535 ) wiz1_4 -0 -0 180 1 1 +( 65647 -6579 65032 ) ( -65423 -6579 65032 ) ( -65423 8734 -65140 ) wiz1_4 -16 -0 180 1 1 +( -65423 9336 65069 ) ( 65647 9336 65069 ) ( -65423 -5978 -65102 ) wiz1_4 -16 -0 180 1 1 +( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 +} +// brush 3 +{ +( 560 -63999 65535 ) ( 560 67071 65535 ) ( 560 67071 -65535 ) wiz1_4 -0 -0 -0 1 1 +( 18764 75564 52575 ) ( -73916 -17116 52575 ) ( 72273 22055 -54442 ) wiz1_4 -16 -0 180 1 1 +( 46588 47740 65535 ) ( -46092 -44940 65535 ) ( 46588 47740 -65535 ) wiz1_4 -0 -0 180 1 1 +( -47676 67071 44892 ) ( -47676 -63999 44892 ) ( 45004 67071 -47788 ) wiz1_4 -16 -0 180 1 1 +( 288 67071 65535 ) ( 288 -63999 65535 ) ( 288 67071 -65535 ) wiz1_4 -0 -0 180 1 1 +( 65647 -51574 -38479 ) ( 65647 57482 34225 ) ( -65423 -51574 -38479 ) wiz1_4 -16 -0 180 1 1 +( 65647 1536 65535 ) ( -65423 1536 65535 ) ( -65423 1536 -65535 ) wiz1_4 -16 -0 180 1 1 +( -65423 -6579 65032 ) ( 65647 -6579 65032 ) ( -65423 8734 -65140 ) wiz1_4 -16 -0 180 1 1 +( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 +} +} +// entity 85 +{ +"origin" "2944 1231 -3312" +"light" "500" +"classname" "light" +} +// entity 86 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "blue tower" +"_tb_id" "420" +// brush 0 +{ +( 73739 -17772 52575 ) ( -18941 74908 52575 ) ( -72450 21399 -54442 ) wiz1_4 -33 16 180 1 1 +( 45915 -45596 65535 ) ( -46765 47084 65535 ) ( -46765 47084 -65535 ) wiz1_4 -16 -0 180 1 1 +( 47499 -64655 44892 ) ( 47499 66415 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 +( -465 -64655 65535 ) ( -465 66415 65535 ) ( -465 66415 -65535 ) wiz1_4 -16 -0 180 1 1 +( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 16 -0 -0 1 1 +( 65246 -52230 -38479 ) ( 65246 56826 34225 ) ( -65824 -52230 -38479 ) wiz1_4 -33 16 180 1 1 +( 65246 880 65535 ) ( -65824 880 65535 ) ( -65824 880 -65535 ) wiz1_4 -33 -0 180 1 1 +( -65824 -7235 65032 ) ( 65246 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -32.9999 -0 180 1 1 +( 65246 66415 -3056 ) ( 65246 -64655 -3056 ) ( -65824 -64655 -3056 ) mmetal1_8 -48 16 180 1 1 +} +// brush 1 +{ +( -18834 -73254 52469 ) ( 73845 19425 52469 ) ( 20336 72934 -54549 ) wiz1_4 -33 16 180 1 1 +( -46605 -45484 65535 ) ( 46075 47196 65535 ) ( 46075 47196 -65535 ) wiz1_4 -16 -0 180 1 1 +( 47499 -64655 44892 ) ( 47499 66415 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 +( -465 -64655 65535 ) ( -465 66415 65535 ) ( -465 66415 -65535 ) wiz1_4 -16 -0 180 1 1 +( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 16 -0 -0 1 1 +( 65246 -7235 65032 ) ( -65824 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -33 -0 180 1 1 +( 65246 -55164 34077 ) ( 65246 53892 -38626 ) ( -65824 -55164 34077 ) wiz1_4 -32.9999 16 180 1 1 +( -65824 560 65535 ) ( 65246 560 65535 ) ( -65824 560 -65535 ) wiz1_4 -33 -0 180 1 1 +( 65246 66415 -3056 ) ( 65246 -64655 -3056 ) ( -65824 -64655 -3056 ) mmetal1_8 -48 16 180 1 1 +} +// brush 2 +{ +( -12447 -64655 64402 ) ( -12447 66415 64402 ) ( 10330 66415 -64673 ) wiz1_4 -16 -0 180 1 1 +( 47499 66415 44892 ) ( 47499 -64655 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 +( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 -0 16 90 1 1 +( 65246 -7235 65032 ) ( -65824 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -33 -0 180 1 1 +( -65824 8680 65069 ) ( 65246 8680 65069 ) ( -65824 -6634 -65102 ) wiz1_4 -33 -0 180 1 1 +( 65246 -64655 -3408 ) ( 65246 66415 -3408 ) ( -65824 -64655 -3408 ) wiz1_4 -32.9999 16 180 1 1 +} +// brush 3 +{ +( 47499 -64655 44892 ) ( 47499 66415 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 +( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 -0 16 90 1 1 +( 65246 -7235 65032 ) ( -65824 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -33 -0 180 1 1 +( 65246 53892 -38626 ) ( 65246 -55164 34077 ) ( -65824 -55164 34077 ) wiz1_4 -33 16 180 1 1 +( -65824 8680 65069 ) ( 65246 8680 65069 ) ( -65824 -6634 -65102 ) wiz1_4 -33 -0 180 1 1 +} +} +// entity 87 +{ +"origin" "2448 1807 -3552" +"light" "500" +"classname" "light" +} +// entity 88 +{ +"origin" "1232 1583 -3008" +"light" "500" +"classname" "light" +} +// entity 89 +{ +"origin" "2592 2351 -3152" +"light" "500" +"classname" "light" +} +// entity 90 +{ +"origin" "2432 2351 -3152" +"light" "500" +"classname" "light" +} +// entity 91 +{ +"origin" "3312 1935 -2896" +"light" "1000" +"classname" "light" +} +// entity 92 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "ladder" +"_tb_id" "421" +// brush 0 +{ +( -2824 -65527 65535 ) ( -2824 65543 65535 ) ( -2824 65543 -65535 ) clip -23 -0 -0 1 1 +( -2928 65543 65535 ) ( -2928 -65527 65535 ) ( -2928 65543 -65535 ) clip -23 -0 -0 1 1 +( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) clip -16 -0 180 1 1 +( -65535 584 65535 ) ( 65535 584 65535 ) ( -65535 584 -65535 ) clip -16 -0 180 1 1 +( 65535 65543 -3312 ) ( 65535 -65527 -3312 ) ( -65535 -65527 -3312 ) clip -15 -8 180 1 1 +( 65535 -65527 -3320 ) ( 65535 65543 -3320 ) ( -65535 -65527 -3320 ) clip -15 -8 180 1 1 +} +// brush 1 +{ +( -2824 -65528 65551 ) ( -2824 65542 65551 ) ( -2824 65542 -65519 ) clip -22 16 -0 1 1 +( -2928 65542 65551 ) ( -2928 -65528 65551 ) ( -2928 65542 -65519 ) clip -22 16 -0 1 1 +( 65535 591 65551 ) ( -65535 591 65551 ) ( -65535 591 -65519 ) clip -16 -16 180 1 1 +( -65535 583 65551 ) ( 65535 583 65551 ) ( -65535 583 -65519 ) clip -16 -16 180 1 1 +( 65535 65542 -3296 ) ( 65535 -65528 -3296 ) ( -65535 -65528 -3296 ) clip -15 -7 180 1 1 +( 65535 -65528 -3304 ) ( 65535 65542 -3304 ) ( -65535 -65528 -3304 ) clip -15 -7 180 1 1 +} +// brush 2 +{ +( -2824 -65529 65567 ) ( -2824 65541 65567 ) ( -2824 65541 -65503 ) clip -21 32 -0 1 1 +( -2928 65541 65567 ) ( -2928 -65529 65567 ) ( -2928 65541 -65503 ) clip -21 32 -0 1 1 +( 65535 590 65567 ) ( -65535 590 65567 ) ( -65535 590 -65503 ) clip 48 -32 180 1 1 +( -65535 582 65567 ) ( 65535 582 65567 ) ( -65535 582 -65503 ) clip 48 -32 180 1 1 +( 65535 65541 -3280 ) ( 65535 -65529 -3280 ) ( -65535 -65529 -3280 ) clip 49 -6 180 1 1 +( 65535 -65529 -3288 ) ( 65535 65541 -3288 ) ( -65535 -65529 -3288 ) clip 49 -6 180 1 1 +} +// brush 3 +{ +( -2824 -65530 65583 ) ( -2824 65540 65583 ) ( -2824 65540 -65487 ) clip -20 48 -0 1 1 +( -2928 65540 65583 ) ( -2928 -65530 65583 ) ( -2928 65540 -65487 ) clip -20 48 -0 1 1 +( 65535 589 65583 ) ( -65535 589 65583 ) ( -65535 589 -65487 ) clip 48 -48 180 1 1 +( -65535 581 65583 ) ( 65535 581 65583 ) ( -65535 581 -65487 ) clip 48 -48 180 1 1 +( 65535 65540 -3264 ) ( 65535 -65530 -3264 ) ( -65535 -65530 -3264 ) clip 49 -5 180 1 1 +( 65535 -65530 -3272 ) ( 65535 65540 -3272 ) ( -65535 -65530 -3272 ) clip 49 -5 180 1 1 +} +// brush 4 +{ +( -2824 -65531 65599 ) ( -2824 65539 65599 ) ( -2824 65539 -65471 ) clip -19 -0 -0 1 1 +( -2928 65539 65599 ) ( -2928 -65531 65599 ) ( -2928 65539 -65471 ) clip -19 -0 -0 1 1 +( 65535 588 65599 ) ( -65535 588 65599 ) ( -65535 588 -65471 ) clip 48 -0 180 1 1 +( -65535 580 65599 ) ( 65535 580 65599 ) ( -65535 580 -65471 ) clip 48 -0 180 1 1 +( 65535 65539 -3248 ) ( 65535 -65531 -3248 ) ( -65535 -65531 -3248 ) clip 49 -4 180 1 1 +( 65535 -65531 -3256 ) ( 65535 65539 -3256 ) ( -65535 -65531 -3256 ) clip 49 -4 180 1 1 +} +// brush 5 +{ +( -2824 -65532 65615 ) ( -2824 65538 65615 ) ( -2824 65538 -65455 ) clip -18 16 -0 1 1 +( -2928 65538 65615 ) ( -2928 -65532 65615 ) ( -2928 65538 -65455 ) clip -18 16 -0 1 1 +( 65535 587 65615 ) ( -65535 587 65615 ) ( -65535 587 -65455 ) clip 48 -16 180 1 1 +( -65535 579 65615 ) ( 65535 579 65615 ) ( -65535 579 -65455 ) clip 48 -16 180 1 1 +( 65535 65538 -3232 ) ( 65535 -65532 -3232 ) ( -65535 -65532 -3232 ) clip 49 -3 180 1 1 +( 65535 -65532 -3240 ) ( 65535 65538 -3240 ) ( -65535 -65532 -3240 ) clip 49 -3 180 1 1 +} +// brush 6 +{ +( -2824 -65533 65631 ) ( -2824 65537 65631 ) ( -2824 65537 -65439 ) clip -17 32 -0 1 1 +( -2928 65537 65631 ) ( -2928 -65533 65631 ) ( -2928 65537 -65439 ) clip -17 32 -0 1 1 +( 65535 586 65631 ) ( -65535 586 65631 ) ( -65535 586 -65439 ) clip 48 -32 180 1 1 +( -65535 578 65631 ) ( 65535 578 65631 ) ( -65535 578 -65439 ) clip 48 -32 180 1 1 +( 65535 65537 -3216 ) ( 65535 -65533 -3216 ) ( -65535 -65533 -3216 ) clip 49 -2 180 1 1 +( 65535 -65533 -3224 ) ( 65535 65537 -3224 ) ( -65535 -65533 -3224 ) clip 49 -2 180 1 1 +} +// brush 7 +{ +( -2824 -65534 65647 ) ( -2824 65536 65647 ) ( -2824 65536 -65423 ) clip -16 48 -0 1 1 +( -2928 65536 65647 ) ( -2928 -65534 65647 ) ( -2928 65536 -65423 ) clip -16 48 -0 1 1 +( 65535 585 65647 ) ( -65535 585 65647 ) ( -65535 585 -65423 ) clip 48 -48 180 1 1 +( -65535 577 65647 ) ( 65535 577 65647 ) ( -65535 577 -65423 ) clip 48 -48 180 1 1 +( 65535 65536 -3200 ) ( 65535 -65534 -3200 ) ( -65535 -65534 -3200 ) clip 49 -1 180 1 1 +( 65535 -65534 -3208 ) ( 65535 65536 -3208 ) ( -65535 -65534 -3208 ) clip 49 -1 180 1 1 +} +// brush 8 +{ +( -2824 -65535 65663 ) ( -2824 65535 65663 ) ( -2824 65535 -65407 ) clip -15 -0 -0 1 1 +( -2928 65535 65663 ) ( -2928 -65535 65663 ) ( -2928 65535 -65407 ) clip -15 -0 -0 1 1 +( 65535 584 65663 ) ( -65535 584 65663 ) ( -65535 584 -65407 ) clip 48 -0 180 1 1 +( -65535 576 65663 ) ( 65535 576 65663 ) ( -65535 576 -65407 ) clip 48 -0 180 1 1 +( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) clip 49 -0 180 1 1 +( 65535 -65535 -3192 ) ( 65535 65535 -3192 ) ( -65535 -65535 -3192 ) clip 49 -0 180 1 1 +} +} +// entity 93 +{ +"origin" "320 1887 -3888" +"light" "500" +"classname" "light" +} +// entity 94 +{ +"origin" "1184 1871 -3440" +"light" "200" +"classname" "light" +} +// entity 95 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "side" +"_tb_id" "422" +// brush 0 +{ +( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal4_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 32 -16 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 +} +// brush 1 +{ +( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 +( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -16 -0 1 1 +} +// brush 2 +{ +( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 -0 -0 180 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal1_4 -0 48 90 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 -0 48 90 1 1 +} +// brush 3 +{ +( 1584 2272 -3472 ) ( 1584 2416 -3456 ) ( 1584 2416 -3472 ) metal1_4 -0 -0 -0 1 1 +( 1568 2272 -3472 ) ( 1568 2416 -3456 ) ( 1568 2272 -3456 ) metal1_4 -0 -0 -0 1 1 +( 1568 2432 -3472 ) ( 1584 2432 -3456 ) ( 1568 2432 -3456 ) metal1_4 32 -0 -0 1 1 +( 1568 2272 -3472 ) ( 1584 2272 -3456 ) ( 1584 2272 -3472 ) metal1_4 32 -0 -0 1 1 +( 1568 2272 -3344 ) ( 1584 2416 -3344 ) ( 1584 2272 -3344 ) metal1_4 32 -0 -0 1 1 +( 1568 2272 -3472 ) ( 1584 2416 -3472 ) ( 1568 2416 -3472 ) metal1_4 32 -0 -0 1 1 +} +// brush 4 +{ +( 3040 2416 -3472 ) ( 3040 2432 -3456 ) ( 3040 2432 -3472 ) metal1_4 -0 -0 -0 1 1 +( 1584 2416 -3472 ) ( 1584 2432 -3456 ) ( 1584 2416 -3456 ) metal1_4 -0 -0 -0 1 1 +( 1584 2432 -3472 ) ( 1712 2432 -3456 ) ( 1584 2432 -3456 ) metal1_4 32 -0 -0 1 1 +( 1584 2416 -3472 ) ( 1712 2416 -3456 ) ( 1712 2416 -3472 ) metal1_4 32 -0 -0 1 1 +( 1584 2416 -3120 ) ( 1712 2432 -3120 ) ( 1712 2416 -3120 ) metal1_4 32 -0 -0 1 1 +( 1584 2416 -3472 ) ( 1712 2432 -3472 ) ( 1584 2432 -3472 ) metal1_4 32 -0 -0 1 1 +} +// brush 5 +{ +( 1904 -63119 65535 ) ( 1904 67951 65535 ) ( 1904 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 1680 67951 65535 ) ( 1680 -63119 65535 ) ( 1680 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) metal1_4 32 -16 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 +} +// brush 6 +{ +( 1680 -63119 65535 ) ( 1680 67951 65535 ) ( 1680 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3360 ) ( 65359 67951 -3360 ) ( -65711 -63119 -3360 ) metal1_4 32 -0 -0 1 1 +} +// brush 7 +{ +( 1680 -63119 65535 ) ( 1680 67951 65535 ) ( 1680 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal4_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) metal4_4 32 -16 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 +} +// brush 8 +{ +( 1680 -63119 65535 ) ( 1680 67951 65535 ) ( 1680 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 1664 67951 65535 ) ( 1664 -63119 65535 ) ( 1664 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 +( 65359 67951 -3360 ) ( 65359 -63119 -3360 ) ( -65711 -63119 -3360 ) metal1_4 -0 48 90 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 -0 48 90 1 1 +} +// brush 9 +{ +( 1904 -63119 65535 ) ( 1904 67951 65535 ) ( 1904 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal4_4 32 -0 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal4_4 32 -16 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) metal4_4 32 -16 -0 1 1 +} +// brush 10 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 32 -16 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal4_4 32 -16 -0 1 1 +} +// brush 11 +{ +( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 1968 67951 65535 ) ( 1968 -63119 65535 ) ( 1968 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 -0 -0 180 1 1 +( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 -0 48 90 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal4_4 -0 48 90 1 1 +} +} +// entity 96 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "test" +"_tb_id" "423" +"_tb_group" "422" +// brush 0 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 32 -0 -0 1 1 +( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 32 -16 -0 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) metal4_4 32 -16 -0 1 1 +} +// brush 1 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 32 -0 -0 1 1 +( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal4_4 32 -16 -0 1 1 +} +// brush 2 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 3328 67951 65535 ) ( 3328 -63119 65535 ) ( 3328 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 -0 -0 180 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal4_4 -0 -0 180 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 -0 48 90 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) metal4_4 -0 48 90 1 1 +} +} +// entity 97 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "test" +"_tb_id" "424" +"_tb_group" "423" +// brush 0 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal1_4 32 -0 -0 1 1 +} +// brush 1 +{ +( 60213 -63118 25762 ) ( 60213 67950 25762 ) ( -57019 -63118 -32853 ) metal1_4 32 -0 -0 1 1 +( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3360 ) ( 65359 67951 -3360 ) ( -65711 -63119 -3360 ) metal1_4 32 -0 -0 1 1 +} +// brush 2 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -0 -0 1 1 +} +// brush 3 +{ +( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 60251 67950 25685 ) ( 60251 -63118 25685 ) ( -56981 -63118 -32930 ) metal1_4 32 -0 -0 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3296 ) ( 65359 -63119 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -0 -0 1 1 +} +// brush 4 +{ +( 57704 67950 -30780 ) ( 57704 -63118 -30780 ) ( -59528 -63118 27836 ) metal1_4 32 -0 -0 1 1 +( 60251 67950 25685 ) ( 60251 -63118 25685 ) ( -56981 -63118 -32930 ) metal1_4 32 -0 -0 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3232 ) ( 65359 -63119 -3232 ) ( -65711 -63119 -3232 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3296 ) ( 65359 67951 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 +} +} +// entity 98 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "wdrop" +"_tb_id" "425" +// brush 0 +{ +( 2976 -63119 65535 ) ( 2976 67951 65535 ) ( 2976 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3296 ) ( 65359 -63119 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -0 -0 1 1 +} +// brush 1 +{ +( 53786 67951 -37201 ) ( 53786 -63119 -37201 ) ( -55270 -63119 35503 ) metal1_4 32 -0 -0 1 1 +( 2880 67951 65535 ) ( 2880 -63119 65535 ) ( 2880 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 -63119 -3296 ) ( 65359 67951 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 +} +// brush 2 +{ +( 2880 -63119 65535 ) ( 2880 67951 65535 ) ( 2880 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 -0 -0 180 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_4 -0 48 90 1 1 +( 65359 -63119 -3296 ) ( 65359 67951 -3296 ) ( -65711 -63119 -3296 ) metal1_4 -0 48 90 1 1 +} +// brush 3 +{ +( 56784 -63119 32704 ) ( 56784 67951 32704 ) ( -52272 -63119 -40000 ) metal1_4 32 -0 -0 1 1 +( 2880 67951 65535 ) ( 2880 -63119 65535 ) ( 2880 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -0 -0 1 1 +} +// brush 4 +{ +( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 2864 67951 65535 ) ( 2864 -63119 65535 ) ( 2864 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -0 -0 1 1 +} +// brush 5 +{ +( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -32 -0 180 1 1 +( 2976 67951 65535 ) ( 2976 -63119 65535 ) ( 2976 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -0 -0 1 1 +( -65711 1984 65535 ) ( 65359 1984 65535 ) ( -65711 1984 -65535 ) metal1_4 32 -0 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -16 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -16 -0 1 1 +} +// brush 6 +{ +( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -32 -48 180 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -0 -0 1 1 +} +// brush 7 +{ +( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 2976 67951 65535 ) ( 2976 -63119 65535 ) ( 2976 67951 -65535 ) metal1_4 -0 -0 -0 1 1 +( 65359 1984 65535 ) ( -65711 1984 65535 ) ( -65711 1984 -65535 ) metal1_4 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 +( 65359 67951 -3280 ) ( 65359 -63119 -3280 ) ( -65711 -63119 -3280 ) metal1_4 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -0 -0 1 1 +} +// brush 8 +{ +( -46580 -63119 46276 ) ( -46580 67951 46276 ) ( 46100 67951 -46404 ) sfloor4_6 32 -0 -0 1 1 +( 2992 67951 65535 ) ( 2992 -63119 65535 ) ( 2992 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +// brush 9 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) metal4_4 -32 -0 180 1 1 +( 2992 67951 65535 ) ( 2992 -63119 65535 ) ( 2992 67951 -65535 ) metal4_4 -0 -0 -0 1 1 +( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 32 -0 -0 1 1 +( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal4_4 32 -16 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 +} +// brush 10 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) *water2 -32 -48 180 1 1 +( -46580 67951 46276 ) ( -46580 -63119 46276 ) ( 46100 67951 -46404 ) *water2 32 -0 -0 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) *water2 32 -48 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) *water2 32 -48 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 +} +} +// entity 99 +{ +"origin" "2912 1839 -3248" +"light" "1000" +"classname" "light" +"_tb_group" "425" +} +// entity 100 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "fs" +"_tb_id" "426" +// brush 0 +{ +( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 32 -0 180 1 1 +( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) metal5r8 32 -0 180 1 1 +( 65359 -51019 -37991 ) ( 65359 58037 34712 ) ( -65711 -51019 -37991 ) metal5r8 32 48 -0 1 1 +( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal5r8 32 48 -0 1 1 +} +// brush 1 +{ +( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 -0 -0 180 1 1 +( 65359 1264 65535 ) ( -65711 1264 65535 ) ( -65711 1264 -65535 ) metal5r8 -0 -0 -0 1 1 +( 65434 67950 -874 ) ( 65434 -63118 -874 ) ( -65548 67950 -5649 ) metal5r8 -0 48 -0 1 1 +( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 -0 32 -0 1 1 +} +// brush 2 +{ +( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 -0 -16 180 1 1 +( -45308 49964 65535 ) ( 47372 -42716 65535 ) ( -45308 49964 -65535 ) metal5r8 -0 -16 180 1 1 +( 65359 1264 65535 ) ( -65711 1264 65535 ) ( -65711 1264 -65535 ) metal5r8 32 -0 -0 1 1 +( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 -0 32 -0 1 1 +( 65434 -63118 -874 ) ( 65434 67950 -874 ) ( -65548 67950 -5649 ) metal5r8 -0 32 -0 1 1 +} +// brush 3 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal5r8 32 -48 180 1 1 +( 2640 67951 65535 ) ( 2640 -63119 65535 ) ( 2640 67951 -65535 ) metal5r8 32 -48 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 +( -65711 1536 65535 ) ( 65359 1536 65535 ) ( -65711 1536 -65535 ) metal5r8 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 +} +// brush 4 +{ +( 2760 -63119 65535 ) ( 2760 67951 65535 ) ( 2760 67951 -65535 ) metal1_3 -0 -0 -0 1 1 +( 2752 67951 65535 ) ( 2752 -63119 65535 ) ( 2752 67951 -65535 ) metal1_3 -0 -0 -0 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) metal1_3 32 -0 -0 1 1 +} +// brush 5 +{ +( 2648 -63119 65535 ) ( 2648 67951 65535 ) ( 2648 67951 -65535 ) metal1_3 -0 -0 -0 1 1 +( 2640 67951 65535 ) ( 2640 -63119 65535 ) ( 2640 67951 -65535 ) metal1_3 -0 -0 -0 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 +( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_3 32 -0 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) metal1_3 32 -0 -0 1 1 +} +} +// entity 101 +{ +"origin" "3840 575 -3080" +"light" "1000" +"classname" "light" +"_tb_group" "426" +} +// entity 102 +{ +"origin" "3840 1631 -3080" +"light" "1000" +"classname" "light" +"_tb_group" "426" +} +// entity 103 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "ladder" +"_tb_id" "427" +"_tb_group" "426" +// brush 0 +{ +( 2752 66487 -72055 ) ( 2752 -64583 -72055 ) ( 2752 66487 59015 ) clip -7 -8 -0 1 -1 +( 2648 -64583 -72055 ) ( 2648 66487 -72055 ) ( 2648 66487 59015 ) clip -7 -8 -0 1 -1 +( -65711 1536 -72055 ) ( 65359 1536 -72055 ) ( 65359 1536 59015 ) clip 32 8 -0 1 1 +( 65359 1528 -72055 ) ( -65711 1528 -72055 ) ( 65359 1528 59015 ) clip 32 8 -0 1 1 +( -65711 -64583 -3200 ) ( -65711 66487 -3200 ) ( 65359 -64583 -3200 ) clip 33 -56 -0 1 -1 +( -65711 66487 -3208 ) ( -65711 -64583 -3208 ) ( 65359 -64583 -3208 ) clip 33 -56 -0 1 -1 +} +// brush 1 +{ +( 2752 66486 -72071 ) ( 2752 -64584 -72071 ) ( 2752 66486 58999 ) clip -6 -56 -0 1 -1 +( 2648 -64584 -72071 ) ( 2648 66486 -72071 ) ( 2648 66486 58999 ) clip -6 -56 -0 1 -1 +( -65711 1535 -72071 ) ( 65359 1535 -72071 ) ( 65359 1535 58999 ) clip 32 56 -0 1 1 +( 65359 1527 -72071 ) ( -65711 1527 -72071 ) ( 65359 1527 58999 ) clip 32 56 -0 1 1 +( -65711 -64584 -3216 ) ( -65711 66486 -3216 ) ( 65359 -64584 -3216 ) clip 33 -55 -0 1 -1 +( -65711 66486 -3224 ) ( -65711 -64584 -3224 ) ( 65359 -64584 -3224 ) clip 33 -55 -0 1 -1 +} +// brush 2 +{ +( 2752 66485 -72087 ) ( 2752 -64585 -72087 ) ( 2752 66485 58983 ) clip -5 -40 -0 1 -1 +( 2648 -64585 -72087 ) ( 2648 66485 -72087 ) ( 2648 66485 58983 ) clip -5 -40 -0 1 -1 +( -65711 1534 -72087 ) ( 65359 1534 -72087 ) ( 65359 1534 58983 ) clip 32 40 -0 1 1 +( 65359 1526 -72087 ) ( -65711 1526 -72087 ) ( 65359 1526 58983 ) clip 32 40 -0 1 1 +( -65711 -64585 -3232 ) ( -65711 66485 -3232 ) ( 65359 -64585 -3232 ) clip 33 -54 -0 1 -1 +( -65711 66485 -3240 ) ( -65711 -64585 -3240 ) ( 65359 -64585 -3240 ) clip 33 -54 -0 1 -1 +} +// brush 3 +{ +( 2752 66484 -72103 ) ( 2752 -64586 -72103 ) ( 2752 66484 58967 ) clip -4 -24 -0 1 -1 +( 2648 -64586 -72103 ) ( 2648 66484 -72103 ) ( 2648 66484 58967 ) clip -4 -24 -0 1 -1 +( -65711 1533 -72103 ) ( 65359 1533 -72103 ) ( 65359 1533 58967 ) clip 32 24 -0 1 1 +( 65359 1525 -72103 ) ( -65711 1525 -72103 ) ( 65359 1525 58967 ) clip 32 24 -0 1 1 +( -65711 -64586 -3248 ) ( -65711 66484 -3248 ) ( 65359 -64586 -3248 ) clip 33 -53 -0 1 -1 +( -65711 66484 -3256 ) ( -65711 -64586 -3256 ) ( 65359 -64586 -3256 ) clip 33 -53 -0 1 -1 +} +// brush 4 +{ +( 2752 66483 -72119 ) ( 2752 -64587 -72119 ) ( 2752 66483 58951 ) clip -3 -8 -0 1 -1 +( 2648 -64587 -72119 ) ( 2648 66483 -72119 ) ( 2648 66483 58951 ) clip -3 -8 -0 1 -1 +( -65711 1532 -72119 ) ( 65359 1532 -72119 ) ( 65359 1532 58951 ) clip 32 8 -0 1 1 +( 65359 1524 -72119 ) ( -65711 1524 -72119 ) ( 65359 1524 58951 ) clip 32 8 -0 1 1 +( -65711 -64587 -3264 ) ( -65711 66483 -3264 ) ( 65359 -64587 -3264 ) clip 33 -52 -0 1 -1 +( -65711 66483 -3272 ) ( -65711 -64587 -3272 ) ( 65359 -64587 -3272 ) clip 33 -52 -0 1 -1 +} +// brush 5 +{ +( 2752 66482 -72135 ) ( 2752 -64588 -72135 ) ( 2752 66482 58935 ) clip -2 -56 -0 1 -1 +( 2648 -64588 -72135 ) ( 2648 66482 -72135 ) ( 2648 66482 58935 ) clip -2 -56 -0 1 -1 +( -65711 1531 -72135 ) ( 65359 1531 -72135 ) ( 65359 1531 58935 ) clip 32 56 -0 1 1 +( 65359 1523 -72135 ) ( -65711 1523 -72135 ) ( 65359 1523 58935 ) clip 32 56 -0 1 1 +( -65711 -64588 -3280 ) ( -65711 66482 -3280 ) ( 65359 -64588 -3280 ) clip 33 -51 -0 1 -1 +( -65711 66482 -3288 ) ( -65711 -64588 -3288 ) ( 65359 -64588 -3288 ) clip 33 -51 -0 1 -1 +} +// brush 6 +{ +( 2752 66481 -72151 ) ( 2752 -64589 -72151 ) ( 2752 66481 58919 ) clip -1 -40 -0 1 -1 +( 2648 -64589 -72151 ) ( 2648 66481 -72151 ) ( 2648 66481 58919 ) clip -1 -40 -0 1 -1 +( -65711 1530 -72151 ) ( 65359 1530 -72151 ) ( 65359 1530 58919 ) clip 32 40 -0 1 1 +( 65359 1522 -72151 ) ( -65711 1522 -72151 ) ( 65359 1522 58919 ) clip 32 40 -0 1 1 +( -65711 -64589 -3296 ) ( -65711 66481 -3296 ) ( 65359 -64589 -3296 ) clip 33 -50 -0 1 -1 +( -65711 66481 -3304 ) ( -65711 -64589 -3304 ) ( 65359 -64589 -3304 ) clip 33 -50 -0 1 -1 +} +// brush 7 +{ +( 2752 66480 -72167 ) ( 2752 -64590 -72167 ) ( 2752 66480 58903 ) clip -0 -24 -0 1 -1 +( 2648 -64590 -72167 ) ( 2648 66480 -72167 ) ( 2648 66480 58903 ) clip -0 -24 -0 1 -1 +( -65711 1529 -72167 ) ( 65359 1529 -72167 ) ( 65359 1529 58903 ) clip 32 24 -0 1 1 +( 65359 1521 -72167 ) ( -65711 1521 -72167 ) ( 65359 1521 58903 ) clip 32 24 -0 1 1 +( -65711 -64590 -3312 ) ( -65711 66480 -3312 ) ( 65359 -64590 -3312 ) clip 33 -49 -0 1 -1 +( -65711 66480 -3320 ) ( -65711 -64590 -3320 ) ( 65359 -64590 -3320 ) clip 33 -49 -0 1 -1 +} +// brush 8 +{ +( 2752 66479 -72183 ) ( 2752 -64591 -72183 ) ( 2752 66479 58887 ) clip -63 -8 -0 1 -1 +( 2648 -64591 -72183 ) ( 2648 66479 -72183 ) ( 2648 66479 58887 ) clip -63 -8 -0 1 -1 +( -65711 1528 -72183 ) ( 65359 1528 -72183 ) ( 65359 1528 58887 ) clip 32 8 -0 1 1 +( 65359 1520 -72183 ) ( -65711 1520 -72183 ) ( 65359 1520 58887 ) clip 32 8 -0 1 1 +( -65711 -64591 -3328 ) ( -65711 66479 -3328 ) ( 65359 -64591 -3328 ) clip 33 -48 -0 1 -1 +( -65711 66479 -3336 ) ( -65711 -64591 -3336 ) ( 65359 -64591 -3336 ) clip 33 -48 -0 1 -1 +} +} +// entity 104 +{ +"origin" "2528 1631 -3216" +"light" "500" +"classname" "light" +} +// entity 105 +{ +"origin" "1216 1695 -2896" +"light" "500" +"classname" "light" +} +// entity 106 +{ +"speed" "100" +"delay" "2" +"style" "32" +"angle" "-1" +"classname" "trigger_push" +// brush 0 +{ +( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city6_8 -0 -0 -0 1 1 +( 1424 67951 65535 ) ( 1424 -63119 65535 ) ( 1424 67951 -65535 ) city6_8 -0 -0 -0 1 1 +( 65359 1696 65535 ) ( -65711 1696 65535 ) ( -65711 1696 -65535 ) city6_8 32 -0 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) city6_8 32 -0 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) city6_8 32 -0 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -0 -0 1 1 +} +} +// entity 107 +{ +"origin" "1456 1695 -3424" +"light" "150" +"classname" "light" +} +// entity 108 +{ +"origin" "1216 2127 -2896" +"light" "500" +"classname" "light" +} +// entity 109 +{ +"speed" "200" +"delay" "2" +"style" "32" +"angle" "360" +"classname" "trigger_push" +// brush 0 +{ +( 1920 -63119 65535 ) ( 1920 67951 65535 ) ( 1920 67951 -65535 ) metal3_2 -0 -0 -0 1 1 +( 1888 67951 65535 ) ( 1888 -63119 65535 ) ( 1888 67951 -65535 ) metal3_2 -0 -0 -0 1 1 +( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) metal3_2 32 -0 -0 1 1 +( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal3_2 32 -0 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) metal3_2 32 -0 -0 1 1 +( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal3_2 32 -0 -0 1 1 +} +} +// entity 110 +{ +"origin" "1952 2127 -2896" +"light" "500" +"classname" "light" +} +// entity 111 +{ +"origin" "2016 1791 -3264" +"light" "500" +"classname" "light" +} +// entity 112 +{ +"origin" "3104 1103 -3248" +"light" "500" +"classname" "light" +} +// entity 113 +{ +"origin" "3392 767 -3088" +"light" "500" +"classname" "light" +} +// entity 114 +{ +"origin" "3328 1103 -3100" +"g_a" "4789" +"owned_by" "2" +"message" "You have their flag.\nTake it home!\n" +"netname" "Red Flag" +"noise" "ogre/ogwake.wav" +"goal_no" "2" +"noise3" "Your flag returned.\n" +"items" "262144" +"delay" "60" +"noise4" "Their flag returned.\n" +"team_no" "1" +"pausetime" "60" +"skin" "2" +"mdl" "progs/tf_flag.mdl" +"angle" "315" +"classname" "item_tfgoal" +"team_broadcast" "Your team got their flag.\n" +"non_team_broadcast" "Your flag was taken.\n" +"n_b" " picked up red's flag.\n" +"d_n_n" " dropped red's flag.\n" +} +// entity 115 +{ +"origin" "3472 1103 -2896" +"light" "1000" +"classname" "light" +} +// entity 116 +{ +"origin" "3392 1439 -3088" +"light" "500" +"classname" "light" +} +// entity 117 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "flag" +"_tb_id" "428" +// brush 0 +{ +( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 1424 65535 ) ( -65711 1424 65535 ) ( -65711 1424 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1408 65535 ) ( 65359 1408 65535 ) ( -65711 1408 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 +} +// brush 1 +{ +( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2624 67951 65535 ) ( 2624 -63119 65535 ) ( 2624 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1424 65535 ) ( 65359 1424 65535 ) ( -65711 1424 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 -0 48 90 1 1 +} +// brush 2 +{ +( 48395 -41606 65535 ) ( -46629 48667 65535 ) ( -46629 48667 -65535 ) metal5r8 32 -0 -0 1 1 +( 64818 -63119 9194 ) ( 64818 67951 9194 ) ( -63706 -63119 -16510 ) metal5r8 32 -0 -0 1 1 +( 2640 67951 65535 ) ( 2640 -63119 65535 ) ( 2640 67951 -65535 ) metal5r8 32 -48 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 +( -65711 1536 65535 ) ( 65359 1536 65535 ) ( -65711 1536 -65535 ) metal5r8 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 -0 -0 1 1 +} +// brush 3 +{ +( 3200 -63119 65535 ) ( 3200 67951 65535 ) ( 3200 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) city4_7 -0 48 90 1 1 +} +// brush 4 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) city4_7 32 -0 180 1 1 +( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 +} +// brush 5 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) city4_7 32 -48 180 1 1 +( 3200 67951 65535 ) ( 3200 -63119 65535 ) ( 3200 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) city4_7 32 -0 -0 1 1 +} +// brush 6 +{ +( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) *water2 32 -48 180 1 1 +( 3200 67951 65535 ) ( 3200 -63119 65535 ) ( 3200 67951 -65535 ) *water2 32 -48 180 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) *water2 32 -48 -0 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) *water2 32 -48 -0 1 1 +( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 +} +// brush 7 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 3328 67951 65535 ) ( 3328 -63119 65535 ) ( 3328 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) city4_7 -0 48 90 1 1 +} +// brush 8 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) sfloor4_6 32 -48 180 1 1 +( 52917 -63119 -38432 ) ( 52917 67951 -38432 ) ( -54459 -63119 36731 ) sfloor4_6 32 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 32 -48 -0 1 1 +( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) sfloor4_6 32 -48 -0 1 1 +( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) sfloor4_6 32 -0 -0 1 1 +} +} +// entity 118 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "flag" +"_tb_id" "429" +"_tb_group" "428" +// brush 0 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 +} +// brush 1 +{ +( 2624 -63119 65535 ) ( 2624 67951 65535 ) ( 2624 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 32 -48 180 1 1 +( 65359 1008 65535 ) ( -65711 1008 65535 ) ( -65711 1008 -65535 ) metal5r8 32 -48 -0 1 1 +( -65711 672 65535 ) ( 65359 672 65535 ) ( -65711 672 -65535 ) metal5r8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 +} +// brush 2 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 +} +// brush 3 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1424 65535 ) ( -65711 1424 65535 ) ( -65711 1424 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 +} +// brush 4 +{ +( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 32 -48 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 +( -65711 1408 65535 ) ( 65359 1408 65535 ) ( -65711 1408 -65535 ) metal5r8 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 -0 -0 1 1 +} +// brush 5 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 +} +// brush 6 +{ +( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 -0 -0 180 1 1 +( -65711 1408 65535 ) ( 65359 1408 65535 ) ( -65711 1408 -65535 ) metal5r8 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 +} +// brush 7 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -48 -0 1 1 +( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -48 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 8 +{ +( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1008 65535 ) ( 65359 1008 65535 ) ( -65711 1008 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 +} +// brush 9 +{ +( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2624 67951 65535 ) ( 2624 -63119 65535 ) ( 2624 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1008 65535 ) ( -65711 1008 65535 ) ( -65711 1008 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 816 65535 ) ( 65359 816 65535 ) ( -65711 816 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 10 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 32 -0 180 1 1 +( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 560 65535 ) ( -65711 560 65535 ) ( -65711 560 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 +} +// brush 11 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal5r8 32 -16 180 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 32 -16 180 1 1 +( 65359 672 65535 ) ( -65711 672 65535 ) ( -65711 672 -65535 ) metal5r8 32 -0 -0 1 1 +( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) metal5r8 32 -16 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 32 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 32 -0 1 1 +} +// brush 12 +{ +( 2528 -63119 65535 ) ( 2528 67951 65535 ) ( 2528 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) city4_7 32 -48 180 1 1 +( 65359 1344 65535 ) ( -65711 1344 65535 ) ( -65711 1344 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1136 65535 ) ( 65359 1136 65535 ) ( -65711 1136 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +// brush 13 +{ +( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) city4_7 32 -0 180 1 1 +( 65359 1024 65535 ) ( -65711 1024 65535 ) ( -65711 1024 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 1008 65535 ) ( 65359 1008 65535 ) ( -65711 1008 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 +} +} +// entity 119 +{ +"origin" "2256 927 -3216" +"light" "500" +"classname" "light" +"_tb_group" "429" +} +// entity 120 +{ +"origin" "2528 575 -3088" +"light" "500" +"classname" "light" +"_tb_group" "429" +} +// entity 121 +{ +"team_no" "2" +"health" "0" +"dmg" "500" +"lip" "0" +"wait" "1" +"sounds" "1" +"speed" "200" +"angle" "90" +"classname" "func_door" +"_tb_group" "429" +// brush 0 +{ +( 2511 -63119 65535 ) ( 2511 67951 65535 ) ( 2511 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 2497 67951 65535 ) ( 2497 -63119 65535 ) ( 2497 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) adoor03_3 -0 -0 -0 1 1 +( -65711 1240 65535 ) ( 65359 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 +} +} +// entity 122 +{ +"team_no" "2" +"health" "0" +"dmg" "500" +"lip" "0" +"wait" "1" +"sounds" "1" +"speed" "200" +"angle" "270" +"classname" "func_door" +"_tb_group" "429" +// brush 0 +{ +( 2511 -63119 65535 ) ( 2511 67951 65535 ) ( 2511 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 2497 67951 65535 ) ( 2497 -63119 65535 ) ( 2497 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 1240 65535 ) ( -65711 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 +( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 +} +} +// entity 123 +{ +"origin" "2528 575 -2896" +"light" "500" +"classname" "light" +"_tb_group" "429" +} +// entity 124 +{ +"origin" "2528 1631 -3088" +"light" "500" +"classname" "light" +"_tb_group" "428" +} +// entity 125 +{ +"origin" "592 463 -2896" +"light" "500" +"classname" "light" +} +// entity 126 +{ +"origin" "992 1567 -3088" +"light" "500" +"classname" "light" +} +// entity 127 +{ +"origin" "1424 1407 -2992" +"light" "500" +"classname" "light" +} +// entity 128 +{ +"origin" "1616 463 -2896" +"light" "400" +"classname" "light" +} +// entity 129 +{ +"origin" "1120 463 -2896" +"light" "500" +"classname" "light" +} +// entity 130 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "frontred" +"_tb_id" "430" +// brush 0 +{ +( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 +( 65359 1424 65535 ) ( -65711 1424 65535 ) ( -65711 1424 -65535 ) mmetal1_8 32 -48 -0 1 1 +( -65711 672 65535 ) ( 65359 672 65535 ) ( -65711 672 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3071 ) ( 65359 67951 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 1 +{ +( 576 -63119 65535 ) ( 576 67951 65535 ) ( 576 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 672 65535 ) ( -65711 672 65535 ) ( -65711 672 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 -0 -0 180 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 2 +{ +( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 672 65535 ) ( -65711 672 65535 ) ( -65711 672 -65535 ) mmetal1_8 32 -48 -0 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3071 ) ( 65359 67951 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 3 +{ +( 640 -64319 65535 ) ( 640 66751 65535 ) ( 640 66751 -65535 ) ecop1_1 -0 -0 -0 1 1 +( 576 66751 65535 ) ( 576 -64319 65535 ) ( 576 66751 -65535 ) ecop1_1 -0 -0 -0 1 1 +( 65871 1088 65535 ) ( -65199 1088 65535 ) ( -65199 1088 -65535 ) ecop1_1 48 -0 -0 1 1 +( -65199 1024 65535 ) ( 65871 1024 65535 ) ( -65199 1024 -65535 ) ecop1_1 48 -0 -0 1 1 +( 65871 66751 -3052 ) ( 65871 -64319 -3052 ) ( -65199 -64319 -3052 ) ecop1_1 48 -0 -0 1 1 +( 65871 -64319 -3056 ) ( 65871 66751 -3056 ) ( -65199 -64319 -3056 ) ecop1_1 48 -0 -0 1 1 +} +// brush 4 +{ +( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) mmetal1_8 32 -48 -0 1 1 +( -65711 1424 65535 ) ( 65359 1424 65535 ) ( -65711 1424 -65535 ) mmetal1_8 32 -48 -0 1 1 +( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 +( 65359 -63119 -3071 ) ( 65359 67951 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 32 -0 -0 1 1 +} +// brush 5 +{ +( 576 -63119 65535 ) ( 576 67951 65535 ) ( 576 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 -0 -0 180 1 1 +( -65711 1424 65535 ) ( 65359 1424 65535 ) ( -65711 1424 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +// brush 6 +{ +( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city6_3 -0 -0 -0 1 1 +( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city6_3 -0 -0 -0 1 1 +( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city6_3 -0 -0 180 1 1 +( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city6_3 -0 -0 180 1 1 +( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city6_3 32 -0 -0 1 1 +( 65359 -63119 -2880 ) ( 65359 67951 -2880 ) ( -65711 -63119 -2880 ) city6_3 32 -0 -0 1 1 +} +// brush 7 +{ +( 576 928 -2864 ) ( 576 1024 -2848 ) ( 576 1024 -2864 ) sky1 -0 -0 -0 1 1 +( 560 928 -2864 ) ( 560 1024 -2848 ) ( 560 928 -2848 ) sky1 -0 -0 -0 1 1 +( 560 1664 -2864 ) ( 576 1664 -2848 ) ( 560 1664 -2848 ) sky1 160 -0 -0 1 1 +( 560 448 -2864 ) ( 576 448 -2848 ) ( 576 448 -2864 ) sky1 160 -0 -0 1 1 +( 560 928 -2576 ) ( 576 1024 -2576 ) ( 576 928 -2576 ) sky1 160 -0 -0 1 1 +( 560 928 -2864 ) ( 576 1024 -2864 ) ( 560 1024 -2864 ) sky1 160 -0 -0 1 1 +} +// brush 8 +{ +( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 704 67951 65535 ) ( 704 -63119 65535 ) ( 704 67951 -65535 ) city4_7 -0 -0 -0 1 1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -0 -0 1 1 +( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 +( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 +} +} +// entity 131 +{ +"origin" "608 1056 -3040" +"frags" "10" +"b_o" "Your flag was captured.\n" +"count" "10" +"b_t" "Your team captured their flag.\n" +"g_e" "19" +"n_b" " captured blue's flag.\n" +"noise" "items/cap2.wav" +"axhitme" "1" +"message" "You captured their flag.\n" +"items_allowed" "1" +"owned_by" "1" +"target" "cap2" +"g_a" "1" +"classname" "info_tfgoal" +"_tb_group" "430" +} +// entity 132 +{ +"origin" "1504 879 -2960" +"light" "200" +"classname" "light" +} +// entity 133 +{ +"origin" "-1680 1231 -2960" +"light" "200" +"classname" "light" +} +// entity 134 +{ +"origin" "800 607 -3200" +"light" "250" +"classname" "light" +} +// entity 135 +{ +"origin" "1152 639 -3200" +"light" "250" +"classname" "light" +} +// entity 136 +{ +"origin" "-1328 1473 -3200" +"light" "250" +"classname" "light" +"angle" "180" +} +// entity 137 +{ +"origin" "-976 1505 -3200" +"light" "250" +"classname" "light" +"angle" "180" +} +// entity 138 +{ +"origin" "1648 927 -3216" +"light" "500" +"classname" "light" +} +// entity 139 +{ +"origin" "1616 463 -3216" +"light" "500" +"classname" "light" +} +// entity 140 +{ +"origin" "1616 847 -3088" +"light" "500" +"classname" "light" +} +// entity 141 +{ +"team_no" "2" +"dmg" "500" +"lip" "0" +"wait" "1" +"sounds" "1" +"speed" "200" +"angle" "270" +"classname" "func_door" +// brush 0 +{ +( 2288 -63119 65535 ) ( 2288 67951 65535 ) ( 2288 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 2272 67951 65535 ) ( 2272 -63119 65535 ) ( 2272 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 1240 65535 ) ( -65711 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 +( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 +} +} +// entity 142 +{ +"team_no" "2" +"dmg" "500" +"lip" "0" +"wait" "1" +"sounds" "1" +"speed" "200" +"angle" "90" +"classname" "func_door" +// brush 0 +{ +( 2288 -63119 65535 ) ( 2288 67951 65535 ) ( 2288 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 2272 67951 65535 ) ( 2272 -63119 65535 ) ( 2272 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) adoor03_3 -0 -0 -0 1 1 +( -65711 1240 65535 ) ( 65359 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 +( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 +} +} +// entity 143 +{ +"origin" "2384 1119 -3216" +"light" "500" +"classname" "light" +} +// entity 144 +{ +"origin" "2456 639 -3280" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 145 +{ +"origin" "2456 719 -3280" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 146 +{ +"origin" "2328 639 -3280" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 147 +{ +"origin" "2328 720 -3280" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 148 +{ +"origin" "2480 1008 -3290" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 149 +{ +"origin" "2480 1072 -3290" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 150 +{ +"origin" "2480 1136 -3290" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 151 +{ +"origin" "2304 1008 -3290" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 152 +{ +"origin" "2304 1072 -3290" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 153 +{ +"origin" "2304 1136 -3290" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 154 +{ +"origin" "-64 1025 -2976" +"light" "1000" +"classname" "light" +"angle" "180" +} +// entity 155 +{ +"origin" "1120 239 -2896" +"light" "350" +"classname" "light" +} +// entity 156 +{ +"team_no" "2" +"health" "0" +"dmg" "500" +"lip" "0" +"wait" "1" +"sounds" "1" +"speed" "200" +"angle" "180" +"classname" "func_door" +// brush 0 +{ +( 1128 -63119 65535 ) ( 1128 67951 65535 ) ( 1128 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 1056 67951 65535 ) ( 1056 -63119 65535 ) ( 1056 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 446 65535 ) ( -65711 446 65535 ) ( -65711 446 -65535 ) adoor03_3 -0 -0 -0 1 1 +( -65711 430 65535 ) ( 65359 430 65535 ) ( -65711 430 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 67951 -2960 ) ( 65359 -63119 -2960 ) ( -65711 -63119 -2960 ) adoor03_3 -0 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) adoor03_3 -0 -0 -0 1 1 +} +} +// entity 157 +{ +"team_no" "2" +"health" "0" +"dmg" "500" +"lip" "0" +"wait" "1" +"sounds" "1" +"speed" "200" +"classname" "func_door" +// brush 0 +{ +( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 1128 67951 65535 ) ( 1128 -63119 65535 ) ( 1128 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 446 65535 ) ( -65711 446 65535 ) ( -65711 446 -65535 ) adoor03_3 -0 -0 -0 1 1 +( -65711 430 65535 ) ( 65359 430 65535 ) ( -65711 430 -65535 ) adoor03_3 -0 -0 -0 1 1 +( 65359 67951 -2960 ) ( 65359 -63119 -2960 ) ( -65711 -63119 -2960 ) adoor03_3 -0 -0 -0 1 1 +( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) adoor03_3 -0 -0 -0 1 1 +} +} +// entity 158 +{ +"origin" "944 240 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 159 +{ +"origin" "944 176 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 160 +{ +"origin" "944 112 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 161 +{ +"origin" "1296 240 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 162 +{ +"origin" "1296 176 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 163 +{ +"origin" "1296 112 -3024" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" +} +// entity 164 +{ +"origin" "1232 -177 -2960" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 165 +{ +"origin" "1216 -241 -2960" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 166 +{ +"origin" "1136 -241 -2960" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 167 +{ +"origin" "1056 -241 -2960" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 168 +{ +"origin" "976 -241 -2960" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 169 +{ +"origin" "1008 -177 -2960" +"team_no" "2" +"classname" "info_player_teamspawn" +} +// entity 170 +{ +"origin" "1120 -161 -2896" +"light" "350" +"classname" "light" +} +// entity 171 +{ +"origin" "-992 1041 -3200" +"light" "250" +"classname" "light" +"angle" "180" +} +// entity 172 +{ +"origin" "816 1073 -3200" +"light" "250" +"classname" "light" +"angle" "180" +} +// entity 173 +{ +"origin" "1984 927 -3088" +"light" "500" +"classname" "light" +} +// entity 174 +{ +"origin" "1648 927 -3088" +"light" "500" +"classname" "light" +} +// entity 175 +{ +"origin" "2256 1503 -3216" +"light" "500" +"classname" "light" +} +// entity 176 +{ +"origin" "2480 1503 -2896" +"light" "500" +"classname" "light" +} +// entity 177 +{ +"origin" "2480 927 -2912" +"light" "500" +"classname" "light" +} +// entity 178 +{ +"height" "154" +"classname" "func_plat" +// brush 0 +{ +( 1744 -63119 65535 ) ( 1744 67951 65535 ) ( 1744 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 +( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 +( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) sfloor4_6 32 -0 -0 1 1 +( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_6 32 -0 -0 1 1 +( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) sfloor4_6 32 -0 -0 1 1 +( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 +} +} +// entity 179 +{ +"origin" "1728 655 -3088" +"light" "500" +"classname" "light" +} +// entity 180 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "lava grate" +"_tb_id" "431" +// brush 0 +{ +( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -2432 65535 65535 ) ( -2432 -65535 65535 ) ( -2432 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65071 1200 65535 ) ( -65999 1200 65535 ) ( -65999 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65999 592 65535 ) ( 65071 592 65535 ) ( -65999 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65071 65535 -3328 ) ( 65071 -65535 -3328 ) ( -65999 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65071 -65535 -3344 ) ( 65071 65535 -3344 ) ( -65999 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 1 +{ +( -2352 -65535 65535 ) ( -2352 65535 65535 ) ( -2352 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -2368 65535 65535 ) ( -2368 -65535 65535 ) ( -2368 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65135 1200 65535 ) ( -65935 1200 65535 ) ( -65935 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65935 592 65535 ) ( 65135 592 65535 ) ( -65935 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65135 65535 -3328 ) ( 65135 -65535 -3328 ) ( -65935 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65135 -65535 -3344 ) ( 65135 65535 -3344 ) ( -65935 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 2 +{ +( -2288 -65535 65535 ) ( -2288 65535 65535 ) ( -2288 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -2304 65535 65535 ) ( -2304 -65535 65535 ) ( -2304 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65199 1200 65535 ) ( -65871 1200 65535 ) ( -65871 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65871 592 65535 ) ( 65199 592 65535 ) ( -65871 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65199 65535 -3328 ) ( 65199 -65535 -3328 ) ( -65871 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65199 -65535 -3344 ) ( 65199 65535 -3344 ) ( -65871 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 3 +{ +( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -2240 65535 65535 ) ( -2240 -65535 65535 ) ( -2240 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65263 1200 65535 ) ( -65807 1200 65535 ) ( -65807 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65807 592 65535 ) ( 65263 592 65535 ) ( -65807 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65263 65535 -3328 ) ( 65263 -65535 -3328 ) ( -65807 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65263 -65535 -3344 ) ( 65263 65535 -3344 ) ( -65807 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 4 +{ +( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65327 1200 65535 ) ( -65743 1200 65535 ) ( -65743 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65743 592 65535 ) ( 65327 592 65535 ) ( -65743 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65327 65535 -3328 ) ( 65327 -65535 -3328 ) ( -65743 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65327 -65535 -3344 ) ( 65327 65535 -3344 ) ( -65743 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 5 +{ +( -2096 -65535 65535 ) ( -2096 65535 65535 ) ( -2096 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -2112 65535 65535 ) ( -2112 -65535 65535 ) ( -2112 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65391 1200 65535 ) ( -65679 1200 65535 ) ( -65679 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65679 592 65535 ) ( 65391 592 65535 ) ( -65679 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65391 65535 -3328 ) ( 65391 -65535 -3328 ) ( -65679 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65391 -65535 -3344 ) ( 65391 65535 -3344 ) ( -65679 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 6 +{ +( -2032 -65535 65535 ) ( -2032 65535 65535 ) ( -2032 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65455 1200 65535 ) ( -65615 1200 65535 ) ( -65615 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65615 592 65535 ) ( 65455 592 65535 ) ( -65615 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65455 65535 -3328 ) ( 65455 -65535 -3328 ) ( -65615 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65455 -65535 -3344 ) ( 65455 65535 -3344 ) ( -65615 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 7 +{ +( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -1984 65535 65535 ) ( -1984 -65535 65535 ) ( -1984 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65519 1200 65535 ) ( -65551 1200 65535 ) ( -65551 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65551 592 65535 ) ( 65519 592 65535 ) ( -65551 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65519 65535 -3328 ) ( 65519 -65535 -3328 ) ( -65551 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65519 -65535 -3344 ) ( 65519 65535 -3344 ) ( -65551 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 8 +{ +( -1904 -65535 65535 ) ( -1904 65535 65535 ) ( -1904 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65583 1200 65535 ) ( -65487 1200 65535 ) ( -65487 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65487 592 65535 ) ( 65583 592 65535 ) ( -65487 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65583 65535 -3328 ) ( 65583 -65535 -3328 ) ( -65487 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65583 -65535 -3344 ) ( 65583 65535 -3344 ) ( -65487 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 9 +{ +( -1840 -65535 65535 ) ( -1840 65535 65535 ) ( -1840 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -1856 65535 65535 ) ( -1856 -65535 65535 ) ( -1856 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65647 1200 65535 ) ( -65423 1200 65535 ) ( -65423 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65423 592 65535 ) ( 65647 592 65535 ) ( -65423 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65647 65535 -3328 ) ( 65647 -65535 -3328 ) ( -65423 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65647 -65535 -3344 ) ( 65647 65535 -3344 ) ( -65423 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 10 +{ +( -1776 -65535 65535 ) ( -1776 65535 65535 ) ( -1776 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65711 1200 65535 ) ( -65359 1200 65535 ) ( -65359 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65359 592 65535 ) ( 65711 592 65535 ) ( -65359 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65711 65535 -3328 ) ( 65711 -65535 -3328 ) ( -65359 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65711 -65535 -3344 ) ( 65711 65535 -3344 ) ( -65359 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 11 +{ +( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( -1728 65535 65535 ) ( -1728 -65535 65535 ) ( -1728 65535 -65535 ) metal5_1 48 -0 -0 1 1 +( 65775 1200 65535 ) ( -65295 1200 65535 ) ( -65295 1200 -65535 ) metal5_1 -0 -48 -0 1 1 +( -65295 592 65535 ) ( 65775 592 65535 ) ( -65295 592 -65535 ) metal5_1 -0 -48 -0 1 1 +( 65775 65535 -3328 ) ( 65775 -65535 -3328 ) ( -65295 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 +( 65775 -65535 -3344 ) ( 65775 65535 -3344 ) ( -65295 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 +} +// brush 12 +{ +( -1664 592 -3336 ) ( -1664 640 -3328 ) ( -1664 640 -3336 ) clip -0 -0 -0 1 1 +( -2448 592 -3336 ) ( -2448 640 -3328 ) ( -2448 592 -3328 ) clip -0 -0 -0 1 1 +( -2448 1200 -3336 ) ( -2432 1200 -3328 ) ( -2448 1200 -3328 ) clip -0 -0 -0 1 1 +( -2448 592 -3336 ) ( -2432 592 -3328 ) ( -2432 592 -3336 ) clip -0 -0 -0 1 1 +( -2448 592 -3328 ) ( -2432 640 -3328 ) ( -2432 592 -3328 ) clip -0 -0 -0 1 1 +( -2448 592 -3336 ) ( -2432 640 -3336 ) ( -2448 640 -3336 ) clip -0 -0 -0 1 1 +} +// brush 13 +{ +( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) metal5_8 -16 -48 180 1 1 +( -2488 65535 65535 ) ( -2488 -65535 65535 ) ( -2488 65535 -65535 ) metal5_8 -16 -48 180 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) metal5_8 -16 -48 -0 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) metal5_8 -16 -48 -0 1 1 +( 65535 65535 -3464 ) ( 65535 -65535 -3464 ) ( -65535 -65535 -3464 ) metal5_8 -16 -48 -0 1 1 +( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) metal5_8 -16 -48 -0 1 1 +} +// brush 14 +{ +( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) *lava1 -15 -0 -0 1 1 +( -2496 65535 65535 ) ( -2496 -65535 65535 ) ( -2496 65535 -65535 ) *lava1 -15 -0 -0 1 1 +( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) *lava1 -15 -0 180 1 1 +( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) *lava1 -15 -0 180 1 1 +( 65535 65535 -3336 ) ( 65535 -65535 -3336 ) ( -65535 -65535 -3336 ) *lava1 -15 -0 180 1 1 +( 65535 -65535 -3464 ) ( 65535 65535 -3464 ) ( -65535 -65535 -3464 ) *lava1 -15 -0 180 1 1 +} +} +// entity 181 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "lava grate" +"_tb_id" "432" +// brush 0 +{ +( 2240 67647 65535 ) ( 2240 -63423 65535 ) ( 2240 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 2256 -63423 65535 ) ( 2256 67647 65535 ) ( 2256 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65247 912 65535 ) ( 65823 912 65535 ) ( 65823 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65823 1520 65535 ) ( -65247 1520 65535 ) ( 65823 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65247 -63423 -3328 ) ( -65247 67647 -3328 ) ( 65823 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65247 67647 -3344 ) ( -65247 -63423 -3344 ) ( 65823 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 1 +{ +( 2176 67647 65535 ) ( 2176 -63423 65535 ) ( 2176 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 2192 -63423 65535 ) ( 2192 67647 65535 ) ( 2192 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65311 912 65535 ) ( 65759 912 65535 ) ( 65759 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65759 1520 65535 ) ( -65311 1520 65535 ) ( 65759 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65311 -63423 -3328 ) ( -65311 67647 -3328 ) ( 65759 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65311 67647 -3344 ) ( -65311 -63423 -3344 ) ( 65759 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 2 +{ +( 2112 67647 65535 ) ( 2112 -63423 65535 ) ( 2112 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 2128 -63423 65535 ) ( 2128 67647 65535 ) ( 2128 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65375 912 65535 ) ( 65695 912 65535 ) ( 65695 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65695 1520 65535 ) ( -65375 1520 65535 ) ( 65695 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65375 -63423 -3328 ) ( -65375 67647 -3328 ) ( 65695 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65375 67647 -3344 ) ( -65375 -63423 -3344 ) ( 65695 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 3 +{ +( 2048 67647 65535 ) ( 2048 -63423 65535 ) ( 2048 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 2064 -63423 65535 ) ( 2064 67647 65535 ) ( 2064 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65439 912 65535 ) ( 65631 912 65535 ) ( 65631 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65631 1520 65535 ) ( -65439 1520 65535 ) ( 65631 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65439 -63423 -3328 ) ( -65439 67647 -3328 ) ( 65631 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65439 67647 -3344 ) ( -65439 -63423 -3344 ) ( 65631 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 4 +{ +( 1984 67647 65535 ) ( 1984 -63423 65535 ) ( 1984 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 2000 -63423 65535 ) ( 2000 67647 65535 ) ( 2000 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65503 912 65535 ) ( 65567 912 65535 ) ( 65567 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65567 1520 65535 ) ( -65503 1520 65535 ) ( 65567 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65503 -63423 -3328 ) ( -65503 67647 -3328 ) ( 65567 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65503 67647 -3344 ) ( -65503 -63423 -3344 ) ( 65567 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 5 +{ +( 1920 67647 65535 ) ( 1920 -63423 65535 ) ( 1920 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 1936 -63423 65535 ) ( 1936 67647 65535 ) ( 1936 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65567 912 65535 ) ( 65503 912 65535 ) ( 65503 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65503 1520 65535 ) ( -65567 1520 65535 ) ( 65503 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65567 -63423 -3328 ) ( -65567 67647 -3328 ) ( 65503 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65567 67647 -3344 ) ( -65567 -63423 -3344 ) ( 65503 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 6 +{ +( 1856 67647 65535 ) ( 1856 -63423 65535 ) ( 1856 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 1872 -63423 65535 ) ( 1872 67647 65535 ) ( 1872 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65631 912 65535 ) ( 65439 912 65535 ) ( 65439 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65439 1520 65535 ) ( -65631 1520 65535 ) ( 65439 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65631 -63423 -3328 ) ( -65631 67647 -3328 ) ( 65439 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65631 67647 -3344 ) ( -65631 -63423 -3344 ) ( 65439 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 7 +{ +( 1792 67647 65535 ) ( 1792 -63423 65535 ) ( 1792 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 1808 -63423 65535 ) ( 1808 67647 65535 ) ( 1808 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65695 912 65535 ) ( 65375 912 65535 ) ( 65375 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65375 1520 65535 ) ( -65695 1520 65535 ) ( 65375 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65695 -63423 -3328 ) ( -65695 67647 -3328 ) ( 65375 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65695 67647 -3344 ) ( -65695 -63423 -3344 ) ( 65375 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 8 +{ +( 1728 67647 65535 ) ( 1728 -63423 65535 ) ( 1728 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 1744 -63423 65535 ) ( 1744 67647 65535 ) ( 1744 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65759 912 65535 ) ( 65311 912 65535 ) ( 65311 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65311 1520 65535 ) ( -65759 1520 65535 ) ( 65311 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65759 -63423 -3328 ) ( -65759 67647 -3328 ) ( 65311 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65759 67647 -3344 ) ( -65759 -63423 -3344 ) ( 65311 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 9 +{ +( 1664 67647 65535 ) ( 1664 -63423 65535 ) ( 1664 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 1680 -63423 65535 ) ( 1680 67647 65535 ) ( 1680 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65823 912 65535 ) ( 65247 912 65535 ) ( 65247 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65247 1520 65535 ) ( -65823 1520 65535 ) ( 65247 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65823 -63423 -3328 ) ( -65823 67647 -3328 ) ( 65247 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65823 67647 -3344 ) ( -65823 -63423 -3344 ) ( 65247 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 10 +{ +( 1600 67647 65535 ) ( 1600 -63423 65535 ) ( 1600 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 1616 -63423 65535 ) ( 1616 67647 65535 ) ( 1616 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65887 912 65535 ) ( 65183 912 65535 ) ( 65183 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65183 1520 65535 ) ( -65887 1520 65535 ) ( 65183 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65887 -63423 -3328 ) ( -65887 67647 -3328 ) ( 65183 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65887 67647 -3344 ) ( -65887 -63423 -3344 ) ( 65183 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 11 +{ +( 1536 67647 65535 ) ( 1536 -63423 65535 ) ( 1536 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( 1552 -63423 65535 ) ( 1552 67647 65535 ) ( 1552 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 +( -65951 912 65535 ) ( 65119 912 65535 ) ( 65119 912 -65535 ) metal5_1 16 -48 180 1 -1 +( 65119 1520 65535 ) ( -65951 1520 65535 ) ( 65119 1520 -65535 ) metal5_1 16 -48 180 1 -1 +( -65951 -63423 -3328 ) ( -65951 67647 -3328 ) ( 65119 67647 -3328 ) metal5_1 16 16 180 1 1 +( -65951 67647 -3344 ) ( -65951 -63423 -3344 ) ( 65119 67647 -3344 ) metal5_1 16 16 180 1 1 +} +// brush 12 +{ +( 1488 1520 -3336 ) ( 1488 1472 -3328 ) ( 1488 1472 -3336 ) clip -0 -0 180 1 -1 +( 2272 1520 -3336 ) ( 2272 1472 -3328 ) ( 2272 1520 -3328 ) clip -0 -0 180 1 -1 +( 2272 912 -3336 ) ( 2256 912 -3328 ) ( 2272 912 -3328 ) clip 16 -0 180 1 -1 +( 2272 1520 -3336 ) ( 2256 1520 -3328 ) ( 2256 1520 -3336 ) clip 16 -0 180 1 -1 +( 2272 1520 -3328 ) ( 2256 1472 -3328 ) ( 2256 1520 -3328 ) clip 16 -0 180 1 1 +( 2272 1520 -3336 ) ( 2256 1472 -3336 ) ( 2272 1472 -3336 ) clip 16 -0 180 1 1 +} +// brush 13 +{ +( 1488 67647 65535 ) ( 1488 -63423 65535 ) ( 1488 -63423 -65535 ) metal5_8 -16 -48 -0 1 -1 +( 2312 -63423 65535 ) ( 2312 67647 65535 ) ( 2312 -63423 -65535 ) metal5_8 -16 -48 -0 1 -1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( 65359 912 -65535 ) metal5_8 -0 -48 180 1 -1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( 65359 1520 -65535 ) metal5_8 -0 -48 180 1 -1 +( -65711 -63423 -3464 ) ( -65711 67647 -3464 ) ( 65359 67647 -3464 ) metal5_8 -0 16 180 1 1 +( -65711 67647 -3472 ) ( -65711 -63423 -3472 ) ( 65359 67647 -3472 ) metal5_8 -0 16 180 1 1 +} +// brush 14 +{ +( 1488 67647 65535 ) ( 1488 -63423 65535 ) ( 1488 -63423 -65535 ) *lava1 -15 -0 180 1 -1 +( 2320 -63423 65535 ) ( 2320 67647 65535 ) ( 2320 -63423 -65535 ) *lava1 -15 -0 180 1 -1 +( -65711 912 65535 ) ( 65359 912 65535 ) ( 65359 912 -65535 ) *lava1 -31 -0 -0 1 -1 +( 65359 1520 65535 ) ( -65711 1520 65535 ) ( 65359 1520 -65535 ) *lava1 -31 -0 -0 1 -1 +( -65711 -63423 -3336 ) ( -65711 67647 -3336 ) ( 65359 67647 -3336 ) *lava1 -31 -0 -0 1 1 +( -65711 67647 -3464 ) ( -65711 -63423 -3464 ) ( 65359 67647 -3464 ) *lava1 -31 -0 -0 1 1 +} +} +// entity 182 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "boxes" +"_tb_id" "433" +// brush 0 +{ +( -2688 1424 -3328 ) ( -2688 1568 -3312 ) ( -2688 1568 -3328 ) iktpw02 -16 -0 -0 1 1 +( -2816 1424 -3328 ) ( -2816 1568 -3312 ) ( -2816 1424 -3312 ) iktpw02 -16 -0 -0 1 1 +( -2816 1568 -3328 ) ( -2688 1568 -3312 ) ( -2816 1568 -3312 ) iktpw02 -16 -0 -0 1 1 +( -2816 1424 -3328 ) ( -2688 1424 -3312 ) ( -2688 1424 -3328 ) iktpw02 -64 -0 -0 1 1 +( -2816 1424 -3200 ) ( -2688 1568 -3200 ) ( -2688 1424 -3200 ) iktpw02 -64 -48 -0 1 1 +( -2816 1424 -3328 ) ( -2688 1568 -3328 ) ( -2816 1568 -3328 ) iktpw02 -16 -0 -0 1 1 +} +// brush 1 +{ +( -2752 1392 -3328 ) ( -2752 1424 -3312 ) ( -2752 1424 -3328 ) iktpw02 -0 -0 -0 0.5 0.5 +( -2784 1392 -3328 ) ( -2784 1424 -3312 ) ( -2784 1392 -3312 ) iktpw02 -32.0005 -0 -0 0.5 0.5 +( -2784 1424 -3328 ) ( -2752 1424 -3312 ) ( -2784 1424 -3312 ) iktpw02 -0 -0 -0 0.5 0.5 +( -2784 1392 -3328 ) ( -2752 1392 -3312 ) ( -2752 1392 -3328 ) iktpw02 -0 -0 -0 0.5 0.5 +( -2784 1392 -3296 ) ( -2752 1424 -3296 ) ( -2752 1392 -3296 ) iktpw02 -63.999 32.0005 -0 0.5 0.5 +( -2784 1392 -3328 ) ( -2752 1424 -3328 ) ( -2784 1424 -3328 ) iktpw02 -0 -0 -0 0.5 0.5 +} +// brush 2 +{ +( -2688 1376 -3328 ) ( -2688 1424 -3312 ) ( -2688 1424 -3328 ) iktpw02 -16 -0 -0 1 1 +( -2752 1376 -3328 ) ( -2752 1424 -3312 ) ( -2752 1376 -3312 ) iktpw02 -16 -0 -0 1 1 +( -2752 1424 -3328 ) ( -2704 1424 -3312 ) ( -2752 1424 -3312 ) iktpw02 -0 -0 -0 1 1 +( -2752 1360 -3328 ) ( -2704 1360 -3312 ) ( -2704 1360 -3328 ) iktpw02 -0 -0 -0 1 1 +( -2752 1376 -3264 ) ( -2704 1424 -3264 ) ( -2704 1376 -3264 ) iktpw02 -0 16 -0 1 1 +( -2752 1376 -3328 ) ( -2704 1424 -3328 ) ( -2752 1424 -3328 ) iktpw02 -0 16 -0 1 1 +} +// brush 3 +{ +( -2688 1392 -3264 ) ( -2688 1424 -3248 ) ( -2688 1424 -3264 ) iktpw02 -0 -0 -0 0.5 0.5 +( -2720 1392 -3264 ) ( -2720 1424 -3248 ) ( -2720 1392 -3248 ) iktpw02 -32 -0 -0 0.5 0.5 +( -2720 1424 -3264 ) ( -2688 1424 -3248 ) ( -2720 1424 -3248 ) iktpw02 -0 -0 -0 0.5 0.5 +( -2720 1392 -3264 ) ( -2688 1392 -3248 ) ( -2688 1392 -3264 ) iktpw02 -0 -0 -0 0.5 0.5 +( -2720 1392 -3232 ) ( -2688 1424 -3232 ) ( -2688 1392 -3232 ) iktpw02 -0 32 -0 0.5 0.5 +( -2720 1392 -3264 ) ( -2688 1424 -3264 ) ( -2720 1424 -3264 ) iktpw02 -0 -0 -0 0.5 0.5 +} +} +// entity 183 +{ +"origin" "-2848 1344 -3168" +"light" "250" +"classname" "light" +"_tb_group" "433" +} +// entity 184 +{ +"classname" "func_group" +"_tb_type" "_tb_group" +"_tb_name" "boxes" +"_tb_id" "434" +// brush 0 +{ +( 2512 704 -3328 ) ( 2512 560 -3312 ) ( 2512 560 -3328 ) iktpw02 -0 -0 180 1 -1 +( 2640 704 -3328 ) ( 2640 560 -3312 ) ( 2640 704 -3312 ) iktpw02 -0 -0 180 1 -1 +( 2640 560 -3328 ) ( 2512 560 -3312 ) ( 2640 560 -3312 ) iktpw02 -0 -0 180 1 -1 +( 2640 704 -3328 ) ( 2512 704 -3312 ) ( 2512 704 -3328 ) iktpw02 -48 -0 180 1 -1 +( 2640 704 -3200 ) ( 2512 560 -3200 ) ( 2512 704 -3200 ) iktpw02 -48 -0 180 1 1 +( 2640 704 -3328 ) ( 2512 560 -3328 ) ( 2640 560 -3328 ) iktpw02 -0 48 180 1 1 +} +// brush 1 +{ +( 2576 736 -3328 ) ( 2576 704 -3312 ) ( 2576 704 -3328 ) iktpw02 -32 -0 180 0.5 -0.5 +( 2608 736 -3328 ) ( 2608 704 -3312 ) ( 2608 736 -3312 ) iktpw02 -63.9987 -0 180 0.5 -0.5 +( 2608 704 -3328 ) ( 2576 704 -3312 ) ( 2608 704 -3312 ) iktpw02 -31.998 -0 180 0.5 -0.5 +( 2608 736 -3328 ) ( 2576 736 -3312 ) ( 2576 736 -3328 ) iktpw02 -31.998 -0 180 0.5 -0.5 +( 2608 736 -3296 ) ( 2576 704 -3296 ) ( 2576 736 -3296 ) iktpw02 -31.998 63.9987 180 0.5 0.5 +( 2608 736 -3328 ) ( 2576 704 -3328 ) ( 2608 704 -3328 ) iktpw02 -31.998 32 180 0.5 0.5 +} +// brush 2 +{ +( 2512 752 -3328 ) ( 2512 704 -3312 ) ( 2512 704 -3328 ) iktpw02 -0 -0 180 1 -1 +( 2576 752 -3328 ) ( 2576 704 -3312 ) ( 2576 752 -3312 ) iktpw02 -0 -0 180 1 -1 +( 2576 704 -3328 ) ( 2528 704 -3312 ) ( 2576 704 -3312 ) iktpw02 -48 -0 180 1 -1 +( 2576 768 -3328 ) ( 2528 768 -3312 ) ( 2528 768 -3328 ) iktpw02 -48 -0 180 1 -1 +( 2576 752 -3264 ) ( 2528 704 -3264 ) ( 2528 752 -3264 ) iktpw02 -48 -0 180 1 1 +( 2576 752 -3328 ) ( 2528 704 -3328 ) ( 2576 704 -3328 ) iktpw02 -48 -0 180 1 1 +} +// brush 3 +{ +( 2512 736 -3264 ) ( 2512 704 -3248 ) ( 2512 704 -3264 ) iktpw02 -32 -0 180 0.5 -0.5 +( 2544 736 -3264 ) ( 2544 704 -3248 ) ( 2544 736 -3248 ) iktpw02 -63.9987 -0 180 0.5 -0.5 +( 2544 704 -3264 ) ( 2512 704 -3248 ) ( 2544 704 -3248 ) iktpw02 -32 -0 180 0.5 -0.5 +( 2544 736 -3264 ) ( 2512 736 -3248 ) ( 2512 736 -3264 ) iktpw02 -32 -0 180 0.5 -0.5 +( 2544 736 -3232 ) ( 2512 704 -3232 ) ( 2512 736 -3232 ) iktpw02 -32 63.9987 180 0.5 0.5 +( 2544 736 -3264 ) ( 2512 704 -3264 ) ( 2544 704 -3264 ) iktpw02 -32 32 180 0.5 0.5 +} +} +// entity 185 +{ +"origin" "2672 784 -3168" +"light" "250" +"classname" "light" +"angle" "180" +"_tb_group" "434" +} From eac00c1693336b5586c90cf96bc80577abb580f6 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 16 Nov 2018 23:29:45 +1100 Subject: [PATCH 0469/2474] Working pre fte extensions integration --- defs.qc | 5 +- fteextensions.qc | 3209 ++++++++++++++++++++++++++++++++++++++++++++++ misc.qc | 6 + progs.src | 2 +- tfort.qc | 2 +- tfortmap.qc | 59 +- 6 files changed, 3254 insertions(+), 29 deletions(-) create mode 100644 fteextensions.qc diff --git a/defs.qc b/defs.qc index 7094ab2e..1cbf2a96 100644 --- a/defs.qc +++ b/defs.qc @@ -461,4 +461,7 @@ float (entity targ, entity inflictor) CanDamage; // // q3 defs // -.string allowteams; \ No newline at end of file +.string allowteams; +.string give; +.string active_all_sound; +.string model; \ No newline at end of file diff --git a/fteextensions.qc b/fteextensions.qc new file mode 100644 index 00000000..3f155dd8 --- /dev/null +++ b/fteextensions.qc @@ -0,0 +1,3209 @@ +/* +This file was automatically generated by FTE Quake v1.06 +This file can be regenerated by issuing the following command: +pr_dumpplatform -o fteextensions +Available options: +-Ffte - target only FTE (optimations and additional extensions) +-Tnq - dump specifically NQ fields +-Tqw - dump specifically QW fields +-Tcs - dump specifically CSQC fields +-Tmenu - dump specifically menuqc fields +-Fdefines - generate #defines instead of constants +-Faccessors - use accessors instead of basic types via defines +-O - write to a different qc file +*/ +#pragma noref 1 +//#pragma flag enable logicops +#pragma warning error Q101 /*too many parms*/ +#pragma warning error Q105 /*too few parms*/ +#pragma warning error Q106 /*assignment to constant/lvalue*/ +#pragma warning disable Q208 /*system crc unknown*/ +#pragma warning disable F211 /*system crc outdated (eg: dp's csqc)*/ +#pragma warning disable F301 /*non-utf-8 strings*/ +#pragma warning enable F302 /*uninitialised locals*/ + + +#define QUAKEWORLD + +#if !defined(CSQC) && !defined(NQSSQC) && !defined(QWSSQC)&& !defined(MENU) +#ifdef QUAKEWORLD +#define QWSSQC +#else +#define NQSSQC +#endif +#endif +#if !defined(SSQC) && (defined(QWSSQC) || defined(NQSSQC)) +#define SSQC +#endif +#define FTE_PEXT_SETVIEW /* NQ's svc_setview works correctly even in quakeworld */ +#define DP_ENT_SCALE +#define FTE_PEXT_LIGHTSTYLECOL +#define DP_ENT_ALPHA +#define FTE_PEXT_VIEW2 +#define FTE_PEXT_ACURATETIMINGS +#define FTE_PEXT_SOUNDDBL +#define FTE_PEXT_FATNESS +#define DP_HALFLIFE_MAP +#define FTE_PEXT_TE_BULLET +#define FTE_PEXT_HULLSIZE +#define FTE_PEXT_MODELDBL +#define FTE_PEXT_ENTITYDBL +#define FTE_PEXT_ENTITYDBL2 +#define FTE_PEXT_FLOATCOORDS +#define FTE_PEXT_VWEAP +#define FTE_PEXT_Q2BSP +#define FTE_PEXT_Q3BSP +#define DP_ENT_COLORMOD +#define FTE_HEXEN2 +#define FTE_PEXT_SPAWNSTATIC +#define FTE_PEXT_CUSTOMTENTS +#define FTE_PEXT_256PACKETENTITIES +#define TEI_SHOWLMP2 +#define DP_GFX_QUAKE3MODELTAGS +#define FTE_PK3DOWNLOADS +#define PEXT_CHUNKEDDOWNLOADS +#define EXT_CSQC_SHARED +#define PEXT_DPFLAGS +#define EXT_CSQC +#define BX_COLOREDTEXT +#define DP_CON_SET /* The 'set' console command exists, and can be used to create/set cvars. */ +#define DP_CON_SETA /* The 'seta' console command exists, like the 'set' command, but also marks the cvar for archiving, allowing it to be written into the user's config. Use this command in your default.cfg file. */ +#define DP_EF_ADDITIVE +#define DP_EF_BLUE +#define DP_EF_FULLBRIGHT +#define DP_EF_NODEPTHTEST +#define DP_EF_NODRAW +#define DP_EF_NOGUNBOB +#define DP_EF_NOSHADOW +#define DP_EF_RED +#define DP_ENT_CUSTOMCOLORMAP +#define DP_ENT_EXTERIORMODELTOCLIENT +#define DP_ENT_TRAILEFFECTNUM /* self.traileffectnum=particleeffectnum("myeffectname"); can be used to attach a particle trail to the given server entity. This is equivelent to calling trailparticles each frame. */ +#define DP_ENT_VIEWMODEL +#define DP_GECKO_SUPPORT +#define DP_GFX_FONTS +#define DP_GFX_SKINFILES +#define DP_GFX_SKYBOX +#define DP_HALFLIFE_MAP_CVAR +#define DP_INPUTBUTTONS +#define DP_LIGHTSTYLE_STATICVALUE +#define DP_LITSUPPORT +#define DP_MONSTERWALK /* MOVETYPE_WALK is valid on non-player entities. Note that only players receive acceleration etc in line with none/bounce/fly/noclip movetypes on the player, thus you will have to provide your own accelerations (incluing gravity) yourself. */ +#define DP_MOVETYPEBOUNCEMISSILE +#define DP_MOVETYPEFOLLOW +#define DP_QC_ASINACOSATANATAN2TAN +#define DP_QC_CHANGEPITCH +#define DP_QC_COPYENTITY +#define DP_QC_CRC16 +#define DP_QC_CVAR_DEFSTRING +#define DP_QC_CVAR_STRING +#define DP_QC_CVAR_TYPE +#define DP_QC_EDICT_NUM +#define DP_QC_ENTITYDATA +#define DP_QC_ETOS +#define DP_QC_FINDCHAIN +#define DP_QC_FINDCHAINFLOAT +#define DP_QC_FINDFLAGS +#define DP_QC_FINDCHAINFLAGS +#define DP_QC_FINDFLOAT +#define DP_QC_FS_SEARCH +#define DP_QC_GETSURFACE +#define DP_QC_GETSURFACEPOINTATTRIBUTE +#define DP_QC_GETTAGINFO +#define DP_QC_MINMAXBOUND +#define DP_QC_MULTIPLETEMPSTRINGS /* Superseded by DP_QC_UNLIMITEDTEMPSTRINGS. Functions that return a temporary string will not overwrite/destroy previous temporary strings until at least 16 strings are returned (or control returns to the engine). */ +#define DP_QC_RANDOMVEC +#define DP_QC_RENDER_SCENE /* clearscene+addentity+setviewprop+renderscene+setmodel are available to menuqc. WARNING: DP advertises this extension without actually supporting it, FTE does actually support it. */ +#define DP_QC_SINCOSSQRTPOW +#define DP_QC_SPRINTF /* Provides the sprintf builtin, which allows for rich formatting along the lines of C's function with the same name. Not to be confused with QC's sprint builtin. */ +#define DP_QC_STRFTIME +#define DP_QC_STRING_CASE_FUNCTIONS +#define DP_QC_STRINGBUFFERS +#define DP_QC_STRINGCOLORFUNCTIONS +#define DP_QC_STRREPLACE +#define DP_QC_TOKENIZEBYSEPARATOR +#define DP_QC_TRACEBOX +#define DP_QC_TRACETOSS +#define DP_QC_TRACE_MOVETYPE_HITMODEL +#define DP_QC_TRACE_MOVETYPE_WORLDONLY +#define DP_QC_TRACE_MOVETYPES +#define DP_QC_UNLIMITEDTEMPSTRINGS /* Supersedes DP_QC_MULTIPLETEMPSTRINGS, superseded by FTE_QC_PERSISTENTTEMPSTRINGS. Specifies that all temp strings will be valid at least until the QCVM returns. */ +#define DP_QC_URI_ESCAPE +#define DP_QC_URI_GET +#define DP_QC_URI_POST +#define DP_QC_VECTOANGLES_WITH_ROLL +#define DP_QC_VECTORVECTORS +#define DP_QC_WHICHPACK +#define DP_QUAKE2_MODEL +#define DP_QUAKE2_SPRITE +#define DP_QUAKE3_MODEL +#define DP_REGISTERCVAR +#define DP_SND_SOUND7_WIP2 +#define DP_SND_STEREOWAV +#define DP_SND_OGGVORBIS +#define DP_SOLIDCORPSE +#define DP_SPRITE32 +#define DP_SV_BOTCLIENT +#define DP_SV_CLIENTCOLORS /* Provided only for compatibility with DP. */ +#define DP_SV_CLIENTNAME /* Provided only for compatibility with DP. */ +#define DP_SV_DRAWONLYTOCLIENT +#define DP_SV_DROPCLIENT /* Equivelent to quakeworld's stuffcmd(self,"disconnect\n"); hack */ +#define DP_SV_EFFECT +#define DP_SV_EXTERIORMODELFORCLIENT +#define DP_SV_NODRAWTOCLIENT +#define DP_SV_PLAYERPHYSICS /* Allows reworking parts of NQ player physics. USE AT OWN RISK - this necessitates NQ physics and is thus guarenteed to break prediction. */ +#define DP_SV_POINTSOUND +#define DP_SV_PRECACHEANYTIME /* Specifies that the various precache builtins can be called at any time. WARNING: precaches are sent reliably while sound events, modelindexes, and particle events are not. This can mean sounds and particles might not work the first time around, or models may take a while to appear (after the reliables are received and the model is loaded from disk). Always attempt to precache a little in advance in order to reduce these issues (preferably at the start of the map...) */ +#define DP_SV_PRINT /* Says that the print builtin can be used from nqssqc (as well as just csqc), bypassing the developer cvar issues. */ +#define DP_SV_SETCOLOR +#define DP_SV_SPAWNFUNC_PREFIX +#define DP_SV_WRITEPICTURE +#define DP_SV_WRITEUNTERMINATEDSTRING +#define DP_TE_BLOOD +#define DP_TE_CUSTOMFLASH +#define DP_TE_EXPLOSIONRGB +#define DP_TE_PARTICLECUBE +#define DP_TE_PARTICLERAIN +#define DP_TE_PARTICLESNOW +#define DP_TE_SMALLFLASH +#define DP_TE_SPARK +#define DP_TE_STANDARDEFFECTBUILTINS +#define DP_VIEWZOOM +#define EXT_BITSHIFT +#define EXT_DIMENSION_VISIBILITY +#define EXT_DIMENSION_PHYSICS +#define EXT_DIMENSION_GHOST +#define FRIK_FILE +#define FTE_CALLTIMEOFDAY /* Replication of mvdsv functionality (call calltimeofday to cause 'timeofday' to be called, with arguments that can be saved off to a global). Generally strftime is simpler to use. */ +#define FTE_CSQC_ALTCONSOLES /* The engine tracks multiple consoles. These may or may not be directly visible to the user. */ +#define FTE_CSQC_BASEFRAME /* Specifies that .basebone, .baseframe2, .baselerpfrac, baseframe1time, etc exist in csqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations. */ +#define FTE_CSQC_HALFLIFE_MODELS +#define FTE_CSQC_SERVERBROWSER /* Provides builtins to query the engine's serverbrowser servers list from ssqc. Note that these builtins are always available in menuqc. */ +#define FTE_CSQC_SKELETONOBJECTS /* Provides container objects for skeletal bone data, which can be modified on a per bone basis if needed. This allows you to dynamically generate animations (or just blend them with greater customisation) instead of being limited to a single animation or two. */ +#define FTE_CSQC_RAWIMAGES /* Provides raw rgba image access to csqc. With this, the csprogs can read textures into qc-accessible memory, modify it, and then upload it to the renderer. */ +#define FTE_CSQC_RENDERTARGETS /* VF_RT_DESTCOLOUR exists and can be used to redirect any rendering to a texture instead of the screen. */ +#define FTE_CSQC_REVERB /* Specifies that the mod can create custom reverb effects. Whether they will actually be used or not depends upon the sound driver. */ +#define FTE_CSQC_WINDOWCAPTION /* Provides csqc with the ability to change the window caption as displayed when running windowed or in the task bar when switched out. */ +#define FTE_ENT_SKIN_CONTENTS /* self.skin = CONTENTS_WATER; makes a brush entity into water. use -16 for a ladder. */ +#define FTE_ENT_UNIQUESPAWNID +#define FTE_EXTENDEDTEXTCODES +#define FTE_FORCESHADER /* Allows csqc to override shaders on models with an explicitly named replacement. Also allows you to define shaders with a fallback if it does not exist on disk. */ +#define FTE_FORCEINFOKEY /* Provides an easy way to change a user's userinfo from the server. */ +#define FTE_GFX_QUAKE3SHADERS /* specifies that the engine has full support for vanilla quake3 shaders */ +#define FTE_GFX_REMAPSHADER /* With the raw power of stuffcmds, the r_remapshader console command is exposed! This mystical command can be used to remap any shader to another. Remapped shaders that specify $diffuse etc in some form will inherit the textures implied by the surface. */ +#define FTE_GFX_MODELEVENTS /* Provides a query for per-animation events in model files, including from progs/foo.mdl.events files. */ +#define FTE_ISBACKBUFFERED /* Allows you to check if a client has too many reliable messages pending. */ +#define FTE_MEMALLOC /* Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games. */ +#define FTE_MEDIA_CIN /* playfilm command supports q2 cin files. */ +#define FTE_MEDIA_ROQ /* playfilm command supports q3 roq files. */ +#define FTE_MULTIPROGS /* Multiple progs.dat files can be loaded inside the same qcvm. Insert new ones with addprogs inside the 'init' function, and use externvalue+externset to rewrite globals (and hook functions) to link them together. Note that the result is generally not very clean unless you carefully design for it beforehand. */ +#define FTE_MULTITHREADED /* Faux multithreading, allowing multiple contexts to run in sequence. */ +#define FTE_MVD_PLAYERSTATS /* In csqc, getplayerstat can be used to query any player's stats when playing back MVDs. isdemo will return 2 in this case. */ +#define FTE_PART_SCRIPT /* Specifies that the r_particledesc cvar can be used to select a list of particle effects to load from particles/*.cfg, the format of which is documented elsewhere. */ +#define FTE_PART_NAMESPACES /* Specifies that the engine can use foo.bar to load effect foo from particle description bar. When used via ssqc, this should cause the client to download whatever effects as needed. */ +#define FTE_PART_NAMESPACE_EFFECTINFO /* Specifies that effectinfo.bar can load effects from effectinfo.txt for DP compatibility. */ +#define FTE_QC_BASEFRAME /* Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc. */ +#define FTE_QC_FILE_BINARY /* Extends FRIK_FILE with binary read+write, as well as allowing seeking. Requires pointers. */ +#define FTE_QC_CHANGELEVEL_HUB /* Adds an extra argument to changelevel which is carried over to the next map in the 'spawnspot' global. Maps will be saved+reloaded until the extra argument is omitted again, purging all saved maps. Saved games will contain a copy of each preserved map. parm1-parm64 globals can be used, giving more space to transfer more player data. */ +#define FTE_QC_CHECKCOMMAND /* Provides a way to test if a console command exists, and whether its a command/alias/cvar. Does not say anything about the expected meanings of any arguments or values. */ +#define FTE_QC_CHECKPVS +#define FTE_QC_CROSSPRODUCT +#define FTE_QC_CUSTOMSKINS /* The engine supports the use of q3 skins, as well as the use of such skin 'files' to specify rich top+bottom colours, qw skins, geomsets, or texture composition even on non-players.. */ +#define FTE_QC_FS_SEARCH_SIZEMTIME +#define FTE_QC_HARDWARECURSORS /* setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits (or hardware cursors are unsupported), it will be emulated using regular draws - this at least still avoids conflicting cursors as only one will ever be used, even if console+menu+csqc are all overlayed. */ +#define FTE_QC_HASHTABLES /* Provides efficient string-based lookups. */ +#define FTE_QC_INFOKEY /* QuakeWorld's infokey builtin works, and reports at least name+topcolor+bottomcolor+ping(in ms)+ip(unmasked, but not always ipv4)+team(aka bottomcolor in nq). Does not require actual localinfo/serverinfo/userinfo, but they're _highly_ recommended to any engines with csqc */ +#define FTE_QC_INTCONV /* Provides string<>int conversions, including hex representations. */ +#define FTE_QC_MATCHCLIENTNAME +#define FTE_QC_MULTICAST /* QuakeWorld's multicast builtin works along with MSG_MULTICAST, but also with unicast support. */ +#define FTE_QC_PAUSED +#define FTE_QC_PERSISTENTTEMPSTRINGS /* Supersedes DP_QC_MULTIPLETEMPSTRINGS. Temp strings are garbage collected automatically, and do not expire while they're still in use. This makes strzone redundant. */ +#define FTE_QC_RAGDOLL_WIP +#define FTE_QC_SENDPACKET /* Allows the use of out-of-band udp packets to/from other hosts. Includes the SV_ParseConnectionlessPacket event. */ +#define FTE_QC_STUFFCMDFLAGS /* Variation on regular stuffcmd that gives control over how spectators/mvds should be treated. */ +#define FTE_QC_TRACETRIGGER +#define FTE_QUAKE2_CLIENT /* This engine is able to act as a quake2 client */ +#define FTE_QUAKE2_SERVER /* This engine is able to act as a quake2 server */ +#define FTE_QUAKE3_CLIENT /* This engine is able to act as a quake3 client */ +#define FTE_QUAKE3_SERVER /* This engine is able to act as a quake3 server */ +#define FTE_SOLID_LADDER /* Allows a simple trigger to remove effects of gravity (solid 20). obsolete. will prolly be removed at some point as it is not networked properly. Use FTE_ENT_SKIN_CONTENTS */ +#define FTE_SPLITSCREEN /* Client supports splitscreen, controlled via cl_splitscreen. Servers require allow_splitscreen 1 if splitscreen is to be used over the internet. Mods that use csqc will need to be aware for this to work properly. per-client networking may be problematic. */ +#define FTE_SQL /* Provides sql* builtins which can be used for sql database access */ +#define FTE_SQL_SQLITE /* SQL functionality is able to utilise sqlite databases */ +#define FTE_STRINGS /* Extra builtins (and additional behaviour) to make string manipulation easier */ +#define FTE_SV_POINTPARTICLES /* Specifies that particleeffectnum, pointparticles, and trailparticles exist in ssqc as well as csqc. particleeffectnum acts as a precache, allowing ssqc values to be networked up with csqc for use. Use in combination with FTE_PART_SCRIPT+FTE_PART_NAMESPACES to use custom effects. This extension is functionally identical to the DP version, but avoids any misplaced assumptions about the format of the client's particle descriptions. */ +#define FTE_SV_REENTER +#define FTE_TE_STANDARDEFFECTBUILTINS /* Provides builtins to replace writebytes, with a QW compatible twist. */ +#define FTE_TERRAIN_MAP /* This engine supports .hmp files, as well as terrain embedded within bsp files. */ +#define FTE_RAW_MAP /* This engine supports directly loading .map files, as well as realtime editing of the various brushes. */ +#define KRIMZON_SV_PARSECLIENTCOMMAND /* SSQC's SV_ParseClientCommand function is able to handle client 'cmd' commands. The tokenizing parts also work in csqc. */ +#define NEH_CMD_PLAY2 +#define NEH_RESTOREGAME +#define QSG_CVARSTRING +#define QW_ENGINE +#define QWE_MVD_RECORD /* You can use the easyrecord command to record MVD demos serverside. */ +#define TEI_MD3_MODEL +#define TENEBRAE_GFX_DLIGHTS /* Allows ssqc to attach rtlights to entities with various special properties. */ +#define ZQ_MOVETYPE_FLY /* MOVETYPE_FLY works on players. */ +#define ZQ_MOVETYPE_NOCLIP /* MOVETYPE_NOCLIP works on players. */ +#define ZQ_MOVETYPE_NONE /* MOVETYPE_NONE works on players. */ +#define ZQ_VWEP +#define ZQ_QC_STRINGS /* The strings-only subset of FRIK_FILE is supported. */ + +#ifdef _ACCESSORS +accessor strbuf : float; +accessor searchhandle : float; +accessor hashtable : float; +accessor infostring : string; +accessor filestream : float; +accessor filestream : float; +#else +#define strbuf float +#define searchhandle float +#define hashtable float +#define infostring string +#define filestream float +#endif + +entity self; /* The magic me */ +#if defined(CSQC) || defined(SSQC) +entity other; /* Valid in touch functions, this is the entity that we touched. */ +entity world; /* The null entity. Hurrah. Readonly after map spawn time. */ +float time; /* The current game time. Stops when paused. */ +#endif +#ifdef CSQC +float cltime; /* A local timer that ticks relative to local time regardless of latency, packetloss, or pause. */ +#endif +#if defined(CSQC) || defined(SSQC) +float frametime; /* The time since the last physics/render/input frame. */ +#endif +#ifdef CSQC +float player_localentnum; /* This is entity number the player is seeing from/spectating, or the player themself, can change mid-map. */ +float player_localnum; /* The 0-based player index, valid for getplayerkeyvalue calls. */ +float maxclients; /* Maximum number of player slots on the server. */ +float clientcommandframe; /* This is the input-frame sequence. frames < clientcommandframe have been sent to the server. frame==clientcommandframe is still being generated and can still change. */ +float servercommandframe; /* This is the input-frame that was last acknowledged by the server. Input frames greater than this should be applied to the player's entity. */ +#endif +#if defined(QWSSQC) +entity newmis; /* A named entity that should be run soon, to reduce the effects of latency. */ +#endif +#ifdef SSQC +float force_retouch; /* If positive, causes all entities to check for triggers. */ +#endif +#if defined(CSQC) || defined(SSQC) +string mapname; /* The short name of the map. */ +#endif +#if defined(NQSSQC) +float deathmatch; +float coop; +float teamplay; +#endif +#ifdef SSQC +float serverflags; +float total_secrets; +float total_monsters; +float found_secrets; +float killed_monsters; +float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16; +#endif +#ifdef CSQC +float intermission; +#endif +#if defined(CSQC) || defined(SSQC) +vector v_forward, v_up, v_right; +#endif +#ifdef CSQC +vector view_angles; /* +x=DOWN */ +#endif +#if defined(CSQC) || defined(SSQC) +float trace_allsolid, trace_startsolid, trace_fraction; +vector trace_endpos, trace_plane_normal; +float trace_plane_dist; +entity trace_ent; +float trace_inopen; +float trace_inwater; +#endif +#ifdef CSQC +float input_timelength; +vector input_angles; /* +x=DOWN */ +vector input_movevalues; +float input_buttons; +float input_impulse; +#endif +#ifdef SSQC +entity msg_entity; +void() main; /* This function is never called, and is effectively dead code. */ +void() StartFrame; /* Called at the start of each new physics frame. Player entities may think out of sequence so try not to depend upon explicit ordering too much. */ +void() PlayerPreThink; /* With Prediction(QW compat/FTE default): Called before the player's input commands are processed. +No Prediction(NQ compat): Called AFTER the player's movement intents have already been processed (ie: velocity will have already changed according to input_*, but before the actual position change. */ +void() PlayerPostThink; /* Called after the player's input commands are processed. */ +//void() ClientKill; /* Called in response to 'cmd kill' (or just 'kill'). */ +//void(optional float csqcactive) ClientConnect; /* Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. */ +void() PutClientInServer; /* Enginewise, this is only ever called immediately after ClientConnect and is thus a little redundant. Modwise, this is also called for respawning a player etc. */ +void() ClientDisconnect; /* Called once a client disconnects or times out. Not guarenteed to be called on map changes. */ +void() SetNewParms; /* Called without context when a new client initially connects (before ClientConnect is even called). This function is expected to only set the parm* globals so that they can be decoded properly later. You should not rely on 'self' being set. */ +void() SetChangeParms; /* Called for each client on map changes. Should copy various entity fields to the parm* globals. */ +#endif +void end_sys_globals; +#if defined(CSQC) || defined(SSQC) +.float modelindex; /* This is the model precache index for the model that was set on the entity, instead of having to look up the model according to the .model field. Use setmodel to change it. */ +.vector absmin; /* Set by the engine when the entity is relinked (by setorigin, setsize, or setmodel). This is in world coordinates. */ +.vector absmax; /* Set by the engine when the entity is relinked (by setorigin, setsize, or setmodel). This is in world coordinates. */ +#endif +#ifdef SSQC +.float ltime; /* On MOVETYPE_PUSH entities, this is used as an alternative to the 'time' global, and .nextthink is synced to this instead of time. This allows time to effectively freeze if the entity is blocked, ensuring the think happens when the entity reaches the target point instead of randomly. */ +#endif +#ifdef CSQC +.float entnum; /* The entity number as its known on the server. */ +.float drawmask; /* Acts as a filter in the addentities call. */ +.float() predraw; /* Called by addentities after the filter and before the entity is actually drawn. Do your interpolation and animation in here. Should return one of the PREDRAW_* constants. */ +#endif +#if defined(QWSSQC) +.float lastruntime; /* This field used to be used to avoid running an entity multiple times in a single frame due to quakeworld's out-of-order thinks. It is no longer used by FTE due to precision issues, but may still be updated for compatibility reasons. */ +#endif +#if defined(CSQC) || defined(SSQC) +.float movetype; /* Describes how the entity moves. One of the MOVETYPE_ constants. */ +.float solid; /* Describes whether the entity is solid or not, and any special properties infered by that. Must be one of the SOLID_ constants */ +.vector origin; /* The current location of the entity in world space. Inline bsp entities (ie: ones placed by a mapper) will typically have a value of '0 0 0' in their neutral pose, as the geometry is offset from that. It is the reference point of the entity rather than the center of its geometry, for non-bsp models, this is often not a significant distinction. */ +.vector oldorigin; /* This is often used on players to reset the player back to where they were last frame if they somehow got stuck inside something due to fpu precision. Never change a player's oldorigin field to inside a solid, because that might cause them to become pemanently stuck. */ +.vector velocity; /* The direction and speed that the entity is moving in world space. */ +.vector angles; /* The eular angles the entity is facing in, in pitch, yaw, roll order. Due to a legacy bug, mdl/iqm/etc formats use +x=UP, bsp/spr/etc formats use +x=DOWN. */ +.vector avelocity; /* The amount the entity's angles change by per second. Note that this is direct eular angles, and thus the angular change is non-linear and often just looks buggy if you're changing more than one angle at a time. */ +#endif +#ifdef CSQC +.float pmove_flags; +#endif +#if defined(NQSSQC) +.vector punchangle; +#endif +#if defined(CSQC) || defined(SSQC) +.string classname; /* Identifies the class/type of the entity. Useful for debugging, also used for loading, but its value is not otherwise significant to the engine, this leaves the mod free to set it to whatever it wants and randomly test strings for values in whatever inefficient way it chooses fit. */ +#endif +#ifdef CSQC +.float renderflags; +#endif +#if defined(CSQC) || defined(SSQC) +.string model; /* The model name that was set via setmodel, in theory. Often, this is cleared to null to prevent the engine from being seen by clients while not changing modelindex. This behaviour allows inline models to remain solid yet be invisible. */ +.float frame; /* The current frame the entity is meant to be displayed in. In CSQC, note the lerpfrac and frame2 fields as well. if it specifies a framegroup, the framegroup will autoanimate in ssqc, but not in csqc. */ +#endif +#ifdef CSQC +.float frame1time; /* The absolute time into the animation/framegroup specified by .frame. */ +.float frame2; /* The alternative frame. Visible only when lerpfrac is set to 1. */ +.float frame2time; /* The absolute time into the animation/framegroup specified by .frame2. */ +.float lerpfrac; /* If 0, use frame1 only. If 1, use frame2 only. Mix them together for values between. */ +#endif +#if defined(CSQC) || defined(SSQC) +.float skin; /* The skin index to use. on a bsp entity, setting this to 1 will switch to the 'activated' texture instead. A negative value will be understood as a replacement contents value, so setting it to CONTENTS_WATER will make a movable pool of water. */ +.float effects; /* Lots of random flags that change random effects. See EF_* constants. */ +.vector mins; /* The minimum extent of the model (ie: the bottom-left coordinate relative to the entity's origin). Change via setsize. May also be changed by setmodel. */ +.vector maxs; /* like mins, but in the other direction. */ +.vector size; /* maxs-mins. Updated when the entity is relinked (by setorigin, setsize, setmodel) */ +.void() touch; +#endif +#ifdef SSQC +.void() use; +#endif +#if defined(CSQC) || defined(SSQC) +.void() think; +.void() blocked; +.float nextthink; /* The time at which the entity is next scheduled to fire its think event. For MOVETYPE_PUSH entities, this is relative to that entity's ltime field, for all other entities it is relative to the time gloal. */ +#endif +#ifdef SSQC +.entity groundentity; +.float health; +.float frags; +.float weapon; +.string weaponmodel; +.float weaponframe; +.float currentammo; +.float ammo_shells; +.float ammo_nails; +.float ammo_rockets; +.float ammo_cells; +.float items; +.float takedamage; +#endif +#if defined(CSQC) || defined(SSQC) +.entity chain; +#endif +#ifdef SSQC +.float deadflag; +.vector view_ofs; +.float button0; +.float button1; +.float button2; +.float impulse; +.float fixangle; /* Forces the clientside view angles to change to the value of .angles (has some lag). If set to 1/TRUE, the server will guess whether to send a delta or an explicit angle. If 2, will always send a delta (due to lag between transmission and acknowledgement, this cannot be spammed reliably). If 3, will always send an explicit angle. */ +.vector v_angle; /* The angles a player is viewing. +x is DOWN (pitch, yaw, roll) */ +#endif +#if defined(NQSSQC) +.float idealpitch; +#endif +#ifdef SSQC +.string netname; +#endif +#if defined(CSQC) || defined(SSQC) +.entity enemy; +.float flags; +.float colormap; +#endif +#ifdef SSQC +.float team; +.float max_health; +.float teleport_time; /* While active, prevents the player from using the +back command, also blocks waterjumping. */ +.float armortype; +.float armorvalue; +.float waterlevel; +.float watertype; +.float ideal_yaw; +.float yaw_speed; +.entity aiment; +.entity goalentity; +.float spawnflags; +.string target; +.string targetname; +.float dmg_take; +.float dmg_save; +.entity dmg_inflictor; +#endif +#if defined(CSQC) || defined(SSQC) +.entity owner; +#endif +#ifdef SSQC +.vector movedir; +.string message; +.float sounds; +.string noise; +.string noise1; +.string noise2; +.string noise3; +#endif +void end_sys_fields; +#ifdef MENU +float time; /* The current local time. Increases while paused. */ +#endif +#ifdef SSQC +float input_timelength; +vector input_angles; /* +x=DOWN */ +vector input_movevalues; +float input_buttons; +float input_impulse; +#endif +#ifdef CSQC +vector input_cursor_screen; +vector input_cursor_trace_start; +vector input_cursor_trace_endpos; +float input_cursor_trace_entnum; +#endif +#if defined(CSQC) || defined(SSQC) +int trace_endcontents; +int trace_surfaceflags; +int trace_brush_id; +int trace_brush_faceid; +int trace_surface_id; /* 1-based. 0 if not known. */ +int trace_bone_id; /* 1-based. 0 if not known. typically needs MOVE_HITMODEL. */ +int trace_triangle_id; /* 1-based. 0 if not known. */ +#endif +#ifdef CSQC +int trace_networkentity; /* Repots which ssqc entnum was hit when a csqc traceline impacts an ssqc-based brush entity. */ +#endif +#if defined(CSQC) || defined(SSQC) +vector global_gravitydir = '0 0 -1'; /* The direction gravity should act in if not otherwise specified per entity. */ +int serverid; /* The unique id of this server within the server cluster. */ +#endif +#if defined(NQSSQC) +.float lastruntime; /* This field used to be used to avoid running an entity multiple times in a single frame due to quakeworld's out-of-order thinks. It is no longer used by FTE due to precision issues, but may still be updated for compatibility reasons. */ +#endif +#if defined(CSQC) || defined(QWSSQC) +.vector punchangle; +#endif +#if defined(CSQC) || defined(SSQC) +.float gravity; +.float hull; /* Overrides the hull used by the entity for walkmove/movetogoal and not traceline/tracebox. */ +.entity movechain; /* This is a linked list of entities which will be moved whenever this entity moves, logically they are attached to this entity. */ +.void() chainmoved; /* Called when the entity is moved as a result of being part of another entity's .movechain */ +.void(float old, float new) contentstransition; /* This function is called when the entity moves between water and air. If specified, default splash sounds will be disabled allowing you to provide your own. */ +.float dimension_solid; /* This is the bitmask of dimensions which the entity is solid within. */ +.float dimension_hit; /* This is the bitmask of dimensions which the entity will be blocked by. If other.dimension_solid & self.dimension_hit, our traces will impact and not proceed. If its false, the traces will NOT impact, allowing self to pass straight through. */ +.int hitcontentsmaski; /* Traces performed for this entity will impact against surfaces that match this contents mask. */ +.float dphitcontentsmask; /* Some crappy field that inefficiently requires translating to the native contents flags. Ditch the 'dp', do it properly. */ +.float scale; /* Multiplier that resizes the entity. 1 is normal sized, 2 is double sized. scale 0 is remapped to 1. In SSQC, this is limited to 1/16th precision, with a maximum just shy of 16. */ +.float fatness; /* How many QuakeUnits to push the entity's verticies along their normals by. */ +.float alpha; /* The transparency of the entity. 1 means opaque, 0.0001 means virtually invisible. 0 is remapped to 1, for compatibility. */ +.float modelflags; /* Used to override the flags set in the entity's model. Should be set according to the MF_ constants. Use effects|=EF_NOMODELFLAGS to ignore the model's flags completely. The traileffectnum field is more versatile. */ +#endif +#ifdef SSQC +.float frame1time; /* This controls the time into the framegroup/animation named by .frame, you should increment this value according to frametime or to distance moved, depending on the sort of animation you're attempting. You may wish to avoid incrementing this while lerpfrac is still changing, to avoid wasting parts of the animation. */ +#endif +#if defined(CSQC) || defined(SSQC) +.float basebone; /* The base* frame animations are equivelent to their non-base versions, except that they only affect bone numbers below the 'basebone' value. This means that the base* animation can affect the legs of a skeletal model independantly of the normal animation fields affecting the torso area. For more complex animation than this, use skeletal objects. */ +.float baseframe; /* See basebone */ +.void() customphysics; /* Called once each physics frame, overriding the entity's .movetype field and associated logic. You'll probably want to use tracebox to move it through the world. Be sure to call .think as appropriate. */ +.entity tag_entity; +.float tag_index; +.float skeletonindex; /* This object serves as a container for the skeletal bone states used to override the animation data. */ +.vector colormod; /* Provides a colour tint for the entity. */ +.vector glowmod; +.vector gravitydir; /* Specifies the direction in which gravity acts. Must be normalised. '0 0 0' also means down. Use '0 0 1' if you want the player to be able to run on ceilings. */ +.vector(vector org, vector ang) camera_transform; /* Provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc. */ +#endif +#ifdef SSQC +.float pmove_flags; +#endif +#if defined(CSQC) || defined(SSQC) +.float geomtype; +.float friction; +.float erp; +.float jointtype; +.float mass; +.float bouncefactor; +.float bouncestop; +#endif +#if defined(CSQC) || defined(QWSSQC) +.float idealpitch; +#endif +#if defined(CSQC) || defined(SSQC) +.float pitch_speed; +.float drawflags; /* Various flags that affect lighting values and scaling. Typically set to 96 in quake for proper compatibility with DP_QC_SCALE. */ +.float abslight; /* Allows overriding light levels. Use drawflags to state that this field should actually be used. */ +.vector color; /* This affects the colour of realtime lights that were enabled via the pflags field. */ +.float light_lev; /* This is the radius of an entity's light. This is not normally used by the engine, but is used for realtime lights (ones that are enabled with the pflags field). */ +.float style; /* Used by the light util to decide how an entity's light should animate. On an entity with pflags set, this also affects realtime lights. */ +.float pflags; /* Realtime lighting flags */ +#endif +#ifdef SSQC +.float maxspeed; +.entity view2; /* defines a second viewpoint, typically displayed in a corner of the screen (also punches open pvs). */ +.vector movement; /* These are the directions that the player is currently trying to move in (ie: which +forward/+moveright/+moveup etc buttons they have held), expressed relative to that player's angles. Order is forward, right, up. */ +.float vw_index; /* This acts as a second modelindex, using the same frames etc. */ +.entity nodrawtoclient; /* This entity will not be sent to the player named by this field. They will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ +.entity drawonlytoclient; /* This entity will be sent *only* to the player named by this field. To other players they will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ +.entity viewmodelforclient; /* This entity will be sent only to the player named by this field, and this entity will be attached to the player's view as an additional weapon model. */ +.entity exteriormodeltoclient; /* This entity will be invisible to the player named by this field, except in mirrors or mirror-like surfaces, where it will be visible as normal. It may still cast shadows as normal, and generate lights+particles, depending on client settings. Does not affect how other players see the entity. */ +.float glow_size; +.float glow_color; +.float glow_trail; +.float traileffectnum; /* This should be set to the result of particleeffectnum, in order to attach a custom trail effect to an entity as it moves. */ +.float emiteffectnum; /* This should be set to the result of particleeffectnum, in order to continually spawn particles in the direction that this entity faces. */ +.float dimension_see; /* This is the dimension mask (bitfield) that the client is allowed to see. Entities and events not in this dimension mask will be invisible. */ +.float dimension_seen; /* This is the dimension mask (bitfield) that the client is visible within. Clients that cannot see this dimension mask will not see this entity. */ +.float dimension_ghost; /* If this entity is visible only within these dimensions, it will become transparent, as if a ghost. */ +.float dimension_ghost_alpha; /* If this entity is subject to dimension_ghost, this is the scaler for its alpha value. If 0, 0.5 will be used instead. */ +.float(entity playerent, float changedflags) SendEntity; /* Called by the engine whenever an entity needs to be (re)sent to a client's csprogs, either because SendFlags was set or because data was lost. Must write its data to the MSG_ENTITY buffer. Will be called at the engine's leasure. */ +.float SendFlags; /* Indicates that something in the entity has been changed, and that it needs to be updated to all players that can see it. The engine will clear it at some point, with the cleared bits appearing in the 'changedflags' argument of the SendEntity method. */ +.float Version; /* Obsolete, set a SendFlags bit instead. */ +.float clientcolors; +.float viewzoom; +.float items2; +.float playerclass; +.float hasted; +.float light_level; /* Used by hexen2 to indicate the light level where the player is standing. */ +.float pvsflags; /* Reconfigures when the entity is visible to clients */ +.float uniquespawnid; /* Incremented by 1 whenever the entity is respawned. Persists across remove calls, for when the two-second grace period is insufficient. */ +.float() customizeentityforclient; /* Called just before an entity is sent to a client (non-csqc protocol). This gives you a chance to tailor 'self' according to what 'other' should see. */ +#endif +#ifdef CSQC +.float frame3; /* Some people just don't understand how to use framegroups... */ +.float frame3time; /* .frame3 equivelent of frame1time. */ +.float lerpfrac3; /* Weight of .frame3 - .frame's weight is automatically calculated as 1-(lerpfrac+lerpfrac3+lerpfrac4), as a result these fields should NEVER add to above 1. */ +.float frame4; +.float frame4time; /* .frame4 equivelent of frame1time. */ +.float lerpfrac4; +.float forceshader; /* Contains a shader handle used to replace all surfaces upon the entity. */ +.float baseframe2; /* See basebone */ +.float baseframe1time; /* See basebone */ +.float baseframe2time; /* See basebone */ +.float baselerpfrac; /* See basebone */ +.float bonecontrol1; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol2; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol3; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol4; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol5; /* Halflife model format bone controller. This typically affects the mouth. */ +.float subblendfrac; /* Weird animation value specific to halflife models. On player models, this typically affects the spine's pitch, or yaw, or... */ +.float subblend2frac; /* Weird animation value specific to halflife models. I've no idea what this does, probably nothing for most models. */ +.float basesubblendfrac; /* See basebone */ +.float basesubblend2frac; /* See basebone */ +#endif +void(float reqid, float responsecode, string resourcebody) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */ +#ifdef SSQC +void() SpectatorConnect; /* Called when a spectator joins the game. */ +void() SpectatorDisconnect; /* Called when a spectator disconnects from the game. */ +void() SpectatorThink; /* Called each frame for each spectator. */ +void(string cmd) SV_ParseClientCommand; /* Provides QC with a way to intercept 'cmd foo' commands from the client. Very handy. Self will be set to the sending client, while the 'cmd' argument can be tokenize()d and each element retrieved via argv(argno). Unrecognised cmds MUST be passed on to the clientcommand builtin. */ +void(string dest, string from, string cmd, string info) SV_ParseClusterEvent; /* Part of cluster mode. Handles cross-node events that were sent via clusterevent, on behalf of the named client. */ +float(string sender, string body) SV_ParseConnectionlessPacket; /* Provides QC with a way to communicate between servers, or with client server browsers. Sender is the sender's ip. Body is the body of the message. You'll need to add your own password/etc support as required. Self is not valid. */ +void(float pauseduration) SV_PausedTic; /* For each frame that the server is paused, this function will be called to give the gamecode a chance to unpause the server again. the pauseduration argument says how long the server has been paused for (the time global is frozen and will not increment while paused). Self is not valid. */ +float(float newstatus) SV_ShouldPause; /* Called to give the qc a change to block pause/unpause requests. Return false for the pause request to be ignored. newstatus is 1 if the user is trying to pause the game. For the duration of the call, self will be set to the player who tried to pause, or to world if it was triggered by a server-side event. */ +void() SV_RunClientCommand; /* Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysics' after modifying the inputs. */ +void() SV_AddDebugPolygons; /* Called each video frame. This is the only place where ssqc is allowed to call the R_BeginPolygon/R_PolygonVertex/R_EndPolygon builtins. This is exclusively for debugging, and will break in anything but single player as it will not be called if the engine is not running both a client and a server. */ +void() SV_PlayerPhysics; /* Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful. */ +void() EndFrame; /* Called after non-player entities have been run at the end of the physics frame. Player physics is performed out of order and can/will still occur between EndFrame and BeginFrame. */ +string(string addr, string uinfo, string features) SV_CheckRejectConnection; /* Called to give the mod a chance to ignore connection requests based upon client protocol support or other properties. Use infoget to read the uinfo and features arguments. */ +#endif +#ifdef CSQC +void(float apilevel, string enginename, float engineversion) CSQC_Init; /* Called at startup. enginename and engineversion are arbitary hints and can take any form. enginename should be consistant between revisions, but this cannot truely be relied upon. */ +void() CSQC_WorldLoaded; /* Called after the server's model+sound precaches have been executed. Gives a chance for the qc to read the entity lump from the bsp (via getentitytoken). */ +void() CSQC_Shutdown; /* Specifies that the csqc is going down. Save your persistant settings here. */ +void(float vwidth, float vheight, float notmenu) CSQC_UpdateView; /* Called every single video frame. The CSQC is responsible for rendering the entire screen. */ +void(float vwidth, float vheight, float notmenu) CSQC_UpdateViewLoading; /* Alternative to CSQC_UpdateView, called when the engine thinks there should be a loading screen. If present, will inhibit the engine's normal loading screen, deferring to qc to draw it. */ +void(vector viewsize, float scoresshown) CSQC_DrawHud; /* Part of simple csqc, called after drawing the 3d view whenever CSQC_UpdateView is not defined. */ +void(vector viewsize, float scoresshown) CSQC_DrawScores; /* Part of simple csqc, called after CSQC_DrawHud whenever CSQC_UpdateView is not defined, and when there are no menus/console active. */ +void(string msg) CSQC_Parse_StuffCmd; /* Gives the CSQC a chance to intercept stuffcmds. Use the tokenize builtin to parse the message. Unrecognised commands would normally be localcmded, but its probably better to drop unrecognised stuffcmds completely. */ +float(string msg) CSQC_Parse_CenterPrint; /* Gives the CSQC a chance to intercept centerprints. Return true if you wish the engine to otherwise ignore the centerprint. */ +float(float save, float take, vector inflictororg) CSQC_Parse_Damage; /* Called as a result of player.dmg_save or player.dmg_take being set on the server. +Return true to completely inhibit the engine's colour shift and damage rolls, allowing you to do your own thing. +You can use punch_roll += (normalize(inflictororg-player.origin)*v_right)*(take+save)*autocvar_v_kickroll; as a modifier for the roll angle should the player be hit from the side, and slowly fade it away over time. */ +void(string printmsg, float printlvl) CSQC_Parse_Print; /* Gives the CSQC a chance to intercept sprint/bprint builtin calls. CSQC should filter by the client's current msg setting and then pass the message on to the print command, or handle them itself. */ +void() CSQC_Parse_Event; /* Called when the client receives an SVC_CGAMEPACKET. The csqc should read the data or call the error builtin if it does not recognise the message. */ +float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent; /* Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */ +__used void() CSQC_Input_Frame; /* Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc. */ +void(string rendererdescription) CSQC_RendererRestarted; /* Called by the engine after the video was restarted. This serves to notify the CSQC that any render targets that it may have cached were purged, and will need to be regenerated. */ +float(string cmd) CSQC_ConsoleCommand; /* Called if the user uses any console command registed via registercommand. */ +float(string text, string info) CSQC_ConsoleLink; /* Called if the user clicks a ^[text\infokey\infovalue^] link. Use infoget to read/check each supported key. Return true if you wish the engine to not attempt to handle the link itself. +WARNING: link text can potentially come from other players, so be careful about what you allow to be changed. */ +void(float entnum) CSQC_Ent_Spawn; /* Clumsily defined function for compat with DP. Should call spawn, set that ent's entnum field, and return the entity inside the 'self' global which will then be used for fllowing Ent_Updates. MUST NOT PARSE ANY NETWORK DATA (which makes it kinda useless). */ +void(float isnew) CSQC_Ent_Update; /* Parses the data sent by ssqc's various SendEntity functions (must use the exact same reads as the ssqc used writes - to debug this rule more easily, you may wish to use sv_csqcdebug). 'self' provides context between frames, and self.entnum should normally report which ssqc entity . Be aware that interpolation will need to happen separately. */ +void() CSQC_Ent_Remove; +float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod, float flags) CSQC_Event_Sound; +float() CSQC_Parse_TempEntity; /* Please don't use this. Use CSQC_Parse_Event and multicasts instead. +The use of serverside protocol translation to handle QW vs NQ protocols mean that you're likely to end up reading slightly different data. Which is bad. +Return true to say that you fully handled the tempentity. Return false to have the client attempt to rewind the network stream and parse the message itself. */ +#endif +#if defined(CSQC) || defined(MENU) +void(string cmdtext) GameCommand; +#endif +string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) Cef_GeneratePage; /* Provides an entrypoint to generate pages for the CEF plugin from within QC. Headers are +-separated key/value pairs (use tokenizebyseparator). */ +#ifdef SSQC +string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) HTTP_GeneratePage; /* Provides an entrypoint to generate pages for pages requested over http (sv_port_tcp+net_enable_http). Headers are +-separated key/value pairs (use tokenizebyseparator). Return __NULL__ to let the engine handle it, an empty string for a 404, and any other text for a regular 200 response. */ +#endif +#if defined(CSQC) || defined(SSQC) +void(float prevprogs) init; /* Part of FTE_MULTIPROGS. Called as soon as a progs is loaded, called at a time when entities are not valid. This is the only time when it is safe to call addprogs without field assignment. As it is also called as part of addprogs, this also gives you a chance to hook functions in modules that are already loaded (via externget+externget). */ +void() initents; /* Part of FTE_MULTIPROGS. Called after fields have been finalized. This is the first point at which it is safe to call spawn(), and is called before any entity fields have been parsed. You can use this entrypoint to send notifications to other modules. */ +#endif +#ifdef MENU +void() m_init; +void() m_shutdown; +void(vector screensize) m_draw; /* Provides the menuqc with a chance to draw. Will be called even if the menu does not have focus, so be sure to avoid that. COMPAT: screensize is not provided in DP. */ +void(vector screensize, float opaque) m_drawloading; /* Additional drawing function to draw loading screens. If opaque is set, then this function must ensure that the entire screen is overdrawn (even if just by a black drawfill). */ +float(float evtype, float scanx, float chary, float devid) Menu_InputEvent; /* If present, this is called instead of m_keydown and m_keyup +Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */ +void(float scan, float chr) m_keydown; +void(float scan, float chr) m_keyup; +void(float wantmode) m_toggle; +float(string cmd) m_consolecommand; +#endif +#ifdef SSQC +float parm17, parm18, parm19, parm20, parm21, parm22, parm23, parm24, parm25, parm26, parm27, parm28, parm29, parm30, parm31, parm32; +float parm33, parm34, parm35, parm36, parm37, parm38, parm39, parm40, parm41, parm42, parm43, parm44, parm45, parm46, parm47, parm48; +float parm49, parm50, parm51, parm52, parm53, parm54, parm55, parm56, parm57, parm58, parm59, parm60, parm61, parm62, parm63, parm64; +var float dimension_send; /* Used by multicast functionality. Multicasts (and related builtins that multicast internally) will only be sent to players where (player.dimension_see & dimension_send) is non-zero. */ +//var float dimension_default = 255; +/* Default dimension bitmask */ +#endif +#if defined(CSQC) || defined(SSQC) +__used var float physics_mode = 2; /* 0: original csqc - physics are not run +1: DP-compat. Thinks occur, but not true movetypes. +2: movetypes occur just as they do in ssqc. */ +#endif +#ifdef CSQC +float gamespeed; /* Set by the engine, this is the value of the sv_gamespeed cvar */ +float numclientseats; /* This is the number of splitscreen clients currently running on this client. */ +#endif +#if defined(CSQC) || defined(MENU) +var vector drawfontscale = '1 1 0'; /* Specifies a scaler for all text rendering. There are other ways to implement this. */ +float drawfont; /* Allows you to choose exactly which font is to be used to draw text. Fonts can be registered/allocated with the loadfont builtin. */ +const float FONT_DEFAULT = 0; +#endif +const float TRUE = 1; +const float FALSE = 0; /* File not found... */ +const float M_PI = 3.14159; +#if defined(CSQC) || defined(SSQC) +const float MOVETYPE_NONE = 0; +const float MOVETYPE_WALK = 3; +const float MOVETYPE_STEP = 4; +const float MOVETYPE_FLY = 5; +const float MOVETYPE_TOSS = 6; +const float MOVETYPE_PUSH = 7; +const float MOVETYPE_NOCLIP = 8; +const float MOVETYPE_FLYMISSILE = 9; +const float MOVETYPE_BOUNCE = 10; +const float MOVETYPE_BOUNCEMISSILE = 11; +const float MOVETYPE_FOLLOW = 12; +const float MOVETYPE_6DOF = 30; /* A glorified MOVETYPE_FLY. Players using this movetype will get some flightsim-like physics, with fully independant rotations (order-dependant transforms). */ +const float MOVETYPE_WALLWALK = 31; /* Players using this movetype will be able to orient themselves to walls, and then run up them. */ +const float MOVETYPE_PHYSICS = 32; /* Enable the use of ODE physics upon this entity. */ +const float SOLID_NOT = 0; +const float SOLID_TRIGGER = 1; +const float SOLID_BBOX = 2; +const float SOLID_SLIDEBOX = 3; +const float SOLID_BSP = 4; /* Does not collide against other SOLID_BSP entities. Normally paired with MOVETYPE_PUSH. */ +const float SOLID_CORPSE = 5; /* Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .solid value to SOLID_BBOX or so, perform the traceline, then revert the player's .solid value. */ +const float SOLID_LADDER = 20; /* Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead. */ +const float SOLID_PORTAL = 21; /* CSG subtraction volume combined with entity transformations on impact. */ +const float SOLID_PHYSICS_BOX = 32; +const float SOLID_PHYSICS_SPHERE = 33; +const float SOLID_PHYSICS_CAPSULE = 34; +const float SOLID_PHYSICS_TRIMESH = 35; +const float SOLID_PHYSICS_CYLINDER = 36; +const float GEOMTYPE_NONE = -1; +const float GEOMTYPE_SOLID = 0; +const float GEOMTYPE_BOX = 1; +const float GEOMTYPE_SPHERE = 2; +const float GEOMTYPE_CAPSULE = 3; +const float GEOMTYPE_TRIMESH = 4; +const float GEOMTYPE_CYLINDER = 5; +const float GEOMTYPE_CAPSULE_X = 6; +const float GEOMTYPE_CAPSULE_Y = 7; +const float GEOMTYPE_CAPSULE_Z = 8; +const float GEOMTYPE_CYLINDER_X = 9; +const float GEOMTYPE_CYLINDER_Y = 10; +const float GEOMTYPE_CYLINDER_Z = 11; +const float JOINTTYPE_FIXED = -1; +const float JOINTTYPE_POINT = 1; +const float JOINTTYPE_HINGE = 2; +const float JOINTTYPE_SLIDER = 3; +const float JOINTTYPE_UNIVERSAL = 4; +const float JOINTTYPE_HINGE2 = 5; +#endif +#ifdef CSQC +const float GE_MAXENTS = -1; /* Valid for getentity, ignores the entity argument. Returns the maximum number of entities which may be valid, to avoid having to poll 65k when only 100 are used. */ +const float GE_ACTIVE = 0; /* Valid for getentity. Returns whether this entity is known to the client or not. */ +const float GE_ORIGIN = 1; /* Valid for getentity. Returns the interpolated .origin. */ +const float GE_FORWARD = 2; /* Valid for getentity. Returns the interpolated forward vector. */ +const float GE_RIGHT = 3; /* Valid for getentity. Returns the entity's right vector. */ +const float GE_UP = 4; /* Valid for getentity. Returns the entity's up vector. */ +const float GE_SCALE = 5; /* Valid for getentity. Returns the entity .scale. */ +const float GE_ORIGINANDVECTORS = 6; /* Valid for getentity. Returns interpolated .origin, but also sets v_forward, v_right, and v_up accordingly. Use vectoangles(v_forward,v_up) to determine the angles. */ +const float GE_ALPHA = 7; /* Valid for getentity. Returns the entity alpha. */ +const float GE_COLORMOD = 8; /* Valid for getentity. Returns the colormod vector. */ +const float GE_PANTSCOLOR = 9; /* Valid for getentity. Returns the entity's lower color (from .colormap), as a palette range value. */ +const float GE_SHIRTCOLOR = 10; /* Valid for getentity. Returns the entity's lower color (from .colormap), as a palette range value. */ +const float GE_SKIN = 11; /* Valid for getentity. Returns the entity's .skin index. */ +const float GE_MINS = 12; /* Valid for getentity. Guesses the entity's .min vector. */ +const float GE_MAXS = 13; /* Valid for getentity. Guesses the entity's .max vector. */ +const float GE_ABSMIN = 14; /* Valid for getentity. Guesses the entity's .absmin vector. */ +const float GE_ABSMAX = 15; /* Valid for getentity. Guesses the entity's .absmax vector. */ +const float GE_MODELINDEX = 200; /* Valid for getentity. Guesses the entity's .modelindex float. */ +const float GE_MODELINDEX2 = 201; /* Valid for getentity. Guesses the entity's .vw_index float. */ +const float GE_EFFECTS = 202; /* Valid for getentity. Guesses the entity's .effects float. */ +const float GE_FRAME = 203; /* Valid for getentity. Guesses the entity's .frame float. */ +const float GE_ANGLES = 204; /* Valid for getentity. Guesses the entity's .angles vector. */ +const float GE_FATNESS = 205; /* Valid for getentity. Guesses the entity's .fatness float. */ +const float GE_DRAWFLAGS = 206; /* Valid for getentity. Guesses the entity's .drawflags float. */ +const float GE_ABSLIGHT = 207; /* Valid for getentity. Guesses the entity's .abslight float. */ +const float GE_GLOWMOD = 208; /* Valid for getentity. Guesses the entity's .glowmod vector. */ +const float GE_GLOWSIZE = 209; /* Valid for getentity. Guesses the entity's .glowsize float. */ +const float GE_GLOWCOLOUR = 210; /* Valid for getentity. Guesses the entity's .glowcolor float. */ +const float GE_RTSTYLE = 211; /* Valid for getentity. Guesses the entity's .style float. */ +const float GE_RTPFLAGS = 212; /* Valid for getentity. Guesses the entity's .pflags float. */ +const float GE_RTCOLOUR = 213; /* Valid for getentity. Guesses the entity's .color vector. */ +const float GE_RTRADIUS = 214; /* Valid for getentity. Guesses the entity's .light_lev float. */ +const float GE_TAGENTITY = 215; /* Valid for getentity. Guesses the entity's .tag_entity float. */ +const float GE_TAGINDEX = 216; /* Valid for getentity. Guesses the entity's .tag_index float. */ +const float GE_GRAVITYDIR = 217; /* Valid for getentity. Guesses the entity's .gravitydir vector. */ +const float GE_TRAILEFFECTNUM = 218; /* Valid for getentity. Guesses the entity's .traileffectnum float. */ +#endif +#ifdef SSQC +const float DAMAGE_NO = 0; +const float DAMAGE_YES = 1; +const float DAMAGE_AIM = 2; +#endif +#if defined(CSQC) || defined(SSQC) +const float CONTENT_EMPTY = -1; +const float CONTENT_SOLID = -2; +const float CONTENT_WATER = -3; +const float CONTENT_SLIME = -4; +const float CONTENT_LAVA = -5; +const float CONTENT_SKY = -6; +const float CONTENT_LADDER = -16; /* If this value is assigned to a solid_bsp's .skin field, the entity will become a ladder volume. */ +const int CONTENTBIT_NONE = 0x00000000i; +const int CONTENTBIT_SOLID = 0x00000001i; +const int CONTENTBIT_LAVA = 0x00000008i; +const int CONTENTBIT_SLIME = 0x00000010i; +const int CONTENTBIT_WATER = 0x00000020i; +const int CONTENTBIT_FTELADDER = 0x00004000i; +const int CONTENTBIT_PLAYERCLIP = 0x00010000i; +const int CONTENTBIT_MONSTERCLIP = 0x00020000i; +const int CONTENTBIT_BODY = 0x02000000i; +const int CONTENTBIT_CORPSE = 0x04000000i; +const int CONTENTBIT_Q2LADDER = 0x20000000i; /* Content bit specific to q2bsp */ +const int CONTENTBIT_SKY = 0x80000000i; +const int CONTENTBITS_POINTSOLID = CONTENTBIT_SOLID|0x00000002i|CONTENTBIT_BODY; /* Bits that traceline would normally consider solid */ +const int CONTENTBITS_BOXSOLID = CONTENTBIT_SOLID|0x00000002i|CONTENTBIT_BODY|CONTENTBIT_PLAYERCLIP; /* Bits that tracebox would normally consider solid */ +const int CONTENTBITS_FLUID = CONTENTBIT_WATER|CONTENTBIT_SLIME|CONTENTBIT_LAVA|CONTENTBIT_SKY; +const int SPA_POSITION; /* These SPA_* constants are to specify which attribute is returned by the getsurfacepointattribute builtin */ +const int SPA_S_AXIS = 1; +const int SPA_T_AXIS = 2; +const int SPA_R_AXIS = 3; /* aka: SPA_NORMAL */ +const int SPA_TEXCOORDS0 = 4; +const int SPA_LIGHTMAP0_TEXCOORDS = 5; +const int SPA_LIGHTMAP0_COLOR = 6; +const float CHAN_AUTO = 0; /* The automatic channel, play as many sounds on this channel as you want, and they'll all play, however the other channels will replace each other. */ +const float CHAN_WEAPON = 1; +const float CHAN_VOICE = 2; +const float CHAN_ITEM = 3; +const float CHAN_BODY = 4; +#endif +#if defined(QWSSQC) +const float CHANF_RELIABLE = 8; /* Only valid if the flags argument is not specified. The sound will be sent reliably, which is important if it is intended to replace looping sounds on doors etc. */ +#endif +#ifdef SSQC +const float SOUNDFLAG_RELIABLE = 1; /* The sound will be sent reliably, and without regard to phs. */ +#endif +#ifdef CSQC +const float SOUNDFLAG_ABSVOLUME = 16; /* The sample's volume is not scaled by the volume cvar. Use with caution */ +#endif +#if defined(CSQC) || defined(SSQC) +const float SOUNDFLAG_FORCELOOP = 2; /* The sound will restart once it reaches the end of the sample. */ +#endif +#ifdef CSQC +const float SOUNDFLAG_NOSPACIALISE = 4; /* The different audio channels are played at the same volume regardless of which way the player is facing, without needing to use 0 attenuation. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float SOUNDFLAG_NOREVERB = 32; /* Disables the use of underwater/reverb effects on this sound effect. */ +const float SOUNDFLAG_FOLLOW = 64; /* The sound's origin will updated to follow the emitting entity. */ +#endif +#ifdef SSQC +const float SOUNDFLAG_UNICAST = 256; /* The sound will be sent only by the player specified by msg_entity. Spectators and related splitscreen players will also hear the sound. */ +const float SOUNDFLAG_SENDVELOCITY = 512; /* The entity's current velocity will be sent to the client, only useful if doppler is enabled. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float ATTN_NONE = 0; /* Sounds with this attenuation can be heard throughout the map */ +const float ATTN_NORM = 1; /* Standard attenuation */ +const float ATTN_IDLE = 2; /* Extra attenuation so that sounds don't travel too far. */ +const float ATTN_STATIC = 3; /* Even more attenuation to avoid torches drowing out everything else throughout the map. */ +#endif +#ifdef SSQC +const float SVC_CGAMEPACKET = 83; /* Direct ssqc->csqc message. Must only be multicast. The data triggers a CSQC_Parse_Event call in the csqc for the csqc to read the contents. The server *may* insert length information for clients connected via proxies which are not able to cope with custom csqc payloads. This should only ever be used in conjunction with the MSG_MULTICAST destination. */ +const float MSG_BROADCAST = 0; /* The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family. */ +const float MSG_ONE = 1; /* The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client. */ +const float MSG_ALL = 2; /* The byte(s) will be reliably sent to all players. */ +const float MSG_INIT = 3; /* The byte(s) will be written into the signon buffer. Clients will see these messages when they connect later. This buffer is only flushed on map changes, so spamming it _WILL_ result in overflows. */ +const float MSG_MULTICAST = 4; /* The byte(s) will be written into the multicast buffer for more selective sending. Messages sent this way will never be split across packets, and using this for csqc-only messages will not break protocol translation. */ +const float MSG_ENTITY = 5; /* The byte(s) will be written into the entity buffer. This is a special value used only inside 'SendEntity' functions. */ +const float MULTICAST_ALL = 0; /* The multicast message is unreliably sent to all players. MULTICAST_ constants are valid arguments for the multicast builtin, which ignores the specified origin when given this constant. */ +const float MULTICAST_PHS = 1; /* The multicast message is unreliably sent to only players that can potentially hear the specified origin. Its quite loose. */ +const float MULTICAST_PVS = 2; /* The multicast message is unreliably sent to only players that can potentially see the specified origin. */ +const float MULTICAST_ONE = 6; /* The multicast message is unreliably sent to the player (AND ALL TRACKING SPECTATORS) specified in the msg_entity global. The specified origin is ignored. */ +const float MULTICAST_ONE_NOSPECS = 9; /* The multicast message is unreliably sent to the player specified in the msg_entity global. The specified origin is ignored. */ +const float MULTICAST_ALL_R = 3; /* The multicast message is reliably sent to all players. The specified origin is ignored. */ +const float MULTICAST_PHS_R = 4; /* The multicast message is reliably sent to only players that can potentially hear the specified origin. Players might still not receive it if they are out of range. */ +const float MULTICAST_PVS_R = 5; /* The multicast message is reliably sent to only players that can potentially see the specified origin. Players might still not receive it if they cannot see the event. */ +const float MULTICAST_ONE_R = 7; /* The multicast message is reliably sent to the player (AND ALL TRACKING SPECTATORS) specified in the msg_entity global. The specified origin is ignored */ +const float MULTICAST_ONE_R_NOSPECS = 10; /* The multicast message is reliably sent to the player specified in the msg_entity global. The specified origin is ignored */ +#endif +#if defined(QWSSQC) +const float PRINT_LOW = 0; +const float PRINT_MEDIUM = 1; +const float PRINT_HIGH = 2; +const float PRINT_CHAT = 3; +#endif +#ifdef SSQC +const float PVSF_NORMALPVS = 0; /* Filter first by PVS, then filter this entity using tracelines if sv_cullentities is enabled. */ +const float PVSF_NOTRACECHECK = 1; /* Filter strictly by PVS. */ +const float PVSF_USEPHS = 2; /* Send if we're close enough to be able to hear this entity. */ +const float PVSF_IGNOREPVS = 3; /* Ignores pvs. This entity is visible whereever you are on the map. */ +const float PVSF_NOREMOVE = 128; /* Once visible to a client, this entity will remain visible. This can be useful for csqc and corpses. */ +const string INFOKEY_P_IP = "ip"; /* The apparent ip address of the client. This may be a proxy's ip address. */ +const string INFOKEY_P_REALIP = "realip"; /* If sv_getrealip is set, this gives the ip as determine using that algorithm. */ +const string INFOKEY_P_CSQCACTIVE = "csqcactive"; /* Client has csqc enabled. CSQC ents etc will be sent to this player. */ +const string INFOKEY_P_SVPING = "svping"; +const string INFOKEY_P_GUID = "guid"; /* Some hash string which should be reasonably unique to this player's quake installation. */ +const string INFOKEY_P_CHALLENGE = "challenge"; +const string INFOKEY_P_USERID = "*userid"; +const string INFOKEY_P_DOWNLOADPCT = "download"; /* The client's download percentage for the current file. Additional files are not known. */ +const string INFOKEY_P_TRUSTLEVEL = "trustlevel"; +const string INFOKEY_P_PROTOCOL = "protocol"; /* The network protocol the client is using to connect to the server. */ +const string INFOKEY_P_VIP = "*VIP"; /* 1 if the player has the VIP 'penalty'. */ +const string INFOKEY_P_ISMUTED = "*ismuted"; /* 1 if the player has the 'mute' penalty and is not allowed to use the say/say_team commands. */ +const string INFOKEY_P_ISDEAF = "*isdeaf"; /* 1 if the player has the 'deaf' penalty and cannot see other people's say/say_team commands. */ +const string INFOKEY_P_ISCRIPPLED = "*ismuted"; /* 1 if the player has the cripple penalty, and their movement values are ignored (.movement is locked to 0). */ +const string INFOKEY_P_ISCUFFED = "*ismuted"; /* 1 if the player has the cuff penalty, and is unable to attack or use impulses(.button0 and .impulse fields are locked to 0). */ +const string INFOKEY_P_ISLAGGED = "*ismuted"; /* 1 if the player has the fakelag penalty and has an extra 200ms of lag. */ +#endif +#if defined(CSQC) || defined(SSQC) +const string INFOKEY_P_PING = "ping"; /* The player's ping time, in milliseconds. */ +const string INFOKEY_P_NAME = "name"; /* The player's name. */ +const string INFOKEY_P_SPECTATOR = "*spectator"; /* Whether the player is a spectator or not. */ +const string INFOKEY_P_TOPCOLOR = "topcolor"; /* The player's upper/shirt colour (palette index). */ +const string INFOKEY_P_BOTTOMCOLOR = "bottomcolor"; /* The player's lower/pants/trouser colour (palette index). */ +#endif +#ifdef CSQC +const string INFOKEY_P_TOPCOLOR_RGB = "topcolor_rgb"; /* The player's upper/shirt colour as an rgb value in a format usable with stov. */ +const string INFOKEY_P_BOTTOMCOLOR_RGB = "bottomcolor_rgb"; /* The player's lower/pants/trouser colour as an rgb value in a format usable with stov. */ +const string INFOKEY_P_MUTED = "ignored"; /* 0: we can see the result of the player's say/say_team commands. 1: we see no say/say_team messages from this player. Use the ignore command to toggle this value. */ +const string INFOKEY_P_VOIP_MUTED = "vignored"; /* 0: we can hear this player when they speak (assuming voip is generally enabled). 1: we ignore everything this player says. Use cl_voip_mute to change the values. */ +const string INFOKEY_P_ENTERTIME = "entertime"; /* Reads the timestamp at which the player entered the game, in terms of csqc's time global. */ +const string INFOKEY_P_FRAGS = "frags"; /* Reads a player's frag count. */ +const string INFOKEY_P_PACKETLOSS = "pl"; /* Reads a player's packetloss, as a percentage. */ +const string INFOKEY_P_VOIPSPEAKING = "voipspeaking"; /* Boolean value that says whether the given player is currently sending voice information. */ +const string INFOKEY_P_VOIPLOUDNESS = "voiploudness"; /* Only valid for the local player. Gives a value between 0 and 1 to indicate to the user how loud their mic is. */ +const string SERVERKEY_IP = "ip"; /* The address of the server we connected to. */ +const string SERVERKEY_SERVERNAME = "servername"; /* The hostname that was last passed to the connect command. */ +const string SERVERKEY_CONSTATE = "constate"; /* The current connection state. Will be set to one of: disconnected (menu-only mode), active (gamestate received and loaded), connecting(connecting, downloading, or precaching content, aka: loading screen). */ +const string SERVERKEY_TRANSFERRING = "transferring"; /* Set to the hostname of the server that we are attempting to connect or transfer to. */ +const string SERVERKEY_LOADSTATE = "loadstate"; /* loadstage, loading image name, current step, max steps +Stages are: 1=connecting, 2=serverside, 3=clientside +Key will be empty if we are not loading. */ +const string SERVERKEY_PAUSESTATE = "pausestate"; /* 1 if the server claimed to be paused. 0 otherwise */ +const string SERVERKEY_DLSTATE = "dlstate"; /* The progress of any current downloads. Empty string if no download is active, otherwise a tokenizable string containing this info: +files-remaining, total-size, unknown-sizes-flag, file-localname, file-remotename, file-percent, file-rate, file-received-bytes, file-total-bytes +If the current file info is omitted, then we are waiting for a download to start. */ +const string SERVERKEY_PROTOCOL = "protocol"; /* The protocol we are connected to the server with. */ +const string SERVERKEY_MAXPLAYERS = "maxplayers"; /* The number of player/spectator slots allocated on the server. */ +#endif +#ifdef SSQC +const float STUFFCMD_IGNOREINDEMO = 1; /* This stuffcmd will NOT be written to mvds/qtv. */ +const float STUFFCMD_DEMOONLY = 2; /* This stuffcmd will ONLY be written into mvds/qtv streams. */ +const float STUFFCMD_BROADCAST = 4; /* The stuffcmd will be broadcast server-wide (according to the mvd filters). */ +const float STUFFCMD_UNRELIABLE = 8; /* The stuffcmd might not arrive. It might also get there faster than ones sent over the reliable channel. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float FL_FLY = 1; +const float FL_SWIM = 2; +const float FL_CLIENT = 8; +const float FL_INWATER = 16; +const float FL_MONSTER = 32; +#endif +#ifdef SSQC +const float FL_GODMODE = 64; +const float FL_NOTARGET = 128; +#endif +#if defined(CSQC) || defined(SSQC) +const float FL_ITEM = 256; +const float FL_ONGROUND = 512; +const float FL_PARTIALGROUND = 1024; +const float FL_WATERJUMP = 2048; +#endif +#if defined(CSQC) || defined(NQSSQC) +const float FL_JUMPRELEASED = 4096; +#endif +#if defined(CSQC) || defined(SSQC) +const float FL_FINDABLE_NONSOLID = 16384; /* Allows this entity to be found with findradius */ +#endif +#ifdef SSQC +const float FL_LAGGEDMOVE = 65536; /* Enables anti-lag on rockets etc. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float MOVE_NORMAL = 0; +const float MOVE_NOMONSTERS = 1; /* The trace will ignore all non-solid_bsp entities. */ +const float MOVE_MISSILE = 2; /* The trace will use a bbox size of +/- 15 against entities with FL_MONSTER set. */ +const float MOVE_HITMODEL = 4; /* Traces will impact the actual mesh of the model instead of merely their bounding box. Should generally only be used for tracelines. Note that this flag is unreliable as an object can animate through projectiles. The bounding box MUST be set to completely encompass the entity or those extra areas will be non-solid (leaving a hole for things to go through). */ +const float MOVE_TRIGGERS = 16; /* This trace type will impact only triggers. It will ignore non-solid entities. */ +const float MOVE_EVERYTHING = 32; /* This type of trace will hit solids and triggers alike. Even non-solid entities. */ +#endif +#ifdef SSQC +const float MOVE_LAGGED = 64; /* Will use antilag based upon the player's latency. Traces will be performed against old positions for entities instead of their current origin. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float MOVE_ENTCHAIN = 128; /* Returns a list of entities impacted via the trace_ent.chain field */ +const float MOVE_OTHERONLY = 256; /* Traces that use this trace type will collide against *only* the entity specified via the 'other' global, and will ignore all owner/solid_not/dimension etc rules, they will still adhere to contents and bsp/bbox rules though. */ +#endif +const float RESTYPE_MODEL = 0; /* RESTYPE_* constants are used as arguments with the resourcestatus builtin. */ +const float RESTYPE_SOUND = 1; /* precache_sound */ +const float RESTYPE_PARTICLE = 2; /* particleeffectnum */ +#if defined(CSQC) || defined(MENU) +const float RESTYPE_PIC = 3; /* precache_pic. Status results are an amalgomation of the textures used by the named shader. */ +const float RESTYPE_SKIN = 4; /* setcustomskin */ +const float RESTYPE_TEXTURE = 5; /* Individual textures within shaders. These are not directly usable, but may be named as part of a skin file, or a shader. */ +#endif +const float RESSTATE_NOTKNOWN = 0; /* RESSTATE_* constants are return values from the resourcestatus builtin. The engine doesn't know about the resource if it is in this state. This means you will need to precache it. Attempting to use it anyway may result in warnings, errors, or silently succeed, depending on engine version and resource type. */ +const float RESSTATE_NOTLOADED = 1; /* The resource was precached, but has been flushed and there has not been an attempt to reload it. If you use the resource normally, chances are it'll be loaded but at the cost of a stall. */ +const float RESSTATE_LOADING = 2; /* Resources in this this state are queued for loading, and will be loaded at the engine's convienience. If you attempt to query the resource now, the engine will stall until the result is available. sounds in this state may be delayed, while models/pics/shaders may be invisible. */ +const float RESSTATE_FAILED = 3; /* Resources in this state are unusable/could not be loaded. You will get placeholders or dummy results. Queries will not stall the engine. The engine may display placeholder content. */ +const float RESSTATE_LOADED = 4; /* Resources in this state are finally usable, everything will work okay. Hurrah. Queries will not stall the engine. */ +#if defined(CSQC) || defined(SSQC) +const float EF_BRIGHTFIELD = 1; +#endif +#if defined(CSQC) || defined(NQSSQC) +const float EF_MUZZLEFLASH = 2; +#endif +#if defined(CSQC) || defined(SSQC) +const float EF_BRIGHTLIGHT = 4; +const float EF_DIMLIGHT = 8; +#endif +#if defined(QWSSQC) +const float EF_FLAG1 = 16; +const float EF_FLAG2 = 32; +#endif +#if defined(CSQC) || defined(NQSSQC) +const float EF_NODRAW = 16; +#endif +#if defined(CSQC) || defined(SSQC) +const float EF_ADDITIVE = 32; /* The entity will be drawn with an additive blend. This is NOT supported on players in any quakeworld engine. */ +const float EF_BLUE = 64; /* A blue glow */ +const float EF_RED = 128; /* A red glow */ +const float EF_GREEN = 262144; /* A green glow */ +const float EF_FULLBRIGHT = 512; /* This entity will ignore lighting */ +const float EF_NOSHADOW = 4096; /* This entity will not cast shadows */ +const float EF_NODEPTHTEST = 8192; /* This entity will be drawn over the top of other things that are closer. */ +#endif +#ifdef SSQC +const float EF_NOMODELFLAGS = 8388608; /* Surpresses the normal flags specified in the model. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float MF_ROCKET = 1; +const float MF_GRENADE = 2; +const float MF_GIB = 4; /* Regular blood trail */ +const float MF_ROTATE = 8; +const float MF_TRACER = 16; /* AKA: green scrag trail */ +const float MF_ZOMGIB = 32; /* Dark blood trail */ +const float MF_TRACER2 = 64; /* AKA: hellknight projectile trail */ +const float MF_TRACER3 = 128; /* AKA: purple vore trail */ +#endif +#ifdef SSQC +const float SL_ORG_TL = 20; /* Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen */ +const float SL_ORG_TR = 21; +const float SL_ORG_BL = 22; +const float SL_ORG_BR = 23; +const float SL_ORG_MM = 24; +const float SL_ORG_TM = 25; +const float SL_ORG_BM = 26; +const float SL_ORG_ML = 27; +const float SL_ORG_MR = 28; +#endif +#if defined(CSQC) || defined(SSQC) +const float PFLAGS_NOSHADOW = 1; /* Associated RT lights attached will not cast shadows, making them significantly faster to draw. */ +const float PFLAGS_CORONA = 2; /* Enables support of coronas on the associated rtlights. */ +#endif +#ifdef SSQC +const float PFLAGS_FULLDYNAMIC = 128; /* When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float EV_STRING = 1; +const float EV_FLOAT = 2; +const float EV_VECTOR = 3; +const float EV_ENTITY = 4; +const float EV_FIELD = 5; +const float EV_FUNCTION = 6; +const float EV_POINTER = 7; +const float EV_INTEGER = 8; +const float EV_VARIANT = 9; +#endif +hashtable gamestate; /* Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted). */ +const float HASH_REPLACE = 256; /* Used with hash_add. Attempts to remove the old value instead of adding two values for a single key. */ +const float HASH_ADD = 512; /* Used with hash_add. The new entry will be inserted in addition to the existing entry. */ +#ifdef CSQC +const float STAT_HEALTH = 0; /* Player's health. */ +const float STAT_WEAPONMODELI = 2; /* This is the modelindex of the current viewmodel (renamed from the original name 'STAT_WEAPON' due to confusions). */ +const float STAT_AMMO = 3; /* player.currentammo */ +const float STAT_ARMOR = 4; +const float STAT_WEAPONFRAME = 5; +const float STAT_SHELLS = 6; +const float STAT_NAILS = 7; +const float STAT_ROCKETS = 8; +const float STAT_CELLS = 9; +const float STAT_ACTIVEWEAPON = 10; /* player.weapon */ +const float STAT_TOTALSECRETS = 11; +const float STAT_TOTALMONSTERS = 12; +const float STAT_FOUNDSECRETS = 13; +const float STAT_KILLEDMONSTERS = 14; +const float STAT_ITEMS = 15; /* self.items | (self.items2<<23). In order to decode this stat properly, you need to use getstatbits(STAT_ITEMS,0,23) to read self.items, and getstatbits(STAT_ITEMS,23,11) to read self.items2 or getstatbits(STAT_ITEMS,28,4) to read the visible part of serverflags, whichever is applicable. */ +const float STAT_VIEWHEIGHT = 16; /* player.view_ofs_z */ +const float STAT_VIEW2 = 20; /* This stat contains the number of the entity in the server's .view2 field. */ +const float STAT_VIEWZOOM = 21; /* Scales fov and sensitiity. Part of DP_VIEWZOOM. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float STAT_USER = 32; /* Custom user stats start here (lower values are reserved for engine use). */ +#endif +#if defined(CSQC) || defined(MENU) +const float VF_MIN = 1; /* The top-left of the 3d viewport in screenspace. The VF_ values are used via the setviewprop/getviewprop builtins. */ +const float VF_MIN_X = 2; +const float VF_MIN_Y = 3; +const float VF_SIZE = 4; /* The width+height of the 3d viewport in screenspace. */ +const float VF_SIZE_X = 5; +const float VF_SIZE_Y = 6; +const float VF_VIEWPORT = 7; /* vector+vector. Two argument shortcut for VF_MIN and VF_SIZE */ +const float VF_FOV = 8; /* sets both fovx and fovy. consider using afov instead. */ +const float VF_FOVX = 9; /* horizontal field of view. does not consider aspect at all. */ +const float VF_FOVY = 10; /* vertical field of view. does not consider aspect at all. */ +const float VF_ORIGIN = 11; /* The origin of the view. Not of the player. */ +const float VF_ORIGIN_X = 12; +const float VF_ORIGIN_Y = 13; +const float VF_ORIGIN_Z = 14; +const float VF_ANGLES = 15; /* The angles the view will be drawn at. Not the angle the client reports to the server. */ +const float VF_ANGLES_X = 16; +const float VF_ANGLES_Y = 17; +const float VF_ANGLES_Z = 18; +#endif +#ifdef CSQC +const float VF_DRAWWORLD = 19; /* boolean. If set to 1, the engine will draw the world and static/persistant rtlights. If 0, the world will be skipped and everything will be fullbright. */ +const float VF_DRAWENGINESBAR = 20; /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ +const float VF_DRAWCROSSHAIR = 21; /* boolean. If set to 1, the engine will draw its default crosshair. */ +#endif +#if defined(CSQC) || defined(MENU) +const float VF_MINDIST = 23; /* The distance of the near clip plane from the view position. Should generally not be <=0, as this would introduce NANs. */ +const float VF_MAXDIST = 24; /* The distance of the far clip plane from the view position. If 0, will be considered infinite. */ +#endif +#ifdef CSQC +const float VF_CL_VIEWANGLES = 33; +const float VF_CL_VIEWANGLES_X = 34; +const float VF_CL_VIEWANGLES_Y = 35; +const float VF_CL_VIEWANGLES_Z = 36; +#endif +#if defined(CSQC) || defined(MENU) +const float VF_PERSPECTIVE = 200; /* 1: regular rendering. Fov specifies the angle. 0: isometric-style. Fov specifies the number of Quake Units each side of the viewport, and mindist restrictions are removed, pvs culling should be disabled. */ +#endif +#ifdef CSQC +#define VF_LPLAYER VF_ACTIVESEAT +const float VF_ACTIVESEAT = 202; /* The 'seat' number, used when running splitscreen. */ +#endif +#if defined(CSQC) || defined(MENU) +const float VF_AFOV = 203; /* Aproximate fov. Matches the 'fov' cvar. The engine handles the aspect ratio for you. */ +const float VF_SCREENVSIZE = 204; /* Provides a reliable way to retrieve the current virtual screen size (even if the screen is automatically scaled to retain aspect). */ +const float VF_SCREENPSIZE = 205; /* Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect). */ +#endif +#ifdef CSQC +const float VF_VIEWENTITY = 206; /* Changes the RF_EXTERNALMODEL flag on entities to match the new selection, and removes entities flaged with RF_VIEWENTITY. Requires cunning use of .entnum and typically requires calling addentities(MASK_VIEWMODEL) too. */ +#endif +#if defined(CSQC) || defined(MENU) +const float VF_RT_DESTCOLOUR = 212; /* The texture name to write colour info into, this includes both 3d and 2d drawing. +Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. +Written to by both 3d and 2d rendering. +Note that any rendertarget textures may be destroyed on video mode changes or so. Shaders can name render targets by prefixing texture names with '$rt:', or $sourcecolour. */ +const float VF_RT_SOURCECOLOUR = 209; /* The texture name to use with shaders that specify a $sourcecolour map. */ +const float VF_RT_DEPTH = 210; /* The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16bit=4,24bit=5,32bit=6), sizexy. */ +const float VF_RT_RIPPLE = 211; /* The texture name to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy. */ +const float VF_ENVMAP = 220; /* The cubemap name to use as a fallback for $reflectcube, if a shader was unable to load one. Note that this doesn't automatically change shader permutations or anything. */ +const float VF_USERDATA = 221; /* Pointer (and byte size) to an array of vec4s. This data is then globally visible to all glsl via the w_user uniform. */ +#endif +#ifdef CSQC +const float RF_VIEWMODEL = 1; /* Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob. */ +const float RF_EXTERNALMODEL = 2; /* Specifies that this entity should be displayed in mirrors (and may still cast shadows), but will not otherwise be visible. */ +#endif +#if defined(CSQC) || defined(MENU) +const float RF_DEPTHHACK = 4; /* Hacks the depth values such that the entity uses depth values as if it were closer to the screen. This is useful when combined with viewmodels to avoid weapons poking in to walls. */ +const float RF_ADDITIVE = 8; /* Shaders from this entity will temporarily be hacked to use an additive blend mode instead of their normal blend mode. */ +#endif +#ifdef CSQC +const float RF_USEAXIS = 16; /* The entity will be oriented according to the current v_forward+v_right+v_up vector values instead of the entity's .angles field. */ +const float RF_NOSHADOW = 32; /* This entity will not cast shadows. Often useful on view models. */ +const float RF_FRAMETIMESARESTARTTIMES = 64; /* Specifies that the frame1time, frame2time field are timestamps (denoting the start of the animation) rather than time into the animation. */ +const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ +const float IE_KEYUP = 1; /* Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired. */ +const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_MOUSEABS = 3; /* Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_ACCELEROMETER = 4; +const float IE_FOCUS = 5; /* Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged. */ +const float IE_JOYAXIS = 6; /* Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller. */ +const float IE_GYROSCOPE = 7; +#endif +#ifdef SSQC +const float CLIENTTYPE_DISCONNECTED = 0; /* Return value from clienttype() builtin. This entity is a player slot that is currently empty. */ +const float CLIENTTYPE_REAL = 1; /* This is a real player, and not a bot. */ +const float CLIENTTYPE_BOT = 2; /* This player slot does not correlate to a real player, any messages sent to this client will be ignored. */ +const float CLIENTTYPE_NOTACLIENT = 3; /* This entity is not even a player slot. This is typically an error condition. */ +#endif +const float FILE_READ = 0; /* The file may be read via fgets to read a single line at a time. */ +const float FILE_APPEND = 1; /* Like FILE_WRITE, but writing starts at the end of the file. */ +const float FILE_WRITE = 2; /* fputs will be used to write to the file. */ +#if defined(CSQC) || defined(SSQC) +const float FILE_READNL = 4; /* Like FILE_READ, except newlines are not special. fgets reads the entire file into a tempstring. */ +const float FILE_MMAP_READ = 5; /* The file will be loaded into memory. fgets returns a pointer to the first byte (and will always return the same value for this file). Cast this to your datatype. */ +const float FILE_MMAP_RW = 6; /* Like FILE_MMAP_READ, except any changes to the data will be written back to disk once the file is closed. */ +#endif +#ifdef CSQC +const float MASK_ENGINE = 1; /* Valid as an argument for addentities. If specified, all non-csqc entities will be added to the scene. */ +const float MASK_VIEWMODEL = 2; /* Valid as an argument for addentities. If specified, the regular engine viewmodel will be added to the scene. */ +const float PREDRAW_AUTOADD = 0; /* Valid as a return value from the predraw function. Returning this will cause the engine to automatically invoke addentity(self) for you. */ +const float PREDRAW_NEXT = 1; /* Valid as a return value from the predraw function. Returning this will simply move on to the next entity without the autoadd behaviour, so can be used for particle/invisible/special entites, or entities that were explicitly drawn with addentity. */ +const float LFIELD_ORIGIN = 0; +const float LFIELD_COLOUR = 1; +const float LFIELD_RADIUS = 2; +const float LFIELD_FLAGS = 3; +const float LFIELD_STYLE = 4; +const float LFIELD_ANGLES = 5; +const float LFIELD_FOV = 6; +const float LFIELD_CORONA = 7; +const float LFIELD_CORONASCALE = 8; +const float LFIELD_CUBEMAPNAME = 9; +const float LFIELD_AMBIENTSCALE = 10; +const float LFIELD_DIFFUSESCALE = 11; +const float LFIELD_SPECULARSCALE = 12; +const float LFIELD_ROTATION = 13; +const float LFIELD_DIETIME = 14; +const float LFIELD_RGBDECAY = 15; +const float LFIELD_RADIUSDECAY = 16; +const float LFLAG_NORMALMODE = 1; +const float LFLAG_REALTIMEMODE = 2; +const float LFLAG_LIGHTMAP = 4; +const float LFLAG_FLASHBLEND = 8; +const float LFLAG_NOSHADOWS = 256; +const float LFLAG_SHADOWMAP = 512; +const float LFLAG_CREPUSCULAR = 1024; +const float LFLAG_ORTHOSUN = 2048; +const float TEREDIT_RELOAD = 0; +const float TEREDIT_SAVE = 1; +const float TEREDIT_SETHOLE = 2; +const float TEREDIT_HEIGHT_SET = 3; +const float TEREDIT_HEIGHT_SMOOTH = 4; +const float TEREDIT_HEIGHT_SPREAD = 5; +const float TEREDIT_HEIGHT_RAISE = 6; +const float TEREDIT_HEIGHT_FLATTEN = 18; +const float TEREDIT_HEIGHT_LOWER = 7; +const float TEREDIT_TEX_KILL = 8; +const float TEREDIT_TEX_GET = 9; +const float TEREDIT_TEX_BLEND = 10; +const float TEREDIT_TEX_UNIFY = 11; +const float TEREDIT_TEX_NOISE = 12; +const float TEREDIT_TEX_BLUR = 13; +const float TEREDIT_TEX_REPLACE = 19; +const float TEREDIT_TEX_SETMASK = 25; +const float TEREDIT_WATER_SET = 14; +const float TEREDIT_MESH_ADD = 15; +const float TEREDIT_MESH_KILL = 16; +const float TEREDIT_TINT = 17; +const float TEREDIT_RESET_SECT = 20; +const float TEREDIT_RELOAD_SECT = 21; +const float TEREDIT_ENT_GET = 26; +const float TEREDIT_ENT_SET = 27; +const float TEREDIT_ENT_ADD = 28; +const float TEREDIT_ENT_COUNT = 29; +#endif +#if defined(CSQC) || defined(MENU) +const float SLIST_HOSTCACHEVIEWCOUNT = 0; +const float SLIST_HOSTCACHETOTALCOUNT = 1; +const float SLIST_MASTERQUERYCOUNT = 2; +const float SLIST_MASTERREPLYCOUNT = 3; +const float SLIST_SERVERQUERYCOUNT = 4; +const float SLIST_SERVERREPLYCOUNT = 5; +const float SLIST_SORTFIELD = 6; +const float SLIST_SORTDESCENDING = 7; +const float SLIST_TEST_CONTAINS = 0; +const float SLIST_TEST_NOTCONTAIN = 1; +const float SLIST_TEST_LESSEQUAL = 2; +const float SLIST_TEST_LESS = 3; +const float SLIST_TEST_EQUAL = 4; +const float SLIST_TEST_GREATER = 5; +const float SLIST_TEST_GREATEREQUAL = 6; +const float SLIST_TEST_NOTEQUAL = 7; +const float SLIST_TEST_STARTSWITH = 8; +const float SLIST_TEST_NOTSTARTSWITH = 9; +#endif +#ifdef MENU +float(string ext) checkextension = #1; /* + Checks if the named extension is supported by the running engine. */ + +void(string err,...) error = #2; +void(string err,...) objerror = #3; +void(string text,...) print = #4; /* Part of DP_SV_PRINT*/ +void(string text,...) bprint = #5; +void(float clientnum, string text,...) msprint = #6; +void(string text,...) cprint = #7; +vector(vector) normalize = #8; +float(vector) vlen = #9; +float(vector) vectoyaw = #10; +vector(vector) vectoangles = #11; +float() random = #12; +void(string,...) localcmd = #13; +float(string name) cvar = #14; +void(string name, string value) cvar_set = #15; +void(string text) dprint = #16; +string(float) ftos = #17; +float(float) fabs = #18; +string(vector) vtos = #19; +string(entity) etos = #20; /* Part of DP_QC_ETOS*/ +float(string) stof = #21; /* Part of FRIK_FILE, FTE_QC_INFOKEY, FTE_STRINGS, QW_ENGINE, ZQ_QC_STRINGS*/ +entity() spawn = #22; +void(entity) remove = #23; +entity(entity start, .string field, string match) find = #24; +entity(entity start, .__variant field, __variant match) findfloat = #25; /* Part of DP_QC_FINDFLOAT*/ +entity(.string field, string match) findchain = #26; /* Part of DP_QC_FINDCHAIN*/ +entity(.__variant field, __variant match) findchainfloat = #27; /* Part of DP_QC_FINDCHAINFLOAT*/ +string(string file) precache_file = #28; +string(string sample) precache_sound = #29; +void() coredump = #30; +void() traceon = #31; +void() traceoff = #32; +void(entity) eprint = #33; +float(float) rint = #34; +float(float) floor = #35; +float(float) ceil = #36; +entity(entity) nextent = #37; +float(float) sin = #38; /* Part of DP_QC_SINCOSSQRTPOW*/ +float(float) cos = #39; /* Part of DP_QC_SINCOSSQRTPOW*/ +float(float) sqrt = #40; /* Part of DP_QC_SINCOSSQRTPOW*/ +vector() randomvector = #41; +float(string name, string value, float flags) registercvar = #42; /* Part of DP_REGISTERCVAR*/ +float(float,...) min = #43; /* Part of DP_QC_MINMAXBOUND*/ +float(float,...) max = #44; /* Part of DP_QC_MINMAXBOUND*/ +float(float min,float value,float max) bound = #45; /* Part of DP_QC_MINMAXBOUND*/ +float(float,float) pow = #46; /* Part of DP_QC_SINCOSSQRTPOW*/ +void(entity src, entity dst) copyentity = #47; /* Part of DP_QC_COPYENTITY*/ +filestream(string filename, float mode) fopen = #48; /* Part of FRIK_FILE*/ +void(filestream fhandle) fclose = #49; /* Part of FRIK_FILE*/ +string(filestream fhandle) fgets = #50; /* Part of FRIK_FILE*/ +void(filestream fhandle, string s) fputs = #51; /* Part of FRIK_FILE*/ +float(string) strlen = #52; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string, optional string, optional string, optional string, optional string, optional string, optional string, optional string) strcat = #53; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s, float start, float length) substring = #54; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +vector(string) stov = #55; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string) strzone = #56; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +void(string) strunzone = #57; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +float(string) tokenize = #58; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +string(float) argv = #59; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +float() isserver = #60; +float() clientcount = #61; +float() clientstate = #62; +void(string map) changelevel = #64; +void(string sample, optional float channel, optional float volume) localsound = #65; +vector() getmousepos = #66; +float(optional float timetype) gettime = #67; +void(string data) loadfromdata = #68; +void(string data) loadfromfile = #69; +float(float val, float m) mod = #70; +string(string name) cvar_string = #71; /* Part of DP_QC_CVAR_STRING*/ +void() crash = #72; +void() stackdump = #73; +searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #74; /* Part of DP_QC_FS_SEARCH*/ +void(searchhandle handle) search_end = #75; /* Part of DP_QC_FS_SEARCH*/ +float(searchhandle handle) search_getsize = #76; /* Part of DP_QC_FS_SEARCH*/ +string(searchhandle handle, float num) search_getfilename = #77; /* Part of DP_QC_FS_SEARCH*/ +float(entity) etof = #79; +entity(float) ftoe = #80; +float(string) validstring = #81; +float(string str) altstr_count = #82; +string(string str) altstr_prepare = #83; +string(string str, float num) altstr_get = #84; +string(string str, float num, string set) altstr_set = #85; +entity(entity start, .float field, float match) findflags = #87; /* Part of DP_QC_FINDFLAGS*/ +entity(.float field, float match) findchainflags = #88; /* Part of DP_QC_FINDCHAINFLAGS*/ +void(entity ent, string mname) setmodel = #90; /* + Menuqc-specific version. */ + +void(string mname) precache_model = #91; /* + Menuqc-specific version. */ + +void(entity ent, vector neworg) setorigin = #92; /* + Menuqc-specific version. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(vector vang) makevectors = #1; /* + Takes an angle vector (pitch,yaw,roll) (+x=DOWN). Writes its results into v_forward, v_right, v_up vectors. */ + +void(entity e, vector o) setorigin = #2; /* + Changes e's origin to be equal to o. Also relinks collision state (as well as setting absmin+absmax), which is required after changing .solid */ + +void(entity e, string m) setmodel = #3; /* + Looks up m in the model precache list, and sets both e.model and e.modelindex to match. BSP models will set e.mins and e.maxs accordingly, other models depend upon the value of sv_gameplayfix_setmodelrealbox - for compatibility you should always call setsize after all pickups or non-bsp models. Also relinks collision state. */ + +void(entity e, vector min, vector max) setsize = #4; /* + Sets the e's mins and maxs fields. Also relinks collision state, which sets absmin and absmax too. */ + +#endif +#ifdef SSQC +void() breakpoint = #6; /* + Trigger a debugging event. FTE will break into the qc debugger. Other engines may crash with a debug execption. */ + +#endif +#if defined(CSQC) || defined(SSQC) +float() random = #7; /* + Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays. */ + +void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs) sound = #8; /* + Starts a sound centered upon the given entity. + chan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample + 'samp' must have been precached first + if specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed. + If flags is specified, the reliable flag in the channels argument is used for additional channels. Flags should be made from SOUNDFLAG_* constants + timeofs should be negative in order to provide a delay before the sound actually starts. */ + +vector(vector v) normalize = #9; /* + Shorten or lengthen a direction vector such that it is only one quake unit long. */ + +void(string e) error = #10; /* + Ends the game with an easily readable error message. */ + +void(string e) objerror = #11; /* + Displays a non-fatal easily readable error message concerning the self entity, including a field dump. self will be removed! */ + +float(vector v) vlen = #12; /* + Returns the square root of the dotproduct of a vector with itself. Or in other words the length of a distance vector, in quake units. */ + +float(vector v, optional entity reference) vectoyaw = #13; /* + Given a direction vector, returns the yaw angle in which that direction vector points. If an entity is passed, the yaw angle will be relative to that entity's gravity direction. */ + +entity() spawn = #14; /* + Adds a brand new entity into the world! Hurrah, you're now a parent! */ + +void(entity e) remove = #15; /* + Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After two seconds, the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid. */ + +void(vector v1, vector v2, float flags, entity ent) traceline = #16; /* + Traces a thin line through the world from v1 towards v2. + Will not collide with ent, ent.owner, or any entity who's owner field refers to ent. + The passed entity will also be used to determine whether to use a capsule trace, the contents that the trace should impact, and a couple of other extra fields that define the trace. + There are no side effects beyond the trace_* globals being written. + flags&MOVE_NOMONSTERS will not impact on non-bsp entities. + flags&MOVE_MISSILE will impact with increased size. + flags&MOVE_HITMODEL will impact upon model meshes, instead of their bounding boxes. + flags&MOVE_TRIGGERS will also stop on triggers + flags&MOVE_EVERYTHING will stop if it hits anything, even non-solid entities. + flags&MOVE_LAGGED will backdate entity positions for the purposes of this builtin according to the indicated player ent's latency, to provide lag compensation. */ + +#endif +#ifdef SSQC +entity() checkclient = #17; /* + Returns one of the player entities. The returned player will change periodically. */ + +#endif +#if defined(CSQC) || defined(SSQC) +entity(entity start, .string fld, string match) find = #18; /* + Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more. + If you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep). */ + +string(string s) precache_sound = #19; /* + Precaches a sound, making it known to clients and loading it from disk. This builtin (strongly) should be called during spawn functions. This builtin must be called for the sound before the sound builtin is called, or it might not even be heard. */ + +string(string s) precache_model = #20; /* + Precaches a model, making it known to clients and loading it from disk if it has a .bsp extension. This builtin (strongly) should be called during spawn functions. This must be called for each model name before setmodel may use that model name. + Modelindicies precached in SSQC will always be positive. CSQC precaches will be negative if they are not also on the server. */ + +#endif +#ifdef SSQC +void(entity client, string s) stuffcmd = #21; /* + Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \n. + This builtin is generally considered evil. */ + +void(entity client, float flags, string s) stuffcmdflags = #0:stuffcmdflags; /* Part of FTE_QC_STUFFCMDFLAGS + Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \n. + This (just as evil) variant allows specifying some flags too. See the STUFFCMD_* constants. */ + +#endif +#if defined(CSQC) || defined(SSQC) +entity(vector org, float rad, optional .entity chainfield) findradius = #22; /* + Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. */ + +#endif +#if defined(NQSSQC) +void(string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) bprint = #23; /* + NQ: Concatenates all arguments, and prints the messsage on the console of all connected clients. */ + +#endif +#if defined(QWSSQC) +void(float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) bprint = #23; /* + QW: Concatenates all string arguments, and prints the messsage on the console of only all clients who's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument. */ + +#endif +#if defined(NQSSQC) +void(entity client, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) sprint = #24; /* + NQ: Concatenates all string arguments, and prints the messsage on the named client's console */ + +#endif +#if defined(QWSSQC) +void(entity client, float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) sprint = #24; /* + QW: Concatenates all string arguments, and prints the messsage on the named client's console, but only if that client's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument. */ + +#endif +#if defined(CSQC) || defined(NQSSQC) +void(string s, ...) dprint = #25; /* + NQ: Prints the given message on the server's console, but only if the developer cvar is set. Arguments will be concatenated into a single message. */ + +#endif +#if defined(CSQC) || defined(QWSSQC) +void(string s, ...) dprint = #25; /* + QW: Unconditionally prints the given message on the server's console. Arguments will be concatenated into a single message. */ + +#endif +#if defined(CSQC) || defined(SSQC) +string(float val) ftos = #26; /* + Returns a tempstring containing a representation of the given float. Precision depends upon engine. */ + +string(vector val) vtos = #27; /* + Returns a tempstring containing a representation of the given vector. Precision depends upon engine. */ + +void() coredump = #28; /* + Writes out a coredump. This contains stack, globals, and field info for all ents. This can be handy for debugging. */ + +void() traceon = #29; /* + Enables tracing. This may be spammy, slow, and stuff. Set debugger 1 in order to use fte's qc debugger. */ + +void() traceoff = #30; /* + Disables tracing again. */ + +void(entity e) eprint = #31; /* + Debugging builtin that prints all fields of the given entity to the console. */ + +float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /* + Attempt to walk the entity at a given angle for a given distance. + if settraceglobals is set, the trace_* globals will be set, showing the results of the movement. + This function will trigger touch events. */ + +float() droptofloor = #34; /* + Instantly moves the entity downwards until it hits the ground. If the entity is in solid or would need to drop more than 'pr_droptofloorunits' quake units, its position will be considered invalid and the builtin will abort, returning FALSE, otherwise TRUE. */ + +void(float lightstyle, string stylestring, optional vector rgb) lightstyle = #35; /* + Specifies an auto-animating string that specifies the light intensity for entities using that lightstyle. + a is off, z is fully lit. Should be lower case only. + rgb will recolour all lights using that lightstyle. */ + +float(float) rint = #36; /* + Rounds the given float up or down to the closest integeral value. X.5 rounds away from 0 */ + +float(float) floor = #37; /* + Rounds the given float downwards, even when negative. */ + +float(float) ceil = #38; /* + Rounds the given float upwards, even when negative. */ + +float(entity ent) checkbottom = #40; /* + Expensive checks to ensure that the entity is actually sitting on something solid, returns true if it is. */ + +float(vector pos) pointcontents = #41; /* + Checks the given point to see what is there. Returns one of the SOLID_* constants. Just because a spot is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ + +float(float) fabs = #43; /* + Removes the sign of the float, making it positive if it is negative. */ + +#endif +#ifdef SSQC +vector(entity player, float missilespeed) aim = #44; /* + Returns a direction vector (specifically v_forward on error). This builtin attempts to guess what pitch angle to fire projectiles at for people that don't know about mouselook. Does not affect yaw angles. */ + +#endif +#if defined(CSQC) || defined(SSQC) +float(string) cvar = #45; /* + Returns the numeric value of the named cvar */ + +void(string, ...) localcmd = #46; /* + Adds the string to the console command queue. Commands will not be executed immediately, but rather at the start of the following frame. */ + +entity(entity) nextent = #47; /* + Returns the following entity. Skips over removed entities. Returns world when passed the last valid entity. */ + +void(vector pos, vector dir, float colour, float count) particle = #48; /* + Spawn 'count' particles around 'pos' moving in the direction 'dir', with a palette colour index between 'colour' and 'colour+8'. */ + +#define ChangeYaw changeyaw +void() changeyaw = #49; /* + Changes the self.angles_y field towards self.ideal_yaw by up to self.yaw_speed. */ + +vector(vector fwd, optional vector up) vectoangles = #51; /* + Returns the angles (+x=UP) required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning. */ + +#endif +#ifdef SSQC +void(float to, float val) WriteByte = #52; /* + Writes a single byte into a network message buffer. Typically you will find a more correct alternative to writing arbitary data. 'to' should be one of the MSG_* constants. MSG_ONE must have msg_entity set first. */ + +void(float to, float val) WriteChar = #53; +void(float to, float val) WriteShort = #54; +void(float to, float val) WriteLong = #55; +void(float to, float val) WriteCoord = #56; +void(float to, float val) WriteAngle = #57; +void(float to, string val) WriteString = #58; +void(float to, entity val) WriteEntity = #59; +#endif +#if defined(CSQC) || defined(SSQC) +float(float angle) sin = #60; /* Part of DP_QC_SINCOSSQRTPOW + Forgive me father, for I have trigonometry homework. */ + +float(float angle) cos = #61; /* Part of DP_QC_SINCOSSQRTPOW*/ +float(float value) sqrt = #62; /* Part of DP_QC_SINCOSSQRTPOW*/ +#endif +#ifdef SSQC +float(float a, float n) modulo = #0:modulo; +#endif +#if defined(CSQC) || defined(SSQC) +void(entity ent) changepitch = #63; /* Part of DP_QC_CHANGEPITCH*/ +void(entity ent, entity ignore) tracetoss = #64; +string(entity ent) etos = #65; /* Part of DP_QC_ETOS*/ +void(float step) movetogoal = #67; /* + Runs lots and lots of fancy logic in order to try to step the entity the specified distance towards its goalentity. */ + +string(string s) precache_file = #68; /* + This builtin does nothing. It was used only as a hint for pak generation. */ + +void(entity e) makestatic = #69; /* + Sends a copy of the entity's renderable fields to all clients, and REMOVES the entity, preventing further changes. This means it will be unmutable and non-solid. */ + +#endif +#ifdef SSQC +void(string mapname, optional string newmapstartspot) changelevel = #70; /* + Attempts to change the map to the named map. If 'newmapstartspot' is specified, the state of the current map will be preserved, and the argument will be passed to the next map in the 'startspot' global, and the next map will be loaded from archived state if it was previously visited. If not specified, all archived map states will be purged. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(string cvarname, string valuetoset) cvar_set = #72; /* + Instantly sets a cvar to the given string value. */ + +#endif +#ifdef SSQC +void(entity ent, string text, optional string text2, optional string text3, optional string text4, optional string text5, optional string text6, optional string text7) centerprint = #73; +#endif +#if defined(CSQC) || defined(SSQC) +void (vector pos, string samp, float vol, float atten) ambientsound = #74; +string(string str) precache_model2 = #75; +string(string str) precache_sound2 = #76; +string(string str) precache_file2 = #77; +#endif +#ifdef SSQC +void(entity player) setspawnparms = #78; +void(entity killer, entity killee) logfrag = #79; /* Part of QW_ENGINE*/ +#endif +#if defined(CSQC) || defined(SSQC) +string(entity e, string key) infokey = #80; /* Part of FTE_QC_INFOKEY, QW_ENGINE + If e is world, returns the field 'key' from either the serverinfo or the localinfo. If e is a player, returns the value of 'key' from the player's userinfo string. There are a few special exceptions, like 'ip' which is not technically part of the userinfo. */ + +#endif +#ifdef SSQC +float(entity e, string key) infokeyf = #0:infokeyf; /* + Identical to regular infokey, except returns a float. */ + +#endif +#if defined(CSQC) || defined(SSQC) +float(string) stof = #81; /* Part of FRIK_FILE, FTE_QC_INFOKEY, FTE_STRINGS, QW_ENGINE, ZQ_QC_STRINGS*/ +#endif +#ifdef SSQC +#define unicast(pl,reli) do{msg_entity = pl; multicast('0 0 0', reli?MULITCAST_ONE_R:MULTICAST_ONE);}while(0) +void(vector where, float set) multicast = #82; /* Part of FTE_QC_MULTICAST + Once the MSG_MULTICAST network message buffer has been filled with data, this builtin is used to dispatch it to the given target, filtering by pvs for reduced network bandwidth. */ + +void(entity to, string str) redirectcmd = #101; /* Part of ??MVDSV_BUILTINS + Executes a single console command, and sends the text generated by it to the specified player. The command will be executed at the end of the frame once QC is no longer running - you may wish to pre/postfix it with 'echo'. */ + +#endif +#if defined(CSQC) || defined(SSQC) +string(float style, optional __out vector rgb) getlightstyle = #0:getlightstyle; /* + Obtains the light style string for the given style. */ + +vector(float style) getlightstylergb = #0:getlightstylergb; /* + Obtains the current rgb value of the specified light style. In csqc, this is correct with regard to the current frame, while ssqc gives no guarentees about time and ignores client cvars. Note: use getlight if you want the actual light value at a point. */ + +#endif +#ifdef SSQC +void(float style, float val, optional vector rgb) lightstylestatic = #5; /* + Sets the lightstyle to an explicit numerical level. From Hexen2. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(vector start, vector mins, vector maxs, vector end, float nomonsters, entity ent) tracebox = #90; /* Part of DP_QC_TRACEBOX + Exactly like traceline, but a box instead of a uselessly thin point. Acceptable sizes are limited by bsp format, q1bsp has strict acceptable size values. */ + +vector() randomvec = #91; /* Part of DP_QC_RANDOMVEC + Returns a vector with random values. Each axis is independantly a value between -1 and 1 inclusive. */ + +vector(vector org) getlight = #92; +float(string cvarname, string defaultvalue) registercvar = #93; /* Part of DP_REGISTERCVAR + Creates a new cvar on the fly. If it does not already exist, it will be given the specified value. If it does exist, this is a no-op. + This builtin has the limitation that it does not apply to configs or commandlines. Such configs will need to use the set or seta command causing this builtin to be a noop. + In engines that support it, you will generally find the autocvar feature easier and more efficient to use. */ + +float(float a, float b, ...) min = #94; /* Part of DP_QC_MINMAXBOUND + Returns the lowest value of its arguments. */ + +float(float a, float b, ...) max = #95; /* Part of DP_QC_MINMAXBOUND + Returns the highest value of its arguments. */ + +float(float minimum, float val, float maximum) bound = #96; /* Part of DP_QC_MINMAXBOUND + Returns val, unless minimum is higher, or maximum is less. */ + +float(float value, float exp) pow = #97; /* Part of DP_QC_SINCOSSQRTPOW*/ +#endif +float(float v, optional float base) logarithm = #0:logarithm; /* + Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */ + +#if defined(CSQC) || defined(SSQC) +#define findentity findfloat +entity(entity start, .__variant fld, __variant match) findfloat = #98; /* Part of DP_QC_FINDFLOAT + Equivelent to the find builtin, but instead of comparing strings contents, this builtin compares the raw values. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value. + world is returned when there are no more entities. */ + +float(string extname) checkextension = #99; /* + Checks for an extension by its name (eg: checkextension("FRIK_FILE") says that its okay to go ahead and use strcat). + Use cvar("pr_checkextension") to see if this builtin exists. */ + +#endif +float(__variant funcref) checkbuiltin = #0:checkbuiltin; /* + Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions. Warning, if two different engines map different builtins to the same number, then this function will not tell you which will be called, only that it won't crash (the exception being #0, which are remapped as available). */ + +#ifdef SSQC +float(string builtinname) builtin_find = #100; /* + Looks to see if the named builtin is valid, and returns the builtin number it exists at. */ + +#endif +#if defined(CSQC) || defined(SSQC) +float(float value) anglemod = #102; +#endif +#ifdef SSQC +void(string slot, string picname, float x, float y, float zone, optional entity player) showpic = #104; /* Part of TEI_SHOWLMP2*/ +void(string slot, optional entity player) hidepic = #105; /* Part of TEI_SHOWLMP2*/ +void(string slot, float x, float y, float zone, optional entity player) movepic = #106; /* Part of TEI_SHOWLMP2*/ +void(string slot, string picname, optional entity player) changepic = #107; /* Part of TEI_SHOWLMP2*/ +#endif +#if defined(CSQC) || defined(SSQC) +filestream(string filename, float mode, optional float mmapminsize) fopen = #110; /* Part of FRIK_FILE + Opens a file, typically prefixed with "data/", for either read or write access. */ + +void(filestream fhandle) fclose = #111; /* Part of FRIK_FILE*/ +string(filestream fhandle) fgets = #112; /* Part of FRIK_FILE + Reads a single line out of the file. The new line character is not returned as part of the string. Returns the null string on EOF (use if not(string) to easily test for this, which distinguishes it from the empty string which is returned if the line being read is blank */ + +void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) fputs = #113; /* Part of FRIK_FILE + Writes the given string(s) into the file. For compatibility with fgets, you should ensure that the string is terminated with a \n - this will not otherwise be done for you. It is up to the engine whether dos or unix line endings are actually written. */ + +#endif +int(filestream fhandle, void *ptr, int size) fread = #0:fread; /* Part of FTE_QC_FILE_BINARY + Reads binary data out of the file. Returns truncated lengths if the read exceeds the length of the file. */ + +int(filestream fhandle, void *ptr, int size) fwrite = #0:fwrite; /* Part of FTE_QC_FILE_BINARY + Writes binary data out of the file. */ + +#define ftell fseek //c compat +int(filestream fhandle, optional int newoffset) fseek = #0:fseek; /* Part of FTE_QC_FILE_BINARY + Changes the current position of the file, if specified. Returns prior position, in bytes. */ + +int(filestream fhandle, optional int newsize) fsize = #0:fsize; /* Part of FTE_QC_FILE_BINARY + Reports the total size of the file, in bytes. Can also be used to truncate/extend the file */ + +#if defined(CSQC) || defined(SSQC) +float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s, float start, float length) substring = #116; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +vector(string s) stov = #117; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS + Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods. */ + +void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS + Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing. */ + +#endif +#ifdef SSQC +void(string cvar, float val) cvar_setf = #176; +#endif +#if defined(CSQC) || defined(SSQC) +void(string soundname, optional float channel, optional float volume) localsound = #177; /* + Plays a sound... locally... probably best not to call this from ssqc. Also disables reverb. */ + +float(string modelname, optional float queryonly) getmodelindex = #200; /* + Acts as an alternative to precache_model(foo);setmodel(bar, foo); return bar.modelindex; + If queryonly is set and the model was not previously precached, the builtin will return 0 without needlessly precaching the model. */ + +__variant(float prnum, string funcname, ...) externcall = #201; /* Part of FTE_MULTIPROGS + Directly call a function in a different/same progs by its name. + prnum=0 is the 'default' or 'main' progs. + prnum=-1 means current progs. + prnum=-2 will scan through the active progs and will use the first it finds. */ + +float(string progsname) addprogs = #202; /* Part of FTE_MULTIPROGS + Loads an additional .dat file into the current qcvm. The returned handle can be used with any of the externcall/externset/externvalue builtins. + There are cvars that allow progs to be loaded automatically. */ + +__variant(float prnum, string varname) externvalue = #203; /* Part of FTE_MULTIPROGS + Reads a global in the named progs by the name of that global. + prnum=0 is the 'default' or 'main' progs. + prnum=-1 means current progs. + prnum=-2 will scan through the active progs and will use the first it finds. */ + +void(float prnum, __variant newval, string varname) externset = #204; /* Part of FTE_MULTIPROGS + Sets a global in the named progs by name. + prnum=0 is the 'default' or 'main' progs. + prnum=-1 means current progs. + prnum=-2 will scan through the active progs and will use the first it finds. */ + +void(entity portal, float state) openportal = #207; /* + Opens or closes the portals associated with a door or some such on q2 or q3 maps. On Q2BSPs, the entity should be the 'func_areaportal' entity - its style field will say which portal to open. On Q3BSPs, the entity is the door itself, the portal will be determined by the two areas found from a preceding setorigin call. */ + +#endif +#ifdef SSQC +float(float attributes, string effectname, ...) RegisterTempEnt = #208; /* Part of FTE_PEXT_CUSTOMTENTS*/ +void(float type, vector pos, ...) CustomTempEnt = #209; /* Part of FTE_PEXT_CUSTOMTENTS*/ +float(optional float sleeptime) fork = #210; /* Part of FTE_MULTITHREADED + When called, this builtin simply returns. Twice. + The current 'thread' will return instantly with a return value of 0. The new 'thread' will return after sleeptime seconds with a return value of 1. See documentation for the 'sleep' builtin for limitations/requirements concerning the new thread. Note that QC should probably call abort in the new thread, as otherwise the function will return to the calling qc function twice also. */ + +#endif +void(optional __variant ret) abort = #211; /* Part of FTE_MULTITHREADED + QC execution is aborted. Parent QC functions on the stack will be skipped, effectively this forces all QC functions to 'return ret' until execution returns to the engine. If ret is ommited, it is assumed to be 0. */ + +#ifdef SSQC +void(float sleeptime) sleep = #212; /* Part of FTE_MULTITHREADED + Suspends the current QC execution thread for 'sleeptime' seconds. + Other QC functions can and will be executed in the interim, including changing globals and field state (but not simultaneously). + The self and other globals will be restored when the thread wakes up (or set to world if they were removed since the thread started sleeping). Locals will be preserved, but will not be protected from remove calls. + If the engine is expecting the QC to return a value (even in the parent/root function), the value 0 shall be used instead of waiting for the qc to resume. */ + +void(entity player, string key, string value) forceinfokey = #213; /* Part of FTE_FORCEINFOKEY + Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers. */ + +void(entity player, string key, void *data, int size) forceinfokeyblob = #0:forceinfokeyblob; /* + Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(vector org, vector dmin, vector dmax, float colour, float effect, float count) particle2 = #215; /* Part of FTE_HEXEN2*/ +void(vector org, vector box, float colour, float effect, float count) particle3 = #216; /* Part of FTE_HEXEN2*/ +void(vector org, float radius, float colour, float effect, float count) particle4 = #217; /* Part of FTE_HEXEN2*/ +float(float number, float quantity) bitshift = #218; /* Part of EXT_BITSHIFT*/ +void(vector pos) te_lightningblood = #219; /* Part of FTE_TE_STANDARDEFFECTBUILTINS*/ +#endif +float(string s1, string sub, optional float startidx) strstrofs = #221; /* Part of FTE_STRINGS + Returns the 0-based offset of sub within the s1 string, or -1 if sub is not in s1. + If startidx is set, this builtin will ignore matches before that 0-based offset. */ + +float(string str, float index) str2chr = #222; /* Part of FTE_STRINGS + Retrieves the character value at offset 'index'. */ + +string(float chr, ...) chr2str = #223; /* Part of FTE_STRINGS + The input floats are considered character values, and are concatenated. */ + +string(float ccase, float redalpha, float redchars, string str, ...) strconv = #224; /* Part of FTE_STRINGS + Converts quake chars in the input string amongst different representations. + ccase specifies the new case for letters. + 0: not changed. + 1: forced to lower case. + 2: forced to upper case. + redalpha and redchars switch between colour ranges. + 0: no change. + 1: Forced white. + 2: Forced red. + 3: Forced gold(low) (numbers only). + 4: Forced gold (high) (numbers only). + 5+6: Forced to white and red alternately. + You should not use this builtin in combination with UTF-8. */ + +string(float pad, string str1, ...) strpad = #225; /* Part of FTE_STRINGS + Pads the string with spaces, to ensure its a specific length (so long as a fixed-width font is used, anyway). If pad is negative, the spaces are added on the left. If positive the padding is on the right. */ + +string(infostring old, string key, string value) infoadd = #226; /* Part of FTE_STRINGS + Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \ character. */ + +string(infostring info, string key) infoget = #227; /* Part of FTE_STRINGS + Reads a named value from an infostring. The returned value is a tempstring */ + +#define strcmp strncmp +float(string s1, string s2, optional float len, optional float s1ofs, optional float s2ofs) strncmp = #228; /* Part of FTE_STRINGS + Compares up to 'len' chars in the two strings. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if the two strings are equal, a negative value if s1 appears numerically lower, and positive if s1 appears numerically higher. */ + +float(string s1, string s2) strcasecmp = #229; /* Part of FTE_STRINGS + Compares the two strings without case sensitivity. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +float(string s1, string s2, float len, optional float s1ofs, optional float s2ofs) strncasecmp = #230; /* Part of FTE_STRINGS + Compares up to 'len' chars in the two strings without case sensitivity. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +string(string s) strtrim = #0:strtrim; /* + Trims the whitespace from the start+end of the string. */ + +#if defined(CSQC) || defined(SSQC) +void() calltimeofday = #231; /* Part of FTE_CALLTIMEOFDAY + Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv. + timeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue) + The strftime builtin is more versatile and less weird. */ + +#endif +#ifdef SSQC +void(float num, float type, .__variant fld) clientstat = #232; /* + Specifies what data to use in order to send various stats, in a client-specific way. + 'num' should be a value between 32 and 127, other values are reserved. + 'type' must be set to one of the EV_* constants, one of EV_FLOAT, EV_STRING, EV_INTEGER, EV_ENTITY. + fld must be a reference to the field used, each player will be sent only their own copy of these fields. */ + +void(float num, float type, string name) globalstat = #233; /* + Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, name however, is the name of the global to read in the form of a string (pass "foo"). */ + +void(float num, float type, __variant *address) pointerstat = #0:pointerstat; /* + Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, address however, is the address of the variable you would like to use (pass &foo). */ + +float(entity player) isbackbuffered = #234; /* Part of FTE_ISBACKBUFFERED + Returns if the given player's network buffer will take multiple network frames in order to clear. If this builtin returns non-zero, you should delay or reduce the amount of reliable (and also unreliable) data that you are sending to that client. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(vector angle) rotatevectorsbyangle = #235; /* + rotates the v_forward,v_right,v_up matrix by the specified angles. */ + +void(vector fwd, vector right, vector up) rotatevectorsbyvectors = #236; +float(float mdlindex, string skinname) skinforname = #237; +#endif +#if defined(CSQC) || defined(MENU) +float(string shadername, optional string defaultshader, ...) shaderforname = #238; /* Part of FTE_FORCESHADER + Caches the named shader and returns a handle to it. + If the shader could not be loaded from disk (missing file or ruleset_allow_shaders 0), it will be created from the 'defaultshader' string if specified, or a 'skin shader' default will be used. + defaultshader if not empty should include the outer {} that you would ordinarily find in a shader. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(vector org, optional float count) te_bloodqw = #239; /* Part of FTE_TE_STANDARDEFFECTBUILTINS*/ +#endif +#ifdef SSQC +void(entity ent) te_muzzleflash = #0:te_muzzleflash; +#endif +#if defined(CSQC) || defined(SSQC) +float(vector viewpos, entity entity) checkpvs = #240; /* Part of FTE_QC_CHECKPVS*/ +#endif +#ifdef SSQC +entity(string match, optional float matchnum) matchclientname = #241; /* Part of FTE_QC_MATCHCLIENTNAME*/ +#endif +void(string destaddress, string content) sendpacket = #242; /* Part of FTE_QC_SENDPACKET + Sends a UDP packet to the specified destination. Note that the payload will be prefixed with four 255 bytes as a sort of security feature. */ + +#ifdef CSQC +vector(entity ent, float tagnum) rotatevectorsbytag = #244; +#endif +#if defined(CSQC) || defined(SSQC) +float(float dividend, float divisor) mod = #245; +#endif +#ifdef SSQC +float(optional string host, optional string user, optional string pass, optional string defaultdb, optional string driver) sqlconnect = #250; /* Part of FTE_SQL*/ +void(float serveridx) sqldisconnect = #251; /* Part of FTE_SQL*/ +float(float serveridx, void(float serveridx, float queryidx, float rows, float columns, float eof, float firstrow) callback, float querytype, string query) sqlopenquery = #252; /* Part of FTE_SQL*/ +void(float serveridx, float queryidx) sqlclosequery = #253; /* Part of FTE_SQL*/ +string(float serveridx, float queryidx, float row, float column) sqlreadfield = #254; /* Part of FTE_SQL*/ +string(float serveridx, optional float queryidx) sqlerror = #255; /* Part of FTE_SQL*/ +string(float serveridx, string data) sqlescape = #256; /* Part of FTE_SQL*/ +string(float serveridx) sqlversion = #257; /* Part of FTE_SQL*/ +float(float serveridx, float queryidx, float row, float column) sqlreadfloat = #258; /* Part of FTE_SQL*/ +int(float serveridx, float queryidx, float row, float column, __variant *ptr, int maxsize) sqlreadblob = #0:sqlreadblob; +string(float serveridx, __variant *ptr, int maxsize) sqlescapeblob = #0:sqlescapeblob; +#endif +#if defined(CSQC) || defined(SSQC) +int(string) stoi = #259; /* Part of FTE_QC_INTCONV + Converts the given string into a true integer. Base 8, 10, or 16 is determined based upon the format of the string. */ + +string(int) itos = #260; /* Part of FTE_QC_INTCONV + Converts the passed true integer into a base10 string. */ + +int(string) stoh = #261; /* Part of FTE_QC_INTCONV + Reads a base-16 string (with or without 0x prefix) as an integer. Bugs out if given a base 8 or base 10 string. :P */ + +string(int) htos = #262; /* Part of FTE_QC_INTCONV + Formats an integer as a base16 string, with leading 0s and no prefix. Always returns 8 characters. */ + +#endif +int(float) ftoi = #0:ftoi; /* Part of FTE_QC_INTCONV + Converts the given float into a true integer without depending on extended qcvm instructions. */ + +float(int) itof = #0:itof; /* Part of FTE_QC_INTCONV + Converts the given true integer into a float without depending on extended qcvm instructions. */ + +#if defined(CSQC) || defined(SSQC) +float(float modlindex, optional float useabstransforms) skel_create = #263; /* Part of FTE_CSQC_SKELETONOBJECTS + Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model. + eg: self.skeletonobject = skel_create(self.modelindex); */ + +typedef struct +{ + int sourcemodelindex; /*frame data will be imported from this model, bones must be compatible*/ + int reserved; + int firstbone; + int lastbone; + float prescale; /*0 destroys existing data, 1 retains it*/ + float scale[4]; /*you'll need to do lerpfrac manually*/ + int animation[4]; + float animationtime[4]; + /*halflife models*/ + float subblend[2]; + float controllers[5]; +} skelblend_t; +float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS + Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object. + If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */ + +float(float skel, int numblends, skelblend_t *weights, int structsize) skel_build_ptr = #0:skel_build_ptr; /* + Like skel_build, but slightly simpler. */ + +float(float skel) skel_get_numbones = #265; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrives the number of bones in the model. The valid range is 1<=bone<=numbones. */ + +string(float skel, float bonenum) skel_get_bonename = #266; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrieves the name of the specified bone. Mostly only for debugging. */ + +float(float skel, float bonenum) skel_get_boneparent = #267; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrieves which bone this bone's position is relative to. Bone 0 refers to the entity's position rather than an actual bone */ + +float(float skel, string tagname) skel_find_bone = #268; /* Part of FTE_CSQC_SKELETONOBJECTS + Finds a bone by its name, from the model that was used to create the skeletal object. */ + +vector(float skel, float bonenum) skel_get_bonerel = #269; /* Part of FTE_CSQC_SKELETONOBJECTS + Gets the bone position and orientation relative to the bone's parent. Return value is the offset, and v_forward, v_right, v_up contain the orientation. */ + +vector(float skel, float bonenum) skel_get_boneabs = #270; /* Part of FTE_CSQC_SKELETONOBJECTS + Gets the bone position and orientation relative to the entity. Return value is the offset, and v_forward, v_right, v_up contain the orientation. + Use gettaginfo for world coord+orientation. */ + +void(float skel, float bonenum, vector org, optional vector fwd, optional vector right, optional vector up) skel_set_bone = #271; /* Part of FTE_CSQC_SKELETONOBJECTS + Sets a bone position relative to its parent. If the orientation arguments are not specified, v_forward+v_right+v_up are used instead. */ + +void(float skel, float bonenum, vector org, optional vector fwd, optional vector right, optional vector up) skel_premul_bone = #272; /* Part of FTE_CSQC_SKELETONOBJECTS + Transforms a single bone by a matrix. You can use makevectors to generate a rotation matrix from an angle. */ + +void(float skel, float startbone, float endbone, vector org, optional vector fwd, optional vector right, optional vector up) skel_premul_bones = #273; /* Part of FTE_CSQC_SKELETONOBJECTS + Transforms an entire consecutive range of bones by a matrix. You can use makevectors to generate a rotation matrix from an angle, but you'll probably want to divide the angle by the number of bones. */ + +void(float skel, float bonenum, vector org, optional vector fwd, optional vector right, optional vector up) skel_postmul_bone = #0:skel_postmul_bone; /* + Transforms a single bone by a matrix. You can use makevectors to generate a rotation matrix from an angle. */ + +void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; /* Part of FTE_CSQC_SKELETONOBJECTS + Copy bone data from one skeleton directly into another. */ + +void(float skel) skel_delete = #275; /* Part of FTE_CSQC_SKELETONOBJECTS + Deletes a skeletal object. The actual delete is delayed, allowing the skeletal object to be deleted in an entity's predraw function yet still be valid by the time the addentity+renderscene builtins need it. Also uninstanciates any ragdoll currently in effect on the skeletal object. */ + +float(float modidx, string framename) frameforname = #276; /* Part of FTE_CSQC_SKELETONOBJECTS + Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error. */ + +float(float modidx, float framenum) frameduration = #277; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrieves the duration (in seconds) of the specified framegroup. */ + +void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback) processmodelevents = #0:processmodelevents; /* Part of FTE_GFX_MODELEVENTS + Calls a callback for each event that has been reached. Basetime is set to targettime. */ + +float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data) getnextmodelevent = #0:getnextmodelevent; /* + Reports the next event within a model's animation. Returns a boolean if an event was found between basetime and targettime. Writes to basetime,code,data arguments (if an event was found, basetime is set to the event's time, otherwise to targettime). + WARNING: this builtin cannot deal with multiple events with the same timestamp (only the first will be reported). */ + +float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data) getmodeleventidx = #0:getmodeleventidx; /* + Reports an indexed event within a model's animation. Writes to timestamp,code,data arguments on success. Returns false if the animation/event/model was out of range/invalid. Does not consider looping animations (retry from index 0 if it fails and you know that its a looping animation). This builtin is more annoying to use than getnextmodelevent, but can be made to deal with multiple events with the exact same timestamp. */ + +#endif +#define dotproduct(v1,v2) ((vector)(v1)*(vector)(v2)) +vector(vector v1, vector v2) crossproduct = #0:crossproduct; /* Part of FTE_QC_CROSSPRODUCT +// Small helper function to calculate the crossproduct of two vectors. */ + +#if defined(CSQC) || defined(SSQC) +float(entity pusher, vector move, vector amove) pushmove = #0:pushmove; +void(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /* Part of FTE_TERRAIN_MAP + Realtime terrain editing. Actions are the TEREDIT_ constants. */ + +typedef struct +{ + string shadername; + vector planenormal; + float planedist; + vector sdir; + float sbias; + vector tdir; + float tbias; +} brushface_t; +int(float modelidx, int brushid, brushface_t *out_faces, int maxfaces, int *out_contents) brush_get = #0:brush_get; /* Part of FTE_RAW_MAP + Queries a brush's information. You must pre-allocate the face array for the builtin to write to. Return value is the number of faces retrieved, 0 on error. */ + +int(float modelidx, brushface_t *in_faces, int numfaces, int contents, optional int brushid) brush_create = #0:brush_create; /* Part of FTE_RAW_MAP + Inserts a new brush into the model. Return value is the new brush's id. */ + +void(float modelidx, int brushid) brush_delete = #0:brush_delete; /* Part of FTE_RAW_MAP + Destroys the specified brush. */ + +float(float modelid, int brushid, int faceid, float selectedstate) brush_selected = #0:brush_selected; /* Part of FTE_RAW_MAP + Allows you to easily set transient visual properties of a brush. returns old value. selectedstate=-1 changes nothing (called for its return value). */ + +int(float modelid, int brushid, int faceid, vector *points, int maxpoints) brush_getfacepoints = #0:brush_getfacepoints; /* Part of FTE_RAW_MAP + Returns the list of verticies surrounding the given face. If face is 0, returns the center of the brush (if space for 1 point) or the mins+maxs (if space for 2 points). */ + +int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoints) brush_calcfacepoints = #0:brush_calcfacepoints; /* Part of FTE_RAW_MAP + Determines the points of the specified face, if the specified brush were to actually be created. */ + +int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults) brush_findinvolume = #0:brush_findinvolume; /* Part of FTE_RAW_MAP + Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice. */ + +void(optional entity ent, optional vector neworigin) touchtriggers = #279; /* + Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity. */ + +#endif +#ifdef SSQC +void(float buf, float fl) WriteFloat = #280; +#endif +#if defined(CSQC) || defined(SSQC) +float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* + Updates the skeletal object attached to the entity according to its origin and other properties. + if animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results. + If dollcmd is not set, the ragdoll will update (this should be done each frame). + If the doll is updated without having a valid doll, the model's default .doll will be instanciated. + commands: + doll foo.doll : sets up the entity to use the named doll file + dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix. + cleardoll : uninstanciates the doll without destroying the skeletal object. + animate 0.5 : specifies the strength of the ragdoll as a whole + animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body). + enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter. */ + +float*(float skel) skel_mmap = #282; /* + Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly). */ + +void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up) skel_set_bone_world = #283; /* + Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use. */ + +string(float modidx, float framenum) frametoname = #284; +string(float modidx, float skin) skintoname = #285; +float(float resourcetype, float tryload, string resourcename) resourcestatus = #286; /* + resourcetype must be one of the RESTYPE_ constants. Returns one of the RESSTATE_ constants. Tryload 0 is a query only. Tryload 1 will attempt to reload the content if it was flushed. */ + +#endif +hashtable(float tabsize, optional float defaulttype) hash_createtab = #287; /* Part of FTE_QC_HASHTABLES + Creates a hash table object with at least 'tabsize' slots. hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return). */ + +void(hashtable table) hash_destroytab = #288; /* Part of FTE_QC_HASHTABLES + Destroys a hash table object. */ + +void(hashtable table, string name, __variant value, optional float typeandflags) hash_add = #289; /* Part of FTE_QC_HASHTABLES + Adds the given key with the given value to the table. + If flags&HASH_REPLACE, the old value will be removed, if not set then multiple values may be added for a single key, they won't overwrite. + The type argument describes how the value should be stored and saved to files. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games. */ + +__variant(hashtable table, string name, optional __variant deflt, optional float requiretype, optional float index) hash_get = #290; /* Part of FTE_QC_HASHTABLES + looks up the specified key name in the hash table. returns deflt if key was not found. If stringsonly=1, the return value will be in the form of a tempstring, otherwise it'll be the original value argument exactly as it was. If requiretype is specified, then values not of the specified type will be ignored. Hurrah for multiple types with the same name. */ + +__variant(hashtable table, string name) hash_delete = #291; /* Part of FTE_QC_HASHTABLES + removes the named key. returns the value of the object that was destroyed, or 0 on error. */ + +string(hashtable table, float idx) hash_getkey = #292; /* Part of FTE_QC_HASHTABLES + gets some random key name. add+delete can change return values of this, so don't blindly increment the key index if you're removing all. */ + +float(string name) checkcommand = #294; /* Part of FTE_QC_CHECKCOMMAND + Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist. */ + +string(string s) argescape = #295; /* + Marks up a string so that it can be reliably tokenized as a single argument later. */ + +#ifdef SSQC +void(string dest, string from, string cmd, string info) clusterevent = #0:clusterevent; /* + Only functions in mapcluster mode. Sends an event to whichever server the named player is on. The destination server can then dispatch the event to the client or handle it itself via the SV_ParseClusterEvent entrypoint. If dest is empty, the event is broadcast to ALL servers. If the named player can't be found, the event will be returned to this server with the cmd prefixed with 'error:'. */ + +string(entity player, optional string newnode) clustertransfer = #0:clustertransfer; /* + Only functions in mapcluster mode. Initiate transfer of the player to a different node. Can take some time. If dest is specified, returns null on error. Otherwise returns the current/new target node (or null if not transferring). */ + +#endif +#if defined(CSQC) || defined(SSQC) +float(float mdlidx) modelframecount = #0:modelframecount; /* + Retrieves the number of frames in the specified model. */ + +#endif +#if defined(CSQC) || defined(MENU) +void() clearscene = #300; /* + Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values. */ + +#endif +#ifdef CSQC +void(float mask) addentities = #301; /* + Walks through all entities effectively doing this: + if (ent.drawmask&mask){ if (!ent.predaw()) addentity(ent); } + If mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list. + If mask&MASK_STDVIEWMODEL then the default view model will also be added. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(entity ent) addentity = #302; /* + Copies the entity fields into a new rentity for later rendering via addscene. */ + +#endif +#ifdef CSQC +void(entity ent) removeentity = #0:removeentity; /* + Undoes all addentities added to the scene from the given entity, without removing ALL entities (useful for splitscreen/etc, readd modified versions as desired). */ + +typedef float vec2[2]; +typedef float vec3[3]; +typedef float vec4[4]; +typedef struct trisoup_simple_vert_s {vec3 xyz;vec2 st;vec4 rgba;} trisoup_simple_vert_t; +void(string texturename, int flags, struct trisoup_simple_vert_s *verts, int *indexes, int numindexes) addtrisoup_simple = #0:addtrisoup_simple; /* + Adds the specified trisoup into the scene as additional geometry. This permits caching geometry to reduce builtin spam. Indexes are a triangle list (so eg quads will need 6 indicies to form two triangles). NOTE: this is not going to be a speedup over polygons if you're still generating lots of new data every frame. */ + +#endif +#if defined(CSQC) || defined(MENU) +#define setviewprop setproperty +float(float property, ...) setproperty = #303; /* + Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats. */ + +void() renderscene = #304; /* + Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy. + The scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame. + You may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView. */ + +#endif +#ifdef CSQC +float(vector org, float radius, vector lightcolours, optional float style, optional string cubemapname, optional float pflags) dynamiclight_add = #305; /* + Adds a temporary dlight, ready to be drawn via addscene. Cubemap orientation will be read from v_forward/v_right/v_up. */ + +#endif +void(string texturename, optional float flags, optional float is2d) R_BeginPolygon = #306; /* + Specifies the shader to use for the following polygons, along with optional flags. + If is2d, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects. */ + +void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307; /* + Specifies a polygon vertex with its various properties. */ + +void() R_EndPolygon = #308; /* + Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader. */ + +#if defined(CSQC) || defined(MENU) +#define getviewprop getproperty +__variant(float property) getproperty = #309; /* + Retrieve a currently-set (typically view) property, allowing you to read the current viewport or other things. Due to cheat protection, certain values may be unretrievable. */ + +#endif +#ifdef CSQC +vector (vector v) unproject = #310; /* + Transform a 2d screen-space point (with depth) into a 3d world-space point, according the various origin+angle+fov etc settings set via setproperty. */ + +vector (vector v) project = #311; /* + Transform a 3d world-space point into a 2d screen-space point, according the various origin+angle+fov etc settings set via setproperty. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(vector pos, vector size, float alignflags, string text) drawtextfield = #0:drawtextfield; /* + Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3. */ + +#endif +#ifdef CSQC +void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional float drawflag) drawline = #315; /* + Draws a 2d line between the two 2d points. */ + +float(string name) iscachedpic = #316; /* + Checks to see if the image is currently loaded. Engines might lie, or cache between maps. */ + +string(string name, optional float trywad) precache_pic = #317; /* + Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(string imagename, int width, int height, void *pixeldata, optional int datasize, optional int format) r_uploadimage = #0:r_uploadimage; /* Part of FTE_CSQC_RAWIMAGES + Updates a texture with the specified rgba data. Will be created if needed. If blobsize is specified then the image is decoded (eg .ktx or .dds data) instead of being raw R8G8B8A data. You'll typically want shaderforname to also generate a shader to use the texture. */ + +int*(string filename, __out int width, __out int height) r_readimage = #0:r_readimage; /* Part of FTE_CSQC_RAWIMAGES + Reads and decodes an image from disk, providing raw R8G8B8A pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it. */ + +#endif +#ifdef CSQC +#define draw_getimagesize drawgetimagesize +vector(string picname) drawgetimagesize = #318; /* + Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution. */ + +void(string name) freepic = #319; /* + Tells the engine that the image is no longer needed. The image will appear to be new the next time its needed. */ + +float(vector position, float character, vector size, vector rgb, float alpha, optional float drawflag) drawcharacter = #320; /* + Draw the given quake character at the given position. + If flag&4, the function will consider the char to be a unicode char instead (or display as a ? if outside the 32-127 range). + size should normally be something like '8 8 0'. + rgb should normally be '1 1 1' + alpha normally 1. + Software engines may assume the named defaults. + Note that ALL text may be rescaled on the X axis due to variable width fonts. The X axis may even be ignored completely. */ + +float(vector position, string text, vector size, vector rgb, float alpha, optional float drawflag) drawrawstring = #321; /* + Draws the specified string without using any markup at all, even in engines that support it. + If UTF-8 is globally enabled in the engine, then that encoding is used (without additional markup), otherwise it is raw quake chars. + Software engines may assume a size of '8 8 0', rgb='1 1 1', alpha=1, flag&3=0, but it is not an error to draw out of the screen. */ + +float(vector position, string pic, vector size, vector rgb, float alpha, optional float drawflag) drawpic = #322; /* + Draws an shader within the given 2d screen box. Software engines may omit support for rgb+alpha, but must support rescaling, and must clip to the screen without crashing. */ + +float(vector position, vector size, vector rgb, float alpha, optional float drawflag) drawfill = #323; /* + Draws a solid block over the given 2d box, with given colour, alpha, and blend mode (specified via flags). + flags&3=0 simple blend. + flags&3=1 additive blend */ + +void(float x, float y, float width, float height) drawsetcliparea = #324; /* + Specifies a 2d clipping region (aka: scissor test). 2d draw calls will all be clipped to this 2d box, the area outside will not be modified by any 2d draw call (even 2d polygons). */ + +void(void) drawresetcliparea = #325; /* + Reverts the scissor/clip area to the whole screen. */ + +float(vector position, string text, vector size, vector rgb, float alpha, float drawflag) drawstring = #326; /* + Draws a string, interpreting markup and recolouring as appropriate. */ + +float(string text, float usecolours, optional vector fontsize) stringwidth = #327; /* + Calculates the width of the screen in virtual pixels. If usecolours is 1, markup that does not affect the string width will be ignored. Will always be decoded as UTF-8 if UTF-8 is globally enabled. + If the char size is not specified, '8 8 0' will be assumed. */ + +void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, optional float drawflag) drawsubpic = #328; /* + Draws a rescaled subsection of an image to the screen. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(vector pivot, vector mins, vector maxs, string pic, vector rgb, float alpha, float angle) drawrotpic = #0:drawrotpic; /* + Draws an image rotating at the pivot. To rotate in the center, use mins+maxs of half the size with mins negated. Angle is in degrees. */ + +void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector txsize, vector rgb, vector alphaandangles) drawrotsubpic = #0:drawrotsubpic; /* + Overcomplicated draw function for over complicated people. Positions follow drawrotpic, while texture coords follow drawsubpic. Due to argument count limitations in builtins, the alpha value and angles are combined into separate fields of a vector (tip: use fteqcc's [alpha, angle] feature. */ + +#endif +#ifdef CSQC +#define getstati_punf(stnum) (float)(__variant)getstati(stnum) +int(float stnum) getstati = #330; /* + Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat. Use getstati_punf if you wish to type-pun a float stat as an int to avoid truncation issues in DP. */ + +#define getstatbits getstatf +float(float stnum, optional float firstbit, optional float bitcount) getstatf = #331; /* + Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat (converted into a float, so there are no VM dependancies). */ + +string(float stnum) getstats = #332; /* + Retrieves the value of the given EV_STRING stat, as a tempstring. + Older engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but FTE Quake uses a separate namespace for string stats and has a much higher length limit. */ + +__variant(float playernum, float statnum, float stattype) getplayerstat = #0:getplayerstat; /* + Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits. */ + +void(entity e, float mdlindex) setmodelindex = #333; /* + Sets a model by precache index instead of by name. Otherwise identical to setmodel. */ + +string(float mdlindex) modelnameforindex = #334; /* + Retrieves the name of the model based upon a precache index. This can be used to reduce csqc network traffic by enabling model matching. */ + +#endif +#if defined(CSQC) || defined(SSQC) +float(string effectname) particleeffectnum = #335; /* Part of DP_ENT_TRAILEFFECTNUM, FTE_SV_POINTPARTICLES + Precaches the named particle effect. If your effect name is of the form 'foo.bar' then particles/foo.cfg will be loaded by the client if foo.bar was not already defined. + Different engines will have different particle systems, this specifies the QC API only. */ + +void(float effectnum, entity ent, vector start, vector end) trailparticles = #336; /* Part of FTE_SV_POINTPARTICLES + Draws the given effect between the two named points. If ent is not world, distances will be cached in the entity in order to avoid framerate dependancies. The entity is not otherwise used. */ + +void(float effectnum, vector origin, optional vector dir, optional float count) pointparticles = #337; /* Part of FTE_SV_POINTPARTICLES + Spawn a load of particles from the given effect at the given point traveling or aiming along the direction specified. The number of particles are scaled by the count argument. + For regular particles, the dir vector is multiplied by the 'veladd' property (while orgadd will push the particles along it). Decals will use it as a hint to align to the correct surface. In both cases, it should normally be a unit vector, but other lengths will still work. If it has length 0 then FTE will assume downwards. */ + +#endif +#ifdef CSQC +void(string s, ...) cprint = #338; /* + Print into the center of the screen just as ssqc's centerprint would appear. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(string s, ...) print = #339; /* Part of DP_SV_PRINT + Unconditionally print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar). */ + +#endif +#ifdef CSQC +string(float keynum) keynumtostring = #340; /* + Returns a hunam-readable name for the given keycode, as a tempstring. */ + +#endif +#ifdef MENU +string(float keynum) keynumtostring_csqc = #340; /* + Returns a hunam-readable name for the given keycode, as a tempstring. */ + +#endif +#ifdef CSQC +float(string keyname) stringtokeynum = #341; /* + Looks up the key name in the same way that the bind command would, returning the keycode for that key. */ + +#endif +#ifdef MENU +float(string keyname) stringtokeynum_csqc = #341; /* + Looks up the key name in the same way that the bind command would, returning the keycode for that key. */ + +#endif +#if defined(CSQC) || defined(MENU) +string(float keynum) getkeybind = #342; /* + Returns the current binding for the given key (returning only the command executed when no modifiers are pressed). */ + +void(float usecursor, optional string cursorimage, optional vector hotspot, optional float scale) setcursormode = #343; /* + Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking). If the image name is specified, the engine will use that image for a cursor (use an empty string to clear it again), in a way that will not conflict with the console. Images specified this way will be hardware accelerated, if supported by the platform/port. */ + +float(float effective) getcursormode = #0:getcursormode; /* + Reports the cursor mode this module previously attempted to use. If 'effective' is true, reports the cursor mode currently active (if was overriden by a different module which has precidence, for instance, or if there is only a touchscreen and no mouse). */ + +#endif +#ifdef CSQC +vector() getmousepos = #344; /* + Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods. */ + +float(float inputsequencenum) getinputstate = #345; /* + Looks up an input frame from the log, setting the input_* globals accordingly. + The sequence number range used for prediction should normally be servercommandframe < sequence <= clientcommandframe. + The sequence equal to clientcommandframe will change between input frames. */ + +void(float sens) setsensitivityscaler = #346; /* + Temporarily scales the player's mouse sensitivity based upon something like zoom, avoiding potential cvar saving and thus corruption. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(entity ent) runstandardplayerphysics = #347; /* + Perform the engine's standard player movement prediction upon the given entity using the input_* globals to describe movement. */ + +#endif +#ifdef CSQC +string(float playernum, string keyname) getplayerkeyvalue = #348; /* + Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver. + Also includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness. */ + +float(float playernum, string keyname, optional float assumevalue) getplayerkeyfloat = #0:getplayerkeyfloat; /* + Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ + +int(float playernum, string keyname, optional void *outptr, int size) getplayerkeyblob = #0:getplayerkeyblob; /* + Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ + +#endif +#ifdef SSQC +int(string keyname, optional void *outptr, int size) getlocalinfo = #0:getlocalinfo; /* + Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ + +void(string keyname, optional void *outptr, int size) setlocalinfo = #0:setlocalinfo; /* + Changes the server's localinfo. This data will be available for the following map, and will *usually* reload with saved games. */ + +#endif +#if defined(CSQC) || defined(MENU) +float() isdemo = #349; /* + Returns if the client is currently playing a demo or not. Returns 2 when playing an mvd (where other player's stats can be queried, or the pov can be changed freely). */ + +#endif +#ifdef CSQC +float() isserver = #350; /* + Returns non-zero whenever the local console can directly affect the server (ie: listen servers or single-player). Compat note: DP returns 0 for single-player. */ + +void(vector origin, vector forward, vector right, vector up, optional float reverbtype) SetListener = #351; /* + Sets the position of the view, as far as the audio subsystem is concerned. This should be called once per CSQC_UpdateView as it will otherwise revert to default. For reverbtype, see setup_reverb or treat as 'underwater'. */ + +typedef struct { + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + vector flReflectionsPan; + float flLateReverbGain; + float flLateReverbDelay; + vector flLateReverbPan; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; +} reverbinfo_t; +void(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t) setup_reverb = #0:setup_reverb; /* Part of FTE_CSQC_REVERB + Reconfigures a reverb slot for weird effects. Slot 0 is reserved for no effects. Slot 1 is reserved for underwater effects. Reserved slots will be reinitialised on snd_restart, but can otherwise be changed. These reverb slots can be activated with SetListener. Note that reverb will currently only work when using OpenAL. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(string cmdname) registercommand = #352; /* + Register the given console command, for easy console use. + Console commands that are later used will invoke CSQC_ConsoleCommand. */ + +#endif +#if defined(CSQC) || defined(SSQC) +float(entity ent) wasfreed = #353; /* + Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust. */ + +string(string key) serverkey = #354; /* + Look up a key in the server's public serverinfo string */ + +float(string key, optional float assumevalue) serverkeyfloat = #0:serverkeyfloat; /* + Version of serverkey that returns the value as a float (which avoids tempstrings). */ + +int(int buf, string key, optional void *ptr, int size) serverkeyblob = #0:serverkeyblob; /* + Version of serverkey that can obtain entire serverinfo, localinfo, or (local)userinfo blobs. Returns blob size */ + +#endif +#ifdef SSQC +void(int buf, string key, void *ptr, optional int size) setserverkey = #0:setserverkey; /* + Changes the server's serverinfo. */ + +#endif +#ifdef CSQC +string(optional string resetstring) getentitytoken = #355; /* + Grab the next token in the map's entity lump. + If resetstring is not specified, the next token will be returned with no other sideeffects. + If empty, will reset from the map before returning the first token, probably {. + If not empty, will tokenize from that string instead. + Always returns tempstrings. */ + +#endif +#if defined(CSQC) || defined(MENU) +float(string s) findfont = #356; /* Part of DP_GFX_FONTS + Looks up a named font slot. Matches the actual font name as a last resort. */ + +float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357; /* Part of DP_GFX_FONTS + too convoluted for me to even try to explain correct usage. Try drawfont = loadfont("", "cour", "16", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows.. */ + +#endif +#ifdef CSQC +void(string evname, string evargs, ...) sendevent = #359; /* + Invoke CSEv_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors. */ + +float() readbyte = #360; +float() readchar = #361; +float() readshort = #362; +float() readlong = #363; +float() readcoord = #364; +float() readangle = #365; +string() readstring = #366; +float() readfloat = #367; +float() readentitynum = #368; +float(string modelname, float(float isnew) updatecallback, float flags) deltalisten = #371; /* + Specifies a per-modelindex callback to listen for engine-networking entity updates. Such entities are automatically interpolated by the engine (unless flags specifies not to). + The various standard entity fields will be overwritten each frame before the updatecallback function is called. */ + +float(vector org, float radius, vector rgb) dynamiclight_spawnstatic = #0:dynamiclight_spawnstatic; /* + Creates a static persistent light at the given position with the specified colour. Additional properties must be set via dynamiclight_set. */ + +__variant(float lno, float fld) dynamiclight_get = #372; /* + Retrieves a property from the given dynamic/rt light. Return type depends upon the light field requested. */ + +void(float lno, float fld, __variant value) dynamiclight_set = #373; /* + Changes a property on the given dynamic/rt light. Value type depends upon the light field to be changed. */ + +string(float efnum, float body) particleeffectquery = #374; /* + Retrieves either the name or the body of the effect with the given number. The effect body is regenerated from internal state, and can be changed before being reapplied via the localcmd builtin. */ + +void(string shadername, vector origin, vector up, vector side, vector rgb, float alpha) adddecal = #375; /* + Adds a temporary clipped decal shader to the scene, centered at the given point with given orientation. Will be drawn by the next renderscene call, and freed by the next clearscene call. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(entity e, string skinfilename, optional string skindata) setcustomskin = #376; /* Part of FTE_QC_CUSTOMSKINS + Sets an entity's skin overrides to a new skin object. Releases the entities old skin (refcounted). */ + +#endif +#ifdef CSQC +float(string skinfilename, optional string skindata) loadcustomskin = #377; /* + Creates a new skin object and returns it. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format: + surfacename,shadername - makes the named surface use the named shader + replace "surfacename" "shadername" - same. + qwskin "foo" - use an unmodified quakeworld player skin (including crop+repalette rules) + q1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red + q1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue + compose "surfacename" "shader" "imagename@x,y:w,h$s,t,s2,t2?r,g,b,a" - compose a skin texture from multiple images. + The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line. + Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). Must be matched with a releasecustomskin call later, and is pointless without applycustomskin. */ + +void(entity e, float skinobj) applycustomskin = #378; /* + Updates the entity's custom skin (refcounted). */ + +void(float skinobj) releasecustomskin = #379; /* + Lets the engine know that the skin will no longer be needed. Thanks to refcounting any ents with the skin already applied will retain their skin until later changed. It is valid to destroy a skin just after applying it to an ent in the same function that it was created in, as the skin will only be destroyed once its refcount rops to 0. */ + +#endif +__variant*(int size) memalloc = #384; /* Part of FTE_MEMALLOC + Allocate an arbitary block of memory */ + +void(__variant *ptr) memfree = #385; /* Part of FTE_MEMALLOC + Frees a block of memory that was allocated with memfree */ + +void(__variant *dst, __variant *src, int size) memcpy = #386; /* Part of FTE_MEMALLOC + Copys memory from one location to another */ + +void(__variant *dst, int val, int size) memfill8 = #387; /* Part of FTE_MEMALLOC + Sets an entire block of memory to a specified value. Pretty much always 0. */ + +__variant(__variant *dst, float ofs) memgetval = #388; /* + Looks up the 32bit value stored at a pointer-with-offset. */ + +void(__variant *dst, float ofs, __variant val) memsetval = #389; /* + Changes the 32bit value stored at the specified pointer-with-offset. */ + +__variant*(__variant *base, float ofs) memptradd = #390; /* + Perform some pointer maths. Woo. */ + +float(string s) memstrsize = #0:memstrsize; /* + strlen, except ignores utf-8 */ + +#if defined(CSQC) || defined(MENU) +string(string conname, string field, optional string newvalue) con_getset = #391; /* Part of FTE_CSQC_ALTCONSOLES + Reads or sets a property from a console object. The old value is returned. Iterrate through consoles with the 'next' field. Valid properties: title, name, next, unseen, markup, forceutf8, close, clear, hidden, linecount */ + +void(string conname, string messagefmt, ...) con_printf = #392; /* Part of FTE_CSQC_ALTCONSOLES + Prints onto a named console. */ + +void(string conname, vector pos, vector size, float fontsize) con_draw = #393; /* Part of FTE_CSQC_ALTCONSOLES + Draws the named console. */ + +float(string conname, float inevtype, float parama, float paramb, float paramc) con_input = #394; /* Part of FTE_CSQC_ALTCONSOLES + Forwards input events to the named console. Mouse updates should be absolute only. */ + +#endif +#ifdef CSQC +void(string newcaption) setwindowcaption = #0:setwindowcaption; /* Part of FTE_CSQC_WINDOWCAPTION + Replaces the title of the game window, as seen when task switching or just running in windowed mode. */ + +#endif +#if defined(CSQC) || defined(MENU) +float() cvars_haveunsaved = #0:cvars_haveunsaved; /* + Returns true if any archived cvar has an unsaved value. */ + +#endif +float(entity e, float nowreadonly) entityprotection = #0:entityprotection; /* + Changes the protection on the specified entity to protect it from further edits from QC. The return value is the previous setting. Note that this can be used to unprotect the world, but doing so long term is not advised as you will no longer be able to detect invalid entity references. Also, world is not networked, so results might not be seen by clients (or in other words, world.avelocity_y=64 is a bad idea). */ + +#if defined(CSQC) || defined(SSQC) +entity(entity from, optional entity to) copyentity = #400; /* Part of DP_QC_COPYENTITY + Copies all fields from one entity to another. */ + +#endif +#ifdef SSQC +void(entity ent, float colours) setcolors = #401; /* + Changes a player's colours. The bits 0-3 are the lower/trouser colour, bits 4-7 are the upper/shirt colours. */ + +#endif +#if defined(CSQC) || defined(SSQC) +entity(.string field, string match, optional .entity chainfield) findchain = #402; /* Part of DP_QC_FINDCHAIN*/ +entity(.float fld, float match, optional .entity chainfield) findchainfloat = #403; /* Part of DP_QC_FINDCHAINFLOAT*/ +void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404; /* Part of DP_SV_EFFECT + Spawns a self-animating sprite */ + +void(vector org, vector dir, float count) te_blood = #405; /* Part of DP_TE_BLOOD*/ +void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406; /* Part of _DP_TE_BLOODSHOWER*/ +void(vector org, vector color) te_explosionrgb = #407; /* Part of DP_TE_EXPLOSIONRGB*/ +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408; /* Part of DP_TE_PARTICLECUBE*/ +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409; /* Part of DP_TE_PARTICLERAIN*/ +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410; /* Part of DP_TE_PARTICLESNOW*/ +void(vector org, vector vel, float howmany) te_spark = #411; /* Part of DP_TE_SPARK*/ +void(vector org) te_gunshotquad = #412; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_spikequad = #413; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_superspikequad = #414; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_explosionquad = #415; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_smallflash = #416; /* Part of DP_TE_SMALLFLASH*/ +void(vector org, float radius, float lifetime, vector color) te_customflash = #417; /* Part of DP_TE_CUSTOMFLASH*/ +void(vector org, optional float count) te_gunshot = #418; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_spike = #419; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_superspike = #420; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_explosion = #421; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_tarexplosion = #422; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_wizspike = #423; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_knightspike = #424; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_lavasplash = #425; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_teleport = #426; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org, float color, float colorlength) te_explosion2 = #427; /* Part of DP_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_lightning1 = #428; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_lightning2 = #429; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_lightning3 = #430; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_beam = #431; /* Part of DP_TE_STANDARDEFFECTBUILTINS*/ +void(vector dir) vectorvectors = #432; /* Part of DP_QC_VECTORVECTORS*/ +void(vector org) te_plasmaburn = #433; /* Part of _DP_TE_PLASMABURN*/ +float(entity e, float s) getsurfacenumpoints = #434; /* Part of DP_QC_GETSURFACE*/ +vector(entity e, float s, float n) getsurfacepoint = #435; /* Part of DP_QC_GETSURFACE*/ +vector(entity e, float s) getsurfacenormal = #436; /* Part of DP_QC_GETSURFACE*/ +string(entity e, float s) getsurfacetexture = #437; /* Part of DP_QC_GETSURFACE*/ +float(entity e, vector p) getsurfacenearpoint = #438; /* Part of DP_QC_GETSURFACE*/ +vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; /* Part of DP_QC_GETSURFACE*/ +#endif +#ifdef MENU +strbuf() buf_create = #440; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle) buf_del = #441; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle) buf_getsize = #442; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle_from, float bufhandle_to) buf_copy = #443; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float sortprefixlen, float backward) buf_sort = #444; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, string glue) buf_implode = #445; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, float string_index) bufstr_get = #446; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index, string str) bufstr_set = #447; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle, string str, float ordered) bufstr_add = #448; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index) bufstr_free = #449; /* Part of DP_QC_STRINGBUFFERS*/ +float(string name) iscachedpic = #451; +string(string name, optional float trywad) precache_pic = #452; +float(vector position, float character, vector scale, vector rgb, float alpha, optional float flag) drawcharacter = #454; +float(vector position, string text, vector scale, vector rgb, float alpha, optional float flag) drawrawstring = #455; +float(vector position, string pic, vector size, vector rgb, float alpha, optional float flag) drawpic = #456; +float(vector position, vector size, vector rgb, float alpha, optional float flag) drawfill = #457; +void(float x, float y, float width, float height) drawsetcliparea = #458; +void(void) drawresetcliparea = #459; +vector(string picname) drawgetimagesize = #460; +float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #467; +float(string text, float usecolours, optional vector fontsize) stringwidth = #468; +void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, float flag) drawsubpic = #469; +#endif +#ifdef SSQC +void(entity e, string s) clientcommand = #440; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +#endif +#if defined(CSQC) || defined(SSQC) +float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +string(float n) argv = #442; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +void(entity e, entity tagentity, string tagname) setattachment = #443; /* Part of DP_GFX_QUAKE3MODELTAGS*/ +searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #444; /* Part of DP_QC_FS_SEARCH + initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. */ + +void(searchhandle handle) search_end = #445; /* Part of DP_QC_FS_SEARCH*/ +float(searchhandle handle) search_getsize = #446; /* Part of DP_QC_FS_SEARCH + Retrieves the number of files that were found. */ + +string(searchhandle handle, float num) search_getfilename = #447; /* Part of DP_QC_FS_SEARCH + Retrieves name of one of the files that was found by the initial search. */ + +#endif +float(searchhandle handle, float num) search_getfilesize = #0:search_getfilesize; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME + Retrieves the size of one of the files that was found by the initial search. */ + +string(searchhandle handle, float num) search_getfilemtime = #0:search_getfilemtime; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME + Retrieves modification time of one of the files. */ + +#if defined(CSQC) || defined(SSQC) +string(string cvarname) cvar_string = #448; /* Part of DP_QC_CVAR_STRING*/ +entity(entity start, .float fld, float match) findflags = #449; /* Part of DP_QC_FINDFLAGS*/ +entity(.float fld, float match, optional .entity chainfield) findchainflags = #450; /* Part of DP_QC_FINDCHAINFLAGS*/ +float(entity ent, string tagname) gettagindex = #451; /* Part of DP_QC_GETTAGINFO*/ +vector(entity ent, float tagindex) gettaginfo = #452; /* Part of DP_QC_GETTAGINFO + Obtains the current worldspace position+orientation of the bone or tag from the given entity. The return value is the world coord, v_forward, v_right, v_up are also set according to the bone/tag's orientation. */ + +#endif +#ifdef SSQC +void(entity player) dropclient = #453; /* Part of DP_SV_DROPCLIENT*/ +entity() spawnclient = #454; /* Part of DP_SV_BOTCLIENT*/ +float(entity client) clienttype = #455; /* Part of DP_SV_BOTCLIENT*/ +void(float target, string str) WriteUnterminatedString = #456; /* Part of DP_SV_WRITEUNTERMINATEDSTRING*/ +#endif +#if defined(CSQC) || defined(SSQC) +void(vector org, vector vel, float howmany) te_flamejet = #457; /* Part of _DP_TE_FLAMEJET*/ +entity(float entnum) edict_num = #459; /* Part of DP_QC_EDICT_NUM*/ +strbuf() buf_create = #460; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle) buf_del = #461; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle) buf_getsize = #462; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle_from, strbuf bufhandle_to) buf_copy = #463; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float sortprefixlen, float backward) buf_sort = #464; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, string glue) buf_implode = #465; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, float string_index) bufstr_get = #466; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index, string str) bufstr_set = #467; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle, string str, float ordered) bufstr_add = #468; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index) bufstr_free = #469; /* Part of DP_QC_STRINGBUFFERS*/ +#endif +float(float s) asin = #471; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float c) acos = #472; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float t) atan = #473; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float c, float s) atan2 = #474; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float a) tan = #475; /* Part of DP_QC_ASINACOSATANATAN2TAN + Forgive me father, for I have a sunbed and I'm not afraid to use it. */ + +float(string s) strlennocol = #476; /* Part of DP_QC_STRINGCOLORFUNCTIONS + Returns the number of characters in the string after any colour codes or other markup has been parsed. */ + +string(string s) strdecolorize = #477; /* Part of DP_QC_STRINGCOLORFUNCTIONS + Flattens any markup/colours, removing them from the string. */ + +string(float uselocaltime, string format, ...) strftime = #478; /* Part of DP_QC_STRFTIME*/ +float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR*/ +string(string s) strtolower = #480; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ +string(string s) strtoupper = #481; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ +string(string s) cvar_defstring = #482; /* Part of DP_QC_CVAR_DEFSTRING*/ +#if defined(CSQC) || defined(SSQC) +void(vector origin, string sample, float volume, float attenuation) pointsound = #483; /* Part of DP_SV_POINTSOUND*/ +#endif +string(string search, string replace, string subject) strreplace = #484; /* Part of DP_QC_STRREPLACE*/ +string(string search, string replace, string subject) strireplace = #485; /* Part of DP_QC_STRREPLACE*/ +#if defined(CSQC) || defined(SSQC) +vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; /* Part of DP_QC_GETSURFACEPOINTATTRIBUTE*/ +#endif +#if defined(CSQC) || defined(MENU) +float(string name, optional string initialURI) gecko_create = #487; /* Part of DP_GECKO_SUPPORT + Create a new 'browser tab' shader with the specified name that can then be drawn via drawpic (shader should not already exist - including from map/model textures or disk). In order to function correctly, this builtin depends upon external plugins being available. Use gecko_navigate to navigate it to a page of your choosing. */ + +void(string name) gecko_destroy = #488; /* Part of DP_GECKO_SUPPORT + Destroy a shader. */ + +void(string name, string URI) gecko_navigate = #489; /* Part of DP_GECKO_SUPPORT + Sends a command to the media decoder attached to the specified shader. In the case of a browser decoder, this changes the url that the browser displays. 'cmd:[un]focus' will tell the decoder that it has focus. */ + +float(string name, float key, float eventtype, optional float charcode) gecko_keyevent = #490; /* Part of DP_GECKO_SUPPORT + Send a key event to a media decoder. This applies only to interactive decoders like browsers. */ + +void(string name, float x, float y) gecko_mousemove = #491; /* Part of DP_GECKO_SUPPORT + Sets a media decoder shader's mouse position. Values should be 0-1. */ + +void(string name, float w, float h) gecko_resize = #492; /* Part of DP_GECKO_SUPPORT + Request to resize a media decoder. */ + +vector(string name) gecko_get_texture_extent = #493; /* Part of DP_GECKO_SUPPORT + Retrieves a media decoder current image pixel sizes. */ + +string(string shadname, string propname) gecko_getproperty = #0:gecko_getproperty; /* + Queries the media decoder (especially browser ones) for decoder-specific properties. The cef plugin recognises url, title, status. */ + +#endif +#ifdef CSQC +float(string file, string id) cin_open = #0:cin_open; +void(string id) cin_close = #0:cin_close; +void(string id, float newstate) cin_setstate = #0:cin_setstate; +float(string id) cin_getstate = #0:cin_getstate; +void(string file) cin_restart = #0:cin_restart; +#endif +float(float caseinsensitive, string s, ...) crc16 = #494; /* Part of DP_QC_CRC16*/ +float(string name) cvar_type = #495; /* Part of DP_QC_CVAR_TYPE*/ +float() numentityfields = #496; /* Part of DP_QC_ENTITYDATA + Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3). */ + +float(string fieldname) findentityfield = #0:findentityfield; /* + Find a field index by name. */ + +typedef .__variant field_t; +field_t(float fieldnum) entityfieldref = #0:entityfieldref; /* + Returns a field value that can be directly used to read entity fields. Be sure to validate the type with entityfieldtype before using. */ + +string(float fieldnum) entityfieldname = #497; /* Part of DP_QC_ENTITYDATA + Retrieves the name of the given entity field. */ + +float(float fieldnum) entityfieldtype = #498; /* Part of DP_QC_ENTITYDATA + Provides information about the type of the field specified by the field num. Returns one of the EV_ values. */ + +string(float fieldnum, entity ent) getentityfieldstring = #499; /* Part of DP_QC_ENTITYDATA*/ +float(float fieldnum, entity ent, string s) putentityfieldstring = #500; /* Part of DP_QC_ENTITYDATA*/ +#ifdef SSQC +void(float to, string s, float sz) WritePicture = #501; /* Part of DP_SV_WRITEPICTURE + Encodes the named image across the network as-is adhering to some size limit. In FTE, this simply writes the string and is equivelent to writestring and sz is ignored. WritePicture should be paired with ReadPicture in csqc. */ + +#endif +#ifdef CSQC +string() ReadPicture = #501; /* + Reads a picture that was written by ReadPicture, and returns a name that can be used in drawpic and other 2d drawing functions. In FTE, this acts as a readstring-with-downloadcheck - the image will appear normally once it has been downloaded, but its size may be incorrect until then. */ + +void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, optional float flags) boxparticles = #502; +#endif +string(string filename, optional float makereferenced) whichpack = #503; /* Part of DP_QC_WHICHPACK + Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If makereferenced is true, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ + +#ifdef CSQC +__variant(float entnum, float fieldnum) getentity = #504; /* + Looks up fields from non-csqc-visible entities. The entity will need to be within the player's pvs. fieldnum should be one of the GE_ constants. */ + +#endif +string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE*/ +string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE*/ +float(entity ent) num_for_edict = #512; +#define uri_post uri_get +float(string uril, float id, optional string postmimetype, optional string postdata) uri_get = #513; /* Part of DP_QC_URI_GET, DP_QC_URI_POST + uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned + returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string + For a POST request, you will typically want the postmimetype set to application/x-www-form-urlencoded. + For a GET request, omit the mime+data entirely. + Consult your webserver/php/etc documentation for best-practise. */ + +float(string str) tokenize_console = #514; /* + Tokenize a string exactly as the console's tokenizer would do so. The regular tokenize builtin became bastardized for convienient string parsing, which resulted in a large disparity that can be exploited to bypass checks implemented in a naive SV_ParseClientCommand function, therefore you can use this builtin to make sure it exactly matches. */ + +float(float idx) argv_start_index = #515; /* + Returns the character index that the tokenized arg started at. */ + +float(float idx) argv_end_index = #516; /* + Returns the character index that the tokenized arg stopped at. */ + +void(strbuf strbuf, string pattern, string antipattern) buf_cvarlist = #517; +string(string cvarname) cvar_description = #518; /* + Retrieves the description of a cvar, which might be useful for tooltips or help files. This may still not be useful. */ + +#if defined(CSQC) || defined(SSQC) +float(optional float timetype) gettime = #519; +#endif +#ifdef CSQC +string(float keynum) keynumtostring_omgwtf = #520; +string(string command, optional float bindmap) findkeysforcommand = #521; /* + Returns a list of keycodes that perform the given console command in a format that can only be parsed via tokenize (NOT tokenize_console). This only and always returns two values - if only one key is actually bound, -1 will be returned. The bindmap argument is listed for compatibility with dp-specific defs, but is ignored in FTE. */ + +string(string command, optional float bindmap) findkeysforcommandex = #0:findkeysforcommandex; /* + Returns a list of key bindings in keyname format instead of keynums. Use tokenize to parse. This list may contain modifiers. May return large numbers of keys. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(string s) loadfromdata = #529; /* + Reads a set of entities from the given string. This string should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + +void(string s) loadfromfile = #530; /* + Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + +#endif +#ifdef SSQC +void(float pause) setpause = #531; /* + Sets whether the server should or should not be paused. This does not affect auto-paused things like when the console is down. */ + +float(string mname) precache_vwep_model = #532; /* Part of ZQ_VWEP*/ +#endif +float(float v, optional float base) log = #532; /* Part of ??MVDSV_BUILTINS + Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */ + +#ifdef CSQC +float(entity e, float channel, string newsample, float volume, float attenuation, float pitchpct, float flags, float timeoffset) soundupdate = #0:soundupdate; /* + Changes the properties of the current sound being played on the given entity channel. newsample may be empty, and will be ignored in this case. timeoffset is relative to the current position (subtract the result of getsoundtime for absolute positions). Negative volume can be used to stop the sound. Return value is a fractional value based upon the number of audio devices that could be updated - test against TRUE rather than non-zero. */ + +float(entity e, float channel) getsoundtime = #533; /* + Returns the current playback time of the sample on the given entity's channel. Beware CHAN_AUTO (in csqc, channels are not limited by network protocol). */ + +#endif +#if defined(CSQC) || defined(MENU) +float(string sample) soundlength = #534; /* + Provides a way to query the duration of a sound sample, allowing you to set up a timer to chain samples. */ + +#endif +float(string filename, strbuf bufhandle) buf_loadfile = #535; /* + Appends the named file into a string buffer (which must have been created in advance). The return value merely says whether the file was readable. */ + +float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536; /* + Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer. */ + +#ifdef SSQC +float(optional float force) physics_supported = #0:physics_supported; /* + Queries whether rigid body physics is enabled or not. CSQC and SSQC may report different values. If the force argument is used then the engine will try to activate or release physics (returning the new state, which may fail if plugins or dlls are missing). Note that restarting the physics engine is likely to result in hitches when collision trees get generated. The state may change if a plugin is disabled mid-map. */ + +#endif +#if defined(CSQC) || defined(SSQC) +void(entity e, float physics_enabled) physics_enable = #540; /* + Enable or disable the physics attached to a MOVETYPE_PHYSICS entity. Entities which have been disabled in this way will stop taking so much cpu time. */ + +void(entity e, vector force, vector relative_ofs) physics_addforce = #541; /* + Apply some impulse directional force upon a MOVETYPE_PHYSICS entity. */ + +void(entity e, vector torque) physics_addtorque = #542; /* + Apply some impulse rotational force upon a MOVETYPE_PHYSICS entity. */ + +#endif +#ifdef MENU +void(float dest) setkeydest = #601; +float() getkeydest = #602; +#endif +#if defined(CSQC) || defined(MENU) +void(float trg) setmousetarget = #603; +float() getmousetarget = #604; +#endif +void(.../*, string funcname*/) callfunction = #605; /* + Invokes the named function. The function name is always passed as the last parameter and must always be present. The others are passed to the named function as-is */ + +void(filestream fh, entity e) writetofile = #606; /* + Writes an entity's fields to the named frik_file file handle. */ + +float(string s) isfunction = #607; /* + Returns true if the named function exists and can be called with the callfunction builtin. */ + +#if defined(CSQC) || defined(MENU) +vector(float vidmode, optional float forfullscreen) getresolution = #608; /* + Supposed to query the driver for supported video modes. FTE does not query drivers in this way, nor would it trust drivers anyway. */ + +#endif +#ifdef CSQC +string(float keynum) keynumtostring_menu = #609; +#endif +#ifdef MENU +string(float keynum) keynumtostring = #609; /* + Converts a qscancode key number into a mostly-human-readable name, matching the bind command. */ + +string(string command, optional float bindmap) findkeysforcommand = #610; +#endif +#if defined(CSQC) || defined(MENU) +float(float type) gethostcachevalue = #611; /* Part of FTE_CSQC_SERVERBROWSER*/ +string(float type, float hostnr) gethostcachestring = #612; /* Part of FTE_CSQC_SERVERBROWSER*/ +#endif +float(entity e, string s, optional float offset) parseentitydata = #613; /* + Reads a single entity's fields into an already-spawned entity. s should contain field pairs like in a saved game: {"foo1" "bar" "foo2" "5"}. Returns <=0 on failure, otherwise returns the offset in the string that was read to. */ + +string(entity e) generateentitydata = #0:generateentitydata; /* + Dumps the entities fields into a string which can later be parsed with parseentitydata. */ + +#ifdef MENU +float(string key) stringtokeynum = #614; /* + Returns the qscancode of a key from its name. Names are identical to the bind command. ctrl/shift/alt modifiers are ignored. */ + +#endif +#ifdef CSQC +float(string key) stringtokeynum_menu = #614; +#endif +#if defined(CSQC) || defined(MENU) +void() resethostcachemasks = #615; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float mask, float fld, string str, float op) sethostcachemaskstring = #616; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float mask, float fld, float num, float op) sethostcachemasknumber = #617; /* Part of FTE_CSQC_SERVERBROWSER*/ +void() resorthostcache = #618; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float fld, float descending) sethostcachesort = #619; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(optional float dopurge) refreshhostcache = #620; /* Part of FTE_CSQC_SERVERBROWSER*/ +float(float fld, float hostnr) gethostcachenumber = #621; /* Part of FTE_CSQC_SERVERBROWSER*/ +float(string key) gethostcacheindexforkey = #622; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(string key) addwantedhostcachekey = #623; /* Part of FTE_CSQC_SERVERBROWSER*/ +string() getextresponse = #624; /* Part of FTE_CSQC_SERVERBROWSER*/ +#endif +string(string dnsname, optional float defport) netaddress_resolve = #625; +string(string fmt, ...) sprintf = #627; /* Part of DP_QC_SPRINTF + 'prints' to a formatted temp-string. Mostly acts as in C, however %d assumes floats (fteqcc has arg checking. Use it.). + type conversions: l=arg is an int, h=arg is a float, and will work as a prefix for any float or int representation. + float representations: d=decimal, e,E=exponent-notation, f,F=floating-point notation, g,G=terse float, c=char code, x,X=hex + other representations: i=int, s=string, S=quoted and marked-up string, v=vector, p=pointer + so %ld will accept an int arg, while %hi will expect a float arg. + entities, fields, and functions will generally need to be printed as ints with %i. */ + +#if defined(CSQC) || defined(SSQC) +float(entity e, float s) getsurfacenumtriangles = #628; +vector(entity e, float s, float n) getsurfacetriangle = #629; +#endif +#if defined(CSQC) || defined(MENU) +vector() getbindmaps = #631; +float(vector bm) setbindmaps = #632; +#endif +string(string digest, string data, ...) digest_hex = #639; +string(string digest, void *data, int length) digest_ptr = #0:digest_ptr; /* + Calculates the digest of a single contiguous block of memory (including nulls) using the specified hash function. */ + +#if defined(CSQC) || defined(MENU) +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 +#define K_LALT 132 +#define K_RALT -245 +#define K_LCTRL 133 +#define K_RCTRL -246 +#define K_LSHIFT 134 +#define K_RSHIFT -247 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 +#define K_KP_HOME 164 +#define K_KP_UPARROW 165 +#define K_KP_PGUP 166 +#define K_KP_LEFTARROW 161 +#define K_KP_5 162 +#define K_KP_RIGHTARROW 163 +#define K_KP_END 158 +#define K_KP_DOWNARROW 159 +#define K_KP_PGDN 160 +#define K_KP_ENTER 172 +#define K_KP_INS 157 +#define K_KP_DEL 167 +#define K_KP_SLASH 168 +#define K_KP_MINUS 170 +#define K_KP_PLUS 171 +#define K_KP_NUMLOCK 154 +#define K_KP_STAR 169 +#define K_KP_EQUALS 173 +#define K_MOUSE1 512 +#define K_MOUSE2 513 +#define K_MOUSE3 514 +#define K_MOUSE4 517 +#define K_MOUSE5 518 +#define K_MOUSE6 519 +#define K_MOUSE7 520 +#define K_MOUSE8 521 +#define K_MOUSE9 522 +#define K_MOUSE10 523 +#define K_MWHEELUP 515 +#define K_MWHEELDOWN 516 +#define K_LWIN -239 +#define K_RWIN -240 +#define K_APP -241 +#define K_SEARCH -242 +#define K_POWER -130 +#define K_VOLUP -243 +#define K_VOLDOWN -244 +#define K_JOY1 768 +#define K_JOY2 769 +#define K_JOY3 770 +#define K_JOY4 771 +#define K_AUX1 784 +#define K_AUX2 785 +#define K_AUX3 786 +#define K_AUX4 787 +#define K_AUX5 788 +#define K_AUX6 789 +#define K_AUX7 790 +#define K_AUX8 791 +#define K_AUX9 792 +#define K_AUX10 793 +#define K_AUX11 794 +#define K_AUX12 795 +#define K_AUX13 796 +#define K_AUX14 797 +#define K_AUX15 798 +#define K_AUX16 799 +#define K_AUX17 800 +#define K_AUX18 801 +#define K_AUX19 802 +#define K_AUX20 803 +#define K_AUX21 804 +#define K_AUX22 805 +#define K_AUX23 806 +#define K_AUX24 807 +#define K_AUX25 808 +#define K_AUX26 809 +#define K_AUX27 810 +#define K_AUX28 811 +#define K_AUX29 812 +#define K_AUX30 813 +#define K_AUX31 814 +#define K_AUX32 815 +#define K_PAUSE 153 +#define K_PRINTSCREEN 174 +#define K_CAPSLOCK 155 +#define K_SCROLLLOCK 156 +#define K_SEMICOLON 59 +#define K_PLUS 43 +#define K_MINUS 45 +#define K_TILDE 126 +#define K_BACKQUOTE 96 +#define K_BACKSLASH 92 +#define K_GP_A 826 +#define K_GP_B 827 +#define K_GP_X 828 +#define K_GP_Y 829 +#define K_GP_LSHOULDER 824 +#define K_GP_RSHOULDER 825 +#define K_GP_LTRIGGER 830 +#define K_GP_RTRIGGER 831 +#define K_GP_BACK 821 +#define K_GP_START 820 +#define K_GP_LTHUMB 822 +#define K_GP_RTHUMB 823 +#define K_GP_DPAD_UP 816 +#define K_GP_DPAD_DOWN 817 +#define K_GP_DPAD_LEFT 818 +#define K_GP_DPAD_RIGHT 819 +#define K_GP_GUIDE -202 +#define K_GP_UNKNOWN -255 +#define K_GP_LTHUMB_UP 832 +#define K_GP_LTHUMB_DOWN 833 +#define K_GP_LTHUMB_LEFT 834 +#define K_GP_LTHUMB_RIGHT 835 +#define K_GP_RTHUMB_UP 836 +#define K_GP_RTHUMB_DOWN 837 +#define K_GP_RTHUMB_LEFT 838 +#define K_GP_RTHUMB_RIGHT 839 +#endif +#ifdef _ACCESSORS +accessor strbuf : float +{ + inline get float asfloat[float idx] = {return stof(bufstr_get(this, idx));}; + inline set float asfloat[float idx] = {bufstr_set(this, idx, ftos(value));}; + get string[float] = bufstr_get; + set string[float] = bufstr_set; + get float length = buf_getsize; +}; +accessor searchhandle : float +{ + get string[float] = search_getfilename; + get float length = search_getsize; +}; +accessor hashtable : float +{ + inline get vector v[string key] = {return hash_get(this, key, '0 0 0', EV_VECTOR);}; + inline set vector v[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_VECTOR);}; + inline get string s[string key] = {return hash_get(this, key, "", EV_STRING);}; + inline set string s[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_STRING);}; + inline get float f[string key] = {return hash_get(this, key, 0.0, EV_FLOAT);}; + inline set float f[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_FLOAT);}; + inline get __variant[string key] = {return hash_get(this, key, __NULL__);}; + inline set __variant[string key] = {hash_add(this, key, value, HASH_REPLACE);}; +}; +accessor infostring : string +{ + get string[string] = infoget; + inline seti& string[string fld] = {this = infoadd(this, fld, value);}; +}; +accessor filestream : float +{ + get string = fgets; + inline set string = {fputs(this,value);}; +}; +#endif +#pragma noref 0 \ No newline at end of file diff --git a/misc.qc b/misc.qc index 1d370301..179a5c33 100644 --- a/misc.qc +++ b/misc.qc @@ -6,6 +6,12 @@ void () info_null = { void () info_notnull = { }; +// q3 +/*void () target_position = { + self.classname = "info_notnull"; + info_notnull(); +};*/ + void () light_use = { if (self.spawnflags & 1) { lightstyle(self.style, "m"); diff --git a/progs.src b/progs.src index 41466369..4edb644e 100644 --- a/progs.src +++ b/progs.src @@ -1,5 +1,5 @@ qwprogs.dat - +//fteextensions.qc defs.qc qw.qc debug.qc diff --git a/tfort.qc b/tfort.qc index c5818095..0ca6e222 100644 --- a/tfort.qc +++ b/tfort.qc @@ -591,7 +591,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Grenade timers", grentimers, "", 1); sprint(self, PRINT_HIGH, "Concussion effect lasts "); - sprint(self, PRINT_HIGH, cussgrentime); + sprint(self, PRINT_HIGH, ftos(cussgrentime)); sprint(self, PRINT_HIGH, " seconds"); sprint(self, PRINT_HIGH, "\n== Scout ==\n"); diff --git a/tfortmap.qc b/tfortmap.qc index e908a4e5..d037dac4 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -421,7 +421,9 @@ void () info_tfgoal = { }; // q3 support +/* void () func_goalinfo = { + dprint("processing func_goalinfo"); self.classname = "info_tfgoal"; if (self.allowteams == "blue") { self.team_no = 1; @@ -431,42 +433,47 @@ void () func_goalinfo = { } self.mdl = self.model; self.noise = self.active_all_sound; - self.armortype = "0.8"; + self.armortype = 0.8; - float comindex, startpos; - comindex = 0; - string searchterm; - searchterm = self.give; + dprint("past setting of fields"); + float startpos, endpos; startpos = 0; - // while index is not -1 - while (comindex >= 0) { - // find index of comma - comindex = strstrofs(searchterm, ",", startpos); - // get substring up to the comma - string val; - val = substring(searchterm, startpos, comindex); - // set pos for next loop - startpos = comindex + 1; - - // process val "health=+100" + string searchterm = self.give; + endpos = strstrofs(searchterm, ",", startpos); + dprint(searchterm); + do { + string splitterm = substring(searchterm, startpos, endpos); + dprint(splitterm); + // split it up "health=+100" float eqindex, opindex, len, amt; - eqindex = strstrofs(val, "=", 0); string givetype, posneg, samt; - givetype = substring(val, 0, eqindex); + eqindex = strstrofs(splitterm, "=", 0); opindex = eqindex + 1; - posneg = substring(val, eqindex, opindex); - len = comindex - 1; - samt = substring(val, opindex, len); + givetype = substring(splitterm, 0, eqindex); + posneg = substring(splitterm, eqindex, opindex); + len = endpos - 1; + samt = substring(splitterm, opindex, len); amt = stof(samt); - - } - - + // now process with case statement + dprint(splitterm); + dprint(givetype); + dprint(posneg); + dprint(samt); + + // next loop, set startpos to endpos through index for while condition + startpos = strstrofs(searchterm, ",", startpos); + endpos = strstrofs(searchterm, ",", startpos); + if (endpos == -1) { + // set endpos to end of string + endpos = strlen(searchterm); + endpos = endpos - startpos; + } + } while (startpos >= -1); info_tfgoal(); } - +*/ void () i_t_g = { self.classname = "info_tfgoal"; info_tfgoal(); From 860a1a02f972006639571598d834e72a3cd83a01 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 18 Nov 2018 01:37:39 +1100 Subject: [PATCH 0470/2474] fix invalid chars --- help.qc | 158 ++++++++++++++++++++++++------------------------ menu.qc | 178 +++++++++++++++++++++++++++--------------------------- spy.qc | 10 +-- status.qc | 64 ++++++++++---------- vote.qc | 12 ++-- 5 files changed, 211 insertions(+), 211 deletions(-) diff --git a/help.qc b/help.qc index 32df9e65..f34a106e 100644 --- a/help.qc +++ b/help.qc @@ -42,122 +42,122 @@ void () Help_Show = { void () Help_ShowScout = { sprint(self, PRINT_HIGH, "\nDefault bindings for Scout:\n"); - sprint(self, PRINT_HIGH, "± - Equip Nailgun\n"); - sprint(self, PRINT_HIGH, "² - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "ε - Toggle Scanner on/off\n"); - sprint(self, PRINT_HIGH, "ζ - Throw Caltrop Canisters\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Concussion Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "Γ₯ - Toggle Scanner on/off\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Throw Caltrop Canisters\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Concussion Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Scout:\n"); - sprint(self, PRINT_HIGH, "αυτοσγαξ - Toggle Scanner on/off\n"); - sprint(self, PRINT_HIGH, "σγαξσουξδ - Toggle Scanner sound on/off\n"); - sprint(self, PRINT_HIGH, "σγαξε - Toggle scanning of enemies on/off\n"); - sprint(self, PRINT_HIGH, "σγαξζ - Toggle scanning of friendlies on/off\n"); + sprint(self, PRINT_HIGH, "ÑáôïóãÑà - Toggle Scanner on/off\n"); + sprint(self, PRINT_HIGH, "óãÑΓΓ³Γ―Γ΅ΓΓ€ - Toggle Scanner sound on/off\n"); + sprint(self, PRINT_HIGH, "óãÑΓΓ₯ - Toggle scanning of enemies on/off\n"); + sprint(self, PRINT_HIGH, "óãÑΓΓ¦ - Toggle scanning of friendlies on/off\n"); }; void () Help_ShowSniper = { sprint(self, PRINT_HIGH, "\nDefault bindings for Sniper:\n"); - sprint(self, PRINT_HIGH, "± - Equip Sniper Rifle\n"); - sprint(self, PRINT_HIGH, "² - Equip Sniper Rifle on Full Auto\n"); - sprint(self, PRINT_HIGH, "³ - Equip Nailgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "ε - Toggle zoom mode\n"); - sprint(self, PRINT_HIGH, "νχθεεμυπ - Zoom in (while in zoom mode)\n"); - sprint(self, PRINT_HIGH, "νχθεεμδοχξ - Zoom out (while in zoom mode)\n"); - sprint(self, PRINT_HIGH, "ζ - Throw Flare\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Sniper Rifle\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Sniper Rifle on Full Auto\n"); + sprint(self, PRINT_HIGH, "Δ‘ - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "Γ₯ - Toggle zoom mode\n"); + sprint(self, PRINT_HIGH, "Γ­αΉ«Γ¨Γ₯Γ₯ìáš - Zoom in (while in zoom mode)\n"); + sprint(self, PRINT_HIGH, "Γ­αΉ«Γ¨Γ₯Γ₯ìÀïṫà - Zoom out (while in zoom mode)\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Throw Flare\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Sniper:\n"); - sprint(self, PRINT_HIGH, "ϊοοντοηημε - Toggle zoom mode\n"); - sprint(self, PRINT_HIGH, "ϊοονιξ  - Zoom in (for adjusting zoom while in zoom mode)\n"); - sprint(self, PRINT_HIGH, "ϊοονουτ - Zoom out (for adjusting zoom while in zoom mode)\n"); + sprint(self, PRINT_HIGH, "úïïíôïççìΓ₯ - Toggle zoom mode\n"); + sprint(self, PRINT_HIGH, "ΓΊΓ―Γ―Γ­Γ©ΓΒ  - Zoom in (for adjusting zoom while in zoom mode)\n"); + sprint(self, PRINT_HIGH, "úïïíïáô - Zoom out (for adjusting zoom while in zoom mode)\n"); sprint(self, PRINT_HIGH, "\nSettings for Sniper:\n"); - sprint(self, PRINT_HIGH, "ϊζ ΌζοφΎ - The default zoom fov which zoomtoggle zooms to (default 30)\n"); - sprint(self, PRINT_HIGH, "ϊσ ΌζοφΎ - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); + sprint(self, PRINT_HIGH, "ΓΊΓ¦ ỳæïâẅ - The default zoom fov which zoomtoggle zooms to (default 30)\n"); + sprint(self, PRINT_HIGH, "ΓΊΓ³ ỳæïâẅ - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); sprint(self, PRINT_HIGH, "Usage: setinfo \n"); }; void () Help_ShowSoldier = { sprint(self, PRINT_HIGH, "\nDefault bindings for Soldier:\n"); - sprint(self, PRINT_HIGH, "± - Equip Rocket Launcher\n"); - sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "ζ - Prime/throw Nail Grenade\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Rocket Launcher\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Nail Grenade\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); }; void () Help_ShowDemoman = { sprint(self, PRINT_HIGH, "\nDefault bindings for Demolitions Man:\n"); - sprint(self, PRINT_HIGH, "± - Equip Grenade Launcher\n"); - sprint(self, PRINT_HIGH, "² - Equip Pipebomb Launcher\n"); - sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "΅ - Detpack menu\n"); - sprint(self, PRINT_HIGH, "ε - Detonate pipebombs\n"); - sprint(self, PRINT_HIGH, "ζ - Prime/throw Mirv Grenade\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Grenade Launcher\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Pipebomb Launcher\n"); + sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "ṁ - Detpack menu\n"); + sprint(self, PRINT_HIGH, "Γ₯ - Detonate pipebombs\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Mirv Grenade\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Demolitions Man:\n"); - sprint(self, PRINT_HIGH, "δετπιπε - Detonate pipebombs\n"); - sprint(self, PRINT_HIGH, "«δετ΅ - Place detpack with 5 second timer\n"); - sprint(self, PRINT_HIGH, "«δετ²° - Place detpack with 20 second timer\n"); - sprint(self, PRINT_HIGH, "«δετ΅° - Place detpack with 50 second timer\n"); - sprint(self, PRINT_HIGH, "«δετ²΅΅ - Place detpack with 255 second timer\n"); + sprint(self, PRINT_HIGH, "Γ€Γ₯Γ΄Ε΅Γ©Ε΅Γ₯ - Detonate pipebombs\n"); + sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôṁ - Place detpack with 5 second timer\n"); + sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôĠḞ - Place detpack with 20 second timer\n"); + sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôṁḞ - Place detpack with 50 second timer\n"); + sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôĠṁṁ - Place detpack with 255 second timer\n"); }; void () Help_ShowMedic = { sprint(self, PRINT_HIGH, "\nDefault bindings for Combat Medic:\n"); - sprint(self, PRINT_HIGH, "± - Equip Super Nailgun\n"); - sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Medikit\n"); - sprint(self, PRINT_HIGH, "ζ - Prime/throw Concussion Grenade\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Super Nailgun\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Medikit\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Concussion Grenade\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); }; void () Help_ShowHWGuy = { sprint(self, PRINT_HIGH, "\nDefault bindings for Heavy Weapons Guy:\n"); - sprint(self, PRINT_HIGH, "± - Equip Assault Cannon\n"); - sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "ζ - Prime/throw Mirv Grenade\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Assault Cannon\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Mirv Grenade\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); }; void () Help_ShowPyro = { sprint(self, PRINT_HIGH, "\nDefault bindings for Pyro:\n"); - sprint(self, PRINT_HIGH, "± - Equip Flamethrower\n"); - sprint(self, PRINT_HIGH, "² - Equip Incendiary Cannon\n"); - sprint(self, PRINT_HIGH, "³ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "ζ - Prime/throw Napalm Grenade\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Flamethrower\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Incendiary Cannon\n"); + sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Napalm Grenade\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); }; void () Help_ShowSpy = { sprint(self, PRINT_HIGH, "\nDefault bindings for Spy:\n"); - sprint(self, PRINT_HIGH, "± - Equip Tranquiliser Gun\n"); - sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "³ - Equip Nailgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Knife\n"); - sprint(self, PRINT_HIGH, "΅ - Disguise menu\n"); - sprint(self, PRINT_HIGH, "ε - Silently feign death\n"); - sprint(self, PRINT_HIGH, "ζ - Prime/throw Gas Grenade\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Tranquiliser Gun\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "Δ‘ - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Knife\n"); + sprint(self, PRINT_HIGH, "ṁ - Disguise menu\n"); + sprint(self, PRINT_HIGH, "Γ₯ - Silently feign death\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Gas Grenade\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Spy:\n"); - sprint(self, PRINT_HIGH, "ζειηξ - Feign death\n"); - sprint(self, PRINT_HIGH, "σζειηξ - Silently feign death\n"); + sprint(self, PRINT_HIGH, "Γ¦Γ₯éçà - Feign death\n"); + sprint(self, PRINT_HIGH, "Γ³Γ¦Γ₯éçà - Silently feign death\n"); }; void () Help_ShowEngineer = { sprint(self, PRINT_HIGH, "\nDefault bindings for Engineer:\n"); - sprint(self, PRINT_HIGH, "± - Equip Railgun\n"); - sprint(self, PRINT_HIGH, "² - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "΄ - Equip Spanner\n"); - sprint(self, PRINT_HIGH, "΅ - Build/destroy menu\n"); - sprint(self, PRINT_HIGH, "ζ - Prime/throw EMP Grenade\n"); - sprint(self, PRINT_HIGH, "νουσε² - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, "ḟ - Equip Railgun\n"); + sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, "αΉ€ - Equip Spanner\n"); + sprint(self, PRINT_HIGH, "ṁ - Build/destroy menu\n"); + sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw EMP Grenade\n"); + sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Engineer:\n"); - sprint(self, PRINT_HIGH, "δετδισπεξσες - Detonate Dispenser\n"); - sprint(self, PRINT_HIGH, "δετσεξτςω - Detonate Sentry Gun\n"); + sprint(self, PRINT_HIGH, "Γ€Γ₯ôÀéóšΓ₯ΓΓ³Γ₯Γ² - Detonate Dispenser\n"); + sprint(self, PRINT_HIGH, "Γ€Γ₯ôóΓ₯Γôòù - Detonate Sentry Gun\n"); }; diff --git a/menu.qc b/menu.qc index 3268613b..69e2ec07 100644 --- a/menu.qc +++ b/menu.qc @@ -181,11 +181,11 @@ void (float update) Menu_Team = { // prepare team strings local string s_select = "Select team:\n\n"; - local string s_blue = "“‘ Blue team "; - local string s_red = "”‘ Red team "; - local string s_yellow = "•‘ Yellow team"; - local string s_green = "–‘ Green team "; - local string s_auto = "—‘ Auto-assign team"; + local string s_blue = "“‘ Blue team "; + local string s_red = "”‘ Red team "; + local string s_yellow = "•‘ Yellow team"; + local string s_green = "–‘ Green team "; + local string s_auto = "—‘ Auto-assign team"; // put together team strings s_blue = Menu_Team_TeamString(1, s_blue); @@ -308,16 +308,16 @@ void (float update) Menu_Class = { // prepare class strings local string s_select = "Select class:\n\n"; - local string s_scout = "“‘ Scout "; - local string s_sniper = "”‘ Sniper "; - local string s_soldier = "•‘ Soldier "; - local string s_demoman = "–‘ Demoman "; - local string s_medic = "—‘ Medic "; - local string s_hwguy = "˜‘ HWGuy "; - local string s_pyro = "™‘ Pyro "; - local string s_spy = "š‘ Spy "; - local string s_engineer = "›‘ Engineer"; - local string s_randompc = "’‘ RandomPC"; + local string s_scout = "“‘ Scout "; + local string s_sniper = "”‘ Sniper "; + local string s_soldier = "•‘ Soldier "; + local string s_demoman = "–‘ Demoman "; + local string s_medic = "—‘ Medic "; + local string s_hwguy = "ΒΒ˜Β‘ HWGuy "; + local string s_pyro = "™‘ Pyro "; + local string s_spy = "ΒΒšΒ‘ Spy "; + local string s_engineer = "›‘ Engineer"; + local string s_randompc = "’‘ RandomPC"; // put together class strings - all strings are strzoned s_scout = Menu_Class_ClassString(PC_SCOUT, s_scout); @@ -361,11 +361,11 @@ void (float inp) Menu_Drop_Input = { void () Menu_Drop = { local string s_drop; - local string s_shells = "“‘ Shells \n"; - local string s_nails = "”‘ Nails \n"; - local string s_rockets = "•‘ Rockets \n"; - local string s_cells = "–‘ Cells \n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_shells = "“‘ Shells \n"; + local string s_nails = "”‘ Nails \n"; + local string s_rockets = "•‘ Rockets \n"; + local string s_cells = "–‘ Cells \n"; + local string s_nothing = "\n—‘ Nothing "; if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -383,11 +383,11 @@ void () Menu_Drop = { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_shells < DROP_SHELLS) && ((self.ammo_cells / AMMO_COST_SHELLS) > (DROP_SHELLS - self.ammo_shells))) - s_shells = "“‘ Shells (make) \n"; + s_shells = "“‘ Shells (make) \n"; if ((self.ammo_nails < DROP_NAILS) && ((self.ammo_cells / AMMO_COST_NAILS) > (DROP_NAILS - self.ammo_nails))) - s_nails = "”‘ Nails (make) \n"; + s_nails = "”‘ Nails (make) \n"; if ((self.ammo_rockets < DROP_ROCKETS) && ((self.ammo_cells / AMMO_COST_ROCKETS) > (DROP_ROCKETS - self.ammo_rockets))) - s_rockets = "•‘ Rockets (make)\n"; + s_rockets = "•‘ Rockets (make)\n"; if (self.ammo_cells < DROP_CELLS) s_cells = "\n"; } @@ -419,28 +419,28 @@ void (float inp) Menu_Scout_Input = { void () Menu_Scout = { local string s_action = "Scanner settings:\n\n"; local string s_scan, s_scane, s_scanf, s_scansound; - local string s_nothing = "\n—‘ Nothing \n\n"; + local string s_nothing = "\n—‘ Nothing \n\n"; if (!self.ScannerOn) - s_scan = "“‘ Turn Scanner on \n"; + s_scan = "“‘ Turn Scanner on \n"; else - s_scan = "“‘ Turn Scanner off \n"; + s_scan = "“‘ Turn Scanner off \n"; if (self.tf_items_flags & NIT_SCANNER_ENEMY) - s_scane = "”‘ Do not scan for enemies \n"; + s_scane = "”‘ Do not scan for enemies \n"; else - s_scane = "”‘ Scan for enemies \n"; + s_scane = "”‘ Scan for enemies \n"; if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) - s_scanf = "•‘ Do not scan for friendlies\n"; + s_scanf = "•‘ Do not scan for friendlies\n"; else - s_scanf = "•‘ Scan for friendlies \n"; + s_scanf = "•‘ Scan for friendlies \n"; if (self.tf_items_flags & 4) - s_scansound = "–‘ Turn off scan sound \n"; + s_scansound = "–‘ Turn off scan sound \n"; else - s_scansound = "–‘ Turn on scan sound \n"; + s_scansound = "–‘ Turn on scan sound \n"; Status_Menu(self, Menu_Scout_Input, s_action, s_scan, s_scane, s_scanf, s_scansound, s_nothing); }; @@ -477,10 +477,10 @@ void (float inp) Menu_Spy_Input = { void (entity pe_player) Menu_Spy = { local string s_action = "Action:\n\n"; - local string s_skin = "“‘ Disguise \n"; - local string s_last = "”‘ Last disguise \n"; + local string s_skin = "“‘ Disguise \n"; + local string s_last = "”‘ Last disguise \n"; local string s_feign, s_reset; - local string s_nothing = "\n—‘ Nothing "; + local string s_nothing = "\n—‘ Nothing "; if (pe_player.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT) || pe_player.is_unabletospy == 1) { return; @@ -488,28 +488,28 @@ void (entity pe_player) Menu_Spy = { if (invis_only) { if (pe_player.is_undercover == 1) - s_skin = "“‘ Become visible \n"; + s_skin = "“‘ Become visible \n"; else if (pe_player.is_undercover == 2) - s_skin = "“‘ Stop going invisible \n"; + s_skin = "“‘ Stop going invisible \n"; else - s_skin = "“‘ Go invisible \n"; + s_skin = "“‘ Go invisible \n"; } else if (pe_player.is_undercover == 2) - s_skin = "“‘ Stop disguising \n"; + s_skin = "“‘ Stop disguising \n"; if ((!pe_player.last_skin && !pe_player.last_team) || invis_only) s_last = "\n"; if (pe_player.is_feigning) - s_feign = "•‘ Stop feigning \n"; + s_feign = "•‘ Stop feigning \n"; else - s_feign = "•‘ Start feigning (silent)\n"; + s_feign = "•‘ Start feigning (silent)\n"; if (pe_player.undercover_team && pe_player.undercover_skin) - s_reset = "–‘ Reset disguise \n"; + s_reset = "–‘ Reset disguise \n"; else if (pe_player.undercover_team) - s_reset = "–‘ Reset color \n"; + s_reset = "–‘ Reset color \n"; else if (pe_player.undercover_skin) - s_reset = "–‘ Reset skin \n"; + s_reset = "–‘ Reset skin \n"; else s_reset = "\n"; @@ -547,16 +547,16 @@ void () Menu_Spy_Skin = { return; local string s_disguise = "Disguise as enemy:\n\n"; - local string s_scout = "“‘ Scout \n"; - local string s_sniper = "”‘ Sniper \n"; - local string s_soldier = "•‘ Soldier \n"; - local string s_demoman = "–‘ Demoman \n"; - local string s_medic = "—‘ Medic \n"; - local string s_hwguy = "˜‘ HWGuy \n"; - local string s_pyro = "™‘ Pyro \n"; - local string s_spy = "š‘ Spy \n"; - local string s_engineer = "›‘ Engineer \n"; - local string s_nothing = "\n’‘ Nothing \n"; + local string s_scout = "“‘ Scout \n"; + local string s_sniper = "”‘ Sniper \n"; + local string s_soldier = "•‘ Soldier \n"; + local string s_demoman = "–‘ Demoman \n"; + local string s_medic = "—‘ Medic \n"; + local string s_hwguy = "ΒΒ˜Β‘ HWGuy \n"; + local string s_pyro = "™‘ Pyro \n"; + local string s_spy = "ΒΒšΒ‘ Spy \n"; + local string s_engineer = "›‘ Engineer \n"; + local string s_nothing = "\n’‘ Nothing \n"; Status_Menu(self, Menu_Spy_Skin_Input, s_disguise, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_nothing); }; @@ -579,11 +579,11 @@ void (float inp) Menu_Spy_Color_Input = { void () Menu_Spy_Color = { local float color = stof(infokey(self, "bottomcolor")); local string s_disguise = "Disguise as:\n\n"; - local string s_blue = "“‘ Blue team \n"; - local string s_red = "”‘ Red team \n"; - local string s_yellow = "•‘ Yellow team\n"; - local string s_green = "–‘ Green team \n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_blue = "“‘ Blue team \n"; + local string s_red = "”‘ Red team \n"; + local string s_yellow = "•‘ Yellow team\n"; + local string s_green = "–‘ Green team \n"; + local string s_nothing = "\n—‘ Nothing "; if (number_of_teams == 0) { sprint(self, PRINT_HIGH, "No color changing allowed in deathmatch\n"); @@ -624,11 +624,11 @@ void (float inp) Menu_Demoman_Input = { void () Menu_Demoman = { local string s_detpack = "Set detpack for:\n\n"; - local string s_5 = "“‘ 5 seconds \n"; - local string s_20 = "”‘ 20 seconds \n"; - local string s_50 = "•‘ 50 seconds \n"; - local string s_255 = "–‘ 255 seconds\n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_5 = "“‘ 5 seconds \n"; + local string s_20 = "”‘ 20 seconds \n"; + local string s_50 = "•‘ 50 seconds \n"; + local string s_255 = "–‘ 255 seconds\n"; + local string s_nothing = "\n—‘ Nothing "; Status_Menu(self, Menu_Demoman_Input, s_detpack, s_5, s_20, s_50, s_255, s_nothing); } @@ -642,7 +642,7 @@ void (float inp) Menu_Demoman_Cancel_Input = { void () Menu_Demoman_Cancel = { local string s_detpack = "Setting detpack...\n\n"; - local string s_cancel = "“‘ Cancel!\n\n\n\n\n"; + local string s_cancel = "“‘ Cancel!\n\n\n\n\n"; Status_Menu(self, Menu_Demoman_Cancel_Input, s_detpack, s_cancel); } @@ -715,35 +715,35 @@ void (entity player) Menu_Engineer = { local string s_disp = "\n"; local string s_dsentry = "\n"; local string s_ddisp = "\n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_nothing = "\n—‘ Nothing "; if (player.has_sentry) { s_sentry = "\n"; - s_dsentry = "•‘ Destroy sentry gun \n"; + s_dsentry = "•‘ Destroy sentry gun \n"; te = findradius(player.origin, 100); while (te) { if (te.classname == "building_sentrygun") { if (te.real_owner == player) - s_dsentry = "•‘ Dismantle sentry gun\n"; + s_dsentry = "•‘ Dismantle sentry gun\n"; } te = te.chain; } } else if (player.ammo_cells >= 130) { - s_sentry = "“‘ Build sentry gun \n"; + s_sentry = "“‘ Build sentry gun \n"; } if (player.has_dispenser) { - s_ddisp = "–‘ Destroy dispenser \n"; + s_ddisp = "–‘ Destroy dispenser \n"; te = findradius(player.origin, 100); while (te) { if (te.classname == "building_dispenser") { if (te.real_owner == player) - s_ddisp = "–‘ Dismantle dispenser \n"; + s_ddisp = "–‘ Dismantle dispenser \n"; } te = te.chain; } } else if (player.ammo_cells >= 100) { - s_disp = "”‘ Build dispenser \n"; + s_disp = "”‘ Build dispenser \n"; } if ((player.has_dispenser || player.has_sentry) && !player.has_menutimer) { @@ -786,23 +786,23 @@ void (float inp) Menu_EngineerFix_Dispenser_Input = { void () Menu_EngineerFix_Dispenser = { local string s_action = "Dispenser maintenance:\n\n"; local string s_ammo, s_armor, s_repair; - local string s_nothing = "\n—‘ Nothing \n\n"; + local string s_nothing = "\n—‘ Nothing \n\n"; if ((self.ammo_shells > 0 && self.building.ammo_shells < 400) || (self.ammo_nails > 0 && self.building.ammo_nails < 600) || (self.ammo_rockets > 0 && self.building.ammo_rockets < 300) || (self.ammo_cells > 0 && self.building.ammo_cells < 400)) - s_ammo = "“‘ Insert ammo \n"; + s_ammo = "“‘ Insert ammo \n"; else s_ammo = "\n"; if (self.armorvalue > 0 && self.building.armorvalue < 500) - s_armor = "”‘ Insert armor\n"; + s_armor = "”‘ Insert armor\n"; else s_armor = "\n"; if (old_spanner && self.building.health < self.building.max_health) - s_repair = "•‘ Repair \n"; + s_repair = "•‘ Repair \n"; else s_repair = "\n"; @@ -827,10 +827,10 @@ void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { void () Menu_EngineerFix_SentryGun_Rotate = { local string action = "Rotate sentry gun:\n\n"; - local string rotl = "“‘ anticlockwise\n"; - local string rot180 = "”‘ 180 degrees \n"; - local string rotr = "•‘ clockwise \n"; - local string nothing = "\n—‘ Nothing \n"; + local string rotl = "“‘ anticlockwise\n"; + local string rot180 = "”‘ 180 degrees \n"; + local string rotr = "•‘ clockwise \n"; + local string nothing = "\n—‘ Nothing \n"; if (!self.building.real_owner.has_sentry || self.building.real_owner != self || self.classname != "player" || self.building == world) @@ -865,26 +865,26 @@ void () Menu_EngineerFix_SentryGun = { local string action = "Sentry gun maintenance:\n\n"; local string putammo, upgrade, repair, rotate; - local string nothing = "\n—‘ Nothing "; + local string nothing = "\n—‘ Nothing "; if ((self.ammo_shells > 0 && self.building.ammo_shells < self.building.maxammo_shells) || (self.ammo_rockets > 0 && self.building.weapon == 3 && self.building.ammo_rockets < self.building.maxammo_rockets)) - putammo = "“‘ Insert ammo\n"; + putammo = "“‘ Insert ammo\n"; else putammo = "\n"; if (self.building.weapon < 3 && self.ammo_cells >= 130) - upgrade = "”‘ Upgrade \n"; + upgrade = "”‘ Upgrade \n"; else upgrade = "\n"; if (self.building.health < self.building.max_health) - repair = "•‘ Repair \n"; + repair = "•‘ Repair \n"; else repair = "\n"; if (self.building.real_owner == self) - rotate = "–‘ Rotate \n"; + rotate = "–‘ Rotate \n"; else rotate = "\n"; @@ -965,18 +965,18 @@ void (float inp) Menu_Dispenser_Input = { void () Menu_Dispenser = { local string s_action = "Use dispenser:\n\n"; local string s_ammo, s_armor; - local string s_nothing = "\n—‘ Nothing \n\n"; + local string s_nothing = "\n—‘ Nothing \n\n"; if ((self.building.ammo_shells > 0 && self.ammo_shells < self.maxammo_shells) || (self.building.ammo_nails > 0 && self.ammo_nails < self.maxammo_nails) || (self.building.ammo_rockets > 0 && self.ammo_rockets < self.maxammo_rockets) || (self.building.ammo_cells > 0 && self.ammo_cells < self.maxammo_cells)) - s_ammo = "“‘ Withdraw some ammo \n"; + s_ammo = "“‘ Withdraw some ammo \n"; else s_ammo = "\n"; if (self.building.armorvalue > 0 && self.armorvalue < self.maxarmor) - s_armor = "”‘ Withdraw some armor\n"; + s_armor = "”‘ Withdraw some armor\n"; else s_armor = "\n"; @@ -992,7 +992,7 @@ void (float inp) Menu_Engineer_Cancel_Input = { void () Menu_Engineer_Cancel = { local string s_build = "Building...\n\n"; - local string s_cancel = "“‘ Cancel!\n\n\n\n\n"; + local string s_cancel = "“‘ Cancel!\n\n\n\n\n"; Status_Menu(self, Menu_Engineer_Cancel_Input, s_build, s_cancel); } diff --git a/spy.qc b/spy.qc index 78b2923c..57ce28ed 100644 --- a/spy.qc +++ b/spy.qc @@ -541,9 +541,9 @@ void (float issilent) CF_Spy_FeignDeath = { tfgoalitem_RemoveFromPlayer(te, self, 0); if (CTF_Map == 1) { if (te.goal_no == 1) - bprint(PRINT_HIGH, self.netname, " ΜΟΣΤ the ΒΜΥΕ flag!\n"); + bprint(PRINT_HIGH, self.netname, " ΓŒΓΓ“Γ” the Γ‚ΓŒΓ•Γ… flag!\n"); else if (te.goal_no == 2) - bprint(PRINT_HIGH, self.netname, " ΜΟΣΤ the ΕΔ flag!\n"); + bprint(PRINT_HIGH, self.netname, " ΓŒΓΓ“Γ” the Γ’Γ…Γ„ flag!\n"); } } te = find(te, classname, "item_tfgoal"); @@ -1151,7 +1151,7 @@ void () HallucinationTimer = { stuffcmd(self.owner, "play weapons/tink1.wav\n"); } else if (halltype2 < 0.55) { CenterPrint2(self.owner, "\n\n\n", - "Your team ΓΑΠΤΥΕΔ the flag!!"); + "Your team ÃÁŴÔÕÒÅÄ the flag!!"); stuffcmd(self.owner, "play weapons/grenade.wav\n"); } else if (halltype2 < 0.6) { stuffcmd(self.owner, "play weapons/bounce.wav\n"); @@ -1203,7 +1203,7 @@ void () HallucinationTimer = { stuffcmd(self.owner, "play weapons/sniper.wav\n"); } else if (halltype2 < 0.6) { CenterPrint2(self.owner, "\n\n\n", - "Your flag has been ΤΑΛΕΞ!!"); + "Your flag has been Γ”ΓΓ‹Γ…ΓŽ!!"); stuffcmd(self.owner, "play weapons/flmfire2.wav\n"); } else if (halltype2 < 0.7) { stuffcmd(self.owner, "play weapons/flmgrexp.wav\n"); @@ -1376,4 +1376,4 @@ void () Spy_DropBackpack = { newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; +}; \ No newline at end of file diff --git a/status.qc b/status.qc index 6c904fe5..d5905190 100644 --- a/status.qc +++ b/status.qc @@ -39,7 +39,7 @@ string (float class) CF_GetRandomClassTip { if (self.tip_type == 1) { // general tip - tiptype = "Ηεξεςαμ τιπ:\n"; + tiptype = "Γ‡Γ₯ΓΓ₯òÑì ôéš:\n"; while (strlen(line1) == 0) { if (!self.display_tip) @@ -93,7 +93,7 @@ string (float class) CF_GetRandomClassTip { } } else { // class tip - tiptype = "Γμασσ Τιπ:\n"; + tiptype = "ÃìÑóó Ôéš:\n"; if (class == PC_SCOUT) { while (strlen(line1) == 0) { @@ -608,7 +608,7 @@ void (entity pl) RefreshStatusBar = { // status line 1 column 1 - grenade timer if (pl.StatusGrenTime > 0) { - st1 = strcat("Ηςεξαδε: ", ftos(pl.StatusGrenTime)); + st1 = strcat("ÇòΓ₯ΓÑÀΓ₯: ", ftos(pl.StatusGrenTime)); if (pl.fragstreak > 1 && pl.caps) st1 = strcat(st1, " sec"); else @@ -617,14 +617,14 @@ void (entity pl) RefreshStatusBar = { st1 = ""; // status line 1 column 3 - kill streak & caps if (pl.fragstreak > 1) { - st2 = "Λιμμ στςεαλ: "; + st2 = "Ëéìì óôòΓ₯Ñë: "; st2 = strcat(st2, strpadl(ftos(pl.fragstreak),2)); } else st2 = ""; if (pl.caps) { if (pl.fragstreak > 1) st2 = strcat(st2, " "); - st3 = "Γαπσ: "; + st3 = "ÃÑšó: "; st3 = strcat(st3, strpadl(ftos(pl.caps),2)); } else st3 = ""; @@ -697,7 +697,7 @@ void (entity pl) RefreshStatusBar = { // status line 3 column 2 - clip size if (pl.tfstate & TFSTATE_RELOADING) { - st2 = "Γμιπ: "; + st2 = "Ãìéš: "; if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { st2 = strcat(st2, strpadl(ftos(25 * pl.reload_sniper_ticks), 3)); st2 = strcat(st2, "% "); @@ -714,10 +714,10 @@ void (entity pl) RefreshStatusBar = { } // status line 3 column 3 - grenade 1 count - st3 = strcat("Ηςεξ±: ", ftos(pl.no_grenades_1)); + st3 = strcat("ÇòΓ₯Γḟ: ", ftos(pl.no_grenades_1)); // status line 3 column 4 - grenade 2 count - st4 = strcat("Ηςεξ²: ", ftos(pl.no_grenades_2)); + st4 = strcat("ÇòΓ₯ΓΔ : ", ftos(pl.no_grenades_2)); // status line 3 s3 = strcat(st1, st2); @@ -751,7 +751,7 @@ string(float num) BlueScoreToString = if (num > 999) num = 999; - return strcat("Βμυε:", strpadl(ftos(floor(num)), 3)); + return strcat("ÂìáΓ₯:", strpadl(ftos(floor(num)), 3)); }; string(float num) RedScoreToString = @@ -759,7 +759,7 @@ string(float num) RedScoreToString = if (num > 999) num = 999; - return strcat("εδ :", strpadl(ftos(floor(num)), 3)); + return strcat("Γ’Γ₯Γ€ :", strpadl(ftos(floor(num)), 3)); }; string(float num) YellowScoreToString = @@ -767,7 +767,7 @@ string(float num) YellowScoreToString = if (num > 999) num = 999; - return strcat("Ωεμμ:", strpadl(ftos(floor(num)), 3)); + return strcat("Γ™Γ₯ìì:", strpadl(ftos(floor(num)), 3)); }; string(float num) GreenScoreToString = @@ -775,7 +775,7 @@ string(float num) GreenScoreToString = if (num > 999) num = 999; - return strcat("Ηςεξ:", strpadl(ftos(floor(num)), 3)); + return strcat("ÇòΓ₯Γ:", strpadl(ftos(floor(num)), 3)); }; string(entity pl) ClipSizeToString = @@ -812,7 +812,7 @@ string(entity pl) ClipSizeToString = if (num > 99) num = 99; - st = "Γμιπ: "; + st = "Ãìéš: "; st = strcat(st, strpadl(ftos(floor(num)), 2)); st = strcat(st, "/"); st = strcat(st, strpadr(ftos(max), 3)); @@ -871,9 +871,9 @@ string(entity pl) DisguiseToString = if (pl.is_undercover == 1) { if (self.items & IT_INVISIBILITY) { - st = "Ιξφισιβμε"; + st = "Γ‰ΓâéóéÒìΓ₯"; } else { - st = "Υξδεςγοφες: "; + st = "Γ•ΓΓ€Γ₯òãïâΓ₯Γ²: "; if (pl.undercover_team) { st = strcat(st, TeamToString(pl.undercover_team)); st = strcat(st, " "); @@ -883,7 +883,7 @@ string(entity pl) DisguiseToString = } } else if (pl.is_undercover == 2) { if (invis_only) { - st = "Ιξφισιβμε in "; + st = "Γ‰ΓâéóéÒìΓ₯ in "; st = strcat(st, ftos(pl.undercover_timer)); st = strcat(st, " seconds"); } else { @@ -912,7 +912,7 @@ string(entity pl) DisguiseToString = } else if (pl.undercover_skin) { skin = strcat(skin, ClassToString(pl.undercover_skin)); } - st = "Υξδεςγοφες: "; + st = "Γ•ΓΓ€Γ₯òãïâΓ₯Γ²: "; st = strcat(st, team); st = strcat(st, skin); } @@ -929,7 +929,7 @@ string(entity pl) SniperPowerToString = return st; if (pl.heat) { - st = "Ποχες: "; + st = "Ε΄Γ―αΉ«Γ₯Γ²: "; st = strcat(st, ftos(pl.heat)); st = strcat(st, " dmg"); if (pl.power_full) { @@ -945,14 +945,14 @@ string(entity pl) DetpackToString = local string st = ""; if (pl.is_detpacking) { - st = "Δετπαγλ: "; + st = "Γ„Γ₯ôšÑãë: "; st = strcat(st, ftos(pl.detpack_left)); st = strcat(st, " ("); st = strcat(st, ftos(pl.is_detpacking)); st = strcat(st, ")"); st = strcat(st, " seconds left"); } else if (pl.detpack_left) { - st = "Δετπαγλ: "; + st = "Γ„Γ₯ôšÑãë: "; st = strcat(st, ftos(pl.detpack_left)); st = strcat(st, " seconds left"); } @@ -965,7 +965,7 @@ string(entity pl) AuraToString = local string st; if (medicaura) { - st = "Θεαμιξη Αυςα: "; + st = "ÈΓ₯ÑìéΓç ÁáòÑ: "; if (pl.aura_active) { if (time < pl.aura_healtime && pl.aura_healcount) { @@ -993,7 +993,7 @@ string(entity pl) AuraToString = string(entity pl) AssaultCannonToString = { if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_LOCK)) - return "Ασσαυμτ Γαξξοξ Μογλεδ"; + return "ÁóóÑáìô ÃÑΓΓΓ―Γ ÌïãëΓ₯Γ€"; else return ""; }; @@ -1039,23 +1039,23 @@ string(entity pl) ScannerToString = } if (pl.ScannerOn != 1) { - return "Σγαξξες: off"; + return "ΓΓΓ₯Γ²: off"; } if (te.health > 0) { - st = "Σγαξξες: "; + st = "ΓΓΓ₯Γ²: "; st = strcat(st, TeamToString(te.team_no)); st = strcat(st, " "); st = strcat(st, ClassToString(te.playerclass)); st = strpadr(st, 26); - range = "αξηε: "; + range = "Γ’Γ‘ΓΓ§Γ₯: "; range = strcat(range, RangeToString(pl)); pad = 40 - strlen(range); st = strpadr(st, pad); st = strcat(st, range); } else { - st = "Σγαξξες: on"; - st = strcat(st, " Σγαξξιξη: "); + st = "ΓΓΓ₯Γ²: on"; + st = strcat(st, " ΓΓΓ©ΓΓ§: "); if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { scanfor = "team"; @@ -1093,14 +1093,14 @@ string(entity pl) SentryDetailsToString = if (self.sentry_ent.weapon == 3) { rockets = ftos(floor(self.sentry_ent.ammo_rockets)); - ammo = strcat(" Αννο: ", strcat(shells, strcat("/", rockets))); + ammo = strcat(" Áííï: ", strcat(shells, strcat("/", rockets))); } else { - ammo = strcat(" Αννο: ", shells); + ammo = strcat(" Áííï: ", shells); } - st = strcat("Σεξτςω: ", strcat(hp, ammo)); + st = strcat("Γ“Γ₯Γôòù: ", strcat(hp, ammo)); st = strpadr(st, 32); - st = strcat(st, strcat("Μεφεμ: ", ftos(self.sentry_ent.weapon))); + st = strcat(st, strcat("ÌΓ₯ΓΆΓ₯Γ¬: ", ftos(self.sentry_ent.weapon))); } return st; @@ -1113,7 +1113,7 @@ string(entity pl) BuildingToString = if (!buildstatus) return "Building..."; - st = "Βυιμδιξη: "; + st = "ÂáéìÀéΓΓ§: "; st = strcat(st, ftos(pl.building_percentage)); st = strcat(st, "%"); diff --git a/vote.qc b/vote.qc index 53570b80..acff5619 100644 --- a/vote.qc +++ b/vote.qc @@ -542,7 +542,7 @@ void (entity pe_player) Vote_Menu = { if (vote1_map != string_null) { strunzone(s_tmp1); - s_tmp1 = strcat("“‘ ", vote1_map); + s_tmp1 = strcat("“‘ ", vote1_map); if (vote1_cnt) s_tmp1 = strzone(strcat(s_tmp1, strcat(" (", strcat(ftos(vote1_cnt), " votes)")))); else @@ -552,7 +552,7 @@ void (entity pe_player) Vote_Menu = { } if (vote2_map != string_null) { strunzone(s_tmp2); - s_tmp2 = strcat("”‘ ", vote2_map); + s_tmp2 = strcat("”‘ ", vote2_map); if (vote2_cnt) s_tmp2 = strzone(strcat(s_tmp2, strcat(" (", strcat(ftos(vote2_cnt), " votes)")))); else @@ -563,7 +563,7 @@ void (entity pe_player) Vote_Menu = { if (vote3_map != string_null) { strunzone(s_tmp3); if (!vote_decider || vote3_cnt) - s_tmp3 = strcat("•‘ ", vote3_map); + s_tmp3 = strcat("•‘ ", vote3_map); if (vote3_cnt) s_tmp3 = strzone(strcat(s_tmp3, strcat(" (", strcat(ftos(vote3_cnt), " votes)")))); else @@ -574,7 +574,7 @@ void (entity pe_player) Vote_Menu = { if (vote4_map != string_null) { strunzone(s_tmp4); if (!vote_decider || vote4_cnt) - s_tmp4 = strcat("–‘ ", vote4_map); + s_tmp4 = strcat("–‘ ", vote4_map); if (vote4_cnt) s_tmp4 = strzone(strcat(s_tmp4, strcat(" (", strcat(ftos(vote4_cnt), " votes)")))); else @@ -585,7 +585,7 @@ void (entity pe_player) Vote_Menu = { if (vote5_map != string_null) { strunzone(s_tmp5); if (!vote_decider || vote5_cnt) - s_tmp5 = strcat("—‘ ", vote5_map); + s_tmp5 = strcat("—‘ ", vote5_map); if (vote5_cnt) s_tmp5 = strzone(strcat(s_tmp5, strcat(" (", strcat(ftos(vote5_cnt), " votes)")))); else @@ -1078,4 +1078,4 @@ string (string ps_list, float pf_idx) List_Index = { return strzone(substr(ps_list, f_start, i - f_start)); return strzone(string_null); -}; +}; \ No newline at end of file From c9f9d3d935ae4e75566951b01387808ef06bc71f Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 18 Nov 2018 01:38:34 +1100 Subject: [PATCH 0471/2474] enable utf8 warnings due to vs code issues --- fteextensions.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fteextensions.qc b/fteextensions.qc index 3f155dd8..09beb673 100644 --- a/fteextensions.qc +++ b/fteextensions.qc @@ -18,8 +18,8 @@ Available options: #pragma warning error Q105 /*too few parms*/ #pragma warning error Q106 /*assignment to constant/lvalue*/ #pragma warning disable Q208 /*system crc unknown*/ -#pragma warning disable F211 /*system crc outdated (eg: dp's csqc)*/ -#pragma warning disable F301 /*non-utf-8 strings*/ +#pragma warning disable F211 /*system crc outdated (eg: dp's csqc)*/ +#pragma warning enable F301 /*non-utf-8 strings*/ #pragma warning enable F302 /*uninitialised locals*/ From e7771343ac588f6aa12a204725cf1b984937cf3c Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 18 Nov 2018 01:39:44 +1100 Subject: [PATCH 0472/2474] rename crossproduct due to return type and name clash with fte extensions --- tfort.qc | 2 +- weapons.qc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tfort.qc b/tfort.qc index 0ca6e222..10668a08 100644 --- a/tfort.qc +++ b/tfort.qc @@ -3085,7 +3085,7 @@ void () PlayerObserverMode = { stuffcmd(self, "cl_rollangle 0\n"); }; -float (vector veca, vector vecb) crossproduct = { +float (vector veca, vector vecb) crossproducttf = { local float result; result = veca_x * vecb_y - vecb_x * veca_y; diff --git a/weapons.qc b/weapons.qc index 7552e5a2..e01d285a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1,7 +1,7 @@ void () player_run; void () TeamFortress_DisplayDetectionItems; -float (vector veca, vector vecb) crossproduct; +float (vector veca, vector vecb) crossproducttf; void (vector org, float damage) SpawnBlood; @@ -185,7 +185,7 @@ void () W_FireAxe = { makevectors(self.v_angle); // Backstab - if (crossproduct(def, v_forward) > 0) { + if (crossproducttf(def, v_forward) > 0) { deathmsg = DMSG_BACKSTAB; TF_T_Damage(trace_ent, self, self, 120, TF_TD_NOTTEAM | TF_TD_IGNOREARMOUR, From 69ed901993d91eb70635cb7ff77331de5127e0ff Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 18 Nov 2018 14:52:22 +1100 Subject: [PATCH 0473/2474] enable fte extensions --- defs.qc | 26 +++++++++++++------------- progs.src | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/defs.qc b/defs.qc index 1cbf2a96..03897dbd 100644 --- a/defs.qc +++ b/defs.qc @@ -315,12 +315,12 @@ void (entity e, vector min, vector max) setsize = #4; // #5 was removed // #6 was removed (was: break) float () random = #7; // returns 0 - 1 -void (entity e, float chan, string samp, float vol, float atten) sound = #8; +//void (entity e, float chan, string samp, float vol, float atten) sound = #8; vector(vector v) normalize = #9; void (string e) error = #10; void (string e) objerror = #11; float (vector v) vlen = #12; -float (vector v) vectoyaw = #13; +//float (vector v) vectoyaw = #13; entity()spawn = #14; void (entity e) remove = #15; @@ -336,25 +336,25 @@ entity(entity start,.string fld, string match) find = #18; string(string s) precache_sound = #19; string(string s) precache_model = #20; void (entity client, string s) stuffcmd = #21; -entity(vector org, float rad) findradius = #22; -void (...) bprint = #23; +//entity(vector org, float rad) findradius = #22; +//void (...) bprint = #23; void (...) bprint2 = #23; void (...) bprint3 = #23; void (...) bprint4 = #23; -void (...) sprint = #24; +//void (...) sprint = #24; void (...) sprint2 = #24; void (...) sprint3 = #24; -void (...) dprint = #25; +//void (...) dprint = #25; string(float f) ftos = #26; string(vector v) vtos = #27; void () coredump = #28; // prints all edicts void () traceon = #29; // turns statment trace on void () traceoff = #30; void (entity e) eprint = #31; // prints an entire edict -float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE +//float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE // #33 was removed float () droptofloor = #34; // TRUE if landed on floor -void (float style, string value) lightstyle = #35; +//void (float style, string value) lightstyle = #35; float (float v) rint = #36; // round to nearest int float (float v) floor = #37; // largest integer <= v float (float v) ceil = #38; // smallest integer >= v @@ -371,7 +371,7 @@ void (vector o, vector d, float color, float count) particle = #48; void () ChangeYaw = #49; // turn towards self.ideal_yaw // at self.yaw_speed // #50 was removed -vector(vector v) vectoangles = #51; +//vector(vector v) vectoangles = #51; // // direct client message generation @@ -391,13 +391,13 @@ void (float step) movetogoal = #67; string(string s) precache_file = #68; // no effect except for -copy void (entity e) makestatic = #69; -void (string s) changelevel = #70; +//void (string s) changelevel = #70; //#71 was removed void (string var, string val) cvar_set = #72; // sets cvar.value -void (...) centerprint = #73; // sprint, but in middle +//void (...) centerprint = #73; // sprint, but in middle void (vector pos, string samp, float vol, float atten) ambientsound = #74; @@ -421,10 +421,10 @@ float (float min, float value, float max) bound = #96; float (float x, float y) pow = #97; float (string s) strlen = #114; -string (string s1, string s2) strcat = #115; +//string (string s1, string s2) strcat = #115; string (string s, float start, float count) substr = #116; string (string s, ...) strzone = #118; -void (string s, ...) strunzone = #119; +//void (string s, ...) strunzone = #119; void() calltimeofday = #231; // force server to call mod function timeofday diff --git a/progs.src b/progs.src index 4edb644e..e2b9e91a 100644 --- a/progs.src +++ b/progs.src @@ -1,5 +1,5 @@ qwprogs.dat -//fteextensions.qc +fteextensions.qc defs.qc qw.qc debug.qc From 2a27d4724c70ba3315af8ce421f2354d831de638 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 19 Nov 2018 09:15:18 +1100 Subject: [PATCH 0474/2474] disable fte duplicate extensions --- defs.qc | 26 +++++++++++++------------- fteextensions.qc | 30 +++++++++++++++--------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/defs.qc b/defs.qc index 03897dbd..1cbf2a96 100644 --- a/defs.qc +++ b/defs.qc @@ -315,12 +315,12 @@ void (entity e, vector min, vector max) setsize = #4; // #5 was removed // #6 was removed (was: break) float () random = #7; // returns 0 - 1 -//void (entity e, float chan, string samp, float vol, float atten) sound = #8; +void (entity e, float chan, string samp, float vol, float atten) sound = #8; vector(vector v) normalize = #9; void (string e) error = #10; void (string e) objerror = #11; float (vector v) vlen = #12; -//float (vector v) vectoyaw = #13; +float (vector v) vectoyaw = #13; entity()spawn = #14; void (entity e) remove = #15; @@ -336,25 +336,25 @@ entity(entity start,.string fld, string match) find = #18; string(string s) precache_sound = #19; string(string s) precache_model = #20; void (entity client, string s) stuffcmd = #21; -//entity(vector org, float rad) findradius = #22; -//void (...) bprint = #23; +entity(vector org, float rad) findradius = #22; +void (...) bprint = #23; void (...) bprint2 = #23; void (...) bprint3 = #23; void (...) bprint4 = #23; -//void (...) sprint = #24; +void (...) sprint = #24; void (...) sprint2 = #24; void (...) sprint3 = #24; -//void (...) dprint = #25; +void (...) dprint = #25; string(float f) ftos = #26; string(vector v) vtos = #27; void () coredump = #28; // prints all edicts void () traceon = #29; // turns statment trace on void () traceoff = #30; void (entity e) eprint = #31; // prints an entire edict -//float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE +float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE // #33 was removed float () droptofloor = #34; // TRUE if landed on floor -//void (float style, string value) lightstyle = #35; +void (float style, string value) lightstyle = #35; float (float v) rint = #36; // round to nearest int float (float v) floor = #37; // largest integer <= v float (float v) ceil = #38; // smallest integer >= v @@ -371,7 +371,7 @@ void (vector o, vector d, float color, float count) particle = #48; void () ChangeYaw = #49; // turn towards self.ideal_yaw // at self.yaw_speed // #50 was removed -//vector(vector v) vectoangles = #51; +vector(vector v) vectoangles = #51; // // direct client message generation @@ -391,13 +391,13 @@ void (float step) movetogoal = #67; string(string s) precache_file = #68; // no effect except for -copy void (entity e) makestatic = #69; -//void (string s) changelevel = #70; +void (string s) changelevel = #70; //#71 was removed void (string var, string val) cvar_set = #72; // sets cvar.value -//void (...) centerprint = #73; // sprint, but in middle +void (...) centerprint = #73; // sprint, but in middle void (vector pos, string samp, float vol, float atten) ambientsound = #74; @@ -421,10 +421,10 @@ float (float min, float value, float max) bound = #96; float (float x, float y) pow = #97; float (string s) strlen = #114; -//string (string s1, string s2) strcat = #115; +string (string s1, string s2) strcat = #115; string (string s, float start, float count) substr = #116; string (string s, ...) strzone = #118; -//void (string s, ...) strunzone = #119; +void (string s, ...) strunzone = #119; void() calltimeofday = #231; // force server to call mod function timeofday diff --git a/fteextensions.qc b/fteextensions.qc index 09beb673..29076912 100644 --- a/fteextensions.qc +++ b/fteextensions.qc @@ -1403,8 +1403,8 @@ void() breakpoint = #6; /* float() random = #7; /* Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays. */ -void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs) sound = #8; /* - Starts a sound centered upon the given entity. +//void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs) sound = #8; /* +/* Starts a sound centered upon the given entity. chan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample 'samp' must have been precached first if specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed. @@ -1423,7 +1423,7 @@ void(string e) objerror = #11; /* float(vector v) vlen = #12; /* Returns the square root of the dotproduct of a vector with itself. Or in other words the length of a distance vector, in quake units. */ -float(vector v, optional entity reference) vectoyaw = #13; /* +/*float(vector v, optional entity reference) vectoyaw = #13; /* Given a direction vector, returns the yaw angle in which that direction vector points. If an entity is passed, the yaw angle will be relative to that entity's gravity direction. */ entity() spawn = #14; /* @@ -1474,7 +1474,7 @@ void(entity client, float flags, string s) stuffcmdflags = #0:stuffcmdflags; /* #endif #if defined(CSQC) || defined(SSQC) -entity(vector org, float rad, optional .entity chainfield) findradius = #22; /* +/*entity(vector org, float rad, optional .entity chainfield) findradius = #22; /* Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. */ #endif @@ -1484,7 +1484,7 @@ void(string s, optional string s2, optional string s3, optional string s4, optio #endif #if defined(QWSSQC) -void(float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) bprint = #23; /* +/*void(float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) bprint = #23; /* QW: Concatenates all string arguments, and prints the messsage on the console of only all clients who's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument. */ #endif @@ -1494,7 +1494,7 @@ void(entity client, string s, optional string s2, optional string s3, optional s #endif #if defined(QWSSQC) -void(entity client, float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) sprint = #24; /* +/*void(entity client, float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) sprint = #24; /* QW: Concatenates all string arguments, and prints the messsage on the named client's console, but only if that client's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument. */ #endif @@ -1504,7 +1504,7 @@ void(string s, ...) dprint = #25; /* #endif #if defined(CSQC) || defined(QWSSQC) -void(string s, ...) dprint = #25; /* +/*void(string s, ...) dprint = #25; /* QW: Unconditionally prints the given message on the server's console. Arguments will be concatenated into a single message. */ #endif @@ -1527,7 +1527,7 @@ void() traceoff = #30; /* void(entity e) eprint = #31; /* Debugging builtin that prints all fields of the given entity to the console. */ -float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /* +/*float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /* Attempt to walk the entity at a given angle for a given distance. if settraceglobals is set, the trace_* globals will be set, showing the results of the movement. This function will trigger touch events. */ @@ -1535,7 +1535,7 @@ float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /* float() droptofloor = #34; /* Instantly moves the entity downwards until it hits the ground. If the entity is in solid or would need to drop more than 'pr_droptofloorunits' quake units, its position will be considered invalid and the builtin will abort, returning FALSE, otherwise TRUE. */ -void(float lightstyle, string stylestring, optional vector rgb) lightstyle = #35; /* +/*void(float lightstyle, string stylestring, optional vector rgb) lightstyle = #35; /* Specifies an auto-animating string that specifies the light intensity for entities using that lightstyle. a is off, z is fully lit. Should be lower case only. rgb will recolour all lights using that lightstyle. */ @@ -1581,7 +1581,7 @@ void(vector pos, vector dir, float colour, float count) particle = #48; /* void() changeyaw = #49; /* Changes the self.angles_y field towards self.ideal_yaw by up to self.yaw_speed. */ -vector(vector fwd, optional vector up) vectoangles = #51; /* +/*vector(vector fwd, optional vector up) vectoangles = #51; /* Returns the angles (+x=UP) required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning. */ #endif @@ -1622,7 +1622,7 @@ void(entity e) makestatic = #69; /* #endif #ifdef SSQC -void(string mapname, optional string newmapstartspot) changelevel = #70; /* +/*void(string mapname, optional string newmapstartspot) changelevel = #70; /* Attempts to change the map to the named map. If 'newmapstartspot' is specified, the state of the current map will be preserved, and the argument will be passed to the next map in the 'startspot' global, and the next map will be loaded from archived state if it was previously visited. If not specified, all archived map states will be purged. */ #endif @@ -1632,7 +1632,7 @@ void(string cvarname, string valuetoset) cvar_set = #72; /* #endif #ifdef SSQC -void(entity ent, string text, optional string text2, optional string text3, optional string text4, optional string text5, optional string text6, optional string text7) centerprint = #73; +//void(entity ent, string text, optional string text2, optional string text3, optional string text4, optional string text5, optional string text6, optional string text7) centerprint = #73; #endif #if defined(CSQC) || defined(SSQC) void (vector pos, string samp, float vol, float atten) ambientsound = #74; @@ -1726,7 +1726,7 @@ float(string builtinname) builtin_find = #100; /* #endif #if defined(CSQC) || defined(SSQC) -float(float value) anglemod = #102; +//float(float value) anglemod = #102; #endif #ifdef SSQC void(string slot, string picname, float x, float y, float zone, optional entity player) showpic = #104; /* Part of TEI_SHOWLMP2*/ @@ -1761,13 +1761,13 @@ int(filestream fhandle, optional int newsize) fsize = #0:fsize; /* Part of FTE_Q #if defined(CSQC) || defined(SSQC) float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +//string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, float start, float length) substring = #116; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ vector(string s) stov = #117; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods. */ -void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS +/*void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing. */ #endif From 34c23c85007e5a24b58254efbfd67666d3f3c46c Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 19 Nov 2018 09:15:32 +1100 Subject: [PATCH 0475/2474] first 'brown text' replacement --- status.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/status.qc b/status.qc index d5905190..eb80b230 100644 --- a/status.qc +++ b/status.qc @@ -39,8 +39,9 @@ string (float class) CF_GetRandomClassTip { if (self.tip_type == 1) { // general tip - tiptype = "Γ‡Γ₯ΓΓ₯òÑì ôéš:\n"; - + //tiptype = "Γ‡Γ₯ΓΓ₯òÑì ôéš:\n"; + tiptype = Q"\sgeneral tip\s:\n"; + while (strlen(line1) == 0) { if (!self.display_tip) self.display_tip = ceil(random() * 14); From 86d94ce2f4bba002074e47e540548dc5b10c852d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 19 Nov 2018 20:31:14 +1100 Subject: [PATCH 0476/2474] Add missing features to readme --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index ac1cbdc0..3376beaf 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ FortressOne Server v0.1.0 New features ------ +* Increased nail velocity. Disable with `localinfo old_ng_velocity on`. +* Nailgun and Super-nailgun damage configurable with `localinfo ng_damage` and `localinfo sng_damage`. +* Keys and flags glow their colour. +* Capping player gets full restock. * Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime`. * Option to fully restock player on cap. `localinfo stock_on_cap on`. * Option for packs to fully restock health and armour of player. `localinfo stockfull on`. @@ -32,6 +36,7 @@ New features * Allow team changing. * Any non-valid impulse now closes the active menu. + == Removed === * Removed weapon messages for weapons without weapon modes. * Removed bioweapon (merged into medikit). @@ -42,6 +47,8 @@ New features * Removed class help. === Fixed === +* Don't allow building in prematch. +* Gas no longer goes through walls. * Fixed the spamming weapon messages (e.g. Tranquiliser gun selected). * Fixed the sentry gun menu to not close prematurely. * Fixed broken ammo display. From c2fab048d0ee6f29eda576ed0e321954bdd2a6ea Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 20 Nov 2018 21:50:50 +1100 Subject: [PATCH 0477/2474] fix bad method name --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index e01d285a..f851eb0f 100644 --- a/weapons.qc +++ b/weapons.qc @@ -591,7 +591,7 @@ void () W_FireMedikit = { } }; -vector()wall_velocity = +vector () wall_velocity = { local vector vel; From f05b4b023163413ac98b5e3d597612d3236cb388 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 20 Nov 2018 22:30:00 +1100 Subject: [PATCH 0478/2474] uncomment fte stuff --- fteextensions.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fteextensions.qc b/fteextensions.qc index 29076912..a9e20a6e 100644 --- a/fteextensions.qc +++ b/fteextensions.qc @@ -1504,7 +1504,7 @@ void(string s, ...) dprint = #25; /* #endif #if defined(CSQC) || defined(QWSSQC) -/*void(string s, ...) dprint = #25; /* +void(string s, ...) dprint = #25; /* QW: Unconditionally prints the given message on the server's console. Arguments will be concatenated into a single message. */ #endif From e09652fc1f0f3e660513ae49ed5abd4ef52ccd22 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 20 Nov 2018 22:30:42 +1100 Subject: [PATCH 0479/2474] reset fte extensions --- fteextensions.qc | 53 +++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/fteextensions.qc b/fteextensions.qc index a9e20a6e..5bf20380 100644 --- a/fteextensions.qc +++ b/fteextensions.qc @@ -14,17 +14,13 @@ Available options: */ #pragma noref 1 //#pragma flag enable logicops -#pragma warning error Q101 /*too many parms*/ -#pragma warning error Q105 /*too few parms*/ -#pragma warning error Q106 /*assignment to constant/lvalue*/ -#pragma warning disable Q208 /*system crc unknown*/ -#pragma warning disable F211 /*system crc outdated (eg: dp's csqc)*/ -#pragma warning enable F301 /*non-utf-8 strings*/ -#pragma warning enable F302 /*uninitialised locals*/ - - -#define QUAKEWORLD - +#pragma warning error Q101 /*too many parms. The vanilla qcc didn't validate properly, hence why fteqcc normally treats it as a warning.*/ +#pragma warning error Q105 /*too few parms. The vanilla qcc didn't validate properly, hence why fteqcc normally treats it as a warning.*/ +#pragma warning error Q106 /*assignment to constant/lvalue. Define them as var if you want to initialise something.*/ +#pragma warning error Q208 /*system crc unknown. Compatibility goes out of the window if you disable this.*/ +#pragma warning disable F211 /*system crc outdated (eg: dp's csqc). Note that this may trigger emulation.*/ +#pragma warning enable F301 /*non-utf-8 strings. Think of the foreigners! Also think of text editors that insist on screwing up your char encodings.*/ +#pragma warning enable F302 /*uninitialised locals. They usually default to 0 in qc (except in recursive functions), but its still probably a bug*/ #if !defined(CSQC) && !defined(NQSSQC) && !defined(QWSSQC)&& !defined(MENU) #ifdef QUAKEWORLD #define QWSSQC @@ -337,8 +333,8 @@ void() StartFrame; /* Called at the start of each new physics frame. Player enti void() PlayerPreThink; /* With Prediction(QW compat/FTE default): Called before the player's input commands are processed. No Prediction(NQ compat): Called AFTER the player's movement intents have already been processed (ie: velocity will have already changed according to input_*, but before the actual position change. */ void() PlayerPostThink; /* Called after the player's input commands are processed. */ -//void() ClientKill; /* Called in response to 'cmd kill' (or just 'kill'). */ -//void(optional float csqcactive) ClientConnect; /* Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. */ +void() ClientKill; /* Called in response to 'cmd kill' (or just 'kill'). */ +void(optional float csqcactive) ClientConnect; /* Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. */ void() PutClientInServer; /* Enginewise, this is only ever called immediately after ClientConnect and is thus a little redundant. Modwise, this is also called for respawning a player etc. */ void() ClientDisconnect; /* Called once a client disconnects or times out. Not guarenteed to be called on map changes. */ void() SetNewParms; /* Called without context when a new client initially connects (before ClientConnect is even called). This function is expected to only set the parm* globals so that they can be decoded properly later. You should not rely on 'self' being set. */ @@ -1226,6 +1222,7 @@ const float LFIELD_ROTATION = 13; const float LFIELD_DIETIME = 14; const float LFIELD_RGBDECAY = 15; const float LFIELD_RADIUSDECAY = 16; +const float LFIELD_STYLESTRING = 17; const float LFLAG_NORMALMODE = 1; const float LFLAG_REALTIMEMODE = 2; const float LFLAG_LIGHTMAP = 4; @@ -1403,8 +1400,8 @@ void() breakpoint = #6; /* float() random = #7; /* Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays. */ -//void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs) sound = #8; /* -/* Starts a sound centered upon the given entity. +void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs) sound = #8; /* + Starts a sound centered upon the given entity. chan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample 'samp' must have been precached first if specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed. @@ -1423,7 +1420,7 @@ void(string e) objerror = #11; /* float(vector v) vlen = #12; /* Returns the square root of the dotproduct of a vector with itself. Or in other words the length of a distance vector, in quake units. */ -/*float(vector v, optional entity reference) vectoyaw = #13; /* +float(vector v, optional entity reference) vectoyaw = #13; /* Given a direction vector, returns the yaw angle in which that direction vector points. If an entity is passed, the yaw angle will be relative to that entity's gravity direction. */ entity() spawn = #14; /* @@ -1474,7 +1471,7 @@ void(entity client, float flags, string s) stuffcmdflags = #0:stuffcmdflags; /* #endif #if defined(CSQC) || defined(SSQC) -/*entity(vector org, float rad, optional .entity chainfield) findradius = #22; /* +entity(vector org, float rad, optional .entity chainfield) findradius = #22; /* Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. */ #endif @@ -1484,7 +1481,7 @@ void(string s, optional string s2, optional string s3, optional string s4, optio #endif #if defined(QWSSQC) -/*void(float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) bprint = #23; /* +void(float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) bprint = #23; /* QW: Concatenates all string arguments, and prints the messsage on the console of only all clients who's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument. */ #endif @@ -1494,7 +1491,7 @@ void(entity client, string s, optional string s2, optional string s3, optional s #endif #if defined(QWSSQC) -/*void(entity client, float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) sprint = #24; /* +void(entity client, float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) sprint = #24; /* QW: Concatenates all string arguments, and prints the messsage on the named client's console, but only if that client's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument. */ #endif @@ -1527,7 +1524,7 @@ void() traceoff = #30; /* void(entity e) eprint = #31; /* Debugging builtin that prints all fields of the given entity to the console. */ -/*float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /* +float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /* Attempt to walk the entity at a given angle for a given distance. if settraceglobals is set, the trace_* globals will be set, showing the results of the movement. This function will trigger touch events. */ @@ -1535,7 +1532,7 @@ void(entity e) eprint = #31; /* float() droptofloor = #34; /* Instantly moves the entity downwards until it hits the ground. If the entity is in solid or would need to drop more than 'pr_droptofloorunits' quake units, its position will be considered invalid and the builtin will abort, returning FALSE, otherwise TRUE. */ -/*void(float lightstyle, string stylestring, optional vector rgb) lightstyle = #35; /* +void(float lightstyle, string stylestring, optional vector rgb) lightstyle = #35; /* Specifies an auto-animating string that specifies the light intensity for entities using that lightstyle. a is off, z is fully lit. Should be lower case only. rgb will recolour all lights using that lightstyle. */ @@ -1581,7 +1578,7 @@ void(vector pos, vector dir, float colour, float count) particle = #48; /* void() changeyaw = #49; /* Changes the self.angles_y field towards self.ideal_yaw by up to self.yaw_speed. */ -/*vector(vector fwd, optional vector up) vectoangles = #51; /* +vector(vector fwd, optional vector up) vectoangles = #51; /* Returns the angles (+x=UP) required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning. */ #endif @@ -1622,7 +1619,7 @@ void(entity e) makestatic = #69; /* #endif #ifdef SSQC -/*void(string mapname, optional string newmapstartspot) changelevel = #70; /* +void(string mapname, optional string newmapstartspot) changelevel = #70; /* Attempts to change the map to the named map. If 'newmapstartspot' is specified, the state of the current map will be preserved, and the argument will be passed to the next map in the 'startspot' global, and the next map will be loaded from archived state if it was previously visited. If not specified, all archived map states will be purged. */ #endif @@ -1632,7 +1629,7 @@ void(string cvarname, string valuetoset) cvar_set = #72; /* #endif #ifdef SSQC -//void(entity ent, string text, optional string text2, optional string text3, optional string text4, optional string text5, optional string text6, optional string text7) centerprint = #73; +void(entity ent, string text, optional string text2, optional string text3, optional string text4, optional string text5, optional string text6, optional string text7) centerprint = #73; #endif #if defined(CSQC) || defined(SSQC) void (vector pos, string samp, float vol, float atten) ambientsound = #74; @@ -1726,7 +1723,7 @@ float(string builtinname) builtin_find = #100; /* #endif #if defined(CSQC) || defined(SSQC) -//float(float value) anglemod = #102; +float(float value) anglemod = #102; #endif #ifdef SSQC void(string slot, string picname, float x, float y, float zone, optional entity player) showpic = #104; /* Part of TEI_SHOWLMP2*/ @@ -1761,13 +1758,13 @@ int(filestream fhandle, optional int newsize) fsize = #0:fsize; /* Part of FTE_Q #if defined(CSQC) || defined(SSQC) float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -//string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, float start, float length) substring = #116; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ vector(string s) stov = #117; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods. */ -/*void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS +void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing. */ #endif @@ -2064,7 +2061,7 @@ float(float modidx, float framenum, int eventidx, __out float timestamp, __out i #endif #define dotproduct(v1,v2) ((vector)(v1)*(vector)(v2)) vector(vector v1, vector v2) crossproduct = #0:crossproduct; /* Part of FTE_QC_CROSSPRODUCT -// Small helper function to calculate the crossproduct of two vectors. */ + Small helper function to calculate the crossproduct of two vectors. */ #if defined(CSQC) || defined(SSQC) float(entity pusher, vector move, vector amove) pushmove = #0:pushmove; From 523099eb55e7dfe8bca23af07336516a58a79456 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 20 Nov 2018 22:31:04 +1100 Subject: [PATCH 0480/2474] change compile order for fte extensions --- progs.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progs.src b/progs.src index e2b9e91a..9ec1798a 100644 --- a/progs.src +++ b/progs.src @@ -1,6 +1,6 @@ qwprogs.dat -fteextensions.qc defs.qc +fteextensions.qc qw.qc debug.qc status.qc From 6fe84587c8c472e664b54ec4fa9d7f7b9610bf3c Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 20 Nov 2018 22:31:18 +1100 Subject: [PATCH 0481/2474] define quakeworld for fte extensions --- defs.qc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/defs.qc b/defs.qc index 1cbf2a96..a32bf4f6 100644 --- a/defs.qc +++ b/defs.qc @@ -344,7 +344,7 @@ void (...) bprint4 = #23; void (...) sprint = #24; void (...) sprint2 = #24; void (...) sprint3 = #24; -void (...) dprint = #25; +//void (...) dprint = #25; string(float f) ftos = #26; string(vector v) vtos = #27; void () coredump = #28; // prints all edicts @@ -464,4 +464,8 @@ float (entity targ, entity inflictor) CanDamage; .string allowteams; .string give; .string active_all_sound; -.string model; \ No newline at end of file +.string model; + + +// enable qw in fteextensions +#define QUAKEWORLD \ No newline at end of file From f09a8f2c3d56efca60a9375c564e42f8c45a40e0 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 20 Nov 2018 23:58:01 +1100 Subject: [PATCH 0482/2474] fix clientkill getting redefined and being bugged because of it. Change custom defs to be in qw.qc instead of defs.qc --- client.qc | 8 +++++--- defs.qc | 12 +----------- qw.qc | 12 ++++++++++++ tfort.qc | 4 +++- tforttm.qc | 10 ++++++++-- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/client.qc b/client.qc index 9be86a74..5a611afb 100644 --- a/client.qc +++ b/client.qc @@ -912,7 +912,7 @@ float () CloseToSpawnPoint = { return 0; }; -void (float force, float free) ClientKill = { +void () ClientKill = { local entity te; local float timeleft; @@ -923,7 +923,7 @@ void (float force, float free) ClientKill = { if (self.playerclass == PC_UNDEFINED) return; - if (self.suicide_time > time && !force) { + if (self.suicide_time > time && self.force == 0) { timeleft = self.suicide_time - time; sprint(self, PRINT_HIGH, "You have to wait ", ftos(ceil(timeleft)), " more seconds to suicide\n"); return; @@ -942,7 +942,7 @@ void (float force, float free) ClientKill = { // players can't suicide again for 10 seconds self.suicide_time = time + 5 + random() * 5; - if (free && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { + if (self.free == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { TeamFortress_SetupRespawn(FALSE); } else { bprint(PRINT_MEDIUM, self.netname, " suicides\n"); @@ -965,6 +965,8 @@ void (float force, float free) ClientKill = { self.th_die(); } + self.force = 0; + self.free = 0; self.health = -1; self.deadflag = DEAD_RESPAWNABLE; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; diff --git a/defs.qc b/defs.qc index a32bf4f6..b946b737 100644 --- a/defs.qc +++ b/defs.qc @@ -60,7 +60,7 @@ void () StartFrame; void () PlayerPreThink; // Called every frame before physics are run void () PlayerPostThink; // Called every frame after physics are run -void (float force, float free) ClientKill; // Player entered the suicide command +void () ClientKill; // Player entered the suicide command void () ClientConnect; // called when a player connects to a server void () PutClientInServer; // call after setting the parm1... parms void () ClientDisconnect; // called when a player disconnects from a server @@ -457,15 +457,5 @@ void (entity targ, entity inflictor, entity attacker, float damage) T_Damage; float (entity e, float healamount, float ignore) T_Heal; // health function float (entity targ, entity inflictor) CanDamage; - -// -// q3 defs -// -.string allowteams; -.string give; -.string active_all_sound; -.string model; - - // enable qw in fteextensions #define QUAKEWORLD \ No newline at end of file diff --git a/qw.qc b/qw.qc index f70effb3..d7e108eb 100644 --- a/qw.qc +++ b/qw.qc @@ -504,6 +504,18 @@ float deathmsg; // Global, which is set before every T_Damage, t float intermission_running; float intermission_exittime; +// q3 defs - enable q3f map ents +.string allowteams; +.string give; +.string active_all_sound; +.string model; + +// add clientkill ent defs +.float force; +.float free; + + + //============================================================================ void (float psize, entity p) KickPlayer = { diff --git a/tfort.qc b/tfort.qc index 10668a08..c9c1acb1 100644 --- a/tfort.qc +++ b/tfort.qc @@ -176,7 +176,9 @@ void (float inp) TeamFortress_ChangeClass = { self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { self.has_changedclass = 1; - ClientKill(0, 1); + self.force = 0; + self.free = 1; + ClientKill(); self.has_changedclass = 0; self.suicide_time = time; } else { diff --git a/tforttm.qc b/tforttm.qc index 9175ddee..3422d1dd 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -209,10 +209,16 @@ float (float tno) TeamFortress_TeamSet = { if (!self.deadflag) { if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { self.has_changedteam = 1; - ClientKill(1, 1); + self.force = 1; + self.free = 1; + ClientKill(); self.has_changedteam = 0; } else - ClientKill(1, 0); + { + self.force = 1; + self.free = 0; + ClientKill(); + } } // remove engineer buildings if (self.playerclass == PC_ENGINEER) From b0c33357a33747a69785db4879e881b65d77f492 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 21 Nov 2018 00:03:14 +1100 Subject: [PATCH 0483/2474] rename client kill ent fields to something a little more descriptive --- client.qc | 8 ++++---- qw.qc | 4 ++-- tfort.qc | 4 ++-- tforttm.qc | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/client.qc b/client.qc index 5a611afb..72880ac5 100644 --- a/client.qc +++ b/client.qc @@ -923,7 +923,7 @@ void () ClientKill = { if (self.playerclass == PC_UNDEFINED) return; - if (self.suicide_time > time && self.force == 0) { + if (self.suicide_time > time && self.clientkillforce == 0) { timeleft = self.suicide_time - time; sprint(self, PRINT_HIGH, "You have to wait ", ftos(ceil(timeleft)), " more seconds to suicide\n"); return; @@ -942,7 +942,7 @@ void () ClientKill = { // players can't suicide again for 10 seconds self.suicide_time = time + 5 + random() * 5; - if (self.free == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { + if (self.clientkillfree == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { TeamFortress_SetupRespawn(FALSE); } else { bprint(PRINT_MEDIUM, self.netname, " suicides\n"); @@ -965,8 +965,8 @@ void () ClientKill = { self.th_die(); } - self.force = 0; - self.free = 0; + self.clientkillforce = 0; + self.clientkillfree = 0; self.health = -1; self.deadflag = DEAD_RESPAWNABLE; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; diff --git a/qw.qc b/qw.qc index d7e108eb..506c13da 100644 --- a/qw.qc +++ b/qw.qc @@ -511,8 +511,8 @@ float intermission_exittime; .string model; // add clientkill ent defs -.float force; -.float free; +.float clientkillforce; +.float clientkillfree; diff --git a/tfort.qc b/tfort.qc index c9c1acb1..18830f78 100644 --- a/tfort.qc +++ b/tfort.qc @@ -176,8 +176,8 @@ void (float inp) TeamFortress_ChangeClass = { self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { self.has_changedclass = 1; - self.force = 0; - self.free = 1; + self.clientkillforce = 0; + self.clientkillfree = 1; ClientKill(); self.has_changedclass = 0; self.suicide_time = time; diff --git a/tforttm.qc b/tforttm.qc index 3422d1dd..12d77965 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -209,14 +209,14 @@ float (float tno) TeamFortress_TeamSet = { if (!self.deadflag) { if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { self.has_changedteam = 1; - self.force = 1; - self.free = 1; + self.clientkillforce = 1; + self.clientkillfree = 1; ClientKill(); self.has_changedteam = 0; } else { - self.force = 1; - self.free = 0; + self.clientkillforce = 1; + self.clientkillfree = 0; ClientKill(); } } From 5bf55be8a591efd3f92fbf7aba695e6e6479cd6b Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 21 Nov 2018 00:59:37 +1100 Subject: [PATCH 0484/2474] WIP - fix some encoded strings --- status.qc | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/status.qc b/status.qc index eb80b230..afeaa1bf 100644 --- a/status.qc +++ b/status.qc @@ -39,7 +39,6 @@ string (float class) CF_GetRandomClassTip { if (self.tip_type == 1) { // general tip - //tiptype = "Γ‡Γ₯ΓΓ₯òÑì ôéš:\n"; tiptype = Q"\sgeneral tip\s:\n"; while (strlen(line1) == 0) { @@ -94,7 +93,7 @@ string (float class) CF_GetRandomClassTip { } } else { // class tip - tiptype = "ÃìÑóó Ôéš:\n"; + tiptype = Q"\sclass tip\s:\n"; if (class == PC_SCOUT) { while (strlen(line1) == 0) { @@ -609,7 +608,7 @@ void (entity pl) RefreshStatusBar = { // status line 1 column 1 - grenade timer if (pl.StatusGrenTime > 0) { - st1 = strcat("ÇòΓ₯ΓÑÀΓ₯: ", ftos(pl.StatusGrenTime)); + st1 = strcat(Q"\sGrenade\s: ", ftos(pl.StatusGrenTime)); if (pl.fragstreak > 1 && pl.caps) st1 = strcat(st1, " sec"); else @@ -618,14 +617,14 @@ void (entity pl) RefreshStatusBar = { st1 = ""; // status line 1 column 3 - kill streak & caps if (pl.fragstreak > 1) { - st2 = "Ëéìì óôòΓ₯Ñë: "; + st2 = Q"\sKill Streak\s: "; st2 = strcat(st2, strpadl(ftos(pl.fragstreak),2)); } else st2 = ""; if (pl.caps) { if (pl.fragstreak > 1) st2 = strcat(st2, " "); - st3 = "ÃÑšó: "; + st3 = Q"\sCaps\s: "; st3 = strcat(st3, strpadl(ftos(pl.caps),2)); } else st3 = ""; @@ -698,7 +697,7 @@ void (entity pl) RefreshStatusBar = { // status line 3 column 2 - clip size if (pl.tfstate & TFSTATE_RELOADING) { - st2 = "Ãìéš: "; + st2 = Q"\sClip\s: "; if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { st2 = strcat(st2, strpadl(ftos(25 * pl.reload_sniper_ticks), 3)); st2 = strcat(st2, "% "); @@ -715,10 +714,10 @@ void (entity pl) RefreshStatusBar = { } // status line 3 column 3 - grenade 1 count - st3 = strcat("ÇòΓ₯Γḟ: ", ftos(pl.no_grenades_1)); + st3 = strcat(Q"\sGren1\s: ", ftos(pl.no_grenades_1)); // status line 3 column 4 - grenade 2 count - st4 = strcat("ÇòΓ₯ΓΔ : ", ftos(pl.no_grenades_2)); + st4 = strcat(Q"\sGren2\s: ", ftos(pl.no_grenades_2)); // status line 3 s3 = strcat(st1, st2); @@ -752,7 +751,7 @@ string(float num) BlueScoreToString = if (num > 999) num = 999; - return strcat("ÂìáΓ₯:", strpadl(ftos(floor(num)), 3)); + return strcat(Q"\sBlue\s:", strpadl(ftos(floor(num)), 3)); }; string(float num) RedScoreToString = @@ -760,7 +759,7 @@ string(float num) RedScoreToString = if (num > 999) num = 999; - return strcat("Γ’Γ₯Γ€ :", strpadl(ftos(floor(num)), 3)); + return strcat(Q"\sRed\s :", strpadl(ftos(floor(num)), 3)); }; string(float num) YellowScoreToString = @@ -768,7 +767,7 @@ string(float num) YellowScoreToString = if (num > 999) num = 999; - return strcat("Γ™Γ₯ìì:", strpadl(ftos(floor(num)), 3)); + return strcat(Q"\sYell\s:", strpadl(ftos(floor(num)), 3)); }; string(float num) GreenScoreToString = @@ -776,7 +775,7 @@ string(float num) GreenScoreToString = if (num > 999) num = 999; - return strcat("ÇòΓ₯Γ:", strpadl(ftos(floor(num)), 3)); + return strcat(Q"\sGren\s:", strpadl(ftos(floor(num)), 3)); }; string(entity pl) ClipSizeToString = @@ -813,7 +812,7 @@ string(entity pl) ClipSizeToString = if (num > 99) num = 99; - st = "Ãìéš: "; + st = Q"\sClip\s: "; st = strcat(st, strpadl(ftos(floor(num)), 2)); st = strcat(st, "/"); st = strcat(st, strpadr(ftos(max), 3)); @@ -872,9 +871,9 @@ string(entity pl) DisguiseToString = if (pl.is_undercover == 1) { if (self.items & IT_INVISIBILITY) { - st = "Γ‰ΓâéóéÒìΓ₯"; + st = Q"\sInvisible\s"; } else { - st = "Γ•ΓΓ€Γ₯òãïâΓ₯Γ²: "; + st = Q"\sUndercover\s: "; if (pl.undercover_team) { st = strcat(st, TeamToString(pl.undercover_team)); st = strcat(st, " "); @@ -884,7 +883,7 @@ string(entity pl) DisguiseToString = } } else if (pl.is_undercover == 2) { if (invis_only) { - st = "Γ‰ΓâéóéÒìΓ₯ in "; + st = Q"\sInvisible\s in "; st = strcat(st, ftos(pl.undercover_timer)); st = strcat(st, " seconds"); } else { @@ -913,7 +912,7 @@ string(entity pl) DisguiseToString = } else if (pl.undercover_skin) { skin = strcat(skin, ClassToString(pl.undercover_skin)); } - st = "Γ•ΓΓ€Γ₯òãïâΓ₯Γ²: "; + st = Q"\sUndercover\s: "; st = strcat(st, team); st = strcat(st, skin); } @@ -946,14 +945,14 @@ string(entity pl) DetpackToString = local string st = ""; if (pl.is_detpacking) { - st = "Γ„Γ₯ôšÑãë: "; + st = Q"\sDetpack\s: "; st = strcat(st, ftos(pl.detpack_left)); st = strcat(st, " ("); st = strcat(st, ftos(pl.is_detpacking)); st = strcat(st, ")"); st = strcat(st, " seconds left"); } else if (pl.detpack_left) { - st = "Γ„Γ₯ôšÑãë: "; + st = Q"\sDetpack\s: "; st = strcat(st, ftos(pl.detpack_left)); st = strcat(st, " seconds left"); } @@ -966,7 +965,7 @@ string(entity pl) AuraToString = local string st; if (medicaura) { - st = "ÈΓ₯ÑìéΓç ÁáòÑ: "; + st = Q"\sHealing Aura\s: "; if (pl.aura_active) { if (time < pl.aura_healtime && pl.aura_healcount) { @@ -994,7 +993,7 @@ string(entity pl) AuraToString = string(entity pl) AssaultCannonToString = { if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_LOCK)) - return "ÁóóÑáìô ÃÑΓΓΓ―Γ ÌïãëΓ₯Γ€"; + return Q"\sAssault Cannon Locked\s"; else return ""; }; @@ -1040,11 +1039,11 @@ string(entity pl) ScannerToString = } if (pl.ScannerOn != 1) { - return "ΓΓΓ₯Γ²: off"; + return Q"\sScanner\s: off"; } if (te.health > 0) { - st = "ΓΓΓ₯Γ²: "; + st = Q"\sScanner\s: "; st = strcat(st, TeamToString(te.team_no)); st = strcat(st, " "); st = strcat(st, ClassToString(te.playerclass)); From 0befcab567f75515ec8a5600bd3d7207f50bff1e Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 21 Nov 2018 13:16:38 +1100 Subject: [PATCH 0485/2474] finish encoded strings in status.qc --- status.qc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/status.qc b/status.qc index afeaa1bf..f302702a 100644 --- a/status.qc +++ b/status.qc @@ -39,7 +39,7 @@ string (float class) CF_GetRandomClassTip { if (self.tip_type == 1) { // general tip - tiptype = Q"\sgeneral tip\s:\n"; + tiptype = Q"\sGeneral tip\s:\n"; while (strlen(line1) == 0) { if (!self.display_tip) @@ -93,7 +93,7 @@ string (float class) CF_GetRandomClassTip { } } else { // class tip - tiptype = Q"\sclass tip\s:\n"; + tiptype = Q"\sClass tip\s:\n"; if (class == PC_SCOUT) { while (strlen(line1) == 0) { @@ -929,7 +929,7 @@ string(entity pl) SniperPowerToString = return st; if (pl.heat) { - st = "Ε΄Γ―αΉ«Γ₯Γ²: "; + st = Q"\spower\s: "; st = strcat(st, ftos(pl.heat)); st = strcat(st, " dmg"); if (pl.power_full) { @@ -1048,14 +1048,14 @@ string(entity pl) ScannerToString = st = strcat(st, " "); st = strcat(st, ClassToString(te.playerclass)); st = strpadr(st, 26); - range = "Γ’Γ‘ΓΓ§Γ₯: "; + range = Q"\srange\s: "; range = strcat(range, RangeToString(pl)); pad = 40 - strlen(range); st = strpadr(st, pad); st = strcat(st, range); } else { - st = "ΓΓΓ₯Γ²: on"; - st = strcat(st, " ΓΓΓ©ΓΓ§: "); + st = Q"\sScanner\s: on"; + st = strcat(st, Q" \sScanning\s: "); if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { scanfor = "team"; @@ -1093,14 +1093,14 @@ string(entity pl) SentryDetailsToString = if (self.sentry_ent.weapon == 3) { rockets = ftos(floor(self.sentry_ent.ammo_rockets)); - ammo = strcat(" Áííï: ", strcat(shells, strcat("/", rockets))); + ammo = strcat(Q" \sAmmo\s: ", strcat(shells, strcat("/", rockets))); } else { - ammo = strcat(" Áííï: ", shells); + ammo = strcat(Q" \sAmmo\s: ", shells); } - st = strcat("Γ“Γ₯Γôòù: ", strcat(hp, ammo)); + st = strcat(Q"\sSentry\s: ", strcat(hp, ammo)); st = strpadr(st, 32); - st = strcat(st, strcat("ÌΓ₯ΓΆΓ₯Γ¬: ", ftos(self.sentry_ent.weapon))); + st = strcat(st, strcat(Q"\slevel\s: ", ftos(self.sentry_ent.weapon))); } return st; @@ -1113,7 +1113,7 @@ string(entity pl) BuildingToString = if (!buildstatus) return "Building..."; - st = "ÂáéìÀéΓΓ§: "; + st = Q"\sBuilding\s: "; st = strcat(st, ftos(pl.building_percentage)); st = strcat(st, "%"); From 2153c9eee8a3c1c0fa85f4f0521841526fa68ea3 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 21 Nov 2018 13:25:04 +1100 Subject: [PATCH 0486/2474] spy encoded strings converted over --- spy.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spy.qc b/spy.qc index 57ce28ed..b0480917 100644 --- a/spy.qc +++ b/spy.qc @@ -541,9 +541,9 @@ void (float issilent) CF_Spy_FeignDeath = { tfgoalitem_RemoveFromPlayer(te, self, 0); if (CTF_Map == 1) { if (te.goal_no == 1) - bprint(PRINT_HIGH, self.netname, " ΓŒΓΓ“Γ” the Γ‚ΓŒΓ•Γ… flag!\n"); + bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sblue\s flag!\n"); else if (te.goal_no == 2) - bprint(PRINT_HIGH, self.netname, " ΓŒΓΓ“Γ” the Γ’Γ…Γ„ flag!\n"); + bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sred\s flag!\n"); } } te = find(te, classname, "item_tfgoal"); @@ -1151,7 +1151,7 @@ void () HallucinationTimer = { stuffcmd(self.owner, "play weapons/tink1.wav\n"); } else if (halltype2 < 0.55) { CenterPrint2(self.owner, "\n\n\n", - "Your team ÃÁŴÔÕÒÅÄ the flag!!"); + Q"Your team \scaptured\s the flag!!"); stuffcmd(self.owner, "play weapons/grenade.wav\n"); } else if (halltype2 < 0.6) { stuffcmd(self.owner, "play weapons/bounce.wav\n"); @@ -1203,7 +1203,7 @@ void () HallucinationTimer = { stuffcmd(self.owner, "play weapons/sniper.wav\n"); } else if (halltype2 < 0.6) { CenterPrint2(self.owner, "\n\n\n", - "Your flag has been Γ”ΓΓ‹Γ…ΓŽ!!"); + Q"Your flag has been \staken\s!!"); stuffcmd(self.owner, "play weapons/flmfire2.wav\n"); } else if (halltype2 < 0.7) { stuffcmd(self.owner, "play weapons/flmgrexp.wav\n"); From f77c15024064f46203920ece285998c7147f8f95 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 21 Nov 2018 13:44:28 +1100 Subject: [PATCH 0487/2474] fix encoded strings for menu.qc --- menu.qc | 178 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/menu.qc b/menu.qc index 69e2ec07..c9eab004 100644 --- a/menu.qc +++ b/menu.qc @@ -181,11 +181,11 @@ void (float update) Menu_Team = { // prepare team strings local string s_select = "Select team:\n\n"; - local string s_blue = "“‘ Blue team "; - local string s_red = "”‘ Red team "; - local string s_yellow = "•‘ Yellow team"; - local string s_green = "–‘ Green team "; - local string s_auto = "—‘ Auto-assign team"; + local string s_blue = Q"\s[1]\s Blue team "; + local string s_red = Q"\s[2]\s Red team "; + local string s_yellow = Q"\s[3]\s Yellow team"; + local string s_green = Q"\s[4]\s Green team "; + local string s_auto = Q"\s[5]\s Auto-assign team"; // put together team strings s_blue = Menu_Team_TeamString(1, s_blue); @@ -308,16 +308,16 @@ void (float update) Menu_Class = { // prepare class strings local string s_select = "Select class:\n\n"; - local string s_scout = "“‘ Scout "; - local string s_sniper = "”‘ Sniper "; - local string s_soldier = "•‘ Soldier "; - local string s_demoman = "–‘ Demoman "; - local string s_medic = "—‘ Medic "; - local string s_hwguy = "ΒΒ˜Β‘ HWGuy "; - local string s_pyro = "™‘ Pyro "; - local string s_spy = "ΒΒšΒ‘ Spy "; - local string s_engineer = "›‘ Engineer"; - local string s_randompc = "’‘ RandomPC"; + local string s_scout = Q"\s[1]\s Scout "; + local string s_sniper = Q"\s[2]\s Sniper "; + local string s_soldier = Q"\s[3]\s Soldier "; + local string s_demoman = Q"\s[4]\s Demoman "; + local string s_medic = Q"\s[5]\s Medic "; + local string s_hwguy = Q"\s[6]\s HWGuy "; + local string s_pyro = Q"\s[7]\s Pyro "; + local string s_spy = Q"\s[8]\s Spy "; + local string s_engineer = Q"\s[9]\s Engineer"; + local string s_randompc = Q"\s[0]\s RandomPC"; // put together class strings - all strings are strzoned s_scout = Menu_Class_ClassString(PC_SCOUT, s_scout); @@ -361,11 +361,11 @@ void (float inp) Menu_Drop_Input = { void () Menu_Drop = { local string s_drop; - local string s_shells = "“‘ Shells \n"; - local string s_nails = "”‘ Nails \n"; - local string s_rockets = "•‘ Rockets \n"; - local string s_cells = "–‘ Cells \n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_shells = Q"\s[1]\s Shells \n"; + local string s_nails = Q"\s[2]\s Nails \n"; + local string s_rockets = Q"\s[3]\s Rockets \n"; + local string s_cells = Q"\s[4]\s Cells \n"; + local string s_nothing = Q"\n\s[5]\s Nothing "; if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -383,11 +383,11 @@ void () Menu_Drop = { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_shells < DROP_SHELLS) && ((self.ammo_cells / AMMO_COST_SHELLS) > (DROP_SHELLS - self.ammo_shells))) - s_shells = "“‘ Shells (make) \n"; + s_shells = Q"\s[1]\s Shells (make) \n"; if ((self.ammo_nails < DROP_NAILS) && ((self.ammo_cells / AMMO_COST_NAILS) > (DROP_NAILS - self.ammo_nails))) - s_nails = "”‘ Nails (make) \n"; + s_nails = Q"\s[2]\s Nails (make) \n"; if ((self.ammo_rockets < DROP_ROCKETS) && ((self.ammo_cells / AMMO_COST_ROCKETS) > (DROP_ROCKETS - self.ammo_rockets))) - s_rockets = "•‘ Rockets (make)\n"; + s_rockets = Q"\s[3]\s Rockets (make)\n"; if (self.ammo_cells < DROP_CELLS) s_cells = "\n"; } @@ -419,28 +419,28 @@ void (float inp) Menu_Scout_Input = { void () Menu_Scout = { local string s_action = "Scanner settings:\n\n"; local string s_scan, s_scane, s_scanf, s_scansound; - local string s_nothing = "\n—‘ Nothing \n\n"; + local string s_nothing = Q"\n\s[5]\s Nothing \n\n"; if (!self.ScannerOn) - s_scan = "“‘ Turn Scanner on \n"; + s_scan = Q"\s[1]\s Turn Scanner on \n"; else - s_scan = "“‘ Turn Scanner off \n"; + s_scan = Q"\s[1]\s Turn Scanner off \n"; if (self.tf_items_flags & NIT_SCANNER_ENEMY) - s_scane = "”‘ Do not scan for enemies \n"; + s_scane = Q"\s[2]\s Do not scan for enemies \n"; else - s_scane = "”‘ Scan for enemies \n"; + s_scane = Q"\s[2]\s Scan for enemies \n"; if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) - s_scanf = "•‘ Do not scan for friendlies\n"; + s_scanf = Q"\s[3]\s Do not scan for friendlies\n"; else - s_scanf = "•‘ Scan for friendlies \n"; + s_scanf = Q"\s[3]\s Scan for friendlies \n"; if (self.tf_items_flags & 4) - s_scansound = "–‘ Turn off scan sound \n"; + s_scansound = Q"\s[4]\s Turn off scan sound \n"; else - s_scansound = "–‘ Turn on scan sound \n"; + s_scansound = Q"\s[4]\s Turn on scan sound \n"; Status_Menu(self, Menu_Scout_Input, s_action, s_scan, s_scane, s_scanf, s_scansound, s_nothing); }; @@ -477,10 +477,10 @@ void (float inp) Menu_Spy_Input = { void (entity pe_player) Menu_Spy = { local string s_action = "Action:\n\n"; - local string s_skin = "“‘ Disguise \n"; - local string s_last = "”‘ Last disguise \n"; + local string s_skin = Q"\s[1]\s Disguise \n"; + local string s_last = Q"\s[2]\s Last disguise \n"; local string s_feign, s_reset; - local string s_nothing = "\n—‘ Nothing "; + local string s_nothing = Q"\n\s[5]\s Nothing "; if (pe_player.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT) || pe_player.is_unabletospy == 1) { return; @@ -488,28 +488,28 @@ void (entity pe_player) Menu_Spy = { if (invis_only) { if (pe_player.is_undercover == 1) - s_skin = "“‘ Become visible \n"; + s_skin = Q"\s[1]\s Become visible \n"; else if (pe_player.is_undercover == 2) - s_skin = "“‘ Stop going invisible \n"; + s_skin = Q"\s[1]\s Stop going invisible \n"; else - s_skin = "“‘ Go invisible \n"; + s_skin = Q"\s[1]\s Go invisible \n"; } else if (pe_player.is_undercover == 2) - s_skin = "“‘ Stop disguising \n"; + s_skin = Q"\s[1]\s Stop disguising \n"; if ((!pe_player.last_skin && !pe_player.last_team) || invis_only) s_last = "\n"; if (pe_player.is_feigning) - s_feign = "•‘ Stop feigning \n"; + s_feign = Q"\s[3]\s Stop feigning \n"; else - s_feign = "•‘ Start feigning (silent)\n"; + s_feign = Q"\s[3]\s Start feigning (silent)\n"; if (pe_player.undercover_team && pe_player.undercover_skin) - s_reset = "–‘ Reset disguise \n"; + s_reset = Q"\s[4]\s Reset disguise \n"; else if (pe_player.undercover_team) - s_reset = "–‘ Reset color \n"; + s_reset = Q"\s[4]\s Reset color \n"; else if (pe_player.undercover_skin) - s_reset = "–‘ Reset skin \n"; + s_reset = Q"\s[4]\s Reset skin \n"; else s_reset = "\n"; @@ -547,16 +547,16 @@ void () Menu_Spy_Skin = { return; local string s_disguise = "Disguise as enemy:\n\n"; - local string s_scout = "“‘ Scout \n"; - local string s_sniper = "”‘ Sniper \n"; - local string s_soldier = "•‘ Soldier \n"; - local string s_demoman = "–‘ Demoman \n"; - local string s_medic = "—‘ Medic \n"; - local string s_hwguy = "ΒΒ˜Β‘ HWGuy \n"; - local string s_pyro = "™‘ Pyro \n"; - local string s_spy = "ΒΒšΒ‘ Spy \n"; - local string s_engineer = "›‘ Engineer \n"; - local string s_nothing = "\n’‘ Nothing \n"; + local string s_scout = Q"\s[1]\s Scout \n"; + local string s_sniper = Q"\s[2]\s Sniper \n"; + local string s_soldier = Q"\s[3]\s Soldier \n"; + local string s_demoman = Q"\s[4]\s Demoman \n"; + local string s_medic = Q"\s[5]\s Medic \n"; + local string s_hwguy = Q"\s[6]\s HWGuy \n"; + local string s_pyro = Q"\s[7]\s Pyro \n"; + local string s_spy = Q"\s[8]\s Spy \n"; + local string s_engineer = Q"\s[9]\s Engineer \n"; + local string s_nothing = Q"\n\s[0]\s Nothing \n"; Status_Menu(self, Menu_Spy_Skin_Input, s_disguise, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_nothing); }; @@ -579,11 +579,11 @@ void (float inp) Menu_Spy_Color_Input = { void () Menu_Spy_Color = { local float color = stof(infokey(self, "bottomcolor")); local string s_disguise = "Disguise as:\n\n"; - local string s_blue = "“‘ Blue team \n"; - local string s_red = "”‘ Red team \n"; - local string s_yellow = "•‘ Yellow team\n"; - local string s_green = "–‘ Green team \n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_blue = Q"\s[1]\s Blue team \n"; + local string s_red = Q"\s[2]\s Red team \n"; + local string s_yellow = Q"\s[3]\s Yellow team\n"; + local string s_green = Q"\s[4]\s Green team \n"; + local string s_nothing = Q"\n\s[5]\s Nothing "; if (number_of_teams == 0) { sprint(self, PRINT_HIGH, "No color changing allowed in deathmatch\n"); @@ -624,11 +624,11 @@ void (float inp) Menu_Demoman_Input = { void () Menu_Demoman = { local string s_detpack = "Set detpack for:\n\n"; - local string s_5 = "“‘ 5 seconds \n"; - local string s_20 = "”‘ 20 seconds \n"; - local string s_50 = "•‘ 50 seconds \n"; - local string s_255 = "–‘ 255 seconds\n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_5 = Q"\s[1]\s 5 seconds \n"; + local string s_20 = Q"\s[2]\s 20 seconds \n"; + local string s_50 = Q"\s[3]\s 50 seconds \n"; + local string s_255 = Q"\s[4]\s 255 seconds\n"; + local string s_nothing = Q"\n\s[5]\s Nothing "; Status_Menu(self, Menu_Demoman_Input, s_detpack, s_5, s_20, s_50, s_255, s_nothing); } @@ -642,7 +642,7 @@ void (float inp) Menu_Demoman_Cancel_Input = { void () Menu_Demoman_Cancel = { local string s_detpack = "Setting detpack...\n\n"; - local string s_cancel = "“‘ Cancel!\n\n\n\n\n"; + local string s_cancel = Q"\s[1]\s Cancel!\n\n\n\n\n"; Status_Menu(self, Menu_Demoman_Cancel_Input, s_detpack, s_cancel); } @@ -715,35 +715,35 @@ void (entity player) Menu_Engineer = { local string s_disp = "\n"; local string s_dsentry = "\n"; local string s_ddisp = "\n"; - local string s_nothing = "\n—‘ Nothing "; + local string s_nothing = Q"\n\s[5]\s Nothing "; if (player.has_sentry) { s_sentry = "\n"; - s_dsentry = "•‘ Destroy sentry gun \n"; + s_dsentry = Q"\s[3]\s Destroy sentry gun \n"; te = findradius(player.origin, 100); while (te) { if (te.classname == "building_sentrygun") { if (te.real_owner == player) - s_dsentry = "•‘ Dismantle sentry gun\n"; + s_dsentry = Q"\s[3]\s Dismantle sentry gun\n"; } te = te.chain; } } else if (player.ammo_cells >= 130) { - s_sentry = "“‘ Build sentry gun \n"; + s_sentry = Q"\s[1]\s Build sentry gun \n"; } if (player.has_dispenser) { - s_ddisp = "–‘ Destroy dispenser \n"; + s_ddisp = Q"\s[4]\s Destroy dispenser \n"; te = findradius(player.origin, 100); while (te) { if (te.classname == "building_dispenser") { if (te.real_owner == player) - s_ddisp = "–‘ Dismantle dispenser \n"; + s_ddisp = Q"\s[4]\s Dismantle dispenser \n"; } te = te.chain; } } else if (player.ammo_cells >= 100) { - s_disp = "”‘ Build dispenser \n"; + s_disp = Q"\s[2]\s Build dispenser \n"; } if ((player.has_dispenser || player.has_sentry) && !player.has_menutimer) { @@ -786,23 +786,23 @@ void (float inp) Menu_EngineerFix_Dispenser_Input = { void () Menu_EngineerFix_Dispenser = { local string s_action = "Dispenser maintenance:\n\n"; local string s_ammo, s_armor, s_repair; - local string s_nothing = "\n—‘ Nothing \n\n"; + local string s_nothing = Q"\n\s[5]\s Nothing \n\n"; if ((self.ammo_shells > 0 && self.building.ammo_shells < 400) || (self.ammo_nails > 0 && self.building.ammo_nails < 600) || (self.ammo_rockets > 0 && self.building.ammo_rockets < 300) || (self.ammo_cells > 0 && self.building.ammo_cells < 400)) - s_ammo = "“‘ Insert ammo \n"; + s_ammo = Q"\s[1]\s Insert ammo \n"; else s_ammo = "\n"; if (self.armorvalue > 0 && self.building.armorvalue < 500) - s_armor = "”‘ Insert armor\n"; + s_armor = Q"\s[2]\s Insert armor\n"; else s_armor = "\n"; if (old_spanner && self.building.health < self.building.max_health) - s_repair = "•‘ Repair \n"; + s_repair = Q"\s[3]\s Repair \n"; else s_repair = "\n"; @@ -827,10 +827,10 @@ void (float inp) Menu_EngineerFix_SentryGun_Rotate_Input = { void () Menu_EngineerFix_SentryGun_Rotate = { local string action = "Rotate sentry gun:\n\n"; - local string rotl = "“‘ anticlockwise\n"; - local string rot180 = "”‘ 180 degrees \n"; - local string rotr = "•‘ clockwise \n"; - local string nothing = "\n—‘ Nothing \n"; + local string rotl = Q"\s[1]\s anticlockwise\n"; + local string rot180 = Q"\s[2]\s 180 degrees \n"; + local string rotr = Q"\s[3]\s clockwise \n"; + local string nothing = Q"\n\s[5]\s Nothing \n"; if (!self.building.real_owner.has_sentry || self.building.real_owner != self || self.classname != "player" || self.building == world) @@ -865,26 +865,26 @@ void () Menu_EngineerFix_SentryGun = { local string action = "Sentry gun maintenance:\n\n"; local string putammo, upgrade, repair, rotate; - local string nothing = "\n—‘ Nothing "; + local string nothing = Q"\n\s[5]\s Nothing "; if ((self.ammo_shells > 0 && self.building.ammo_shells < self.building.maxammo_shells) || (self.ammo_rockets > 0 && self.building.weapon == 3 && self.building.ammo_rockets < self.building.maxammo_rockets)) - putammo = "“‘ Insert ammo\n"; + putammo = Q"\s[1]\s Insert ammo\n"; else putammo = "\n"; if (self.building.weapon < 3 && self.ammo_cells >= 130) - upgrade = "”‘ Upgrade \n"; + upgrade = Q"\s[2]\s Upgrade \n"; else upgrade = "\n"; if (self.building.health < self.building.max_health) - repair = "•‘ Repair \n"; + repair = Q"\s[3]\s Repair \n"; else repair = "\n"; if (self.building.real_owner == self) - rotate = "–‘ Rotate \n"; + rotate = Q"\s[4]\s Rotate \n"; else rotate = "\n"; @@ -965,18 +965,18 @@ void (float inp) Menu_Dispenser_Input = { void () Menu_Dispenser = { local string s_action = "Use dispenser:\n\n"; local string s_ammo, s_armor; - local string s_nothing = "\n—‘ Nothing \n\n"; + local string s_nothing = Q"\n\s[5]\s Nothing \n\n"; if ((self.building.ammo_shells > 0 && self.ammo_shells < self.maxammo_shells) || (self.building.ammo_nails > 0 && self.ammo_nails < self.maxammo_nails) || (self.building.ammo_rockets > 0 && self.ammo_rockets < self.maxammo_rockets) || (self.building.ammo_cells > 0 && self.ammo_cells < self.maxammo_cells)) - s_ammo = "“‘ Withdraw some ammo \n"; + s_ammo = Q"\s[1]\s Withdraw some ammo \n"; else s_ammo = "\n"; if (self.building.armorvalue > 0 && self.armorvalue < self.maxarmor) - s_armor = "”‘ Withdraw some armor\n"; + s_armor = Q"\s[2]\s Withdraw some armor\n"; else s_armor = "\n"; @@ -992,7 +992,7 @@ void (float inp) Menu_Engineer_Cancel_Input = { void () Menu_Engineer_Cancel = { local string s_build = "Building...\n\n"; - local string s_cancel = "“‘ Cancel!\n\n\n\n\n"; + local string s_cancel = Q"\s[1]\s Cancel!\n\n\n\n\n"; Status_Menu(self, Menu_Engineer_Cancel_Input, s_build, s_cancel); } From 66f0ede7ee3375285e227142cb97b2ac7a4fd6fc Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 21 Nov 2018 13:58:43 +1100 Subject: [PATCH 0488/2474] vote.qc fix string encodings --- vote.qc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vote.qc b/vote.qc index acff5619..94efb7cf 100644 --- a/vote.qc +++ b/vote.qc @@ -542,7 +542,7 @@ void (entity pe_player) Vote_Menu = { if (vote1_map != string_null) { strunzone(s_tmp1); - s_tmp1 = strcat("“‘ ", vote1_map); + s_tmp1 = strcat(Q"\s[1]\s ", vote1_map); if (vote1_cnt) s_tmp1 = strzone(strcat(s_tmp1, strcat(" (", strcat(ftos(vote1_cnt), " votes)")))); else @@ -552,7 +552,7 @@ void (entity pe_player) Vote_Menu = { } if (vote2_map != string_null) { strunzone(s_tmp2); - s_tmp2 = strcat("”‘ ", vote2_map); + s_tmp2 = strcat(Q"\s[2]\s ", vote2_map); if (vote2_cnt) s_tmp2 = strzone(strcat(s_tmp2, strcat(" (", strcat(ftos(vote2_cnt), " votes)")))); else @@ -563,7 +563,7 @@ void (entity pe_player) Vote_Menu = { if (vote3_map != string_null) { strunzone(s_tmp3); if (!vote_decider || vote3_cnt) - s_tmp3 = strcat("•‘ ", vote3_map); + s_tmp3 = strcat(Q"\s[3]\s ", vote3_map); if (vote3_cnt) s_tmp3 = strzone(strcat(s_tmp3, strcat(" (", strcat(ftos(vote3_cnt), " votes)")))); else @@ -574,7 +574,7 @@ void (entity pe_player) Vote_Menu = { if (vote4_map != string_null) { strunzone(s_tmp4); if (!vote_decider || vote4_cnt) - s_tmp4 = strcat("–‘ ", vote4_map); + s_tmp4 = strcat(Q"\s[4]\s ", vote4_map); if (vote4_cnt) s_tmp4 = strzone(strcat(s_tmp4, strcat(" (", strcat(ftos(vote4_cnt), " votes)")))); else @@ -585,7 +585,7 @@ void (entity pe_player) Vote_Menu = { if (vote5_map != string_null) { strunzone(s_tmp5); if (!vote_decider || vote5_cnt) - s_tmp5 = strcat("—‘ ", vote5_map); + s_tmp5 = strcat(Q"\s[5]\s ", vote5_map); if (vote5_cnt) s_tmp5 = strzone(strcat(s_tmp5, strcat(" (", strcat(ftos(vote5_cnt), " votes)")))); else From 6398248bc22cb3f1acd7db486978596358823341 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 21 Nov 2018 13:58:56 +1100 Subject: [PATCH 0489/2474] help.qc fix string encoding --- help.qc | 158 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/help.qc b/help.qc index f34a106e..43b4e66e 100644 --- a/help.qc +++ b/help.qc @@ -42,122 +42,122 @@ void () Help_Show = { void () Help_ShowScout = { sprint(self, PRINT_HIGH, "\nDefault bindings for Scout:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Nailgun\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "Γ₯ - Toggle Scanner on/off\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Throw Caltrop Canisters\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Concussion Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Axe\n"); + sprint(self, PRINT_HIGH, Q"\se\s - Toggle Scanner on/off\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Throw Caltrop Canisters\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Concussion Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Scout:\n"); - sprint(self, PRINT_HIGH, "ÑáôïóãÑà - Toggle Scanner on/off\n"); - sprint(self, PRINT_HIGH, "óãÑΓΓ³Γ―Γ΅ΓΓ€ - Toggle Scanner sound on/off\n"); - sprint(self, PRINT_HIGH, "óãÑΓΓ₯ - Toggle scanning of enemies on/off\n"); - sprint(self, PRINT_HIGH, "óãÑΓΓ¦ - Toggle scanning of friendlies on/off\n"); + sprint(self, PRINT_HIGH, Q"\sautoscan\s - Toggle Scanner on/off\n"); + sprint(self, PRINT_HIGH, Q"\sscansound\s - Toggle Scanner sound on/off\n"); + sprint(self, PRINT_HIGH, Q"\sscane\s - Toggle scanning of enemies on/off\n"); + sprint(self, PRINT_HIGH, Q"\sscanf\s - Toggle scanning of friendlies on/off\n"); }; void () Help_ShowSniper = { sprint(self, PRINT_HIGH, "\nDefault bindings for Sniper:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Sniper Rifle\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Sniper Rifle on Full Auto\n"); - sprint(self, PRINT_HIGH, "Δ‘ - Equip Nailgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "Γ₯ - Toggle zoom mode\n"); - sprint(self, PRINT_HIGH, "Γ­αΉ«Γ¨Γ₯Γ₯ìáš - Zoom in (while in zoom mode)\n"); - sprint(self, PRINT_HIGH, "Γ­αΉ«Γ¨Γ₯Γ₯ìÀïṫà - Zoom out (while in zoom mode)\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Throw Flare\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Sniper Rifle\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Sniper Rifle on Full Auto\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Axe\n"); + sprint(self, PRINT_HIGH, Q"\se\s - Toggle zoom mode\n"); + sprint(self, PRINT_HIGH, Q"\smwheelup\s - Zoom in (while in zoom mode)\n"); + sprint(self, PRINT_HIGH, Q"\smwheeldown\s - Zoom out (while in zoom mode)\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Throw Flare\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Sniper:\n"); - sprint(self, PRINT_HIGH, "úïïíôïççìΓ₯ - Toggle zoom mode\n"); - sprint(self, PRINT_HIGH, "ΓΊΓ―Γ―Γ­Γ©ΓΒ  - Zoom in (for adjusting zoom while in zoom mode)\n"); - sprint(self, PRINT_HIGH, "úïïíïáô - Zoom out (for adjusting zoom while in zoom mode)\n"); + sprint(self, PRINT_HIGH, Q"\szoomtoggle\s - Toggle zoom mode\n"); + sprint(self, PRINT_HIGH, Q"\szoomin\s - Zoom in (for adjusting zoom while in zoom mode)\n"); + sprint(self, PRINT_HIGH, Q"\szoomout\s - Zoom out (for adjusting zoom while in zoom mode)\n"); sprint(self, PRINT_HIGH, "\nSettings for Sniper:\n"); - sprint(self, PRINT_HIGH, "ΓΊΓ¦ ỳæïâẅ - The default zoom fov which zoomtoggle zooms to (default 30)\n"); - sprint(self, PRINT_HIGH, "ΓΊΓ³ ỳæïâẅ - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); + sprint(self, PRINT_HIGH, Q"\szf α»³fovαΊ…\s - The default zoom fov which zoomtoggle zooms to (default 30)\n"); + sprint(self, PRINT_HIGH, Q"\szS α»³fovαΊ…\s - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); sprint(self, PRINT_HIGH, "Usage: setinfo \n"); }; void () Help_ShowSoldier = { sprint(self, PRINT_HIGH, "\nDefault bindings for Soldier:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Rocket Launcher\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Nail Grenade\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Rocket Launcher\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Axe\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Nail Grenade\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); }; void () Help_ShowDemoman = { sprint(self, PRINT_HIGH, "\nDefault bindings for Demolitions Man:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Grenade Launcher\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Pipebomb Launcher\n"); - sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "ṁ - Detpack menu\n"); - sprint(self, PRINT_HIGH, "Γ₯ - Detonate pipebombs\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Mirv Grenade\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Grenade Launcher\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Pipebomb Launcher\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Axe\n"); + sprint(self, PRINT_HIGH, Q"\s5\s - Detpack menu\n"); + sprint(self, PRINT_HIGH, Q"\se\s - Detonate pipebombs\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Mirv Grenade\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Demolitions Man:\n"); - sprint(self, PRINT_HIGH, "Γ€Γ₯Γ΄Ε΅Γ©Ε΅Γ₯ - Detonate pipebombs\n"); - sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôṁ - Place detpack with 5 second timer\n"); - sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôĠḞ - Place detpack with 20 second timer\n"); - sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôṁḞ - Place detpack with 50 second timer\n"); - sprint(self, PRINT_HIGH, "αΈ‹Γ€Γ₯ôĠṁṁ - Place detpack with 255 second timer\n"); + sprint(self, PRINT_HIGH, Q"\sdetpipe\s - Detonate pipebombs\n"); + sprint(self, PRINT_HIGH, Q"\s+det5\s - Place detpack with 5 second timer\n"); + sprint(self, PRINT_HIGH, Q"\s+det20\s - Place detpack with 20 second timer\n"); + sprint(self, PRINT_HIGH, Q"\s+det50\s - Place detpack with 50 second timer\n"); + sprint(self, PRINT_HIGH, Q"\s+det255\s - Place detpack with 255 second timer\n"); }; void () Help_ShowMedic = { sprint(self, PRINT_HIGH, "\nDefault bindings for Combat Medic:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Super Nailgun\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Medikit\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Concussion Grenade\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Super Nailgun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Medikit\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Concussion Grenade\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); }; void () Help_ShowHWGuy = { sprint(self, PRINT_HIGH, "\nDefault bindings for Heavy Weapons Guy:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Assault Cannon\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Mirv Grenade\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Assault Cannon\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Axe\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Mirv Grenade\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); }; void () Help_ShowPyro = { sprint(self, PRINT_HIGH, "\nDefault bindings for Pyro:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Flamethrower\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Incendiary Cannon\n"); - sprint(self, PRINT_HIGH, "Δ‘ - Equip Shotgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Axe\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Napalm Grenade\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Flamethrower\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Incendiary Cannon\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Axe\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Napalm Grenade\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); }; void () Help_ShowSpy = { sprint(self, PRINT_HIGH, "\nDefault bindings for Spy:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Tranquiliser Gun\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "Δ‘ - Equip Nailgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Knife\n"); - sprint(self, PRINT_HIGH, "ṁ - Disguise menu\n"); - sprint(self, PRINT_HIGH, "Γ₯ - Silently feign death\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw Gas Grenade\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Tranquiliser Gun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Nailgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Knife\n"); + sprint(self, PRINT_HIGH, Q"\s5\s - Disguise menu\n"); + sprint(self, PRINT_HIGH, Q"\se\s - Silently feign death\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Gas Grenade\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Spy:\n"); - sprint(self, PRINT_HIGH, "Γ¦Γ₯éçà - Feign death\n"); - sprint(self, PRINT_HIGH, "Γ³Γ¦Γ₯éçà - Silently feign death\n"); + sprint(self, PRINT_HIGH, Q"\sfeign\s - Feign death\n"); + sprint(self, PRINT_HIGH, Q"\ssfeign\s - Silently feign death\n"); }; void () Help_ShowEngineer = { sprint(self, PRINT_HIGH, "\nDefault bindings for Engineer:\n"); - sprint(self, PRINT_HIGH, "ḟ - Equip Railgun\n"); - sprint(self, PRINT_HIGH, "Δ  - Equip Super Shotgun\n"); - sprint(self, PRINT_HIGH, "αΉ€ - Equip Spanner\n"); - sprint(self, PRINT_HIGH, "ṁ - Build/destroy menu\n"); - sprint(self, PRINT_HIGH, "Γ¦ - Prime/throw EMP Grenade\n"); - sprint(self, PRINT_HIGH, "íïáóΓ₯Δ  - Prime/throw Hand Grenade\n"); + sprint(self, PRINT_HIGH, Q"\s1\s - Equip Railgun\n"); + sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Equip Spanner\n"); + sprint(self, PRINT_HIGH, Q"\s4\s - Build/destroy menu\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw EMP Grenade\n"); + sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Engineer:\n"); - sprint(self, PRINT_HIGH, "Γ€Γ₯ôÀéóšΓ₯ΓΓ³Γ₯Γ² - Detonate Dispenser\n"); - sprint(self, PRINT_HIGH, "Γ€Γ₯ôóΓ₯Γôòù - Detonate Sentry Gun\n"); + sprint(self, PRINT_HIGH, Q"\sdetdispenser\s - Detonate Dispenser\n"); + sprint(self, PRINT_HIGH, Q"\sdetsentry\s - Detonate Sentry Gun\n"); }; From 4adc93a7af0750f4440289b2bfc532be41f13125 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 21 Nov 2018 15:30:57 +1100 Subject: [PATCH 0490/2474] fix sniper encoded strings --- help.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/help.qc b/help.qc index 43b4e66e..c6b27f6b 100644 --- a/help.qc +++ b/help.qc @@ -71,8 +71,8 @@ void () Help_ShowSniper = { sprint(self, PRINT_HIGH, Q"\szoomin\s - Zoom in (for adjusting zoom while in zoom mode)\n"); sprint(self, PRINT_HIGH, Q"\szoomout\s - Zoom out (for adjusting zoom while in zoom mode)\n"); sprint(self, PRINT_HIGH, "\nSettings for Sniper:\n"); - sprint(self, PRINT_HIGH, Q"\szf α»³fovαΊ…\s - The default zoom fov which zoomtoggle zooms to (default 30)\n"); - sprint(self, PRINT_HIGH, Q"\szS α»³fovαΊ…\s - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); + sprint(self, PRINT_HIGH, Q"\szf \"fov\"\s - The default zoom fov which zoomtoggle zooms to (default 30)\n"); + sprint(self, PRINT_HIGH, Q"\szs \"fov\"\s - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); sprint(self, PRINT_HIGH, "Usage: setinfo \n"); }; From f465cdca0dd022c8bb8f6d63405d1ee642a43a0d Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 22 Nov 2018 14:06:07 +1100 Subject: [PATCH 0491/2474] organise q3 ent support in to own file, finish backpack support --- progs.src | 1 + q3.qc | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++ qw.qc | 8 ----- tfortmap.qc | 54 -------------------------------- 4 files changed, 89 insertions(+), 62 deletions(-) create mode 100644 q3.qc diff --git a/progs.src b/progs.src index 9ec1798a..6eb6aa41 100644 --- a/progs.src +++ b/progs.src @@ -2,6 +2,7 @@ qwprogs.dat defs.qc fteextensions.qc qw.qc +q3.qc debug.qc status.qc menu.qc diff --git a/q3.qc b/q3.qc new file mode 100644 index 00000000..3fef5b0b --- /dev/null +++ b/q3.qc @@ -0,0 +1,88 @@ +// q3 defs - enable q3f map ents +.string allowteams; +.string give; +.string active_all_sound; +.string model; + +// backpacks etc +void () func_goalinfo = { + self.classname = "info_tfgoal"; + + self.mdl = self.model; + self.noise = self.active_all_sound; + self.armortype = 0.8; + self.goal_effects = 1; + + // probably have to tokenise this? + if (self.allowteams == "blue") { + self.team_no = 1; + } + if (self.allowteams == "red") { + self.team_no = 2; + } + + string give; + give = self.give; + + float count = tokenizebyseparator(self.give, ","); + + for (i = 0; i <= count; i++) + { + string s, gtype, gop, gamt, val; + float loc, slen; + + s = argv[i]; + slen = strlen(s); + + gtype = substring(s, 0, loc); + gop = substring(s, loc, loc + 1); + gamt = substring(s, loc + 1, slen); + if (gop == "-") { + val = "-" + ftos(gamt); + } else { + val = ftos(gamt); + } + dprint(gtype); + dprint(gop); + dprint(gamt); + + switch (gtype) + { + case "health": + self.health = val; + break; + case "armor": + self.armorvalue = val; + break; + case "ammo_shells": + self.ammo_shells = val; + break; + case "ammo_bullets": + self.ammo_nails = val; + break; + case "ammo_rockets": + self.ammo_rockets = val; + break; + case "ammo_cells": + self.ammo_cells = val; + break; + case "gren1": + self.no_grenades_1 = val; + break; + case "gren2": + self.no_grenades_2 = val; + break; + default: + dprint("gtype not found, discarding\n"); + break; + } + } + + info_tfgoal(); +} + +/* +void () target_position = { + self.classname = "info_notnull"; + info_notnull(); +};*/ \ No newline at end of file diff --git a/qw.qc b/qw.qc index 506c13da..aee2c20f 100644 --- a/qw.qc +++ b/qw.qc @@ -504,18 +504,10 @@ float deathmsg; // Global, which is set before every T_Damage, t float intermission_running; float intermission_exittime; -// q3 defs - enable q3f map ents -.string allowteams; -.string give; -.string active_all_sound; -.string model; - // add clientkill ent defs .float clientkillforce; .float clientkillfree; - - //============================================================================ void (float psize, entity p) KickPlayer = { diff --git a/tfortmap.qc b/tfortmap.qc index d037dac4..17b354db 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -420,60 +420,6 @@ void () info_tfgoal = { TF_StartGoal(); }; -// q3 support -/* -void () func_goalinfo = { - dprint("processing func_goalinfo"); - self.classname = "info_tfgoal"; - if (self.allowteams == "blue") { - self.team_no = 1; - } - if (self.allowteams == "red") { - self.team_no = 2; - } - self.mdl = self.model; - self.noise = self.active_all_sound; - self.armortype = 0.8; - - dprint("past setting of fields"); - float startpos, endpos; - startpos = 0; - string searchterm = self.give; - endpos = strstrofs(searchterm, ",", startpos); - dprint(searchterm); - do { - string splitterm = substring(searchterm, startpos, endpos); - dprint(splitterm); - // split it up "health=+100" - float eqindex, opindex, len, amt; - string givetype, posneg, samt; - eqindex = strstrofs(splitterm, "=", 0); - opindex = eqindex + 1; - givetype = substring(splitterm, 0, eqindex); - posneg = substring(splitterm, eqindex, opindex); - len = endpos - 1; - samt = substring(splitterm, opindex, len); - amt = stof(samt); - - // now process with case statement - dprint(splitterm); - dprint(givetype); - dprint(posneg); - dprint(samt); - - // next loop, set startpos to endpos through index for while condition - startpos = strstrofs(searchterm, ",", startpos); - endpos = strstrofs(searchterm, ",", startpos); - if (endpos == -1) { - // set endpos to end of string - endpos = strlen(searchterm); - endpos = endpos - startpos; - } - } while (startpos >= -1); - - info_tfgoal(); -} -*/ void () i_t_g = { self.classname = "info_tfgoal"; info_tfgoal(); From 5e28f0012cbaecf3ff3cdd5aaeb3e285212f39ca Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 22 Nov 2018 16:13:45 +1100 Subject: [PATCH 0492/2474] remove q3 ent --- misc.qc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/misc.qc b/misc.qc index 179a5c33..1d370301 100644 --- a/misc.qc +++ b/misc.qc @@ -6,12 +6,6 @@ void () info_null = { void () info_notnull = { }; -// q3 -/*void () target_position = { - self.classname = "info_notnull"; - info_notnull(); -};*/ - void () light_use = { if (self.spawnflags & 1) { lightstyle(self.style, "m"); From fab286e808f51c29a9c4b8aac11811d66c53104f Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 22 Nov 2018 16:14:15 +1100 Subject: [PATCH 0493/2474] q3f flag support --- q3.qc | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/q3.qc b/q3.qc index 3fef5b0b..2ed8253d 100644 --- a/q3.qc +++ b/q3.qc @@ -12,6 +12,7 @@ void () func_goalinfo = { self.noise = self.active_all_sound; self.armortype = 0.8; self.goal_effects = 1; + self.goal_activation = 1; // touched by player // probably have to tokenise this? if (self.allowteams == "blue") { @@ -74,13 +75,51 @@ void () func_goalinfo = { break; default: dprint("gtype not found, discarding\n"); - break; } } info_tfgoal(); } +// flags +void () func_goalitem = { + self.classname = "item_tfgoal"; + self.mdl = self.model; + self.delay = self.wait; // is delay used anymore? + self.pausetime = self.wait; + self.netname = self.groupname; + self.g_a = "4789"; + switch(self.allowteams) + { + case "blue": + self.team_no = 1; + self.owned_by = 2; + self.skin = 1; + self.goal_no = 2; + self.items = "262144"; // used by hud? + break; + case "red": + self.team_no = 2; + self.owned_by = 1; + self.skin = 2; + self.goal_no = 1; + self.items = "131072"; // used by hud? + break; + default: + } + self.team_broadcast = strcat(self.carried_all_message, "\n"); + self.non_team_broadcast = strcat(self.carried_all_message, "\n"); + self.message = strcat(self.carried_message, "\n"); + self.noise = strcat(self.carried_all_sound; + self.noise3 = strcat(self.inactive_all_message, "\n"); + self.noise4 = strcat(self.inactive_all_message, "\n"); + self.n_b = strcat(self.carried_all_message, "\n"); + self.d_n_n = strcat(self.active_all_message, "\n"); + + item_tfgoal(); +} + + /* void () target_position = { self.classname = "info_notnull"; From 94bed39d7c8a9bcd8cc6727242e33e03bc600cb5 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 22 Nov 2018 16:51:40 +1100 Subject: [PATCH 0494/2474] add support for cap points --- q3.qc | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/q3.qc b/q3.qc index 2ed8253d..3f9dfceb 100644 --- a/q3.qc +++ b/q3.qc @@ -4,24 +4,42 @@ .string active_all_sound; .string model; -// backpacks etc +// backpacks, cap points etc void () func_goalinfo = { self.classname = "info_tfgoal"; - + self.frags = self.teamscore; + self.count = self.teamscore; self.mdl = self.model; self.noise = self.active_all_sound; self.armortype = 0.8; self.goal_effects = 1; self.goal_activation = 1; // touched by player + self.n_b = self.active_all_message; // probably have to tokenise this? - if (self.allowteams == "blue") { + if (self.allowteams == "blue") + { self.team_no = 1; } - if (self.allowteams == "red") { + if (self.allowteams == "red") + { self.team_no = 2; } + // note: need to see if this is groupname or builtin name in q3f + if (self.holding == "blueflag") + { + self.items_allowed = "1"; + self.owned_by "1"; + self.axhitme = "1"; + } + if (self.holding == "redflag") + { + self.items_allowed = "2"; + self.owned_by "2"; + self.axhitme = "2"; + } + string give; give = self.give; From 611df885d02c9f31a1f0b426cd61891a78ece012 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 22 Nov 2018 17:05:29 +1100 Subject: [PATCH 0495/2474] note .map usage --- q3f_openfire2b working copy.map | 12 +- stag3.map | 5523 +------------------------------ 2 files changed, 89 insertions(+), 5446 deletions(-) diff --git a/q3f_openfire2b working copy.map b/q3f_openfire2b working copy.map index d63c1ae6..f19e2082 100644 --- a/q3f_openfire2b working copy.map +++ b/q3f_openfire2b working copy.map @@ -12,13 +12,15 @@ } +/* // entity 3 { "classname" "target_position" "targetname" "t3" "origin" "1072 1152 -88" } - +*/ +/* // entity 65 { "angle" "180" @@ -31,15 +33,16 @@ "model" "models/objects/backpack/backpack.md3" "wait" "2" } - +*/ +/* // entity 93 { +"classname" "func_goalitem" "inactivetarget" "redflaghud=~inactive" "activetarget" "redflaghud=~active" "carriedtarget" "redflaghud=~carried" "sparkle" "1.000000 0.392157 0.392157" "angle" "90" -"classname" "func_goalitem" "carried_sound" "sound/teamplay/flagtk_red.wav" "carried_all_sound" "sound/teamplay/flagtk_red.wav" "carried_message" "~You got the ^1red^* flag! Run for it!" @@ -58,6 +61,8 @@ "_color" "1.000000 0.392157 0.392157" "light" "50" } +*/ +/* // entity 94 { "classname" "func_goalinfo" @@ -72,6 +77,7 @@ "angle" "270" "active_all_sound" "sound/teamplay/flagcap_red.wav" } +*/ // entity 95 { "origin" "-352 512 128" diff --git a/stag3.map b/stag3.map index abcb7c23..0f3e06d3 100644 --- a/stag3.map +++ b/stag3.map @@ -6,5038 +6,99 @@ "classname" "worldspawn" "wad" "/home/danni/Games/QuakeDev/wads/stag.wad;../wads/oppose2.wad" "_sunlight" "0" -// brush 0 -{ -( -2608 -65535 65535 ) ( -2608 65535 65535 ) ( -2608 65535 -65535 ) city4_5 -16 0 90 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 -16 0 180 1 1 -} -// brush 1 -{ -( -224 -65535 65535 ) ( -224 65535 65535 ) ( -224 65535 -65535 ) wiz1_4 -16 -2 90 1 1 -( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) wiz1_4 -16 -2 90 1 1 -( 65247 1680 65535 ) ( -65823 1680 65535 ) ( -65823 1680 -65535 ) wiz1_4 -48 -2 180 1 1 -( -65823 1648 65535 ) ( 65247 1648 65535 ) ( -65823 1648 -65535 ) wiz1_4 -48 -2 180 1 1 -( 65247 65535 -2864 ) ( 65247 -65535 -2864 ) ( -65823 -65535 -2864 ) wiz1_4 -47 -2 180 1 1 -( 65247 -65535 -4000 ) ( 65247 65535 -4000 ) ( -65823 -65535 -4000 ) wiz1_4 -48 -2 180 1 1 -} -// brush 2 -{ -( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) rock5_2 -80 0 90 1 1 -( -2832 65535 65535 ) ( -2832 -65535 65535 ) ( -2832 65535 -65535 ) rock5_2 -80 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 -( 65535 65535 -3472 ) ( 65535 -65535 -3472 ) ( -65535 -65535 -3472 ) rock5_2 -80 0 180 1 1 -( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -80 0 180 1 1 -} -// brush 3 -{ -( -304 -63567 65535 ) ( -304 67503 65535 ) ( -304 67503 -65535 ) metal1_4 -0 -48 180 1 1 -( -880 67503 65535 ) ( -880 -63567 65535 ) ( -880 67503 -65535 ) metal1_4 -0 -48 180 1 1 -( 64655 1664 65535 ) ( -66415 1664 65535 ) ( -66415 1664 -65535 ) metal1_4 -0 -48 -0 1 1 -( -66415 464 65535 ) ( 64655 464 65535 ) ( -66415 464 -65535 ) metal1_4 -0 -48 -0 1 1 -( 64655 67503 -3408 ) ( 64655 -63567 -3408 ) ( -66415 -63567 -3408 ) city4_8 32 -16 -0 1 1 -( 64655 -63567 -3952 ) ( 64655 67503 -3952 ) ( -66415 -63567 -3952 ) metal1_4 -0 -0 -0 1 1 -} -// brush 4 -{ -( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) sfloor4_1 -16 0 180 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) sfloor4_1 -16 -0 180 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -16 -0 -0 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -16 0 0 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -16 -48 0 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -16 0 0 1 1 -} -// brush 5 -{ -( -2944 -65535 65535 ) ( -2944 65535 65535 ) ( -2944 65535 -65535 ) sfloor4_1 -16 0 90 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) sfloor4_1 -16 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) sfloor4_1 -16 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -16 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) sfloor4_1 -16 0 180 1 1 -} -// brush 6 -{ -( -2608 -65535 65535 ) ( -2608 65535 65535 ) ( -2608 65535 -65535 ) city4_5 -16 0 90 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -16 0 180 1 1 -} -// brush 7 -{ -( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) rock5_2 -80 0 90 1 1 -( -2832 65535 65535 ) ( -2832 -65535 65535 ) ( -2832 65535 -65535 ) rock5_2 -80 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) rock5_2 -80 0 180 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) rock5_2 -80 0 180 1 1 -} -// brush 8 -{ -( -2832 -65535 65535 ) ( -2832 65535 65535 ) ( -2832 65535 -65535 ) rock5_2 -80 0 90 1 1 -( -2944 65535 65535 ) ( -2944 -65535 65535 ) ( -2944 65535 -65535 ) rock5_2 -80 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) rock5_2 -80 0 180 1 1 -( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -80 0 180 1 1 -} -// brush 9 -{ -( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) city4_5 -16 0 90 1 1 -( -2608 65535 65535 ) ( -2608 -65535 65535 ) ( -2608 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -16 0 180 1 1 -} -// brush 10 -{ -( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) mmetal1_8 -15 0 0 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) mmetal1_8 -15 0 0 1 1 -( 65535 1312 65535 ) ( -65535 1312 65535 ) ( -65535 1312 -65535 ) mmetal1_8 -15 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) mmetal1_8 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) mmetal1_8 -15 0 180 1 1 -} -// brush 11 -{ -( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal4_4 -16 0 90 1 1 -( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal4_4 -16 0 90 1 1 -( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal4_4 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 -16 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) metal4_4 -16 0 180 1 1 -} -// brush 12 -{ -( -368 -65535 65535 ) ( -368 65535 65535 ) ( -368 65535 -65535 ) city4_8 -16 0 180 1 1 -( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) city4_8 -16 0 180 1 1 -( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) city4_8 -16 0 0 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_8 -16 0 0 1 1 -} -// brush 13 -{ -( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) wizmet1_8 -16 0 90 1 1 -( -2544 65535 65535 ) ( -2544 -65535 65535 ) ( -2544 65535 -65535 ) wizmet1_8 -16 0 90 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 -16 0 180 1 1 -( -65535 1072 65535 ) ( 65535 1072 65535 ) ( -65535 1072 -65535 ) wizmet1_8 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 -} -// brush 14 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -15 0 0 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -15 0 180 1 1 -( -65535 1504 65535 ) ( 65535 1504 65535 ) ( -65535 1504 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 15 -{ -( -3504 -65535 65535 ) ( -3504 65535 65535 ) ( -3504 65535 -65535 ) city4_5 0 0 180 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 0 0 270 1 1 -} -// brush 16 -{ -( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) rock5_2 0 0 180 1 1 -( -3040 65535 65535 ) ( -3040 -65535 65535 ) ( -3040 65535 -65535 ) rock5_2 -79 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -79 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) rock5_2 -79 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) rock5_2 -79 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 -79 0 180 1 1 -} -// brush 17 -{ -( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) rock5_2 0 0 180 1 1 -( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) rock5_2 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 0 0 90 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) rock5_2 0 0 90 1 1 -( 65535 65535 -3472 ) ( 65535 -65535 -3472 ) ( -65535 -65535 -3472 ) rock5_2 0 0 270 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 0 0 270 1 1 -} -// brush 18 -{ -( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) city6_8 0 0 180 1 1 -( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) city6_8 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 0 0 90 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) city6_8 0 0 90 1 1 -( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 0 0 270 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city6_8 0 0 270 1 1 -} -// brush 19 -{ -( -1840 -65535 65535 ) ( -1840 65535 65535 ) ( -1840 65535 -65535 ) metal1_4 0 0 180 1 1 -( -1856 65535 65535 ) ( -1856 -65535 65535 ) ( -1856 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 0 0 270 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 0 0 270 1 1 -} -// brush 20 -{ -( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -16 0 90 1 1 -( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 -} -// brush 21 -{ -( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 -( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -16 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3952.3362112220348 ) ( 65535 65535 -3952.3362112220348 ) ( -65535 -65535 -3952.3362112220348 ) metal1_4 -16 -0 180 1 1 -} -// brush 22 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 -0 90 1 1 -( -1600 65535 65535 ) ( -1600 -65535 65535 ) ( -1600 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -16 0 180 1 1 -} -// brush 23 -{ -( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) sfloor4_1 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -// brush 24 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( -2544 65535 65535 ) ( -2544 -65535 65535 ) ( -2544 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 1520 65535 ) ( 65535 1520 65535 ) ( -65535 1520 -65535 ) wizmet1_8 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 -} -// brush 25 -{ -( -737 -65535 65535 ) ( -737 65535 65535 ) ( -737 65535 -65535 ) wizmet1_8 0 0 180 1 1 -( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) wizmet1_8 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) wizmet1_8 0 0 90 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) wizmet1_8 0 0 90 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 -} -// brush 26 -{ -( 46404 -65535 46276 ) ( 46404 65535 46276 ) ( -46276 65535 -46404 ) *water2 -15 0 180 1 1 -( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) *water2 -15 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) *water2 -15 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *water2 -15 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 -} -// brush 27 -{ -( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) metal4_4 0 0 180 1 1 -( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) metal4_4 -16 0 90 1 1 -( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) metal4_4 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 -16 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal4_4 -16 0 180 1 1 -} -// brush 28 -{ -( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 46404 65535 46276 ) ( 46404 -65535 46276 ) ( -46276 65535 -46404 ) sfloor4_1 -15 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -15 0 180 1 1 -} -// brush 29 -{ -( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) city4_5 0 0 180 1 1 -( -3376 65535 65535 ) ( -3376 -65535 65535 ) ( -3376 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 0 0 270 1 1 -} -// brush 30 -{ -( 56805 65534 -32930 ) ( 56805 -65534 -32930 ) ( -60427 -65534 25685 ) metal1_4 -15 0 180 1 1 -( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3296 ) ( 65535 -65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 -} -// brush 31 -{ -( 56814 65534 -32911 ) ( 56814 -65534 -32911 ) ( -60417 -65534 25704 ) city6_8 -15 16 180 1 1 -( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) city6_8 0 15 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 0 15 90 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) city6_8 -16 15 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 0 15 270 1 1 -} -// brush 32 -{ -( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -16 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 -15 0 180 1 1 -} -// brush 33 -{ -( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 -16 0 0 1 1 -( -1600 65535 65535 ) ( -1600 -65535 65535 ) ( -1600 65535 -65535 ) city4_5 -16 0 0 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 90 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 90 1 1 -} -// brush 34 -{ -( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal5_8 -15 0 0 1 1 -( 65535 1168 65535 ) ( -65535 1168 65535 ) ( -65535 1168 -65535 ) metal5_8 -16 0 180 1 1 -( 65535 65535 -3120 ) ( 65535 -65535 -3120 ) ( -65535 -65535 -3120 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 0 180 1 1 -} -// brush 35 -{ -( -3344 -65535 65535 ) ( -3344 65535 65535 ) ( -3344 65535 -65535 ) metal5_8 0 0 180 1 1 -( 44196 48484 65535 ) ( -48484 -44196 65535 ) ( 44196 48484 -65535 ) metal5_8 16 0 180 1 1 -( -47636 45044 65535 ) ( 45044 -47636 65535 ) ( -47636 45044 -65535 ) metal5_8 16 0 180 1 1 -( 65535 65535 -3120 ) ( 65535 -65535 -3120 ) ( -65535 -65535 -3120 ) metal5_8 -47 32 180 1 1 -( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -47 32 180 1 1 -} -// brush 36 -{ -( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1168 65535 ) ( 65535 1168 65535 ) ( -65535 1168 -65535 ) city4_5 -16 0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 270 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 270 1 1 -} -// brush 37 -{ -( 45140 -47540 65535 ) ( -47540 45140 65535 ) ( -47540 45140 -65535 ) metal5_8 -16 0 180 1 1 -( 63533 65535 -16495 ) ( 63533 -65535 -16495 ) ( -64990 -65535 9209 ) metal5_8 -15 0 180 1 1 -( -48723 43862 65535 ) ( 46302 -46411 65535 ) ( -48723 43862 -65535 ) metal5_8 -16 0 180 1 1 -( 63530 -65535 -16510 ) ( 63530 65535 -16510 ) ( -64994 -65535 9194 ) metal5_8 -15 0 180 1 1 -( -3344 65535 65535 ) ( -3344 -65535 65535 ) ( -3344 65535 -65535 ) metal5_8 -15 0 0 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 -} -// brush 38 -{ -( -2928 -65535 65535 ) ( -2928 65535 65535 ) ( -2928 65535 -65535 ) metal1_3 0 0 180 1 1 -( -2936 65535 65535 ) ( -2936 -65535 65535 ) ( -2936 65535 -65535 ) metal1_3 0 0 180 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) metal1_3 -15 0 180 1 1 -} -// brush 39 -{ -( -2816 -65535 65535 ) ( -2816 65535 65535 ) ( -2816 65535 -65535 ) metal1_3 0 0 180 1 1 -( -2824 65535 65535 ) ( -2824 -65535 65535 ) ( -2824 65535 -65535 ) metal1_3 0 0 180 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) metal1_3 -15 0 180 1 1 -} -// brush 40 -{ -( -2816 -65535 65535 ) ( -2816 65535 65535 ) ( -2816 65535 -65535 ) metal5_8 -15 0 0 1 1 -( -48723 43862 65535 ) ( 46302 -46411 65535 ) ( -48723 43862 -65535 ) metal5_8 -16 0 180 1 1 -( 63530 -65535 -16510 ) ( 63530 65535 -16510 ) ( -64994 -65535 9194 ) metal5_8 -15 0 180 1 1 -( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -16 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 0 180 1 1 -} -// brush 41 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal5_8 -15 0 0 1 1 -( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -16 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 -} -// brush 42 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) sfloor4_1 -47 0 0 1 1 -( 54283 65535 36731 ) ( 54283 -65535 36731 ) ( -53093 -65535 -38432 ) sfloor4_1 -47 0 180 1 1 -( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) sfloor4_1 -47 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -47 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -47 0 180 1 1 -} -// brush 43 -{ -( -2448 -65535 65535 ) ( -2448 65535 65535 ) ( -2448 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -// brush 44 -{ -( -2544 -65535 65535 ) ( -2544 65535 65535 ) ( -2544 65535 -65535 ) metal2_6 0 0 180 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) metal2_6 -15 0 0 1 1 -( 65535 -57182 -32175 ) ( 65535 60049 26440 ) ( -65535 -57182 -32175 ) metal2_6 -15 0 180 1 1 -( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) metal2_6 -15 0 180 1 1 -( 65535 60043 26453 ) ( 65535 -57189 -32162 ) ( -65535 -57189 -32162 ) metal2_6 -15 0 180 1 1 -( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) metal2_6 -15 0 180 1 1 -} -// brush 45 -{ -( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 -0 -0 180 1 1 -( -2496 65535 65535 ) ( -2496 -65535 65535 ) ( -2496 65535 -65535 ) city4_5 -16 -0 90 1 1 -( 65535 1392 65535 ) ( -65535 1392 65535 ) ( -65535 1392 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -16 -0 180 1 1 -} -// brush 46 -{ -( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 0 0 180 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1520 65535 ) ( 65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 180 1 1 -} -// brush 47 -{ -( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 0 0 90 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 48 -{ -( 128 -64815 65535 ) ( 128 66255 65535 ) ( 128 66255 -65535 ) metal1_4 1 -15 -0 1 1 -( -304 66255 65535 ) ( -304 -64815 65535 ) ( -304 66255 -65535 ) metal1_4 1 -15 -0 1 1 -( 65679 1232 65535 ) ( -65391 1232 65535 ) ( -65391 1232 -65535 ) metal1_4 33 -15 180 1 1 -( -65391 880 65535 ) ( 65679 880 65535 ) ( -65391 880 -65535 ) metal1_4 33 -15 180 1 1 -( 65679 66255 -3408 ) ( 65679 -64815 -3408 ) ( -65391 -64815 -3408 ) city4_8 -32 -48 -0 1 1 -( 65679 -64815 -3440 ) ( 65679 66255 -3440 ) ( -65391 -64815 -3440 ) metal1_4 33 33 180 1 1 -} -// brush 49 -{ -( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 2416 65535 ) ( -65535 2416 65535 ) ( -65535 2416 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 1776 65535 ) ( 65535 1776 65535 ) ( -65535 1776 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 -0 180 1 1 -} -// brush 50 -{ -( -2944 -65535 65535 ) ( -2944 65535 65535 ) ( -2944 65535 -65535 ) rock5_2 -80 0 90 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) rock5_2 -80 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -80 0 180 1 1 -( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) rock5_2 -80 0 180 1 1 -( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -80 0 180 1 1 -} -// brush 51 -{ -( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 -( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 -( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) metal3_2 -15 0 180 1 1 -( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) city4_5 0 0 270 1 1 -} -// brush 52 -{ -( 60085 -65534 26370 ) ( 60085 65534 26370 ) ( -57147 -65534 -32245 ) city4_8 -16 0 0 1 1 -( -224 -65535 65535 ) ( -224 65535 65535 ) ( -224 65535 -65535 ) city4_8 -16 0 180 1 1 -( -368 65535 65535 ) ( -368 -65535 65535 ) ( -368 65535 -65535 ) city4_8 -16 0 180 1 1 -( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) city4_8 -16 0 0 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) city4_8 -16 0 0 1 1 -( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 -} -// brush 53 -{ -( -224 -65535 65535 ) ( -224 65535 65535 ) ( -224 65535 -65535 ) metal1_4 -15 0 90 1 1 -( 60085 65534 26370 ) ( 60085 -65534 26370 ) ( -57147 -65534 -32245 ) metal1_4 -15 0 180 1 1 -( -304 65535 65535 ) ( -304 -65535 65535 ) ( -304 65535 -65535 ) metal1_4 -15 0 90 1 1 -( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 -} -// brush 54 -{ -( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 60085 65534 26370 ) ( 60085 -65534 26370 ) ( -57147 -65534 -32245 ) metal1_4 -16 0 180 1 1 -( -368 65535 65535 ) ( -368 -65535 65535 ) ( -368 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -16 0 180 1 1 -} -// brush 55 -{ -( -1648 -65535 65535 ) ( -1648 65535 65535 ) ( -1648 65535 -65535 ) city4_5 -15 0 0 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 1504 65535 ) ( -65535 1504 65535 ) ( -65535 1504 -65535 ) city4_5 -15 0 180 1 1 -( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 56 -{ -( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) city4_5 -15 0 0 1 1 -( -1648 65535 65535 ) ( -1648 -65535 65535 ) ( -1648 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 1328 65535 ) ( -65535 1328 65535 ) ( -65535 1328 -65535 ) city4_5 -15 0 180 1 1 -( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 57 -{ -( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -1840 65535 65535 ) ( -1840 -65535 65535 ) ( -1840 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3360 ) ( 65535 65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -15 0 180 1 1 -} -// brush 58 -{ -( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) metal4_4 -16 0 90 1 1 -( -1744 65535 65535 ) ( -1744 -65535 65535 ) ( -1744 65535 -65535 ) metal4_4 -16 0 90 1 1 -( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal4_4 -16 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal4_4 -16 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal4_4 -16 0 180 1 1 -} -// brush 59 -{ -( -1744 -65535 65535 ) ( -1744 65535 65535 ) ( -1744 65535 -65535 ) metal1_4 -16 0 90 1 1 -( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 -} -// brush 60 -{ -( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) city4_5 -16 0 90 1 1 -( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -16 0 180 1 1 -} -// brush 61 -{ -( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) city4_5 -16 0 90 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3632 ) ( 65535 -65535 -3632 ) ( -65535 -65535 -3632 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -16 0 180 1 1 -} -// brush 62 -{ -( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -2544 65535 65535 ) ( -2544 -65535 65535 ) ( -2544 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 0 180 1 1 -} -// brush 63 -{ -( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) metal3_2 -15 0 0 1 1 -( -1648 65535 65535 ) ( -1648 -65535 65535 ) ( -1648 65535 -65535 ) metal3_2 -15 0 0 1 1 -( 65535 1504 65535 ) ( -65535 1504 65535 ) ( -65535 1504 -65535 ) metal3_2 -15 0 180 1 1 -( -65535 1328 65535 ) ( 65535 1328 65535 ) ( -65535 1328 -65535 ) metal3_2 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal3_2 -15 0 180 1 1 -} -// brush 64 -{ -( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) city4_5 0 0 180 1 1 -( -304 65535 65535 ) ( -304 -65535 65535 ) ( -304 65535 -65535 ) metal1_4 -15 0 90 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3936 ) ( 65535 -65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) metal1_4 -15 0 180 1 1 -} -// brush 65 -{ -( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 -32 0 90 1 1 -( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) metal1_4 -32 -0 90 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -32 0 180 1 1 -( 65535 65535 -3952 ) ( 65535 -65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -32 0 180 1 1 -( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) metal1_4 -32 0 180 1 1 -} -// brush 66 -{ -( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 56054 -65535 -34151 ) ( 56054 65535 -34151 ) ( -59539 -65535 27631 ) metal1_4 -16 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3936 ) ( 65535 -65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3952 ) ( 65535 65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -16 0 180 1 1 -} -// brush 67 -{ -( -3504 -65535 65535 ) ( -3504 65535 65535 ) ( -3504 65535 -65535 ) metal4_4 0 0 180 1 1 -( -3616 65535 65535 ) ( -3616 -65535 65535 ) ( -3616 65535 -65535 ) metal4_4 -0 -0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal4_4 0 0 90 1 1 -( -65535 80 65535 ) ( 65535 80 65535 ) ( -65535 80 -65535 ) metal4_4 -0 -0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 0 0 270 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) metal4_4 0 0 270 1 1 -} -// brush 68 -{ -( -3376 -65535 65535 ) ( -3376 65535 65535 ) ( -3376 65535 -65535 ) *water2 -15 0 0 1 1 -( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) *water2 -15 0 0 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) *water2 -15 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) *water2 -15 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 -} -// brush 69 -{ -( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) rock5_2 0 0 180 1 1 -( -3056 65535 65535 ) ( -3056 -65535 65535 ) ( -3056 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 0 0 90 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 0 0 270 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 0 0 270 1 1 -} -// brush 70 -{ -( -3040 -65535 65535 ) ( -3040 65535 65535 ) ( -3040 65535 -65535 ) metal1_4 0 0 180 1 1 -( -3056 65535 65535 ) ( -3056 -65535 65535 ) ( -3056 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 0 0 90 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 0 0 90 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 0 0 270 1 1 -} -// brush 71 -{ -( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 -} -// brush 72 -{ -( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) wiz1_4 -0 -0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 -( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) wizmet1_8 -15 -0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) wizmet1_8 -15 -0 180 1 1 -} -// brush 73 -{ -( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 -( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 0 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 -( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 0 0 180 1 1 -( -65535 80 65535 ) ( 65535 80 65535 ) ( -65535 80 -65535 ) metal1_4 0 0 180 1 1 -( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 0 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 0 0 180 1 1 -} -// brush 74 -{ -( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 -( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -16 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -16 0 180 1 1 -} -// brush 75 -{ -( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal4_4 0 0 90 1 1 -( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) metal4_4 0 0 90 1 1 -( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal4_4 0 0 270 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal4_4 0 0 270 1 1 -} -// brush 76 -{ -( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3360 ) ( 65535 -65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 -} -// brush 77 -{ -( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 -15 0 0 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -15 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 78 -{ -( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) city4_5 -15 0 0 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -2976 ) ( 65535 65535 -2976 ) ( -65535 -65535 -2976 ) city4_5 -15 0 180 1 1 -} -// brush 79 -{ -( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) city4_5 0 0 180 1 1 -( -224 65535 65535 ) ( -224 -65535 65535 ) ( -224 65535 -65535 ) metal1_4 -15 0 90 1 1 -( 65535 432 65535 ) ( -65535 432 65535 ) ( -65535 432 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 -} -// brush 80 -{ -( 45204 -47476 65535 ) ( -47476 45204 65535 ) ( -47476 45204 -65535 ) metal5_8 -15 0 180 1 1 -( -48484 -44196 65535 ) ( 44196 48484 65535 ) ( 44196 48484 -65535 ) metal5_8 -15 0 0 1 1 -( -3344 -65535 65535 ) ( -3344 65535 65535 ) ( -3344 65535 -65535 ) metal5_8 0 0 180 1 1 -( 44036 48644 65535 ) ( -48644 -44036 65535 ) ( 44036 48644 -65535 ) metal5_8 -15 0 0 1 1 -( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) metal5_8 -16 0 180 1 1 -( 65535 65535 -3120 ) ( 65535 -65535 -3120 ) ( -65535 -65535 -3120 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -47 32 180 1 1 -} -// brush 81 -{ -( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) sfloor4_1 -16 -48 180 1 1 -( -2448 65535 65535 ) ( -2448 -65535 65535 ) ( -2448 65535 -65535 ) sfloor4_1 -16 -48 180 1 1 -( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) sfloor4_1 -16 -48 0 1 1 -( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) sfloor4_1 -16 -48 0 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -16 -48 0 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -16 -48 0 1 1 -} -// brush 82 -{ -( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) wall9_8 0 0 180 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) wall9_8 -15 0 0 1 1 -( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) wall9_8 -15 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) wall9_8 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wall9_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wall9_8 -15 0 180 1 1 -} -// brush 83 -{ -( -2448 -65535 65535 ) ( -2448 65535 65535 ) ( -2448 65535 -65535 ) wall9_8 -15 0 0 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) wall9_8 -15 0 0 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wall9_8 -15 0 180 1 1 -( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wall9_8 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wall9_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wall9_8 -15 0 180 1 1 -} -// brush 84 -{ -( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) wall9_8 0 0 180 1 1 -( -2448 65535 65535 ) ( -2448 -65535 65535 ) ( -2448 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wizmet1_8 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wall9_8 -15 0 180 1 1 -} -// brush 85 -{ -( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) city4_5 -16 0 90 1 1 -( -2465 65535 65535 ) ( -2465 -65535 65535 ) ( -2465 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -16 0 180 1 1 -} -// brush 86 -{ -( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) sfloor4_1 -15 0 180 1 1 -} -// brush 87 -{ -( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) city4_5 -16 0 90 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 -} -// brush 88 -{ -( -2544 -65535 65535 ) ( -2544 65535 65535 ) ( -2544 65535 -65535 ) metal5_8 0 0 180 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) metal5_8 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal5_8 0 0 90 1 1 -( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) metal5_8 0 0 90 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 -} -// brush 89 -{ -( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 -16 0 90 1 1 -( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) wizmet1_8 -16 0 90 1 1 -( 65535 1392 65535 ) ( -65535 1392 65535 ) ( -65535 1392 -65535 ) wizmet1_8 -16 0 180 1 1 -( -65535 1072 65535 ) ( 65535 1072 65535 ) ( -65535 1072 -65535 ) wizmet1_8 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 -} -// brush 90 -{ -( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) wizmet1_8 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 -} -// brush 91 -{ -( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) city4_5 -15 0 0 1 1 -( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -15 0 180 1 1 -( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 92 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) metal3_2 -15 0 0 1 1 -( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) metal3_2 -15 0 0 1 1 -( 65535 1504 65535 ) ( -65535 1504 65535 ) ( -65535 1504 -65535 ) metal3_2 -15 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) metal3_2 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal3_2 -15 0 180 1 1 -} -// brush 93 -{ -( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 -( -737 65535 65535 ) ( -737 -65535 65535 ) ( -737 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 688 65535 ) ( -65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 94 -{ -( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 -( -737 65535 65535 ) ( -737 -65535 65535 ) ( -737 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1440 65535 ) ( 65535 1440 65535 ) ( -65535 1440 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 95 -{ -( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) rock5_2 -79 -0 -0 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) rock5_2 -79 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -79 0 180 1 1 -( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) rock5_2 -79 -0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) rock5_2 -79 0 180 1 1 -( 65535 -65535 -2880 ) ( 65535 65535 -2880 ) ( -65535 -65535 -2880 ) rock5_2 -79 0 180 1 1 -} -// brush 96 -{ -( -4032 -65535 65535 ) ( -4032 65535 65535 ) ( -4032 65535 -65535 ) city4_5 0 0 180 1 1 -( -4048 65535 65535 ) ( -4048 -65535 65535 ) ( -4048 65535 -65535 ) city4_7 48 -0 -0 1 1 -( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 -0 -0 90 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -0 -0 90 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -0 -0 270 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city4_5 -0 -0 270 1 1 -} -// brush 97 -{ -( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) metal1_4 -15 -0 -0 1 1 -( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3952 ) ( 65535 -65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) metal1_4 -15 0 180 1 1 -} -// brush 98 -{ -( 48 -65535 65535 ) ( 48 65535 65535 ) ( 48 65535 -65535 ) metal1_4 -15 -0 -0 1 1 -( -208 65535 65535 ) ( -208 -65535 65535 ) ( -208 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 -15 -0 180 1 1 -( 65535 65535 -3952 ) ( 65535 -65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -15 -0 180 1 1 -( 65535 -65535 -3968 ) ( 65535 65535 -3968 ) ( -65535 -65535 -3968 ) metal1_4 -15 -0 180 1 1 -} -// brush 99 -{ -( 128 -63999 65535 ) ( 128 67071 65535 ) ( 128 67071 -65535 ) metal1_4 48 -48 180 1 1 -( -400 67071 65535 ) ( -400 -63999 65535 ) ( -400 67071 -65535 ) metal1_4 48 -48 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal1_4 48 -48 -0 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 48 -48 -0 1 1 -( 65535 67071 -3952 ) ( 65535 -63999 -3952 ) ( -65535 -63999 -3952 ) metal1_4 48 16 -0 1 1 -( 65535 -63999 -3968 ) ( 65535 67071 -3968 ) ( -65535 -63999 -3968 ) metal1_4 48 16 -0 1 1 -} -// brush 100 -{ -( -3168 -65535 65535 ) ( -3168 65535 65535 ) ( -3168 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) sfloor4_1 -15 0 180 1 1 -} -// brush 101 -{ -( -3376 -65535 65535 ) ( -3376 65535 65535 ) ( -3376 65535 -65535 ) city4_5 -15 0 0 1 1 -( -3504 65535 65535 ) ( -3504 -65535 65535 ) ( -3504 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) city4_5 -15 0 180 1 1 -} -// brush 102 -{ -( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) rock5_2 0 0 180 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) rock5_2 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 0 0 90 1 1 -( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) rock5_2 -0 -0 90 1 1 -( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 0 0 270 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) rock5_2 0 0 270 1 1 -} -// brush 103 -{ -( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) rock5_2 -79 0 0 1 1 -( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) rock5_2 -79 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 -79 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) rock5_2 -79 0 180 1 1 -( 65535 65535 -3632 ) ( 65535 -65535 -3632 ) ( -65535 -65535 -3632 ) rock5_2 -79 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) rock5_2 -79 0 180 1 1 -} -// brush 104 -{ -( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) *lava1 -15 0 0 1 1 -( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) *lava1 -15 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) *lava1 -15 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *lava1 -15 0 180 1 1 -( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) *lava1 -15 0 180 1 1 -( 65535 -65535 -3632 ) ( 65535 65535 -3632 ) ( -65535 -65535 -3632 ) *lava1 -15 0 180 1 1 -} -// brush 105 -{ -( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -16 0 90 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 65535 -304 65535 ) ( -65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -16 0 180 1 1 -} -// brush 106 -{ -( -3152 -65535 65535 ) ( -3152 65535 65535 ) ( -3152 65535 -65535 ) metal1_4 0 0 180 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -16 0 180 1 1 -} -// brush 107 -{ -( -3152 -65535 65535 ) ( -3152 65535 65535 ) ( -3152 65535 -65535 ) metal1_4 0 0 180 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3280 ) ( 65535 -65535 -3280 ) ( -65535 -65535 -3280 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 -} -// brush 108 -{ -( -3152 -65535 65535 ) ( -3152 65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 -} -// brush 109 -{ -( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 -} -// brush 110 -{ -( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3296 ) ( 65535 -65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -15 0 180 1 1 -} -// brush 111 -{ -( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 55094 65535 35503 ) ( 55094 -65535 35503 ) ( -53962 -65535 -37201 ) metal1_4 -15 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3296 ) ( 65535 65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 -} -// brush 112 -{ -( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 52096 -65535 -40000 ) ( 52096 65535 -40000 ) ( -56960 -65535 32704 ) metal1_4 -15 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 -} -// brush 113 -{ -( -3056 -65535 65535 ) ( -3056 65535 65535 ) ( -3056 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -3152 65535 65535 ) ( -3152 -65535 65535 ) ( -3152 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 -} -// brush 114 -{ -( -3024 -65535 65535 ) ( -3024 65535 65535 ) ( -3024 65535 -65535 ) metal4_4 -16 0 90 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) metal4_4 -16 0 90 1 1 -( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal4_4 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal4_4 -16 0 180 1 1 -( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) metal4_4 -16 0 180 1 1 -} -// brush 115 -{ -( 56805 65534 -32930 ) ( 56805 -65534 -32930 ) ( -60427 -65534 25685 ) metal1_4 -15 0 180 1 1 -( 59352 65534 27836 ) ( 59352 -65534 27836 ) ( -57880 -65534 -30780 ) metal1_4 -15 0 180 1 1 -( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3232 ) ( 65535 -65535 -3232 ) ( -65535 -65535 -3232 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3296 ) ( 65535 65535 -3296 ) ( -65535 -65535 -3296 ) metal1_4 -15 0 180 1 1 -} -// brush 116 -{ -( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 56843 -65534 -32853 ) ( 56843 65534 -32853 ) ( -60389 -65534 25762 ) metal1_4 -15 0 180 1 1 -( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -15 0 180 1 1 -} -// brush 117 -{ -( 59313 -65534 27912 ) ( 59313 65534 27912 ) ( -57918 -65534 -30703 ) metal1_4 -15 0 180 1 1 -( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal1_4 -15 0 180 1 1 -} -// brush 118 -{ -( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal4_4 0 0 180 1 1 -( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) metal1_4 -16 0 180 1 1 -} -// brush 119 -{ -( -2144 -65535 65535 ) ( -2144 65535 65535 ) ( -2144 65535 -65535 ) metal4_4 0 0 180 1 1 -( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3136 ) ( 65535 65535 -3136 ) ( -65535 -65535 -3136 ) metal1_4 -15 0 180 1 1 -} -// brush 120 -{ -( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 -304 65535 ) ( 65535 -304 65535 ) ( -65535 -304 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3360 ) ( 65535 65535 -3360 ) ( -65535 -65535 -3360 ) metal1_4 -15 0 180 1 1 -} -// brush 121 -{ -( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) metal5_8 0 0 180 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) metal5_8 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal5_8 0 0 90 1 1 -( -65535 416 65535 ) ( 65535 416 65535 ) ( -65535 416 -65535 ) metal5_8 -16 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal5_8 0 0 270 1 1 -} -// brush 122 -{ -( 56054 65535 -34151 ) ( 56054 -65535 -34151 ) ( -59539 -65535 27631 ) metal1_4 -15 0 180 1 1 -( 55969 -65535 -34311 ) ( 55969 65535 -34311 ) ( -59625 -65535 27471 ) metal1_4 -15 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -15 0 180 1 1 -} -// brush 123 -{ -( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 0 0 180 1 1 -( 56094 -65535 -34077 ) ( 56094 65535 -34077 ) ( -59499 -65535 27706 ) metal1_4 -15 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 -0 -0 180 1 1 -( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3040 ) ( 65535 -65535 -3040 ) ( -65535 -65535 -3040 ) wizmet1_8 -15 -0 180 1 1 -} -// brush 124 -{ -( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 0 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city4_5 0 0 90 1 1 -( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) city4_5 -0 -0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 125 -{ -( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) city4_5 0 0 180 1 1 -( -3168 65535 65535 ) ( -3168 -65535 65535 ) ( -3168 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -16 0 180 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2976 ) ( 65535 -65535 -2976 ) ( -65535 -65535 -2976 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 126 -{ -( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) city4_5 17 16 180 1 1 -( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) city4_5 17 16 180 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 17 16 0 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 17 16 0 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 17 16 -0 1 1 -} -// brush 127 -{ -( -448 -65535 65535 ) ( -448 65535 65535 ) ( -448 65535 -65535 ) wiz1_4 -0 -0 180 1 1 -( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) city4_5 -16 -0 -0 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) city4_5 16 0 0 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -16 -0 90 1 1 -( 65535 -65535 -3408 ) ( 65535 65535 -3408 ) ( -65535 -65535 -3408 ) city4_5 -16 -0 90 1 1 -} -// brush 128 -{ -( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) city4_5 -0 -0 180 1 1 -( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -16 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal1_4 -0 -0 180 1 1 -( 65535 65535 -3744 ) ( 65535 -65535 -3744 ) ( -65535 -65535 -3744 ) city4_8 -16 -0 -0 1 1 -( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) city4_5 -0 -0 270 1 1 -} -// brush 129 -{ -( 60085 -65534 26370 ) ( 60085 65534 26370 ) ( -57147 -65534 -32245 ) metal1_4 -15 0 180 1 1 -( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) metal1_4 -15 0 0 1 1 -( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) metal1_4 -15 0 0 1 1 -( 65535 304 65535 ) ( -65535 304 65535 ) ( -65535 304 -65535 ) metal1_4 -15 0 180 1 1 -( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -15 0 180 1 1 -( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -16 0 0 1 1 -( 65535 -65535 -3856 ) ( 65535 65535 -3856 ) ( -65535 -65535 -3856 ) metal1_4 -15 0 180 1 1 -} -// brush 130 -{ -( -752 -64335 65535 ) ( -752 66735 65535 ) ( -752 66735 -65535 ) ecop1_1 16 -0 -0 1 1 -( -816 66735 65535 ) ( -816 -64335 65535 ) ( -816 66735 -65535 ) ecop1_1 16 -0 -0 1 1 -( 65023 1072 65535 ) ( -66047 1072 65535 ) ( -66047 1072 -65535 ) ecop1_1 -0 -0 -0 1 1 -( -66047 1008 65535 ) ( 65023 1008 65535 ) ( -66047 1008 -65535 ) ecop1_1 -0 -0 -0 1 1 -( 65023 66735 -3052 ) ( 65023 -64335 -3052 ) ( -66047 -64335 -3052 ) ecop1_1 -0 -16 -0 1 1 -( 65023 -64335 -3056 ) ( 65023 66735 -3056 ) ( -66047 -64335 -3056 ) ecop1_1 -0 -16 -0 1 1 -} -// brush 131 -{ -( -2488 -65535 65535 ) ( -2488 65535 65535 ) ( -2488 65535 -65535 ) sfloor4_1 -15 -0 -0 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) sfloor4_1 -15 -0 180 1 1 -} -// brush 132 -{ -( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 -( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 -( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) city4_5 0 0 180 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 270 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) city4_5 -16 0 270 1 1 -} -// brush 133 -{ -( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) *water2 -15 0 0 1 1 -( -47636 45044 65535 ) ( 45044 -47636 65535 ) ( -47636 45044 -65535 ) *water2 -15 0 0 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) *water2 -15 0 0 1 1 -( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) *water2 -15 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 -} -// brush 134 -{ -( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) *water2 -15 0 0 1 1 -( 44036 48644 65535 ) ( -48644 -44036 65535 ) ( 44036 48644 -65535 ) *water2 -15 0 0 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) *water2 -15 0 0 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) *water2 -15 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 -} -// brush 135 -{ -( -2488 -65535 65535 ) ( -2488 65535 65535 ) ( -2488 65535 -65535 ) sfloor4_6 48 -0 -0 1 1 -( 54283 65535 36731 ) ( 54283 -65535 36731 ) ( -53093 -65535 -38432 ) sfloor4_1 -47 0 180 1 1 -( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) sfloor4_1 -47 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -47 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -47 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) sfloor4_1 -47 0 180 1 1 -} -// brush 136 -{ -( 54283 -65535 36731 ) ( 54283 65535 36731 ) ( -53093 -65535 -38432 ) *water2 -15 0 180 1 1 -( -3664 65535 65535 ) ( -3664 -65535 65535 ) ( -3664 65535 -65535 ) *water2 -15 0 0 1 1 -( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) *water2 -15 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) *water2 -15 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) *water2 -15 0 180 1 1 -( 65535 -65535 -3440 ) ( 65535 65535 -3440 ) ( -65535 -65535 -3440 ) *water2 -15 0 180 1 1 -} -// brush 137 -{ -( 61198 -69207 -8124 ) ( 61198 48024 50491 ) ( -58451 -45277 -55984 ) sfloor4_6 48 0 90 1 1 -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) sfloor4_6 48 0 0 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) sfloor4_6 48 -0 -0 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_6 48 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_6 48 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) sfloor4_6 48 0 90 1 1 -} -// brush 138 -{ -( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 -( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 -( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) city4_5 0 0 180 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 -( 65535 1168 65535 ) ( -65535 1168 65535 ) ( -65535 1168 -65535 ) city4_5 -16 0 90 1 1 -( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) city4_5 -16 0 270 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 270 1 1 -} -// brush 139 -{ -( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) metal5_8 -15 -15 0 1 1 -( -47636 45044 65535 ) ( 45044 -47636 65535 ) ( -47636 45044 -65535 ) metal5_8 -15 -15 0 1 1 -( 65535 -52721 -39062 ) ( 65535 56335 33642 ) ( -65535 -52721 -39062 ) metal5_8 -15 -15 180 1 1 -( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 -15 180 1 1 -} -// brush 140 -{ -( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) metal5_8 -15 -15 0 1 1 -( 44036 48644 65535 ) ( -48644 -44036 65535 ) ( 44036 48644 -65535 ) metal5_8 -15 -15 0 1 1 -( 65535 -55714 34572 ) ( 65535 53341 -38131 ) ( -65535 -55714 34572 ) metal5_8 -15 -15 180 1 1 -( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 -15 180 1 1 -} -// brush 141 -{ -( 73382 -19297 53221 ) ( -19297 73382 53221 ) ( -72806 19873 -53797 ) metal5_8 -15 -15 180 1 1 -( -19969 -72710 53893 ) ( 72710 19969 53893 ) ( 19201 73478 -53125 ) metal5_8 -15 -15 180 1 1 -( 46236 -65535 46444 ) ( 46236 65535 46444 ) ( -46444 65535 -46236 ) metal5_8 -15 -15 180 1 1 -( -3664 65535 65535 ) ( -3664 -65535 65535 ) ( -3664 65535 -65535 ) metal5_8 -15 -15 0 1 1 -( 65535 -52721 -39062 ) ( 65535 56335 33642 ) ( -65535 -52721 -39062 ) metal5_8 -15 -15 180 1 1 -( 65535 -55714 34572 ) ( 65535 53341 -38131 ) ( -65535 -55714 34572 ) metal5_8 -15 -15 180 1 1 -( 65535 65535 -3136 ) ( 65535 -65535 -3136 ) ( -65535 -65535 -3136 ) metal5_8 -15 -15 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 -15 180 1 1 -} -// brush 142 -{ -( 45044 -47636 65535 ) ( -47636 45044 65535 ) ( -47636 45044 -65535 ) city4_5 -16 0 180 1 1 -( -48644 -44036 65535 ) ( 44036 48644 65535 ) ( 44036 48644 -65535 ) city4_5 16 0 180 1 1 -( -3664 -65535 65535 ) ( -3664 65535 65535 ) ( -3664 65535 -65535 ) city4_5 0 0 180 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 180 1 1 -( 65535 1168 65535 ) ( -65535 1168 65535 ) ( -65535 1168 -65535 ) city4_5 -16 0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 270 1 1 -( 65535 -65535 -3120 ) ( 65535 65535 -3120 ) ( -65535 -65535 -3120 ) city4_5 -16 0 270 1 1 -} -// brush 143 -{ -( -3840 1440 -3055.6818278010733 ) ( -3840 1440 -3071.9626565132116 ) ( -3568 1168 -3135.9615853377113 ) metal5_8 16 0 180 1 1 -( -3760 1168 -3135.9612395957392 ) ( -4032 1440 -3071.9623107712378 ) ( -4032 1440 -3055.6818278010719 ) metal5_8 16 0 180 1 1 -( -3840 1440 -3071.9626565132116 ) ( -4032 1440 -3071.9623107712378 ) ( -3760 1168 -3135.9612395957392 ) metal5_8 -15 32 180 1 1 -( -4032 1440 -3055.6818278010719 ) ( -4032 1440 -3071.9623107712378 ) ( -3840 1440 -3071.9626565132116 ) metal5_8 16 0 90 1 1 -( -3568 1168 -3119.6796958890081 ) ( -3760 1168 -3119.6796958890072 ) ( -4032 1440 -3055.6818278010719 ) metal5_8 -15 32 180 1 1 -( -3568 1168 -3135.9615853377113 ) ( -3760 1168 -3135.9612395957392 ) ( -3760 1168 -3119.6796958890072 ) metal5_8 16 0 90 1 1 -} -// brush 144 -{ -( 45140 -47540 65535 ) ( -47540 45140 65535 ) ( -47540 45140 -65535 ) metal5_8 -16 0 180 1 1 -( 63530 -65535 -16510 ) ( 63530 65535 -16510 ) ( -64994 -65535 9194 ) metal5_8 -15 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 0 180 1 1 -} -// brush 145 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3312 ) ( 65535 -65535 -3312 ) ( -65535 -65535 -3312 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3320 ) ( 65535 65535 -3320 ) ( -65535 -65535 -3320 ) metal1_3 -15 0 180 1 1 -} -// brush 146 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3296 ) ( 65535 -65535 -3296 ) ( -65535 -65535 -3296 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3304 ) ( 65535 65535 -3304 ) ( -65535 -65535 -3304 ) metal1_3 -15 0 180 1 1 -} -// brush 147 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3280 ) ( 65535 -65535 -3280 ) ( -65535 -65535 -3280 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3288 ) ( 65535 65535 -3288 ) ( -65535 -65535 -3288 ) metal1_3 -15 0 180 1 1 -} -// brush 148 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3264 ) ( 65535 -65535 -3264 ) ( -65535 -65535 -3264 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3272 ) ( 65535 65535 -3272 ) ( -65535 -65535 -3272 ) metal1_3 -15 0 180 1 1 -} -// brush 149 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3248 ) ( 65535 -65535 -3248 ) ( -65535 -65535 -3248 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3256 ) ( 65535 65535 -3256 ) ( -65535 -65535 -3256 ) metal1_3 -15 0 180 1 1 -} -// brush 150 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3232 ) ( 65535 -65535 -3232 ) ( -65535 -65535 -3232 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3240 ) ( 65535 65535 -3240 ) ( -65535 -65535 -3240 ) metal1_3 -15 0 180 1 1 -} -// brush 151 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3216 ) ( 65535 -65535 -3216 ) ( -65535 -65535 -3216 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3224 ) ( 65535 65535 -3224 ) ( -65535 -65535 -3224 ) metal1_3 -15 0 180 1 1 -} -// brush 152 -{ -( -2824 -65535 65535 ) ( -2824 65535 65535 ) ( -2824 65535 -65535 ) metal1_3 -15 0 0 1 1 -( -2928 65535 65535 ) ( -2928 -65535 65535 ) ( -2928 65535 -65535 ) metal1_3 -15 0 0 1 1 -( 65535 584 65535 ) ( -65535 584 65535 ) ( -65535 584 -65535 ) metal1_3 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal1_3 -16 0 180 1 1 -( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) metal1_3 -15 0 180 1 1 -( 65535 -65535 -3208 ) ( 65535 65535 -3208 ) ( -65535 -65535 -3208 ) metal1_3 -15 0 180 1 1 -} -// brush 153 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 -( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) metal5_8 0 0 180 1 1 -( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) metal5_8 -16 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) metal5_8 -15 0 180 1 1 -} -// brush 154 -{ -( -2800 -65535 65535 ) ( -2800 65535 65535 ) ( -2800 65535 -65535 ) city4_5 0 0 180 1 1 -( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) city4_5 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) city4_5 0 0 270 1 1 -} -// brush 155 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -16 0 90 1 1 -( -2800 65535 65535 ) ( -2800 -65535 65535 ) ( -2800 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) city4_5 -16 0 180 1 1 -( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) city4_5 -16 0 180 1 1 -} -// brush 156 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 -( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) metal5_8 0 0 180 1 1 -( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) metal5_8 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 -} -// brush 157 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -15 0 0 1 1 -( -2704 65535 65535 ) ( -2704 -65535 65535 ) ( -2704 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 976 65535 ) ( -65535 976 65535 ) ( -65535 976 -65535 ) city4_5 -16 0 180 1 1 -( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 158 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -16 0 90 1 1 -( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1104 65535 ) ( -65535 1104 65535 ) ( -65535 1104 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 159 -{ -( -2800 -65535 65535 ) ( -2800 65535 65535 ) ( -2800 65535 -65535 ) city4_5 0 0 180 1 1 -( -2816 65535 65535 ) ( -2816 -65535 65535 ) ( -2816 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1104 65535 ) ( 65535 1104 65535 ) ( -65535 1104 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 160 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 0 0 1 1 -( -2800 65535 65535 ) ( -2800 -65535 65535 ) ( -2800 65535 -65535 ) metal5_8 0 0 180 1 1 -( 65535 1440 65535 ) ( -65535 1440 65535 ) ( -65535 1440 -65535 ) metal5_8 -15 0 180 1 1 -( -65535 1104 65535 ) ( 65535 1104 65535 ) ( -65535 1104 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 0 180 1 1 -} -// brush 161 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) metal5_8 -15 32 0 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal5_8 -15 32 0 1 1 -( 65535 1552 65535 ) ( -65535 1552 65535 ) ( -65535 1552 -65535 ) metal5_8 -15 32 180 1 1 -( -65535 1440 65535 ) ( 65535 1440 65535 ) ( -65535 1440 -65535 ) metal5_8 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 32 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) metal5_8 -15 32 180 1 1 -} -// brush 162 -{ -( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) city4_5 -16 0 90 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1552 65535 ) ( 65535 1552 65535 ) ( -65535 1552 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city4_5 -16 -0 180 1 1 -} -// brush 163 -{ -( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) city4_5 -0 -0 270 1 1 -} -// brush 164 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -// brush 165 -{ -( -1488 -65535 65535 ) ( -1488 65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 -( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 -} -// brush 166 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) wizmet1_8 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 -} -// brush 167 -{ -( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -16 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) metal5_8 -15 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) metal5_8 -15 0 180 1 1 -} -// brush 168 -{ -( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -16 0 180 1 1 -( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3184 ) ( 65535 65535 -3184 ) ( -65535 -65535 -3184 ) city4_5 -16 0 180 1 1 -} -// brush 169 -{ -( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -15 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 170 -{ -( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -15 0 180 1 1 -( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 -} -// brush 171 -{ -( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal5_8 -15 0 180 1 1 -( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) metal5_8 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) metal5_8 -15 0 180 1 1 -} -// brush 172 -{ -( -2672 -65535 65535 ) ( -2672 65535 65535 ) ( -2672 65535 -65535 ) city4_5 0 0 180 1 1 -( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1104 65535 ) ( -65535 1104 65535 ) ( -65535 1104 -65535 ) city4_5 -16 0 180 1 1 -( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 -} -// brush 173 -{ -( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -// brush 174 -{ -( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) city4_5 0 0 180 1 1 -( -2465 65535 65535 ) ( -2465 -65535 65535 ) ( -2465 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) city4_5 -16 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 0 0 270 1 1 -} -// brush 175 -{ -( -2465 -65535 65535 ) ( -2465 65535 65535 ) ( -2465 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -2672 65535 65535 ) ( -2672 -65535 65535 ) ( -2672 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -// brush 176 -{ -( -2447 -65535 65535 ) ( -2447 65535 65535 ) ( -2447 65535 -65535 ) city4_5 0 0 180 1 1 -( -2465 65535 65535 ) ( -2465 -65535 65535 ) ( -2465 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 0 0 90 1 1 -( -65535 944 65535 ) ( 65535 944 65535 ) ( -65535 944 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 0 0 270 1 1 -} -// brush 177 -{ -( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( -2447 65535 65535 ) ( -2447 -65535 65535 ) ( -2447 65535 -65535 ) wizmet1_8 -15 0 0 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wizmet1_8 -16 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wizmet1_8 -15 0 180 1 1 -} -// brush 178 -{ -( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) city4_5 0 0 180 1 1 -( -2447 65535 65535 ) ( -2447 -65535 65535 ) ( -2447 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 0 0 90 1 1 -( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 0 0 270 1 1 -} -// brush 179 -{ -( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) wizmet1_8 0 0 180 1 1 -( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) wizmet1_8 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) wizmet1_8 -16 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) wizmet1_8 -15 0 180 1 1 -} -// brush 180 -{ -( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) city4_5 0 0 180 1 1 -( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 608 65535 ) ( -65535 608 65535 ) ( -65535 608 -65535 ) city4_5 -16 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 181 -{ -( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 -( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1328 65535 ) ( -65535 1328 65535 ) ( -65535 1328 -65535 ) city4_5 -16 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -16 0 180 1 1 -} -// brush 182 -{ -( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 1328 65535 ) ( 65535 1328 65535 ) ( -65535 1328 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -// brush 183 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -// brush 184 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 -( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 608 65535 ) ( -65535 608 65535 ) ( -65535 608 -65535 ) city4_5 -16 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3072 ) ( 65535 -65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3200 ) ( 65535 65535 -3200 ) ( -65535 -65535 -3200 ) city4_5 -15 0 180 1 1 -} -// brush 185 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 0 0 180 1 1 -( -1520 65535 65535 ) ( -1520 -65535 65535 ) ( -1520 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 0 0 90 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 186 -{ -( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -16 0 180 1 1 -} -// brush 187 -{ -( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 -( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) city4_5 -16 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -3055 ) ( 65535 -65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -15 0 180 1 1 -} -// brush 188 -{ -( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 -( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) city4_5 -16 0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3055 ) ( 65535 65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -16 0 180 1 1 -} -// brush 189 -{ -( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) sfloor4_1 -15 0 180 1 1 -} -// brush 190 -{ -( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 -( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -15 0 180 1 1 -( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) city4_5 -15 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -15 0 180 1 1 -} -// brush 191 -{ -( 61198 -69207 -8124 ) ( 61198 48024 50491 ) ( -58451 -45277 -55984 ) city4_5 -15 0 180 1 1 -( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 -( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -15 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3055 ) ( 65535 -65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 -15 0 180 1 1 -} -// brush 192 -{ -( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) city4_5 0 0 180 1 1 -( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1200 65535 ) ( 65535 1200 65535 ) ( -65535 1200 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 -16 0 180 1 1 -( 65535 -65535 -3055 ) ( 65535 65535 -3055 ) ( -65535 -65535 -3055 ) city4_5 -16 0 180 1 1 -} -// brush 193 -{ -( 61106 65535 -23920 ) ( 61106 -65535 -23920 ) ( -63237 -65535 17527 ) sfloor4_1 -15 0 180 1 1 -( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1232 65535 ) ( -65535 1232 65535 ) ( -65535 1232 -65535 ) sfloor4_1 -16 0 180 1 1 -( -65535 864 65535 ) ( 65535 864 65535 ) ( -65535 864 -65535 ) sfloor4_1 -16 0 180 1 1 -( 65535 65535 -3328 ) ( 65535 -65535 -3328 ) ( -65535 -65535 -3328 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3408 ) ( 65535 65535 -3408 ) ( -65535 -65535 -3408 ) sfloor4_1 -15 0 180 1 1 -} -// brush 194 -{ -( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 -( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 688 65535 ) ( -65535 688 65535 ) ( -65535 688 -65535 ) city4_5 -16 0 180 1 1 -( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 195 -{ -( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) city4_5 0 0 180 1 1 -( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 0 0 90 1 1 -( -65535 1440 65535 ) ( 65535 1440 65535 ) ( -65535 1440 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 196 -{ -( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) city4_5 -15 0 0 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 -15 0 180 1 1 -( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -4000 ) ( 65535 65535 -4000 ) ( -65535 -65535 -4000 ) city4_5 -15 0 180 1 1 -} -// brush 197 -{ -( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) city4_5 -15 0 0 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) city4_5 -15 0 0 1 1 -( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -15 0 180 1 1 -( 65535 -65535 -2960 ) ( 65535 65535 -2960 ) ( -65535 -65535 -2960 ) city4_5 -15 0 180 1 1 -} -// brush 198 -{ -( -1488 -65535 65535 ) ( -1488 65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 -( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) city4_5 -0 -0 180 1 1 -( 65535 2432 65535 ) ( -65535 2432 65535 ) ( -65535 2432 -65535 ) city4_5 -0 -0 90 1 1 -( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -0 -0 270 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 -} -// brush 199 -{ -( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) city4_5 0 0 180 1 1 -( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1776 65535 ) ( -65535 1776 65535 ) ( -65535 1776 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 -} -// brush 200 -{ -( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) sfloor4_1 -15 0 0 1 1 -( 65535 1776 65535 ) ( -65535 1776 65535 ) ( -65535 1776 -65535 ) sfloor4_1 -15 0 180 1 1 -( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) sfloor4_1 -15 0 180 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) sfloor4_1 -15 -0 180 1 1 -} -// brush 201 -{ -( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 -( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 1776 65535 ) ( -65535 1776 65535 ) ( -65535 1776 -65535 ) city4_5 -16 0 180 1 1 -( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 -} -// brush 202 -{ -( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) city4_5 0 0 180 1 1 -( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 2192 65535 ) ( -65535 2192 65535 ) ( -65535 2192 -65535 ) city4_5 -16 0 180 1 1 -( -65535 2096 65535 ) ( 65535 2096 65535 ) ( -65535 2096 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 203 -{ -( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 -( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 2192 65535 ) ( -65535 2192 65535 ) ( -65535 2192 -65535 ) city4_5 -16 0 180 1 1 -( -65535 2096 65535 ) ( 65535 2096 65535 ) ( -65535 2096 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2880 ) ( 65535 -65535 -2880 ) ( -65535 -65535 -2880 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3056 ) ( 65535 65535 -3056 ) ( -65535 -65535 -3056 ) city4_5 0 0 270 1 1 -} -// brush 204 -{ -( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) metal3_2 -15 0 0 1 1 -( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) metal3_2 -15 0 0 1 1 -( 65535 2416 65535 ) ( -65535 2416 65535 ) ( -65535 2416 -65535 ) metal3_2 -15 0 180 1 1 -( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) metal3_2 -15 0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) metal3_2 -15 -0 180 1 1 -( 65535 -65535 -2880 ) ( 65535 65535 -2880 ) ( -65535 -65535 -2880 ) metal3_2 -15 0 180 1 1 -} -// brush 205 -{ -( -1104 -65535 65535 ) ( -1104 65535 65535 ) ( -1104 65535 -65535 ) city4_5 -16 0 90 1 1 -( -1488 65535 65535 ) ( -1488 -65535 65535 ) ( -1488 65535 -65535 ) city4_5 -16 0 90 1 1 -( 65535 2432 65535 ) ( -65535 2432 65535 ) ( -65535 2432 -65535 ) city4_5 -16 -0 180 1 1 -( -65535 2416 65535 ) ( 65535 2416 65535 ) ( -65535 2416 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -16 -0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -16 -0 180 1 1 -} -// brush 206 -{ -( -1088 -65535 65535 ) ( -1088 65535 65535 ) ( -1088 65535 -65535 ) city4_5 -0 -0 180 1 1 -( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 2432 65535 ) ( -65535 2432 65535 ) ( -65535 2432 -65535 ) city4_5 -0 -0 90 1 1 -( -65535 1680 65535 ) ( 65535 1680 65535 ) ( -65535 1680 -65535 ) sky1 16 0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 -0 -0 270 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) city4_5 -0 -0 270 1 1 -} -// brush 207 -{ -( -1520 -65535 65535 ) ( -1520 65535 65535 ) ( -1520 65535 -65535 ) wizmet1_8 0 0 180 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) wizmet1_8 0 0 180 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) wizmet1_8 0 0 90 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) wizmet1_8 0 0 90 1 1 -( 65535 65535 -3056 ) ( 65535 -65535 -3056 ) ( -65535 -65535 -3056 ) wizmet1_8 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) wizmet1_8 -15 0 180 1 1 -} -// brush 208 -{ -( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) city6_8 -15 0 0 1 1 -( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) city6_8 -15 0 0 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 -15 0 180 1 1 -( -65535 -48 65535 ) ( 65535 -48 65535 ) ( -65535 -48 -65535 ) city6_8 -15 0 180 1 1 -( 65535 65535 -3456 ) ( 65535 -65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 -15 0 180 1 1 -( 65535 -65535 -3520 ) ( 65535 65535 -3520 ) ( -65535 -65535 -3520 ) city6_8 -15 0 180 1 1 -} -// brush 209 -{ -( -1856 -65535 65535 ) ( -1856 65535 65535 ) ( -1856 65535 -65535 ) metal1_4 -16 0 90 1 1 -( -2144 65535 65535 ) ( -2144 -65535 65535 ) ( -2144 65535 -65535 ) metal1_4 -16 0 90 1 1 -( 65535 -48 65535 ) ( -65535 -48 65535 ) ( -65535 -48 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) metal1_4 -16 0 180 1 1 -( 65535 65535 -3344 ) ( 65535 -65535 -3344 ) ( -65535 -65535 -3344 ) metal1_4 -16 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal1_4 -16 0 180 1 1 -} -// brush 210 -{ -( -736 -65535 65535 ) ( -736 65535 65535 ) ( -736 65535 -65535 ) metal3_2 0 0 180 1 1 -( -4032 65535 65535 ) ( -4032 -65535 65535 ) ( -4032 65535 -65535 ) metal3_2 0 0 180 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) metal3_2 0 0 90 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) metal3_2 0 0 90 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) metal3_2 -15 0 180 1 1 -( 65535 -65535 -2880 ) ( 65535 65535 -2880 ) ( -65535 -65535 -2880 ) metal3_2 -15 0 180 1 1 -} -// brush 211 -{ -( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) rock5_2 -0 -0 180 1 1 -( -2160 65535 65535 ) ( -2160 -65535 65535 ) ( -2160 65535 -65535 ) rock5_2 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) rock5_2 0 0 90 1 1 -( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) rock5_2 -0 -0 90 1 1 -( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) rock5_2 0 0 270 1 1 -( 65535 -65535 -3712 ) ( 65535 65535 -3712 ) ( -65535 -65535 -3712 ) rock5_2 -0 -0 270 1 1 -} -// brush 212 -{ -( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) metal4_4 -16 0 90 1 1 -( -3024 65535 65535 ) ( -3024 -65535 65535 ) ( -3024 65535 -65535 ) metal4_4 -16 0 90 1 1 -( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) metal4_4 -16 0 180 1 1 -( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metal4_4 -16 -0 180 1 1 -( 65535 65535 -3520 ) ( 65535 -65535 -3520 ) ( -65535 -65535 -3520 ) metal4_4 -16 0 180 1 1 -( 65535 -65535 -3664 ) ( 65535 65535 -3664 ) ( -65535 -65535 -3664 ) metal4_4 -16 -0 180 1 1 -} -// brush 213 -{ -( -1744 -65695 65535 ) ( -1744 65375 65535 ) ( -1744 65375 -65535 ) metal1_4 -32 -0 180 1 1 -( -1760 65375 65535 ) ( -1760 -65695 65535 ) ( -1760 65375 -65535 ) metal1_4 -32 -0 180 1 1 -( 65631 -160 65535 ) ( -65439 -160 65535 ) ( -65439 -160 -65535 ) metal1_4 16 -0 180 1 1 -( -65439 -320 65535 ) ( 65631 -320 65535 ) ( -65439 -320 -65535 ) metal1_4 16 -0 180 1 1 -( 65631 65375 -3328 ) ( 65631 -65695 -3328 ) ( -65439 -65695 -3328 ) metal1_4 -32 -32 270 1 1 -( 65631 -65695 -3472 ) ( 65631 65375 -3472 ) ( -65439 -65695 -3472 ) metal1_4 -32 -32 270 1 1 -} -// brush 214 -{ -( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) wiz1_4 -0 -0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) metal4_4 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) wizmet1_8 -15 0 180 1 1 -( -65535 304 65535 ) ( 65535 304 65535 ) ( -65535 304 -65535 ) wizmet1_8 -15 0 180 1 1 -( 65535 65535 -3040 ) ( 65535 -65535 -3040 ) ( -65535 -65535 -3040 ) wizmet1_8 -15 -0 180 1 1 -( 65535 -65535 -3360 ) ( 65535 65535 -3360 ) ( -65535 -65535 -3360 ) wizmet1_8 -15 0 180 1 1 -} -// brush 215 -{ -( 704 -63583 65535 ) ( 704 67487 65535 ) ( 704 67487 -65535 ) metal1_4 48 16 180 1 1 -( 128 67487 65535 ) ( 128 -63583 65535 ) ( 128 67487 -65535 ) metal1_4 48 16 180 1 1 -( 65663 1648 65535 ) ( -65407 1648 65535 ) ( -65407 1648 -65535 ) metal1_4 16 -48 -0 1 1 -( -65407 448 65535 ) ( 65663 448 65535 ) ( -65407 448 -65535 ) metal1_4 16 -48 -0 1 1 -( 65663 67487 -3408 ) ( 65663 -63583 -3408 ) ( -65407 -63583 -3408 ) city4_8 -16 32 -0 1 1 -( 65663 -63583 -3952 ) ( 65663 67487 -3952 ) ( -65407 -63583 -3952 ) metal1_4 16 48 -0 1 1 -} -// brush 216 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3208 ) ( 65359 67951 -3208 ) ( -65711 -63119 -3208 ) metal1_3 32 -0 -0 1 1 -} -// brush 217 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3216 ) ( 65359 -63119 -3216 ) ( -65711 -63119 -3216 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3224 ) ( 65359 67951 -3224 ) ( -65711 -63119 -3224 ) metal1_3 32 -0 -0 1 1 -} -// brush 218 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3232 ) ( 65359 -63119 -3232 ) ( -65711 -63119 -3232 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3240 ) ( 65359 67951 -3240 ) ( -65711 -63119 -3240 ) metal1_3 32 -0 -0 1 1 -} -// brush 219 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3248 ) ( 65359 -63119 -3248 ) ( -65711 -63119 -3248 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3256 ) ( 65359 67951 -3256 ) ( -65711 -63119 -3256 ) metal1_3 32 -0 -0 1 1 -} -// brush 220 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3264 ) ( 65359 -63119 -3264 ) ( -65711 -63119 -3264 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3272 ) ( 65359 67951 -3272 ) ( -65711 -63119 -3272 ) metal1_3 32 -0 -0 1 1 -} -// brush 221 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3280 ) ( 65359 -63119 -3280 ) ( -65711 -63119 -3280 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3288 ) ( 65359 67951 -3288 ) ( -65711 -63119 -3288 ) metal1_3 32 -0 -0 1 1 -} -// brush 222 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3296 ) ( 65359 -63119 -3296 ) ( -65711 -63119 -3296 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3304 ) ( 65359 67951 -3304 ) ( -65711 -63119 -3304 ) metal1_3 32 -0 -0 1 1 -} -// brush 223 -{ -( 2752 -63119 65535 ) ( 2752 67951 65535 ) ( 2752 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 2648 67951 65535 ) ( 2648 -63119 65535 ) ( 2648 67951 -65535 ) metal1_3 32 -48 180 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3312 ) ( 65359 -63119 -3312 ) ( -65711 -63119 -3312 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3320 ) ( 65359 67951 -3320 ) ( -65711 -63119 -3320 ) metal1_3 32 -0 -0 1 1 -} -// brush 224 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 32 -0 180 1 1 -( 52917 -63119 -38432 ) ( 52917 67951 -38432 ) ( -54459 -63119 36731 ) city4_7 32 48 -0 1 1 -( 65359 560 65535 ) ( -65711 560 65535 ) ( -65711 560 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3450.9930803904022 ) ( 65359 67951 -3450.9930803904022 ) ( -65711 -63119 -3450.9930803904022 ) city4_7 32 48 -0 1 1 -} -// brush 225 -{ -( 64 1680 -3968 ) ( 64 1792 -3952 ) ( 64 1792 -3968 ) metal1_4 -0 -48 -0 1 1 -( -240 1680 -3968 ) ( -240 1792 -3952 ) ( -240 1680 -3952 ) metal1_4 -0 -48 -0 1 1 -( -112 1952 -3968 ) ( 32 1952 -3952 ) ( -112 1952 -3952 ) metal1_4 -16 -48 -0 1 1 -( -112 1664 -3968 ) ( 32 1664 -3952 ) ( 32 1664 -3968 ) metal1_4 -16 -48 -0 1 1 -( -112 1680 -3952 ) ( 32 1792 -3952 ) ( 32 1680 -3952 ) metal1_4 -16 -0 -0 1 1 -( -112 1680 -3968 ) ( 32 1792 -3968 ) ( -112 1792 -3968 ) metal1_4 -16 -0 -0 1 1 -} -// brush 226 -{ -( 272 1664 -3088 ) ( 272 1712 -3072 ) ( 272 1712 -3088 ) wiz1_4 -32 -0 -0 1 1 -( -224 1664 -3088 ) ( -224 1712 -3072 ) ( -224 1664 -3072 ) wiz1_4 -32 -0 -0 1 1 -( -224 1664 -3088 ) ( -192 1664 -3072 ) ( -224 1664 -3072 ) wiz1_4 16 -0 -0 1 1 -( -224 1648 -3088 ) ( -192 1648 -3072 ) ( -192 1648 -3088 ) wiz1_4 16 -0 -0 1 1 -( -224 1664 -2864 ) ( -192 1712 -2864 ) ( -192 1664 -2864 ) wiz1_4 16 32 -0 1 1 -( -224 1664 -3792 ) ( -192 1712 -3792 ) ( -224 1712 -3792 ) wiz1_4 16 32 -0 1 1 -} -// brush 227 -{ -( -736 1632 -3344 ) ( -736 1664 -3328 ) ( -736 1664 -3344 ) city4_5 0 0 0 1 1 -( -880 1632 -3344 ) ( -880 1664 -3328 ) ( -880 1632 -3328 ) city4_5 -0 -0 -0 1 1 -( -784 1664 -3344 ) ( -736 1664 -3328 ) ( -784 1664 -3328 ) city4_5 0 0 0 1 1 -( -784 1648 -3344 ) ( -736 1648 -3328 ) ( -736 1648 -3344 ) city4_5 -0 -0 -0 1 1 -( -784 1632 -3072 ) ( -736 1664 -3072 ) ( -736 1632 -3072 ) city4_5 -0 -0 -0 1 1 -( -784 1632 -3408 ) ( -736 1664 -3408 ) ( -784 1664 -3408 ) city4_5 -0 -0 -0 1 1 -} -// brush 228 -{ -( -304 -65535 65535 ) ( -304 65535 65535 ) ( -304 65535 -65535 ) metal1_4 0 0 180 1 1 -( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) metal1_4 0 0 180 1 1 -( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) metal1_4 0 0 90 1 1 -( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 0 0 90 1 1 -( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 0 0 270 1 1 -} -// brush 229 -{ -( -208 -65535 65535 ) ( -208 65535 65535 ) ( -208 65535 -65535 ) city4_5 0 0 180 1 1 -( -448 65535 65535 ) ( -448 -65535 65535 ) ( -448 65535 -65535 ) city4_5 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 -( -65535 432 65535 ) ( 65535 432 65535 ) ( -65535 432 -65535 ) city4_5 0 0 90 1 1 -( 65535 65535 -3408 ) ( 65535 -65535 -3408 ) ( -65535 -65535 -3408 ) city4_8 -15 0 180 1 1 -( 65535 -65535 -3936 ) ( 65535 65535 -3936 ) ( -65535 -65535 -3936 ) city4_5 0 0 270 1 1 -} -// brush 230 -{ -( -448 -64335 65535 ) ( -448 66735 65535 ) ( -448 66735 -65535 ) wiz1_4 48 -0 180 1 1 -( -736 66735 65535 ) ( -736 -64335 65535 ) ( -736 66735 -65535 ) city4_5 -0 -0 -0 1 1 -( 65535 1664 65535 ) ( -65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 16 -0 -0 1 1 -( -65535 1648 65535 ) ( 65535 1648 65535 ) ( -65535 1648 -65535 ) city4_5 -16 -0 180 1 1 -( 65535 66735 -2864 ) ( 65535 -64335 -2864 ) ( -65535 -64335 -2864 ) city4_5 -0 -0 90 1 1 -( 65535 -64335 -3408 ) ( 65535 66735 -3408 ) ( -65535 -64335 -3408 ) city4_5 -0 -0 90 1 1 -} -// brush 231 -{ -( 48 448 -3088 ) ( 48 496 -3072 ) ( 48 496 -3088 ) wiz1_4 -32 -0 -0 1 1 -( -448 448 -3088 ) ( -448 496 -3072 ) ( -448 448 -3072 ) wiz1_4 -32 -0 -0 1 1 -( -448 464 -3088 ) ( -416 464 -3072 ) ( -448 464 -3072 ) wiz1_4 48 -0 -0 1 1 -( -448 432 -3088 ) ( -416 432 -3072 ) ( -416 432 -3088 ) wiz1_4 48 -0 -0 1 1 -( -448 448 -2864 ) ( -416 496 -2864 ) ( -416 448 -2864 ) wiz1_4 48 32 -0 1 1 -( -448 448 -3792 ) ( -416 496 -3792 ) ( -448 496 -3792 ) wiz1_4 48 32 -0 1 1 -} -// brush 232 -{ -( 544 1616 -3808 ) ( 544 1664 -3792 ) ( 544 1664 -3808 ) wiz1_4 0 0 0 1 1 -( 448 1616 -3808 ) ( 448 1664 -3792 ) ( 448 1616 -3792 ) wiz1_4 -0 -0 -0 1 1 -( 464 1664 -3808 ) ( 544 1664 -3792 ) ( 464 1664 -3792 ) wiz1_4 0 0 0 1 1 -( 464 1648 -3808 ) ( 544 1648 -3792 ) ( 544 1648 -3808 ) wiz1_4 -0 -0 -0 1 1 -( 464 1616 -3792 ) ( 544 1664 -3792 ) ( 544 1616 -3792 ) wiz1_4 0 0 0 1 1 -( 464 1616 -3952 ) ( 544 1664 -3952 ) ( 464 1664 -3952 ) wiz1_4 -0 -0 -0 1 1 -} -// brush 233 -{ -( -208 416 -3808 ) ( -208 464 -3792 ) ( -208 464 -3808 ) wiz1_4 48 -0 -0 1 1 -( -304 416 -3808 ) ( -304 464 -3792 ) ( -304 416 -3792 ) wiz1_4 48 -0 -0 1 1 -( -288 464 -3808 ) ( -208 464 -3792 ) ( -288 464 -3792 ) wiz1_4 48 -0 -0 1 1 -( -288 448 -3808 ) ( -208 448 -3792 ) ( -208 448 -3808 ) wiz1_4 48 -0 -0 1 1 -( -288 416 -3792 ) ( -208 464 -3792 ) ( -208 416 -3792 ) wiz1_4 48 -48 -0 1 1 -( -288 416 -3952 ) ( -208 464 -3952 ) ( -288 464 -3952 ) wiz1_4 48 -48 -0 1 1 -} -// brush 234 -{ -( 64 384 -3968 ) ( 64 432 -3952 ) ( 64 432 -3968 ) city4_5 -16 -16 -0 1 1 -( 48 384 -3968 ) ( 48 432 -3952 ) ( 48 384 -3952 ) city4_5 -16 -16 -0 1 1 -( 48 432 -3968 ) ( 80 432 -3952 ) ( 48 432 -3952 ) city4_5 -0 -16 -0 1 1 -( 48 160 -3968 ) ( 80 160 -3952 ) ( 80 160 -3968 ) city4_5 -0 -16 -0 1 1 -( 48 384 -3744 ) ( 80 432 -3744 ) ( 80 384 -3744 ) city4_5 -0 16 -0 1 1 -( 48 384 -3968 ) ( 80 432 -3968 ) ( 48 432 -3968 ) city4_5 -0 16 -0 1 1 -} -// brush 235 -{ -( 64 144 -3744 ) ( 64 176 -3728 ) ( 64 176 -3744 ) metal1_4 -0 -0 -0 1 1 -( -208 144 -3744 ) ( -208 176 -3728 ) ( -208 144 -3728 ) metal1_4 -0 -0 -0 1 1 -( -208 432 -3744 ) ( -192 432 -3728 ) ( -208 432 -3728 ) metal1_4 16 -0 -0 1 1 -( -208 144 -3744 ) ( -192 144 -3728 ) ( -192 144 -3744 ) metal1_4 16 -0 -0 1 1 -( -208 144 -3728 ) ( -192 176 -3728 ) ( -192 144 -3728 ) metal1_4 16 -0 -0 1 1 -( -208 144 -3744 ) ( -192 176 -3744 ) ( -208 176 -3744 ) metal1_4 16 -0 -0 1 1 -} -// brush 236 -{ -( 48 160 -3952 ) ( 48 208 -3936 ) ( 48 208 -3952 ) *water2 -16 -0 -0 1 1 -( -848 160 -3952 ) ( -848 208 -3936 ) ( -848 160 -3936 ) *water2 -16 -0 -0 1 1 -( -208 432 -3952 ) ( -160 432 -3936 ) ( -208 432 -3936 ) *water2 32 -0 -0 1 1 -( -208 160 -3952 ) ( -160 160 -3936 ) ( -160 160 -3952 ) *water2 32 -0 -0 1 1 -( -208 160 -3744 ) ( -160 208 -3744 ) ( -160 160 -3744 ) *water2 32 16 -0 1 1 -( -208 160 -3952 ) ( -160 208 -3952 ) ( -208 208 -3952 ) *water2 32 16 -0 1 1 -} -// brush 237 -{ -( 976 1648 -2880 ) ( 976 1664 -2864 ) ( 976 1664 -2880 ) city4_7 -0 -0 -0 1 1 -( 688 1648 -2880 ) ( 688 1664 -2864 ) ( 688 1648 -2864 ) city4_7 0 0 0 1 1 -( 688 1664 -2880 ) ( 720 1664 -2864 ) ( 688 1664 -2864 ) city4_7 0 0 0 1 1 -( 688 1648 -2880 ) ( 720 1648 -2864 ) ( 720 1648 -2880 ) city4_7 0 0 0 1 1 -( 688 1648 -2864 ) ( 720 1664 -2864 ) ( 720 1648 -2864 ) city4_7 0 0 0 1 1 -( 688 1648 -2880 ) ( 720 1664 -2880 ) ( 688 1664 -2880 ) city4_7 0 0 0 1 1 -} -// brush 238 -{ -( 128 1568 -3936 ) ( 128 1648 -3920 ) ( 128 1648 -3936 ) *water2 -0 -0 -0 1 1 -( -304 1568 -3936 ) ( -304 1648 -3920 ) ( -304 1568 -3920 ) *water2 -0 -0 -0 1 1 -( 400 1648 -3936 ) ( 544 1648 -3920 ) ( 400 1648 -3920 ) *water2 -0 -0 -0 1 1 -( 400 464 -3936 ) ( 544 464 -3920 ) ( 544 464 -3936 ) *water2 -0 -0 -0 1 1 -( 400 1568 -3584 ) ( 544 1648 -3584 ) ( 544 1568 -3584 ) *water2 -0 -0 -0 1 1 -( 400 1568 -3952 ) ( 544 1648 -3952 ) ( 400 1648 -3952 ) *water2 -0 -0 -0 1 1 -} -// brush 239 -{ -( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) city4_7 32 -0 180 1 1 -( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) city4_7 32 48 -0 1 1 -} -// brush 240 -{ -( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 63061 67951 17527 ) ( 63061 -63119 17527 ) ( -61282 -63119 -23920 ) sfloor4_6 32 -0 -0 1 1 -( 65359 1248 65535 ) ( -65711 1248 65535 ) ( -65711 1248 -65535 ) sfloor4_6 32 -0 -0 1 1 -( -65711 880 65535 ) ( 65359 880 65535 ) ( -65711 880 -65535 ) sfloor4_6 32 -0 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3408 ) ( 65359 67951 -3408 ) ( -65711 -63119 -3408 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 241 -{ -( -736 928 -2864 ) ( -736 1024 -2848 ) ( -736 1024 -2864 ) sky1 -0 -0 -0 1 1 -( -752 928 -2864 ) ( -752 1024 -2848 ) ( -752 928 -2848 ) sky1 -0 -0 -0 1 1 -( -752 1664 -2864 ) ( -736 1664 -2848 ) ( -752 1664 -2848 ) sky1 192 -0 -0 1 1 -( -752 448 -2864 ) ( -736 448 -2848 ) ( -736 448 -2864 ) sky1 192 -0 -0 1 1 -( -752 928 -2576 ) ( -736 1024 -2576 ) ( -736 928 -2576 ) sky1 192 -0 -0 1 1 -( -752 928 -2864 ) ( -736 1024 -2864 ) ( -752 1024 -2864 ) sky1 192 -0 -0 1 1 -} -// brush 242 -{ -( 976 448 -2864 ) ( 976 464 -2848 ) ( 976 464 -2864 ) sky1 -0 -0 -0 1 1 -( -736 448 -2864 ) ( -736 464 -2848 ) ( -736 448 -2848 ) sky1 -0 -0 -0 1 1 -( 688 464 -2864 ) ( 912 464 -2848 ) ( 688 464 -2848 ) sky1 0 0 0 1 1 -( 688 448 -2864 ) ( 912 448 -2848 ) ( 912 448 -2864 ) sky1 0 0 0 1 1 -( 688 448 -2576 ) ( 912 464 -2576 ) ( 912 448 -2576 ) sky1 -0 -0 -0 1 1 -( 688 448 -2864 ) ( 912 464 -2864 ) ( 688 464 -2864 ) sky1 0 0 0 1 1 -} -// brush 243 -{ -( 976 1648 -2864 ) ( 976 1664 -2848 ) ( 976 1664 -2864 ) sky1 -176 -0 -0 1 1 -( -736 1648 -2864 ) ( -736 1664 -2848 ) ( -736 1648 -2848 ) sky1 -176 -0 -0 1 1 -( 688 1664 -2864 ) ( 912 1664 -2848 ) ( 688 1664 -2848 ) sky1 -0 -0 -0 1 1 -( 688 1648 -2864 ) ( 912 1648 -2848 ) ( 912 1648 -2864 ) sky1 -0 -0 -0 1 1 -( 688 1648 -2576 ) ( 912 1664 -2576 ) ( 912 1648 -2576 ) sky1 -0 48 -0 1 1 -( 688 1648 -2864 ) ( 912 1664 -2864 ) ( 688 1664 -2864 ) sky1 -0 48 -0 1 1 -} -// brush 244 -{ -( 576 -65311 65663 ) ( 576 65759 65663 ) ( 576 65759 -65407 ) sky1 224 -0 180 1 1 -( -752 65759 65663 ) ( -752 -65311 65663 ) ( -752 65759 -65407 ) sky1 224 -0 180 1 1 -( 67007 1664 65663 ) ( -64063 1664 65663 ) ( -64063 1664 -65407 ) sky1 128 -64 90 1 1 -( -64063 448 65663 ) ( 67007 448 65663 ) ( -64063 448 -65407 ) sky1 128 -64 90 1 1 -( 67007 65759 -2576 ) ( 67007 -65311 -2576 ) ( -64063 -65311 -2576 ) sky1 224 64 270 1 1 -( 67007 -65311 -2592 ) ( 67007 65759 -2592 ) ( -64063 -65311 -2592 ) sky1 224 64 270 1 1 -} -// brush 245 -{ -( 3344 -63119 65535 ) ( 3344 67951 65535 ) ( 3344 67951 -65535 ) city4_7 -32 -0 180 1 1 -( 3328 67951 65535 ) ( 3328 -63119 65535 ) ( 3328 67951 -65535 ) city4_7 -32 -0 180 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) city4_7 32 -16 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) city4_7 32 -16 -0 1 1 -} -// brush 246 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 1424 67951 65535 ) ( 1424 -63119 65535 ) ( 1424 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 65359 1696 65535 ) ( -65711 1696 65535 ) ( -65711 1696 -65535 ) metal5r8 32 -0 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal5r8 -0 -0 180 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal5r8 -0 48 90 1 1 -} -// brush 247 -{ -( 2960 -63119 65535 ) ( 2960 67951 65535 ) ( 2960 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 57854 -63118 -30703 ) ( 57854 67950 -30703 ) ( -59377 -63118 27912 ) metal1_4 48 -0 -0 1 1 -( 65471 2416 65535 ) ( -65599 2416 65535 ) ( -65599 2416 -65535 ) metal1_4 48 -48 -0 1 1 -( -65599 2256 65535 ) ( 65471 2256 65535 ) ( -65599 2256 -65535 ) metal1_4 48 -48 -0 1 1 -( 65471 67951 -3136 ) ( 65471 -63119 -3136 ) ( -65599 -63119 -3136 ) metal1_4 48 -0 -0 1 1 -( 65471 -63119 -3200 ) ( 65471 67951 -3200 ) ( -65599 -63119 -3200 ) metal1_4 48 -0 -0 1 1 -} -// brush 248 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 1904 67951 65535 ) ( 1904 -63119 65535 ) ( 1904 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal1_4 32 -16 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 -} -// brush 249 -{ -( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal1_4 48 -0 -0 1 1 -( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -16 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 -} -// brush 250 -{ -( -46580 -63119 46276 ) ( -46580 67951 46276 ) ( 46100 67951 -46404 ) sfloor4_6 32 -0 -0 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 251 -{ -( 3200 -63119 65535 ) ( 3200 67951 65535 ) ( 3200 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 252 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 -( 3200 67951 65535 ) ( 3200 -63119 65535 ) ( 3200 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 253 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) rock5_2 -96 -48 180 1 1 -( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) rock5_2 -96 -48 180 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) rock5_2 96 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -48 -0 1 1 -( 65359 67951 -3632 ) ( 65359 -63119 -3632 ) ( -65711 -63119 -3632 ) rock5_2 96 -64 -0 1 1 -( 65359 -63119 -3648 ) ( 65359 67951 -3648 ) ( -65711 -63119 -3648 ) rock5_2 96 -64 -0 1 1 -} -// brush 254 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) *lava1 -32 -48 180 1 1 -( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) *lava1 -32 -48 180 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) *lava1 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) *lava1 32 -48 -0 1 1 -( 65359 67951 -3520 ) ( 65359 -63119 -3520 ) ( -65711 -63119 -3520 ) *lava1 32 -0 -0 1 1 -( 65359 -63119 -3632 ) ( 65359 67951 -3632 ) ( -65711 -63119 -3632 ) *lava1 32 -0 -0 1 1 -} -// brush 255 -{ -( 2864 -63119 65535 ) ( 2864 67951 65535 ) ( 2864 67951 -65535 ) rock5_2 -96 -48 180 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) rock5_2 96 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -48 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) rock5_2 96 -64 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) rock5_2 96 -64 -0 1 1 -} -// brush 256 -{ -( 160 -63135 65519 ) ( 160 67935 65519 ) ( 160 67935 -65551 ) metal1_4 -0 16 180 1 1 -( 48 67935 65519 ) ( 48 -63135 65519 ) ( 48 67935 -65551 ) city4_7 -0 -16 -0 1 1 -( 65375 1808 65519 ) ( -65695 1808 65519 ) ( -65695 1808 -65551 ) metal1_4 -0 -16 -0 1 1 -( -65695 1664 65519 ) ( 65375 1664 65519 ) ( -65695 1664 -65551 ) metal1_4 -0 -16 -0 1 1 -( 65375 67935 -3776 ) ( 65375 -63135 -3776 ) ( -65695 -63135 -3776 ) metal1_4 -0 -32 -0 1 1 -( 65375 -63135 -3968 ) ( 65375 67935 -3968 ) ( -65695 -63135 -3968 ) metal1_4 -0 -32 -0 1 1 -} -// brush 257 -{ -( 3840 -63119 65535 ) ( 3840 67951 65535 ) ( 3840 67951 -65535 ) rock5_2 -96 -48 180 1 1 -( 1185 67951 65535 ) ( 1185 -63119 65535 ) ( 1185 67951 -65535 ) rock5_2 -96 -48 180 1 1 -( 65343 2192 65535 ) ( -65727 2192 65535 ) ( -65727 2192 -65535 ) rock5_2 112 -48 -0 1 1 -( -65727 1664 65535 ) ( 65343 1664 65535 ) ( -65727 1664 -65535 ) rock5_2 112 -48 -0 1 1 -( 65343 67951 -2864 ) ( 65343 -63119 -2864 ) ( -65727 -63119 -2864 ) rock5_2 112 -64 -0 1 1 -( 65343 -63119 -2880 ) ( 65343 67951 -2880 ) ( -65727 -63119 -2880 ) rock5_2 112 -64 -0 1 1 -} -// brush 258 -{ -( 56054 65535 -34151 ) ( 56054 -65535 -34151 ) ( -59539 -65535 27631 ) metal1_4 -15 0 180 1 1 -( -704 65535 65535 ) ( -704 -65535 65535 ) ( -704 65535 -65535 ) metal1_4 -32 -0 90 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal1_4 -32 0 180 1 1 -( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) metal1_4 -32 0 180 1 1 -( 65535 65535 -3936 ) ( 65535 -65535 -3936 ) ( -65535 -65535 -3936 ) metal1_4 -32 0 180 1 1 -( 65535 -65535 -3952 ) ( 65535 65535 -3952 ) ( -65535 -65535 -3952 ) metal1_4 -32 0 180 1 1 -} -// brush 259 -{ -( 48 432 -3952 ) ( 48 464 -3936 ) ( 48 464 -3952 ) *water2 -0 -0 -0 1 1 -( -208 432 -3952 ) ( -208 464 -3936 ) ( -208 432 -3936 ) *water2 0 0 0 1 1 -( -208 464 -3952 ) ( -192 464 -3936 ) ( -208 464 -3936 ) *water2 0 0 0 1 1 -( -208 432 -3952 ) ( -192 432 -3936 ) ( -192 432 -3952 ) *water2 0 0 0 1 1 -( -208 432 -3792 ) ( -192 464 -3792 ) ( -192 432 -3792 ) *water2 -0 -0 -0 1 1 -( -208 432 -3952 ) ( -192 464 -3952 ) ( -208 464 -3952 ) *water2 0 0 0 1 1 -} -// brush 260 -{ -( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) city4_5 0 0 180 1 1 -( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) city4_5 -0 -0 180 1 1 -( 65535 1680 65535 ) ( -65535 1680 65535 ) ( -65535 1680 -65535 ) city4_5 0 0 90 1 1 -( -65535 1664 65535 ) ( 65535 1664 65535 ) ( -65535 1664 -65535 ) city4_5 -16 0 180 1 1 -( 65535 65535 -2864 ) ( 65535 -65535 -2864 ) ( -65535 -65535 -2864 ) city4_5 0 0 270 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) city4_5 -0 -0 270 1 1 -} -// brush 261 -{ -( -224 1968 -3968 ) ( -224 1984 -3952 ) ( -224 1984 -3968 ) city4_7 16 16 -0 1 1 -( -240 1968 -3968 ) ( -240 1984 -3952 ) ( -240 1968 -3952 ) city4_7 16 16 -0 1 1 -( -336 1968 -3968 ) ( -224 1968 -3952 ) ( -336 1968 -3952 ) city4_7 32 16 -0 1 1 -( -336 1680 -3968 ) ( -224 1680 -3952 ) ( -224 1680 -3968 ) city4_7 32 16 -0 1 1 -( -336 1968 -3776 ) ( -224 1984 -3776 ) ( -224 1968 -3776 ) city4_7 32 -16 -0 1 1 -( -336 1968 -3968 ) ( -224 1984 -3968 ) ( -336 1984 -3968 ) city4_7 32 -16 -0 1 1 -} -// brush 262 -{ -( 64 1952 -3968 ) ( 64 1968 -3952 ) ( 64 1968 -3968 ) city4_7 32 -48 -0 1 1 -( -224 1952 -3968 ) ( -224 1968 -3952 ) ( -224 1952 -3952 ) city4_7 32 -48 -0 1 1 -( -48 1968 -3968 ) ( 64 1968 -3952 ) ( -48 1968 -3952 ) city4_7 -0 -48 -0 1 1 -( -48 1952 -3968 ) ( 64 1952 -3952 ) ( 64 1952 -3968 ) city4_7 -0 -48 -0 1 1 -( -48 1952 -3776 ) ( 64 1968 -3776 ) ( 64 1952 -3776 ) city4_7 -0 -32 -0 1 1 -( -48 1952 -3968 ) ( 64 1968 -3968 ) ( -48 1968 -3968 ) city4_7 -0 -32 -0 1 1 -} -// brush 263 -{ -( 48 1728 -3952 ) ( 48 1808 -3936 ) ( 48 1808 -3952 ) *water2 -0 -0 -0 1 1 -( -224 1728 -3952 ) ( -224 1808 -3936 ) ( -224 1728 -3936 ) *water2 -0 -0 -0 1 1 -( -224 1808 -3952 ) ( -160 1808 -3936 ) ( -224 1808 -3936 ) *water2 16 -0 -0 1 1 -( -224 1648 -3952 ) ( -160 1648 -3936 ) ( -160 1648 -3952 ) *water2 16 -0 -0 1 1 -( -224 1728 -3792 ) ( -160 1808 -3792 ) ( -160 1728 -3792 ) *water2 16 -0 -0 1 1 -( -224 1728 -3952 ) ( -160 1808 -3952 ) ( -224 1808 -3952 ) *water2 16 -0 -0 1 1 -} -// brush 264 -{ -( 640 1824 -3952 ) ( 640 1856 -3936 ) ( 640 1856 -3952 ) *water2 -0 -0 -0 1 1 -( -224 1824 -3952 ) ( -224 1856 -3936 ) ( -224 1824 -3936 ) *water2 -0 -0 -0 1 1 -( -144 1952 -3952 ) ( -32 1952 -3936 ) ( -144 1952 -3936 ) *water2 -0 -0 -0 1 1 -( -144 1808 -3952 ) ( -32 1808 -3936 ) ( -32 1808 -3952 ) *water2 -0 -0 -0 1 1 -( -144 1824 -3792 ) ( -32 1856 -3792 ) ( -32 1824 -3792 ) *water2 -0 -0 -0 1 1 -( -144 1824 -3952 ) ( -32 1856 -3952 ) ( -144 1856 -3952 ) *water2 -0 -0 -0 1 1 -} -// brush 265 -{ -( 64 1680 -3792 ) ( 64 1792 -3776 ) ( 64 1792 -3792 ) metal1_4 -0 -0 -0 1 1 -( -240 1680 -3792 ) ( -240 1792 -3776 ) ( -240 1680 -3776 ) metal1_4 -0 -0 -0 1 1 -( -112 1952 -3792 ) ( 32 1952 -3776 ) ( -112 1952 -3776 ) metal1_4 48 -0 -0 1 1 -( -112 1664 -3792 ) ( 32 1664 -3776 ) ( 32 1664 -3792 ) metal1_4 48 -0 -0 1 1 -( -112 1680 -3776 ) ( 32 1792 -3776 ) ( 32 1680 -3776 ) metal1_4 48 -0 -0 1 1 -( -112 1680 -3792 ) ( 32 1792 -3792 ) ( -112 1792 -3792 ) metal1_4 48 -0 -0 1 1 -} -// brush 266 -{ -( 59481 -63119 27471 ) ( 59481 67951 27471 ) ( -56113 -63119 -34311 ) metal1_4 16 -16 -0 1 1 -( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65391 2032 65535 ) ( -65679 2032 65535 ) ( -65679 2032 -65535 ) metal1_4 16 -0 -0 1 1 -( -65679 1968 65535 ) ( 65391 1968 65535 ) ( -65679 1968 -65535 ) metal1_4 16 -0 -0 1 1 -( 65391 67951 -3936 ) ( 65391 -63119 -3936 ) ( -65679 -63119 -3936 ) metal1_4 16 -16 -0 1 1 -( 65391 -63119 -4000 ) ( 65391 67951 -4000 ) ( -65679 -63119 -4000 ) metal1_4 16 -16 -0 1 1 -} -// brush 267 -{ -( 448 -63119 65535 ) ( 448 67951 65535 ) ( 448 67951 -65535 ) city4_8 -32 -0 180 1 1 -( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65391 1968 65535 ) ( -65679 1968 65535 ) ( -65679 1968 -65535 ) city4_8 -0 -0 -0 1 1 -( -65679 1952 65535 ) ( 65391 1952 65535 ) ( -65679 1952 -65535 ) metal1_4 -0 -0 -0 1 1 -( 65391 67951 -3776 ) ( 65391 -63119 -3776 ) ( -65679 -63119 -3776 ) city4_8 -0 -16 -0 1 1 -( 65391 -63119 -3952 ) ( 65391 67951 -3952 ) ( -65679 -63119 -3952 ) city4_8 -0 -16 -0 1 1 -} -// brush 268 -{ -( 272 -63119 65535 ) ( 272 67951 65535 ) ( 272 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 56971 -63118 -32245 ) ( 56971 67950 -32245 ) ( -60261 -63118 26370 ) metal1_4 32 -0 -0 1 1 -( 65359 1952 65535 ) ( -65711 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 1808 65535 ) ( 65359 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3776 ) ( 65359 -63119 -3776 ) ( -65711 -63119 -3776 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3856 ) ( 65359 67951 -3856 ) ( -65711 -63119 -3856 ) metal1_4 32 -0 -0 1 1 -} -// brush 269 -{ -( 304 -63119 65535 ) ( 304 67951 65535 ) ( 304 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 160 67951 65535 ) ( 160 -63119 65535 ) ( 160 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 65391 1808 65535 ) ( -65679 1808 65535 ) ( -65679 1808 -65535 ) metal1_4 -0 -0 -0 1 1 -( -65679 1648 65535 ) ( 65391 1648 65535 ) ( -65679 1648 -65535 ) metal1_4 -32 -0 180 1 1 -( 65391 67951 -3776 ) ( 65391 -63119 -3776 ) ( -65679 -63119 -3776 ) metal1_4 -0 16 90 1 1 -( 65391 -63119 -3952 ) ( 65391 67951 -3952 ) ( -65679 -63119 -3952 ) metal1_4 -0 16 90 1 1 -} -// brush 270 -{ -( 59481 -63119 27471 ) ( 59481 67951 27471 ) ( -56113 -63119 -34311 ) metal1_4 48 -16 -0 1 1 -( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 48 -0 -0 1 1 -( 65391 1952 65535 ) ( -65679 1952 65535 ) ( -65679 1952 -65535 ) metal1_4 48 -0 -0 1 1 -( -65679 1664 65535 ) ( 65391 1664 65535 ) ( -65679 1664 -65535 ) metal1_4 48 -0 -0 1 1 -( 65391 67951 -3952 ) ( 65391 -63119 -3952 ) ( -65679 -63119 -3952 ) metal1_4 -0 -0 -0 1 1 -( 65391 -63119 -4000 ) ( 65391 67951 -4000 ) ( -65679 -63119 -4000 ) metal1_4 48 -16 -0 1 1 -} -// brush 271 -{ -( 59481 -63119 27471 ) ( 59481 67951 27471 ) ( -56113 -63119 -34311 ) metal1_4 -0 -16 -0 1 1 -( 64 67951 65535 ) ( 64 -63119 65535 ) ( 64 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65391 1968 65535 ) ( -65679 1968 65535 ) ( -65679 1968 -65535 ) metal1_4 -0 -0 -0 1 1 -( -65679 1952 65535 ) ( 65391 1952 65535 ) ( -65679 1952 -65535 ) metal1_4 -0 -0 -0 1 1 -( 65391 67951 -3936 ) ( 65391 -63119 -3936 ) ( -65679 -63119 -3936 ) metal1_4 -0 -16 -0 1 1 -( 65391 -63119 -4000 ) ( 65391 67951 -4000 ) ( -65679 -63119 -4000 ) metal1_4 -0 -16 -0 1 1 -} -// brush 272 -{ -( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -0 -0 1 1 -( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 59363 67951 27631 ) ( 59363 -63119 27631 ) ( -56230 -63119 -34151 ) metal1_4 32 -0 -0 1 1 -( 65359 1952 65535 ) ( -65711 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 1808 65535 ) ( 65359 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 -63119 -3952 ) ( 65359 67951 -3952 ) ( -65711 -63119 -3952 ) metal1_4 32 -0 -0 1 1 -} -// brush 273 -{ -( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -16 -0 1 1 -( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 416 67951 65535 ) ( 416 -63119 65535 ) ( 416 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 1952 65535 ) ( 65359 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -0 -0 1 1 -( 65359 67951 -3360 ) ( 65359 -63119 -3360 ) ( -65711 -63119 -3360 ) metal1_4 32 -16 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -16 -0 1 1 -} -// brush 274 -{ -( 59323 -63119 27706 ) ( 59323 67951 27706 ) ( -56270 -63119 -34077 ) metal1_4 32 -0 -0 1 1 -( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 272 67951 65535 ) ( 272 -63119 65535 ) ( 272 67951 -65535 ) wiz1_4 -0 -0 -0 1 1 -( 65359 1952 65535 ) ( -65711 1952 65535 ) ( -65711 1952 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 1808 65535 ) ( 65359 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3360 ) ( 65359 -63119 -3360 ) ( -65711 -63119 -3360 ) mmetal1_8 -63 16 180 1 1 -} -// brush 275 -{ -( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -16 -0 1 1 -( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 272 67951 65535 ) ( 272 -63119 65535 ) ( 272 67951 -65535 ) wiz1_4 -0 -0 -0 1 1 -( 65359 1808 65535 ) ( -65711 1808 65535 ) ( -65711 1808 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) mmetal1_8 -63 16 180 1 1 -( 65359 -63119 -3952.3362112220393 ) ( 65359 67951 -3952.3362112220393 ) ( -65711 -63119 -3952.3362112220393 ) metal1_4 32 -16 -0 1 1 -} -// brush 276 -{ -( 128 1648 -3952 ) ( 128 1664 -3936 ) ( 128 1664 -3952 ) wiz1_4 0 0 0 1 1 -( 48 1648 -3952 ) ( 48 1664 -3936 ) ( 48 1648 -3936 ) wiz1_4 0 0 0 1 1 -( 48 1664 -3952 ) ( 128 1664 -3936 ) ( 48 1664 -3936 ) wiz1_4 0 0 0 1 1 -( 48 1648 -3952 ) ( 128 1648 -3936 ) ( 128 1648 -3952 ) wiz1_4 0 0 0 1 1 -( 48 1648 -3792 ) ( 128 1664 -3792 ) ( 128 1648 -3792 ) wiz1_4 -0 -0 -0 1 1 -( 48 1648 -3952 ) ( 128 1664 -3952 ) ( 48 1664 -3952 ) wiz1_4 0 0 0 1 1 -} -// brush 277 -{ -( 560 -66751 65535 ) ( 560 64319 65535 ) ( 560 64319 -65535 ) wiz1_4 -16 -2 90 1 1 -( 48 64319 65535 ) ( 48 -66751 65535 ) ( 48 64319 -65535 ) wiz1_4 -16 -2 90 1 1 -( 66047 464 65535 ) ( -65023 464 65535 ) ( -65023 464 -65535 ) wiz1_4 -16 -2 180 1 1 -( -65023 432 65535 ) ( 66047 432 65535 ) ( -65023 432 -65535 ) wiz1_4 -16 -2 180 1 1 -( 66047 64319 -2864 ) ( 66047 -66751 -2864 ) ( -65023 -66751 -2864 ) wiz1_4 -15 -2 180 1 1 -( 66047 -66751 -4000 ) ( 66047 64319 -4000 ) ( -65023 -66751 -4000 ) wiz1_4 -16 -2 180 1 1 -} -// brush 278 -{ -( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1744 67951 65535 ) ( 1744 -63119 65535 ) ( 1744 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 -} -// brush 279 -{ -( 1648 -63119 65535 ) ( 1648 67951 65535 ) ( 1648 67951 -65535 ) city4_7 32 -48 180 1 1 -( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 280 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 -( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal5r8 32 -0 -0 1 1 -} -// brush 281 -{ -( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 1648 67951 65535 ) ( 1648 -63119 65535 ) ( 1648 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 282 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 32 -48 180 1 1 -( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 896 65535 ) ( 65359 896 65535 ) ( -65711 896 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 -} -// brush 283 -{ -( 2768 -63119 65535 ) ( 2768 67951 65535 ) ( 2768 67951 -65535 ) rock5_2 32 -0 180 1 1 -( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) rock5_2 32 -0 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) rock5_2 96 112 -0 1 1 -( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) rock5_2 96 112 -0 1 1 -} -// brush 284 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) rock5_2 32 -0 180 1 1 -( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) rock5_2 32 -0 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) rock5_2 96 -0 -0 1 1 -( 65359 67951 -3520 ) ( 65359 -63119 -3520 ) ( -65711 -63119 -3520 ) rock5_2 96 112 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) rock5_2 96 112 -0 1 1 -} -// brush 285 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) sfloor4_6 32 -0 180 1 1 -( 2768 67951 65535 ) ( 2768 -63119 65535 ) ( 2768 67951 -65535 ) sfloor4_6 32 -0 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 48 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) sfloor4_6 32 48 -0 1 1 -} -// brush 286 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) rock5_2 32 -0 180 1 1 -( 2768 67951 65535 ) ( 2768 -63119 65535 ) ( 2768 67951 -65535 ) rock5_2 32 -0 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 96 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) rock5_2 96 112 -0 1 1 -( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) rock5_2 96 112 -0 1 1 -} -// brush 287 -{ -( 52917 67951 -38432 ) ( 52917 -63119 -38432 ) ( -54459 -63119 36731 ) sfloor4_6 -0 -0 -0 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) sfloor4_6 -0 -48 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 -0 -48 -0 1 1 -( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) sfloor4_6 -0 -48 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 -0 -0 -0 1 1 -} -// brush 288 -{ -( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) city4_7 32 -16 -0 1 1 -( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city4_7 -32 -0 180 1 1 -( 65359 1792 65535 ) ( -65711 1792 65535 ) ( -65711 1792 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -16 -0 1 1 -} -// brush 289 -{ -( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) city6_8 32 -0 -0 1 1 -( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) city6_8 -32 -48 180 1 1 -( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city6_8 -32 -48 180 1 1 -( 65359 1969 65535 ) ( -65711 1969 65535 ) ( -65711 1969 -65535 ) city6_8 32 -48 -0 1 1 -( -65711 1792 65535 ) ( 65359 1792 65535 ) ( -65711 1792 -65535 ) city6_8 32 -48 -0 1 1 -( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -0 -0 1 1 -} -// brush 290 -{ -( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) rock5_2 -0 -0 180 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) rock5_2 -0 -0 180 1 1 -( 65359 67951 -3520 ) ( 65359 -63119 -3520 ) ( -65711 -63119 -3520 ) rock5_2 64 48 90 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) rock5_2 64 48 90 1 1 -} -// brush 291 -{ -( 59449 -63119 27471 ) ( 59449 67951 27471 ) ( -56145 -63119 -34311 ) metal1_4 32 -16 -0 1 1 -( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -16 -0 180 1 1 -( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal1_4 32 -16 -0 1 1 -} -// brush 292 -{ -( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city4_7 -32 -48 180 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 1792 65535 ) ( 65359 1792 65535 ) ( -65711 1792 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3360 ) ( 65359 67951 -3360 ) ( -65711 -63119 -3360 ) city4_7 32 -0 -0 1 1 -} -// brush 293 -{ -( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) city6_8 -0 -0 -0 1 1 -( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) city6_8 -32 -48 180 1 1 -( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) city6_8 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) city6_8 32 -48 -0 1 1 -( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -0 -0 1 1 -( 65359 -63119 -3472 ) ( 65359 67951 -3472 ) ( -65711 -63119 -3472 ) city6_8 32 -0 -0 1 1 -} -// brush 294 -{ -( 1568 -63119 65535 ) ( 1568 67951 65535 ) ( 1568 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal1_4 32 -16 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -16 -0 1 1 -} -// brush 295 -{ -( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -16 -0 180 1 1 -( 1184 67951 65535 ) ( 1184 -63119 65535 ) ( 1184 67951 -65535 ) city4_7 -16 -0 180 1 1 -( 65359 2176 65535 ) ( -65711 2176 65535 ) ( -65711 2176 -65535 ) city4_7 -0 48 90 1 1 -( -65711 1969 65535 ) ( 65359 1969 65535 ) ( -65711 1969 -65535 ) city4_7 -0 48 90 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -16 -48 270 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -16 -48 270 1 1 -} -// brush 296 -{ -( 1201 -63119 65535 ) ( 1201 67951 65535 ) ( 1201 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 1184 67951 65535 ) ( 1184 -63119 65535 ) ( 1184 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1969 65535 ) ( -65711 1969 65535 ) ( -65711 1969 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -16 -0 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -16 -0 1 1 -} -// brush 297 -{ -( 1424 -63119 65535 ) ( 1424 67951 65535 ) ( 1424 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2976 ) ( 65359 -63119 -2976 ) ( -65711 -63119 -2976 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 298 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) city4_7 32 -48 180 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -2976 ) ( 65359 67951 -2976 ) ( -65711 -63119 -2976 ) city4_7 32 -0 -0 1 1 -} -// brush 299 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) city4_7 32 -48 180 1 1 -( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) city4_7 32 -0 -0 1 1 -} -// brush 300 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1488 67951 65535 ) ( 1488 -63119 65535 ) ( 1488 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2976 ) ( 65359 -63119 -2976 ) ( -65711 -63119 -2976 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 301 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1488 67951 65535 ) ( 1488 -63119 65535 ) ( 1488 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 -} -// brush 302 -{ -( 2032 -63119 65535 ) ( 2032 67951 65535 ) ( 2032 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1712 67951 65535 ) ( 1712 -63119 65535 ) ( 1712 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 1504 65535 ) ( 65359 1504 65535 ) ( -65711 1504 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 303 -{ -( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) city6_8 -0 16 -0 1 1 -( 60241 67950 25704 ) ( 60241 -63118 25704 ) ( -56990 -63118 -32911 ) city6_8 32 -48 -0 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) city6_8 32 16 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) city6_8 32 -32 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -48 -0 1 1 -} -// brush 304 -{ -( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 1201 67951 65535 ) ( 1201 -63119 65535 ) ( 1201 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) rock5_2 -0 -0 180 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) rock5_2 -0 -0 180 1 1 -( 65359 67951 -3472 ) ( 65359 -63119 -3472 ) ( -65711 -63119 -3472 ) rock5_2 64 48 90 1 1 -( 65359 -63119 -3520 ) ( 65359 67951 -3520 ) ( -65711 -63119 -3520 ) rock5_2 64 48 90 1 1 -} -// brush 305 -{ -( -208 1664 -3968 ) ( -208 1680 -3952 ) ( -208 1680 -3968 ) metal1_4 0 0 0 1 1 -( -224 1664 -3968 ) ( -224 1680 -3952 ) ( -224 1664 -3952 ) metal1_4 0 0 0 1 1 -( -224 1680 -3968 ) ( -208 1680 -3952 ) ( -224 1680 -3952 ) metal1_4 0 0 0 1 1 -( -224 1664 -3968 ) ( -208 1664 -3952 ) ( -208 1664 -3968 ) metal1_4 0 0 0 1 1 -( -224 1664 -3952 ) ( -208 1680 -3952 ) ( -208 1664 -3952 ) metal1_4 0 0 0 1 1 -( -224 1664 -3968 ) ( -208 1680 -3968 ) ( -224 1680 -3968 ) metal1_4 0 0 0 1 1 -} -// brush 306 -{ -( 3488 -63119 65535 ) ( 3488 67951 65535 ) ( 3488 67951 -65535 ) *water2 32 -48 180 1 1 -( 52917 -63119 -38432 ) ( 52917 67951 -38432 ) ( -54459 -63119 36731 ) *water2 32 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) *water2 32 -48 -0 1 1 -( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) *water2 32 -48 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 -} -// brush 307 -{ -( 3872 1648 -2880 ) ( 3872 1664 -2864 ) ( 3872 1664 -2880 ) city4_7 -0 -0 -0 1 1 -( 3856 1648 -2880 ) ( 3856 1664 -2864 ) ( 3856 1648 -2864 ) city4_7 -0 -0 -0 1 1 -( 3856 1664 -2880 ) ( 3872 1664 -2864 ) ( 3856 1664 -2864 ) city4_7 32 -0 -0 1 1 -( 3856 464 -2880 ) ( 3872 464 -2864 ) ( 3872 464 -2880 ) city4_7 32 -0 -0 1 1 -( 3856 1648 -2864 ) ( 3872 1664 -2864 ) ( 3872 1648 -2864 ) city4_7 32 -0 -0 1 1 -( 3856 1648 -3456 ) ( 3872 1664 -3456 ) ( 3856 1664 -3456 ) city4_7 32 -0 -0 1 1 -} -// brush 308 -{ -( 3583.4505200993262 949 -3138.9172473249582 ) ( 3856 672 -3055.9193792414385 ) ( 3584 944.44800098396217 -3120.3757850958596 ) metal5r8 26.6304 39.1252 180 1 1 -( 3856 672 -3071.9768577734121 ) ( 3856 672 -3055.9193792414385 ) ( 3583.4505200993262 949 -3138.9172473249582 ) metal5r8 32 -16 180 1 1 -( 3664 672 -3071.9772035159772 ) ( 3392 944 -3135.9761323403272 ) ( 3392 944 -3119.9172472754499 ) metal5r8 -32 -0 -0 1 1 -( 3392 944 -3119.9172472754499 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3584 944.44800098396217 -3120.3757850958596 ) metal5r8 32 -16 -0 1 1 -( 3392 944 -3119.9172472754499 ) ( 3856 672 -3055.9193792414385 ) ( 3664 672 -3055.9193792413157 ) metal5r8 32 32 -0 1 1 -( 3584 944.44800098396217 -3120.3757850958596 ) ( 3856 672 -3055.9193792414385 ) ( 3392 944 -3119.9172472754499 ) metal5r8 32 32 -0 1 1 -( 3392 944 -3135.9761323403272 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3392 944 -3119.9172472754499 ) metal5r8 32 -16 -0 1 1 -( 3856 672 -3071.9768577734121 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3664 672 -3071.9772035159772 ) metal5r8 32 32 -0 1 1 -( 3664 672 -3071.9772035159772 ) ( 3583.4505200993262 949 -3138.9172473249582 ) ( 3392 944 -3135.9761323403272 ) metal5r8 32 32 -0 1 1 -( 3664 672 -3055.9193792413157 ) ( 3856 672 -3055.9193792414385 ) ( 3856 672 -3071.9768577734121 ) metal5r8 32 -16 -0 1 1 -} -// brush 309 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal5r8 32 -48 180 1 1 -( 48620 46300 65535 ) ( -44060 -46380 65535 ) ( 48620 46300 -65535 ) city4_7 -0 -0 -0 1 1 -( -65711 944 65535 ) ( 65359 944 65535 ) ( -65711 944 -65535 ) metal5r8 32 -0 -0 1 1 -( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 32 -0 -0 1 1 -} -// brush 310 -{ -( 47372 -42716 65535 ) ( -45308 49964 65535 ) ( -45308 49964 -65535 ) metal5r8 32 -48 180 1 1 -( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 32 -48 180 1 1 -( 48460 46460 65535 ) ( -44220 -46220 65535 ) ( -44220 -46220 -65535 ) metal5r8 32 -48 180 1 1 -( -45532 49740 65535 ) ( 47148 -42940 65535 ) ( -45532 49740 -65535 ) metal5r8 -0 -0 -0 1 1 -( 3168 67951 65535 ) ( 3168 -63119 65535 ) ( 3168 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 65359 1264 65535 ) ( -65711 1264 65535 ) ( -65711 1264 -65535 ) metal5r8 32 -0 -0 1 1 -( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 -0 32 -0 1 1 -( 65434 -63118 -874 ) ( 65434 67950 -874 ) ( -65548 67950 -5649 ) metal5r8 32 -0 -0 1 1 -} -// brush 311 -{ -( 3488 -63119 65535 ) ( 3488 67951 65535 ) ( 3488 67951 -65535 ) metal5r8 32 -0 180 1 1 -( 19895 75025 53994 ) ( -72785 -17655 53994 ) ( 73404 21516 -53023 ) metal5r8 32 48 -0 1 1 -( -73660 21612 53119 ) ( 19020 -71068 53119 ) ( -20151 75121 -53898 ) metal5r8 32 48 -0 1 1 -( -46412 67951 46444 ) ( -46412 -63119 46444 ) ( 46268 67951 -46236 ) metal5r8 32 48 -0 1 1 -( 65359 -51019 -37991 ) ( 65359 58037 34712 ) ( -65711 -51019 -37991 ) metal5r8 32 48 -0 1 1 -( 65359 -54012 33501 ) ( 65359 55044 -39202 ) ( -65711 -54012 33501 ) metal5r8 32 48 -0 1 1 -( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal5r8 32 48 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 48 -0 1 1 -} -// brush 312 -{ -( 48395 -41606 65535 ) ( -46629 48667 65535 ) ( -46629 48667 -65535 ) metal5r8 32 -0 -0 1 1 -( 64818 -63119 9194 ) ( 64818 67951 9194 ) ( -63706 -63119 -16510 ) metal5r8 32 -0 -0 1 1 -( 3168 -63119 65535 ) ( 3168 67951 65535 ) ( 3168 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( -45468 49804 65535 ) ( 47212 -42876 65535 ) ( -45468 49804 -65535 ) metal5r8 -0 -0 -0 1 1 -( 64814 67951 9209 ) ( 64814 -63119 9209 ) ( -63709 -63119 -16495 ) metal5r8 32 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 -0 -0 180 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) metal5r8 -0 48 90 1 1 -} -// brush 313 -{ -( 47308 -42780 65535 ) ( -45372 49900 65535 ) ( -45372 49900 -65535 ) metal5r8 -32 -0 -0 1 1 -( -44220 -46220 65535 ) ( 48460 46460 65535 ) ( -44220 -46220 -65535 ) metal5r8 -32 -0 -0 1 1 -( 3168 67951 65535 ) ( 3168 -63119 65535 ) ( 3168 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 -0 32 -0 1 1 -( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 -0 32 -0 1 1 -} -// brush 314 -{ -( 64818 -63119 9194 ) ( 64818 67951 9194 ) ( -63706 -63119 -16510 ) metal5r8 32 -0 -0 1 1 -( -45468 49804 65535 ) ( 47212 -42876 65535 ) ( -45468 49804 -65535 ) metal5r8 -0 -0 -0 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal5r8 32 -48 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 -0 -0 1 1 -} -// brush 315 -{ -( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) *water2 32 -48 180 1 1 -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) *water2 32 -48 180 1 1 -( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) *water2 32 -48 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) *water2 32 -48 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 -} -// brush 316 -{ -( 47308 -42780 65535 ) ( -45372 49900 65535 ) ( -45372 49900 -65535 ) *water2 32 -48 180 1 1 -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) *water2 32 -48 180 1 1 -( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) *water2 32 -48 180 1 1 -( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) *water2 32 -48 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 -} -// brush 317 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 48620 46300 65535 ) ( -44060 -46380 65535 ) ( 48620 46300 -65535 ) city4_7 -0 -0 -0 1 1 -( -45372 49900 65535 ) ( 47308 -42780 65535 ) ( -45372 49900 -65535 ) city4_7 -0 -0 -0 1 1 -( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) city4_7 -0 48 90 1 1 -} -// brush 318 -{ -( 47460 -42932 65535 ) ( -45220 49748 65535 ) ( 47460 -42932 -65535 ) metal5r8 -15 -15 180 1 -1 -( 3488 67647 65535 ) ( 3488 -63423 65535 ) ( 3488 -63423 -65535 ) metal5r8 -15 -15 180 1 -1 -( -65711 54833 -39062 ) ( -65711 -54223 33642 ) ( 65359 54833 -39062 ) metal5r8 -31 -15 -0 1 1 -( -65711 -63423 -3136 ) ( -65711 67647 -3136 ) ( 65359 67647 -3136 ) metal5r8 -31 -15 -0 1 1 -} -// brush 319 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -48 180 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 608 65535 ) ( -65711 608 65535 ) ( -65711 608 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 320 -{ -( 1344 -63119 65535 ) ( 1344 67951 65535 ) ( 1344 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -48 -0 1 1 -( -65711 784 65535 ) ( 65359 784 65535 ) ( -65711 784 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 321 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -48 180 1 1 -( 1344 67951 65535 ) ( 1344 -63119 65535 ) ( 1344 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 800 65535 ) ( -65711 800 65535 ) ( -65711 800 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 784 65535 ) ( 65359 784 65535 ) ( -65711 784 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 322 -{ -( 1344 -63119 65535 ) ( 1344 67951 65535 ) ( 1344 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 323 -{ -( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) mmetal1_8 -0 -0 180 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 -0 -0 180 1 1 -( 65359 67951 -3071 ) ( 65359 -63119 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 -0 48 90 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 324 -{ -( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 65359 1216 65535 ) ( -65711 1216 65535 ) ( -65711 1216 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 325 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 326 -{ -( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 32 -48 180 1 1 -( 704 67951 65535 ) ( 704 -63119 65535 ) ( 704 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 1216 65535 ) ( -65711 1216 65535 ) ( -65711 1216 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 327 -{ -( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city6_3 32 -48 180 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city6_3 32 -48 180 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city6_3 32 -48 -0 1 1 -( -65711 608 65535 ) ( 65359 608 65535 ) ( -65711 608 -65535 ) city6_3 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city6_3 32 -0 -0 1 1 -} -// brush 328 -{ -( 1472 -63119 65535 ) ( 1472 67951 65535 ) ( 1472 67951 -65535 ) city6_3 32 -48 180 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city6_3 32 -48 180 1 1 -( 65359 784 65535 ) ( -65711 784 65535 ) ( -65711 784 -65535 ) city6_3 32 -48 -0 1 1 -( -65711 608 65535 ) ( 65359 608 65535 ) ( -65711 608 -65535 ) city6_3 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city6_3 32 -0 -0 1 1 -} -// brush 329 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) mmetal1_8 32 -48 -0 1 1 -( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 330 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 -( 1344 67951 65535 ) ( 1344 -63119 65535 ) ( 1344 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) mmetal1_8 -0 -0 180 1 1 -( -65711 800 65535 ) ( 65359 800 65535 ) ( -65711 800 -65535 ) mmetal1_8 -0 -0 180 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 331 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 -} -// brush 332 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 65359 592 65535 ) ( -65711 592 65535 ) ( -65711 592 -65535 ) mmetal1_8 32 -48 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 333 -{ -( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3424 ) ( 65359 67951 -3424 ) ( -65711 -63119 -3424 ) city4_7 32 48 -0 1 1 -} -// brush 334 -{ -( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 1216 65535 ) ( 65359 1216 65535 ) ( -65711 1216 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3424 ) ( 65359 67951 -3424 ) ( -65711 -63119 -3424 ) city4_7 32 -0 -0 1 1 -} -// brush 335 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 336 -{ -( 1344 -63119 65535 ) ( 1344 67951 65535 ) ( 1344 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 784 65535 ) ( 65359 784 65535 ) ( -65711 784 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) city4_7 -0 48 90 1 1 -} -// brush 337 -{ -( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city4_7 32 -48 180 1 1 -( 720 67951 65535 ) ( 720 -63119 65535 ) ( 720 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1504 65535 ) ( 65359 1504 65535 ) ( -65711 1504 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 -} -// brush 338 -{ -( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city4_7 32 -0 180 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 432 65535 ) ( 65359 432 65535 ) ( -65711 432 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city6_3 32 -0 -0 1 1 -( 65359 -63119 -3424 ) ( 65359 67951 -3424 ) ( -65711 -63119 -3424 ) city4_7 32 48 -0 1 1 -} -// brush 339 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -0 180 1 1 -( 1312 67951 65535 ) ( 1312 -63119 65535 ) ( 1312 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 -} -// brush 340 -{ -( -3840 576 -3072 ) ( -3840 576 -3056 ) ( -3568 848 -3120 ) metal5_8 -0 1 -0 1 1 -( -4033 576 -3056 ) ( -4033 576 -3072 ) ( -3763 848 -3136 ) metal5_8 -0 1 -0 1 1 -( -3840 576 -3056 ) ( -4033 576 -3056 ) ( -3763 848 -3120 ) metal5_8 2 -0 -0 1 1 -( -3568 848 -3136 ) ( -3568 848 -3120 ) ( -3763 848 -3120 ) metal5_8 2 1 -0 1 1 -( -3763 848 -3136 ) ( -4033 576 -3072 ) ( -3840 576 -3072 ) metal5_8 2 -0 -0 1 1 -( -3840 576 -3072 ) ( -4033 576 -3072 ) ( -4033 576 -3056 ) metal5_8 2 1 -0 1 1 -} -// brush 341 -{ -( 3857 1536 -3056 ) ( 3857 1536 -3072 ) ( 3587 1264 -3136 ) metal5r8 -0 1 180 1 -1 -( 3664 1536 -3072 ) ( 3664 1536 -3056 ) ( 3392 1264 -3120 ) metal5r8 -0 1 180 1 -1 -( 3587 1264 -3136 ) ( 3857 1536 -3072 ) ( 3664 1536 -3072 ) metal5r8 18 -0 180 1 1 -( 3664 1536 -3072 ) ( 3857 1536 -3072 ) ( 3857 1536 -3056 ) metal5r8 18 1 180 1 -1 -( 3664 1536 -3056 ) ( 3857 1536 -3056 ) ( 3587 1264 -3120 ) metal5r8 18 -0 180 1 1 -( 3392 1264 -3136 ) ( 3392 1264 -3120 ) ( 3587 1264 -3120 ) metal5r8 18 1 180 1 -1 -} -// brush 342 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 343 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 344 -{ -( 52917 67951 -38432 ) ( 52917 -63119 -38432 ) ( -54459 -63119 36731 ) sfloor4_6 -0 -0 -0 1 1 -( 2312 67951 65535 ) ( 2312 -63119 65535 ) ( 2312 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 -0 -0 180 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) sfloor4_6 -0 -0 180 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 -0 48 90 1 1 -( 65359 -63119 -3473.3930207867638 ) ( 65359 67951 -3473.3930207867638 ) ( -65711 -63119 -3473.3930207867638 ) sfloor4_6 -0 48 90 1 1 -} -// brush 345 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) metal5r8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal5r8 32 -0 -0 1 1 -} -// brush 346 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 347 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) metal5r8 32 -48 180 1 1 -( 2368 67951 65535 ) ( 2368 -63119 65535 ) ( 2368 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 65359 1088 65535 ) ( -65711 1088 65535 ) ( -65711 1088 -65535 ) metal5r8 32 -48 -0 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) metal5r8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 -} -// brush 348 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) metal2_6 32 -48 180 1 1 -( 2368 67951 65535 ) ( 2368 -63119 65535 ) ( 2368 67951 -65535 ) metal2_6 -0 -0 -0 1 1 -( 65359 59544 -32284 ) ( 65359 -57688 26332 ) ( -65711 -57688 26332 ) metal2_6 32 -0 -0 1 1 -( 65359 -57694 26319 ) ( 65359 59537 -32296 ) ( -65711 -57694 26319 ) metal2_6 32 -0 -0 1 1 -( -65711 1088 65535 ) ( 65359 1088 65535 ) ( -65711 1088 -65535 ) metal2_6 32 -48 -0 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) metal2_6 32 -0 -0 1 1 -} -// brush 349 -{ -( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 -} -// brush 350 -{ -( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 -} -// brush 351 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city3_2 -0 -0 -0 1 1 -( 2271 67951 65535 ) ( 2271 -63119 65535 ) ( 2271 67951 -65535 ) city3_2 -0 -0 -0 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city3_2 -0 -0 180 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) city3_2 -0 -0 180 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) city3_2 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city3_2 32 -0 -0 1 1 -} -// brush 352 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) sfloor4_1 32 -48 180 1 1 -( 2289 67951 65535 ) ( 2289 -63119 65535 ) ( 2289 67951 -65535 ) sfloor4_1 32 -48 180 1 1 -( 65359 896 65535 ) ( -65711 896 65535 ) ( -65711 896 -65535 ) sfloor4_1 32 -48 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_1 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) sfloor4_1 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) sfloor4_1 32 -0 -0 1 1 -} -// brush 353 -{ -( -1664 1200 -3352 ) ( -1664 1208 -3344 ) ( -1664 1208 -3352 ) city4_5 -0 -0 -0 1 1 -( -1808 1200 -3352 ) ( -1808 1208 -3344 ) ( -1808 1200 -3344 ) city4_5 0 0 0 1 1 -( -1808 1208 -3352 ) ( -1792 1208 -3344 ) ( -1808 1208 -3344 ) city4_5 0 0 0 1 1 -( -1808 1200 -3352 ) ( -1792 1200 -3344 ) ( -1792 1200 -3352 ) city4_5 0 0 0 1 1 -( -1808 1200 -3344 ) ( -1792 1208 -3344 ) ( -1792 1200 -3344 ) city4_5 0 0 0 1 1 -( -1808 1200 -3472 ) ( -1792 1208 -3472 ) ( -1808 1208 -3472 ) city4_5 -0 -0 -0 1 1 -} -// brush 354 -{ -( -1792 1392 -3360 ) ( -1792 1536 -3344 ) ( -1792 1536 -3360 ) iktkpn17 -0 -0 -0 1 1 -( -1936 1392 -3360 ) ( -1936 1536 -3344 ) ( -1936 1392 -3344 ) iktkpn17 0 0 0 1 1 -( -1936 1536 -3360 ) ( -1808 1536 -3344 ) ( -1936 1536 -3344 ) iktkpn17 0 0 0 1 1 -( -1936 1392 -3360 ) ( -1808 1392 -3344 ) ( -1808 1392 -3360 ) iktkpn17 0 0 0 1 1 -( -1936 1392 -3344 ) ( -1808 1536 -3344 ) ( -1808 1392 -3344 ) iktkpn17 0 0 0 1 1 -( -1936 1392 -3360 ) ( -1808 1536 -3360 ) ( -1936 1536 -3360 ) iktkpn17 0 0 0 1 1 -} -// brush 355 -{ -( 704 -63119 65535 ) ( 704 67951 65535 ) ( 704 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 65359 1216 65535 ) ( -65711 1216 65535 ) ( -65711 1216 -65535 ) mmetal1_8 32 -48 -0 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 356 -{ -( 704 -63119 65535 ) ( 704 67951 65535 ) ( 704 67951 -65535 ) city4_7 32 -48 180 1 1 -( 703 67951 65535 ) ( 703 -63119 65535 ) ( 703 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 357 -{ -( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city6_3 32 -48 180 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city6_3 32 -48 180 1 1 -( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city6_3 32 -48 -0 1 1 -( -65711 -304 65535 ) ( 65359 -304 65535 ) ( -65711 -304 -65535 ) city6_3 32 -48 -0 1 1 -( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city6_3 32 -0 -0 1 1 -( 65359 -63119 -2880 ) ( 65359 67951 -2880 ) ( -65711 -63119 -2880 ) city6_3 32 -0 -0 1 1 -} -// brush 358 -{ -( 1056 -63119 65535 ) ( 1056 67951 65535 ) ( 1056 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 336 65535 ) ( 65359 336 65535 ) ( -65711 336 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 359 -{ -( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) city4_7 32 -0 180 1 1 -( 1056 67951 65535 ) ( 1056 -63119 65535 ) ( 1056 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 432 65535 ) ( 65359 432 65535 ) ( -65711 432 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -16 -0 1 1 -( 65359 -63119 -2960 ) ( 65359 67951 -2960 ) ( -65711 -63119 -2960 ) city4_7 32 -0 -0 1 1 -} -// brush 360 -{ -( 1648 -63119 65535 ) ( 1648 67951 65535 ) ( 1648 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1200 67951 65535 ) ( 1200 -63119 65535 ) ( 1200 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 336 65535 ) ( 65359 336 65535 ) ( -65711 336 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 -0 48 90 1 1 -} -// brush 361 -{ -( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1184 67951 65535 ) ( 1184 -63119 65535 ) ( 1184 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 16 65535 ) ( -65711 16 65535 ) ( -65711 16 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 -80 65535 ) ( 65359 -80 65535 ) ( -65711 -80 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 362 -{ -( 1056 -63119 65535 ) ( 1056 67951 65535 ) ( 1056 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 16 65535 ) ( -65711 16 65535 ) ( -65711 16 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 -80 65535 ) ( 65359 -80 65535 ) ( -65711 -80 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 363 -{ -( 928 -63119 65535 ) ( 928 67951 65535 ) ( 928 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 912 67951 65535 ) ( 912 -63119 65535 ) ( 912 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 432 65535 ) ( -65711 432 65535 ) ( -65711 432 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 -352 65535 ) ( 65359 -352 65535 ) ( -65711 -352 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 -} -// brush 364 -{ -( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city4_7 32 -0 180 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 -304 65535 ) ( -65711 -304 65535 ) ( -65711 -304 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 -352 65535 ) ( 65359 -352 65535 ) ( -65711 -352 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city4_7 32 -16 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -16 -0 1 1 -} -// brush 365 -{ -( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) sfloor4_1 32 -48 180 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) sfloor4_1 32 -48 180 1 1 -( 65359 432 65535 ) ( -65711 432 65535 ) ( -65711 432 -65535 ) sfloor4_1 32 -48 -0 1 1 -( -65711 -304 65535 ) ( 65359 -304 65535 ) ( -65711 -304 -65535 ) sfloor4_1 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) sfloor4_1 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) sfloor4_1 32 -0 -0 1 1 -} -// brush 366 -{ -( 1328 -63119 65535 ) ( 1328 67951 65535 ) ( 1328 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1312 67951 65535 ) ( 1312 -63119 65535 ) ( 1312 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 352 65535 ) ( -65711 352 65535 ) ( -65711 352 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 -352 65535 ) ( 65359 -352 65535 ) ( -65711 -352 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 -} -// brush 367 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 -( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 592 65535 ) ( -65711 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 -} -// brush 368 -{ -( 2289 -63119 65535 ) ( 2289 67951 65535 ) ( 2289 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 720 65535 ) ( 65359 720 65535 ) ( -65711 720 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 -} -// brush 369 -{ -( 1632 -63119 65535 ) ( 1632 67951 65535 ) ( 1632 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 -( 1456 67951 65535 ) ( 1456 -63119 65535 ) ( 1456 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 -( 65359 1088 65535 ) ( -65711 1088 65535 ) ( -65711 1088 -65535 ) mmetal1_8 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 370 -{ -( 1632 -63119 65535 ) ( 1632 67951 65535 ) ( 1632 67951 -65535 ) mmetal1_8 32 -0 180 1 1 -( 1488 67951 65535 ) ( 1488 -63119 65535 ) ( 1488 67951 -65535 ) mmetal1_8 32 -0 180 1 1 -( 65359 1040 65535 ) ( -65711 1040 65535 ) ( -65711 1040 -65535 ) mmetal1_8 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 371 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city4_7 32 -48 180 1 1 -( 1472 67951 65535 ) ( 1472 -63119 65535 ) ( 1472 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 784 65535 ) ( -65711 784 65535 ) ( -65711 784 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 608 65535 ) ( 65359 608 65535 ) ( -65711 608 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 372 -{ -( 2271 -63119 65535 ) ( 2271 67951 65535 ) ( 2271 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 65359 1088 65535 ) ( -65711 1088 65535 ) ( -65711 1088 -65535 ) mmetal1_8 32 -0 -0 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 373 -{ -( 2368 -63119 65535 ) ( 2368 67951 65535 ) ( 2368 67951 -65535 ) mmetal1_8 32 -0 180 1 1 -( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) mmetal1_8 32 -0 180 1 1 -( 65359 1040 65535 ) ( -65711 1040 65535 ) ( -65711 1040 -65535 ) mmetal1_8 32 -0 -0 1 1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( -65711 912 -65535 ) mmetal1_8 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 374 -{ -( 2496 -63119 65535 ) ( 2496 67951 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 -( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 -} -// brush 375 -{ -( 1312 -63119 65535 ) ( 1312 67951 65535 ) ( 1312 67951 -65535 ) city4_7 32 -48 180 1 1 -( 928 67951 65535 ) ( 928 -63119 65535 ) ( 928 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 448 65535 ) ( -65711 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 432 65535 ) ( 65359 432 65535 ) ( -65711 432 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 -0 -0 1 1 -} -// brush 376 -{ -( 1744 576 -3360 ) ( 1760 576 -3344 ) ( 1760 576 -3360 ) iktkfl03 -0 -0 -0 1 1 -( 1616 704 -3360 ) ( 1616 736 -3344 ) ( 1616 704 -3344 ) iktkfl03 -0 -0 -0 1 1 -( 1744 704 -3360 ) ( 1760 736 -3360 ) ( 1744 736 -3360 ) iktkfl03 0 0 0 1 1 -( 1744 704 -3344 ) ( 1760 736 -3344 ) ( 1760 704 -3344 ) iktkfl03 0 0 0 1 1 -( 1744 736 -3360 ) ( 1760 736 -3344 ) ( 1744 736 -3344 ) iktkfl03 0 0 0 1 1 -( 1760 704 -3360 ) ( 1760 736 -3344 ) ( 1760 736 -3360 ) iktkfl03 0 0 0 1 1 -} -// brush 377 -{ -( 1632 -63127 65535 ) ( 1632 67943 65535 ) ( 1632 67943 -65535 ) sfloor4_6 8 -0 -0 1 1 -( 1488 67943 65535 ) ( 1488 -63127 65535 ) ( 1488 67943 -65535 ) sfloor4_6 24 -48 180 1 1 -( 65503 912 65535 ) ( -65567 912 65535 ) ( -65567 912 -65535 ) sfloor4_6 -48 -48 -0 1 1 -( -65567 440 65535 ) ( 65503 440 65535 ) ( -65567 440 -65535 ) sfloor4_6 -48 -48 -0 1 1 -( 65503 67943 -3328 ) ( 65503 -63127 -3328 ) ( -65567 -63127 -3328 ) sfloor4_6 -48 -8 -0 1 1 -( 65503 -63127 -3344 ) ( 65503 67943 -3344 ) ( -65567 -63127 -3344 ) sfloor4_6 -48 -8 -0 1 1 -} -// brush 378 -{ -( 2304 1520 -3360 ) ( 2320 1520 -3344 ) ( 2320 1520 -3360 ) iktkfl03 0 0 0 1 1 -( 1488 1520 -3360 ) ( 1488 1536 -3344 ) ( 1488 1520 -3344 ) iktkfl03 -0 -0 -0 1 1 -( 2304 1520 -3472 ) ( 2320 1536 -3472 ) ( 2304 1536 -3472 ) iktkfl03 -0 -0 -0 1 1 -( 2304 1520 -3344 ) ( 2320 1536 -3344 ) ( 2320 1520 -3344 ) iktkfl03 0 0 0 1 1 -( 2304 1536 -3360 ) ( 2320 1536 -3344 ) ( 2304 1536 -3344 ) iktkfl03 0 0 0 1 1 -( 2320 1520 -3360 ) ( 2320 1536 -3344 ) ( 2320 1536 -3360 ) iktkfl03 0 0 0 1 1 -} -// brush 379 -{ -( 1472 912 -3360 ) ( 1488 912 -3344 ) ( 1488 912 -3360 ) iktkfl03 -0 -0 -0 1 1 -( 1472 1520 -3360 ) ( 1472 1536 -3344 ) ( 1472 1520 -3344 ) iktkfl03 0 0 0 1 1 -( 1472 1520 -3472 ) ( 1488 1536 -3472 ) ( 1472 1536 -3472 ) iktkfl03 -0 -0 -0 1 1 -( 1472 1520 -3344 ) ( 1488 1536 -3344 ) ( 1488 1520 -3344 ) iktkfl03 0 0 0 1 1 -( 1472 1536 -3360 ) ( 1488 1536 -3344 ) ( 1472 1536 -3344 ) iktkfl03 0 0 0 1 1 -( 1488 1520 -3360 ) ( 1488 1536 -3344 ) ( 1488 1536 -3360 ) iktkfl03 0 0 0 1 1 -} -// brush 380 -{ -( 2288 896 -3360 ) ( 2320 896 -3344 ) ( 2320 896 -3360 ) iktkfl03 0 0 0 1 1 -( 1472 896 -3360 ) ( 1472 912 -3344 ) ( 1472 896 -3344 ) iktkfl03 -0 -0 -0 1 1 -( 2288 896 -3472 ) ( 2320 912 -3472 ) ( 2288 912 -3472 ) iktkfl03 -0 -0 -0 1 1 -( 2288 896 -3344 ) ( 2320 912 -3344 ) ( 2320 896 -3344 ) iktkfl03 0 0 0 1 1 -( 2288 912 -3360 ) ( 2320 912 -3344 ) ( 2288 912 -3344 ) iktkfl03 0 0 0 1 1 -( 2320 896 -3360 ) ( 2320 912 -3344 ) ( 2320 912 -3360 ) iktkfl03 -0 -0 -0 1 1 -} -} -// entity 1 -{ -"speed" "200" -"sounds" "1" -"wait" "1" -"lip" "0" -"dmg" "500" -"team_no" "1" -"angle" "271" -"classname" "func_door" -// brush 0 -{ -( -2449 -65535 65535 ) ( -2449 65535 65535 ) ( -2449 65535 -65535 ) adoor03_3 0 0 180 1 1 -( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) adoor03_3 0 0 180 1 1 -( 65535 872 65535 ) ( -65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 -( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) adoor03_3 16 0 180 1 1 -( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) adoor03_3 -15 0 180 1 1 -( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) adoor03_3 -15 0 180 1 1 -} -} -// entity 2 -{ -"speed" "200" -"sounds" "1" -"wait" "1" -"lip" "0" -"dmg" "500" -"team_no" "1" -"angle" "90" -"classname" "func_door" -// brush 0 -{ -( -2448 -65535 65535 ) ( -2448 65535 65535 ) ( -2448 65535 -65535 ) adoor03_3 0 0 180 1 1 -( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) adoor03_3 0 0 180 1 1 -( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) adoor03_3 16 0 180 1 1 -( -65535 872 65535 ) ( 65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 -( 65535 65535 -3200 ) ( 65535 -65535 -3200 ) ( -65535 -65535 -3200 ) adoor03_3 -15 0 180 1 1 -( 65535 -65535 -3328 ) ( 65535 65535 -3328 ) ( -65535 -65535 -3328 ) adoor03_3 -15 0 180 1 1 -} -} -// entity 3 -{ -"speed" "200" -"sounds" "1" -"wait" "1" -"lip" "0" -"dmg" "500" -"health" "0" -"team_no" "1" -"angle" "90" -"classname" "func_door" -// brush 0 -{ -( -2675 -65535 65535 ) ( -2675 65535 65535 ) ( -2675 65535 -65535 ) adoor03_3 0 0 180 1 1 -( -2687 65535 65535 ) ( -2687 -65535 65535 ) ( -2687 65535 -65535 ) adoor03_3 0 0 180 1 1 -( 65535 944 65535 ) ( -65535 944 65535 ) ( -65535 944 -65535 ) adoor03_3 16 0 180 1 1 -( -65535 872 65535 ) ( 65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 -( 65535 65535 -3201 ) ( 65535 -65535 -3201 ) ( -65535 -65535 -3201 ) adoor03_3 -15 0 180 1 1 -( 65535 -65535 -3329 ) ( 65535 65535 -3329 ) ( -65535 -65535 -3329 ) adoor03_3 -15 0 180 1 1 -} -} -// entity 4 -{ -"speed" "200" -"sounds" "1" -"wait" "1" -"lip" "0" -"dmg" "500" -"health" "0" -"team_no" "1" -"angle" "272" -"classname" "func_door" -// brush 0 -{ -( -2675 -65535 65535 ) ( -2675 65535 65535 ) ( -2675 65535 -65535 ) adoor03_3 0 0 180 1 1 -( -2687 65535 65535 ) ( -2687 -65535 65535 ) ( -2687 65535 -65535 ) adoor03_3 0 0 180 1 1 -( 65535 872 65535 ) ( -65535 872 65535 ) ( -65535 872 -65535 ) adoor03_3 16 0 180 1 1 -( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) adoor03_3 16 0 180 1 1 -( 65535 65535 -3201 ) ( 65535 -65535 -3201 ) ( -65535 -65535 -3201 ) adoor03_3 -15 0 180 1 1 -( 65535 -65535 -3329 ) ( 65535 65535 -3329 ) ( -65535 -65535 -3329 ) adoor03_3 -15 0 180 1 1 -} -} -// entity 5 -{ -"speed" "200" -"sounds" "1" -"wait" "1" -"lip" "0" -"dmg" "500" -"health" "0" -"team_no" "1" -"angle" "357" -"classname" "func_door" -// brush 0 -{ -( -1232 -65535 65535 ) ( -1232 65535 65535 ) ( -1232 65535 -65535 ) adoor03_3 0 0 180 1 1 -( -1304 65535 65535 ) ( -1304 -65535 65535 ) ( -1304 65535 -65535 ) adoor03_3 0 0 180 1 1 -( 65535 1682 65535 ) ( -65535 1682 65535 ) ( -65535 1682 -65535 ) adoor03_3 16 0 180 1 1 -( -65535 1668 65535 ) ( 65535 1668 65535 ) ( -65535 1668 -65535 ) adoor03_3 16 0 180 1 1 -( 65535 65535 -2960 ) ( 65535 -65535 -2960 ) ( -65535 -65535 -2960 ) adoor03_3 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) adoor03_3 -15 0 180 1 1 -} -} -// entity 6 -{ -"speed" "200" -"sounds" "1" -"wait" "1" -"lip" "0" -"dmg" "500" -"health" "0" -"team_no" "1" -"angle" "183" -"classname" "func_door" -// brush 0 -{ -( -1304 -65535 65535 ) ( -1304 65535 65535 ) ( -1304 65535 -65535 ) adoor03_3 0 0 180 1 1 -( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) adoor03_3 0 0 180 1 1 -( 65535 1682 65535 ) ( -65535 1682 65535 ) ( -65535 1682 -65535 ) adoor03_3 16 0 180 1 1 -( -65535 1668 65535 ) ( 65535 1668 65535 ) ( -65535 1668 -65535 ) adoor03_3 16 0 180 1 1 -( 65535 65535 -2960 ) ( 65535 -65535 -2960 ) ( -65535 -65535 -2960 ) adoor03_3 -15 0 180 1 1 -( 65535 -65535 -3072 ) ( 65535 65535 -3072 ) ( -65535 -65535 -3072 ) adoor03_3 -15 0 180 1 1 -} -} -// entity 7 -{ -"height" "154" -"classname" "func_plat" -// brush 0 -{ -( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) sfloor4_1 0 0 180 1 1 -( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) sfloor4_1 0 0 180 1 1 -( 65535 1520 65535 ) ( -65535 1520 65535 ) ( -65535 1520 -65535 ) sfloor4_1 -16 0 180 1 1 -( -65535 1392 65535 ) ( 65535 1392 65535 ) ( -65535 1392 -65535 ) sfloor4_1 -16 0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) sfloor4_1 -15 0 180 1 1 -( 65535 -65535 -3344 ) ( 65535 65535 -3344 ) ( -65535 -65535 -3344 ) sfloor4_1 -15 0 180 1 1 -} -} -// entity 8 -{ -"style" "32" -"delay" "2" -"speed" "100" -"angle" "-1" -"classname" "trigger_push" -// brush 0 -{ -( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) city6_8 0 0 180 1 1 -( -1664 65535 65535 ) ( -1664 -65535 65535 ) ( -1664 65535 -65535 ) city6_8 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) city6_8 -16 0 180 1 1 -( -65535 416 65535 ) ( 65535 416 65535 ) ( -65535 416 -65535 ) city6_8 -16 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) city6_8 -15 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) city6_8 -15 0 180 1 1 -} -} -// entity 9 -{ -"style" "32" -"delay" "2" -"speed" "200" -"angle" "183" -"classname" "trigger_push" -// brush 0 -{ -( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) metal3_2 0 0 180 1 1 -( -2096 65535 65535 ) ( -2096 -65535 65535 ) ( -2096 65535 -65535 ) metal3_2 0 0 180 1 1 -( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) metal3_2 -16 0 180 1 1 -( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) metal3_2 -16 0 180 1 1 -( 65535 65535 -3440 ) ( 65535 -65535 -3440 ) ( -65535 -65535 -3440 ) metal3_2 -15 0 180 1 1 -( 65535 -65535 -3456 ) ( 65535 65535 -3456 ) ( -65535 -65535 -3456 ) metal3_2 -15 0 180 1 1 -} -} -// entity 10 -{ -"origin" "-2632 1472 -3280" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 11 -{ -"origin" "-2632 1392 -3280" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 12 -{ -"origin" "-1392 2352 -2960" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 13 -{ -"origin" "-1312 2352 -2960" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 14 -{ -"origin" "-1232 2352 -2960" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 15 -{ -"origin" "-1408 2288 -2960" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 16 -{ -"origin" "-1184 2288 -2960" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 17 -{ -"origin" "-608 704 -3168" -"light" "3000" -"classname" "light" -} -// entity 18 -{ -"origin" "-992 528 -3008" -"light" "500" -"classname" "light" -} -// entity 19 -{ -"origin" "-1600 704 -2992" -"light" "500" -"classname" "light" -} -// entity 20 -{ -"origin" "-1168 544 -3088" -"light" "500" -"classname" "light" -} -// entity 21 -{ -"origin" "-1296 1648 -2896" -"light" "500" -"classname" "light" -} -// entity 22 -{ -"origin" "-768 1648 -2896" -"light" "500" -"classname" "light" -} -// entity 23 -{ -"origin" "-1792 1648 -2896" -"light" "400" -"classname" "light" -} -// entity 24 -{ -"origin" "-1904 1456 -3088" -"light" "500" -"classname" "light" -} -// entity 25 -{ -"origin" "-1792 1648 -3216" -"light" "500" -"classname" "light" -} -// entity 26 -{ -"origin" "-2432 608 -3216" -"light" "500" -"classname" "light" -} -// entity 27 -{ -"origin" "-2432 1184 -3216" -"light" "500" -"classname" "light" -} -// entity 28 -{ -"origin" "-1824 1184 -3088" -"light" "500" -"classname" "light" -} -// entity 29 -{ -"origin" "-1824 1184 -3216" -"light" "500" -"classname" "light" -} -// entity 30 -{ -"origin" "-1792 1264 -3088" -"light" "500" -"classname" "light" -} -// entity 31 -{ -"origin" "-2160 1184 -3088" -"light" "500" -"classname" "light" -} -// entity 32 -{ -"origin" "-2656 608 -2896" -"light" "500" -"classname" "light" -} -// entity 33 -{ -"origin" "-2656 1184 -2912" -"light" "500" -"classname" "light" -} -// entity 34 -{ -"origin" "-2704 1536 -2896" -"light" "500" -"classname" "light" -} -// entity 35 -{ -"origin" "-2704 480 -3088" -"light" "500" -"classname" "light" -} -// entity 36 -{ -"origin" "-3648 1008 -2896" -"light" "1000" -"classname" "light" -} -// entity 37 -{ -"origin" "-4016 1536 -3080" -"light" "1000" -"classname" "light" -} -// entity 38 -{ -"origin" "-4016 480 -3080" -"light" "1000" -"classname" "light" -} -// entity 39 -{ -"origin" "-3280 1008 -3248" -"light" "500" -"classname" "light" -} -// entity 40 -{ -"origin" "-2704 480 -3216" -"light" "500" -"classname" "light" -} -// entity 41 -{ -"origin" "-2704 1536 -3088" -"light" "500" -"classname" "light" -} -// entity 42 -{ -"origin" "-2704 880 -3312" -"light" "500" -"classname" "light" -} -// entity 43 -{ -"origin" "-3568 672 -3088" -"light" "500" -"classname" "light" -} -// entity 44 -{ -"origin" "-3568 1344 -3088" -"light" "500" -"classname" "light" -} -// entity 45 -{ -"origin" "-3488 176 -2896" -"light" "1000" -"classname" "light" -} -// entity 46 -{ -"origin" "-3088 272 -3248" -"light" "1000" -"classname" "light" -} -// entity 47 -{ -"origin" "-2768 -208 -3152" -"light" "500" -"classname" "light" -} -// entity 48 -{ -"origin" "-2608 -208 -3152" -"light" "500" -"classname" "light" -} -// entity 49 -{ -"origin" "-1800 -216 -3400" -"light" "150" -"classname" "light" -} -// entity 50 -{ -"origin" "-2624 304 -3552" -"light" "500" -"classname" "light" -} -// entity 51 -{ -"origin" "-1392 416 -2896" -"light" "500" -"classname" "light" -} -// entity 52 -{ -"origin" "-2192 320 -3264" -"light" "500" -"classname" "light" -} -// entity 53 -{ -"origin" "-2128 -16 -2896" -"light" "500" -"classname" "light" -} -// entity 54 -{ -"origin" "-1632 416 -3424" -"light" "150" -"classname" "light" -} -// entity 55 -{ -"origin" "-1392 -16 -2896" -"light" "500" -"classname" "light" -} -// entity 56 -{ -"origin" "-1328 240 -3440" -"light" "200" -"classname" "light" -} -// entity 57 -{ -"origin" "-464 224 -3888" -"light" "500" -"classname" "light" -} -// entity 58 -{ -"origin" "-16 816 -3792" -"light" "500" -"classname" "light" -} -// entity 59 -{ -"origin" "-1296 1872 -2896" -"light" "350" -"classname" "light" -} -// entity 60 -{ -"origin" "-1296 2272 -2896" -"light" "350" -"classname" "light" -} -// entity 61 -{ -"origin" "-2560 992 -3216" -"light" "500" -"classname" "light" -} -// entity 62 -{ -"origin" "-2504 1471 -3280" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 63 -{ -"origin" "-48 1023 -3008" -"classname" "info_intermission" -} -// entity 64 -{ -"origin" "-272 991 -3184" -"classname" "info_player_deathmatch" -} -// entity 65 -{ -"origin" "-2504 1391 -3280" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 66 -{ -"origin" "-1152 2351 -2960" -"team_no" "1" -"classname" "info_player_teamspawn" -} -// entity 67 -{ -"origin" "-3504 1007 -3100" -"g_a" "4789" -"owned_by" "1" -"netname" "Blue Flag" -"message" "You have their flag.\nTake it home!\n" -"noise" "ogre/ogwake.wav" -"n_b" " picked up blue's flag.\n" -"items" "131072" -"noise3" "Your flag returned.\n" -"goal_no" "1" -"noise4" "Their flag returned.\n" -"delay" "60" -"pausetime" "60" -"team_no" "2" -"skin" "1" -"mdl" "progs/tf_flag.mdl" -"angle" "135" -"classname" "item_tfgoal" -"team_broadcast" "Your team got their flag.\n" -"non_team_broadcast" "Your flag has been taken!\n" -"d_n_n" " dropped blue's flag.\n" -} -// entity 68 -{ -"origin" "-272 935 -3184" -"classname" "info_player_start" -} -// entity 69 -{ -"origin" "-208 1280 -3168" -"impulse" "196" -"display_item_status1" "1" -"display_item_status2" "2" -"team_str_home" "Your flag is in your base.\n" -"team_str_moved" "Your flag is lying around." -"team_str_carried" "Your flag is being carried by\n" -"non_team_str_home" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is in their base.\n" -"non_team_str_moved" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is lying around." -"non_team_str_carried" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is being carried by\n" -"hook_out" "1" -"non_team_broadcast" "Get the enemy flag and take it to your tower!\n" -"classname" "info_tfdetect" -} -// entity 70 -{ -"origin" "-2656 1104 -3296" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 71 -{ -"origin" "-2656 1040 -3296" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 72 -{ -"origin" "-2656 976 -3296" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 73 -{ -"origin" "-2480 1104 -3296" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 74 -{ -"origin" "-2480 1040 -3296" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 75 -{ -"origin" "-2480 976 -3296" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 76 -{ -"origin" "-1472 2000 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 77 -{ -"origin" "-1472 1936 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 78 -{ -"origin" "-1472 1872 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 79 -{ -"origin" "-1120 2000 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 80 -{ -"origin" "-1120 1936 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 81 -{ -"origin" "-1120 1872 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 82 -{ -"origin" "-784 1040 -3040" -"frags" "10" -"b_o" "Your flag was captured.\n" -"count" "10" -"b_t" "Your team captured their flag.\n" -"g_e" "19" -"n_b" " captured red's flag.\n" -"noise" "items/cap1.wav" -"axhitme" "2" -"message" "You captured their flag.\n" -"items_allowed" "2" -"owned_by" "2" -"target" "cap1" -"g_a" "1" -"classname" "info_tfgoal" -} -// entity 83 -{ -"origin" "1624 2327 -3400" -"light" "150" -"classname" "light" -} -// entity 84 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "tower" -"_tb_id" "419" -// brush 0 -{ -( 560 -63999 65535 ) ( 560 67071 65535 ) ( 560 67071 -65535 ) wiz1_4 -0 -0 180 1 1 -( 12270 67071 64402 ) ( 12270 -63999 64402 ) ( -10507 67071 -64673 ) wiz1_4 -0 -0 180 1 1 -( 65647 -6579 65032 ) ( -65423 -6579 65032 ) ( -65423 8734 -65140 ) wiz1_4 -16 -0 180 1 1 -( -65423 9336 65069 ) ( 65647 9336 65069 ) ( -65423 -5978 -65102 ) wiz1_4 -16 -0 180 1 1 -( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 -( 65647 -63999 -3408 ) ( 65647 67071 -3408 ) ( -65423 -63999 -3408 ) wiz1_4 -0 -16 270 1 1 -} -// brush 1 -{ -( 560 -63999 65535 ) ( 560 67071 65535 ) ( 560 67071 -65535 ) wiz1_4 -0 -0 -0 1 1 -( -74022 20081 52469 ) ( 18657 -72598 52469 ) ( -20513 73590 -54549 ) wiz1_4 -16 -0 180 1 1 -( -46252 47852 65535 ) ( 46428 -44828 65535 ) ( -46252 47852 -65535 ) wiz1_4 -0 -0 180 1 1 -( -47676 67071 44892 ) ( -47676 -63999 44892 ) ( 45004 67071 -47788 ) wiz1_4 -16 -0 180 1 1 -( 288 67071 65535 ) ( 288 -63999 65535 ) ( 288 67071 -65535 ) wiz1_4 -0 -0 180 1 1 -( 65647 9336 65069 ) ( -65423 9336 65069 ) ( -65423 -5978 -65102 ) wiz1_4 -16 -0 180 1 1 -( 65647 -54508 34077 ) ( 65647 54548 -38626 ) ( -65423 -54508 34077 ) wiz1_4 -16 -0 180 1 1 -( -65423 1216 65535 ) ( 65647 1216 65535 ) ( -65423 1216 -65535 ) wiz1_4 -16 -0 180 1 1 -( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 -} -// brush 2 -{ -( 12270 -63999 64402 ) ( 12270 67071 64402 ) ( -10507 67071 -64673 ) wiz1_4 -0 -0 -0 1 1 -( -47676 67071 44892 ) ( -47676 -63999 44892 ) ( 45004 67071 -47788 ) wiz1_4 -16 -0 180 1 1 -( 288 67071 65535 ) ( 288 -63999 65535 ) ( 288 67071 -65535 ) wiz1_4 -0 -0 180 1 1 -( 65647 -6579 65032 ) ( -65423 -6579 65032 ) ( -65423 8734 -65140 ) wiz1_4 -16 -0 180 1 1 -( -65423 9336 65069 ) ( 65647 9336 65069 ) ( -65423 -5978 -65102 ) wiz1_4 -16 -0 180 1 1 -( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 -} -// brush 3 -{ -( 560 -63999 65535 ) ( 560 67071 65535 ) ( 560 67071 -65535 ) wiz1_4 -0 -0 -0 1 1 -( 18764 75564 52575 ) ( -73916 -17116 52575 ) ( 72273 22055 -54442 ) wiz1_4 -16 -0 180 1 1 -( 46588 47740 65535 ) ( -46092 -44940 65535 ) ( 46588 47740 -65535 ) wiz1_4 -0 -0 180 1 1 -( -47676 67071 44892 ) ( -47676 -63999 44892 ) ( 45004 67071 -47788 ) wiz1_4 -16 -0 180 1 1 -( 288 67071 65535 ) ( 288 -63999 65535 ) ( 288 67071 -65535 ) wiz1_4 -0 -0 180 1 1 -( 65647 -51574 -38479 ) ( 65647 57482 34225 ) ( -65423 -51574 -38479 ) wiz1_4 -16 -0 180 1 1 -( 65647 1536 65535 ) ( -65423 1536 65535 ) ( -65423 1536 -65535 ) wiz1_4 -16 -0 180 1 1 -( -65423 -6579 65032 ) ( 65647 -6579 65032 ) ( -65423 8734 -65140 ) wiz1_4 -16 -0 180 1 1 -( 65647 67071 -3056 ) ( 65647 -63999 -3056 ) ( -65423 -63999 -3056 ) mmetal1_8 -31 -0 180 1 1 -} -} -// entity 85 -{ -"origin" "2944 1231 -3312" -"light" "500" -"classname" "light" -} -// entity 86 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "blue tower" -"_tb_id" "420" -// brush 0 -{ -( 73739 -17772 52575 ) ( -18941 74908 52575 ) ( -72450 21399 -54442 ) wiz1_4 -33 16 180 1 1 -( 45915 -45596 65535 ) ( -46765 47084 65535 ) ( -46765 47084 -65535 ) wiz1_4 -16 -0 180 1 1 -( 47499 -64655 44892 ) ( 47499 66415 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 -( -465 -64655 65535 ) ( -465 66415 65535 ) ( -465 66415 -65535 ) wiz1_4 -16 -0 180 1 1 -( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 16 -0 -0 1 1 -( 65246 -52230 -38479 ) ( 65246 56826 34225 ) ( -65824 -52230 -38479 ) wiz1_4 -33 16 180 1 1 -( 65246 880 65535 ) ( -65824 880 65535 ) ( -65824 880 -65535 ) wiz1_4 -33 -0 180 1 1 -( -65824 -7235 65032 ) ( 65246 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -32.9999 -0 180 1 1 -( 65246 66415 -3056 ) ( 65246 -64655 -3056 ) ( -65824 -64655 -3056 ) mmetal1_8 -48 16 180 1 1 -} -// brush 1 -{ -( -18834 -73254 52469 ) ( 73845 19425 52469 ) ( 20336 72934 -54549 ) wiz1_4 -33 16 180 1 1 -( -46605 -45484 65535 ) ( 46075 47196 65535 ) ( 46075 47196 -65535 ) wiz1_4 -16 -0 180 1 1 -( 47499 -64655 44892 ) ( 47499 66415 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 -( -465 -64655 65535 ) ( -465 66415 65535 ) ( -465 66415 -65535 ) wiz1_4 -16 -0 180 1 1 -( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 16 -0 -0 1 1 -( 65246 -7235 65032 ) ( -65824 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -33 -0 180 1 1 -( 65246 -55164 34077 ) ( 65246 53892 -38626 ) ( -65824 -55164 34077 ) wiz1_4 -32.9999 16 180 1 1 -( -65824 560 65535 ) ( 65246 560 65535 ) ( -65824 560 -65535 ) wiz1_4 -33 -0 180 1 1 -( 65246 66415 -3056 ) ( 65246 -64655 -3056 ) ( -65824 -64655 -3056 ) mmetal1_8 -48 16 180 1 1 -} -// brush 2 -{ -( -12447 -64655 64402 ) ( -12447 66415 64402 ) ( 10330 66415 -64673 ) wiz1_4 -16 -0 180 1 1 -( 47499 66415 44892 ) ( 47499 -64655 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 -( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 -0 16 90 1 1 -( 65246 -7235 65032 ) ( -65824 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -33 -0 180 1 1 -( -65824 8680 65069 ) ( 65246 8680 65069 ) ( -65824 -6634 -65102 ) wiz1_4 -33 -0 180 1 1 -( 65246 -64655 -3408 ) ( 65246 66415 -3408 ) ( -65824 -64655 -3408 ) wiz1_4 -32.9999 16 180 1 1 -} -// brush 3 -{ -( 47499 -64655 44892 ) ( 47499 66415 44892 ) ( -45181 66415 -47788 ) wiz1_4 -33 16 180 1 1 -( -737 66415 65535 ) ( -737 -64655 65535 ) ( -737 66415 -65535 ) wiz1_4 -0 16 90 1 1 -( 65246 -7235 65032 ) ( -65824 -7235 65032 ) ( -65824 8078 -65140 ) wiz1_4 -33 -0 180 1 1 -( 65246 53892 -38626 ) ( 65246 -55164 34077 ) ( -65824 -55164 34077 ) wiz1_4 -33 16 180 1 1 -( -65824 8680 65069 ) ( 65246 8680 65069 ) ( -65824 -6634 -65102 ) wiz1_4 -33 -0 180 1 1 -} -} -// entity 87 -{ -"origin" "2448 1807 -3552" -"light" "500" -"classname" "light" -} -// entity 88 -{ -"origin" "1232 1583 -3008" -"light" "500" -"classname" "light" -} -// entity 89 -{ -"origin" "2592 2351 -3152" -"light" "500" -"classname" "light" -} -// entity 90 -{ -"origin" "2432 2351 -3152" -"light" "500" -"classname" "light" -} -// entity 91 -{ -"origin" "3312 1935 -2896" -"light" "1000" -"classname" "light" -} -// entity 92 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "ladder" -"_tb_id" "421" -// brush 0 -{ -( -2824 -65527 65535 ) ( -2824 65543 65535 ) ( -2824 65543 -65535 ) clip -23 -0 -0 1 1 -( -2928 65543 65535 ) ( -2928 -65527 65535 ) ( -2928 65543 -65535 ) clip -23 -0 -0 1 1 -( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) clip -16 -0 180 1 1 -( -65535 584 65535 ) ( 65535 584 65535 ) ( -65535 584 -65535 ) clip -16 -0 180 1 1 -( 65535 65543 -3312 ) ( 65535 -65527 -3312 ) ( -65535 -65527 -3312 ) clip -15 -8 180 1 1 -( 65535 -65527 -3320 ) ( 65535 65543 -3320 ) ( -65535 -65527 -3320 ) clip -15 -8 180 1 1 -} -// brush 1 -{ -( -2824 -65528 65551 ) ( -2824 65542 65551 ) ( -2824 65542 -65519 ) clip -22 16 -0 1 1 -( -2928 65542 65551 ) ( -2928 -65528 65551 ) ( -2928 65542 -65519 ) clip -22 16 -0 1 1 -( 65535 591 65551 ) ( -65535 591 65551 ) ( -65535 591 -65519 ) clip -16 -16 180 1 1 -( -65535 583 65551 ) ( 65535 583 65551 ) ( -65535 583 -65519 ) clip -16 -16 180 1 1 -( 65535 65542 -3296 ) ( 65535 -65528 -3296 ) ( -65535 -65528 -3296 ) clip -15 -7 180 1 1 -( 65535 -65528 -3304 ) ( 65535 65542 -3304 ) ( -65535 -65528 -3304 ) clip -15 -7 180 1 1 -} -// brush 2 -{ -( -2824 -65529 65567 ) ( -2824 65541 65567 ) ( -2824 65541 -65503 ) clip -21 32 -0 1 1 -( -2928 65541 65567 ) ( -2928 -65529 65567 ) ( -2928 65541 -65503 ) clip -21 32 -0 1 1 -( 65535 590 65567 ) ( -65535 590 65567 ) ( -65535 590 -65503 ) clip 48 -32 180 1 1 -( -65535 582 65567 ) ( 65535 582 65567 ) ( -65535 582 -65503 ) clip 48 -32 180 1 1 -( 65535 65541 -3280 ) ( 65535 -65529 -3280 ) ( -65535 -65529 -3280 ) clip 49 -6 180 1 1 -( 65535 -65529 -3288 ) ( 65535 65541 -3288 ) ( -65535 -65529 -3288 ) clip 49 -6 180 1 1 -} -// brush 3 -{ -( -2824 -65530 65583 ) ( -2824 65540 65583 ) ( -2824 65540 -65487 ) clip -20 48 -0 1 1 -( -2928 65540 65583 ) ( -2928 -65530 65583 ) ( -2928 65540 -65487 ) clip -20 48 -0 1 1 -( 65535 589 65583 ) ( -65535 589 65583 ) ( -65535 589 -65487 ) clip 48 -48 180 1 1 -( -65535 581 65583 ) ( 65535 581 65583 ) ( -65535 581 -65487 ) clip 48 -48 180 1 1 -( 65535 65540 -3264 ) ( 65535 -65530 -3264 ) ( -65535 -65530 -3264 ) clip 49 -5 180 1 1 -( 65535 -65530 -3272 ) ( 65535 65540 -3272 ) ( -65535 -65530 -3272 ) clip 49 -5 180 1 1 -} -// brush 4 -{ -( -2824 -65531 65599 ) ( -2824 65539 65599 ) ( -2824 65539 -65471 ) clip -19 -0 -0 1 1 -( -2928 65539 65599 ) ( -2928 -65531 65599 ) ( -2928 65539 -65471 ) clip -19 -0 -0 1 1 -( 65535 588 65599 ) ( -65535 588 65599 ) ( -65535 588 -65471 ) clip 48 -0 180 1 1 -( -65535 580 65599 ) ( 65535 580 65599 ) ( -65535 580 -65471 ) clip 48 -0 180 1 1 -( 65535 65539 -3248 ) ( 65535 -65531 -3248 ) ( -65535 -65531 -3248 ) clip 49 -4 180 1 1 -( 65535 -65531 -3256 ) ( 65535 65539 -3256 ) ( -65535 -65531 -3256 ) clip 49 -4 180 1 1 -} -// brush 5 -{ -( -2824 -65532 65615 ) ( -2824 65538 65615 ) ( -2824 65538 -65455 ) clip -18 16 -0 1 1 -( -2928 65538 65615 ) ( -2928 -65532 65615 ) ( -2928 65538 -65455 ) clip -18 16 -0 1 1 -( 65535 587 65615 ) ( -65535 587 65615 ) ( -65535 587 -65455 ) clip 48 -16 180 1 1 -( -65535 579 65615 ) ( 65535 579 65615 ) ( -65535 579 -65455 ) clip 48 -16 180 1 1 -( 65535 65538 -3232 ) ( 65535 -65532 -3232 ) ( -65535 -65532 -3232 ) clip 49 -3 180 1 1 -( 65535 -65532 -3240 ) ( 65535 65538 -3240 ) ( -65535 -65532 -3240 ) clip 49 -3 180 1 1 -} -// brush 6 -{ -( -2824 -65533 65631 ) ( -2824 65537 65631 ) ( -2824 65537 -65439 ) clip -17 32 -0 1 1 -( -2928 65537 65631 ) ( -2928 -65533 65631 ) ( -2928 65537 -65439 ) clip -17 32 -0 1 1 -( 65535 586 65631 ) ( -65535 586 65631 ) ( -65535 586 -65439 ) clip 48 -32 180 1 1 -( -65535 578 65631 ) ( 65535 578 65631 ) ( -65535 578 -65439 ) clip 48 -32 180 1 1 -( 65535 65537 -3216 ) ( 65535 -65533 -3216 ) ( -65535 -65533 -3216 ) clip 49 -2 180 1 1 -( 65535 -65533 -3224 ) ( 65535 65537 -3224 ) ( -65535 -65533 -3224 ) clip 49 -2 180 1 1 -} -// brush 7 -{ -( -2824 -65534 65647 ) ( -2824 65536 65647 ) ( -2824 65536 -65423 ) clip -16 48 -0 1 1 -( -2928 65536 65647 ) ( -2928 -65534 65647 ) ( -2928 65536 -65423 ) clip -16 48 -0 1 1 -( 65535 585 65647 ) ( -65535 585 65647 ) ( -65535 585 -65423 ) clip 48 -48 180 1 1 -( -65535 577 65647 ) ( 65535 577 65647 ) ( -65535 577 -65423 ) clip 48 -48 180 1 1 -( 65535 65536 -3200 ) ( 65535 -65534 -3200 ) ( -65535 -65534 -3200 ) clip 49 -1 180 1 1 -( 65535 -65534 -3208 ) ( 65535 65536 -3208 ) ( -65535 -65534 -3208 ) clip 49 -1 180 1 1 -} -// brush 8 -{ -( -2824 -65535 65663 ) ( -2824 65535 65663 ) ( -2824 65535 -65407 ) clip -15 -0 -0 1 1 -( -2928 65535 65663 ) ( -2928 -65535 65663 ) ( -2928 65535 -65407 ) clip -15 -0 -0 1 1 -( 65535 584 65663 ) ( -65535 584 65663 ) ( -65535 584 -65407 ) clip 48 -0 180 1 1 -( -65535 576 65663 ) ( 65535 576 65663 ) ( -65535 576 -65407 ) clip 48 -0 180 1 1 -( 65535 65535 -3184 ) ( 65535 -65535 -3184 ) ( -65535 -65535 -3184 ) clip 49 -0 180 1 1 -( 65535 -65535 -3192 ) ( 65535 65535 -3192 ) ( -65535 -65535 -3192 ) clip 49 -0 180 1 1 -} -} -// entity 93 -{ -"origin" "320 1887 -3888" -"light" "500" -"classname" "light" -} -// entity 94 -{ -"origin" "1184 1871 -3440" -"light" "200" -"classname" "light" -} -// entity 95 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "side" -"_tb_id" "422" -// brush 0 -{ -( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal4_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 32 -16 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 -} -// brush 1 -{ -( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 65359 2272 65535 ) ( -65711 2272 65535 ) ( -65711 2272 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 -( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -16 -0 1 1 -} -// brush 2 -{ -( 1584 -63119 65535 ) ( 1584 67951 65535 ) ( 1584 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 1568 67951 65535 ) ( 1568 -63119 65535 ) ( 1568 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 -0 -0 180 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal1_4 -0 48 90 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 -0 48 90 1 1 -} -// brush 3 -{ -( 1584 2272 -3472 ) ( 1584 2416 -3456 ) ( 1584 2416 -3472 ) metal1_4 -0 -0 -0 1 1 -( 1568 2272 -3472 ) ( 1568 2416 -3456 ) ( 1568 2272 -3456 ) metal1_4 -0 -0 -0 1 1 -( 1568 2432 -3472 ) ( 1584 2432 -3456 ) ( 1568 2432 -3456 ) metal1_4 32 -0 -0 1 1 -( 1568 2272 -3472 ) ( 1584 2272 -3456 ) ( 1584 2272 -3472 ) metal1_4 32 -0 -0 1 1 -( 1568 2272 -3344 ) ( 1584 2416 -3344 ) ( 1584 2272 -3344 ) metal1_4 32 -0 -0 1 1 -( 1568 2272 -3472 ) ( 1584 2416 -3472 ) ( 1568 2416 -3472 ) metal1_4 32 -0 -0 1 1 -} -// brush 4 -{ -( 3040 2416 -3472 ) ( 3040 2432 -3456 ) ( 3040 2432 -3472 ) metal1_4 -0 -0 -0 1 1 -( 1584 2416 -3472 ) ( 1584 2432 -3456 ) ( 1584 2416 -3456 ) metal1_4 -0 -0 -0 1 1 -( 1584 2432 -3472 ) ( 1712 2432 -3456 ) ( 1584 2432 -3456 ) metal1_4 32 -0 -0 1 1 -( 1584 2416 -3472 ) ( 1712 2416 -3456 ) ( 1712 2416 -3472 ) metal1_4 32 -0 -0 1 1 -( 1584 2416 -3120 ) ( 1712 2432 -3120 ) ( 1712 2416 -3120 ) metal1_4 32 -0 -0 1 1 -( 1584 2416 -3472 ) ( 1712 2432 -3472 ) ( 1584 2432 -3472 ) metal1_4 32 -0 -0 1 1 -} -// brush 5 -{ -( 1904 -63119 65535 ) ( 1904 67951 65535 ) ( 1904 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 1680 67951 65535 ) ( 1680 -63119 65535 ) ( 1680 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) metal1_4 32 -16 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -16 -0 1 1 -} -// brush 6 -{ -( 1680 -63119 65535 ) ( 1680 67951 65535 ) ( 1680 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3360 ) ( 65359 67951 -3360 ) ( -65711 -63119 -3360 ) metal1_4 32 -0 -0 1 1 -} -// brush 7 -{ -( 1680 -63119 65535 ) ( 1680 67951 65535 ) ( 1680 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal4_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -3328 ) ( 65359 -63119 -3328 ) ( -65711 -63119 -3328 ) metal4_4 32 -16 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 -} -// brush 8 -{ -( 1680 -63119 65535 ) ( 1680 67951 65535 ) ( 1680 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 1664 67951 65535 ) ( 1664 -63119 65535 ) ( 1664 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -0 -0 1 1 -( 65359 67951 -3360 ) ( 65359 -63119 -3360 ) ( -65711 -63119 -3360 ) metal1_4 -0 48 90 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 -0 48 90 1 1 -} -// brush 9 -{ -( 1904 -63119 65535 ) ( 1904 67951 65535 ) ( 1904 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal4_4 32 -0 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal4_4 32 -16 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) metal4_4 32 -16 -0 1 1 -} -// brush 10 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 1984 67951 65535 ) ( 1984 -63119 65535 ) ( 1984 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 32 -16 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal4_4 32 -16 -0 1 1 -} -// brush 11 -{ -( 1984 -63119 65535 ) ( 1984 67951 65535 ) ( 1984 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 1968 67951 65535 ) ( 1968 -63119 65535 ) ( 1968 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 65359 2160 65535 ) ( -65711 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 -0 -0 180 1 1 -( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 -0 48 90 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal4_4 -0 48 90 1 1 -} -} -// entity 96 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "test" -"_tb_id" "423" -"_tb_group" "422" -// brush 0 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 32 -0 -0 1 1 -( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 32 -16 -0 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) metal4_4 32 -16 -0 1 1 -} -// brush 1 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 32 -0 -0 1 1 -( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal4_4 32 -16 -0 1 1 -} -// brush 2 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 3328 67951 65535 ) ( 3328 -63119 65535 ) ( 3328 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 -0 -0 180 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal4_4 -0 -0 180 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal4_4 -0 48 90 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) metal4_4 -0 48 90 1 1 -} -} -// entity 97 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "test" -"_tb_id" "424" -"_tb_group" "423" -// brush 0 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal1_4 32 -0 -0 1 1 -} -// brush 1 -{ -( 60213 -63118 25762 ) ( 60213 67950 25762 ) ( -57019 -63118 -32853 ) metal1_4 32 -0 -0 1 1 -( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3360 ) ( 65359 67951 -3360 ) ( -65711 -63119 -3360 ) metal1_4 32 -0 -0 1 1 -} -// brush 2 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 1584 67951 65535 ) ( 1584 -63119 65535 ) ( 1584 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 2160 65535 ) ( 65359 2160 65535 ) ( -65711 2160 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3456 ) ( 65359 -63119 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) metal1_4 32 -0 -0 1 1 -} -// brush 3 -{ -( 2848 -63119 65535 ) ( 2848 67951 65535 ) ( 2848 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 60251 67950 25685 ) ( 60251 -63118 25685 ) ( -56981 -63118 -32930 ) metal1_4 32 -0 -0 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3296 ) ( 65359 -63119 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal1_4 32 -0 -0 1 1 -} -// brush 4 -{ -( 57704 67950 -30780 ) ( 57704 -63118 -30780 ) ( -59528 -63118 27836 ) metal1_4 32 -0 -0 1 1 -( 60251 67950 25685 ) ( 60251 -63118 25685 ) ( -56981 -63118 -32930 ) metal1_4 32 -0 -0 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 2256 65535 ) ( 65359 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3232 ) ( 65359 -63119 -3232 ) ( -65711 -63119 -3232 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3296 ) ( 65359 67951 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 -} -} -// entity 98 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "wdrop" -"_tb_id" "425" -// brush 0 -{ -( 2976 -63119 65535 ) ( 2976 67951 65535 ) ( 2976 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3296 ) ( 65359 -63119 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -0 -0 1 1 -} -// brush 1 -{ -( 53786 67951 -37201 ) ( 53786 -63119 -37201 ) ( -55270 -63119 35503 ) metal1_4 32 -0 -0 1 1 -( 2880 67951 65535 ) ( 2880 -63119 65535 ) ( 2880 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 -63119 -3296 ) ( 65359 67951 -3296 ) ( -65711 -63119 -3296 ) metal1_4 32 -0 -0 1 1 -} -// brush 2 -{ -( 2880 -63119 65535 ) ( 2880 67951 65535 ) ( 2880 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 -0 -0 180 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_4 -0 48 90 1 1 -( 65359 -63119 -3296 ) ( 65359 67951 -3296 ) ( -65711 -63119 -3296 ) metal1_4 -0 48 90 1 1 -} -// brush 3 -{ -( 56784 -63119 32704 ) ( 56784 67951 32704 ) ( -52272 -63119 -40000 ) metal1_4 32 -0 -0 1 1 -( 2880 67951 65535 ) ( 2880 -63119 65535 ) ( 2880 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 65359 2256 65535 ) ( -65711 2256 65535 ) ( -65711 2256 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -0 -0 1 1 -} -// brush 4 -{ -( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 2864 67951 65535 ) ( 2864 -63119 65535 ) ( 2864 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -0 -0 1 1 -} -// brush 5 -{ -( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -32 -0 180 1 1 -( 2976 67951 65535 ) ( 2976 -63119 65535 ) ( 2976 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -0 -0 1 1 -( -65711 1984 65535 ) ( 65359 1984 65535 ) ( -65711 1984 -65535 ) metal1_4 32 -0 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -16 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -16 -0 1 1 -} -// brush 6 -{ -( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -32 -48 180 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) rock5_2 64 -0 -0 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal1_4 32 -0 -0 1 1 -} -// brush 7 -{ -( 2992 -63119 65535 ) ( 2992 67951 65535 ) ( 2992 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 2976 67951 65535 ) ( 2976 -63119 65535 ) ( 2976 67951 -65535 ) metal1_4 -0 -0 -0 1 1 -( 65359 1984 65535 ) ( -65711 1984 65535 ) ( -65711 1984 -65535 ) metal1_4 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal1_4 32 -48 -0 1 1 -( 65359 67951 -3280 ) ( 65359 -63119 -3280 ) ( -65711 -63119 -3280 ) metal1_4 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal1_4 32 -0 -0 1 1 -} -// brush 8 -{ -( -46580 -63119 46276 ) ( -46580 67951 46276 ) ( 46100 67951 -46404 ) sfloor4_6 32 -0 -0 1 1 -( 2992 67951 65535 ) ( 2992 -63119 65535 ) ( 2992 67951 -65535 ) sfloor4_6 -32 -48 180 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -// brush 9 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) metal4_4 -32 -0 180 1 1 -( 2992 67951 65535 ) ( 2992 -63119 65535 ) ( 2992 67951 -65535 ) metal4_4 -0 -0 -0 1 1 -( 65359 2416 65535 ) ( -65711 2416 65535 ) ( -65711 2416 -65535 ) metal4_4 32 -0 -0 1 1 -( -65711 1968 65535 ) ( 65359 1968 65535 ) ( -65711 1968 -65535 ) metal4_4 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal4_4 32 -16 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) metal4_4 32 -16 -0 1 1 -} -// brush 10 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) *water2 -32 -48 180 1 1 -( -46580 67951 46276 ) ( -46580 -63119 46276 ) ( 46100 67951 -46404 ) *water2 32 -0 -0 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) *water2 32 -48 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) *water2 32 -48 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 -} -} -// entity 99 -{ -"origin" "2912 1839 -3248" -"light" "1000" -"classname" "light" -"_tb_group" "425" -} -// entity 100 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "fs" -"_tb_id" "426" -// brush 0 -{ -( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 32 -0 180 1 1 -( 3488 67951 65535 ) ( 3488 -63119 65535 ) ( 3488 67951 -65535 ) metal5r8 32 -0 180 1 1 -( 65359 -51019 -37991 ) ( 65359 58037 34712 ) ( -65711 -51019 -37991 ) metal5r8 32 48 -0 1 1 -( 65359 67951 -3136 ) ( 65359 -63119 -3136 ) ( -65711 -63119 -3136 ) metal5r8 32 48 -0 1 1 -} -// brush 1 -{ -( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 -0 -0 180 1 1 -( 65359 1264 65535 ) ( -65711 1264 65535 ) ( -65711 1264 -65535 ) metal5r8 -0 -0 -0 1 1 -( 65434 67950 -874 ) ( 65434 -63118 -874 ) ( -65548 67950 -5649 ) metal5r8 -0 48 -0 1 1 -( 65359 -63119 -3136 ) ( 65359 67951 -3136 ) ( -65711 -63119 -3136 ) metal5r8 -0 32 -0 1 1 -} -// brush 2 -{ -( -44060 -46380 65535 ) ( 48620 46300 65535 ) ( 48620 46300 -65535 ) metal5r8 -0 -16 180 1 1 -( -45308 49964 65535 ) ( 47372 -42716 65535 ) ( -45308 49964 -65535 ) metal5r8 -0 -16 180 1 1 -( 65359 1264 65535 ) ( -65711 1264 65535 ) ( -65711 1264 -65535 ) metal5r8 32 -0 -0 1 1 -( 65359 67951 -3120 ) ( 65359 -63119 -3120 ) ( -65711 -63119 -3120 ) metal5r8 -0 32 -0 1 1 -( 65434 -63118 -874 ) ( 65434 67950 -874 ) ( -65548 67950 -5649 ) metal5r8 -0 32 -0 1 1 -} -// brush 3 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal5r8 32 -48 180 1 1 -( 2640 67951 65535 ) ( 2640 -63119 65535 ) ( 2640 67951 -65535 ) metal5r8 32 -48 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 -( -65711 1536 65535 ) ( 65359 1536 65535 ) ( -65711 1536 -65535 ) metal5r8 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 -} -// brush 4 -{ -( 2760 -63119 65535 ) ( 2760 67951 65535 ) ( 2760 67951 -65535 ) metal1_3 -0 -0 -0 1 1 -( 2752 67951 65535 ) ( 2752 -63119 65535 ) ( 2752 67951 -65535 ) metal1_3 -0 -0 -0 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) metal1_3 32 -0 -0 1 1 -} -// brush 5 -{ -( 2648 -63119 65535 ) ( 2648 67951 65535 ) ( 2648 67951 -65535 ) metal1_3 -0 -0 -0 1 1 -( 2640 67951 65535 ) ( 2640 -63119 65535 ) ( 2640 67951 -65535 ) metal1_3 -0 -0 -0 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) metal1_3 32 -0 -0 1 1 -( -65711 1528 65535 ) ( 65359 1528 65535 ) ( -65711 1528 -65535 ) metal1_3 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal1_3 32 -0 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) metal1_3 32 -0 -0 1 1 -} -} -// entity 101 -{ -"origin" "3840 575 -3080" -"light" "1000" -"classname" "light" -"_tb_group" "426" -} -// entity 102 -{ -"origin" "3840 1631 -3080" -"light" "1000" -"classname" "light" -"_tb_group" "426" -} -// entity 103 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "ladder" -"_tb_id" "427" -"_tb_group" "426" -// brush 0 -{ -( 2752 66487 -72055 ) ( 2752 -64583 -72055 ) ( 2752 66487 59015 ) clip -7 -8 -0 1 -1 -( 2648 -64583 -72055 ) ( 2648 66487 -72055 ) ( 2648 66487 59015 ) clip -7 -8 -0 1 -1 -( -65711 1536 -72055 ) ( 65359 1536 -72055 ) ( 65359 1536 59015 ) clip 32 8 -0 1 1 -( 65359 1528 -72055 ) ( -65711 1528 -72055 ) ( 65359 1528 59015 ) clip 32 8 -0 1 1 -( -65711 -64583 -3200 ) ( -65711 66487 -3200 ) ( 65359 -64583 -3200 ) clip 33 -56 -0 1 -1 -( -65711 66487 -3208 ) ( -65711 -64583 -3208 ) ( 65359 -64583 -3208 ) clip 33 -56 -0 1 -1 -} -// brush 1 -{ -( 2752 66486 -72071 ) ( 2752 -64584 -72071 ) ( 2752 66486 58999 ) clip -6 -56 -0 1 -1 -( 2648 -64584 -72071 ) ( 2648 66486 -72071 ) ( 2648 66486 58999 ) clip -6 -56 -0 1 -1 -( -65711 1535 -72071 ) ( 65359 1535 -72071 ) ( 65359 1535 58999 ) clip 32 56 -0 1 1 -( 65359 1527 -72071 ) ( -65711 1527 -72071 ) ( 65359 1527 58999 ) clip 32 56 -0 1 1 -( -65711 -64584 -3216 ) ( -65711 66486 -3216 ) ( 65359 -64584 -3216 ) clip 33 -55 -0 1 -1 -( -65711 66486 -3224 ) ( -65711 -64584 -3224 ) ( 65359 -64584 -3224 ) clip 33 -55 -0 1 -1 -} -// brush 2 -{ -( 2752 66485 -72087 ) ( 2752 -64585 -72087 ) ( 2752 66485 58983 ) clip -5 -40 -0 1 -1 -( 2648 -64585 -72087 ) ( 2648 66485 -72087 ) ( 2648 66485 58983 ) clip -5 -40 -0 1 -1 -( -65711 1534 -72087 ) ( 65359 1534 -72087 ) ( 65359 1534 58983 ) clip 32 40 -0 1 1 -( 65359 1526 -72087 ) ( -65711 1526 -72087 ) ( 65359 1526 58983 ) clip 32 40 -0 1 1 -( -65711 -64585 -3232 ) ( -65711 66485 -3232 ) ( 65359 -64585 -3232 ) clip 33 -54 -0 1 -1 -( -65711 66485 -3240 ) ( -65711 -64585 -3240 ) ( 65359 -64585 -3240 ) clip 33 -54 -0 1 -1 -} -// brush 3 -{ -( 2752 66484 -72103 ) ( 2752 -64586 -72103 ) ( 2752 66484 58967 ) clip -4 -24 -0 1 -1 -( 2648 -64586 -72103 ) ( 2648 66484 -72103 ) ( 2648 66484 58967 ) clip -4 -24 -0 1 -1 -( -65711 1533 -72103 ) ( 65359 1533 -72103 ) ( 65359 1533 58967 ) clip 32 24 -0 1 1 -( 65359 1525 -72103 ) ( -65711 1525 -72103 ) ( 65359 1525 58967 ) clip 32 24 -0 1 1 -( -65711 -64586 -3248 ) ( -65711 66484 -3248 ) ( 65359 -64586 -3248 ) clip 33 -53 -0 1 -1 -( -65711 66484 -3256 ) ( -65711 -64586 -3256 ) ( 65359 -64586 -3256 ) clip 33 -53 -0 1 -1 -} -// brush 4 -{ -( 2752 66483 -72119 ) ( 2752 -64587 -72119 ) ( 2752 66483 58951 ) clip -3 -8 -0 1 -1 -( 2648 -64587 -72119 ) ( 2648 66483 -72119 ) ( 2648 66483 58951 ) clip -3 -8 -0 1 -1 -( -65711 1532 -72119 ) ( 65359 1532 -72119 ) ( 65359 1532 58951 ) clip 32 8 -0 1 1 -( 65359 1524 -72119 ) ( -65711 1524 -72119 ) ( 65359 1524 58951 ) clip 32 8 -0 1 1 -( -65711 -64587 -3264 ) ( -65711 66483 -3264 ) ( 65359 -64587 -3264 ) clip 33 -52 -0 1 -1 -( -65711 66483 -3272 ) ( -65711 -64587 -3272 ) ( 65359 -64587 -3272 ) clip 33 -52 -0 1 -1 -} -// brush 5 -{ -( 2752 66482 -72135 ) ( 2752 -64588 -72135 ) ( 2752 66482 58935 ) clip -2 -56 -0 1 -1 -( 2648 -64588 -72135 ) ( 2648 66482 -72135 ) ( 2648 66482 58935 ) clip -2 -56 -0 1 -1 -( -65711 1531 -72135 ) ( 65359 1531 -72135 ) ( 65359 1531 58935 ) clip 32 56 -0 1 1 -( 65359 1523 -72135 ) ( -65711 1523 -72135 ) ( 65359 1523 58935 ) clip 32 56 -0 1 1 -( -65711 -64588 -3280 ) ( -65711 66482 -3280 ) ( 65359 -64588 -3280 ) clip 33 -51 -0 1 -1 -( -65711 66482 -3288 ) ( -65711 -64588 -3288 ) ( 65359 -64588 -3288 ) clip 33 -51 -0 1 -1 -} -// brush 6 -{ -( 2752 66481 -72151 ) ( 2752 -64589 -72151 ) ( 2752 66481 58919 ) clip -1 -40 -0 1 -1 -( 2648 -64589 -72151 ) ( 2648 66481 -72151 ) ( 2648 66481 58919 ) clip -1 -40 -0 1 -1 -( -65711 1530 -72151 ) ( 65359 1530 -72151 ) ( 65359 1530 58919 ) clip 32 40 -0 1 1 -( 65359 1522 -72151 ) ( -65711 1522 -72151 ) ( 65359 1522 58919 ) clip 32 40 -0 1 1 -( -65711 -64589 -3296 ) ( -65711 66481 -3296 ) ( 65359 -64589 -3296 ) clip 33 -50 -0 1 -1 -( -65711 66481 -3304 ) ( -65711 -64589 -3304 ) ( 65359 -64589 -3304 ) clip 33 -50 -0 1 -1 -} -// brush 7 -{ -( 2752 66480 -72167 ) ( 2752 -64590 -72167 ) ( 2752 66480 58903 ) clip -0 -24 -0 1 -1 -( 2648 -64590 -72167 ) ( 2648 66480 -72167 ) ( 2648 66480 58903 ) clip -0 -24 -0 1 -1 -( -65711 1529 -72167 ) ( 65359 1529 -72167 ) ( 65359 1529 58903 ) clip 32 24 -0 1 1 -( 65359 1521 -72167 ) ( -65711 1521 -72167 ) ( 65359 1521 58903 ) clip 32 24 -0 1 1 -( -65711 -64590 -3312 ) ( -65711 66480 -3312 ) ( 65359 -64590 -3312 ) clip 33 -49 -0 1 -1 -( -65711 66480 -3320 ) ( -65711 -64590 -3320 ) ( 65359 -64590 -3320 ) clip 33 -49 -0 1 -1 -} -// brush 8 -{ -( 2752 66479 -72183 ) ( 2752 -64591 -72183 ) ( 2752 66479 58887 ) clip -63 -8 -0 1 -1 -( 2648 -64591 -72183 ) ( 2648 66479 -72183 ) ( 2648 66479 58887 ) clip -63 -8 -0 1 -1 -( -65711 1528 -72183 ) ( 65359 1528 -72183 ) ( 65359 1528 58887 ) clip 32 8 -0 1 1 -( 65359 1520 -72183 ) ( -65711 1520 -72183 ) ( 65359 1520 58887 ) clip 32 8 -0 1 1 -( -65711 -64591 -3328 ) ( -65711 66479 -3328 ) ( 65359 -64591 -3328 ) clip 33 -48 -0 1 -1 -( -65711 66479 -3336 ) ( -65711 -64591 -3336 ) ( 65359 -64591 -3336 ) clip 33 -48 -0 1 -1 -} -} -// entity 104 -{ -"origin" "2528 1631 -3216" -"light" "500" -"classname" "light" } -// entity 105 -{ -"origin" "1216 1695 -2896" -"light" "500" -"classname" "light" -} -// entity 106 -{ -"speed" "100" -"delay" "2" -"style" "32" -"angle" "-1" -"classname" "trigger_push" -// brush 0 -{ -( 1488 -63119 65535 ) ( 1488 67951 65535 ) ( 1488 67951 -65535 ) city6_8 -0 -0 -0 1 1 -( 1424 67951 65535 ) ( 1424 -63119 65535 ) ( 1424 67951 -65535 ) city6_8 -0 -0 -0 1 1 -( 65359 1696 65535 ) ( -65711 1696 65535 ) ( -65711 1696 -65535 ) city6_8 32 -0 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) city6_8 32 -0 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) city6_8 32 -0 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) city6_8 32 -0 -0 1 1 -} -} -// entity 107 -{ -"origin" "1456 1695 -3424" -"light" "150" -"classname" "light" -} -// entity 108 + +// entity 67 { -"origin" "1216 2127 -2896" -"light" "500" -"classname" "light" +"origin" "-3504 1007 -3100" +"g_a" "4789" +"owned_by" "1" +"netname" "Blue Flag" +"message" "You have their flag.\nTake it home!\n" +"noise" "ogre/ogwake.wav" +"n_b" " picked up blue's flag.\n" +"items" "131072" +"noise3" "Your flag returned.\n" +"goal_no" "1" +"noise4" "Their flag returned.\n" +"delay" "60" +"pausetime" "60" +"team_no" "2" +"skin" "1" +"mdl" "progs/tf_flag.mdl" +"angle" "135" +"classname" "item_tfgoal" +"team_broadcast" "Your team got their flag.\n" +"non_team_broadcast" "Your flag has been taken!\n" +"d_n_n" " dropped blue's flag.\n" } -// entity 109 -{ -"speed" "200" -"delay" "2" -"style" "32" -"angle" "360" -"classname" "trigger_push" -// brush 0 +// entity 68 { -( 1920 -63119 65535 ) ( 1920 67951 65535 ) ( 1920 67951 -65535 ) metal3_2 -0 -0 -0 1 1 -( 1888 67951 65535 ) ( 1888 -63119 65535 ) ( 1888 67951 -65535 ) metal3_2 -0 -0 -0 1 1 -( 65359 1968 65535 ) ( -65711 1968 65535 ) ( -65711 1968 -65535 ) metal3_2 32 -0 -0 1 1 -( -65711 1664 65535 ) ( 65359 1664 65535 ) ( -65711 1664 -65535 ) metal3_2 32 -0 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) metal3_2 32 -0 -0 1 1 -( 65359 -63119 -3456 ) ( 65359 67951 -3456 ) ( -65711 -63119 -3456 ) metal3_2 32 -0 -0 1 1 -} +"origin" "-272 935 -3184" +"classname" "info_player_start" } -// entity 110 +// entity 69 { -"origin" "1952 2127 -2896" -"light" "500" -"classname" "light" +"origin" "-208 1280 -3168" +"impulse" "196" +"display_item_status1" "1" +"display_item_status2" "2" +"team_str_home" "Your flag is in your base.\n" +"team_str_moved" "Your flag is lying around." +"team_str_carried" "Your flag is being carried by\n" +"non_team_str_home" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is in their base.\n" +"non_team_str_moved" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is lying around." +"non_team_str_carried" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is being carried by\n" +"hook_out" "1" +"non_team_broadcast" "Get the enemy flag and take it to your tower!\n" +"classname" "info_tfdetect" } -// entity 111 + +// entity 71 { -"origin" "2016 1791 -3264" -"light" "500" -"classname" "light" +"origin" "-2656 1040 -3296" +"noise" "edge/backpack.wav" +"wait" "2" +"ammo_medikit" "100" +"ammo_cells" "200" +"ammo_rockets" "50" +"ammo_nails" "100" +"ammo_shells" "100" +"health" "50" +"armorvalue" "100" +"goal_effects" "1" +"goal_activation" "1" +"mdl" "progs/backpack.mdl" +"netname" "blue_pak1" +"armortype" "0.8" +"classname" "info_tfgoal" } -// entity 112 + +// entity 82 { -"origin" "3104 1103 -3248" -"light" "500" -"classname" "light" +"origin" "-784 1040 -3040" +"frags" "10" +"b_o" "Your flag was captured.\n" +"count" "10" +"b_t" "Your team captured their flag.\n" +"g_e" "19" +"n_b" " captured red's flag.\n" +"noise" "items/cap1.wav" +"axhitme" "2" +"message" "You captured their flag.\n" +"items_allowed" "2" +"owned_by" "2" +"target" "cap1" +"g_a" "1" +"classname" "info_tfgoal" } -// entity 113 +// entity 83 { -"origin" "3392 767 -3088" -"light" "500" +"origin" "1624 2327 -3400" +"light" "150" "classname" "light" } + // entity 114 { "origin" "3328 1103 -3100" @@ -5062,431 +123,7 @@ "n_b" " picked up red's flag.\n" "d_n_n" " dropped red's flag.\n" } -// entity 115 -{ -"origin" "3472 1103 -2896" -"light" "1000" -"classname" "light" -} -// entity 116 -{ -"origin" "3392 1439 -3088" -"light" "500" -"classname" "light" -} -// entity 117 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "flag" -"_tb_id" "428" -// brush 0 -{ -( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 1424 65535 ) ( -65711 1424 65535 ) ( -65711 1424 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1408 65535 ) ( 65359 1408 65535 ) ( -65711 1408 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 -} -// brush 1 -{ -( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2624 67951 65535 ) ( 2624 -63119 65535 ) ( 2624 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1536 65535 ) ( -65711 1536 65535 ) ( -65711 1536 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1424 65535 ) ( 65359 1424 65535 ) ( -65711 1424 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 -0 48 90 1 1 -} -// brush 2 -{ -( 48395 -41606 65535 ) ( -46629 48667 65535 ) ( -46629 48667 -65535 ) metal5r8 32 -0 -0 1 1 -( 64818 -63119 9194 ) ( 64818 67951 9194 ) ( -63706 -63119 -16510 ) metal5r8 32 -0 -0 1 1 -( 2640 67951 65535 ) ( 2640 -63119 65535 ) ( 2640 67951 -65535 ) metal5r8 32 -48 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 -( -65711 1536 65535 ) ( 65359 1536 65535 ) ( -65711 1536 -65535 ) metal5r8 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 -0 -0 1 1 -} -// brush 3 -{ -( 3200 -63119 65535 ) ( 3200 67951 65535 ) ( 3200 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) city4_7 -0 48 90 1 1 -} -// brush 4 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) city4_7 32 -0 180 1 1 -( 2848 67951 65535 ) ( 2848 -63119 65535 ) ( 2848 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 -} -// brush 5 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) city4_7 32 -48 180 1 1 -( 3200 67951 65535 ) ( 3200 -63119 65535 ) ( 3200 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) city4_7 32 -0 -0 1 1 -} -// brush 6 -{ -( 3328 -63119 65535 ) ( 3328 67951 65535 ) ( 3328 67951 -65535 ) *water2 32 -48 180 1 1 -( 3200 67951 65535 ) ( 3200 -63119 65535 ) ( 3200 67951 -65535 ) *water2 32 -48 180 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) *water2 32 -48 -0 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) *water2 32 -48 -0 1 1 -( 65359 67951 -3344 ) ( 65359 -63119 -3344 ) ( -65711 -63119 -3344 ) *water2 32 -0 -0 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) *water2 32 -0 -0 1 1 -} -// brush 7 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 3328 67951 65535 ) ( 3328 -63119 65535 ) ( 3328 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 1648 65535 ) ( 65359 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3440 ) ( 65359 67951 -3440 ) ( -65711 -63119 -3440 ) city4_7 -0 48 90 1 1 -} -// brush 8 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) sfloor4_6 32 -48 180 1 1 -( 52917 -63119 -38432 ) ( 52917 67951 -38432 ) ( -54459 -63119 36731 ) sfloor4_6 32 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) sfloor4_6 32 -48 -0 1 1 -( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) sfloor4_6 32 -48 -0 1 1 -( 65359 67951 -3440 ) ( 65359 -63119 -3440 ) ( -65711 -63119 -3440 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3936 ) ( 65359 67951 -3936 ) ( -65711 -63119 -3936 ) sfloor4_6 32 -0 -0 1 1 -} -} -// entity 118 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "flag" -"_tb_id" "429" -"_tb_group" "428" -// brush 0 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 912 65535 ) ( -65711 912 65535 ) ( -65711 912 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 -} -// brush 1 -{ -( 2624 -63119 65535 ) ( 2624 67951 65535 ) ( 2624 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 32 -48 180 1 1 -( 65359 1008 65535 ) ( -65711 1008 65535 ) ( -65711 1008 -65535 ) metal5r8 32 -48 -0 1 1 -( -65711 672 65535 ) ( 65359 672 65535 ) ( -65711 672 -65535 ) metal5r8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 -} -// brush 2 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) city4_7 32 -0 -0 1 1 -} -// brush 3 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1424 65535 ) ( -65711 1424 65535 ) ( -65711 1424 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 -} -// brush 4 -{ -( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 32 -48 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 32 -48 -0 1 1 -( -65711 1408 65535 ) ( 65359 1408 65535 ) ( -65711 1408 -65535 ) metal5r8 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3200 ) ( 65359 67951 -3200 ) ( -65711 -63119 -3200 ) metal5r8 32 -0 -0 1 1 -} -// brush 5 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1520 65535 ) ( 65359 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3072 ) ( 65359 -63119 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3184 ) ( 65359 67951 -3184 ) ( -65711 -63119 -3184 ) city4_7 32 48 -0 1 1 -} -// brush 6 -{ -( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) metal5r8 -0 -0 180 1 1 -( -65711 1408 65535 ) ( 65359 1408 65535 ) ( -65711 1408 -65535 ) metal5r8 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 -0 -0 1 1 -} -// brush 7 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 32 -48 -0 1 1 -( -65711 1312 65535 ) ( 65359 1312 65535 ) ( -65711 1312 -65535 ) city4_7 32 -48 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 8 -{ -( 2512 -63119 65535 ) ( 2512 67951 65535 ) ( 2512 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1168 65535 ) ( -65711 1168 65535 ) ( -65711 1168 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1008 65535 ) ( 65359 1008 65535 ) ( -65711 1008 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 48 -0 1 1 -} -// brush 9 -{ -( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2624 67951 65535 ) ( 2624 -63119 65535 ) ( 2624 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1008 65535 ) ( -65711 1008 65535 ) ( -65711 1008 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 816 65535 ) ( 65359 816 65535 ) ( -65711 816 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 10 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city4_7 32 -0 180 1 1 -( 2496 67951 65535 ) ( 2496 -63119 65535 ) ( 2496 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 560 65535 ) ( -65711 560 65535 ) ( -65711 560 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) city4_7 32 48 -0 1 1 -} -// brush 11 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) metal5r8 32 -16 180 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) metal5r8 32 -16 180 1 1 -( 65359 672 65535 ) ( -65711 672 65535 ) ( -65711 672 -65535 ) metal5r8 32 -0 -0 1 1 -( -65711 560 65535 ) ( 65359 560 65535 ) ( -65711 560 -65535 ) metal5r8 32 -16 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) metal5r8 32 32 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) metal5r8 32 32 -0 1 1 -} -// brush 12 -{ -( 2528 -63119 65535 ) ( 2528 67951 65535 ) ( 2528 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) city4_7 32 -48 180 1 1 -( 65359 1344 65535 ) ( -65711 1344 65535 ) ( -65711 1344 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1136 65535 ) ( 65359 1136 65535 ) ( -65711 1136 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) city4_7 32 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -// brush 13 -{ -( 2640 -63119 65535 ) ( 2640 67951 65535 ) ( 2640 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 2512 67951 65535 ) ( 2512 -63119 65535 ) ( 2512 67951 -65535 ) city4_7 32 -0 180 1 1 -( 65359 1024 65535 ) ( -65711 1024 65535 ) ( -65711 1024 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 1008 65535 ) ( 65359 1008 65535 ) ( -65711 1008 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 32 48 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) city4_7 32 -0 -0 1 1 -} -} -// entity 119 -{ -"origin" "2256 927 -3216" -"light" "500" -"classname" "light" -"_tb_group" "429" -} -// entity 120 -{ -"origin" "2528 575 -3088" -"light" "500" -"classname" "light" -"_tb_group" "429" -} -// entity 121 -{ -"team_no" "2" -"health" "0" -"dmg" "500" -"lip" "0" -"wait" "1" -"sounds" "1" -"speed" "200" -"angle" "90" -"classname" "func_door" -"_tb_group" "429" -// brush 0 -{ -( 2511 -63119 65535 ) ( 2511 67951 65535 ) ( 2511 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 2497 67951 65535 ) ( 2497 -63119 65535 ) ( 2497 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) adoor03_3 -0 -0 -0 1 1 -( -65711 1240 65535 ) ( 65359 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 -} -} -// entity 122 -{ -"team_no" "2" -"health" "0" -"dmg" "500" -"lip" "0" -"wait" "1" -"sounds" "1" -"speed" "200" -"angle" "270" -"classname" "func_door" -"_tb_group" "429" -// brush 0 -{ -( 2511 -63119 65535 ) ( 2511 67951 65535 ) ( 2511 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 2497 67951 65535 ) ( 2497 -63119 65535 ) ( 2497 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 1240 65535 ) ( -65711 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 -( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 -} -} -// entity 123 -{ -"origin" "2528 575 -2896" -"light" "500" -"classname" "light" -"_tb_group" "429" -} -// entity 124 -{ -"origin" "2528 1631 -3088" -"light" "500" -"classname" "light" -"_tb_group" "428" -} -// entity 125 -{ -"origin" "592 463 -2896" -"light" "500" -"classname" "light" -} -// entity 126 -{ -"origin" "992 1567 -3088" -"light" "500" -"classname" "light" -} -// entity 127 -{ -"origin" "1424 1407 -2992" -"light" "500" -"classname" "light" -} -// entity 128 -{ -"origin" "1616 463 -2896" -"light" "400" -"classname" "light" -} -// entity 129 -{ -"origin" "1120 463 -2896" -"light" "500" -"classname" "light" -} -// entity 130 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "frontred" -"_tb_id" "430" -// brush 0 -{ -( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) mmetal1_8 -0 -0 -0 1 1 -( 65359 1424 65535 ) ( -65711 1424 65535 ) ( -65711 1424 -65535 ) mmetal1_8 32 -48 -0 1 1 -( -65711 672 65535 ) ( 65359 672 65535 ) ( -65711 672 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3071 ) ( 65359 67951 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 1 -{ -( 576 -63119 65535 ) ( 576 67951 65535 ) ( 576 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 672 65535 ) ( -65711 672 65535 ) ( -65711 672 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city4_7 -0 -0 180 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 2 -{ -( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 672 65535 ) ( -65711 672 65535 ) ( -65711 672 -65535 ) mmetal1_8 32 -48 -0 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3071 ) ( 65359 67951 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 3 -{ -( 640 -64319 65535 ) ( 640 66751 65535 ) ( 640 66751 -65535 ) ecop1_1 -0 -0 -0 1 1 -( 576 66751 65535 ) ( 576 -64319 65535 ) ( 576 66751 -65535 ) ecop1_1 -0 -0 -0 1 1 -( 65871 1088 65535 ) ( -65199 1088 65535 ) ( -65199 1088 -65535 ) ecop1_1 48 -0 -0 1 1 -( -65199 1024 65535 ) ( 65871 1024 65535 ) ( -65199 1024 -65535 ) ecop1_1 48 -0 -0 1 1 -( 65871 66751 -3052 ) ( 65871 -64319 -3052 ) ( -65199 -64319 -3052 ) ecop1_1 48 -0 -0 1 1 -( 65871 -64319 -3056 ) ( 65871 66751 -3056 ) ( -65199 -64319 -3056 ) ecop1_1 48 -0 -0 1 1 -} -// brush 4 -{ -( 703 -63119 65535 ) ( 703 67951 65535 ) ( 703 67951 -65535 ) mmetal1_8 32 -48 180 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) mmetal1_8 32 -48 -0 1 1 -( -65711 1424 65535 ) ( 65359 1424 65535 ) ( -65711 1424 -65535 ) mmetal1_8 32 -48 -0 1 1 -( 65359 67951 -3056 ) ( 65359 -63119 -3056 ) ( -65711 -63119 -3056 ) mmetal1_8 32 -0 -0 1 1 -( 65359 -63119 -3071 ) ( 65359 67951 -3071 ) ( -65711 -63119 -3071 ) mmetal1_8 32 -0 -0 1 1 -} -// brush 5 -{ -( 576 -63119 65535 ) ( 576 67951 65535 ) ( 576 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1648 65535 ) ( -65711 1648 65535 ) ( -65711 1648 -65535 ) city4_7 -0 -0 180 1 1 -( -65711 1424 65535 ) ( 65359 1424 65535 ) ( -65711 1424 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -// brush 6 -{ -( 3856 -63119 65535 ) ( 3856 67951 65535 ) ( 3856 67951 -65535 ) city6_3 -0 -0 -0 1 1 -( 560 67951 65535 ) ( 560 -63119 65535 ) ( 560 67951 -65535 ) city6_3 -0 -0 -0 1 1 -( 65359 1664 65535 ) ( -65711 1664 65535 ) ( -65711 1664 -65535 ) city6_3 -0 -0 180 1 1 -( -65711 448 65535 ) ( 65359 448 65535 ) ( -65711 448 -65535 ) city6_3 -0 -0 180 1 1 -( 65359 67951 -2864 ) ( 65359 -63119 -2864 ) ( -65711 -63119 -2864 ) city6_3 32 -0 -0 1 1 -( 65359 -63119 -2880 ) ( 65359 67951 -2880 ) ( -65711 -63119 -2880 ) city6_3 32 -0 -0 1 1 -} -// brush 7 -{ -( 576 928 -2864 ) ( 576 1024 -2848 ) ( 576 1024 -2864 ) sky1 -0 -0 -0 1 1 -( 560 928 -2864 ) ( 560 1024 -2848 ) ( 560 928 -2848 ) sky1 -0 -0 -0 1 1 -( 560 1664 -2864 ) ( 576 1664 -2848 ) ( 560 1664 -2848 ) sky1 160 -0 -0 1 1 -( 560 448 -2864 ) ( 576 448 -2848 ) ( 576 448 -2864 ) sky1 160 -0 -0 1 1 -( 560 928 -2576 ) ( 576 1024 -2576 ) ( 576 928 -2576 ) sky1 160 -0 -0 1 1 -( 560 928 -2864 ) ( 576 1024 -2864 ) ( 560 1024 -2864 ) sky1 160 -0 -0 1 1 -} -// brush 8 -{ -( 720 -63119 65535 ) ( 720 67951 65535 ) ( 720 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 704 67951 65535 ) ( 704 -63119 65535 ) ( 704 67951 -65535 ) city4_7 -0 -0 -0 1 1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( -65711 1520 -65535 ) city4_7 32 -0 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) city4_7 32 -0 -0 1 1 -( 65359 67951 -2880 ) ( 65359 -63119 -2880 ) ( -65711 -63119 -2880 ) city4_7 -0 48 90 1 1 -( 65359 -63119 -3056 ) ( 65359 67951 -3056 ) ( -65711 -63119 -3056 ) city4_7 -0 48 90 1 1 -} -} + // entity 131 { "origin" "608 1056 -3040" From c4006d402e50506b29d822cb834a004edcbdcbfb Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 22 Nov 2018 23:54:25 +1100 Subject: [PATCH 0496/2474] fix encoded strings --- tfortmap.qc | 64 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 17b354db..551ccf8e 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1701,7 +1701,7 @@ void (entity Goal, entity AP, float addb) DoResults = { } else { CenterPrint2(te, "\n\n\n", - "Is that a flag in your pocket\nor a you just happy to see me?"); + "Is that a flag in your pocket\nor are you just happy to see me?"); } } } @@ -1710,15 +1710,15 @@ void (entity Goal, entity AP, float addb) DoResults = { } } else { CenterPrint2(te, "\n\n\n", - "Your team οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½οΏ½ flag!!"); + Q"Your team \sgot\s the \senemy\s flag!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your flag has been οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"Your flag has been \staken\s!!"); } te = find(te, classname, "player"); } - bprint(PRINT_HIGH, AP.netname, " οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); + bprint(PRINT_HIGH, AP.netname, Q" \sgot\s the \sblue\s flag!\n"); AP.items = AP.items | IT_KEY1; } else { if (Goal.goal_no == 2) { @@ -1755,7 +1755,7 @@ void (entity Goal, entity AP, float addb) DoResults = { } else { CenterPrint2(te, "\n\n\n", - "Is that a flag in your pocket\nor a you just happy to see me?"); + "Is that a flag in your pocket\nor are you just happy to see me?"); } } } @@ -1764,15 +1764,15 @@ void (entity Goal, entity AP, float addb) DoResults = { } } else { CenterPrint2(te, "\n\n\n", - "Your team οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½οΏ½ flag!!"); + Q"Your team \sgot\s the \senemy\s flag!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your flag has been οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"Your flag has been \staken\s!!"); } te = find(te, classname, "player"); } - bprint(PRINT_HIGH, AP.netname, " οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); + bprint(PRINT_HIGH, AP.netname, Q" \sgot\s the \sred\s flag!\n"); AP.items = AP.items | IT_KEY2; } else { if (Goal.goal_no == 3) { @@ -1781,19 +1781,19 @@ void (entity Goal, entity AP, float addb) DoResults = { if (te.team_no == 2) { if (te == AP) { CenterPrint2(te, "\n\n\n", - "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); + Q"You \scaptured\s the flag!!"); } else { CenterPrint2(te, "\n\n\n", - "Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"Your flag was \scaptured\s!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your team οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); + Q"Your team \scaptured\s the flag!!"); } te = find(te, classname, "player"); } bprint(PRINT_HIGH, AP.netname, - " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); + Q" \scaptured\s the \sred\s flag!\n"); AP.items = AP.items - (AP.items & IT_KEY2); } else { if (Goal.goal_no == 4) { @@ -1802,19 +1802,19 @@ void (entity Goal, entity AP, float addb) DoResults = { if (te.team_no == 1) { if (te == AP) { CenterPrint2(te, "\n\n\n", - "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); + Q"You \scaptured\s the flag!!"); } else { CenterPrint2(te, "\n\n\n", - "Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"Your flag was \scaptured\s!!"); } } else { CenterPrint2(te, "\n\n\n", - "Your team οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the flag!!"); + Q"Your team \scaptured\s the flag!!"); } te = find(te, classname, "player"); } bprint(PRINT_HIGH, AP.netname, - " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); + Q" \scaptured\s the \sblue\s flag!\n"); AP.items = AP.items - (AP.items & IT_KEY1); } } @@ -2009,15 +2009,15 @@ void () item_tfgoal_touch = { if (self.origin != self.oldorigin) { if (other.team_no == 1) { bprint(2, other.netname); - bprint(2, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); + bprint(2, Q" \scaptured\s the \sblue\s flag!\n"); te = find(world, classname, "player"); while (te != world) { if (te.team_no == 1) { CenterPrint2(te, "\n\n\n", - "Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"Your flag was \scaptured\s!!"); } else { CenterPrint2(te, "\n\n\n", - "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"The \senemy\s flag was \scaptured\s!!"); } te = find(te, classname, "player"); } @@ -2040,15 +2040,15 @@ void () item_tfgoal_touch = { if (self.origin != self.oldorigin) { if (other.team_no == 2) { bprint(2, other.netname); - bprint(2, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); + bprint(2, Q" \scaptured\s the \sred\s flag!\n"); te = find(world, classname, "player"); while (te != world) { if (te.team_no == 2) { CenterPrint(te, - "\n\n\n Your flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"\n\n\n Your flag was \scaptured\s!!"); } else { CenterPrint(te, - "\n\n\n The οΏ½οΏ½οΏ½οΏ½οΏ½ flag was οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½!!"); + Q"\n\n\n The \senemy\s flag was \scaptured\s!!"); } te = find(te, classname, "player"); } @@ -2558,7 +2558,7 @@ void () item_flag_team2 = { precache_sound("boss2/pop2.wav"); self.classname = "item_tfgoal"; self.netname = "Blue Flag"; - self.broadcast = " οΏ½οΏ½οΏ½ the enemy team's flag!\n"; + self.broadcast = Q" \sgot\s the enemy team's flag!\n"; self.deathtype = "You've got the enemy flag!\n"; self.noise = "ogre/ogwake.wav"; @@ -2595,8 +2595,8 @@ void () item_flag_team2 = { dp.items_allowed = 2; dp.goal_no = 3; dp.goal_effects = 3; - dp.broadcast = " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; - dp.message = "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; + dp.broadcast = Q" \scaptured\s the enemy flag!\n"; + dp.message = Q"You \scaptured\s the enemy flag!\n"; dp.noise = "boss2/pop2.wav"; dp.goal_result = 2; dp.activate_goal_no = 5; @@ -2635,7 +2635,7 @@ void () item_flag_team1 = { precache_sound("boss2/pop2.wav"); self.classname = "item_tfgoal"; self.netname = "Red Flag"; - self.broadcast = " οΏ½οΏ½οΏ½ the enemy team's flag!\n"; + self.broadcast = Q" \sgot\s the enemy team's flag!\n"; self.deathtype = "You've got the enemy flag!\n"; self.noise = "ogre/ogwake.wav"; @@ -2670,8 +2670,8 @@ void () item_flag_team1 = { dp.items_allowed = 1; dp.goal_no = 4; dp.goal_effects = 3; - dp.broadcast = " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; - dp.message = "You οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½ the enemy flag!\n"; + dp.broadcast = Q" \scaptured\s the enemy flag!\n"; + dp.message = Q"You \scaptured\s the enemy flag!\n"; dp.noise = "boss2/pop2.wav"; dp.goal_result = 2; dp.activate_goal_no = 6; @@ -2813,11 +2813,11 @@ void () DropGoalItems = { tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); if (self.team_no == 1) - bprint(PRINT_HIGH, self.netname, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½\n"); + bprint(PRINT_HIGH, self.netname, Q" \sdropped red's flag!\s\n"); else if (self.team_no == 2) - bprint(PRINT_HIGH, self.netname, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½\n"); + bprint(PRINT_HIGH, self.netname, Q" \sdropped blue's flag!\s\n"); else - bprint(PRINT_HIGH, self.netname, " οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½\n"); + bprint(PRINT_HIGH, self.netname, Q" \sdropped the enemy's flag!\s\n"); Status_Print(self, "\n\n\n", "You dropped the flag!"); search = find(world, classname, "player"); @@ -2836,4 +2836,4 @@ void () DropGoalItems = { } dremove(newmis); TeamFortress_SetSpeed(self); -}; +}; \ No newline at end of file From 582caa7b5323418c23283ed3447ebf9e20d71844 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 22 Nov 2018 23:55:21 +1100 Subject: [PATCH 0497/2474] q3f ent support 90% complete --- progs.src | 3 ++- q3.qc | 50 ++++++++++++++++++++++++-------------------------- q3defs.qc | 14 ++++++++++++++ 3 files changed, 40 insertions(+), 27 deletions(-) create mode 100644 q3defs.qc diff --git a/progs.src b/progs.src index 6eb6aa41..05fe512c 100644 --- a/progs.src +++ b/progs.src @@ -2,7 +2,7 @@ qwprogs.dat defs.qc fteextensions.qc qw.qc -q3.qc +q3defs.qc debug.qc status.qc menu.qc @@ -43,3 +43,4 @@ ctf.qc coop.qc actions.qc spect.qc +q3.qc \ No newline at end of file diff --git a/q3.qc b/q3.qc index 3f9dfceb..e7bac3ea 100644 --- a/q3.qc +++ b/q3.qc @@ -1,8 +1,4 @@ -// q3 defs - enable q3f map ents -.string allowteams; -.string give; -.string active_all_sound; -.string model; + // backpacks, cap points etc void () func_goalinfo = { @@ -29,37 +25,35 @@ void () func_goalinfo = { // note: need to see if this is groupname or builtin name in q3f if (self.holding == "blueflag") { - self.items_allowed = "1"; - self.owned_by "1"; - self.axhitme = "1"; + self.items_allowed = 1; + self.owned_by = 1; + self.axhitme = 1; } if (self.holding == "redflag") { - self.items_allowed = "2"; - self.owned_by "2"; - self.axhitme = "2"; + self.items_allowed = 2; + self.owned_by = 2; + self.axhitme = 2; } - - string give; - give = self.give; - + float count = tokenizebyseparator(self.give, ","); - for (i = 0; i <= count; i++) + for (float i = 0; i <= count; i++) { - string s, gtype, gop, gamt, val; - float loc, slen; + string s, gtype, gop, gamt; + float loc, slen, val; - s = argv[i]; + s = argv(i); slen = strlen(s); + loc = strstrofs(s, "="); gtype = substring(s, 0, loc); gop = substring(s, loc, loc + 1); gamt = substring(s, loc + 1, slen); if (gop == "-") { - val = "-" + ftos(gamt); + val = stof(strcat("-", gamt)); } else { - val = ftos(gamt); + val = stof(gamt); } dprint(gtype); dprint(gop); @@ -106,7 +100,7 @@ void () func_goalitem = { self.delay = self.wait; // is delay used anymore? self.pausetime = self.wait; self.netname = self.groupname; - self.g_a = "4789"; + self.g_a = 4789; switch(self.allowteams) { case "blue": @@ -114,21 +108,25 @@ void () func_goalitem = { self.owned_by = 2; self.skin = 1; self.goal_no = 2; - self.items = "262144"; // used by hud? + self.items = 262144; // used by hud? break; case "red": self.team_no = 2; self.owned_by = 1; self.skin = 2; self.goal_no = 1; - self.items = "131072"; // used by hud? + self.items = 131072; // used by hud? break; default: } - self.team_broadcast = strcat(self.carried_all_message, "\n"); + string cam; + cam = self.carried_all_message; + cam = strireplace("%n", "", cam); + + self.team_broadcast = strcat(cam, "\n"); self.non_team_broadcast = strcat(self.carried_all_message, "\n"); self.message = strcat(self.carried_message, "\n"); - self.noise = strcat(self.carried_all_sound; + self.noise = self.carried_all_sound; self.noise3 = strcat(self.inactive_all_message, "\n"); self.noise4 = strcat(self.inactive_all_message, "\n"); self.n_b = strcat(self.carried_all_message, "\n"); diff --git a/q3defs.qc b/q3defs.qc new file mode 100644 index 00000000..aa154f0f --- /dev/null +++ b/q3defs.qc @@ -0,0 +1,14 @@ +// q3 defs - enable q3f map ents +.string allowteams; +.string give; +.string active_all_sound; +.string model; +.float teamscore; +.string active_all_message; +.string holding; +.string give; +.string groupname; +.string carried_all_message; +.string carried_message; +.string carried_all_sound; +.string inactive_all_message; \ No newline at end of file From 0482716797e87ff4b41834c2a275c7f6edbca65e Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 23 Nov 2018 00:57:43 +1100 Subject: [PATCH 0498/2474] fix q3f strings --- q3.qc | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/q3.qc b/q3.qc index e7bac3ea..356ff68f 100644 --- a/q3.qc +++ b/q3.qc @@ -1,4 +1,16 @@ +string (string s) prepq3fstring = { + string ret; + ret = strireplace("%n", "", s); + ret = strireplace("~", "", ret); + ret = strireplace("^*", "", ret); + + ret = strireplace("^4blue", Q"\sblue\s", ret); + ret = strireplace("^1red", Q"\sred\s", ret); + + ret = strcat(ret, "\n"); + return (ret); +} // backpacks, cap points etc void () func_goalinfo = { @@ -10,7 +22,7 @@ void () func_goalinfo = { self.armortype = 0.8; self.goal_effects = 1; self.goal_activation = 1; // touched by player - self.n_b = self.active_all_message; + self.n_b = prepq3fstring(self.active_all_message); // probably have to tokenise this? if (self.allowteams == "blue") @@ -119,23 +131,24 @@ void () func_goalitem = { break; default: } - string cam; - cam = self.carried_all_message; - cam = strireplace("%n", "", cam); + string cam, iam; + cam = prepq3fstring(self.carried_all_message); + iam = prepq3fstring(self.inactive_all_message); - self.team_broadcast = strcat(cam, "\n"); - self.non_team_broadcast = strcat(self.carried_all_message, "\n"); - self.message = strcat(self.carried_message, "\n"); + self.team_broadcast = cam; + self.non_team_broadcast = cam; + self.message = prepq3fstring(self.carried_message); self.noise = self.carried_all_sound; - self.noise3 = strcat(self.inactive_all_message, "\n"); - self.noise4 = strcat(self.inactive_all_message, "\n"); - self.n_b = strcat(self.carried_all_message, "\n"); - self.d_n_n = strcat(self.active_all_message, "\n"); + self.noise3 = iam; + self.noise4 = iam; + self.n_b = cam; + self.d_n_n = prepq3fstring(self.active_all_message); item_tfgoal(); } + /* void () target_position = { self.classname = "info_notnull"; From 240f89cfff58e67e12d56778666f8d0b5b765b89 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 23 Nov 2018 00:58:03 +1100 Subject: [PATCH 0499/2474] remove converted ents from openfire, add frozen1 for qw style kill ents --- frozen1.map | 15000 ++++++++++++++++++++++++++++++ q3f_openfire2b working copy.map | 146 +- 2 files changed, 15002 insertions(+), 144 deletions(-) create mode 100644 frozen1.map diff --git a/frozen1.map b/frozen1.map new file mode 100644 index 00000000..c88d265c --- /dev/null +++ b/frozen1.map @@ -0,0 +1,15000 @@ +//===================================================== +// +// map file created with BSPC v1.6 +// +// BSPC is created by Mr Elusive +// +// +//===================================================== +{ + "classname" "worldspawn" + "sounds" "1" + "light" "50" + "message" "Frozen Fire v1.1\nby Night Hunter\nhttp://clan.sd.ru" + "wad" "d:\games\quake\worldcraft\wads\apocrypha.wad;d:\games\quake\worldcraft\wads\dethtex_gothic.wad;d:\games\quake\worldcraf" + { //brush 0 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 1 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 58392 65534 -29756 ) ( 58392 -65534 -29756 ) ( -58840 -65534 28860 ) stonesnow 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stonesnow 0 0 0 1 1 + } + { //brush 2 + ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 3 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 + ( 63647 65534 15615 ) ( 63647 -65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 + } + { //brush 4 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 0 1 1 + ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 + ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) fstng_2 0 16 0 1 1 + } + { //brush 5 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( -31464 -57537 65535 ) ( 27151 59694 65535 ) ( 27151 59694 -65535 ) stnwll01 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 6 + ( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 58952 28636 65535 ) ( -58280 -29980 65535 ) ( -58280 -29980 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 7 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 + } + { //brush 8 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 9 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 10 + ( 64 65535 65535 ) ( 64 -65535 65535 ) ( 64 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 11 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 16 180 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 + ( 47244 65535 45436 ) ( 47244 -65535 45436 ) ( -45436 65535 -47244 ) fstng_2 0 16 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 0 1 1 + ( -65535 -46348 46332 ) ( 65535 -46348 46332 ) ( 65535 46332 -46348 ) fstng_2 0 16 0 1 1 + ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 + } + { //brush 12 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 + ( -64 -65535 65535 ) ( -64 65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 + ( 60996 -69391 7356 ) ( 60996 57765 39146 ) ( -61258 69226 -6699 ) tile2492 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) tile2492 0 0 0 1 1 + } + { //brush 13 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 + ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 + ( 47308 -65535 45372 ) ( 47308 65535 45372 ) ( -45372 -65535 -47308 ) fstng_2 0 16 90 1 1 + } + { //brush 14 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 15 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 + ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 + ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 + } + { //brush 16 + ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 + ( -57573 31394 65535 ) ( 59659 -27221 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 17 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 90 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 180 1 1 + ( -44652 65535 48028 ) ( -44652 -65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 + } + { //brush 18 + ( 1824 65535 65535 ) ( 1824 -65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 + } + { //brush 19 + ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 + ( -65534 17219 63246 ) ( 65534 17219 63246 ) ( -65534 -14569 -63909 ) stnwll02 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 0 1 1 + } + { //brush 20 + ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 + } + { //brush 21 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 + ( -65534 17219 63246 ) ( 65534 17219 63246 ) ( -65534 -14569 -63909 ) stnwll02 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 0 1 1 + } + { //brush 22 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 0 1 1 + } + { //brush 23 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 0 1 1 + } + { //brush 24 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 16 0 1 1 + ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 + ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 16 0 1 1 + ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 + } + { //brush 25 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 26 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 + } + { //brush 27 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -192 65535 ) ( 65535 -192 65535 ) ( -65535 -192 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -160 65535 ) ( -65535 -160 65535 ) ( -65535 -160 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 + } + { //brush 28 + ( 65535 -192 65535 ) ( -65535 -192 65535 ) ( -65535 -192 -65535 ) ftlattice2 16 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 + ( 65535 -63467 16338 ) ( 65535 63689 -15450 ) ( -65535 -63467 16338 ) ftlattice2 16 0 0 1 1 + ( 65535 -63713 -15352 ) ( 65535 63442 16436 ) ( -65535 -63713 -15352 ) ftlattice2 16 0 0 1 1 + ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 0 0 1 1 + ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 0 0 1 1 + } + { //brush 29 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -224 65535 ) ( 65535 -224 65535 ) ( -65535 -224 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -192 65535 ) ( -65535 -192 65535 ) ( -65535 -192 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 + } + { //brush 30 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -224 65535 ) ( -65535 -224 65535 ) ( -65535 -224 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + } + { //brush 31 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 32 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -63355 16786 ) ( 65535 63801 -15002 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_0 0 0 0 1 1 + } + { //brush 33 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 + ( 65535 -63355 16786 ) ( 65535 63801 -15002 ) ( -65535 -63355 16786 ) millgt1 16 16 0 1 1 + ( 65535 -63631 -15679 ) ( 65535 63524 16109 ) ( -65535 -63631 -15679 ) millgt1 16 16 0 1 1 + ( 63566 -65534 15943 ) ( 63566 65534 15943 ) ( -63590 -65534 -15845 ) millgt1 16 16 0 1 1 + ( 63842 -65534 -14836 ) ( 63842 65534 -14836 ) ( -63313 -65534 16952 ) millgt1 16 16 0 1 1 + } + { //brush 34 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1296 65535 ) ( 65535 1296 65535 ) ( -65535 1296 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 0 1 1 + } + { //brush 35 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1264 65535 ) ( 65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 90 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 36 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 1264 65535 ) ( 65535 1264 65535 ) ( -65535 1264 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) millgt1 16 0 90 1 0.500000 + ( 18108 -65534 63024 ) ( 18108 65534 63024 ) ( -13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 + ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + } + { //brush 37 + ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( -57649 31240 65535 ) ( 59582 -27375 65535 ) ( -57649 31240 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 38 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 16 0 1 1 + ( 65535 -63639 -15649 ) ( 65535 63517 16139 ) ( -65535 -63639 -15649 ) millgt1 0 16 0 1 1 + ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) millgt1 0 16 0 1 1 + ( 63851 -65534 -14802 ) ( 63851 65534 -14802 ) ( -63305 -65534 16986 ) millgt1 0 16 0 1 1 + ( 63604 -65534 15789 ) ( 63604 65534 15789 ) ( -63551 -65534 -15999 ) millgt1 0 16 0 1 1 + } + { //brush 39 + ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( 58737 29064 65535 ) ( -58494 -29551 65535 ) ( -58494 -29551 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 40 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 816 65535 ) ( 65535 816 65535 ) ( -65535 816 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 848 65535 ) ( -65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 90 1 1 + ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 90 1 1 + } + { //brush 41 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 816 65535 ) ( 65535 816 65535 ) ( -65535 816 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 848 65535 ) ( -65535 848 65535 ) ( -65535 848 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) millgt1 16 0 90 1 0.500000 + ( 18108 -65534 63024 ) ( 18108 65534 63024 ) ( -13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 + ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + } + { //brush 42 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 816 65535 ) ( -65535 816 65535 ) ( -65535 816 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 0 1 1 + } + { //brush 43 + ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_0 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 + } + { //brush 44 + ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 180 1 1 + ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 + } + { //brush 45 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 + ( -28130 -59205 65535 ) ( 30485 58027 65535 ) ( 30485 58027 -65535 ) fstng_2 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 46 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 90 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 + ( -28104 -59217 65535 ) ( 30511 58014 65535 ) ( 30511 58014 -65535 ) fstng_2 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 47 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 + ( -28079 -59230 65535 ) ( 30536 58001 65535 ) ( 30536 58001 -65535 ) fstng_2 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 48 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 + ( -28053 -59243 65535 ) ( 30562 57989 65535 ) ( 30562 57989 -65535 ) fstng_2 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 49 + ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 0 1 1 + ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 50 + ( 2656 65535 65535 ) ( 2656 -65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 51 + ( 2656 65535 65535 ) ( 2656 -65535 65535 ) ( 2656 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 52 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) ftlattice2 16 16 0 1 1 + ( 65535 -63726 -15303 ) ( 65535 63430 16485 ) ( -65535 -63726 -15303 ) ftlattice2 16 16 0 1 1 + ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 16 0 1 1 + ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 16 0 1 1 + } + { //brush 53 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 16 0 1 1 + ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 + ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 16 0 1 1 + ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 + } + { //brush 54 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 + ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 0 0 1 1 + ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 0 0 1 1 + ( 65535 -63467 16338 ) ( 65535 63689 -15450 ) ( -65535 -63467 16338 ) ftlattice2 16 0 0 1 1 + ( 65535 -63713 -15352 ) ( 65535 63442 16436 ) ( -65535 -63713 -15352 ) ftlattice2 16 0 0 1 1 + } + { //brush 55 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 0 1 1 + ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 + } + { //brush 56 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 57 + ( 2624 65535 65535 ) ( 2624 -65535 65535 ) ( 2624 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + } + { //brush 58 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 2624 -65535 65535 ) ( 2624 65535 65535 ) ( 2624 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 + } + { //brush 59 + ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 60 + ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 59032 -28476 ) ( 65535 -58200 30140 ) ( -65535 -58200 30140 ) stnwll05 0 0 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 61 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 62 + ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 + } + { //brush 63 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 + } + { //brush 64 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 1424 65535 ) ( 65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 65 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 + ( -63800 -15006 65535 ) ( 63356 16783 65535 ) ( -63800 -15006 -65535 ) shootit 0 8 0 1 1 + ( -63132 17679 65535 ) ( 64024 -14110 65535 ) ( -63132 17679 -65535 ) shootit 0 8 0 1 1 + ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 + ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 + } + { //brush 66 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 + ( -63162 17558 65535 ) ( 63994 -14230 65535 ) ( -63162 17558 -65535 ) shootit 0 8 0 1 1 + ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 + ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 + ( -63830 -14885 65535 ) ( 63326 16903 65535 ) ( -63830 -14885 -65535 ) shootit 0 8 0 1 1 + } + { //brush 67 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 + ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 + ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 + ( -63822 -14915 65535 ) ( 63333 16873 65535 ) ( -63822 -14915 -65535 ) shootit 0 8 0 1 1 + ( -63154 17588 65535 ) ( 64001 -14200 65535 ) ( -63154 17588 -65535 ) shootit 0 8 0 1 1 + } + { //brush 68 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 + ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 + ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 + ( -63139 17648 65535 ) ( 64016 -14140 65535 ) ( -63139 17648 -65535 ) shootit 0 8 0 1 1 + ( -63807 -14975 65535 ) ( 63348 16813 65535 ) ( -63807 -14975 -65535 ) shootit 0 8 0 1 1 + } + { //brush 69 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 + ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 + ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 + ( -63815 -14945 65535 ) ( 63341 16843 65535 ) ( -63815 -14945 -65535 ) shootit 0 8 0 1 1 + ( -63147 17618 65535 ) ( 64009 -14170 65535 ) ( -63147 17618 -65535 ) shootit 0 8 0 1 1 + } + { //brush 70 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -58424 -29692 ) ( 65535 58808 28924 ) ( -65535 -58424 -29692 ) stnwll05 0 0 90 1 1 + } + { //brush 71 + ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -58424 -29692 ) ( 65535 58808 28924 ) ( -65535 -58424 -29692 ) stnwll05 0 0 90 1 1 + } + { //brush 72 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnfloor02 0 0 180 1 1 + ( 65535 58808 28924 ) ( 65535 -58424 -29692 ) ( -65535 -58424 -29692 ) stnfloor02 0 0 0 1 1 + } + { //brush 73 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 74 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 75 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) millgt1 16 0 0 1 1 + ( 63507 -65534 16176 ) ( 63507 65534 16176 ) ( -63648 -65534 -15612 ) millgt1 16 0 0 1 1 + ( 65535 -63361 16760 ) ( 65535 63794 -15028 ) ( -65535 -63361 16760 ) millgt1 16 0 0 1 1 + ( 63769 -65534 -15130 ) ( 63769 65534 -15130 ) ( -63387 -65534 16658 ) millgt1 16 0 0 1 1 + ( 65535 -63623 -15713 ) ( 65535 63533 16075 ) ( -65535 -63623 -15713 ) millgt1 16 0 0 1 1 + } + { //brush 76 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 880 -65535 65535 ) ( 880 65535 65535 ) ( 880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 + } + { //brush 77 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 78 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) fstng_2 0 0 0 1 1 + ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 79 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 80 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + } + { //brush 81 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -45524 65535 47156 ) ( -45524 -65535 47156 ) ( 47156 65535 -45524 ) fstng_2 0 16 90 1 1 + } + { //brush 82 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 + } + { //brush 83 + ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 84 + ( 2136 65535 65535 ) ( 2136 -65535 65535 ) ( 2136 65535 -65535 ) ctf07 0 16 0 1 1 + ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 16 180 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) ctf07 0 16 180 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) ctf07 0 16 0 1 1 + } + { //brush 85 + ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 + } + { //brush 86 + ( 2136 65535 65535 ) ( 2136 -65535 65535 ) ( 2136 65535 -65535 ) ctf07 0 16 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) ctf07 0 16 180 1 1 + ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 16 180 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) ctf07 0 16 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) ctf07 0 16 90 1 1 + } + { //brush 87 + ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 + } + { //brush 88 + ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 + ( -44964 65535 47716 ) ( -44964 -65535 47716 ) ( 47716 65535 -44964 ) fstng_2 0 16 90 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 + } + { //brush 89 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 + } + { //brush 90 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 180 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 0 1 1 + ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 91 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 90 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 180 1 1 + } + { //brush 92 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + ( 63749 65534 -15209 ) ( 63749 -65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 0 1 1 + } + { //brush 93 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 90 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + } + { //brush 94 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 90 1 1 + } + { //brush 95 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stnwll05 0 0 0 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 + ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stnwll05 0 0 0 1 1 + } + { //brush 96 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + ( 63749 65534 -15209 ) ( 63749 -65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 0 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 97 + ( 2080 -65535 65535 ) ( 2080 65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 + } + { //brush 98 + ( 2080 -65535 65535 ) ( 2080 65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 0 1 1 + } + { //brush 99 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 624 65535 ) ( 65535 624 65535 ) ( -65535 624 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 100 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 624 65535 ) ( -65535 624 65535 ) ( -65535 624 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 101 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 400 65535 ) ( 65535 400 65535 ) ( -65535 400 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 102 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 368 65535 ) ( 65535 368 65535 ) ( -65535 368 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 400 65535 ) ( -65535 400 65535 ) ( -65535 400 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 103 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 368 65535 ) ( -65535 368 65535 ) ( -65535 368 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + } + { //brush 104 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 + ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) fstng_0 0 0 180 1 1 + } + { //brush 105 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 176 65535 ) ( 65535 176 65535 ) ( -65535 176 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 106 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 176 65535 ) ( -65535 176 65535 ) ( -65535 176 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 + ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 107 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + } + { //brush 108 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 + ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_0 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 109 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( -65535 45836 46844 ) ( 65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 + ( 58878 -28783 65535 ) ( -58353 29832 65535 ) ( -58353 29832 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 110 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) metdec1 32 0 180 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) metdec1 32 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 63809 65534 -14968 ) ( 63809 -65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) metdec1 32 0 0 1 1 + } + { //brush 111 + ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 112 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 + ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 113 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) millgt1 16 0 0 1 0.500000 + ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 16 0 0 1 0.500000 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 + } + { //brush 114 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 115 + ( 2528 65535 65535 ) ( 2528 -65535 65535 ) ( 2528 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 2560 -65535 65535 ) ( 2560 65535 65535 ) ( 2560 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + } + { //brush 116 + ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 117 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 + ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 118 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) millgt1 16 0 0 1 0.500000 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 + } + { //brush 119 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 + } + { //brush 120 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 + ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_0 0 0 180 1 1 + } + { //brush 121 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 + ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 0 1 1 + ( 31381 -57579 65535 ) ( -27234 59653 65535 ) ( -27234 59653 -65535 ) fstng_2 0 0 0 1 1 + ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 122 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 0 1 1 + ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 180 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 123 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 + ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 124 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 + ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 + ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 125 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 + ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 + } + { //brush 126 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 + ( 65535 -63400 16606 ) ( 65535 63756 -15183 ) ( -65535 -63400 16606 ) millgt1 16 16 0 1 1 + ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) millgt1 16 16 0 1 1 + ( 63842 -65534 -14836 ) ( 63842 65534 -14836 ) ( -63313 -65534 16952 ) millgt1 16 16 0 1 1 + ( 63566 -65534 15943 ) ( 63566 65534 15943 ) ( -63590 -65534 -15845 ) millgt1 16 16 0 1 1 + } + { //brush 127 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 31330 -57605 65535 ) ( -27285 59627 65535 ) ( -27285 59627 -65535 ) fstng_2 0 0 0 1 1 + ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 128 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 + ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 + ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 129 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 + ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 + ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 130 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + ( -28757 -58891 65535 ) ( 29858 58341 65535 ) ( 29858 58341 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 131 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 864 65535 ) ( 65535 864 65535 ) ( -65535 864 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + ( 30703 -57918 65535 ) ( -27912 59313 65535 ) ( -27912 59313 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 132 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 864 65535 ) ( -65535 864 65535 ) ( -65535 864 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 133 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + } + { //brush 134 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 + } + { //brush 135 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) ctf07 0 16 0 1 1 + ( 1240 -65535 65535 ) ( 1240 65535 65535 ) ( 1240 65535 -65535 ) ctf07 0 16 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 16 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 16 180 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 + } + { //brush 136 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 + } + { //brush 137 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 + } + { //brush 138 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -62234 -20536 65535 ) ( 62109 20911 65535 ) ( -62234 -20536 -65535 ) mtn 0 0 0 1 1 + } + { //brush 139 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + } + { //brush 140 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -64693 -10472 65535 ) ( 64593 11074 65535 ) ( -64693 -10472 -65535 ) mtn 0 0 0 1 1 + ( -58219 30101 65535 ) ( 59013 -28514 65535 ) ( -58219 30101 -65535 ) mtn 0 0 0 1 1 + } + { //brush 141 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( 62109 20911 65535 ) ( -62234 -20536 65535 ) ( -62234 -20536 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 142 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( 62109 20911 65535 ) ( -62234 -20536 65535 ) ( -62234 -20536 -65535 ) stnfloor02 0 0 0 1 1 + } + { //brush 143 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 + ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 + } + { //brush 144 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 + ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) ftlattice2 16 0 0 1 1 + ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 0 0 1 1 + ( 65535 -63408 16572 ) ( 65535 63747 -15216 ) ( -65535 -63408 16572 ) ftlattice2 16 0 0 1 1 + ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 0 0 1 1 + } + { //brush 145 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 + ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + } + { //brush 146 + ( 1568 65535 65535 ) ( 1568 -65535 65535 ) ( 1568 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 + } + { //brush 147 + ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 58558 29423 65535 ) ( -58673 -29192 65535 ) ( -58673 -29192 -65535 ) stonesnw 0 0 0 1 1 + ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) stonesnw 0 0 0 1 1 + } + { //brush 148 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) stonesnow 0 0 0 1 1 + ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stonesnow 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 + } + { //brush 149 + ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 + } + { //brush 150 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 + } + { //brush 151 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 + } + { //brush 152 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 + ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 153 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 0 1 1 + ( -28680 -58929 65535 ) ( 29935 58302 65535 ) ( 29935 58302 -65535 ) stnwll05 0 0 0 1 1 + ( 30780 -57880 65535 ) ( -27836 59352 65535 ) ( -27836 59352 -65535 ) stnwll05 0 0 0 1 1 + ( 59086 65534 -28367 ) ( 59086 -65534 -28367 ) ( -58145 -65534 30248 ) stnfloor02 0 0 0 1 1 + } + { //brush 154 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 + ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 + ( 30780 -57880 65535 ) ( -27836 59352 65535 ) ( -27836 59352 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 155 + ( 1256 65535 65535 ) ( 1256 -65535 65535 ) ( 1256 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 61626 -22305 ) ( 65535 -61098 23715 ) ( -65535 -61098 23715 ) stnfloor02 0 0 0 1 1 + ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 + ( 65535 61358 23021 ) ( 65535 -61366 -23000 ) ( -65535 -61366 -23000 ) stnfloor02 0 0 0 1 1 + } + { //brush 156 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) ctf01 32 0 0 1 1 + ( 1256 -65535 65535 ) ( 1256 65535 65535 ) ( 1256 65535 -65535 ) ctf01 32 0 0 1 1 + ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 0 180 1 1 + ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) ctf01 32 0 180 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) ctf01 32 0 90 1 1 + ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 + } + { //brush 157 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 + ( -28680 -58929 65535 ) ( 29935 58302 65535 ) ( 29935 58302 -65535 ) stnwll05 0 0 0 1 1 + ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 + } + { //brush 158 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 159 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll01 0 0 0 1 1 + } + { //brush 160 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 + ( 16880 65534 63331 ) ( 16880 -65534 63331 ) ( -14908 65534 -63824 ) stnwll01 0 0 0 1 1 + } + { //brush 161 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 + ( -45476 65535 47204 ) ( -45476 -65535 47204 ) ( 47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 + ( 16880 -65534 63331 ) ( 16880 65534 63331 ) ( -14908 65534 -63824 ) millgt1 0 0 0 1 0.500000 + } + { //brush 162 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 + ( -45476 65535 47204 ) ( -45476 -65535 47204 ) ( 47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 + } + { //brush 163 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 16880 65534 63331 ) ( 16880 -65534 63331 ) ( -14908 65534 -63824 ) stnwll01 0 0 0 1 1 + ( -45476 -65535 47204 ) ( -45476 65535 47204 ) ( 47204 65535 -45476 ) stnwll01 0 0 90 1 1 + } + { //brush 164 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + } + { //brush 165 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 166 + ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) tile2492 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 167 + ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) tile2492 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 168 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) shootit 16 0 180 1 1 + ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) shootit 16 0 180 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 + ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 + } + { //brush 169 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) shootit 16 0 180 1 1 + ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 + ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 + } + { //brush 170 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 + ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + } + { //brush 171 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 + ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 + } + { //brush 172 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 832 65535 ) ( 65535 832 65535 ) ( -65535 832 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -45524 65535 47156 ) ( -45524 -65535 47156 ) ( 47156 65535 -45524 ) fstng_2 0 16 90 1 1 + } + { //brush 173 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -57896 30748 65535 ) ( 59336 -27868 65535 ) ( -57896 30748 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 174 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 832 65535 ) ( 65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 175 + ( 1136 65535 65535 ) ( 1136 -65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 0 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 180 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 176 + ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 180 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 177 + ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) shootit 16 0 180 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) shootit 16 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 + } + { //brush 178 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 0 1 1 + ( 1104 -65535 65535 ) ( 1104 65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 179 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 + ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 180 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 + ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) shootit 16 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 + } + { //brush 181 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 182 + ( 1136 65535 65535 ) ( 1136 -65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 0 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 183 + ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) shootit 16 0 180 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 + } + { //brush 184 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 0 1 1 + ( 1104 -65535 65535 ) ( 1104 65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 185 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 + ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 + } + { //brush 186 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 187 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 + ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 188 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 + ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 + } + { //brush 189 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 + ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 + } + { //brush 190 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + ( 46508 65535 46172 ) ( 46508 -65535 46172 ) ( -46172 65535 -46508 ) stnwll02 0 0 0 1 1 + ( -58699 -29141 65535 ) ( 58533 29474 65535 ) ( -58699 -29141 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 191 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 + ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 + ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 + ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 + } + { //brush 192 + ( 1824 65535 65535 ) ( 1824 -65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 193 + ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 0 1 0.500000 + ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) millgt1 0 0 0 1 0.500000 + ( -65534 -15231 63743 ) ( 65534 -15231 63743 ) ( -65534 16557 -63412 ) millgt1 0 0 0 1 0.500000 + } + { //brush 194 + ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 + ( 65534 -15231 63743 ) ( -65534 -15231 63743 ) ( -65534 16557 -63412 ) stnwll02 0 0 0 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 + } + { //brush 195 + ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 90 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 196 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 0 1 0.500000 + ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) millgt1 0 0 0 1 0.500000 + ( -65534 -15231 63743 ) ( 65534 -15231 63743 ) ( -65534 16557 -63412 ) millgt1 0 0 0 1 0.500000 + } + { //brush 197 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 + ( 65534 -15231 63743 ) ( -65534 -15231 63743 ) ( -65534 16557 -63412 ) stnwll02 0 0 0 1 1 + } + { //brush 198 + ( 1184 65535 65535 ) ( 1184 -65535 65535 ) ( 1184 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 + } + { //brush 199 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 1152 -65535 65535 ) ( 1152 65535 65535 ) ( 1152 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 90 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 + } + { //brush 200 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1184 -65535 65535 ) ( 1184 65535 65535 ) ( 1184 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 + } + { //brush 201 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 + ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 + ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) fstng_2 0 16 0 1 1 + } + { //brush 202 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1184 -65535 65535 ) ( 1184 65535 65535 ) ( 1184 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 + ( 58533 29474 65535 ) ( -58699 -29141 65535 ) ( -58699 -29141 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 203 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 704 65535 ) ( 65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 58622 29295 ) ( 65535 -58609 -29320 ) ( -65535 -58609 -29320 ) stnwll05 0 0 90 1 1 + ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 204 + ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 + ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 + ( 63830 -14885 65535 ) ( -63326 16903 65535 ) ( -63326 16903 -65535 ) shootit 0 8 0 1 1 + ( 63504 16188 65535 ) ( -63651 -15600 65535 ) ( -63651 -15600 -65535 ) shootit 0 8 0 1 1 + ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 + } + { //brush 205 + ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 + ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 + ( 63512 16158 65535 ) ( -63644 -15631 65535 ) ( -63644 -15631 -65535 ) shootit 0 8 0 1 1 + ( 63838 -14855 65535 ) ( -63318 16933 65535 ) ( -63318 16933 -65535 ) shootit 0 8 0 1 1 + ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 + } + { //brush 206 + ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 + ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 + ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 + ( 63845 -14825 65535 ) ( -63310 16963 65535 ) ( -63310 16963 -65535 ) shootit 0 8 0 1 1 + ( 63519 16127 65535 ) ( -63636 -15661 65535 ) ( -63636 -15661 -65535 ) shootit 0 8 0 1 1 + } + { //brush 207 + ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 + ( 63527 16097 65535 ) ( -63629 -15691 65535 ) ( -63629 -15691 -65535 ) shootit 0 8 0 1 1 + ( 63853 -14795 65535 ) ( -63303 16993 65535 ) ( -63303 16993 -65535 ) shootit 0 8 0 1 1 + ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 + ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 + } + { //brush 208 + ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 + ( 63822 -14915 65535 ) ( -63333 16873 65535 ) ( -63333 16873 -65535 ) shootit 0 8 0 1 1 + ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 + ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 + ( 63497 16218 65535 ) ( -63659 -15570 65535 ) ( -63659 -15570 -65535 ) shootit 0 8 0 1 1 + } + { //brush 209 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -58385 29768 ) ( 65535 58846 -28847 ) ( -65535 -58385 29768 ) stnwll05 0 0 90 1 1 + } + { //brush 210 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnfloor02 0 0 180 1 1 + ( 65535 58846 -28847 ) ( 65535 -58385 29768 ) ( -65535 -58385 29768 ) stnfloor02 0 0 0 1 1 + } + { //brush 211 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 688 65535 ) ( -65535 688 65535 ) ( -65535 688 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 212 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stonesnw 0 0 0 1 1 + } + { //brush 213 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 + } + { //brush 214 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 + ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 90 1 1 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll02 0 0 90 1 1 + ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll02 0 0 90 1 1 + } + { //brush 215 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 + } + { //brush 216 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 + ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 217 + ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 + ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 218 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 + ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 + ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 + } + { //brush 219 + ( 1008 65535 65535 ) ( 1008 -65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 + ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 + } + { //brush 220 + ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 + ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 + ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 + } + { //brush 221 + ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 976 -65535 65535 ) ( 976 65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 + ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 + } + { //brush 222 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 + } + { //brush 223 + ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -58952 -28636 65535 ) ( 58280 29980 65535 ) ( -58952 -28636 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 224 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 + } + { //brush 225 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 46436 65535 46244 ) ( 46436 -65535 46244 ) ( -46244 65535 -46436 ) stnwll01 0 0 90 1 1 + ( -15073 -65534 63783 ) ( -15073 65534 63783 ) ( 16715 65534 -63373 ) stnwll01 0 0 0 1 1 + } + { //brush 226 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) millgt1 0 0 90 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 + ( 46436 -65535 46244 ) ( 46436 65535 46244 ) ( -46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) millgt1 0 0 0 1 0.500000 + } + { //brush 227 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 + ( 46436 -65535 46244 ) ( 46436 65535 46244 ) ( -46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 + ( -15073 65534 63783 ) ( -15073 -65534 63783 ) ( 16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 + } + { //brush 228 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -15073 -65534 63783 ) ( -15073 65534 63783 ) ( 16715 65534 -63373 ) stnwll01 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 + } + { //brush 229 + ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 230 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 + } + { //brush 231 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_2 0 0 180 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) fstng_2 0 0 0 1 1 + } + { //brush 232 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + } + { //brush 233 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 234 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -64299 12680 65535 ) ( 64525 -11474 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 + } + { //brush 235 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -65081 -7711 65535 ) ( 64976 8546 65535 ) ( -65081 -7711 -65535 ) mtn 0 0 0 1 1 + ( -64306 12641 65535 ) ( 64518 -11513 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 + ( 64525 -11474 65535 ) ( -64299 12680 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 + } + { //brush 236 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 64976 8546 65535 ) ( -65081 -7711 65535 ) ( -65081 -7711 -65535 ) mtn 0 0 0 1 1 + ( 64525 -11474 65535 ) ( -64299 12680 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 + ( -64306 12641 65535 ) ( 64518 -11513 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 + ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + } + { //brush 237 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -58744 -29052 65535 ) ( 58488 29564 65535 ) ( -58744 -29052 -65535 ) mtn 0 0 0 1 1 + ( -63859 14731 65535 ) ( 64088 -13701 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 + } + { //brush 238 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + ( 58488 29564 65535 ) ( -58744 -29052 65535 ) ( -58744 -29052 -65535 ) mtn 0 0 0 1 1 + ( 64518 -11513 65535 ) ( -64306 12641 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 + ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 + } + { //brush 239 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( -65534 -15329 63719 ) ( 65534 -15329 63719 ) ( -65534 16459 -63437 ) mtn 0 0 0 1 1 + ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 + ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 + ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 + ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 + ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 + } + { //brush 240 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 + ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 + ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 + } + { //brush 241 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( -65534 -7581 65097 ) ( 65534 -7581 65097 ) ( -65534 8676 -64960 ) mtn 0 0 0 1 1 + ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 + ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 + ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + ( 65271 -14499 64180 ) ( -54501 38733 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 + } + { //brush 242 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65534 -15314 63723 ) ( -65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + ( -59675 27091 65535 ) ( 60097 -26141 65535 ) ( -59675 27091 -65535 ) mtn 0 0 0 1 1 + ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 + ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 + ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 + } + { //brush 243 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 + ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 + } + { //brush 244 + ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 + ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 + ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + ( -65534 29461 58539 ) ( 65534 29461 58539 ) ( -65534 -29154 -58693 ) mtn 0 0 0 1 1 + ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 + ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 + } + { //brush 245 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -63219 -26421 62412 ) ( 67199 -13380 62412 ) ( -67325 14635 -61993 ) mtn 0 0 0 1 1 + ( -67199 -13380 62412 ) ( 63219 -26421 62412 ) ( -63094 27677 -61993 ) mtn 0 0 0 1 1 + ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 + ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 + ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 + ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 + ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 + } + { //brush 246 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 + ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 + ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + ( -59675 27091 65535 ) ( 60097 -26141 65535 ) ( -59675 27091 -65535 ) mtn 0 0 0 1 1 + } + { //brush 247 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + } + { //brush 248 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -58488 29564 65535 ) ( 58744 -29052 65535 ) ( -58488 29564 -65535 ) mtn 0 0 0 1 1 + ( -64088 -13701 65535 ) ( 63859 14731 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + } + { //brush 249 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 + ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( 64306 12641 65535 ) ( -64518 -11513 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 + ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + ( 58744 -29052 65535 ) ( -58488 29564 65535 ) ( -58488 29564 -65535 ) mtn 0 0 0 1 1 + } + { //brush 250 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 + ( 63859 14731 65535 ) ( -64088 -13701 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 + ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 + } + { //brush 251 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( -65534 -7581 65097 ) ( 65534 -7581 65097 ) ( -65534 8676 -64960 ) mtn 0 0 0 1 1 + ( 63859 14731 65535 ) ( -64088 -13701 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 + ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 + ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + ( 54501 38733 64180 ) ( -65271 -14499 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 + ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 + } + { //brush 252 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -60097 -26141 65535 ) ( 59675 27091 65535 ) ( -60097 -26141 -65535 ) mtn 0 0 0 1 1 + ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 + ( 65534 -15314 63723 ) ( -65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 + } + { //brush 253 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 + ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + ( -60097 -26141 65535 ) ( 59675 27091 65535 ) ( -60097 -26141 -65535 ) mtn 0 0 0 1 1 + } + { //brush 254 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -50409 45720 62915 ) ( 66822 -12895 62915 ) ( -66454 13631 -63149 ) mtn 0 0 0 1 1 + ( -66510 3720 64438 ) ( 63547 19978 64438 ) ( -63623 -19370 -64549 ) mtn 0 0 0 1 1 + ( -63536 20069 64421 ) ( 66521 3812 64421 ) ( -66422 -3021 -64565 ) mtn 0 0 0 1 1 + } + { //brush 255 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -50015 46510 62651 ) ( 67217 -12106 62651 ) ( -66762 13015 -62954 ) mtn 0 0 0 1 1 + ( 63547 19978 64438 ) ( -66510 3720 64438 ) ( -63623 -19370 -64549 ) mtn 0 0 0 1 1 + ( -66017 5667 64802 ) ( 64797 13842 64802 ) ( -64839 -13174 -64900 ) mtn 0 0 0 1 1 + ( -66636 -8945 63790 ) ( 56087 37076 63790 ) ( -56147 -36916 -63830 ) mtn 0 0 0 1 1 + } + { //brush 256 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 + } + { //brush 257 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) shootit 16 0 180 1 1 + ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 + } + { //brush 258 + ( 784 65535 65535 ) ( 784 -65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 0 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 259 + ( 496 65535 65535 ) ( 496 -65535 65535 ) ( 496 65535 -65535 ) tile2492 0 0 0 1 1 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 + ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 260 + ( 432 65535 65535 ) ( 432 -65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 0 1 1 + ( 464 -65535 65535 ) ( 464 65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 261 + ( 144 65535 65535 ) ( 144 -65535 65535 ) ( 144 65535 -65535 ) tile2492 0 0 0 1 1 + ( 400 -65535 65535 ) ( 400 65535 65535 ) ( 400 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 + ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 262 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 263 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_0 0 0 0 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) fstng_0 0 0 0 1 1 + } + { //brush 264 + ( 784 65535 65535 ) ( 784 -65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 0 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + } + { //brush 265 + ( 464 65535 65535 ) ( 464 -65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 180 1 1 + ( 784 -65535 65535 ) ( 784 65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 + ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 266 + ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) shootit 16 0 180 1 1 + ( 784 -65535 65535 ) ( 784 65535 65535 ) ( 784 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 + ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 + } + { //brush 267 + ( 496 65535 65535 ) ( 496 -65535 65535 ) ( 496 65535 -65535 ) tile2492 0 0 0 1 1 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 180 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 268 + ( 464 65535 65535 ) ( 464 -65535 65535 ) ( 464 65535 -65535 ) shootit 16 0 180 1 1 + ( 496 -65535 65535 ) ( 496 65535 65535 ) ( 496 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 + ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 + } + { //brush 269 + ( 432 65535 65535 ) ( 432 -65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 0 1 1 + ( 464 -65535 65535 ) ( 464 65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + } + { //brush 270 + ( 400 65535 65535 ) ( 400 -65535 65535 ) ( 400 65535 -65535 ) shootit 16 0 180 1 1 + ( 432 -65535 65535 ) ( 432 65535 65535 ) ( 432 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 + ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 + } + { //brush 271 + ( 144 65535 65535 ) ( 144 -65535 65535 ) ( 144 65535 -65535 ) tile2492 0 0 0 1 1 + ( 400 -65535 65535 ) ( 400 65535 65535 ) ( 400 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 272 + ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) shootit 16 0 180 1 1 + ( 144 -65535 65535 ) ( 144 65535 65535 ) ( 144 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 + ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 + } + { //brush 273 + ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 180 1 1 + ( 432 -65535 65535 ) ( 432 65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 274 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + } + { //brush 275 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 276 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 277 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -58408 29724 65535 ) ( 58824 -28892 65535 ) ( -58408 29724 -65535 ) tile2492 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 + } + { //brush 278 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 + ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 279 + ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 + ( -51172 44196 63387 ) ( 66060 -14420 63387 ) ( -65685 15170 -63601 ) mtn 0 0 0 1 1 + ( -58401 29736 65535 ) ( 58830 -28879 65535 ) ( -58401 29736 -65535 ) mtn 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) mtn 0 0 180 1 1 + } + { //brush 280 + ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + } + { //brush 281 + ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 282 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 + ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 + } + { //brush 283 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_0 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 + ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) fstng_0 0 0 0 1 1 + ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) fstng_0 0 0 0 1 1 + } + { //brush 284 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) shootit 16 16 180 1 1 + ( -65535 1040 65535 ) ( 65535 1040 65535 ) ( -65535 1040 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1072 65535 ) ( -65535 1072 65535 ) ( -65535 1072 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 16 0 1 1 + ( 58504 -65534 29532 ) ( 58504 65534 29532 ) ( -58728 -65534 -29084 ) shootit 16 16 0 1 1 + } + { //brush 285 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 286 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 + ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 + } + { //brush 287 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 + ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 + ( 65535 -63481 16282 ) ( 65535 63675 -15506 ) ( -65535 -63481 16282 ) shootit 16 16 0 1 1 + ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 + ( 65535 -63577 -15898 ) ( 65535 63579 15890 ) ( -65535 -63577 -15898 ) shootit 16 16 0 1 1 + } + { //brush 288 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 + ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 + ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 + ( 65535 -63496 16222 ) ( 65535 63660 -15567 ) ( -65535 -63496 16222 ) shootit 16 16 0 1 1 + ( 65535 -63592 -15838 ) ( 65535 63564 15951 ) ( -65535 -63592 -15838 ) shootit 16 16 0 1 1 + } + { //brush 289 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 + ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 + } + { //brush 290 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 291 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 + ( -58824 -28892 65535 ) ( 58408 29724 65535 ) ( -58824 -28892 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 292 + ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 293 + ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 + ( -58830 -28879 65535 ) ( 58401 29736 65535 ) ( -58830 -28879 -65535 ) mtn 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( -66060 -14420 63387 ) ( 51172 44196 63387 ) ( -51547 -43446 -63601 ) mtn 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) mtn 0 0 0 1 1 + } + { //brush 294 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 + } + { //brush 295 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 + } + { //brush 296 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -64525 -11474 65535 ) ( 64299 12680 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) mtn 0 0 0 1 1 + } + { //brush 297 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 + ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + } + { //brush 298 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 + ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + ( 65534 16203 63501 ) ( -65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 + } + { //brush 299 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -64976 8546 65535 ) ( 65081 -7711 65535 ) ( -64976 8546 -65535 ) mtn 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 + ( 65535 14338 63948 ) ( -65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 + ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 + } + { //brush 300 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -66822 -12895 62915 ) ( 50409 45720 62915 ) ( -50778 -44984 -63149 ) mtn 0 0 0 1 1 + ( -66521 3812 64421 ) ( 63536 20069 64421 ) ( -63635 -19279 -64565 ) mtn 0 0 0 1 1 + ( -63547 19978 64438 ) ( 66510 3720 64438 ) ( -66434 -3113 -64549 ) mtn 0 0 0 1 1 + } + { //brush 301 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 66510 3720 64438 ) ( -63547 19978 64438 ) ( -66434 -3113 -64549 ) mtn 0 0 0 1 1 + ( -56087 37076 63790 ) ( 66636 -8945 63790 ) ( -66577 9104 -63830 ) mtn 0 0 0 1 1 + ( -64797 13842 64802 ) ( 66017 5667 64802 ) ( -65975 -4998 -64900 ) mtn 0 0 0 1 1 + ( -67217 -12106 62651 ) ( 50015 46510 62651 ) ( -50469 -45601 -62954 ) mtn 0 0 0 1 1 + } + { //brush 302 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 + } + { //brush 303 + ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 304 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) millgt1 0 0 0 1 0.500000 + } + { //brush 305 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( -65534 15887 63580 ) ( 65534 15887 63580 ) ( -65534 -15902 -63576 ) stnwll02 0 0 0 1 1 + ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) stnwll02 0 0 0 1 1 + } + { //brush 306 + ( 1920 65535 65535 ) ( 1920 -65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + } + { //brush 307 + ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 308 + ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 + ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 0 0 0 1 0.500000 + } + { //brush 309 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1888 -65535 65535 ) ( 1888 65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + } + { //brush 310 + ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 + } + { //brush 311 + ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 180 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 + } + { //brush 312 + ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 180 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 + ( 47116 65535 45564 ) ( 47116 -65535 45564 ) ( -45564 65535 -47116 ) fstng_2 0 16 0 1 1 + } + { //brush 313 + ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 90 1 1 + ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 90 1 1 + ( 47116 -65535 45564 ) ( 47116 65535 45564 ) ( -45564 65535 -47116 ) fstng_2 0 16 90 1 1 + } + { //brush 314 + ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 + ( 47172 -65535 45508 ) ( 47172 65535 45508 ) ( -45508 65535 -47172 ) millgt1 16 0 90 1 0.500000 + } + { //brush 315 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 316 + ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 + } + { //brush 317 + ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 318 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 0 0 1 0.500000 + ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) millgt1 0 0 0 1 0.500000 + ( -65534 -15887 63580 ) ( 65534 -15887 63580 ) ( -65534 15902 -63576 ) millgt1 0 0 0 1 0.500000 + } + { //brush 319 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65534 -15887 63580 ) ( -65534 -15887 63580 ) ( -65534 15902 -63576 ) stnwll02 0 0 0 1 1 + } + { //brush 320 + ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 321 + ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 322 + ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 323 + ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 + } + { //brush 324 + ( 2224 65535 65535 ) ( 2224 -65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll01 0 0 90 1 1 + } + { //brush 325 + ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 + ( -65534 15333 63718 ) ( 65534 15333 63718 ) ( -65534 -16455 -63438 ) stnwll01 0 0 0 1 1 + } + { //brush 326 + ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 + ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 16 0 0 1 0.500000 + ( 65534 15333 63718 ) ( -65534 15333 63718 ) ( -65534 -16455 -63438 ) millgt1 16 0 0 1 0.500000 + } + { //brush 327 + ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 + ( -65534 15333 63718 ) ( 65534 15333 63718 ) ( -65534 -16455 -63438 ) stnwll01 0 0 0 1 1 + } + { //brush 328 + ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 + ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 16 0 0 1 0.500000 + ( 65534 15333 63718 ) ( -65534 15333 63718 ) ( -65534 -16455 -63438 ) millgt1 16 0 0 1 0.500000 + } + { //brush 329 + ( 1920 65535 65535 ) ( 1920 -65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + } + { //brush 330 + ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 + ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 331 + ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 + } + { //brush 332 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1888 -65535 65535 ) ( 1888 65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + } + { //brush 333 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 + } + { //brush 334 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 335 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 336 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_0 0 0 0 1 1 + } + { //brush 337 + ( 960 65535 65535 ) ( 960 -65535 65535 ) ( 960 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + } + { //brush 338 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 65535 -63731 -15280 ) ( 65535 63424 16508 ) ( -65535 -63731 -15280 ) ftlattice2 16 16 0 1 1 + ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 + ( 65535 -63439 16447 ) ( 65535 63716 -15341 ) ( -65535 -63439 16447 ) ftlattice2 16 16 0 1 1 + ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 + } + { //brush 339 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 + ( 65535 -63716 -15341 ) ( 65535 63439 16447 ) ( -65535 -63716 -15341 ) ftlattice2 16 16 0 1 1 + ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 + ( 65535 -63424 16508 ) ( 65535 63731 -15280 ) ( -65535 -63424 16508 ) ftlattice2 16 16 0 1 1 + } + { //brush 340 + ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) stnwll05 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 341 + ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + } + { //brush 342 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 343 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 688 ) ( 65535 65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 344 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 + ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 345 + ( 872 65535 65535 ) ( 872 -65535 65535 ) ( 872 65535 -65535 ) ctf07 32 48 0 1 1 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) ctf07 32 48 0 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) ctf07 32 48 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) ctf07 32 48 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf07 32 48 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf07 32 48 90 1 1 + } + { //brush 346 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 + } + { //brush 347 + ( 872 65535 65535 ) ( 872 -65535 65535 ) ( 872 65535 -65535 ) ctf07 32 48 0 1 1 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) ctf07 32 48 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf07 32 48 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) ctf07 32 48 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf07 32 48 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf07 32 48 90 1 1 + } + { //brush 348 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 + ( 59032 -65534 -28476 ) ( 59032 65534 -28476 ) ( -58200 -65534 30140 ) fstng_2 0 0 0 1 1 + ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 349 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( 59032 -65534 -28476 ) ( 59032 65534 -28476 ) ( -58200 -65534 30140 ) fstng_2 0 0 0 1 1 + } + { //brush 350 + ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 351 + ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 352 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 + ( 65535 -63747 -15216 ) ( 65535 63408 16572 ) ( -65535 -63747 -15216 ) ftlattice2 16 0 0 1 1 + ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 0 0 1 1 + ( 65535 -63455 16383 ) ( 65535 63700 -15405 ) ( -65535 -63455 16383 ) ftlattice2 16 0 0 1 1 + ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 0 0 1 1 + } + { //brush 353 + ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) fstng_2 0 16 180 1 1 + } + { //brush 354 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 355 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 356 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 + ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 357 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 62109 -20911 65535 ) ( -62234 20536 65535 ) ( -62234 20536 -65535 ) mtn 0 0 0 1 1 + } + { //brush 358 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( 62109 -20911 65535 ) ( -62234 20536 65535 ) ( -62234 20536 -65535 ) mtn 0 0 0 1 1 + } + { //brush 359 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_0 0 0 0 1 1 + } + { //brush 360 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_2 0 16 180 1 1 + } + { //brush 361 + ( 1712 65535 65535 ) ( 1712 -65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 + } + { //brush 362 + ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 0.500000 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 + } + { //brush 363 + ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 + ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 364 + ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1680 -65535 65535 ) ( 1680 65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 + } + { //brush 365 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 366 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 + ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 0 0 0 1 0.500000 + } + { //brush 367 + ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 + } + { //brush 368 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( -45284 65535 47396 ) ( -45284 -65535 47396 ) ( 47396 65535 -45284 ) fstng_2 0 0 90 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 369 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 1 + ( 63767 -65534 -15137 ) ( 63767 65534 -15137 ) ( -63389 -65534 16651 ) millgt1 16 0 0 1 1 + ( 63588 -65534 15853 ) ( 63588 65534 15853 ) ( -63567 -65534 -15935 ) millgt1 16 0 0 1 1 + ( 65535 -63501 16203 ) ( 65535 63655 -15585 ) ( -65535 -63501 16203 ) millgt1 16 0 0 1 1 + ( 65535 -63679 -15487 ) ( 65535 63476 16301 ) ( -65535 -63679 -15487 ) millgt1 16 0 0 1 1 + } + { //brush 370 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 46980 -65535 45700 ) ( 46980 65535 45700 ) ( -45700 65535 -46980 ) fstng_2 0 0 90 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 371 + ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll05 0 0 90 1 1 + } + { //brush 372 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 + ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 373 + ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 90 1 1 + } + { //brush 374 + ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 + ( -65535 -46196 46484 ) ( 65535 -46196 46484 ) ( -65535 46484 -46196 ) millgt1 16 0 0 1 0.500000 + } + { //brush 375 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -352 65535 ) ( 65535 -352 65535 ) ( -65535 -352 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + } + { //brush 376 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -384 65535 ) ( 65535 -384 65535 ) ( -65535 -384 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -352 65535 ) ( -65535 -352 65535 ) ( -65535 -352 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 + } + { //brush 377 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -416 65535 ) ( 65535 -416 65535 ) ( -65535 -416 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -384 65535 ) ( -65535 -384 65535 ) ( -65535 -384 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + } + { //brush 378 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -416 65535 ) ( -65535 -416 65535 ) ( -65535 -416 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 379 + ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 380 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 0 0 0 1 0.500000 + } + { //brush 381 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 0 1 1 + ( -65534 15352 63713 ) ( 65534 15352 63713 ) ( -65534 -16436 -63442 ) stnwll02 0 0 0 1 1 + ( 65535 -46268 46412 ) ( -65535 -46268 46412 ) ( -65535 46412 -46268 ) stnwll02 0 0 0 1 1 + } + { //brush 382 + ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 383 + ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + } + { //brush 384 + ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -28168 59185 65535 ) ( 30447 -58046 65535 ) ( -28168 59185 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 385 + ( 1280 65535 65535 ) ( 1280 -65535 65535 ) ( 1280 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 386 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + ( -65534 15352 63713 ) ( 65534 15352 63713 ) ( -65534 -16436 -63442 ) stnwll02 0 0 0 1 1 + ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 387 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 + ( 65534 15352 63713 ) ( -65534 15352 63713 ) ( -65534 -16436 -63442 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 0 0 0 1 0.500000 + } + { //brush 388 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 389 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll05 0 0 90 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 + ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 + ( 28937 -58807 65535 ) ( -27299 59585 65535 ) ( -27299 59585 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 390 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 391 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 30114 58213 65535 ) ( -28501 -59019 65535 ) ( 30114 58213 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 392 + ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 + ( -28501 -59019 65535 ) ( 30114 58213 65535 ) ( 30114 58213 -65535 ) stnwll05 0 0 0 1 1 + ( 30088 -58225 65535 ) ( -28527 59006 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 393 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 + ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 + ( -28501 -59019 65535 ) ( 30114 58213 65535 ) ( 30114 58213 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 394 + ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 + ( 58606 65534 29327 ) ( 58606 -65534 29327 ) ( -58625 -65534 -29288 ) stnfloor02 0 0 0 1 1 + ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 395 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( 30447 -58046 65535 ) ( -28168 59185 65535 ) ( -28168 59185 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) fstng_2 0 0 0 1 1 + ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 396 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 + ( 30248 -58145 65535 ) ( -28367 59086 65535 ) ( -28367 59086 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 397 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) millgt1 16 0 90 1 0.500000 + ( 46700 -65535 45980 ) ( 46700 65535 45980 ) ( -45980 65535 -46700 ) millgt1 16 0 90 1 0.500000 + ( -14746 65534 63865 ) ( -14746 -65534 63865 ) ( 17042 65534 -63291 ) millgt1 16 0 0 1 0.500000 + } + { //brush 398 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + } + { //brush 399 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 400 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) fstng_2 0 0 0 1 1 + ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 401 + ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 402 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 + ( -65535 45972 46708 ) ( 65535 45972 46708 ) ( -65535 -46708 -45972 ) stnwll05 0 0 0 1 1 + } + { //brush 403 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 + ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 + } + { //brush 404 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + } + { //brush 405 + ( 1008 65535 65535 ) ( 1008 -65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 406 + ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 + ( -65534 -16116 63522 ) ( 65534 -16116 63522 ) ( -65534 15672 -63633 ) millgt1 16 0 0 1 0.500000 + } + { //brush 407 + ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 + } + { //brush 408 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 976 -65535 65535 ) ( 976 65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 409 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 410 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 411 + ( 1600 65535 65535 ) ( 1600 -65535 65535 ) ( 1600 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 412 + ( 1568 65535 65535 ) ( 1568 -65535 65535 ) ( 1568 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1600 -65535 65535 ) ( 1600 65535 65535 ) ( 1600 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 + } + { //brush 413 + ( 1536 65535 65535 ) ( 1536 -65535 65535 ) ( 1536 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 + } + { //brush 414 + ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1536 -65535 65535 ) ( 1536 65535 65535 ) ( 1536 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 + } + { //brush 415 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + } + { //brush 416 + ( 1440 65535 65535 ) ( 1440 -65535 65535 ) ( 1440 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 417 + ( 1408 65535 65535 ) ( 1408 -65535 65535 ) ( 1408 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1440 -65535 65535 ) ( 1440 65535 65535 ) ( 1440 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + } + { //brush 418 + ( 1376 65535 65535 ) ( 1376 -65535 65535 ) ( 1376 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1408 -65535 65535 ) ( 1408 65535 65535 ) ( 1408 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 + } + { //brush 419 + ( 1344 65535 65535 ) ( 1344 -65535 65535 ) ( 1344 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 1376 -65535 65535 ) ( 1376 65535 65535 ) ( 1376 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 + } + { //brush 420 + ( 1312 65535 65535 ) ( 1312 -65535 65535 ) ( 1312 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1344 -65535 65535 ) ( 1344 65535 65535 ) ( 1344 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 421 + ( 1280 65535 65535 ) ( 1280 -65535 65535 ) ( 1280 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1312 -65535 65535 ) ( 1312 65535 65535 ) ( 1312 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 + } + { //brush 422 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 + } + { //brush 423 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 424 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 425 + ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 + ( 52679 65535 -38985 ) ( 52679 -65535 -38985 ) ( -52176 -65535 39656 ) stonesnow 0 0 0 1 1 + } + { //brush 426 + ( -240 65535 65535 ) ( -240 -65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 180 1 1 + ( 240 -65535 65535 ) ( 240 65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) stonesnow 0 0 0 1 1 + ( 65534 -29084 58728 ) ( -65534 -29084 58728 ) ( -65534 29532 -58504 ) tile2492 0 0 0 1 1 + } + { //brush 427 + ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 + ( 52176 65535 39656 ) ( 52176 -65535 39656 ) ( -52679 -65535 -38985 ) stonesnow 0 0 0 1 1 + } + { //brush 428 + ( 280 65535 65535 ) ( 280 -65535 65535 ) ( 280 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 180 1 1 + } + { //brush 429 + ( 276 65535 65535 ) ( 276 -65535 65535 ) ( 276 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 180 1 1 + } + { //brush 430 + ( 272 65535 65535 ) ( 272 -65535 65535 ) ( 272 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 431 + ( 268 65535 65535 ) ( 268 -65535 65535 ) ( 268 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 432 + ( 264 65535 65535 ) ( 264 -65535 65535 ) ( 264 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 433 + ( 260 65535 65535 ) ( 260 -65535 65535 ) ( 260 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 434 + ( 256 65535 65535 ) ( 256 -65535 65535 ) ( 256 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 + ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 435 + ( 252 65535 65535 ) ( 252 -65535 65535 ) ( 252 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 + ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 436 + ( 248 65535 65535 ) ( 248 -65535 65535 ) ( 248 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 + ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 437 + ( 244 65535 65535 ) ( 244 -65535 65535 ) ( 244 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 + ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 438 + ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 + ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 439 + ( 236 65535 65535 ) ( 236 -65535 65535 ) ( 236 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 + ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 440 + ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 441 + ( -276 -65535 65535 ) ( -276 65535 65535 ) ( -276 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 442 + ( -272 -65535 65535 ) ( -272 65535 65535 ) ( -272 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 + } + { //brush 443 + ( -268 -65535 65535 ) ( -268 65535 65535 ) ( -268 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 444 + ( -264 -65535 65535 ) ( -264 65535 65535 ) ( -264 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 445 + ( -260 -65535 65535 ) ( -260 65535 65535 ) ( -260 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 + } + { //brush 446 + ( -256 -65535 65535 ) ( -256 65535 65535 ) ( -256 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 + ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 447 + ( -252 -65535 65535 ) ( -252 65535 65535 ) ( -252 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 + ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 448 + ( -248 -65535 65535 ) ( -248 65535 65535 ) ( -248 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 + ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 449 + ( -244 -65535 65535 ) ( -244 65535 65535 ) ( -244 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 + ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 450 + ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 + ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 451 + ( -236 -65535 65535 ) ( -236 65535 65535 ) ( -236 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 + ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 452 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 + ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 + } + { //brush 453 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 0 1 1 + } + { //brush 454 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 455 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 + ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) fstng_0 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 + } + { //brush 456 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 0 16 0 1 1 + ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 0 16 0 1 1 + ( 63646 -65534 -15623 ) ( 63646 65534 -15623 ) ( -63510 -65534 16165 ) shootit 0 16 0 1 1 + ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 0 16 0 1 1 + ( 63534 -65534 16067 ) ( 63534 65534 16067 ) ( -63621 -65534 -15721 ) shootit 0 16 0 1 1 + } + { //brush 457 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 16 16 0 1 1 + ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 16 16 0 1 1 + ( 63522 -65534 16116 ) ( 63522 65534 16116 ) ( -63633 -65534 -15672 ) shootit 16 16 0 1 1 + ( 63633 -65534 -15672 ) ( 63633 65534 -15672 ) ( -63522 -65534 16116 ) shootit 16 16 0 1 1 + ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 16 16 0 1 1 + } + { //brush 458 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 0 16 0 1 1 + ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 0 16 0 1 1 + ( 63621 -65534 -15721 ) ( 63621 65534 -15721 ) ( -63534 -65534 16067 ) shootit 0 16 0 1 1 + ( 63510 -65534 16165 ) ( 63510 65534 16165 ) ( -63646 -65534 -15623 ) shootit 0 16 0 1 1 + ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 0 16 0 1 1 + } + { //brush 459 + ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 + ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 + ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 + } + { //brush 460 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 + ( 58750 -65534 -29039 ) ( 58750 65534 -29039 ) ( -58481 -65534 29576 ) fstng_0 0 0 0 1 1 + } + { //brush 461 + ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58565 -65534 29410 ) ( 58565 65534 29410 ) ( -58667 -65534 -29205 ) fstng_0 0 0 0 1 1 + } + { //brush 462 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 90 1 1 + } + { //brush 463 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 + } + { //brush 464 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 + } + { //brush 465 + ( 120 65535 65535 ) ( 120 -65535 65535 ) ( 120 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 76 ) ( 65535 65535 76 ) ( -65535 -65535 76 ) fstng_0 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 + } + { //brush 466 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 76 ) ( 65535 -65535 76 ) ( -65535 -65535 76 ) stonesnow 0 0 90 1 1 + ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 + } + { //brush 467 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 + ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 + } + { //brush 468 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58523 -65534 29493 ) ( 58523 65534 29493 ) ( -58709 -65534 -29122 ) fstng_0 0 0 0 1 1 + } + { //brush 469 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58709 -65534 -29122 ) ( 58709 65534 -29122 ) ( -58523 -65534 29493 ) fstng_0 0 0 0 1 1 + } + { //brush 470 + ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 90 1 1 + } + { //brush 471 + ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 + ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 + ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 + } + { //brush 472 + ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58667 -65534 -29205 ) ( 58667 65534 -29205 ) ( -58565 -65534 29410 ) fstng_0 0 0 0 1 1 + } + { //brush 473 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 + ( 58481 -65534 29576 ) ( 58481 65534 29576 ) ( -58750 -65534 -29039 ) fstng_0 0 0 0 1 1 + } + { //brush 474 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 180 1 1 + } + { //brush 475 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 + } + { //brush 476 + ( -120 -65535 65535 ) ( -120 65535 65535 ) ( -120 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 76 ) ( 65535 65535 76 ) ( -65535 -65535 76 ) fstng_0 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 + } + { //brush 477 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 76 ) ( 65535 -65535 76 ) ( -65535 -65535 76 ) stonesnow 0 0 90 1 1 + ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 + } + { //brush 478 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 + } + { //brush 479 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 + } + { //brush 480 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 481 + ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 + ( 52679 65535 -38985 ) ( 52679 -65535 -38985 ) ( -52176 -65535 39656 ) stonesnow 0 0 0 1 1 + } + { //brush 482 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 67217 12106 62651 ) ( -50015 -46510 62651 ) ( -66762 -13015 -62954 ) mtn 0 0 0 1 1 + ( 64797 -13842 64802 ) ( -66017 -5667 64802 ) ( -64839 13174 -64900 ) mtn 0 0 0 1 1 + ( -66510 -3720 64438 ) ( 63547 -19978 64438 ) ( -63623 19370 -64549 ) mtn 0 0 0 1 1 + ( 56087 -37076 63790 ) ( -66636 8945 63790 ) ( -56147 36916 -63830 ) mtn 0 0 0 1 1 + } + { //brush 483 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 63547 -19978 64438 ) ( -66510 -3720 64438 ) ( -63623 19370 -64549 ) mtn 0 0 0 1 1 + ( 66822 12895 62915 ) ( -50409 -45720 62915 ) ( -66454 -13631 -63149 ) mtn 0 0 0 1 1 + ( 66521 -3812 64421 ) ( -63536 -20069 64421 ) ( -66422 3021 -64565 ) mtn 0 0 0 1 1 + } + { //brush 484 + ( -240 65535 65535 ) ( -240 -65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 180 1 1 + ( 240 -65535 65535 ) ( 240 65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) stonesnow 0 0 0 1 1 + ( -65534 29084 58728 ) ( 65534 29084 58728 ) ( -65534 -29532 -58504 ) tile2492 0 0 0 1 1 + } + { //brush 485 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 60097 26141 65535 ) ( -59675 -27091 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 + ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + } + { //brush 486 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 + ( -64306 -12641 65535 ) ( 64518 11513 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 + } + { //brush 487 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -65081 7711 65535 ) ( 64976 -8546 65535 ) ( -65081 7711 -65535 ) mtn 0 0 0 1 1 + ( -64299 -12680 65535 ) ( 64525 11474 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 + ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + } + { //brush 488 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 64976 -8546 65535 ) ( -65081 7711 65535 ) ( -65081 7711 -65535 ) mtn 0 0 0 1 1 + ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( -64299 -12680 65535 ) ( 64525 11474 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 + } + { //brush 489 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( -65534 15314 63723 ) ( 65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( -59675 -27091 65535 ) ( 60097 26141 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 + ( 65534 15329 63719 ) ( -65534 15329 63719 ) ( -65534 -16459 -63437 ) mtn 0 0 0 1 1 + ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 + ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 + ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 + ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 + } + { //brush 490 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 + ( -65534 15314 63723 ) ( 65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 + ( 60097 26141 65535 ) ( -59675 -27091 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 + } + { //brush 491 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( -58795 28949 65535 ) ( 58437 -29666 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 + ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 + ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( -54501 -38733 64180 ) ( 65271 14499 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 + ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + } + { //brush 492 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 + ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( -54501 -38733 64180 ) ( 65271 14499 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 + ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 + ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 + ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 + } + { //brush 493 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 + ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 + } + { //brush 494 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 64088 13701 65535 ) ( -63859 -14731 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 + ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + } + { //brush 495 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 64525 11474 65535 ) ( -64299 -12680 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 + } + { //brush 496 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + } + { //brush 497 + ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 + ( 52176 65535 39656 ) ( 52176 -65535 39656 ) ( -52679 -65535 -38985 ) stonesnow 0 0 0 1 1 + } + { //brush 498 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 + } + { //brush 499 + ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58565 -65534 29410 ) ( 58565 65534 29410 ) ( -58667 -65534 -29205 ) fstng_0 0 0 0 1 1 + } + { //brush 500 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) tile2492 0 0 90 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 + } + { //brush 501 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 + ( 58750 -65534 -29039 ) ( 58750 65534 -29039 ) ( -58481 -65534 29576 ) fstng_0 0 0 0 1 1 + } + { //brush 502 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 + ( 65534 -29320 58609 ) ( -65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 180 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 503 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + } + { //brush 504 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 505 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 + } + { //brush 506 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58523 -65534 29493 ) ( 58523 65534 29493 ) ( -58709 -65534 -29122 ) fstng_0 0 0 0 1 1 + } + { //brush 507 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58709 -65534 -29122 ) ( 58709 65534 -29122 ) ( -58523 -65534 29493 ) fstng_0 0 0 0 1 1 + } + { //brush 508 + ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 + } + { //brush 509 + ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 + } + { //brush 510 + ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 58667 -65534 -29205 ) ( 58667 65534 -29205 ) ( -58565 -65534 29410 ) fstng_0 0 0 0 1 1 + } + { //brush 511 + ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 + ( 58481 -65534 29576 ) ( 58481 65534 29576 ) ( -58750 -65534 -29039 ) fstng_0 0 0 0 1 1 + } + { //brush 512 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 513 + ( 280 65535 65535 ) ( 280 -65535 65535 ) ( 280 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 514 + ( 276 65535 65535 ) ( 276 -65535 65535 ) ( 276 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 515 + ( 272 65535 65535 ) ( 272 -65535 65535 ) ( 272 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 516 + ( 268 65535 65535 ) ( 268 -65535 65535 ) ( 268 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 517 + ( 264 65535 65535 ) ( 264 -65535 65535 ) ( 264 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 518 + ( 260 65535 65535 ) ( 260 -65535 65535 ) ( 260 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 519 + ( 256 65535 65535 ) ( 256 -65535 65535 ) ( 256 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 + ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 520 + ( 252 65535 65535 ) ( 252 -65535 65535 ) ( 252 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 + ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 521 + ( 248 65535 65535 ) ( 248 -65535 65535 ) ( 248 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 + ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 522 + ( 244 65535 65535 ) ( 244 -65535 65535 ) ( 244 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 + ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 523 + ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 + ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 524 + ( 236 65535 65535 ) ( 236 -65535 65535 ) ( 236 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 + ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 525 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 0 1 1 + } + { //brush 526 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 527 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 + ( 58824 28892 65535 ) ( -58408 -29724 65535 ) ( -58408 -29724 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 528 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 529 + ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 + ( 66060 14420 63387 ) ( -51172 -44196 63387 ) ( -65685 -15170 -63601 ) mtn 0 0 0 1 1 + ( 58830 28879 65535 ) ( -58401 -29736 65535 ) ( -58401 -29736 -65535 ) mtn 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) mtn 0 0 180 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + } + { //brush 530 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 531 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 532 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 533 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 534 + ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 535 + ( -276 -65535 65535 ) ( -276 65535 65535 ) ( -276 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 536 + ( -272 -65535 65535 ) ( -272 65535 65535 ) ( -272 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 + } + { //brush 537 + ( -268 -65535 65535 ) ( -268 65535 65535 ) ( -268 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 538 + ( -264 -65535 65535 ) ( -264 65535 65535 ) ( -264 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 539 + ( -260 -65535 65535 ) ( -260 65535 65535 ) ( -260 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 + } + { //brush 540 + ( -256 -65535 65535 ) ( -256 65535 65535 ) ( -256 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 + ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 541 + ( -252 -65535 65535 ) ( -252 65535 65535 ) ( -252 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 + ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 542 + ( -248 -65535 65535 ) ( -248 65535 65535 ) ( -248 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 + ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 543 + ( -244 -65535 65535 ) ( -244 65535 65535 ) ( -244 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 + ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 544 + ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 + ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 + } + { //brush 545 + ( -236 -65535 65535 ) ( -236 65535 65535 ) ( -236 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 + ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 + } + { //brush 546 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 + ( -58824 28892 65535 ) ( 58408 -29724 65535 ) ( -58824 28892 -65535 ) tile2492 0 0 180 1 1 + } + { //brush 547 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 + ( 58408 -29724 65535 ) ( -58824 28892 65535 ) ( -58824 28892 -65535 ) tile2492 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 180 1 1 + } + { //brush 548 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 549 + ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 550 + ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 + ( 58401 -29736 65535 ) ( -58830 28879 65535 ) ( -58830 28879 -65535 ) mtn 0 0 0 1 1 + ( 51172 -44196 63387 ) ( -66060 14420 63387 ) ( -51547 43446 -63601 ) mtn 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 + } + { //brush 551 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 180 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 552 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) stonesnow 0 0 180 1 1 + } + { //brush 553 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 554 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 180 1 1 + } + { //brush 555 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 + ( -65534 -16203 63501 ) ( 65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 + ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 + } + { //brush 556 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 + ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 + } + { //brush 557 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 64088 13701 65535 ) ( -63859 -14731 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 + ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 + ( -58795 28949 65535 ) ( 58437 -29666 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 + ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + } + { //brush 558 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 + ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 + ( 63219 26421 62412 ) ( -67199 13380 62412 ) ( -63094 -27677 -61993 ) mtn 0 0 0 1 1 + ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 + } + { //brush 559 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( -65271 14499 64180 ) ( 54501 -38733 64180 ) ( -54837 37977 -64346 ) mtn 0 0 0 1 1 + ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 + } + { //brush 560 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + ( 54501 -38733 64180 ) ( -65271 14499 64180 ) ( -54837 37977 -64346 ) mtn 0 0 0 1 1 + } + { //brush 561 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) stonesnow 0 0 0 1 1 + ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) stonesnow 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 562 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 563 + ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65534 -16350 63464 ) ( -65534 -16350 63464 ) ( -65534 15439 -63692 ) stnwll02 0 0 0 1 1 + } + { //brush 564 + ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65535 45828 46852 ) ( -65535 45828 46852 ) ( -65535 -46852 -45828 ) millgt1 16 0 0 1 0.500000 + } + { //brush 565 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1680 -65535 65535 ) ( 1680 65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 566 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 567 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 + ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 180 1 1 + } + { //brush 568 + ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 + ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 + ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + } + { //brush 569 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 + ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 + ( -58488 -29564 65535 ) ( 58744 29052 65535 ) ( -58488 -29564 -65535 ) mtn 0 0 0 1 1 + ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 + } + { //brush 570 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 58744 29052 65535 ) ( -58488 -29564 65535 ) ( -58488 -29564 -65535 ) mtn 0 0 0 1 1 + ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 + ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + } + { //brush 571 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) stonesnow 0 0 0 1 1 + ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) stonesnow 0 0 0 1 1 + ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 572 + ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 + ( 64306 -12641 65535 ) ( -64518 11513 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 + ( -64976 -8546 65535 ) ( 65081 7711 65535 ) ( -64976 -8546 -65535 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 + } + { //brush 573 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 574 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) ftlattice2 16 16 0 1 1 + ( 65535 -63726 -15303 ) ( 65535 63430 16485 ) ( -65535 -63726 -15303 ) ftlattice2 16 16 0 1 1 + ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 16 0 1 1 + ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 16 0 1 1 + } + { //brush 575 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 0 1 1 + ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 + } + { //brush 576 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 577 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 578 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 + ( -27688 59425 65535 ) ( 30927 -57806 65535 ) ( -27688 59425 -65535 ) stnwll01 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 579 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 580 + ( 1872 65535 65535 ) ( 1872 -65535 65535 ) ( 1872 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 65535 672 ) ( 65535 -65535 672 ) ( -65535 -65535 672 ) fstng_2 0 0 0 1 1 + ( -65535 -46316 46364 ) ( 65535 -46316 46364 ) ( -65535 46364 -46316 ) fstng_2 0 0 0 1 1 + } + { //brush 581 + ( 1808 65535 65535 ) ( 1808 -65535 65535 ) ( 1808 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1872 -65535 65535 ) ( 1872 65535 65535 ) ( 1872 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 + } + { //brush 582 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 + ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 + ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 + ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 + } + { //brush 583 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 0 16 0 1 1 + ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 0 16 0 1 1 + ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 0 16 0 1 1 + ( 63512 -65534 16158 ) ( 63512 65534 16158 ) ( -63644 -65534 -15631 ) ftlattice2 0 16 0 1 1 + ( 63804 -65534 -14991 ) ( 63804 65534 -14991 ) ( -63352 -65534 16798 ) ftlattice2 0 16 0 1 1 + } + { //brush 584 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 + ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 + ( 63823 -65534 -14911 ) ( 63823 65534 -14911 ) ( -63332 -65534 16877 ) ftlattice2 16 16 0 1 1 + ( 63532 -65534 16079 ) ( 63532 65534 16079 ) ( -63624 -65534 -15710 ) ftlattice2 16 16 0 1 1 + } + { //brush 585 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) tile2492 0 0 90 1 1 + } + { //brush 586 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( 66017 -5667 64802 ) ( -64797 -13842 64802 ) ( -65975 4998 -64900 ) mtn 0 0 0 1 1 + ( 66636 8945 63790 ) ( -56087 -37076 63790 ) ( -66577 -9104 -63830 ) mtn 0 0 0 1 1 + ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 + } + { //brush 587 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 + ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 + ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 + } + { //brush 588 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 + ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) tile2492 0 0 180 1 1 + } + { //brush 589 + ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 + ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 + } + { //brush 590 + ( 1872 -65535 65535 ) ( 1872 65535 65535 ) ( 1872 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 0 1 1 + } + { //brush 591 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 592 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 16 180 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 16 0 1 1 + ( 46508 65535 46172 ) ( 46508 -65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 0 1 1 + ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 0 1 1 + } + { //brush 593 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 180 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 16 90 1 1 + } + { //brush 594 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 90 1 1 + } + { //brush 595 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) fstng_2 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 596 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) tile2492 0 0 90 1 1 + ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 + } + { //brush 597 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_0 0 0 0 1 1 + ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 598 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 + ( 65535 -63579 15890 ) ( 65535 63577 -15898 ) ( -65535 -63579 15890 ) shootit 16 16 0 1 1 + ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 + ( 65535 -63675 -15506 ) ( 65535 63481 16282 ) ( -65535 -63675 -15506 ) shootit 16 16 0 1 1 + ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 + } + { //brush 599 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 + ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) tile2492 0 0 90 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 + } + { //brush 600 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 65535 45644 47036 ) ( -65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 + } + { //brush 601 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( 65535 45644 47036 ) ( -65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 + ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 602 + ( 2224 65535 65535 ) ( 2224 -65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 + } + { //brush 603 + ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 + ( 65535 45596 47084 ) ( -65535 45596 47084 ) ( -65535 -47084 -45596 ) millgt1 16 0 0 1 0.500000 + ( -65534 -16598 63402 ) ( 65534 -16598 63402 ) ( -65534 15190 -63754 ) millgt1 16 0 0 1 0.500000 + } + { //brush 604 + ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 0 1 1 + ( 65534 -16598 63402 ) ( -65534 -16598 63402 ) ( -65534 15190 -63754 ) stnwll01 0 0 0 1 1 + } + { //brush 605 + ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 + ( 65535 45596 47084 ) ( -65535 45596 47084 ) ( -65535 -47084 -45596 ) millgt1 16 0 0 1 0.500000 + ( -65534 -16598 63402 ) ( 65534 -16598 63402 ) ( -65534 15190 -63754 ) millgt1 16 0 0 1 0.500000 + } + { //brush 606 + ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 0 1 1 + ( 65534 -16598 63402 ) ( -65534 -16598 63402 ) ( -65534 15190 -63754 ) stnwll01 0 0 0 1 1 + } + { //brush 607 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 608 + ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 + } + { //brush 609 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 + ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 + } + { //brush 610 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 + ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) mtn 0 0 0 1 1 + } + { //brush 611 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 612 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 613 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 614 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 + ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) mtn 0 0 0 1 1 + } + { //brush 615 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 -36876 54178 ) ( -65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 + } + { //brush 616 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -36876 54178 ) ( -65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 + } + { //brush 617 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 618 + ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 + } + { //brush 619 + ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 180 1 1 + ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 620 + ( -144 65535 65535 ) ( -144 -65535 65535 ) ( -144 65535 -65535 ) shootit 16 0 180 1 1 + ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 + ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 + } + { //brush 621 + ( -400 65535 65535 ) ( -400 -65535 65535 ) ( -400 65535 -65535 ) tile2492 0 0 0 1 1 + ( -144 -65535 65535 ) ( -144 65535 65535 ) ( -144 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 622 + ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) shootit 16 0 180 1 1 + ( -400 -65535 65535 ) ( -400 65535 65535 ) ( -400 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 + ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 + } + { //brush 623 + ( -464 65535 65535 ) ( -464 -65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 0 1 1 + ( -432 -65535 65535 ) ( -432 65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 + } + { //brush 624 + ( -496 65535 65535 ) ( -496 -65535 65535 ) ( -496 65535 -65535 ) shootit 16 0 180 1 1 + ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 + ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 + } + { //brush 625 + ( -496 -65535 65535 ) ( -496 65535 65535 ) ( -496 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 626 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 627 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 180 1 1 + } + { //brush 628 + ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 629 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 + ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 630 + ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) shootit 16 0 180 1 1 + ( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 + ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) shootit 16 0 0 1 1 + } + { //brush 631 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 + ( -784 -65535 65535 ) ( -784 65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 + } + { //brush 632 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + } + { //brush 633 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 15073 65534 63783 ) ( 15073 -65534 63783 ) ( -16715 65534 -63373 ) stnwll01 0 0 0 1 1 + } + { //brush 634 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 + ( -46436 65535 46244 ) ( -46436 -65535 46244 ) ( 46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 + ( 15073 -65534 63783 ) ( 15073 65534 63783 ) ( -16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 + } + { //brush 635 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 15073 65534 63783 ) ( 15073 -65534 63783 ) ( -16715 65534 -63373 ) stnwll01 0 0 0 1 1 + } + { //brush 636 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 + ( -46436 65535 46244 ) ( -46436 -65535 46244 ) ( 46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 + ( 15073 -65534 63783 ) ( 15073 65534 63783 ) ( -16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 + } + { //brush 637 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + } + { //brush 638 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) shootit 16 16 180 1 1 + ( -65535 -1072 65535 ) ( 65535 -1072 65535 ) ( -65535 -1072 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -1040 65535 ) ( -65535 -1040 65535 ) ( -65535 -1040 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 16 0 1 1 + ( 58728 -65534 -29084 ) ( 58728 65534 -29084 ) ( -58504 -65534 29532 ) shootit 16 16 0 1 1 + } + { //brush 639 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 640 + ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 641 + ( -144 65535 65535 ) ( -144 -65535 65535 ) ( -144 65535 -65535 ) shootit 16 0 180 1 1 + ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 + ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 + } + { //brush 642 + ( -400 65535 65535 ) ( -400 -65535 65535 ) ( -400 65535 -65535 ) tile2492 0 0 0 1 1 + ( -144 -65535 65535 ) ( -144 65535 65535 ) ( -144 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 643 + ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) shootit 16 0 180 1 1 + ( -400 -65535 65535 ) ( -400 65535 65535 ) ( -400 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 + ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 + } + { //brush 644 + ( -464 65535 65535 ) ( -464 -65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 0 1 1 + ( -432 -65535 65535 ) ( -432 65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 645 + ( -496 65535 65535 ) ( -496 -65535 65535 ) ( -496 65535 -65535 ) shootit 16 0 180 1 1 + ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 + ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 + } + { //brush 646 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) tile2492 0 0 0 1 1 + ( -496 -65535 65535 ) ( -496 65535 65535 ) ( -496 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 647 + ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) shootit 16 0 180 1 1 + ( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 + ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 + } + { //brush 648 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 + ( -784 -65535 65535 ) ( -784 65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 649 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) fstng_0 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 + } + { //brush 650 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stnwll01 0 0 0 1 1 + ( 58952 28636 65535 ) ( -58280 -29980 65535 ) ( -58280 -29980 -65535 ) stnwll01 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 0 1 1 + } + { //brush 651 + ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) fstng_2 0 0 0 1 1 + } + { //brush 652 + ( -1968 65535 65535 ) ( -1968 -65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 + } + { //brush 653 + ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) millgt1 16 0 0 1 0.500000 + ( -65535 -45596 47084 ) ( 65535 -45596 47084 ) ( -65535 47084 -45596 ) millgt1 16 0 0 1 0.500000 + } + { //brush 654 + ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 + ( 65535 -45596 47084 ) ( -65535 -45596 47084 ) ( -65535 47084 -45596 ) stnwll01 0 0 0 1 1 + ( -65534 16598 63402 ) ( 65534 16598 63402 ) ( -65534 -15190 -63754 ) stnwll01 0 0 0 1 1 + } + { //brush 655 + ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 + ( -65534 16598 63402 ) ( 65534 16598 63402 ) ( -65534 -15190 -63754 ) stnwll01 0 0 0 1 1 + } + { //brush 656 + ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 + ( -65535 -45596 47084 ) ( 65535 -45596 47084 ) ( -65535 47084 -45596 ) millgt1 16 0 0 1 0.500000 + ( 65534 16598 63402 ) ( -65534 16598 63402 ) ( -65534 -15190 -63754 ) millgt1 16 0 0 1 0.500000 + } + { //brush 657 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 + } + { //brush 658 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( -65535 -45644 47036 ) ( 65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 0 0 1 1 + } + { //brush 659 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( -65535 -45644 47036 ) ( 65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 + ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 660 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 661 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 90 1 1 + } + { //brush 662 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 180 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 16 90 1 1 + } + { //brush 663 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 16 180 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 16 0 1 1 + ( -46508 -65535 46172 ) ( -46508 65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 0 1 1 + ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 0 1 1 + } + { //brush 664 + ( -1872 65535 65535 ) ( -1872 -65535 65535 ) ( -1872 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 + ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 0 1 1 + } + { //brush 665 + ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 + ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 + } + { //brush 666 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_0 0 0 0 1 1 + } + { //brush 667 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 0 16 0 1 1 + ( 63352 -65534 16798 ) ( 63352 65534 16798 ) ( -63804 -65534 -14991 ) ftlattice2 0 16 0 1 1 + ( 63644 -65534 -15631 ) ( 63644 65534 -15631 ) ( -63512 -65534 16158 ) ftlattice2 0 16 0 1 1 + ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 0 16 0 1 1 + ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 0 16 0 1 1 + } + { //brush 668 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 63624 -65534 -15710 ) ( 63624 65534 -15710 ) ( -63532 -65534 16079 ) ftlattice2 16 16 0 1 1 + ( 63332 -65534 16877 ) ( 63332 65534 16877 ) ( -63823 -65534 -14911 ) ftlattice2 16 16 0 1 1 + ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 + ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 + } + { //brush 669 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 + ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 + ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 + ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 + } + { //brush 670 + ( -1872 65535 65535 ) ( -1872 -65535 65535 ) ( -1872 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_0 0 0 0 1 1 + } + { //brush 671 + ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1872 -65535 65535 ) ( -1872 65535 65535 ) ( -1872 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 65535 672 ) ( 65535 -65535 672 ) ( -65535 -65535 672 ) fstng_2 0 0 0 1 1 + ( 65535 46316 46364 ) ( -65535 46316 46364 ) ( -65535 -46364 -46316 ) fstng_2 0 0 0 1 1 + } + { //brush 672 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 673 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 674 + ( -1680 65535 65535 ) ( -1680 -65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 675 + ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( -65534 16350 63464 ) ( 65534 16350 63464 ) ( -65534 -15439 -63692 ) stnwll02 0 0 0 1 1 + } + { //brush 676 + ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -65535 -45828 46852 ) ( 65535 -45828 46852 ) ( -65535 46852 -45828 ) millgt1 16 0 0 1 0.500000 + ( 65534 16350 63464 ) ( -65534 16350 63464 ) ( -65534 -15439 -63692 ) millgt1 16 0 0 1 0.500000 + } + { //brush 677 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 + } + { //brush 678 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( 27688 -59425 65535 ) ( -30927 57806 65535 ) ( -30927 57806 -65535 ) stnwll01 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 679 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 680 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 681 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 0 1 1 + ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 + } + { //brush 682 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 65535 -63430 16485 ) ( 65535 63726 -15303 ) ( -65535 -63430 16485 ) ftlattice2 16 16 0 1 1 + ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 16 0 1 1 + ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) ftlattice2 16 16 0 1 1 + ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 16 0 1 1 + } + { //brush 683 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 684 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) fstng_2 0 16 180 1 1 + } + { //brush 685 + ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnfloor02 0 0 0 1 1 + } + { //brush 686 + ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 687 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 688 ) ( 65535 65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 + ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 688 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 + ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 689 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) ctf08 32 48 0 1 1 + ( -872 -65535 65535 ) ( -872 65535 65535 ) ( -872 65535 -65535 ) ctf08 32 48 0 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) ctf08 32 48 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) ctf08 32 48 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf08 32 48 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf08 32 48 90 1 1 + } + { //brush 690 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 + } + { //brush 691 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) ctf08 32 48 0 1 1 + ( -872 -65535 65535 ) ( -872 65535 65535 ) ( -872 65535 -65535 ) ctf08 32 48 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf08 32 48 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) ctf08 32 48 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf08 32 48 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf08 32 48 90 1 1 + } + { //brush 692 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 + ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 693 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 + ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 + ( 58200 -65534 30140 ) ( 58200 65534 30140 ) ( -59032 -65534 -28476 ) fstng_2 0 0 0 1 1 + ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 694 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 695 + ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) stnwll05 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 + ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 696 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 697 + ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) mtn 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 62234 20536 65535 ) ( -62109 -20911 65535 ) ( -62109 -20911 -65535 ) mtn 0 0 0 1 1 + } + { //brush 698 + ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 + ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 + } + { //brush 699 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 62234 20536 65535 ) ( -62109 -20911 65535 ) ( -62109 -20911 -65535 ) mtn 0 0 0 1 1 + } + { //brush 700 + ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + } + { //brush 701 + ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) mtn 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + } + { //brush 702 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -64593 11074 65535 ) ( 64693 -10472 65535 ) ( -64593 11074 -65535 ) mtn 0 0 0 1 1 + ( -59013 -28514 65535 ) ( 58219 30101 65535 ) ( -59013 -28514 -65535 ) mtn 0 0 0 1 1 + } + { //brush 703 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) mtn 0 0 180 1 1 + ( -960 -65535 65535 ) ( -960 65535 65535 ) ( -960 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 58219 -30101 65535 ) ( -59013 28514 65535 ) ( -59013 28514 -65535 ) mtn 0 0 0 1 1 + ( 64693 10472 65535 ) ( -64593 -11074 65535 ) ( -64593 -11074 -65535 ) mtn 0 0 0 1 1 + } + { //brush 704 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -960 -65535 65535 ) ( -960 65535 65535 ) ( -960 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + } + { //brush 705 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 + ( 65535 -63424 16508 ) ( 65535 63731 -15280 ) ( -65535 -63424 16508 ) ftlattice2 16 16 0 1 1 + ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 + ( 65535 -63716 -15341 ) ( 65535 63439 16447 ) ( -65535 -63716 -15341 ) ftlattice2 16 16 0 1 1 + } + { //brush 706 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 + ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 0 0 1 1 + ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 0 0 1 1 + ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) ftlattice2 16 0 0 1 1 + ( 65535 -63408 16572 ) ( 65535 63747 -15216 ) ( -65535 -63408 16572 ) ftlattice2 16 0 0 1 1 + } + { //brush 707 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 + ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 + ( 65535 -63439 16447 ) ( 65535 63716 -15341 ) ( -65535 -63439 16447 ) ftlattice2 16 16 0 1 1 + ( 65535 -63731 -15280 ) ( 65535 63424 16508 ) ( -65535 -63731 -15280 ) ftlattice2 16 16 0 1 1 + } + { //brush 708 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 + ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 0 0 1 1 + ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 0 0 1 1 + ( 65535 -63747 -15216 ) ( 65535 63408 16572 ) ( -65535 -63747 -15216 ) ftlattice2 16 0 0 1 1 + ( 65535 -63455 16383 ) ( 65535 63700 -15405 ) ( -65535 -63455 16383 ) ftlattice2 16 0 0 1 1 + } + { //brush 709 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + } + { //brush 710 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 711 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 712 + ( -976 65535 65535 ) ( -976 -65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 713 + ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 + } + { //brush 714 + ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 + ( 65534 16116 63522 ) ( -65534 16116 63522 ) ( -65534 -15672 -63633 ) millgt1 16 0 0 1 0.500000 + } + { //brush 715 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1008 -65535 65535 ) ( -1008 65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 716 + ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + } + { //brush 717 + ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 + } + { //brush 718 + ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 + ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 + } + { //brush 719 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + } + { //brush 720 + ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 + ( -65534 -15352 63713 ) ( 65534 -15352 63713 ) ( -65534 16436 -63442 ) millgt1 0 0 0 1 0.500000 + ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 0 0 0 1 0.500000 + } + { //brush 721 + ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + ( 65534 -15352 63713 ) ( -65534 -15352 63713 ) ( -65534 16436 -63442 ) stnwll02 0 0 0 1 1 + } + { //brush 722 + ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 + } + { //brush 723 + ( -1312 65535 65535 ) ( -1312 -65535 65535 ) ( -1312 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 + } + { //brush 724 + ( -1344 65535 65535 ) ( -1344 -65535 65535 ) ( -1344 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1312 -65535 65535 ) ( -1312 65535 65535 ) ( -1312 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 725 + ( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1344 -65535 65535 ) ( -1344 65535 65535 ) ( -1344 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 + } + { //brush 726 + ( -1408 65535 65535 ) ( -1408 -65535 65535 ) ( -1408 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 + } + { //brush 727 + ( -1440 65535 65535 ) ( -1440 -65535 65535 ) ( -1440 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1408 -65535 65535 ) ( -1408 65535 65535 ) ( -1408 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + } + { //brush 728 + ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1440 -65535 65535 ) ( -1440 65535 65535 ) ( -1440 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 729 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + } + { //brush 730 + ( -1536 65535 65535 ) ( -1536 -65535 65535 ) ( -1536 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 + } + { //brush 731 + ( -1568 65535 65535 ) ( -1568 -65535 65535 ) ( -1568 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1536 -65535 65535 ) ( -1536 65535 65535 ) ( -1536 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 + } + { //brush 732 + ( -1600 65535 65535 ) ( -1600 -65535 65535 ) ( -1600 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1568 -65535 65535 ) ( -1568 65535 65535 ) ( -1568 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 + } + { //brush 733 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 734 + ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 735 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 + ( -65534 -15352 63713 ) ( 65534 -15352 63713 ) ( -65534 16436 -63442 ) millgt1 0 0 0 1 0.500000 + ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 0 0 0 1 0.500000 + } + { //brush 736 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + ( 65534 -15352 63713 ) ( -65534 -15352 63713 ) ( -65534 16436 -63442 ) stnwll02 0 0 0 1 1 + } + { //brush 737 + ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 738 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 416 65535 ) ( 65535 416 65535 ) ( -65535 416 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 739 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 384 65535 ) ( 65535 384 65535 ) ( -65535 384 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 416 65535 ) ( -65535 416 65535 ) ( -65535 416 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + } + { //brush 740 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 352 65535 ) ( 65535 352 65535 ) ( -65535 352 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 384 65535 ) ( -65535 384 65535 ) ( -65535 384 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 + } + { //brush 741 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + } + { //brush 742 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 + ( 58625 65534 -29288 ) ( 58625 -65534 -29288 ) ( -58606 -65534 29327 ) stnfloor02 0 0 0 1 1 + ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 743 + ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 + ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 + ( 28501 59019 65535 ) ( -30114 -58213 65535 ) ( 28501 59019 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 744 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 + ( 28501 59019 65535 ) ( -30114 -58213 65535 ) ( 28501 59019 -65535 ) stnwll05 0 0 0 1 1 + ( -30088 58225 65535 ) ( 28527 -59006 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 745 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -30114 -58213 65535 ) ( 28501 59019 65535 ) ( 28501 59019 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 746 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll05 0 0 90 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 + ( -28937 58807 65535 ) ( 27299 -59585 65535 ) ( -28937 58807 -65535 ) stnwll05 0 0 0 1 1 + ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 747 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 748 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 749 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( 28168 59185 65535 ) ( -30447 -58046 65535 ) ( 28168 59185 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) fstng_2 0 0 0 1 1 + ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 750 + ( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 751 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 + ( 28367 59086 65535 ) ( -30248 -58145 65535 ) ( 28367 59086 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 752 + ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + } + { //brush 753 + ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 754 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) millgt1 16 0 90 1 0.500000 + ( -46700 65535 45980 ) ( -46700 -65535 45980 ) ( 45980 65535 -46700 ) millgt1 16 0 90 1 0.500000 + ( 14746 -65534 63865 ) ( 14746 65534 63865 ) ( -17042 65534 -63291 ) millgt1 16 0 0 1 0.500000 + } + { //brush 755 + ( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 756 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 + ( -30248 58145 65535 ) ( 28367 -59086 65535 ) ( -30248 58145 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 757 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) fstng_2 0 0 0 1 1 + ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 758 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 759 + ( -976 65535 65535 ) ( -976 -65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 760 + ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 + ( -65534 -16116 63522 ) ( 65534 -16116 63522 ) ( -65534 15672 -63633 ) millgt1 16 0 0 1 0.500000 + } + { //brush 761 + ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 + } + { //brush 762 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1008 -65535 65535 ) ( -1008 65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 763 + ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 764 + ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 + ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 45972 46708 ) ( 65535 45972 46708 ) ( -65535 -46708 -45972 ) stnwll05 0 0 0 1 1 + } + { //brush 765 + ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 + ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 + } + { //brush 766 + ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 767 + ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( 28168 -59185 65535 ) ( -30447 58046 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 768 + ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -30447 -58046 65535 ) ( 28168 59185 65535 ) ( 28168 59185 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 769 + ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 770 + ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 + ( 65535 46196 46484 ) ( -65535 46196 46484 ) ( -65535 -46484 -46196 ) millgt1 16 0 0 1 0.500000 + } + { //brush 771 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + } + { //brush 772 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 1 + ( 63389 -65534 16651 ) ( 63389 65534 16651 ) ( -63767 -65534 -15137 ) millgt1 16 0 0 1 1 + ( 65535 -63476 16301 ) ( 65535 63679 -15487 ) ( -65535 -63476 16301 ) millgt1 16 0 0 1 1 + ( 63567 -65534 -15935 ) ( 63567 65534 -15935 ) ( -63588 -65534 15853 ) millgt1 16 0 0 1 1 + ( 65535 -63655 -15585 ) ( 65535 63501 16203 ) ( -65535 -63655 -15585 ) millgt1 16 0 0 1 1 + } + { //brush 773 + ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 + } + { //brush 774 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 + } + { //brush 775 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 + ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 776 + ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 + } + { //brush 777 + ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 778 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 + ( -46980 65535 45700 ) ( -46980 -65535 45700 ) ( 45700 65535 -46980 ) fstng_2 0 0 90 1 1 + } + { //brush 779 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 45284 -65535 47396 ) ( 45284 65535 47396 ) ( -47396 65535 -45284 ) fstng_2 0 0 90 1 1 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 780 + ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 781 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 + ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 782 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 + ( -65534 15231 63743 ) ( 65534 15231 63743 ) ( -65534 -16557 -63412 ) stnwll02 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 + } + { //brush 783 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 + ( 65534 15231 63743 ) ( -65534 15231 63743 ) ( -65534 -16557 -63412 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) millgt1 0 0 0 1 0.500000 + } + { //brush 784 + ( -1680 65535 65535 ) ( -1680 -65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 785 + ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 + ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 786 + ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 + } + { //brush 787 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 788 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 + } + { //brush 789 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 790 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( 27688 -59425 65535 ) ( -30927 57806 65535 ) ( -30927 57806 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 791 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 792 + ( -1888 65535 65535 ) ( -1888 -65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 + } + { //brush 793 + ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 + } + { //brush 794 + ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 + ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 795 + ( -1968 65535 65535 ) ( -1968 -65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + } + { //brush 796 + ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 16 0 0 1 0.500000 + ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 16 0 0 1 0.500000 + ( -65534 -15333 63718 ) ( 65534 -15333 63718 ) ( -65534 16455 -63438 ) millgt1 16 0 0 1 0.500000 + } + { //brush 797 + ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 0 1 1 + ( 65534 -15333 63718 ) ( -65534 -15333 63718 ) ( -65534 16455 -63438 ) stnwll01 0 0 0 1 1 + } + { //brush 798 + ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 0 1 1 + ( 65534 -15333 63718 ) ( -65534 -15333 63718 ) ( -65534 16455 -63438 ) stnwll01 0 0 0 1 1 + ( -65535 46268 46412 ) ( 65535 46268 46412 ) ( -65535 -46412 -46268 ) stnwll01 0 0 0 1 1 + } + { //brush 799 + ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 16 0 0 1 0.500000 + ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 16 0 0 1 0.500000 + } + { //brush 800 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + } + { //brush 801 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + } + { //brush 802 + ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 803 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 804 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 + } + { //brush 805 + ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 806 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( -65534 15887 63580 ) ( 65534 15887 63580 ) ( -65534 -15902 -63576 ) stnwll02 0 0 0 1 1 + } + { //brush 807 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) millgt1 0 0 0 1 0.500000 + ( 65534 15887 63580 ) ( -65534 15887 63580 ) ( -65534 -15902 -63576 ) millgt1 0 0 0 1 0.500000 + } + { //brush 808 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 809 + ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 810 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + } + { //brush 811 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 + } + { //brush 812 + ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 90 1 1 + ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 90 1 1 + ( -47116 65535 45564 ) ( -47116 -65535 45564 ) ( 45564 65535 -47116 ) fstng_2 0 16 90 1 1 + } + { //brush 813 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 + ( -47116 -65535 45564 ) ( -47116 65535 45564 ) ( 45564 65535 -47116 ) fstng_2 0 16 0 1 1 + } + { //brush 814 + ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 + ( -47172 65535 45508 ) ( -47172 -65535 45508 ) ( 45508 65535 -47172 ) millgt1 16 0 90 1 0.500000 + } + { //brush 815 + ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 + } + { //brush 816 + ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 + ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) millgt1 0 0 0 1 0.500000 + } + { //brush 817 + ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 0 1 1 + ( -65534 15231 63743 ) ( 65534 15231 63743 ) ( -65534 -16557 -63412 ) stnwll02 0 0 0 1 1 + } + { //brush 818 + ( -1888 65535 65535 ) ( -1888 -65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 + } + { //brush 819 + ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 + ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 820 + ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 + } + { //brush 821 + ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 + } + { //brush 822 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 + ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) millgt1 0 0 0 1 0.500000 + ( -65534 -15887 63580 ) ( 65534 -15887 63580 ) ( -65534 15902 -63576 ) millgt1 0 0 0 1 0.500000 + } + { //brush 823 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 0 1 1 + ( 65534 -15887 63580 ) ( -65534 -15887 63580 ) ( -65534 15902 -63576 ) stnwll02 0 0 0 1 1 + } + { //brush 824 + ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 + } + { //brush 825 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_2 0 16 90 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 180 1 1 + ( -47244 65535 45436 ) ( -47244 -65535 45436 ) ( 45436 65535 -47244 ) fstng_2 0 16 90 1 1 + } + { //brush 826 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 + ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) fstng_0 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 827 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 0 1 1 + ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 + ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) fstng_2 0 16 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 0 1 1 + } + { //brush 828 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 90 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 180 1 1 + ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 + } + { //brush 829 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 + ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 0 0 1 1 + ( 65535 -63442 16436 ) ( 65535 63713 -15352 ) ( -65535 -63442 16436 ) ftlattice2 16 0 0 1 1 + ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 0 0 1 1 + ( 65535 -63689 -15450 ) ( 65535 63467 16338 ) ( -65535 -63689 -15450 ) ftlattice2 16 0 0 1 1 + } + { //brush 830 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) ftlattice2 16 16 0 1 1 + ( 65535 -63430 16485 ) ( 65535 63726 -15303 ) ( -65535 -63430 16485 ) ftlattice2 16 16 0 1 1 + ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 16 0 1 1 + ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 16 0 1 1 + } + { //brush 831 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 + ( 65535 -63689 -15450 ) ( 65535 63467 16338 ) ( -65535 -63689 -15450 ) ftlattice2 16 0 0 1 1 + ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 0 0 1 1 + ( 65535 -63442 16436 ) ( 65535 63713 -15352 ) ( -65535 -63442 16436 ) ftlattice2 16 0 0 1 1 + ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 0 0 1 1 + } + { //brush 832 + ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 63508 65534 -16173 ) ( 63508 -65534 -16173 ) ( -63647 -65534 15615 ) metdec1 32 0 0 1 1 + ( 65535 -63484 16271 ) ( 65535 63672 -15518 ) ( -65535 -63484 16271 ) metdec1 32 0 0 1 1 + ( 65535 -63646 -15623 ) ( 65535 63510 16165 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 + } + { //brush 833 + ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metdec1 32 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) metdec1 32 0 0 1 1 + ( 65535 63672 -15518 ) ( 65535 -63484 16271 ) ( -65535 -63484 16271 ) metdec1 32 0 0 1 1 + ( 63346 -65534 16820 ) ( 63346 65534 16820 ) ( -63809 -65534 -14968 ) metdec1 32 0 0 1 1 + } + { //brush 834 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) metdec1 32 0 180 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metdec1 32 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 63346 65534 16820 ) ( 63346 -65534 16820 ) ( -63809 -65534 -14968 ) metdec1 32 0 0 1 1 + ( 65535 -63646 -15623 ) ( 65535 63510 16165 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 + } + { //brush 835 + ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) metdec1 32 0 180 1 1 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) metdec1 32 0 180 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) metdec1 32 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65535 63510 16165 ) ( 65535 -63646 -15623 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) metdec1 32 0 0 1 1 + } + { //brush 836 + ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 837 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 838 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 224 65535 ) ( 65535 224 65535 ) ( -65535 224 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + } + { //brush 839 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 192 65535 ) ( 65535 192 65535 ) ( -65535 192 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 224 65535 ) ( -65535 224 65535 ) ( -65535 224 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 + } + { //brush 840 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 192 65535 ) ( -65535 192 65535 ) ( -65535 192 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 + } + { //brush 841 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 + } + { //brush 842 + ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 843 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 844 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 + ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 16 0 0 1 0.500000 + } + { //brush 845 + ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 846 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 847 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 + ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 16 0 1 1 + ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 + ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 16 0 1 1 + } + { //brush 848 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 + ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 + ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 + ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 16 0 1 1 + ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 16 0 1 1 + } + { //brush 849 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_0 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 850 + ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 851 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 + ( -65534 -15920 63571 ) ( 65534 -15920 63571 ) ( -65534 15868 -63584 ) millgt1 16 0 0 1 0.500000 + } + { //brush 852 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 + } + { //brush 853 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 854 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 0 1 1 + ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 + } + { //brush 855 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -2656 -65535 65535 ) ( -2656 65535 65535 ) ( -2656 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 90 1 1 + ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 + } + { //brush 856 + ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 16 0 90 1 0.500000 + ( -18108 65534 63024 ) ( -18108 -65534 63024 ) ( 13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 + ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + } + { //brush 857 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 + ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 + } + { //brush 858 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -368 65535 ) ( 65535 -368 65535 ) ( -65535 -368 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 859 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -400 65535 ) ( 65535 -400 65535 ) ( -65535 -400 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -368 65535 ) ( -65535 -368 65535 ) ( -65535 -368 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 + ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 + } + { //brush 860 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -400 65535 ) ( -65535 -400 65535 ) ( -65535 -400 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 861 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 0 0 1 1 + } + { //brush 862 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 16 0 90 1 0.500000 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 16 0 90 1 0.500000 + ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 + } + { //brush 863 + ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 864 + ( -2560 65535 65535 ) ( -2560 -65535 65535 ) ( -2560 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2528 -65535 65535 ) ( -2528 65535 65535 ) ( -2528 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 + } + { //brush 865 + ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2560 -65535 65535 ) ( -2560 65535 65535 ) ( -2560 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + } + { //brush 866 + ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 + } + { //brush 867 + ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + } + { //brush 868 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -2624 -65535 65535 ) ( -2624 65535 65535 ) ( -2624 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 869 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 + } + { //brush 870 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + } + { //brush 871 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 + ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 0 1 1 + ( 45484 -65535 47196 ) ( 45484 65535 47196 ) ( -47196 65535 -45484 ) fstng_2 0 16 90 1 1 + } + { //brush 872 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 + ( -46484 65535 46196 ) ( -46484 -65535 46196 ) ( 46196 65535 -46484 ) fstng_2 0 16 90 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 + } + { //brush 873 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -46484 65535 46196 ) ( -46484 -65535 46196 ) ( 46196 65535 -46484 ) stnwll01 0 0 0 1 1 + ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 874 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 0 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 0 1 1 + } + { //brush 875 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll05 0 0 0 1 1 + } + { //brush 876 + ( -1240 65535 65535 ) ( -1240 -65535 65535 ) ( -1240 65535 -65535 ) ctf08 0 16 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 16 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 16 180 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) ctf08 0 16 90 1 1 + } + { //brush 877 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 0 1 1 + } + { //brush 878 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnfloor02 0 0 0 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnfloor02 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnfloor02 0 0 0 1 1 + } + { //brush 879 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 -864 65535 ) ( 65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll05 0 0 0 1 1 + } + { //brush 880 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -864 65535 ) ( -65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + ( -30703 57918 65535 ) ( 27912 -59313 65535 ) ( -30703 57918 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 881 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -864 65535 ) ( -65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 882 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1248 65535 ) ( 65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 + ( 28757 58891 65535 ) ( -29858 -58341 65535 ) ( 28757 58891 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 883 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 -1248 65535 ) ( 65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 884 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -1248 65535 ) ( -65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 + } + { //brush 885 + ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll05 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 + } + { //brush 886 + ( -2136 -65535 65535 ) ( -2136 65535 65535 ) ( -2136 65535 -65535 ) ctf08 0 16 0 1 1 + ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 16 180 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) ctf08 0 16 180 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) ctf08 0 16 90 1 1 + } + { //brush 887 + ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 + } + { //brush 888 + ( -2136 -65535 65535 ) ( -2136 65535 65535 ) ( -2136 65535 -65535 ) ctf08 0 16 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) ctf08 0 16 180 1 1 + ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 16 180 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 + ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) ctf08 0 16 90 1 1 + } + { //brush 889 + ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 + } + { //brush 890 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_2 0 16 90 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 + ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) fstng_2 0 16 90 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + } + { //brush 891 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 + ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 + ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 + ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 + ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 + } + { //brush 892 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 + ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) stnwll02 0 0 90 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 893 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 + ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) stnwll02 0 0 90 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 90 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 90 1 1 + } + { //brush 894 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_2 0 16 90 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 + } + { //brush 895 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 896 + ( -1152 65535 65535 ) ( -1152 -65535 65535 ) ( -1152 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 + } + { //brush 897 + ( -1184 65535 65535 ) ( -1184 -65535 65535 ) ( -1184 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -1152 -65535 65535 ) ( -1152 65535 65535 ) ( -1152 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 + } + { //brush 898 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1184 -65535 65535 ) ( -1184 65535 65535 ) ( -1184 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 899 + ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 45524 -65535 47156 ) ( 45524 65535 47156 ) ( -47156 65535 -45524 ) fstng_2 0 16 90 1 1 + } + { //brush 900 + ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 901 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll01 0 0 0 1 1 + ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 902 + ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( 57896 -30748 65535 ) ( -59336 27868 65535 ) ( -59336 27868 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 903 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + } + { //brush 904 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( -16880 -65534 63331 ) ( -16880 65534 63331 ) ( 14908 65534 -63824 ) stnwll01 0 0 0 1 1 + ( 45476 65535 47204 ) ( 45476 -65535 47204 ) ( -47204 65535 -45476 ) stnwll01 0 0 90 1 1 + } + { //brush 905 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 + ( 45476 -65535 47204 ) ( 45476 65535 47204 ) ( -47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 + } + { //brush 906 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 + ( 45476 -65535 47204 ) ( 45476 65535 47204 ) ( -47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 + ( -16880 65534 63331 ) ( -16880 -65534 63331 ) ( 14908 65534 -63824 ) millgt1 0 0 0 1 0.500000 + } + { //brush 907 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 + ( -16880 -65534 63331 ) ( -16880 65534 63331 ) ( 14908 65534 -63824 ) stnwll01 0 0 0 1 1 + } + { //brush 908 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + } + { //brush 909 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_0 0 0 0 1 1 + } + { //brush 910 + ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_0 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 + } + { //brush 911 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) millgt1 16 0 0 1 1 + ( 63387 -65534 16658 ) ( 63387 65534 16658 ) ( -63769 -65534 -15130 ) millgt1 16 0 0 1 1 + ( 65535 -63533 16075 ) ( 65535 63623 -15713 ) ( -65535 -63533 16075 ) millgt1 16 0 0 1 1 + ( 63648 -65534 -15612 ) ( 63648 65534 -15612 ) ( -63507 -65534 16176 ) millgt1 16 0 0 1 1 + ( 65535 -63794 -15028 ) ( 65535 63361 16760 ) ( -65535 -63794 -15028 ) millgt1 16 0 0 1 1 + } + { //brush 912 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 913 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) shootit 16 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 + } + { //brush 914 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 915 + ( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) tile2492 0 0 0 1 1 + ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + ( 65535 58533 -29474 ) ( 65535 -58699 29141 ) ( -65535 -58699 29141 ) tile2492 0 0 0 1 1 + } + { //brush 916 + ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 0 1 1 + ( -1136 -65535 65535 ) ( -1136 65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 917 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 + } + { //brush 918 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 919 + ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) shootit 16 0 180 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) shootit 16 0 0 1 1 + ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 + } + { //brush 920 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 921 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) shootit 16 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 + ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 + } + { //brush 922 + ( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) tile2492 0 0 0 1 1 + ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 + ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 0 1 1 + ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 923 + ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 0 1 1 + ( -1136 -65535 65535 ) ( -1136 65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 + ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 90 1 1 + } + { //brush 924 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 + ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 90 1 1 + ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 + } + { //brush 925 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 28802 58869 65535 ) ( -29813 -58363 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 926 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -30658 57941 65535 ) ( 27957 -59291 65535 ) ( -30658 57941 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 927 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -800 65535 ) ( 65535 -800 65535 ) ( -65535 -800 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 + } + { //brush 928 + ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -800 65535 ) ( 65535 -800 65535 ) ( -65535 -800 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 + } + { //brush 929 + ( -65535 -688 65535 ) ( 65535 -688 65535 ) ( -65535 -688 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 + ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 180 1 1 + ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 930 + ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 + ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 + ( -63497 -16218 65535 ) ( 63659 15570 65535 ) ( -63497 -16218 -65535 ) shootit 0 8 0 1 1 + ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 + ( -63822 14915 65535 ) ( 63333 -16873 65535 ) ( -63822 14915 -65535 ) shootit 0 8 0 1 1 + } + { //brush 931 + ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 + ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 + ( -63853 14795 65535 ) ( 63303 -16993 65535 ) ( -63853 14795 -65535 ) shootit 0 8 0 1 1 + ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 + ( -63527 -16097 65535 ) ( 63629 15691 65535 ) ( -63527 -16097 -65535 ) shootit 0 8 0 1 1 + } + { //brush 932 + ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 + ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 + ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 + ( -63519 -16127 65535 ) ( 63636 15661 65535 ) ( -63519 -16127 -65535 ) shootit 0 8 0 1 1 + ( -63845 14825 65535 ) ( 63310 -16963 65535 ) ( -63845 14825 -65535 ) shootit 0 8 0 1 1 + } + { //brush 933 + ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 + ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 + ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 + ( -63830 14885 65535 ) ( 63326 -16903 65535 ) ( -63830 14885 -65535 ) shootit 0 8 0 1 1 + ( -63504 -16188 65535 ) ( 63651 15600 65535 ) ( -63504 -16188 -65535 ) shootit 0 8 0 1 1 + } + { //brush 934 + ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 + ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 + ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 + ( -63512 -16158 65535 ) ( 63644 15631 65535 ) ( -63512 -16158 -65535 ) shootit 0 8 0 1 1 + ( -63838 14855 65535 ) ( 63318 -16933 65535 ) ( -63838 14855 -65535 ) shootit 0 8 0 1 1 + } + { //brush 935 + ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 + ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) stnfloor02 0 0 180 1 1 + ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) stnfloor02 0 0 180 1 1 + ( 65535 58385 29768 ) ( 65535 -58846 -28847 ) ( -65535 -58846 -28847 ) stnfloor02 0 0 0 1 1 + } + { //brush 936 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 + ( 63313 -65534 16952 ) ( 63313 65534 16952 ) ( -63842 -65534 -14836 ) millgt1 16 16 0 1 1 + ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) millgt1 16 16 0 1 1 + ( 63590 -65534 -15845 ) ( 63590 65534 -15845 ) ( -63566 -65534 15943 ) millgt1 16 16 0 1 1 + ( 65535 -63756 -15183 ) ( 65535 63400 16606 ) ( -65535 -63756 -15183 ) millgt1 16 16 0 1 1 + } + { //brush 937 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 + ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 938 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 + ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 939 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -30703 -57918 65535 ) ( 27912 59313 65535 ) ( 27912 59313 -65535 ) fstng_2 0 0 0 1 1 + ( -31330 57605 65535 ) ( 27285 -59627 65535 ) ( -31330 57605 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 940 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 + ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) fstng_2 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 941 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 + ( 27260 -59640 65535 ) ( -31356 57592 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 942 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 + ( -31381 57579 65535 ) ( 27234 -59653 65535 ) ( -31381 57579 -65535 ) fstng_2 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 943 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) stnwll05 0 0 90 1 1 + ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 + ( 27234 -59653 65535 ) ( -31381 57579 65535 ) ( -31381 57579 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 944 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( -31407 57566 65535 ) ( 27208 -59665 65535 ) ( -31407 57566 -65535 ) fstng_2 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 945 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 + ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 + ( 27208 -59665 65535 ) ( -31407 57566 65535 ) ( -31407 57566 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 946 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) tile2492 0 0 180 1 1 + } + { //brush 947 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65534 15002 63801 ) ( -65534 15002 63801 ) ( -65534 -16786 -63355 ) stonesnw 0 0 0 1 1 + ( -58558 -29423 65535 ) ( 58673 29192 65535 ) ( -58558 -29423 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 948 + ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 0 1 1 + ( 28680 58929 65535 ) ( -29935 -58302 65535 ) ( 28680 58929 -65535 ) stnwll05 0 0 0 1 1 + ( -30780 57880 65535 ) ( 27836 -59352 65535 ) ( -30780 57880 -65535 ) stnwll05 0 0 0 1 1 + ( 58145 65534 30248 ) ( 58145 -65534 30248 ) ( -59086 -65534 -28367 ) stnfloor02 0 0 0 1 1 + } + { //brush 949 + ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 + ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 + ( 28680 58929 65535 ) ( -29935 -58302 65535 ) ( 28680 58929 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 950 + ( -1256 65535 65535 ) ( -1256 -65535 65535 ) ( -1256 65535 -65535 ) ctf02 96 0 0 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) ctf02 96 0 0 1 1 + ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 0 180 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 0 180 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) ctf02 96 0 90 1 1 + ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 + } + { //brush 951 + ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1256 -65535 65535 ) ( -1256 65535 65535 ) ( -1256 65535 -65535 ) stnfloor02 0 0 180 1 1 + ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 61098 23715 ) ( 65535 -61626 -22305 ) ( -65535 -61626 -22305 ) stnfloor02 0 0 0 1 1 + ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 + ( 65535 61366 -23000 ) ( 65535 -61358 23021 ) ( -65535 -61358 23021 ) stnfloor02 0 0 0 1 1 + } + { //brush 952 + ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 + ( -30780 57880 65535 ) ( 27836 -59352 65535 ) ( -30780 57880 -65535 ) stnwll05 0 0 0 1 1 + ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 + } + { //brush 953 + ( -2080 65535 65535 ) ( -2080 -65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -1568 -65535 65535 ) ( -1568 65535 65535 ) ( -1568 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + } + { //brush 954 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 + ( 44964 -65535 47716 ) ( 44964 65535 47716 ) ( -47716 65535 -44964 ) fstng_2 0 16 90 1 1 + } + { //brush 955 + ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + } + { //brush 956 + ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + ( 63406 65534 16579 ) ( 63406 -65534 16579 ) ( -63749 -65534 -15209 ) stonesnw 0 0 0 1 1 + } + { //brush 957 + ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + } + { //brush 958 + ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + ( 63406 65534 16579 ) ( 63406 -65534 16579 ) ( -63749 -65534 -15209 ) stonesnw 0 0 0 1 1 + } + { //brush 959 + ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 + ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 + } + { //brush 960 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1312 65535 ) ( -65535 -1312 65535 ) ( -65535 -1312 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 + } + { //brush 961 + ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1312 65535 ) ( -65535 -1312 65535 ) ( -65535 -1312 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 + ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 + } + { //brush 962 + ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 963 + ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 964 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -1344 65535 ) ( -65535 -1344 65535 ) ( -65535 -1344 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 965 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 + ( 63313 -65534 16952 ) ( 63313 65534 16952 ) ( -63842 -65534 -14836 ) millgt1 16 16 0 1 1 + ( 65535 -63524 16109 ) ( 65535 63631 -15679 ) ( -65535 -63524 16109 ) millgt1 16 16 0 1 1 + ( 63590 -65534 -15845 ) ( 63590 65534 -15845 ) ( -63566 -65534 15943 ) millgt1 16 16 0 1 1 + ( 65535 -63801 -15002 ) ( 65535 63355 16786 ) ( -65535 -63801 -15002 ) millgt1 16 16 0 1 1 + } + { //brush 966 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 28130 59205 65535 ) ( -30485 -58027 65535 ) ( 28130 59205 -65535 ) fstng_2 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 + ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 967 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 90 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 + ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 + ( 28104 59217 65535 ) ( -30511 -58014 65535 ) ( 28104 59217 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 968 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 + ( 28079 59230 65535 ) ( -30536 -58001 65535 ) ( 28079 59230 -65535 ) fstng_2 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 + ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 969 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 28053 59243 65535 ) ( -30562 -57989 65535 ) ( 28053 59243 -65535 ) fstng_2 0 0 0 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 970 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 + ( -30562 -57989 65535 ) ( 28053 59243 65535 ) ( 28053 59243 -65535 ) stnwll05 0 0 0 1 1 + ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 971 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1408 65535 ) ( 65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 972 + ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 + ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 + ( 63139 -17648 65535 ) ( -64016 14140 65535 ) ( -64016 14140 -65535 ) shootit 0 8 0 1 1 + ( 63807 14975 65535 ) ( -63348 -16813 65535 ) ( -63348 -16813 -65535 ) shootit 0 8 0 1 1 + ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 + } + { //brush 973 + ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 + ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 + ( 63815 14945 65535 ) ( -63341 -16843 65535 ) ( -63341 -16843 -65535 ) shootit 0 8 0 1 1 + ( 63147 -17618 65535 ) ( -64009 14170 65535 ) ( -64009 14170 -65535 ) shootit 0 8 0 1 1 + ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 + } + { //brush 974 + ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 + ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 + ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 + ( 63154 -17588 65535 ) ( -64001 14200 65535 ) ( -64001 14200 -65535 ) shootit 0 8 0 1 1 + ( 63822 14915 65535 ) ( -63333 -16873 65535 ) ( -63333 -16873 -65535 ) shootit 0 8 0 1 1 + } + { //brush 975 + ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 + ( 63830 14885 65535 ) ( -63326 -16903 65535 ) ( -63326 -16903 -65535 ) shootit 0 8 0 1 1 + ( 63162 -17558 65535 ) ( -63994 14230 65535 ) ( -63994 14230 -65535 ) shootit 0 8 0 1 1 + ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 + ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 + } + { //brush 976 + ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 + ( 63132 -17679 65535 ) ( -64024 14110 65535 ) ( -64024 14110 -65535 ) shootit 0 8 0 1 1 + ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 + ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 + ( 63800 15006 65535 ) ( -63356 -16783 65535 ) ( -63356 -16783 -65535 ) shootit 0 8 0 1 1 + } + { //brush 977 + ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -1408 65535 ) ( -65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -58808 28924 ) ( 65535 58424 -29692 ) ( -65535 -58808 28924 ) stnwll05 0 0 90 1 1 + } + { //brush 978 + ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -1408 65535 ) ( -65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnfloor02 0 0 0 1 1 + ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnfloor02 0 0 180 1 1 + ( 65535 58424 -29692 ) ( 65535 -58808 28924 ) ( -65535 -58808 28924 ) stnfloor02 0 0 0 1 1 + } + { //brush 979 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1424 65535 ) ( -65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 + ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 180 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 980 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stonesnw 0 0 0 1 1 + ( 57829 -30882 65535 ) ( -59403 27733 65535 ) ( -59403 27733 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 981 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) tile2492 0 0 180 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 982 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 + ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 983 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) tile2492 0 0 0 1 1 + } + { //brush 984 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_2 0 16 90 1 1 + ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 180 1 1 + } + { //brush 985 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 986 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -624 65535 ) ( 65535 -624 65535 ) ( -65535 -624 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 987 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 -624 65535 ) ( 65535 -624 65535 ) ( -65535 -624 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 + ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 + } + { //brush 988 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -816 65535 ) ( 65535 -816 65535 ) ( -65535 -816 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -624 65535 ) ( -65535 -624 65535 ) ( -65535 -624 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 989 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -848 65535 ) ( 65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -816 65535 ) ( -65535 -816 65535 ) ( -65535 -816 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 + } + { //brush 990 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 -848 65535 ) ( 65535 -848 65535 ) ( -65535 -848 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -816 65535 ) ( -65535 -816 65535 ) ( -65535 -816 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 + ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 + } + { //brush 991 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 16 0 1 1 + ( 65535 -63517 16139 ) ( 65535 63639 -15649 ) ( -65535 -63517 16139 ) millgt1 0 16 0 1 1 + ( 63305 -65534 16986 ) ( 63305 65534 16986 ) ( -63851 -65534 -14802 ) millgt1 0 16 0 1 1 + ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) millgt1 0 16 0 1 1 + ( 63551 -65534 -15999 ) ( 63551 65534 -15999 ) ( -63604 -65534 15789 ) millgt1 0 16 0 1 1 + } + { //brush 992 + ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( 57649 -31240 65535 ) ( -59582 27375 65535 ) ( -59582 27375 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 993 + ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( -58737 -29064 65535 ) ( 58494 29551 65535 ) ( -58737 -29064 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 994 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 -1296 65535 ) ( 65535 -1296 65535 ) ( -65535 -1296 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 -1264 65535 ) ( -65535 -1264 65535 ) ( -65535 -1264 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 + ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + ( -18108 65534 63024 ) ( -18108 -65534 63024 ) ( 13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 + } + { //brush 995 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1296 65535 ) ( 65535 -1296 65535 ) ( -65535 -1296 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -1264 65535 ) ( -65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 + ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 996 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1296 65535 ) ( -65535 -1296 65535 ) ( -65535 -1296 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 997 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_2 0 16 0 1 1 + } + { //brush 998 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 + } + { //brush 999 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) *rtex345 0 0 0 1 1 + ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) *rtex345 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) *rtex345 0 0 0 1 1 + } + { //brush 1000 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 + ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 + } + { //brush 1001 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) *rtex345 0 0 0 1 1 + } + { //brush 1002 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1003 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1004 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 0 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) tile2492 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + } + { //brush 1005 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1006 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 + } + { //brush 1007 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 -60809 -24435 ) ( 65535 60886 24242 ) ( -65535 -60809 -24435 ) *rtex345 0 0 0 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 + } + { //brush 1008 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 180 1 1 + ( 65535 60886 24242 ) ( 65535 -60809 -24435 ) ( -65535 -60809 -24435 ) stonesnow 0 0 0 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 180 1 1 + } + { //brush 1009 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1010 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + } + { //brush 1011 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1012 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 + } + { //brush 1013 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + } + { //brush 1014 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 180 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + } + { //brush 1015 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 + } + { //brush 1016 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1017 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 + ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 + } + { //brush 1018 + ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) fstng_0 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + } + { //brush 1019 + ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + } + { //brush 1020 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 90 1 1 + ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) stonesnow 0 0 90 1 1 + ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 + } + { //brush 1021 + ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 + ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 + } + { //brush 1022 + ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) fstng_0 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + } + { //brush 1023 + ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 104 -65535 65535 ) ( 104 65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + } + { //brush 1024 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 90 1 1 + ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) stonesnow 0 0 90 1 1 + ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 + } + { //brush 1025 + ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) *rtex345 0 0 0 1 1 + ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 + ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 + } + { //brush 1026 + ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 28 ) ( 65535 65535 28 ) ( -65535 -65535 28 ) fstng_0 0 0 0 1 1 + ( 65535 65535 32 ) ( 65535 -65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 0 1 1 + } + { //brush 1027 + ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) stonesnow 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 90 1 1 + ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) stonesnow 0 0 90 1 1 + ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 + } + { //brush 1028 + ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) *rtex345 0 0 0 1 1 + ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 + } + { //brush 1029 + ( -96 65535 65535 ) ( -96 -65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 96 -65535 65535 ) ( 96 65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + } + { //brush 1030 + ( -96 65535 65535 ) ( -96 -65535 65535 ) ( -96 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 96 -65535 65535 ) ( 96 65535 65535 ) ( 96 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 + ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 + } + { //brush 1031 + ( -104 65535 65535 ) ( -104 -65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + } + { //brush 1032 + ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + } + { //brush 1033 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) fstng_0 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + } + { //brush 1034 + ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 + ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 + } + { //brush 1035 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 90 1 1 + ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) stonesnow 0 0 90 1 1 + ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 + } + { //brush 1036 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) fstng_0 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + } + { //brush 1037 + ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) *rtex345 0 0 0 1 1 + ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 + ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 + } + { //brush 1038 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 90 1 1 + ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) stonesnow 0 0 90 1 1 + ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 + } + { //brush 1039 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 28 ) ( 65535 65535 28 ) ( -65535 -65535 28 ) fstng_0 0 0 0 1 1 + ( 65535 65535 32 ) ( 65535 -65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 0 1 1 + } + { //brush 1040 + ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) *rtex345 0 0 0 1 1 + ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 + } + { //brush 1041 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 90 1 1 + ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) stonesnow 0 0 90 1 1 + ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 + } + { //brush 1042 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1043 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 + } + { //brush 1044 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + } + { //brush 1045 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + } + { //brush 1046 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 + } + { //brush 1047 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1048 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 180 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + } + { //brush 1049 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 + } + { //brush 1050 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 + ( 65535 -60886 24242 ) ( 65535 60809 -24435 ) ( -65535 -60886 24242 ) *rtex345 0 0 0 1 1 + } + { //brush 1051 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + ( 65535 60809 -24435 ) ( 65535 -60886 24242 ) ( -65535 -60886 24242 ) stonesnow 0 0 0 1 1 + ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 180 1 1 + ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 180 1 1 + } + { //brush 1052 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 + ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 + } + { //brush 1053 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) tile2492 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + } + { //brush 1054 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) *rtex345 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) *rtex345 0 0 0 1 1 + } + { //brush 1055 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 + } + { //brush 1056 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 + ( 65534 15002 63801 ) ( -65534 15002 63801 ) ( -65534 -16786 -63355 ) *rtex345 0 0 0 1 1 + ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) *rtex345 0 0 0 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) *rtex345 0 0 0 1 1 + } + { //brush 1057 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 + ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 + } + { //brush 1058 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 58392 65534 -29756 ) ( 58392 -65534 -29756 ) ( -58840 -65534 28860 ) stonesnow 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1059 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 + ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1060 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 90 1 1 + ( 44652 -65535 48028 ) ( 44652 65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_2 0 16 90 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 180 1 1 + } + { //brush 1061 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 + ( 57573 -31394 65535 ) ( -59659 27221 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1062 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 + ( 65534 -17219 63246 ) ( -65534 -17219 63246 ) ( -65534 14569 -63909 ) stnwll02 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 0 1 1 + } + { //brush 1063 + ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) millgt1 0 0 0 1 0.500000 + ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) millgt1 0 0 0 1 0.500000 + } + { //brush 1064 + ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + } + { //brush 1065 + ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) millgt1 0 0 0 1 0.500000 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) millgt1 0 0 0 1 0.500000 + ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) millgt1 0 0 0 1 0.500000 + ( -65534 -17219 63246 ) ( 65534 -17219 63246 ) ( -65534 14569 -63909 ) millgt1 0 0 0 1 0.500000 + } + { //brush 1066 + ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 + ( 65534 -17219 63246 ) ( -65534 -17219 63246 ) ( -65534 14569 -63909 ) stnwll02 0 0 0 1 1 + } + { //brush 1067 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + } + { //brush 1068 + ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 + } + { //brush 1069 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 0 0 180 1 0.500000 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) millgt1 0 0 0 1 0.500000 + ( -65535 -45276 47404 ) ( 65535 -45276 47404 ) ( -65535 47404 -45276 ) millgt1 0 0 0 1 0.500000 + ( -65535 46812 45868 ) ( 65535 46812 45868 ) ( 65535 -45868 -46812 ) millgt1 0 0 0 1 0.500000 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) millgt1 0 0 0 1 0.500000 + } + { //brush 1070 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2720 -65535 65535 ) ( 2720 65535 65535 ) ( 2720 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 + ( 61587 -65535 22411 ) ( 61587 65535 22411 ) ( -61137 -65535 -23610 ) stnwll02 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 1071 + ( 2516 65535 65535 ) ( 2516 -65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1072 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 + } + { //brush 1073 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 1074 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 1075 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2508 -65535 65535 ) ( 2508 65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( 58731 29077 65535 ) ( -58501 -29538 65535 ) ( -58501 -29538 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1076 + ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + } + { //brush 1077 + ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_0 0 0 0 1 1 + } + { //brush 1078 + ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 + } + { //brush 1079 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 180 1 1 + ( -64 -65535 65535 ) ( -64 65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 1080 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 200 ) ( 65535 65535 200 ) ( -65535 -65535 200 ) stnwll05 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 0 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 1081 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + } + { //brush 1082 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnow 0 0 0 1 1 + } + { //brush 1083 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) millgt1 16 0 0 1 0.500000 + ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) millgt1 16 0 0 1 0.500000 + ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) millgt1 16 0 0 1 0.500000 + } + { //brush 1084 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 + ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) skull1 32 0 0 0.500000 0.500000 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) skull1 32 0 0 0.500000 0.500000 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) skull1 32 0 0 0.500000 0.500000 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) skull1 32 0 0 0.500000 0.500000 + } + { //brush 1085 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + } + { //brush 1086 + ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + } + { //brush 1087 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1088 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1089 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) ctf07 0 48 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll05 0 0 90 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 + } + { //brush 1090 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 + } + { //brush 1091 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + } + { //brush 1092 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 + } + { //brush 1093 + ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + } + { //brush 1094 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) ctf07 32 48 180 1 1 + ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) ctf07 32 48 180 1 1 + ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) ctf07 32 48 0 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf07 32 48 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf07 32 48 0 1 1 + ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) ctf07 32 48 0 1 1 + } + { //brush 1095 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1096 + ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1097 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 + ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1098 + ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 + ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1099 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) ctf07 0 48 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 48 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 48 180 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf07 0 48 90 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf07 0 48 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf07 0 48 0 1 1 + } + { //brush 1100 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 + } + { //brush 1101 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 + } + { //brush 1102 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 + } + { //brush 1103 + ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 + } + { //brush 1104 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 + ( 65535 -35414 55153 ) ( -65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 180 1 1 + } + { //brush 1105 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) ctf07 32 16 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 0 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 + } + { //brush 1106 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 + } + { //brush 1107 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 0 1 1 + } + { //brush 1108 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 + } + { //brush 1109 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + } + { //brush 1110 + ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) ctf07 48 32 180 1 1 + ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) ctf07 48 32 180 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) ctf07 48 32 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) ctf07 48 32 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 48 32 0 1 1 + ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 48 32 0 1 1 + } + { //brush 1111 + ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 + } + { //brush 1112 + ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2064 -65535 65535 ) ( 2064 65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + } + { //brush 1113 + ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + } + { //brush 1114 + ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + } + { //brush 1115 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( 65535 -46212 46468 ) ( -65535 -46212 46468 ) ( 65535 46468 -46212 ) stnwll02 0 0 0 1 1 + ( -65535 -46228 46452 ) ( 65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 + } + { //brush 1116 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 + ( -65535 -46212 46468 ) ( 65535 -46212 46468 ) ( 65535 46468 -46212 ) fstng_2 0 0 0 1 1 + } + { //brush 1117 + ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( -65535 -46228 46452 ) ( 65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 1118 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( 65535 -46228 46452 ) ( -65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 + } + { //brush 1119 + ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 1120 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( 62344 65535 -20205 ) ( 62344 -65535 -20205 ) ( -61999 -65535 21242 ) stonesnw 0 0 0 1 1 + } + { //brush 1121 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 1122 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 16 65535 ) ( 65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 0 1 1 + } + { //brush 1123 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) ctf01 64 32 180 1 1 + ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) ctf01 64 32 90 1 1 + ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) ctf01 64 32 90 1 1 + } + { //brush 1124 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 + ( -14746 -65534 63865 ) ( -14746 65534 63865 ) ( 17042 65534 -63291 ) stnwll05 0 0 0 1 1 + } + { //brush 1125 + ( 912 65535 65535 ) ( 912 -65535 65535 ) ( 912 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 62344 65535 -20205 ) ( 62344 -65535 -20205 ) ( -61999 -65535 21242 ) stonesnw 0 0 0 1 1 + } + { //brush 1126 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 + } + { //brush 1127 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + } + { //brush 1128 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + } + { //brush 1129 + ( 320 -65535 65535 ) ( 320 65535 65535 ) ( 320 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) stonesnw 0 0 180 1 1 + } + { //brush 1130 + ( 320 65535 65535 ) ( 320 -65535 65535 ) ( 320 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 1131 + ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 + } + { //brush 1132 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1133 + ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) ctf07 0 32 0 1 1 + ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) ctf07 0 32 180 1 1 + ( 65535 -640 65535 ) ( -65535 -640 65535 ) ( -65535 -640 -65535 ) ctf07 0 32 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 0 32 90 1 1 + ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 0 32 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) ctf07 0 32 90 1 1 + } + { //brush 1134 + ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -640 65535 ) ( -65535 -640 65535 ) ( -65535 -640 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 90 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 1135 + ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -640 65535 ) ( 65535 -640 65535 ) ( -65535 -640 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 1136 + ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 1137 + ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -704 65535 ) ( -65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 1138 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 + ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1139 + ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1056 -65535 65535 ) ( 1056 65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) ctf07 32 0 0 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 + ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 + } + { //brush 1140 + ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1056 -65535 65535 ) ( 1056 65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 576 ) ( 65535 65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1141 + ( 1056 65535 65535 ) ( 1056 -65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 + ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1142 + ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 + ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 + } + { //brush 1143 + ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 + } + { //brush 1144 + ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) ctf07 48 32 180 1 1 + ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) ctf07 48 32 180 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) ctf07 48 32 0 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) ctf07 48 32 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 48 32 0 1 1 + ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 48 32 0 1 1 + } + { //brush 1145 + ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 + } + { //brush 1146 + ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + } + { //brush 1147 + ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 + } + { //brush 1148 + ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 2064 -65535 65535 ) ( 2064 65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 + } + { //brush 1149 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 1150 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) ctf08 0 48 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) ctf08 0 48 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 48 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 48 180 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf08 0 48 90 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf08 0 48 90 1 1 + } + { //brush 1151 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + } + { //brush 1152 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + } + { //brush 1153 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 + } + { //brush 1154 + ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + } + { //brush 1155 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) ctf08 16 32 180 1 1 + ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) ctf08 16 32 180 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) ctf08 16 32 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) ctf08 16 32 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 16 32 0 1 1 + ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 16 32 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) ctf08 16 32 0 1 1 + } + { //brush 1156 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 + } + { //brush 1157 + ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 + } + { //brush 1158 + ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + } + { //brush 1159 + ( -2064 65535 65535 ) ( -2064 -65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 + } + { //brush 1160 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 576 ) ( 65535 65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 + } + { //brush 1161 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll01 0 0 90 1 1 + ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 + } + { //brush 1162 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll01 0 0 90 1 1 + ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1163 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 1164 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 640 65535 ) ( -65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 + } + { //brush 1165 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 704 65535 ) ( 65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 1166 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1167 + ( -912 65535 65535 ) ( -912 -65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( -58741 29058 65535 ) ( 58491 -29557 65535 ) ( -58741 29058 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 1168 + ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -58741 29058 65535 ) ( 58491 -29557 65535 ) ( -58741 29058 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1169 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 + ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) ctf02 64 32 180 1 1 + ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) ctf02 64 32 90 1 1 + ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) ctf02 64 32 90 1 1 + } + { //brush 1170 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 + ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 + ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 + ( 14746 65534 63865 ) ( 14746 -65534 63865 ) ( -17042 65534 -63291 ) stnwll05 0 0 0 1 1 + } + { //brush 1171 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -16 65535 ) ( -65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 0 1 1 + } + { //brush 1172 + ( -912 -65535 65535 ) ( -912 65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 61999 65535 21242 ) ( 61999 -65535 21242 ) ( -62344 -65535 -20205 ) stonesnw 0 0 0 1 1 + } + { //brush 1173 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) ctf08 16 32 180 1 1 + ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) ctf08 16 32 180 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) ctf08 16 32 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) ctf08 16 32 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 16 32 0 1 1 + ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 16 32 0 1 1 + } + { //brush 1174 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 0 1 1 + } + { //brush 1175 + ( -2064 65535 65535 ) ( -2064 -65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + } + { //brush 1176 + ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 + } + { //brush 1177 + ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + } + { //brush 1178 + ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) ctf08 32 16 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) ctf08 32 16 0 1 1 + ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) ctf08 32 16 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) ctf08 32 16 180 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) ctf08 32 16 90 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf08 32 16 90 1 1 + } + { //brush 1179 + ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 + } + { //brush 1180 + ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 + } + { //brush 1181 + ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 + } + { //brush 1182 + ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 + } + { //brush 1183 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 + ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) skull1 32 0 0 0.500000 0.500000 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) skull1 32 0 0 0.500000 0.500000 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) skull1 32 0 0 0.500000 0.500000 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) skull1 32 0 0 0.500000 0.500000 + } + { //brush 1184 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 0 1 1 + ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1185 + ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1186 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1187 + ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1188 + ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) stnwll02 0 0 0 1 1 + ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1189 + ( -2720 65535 65535 ) ( -2720 -65535 65535 ) ( -2720 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( 61137 -65535 -23610 ) ( 61137 65535 -23610 ) ( -61587 -65535 22411 ) stnwll02 0 0 0 1 1 + } + { //brush 1190 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stonesnw 0 0 0 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 1191 + ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) ctf08 32 48 0 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 + ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1192 + ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 + ( -46508 -65535 46172 ) ( -46508 65535 46172 ) ( 46172 65535 -46508 ) stnwll02 0 0 0 1 1 + ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) stnwll02 0 0 0 1 1 + } + { //brush 1193 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -992 -65535 65535 ) ( -992 65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1194 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 + ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1195 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) ctf08 0 48 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 48 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 48 180 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf08 0 48 90 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf08 0 48 90 1 1 + } + { //brush 1196 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 + } + { //brush 1197 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + } + { //brush 1198 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 + } + { //brush 1199 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 + } + { //brush 1200 + ( -1072 65535 65535 ) ( -1072 -65535 65535 ) ( -1072 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -1040 -65535 65535 ) ( -1040 65535 65535 ) ( -1040 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 + ( -46188 -46492 65535 ) ( 46492 46188 65535 ) ( 46492 46188 -65535 ) stnwll01 0 0 180 1 1 + } + { //brush 1201 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 + ( -59323 27893 65535 ) ( 57909 -30722 65535 ) ( -59323 27893 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_0 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1202 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 + ( 57909 -30722 65535 ) ( -59323 27893 65535 ) ( -59323 27893 -65535 ) fstng_0 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 + ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_0 0 0 0 1 1 + } + { //brush 1203 + ( -2508 65535 65535 ) ( -2508 -65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( -58731 -29077 65535 ) ( 58501 29538 65535 ) ( -58731 -29077 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1204 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) ctf08 0 32 0 1 1 + ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) ctf08 0 32 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 32 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 32 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) ctf08 0 32 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) ctf08 0 32 90 1 1 + } + { //brush 1205 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 + } + { //brush 1206 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 + } + { //brush 1207 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 + } + { //brush 1208 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 + } + { //brush 1209 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2516 -65535 65535 ) ( -2516 65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1210 + ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 + } + { //brush 1211 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 1216 -65535 65535 ) ( 1216 65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 + } + { //brush 1212 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 + } + { //brush 1213 + ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1214 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + } + { //brush 1215 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + } + { //brush 1216 + ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) ctf07 0 32 0 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) ctf07 0 32 0 1 1 + ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 32 180 1 1 + ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 32 180 1 1 + ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) ctf07 0 32 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) ctf07 0 32 90 1 1 + } + { //brush 1217 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 + } + { //brush 1218 + ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1219 + ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + } + { //brush 1220 + ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + } + { //brush 1221 + ( 1040 65535 65535 ) ( 1040 -65535 65535 ) ( 1040 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1216 -65535 65535 ) ( 1216 65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 + ( 46188 46492 65535 ) ( -46492 -46188 65535 ) ( 46188 46492 -65535 ) stnwll01 0 0 180 1 1 + } + { //brush 1222 + ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf01 64 80 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) ctf01 64 80 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf01 64 80 0 1 1 + ( 60996 69391 7356 ) ( 60996 -57765 39146 ) ( -61258 57929 -38488 ) ctf01 64 80 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) ctf01 64 80 0 1 1 + ( 61258 -69226 -6699 ) ( 61258 57929 -38488 ) ( -60996 -57765 39146 ) ctf01 64 80 0 1 1 + } + { //brush 1223 + ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf01 64 80 180 1 1 + ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf01 64 80 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) ctf01 64 80 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf01 64 80 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) ctf01 64 80 0 1 1 + ( 60996 -57765 39146 ) ( 60996 69391 7356 ) ( -61258 57929 -38488 ) ctf01 64 80 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) ctf01 64 80 0 1 1 + } + { //brush 1224 + ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) stnwll02 0 0 0 1 1 + ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 + } + { //brush 1225 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) stnwll02 0 0 0 1 1 + ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 + } + { //brush 1226 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 + ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 180 1 1 + } + { //brush 1227 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) tile2492 0 0 180 1 1 + ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 61458 22754 ) ( 65535 -61266 -23266 ) ( -65535 61458 22754 ) tile2492 0 0 90 1 1 + ( 65535 61526 -22572 ) ( 65535 -61197 23449 ) ( -65535 -61197 23449 ) tile2492 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + } + { //brush 1228 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) ctf01 32 80 0 1 1 + ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 80 180 1 1 + ( 65535 61526 -22572 ) ( 65535 -61197 23449 ) ( -65535 -61197 23449 ) ctf01 32 80 90 1 1 + ( 65535 -61266 -23266 ) ( 65535 61458 22754 ) ( -65535 61458 22754 ) ctf01 32 80 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf01 32 80 0 1 1 + } + { //brush 1229 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + } + { //brush 1230 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 61421 65535 22853 ) ( 61421 -65535 22853 ) ( -61303 65535 -23168 ) stnwll02 0 0 0 1 1 + ( 61721 65535 -22053 ) ( 61721 -65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 + } + { //brush 1231 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) ctf01 32 48 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 61421 -65535 22853 ) ( 61421 65535 22853 ) ( -61303 65535 -23168 ) stnwll02 0 0 0 1 1 + ( 61721 65535 -22053 ) ( 61721 -65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 + } + { //brush 1232 + ( 1408 65535 65535 ) ( 1408 -65535 65535 ) ( 1408 65535 -65535 ) stonesnw2 0 0 180 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stonesnw2 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw2 0 0 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw2 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw2 0 0 180 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw2 0 0 180 1 1 + } + { //brush 1233 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 1408 -65535 65535 ) ( 1408 65535 65535 ) ( 1408 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + } + { //brush 1234 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 80 180 1 1 + ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 + ( 65535 -61458 22754 ) ( 65535 61266 -23266 ) ( -65535 -61458 22754 ) ctf02 96 80 90 1 1 + } + { //brush 1235 + ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + } + { //brush 1236 + ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 + ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1237 + ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) ctf08 0 32 0 1 1 + ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) ctf08 0 32 180 1 1 + ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) ctf08 0 32 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 0 32 90 1 1 + ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 0 32 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) ctf08 0 32 90 1 1 + } + { //brush 1238 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + } + { //brush 1239 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 61303 65535 -23168 ) ( 61303 -65535 -23168 ) ( -61421 65535 22853 ) fstng_0 0 0 0 1 1 + ( 61003 65535 23968 ) ( 61003 -65535 23968 ) ( -61721 -65535 -22053 ) fstng_0 0 0 0 1 1 + } + { //brush 1240 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) ctf02 96 48 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 96 48 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) ctf02 96 48 0 1 1 + ( 61303 -65535 -23168 ) ( 61303 65535 -23168 ) ( -61421 65535 22853 ) ctf02 96 48 0 1 1 + ( 61003 65535 23968 ) ( 61003 -65535 23968 ) ( -61721 -65535 -22053 ) ctf02 96 48 0 1 1 + } + { //brush 1241 + ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 + ( 72321 -20359 54282 ) ( -20359 72321 54282 ) ( 18812 -73868 -52735 ) stnwll02 0 0 0 1 1 + ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) stnwll02 0 0 0 1 1 + } + { //brush 1242 + ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + } + { //brush 1243 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 + } + { //brush 1244 + ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1245 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + } + { //brush 1246 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 + } + { //brush 1247 + ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1248 + ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 + } + { //brush 1249 + ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 288 ) ( 65535 65535 288 ) ( -65535 -65535 288 ) stnwll02 0 0 90 1 1 + ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 + ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 + } + { //brush 1250 + ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) ctf02 64 80 0 1 1 + ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) ctf02 64 80 0 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf02 64 80 180 1 1 + ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) ctf02 64 80 90 1 1 + ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) ctf02 64 80 90 1 1 + } + { //brush 1251 + ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + } + { //brush 1252 + ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 90 1 1 + ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 + } + { //brush 1253 + ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 0 1 1 + ( 61587 65535 22411 ) ( 61587 -65535 22411 ) ( -61137 -65535 -23610 ) stnwll02 0 0 0 1 1 + ( 61823 65535 -21779 ) ( 61823 -65535 -21779 ) ( -60900 -65535 24241 ) stnwll02 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1254 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 + } + { //brush 1255 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 + } + { //brush 1256 + ( -280 65535 65535 ) ( -280 -65535 65535 ) ( -280 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 + } + { //brush 1257 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) tile2492 0 0 90 1 1 + ( 65535 61197 23449 ) ( 65535 -61526 -22572 ) ( -65535 -61526 -22572 ) tile2492 0 0 90 1 1 + ( 65535 61266 -23266 ) ( 65535 -61458 22754 ) ( -65535 -61458 22754 ) tile2492 0 0 90 1 1 + } + { //brush 1258 + ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf02 64 80 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf02 64 80 0 1 1 + ( 61258 69226 -6699 ) ( 61258 -57929 -38488 ) ( -60996 57765 39146 ) ctf02 64 80 0 1 1 + ( 60996 -69391 7356 ) ( 60996 57765 39146 ) ( -61258 69226 -6699 ) ctf02 64 80 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) ctf02 64 80 0 1 1 + } + { //brush 1259 + ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf02 64 80 180 1 1 + ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf02 64 80 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) ctf02 64 80 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf02 64 80 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) ctf02 64 80 0 1 1 + ( 61258 -57929 -38488 ) ( 61258 69226 -6699 ) ( -60996 57765 39146 ) ctf02 64 80 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) ctf02 64 80 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) ctf02 64 80 0 1 1 + } + { //brush 1260 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) millgt1 16 0 0 1 0.500000 + ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) millgt1 16 0 0 1 0.500000 + ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) millgt1 16 0 0 1 0.500000 + } + { //brush 1261 + ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 0 1 1 + ( 60900 65535 24241 ) ( 60900 -65535 24241 ) ( -61823 -65535 -21779 ) stnwll02 0 0 0 1 1 + ( 61137 65535 -23610 ) ( 61137 -65535 -23610 ) ( -61587 -65535 22411 ) stnwll02 0 0 0 1 1 + } + { //brush 1262 + ( -1408 65535 65535 ) ( -1408 -65535 65535 ) ( -1408 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + } + { //brush 1263 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 + } + { //brush 1264 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 + } + { //brush 1265 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 + } + { //brush 1266 + ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) ctf02 64 80 0 1 1 + ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) ctf02 64 80 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf02 64 80 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf02 64 80 180 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf02 64 80 90 1 1 + ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) ctf02 64 80 90 1 1 + } + { //brush 1267 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 + } + { //brush 1268 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1269 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 + } + { //brush 1270 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 + ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 + } + { //brush 1271 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 + ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 + } + { //brush 1272 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 + } + { //brush 1273 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1274 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 + } + { //brush 1275 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 + ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 + } + { //brush 1276 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 + ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 + } + { //brush 1277 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 + } + { //brush 1278 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1279 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 + } + { //brush 1280 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 + ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 + } + { //brush 1281 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 + ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 + } + { //brush 1282 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 + } + { //brush 1283 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1284 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 + } + { //brush 1285 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 + ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 + } + { //brush 1286 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 + ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 + } + { //brush 1287 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 + } + { //brush 1288 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 + ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 + } + { //brush 1289 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 + ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 + } + { //brush 1290 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 + } + { //brush 1291 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 + ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 + } + { //brush 1292 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 + ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 + } + { //brush 1293 + ( -320 65535 65535 ) ( -320 -65535 65535 ) ( -320 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) stonesnw 0 0 180 1 1 + } + { //brush 1294 + ( -1056 65535 65535 ) ( -1056 -65535 65535 ) ( -1056 65535 -65535 ) ctf08 32 0 180 1 1 + ( -992 -65535 65535 ) ( -992 65535 65535 ) ( -992 65535 -65535 ) ctf08 32 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) ctf08 32 0 0 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) ctf08 32 0 0 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) ctf08 32 0 0 1 1 + ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) ctf08 32 0 0 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) ctf08 32 0 0 1 1 + } + { //brush 1295 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 + } + { //brush 1296 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 + ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 + } + { //brush 1297 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 + ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 + } + { //brush 1298 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 + } + { //brush 1299 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 + ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 + } + { //brush 1300 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 + ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 + } + { //brush 1301 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 + ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 768 ) ( 65535 65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 + } + { //brush 1302 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 + ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 + ( 59013 28514 65535 ) ( -58219 -30101 65535 ) ( -58219 -30101 -65535 ) sky003 0 0 0 1 1 + } + { //brush 1303 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll05 0 0 0 1 1 + } + { //brush 1304 + ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 + ( 29813 58363 65535 ) ( -28802 -58869 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 1305 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 1306 + ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) tile2492 0 0 180 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 1307 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -57896 30748 65535 ) ( 59336 -27868 65535 ) ( -57896 30748 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1308 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( -58952 -28636 65535 ) ( 58280 29980 65535 ) ( -58952 -28636 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1309 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 + } + { //brush 1310 + ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 1311 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 + ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 1312 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 + } + { //brush 1313 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnow 0 0 0 1 1 + } + { //brush 1314 + ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 + ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 1315 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 + } + { //brush 1316 + ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 90 1 1 + ( 47244 -65535 45436 ) ( 47244 65535 45436 ) ( -45436 65535 -47244 ) fstng_2 0 16 90 1 1 + } + { //brush 1317 + ( 2560 65535 65535 ) ( 2560 -65535 65535 ) ( 2560 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 + } + { //brush 1318 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65535 63484 16271 ) ( 65535 -63672 -15518 ) ( -65535 -63672 -15518 ) metdec1 32 0 0 1 1 + ( 63809 -65534 -14968 ) ( 63809 65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 + ( 63647 -65534 15615 ) ( 63647 65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 + } + { //brush 1319 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) metdec1 32 0 0 1 1 + ( 65535 63646 -15623 ) ( 65535 -63510 16165 ) ( -65535 -63510 16165 ) metdec1 32 0 0 1 1 + ( 63647 -65534 15615 ) ( 63647 65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 + ( 63809 -65534 -14968 ) ( 63809 65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 + } + { //brush 1320 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( 2528 -65535 65535 ) ( 2528 65535 65535 ) ( 2528 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 + } + { //brush 1321 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 + ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 + ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 + ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 1322 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 + ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 + ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 + } + { //brush 1323 + ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) tile2492 0 0 180 1 1 + ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 1324 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 1325 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 16 180 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 0 1 1 + ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) fstng_2 0 16 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) fstng_2 0 16 180 1 1 + } + { //brush 1326 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 58533 29474 65535 ) ( -58699 -29141 65535 ) ( -58699 -29141 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 1327 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 + ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 + ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 1328 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 + ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 + } + { //brush 1329 + ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 + ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 1330 + ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( -27688 59425 65535 ) ( 30927 -57806 65535 ) ( -27688 59425 -65535 ) stnwll01 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll01 0 0 180 1 1 + } + { //brush 1331 + ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 64593 -11074 65535 ) ( -64693 10472 65535 ) ( -64693 10472 -65535 ) mtn 0 0 0 1 1 + ( 59013 28514 65535 ) ( -58219 -30101 65535 ) ( -58219 -30101 -65535 ) mtn 0 0 0 1 1 + } + { //brush 1332 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 30447 -58046 65535 ) ( -28168 59185 65535 ) ( -28168 59185 -65535 ) fstng_0 0 0 180 1 1 + ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) fstng_0 0 0 180 1 1 + } + { //brush 1333 + ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 1334 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 + ( -28367 -59086 65535 ) ( 30248 58145 65535 ) ( 30248 58145 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 1335 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 + ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 + } + { //brush 1336 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1337 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 + ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) fstng_0 0 0 0 1 1 + ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 + } + { //brush 1338 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( -58437 -29666 65535 ) ( 58795 28949 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 + ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 + } + { //brush 1339 + ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 + ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 + ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 + ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 + ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 + ( 65534 -29461 58539 ) ( -65534 -29461 58539 ) ( -65534 29154 -58693 ) mtn 0 0 0 1 1 + } + { //brush 1340 + ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 + ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 180 1 1 + } + { //brush 1341 + ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 180 1 1 + } + { //brush 1342 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 + ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 + ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 + ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 + ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 + ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 + } + { //brush 1343 + ( 1712 65535 65535 ) ( 1712 -65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 1344 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 + } + { //brush 1345 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 90 1 1 + } + { //brush 1346 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 + ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 + ( 65535 -63564 15951 ) ( 65535 63592 -15838 ) ( -65535 -63564 15951 ) shootit 16 16 0 1 1 + ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 + ( 65535 -63660 -15567 ) ( 65535 63496 16222 ) ( -65535 -63660 -15567 ) shootit 16 16 0 1 1 + } + { //brush 1347 + ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 + ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 + ( 63536 -20069 64421 ) ( -66521 -3812 64421 ) ( -63635 19279 -64565 ) mtn 0 0 0 1 1 + ( 66510 -3720 64438 ) ( -63547 -19978 64438 ) ( -66434 3113 -64549 ) mtn 0 0 0 1 1 + ( 50409 -45720 62915 ) ( -66822 12895 62915 ) ( -50778 44984 -63149 ) mtn 0 0 0 1 1 + } + { //brush 1348 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 65081 7711 65535 ) ( -64976 -8546 65535 ) ( -64976 -8546 -65535 ) mtn 0 0 0 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) mtn 0 0 0 1 1 + ( 64306 -12641 65535 ) ( -64518 11513 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 + ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 + } + { //brush 1349 + ( 1872 65535 65535 ) ( 1872 -65535 65535 ) ( 1872 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 672 ) ( 65535 65535 672 ) ( -65535 -65535 672 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_0 0 0 0 1 1 + } + { //brush 1350 + ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 1351 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 + ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 1352 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 + ( 31464 57537 65535 ) ( -27151 -59694 65535 ) ( 31464 57537 -65535 ) stnwll01 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 + } + { //brush 1353 + ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 180 1 1 + ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 1354 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 1355 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 + } + { //brush 1356 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 1357 + ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -1872 -65535 65535 ) ( -1872 65535 65535 ) ( -1872 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 672 ) ( 65535 65535 672 ) ( -65535 -65535 672 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_0 0 0 0 1 1 + } + { //brush 1358 + ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) mtn 0 0 0 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) mtn 0 0 0 1 1 + } + { //brush 1359 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_2 0 16 180 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 90 1 1 + } + { //brush 1360 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) mtn 0 0 180 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) mtn 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 + ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) mtn 0 0 0 1 1 + } + { //brush 1361 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 1362 + ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 + ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 + } + { //brush 1363 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 + ( 45484 -65535 47196 ) ( 45484 65535 47196 ) ( -47196 65535 -45484 ) fstng_2 0 16 90 1 1 + ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) fstng_2 0 16 0 1 1 + } + { //brush 1364 + ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + ( 28168 59185 65535 ) ( -30447 -58046 65535 ) ( 28168 59185 -65535 ) fstng_0 0 0 180 1 1 + ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) fstng_0 0 0 180 1 1 + } + { //brush 1365 + ( -912 -65535 65535 ) ( -912 65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 61999 65535 21242 ) ( 61999 -65535 21242 ) ( -62344 -65535 -20205 ) stonesnw 0 0 0 1 1 + } + { //brush 1366 + ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 + ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 + } + { //brush 1367 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( -58878 28783 65535 ) ( 58353 -29832 65535 ) ( -58878 28783 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 + ( -20359 72321 54282 ) ( 72321 -20359 54282 ) ( 18812 -73868 -52735 ) stnwll02 0 0 0 1 1 + } + { //brush 1368 + ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 + } + { //brush 1369 + ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 + ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnfloor02 0 0 0 1 1 + ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnfloor02 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnfloor02 0 0 0 1 1 + ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnfloor02 0 0 0 1 1 + } + { //brush 1370 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 + } + { //brush 1371 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 + } + { //brush 1372 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 + ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 1373 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1344 65535 ) ( -65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( -31445 57547 65535 ) ( 27170 -59685 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 + ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 1374 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 + } + { //brush 1375 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1376 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 + ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 + ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 + ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 + } + { //brush 1377 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 0 1 1 + ( -65535 -45276 47404 ) ( 65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_2 0 16 0 1 1 + ( 65535 46812 45868 ) ( -65535 46812 45868 ) ( 65535 -45868 -46812 ) fstng_2 0 16 0 1 1 + } + { //brush 1378 + ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 + } + { //brush 1379 + ( 2720 65535 65535 ) ( 2720 -65535 65535 ) ( 2720 65535 -65535 ) ctf01 96 80 180 1 1 + ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) ctf01 96 80 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) ctf01 96 80 0 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf01 96 80 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) ctf01 96 80 0 1 1 + ( 61587 -65535 22411 ) ( 61587 65535 22411 ) ( -61137 -65535 -23610 ) ctf01 96 80 0 1 1 + } + { //brush 1380 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( -57656 31228 65535 ) ( 59576 -27388 65535 ) ( -57656 31228 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1381 + ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( -65535 46722 45958 ) ( 65535 46722 45958 ) ( -65535 -45958 -46722 ) light04 16 16 0 0.250000 0.250000 + ( -65535 -45574 47106 ) ( 65535 -45574 47106 ) ( -65535 47106 -45574 ) light04 16 16 0 0.250000 0.250000 + ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1382 + ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( -65535 -45542 47138 ) ( 65535 -45542 47138 ) ( -65535 47138 -45542 ) light04 16 16 0 0.250000 0.250000 + ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 46690 45990 ) ( 65535 46690 45990 ) ( -65535 -45990 -46690 ) light04 16 16 0 0.250000 0.250000 + ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1383 + ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( -65535 46658 46022 ) ( 65535 46658 46022 ) ( -65535 -46022 -46658 ) light04 16 16 0 0.250000 0.250000 + ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 -45510 47170 ) ( 65535 -45510 47170 ) ( -65535 47170 -45510 ) light04 16 16 0 0.250000 0.250000 + ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1384 + ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( -65535 -45526 47154 ) ( 65535 -45526 47154 ) ( -65535 47154 -45526 ) light04 16 16 0 0.250000 0.250000 + ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 46674 46006 ) ( 65535 46674 46006 ) ( -65535 -46006 -46674 ) light04 16 16 0 0.250000 0.250000 + ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1385 + ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( -65535 46706 45974 ) ( 65535 46706 45974 ) ( -65535 -45974 -46706 ) light04 16 16 0 0.250000 0.250000 + ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 -45558 47122 ) ( 65535 -45558 47122 ) ( -65535 47122 -45558 ) light04 16 16 0 0.250000 0.250000 + ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1386 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 -45618 47062 ) ( -65535 -45618 47062 ) ( -65535 47062 -45618 ) light04 16 16 0 0.250000 0.250000 + ( 65535 46582 46098 ) ( -65535 46582 46098 ) ( -65535 -46098 -46582 ) light04 16 16 0 0.250000 0.250000 + ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1387 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 46598 46082 ) ( -65535 46598 46082 ) ( -65535 -46082 -46598 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -45634 47046 ) ( -65535 -45634 47046 ) ( -65535 47046 -45634 ) light04 16 16 0 0.250000 0.250000 + ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1388 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 -45602 47078 ) ( -65535 -45602 47078 ) ( -65535 47078 -45602 ) light04 16 16 0 0.250000 0.250000 + ( 65535 46566 46114 ) ( -65535 46566 46114 ) ( -65535 -46114 -46566 ) light04 16 16 0 0.250000 0.250000 + ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1389 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 46614 46066 ) ( -65535 46614 46066 ) ( -65535 -46066 -46614 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -45650 47030 ) ( -65535 -45650 47030 ) ( -65535 47030 -45650 ) light04 16 16 0 0.250000 0.250000 + ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1390 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 46630 46050 ) ( -65535 46630 46050 ) ( -65535 -46050 -46630 ) light04 16 16 0 0.250000 0.250000 + ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 -45666 47014 ) ( -65535 -45666 47014 ) ( -65535 47014 -45666 ) light04 16 16 0 0.250000 0.250000 + ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1391 + ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1392 + ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 + } + { //brush 1393 + ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 1394 + ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 + ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 61258 57929 -38488 ) ( 61258 -69226 -6699 ) ( -60996 -57765 39146 ) tile2492 0 0 0 1 1 + ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 + ( 60996 69391 7356 ) ( 60996 -57765 39146 ) ( -61258 57929 -38488 ) tile2492 0 0 0 1 1 + } + { //brush 1395 + ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) ctf01 32 48 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 + ( 61721 -65535 -22053 ) ( 61721 65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 + } + { //brush 1396 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1397 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -16 65535 ) ( -65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 0 1 1 + } + { //brush 1398 + ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1399 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 + ( 912 -65535 65535 ) ( 912 65535 65535 ) ( 912 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 1400 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 1401 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 + ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 80 180 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 80 180 1 1 + ( 65535 -65535 104 ) ( 65535 65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) ctf02 96 80 90 1 1 + } + { //brush 1402 + ( 64 65535 65535 ) ( 64 -65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) tile2492 0 0 0 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) tile2492 0 0 0 1 1 + } + { //brush 1403 + ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 90 1 1 + } + { //brush 1404 + ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stonesnow 0 0 0 1 1 + } + { //brush 1405 + ( -912 65535 65535 ) ( -912 -65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnw 0 0 180 1 1 + ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 + ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stonesnw 0 0 0 1 1 + } + { //brush 1406 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) ctf02 96 48 180 1 1 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) ctf02 96 48 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 96 48 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) ctf02 96 48 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf02 96 48 0 1 1 + ( 61003 -65535 23968 ) ( 61003 65535 23968 ) ( -61721 -65535 -22053 ) ctf02 96 48 0 1 1 + } + { //brush 1407 + ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) ctf02 32 80 180 1 1 + ( -2720 -65535 65535 ) ( -2720 65535 65535 ) ( -2720 65535 -65535 ) ctf02 32 80 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) ctf02 32 80 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 32 80 0 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf02 32 80 0 1 1 + ( 61137 -65535 -23610 ) ( 61137 65535 -23610 ) ( -61587 -65535 22411 ) ctf02 32 80 0 1 1 + } + { //brush 1408 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 + } + { //brush 1409 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1072 -65535 65535 ) ( -1072 65535 65535 ) ( -1072 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 + } + { //brush 1410 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + } + { //brush 1411 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_0 0 0 0 1 1 + } + { //brush 1412 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 1413 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 -46706 45974 ) ( -65535 -46706 45974 ) ( -65535 45974 -46706 ) light04 16 16 0 0.250000 0.250000 + ( 65535 45558 47122 ) ( -65535 45558 47122 ) ( -65535 -47122 -45558 ) light04 16 16 0 0.250000 0.250000 + ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1414 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 45526 47154 ) ( -65535 45526 47154 ) ( -65535 -47154 -45526 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -46674 46006 ) ( -65535 -46674 46006 ) ( -65535 46006 -46674 ) light04 16 16 0 0.250000 0.250000 + ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1415 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 -46658 46022 ) ( -65535 -46658 46022 ) ( -65535 46022 -46658 ) light04 16 16 0 0.250000 0.250000 + ( 65535 45510 47170 ) ( -65535 45510 47170 ) ( -65535 -47170 -45510 ) light04 16 16 0 0.250000 0.250000 + ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1416 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 45542 47138 ) ( -65535 45542 47138 ) ( -65535 -47138 -45542 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -46690 45990 ) ( -65535 -46690 45990 ) ( -65535 45990 -46690 ) light04 16 16 0 0.250000 0.250000 + ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1417 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 45574 47106 ) ( -65535 45574 47106 ) ( -65535 -47106 -45574 ) light04 16 16 0 0.250000 0.250000 + ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 + ( 65535 -46722 45958 ) ( -65535 -46722 45958 ) ( -65535 45958 -46722 ) light04 16 16 0 0.250000 0.250000 + ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1418 + ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 -46630 46050 ) ( 65535 -46630 46050 ) ( -65535 46050 -46630 ) light04 16 16 0 0.250000 0.250000 + ( -65535 45666 47014 ) ( 65535 45666 47014 ) ( -65535 -47014 -45666 ) light04 16 16 0 0.250000 0.250000 + ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1419 + ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( -65535 45602 47078 ) ( 65535 45602 47078 ) ( -65535 -47078 -45602 ) light04 16 16 0 0.250000 0.250000 + ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 -46566 46114 ) ( 65535 -46566 46114 ) ( -65535 46114 -46566 ) light04 16 16 0 0.250000 0.250000 + ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1420 + ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( -65535 -46614 46066 ) ( 65535 -46614 46066 ) ( -65535 46066 -46614 ) light04 16 16 0 0.250000 0.250000 + ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 45650 47030 ) ( 65535 45650 47030 ) ( -65535 -47030 -45650 ) light04 16 16 0 0.250000 0.250000 + ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1421 + ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( -65535 45618 47062 ) ( 65535 45618 47062 ) ( -65535 -47062 -45618 ) light04 16 16 0 0.250000 0.250000 + ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 -46582 46098 ) ( 65535 -46582 46098 ) ( -65535 46098 -46582 ) light04 16 16 0 0.250000 0.250000 + ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1422 + ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( -65535 -46598 46082 ) ( 65535 -46598 46082 ) ( -65535 46082 -46598 ) light04 16 16 0 0.250000 0.250000 + ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 + ( -65535 45634 47046 ) ( 65535 45634 47046 ) ( -65535 -47046 -45634 ) light04 16 16 0 0.250000 0.250000 + ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 + } + { //brush 1423 + ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + ( 57656 -31228 65535 ) ( -59576 27388 65535 ) ( -59576 27388 -65535 ) stnwll02 0 0 0 1 1 + } + { //brush 1424 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 0 1 1 + } + { //brush 1425 + ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + } + { //brush 1426 + ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 288 ) ( 65535 65535 288 ) ( -65535 -65535 288 ) stnwll02 0 0 90 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + } + { //brush 1427 + ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + } + { //brush 1428 + ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 + } + { //brush 1429 + ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) ctf01 96 80 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) ctf01 96 80 0 1 1 + ( 61587 65535 22411 ) ( 61587 -65535 22411 ) ( -61137 -65535 -23610 ) ctf01 96 80 0 1 1 + ( 61823 -65535 -21779 ) ( 61823 65535 -21779 ) ( -60900 -65535 24241 ) ctf01 96 80 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) ctf01 96 80 0 1 1 + } + { //brush 1430 + ( 2848 65535 65535 ) ( 2848 -65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 1431 + ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 + ( 47308 65535 45372 ) ( 47308 -65535 45372 ) ( -45372 -65535 -47308 ) stnwll02 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 + } + { //brush 1432 + ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 + } + { //brush 1433 + ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 + ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 90 1 1 + } + { //brush 1434 + ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 + } + { //brush 1435 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 180 1 1 + } + { //brush 1436 + ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + } + { //brush 1437 + ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1438 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 1439 + ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 + ( 1808 -65535 65535 ) ( 1808 65535 65535 ) ( 1808 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 + } + { //brush 1440 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll02 0 0 90 1 1 + } + { //brush 1441 + ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1442 + ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 1443 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 + ( 65535 -61526 -22572 ) ( 65535 61197 23449 ) ( -65535 -61526 -22572 ) tile2492 0 0 90 1 1 + ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 + } + { //brush 1444 + ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 + ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 + ( 61258 69226 -6699 ) ( 61258 -57929 -38488 ) ( -60996 57765 39146 ) tile2492 0 0 0 1 1 + ( 60996 57765 39146 ) ( 60996 -69391 7356 ) ( -61258 69226 -6699 ) tile2492 0 0 0 1 1 + } + { //brush 1445 + ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 1446 + ( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 + } + { //brush 1447 + ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll02 0 0 90 1 1 + } + { //brush 1448 + ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 90 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 + ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 + } + { //brush 1449 + ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 + ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 + } + { //brush 1450 + ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 + } + { //brush 1451 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 + ( -65535 16 65535 ) ( 65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 + ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 0 1 1 + } + { //brush 1452 + ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 + } + { //brush 1453 + ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 + ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 + ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 + ( 65535 46348 46332 ) ( -65535 46348 46332 ) ( -65535 -46332 -46348 ) fstng_2 0 16 0 1 1 + } + { //brush 1454 + ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) ctf02 32 80 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) ctf02 32 80 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 32 80 0 1 1 + ( 60900 -65535 24241 ) ( 60900 65535 24241 ) ( -61823 -65535 -21779 ) ctf02 32 80 0 1 1 + ( 61137 65535 -23610 ) ( 61137 -65535 -23610 ) ( -61587 -65535 22411 ) ctf02 32 80 0 1 1 + } + { //brush 1455 + ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2848 -65535 65535 ) ( -2848 65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 1456 + ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnfloor1 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnfloor1 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 + } + { //brush 1457 + ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll01 0 0 0 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll01 0 0 90 1 1 + } + { //brush 1458 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 + ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 90 1 1 + } + { //brush 1459 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 + } + { //brush 1460 + ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) ctf01 64 80 0 1 1 + ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) ctf01 64 80 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf01 64 80 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf01 64 80 180 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf01 64 80 90 1 1 + ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) ctf01 64 80 90 1 1 + } + { //brush 1461 + ( 2720 65535 65535 ) ( 2720 -65535 65535 ) ( 2720 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 + } + { //brush 1462 + ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) ctf01 32 80 0 1 1 + ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 80 180 1 1 + ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) ctf01 32 80 180 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) ctf01 32 80 90 1 1 + ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf01 32 80 0 1 1 + ( 65535 -61197 23449 ) ( 65535 61526 -22572 ) ( -65535 -61197 23449 ) ctf01 32 80 90 1 1 + } + { //brush 1463 + ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 + ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 80 180 1 1 + ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 + ( 65535 -61526 -22572 ) ( 65535 61197 23449 ) ( -65535 -61526 -22572 ) ctf02 96 80 90 1 1 + } + { //brush 1464 + ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2720 -65535 65535 ) ( -2720 65535 65535 ) ( -2720 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 + } + { //brush 1465 + ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stonesnw2 0 0 180 1 1 + ( -1408 -65535 65535 ) ( -1408 65535 65535 ) ( -1408 65535 -65535 ) stonesnw2 0 0 180 1 1 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw2 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw2 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw2 0 0 0 1 1 + } + { //brush 1466 + ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -1072 -65535 65535 ) ( -1072 65535 65535 ) ( -1072 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + } + { //brush 1467 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 + } + { //brush 1468 + ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + } + { //brush 1469 + ( -1216 65535 65535 ) ( -1216 -65535 65535 ) ( -1216 65535 -65535 ) stnwll01 0 0 180 1 1 + ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 180 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll01 0 0 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 0 1 1 + } + { //brush 1470 + ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 + } + { //brush 1471 + ( -320 65535 65535 ) ( -320 -65535 65535 ) ( -320 65535 -65535 ) tile2492 0 0 0 1 1 + ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) tile2492 0 0 0 1 1 + ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 + } + { //brush 1472 + ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 + ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 + } + { //brush 1473 + ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 + ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 90 1 1 + } + { //brush 1474 + ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 180 1 1 + ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 + ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 + ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 180 1 1 + } + { //brush 1475 + ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 + ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 + ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 180 1 1 + } + { //brush 1476 + ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 + ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 + ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 1477 + ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 + ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 0 1 1 + ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 + ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 + ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 + ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 + } + { //brush 1478 + ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 + ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + } + { //brush 1479 + ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 1480 + ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 + ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 + } + { //brush 1481 + ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -320 -65535 65535 ) ( -320 65535 65535 ) ( -320 65535 -65535 ) stonesnow 0 0 180 1 1 + ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 + ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 + ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 + } + { //brush 1482 + ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1056 -65535 65535 ) ( -1056 65535 65535 ) ( -1056 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 + ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 + ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 + } + { //brush 1483 + ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 + ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 + ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 + } + { //brush 1484 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 + } + { //brush 1485 + ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) ctf01 64 80 0 1 1 + ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) ctf01 64 80 0 1 1 + ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf01 64 80 180 1 1 + ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) ctf01 64 80 90 1 1 + ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) ctf01 64 80 90 1 1 + } + { //brush 1486 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 + ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 + } + { //brush 1487 + ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 + } + { //brush 1488 + ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 + ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 + ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 + ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 + ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 + ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 + } + { //brush 1489 + ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 180 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stnwll05 0 0 90 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } + { //brush 1490 + ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 + ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 + ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 + ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 + ( -58219 -30101 65535 ) ( 59013 28514 65535 ) ( -58219 -30101 -65535 ) sky003 0 0 0 1 1 + ( 64593 -11074 65535 ) ( -64693 10472 65535 ) ( -64693 10472 -65535 ) sky003 0 0 0 1 1 + } + { //brush 1491 + ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 90 1 1 + ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) sky003 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 90 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 90 1 1 + ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) sky003 0 0 180 1 1 + } + { //brush 1492 + ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 + ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 + ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 90 1 1 + ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 90 1 1 + ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 90 1 1 + ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) sky003 0 0 180 1 1 + ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) sky003 0 0 90 1 1 + } +} +{ + "classname" "func_door" + "angle" "-1" + "speed" "600" + "sounds" "2" + "wait" "1" + "lip" "0" + "dmg" "0" + "health" "0" + "team_no" "2" + { //brush 0 + ( 1776 65535 65535 ) ( 1776 -65535 65535 ) ( 1776 65535 -65535 ) door 0 -4 0 1 1 + ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) door 0 -4 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + } + { //brush 1 + ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) door 0 -4 0 1 1 + ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) door 0 -4 0 1 1 + ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + } +} +{ + "classname" "func_door" + "angle" "-1" + "speed" "600" + "sounds" "2" + "wait" "1" + "lip" "0" + "dmg" "0" + "health" "0" + "team_no" "2" + { //brush 0 + ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) door 0 12 0 1 1 + ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) door 0 12 0 1 1 + ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + } + { //brush 1 + ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) door 0 12 0 1 1 + ( 1232 -65535 65535 ) ( 1232 65535 65535 ) ( 1232 65535 -65535 ) door 0 12 0 1 1 + ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 + } +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "1120 912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "832 912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "768 912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "480 912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "416 912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "1120 1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "832 1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "768 1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "480 1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "416 1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "128 912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "128 1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "1920 1056 736" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "1408 1056 736" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "1904 -104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "1904 104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "1128 0 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "1488 -104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "1488 104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "2208 -456 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "1984 -456 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "2208 -888 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "1984 -888 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "744 944 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "744 1168 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "1176 944 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "1024 1456 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1696 -208 368" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "1696 -304 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "1184 -328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "1184 328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "640 0 704" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "384 -384 704" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "384 384 704" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "992 -328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "992 328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1024 -128 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1024 128 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1024 400 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1024 -400 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1024 -672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1024 672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1696 -672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "1360 -672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "1696 104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1488 -440 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1264 -440 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2784 0 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2784 -416 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2528 -416 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2528 -208 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2784 -208 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "2192 104 480" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "2192 -104 480" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "2400 104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "2400 -104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2064 0 384" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2472 1280 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2472 832 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2472 384 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2472 608 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2472 160 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1808 568 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1488 568 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1808 1544 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1488 1544 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "0 832 192" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "0 576 192" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "1184 912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "1184 1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2144 672 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "2144 1440 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2400 -520 480" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "1696 -584 432" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1904 700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1776 700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1648 700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1520 700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1392 700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1392 1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1520 1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1648 1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1776 1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "1904 1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "1392 1056 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "1176 1168 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "200" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2784 0 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2528 0 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2528 0 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "200" + "style" "0" + "_color" "1 1 0.7" + "origin" "2272 0 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "220" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2784 -128 360" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "2400 -208 480" +} +{ + "classname" "func_plat" + "angle" "-2" + "height" "160" + "speed" "50" + { //brush 0 + ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 0 1 1 + ( 63787 -65534 -15058 ) ( 63787 65534 -15058 ) ( -63369 -65534 16730 ) fstng_2 0 0 0 1 1 + } + { //brush 1 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 + } + { //brush 2 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 + } + { //brush 3 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 90 1 1 + } + { //brush 4 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 90 1 1 + ( 63787 -65534 -15058 ) ( 63787 65534 -15058 ) ( -63369 -65534 16730 ) fstng_2 0 0 0 1 1 + } + { //brush 5 + ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 0 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 0 1 1 + } + { //brush 6 + ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 360 ) ( 65535 65535 360 ) ( -65535 -65535 360 ) fstng_0 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "64 -1056 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "200" + "style" "33" + "targetname" "r_p_lite" + "origin" "2544 1056 512" +} +{ + "classname" "trigger_multiple" + "sounds" "0" + "wait" "0" + "delay" "0" + "team_no" "1" + "target" "r_guard" + "netname" "r_beam_trig" + "style" "32" + { //brush 0 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 + ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 + } + { //brush 1 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 + ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 + } + { //brush 2 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 + } + { //brush 3 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 + ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 + } + { //brush 4 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 + ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 + } + { //brush 5 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 + } + { //brush 6 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) fstng_0 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) fstng_0 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + } + { //brush 7 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 + } + { //brush 8 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 + } + { //brush 9 + ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 0 1 1 + ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + } + { //brush 10 + ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) trigger 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 + } + { //brush 11 + ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) trigger 0 0 0 1 1 + ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + } + { //brush 12 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 + } +} +{ + "classname" "i_t_g" + "noise" "weapons/lhit.wav" + "health" "-500" + "deathtype" " died\n" + "targetname" "r_guard" + "goal_effects" "1" + "group_no" "40" + "netname" "b_kill" + "origin" "2464 1056 449" +} +{ + "classname" "i_t_g" + "n_b" " deactivated reds lasers.\n" + "style" "33" + "targetname" "r_start" + "activate_goal_no" "186" + "b_b" "Reds Lasers are Down!\n" + "g_e" "3" + "noise" "misc/power.wav" + "remove_group_no" "40" + "wait" "20" + "message" "You have deactivated enemy Lasers!\n" + "netname" "r_power_off" + "target" "r_p_lite" + "origin" "2432 1056 449" +} +{ + "classname" "i_t_g" + "b_o" "Our lasers are back up!\n" + "b_t" "Enemy lasers are back up!\n" + "style" "33" + "restore_group_no" "40" + "delay_time" "20" + "goal_no" "186" + "b_b" "Reds Lasers are Restored!" + "wait" "0" + "netname" "r_power_on" + "target" "r_p_lite" + "origin" "2400 1056 449" +} +{ + "classname" "func_door" + "angle" "270" + "wait" "20" + "lip" "-8" + "dmg" "1000" + "targetname" "r_start" + "speed" "10000" + "sounds" "0" + { //brush 0 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) *lavakell5 0 0 0 1 1 + } + { //brush 1 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) *lavakell5 0 0 0 1 1 + } + { //brush 2 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) *lavakell5 0 0 0 1 1 + } + { //brush 3 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) *lavakell5 0 0 0 1 1 + } + { //brush 4 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) *lavakell5 0 0 0 1 1 + } +} +{ + "classname" "trigger_multiple" + "sounds" "4" + "wait" "5" + "message" "Laser deactivation switch\nPrevent of enemy usage!\n" + "style" "32" + "delay" "0" + "team_no" "2" + { //brush 0 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) trigger 0 0 0 1 1 + } +} +{ + "classname" "trigger_multiple" + "sounds" "4" + "wait" "5" + "message" "Laser deactivation switch\nPress it!\n" + "style" "32" + "delay" "0" + "team_no" "1" + { //brush 0 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) trigger 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 + } +} +{ + "classname" "func_button" + "angle" "270" + "delay" "0" + "lip" "-2" + "team_no" "1" + "targetname" "red_button" + "wait" "20" + "style" "36" + "target" "r_start" + { //brush 0 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) fstng_0 0 0 0 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) skull1 32 0 0 0.500000 0.500000 + ( 65535 -520 65535 ) ( -65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_0 0 0 0 1 1 + } +} +{ + "classname" "info_player_teamspawn" + "angle" "90" + "netname" "team2_spawn" + "team_no" "2" + "origin" "1024 880 512" +} +{ + "classname" "info_player_teamspawn" + "angle" "90" + "netname" "team2_spawn" + "team_no" "2" + "origin" "896 880 512" +} +{ + "classname" "info_player_teamspawn" + "netname" "team2_spawn" + "team_no" "2" + "origin" "800 960 514" +} +{ + "classname" "info_player_teamspawn" + "netname" "team2_spawn" + "team_no" "2" + "origin" "800 1088 512" +} +{ + "classname" "info_player_teamspawn" + "angle" "180" + "netname" "team2_spawn" + "team_no" "2" + "origin" "1120 1088 512" +} +{ + "classname" "info_player_teamspawn" + "angle" "180" + "netname" "team2_spawn" + "team_no" "2" + "origin" "1120 960 512" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "1056 1232 456" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "2" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team2_armor" + "goal_activation" "1" + "skin" "2" + "origin" "1096 1208 448" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "1136 1184 456" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "864 1232 456" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "2" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team2_armor" + "goal_activation" "1" + "skin" "2" + "origin" "824 1208 448" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "784 1184 456" +} +{ + "classname" "info_player_teamspawn" + "angle" "180" + "netname" "team2_spawn" + "team_no" "2" + "origin" "2272 -736 560" +} +{ + "classname" "info_player_teamspawn" + "angle" "180" + "netname" "team2_spawn" + "team_no" "2" + "origin" "2272 -608 560" +} +{ + "classname" "info_player_teamspawn" + "angle" "270" + "netname" "team2_spawn" + "team_no" "2" + "origin" "2208 -512 560" +} +{ + "classname" "info_player_teamspawn" + "angle" "270" + "netname" "team2_spawn" + "team_no" "2" + "origin" "2080 -512 560" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "1968 -496 504" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "2" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team2_armor" + "goal_activation" "1" + "skin" "2" + "origin" "1944 -536 496" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "1920 -576 504" +} +{ + "classname" "info_player_teamspawn" + "angle" "90" + "netname" "team2_spawn" + "team_no" "2" + "origin" "2208 -832 560" +} +{ + "classname" "info_player_teamspawn" + "angle" "90" + "netname" "team2_spawn" + "team_no" "2" + "origin" "2080 -832 560" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "1968 -848 504" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "2" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team2_armor" + "goal_activation" "1" + "skin" "2" + "origin" "1944 -808 496" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "2" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team2_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "1920 -768 504" +} +{ + "classname" "info_tfdetect" + "hook_out" "1" + "impulse" "4" + "b_n" "Capture the emeny flag. See the frozen.txt for detail.\n" + "b_t" "\nFrozen Fire\n\n\nSELECT TEAM\n“‘ BLUE\n”‘ RED \n" + "display_item_status1" "1" + "display_item_status2" "2" + "team_str_home" "Your Flag: Base." + "team_str_carried" "Your Flag: Carried by" + "team_str_moved" "Your Flag: Down." + "non_team_str_home" "Enemy Flag: Base." + "non_team_str_carried" "Enemy Flag: Carried by" + "non_team_str_moved" "Enemy Flag: Down." + "origin" "0 0 576" +} +{ + "classname" "info_player_start" + "origin" "0 0 504" +} +{ + "classname" "func_door" + "angle" "-1" + "speed" "600" + "sounds" "2" + "wait" "1" + "lip" "0" + "dmg" "0" + "health" "0" + "team_no" "1" + { //brush 0 + ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) door 0 -4 0 1 1 + ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) door 0 -4 0 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 + } + { //brush 1 + ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) door 0 -4 0 1 1 + ( -1776 -65535 65535 ) ( -1776 65535 65535 ) ( -1776 65535 -65535 ) door 0 -4 0 1 1 + ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 + ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 + } +} +{ + "classname" "func_door" + "angle" "-1" + "speed" "600" + "sounds" "2" + "wait" "1" + "lip" "0" + "dmg" "0" + "health" "0" + "team_no" "1" + { //brush 0 + ( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) door 0 12 0 1 1 + ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 + } + { //brush 1 + ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) door 0 12 0 1 1 + ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 + ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 + ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 + } +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1120 -912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-832 -912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-768 -912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-480 -912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-416 -912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1120 -1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-832 -1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-768 -1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-480 -1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-416 -1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-128 -912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-128 -1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "-1920 -1056 736" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "-1408 -1056 736" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1904 104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1904 -104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1128 0 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1488 104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1488 -104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-2208 456 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1984 456 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-2208 888 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1984 888 592" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-744 -944 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-744 -1168 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1176 -944 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1024 -1456 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1696 208 368" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1696 304 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1184 328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1184 -328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "-640 0 704" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "-384 384 704" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "-384 -384 704" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "-992 328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "350" + "style" "0" + "_color" "1 1 0.7" + "origin" "-992 -328 400" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1024 128 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1024 -128 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1024 -400 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1024 400 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1024 672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1024 -672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1696 672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 0.8" + "origin" "-1360 672 608" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1696 -104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1488 440 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1264 440 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2784 0 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2784 416 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2528 416 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2528 208 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2784 208 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2192 -104 480" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2192 104 480" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2400 -104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2400 104 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2064 0 384" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2472 -1280 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2472 -832 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2472 -384 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2472 -608 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2472 -160 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1808 -568 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1488 -568 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1808 -1544 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1488 -1544 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "650" + "style" "0" + "origin" "0 0 704" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "0 -832 192" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "0 -576 192" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1184 -912 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "280" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1184 -1200 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2144 -672 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2144 -1440 576" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2400 520 480" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 1 0.7" + "origin" "-1696 584 432" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1904 -700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1776 -700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1648 -700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1520 -700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1392 -700 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1392 -1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1520 -1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1648 -1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1776 -1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "150" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1904 -1412 280" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1392 -1056 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-1176 -1168 544" +} +{ + "classname" "light" + "angle" "-2" + "light" "200" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2784 0 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2528 0 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2528 0 512" +} +{ + "classname" "light" + "angle" "-2" + "light" "200" + "style" "0" + "_color" "1 1 0.7" + "origin" "-2272 0 336" +} +{ + "classname" "light" + "angle" "-2" + "light" "220" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2784 128 360" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "1 0.6 0.8" + "origin" "-2400 208 480" +} +{ + "classname" "func_plat" + "angle" "-2" + "height" "160" + "speed" "50" + { //brush 0 + ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 0 1 1 + ( 63369 -65534 16730 ) ( 63369 65534 16730 ) ( -63787 -65534 -15058 ) fstng_2 0 0 0 1 1 + } + { //brush 1 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 + } + { //brush 2 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) fstng_0 0 0 0 1 1 + ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 + ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 + } + { //brush 3 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_2 0 0 180 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 90 1 1 + } + { //brush 4 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_2 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 90 1 1 + ( 63369 -65534 16730 ) ( 63369 65534 16730 ) ( -63787 -65534 -15058 ) fstng_2 0 0 0 1 1 + } + { //brush 5 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 + ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 0 1 1 + } + { //brush 6 + ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 + ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 + ( 65535 -65535 360 ) ( 65535 65535 360 ) ( -65535 -65535 360 ) fstng_0 0 0 0 1 1 + ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + } +} +{ + "classname" "light" + "angle" "-2" + "light" "300" + "style" "0" + "_color" "0.8 1 1" + "origin" "-64 1056 240" +} +{ + "classname" "light" + "angle" "-2" + "light" "200" + "style" "33" + "targetname" "b_p_lite" + "origin" "-2544 -1056 512" +} +{ + "classname" "i_t_g" + "noise" "weapons/lhit.wav" + "health" "-500" + "targetname" "b_guard" + "deathtype" " died\n" + "goal_effects" "1" + "group_no" "41" + "netname" "r_kill" + "origin" "-2464 -1056 449" +} +{ + "classname" "i_t_g" + "n_b" " deactivated blues lasers.\n" + "style" "33" + "targetname" "b_start" + "activate_goal_no" "187" + "b_b" "Blues Lasers are Down!\n" + "g_e" "3" + "noise" "misc/power.wav" + "remove_group_no" "41" + "wait" "20" + "message" "You have deactivated enemy Lasers!\n" + "netname" "b_power_off" + "target" "b_p_lite" + "origin" "-2432 -1056 449" +} +{ + "classname" "i_t_g" + "b_o" "Our lasers are back up!\n" + "b_t" "Enemy lasers are back up!\n" + "style" "33" + "restore_group_no" "41" + "delay_time" "20" + "goal_no" "187" + "b_b" "Blues Lasers are Restored!" + "wait" "0" + "netname" "b_power_on" + "target" "b_p_lite" + "origin" "-2400 -1056 449" +} +{ + "classname" "trigger_multiple" + "sounds" "0" + "wait" "0" + "delay" "0" + "team_no" "2" + "target" "b_guard" + "netname" "b_beam_trig" + "style" "32" + { //brush 0 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 + ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 + } + { //brush 1 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 + ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 + } + { //brush 2 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 + } + { //brush 3 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 + ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 + } + { //brush 4 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 + ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 + } + { //brush 5 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 + } + { //brush 6 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) fstng_0 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) fstng_0 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + } + { //brush 7 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 + } + { //brush 8 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 + } + { //brush 9 + ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) trigger 0 0 0 1 1 + ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + } + { //brush 10 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 0 1 1 + ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 + } + { //brush 11 + ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 0 1 1 + ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 + ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 + } + { //brush 12 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 + } +} +{ + "classname" "func_door" + "angle" "90" + "wait" "20" + "lip" "-8" + "dmg" "1000" + "targetname" "b_start" + "speed" "10000" + "sounds" "0" + { //brush 0 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) *lavakell5 0 0 0 1 1 + } + { //brush 1 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) *lavakell5 0 0 0 1 1 + } + { //brush 2 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) *lavakell5 0 0 0 1 1 + } + { //brush 3 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) *lavakell5 0 0 0 1 1 + } + { //brush 4 + ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) *lavakell5 0 0 0 1 1 + } +} +{ + "classname" "trigger_multiple" + "sounds" "4" + "wait" "5" + "message" "Laser deactivation switch\nPrevent of enemy usage!\n" + "style" "32" + "delay" "0" + "team_no" "1" + { //brush 0 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) trigger 0 0 0 1 1 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) trigger 0 0 0 1 1 + ( 65535 520 65535 ) ( -65535 520 65535 ) ( -65535 520 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) trigger 0 0 0 1 1 + } +} +{ + "classname" "trigger_multiple" + "sounds" "4" + "wait" "5" + "message" "Laser deactivation switch\nPress it!\n" + "style" "32" + "delay" "0" + "team_no" "2" + { //brush 0 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) trigger 0 0 0 1 1 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) trigger 0 0 0 1 1 + ( 65535 520 65535 ) ( -65535 520 65535 ) ( -65535 520 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) trigger 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 + } +} +{ + "classname" "func_button" + "angle" "90" + "delay" "0" + "lip" "-2" + "team_no" "2" + "targetname" "blue_button" + "wait" "20" + "style" "36" + "target" "b_start" + { //brush 0 + ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) fstng_0 0 0 0 1 1 + ( -65535 520 65535 ) ( 65535 520 65535 ) ( -65535 520 -65535 ) trigger 0 0 0 1 1 + ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) skull1 32 0 0 0.500000 0.500000 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_0 0 0 0 1 1 + } +} +{ + "classname" "info_player_teamspawn" + "angle" "270" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-1024 -880 512" +} +{ + "classname" "info_player_teamspawn" + "angle" "270" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-896 -880 512" +} +{ + "classname" "info_player_teamspawn" + "angle" "180" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-800 -960 514" +} +{ + "classname" "info_player_teamspawn" + "angle" "180" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-800 -1088 512" +} +{ + "classname" "info_player_teamspawn" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-1120 -1088 512" +} +{ + "classname" "info_player_teamspawn" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-1120 -960 512" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "-1056 -1232 456" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "1" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team1_armor" + "goal_activation" "1" + "skin" "2" + "origin" "-1096 -1208 448" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "-1136 -1184 456" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "-864 -1232 456" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "1" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team1_armor" + "goal_activation" "1" + "skin" "2" + "origin" "-824 -1208 448" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "-784 -1184 456" +} +{ + "classname" "info_player_teamspawn" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-2272 736 560" +} +{ + "classname" "info_player_teamspawn" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-2272 608 560" +} +{ + "classname" "info_player_teamspawn" + "angle" "90" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-2208 512 560" +} +{ + "classname" "info_player_teamspawn" + "angle" "90" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-2080 512 560" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "-1968 496 504" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "1" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team1_armor" + "goal_activation" "1" + "skin" "2" + "origin" "-1944 536 496" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "-1920 576 504" +} +{ + "classname" "info_player_teamspawn" + "angle" "270" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-2208 832 560" +} +{ + "classname" "info_player_teamspawn" + "angle" "270" + "netname" "team1_spawn" + "team_no" "1" + "origin" "-2080 832 560" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "5" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "health" "25" + "origin" "-1968 848 504" +} +{ + "classname" "info_tfgoal" + "mdl" "progs/armor.mdl" + "team_no" "1" + "armorvalue" "200" + "goal_effects" "1" + "wait" "1" + "armortype" "0.8" + "noise" "items/armor1.wav" + "netname" "team1_armor" + "goal_activation" "1" + "skin" "2" + "origin" "-1944 808 496" +} +{ + "classname" "info_tfgoal" + "ammo_rockets" "20" + "ammo_cells" "100" + "mdl" "progs/backpack.mdl" + "team_no" "1" + "ammo_nails" "100" + "ammo_medikit" "50" + "goal_effects" "1" + "wait" "1" + "noise" "weapons/pkup.wav" + "netname" "team1_resupply" + "ammo_shells" "50" + "goal_activation" "1" + "no_grenades_1" "2" + "origin" "-1920 770 504" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "208 0 224" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "-208 0 224" +} +{ + "classname" "light" + "angle" "-2" + "light" "250" + "style" "0" + "_color" "0.8 1 1" + "origin" "0 0 224" +} +{ + "classname" "light" + "angle" "-2" + "light" "450" + "style" "0" + "origin" "0 -288 384" +} +{ + "classname" "light" + "angle" "-2" + "light" "450" + "style" "0" + "origin" "0 288 384" +} +{ + "classname" "item_tfgoal" + "angle" "145" + "netname" "blue flag" + "mdl" "progs/tf_stan.mdl" + "skin" "1" + "goal_no" "1" + "g_a" "693" + "g_e" "1" + "goal_result" "18" + "team_no" "2" + "owned_by" "1" + "items" "131072" + "pausetime" "30" + "n_b" " StolE ThE ΒΜΥΕ FlaG!\n" + "message" "YoU HavE ThE EnemY FlaG!\nΥΞ ΜΙΛΕ ΘΕΜΜ‘\n" + "d_n_t" " ΜοσΤ YouR FLAG‘\n" + "d_n_n" " ΜοσΤ ΤθΕ BLUE FLAG‘\n" + "b_n" "YouR FlaG HaS BeeN StoleN!!\nΗεΤ ΕΝ‘\n" + "b_t" "Ωου ΤεαΝ ΣτομΕ ΤθΕ EnemieS FlaG‘\n" + "noise" "flagtaken.wav" + "noise3" "Your flag was returned to base!" + "noise4" "The enemy flag was returned to base!" + "origin" "-2560 -1056 392" +} +{ + "classname" "i_t_g" + "netname" "blue capture" + "axhitme" "2" + "count" "10" + "frags" "10" + "noise" "items/cap2.wav" + "message" "Ωου ΤεαΝ ΟχεΣ ΩοΥ ΒιΗ‘\nΊ©\n" + "g_a" "1" + "g_e" "2" + "items_allowed" "2" + "team_no" "1" + "b_t" "€ƒƒƒƒ‚\n“’ ΖςαηΣ Ζο Ωα‘‘\n€ƒƒƒ‚\n" + "b_n" "Ωου FLAG ΧαΣ CAPTURED‘\nΊ―\n" + "origin" "-2560 224 384" +} +{ + "classname" "i_t_g" + "netname" "red capture" + "g_a" "1" + "team_no" "2" + "items_allowed" "1" + "g_e" "2" + "axhitme" "1" + "count" "10" + "frags" "10" + "message" "Ωου ΤεαΝ ΟχεΣ ΩοΥ ΒιΗ‘\nΊ©\n" + "b_t" "€ƒƒƒƒ‚\n“’ ΖςαηΣ Ζο Ωα‘‘\n€ƒƒƒ‚\n" + "b_n" "Ωου FLAG ΧαΣ CAPTURED‘\nΊ―\n" + "noise" "items/cap2.wav" + "origin" "2560 -224 384" +} +{ + "classname" "item_tfgoal" + "angle" "315" + "netname" "red flag" + "mdl" "progs/tf_stan.mdl" + "skin" "2" + "goal_no" "2" + "g_a" "693" + "g_e" "1" + "goal_result" "18" + "team_no" "1" + "owned_by" "2" + "items" "262144" + "pausetime" "30" + "n_b" " StolE ThE ΕΔ FlaG!\n" + "message" "YoU HavE ThE EnemY FlaG!\nΥΞ ΜΙΛΕ ΘΕΜΜ‘\n" + "d_n_t" " ΜοσΤ YouR FLAG‘\n" + "d_n_n" " ΜοσΤ ΤθΕ RED FLAG‘\n" + "b_n" "YouR FlaG HaS BeeN StoleN!!\nΗεΤ ΕΝ‘\n" + "b_t" "Ωου ΤεαΝ ΣτομΕ ΤθΕ EnemieS FlaG‘\n" + "noise" "flagtaken.wav" + "noise3" "Your flag was returned to base!" + "noise4" "The enemy flag was returned to base!" + "origin" "2560 1056 392" +} +//total of 1557 brushes diff --git a/q3f_openfire2b working copy.map b/q3f_openfire2b working copy.map index f19e2082..9aa7dfa8 100644 --- a/q3f_openfire2b working copy.map +++ b/q3f_openfire2b working copy.map @@ -1,147 +1,3 @@ -// Game: Quake -// Format: Standard -// entity 0 -{ -"angle" "90" -"classname" "worldspawn" -"team_blue_name" "Blue Team" -"team_red_name" "Red Team" -"author" "Jeremy Raymond" -"message" "Openfire by War|ocK" -"atmosphere" "T=RAIN,B=5 10,C=0.5,G=0.5 2,BV=0,GV=0 100,W=1 2,D=300" - -} - -/* -// entity 3 -{ -"classname" "target_position" -"targetname" "t3" -"origin" "1072 1152 -88" -} -*/ -/* -// entity 65 -{ -"angle" "180" -"classname" "func_goalinfo" -"allowteams" "red" -"flags" "hideactive" -"origin" "-1801 855 223" -"active_all_sound" "sound/misc/am_pkup.wav" -"give" "health=+100,armor=+300,ammo_shells=+100,ammo_bullets=+100,ammo_rockets=+100,ammo_cells=+200,gren1=+2,gren2=+0,ammo_medikit=+100" -"model" "models/objects/backpack/backpack.md3" -"wait" "2" -} -*/ -/* -// entity 93 -{ -"classname" "func_goalitem" -"inactivetarget" "redflaghud=~inactive" -"activetarget" "redflaghud=~active" -"carriedtarget" "redflaghud=~carried" -"sparkle" "1.000000 0.392157 0.392157" -"angle" "90" -"carried_sound" "sound/teamplay/flagtk_red.wav" -"carried_all_sound" "sound/teamplay/flagtk_red.wav" -"carried_message" "~You got the ^1red^* flag! Run for it!" -"carried_all_message" "%N nabbed the ^1red^* flag!" -"groupname" "redflag" -"origin" "-2562 -1154 158" -"allowteams" "blue" -"model" "models/flags/r_flag.md3" -"inactive_all_message" "The ^1red^* flag returned to base!" -"active_all_message" "The ^1red^* flag was dropped in the field!" -"flags" "showcarry,revealagent" -"active_flaginfo" "The ^1Red^* flag has been dropped in the field!" -"inactive_flaginfo" "The ^1Red^* flag is at base." -"carried_flaginfo" "%N is carrying the ^1Red^* flag!" -"wait" "45" -"_color" "1.000000 0.392157 0.392157" -"light" "50" -} -*/ -/* -// entity 94 -{ -"classname" "func_goalinfo" -"holding" "blueflag" -"give" "health=+100,armor=+300,ammo_shells=+100,ammo_bullets=+100,ammo_rockets=+100,ammo_cells=+100,gren1=+2,gren2=+2,ammo_medikit=+100,ammo_detpack=+1" -"teamscore" "10" -"origin" "-2513 239 159" -"active_team_sound" "sound/teamplay/flagcap_red.wav" -"active_all_message" "~%N CAPTURED the ^4blue ^*flag!" -"active_sound" "sound/teamplay/flagcap_red.wav" -"activetarget" "blueflag=~inactive,scorer" -"angle" "270" -"active_all_sound" "sound/teamplay/flagcap_red.wav" -} -*/ -// entity 95 -{ -"origin" "-352 512 128" -"angle" "315" -"classname" "info_player_intermission" -} -// entity 96 -{ -"origin" "-424 520 136" -"slot" "1" -"inactive_model" "models/flags/r_flag.md3" -"holding" "redflag" -"classname" "func_hud" -} -{ -"scale" ".5" -"targetname" "redflaghud" -"carried_shader" "textures/q3f_hud/red_lost" -"active_shader" "textures/q3f_hud/red_down" -"inactive_shader" "textures/q3f_hud/red_safe" -"slot" "3" -"origin" "-400 520 136" -"classname" "func_hud" -} -// entity 100 -{ -"angle" "270" -"classname" "func_goalitem" -"carried_sound" "sound/teamplay/flagtk_red.wav" -"carried_all_sound" "sound/teamplay/flagtk_red.wav" -"carried_message" "~You got the ^4blue^* flag! Run for it!" -"carried_all_message" "%N nabbed the ^4blue^* flag!" -"groupname" "blueflag" -"origin" "2558 1150 158" -"allowteams" "red" -"model" "models/flags/b_flag.md3" -"inactive_all_message" "The ^4blue^* flag returned to base!" -"active_all_message" "The ^4blue^* flag was dropped in the field!" -"flags" "showcarry,revealagent" -"active_flaginfo" "The ^4Blue^* flag has been dropped in the field!" -"inactive_flaginfo" "The ^4Blue^* flag is at base." -"carried_flaginfo" "%N is carrying the ^4Blue^* flag!" -"wait" "45" -"_color" "0.392157 0.392157 1.000000" -"light" "50" -"sparkle" "0.392157 0.392157 1.000000" -"carriedtarget" "blueflaghud=~carried" -"activetarget" "blueflaghud=~active" -"inactivetarget" "blueflaghud=~inactive" -} -// entity 101 -{ -"activetarget" "redflag=~inactive,scorer" -"active_sound" "sound/teamplay/flagcap_red.wav" -"active_all_message" "~%N CAPTURED the ^1red ^*flag!" -"active_team_sound" "sound/teamplay/flagcap_red.wav" -"origin" "2511 -241 159" -"teamscore" "10" -"give" "health=+100,armor=+300,ammo_shells=+100,ammo_bullets=+100,ammo_rockets=+100,ammo_cells=+100,gren1=+2,gren2=+2,ammo_medikit=+100,ammo_detpack=+1" -"holding" "redflag" -"classname" "func_goalinfo" -"angle" "90" -"active_all_sound" "sound/teamplay/flagcap_red.wav" -} // entity 102 { "classname" "target_kill" @@ -257,6 +113,8 @@ ( 65535 -65535 128 ) ( 65535 65535 128 ) ( -65535 -65535 128 ) e2u3/floor1_2 0 0 0 1 1 } } + + // entity 113 { "speed" "9999" From 47af083e350037a2fc13fd731282d11f302e21bc Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 23 Nov 2018 14:03:28 +1100 Subject: [PATCH 0500/2474] q3 ent support for target_kill (lasers on openfire) --- buttons.qc | 11 +++++++++++ q3.qc | 24 ++++++++++++++++++++++++ q3defs.qc | 4 +++- triggers.qc | 12 ++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/buttons.qc b/buttons.qc index 0c6ab1f3..b73643a7 100644 --- a/buttons.qc +++ b/buttons.qc @@ -104,6 +104,17 @@ void () func_button = { SetMovedir(); + // q3 support + if (self.activetarget != "") { + self.target = self.activetarget; + } + if (self.allowteams == "blue") { + self.team_no = 1; + } + if (self.allowteams == "red") { + self.team_no = 2; + } + self.movetype = MOVETYPE_PUSH; self.solid = SOLID_BSP; setmodel(self, self.model); diff --git a/q3.qc b/q3.qc index 356ff68f..eafe4198 100644 --- a/q3.qc +++ b/q3.qc @@ -147,7 +147,31 @@ void () func_goalitem = { item_tfgoal(); } +void () target_kill = { + self.classname = "info_tfgoal"; + self.health = -500; + self.deathtype = " died\n"; + self.goal_effects = 1; + + string cname, cstate; + float slen, idx; + idx = strstrofs(s, "="); + slen = strlen(self.checkstate); + cname = substring(self.checkstate, 0, idx); + cstate = substring(self.checkstate, idx + 1, slen); + + switch (cstate) + { + case "inactive": + self.if_goal_is_inactive = cname; + break; + case "active": + self.if_goal_is_active = cname; + } + + info_tfgoal(); +} /* void () target_position = { diff --git a/q3defs.qc b/q3defs.qc index aa154f0f..104c9ad8 100644 --- a/q3defs.qc +++ b/q3defs.qc @@ -11,4 +11,6 @@ .string carried_all_message; .string carried_message; .string carried_all_sound; -.string inactive_all_message; \ No newline at end of file +.string inactive_all_message; +.string activetarget; +.string checkstate; \ No newline at end of file diff --git a/triggers.qc b/triggers.qc index 3ea40d61..be6f25ef 100644 --- a/triggers.qc +++ b/triggers.qc @@ -100,6 +100,18 @@ void () trigger_multiple = { } self.use = multi_use; + // q3 fields + switch(self.allowteams) + { + case "blue": + self.team_no = 1; + break; + case "red": + self.team_no = 2; + break; + default: + } + InitTrigger(); if (self.health) { From 1fa45501e2d166a76c1d08c3848b8b2252445469 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 23 Nov 2018 14:03:37 +1100 Subject: [PATCH 0501/2474] ent conversion tracking --- frozen1.map | 14848 +----------------------------- q3f_openfire2b working copy.map | 39 +- stag3.map | 6 +- 3 files changed, 152 insertions(+), 14741 deletions(-) diff --git a/frozen1.map b/frozen1.map index c88d265c..b652c5a2 100644 --- a/frozen1.map +++ b/frozen1.map @@ -12,14337 +12,171 @@ "light" "50" "message" "Frozen Fire v1.1\nby Night Hunter\nhttp://clan.sd.ru" "wad" "d:\games\quake\worldcraft\wads\apocrypha.wad;d:\games\quake\worldcraft\wads\dethtex_gothic.wad;d:\games\quake\worldcraf" - { //brush 0 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 58392 65534 -29756 ) ( 58392 -65534 -29756 ) ( -58840 -65534 28860 ) stonesnow 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 2 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 3 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 - ( 63647 65534 15615 ) ( 63647 -65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 - } - { //brush 4 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 0 1 1 - ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) fstng_2 0 16 0 1 1 - } - { //brush 5 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -31464 -57537 65535 ) ( 27151 59694 65535 ) ( 27151 59694 -65535 ) stnwll01 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 6 - ( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 58952 28636 65535 ) ( -58280 -29980 65535 ) ( -58280 -29980 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 7 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 - } - { //brush 8 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 9 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 10 - ( 64 65535 65535 ) ( 64 -65535 65535 ) ( 64 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 11 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 - ( 47244 65535 45436 ) ( 47244 -65535 45436 ) ( -45436 65535 -47244 ) fstng_2 0 16 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 0 1 1 - ( -65535 -46348 46332 ) ( 65535 -46348 46332 ) ( 65535 46332 -46348 ) fstng_2 0 16 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 - } - { //brush 12 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -64 -65535 65535 ) ( -64 65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( 60996 -69391 7356 ) ( 60996 57765 39146 ) ( -61258 69226 -6699 ) tile2492 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) tile2492 0 0 0 1 1 - } - { //brush 13 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( 47308 -65535 45372 ) ( 47308 65535 45372 ) ( -45372 -65535 -47308 ) fstng_2 0 16 90 1 1 - } - { //brush 14 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 15 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - } - { //brush 16 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - ( -57573 31394 65535 ) ( 59659 -27221 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 17 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 180 1 1 - ( -44652 65535 48028 ) ( -44652 -65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 - } - { //brush 18 - ( 1824 65535 65535 ) ( 1824 -65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 19 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( -65534 17219 63246 ) ( 65534 17219 63246 ) ( -65534 -14569 -63909 ) stnwll02 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 20 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 21 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( -65534 17219 63246 ) ( 65534 17219 63246 ) ( -65534 -14569 -63909 ) stnwll02 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 22 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 0 1 1 - } - { //brush 23 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 0 1 1 - } - { //brush 24 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - } - { //brush 25 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 26 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 27 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -192 65535 ) ( 65535 -192 65535 ) ( -65535 -192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -160 65535 ) ( -65535 -160 65535 ) ( -65535 -160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 28 - ( 65535 -192 65535 ) ( -65535 -192 65535 ) ( -65535 -192 -65535 ) ftlattice2 16 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 65535 -63467 16338 ) ( 65535 63689 -15450 ) ( -65535 -63467 16338 ) ftlattice2 16 0 0 1 1 - ( 65535 -63713 -15352 ) ( 65535 63442 16436 ) ( -65535 -63713 -15352 ) ftlattice2 16 0 0 1 1 - ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 0 0 1 1 - ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 0 0 1 1 - } - { //brush 29 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -224 65535 ) ( 65535 -224 65535 ) ( -65535 -224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -192 65535 ) ( -65535 -192 65535 ) ( -65535 -192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 30 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -224 65535 ) ( -65535 -224 65535 ) ( -65535 -224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 31 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 32 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -63355 16786 ) ( 65535 63801 -15002 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 33 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 65535 -63355 16786 ) ( 65535 63801 -15002 ) ( -65535 -63355 16786 ) millgt1 16 16 0 1 1 - ( 65535 -63631 -15679 ) ( 65535 63524 16109 ) ( -65535 -63631 -15679 ) millgt1 16 16 0 1 1 - ( 63566 -65534 15943 ) ( 63566 65534 15943 ) ( -63590 -65534 -15845 ) millgt1 16 16 0 1 1 - ( 63842 -65534 -14836 ) ( 63842 65534 -14836 ) ( -63313 -65534 16952 ) millgt1 16 16 0 1 1 - } - { //brush 34 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1296 65535 ) ( 65535 1296 65535 ) ( -65535 1296 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 0 1 1 - } - { //brush 35 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1264 65535 ) ( 65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 36 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 1264 65535 ) ( 65535 1264 65535 ) ( -65535 1264 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) millgt1 16 0 90 1 0.500000 - ( 18108 -65534 63024 ) ( 18108 65534 63024 ) ( -13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - } - { //brush 37 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -57649 31240 65535 ) ( 59582 -27375 65535 ) ( -57649 31240 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 38 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 16 0 1 1 - ( 65535 -63639 -15649 ) ( 65535 63517 16139 ) ( -65535 -63639 -15649 ) millgt1 0 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) millgt1 0 16 0 1 1 - ( 63851 -65534 -14802 ) ( 63851 65534 -14802 ) ( -63305 -65534 16986 ) millgt1 0 16 0 1 1 - ( 63604 -65534 15789 ) ( 63604 65534 15789 ) ( -63551 -65534 -15999 ) millgt1 0 16 0 1 1 - } - { //brush 39 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 58737 29064 65535 ) ( -58494 -29551 65535 ) ( -58494 -29551 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 40 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 816 65535 ) ( 65535 816 65535 ) ( -65535 816 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 848 65535 ) ( -65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 90 1 1 - } - { //brush 41 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 816 65535 ) ( 65535 816 65535 ) ( -65535 816 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 848 65535 ) ( -65535 848 65535 ) ( -65535 848 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) millgt1 16 0 90 1 0.500000 - ( 18108 -65534 63024 ) ( 18108 65534 63024 ) ( -13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - } - { //brush 42 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 816 65535 ) ( -65535 816 65535 ) ( -65535 816 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 0 1 1 - } - { //brush 43 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_0 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 - } - { //brush 44 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 180 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - } - { //brush 45 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28130 -59205 65535 ) ( 30485 58027 65535 ) ( 30485 58027 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 46 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28104 -59217 65535 ) ( 30511 58014 65535 ) ( 30511 58014 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 47 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28079 -59230 65535 ) ( 30536 58001 65535 ) ( 30536 58001 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 48 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28053 -59243 65535 ) ( 30562 57989 65535 ) ( 30562 57989 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 49 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 50 - ( 2656 65535 65535 ) ( 2656 -65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 51 - ( 2656 65535 65535 ) ( 2656 -65535 65535 ) ( 2656 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 52 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) ftlattice2 16 16 0 1 1 - ( 65535 -63726 -15303 ) ( 65535 63430 16485 ) ( -65535 -63726 -15303 ) ftlattice2 16 16 0 1 1 - ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 16 0 1 1 - ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 16 0 1 1 - } - { //brush 53 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - } - { //brush 54 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 0 0 1 1 - ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 0 0 1 1 - ( 65535 -63467 16338 ) ( 65535 63689 -15450 ) ( -65535 -63467 16338 ) ftlattice2 16 0 0 1 1 - ( 65535 -63713 -15352 ) ( 65535 63442 16436 ) ( -65535 -63713 -15352 ) ftlattice2 16 0 0 1 1 - } - { //brush 55 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 - } - { //brush 56 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 57 - ( 2624 65535 65535 ) ( 2624 -65535 65535 ) ( 2624 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - } - { //brush 58 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2624 -65535 65535 ) ( 2624 65535 65535 ) ( 2624 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 59 - ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 60 - ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 59032 -28476 ) ( 65535 -58200 30140 ) ( -65535 -58200 30140 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 61 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 62 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 - } - { //brush 63 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 - } - { //brush 64 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 1424 65535 ) ( 65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 65 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -63800 -15006 65535 ) ( 63356 16783 65535 ) ( -63800 -15006 -65535 ) shootit 0 8 0 1 1 - ( -63132 17679 65535 ) ( 64024 -14110 65535 ) ( -63132 17679 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - } - { //brush 66 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -63162 17558 65535 ) ( 63994 -14230 65535 ) ( -63162 17558 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63830 -14885 65535 ) ( 63326 16903 65535 ) ( -63830 -14885 -65535 ) shootit 0 8 0 1 1 - } - { //brush 67 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63822 -14915 65535 ) ( 63333 16873 65535 ) ( -63822 -14915 -65535 ) shootit 0 8 0 1 1 - ( -63154 17588 65535 ) ( 64001 -14200 65535 ) ( -63154 17588 -65535 ) shootit 0 8 0 1 1 - } - { //brush 68 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63139 17648 65535 ) ( 64016 -14140 65535 ) ( -63139 17648 -65535 ) shootit 0 8 0 1 1 - ( -63807 -14975 65535 ) ( 63348 16813 65535 ) ( -63807 -14975 -65535 ) shootit 0 8 0 1 1 - } - { //brush 69 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63815 -14945 65535 ) ( 63341 16843 65535 ) ( -63815 -14945 -65535 ) shootit 0 8 0 1 1 - ( -63147 17618 65535 ) ( 64009 -14170 65535 ) ( -63147 17618 -65535 ) shootit 0 8 0 1 1 - } - { //brush 70 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58424 -29692 ) ( 65535 58808 28924 ) ( -65535 -58424 -29692 ) stnwll05 0 0 90 1 1 - } - { //brush 71 - ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58424 -29692 ) ( 65535 58808 28924 ) ( -65535 -58424 -29692 ) stnwll05 0 0 90 1 1 - } - { //brush 72 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58808 28924 ) ( 65535 -58424 -29692 ) ( -65535 -58424 -29692 ) stnfloor02 0 0 0 1 1 - } - { //brush 73 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 74 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 75 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) millgt1 16 0 0 1 1 - ( 63507 -65534 16176 ) ( 63507 65534 16176 ) ( -63648 -65534 -15612 ) millgt1 16 0 0 1 1 - ( 65535 -63361 16760 ) ( 65535 63794 -15028 ) ( -65535 -63361 16760 ) millgt1 16 0 0 1 1 - ( 63769 -65534 -15130 ) ( 63769 65534 -15130 ) ( -63387 -65534 16658 ) millgt1 16 0 0 1 1 - ( 65535 -63623 -15713 ) ( 65535 63533 16075 ) ( -65535 -63623 -15713 ) millgt1 16 0 0 1 1 - } - { //brush 76 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 880 -65535 65535 ) ( 880 65535 65535 ) ( 880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 77 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 78 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) fstng_2 0 0 0 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 79 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 80 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - } - { //brush 81 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -45524 65535 47156 ) ( -45524 -65535 47156 ) ( 47156 65535 -45524 ) fstng_2 0 16 90 1 1 - } - { //brush 82 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 - } - { //brush 83 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 84 - ( 2136 65535 65535 ) ( 2136 -65535 65535 ) ( 2136 65535 -65535 ) ctf07 0 16 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 16 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) ctf07 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) ctf07 0 16 0 1 1 - } - { //brush 85 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 86 - ( 2136 65535 65535 ) ( 2136 -65535 65535 ) ( 2136 65535 -65535 ) ctf07 0 16 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) ctf07 0 16 180 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) ctf07 0 16 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) ctf07 0 16 90 1 1 - } - { //brush 87 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 88 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 - ( -44964 65535 47716 ) ( -44964 -65535 47716 ) ( 47716 65535 -44964 ) fstng_2 0 16 90 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - } - { //brush 89 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 90 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 180 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 0 1 1 - ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 91 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 90 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 180 1 1 - } - { //brush 92 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63749 65534 -15209 ) ( 63749 -65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 0 1 1 - } - { //brush 93 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 90 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 94 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 90 1 1 - } - { //brush 95 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stnwll05 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stnwll05 0 0 0 1 1 - } - { //brush 96 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63749 65534 -15209 ) ( 63749 -65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 97 - ( 2080 -65535 65535 ) ( 2080 65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - } - { //brush 98 - ( 2080 -65535 65535 ) ( 2080 65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 0 1 1 - } - { //brush 99 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 624 65535 ) ( 65535 624 65535 ) ( -65535 624 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 100 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 624 65535 ) ( -65535 624 65535 ) ( -65535 624 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 101 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 400 65535 ) ( 65535 400 65535 ) ( -65535 400 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 102 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 368 65535 ) ( 65535 368 65535 ) ( -65535 368 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 400 65535 ) ( -65535 400 65535 ) ( -65535 400 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 103 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 368 65535 ) ( -65535 368 65535 ) ( -65535 368 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 104 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 105 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 176 65535 ) ( 65535 176 65535 ) ( -65535 176 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 106 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 176 65535 ) ( -65535 176 65535 ) ( -65535 176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 107 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 108 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 109 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( -65535 45836 46844 ) ( 65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 - ( 58878 -28783 65535 ) ( -58353 29832 65535 ) ( -58353 29832 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 110 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) metdec1 32 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 63809 65534 -14968 ) ( 63809 -65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) metdec1 32 0 0 1 1 - } - { //brush 111 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 112 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 113 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) millgt1 16 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 114 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 115 - ( 2528 65535 65535 ) ( 2528 -65535 65535 ) ( 2528 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2560 -65535 65535 ) ( 2560 65535 65535 ) ( 2560 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 116 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 117 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 118 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) millgt1 16 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 119 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - } - { //brush 120 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 121 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 0 1 1 - ( 31381 -57579 65535 ) ( -27234 59653 65535 ) ( -27234 59653 -65535 ) fstng_2 0 0 0 1 1 - ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 122 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 0 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 180 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 123 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 124 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 125 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 126 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 65535 -63400 16606 ) ( 65535 63756 -15183 ) ( -65535 -63400 16606 ) millgt1 16 16 0 1 1 - ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) millgt1 16 16 0 1 1 - ( 63842 -65534 -14836 ) ( 63842 65534 -14836 ) ( -63313 -65534 16952 ) millgt1 16 16 0 1 1 - ( 63566 -65534 15943 ) ( 63566 65534 15943 ) ( -63590 -65534 -15845 ) millgt1 16 16 0 1 1 - } - { //brush 127 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 31330 -57605 65535 ) ( -27285 59627 65535 ) ( -27285 59627 -65535 ) fstng_2 0 0 0 1 1 - ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 128 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 129 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 130 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -28757 -58891 65535 ) ( 29858 58341 65535 ) ( 29858 58341 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 131 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 864 65535 ) ( 65535 864 65535 ) ( -65535 864 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( 30703 -57918 65535 ) ( -27912 59313 65535 ) ( -27912 59313 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 132 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 864 65535 ) ( -65535 864 65535 ) ( -65535 864 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 133 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - } - { //brush 134 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 - } - { //brush 135 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) ctf07 0 16 0 1 1 - ( 1240 -65535 65535 ) ( 1240 65535 65535 ) ( 1240 65535 -65535 ) ctf07 0 16 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 16 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 - } - { //brush 136 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 - } - { //brush 137 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - } - { //brush 138 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -62234 -20536 65535 ) ( 62109 20911 65535 ) ( -62234 -20536 -65535 ) mtn 0 0 0 1 1 - } - { //brush 139 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - } - { //brush 140 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64693 -10472 65535 ) ( 64593 11074 65535 ) ( -64693 -10472 -65535 ) mtn 0 0 0 1 1 - ( -58219 30101 65535 ) ( 59013 -28514 65535 ) ( -58219 30101 -65535 ) mtn 0 0 0 1 1 - } - { //brush 141 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 62109 20911 65535 ) ( -62234 -20536 65535 ) ( -62234 -20536 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 142 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 62109 20911 65535 ) ( -62234 -20536 65535 ) ( -62234 -20536 -65535 ) stnfloor02 0 0 0 1 1 - } - { //brush 143 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 - } - { //brush 144 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) ftlattice2 16 0 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 0 0 1 1 - ( 65535 -63408 16572 ) ( 65535 63747 -15216 ) ( -65535 -63408 16572 ) ftlattice2 16 0 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 0 0 1 1 - } - { //brush 145 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 146 - ( 1568 65535 65535 ) ( 1568 -65535 65535 ) ( 1568 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 - } - { //brush 147 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 58558 29423 65535 ) ( -58673 -29192 65535 ) ( -58673 -29192 -65535 ) stonesnw 0 0 0 1 1 - ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) stonesnw 0 0 0 1 1 - } - { //brush 148 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) stonesnow 0 0 0 1 1 - ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stonesnow 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 149 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 - } - { //brush 150 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 - } - { //brush 151 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 - } - { //brush 152 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 153 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 0 1 1 - ( -28680 -58929 65535 ) ( 29935 58302 65535 ) ( 29935 58302 -65535 ) stnwll05 0 0 0 1 1 - ( 30780 -57880 65535 ) ( -27836 59352 65535 ) ( -27836 59352 -65535 ) stnwll05 0 0 0 1 1 - ( 59086 65534 -28367 ) ( 59086 -65534 -28367 ) ( -58145 -65534 30248 ) stnfloor02 0 0 0 1 1 - } - { //brush 154 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 30780 -57880 65535 ) ( -27836 59352 65535 ) ( -27836 59352 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 155 - ( 1256 65535 65535 ) ( 1256 -65535 65535 ) ( 1256 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 61626 -22305 ) ( 65535 -61098 23715 ) ( -65535 -61098 23715 ) stnfloor02 0 0 0 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 65535 61358 23021 ) ( 65535 -61366 -23000 ) ( -65535 -61366 -23000 ) stnfloor02 0 0 0 1 1 - } - { //brush 156 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) ctf01 32 0 0 1 1 - ( 1256 -65535 65535 ) ( 1256 65535 65535 ) ( 1256 65535 -65535 ) ctf01 32 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 0 180 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) ctf01 32 0 180 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) ctf01 32 0 90 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 157 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( -28680 -58929 65535 ) ( 29935 58302 65535 ) ( 29935 58302 -65535 ) stnwll05 0 0 0 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 158 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 159 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll01 0 0 0 1 1 - } - { //brush 160 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - ( 16880 65534 63331 ) ( 16880 -65534 63331 ) ( -14908 65534 -63824 ) stnwll01 0 0 0 1 1 - } - { //brush 161 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( -45476 65535 47204 ) ( -45476 -65535 47204 ) ( 47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - ( 16880 -65534 63331 ) ( 16880 65534 63331 ) ( -14908 65534 -63824 ) millgt1 0 0 0 1 0.500000 - } - { //brush 162 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( -45476 65535 47204 ) ( -45476 -65535 47204 ) ( 47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - } - { //brush 163 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 16880 65534 63331 ) ( 16880 -65534 63331 ) ( -14908 65534 -63824 ) stnwll01 0 0 0 1 1 - ( -45476 -65535 47204 ) ( -45476 65535 47204 ) ( 47204 65535 -45476 ) stnwll01 0 0 90 1 1 - } - { //brush 164 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 165 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 166 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 167 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 168 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) shootit 16 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) shootit 16 0 180 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 169 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) shootit 16 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 170 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - } - { //brush 171 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 - } - { //brush 172 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 832 65535 ) ( 65535 832 65535 ) ( -65535 832 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -45524 65535 47156 ) ( -45524 -65535 47156 ) ( 47156 65535 -45524 ) fstng_2 0 16 90 1 1 - } - { //brush 173 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -57896 30748 65535 ) ( 59336 -27868 65535 ) ( -57896 30748 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 174 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 832 65535 ) ( 65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 175 - ( 1136 65535 65535 ) ( 1136 -65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 176 - ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 177 - ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) shootit 16 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 178 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1104 -65535 65535 ) ( 1104 65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 179 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 180 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 181 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 182 - ( 1136 65535 65535 ) ( 1136 -65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 183 - ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) shootit 16 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 184 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1104 -65535 65535 ) ( 1104 65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 185 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 186 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 187 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 188 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 - } - { //brush 189 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 - } - { //brush 190 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 46508 65535 46172 ) ( 46508 -65535 46172 ) ( -46172 65535 -46508 ) stnwll02 0 0 0 1 1 - ( -58699 -29141 65535 ) ( 58533 29474 65535 ) ( -58699 -29141 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 191 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - } - { //brush 192 - ( 1824 65535 65535 ) ( 1824 -65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 193 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 0 1 0.500000 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15231 63743 ) ( 65534 -15231 63743 ) ( -65534 16557 -63412 ) millgt1 0 0 0 1 0.500000 - } - { //brush 194 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 - ( 65534 -15231 63743 ) ( -65534 -15231 63743 ) ( -65534 16557 -63412 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - } - { //brush 195 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 196 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 0 1 0.500000 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15231 63743 ) ( 65534 -15231 63743 ) ( -65534 16557 -63412 ) millgt1 0 0 0 1 0.500000 - } - { //brush 197 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - ( 65534 -15231 63743 ) ( -65534 -15231 63743 ) ( -65534 16557 -63412 ) stnwll02 0 0 0 1 1 - } - { //brush 198 - ( 1184 65535 65535 ) ( 1184 -65535 65535 ) ( 1184 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - } - { //brush 199 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1152 -65535 65535 ) ( 1152 65535 65535 ) ( 1152 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 200 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1184 -65535 65535 ) ( 1184 65535 65535 ) ( 1184 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - } - { //brush 201 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) fstng_2 0 16 0 1 1 - } - { //brush 202 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1184 -65535 65535 ) ( 1184 65535 65535 ) ( 1184 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - ( 58533 29474 65535 ) ( -58699 -29141 65535 ) ( -58699 -29141 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 203 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 704 65535 ) ( 65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 58622 29295 ) ( 65535 -58609 -29320 ) ( -65535 -58609 -29320 ) stnwll05 0 0 90 1 1 - ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 204 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 63830 -14885 65535 ) ( -63326 16903 65535 ) ( -63326 16903 -65535 ) shootit 0 8 0 1 1 - ( 63504 16188 65535 ) ( -63651 -15600 65535 ) ( -63651 -15600 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - } - { //brush 205 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 63512 16158 65535 ) ( -63644 -15631 65535 ) ( -63644 -15631 -65535 ) shootit 0 8 0 1 1 - ( 63838 -14855 65535 ) ( -63318 16933 65535 ) ( -63318 16933 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - } - { //brush 206 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - ( 63845 -14825 65535 ) ( -63310 16963 65535 ) ( -63310 16963 -65535 ) shootit 0 8 0 1 1 - ( 63519 16127 65535 ) ( -63636 -15661 65535 ) ( -63636 -15661 -65535 ) shootit 0 8 0 1 1 - } - { //brush 207 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 63527 16097 65535 ) ( -63629 -15691 65535 ) ( -63629 -15691 -65535 ) shootit 0 8 0 1 1 - ( 63853 -14795 65535 ) ( -63303 16993 65535 ) ( -63303 16993 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - } - { //brush 208 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 63822 -14915 65535 ) ( -63333 16873 65535 ) ( -63333 16873 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 63497 16218 65535 ) ( -63659 -15570 65535 ) ( -63659 -15570 -65535 ) shootit 0 8 0 1 1 - } - { //brush 209 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58385 29768 ) ( 65535 58846 -28847 ) ( -65535 -58385 29768 ) stnwll05 0 0 90 1 1 - } - { //brush 210 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58846 -28847 ) ( 65535 -58385 29768 ) ( -65535 -58385 29768 ) stnfloor02 0 0 0 1 1 - } - { //brush 211 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 688 65535 ) ( -65535 688 65535 ) ( -65535 688 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 212 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stonesnw 0 0 0 1 1 - } - { //brush 213 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - } - { //brush 214 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 90 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll02 0 0 90 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll02 0 0 90 1 1 - } - { //brush 215 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 - } - { //brush 216 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 217 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 218 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 219 - ( 1008 65535 65535 ) ( 1008 -65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 - } - { //brush 220 - ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 221 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 976 -65535 65535 ) ( 976 65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 - } - { //brush 222 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 223 - ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -58952 -28636 65535 ) ( 58280 29980 65535 ) ( -58952 -28636 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 224 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 225 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 46436 65535 46244 ) ( 46436 -65535 46244 ) ( -46244 65535 -46436 ) stnwll01 0 0 90 1 1 - ( -15073 -65534 63783 ) ( -15073 65534 63783 ) ( 16715 65534 -63373 ) stnwll01 0 0 0 1 1 - } - { //brush 226 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) millgt1 0 0 90 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( 46436 -65535 46244 ) ( 46436 65535 46244 ) ( -46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) millgt1 0 0 0 1 0.500000 - } - { //brush 227 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( 46436 -65535 46244 ) ( 46436 65535 46244 ) ( -46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( -15073 65534 63783 ) ( -15073 -65534 63783 ) ( 16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 - } - { //brush 228 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -15073 -65534 63783 ) ( -15073 65534 63783 ) ( 16715 65534 -63373 ) stnwll01 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 229 - ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 230 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 231 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_2 0 0 180 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) fstng_2 0 0 0 1 1 - } - { //brush 232 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - } - { //brush 233 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 234 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64299 12680 65535 ) ( 64525 -11474 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 235 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -65081 -7711 65535 ) ( 64976 8546 65535 ) ( -65081 -7711 -65535 ) mtn 0 0 0 1 1 - ( -64306 12641 65535 ) ( 64518 -11513 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 - ( 64525 -11474 65535 ) ( -64299 12680 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 236 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 64976 8546 65535 ) ( -65081 -7711 65535 ) ( -65081 -7711 -65535 ) mtn 0 0 0 1 1 - ( 64525 -11474 65535 ) ( -64299 12680 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 - ( -64306 12641 65535 ) ( 64518 -11513 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 237 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -58744 -29052 65535 ) ( 58488 29564 65535 ) ( -58744 -29052 -65535 ) mtn 0 0 0 1 1 - ( -63859 14731 65535 ) ( 64088 -13701 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 238 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( 58488 29564 65535 ) ( -58744 -29052 65535 ) ( -58744 -29052 -65535 ) mtn 0 0 0 1 1 - ( 64518 -11513 65535 ) ( -64306 12641 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 - ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 239 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15329 63719 ) ( 65534 -15329 63719 ) ( -65534 16459 -63437 ) mtn 0 0 0 1 1 - ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - } - { //brush 240 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - } - { //brush 241 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -7581 65097 ) ( 65534 -7581 65097 ) ( -65534 8676 -64960 ) mtn 0 0 0 1 1 - ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 65271 -14499 64180 ) ( -54501 38733 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - } - { //brush 242 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65534 -15314 63723 ) ( -65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( -59675 27091 65535 ) ( 60097 -26141 65535 ) ( -59675 27091 -65535 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - } - { //brush 243 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 244 - ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 - ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65534 29461 58539 ) ( 65534 29461 58539 ) ( -65534 -29154 -58693 ) mtn 0 0 0 1 1 - ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 - } - { //brush 245 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -63219 -26421 62412 ) ( 67199 -13380 62412 ) ( -67325 14635 -61993 ) mtn 0 0 0 1 1 - ( -67199 -13380 62412 ) ( 63219 -26421 62412 ) ( -63094 27677 -61993 ) mtn 0 0 0 1 1 - ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 - ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 - ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 246 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -59675 27091 65535 ) ( 60097 -26141 65535 ) ( -59675 27091 -65535 ) mtn 0 0 0 1 1 - } - { //brush 247 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 248 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -58488 29564 65535 ) ( 58744 -29052 65535 ) ( -58488 29564 -65535 ) mtn 0 0 0 1 1 - ( -64088 -13701 65535 ) ( 63859 14731 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - } - { //brush 249 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 64306 12641 65535 ) ( -64518 -11513 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 58744 -29052 65535 ) ( -58488 29564 65535 ) ( -58488 29564 -65535 ) mtn 0 0 0 1 1 - } - { //brush 250 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( 63859 14731 65535 ) ( -64088 -13701 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 - ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - } - { //brush 251 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -7581 65097 ) ( 65534 -7581 65097 ) ( -65534 8676 -64960 ) mtn 0 0 0 1 1 - ( 63859 14731 65535 ) ( -64088 -13701 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 - ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 54501 38733 64180 ) ( -65271 -14499 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 252 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -60097 -26141 65535 ) ( 59675 27091 65535 ) ( -60097 -26141 -65535 ) mtn 0 0 0 1 1 - ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( 65534 -15314 63723 ) ( -65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - } - { //brush 253 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -60097 -26141 65535 ) ( 59675 27091 65535 ) ( -60097 -26141 -65535 ) mtn 0 0 0 1 1 - } - { //brush 254 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -50409 45720 62915 ) ( 66822 -12895 62915 ) ( -66454 13631 -63149 ) mtn 0 0 0 1 1 - ( -66510 3720 64438 ) ( 63547 19978 64438 ) ( -63623 -19370 -64549 ) mtn 0 0 0 1 1 - ( -63536 20069 64421 ) ( 66521 3812 64421 ) ( -66422 -3021 -64565 ) mtn 0 0 0 1 1 - } - { //brush 255 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -50015 46510 62651 ) ( 67217 -12106 62651 ) ( -66762 13015 -62954 ) mtn 0 0 0 1 1 - ( 63547 19978 64438 ) ( -66510 3720 64438 ) ( -63623 -19370 -64549 ) mtn 0 0 0 1 1 - ( -66017 5667 64802 ) ( 64797 13842 64802 ) ( -64839 -13174 -64900 ) mtn 0 0 0 1 1 - ( -66636 -8945 63790 ) ( 56087 37076 63790 ) ( -56147 -36916 -63830 ) mtn 0 0 0 1 1 - } - { //brush 256 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 257 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) shootit 16 0 180 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 258 - ( 784 65535 65535 ) ( 784 -65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 259 - ( 496 65535 65535 ) ( 496 -65535 65535 ) ( 496 65535 -65535 ) tile2492 0 0 0 1 1 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 260 - ( 432 65535 65535 ) ( 432 -65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 0 1 1 - ( 464 -65535 65535 ) ( 464 65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 261 - ( 144 65535 65535 ) ( 144 -65535 65535 ) ( 144 65535 -65535 ) tile2492 0 0 0 1 1 - ( 400 -65535 65535 ) ( 400 65535 65535 ) ( 400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 262 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 263 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_0 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) fstng_0 0 0 0 1 1 - } - { //brush 264 - ( 784 65535 65535 ) ( 784 -65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 265 - ( 464 65535 65535 ) ( 464 -65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 180 1 1 - ( 784 -65535 65535 ) ( 784 65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 266 - ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) shootit 16 0 180 1 1 - ( 784 -65535 65535 ) ( 784 65535 65535 ) ( 784 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 267 - ( 496 65535 65535 ) ( 496 -65535 65535 ) ( 496 65535 -65535 ) tile2492 0 0 0 1 1 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 268 - ( 464 65535 65535 ) ( 464 -65535 65535 ) ( 464 65535 -65535 ) shootit 16 0 180 1 1 - ( 496 -65535 65535 ) ( 496 65535 65535 ) ( 496 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 269 - ( 432 65535 65535 ) ( 432 -65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 0 1 1 - ( 464 -65535 65535 ) ( 464 65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 270 - ( 400 65535 65535 ) ( 400 -65535 65535 ) ( 400 65535 -65535 ) shootit 16 0 180 1 1 - ( 432 -65535 65535 ) ( 432 65535 65535 ) ( 432 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 271 - ( 144 65535 65535 ) ( 144 -65535 65535 ) ( 144 65535 -65535 ) tile2492 0 0 0 1 1 - ( 400 -65535 65535 ) ( 400 65535 65535 ) ( 400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 272 - ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) shootit 16 0 180 1 1 - ( 144 -65535 65535 ) ( 144 65535 65535 ) ( 144 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 273 - ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 180 1 1 - ( 432 -65535 65535 ) ( 432 65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 274 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 275 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 276 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 277 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -58408 29724 65535 ) ( 58824 -28892 65535 ) ( -58408 29724 -65535 ) tile2492 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 278 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 279 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( -51172 44196 63387 ) ( 66060 -14420 63387 ) ( -65685 15170 -63601 ) mtn 0 0 0 1 1 - ( -58401 29736 65535 ) ( 58830 -28879 65535 ) ( -58401 29736 -65535 ) mtn 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 280 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - } - { //brush 281 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 282 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 283 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) fstng_0 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) fstng_0 0 0 0 1 1 - } - { //brush 284 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) shootit 16 16 180 1 1 - ( -65535 1040 65535 ) ( 65535 1040 65535 ) ( -65535 1040 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1072 65535 ) ( -65535 1072 65535 ) ( -65535 1072 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 16 0 1 1 - ( 58504 -65534 29532 ) ( 58504 65534 29532 ) ( -58728 -65534 -29084 ) shootit 16 16 0 1 1 - } - { //brush 285 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 286 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 - } - { //brush 287 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 65535 -63481 16282 ) ( 65535 63675 -15506 ) ( -65535 -63481 16282 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - ( 65535 -63577 -15898 ) ( 65535 63579 15890 ) ( -65535 -63577 -15898 ) shootit 16 16 0 1 1 - } - { //brush 288 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - ( 65535 -63496 16222 ) ( 65535 63660 -15567 ) ( -65535 -63496 16222 ) shootit 16 16 0 1 1 - ( 65535 -63592 -15838 ) ( 65535 63564 15951 ) ( -65535 -63592 -15838 ) shootit 16 16 0 1 1 - } - { //brush 289 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 - } - { //brush 290 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 291 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( -58824 -28892 65535 ) ( 58408 29724 65535 ) ( -58824 -28892 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 292 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 293 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( -58830 -28879 65535 ) ( 58401 29736 65535 ) ( -58830 -28879 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -66060 -14420 63387 ) ( 51172 44196 63387 ) ( -51547 -43446 -63601 ) mtn 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) mtn 0 0 0 1 1 - } - { //brush 294 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 295 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 296 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64525 -11474 65535 ) ( 64299 12680 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) mtn 0 0 0 1 1 - } - { //brush 297 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 298 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( 65534 16203 63501 ) ( -65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 299 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64976 8546 65535 ) ( 65081 -7711 65535 ) ( -64976 8546 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( 65535 14338 63948 ) ( -65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - } - { //brush 300 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -66822 -12895 62915 ) ( 50409 45720 62915 ) ( -50778 -44984 -63149 ) mtn 0 0 0 1 1 - ( -66521 3812 64421 ) ( 63536 20069 64421 ) ( -63635 -19279 -64565 ) mtn 0 0 0 1 1 - ( -63547 19978 64438 ) ( 66510 3720 64438 ) ( -66434 -3113 -64549 ) mtn 0 0 0 1 1 - } - { //brush 301 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 66510 3720 64438 ) ( -63547 19978 64438 ) ( -66434 -3113 -64549 ) mtn 0 0 0 1 1 - ( -56087 37076 63790 ) ( 66636 -8945 63790 ) ( -66577 9104 -63830 ) mtn 0 0 0 1 1 - ( -64797 13842 64802 ) ( 66017 5667 64802 ) ( -65975 -4998 -64900 ) mtn 0 0 0 1 1 - ( -67217 -12106 62651 ) ( 50015 46510 62651 ) ( -50469 -45601 -62954 ) mtn 0 0 0 1 1 - } - { //brush 302 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 303 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 304 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) millgt1 0 0 0 1 0.500000 - } - { //brush 305 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65534 15887 63580 ) ( 65534 15887 63580 ) ( -65534 -15902 -63576 ) stnwll02 0 0 0 1 1 - ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) stnwll02 0 0 0 1 1 - } - { //brush 306 - ( 1920 65535 65535 ) ( 1920 -65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 307 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 308 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 0 0 0 1 0.500000 - } - { //brush 309 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1888 -65535 65535 ) ( 1888 65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 310 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 311 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 - } - { //brush 312 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 - ( 47116 65535 45564 ) ( 47116 -65535 45564 ) ( -45564 65535 -47116 ) fstng_2 0 16 0 1 1 - } - { //brush 313 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 90 1 1 - ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 90 1 1 - ( 47116 -65535 45564 ) ( 47116 65535 45564 ) ( -45564 65535 -47116 ) fstng_2 0 16 90 1 1 - } - { //brush 314 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 - ( 47172 -65535 45508 ) ( 47172 65535 45508 ) ( -45508 65535 -47172 ) millgt1 16 0 90 1 0.500000 - } - { //brush 315 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 316 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 317 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 318 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 0 0 1 0.500000 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15887 63580 ) ( 65534 -15887 63580 ) ( -65534 15902 -63576 ) millgt1 0 0 0 1 0.500000 - } - { //brush 319 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65534 -15887 63580 ) ( -65534 -15887 63580 ) ( -65534 15902 -63576 ) stnwll02 0 0 0 1 1 - } - { //brush 320 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 321 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 322 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 323 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - } - { //brush 324 - ( 2224 65535 65535 ) ( 2224 -65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll01 0 0 90 1 1 - } - { //brush 325 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( -65534 15333 63718 ) ( 65534 15333 63718 ) ( -65534 -16455 -63438 ) stnwll01 0 0 0 1 1 - } - { //brush 326 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 16 0 0 1 0.500000 - ( 65534 15333 63718 ) ( -65534 15333 63718 ) ( -65534 -16455 -63438 ) millgt1 16 0 0 1 0.500000 - } - { //brush 327 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( -65534 15333 63718 ) ( 65534 15333 63718 ) ( -65534 -16455 -63438 ) stnwll01 0 0 0 1 1 - } - { //brush 328 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 16 0 0 1 0.500000 - ( 65534 15333 63718 ) ( -65534 15333 63718 ) ( -65534 -16455 -63438 ) millgt1 16 0 0 1 0.500000 - } - { //brush 329 - ( 1920 65535 65535 ) ( 1920 -65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 330 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 331 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 332 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1888 -65535 65535 ) ( 1888 65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 333 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 334 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 335 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 336 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_0 0 0 0 1 1 - } - { //brush 337 - ( 960 65535 65535 ) ( 960 -65535 65535 ) ( 960 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - } - { //brush 338 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63731 -15280 ) ( 65535 63424 16508 ) ( -65535 -63731 -15280 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63439 16447 ) ( 65535 63716 -15341 ) ( -65535 -63439 16447 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - } - { //brush 339 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63716 -15341 ) ( 65535 63439 16447 ) ( -65535 -63716 -15341 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - ( 65535 -63424 16508 ) ( 65535 63731 -15280 ) ( -65535 -63424 16508 ) ftlattice2 16 16 0 1 1 - } - { //brush 340 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 341 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 342 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 343 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 688 ) ( 65535 65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 344 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 345 - ( 872 65535 65535 ) ( 872 -65535 65535 ) ( 872 65535 -65535 ) ctf07 32 48 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) ctf07 32 48 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) ctf07 32 48 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) ctf07 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf07 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf07 32 48 90 1 1 - } - { //brush 346 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - } - { //brush 347 - ( 872 65535 65535 ) ( 872 -65535 65535 ) ( 872 65535 -65535 ) ctf07 32 48 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) ctf07 32 48 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf07 32 48 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) ctf07 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf07 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf07 32 48 90 1 1 - } - { //brush 348 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 59032 -65534 -28476 ) ( 59032 65534 -28476 ) ( -58200 -65534 30140 ) fstng_2 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 349 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 59032 -65534 -28476 ) ( 59032 65534 -28476 ) ( -58200 -65534 30140 ) fstng_2 0 0 0 1 1 - } - { //brush 350 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 351 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 352 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 65535 -63747 -15216 ) ( 65535 63408 16572 ) ( -65535 -63747 -15216 ) ftlattice2 16 0 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 0 0 1 1 - ( 65535 -63455 16383 ) ( 65535 63700 -15405 ) ( -65535 -63455 16383 ) ftlattice2 16 0 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 0 0 1 1 - } - { //brush 353 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 354 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 355 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 356 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 357 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62109 -20911 65535 ) ( -62234 20536 65535 ) ( -62234 20536 -65535 ) mtn 0 0 0 1 1 - } - { //brush 358 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 62109 -20911 65535 ) ( -62234 20536 65535 ) ( -62234 20536 -65535 ) mtn 0 0 0 1 1 - } - { //brush 359 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_0 0 0 0 1 1 - } - { //brush 360 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_2 0 16 180 1 1 - } - { //brush 361 - ( 1712 65535 65535 ) ( 1712 -65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 362 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 363 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 364 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1680 -65535 65535 ) ( 1680 65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 365 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 366 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 0 0 0 1 0.500000 - } - { //brush 367 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 368 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -45284 65535 47396 ) ( -45284 -65535 47396 ) ( 47396 65535 -45284 ) fstng_2 0 0 90 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 369 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 1 - ( 63767 -65534 -15137 ) ( 63767 65534 -15137 ) ( -63389 -65534 16651 ) millgt1 16 0 0 1 1 - ( 63588 -65534 15853 ) ( 63588 65534 15853 ) ( -63567 -65534 -15935 ) millgt1 16 0 0 1 1 - ( 65535 -63501 16203 ) ( 65535 63655 -15585 ) ( -65535 -63501 16203 ) millgt1 16 0 0 1 1 - ( 65535 -63679 -15487 ) ( 65535 63476 16301 ) ( -65535 -63679 -15487 ) millgt1 16 0 0 1 1 - } - { //brush 370 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 46980 -65535 45700 ) ( 46980 65535 45700 ) ( -45700 65535 -46980 ) fstng_2 0 0 90 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 371 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll05 0 0 90 1 1 - } - { //brush 372 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 373 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 90 1 1 - } - { //brush 374 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46196 46484 ) ( 65535 -46196 46484 ) ( -65535 46484 -46196 ) millgt1 16 0 0 1 0.500000 - } - { //brush 375 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -352 65535 ) ( 65535 -352 65535 ) ( -65535 -352 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 376 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -384 65535 ) ( 65535 -384 65535 ) ( -65535 -384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -352 65535 ) ( -65535 -352 65535 ) ( -65535 -352 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 377 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -416 65535 ) ( 65535 -416 65535 ) ( -65535 -416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -384 65535 ) ( -65535 -384 65535 ) ( -65535 -384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - } - { //brush 378 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -416 65535 ) ( -65535 -416 65535 ) ( -65535 -416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 379 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 380 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 381 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 0 1 1 - ( -65534 15352 63713 ) ( 65534 15352 63713 ) ( -65534 -16436 -63442 ) stnwll02 0 0 0 1 1 - ( 65535 -46268 46412 ) ( -65535 -46268 46412 ) ( -65535 46412 -46268 ) stnwll02 0 0 0 1 1 - } - { //brush 382 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 383 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 384 - ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -28168 59185 65535 ) ( 30447 -58046 65535 ) ( -28168 59185 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 385 - ( 1280 65535 65535 ) ( 1280 -65535 65535 ) ( 1280 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 386 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( -65534 15352 63713 ) ( 65534 15352 63713 ) ( -65534 -16436 -63442 ) stnwll02 0 0 0 1 1 - ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 387 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( 65534 15352 63713 ) ( -65534 15352 63713 ) ( -65534 -16436 -63442 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 388 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 389 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll05 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - ( 28937 -58807 65535 ) ( -27299 59585 65535 ) ( -27299 59585 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 390 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 391 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 30114 58213 65535 ) ( -28501 -59019 65535 ) ( 30114 58213 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 392 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -28501 -59019 65535 ) ( 30114 58213 65535 ) ( 30114 58213 -65535 ) stnwll05 0 0 0 1 1 - ( 30088 -58225 65535 ) ( -28527 59006 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 393 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - ( -28501 -59019 65535 ) ( 30114 58213 65535 ) ( 30114 58213 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 394 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - ( 58606 65534 29327 ) ( 58606 -65534 29327 ) ( -58625 -65534 -29288 ) stnfloor02 0 0 0 1 1 - ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 395 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 30447 -58046 65535 ) ( -28168 59185 65535 ) ( -28168 59185 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) fstng_2 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 396 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - ( 30248 -58145 65535 ) ( -28367 59086 65535 ) ( -28367 59086 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 397 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) millgt1 16 0 90 1 0.500000 - ( 46700 -65535 45980 ) ( 46700 65535 45980 ) ( -45980 65535 -46700 ) millgt1 16 0 90 1 0.500000 - ( -14746 65534 63865 ) ( -14746 -65534 63865 ) ( 17042 65534 -63291 ) millgt1 16 0 0 1 0.500000 - } - { //brush 398 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - } - { //brush 399 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 400 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) fstng_2 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 401 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 402 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - ( -65535 45972 46708 ) ( 65535 45972 46708 ) ( -65535 -46708 -45972 ) stnwll05 0 0 0 1 1 - } - { //brush 403 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - } - { //brush 404 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - } - { //brush 405 - ( 1008 65535 65535 ) ( 1008 -65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 406 - ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16116 63522 ) ( 65534 -16116 63522 ) ( -65534 15672 -63633 ) millgt1 16 0 0 1 0.500000 - } - { //brush 407 - ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 408 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 976 -65535 65535 ) ( 976 65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 409 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 410 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 411 - ( 1600 65535 65535 ) ( 1600 -65535 65535 ) ( 1600 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 412 - ( 1568 65535 65535 ) ( 1568 -65535 65535 ) ( 1568 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1600 -65535 65535 ) ( 1600 65535 65535 ) ( 1600 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 413 - ( 1536 65535 65535 ) ( 1536 -65535 65535 ) ( 1536 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 414 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1536 -65535 65535 ) ( 1536 65535 65535 ) ( 1536 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 415 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 416 - ( 1440 65535 65535 ) ( 1440 -65535 65535 ) ( 1440 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 417 - ( 1408 65535 65535 ) ( 1408 -65535 65535 ) ( 1408 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1440 -65535 65535 ) ( 1440 65535 65535 ) ( 1440 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - } - { //brush 418 - ( 1376 65535 65535 ) ( 1376 -65535 65535 ) ( 1376 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1408 -65535 65535 ) ( 1408 65535 65535 ) ( 1408 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - } - { //brush 419 - ( 1344 65535 65535 ) ( 1344 -65535 65535 ) ( 1344 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1376 -65535 65535 ) ( 1376 65535 65535 ) ( 1376 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - } - { //brush 420 - ( 1312 65535 65535 ) ( 1312 -65535 65535 ) ( 1312 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1344 -65535 65535 ) ( 1344 65535 65535 ) ( 1344 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 421 - ( 1280 65535 65535 ) ( 1280 -65535 65535 ) ( 1280 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1312 -65535 65535 ) ( 1312 65535 65535 ) ( 1312 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - } - { //brush 422 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 423 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 424 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 425 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52679 65535 -38985 ) ( 52679 -65535 -38985 ) ( -52176 -65535 39656 ) stonesnow 0 0 0 1 1 - } - { //brush 426 - ( -240 65535 65535 ) ( -240 -65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 180 1 1 - ( 240 -65535 65535 ) ( 240 65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) stonesnow 0 0 0 1 1 - ( 65534 -29084 58728 ) ( -65534 -29084 58728 ) ( -65534 29532 -58504 ) tile2492 0 0 0 1 1 - } - { //brush 427 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52176 65535 39656 ) ( 52176 -65535 39656 ) ( -52679 -65535 -38985 ) stonesnow 0 0 0 1 1 - } - { //brush 428 - ( 280 65535 65535 ) ( 280 -65535 65535 ) ( 280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 429 - ( 276 65535 65535 ) ( 276 -65535 65535 ) ( 276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 430 - ( 272 65535 65535 ) ( 272 -65535 65535 ) ( 272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 431 - ( 268 65535 65535 ) ( 268 -65535 65535 ) ( 268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 432 - ( 264 65535 65535 ) ( 264 -65535 65535 ) ( 264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 433 - ( 260 65535 65535 ) ( 260 -65535 65535 ) ( 260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 434 - ( 256 65535 65535 ) ( 256 -65535 65535 ) ( 256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 435 - ( 252 65535 65535 ) ( 252 -65535 65535 ) ( 252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 436 - ( 248 65535 65535 ) ( 248 -65535 65535 ) ( 248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 437 - ( 244 65535 65535 ) ( 244 -65535 65535 ) ( 244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 438 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 439 - ( 236 65535 65535 ) ( 236 -65535 65535 ) ( 236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 440 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 441 - ( -276 -65535 65535 ) ( -276 65535 65535 ) ( -276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 442 - ( -272 -65535 65535 ) ( -272 65535 65535 ) ( -272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 443 - ( -268 -65535 65535 ) ( -268 65535 65535 ) ( -268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 444 - ( -264 -65535 65535 ) ( -264 65535 65535 ) ( -264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 445 - ( -260 -65535 65535 ) ( -260 65535 65535 ) ( -260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 446 - ( -256 -65535 65535 ) ( -256 65535 65535 ) ( -256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 447 - ( -252 -65535 65535 ) ( -252 65535 65535 ) ( -252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 448 - ( -248 -65535 65535 ) ( -248 65535 65535 ) ( -248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 449 - ( -244 -65535 65535 ) ( -244 65535 65535 ) ( -244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 450 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 451 - ( -236 -65535 65535 ) ( -236 65535 65535 ) ( -236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 452 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 453 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 0 1 1 - } - { //brush 454 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 455 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 456 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 0 16 0 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 0 16 0 1 1 - ( 63646 -65534 -15623 ) ( 63646 65534 -15623 ) ( -63510 -65534 16165 ) shootit 0 16 0 1 1 - ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 0 16 0 1 1 - ( 63534 -65534 16067 ) ( 63534 65534 16067 ) ( -63621 -65534 -15721 ) shootit 0 16 0 1 1 - } - { //brush 457 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 16 16 0 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 16 16 0 1 1 - ( 63522 -65534 16116 ) ( 63522 65534 16116 ) ( -63633 -65534 -15672 ) shootit 16 16 0 1 1 - ( 63633 -65534 -15672 ) ( 63633 65534 -15672 ) ( -63522 -65534 16116 ) shootit 16 16 0 1 1 - ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 16 16 0 1 1 - } - { //brush 458 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 0 16 0 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 0 16 0 1 1 - ( 63621 -65534 -15721 ) ( 63621 65534 -15721 ) ( -63534 -65534 16067 ) shootit 0 16 0 1 1 - ( 63510 -65534 16165 ) ( 63510 65534 16165 ) ( -63646 -65534 -15623 ) shootit 0 16 0 1 1 - ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 0 16 0 1 1 - } - { //brush 459 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 - } - { //brush 460 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58750 -65534 -29039 ) ( 58750 65534 -29039 ) ( -58481 -65534 29576 ) fstng_0 0 0 0 1 1 - } - { //brush 461 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58565 -65534 29410 ) ( 58565 65534 29410 ) ( -58667 -65534 -29205 ) fstng_0 0 0 0 1 1 - } - { //brush 462 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 90 1 1 - } - { //brush 463 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 464 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 465 - ( 120 65535 65535 ) ( 120 -65535 65535 ) ( 120 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 76 ) ( 65535 65535 76 ) ( -65535 -65535 76 ) fstng_0 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 466 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 76 ) ( 65535 -65535 76 ) ( -65535 -65535 76 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 467 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 - ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 - } - { //brush 468 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58523 -65534 29493 ) ( 58523 65534 29493 ) ( -58709 -65534 -29122 ) fstng_0 0 0 0 1 1 - } - { //brush 469 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58709 -65534 -29122 ) ( 58709 65534 -29122 ) ( -58523 -65534 29493 ) fstng_0 0 0 0 1 1 - } - { //brush 470 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 90 1 1 - } - { //brush 471 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 - } - { //brush 472 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58667 -65534 -29205 ) ( 58667 65534 -29205 ) ( -58565 -65534 29410 ) fstng_0 0 0 0 1 1 - } - { //brush 473 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58481 -65534 29576 ) ( 58481 65534 29576 ) ( -58750 -65534 -29039 ) fstng_0 0 0 0 1 1 - } - { //brush 474 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 180 1 1 - } - { //brush 475 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 476 - ( -120 -65535 65535 ) ( -120 65535 65535 ) ( -120 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 76 ) ( 65535 65535 76 ) ( -65535 -65535 76 ) fstng_0 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 477 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 76 ) ( 65535 -65535 76 ) ( -65535 -65535 76 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 478 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 479 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 480 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 481 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52679 65535 -38985 ) ( 52679 -65535 -38985 ) ( -52176 -65535 39656 ) stonesnow 0 0 0 1 1 - } - { //brush 482 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 67217 12106 62651 ) ( -50015 -46510 62651 ) ( -66762 -13015 -62954 ) mtn 0 0 0 1 1 - ( 64797 -13842 64802 ) ( -66017 -5667 64802 ) ( -64839 13174 -64900 ) mtn 0 0 0 1 1 - ( -66510 -3720 64438 ) ( 63547 -19978 64438 ) ( -63623 19370 -64549 ) mtn 0 0 0 1 1 - ( 56087 -37076 63790 ) ( -66636 8945 63790 ) ( -56147 36916 -63830 ) mtn 0 0 0 1 1 - } - { //brush 483 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 63547 -19978 64438 ) ( -66510 -3720 64438 ) ( -63623 19370 -64549 ) mtn 0 0 0 1 1 - ( 66822 12895 62915 ) ( -50409 -45720 62915 ) ( -66454 -13631 -63149 ) mtn 0 0 0 1 1 - ( 66521 -3812 64421 ) ( -63536 -20069 64421 ) ( -66422 3021 -64565 ) mtn 0 0 0 1 1 - } - { //brush 484 - ( -240 65535 65535 ) ( -240 -65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 180 1 1 - ( 240 -65535 65535 ) ( 240 65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) stonesnow 0 0 0 1 1 - ( -65534 29084 58728 ) ( 65534 29084 58728 ) ( -65534 -29532 -58504 ) tile2492 0 0 0 1 1 - } - { //brush 485 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 60097 26141 65535 ) ( -59675 -27091 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 - ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 486 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -64306 -12641 65535 ) ( 64518 11513 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - } - { //brush 487 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -65081 7711 65535 ) ( 64976 -8546 65535 ) ( -65081 7711 -65535 ) mtn 0 0 0 1 1 - ( -64299 -12680 65535 ) ( 64525 11474 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 - ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 488 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64976 -8546 65535 ) ( -65081 7711 65535 ) ( -65081 7711 -65535 ) mtn 0 0 0 1 1 - ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -64299 -12680 65535 ) ( 64525 11474 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 489 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( -65534 15314 63723 ) ( 65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -59675 -27091 65535 ) ( 60097 26141 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 - ( 65534 15329 63719 ) ( -65534 15329 63719 ) ( -65534 -16459 -63437 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 490 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( -65534 15314 63723 ) ( 65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 60097 26141 65535 ) ( -59675 -27091 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 - } - { //brush 491 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( -58795 28949 65535 ) ( 58437 -29666 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -54501 -38733 64180 ) ( 65271 14499 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 492 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -54501 -38733 64180 ) ( 65271 14499 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - } - { //brush 493 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 494 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64088 13701 65535 ) ( -63859 -14731 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - } - { //brush 495 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64525 11474 65535 ) ( -64299 -12680 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 496 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 497 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52176 65535 39656 ) ( 52176 -65535 39656 ) ( -52679 -65535 -38985 ) stonesnow 0 0 0 1 1 - } - { //brush 498 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 499 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58565 -65534 29410 ) ( 58565 65534 29410 ) ( -58667 -65534 -29205 ) fstng_0 0 0 0 1 1 - } - { //brush 500 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) tile2492 0 0 90 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 501 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58750 -65534 -29039 ) ( 58750 65534 -29039 ) ( -58481 -65534 29576 ) fstng_0 0 0 0 1 1 - } - { //brush 502 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( 65534 -29320 58609 ) ( -65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 180 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 503 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 504 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 505 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 - } - { //brush 506 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58523 -65534 29493 ) ( 58523 65534 29493 ) ( -58709 -65534 -29122 ) fstng_0 0 0 0 1 1 - } - { //brush 507 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58709 -65534 -29122 ) ( 58709 65534 -29122 ) ( -58523 -65534 29493 ) fstng_0 0 0 0 1 1 - } - { //brush 508 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 509 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 510 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58667 -65534 -29205 ) ( 58667 65534 -29205 ) ( -58565 -65534 29410 ) fstng_0 0 0 0 1 1 - } - { //brush 511 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58481 -65534 29576 ) ( 58481 65534 29576 ) ( -58750 -65534 -29039 ) fstng_0 0 0 0 1 1 - } - { //brush 512 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 513 - ( 280 65535 65535 ) ( 280 -65535 65535 ) ( 280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 514 - ( 276 65535 65535 ) ( 276 -65535 65535 ) ( 276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 515 - ( 272 65535 65535 ) ( 272 -65535 65535 ) ( 272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 516 - ( 268 65535 65535 ) ( 268 -65535 65535 ) ( 268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 517 - ( 264 65535 65535 ) ( 264 -65535 65535 ) ( 264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 518 - ( 260 65535 65535 ) ( 260 -65535 65535 ) ( 260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 519 - ( 256 65535 65535 ) ( 256 -65535 65535 ) ( 256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 520 - ( 252 65535 65535 ) ( 252 -65535 65535 ) ( 252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 521 - ( 248 65535 65535 ) ( 248 -65535 65535 ) ( 248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 522 - ( 244 65535 65535 ) ( 244 -65535 65535 ) ( 244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 523 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 524 - ( 236 65535 65535 ) ( 236 -65535 65535 ) ( 236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 525 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 0 1 1 - } - { //brush 526 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 527 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 58824 28892 65535 ) ( -58408 -29724 65535 ) ( -58408 -29724 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 528 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 529 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( 66060 14420 63387 ) ( -51172 -44196 63387 ) ( -65685 -15170 -63601 ) mtn 0 0 0 1 1 - ( 58830 28879 65535 ) ( -58401 -29736 65535 ) ( -58401 -29736 -65535 ) mtn 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 530 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 531 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 532 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 533 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 534 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 535 - ( -276 -65535 65535 ) ( -276 65535 65535 ) ( -276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 536 - ( -272 -65535 65535 ) ( -272 65535 65535 ) ( -272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 537 - ( -268 -65535 65535 ) ( -268 65535 65535 ) ( -268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 538 - ( -264 -65535 65535 ) ( -264 65535 65535 ) ( -264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 539 - ( -260 -65535 65535 ) ( -260 65535 65535 ) ( -260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 540 - ( -256 -65535 65535 ) ( -256 65535 65535 ) ( -256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 541 - ( -252 -65535 65535 ) ( -252 65535 65535 ) ( -252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 542 - ( -248 -65535 65535 ) ( -248 65535 65535 ) ( -248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 543 - ( -244 -65535 65535 ) ( -244 65535 65535 ) ( -244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 544 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 545 - ( -236 -65535 65535 ) ( -236 65535 65535 ) ( -236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 546 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -58824 28892 65535 ) ( 58408 -29724 65535 ) ( -58824 28892 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 547 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - ( 58408 -29724 65535 ) ( -58824 28892 65535 ) ( -58824 28892 -65535 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 548 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 549 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 550 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( 58401 -29736 65535 ) ( -58830 28879 65535 ) ( -58830 28879 -65535 ) mtn 0 0 0 1 1 - ( 51172 -44196 63387 ) ( -66060 14420 63387 ) ( -51547 43446 -63601 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 551 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 180 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 552 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) stonesnow 0 0 180 1 1 - } - { //brush 553 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 554 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 555 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -65534 -16203 63501 ) ( 65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - } - { //brush 556 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 557 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64088 13701 65535 ) ( -63859 -14731 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -58795 28949 65535 ) ( 58437 -29666 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 558 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( 63219 26421 62412 ) ( -67199 13380 62412 ) ( -63094 -27677 -61993 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - } - { //brush 559 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -65271 14499 64180 ) ( 54501 -38733 64180 ) ( -54837 37977 -64346 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 - } - { //brush 560 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( 54501 -38733 64180 ) ( -65271 14499 64180 ) ( -54837 37977 -64346 ) mtn 0 0 0 1 1 - } - { //brush 561 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) stonesnow 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) stonesnow 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 562 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 563 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65534 -16350 63464 ) ( -65534 -16350 63464 ) ( -65534 15439 -63692 ) stnwll02 0 0 0 1 1 - } - { //brush 564 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 45828 46852 ) ( -65535 45828 46852 ) ( -65535 -46852 -45828 ) millgt1 16 0 0 1 0.500000 - } - { //brush 565 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1680 -65535 65535 ) ( 1680 65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 566 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 567 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 568 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 569 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( -58488 -29564 65535 ) ( 58744 29052 65535 ) ( -58488 -29564 -65535 ) mtn 0 0 0 1 1 - ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 570 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 58744 29052 65535 ) ( -58488 -29564 65535 ) ( -58488 -29564 -65535 ) mtn 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 571 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) stonesnow 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) stonesnow 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 572 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( 64306 -12641 65535 ) ( -64518 11513 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( -64976 -8546 65535 ) ( 65081 7711 65535 ) ( -64976 -8546 -65535 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - } - { //brush 573 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 574 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) ftlattice2 16 16 0 1 1 - ( 65535 -63726 -15303 ) ( 65535 63430 16485 ) ( -65535 -63726 -15303 ) ftlattice2 16 16 0 1 1 - ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 16 0 1 1 - ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 16 0 1 1 - } - { //brush 575 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 - } - { //brush 576 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 577 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 578 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( -27688 59425 65535 ) ( 30927 -57806 65535 ) ( -27688 59425 -65535 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 579 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 580 - ( 1872 65535 65535 ) ( 1872 -65535 65535 ) ( 1872 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 672 ) ( 65535 -65535 672 ) ( -65535 -65535 672 ) fstng_2 0 0 0 1 1 - ( -65535 -46316 46364 ) ( 65535 -46316 46364 ) ( -65535 46364 -46316 ) fstng_2 0 0 0 1 1 - } - { //brush 581 - ( 1808 65535 65535 ) ( 1808 -65535 65535 ) ( 1808 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1872 -65535 65535 ) ( 1872 65535 65535 ) ( 1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 582 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - } - { //brush 583 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 0 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 0 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 0 16 0 1 1 - ( 63512 -65534 16158 ) ( 63512 65534 16158 ) ( -63644 -65534 -15631 ) ftlattice2 0 16 0 1 1 - ( 63804 -65534 -14991 ) ( 63804 65534 -14991 ) ( -63352 -65534 16798 ) ftlattice2 0 16 0 1 1 - } - { //brush 584 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 - ( 63823 -65534 -14911 ) ( 63823 65534 -14911 ) ( -63332 -65534 16877 ) ftlattice2 16 16 0 1 1 - ( 63532 -65534 16079 ) ( 63532 65534 16079 ) ( -63624 -65534 -15710 ) ftlattice2 16 16 0 1 1 - } - { //brush 585 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) tile2492 0 0 90 1 1 - } - { //brush 586 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 66017 -5667 64802 ) ( -64797 -13842 64802 ) ( -65975 4998 -64900 ) mtn 0 0 0 1 1 - ( 66636 8945 63790 ) ( -56087 -37076 63790 ) ( -66577 -9104 -63830 ) mtn 0 0 0 1 1 - ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - } - { //brush 587 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 588 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 - ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) tile2492 0 0 180 1 1 - } - { //brush 589 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 590 - ( 1872 -65535 65535 ) ( 1872 65535 65535 ) ( 1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 591 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 592 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 16 0 1 1 - ( 46508 65535 46172 ) ( 46508 -65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 0 1 1 - ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 593 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 180 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 16 90 1 1 - } - { //brush 594 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 90 1 1 - } - { //brush 595 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) fstng_2 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 596 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) tile2492 0 0 90 1 1 - ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 597 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_0 0 0 0 1 1 - ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 598 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 65535 -63579 15890 ) ( 65535 63577 -15898 ) ( -65535 -63579 15890 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 65535 -63675 -15506 ) ( 65535 63481 16282 ) ( -65535 -63675 -15506 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - } - { //brush 599 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) tile2492 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 600 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 45644 47036 ) ( -65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 601 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 65535 45644 47036 ) ( -65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 602 - ( 2224 65535 65535 ) ( 2224 -65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 - } - { //brush 603 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( 65535 45596 47084 ) ( -65535 45596 47084 ) ( -65535 -47084 -45596 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16598 63402 ) ( 65534 -16598 63402 ) ( -65534 15190 -63754 ) millgt1 16 0 0 1 0.500000 - } - { //brush 604 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 0 1 1 - ( 65534 -16598 63402 ) ( -65534 -16598 63402 ) ( -65534 15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 605 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( 65535 45596 47084 ) ( -65535 45596 47084 ) ( -65535 -47084 -45596 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16598 63402 ) ( 65534 -16598 63402 ) ( -65534 15190 -63754 ) millgt1 16 0 0 1 0.500000 - } - { //brush 606 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 0 1 1 - ( 65534 -16598 63402 ) ( -65534 -16598 63402 ) ( -65534 15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 607 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 608 - ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 - } - { //brush 609 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 - ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 - } - { //brush 610 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) mtn 0 0 0 1 1 - } - { //brush 611 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 612 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 613 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 614 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) mtn 0 0 0 1 1 - } - { //brush 615 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 -36876 54178 ) ( -65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 616 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -36876 54178 ) ( -65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 617 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 618 - ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - } - { //brush 619 - ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 180 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 620 - ( -144 65535 65535 ) ( -144 -65535 65535 ) ( -144 65535 -65535 ) shootit 16 0 180 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 621 - ( -400 65535 65535 ) ( -400 -65535 65535 ) ( -400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -144 -65535 65535 ) ( -144 65535 65535 ) ( -144 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 622 - ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) shootit 16 0 180 1 1 - ( -400 -65535 65535 ) ( -400 65535 65535 ) ( -400 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 623 - ( -464 65535 65535 ) ( -464 -65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -432 -65535 65535 ) ( -432 65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - } - { //brush 624 - ( -496 65535 65535 ) ( -496 -65535 65535 ) ( -496 65535 -65535 ) shootit 16 0 180 1 1 - ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 625 - ( -496 -65535 65535 ) ( -496 65535 65535 ) ( -496 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 626 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 627 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 628 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 629 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 630 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) shootit 16 0 180 1 1 - ( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) shootit 16 0 0 1 1 - } - { //brush 631 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -784 -65535 65535 ) ( -784 65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 632 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - } - { //brush 633 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 15073 65534 63783 ) ( 15073 -65534 63783 ) ( -16715 65534 -63373 ) stnwll01 0 0 0 1 1 - } - { //brush 634 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( -46436 65535 46244 ) ( -46436 -65535 46244 ) ( 46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( 15073 -65534 63783 ) ( 15073 65534 63783 ) ( -16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 - } - { //brush 635 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 15073 65534 63783 ) ( 15073 -65534 63783 ) ( -16715 65534 -63373 ) stnwll01 0 0 0 1 1 - } - { //brush 636 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( -46436 65535 46244 ) ( -46436 -65535 46244 ) ( 46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( 15073 -65534 63783 ) ( 15073 65534 63783 ) ( -16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 - } - { //brush 637 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } - { //brush 638 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) shootit 16 16 180 1 1 - ( -65535 -1072 65535 ) ( 65535 -1072 65535 ) ( -65535 -1072 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1040 65535 ) ( -65535 -1040 65535 ) ( -65535 -1040 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 16 0 1 1 - ( 58728 -65534 -29084 ) ( 58728 65534 -29084 ) ( -58504 -65534 29532 ) shootit 16 16 0 1 1 - } - { //brush 639 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 640 - ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 641 - ( -144 65535 65535 ) ( -144 -65535 65535 ) ( -144 65535 -65535 ) shootit 16 0 180 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 642 - ( -400 65535 65535 ) ( -400 -65535 65535 ) ( -400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -144 -65535 65535 ) ( -144 65535 65535 ) ( -144 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 643 - ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) shootit 16 0 180 1 1 - ( -400 -65535 65535 ) ( -400 65535 65535 ) ( -400 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 644 - ( -464 65535 65535 ) ( -464 -65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -432 -65535 65535 ) ( -432 65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 645 - ( -496 65535 65535 ) ( -496 -65535 65535 ) ( -496 65535 -65535 ) shootit 16 0 180 1 1 - ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 646 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -496 -65535 65535 ) ( -496 65535 65535 ) ( -496 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 647 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) shootit 16 0 180 1 1 - ( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 648 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -784 -65535 65535 ) ( -784 65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 649 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 650 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stnwll01 0 0 0 1 1 - ( 58952 28636 65535 ) ( -58280 -29980 65535 ) ( -58280 -29980 -65535 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 0 1 1 - } - { //brush 651 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) fstng_2 0 0 0 1 1 - } - { //brush 652 - ( -1968 65535 65535 ) ( -1968 -65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 653 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45596 47084 ) ( 65535 -45596 47084 ) ( -65535 47084 -45596 ) millgt1 16 0 0 1 0.500000 - } - { //brush 654 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 - ( 65535 -45596 47084 ) ( -65535 -45596 47084 ) ( -65535 47084 -45596 ) stnwll01 0 0 0 1 1 - ( -65534 16598 63402 ) ( 65534 16598 63402 ) ( -65534 -15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 655 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - ( -65534 16598 63402 ) ( 65534 16598 63402 ) ( -65534 -15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 656 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45596 47084 ) ( 65535 -45596 47084 ) ( -65535 47084 -45596 ) millgt1 16 0 0 1 0.500000 - ( 65534 16598 63402 ) ( -65534 16598 63402 ) ( -65534 -15190 -63754 ) millgt1 16 0 0 1 0.500000 - } - { //brush 657 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 658 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( -65535 -45644 47036 ) ( 65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 0 0 1 1 - } - { //brush 659 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -65535 -45644 47036 ) ( 65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 660 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 661 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 90 1 1 - } - { //brush 662 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 180 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 16 90 1 1 - } - { //brush 663 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 16 0 1 1 - ( -46508 -65535 46172 ) ( -46508 65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 0 1 1 - ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 664 - ( -1872 65535 65535 ) ( -1872 -65535 65535 ) ( -1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 665 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 666 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 667 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 0 16 0 1 1 - ( 63352 -65534 16798 ) ( 63352 65534 16798 ) ( -63804 -65534 -14991 ) ftlattice2 0 16 0 1 1 - ( 63644 -65534 -15631 ) ( 63644 65534 -15631 ) ( -63512 -65534 16158 ) ftlattice2 0 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 0 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 0 16 0 1 1 - } - { //brush 668 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63624 -65534 -15710 ) ( 63624 65534 -15710 ) ( -63532 -65534 16079 ) ftlattice2 16 16 0 1 1 - ( 63332 -65534 16877 ) ( 63332 65534 16877 ) ( -63823 -65534 -14911 ) ftlattice2 16 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 - } - { //brush 669 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 - } - { //brush 670 - ( -1872 65535 65535 ) ( -1872 -65535 65535 ) ( -1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 671 - ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1872 -65535 65535 ) ( -1872 65535 65535 ) ( -1872 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 672 ) ( 65535 -65535 672 ) ( -65535 -65535 672 ) fstng_2 0 0 0 1 1 - ( 65535 46316 46364 ) ( -65535 46316 46364 ) ( -65535 -46364 -46316 ) fstng_2 0 0 0 1 1 - } - { //brush 672 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 673 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 674 - ( -1680 65535 65535 ) ( -1680 -65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 675 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -65534 16350 63464 ) ( 65534 16350 63464 ) ( -65534 -15439 -63692 ) stnwll02 0 0 0 1 1 - } - { //brush 676 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65535 -45828 46852 ) ( 65535 -45828 46852 ) ( -65535 46852 -45828 ) millgt1 16 0 0 1 0.500000 - ( 65534 16350 63464 ) ( -65534 16350 63464 ) ( -65534 -15439 -63692 ) millgt1 16 0 0 1 0.500000 - } - { //brush 677 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 678 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27688 -59425 65535 ) ( -30927 57806 65535 ) ( -30927 57806 -65535 ) stnwll01 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 679 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 680 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 681 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 - } - { //brush 682 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63430 16485 ) ( 65535 63726 -15303 ) ( -65535 -63430 16485 ) ftlattice2 16 16 0 1 1 - ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 16 0 1 1 - ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) ftlattice2 16 16 0 1 1 - ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 16 0 1 1 - } - { //brush 683 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 684 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 685 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnfloor02 0 0 0 1 1 - } - { //brush 686 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 687 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 688 ) ( 65535 65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 688 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 689 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) ctf08 32 48 0 1 1 - ( -872 -65535 65535 ) ( -872 65535 65535 ) ( -872 65535 -65535 ) ctf08 32 48 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) ctf08 32 48 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) ctf08 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf08 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf08 32 48 90 1 1 - } - { //brush 690 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - } - { //brush 691 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) ctf08 32 48 0 1 1 - ( -872 -65535 65535 ) ( -872 65535 65535 ) ( -872 65535 -65535 ) ctf08 32 48 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf08 32 48 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) ctf08 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf08 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf08 32 48 90 1 1 - } - { //brush 692 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 693 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58200 -65534 30140 ) ( 58200 65534 30140 ) ( -59032 -65534 -28476 ) fstng_2 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 694 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 695 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 696 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 697 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) mtn 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62234 20536 65535 ) ( -62109 -20911 65535 ) ( -62109 -20911 -65535 ) mtn 0 0 0 1 1 - } - { //brush 698 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - } - { //brush 699 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62234 20536 65535 ) ( -62109 -20911 65535 ) ( -62109 -20911 -65535 ) mtn 0 0 0 1 1 - } - { //brush 700 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 701 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) mtn 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 702 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64593 11074 65535 ) ( 64693 -10472 65535 ) ( -64593 11074 -65535 ) mtn 0 0 0 1 1 - ( -59013 -28514 65535 ) ( 58219 30101 65535 ) ( -59013 -28514 -65535 ) mtn 0 0 0 1 1 - } - { //brush 703 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) mtn 0 0 180 1 1 - ( -960 -65535 65535 ) ( -960 65535 65535 ) ( -960 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 58219 -30101 65535 ) ( -59013 28514 65535 ) ( -59013 28514 -65535 ) mtn 0 0 0 1 1 - ( 64693 10472 65535 ) ( -64593 -11074 65535 ) ( -64593 -11074 -65535 ) mtn 0 0 0 1 1 - } - { //brush 704 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -960 -65535 65535 ) ( -960 65535 65535 ) ( -960 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - } - { //brush 705 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - ( 65535 -63424 16508 ) ( 65535 63731 -15280 ) ( -65535 -63424 16508 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 65535 -63716 -15341 ) ( 65535 63439 16447 ) ( -65535 -63716 -15341 ) ftlattice2 16 16 0 1 1 - } - { //brush 706 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 0 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 0 0 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) ftlattice2 16 0 0 1 1 - ( 65535 -63408 16572 ) ( 65535 63747 -15216 ) ( -65535 -63408 16572 ) ftlattice2 16 0 0 1 1 - } - { //brush 707 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 65535 -63439 16447 ) ( 65535 63716 -15341 ) ( -65535 -63439 16447 ) ftlattice2 16 16 0 1 1 - ( 65535 -63731 -15280 ) ( 65535 63424 16508 ) ( -65535 -63731 -15280 ) ftlattice2 16 16 0 1 1 - } - { //brush 708 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 0 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 0 0 1 1 - ( 65535 -63747 -15216 ) ( 65535 63408 16572 ) ( -65535 -63747 -15216 ) ftlattice2 16 0 0 1 1 - ( 65535 -63455 16383 ) ( 65535 63700 -15405 ) ( -65535 -63455 16383 ) ftlattice2 16 0 0 1 1 - } - { //brush 709 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - } - { //brush 710 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 711 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 712 - ( -976 65535 65535 ) ( -976 -65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 713 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 714 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( 65534 16116 63522 ) ( -65534 16116 63522 ) ( -65534 -15672 -63633 ) millgt1 16 0 0 1 0.500000 - } - { //brush 715 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1008 -65535 65535 ) ( -1008 65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 716 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - } - { //brush 717 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 - } - { //brush 718 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - } - { //brush 719 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - } - { //brush 720 - ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15352 63713 ) ( 65534 -15352 63713 ) ( -65534 16436 -63442 ) millgt1 0 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 721 - ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65534 -15352 63713 ) ( -65534 -15352 63713 ) ( -65534 16436 -63442 ) stnwll02 0 0 0 1 1 - } - { //brush 722 - ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 723 - ( -1312 65535 65535 ) ( -1312 -65535 65535 ) ( -1312 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - } - { //brush 724 - ( -1344 65535 65535 ) ( -1344 -65535 65535 ) ( -1344 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1312 -65535 65535 ) ( -1312 65535 65535 ) ( -1312 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 725 - ( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1344 -65535 65535 ) ( -1344 65535 65535 ) ( -1344 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - } - { //brush 726 - ( -1408 65535 65535 ) ( -1408 -65535 65535 ) ( -1408 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - } - { //brush 727 - ( -1440 65535 65535 ) ( -1440 -65535 65535 ) ( -1440 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1408 -65535 65535 ) ( -1408 65535 65535 ) ( -1408 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - } - { //brush 728 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1440 -65535 65535 ) ( -1440 65535 65535 ) ( -1440 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 729 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 730 - ( -1536 65535 65535 ) ( -1536 -65535 65535 ) ( -1536 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 731 - ( -1568 65535 65535 ) ( -1568 -65535 65535 ) ( -1568 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1536 -65535 65535 ) ( -1536 65535 65535 ) ( -1536 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 732 - ( -1600 65535 65535 ) ( -1600 -65535 65535 ) ( -1600 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1568 -65535 65535 ) ( -1568 65535 65535 ) ( -1568 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 733 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 734 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 735 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15352 63713 ) ( 65534 -15352 63713 ) ( -65534 16436 -63442 ) millgt1 0 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 736 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65534 -15352 63713 ) ( -65534 -15352 63713 ) ( -65534 16436 -63442 ) stnwll02 0 0 0 1 1 - } - { //brush 737 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 738 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 416 65535 ) ( 65535 416 65535 ) ( -65535 416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 739 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 384 65535 ) ( 65535 384 65535 ) ( -65535 384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 416 65535 ) ( -65535 416 65535 ) ( -65535 416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - } - { //brush 740 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 352 65535 ) ( 65535 352 65535 ) ( -65535 352 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 384 65535 ) ( -65535 384 65535 ) ( -65535 384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 741 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 742 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58625 65534 -29288 ) ( 58625 -65534 -29288 ) ( -58606 -65534 29327 ) stnfloor02 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 743 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - ( 28501 59019 65535 ) ( -30114 -58213 65535 ) ( 28501 59019 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 744 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( 28501 59019 65535 ) ( -30114 -58213 65535 ) ( 28501 59019 -65535 ) stnwll05 0 0 0 1 1 - ( -30088 58225 65535 ) ( 28527 -59006 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 745 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -30114 -58213 65535 ) ( 28501 59019 65535 ) ( 28501 59019 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 746 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll05 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -28937 58807 65535 ) ( 27299 -59585 65535 ) ( -28937 58807 -65535 ) stnwll05 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 747 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 748 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 749 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 28168 59185 65535 ) ( -30447 -58046 65535 ) ( 28168 59185 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) fstng_2 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 750 - ( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 751 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - ( 28367 59086 65535 ) ( -30248 -58145 65535 ) ( 28367 59086 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 752 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - } - { //brush 753 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 754 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) millgt1 16 0 90 1 0.500000 - ( -46700 65535 45980 ) ( -46700 -65535 45980 ) ( 45980 65535 -46700 ) millgt1 16 0 90 1 0.500000 - ( 14746 -65534 63865 ) ( 14746 65534 63865 ) ( -17042 65534 -63291 ) millgt1 16 0 0 1 0.500000 - } - { //brush 755 - ( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 756 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - ( -30248 58145 65535 ) ( 28367 -59086 65535 ) ( -30248 58145 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 757 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) fstng_2 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 758 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 759 - ( -976 65535 65535 ) ( -976 -65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 760 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16116 63522 ) ( 65534 -16116 63522 ) ( -65534 15672 -63633 ) millgt1 16 0 0 1 0.500000 - } - { //brush 761 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 762 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1008 -65535 65535 ) ( -1008 65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 763 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 764 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 45972 46708 ) ( 65535 45972 46708 ) ( -65535 -46708 -45972 ) stnwll05 0 0 0 1 1 - } - { //brush 765 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - } - { //brush 766 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 767 - ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 28168 -59185 65535 ) ( -30447 58046 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 768 - ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -30447 -58046 65535 ) ( 28168 59185 65535 ) ( 28168 59185 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 769 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 770 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( 65535 46196 46484 ) ( -65535 46196 46484 ) ( -65535 -46484 -46196 ) millgt1 16 0 0 1 0.500000 - } - { //brush 771 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 772 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 1 - ( 63389 -65534 16651 ) ( 63389 65534 16651 ) ( -63767 -65534 -15137 ) millgt1 16 0 0 1 1 - ( 65535 -63476 16301 ) ( 65535 63679 -15487 ) ( -65535 -63476 16301 ) millgt1 16 0 0 1 1 - ( 63567 -65534 -15935 ) ( 63567 65534 -15935 ) ( -63588 -65534 15853 ) millgt1 16 0 0 1 1 - ( 65535 -63655 -15585 ) ( 65535 63501 16203 ) ( -65535 -63655 -15585 ) millgt1 16 0 0 1 1 - } - { //brush 773 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 774 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 775 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 776 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - } - { //brush 777 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 778 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - ( -46980 65535 45700 ) ( -46980 -65535 45700 ) ( 45700 65535 -46980 ) fstng_2 0 0 90 1 1 - } - { //brush 779 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 45284 -65535 47396 ) ( 45284 65535 47396 ) ( -47396 65535 -45284 ) fstng_2 0 0 90 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 780 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 781 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 782 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65534 15231 63743 ) ( 65534 15231 63743 ) ( -65534 -16557 -63412 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 783 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( 65534 15231 63743 ) ( -65534 15231 63743 ) ( -65534 -16557 -63412 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) millgt1 0 0 0 1 0.500000 - } - { //brush 784 - ( -1680 65535 65535 ) ( -1680 -65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 785 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 786 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 787 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 788 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 789 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 790 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27688 -59425 65535 ) ( -30927 57806 65535 ) ( -30927 57806 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 791 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 792 - ( -1888 65535 65535 ) ( -1888 -65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 793 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 794 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 795 - ( -1968 65535 65535 ) ( -1968 -65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 796 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 16 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 16 0 0 1 0.500000 - ( -65534 -15333 63718 ) ( 65534 -15333 63718 ) ( -65534 16455 -63438 ) millgt1 16 0 0 1 0.500000 - } - { //brush 797 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 0 1 1 - ( 65534 -15333 63718 ) ( -65534 -15333 63718 ) ( -65534 16455 -63438 ) stnwll01 0 0 0 1 1 - } - { //brush 798 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 0 1 1 - ( 65534 -15333 63718 ) ( -65534 -15333 63718 ) ( -65534 16455 -63438 ) stnwll01 0 0 0 1 1 - ( -65535 46268 46412 ) ( 65535 46268 46412 ) ( -65535 -46412 -46268 ) stnwll01 0 0 0 1 1 - } - { //brush 799 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 16 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 16 0 0 1 0.500000 - } - { //brush 800 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 801 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - } - { //brush 802 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 803 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 804 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - } - { //brush 805 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 806 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( -65534 15887 63580 ) ( 65534 15887 63580 ) ( -65534 -15902 -63576 ) stnwll02 0 0 0 1 1 - } - { //brush 807 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) millgt1 0 0 0 1 0.500000 - ( 65534 15887 63580 ) ( -65534 15887 63580 ) ( -65534 -15902 -63576 ) millgt1 0 0 0 1 0.500000 - } - { //brush 808 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 809 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 810 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - } - { //brush 811 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 - } - { //brush 812 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 90 1 1 - ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 90 1 1 - ( -47116 65535 45564 ) ( -47116 -65535 45564 ) ( 45564 65535 -47116 ) fstng_2 0 16 90 1 1 - } - { //brush 813 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 - ( -47116 -65535 45564 ) ( -47116 65535 45564 ) ( 45564 65535 -47116 ) fstng_2 0 16 0 1 1 - } - { //brush 814 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 - ( -47172 65535 45508 ) ( -47172 -65535 45508 ) ( 45508 65535 -47172 ) millgt1 16 0 90 1 0.500000 - } - { //brush 815 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 816 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) millgt1 0 0 0 1 0.500000 - } - { //brush 817 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 0 1 1 - ( -65534 15231 63743 ) ( 65534 15231 63743 ) ( -65534 -16557 -63412 ) stnwll02 0 0 0 1 1 - } - { //brush 818 - ( -1888 65535 65535 ) ( -1888 -65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 819 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 820 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 821 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 822 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15887 63580 ) ( 65534 -15887 63580 ) ( -65534 15902 -63576 ) millgt1 0 0 0 1 0.500000 - } - { //brush 823 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 0 1 1 - ( 65534 -15887 63580 ) ( -65534 -15887 63580 ) ( -65534 15902 -63576 ) stnwll02 0 0 0 1 1 - } - { //brush 824 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 825 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_2 0 16 90 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 180 1 1 - ( -47244 65535 45436 ) ( -47244 -65535 45436 ) ( 45436 65535 -47244 ) fstng_2 0 16 90 1 1 - } - { //brush 826 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 827 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) fstng_2 0 16 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 0 1 1 - } - { //brush 828 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 180 1 1 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - } - { //brush 829 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 0 0 1 1 - ( 65535 -63442 16436 ) ( 65535 63713 -15352 ) ( -65535 -63442 16436 ) ftlattice2 16 0 0 1 1 - ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 0 0 1 1 - ( 65535 -63689 -15450 ) ( 65535 63467 16338 ) ( -65535 -63689 -15450 ) ftlattice2 16 0 0 1 1 - } - { //brush 830 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) ftlattice2 16 16 0 1 1 - ( 65535 -63430 16485 ) ( 65535 63726 -15303 ) ( -65535 -63430 16485 ) ftlattice2 16 16 0 1 1 - ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 16 0 1 1 - ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 16 0 1 1 - } - { //brush 831 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 65535 -63689 -15450 ) ( 65535 63467 16338 ) ( -65535 -63689 -15450 ) ftlattice2 16 0 0 1 1 - ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 0 0 1 1 - ( 65535 -63442 16436 ) ( 65535 63713 -15352 ) ( -65535 -63442 16436 ) ftlattice2 16 0 0 1 1 - ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 0 0 1 1 - } - { //brush 832 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 63508 65534 -16173 ) ( 63508 -65534 -16173 ) ( -63647 -65534 15615 ) metdec1 32 0 0 1 1 - ( 65535 -63484 16271 ) ( 65535 63672 -15518 ) ( -65535 -63484 16271 ) metdec1 32 0 0 1 1 - ( 65535 -63646 -15623 ) ( 65535 63510 16165 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 - } - { //brush 833 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) metdec1 32 0 0 1 1 - ( 65535 63672 -15518 ) ( 65535 -63484 16271 ) ( -65535 -63484 16271 ) metdec1 32 0 0 1 1 - ( 63346 -65534 16820 ) ( 63346 65534 16820 ) ( -63809 -65534 -14968 ) metdec1 32 0 0 1 1 - } - { //brush 834 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) metdec1 32 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 63346 65534 16820 ) ( 63346 -65534 16820 ) ( -63809 -65534 -14968 ) metdec1 32 0 0 1 1 - ( 65535 -63646 -15623 ) ( 65535 63510 16165 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 - } - { //brush 835 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) metdec1 32 0 180 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) metdec1 32 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 63510 16165 ) ( 65535 -63646 -15623 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) metdec1 32 0 0 1 1 - } - { //brush 836 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 837 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 838 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 224 65535 ) ( 65535 224 65535 ) ( -65535 224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 839 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 192 65535 ) ( 65535 192 65535 ) ( -65535 192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 224 65535 ) ( -65535 224 65535 ) ( -65535 224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 840 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 192 65535 ) ( -65535 192 65535 ) ( -65535 192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 841 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 842 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 843 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 844 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 16 0 0 1 0.500000 - } - { //brush 845 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 846 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 847 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 16 0 1 1 - } - { //brush 848 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 16 0 1 1 - ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 16 0 1 1 - } - { //brush 849 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 850 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 851 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 - ( -65534 -15920 63571 ) ( 65534 -15920 63571 ) ( -65534 15868 -63584 ) millgt1 16 0 0 1 0.500000 - } - { //brush 852 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 853 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 854 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 - } - { //brush 855 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -2656 -65535 65535 ) ( -2656 65535 65535 ) ( -2656 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 90 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 856 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 16 0 90 1 0.500000 - ( -18108 65534 63024 ) ( -18108 -65534 63024 ) ( 13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - } - { //brush 857 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - } - { //brush 858 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -368 65535 ) ( 65535 -368 65535 ) ( -65535 -368 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 859 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -400 65535 ) ( 65535 -400 65535 ) ( -65535 -400 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -368 65535 ) ( -65535 -368 65535 ) ( -65535 -368 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - } - { //brush 860 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -400 65535 ) ( -65535 -400 65535 ) ( -65535 -400 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 861 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 0 0 1 1 - } - { //brush 862 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 16 0 90 1 0.500000 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 - } - { //brush 863 - ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 864 - ( -2560 65535 65535 ) ( -2560 -65535 65535 ) ( -2560 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2528 -65535 65535 ) ( -2528 65535 65535 ) ( -2528 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 865 - ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2560 -65535 65535 ) ( -2560 65535 65535 ) ( -2560 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 866 - ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 867 - ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - } - { //brush 868 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -2624 -65535 65535 ) ( -2624 65535 65535 ) ( -2624 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 869 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 870 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 871 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 0 1 1 - ( 45484 -65535 47196 ) ( 45484 65535 47196 ) ( -47196 65535 -45484 ) fstng_2 0 16 90 1 1 - } - { //brush 872 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( -46484 65535 46196 ) ( -46484 -65535 46196 ) ( 46196 65535 -46484 ) fstng_2 0 16 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 873 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -46484 65535 46196 ) ( -46484 -65535 46196 ) ( 46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 874 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 0 1 1 - } - { //brush 875 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll05 0 0 0 1 1 - } - { //brush 876 - ( -1240 65535 65535 ) ( -1240 -65535 65535 ) ( -1240 65535 -65535 ) ctf08 0 16 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) ctf08 0 16 90 1 1 - } - { //brush 877 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 878 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnfloor02 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnfloor02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnfloor02 0 0 0 1 1 - } - { //brush 879 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -864 65535 ) ( 65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll05 0 0 0 1 1 - } - { //brush 880 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -864 65535 ) ( -65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -30703 57918 65535 ) ( 27912 -59313 65535 ) ( -30703 57918 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 881 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -864 65535 ) ( -65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 882 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1248 65535 ) ( 65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( 28757 58891 65535 ) ( -29858 -58341 65535 ) ( 28757 58891 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 883 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -1248 65535 ) ( 65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 884 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1248 65535 ) ( -65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 - } - { //brush 885 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 886 - ( -2136 -65535 65535 ) ( -2136 65535 65535 ) ( -2136 65535 -65535 ) ctf08 0 16 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) ctf08 0 16 90 1 1 - } - { //brush 887 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 888 - ( -2136 -65535 65535 ) ( -2136 65535 65535 ) ( -2136 65535 -65535 ) ctf08 0 16 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) ctf08 0 16 90 1 1 - } - { //brush 889 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 - } - { //brush 890 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_2 0 16 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 891 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - } - { //brush 892 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) stnwll02 0 0 90 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 893 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) stnwll02 0 0 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 90 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 90 1 1 - } - { //brush 894 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_2 0 16 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 - } - { //brush 895 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 896 - ( -1152 65535 65535 ) ( -1152 -65535 65535 ) ( -1152 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 897 - ( -1184 65535 65535 ) ( -1184 -65535 65535 ) ( -1184 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1152 -65535 65535 ) ( -1152 65535 65535 ) ( -1152 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - } - { //brush 898 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1184 -65535 65535 ) ( -1184 65535 65535 ) ( -1184 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 899 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 45524 -65535 47156 ) ( 45524 65535 47156 ) ( -47156 65535 -45524 ) fstng_2 0 16 90 1 1 - } - { //brush 900 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 901 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 902 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 57896 -30748 65535 ) ( -59336 27868 65535 ) ( -59336 27868 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 903 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 904 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( -16880 -65534 63331 ) ( -16880 65534 63331 ) ( 14908 65534 -63824 ) stnwll01 0 0 0 1 1 - ( 45476 65535 47204 ) ( 45476 -65535 47204 ) ( -47204 65535 -45476 ) stnwll01 0 0 90 1 1 - } - { //brush 905 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( 45476 -65535 47204 ) ( 45476 65535 47204 ) ( -47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - } - { //brush 906 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( 45476 -65535 47204 ) ( 45476 65535 47204 ) ( -47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - ( -16880 65534 63331 ) ( -16880 -65534 63331 ) ( 14908 65534 -63824 ) millgt1 0 0 0 1 0.500000 - } - { //brush 907 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - ( -16880 -65534 63331 ) ( -16880 65534 63331 ) ( 14908 65534 -63824 ) stnwll01 0 0 0 1 1 - } - { //brush 908 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 909 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_0 0 0 0 1 1 - } - { //brush 910 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_0 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 911 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) millgt1 16 0 0 1 1 - ( 63387 -65534 16658 ) ( 63387 65534 16658 ) ( -63769 -65534 -15130 ) millgt1 16 0 0 1 1 - ( 65535 -63533 16075 ) ( 65535 63623 -15713 ) ( -65535 -63533 16075 ) millgt1 16 0 0 1 1 - ( 63648 -65534 -15612 ) ( 63648 65534 -15612 ) ( -63507 -65534 16176 ) millgt1 16 0 0 1 1 - ( 65535 -63794 -15028 ) ( 65535 63361 16760 ) ( -65535 -63794 -15028 ) millgt1 16 0 0 1 1 - } - { //brush 912 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 913 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) shootit 16 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 914 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 915 - ( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( 65535 58533 -29474 ) ( 65535 -58699 29141 ) ( -65535 -58699 29141 ) tile2492 0 0 0 1 1 - } - { //brush 916 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -1136 -65535 65535 ) ( -1136 65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 917 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - } - { //brush 918 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 919 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) shootit 16 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 920 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 921 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 922 - ( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 923 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -1136 -65535 65535 ) ( -1136 65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 90 1 1 - } - { //brush 924 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 90 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 925 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 28802 58869 65535 ) ( -29813 -58363 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 926 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -30658 57941 65535 ) ( 27957 -59291 65535 ) ( -30658 57941 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 927 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -800 65535 ) ( 65535 -800 65535 ) ( -65535 -800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 - } - { //brush 928 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -800 65535 ) ( 65535 -800 65535 ) ( -65535 -800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 - } - { //brush 929 - ( -65535 -688 65535 ) ( 65535 -688 65535 ) ( -65535 -688 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 180 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 930 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -63497 -16218 65535 ) ( 63659 15570 65535 ) ( -63497 -16218 -65535 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63822 14915 65535 ) ( 63333 -16873 65535 ) ( -63822 14915 -65535 ) shootit 0 8 0 1 1 - } - { //brush 931 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -63853 14795 65535 ) ( 63303 -16993 65535 ) ( -63853 14795 -65535 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63527 -16097 65535 ) ( 63629 15691 65535 ) ( -63527 -16097 -65535 ) shootit 0 8 0 1 1 - } - { //brush 932 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63519 -16127 65535 ) ( 63636 15661 65535 ) ( -63519 -16127 -65535 ) shootit 0 8 0 1 1 - ( -63845 14825 65535 ) ( 63310 -16963 65535 ) ( -63845 14825 -65535 ) shootit 0 8 0 1 1 - } - { //brush 933 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63830 14885 65535 ) ( 63326 -16903 65535 ) ( -63830 14885 -65535 ) shootit 0 8 0 1 1 - ( -63504 -16188 65535 ) ( 63651 15600 65535 ) ( -63504 -16188 -65535 ) shootit 0 8 0 1 1 - } - { //brush 934 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63512 -16158 65535 ) ( 63644 15631 65535 ) ( -63512 -16158 -65535 ) shootit 0 8 0 1 1 - ( -63838 14855 65535 ) ( 63318 -16933 65535 ) ( -63838 14855 -65535 ) shootit 0 8 0 1 1 - } - { //brush 935 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) stnfloor02 0 0 180 1 1 - ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58385 29768 ) ( 65535 -58846 -28847 ) ( -65535 -58846 -28847 ) stnfloor02 0 0 0 1 1 - } - { //brush 936 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 63313 -65534 16952 ) ( 63313 65534 16952 ) ( -63842 -65534 -14836 ) millgt1 16 16 0 1 1 - ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) millgt1 16 16 0 1 1 - ( 63590 -65534 -15845 ) ( 63590 65534 -15845 ) ( -63566 -65534 15943 ) millgt1 16 16 0 1 1 - ( 65535 -63756 -15183 ) ( 65535 63400 16606 ) ( -65535 -63756 -15183 ) millgt1 16 16 0 1 1 - } - { //brush 937 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 938 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 939 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -30703 -57918 65535 ) ( 27912 59313 65535 ) ( 27912 59313 -65535 ) fstng_2 0 0 0 1 1 - ( -31330 57605 65535 ) ( 27285 -59627 65535 ) ( -31330 57605 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 940 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 941 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( 27260 -59640 65535 ) ( -31356 57592 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 942 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( -31381 57579 65535 ) ( 27234 -59653 65535 ) ( -31381 57579 -65535 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 943 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( 27234 -59653 65535 ) ( -31381 57579 65535 ) ( -31381 57579 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 944 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -31407 57566 65535 ) ( 27208 -59665 65535 ) ( -31407 57566 -65535 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 945 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( 27208 -59665 65535 ) ( -31407 57566 65535 ) ( -31407 57566 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 946 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 947 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65534 15002 63801 ) ( -65534 15002 63801 ) ( -65534 -16786 -63355 ) stonesnw 0 0 0 1 1 - ( -58558 -29423 65535 ) ( 58673 29192 65535 ) ( -58558 -29423 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 948 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 0 1 1 - ( 28680 58929 65535 ) ( -29935 -58302 65535 ) ( 28680 58929 -65535 ) stnwll05 0 0 0 1 1 - ( -30780 57880 65535 ) ( 27836 -59352 65535 ) ( -30780 57880 -65535 ) stnwll05 0 0 0 1 1 - ( 58145 65534 30248 ) ( 58145 -65534 30248 ) ( -59086 -65534 -28367 ) stnfloor02 0 0 0 1 1 - } - { //brush 949 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 28680 58929 65535 ) ( -29935 -58302 65535 ) ( 28680 58929 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 950 - ( -1256 65535 65535 ) ( -1256 -65535 65535 ) ( -1256 65535 -65535 ) ctf02 96 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) ctf02 96 0 0 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 0 180 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 0 180 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) ctf02 96 0 90 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 951 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1256 -65535 65535 ) ( -1256 65535 65535 ) ( -1256 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 61098 23715 ) ( 65535 -61626 -22305 ) ( -65535 -61626 -22305 ) stnfloor02 0 0 0 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 65535 61366 -23000 ) ( 65535 -61358 23021 ) ( -65535 -61358 23021 ) stnfloor02 0 0 0 1 1 - } - { //brush 952 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( -30780 57880 65535 ) ( 27836 -59352 65535 ) ( -30780 57880 -65535 ) stnwll05 0 0 0 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 953 - ( -2080 65535 65535 ) ( -2080 -65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -1568 -65535 65535 ) ( -1568 65535 65535 ) ( -1568 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 954 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( 44964 -65535 47716 ) ( 44964 65535 47716 ) ( -47716 65535 -44964 ) fstng_2 0 16 90 1 1 - } - { //brush 955 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 956 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63406 65534 16579 ) ( 63406 -65534 16579 ) ( -63749 -65534 -15209 ) stonesnw 0 0 0 1 1 - } - { //brush 957 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 958 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63406 65534 16579 ) ( 63406 -65534 16579 ) ( -63749 -65534 -15209 ) stonesnw 0 0 0 1 1 - } - { //brush 959 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 960 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1312 65535 ) ( -65535 -1312 65535 ) ( -65535 -1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 - } - { //brush 961 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1312 65535 ) ( -65535 -1312 65535 ) ( -65535 -1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 - } - { //brush 962 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 963 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 964 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1344 65535 ) ( -65535 -1344 65535 ) ( -65535 -1344 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 965 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 63313 -65534 16952 ) ( 63313 65534 16952 ) ( -63842 -65534 -14836 ) millgt1 16 16 0 1 1 - ( 65535 -63524 16109 ) ( 65535 63631 -15679 ) ( -65535 -63524 16109 ) millgt1 16 16 0 1 1 - ( 63590 -65534 -15845 ) ( 63590 65534 -15845 ) ( -63566 -65534 15943 ) millgt1 16 16 0 1 1 - ( 65535 -63801 -15002 ) ( 65535 63355 16786 ) ( -65535 -63801 -15002 ) millgt1 16 16 0 1 1 - } - { //brush 966 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 28130 59205 65535 ) ( -30485 -58027 65535 ) ( 28130 59205 -65535 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 967 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - ( 28104 59217 65535 ) ( -30511 -58014 65535 ) ( 28104 59217 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 968 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( 28079 59230 65535 ) ( -30536 -58001 65535 ) ( 28079 59230 -65535 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 969 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 28053 59243 65535 ) ( -30562 -57989 65535 ) ( 28053 59243 -65535 ) fstng_2 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 970 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( -30562 -57989 65535 ) ( 28053 59243 65535 ) ( 28053 59243 -65535 ) stnwll05 0 0 0 1 1 - ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 971 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1408 65535 ) ( 65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 972 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 63139 -17648 65535 ) ( -64016 14140 65535 ) ( -64016 14140 -65535 ) shootit 0 8 0 1 1 - ( 63807 14975 65535 ) ( -63348 -16813 65535 ) ( -63348 -16813 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - } - { //brush 973 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 63815 14945 65535 ) ( -63341 -16843 65535 ) ( -63341 -16843 -65535 ) shootit 0 8 0 1 1 - ( 63147 -17618 65535 ) ( -64009 14170 65535 ) ( -64009 14170 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - } - { //brush 974 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - ( 63154 -17588 65535 ) ( -64001 14200 65535 ) ( -64001 14200 -65535 ) shootit 0 8 0 1 1 - ( 63822 14915 65535 ) ( -63333 -16873 65535 ) ( -63333 -16873 -65535 ) shootit 0 8 0 1 1 - } - { //brush 975 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 63830 14885 65535 ) ( -63326 -16903 65535 ) ( -63326 -16903 -65535 ) shootit 0 8 0 1 1 - ( 63162 -17558 65535 ) ( -63994 14230 65535 ) ( -63994 14230 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - } - { //brush 976 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 63132 -17679 65535 ) ( -64024 14110 65535 ) ( -64024 14110 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 63800 15006 65535 ) ( -63356 -16783 65535 ) ( -63356 -16783 -65535 ) shootit 0 8 0 1 1 - } - { //brush 977 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1408 65535 ) ( -65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58808 28924 ) ( 65535 58424 -29692 ) ( -65535 -58808 28924 ) stnwll05 0 0 90 1 1 - } - { //brush 978 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -1408 65535 ) ( -65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnfloor02 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58424 -29692 ) ( 65535 -58808 28924 ) ( -65535 -58808 28924 ) stnfloor02 0 0 0 1 1 - } - { //brush 979 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1424 65535 ) ( -65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 180 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 980 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stonesnw 0 0 0 1 1 - ( 57829 -30882 65535 ) ( -59403 27733 65535 ) ( -59403 27733 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 981 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) tile2492 0 0 180 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 982 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 983 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 984 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_2 0 16 90 1 1 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 985 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 986 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -624 65535 ) ( 65535 -624 65535 ) ( -65535 -624 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 987 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -624 65535 ) ( 65535 -624 65535 ) ( -65535 -624 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 - } - { //brush 988 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -816 65535 ) ( 65535 -816 65535 ) ( -65535 -816 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -624 65535 ) ( -65535 -624 65535 ) ( -65535 -624 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 989 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -848 65535 ) ( 65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -816 65535 ) ( -65535 -816 65535 ) ( -65535 -816 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 990 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -848 65535 ) ( 65535 -848 65535 ) ( -65535 -848 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -816 65535 ) ( -65535 -816 65535 ) ( -65535 -816 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 - } - { //brush 991 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 16 0 1 1 - ( 65535 -63517 16139 ) ( 65535 63639 -15649 ) ( -65535 -63517 16139 ) millgt1 0 16 0 1 1 - ( 63305 -65534 16986 ) ( 63305 65534 16986 ) ( -63851 -65534 -14802 ) millgt1 0 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) millgt1 0 16 0 1 1 - ( 63551 -65534 -15999 ) ( 63551 65534 -15999 ) ( -63604 -65534 15789 ) millgt1 0 16 0 1 1 - } - { //brush 992 - ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 57649 -31240 65535 ) ( -59582 27375 65535 ) ( -59582 27375 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 993 - ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -58737 -29064 65535 ) ( 58494 29551 65535 ) ( -58737 -29064 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 994 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -1296 65535 ) ( 65535 -1296 65535 ) ( -65535 -1296 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -1264 65535 ) ( -65535 -1264 65535 ) ( -65535 -1264 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( -18108 65534 63024 ) ( -18108 -65534 63024 ) ( 13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - } - { //brush 995 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1296 65535 ) ( 65535 -1296 65535 ) ( -65535 -1296 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1264 65535 ) ( -65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 996 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1296 65535 ) ( -65535 -1296 65535 ) ( -65535 -1296 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 997 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_2 0 16 0 1 1 - } - { //brush 998 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 - } - { //brush 999 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) *rtex345 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) *rtex345 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1000 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 - } - { //brush 1001 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1002 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1003 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1004 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) tile2492 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - } - { //brush 1005 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1006 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1007 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 -60809 -24435 ) ( 65535 60886 24242 ) ( -65535 -60809 -24435 ) *rtex345 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1008 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 180 1 1 - ( 65535 60886 24242 ) ( 65535 -60809 -24435 ) ( -65535 -60809 -24435 ) stonesnow 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 180 1 1 - } - { //brush 1009 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1010 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1011 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1012 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1013 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1014 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1015 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1016 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1017 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - } - { //brush 1018 - ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) fstng_0 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - } - { //brush 1019 - ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1020 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 90 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1021 - ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1022 - ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) fstng_0 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - } - { //brush 1023 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 104 -65535 65535 ) ( 104 65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1024 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 90 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1025 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) *rtex345 0 0 0 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1026 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 28 ) ( 65535 65535 28 ) ( -65535 -65535 28 ) fstng_0 0 0 0 1 1 - ( 65535 65535 32 ) ( 65535 -65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 0 1 1 - } - { //brush 1027 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) stonesnow 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 90 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1028 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) *rtex345 0 0 0 1 1 - ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1029 - ( -96 65535 65535 ) ( -96 -65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 96 -65535 65535 ) ( 96 65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1030 - ( -96 65535 65535 ) ( -96 -65535 65535 ) ( -96 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 96 -65535 65535 ) ( 96 65535 65535 ) ( 96 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - } - { //brush 1031 - ( -104 65535 65535 ) ( -104 -65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1032 - ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1033 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) fstng_0 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - } - { //brush 1034 - ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1035 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 90 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1036 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) fstng_0 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - } - { //brush 1037 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) *rtex345 0 0 0 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1038 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 90 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1039 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 28 ) ( 65535 65535 28 ) ( -65535 -65535 28 ) fstng_0 0 0 0 1 1 - ( 65535 65535 32 ) ( 65535 -65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 0 1 1 - } - { //brush 1040 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) *rtex345 0 0 0 1 1 - ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1041 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 90 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1042 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1043 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1044 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1045 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1046 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1047 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1048 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1049 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1050 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 65535 -60886 24242 ) ( 65535 60809 -24435 ) ( -65535 -60886 24242 ) *rtex345 0 0 0 1 1 - } - { //brush 1051 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 65535 60809 -24435 ) ( 65535 -60886 24242 ) ( -65535 -60886 24242 ) stonesnow 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 180 1 1 - } - { //brush 1052 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - } - { //brush 1053 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) tile2492 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - } - { //brush 1054 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1055 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 - } - { //brush 1056 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 65534 15002 63801 ) ( -65534 15002 63801 ) ( -65534 -16786 -63355 ) *rtex345 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) *rtex345 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1057 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 - } - { //brush 1058 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 58392 65534 -29756 ) ( 58392 -65534 -29756 ) ( -58840 -65534 28860 ) stonesnow 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1059 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1060 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 90 1 1 - ( 44652 -65535 48028 ) ( 44652 65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_2 0 16 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 1061 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - ( 57573 -31394 65535 ) ( -59659 27221 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1062 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65534 -17219 63246 ) ( -65534 -17219 63246 ) ( -65534 14569 -63909 ) stnwll02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 1063 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) millgt1 0 0 0 1 0.500000 - ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1064 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1065 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) millgt1 0 0 0 1 0.500000 - ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) millgt1 0 0 0 1 0.500000 - ( -65534 -17219 63246 ) ( 65534 -17219 63246 ) ( -65534 14569 -63909 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1066 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - ( 65534 -17219 63246 ) ( -65534 -17219 63246 ) ( -65534 14569 -63909 ) stnwll02 0 0 0 1 1 - } - { //brush 1067 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1068 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1069 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) millgt1 0 0 0 1 0.500000 - ( -65535 -45276 47404 ) ( 65535 -45276 47404 ) ( -65535 47404 -45276 ) millgt1 0 0 0 1 0.500000 - ( -65535 46812 45868 ) ( 65535 46812 45868 ) ( 65535 -45868 -46812 ) millgt1 0 0 0 1 0.500000 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1070 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2720 -65535 65535 ) ( 2720 65535 65535 ) ( 2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( 61587 -65535 22411 ) ( 61587 65535 22411 ) ( -61137 -65535 -23610 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1071 - ( 2516 65535 65535 ) ( 2516 -65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1072 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 - } - { //brush 1073 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 1074 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 1075 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2508 -65535 65535 ) ( 2508 65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 58731 29077 65535 ) ( -58501 -29538 65535 ) ( -58501 -29538 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1076 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - } - { //brush 1077 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 1078 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1079 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 180 1 1 - ( -64 -65535 65535 ) ( -64 65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 1080 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 200 ) ( 65535 65535 200 ) ( -65535 -65535 200 ) stnwll05 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1081 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - } - { //brush 1082 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnow 0 0 0 1 1 - } - { //brush 1083 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) millgt1 16 0 0 1 0.500000 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) millgt1 16 0 0 1 0.500000 - } - { //brush 1084 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) skull1 32 0 0 0.500000 0.500000 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) skull1 32 0 0 0.500000 0.500000 - } - { //brush 1085 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 1086 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 1087 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1088 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1089 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) ctf07 0 48 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll05 0 0 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - } - { //brush 1090 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - } - { //brush 1091 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1092 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - } - { //brush 1093 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1094 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) ctf07 32 48 180 1 1 - ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) ctf07 32 48 180 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) ctf07 32 48 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf07 32 48 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf07 32 48 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) ctf07 32 48 0 1 1 - } - { //brush 1095 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1096 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1097 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1098 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1099 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) ctf07 0 48 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 48 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 48 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf07 0 48 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf07 0 48 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf07 0 48 0 1 1 - } - { //brush 1100 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1101 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1102 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1103 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1104 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - ( 65535 -35414 55153 ) ( -65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 180 1 1 - } - { //brush 1105 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) ctf07 32 16 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - } - { //brush 1106 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - } - { //brush 1107 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 0 1 1 - } - { //brush 1108 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - } - { //brush 1109 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - } - { //brush 1110 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) ctf07 48 32 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) ctf07 48 32 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 48 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 48 32 0 1 1 - } - { //brush 1111 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - } - { //brush 1112 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2064 -65535 65535 ) ( 2064 65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - } - { //brush 1113 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - } - { //brush 1114 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - } - { //brush 1115 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 65535 -46212 46468 ) ( -65535 -46212 46468 ) ( 65535 46468 -46212 ) stnwll02 0 0 0 1 1 - ( -65535 -46228 46452 ) ( 65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1116 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - ( -65535 -46212 46468 ) ( 65535 -46212 46468 ) ( 65535 46468 -46212 ) fstng_2 0 0 0 1 1 - } - { //brush 1117 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -65535 -46228 46452 ) ( 65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1118 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 65535 -46228 46452 ) ( -65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - } - { //brush 1119 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1120 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 62344 65535 -20205 ) ( 62344 -65535 -20205 ) ( -61999 -65535 21242 ) stonesnw 0 0 0 1 1 - } - { //brush 1121 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1122 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 16 65535 ) ( 65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 0 1 1 - } - { //brush 1123 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) ctf01 64 32 180 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) ctf01 64 32 90 1 1 - ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) ctf01 64 32 90 1 1 - } - { //brush 1124 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 - ( -14746 -65534 63865 ) ( -14746 65534 63865 ) ( 17042 65534 -63291 ) stnwll05 0 0 0 1 1 - } - { //brush 1125 - ( 912 65535 65535 ) ( 912 -65535 65535 ) ( 912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 62344 65535 -20205 ) ( 62344 -65535 -20205 ) ( -61999 -65535 21242 ) stonesnw 0 0 0 1 1 - } - { //brush 1126 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1127 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1128 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1129 - ( 320 -65535 65535 ) ( 320 65535 65535 ) ( 320 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) stonesnw 0 0 180 1 1 - } - { //brush 1130 - ( 320 65535 65535 ) ( 320 -65535 65535 ) ( 320 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 1131 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1132 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1133 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) ctf07 0 32 0 1 1 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) ctf07 0 32 180 1 1 - ( 65535 -640 65535 ) ( -65535 -640 65535 ) ( -65535 -640 -65535 ) ctf07 0 32 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 0 32 90 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 0 32 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) ctf07 0 32 90 1 1 - } - { //brush 1134 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -640 65535 ) ( -65535 -640 65535 ) ( -65535 -640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1135 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -640 65535 ) ( 65535 -640 65535 ) ( -65535 -640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1136 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1137 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -704 65535 ) ( -65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1138 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1139 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1056 -65535 65535 ) ( 1056 65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) ctf07 32 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1140 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1056 -65535 65535 ) ( 1056 65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 576 ) ( 65535 65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1141 - ( 1056 65535 65535 ) ( 1056 -65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1142 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1143 - ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1144 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) ctf07 48 32 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) ctf07 48 32 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 48 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 48 32 0 1 1 - } - { //brush 1145 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - } - { //brush 1146 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - } - { //brush 1147 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 - } - { //brush 1148 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2064 -65535 65535 ) ( 2064 65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 - } - { //brush 1149 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1150 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) ctf08 0 48 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) ctf08 0 48 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf08 0 48 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf08 0 48 90 1 1 - } - { //brush 1151 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - } - { //brush 1152 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - } - { //brush 1153 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - } - { //brush 1154 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - } - { //brush 1155 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) ctf08 16 32 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) ctf08 16 32 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) ctf08 16 32 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) ctf08 16 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 16 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 16 32 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) ctf08 16 32 0 1 1 - } - { //brush 1156 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1157 - ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 1158 - ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - } - { //brush 1159 - ( -2064 65535 65535 ) ( -2064 -65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 1160 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 576 ) ( 65535 65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1161 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - } - { //brush 1162 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1163 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1164 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 640 65535 ) ( -65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1165 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 704 65535 ) ( 65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1166 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1167 - ( -912 65535 65535 ) ( -912 -65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -58741 29058 65535 ) ( 58491 -29557 65535 ) ( -58741 29058 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1168 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -58741 29058 65535 ) ( 58491 -29557 65535 ) ( -58741 29058 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1169 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) ctf02 64 32 180 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) ctf02 64 32 90 1 1 - ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) ctf02 64 32 90 1 1 - } - { //brush 1170 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 - ( 14746 65534 63865 ) ( 14746 -65534 63865 ) ( -17042 65534 -63291 ) stnwll05 0 0 0 1 1 - } - { //brush 1171 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -16 65535 ) ( -65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 0 1 1 - } - { //brush 1172 - ( -912 -65535 65535 ) ( -912 65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 61999 65535 21242 ) ( 61999 -65535 21242 ) ( -62344 -65535 -20205 ) stonesnw 0 0 0 1 1 - } - { //brush 1173 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) ctf08 16 32 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) ctf08 16 32 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) ctf08 16 32 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) ctf08 16 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 16 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 16 32 0 1 1 - } - { //brush 1174 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 0 1 1 - } - { //brush 1175 - ( -2064 65535 65535 ) ( -2064 -65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 1176 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - } - { //brush 1177 - ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 1178 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) ctf08 32 16 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) ctf08 32 16 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) ctf08 32 16 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) ctf08 32 16 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) ctf08 32 16 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf08 32 16 90 1 1 - } - { //brush 1179 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - } - { //brush 1180 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 1181 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 1182 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 - } - { //brush 1183 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) skull1 32 0 0 0.500000 0.500000 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) skull1 32 0 0 0.500000 0.500000 - } - { //brush 1184 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1185 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1186 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1187 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1188 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) stnwll02 0 0 0 1 1 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1189 - ( -2720 65535 65535 ) ( -2720 -65535 65535 ) ( -2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 61137 -65535 -23610 ) ( 61137 65535 -23610 ) ( -61587 -65535 22411 ) stnwll02 0 0 0 1 1 - } - { //brush 1190 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stonesnw 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1191 - ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) ctf08 32 48 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1192 - ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - ( -46508 -65535 46172 ) ( -46508 65535 46172 ) ( 46172 65535 -46508 ) stnwll02 0 0 0 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) stnwll02 0 0 0 1 1 - } - { //brush 1193 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -992 -65535 65535 ) ( -992 65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1194 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1195 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) ctf08 0 48 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf08 0 48 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf08 0 48 90 1 1 - } - { //brush 1196 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - } - { //brush 1197 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1198 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - } - { //brush 1199 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1200 - ( -1072 65535 65535 ) ( -1072 -65535 65535 ) ( -1072 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1040 -65535 65535 ) ( -1040 65535 65535 ) ( -1040 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 - ( -46188 -46492 65535 ) ( 46492 46188 65535 ) ( 46492 46188 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 1201 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( -59323 27893 65535 ) ( 57909 -30722 65535 ) ( -59323 27893 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_0 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1202 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - ( 57909 -30722 65535 ) ( -59323 27893 65535 ) ( -59323 27893 -65535 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_0 0 0 0 1 1 - } - { //brush 1203 - ( -2508 65535 65535 ) ( -2508 -65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -58731 -29077 65535 ) ( 58501 29538 65535 ) ( -58731 -29077 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1204 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) ctf08 0 32 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) ctf08 0 32 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 32 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 32 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) ctf08 0 32 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) ctf08 0 32 90 1 1 - } - { //brush 1205 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1206 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1207 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 - } - { //brush 1208 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1209 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2516 -65535 65535 ) ( -2516 65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1210 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1211 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1216 -65535 65535 ) ( 1216 65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1212 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1213 - ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1214 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1215 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 1216 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) ctf07 0 32 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) ctf07 0 32 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 32 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 32 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) ctf07 0 32 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) ctf07 0 32 90 1 1 - } - { //brush 1217 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1218 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1219 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1220 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1221 - ( 1040 65535 65535 ) ( 1040 -65535 65535 ) ( 1040 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1216 -65535 65535 ) ( 1216 65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 - ( 46188 46492 65535 ) ( -46492 -46188 65535 ) ( 46188 46492 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 1222 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf01 64 80 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) ctf01 64 80 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf01 64 80 0 1 1 - ( 60996 69391 7356 ) ( 60996 -57765 39146 ) ( -61258 57929 -38488 ) ctf01 64 80 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) ctf01 64 80 0 1 1 - ( 61258 -69226 -6699 ) ( 61258 57929 -38488 ) ( -60996 -57765 39146 ) ctf01 64 80 0 1 1 - } - { //brush 1223 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf01 64 80 180 1 1 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf01 64 80 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) ctf01 64 80 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf01 64 80 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) ctf01 64 80 0 1 1 - ( 60996 -57765 39146 ) ( 60996 69391 7356 ) ( -61258 57929 -38488 ) ctf01 64 80 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) ctf01 64 80 0 1 1 - } - { //brush 1224 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) stnwll02 0 0 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 - } - { //brush 1225 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) stnwll02 0 0 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 - } - { //brush 1226 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 1227 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 61458 22754 ) ( 65535 -61266 -23266 ) ( -65535 61458 22754 ) tile2492 0 0 90 1 1 - ( 65535 61526 -22572 ) ( 65535 -61197 23449 ) ( -65535 -61197 23449 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 1228 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) ctf01 32 80 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 80 180 1 1 - ( 65535 61526 -22572 ) ( 65535 -61197 23449 ) ( -65535 -61197 23449 ) ctf01 32 80 90 1 1 - ( 65535 -61266 -23266 ) ( 65535 61458 22754 ) ( -65535 61458 22754 ) ctf01 32 80 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf01 32 80 0 1 1 - } - { //brush 1229 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } - { //brush 1230 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 61421 65535 22853 ) ( 61421 -65535 22853 ) ( -61303 65535 -23168 ) stnwll02 0 0 0 1 1 - ( 61721 65535 -22053 ) ( 61721 -65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 - } - { //brush 1231 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) ctf01 32 48 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 61421 -65535 22853 ) ( 61421 65535 22853 ) ( -61303 65535 -23168 ) stnwll02 0 0 0 1 1 - ( 61721 65535 -22053 ) ( 61721 -65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 - } - { //brush 1232 - ( 1408 65535 65535 ) ( 1408 -65535 65535 ) ( 1408 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw2 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw2 0 0 180 1 1 - } - { //brush 1233 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 1408 -65535 65535 ) ( 1408 65535 65535 ) ( 1408 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1234 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 80 180 1 1 - ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 - ( 65535 -61458 22754 ) ( 65535 61266 -23266 ) ( -65535 -61458 22754 ) ctf02 96 80 90 1 1 - } - { //brush 1235 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } - { //brush 1236 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1237 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) ctf08 0 32 0 1 1 - ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) ctf08 0 32 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) ctf08 0 32 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 0 32 90 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 0 32 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) ctf08 0 32 90 1 1 - } - { //brush 1238 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } - { //brush 1239 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 61303 65535 -23168 ) ( 61303 -65535 -23168 ) ( -61421 65535 22853 ) fstng_0 0 0 0 1 1 - ( 61003 65535 23968 ) ( 61003 -65535 23968 ) ( -61721 -65535 -22053 ) fstng_0 0 0 0 1 1 - } - { //brush 1240 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) ctf02 96 48 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 96 48 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) ctf02 96 48 0 1 1 - ( 61303 -65535 -23168 ) ( 61303 65535 -23168 ) ( -61421 65535 22853 ) ctf02 96 48 0 1 1 - ( 61003 65535 23968 ) ( 61003 -65535 23968 ) ( -61721 -65535 -22053 ) ctf02 96 48 0 1 1 - } - { //brush 1241 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 - ( 72321 -20359 54282 ) ( -20359 72321 54282 ) ( 18812 -73868 -52735 ) stnwll02 0 0 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) stnwll02 0 0 0 1 1 - } - { //brush 1242 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1243 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1244 - ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1245 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1246 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1247 - ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1248 - ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1249 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 288 ) ( 65535 65535 288 ) ( -65535 -65535 288 ) stnwll02 0 0 90 1 1 - ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 - ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1250 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) ctf02 64 80 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) ctf02 64 80 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf02 64 80 180 1 1 - ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) ctf02 64 80 90 1 1 - ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) ctf02 64 80 90 1 1 - } - { //brush 1251 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1252 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 90 1 1 - ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1253 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 0 1 1 - ( 61587 65535 22411 ) ( 61587 -65535 22411 ) ( -61137 -65535 -23610 ) stnwll02 0 0 0 1 1 - ( 61823 65535 -21779 ) ( 61823 -65535 -21779 ) ( -60900 -65535 24241 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1254 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1255 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1256 - ( -280 65535 65535 ) ( -280 -65535 65535 ) ( -280 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1257 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) tile2492 0 0 90 1 1 - ( 65535 61197 23449 ) ( 65535 -61526 -22572 ) ( -65535 -61526 -22572 ) tile2492 0 0 90 1 1 - ( 65535 61266 -23266 ) ( 65535 -61458 22754 ) ( -65535 -61458 22754 ) tile2492 0 0 90 1 1 - } - { //brush 1258 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf02 64 80 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf02 64 80 0 1 1 - ( 61258 69226 -6699 ) ( 61258 -57929 -38488 ) ( -60996 57765 39146 ) ctf02 64 80 0 1 1 - ( 60996 -69391 7356 ) ( 60996 57765 39146 ) ( -61258 69226 -6699 ) ctf02 64 80 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) ctf02 64 80 0 1 1 - } - { //brush 1259 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf02 64 80 180 1 1 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf02 64 80 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) ctf02 64 80 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf02 64 80 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) ctf02 64 80 0 1 1 - ( 61258 -57929 -38488 ) ( 61258 69226 -6699 ) ( -60996 57765 39146 ) ctf02 64 80 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) ctf02 64 80 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) ctf02 64 80 0 1 1 - } - { //brush 1260 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) millgt1 16 0 0 1 0.500000 - } - { //brush 1261 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 0 1 1 - ( 60900 65535 24241 ) ( 60900 -65535 24241 ) ( -61823 -65535 -21779 ) stnwll02 0 0 0 1 1 - ( 61137 65535 -23610 ) ( 61137 -65535 -23610 ) ( -61587 -65535 22411 ) stnwll02 0 0 0 1 1 - } - { //brush 1262 - ( -1408 65535 65535 ) ( -1408 -65535 65535 ) ( -1408 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1263 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1264 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1265 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - } - { //brush 1266 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) ctf02 64 80 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) ctf02 64 80 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf02 64 80 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf02 64 80 180 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf02 64 80 90 1 1 - ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) ctf02 64 80 90 1 1 - } - { //brush 1267 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1268 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1269 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1270 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1271 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1272 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1273 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1274 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1275 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1276 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1277 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1278 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1279 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1280 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1281 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1282 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1283 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1284 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1285 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1286 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1287 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1288 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1289 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1290 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1291 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1292 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1293 - ( -320 65535 65535 ) ( -320 -65535 65535 ) ( -320 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) stonesnw 0 0 180 1 1 - } - { //brush 1294 - ( -1056 65535 65535 ) ( -1056 -65535 65535 ) ( -1056 65535 -65535 ) ctf08 32 0 180 1 1 - ( -992 -65535 65535 ) ( -992 65535 65535 ) ( -992 65535 -65535 ) ctf08 32 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) ctf08 32 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) ctf08 32 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) ctf08 32 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) ctf08 32 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) ctf08 32 0 0 1 1 - } - { //brush 1295 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1296 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1297 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1298 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1299 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1300 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1301 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 768 ) ( 65535 65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 - } - { //brush 1302 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - ( 59013 28514 65535 ) ( -58219 -30101 65535 ) ( -58219 -30101 -65535 ) sky003 0 0 0 1 1 - } - { //brush 1303 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll05 0 0 0 1 1 - } - { //brush 1304 - ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 - ( 29813 58363 65535 ) ( -28802 -58869 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1305 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1306 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) tile2492 0 0 180 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 1307 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -57896 30748 65535 ) ( 59336 -27868 65535 ) ( -57896 30748 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1308 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -58952 -28636 65535 ) ( 58280 29980 65535 ) ( -58952 -28636 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1309 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - } - { //brush 1310 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1311 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1312 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 1313 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnow 0 0 0 1 1 - } - { //brush 1314 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1315 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 1316 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 90 1 1 - ( 47244 -65535 45436 ) ( 47244 65535 45436 ) ( -45436 65535 -47244 ) fstng_2 0 16 90 1 1 - } - { //brush 1317 - ( 2560 65535 65535 ) ( 2560 -65535 65535 ) ( 2560 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 1318 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 63484 16271 ) ( 65535 -63672 -15518 ) ( -65535 -63672 -15518 ) metdec1 32 0 0 1 1 - ( 63809 -65534 -14968 ) ( 63809 65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 - ( 63647 -65534 15615 ) ( 63647 65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 - } - { //brush 1319 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) metdec1 32 0 0 1 1 - ( 65535 63646 -15623 ) ( 65535 -63510 16165 ) ( -65535 -63510 16165 ) metdec1 32 0 0 1 1 - ( 63647 -65534 15615 ) ( 63647 65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 - ( 63809 -65534 -14968 ) ( 63809 65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 - } - { //brush 1320 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( 2528 -65535 65535 ) ( 2528 65535 65535 ) ( 2528 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1321 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1322 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 1323 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1324 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1325 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 0 1 1 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) fstng_2 0 16 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 1326 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 58533 29474 65535 ) ( -58699 -29141 65535 ) ( -58699 -29141 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 1327 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 1328 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - } - { //brush 1329 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1330 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -27688 59425 65535 ) ( 30927 -57806 65535 ) ( -27688 59425 -65535 ) stnwll01 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 1331 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64593 -11074 65535 ) ( -64693 10472 65535 ) ( -64693 10472 -65535 ) mtn 0 0 0 1 1 - ( 59013 28514 65535 ) ( -58219 -30101 65535 ) ( -58219 -30101 -65535 ) mtn 0 0 0 1 1 - } - { //brush 1332 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 30447 -58046 65535 ) ( -28168 59185 65535 ) ( -28168 59185 -65535 ) fstng_0 0 0 180 1 1 - ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 1333 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 1334 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 - ( -28367 -59086 65535 ) ( 30248 58145 65535 ) ( 30248 58145 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1335 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1336 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1337 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) fstng_0 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 1338 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -58437 -29666 65535 ) ( 58795 28949 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 - } - { //brush 1339 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65534 -29461 58539 ) ( -65534 -29461 58539 ) ( -65534 29154 -58693 ) mtn 0 0 0 1 1 - } - { //brush 1340 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 1341 - ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 1342 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 1343 - ( 1712 65535 65535 ) ( 1712 -65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 1344 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 1345 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 90 1 1 - } - { //brush 1346 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 65535 -63564 15951 ) ( 65535 63592 -15838 ) ( -65535 -63564 15951 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - ( 65535 -63660 -15567 ) ( 65535 63496 16222 ) ( -65535 -63660 -15567 ) shootit 16 16 0 1 1 - } - { //brush 1347 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( 63536 -20069 64421 ) ( -66521 -3812 64421 ) ( -63635 19279 -64565 ) mtn 0 0 0 1 1 - ( 66510 -3720 64438 ) ( -63547 -19978 64438 ) ( -66434 3113 -64549 ) mtn 0 0 0 1 1 - ( 50409 -45720 62915 ) ( -66822 12895 62915 ) ( -50778 44984 -63149 ) mtn 0 0 0 1 1 - } - { //brush 1348 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 65081 7711 65535 ) ( -64976 -8546 65535 ) ( -64976 -8546 -65535 ) mtn 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) mtn 0 0 0 1 1 - ( 64306 -12641 65535 ) ( -64518 11513 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - } - { //brush 1349 - ( 1872 65535 65535 ) ( 1872 -65535 65535 ) ( 1872 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 672 ) ( 65535 65535 672 ) ( -65535 -65535 672 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_0 0 0 0 1 1 - } - { //brush 1350 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1351 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 1352 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 31464 57537 65535 ) ( -27151 -59694 65535 ) ( 31464 57537 -65535 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1353 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 180 1 1 - ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1354 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 1355 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1356 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1357 - ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1872 -65535 65535 ) ( -1872 65535 65535 ) ( -1872 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 672 ) ( 65535 65535 672 ) ( -65535 -65535 672 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_0 0 0 0 1 1 - } - { //brush 1358 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) mtn 0 0 0 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) mtn 0 0 0 1 1 - } - { //brush 1359 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_2 0 16 180 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 90 1 1 - } - { //brush 1360 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) mtn 0 0 0 1 1 - } - { //brush 1361 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1362 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 1363 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 45484 -65535 47196 ) ( 45484 65535 47196 ) ( -47196 65535 -45484 ) fstng_2 0 16 90 1 1 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) fstng_2 0 16 0 1 1 - } - { //brush 1364 - ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 28168 59185 65535 ) ( -30447 -58046 65535 ) ( 28168 59185 -65535 ) fstng_0 0 0 180 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 1365 - ( -912 -65535 65535 ) ( -912 65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 61999 65535 21242 ) ( 61999 -65535 21242 ) ( -62344 -65535 -20205 ) stonesnw 0 0 0 1 1 - } - { //brush 1366 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1367 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( -58878 28783 65535 ) ( 58353 -29832 65535 ) ( -58878 28783 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 - ( -20359 72321 54282 ) ( 72321 -20359 54282 ) ( 18812 -73868 -52735 ) stnwll02 0 0 0 1 1 - } - { //brush 1368 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 1369 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnfloor02 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnfloor02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnfloor02 0 0 0 1 1 - } - { //brush 1370 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - } - { //brush 1371 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 1372 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1373 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1344 65535 ) ( -65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -31445 57547 65535 ) ( 27170 -59685 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1374 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1375 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1376 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1377 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -45276 47404 ) ( 65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_2 0 16 0 1 1 - ( 65535 46812 45868 ) ( -65535 46812 45868 ) ( 65535 -45868 -46812 ) fstng_2 0 16 0 1 1 - } - { //brush 1378 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 1379 - ( 2720 65535 65535 ) ( 2720 -65535 65535 ) ( 2720 65535 -65535 ) ctf01 96 80 180 1 1 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) ctf01 96 80 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) ctf01 96 80 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf01 96 80 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) ctf01 96 80 0 1 1 - ( 61587 -65535 22411 ) ( 61587 65535 22411 ) ( -61137 -65535 -23610 ) ctf01 96 80 0 1 1 - } - { //brush 1380 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -57656 31228 65535 ) ( 59576 -27388 65535 ) ( -57656 31228 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1381 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 46722 45958 ) ( 65535 46722 45958 ) ( -65535 -45958 -46722 ) light04 16 16 0 0.250000 0.250000 - ( -65535 -45574 47106 ) ( 65535 -45574 47106 ) ( -65535 47106 -45574 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1382 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 -45542 47138 ) ( 65535 -45542 47138 ) ( -65535 47138 -45542 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 46690 45990 ) ( 65535 46690 45990 ) ( -65535 -45990 -46690 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1383 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 46658 46022 ) ( 65535 46658 46022 ) ( -65535 -46022 -46658 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -45510 47170 ) ( 65535 -45510 47170 ) ( -65535 47170 -45510 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1384 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 -45526 47154 ) ( 65535 -45526 47154 ) ( -65535 47154 -45526 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 46674 46006 ) ( 65535 46674 46006 ) ( -65535 -46006 -46674 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1385 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 46706 45974 ) ( 65535 46706 45974 ) ( -65535 -45974 -46706 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -45558 47122 ) ( 65535 -45558 47122 ) ( -65535 47122 -45558 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1386 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -45618 47062 ) ( -65535 -45618 47062 ) ( -65535 47062 -45618 ) light04 16 16 0 0.250000 0.250000 - ( 65535 46582 46098 ) ( -65535 46582 46098 ) ( -65535 -46098 -46582 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1387 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 46598 46082 ) ( -65535 46598 46082 ) ( -65535 -46082 -46598 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -45634 47046 ) ( -65535 -45634 47046 ) ( -65535 47046 -45634 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1388 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -45602 47078 ) ( -65535 -45602 47078 ) ( -65535 47078 -45602 ) light04 16 16 0 0.250000 0.250000 - ( 65535 46566 46114 ) ( -65535 46566 46114 ) ( -65535 -46114 -46566 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1389 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 46614 46066 ) ( -65535 46614 46066 ) ( -65535 -46066 -46614 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -45650 47030 ) ( -65535 -45650 47030 ) ( -65535 47030 -45650 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1390 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 46630 46050 ) ( -65535 46630 46050 ) ( -65535 -46050 -46630 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -45666 47014 ) ( -65535 -45666 47014 ) ( -65535 47014 -45666 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1391 - ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1392 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - } - { //brush 1393 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 1394 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 61258 57929 -38488 ) ( 61258 -69226 -6699 ) ( -60996 -57765 39146 ) tile2492 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - ( 60996 69391 7356 ) ( 60996 -57765 39146 ) ( -61258 57929 -38488 ) tile2492 0 0 0 1 1 - } - { //brush 1395 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) ctf01 32 48 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 61721 -65535 -22053 ) ( 61721 65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 - } - { //brush 1396 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1397 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -16 65535 ) ( -65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 0 1 1 - } - { //brush 1398 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1399 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 912 -65535 65535 ) ( 912 65535 65535 ) ( 912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1400 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1401 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 80 180 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 80 180 1 1 - ( 65535 -65535 104 ) ( 65535 65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) ctf02 96 80 90 1 1 - } - { //brush 1402 - ( 64 65535 65535 ) ( 64 -65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) tile2492 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) tile2492 0 0 0 1 1 - } - { //brush 1403 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 90 1 1 - } - { //brush 1404 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1405 - ( -912 65535 65535 ) ( -912 -65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1406 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) ctf02 96 48 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) ctf02 96 48 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 96 48 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) ctf02 96 48 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf02 96 48 0 1 1 - ( 61003 -65535 23968 ) ( 61003 65535 23968 ) ( -61721 -65535 -22053 ) ctf02 96 48 0 1 1 - } - { //brush 1407 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) ctf02 32 80 180 1 1 - ( -2720 -65535 65535 ) ( -2720 65535 65535 ) ( -2720 65535 -65535 ) ctf02 32 80 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) ctf02 32 80 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 32 80 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf02 32 80 0 1 1 - ( 61137 -65535 -23610 ) ( 61137 65535 -23610 ) ( -61587 -65535 22411 ) ctf02 32 80 0 1 1 - } - { //brush 1408 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1409 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1072 -65535 65535 ) ( -1072 65535 65535 ) ( -1072 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - } - { //brush 1410 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 1411 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 1412 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1413 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -46706 45974 ) ( -65535 -46706 45974 ) ( -65535 45974 -46706 ) light04 16 16 0 0.250000 0.250000 - ( 65535 45558 47122 ) ( -65535 45558 47122 ) ( -65535 -47122 -45558 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1414 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 45526 47154 ) ( -65535 45526 47154 ) ( -65535 -47154 -45526 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -46674 46006 ) ( -65535 -46674 46006 ) ( -65535 46006 -46674 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1415 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -46658 46022 ) ( -65535 -46658 46022 ) ( -65535 46022 -46658 ) light04 16 16 0 0.250000 0.250000 - ( 65535 45510 47170 ) ( -65535 45510 47170 ) ( -65535 -47170 -45510 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1416 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 45542 47138 ) ( -65535 45542 47138 ) ( -65535 -47138 -45542 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -46690 45990 ) ( -65535 -46690 45990 ) ( -65535 45990 -46690 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1417 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 45574 47106 ) ( -65535 45574 47106 ) ( -65535 -47106 -45574 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -46722 45958 ) ( -65535 -46722 45958 ) ( -65535 45958 -46722 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1418 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -46630 46050 ) ( 65535 -46630 46050 ) ( -65535 46050 -46630 ) light04 16 16 0 0.250000 0.250000 - ( -65535 45666 47014 ) ( 65535 45666 47014 ) ( -65535 -47014 -45666 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1419 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 45602 47078 ) ( 65535 45602 47078 ) ( -65535 -47078 -45602 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -46566 46114 ) ( 65535 -46566 46114 ) ( -65535 46114 -46566 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1420 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 -46614 46066 ) ( 65535 -46614 46066 ) ( -65535 46066 -46614 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 45650 47030 ) ( 65535 45650 47030 ) ( -65535 -47030 -45650 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1421 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 45618 47062 ) ( 65535 45618 47062 ) ( -65535 -47062 -45618 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -46582 46098 ) ( 65535 -46582 46098 ) ( -65535 46098 -46582 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1422 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 -46598 46082 ) ( 65535 -46598 46082 ) ( -65535 46082 -46598 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 45634 47046 ) ( 65535 45634 47046 ) ( -65535 -47046 -45634 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1423 - ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 57656 -31228 65535 ) ( -59576 27388 65535 ) ( -59576 27388 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1424 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 1425 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1426 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 288 ) ( 65535 65535 288 ) ( -65535 -65535 288 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1427 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1428 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 1429 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) ctf01 96 80 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) ctf01 96 80 0 1 1 - ( 61587 65535 22411 ) ( 61587 -65535 22411 ) ( -61137 -65535 -23610 ) ctf01 96 80 0 1 1 - ( 61823 -65535 -21779 ) ( 61823 65535 -21779 ) ( -60900 -65535 24241 ) ctf01 96 80 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) ctf01 96 80 0 1 1 - } - { //brush 1430 - ( 2848 65535 65535 ) ( 2848 -65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1431 - ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 47308 65535 45372 ) ( 47308 -65535 45372 ) ( -45372 -65535 -47308 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 1432 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - } - { //brush 1433 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 90 1 1 - } - { //brush 1434 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - } - { //brush 1435 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 1436 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - } - { //brush 1437 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1438 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1439 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1808 -65535 65535 ) ( 1808 65535 65535 ) ( 1808 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1440 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll02 0 0 90 1 1 - } - { //brush 1441 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1442 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1443 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( 65535 -61526 -22572 ) ( 65535 61197 23449 ) ( -65535 -61526 -22572 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 1444 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( 61258 69226 -6699 ) ( 61258 -57929 -38488 ) ( -60996 57765 39146 ) tile2492 0 0 0 1 1 - ( 60996 57765 39146 ) ( 60996 -69391 7356 ) ( -61258 69226 -6699 ) tile2492 0 0 0 1 1 - } - { //brush 1445 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1446 - ( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1447 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll02 0 0 90 1 1 - } - { //brush 1448 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1449 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1450 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1451 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( -65535 16 65535 ) ( 65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 0 1 1 - } - { //brush 1452 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - } - { //brush 1453 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 46348 46332 ) ( -65535 46348 46332 ) ( -65535 -46332 -46348 ) fstng_2 0 16 0 1 1 - } - { //brush 1454 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) ctf02 32 80 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) ctf02 32 80 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 32 80 0 1 1 - ( 60900 -65535 24241 ) ( 60900 65535 24241 ) ( -61823 -65535 -21779 ) ctf02 32 80 0 1 1 - ( 61137 65535 -23610 ) ( 61137 -65535 -23610 ) ( -61587 -65535 22411 ) ctf02 32 80 0 1 1 - } - { //brush 1455 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2848 -65535 65535 ) ( -2848 65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1456 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1457 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 1458 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 1459 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - } - { //brush 1460 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) ctf01 64 80 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) ctf01 64 80 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf01 64 80 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf01 64 80 180 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf01 64 80 90 1 1 - ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) ctf01 64 80 90 1 1 - } - { //brush 1461 - ( 2720 65535 65535 ) ( 2720 -65535 65535 ) ( 2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1462 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) ctf01 32 80 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 80 180 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) ctf01 32 80 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) ctf01 32 80 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf01 32 80 0 1 1 - ( 65535 -61197 23449 ) ( 65535 61526 -22572 ) ( -65535 -61197 23449 ) ctf01 32 80 90 1 1 - } - { //brush 1463 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 80 180 1 1 - ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 - ( 65535 -61526 -22572 ) ( 65535 61197 23449 ) ( -65535 -61526 -22572 ) ctf02 96 80 90 1 1 - } - { //brush 1464 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2720 -65535 65535 ) ( -2720 65535 65535 ) ( -2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1465 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( -1408 -65535 65535 ) ( -1408 65535 65535 ) ( -1408 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw2 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw2 0 0 0 1 1 - } - { //brush 1466 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1072 -65535 65535 ) ( -1072 65535 65535 ) ( -1072 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1467 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - } - { //brush 1468 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1469 - ( -1216 65535 65535 ) ( -1216 -65535 65535 ) ( -1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 0 1 1 - } - { //brush 1470 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1471 - ( -320 65535 65535 ) ( -320 -65535 65535 ) ( -320 65535 -65535 ) tile2492 0 0 0 1 1 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1472 - ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1473 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1474 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 1475 - ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 1476 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 1477 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 1478 - ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1479 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1480 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 - ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 - } - { //brush 1481 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -320 -65535 65535 ) ( -320 65535 65535 ) ( -320 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 1482 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1056 -65535 65535 ) ( -1056 65535 65535 ) ( -1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1483 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 - ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 - } - { //brush 1484 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1485 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) ctf01 64 80 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) ctf01 64 80 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf01 64 80 180 1 1 - ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) ctf01 64 80 90 1 1 - ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) ctf01 64 80 90 1 1 - } - { //brush 1486 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1487 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - } - { //brush 1488 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1489 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stnwll05 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 1490 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - ( -58219 -30101 65535 ) ( 59013 28514 65535 ) ( -58219 -30101 -65535 ) sky003 0 0 0 1 1 - ( 64593 -11074 65535 ) ( -64693 10472 65535 ) ( -64693 10472 -65535 ) sky003 0 0 0 1 1 - } - { //brush 1491 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) sky003 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) sky003 0 0 180 1 1 - } - { //brush 1492 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) sky003 0 0 180 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) sky003 0 0 90 1 1 - } -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "2" - { //brush 0 - ( 1776 65535 65535 ) ( 1776 -65535 65535 ) ( 1776 65535 -65535 ) door 0 -4 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } - { //brush 1 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) door 0 -4 0 1 1 - ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "2" - { //brush 0 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) door 0 12 0 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) door 0 12 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) door 0 12 0 1 1 - ( 1232 -65535 65535 ) ( 1232 65535 65535 ) ( 1232 65535 -65535 ) door 0 12 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - } -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1120 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "832 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "768 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "480 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "416 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1120 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "832 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "768 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "480 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "416 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "128 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "128 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "1920 1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "1408 1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1904 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1904 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "1128 0 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "2208 -456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1984 -456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "2208 -888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1984 -888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "744 944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "744 1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1176 944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1024 1456 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 -208 368" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 -304 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "1184 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "1184 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "640 0 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "384 -384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "384 384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "992 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "992 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 -128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 -400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1696 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1360 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 -440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1264 -440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 0 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 -416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 -416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 -208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 -208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2192 104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2192 -104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2400 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2400 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2064 0 384" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 1280 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 832 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 384 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 608 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 160 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1808 568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1808 1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 832 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 576 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1184 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1184 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2144 672 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2144 1440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2400 -520 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 -584 432" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1904 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1776 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1648 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1520 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1392 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1392 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1520 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1648 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1776 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1904 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "1392 1056 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1176 1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 0 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 1 0.7" - "origin" "2272 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "220" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 -128 360" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2400 -208 480" -} -{ - "classname" "func_plat" - "angle" "-2" - "height" "160" - "speed" "50" - { //brush 0 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 0 1 1 - ( 63787 -65534 -15058 ) ( 63787 65534 -15058 ) ( -63369 -65534 16730 ) fstng_2 0 0 0 1 1 - } - { //brush 1 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - } - { //brush 2 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - } - { //brush 3 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 90 1 1 - } - { //brush 4 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 90 1 1 - ( 63787 -65534 -15058 ) ( 63787 65534 -15058 ) ( -63369 -65534 16730 ) fstng_2 0 0 0 1 1 - } - { //brush 5 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 0 1 1 - } - { //brush 6 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 360 ) ( 65535 65535 360 ) ( -65535 -65535 360 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "64 -1056 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "33" - "targetname" "r_p_lite" - "origin" "2544 1056 512" -} -{ - "classname" "trigger_multiple" - "sounds" "0" - "wait" "0" - "delay" "0" - "team_no" "1" - "target" "r_guard" - "netname" "r_beam_trig" - "style" "32" - { //brush 0 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 2 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 3 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 4 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 5 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 6 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) fstng_0 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 7 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 8 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 9 - ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 0 1 1 - ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 10 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) trigger 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 - } - { //brush 11 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) trigger 0 0 0 1 1 - ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 12 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "i_t_g" - "noise" "weapons/lhit.wav" - "health" "-500" - "deathtype" " died\n" - "targetname" "r_guard" - "goal_effects" "1" - "group_no" "40" - "netname" "b_kill" - "origin" "2464 1056 449" -} -{ - "classname" "i_t_g" - "n_b" " deactivated reds lasers.\n" - "style" "33" - "targetname" "r_start" - "activate_goal_no" "186" - "b_b" "Reds Lasers are Down!\n" - "g_e" "3" - "noise" "misc/power.wav" - "remove_group_no" "40" - "wait" "20" - "message" "You have deactivated enemy Lasers!\n" - "netname" "r_power_off" - "target" "r_p_lite" - "origin" "2432 1056 449" -} -{ - "classname" "i_t_g" - "b_o" "Our lasers are back up!\n" - "b_t" "Enemy lasers are back up!\n" - "style" "33" - "restore_group_no" "40" - "delay_time" "20" - "goal_no" "186" - "b_b" "Reds Lasers are Restored!" - "wait" "0" - "netname" "r_power_on" - "target" "r_p_lite" - "origin" "2400 1056 449" -} -{ - "classname" "func_door" - "angle" "270" - "wait" "20" - "lip" "-8" - "dmg" "1000" - "targetname" "r_start" - "speed" "10000" - "sounds" "0" - { //brush 0 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) *lavakell5 0 0 0 1 1 - } - { //brush 1 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) *lavakell5 0 0 0 1 1 - } - { //brush 2 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) *lavakell5 0 0 0 1 1 - } - { //brush 3 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) *lavakell5 0 0 0 1 1 - } - { //brush 4 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) *lavakell5 0 0 0 1 1 - } -} -{ - "classname" "trigger_multiple" - "sounds" "4" - "wait" "5" - "message" "Laser deactivation switch\nPrevent of enemy usage!\n" - "style" "32" - "delay" "0" - "team_no" "2" - { //brush 0 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "trigger_multiple" - "sounds" "4" - "wait" "5" - "message" "Laser deactivation switch\nPress it!\n" - "style" "32" - "delay" "0" - "team_no" "1" - { //brush 0 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) trigger 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "func_button" - "angle" "270" - "delay" "0" - "lip" "-2" - "team_no" "1" - "targetname" "red_button" - "wait" "20" - "style" "36" - "target" "r_start" - { //brush 0 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 -520 65535 ) ( -65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_0 0 0 0 1 1 - } -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "1024 880 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "896 880 512" -} -{ - "classname" "info_player_teamspawn" - "netname" "team2_spawn" - "team_no" "2" - "origin" "800 960 514" -} -{ - "classname" "info_player_teamspawn" - "netname" "team2_spawn" - "team_no" "2" - "origin" "800 1088 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "1120 1088 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "1120 960 512" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "1056 1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "1096 1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "1136 1184 456" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "864 1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "824 1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "784 1184 456" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2272 -736 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2272 -608 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2208 -512 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2080 -512 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "1968 -496 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "1944 -536 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "1920 -576 504" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2208 -832 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2080 -832 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "1968 -848 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "1944 -808 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "1920 -768 504" -} -{ - "classname" "info_tfdetect" - "hook_out" "1" - "impulse" "4" - "b_n" "Capture the emeny flag. See the frozen.txt for detail.\n" - "b_t" "\nFrozen Fire\n\n\nSELECT TEAM\n“‘ BLUE\n”‘ RED \n" - "display_item_status1" "1" - "display_item_status2" "2" - "team_str_home" "Your Flag: Base." - "team_str_carried" "Your Flag: Carried by" - "team_str_moved" "Your Flag: Down." - "non_team_str_home" "Enemy Flag: Base." - "non_team_str_carried" "Enemy Flag: Carried by" - "non_team_str_moved" "Enemy Flag: Down." - "origin" "0 0 576" -} -{ - "classname" "info_player_start" - "origin" "0 0 504" -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "1" - { //brush 0 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) door 0 -4 0 1 1 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } - { //brush 1 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) door 0 -4 0 1 1 - ( -1776 -65535 65535 ) ( -1776 65535 65535 ) ( -1776 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "1" - { //brush 0 - ( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) door 0 12 0 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - } - { //brush 1 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) door 0 12 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1120 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-832 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-768 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-480 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-416 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1120 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-832 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-768 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-480 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-416 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-128 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-128 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-1920 -1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-1408 -1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1904 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1904 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1128 0 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-2208 456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1984 456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-2208 888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1984 888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-744 -944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-744 -1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1176 -944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1024 -1456 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 208 368" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 304 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1184 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1184 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-640 0 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-384 384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-384 -384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-992 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-992 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 -128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 -400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1696 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1360 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1264 440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 0 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2192 -104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2192 104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2400 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2400 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2064 0 384" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -1280 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -832 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -384 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -608 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -160 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1808 -568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 -568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1808 -1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 -1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "0 0 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 -832 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 -576 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1184 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1184 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2144 -672 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2144 -1440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2400 520 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 584 432" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1904 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1776 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1648 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1520 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1392 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1392 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1520 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1648 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1776 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1904 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1392 -1056 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1176 -1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 0 512" -} + + +/* { - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2272 0 336" + "classname" "trigger_multiple" + "sounds" "0" + "wait" "0" + "delay" "0" + "team_no" "1" + "target" "r_guard" + "netname" "r_beam_trig" + "style" "32" + } +*/ + + { - "classname" "light" - "angle" "-2" - "light" "220" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 128 360" + "classname" "i_t_g" + "noise" "weapons/lhit.wav" + "health" "-500" + "deathtype" " died\n" + "targetname" "r_guard" + "goal_effects" "1" + "group_no" "40" + "netname" "b_kill" + "origin" "2464 1056 449" } + { - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2400 208 480" + "classname" "func_button" + "angle" "270" + "delay" "0" + "lip" "-2" + "team_no" "1" + "targetname" "red_button" + "wait" "20" + "style" "36" + "target" "r_start" } + { - "classname" "func_plat" - "angle" "-2" - "height" "160" - "speed" "50" + "classname" "func_door" + "angle" "270" + "wait" "20" + "lip" "-8" + "dmg" "1000" + "targetname" "r_start" + "speed" "10000" + "sounds" "0" { //brush 0 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 0 1 1 - ( 63369 -65534 16730 ) ( 63369 65534 16730 ) ( -63787 -65534 -15058 ) fstng_2 0 0 0 1 1 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) *lavakell5 0 0 0 1 1 } { //brush 1 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) *lavakell5 0 0 0 1 1 } { //brush 2 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) *lavakell5 0 0 0 1 1 } { //brush 3 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 90 1 1 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) *lavakell5 0 0 0 1 1 } { //brush 4 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 90 1 1 - ( 63369 -65534 16730 ) ( 63369 65534 16730 ) ( -63787 -65534 -15058 ) fstng_2 0 0 0 1 1 - } - { //brush 5 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 0 1 1 - } - { //brush 6 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 360 ) ( 65535 65535 360 ) ( -65535 -65535 360 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 + ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 + ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 + ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) *lavakell5 0 0 0 1 1 + ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) *lavakell5 0 0 0 1 1 } } + { - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-64 1056 240" + "classname" "i_t_g" + "n_b" " deactivated reds lasers.\n" + "style" "33" + "targetname" "r_start" + "activate_goal_no" "186" + "b_b" "Reds Lasers are Down!\n" + "g_e" "3" + "noise" "misc/power.wav" + "remove_group_no" "40" + "wait" "20" + "message" "You have deactivated enemy Lasers!\n" + "netname" "r_power_off" + "target" "r_p_lite" + "origin" "2432 1056 449" } { - "classname" "light" - "angle" "-2" - "light" "200" + "classname" "i_t_g" + "b_o" "Our lasers are back up!\n" + "b_t" "Enemy lasers are back up!\n" "style" "33" - "targetname" "b_p_lite" - "origin" "-2544 -1056 512" + "restore_group_no" "40" + "delay_time" "20" + "goal_no" "186" + "b_b" "Reds Lasers are Restored!" + "wait" "0" + "netname" "r_power_on" + "target" "r_p_lite" + "origin" "2400 1056 449" +} + + + + +{ + "classname" "trigger_multiple" + "sounds" "4" + "wait" "5" + "message" "Laser deactivation switch\nPrevent of enemy usage!\n" + "style" "32" + "delay" "0" + "team_no" "2" + { //brush 0 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 + ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) trigger 0 0 0 1 1 + } +} +{ + "classname" "trigger_multiple" + "sounds" "4" + "wait" "5" + "message" "Laser deactivation switch\nPress it!\n" + "style" "32" + "delay" "0" + "team_no" "1" + { //brush 0 + ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 + ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 + ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 + ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 + ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) trigger 0 0 0 1 1 + ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 + } } + + + + + { "classname" "i_t_g" "noise" "weapons/lhit.wav" @@ -14601,400 +435,4 @@ ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_0 0 0 0 1 1 } } -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-1024 -880 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-896 -880 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-800 -960 514" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-800 -1088 512" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-1120 -1088 512" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-1120 -960 512" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-1056 -1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-1096 -1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-1136 -1184 456" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-864 -1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-824 -1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-784 -1184 456" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2272 736 560" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2272 608 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2208 512 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2080 512 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-1968 496 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-1944 536 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-1920 576 504" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2208 832 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2080 832 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-1968 848 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-1944 808 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-1920 770 504" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "208 0 224" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "-208 0 224" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 0 224" -} -{ - "classname" "light" - "angle" "-2" - "light" "450" - "style" "0" - "origin" "0 -288 384" -} -{ - "classname" "light" - "angle" "-2" - "light" "450" - "style" "0" - "origin" "0 288 384" -} -{ - "classname" "item_tfgoal" - "angle" "145" - "netname" "blue flag" - "mdl" "progs/tf_stan.mdl" - "skin" "1" - "goal_no" "1" - "g_a" "693" - "g_e" "1" - "goal_result" "18" - "team_no" "2" - "owned_by" "1" - "items" "131072" - "pausetime" "30" - "n_b" " StolE ThE ΒΜΥΕ FlaG!\n" - "message" "YoU HavE ThE EnemY FlaG!\nΥΞ ΜΙΛΕ ΘΕΜΜ‘\n" - "d_n_t" " ΜοσΤ YouR FLAG‘\n" - "d_n_n" " ΜοσΤ ΤθΕ BLUE FLAG‘\n" - "b_n" "YouR FlaG HaS BeeN StoleN!!\nΗεΤ ΕΝ‘\n" - "b_t" "Ωου ΤεαΝ ΣτομΕ ΤθΕ EnemieS FlaG‘\n" - "noise" "flagtaken.wav" - "noise3" "Your flag was returned to base!" - "noise4" "The enemy flag was returned to base!" - "origin" "-2560 -1056 392" -} -{ - "classname" "i_t_g" - "netname" "blue capture" - "axhitme" "2" - "count" "10" - "frags" "10" - "noise" "items/cap2.wav" - "message" "Ωου ΤεαΝ ΟχεΣ ΩοΥ ΒιΗ‘\nΊ©\n" - "g_a" "1" - "g_e" "2" - "items_allowed" "2" - "team_no" "1" - "b_t" "€ƒƒƒƒ‚\n“’ ΖςαηΣ Ζο Ωα‘‘\n€ƒƒƒ‚\n" - "b_n" "Ωου FLAG ΧαΣ CAPTURED‘\nΊ―\n" - "origin" "-2560 224 384" -} -{ - "classname" "i_t_g" - "netname" "red capture" - "g_a" "1" - "team_no" "2" - "items_allowed" "1" - "g_e" "2" - "axhitme" "1" - "count" "10" - "frags" "10" - "message" "Ωου ΤεαΝ ΟχεΣ ΩοΥ ΒιΗ‘\nΊ©\n" - "b_t" "€ƒƒƒƒ‚\n“’ ΖςαηΣ Ζο Ωα‘‘\n€ƒƒƒ‚\n" - "b_n" "Ωου FLAG ΧαΣ CAPTURED‘\nΊ―\n" - "noise" "items/cap2.wav" - "origin" "2560 -224 384" -} -{ - "classname" "item_tfgoal" - "angle" "315" - "netname" "red flag" - "mdl" "progs/tf_stan.mdl" - "skin" "2" - "goal_no" "2" - "g_a" "693" - "g_e" "1" - "goal_result" "18" - "team_no" "1" - "owned_by" "2" - "items" "262144" - "pausetime" "30" - "n_b" " StolE ThE ΕΔ FlaG!\n" - "message" "YoU HavE ThE EnemY FlaG!\nΥΞ ΜΙΛΕ ΘΕΜΜ‘\n" - "d_n_t" " ΜοσΤ YouR FLAG‘\n" - "d_n_n" " ΜοσΤ ΤθΕ RED FLAG‘\n" - "b_n" "YouR FlaG HaS BeeN StoleN!!\nΗεΤ ΕΝ‘\n" - "b_t" "Ωου ΤεαΝ ΣτομΕ ΤθΕ EnemieS FlaG‘\n" - "noise" "flagtaken.wav" - "noise3" "Your flag was returned to base!" - "noise4" "The enemy flag was returned to base!" - "origin" "2560 1056 392" -} -//total of 1557 brushes + diff --git a/q3f_openfire2b working copy.map b/q3f_openfire2b working copy.map index 9aa7dfa8..b10827f1 100644 --- a/q3f_openfire2b working copy.map +++ b/q3f_openfire2b working copy.map @@ -5,21 +5,7 @@ "origin" "2433 1150 239" "checkstate" "t1=inactive" } -// entity 103 -{ -"allowteams" "red" -"classname" "trigger_multiple" -"target" "kill" -// brush 0 -{ -( 2483 -65535 65535 ) ( 2483 65535 65535 ) ( 2483 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 2477 65535 65535 ) ( 2477 -65535 65535 ) ( 2477 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -65535 128 ) ( 65535 65535 128 ) ( -65535 -65535 128 ) e2u3/floor1_2 0 0 0 1 1 -} -} + // entity 104 { "targetname" "t1" @@ -115,6 +101,13 @@ } + + + + + + + // entity 113 { "speed" "9999" @@ -131,15 +124,6 @@ "wait" "30" "activetarget" "t2" "allowteams" "blue" -// brush 0 -{ -( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -2351 65535 65535 ) ( -2351 -65535 65535 ) ( -2351 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 504 65535 ) ( -65535 504 65535 ) ( -65535 504 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -65535 496 65535 ) ( 65535 496 65535 ) ( -65535 496 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -65535 144 ) ( 65535 65535 144 ) ( -65535 -65535 144 ) e2u3/floor1_2 0 0 0 1 1 -} } // entity 115 { @@ -187,11 +171,4 @@ "targetname" "t2" } -// entity 207 -{ -"origin" "0 -320 -192" -"noise" "sound/world/curnt2.wav" -"classname" "target_speaker" -"spawnflags" "1" -} diff --git a/stag3.map b/stag3.map index 0f3e06d3..a6171dbd 100644 --- a/stag3.map +++ b/stag3.map @@ -32,11 +32,7 @@ "non_team_broadcast" "Your flag has been taken!\n" "d_n_n" " dropped blue's flag.\n" } -// entity 68 -{ -"origin" "-272 935 -3184" -"classname" "info_player_start" -} + // entity 69 { "origin" "-208 1280 -3168" From 925bc87274344146ec7a7d5c308069845240fb5c Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 23 Nov 2018 14:04:51 +1100 Subject: [PATCH 0502/2474] remove .maps from master branch --- frozen1.map | 15000 ------------------------------ q3f_openfire2b working copy.map | 197 - stag3.map | 1044 --- 3 files changed, 16241 deletions(-) delete mode 100644 frozen1.map delete mode 100644 q3f_openfire2b working copy.map delete mode 100644 stag3.map diff --git a/frozen1.map b/frozen1.map deleted file mode 100644 index c88d265c..00000000 --- a/frozen1.map +++ /dev/null @@ -1,15000 +0,0 @@ -//===================================================== -// -// map file created with BSPC v1.6 -// -// BSPC is created by Mr Elusive -// -// -//===================================================== -{ - "classname" "worldspawn" - "sounds" "1" - "light" "50" - "message" "Frozen Fire v1.1\nby Night Hunter\nhttp://clan.sd.ru" - "wad" "d:\games\quake\worldcraft\wads\apocrypha.wad;d:\games\quake\worldcraft\wads\dethtex_gothic.wad;d:\games\quake\worldcraf" - { //brush 0 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 58392 65534 -29756 ) ( 58392 -65534 -29756 ) ( -58840 -65534 28860 ) stonesnow 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 2 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 3 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 - ( 63647 65534 15615 ) ( 63647 -65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 - } - { //brush 4 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 0 1 1 - ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) fstng_2 0 16 0 1 1 - } - { //brush 5 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -31464 -57537 65535 ) ( 27151 59694 65535 ) ( 27151 59694 -65535 ) stnwll01 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 6 - ( -880 65535 65535 ) ( -880 -65535 65535 ) ( -880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 58952 28636 65535 ) ( -58280 -29980 65535 ) ( -58280 -29980 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 7 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 - } - { //brush 8 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 9 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 10 - ( 64 65535 65535 ) ( 64 -65535 65535 ) ( 64 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 11 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 - ( 47244 65535 45436 ) ( 47244 -65535 45436 ) ( -45436 65535 -47244 ) fstng_2 0 16 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 0 1 1 - ( -65535 -46348 46332 ) ( 65535 -46348 46332 ) ( 65535 46332 -46348 ) fstng_2 0 16 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 - } - { //brush 12 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -64 -65535 65535 ) ( -64 65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( 60996 -69391 7356 ) ( 60996 57765 39146 ) ( -61258 69226 -6699 ) tile2492 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) tile2492 0 0 0 1 1 - } - { //brush 13 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( 47308 -65535 45372 ) ( 47308 65535 45372 ) ( -45372 -65535 -47308 ) fstng_2 0 16 90 1 1 - } - { //brush 14 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 15 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - } - { //brush 16 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - ( -57573 31394 65535 ) ( 59659 -27221 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 17 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 180 1 1 - ( -44652 65535 48028 ) ( -44652 -65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 - } - { //brush 18 - ( 1824 65535 65535 ) ( 1824 -65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 19 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( -65534 17219 63246 ) ( 65534 17219 63246 ) ( -65534 -14569 -63909 ) stnwll02 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 20 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 21 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( -65534 17219 63246 ) ( 65534 17219 63246 ) ( -65534 -14569 -63909 ) stnwll02 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 22 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 0 1 1 - } - { //brush 23 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 0 1 1 - } - { //brush 24 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - } - { //brush 25 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 26 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -160 65535 ) ( 65535 -160 65535 ) ( -65535 -160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 27 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -192 65535 ) ( 65535 -192 65535 ) ( -65535 -192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -160 65535 ) ( -65535 -160 65535 ) ( -65535 -160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 28 - ( 65535 -192 65535 ) ( -65535 -192 65535 ) ( -65535 -192 -65535 ) ftlattice2 16 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 65535 -63467 16338 ) ( 65535 63689 -15450 ) ( -65535 -63467 16338 ) ftlattice2 16 0 0 1 1 - ( 65535 -63713 -15352 ) ( 65535 63442 16436 ) ( -65535 -63713 -15352 ) ftlattice2 16 0 0 1 1 - ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 0 0 1 1 - ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 0 0 1 1 - } - { //brush 29 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -224 65535 ) ( 65535 -224 65535 ) ( -65535 -224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -192 65535 ) ( -65535 -192 65535 ) ( -65535 -192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 30 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -224 65535 ) ( -65535 -224 65535 ) ( -65535 -224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 31 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 32 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -63355 16786 ) ( 65535 63801 -15002 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 33 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 65535 -63355 16786 ) ( 65535 63801 -15002 ) ( -65535 -63355 16786 ) millgt1 16 16 0 1 1 - ( 65535 -63631 -15679 ) ( 65535 63524 16109 ) ( -65535 -63631 -15679 ) millgt1 16 16 0 1 1 - ( 63566 -65534 15943 ) ( 63566 65534 15943 ) ( -63590 -65534 -15845 ) millgt1 16 16 0 1 1 - ( 63842 -65534 -14836 ) ( 63842 65534 -14836 ) ( -63313 -65534 16952 ) millgt1 16 16 0 1 1 - } - { //brush 34 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1296 65535 ) ( 65535 1296 65535 ) ( -65535 1296 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 0 1 1 - } - { //brush 35 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1264 65535 ) ( 65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 36 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 1264 65535 ) ( 65535 1264 65535 ) ( -65535 1264 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 1296 65535 ) ( -65535 1296 65535 ) ( -65535 1296 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) millgt1 16 0 90 1 0.500000 - ( 18108 -65534 63024 ) ( 18108 65534 63024 ) ( -13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - } - { //brush 37 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -57649 31240 65535 ) ( 59582 -27375 65535 ) ( -57649 31240 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 38 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 16 0 1 1 - ( 65535 -63639 -15649 ) ( 65535 63517 16139 ) ( -65535 -63639 -15649 ) millgt1 0 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) millgt1 0 16 0 1 1 - ( 63851 -65534 -14802 ) ( 63851 65534 -14802 ) ( -63305 -65534 16986 ) millgt1 0 16 0 1 1 - ( 63604 -65534 15789 ) ( 63604 65534 15789 ) ( -63551 -65534 -15999 ) millgt1 0 16 0 1 1 - } - { //brush 39 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 58737 29064 65535 ) ( -58494 -29551 65535 ) ( -58494 -29551 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 40 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 816 65535 ) ( 65535 816 65535 ) ( -65535 816 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 848 65535 ) ( -65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 90 1 1 - } - { //brush 41 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 816 65535 ) ( 65535 816 65535 ) ( -65535 816 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 848 65535 ) ( -65535 848 65535 ) ( -65535 848 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) millgt1 16 0 90 1 0.500000 - ( 18108 -65534 63024 ) ( 18108 65534 63024 ) ( -13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - } - { //brush 42 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 816 65535 ) ( -65535 816 65535 ) ( -65535 816 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) stnwll02 0 0 0 1 1 - } - { //brush 43 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_0 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 63801 -15002 ) ( 65535 -63355 16786 ) ( -65535 -63355 16786 ) fstng_0 0 0 0 1 1 - } - { //brush 44 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 180 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - } - { //brush 45 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28130 -59205 65535 ) ( 30485 58027 65535 ) ( 30485 58027 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 46 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28104 -59217 65535 ) ( 30511 58014 65535 ) ( 30511 58014 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 47 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28079 -59230 65535 ) ( 30536 58001 65535 ) ( 30536 58001 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 48 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 180 1 1 - ( -28053 -59243 65535 ) ( 30562 57989 65535 ) ( 30562 57989 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 49 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 0 0 1 1 - ( -27068 59736 65535 ) ( 31548 -57496 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 50 - ( 2656 65535 65535 ) ( 2656 -65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 51 - ( 2656 65535 65535 ) ( 2656 -65535 65535 ) ( 2656 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 52 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) ftlattice2 16 16 0 1 1 - ( 65535 -63726 -15303 ) ( 65535 63430 16485 ) ( -65535 -63726 -15303 ) ftlattice2 16 16 0 1 1 - ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 16 0 1 1 - ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 16 0 1 1 - } - { //brush 53 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - } - { //brush 54 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 63850 -65534 -14806 ) ( 63850 65534 -14806 ) ( -63306 -65534 16982 ) ftlattice2 16 0 0 1 1 - ( 63603 -65534 15792 ) ( 63603 65534 15792 ) ( -63552 -65534 -15996 ) ftlattice2 16 0 0 1 1 - ( 65535 -63467 16338 ) ( 65535 63689 -15450 ) ( -65535 -63467 16338 ) ftlattice2 16 0 0 1 1 - ( 65535 -63713 -15352 ) ( 65535 63442 16436 ) ( -65535 -63713 -15352 ) ftlattice2 16 0 0 1 1 - } - { //brush 55 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 - } - { //brush 56 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 57 - ( 2624 65535 65535 ) ( 2624 -65535 65535 ) ( 2624 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - } - { //brush 58 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2624 -65535 65535 ) ( 2624 65535 65535 ) ( 2624 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 59 - ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 60 - ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 59032 -28476 ) ( 65535 -58200 30140 ) ( -65535 -58200 30140 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 61 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 62 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 - } - { //brush 63 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1312 65535 ) ( 65535 1312 65535 ) ( -65535 1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1344 65535 ) ( -65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 - } - { //brush 64 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 1424 65535 ) ( 65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 65 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -63800 -15006 65535 ) ( 63356 16783 65535 ) ( -63800 -15006 -65535 ) shootit 0 8 0 1 1 - ( -63132 17679 65535 ) ( 64024 -14110 65535 ) ( -63132 17679 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - } - { //brush 66 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -63162 17558 65535 ) ( 63994 -14230 65535 ) ( -63162 17558 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63830 -14885 65535 ) ( 63326 16903 65535 ) ( -63830 -14885 -65535 ) shootit 0 8 0 1 1 - } - { //brush 67 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63822 -14915 65535 ) ( 63333 16873 65535 ) ( -63822 -14915 -65535 ) shootit 0 8 0 1 1 - ( -63154 17588 65535 ) ( 64001 -14200 65535 ) ( -63154 17588 -65535 ) shootit 0 8 0 1 1 - } - { //brush 68 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63139 17648 65535 ) ( 64016 -14140 65535 ) ( -63139 17648 -65535 ) shootit 0 8 0 1 1 - ( -63807 -14975 65535 ) ( 63348 16813 65535 ) ( -63807 -14975 -65535 ) shootit 0 8 0 1 1 - } - { //brush 69 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) shootit 0 8 0 1 1 - ( -65534 17165 63260 ) ( 65534 17165 63260 ) ( -65534 -14623 -63895 ) shootit 0 8 0 1 1 - ( -65534 -14492 63928 ) ( 65534 -14492 63928 ) ( -65534 17296 -63227 ) shootit 0 8 0 1 1 - ( -63815 -14945 65535 ) ( 63341 16843 65535 ) ( -63815 -14945 -65535 ) shootit 0 8 0 1 1 - ( -63147 17618 65535 ) ( 64009 -14170 65535 ) ( -63147 17618 -65535 ) shootit 0 8 0 1 1 - } - { //brush 70 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58424 -29692 ) ( 65535 58808 28924 ) ( -65535 -58424 -29692 ) stnwll05 0 0 90 1 1 - } - { //brush 71 - ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58424 -29692 ) ( 65535 58808 28924 ) ( -65535 -58424 -29692 ) stnwll05 0 0 90 1 1 - } - { //brush 72 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 1408 65535 ) ( 65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1424 65535 ) ( -65535 1424 65535 ) ( -65535 1424 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58808 28924 ) ( 65535 -58424 -29692 ) ( -65535 -58424 -29692 ) stnfloor02 0 0 0 1 1 - } - { //brush 73 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 74 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 75 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) millgt1 16 0 0 1 1 - ( 63507 -65534 16176 ) ( 63507 65534 16176 ) ( -63648 -65534 -15612 ) millgt1 16 0 0 1 1 - ( 65535 -63361 16760 ) ( 65535 63794 -15028 ) ( -65535 -63361 16760 ) millgt1 16 0 0 1 1 - ( 63769 -65534 -15130 ) ( 63769 65534 -15130 ) ( -63387 -65534 16658 ) millgt1 16 0 0 1 1 - ( 65535 -63623 -15713 ) ( 65535 63533 16075 ) ( -65535 -63623 -15713 ) millgt1 16 0 0 1 1 - } - { //brush 76 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 880 -65535 65535 ) ( 880 65535 65535 ) ( 880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 77 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 78 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) fstng_2 0 0 0 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 79 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 80 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - } - { //brush 81 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -45524 65535 47156 ) ( -45524 -65535 47156 ) ( 47156 65535 -45524 ) fstng_2 0 16 90 1 1 - } - { //brush 82 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 - } - { //brush 83 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 84 - ( 2136 65535 65535 ) ( 2136 -65535 65535 ) ( 2136 65535 -65535 ) ctf07 0 16 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 16 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) ctf07 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) ctf07 0 16 0 1 1 - } - { //brush 85 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 86 - ( 2136 65535 65535 ) ( 2136 -65535 65535 ) ( 2136 65535 -65535 ) ctf07 0 16 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) ctf07 0 16 180 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) ctf07 0 16 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) ctf07 0 16 90 1 1 - } - { //brush 87 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 88 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 16 0 1 1 - ( -44964 65535 47716 ) ( -44964 -65535 47716 ) ( 47716 65535 -44964 ) fstng_2 0 16 90 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - } - { //brush 89 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 90 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 180 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 0 1 1 - ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 91 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 90 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 180 1 1 - } - { //brush 92 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63749 65534 -15209 ) ( 63749 -65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 0 1 1 - } - { //brush 93 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 90 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 94 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 90 1 1 - } - { //brush 95 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stnwll05 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stnwll05 0 0 0 1 1 - } - { //brush 96 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63749 65534 -15209 ) ( 63749 -65534 -15209 ) ( -63406 -65534 16579 ) stonesnw 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 97 - ( 2080 -65535 65535 ) ( 2080 65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -27170 59685 65535 ) ( 31445 -57547 65535 ) ( -27170 59685 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - } - { //brush 98 - ( 2080 -65535 65535 ) ( 2080 65535 65535 ) ( 2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 0 1 1 - } - { //brush 99 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 624 65535 ) ( 65535 624 65535 ) ( -65535 624 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 100 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 624 65535 ) ( -65535 624 65535 ) ( -65535 624 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 101 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 400 65535 ) ( 65535 400 65535 ) ( -65535 400 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 102 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 368 65535 ) ( 65535 368 65535 ) ( -65535 368 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 400 65535 ) ( -65535 400 65535 ) ( -65535 400 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 103 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 368 65535 ) ( -65535 368 65535 ) ( -65535 368 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 104 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 105 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 176 65535 ) ( 65535 176 65535 ) ( -65535 176 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 106 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 176 65535 ) ( -65535 176 65535 ) ( -65535 176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - ( 18108 65534 63024 ) ( 18108 -65534 63024 ) ( -13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 107 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 108 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 109 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( -65535 45836 46844 ) ( 65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 - ( 58878 -28783 65535 ) ( -58353 29832 65535 ) ( -58353 29832 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 110 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) metdec1 32 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 63809 65534 -14968 ) ( 63809 -65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) metdec1 32 0 0 1 1 - } - { //brush 111 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 112 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 113 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) millgt1 16 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 114 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 115 - ( 2528 65535 65535 ) ( 2528 -65535 65535 ) ( 2528 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2560 -65535 65535 ) ( 2560 65535 65535 ) ( 2560 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 116 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 117 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 118 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) millgt1 16 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 119 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll02 0 0 90 1 1 - } - { //brush 120 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 121 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 0 1 1 - ( 31381 -57579 65535 ) ( -27234 59653 65535 ) ( -27234 59653 -65535 ) fstng_2 0 0 0 1 1 - ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 122 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 31407 -57566 65535 ) ( -27208 59665 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 0 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 180 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 123 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_0 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 124 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 125 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_0 0 0 180 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 126 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 65535 -63400 16606 ) ( 65535 63756 -15183 ) ( -65535 -63400 16606 ) millgt1 16 16 0 1 1 - ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) millgt1 16 16 0 1 1 - ( 63842 -65534 -14836 ) ( 63842 65534 -14836 ) ( -63313 -65534 16952 ) millgt1 16 16 0 1 1 - ( 63566 -65534 15943 ) ( 63566 65534 15943 ) ( -63590 -65534 -15845 ) millgt1 16 16 0 1 1 - } - { //brush 127 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 31330 -57605 65535 ) ( -27285 59627 65535 ) ( -27285 59627 -65535 ) fstng_2 0 0 0 1 1 - ( 30703 57918 65535 ) ( -27912 -59313 65535 ) ( 30703 57918 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 128 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 129 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( 31356 -57592 65535 ) ( -27260 59640 65535 ) ( -27260 59640 -65535 ) fstng_2 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 130 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -28757 -58891 65535 ) ( 29858 58341 65535 ) ( 29858 58341 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 131 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 864 65535 ) ( 65535 864 65535 ) ( -65535 864 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( 30703 -57918 65535 ) ( -27912 59313 65535 ) ( -27912 59313 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 132 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 864 65535 ) ( -65535 864 65535 ) ( -65535 864 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 133 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - } - { //brush 134 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 - } - { //brush 135 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) ctf07 0 16 0 1 1 - ( 1240 -65535 65535 ) ( 1240 65535 65535 ) ( 1240 65535 -65535 ) ctf07 0 16 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 16 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf07 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf07 0 16 90 1 1 - } - { //brush 136 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 - } - { //brush 137 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - } - { //brush 138 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -62234 -20536 65535 ) ( 62109 20911 65535 ) ( -62234 -20536 -65535 ) mtn 0 0 0 1 1 - } - { //brush 139 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - } - { //brush 140 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64693 -10472 65535 ) ( 64593 11074 65535 ) ( -64693 -10472 -65535 ) mtn 0 0 0 1 1 - ( -58219 30101 65535 ) ( 59013 -28514 65535 ) ( -58219 30101 -65535 ) mtn 0 0 0 1 1 - } - { //brush 141 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 62109 20911 65535 ) ( -62234 -20536 65535 ) ( -62234 -20536 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 142 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 62109 20911 65535 ) ( -62234 -20536 65535 ) ( -62234 -20536 -65535 ) stnfloor02 0 0 0 1 1 - } - { //brush 143 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 - } - { //brush 144 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) ftlattice2 16 0 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 0 0 1 1 - ( 65535 -63408 16572 ) ( 65535 63747 -15216 ) ( -65535 -63408 16572 ) ftlattice2 16 0 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 0 0 1 1 - } - { //brush 145 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 146 - ( 1568 65535 65535 ) ( 1568 -65535 65535 ) ( 1568 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stonesnw 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnw 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 - } - { //brush 147 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 58558 29423 65535 ) ( -58673 -29192 65535 ) ( -58673 -29192 -65535 ) stonesnw 0 0 0 1 1 - ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) stonesnw 0 0 0 1 1 - } - { //brush 148 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) stonesnow 0 0 0 1 1 - ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stonesnow 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 149 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 - } - { //brush 150 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 - } - { //brush 151 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 800 65535 ) ( -65535 800 65535 ) ( -65535 800 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 - } - { //brush 152 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 153 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 0 1 1 - ( -28680 -58929 65535 ) ( 29935 58302 65535 ) ( 29935 58302 -65535 ) stnwll05 0 0 0 1 1 - ( 30780 -57880 65535 ) ( -27836 59352 65535 ) ( -27836 59352 -65535 ) stnwll05 0 0 0 1 1 - ( 59086 65534 -28367 ) ( 59086 -65534 -28367 ) ( -58145 -65534 30248 ) stnfloor02 0 0 0 1 1 - } - { //brush 154 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 30780 -57880 65535 ) ( -27836 59352 65535 ) ( -27836 59352 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 155 - ( 1256 65535 65535 ) ( 1256 -65535 65535 ) ( 1256 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 61626 -22305 ) ( 65535 -61098 23715 ) ( -65535 -61098 23715 ) stnfloor02 0 0 0 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 65535 61358 23021 ) ( 65535 -61366 -23000 ) ( -65535 -61366 -23000 ) stnfloor02 0 0 0 1 1 - } - { //brush 156 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) ctf01 32 0 0 1 1 - ( 1256 -65535 65535 ) ( 1256 65535 65535 ) ( 1256 65535 -65535 ) ctf01 32 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 0 180 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) ctf01 32 0 180 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) ctf01 32 0 90 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 157 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1264 -65535 65535 ) ( 1264 65535 65535 ) ( 1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( -28680 -58929 65535 ) ( 29935 58302 65535 ) ( 29935 58302 -65535 ) stnwll05 0 0 0 1 1 - ( 30181 -65534 58179 ) ( 30181 65534 58179 ) ( -28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 158 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 159 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll01 0 0 0 1 1 - } - { //brush 160 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - ( 16880 65534 63331 ) ( 16880 -65534 63331 ) ( -14908 65534 -63824 ) stnwll01 0 0 0 1 1 - } - { //brush 161 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( -45476 65535 47204 ) ( -45476 -65535 47204 ) ( 47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - ( 16880 -65534 63331 ) ( 16880 65534 63331 ) ( -14908 65534 -63824 ) millgt1 0 0 0 1 0.500000 - } - { //brush 162 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( -45476 65535 47204 ) ( -45476 -65535 47204 ) ( 47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - } - { //brush 163 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 16880 65534 63331 ) ( 16880 -65534 63331 ) ( -14908 65534 -63824 ) stnwll01 0 0 0 1 1 - ( -45476 -65535 47204 ) ( -45476 65535 47204 ) ( 47204 65535 -45476 ) stnwll01 0 0 90 1 1 - } - { //brush 164 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 165 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 166 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 167 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 168 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) shootit 16 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) shootit 16 0 180 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 169 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) shootit 16 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 170 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - } - { //brush 171 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 - } - { //brush 172 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 832 65535 ) ( 65535 832 65535 ) ( -65535 832 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -45524 65535 47156 ) ( -45524 -65535 47156 ) ( 47156 65535 -45524 ) fstng_2 0 16 90 1 1 - } - { //brush 173 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -57896 30748 65535 ) ( 59336 -27868 65535 ) ( -57896 30748 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 174 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 832 65535 ) ( 65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 175 - ( 1136 65535 65535 ) ( 1136 -65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 176 - ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 177 - ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) shootit 16 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 178 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1104 -65535 65535 ) ( 1104 65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 179 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 180 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 181 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 182 - ( 1136 65535 65535 ) ( 1136 -65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 183 - ( 1104 65535 65535 ) ( 1104 -65535 65535 ) ( 1104 65535 -65535 ) shootit 16 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 184 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1104 -65535 65535 ) ( 1104 65535 65535 ) ( 1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 185 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 186 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 187 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 188 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 - } - { //brush 189 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 - } - { //brush 190 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 46508 65535 46172 ) ( 46508 -65535 46172 ) ( -46172 65535 -46508 ) stnwll02 0 0 0 1 1 - ( -58699 -29141 65535 ) ( 58533 29474 65535 ) ( -58699 -29141 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 191 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - } - { //brush 192 - ( 1824 65535 65535 ) ( 1824 -65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 193 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 0 1 0.500000 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15231 63743 ) ( 65534 -15231 63743 ) ( -65534 16557 -63412 ) millgt1 0 0 0 1 0.500000 - } - { //brush 194 - ( 1792 65535 65535 ) ( 1792 -65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1824 -65535 65535 ) ( 1824 65535 65535 ) ( 1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 - ( 65534 -15231 63743 ) ( -65534 -15231 63743 ) ( -65534 16557 -63412 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - } - { //brush 195 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 196 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 0 1 0.500000 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15231 63743 ) ( 65534 -15231 63743 ) ( -65534 16557 -63412 ) millgt1 0 0 0 1 0.500000 - } - { //brush 197 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - ( 65534 -15231 63743 ) ( -65534 -15231 63743 ) ( -65534 16557 -63412 ) stnwll02 0 0 0 1 1 - } - { //brush 198 - ( 1184 65535 65535 ) ( 1184 -65535 65535 ) ( 1184 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - } - { //brush 199 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1152 -65535 65535 ) ( 1152 65535 65535 ) ( 1152 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 200 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1184 -65535 65535 ) ( 1184 65535 65535 ) ( 1184 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 0 1 1 - } - { //brush 201 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - ( -45484 65535 47196 ) ( -45484 -65535 47196 ) ( 47196 65535 -45484 ) fstng_2 0 16 90 1 1 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) fstng_2 0 16 0 1 1 - } - { //brush 202 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1184 -65535 65535 ) ( 1184 65535 65535 ) ( 1184 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - ( 58533 29474 65535 ) ( -58699 -29141 65535 ) ( -58699 -29141 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 203 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 704 65535 ) ( 65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 58622 29295 ) ( 65535 -58609 -29320 ) ( -65535 -58609 -29320 ) stnwll05 0 0 90 1 1 - ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 204 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 63830 -14885 65535 ) ( -63326 16903 65535 ) ( -63326 16903 -65535 ) shootit 0 8 0 1 1 - ( 63504 16188 65535 ) ( -63651 -15600 65535 ) ( -63651 -15600 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - } - { //brush 205 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 63512 16158 65535 ) ( -63644 -15631 65535 ) ( -63644 -15631 -65535 ) shootit 0 8 0 1 1 - ( 63838 -14855 65535 ) ( -63318 16933 65535 ) ( -63318 16933 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - } - { //brush 206 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - ( 63845 -14825 65535 ) ( -63310 16963 65535 ) ( -63310 16963 -65535 ) shootit 0 8 0 1 1 - ( 63519 16127 65535 ) ( -63636 -15661 65535 ) ( -63636 -15661 -65535 ) shootit 0 8 0 1 1 - } - { //brush 207 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 63527 16097 65535 ) ( -63629 -15691 65535 ) ( -63629 -15691 -65535 ) shootit 0 8 0 1 1 - ( 63853 -14795 65535 ) ( -63303 16993 65535 ) ( -63303 16993 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - } - { //brush 208 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) shootit 0 8 0 1 1 - ( 63822 -14915 65535 ) ( -63333 16873 65535 ) ( -63333 16873 -65535 ) shootit 0 8 0 1 1 - ( 65534 16479 63431 ) ( -65534 16479 63431 ) ( -65534 -15309 -63724 ) shootit 0 8 0 1 1 - ( 65534 -15177 63757 ) ( -65534 -15177 63757 ) ( -65534 16611 -63398 ) shootit 0 8 0 1 1 - ( 63497 16218 65535 ) ( -63659 -15570 65535 ) ( -63659 -15570 -65535 ) shootit 0 8 0 1 1 - } - { //brush 209 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 30658 -57941 65535 ) ( -27957 59291 65535 ) ( -27957 59291 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58385 29768 ) ( 65535 58846 -28847 ) ( -65535 -58385 29768 ) stnwll05 0 0 90 1 1 - } - { //brush 210 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 688 65535 ) ( 65535 688 65535 ) ( -65535 688 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58846 -28847 ) ( 65535 -58385 29768 ) ( -65535 -58385 29768 ) stnfloor02 0 0 0 1 1 - } - { //brush 211 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 688 65535 ) ( -65535 688 65535 ) ( -65535 688 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 212 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stonesnw 0 0 0 1 1 - } - { //brush 213 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) fstng_2 0 16 90 1 1 - } - { //brush 214 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 63455 16383 ) ( 65535 -63700 -15405 ) ( -65535 -63700 -15405 ) stnwll02 0 0 90 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll02 0 0 90 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll02 0 0 90 1 1 - } - { //brush 215 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) fstng_2 0 16 90 1 1 - } - { //brush 216 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 46484 -65535 46196 ) ( 46484 65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 217 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 218 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 219 - ( 1008 65535 65535 ) ( 1008 -65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 - } - { //brush 220 - ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 0 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 221 - ( 816 65535 65535 ) ( 816 -65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 976 -65535 65535 ) ( 976 65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll05 0 0 90 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 90 1 1 - } - { //brush 222 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 223 - ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -58952 -28636 65535 ) ( 58280 29980 65535 ) ( -58952 -28636 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 224 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 225 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 46436 65535 46244 ) ( 46436 -65535 46244 ) ( -46244 65535 -46436 ) stnwll01 0 0 90 1 1 - ( -15073 -65534 63783 ) ( -15073 65534 63783 ) ( 16715 65534 -63373 ) stnwll01 0 0 0 1 1 - } - { //brush 226 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) millgt1 0 0 90 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( 46436 -65535 46244 ) ( 46436 65535 46244 ) ( -46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) millgt1 0 0 0 1 0.500000 - } - { //brush 227 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( 46436 -65535 46244 ) ( 46436 65535 46244 ) ( -46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( -15073 65534 63783 ) ( -15073 -65534 63783 ) ( 16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 - } - { //brush 228 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -15073 -65534 63783 ) ( -15073 65534 63783 ) ( 16715 65534 -63373 ) stnwll01 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 229 - ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 59125 -28290 65535 ) ( -58107 30325 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 230 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 231 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_2 0 0 180 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) fstng_2 0 0 0 1 1 - } - { //brush 232 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - } - { //brush 233 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 234 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64299 12680 65535 ) ( 64525 -11474 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 235 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -65081 -7711 65535 ) ( 64976 8546 65535 ) ( -65081 -7711 -65535 ) mtn 0 0 0 1 1 - ( -64306 12641 65535 ) ( 64518 -11513 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 - ( 64525 -11474 65535 ) ( -64299 12680 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 236 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 64976 8546 65535 ) ( -65081 -7711 65535 ) ( -65081 -7711 -65535 ) mtn 0 0 0 1 1 - ( 64525 -11474 65535 ) ( -64299 12680 65535 ) ( -64299 12680 -65535 ) mtn 0 0 0 1 1 - ( -64306 12641 65535 ) ( 64518 -11513 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 237 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -58744 -29052 65535 ) ( 58488 29564 65535 ) ( -58744 -29052 -65535 ) mtn 0 0 0 1 1 - ( -63859 14731 65535 ) ( 64088 -13701 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 238 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( 58488 29564 65535 ) ( -58744 -29052 65535 ) ( -58744 -29052 -65535 ) mtn 0 0 0 1 1 - ( 64518 -11513 65535 ) ( -64306 12641 65535 ) ( -64306 12641 -65535 ) mtn 0 0 0 1 1 - ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 239 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15329 63719 ) ( 65534 -15329 63719 ) ( -65534 16459 -63437 ) mtn 0 0 0 1 1 - ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - } - { //brush 240 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - } - { //brush 241 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -7581 65097 ) ( 65534 -7581 65097 ) ( -65534 8676 -64960 ) mtn 0 0 0 1 1 - ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 65271 -14499 64180 ) ( -54501 38733 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - } - { //brush 242 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65534 -15314 63723 ) ( -65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( -59675 27091 65535 ) ( 60097 -26141 65535 ) ( -59675 27091 -65535 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - ( 58437 29666 65535 ) ( -58795 -28949 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - } - { //brush 243 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 244 - ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 - ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65534 29461 58539 ) ( 65534 29461 58539 ) ( -65534 -29154 -58693 ) mtn 0 0 0 1 1 - ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 - } - { //brush 245 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -63219 -26421 62412 ) ( 67199 -13380 62412 ) ( -67325 14635 -61993 ) mtn 0 0 0 1 1 - ( -67199 -13380 62412 ) ( 63219 -26421 62412 ) ( -63094 27677 -61993 ) mtn 0 0 0 1 1 - ( -58795 -28949 65535 ) ( 58437 29666 65535 ) ( -58795 -28949 -65535 ) mtn 0 0 0 1 1 - ( -65257 -6045 65535 ) ( 65162 6996 65535 ) ( -65257 -6045 -65535 ) mtn 0 0 0 1 1 - ( 65535 10118 64750 ) ( -65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - ( -65162 6996 65535 ) ( 65257 -6045 65535 ) ( -65162 6996 -65535 ) mtn 0 0 0 1 1 - ( -58437 29666 65535 ) ( 58795 -28949 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( 64088 -13701 65535 ) ( -63859 14731 65535 ) ( -63859 14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 246 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -54501 38733 64180 ) ( 65271 -14499 64180 ) ( -64935 15255 -64346 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -59675 27091 65535 ) ( 60097 -26141 65535 ) ( -59675 27091 -65535 ) mtn 0 0 0 1 1 - } - { //brush 247 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 248 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -58488 29564 65535 ) ( 58744 -29052 65535 ) ( -58488 29564 -65535 ) mtn 0 0 0 1 1 - ( -64088 -13701 65535 ) ( 63859 14731 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - } - { //brush 249 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 64306 12641 65535 ) ( -64518 -11513 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 58744 -29052 65535 ) ( -58488 29564 65535 ) ( -58488 29564 -65535 ) mtn 0 0 0 1 1 - } - { //brush 250 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( 63859 14731 65535 ) ( -64088 -13701 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 - ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - } - { //brush 251 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( -65534 -7581 65097 ) ( 65534 -7581 65097 ) ( -65534 8676 -64960 ) mtn 0 0 0 1 1 - ( 63859 14731 65535 ) ( -64088 -13701 65535 ) ( -64088 -13701 -65535 ) mtn 0 0 0 1 1 - ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( -65534 -15314 63723 ) ( 65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - ( 54501 38733 64180 ) ( -65271 -14499 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - ( -65535 10118 64750 ) ( 65535 10118 64750 ) ( -65535 -9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 252 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -60097 -26141 65535 ) ( 59675 27091 65535 ) ( -60097 -26141 -65535 ) mtn 0 0 0 1 1 - ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 58795 -28949 65535 ) ( -58437 29666 65535 ) ( -58437 29666 -65535 ) mtn 0 0 0 1 1 - ( 65534 -15314 63723 ) ( -65534 -15314 63723 ) ( -65534 16474 -63433 ) mtn 0 0 0 1 1 - } - { //brush 253 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -65271 -14499 64180 ) ( 54501 38733 64180 ) ( -54837 -37977 -64346 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -60097 -26141 65535 ) ( 59675 27091 65535 ) ( -60097 -26141 -65535 ) mtn 0 0 0 1 1 - } - { //brush 254 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -50409 45720 62915 ) ( 66822 -12895 62915 ) ( -66454 13631 -63149 ) mtn 0 0 0 1 1 - ( -66510 3720 64438 ) ( 63547 19978 64438 ) ( -63623 -19370 -64549 ) mtn 0 0 0 1 1 - ( -63536 20069 64421 ) ( 66521 3812 64421 ) ( -66422 -3021 -64565 ) mtn 0 0 0 1 1 - } - { //brush 255 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -50015 46510 62651 ) ( 67217 -12106 62651 ) ( -66762 13015 -62954 ) mtn 0 0 0 1 1 - ( 63547 19978 64438 ) ( -66510 3720 64438 ) ( -63623 -19370 -64549 ) mtn 0 0 0 1 1 - ( -66017 5667 64802 ) ( 64797 13842 64802 ) ( -64839 -13174 -64900 ) mtn 0 0 0 1 1 - ( -66636 -8945 63790 ) ( 56087 37076 63790 ) ( -56147 -36916 -63830 ) mtn 0 0 0 1 1 - } - { //brush 256 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 1216 65535 ) ( 65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 257 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) shootit 16 0 180 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) shootit 16 0 180 1 1 - ( 65535 -58277 29986 ) ( 65535 58955 -28629 ) ( -65535 -58277 29986 ) shootit 16 0 0 1 1 - } - { //brush 258 - ( 784 65535 65535 ) ( 784 -65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 259 - ( 496 65535 65535 ) ( 496 -65535 65535 ) ( 496 65535 -65535 ) tile2492 0 0 0 1 1 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 260 - ( 432 65535 65535 ) ( 432 -65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 0 1 1 - ( 464 -65535 65535 ) ( 464 65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 261 - ( 144 65535 65535 ) ( 144 -65535 65535 ) ( 144 65535 -65535 ) tile2492 0 0 0 1 1 - ( 400 -65535 65535 ) ( 400 65535 65535 ) ( 400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 262 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1184 65535 ) ( 65535 1184 65535 ) ( -65535 1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 90 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 263 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_0 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) fstng_0 0 0 0 1 1 - } - { //brush 264 - ( 784 65535 65535 ) ( 784 -65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 265 - ( 464 65535 65535 ) ( 464 -65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 180 1 1 - ( 784 -65535 65535 ) ( 784 65535 65535 ) ( 784 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 266 - ( 752 65535 65535 ) ( 752 -65535 65535 ) ( 752 65535 -65535 ) shootit 16 0 180 1 1 - ( 784 -65535 65535 ) ( 784 65535 65535 ) ( 784 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 267 - ( 496 65535 65535 ) ( 496 -65535 65535 ) ( 496 65535 -65535 ) tile2492 0 0 0 1 1 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 268 - ( 464 65535 65535 ) ( 464 -65535 65535 ) ( 464 65535 -65535 ) shootit 16 0 180 1 1 - ( 496 -65535 65535 ) ( 496 65535 65535 ) ( 496 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 269 - ( 432 65535 65535 ) ( 432 -65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 0 1 1 - ( 464 -65535 65535 ) ( 464 65535 65535 ) ( 464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 270 - ( 400 65535 65535 ) ( 400 -65535 65535 ) ( 400 65535 -65535 ) shootit 16 0 180 1 1 - ( 432 -65535 65535 ) ( 432 65535 65535 ) ( 432 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 271 - ( 144 65535 65535 ) ( 144 -65535 65535 ) ( 144 65535 -65535 ) tile2492 0 0 0 1 1 - ( 400 -65535 65535 ) ( 400 65535 65535 ) ( 400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 272 - ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) shootit 16 0 180 1 1 - ( 144 -65535 65535 ) ( 144 65535 65535 ) ( 144 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) shootit 16 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) shootit 16 0 0 1 1 - ( 65535 -58533 -29474 ) ( 65535 58699 29141 ) ( -65535 -58533 -29474 ) shootit 16 0 0 1 1 - } - { //brush 273 - ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 180 1 1 - ( 432 -65535 65535 ) ( 432 65535 65535 ) ( 432 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 274 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 896 65535 ) ( 65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 275 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 276 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 277 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -58408 29724 65535 ) ( 58824 -28892 65535 ) ( -58408 29724 -65535 ) tile2492 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 278 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 279 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( -51172 44196 63387 ) ( 66060 -14420 63387 ) ( -65685 15170 -63601 ) mtn 0 0 0 1 1 - ( -58401 29736 65535 ) ( 58830 -28879 65535 ) ( -58401 29736 -65535 ) mtn 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 280 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 816 -65535 65535 ) ( 816 65535 65535 ) ( 816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - } - { //brush 281 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 282 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1216 65535 ) ( -65535 1216 65535 ) ( -65535 1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) tile2492 0 0 0 1 1 - ( -65535 -35414 55153 ) ( 65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 283 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 65535 58955 -28629 ) ( 65535 -58277 29986 ) ( -65535 -58277 29986 ) fstng_0 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) fstng_0 0 0 0 1 1 - } - { //brush 284 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) shootit 16 16 180 1 1 - ( -65535 1040 65535 ) ( 65535 1040 65535 ) ( -65535 1040 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1072 65535 ) ( -65535 1072 65535 ) ( -65535 1072 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 16 0 1 1 - ( 58504 -65534 29532 ) ( 58504 65534 29532 ) ( -58728 -65534 -29084 ) shootit 16 16 0 1 1 - } - { //brush 285 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 286 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 - } - { //brush 287 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 65535 -63481 16282 ) ( 65535 63675 -15506 ) ( -65535 -63481 16282 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - ( 65535 -63577 -15898 ) ( 65535 63579 15890 ) ( -65535 -63577 -15898 ) shootit 16 16 0 1 1 - } - { //brush 288 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - ( 65535 -63496 16222 ) ( 65535 63660 -15567 ) ( -65535 -63496 16222 ) shootit 16 16 0 1 1 - ( 65535 -63592 -15838 ) ( 65535 63564 15951 ) ( -65535 -63592 -15838 ) shootit 16 16 0 1 1 - } - { //brush 289 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( -65534 -28834 58853 ) ( 65534 -28834 58853 ) ( -65534 29781 -58379 ) tile2492 0 0 0 1 1 - } - { //brush 290 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 291 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( -58824 -28892 65535 ) ( 58408 29724 65535 ) ( -58824 -28892 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 292 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 293 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( -58830 -28879 65535 ) ( 58401 29736 65535 ) ( -58830 -28879 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -66060 -14420 63387 ) ( 51172 44196 63387 ) ( -51547 -43446 -63601 ) mtn 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) mtn 0 0 0 1 1 - } - { //brush 294 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 65535 36876 54178 ) ( -65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 295 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 296 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 1248 65535 ) ( -65535 1248 65535 ) ( -65535 1248 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64525 -11474 65535 ) ( 64299 12680 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) mtn 0 0 0 1 1 - } - { //brush 297 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -65534 16203 63501 ) ( 65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 298 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( -65535 14338 63948 ) ( 65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( 65534 16203 63501 ) ( -65534 16203 63501 ) ( -65534 -15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 299 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64976 8546 65535 ) ( 65081 -7711 65535 ) ( -64976 8546 -65535 ) mtn 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - ( 64299 12680 65535 ) ( -64525 -11474 65535 ) ( -64525 -11474 -65535 ) mtn 0 0 0 1 1 - ( 65535 14338 63948 ) ( -65535 14338 63948 ) ( -65535 -13670 -64094 ) mtn 0 0 0 1 1 - ( -64518 -11513 65535 ) ( 64306 12641 65535 ) ( -64518 -11513 -65535 ) mtn 0 0 0 1 1 - } - { //brush 300 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -66822 -12895 62915 ) ( 50409 45720 62915 ) ( -50778 -44984 -63149 ) mtn 0 0 0 1 1 - ( -66521 3812 64421 ) ( 63536 20069 64421 ) ( -63635 -19279 -64565 ) mtn 0 0 0 1 1 - ( -63547 19978 64438 ) ( 66510 3720 64438 ) ( -66434 -3113 -64549 ) mtn 0 0 0 1 1 - } - { //brush 301 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 66510 3720 64438 ) ( -63547 19978 64438 ) ( -66434 -3113 -64549 ) mtn 0 0 0 1 1 - ( -56087 37076 63790 ) ( 66636 -8945 63790 ) ( -66577 9104 -63830 ) mtn 0 0 0 1 1 - ( -64797 13842 64802 ) ( 66017 5667 64802 ) ( -65975 -4998 -64900 ) mtn 0 0 0 1 1 - ( -67217 -12106 62651 ) ( 50015 46510 62651 ) ( -50469 -45601 -62954 ) mtn 0 0 0 1 1 - } - { //brush 302 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 303 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 304 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) millgt1 0 0 0 1 0.500000 - } - { //brush 305 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65534 15887 63580 ) ( 65534 15887 63580 ) ( -65534 -15902 -63576 ) stnwll02 0 0 0 1 1 - ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) stnwll02 0 0 0 1 1 - } - { //brush 306 - ( 1920 65535 65535 ) ( 1920 -65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 307 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 308 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 0 0 0 1 0.500000 - } - { //brush 309 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1888 -65535 65535 ) ( 1888 65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 310 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 311 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 - } - { //brush 312 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 - ( 47116 65535 45564 ) ( 47116 -65535 45564 ) ( -45564 65535 -47116 ) fstng_2 0 16 0 1 1 - } - { //brush 313 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 90 1 1 - ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 90 1 1 - ( 47116 -65535 45564 ) ( 47116 65535 45564 ) ( -45564 65535 -47116 ) fstng_2 0 16 90 1 1 - } - { //brush 314 - ( 2048 65535 65535 ) ( 2048 -65535 65535 ) ( 2048 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 - ( 47172 -65535 45508 ) ( 47172 65535 45508 ) ( -45508 65535 -47172 ) millgt1 16 0 90 1 0.500000 - } - { //brush 315 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 316 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 317 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 318 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 0 0 1 0.500000 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15887 63580 ) ( 65534 -15887 63580 ) ( -65534 15902 -63576 ) millgt1 0 0 0 1 0.500000 - } - { //brush 319 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65534 -15887 63580 ) ( -65534 -15887 63580 ) ( -65534 15902 -63576 ) stnwll02 0 0 0 1 1 - } - { //brush 320 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -112 65535 ) ( 65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 321 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 322 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 323 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -112 65535 ) ( -65535 -112 65535 ) ( -65535 -112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - } - { //brush 324 - ( 2224 65535 65535 ) ( 2224 -65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll01 0 0 90 1 1 - } - { //brush 325 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( -65534 15333 63718 ) ( 65534 15333 63718 ) ( -65534 -16455 -63438 ) stnwll01 0 0 0 1 1 - } - { //brush 326 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 16 0 0 1 0.500000 - ( 65534 15333 63718 ) ( -65534 15333 63718 ) ( -65534 -16455 -63438 ) millgt1 16 0 0 1 0.500000 - } - { //brush 327 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( -65534 15333 63718 ) ( 65534 15333 63718 ) ( -65534 -16455 -63438 ) stnwll01 0 0 0 1 1 - } - { //brush 328 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 16 0 0 1 0.500000 - ( 65534 15333 63718 ) ( -65534 15333 63718 ) ( -65534 -16455 -63438 ) millgt1 16 0 0 1 0.500000 - } - { //brush 329 - ( 1920 65535 65535 ) ( 1920 -65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 330 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 331 - ( 1888 65535 65535 ) ( 1888 -65535 65535 ) ( 1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1920 -65535 65535 ) ( 1920 65535 65535 ) ( 1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 0 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 332 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1888 -65535 65535 ) ( 1888 65535 65535 ) ( 1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - } - { //brush 333 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 334 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 335 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 336 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_0 0 0 0 1 1 - } - { //brush 337 - ( 960 65535 65535 ) ( 960 -65535 65535 ) ( 960 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - } - { //brush 338 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63731 -15280 ) ( 65535 63424 16508 ) ( -65535 -63731 -15280 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63439 16447 ) ( 65535 63716 -15341 ) ( -65535 -63439 16447 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - } - { //brush 339 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63716 -15341 ) ( 65535 63439 16447 ) ( -65535 -63716 -15341 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - ( 65535 -63424 16508 ) ( 65535 63731 -15280 ) ( -65535 -63424 16508 ) ftlattice2 16 16 0 1 1 - } - { //brush 340 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 341 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 342 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 343 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 688 ) ( 65535 65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 344 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 345 - ( 872 65535 65535 ) ( 872 -65535 65535 ) ( 872 65535 -65535 ) ctf07 32 48 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) ctf07 32 48 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) ctf07 32 48 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) ctf07 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf07 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf07 32 48 90 1 1 - } - { //brush 346 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - } - { //brush 347 - ( 872 65535 65535 ) ( 872 -65535 65535 ) ( 872 65535 -65535 ) ctf07 32 48 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) ctf07 32 48 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf07 32 48 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) ctf07 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf07 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf07 32 48 90 1 1 - } - { //brush 348 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 59032 -65534 -28476 ) ( 59032 65534 -28476 ) ( -58200 -65534 30140 ) fstng_2 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 349 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 960 -65535 65535 ) ( 960 65535 65535 ) ( 960 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 59032 -65534 -28476 ) ( 59032 65534 -28476 ) ( -58200 -65534 30140 ) fstng_2 0 0 0 1 1 - } - { //brush 350 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 351 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 352 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 65535 -63747 -15216 ) ( 65535 63408 16572 ) ( -65535 -63747 -15216 ) ftlattice2 16 0 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 0 0 1 1 - ( 65535 -63455 16383 ) ( 65535 63700 -15405 ) ( -65535 -63455 16383 ) ftlattice2 16 0 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 0 0 1 1 - } - { //brush 353 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 354 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 355 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 356 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - ( -62234 20536 65535 ) ( 62109 -20911 65535 ) ( -62234 20536 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 357 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62109 -20911 65535 ) ( -62234 20536 65535 ) ( -62234 20536 -65535 ) mtn 0 0 0 1 1 - } - { //brush 358 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 62109 -20911 65535 ) ( -62234 20536 65535 ) ( -62234 20536 -65535 ) mtn 0 0 0 1 1 - } - { //brush 359 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_0 0 0 0 1 1 - } - { //brush 360 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) fstng_2 0 16 180 1 1 - } - { //brush 361 - ( 1712 65535 65535 ) ( 1712 -65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 362 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 363 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 364 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1680 -65535 65535 ) ( 1680 65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 365 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 366 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 0 0 0 1 0.500000 - } - { //brush 367 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 368 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -45284 65535 47396 ) ( -45284 -65535 47396 ) ( 47396 65535 -45284 ) fstng_2 0 0 90 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 369 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 1 - ( 63767 -65534 -15137 ) ( 63767 65534 -15137 ) ( -63389 -65534 16651 ) millgt1 16 0 0 1 1 - ( 63588 -65534 15853 ) ( 63588 65534 15853 ) ( -63567 -65534 -15935 ) millgt1 16 0 0 1 1 - ( 65535 -63501 16203 ) ( 65535 63655 -15585 ) ( -65535 -63501 16203 ) millgt1 16 0 0 1 1 - ( 65535 -63679 -15487 ) ( 65535 63476 16301 ) ( -65535 -63679 -15487 ) millgt1 16 0 0 1 1 - } - { //brush 370 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 46980 -65535 45700 ) ( 46980 65535 45700 ) ( -45700 65535 -46980 ) fstng_2 0 0 90 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 371 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll05 0 0 90 1 1 - } - { //brush 372 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 373 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 90 1 1 - } - { //brush 374 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( -65535 -46196 46484 ) ( 65535 -46196 46484 ) ( -65535 46484 -46196 ) millgt1 16 0 0 1 0.500000 - } - { //brush 375 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -352 65535 ) ( 65535 -352 65535 ) ( -65535 -352 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 376 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -384 65535 ) ( 65535 -384 65535 ) ( -65535 -384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -352 65535 ) ( -65535 -352 65535 ) ( -65535 -352 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 377 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -416 65535 ) ( 65535 -416 65535 ) ( -65535 -416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -384 65535 ) ( -65535 -384 65535 ) ( -65535 -384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - } - { //brush 378 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -416 65535 ) ( -65535 -416 65535 ) ( -65535 -416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 379 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 380 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 381 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 0 1 1 - ( -65534 15352 63713 ) ( 65534 15352 63713 ) ( -65534 -16436 -63442 ) stnwll02 0 0 0 1 1 - ( 65535 -46268 46412 ) ( -65535 -46268 46412 ) ( -65535 46412 -46268 ) stnwll02 0 0 0 1 1 - } - { //brush 382 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 383 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 384 - ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -28168 59185 65535 ) ( 30447 -58046 65535 ) ( -28168 59185 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 385 - ( 1280 65535 65535 ) ( 1280 -65535 65535 ) ( 1280 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 386 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( -65534 15352 63713 ) ( 65534 15352 63713 ) ( -65534 -16436 -63442 ) stnwll02 0 0 0 1 1 - ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 387 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( 65534 15352 63713 ) ( -65534 15352 63713 ) ( -65534 -16436 -63442 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46268 46412 ) ( 65535 -46268 46412 ) ( -65535 46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 388 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 30447 58046 65535 ) ( -28168 -59185 65535 ) ( 30447 58046 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 389 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll05 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - ( 28937 -58807 65535 ) ( -27299 59585 65535 ) ( -27299 59585 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 390 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 391 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 30114 58213 65535 ) ( -28501 -59019 65535 ) ( 30114 58213 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 392 - ( 896 65535 65535 ) ( 896 -65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -28501 -59019 65535 ) ( 30114 58213 65535 ) ( 30114 58213 -65535 ) stnwll05 0 0 0 1 1 - ( 30088 -58225 65535 ) ( -28527 59006 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 393 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - ( -28501 -59019 65535 ) ( 30114 58213 65535 ) ( 30114 58213 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 394 - ( 896 -65535 65535 ) ( 896 65535 65535 ) ( 896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - ( 58606 65534 29327 ) ( 58606 -65534 29327 ) ( -58625 -65534 -29288 ) stnfloor02 0 0 0 1 1 - ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 395 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 30447 -58046 65535 ) ( -28168 59185 65535 ) ( -28168 59185 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) fstng_2 0 0 0 1 1 - ( -28527 59006 65535 ) ( 30088 -58225 65535 ) ( -28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 396 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 58741 29058 65535 ) ( -58491 -29557 65535 ) ( -58491 -29557 -65535 ) stnwll05 0 0 0 1 1 - ( 30248 -58145 65535 ) ( -28367 59086 65535 ) ( -28367 59086 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 397 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) millgt1 16 0 90 1 0.500000 - ( 46700 -65535 45980 ) ( 46700 65535 45980 ) ( -45980 65535 -46700 ) millgt1 16 0 90 1 0.500000 - ( -14746 65534 63865 ) ( -14746 -65534 63865 ) ( 17042 65534 -63291 ) millgt1 16 0 0 1 0.500000 - } - { //brush 398 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - } - { //brush 399 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 400 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) fstng_2 0 0 0 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 401 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 402 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - ( -65535 45972 46708 ) ( 65535 45972 46708 ) ( -65535 -46708 -45972 ) stnwll05 0 0 0 1 1 - } - { //brush 403 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1200 -65535 65535 ) ( 1200 65535 65535 ) ( 1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - } - { //brush 404 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - } - { //brush 405 - ( 1008 65535 65535 ) ( 1008 -65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 406 - ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16116 63522 ) ( 65534 -16116 63522 ) ( -65534 15672 -63633 ) millgt1 16 0 0 1 0.500000 - } - { //brush 407 - ( 976 65535 65535 ) ( 976 -65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 1008 -65535 65535 ) ( 1008 65535 65535 ) ( 1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 408 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 976 -65535 65535 ) ( 976 65535 65535 ) ( 976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 409 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 30088 58225 65535 ) ( -28527 -59006 65535 ) ( 30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 410 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 411 - ( 1600 65535 65535 ) ( 1600 -65535 65535 ) ( 1600 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 412 - ( 1568 65535 65535 ) ( 1568 -65535 65535 ) ( 1568 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1600 -65535 65535 ) ( 1600 65535 65535 ) ( 1600 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 413 - ( 1536 65535 65535 ) ( 1536 -65535 65535 ) ( 1536 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 414 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1536 -65535 65535 ) ( 1536 65535 65535 ) ( 1536 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 415 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 416 - ( 1440 65535 65535 ) ( 1440 -65535 65535 ) ( 1440 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 417 - ( 1408 65535 65535 ) ( 1408 -65535 65535 ) ( 1408 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1440 -65535 65535 ) ( 1440 65535 65535 ) ( 1440 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - } - { //brush 418 - ( 1376 65535 65535 ) ( 1376 -65535 65535 ) ( 1376 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1408 -65535 65535 ) ( 1408 65535 65535 ) ( 1408 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - } - { //brush 419 - ( 1344 65535 65535 ) ( 1344 -65535 65535 ) ( 1344 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1376 -65535 65535 ) ( 1376 65535 65535 ) ( 1376 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - } - { //brush 420 - ( 1312 65535 65535 ) ( 1312 -65535 65535 ) ( 1312 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1344 -65535 65535 ) ( 1344 65535 65535 ) ( 1344 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 421 - ( 1280 65535 65535 ) ( 1280 -65535 65535 ) ( 1280 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1312 -65535 65535 ) ( 1312 65535 65535 ) ( 1312 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - } - { //brush 422 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 1280 -65535 65535 ) ( 1280 65535 65535 ) ( 1280 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 423 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 424 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 425 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52679 65535 -38985 ) ( 52679 -65535 -38985 ) ( -52176 -65535 39656 ) stonesnow 0 0 0 1 1 - } - { //brush 426 - ( -240 65535 65535 ) ( -240 -65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 180 1 1 - ( 240 -65535 65535 ) ( 240 65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) stonesnow 0 0 0 1 1 - ( 65534 -29084 58728 ) ( -65534 -29084 58728 ) ( -65534 29532 -58504 ) tile2492 0 0 0 1 1 - } - { //brush 427 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52176 65535 39656 ) ( 52176 -65535 39656 ) ( -52679 -65535 -38985 ) stonesnow 0 0 0 1 1 - } - { //brush 428 - ( 280 65535 65535 ) ( 280 -65535 65535 ) ( 280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 429 - ( 276 65535 65535 ) ( 276 -65535 65535 ) ( 276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 430 - ( 272 65535 65535 ) ( 272 -65535 65535 ) ( 272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 431 - ( 268 65535 65535 ) ( 268 -65535 65535 ) ( 268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 432 - ( 264 65535 65535 ) ( 264 -65535 65535 ) ( 264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 433 - ( 260 65535 65535 ) ( 260 -65535 65535 ) ( 260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 434 - ( 256 65535 65535 ) ( 256 -65535 65535 ) ( 256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 435 - ( 252 65535 65535 ) ( 252 -65535 65535 ) ( 252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 436 - ( 248 65535 65535 ) ( 248 -65535 65535 ) ( 248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 437 - ( 244 65535 65535 ) ( 244 -65535 65535 ) ( 244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 438 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 439 - ( 236 65535 65535 ) ( 236 -65535 65535 ) ( 236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 440 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 441 - ( -276 -65535 65535 ) ( -276 65535 65535 ) ( -276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 442 - ( -272 -65535 65535 ) ( -272 65535 65535 ) ( -272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 443 - ( -268 -65535 65535 ) ( -268 65535 65535 ) ( -268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 444 - ( -264 -65535 65535 ) ( -264 65535 65535 ) ( -264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 445 - ( -260 -65535 65535 ) ( -260 65535 65535 ) ( -260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 446 - ( -256 -65535 65535 ) ( -256 65535 65535 ) ( -256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 447 - ( -252 -65535 65535 ) ( -252 65535 65535 ) ( -252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 448 - ( -248 -65535 65535 ) ( -248 65535 65535 ) ( -248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 449 - ( -244 -65535 65535 ) ( -244 65535 65535 ) ( -244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 450 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 451 - ( -236 -65535 65535 ) ( -236 65535 65535 ) ( -236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 452 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 453 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 0 1 1 - } - { //brush 454 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 455 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 456 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 0 16 0 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 0 16 0 1 1 - ( 63646 -65534 -15623 ) ( 63646 65534 -15623 ) ( -63510 -65534 16165 ) shootit 0 16 0 1 1 - ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 0 16 0 1 1 - ( 63534 -65534 16067 ) ( 63534 65534 16067 ) ( -63621 -65534 -15721 ) shootit 0 16 0 1 1 - } - { //brush 457 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 16 16 0 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 16 16 0 1 1 - ( 63522 -65534 16116 ) ( 63522 65534 16116 ) ( -63633 -65534 -15672 ) shootit 16 16 0 1 1 - ( 63633 -65534 -15672 ) ( 63633 65534 -15672 ) ( -63522 -65534 16116 ) shootit 16 16 0 1 1 - ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 16 16 0 1 1 - } - { //brush 458 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) shootit 0 16 0 1 1 - ( 65535 -63633 -15672 ) ( 65535 63522 16116 ) ( -65535 -63633 -15672 ) shootit 0 16 0 1 1 - ( 63621 -65534 -15721 ) ( 63621 65534 -15721 ) ( -63534 -65534 16067 ) shootit 0 16 0 1 1 - ( 63510 -65534 16165 ) ( 63510 65534 16165 ) ( -63646 -65534 -15623 ) shootit 0 16 0 1 1 - ( 65535 -63522 16116 ) ( 65535 63633 -15672 ) ( -65535 -63522 16116 ) shootit 0 16 0 1 1 - } - { //brush 459 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 - } - { //brush 460 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58750 -65534 -29039 ) ( 58750 65534 -29039 ) ( -58481 -65534 29576 ) fstng_0 0 0 0 1 1 - } - { //brush 461 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58565 -65534 29410 ) ( 58565 65534 29410 ) ( -58667 -65534 -29205 ) fstng_0 0 0 0 1 1 - } - { //brush 462 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 90 1 1 - } - { //brush 463 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 464 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 465 - ( 120 65535 65535 ) ( 120 -65535 65535 ) ( 120 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 76 ) ( 65535 65535 76 ) ( -65535 -65535 76 ) fstng_0 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 466 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 76 ) ( 65535 -65535 76 ) ( -65535 -65535 76 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 467 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 - ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 - } - { //brush 468 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58523 -65534 29493 ) ( 58523 65534 29493 ) ( -58709 -65534 -29122 ) fstng_0 0 0 0 1 1 - } - { //brush 469 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58709 -65534 -29122 ) ( 58709 65534 -29122 ) ( -58523 -65534 29493 ) fstng_0 0 0 0 1 1 - } - { //brush 470 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 90 1 1 - } - { //brush 471 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 65534 29320 58609 ) ( -65534 29320 58609 ) ( -65534 -29295 -58622 ) tile2492 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) tile2492 0 0 0 1 1 - } - { //brush 472 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58667 -65534 -29205 ) ( 58667 65534 -29205 ) ( -58565 -65534 29410 ) fstng_0 0 0 0 1 1 - } - { //brush 473 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58481 -65534 29576 ) ( 58481 65534 29576 ) ( -58750 -65534 -29039 ) fstng_0 0 0 0 1 1 - } - { //brush 474 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 180 1 1 - } - { //brush 475 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 476 - ( -120 -65535 65535 ) ( -120 65535 65535 ) ( -120 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 76 ) ( 65535 65535 76 ) ( -65535 -65535 76 ) fstng_0 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 477 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 76 ) ( 65535 -65535 76 ) ( -65535 -65535 76 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 478 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 479 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stonesnow 0 0 0 1 1 - } - { //brush 480 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 481 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52679 65535 -38985 ) ( 52679 -65535 -38985 ) ( -52176 -65535 39656 ) stonesnow 0 0 0 1 1 - } - { //brush 482 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 67217 12106 62651 ) ( -50015 -46510 62651 ) ( -66762 -13015 -62954 ) mtn 0 0 0 1 1 - ( 64797 -13842 64802 ) ( -66017 -5667 64802 ) ( -64839 13174 -64900 ) mtn 0 0 0 1 1 - ( -66510 -3720 64438 ) ( 63547 -19978 64438 ) ( -63623 19370 -64549 ) mtn 0 0 0 1 1 - ( 56087 -37076 63790 ) ( -66636 8945 63790 ) ( -56147 36916 -63830 ) mtn 0 0 0 1 1 - } - { //brush 483 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 63547 -19978 64438 ) ( -66510 -3720 64438 ) ( -63623 19370 -64549 ) mtn 0 0 0 1 1 - ( 66822 12895 62915 ) ( -50409 -45720 62915 ) ( -66454 -13631 -63149 ) mtn 0 0 0 1 1 - ( 66521 -3812 64421 ) ( -63536 -20069 64421 ) ( -66422 3021 -64565 ) mtn 0 0 0 1 1 - } - { //brush 484 - ( -240 65535 65535 ) ( -240 -65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 180 1 1 - ( 240 -65535 65535 ) ( 240 65535 65535 ) ( 240 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) stonesnow 0 0 0 1 1 - ( -65534 29084 58728 ) ( 65534 29084 58728 ) ( -65534 -29532 -58504 ) tile2492 0 0 0 1 1 - } - { //brush 485 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 60097 26141 65535 ) ( -59675 -27091 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 - ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 486 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -64306 -12641 65535 ) ( 64518 11513 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - } - { //brush 487 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -65081 7711 65535 ) ( 64976 -8546 65535 ) ( -65081 7711 -65535 ) mtn 0 0 0 1 1 - ( -64299 -12680 65535 ) ( 64525 11474 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 - ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 488 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64976 -8546 65535 ) ( -65081 7711 65535 ) ( -65081 7711 -65535 ) mtn 0 0 0 1 1 - ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -64299 -12680 65535 ) ( 64525 11474 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 489 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( -65534 15314 63723 ) ( 65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -59675 -27091 65535 ) ( 60097 26141 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 - ( 65534 15329 63719 ) ( -65534 15329 63719 ) ( -65534 -16459 -63437 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 490 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( -65534 15314 63723 ) ( 65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 60097 26141 65535 ) ( -59675 -27091 65535 ) ( -59675 -27091 -65535 ) mtn 0 0 0 1 1 - } - { //brush 491 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( -58795 28949 65535 ) ( 58437 -29666 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -54501 -38733 64180 ) ( 65271 14499 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 492 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -54501 -38733 64180 ) ( 65271 14499 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - } - { //brush 493 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( 65271 14499 64180 ) ( -54501 -38733 64180 ) ( -64935 -15255 -64346 ) mtn 0 0 0 1 1 - ( -63859 -14731 65535 ) ( 64088 13701 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - } - { //brush 494 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64088 13701 65535 ) ( -63859 -14731 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - } - { //brush 495 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64525 11474 65535 ) ( -64299 -12680 65535 ) ( -64299 -12680 -65535 ) mtn 0 0 0 1 1 - } - { //brush 496 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -63219 26421 62412 ) ( 67199 13380 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 497 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) stonesnow 0 0 0 1 1 - ( 52176 65535 39656 ) ( 52176 -65535 39656 ) ( -52679 -65535 -38985 ) stonesnow 0 0 0 1 1 - } - { //brush 498 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 499 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58565 -65534 29410 ) ( 58565 65534 29410 ) ( -58667 -65534 -29205 ) fstng_0 0 0 0 1 1 - } - { //brush 500 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) tile2492 0 0 90 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 501 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58750 -65534 -29039 ) ( 58750 65534 -29039 ) ( -58481 -65534 29576 ) fstng_0 0 0 0 1 1 - } - { //brush 502 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( 65534 -29320 58609 ) ( -65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 180 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 503 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 504 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 505 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 - } - { //brush 506 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58523 -65534 29493 ) ( 58523 65534 29493 ) ( -58709 -65534 -29122 ) fstng_0 0 0 0 1 1 - } - { //brush 507 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58709 -65534 -29122 ) ( 58709 65534 -29122 ) ( -58523 -65534 29493 ) fstng_0 0 0 0 1 1 - } - { //brush 508 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 90 1 1 - } - { //brush 509 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 180 1 1 - } - { //brush 510 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 58667 -65534 -29205 ) ( 58667 65534 -29205 ) ( -58565 -65534 29410 ) fstng_0 0 0 0 1 1 - } - { //brush 511 - ( -65535 -128 65535 ) ( 65535 -128 65535 ) ( -65535 -128 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( 58481 -65534 29576 ) ( 58481 65534 29576 ) ( -58750 -65534 -29039 ) fstng_0 0 0 0 1 1 - } - { //brush 512 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 513 - ( 280 65535 65535 ) ( 280 -65535 65535 ) ( 280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 514 - ( 276 65535 65535 ) ( 276 -65535 65535 ) ( 276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 515 - ( 272 65535 65535 ) ( 272 -65535 65535 ) ( 272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 516 - ( 268 65535 65535 ) ( 268 -65535 65535 ) ( 268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 517 - ( 264 65535 65535 ) ( 264 -65535 65535 ) ( 264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 518 - ( 260 65535 65535 ) ( 260 -65535 65535 ) ( 260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 519 - ( 256 65535 65535 ) ( 256 -65535 65535 ) ( 256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 520 - ( 252 65535 65535 ) ( 252 -65535 65535 ) ( 252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 521 - ( 248 65535 65535 ) ( 248 -65535 65535 ) ( 248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 522 - ( 244 65535 65535 ) ( 244 -65535 65535 ) ( 244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 523 - ( 240 65535 65535 ) ( 240 -65535 65535 ) ( 240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 524 - ( 236 65535 65535 ) ( 236 -65535 65535 ) ( 236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 525 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 0 1 1 - } - { //brush 526 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 527 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( 58824 28892 65535 ) ( -58408 -29724 65535 ) ( -58408 -29724 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 528 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 529 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( 66060 14420 63387 ) ( -51172 -44196 63387 ) ( -65685 -15170 -63601 ) mtn 0 0 0 1 1 - ( 58830 28879 65535 ) ( -58401 -29736 65535 ) ( -58401 -29736 -65535 ) mtn 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) mtn 0 0 180 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 530 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 531 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) stonesnow 0 0 0 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 532 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 180 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 533 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 534 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 268 ) ( 65535 65535 268 ) ( -65535 -65535 268 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 535 - ( -276 -65535 65535 ) ( -276 65535 65535 ) ( -276 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 252 ) ( 65535 65535 252 ) ( -65535 -65535 252 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 536 - ( -272 -65535 65535 ) ( -272 65535 65535 ) ( -272 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 236 ) ( 65535 65535 236 ) ( -65535 -65535 236 ) fstng_0 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 537 - ( -268 -65535 65535 ) ( -268 65535 65535 ) ( -268 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 220 ) ( 65535 65535 220 ) ( -65535 -65535 220 ) fstng_0 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 538 - ( -264 -65535 65535 ) ( -264 65535 65535 ) ( -264 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 204 ) ( 65535 65535 204 ) ( -65535 -65535 204 ) fstng_0 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 539 - ( -260 -65535 65535 ) ( -260 65535 65535 ) ( -260 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 188 ) ( 65535 65535 188 ) ( -65535 -65535 188 ) fstng_0 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 180 1 1 - } - { //brush 540 - ( -256 -65535 65535 ) ( -256 65535 65535 ) ( -256 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 172 ) ( 65535 65535 172 ) ( -65535 -65535 172 ) fstng_0 0 0 0 1 1 - ( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 541 - ( -252 -65535 65535 ) ( -252 65535 65535 ) ( -252 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 156 ) ( 65535 65535 156 ) ( -65535 -65535 156 ) fstng_0 0 0 0 1 1 - ( 65535 65535 160 ) ( 65535 -65535 160 ) ( -65535 -65535 160 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 542 - ( -248 -65535 65535 ) ( -248 65535 65535 ) ( -248 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 140 ) ( 65535 65535 140 ) ( -65535 -65535 140 ) fstng_0 0 0 0 1 1 - ( 65535 65535 144 ) ( 65535 -65535 144 ) ( -65535 -65535 144 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 543 - ( -244 -65535 65535 ) ( -244 65535 65535 ) ( -244 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 124 ) ( 65535 65535 124 ) ( -65535 -65535 124 ) fstng_0 0 0 0 1 1 - ( 65535 65535 128 ) ( 65535 -65535 128 ) ( -65535 -65535 128 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 544 - ( -240 -65535 65535 ) ( -240 65535 65535 ) ( -240 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 108 ) ( 65535 65535 108 ) ( -65535 -65535 108 ) fstng_0 0 0 0 1 1 - ( 65535 65535 112 ) ( 65535 -65535 112 ) ( -65535 -65535 112 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) fstng_0 0 0 0 1 1 - } - { //brush 545 - ( -236 -65535 65535 ) ( -236 65535 65535 ) ( -236 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -256 65535 ) ( -65535 -256 65535 ) ( -65535 -256 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 92 ) ( 65535 65535 92 ) ( -65535 -65535 92 ) fstng_0 0 0 0 1 1 - ( 65535 65535 96 ) ( 65535 -65535 96 ) ( -65535 -65535 96 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 180 1 1 - } - { //brush 546 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -58824 28892 65535 ) ( 58408 -29724 65535 ) ( -58824 28892 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 547 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - ( 58408 -29724 65535 ) ( -58824 28892 65535 ) ( -58824 28892 -65535 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 548 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 549 - ( -128 65535 65535 ) ( -128 -65535 65535 ) ( -128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 550 - ( -128 -65535 65535 ) ( -128 65535 65535 ) ( -128 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) mtn 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) mtn 0 0 0 1 1 - ( 58401 -29736 65535 ) ( -58830 28879 65535 ) ( -58830 28879 -65535 ) mtn 0 0 0 1 1 - ( 51172 -44196 63387 ) ( -66060 14420 63387 ) ( -51547 43446 -63601 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) mtn 0 0 180 1 1 - } - { //brush 551 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 90 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 180 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 552 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) stonesnow 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) stonesnow 0 0 180 1 1 - } - { //brush 553 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 554 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 555 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -65534 -16203 63501 ) ( 65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - ( 64518 11513 65535 ) ( -64306 -12641 65535 ) ( -64306 -12641 -65535 ) mtn 0 0 0 1 1 - } - { //brush 556 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( -58744 29052 65535 ) ( 58488 -29564 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 557 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64088 13701 65535 ) ( -63859 -14731 65535 ) ( -63859 -14731 -65535 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( -58795 28949 65535 ) ( 58437 -29666 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 558 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( 63219 26421 62412 ) ( -67199 13380 62412 ) ( -63094 -27677 -61993 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - } - { //brush 559 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -65271 14499 64180 ) ( 54501 -38733 64180 ) ( -54837 37977 -64346 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 - } - { //brush 560 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( 54501 -38733 64180 ) ( -65271 14499 64180 ) ( -54837 37977 -64346 ) mtn 0 0 0 1 1 - } - { //brush 561 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 59675 -27091 65535 ) ( -60097 26141 65535 ) ( -60097 26141 -65535 ) stonesnow 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) stonesnow 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 562 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 563 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65534 -16350 63464 ) ( -65534 -16350 63464 ) ( -65534 15439 -63692 ) stnwll02 0 0 0 1 1 - } - { //brush 564 - ( 1680 65535 65535 ) ( 1680 -65535 65535 ) ( 1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 1712 -65535 65535 ) ( 1712 65535 65535 ) ( 1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 45828 46852 ) ( -65535 45828 46852 ) ( -65535 -46852 -45828 ) millgt1 16 0 0 1 0.500000 - } - { //brush 565 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1680 -65535 65535 ) ( 1680 65535 65535 ) ( 1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 566 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 567 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 568 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 569 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( -58488 -29564 65535 ) ( 58744 29052 65535 ) ( -58488 -29564 -65535 ) mtn 0 0 0 1 1 - ( 65534 -16203 63501 ) ( -65534 -16203 63501 ) ( -65534 15585 -63655 ) mtn 0 0 0 1 1 - } - { //brush 570 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 58744 29052 65535 ) ( -58488 -29564 65535 ) ( -58488 -29564 -65535 ) mtn 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - } - { //brush 571 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) stonesnow 0 0 0 1 1 - ( -64518 11513 65535 ) ( 64306 -12641 65535 ) ( -64518 11513 -65535 ) stonesnow 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 572 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( 64306 -12641 65535 ) ( -64518 11513 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( -64976 -8546 65535 ) ( 65081 7711 65535 ) ( -64976 -8546 -65535 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - } - { //brush 573 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 574 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) ftlattice2 16 16 0 1 1 - ( 65535 -63726 -15303 ) ( 65535 63430 16485 ) ( -65535 -63726 -15303 ) ftlattice2 16 16 0 1 1 - ( 63618 -65534 15732 ) ( 63618 65534 15732 ) ( -63537 -65534 -16056 ) ftlattice2 16 16 0 1 1 - ( 63865 -65534 -14746 ) ( 63865 65534 -14746 ) ( -63291 -65534 17042 ) ftlattice2 16 16 0 1 1 - } - { //brush 575 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) fstng_2 0 16 0 1 1 - } - { //brush 576 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 577 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 578 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( -27688 59425 65535 ) ( 30927 -57806 65535 ) ( -27688 59425 -65535 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 579 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 59313 27912 65535 ) ( -57918 -30703 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 580 - ( 1872 65535 65535 ) ( 1872 -65535 65535 ) ( 1872 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 672 ) ( 65535 -65535 672 ) ( -65535 -65535 672 ) fstng_2 0 0 0 1 1 - ( -65535 -46316 46364 ) ( 65535 -46316 46364 ) ( -65535 46364 -46316 ) fstng_2 0 0 0 1 1 - } - { //brush 581 - ( 1808 65535 65535 ) ( 1808 -65535 65535 ) ( 1808 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1872 -65535 65535 ) ( 1872 65535 65535 ) ( 1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 582 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 - ( 63784 -65534 -15070 ) ( 63784 65534 -15070 ) ( -63372 -65534 16719 ) ftlattice2 16 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 - ( 63492 -65534 16237 ) ( 63492 65534 16237 ) ( -63663 -65534 -15551 ) ftlattice2 16 16 0 1 1 - } - { //brush 583 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 0 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 0 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 0 16 0 1 1 - ( 63512 -65534 16158 ) ( 63512 65534 16158 ) ( -63644 -65534 -15631 ) ftlattice2 0 16 0 1 1 - ( 63804 -65534 -14991 ) ( 63804 65534 -14991 ) ( -63352 -65534 16798 ) ftlattice2 0 16 0 1 1 - } - { //brush 584 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 - ( 63823 -65534 -14911 ) ( 63823 65534 -14911 ) ( -63332 -65534 16877 ) ftlattice2 16 16 0 1 1 - ( 63532 -65534 16079 ) ( 63532 65534 16079 ) ( -63624 -65534 -15710 ) ftlattice2 16 16 0 1 1 - } - { //brush 585 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) tile2492 0 0 90 1 1 - } - { //brush 586 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( 66017 -5667 64802 ) ( -64797 -13842 64802 ) ( -65975 4998 -64900 ) mtn 0 0 0 1 1 - ( 66636 8945 63790 ) ( -56087 -37076 63790 ) ( -66577 -9104 -63830 ) mtn 0 0 0 1 1 - ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - } - { //brush 587 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -448 65535 ) ( -65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( 65535 -14338 63948 ) ( -65535 -14338 63948 ) ( -65535 13670 -64094 ) mtn 0 0 0 1 1 - } - { //brush 588 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 - ( 50015 -46510 62651 ) ( -67217 12106 62651 ) ( -50469 45601 -62954 ) tile2492 0 0 180 1 1 - } - { //brush 589 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 590 - ( 1872 -65535 65535 ) ( 1872 65535 65535 ) ( 1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 591 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 592 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 16 0 1 1 - ( 46508 65535 46172 ) ( 46508 -65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 0 1 1 - ( 65535 45660 47020 ) ( -65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 593 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 180 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 16 90 1 1 - } - { //brush 594 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 90 1 1 - } - { //brush 595 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) fstng_2 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 596 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) tile2492 0 0 90 1 1 - ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 597 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_0 0 0 0 1 1 - ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 598 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 65535 -63579 15890 ) ( 65535 63577 -15898 ) ( -65535 -63579 15890 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 65535 -63675 -15506 ) ( 65535 63481 16282 ) ( -65535 -63675 -15506 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - } - { //brush 599 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - ( 64299 -12680 65535 ) ( -64525 11474 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) tile2492 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 600 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 45644 47036 ) ( -65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_2 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 601 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 65535 45644 47036 ) ( -65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 602 - ( 2224 65535 65535 ) ( 2224 -65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 - } - { //brush 603 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( 65535 45596 47084 ) ( -65535 45596 47084 ) ( -65535 -47084 -45596 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16598 63402 ) ( 65534 -16598 63402 ) ( -65534 15190 -63754 ) millgt1 16 0 0 1 0.500000 - } - { //brush 604 - ( 2192 65535 65535 ) ( 2192 -65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2224 -65535 65535 ) ( 2224 65535 65535 ) ( 2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 0 1 1 - ( 65534 -16598 63402 ) ( -65534 -16598 63402 ) ( -65534 15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 605 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( 65535 45596 47084 ) ( -65535 45596 47084 ) ( -65535 -47084 -45596 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16598 63402 ) ( 65534 -16598 63402 ) ( -65534 15190 -63754 ) millgt1 16 0 0 1 0.500000 - } - { //brush 606 - ( 1968 65535 65535 ) ( 1968 -65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2000 -65535 65535 ) ( 2000 65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 0 1 1 - ( 65534 -16598 63402 ) ( -65534 -16598 63402 ) ( -65534 15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 607 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 608 - ( 1968 -65535 65535 ) ( 1968 65535 65535 ) ( 1968 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 - } - { //brush 609 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 - ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 - } - { //brush 610 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 480 65535 ) ( 65535 480 65535 ) ( -65535 480 -65535 ) mtn 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) mtn 0 0 0 1 1 - } - { //brush 611 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 612 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll05 0 0 90 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 613 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -480 65535 ) ( 65535 -480 65535 ) ( -65535 -480 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 480 65535 ) ( -65535 480 65535 ) ( -65535 480 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 614 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -768 -65535 65535 ) ( -768 65535 65535 ) ( -768 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) mtn 0 0 0 1 1 - } - { //brush 615 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 -36876 54178 ) ( -65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 616 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -36876 54178 ) ( -65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 617 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 618 - ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - } - { //brush 619 - ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 180 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 620 - ( -144 65535 65535 ) ( -144 -65535 65535 ) ( -144 65535 -65535 ) shootit 16 0 180 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 621 - ( -400 65535 65535 ) ( -400 -65535 65535 ) ( -400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -144 -65535 65535 ) ( -144 65535 65535 ) ( -144 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 622 - ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) shootit 16 0 180 1 1 - ( -400 -65535 65535 ) ( -400 65535 65535 ) ( -400 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 623 - ( -464 65535 65535 ) ( -464 -65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -432 -65535 65535 ) ( -432 65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 90 1 1 - } - { //brush 624 - ( -496 65535 65535 ) ( -496 -65535 65535 ) ( -496 65535 -65535 ) shootit 16 0 180 1 1 - ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 625 - ( -496 -65535 65535 ) ( -496 65535 65535 ) ( -496 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 626 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 627 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 628 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 629 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 630 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) shootit 16 0 180 1 1 - ( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) shootit 16 0 0 1 1 - } - { //brush 631 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -784 -65535 65535 ) ( -784 65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 58107 -30325 65535 ) ( -59125 28290 65535 ) ( -59125 28290 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 632 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - } - { //brush 633 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 15073 65534 63783 ) ( 15073 -65534 63783 ) ( -16715 65534 -63373 ) stnwll01 0 0 0 1 1 - } - { //brush 634 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( -46436 65535 46244 ) ( -46436 -65535 46244 ) ( 46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( 15073 -65534 63783 ) ( 15073 65534 63783 ) ( -16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 - } - { //brush 635 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 15073 65534 63783 ) ( 15073 -65534 63783 ) ( -16715 65534 -63373 ) stnwll01 0 0 0 1 1 - } - { //brush 636 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 90 1 0.500000 - ( -46436 65535 46244 ) ( -46436 -65535 46244 ) ( 46244 65535 -46436 ) millgt1 0 0 90 1 0.500000 - ( 15073 -65534 63783 ) ( 15073 65534 63783 ) ( -16715 65534 -63373 ) millgt1 0 0 0 1 0.500000 - } - { //brush 637 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } - { //brush 638 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) shootit 16 16 180 1 1 - ( -65535 -1072 65535 ) ( 65535 -1072 65535 ) ( -65535 -1072 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1040 65535 ) ( -65535 -1040 65535 ) ( -65535 -1040 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 16 0 1 1 - ( 58728 -65534 -29084 ) ( 58728 65534 -29084 ) ( -58504 -65534 29532 ) shootit 16 16 0 1 1 - } - { //brush 639 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 640 - ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 641 - ( -144 65535 65535 ) ( -144 -65535 65535 ) ( -144 65535 -65535 ) shootit 16 0 180 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 642 - ( -400 65535 65535 ) ( -400 -65535 65535 ) ( -400 65535 -65535 ) tile2492 0 0 0 1 1 - ( -144 -65535 65535 ) ( -144 65535 65535 ) ( -144 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 643 - ( -432 65535 65535 ) ( -432 -65535 65535 ) ( -432 65535 -65535 ) shootit 16 0 180 1 1 - ( -400 -65535 65535 ) ( -400 65535 65535 ) ( -400 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 644 - ( -464 65535 65535 ) ( -464 -65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 0 1 1 - ( -432 -65535 65535 ) ( -432 65535 65535 ) ( -432 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 645 - ( -496 65535 65535 ) ( -496 -65535 65535 ) ( -496 65535 -65535 ) shootit 16 0 180 1 1 - ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 646 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) tile2492 0 0 0 1 1 - ( -496 -65535 65535 ) ( -496 65535 65535 ) ( -496 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 647 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) shootit 16 0 180 1 1 - ( -752 -65535 65535 ) ( -752 65535 65535 ) ( -752 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 648 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 0 1 1 - ( -784 -65535 65535 ) ( -784 65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 649 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) fstng_0 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 650 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stnwll01 0 0 0 1 1 - ( 58952 28636 65535 ) ( -58280 -29980 65535 ) ( -58280 -29980 -65535 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 0 1 1 - } - { //brush 651 - ( -816 65535 65535 ) ( -816 -65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) fstng_2 0 0 0 1 1 - } - { //brush 652 - ( -1968 65535 65535 ) ( -1968 -65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 653 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45596 47084 ) ( 65535 -45596 47084 ) ( -65535 47084 -45596 ) millgt1 16 0 0 1 0.500000 - } - { //brush 654 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 - ( 65535 -45596 47084 ) ( -65535 -45596 47084 ) ( -65535 47084 -45596 ) stnwll01 0 0 0 1 1 - ( -65534 16598 63402 ) ( 65534 16598 63402 ) ( -65534 -15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 655 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - ( -65534 16598 63402 ) ( 65534 16598 63402 ) ( -65534 -15190 -63754 ) stnwll01 0 0 0 1 1 - } - { //brush 656 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45596 47084 ) ( 65535 -45596 47084 ) ( -65535 47084 -45596 ) millgt1 16 0 0 1 0.500000 - ( 65534 16598 63402 ) ( -65534 16598 63402 ) ( -65534 -15190 -63754 ) millgt1 16 0 0 1 0.500000 - } - { //brush 657 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 658 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( -65535 -45644 47036 ) ( 65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 0 0 1 1 - } - { //brush 659 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -65535 -45644 47036 ) ( 65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 660 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 661 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 90 1 1 - } - { //brush 662 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 180 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 16 90 1 1 - } - { //brush 663 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_2 0 16 0 1 1 - ( -46508 -65535 46172 ) ( -46508 65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 0 1 1 - ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 664 - ( -1872 65535 65535 ) ( -1872 -65535 65535 ) ( -1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 0 1 1 - } - { //brush 665 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -65535 -45660 47020 ) ( 65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 666 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 667 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 0 16 0 1 1 - ( 63352 -65534 16798 ) ( 63352 65534 16798 ) ( -63804 -65534 -14991 ) ftlattice2 0 16 0 1 1 - ( 63644 -65534 -15631 ) ( 63644 65534 -15631 ) ( -63512 -65534 16158 ) ftlattice2 0 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 0 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 0 16 0 1 1 - } - { //brush 668 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63624 -65534 -15710 ) ( 63624 65534 -15710 ) ( -63532 -65534 16079 ) ftlattice2 16 16 0 1 1 - ( 63332 -65534 16877 ) ( 63332 65534 16877 ) ( -63823 -65534 -14911 ) ftlattice2 16 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 - } - { //brush 669 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 65535 -63684 -15469 ) ( 65535 63471 16319 ) ( -65535 -63684 -15469 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - ( 65535 -63392 16636 ) ( 65535 63763 -15152 ) ( -65535 -63392 16636 ) ftlattice2 16 16 0 1 1 - } - { //brush 670 - ( -1872 65535 65535 ) ( -1872 -65535 65535 ) ( -1872 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1808 -65535 65535 ) ( -1808 65535 65535 ) ( -1808 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 671 - ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1872 -65535 65535 ) ( -1872 65535 65535 ) ( -1872 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 672 ) ( 65535 -65535 672 ) ( -65535 -65535 672 ) fstng_2 0 0 0 1 1 - ( 65535 46316 46364 ) ( -65535 46316 46364 ) ( -65535 -46364 -46316 ) fstng_2 0 0 0 1 1 - } - { //brush 672 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 673 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 674 - ( -1680 65535 65535 ) ( -1680 -65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 675 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -65534 16350 63464 ) ( 65534 16350 63464 ) ( -65534 -15439 -63692 ) stnwll02 0 0 0 1 1 - } - { //brush 676 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65535 -45828 46852 ) ( 65535 -45828 46852 ) ( -65535 46852 -45828 ) millgt1 16 0 0 1 0.500000 - ( 65534 16350 63464 ) ( -65534 16350 63464 ) ( -65534 -15439 -63692 ) millgt1 16 0 0 1 0.500000 - } - { //brush 677 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 678 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27688 -59425 65535 ) ( -30927 57806 65535 ) ( -30927 57806 -65535 ) stnwll01 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 679 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 680 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 681 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 - } - { //brush 682 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63430 16485 ) ( 65535 63726 -15303 ) ( -65535 -63430 16485 ) ftlattice2 16 16 0 1 1 - ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 16 0 1 1 - ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) ftlattice2 16 16 0 1 1 - ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 16 0 1 1 - } - { //brush 683 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -59313 -27912 65535 ) ( 57918 30703 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 684 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 685 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnfloor02 0 0 0 1 1 - } - { //brush 686 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 687 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 688 ) ( 65535 65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 688 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 689 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) ctf08 32 48 0 1 1 - ( -872 -65535 65535 ) ( -872 65535 65535 ) ( -872 65535 -65535 ) ctf08 32 48 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) ctf08 32 48 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) ctf08 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf08 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf08 32 48 90 1 1 - } - { //brush 690 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - } - { //brush 691 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) ctf08 32 48 0 1 1 - ( -872 -65535 65535 ) ( -872 65535 65535 ) ( -872 65535 -65535 ) ctf08 32 48 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf08 32 48 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) ctf08 32 48 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) ctf08 32 48 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) ctf08 32 48 90 1 1 - } - { //brush 692 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 688 ) ( 65535 -65535 688 ) ( -65535 -65535 688 ) stnwll05 0 0 90 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 693 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58200 -65534 30140 ) ( 58200 65534 30140 ) ( -59032 -65534 -28476 ) fstng_2 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 694 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 695 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) stnwll05 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 696 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 697 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) mtn 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 704 ) ( 65535 65535 704 ) ( -65535 -65535 704 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62234 20536 65535 ) ( -62109 -20911 65535 ) ( -62109 -20911 -65535 ) mtn 0 0 0 1 1 - } - { //brush 698 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 704 ) ( 65535 -65535 704 ) ( -65535 -65535 704 ) stnfloor02 0 0 0 1 1 - } - { //brush 699 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62234 20536 65535 ) ( -62109 -20911 65535 ) ( -62109 -20911 -65535 ) mtn 0 0 0 1 1 - } - { //brush 700 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stonesnow 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 701 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) mtn 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 702 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -64593 11074 65535 ) ( 64693 -10472 65535 ) ( -64593 11074 -65535 ) mtn 0 0 0 1 1 - ( -59013 -28514 65535 ) ( 58219 30101 65535 ) ( -59013 -28514 -65535 ) mtn 0 0 0 1 1 - } - { //brush 703 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) mtn 0 0 180 1 1 - ( -960 -65535 65535 ) ( -960 65535 65535 ) ( -960 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 58219 -30101 65535 ) ( -59013 28514 65535 ) ( -59013 28514 -65535 ) mtn 0 0 0 1 1 - ( 64693 10472 65535 ) ( -64593 -11074 65535 ) ( -64593 -11074 -65535 ) mtn 0 0 0 1 1 - } - { //brush 704 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -960 -65535 65535 ) ( -960 65535 65535 ) ( -960 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - } - { //brush 705 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - ( 65535 -63424 16508 ) ( 65535 63731 -15280 ) ( -65535 -63424 16508 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 65535 -63716 -15341 ) ( 65535 63439 16447 ) ( -65535 -63716 -15341 ) ftlattice2 16 16 0 1 1 - } - { //brush 706 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 0 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 0 0 1 1 - ( 65535 -63700 -15405 ) ( 65535 63455 16383 ) ( -65535 -63700 -15405 ) ftlattice2 16 0 0 1 1 - ( 65535 -63408 16572 ) ( 65535 63747 -15216 ) ( -65535 -63408 16572 ) ftlattice2 16 0 0 1 1 - } - { //brush 707 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 65535 -63439 16447 ) ( 65535 63716 -15341 ) ( -65535 -63439 16447 ) ftlattice2 16 16 0 1 1 - ( 65535 -63731 -15280 ) ( 65535 63424 16508 ) ( -65535 -63731 -15280 ) ftlattice2 16 16 0 1 1 - } - { //brush 708 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 0 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 0 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 0 0 1 1 - ( 65535 -63747 -15216 ) ( 65535 63408 16572 ) ( -65535 -63747 -15216 ) ftlattice2 16 0 0 1 1 - ( 65535 -63455 16383 ) ( 65535 63700 -15405 ) ( -65535 -63455 16383 ) ftlattice2 16 0 0 1 1 - } - { //brush 709 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - } - { //brush 710 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 711 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 712 - ( -976 65535 65535 ) ( -976 -65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 713 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 714 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( 65534 16116 63522 ) ( -65534 16116 63522 ) ( -65534 -15672 -63633 ) millgt1 16 0 0 1 0.500000 - } - { //brush 715 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1008 -65535 65535 ) ( -1008 65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 716 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - } - { //brush 717 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 - } - { //brush 718 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( -65534 16116 63522 ) ( 65534 16116 63522 ) ( -65534 -15672 -63633 ) stnwll05 0 0 0 1 1 - ( 65535 -45972 46708 ) ( -65535 -45972 46708 ) ( -65535 46708 -45972 ) stnwll05 0 0 0 1 1 - } - { //brush 719 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - } - { //brush 720 - ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15352 63713 ) ( 65534 -15352 63713 ) ( -65534 16436 -63442 ) millgt1 0 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 721 - ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65534 -15352 63713 ) ( -65534 -15352 63713 ) ( -65534 16436 -63442 ) stnwll02 0 0 0 1 1 - } - { //brush 722 - ( -1280 65535 65535 ) ( -1280 -65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 723 - ( -1312 65535 65535 ) ( -1312 -65535 65535 ) ( -1312 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - } - { //brush 724 - ( -1344 65535 65535 ) ( -1344 -65535 65535 ) ( -1344 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1312 -65535 65535 ) ( -1312 65535 65535 ) ( -1312 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 725 - ( -1376 65535 65535 ) ( -1376 -65535 65535 ) ( -1376 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1344 -65535 65535 ) ( -1344 65535 65535 ) ( -1344 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - } - { //brush 726 - ( -1408 65535 65535 ) ( -1408 -65535 65535 ) ( -1408 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1376 -65535 65535 ) ( -1376 65535 65535 ) ( -1376 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - } - { //brush 727 - ( -1440 65535 65535 ) ( -1440 -65535 65535 ) ( -1440 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1408 -65535 65535 ) ( -1408 65535 65535 ) ( -1408 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - } - { //brush 728 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1440 -65535 65535 ) ( -1440 65535 65535 ) ( -1440 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 729 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 730 - ( -1536 65535 65535 ) ( -1536 -65535 65535 ) ( -1536 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 731 - ( -1568 65535 65535 ) ( -1568 -65535 65535 ) ( -1568 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1536 -65535 65535 ) ( -1536 65535 65535 ) ( -1536 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 732 - ( -1600 65535 65535 ) ( -1600 -65535 65535 ) ( -1600 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1568 -65535 65535 ) ( -1568 65535 65535 ) ( -1568 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 733 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1600 -65535 65535 ) ( -1600 65535 65535 ) ( -1600 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 448 65535 ) ( 65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 734 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 735 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15352 63713 ) ( 65534 -15352 63713 ) ( -65534 16436 -63442 ) millgt1 0 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 0 0 0 1 0.500000 - } - { //brush 736 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65534 -15352 63713 ) ( -65534 -15352 63713 ) ( -65534 16436 -63442 ) stnwll02 0 0 0 1 1 - } - { //brush 737 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 738 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 416 65535 ) ( 65535 416 65535 ) ( -65535 416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 448 65535 ) ( -65535 448 65535 ) ( -65535 448 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 739 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 384 65535 ) ( 65535 384 65535 ) ( -65535 384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 416 65535 ) ( -65535 416 65535 ) ( -65535 416 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - } - { //brush 740 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 352 65535 ) ( 65535 352 65535 ) ( -65535 352 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 384 65535 ) ( -65535 384 65535 ) ( -65535 384 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 741 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1280 -65535 65535 ) ( -1280 65535 65535 ) ( -1280 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 742 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - ( 58625 65534 -29288 ) ( 58625 -65534 -29288 ) ( -58606 -65534 29327 ) stnfloor02 0 0 0 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 743 - ( -896 65535 65535 ) ( -896 -65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - ( 28501 59019 65535 ) ( -30114 -58213 65535 ) ( 28501 59019 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 744 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( 28501 59019 65535 ) ( -30114 -58213 65535 ) ( 28501 59019 -65535 ) stnwll05 0 0 0 1 1 - ( -30088 58225 65535 ) ( 28527 -59006 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 745 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -30114 -58213 65535 ) ( 28501 59019 65535 ) ( 28501 59019 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 746 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll05 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnfloor02 0 0 0 1 1 - ( -28937 58807 65535 ) ( 27299 -59585 65535 ) ( -28937 58807 -65535 ) stnwll05 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 747 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 748 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 749 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 28168 59185 65535 ) ( -30447 -58046 65535 ) ( 28168 59185 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) fstng_2 0 0 0 1 1 - ( -30088 -58225 65535 ) ( 28527 59006 65535 ) ( 28527 59006 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 750 - ( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 751 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 58491 -29557 65535 ) ( -58741 29058 65535 ) ( -58741 29058 -65535 ) stnwll05 0 0 0 1 1 - ( 28367 59086 65535 ) ( -30248 -58145 65535 ) ( 28367 59086 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 752 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - } - { //brush 753 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 754 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) millgt1 16 0 90 1 0.500000 - ( -46700 65535 45980 ) ( -46700 -65535 45980 ) ( 45980 65535 -46700 ) millgt1 16 0 90 1 0.500000 - ( 14746 -65534 63865 ) ( 14746 65534 63865 ) ( -17042 65534 -63291 ) millgt1 16 0 0 1 0.500000 - } - { //brush 755 - ( -848 65535 65535 ) ( -848 -65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 756 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( -58741 -29058 65535 ) ( 58491 29557 65535 ) ( -58741 -29058 -65535 ) stnwll05 0 0 0 1 1 - ( -30248 58145 65535 ) ( 28367 -59086 65535 ) ( -30248 58145 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 757 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) fstng_2 0 0 0 1 1 - ( 28527 -59006 65535 ) ( -30088 58225 65535 ) ( -30088 58225 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 758 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 759 - ( -976 65535 65535 ) ( -976 -65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 760 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( -65534 -16116 63522 ) ( 65534 -16116 63522 ) ( -65534 15672 -63633 ) millgt1 16 0 0 1 0.500000 - } - { //brush 761 - ( -1008 65535 65535 ) ( -1008 -65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -976 -65535 65535 ) ( -976 65535 65535 ) ( -976 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - } - { //brush 762 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1008 -65535 65535 ) ( -1008 65535 65535 ) ( -1008 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 763 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 764 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65534 -16116 63522 ) ( -65534 -16116 63522 ) ( -65534 15672 -63633 ) stnwll05 0 0 0 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 45972 46708 ) ( 65535 45972 46708 ) ( -65535 -46708 -45972 ) stnwll05 0 0 0 1 1 - } - { //brush 765 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 45972 46708 ) ( -65535 45972 46708 ) ( -65535 -46708 -45972 ) millgt1 16 0 0 1 0.500000 - } - { //brush 766 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -320 65535 ) ( -65535 -320 65535 ) ( -65535 -320 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 767 - ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 28168 -59185 65535 ) ( -30447 58046 65535 ) ( -30447 58046 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 768 - ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -30447 -58046 65535 ) ( 28168 59185 65535 ) ( 28168 59185 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 769 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 770 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( 65535 46196 46484 ) ( -65535 46196 46484 ) ( -65535 -46484 -46196 ) millgt1 16 0 0 1 0.500000 - } - { //brush 771 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 772 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 16 0 0 1 1 - ( 63389 -65534 16651 ) ( 63389 65534 16651 ) ( -63767 -65534 -15137 ) millgt1 16 0 0 1 1 - ( 65535 -63476 16301 ) ( 65535 63679 -15487 ) ( -65535 -63476 16301 ) millgt1 16 0 0 1 1 - ( 63567 -65534 -15935 ) ( 63567 65534 -15935 ) ( -63588 -65534 15853 ) millgt1 16 0 0 1 1 - ( 65535 -63655 -15585 ) ( 65535 63501 16203 ) ( -65535 -63655 -15585 ) millgt1 16 0 0 1 1 - } - { //brush 773 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - } - { //brush 774 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 775 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 776 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - } - { //brush 777 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 778 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - ( -46980 65535 45700 ) ( -46980 -65535 45700 ) ( 45700 65535 -46980 ) fstng_2 0 0 90 1 1 - } - { //brush 779 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 45284 -65535 47396 ) ( 45284 65535 47396 ) ( -47396 65535 -45284 ) fstng_2 0 0 90 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 780 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 781 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 782 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( -65534 15231 63743 ) ( 65534 15231 63743 ) ( -65534 -16557 -63412 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 783 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 0 0 0 1 0.500000 - ( 65534 15231 63743 ) ( -65534 15231 63743 ) ( -65534 -16557 -63412 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) millgt1 0 0 0 1 0.500000 - } - { //brush 784 - ( -1680 65535 65535 ) ( -1680 -65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 785 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 786 - ( -1712 65535 65535 ) ( -1712 -65535 65535 ) ( -1712 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1680 -65535 65535 ) ( -1680 65535 65535 ) ( -1680 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 - } - { //brush 787 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 788 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - } - { //brush 789 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 790 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27688 -59425 65535 ) ( -30927 57806 65535 ) ( -30927 57806 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 791 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 792 - ( -1888 65535 65535 ) ( -1888 -65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 793 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 794 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 -46116 46564 ) ( -65535 -46116 46564 ) ( -65535 46564 -46116 ) stnwll02 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 795 - ( -1968 65535 65535 ) ( -1968 -65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 796 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 16 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 16 0 0 1 0.500000 - ( -65534 -15333 63718 ) ( 65534 -15333 63718 ) ( -65534 16455 -63438 ) millgt1 16 0 0 1 0.500000 - } - { //brush 797 - ( -2000 65535 65535 ) ( -2000 -65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 0 1 1 - ( 65534 -15333 63718 ) ( -65534 -15333 63718 ) ( -65534 16455 -63438 ) stnwll01 0 0 0 1 1 - } - { //brush 798 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 0 1 1 - ( 65534 -15333 63718 ) ( -65534 -15333 63718 ) ( -65534 16455 -63438 ) stnwll01 0 0 0 1 1 - ( -65535 46268 46412 ) ( 65535 46268 46412 ) ( -65535 -46412 -46268 ) stnwll01 0 0 0 1 1 - } - { //brush 799 - ( -2224 65535 65535 ) ( -2224 -65535 65535 ) ( -2224 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2192 -65535 65535 ) ( -2192 65535 65535 ) ( -2192 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 16 0 0 1 0.500000 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) millgt1 16 0 0 1 0.500000 - } - { //brush 800 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 801 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - } - { //brush 802 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 803 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 804 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 112 65535 ) ( 65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - } - { //brush 805 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 806 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( -65534 15887 63580 ) ( 65534 15887 63580 ) ( -65534 -15902 -63576 ) stnwll02 0 0 0 1 1 - } - { //brush 807 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) millgt1 0 0 0 1 0.500000 - ( 65534 15887 63580 ) ( -65534 15887 63580 ) ( -65534 -15902 -63576 ) millgt1 0 0 0 1 0.500000 - } - { //brush 808 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 112 65535 ) ( -65535 112 65535 ) ( -65535 112 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 809 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 810 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - } - { //brush 811 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 - } - { //brush 812 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 90 1 1 - ( 65535 -46044 46636 ) ( -65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 90 1 1 - ( -47116 65535 45564 ) ( -47116 -65535 45564 ) ( 45564 65535 -47116 ) fstng_2 0 16 90 1 1 - } - { //brush 813 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 - ( -47116 -65535 45564 ) ( -47116 65535 45564 ) ( 45564 65535 -47116 ) fstng_2 0 16 0 1 1 - } - { //brush 814 - ( -2048 -65535 65535 ) ( -2048 65535 65535 ) ( -2048 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 - ( -47172 65535 45508 ) ( -47172 -65535 45508 ) ( 45508 65535 -47172 ) millgt1 16 0 90 1 0.500000 - } - { //brush 815 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 816 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) millgt1 0 0 0 1 0.500000 - } - { //brush 817 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 0 1 1 - ( -65534 15231 63743 ) ( 65534 15231 63743 ) ( -65534 -16557 -63412 ) stnwll02 0 0 0 1 1 - } - { //brush 818 - ( -1888 65535 65535 ) ( -1888 -65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 819 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( -65535 46116 46564 ) ( 65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 820 - ( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1888 -65535 65535 ) ( -1888 65535 65535 ) ( -1888 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 821 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1920 -65535 65535 ) ( -1920 65535 65535 ) ( -1920 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 822 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) millgt1 0 0 0 1 0.500000 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) millgt1 0 0 0 1 0.500000 - ( -65534 -15887 63580 ) ( 65534 -15887 63580 ) ( -65534 15902 -63576 ) millgt1 0 0 0 1 0.500000 - } - { //brush 823 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 0 1 1 - ( 65534 -15887 63580 ) ( -65534 -15887 63580 ) ( -65534 15902 -63576 ) stnwll02 0 0 0 1 1 - } - { //brush 824 - ( -2336 65535 65535 ) ( -2336 -65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 825 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_2 0 16 90 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 180 1 1 - ( -47244 65535 45436 ) ( -47244 -65535 45436 ) ( 45436 65535 -47244 ) fstng_2 0 16 90 1 1 - } - { //brush 826 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) fstng_0 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 827 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) fstng_2 0 16 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 0 1 1 - } - { //brush 828 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 180 1 1 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - } - { //brush 829 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 0 0 1 1 - ( 65535 -63442 16436 ) ( 65535 63713 -15352 ) ( -65535 -63442 16436 ) ftlattice2 16 0 0 1 1 - ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 0 0 1 1 - ( 65535 -63689 -15450 ) ( 65535 63467 16338 ) ( -65535 -63689 -15450 ) ftlattice2 16 0 0 1 1 - } - { //brush 830 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63677 -15499 ) ( 65535 63479 16289 ) ( -65535 -63677 -15499 ) ftlattice2 16 16 0 1 1 - ( 65535 -63430 16485 ) ( 65535 63726 -15303 ) ( -65535 -63430 16485 ) ftlattice2 16 16 0 1 1 - ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 16 0 1 1 - ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 16 0 1 1 - } - { //brush 831 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 0 0 1 1 - ( 65535 -63689 -15450 ) ( 65535 63467 16338 ) ( -65535 -63689 -15450 ) ftlattice2 16 0 0 1 1 - ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 0 0 1 1 - ( 65535 -63442 16436 ) ( 65535 63713 -15352 ) ( -65535 -63442 16436 ) ftlattice2 16 0 0 1 1 - ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 0 0 1 1 - } - { //brush 832 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 63508 65534 -16173 ) ( 63508 -65534 -16173 ) ( -63647 -65534 15615 ) metdec1 32 0 0 1 1 - ( 65535 -63484 16271 ) ( 65535 63672 -15518 ) ( -65535 -63484 16271 ) metdec1 32 0 0 1 1 - ( 65535 -63646 -15623 ) ( 65535 63510 16165 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 - } - { //brush 833 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) metdec1 32 0 0 1 1 - ( 65535 63672 -15518 ) ( 65535 -63484 16271 ) ( -65535 -63484 16271 ) metdec1 32 0 0 1 1 - ( 63346 -65534 16820 ) ( 63346 65534 16820 ) ( -63809 -65534 -14968 ) metdec1 32 0 0 1 1 - } - { //brush 834 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) metdec1 32 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 63346 65534 16820 ) ( 63346 -65534 16820 ) ( -63809 -65534 -14968 ) metdec1 32 0 0 1 1 - ( 65535 -63646 -15623 ) ( 65535 63510 16165 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 - } - { //brush 835 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) metdec1 32 0 180 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) metdec1 32 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) metdec1 32 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 63510 16165 ) ( 65535 -63646 -15623 ) ( -65535 -63646 -15623 ) metdec1 32 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) metdec1 32 0 0 1 1 - } - { //brush 836 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 837 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 256 65535 ) ( 65535 256 65535 ) ( -65535 256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 838 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 224 65535 ) ( 65535 224 65535 ) ( -65535 224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - } - { //brush 839 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 192 65535 ) ( 65535 192 65535 ) ( -65535 192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 224 65535 ) ( -65535 224 65535 ) ( -65535 224 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) fstng_2 0 0 0 1 1 - } - { //brush 840 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 160 65535 ) ( 65535 160 65535 ) ( -65535 160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 192 65535 ) ( -65535 192 65535 ) ( -65535 192 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 320 ) ( 65535 -65535 320 ) ( -65535 -65535 320 ) fstng_2 0 0 0 1 1 - } - { //brush 841 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 160 65535 ) ( -65535 160 65535 ) ( -65535 160 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 304 ) ( 65535 -65535 304 ) ( -65535 -65535 304 ) fstng_2 0 0 0 1 1 - } - { //brush 842 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 843 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -65534 15920 63571 ) ( 65534 15920 63571 ) ( -65534 -15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 844 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) millgt1 16 0 0 1 0.500000 - ( 65534 15920 63571 ) ( -65534 15920 63571 ) ( -65534 -15868 -63584 ) millgt1 16 0 0 1 0.500000 - } - { //brush 845 - ( -2688 65535 65535 ) ( -2688 -65535 65535 ) ( -2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 846 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2688 -65535 65535 ) ( -2688 65535 65535 ) ( -2688 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 128 65535 ) ( -65535 128 65535 ) ( -65535 128 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 847 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - ( 63291 -65534 17042 ) ( 63291 65534 17042 ) ( -63865 -65534 -14746 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63537 -65534 -16056 ) ( 63537 65534 -16056 ) ( -63618 -65534 15732 ) ftlattice2 16 16 0 1 1 - } - { //brush 848 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) ftlattice2 16 16 0 1 1 - ( 65535 -63454 16387 ) ( 65535 63701 -15401 ) ( -65535 -63454 16387 ) ftlattice2 16 16 0 1 1 - ( 65535 -63701 -15401 ) ( 65535 63454 16387 ) ( -65535 -63701 -15401 ) ftlattice2 16 16 0 1 1 - ( 63306 -65534 16982 ) ( 63306 65534 16982 ) ( -63850 -65534 -14806 ) ftlattice2 16 16 0 1 1 - ( 63552 -65534 -15996 ) ( 63552 65534 -15996 ) ( -63603 -65534 15792 ) ftlattice2 16 16 0 1 1 - } - { //brush 849 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) knottrim3 0 0 0 0.500000 0.500000 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 850 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 851 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 16 0 0 1 0.500000 - ( -65534 -15920 63571 ) ( 65534 -15920 63571 ) ( -65534 15868 -63584 ) millgt1 16 0 0 1 0.500000 - } - { //brush 852 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65534 -15920 63571 ) ( -65534 -15920 63571 ) ( -65534 15868 -63584 ) stnwll02 0 0 0 1 1 - } - { //brush 853 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 854 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( 65535 46044 46636 ) ( -65535 46044 46636 ) ( -65535 -46636 -46044 ) fstng_2 0 16 0 1 1 - } - { //brush 855 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -2656 -65535 65535 ) ( -2656 65535 65535 ) ( -2656 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 90 1 1 - ( 65535 65535 288 ) ( 65535 -65535 288 ) ( -65535 -65535 288 ) fstng_2 0 0 0 1 1 - } - { //brush 856 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 16 0 90 1 0.500000 - ( -18108 65534 63024 ) ( -18108 -65534 63024 ) ( 13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - } - { //brush 857 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -176 65535 ) ( 65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - } - { //brush 858 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -368 65535 ) ( 65535 -368 65535 ) ( -65535 -368 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 859 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -400 65535 ) ( 65535 -400 65535 ) ( -65535 -400 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -368 65535 ) ( -65535 -368 65535 ) ( -65535 -368 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - } - { //brush 860 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -400 65535 ) ( -65535 -400 65535 ) ( -65535 -400 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 861 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 0 0 1 1 - } - { //brush 862 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -176 65535 ) ( -65535 -176 65535 ) ( -65535 -176 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) millgt1 16 0 90 1 0.500000 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 - } - { //brush 863 - ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 864 - ( -2560 65535 65535 ) ( -2560 -65535 65535 ) ( -2560 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2528 -65535 65535 ) ( -2528 65535 65535 ) ( -2528 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 224 ) ( 65535 -65535 224 ) ( -65535 -65535 224 ) fstng_2 0 0 0 1 1 - } - { //brush 865 - ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2560 -65535 65535 ) ( -2560 65535 65535 ) ( -2560 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 866 - ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) fstng_2 0 0 0 1 1 - } - { //brush 867 - ( -2624 65535 65535 ) ( -2624 -65535 65535 ) ( -2624 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - } - { //brush 868 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -2624 -65535 65535 ) ( -2624 65535 65535 ) ( -2624 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_2 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) fstng_2 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 869 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 870 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 871 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -65535 -46332 46348 ) ( 65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 0 1 1 - ( 45484 -65535 47196 ) ( 45484 65535 47196 ) ( -47196 65535 -45484 ) fstng_2 0 16 90 1 1 - } - { //brush 872 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( -46484 65535 46196 ) ( -46484 -65535 46196 ) ( 46196 65535 -46484 ) fstng_2 0 16 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 873 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -46484 65535 46196 ) ( -46484 -65535 46196 ) ( 46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 874 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 0 1 1 - } - { //brush 875 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll05 0 0 0 1 1 - } - { //brush 876 - ( -1240 65535 65535 ) ( -1240 -65535 65535 ) ( -1240 65535 -65535 ) ctf08 0 16 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) ctf08 0 16 90 1 1 - } - { //brush 877 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll02 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll02 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 878 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnfloor02 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnfloor02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnfloor02 0 0 0 1 1 - } - { //brush 879 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -864 65535 ) ( 65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll05 0 0 0 1 1 - } - { //brush 880 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -864 65535 ) ( -65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -30703 57918 65535 ) ( 27912 -59313 65535 ) ( -30703 57918 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 881 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -864 65535 ) ( -65535 -864 65535 ) ( -65535 -864 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 882 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1248 65535 ) ( 65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 90 1 1 - ( 28757 58891 65535 ) ( -29858 -58341 65535 ) ( 28757 58891 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 883 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 -1248 65535 ) ( 65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 884 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1248 65535 ) ( -65535 -1248 65535 ) ( -65535 -1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 - } - { //brush 885 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 886 - ( -2136 -65535 65535 ) ( -2136 65535 65535 ) ( -2136 65535 -65535 ) ctf08 0 16 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) ctf08 0 16 90 1 1 - } - { //brush 887 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 888 - ( -2136 -65535 65535 ) ( -2136 65535 65535 ) ( -2136 65535 -65535 ) ctf08 0 16 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 16 180 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) ctf08 0 16 90 1 1 - ( 65535 65535 720 ) ( 65535 -65535 720 ) ( -65535 -65535 720 ) ctf08 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) ctf08 0 16 90 1 1 - } - { //brush 889 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 656 ) ( 65535 65535 656 ) ( -65535 -65535 656 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll05 0 0 0 1 1 - } - { //brush 890 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_2 0 16 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 891 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) ftlattice2 16 16 0 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) ftlattice2 16 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) ftlattice2 16 16 0 1 1 - ( 63663 -65534 -15551 ) ( 63663 65534 -15551 ) ( -63492 -65534 16237 ) ftlattice2 16 16 0 1 1 - ( 63372 -65534 16719 ) ( 63372 65534 16719 ) ( -63784 -65534 -15070 ) ftlattice2 16 16 0 1 1 - } - { //brush 892 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - ( 65535 -63471 16319 ) ( 65535 63684 -15469 ) ( -65535 -63471 16319 ) stnwll02 0 0 90 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 893 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) stnwll02 0 0 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnwll02 0 0 90 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll02 0 0 90 1 1 - } - { //brush 894 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_2 0 16 90 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_2 0 16 90 1 1 - } - { //brush 895 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 896 - ( -1152 65535 65535 ) ( -1152 -65535 65535 ) ( -1152 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) fstng_2 0 0 0 1 1 - } - { //brush 897 - ( -1184 65535 65535 ) ( -1184 -65535 65535 ) ( -1184 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -1152 -65535 65535 ) ( -1152 65535 65535 ) ( -1152 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) fstng_2 0 0 0 1 1 - } - { //brush 898 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1184 -65535 65535 ) ( -1184 65535 65535 ) ( -1184 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 899 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 45524 -65535 47156 ) ( 45524 65535 47156 ) ( -47156 65535 -45524 ) fstng_2 0 16 90 1 1 - } - { //brush 900 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 901 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( -59125 28290 65535 ) ( 58107 -30325 65535 ) ( -59125 28290 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 902 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 57896 -30748 65535 ) ( -59336 27868 65535 ) ( -59336 27868 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 903 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 904 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( -16880 -65534 63331 ) ( -16880 65534 63331 ) ( 14908 65534 -63824 ) stnwll01 0 0 0 1 1 - ( 45476 65535 47204 ) ( 45476 -65535 47204 ) ( -47204 65535 -45476 ) stnwll01 0 0 90 1 1 - } - { //brush 905 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( 45476 -65535 47204 ) ( 45476 65535 47204 ) ( -47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - } - { //brush 906 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) millgt1 0 0 90 1 0.500000 - ( 45476 -65535 47204 ) ( 45476 65535 47204 ) ( -47204 65535 -45476 ) millgt1 0 0 90 1 0.500000 - ( -16880 65534 63331 ) ( -16880 -65534 63331 ) ( 14908 65534 -63824 ) millgt1 0 0 0 1 0.500000 - } - { //brush 907 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - ( -16880 -65534 63331 ) ( -16880 65534 63331 ) ( 14908 65534 -63824 ) stnwll01 0 0 0 1 1 - } - { //brush 908 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 909 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_0 0 0 0 1 1 - } - { //brush 910 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -880 -65535 65535 ) ( -880 65535 65535 ) ( -880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( -46484 -65535 46196 ) ( -46484 65535 46196 ) ( 46196 65535 -46484 ) fstng_0 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 911 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) millgt1 16 0 0 1 1 - ( 63387 -65534 16658 ) ( 63387 65534 16658 ) ( -63769 -65534 -15130 ) millgt1 16 0 0 1 1 - ( 65535 -63533 16075 ) ( 65535 63623 -15713 ) ( -65535 -63533 16075 ) millgt1 16 0 0 1 1 - ( 63648 -65534 -15612 ) ( 63648 65534 -15612 ) ( -63507 -65534 16176 ) millgt1 16 0 0 1 1 - ( 65535 -63794 -15028 ) ( 65535 63361 16760 ) ( -65535 -63794 -15028 ) millgt1 16 0 0 1 1 - } - { //brush 912 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 913 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) shootit 16 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 914 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 915 - ( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - ( 65535 58533 -29474 ) ( 65535 -58699 29141 ) ( -65535 -58699 29141 ) tile2492 0 0 0 1 1 - } - { //brush 916 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -1136 -65535 65535 ) ( -1136 65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 917 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -832 65535 ) ( -65535 -832 65535 ) ( -65535 -832 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - } - { //brush 918 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 919 - ( -1200 65535 65535 ) ( -1200 -65535 65535 ) ( -1200 65535 -65535 ) shootit 16 0 180 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) shootit 16 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) shootit 16 0 0 1 1 - ( 65535 -58699 29141 ) ( 65535 58533 -29474 ) ( -65535 -58699 29141 ) shootit 16 0 0 1 1 - } - { //brush 920 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 921 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) shootit 16 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) shootit 16 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) shootit 16 0 0 1 1 - ( 65535 -58955 -28629 ) ( 65535 58277 29986 ) ( -65535 -58955 -28629 ) shootit 16 0 0 1 1 - } - { //brush 922 - ( -1104 65535 65535 ) ( -1104 -65535 65535 ) ( -1104 65535 -65535 ) tile2492 0 0 0 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 0 1 1 - ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 0 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 923 - ( -1168 65535 65535 ) ( -1168 -65535 65535 ) ( -1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -1136 -65535 65535 ) ( -1136 65535 65535 ) ( -1136 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) tile2492 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 90 1 1 - } - { //brush 924 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 180 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( 65535 58277 29986 ) ( 65535 -58955 -28629 ) ( -65535 -58955 -28629 ) tile2492 0 0 90 1 1 - ( 65535 35414 55153 ) ( -65535 35414 55153 ) ( -65535 -37290 -53903 ) tile2492 0 0 0 1 1 - } - { //brush 925 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 28802 58869 65535 ) ( -29813 -58363 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 926 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -30658 57941 65535 ) ( 27957 -59291 65535 ) ( -30658 57941 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 927 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -800 65535 ) ( 65535 -800 65535 ) ( -65535 -800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 - } - { //brush 928 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -800 65535 ) ( 65535 -800 65535 ) ( -65535 -800 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 - } - { //brush 929 - ( -65535 -688 65535 ) ( 65535 -688 65535 ) ( -65535 -688 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 180 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 930 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -63497 -16218 65535 ) ( 63659 15570 65535 ) ( -63497 -16218 -65535 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63822 14915 65535 ) ( 63333 -16873 65535 ) ( -63822 14915 -65535 ) shootit 0 8 0 1 1 - } - { //brush 931 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -63853 14795 65535 ) ( 63303 -16993 65535 ) ( -63853 14795 -65535 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63527 -16097 65535 ) ( 63629 15691 65535 ) ( -63527 -16097 -65535 ) shootit 0 8 0 1 1 - } - { //brush 932 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63519 -16127 65535 ) ( 63636 15661 65535 ) ( -63519 -16127 -65535 ) shootit 0 8 0 1 1 - ( -63845 14825 65535 ) ( 63310 -16963 65535 ) ( -63845 14825 -65535 ) shootit 0 8 0 1 1 - } - { //brush 933 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63830 14885 65535 ) ( 63326 -16903 65535 ) ( -63830 14885 -65535 ) shootit 0 8 0 1 1 - ( -63504 -16188 65535 ) ( 63651 15600 65535 ) ( -63504 -16188 -65535 ) shootit 0 8 0 1 1 - } - { //brush 934 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) shootit 0 8 0 1 1 - ( -65534 15177 63757 ) ( 65534 15177 63757 ) ( -65534 -16611 -63398 ) shootit 0 8 0 1 1 - ( -65534 -16479 63431 ) ( 65534 -16479 63431 ) ( -65534 15309 -63724 ) shootit 0 8 0 1 1 - ( -63512 -16158 65535 ) ( 63644 15631 65535 ) ( -63512 -16158 -65535 ) shootit 0 8 0 1 1 - ( -63838 14855 65535 ) ( 63318 -16933 65535 ) ( -63838 14855 -65535 ) shootit 0 8 0 1 1 - } - { //brush 935 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -688 65535 ) ( -65535 -688 65535 ) ( -65535 -688 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) stnfloor02 0 0 180 1 1 - ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58385 29768 ) ( 65535 -58846 -28847 ) ( -65535 -58846 -28847 ) stnfloor02 0 0 0 1 1 - } - { //brush 936 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 63313 -65534 16952 ) ( 63313 65534 16952 ) ( -63842 -65534 -14836 ) millgt1 16 16 0 1 1 - ( 65535 -63479 16289 ) ( 65535 63677 -15499 ) ( -65535 -63479 16289 ) millgt1 16 16 0 1 1 - ( 63590 -65534 -15845 ) ( 63590 65534 -15845 ) ( -63566 -65534 15943 ) millgt1 16 16 0 1 1 - ( 65535 -63756 -15183 ) ( 65535 63400 16606 ) ( -65535 -63756 -15183 ) millgt1 16 16 0 1 1 - } - { //brush 937 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 938 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 939 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -30703 -57918 65535 ) ( 27912 59313 65535 ) ( 27912 59313 -65535 ) fstng_2 0 0 0 1 1 - ( -31330 57605 65535 ) ( 27285 -59627 65535 ) ( -31330 57605 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 940 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( -31356 57592 65535 ) ( 27260 -59640 65535 ) ( -31356 57592 -65535 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 941 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( 27260 -59640 65535 ) ( -31356 57592 65535 ) ( -31356 57592 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 942 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( -31381 57579 65535 ) ( 27234 -59653 65535 ) ( -31381 57579 -65535 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 943 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( 27234 -59653 65535 ) ( -31381 57579 65535 ) ( -31381 57579 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 944 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( -31407 57566 65535 ) ( 27208 -59665 65535 ) ( -31407 57566 -65535 ) fstng_2 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 945 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( 27912 59313 65535 ) ( -30703 -57918 65535 ) ( 27912 59313 -65535 ) stnwll05 0 0 0 1 1 - ( 27208 -59665 65535 ) ( -31407 57566 65535 ) ( -31407 57566 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 946 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) tile2492 0 0 180 1 1 - } - { //brush 947 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65534 15002 63801 ) ( -65534 15002 63801 ) ( -65534 -16786 -63355 ) stonesnw 0 0 0 1 1 - ( -58558 -29423 65535 ) ( 58673 29192 65535 ) ( -58558 -29423 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 948 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 0 1 1 - ( 28680 58929 65535 ) ( -29935 -58302 65535 ) ( 28680 58929 -65535 ) stnwll05 0 0 0 1 1 - ( -30780 57880 65535 ) ( 27836 -59352 65535 ) ( -30780 57880 -65535 ) stnwll05 0 0 0 1 1 - ( 58145 65534 30248 ) ( 58145 -65534 30248 ) ( -59086 -65534 -28367 ) stnfloor02 0 0 0 1 1 - } - { //brush 949 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 28680 58929 65535 ) ( -29935 -58302 65535 ) ( 28680 58929 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 950 - ( -1256 65535 65535 ) ( -1256 -65535 65535 ) ( -1256 65535 -65535 ) ctf02 96 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) ctf02 96 0 0 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 0 180 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 0 180 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) ctf02 96 0 90 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 951 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1256 -65535 65535 ) ( -1256 65535 65535 ) ( -1256 65535 -65535 ) stnfloor02 0 0 180 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 61098 23715 ) ( 65535 -61626 -22305 ) ( -65535 -61626 -22305 ) stnfloor02 0 0 0 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - ( 65535 61366 -23000 ) ( 65535 -61358 23021 ) ( -65535 -61358 23021 ) stnfloor02 0 0 0 1 1 - } - { //brush 952 - ( -1264 65535 65535 ) ( -1264 -65535 65535 ) ( -1264 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll05 0 0 90 1 1 - ( -30780 57880 65535 ) ( 27836 -59352 65535 ) ( -30780 57880 -65535 ) stnwll05 0 0 0 1 1 - ( -30181 65534 58179 ) ( -30181 -65534 58179 ) ( 28434 65534 -59053 ) stnwll05 0 0 0 1 1 - } - { //brush 953 - ( -2080 65535 65535 ) ( -2080 -65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -1568 -65535 65535 ) ( -1568 65535 65535 ) ( -1568 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 954 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( 44964 -65535 47716 ) ( 44964 65535 47716 ) ( -47716 65535 -44964 ) fstng_2 0 16 90 1 1 - } - { //brush 955 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 956 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63406 65534 16579 ) ( 63406 -65534 16579 ) ( -63749 -65534 -15209 ) stonesnw 0 0 0 1 1 - } - { //brush 957 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 958 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - ( 63406 65534 16579 ) ( 63406 -65534 16579 ) ( -63749 -65534 -15209 ) stonesnw 0 0 0 1 1 - } - { //brush 959 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) stonesnw 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 200 ) ( 65535 -65535 200 ) ( -65535 -65535 200 ) stonesnw 0 0 0 1 1 - } - { //brush 960 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1312 65535 ) ( -65535 -1312 65535 ) ( -65535 -1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 - } - { //brush 961 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1312 65535 ) ( -65535 -1312 65535 ) ( -65535 -1312 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 0 1 1 - ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 - } - { //brush 962 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 963 - ( -65535 -1344 65535 ) ( 65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 964 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1344 65535 ) ( -65535 -1344 65535 ) ( -65535 -1344 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_0 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 965 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) millgt1 16 16 0 1 1 - ( 63313 -65534 16952 ) ( 63313 65534 16952 ) ( -63842 -65534 -14836 ) millgt1 16 16 0 1 1 - ( 65535 -63524 16109 ) ( 65535 63631 -15679 ) ( -65535 -63524 16109 ) millgt1 16 16 0 1 1 - ( 63590 -65534 -15845 ) ( 63590 65534 -15845 ) ( -63566 -65534 15943 ) millgt1 16 16 0 1 1 - ( 65535 -63801 -15002 ) ( 65535 63355 16786 ) ( -65535 -63801 -15002 ) millgt1 16 16 0 1 1 - } - { //brush 966 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 28130 59205 65535 ) ( -30485 -58027 65535 ) ( 28130 59205 -65535 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 967 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_2 0 0 0 1 1 - ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - ( 28104 59217 65535 ) ( -30511 -58014 65535 ) ( 28104 59217 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 968 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 90 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_2 0 0 0 1 1 - ( 28079 59230 65535 ) ( -30536 -58001 65535 ) ( 28079 59230 -65535 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - ( 27068 -59736 65535 ) ( -31548 57496 65535 ) ( -31548 57496 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 969 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 28053 59243 65535 ) ( -30562 -57989 65535 ) ( 28053 59243 -65535 ) fstng_2 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 970 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( -30562 -57989 65535 ) ( 28053 59243 65535 ) ( 28053 59243 -65535 ) stnwll05 0 0 0 1 1 - ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 971 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1408 65535 ) ( 65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 972 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 63139 -17648 65535 ) ( -64016 14140 65535 ) ( -64016 14140 -65535 ) shootit 0 8 0 1 1 - ( 63807 14975 65535 ) ( -63348 -16813 65535 ) ( -63348 -16813 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - } - { //brush 973 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 63815 14945 65535 ) ( -63341 -16843 65535 ) ( -63341 -16843 -65535 ) shootit 0 8 0 1 1 - ( 63147 -17618 65535 ) ( -64009 14170 65535 ) ( -64009 14170 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - } - { //brush 974 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - ( 63154 -17588 65535 ) ( -64001 14200 65535 ) ( -64001 14200 -65535 ) shootit 0 8 0 1 1 - ( 63822 14915 65535 ) ( -63333 -16873 65535 ) ( -63333 -16873 -65535 ) shootit 0 8 0 1 1 - } - { //brush 975 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 63830 14885 65535 ) ( -63326 -16903 65535 ) ( -63326 -16903 -65535 ) shootit 0 8 0 1 1 - ( 63162 -17558 65535 ) ( -63994 14230 65535 ) ( -63994 14230 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - } - { //brush 976 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) shootit 0 8 0 1 1 - ( 63132 -17679 65535 ) ( -64024 14110 65535 ) ( -64024 14110 -65535 ) shootit 0 8 0 1 1 - ( 65534 14492 63928 ) ( -65534 14492 63928 ) ( -65534 -17296 -63227 ) shootit 0 8 0 1 1 - ( 65534 -17165 63260 ) ( -65534 -17165 63260 ) ( -65534 14623 -63895 ) shootit 0 8 0 1 1 - ( 63800 15006 65535 ) ( -63356 -16783 65535 ) ( -63356 -16783 -65535 ) shootit 0 8 0 1 1 - } - { //brush 977 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1408 65535 ) ( -65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -58808 28924 ) ( 65535 58424 -29692 ) ( -65535 -58808 28924 ) stnwll05 0 0 90 1 1 - } - { //brush 978 - ( -65535 -1424 65535 ) ( 65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -1408 65535 ) ( -65535 -1408 65535 ) ( -65535 -1408 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnfloor02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnfloor02 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnfloor02 0 0 180 1 1 - ( 65535 58424 -29692 ) ( 65535 -58808 28924 ) ( -65535 -58808 28924 ) stnfloor02 0 0 0 1 1 - } - { //brush 979 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1424 65535 ) ( -65535 -1424 65535 ) ( -65535 -1424 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 180 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 980 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) stonesnw 0 0 0 1 1 - ( 57829 -30882 65535 ) ( -59403 27733 65535 ) ( -59403 27733 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 981 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) tile2492 0 0 180 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 982 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 983 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) tile2492 0 0 0 1 1 - } - { //brush 984 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_2 0 16 90 1 1 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 985 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 986 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -624 65535 ) ( 65535 -624 65535 ) ( -65535 -624 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 987 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -624 65535 ) ( 65535 -624 65535 ) ( -65535 -624 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 - } - { //brush 988 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -816 65535 ) ( 65535 -816 65535 ) ( -65535 -816 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -624 65535 ) ( -65535 -624 65535 ) ( -65535 -624 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 989 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -848 65535 ) ( 65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -816 65535 ) ( -65535 -816 65535 ) ( -65535 -816 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll02 0 0 90 1 1 - } - { //brush 990 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -848 65535 ) ( 65535 -848 65535 ) ( -65535 -848 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -816 65535 ) ( -65535 -816 65535 ) ( -65535 -816 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) millgt1 16 0 90 1 0.500000 - } - { //brush 991 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) millgt1 0 16 0 1 1 - ( 65535 -63517 16139 ) ( 65535 63639 -15649 ) ( -65535 -63517 16139 ) millgt1 0 16 0 1 1 - ( 63305 -65534 16986 ) ( 63305 65534 16986 ) ( -63851 -65534 -14802 ) millgt1 0 16 0 1 1 - ( 65535 -63763 -15152 ) ( 65535 63392 16636 ) ( -65535 -63763 -15152 ) millgt1 0 16 0 1 1 - ( 63551 -65534 -15999 ) ( 63551 65534 -15999 ) ( -63604 -65534 15789 ) millgt1 0 16 0 1 1 - } - { //brush 992 - ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 57649 -31240 65535 ) ( -59582 27375 65535 ) ( -59582 27375 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 993 - ( -2592 65535 65535 ) ( -2592 -65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -58737 -29064 65535 ) ( 58494 29551 65535 ) ( -58737 -29064 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 994 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 -1296 65535 ) ( 65535 -1296 65535 ) ( -65535 -1296 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 -1264 65535 ) ( -65535 -1264 65535 ) ( -65535 -1264 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) millgt1 16 0 90 1 0.500000 - ( 44844 -65535 47836 ) ( 44844 65535 47836 ) ( -47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( -18108 65534 63024 ) ( -18108 -65534 63024 ) ( 13680 65534 -64131 ) millgt1 16 0 0 1 0.500000 - } - { //brush 995 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1296 65535 ) ( 65535 -1296 65535 ) ( -65535 -1296 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1264 65535 ) ( -65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - ( -18108 -65534 63024 ) ( -18108 65534 63024 ) ( 13680 65534 -64131 ) stnwll02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 996 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1296 65535 ) ( -65535 -1296 65535 ) ( -65535 -1296 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 997 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) fstng_2 0 16 0 1 1 - } - { //brush 998 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 - } - { //brush 999 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -65534 -15002 63801 ) ( 65534 -15002 63801 ) ( -65534 16786 -63355 ) *rtex345 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) *rtex345 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1000 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - ( 58840 -65534 28860 ) ( 58840 65534 28860 ) ( -58392 -65534 -29756 ) tile2492 0 0 0 1 1 - } - { //brush 1001 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1002 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 58840 65534 28860 ) ( 58840 -65534 28860 ) ( -58392 -65534 -29756 ) stonesnow 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1003 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1004 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) tile2492 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - } - { //brush 1005 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1006 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1007 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 -60809 -24435 ) ( 65535 60886 24242 ) ( -65535 -60809 -24435 ) *rtex345 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1008 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 180 1 1 - ( 65535 60886 24242 ) ( 65535 -60809 -24435 ) ( -65535 -60809 -24435 ) stonesnow 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 180 1 1 - } - { //brush 1009 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1010 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1011 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1012 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1013 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1014 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1015 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1016 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1017 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - } - { //brush 1018 - ( 112 65535 65535 ) ( 112 -65535 65535 ) ( 112 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) fstng_0 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - } - { //brush 1019 - ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 112 -65535 65535 ) ( 112 65535 65535 ) ( 112 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1020 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 90 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1021 - ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1022 - ( 104 65535 65535 ) ( 104 -65535 65535 ) ( 104 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) fstng_0 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - } - { //brush 1023 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 104 -65535 65535 ) ( 104 65535 65535 ) ( 104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1024 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 90 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1025 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) *rtex345 0 0 0 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1026 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 28 ) ( 65535 65535 28 ) ( -65535 -65535 28 ) fstng_0 0 0 0 1 1 - ( 65535 65535 32 ) ( 65535 -65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 0 1 1 - } - { //brush 1027 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) stonesnow 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 90 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) stonesnow 0 0 90 1 1 - ( 29378 65534 58581 ) ( 29378 -65534 58581 ) ( -29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1028 - ( 96 65535 65535 ) ( 96 -65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) *rtex345 0 0 0 1 1 - ( 29378 -65534 58581 ) ( 29378 65534 58581 ) ( -29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1029 - ( -96 65535 65535 ) ( -96 -65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 96 -65535 65535 ) ( 96 65535 65535 ) ( 96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1030 - ( -96 65535 65535 ) ( -96 -65535 65535 ) ( -96 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 96 -65535 65535 ) ( 96 65535 65535 ) ( 96 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - } - { //brush 1031 - ( -104 65535 65535 ) ( -104 -65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1032 - ( -112 65535 65535 ) ( -112 -65535 65535 ) ( -112 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1033 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -112 -65535 65535 ) ( -112 65535 65535 ) ( -112 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 60 ) ( 65535 65535 60 ) ( -65535 -65535 60 ) fstng_0 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - } - { //brush 1034 - ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) *rtex345 0 0 0 1 1 - ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1035 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 90 1 1 - ( 65535 65535 60 ) ( 65535 -65535 60 ) ( -65535 -65535 60 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1036 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -104 -65535 65535 ) ( -104 65535 65535 ) ( -104 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 44 ) ( 65535 65535 44 ) ( -65535 -65535 44 ) fstng_0 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - } - { //brush 1037 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) *rtex345 0 0 0 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) *rtex345 0 0 0 1 1 - ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1038 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 32 ) ( 65535 65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 90 1 1 - ( 65535 65535 44 ) ( 65535 -65535 44 ) ( -65535 -65535 44 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1039 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 28 ) ( 65535 65535 28 ) ( -65535 -65535 28 ) fstng_0 0 0 0 1 1 - ( 65535 65535 32 ) ( 65535 -65535 32 ) ( -65535 -65535 32 ) stonesnow 0 0 0 1 1 - } - { //brush 1040 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) *rtex345 0 0 0 1 1 - ( -29378 65534 58581 ) ( -29378 -65534 58581 ) ( 29237 65534 -58651 ) *rtex345 0 0 180 1 1 - } - { //brush 1041 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -96 -65535 65535 ) ( -96 65535 65535 ) ( -96 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 90 1 1 - ( 65535 65535 28 ) ( 65535 -65535 28 ) ( -65535 -65535 28 ) stonesnow 0 0 90 1 1 - ( -29378 -65534 58581 ) ( -29378 65534 58581 ) ( 29237 65534 -58651 ) stonesnow 0 0 0 1 1 - } - { //brush 1042 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1043 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1044 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1045 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - } - { //brush 1046 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1047 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1048 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - } - { //brush 1049 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - } - { //brush 1050 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) *rtex345 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) *rtex345 0 0 180 1 1 - ( 65535 -60886 24242 ) ( 65535 60809 -24435 ) ( -65535 -60886 24242 ) *rtex345 0 0 0 1 1 - } - { //brush 1051 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 65535 60809 -24435 ) ( 65535 -60886 24242 ) ( -65535 -60886 24242 ) stonesnow 0 0 0 1 1 - ( -29365 65534 58587 ) ( -29365 -65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 180 1 1 - ( 29365 -65534 58587 ) ( 29365 65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 180 1 1 - } - { //brush 1052 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 16 ) ( 65535 -65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 0 1 1 - } - { //brush 1053 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) tile2492 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - } - { //brush 1054 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) *rtex345 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1055 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 - } - { //brush 1056 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) *rtex345 0 0 180 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) *rtex345 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) *rtex345 0 0 0 1 1 - ( 65534 15002 63801 ) ( -65534 15002 63801 ) ( -65534 -16786 -63355 ) *rtex345 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) *rtex345 0 0 0 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) *rtex345 0 0 0 1 1 - } - { //brush 1057 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) tile2492 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( 58392 -65534 -29756 ) ( 58392 65534 -29756 ) ( -58840 -65534 28860 ) tile2492 0 0 0 1 1 - } - { //brush 1058 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 48 ) ( 65535 65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 58392 65534 -29756 ) ( 58392 -65534 -29756 ) ( -58840 -65534 28860 ) stonesnow 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1059 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stonesnow 0 0 0 1 1 - ( 65535 65535 48 ) ( 65535 -65535 48 ) ( -65535 -65535 48 ) stonesnow 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1060 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 90 1 1 - ( 44652 -65535 48028 ) ( 44652 65535 48028 ) ( -48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_2 0 16 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 1061 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - ( 57573 -31394 65535 ) ( -59659 27221 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1062 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65534 -17219 63246 ) ( -65534 -17219 63246 ) ( -65534 14569 -63909 ) stnwll02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 0 1 1 - } - { //brush 1063 - ( -1504 65535 65535 ) ( -1504 -65535 65535 ) ( -1504 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) millgt1 0 0 0 1 0.500000 - ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1064 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1504 -65535 65535 ) ( -1504 65535 65535 ) ( -1504 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1065 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) millgt1 0 0 0 1 0.500000 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) millgt1 0 0 0 1 0.500000 - ( 65535 45276 47404 ) ( -65535 45276 47404 ) ( -65535 -47404 -45276 ) millgt1 0 0 0 1 0.500000 - ( -65534 -17219 63246 ) ( 65534 -17219 63246 ) ( -65534 14569 -63909 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1066 - ( -1824 65535 65535 ) ( -1824 -65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - ( 65534 -17219 63246 ) ( -65534 -17219 63246 ) ( -65534 14569 -63909 ) stnwll02 0 0 0 1 1 - } - { //brush 1067 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1824 -65535 65535 ) ( -1824 65535 65535 ) ( -1824 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1068 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1069 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) millgt1 0 0 180 1 0.500000 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) millgt1 0 0 0 1 0.500000 - ( -65535 -45276 47404 ) ( 65535 -45276 47404 ) ( -65535 47404 -45276 ) millgt1 0 0 0 1 0.500000 - ( -65535 46812 45868 ) ( 65535 46812 45868 ) ( 65535 -45868 -46812 ) millgt1 0 0 0 1 0.500000 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1070 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2720 -65535 65535 ) ( 2720 65535 65535 ) ( 2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( 61587 -65535 22411 ) ( 61587 65535 22411 ) ( -61137 -65535 -23610 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1071 - ( 2516 65535 65535 ) ( 2516 -65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1072 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 - } - { //brush 1073 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 1074 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 1075 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2508 -65535 65535 ) ( 2508 65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 58731 29077 65535 ) ( -58501 -29538 65535 ) ( -58501 -29538 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1076 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - } - { //brush 1077 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_0 0 0 0 1 1 - } - { //brush 1078 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1079 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) tile2492 0 0 180 1 1 - ( -64 -65535 65535 ) ( -64 65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) tile2492 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 1080 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 200 ) ( 65535 65535 200 ) ( -65535 -65535 200 ) stnwll05 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1081 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - } - { //brush 1082 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnow 0 0 0 1 1 - } - { //brush 1083 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) millgt1 16 0 0 1 0.500000 - ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) millgt1 16 0 0 1 0.500000 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) millgt1 16 0 0 1 0.500000 - } - { //brush 1084 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) skull1 32 0 0 0.500000 0.500000 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) skull1 32 0 0 0.500000 0.500000 - } - { //brush 1085 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 1086 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 1087 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1088 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -528 65535 ) ( -65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1089 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) ctf07 0 48 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll05 0 0 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - } - { //brush 1090 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll05 0 0 90 1 1 - } - { //brush 1091 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1092 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - } - { //brush 1093 - ( 1168 65535 65535 ) ( 1168 -65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1094 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) ctf07 32 48 180 1 1 - ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) ctf07 32 48 180 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) ctf07 32 48 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf07 32 48 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf07 32 48 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) ctf07 32 48 0 1 1 - } - { //brush 1095 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1096 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1097 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1098 - ( 928 -65535 65535 ) ( 928 65535 65535 ) ( 928 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 832 65535 ) ( -65535 832 65535 ) ( -65535 832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - ( 46484 65535 46196 ) ( 46484 -65535 46196 ) ( -46196 65535 -46484 ) stnwll01 0 0 0 1 1 - ( -58107 30325 65535 ) ( 59125 -28290 65535 ) ( -58107 30325 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1099 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) ctf07 0 48 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 48 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 48 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf07 0 48 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf07 0 48 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf07 0 48 0 1 1 - } - { //brush 1100 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1101 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1024 65535 ) ( -65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1102 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1103 - ( 752 -65535 65535 ) ( 752 65535 65535 ) ( 752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1088 65535 ) ( 65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) stnwll01 0 0 0 1 1 - } - { //brush 1104 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 180 1 1 - ( 65535 -35414 55153 ) ( -65535 -35414 55153 ) ( -65535 37290 -53903 ) tile2492 0 0 180 1 1 - } - { //brush 1105 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) ctf07 32 16 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - } - { //brush 1106 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - } - { //brush 1107 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 0 1 1 - } - { //brush 1108 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - } - { //brush 1109 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - } - { //brush 1110 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) ctf07 48 32 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) ctf07 48 32 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 48 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 48 32 0 1 1 - } - { //brush 1111 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - } - { //brush 1112 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2064 -65535 65535 ) ( 2064 65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - } - { //brush 1113 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - } - { //brush 1114 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -128 65535 ) ( -65535 -128 65535 ) ( -65535 -128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - } - { //brush 1115 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 65535 -46212 46468 ) ( -65535 -46212 46468 ) ( 65535 46468 -46212 ) stnwll02 0 0 0 1 1 - ( -65535 -46228 46452 ) ( 65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) millgt1 0 0 0 1 0.500000 - } - { //brush 1116 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1504 -65535 65535 ) ( 1504 65535 65535 ) ( 1504 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - ( -65535 -46212 46468 ) ( 65535 -46212 46468 ) ( 65535 46468 -46212 ) fstng_2 0 0 0 1 1 - } - { //brush 1117 - ( 1504 65535 65535 ) ( 1504 -65535 65535 ) ( 1504 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -65535 -46228 46452 ) ( 65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1118 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 65535 -46228 46452 ) ( -65535 -46228 46452 ) ( -65535 46452 -46228 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) stnwll02 0 0 0 1 1 - } - { //brush 1119 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1120 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 62344 65535 -20205 ) ( 62344 -65535 -20205 ) ( -61999 -65535 21242 ) stonesnw 0 0 0 1 1 - } - { //brush 1121 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1122 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 16 65535 ) ( 65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 0 1 1 - } - { //brush 1123 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) ctf01 64 32 180 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) ctf01 64 32 90 1 1 - ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) ctf01 64 32 90 1 1 - } - { //brush 1124 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 - ( -14746 -65534 63865 ) ( -14746 65534 63865 ) ( 17042 65534 -63291 ) stnwll05 0 0 0 1 1 - } - { //brush 1125 - ( 912 65535 65535 ) ( 912 -65535 65535 ) ( 912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 62344 65535 -20205 ) ( 62344 -65535 -20205 ) ( -61999 -65535 21242 ) stonesnw 0 0 0 1 1 - } - { //brush 1126 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1127 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1128 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -288 65535 ) ( -65535 -288 65535 ) ( -65535 -288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1129 - ( 320 -65535 65535 ) ( 320 65535 65535 ) ( 320 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) stonesnw 0 0 180 1 1 - } - { //brush 1130 - ( 320 65535 65535 ) ( 320 -65535 65535 ) ( 320 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 1131 - ( 768 -65535 65535 ) ( 768 65535 65535 ) ( 768 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16101 65534 63526 ) ( 16101 -65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1132 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1133 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) ctf07 0 32 0 1 1 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) ctf07 0 32 180 1 1 - ( 65535 -640 65535 ) ( -65535 -640 65535 ) ( -65535 -640 -65535 ) ctf07 0 32 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 0 32 90 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 0 32 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) ctf07 0 32 90 1 1 - } - { //brush 1134 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -640 65535 ) ( -65535 -640 65535 ) ( -65535 -640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1135 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -640 65535 ) ( 65535 -640 65535 ) ( -65535 -640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1136 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -704 65535 ) ( 65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1137 - ( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -704 65535 ) ( -65535 -704 65535 ) ( -65535 -704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1138 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll01 0 0 90 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1139 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1056 -65535 65535 ) ( 1056 65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) ctf07 32 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1140 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1056 -65535 65535 ) ( 1056 65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 576 ) ( 65535 65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1141 - ( 1056 65535 65535 ) ( 1056 -65535 65535 ) ( 1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1142 - ( 992 65535 65535 ) ( 992 -65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1143 - ( 992 -65535 65535 ) ( 992 65535 65535 ) ( 992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1144 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) ctf07 48 32 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) ctf07 48 32 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) ctf07 48 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf07 48 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf07 48 32 0 1 1 - } - { //brush 1145 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2128 -65535 65535 ) ( 2128 65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - } - { //brush 1146 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - } - { //brush 1147 - ( 2064 65535 65535 ) ( 2064 -65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2192 -65535 65535 ) ( 2192 65535 65535 ) ( 2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 - } - { //brush 1148 - ( 2000 65535 65535 ) ( 2000 -65535 65535 ) ( 2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 2064 -65535 65535 ) ( 2064 65535 65535 ) ( 2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -896 65535 ) ( 65535 -896 65535 ) ( -65535 -896 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -880 65535 ) ( -65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) stnwll01 0 0 180 1 1 - } - { //brush 1149 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1150 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) ctf08 0 48 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) ctf08 0 48 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf08 0 48 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf08 0 48 90 1 1 - } - { //brush 1151 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - } - { //brush 1152 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - } - { //brush 1153 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 90 1 1 - } - { //brush 1154 - ( -752 65535 65535 ) ( -752 -65535 65535 ) ( -752 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - } - { //brush 1155 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) ctf08 16 32 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) ctf08 16 32 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) ctf08 16 32 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) ctf08 16 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 16 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 16 32 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) ctf08 16 32 0 1 1 - } - { //brush 1156 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1157 - ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 1158 - ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - } - { //brush 1159 - ( -2064 65535 65535 ) ( -2064 -65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 880 65535 ) ( 65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 1160 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 576 ) ( 65535 65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1161 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - } - { //brush 1162 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 512 ) ( 65535 -65535 512 ) ( -65535 -65535 512 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1163 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1164 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 640 65535 ) ( -65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1165 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 704 65535 ) ( 65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1166 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1167 - ( -912 65535 65535 ) ( -912 -65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -58741 29058 65535 ) ( 58491 -29557 65535 ) ( -58741 29058 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1168 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -58741 29058 65535 ) ( 58491 -29557 65535 ) ( -58741 29058 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1169 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) ctf02 64 32 180 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) ctf02 64 32 90 1 1 - ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) ctf02 64 32 90 1 1 - } - { //brush 1170 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( -65535 -16 65535 ) ( 65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 16 65535 ) ( -65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 90 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 - ( 14746 65534 63865 ) ( 14746 -65534 63865 ) ( -17042 65534 -63291 ) stnwll05 0 0 0 1 1 - } - { //brush 1171 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -16 65535 ) ( -65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 0 1 1 - } - { //brush 1172 - ( -912 -65535 65535 ) ( -912 65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 61999 65535 21242 ) ( 61999 -65535 21242 ) ( -62344 -65535 -20205 ) stonesnw 0 0 0 1 1 - } - { //brush 1173 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) ctf08 16 32 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) ctf08 16 32 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) ctf08 16 32 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) ctf08 16 32 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 16 32 0 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 16 32 0 1 1 - } - { //brush 1174 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -2064 -65535 65535 ) ( -2064 65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 0 1 1 - } - { //brush 1175 - ( -2064 65535 65535 ) ( -2064 -65535 65535 ) ( -2064 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 1176 - ( -2128 65535 65535 ) ( -2128 -65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2000 -65535 65535 ) ( -2000 65535 65535 ) ( -2000 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 90 1 1 - } - { //brush 1177 - ( -2192 65535 65535 ) ( -2192 -65535 65535 ) ( -2192 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 128 65535 ) ( 65535 128 65535 ) ( -65535 128 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 464 65535 ) ( -65535 464 65535 ) ( -65535 464 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - } - { //brush 1178 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) ctf08 32 16 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) ctf08 32 16 0 1 1 - ( -65535 -32 65535 ) ( 65535 -32 65535 ) ( -65535 -32 -65535 ) ctf08 32 16 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) ctf08 32 16 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) ctf08 32 16 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf08 32 16 90 1 1 - } - { //brush 1179 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -32 65535 ) ( -65535 -32 65535 ) ( -65535 -32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - } - { //brush 1180 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 32 65535 ) ( -65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 1181 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 32 65535 ) ( 65535 32 65535 ) ( -65535 32 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) stnwll02 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll02 0 0 90 1 1 - } - { //brush 1182 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) fstng_0 0 0 0 1 1 - } - { //brush 1183 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) skull1 32 0 180 0.500000 0.500000 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) skull1 32 0 0 0.500000 0.500000 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) skull1 32 0 0 0.500000 0.500000 - } - { //brush 1184 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1185 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1186 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1187 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 528 65535 ) ( 65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( -47244 -65535 45436 ) ( -47244 65535 45436 ) ( 45436 65535 -47244 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1188 - ( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) stnwll02 0 0 0 1 1 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1189 - ( -2720 65535 65535 ) ( -2720 -65535 65535 ) ( -2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 61137 -65535 -23610 ) ( 61137 65535 -23610 ) ( -61587 -65535 22411 ) stnwll02 0 0 0 1 1 - } - { //brush 1190 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 288 65535 ) ( 65535 288 65535 ) ( -65535 288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) stonesnw 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1191 - ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) ctf08 32 48 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1192 - ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - ( -46508 -65535 46172 ) ( -46508 65535 46172 ) ( 46172 65535 -46508 ) stnwll02 0 0 0 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) stnwll02 0 0 0 1 1 - } - { //brush 1193 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -992 -65535 65535 ) ( -992 65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1194 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll02 0 0 0 1 1 - ( 58699 29141 65535 ) ( -58533 -29474 65535 ) ( -58533 -29474 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1195 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) ctf08 0 48 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 48 180 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) ctf08 0 48 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf08 0 48 90 1 1 - } - { //brush 1196 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - } - { //brush 1197 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 496 ) ( 65535 65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1198 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 496 ) ( 65535 -65535 496 ) ( -65535 -65535 496 ) stnwll01 0 0 0 1 1 - } - { //brush 1199 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1168 -65535 65535 ) ( -1168 65535 65535 ) ( -1168 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 0 1 1 - } - { //brush 1200 - ( -1072 65535 65535 ) ( -1072 -65535 65535 ) ( -1072 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1040 -65535 65535 ) ( -1040 65535 65535 ) ( -1040 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 - ( -46188 -46492 65535 ) ( 46492 46188 65535 ) ( 46492 46188 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 1201 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( -59323 27893 65535 ) ( 57909 -30722 65535 ) ( -59323 27893 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_0 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1202 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( -30600 -57969 65535 ) ( 28015 59262 65535 ) ( 28015 59262 -65535 ) stnwll05 0 0 0 1 1 - ( 57909 -30722 65535 ) ( -59323 27893 65535 ) ( -59323 27893 -65535 ) fstng_0 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) fstng_0 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) fstng_0 0 0 0 1 1 - ( 65535 63684 -15469 ) ( 65535 -63471 16319 ) ( -65535 -63471 16319 ) fstng_0 0 0 0 1 1 - } - { //brush 1203 - ( -2508 65535 65535 ) ( -2508 -65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -58731 -29077 65535 ) ( 58501 29538 65535 ) ( -58731 -29077 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1204 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) ctf08 0 32 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) ctf08 0 32 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) ctf08 0 32 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) ctf08 0 32 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) ctf08 0 32 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) ctf08 0 32 90 1 1 - } - { //brush 1205 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1088 65535 ) ( 65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1206 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1088 65535 ) ( -65535 -1088 65535 ) ( -65535 -1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1207 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) stnwll02 0 0 90 1 1 - } - { //brush 1208 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2592 -65535 65535 ) ( -2592 65535 65535 ) ( -2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1024 65535 ) ( 65535 -1024 65535 ) ( -65535 -1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1209 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2516 -65535 65535 ) ( -2516 65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1210 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1211 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1216 -65535 65535 ) ( 1216 65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll01 0 0 0 1 1 - } - { //brush 1212 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1213 - ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1214 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1215 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - } - { //brush 1216 - ( 2592 65535 65535 ) ( 2592 -65535 65535 ) ( 2592 65535 -65535 ) ctf07 0 32 0 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) ctf07 0 32 0 1 1 - ( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) ctf07 0 32 180 1 1 - ( 65535 1088 65535 ) ( -65535 1088 65535 ) ( -65535 1088 -65535 ) ctf07 0 32 180 1 1 - ( 65535 -65535 416 ) ( 65535 65535 416 ) ( -65535 -65535 416 ) ctf07 0 32 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) ctf07 0 32 90 1 1 - } - { //brush 1217 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1218 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1219 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1220 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1221 - ( 1040 65535 65535 ) ( 1040 -65535 65535 ) ( 1040 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1216 -65535 65535 ) ( 1216 65535 65535 ) ( 1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 0 1 1 - ( 46188 46492 65535 ) ( -46492 -46188 65535 ) ( 46188 46492 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 1222 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf01 64 80 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) ctf01 64 80 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf01 64 80 0 1 1 - ( 60996 69391 7356 ) ( 60996 -57765 39146 ) ( -61258 57929 -38488 ) ctf01 64 80 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) ctf01 64 80 0 1 1 - ( 61258 -69226 -6699 ) ( 61258 57929 -38488 ) ( -60996 -57765 39146 ) ctf01 64 80 0 1 1 - } - { //brush 1223 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf01 64 80 180 1 1 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf01 64 80 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) ctf01 64 80 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf01 64 80 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) ctf01 64 80 0 1 1 - ( 60996 -57765 39146 ) ( 60996 69391 7356 ) ( -61258 57929 -38488 ) ctf01 64 80 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) ctf01 64 80 0 1 1 - } - { //brush 1224 - ( 2416 65535 65535 ) ( 2416 -65535 65535 ) ( 2416 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) stnwll02 0 0 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 - } - { //brush 1225 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2384 -65535 65535 ) ( 2384 65535 65535 ) ( 2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -46348 46332 ) ( -65535 -46348 46332 ) ( 65535 46332 -46348 ) stnwll02 0 0 0 1 1 - ( 65535 45836 46844 ) ( -65535 45836 46844 ) ( -65535 -46844 -45836 ) stnwll02 0 0 0 1 1 - } - { //brush 1226 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( 65535 65535 256 ) ( 65535 -65535 256 ) ( -65535 -65535 256 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 1227 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 61458 22754 ) ( 65535 -61266 -23266 ) ( -65535 61458 22754 ) tile2492 0 0 90 1 1 - ( 65535 61526 -22572 ) ( 65535 -61197 23449 ) ( -65535 -61197 23449 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - } - { //brush 1228 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) ctf01 32 80 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 80 180 1 1 - ( 65535 61526 -22572 ) ( 65535 -61197 23449 ) ( -65535 -61197 23449 ) ctf01 32 80 90 1 1 - ( 65535 -61266 -23266 ) ( 65535 61458 22754 ) ( -65535 61458 22754 ) ctf01 32 80 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf01 32 80 0 1 1 - } - { //brush 1229 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } - { //brush 1230 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 61421 65535 22853 ) ( 61421 -65535 22853 ) ( -61303 65535 -23168 ) stnwll02 0 0 0 1 1 - ( 61721 65535 -22053 ) ( 61721 -65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 - } - { //brush 1231 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) ctf01 32 48 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 61421 -65535 22853 ) ( 61421 65535 22853 ) ( -61303 65535 -23168 ) stnwll02 0 0 0 1 1 - ( 61721 65535 -22053 ) ( 61721 -65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 - } - { //brush 1232 - ( 1408 65535 65535 ) ( 1408 -65535 65535 ) ( 1408 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw2 0 0 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw2 0 0 180 1 1 - } - { //brush 1233 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 1408 -65535 65535 ) ( 1408 65535 65535 ) ( 1408 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1234 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 80 180 1 1 - ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 - ( 65535 -61458 22754 ) ( 65535 61266 -23266 ) ( -65535 -61458 22754 ) ctf02 96 80 90 1 1 - } - { //brush 1235 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } - { //brush 1236 - ( -1792 -65535 65535 ) ( -1792 65535 65535 ) ( -1792 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll01 0 0 90 1 1 - ( -30504 58017 65535 ) ( 28111 -59214 65535 ) ( -30504 58017 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1237 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) ctf08 0 32 0 1 1 - ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) ctf08 0 32 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) ctf08 0 32 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) ctf08 0 32 90 1 1 - ( 65535 65535 608 ) ( 65535 -65535 608 ) ( -65535 -65535 608 ) ctf08 0 32 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) ctf08 0 32 90 1 1 - } - { //brush 1238 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } - { //brush 1239 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 61303 65535 -23168 ) ( 61303 -65535 -23168 ) ( -61421 65535 22853 ) fstng_0 0 0 0 1 1 - ( 61003 65535 23968 ) ( 61003 -65535 23968 ) ( -61721 -65535 -22053 ) fstng_0 0 0 0 1 1 - } - { //brush 1240 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) ctf02 96 48 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 96 48 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) ctf02 96 48 0 1 1 - ( 61303 -65535 -23168 ) ( 61303 65535 -23168 ) ( -61421 65535 22853 ) ctf02 96 48 0 1 1 - ( 61003 65535 23968 ) ( 61003 -65535 23968 ) ( -61721 -65535 -22053 ) ctf02 96 48 0 1 1 - } - { //brush 1241 - ( -2384 65535 65535 ) ( -2384 -65535 65535 ) ( -2384 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 - ( 72321 -20359 54282 ) ( -20359 72321 54282 ) ( 18812 -73868 -52735 ) stnwll02 0 0 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) stnwll02 0 0 0 1 1 - } - { //brush 1242 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1243 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1244 - ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1245 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1246 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } - { //brush 1247 - ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1248 - ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) stnwll02 0 0 0 1 1 - } - { //brush 1249 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 288 ) ( 65535 65535 288 ) ( -65535 -65535 288 ) stnwll02 0 0 90 1 1 - ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 - ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1250 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) ctf02 64 80 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) ctf02 64 80 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf02 64 80 180 1 1 - ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) ctf02 64 80 90 1 1 - ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) ctf02 64 80 90 1 1 - } - { //brush 1251 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 64 65535 ) ( 65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1252 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 90 1 1 - ( 65535 61243 23326 ) ( 65535 -61480 -22695 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1253 - ( 2688 65535 65535 ) ( 2688 -65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 0 1 1 - ( 61587 65535 22411 ) ( 61587 -65535 22411 ) ( -61137 -65535 -23610 ) stnwll02 0 0 0 1 1 - ( 61823 65535 -21779 ) ( 61823 -65535 -21779 ) ( -60900 -65535 24241 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1254 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1255 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1256 - ( -280 65535 65535 ) ( -280 -65535 65535 ) ( -280 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1257 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) tile2492 0 0 90 1 1 - ( 65535 61197 23449 ) ( 65535 -61526 -22572 ) ( -65535 -61526 -22572 ) tile2492 0 0 90 1 1 - ( 65535 61266 -23266 ) ( 65535 -61458 22754 ) ( -65535 -61458 22754 ) tile2492 0 0 90 1 1 - } - { //brush 1258 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf02 64 80 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf02 64 80 0 1 1 - ( 61258 69226 -6699 ) ( 61258 -57929 -38488 ) ( -60996 57765 39146 ) ctf02 64 80 0 1 1 - ( 60996 -69391 7356 ) ( 60996 57765 39146 ) ( -61258 69226 -6699 ) ctf02 64 80 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) ctf02 64 80 0 1 1 - } - { //brush 1259 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) ctf02 64 80 180 1 1 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) ctf02 64 80 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) ctf02 64 80 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) ctf02 64 80 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) ctf02 64 80 0 1 1 - ( 61258 -57929 -38488 ) ( 61258 69226 -6699 ) ( -60996 57765 39146 ) ctf02 64 80 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) ctf02 64 80 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) ctf02 64 80 0 1 1 - } - { //brush 1260 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) millgt1 16 0 180 1 0.500000 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) millgt1 16 0 0 1 0.500000 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) millgt1 16 0 0 1 0.500000 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) millgt1 16 0 0 1 0.500000 - } - { //brush 1261 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll02 0 0 0 1 1 - ( 60900 65535 24241 ) ( 60900 -65535 24241 ) ( -61823 -65535 -21779 ) stnwll02 0 0 0 1 1 - ( 61137 65535 -23610 ) ( 61137 -65535 -23610 ) ( -61587 -65535 22411 ) stnwll02 0 0 0 1 1 - } - { //brush 1262 - ( -1408 65535 65535 ) ( -1408 -65535 65535 ) ( -1408 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - } - { //brush 1263 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1264 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 1265 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - } - { //brush 1266 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) ctf02 64 80 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) ctf02 64 80 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf02 64 80 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf02 64 80 180 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf02 64 80 90 1 1 - ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) ctf02 64 80 90 1 1 - } - { //brush 1267 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1268 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1269 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1270 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1271 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1272 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1273 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1274 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1275 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1276 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1277 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1278 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1279 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1280 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1281 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1282 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 1283 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1284 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 1285 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 1286 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 1287 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1288 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1289 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1290 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1291 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1292 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1293 - ( -320 65535 65535 ) ( -320 -65535 65535 ) ( -320 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 144 65535 ) ( -65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) stonesnw 0 0 180 1 1 - } - { //brush 1294 - ( -1056 65535 65535 ) ( -1056 -65535 65535 ) ( -1056 65535 -65535 ) ctf08 32 0 180 1 1 - ( -992 -65535 65535 ) ( -992 65535 65535 ) ( -992 65535 -65535 ) ctf08 32 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) ctf08 32 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) ctf08 32 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) ctf08 32 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) ctf08 32 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) ctf08 32 0 0 1 1 - } - { //brush 1295 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1296 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1297 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1298 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 1299 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 1300 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1301 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 512 65535 ) ( -65535 512 65535 ) ( -65535 512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 768 ) ( 65535 65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 0 1 1 - } - { //brush 1302 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - ( 59013 28514 65535 ) ( -58219 -30101 65535 ) ( -58219 -30101 -65535 ) sky003 0 0 0 1 1 - } - { //brush 1303 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 180 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll05 0 0 0 1 1 - } - { //brush 1304 - ( -65535 1344 65535 ) ( 65535 1344 65535 ) ( -65535 1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -58200 30140 ) ( 65535 59032 -28476 ) ( -65535 -58200 30140 ) stnwll05 0 0 0 1 1 - ( 29813 58363 65535 ) ( -28802 -58869 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1305 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1306 - ( 1248 65535 65535 ) ( 1248 -65535 65535 ) ( 1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1408 65535 ) ( -65535 1408 65535 ) ( -65535 1408 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) tile2492 0 0 180 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 1307 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -57896 30748 65535 ) ( 59336 -27868 65535 ) ( -57896 30748 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1308 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( -58952 -28636 65535 ) ( 58280 29980 65535 ) ( -58952 -28636 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1309 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1248 65535 ) ( 65535 1248 65535 ) ( -65535 1248 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -28802 -58869 65535 ) ( 29813 58363 65535 ) ( 29813 58363 -65535 ) stnwll05 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stnwll05 0 0 180 1 1 - } - { //brush 1310 - ( 2128 65535 65535 ) ( 2128 -65535 65535 ) ( 2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll05 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1311 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1312 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65534 16990 63304 ) ( -65534 16990 63304 ) ( -65534 -14799 -63852 ) stonesnow 0 0 0 1 1 - } - { //brush 1313 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 65535 192 ) ( 65535 -65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 63749 -65534 -15209 ) ( 63749 65534 -15209 ) ( -63406 -65534 16579 ) stonesnow 0 0 0 1 1 - } - { //brush 1314 - ( 2464 -65535 65535 ) ( 2464 65535 65535 ) ( 2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - ( -27208 59665 65535 ) ( 31407 -57566 65535 ) ( -27208 59665 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1315 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 560 ) ( 65535 65535 560 ) ( -65535 -65535 560 ) fstng_0 0 0 0 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) fstng_0 0 0 0 1 1 - } - { //brush 1316 - ( 2336 65535 65535 ) ( 2336 -65535 65535 ) ( 2336 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) fstng_2 0 16 90 1 1 - ( 47244 -65535 45436 ) ( 47244 65535 45436 ) ( -45436 65535 -47244 ) fstng_2 0 16 90 1 1 - } - { //brush 1317 - ( 2560 65535 65535 ) ( 2560 -65535 65535 ) ( 2560 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2592 -65535 65535 ) ( 2592 65535 65535 ) ( 2592 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 90 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) fstng_2 0 0 0 1 1 - } - { //brush 1318 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 63484 16271 ) ( 65535 -63672 -15518 ) ( -65535 -63672 -15518 ) metdec1 32 0 0 1 1 - ( 63809 -65534 -14968 ) ( 63809 65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 - ( 63647 -65534 15615 ) ( 63647 65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 - } - { //brush 1319 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) metdec1 32 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) metdec1 32 0 0 1 1 - ( 65535 63646 -15623 ) ( 65535 -63510 16165 ) ( -65535 -63510 16165 ) metdec1 32 0 0 1 1 - ( 63647 -65534 15615 ) ( 63647 65534 15615 ) ( -63508 -65534 -16173 ) metdec1 32 0 0 1 1 - ( 63809 -65534 -14968 ) ( 63809 65534 -14968 ) ( -63346 -65534 16820 ) metdec1 32 0 0 1 1 - } - { //brush 1320 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( 2528 -65535 65535 ) ( 2528 65535 65535 ) ( 2528 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1321 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll05 0 0 90 1 1 - ( -27260 59640 65535 ) ( 31356 -57592 65535 ) ( -27260 59640 -65535 ) stnwll05 0 0 0 1 1 - ( 59403 -27733 65535 ) ( -57829 30882 65535 ) ( -57829 30882 -65535 ) stnwll05 0 0 180 1 1 - ( -27912 -59313 65535 ) ( 30703 57918 65535 ) ( 30703 57918 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1322 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 576 65535 ) ( -65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 0 1 1 - ( 30600 57969 65535 ) ( -28015 -59262 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 - ( -44844 -65535 47836 ) ( -44844 65535 47836 ) ( 47836 65535 -44844 ) stnwll02 0 0 0 1 1 - } - { //brush 1323 - ( 1472 65535 65535 ) ( 1472 -65535 65535 ) ( 1472 65535 -65535 ) tile2492 0 0 180 1 1 - ( 1568 -65535 65535 ) ( 1568 65535 65535 ) ( 1568 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 800 65535 ) ( 65535 800 65535 ) ( -65535 800 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1324 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 1168 -65535 65535 ) ( 1168 65535 65535 ) ( 1168 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65534 -15002 63801 ) ( -65534 -15002 63801 ) ( -65534 16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1325 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 16 180 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 0 1 1 - ( 65535 46332 46348 ) ( -65535 46332 46348 ) ( -65535 -46348 -46332 ) fstng_2 0 16 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 1326 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 58533 29474 65535 ) ( -58699 -29141 65535 ) ( -58699 -29141 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 1327 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 320 65535 ) ( 65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -65535 -45972 46708 ) ( 65535 -45972 46708 ) ( -65535 46708 -45972 ) millgt1 16 0 0 1 0.500000 - ( 65535 -58609 -29320 ) ( 65535 58622 29295 ) ( -65535 -58609 -29320 ) stnwll05 0 0 0 1 1 - ( -28015 -59262 65535 ) ( 30600 57969 65535 ) ( 30600 57969 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 1328 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 128 -65535 65535 ) ( 128 65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 464 65535 ) ( 65535 464 65535 ) ( -65535 464 -65535 ) tile2492 0 0 0 1 1 - ( 65535 896 65535 ) ( -65535 896 65535 ) ( -65535 896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 240 ) ( 65535 -65535 240 ) ( -65535 -65535 240 ) tile2492 0 0 0 1 1 - } - { //brush 1329 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 2048 -65535 65535 ) ( 2048 65535 65535 ) ( 2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll05 0 0 90 1 1 - ( -65535 -46116 46564 ) ( 65535 -46116 46564 ) ( -65535 46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1330 - ( 2336 -65535 65535 ) ( 2336 65535 65535 ) ( 2336 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -464 65535 ) ( -65535 -464 65535 ) ( -65535 -464 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( -27688 59425 65535 ) ( 30927 -57806 65535 ) ( -27688 59425 -65535 ) stnwll01 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll01 0 0 180 1 1 - } - { //brush 1331 - ( 1120 -65535 65535 ) ( 1120 65535 65535 ) ( 1120 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 640 ) ( 65535 65535 640 ) ( -65535 -65535 640 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 64593 -11074 65535 ) ( -64693 10472 65535 ) ( -64693 10472 -65535 ) mtn 0 0 0 1 1 - ( 59013 28514 65535 ) ( -58219 -30101 65535 ) ( -58219 -30101 -65535 ) mtn 0 0 0 1 1 - } - { //brush 1332 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1360 -65535 65535 ) ( 1360 65535 65535 ) ( 1360 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 30447 -58046 65535 ) ( -28168 59185 65535 ) ( -28168 59185 -65535 ) fstng_0 0 0 180 1 1 - ( -28168 -59185 65535 ) ( 30447 58046 65535 ) ( 30447 58046 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 1333 - ( 768 65535 65535 ) ( 768 -65535 65535 ) ( 768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 848 -65535 65535 ) ( 848 65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 1334 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( -58491 29557 65535 ) ( 58741 -29058 65535 ) ( -58491 29557 -65535 ) stnwll05 0 0 0 1 1 - ( -28367 -59086 65535 ) ( 30248 58145 65535 ) ( 30248 58145 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1335 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 256 65535 ) ( -65535 256 65535 ) ( -65535 256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1336 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 80 ) ( 65535 -65535 80 ) ( -65535 -65535 80 ) stonesnow 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) stonesnow 0 0 180 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1337 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 240 ) ( 65535 65535 240 ) ( -65535 -65535 240 ) fstng_0 0 0 0 1 1 - ( 65535 63522 16116 ) ( 65535 -63633 -15672 ) ( -65535 -63633 -15672 ) fstng_0 0 0 0 1 1 - ( 16086 -65534 63530 ) ( 16086 65534 63530 ) ( -15702 65534 -63626 ) fstng_0 0 0 180 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) fstng_0 0 0 180 1 1 - } - { //brush 1338 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( -58437 -29666 65535 ) ( 58795 28949 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 65534 7581 65097 ) ( -65534 7581 65097 ) ( -65534 -8676 -64960 ) mtn 0 0 0 1 1 - } - { //brush 1339 - ( 65162 -6996 65535 ) ( -65257 6045 65535 ) ( -65257 6045 -65535 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( 65257 6045 65535 ) ( -65162 -6996 65535 ) ( -65162 -6996 -65535 ) mtn 0 0 0 1 1 - ( 65534 15314 63723 ) ( -65534 15314 63723 ) ( -65534 -16474 -63433 ) mtn 0 0 0 1 1 - ( -65535 -10118 64750 ) ( 65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - ( 58437 -29666 65535 ) ( -58795 28949 65535 ) ( -58795 28949 -65535 ) mtn 0 0 0 1 1 - ( 65534 -29461 58539 ) ( -65534 -29461 58539 ) ( -65534 29154 -58693 ) mtn 0 0 0 1 1 - } - { //brush 1340 - ( 128 65535 65535 ) ( 128 -65535 65535 ) ( 128 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 224 ) ( 65535 65535 224 ) ( -65535 -65535 224 ) fstng_0 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) tile2492 0 0 0 1 1 - ( -65534 -29320 58609 ) ( 65534 -29320 58609 ) ( -65534 29295 -58622 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 1341 - ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16086 -65534 63530 ) ( -16086 65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -16101 65534 63526 ) ( -16101 -65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 1342 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -60097 26141 65535 ) ( 59675 -27091 65535 ) ( -60097 26141 -65535 ) mtn 0 0 0 1 1 - ( 58795 28949 65535 ) ( -58437 -29666 65535 ) ( -58437 -29666 -65535 ) mtn 0 0 0 1 1 - ( -64088 13701 65535 ) ( 63859 -14731 65535 ) ( -64088 13701 -65535 ) mtn 0 0 0 1 1 - ( 67199 13380 62412 ) ( -63219 26421 62412 ) ( -67325 -14635 -61993 ) mtn 0 0 0 1 1 - ( 58488 -29564 65535 ) ( -58744 29052 65535 ) ( -58744 29052 -65535 ) mtn 0 0 0 1 1 - ( 65535 -10118 64750 ) ( -65535 -10118 64750 ) ( -65535 9324 -64869 ) mtn 0 0 0 1 1 - } - { //brush 1343 - ( 1712 65535 65535 ) ( 1712 -65535 65535 ) ( 1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 1344 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 - } - { //brush 1345 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 46508 -65535 46172 ) ( 46508 65535 46172 ) ( -46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_2 0 16 90 1 1 - } - { //brush 1346 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) shootit 16 16 0 1 1 - ( 63530 -65534 16086 ) ( 63530 65534 16086 ) ( -63626 -65534 -15702 ) shootit 16 16 0 1 1 - ( 65535 -63564 15951 ) ( 65535 63592 -15838 ) ( -65535 -63564 15951 ) shootit 16 16 0 1 1 - ( 63626 -65534 -15702 ) ( 63626 65534 -15702 ) ( -63530 -65534 16086 ) shootit 16 16 0 1 1 - ( 65535 -63660 -15567 ) ( 65535 63496 16222 ) ( -65535 -63660 -15567 ) shootit 16 16 0 1 1 - } - { //brush 1347 - ( -65535 -448 65535 ) ( 65535 -448 65535 ) ( -65535 -448 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - ( 63536 -20069 64421 ) ( -66521 -3812 64421 ) ( -63635 19279 -64565 ) mtn 0 0 0 1 1 - ( 66510 -3720 64438 ) ( -63547 -19978 64438 ) ( -66434 3113 -64549 ) mtn 0 0 0 1 1 - ( 50409 -45720 62915 ) ( -66822 12895 62915 ) ( -50778 44984 -63149 ) mtn 0 0 0 1 1 - } - { //brush 1348 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 65081 7711 65535 ) ( -64976 -8546 65535 ) ( -64976 -8546 -65535 ) mtn 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) mtn 0 0 0 1 1 - ( 64306 -12641 65535 ) ( -64518 11513 65535 ) ( -64518 11513 -65535 ) mtn 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) mtn 0 0 0 1 1 - ( -67217 12106 62651 ) ( 50015 -46510 62651 ) ( -50469 45601 -62954 ) mtn 0 0 0 1 1 - } - { //brush 1349 - ( 1872 65535 65535 ) ( 1872 -65535 65535 ) ( 1872 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 672 ) ( 65535 65535 672 ) ( -65535 -65535 672 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( -65535 45644 47036 ) ( 65535 45644 47036 ) ( -65535 -47036 -45644 ) fstng_0 0 0 0 1 1 - } - { //brush 1350 - ( 928 65535 65535 ) ( 928 -65535 65535 ) ( 928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1351 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 63859 -14731 65535 ) ( -64088 13701 65535 ) ( -64088 13701 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) fstng_0 0 0 0 1 1 - ( -64525 11474 65535 ) ( 64299 -12680 65535 ) ( -64525 11474 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 1352 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stnwll01 0 0 90 1 1 - ( 31464 57537 65535 ) ( -27151 -59694 65535 ) ( 31464 57537 -65535 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 90 1 1 - } - { //brush 1353 - ( -784 65535 65535 ) ( -784 -65535 65535 ) ( -784 65535 -65535 ) tile2492 0 0 180 1 1 - ( -464 -65535 65535 ) ( -464 65535 65535 ) ( -464 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -928 65535 ) ( 65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -896 65535 ) ( -65535 -896 65535 ) ( -65535 -896 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1354 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 256 ) ( 65535 65535 256 ) ( -65535 -65535 256 ) fstng_0 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 1355 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( -65534 15002 63801 ) ( 65534 15002 63801 ) ( -65534 -16786 -63355 ) tile2492 0 0 0 1 1 - } - { //brush 1356 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1357 - ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1872 -65535 65535 ) ( -1872 65535 65535 ) ( -1872 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 672 ) ( 65535 65535 672 ) ( -65535 -65535 672 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) fstng_0 0 0 0 1 1 - } - { //brush 1358 - ( -928 65535 65535 ) ( -928 -65535 65535 ) ( -928 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) mtn 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) mtn 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) mtn 0 0 0 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) mtn 0 0 0 1 1 - } - { //brush 1359 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_2 0 16 90 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( -62109 20911 65535 ) ( 62234 -20536 65535 ) ( -62109 20911 -65535 ) fstng_2 0 16 180 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) fstng_2 0 16 90 1 1 - } - { //brush 1360 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) mtn 0 0 180 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) mtn 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) mtn 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) mtn 0 0 0 1 1 - ( 62234 -20536 65535 ) ( -62109 20911 65535 ) ( -62109 20911 -65535 ) mtn 0 0 0 1 1 - } - { //brush 1361 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 90 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1362 - ( -960 65535 65535 ) ( -960 -65535 65535 ) ( -960 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -896 -65535 65535 ) ( -896 65535 65535 ) ( -896 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 640 ) ( 65535 -65535 640 ) ( -65535 -65535 640 ) stonesnow 0 0 0 1 1 - ( -46508 65535 46172 ) ( -46508 -65535 46172 ) ( 46172 65535 -46508 ) fstng_2 0 16 90 1 1 - } - { //brush 1363 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) fstng_2 0 16 90 1 1 - ( 45484 -65535 47196 ) ( 45484 65535 47196 ) ( -47196 65535 -45484 ) fstng_2 0 16 90 1 1 - ( 65535 46268 46412 ) ( -65535 46268 46412 ) ( -65535 -46412 -46268 ) fstng_2 0 16 0 1 1 - } - { //brush 1364 - ( -1360 65535 65535 ) ( -1360 -65535 65535 ) ( -1360 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 448 ) ( 65535 65535 448 ) ( -65535 -65535 448 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - ( 28168 59185 65535 ) ( -30447 -58046 65535 ) ( 28168 59185 -65535 ) fstng_0 0 0 180 1 1 - ( -30447 58046 65535 ) ( 28168 -59185 65535 ) ( -30447 58046 -65535 ) fstng_0 0 0 180 1 1 - } - { //brush 1365 - ( -912 -65535 65535 ) ( -912 65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 61999 65535 21242 ) ( 61999 -65535 21242 ) ( -62344 -65535 -20205 ) stonesnw 0 0 0 1 1 - } - { //brush 1366 - ( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 384 ) ( 65535 -65535 384 ) ( -65535 -65535 384 ) stnwll02 0 0 90 1 1 - ( 65535 46116 46564 ) ( -65535 46116 46564 ) ( -65535 -46564 -46116 ) fstng_2 0 0 0 1 1 - } - { //brush 1367 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( -58878 28783 65535 ) ( 58353 -29832 65535 ) ( -58878 28783 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 46348 46332 ) ( 65535 46348 46332 ) ( -65535 -46332 -46348 ) stnwll02 0 0 0 1 1 - ( -20359 72321 54282 ) ( 72321 -20359 54282 ) ( 18812 -73868 -52735 ) stnwll02 0 0 0 1 1 - } - { //brush 1368 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 720 ) ( 65535 65535 720 ) ( -65535 -65535 720 ) stnwll05 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll05 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnwll05 0 0 0 1 1 - } - { //brush 1369 - ( -2128 -65535 65535 ) ( -2128 65535 65535 ) ( -2128 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 624 ) ( 65535 65535 624 ) ( -65535 -65535 624 ) stnfloor02 0 0 0 1 1 - ( 65535 65535 656 ) ( 65535 -65535 656 ) ( -65535 -65535 656 ) stnfloor02 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnfloor02 0 0 0 1 1 - ( 44844 65535 47836 ) ( 44844 -65535 47836 ) ( -47836 65535 -44844 ) stnfloor02 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnfloor02 0 0 0 1 1 - ( 65535 -46332 46348 ) ( -65535 -46332 46348 ) ( -65535 46348 -46332 ) stnfloor02 0 0 0 1 1 - } - { //brush 1370 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -832 65535 ) ( 65535 -832 65535 ) ( -65535 -832 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -768 65535 ) ( -65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 0 1 1 - } - { //brush 1371 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) tile2492 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1216 65535 ) ( 65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - } - { //brush 1372 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 28015 59262 65535 ) ( -30600 -57969 65535 ) ( 28015 59262 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -58622 29295 ) ( 65535 58609 -29320 ) ( -65535 -58622 29295 ) stnwll05 0 0 0 1 1 - ( 27957 -59291 65535 ) ( -30658 57941 65535 ) ( -30658 57941 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1373 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1344 65535 ) ( -65535 -1344 65535 ) ( -65535 -1344 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll02 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( -31445 57547 65535 ) ( 27170 -59685 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -59032 -28476 ) ( 65535 58200 30140 ) ( -65535 -59032 -28476 ) stnwll05 0 0 0 1 1 - ( -29813 -58363 65535 ) ( 28802 58869 65535 ) ( 28802 58869 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1374 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -31548 57496 65535 ) ( 27068 -59736 65535 ) ( -31548 57496 -65535 ) stnwll05 0 0 0 1 1 - } - { //brush 1375 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( 29365 65534 58587 ) ( 29365 -65534 58587 ) ( -29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1376 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stonesnow 0 0 0 1 1 - ( -65535 -464 65535 ) ( 65535 -464 65535 ) ( -65535 -464 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 -65535 16 ) ( 65535 65535 16 ) ( -65535 -65535 16 ) stonesnow 0 0 90 1 1 - ( 65535 65535 64 ) ( 65535 -65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 90 1 1 - ( -29365 -65534 58587 ) ( -29365 65534 58587 ) ( 29250 65534 -58645 ) stonesnow 0 0 0 1 1 - } - { //brush 1377 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) fstng_2 0 16 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) fstng_2 0 16 0 1 1 - ( -65535 -45276 47404 ) ( 65535 -45276 47404 ) ( -65535 47404 -45276 ) fstng_2 0 16 0 1 1 - ( 65535 46812 45868 ) ( -65535 46812 45868 ) ( 65535 -45868 -46812 ) fstng_2 0 16 0 1 1 - } - { //brush 1378 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 1379 - ( 2720 65535 65535 ) ( 2720 -65535 65535 ) ( 2720 65535 -65535 ) ctf01 96 80 180 1 1 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) ctf01 96 80 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) ctf01 96 80 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf01 96 80 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) ctf01 96 80 0 1 1 - ( 61587 -65535 22411 ) ( 61587 65535 22411 ) ( -61137 -65535 -23610 ) ctf01 96 80 0 1 1 - } - { //brush 1380 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1264 65535 ) ( -65535 1264 65535 ) ( -65535 1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( -57656 31228 65535 ) ( 59576 -27388 65535 ) ( -57656 31228 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1381 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 46722 45958 ) ( 65535 46722 45958 ) ( -65535 -45958 -46722 ) light04 16 16 0 0.250000 0.250000 - ( -65535 -45574 47106 ) ( 65535 -45574 47106 ) ( -65535 47106 -45574 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1382 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 -45542 47138 ) ( 65535 -45542 47138 ) ( -65535 47138 -45542 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 46690 45990 ) ( 65535 46690 45990 ) ( -65535 -45990 -46690 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1383 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 46658 46022 ) ( 65535 46658 46022 ) ( -65535 -46022 -46658 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -45510 47170 ) ( 65535 -45510 47170 ) ( -65535 47170 -45510 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1384 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 -45526 47154 ) ( 65535 -45526 47154 ) ( -65535 47154 -45526 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 46674 46006 ) ( 65535 46674 46006 ) ( -65535 -46006 -46674 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1385 - ( -65535 1151 65535 ) ( 65535 1151 65535 ) ( -65535 1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( -65535 46706 45974 ) ( 65535 46706 45974 ) ( -65535 -45974 -46706 ) light04 16 16 0 0.250000 0.250000 - ( -44510 48170 65535 ) ( 48170 -44510 65535 ) ( -44510 48170 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -45558 47122 ) ( 65535 -45558 47122 ) ( -65535 47122 -45558 ) light04 16 16 0 0.250000 0.250000 - ( -45658 -47022 65535 ) ( 47022 45658 65535 ) ( 47022 45658 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1386 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -45618 47062 ) ( -65535 -45618 47062 ) ( -65535 47062 -45618 ) light04 16 16 0 0.250000 0.250000 - ( 65535 46582 46098 ) ( -65535 46582 46098 ) ( -65535 -46098 -46582 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1387 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 46598 46082 ) ( -65535 46598 46082 ) ( -65535 -46082 -46598 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -45634 47046 ) ( -65535 -45634 47046 ) ( -65535 47046 -45634 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1388 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -45602 47078 ) ( -65535 -45602 47078 ) ( -65535 47078 -45602 ) light04 16 16 0 0.250000 0.250000 - ( 65535 46566 46114 ) ( -65535 46566 46114 ) ( -65535 -46114 -46566 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1389 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 46614 46066 ) ( -65535 46614 46066 ) ( -65535 -46066 -46614 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -45650 47030 ) ( -65535 -45650 47030 ) ( -65535 47030 -45650 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1390 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 961 65535 ) ( -65535 961 65535 ) ( -65535 961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 46630 46050 ) ( -65535 46630 46050 ) ( -65535 -46050 -46630 ) light04 16 16 0 0.250000 0.250000 - ( 48078 -44602 65535 ) ( -44602 48078 65535 ) ( -44602 48078 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -45666 47014 ) ( -65535 -45666 47014 ) ( -65535 47014 -45666 ) light04 16 16 0 0.250000 0.250000 - ( 47114 45566 65535 ) ( -45566 -47114 65535 ) ( 47114 45566 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1391 - ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2688 -65535 65535 ) ( 2688 65535 65535 ) ( 2688 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 848 65535 ) ( 65535 848 65535 ) ( -65535 848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 960 65535 ) ( -65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1392 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - } - { //brush 1393 - ( 880 65535 65535 ) ( 880 -65535 65535 ) ( 880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 1394 - ( -64 65535 65535 ) ( -64 -65535 65535 ) ( -64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 61258 57929 -38488 ) ( 61258 -69226 -6699 ) ( -60996 -57765 39146 ) tile2492 0 0 0 1 1 - ( -65534 16990 63304 ) ( 65534 16990 63304 ) ( -65534 -14799 -63852 ) tile2492 0 0 0 1 1 - ( 60996 69391 7356 ) ( 60996 -57765 39146 ) ( -61258 57929 -38488 ) tile2492 0 0 0 1 1 - } - { //brush 1395 - ( 1632 65535 65535 ) ( 1632 -65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 1760 -65535 65535 ) ( 1760 65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) ctf01 32 48 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 0 1 1 - ( 61721 -65535 -22053 ) ( 61721 65535 -22053 ) ( -61003 -65535 23968 ) stnwll02 0 0 0 1 1 - } - { //brush 1396 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -58491 -29557 65535 ) ( 58741 29058 65535 ) ( -58491 -29557 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1397 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) ctf01 64 32 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -16 65535 ) ( -65535 -16 65535 ) ( -65535 -16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61464 -22737 ) ( 65535 61259 23284 ) ( -65535 61259 23284 ) stnwll05 0 0 0 1 1 - } - { //brush 1398 - ( 848 65535 65535 ) ( 848 -65535 65535 ) ( 848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( 864 -65535 65535 ) ( 864 65535 65535 ) ( 864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1399 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( 912 -65535 65535 ) ( 912 65535 65535 ) ( 912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 58741 -29058 65535 ) ( -58491 29557 65535 ) ( -58491 29557 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1400 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 2320 -65535 65535 ) ( 2320 65535 65535 ) ( 2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1401 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 80 180 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) ctf02 96 80 180 1 1 - ( 65535 -65535 104 ) ( 65535 65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) ctf02 96 80 90 1 1 - } - { //brush 1402 - ( 64 65535 65535 ) ( 64 -65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) tile2492 0 0 0 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) tile2492 0 0 0 1 1 - } - { //brush 1403 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 90 1 1 - } - { //brush 1404 - ( -864 65535 65535 ) ( -864 -65535 65535 ) ( -864 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -848 -65535 65535 ) ( -848 65535 65535 ) ( -848 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stonesnow 0 0 0 1 1 - } - { //brush 1405 - ( -912 65535 65535 ) ( -912 -65535 65535 ) ( -912 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stonesnw 0 0 180 1 1 - ( -65535 -320 65535 ) ( 65535 -320 65535 ) ( -65535 -320 -65535 ) stonesnw 0 0 0 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stonesnw 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnw 0 0 0 1 1 - ( 58491 29557 65535 ) ( -58741 -29058 65535 ) ( -58741 -29058 -65535 ) stonesnw 0 0 0 1 1 - } - { //brush 1406 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) ctf02 96 48 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) ctf02 96 48 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 96 48 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) ctf02 96 48 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) ctf02 96 48 0 1 1 - ( 61003 -65535 23968 ) ( 61003 65535 23968 ) ( -61721 -65535 -22053 ) ctf02 96 48 0 1 1 - } - { //brush 1407 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) ctf02 32 80 180 1 1 - ( -2720 -65535 65535 ) ( -2720 65535 65535 ) ( -2720 65535 -65535 ) ctf02 32 80 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) ctf02 32 80 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 32 80 0 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf02 32 80 0 1 1 - ( 61137 -65535 -23610 ) ( 61137 65535 -23610 ) ( -61587 -65535 22411 ) ctf02 32 80 0 1 1 - } - { //brush 1408 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -1632 -65535 65535 ) ( -1632 65535 65535 ) ( -1632 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1409 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1072 -65535 65535 ) ( -1072 65535 65535 ) ( -1072 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll05 0 0 90 1 1 - } - { //brush 1410 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1216 65535 ) ( -65535 -1216 65535 ) ( -65535 -1216 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65535 65535 432 ) ( 65535 -65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - } - { //brush 1411 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_0 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) fstng_0 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_0 0 0 0 1 1 - } - { //brush 1412 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1413 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -46706 45974 ) ( -65535 -46706 45974 ) ( -65535 45974 -46706 ) light04 16 16 0 0.250000 0.250000 - ( 65535 45558 47122 ) ( -65535 45558 47122 ) ( -65535 -47122 -45558 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1414 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 45526 47154 ) ( -65535 45526 47154 ) ( -65535 -47154 -45526 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -46674 46006 ) ( -65535 -46674 46006 ) ( -65535 46006 -46674 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1415 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -46658 46022 ) ( -65535 -46658 46022 ) ( -65535 46022 -46658 ) light04 16 16 0 0.250000 0.250000 - ( 65535 45510 47170 ) ( -65535 45510 47170 ) ( -65535 -47170 -45510 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1416 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 45542 47138 ) ( -65535 45542 47138 ) ( -65535 -47138 -45542 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -46690 45990 ) ( -65535 -46690 45990 ) ( -65535 45990 -46690 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1417 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -1151 65535 ) ( -65535 -1151 65535 ) ( -65535 -1151 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 45574 47106 ) ( -65535 45574 47106 ) ( -65535 -47106 -45574 ) light04 16 16 0 0.250000 0.250000 - ( 44510 -48170 65535 ) ( -48170 44510 65535 ) ( -48170 44510 -65535 ) light04 16 16 180 0.250000 0.250000 - ( 65535 -46722 45958 ) ( -65535 -46722 45958 ) ( -65535 45958 -46722 ) light04 16 16 0 0.250000 0.250000 - ( 45658 47022 65535 ) ( -47022 -45658 65535 ) ( 45658 47022 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1418 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -46630 46050 ) ( 65535 -46630 46050 ) ( -65535 46050 -46630 ) light04 16 16 0 0.250000 0.250000 - ( -65535 45666 47014 ) ( 65535 45666 47014 ) ( -65535 -47014 -45666 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1419 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 45602 47078 ) ( 65535 45602 47078 ) ( -65535 -47078 -45602 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -46566 46114 ) ( 65535 -46566 46114 ) ( -65535 46114 -46566 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1420 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 -46614 46066 ) ( 65535 -46614 46066 ) ( -65535 46066 -46614 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 45650 47030 ) ( 65535 45650 47030 ) ( -65535 -47030 -45650 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1421 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 45618 47062 ) ( 65535 45618 47062 ) ( -65535 -47062 -45618 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 -46582 46098 ) ( 65535 -46582 46098 ) ( -65535 46098 -46582 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1422 - ( -65535 -961 65535 ) ( 65535 -961 65535 ) ( -65535 -961 -65535 ) light04 16 16 0 0.250000 0.250000 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( -65535 -46598 46082 ) ( 65535 -46598 46082 ) ( -65535 46082 -46598 ) light04 16 16 0 0.250000 0.250000 - ( -48078 44602 65535 ) ( 44602 -48078 65535 ) ( -48078 44602 -65535 ) light04 16 16 180 0.250000 0.250000 - ( -65535 45634 47046 ) ( 65535 45634 47046 ) ( -65535 -47046 -45634 ) light04 16 16 0 0.250000 0.250000 - ( -47114 -45566 65535 ) ( 45566 47114 65535 ) ( 45566 47114 -65535 ) light04 16 16 180 0.250000 0.250000 - } - { //brush 1423 - ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1152 65535 ) ( -65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - ( 57656 -31228 65535 ) ( -59576 27388 65535 ) ( -59576 27388 -65535 ) stnwll02 0 0 0 1 1 - } - { //brush 1424 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -2464 -65535 65535 ) ( -2464 65535 65535 ) ( -2464 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1264 65535 ) ( 65535 -1264 65535 ) ( -65535 -1264 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -848 65535 ) ( -65535 -848 65535 ) ( -65535 -848 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) fstng_2 0 0 0 1 1 - } - { //brush 1425 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1248 -65535 65535 ) ( -1248 65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1426 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 288 ) ( 65535 65535 288 ) ( -65535 -65535 288 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1427 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1428 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1472 -65535 65535 ) ( 1472 65535 65535 ) ( 1472 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1536 65535 ) ( 65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1632 65535 ) ( -65535 1632 65535 ) ( -65535 1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 1429 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) ctf01 96 80 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) ctf01 96 80 0 1 1 - ( 61587 65535 22411 ) ( 61587 -65535 22411 ) ( -61137 -65535 -23610 ) ctf01 96 80 0 1 1 - ( 61823 -65535 -21779 ) ( 61823 65535 -21779 ) ( -60900 -65535 24241 ) ctf01 96 80 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) ctf01 96 80 0 1 1 - } - { //brush 1430 - ( 2848 65535 65535 ) ( 2848 -65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1431 - ( 2656 -65535 65535 ) ( 2656 65535 65535 ) ( 2656 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) millgt1 16 0 90 1 0.500000 - ( 47308 65535 45372 ) ( 47308 -65535 45372 ) ( -45372 -65535 -47308 ) stnwll02 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) stnwll02 0 0 180 1 1 - } - { //brush 1432 - ( 1200 65535 65535 ) ( 1200 -65535 65535 ) ( 1200 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll01 0 0 90 1 1 - } - { //brush 1433 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - ( 65535 65535 560 ) ( 65535 -65535 560 ) ( -65535 -65535 560 ) stnwll02 0 0 90 1 1 - } - { //brush 1434 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1248 -65535 65535 ) ( 1248 65535 65535 ) ( 1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1280 65535 ) ( 65535 1280 65535 ) ( -65535 1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 1376 65535 ) ( -65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - } - { //brush 1435 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( -65535 36876 54178 ) ( 65535 36876 54178 ) ( -65535 -35827 -54877 ) tile2492 0 0 180 1 1 - } - { //brush 1436 - ( 1360 65535 65535 ) ( 1360 -65535 65535 ) ( 1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1632 -65535 65535 ) ( 1632 65535 65535 ) ( 1632 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -288 65535 ) ( 65535 -288 65535 ) ( -65535 -288 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - } - { //brush 1437 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( -27573 -59483 65535 ) ( 31042 57749 65535 ) ( 31042 57749 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1438 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -592 65535 ) ( 65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -576 65535 ) ( -65535 -576 65535 ) ( -65535 -576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1439 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( 1808 -65535 65535 ) ( 1808 65535 65535 ) ( 1808 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1440 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( -65535 45660 47020 ) ( 65535 45660 47020 ) ( -65535 -47020 -45660 ) stnwll02 0 0 90 1 1 - } - { //brush 1441 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 30504 -58017 65535 ) ( -28111 59214 65535 ) ( -28111 59214 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1442 - ( 1760 65535 65535 ) ( 1760 -65535 65535 ) ( 1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -768 65535 ) ( 65535 -768 65535 ) ( -65535 -768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -752 65535 ) ( -65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1443 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 90 1 1 - ( 65535 -61526 -22572 ) ( 65535 61197 23449 ) ( -65535 -61526 -22572 ) tile2492 0 0 90 1 1 - ( -65534 -16990 63304 ) ( 65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 180 1 1 - } - { //brush 1444 - ( 64 -65535 65535 ) ( 64 65535 65535 ) ( 64 65535 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 0 1 1 - ( 65534 -16990 63304 ) ( -65534 -16990 63304 ) ( -65534 14799 -63852 ) tile2492 0 0 0 1 1 - ( 61258 69226 -6699 ) ( 61258 -57929 -38488 ) ( -60996 57765 39146 ) tile2492 0 0 0 1 1 - ( 60996 57765 39146 ) ( 60996 -69391 7356 ) ( -61258 69226 -6699 ) tile2492 0 0 0 1 1 - } - { //brush 1445 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 752 65535 ) ( 65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 768 65535 ) ( -65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1446 - ( -1808 65535 65535 ) ( -1808 -65535 65535 ) ( -1808 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1447 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 592 ) ( 65535 65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) stnwll02 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll02 0 0 90 1 1 - } - { //brush 1448 - ( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 640 65535 ) ( 65535 640 65535 ) ( -65535 640 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 704 65535 ) ( -65535 704 65535 ) ( -65535 704 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 608 ) ( 65535 65535 608 ) ( -65535 -65535 608 ) stnwll01 0 0 90 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll01 0 0 90 1 1 - ( 65535 -45660 47020 ) ( -65535 -45660 47020 ) ( -65535 47020 -45660 ) stnwll01 0 0 90 1 1 - } - { //brush 1449 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll01 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 90 1 1 - ( 27573 59483 65535 ) ( -31042 -57749 65535 ) ( 27573 59483 -65535 ) stnwll01 0 0 0 1 1 - } - { //brush 1450 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1760 -65535 65535 ) ( -1760 65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 576 65535 ) ( 65535 576 65535 ) ( -65535 576 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 592 65535 ) ( -65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) stnwll02 0 0 90 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 90 1 1 - } - { //brush 1451 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) ctf02 64 32 0 1 1 - ( -65535 16 65535 ) ( 65535 16 65535 ) ( -65535 16 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 65535 448 ) ( 65535 -65535 448 ) ( -65535 -65535 448 ) stnwll05 0 0 0 1 1 - ( 65535 -61259 23284 ) ( 65535 61464 -22737 ) ( -65535 61464 -22737 ) stnwll05 0 0 0 1 1 - } - { //brush 1452 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -1360 -65535 65535 ) ( -1360 65535 65535 ) ( -1360 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 288 65535 ) ( -65535 288 65535 ) ( -65535 288 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) fstng_0 0 0 0 1 1 - } - { //brush 1453 - ( -2336 -65535 65535 ) ( -2336 65535 65535 ) ( -2336 65535 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_2 0 16 0 1 1 - ( -65535 -45836 46844 ) ( 65535 -45836 46844 ) ( -65535 46844 -45836 ) fstng_2 0 16 0 1 1 - ( 57918 30703 65535 ) ( -59313 -27912 65535 ) ( -59313 -27912 -65535 ) fstng_2 0 16 0 1 1 - ( 65535 46348 46332 ) ( -65535 46348 46332 ) ( -65535 -46332 -46348 ) fstng_2 0 16 0 1 1 - } - { //brush 1454 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) ctf02 32 80 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) ctf02 32 80 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) ctf02 32 80 0 1 1 - ( 60900 -65535 24241 ) ( 60900 65535 24241 ) ( -61823 -65535 -21779 ) ctf02 32 80 0 1 1 - ( 61137 65535 -23610 ) ( 61137 -65535 -23610 ) ( -61587 -65535 22411 ) ctf02 32 80 0 1 1 - } - { //brush 1455 - ( -2880 65535 65535 ) ( -2880 -65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2848 -65535 65535 ) ( -2848 65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 272 ) ( 65535 65535 272 ) ( -65535 -65535 272 ) stnwll02 0 0 0 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1456 - ( -1632 65535 65535 ) ( -1632 -65535 65535 ) ( -1632 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -1472 -65535 65535 ) ( -1472 65535 65535 ) ( -1472 65535 -65535 ) stnfloor1 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnfloor1 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stnfloor1 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stnfloor1 0 0 0 1 1 - } - { //brush 1457 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -1200 -65535 65535 ) ( -1200 65535 65535 ) ( -1200 65535 -65535 ) stnwll01 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll01 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll01 0 0 90 1 1 - } - { //brush 1458 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - ( 65535 65535 624 ) ( 65535 -65535 624 ) ( -65535 -65535 624 ) stnwll02 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) stnwll02 0 0 90 1 1 - } - { //brush 1459 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 544 ) ( 65535 65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 0 1 1 - } - { //brush 1460 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) ctf01 64 80 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) ctf01 64 80 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf01 64 80 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) ctf01 64 80 180 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) ctf01 64 80 90 1 1 - ( 65535 -61243 23326 ) ( 65535 61480 -22695 ) ( -65535 -61243 23326 ) ctf01 64 80 90 1 1 - } - { //brush 1461 - ( 2720 65535 65535 ) ( 2720 -65535 65535 ) ( 2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2848 -65535 65535 ) ( 2848 65535 65535 ) ( 2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 96 65535 ) ( 65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) stnwll02 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 0 1 1 - } - { //brush 1462 - ( -80 -65535 65535 ) ( -80 65535 65535 ) ( -80 65535 -65535 ) ctf01 32 80 0 1 1 - ( -65535 992 65535 ) ( 65535 992 65535 ) ( -65535 992 -65535 ) ctf01 32 80 180 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) ctf01 32 80 180 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) ctf01 32 80 90 1 1 - ( -16086 65534 63530 ) ( -16086 -65534 63530 ) ( 15702 65534 -63626 ) ctf01 32 80 0 1 1 - ( 65535 -61197 23449 ) ( 65535 61526 -22572 ) ( -65535 -61197 23449 ) ctf01 32 80 90 1 1 - } - { //brush 1463 - ( 80 65535 65535 ) ( 80 -65535 65535 ) ( 80 65535 -65535 ) ctf02 96 80 0 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) ctf02 96 80 0 1 1 - ( -65535 -1120 65535 ) ( 65535 -1120 65535 ) ( -65535 -1120 -65535 ) ctf02 96 80 180 1 1 - ( 65535 65535 104 ) ( 65535 -65535 104 ) ( -65535 -65535 104 ) ctf02 96 80 90 1 1 - ( 65535 -61526 -22572 ) ( 65535 61197 23449 ) ( -65535 -61526 -22572 ) ctf02 96 80 90 1 1 - } - { //brush 1464 - ( -2848 65535 65535 ) ( -2848 -65535 65535 ) ( -2848 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2720 -65535 65535 ) ( -2720 65535 65535 ) ( -2720 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -144 65535 ) ( 65535 -144 65535 ) ( -65535 -144 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -96 65535 ) ( -65535 -96 65535 ) ( -65535 -96 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 0 1 1 - } - { //brush 1465 - ( -1472 65535 65535 ) ( -1472 -65535 65535 ) ( -1472 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( -1408 -65535 65535 ) ( -1408 65535 65535 ) ( -1408 65535 -65535 ) stonesnw2 0 0 180 1 1 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) stonesnw2 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stonesnw2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnw2 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) stonesnw2 0 0 0 1 1 - } - { //brush 1466 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1072 -65535 65535 ) ( -1072 65535 65535 ) ( -1072 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1467 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1376 65535 ) ( 65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -1280 65535 ) ( -65535 -1280 65535 ) ( -65535 -1280 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll05 0 0 90 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll05 0 0 90 1 1 - } - { //brush 1468 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1469 - ( -1216 65535 65535 ) ( -1216 -65535 65535 ) ( -1216 65535 -65535 ) stnwll01 0 0 180 1 1 - ( 2880 -65535 65535 ) ( 2880 65535 65535 ) ( 2880 65535 -65535 ) stnwll01 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll01 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll01 0 0 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll01 0 0 0 1 1 - } - { //brush 1470 - ( -2976 65535 65535 ) ( -2976 -65535 65535 ) ( -2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -2880 -65535 65535 ) ( -2880 65535 65535 ) ( -2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 464 ) ( 65535 65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) stnwll02 0 0 90 1 1 - } - { //brush 1471 - ( -320 65535 65535 ) ( -320 -65535 65535 ) ( -320 65535 -65535 ) tile2492 0 0 0 1 1 - ( -280 -65535 65535 ) ( -280 65535 65535 ) ( -280 65535 -65535 ) tile2492 0 0 0 1 1 - ( -65535 144 65535 ) ( 65535 144 65535 ) ( -65535 144 -65535 ) tile2492 0 0 180 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) tile2492 0 0 180 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) tile2492 0 0 90 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( -16101 -65534 63526 ) ( -16101 65534 63526 ) ( 15687 65534 -63630 ) tile2492 0 0 0 1 1 - } - { //brush 1472 - ( -992 65535 65535 ) ( -992 -65535 65535 ) ( -992 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -816 -65535 65535 ) ( -816 65535 65535 ) ( -816 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1473 - ( 2464 65535 65535 ) ( 2464 -65535 65535 ) ( 2464 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) stnwll02 0 0 90 1 1 - ( -65535 -46044 46636 ) ( 65535 -46044 46636 ) ( -65535 46636 -46044 ) fstng_2 0 16 0 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) stnwll02 0 0 90 1 1 - } - { //brush 1474 - ( -65535 -576 65535 ) ( 65535 -576 65535 ) ( -65535 -576 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 96 65535 ) ( -65535 96 65535 ) ( -65535 96 -65535 ) fstng_2 0 16 180 1 1 - ( 65535 -65535 528 ) ( 65535 65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - ( 65535 65535 752 ) ( 65535 -65535 752 ) ( -65535 -65535 752 ) fstng_2 0 16 90 1 1 - ( -44844 65535 47836 ) ( -44844 -65535 47836 ) ( 47836 65535 -44844 ) fstng_2 0 16 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) fstng_2 0 16 90 1 1 - ( -57918 -30703 65535 ) ( 59313 27912 65535 ) ( -57918 -30703 -65535 ) fstng_2 0 16 180 1 1 - } - { //brush 1475 - ( -65535 -256 65535 ) ( 65535 -256 65535 ) ( -65535 -256 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -144 65535 ) ( -65535 -144 65535 ) ( -65535 -144 -65535 ) tile2492 0 0 0 1 1 - ( 65535 -65535 80 ) ( 65535 65535 80 ) ( -65535 -65535 80 ) tile2492 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - ( 16086 65534 63530 ) ( 16086 -65534 63530 ) ( -15702 65534 -63626 ) tile2492 0 0 0 1 1 - ( 16101 -65534 63526 ) ( 16101 65534 63526 ) ( -15687 65534 -63630 ) tile2492 0 0 180 1 1 - } - { //brush 1476 - ( 80 -65535 65535 ) ( 80 65535 65535 ) ( 80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( -36223 65535 54614 ) ( -36223 -65535 54614 ) ( 36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 1477 - ( -80 65535 65535 ) ( -80 -65535 65535 ) ( -80 65535 -65535 ) tile2492 0 0 180 1 1 - ( -65535 -880 65535 ) ( 65535 -880 65535 ) ( -65535 -880 -65535 ) tile2492 0 0 0 1 1 - ( 65535 65535 208 ) ( 65535 -65535 208 ) ( -65535 -65535 208 ) tile2492 0 0 0 1 1 - ( 36223 -65535 54614 ) ( 36223 65535 54614 ) ( -36481 65535 -54442 ) tile2492 0 0 0 1 1 - ( 65534 28834 58853 ) ( -65534 28834 58853 ) ( -65534 -29781 -58379 ) tile2492 0 0 0 1 1 - ( -65535 -36876 54178 ) ( 65535 -36876 54178 ) ( -65535 35827 -54877 ) tile2492 0 0 0 1 1 - } - { //brush 1478 - ( -2320 65535 65535 ) ( -2320 -65535 65535 ) ( -2320 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -928 -65535 65535 ) ( -928 65535 65535 ) ( -928 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) fstng_2 0 0 0 1 1 - ( 65535 65535 480 ) ( 65535 -65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - } - { //brush 1479 - ( 2208 65535 65535 ) ( 2208 -65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1480 - ( 864 65535 65535 ) ( 864 -65535 65535 ) ( 864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( 1136 -65535 65535 ) ( 1136 65535 65535 ) ( 1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 - ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 - } - { //brush 1481 - ( -768 65535 65535 ) ( -768 -65535 65535 ) ( -768 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -320 -65535 65535 ) ( -320 65535 65535 ) ( -320 65535 -65535 ) stonesnow 0 0 180 1 1 - ( -65535 -96 65535 ) ( 65535 -96 65535 ) ( -65535 -96 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 320 65535 ) ( -65535 320 65535 ) ( -65535 320 -65535 ) stonesnow 0 0 0 1 1 - ( 65535 -65535 64 ) ( 65535 65535 64 ) ( -65535 -65535 64 ) stonesnow 0 0 0 1 1 - ( 65535 65535 272 ) ( 65535 -65535 272 ) ( -65535 -65535 272 ) stonesnow 0 0 0 1 1 - } - { //brush 1482 - ( -1760 65535 65535 ) ( -1760 -65535 65535 ) ( -1760 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1056 -65535 65535 ) ( -1056 65535 65535 ) ( -1056 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 768 65535 ) ( 65535 768 65535 ) ( -65535 768 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 880 65535 ) ( -65535 880 65535 ) ( -65535 880 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 512 ) ( 65535 65535 512 ) ( -65535 -65535 512 ) stnwll02 0 0 0 1 1 - ( 65535 65535 576 ) ( 65535 -65535 576 ) ( -65535 -65535 576 ) stnwll02 0 0 0 1 1 - ( 65535 -45644 47036 ) ( -65535 -45644 47036 ) ( -65535 47036 -45644 ) stnwll02 0 0 0 1 1 - } - { //brush 1483 - ( -1136 65535 65535 ) ( -1136 -65535 65535 ) ( -1136 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -864 -65535 65535 ) ( -864 65535 65535 ) ( -864 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 64 65535 ) ( -65535 64 65535 ) ( -65535 64 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 208 ) ( 65535 65535 208 ) ( -65535 -65535 208 ) stnwll05 0 0 90 1 1 - ( 65535 61464 -22737 ) ( 65535 -61259 23284 ) ( -65535 61464 -22737 ) stnwll05 0 0 90 1 1 - ( 65535 61259 23284 ) ( 65535 -61464 -22737 ) ( -65535 61259 23284 ) stnwll05 0 0 90 1 1 - } - { //brush 1484 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -1184 65535 ) ( -65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 336 ) ( 65535 65535 336 ) ( -65535 -65535 336 ) stnwll05 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 27170 -59685 65535 ) ( -31445 57547 65535 ) ( -31445 57547 -65535 ) stnwll05 0 0 0 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) stnwll05 0 0 180 1 1 - } - { //brush 1485 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) ctf01 64 80 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) ctf01 64 80 0 1 1 - ( -65535 -64 65535 ) ( 65535 -64 65535 ) ( -65535 -64 -65535 ) ctf01 64 80 180 1 1 - ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) ctf01 64 80 90 1 1 - ( 65535 61480 -22695 ) ( 65535 -61243 23326 ) ( -65535 -61243 23326 ) ctf01 64 80 90 1 1 - } - { //brush 1486 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 928 65535 ) ( -65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( -57829 30882 65535 ) ( 59403 -27733 65535 ) ( -57829 30882 -65535 ) fstng_2 0 0 0 1 1 - ( 31548 -57496 65535 ) ( -27068 59736 65535 ) ( -27068 59736 -65535 ) fstng_2 0 0 180 1 1 - } - { //brush 1487 - ( -1248 65535 65535 ) ( -1248 -65535 65535 ) ( -1248 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1536 65535 ) ( -65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) stnwll02 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - } - { //brush 1488 - ( 2880 65535 65535 ) ( 2880 -65535 65535 ) ( 2880 65535 -65535 ) stnwll02 0 0 0 1 1 - ( 2976 -65535 65535 ) ( 2976 65535 65535 ) ( 2976 65535 -65535 ) stnwll02 0 0 0 1 1 - ( -65535 -1632 65535 ) ( 65535 -1632 65535 ) ( -65535 -1632 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -64 65535 ) ( -65535 -64 65535 ) ( -65535 -64 -65535 ) stnwll02 0 0 180 1 1 - ( 65535 -65535 -80 ) ( 65535 65535 -80 ) ( -65535 -65535 -80 ) stnwll02 0 0 90 1 1 - ( 65535 65535 464 ) ( 65535 -65535 464 ) ( -65535 -65535 464 ) stnwll02 0 0 90 1 1 - ( 65535 -61480 -22695 ) ( 65535 61243 23326 ) ( -65535 61243 23326 ) stnwll02 0 0 90 1 1 - } - { //brush 1489 - ( -2464 65535 65535 ) ( -2464 -65535 65535 ) ( -2464 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2208 -65535 65535 ) ( -2208 65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 180 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stnwll05 0 0 90 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } - { //brush 1490 - ( -1120 65535 65535 ) ( -1120 -65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 - ( -65535 -512 65535 ) ( 65535 -512 65535 ) ( -65535 -512 -65535 ) sky003 0 0 0 1 1 - ( 65535 -480 65535 ) ( -65535 -480 65535 ) ( -65535 -480 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 768 ) ( 65535 -65535 768 ) ( -65535 -65535 768 ) sky003 0 0 0 1 1 - ( -58219 -30101 65535 ) ( 59013 28514 65535 ) ( -58219 -30101 -65535 ) sky003 0 0 0 1 1 - ( 64593 -11074 65535 ) ( -64693 10472 65535 ) ( -64693 10472 -65535 ) sky003 0 0 0 1 1 - } - { //brush 1491 - ( 1120 65535 65535 ) ( 1120 -65535 65535 ) ( 1120 65535 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 90 1 1 - ( -44652 -65535 48028 ) ( -44652 65535 48028 ) ( 48028 65535 -44652 ) sky003 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 90 1 1 - ( 59659 -27221 65535 ) ( -57573 31394 65535 ) ( -57573 31394 -65535 ) sky003 0 0 180 1 1 - } - { //brush 1492 - ( -1120 -65535 65535 ) ( -1120 65535 65535 ) ( -1120 65535 -65535 ) sky003 0 0 0 1 1 - ( 65535 -65535 752 ) ( 65535 65535 752 ) ( -65535 -65535 752 ) sky003 0 0 0 1 1 - ( 65535 65535 800 ) ( 65535 -65535 800 ) ( -65535 -65535 800 ) sky003 0 0 90 1 1 - ( 65535 -45276 47404 ) ( -65535 -45276 47404 ) ( -65535 47404 -45276 ) sky003 0 0 90 1 1 - ( -65535 45276 47404 ) ( 65535 45276 47404 ) ( -65535 -47404 -45276 ) sky003 0 0 90 1 1 - ( -59659 27221 65535 ) ( 57573 -31394 65535 ) ( -59659 27221 -65535 ) sky003 0 0 180 1 1 - ( 44652 65535 48028 ) ( 44652 -65535 48028 ) ( -48028 65535 -44652 ) sky003 0 0 90 1 1 - } -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "2" - { //brush 0 - ( 1776 65535 65535 ) ( 1776 -65535 65535 ) ( 1776 65535 -65535 ) door 0 -4 0 1 1 - ( 1784 -65535 65535 ) ( 1784 65535 65535 ) ( 1784 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } - { //brush 1 - ( 1784 65535 65535 ) ( 1784 -65535 65535 ) ( 1784 65535 -65535 ) door 0 -4 0 1 1 - ( 1792 -65535 65535 ) ( 1792 65535 65535 ) ( 1792 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 -752 65535 ) ( 65535 -752 65535 ) ( -65535 -752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -592 65535 ) ( -65535 -592 65535 ) ( -65535 -592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "2" - { //brush 0 - ( 1216 65535 65535 ) ( 1216 -65535 65535 ) ( 1216 65535 -65535 ) door 0 12 0 1 1 - ( 1224 -65535 65535 ) ( 1224 65535 65535 ) ( 1224 65535 -65535 ) door 0 12 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } - { //brush 1 - ( 1224 65535 65535 ) ( 1224 -65535 65535 ) ( 1224 65535 -65535 ) door 0 12 0 1 1 - ( 1232 -65535 65535 ) ( 1232 65535 65535 ) ( 1232 65535 -65535 ) door 0 12 0 1 1 - ( -65535 1376 65535 ) ( 65535 1376 65535 ) ( -65535 1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1536 65535 ) ( -65535 1536 65535 ) ( -65535 1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - } -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1120 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "832 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "768 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "480 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "416 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1120 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "832 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "768 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "480 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "416 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "128 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "128 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "1920 1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "1408 1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1904 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1904 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "1128 0 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "2208 -456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1984 -456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "2208 -888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1984 -888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "744 944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "744 1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1176 944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1024 1456 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 -208 368" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 -304 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "1184 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "1184 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "640 0 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "384 -384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "384 384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "992 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "992 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 -128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 -400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1024 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1696 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "1360 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 -440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1264 -440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 0 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 -416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 -416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 -208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 -208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2192 104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2192 -104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2400 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "2400 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2064 0 384" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 1280 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 832 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 384 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 608 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2472 160 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1808 568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1808 1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1488 1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 832 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 576 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1184 912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "1184 1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2144 672 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "2144 1440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2400 -520 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "1696 -584 432" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1904 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1776 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1648 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1520 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1392 700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1392 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1520 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1648 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1776 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "1904 1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "1392 1056 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "1176 1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2528 0 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 1 0.7" - "origin" "2272 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "220" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2784 -128 360" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "2400 -208 480" -} -{ - "classname" "func_plat" - "angle" "-2" - "height" "160" - "speed" "50" - { //brush 0 - ( 2176 -65535 65535 ) ( 2176 65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 0 1 1 - ( 63787 -65534 -15058 ) ( 63787 65534 -15058 ) ( -63369 -65534 16730 ) fstng_2 0 0 0 1 1 - } - { //brush 1 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - } - { //brush 2 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 992 65535 ) ( -65535 992 65535 ) ( -65535 992 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - } - { //brush 3 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1152 65535 ) ( 65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 90 1 1 - } - { //brush 4 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 1120 65535 ) ( 65535 1120 65535 ) ( -65535 1120 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 90 1 1 - ( 63787 -65534 -15058 ) ( 63787 65534 -15058 ) ( -63369 -65534 16730 ) fstng_2 0 0 0 1 1 - } - { //brush 5 - ( 2176 65535 65535 ) ( 2176 -65535 65535 ) ( 2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1120 65535 ) ( -65535 1120 65535 ) ( -65535 1120 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 0 1 1 - } - { //brush 6 - ( 2080 65535 65535 ) ( 2080 -65535 65535 ) ( 2080 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2208 -65535 65535 ) ( 2208 65535 65535 ) ( 2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 928 65535 ) ( 65535 928 65535 ) ( -65535 928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 1184 65535 ) ( -65535 1184 65535 ) ( -65535 1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 360 ) ( 65535 65535 360 ) ( -65535 -65535 360 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "64 -1056 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "33" - "targetname" "r_p_lite" - "origin" "2544 1056 512" -} -{ - "classname" "trigger_multiple" - "sounds" "0" - "wait" "0" - "delay" "0" - "team_no" "1" - "target" "r_guard" - "netname" "r_beam_trig" - "style" "32" - { //brush 0 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 2 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 3 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 4 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 5 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 6 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) fstng_0 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) fstng_0 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 7 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 8 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 9 - ( 2513 65535 65535 ) ( 2513 -65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 0 1 1 - ( 2516 -65535 65535 ) ( 2516 65535 65535 ) ( 2516 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 10 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) trigger 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 - } - { //brush 11 - ( 2508 65535 65535 ) ( 2508 -65535 65535 ) ( 2508 65535 -65535 ) trigger 0 0 0 1 1 - ( 2511 -65535 65535 ) ( 2511 65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 12 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) trigger 0 0 180 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "i_t_g" - "noise" "weapons/lhit.wav" - "health" "-500" - "deathtype" " died\n" - "targetname" "r_guard" - "goal_effects" "1" - "group_no" "40" - "netname" "b_kill" - "origin" "2464 1056 449" -} -{ - "classname" "i_t_g" - "n_b" " deactivated reds lasers.\n" - "style" "33" - "targetname" "r_start" - "activate_goal_no" "186" - "b_b" "Reds Lasers are Down!\n" - "g_e" "3" - "noise" "misc/power.wav" - "remove_group_no" "40" - "wait" "20" - "message" "You have deactivated enemy Lasers!\n" - "netname" "r_power_off" - "target" "r_p_lite" - "origin" "2432 1056 449" -} -{ - "classname" "i_t_g" - "b_o" "Our lasers are back up!\n" - "b_t" "Enemy lasers are back up!\n" - "style" "33" - "restore_group_no" "40" - "delay_time" "20" - "goal_no" "186" - "b_b" "Reds Lasers are Restored!" - "wait" "0" - "netname" "r_power_on" - "target" "r_p_lite" - "origin" "2400 1056 449" -} -{ - "classname" "func_door" - "angle" "270" - "wait" "20" - "lip" "-8" - "dmg" "1000" - "targetname" "r_start" - "speed" "10000" - "sounds" "0" - { //brush 0 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) *lavakell5 0 0 0 1 1 - } - { //brush 1 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) *lavakell5 0 0 0 1 1 - } - { //brush 2 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) *lavakell5 0 0 0 1 1 - } - { //brush 3 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) *lavakell5 0 0 0 1 1 - } - { //brush 4 - ( 2511 65535 65535 ) ( 2511 -65535 65535 ) ( 2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( 2513 -65535 65535 ) ( 2513 65535 65535 ) ( 2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 960 65535 ) ( 65535 960 65535 ) ( -65535 960 -65535 ) trigger 0 0 0 1 1 - ( 65535 1152 65535 ) ( -65535 1152 65535 ) ( -65535 1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) *lavakell5 0 0 0 1 1 - } -} -{ - "classname" "trigger_multiple" - "sounds" "4" - "wait" "5" - "message" "Laser deactivation switch\nPrevent of enemy usage!\n" - "style" "32" - "delay" "0" - "team_no" "2" - { //brush 0 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "trigger_multiple" - "sounds" "4" - "wait" "5" - "message" "Laser deactivation switch\nPress it!\n" - "style" "32" - "delay" "0" - "team_no" "1" - { //brush 0 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) trigger 0 0 0 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 -520 65535 ) ( 65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -512 65535 ) ( -65535 -512 65535 ) ( -65535 -512 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) trigger 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "func_button" - "angle" "270" - "delay" "0" - "lip" "-2" - "team_no" "1" - "targetname" "red_button" - "wait" "20" - "style" "36" - "target" "r_start" - { //brush 0 - ( 2384 65535 65535 ) ( 2384 -65535 65535 ) ( 2384 65535 -65535 ) fstng_0 0 0 0 1 1 - ( 2416 -65535 65535 ) ( 2416 65535 65535 ) ( 2416 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -528 65535 ) ( 65535 -528 65535 ) ( -65535 -528 -65535 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 -520 65535 ) ( -65535 -520 65535 ) ( -65535 -520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_0 0 0 0 1 1 - } -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "1024 880 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "896 880 512" -} -{ - "classname" "info_player_teamspawn" - "netname" "team2_spawn" - "team_no" "2" - "origin" "800 960 514" -} -{ - "classname" "info_player_teamspawn" - "netname" "team2_spawn" - "team_no" "2" - "origin" "800 1088 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "1120 1088 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "1120 960 512" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "1056 1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "1096 1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "1136 1184 456" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "864 1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "824 1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "784 1184 456" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2272 -736 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2272 -608 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2208 -512 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2080 -512 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "1968 -496 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "1944 -536 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "1920 -576 504" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2208 -832 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team2_spawn" - "team_no" "2" - "origin" "2080 -832 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "1968 -848 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "2" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team2_armor" - "goal_activation" "1" - "skin" "2" - "origin" "1944 -808 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "2" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team2_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "1920 -768 504" -} -{ - "classname" "info_tfdetect" - "hook_out" "1" - "impulse" "4" - "b_n" "Capture the emeny flag. See the frozen.txt for detail.\n" - "b_t" "\nFrozen Fire\n\n\nSELECT TEAM\n“‘ BLUE\n”‘ RED \n" - "display_item_status1" "1" - "display_item_status2" "2" - "team_str_home" "Your Flag: Base." - "team_str_carried" "Your Flag: Carried by" - "team_str_moved" "Your Flag: Down." - "non_team_str_home" "Enemy Flag: Base." - "non_team_str_carried" "Enemy Flag: Carried by" - "non_team_str_moved" "Enemy Flag: Down." - "origin" "0 0 576" -} -{ - "classname" "info_player_start" - "origin" "0 0 504" -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "1" - { //brush 0 - ( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) door 0 -4 0 1 1 - ( -1784 -65535 65535 ) ( -1784 65535 65535 ) ( -1784 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll01 0 0 0 1 1 - } - { //brush 1 - ( -1784 65535 65535 ) ( -1784 -65535 65535 ) ( -1784 65535 -65535 ) door 0 -4 0 1 1 - ( -1776 -65535 65535 ) ( -1776 65535 65535 ) ( -1776 65535 -65535 ) door 0 -4 0 1 1 - ( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 752 65535 ) ( -65535 752 65535 ) ( -65535 752 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 480 ) ( 65535 65535 480 ) ( -65535 -65535 480 ) fstng_2 0 0 0 1 1 - ( 65535 65535 592 ) ( 65535 -65535 592 ) ( -65535 -65535 592 ) stnwll02 0 0 0 1 1 - } -} -{ - "classname" "func_door" - "angle" "-1" - "speed" "600" - "sounds" "2" - "wait" "1" - "lip" "0" - "dmg" "0" - "health" "0" - "team_no" "1" - { //brush 0 - ( -1232 65535 65535 ) ( -1232 -65535 65535 ) ( -1232 65535 -65535 ) door 0 12 0 1 1 - ( -1224 -65535 65535 ) ( -1224 65535 65535 ) ( -1224 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll02 0 0 0 1 1 - } - { //brush 1 - ( -1224 65535 65535 ) ( -1224 -65535 65535 ) ( -1224 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -1216 -65535 65535 ) ( -1216 65535 65535 ) ( -1216 65535 -65535 ) door 0 12 0 1 1 - ( -65535 -1536 65535 ) ( 65535 -1536 65535 ) ( -65535 -1536 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -1376 65535 ) ( -65535 -1376 65535 ) ( -65535 -1376 -65535 ) stnwll01 0 0 0 1 1 - ( 65535 -65535 432 ) ( 65535 65535 432 ) ( -65535 -65535 432 ) fstng_2 0 0 0 1 1 - ( 65535 65535 544 ) ( 65535 -65535 544 ) ( -65535 -65535 544 ) stnwll01 0 0 0 1 1 - } -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1120 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-832 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-768 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-480 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-416 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1120 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-832 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-768 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-480 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-416 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-128 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-128 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-1920 -1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-1408 -1056 736" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1904 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1904 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1128 0 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-2208 456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1984 456 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-2208 888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1984 888 592" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-744 -944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-744 -1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1176 -944 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1024 -1456 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 208 368" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 304 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1184 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1184 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-640 0 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-384 384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "-384 -384 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-992 328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "350" - "style" "0" - "_color" "1 1 0.7" - "origin" "-992 -328 400" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 -128 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 -400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 400 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1024 -672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1696 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 0.8" - "origin" "-1360 672 608" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1264 440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 0 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 416 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 208 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2192 -104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2192 104 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2400 -104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2400 104 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2064 0 384" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -1280 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -832 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -384 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -608 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2472 -160 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1808 -568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 -568 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1808 -1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1488 -1544 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "650" - "style" "0" - "origin" "0 0 704" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 -832 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 -576 192" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1184 -912 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "280" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1184 -1200 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2144 -672 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2144 -1440 576" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2400 520 480" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 1 0.7" - "origin" "-1696 584 432" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1904 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1776 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1648 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1520 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1392 -700 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1392 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1520 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1648 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1776 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "150" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1904 -1412 280" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1392 -1056 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-1176 -1168 544" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2528 0 512" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "0" - "_color" "1 1 0.7" - "origin" "-2272 0 336" -} -{ - "classname" "light" - "angle" "-2" - "light" "220" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2784 128 360" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "1 0.6 0.8" - "origin" "-2400 208 480" -} -{ - "classname" "func_plat" - "angle" "-2" - "height" "160" - "speed" "50" - { //brush 0 - ( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 0 1 1 - ( 63369 -65534 16730 ) ( 63369 65534 16730 ) ( -63787 -65534 -15058 ) fstng_2 0 0 0 1 1 - } - { //brush 1 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - } - { //brush 2 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -1120 65535 ) ( -65535 -1120 65535 ) ( -65535 -1120 -65535 ) fstng_0 0 0 0 1 1 - ( 65535 -65535 192 ) ( 65535 65535 192 ) ( -65535 -65535 192 ) stonesnow 0 0 0 1 1 - ( 65535 65535 352 ) ( 65535 -65535 352 ) ( -65535 -65535 352 ) stnwll05 0 0 90 1 1 - } - { //brush 3 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -960 65535 ) ( 65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_2 0 0 180 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) fstng_2 0 0 90 1 1 - } - { //brush 4 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -65535 -992 65535 ) ( 65535 -992 65535 ) ( -65535 -992 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) fstng_2 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 90 1 1 - ( 63369 -65534 16730 ) ( 63369 65534 16730 ) ( -63787 -65534 -15058 ) fstng_2 0 0 0 1 1 - } - { //brush 5 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2176 -65535 65535 ) ( -2176 65535 65535 ) ( -2176 65535 -65535 ) fstng_2 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -992 65535 ) ( -65535 -992 65535 ) ( -65535 -992 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 352 ) ( 65535 65535 352 ) ( -65535 -65535 352 ) fstng_2 0 0 0 1 1 - ( 65535 65535 360 ) ( 65535 -65535 360 ) ( -65535 -65535 360 ) stnwll05 0 0 0 1 1 - } - { //brush 6 - ( -2208 65535 65535 ) ( -2208 -65535 65535 ) ( -2208 65535 -65535 ) stnwll05 0 0 0 1 1 - ( -2080 -65535 65535 ) ( -2080 65535 65535 ) ( -2080 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 -1184 65535 ) ( 65535 -1184 65535 ) ( -65535 -1184 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -928 65535 ) ( -65535 -928 65535 ) ( -65535 -928 -65535 ) stnwll05 0 0 0 1 1 - ( 65535 -65535 360 ) ( 65535 65535 360 ) ( -65535 -65535 360 ) fstng_0 0 0 0 1 1 - ( 65535 65535 368 ) ( 65535 -65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - } -} -{ - "classname" "light" - "angle" "-2" - "light" "300" - "style" "0" - "_color" "0.8 1 1" - "origin" "-64 1056 240" -} -{ - "classname" "light" - "angle" "-2" - "light" "200" - "style" "33" - "targetname" "b_p_lite" - "origin" "-2544 -1056 512" -} -{ - "classname" "i_t_g" - "noise" "weapons/lhit.wav" - "health" "-500" - "targetname" "b_guard" - "deathtype" " died\n" - "goal_effects" "1" - "group_no" "41" - "netname" "r_kill" - "origin" "-2464 -1056 449" -} -{ - "classname" "i_t_g" - "n_b" " deactivated blues lasers.\n" - "style" "33" - "targetname" "b_start" - "activate_goal_no" "187" - "b_b" "Blues Lasers are Down!\n" - "g_e" "3" - "noise" "misc/power.wav" - "remove_group_no" "41" - "wait" "20" - "message" "You have deactivated enemy Lasers!\n" - "netname" "b_power_off" - "target" "b_p_lite" - "origin" "-2432 -1056 449" -} -{ - "classname" "i_t_g" - "b_o" "Our lasers are back up!\n" - "b_t" "Enemy lasers are back up!\n" - "style" "33" - "restore_group_no" "41" - "delay_time" "20" - "goal_no" "187" - "b_b" "Blues Lasers are Restored!" - "wait" "0" - "netname" "b_power_on" - "target" "b_p_lite" - "origin" "-2400 -1056 449" -} -{ - "classname" "trigger_multiple" - "sounds" "0" - "wait" "0" - "delay" "0" - "team_no" "2" - "target" "b_guard" - "netname" "b_beam_trig" - "style" "32" - { //brush 0 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 449 ) ( 65535 65535 449 ) ( -65535 -65535 449 ) stnwll02 0 0 0 1 1 - ( 65535 65535 479 ) ( 65535 -65535 479 ) ( -65535 -65535 479 ) stnwll02 0 0 0 1 1 - } - { //brush 1 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 481 ) ( 65535 65535 481 ) ( -65535 -65535 481 ) stnwll02 0 0 0 1 1 - ( 65535 65535 511 ) ( 65535 -65535 511 ) ( -65535 -65535 511 ) stnwll02 0 0 0 1 1 - } - { //brush 2 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) trigger 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) trigger 0 0 0 1 1 - } - { //brush 3 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 385 ) ( 65535 65535 385 ) ( -65535 -65535 385 ) stnwll02 0 0 0 1 1 - ( 65535 65535 415 ) ( 65535 -65535 415 ) ( -65535 -65535 415 ) stnwll02 0 0 0 1 1 - } - { //brush 4 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) stnwll02 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 417 ) ( 65535 65535 417 ) ( -65535 -65535 417 ) stnwll02 0 0 0 1 1 - ( 65535 65535 447 ) ( 65535 -65535 447 ) ( -65535 -65535 447 ) stnwll02 0 0 0 1 1 - } - { //brush 5 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) trigger 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) trigger 0 0 0 1 1 - } - { //brush 6 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) fstng_0 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 513 ) ( 65535 65535 513 ) ( -65535 -65535 513 ) fstng_0 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 7 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) trigger 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) trigger 0 0 0 1 1 - } - { //brush 8 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) trigger 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) trigger 0 0 0 1 1 - } - { //brush 9 - ( -2516 65535 65535 ) ( -2516 -65535 65535 ) ( -2516 65535 -65535 ) trigger 0 0 0 1 1 - ( -2513 -65535 65535 ) ( -2513 65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 10 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 0 1 1 - ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 368 ) ( 65535 65535 368 ) ( -65535 -65535 368 ) fstng_2 0 0 0 1 1 - ( 65535 65535 383 ) ( 65535 -65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 - } - { //brush 11 - ( -2511 65535 65535 ) ( -2511 -65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 0 1 1 - ( -2508 -65535 65535 ) ( -2508 65535 65535 ) ( -2508 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) stnwll02 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 90 1 1 - ( 65535 65535 528 ) ( 65535 -65535 528 ) ( -65535 -65535 528 ) fstng_0 0 0 0 1 1 - } - { //brush 12 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) trigger 0 0 180 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) trigger 0 0 180 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) trigger 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "func_door" - "angle" "90" - "wait" "20" - "lip" "-8" - "dmg" "1000" - "targetname" "b_start" - "speed" "10000" - "sounds" "0" - { //brush 0 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 383 ) ( 65535 65535 383 ) ( -65535 -65535 383 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 385 ) ( 65535 -65535 385 ) ( -65535 -65535 385 ) *lavakell5 0 0 0 1 1 - } - { //brush 1 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 415 ) ( 65535 65535 415 ) ( -65535 -65535 415 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 417 ) ( 65535 -65535 417 ) ( -65535 -65535 417 ) *lavakell5 0 0 0 1 1 - } - { //brush 2 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 447 ) ( 65535 65535 447 ) ( -65535 -65535 447 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 449 ) ( 65535 -65535 449 ) ( -65535 -65535 449 ) *lavakell5 0 0 0 1 1 - } - { //brush 3 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 479 ) ( 65535 65535 479 ) ( -65535 -65535 479 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 481 ) ( 65535 -65535 481 ) ( -65535 -65535 481 ) *lavakell5 0 0 0 1 1 - } - { //brush 4 - ( -2513 65535 65535 ) ( -2513 -65535 65535 ) ( -2513 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -2511 -65535 65535 ) ( -2511 65535 65535 ) ( -2511 65535 -65535 ) *lavakell5 0 0 0 1 1 - ( -65535 -1152 65535 ) ( 65535 -1152 65535 ) ( -65535 -1152 -65535 ) trigger 0 0 0 1 1 - ( 65535 -960 65535 ) ( -65535 -960 65535 ) ( -65535 -960 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 511 ) ( 65535 65535 511 ) ( -65535 -65535 511 ) *lavakell5 0 0 0 1 1 - ( 65535 65535 513 ) ( 65535 -65535 513 ) ( -65535 -65535 513 ) *lavakell5 0 0 0 1 1 - } -} -{ - "classname" "trigger_multiple" - "sounds" "4" - "wait" "5" - "message" "Laser deactivation switch\nPrevent of enemy usage!\n" - "style" "32" - "delay" "0" - "team_no" "1" - { //brush 0 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) trigger 0 0 0 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) trigger 0 0 0 1 1 - ( 65535 520 65535 ) ( -65535 520 65535 ) ( -65535 520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 400 ) ( 65535 65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "trigger_multiple" - "sounds" "4" - "wait" "5" - "message" "Laser deactivation switch\nPress it!\n" - "style" "32" - "delay" "0" - "team_no" "2" - { //brush 0 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) trigger 0 0 0 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) trigger 0 0 0 1 1 - ( -65535 512 65535 ) ( 65535 512 65535 ) ( -65535 512 -65535 ) trigger 0 0 0 1 1 - ( 65535 520 65535 ) ( -65535 520 65535 ) ( -65535 520 -65535 ) trigger 0 0 0 1 1 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) trigger 0 0 0 1 1 - ( 65535 65535 400 ) ( 65535 -65535 400 ) ( -65535 -65535 400 ) trigger 0 0 0 1 1 - } -} -{ - "classname" "func_button" - "angle" "90" - "delay" "0" - "lip" "-2" - "team_no" "2" - "targetname" "blue_button" - "wait" "20" - "style" "36" - "target" "b_start" - { //brush 0 - ( -2416 65535 65535 ) ( -2416 -65535 65535 ) ( -2416 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -2384 -65535 65535 ) ( -2384 65535 65535 ) ( -2384 65535 -65535 ) fstng_0 0 0 0 1 1 - ( -65535 520 65535 ) ( 65535 520 65535 ) ( -65535 520 -65535 ) trigger 0 0 0 1 1 - ( 65535 528 65535 ) ( -65535 528 65535 ) ( -65535 528 -65535 ) skull1 32 0 0 0.500000 0.500000 - ( 65535 -65535 384 ) ( 65535 65535 384 ) ( -65535 -65535 384 ) fstng_0 0 0 0 1 1 - ( 65535 65535 416 ) ( 65535 -65535 416 ) ( -65535 -65535 416 ) fstng_0 0 0 0 1 1 - } -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-1024 -880 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-896 -880 512" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-800 -960 514" -} -{ - "classname" "info_player_teamspawn" - "angle" "180" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-800 -1088 512" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-1120 -1088 512" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-1120 -960 512" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-1056 -1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-1096 -1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-1136 -1184 456" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-864 -1232 456" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-824 -1208 448" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-784 -1184 456" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2272 736 560" -} -{ - "classname" "info_player_teamspawn" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2272 608 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2208 512 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "90" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2080 512 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-1968 496 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-1944 536 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-1920 576 504" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2208 832 560" -} -{ - "classname" "info_player_teamspawn" - "angle" "270" - "netname" "team1_spawn" - "team_no" "1" - "origin" "-2080 832 560" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "5" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "health" "25" - "origin" "-1968 848 504" -} -{ - "classname" "info_tfgoal" - "mdl" "progs/armor.mdl" - "team_no" "1" - "armorvalue" "200" - "goal_effects" "1" - "wait" "1" - "armortype" "0.8" - "noise" "items/armor1.wav" - "netname" "team1_armor" - "goal_activation" "1" - "skin" "2" - "origin" "-1944 808 496" -} -{ - "classname" "info_tfgoal" - "ammo_rockets" "20" - "ammo_cells" "100" - "mdl" "progs/backpack.mdl" - "team_no" "1" - "ammo_nails" "100" - "ammo_medikit" "50" - "goal_effects" "1" - "wait" "1" - "noise" "weapons/pkup.wav" - "netname" "team1_resupply" - "ammo_shells" "50" - "goal_activation" "1" - "no_grenades_1" "2" - "origin" "-1920 770 504" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "208 0 224" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "-208 0 224" -} -{ - "classname" "light" - "angle" "-2" - "light" "250" - "style" "0" - "_color" "0.8 1 1" - "origin" "0 0 224" -} -{ - "classname" "light" - "angle" "-2" - "light" "450" - "style" "0" - "origin" "0 -288 384" -} -{ - "classname" "light" - "angle" "-2" - "light" "450" - "style" "0" - "origin" "0 288 384" -} -{ - "classname" "item_tfgoal" - "angle" "145" - "netname" "blue flag" - "mdl" "progs/tf_stan.mdl" - "skin" "1" - "goal_no" "1" - "g_a" "693" - "g_e" "1" - "goal_result" "18" - "team_no" "2" - "owned_by" "1" - "items" "131072" - "pausetime" "30" - "n_b" " StolE ThE ΒΜΥΕ FlaG!\n" - "message" "YoU HavE ThE EnemY FlaG!\nΥΞ ΜΙΛΕ ΘΕΜΜ‘\n" - "d_n_t" " ΜοσΤ YouR FLAG‘\n" - "d_n_n" " ΜοσΤ ΤθΕ BLUE FLAG‘\n" - "b_n" "YouR FlaG HaS BeeN StoleN!!\nΗεΤ ΕΝ‘\n" - "b_t" "Ωου ΤεαΝ ΣτομΕ ΤθΕ EnemieS FlaG‘\n" - "noise" "flagtaken.wav" - "noise3" "Your flag was returned to base!" - "noise4" "The enemy flag was returned to base!" - "origin" "-2560 -1056 392" -} -{ - "classname" "i_t_g" - "netname" "blue capture" - "axhitme" "2" - "count" "10" - "frags" "10" - "noise" "items/cap2.wav" - "message" "Ωου ΤεαΝ ΟχεΣ ΩοΥ ΒιΗ‘\nΊ©\n" - "g_a" "1" - "g_e" "2" - "items_allowed" "2" - "team_no" "1" - "b_t" "€ƒƒƒƒ‚\n“’ ΖςαηΣ Ζο Ωα‘‘\n€ƒƒƒ‚\n" - "b_n" "Ωου FLAG ΧαΣ CAPTURED‘\nΊ―\n" - "origin" "-2560 224 384" -} -{ - "classname" "i_t_g" - "netname" "red capture" - "g_a" "1" - "team_no" "2" - "items_allowed" "1" - "g_e" "2" - "axhitme" "1" - "count" "10" - "frags" "10" - "message" "Ωου ΤεαΝ ΟχεΣ ΩοΥ ΒιΗ‘\nΊ©\n" - "b_t" "€ƒƒƒƒ‚\n“’ ΖςαηΣ Ζο Ωα‘‘\n€ƒƒƒ‚\n" - "b_n" "Ωου FLAG ΧαΣ CAPTURED‘\nΊ―\n" - "noise" "items/cap2.wav" - "origin" "2560 -224 384" -} -{ - "classname" "item_tfgoal" - "angle" "315" - "netname" "red flag" - "mdl" "progs/tf_stan.mdl" - "skin" "2" - "goal_no" "2" - "g_a" "693" - "g_e" "1" - "goal_result" "18" - "team_no" "1" - "owned_by" "2" - "items" "262144" - "pausetime" "30" - "n_b" " StolE ThE ΕΔ FlaG!\n" - "message" "YoU HavE ThE EnemY FlaG!\nΥΞ ΜΙΛΕ ΘΕΜΜ‘\n" - "d_n_t" " ΜοσΤ YouR FLAG‘\n" - "d_n_n" " ΜοσΤ ΤθΕ RED FLAG‘\n" - "b_n" "YouR FlaG HaS BeeN StoleN!!\nΗεΤ ΕΝ‘\n" - "b_t" "Ωου ΤεαΝ ΣτομΕ ΤθΕ EnemieS FlaG‘\n" - "noise" "flagtaken.wav" - "noise3" "Your flag was returned to base!" - "noise4" "The enemy flag was returned to base!" - "origin" "2560 1056 392" -} -//total of 1557 brushes diff --git a/q3f_openfire2b working copy.map b/q3f_openfire2b working copy.map deleted file mode 100644 index 9aa7dfa8..00000000 --- a/q3f_openfire2b working copy.map +++ /dev/null @@ -1,197 +0,0 @@ -// entity 102 -{ -"classname" "target_kill" -"targetname" "kill" -"origin" "2433 1150 239" -"checkstate" "t1=inactive" -} -// entity 103 -{ -"allowteams" "red" -"classname" "trigger_multiple" -"target" "kill" -// brush 0 -{ -( 2483 -65535 65535 ) ( 2483 65535 65535 ) ( 2483 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 2477 65535 65535 ) ( 2477 -65535 65535 ) ( 2477 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 1280 65535 ) ( -65535 1280 65535 ) ( -65535 1280 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -65535 1024 65535 ) ( 65535 1024 65535 ) ( -65535 1024 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -65535 128 ) ( 65535 65535 128 ) ( -65535 -65535 128 ) e2u3/floor1_2 0 0 0 1 1 -} -} -// entity 104 -{ -"targetname" "t1" -"lip" "0" -"wait" "30" -"classname" "func_door" -"angle" "270" -"speed" "9999" -} -// entity 105 -{ -"allowteams" "red" -"activetarget" "t1" -"wait" "30" -"angle" "270" -"classname" "func_button" -// brush 0 -{ -( 2351 -65535 65535 ) ( 2351 65535 65535 ) ( 2351 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 2320 65535 65535 ) ( 2320 -65535 65535 ) ( 2320 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -496 65535 ) ( -65535 -496 65535 ) ( -65535 -496 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -65535 -504 65535 ) ( 65535 -504 65535 ) ( -65535 -504 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -65535 144 ) ( 65535 65535 144 ) ( -65535 -65535 144 ) e2u3/floor1_2 0 0 0 1 1 -} -} -// entity 106 -{ -"targetname" "t1" -"lip" "0" -"wait" "30" -"angle" "90" -"classname" "func_door" -"speed" "9999" -} -// entity 107 -{ -"targetname" "t1" -"lip" "0" -"wait" "30" -"speed" "9999" -"angle" "270" -"classname" "func_door" -} -// entity 108 -{ -"speed" "9999" -"classname" "func_door" -"angle" "90" -"wait" "30" -"lip" "0" -"targetname" "t1" -} -// entity 109 -{ -"classname" "func_door" -"angle" "270" -"speed" "9999" -"wait" "30" -"lip" "0" -"targetname" "t1" -} -// entity 110 -{ -"targetname" "t1" -"lip" "0" -"wait" "30" -"angle" "90" -"classname" "func_door" -"speed" "9999" -} -// entity 111 -{ -"checkstate" "t2=inactive" -"origin" "-2433 -1150 239" -"targetname" "kill2" -"classname" "target_kill" -} -// entity 112 -{ -"target" "kill2" -"classname" "trigger_multiple" -"allowteams" "blue" -// brush 0 -{ -( -2477 -65535 65535 ) ( -2477 65535 65535 ) ( -2477 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -2483 65535 65535 ) ( -2483 -65535 65535 ) ( -2483 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -1024 65535 ) ( -65535 -1024 65535 ) ( -65535 -1024 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -65535 -1280 65535 ) ( 65535 -1280 65535 ) ( -65535 -1280 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 65535 336 ) ( 65535 -65535 336 ) ( -65535 -65535 336 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -65535 128 ) ( 65535 65535 128 ) ( -65535 -65535 128 ) e2u3/floor1_2 0 0 0 1 1 -} -} - - -// entity 113 -{ -"speed" "9999" -"angle" "270" -"classname" "func_door" -"wait" "30" -"lip" "0" -"targetname" "t2" -} -// entity 114 -{ -"classname" "func_button" -"angle" "90" -"wait" "30" -"activetarget" "t2" -"allowteams" "blue" -// brush 0 -{ -( -2320 -65535 65535 ) ( -2320 65535 65535 ) ( -2320 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -2351 65535 65535 ) ( -2351 -65535 65535 ) ( -2351 65535 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 504 65535 ) ( -65535 504 65535 ) ( -65535 504 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( -65535 496 65535 ) ( 65535 496 65535 ) ( -65535 496 -65535 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 65535 176 ) ( 65535 -65535 176 ) ( -65535 -65535 176 ) e2u3/floor1_2 0 0 0 1 1 -( 65535 -65535 144 ) ( 65535 65535 144 ) ( -65535 -65535 144 ) e2u3/floor1_2 0 0 0 1 1 -} -} -// entity 115 -{ -"speed" "9999" -"classname" "func_door" -"angle" "90" -"wait" "30" -"lip" "0" -"targetname" "t2" -} -// entity 116 -{ -"classname" "func_door" -"angle" "270" -"speed" "9999" -"wait" "30" -"lip" "0" -"targetname" "t2" -} -// entity 117 -{ -"targetname" "t2" -"lip" "0" -"wait" "30" -"angle" "90" -"classname" "func_door" -"speed" "9999" -} -// entity 118 -{ -"targetname" "t2" -"lip" "0" -"wait" "30" -"speed" "9999" -"angle" "270" -"classname" "func_door" -} -// entity 119 -{ -"speed" "9999" -"classname" "func_door" -"angle" "90" -"wait" "30" -"lip" "0" -"targetname" "t2" -} - -// entity 207 -{ -"origin" "0 -320 -192" -"noise" "sound/world/curnt2.wav" -"classname" "target_speaker" -"spawnflags" "1" -} - diff --git a/stag3.map b/stag3.map deleted file mode 100644 index 0f3e06d3..00000000 --- a/stag3.map +++ /dev/null @@ -1,1044 +0,0 @@ -// Game: Quake -// Format: Standard -// entity 0 -{ -"message" "stag3\nby lordy with help and stuff from dp!\nbased on the q3f level q3f_2stag2" -"classname" "worldspawn" -"wad" "/home/danni/Games/QuakeDev/wads/stag.wad;../wads/oppose2.wad" -"_sunlight" "0" -} - -// entity 67 -{ -"origin" "-3504 1007 -3100" -"g_a" "4789" -"owned_by" "1" -"netname" "Blue Flag" -"message" "You have their flag.\nTake it home!\n" -"noise" "ogre/ogwake.wav" -"n_b" " picked up blue's flag.\n" -"items" "131072" -"noise3" "Your flag returned.\n" -"goal_no" "1" -"noise4" "Their flag returned.\n" -"delay" "60" -"pausetime" "60" -"team_no" "2" -"skin" "1" -"mdl" "progs/tf_flag.mdl" -"angle" "135" -"classname" "item_tfgoal" -"team_broadcast" "Your team got their flag.\n" -"non_team_broadcast" "Your flag has been taken!\n" -"d_n_n" " dropped blue's flag.\n" -} -// entity 68 -{ -"origin" "-272 935 -3184" -"classname" "info_player_start" -} -// entity 69 -{ -"origin" "-208 1280 -3168" -"impulse" "196" -"display_item_status1" "1" -"display_item_status2" "2" -"team_str_home" "Your flag is in your base.\n" -"team_str_moved" "Your flag is lying around." -"team_str_carried" "Your flag is being carried by\n" -"non_team_str_home" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is in their base.\n" -"non_team_str_moved" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is lying around." -"non_team_str_carried" "The οΏ½οΏ½οΏ½οΏ½οΏ½ flag is being carried by\n" -"hook_out" "1" -"non_team_broadcast" "Get the enemy flag and take it to your tower!\n" -"classname" "info_tfdetect" -} - -// entity 71 -{ -"origin" "-2656 1040 -3296" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} - -// entity 82 -{ -"origin" "-784 1040 -3040" -"frags" "10" -"b_o" "Your flag was captured.\n" -"count" "10" -"b_t" "Your team captured their flag.\n" -"g_e" "19" -"n_b" " captured red's flag.\n" -"noise" "items/cap1.wav" -"axhitme" "2" -"message" "You captured their flag.\n" -"items_allowed" "2" -"owned_by" "2" -"target" "cap1" -"g_a" "1" -"classname" "info_tfgoal" -} -// entity 83 -{ -"origin" "1624 2327 -3400" -"light" "150" -"classname" "light" -} - -// entity 114 -{ -"origin" "3328 1103 -3100" -"g_a" "4789" -"owned_by" "2" -"message" "You have their flag.\nTake it home!\n" -"netname" "Red Flag" -"noise" "ogre/ogwake.wav" -"goal_no" "2" -"noise3" "Your flag returned.\n" -"items" "262144" -"delay" "60" -"noise4" "Their flag returned.\n" -"team_no" "1" -"pausetime" "60" -"skin" "2" -"mdl" "progs/tf_flag.mdl" -"angle" "315" -"classname" "item_tfgoal" -"team_broadcast" "Your team got their flag.\n" -"non_team_broadcast" "Your flag was taken.\n" -"n_b" " picked up red's flag.\n" -"d_n_n" " dropped red's flag.\n" -} - -// entity 131 -{ -"origin" "608 1056 -3040" -"frags" "10" -"b_o" "Your flag was captured.\n" -"count" "10" -"b_t" "Your team captured their flag.\n" -"g_e" "19" -"n_b" " captured blue's flag.\n" -"noise" "items/cap2.wav" -"axhitme" "1" -"message" "You captured their flag.\n" -"items_allowed" "1" -"owned_by" "1" -"target" "cap2" -"g_a" "1" -"classname" "info_tfgoal" -"_tb_group" "430" -} -// entity 132 -{ -"origin" "1504 879 -2960" -"light" "200" -"classname" "light" -} -// entity 133 -{ -"origin" "-1680 1231 -2960" -"light" "200" -"classname" "light" -} -// entity 134 -{ -"origin" "800 607 -3200" -"light" "250" -"classname" "light" -} -// entity 135 -{ -"origin" "1152 639 -3200" -"light" "250" -"classname" "light" -} -// entity 136 -{ -"origin" "-1328 1473 -3200" -"light" "250" -"classname" "light" -"angle" "180" -} -// entity 137 -{ -"origin" "-976 1505 -3200" -"light" "250" -"classname" "light" -"angle" "180" -} -// entity 138 -{ -"origin" "1648 927 -3216" -"light" "500" -"classname" "light" -} -// entity 139 -{ -"origin" "1616 463 -3216" -"light" "500" -"classname" "light" -} -// entity 140 -{ -"origin" "1616 847 -3088" -"light" "500" -"classname" "light" -} -// entity 141 -{ -"team_no" "2" -"dmg" "500" -"lip" "0" -"wait" "1" -"sounds" "1" -"speed" "200" -"angle" "270" -"classname" "func_door" -// brush 0 -{ -( 2288 -63119 65535 ) ( 2288 67951 65535 ) ( 2288 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 2272 67951 65535 ) ( 2272 -63119 65535 ) ( 2272 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 1240 65535 ) ( -65711 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 -( -65711 1168 65535 ) ( 65359 1168 65535 ) ( -65711 1168 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 -} -} -// entity 142 -{ -"team_no" "2" -"dmg" "500" -"lip" "0" -"wait" "1" -"sounds" "1" -"speed" "200" -"angle" "90" -"classname" "func_door" -// brush 0 -{ -( 2288 -63119 65535 ) ( 2288 67951 65535 ) ( 2288 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 2272 67951 65535 ) ( 2272 -63119 65535 ) ( 2272 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 1312 65535 ) ( -65711 1312 65535 ) ( -65711 1312 -65535 ) adoor03_3 -0 -0 -0 1 1 -( -65711 1240 65535 ) ( 65359 1240 65535 ) ( -65711 1240 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 67951 -3200 ) ( 65359 -63119 -3200 ) ( -65711 -63119 -3200 ) adoor03_3 -0 -0 -0 1 1 -( 65359 -63119 -3328 ) ( 65359 67951 -3328 ) ( -65711 -63119 -3328 ) adoor03_3 -0 -0 -0 1 1 -} -} -// entity 143 -{ -"origin" "2384 1119 -3216" -"light" "500" -"classname" "light" -} -// entity 144 -{ -"origin" "2456 639 -3280" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 145 -{ -"origin" "2456 719 -3280" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 146 -{ -"origin" "2328 639 -3280" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 147 -{ -"origin" "2328 720 -3280" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 148 -{ -"origin" "2480 1008 -3290" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 149 -{ -"origin" "2480 1072 -3290" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 150 -{ -"origin" "2480 1136 -3290" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 151 -{ -"origin" "2304 1008 -3290" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 152 -{ -"origin" "2304 1072 -3290" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 153 -{ -"origin" "2304 1136 -3290" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 154 -{ -"origin" "-64 1025 -2976" -"light" "1000" -"classname" "light" -"angle" "180" -} -// entity 155 -{ -"origin" "1120 239 -2896" -"light" "350" -"classname" "light" -} -// entity 156 -{ -"team_no" "2" -"health" "0" -"dmg" "500" -"lip" "0" -"wait" "1" -"sounds" "1" -"speed" "200" -"angle" "180" -"classname" "func_door" -// brush 0 -{ -( 1128 -63119 65535 ) ( 1128 67951 65535 ) ( 1128 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 1056 67951 65535 ) ( 1056 -63119 65535 ) ( 1056 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 446 65535 ) ( -65711 446 65535 ) ( -65711 446 -65535 ) adoor03_3 -0 -0 -0 1 1 -( -65711 430 65535 ) ( 65359 430 65535 ) ( -65711 430 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 67951 -2960 ) ( 65359 -63119 -2960 ) ( -65711 -63119 -2960 ) adoor03_3 -0 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) adoor03_3 -0 -0 -0 1 1 -} -} -// entity 157 -{ -"team_no" "2" -"health" "0" -"dmg" "500" -"lip" "0" -"wait" "1" -"sounds" "1" -"speed" "200" -"classname" "func_door" -// brush 0 -{ -( 1200 -63119 65535 ) ( 1200 67951 65535 ) ( 1200 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 1128 67951 65535 ) ( 1128 -63119 65535 ) ( 1128 67951 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 446 65535 ) ( -65711 446 65535 ) ( -65711 446 -65535 ) adoor03_3 -0 -0 -0 1 1 -( -65711 430 65535 ) ( 65359 430 65535 ) ( -65711 430 -65535 ) adoor03_3 -0 -0 -0 1 1 -( 65359 67951 -2960 ) ( 65359 -63119 -2960 ) ( -65711 -63119 -2960 ) adoor03_3 -0 -0 -0 1 1 -( 65359 -63119 -3072 ) ( 65359 67951 -3072 ) ( -65711 -63119 -3072 ) adoor03_3 -0 -0 -0 1 1 -} -} -// entity 158 -{ -"origin" "944 240 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 159 -{ -"origin" "944 176 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 160 -{ -"origin" "944 112 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 161 -{ -"origin" "1296 240 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 162 -{ -"origin" "1296 176 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 163 -{ -"origin" "1296 112 -3024" -"noise" "edge/backpack.wav" -"wait" "2" -"ammo_medikit" "100" -"ammo_cells" "200" -"ammo_rockets" "50" -"ammo_nails" "100" -"ammo_shells" "100" -"health" "50" -"armorvalue" "100" -"goal_effects" "1" -"goal_activation" "1" -"mdl" "progs/backpack.mdl" -"netname" "blue_pak1" -"armortype" "0.8" -"classname" "info_tfgoal" -} -// entity 164 -{ -"origin" "1232 -177 -2960" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 165 -{ -"origin" "1216 -241 -2960" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 166 -{ -"origin" "1136 -241 -2960" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 167 -{ -"origin" "1056 -241 -2960" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 168 -{ -"origin" "976 -241 -2960" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 169 -{ -"origin" "1008 -177 -2960" -"team_no" "2" -"classname" "info_player_teamspawn" -} -// entity 170 -{ -"origin" "1120 -161 -2896" -"light" "350" -"classname" "light" -} -// entity 171 -{ -"origin" "-992 1041 -3200" -"light" "250" -"classname" "light" -"angle" "180" -} -// entity 172 -{ -"origin" "816 1073 -3200" -"light" "250" -"classname" "light" -"angle" "180" -} -// entity 173 -{ -"origin" "1984 927 -3088" -"light" "500" -"classname" "light" -} -// entity 174 -{ -"origin" "1648 927 -3088" -"light" "500" -"classname" "light" -} -// entity 175 -{ -"origin" "2256 1503 -3216" -"light" "500" -"classname" "light" -} -// entity 176 -{ -"origin" "2480 1503 -2896" -"light" "500" -"classname" "light" -} -// entity 177 -{ -"origin" "2480 927 -2912" -"light" "500" -"classname" "light" -} -// entity 178 -{ -"height" "154" -"classname" "func_plat" -// brush 0 -{ -( 1744 -63119 65535 ) ( 1744 67951 65535 ) ( 1744 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 -( 1632 67951 65535 ) ( 1632 -63119 65535 ) ( 1632 67951 -65535 ) sfloor4_6 -0 -0 -0 1 1 -( 65359 720 65535 ) ( -65711 720 65535 ) ( -65711 720 -65535 ) sfloor4_6 32 -0 -0 1 1 -( -65711 592 65535 ) ( 65359 592 65535 ) ( -65711 592 -65535 ) sfloor4_6 32 -0 -0 1 1 -( 65359 67951 -3184 ) ( 65359 -63119 -3184 ) ( -65711 -63119 -3184 ) sfloor4_6 32 -0 -0 1 1 -( 65359 -63119 -3344 ) ( 65359 67951 -3344 ) ( -65711 -63119 -3344 ) sfloor4_6 32 -0 -0 1 1 -} -} -// entity 179 -{ -"origin" "1728 655 -3088" -"light" "500" -"classname" "light" -} -// entity 180 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "lava grate" -"_tb_id" "431" -// brush 0 -{ -( -2416 -65535 65535 ) ( -2416 65535 65535 ) ( -2416 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -2432 65535 65535 ) ( -2432 -65535 65535 ) ( -2432 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65071 1200 65535 ) ( -65999 1200 65535 ) ( -65999 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65999 592 65535 ) ( 65071 592 65535 ) ( -65999 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65071 65535 -3328 ) ( 65071 -65535 -3328 ) ( -65999 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65071 -65535 -3344 ) ( 65071 65535 -3344 ) ( -65999 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 1 -{ -( -2352 -65535 65535 ) ( -2352 65535 65535 ) ( -2352 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -2368 65535 65535 ) ( -2368 -65535 65535 ) ( -2368 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65135 1200 65535 ) ( -65935 1200 65535 ) ( -65935 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65935 592 65535 ) ( 65135 592 65535 ) ( -65935 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65135 65535 -3328 ) ( 65135 -65535 -3328 ) ( -65935 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65135 -65535 -3344 ) ( 65135 65535 -3344 ) ( -65935 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 2 -{ -( -2288 -65535 65535 ) ( -2288 65535 65535 ) ( -2288 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -2304 65535 65535 ) ( -2304 -65535 65535 ) ( -2304 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65199 1200 65535 ) ( -65871 1200 65535 ) ( -65871 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65871 592 65535 ) ( 65199 592 65535 ) ( -65871 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65199 65535 -3328 ) ( 65199 -65535 -3328 ) ( -65871 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65199 -65535 -3344 ) ( 65199 65535 -3344 ) ( -65871 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 3 -{ -( -2224 -65535 65535 ) ( -2224 65535 65535 ) ( -2224 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -2240 65535 65535 ) ( -2240 -65535 65535 ) ( -2240 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65263 1200 65535 ) ( -65807 1200 65535 ) ( -65807 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65807 592 65535 ) ( 65263 592 65535 ) ( -65807 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65263 65535 -3328 ) ( 65263 -65535 -3328 ) ( -65807 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65263 -65535 -3344 ) ( 65263 65535 -3344 ) ( -65807 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 4 -{ -( -2160 -65535 65535 ) ( -2160 65535 65535 ) ( -2160 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -2176 65535 65535 ) ( -2176 -65535 65535 ) ( -2176 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65327 1200 65535 ) ( -65743 1200 65535 ) ( -65743 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65743 592 65535 ) ( 65327 592 65535 ) ( -65743 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65327 65535 -3328 ) ( 65327 -65535 -3328 ) ( -65743 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65327 -65535 -3344 ) ( 65327 65535 -3344 ) ( -65743 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 5 -{ -( -2096 -65535 65535 ) ( -2096 65535 65535 ) ( -2096 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -2112 65535 65535 ) ( -2112 -65535 65535 ) ( -2112 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65391 1200 65535 ) ( -65679 1200 65535 ) ( -65679 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65679 592 65535 ) ( 65391 592 65535 ) ( -65679 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65391 65535 -3328 ) ( 65391 -65535 -3328 ) ( -65679 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65391 -65535 -3344 ) ( 65391 65535 -3344 ) ( -65679 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 6 -{ -( -2032 -65535 65535 ) ( -2032 65535 65535 ) ( -2032 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -2048 65535 65535 ) ( -2048 -65535 65535 ) ( -2048 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65455 1200 65535 ) ( -65615 1200 65535 ) ( -65615 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65615 592 65535 ) ( 65455 592 65535 ) ( -65615 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65455 65535 -3328 ) ( 65455 -65535 -3328 ) ( -65615 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65455 -65535 -3344 ) ( 65455 65535 -3344 ) ( -65615 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 7 -{ -( -1968 -65535 65535 ) ( -1968 65535 65535 ) ( -1968 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -1984 65535 65535 ) ( -1984 -65535 65535 ) ( -1984 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65519 1200 65535 ) ( -65551 1200 65535 ) ( -65551 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65551 592 65535 ) ( 65519 592 65535 ) ( -65551 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65519 65535 -3328 ) ( 65519 -65535 -3328 ) ( -65551 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65519 -65535 -3344 ) ( 65519 65535 -3344 ) ( -65551 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 8 -{ -( -1904 -65535 65535 ) ( -1904 65535 65535 ) ( -1904 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -1920 65535 65535 ) ( -1920 -65535 65535 ) ( -1920 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65583 1200 65535 ) ( -65487 1200 65535 ) ( -65487 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65487 592 65535 ) ( 65583 592 65535 ) ( -65487 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65583 65535 -3328 ) ( 65583 -65535 -3328 ) ( -65487 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65583 -65535 -3344 ) ( 65583 65535 -3344 ) ( -65487 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 9 -{ -( -1840 -65535 65535 ) ( -1840 65535 65535 ) ( -1840 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -1856 65535 65535 ) ( -1856 -65535 65535 ) ( -1856 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65647 1200 65535 ) ( -65423 1200 65535 ) ( -65423 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65423 592 65535 ) ( 65647 592 65535 ) ( -65423 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65647 65535 -3328 ) ( 65647 -65535 -3328 ) ( -65423 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65647 -65535 -3344 ) ( 65647 65535 -3344 ) ( -65423 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 10 -{ -( -1776 -65535 65535 ) ( -1776 65535 65535 ) ( -1776 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -1792 65535 65535 ) ( -1792 -65535 65535 ) ( -1792 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65711 1200 65535 ) ( -65359 1200 65535 ) ( -65359 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65359 592 65535 ) ( 65711 592 65535 ) ( -65359 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65711 65535 -3328 ) ( 65711 -65535 -3328 ) ( -65359 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65711 -65535 -3344 ) ( 65711 65535 -3344 ) ( -65359 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 11 -{ -( -1712 -65535 65535 ) ( -1712 65535 65535 ) ( -1712 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( -1728 65535 65535 ) ( -1728 -65535 65535 ) ( -1728 65535 -65535 ) metal5_1 48 -0 -0 1 1 -( 65775 1200 65535 ) ( -65295 1200 65535 ) ( -65295 1200 -65535 ) metal5_1 -0 -48 -0 1 1 -( -65295 592 65535 ) ( 65775 592 65535 ) ( -65295 592 -65535 ) metal5_1 -0 -48 -0 1 1 -( 65775 65535 -3328 ) ( 65775 -65535 -3328 ) ( -65295 -65535 -3328 ) metal5_1 -0 -48 -0 1 1 -( 65775 -65535 -3344 ) ( 65775 65535 -3344 ) ( -65295 -65535 -3344 ) metal5_1 -0 -48 -0 1 1 -} -// brush 12 -{ -( -1664 592 -3336 ) ( -1664 640 -3328 ) ( -1664 640 -3336 ) clip -0 -0 -0 1 1 -( -2448 592 -3336 ) ( -2448 640 -3328 ) ( -2448 592 -3328 ) clip -0 -0 -0 1 1 -( -2448 1200 -3336 ) ( -2432 1200 -3328 ) ( -2448 1200 -3328 ) clip -0 -0 -0 1 1 -( -2448 592 -3336 ) ( -2432 592 -3328 ) ( -2432 592 -3336 ) clip -0 -0 -0 1 1 -( -2448 592 -3328 ) ( -2432 640 -3328 ) ( -2432 592 -3328 ) clip -0 -0 -0 1 1 -( -2448 592 -3336 ) ( -2432 640 -3336 ) ( -2448 640 -3336 ) clip -0 -0 -0 1 1 -} -// brush 13 -{ -( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) metal5_8 -16 -48 180 1 1 -( -2488 65535 65535 ) ( -2488 -65535 65535 ) ( -2488 65535 -65535 ) metal5_8 -16 -48 180 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) metal5_8 -16 -48 -0 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) metal5_8 -16 -48 -0 1 1 -( 65535 65535 -3464 ) ( 65535 -65535 -3464 ) ( -65535 -65535 -3464 ) metal5_8 -16 -48 -0 1 1 -( 65535 -65535 -3472 ) ( 65535 65535 -3472 ) ( -65535 -65535 -3472 ) metal5_8 -16 -48 -0 1 1 -} -// brush 14 -{ -( -1664 -65535 65535 ) ( -1664 65535 65535 ) ( -1664 65535 -65535 ) *lava1 -15 -0 -0 1 1 -( -2496 65535 65535 ) ( -2496 -65535 65535 ) ( -2496 65535 -65535 ) *lava1 -15 -0 -0 1 1 -( 65535 1200 65535 ) ( -65535 1200 65535 ) ( -65535 1200 -65535 ) *lava1 -15 -0 180 1 1 -( -65535 592 65535 ) ( 65535 592 65535 ) ( -65535 592 -65535 ) *lava1 -15 -0 180 1 1 -( 65535 65535 -3336 ) ( 65535 -65535 -3336 ) ( -65535 -65535 -3336 ) *lava1 -15 -0 180 1 1 -( 65535 -65535 -3464 ) ( 65535 65535 -3464 ) ( -65535 -65535 -3464 ) *lava1 -15 -0 180 1 1 -} -} -// entity 181 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "lava grate" -"_tb_id" "432" -// brush 0 -{ -( 2240 67647 65535 ) ( 2240 -63423 65535 ) ( 2240 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 2256 -63423 65535 ) ( 2256 67647 65535 ) ( 2256 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65247 912 65535 ) ( 65823 912 65535 ) ( 65823 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65823 1520 65535 ) ( -65247 1520 65535 ) ( 65823 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65247 -63423 -3328 ) ( -65247 67647 -3328 ) ( 65823 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65247 67647 -3344 ) ( -65247 -63423 -3344 ) ( 65823 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 1 -{ -( 2176 67647 65535 ) ( 2176 -63423 65535 ) ( 2176 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 2192 -63423 65535 ) ( 2192 67647 65535 ) ( 2192 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65311 912 65535 ) ( 65759 912 65535 ) ( 65759 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65759 1520 65535 ) ( -65311 1520 65535 ) ( 65759 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65311 -63423 -3328 ) ( -65311 67647 -3328 ) ( 65759 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65311 67647 -3344 ) ( -65311 -63423 -3344 ) ( 65759 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 2 -{ -( 2112 67647 65535 ) ( 2112 -63423 65535 ) ( 2112 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 2128 -63423 65535 ) ( 2128 67647 65535 ) ( 2128 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65375 912 65535 ) ( 65695 912 65535 ) ( 65695 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65695 1520 65535 ) ( -65375 1520 65535 ) ( 65695 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65375 -63423 -3328 ) ( -65375 67647 -3328 ) ( 65695 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65375 67647 -3344 ) ( -65375 -63423 -3344 ) ( 65695 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 3 -{ -( 2048 67647 65535 ) ( 2048 -63423 65535 ) ( 2048 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 2064 -63423 65535 ) ( 2064 67647 65535 ) ( 2064 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65439 912 65535 ) ( 65631 912 65535 ) ( 65631 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65631 1520 65535 ) ( -65439 1520 65535 ) ( 65631 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65439 -63423 -3328 ) ( -65439 67647 -3328 ) ( 65631 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65439 67647 -3344 ) ( -65439 -63423 -3344 ) ( 65631 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 4 -{ -( 1984 67647 65535 ) ( 1984 -63423 65535 ) ( 1984 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 2000 -63423 65535 ) ( 2000 67647 65535 ) ( 2000 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65503 912 65535 ) ( 65567 912 65535 ) ( 65567 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65567 1520 65535 ) ( -65503 1520 65535 ) ( 65567 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65503 -63423 -3328 ) ( -65503 67647 -3328 ) ( 65567 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65503 67647 -3344 ) ( -65503 -63423 -3344 ) ( 65567 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 5 -{ -( 1920 67647 65535 ) ( 1920 -63423 65535 ) ( 1920 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 1936 -63423 65535 ) ( 1936 67647 65535 ) ( 1936 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65567 912 65535 ) ( 65503 912 65535 ) ( 65503 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65503 1520 65535 ) ( -65567 1520 65535 ) ( 65503 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65567 -63423 -3328 ) ( -65567 67647 -3328 ) ( 65503 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65567 67647 -3344 ) ( -65567 -63423 -3344 ) ( 65503 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 6 -{ -( 1856 67647 65535 ) ( 1856 -63423 65535 ) ( 1856 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 1872 -63423 65535 ) ( 1872 67647 65535 ) ( 1872 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65631 912 65535 ) ( 65439 912 65535 ) ( 65439 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65439 1520 65535 ) ( -65631 1520 65535 ) ( 65439 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65631 -63423 -3328 ) ( -65631 67647 -3328 ) ( 65439 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65631 67647 -3344 ) ( -65631 -63423 -3344 ) ( 65439 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 7 -{ -( 1792 67647 65535 ) ( 1792 -63423 65535 ) ( 1792 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 1808 -63423 65535 ) ( 1808 67647 65535 ) ( 1808 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65695 912 65535 ) ( 65375 912 65535 ) ( 65375 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65375 1520 65535 ) ( -65695 1520 65535 ) ( 65375 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65695 -63423 -3328 ) ( -65695 67647 -3328 ) ( 65375 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65695 67647 -3344 ) ( -65695 -63423 -3344 ) ( 65375 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 8 -{ -( 1728 67647 65535 ) ( 1728 -63423 65535 ) ( 1728 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 1744 -63423 65535 ) ( 1744 67647 65535 ) ( 1744 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65759 912 65535 ) ( 65311 912 65535 ) ( 65311 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65311 1520 65535 ) ( -65759 1520 65535 ) ( 65311 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65759 -63423 -3328 ) ( -65759 67647 -3328 ) ( 65311 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65759 67647 -3344 ) ( -65759 -63423 -3344 ) ( 65311 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 9 -{ -( 1664 67647 65535 ) ( 1664 -63423 65535 ) ( 1664 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 1680 -63423 65535 ) ( 1680 67647 65535 ) ( 1680 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65823 912 65535 ) ( 65247 912 65535 ) ( 65247 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65247 1520 65535 ) ( -65823 1520 65535 ) ( 65247 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65823 -63423 -3328 ) ( -65823 67647 -3328 ) ( 65247 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65823 67647 -3344 ) ( -65823 -63423 -3344 ) ( 65247 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 10 -{ -( 1600 67647 65535 ) ( 1600 -63423 65535 ) ( 1600 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 1616 -63423 65535 ) ( 1616 67647 65535 ) ( 1616 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65887 912 65535 ) ( 65183 912 65535 ) ( 65183 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65183 1520 65535 ) ( -65887 1520 65535 ) ( 65183 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65887 -63423 -3328 ) ( -65887 67647 -3328 ) ( 65183 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65887 67647 -3344 ) ( -65887 -63423 -3344 ) ( 65183 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 11 -{ -( 1536 67647 65535 ) ( 1536 -63423 65535 ) ( 1536 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( 1552 -63423 65535 ) ( 1552 67647 65535 ) ( 1552 -63423 -65535 ) metal5_1 -16 -0 180 1 -1 -( -65951 912 65535 ) ( 65119 912 65535 ) ( 65119 912 -65535 ) metal5_1 16 -48 180 1 -1 -( 65119 1520 65535 ) ( -65951 1520 65535 ) ( 65119 1520 -65535 ) metal5_1 16 -48 180 1 -1 -( -65951 -63423 -3328 ) ( -65951 67647 -3328 ) ( 65119 67647 -3328 ) metal5_1 16 16 180 1 1 -( -65951 67647 -3344 ) ( -65951 -63423 -3344 ) ( 65119 67647 -3344 ) metal5_1 16 16 180 1 1 -} -// brush 12 -{ -( 1488 1520 -3336 ) ( 1488 1472 -3328 ) ( 1488 1472 -3336 ) clip -0 -0 180 1 -1 -( 2272 1520 -3336 ) ( 2272 1472 -3328 ) ( 2272 1520 -3328 ) clip -0 -0 180 1 -1 -( 2272 912 -3336 ) ( 2256 912 -3328 ) ( 2272 912 -3328 ) clip 16 -0 180 1 -1 -( 2272 1520 -3336 ) ( 2256 1520 -3328 ) ( 2256 1520 -3336 ) clip 16 -0 180 1 -1 -( 2272 1520 -3328 ) ( 2256 1472 -3328 ) ( 2256 1520 -3328 ) clip 16 -0 180 1 1 -( 2272 1520 -3336 ) ( 2256 1472 -3336 ) ( 2272 1472 -3336 ) clip 16 -0 180 1 1 -} -// brush 13 -{ -( 1488 67647 65535 ) ( 1488 -63423 65535 ) ( 1488 -63423 -65535 ) metal5_8 -16 -48 -0 1 -1 -( 2312 -63423 65535 ) ( 2312 67647 65535 ) ( 2312 -63423 -65535 ) metal5_8 -16 -48 -0 1 -1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( 65359 912 -65535 ) metal5_8 -0 -48 180 1 -1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( 65359 1520 -65535 ) metal5_8 -0 -48 180 1 -1 -( -65711 -63423 -3464 ) ( -65711 67647 -3464 ) ( 65359 67647 -3464 ) metal5_8 -0 16 180 1 1 -( -65711 67647 -3472 ) ( -65711 -63423 -3472 ) ( 65359 67647 -3472 ) metal5_8 -0 16 180 1 1 -} -// brush 14 -{ -( 1488 67647 65535 ) ( 1488 -63423 65535 ) ( 1488 -63423 -65535 ) *lava1 -15 -0 180 1 -1 -( 2320 -63423 65535 ) ( 2320 67647 65535 ) ( 2320 -63423 -65535 ) *lava1 -15 -0 180 1 -1 -( -65711 912 65535 ) ( 65359 912 65535 ) ( 65359 912 -65535 ) *lava1 -31 -0 -0 1 -1 -( 65359 1520 65535 ) ( -65711 1520 65535 ) ( 65359 1520 -65535 ) *lava1 -31 -0 -0 1 -1 -( -65711 -63423 -3336 ) ( -65711 67647 -3336 ) ( 65359 67647 -3336 ) *lava1 -31 -0 -0 1 1 -( -65711 67647 -3464 ) ( -65711 -63423 -3464 ) ( 65359 67647 -3464 ) *lava1 -31 -0 -0 1 1 -} -} -// entity 182 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "boxes" -"_tb_id" "433" -// brush 0 -{ -( -2688 1424 -3328 ) ( -2688 1568 -3312 ) ( -2688 1568 -3328 ) iktpw02 -16 -0 -0 1 1 -( -2816 1424 -3328 ) ( -2816 1568 -3312 ) ( -2816 1424 -3312 ) iktpw02 -16 -0 -0 1 1 -( -2816 1568 -3328 ) ( -2688 1568 -3312 ) ( -2816 1568 -3312 ) iktpw02 -16 -0 -0 1 1 -( -2816 1424 -3328 ) ( -2688 1424 -3312 ) ( -2688 1424 -3328 ) iktpw02 -64 -0 -0 1 1 -( -2816 1424 -3200 ) ( -2688 1568 -3200 ) ( -2688 1424 -3200 ) iktpw02 -64 -48 -0 1 1 -( -2816 1424 -3328 ) ( -2688 1568 -3328 ) ( -2816 1568 -3328 ) iktpw02 -16 -0 -0 1 1 -} -// brush 1 -{ -( -2752 1392 -3328 ) ( -2752 1424 -3312 ) ( -2752 1424 -3328 ) iktpw02 -0 -0 -0 0.5 0.5 -( -2784 1392 -3328 ) ( -2784 1424 -3312 ) ( -2784 1392 -3312 ) iktpw02 -32.0005 -0 -0 0.5 0.5 -( -2784 1424 -3328 ) ( -2752 1424 -3312 ) ( -2784 1424 -3312 ) iktpw02 -0 -0 -0 0.5 0.5 -( -2784 1392 -3328 ) ( -2752 1392 -3312 ) ( -2752 1392 -3328 ) iktpw02 -0 -0 -0 0.5 0.5 -( -2784 1392 -3296 ) ( -2752 1424 -3296 ) ( -2752 1392 -3296 ) iktpw02 -63.999 32.0005 -0 0.5 0.5 -( -2784 1392 -3328 ) ( -2752 1424 -3328 ) ( -2784 1424 -3328 ) iktpw02 -0 -0 -0 0.5 0.5 -} -// brush 2 -{ -( -2688 1376 -3328 ) ( -2688 1424 -3312 ) ( -2688 1424 -3328 ) iktpw02 -16 -0 -0 1 1 -( -2752 1376 -3328 ) ( -2752 1424 -3312 ) ( -2752 1376 -3312 ) iktpw02 -16 -0 -0 1 1 -( -2752 1424 -3328 ) ( -2704 1424 -3312 ) ( -2752 1424 -3312 ) iktpw02 -0 -0 -0 1 1 -( -2752 1360 -3328 ) ( -2704 1360 -3312 ) ( -2704 1360 -3328 ) iktpw02 -0 -0 -0 1 1 -( -2752 1376 -3264 ) ( -2704 1424 -3264 ) ( -2704 1376 -3264 ) iktpw02 -0 16 -0 1 1 -( -2752 1376 -3328 ) ( -2704 1424 -3328 ) ( -2752 1424 -3328 ) iktpw02 -0 16 -0 1 1 -} -// brush 3 -{ -( -2688 1392 -3264 ) ( -2688 1424 -3248 ) ( -2688 1424 -3264 ) iktpw02 -0 -0 -0 0.5 0.5 -( -2720 1392 -3264 ) ( -2720 1424 -3248 ) ( -2720 1392 -3248 ) iktpw02 -32 -0 -0 0.5 0.5 -( -2720 1424 -3264 ) ( -2688 1424 -3248 ) ( -2720 1424 -3248 ) iktpw02 -0 -0 -0 0.5 0.5 -( -2720 1392 -3264 ) ( -2688 1392 -3248 ) ( -2688 1392 -3264 ) iktpw02 -0 -0 -0 0.5 0.5 -( -2720 1392 -3232 ) ( -2688 1424 -3232 ) ( -2688 1392 -3232 ) iktpw02 -0 32 -0 0.5 0.5 -( -2720 1392 -3264 ) ( -2688 1424 -3264 ) ( -2720 1424 -3264 ) iktpw02 -0 -0 -0 0.5 0.5 -} -} -// entity 183 -{ -"origin" "-2848 1344 -3168" -"light" "250" -"classname" "light" -"_tb_group" "433" -} -// entity 184 -{ -"classname" "func_group" -"_tb_type" "_tb_group" -"_tb_name" "boxes" -"_tb_id" "434" -// brush 0 -{ -( 2512 704 -3328 ) ( 2512 560 -3312 ) ( 2512 560 -3328 ) iktpw02 -0 -0 180 1 -1 -( 2640 704 -3328 ) ( 2640 560 -3312 ) ( 2640 704 -3312 ) iktpw02 -0 -0 180 1 -1 -( 2640 560 -3328 ) ( 2512 560 -3312 ) ( 2640 560 -3312 ) iktpw02 -0 -0 180 1 -1 -( 2640 704 -3328 ) ( 2512 704 -3312 ) ( 2512 704 -3328 ) iktpw02 -48 -0 180 1 -1 -( 2640 704 -3200 ) ( 2512 560 -3200 ) ( 2512 704 -3200 ) iktpw02 -48 -0 180 1 1 -( 2640 704 -3328 ) ( 2512 560 -3328 ) ( 2640 560 -3328 ) iktpw02 -0 48 180 1 1 -} -// brush 1 -{ -( 2576 736 -3328 ) ( 2576 704 -3312 ) ( 2576 704 -3328 ) iktpw02 -32 -0 180 0.5 -0.5 -( 2608 736 -3328 ) ( 2608 704 -3312 ) ( 2608 736 -3312 ) iktpw02 -63.9987 -0 180 0.5 -0.5 -( 2608 704 -3328 ) ( 2576 704 -3312 ) ( 2608 704 -3312 ) iktpw02 -31.998 -0 180 0.5 -0.5 -( 2608 736 -3328 ) ( 2576 736 -3312 ) ( 2576 736 -3328 ) iktpw02 -31.998 -0 180 0.5 -0.5 -( 2608 736 -3296 ) ( 2576 704 -3296 ) ( 2576 736 -3296 ) iktpw02 -31.998 63.9987 180 0.5 0.5 -( 2608 736 -3328 ) ( 2576 704 -3328 ) ( 2608 704 -3328 ) iktpw02 -31.998 32 180 0.5 0.5 -} -// brush 2 -{ -( 2512 752 -3328 ) ( 2512 704 -3312 ) ( 2512 704 -3328 ) iktpw02 -0 -0 180 1 -1 -( 2576 752 -3328 ) ( 2576 704 -3312 ) ( 2576 752 -3312 ) iktpw02 -0 -0 180 1 -1 -( 2576 704 -3328 ) ( 2528 704 -3312 ) ( 2576 704 -3312 ) iktpw02 -48 -0 180 1 -1 -( 2576 768 -3328 ) ( 2528 768 -3312 ) ( 2528 768 -3328 ) iktpw02 -48 -0 180 1 -1 -( 2576 752 -3264 ) ( 2528 704 -3264 ) ( 2528 752 -3264 ) iktpw02 -48 -0 180 1 1 -( 2576 752 -3328 ) ( 2528 704 -3328 ) ( 2576 704 -3328 ) iktpw02 -48 -0 180 1 1 -} -// brush 3 -{ -( 2512 736 -3264 ) ( 2512 704 -3248 ) ( 2512 704 -3264 ) iktpw02 -32 -0 180 0.5 -0.5 -( 2544 736 -3264 ) ( 2544 704 -3248 ) ( 2544 736 -3248 ) iktpw02 -63.9987 -0 180 0.5 -0.5 -( 2544 704 -3264 ) ( 2512 704 -3248 ) ( 2544 704 -3248 ) iktpw02 -32 -0 180 0.5 -0.5 -( 2544 736 -3264 ) ( 2512 736 -3248 ) ( 2512 736 -3264 ) iktpw02 -32 -0 180 0.5 -0.5 -( 2544 736 -3232 ) ( 2512 704 -3232 ) ( 2512 736 -3232 ) iktpw02 -32 63.9987 180 0.5 0.5 -( 2544 736 -3264 ) ( 2512 704 -3264 ) ( 2544 704 -3264 ) iktpw02 -32 32 180 0.5 0.5 -} -} -// entity 185 -{ -"origin" "2672 784 -3168" -"light" "250" -"classname" "light" -"angle" "180" -"_tb_group" "434" -} From 15eba80636b8f352867911f67b5ce766defdd9e8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 23 Nov 2018 19:05:36 +1100 Subject: [PATCH 0503/2474] Don't cuss medic --- scout.qc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scout.qc b/scout.qc index 56c99943..c4975dda 100644 --- a/scout.qc +++ b/scout.qc @@ -286,6 +286,12 @@ void () ConcussionGrenadeTimer = { local float concadjust; local float stumble; + if (self.owner.playerclass == 5) { + self.owner.fixangle = 0; + self.owner.is_concussed = 0; + dremove(self); + } + if (self.owner.invincible_finished > time) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); self.owner.fixangle = 0; @@ -293,6 +299,7 @@ void () ConcussionGrenadeTimer = { dremove(self); return; } + if ((self.health == 200) || (self.health == 400) || (self.health == 600) || (self.health == 800) || (self.health == 1000)) { From 5a663152eb0ce35926a94d39a9869f2a2df8be2c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 23 Nov 2018 19:10:03 +1100 Subject: [PATCH 0504/2474] return after removing cuss effect from medic --- scout.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/scout.qc b/scout.qc index c4975dda..e045af18 100644 --- a/scout.qc +++ b/scout.qc @@ -290,6 +290,7 @@ void () ConcussionGrenadeTimer = { self.owner.fixangle = 0; self.owner.is_concussed = 0; dremove(self); + return; } if (self.owner.invincible_finished > time) { From b2361ae9e6a9fe4019669b68750241dbf22f5f3c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 23 Nov 2018 20:06:26 +1100 Subject: [PATCH 0505/2474] Don't even let medic get cussed in the first place --- scout.qc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scout.qc b/scout.qc index e045af18..cfc67b6b 100644 --- a/scout.qc +++ b/scout.qc @@ -286,13 +286,6 @@ void () ConcussionGrenadeTimer = { local float concadjust; local float stumble; - if (self.owner.playerclass == 5) { - self.owner.fixangle = 0; - self.owner.is_concussed = 0; - dremove(self); - return; - } - if (self.owner.invincible_finished > time) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); self.owner.fixangle = 0; @@ -590,6 +583,10 @@ void (entity inflictor, entity attacker, float bounce, te.nextthink = time + 0.25; } } else { + if (self.owner.playerclass == 5) { + return; + } + if (old_grens == TRUE) { stuffcmd(head, "v_idlescale 100\n"); stuffcmd(head, "fov 130\n"); From 64ffe91b5d15bc5b19f39486e130a086a92568a6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 23 Nov 2018 20:54:21 +1100 Subject: [PATCH 0506/2474] Make medic cuss gren immunity an option --- README.md | 3 ++- client.qc | 3 +++ qw.qc | 1 + tfort.qc | 4 ++++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ac1cbdc0..36bc6349 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ FortressOne Server v0.1.0 New features ------ -* Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime`. +* Option for medic to be immune from cusscussion effects. `localinfo medicnocuss on`. +* Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime n`. * Option to fully restock player on cap. `localinfo stock_on_cap on`. * Option for packs to fully restock health and armour of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. diff --git a/client.qc b/client.qc index f7acd4f0..38444403 100644 --- a/client.qc +++ b/client.qc @@ -475,6 +475,9 @@ void () DecodeLevelParms = { // concussion grenade effect time [19] cussgrentime = CF_GetSetting("cgt", "cussgrentime", "19"); + // medic immune to concussion grenade effects [on] + cussgrentime = CF_GetSetting("mnc", "medicnocuss", "on"); + // display sniper rifle power in status bar [on] sniperpower = CF_GetSetting("sp", "sniperpower", "on"); diff --git a/qw.qc b/qw.qc index f70effb3..6169c588 100644 --- a/qw.qc +++ b/qw.qc @@ -472,6 +472,7 @@ float stockfull; float stock_on_cap; float classtips; float cussgrentime; +float medicnocuss; float sniperpower; float sniperreloadpercent; float buildstatus; diff --git a/tfort.qc b/tfort.qc index c5818095..bc6fa0f1 100644 --- a/tfort.qc +++ b/tfort.qc @@ -596,12 +596,16 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "\n== Scout ==\n"); CF_PrintSetting("Scout dash ability", scoutdash, "", 1); + sprint(self, PRINT_HIGH, "\n== Sniper ==\n"); CF_PrintSetting("Sniper reload", sniperreload, "", 1); CF_PrintSetting("Old sniper rifle range", old_sniperrange, "", 1); CF_PrintSetting("Sniper Rifle power in status bar", sniperpower, "", 1); CF_PrintSetting("Reload percentage in status bar", sniperreloadpercent, "", 1); + sprint(self, PRINT_HIGH, "\n== Medic ==\n"); + CF_PrintSetting("Medic immune to concussion grenade", medicnocuss, "", 1); + sprint(self, PRINT_HIGH, "\n== Demolitions Man ==\n"); if (detpipe_limit > 0) { CF_PrintSetting("Pipebomb limit (per demoman)", detpipe_limit, "", 0); From e3a4de9d182a489cf64e5bef9e4d1732dfafbaa1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 23 Nov 2018 20:57:41 +1100 Subject: [PATCH 0507/2474] Check for medicnocuss option --- scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scout.qc b/scout.qc index cfc67b6b..57b39a4a 100644 --- a/scout.qc +++ b/scout.qc @@ -583,7 +583,7 @@ void (entity inflictor, entity attacker, float bounce, te.nextthink = time + 0.25; } } else { - if (self.owner.playerclass == 5) { + if (medicnocuss && self.owner.playerclass == 5) { return; } From 26463f672bc3d9a805f5905b4055366a0c96a8f3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 23 Nov 2018 21:02:43 +1100 Subject: [PATCH 0508/2474] Fix incorrectly named variable --- client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 38444403..e9086bdd 100644 --- a/client.qc +++ b/client.qc @@ -476,7 +476,7 @@ void () DecodeLevelParms = { cussgrentime = CF_GetSetting("cgt", "cussgrentime", "19"); // medic immune to concussion grenade effects [on] - cussgrentime = CF_GetSetting("mnc", "medicnocuss", "on"); + medicnocuss = CF_GetSetting("mnc", "medicnocuss", "on"); // display sniper rifle power in status bar [on] sniperpower = CF_GetSetting("sp", "sniperpower", "on"); From 359655e6b0c407e2b444c28a362fc1456817e2da Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 23 Nov 2018 22:58:06 +1100 Subject: [PATCH 0509/2474] Allow medics grens to still cuss other players --- scout.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scout.qc b/scout.qc index 57b39a4a..4a796bc5 100644 --- a/scout.qc +++ b/scout.qc @@ -559,6 +559,10 @@ void (entity inflictor, entity attacker, float bounce, if (head.flags & FL_ONGROUND) head.flags = head.flags - FL_ONGROUND; } else { + if (medicnocuss && head.playerclass == 5) { + return; + } + te = find(world, classname, "timer"); if (old_grens == TRUE) while (((te.owner != head) || @@ -583,10 +587,6 @@ void (entity inflictor, entity attacker, float bounce, te.nextthink = time + 0.25; } } else { - if (medicnocuss && self.owner.playerclass == 5) { - return; - } - if (old_grens == TRUE) { stuffcmd(head, "v_idlescale 100\n"); stuffcmd(head, "fov 130\n"); From 876b0a79c951cbbda47c35acc7fbc063a980d705 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 24 Nov 2018 19:33:10 +1100 Subject: [PATCH 0510/2474] q3f support for checkstate of ents, q3f_openfire2b now works fully --- buttons.qc | 17 +++++++++++++++++ q3.qc | 17 ----------------- q3defs.qc | 3 ++- tfortmap.qc | 29 +++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/buttons.qc b/buttons.qc index b73643a7..baf1d3d8 100644 --- a/buttons.qc +++ b/buttons.qc @@ -18,6 +18,14 @@ void () button_done = { }; void () button_return = { + // q3f support + string targname; + entity targ; + targ = world; + targname = self.target; + targ = find(targ, targetname, targname); + targ.active = TFGS_INACTIVE; + self.goal_state = TFGS_INACTIVE; self.state = STATE_DOWN; SUB_CalcMove(self.pos1, self.speed, button_done); @@ -34,6 +42,14 @@ void () button_fire = { if ((self.state == STATE_UP) || (self.state == STATE_TOP)) return; + // q3f support + string targname; + entity targ; + targ = world; + targname = self.target; + targ = find(targ, targetname, targname); + targ.active = TFGS_ACTIVE; + sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_UP; @@ -115,6 +131,7 @@ void () func_button = { self.team_no = 2; } + self.movetype = MOVETYPE_PUSH; self.solid = SOLID_BSP; setmodel(self, self.model); diff --git a/q3.qc b/q3.qc index eafe4198..d73e5133 100644 --- a/q3.qc +++ b/q3.qc @@ -153,23 +153,6 @@ void () target_kill = { self.deathtype = " died\n"; self.goal_effects = 1; - string cname, cstate; - float slen, idx; - - idx = strstrofs(s, "="); - slen = strlen(self.checkstate); - cname = substring(self.checkstate, 0, idx); - cstate = substring(self.checkstate, idx + 1, slen); - - switch (cstate) - { - case "inactive": - self.if_goal_is_inactive = cname; - break; - case "active": - self.if_goal_is_active = cname; - } - info_tfgoal(); } diff --git a/q3defs.qc b/q3defs.qc index 104c9ad8..3c28a175 100644 --- a/q3defs.qc +++ b/q3defs.qc @@ -13,4 +13,5 @@ .string carried_all_sound; .string inactive_all_message; .string activetarget; -.string checkstate; \ No newline at end of file +.string checkstate; +.float active; \ No newline at end of file diff --git a/tfortmap.qc b/tfortmap.qc index 551ccf8e..0c63fd62 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1333,6 +1333,33 @@ void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate = { if (cb_prematch_time > time) return; + + // q3f support + if (Goal.checkstate != string_null) { + string cname, cstate; + float slen, idx; + entity targ; + targ = world; + + idx = strstrofs(Goal.checkstate, "="); + slen = strlen(Goal.checkstate); + cname = substring(Goal.checkstate, 0, idx); + targ = find(targ, targetname, cname); + cstate = substring(Goal.checkstate, idx + 1, slen); + switch (cstate) + { + case "inactive": + if (targ.active == TFGS_ACTIVE) { + return; + } + break; + case "active": + if (targ.active == TFGS_INACTIVE) { + return; + } + } + } + if (Activated(Goal, AP)) { if (ActivatingGoal == Goal) DoResults(Goal, AP, 1); @@ -1638,6 +1665,7 @@ void (entity Goal, entity AP, float addb) DoResults = { te.weapon = addb; return; } + UpdateAbbreviations(Goal); Goal.goal_state = 2; if ((Goal.classname == "info_tfgoal") && (Goal.mdl != string_null)) { @@ -1946,6 +1974,7 @@ void () tfgoal_touch = { }; void () info_tfgoal_use = { + dprint("info_tfgoal_use\n"); AttemptToActivate(self, activator, self); }; From 42ceece3502eb83e81a52a3961a1cfda4dcf771f Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 24 Nov 2018 20:57:05 +1100 Subject: [PATCH 0511/2474] update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0214f2f2..c0ecc834 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ *.log *.patch fteqcc64 +.vscode/tasks.json +.gitignore From 03fd391624125a575b70b295843183e6a96a4e4f Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 26 Nov 2018 16:32:06 +1100 Subject: [PATCH 0512/2474] fix yet another encoded string --- tfort.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tfort.qc b/tfort.qc index 18830f78..6a72f3b5 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2361,10 +2361,10 @@ void () TeamFortress_RemoveTimers = { if (CTF_Map == 1) { if (te.goal_no == 1) { bprint(PRINT_HIGH, self.netname, - " οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½οΏ½ flag!\n"); + Q" \stook\s the \sblue\s flag!\n"); } else if (te.goal_no == 2) { bprint(PRINT_HIGH, self.netname, - " οΏ½οΏ½οΏ½οΏ½ the οΏ½οΏ½οΏ½ flag!\n"); + Q" \stook\s the \sred\s flag!\n"); } } } From 3200e1cb02c3036da1340e9dbd2577f61e6d3c13 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 7 Dec 2018 16:38:25 +1100 Subject: [PATCH 0513/2474] fix for detpipe being delayed if weapon is reloading while "special" detpipe is not delayed --- weapons.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index f851eb0f..66709b31 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2760,8 +2760,9 @@ void () W_WeaponFrame = { } } - // class specials and grenade impulses always possible - if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= TF_GRENADE_1 && self.impulse <= TF_GRENADE_SWITCH)) { + // class specials and grenade impulses always possible, also detpipe + if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= TF_GRENADE_1 && self.impulse <= TF_GRENADE_SWITCH) + || self.impulse == TF_PB_DETONATE) { ImpulseCommands(); return; } From b4bf51ec65d177daf7d5a1fc432e81c39f499353 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 12 Dec 2018 15:14:22 +1100 Subject: [PATCH 0514/2474] revert discard behaviour, add in discard_drop_ammo command --- actions.qc | 103 +++++++++++++++++++++++++++++++++++++--------------- defs.h | 2 +- tforthlp.qc | 1 + weapons.qc | 3 ++ 4 files changed, 78 insertions(+), 31 deletions(-) diff --git a/actions.qc b/actions.qc index 8b37d999..e9d14986 100644 --- a/actions.qc +++ b/actions.qc @@ -6,36 +6,35 @@ void () TeamFortress_ClipTick; void () TeamFortress_Discard = { newmis = spawn(); - if ((self.playerclass == PC_SCOUT) - || (self.playerclass == PC_ENGINEER) - || (self.playerclass == PC_MEDIC)) { - newmis.ammo_rockets = self.ammo_rockets; - } else if ((self.playerclass == PC_SNIPER) - || (self.playerclass == PC_SPY)) { - newmis.ammo_rockets = self.ammo_rockets; - newmis.ammo_cells = self.ammo_cells; - } else if ((self.playerclass == PC_SOLDIER) - || (self.playerclass == PC_DEMOMAN)) { - newmis.ammo_cells = self.ammo_cells; - newmis.ammo_nails = self.ammo_nails; - } else if (self.playerclass == PC_HVYWEAP) { - newmis.ammo_rockets = self.ammo_rockets; - newmis.ammo_nails = self.ammo_nails; - } else if (self.playerclass == PC_PYRO) { - newmis.ammo_nails = self.ammo_nails; - } - - if (self.playerclass == PC_MEDIC && !medicaura && old_medikit) - newmis.ammo_cells = self.ammo_cells; - - - if (!(newmis.ammo_shells + newmis.ammo_nails + newmis.ammo_rockets + newmis.ammo_cells)) { - dremove(newmis); - if (self.menu_input != Menu_Drop_Input) - Menu_Drop(); - else - Menu_Close(self); - return; + switch (self.playerclass) { + case PC_SCOUT: + case PC_ENGINEER: + newmis.ammo_rockets = self.ammo_rockets; + break; + case PC_MEDIC: + newmis.ammo_rockets = self.ammo_rockets; + if (!medicaura && old_medikit) { + newmis.ammo_cells = self.ammo_cells; + } + break; + case PC_SNIPER: + case PC_SPY: + newmis.ammo_rockets = self.ammo_rockets; + newmis.ammo_cells = self.ammo_cells; + break; + case PC_SOLDIER: + case PC_DEMOMAN: + newmis.ammo_cells = self.ammo_cells; + newmis.ammo_nails = self.ammo_nails; + break; + case PC_HVYWEAP: + newmis.ammo_rockets = self.ammo_rockets; + newmis.ammo_nails = self.ammo_nails; + break; + case PC_PYRO: + newmis.ammo_nails = self.ammo_nails; + break; + default: } if (newmis.ammo_shells) { @@ -76,6 +75,50 @@ void () TeamFortress_Discard = { setmodel(newmis, "progs/backpack.mdl"); }; +void () TeamFortress_Discard_DropAmmo = { + // if nothing to discard, do dropammo instead + float disc; + disc = 0; + + switch (self.playerclass) { + case PC_SCOUT: + case PC_ENGINEER: + disc = self.ammo_rockets; + break; + case PC_MEDIC: + disc = self.ammo_rockets; + if (!medicaura && old_medikit) { + disc += self.ammo_cells; + } + break; + case PC_SNIPER: + case PC_SPY: + disc = self.ammo_rockets + self.ammo_cells; + break; + case PC_SOLDIER: + case PC_DEMOMAN: + disc = self.ammo_cells + self.ammo_nails; + break; + case PC_HVYWEAP: + disc = self.ammo_rockets + self.ammo_nails; + break; + case PC_PYRO: + disc = self.ammo_nails; + break; + default: + } + + if (disc == 0) { + if (self.menu_input != Menu_Drop_Input) + Menu_Drop(); + else + Menu_Close(self); + return; + } else { + TeamFortress_Discard(); + } +}; + void () TeamFortress_SaveMe = { local entity te, tl; diff --git a/defs.h b/defs.h index fae2bd96..ccf19afa 100644 --- a/defs.h +++ b/defs.h @@ -402,7 +402,7 @@ #define TF_ENGINEER_BUILD 77 // Engineer: Bring up build menu for Engineer #define TF_ENGINEER_DETDISP 78 // Engineer: Detonate dispenser for Engineer #define TF_ENGINEER_DETSENTRY 79 // Engineer: Detonate sentry gun for Engineer -// unused 80 +#define TF_DISCARD_DROP_AMMO 80 // unused 81 // unused 82 // unused 83 diff --git a/tforthlp.qc b/tforthlp.qc index adcdcf8e..6d2f3f44 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -108,6 +108,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("special", TF_SPECIAL_SKILL, 0); TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); TeamFortress_Alias("discard", TF_DISCARD, 0); + TeamFortress_Alias("discard_drop_ammo", TF_DISCARD_DROP_AMMO, 0); } else if (self.motd == 60) { TeamFortress_Alias("weapnext", TF_WEAPNEXT, 0); TeamFortress_Alias("weapprev", TF_WEAPPREV, 0); diff --git a/weapons.qc b/weapons.qc index f851eb0f..e1c8780c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -59,6 +59,7 @@ void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; +void () TeamFortress_Discard_Drop_Ammo; void (float force) TeamFortress_DetonatePipebombs; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; @@ -2400,6 +2401,8 @@ void () ImpulseCommands = { DropGoalItems(); else if (self.impulse == TF_DISCARD) TeamFortress_Discard(); + else if (self.impulse == TF_DISCARD_DROP_AMMO) + TeamFortress_Discard_Drop_Ammo(); else if (self.impulse == TF_DASH) CF_Scout_Dash(); else if (self.impulse == TF_PB_DETONATE) From 70c7e7de96d742e55ed780ec84b5066148700542 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 13 Dec 2018 19:56:27 +1100 Subject: [PATCH 0515/2474] fix for incorrect method name --- weapons.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/weapons.qc b/weapons.qc index 9d6c632d..2cda0173 100644 --- a/weapons.qc +++ b/weapons.qc @@ -59,7 +59,7 @@ void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; -void () TeamFortress_Discard_Drop_Ammo; +void () TeamFortress_Discard_DropAmmo; void (float force) TeamFortress_DetonatePipebombs; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; @@ -2402,7 +2402,7 @@ void () ImpulseCommands = { else if (self.impulse == TF_DISCARD) TeamFortress_Discard(); else if (self.impulse == TF_DISCARD_DROP_AMMO) - TeamFortress_Discard_Drop_Ammo(); + TeamFortress_Discard_DropAmmo(); else if (self.impulse == TF_DASH) CF_Scout_Dash(); else if (self.impulse == TF_PB_DETONATE) From 117c7d7d0f5e8c5bbe059323c1192f87e9b51eeb Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 13 Dec 2018 19:59:27 +1100 Subject: [PATCH 0516/2474] only create discard backpack if there is ammo in it --- actions.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/actions.qc b/actions.qc index e9d14986..e600777f 100644 --- a/actions.qc +++ b/actions.qc @@ -20,7 +20,7 @@ void () TeamFortress_Discard = { case PC_SNIPER: case PC_SPY: newmis.ammo_rockets = self.ammo_rockets; - newmis.ammo_cells = self.ammo_cells; + newmis.ammo_cells = self.ammo_cells; break; case PC_SOLDIER: case PC_DEMOMAN: @@ -29,13 +29,16 @@ void () TeamFortress_Discard = { break; case PC_HVYWEAP: newmis.ammo_rockets = self.ammo_rockets; - newmis.ammo_nails = self.ammo_nails; + newmis.ammo_nails = self.ammo_nails; break; case PC_PYRO: newmis.ammo_nails = self.ammo_nails; break; default: } + if ((newmis.ammo_rockets + newmis.ammo_cells + newmis.ammo_nails + newmis.ammo_shells) == 0) { + return; + } if (newmis.ammo_shells) { self.ammo_shells = 0; From 2b51f7f7501c838e55e6aeb9f997be72320e1fe2 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 8 Jan 2019 20:51:02 +1100 Subject: [PATCH 0517/2474] fix for flag return sound not playing and centerprint of flag return messages not working --- tfortmap.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 0c63fd62..c7c591a8 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2205,9 +2205,6 @@ void () ReturnItem = { setorigin(self.enemy, self.enemy.origin); tfgoalitem_checkgoalreturn(self.enemy); - if (self.enemy.origin == self.enemy.oldorigin) - return; - sound(self.enemy, 2, "items/itembk2.wav", 1, 1); if (self.weapon != 2) { From 9ffc345b6317bcecc6b68b3c8125ca8eb8ef680b Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 8 Jan 2019 22:30:05 +1100 Subject: [PATCH 0518/2474] fix for noise not being played if owner is world --- tfortmap.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index c7c591a8..32137f10 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1671,8 +1671,13 @@ void (entity Goal, entity AP, float addb) DoResults = { if ((Goal.classname == "info_tfgoal") && (Goal.mdl != string_null)) { setmodel(Goal, string_null); } + if (Goal.noise) { - sound(other, 3, Goal.noise, 1, 1); + if (other == world) { + sound(Goal, 3, Goal.noise, 1, 1); + } else { + sound(other, 3, Goal.noise, 1, 1); + } } winners = 0; if (Goal.increase_team1 != 0) { From 003a8892830be2534169bdfdec39e78f43797f1b Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 9 Jan 2019 19:43:05 +1100 Subject: [PATCH 0519/2474] ability for doors to close instantly if they have a wait and are blocked --- doors.qc | 2 +- qw.qc | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doors.qc b/doors.qc index ca92a240..a35b9db5 100644 --- a/doors.qc +++ b/doors.qc @@ -17,7 +17,7 @@ void () door_blocked = { } T_Damage(other, self, self, self.dmg); - if (self.wait >= 0) { + if (self.wait >= 0 && self.forcecloseonblock == 0) { if (self.state == STATE_DOWN) door_go_up(); else diff --git a/qw.qc b/qw.qc index d702a093..f45e97d2 100644 --- a/qw.qc +++ b/qw.qc @@ -509,6 +509,9 @@ float intermission_exittime; .float clientkillforce; .float clientkillfree; +// ability for doors to close instantly if they have a wait and are blocked +.float forcecloseonblock; + //============================================================================ void (float psize, entity p) KickPlayer = { From 4a5fd57a4928e8f2a0cbb7196e15905256c3b2ed Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 12 Jan 2019 02:01:38 +1100 Subject: [PATCH 0520/2474] Limit soldier nails grens to 1, refactor --- items.qc | 27 +++++++++++---------------- tfortmap.qc | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/items.qc b/items.qc index 8d50fce3..26ab3d4b 100644 --- a/items.qc +++ b/items.qc @@ -781,20 +781,15 @@ void (entity pl, float typ) PrintGrenadeType = { sprint(pl, PRINT_HIGH, st); }; -float (float pf_grenade_number, float pf_grenade_type) GetMaxGrenades = { - if (pf_grenade_number == 1) { - if (pf_grenade_type == GR_TYPE_NAIL) { - return 2; - } - if (pf_grenade_type == GR_TYPE_CALTROP) { +float (float pf_grenade_type) GetMaxGrenades = { + switch(pf_grenade_type) { + case GR_TYPE_NAIL: + return 1; + case GR_TYPE_CALTROP: return 3; - } - } else { - if (pf_grenade_type == GR_TYPE_NAIL) { - return 2; - } + default: + return 4; } - return 4; } void (entity pe_player, float pf_grenade_type, float pf_grenade_count) PrintFoundGrenade = { @@ -823,14 +818,14 @@ float () GetGrenadePossibility = { return 0; } if (random() < 0.500) { - maxg = GetMaxGrenades(1, other.tp_grenades_1); + maxg = GetMaxGrenades(other.tp_grenades_1); if ((other.tp_grenades_1 != 0) && (other.no_grenades_1 < maxg)) { other.no_grenades_1 = other.no_grenades_1 + 1; PrintFoundGrenade(other, other.tp_grenades_1, 1); return 1; } } else { - maxg = GetMaxGrenades(1, other.tp_grenades_2); + maxg = GetMaxGrenades(other.tp_grenades_2); if ((other.tp_grenades_2 != 0) && (other.no_grenades_2 < maxg)) { other.no_grenades_2 = other.no_grenades_2 + 1; PrintFoundGrenade(other, other.tp_grenades_2, 1); @@ -1356,7 +1351,7 @@ void () BackpackTouch = { if (drop_grenpack && other.playerclass != PC_SCOUT) { // give grenade type 1 - maxg = GetMaxGrenades(1, other.tp_grenades_1); + maxg = GetMaxGrenades(other.tp_grenades_1); if ((other.no_grenades_1 + self.no_grenades_1) >= maxg) giveg = maxg - other.no_grenades_1; else @@ -1365,7 +1360,7 @@ void () BackpackTouch = { PrintFoundGrenade(other, other.tp_grenades_1, giveg); // give grenade type 2 - maxg = GetMaxGrenades(2, other.tp_grenades_2); + maxg = GetMaxGrenades(other.tp_grenades_2); if ((other.no_grenades_2 + self.no_grenades_2) >= maxg) giveg = maxg - other.no_grenades_2; else diff --git a/tfortmap.qc b/tfortmap.qc index 32137f10..74234235 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -812,12 +812,12 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.no_grenades_2 = 4; } if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > 2)) { - Player.no_grenades_1 = 2; + (Player.no_grenades_1 > 1)) { + Player.no_grenades_1 = 1; } if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > 2)) { - Player.no_grenades_2 = 2; + (Player.no_grenades_2 > 1)) { + Player.no_grenades_2 = 1; } if (Player.ammo_detpack > Player.maxammo_detpack) { Player.ammo_detpack = Player.maxammo_detpack; @@ -911,8 +911,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.ammo_medikit = Player.maxammo_medikit; Player.ammo_detpack = Player.maxammo_detpack; - Player.no_grenades_1 = GetMaxGrenades(1, Player.tp_grenades_1); - Player.no_grenades_2 = GetMaxGrenades(2, Player.tp_grenades_2); + Player.no_grenades_1 = GetMaxGrenades(Player.tp_grenades_1); + Player.no_grenades_2 = GetMaxGrenades(Player.tp_grenades_2); te = find(Player, classname, "timer"); @@ -1078,11 +1078,11 @@ void (entity Goal, entity Player) RemoveResults = { Player.no_grenades_2 = 4; if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > 2)) - Player.no_grenades_1 = 2; + (Player.no_grenades_1 > 1)) + Player.no_grenades_1 = 1; if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > 2)) - Player.no_grenades_2 = 2; + (Player.no_grenades_2 > 1)) + Player.no_grenades_2 = 1; if (Player.ammo_detpack > Player.maxammo_detpack) Player.ammo_detpack = Player.maxammo_detpack; @@ -2867,4 +2867,4 @@ void () DropGoalItems = { } dremove(newmis); TeamFortress_SetSpeed(self); -}; \ No newline at end of file +}; From 69382fd49c2ddb69e8e066f57db35d5aec82f675 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 12 Jan 2019 12:06:11 +1100 Subject: [PATCH 0521/2474] fix readnme spelling error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5bcc6d7..b1a3cad3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server v0.1.0 New features ------ -* Option for medic to be immune from cusscussion effects. `localinfo medicnocuss on`. +* Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime n`. * Increased nail velocity. Disable with `localinfo old_ng_velocity on`. * Nailgun and Super-nailgun damage configurable with `localinfo ng_damage` and `localinfo sng_damage`. From d21a63f4cfdea4a3b8f82bfff8e6ed410d31f09a Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 12 Jan 2019 12:16:33 +1100 Subject: [PATCH 0522/2474] remove screen shake and flash from hwguy firing cannon --- client.qc | 2 -- player.qc | 22 ---------------------- 2 files changed, 24 deletions(-) diff --git a/client.qc b/client.qc index d3c5c08f..f7e00c6d 100644 --- a/client.qc +++ b/client.qc @@ -1531,7 +1531,6 @@ void () PlayerJump = { sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { - stuffcmd(self, "v_idlescale 0\n"); self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); @@ -1567,7 +1566,6 @@ void () PlayerJump = { self.count = 1; self.heat = 0; player_assaultcannondown1(); - stuffcmd(self, "v_idlescale 0\n"); } else { self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); diff --git a/player.qc b/player.qc index b4d74a3d..bc767f04 100644 --- a/player.qc +++ b/player.qc @@ -411,8 +411,6 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { }; void () player_assaultcannon1 =[103, player_assaultcannon2] { - local string st; - if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) <= 30) && !(self.tfstate & TFSTATE_LOCK)) { muzzleflash(); @@ -431,20 +429,6 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { TeamFortress_SetSpeed(self); W_FireAssaultCannon(); - stuffcmd(self, "v_idlescale "); - if (vlen(self.velocity) < 30) { - if (self.heat < 5) - st = ftos(self.heat * 4); - else - st = "20"; - } else { - if (self.heat < 5) - st = ftos(self.heat * 8); - else - st = "40"; - } - stuffcmd(self, st); - stuffcmd(self, "\n"); } else { sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); @@ -452,11 +436,8 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { self.weaponframe = 0; else self.weaponframe = 2; - - stuffcmd(self, "v_idlescale 5\n"); } if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - stuffcmd(self, "v_idlescale 0\n"); self.tfstate = self.tfstate | TFSTATE_AIMING; if (!cannon_move) self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); @@ -470,7 +451,6 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { }; void () player_assaultcannon2 =[104, player_assaultcannon1] { - stuffcmd(self, "v_idlescale 0\n"); if (vlen(self.velocity) < 30 && !(self.tfstate & TFSTATE_LOCK)) { if (self.weaponframe == 2) { self.weaponframe = 4; @@ -480,7 +460,6 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { SuperDamageSound(); W_FireAssaultCannon(); self.heat = self.heat + 0.1; - stuffcmd(self, "bf\n"); } else { if (self.weaponframe == 2) { self.weaponframe = 0; @@ -489,7 +468,6 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { } } if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - stuffcmd(self, "v_idlescale 0\n"); self.tfstate = self.tfstate | TFSTATE_AIMING; if (!cannon_move) self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); From dbdad1b638135b69013f7fec9f2be1bb64d21d70 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 12 Jan 2019 21:14:06 +1100 Subject: [PATCH 0523/2474] Refactor --- defs.h | 20 ++++++++++++++++++++ items.qc | 4 ++-- tfortmap.qc | 21 +++++++++++++-------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/defs.h b/defs.h index ccf19afa..82d2c660 100644 --- a/defs.h +++ b/defs.h @@ -796,6 +796,8 @@ #define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has #define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned #define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned +#define PC_SCOUT_GRENADE_MAX_1 3 +#define PC_SCOUT_GRENADE_MAX_2 4 #define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has #define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range @@ -825,6 +827,8 @@ #define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_FLARE #define PC_SNIPER_GRENADE_INIT_1 2 #define PC_SNIPER_GRENADE_INIT_2 3 +#define PC_SNIPER_GRENADE_MAX_1 4 +#define PC_SNIPER_GRENADE_MAX_2 4 #define PC_SNIPER_TF_ITEMS 0 // Class Details for SOLDIER @@ -851,6 +855,8 @@ #define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL #define PC_SOLDIER_GRENADE_INIT_1 4 #define PC_SOLDIER_GRENADE_INIT_2 1 +#define PC_SOLDIER_GRENADE_MAX_1 4 +#define PC_SOLDIER_GRENADE_MAX_2 1 #define PC_SOLDIER_TF_ITEMS 0 // Class Details for DEMOLITION MAN @@ -879,6 +885,8 @@ #define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV #define PC_DEMOMAN_GRENADE_INIT_1 4 #define PC_DEMOMAN_GRENADE_INIT_2 4 +#define PC_DEMOMAN_GRENADE_MAX_1 4 +#define PC_DEMOMAN_GRENADE_MAX_2 4 #define PC_DEMOMAN_TF_ITEMS 0 // Class Details for COMBAT MEDIC @@ -907,6 +915,8 @@ #define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION #define PC_MEDIC_GRENADE_INIT_1 3 #define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_GRENADE_MAX_1 4 +#define PC_MEDIC_GRENADE_MAX_2 4 #define PC_MEDIC_TF_ITEMS 0 #define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. #define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. @@ -942,6 +952,8 @@ #define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV #define PC_HVYWEAP_GRENADE_INIT_1 4 #define PC_HVYWEAP_GRENADE_INIT_2 1 +#define PC_HVYWEAP_GRENADE_MAX_1 4 +#define PC_HVYWEAP_GRENADE_MAX_2 4 #define PC_HVYWEAP_TF_ITEMS 0 @@ -969,6 +981,8 @@ #define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM #define PC_PYRO_GRENADE_INIT_1 1 #define PC_PYRO_GRENADE_INIT_2 4 +#define PC_PYRO_GRENADE_MAX_1 4 +#define PC_PYRO_GRENADE_MAX_2 4 #define PC_PYRO_TF_ITEMS 0 // Class Details for SPY @@ -995,6 +1009,8 @@ #define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS #define PC_SPY_GRENADE_INIT_1 2 #define PC_SPY_GRENADE_INIT_2 2 +#define PC_SPY_GRENADE_MAX_1 4 +#define PC_SPY_GRENADE_MAX_2 4 #define PC_SPY_TF_ITEMS 0 #define PC_SPY_CELL_REGEN_TIME 5 #define PC_SPY_CELL_REGEN_AMOUNT 1 @@ -1025,6 +1041,8 @@ #define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP #define PC_ENGINEER_GRENADE_INIT_1 2 #define PC_ENGINEER_GRENADE_INIT_2 2 +#define PC_ENGINEER_GRENADE_MAX_1 4 +#define PC_ENGINEER_GRENADE_MAX_2 4 #define PC_ENGINEER_TF_ITEMS 0 // Class Details for CIVILIAN @@ -1051,6 +1069,8 @@ #define PC_CIVILIAN_GRENADE_TYPE_2 0 #define PC_CIVILIAN_GRENADE_INIT_1 0 #define PC_CIVILIAN_GRENADE_INIT_2 0 +#define PC_CIVILIAN_GRENADE_MAX_1 0 +#define PC_CIVILIAN_GRENADE_MAX_2 0 #define PC_CIVILIAN_TF_ITEMS 0 diff --git a/items.qc b/items.qc index 26ab3d4b..c05072fd 100644 --- a/items.qc +++ b/items.qc @@ -784,9 +784,9 @@ void (entity pl, float typ) PrintGrenadeType = { float (float pf_grenade_type) GetMaxGrenades = { switch(pf_grenade_type) { case GR_TYPE_NAIL: - return 1; + return PC_SOLDIER_GRENADE_MAX_2; case GR_TYPE_CALTROP: - return 3; + return PC_SCOUT_GRENADE_MAX_1; default: return 4; } diff --git a/tfortmap.qc b/tfortmap.qc index 74234235..276e391a 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -811,13 +811,16 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player.no_grenades_2 > 4) { Player.no_grenades_2 = 4; } + + // This should never happen if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > 1)) { - Player.no_grenades_1 = 1; + (Player.no_grenades_1 > GR_SOLDIER_GRENADE_MAX_2)) { + Player.no_grenades_1 = GR_SOLDIER_GRENADE_MAX_2; } + if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > 1)) { - Player.no_grenades_2 = 1; + (Player.no_grenades_2 > GR_SOLDIER_GRENADE_MAX_2)) { + Player.no_grenades_2 = GR_SOLDIER_GRENADE_MAX_2; } if (Player.ammo_detpack > Player.maxammo_detpack) { Player.ammo_detpack = Player.maxammo_detpack; @@ -1077,12 +1080,14 @@ void (entity Goal, entity Player) RemoveResults = { if (Player.no_grenades_2 > 4) Player.no_grenades_2 = 4; + // this should never happen if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > 1)) - Player.no_grenades_1 = 1; + (Player.no_grenades_1 > GR_SOLDIER_GRENADE_MAX_2)) + Player.no_grenades_1 = GR_SOLDIER_GRENADE_MAX_2; + if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > 1)) - Player.no_grenades_2 = 1; + (Player.no_grenades_2 > GR_SOLDIER_GRENADE_MAX_2)) + Player.no_grenades_2 = GR_SOLDIER_GRENADE_MAX_2; if (Player.ammo_detpack > Player.maxammo_detpack) Player.ammo_detpack = Player.maxammo_detpack; From 31b31fd482566d533f3db55a3046c5679e3abdac Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 12 Jan 2019 23:45:59 +1100 Subject: [PATCH 0524/2474] Fix misnamed constant --- tfortmap.qc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 276e391a..695c61f4 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -814,13 +814,13 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { // This should never happen if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > GR_SOLDIER_GRENADE_MAX_2)) { - Player.no_grenades_1 = GR_SOLDIER_GRENADE_MAX_2; + (Player.no_grenades_1 > PC_SOLDIER_GRENADE_MAX_2)) { + Player.no_grenades_1 = PC_SOLDIER_GRENADE_MAX_2; } if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > GR_SOLDIER_GRENADE_MAX_2)) { - Player.no_grenades_2 = GR_SOLDIER_GRENADE_MAX_2; + (Player.no_grenades_2 > PC_SOLDIER_GRENADE_MAX_2)) { + Player.no_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; } if (Player.ammo_detpack > Player.maxammo_detpack) { Player.ammo_detpack = Player.maxammo_detpack; @@ -1082,12 +1082,12 @@ void (entity Goal, entity Player) RemoveResults = { // this should never happen if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > GR_SOLDIER_GRENADE_MAX_2)) - Player.no_grenades_1 = GR_SOLDIER_GRENADE_MAX_2; + (Player.no_grenades_1 > PC_SOLDIER_GRENADE_MAX_2)) + Player.no_grenades_1 = PC_SOLDIER_GRENADE_MAX_2; if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > GR_SOLDIER_GRENADE_MAX_2)) - Player.no_grenades_2 = GR_SOLDIER_GRENADE_MAX_2; + (Player.no_grenades_2 > PC_SOLDIER_GRENADE_MAX_2)) + Player.no_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; if (Player.ammo_detpack > Player.maxammo_detpack) Player.ammo_detpack = Player.maxammo_detpack; From bd96861bfa4340cae446a7a85ab4f3be2b151388 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 13 Jan 2019 12:59:29 +1100 Subject: [PATCH 0525/2474] update spawnfull to use max grenades, lower max grens of hwguy, medic, spy --- client.qc | 2 +- defs.h | 6 ++--- tfort.qc | 70 ++++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/client.qc b/client.qc index f7e00c6d..a3975588 100644 --- a/client.qc +++ b/client.qc @@ -553,7 +553,7 @@ void () DecodeLevelParms = { feign_air = TRUE; feign_pack = TRUE; feign_msg = TRUE; - spawnfull = FALSE; + spawnfull = TRUE; stockfull = TRUE; stock_on_cap = TRUE; classtips = TRUE; diff --git a/defs.h b/defs.h index 82d2c660..4f504994 100644 --- a/defs.h +++ b/defs.h @@ -916,7 +916,7 @@ #define PC_MEDIC_GRENADE_INIT_1 3 #define PC_MEDIC_GRENADE_INIT_2 2 #define PC_MEDIC_GRENADE_MAX_1 4 -#define PC_MEDIC_GRENADE_MAX_2 4 +#define PC_MEDIC_GRENADE_MAX_2 3 #define PC_MEDIC_TF_ITEMS 0 #define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. #define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. @@ -953,7 +953,7 @@ #define PC_HVYWEAP_GRENADE_INIT_1 4 #define PC_HVYWEAP_GRENADE_INIT_2 1 #define PC_HVYWEAP_GRENADE_MAX_1 4 -#define PC_HVYWEAP_GRENADE_MAX_2 4 +#define PC_HVYWEAP_GRENADE_MAX_2 2 #define PC_HVYWEAP_TF_ITEMS 0 @@ -1010,7 +1010,7 @@ #define PC_SPY_GRENADE_INIT_1 2 #define PC_SPY_GRENADE_INIT_2 2 #define PC_SPY_GRENADE_MAX_1 4 -#define PC_SPY_GRENADE_MAX_2 4 +#define PC_SPY_GRENADE_MAX_2 2 #define PC_SPY_TF_ITEMS 0 #define PC_SPY_CELL_REGEN_TIME 5 #define PC_SPY_CELL_REGEN_AMOUNT 1 diff --git a/tfort.qc b/tfort.qc index 232b0744..90d1e502 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1595,6 +1595,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.ammo_cells = PC_SCOUT_MAXAMMO_CELL; self.armortype = PC_SCOUT_MAXARMORTYPE; + self.no_grenades_1 = PC_SCOUT_GRENADE_MAX_1; + self.no_grenades_2 = PC_SCOUT_GRENADE_MAX_2; if (old_hp_armor) self.armorvalue = 50; else @@ -1605,6 +1607,9 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SCOUT_INITAMMO_SHOT; self.ammo_cells = PC_SCOUT_INITAMMO_CELL; self.armortype = PC_SCOUT_INITARMORTYPE; + self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1; + self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2; + if (old_hp_armor) self.armorvalue = 25; else @@ -1621,8 +1626,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL; self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL; - self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1; - self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2; if (old_grens == 1) self.tp_grenades_1 = GR_TYPE_FLASH; @@ -1657,6 +1660,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.ammo_cells = PC_SNIPER_MAXAMMO_CELL; self.armortype = PC_SNIPER_MAXARMORTYPE; + self.no_grenades_1 = PC_SNIPER_GRENADE_MAX_1; + self.no_grenades_2 = PC_SNIPER_GRENADE_MAX_2; if (old_hp_armor) self.armorvalue = 50; else @@ -1667,6 +1672,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SNIPER_INITAMMO_SHOT; self.ammo_cells = PC_SNIPER_INITAMMO_CELL; self.armortype = PC_SNIPER_INITARMORTYPE; + self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1; + self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2; if (old_hp_armor) self.armorvalue = 0; else @@ -1683,9 +1690,7 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL; self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL; - - self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1; - self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2; + self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2; self.tf_items = PC_SNIPER_TF_ITEMS; @@ -1711,6 +1716,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.ammo_cells = PC_SOLDIER_MAXAMMO_CELL; self.armortype = PC_SOLDIER_MAXARMORTYPE; + self.no_grenades_1 = PC_SOLDIER_GRENADE_MAX_1; + self.no_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; if (old_hp_armor) self.armorvalue = 200; else @@ -1721,6 +1728,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT; self.ammo_cells = PC_SOLDIER_INITAMMO_CELL; self.armortype = PC_SOLDIER_INITARMORTYPE; + self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1; + self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2; if (old_hp_armor) self.armorvalue = 100; else @@ -1738,8 +1747,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL; - self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1; - self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2; self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2; self.tf_items = PC_SOLDIER_TF_ITEMS; @@ -1766,6 +1773,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_MAXAMMO_CELL; self.armortype = PC_DEMOMAN_MAXARMORTYPE; + self.no_grenades_1 = PC_DEMOMAN_GRENADE_MAX_1; + self.no_grenades_2 = PC_DEMOMAN_GRENADE_MAX_2; if (old_hp_armor) self.armorvalue = 120; else @@ -1776,6 +1785,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL; self.armortype = PC_DEMOMAN_INITARMORTYPE; + self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1; + self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2; if (old_hp_armor) self.armorvalue = 50; else @@ -1793,8 +1804,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL; - self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1; - self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2; self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1; self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2; self.tf_items = PC_DEMOMAN_TF_ITEMS; @@ -1822,6 +1831,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.ammo_cells = PC_MEDIC_MAXAMMO_CELL; self.armortype = PC_MEDIC_MAXARMORTYPE; + self.no_grenades_1 = PC_MEDIC_GRENADE_MAX_1; + self.no_grenades_2 = PC_MEDIC_GRENADE_MAX_2; if (old_hp_armor) self.armorvalue = 100; else @@ -1832,6 +1843,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_MEDIC_INITAMMO_SHOT; self.ammo_cells = PC_MEDIC_INITAMMO_CELL; self.armortype = PC_MEDIC_INITARMORTYPE; + self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1; + self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2; if (old_hp_armor) self.armorvalue = 50; else @@ -1849,8 +1862,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL; - self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1; - self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2; self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1; self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2; self.tf_items = PC_MEDIC_TF_ITEMS; @@ -1897,6 +1908,9 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_MAXAMMO_CELL; self.armortype = PC_HVYWEAP_MAXARMORTYPE; + self.no_grenades_1 = PC_HVYWEAP_GRENADE_MAX_1; + self.no_grenades_2 = PC_HVYWEAP_GRENADE_MAX_2; + if (old_hp_armor) self.armorvalue = 300; else @@ -1907,6 +1921,9 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL; self.armortype = PC_HVYWEAP_INITARMORTYPE; + self.no_grenades_1 = PC_HVYWEAP_GRENADE_INIT_1; + self.no_grenades_2 = PC_HVYWEAP_GRENADE_INIT_2; + if (old_hp_armor) self.armorvalue = 150; else @@ -1924,8 +1941,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.maxammo_cells = PC_HVYWEAP_MAXAMMO_CELL; - self.no_grenades_1 = PC_HVYWEAP_GRENADE_INIT_1; - self.no_grenades_2 = PC_HVYWEAP_GRENADE_INIT_2; self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1; self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2; self.tf_items = PC_HVYWEAP_TF_ITEMS; @@ -1952,6 +1967,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_PYRO_MAXAMMO_SHOT; self.ammo_cells = PC_PYRO_MAXAMMO_CELL; self.armortype = PC_PYRO_MAXARMORTYPE; + self.no_grenades_1 = PC_PYRO_GRENADE_MAX_1; + self.no_grenades_2 = PC_PYRO_GRENADE_MAX_2; if (old_hp_armor) self.armorvalue = 150; else @@ -1962,6 +1979,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_PYRO_INITAMMO_SHOT; self.ammo_cells = PC_PYRO_INITAMMO_CELL; self.armortype = PC_PYRO_INITARMORTYPE; + self.no_grenades_1 = PC_PYRO_GRENADE_INIT_1; + self.no_grenades_2 = PC_PYRO_GRENADE_INIT_2; if (old_hp_armor) self.armorvalue = 50; else @@ -1979,8 +1998,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_shells = PC_PYRO_MAXAMMO_SHOT; self.maxammo_cells = PC_PYRO_MAXAMMO_CELL; - self.no_grenades_1 = PC_PYRO_GRENADE_INIT_1; - self.no_grenades_2 = PC_PYRO_GRENADE_INIT_2; self.tp_grenades_1 = PC_PYRO_GRENADE_TYPE_1; self.tp_grenades_2 = PC_PYRO_GRENADE_TYPE_2; self.tf_items = PC_PYRO_TF_ITEMS; @@ -2007,6 +2024,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; self.ammo_cells = PC_CIVILIAN_MAXAMMO_CELL; self.armortype = PC_CIVILIAN_MAXARMORTYPE; + self.no_grenades_1 = PC_CIVILIAN_GRENADE_MAX_1; + self.no_grenades_2 = PC_CIVILIAN_GRENADE_MAX_2; if (old_hp_armor) self.armorvalue = 0; else @@ -2017,6 +2036,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_CIVILIAN_INITAMMO_SHOT; self.ammo_cells = PC_CIVILIAN_INITAMMO_CELL; self.armortype = PC_CIVILIAN_INITARMORTYPE; + self.no_grenades_1 = PC_CIVILIAN_GRENADE_INIT_1; + self.no_grenades_2 = PC_CIVILIAN_GRENADE_INIT_2; if (old_hp_armor) self.armorvalue = 0; else @@ -2034,8 +2055,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; self.maxammo_cells = PC_CIVILIAN_MAXAMMO_CELL; - self.no_grenades_1 = PC_CIVILIAN_GRENADE_INIT_1; - self.no_grenades_2 = PC_CIVILIAN_GRENADE_INIT_2; self.tp_grenades_1 = PC_CIVILIAN_GRENADE_TYPE_1; self.tp_grenades_2 = PC_CIVILIAN_GRENADE_TYPE_2; self.tf_items = PC_CIVILIAN_TF_ITEMS; @@ -2060,6 +2079,9 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SPY_MAXAMMO_SHOT; self.ammo_cells = PC_SPY_MAXAMMO_CELL; self.armortype = PC_SPY_MAXARMORTYPE; + self.no_grenades_1 = PC_SPY_GRENADE_MAX_1; + self.no_grenades_2 = PC_SPY_GRENADE_MAX_2; + if (old_hp_armor) self.armorvalue = 100; else @@ -2070,6 +2092,9 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SPY_INITAMMO_SHOT; self.ammo_cells = PC_SPY_INITAMMO_CELL; self.armortype = PC_SPY_INITARMORTYPE; + self.no_grenades_1 = PC_SPY_GRENADE_INIT_1; + self.no_grenades_2 = PC_SPY_GRENADE_INIT_2; + if (old_hp_armor) self.armorvalue = 25; else @@ -2086,9 +2111,7 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SPY_MAXAMMO_NAIL; self.maxammo_shells = PC_SPY_MAXAMMO_SHOT; self.maxammo_cells = PC_SPY_MAXAMMO_CELL; - - self.no_grenades_1 = PC_SPY_GRENADE_INIT_1; - self.no_grenades_2 = PC_SPY_GRENADE_INIT_2; + self.tp_grenades_1 = PC_SPY_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SPY_GRENADE_TYPE_2; self.tf_items = PC_SPY_TF_ITEMS; @@ -2122,6 +2145,9 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.ammo_cells = PC_ENGINEER_MAXAMMO_CELL; self.armortype = PC_ENGINEER_MAXARMORTYPE; + self.no_grenades_1 = PC_ENGINEER_GRENADE_MAX_1; + self.no_grenades_2 = PC_ENGINEER_GRENADE_MAX_2; + if (old_hp_armor) self.armorvalue = 50; else @@ -2132,6 +2158,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_ENGINEER_INITAMMO_SHOT; self.ammo_cells = PC_ENGINEER_INITAMMO_CELL; self.armortype = PC_ENGINEER_INITARMORTYPE; + self.no_grenades_1 = PC_ENGINEER_GRENADE_INIT_1; + self.no_grenades_2 = PC_ENGINEER_GRENADE_INIT_2; if (old_hp_armor) self.armorvalue = 25; else @@ -2149,8 +2177,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.maxammo_cells = PC_ENGINEER_MAXAMMO_CELL; - self.no_grenades_1 = PC_ENGINEER_GRENADE_INIT_1; - self.no_grenades_2 = PC_ENGINEER_GRENADE_INIT_2; self.tp_grenades_1 = PC_ENGINEER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_ENGINEER_GRENADE_TYPE_2; self.tf_items = PC_ENGINEER_TF_ITEMS; From d86bd5483f3015a5c96eaab83c76a2b6a7f82d3d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 13 Jan 2019 15:08:42 +1100 Subject: [PATCH 0526/2474] Respawn at same spawn point when changing class immediately after spawn --- client.qc | 29 ++++++++++------------------- qw.qc | 4 ++++ tfort.qc | 2 +- tfortmap.qc | 1 - 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/client.qc b/client.qc index f7e00c6d..55add904 100644 --- a/client.qc +++ b/client.qc @@ -1091,9 +1091,15 @@ entity () SelectSpawnPoint = local entity spot; local float attempts; + if (self.spawn_at_last_spawn_spot == 1) { + self.spawn_at_last_spawn_spot = 0; + return(self.last_spawn_spot); + } + if (self.team_no != 0) { spot = FindTeamSpawnPoint(self.team_no); if (spot != world) + self.last_spawn_spot = spot; return (spot); } if (coop) { @@ -1102,6 +1108,7 @@ entity () SelectSpawnPoint = lastspawn = find(world, classname, "info_player_coop"); } if (lastspawn != world) { + self.last_spawn_spot = lastspawn; return (lastspawn); } } else { @@ -1115,6 +1122,7 @@ entity () SelectSpawnPoint = attempts = attempts + 1; if (CheckSpawnPoint(spot.origin) || (attempts >= 10)) { lastspawn = spot; + self.last_spawn_spot = spot; return (spot); } spot = find(spot, classname, "info_player_deathmatch"); @@ -1128,6 +1136,7 @@ entity () SelectSpawnPoint = if (serverflags) { spot = find(world, classname, "info_player_start2"); if (spot) { + self.last_spawn_spot = spot; return (spot); } } @@ -1139,6 +1148,7 @@ entity () SelectSpawnPoint = if (!spot) { error("PutClientInServer: no info_player_start on level\n"); } + self.last_spawn_spot = spot; return (spot); }; @@ -1148,24 +1158,6 @@ void () TeamFortress_SetEquipment; void () TeamFortress_StartTimers; void () player_touch; -// moves the client forward if spawn point is occupied -void () CheckClientSpawn = { - local float attempts; - local vector orig = self.origin; - attempts = 0; - - while (!CheckSpawnPoint(self.origin) && attempts < 30) { - makevectors(self.angles); - self.origin = self.origin + v_forward * 60; - attempts = attempts + 1; - } - - if (attempts == 30) { - dprint("Warning: Could not find a safe spawn point for player!\n"); - self.origin = orig; - } -}; - void () PutClientInServer = { local float oldclass; local entity spot; @@ -1286,7 +1278,6 @@ void () PutClientInServer = { self.origin = spot.origin + '0 0 1'; self.angles = spot.angles; self.fixangle = 1; - CheckClientSpawn(); if (self.playerclass != 0) spawn_tdeath(self.origin, self); diff --git a/qw.qc b/qw.qc index f45e97d2..3ff1733c 100644 --- a/qw.qc +++ b/qw.qc @@ -512,6 +512,10 @@ float intermission_exittime; // ability for doors to close instantly if they have a wait and are blocked .float forcecloseonblock; +// used to remember last spawn +.entity last_spawn_spot; +.float spawn_at_last_spawn_spot; + //============================================================================ void (float psize, entity p) KickPlayer = { diff --git a/tfort.qc b/tfort.qc index 232b0744..a8917ea7 100644 --- a/tfort.qc +++ b/tfort.qc @@ -178,6 +178,7 @@ void (float inp) TeamFortress_ChangeClass = { self.has_changedclass = 1; self.clientkillforce = 0; self.clientkillfree = 1; + self.spawn_at_last_spawn_spot = 1; ClientKill(); self.has_changedclass = 0; self.suicide_time = time; @@ -231,7 +232,6 @@ void (float inp) TeamFortress_ChangeClass = { self.origin = spot.origin + '0 0 1'; self.angles = spot.angles; self.fixangle = 1; - CheckClientSpawn(); setmodel(self, string_null); modelindex_null = self.modelindex; diff --git a/tfortmap.qc b/tfortmap.qc index 695c61f4..612ff3b1 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2787,7 +2787,6 @@ void (entity P) ForceRespawn = { self.origin = spot.origin + '0 0 1'; self.angles = spot.angles; self.fixangle = 1; - CheckClientSpawn(); if (self.playerclass != 0) spawn_tdeath(self.origin, self); if ((spot.classname == "info_player_teamspawn") && From f12b2f2ce65ca70db91d2c6198c0427002077508 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 13 Jan 2019 15:14:38 +1100 Subject: [PATCH 0527/2474] Fix bug where changeclass quick respawn fails sometimes --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index a8917ea7..409a849d 100644 --- a/tfort.qc +++ b/tfort.qc @@ -174,7 +174,7 @@ void (float inp) TeamFortress_ChangeClass = { return; } self.nextpc = inp; - if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { + if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint()) { self.has_changedclass = 1; self.clientkillforce = 0; self.clientkillfree = 1; From 5c1c8311aaa887a25277f762708b515fe8154647 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 13 Jan 2019 19:05:36 +1100 Subject: [PATCH 0528/2474] fix some classes going over max grenades --- items.qc | 45 ++++++++------------------------------------- qw.qc | 3 +++ tfort.qc | 22 ++++++++++++++++++++++ tfortmap.qc | 41 +++++++++++------------------------------ 4 files changed, 44 insertions(+), 67 deletions(-) diff --git a/items.qc b/items.qc index c05072fd..63901fea 100644 --- a/items.qc +++ b/items.qc @@ -485,29 +485,11 @@ void (entity p) bound_other_ammo = { if (p.armorvalue > p.maxarmor) { p.armorvalue = p.maxarmor; } - if (p.no_grenades_1 > 4) { - p.no_grenades_1 = 4; + if (p.no_grenades_1 > p.max_grenades_1) { + p.no_grenades_1 = p.max_grenades_1; } - if (p.no_grenades_2 > 4) { - p.no_grenades_2 = 4; - } - if ((p.tp_grenades_1 == 3) && (p.no_grenades_1 > 2)) { - p.no_grenades_1 = 2; - } - if ((p.tp_grenades_2 == 3) && (p.no_grenades_2 > 2)) { - p.no_grenades_2 = 2; - } - if ((p.tp_grenades_1 == 2) && (p.no_grenades_1 > 3)) { - p.no_grenades_1 = 3; - } - if ((p.tp_grenades_2 == 2) && (p.no_grenades_2 > 3)) { - p.no_grenades_2 = 3; - } - if ((p.tp_grenades_1 == 10) && (p.no_grenades_1 > 3)) { - p.no_grenades_1 = 3; - } - if ((p.tp_grenades_2 == 10) && (p.no_grenades_2 > 3)) { - p.no_grenades_2 = 3; + if (p.no_grenades_2 > p.max_grenades_2) { + p.no_grenades_2 = p.max_grenades_2; } }; @@ -781,17 +763,6 @@ void (entity pl, float typ) PrintGrenadeType = { sprint(pl, PRINT_HIGH, st); }; -float (float pf_grenade_type) GetMaxGrenades = { - switch(pf_grenade_type) { - case GR_TYPE_NAIL: - return PC_SOLDIER_GRENADE_MAX_2; - case GR_TYPE_CALTROP: - return PC_SCOUT_GRENADE_MAX_1; - default: - return 4; - } -} - void (entity pe_player, float pf_grenade_type, float pf_grenade_count) PrintFoundGrenade = { if (!pf_grenade_count) return; @@ -818,14 +789,14 @@ float () GetGrenadePossibility = { return 0; } if (random() < 0.500) { - maxg = GetMaxGrenades(other.tp_grenades_1); + maxg = other.max_grenades_1; if ((other.tp_grenades_1 != 0) && (other.no_grenades_1 < maxg)) { other.no_grenades_1 = other.no_grenades_1 + 1; PrintFoundGrenade(other, other.tp_grenades_1, 1); return 1; } } else { - maxg = GetMaxGrenades(other.tp_grenades_2); + maxg = other.max_grenades_2; if ((other.tp_grenades_2 != 0) && (other.no_grenades_2 < maxg)) { other.no_grenades_2 = other.no_grenades_2 + 1; PrintFoundGrenade(other, other.tp_grenades_2, 1); @@ -1351,7 +1322,7 @@ void () BackpackTouch = { if (drop_grenpack && other.playerclass != PC_SCOUT) { // give grenade type 1 - maxg = GetMaxGrenades(other.tp_grenades_1); + maxg = other.max_grenades_1; if ((other.no_grenades_1 + self.no_grenades_1) >= maxg) giveg = maxg - other.no_grenades_1; else @@ -1360,7 +1331,7 @@ void () BackpackTouch = { PrintFoundGrenade(other, other.tp_grenades_1, giveg); // give grenade type 2 - maxg = GetMaxGrenades(other.tp_grenades_2); + maxg = other.max_grenades_2; if ((other.no_grenades_2 + self.no_grenades_2) >= maxg) giveg = maxg - other.no_grenades_2; else diff --git a/qw.qc b/qw.qc index f45e97d2..0e73cff5 100644 --- a/qw.qc +++ b/qw.qc @@ -512,6 +512,9 @@ float intermission_exittime; // ability for doors to close instantly if they have a wait and are blocked .float forcecloseonblock; +.float max_grenades_1; +.float max_grenades_2; + //============================================================================ void (float psize, entity p) KickPlayer = { diff --git a/tfort.qc b/tfort.qc index 90d1e502..3c55d701 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1626,6 +1626,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL; self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL; + self.max_grenades_1 = PC_SCOUT_GRENADE_MAX_1; + self.max_grenades_2 = PC_SCOUT_GRENADE_MAX_2; if (old_grens == 1) self.tp_grenades_1 = GR_TYPE_FLASH; @@ -1690,6 +1692,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL; self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL; + self.max_grenades_1 = PC_SNIPER_GRENADE_MAX_1; + self.max_grenades_2 = PC_SNIPER_GRENADE_MAX_2; self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2; @@ -1746,6 +1750,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL; self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL; + self.max_grenades_1 = PC_SOLDIER_GRENADE_MAX_1; + self.max_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2; @@ -1803,6 +1809,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL; + self.max_grenades_1 = PC_DEMOMAN_GRENADE_MAX_1; + self.max_grenades_2 = PC_DEMOMAN_GRENADE_MAX_2; self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1; self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2; @@ -1861,6 +1869,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL; self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL; + self.max_grenades_1 = PC_MEDIC_GRENADE_MAX_1; + self.max_grenades_2 = PC_MEDIC_GRENADE_MAX_2; self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1; self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2; @@ -1940,6 +1950,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.maxammo_cells = PC_HVYWEAP_MAXAMMO_CELL; + self.max_grenades_1 = PC_HVYWEAP_GRENADE_MAX_1; + self.max_grenades_2 = PC_HVYWEAP_GRENADE_MAX_2; self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1; self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2; @@ -1997,6 +2009,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_PYRO_MAXAMMO_NAIL; self.maxammo_shells = PC_PYRO_MAXAMMO_SHOT; self.maxammo_cells = PC_PYRO_MAXAMMO_CELL; + self.max_grenades_1 = PC_PYRO_GRENADE_MAX_1; + self.max_grenades_2 = PC_PYRO_GRENADE_MAX_2; self.tp_grenades_1 = PC_PYRO_GRENADE_TYPE_1; self.tp_grenades_2 = PC_PYRO_GRENADE_TYPE_2; @@ -2054,6 +2068,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_CIVILIAN_MAXAMMO_NAIL; self.maxammo_shells = PC_CIVILIAN_MAXAMMO_SHOT; self.maxammo_cells = PC_CIVILIAN_MAXAMMO_CELL; + self.max_grenades_1 = PC_CIVILIAN_GRENADE_MAX_1; + self.max_grenades_2 = PC_CIVILIAN_GRENADE_MAX_2; self.tp_grenades_1 = PC_CIVILIAN_GRENADE_TYPE_1; self.tp_grenades_2 = PC_CIVILIAN_GRENADE_TYPE_2; @@ -2111,6 +2127,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SPY_MAXAMMO_NAIL; self.maxammo_shells = PC_SPY_MAXAMMO_SHOT; self.maxammo_cells = PC_SPY_MAXAMMO_CELL; + self.max_grenades_1 = PC_SPY_GRENADE_MAX_1; + self.max_grenades_2 = PC_SPY_GRENADE_MAX_2; self.tp_grenades_1 = PC_SPY_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SPY_GRENADE_TYPE_2; @@ -2176,6 +2194,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_ENGINEER_MAXAMMO_NAIL; self.maxammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.maxammo_cells = PC_ENGINEER_MAXAMMO_CELL; + self.max_grenades_1 = PC_ENGINEER_GRENADE_MAX_1; + self.max_grenades_2 = PC_ENGINEER_GRENADE_MAX_2; self.tp_grenades_1 = PC_ENGINEER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_ENGINEER_GRENADE_TYPE_2; @@ -2203,6 +2223,8 @@ void () TeamFortress_SetEquipment = { self.no_grenades_2 = 0; self.tp_grenades_1 = 0; self.tp_grenades_2 = 0; + self.max_grenades_1 = 0; + self.max_grenades_2 = 0; self.armorclass = 0; self.armortype = 0; diff --git a/tfortmap.qc b/tfortmap.qc index 695c61f4..c4114df2 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -804,24 +804,14 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.no_grenades_1 + Goal.no_grenades_1; Player.no_grenades_2 = Player.no_grenades_2 + Goal.no_grenades_2; - - if (Player.no_grenades_1 > 4) { - Player.no_grenades_1 = 4; - } - if (Player.no_grenades_2 > 4) { - Player.no_grenades_2 = 4; + + if (Player.no_grenades_1 > Player.max_grenades_1) { + Player.no_grenades_1 = Player.max_grenades_1; } - - // This should never happen - if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > PC_SOLDIER_GRENADE_MAX_2)) { - Player.no_grenades_1 = PC_SOLDIER_GRENADE_MAX_2; + if (Player.no_grenades_2 > Player.max_grenades_2) { + Player.no_grenades_2 = Player.max_grenades_2; } - if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > PC_SOLDIER_GRENADE_MAX_2)) { - Player.no_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; - } if (Player.ammo_detpack > Player.maxammo_detpack) { Player.ammo_detpack = Player.maxammo_detpack; } @@ -914,8 +904,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.ammo_medikit = Player.maxammo_medikit; Player.ammo_detpack = Player.maxammo_detpack; - Player.no_grenades_1 = GetMaxGrenades(Player.tp_grenades_1); - Player.no_grenades_2 = GetMaxGrenades(Player.tp_grenades_2); + Player.no_grenades_1 = Player.max_grenades_1; + Player.no_grenades_2 = Player.max_grenades_2; te = find(Player, classname, "timer"); @@ -1074,20 +1064,11 @@ void (entity Goal, entity Player) RemoveResults = { Player.no_grenades_1 = Player.no_grenades_1 - Goal.no_grenades_1; Player.no_grenades_2 = Player.no_grenades_2 - Goal.no_grenades_2; - if (Player.no_grenades_1 > 4) - Player.no_grenades_1 = 4; - - if (Player.no_grenades_2 > 4) - Player.no_grenades_2 = 4; - - // this should never happen - if ((Player.tp_grenades_1 == GR_TYPE_NAIL) && - (Player.no_grenades_1 > PC_SOLDIER_GRENADE_MAX_2)) - Player.no_grenades_1 = PC_SOLDIER_GRENADE_MAX_2; + if (Player.no_grenades_1 > Player.max_grenades_1) + Player.no_grenades_1 = Player.max_grenades_1; - if ((Player.tp_grenades_2 == GR_TYPE_NAIL) && - (Player.no_grenades_2 > PC_SOLDIER_GRENADE_MAX_2)) - Player.no_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; + if (Player.no_grenades_2 > Player.max_grenades_2) + Player.no_grenades_2 = Player.max_grenades_2; if (Player.ammo_detpack > Player.maxammo_detpack) Player.ammo_detpack = Player.maxammo_detpack; From deb5b54218a3acc9ced516629ca9607f49540c8b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 14 Jan 2019 21:11:38 +1100 Subject: [PATCH 0529/2474] Add centreprint for getting flag (to match dropping flag) --- tfortmap.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tfortmap.qc b/tfortmap.qc index c743aa18..654c1213 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2124,8 +2124,10 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { if (Item.items & IT_KEY1) AP.items = AP.items | IT_KEY1; + Status_Print(AP, "\n\n\n", "You got the enemy flag!"); if (Item.items & IT_KEY2) AP.items = AP.items | IT_KEY2; + Status_Print(AP, "\n\n\n", "You got the enemy flag!"); if (Goal != Item) { if (Goal.goal_result & TFGR_NO_ITEM_RESULTS) { From 5d311c904813b26da345f08342faabc6fc137b07 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 14 Jan 2019 22:58:19 +1100 Subject: [PATCH 0530/2474] Don't show got flag message if flag has message already --- tfortmap.qc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 654c1213..ce8023aa 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2124,10 +2124,18 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { if (Item.items & IT_KEY1) AP.items = AP.items | IT_KEY1; - Status_Print(AP, "\n\n\n", "You got the enemy flag!"); + if (Item.message == string_null) { + Status_Print(AP, "\n\n\n", "You got the enemy flag!"); + } else { + Status_Print(AP, "\n\n\n", AP.message); + } if (Item.items & IT_KEY2) AP.items = AP.items | IT_KEY2; - Status_Print(AP, "\n\n\n", "You got the enemy flag!"); + if (Item.message == string_null) { + Status_Print(AP, "\n\n\n", "You got the enemy flag!"); + } else { + Status_Print(AP, "\n\n\n", AP.message); + } if (Goal != Item) { if (Goal.goal_result & TFGR_NO_ITEM_RESULTS) { From c52245441c5cd4af82fbc30917cb60d643275390 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 14 Jan 2019 23:09:23 +1100 Subject: [PATCH 0531/2474] change finished reloading messages to print up high for message triggers --- weapons.qc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/weapons.qc b/weapons.qc index 2cda0173..954fcc73 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1680,7 +1680,7 @@ float () W_CheckNoAmmo = { void () W_Reload_shotgun = { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_shot.mdl"; - sprint(self.owner, PRINT_LOW, "Finished reloading\n"); + sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); @@ -1689,7 +1689,7 @@ void () W_Reload_shotgun = { void () W_Reload_super_shotgun = { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_shot2.mdl"; - sprint(self.owner, PRINT_LOW, "Finished reloading\n"); + sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); @@ -1699,7 +1699,7 @@ void (entity pl) W_Reload_sniper_rifle = { pl.reload_sniper_ticks = 0; pl.tfstate = pl.tfstate - (pl.tfstate & TFSTATE_RELOADING); pl.weaponmodel = "progs/v_srifle.mdl"; - sprint(pl, PRINT_LOW, "Finished reloading\n"); + sprint(pl, PRINT_HIGH, "Finished reloading\n"); W_WeaponState_Load(pl, 0); Status_Refresh(pl); }; @@ -1723,7 +1723,7 @@ void () W_Reload_grenade_launcher = { self.owner.weaponmodel = "progs/v_rock.mdl"; else self.owner.weaponmodel = "progs/v_pipe.mdl"; - sprint(self.owner, PRINT_LOW, "Finished reloading\n"); + sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); @@ -1732,7 +1732,7 @@ void () W_Reload_grenade_launcher = { void () W_Reload_rocket_launcher = { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); self.owner.weaponmodel = "progs/v_rock2.mdl"; - sprint(self.owner, PRINT_LOW, "Finished reloading\n"); + sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); Status_Refresh(self.owner); From 8485cc969fc67c2afbefdbf93d2ad768a1dc7304 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 14 Jan 2019 23:19:41 +1100 Subject: [PATCH 0532/2474] Don't print the entity .message twice --- tfortmap.qc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index ce8023aa..c2998eaa 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2122,20 +2122,21 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { /* if (Item.goal_activation & TFGI_ITEMGLOWS) */ /* Item.effects = EF_DIMLIGHT; */ - if (Item.items & IT_KEY1) + if (Item.items & IT_KEY1) { AP.items = AP.items | IT_KEY1; if (Item.message == string_null) { Status_Print(AP, "\n\n\n", "You got the enemy flag!"); - } else { - Status_Print(AP, "\n\n\n", AP.message); } - if (Item.items & IT_KEY2) + // else is taken care of in DoResults() + } + + if (Item.items & IT_KEY2) { AP.items = AP.items | IT_KEY2; if (Item.message == string_null) { Status_Print(AP, "\n\n\n", "You got the enemy flag!"); - } else { - Status_Print(AP, "\n\n\n", AP.message); } + // else is taken care of in DoResults() + } if (Goal != Item) { if (Goal.goal_result & TFGR_NO_ITEM_RESULTS) { From bd1dfe310564e00a5e09cd3db59dc7b56f44d066 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 18 Jan 2019 00:24:39 +1100 Subject: [PATCH 0533/2474] fix for sentry traceline issue --- sentry.qc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sentry.qc b/sentry.qc index cce61644..b4bf38bc 100644 --- a/sentry.qc +++ b/sentry.qc @@ -267,11 +267,16 @@ void () Sentry_Die = { }; float () Sentry_Fire = { - local vector dir; + local vector dir, org; self.effects = self.effects - (self.effects & EF_DIMLIGHT); + org = self.origin; + org_z = org_z + 20; + dir = self.enemy.origin - org; + dprint("enemy origin: ", vtos(self.enemy.origin), "\n"); + dprint("sentry origin: ", vtos(self.origin), "\n"); + - dir = self.enemy.origin - self.origin; if (((self.ideal_yaw - anglemod(self.angles_y)) < -10) || ((self.ideal_yaw - anglemod(self.angles_y)) > 10)) return (0); From f091b945156a9e30637c78d478ae1291a539b1f4 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 18 Jan 2019 00:41:36 +1100 Subject: [PATCH 0534/2474] remove debugs --- sentry.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/sentry.qc b/sentry.qc index b4bf38bc..e85ed4aa 100644 --- a/sentry.qc +++ b/sentry.qc @@ -273,9 +273,6 @@ float () Sentry_Fire = { org = self.origin; org_z = org_z + 20; dir = self.enemy.origin - org; - dprint("enemy origin: ", vtos(self.enemy.origin), "\n"); - dprint("sentry origin: ", vtos(self.origin), "\n"); - if (((self.ideal_yaw - anglemod(self.angles_y)) < -10) || ((self.ideal_yaw - anglemod(self.angles_y)) > 10)) From 7b0d92d19f5220220d3229a162417c91b4d238b1 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 18 Jan 2019 12:40:02 +1100 Subject: [PATCH 0535/2474] fix spelling mistake --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b1a3cad3..4c1109ba 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server v0.1.0 New features ------ * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. -* Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime n`. +* Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. * Increased nail velocity. Disable with `localinfo old_ng_velocity on`. * Nailgun and Super-nailgun damage configurable with `localinfo ng_damage` and `localinfo sng_damage`. * Keys and flags glow their colour. From bf825a0098b2f77ebd31085c87c89ab1f899640c Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Fri, 18 Jan 2019 14:40:00 -0200 Subject: [PATCH 0536/2474] admin menu interface --- admin.qc | 29 +++ commands.qc | 18 ++ defs.qc | 5 + functions.qc | 140 ++++++++++++++ menu.qc | 510 +++++++++++++++++++++++++++++++++++++++++++++++++++ mvdsv.qc | 322 ++++++++++++++++++++++++++++++++ progs.src | 5 +- qw.qc | 8 + spect.qc | 9 +- weapons.qc | 9 +- 10 files changed, 1046 insertions(+), 9 deletions(-) create mode 100644 commands.qc create mode 100644 functions.qc create mode 100644 mvdsv.qc diff --git a/admin.qc b/admin.qc index 7141a49f..6a8dbc54 100644 --- a/admin.qc +++ b/admin.qc @@ -225,3 +225,32 @@ void (entity p) CheckAutoKick = { } } }; + +void (string cl_pwd) Admin_Check = +{ + local string st2; + + st2 = infokey (world, "adminpwd"); + if ((cl_pwd != string_null)) + { + stuffcmd (self, "setinfo adminpwd \""); + stuffcmd (self, "\"\n"); + if (((st2 != string_null) && (cl_pwd == st2))) + { + self.is_admin = TRUE; + } + } +}; + +void () Admin_Aliases = +{ + TeamFortress_Alias("countplayers", 192, 0); + TeamFortress_Alias("deal", 189, 0); + TeamFortress_Alias("kick", 190, 0); + TeamFortress_Alias("ban", 191, 0); + TeamFortress_Alias("next", 195, 0); + TeamFortress_Alias("ceasefire", 193, 0); + TeamFortress_Alias("listips", 198, 0); + TeamFortress_Alias("clan", 207, 0); + TeamFortress_Alias("adminmenu", 239, 0); +}; \ No newline at end of file diff --git a/commands.qc b/commands.qc new file mode 100644 index 00000000..6c90ca7d --- /dev/null +++ b/commands.qc @@ -0,0 +1,18 @@ +void () ClanMode = +{ + local string st; + + st = infokey (world, "clan"); + if ((st == "on")) + { + st = "off"; + localcmd ("localinfo clan off\n"); + } + else + { + st = "on"; + localcmd ("localinfo clan on\n"); + bprint (2, "Map Restart needed to take affect!\n"); + } + bprint3 (2, "Clan Mode set to ", st, "\n"); +}; \ No newline at end of file diff --git a/defs.qc b/defs.qc index b946b737..1af9de34 100644 --- a/defs.qc +++ b/defs.qc @@ -286,6 +286,7 @@ float rj; // misc flag .float cnt; +.float cnt2; // subs .void () think1; @@ -415,6 +416,10 @@ float (string s) stof = #81; // convert string to float void (vector where, float set) multicast = #82; // sends the temp message to a set // of clients, possibly in PVS or PHS +void(string str) tokanize = #84; // tokanize text +float() argc = #85; // returns number of tokens +string(float num) argv_mvdsv = #86; // returns token for the given number + float (float a, float b, ...) min = #94; float (float a, float b, ...) max = #95; float (float min, float value, float max) bound = #96; diff --git a/functions.qc b/functions.qc new file mode 100644 index 00000000..4216fa07 --- /dev/null +++ b/functions.qc @@ -0,0 +1,140 @@ +float (float tno) TeamFortress_TeamSet; +float (float tno) TeamFortress_TeamGetColor; +void (entity p) SetTeamName; +void (entity pl) Menu_Close; + +void (float tno) playerSetTeam = { + local entity te; + local string st; + + TeamFortress_TeamSet (tno); + + self.team_no = tno; + + stuffcmd (self, "color "); + st = ftos (TeamFortress_TeamGetColor (tno) - 1); + stuffcmd (self, st); + stuffcmd (self, "\n"); + + SetTeamName (self); +}; + +float () PlayerCount = { + local entity te; + local float tmp = 0; + + te = find (world, classname, "player"); + while (te != world) { + tmp = tmp + 1; + te = find (te, classname, "player"); + } + + return tmp; +}; + +float () SpectatorCount = { + local entity te; + local float tmp = 0; + + te = find (world, classname, "observer"); + while (te != world) { + tmp = tmp + 1; + te = find (te, classname, "observer"); + } + return tmp; +}; + +void () nextCaptain = { + local entity te; + + te = find (world, classname, "player"); + while (te != world) { + + if (te.captain == 4) + te.captain = 3; + else if (te.captain == 3) + te.captain = 2; + else if (te.captain == 2) { + te.captain = 1; + stuffcmd(te,"reload\n"); // Required to send one impulse in order to show menu + } else if (te.captain == 1) + te.captain = number_of_teams; + + te = find (te, classname, "player"); + + } +}; + +void () disableCaptain = { + captainmode = 0; + bprint(2, "\[\sCaptain Mode\s\]\s:\s Captain Mode Disabled!\n"); +}; + +void () randomizeCaptains = { + local entity te; + local float tmp = 0; + local float teamno = 0; + local float capteam[4] = {0, 0, 0, 0}; + + te = find (world, classname, "player"); + while (te != world) { + + if (te.captain == 9 && tmp < number_of_teams) { + do { + teamno = floor((random() * number_of_teams)); + } while (capteam[teamno] == 1); + + capteam[teamno] = 1; + te.captain = teamno + 1; + + if (te.captain == 1) + stuffcmd(te, "reload\n"); + + tmp = tmp + 1; + + } + + te = find (te, classname, "player"); + } + +}; + + +void () randomizeTeams = { + local entity te, temp; + local float tmp = 0; + local float teamno = 0; + local float randteam[4] = {0, 0, 0, 0}; + + te = find (world, classname, "player"); + while (te != world) { + + if (tmp >= number_of_teams) { + tmp = 0; + randteam[0] = 0; + randteam[1] = 0; + randteam[2] = 0; + randteam[3] = 0; + } + + if (tmp < number_of_teams) { + do { + teamno = floor((random() * number_of_teams)); + } while (randteam[teamno] == 1); + + randteam[teamno] = 1; + + temp = self; + self = te; + + playerSetTeam(teamno + 1); + + self = temp; + + tmp = tmp + 1; + + } + + te = find (te, classname, "player"); + } +}; diff --git a/menu.qc b/menu.qc index c9eab004..1cc15db7 100644 --- a/menu.qc +++ b/menu.qc @@ -90,12 +90,32 @@ void (float inp) Menu_EngineerFix_SentryGun_Input; void () Menu_Dispenser; void (float inp) Menu_Dispenser_Input; +void () Menu_Admin; +void (float inp) Menu_Admin_Input; +void () Admin_DoKick; + void (entity pl) Menu_Close = { pl.menu_input = nil; Status_Print(pl, ""); + self.current_menu_type = 0; + self.current_menu_page = 0; }; +string (string text, float maxlength) Menu_Indent_line = +{ + local float spaces; + local float i; + + spaces = maxlength - (strlen(text)); + for (i = 0; i < spaces; i = i + 1) + { + text = strcat(text," "); + } + text = strcat(text,"\n"); + return text; +} + void (float inp) Menu_Input = { var f_void_float tmp; tmp = self.menu_input; @@ -996,3 +1016,493 @@ void () Menu_Engineer_Cancel = { Status_Menu(self, Menu_Engineer_Cancel_Input, s_build, s_cancel); } + +void () Menu_Admin = +{ + local string s_menu1; + local string s_menu2; + local string s_menu3; + local string s_menu4; + local string s_menu5; + local string s_menu6; + local string s_menu7; + local string s_menu8; + local string s_menu9; + + local entity te; + local entity temp; + + local float f_tmp; + local float f_tmp2; + + self.impulse = 0; + + + if (self.current_menu_type == 0) { + s_menu1 = "HueTF Admin Menu: \n\n"; + if (self.current_menu_page == 1) { + s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit \n"); + s_menu1 = strcat(s_menu1, Q"\s[3]\s Kick \n"); + s_menu1 = strcat(s_menu1, Q"\s[4]\s Ban \n"); + s_menu1 = strcat(s_menu1, Q"\s[5]\s Captain \n"); + s_menu1 = strcat(s_menu1, Q"\s[6]\s Randomize Teams \n"); + s_menu1 = strcat(s_menu1, Q"\s[7]\s Restart current map \n"); + } else if (self.current_menu_page == 2) { + s_menu1 = strcat(s_menu1, Q"\s[1]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[3]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[4]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[6]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[7]\s \n"); + } + s_menu1 = strcat(s_menu1, "\n\n"); + s_menu1 = strcat(s_menu1, Q"\s[8]\s Previous Page \n"); + s_menu1 = strcat(s_menu1, Q"\s[9]\s Next Page \n"); + s_menu1 = strcat(s_menu1, Q"\s[0]\s Exit Menu \n"); + + Status_Menu(self, Menu_Admin_Input, s_menu1); + } + +// 1 = kick selection menu +// 2 = ban selection menu +// 3 = team 1's captain select menu +// 4 = team 2's captain select menu +// 5 = captain player selection menu + + if (self.current_menu_type == 1 || self.current_menu_type == 2 || self.current_menu_type == 3 || self.current_menu_type == 4 || self.current_menu_type == 5) { + if (self.current_menu_type == 1) { + s_menu1 = "Admin Kick Menu: \n\n"; + } else if (self.current_menu_type == 2) { + s_menu1 = "Admin Ban Menu: \n\n"; + } else if (self.current_menu_type == 3) { + s_menu1 = "Captain Team 1 Select Menu: \n\n"; + } else if (self.current_menu_type == 4) { + s_menu1 = "Captain Team 2 Select Menu: \n\n"; + } else if (self.current_menu_type == 5) { + s_menu1 = strcat(Q"\[\sCaptain\s\] Team ", ftos(self.team_no)); + s_menu1 = strcat(s_menu1, " : \n\n"); + } + + f_tmp = 0; + f_tmp2 = 0; + s_menu2 = strcat (s_menu2, "\bPlayers:\b \n"); + s_menu2 = "\sPage\s "; + s_menu2 = strcat (s_menu2, ftos(self.current_menu_page)); + s_menu2 = strcat (s_menu2, "\n"); + s_menu2 = Menu_Indent_line(s_menu2, 30); + + te = find (world, classname, "player"); + while (te != world) { + if ( (f_tmp < (self.current_menu_page * 7) ) && ( f_tmp >= ((self.current_menu_page - 1) * 7) ) && ( ( ( self.current_menu_type == 5 || self.current_menu_type == 4 ) && !te.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + f_tmp2 = f_tmp2 + 1; + f_tmp = f_tmp + 1; + s_menu2 = strcat( s_menu2, Q"\s[\s" ); + s_menu2 = strcat( s_menu2, ftos(f_tmp2)); + s_menu2 = strcat( s_menu2, Q"\s]\s " ); + if (strlen(te.netname) <= 26) { + s_menu2 = strcat( s_menu2, te.netname ); + } + else { + s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + } + s_menu2 = Menu_Indent_line(s_menu2, 30); + } + + if (( f_tmp < (self.current_menu_page - 1) * 7) && ( ( ( self.current_menu_type == 5 || self.current_menu_type == 4 ) && !te.captain) || ( self.current_menu_type != 5 && self.current_menu_type != 4 ) ) ) { + f_tmp = f_tmp + 1; + } + + te = find (te, classname, "player"); + } + +if (self.current_menu_type != 3 && self.current_menu_type != 4 && self.current_menu_type != 5 ) { + te = find (world, classname, "observer"); + while (te != world) { + if ( (f_tmp <= (self.current_menu_page * 7) ) && (f_tmp > (self.current_menu_page - 1) * 7) && te.netname != "") { + f_tmp2 = f_tmp2 + 1; + s_menu2 = strcat( s_menu2, Q"\s[\s" ); + s_menu2 = strcat( s_menu2, ftos(f_tmp2)); + s_menu2 = strcat( s_menu2, Q"\s]\s " ); + s_menu2 = strcat( s_menu2, te.netname ); + if (strlen(te.netname) <= 26) { + s_menu2 = strcat( s_menu2, te.netname ); + } + else { + s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + } + s_menu2 = Menu_Indent_line(s_menu2, 30); + } + f_tmp = f_tmp + 1; + te = find (te, classname, "observer"); + } +} + +if (f_tmp == 0 && ( self.current_menu_type == 5 || self.current_menu_type == 4 ) ) { + bprint(2, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s.\n"); + temp = self; + te = find (world, classname, "player"); + while (te != world) { + te.captain = 0; + self = te; + Menu_Close(self); + te = find (te, classname, "player"); + } + self = temp; + captainmode = 0; + return; +} + s_menu2 = strcat( s_menu2, "\n"); + s_menu7 = "\b[\b8\b]\b \bPrevious Page\b "; + s_menu7 = Menu_Indent_line(s_menu7, 30); + s_menu8 = "\b[\b9\b]\b \bNext Page\b "; + s_menu8 = Menu_Indent_line(s_menu8, 30); +if (self.is_admin || self.captain == 1) { + s_menu9 = "\b[\b0\b]\b \bBack to Main Menu\b "; + s_menu9 = Menu_Indent_line(s_menu9, 30); +} else { + s_menu9 = "\n"; +} +if ((self.is_admin || self.captain == 1) && captainmode) { + s_menu9 = strcat(s_menu9, "Option 0 results in canceling captain mode.\n"); +} + + s_menu1 = strcat(s_menu1, s_menu2); + s_menu1 = strcat(s_menu1, s_menu7); + s_menu1 = strcat(s_menu1, s_menu8); + s_menu1 = strcat(s_menu1, s_menu9); + + + Status_Menu(self, Menu_Admin_Input, s_menu1); + } + + + +}; + +void (float inp) Menu_Admin_Input = +{ + local entity temp; + local entity te; + local string s_temp; + local float f_tmp; + +// Actions for AdminMenu Page 0 +if (self.current_menu_type == 0 && self.current_menu_page == 1) { + +// +// clanmode +// + + if (inp == 1) { + sprint(self,2,"TESTE CLAN MODE\n"); + localcmd("clan\n"); + Menu_Close(self); + } + +// +// timelimit +// + if (inp == 2) { + if (stof(infokey (world, "timelimit")) > 35) { + s_temp = "5"; + } else { + s_temp = ftos(timelimit/60 + 5); + } + + localcmd ("timelimit "); + localcmd(s_temp); + localcmd("\n"); + + bprint ( 2, self.netname); + bprint ( 2, " sets "); + bprint ( 2, "\stimelimit\s to: "); + bprint ( 2, s_temp); + bprint ( 2, "\n"); + } + +// +// kick +// + + if (inp == 3) { + self.current_menu_type = 1; + self.current_menu_page = 1; + Menu_Admin(); + } + +// +// ban +// + + if (inp == 4) { + self.current_menu_type = 2; + self.current_menu_page = 1; + Menu_Admin(); + } + +// +// Restart current map +// + + if (inp == 7) { + + bprint(2, self.netname); + bprint(2, " Has restarted the map.\n"); + + localcmd ("map "); + localcmd (mapname); + localcmd ("\n"); + } + +// +// Randomize Teams +// + + if (inp == 6) { + + randomizeTeams(); + + + + } + + +// +// Captain +// + + if (inp == 5) { + if (!captainmode) { + captainmode = 1; + self.current_menu_type = 3; + self.current_menu_page = 1; + + bprint(2, "\[\sCaptain Mode\s\]\s:\s is now \sON\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + + temp = find (world, classname, "player"); + while (temp != world) { + temp.captain = 0; + temp = find (temp, classname, "player"); + } + + } else { // end captainmode1 + disableCaptain(); + local entity te; + local entity temp; + te = self; + temp = find (world, classname, "player"); + while (temp != world) { + self = temp; + temp.captain = 0; + Menu_Close(self); + temp = find (temp, classname, "player"); + } + self = te; + } + Menu_Admin(); + + } + +// Actions for AdminMenu Page 1 +} else if (self.current_menu_type == 0 && self.current_menu_page == 2) { + if (inp == 1) { + sprint(self, 2, "AdminMenu Page 2 Action 1\n"); + } + else if (inp == 2) { + sprint(self, 2, "AdminMenu Page 2 Action 2\n"); + } + else if (inp == 3) { + sprint(self, 2, "AdminMenu Page 2 Action 3\n"); + } + else if (inp == 4) { + sprint(self, 2, "AdminMenu Page 2 Action 4\n"); + } + else if (inp == 5) { + sprint(self, 2, "AdminMenu Page 2 Action 5\n"); + } + else if (inp == 6) { + sprint(self, 2, "AdminMenu Page 2 Action 6\n"); + } + else if (inp == 7) { + sprint(self, 2, "AdminMenu Page 2 Action 7\n"); + } + + +} else if ((self.current_menu_type == 1 || self.current_menu_type == 2 ) && inp >= 1 && inp <= 7) { // Kick / Ban Actions + f_tmp = 1; + self.admin_use = find (world, classname, "player"); + while (self.admin_use != world) { + if (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) { + + f_tmp = f_tmp + 1; + self.admin_use = find (self.admin_use, classname, "player"); + } else { + break; + } + } + if (f_tmp < ((self.current_menu_page - 1) * 7) + inp) { + self.admin_use = find (world, classname, "observer"); + while (self.admin_use != world) { + if (f_tmp < ((self.current_menu_page - 1) * 7) + inp && self.admin_use.netname != "") { + f_tmp = f_tmp + 1; + } else { + break; + } + self.admin_use = find (self.admin_use, classname, "observer"); + } + } + + if (self.admin_use) { + if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { + self.admin_use.ip = infokey (self.admin_use, "ip"); + if (self.current_menu_type == 2) { + localcmd("addip "); + localcmd(self.admin_use.ip); + localcmd("\n"); + } + Admin_DoKick(); + } + } + +} else if ((self.current_menu_type == 3 || self.current_menu_type == 4 || self.current_menu_type == 5) && inp >= 1 && inp <= 7) { // Captain Actions + f_tmp = 1; + self.admin_use = find (world, classname, "player"); + while (self.admin_use != world) { + if ( (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + f_tmp = f_tmp + 1; + } else if ( (f_tmp == ((self.current_menu_page - 1) * 7) + inp) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + break; + } + self.admin_use = find (self.admin_use, classname, "player"); + + } + + + if (self.current_menu_type != 5) { + sprint(self,2,"TEST CAP\n"); + if (self.admin_use != world) { + sprint(self,2,"TEST CAPy\n"); + if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { + sprint(self,2,"TEST CAP2\n"); + temp = self; + self = self.admin_use; + self.captain = 9; + if (temp.current_menu_type == 3) { + // Captain for Team 1 + self.team_no = 1; + temp.current_menu_type = 4; + Menu_Admin(); + } else if (temp.current_menu_type == 4) { + // Captain for Team 2 + self.team_no = 2; + + randomizeCaptains(); + + te = find (world, classname, "player"); + while (te != world) + { + self = te; + if (!self.captain) + { + self.playerclass = 0; + playerSetTeam (-1); + self.current_menu = 0; + self.impulse = 0; + } else if (self.captain > 0 && self.captain < 5) { + //TeamFortress_TeamSet(self.team_no); + self.playerclass = 0; + playerSetTeam(self.team_no); + bprint(2, "\[\sCaptain Mode\s\]\s:\s "); + bprint(2, self.netname); + bprint(2, " \bIs the captain for team\b "); + bprint(2, TeamToString(self.team_no)); + bprint(2, "\b.\b\n"); + } + te = find (te, classname, "player"); + } + self = temp; + bprint(2, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); + Menu_Close(self); + } + self = temp; + } + } + } else { + if (self.admin_use && f_tmp == ((self.current_menu_page - 1) * 7) + inp && self.captain == 1) { + temp = self; + self = self.admin_use; + self.captain = 10; + + playerSetTeam (temp.team_no); + + bprint(2, "\[\bCaptain Mode\b\]\b:\b "); + bprint(2, temp.netname); + bprint(2, " \bcalled\b "); + bprint(2, self.netname); + bprint(2, " \bfor team\b "); + bprint(2, TeamToString(self.team_no)); + bprint(2, "\b.\b\n"); + self = temp; + + nextCaptain(); + Menu_Close(self); + } + } + + } + + + + if ((inp == 8)) { + if (self.current_menu_page > 1) { + self.current_menu_page = self.current_menu_page - 1; + } + } + + if ((inp == 9)) { + if (self.current_menu_page < 5) { + self.current_menu_page = self.current_menu_page + 1; + } + } + + + if ((inp == 10)) { + + if (self.current_menu_type == 4 || self.current_menu_type == 5 || self.current_menu_type == 3) { + captainmode = 0; + bprint(2, "\[\sCaptain Mode\s\]\s:\s \scanceled by request of\s "); + bprint(2, self.netname); + bprint(2, ".\n"); + + + te = self; + temp = find (world, classname, "player"); + while (temp != world) { + self = temp; + temp.captain = 0; + Menu_Close(self); + temp = find (temp, classname, "player"); + } + self = te; + + + + + } + + if (self.current_menu_type == 0) + Menu_Close(self); + else if (self.is_admin) { + self.current_menu_type = 0; + self.current_menu_page = 1; + Menu_Admin(); + } + } + +self.impulse = 0; +}; \ No newline at end of file diff --git a/mvdsv.qc b/mvdsv.qc new file mode 100644 index 00000000..13c40073 --- /dev/null +++ b/mvdsv.qc @@ -0,0 +1,322 @@ +float () UserCmd = +{ + local float arg_num; + local float fl; + local string tmp; + + arg_num = argc (); + if (arg_num == 0) + { + return (0); + } + if (argv_mvdsv (0) == "adminpwd") + { + if (arg_num == 2) + { + if (self.is_admin) + { + sprint (self, 2, "You are already an admin\n"); + return (1); + } + Admin_Check (argv_mvdsv (1)); + if (self.is_admin) + { + Admin_Aliases (); + } + return (1); + } + if (arg_num == 1) + { + sprint (self, 2, "usage: cmd adminpwd password, where password is the admin password\n"); + sprint (self, 2, "\n"); + return (1); + } + } + if (self.is_admin) { + //Adminpwd commands + if (argv_mvdsv (0) == "timelimit") + { + if (arg_num == 2) + { + localcmd ("timelimit "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + tmp = infokey (world, argv_mvdsv (0)); + sprint (self, 2, "timelimit is "); + sprint (self, 2, "\""); + sprint (self, 2, tmp); + sprint (self, 2, "\"\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "prematch") + { + if (arg_num == 2) + { + localcmd ("prematch "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + tmp = infokey (world, argv_mvdsv (0)); + sprint (self, 2, "prematch is "); + sprint (self, 2, "\""); + sprint (self, 2, tmp); + sprint (self, 2, "\"\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "fraglimit") + { + if (arg_num == 2) + { + localcmd ("fraglimit "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + tmp = infokey (world, argv_mvdsv (0)); + sprint (self, 2, "fraglimit is "); + sprint (self, 2, "\""); + sprint (self, 2, tmp); + sprint (self, 2, "\"\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "teamplay") + { + if (arg_num == 2) + { + localcmd ("teamplay "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + tmp = infokey (world, argv_mvdsv (0)); + sprint (self, 2, "teamplay is "); + sprint (self, 2, "\""); + sprint (self, 2, tmp); + sprint (self, 2, "\"\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "password") + { + if (arg_num == 2) + { + localcmd ("password "); + if (argv_mvdsv(1) == "none") { + localcmd ("\"\""); + } else { + localcmd (argv_mvdsv (1)); + } + localcmd ("\n"); + bprint ("\n"); + argv_mvdsv (1); + if (argv_mvdsv(1) == "none") { + bprint (2, "Server Password removed!\n"); + } else { + bprint3 (2, "Server Password changed to \"", argv_mvdsv (1), "\"\n"); + } + bprint ("\n"); + return (1); + } + if (arg_num == 1) + { + sprint (self, 2, "usage: cmd password pwd\n"); + sprint (self, 2, "\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "record") + { + if (arg_num == 2) + { + localcmd ("record "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + sprint (self, 2, "usage: cmd record demo, where demo is the demo name\n"); + sprint (self, 2, "\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "easyrecord") + { + if (arg_num == 2) + { + localcmd ("easyrecord "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + localcmd ("easyrecord\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "autorecord") + { + if (arg_num == 2) + { + localcmd ("localinfo demo_auto_left "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + tmp = infokey (world, "demo_auto_left"); + if (stof (tmp) > 0) + { + dprint ("Auto-Recording off\n"); + localcmd ("localinfo demo_auto_left 0\n"); + return (1); + } + else + { + dprint ("Auto-Recording the next match\n"); + localcmd ("localinfo demo_auto_left 1\n"); + return (1); + } + } + } + else if (argv_mvdsv (0) == "cancel") + { + localcmd ("cancel\n"); + return (1); + } + else if (argv_mvdsv (0) == "stop") + { + localcmd ("stop\n"); + return (1); + } + else if (argv_mvdsv (0) == "kick") + { + Admin_CycleDeal (); + return (1); + } + else if (argv_mvdsv (0) == "map") + { + if (self.is_admin) + { + if (clanbattle == 1 && !(cb_prematch_time > time)) + { + sprint (self, 2, "Clan Battle in progress....\n"); + self.impulse = 0; + return (1); + } + } + if (arg_num == 2) + { + bprint(2, self.netname); + bprint(2, " Has changed the map to "); + bprint(2, argv_mvdsv(1)); + bprint(2, "\n"); + localcmd ("map "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + sprint (self, 2, "usage: cmd map mapname, where mapname is the map name you wish to change to\n"); + sprint (self, 2, "\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "help" || argv_mvdsv (0) == "list") + { + sprint (self, 2, "Commands list:\n"); + sprint (self, 2, "cmd adminpwd\n"); + sprint (self, 2, "cmd timelimit\n"); + sprint (self, 2, "cmd prematch\n"); + sprint (self, 2, "cmd fraglimit\n"); + sprint (self, 2, "cmd teamplay\n"); + sprint (self, 2, "cmd password\n"); + sprint (self, 2, "cmd map\n"); + sprint (self, 2, "cmd record\n"); + sprint (self, 2, "cmd easyrecord\n"); + sprint (self, 2, "cmd autorecord\n"); + sprint (self, 2, "cmd cancel\n"); + sprint (self, 2, "cmd stop\n"); + sprint (self, 2, "cmd kick\n"); + sprint (self, 2, "cmd help || list (this command)\n"); + sprint (self, 2, "\n"); + return (1); + } + + } + + return 0; +}; + +float () ConsoleCmd { +local float arg_num; + local float fl; + local string tmp; + + arg_num = argc (); + if (arg_num == 0) + { + return (0); + } + if (argv_mvdsv (0) == "prematch") { + if (arg_num == 2) + { + localcmd ("localinfo prematch "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + tmp = infokey (world, argv_mvdsv (0)); + dprint ("prematch is "); + dprint ("\""); + dprint (tmp); + dprint ("\"\n"); + return (1); + } + } + else if (argv_mvdsv (0) == "autorecord") + { + if (arg_num == 2) + { + localcmd ("localinfo demo_auto_left "); + localcmd (argv_mvdsv (1)); + localcmd ("\n"); + return (1); + } + if (arg_num == 1) + { + tmp = infokey (world, "demo_auto_left"); + if ((stof (tmp) > 0)) + { + dprint ("Auto-Recording off\n"); + localcmd ("localinfo demo_auto_left 0\n"); + return (1); + } + else + { + dprint ("Auto-Recording the next match\n"); + localcmd ("localinfo demo_auto_left 1\n"); + return (1); + } + } + } +} \ No newline at end of file diff --git a/progs.src b/progs.src index 05fe512c..c6f68aff 100644 --- a/progs.src +++ b/progs.src @@ -5,6 +5,7 @@ qw.qc q3defs.qc debug.qc status.qc +functions.qc menu.qc vote.qc help.qc @@ -39,8 +40,10 @@ clan.qc tfort.qc tforthlp.qc tfortmap.qc +commands.qc ctf.qc coop.qc actions.qc spect.qc -q3.qc \ No newline at end of file +q3.qc +mvdsv.qc \ No newline at end of file diff --git a/qw.qc b/qw.qc index 21801ada..cdf8c32d 100644 --- a/qw.qc +++ b/qw.qc @@ -111,6 +111,11 @@ typedef void (float n) f_void_float; .float weaponmode; // Used for multiple mode weapons .float last_weaponmode; // Last weapon's weapon mode .float motd; // Used to display MOTD +.float current_menu; +.float current_menu_type; +.float current_menu_page; +.float menu_count; +.float menu_displaytime; .f_void_float menu_input; float toggleflags; // toggleable flags @@ -555,3 +560,6 @@ string (string s, float width) strpadr = return s; }; + +float captainmode; +.float captain; \ No newline at end of file diff --git a/spect.qc b/spect.qc index 8f455eb3..d72e9443 100644 --- a/spect.qc +++ b/spect.qc @@ -12,6 +12,7 @@ void () SpectatorDisconnect; void () SpectatorImpulseCommand; void () SpectatorThink; +void () Admin_Aliases; void () SpectatorConnect = { local string st; @@ -35,13 +36,7 @@ void () SpectatorConnect = { stuffcmd(self, "\"\n"); stuffcmd(self, "setinfo adminpwd \""); stuffcmd(self, "\"\n"); - TeamFortress_Alias("countplayers", 192, 0); - TeamFortress_Alias("deal", 189, 0); - TeamFortress_Alias("kick", 190, 0); - TeamFortress_Alias("ban", 191, 0); - TeamFortress_Alias("next", 195, 0); - TeamFortress_Alias("ceasefire", 193, 0); - TeamFortress_Alias("listips", 198, 0); + Admin_Aliases(); } else self.is_admin = FALSE; diff --git a/weapons.qc b/weapons.qc index 954fcc73..308c4dc0 100644 --- a/weapons.qc +++ b/weapons.qc @@ -105,6 +105,7 @@ void () HallucinationTimer; void () TranquiliserTimer; void () TeamFortress_CTF_FlagInfo; +void () ClanMode; void () W_Precache = { precache_sound("weapons/r_exp3.wav"); @@ -2523,7 +2524,7 @@ void () DeadImpulses = { } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGECLASS) && (deathmatch == 3) && (cb_prematch_time < time)) { Menu_Class(0); - } else if (self.is_admin == 1) { + } else if (self.is_admin) { if (self.impulse == 193) Admin_CeaseFire(); else if (self.impulse == 192) @@ -2538,6 +2539,12 @@ void () DeadImpulses = { Admin_CycleDeal(); else if (self.impulse == 198) Admin_ListIPs(); + else if (self.impulse == 207) + ClanMode(); + else if (self.impulse == 239) { + self.current_menu_page = 1; + Menu_Admin(); + } } if (self.impulse == TF_HELP_MAP) TeamFortress_HelpMap(); From ab7ffc9386979d07a430649f26c6ad65d0c0deba Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Fri, 18 Jan 2019 17:06:27 -0200 Subject: [PATCH 0537/2474] using huetf clan mode --- admin.qc | 100 +++++------ buttons.qc | 2 +- clan.qc | 472 ++++++++++++++++++++++++++++++++++++++++++++-------- client.qc | 106 ++++++------ engineer.qc | 2 +- items.qc | 16 +- mvdsv.qc | 2 +- pyro.qc | 10 +- qw.qc | 1 + tfort.qc | 240 ++++++++++++++++---------- tfortmap.qc | 8 +- weapons.qc | 10 +- 12 files changed, 676 insertions(+), 293 deletions(-) diff --git a/admin.qc b/admin.qc index 6a8dbc54..a55dccd1 100644 --- a/admin.qc +++ b/admin.qc @@ -122,73 +122,73 @@ void () Admin_DoBan = { self.admin_use = world; }; -void () CeaseFire_think = { +void () CeaseFire_think = +{ local entity te; + local float temp; - if ((time > cb_ceasefire_time) && (self.weapon == 1) && - (cease_fire == 1)) { - cease_fire = 0; - bprint(PRINT_HIGH, "Resume fire\n"); - te = find(world, classname, "player"); - while (te) { - CenterPrint3(te, "Resume fire\nCalled by: ", - self.owner.netname, "\n"); - te.immune_to_check = time + 10; - te.tfstate = te.tfstate - (te.tfstate & 65536); - TeamFortress_SetSpeed(te); - te = find(te, classname, "player"); - } - dremove(self); - return; - } - if (!cease_fire) { - dremove(self); + if (cease_fire == 0) + { + dremove (self); return; } te = find(world, classname, "player"); - while (te) { - CenterPrint3(te, "CEASE FIRE\nCalled by: ", self.owner.netname, - "\n"); - te = find(te, classname, "player"); + while (te) + { + CenterPrint3 (te, "CEASE FIRE\nCalled by: ", self.owner.netname, "\n"); + te = find (te, classname, "player"); } - self.nextthink = time + 5; + self.nextthink = (time + 5); }; void () Admin_CeaseFire = { - local entity te; + local entity te; - if (!cease_fire) { + if (!cease_fire) + { + if (cb_prematch) + { + StopTimer (); + } cease_fire = 1; - bprint(PRINT_HIGH, "Cease fire\n"); - te = find(world, classname, "player"); - while (te) { - CenterPrint3(te, "Cease fire\nCalled by: ", self.netname, - "\n"); - te.immune_to_check = time + 10; - te.tfstate = te.tfstate | 65536; - TeamFortress_SetSpeed(te); - te = find(te, classname, "player"); + bprint (2, "CEASE FIRE\n"); + te = find (world, classname, "player"); + while (te) + { + CenterPrint3 (te, "CEASE FIRE\nCalled by: ", self.netname, "\n"); + te.immune_to_check = (time + 5); + te.tfstate = (te.tfstate | 65536); + TeamFortress_SetSpeed (te); + te = find (te, classname, "player"); } - te = spawn(); + te = spawn (); te.owner = self; te.classname = "ceasefire"; te.think = CeaseFire_think; - te.nextthink = time + 5; - } else { - te = find(world, classname, "ceasefire"); + te.nextthink = (time + 5); + } + else + { + te = find (world, classname, "ceasefire"); if (te) - dremove(te); - + { + dremove (te); + } cease_fire = 0; - bprint(PRINT_HIGH, "Resume fire\n"); - te = find(world, classname, "player"); - while (te) { - CenterPrint3(te, "Resume fire\nCalled by: ", self.netname, - "\n"); - te.immune_to_check = time + 10; - te.tfstate = te.tfstate - (te.tfstate & 65536); - TeamFortress_SetSpeed(te); - te = find(te, classname, "player"); + if (cb_prematch) + { + cb_prematch_time = 0; + StartTimer (); + } + bprint (2, "RESUME FIRE\n"); + te = find (world, classname, "player"); + while (te) + { + CenterPrint3 (te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); + te.immune_to_check = (time + 5); + te.tfstate = (te.tfstate - (te.tfstate & 65536)); + TeamFortress_SetSpeed (te); + te = find (te, classname, "player"); } } }; diff --git a/buttons.qc b/buttons.qc index baf1d3d8..62031067 100644 --- a/buttons.qc +++ b/buttons.qc @@ -64,7 +64,7 @@ void () button_use = { void () button_touch = { local entity te; - if (cb_prematch_time > time) + if (cb_prematch) return; if (other.classname != "player") diff --git a/clan.qc b/clan.qc index 37c5b4f0..d7f7d782 100644 --- a/clan.qc +++ b/clan.qc @@ -1,65 +1,87 @@ -void () PreMatch_Think = { - local float time_left; - local string st; - local entity te; - local entity oldself; - local entity gren; +void () MatchThink = +{ + local string tmp; - time_left = rint(cb_prematch_time - time); - if (time_left > 60) { - st = ftos(time_left / 60); - bprint2(PRINT_HIGH, st, " minutes left till match begins\n"); - if (time_left < 120) { - self.nextthink = time + time_left - 60; - } else { - self.nextthink = time + 60; - } - return; - } else if (time_left >= 59) { - bprint(PRINT_HIGH, "1 minute left till match begins\n"); - self.nextthink = time + 30; + if ((self.cnt == -1)) + { return; - } else if (time_left >= 29) { - bprint(PRINT_HIGH, "30 seconds left till match begins\n"); - self.nextthink = time + 20; - return; - } else if (time_left > 1) { - st = ftos(time_left); - bprint2(PRINT_HIGH, st, " seconds\n"); - self.nextthink = time + 1; + } + if (cease_fire) + { + self.nextthink = (time + 1); return; - } else if (time_left > 0) { - bprint(PRINT_HIGH, "1 second\n"); - self.nextthink = time + 1; + } + self.cnt2 = (self.cnt2 - 1); + if (!TeamFortress_GetNoPlayers ()) + { + NextLevel (); return; } - bprint(PRINT_HIGH, "Match begins now\n"); - if (game_locked) - bprint(PRINT_HIGH, "Game is now locked\n"); + if ( self.cnt == cvar("timelimit") - 1 && self.cnt2 == 59 ) + { + localcmd ("serverinfo status \""); + tmp = ftos (self.cnt + 1); + localcmd (tmp); + localcmd (" min left\"\n"); + } - if (infokey (world, "serverdemo") == "on") + if (self.cnt2 == 1) { + localcmd ("serverinfo status \""); + tmp = ftos (self.cnt + 1); + localcmd (tmp); + localcmd (" min left\"\n"); + } + + if ((self.cnt2 == -1)) + { + self.cnt2 = 59; + self.cnt = (self.cnt - 1); + } + if (!self.cnt2) + { + if (((self.cnt == 1) || (self.cnt == 5))) { - calltimeofday (); - - localcmd ("record \""); - localcmd (ftos (tod_day)); // day - localcmd ("-"); - localcmd (ftos (tod_mon)); // month - localcmd ("-"); - localcmd (ftos (tod_year)); // year - localcmd ("_"); - localcmd (ftos (tod_hour)); // hour - localcmd ("-"); - localcmd (ftos (tod_min)); // minute - localcmd ("-"); - localcmd (ftos (tod_sec)); // second - - localcmd ("_["); - localcmd (mapname); - localcmd ("]"); - localcmd ("\"\n"); + tmp = ftos (self.cnt); + bprint3 (2, "", tmp, "β€˜ minute"); + if ((self.cnt != 1)) + { + bprint (2, "s"); + } + bprint (2, " remaining\n"); + } + if (!self.cnt) + { + self.think = SUB_Remove; + self.nextthink = (time + 0.1); + NextLevel (); + return; } + } + if ((!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= 10)))) + { + tmp = ftos (self.cnt2); + bprint3 (2, "", tmp, "β€˜ second"); + if ((self.cnt2 != 1)) + { + bprint (2, "s"); + } + bprint (2, " remaining\n"); + } + self.nextthink = (time + 1); +}; + +void () StartMatch = +{ + local string st; + local float f1; + local float f2; + local entity te; + local entity oldself; + local entity gren; + + lightstyle (0, "m"); + bprint (2, "MATCH BEGINS NOW\n"); team4score = 0; team3score = 0; @@ -69,34 +91,336 @@ void () PreMatch_Think = { team3frags = 0; team2frags = 0; team1frags = 0; + te = find (world, classname, "player"); - te = find(world, classname, "player"); - while (te) { + while (te) + { oldself = self; self = te; - if (self.tf_id == 0) { - last_id = last_id + 20 + random() * 10; - self.tf_id = rint(random() * 10 + last_id); - st = ftos(self.tf_id); - stuffcmd(self, "setinfo tf_id "); - stuffcmd(self, st); - stuffcmd(self, "\n"); - sprint(self, PRINT_HIGH, "Your battle ID is ", st, "\n"); - } - TeamFortress_RemoveTimers(); + + TeamFortress_RemoveTimers (); self.frags = 0; - self.real_frags = 0; - gren = find(world, classname, "grenade"); - while (gren) { - if (gren.owner == self) { - gren.nextthink = time + 0.1; + self.real_frags = 0; + setspawnparms (self); + if (infokey(world, "quadmode") != "on") + PutClientInServer (); + self = oldself; + te = find (te, classname, "player"); + } + gren = find (world, classname, "grenade"); + while (gren) + { + gren.think = GrenadeExplode; + gren.nextthink = (time + 0.1); + gren = find (gren, classname, "grenade"); + } + cb_prematch = 0; + cease_fire = 0; + te = find (world, classname, "prematch"); + te.classname = "match"; + te.cnt = (timelimit / 60); + te.cnt2 = 60; + if ((te.cnt == 0)) + { + bprint (2, "Warning no timelimit set!\n"); + localcmd ("\nserverinfo status \"0 min left\"\n"); + te.cnt = -1; + te.cnt2 = -1; + } + else + { + te.cnt = (te.cnt - 1); + localcmd ("\nserverinfo status \""); + st = ftos (te.cnt); + localcmd (st); + localcmd (" min left\"\n"); + if (infokey(world, "quadmode") != "on") { + te.think = MatchThink; + te.nextthink = (time + 1); + } + } + st = infokey (world, "spectalk"); + f2 = stof (st); + if (!f2) + { + st = "0"; + } + localcmd ("sv_spectalk "); + localcmd (st); + localcmd ("\n"); + f1 = stof (infokey (world, "fpd")); + f1 = ((f1 - (f1 & 64)) + (f2 * 64)); + localcmd ("serverinfo fpd "); + st = ftos (f1); + localcmd (st); + localcmd ("\n"); + + st = infokey(world, "quadmode"); +}; + +void () PreMatch_Think = { + local entity p; + local string num, tmp; + local float fl; + + self.cnt2 = (self.cnt2 - 1); + if ((self.cnt2 == 1)) + { + p = find (world, classname, "player"); + while ((p != world)) + { + if ((p.netname != "")) + { + p.respawn_time = (time + 2); + p.takedamage = 0; + p.solid = 0; + p.movetype = 0; + p.modelindex = 0; + p.model = string_null; } - gren = find(gren, classname, "grenade"); + p = find (p, classname, "player"); } - TF_T_Damage(self, world, world, self.health + 1, 1, 0); - self = oldself; - te = find(te, classname, "player"); } + else + { + if (!self.cnt2) + { + self.nextthink = (time + 0.1); + self.think = SUB_Remove; + p = find (world, classname, "player"); + while ((p != world)) + { + if ((p.netname != "")) + { + p.takedamage = 2; + p.solid = 3; + p.movetype = 3; + } + p = find (p, classname, "player"); + } + StartMatch (); + return; + } + } + fl = (self.cnt2 / 60); + if (fl == 1 || fl == 2 || fl == 3 || fl == 4 || fl == 5 || fl == 6 || fl == 7 || fl == 8 || fl == 9 || fl == 10) + { + num = ftos (fl); + bprint3 (2, "Match will begin in ", num, " minute(s).\n"); + } + if ((self.cnt2 == 30)) + { + num = ftos ((self.cnt2 / 60)); + bprint (2, "Match will begin in 30 seconds.\n"); + } + if ((self.cnt2 <= 10)) + { + if ((self.cnt2 == 10)) + { + lightstyle (0, "e"); + localcmd ("serverinfo status Countdown\n"); + + if ((stof (infokey (world, "demo_auto_left")) > 0)) + { + if (infokey (world, "serverdemo") == "on") + { + calltimeofday (); + + localcmd ("record \""); + localcmd (ftos (tod_day)); // day + localcmd ("-"); + localcmd (ftos (tod_mon)); // month + localcmd ("-"); + localcmd (ftos (tod_year)); // year + localcmd ("_"); + localcmd (ftos (tod_hour)); // hour + localcmd ("-"); + localcmd (ftos (tod_min)); // minute + localcmd ("-"); + localcmd (ftos (tod_sec)); // second + + localcmd ("_["); + localcmd (mapname); + localcmd ("]"); + localcmd ("\"\n"); + } + } + } + num = ftos (self.cnt2); + p = find (world, classname, "player"); + tmp = strcat(num ,"\n\n\b:[\b"); + tmp = strcat(tmp, mapname); + tmp = strcat(tmp, "\b]:\b"); + strcat(tmp, "\n"); + + while ((p != world)) + { + if ((p.netname != "")) + { + CenterPrint3 (p, "Countdown ", tmp, "\n"); + if ((self.cnt2 < 6)) + { + cease_fire = 0; + stuffcmd (p, "play buttons/switch04.wav\n"); + } + } + p = find (p, classname, "player"); + } + if ((self.cnt2 > 1)) + { + bprint2 (2, num, " seconds.\n"); + } + else + { + bprint (2, "1 second.\n"); + } + } + self.nextthink = (time + 1); +}; + +void () StartTimer = +{ + local entity timer; + local entity p; + local float f1; + local string tmp; + + if ((clanbattle == 0)) + { + if ((self != world)) + { + sprint (self, 2, "Clan mode off....\n"); + sprint (self, 2, "Match cannot be started.\n"); + } + else + { + dprint ("Clan mode off....\n"); + dprint ("Match cannot be started.\n"); + } + return; + } + if (((clanbattle == 1) && (cb_prematch == 0))) + { + if ((self != world)) + { + sprint (self, 2, "Clan Battle in progress....\n"); + sprint (self, 2, "Type break to stop the current battle.\n"); + } + else + { + dprint ("Clan Battle in progress....\n"); + dprint ("Type break to stop the current battle.\n"); + } + return; + } + if ((infokey (world, "status") == "Countdown")) + { + if ((self != world)) + { + sprint (self, 2, "Countdown in progress....\n"); + } + else + { + dprint ("Countdown in progress....\n"); + } + return; + } + timer = find (world, classname, "prematch"); + while ((timer != world)) + { + dremove (timer); + timer = find (timer, classname, "prematch"); + } + f1 = stof (infokey (world, "prematch")); + timer = spawn (); + timer.owner = world; + timer.classname = "prematch"; + timer.cnt = 0; + if (cb_prematch_time) + { + timer.cnt2 = rint ((cb_prematch_time * 60)); + if ((timer.cnt2 < 1)) + { + timer.cnt2 = 1; + } + } + else + { + lightstyle (0, "e"); + if ((stof (infokey (world, "demo_auto_left")) > 0)) + { + if (infokey (world, "serverdemo") == "on") + { + calltimeofday (); + + localcmd ("record \""); + localcmd (ftos (tod_day)); // day + localcmd ("-"); + localcmd (ftos (tod_mon)); // month + localcmd ("-"); + localcmd (ftos (tod_year)); // year + localcmd ("_"); + localcmd (ftos (tod_hour)); // hour + localcmd ("-"); + localcmd (ftos (tod_min)); // minute + localcmd ("-"); + localcmd (ftos (tod_sec)); // second + + localcmd ("_["); + localcmd (mapname); + localcmd ("]"); + localcmd ("\"\n"); + } + } + localcmd ("serverinfo status Countdown\n"); + p = find (world, classname, "player"); + while ((p != world)) + { + if ((p.netname != "")) + { + stuffcmd (p, "play items/protect2.wav\n"); + } + p = find (timer, classname, "player"); + } + timer.cnt2 = rint (stof (infokey (world, "count"))); + if ((timer.cnt2 < 1)) + { + timer.cnt2 = 0; + } + } + timer.cnt2 = (timer.cnt2 + 1); + timer.nextthink = (time + 0.1); + tmp = ftos (timer.cnt2); + timer.think = PreMatch_Think; +}; + +void () StopTimer = +{ + local entity t; + + if ((infokey (world, "serverdemo") != string_null)) + { + localcmd ("cancel\n"); + } + if (cb_prematch) + { + t = find (world, classname, "prematch"); + while ((t != world)) + { + t.nextthink = (time + 0.1); + t.think = SUB_Remove; + t = find (t, classname, "prematch"); + } + localcmd ("serverinfo status Standby\n"); + lightstyle (0, "m"); + return; + } + t = find (world, classname, "match"); + if ((t != world)) + { + remove (t); + } + localcmd ("serverinfo status Normal\n"); }; void () DumpClanScores = { diff --git a/client.qc b/client.qc index a9c12fb5..5039f55d 100644 --- a/client.qc +++ b/client.qc @@ -50,6 +50,8 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer; void () CTF_FlagCheck; void (entity pl) Sniper_ZoomReset; +void () StartTimer; +void () StopTimer; string nextmap; @@ -253,69 +255,48 @@ void () DecodeLevelParms = { clanbattle = CF_GetSetting("c", "clan", "off"); if (clanbattle) { - + localcmd ("serverinfo status Standby\n"); + clan_scores_dumped = 0; game_locked = 0; + cb_prematch = 1; cb_prematch_time = CF_GetSetting("pm", "prematch", "0"); - cb_prematch_time = time + cb_prematch_time * 60; - - if (timelimit && ((time + timelimit) < cb_prematch_time)) { - - timelimit = timelimit + cb_prematch_time; - ti = ceil(timelimit / 60); - st = ftos(ti); - cvar_set("timelimit", st); - - } - if (cb_prematch_time > time) { - - cb_prematch_time = cb_prematch_time + 5; - ent = spawn(); - ent.think = PreMatch_Think; - ent.nextthink = time + 5; - + if (cb_prematch_time) + { + StartTimer(); } - - cb_ceasefire_time = CF_GetSetting("cft", "ceasefire_time", "0"); - if (cb_ceasefire_time != 0) { - - cb_ceasefire_time = time + cb_ceasefire_time * 60; - if (cb_prematch_time < cb_ceasefire_time) { - - cb_prematch_time = cb_ceasefire_time + 5; - if (timelimit && - ((time + timelimit) < cb_prematch_time)) { - - timelimit = timelimit + cb_ceasefire_time; - ti = ceil(timelimit / 60); - st = ftos(ti); - cvar_set("timelimit", st); - + if (!cb_prematch_time) { + cb_ceasefire_time = CF_GetSetting("cft", "ceasefire_time", "0"); + if (cb_ceasefire_time) { + + cease_fire = 1; + bprint (2, "CEASE FIRE\n"); + te = find (world, classname, "player"); + while (te) + { + centerprint (te, "CEASE FIRE\n"); + te.immune_to_check = (time + 5); + te.tfstate = (te.tfstate | TFSTATE_CANT_MOVE); + TeamFortress_SetSpeed (te); + te = find (te, classname, "player"); } - - } - cease_fire = 1; - bprint(PRINT_HIGH, "Cease fire\n"); - - te = find(world, classname, "player"); - while (te) { - centerprint(te, "Cease fire\n"); - te.immune_to_check = time + 10; - te.tfstate = te.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(te); - te = find(te, classname, "player"); - } - te = spawn(); - te.classname = "ceasefire"; - te.think = CeaseFire_think; - te.nextthink = time + 5; - + te = spawn (); + te.classname = "ceasefire"; + te.think = CeaseFire_think; + te.nextthink = (time + 5); + te.weapon = 1; + StartTimer(); + + } } + game_locked = CF_GetSetting("lg", "locked_game", "off"); - } else + } else { clanbattle = FALSE; + localcmd ("serverinfo status Normal\n"); + } // automatically assign team [off] fl = CF_GetSetting("a", "autoteam", "off"); @@ -1435,6 +1416,10 @@ void () DumpScore = { float already_cycled; void () NextLevel = { + bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); + bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); + bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); + bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); local entity o; if (already_cycled) @@ -1448,7 +1433,18 @@ void () NextLevel = { }; void () CheckRules = { - if ((timelimit && time >= timelimit) || (fraglimit && self.frags >= fraglimit)) { + if (!clanbattle) + { + if ((timelimit && (time >= timelimit))) + { + NextLevel(); + RemoveGrenadeTimers(); + RemovePrimeTimers(); + RemoveGrenades(); + } + } + if ((fraglimit && (self.frags >= fraglimit))) + { NextLevel(); RemoveGrenadeTimers(); RemovePrimeTimers(); @@ -2070,7 +2066,7 @@ void () ClientConnect = { sprint(self, PRINT_HIGH, "Your battle ID is ", st, "\n"); } } - if (cb_prematch_time > time) + if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in prematch time\n"); }; diff --git a/engineer.qc b/engineer.qc index 7648747f..ac5b92fb 100644 --- a/engineer.qc +++ b/engineer.qc @@ -346,7 +346,7 @@ float (entity obj, entity builder) CheckArea = { }; void (float objtobuild) TeamFortress_Build = { - if (cb_prematch_time > time) { + if (cb_prematch) { sprint(self, PRINT_MEDIUM, "You cannot build during prematch\n"); return; } diff --git a/items.qc b/items.qc index 63901fea..ae1790bd 100644 --- a/items.qc +++ b/items.qc @@ -226,7 +226,7 @@ void () health_touch = { if ((other.tfstate & 65536) || (other.tfstate & 2048)) { return; } - if (cb_prematch_time > time) { + if (cb_prematch == 1) { return; } medi = 0; @@ -332,7 +332,7 @@ void () armor_touch = { if ((other.tfstate & 65536) || (other.tfstate & 2048)) { return; } - if (cb_prematch_time > time) { + if (cb_prematch == 1) { return; } if (self.classname == "item_armor1") { @@ -550,7 +550,7 @@ void () weapon_touch = { return; if ((other.tfstate & 65536) || (other.tfstate & 2048)) return; - if (cb_prematch_time > time) + if (cb_prematch == 1) return; stemp = self; @@ -821,7 +821,7 @@ void () ammo_touch = { if ((other.tfstate & 65536) || (other.tfstate & 2048)) { return; } - if (cb_prematch_time > time) { + if (cb_prematch == 1) { return; } gotgren = 0; @@ -1028,7 +1028,7 @@ void () key_touch = { if ((other.tfstate & 65536) || (other.tfstate & 2048)) { return; } - if (cb_prematch_time > time) { + if (cb_prematch == 1) { return; } sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); @@ -1128,7 +1128,7 @@ void () sigil_touch = { return; if ((other.tfstate & 65536) || (other.tfstate & 2048)) return; - if (cb_prematch_time > time) + if (cb_prematch == 1) return; sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); @@ -1181,7 +1181,7 @@ void () powerup_touch = { return; if ((other.tfstate & 65536) || (other.tfstate & 2048)) return; - if (cb_prematch_time > time) + if (cb_prematch == 1) return; sprint(other, PRINT_LOW, "You got the "); @@ -1376,7 +1376,7 @@ void () BackpackTouch = { }; void () DropBackpack = { - if ((cb_prematch_time + 3) > time) + if (cb_prematch == 1) return; if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) { diff --git a/mvdsv.qc b/mvdsv.qc index 13c40073..6bc79f2f 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -214,7 +214,7 @@ float () UserCmd = { if (self.is_admin) { - if (clanbattle == 1 && !(cb_prematch_time > time)) + if (clanbattle == 1 && !(cb_prematch)) { sprint (self, 2, "Clan Battle in progress....\n"); self.impulse = 0; diff --git a/pyro.qc b/pyro.qc index 23123a28..9049e7fe 100644 --- a/pyro.qc +++ b/pyro.qc @@ -10,7 +10,7 @@ float (string id_flame) RemoveFlameFromQueue; entity(string type, entity p_owner) FlameSpawn = { - if (cb_prematch_time > time) { + if (cb_prematch) { return (world); } if (type != "1") { @@ -317,7 +317,7 @@ void () OnPlayerFlame_touch = { local vector vtemp; if (((other != world) && (other.health > 0)) && (other != self.enemy)) { - if (cb_prematch_time > time) { + if (cb_prematch) { return; } if (other.numflames >= 4) { @@ -375,7 +375,7 @@ void () WorldFlame_touch = { self.nextthink = time + 1; } if (((other != world) && (other.solid != 1)) && (other.health > 0)) { - if (cb_prematch_time > time) { + if (cb_prematch) { return; } if (other.numflames >= 4) { @@ -433,7 +433,7 @@ void () Flamer_stream_touch = { TF_T_Damage(other, self, self.owner, 10, TF_TD_NOTTEAM, TF_TD_FIRE); - if (cb_prematch_time > time) { + if (cb_prematch) { return; } if (other.numflames >= 4) { @@ -506,7 +506,7 @@ void () Napalm_touch = { deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, 6, TF_TD_NOTTEAM, TF_TD_FIRE); - if (cb_prematch_time > time) { + if (cb_prematch) { return; } if (other.numflames >= 4) { diff --git a/qw.qc b/qw.qc index cdf8c32d..ac98ec7c 100644 --- a/qw.qc +++ b/qw.qc @@ -424,6 +424,7 @@ float already_chosen_map; float clanbattle; float clan_scores_dumped; +float cb_prematch; float cb_prematch_time; float cb_ceasefire_time; float game_locked; diff --git a/tfort.qc b/tfort.qc index 1c08ba7b..d5421733 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1071,111 +1071,173 @@ float (float pc) IsLegalClass = { return (TRUE); }; -void (entity p) TeamFortress_SetSpeed = { +void (entity p) TeamFortress_SetSpeed = +{ local string sp; local float tf; local entity te; + local string st; - stuffcmd(p, "cl_movespeedkey 1\n"); - if (p.tfstate & TFSTATE_CANT_MOVE || p.is_building == 1 || p.is_detpacking > 0) { -#ifdef STOP_MOUSE_MOVEMENT - stuffcmd(p, "m_forward 0\n"); - stuffcmd(p, "m_side 0\n"); -#endif + stuffcmd (p, "cl_movespeedkey 1\n"); + if ((p.tfstate & 65536)) + { + if ((0 == 1)) + { + stuffcmd (p, "m_forward 0\n"); + stuffcmd (p, "m_side 0\n"); + } p.velocity = '0 0 0'; - stuffcmd(p, "cl_backspeed 0\n"); - stuffcmd(p, "cl_forwardspeed 0\n"); - stuffcmd(p, "cl_sidespeed 0\n"); + stuffcmd (p, "cl_backspeed 0\n"); + stuffcmd (p, "cl_forwardspeed 0\n"); + stuffcmd (p, "cl_sidespeed 0\n"); p.maxspeed = 0; return; } -#ifdef STOP_MOUSE_MOVEMENT - else { - stuffcmd(p, "m_forward 1\n"); - stuffcmd(p, "m_side 0.8\n"); - } -#endif - if (p.playerclass == PC_SCOUT) { - p.maxfbspeed = PC_SCOUT_MAXSPEED; - p.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED; - } else if (p.playerclass == PC_SNIPER) { - p.maxfbspeed = PC_SNIPER_MAXSPEED; - p.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED; - } else if (p.playerclass == PC_SOLDIER) { - p.maxfbspeed = PC_SOLDIER_MAXSPEED; - p.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED; - } else if (p.playerclass == PC_DEMOMAN) { - p.maxfbspeed = PC_DEMOMAN_MAXSPEED; - p.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED; - } else if (p.playerclass == PC_MEDIC) { - p.maxfbspeed = PC_MEDIC_MAXSPEED; - p.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED; - } else if (p.playerclass == PC_HVYWEAP) { - p.maxfbspeed = PC_HVYWEAP_MAXSPEED; - p.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED; - } else if (p.playerclass == PC_PYRO) { - p.maxfbspeed = PC_PYRO_MAXSPEED; - p.maxstrafespeed = PC_PYRO_MAXSTRAFESPEED; - } else if (p.playerclass == PC_CIVILIAN) { - p.maxfbspeed = PC_CIVILIAN_MAXSPEED; - p.maxstrafespeed = PC_CIVILIAN_MAXSTRAFESPEED; - } else if (p.playerclass == PC_SPY) { - p.maxfbspeed = PC_SPY_MAXSPEED; - p.maxstrafespeed = PC_SPY_MAXSTRAFESPEED; - } else if (p.playerclass == PC_ENGINEER) { - p.maxfbspeed = PC_ENGINEER_MAXSPEED; - p.maxstrafespeed = PC_ENGINEER_MAXSTRAFESPEED; - } else if (p.playerclass == PC_UNDEFINED) { -// p.maxfbspeed = 320; -// p.maxstrafespeed = 320; - p.maxfbspeed = 0; - p.maxstrafespeed = 0; - p.maxspeed = 0; - return; + else + { + if ((0 == 1)) + { + stuffcmd (p, "m_forward 1\n"); + stuffcmd (p, "m_side 0.8\n"); + } + } + if ((p.playerclass == 1)) + { + p.maxspeed = 450; + } + else + { + if ((p.playerclass == 2)) + { + p.maxspeed = 300; + } + else + { + if ((p.playerclass == 3)) + { + p.maxspeed = 240; + } + else + { + if ((p.playerclass == 4)) + { + p.maxspeed = 280; + } + else + { + if ((p.playerclass == 5)) + { + p.maxspeed = 320; + } + else + { + if ((p.playerclass == 6)) + { + p.maxspeed = 230; + } + else + { + if ((p.playerclass == 7)) + { + p.maxspeed = 300; + } + else + { + if ((p.playerclass == 11)) + { + p.maxspeed = 240; + } + else + { + if ((p.playerclass == 8)) + { + p.maxspeed = 300; + } + else + { + if ((p.playerclass == 9)) + { + p.maxspeed = 300; + } + else + { + if (!p.playerclass) + { + st = infokey (world, "clan"); + if ((st == "on")) + { + p.maxspeed = 0; + return; + } + else + { + p.maxspeed = 400; + } + } + } + } + } + } + } + } + } + } + } } tf = 0; - te = find(world, classname, "item_tfgoal"); - while ((te != world) && (tf == 0)) { - if (te.owner == p) { - if (te.goal_activation & TFGI_SLOW) { + te = find (world, classname, "item_tfgoal"); + while (((te != world) && (tf == 0))) + { + if ((te.owner == p)) + { + if ((te.goal_activation & 2)) + { tf = 1; - p.maxfbspeed = p.maxfbspeed / 2; - p.maxstrafespeed = p.maxstrafespeed / 2; + p.maxspeed = (p.maxspeed / 2); } } - te = find(te, classname, "item_tfgoal"); + te = find (te, classname, "item_tfgoal"); } - if (p.tfstate & TFSTATE_TRANQUILISED) { - p.maxfbspeed = p.maxfbspeed / 2; - p.maxstrafespeed = p.maxstrafespeed / 2; + if ((p.tfstate & 32768)) + { + p.maxspeed = (p.maxspeed / 2); } - if (p.leg_damage) { - if (p.leg_damage > 6) { + if (p.leg_damage) + { + if ((p.leg_damage > 6)) + { p.leg_damage = 6; } - p.maxfbspeed = p.maxfbspeed * (10 - p.leg_damage) / 10; - p.maxstrafespeed = p.maxstrafespeed * (10 - p.leg_damage) / 10; - } - if (p.tfstate & TFSTATE_AIMING) { - if (p.maxfbspeed > 80) { - p.maxfbspeed = 80; - } - if (p.maxstrafespeed > 80) { - p.maxstrafespeed = 80; - } - } - sp = ftos(p.maxfbspeed); - stuffcmd(p, "cl_backspeed "); - stuffcmd(p, sp); - stuffcmd(p, "\n"); - stuffcmd(p, "cl_forwardspeed "); - stuffcmd(p, sp); - stuffcmd(p, "\n"); - sp = ftos(p.maxstrafespeed); - stuffcmd(p, "cl_sidespeed "); - stuffcmd(p, sp); - stuffcmd(p, "\n"); - p.maxspeed = p.maxfbspeed; + p.maxspeed = (p.maxspeed * ((10 - p.leg_damage) / 10)); + } + if ((p.tfstate & 2048)) + { + if ((p.current_weapon == 32768)) + { + if ((p.maxspeed > (p.maxspeed / 2))) + { + p.maxspeed = (p.maxspeed / 2); + } + } + else + { + if ((p.maxspeed > 80)) + { + p.maxspeed = 80; + } + } + } + sp = ftos (p.maxspeed); + sp = "9999"; + stuffcmd (p, "cl_backspeed "); + stuffcmd (p, sp); + stuffcmd (p, "\n"); + stuffcmd (p, "cl_forwardspeed "); + stuffcmd (p, sp); + stuffcmd (p, "\n"); + stuffcmd (p, "cl_sidespeed "); + stuffcmd (p, sp); + stuffcmd (p, "\n"); }; void () TeamFortress_SetHealth = { @@ -2470,7 +2532,7 @@ void (float Suicided) TeamFortress_SetupRespawn = { restime = restime + 7; } } - if (cb_prematch_time > time) { + if (cb_prematch) { if (self.lives > 0) self.lives = self.lives - 1; diff --git a/tfortmap.qc b/tfortmap.qc index c2998eaa..9a693762 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1316,7 +1316,7 @@ float (entity Goal, entity AP) Activated = { void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate = { local entity te; - if (cb_prematch_time > time) + if (cb_prematch) return; @@ -1635,7 +1635,7 @@ void (entity Goal, entity AP, float addb) DoResults = { local float winners; local float gotone; - if (cb_prematch_time > time) { + if (cb_prematch) { return; } if (Goal.goal_state == 1) { @@ -1944,7 +1944,7 @@ void () tfgoal_touch = { return; if (other.classname != "player") return; - if (cb_prematch_time > time) + if (cb_prematch) return; if (self.goal_state == TFGS_ACTIVE) return; @@ -2006,7 +2006,7 @@ void () item_tfgoal_touch = { return; if (other.health <= 0) return; - if (cb_prematch_time > time) + if (cb_prematch) return; if (other.is_feigning) return; diff --git a/weapons.qc b/weapons.qc index 308c4dc0..30b7a4d9 100644 --- a/weapons.qc +++ b/weapons.qc @@ -563,7 +563,7 @@ void () W_FireMedikit = { if (trace_ent.playerclass == PC_MEDIC) return; - if (cb_prematch_time > time) + if (cb_prematch) return; if (trace_ent.tfstate & TFSTATE_INFECTED) return; @@ -1252,7 +1252,7 @@ void () W_FireGrenade = { newmis.owner = self; newmis.movetype = 10; newmis.solid = 2; - if ((self.weaponmode == 0) || (cb_prematch_time > time)) { + if ((self.weaponmode == 0) || (cb_prematch)) { newmis.weapon = 5; newmis.classname = "grenade"; newmis.skin = 1; @@ -1975,7 +1975,7 @@ void () W_PrintWeaponMessage = { if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { if (self.weaponmode == GL_NORMAL) sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); - else if (cb_prematch_time > time) + else if (cb_prematch) sprint(self, PRINT_MEDIUM, "Pipebomb mode not available in prematch\n"); else if (self.weaponmode == GL_PIPEBOMB) @@ -2316,7 +2316,7 @@ void () ImpulseCommands = { if ((self.last_impulse == TF_DETPACK) && self.impulse) TeamFortress_SetDetpack(self.impulse); - if ((cb_prematch_time > time) || cease_fire) { + if ((cb_prematch) || cease_fire) { PreMatchImpulses(); DeadImpulses(); self.impulse = 0; @@ -2738,7 +2738,7 @@ void () W_WeaponFrame = { return; } - if (intermission_running || cease_fire) + if (intermission_running) return; // hwguy assault cannon special From acba92f0416f4bc1d81a877eadf9a4457ec31931 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 19 Jan 2019 19:19:15 +0000 Subject: [PATCH 0538/2474] using original TeamFortress_SetSpeed, improving old huetf code --- admin.qc | 1 - client.qc | 1 - functions.qc | 1 - menu.qc | 565 +++++++++++++++++++++++++-------------------------- mvdsv.qc | 9 +- tfort.qc | 238 ++++++++-------------- 6 files changed, 365 insertions(+), 450 deletions(-) diff --git a/admin.qc b/admin.qc index a55dccd1..adc8ac36 100644 --- a/admin.qc +++ b/admin.qc @@ -125,7 +125,6 @@ void () Admin_DoBan = { void () CeaseFire_think = { local entity te; - local float temp; if (cease_fire == 0) { diff --git a/client.qc b/client.qc index 5039f55d..6e9163ee 100644 --- a/client.qc +++ b/client.qc @@ -159,7 +159,6 @@ void () DecodeLevelParms = { local entity ent; local entity te; - local float ti; if (serverflags) if (world.model == "maps/start.bsp") diff --git a/functions.qc b/functions.qc index 4216fa07..80b9cddc 100644 --- a/functions.qc +++ b/functions.qc @@ -4,7 +4,6 @@ void (entity p) SetTeamName; void (entity pl) Menu_Close; void (float tno) playerSetTeam = { - local entity te; local string st; TeamFortress_TeamSet (tno); diff --git a/menu.qc b/menu.qc index 1cc15db7..c107b025 100644 --- a/menu.qc +++ b/menu.qc @@ -97,9 +97,7 @@ void () Admin_DoKick; void (entity pl) Menu_Close = { pl.menu_input = nil; - Status_Print(pl, ""); - self.current_menu_type = 0; - self.current_menu_page = 0; + Status_Print(pl, ""); }; string (string text, float maxlength) Menu_Indent_line = @@ -1021,13 +1019,16 @@ void () Menu_Admin = { local string s_menu1; local string s_menu2; - local string s_menu3; - local string s_menu4; - local string s_menu5; - local string s_menu6; + + /* More menu lines, commented for the sake of unecessary warnings + * local string s_menu3; + * local string s_menu4; + * local string s_menu5; + * local string s_menu6; + */ local string s_menu7; local string s_menu8; - local string s_menu9; + local string s_menu9; local entity te; local entity temp; @@ -1037,7 +1038,6 @@ void () Menu_Admin = self.impulse = 0; - if (self.current_menu_type == 0) { s_menu1 = "HueTF Admin Menu: \n\n"; if (self.current_menu_page == 1) { @@ -1117,68 +1117,66 @@ void () Menu_Admin = te = find (te, classname, "player"); } -if (self.current_menu_type != 3 && self.current_menu_type != 4 && self.current_menu_type != 5 ) { - te = find (world, classname, "observer"); - while (te != world) { - if ( (f_tmp <= (self.current_menu_page * 7) ) && (f_tmp > (self.current_menu_page - 1) * 7) && te.netname != "") { - f_tmp2 = f_tmp2 + 1; - s_menu2 = strcat( s_menu2, Q"\s[\s" ); - s_menu2 = strcat( s_menu2, ftos(f_tmp2)); - s_menu2 = strcat( s_menu2, Q"\s]\s " ); - s_menu2 = strcat( s_menu2, te.netname ); - if (strlen(te.netname) <= 26) { - s_menu2 = strcat( s_menu2, te.netname ); - } - else { - s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + if (self.current_menu_type != 3 && self.current_menu_type != 4 && self.current_menu_type != 5 ) { + te = find (world, classname, "observer"); + while (te != world) { + if ( (f_tmp <= (self.current_menu_page * 7) ) && (f_tmp > (self.current_menu_page - 1) * 7) && te.netname != "") { + f_tmp2 = f_tmp2 + 1; + s_menu2 = strcat( s_menu2, Q"\s[\s" ); + s_menu2 = strcat( s_menu2, ftos(f_tmp2)); + s_menu2 = strcat( s_menu2, Q"\s]\s " ); + s_menu2 = strcat( s_menu2, te.netname ); + if (strlen(te.netname) <= 26) { + s_menu2 = strcat( s_menu2, te.netname ); + } + else { + s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + } + s_menu2 = Menu_Indent_line(s_menu2, 30); } - s_menu2 = Menu_Indent_line(s_menu2, 30); + f_tmp = f_tmp + 1; + te = find (te, classname, "observer"); } - f_tmp = f_tmp + 1; - te = find (te, classname, "observer"); } -} -if (f_tmp == 0 && ( self.current_menu_type == 5 || self.current_menu_type == 4 ) ) { - bprint(2, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s.\n"); - temp = self; - te = find (world, classname, "player"); - while (te != world) { - te.captain = 0; - self = te; - Menu_Close(self); - te = find (te, classname, "player"); + if (f_tmp == 0 && ( self.current_menu_type == 5 || self.current_menu_type == 4 ) ) { + bprint(2, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s.\n"); + temp = self; + te = find (world, classname, "player"); + while (te != world) { + te.captain = 0; + self = te; + Menu_Close(self); + self.current_menu_type = 0; + self.current_menu_page = 0; + te = find (te, classname, "player"); + } + self = temp; + captainmode = 0; + return; } - self = temp; - captainmode = 0; - return; -} s_menu2 = strcat( s_menu2, "\n"); s_menu7 = "\b[\b8\b]\b \bPrevious Page\b "; s_menu7 = Menu_Indent_line(s_menu7, 30); s_menu8 = "\b[\b9\b]\b \bNext Page\b "; s_menu8 = Menu_Indent_line(s_menu8, 30); -if (self.is_admin || self.captain == 1) { - s_menu9 = "\b[\b0\b]\b \bBack to Main Menu\b "; - s_menu9 = Menu_Indent_line(s_menu9, 30); -} else { - s_menu9 = "\n"; -} -if ((self.is_admin || self.captain == 1) && captainmode) { - s_menu9 = strcat(s_menu9, "Option 0 results in canceling captain mode.\n"); -} + if (self.is_admin || self.captain == 1) { + s_menu9 = "\b[\b0\b]\b \bBack to Main Menu\b "; + s_menu9 = Menu_Indent_line(s_menu9, 30); + } else { + s_menu9 = "\n"; + } + if ((self.is_admin || self.captain == 1) && captainmode) { + s_menu9 = strcat(s_menu9, "Option 0 results in canceling captain mode.\n"); + } s_menu1 = strcat(s_menu1, s_menu2); s_menu1 = strcat(s_menu1, s_menu7); s_menu1 = strcat(s_menu1, s_menu8); s_menu1 = strcat(s_menu1, s_menu9); - Status_Menu(self, Menu_Admin_Input, s_menu1); } - - - }; void (float inp) Menu_Admin_Input = @@ -1188,252 +1186,242 @@ void (float inp) Menu_Admin_Input = local string s_temp; local float f_tmp; -// Actions for AdminMenu Page 0 -if (self.current_menu_type == 0 && self.current_menu_page == 1) { - -// -// clanmode -// - - if (inp == 1) { - sprint(self,2,"TESTE CLAN MODE\n"); - localcmd("clan\n"); - Menu_Close(self); - } - -// -// timelimit -// - if (inp == 2) { - if (stof(infokey (world, "timelimit")) > 35) { - s_temp = "5"; - } else { - s_temp = ftos(timelimit/60 + 5); + // Actions for AdminMenu Page 0 + if (self.current_menu_type == 0 && self.current_menu_page == 1) { + + /* + * Toggle Clanmode Option + */ + if (inp == 1) { + localcmd("clan\n"); + Menu_Close(self); + self.current_menu_type = 0; + self.current_menu_page = 0; } - localcmd ("timelimit "); - localcmd(s_temp); - localcmd("\n"); - - bprint ( 2, self.netname); - bprint ( 2, " sets "); - bprint ( 2, "\stimelimit\s to: "); - bprint ( 2, s_temp); - bprint ( 2, "\n"); - } - -// -// kick -// - - if (inp == 3) { - self.current_menu_type = 1; - self.current_menu_page = 1; - Menu_Admin(); - } - -// -// ban -// - - if (inp == 4) { - self.current_menu_type = 2; - self.current_menu_page = 1; - Menu_Admin(); - } - -// -// Restart current map -// - - if (inp == 7) { - - bprint(2, self.netname); - bprint(2, " Has restarted the map.\n"); + /* + * Change Timelimit + */ + if (inp == 2) { + if (stof(infokey (world, "timelimit")) > 35) { + s_temp = "5"; + } else { + s_temp = ftos(timelimit/60 + 5); + } - localcmd ("map "); - localcmd (mapname); - localcmd ("\n"); - } + localcmd ("timelimit "); + localcmd(s_temp); + localcmd("\n"); -// -// Randomize Teams -// + bprint ( 2, self.netname); + bprint ( 2, " sets "); + bprint ( 2, "\stimelimit\s to: "); + bprint ( 2, s_temp); + bprint ( 2, "\n"); + } - if (inp == 6) { + /* + * Kick Player Menu + */ + if (inp == 3) { + self.current_menu_type = 1; + self.current_menu_page = 1; + Menu_Admin(); + } - randomizeTeams(); + /* + * Ban Player Menu + */ + if (inp == 4) { + self.current_menu_type = 2; + self.current_menu_page = 1; + Menu_Admin(); + } + /* + * Restart Current Map Option + */ + if (inp == 7) { + bprint(2, self.netname); + bprint(2, " Has restarted the map.\n"); - } + localcmd ("map "); + localcmd (mapname); + localcmd ("\n"); + } + /* + * Randomize Teams Option + */ + if (inp == 6) { + randomizeTeams(); + } -// -// Captain -// + /* + * Toggle Captain (pickup) Mode + */ + if (inp == 5) { + if (!captainmode) { + captainmode = 1; + self.current_menu_type = 3; + self.current_menu_page = 1; - if (inp == 5) { - if (!captainmode) { - captainmode = 1; - self.current_menu_type = 3; - self.current_menu_page = 1; + bprint(2, "\[\sCaptain Mode\s\]\s:\s is now \sON\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s is now \sON\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + temp = find (world, classname, "player"); + while (temp != world) { + temp.captain = 0; + temp = find (temp, classname, "player"); + } - temp = find (world, classname, "player"); - while (temp != world) { - temp.captain = 0; - temp = find (temp, classname, "player"); + } else { // end captainmode1 + disableCaptain(); + local entity te; + local entity temp; + te = self; + temp = find (world, classname, "player"); + while (temp != world) { + self = temp; + temp.captain = 0; + Menu_Close(self); + self.current_menu_type = 0; + self.current_menu_page = 0; + temp = find (temp, classname, "player"); + } + self = te; } + Menu_Admin(); - } else { // end captainmode1 - disableCaptain(); - local entity te; - local entity temp; - te = self; - temp = find (world, classname, "player"); - while (temp != world) { - self = temp; - temp.captain = 0; - Menu_Close(self); - temp = find (temp, classname, "player"); - } - self = te; } - Menu_Admin(); - - } - -// Actions for AdminMenu Page 1 -} else if (self.current_menu_type == 0 && self.current_menu_page == 2) { - if (inp == 1) { - sprint(self, 2, "AdminMenu Page 2 Action 1\n"); - } - else if (inp == 2) { - sprint(self, 2, "AdminMenu Page 2 Action 2\n"); - } - else if (inp == 3) { - sprint(self, 2, "AdminMenu Page 2 Action 3\n"); - } - else if (inp == 4) { - sprint(self, 2, "AdminMenu Page 2 Action 4\n"); - } - else if (inp == 5) { - sprint(self, 2, "AdminMenu Page 2 Action 5\n"); - } - else if (inp == 6) { - sprint(self, 2, "AdminMenu Page 2 Action 6\n"); - } - else if (inp == 7) { - sprint(self, 2, "AdminMenu Page 2 Action 7\n"); - } + // Actions for AdminMenu Page 1 + } else if (self.current_menu_type == 0 && self.current_menu_page == 2) { + if (inp == 1) { + sprint(self, 2, "AdminMenu Page 2 Action 1\n"); + } + else if (inp == 2) { + sprint(self, 2, "AdminMenu Page 2 Action 2\n"); + } + else if (inp == 3) { + sprint(self, 2, "AdminMenu Page 2 Action 3\n"); + } + else if (inp == 4) { + sprint(self, 2, "AdminMenu Page 2 Action 4\n"); + } + else if (inp == 5) { + sprint(self, 2, "AdminMenu Page 2 Action 5\n"); + } + else if (inp == 6) { + sprint(self, 2, "AdminMenu Page 2 Action 6\n"); + } + else if (inp == 7) { + sprint(self, 2, "AdminMenu Page 2 Action 7\n"); + } -} else if ((self.current_menu_type == 1 || self.current_menu_type == 2 ) && inp >= 1 && inp <= 7) { // Kick / Ban Actions - f_tmp = 1; - self.admin_use = find (world, classname, "player"); - while (self.admin_use != world) { - if (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) { - - f_tmp = f_tmp + 1; - self.admin_use = find (self.admin_use, classname, "player"); - } else { - break; - } - } - if (f_tmp < ((self.current_menu_page - 1) * 7) + inp) { - self.admin_use = find (world, classname, "observer"); + } else if ((self.current_menu_type == 1 || self.current_menu_type == 2 ) && inp >= 1 && inp <= 7) { // Kick / Ban Actions + f_tmp = 1; + self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { - if (f_tmp < ((self.current_menu_page - 1) * 7) + inp && self.admin_use.netname != "") { + if (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) { f_tmp = f_tmp + 1; + self.admin_use = find (self.admin_use, classname, "player"); } else { break; } - self.admin_use = find (self.admin_use, classname, "observer"); } - } - - if (self.admin_use) { - if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { - self.admin_use.ip = infokey (self.admin_use, "ip"); - if (self.current_menu_type == 2) { - localcmd("addip "); - localcmd(self.admin_use.ip); - localcmd("\n"); + if (f_tmp < ((self.current_menu_page - 1) * 7) + inp) { + self.admin_use = find (world, classname, "observer"); + while (self.admin_use != world) { + if (f_tmp < ((self.current_menu_page - 1) * 7) + inp && self.admin_use.netname != "") { + f_tmp = f_tmp + 1; + } else { + break; + } + self.admin_use = find (self.admin_use, classname, "observer"); } - Admin_DoKick(); } - } - -} else if ((self.current_menu_type == 3 || self.current_menu_type == 4 || self.current_menu_type == 5) && inp >= 1 && inp <= 7) { // Captain Actions - f_tmp = 1; - self.admin_use = find (world, classname, "player"); - while (self.admin_use != world) { - if ( (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { - f_tmp = f_tmp + 1; - } else if ( (f_tmp == ((self.current_menu_page - 1) * 7) + inp) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { - break; + if (self.admin_use) { + if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { + self.admin_use.ip = infokey (self.admin_use, "ip"); + if (self.current_menu_type == 2) { + localcmd("addip "); + localcmd(self.admin_use.ip); + localcmd("\n"); + } + Admin_DoKick(); + } } - self.admin_use = find (self.admin_use, classname, "player"); + } else if ((self.current_menu_type == 3 || self.current_menu_type == 4 || self.current_menu_type == 5) && inp >= 1 && inp <= 7) { // Captain Actions + f_tmp = 1; + self.admin_use = find (world, classname, "player"); + while (self.admin_use != world) { + if ( (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + f_tmp = f_tmp + 1; + } else if ( (f_tmp == ((self.current_menu_page - 1) * 7) + inp) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + break; + } + self.admin_use = find (self.admin_use, classname, "player"); - } + } - if (self.current_menu_type != 5) { - sprint(self,2,"TEST CAP\n"); - if (self.admin_use != world) { - sprint(self,2,"TEST CAPy\n"); - if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { - sprint(self,2,"TEST CAP2\n"); - temp = self; - self = self.admin_use; - self.captain = 9; - if (temp.current_menu_type == 3) { - // Captain for Team 1 - self.team_no = 1; - temp.current_menu_type = 4; - Menu_Admin(); - } else if (temp.current_menu_type == 4) { - // Captain for Team 2 - self.team_no = 2; - - randomizeCaptains(); - - te = find (world, classname, "player"); - while (te != world) - { - self = te; - if (!self.captain) + if (self.current_menu_type != 5) { + sprint(self,2,"TEST CAP\n"); + if (self.admin_use != world) { + sprint(self,2,"TEST CAPy\n"); + if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { + sprint(self,2,"TEST CAP2\n"); + temp = self; + self = self.admin_use; + self.captain = 9; + if (temp.current_menu_type == 3) { + // Captain for Team 1 + self.team_no = 1; + temp.current_menu_type = 4; + Menu_Admin(); + } else if (temp.current_menu_type == 4) { + // Captain for Team 2 + self.team_no = 2; + + randomizeCaptains(); + + te = find (world, classname, "player"); + while (te != world) { - self.playerclass = 0; - playerSetTeam (-1); - self.current_menu = 0; - self.impulse = 0; - } else if (self.captain > 0 && self.captain < 5) { - //TeamFortress_TeamSet(self.team_no); - self.playerclass = 0; - playerSetTeam(self.team_no); - bprint(2, "\[\sCaptain Mode\s\]\s:\s "); - bprint(2, self.netname); - bprint(2, " \bIs the captain for team\b "); - bprint(2, TeamToString(self.team_no)); - bprint(2, "\b.\b\n"); + self = te; + if (!self.captain) + { + self.playerclass = 0; + playerSetTeam (-1); + self.current_menu = 0; + self.impulse = 0; + } else if (self.captain > 0 && self.captain < 5) { + //TeamFortress_TeamSet(self.team_no); + self.playerclass = 0; + playerSetTeam(self.team_no); + bprint(2, "\[\sCaptain Mode\s\]\s:\s "); + bprint(2, self.netname); + bprint(2, " \bIs the captain for team\b "); + bprint(2, TeamToString(self.team_no)); + bprint(2, "\b.\b\n"); + } + te = find (te, classname, "player"); } - te = find (te, classname, "player"); + self = temp; + bprint(2, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); + Menu_Close(self); + self.current_menu_type = 0; + self.current_menu_page = 0; } self = temp; - bprint(2, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); - Menu_Close(self); } - self = temp; } - } - } else { - if (self.admin_use && f_tmp == ((self.current_menu_page - 1) * 7) + inp && self.captain == 1) { + } else { + if (self.admin_use && f_tmp == ((self.current_menu_page - 1) * 7) + inp && self.captain == 1) { temp = self; self = self.admin_use; self.captain = 10; @@ -1451,58 +1439,53 @@ if (self.current_menu_type == 0 && self.current_menu_page == 1) { nextCaptain(); Menu_Close(self); + self.current_menu_type = 0; + self.current_menu_page = 0; } } - } - - - - if ((inp == 8)) { + //Previous page + if (inp == 8) { if (self.current_menu_page > 1) { self.current_menu_page = self.current_menu_page - 1; } } - - if ((inp == 9)) { + //Next page + if (inp == 9) { if (self.current_menu_page < 5) { self.current_menu_page = self.current_menu_page + 1; } } - - if ((inp == 10)) { - + //Closes menus, disables captain mode + if (inp == 10) { if (self.current_menu_type == 4 || self.current_menu_type == 5 || self.current_menu_type == 3) { captainmode = 0; bprint(2, "\[\sCaptain Mode\s\]\s:\s \scanceled by request of\s "); bprint(2, self.netname); bprint(2, ".\n"); - - - te = self; - temp = find (world, classname, "player"); - while (temp != world) { - self = temp; - temp.captain = 0; - Menu_Close(self); - temp = find (temp, classname, "player"); - } - self = te; - - - - + te = self; + temp = find (world, classname, "player"); + while (temp != world) { + self = temp; + temp.captain = 0; + Menu_Close(self); + self.current_menu_type = 0; + self.current_menu_page = 0; + temp = find (temp, classname, "player"); + } + self = te; } - - if (self.current_menu_type == 0) + if (self.current_menu_type == 0) { Menu_Close(self); + self.current_menu_type = 0; + self.current_menu_page = 0; + } else if (self.is_admin) { self.current_menu_type = 0; self.current_menu_page = 1; Menu_Admin(); } } - -self.impulse = 0; + self.impulse = 0; }; \ No newline at end of file diff --git a/mvdsv.qc b/mvdsv.qc index 6bc79f2f..0b6901bd 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -1,7 +1,6 @@ float () UserCmd = { - local float arg_num; - local float fl; + local float arg_num; local string tmp; arg_num = argc (); @@ -259,15 +258,12 @@ float () UserCmd = sprint (self, 2, "\n"); return (1); } - } - return 0; }; float () ConsoleCmd { -local float arg_num; - local float fl; + local float arg_num; local string tmp; arg_num = argc (); @@ -319,4 +315,5 @@ local float arg_num; } } } + return 0; } \ No newline at end of file diff --git a/tfort.qc b/tfort.qc index d5421733..75f218eb 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1071,173 +1071,111 @@ float (float pc) IsLegalClass = { return (TRUE); }; -void (entity p) TeamFortress_SetSpeed = -{ +void (entity p) TeamFortress_SetSpeed = { local string sp; local float tf; local entity te; - local string st; - stuffcmd (p, "cl_movespeedkey 1\n"); - if ((p.tfstate & 65536)) - { - if ((0 == 1)) - { - stuffcmd (p, "m_forward 0\n"); - stuffcmd (p, "m_side 0\n"); - } + stuffcmd(p, "cl_movespeedkey 1\n"); + if (p.tfstate & TFSTATE_CANT_MOVE || p.is_building == 1 || p.is_detpacking > 0) { +#ifdef STOP_MOUSE_MOVEMENT + stuffcmd(p, "m_forward 0\n"); + stuffcmd(p, "m_side 0\n"); +#endif p.velocity = '0 0 0'; - stuffcmd (p, "cl_backspeed 0\n"); - stuffcmd (p, "cl_forwardspeed 0\n"); - stuffcmd (p, "cl_sidespeed 0\n"); + stuffcmd(p, "cl_backspeed 0\n"); + stuffcmd(p, "cl_forwardspeed 0\n"); + stuffcmd(p, "cl_sidespeed 0\n"); p.maxspeed = 0; return; } - else - { - if ((0 == 1)) - { - stuffcmd (p, "m_forward 1\n"); - stuffcmd (p, "m_side 0.8\n"); - } - } - if ((p.playerclass == 1)) - { - p.maxspeed = 450; - } - else - { - if ((p.playerclass == 2)) - { - p.maxspeed = 300; - } - else - { - if ((p.playerclass == 3)) - { - p.maxspeed = 240; - } - else - { - if ((p.playerclass == 4)) - { - p.maxspeed = 280; - } - else - { - if ((p.playerclass == 5)) - { - p.maxspeed = 320; - } - else - { - if ((p.playerclass == 6)) - { - p.maxspeed = 230; - } - else - { - if ((p.playerclass == 7)) - { - p.maxspeed = 300; - } - else - { - if ((p.playerclass == 11)) - { - p.maxspeed = 240; - } - else - { - if ((p.playerclass == 8)) - { - p.maxspeed = 300; - } - else - { - if ((p.playerclass == 9)) - { - p.maxspeed = 300; - } - else - { - if (!p.playerclass) - { - st = infokey (world, "clan"); - if ((st == "on")) - { - p.maxspeed = 0; - return; - } - else - { - p.maxspeed = 400; - } - } - } - } - } - } - } - } - } - } - } +#ifdef STOP_MOUSE_MOVEMENT + else { + stuffcmd(p, "m_forward 1\n"); + stuffcmd(p, "m_side 0.8\n"); + } +#endif + if (p.playerclass == PC_SCOUT) { + p.maxfbspeed = PC_SCOUT_MAXSPEED; + p.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED; + } else if (p.playerclass == PC_SNIPER) { + p.maxfbspeed = PC_SNIPER_MAXSPEED; + p.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED; + } else if (p.playerclass == PC_SOLDIER) { + p.maxfbspeed = PC_SOLDIER_MAXSPEED; + p.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED; + } else if (p.playerclass == PC_DEMOMAN) { + p.maxfbspeed = PC_DEMOMAN_MAXSPEED; + p.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED; + } else if (p.playerclass == PC_MEDIC) { + p.maxfbspeed = PC_MEDIC_MAXSPEED; + p.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED; + } else if (p.playerclass == PC_HVYWEAP) { + p.maxfbspeed = PC_HVYWEAP_MAXSPEED; + p.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED; + } else if (p.playerclass == PC_PYRO) { + p.maxfbspeed = PC_PYRO_MAXSPEED; + p.maxstrafespeed = PC_PYRO_MAXSTRAFESPEED; + } else if (p.playerclass == PC_CIVILIAN) { + p.maxfbspeed = PC_CIVILIAN_MAXSPEED; + p.maxstrafespeed = PC_CIVILIAN_MAXSTRAFESPEED; + } else if (p.playerclass == PC_SPY) { + p.maxfbspeed = PC_SPY_MAXSPEED; + p.maxstrafespeed = PC_SPY_MAXSTRAFESPEED; + } else if (p.playerclass == PC_ENGINEER) { + p.maxfbspeed = PC_ENGINEER_MAXSPEED; + p.maxstrafespeed = PC_ENGINEER_MAXSTRAFESPEED; + } else if (p.playerclass == PC_UNDEFINED) { +// p.maxfbspeed = 320; +// p.maxstrafespeed = 320; + p.maxfbspeed = 0; + p.maxstrafespeed = 0; + p.maxspeed = 0; + return; } tf = 0; - te = find (world, classname, "item_tfgoal"); - while (((te != world) && (tf == 0))) - { - if ((te.owner == p)) - { - if ((te.goal_activation & 2)) - { + te = find(world, classname, "item_tfgoal"); + while ((te != world) && (tf == 0)) { + if (te.owner == p) { + if (te.goal_activation & TFGI_SLOW) { tf = 1; - p.maxspeed = (p.maxspeed / 2); + p.maxfbspeed = p.maxfbspeed / 2; + p.maxstrafespeed = p.maxstrafespeed / 2; } } - te = find (te, classname, "item_tfgoal"); + te = find(te, classname, "item_tfgoal"); } - if ((p.tfstate & 32768)) - { - p.maxspeed = (p.maxspeed / 2); + if (p.tfstate & TFSTATE_TRANQUILISED) { + p.maxfbspeed = p.maxfbspeed / 2; + p.maxstrafespeed = p.maxstrafespeed / 2; } - if (p.leg_damage) - { - if ((p.leg_damage > 6)) - { + if (p.leg_damage) { + if (p.leg_damage > 6) { p.leg_damage = 6; } - p.maxspeed = (p.maxspeed * ((10 - p.leg_damage) / 10)); - } - if ((p.tfstate & 2048)) - { - if ((p.current_weapon == 32768)) - { - if ((p.maxspeed > (p.maxspeed / 2))) - { - p.maxspeed = (p.maxspeed / 2); - } - } - else - { - if ((p.maxspeed > 80)) - { - p.maxspeed = 80; - } - } - } - sp = ftos (p.maxspeed); - sp = "9999"; - stuffcmd (p, "cl_backspeed "); - stuffcmd (p, sp); - stuffcmd (p, "\n"); - stuffcmd (p, "cl_forwardspeed "); - stuffcmd (p, sp); - stuffcmd (p, "\n"); - stuffcmd (p, "cl_sidespeed "); - stuffcmd (p, sp); - stuffcmd (p, "\n"); + p.maxfbspeed = p.maxfbspeed * (10 - p.leg_damage) / 10; + p.maxstrafespeed = p.maxstrafespeed * (10 - p.leg_damage) / 10; + } + if (p.tfstate & TFSTATE_AIMING) { + if (p.maxfbspeed > 80) { + p.maxfbspeed = 80; + } + if (p.maxstrafespeed > 80) { + p.maxstrafespeed = 80; + } + } + sp = ftos(p.maxfbspeed); + stuffcmd(p, "cl_backspeed "); + stuffcmd(p, sp); + stuffcmd(p, "\n"); + stuffcmd(p, "cl_forwardspeed "); + stuffcmd(p, sp); + stuffcmd(p, "\n"); + sp = ftos(p.maxstrafespeed); + stuffcmd(p, "cl_sidespeed "); + stuffcmd(p, sp); + stuffcmd(p, "\n"); + p.maxspeed = p.maxfbspeed; }; void () TeamFortress_SetHealth = { From 83ecf6ed2f4524e37de3bb4a664adcb825e654f4 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sun, 20 Jan 2019 12:10:05 -0200 Subject: [PATCH 0539/2474] fixing some ceasefire bugs --- admin.qc | 6 +++--- weapons.qc | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/admin.qc b/admin.qc index adc8ac36..37eb667c 100644 --- a/admin.qc +++ b/admin.qc @@ -141,7 +141,7 @@ void () CeaseFire_think = }; void () Admin_CeaseFire = { - local entity te; + local entity te; if (!cease_fire) { @@ -156,7 +156,7 @@ void () Admin_CeaseFire = { { CenterPrint3 (te, "CEASE FIRE\nCalled by: ", self.netname, "\n"); te.immune_to_check = (time + 5); - te.tfstate = (te.tfstate | 65536); + te.tfstate = (te.tfstate | TFSTATE_CANT_MOVE); TeamFortress_SetSpeed (te); te = find (te, classname, "player"); } @@ -185,7 +185,7 @@ void () Admin_CeaseFire = { { CenterPrint3 (te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); te.immune_to_check = (time + 5); - te.tfstate = (te.tfstate - (te.tfstate & 65536)); + te.tfstate = (te.tfstate - (te.tfstate & TFSTATE_CANT_MOVE)); TeamFortress_SetSpeed (te); te = find (te, classname, "player"); } diff --git a/weapons.qc b/weapons.qc index 30b7a4d9..9fde972f 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2736,8 +2736,7 @@ void () W_WeaponFrame = { Menu_Class(0); self.impulse = 0; return; - } - + } if (intermission_running) return; @@ -2789,6 +2788,8 @@ void () W_WeaponFrame = { if (self.impulse != 0 && self.has_disconnected == 0) ImpulseCommands(); + if (cease_fire) + return; if (self.button0 && !self.fire_held_down) { if (self.current_weapon == WEAP_SNIPER_RIFLE) { From 67f08b45f285b829f0db5840ca3031885c388c44 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sun, 20 Jan 2019 12:10:45 -0200 Subject: [PATCH 0540/2474] cleaning some forgotten debug messages --- client.qc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client.qc b/client.qc index 6e9163ee..d575daab 100644 --- a/client.qc +++ b/client.qc @@ -1415,10 +1415,6 @@ void () DumpScore = { float already_cycled; void () NextLevel = { - bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); - bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); - bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); - bprint(PRINT_MEDIUM, "NEXT LEVEL CALLED?\n"); local entity o; if (already_cycled) From e789fb5ec2c14c0c049987ecc25bcad58d1b8805 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Mon, 21 Jan 2019 16:24:21 +0000 Subject: [PATCH 0541/2474] improving admin interface, correcting clan mode countdown --- admin.qc | 5 +- clan.qc | 19 ++--- client.qc | 31 +++----- commands.qc | 1 - menu.qc | 8 +-- mvdsv.qc | 201 +++++++++++++++++++++++++++------------------------- spect.qc | 22 ++---- 7 files changed, 136 insertions(+), 151 deletions(-) diff --git a/admin.qc b/admin.qc index 37eb667c..1c471ba5 100644 --- a/admin.qc +++ b/admin.qc @@ -234,9 +234,12 @@ void (string cl_pwd) Admin_Check = { stuffcmd (self, "setinfo adminpwd \""); stuffcmd (self, "\"\n"); - if (((st2 != string_null) && (cl_pwd == st2))) + if (st2 != string_null && cl_pwd == st2) { self.is_admin = TRUE; + bprint2 (2, self.netname, "\s gains full admin status!\s\n"); + sprint (self, 2, "Type \scmd list\s for admin commands.\n"); + sprint (self, 2, "You can also use the \sadminmenu\s command for adjusting some settings.\n"); } } }; diff --git a/clan.qc b/clan.qc index d7f7d782..42a1fcab 100644 --- a/clan.qc +++ b/clan.qc @@ -43,7 +43,7 @@ void () MatchThink = if (((self.cnt == 1) || (self.cnt == 5))) { tmp = ftos (self.cnt); - bprint3 (2, "", tmp, "β€˜ minute"); + bprint3 (2, Q"\s[\s", tmp, "\s]\s minute"); if ((self.cnt != 1)) { bprint (2, "s"); @@ -61,7 +61,7 @@ void () MatchThink = if ((!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= 10)))) { tmp = ftos (self.cnt2); - bprint3 (2, "", tmp, "β€˜ second"); + bprint3 (2, Q"\s[\s", tmp, "\s]\s second"); if ((self.cnt2 != 1)) { bprint (2, "s"); @@ -285,9 +285,9 @@ void () StartTimer = local float f1; local string tmp; - if ((clanbattle == 0)) + if (clanbattle == 0) { - if ((self != world)) + if (self != world) { sprint (self, 2, "Clan mode off....\n"); sprint (self, 2, "Match cannot be started.\n"); @@ -299,7 +299,7 @@ void () StartTimer = } return; } - if (((clanbattle == 1) && (cb_prematch == 0))) + if (clanbattle == 1 && cb_prematch == 0) { if ((self != world)) { @@ -313,7 +313,7 @@ void () StartTimer = } return; } - if ((infokey (world, "status") == "Countdown")) + if (infokey (world, "status") == "Countdown") { if ((self != world)) { @@ -326,7 +326,7 @@ void () StartTimer = return; } timer = find (world, classname, "prematch"); - while ((timer != world)) + while (timer != world) { dremove (timer); timer = find (timer, classname, "prematch"); @@ -347,7 +347,7 @@ void () StartTimer = else { lightstyle (0, "e"); - if ((stof (infokey (world, "demo_auto_left")) > 0)) + if (stof (infokey (world, "demo_auto_left")) > 0) { if (infokey (world, "serverdemo") == "on") { @@ -385,7 +385,8 @@ void () StartTimer = timer.cnt2 = rint (stof (infokey (world, "count"))); if ((timer.cnt2 < 1)) { - timer.cnt2 = 0; + //By default, 10 seconds of countdown + timer.cnt2 = 10; } } timer.cnt2 = (timer.cnt2 + 1); diff --git a/client.qc b/client.qc index d575daab..5f46abbc 100644 --- a/client.qc +++ b/client.qc @@ -52,6 +52,9 @@ void () CTF_FlagCheck; void (entity pl) Sniper_ZoomReset; void () StartTimer; void () StopTimer; +void (string cl_pwd) Admin_Check; +void () Admin_Aliases; + string nextmap; @@ -1974,7 +1977,6 @@ void () PlayerPostThink = { void () ClientConnect = { local entity te; local string st; - local string st2; local float got_one; stuffcmd(self, "set fortressone 1\n"); @@ -1996,29 +1998,16 @@ void () ClientConnect = { GotoNextMap(); } - st2 = infokey(world, "apw"); - if (st2 == string_null) - st2 = infokey(world, "adminpwd"); - st = infokey(self, "apw"); if (st == string_null) st = infokey(self, "adminpwd"); - - if ((st2 != string_null) && (st != string_null) && (st == st2)) { - self.is_admin = TRUE; - stuffcmd(self, "setinfo apw \""); - stuffcmd(self, "\"\n"); - stuffcmd(self, "setinfo adminpwd \""); - stuffcmd(self, "\"\n"); - TeamFortress_Alias("countplayers", 192, 0); - TeamFortress_Alias("deal", 189, 0); - TeamFortress_Alias("kick", 190, 0); - TeamFortress_Alias("ban", 191, 0); - TeamFortress_Alias("next", 195, 0); - TeamFortress_Alias("ceasefire", 193, 0); - TeamFortress_Alias("listips", 198, 0); - } else - self.is_admin = FALSE; + if (st) { + Admin_Check(st); + if (self.is_admin) + Admin_Aliases(); + else + self.is_admin = FALSE; + } if (clanbattle && (self.has_disconnected != 1)) { got_one = 0; diff --git a/commands.qc b/commands.qc index 6c90ca7d..0aa50755 100644 --- a/commands.qc +++ b/commands.qc @@ -1,7 +1,6 @@ void () ClanMode = { local string st; - st = infokey (world, "clan"); if ((st == "on")) { diff --git a/menu.qc b/menu.qc index c107b025..777daa25 100644 --- a/menu.qc +++ b/menu.qc @@ -1039,7 +1039,7 @@ void () Menu_Admin = self.impulse = 0; if (self.current_menu_type == 0) { - s_menu1 = "HueTF Admin Menu: \n\n"; + s_menu1 = "FortressOne Admin Menu: \n\n"; if (self.current_menu_page == 1) { s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode \n"); s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit \n"); @@ -1140,7 +1140,7 @@ void () Menu_Admin = } if (f_tmp == 0 && ( self.current_menu_type == 5 || self.current_menu_type == 4 ) ) { - bprint(2, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s\n"); temp = self; te = find (world, classname, "player"); while (te != world) { @@ -1368,13 +1368,9 @@ void (float inp) Menu_Admin_Input = } - if (self.current_menu_type != 5) { - sprint(self,2,"TEST CAP\n"); if (self.admin_use != world) { - sprint(self,2,"TEST CAPy\n"); if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { - sprint(self,2,"TEST CAP2\n"); temp = self; self = self.admin_use; self.captain = 9; diff --git a/mvdsv.qc b/mvdsv.qc index 0b6901bd..10bb9a83 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -8,66 +8,66 @@ float () UserCmd = { return (0); } - if (argv_mvdsv (0) == "adminpwd") + if (argv_mvdsv(0) == "adminpwd") { if (arg_num == 2) { if (self.is_admin) { - sprint (self, 2, "You are already an admin\n"); + sprint(self, 2, "You are already an admin\n"); return (1); } - Admin_Check (argv_mvdsv (1)); + Admin_Check(argv_mvdsv (1)); if (self.is_admin) { - Admin_Aliases (); + Admin_Aliases(); } return (1); } if (arg_num == 1) { - sprint (self, 2, "usage: cmd adminpwd password, where password is the admin password\n"); - sprint (self, 2, "\n"); + sprint(self, 2, "usage: cmd adminpwd password, where password is the admin password\n"); + sprint(self, 2, "\n"); return (1); } } if (self.is_admin) { //Adminpwd commands - if (argv_mvdsv (0) == "timelimit") + if (argv_mvdsv(0) == "timelimit") { if (arg_num == 2) { - localcmd ("timelimit "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("timelimit "); + localcmd(argv_mvdsv (1)); + localcmd("\n"); return (1); } if (arg_num == 1) { - tmp = infokey (world, argv_mvdsv (0)); - sprint (self, 2, "timelimit is "); - sprint (self, 2, "\""); - sprint (self, 2, tmp); - sprint (self, 2, "\"\n"); + tmp = infokey(world, argv_mvdsv (0)); + sprint(self, 2, "timelimit is "); + sprint(self, 2, "\""); + sprint(self, 2, tmp); + sprint(self, 2, "\"\n"); return (1); } } - else if (argv_mvdsv (0) == "prematch") + else if (argv_mvdsv(0) == "prematch") { if (arg_num == 2) { - localcmd ("prematch "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("prematch "); + localcmd(argv_mvdsv (1)); + localcmd("\n"); return (1); } if (arg_num == 1) { - tmp = infokey (world, argv_mvdsv (0)); - sprint (self, 2, "prematch is "); - sprint (self, 2, "\""); - sprint (self, 2, tmp); - sprint (self, 2, "\"\n"); + tmp = infokey(world, argv_mvdsv (0)); + sprint(self, 2, "prematch is "); + sprint(self, 2, "\""); + sprint(self, 2, tmp); + sprint(self, 2, "\"\n"); return (1); } } @@ -75,112 +75,112 @@ float () UserCmd = { if (arg_num == 2) { - localcmd ("fraglimit "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("fraglimit "); + localcmd(argv_mvdsv (1)); + localcmd("\n"); return (1); } if (arg_num == 1) { - tmp = infokey (world, argv_mvdsv (0)); - sprint (self, 2, "fraglimit is "); - sprint (self, 2, "\""); - sprint (self, 2, tmp); - sprint (self, 2, "\"\n"); + tmp = infokey(world, argv_mvdsv (0)); + sprint(self, 2, "fraglimit is "); + sprint(self, 2, "\""); + sprint(self, 2, tmp); + sprint(self, 2, "\"\n"); return (1); } } - else if (argv_mvdsv (0) == "teamplay") + else if (argv_mvdsv(0) == "teamplay") { if (arg_num == 2) { - localcmd ("teamplay "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("teamplay "); + localcmd(argv_mvdsv (1)); + localcmd("\n"); return (1); } if (arg_num == 1) { - tmp = infokey (world, argv_mvdsv (0)); - sprint (self, 2, "teamplay is "); - sprint (self, 2, "\""); - sprint (self, 2, tmp); - sprint (self, 2, "\"\n"); + tmp = infokey(world, argv_mvdsv (0)); + sprint(self, 2, "teamplay is "); + sprint(self, 2, "\""); + sprint(self, 2, tmp); + sprint(self, 2, "\"\n"); return (1); } } - else if (argv_mvdsv (0) == "password") + else if (argv_mvdsv(0) == "password") { if (arg_num == 2) { - localcmd ("password "); + localcmd("password "); if (argv_mvdsv(1) == "none") { - localcmd ("\"\""); + localcmd("\"\""); } else { - localcmd (argv_mvdsv (1)); + localcmd(argv_mvdsv (1)); } - localcmd ("\n"); - bprint ("\n"); - argv_mvdsv (1); + localcmd("\n"); + bprint("\n"); + argv_mvdsv(1); if (argv_mvdsv(1) == "none") { - bprint (2, "Server Password removed!\n"); + bprint(2, "Server Password removed!\n"); } else { - bprint3 (2, "Server Password changed to \"", argv_mvdsv (1), "\"\n"); + bprint3(2, "Server Password changed to \"", argv_mvdsv (1), "\"\n"); } - bprint ("\n"); + bprint("\n"); return (1); } if (arg_num == 1) { - sprint (self, 2, "usage: cmd password pwd\n"); - sprint (self, 2, "\n"); + sprint(self, 2, "usage: cmd password pwd\n"); + sprint(self, 2, "\n"); return (1); } } - else if (argv_mvdsv (0) == "record") + else if (argv_mvdsv(0) == "record") { if (arg_num == 2) { - localcmd ("record "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("record "); + localcmd(argv_mvdsv (1)); + localcmd("\n"); return (1); } if (arg_num == 1) { - sprint (self, 2, "usage: cmd record demo, where demo is the demo name\n"); - sprint (self, 2, "\n"); + sprint(self, 2, "usage: cmd record demo, where demo is the demo name\n"); + sprint(self, 2, "\n"); return (1); } } - else if (argv_mvdsv (0) == "easyrecord") + else if (argv_mvdsv(0) == "easyrecord") { if (arg_num == 2) { - localcmd ("easyrecord "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("easyrecord "); + localcmd(argv_mvdsv (1)); + localcmd("\n"); return (1); } if (arg_num == 1) { - localcmd ("easyrecord\n"); + localcmd("easyrecord\n"); return (1); } } - else if (argv_mvdsv (0) == "autorecord") + else if (argv_mvdsv(0) == "autorecord") { if (arg_num == 2) { - localcmd ("localinfo demo_auto_left "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("localinfo demo_auto_left "); + localcmd(argv_mvdsv (1)); + localcmd("\n"); return (1); } if (arg_num == 1) { - tmp = infokey (world, "demo_auto_left"); - if (stof (tmp) > 0) + tmp = infokey(world, "demo_auto_left"); + if (stof(tmp) > 0) { dprint ("Auto-Recording off\n"); localcmd ("localinfo demo_auto_left 0\n"); @@ -188,28 +188,28 @@ float () UserCmd = } else { - dprint ("Auto-Recording the next match\n"); - localcmd ("localinfo demo_auto_left 1\n"); + dprint("Auto-Recording the next match\n"); + localcmd("localinfo demo_auto_left 1\n"); return (1); } } } - else if (argv_mvdsv (0) == "cancel") + else if (argv_mvdsv(0) == "cancel") { localcmd ("cancel\n"); return (1); } - else if (argv_mvdsv (0) == "stop") + else if (argv_mvdsv(0) == "stop") { localcmd ("stop\n"); return (1); } - else if (argv_mvdsv (0) == "kick") + else if (argv_mvdsv(0) == "kick") { - Admin_CycleDeal (); + Admin_CycleDeal(); return (1); } - else if (argv_mvdsv (0) == "map") + else if (argv_mvdsv(0) == "map") { if (self.is_admin) { @@ -226,9 +226,9 @@ float () UserCmd = bprint(2, " Has changed the map to "); bprint(2, argv_mvdsv(1)); bprint(2, "\n"); - localcmd ("map "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + localcmd("map "); + localcmd(argv_mvdsv(1)); + localcmd("\n"); return (1); } if (arg_num == 1) @@ -238,26 +238,26 @@ float () UserCmd = return (1); } } - else if (argv_mvdsv (0) == "help" || argv_mvdsv (0) == "list") + else if (argv_mvdsv(0) == "help" || argv_mvdsv(0) == "list") { - sprint (self, 2, "Commands list:\n"); - sprint (self, 2, "cmd adminpwd\n"); - sprint (self, 2, "cmd timelimit\n"); - sprint (self, 2, "cmd prematch\n"); - sprint (self, 2, "cmd fraglimit\n"); - sprint (self, 2, "cmd teamplay\n"); - sprint (self, 2, "cmd password\n"); - sprint (self, 2, "cmd map\n"); - sprint (self, 2, "cmd record\n"); - sprint (self, 2, "cmd easyrecord\n"); - sprint (self, 2, "cmd autorecord\n"); - sprint (self, 2, "cmd cancel\n"); - sprint (self, 2, "cmd stop\n"); - sprint (self, 2, "cmd kick\n"); - sprint (self, 2, "cmd help || list (this command)\n"); - sprint (self, 2, "\n"); + sprint(self, 2, "Commands list:\n"); + sprint(self, 2, "cmd adminpwd\n"); + sprint(self, 2, "cmd timelimit\n"); + sprint(self, 2, "cmd prematch\n"); + sprint(self, 2, "cmd fraglimit\n"); + sprint(self, 2, "cmd teamplay\n"); + sprint(self, 2, "cmd password\n"); + sprint(self, 2, "cmd map\n"); + sprint(self, 2, "cmd record\n"); + sprint(self, 2, "cmd easyrecord\n"); + sprint(self, 2, "cmd autorecord\n"); + sprint(self, 2, "cmd cancel\n"); + sprint(self, 2, "cmd stop\n"); + sprint(self, 2, "cmd kick\n"); + sprint(self, 2, "cmd help || list (this command)\n"); + sprint(self, 2, "\n"); return (1); - } + } } return 0; }; @@ -314,6 +314,11 @@ float () ConsoleCmd { return (1); } } + } + else if (argv_mvdsv (0) == "clan") + { + ClanMode (); + return (1); } return 0; } \ No newline at end of file diff --git a/spect.qc b/spect.qc index d72e9443..4c5bf367 100644 --- a/spect.qc +++ b/spect.qc @@ -16,29 +16,21 @@ void () Admin_Aliases; void () SpectatorConnect = { local string st; - local string st2; self.playerclass = PC_UNDEFINED; self.classname = "observer"; self.flags = 8; - st2 = infokey(world, "apw"); - if (st2 == string_null) - st2 = infokey(world, "adminpwd"); - st = infokey(self, "apw"); if (st == string_null) st = infokey(self, "adminpwd"); - - if (((st2 != string_null) && (st != string_null)) && (st == st2)) { - self.is_admin = TRUE; - stuffcmd(self, "setinfo apw \""); - stuffcmd(self, "\"\n"); - stuffcmd(self, "setinfo adminpwd \""); - stuffcmd(self, "\"\n"); - Admin_Aliases(); - } else - self.is_admin = FALSE; + if (st) { + Admin_Check(st); + if (self.is_admin) + Admin_Aliases(); + else + self.is_admin = FALSE; + } st = infokey(self, "em"); if (st == string_null) From e038bf68d69460051ad442589c49b3fa8b2e1aeb Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Thu, 24 Jan 2019 00:43:54 +0000 Subject: [PATCH 0542/2474] adjusting code format to match FO's standards --- admin.qc | 110 ++++++------- clan.qc | 424 +++++++++++++++++++++++---------------------------- commands.qc | 16 +- functions.qc | 72 +++------ mvdsv.qc | 224 +++++++++++---------------- weapons.qc | 2 +- 6 files changed, 355 insertions(+), 493 deletions(-) diff --git a/admin.qc b/admin.qc index 1c471ba5..cfd1055b 100644 --- a/admin.qc +++ b/admin.qc @@ -76,47 +76,40 @@ void () Admin_CycleDeal = { } if (self.admin_use == world) { self.admin_use = find(self.admin_use, classname, "observer"); - while ((self.admin_use != world) && - ((self.admin_use.netname == string_null) - || (self.admin_use == self))) { - self.admin_use = - find(self.admin_use, classname, "observer"); + while ((self.admin_use != world) && ((self.admin_use.netname == string_null) || (self.admin_use == self))) { + self.admin_use = find(self.admin_use, classname, "observer"); } } - } else { + } + else { self.admin_use = find(self.admin_use, classname, "observer"); - while ((self.admin_use != world) && - ((self.admin_use.netname == string_null) - || (self.admin_use == self))) { + while ((self.admin_use != world) && ((self.admin_use.netname == string_null) || (self.admin_use == self))) { self.admin_use = find(self.admin_use, classname, "observer"); } } if (self.admin_use) { self.admin_use.ip = infokey(self.admin_use, "ip"); self.admin_mode = 1; - sprint(self, PRINT_HIGH, self.admin_use.netname, " (", - self.admin_use.ip, ")"); - if (self.admin_use.classname == "observer") { + sprint(self, PRINT_HIGH, self.admin_use.netname, " (", self.admin_use.ip, ")"); + if (self.admin_use.classname == "observer") sprint(self, PRINT_HIGH, " (spectator)"); - } sprint(self, PRINT_HIGH, "\n kick/ban/next?\n"); - } else { + } + else { self.admin_mode = 0; sprint(self, PRINT_HIGH, "End of player list\n"); } }; void () Admin_DoKick = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was kicked by ", - self.netname, "\n"); + bprint4(PRINT_HIGH, self.admin_use.netname, " was kicked by ", self.netname, "\n"); KickCheater(self.admin_use); self.admin_mode = 0; self.admin_use = world; }; void () Admin_DoBan = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was banned by ", - self.netname, "\n"); + bprint4(PRINT_HIGH, self.admin_use.netname, " was banned by ", self.netname, "\n"); BanCheater(self.admin_use); self.admin_mode = 0; self.admin_use = world; @@ -125,17 +118,14 @@ void () Admin_DoBan = { void () CeaseFire_think = { local entity te; - - if (cease_fire == 0) - { - dremove (self); + if (cease_fire == 0) { + dremove(self); return; } te = find(world, classname, "player"); - while (te) - { - CenterPrint3 (te, "CEASE FIRE\nCalled by: ", self.owner.netname, "\n"); - te = find (te, classname, "player"); + while (te) { + CenterPrint3(te, "CEASE FIRE\nCalled by: ", self.owner.netname, "\n"); + te = find(te, classname, "player"); } self.nextthink = (time + 5); }; @@ -143,47 +133,40 @@ void () CeaseFire_think = void () Admin_CeaseFire = { local entity te; - if (!cease_fire) - { - if (cb_prematch) - { - StopTimer (); + if (!cease_fire) { + if (cb_prematch) { + StopTimer(); } cease_fire = 1; - bprint (2, "CEASE FIRE\n"); - te = find (world, classname, "player"); - while (te) - { - CenterPrint3 (te, "CEASE FIRE\nCalled by: ", self.netname, "\n"); + bprint(2, "CEASE FIRE\n"); + te = find(world, classname, "player"); + while (te) { + CenterPrint3(te, "CEASE FIRE\nCalled by: ", self.netname, "\n"); te.immune_to_check = (time + 5); te.tfstate = (te.tfstate | TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed (te); - te = find (te, classname, "player"); + TeamFortress_SetSpeed(te); + te = find(te, classname, "player"); } - te = spawn (); + te = spawn(); te.owner = self; te.classname = "ceasefire"; te.think = CeaseFire_think; te.nextthink = (time + 5); } - else - { - te = find (world, classname, "ceasefire"); - if (te) - { - dremove (te); + else { + te = find(world, classname, "ceasefire"); + if (te) { + dremove(te); } cease_fire = 0; - if (cb_prematch) - { + if (cb_prematch) { cb_prematch_time = 0; - StartTimer (); + StartTimer(); } - bprint (2, "RESUME FIRE\n"); - te = find (world, classname, "player"); - while (te) - { - CenterPrint3 (te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); + bprint(2, "RESUME FIRE\n"); + te = find(world, classname, "player"); + while (te) { + CenterPrint3(te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); te.immune_to_check = (time + 5); te.tfstate = (te.tfstate - (te.tfstate & TFSTATE_CANT_MOVE)); TeamFortress_SetSpeed (te); @@ -201,7 +184,8 @@ void (entity p) CheckAutoKick = { " was kicked for killing teammates\n"); sprint(p, PRINT_HIGH, "You were kicked for killing teammates\n"); KickCheater(p); - } else if (autokick_kills != 0) { + } + else if (autokick_kills != 0) { if (p.teamkills == (autokick_kills - 1)) { sprint(p, PRINT_HIGH, "Kill one more teammate, and you will get kicked out\n"); @@ -229,17 +213,15 @@ void (string cl_pwd) Admin_Check = { local string st2; - st2 = infokey (world, "adminpwd"); - if ((cl_pwd != string_null)) - { - stuffcmd (self, "setinfo adminpwd \""); - stuffcmd (self, "\"\n"); - if (st2 != string_null && cl_pwd == st2) - { + st2 = infokey(world, "adminpwd"); + if (cl_pwd != string_null) { + stuffcmd(self, "setinfo adminpwd \""); + stuffcmd(self, "\"\n"); + if (st2 != string_null && cl_pwd == st2) { self.is_admin = TRUE; - bprint2 (2, self.netname, "\s gains full admin status!\s\n"); - sprint (self, 2, "Type \scmd list\s for admin commands.\n"); - sprint (self, 2, "You can also use the \sadminmenu\s command for adjusting some settings.\n"); + bprint2(2, self.netname, "\s gains full admin status!\s\n"); + sprint(self, 2, "Type \scmd list\s for admin commands.\n"); + sprint(self, 2, "You can also use the \sadminmenu\s command for adjusting some settings.\n"); } } }; diff --git a/clan.qc b/clan.qc index 42a1fcab..8d6c8de5 100644 --- a/clan.qc +++ b/clan.qc @@ -2,71 +2,60 @@ void () MatchThink = { local string tmp; - if ((self.cnt == -1)) - { + if (self.cnt == -1) { return; } - if (cease_fire) - { + if (cease_fire) { self.nextthink = (time + 1); return; } self.cnt2 = (self.cnt2 - 1); - if (!TeamFortress_GetNoPlayers ()) - { - NextLevel (); + if (!TeamFortress_GetNoPlayers()) { + NextLevel(); return; } - if ( self.cnt == cvar("timelimit") - 1 && self.cnt2 == 59 ) - { - localcmd ("serverinfo status \""); - tmp = ftos (self.cnt + 1); - localcmd (tmp); - localcmd (" min left\"\n"); + if ( self.cnt == cvar("timelimit") - 1 && self.cnt2 == 59 ) { + localcmd("serverinfo status \""); + tmp = ftos(self.cnt + 1); + localcmd(tmp); + localcmd(" min left\"\n"); } if (self.cnt2 == 1) { - localcmd ("serverinfo status \""); - tmp = ftos (self.cnt + 1); - localcmd (tmp); - localcmd (" min left\"\n"); + localcmd("serverinfo status \""); + tmp = ftos(self.cnt + 1); + localcmd(tmp); + localcmd(" min left\"\n"); } - if ((self.cnt2 == -1)) - { + if (self.cnt2 == -1) { self.cnt2 = 59; self.cnt = (self.cnt - 1); } - if (!self.cnt2) - { - if (((self.cnt == 1) || (self.cnt == 5))) - { + if (!self.cnt2) { + if (self.cnt == 1 || self.cnt == 5) { tmp = ftos (self.cnt); - bprint3 (2, Q"\s[\s", tmp, "\s]\s minute"); - if ((self.cnt != 1)) - { - bprint (2, "s"); + bprint3(2, Q"\s[\s", tmp, "\s]\s minute"); + if (self.cnt != 1) { + bprint(2, "s"); } - bprint (2, " remaining\n"); + bprint(2, " remaining\n"); } - if (!self.cnt) - { + if (!self.cnt) { self.think = SUB_Remove; self.nextthink = (time + 0.1); - NextLevel (); + NextLevel(); return; } } - if ((!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= 10)))) - { - tmp = ftos (self.cnt2); - bprint3 (2, Q"\s[\s", tmp, "\s]\s second"); - if ((self.cnt2 != 1)) - { - bprint (2, "s"); + if (!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= 10))) { + tmp = ftos(self.cnt2); + bprint3(2, Q"\s[\s", tmp, "\s]\s second"); + if (self.cnt2 != 1) { + bprint(2, "s"); } - bprint (2, " remaining\n"); + bprint(2, " remaining\n"); } self.nextthink = (time + 1); }; @@ -80,8 +69,8 @@ void () StartMatch = local entity oldself; local entity gren; - lightstyle (0, "m"); - bprint (2, "MATCH BEGINS NOW\n"); + lightstyle(0, "m"); + bprint(2, "MATCH BEGINS NOW\n"); team4score = 0; team3score = 0; @@ -91,69 +80,68 @@ void () StartMatch = team3frags = 0; team2frags = 0; team1frags = 0; - te = find (world, classname, "player"); + te = find(world, classname, "player"); - while (te) - { + while (te) { oldself = self; self = te; - TeamFortress_RemoveTimers (); + TeamFortress_RemoveTimers(); self.frags = 0; self.real_frags = 0; - setspawnparms (self); + setspawnparms(self); if (infokey(world, "quadmode") != "on") - PutClientInServer (); + PutClientInServer(); self = oldself; - te = find (te, classname, "player"); + te = find(te, classname, "player"); } - gren = find (world, classname, "grenade"); + gren = find(world, classname, "grenade"); while (gren) { gren.think = GrenadeExplode; gren.nextthink = (time + 0.1); - gren = find (gren, classname, "grenade"); + gren = find(gren, classname, "grenade"); } cb_prematch = 0; cease_fire = 0; - te = find (world, classname, "prematch"); + te = find(world, classname, "prematch"); te.classname = "match"; te.cnt = (timelimit / 60); te.cnt2 = 60; - if ((te.cnt == 0)) + if (te.cnt == 0) { - bprint (2, "Warning no timelimit set!\n"); - localcmd ("\nserverinfo status \"0 min left\"\n"); + bprint(2, "Warning no timelimit set!\n"); + localcmd("\nserverinfo status \"0 min left\"\n"); te.cnt = -1; te.cnt2 = -1; } else { te.cnt = (te.cnt - 1); - localcmd ("\nserverinfo status \""); - st = ftos (te.cnt); - localcmd (st); - localcmd (" min left\"\n"); + localcmd("\nserverinfo status \""); + st = ftos(te.cnt); + localcmd(st); + localcmd(" min left\"\n"); if (infokey(world, "quadmode") != "on") { te.think = MatchThink; te.nextthink = (time + 1); } } - st = infokey (world, "spectalk"); - f2 = stof (st); + st = infokey(world, "spectalk"); + f2 = stof(st); if (!f2) { st = "0"; } - localcmd ("sv_spectalk "); - localcmd (st); - localcmd ("\n"); - f1 = stof (infokey (world, "fpd")); - f1 = ((f1 - (f1 & 64)) + (f2 * 64)); - localcmd ("serverinfo fpd "); - st = ftos (f1); - localcmd (st); - localcmd ("\n"); + localcmd("sv_spectalk "); + localcmd(st); + localcmd("\n"); + f1 = stof(infokey(world, "fpd")); + f1 = (f1 - (f1 & 64)) + (f2 * 64); + localcmd("serverinfo fpd "); + st = ftos(f1); + localcmd(st); + localcmd("\n"); st = infokey(world, "quadmode"); }; @@ -164,13 +152,10 @@ void () PreMatch_Think = { local float fl; self.cnt2 = (self.cnt2 - 1); - if ((self.cnt2 == 1)) - { - p = find (world, classname, "player"); - while ((p != world)) - { - if ((p.netname != "")) - { + if (self.cnt2 == 1) { + p = find(world, classname, "player"); + while (p != world) { + if (p.netname != "") { p.respawn_time = (time + 2); p.takedamage = 0; p.solid = 0; @@ -178,101 +163,87 @@ void () PreMatch_Think = { p.modelindex = 0; p.model = string_null; } - p = find (p, classname, "player"); + p = find(p, classname, "player"); } } else { - if (!self.cnt2) - { + if (!self.cnt2) { self.nextthink = (time + 0.1); self.think = SUB_Remove; - p = find (world, classname, "player"); - while ((p != world)) - { - if ((p.netname != "")) - { + p = find(world, classname, "player"); + while (p != world) { + if (p.netname != "") { p.takedamage = 2; p.solid = 3; p.movetype = 3; } - p = find (p, classname, "player"); + p = find(p, classname, "player"); } - StartMatch (); + StartMatch(); return; } } fl = (self.cnt2 / 60); - if (fl == 1 || fl == 2 || fl == 3 || fl == 4 || fl == 5 || fl == 6 || fl == 7 || fl == 8 || fl == 9 || fl == 10) - { - num = ftos (fl); - bprint3 (2, "Match will begin in ", num, " minute(s).\n"); - } - if ((self.cnt2 == 30)) - { - num = ftos ((self.cnt2 / 60)); - bprint (2, "Match will begin in 30 seconds.\n"); - } - if ((self.cnt2 <= 10)) - { - if ((self.cnt2 == 10)) - { - lightstyle (0, "e"); - localcmd ("serverinfo status Countdown\n"); - - if ((stof (infokey (world, "demo_auto_left")) > 0)) - { - if (infokey (world, "serverdemo") == "on") - { - calltimeofday (); - - localcmd ("record \""); - localcmd (ftos (tod_day)); // day - localcmd ("-"); - localcmd (ftos (tod_mon)); // month - localcmd ("-"); - localcmd (ftos (tod_year)); // year - localcmd ("_"); - localcmd (ftos (tod_hour)); // hour - localcmd ("-"); - localcmd (ftos (tod_min)); // minute - localcmd ("-"); - localcmd (ftos (tod_sec)); // second - - localcmd ("_["); - localcmd (mapname); - localcmd ("]"); - localcmd ("\"\n"); + if (fl == 1 || fl == 2 || fl == 3 || fl == 4 || fl == 5 || fl == 6 || fl == 7 || fl == 8 || fl == 9 || fl == 10) { + num = ftos(fl); + bprint3(2, "Match will begin in ", num, " minute(s).\n"); + } + if (self.cnt2 == 30) { + num = ftos(self.cnt2 / 60); + bprint(2, "Match will begin in 30 seconds.\n"); + } + if (self.cnt2 <= 10) { + if (self.cnt2 == 10) { + lightstyle(0, "e"); + localcmd("serverinfo status Countdown\n"); + + if (stof(infokey(world, "demo_auto_left")) > 0) { + if (infokey(world, "serverdemo") == "on") { + calltimeofday(); + + localcmd("record \""); + localcmd(ftos (tod_day)); // day + localcmd("-"); + localcmd(ftos (tod_mon)); // month + localcmd("-"); + localcmd(ftos (tod_year)); // year + localcmd("_"); + localcmd(ftos (tod_hour)); // hour + localcmd("-"); + localcmd(ftos (tod_min)); // minute + localcmd("-"); + localcmd(ftos (tod_sec)); // second + + localcmd("_["); + localcmd(mapname); + localcmd("]"); + localcmd("\"\n"); } } } - num = ftos (self.cnt2); - p = find (world, classname, "player"); + num = ftos(self.cnt2); + p = find(world, classname, "player"); tmp = strcat(num ,"\n\n\b:[\b"); tmp = strcat(tmp, mapname); tmp = strcat(tmp, "\b]:\b"); strcat(tmp, "\n"); - while ((p != world)) - { - if ((p.netname != "")) - { + while (p != world) { + if (p.netname != "") { CenterPrint3 (p, "Countdown ", tmp, "\n"); - if ((self.cnt2 < 6)) - { + if (self.cnt2 < 6) { cease_fire = 0; stuffcmd (p, "play buttons/switch04.wav\n"); } } - p = find (p, classname, "player"); + p = find(p, classname, "player"); } - if ((self.cnt2 > 1)) - { - bprint2 (2, num, " seconds.\n"); + if (self.cnt2 > 1) { + bprint2(2, num, " seconds.\n"); } - else - { - bprint (2, "1 second.\n"); + else { + bprint(2, "1 second.\n"); } } self.nextthink = (time + 1); @@ -285,113 +256,95 @@ void () StartTimer = local float f1; local string tmp; - if (clanbattle == 0) - { - if (self != world) - { - sprint (self, 2, "Clan mode off....\n"); - sprint (self, 2, "Match cannot be started.\n"); + if (clanbattle == 0) { + if (self != world) { + sprint(self, 2, "Clan mode off....\n"); + sprint(self, 2, "Match cannot be started.\n"); } - else - { - dprint ("Clan mode off....\n"); - dprint ("Match cannot be started.\n"); + else { + dprint("Clan mode off....\n"); + dprint("Match cannot be started.\n"); } return; } - if (clanbattle == 1 && cb_prematch == 0) - { - if ((self != world)) - { - sprint (self, 2, "Clan Battle in progress....\n"); - sprint (self, 2, "Type break to stop the current battle.\n"); + if (clanbattle == 1 && cb_prematch == 0) { + if (self != world) { + sprint(self, 2, "Clan Battle in progress....\n"); + sprint(self, 2, "Type break to stop the current battle.\n"); } - else - { - dprint ("Clan Battle in progress....\n"); - dprint ("Type break to stop the current battle.\n"); + else { + dprint("Clan Battle in progress....\n"); + dprint("Type break to stop the current battle.\n"); } return; } - if (infokey (world, "status") == "Countdown") - { - if ((self != world)) - { - sprint (self, 2, "Countdown in progress....\n"); + if (infokey(world, "status") == "Countdown") { + if (self != world) { + sprint(self, 2, "Countdown in progress....\n"); } - else - { - dprint ("Countdown in progress....\n"); + else { + dprint("Countdown in progress....\n"); } return; } - timer = find (world, classname, "prematch"); - while (timer != world) - { - dremove (timer); - timer = find (timer, classname, "prematch"); + timer = find(world, classname, "prematch"); + while (timer != world) { + dremove(timer); + timer = find(timer, classname, "prematch"); } - f1 = stof (infokey (world, "prematch")); - timer = spawn (); + f1 = stof(infokey (world, "prematch")); + timer = spawn(); timer.owner = world; timer.classname = "prematch"; timer.cnt = 0; - if (cb_prematch_time) - { - timer.cnt2 = rint ((cb_prematch_time * 60)); - if ((timer.cnt2 < 1)) - { + if (cb_prematch_time) { + timer.cnt2 = rint(cb_prematch_time * 60); + if (timer.cnt2 < 1) { timer.cnt2 = 1; } } - else - { + else { lightstyle (0, "e"); - if (stof (infokey (world, "demo_auto_left")) > 0) - { - if (infokey (world, "serverdemo") == "on") - { - calltimeofday (); - - localcmd ("record \""); - localcmd (ftos (tod_day)); // day - localcmd ("-"); - localcmd (ftos (tod_mon)); // month - localcmd ("-"); - localcmd (ftos (tod_year)); // year - localcmd ("_"); - localcmd (ftos (tod_hour)); // hour - localcmd ("-"); - localcmd (ftos (tod_min)); // minute - localcmd ("-"); - localcmd (ftos (tod_sec)); // second - - localcmd ("_["); - localcmd (mapname); - localcmd ("]"); - localcmd ("\"\n"); + if (stof(infokey(world, "demo_auto_left")) > 0) { + if (infokey(world, "serverdemo") == "on") { + calltimeofday(); + + localcmd("record \""); + localcmd(ftos (tod_day)); // day + localcmd("-"); + localcmd(ftos (tod_mon)); // month + localcmd("-"); + localcmd(ftos (tod_year)); // year + localcmd("_"); + localcmd(ftos (tod_hour)); // hour + localcmd("-"); + localcmd(ftos (tod_min)); // minute + localcmd("-"); + localcmd(ftos (tod_sec)); // second + + localcmd("_["); + localcmd(mapname); + localcmd("]"); + localcmd("\"\n"); } } - localcmd ("serverinfo status Countdown\n"); - p = find (world, classname, "player"); - while ((p != world)) - { - if ((p.netname != "")) - { - stuffcmd (p, "play items/protect2.wav\n"); + localcmd("serverinfo status Countdown\n"); + p = find(world, classname, "player"); + while (p != world) { + if (p.netname != "") { + stuffcmd(p, "play items/protect2.wav\n"); } - p = find (timer, classname, "player"); + p = find(timer, classname, "player"); } - timer.cnt2 = rint (stof (infokey (world, "count"))); - if ((timer.cnt2 < 1)) - { + timer.cnt2 = rint(stof(infokey(world, "count"))); + if (timer.cnt2 < 1) { //By default, 10 seconds of countdown timer.cnt2 = 10; } } timer.cnt2 = (timer.cnt2 + 1); timer.nextthink = (time + 0.1); - tmp = ftos (timer.cnt2); + tmp = ftos(timer.cnt2); timer.think = PreMatch_Think; }; @@ -399,29 +352,25 @@ void () StopTimer = { local entity t; - if ((infokey (world, "serverdemo") != string_null)) - { - localcmd ("cancel\n"); + if (infokey(world, "serverdemo") != string_null) { + localcmd("cancel\n"); } - if (cb_prematch) - { - t = find (world, classname, "prematch"); - while ((t != world)) - { + if (cb_prematch) { + t = find(world, classname, "prematch"); + while (t != world) { t.nextthink = (time + 0.1); t.think = SUB_Remove; t = find (t, classname, "prematch"); } - localcmd ("serverinfo status Standby\n"); - lightstyle (0, "m"); + localcmd("serverinfo status Standby\n"); + lightstyle(0, "m"); return; } - t = find (world, classname, "match"); - if ((t != world)) - { - remove (t); + t = find(world, classname, "match"); + if (t != world) { + remove(t); } - localcmd ("serverinfo status Normal\n"); + localcmd("serverinfo status Normal\n"); }; void () DumpClanScores = { @@ -497,12 +446,14 @@ void () DumpClanScores = { if ((no_teams == 2) && (((team1score == team2score) && teamfrags) || ((team1frags == team2frags) && !teamfrags))) { bprint(PRINT_HIGH, " draw "); - } else if ((no_teams == 3) && + } + else if ((no_teams == 3) && ((((team1score == team2score) == team3score) && teamfrags) || (((team1frags == team2frags) == team3frags) && !teamfrags))) { bprint(PRINT_HIGH, " draw "); - } else if ((no_teams == 3) + } + else if ((no_teams == 3) && (((((team1score == team2score) == team3score) == team4score) && teamfrags) @@ -510,7 +461,8 @@ void () DumpClanScores = { ((((team1frags == team2frags) == team3frags) == team4frags) && !teamfrags))) { bprint(PRINT_HIGH, " draw "); - } else { + } + else { st = GetTeamName(winners); bprint(PRINT_HIGH, st, " defeated "); if ((winners != 1) && (t1_pl != 0)) { diff --git a/commands.qc b/commands.qc index 0aa50755..f856a16f 100644 --- a/commands.qc +++ b/commands.qc @@ -1,17 +1,15 @@ void () ClanMode = { local string st; - st = infokey (world, "clan"); - if ((st == "on")) - { + st = infokey(world, "clan"); + if (st == "on") { st = "off"; - localcmd ("localinfo clan off\n"); + localcmd("localinfo clan off\n"); } - else - { + else { st = "on"; - localcmd ("localinfo clan on\n"); - bprint (2, "Map Restart needed to take affect!\n"); + localcmd("localinfo clan on\n"); + bprint(2, "Map Restart needed to take affect!\n"); } - bprint3 (2, "Clan Mode set to ", st, "\n"); + bprint3(2, "Clan Mode set to ", st, "\n"); }; \ No newline at end of file diff --git a/functions.qc b/functions.qc index 80b9cddc..57cbbb00 100644 --- a/functions.qc +++ b/functions.qc @@ -5,29 +5,24 @@ void (entity pl) Menu_Close; void (float tno) playerSetTeam = { local string st; - - TeamFortress_TeamSet (tno); - + TeamFortress_TeamSet(tno); self.team_no = tno; - - stuffcmd (self, "color "); - st = ftos (TeamFortress_TeamGetColor (tno) - 1); - stuffcmd (self, st); - stuffcmd (self, "\n"); - - SetTeamName (self); + stuffcmd(self, "color "); + st = ftos(TeamFortress_TeamGetColor (tno) - 1); + stuffcmd(self, st); + stuffcmd(self, "\n"); + SetTeamName(self); }; float () PlayerCount = { local entity te; local float tmp = 0; - te = find (world, classname, "player"); + te = find(world, classname, "player"); while (te != world) { tmp = tmp + 1; - te = find (te, classname, "player"); + te = find(te, classname, "player"); } - return tmp; }; @@ -35,10 +30,10 @@ float () SpectatorCount = { local entity te; local float tmp = 0; - te = find (world, classname, "observer"); + te = find(world, classname, "observer"); while (te != world) { tmp = tmp + 1; - te = find (te, classname, "observer"); + te = find(te, classname, "observer"); } return tmp; }; @@ -46,9 +41,8 @@ float () SpectatorCount = { void () nextCaptain = { local entity te; - te = find (world, classname, "player"); + te = find(world, classname, "player"); while (te != world) { - if (te.captain == 4) te.captain = 3; else if (te.captain == 3) @@ -58,9 +52,7 @@ void () nextCaptain = { stuffcmd(te,"reload\n"); // Required to send one impulse in order to show menu } else if (te.captain == 1) te.captain = number_of_teams; - - te = find (te, classname, "player"); - + te = find(te, classname, "player"); } }; @@ -75,39 +67,30 @@ void () randomizeCaptains = { local float teamno = 0; local float capteam[4] = {0, 0, 0, 0}; - te = find (world, classname, "player"); - while (te != world) { - - if (te.captain == 9 && tmp < number_of_teams) { + te = find(world, classname, "player"); + while (te != world) { + if (te.captain == 9 && tmp < number_of_teams) { do { teamno = floor((random() * number_of_teams)); } while (capteam[teamno] == 1); - capteam[teamno] = 1; - te.captain = teamno + 1; - + te.captain = teamno + 1; if (te.captain == 1) stuffcmd(te, "reload\n"); - tmp = tmp + 1; - } - - te = find (te, classname, "player"); - } - + te = find(te, classname, "player"); + } }; - void () randomizeTeams = { local entity te, temp; local float tmp = 0; local float teamno = 0; local float randteam[4] = {0, 0, 0, 0}; - te = find (world, classname, "player"); - while (te != world) { - + te = find(world, classname, "player"); + while (te != world) { if (tmp >= number_of_teams) { tmp = 0; randteam[0] = 0; @@ -115,25 +98,18 @@ void () randomizeTeams = { randteam[2] = 0; randteam[3] = 0; } - - if (tmp < number_of_teams) { + if (tmp < number_of_teams) { do { teamno = floor((random() * number_of_teams)); } while (randteam[teamno] == 1); randteam[teamno] = 1; - temp = self; self = te; - playerSetTeam(teamno + 1); - self = temp; - tmp = tmp + 1; - - } - - te = find (te, classname, "player"); - } + } + te = find(te, classname, "player"); + } }; diff --git a/mvdsv.qc b/mvdsv.qc index 10bb9a83..38e0ef5d 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -3,29 +3,23 @@ float () UserCmd = local float arg_num; local string tmp; - arg_num = argc (); - if (arg_num == 0) - { + arg_num = argc(); + if (arg_num == 0) { return (0); } - if (argv_mvdsv(0) == "adminpwd") - { - if (arg_num == 2) - { - if (self.is_admin) - { + if (argv_mvdsv(0) == "adminpwd") { + if (arg_num == 2) { + if (self.is_admin) { sprint(self, 2, "You are already an admin\n"); return (1); } - Admin_Check(argv_mvdsv (1)); - if (self.is_admin) - { + Admin_Check(argv_mvdsv(1)); + if (self.is_admin) { Admin_Aliases(); } return (1); } - if (arg_num == 1) - { + if (arg_num == 1) { sprint(self, 2, "usage: cmd adminpwd password, where password is the admin password\n"); sprint(self, 2, "\n"); return (1); @@ -33,18 +27,15 @@ float () UserCmd = } if (self.is_admin) { //Adminpwd commands - if (argv_mvdsv(0) == "timelimit") - { - if (arg_num == 2) - { + if (argv_mvdsv(0) == "timelimit") { + if (arg_num == 2) { localcmd("timelimit "); - localcmd(argv_mvdsv (1)); + localcmd(argv_mvdsv(1)); localcmd("\n"); return (1); } - if (arg_num == 1) - { - tmp = infokey(world, argv_mvdsv (0)); + if (arg_num == 1) { + tmp = infokey(world, argv_mvdsv(0)); sprint(self, 2, "timelimit is "); sprint(self, 2, "\""); sprint(self, 2, tmp); @@ -52,18 +43,15 @@ float () UserCmd = return (1); } } - else if (argv_mvdsv(0) == "prematch") - { - if (arg_num == 2) - { + else if (argv_mvdsv(0) == "prematch") { + if (arg_num == 2) { localcmd("prematch "); - localcmd(argv_mvdsv (1)); + localcmd(argv_mvdsv(1)); localcmd("\n"); return (1); } - if (arg_num == 1) - { - tmp = infokey(world, argv_mvdsv (0)); + if (arg_num == 1) { + tmp = infokey(world, argv_mvdsv(0)); sprint(self, 2, "prematch is "); sprint(self, 2, "\""); sprint(self, 2, tmp); @@ -71,18 +59,15 @@ float () UserCmd = return (1); } } - else if (argv_mvdsv (0) == "fraglimit") - { - if (arg_num == 2) - { + else if (argv_mvdsv(0) == "fraglimit") { + if (arg_num == 2) { localcmd("fraglimit "); - localcmd(argv_mvdsv (1)); + localcmd(argv_mvdsv(1)); localcmd("\n"); return (1); } - if (arg_num == 1) - { - tmp = infokey(world, argv_mvdsv (0)); + if (arg_num == 1) { + tmp = infokey(world, argv_mvdsv(0)); sprint(self, 2, "fraglimit is "); sprint(self, 2, "\""); sprint(self, 2, tmp); @@ -90,18 +75,15 @@ float () UserCmd = return (1); } } - else if (argv_mvdsv(0) == "teamplay") - { - if (arg_num == 2) - { + else if (argv_mvdsv(0) == "teamplay") { + if (arg_num == 2) { localcmd("teamplay "); - localcmd(argv_mvdsv (1)); + localcmd(argv_mvdsv(1)); localcmd("\n"); return (1); } - if (arg_num == 1) - { - tmp = infokey(world, argv_mvdsv (0)); + if (arg_num == 1) { + tmp = infokey(world, argv_mvdsv(0)); sprint(self, 2, "teamplay is "); sprint(self, 2, "\""); sprint(self, 2, tmp); @@ -109,119 +91,100 @@ float () UserCmd = return (1); } } - else if (argv_mvdsv(0) == "password") - { - if (arg_num == 2) - { + else if (argv_mvdsv(0) == "password") { + if (arg_num == 2) { localcmd("password "); if (argv_mvdsv(1) == "none") { localcmd("\"\""); - } else { - localcmd(argv_mvdsv (1)); + } + else { + localcmd(argv_mvdsv(1)); } localcmd("\n"); bprint("\n"); argv_mvdsv(1); if (argv_mvdsv(1) == "none") { - bprint(2, "Server Password removed!\n"); - } else { - bprint3(2, "Server Password changed to \"", argv_mvdsv (1), "\"\n"); + bprint(2, Q"\sServer Password removed!\s\n"); + } + else { + bprint3(2, Q"\sServer Password changed to \"", argv_mvdsv(1), "\"\s\n"); } bprint("\n"); return (1); } - if (arg_num == 1) - { + if (arg_num == 1) { sprint(self, 2, "usage: cmd password pwd\n"); sprint(self, 2, "\n"); return (1); } } - else if (argv_mvdsv(0) == "record") - { - if (arg_num == 2) - { + else if (argv_mvdsv(0) == "record") { + if (arg_num == 2) { localcmd("record "); - localcmd(argv_mvdsv (1)); + localcmd(argv_mvdsv(1)); localcmd("\n"); return (1); } - if (arg_num == 1) - { + if (arg_num == 1) { sprint(self, 2, "usage: cmd record demo, where demo is the demo name\n"); sprint(self, 2, "\n"); return (1); } } - else if (argv_mvdsv(0) == "easyrecord") - { - if (arg_num == 2) - { + else if (argv_mvdsv(0) == "easyrecord") { + if (arg_num == 2) { localcmd("easyrecord "); - localcmd(argv_mvdsv (1)); + localcmd(argv_mvdsv(1)); localcmd("\n"); return (1); } - if (arg_num == 1) - { + if (arg_num == 1) { localcmd("easyrecord\n"); return (1); } } - else if (argv_mvdsv(0) == "autorecord") - { - if (arg_num == 2) - { + else if (argv_mvdsv(0) == "autorecord") { + if (arg_num == 2) { localcmd("localinfo demo_auto_left "); - localcmd(argv_mvdsv (1)); + localcmd(argv_mvdsv(1)); localcmd("\n"); return (1); } - if (arg_num == 1) - { + if (arg_num == 1) { tmp = infokey(world, "demo_auto_left"); - if (stof(tmp) > 0) - { + if (stof(tmp) > 0) { dprint ("Auto-Recording off\n"); localcmd ("localinfo demo_auto_left 0\n"); return (1); } - else - { + else { dprint("Auto-Recording the next match\n"); localcmd("localinfo demo_auto_left 1\n"); return (1); } } } - else if (argv_mvdsv(0) == "cancel") - { + else if (argv_mvdsv(0) == "cancel") { localcmd ("cancel\n"); return (1); } - else if (argv_mvdsv(0) == "stop") - { + else if (argv_mvdsv(0) == "stop") { localcmd ("stop\n"); return (1); } - else if (argv_mvdsv(0) == "kick") - { + else if (argv_mvdsv(0) == "kick") { Admin_CycleDeal(); return (1); } - else if (argv_mvdsv(0) == "map") - { - if (self.is_admin) - { - if (clanbattle == 1 && !(cb_prematch)) - { - sprint (self, 2, "Clan Battle in progress....\n"); + else if (argv_mvdsv(0) == "map") { + if (self.is_admin) { + if (clanbattle == 1 && !(cb_prematch)) { + sprint(self, 2, "Clan Battle in progress....\n"); self.impulse = 0; return (1); } } - if (arg_num == 2) - { + if (arg_num == 2) { bprint(2, self.netname); bprint(2, " Has changed the map to "); bprint(2, argv_mvdsv(1)); @@ -231,15 +194,13 @@ float () UserCmd = localcmd("\n"); return (1); } - if (arg_num == 1) - { + if (arg_num == 1) { sprint (self, 2, "usage: cmd map mapname, where mapname is the map name you wish to change to\n"); sprint (self, 2, "\n"); return (1); } } - else if (argv_mvdsv(0) == "help" || argv_mvdsv(0) == "list") - { + else if (argv_mvdsv(0) == "help" || argv_mvdsv(0) == "list") { sprint(self, 2, "Commands list:\n"); sprint(self, 2, "cmd adminpwd\n"); sprint(self, 2, "cmd timelimit\n"); @@ -266,58 +227,51 @@ float () ConsoleCmd { local float arg_num; local string tmp; - arg_num = argc (); - if (arg_num == 0) - { + arg_num = argc(); + if (arg_num == 0) { return (0); } - if (argv_mvdsv (0) == "prematch") { - if (arg_num == 2) - { - localcmd ("localinfo prematch "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + if (argv_mvdsv(0) == "prematch") { + if (arg_num == 2) { + localcmd("localinfo prematch "); + localcmd(argv_mvdsv(1)); + localcmd("\n"); return (1); } - if (arg_num == 1) - { - tmp = infokey (world, argv_mvdsv (0)); - dprint ("prematch is "); - dprint ("\""); - dprint (tmp); - dprint ("\"\n"); + if (arg_num == 1) { + tmp = infokey (world, argv_mvdsv(0)); + dprint("prematch is "); + dprint("\""); + dprint(tmp); + dprint("\"\n"); return (1); } } - else if (argv_mvdsv (0) == "autorecord") + else if (argv_mvdsv(0) == "autorecord") { - if (arg_num == 2) - { - localcmd ("localinfo demo_auto_left "); - localcmd (argv_mvdsv (1)); - localcmd ("\n"); + if (arg_num == 2) { + localcmd("localinfo demo_auto_left "); + localcmd(argv_mvdsv(1)); + localcmd("\n"); return (1); } - if (arg_num == 1) - { + if (arg_num == 1) { tmp = infokey (world, "demo_auto_left"); - if ((stof (tmp) > 0)) - { - dprint ("Auto-Recording off\n"); - localcmd ("localinfo demo_auto_left 0\n"); + if ((stof(tmp) > 0)) { + dprint("Auto-Recording off\n"); + localcmd("localinfo demo_auto_left 0\n"); return (1); } - else - { - dprint ("Auto-Recording the next match\n"); - localcmd ("localinfo demo_auto_left 1\n"); + else { + dprint("Auto-Recording the next match\n"); + localcmd("localinfo demo_auto_left 1\n"); return (1); } } } - else if (argv_mvdsv (0) == "clan") + else if (argv_mvdsv(0) == "clan") { - ClanMode (); + ClanMode(); return (1); } return 0; diff --git a/weapons.qc b/weapons.qc index 9fde972f..37bc8eeb 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2316,7 +2316,7 @@ void () ImpulseCommands = { if ((self.last_impulse == TF_DETPACK) && self.impulse) TeamFortress_SetDetpack(self.impulse); - if ((cb_prematch) || cease_fire) { + if (cb_prematch || cease_fire) { PreMatchImpulses(); DeadImpulses(); self.impulse = 0; From 9fd264490bd5698e5f12981af1af5a67ada98897 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 00:43:35 +0000 Subject: [PATCH 0543/2474] changing pyro's rocket to resemble heavy incendiary cannon from ozt. On toggle, oztf_classes --- client.qc | 3 ++ pyro.qc | 82 +++++++++++++++++++++++++++++++++++++----------------- qw.qc | 1 + weapons.qc | 5 +++- 4 files changed, 64 insertions(+), 27 deletions(-) diff --git a/client.qc b/client.qc index 5f46abbc..55a498a1 100644 --- a/client.qc +++ b/client.qc @@ -498,6 +498,9 @@ void () DecodeLevelParms = { // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); + // oztf-like classes + oztf_classes = CF_GetSetting("oztfclasses", "oztf_classes", "on"); + st = infokey(world, "default"); if (st == "on") { server_default = TRUE; diff --git a/pyro.qc b/pyro.qc index 9049e7fe..94eaf498 100644 --- a/pyro.qc +++ b/pyro.qc @@ -617,6 +617,23 @@ void () W_FireFlame = { setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); }; +void () IncendiaryRadius = +{ + local float damg; + + damg = 64; + deathmsg = 15; + T_RadiusDamage(self, self.owner, damg, other); + self.origin = (self.origin - (8 * normalize (self.velocity))); + WriteByte(4, 23); + WriteByte(4, 3); + WriteCoord(4, self.origin_x); + WriteCoord(4, self.origin_y); + WriteCoord(4, self.origin_z); + multicast(self.origin, 1); + dremove(self); +}; + void () T_IncendiaryTouch = { local float damg; local entity head; @@ -629,39 +646,46 @@ void () T_IncendiaryTouch = { return; } self.effects = self.effects | 4; - damg = 30 + random() * 20; + if (oztf_classes) + damg = 50 + random() * 20; + else + damg = 30 + random() * 20; if (other.health) { deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_FIRE); } - head = findradius(self.origin, 180); - while (head) { - if (head.takedamage) { - traceline(self.origin, head.origin, 1, self); - if ((trace_fraction == 1) - || ((trace_fraction != 1) - && (vlen(self.origin - head.origin) <= 64))) { - deathmsg = DMSG_FLAME; - TF_T_Damage(head, self, self.owner, 10, TF_TD_NOTTEAM, - TF_TD_FIRE); - other = head; - Napalm_touch(); - if (other.classname == "player") { - stuffcmd(other, "bf\nbf\n"); + if (oztf_classes) + IncendiaryRadius(); + else { + head = findradius(self.origin, 180); + while (head) { + if (head.takedamage) { + traceline(self.origin, head.origin, 1, self); + if ((trace_fraction == 1) + || ((trace_fraction != 1) + && (vlen(self.origin - head.origin) <= 64))) { + deathmsg = DMSG_FLAME; + TF_T_Damage(head, self, self.owner, 10, TF_TD_NOTTEAM, + TF_TD_FIRE); + other = head; + Napalm_touch(); + if (other.classname == "player") { + stuffcmd(other, "bf\nbf\n"); + } } } + head = head.chain; } - head = head.chain; + self.origin = self.origin - 8 * normalize(self.velocity); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PHS); + dremove(self); } - self.origin = self.origin - 8 * normalize(self.velocity); - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); - dremove(self); }; void () W_FireIncendiaryCannon = { @@ -678,11 +702,17 @@ void () W_FireIncendiaryCannon = { newmis.solid = SOLID_BBOX; makevectors(self.v_angle); newmis.velocity = aim(self, 1000); - newmis.velocity = newmis.velocity * 600; + if (oztf_classes) { + newmis.velocity = newmis.velocity * 800; + newmis.think = IncendiaryRadius; + } + else { + newmis.velocity = newmis.velocity * 600; + newmis.think = SUB_Remove; + } newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_IncendiaryTouch; newmis.nextthink = time + 5; - newmis.think = SUB_Remove; newmis.weapon = DMSG_INCENDIARY; setmodel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); diff --git a/qw.qc b/qw.qc index ac98ec7c..37ffc3fa 100644 --- a/qw.qc +++ b/qw.qc @@ -494,6 +494,7 @@ float ng_velocity; float ng_damage; float sng_damage; float old_ng_rof; +float oztf_classes; .float teamkills; diff --git a/weapons.qc b/weapons.qc index 37bc8eeb..ddf1d615 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1933,7 +1933,10 @@ void () W_Attack = { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); - Attack_Finished(1.2); + if (oztf_classes) + Attack_Finished(0.9); + else + Attack_Finished(1.2); } else if (time >= self.antispam_incendiary_cannon) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; From 8a1be6c5cbf84597961bf98b62db87cad5b69547 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 11:00:46 +0000 Subject: [PATCH 0544/2474] changing pyro toggle from oztf_classes to pyro_type --- client.qc | 4 ++-- pyro.qc | 6 +++--- qw.qc | 2 +- weapons.qc | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client.qc b/client.qc index 55a498a1..32a2fa2f 100644 --- a/client.qc +++ b/client.qc @@ -498,8 +498,8 @@ void () DecodeLevelParms = { // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); - // oztf-like classes - oztf_classes = CF_GetSetting("oztfclasses", "oztf_classes", "on"); + // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass + pyro_type = CF_GetSetting("pyrotype", "pyro_type", 0); st = infokey(world, "default"); if (st == "on") { diff --git a/pyro.qc b/pyro.qc index 94eaf498..e7b1c5bc 100644 --- a/pyro.qc +++ b/pyro.qc @@ -646,7 +646,7 @@ void () T_IncendiaryTouch = { return; } self.effects = self.effects | 4; - if (oztf_classes) + if (pyro_type == 1) damg = 50 + random() * 20; else damg = 30 + random() * 20; @@ -655,7 +655,7 @@ void () T_IncendiaryTouch = { TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_FIRE); } - if (oztf_classes) + if (pyro_type == 1) IncendiaryRadius(); else { head = findradius(self.origin, 180); @@ -702,7 +702,7 @@ void () W_FireIncendiaryCannon = { newmis.solid = SOLID_BBOX; makevectors(self.v_angle); newmis.velocity = aim(self, 1000); - if (oztf_classes) { + if (pyro_type == 1) { newmis.velocity = newmis.velocity * 800; newmis.think = IncendiaryRadius; } diff --git a/qw.qc b/qw.qc index 37ffc3fa..07b630e9 100644 --- a/qw.qc +++ b/qw.qc @@ -494,7 +494,7 @@ float ng_velocity; float ng_damage; float sng_damage; float old_ng_rof; -float oztf_classes; +float pyro_type; .float teamkills; diff --git a/weapons.qc b/weapons.qc index ddf1d615..f4b9bd5d 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1933,7 +1933,7 @@ void () W_Attack = { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); - if (oztf_classes) + if (pyro_type == 1) Attack_Finished(0.9); else Attack_Finished(1.2); From ad965686c407e2547ec5b46b071dcc83d295c920 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 11:11:00 +0000 Subject: [PATCH 0545/2474] tweaking damage numbers to make pyro rjump more useful --- pyro.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyro.qc b/pyro.qc index e7b1c5bc..ea0ba892 100644 --- a/pyro.qc +++ b/pyro.qc @@ -621,7 +621,7 @@ void () IncendiaryRadius = { local float damg; - damg = 64; + damg = 69; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -647,7 +647,7 @@ void () T_IncendiaryTouch = { } self.effects = self.effects | 4; if (pyro_type == 1) - damg = 50 + random() * 20; + damg = 45 + random() * 20; else damg = 30 + random() * 20; if (other.health) { From 42721b87062e4023440ec2080554d0c62fb21e46 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 19:53:59 +0000 Subject: [PATCH 0546/2474] making rjump more effective --- client.qc | 2 ++ pyro.qc | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index 32a2fa2f..ebe37dfc 100644 --- a/client.qc +++ b/client.qc @@ -549,6 +549,7 @@ void () DecodeLevelParms = { old_hp_armor = FALSE; ng_velocity = 1500; old_ng_rof = FALSE; + pyro_type = 0; } st = infokey(world, "faithful"); @@ -598,6 +599,7 @@ void () DecodeLevelParms = { old_hp_armor = TRUE; ng_velocity = 1000; old_ng_rof = TRUE; + pyro_type = 0; } } diff --git a/pyro.qc b/pyro.qc index ea0ba892..ade987ea 100644 --- a/pyro.qc +++ b/pyro.qc @@ -621,7 +621,7 @@ void () IncendiaryRadius = { local float damg; - damg = 69; + damg = 72; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -647,7 +647,7 @@ void () T_IncendiaryTouch = { } self.effects = self.effects | 4; if (pyro_type == 1) - damg = 45 + random() * 20; + damg = 42 + random() * 20; else damg = 30 + random() * 20; if (other.health) { From 3146201da17c23c99dde66aba37f5eec25f50cae Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Wed, 30 Jan 2019 19:18:35 +0000 Subject: [PATCH 0547/2474] trying to solve countdown problems, cleaning compiler warnings --- clan.qc | 5 +++-- menu.qc | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/clan.qc b/clan.qc index 8d6c8de5..cbdef05c 100644 --- a/clan.qc +++ b/clan.qc @@ -197,6 +197,7 @@ void () PreMatch_Think = { if (self.cnt2 == 10) { lightstyle(0, "e"); localcmd("serverinfo status Countdown\n"); + bprint(2,"\n"); if (stof(infokey(world, "demo_auto_left")) > 0) { if (infokey(world, "serverdemo") == "on") { @@ -240,10 +241,10 @@ void () PreMatch_Think = { p = find(p, classname, "player"); } if (self.cnt2 > 1) { - bprint2(2, num, " seconds.\n"); + bprint2(2, num, " seconds \n"); } else { - bprint(2, "1 second.\n"); + bprint(2, "1 second \n"); } } self.nextthink = (time + 1); diff --git a/menu.qc b/menu.qc index 777daa25..6a02e562 100644 --- a/menu.qc +++ b/menu.qc @@ -1037,6 +1037,8 @@ void () Menu_Admin = local float f_tmp2; self.impulse = 0; + s_menu1 = ""; + s_menu2 = ""; if (self.current_menu_type == 0) { s_menu1 = "FortressOne Admin Menu: \n\n"; @@ -1280,19 +1282,19 @@ void (float inp) Menu_Admin_Input = } else { // end captainmode1 disableCaptain(); - local entity te; - local entity temp; - te = self; - temp = find (world, classname, "player"); - while (temp != world) { - self = temp; - temp.captain = 0; + local entity pl; + local entity temppl; + pl = self; + temppl = find (world, classname, "player"); + while (temppl != world) { + self = temppl; + temppl.captain = 0; Menu_Close(self); self.current_menu_type = 0; self.current_menu_page = 0; - temp = find (temp, classname, "player"); + temppl = find (temppl, classname, "player"); } - self = te; + self = pl; } Menu_Admin(); From 5ed0718e4bc7a726b22513717094e0c800952e72 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 31 Jan 2019 12:56:47 +1100 Subject: [PATCH 0548/2474] fix for countdown being broken --- clan.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clan.qc b/clan.qc index cbdef05c..96349cb1 100644 --- a/clan.qc +++ b/clan.qc @@ -197,7 +197,6 @@ void () PreMatch_Think = { if (self.cnt2 == 10) { lightstyle(0, "e"); localcmd("serverinfo status Countdown\n"); - bprint(2,"\n"); if (stof(infokey(world, "demo_auto_left")) > 0) { if (infokey(world, "serverdemo") == "on") { @@ -223,7 +222,7 @@ void () PreMatch_Think = { } } } - num = ftos(self.cnt2); + num = strzone(ftos(self.cnt2)); p = find(world, classname, "player"); tmp = strcat(num ,"\n\n\b:[\b"); tmp = strcat(tmp, mapname); @@ -246,6 +245,7 @@ void () PreMatch_Think = { else { bprint(2, "1 second \n"); } + strunzone(num); } self.nextthink = (time + 1); }; From ac3ffbc2568556ebd31e45007dab65a254866b53 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 31 Jan 2019 13:14:17 +1100 Subject: [PATCH 0549/2474] implement impulse queueing and support in detpipe --- client.qc | 6 ++++++ demoman.qc | 7 +++++-- qw.qc | 1 + weapons.qc | 15 +++++++++++---- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/client.qc b/client.qc index 5f46abbc..d9a38ddc 100644 --- a/client.qc +++ b/client.qc @@ -498,8 +498,13 @@ void () DecodeLevelParms = { // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); + // impulse command queueing + // ensures detpipe impulse isn't cleared at end of function + impulse_queue = CF_GetSetting("impulsequeue", "impulse_queue", "off"); + st = infokey(world, "default"); if (st == "on") { + impulse_queue = FALSE; server_default = TRUE; old_grens = FALSE; drop_grenades = TRUE; @@ -550,6 +555,7 @@ void () DecodeLevelParms = { st = infokey(world, "faithful"); if (st == "on") { + impulse_queue = FALSE; server_faithful = TRUE; drop_grenades = FALSE; drop_grenpack = FALSE; diff --git a/demoman.qc b/demoman.qc index 29e763ed..dee09745 100644 --- a/demoman.qc +++ b/demoman.qc @@ -17,11 +17,13 @@ void () TeamFortress_DetpackTouch; void () TeamFortress_DetpackDisarm; void () TeamFortress_DetpackCountDown; -void (float force) TeamFortress_DetonatePipebombs = { +float (float force) TeamFortress_DetonatePipebombs = { local entity e; if (time < self.pipecooldown && !force) - return; + { + return impulse_queue ? FALSE : TRUE; + } e = find(world, classname, "pipebomb"); while (e != world) { @@ -29,6 +31,7 @@ void (float force) TeamFortress_DetonatePipebombs = { e.nextthink = time; e = find(e, classname, "pipebomb"); } + return TRUE; }; void () PipebombTouch = { diff --git a/qw.qc b/qw.qc index ac98ec7c..1382057f 100644 --- a/qw.qc +++ b/qw.qc @@ -494,6 +494,7 @@ float ng_velocity; float ng_damage; float sng_damage; float old_ng_rof; +float impulse_queue; .float teamkills; diff --git a/weapons.qc b/weapons.qc index 37bc8eeb..dd41b6ea 100644 --- a/weapons.qc +++ b/weapons.qc @@ -60,7 +60,7 @@ void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; void () TeamFortress_Discard_DropAmmo; -void (float force) TeamFortress_DetonatePipebombs; +float (float force) TeamFortress_DetonatePipebombs; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; @@ -2313,6 +2313,9 @@ void () PreMatchImpulses; void () DeadImpulses; void () ImpulseCommands = { + float clearImpulse; // related to impulse_queue + clearImpulse = TRUE; + if ((self.last_impulse == TF_DETPACK) && self.impulse) TeamFortress_SetDetpack(self.impulse); @@ -2406,8 +2409,8 @@ void () ImpulseCommands = { TeamFortress_Discard_DropAmmo(); else if (self.impulse == TF_DASH) CF_Scout_Dash(); - else if (self.impulse == TF_PB_DETONATE) - TeamFortress_DetonatePipebombs(0); + else if (self.impulse == TF_PB_DETONATE) + clearImpulse = TeamFortress_DetonatePipebombs(0); else if (self.impulse == TF_DETPACK_STOP) TeamFortress_DetpackStop(); else if (self.impulse == TF_MEDIC_AURA_TOGGLE) @@ -2487,7 +2490,11 @@ void () ImpulseCommands = { if (self.impulse == TF_DETPACK) self.last_impulse = self.impulse; - self.impulse = 0; + if (clearImpulse) + { + self.impulse = 0; + } + }; void () PreMatchImpulses = { From 9e60e3ab0babcb028626744aefb0cfdc246ac773 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 00:43:35 +0000 Subject: [PATCH 0550/2474] changing pyro's rocket to resemble heavy incendiary cannon from ozt. On toggle, oztf_classes --- client.qc | 3 ++ pyro.qc | 82 +++++++++++++++++++++++++++++++++++++----------------- qw.qc | 1 + weapons.qc | 5 +++- 4 files changed, 64 insertions(+), 27 deletions(-) diff --git a/client.qc b/client.qc index d9a38ddc..a6f7f77a 100644 --- a/client.qc +++ b/client.qc @@ -502,6 +502,9 @@ void () DecodeLevelParms = { // ensures detpipe impulse isn't cleared at end of function impulse_queue = CF_GetSetting("impulsequeue", "impulse_queue", "off"); + // oztf-like classes + oztf_classes = CF_GetSetting("oztfclasses", "oztf_classes", "on"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/pyro.qc b/pyro.qc index 9049e7fe..94eaf498 100644 --- a/pyro.qc +++ b/pyro.qc @@ -617,6 +617,23 @@ void () W_FireFlame = { setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); }; +void () IncendiaryRadius = +{ + local float damg; + + damg = 64; + deathmsg = 15; + T_RadiusDamage(self, self.owner, damg, other); + self.origin = (self.origin - (8 * normalize (self.velocity))); + WriteByte(4, 23); + WriteByte(4, 3); + WriteCoord(4, self.origin_x); + WriteCoord(4, self.origin_y); + WriteCoord(4, self.origin_z); + multicast(self.origin, 1); + dremove(self); +}; + void () T_IncendiaryTouch = { local float damg; local entity head; @@ -629,39 +646,46 @@ void () T_IncendiaryTouch = { return; } self.effects = self.effects | 4; - damg = 30 + random() * 20; + if (oztf_classes) + damg = 50 + random() * 20; + else + damg = 30 + random() * 20; if (other.health) { deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_FIRE); } - head = findradius(self.origin, 180); - while (head) { - if (head.takedamage) { - traceline(self.origin, head.origin, 1, self); - if ((trace_fraction == 1) - || ((trace_fraction != 1) - && (vlen(self.origin - head.origin) <= 64))) { - deathmsg = DMSG_FLAME; - TF_T_Damage(head, self, self.owner, 10, TF_TD_NOTTEAM, - TF_TD_FIRE); - other = head; - Napalm_touch(); - if (other.classname == "player") { - stuffcmd(other, "bf\nbf\n"); + if (oztf_classes) + IncendiaryRadius(); + else { + head = findradius(self.origin, 180); + while (head) { + if (head.takedamage) { + traceline(self.origin, head.origin, 1, self); + if ((trace_fraction == 1) + || ((trace_fraction != 1) + && (vlen(self.origin - head.origin) <= 64))) { + deathmsg = DMSG_FLAME; + TF_T_Damage(head, self, self.owner, 10, TF_TD_NOTTEAM, + TF_TD_FIRE); + other = head; + Napalm_touch(); + if (other.classname == "player") { + stuffcmd(other, "bf\nbf\n"); + } } } + head = head.chain; } - head = head.chain; + self.origin = self.origin - 8 * normalize(self.velocity); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PHS); + dremove(self); } - self.origin = self.origin - 8 * normalize(self.velocity); - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); - dremove(self); }; void () W_FireIncendiaryCannon = { @@ -678,11 +702,17 @@ void () W_FireIncendiaryCannon = { newmis.solid = SOLID_BBOX; makevectors(self.v_angle); newmis.velocity = aim(self, 1000); - newmis.velocity = newmis.velocity * 600; + if (oztf_classes) { + newmis.velocity = newmis.velocity * 800; + newmis.think = IncendiaryRadius; + } + else { + newmis.velocity = newmis.velocity * 600; + newmis.think = SUB_Remove; + } newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_IncendiaryTouch; newmis.nextthink = time + 5; - newmis.think = SUB_Remove; newmis.weapon = DMSG_INCENDIARY; setmodel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); diff --git a/qw.qc b/qw.qc index 1382057f..b65a2e9e 100644 --- a/qw.qc +++ b/qw.qc @@ -495,6 +495,7 @@ float ng_damage; float sng_damage; float old_ng_rof; float impulse_queue; +float oztf_classes; .float teamkills; diff --git a/weapons.qc b/weapons.qc index dd41b6ea..a59268ae 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1933,7 +1933,10 @@ void () W_Attack = { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); - Attack_Finished(1.2); + if (oztf_classes) + Attack_Finished(0.9); + else + Attack_Finished(1.2); } else if (time >= self.antispam_incendiary_cannon) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; From 55fcbc55fa6c8c7fdba9d609cced17ed912f514f Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 11:00:46 +0000 Subject: [PATCH 0551/2474] changing pyro toggle from oztf_classes to pyro_type --- client.qc | 4 ++-- pyro.qc | 6 +++--- qw.qc | 2 +- weapons.qc | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client.qc b/client.qc index a6f7f77a..c9df5bab 100644 --- a/client.qc +++ b/client.qc @@ -502,8 +502,8 @@ void () DecodeLevelParms = { // ensures detpipe impulse isn't cleared at end of function impulse_queue = CF_GetSetting("impulsequeue", "impulse_queue", "off"); - // oztf-like classes - oztf_classes = CF_GetSetting("oztfclasses", "oztf_classes", "on"); + // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass + pyro_type = CF_GetSetting("pyrotype", "pyro_type", 0); st = infokey(world, "default"); if (st == "on") { diff --git a/pyro.qc b/pyro.qc index 94eaf498..e7b1c5bc 100644 --- a/pyro.qc +++ b/pyro.qc @@ -646,7 +646,7 @@ void () T_IncendiaryTouch = { return; } self.effects = self.effects | 4; - if (oztf_classes) + if (pyro_type == 1) damg = 50 + random() * 20; else damg = 30 + random() * 20; @@ -655,7 +655,7 @@ void () T_IncendiaryTouch = { TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_FIRE); } - if (oztf_classes) + if (pyro_type == 1) IncendiaryRadius(); else { head = findradius(self.origin, 180); @@ -702,7 +702,7 @@ void () W_FireIncendiaryCannon = { newmis.solid = SOLID_BBOX; makevectors(self.v_angle); newmis.velocity = aim(self, 1000); - if (oztf_classes) { + if (pyro_type == 1) { newmis.velocity = newmis.velocity * 800; newmis.think = IncendiaryRadius; } diff --git a/qw.qc b/qw.qc index b65a2e9e..b2d4bed9 100644 --- a/qw.qc +++ b/qw.qc @@ -495,7 +495,7 @@ float ng_damage; float sng_damage; float old_ng_rof; float impulse_queue; -float oztf_classes; +float pyro_type; .float teamkills; diff --git a/weapons.qc b/weapons.qc index a59268ae..2ecf1437 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1933,7 +1933,7 @@ void () W_Attack = { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); - if (oztf_classes) + if (pyro_type == 1) Attack_Finished(0.9); else Attack_Finished(1.2); From f74029e44a5fe81bb349fa8d6bd0e84b48ddd65c Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 11:11:00 +0000 Subject: [PATCH 0552/2474] tweaking damage numbers to make pyro rjump more useful --- pyro.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyro.qc b/pyro.qc index e7b1c5bc..ea0ba892 100644 --- a/pyro.qc +++ b/pyro.qc @@ -621,7 +621,7 @@ void () IncendiaryRadius = { local float damg; - damg = 64; + damg = 69; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -647,7 +647,7 @@ void () T_IncendiaryTouch = { } self.effects = self.effects | 4; if (pyro_type == 1) - damg = 50 + random() * 20; + damg = 45 + random() * 20; else damg = 30 + random() * 20; if (other.health) { From 9753352fd5e61300dd173394f1210afd1df611d1 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 26 Jan 2019 19:53:59 +0000 Subject: [PATCH 0553/2474] making rjump more effective --- client.qc | 2 ++ pyro.qc | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index c9df5bab..b556238f 100644 --- a/client.qc +++ b/client.qc @@ -554,6 +554,7 @@ void () DecodeLevelParms = { old_hp_armor = FALSE; ng_velocity = 1500; old_ng_rof = FALSE; + pyro_type = 0; } st = infokey(world, "faithful"); @@ -604,6 +605,7 @@ void () DecodeLevelParms = { old_hp_armor = TRUE; ng_velocity = 1000; old_ng_rof = TRUE; + pyro_type = 0; } } diff --git a/pyro.qc b/pyro.qc index ea0ba892..ade987ea 100644 --- a/pyro.qc +++ b/pyro.qc @@ -621,7 +621,7 @@ void () IncendiaryRadius = { local float damg; - damg = 69; + damg = 72; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -647,7 +647,7 @@ void () T_IncendiaryTouch = { } self.effects = self.effects | 4; if (pyro_type == 1) - damg = 45 + random() * 20; + damg = 42 + random() * 20; else damg = 30 + random() * 20; if (other.health) { From 0229738e67ef6a190f2be4f9ea2ddee19c7c727d Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 31 Jan 2019 13:58:33 +1100 Subject: [PATCH 0554/2474] enable buffed pyro for FO defaults --- client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index b556238f..28026c0c 100644 --- a/client.qc +++ b/client.qc @@ -503,7 +503,7 @@ void () DecodeLevelParms = { impulse_queue = CF_GetSetting("impulsequeue", "impulse_queue", "off"); // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass - pyro_type = CF_GetSetting("pyrotype", "pyro_type", 0); + pyro_type = CF_GetSetting("pyrotype", "pyro_type", 1); st = infokey(world, "default"); if (st == "on") { @@ -554,7 +554,7 @@ void () DecodeLevelParms = { old_hp_armor = FALSE; ng_velocity = 1500; old_ng_rof = FALSE; - pyro_type = 0; + pyro_type = 1; } st = infokey(world, "faithful"); From be7b79a0b603c400140fd614f1b5a2394281148a Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Thu, 31 Jan 2019 15:40:04 +0000 Subject: [PATCH 0555/2474] fixing CF_GetSetting for pyrotype, from float to string --- client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 28026c0c..6ac0fa27 100644 --- a/client.qc +++ b/client.qc @@ -503,7 +503,7 @@ void () DecodeLevelParms = { impulse_queue = CF_GetSetting("impulsequeue", "impulse_queue", "off"); // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass - pyro_type = CF_GetSetting("pyrotype", "pyro_type", 1); + pyro_type = CF_GetSetting("pyrotype", "pyro_type", "1"); st = infokey(world, "default"); if (st == "on") { From 7e38311aa420a917c0a906dc8d7ff2670834e009 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 1 Feb 2019 14:38:24 +1100 Subject: [PATCH 0556/2474] POC for particles to appear above spy's head for teammates and enemy team if disguised as their team as a spy --- client.qc | 3 +++ spy.qc | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 6ac0fa27..983a2cae 100644 --- a/client.qc +++ b/client.qc @@ -1943,6 +1943,9 @@ void () PlayerPostThink = { self.impulse = 0; return; } + + SpyParticles(); + if (((self.jump_flag < -300) && (self.flags & 512)) && (self.health > 0)) { if (self.watertype == -3) { diff --git a/spy.qc b/spy.qc index b0480917..4b8ad114 100644 --- a/spy.qc +++ b/spy.qc @@ -1376,4 +1376,36 @@ void () Spy_DropBackpack = { newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; \ No newline at end of file +}; + +void () SpyParticles = { + if (self.playerclass == PC_SPY) + { + entity te, t1; + te = find(world, classname, "player"); + while (te) { + if ( + (te.team_no == self.team_no) + || (te.team_no == self.undercover_team && self.undercover_skin == PC_SPY) + ) + { + if (visible(te)) { + msg_entity = te; + tl = spawn(); + tl.origin = self.origin; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_LIGHTNING3); + WriteEntity(MSG_ONE, tl); + WriteCoord(MSG_ONE, tl.origin_x); + WriteCoord(MSG_ONE, tl.origin_y); + WriteCoord(MSG_ONE, tl.origin_z + 56); + WriteCoord(MSG_ONE, self.origin_x); + WriteCoord(MSG_ONE, self.origin_y); + WriteCoord(MSG_ONE, self.origin_z + 32); + dremove(tl); + } + } + te = find(te, classname, "player"); + } + } +} \ No newline at end of file From c486401451a8fd950ec4c3396f662d2e2799a20e Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 1 Feb 2019 14:39:20 +1100 Subject: [PATCH 0557/2474] declaration --- client.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client.qc b/client.qc index 983a2cae..aca7f419 100644 --- a/client.qc +++ b/client.qc @@ -1932,6 +1932,8 @@ void () CheckPowerups = { } }; +void () SpyParticles; + void () PlayerPostThink = { local float fdmg; From ec69d12c96d03f21f2ccbac1546665625fc729bd Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 1 Feb 2019 16:25:38 +1100 Subject: [PATCH 0558/2474] better spy system --- client.qc | 4 --- spy.qc | 73 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/client.qc b/client.qc index aca7f419..b4eeba31 100644 --- a/client.qc +++ b/client.qc @@ -1932,8 +1932,6 @@ void () CheckPowerups = { } }; -void () SpyParticles; - void () PlayerPostThink = { local float fdmg; @@ -1946,8 +1944,6 @@ void () PlayerPostThink = { return; } - SpyParticles(); - if (((self.jump_flag < -300) && (self.flags & 512)) && (self.health > 0)) { if (self.watertype == -3) { diff --git a/spy.qc b/spy.qc index 4b8ad114..810b0df8 100644 --- a/spy.qc +++ b/spy.qc @@ -675,6 +675,41 @@ void () CF_Spy_DisguiseLast = { } }; +void () Spy_SetClientSkins = { + entity te; + string color, skin; + float team; + team = self.undercover_team == 0 ? self.team_no : self.undercover_team; + color = ftos(TeamFortress_TeamGetColor(t) - 1); + skin = TeamFortress_GetSkin(self); + + te = find(world, classname, "player"); + while (te) { + if ( + (te.team_no == self.team_no) + || (te.team_no == self.undercover_team && self.undercover_skin == PC_SPY) + ) + { + if (visible(te)) { + msg_entity = te; + + // set skin + WriteByte(MSG_ONE, svc_setinfo); + WriteByte(MSG_ONE, self.colormap-1); // ???? 0 based player index + WriteString(MSG_ONE, "skin"); + WriteString(MSG_ONE, skin); + + // set colour / color + WriteByte(MSG_ONE, svc_setinfo); + WriteByte(MSG_ONE, self.colormap-1); // ???? 0 based player index + WriteString(MSG_ONE, "color"); + WriteString(MSG_ONE, color); + } + } + te = find(te, classname, "player"); + } +} + void () CF_Spy_UndercoverThink = { local float f_team_color; local string s_team, s_class; @@ -697,12 +732,10 @@ void () CF_Spy_UndercoverThink = { // make spy invisible if invis_only is turned on if (invis_only) { - self.owner.items = self.owner.items | IT_INVISIBILITY; self.owner.frame = 0; self.owner.modelindex = modelindex_eyes; self.owner.is_undercover = 1; - } else { // don't check for color cheating for next 10 seconds @@ -715,6 +748,7 @@ void () CF_Spy_UndercoverThink = { self.owner.queue_skin = 0; self.owner.is_undercover = 1; TeamFortress_SetSkin(self.owner); + Spy_SetClientSkins(); if (self.owner.queue_team) { CF_Spy_ChangeColor(self.owner, self.owner.queue_team); @@ -742,6 +776,7 @@ void () CF_Spy_UndercoverThink = { self.owner.queue_team = 0; self.owner.is_undercover = 1; TeamFortress_SetSkin(self.owner); + Spy_SetClientSkins(); if (self.owner.queue_skin) { CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin); @@ -1376,36 +1411,4 @@ void () Spy_DropBackpack = { newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; - -void () SpyParticles = { - if (self.playerclass == PC_SPY) - { - entity te, t1; - te = find(world, classname, "player"); - while (te) { - if ( - (te.team_no == self.team_no) - || (te.team_no == self.undercover_team && self.undercover_skin == PC_SPY) - ) - { - if (visible(te)) { - msg_entity = te; - tl = spawn(); - tl.origin = self.origin; - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_LIGHTNING3); - WriteEntity(MSG_ONE, tl); - WriteCoord(MSG_ONE, tl.origin_x); - WriteCoord(MSG_ONE, tl.origin_y); - WriteCoord(MSG_ONE, tl.origin_z + 56); - WriteCoord(MSG_ONE, self.origin_x); - WriteCoord(MSG_ONE, self.origin_y); - WriteCoord(MSG_ONE, self.origin_z + 32); - dremove(tl); - } - } - te = find(te, classname, "player"); - } - } -} \ No newline at end of file +}; \ No newline at end of file From 88fa9226538616869124613d57e8b8606dcca029 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 1 Feb 2019 16:26:36 +1100 Subject: [PATCH 0559/2474] forgot to update variable name change --- spy.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spy.qc b/spy.qc index 810b0df8..fe7534eb 100644 --- a/spy.qc +++ b/spy.qc @@ -680,7 +680,7 @@ void () Spy_SetClientSkins = { string color, skin; float team; team = self.undercover_team == 0 ? self.team_no : self.undercover_team; - color = ftos(TeamFortress_TeamGetColor(t) - 1); + color = ftos(TeamFortress_TeamGetColor(team) - 1); skin = TeamFortress_GetSkin(self); te = find(world, classname, "player"); From d0a860e6bc85a3a1847c55181daa1c96cafb7b9f Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 1 Feb 2019 16:27:29 +1100 Subject: [PATCH 0560/2474] code style --- spy.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spy.qc b/spy.qc index fe7534eb..fce263b6 100644 --- a/spy.qc +++ b/spy.qc @@ -684,13 +684,15 @@ void () Spy_SetClientSkins = { skin = TeamFortress_GetSkin(self); te = find(world, classname, "player"); - while (te) { + while (te) + { if ( (te.team_no == self.team_no) || (te.team_no == self.undercover_team && self.undercover_skin == PC_SPY) ) { - if (visible(te)) { + if (visible(te)) + { msg_entity = te; // set skin From a65836bfcca63c00d81006c73ac088ba964f203c Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 1 Feb 2019 16:33:21 +1100 Subject: [PATCH 0561/2474] logic fix for team colour --- spy.qc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/spy.qc b/spy.qc index fce263b6..92f73eff 100644 --- a/spy.qc +++ b/spy.qc @@ -677,10 +677,11 @@ void () CF_Spy_DisguiseLast = { void () Spy_SetClientSkins = { entity te; - string color, skin; - float team; - team = self.undercover_team == 0 ? self.team_no : self.undercover_team; - color = ftos(TeamFortress_TeamGetColor(team) - 1); + string color, dcolor, skin; + float dteam; + dteam = self.undercover_team == 0 ? self.team_no : self.undercover_team; + color = ftos(TeamFortress_TeamGetColor(self.team_no) - 1); + dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); skin = TeamFortress_GetSkin(self); te = find(world, classname, "player"); @@ -705,7 +706,14 @@ void () Spy_SetClientSkins = { WriteByte(MSG_ONE, svc_setinfo); WriteByte(MSG_ONE, self.colormap-1); // ???? 0 based player index WriteString(MSG_ONE, "color"); - WriteString(MSG_ONE, color); + if (te.team_no == self.team_no) + { + WriteString(MSG_ONE, color); + } + else + { + WriteString(MSG_ONE, dcolor); + } } } te = find(te, classname, "player"); From 342dd35bf71f4697de272001c5aaf7a0e071efc4 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 1 Feb 2019 16:39:49 +1100 Subject: [PATCH 0562/2474] top/bottom color - spike doing all but write this change for me --- spy.qc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spy.qc b/spy.qc index 92f73eff..b3631aae 100644 --- a/spy.qc +++ b/spy.qc @@ -694,6 +694,7 @@ void () Spy_SetClientSkins = { { if (visible(te)) { + color = (te.team_no == self.team_no) ? color : dcolor; msg_entity = te; // set skin @@ -702,18 +703,17 @@ void () Spy_SetClientSkins = { WriteString(MSG_ONE, "skin"); WriteString(MSG_ONE, skin); - // set colour / color + // set top colour / color WriteByte(MSG_ONE, svc_setinfo); - WriteByte(MSG_ONE, self.colormap-1); // ???? 0 based player index - WriteString(MSG_ONE, "color"); - if (te.team_no == self.team_no) - { - WriteString(MSG_ONE, color); - } - else - { - WriteString(MSG_ONE, dcolor); - } + WriteByte(MSG_ONE, self.colormap-1); + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + + // set bottom colour / color + WriteByte(MSG_ONE, svc_setinfo); + WriteByte(MSG_ONE, self.colormap-1); + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); } } te = find(te, classname, "player"); From 627a72f67d40117c8320648f850f713f33f914c2 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 2 Feb 2019 00:09:14 +1100 Subject: [PATCH 0563/2474] fix for spy disguise to show to teammates etc --- client.qc | 8 ++++++ spy.qc | 74 ++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 57 insertions(+), 25 deletions(-) diff --git a/client.qc b/client.qc index b4eeba31..4dc541ef 100644 --- a/client.qc +++ b/client.qc @@ -1932,6 +1932,8 @@ void () CheckPowerups = { } }; +void (entity owner) Spy_SetClientSkins; + void () PlayerPostThink = { local float fdmg; @@ -1969,6 +1971,12 @@ void () PlayerPostThink = { } } self.jump_flag = self.velocity_z; + + if (self.playerclass == PC_SPY) + { + Spy_SetClientSkins(self); + } + CheckPowerups(); W_WeaponFrame(); if (self.motd <= 400) { diff --git a/spy.qc b/spy.qc index b3631aae..68b7bb8a 100644 --- a/spy.qc +++ b/spy.qc @@ -675,47 +675,72 @@ void () CF_Spy_DisguiseLast = { } }; -void () Spy_SetClientSkins = { +string (float team) Spy_GetSkin = { + string skin; + skin = ""; + switch (team) + { + case 1: + skin = "blue_spy"; + break; + case 2: + skin = "red_spy"; + break; + case 3: + skin = "yell_spy"; + break; + case 4: + skin = "gren_spy"; + break; + } + return skin; +} + +void (entity owner) Spy_SetClientSkins = { entity te; - string color, dcolor, skin; + string color, dcolor, skin, dskin, sendcolor, sendskin; float dteam; - dteam = self.undercover_team == 0 ? self.team_no : self.undercover_team; - color = ftos(TeamFortress_TeamGetColor(self.team_no) - 1); + dteam = owner.undercover_team == 0 ? owner.team_no : owner.undercover_team; + color = ftos(TeamFortress_TeamGetColor(owner.team_no) - 1); dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); - skin = TeamFortress_GetSkin(self); + + skin = Spy_GetSkin(owner.team_no); + dskin = Spy_GetSkin(dteam); te = find(world, classname, "player"); while (te) { - if ( - (te.team_no == self.team_no) - || (te.team_no == self.undercover_team && self.undercover_skin == PC_SPY) - ) + if (te.team_no) { - if (visible(te)) + if ( + (te.team_no == owner.team_no) + || (te.team_no == owner.undercover_team && owner.undercover_skin == PC_SPY) + ) { - color = (te.team_no == self.team_no) ? color : dcolor; + sendcolor = (te.team_no == owner.team_no) ? color : dcolor; + sendskin = (te.team_no == owner.team_no) ? skin : dskin; msg_entity = te; // set skin - WriteByte(MSG_ONE, svc_setinfo); - WriteByte(MSG_ONE, self.colormap-1); // ???? 0 based player index + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, owner.colormap-1); // ???? 0 based player index WriteString(MSG_ONE, "skin"); - WriteString(MSG_ONE, skin); + WriteString(MSG_ONE, sendskin); // set top colour / color - WriteByte(MSG_ONE, svc_setinfo); - WriteByte(MSG_ONE, self.colormap-1); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, owner.colormap-1); WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); + WriteString(MSG_ONE, sendcolor); // set bottom colour / color - WriteByte(MSG_ONE, svc_setinfo); - WriteByte(MSG_ONE, self.colormap-1); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, owner.colormap-1); WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); + WriteString(MSG_ONE, sendcolor); } } + te = find(te, classname, "player"); } } @@ -758,8 +783,7 @@ void () CF_Spy_UndercoverThink = { self.owner.queue_skin = 0; self.owner.is_undercover = 1; TeamFortress_SetSkin(self.owner); - Spy_SetClientSkins(); - + if (self.owner.queue_team) { CF_Spy_ChangeColor(self.owner, self.owner.queue_team); } else { @@ -773,7 +797,7 @@ void () CF_Spy_UndercoverThink = { s_class = "Spy"; sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); } - + } else if (self.team) { self.owner.undercover_team = self.team; self.owner.last_team = self.team; @@ -786,7 +810,7 @@ void () CF_Spy_UndercoverThink = { self.owner.queue_team = 0; self.owner.is_undercover = 1; TeamFortress_SetSkin(self.owner); - Spy_SetClientSkins(); + if (self.owner.queue_skin) { CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin); @@ -799,7 +823,7 @@ void () CF_Spy_UndercoverThink = { sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); } } - + TeamFortress_SpyCalcName(self.owner); } From 533af9ae670582b37512a7cf429709e3f75fc7b7 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 2 Feb 2019 15:44:54 +1100 Subject: [PATCH 0564/2474] fix for race condition on skin set --- client.qc | 7 ------- spy.qc | 36 +++++++++++++++++++++++------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/client.qc b/client.qc index 4dc541ef..8030ee86 100644 --- a/client.qc +++ b/client.qc @@ -1932,8 +1932,6 @@ void () CheckPowerups = { } }; -void (entity owner) Spy_SetClientSkins; - void () PlayerPostThink = { local float fdmg; @@ -1971,11 +1969,6 @@ void () PlayerPostThink = { } } self.jump_flag = self.velocity_z; - - if (self.playerclass == PC_SPY) - { - Spy_SetClientSkins(self); - } CheckPowerups(); W_WeaponFrame(); diff --git a/spy.qc b/spy.qc index 68b7bb8a..4cacb85c 100644 --- a/spy.qc +++ b/spy.qc @@ -696,15 +696,16 @@ string (float team) Spy_GetSkin = { return skin; } -void (entity owner) Spy_SetClientSkins = { - entity te; +void () Spy_SetClientSkinsThink = { + entity te, own; string color, dcolor, skin, dskin, sendcolor, sendskin; float dteam; - dteam = owner.undercover_team == 0 ? owner.team_no : owner.undercover_team; - color = ftos(TeamFortress_TeamGetColor(owner.team_no) - 1); + own = self.owner; + dteam = own.undercover_team == 0 ? own.team_no : own.undercover_team; + color = ftos(TeamFortress_TeamGetColor(own.team_no) - 1); dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); - skin = Spy_GetSkin(owner.team_no); + skin = Spy_GetSkin(own.team_no); dskin = Spy_GetSkin(dteam); te = find(world, classname, "player"); @@ -713,29 +714,29 @@ void (entity owner) Spy_SetClientSkins = { if (te.team_no) { if ( - (te.team_no == owner.team_no) - || (te.team_no == owner.undercover_team && owner.undercover_skin == PC_SPY) + (te.team_no == own.team_no) + || (te.team_no == own.undercover_team && own.undercover_skin == PC_SPY) ) { - sendcolor = (te.team_no == owner.team_no) ? color : dcolor; - sendskin = (te.team_no == owner.team_no) ? skin : dskin; + sendcolor = (te.team_no == own.team_no) ? color : dcolor; + sendskin = (te.team_no == own.team_no) ? skin : dskin; msg_entity = te; // set skin WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, owner.colormap-1); // ???? 0 based player index + WriteByte(MSG_ONE, own.colormap-1); // ???? 0 based player index WriteString(MSG_ONE, "skin"); WriteString(MSG_ONE, sendskin); // set top colour / color WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, owner.colormap-1); + WriteByte(MSG_ONE, own.colormap-1); WriteString(MSG_ONE, "topcolor"); WriteString(MSG_ONE, sendcolor); // set bottom colour / color WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, owner.colormap-1); + WriteByte(MSG_ONE, own.colormap-1); WriteString(MSG_ONE, "bottomcolor"); WriteString(MSG_ONE, sendcolor); } @@ -743,6 +744,8 @@ void (entity owner) Spy_SetClientSkins = { te = find(te, classname, "player"); } + + dremove(self); } void () CF_Spy_UndercoverThink = { @@ -831,8 +834,15 @@ void () CF_Spy_UndercoverThink = { Status_Refresh(self.owner); if (self.owner.menu_input == Menu_Spy_Input) Menu_Spy(self.owner); - dremove(self); + entity e_timer; + e_timer = spawn(); + e_timer.classname = "spytimerskins"; + e_timer.owner = self.owner; + e_timer.think = Spy_SetClientSkinsThink; + e_timer.nextthink = time + 1; + + dremove(self); }; void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { From bca8c62f4d5100c2074e1b8369eff202f7916971 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 2 Feb 2019 23:06:57 +1100 Subject: [PATCH 0565/2474] rework spy disguise so teammates always see spy, refactor skin code --- spy.qc | 118 ++++++------------ tfort.qc | 349 +++++++++++++---------------------------------------- tforttm.qc | 45 +++---- 3 files changed, 134 insertions(+), 378 deletions(-) diff --git a/spy.qc b/spy.qc index 4cacb85c..86561de3 100644 --- a/spy.qc +++ b/spy.qc @@ -675,81 +675,62 @@ void () CF_Spy_DisguiseLast = { } }; -string (float team) Spy_GetSkin = { - string skin; - skin = ""; - switch (team) - { - case 1: - skin = "blue_spy"; - break; - case 2: - skin = "red_spy"; - break; - case 3: - skin = "yell_spy"; - break; - case 4: - skin = "gren_spy"; - break; - } - return skin; -} - -void () Spy_SetClientSkinsThink = { - entity te, own; +void (entity own) Spy_SetClientSkins = { + entity te; string color, dcolor, skin, dskin, sendcolor, sendskin; - float dteam; - own = self.owner; + float dteam, dpc; + dteam = own.undercover_team == 0 ? own.team_no : own.undercover_team; + dpc = own.undercover_skin == 0 ? own.playerclass : own.undercover_skin; color = ftos(TeamFortress_TeamGetColor(own.team_no) - 1); dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); - skin = Spy_GetSkin(own.team_no); - dskin = Spy_GetSkin(dteam); + skin = TeamFortress_GetSkin(own.team_no, own.playerclass); + dskin = TeamFortress_GetSkin(dteam, dpc); te = find(world, classname, "player"); while (te) { if (te.team_no) { - if ( - (te.team_no == own.team_no) - || (te.team_no == own.undercover_team && own.undercover_skin == PC_SPY) - ) + if (te.team_no == own.team_no) { - sendcolor = (te.team_no == own.team_no) ? color : dcolor; - sendskin = (te.team_no == own.team_no) ? skin : dskin; - msg_entity = te; - - // set skin - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, own.colormap-1); // ???? 0 based player index - WriteString(MSG_ONE, "skin"); - WriteString(MSG_ONE, sendskin); - - // set top colour / color - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, own.colormap-1); - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, sendcolor); - - // set bottom colour / color - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, own.colormap-1); - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, sendcolor); + // on same team, send them spy/team (initial spawn etc) + sendcolor = color; + sendskin = skin; } + else // not on same team, send them disguise + { + sendcolor = dcolor; + sendskin = dskin; + } + + msg_entity = te; + + // set skin + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, own.colormap-1); // ???? 0 based player index + WriteString(MSG_ONE, "skin"); + WriteString(MSG_ONE, sendskin); + + // set top colour / color + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, own.colormap-1); + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, sendcolor); + + // set bottom colour / color + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, own.colormap-1); + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, sendcolor); } te = find(te, classname, "player"); } - - dremove(self); } void () CF_Spy_UndercoverThink = { - local float f_team_color; local string s_team, s_class; // keep track of seconds left to @@ -804,16 +785,9 @@ void () CF_Spy_UndercoverThink = { } else if (self.team) { self.owner.undercover_team = self.team; self.owner.last_team = self.team; - - // tell client to change color - f_team_color = TeamFortress_TeamGetColor(self.team) - 1; - stuffcmd(self.owner, "color "); - stuffcmd(self.owner, ftos(f_team_color)); - stuffcmd(self.owner, "\n"); self.owner.queue_team = 0; self.owner.is_undercover = 1; TeamFortress_SetSkin(self.owner); - if (self.owner.queue_skin) { CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin); @@ -834,14 +808,7 @@ void () CF_Spy_UndercoverThink = { Status_Refresh(self.owner); if (self.owner.menu_input == Menu_Spy_Input) Menu_Spy(self.owner); - - entity e_timer; - e_timer = spawn(); - e_timer.classname = "spytimerskins"; - e_timer.owner = self.owner; - e_timer.think = Spy_SetClientSkinsThink; - e_timer.nextthink = time + 1; - + dremove(self); }; @@ -893,7 +860,6 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { e_timer.nextthink = time + 1; e_timer.skin = pf_class; pe_player.undercover_timer = 4; - TeamFortress_SetSkin(pe_player); Status_Refresh(pe_player); }; @@ -921,9 +887,6 @@ void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { pe_player.undercover_team = 0; pe_player.disguise_team = 0; pe_player.queue_team = 0; - stuffcmd(pe_player, "color "); - stuffcmd(pe_player, ftos(f_team_color)); - stuffcmd(pe_player, "\n"); if (!pe_player.undercover_skin) pe_player.is_undercover = 0; TeamFortress_SetSkin(pe_player); @@ -1384,8 +1347,6 @@ void () TranquiliserTimer = { }; void (entity spy) Spy_RemoveDisguise = { - local string st; - local float tc; local float coverblown = 0; if (invis_only != 1) { @@ -1394,11 +1355,6 @@ void (entity spy) Spy_RemoveDisguise = { spy.immune_to_check = time + 10; spy.undercover_team = 0; spy.disguise_team = 0; - stuffcmd(spy, "color "); - tc = TeamFortress_TeamGetColor(spy.team_no) - 1; - st = ftos(tc); - stuffcmd(spy, st); - stuffcmd(spy, "\n"); coverblown = 1; } if (spy.undercover_skin != 0) { diff --git a/tfort.qc b/tfort.qc index 75f218eb..531ba01d 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1236,266 +1236,69 @@ void () TeamFortress_SetHealth = { self.health = self.max_health; }; -string(entity p) TeamFortress_GetSkin = +string (float tn) TeamFortress_GetColorSkin = { + string s; + s = ""; + switch (tn) + { + case 1: + s = "blue"; + break; + case 2: + s = "red"; + break; + case 3: + s = "yell"; + break; + case 4: + s = "gren"; + break; + } + + return s; +} + +string(float tn, float pc) TeamFortress_GetSkin = { - local float tn; - local float pc; - local string st; local string skin = "base"; - tn = p.team_no; - pc = p.playerclass; - if (p.playerclass == 8) { - if (p.undercover_team != 0) { - tn = p.undercover_team; - } - if (p.undercover_skin != 0) { - pc = p.undercover_skin; - } - } - if (tn == 4) { - if (pc == 1) { - st = infokey(world, "sk_t4_scout"); - if (st != string_null) { - skin = st; - } - skin = "gren_sco"; - } else if (pc == 2) { - st = infokey(world, "sk_t4_sniper"); - if (st != string_null) { - skin = st; - } - skin = "gren_sni"; - } else if (pc == 3) { - st = infokey(world, "sk_t4_soldier"); - if (st != string_null) { - skin = st; - } - skin = "gren_sol"; - } else if (pc == 4) { - st = infokey(world, "sk_t4_demoman"); - if (st != string_null) { - skin = st; - } - skin = "gren_dem"; - } else if (pc == 5) { - st = infokey(world, "sk_t4_medic"); - if (st != string_null) { - skin = st; - } - skin = "gren_med"; - } else if (pc == 6) { - st = infokey(world, "sk_t4_hwguy"); - if (st != string_null) { - skin = st; - } - skin = "gren_hwg"; - } else if (pc == 7) { - st = infokey(world, "sk_t4_pyro"); - if (st != string_null) { - skin = st; - } - skin = "gren_pyr"; - } else if (pc == 8) { - st = infokey(world, "sk_t4_spy"); - if (st != string_null) { - skin = st; - } - skin = "gren_spy"; - } else if (pc == 9) { - st = infokey(world, - "sk_t4_engineer"); - if (st != string_null) { - skin = st; - } - skin = "gren_eng"; - } else if (pc == 11) { - skin = "gren_civ"; - } - } else if (tn == 3) { - if (pc == 1) { - st = infokey(world, "sk_t3_scout"); - if (st != string_null) { - skin = st; - } - skin = "yell_sco"; - } else if (pc == 2) { - st = infokey(world, "sk_t3_sniper"); - if (st != string_null) { - skin = st; - } - skin = "yell_sni"; - } else if (pc == 3) { - st = infokey(world, "sk_t3_soldier"); - if (st != string_null) { - skin = st; - } - skin = "yell_sol"; - } else if (pc == 4) { - st = infokey(world, "sk_t3_demoman"); - if (st != string_null) { - skin = st; - } - skin = "yell_dem"; - } else if (pc == 5) { - st = infokey(world, "sk_t3_medic"); - if (st != string_null) { - skin = st; - } - skin = "yell_med"; - } else if (pc == 6) { - st = infokey(world, "sk_t3_hwguy"); - if (st != string_null) { - skin = st; - } - skin = "yell_hwg"; - } else if (pc == 7) { - st = infokey(world, "sk_t3_pyro"); - if (st != string_null) { - skin = st; - } - skin = "yell_pyr"; - } else if (pc == 8) { - st = infokey(world, - "sk_t3_spy"); - if (st != string_null) { - skin = st; - } - skin = "yell_spy"; - } else if (pc == 9) { - st = infokey(world, - "sk_t3_engineer"); - if (st != string_null) { - skin = st; - } - skin = "yell_eng"; - } else if (pc == 11) { - skin = "yell_civ"; - } - } else if (tn == 2) { - if (pc == 1) { - st = infokey(world, "sk_t2_scout"); - if (st != string_null) { - skin = st; - } - skin = "red_sco"; - } else if (pc == 2) { - st = infokey(world, "sk_t2_sniper"); - if (st != string_null) { - skin = st; - } - skin = "red_sni"; - } else if (pc == 3) { - st = infokey(world, "sk_t2_soldier"); - if (st != string_null) { - skin = st; - } - skin = "red_sol"; - } else if (pc == 4) { - st = infokey(world, "sk_t2_demoman"); - if (st != string_null) { - skin = st; - } - skin = "red_dem"; - } else if (pc == 5) { - st = infokey(world, "sk_t2_medic"); - if (st != string_null) { - skin = st; - } - skin = "red_med"; - } else if (pc == 6) { - st = infokey(world, "sk_t2_hwguy"); - if (st != string_null) { - skin = st; - } - skin = "red_hwg"; - } else if (pc == 7) { - st = infokey(world, - "sk_t2_pyro"); - if (st != string_null) { - skin = st; - } - skin = "red_pyr"; - } else if (pc == 8) { - st = infokey(world, - "sk_t2_spy"); - if (st != string_null) { - skin = st; - } - skin = "red_spy"; - } else if (pc == 9) { - st = infokey(world, - "sk_t2_engineer"); - if (st != string_null) { - skin = st; - } - skin = "red_eng"; - } else if (pc == 11) { - skin = "red_civ"; - } - } else if (tn == 1) { - if (pc == 1) { - st = infokey(world, "sk_t1_scout"); - if (st != string_null) { - skin = st; - } - skin = "blue_sco"; - } else if (pc == 2) { - st = infokey(world, "sk_t1_sniper"); - if (st != string_null) { - skin = st; - } - skin = "blue_sni"; - } else if (pc == 3) { - st = infokey(world, "sk_t1_soldier"); - if (st != string_null) { - skin = st; - } - skin = "blue_sol"; - } else if (pc == 4) { - st = infokey(world, "sk_t1_demoman"); - if (st != string_null) { - skin = st; - } - skin = "blue_dem"; - } else if (pc == 5) { - st = infokey(world, "sk_t1_medic"); - if (st != string_null) { - skin = st; - } - skin = "blue_med"; - } else if (pc == 6) { - st = infokey(world, "sk_t1_hwguy"); - if (st != string_null) { - skin = st; - } - skin = "blue_hwg"; - } else if (pc == 7) { - st = infokey(world, - "sk_t1_pyro"); - if (st != string_null) { - skin = st; - } - skin = "blue_pyr"; - } else if (pc == 8) { - st = infokey(world, - "sk_t1_spy"); - if (st != string_null) { - skin = st; - } - skin = "blue_spy"; - } else if (pc == 9) { - st = infokey(world, - "sk_t1_engineer"); - if (st != string_null) { - skin = st; - } - skin = "blue_eng"; - } else if (pc == 11) { - skin = "blue_civ"; - } - } + string col; + col = TeamFortress_GetColorSkin(tn); + + switch (pc) + { + case 1: + skin = strcat(col, "_sco"); + break; + case 2: + skin = strcat(col, "_sni"); + break; + case 3: + skin = strcat(col, "_sol"); + break; + case 4: + skin = strcat(col, "_dem"); + break; + case 5: + skin = strcat(col, "_med"); + break; + case 6: + skin = strcat(col, "_hwg"); + break; + case 7: + skin = strcat(col, "_pyr"); + break; + case 8: + skin = strcat(col, "_spy"); + break; + case 9: + skin = strcat(col, "_eng"); + break; + case 11: + skin = strcat(col, "_civ"); + break; + } return skin; }; @@ -1503,18 +1306,32 @@ void (entity p) TeamFortress_SetSkin = { local string st; p.immune_to_check = time + 10; - if ((p.playerclass == PC_SPY) && (p.undercover_skin != 0)) - p.skin = p.undercover_skin; + if (p.playerclass == PC_SPY) + { + if (!p.is_undercover) + { + stuffcmd(p, "skin "); + st = TeamFortress_GetSkin(p.team_no, p.playerclass); + stuffcmd(p, st); + stuffcmd(p, "\n"); + } + Spy_SetClientSkins(p); + } else + { p.skin = p.playerclass; - - if (p.skin != 0) { - stuffcmd(p, "skin "); - st = TeamFortress_GetSkin(p); - stuffcmd(p, st); - stuffcmd(p, "\n"); - } else - stuffcmd(p, "skin base\n"); + + if (p.skin != 0) { + stuffcmd(p, "skin "); + st = TeamFortress_GetSkin(p.team_no, p.playerclass); + stuffcmd(p, st); + stuffcmd(p, "\n"); + } + else + { + stuffcmd(p, "skin base\n"); + } + } }; void () TeamFortress_SetEquipment = { diff --git a/tforttm.qc b/tforttm.qc index 12d77965..d962e259 100644 --- a/tforttm.qc +++ b/tforttm.qc @@ -9,7 +9,7 @@ float (float tno) TeamFortress_TeamGetLives; float (float tno) TeamFortress_TeamGetMaxPlayers; string(float tno) TeamFortress_TeamGetColorString; float (float tno) TeamFortress_TeamGetIllegalClasses; -string(entity p) TeamFortress_GetSkin; +string(float tn, float pc) TeamFortress_GetSkin; float () TeamFortress_TeamPutPlayerInTeam = { @@ -273,40 +273,23 @@ void () TeamFortress_CheckTeamCheats = { if ((self.team_no > 0) && (teamplay > 0)) { st = infokey(self, "bottomcolor"); tc = stof(st); - if ((self.playerclass == 8) && (self.undercover_team != 0)) { - if ((TeamFortress_TeamGetColor(self.undercover_team) - 1) != - tc) { - stuffcmd(self, "color "); - tc = TeamFortress_TeamGetColor(self.undercover_team) - 1; - st = ftos(tc); - stuffcmd(self, st); - stuffcmd(self, "\n"); - bprint2(PRINT_MEDIUM, self.netname, - " has been kicked for changing color\n"); - sprint(self, PRINT_HIGH, - "You have been kicked for changing your pants color\n"); - KickCheater(self); - return; - } - } else { - if (tc != (TeamFortress_TeamGetColor(self.team_no) - 1)) { - stuffcmd(self, "color "); - tc = TeamFortress_TeamGetColor(self.team_no) - 1; - st = ftos(tc); - stuffcmd(self, st); - stuffcmd(self, "\n"); - bprint2(PRINT_MEDIUM, self.netname, - " has been kicked for changing color\n"); - sprint(self, PRINT_HIGH, - "You have been kicked for changing your pants color\n"); - KickCheater(self); - return; - } + if (tc != (TeamFortress_TeamGetColor(self.team_no) - 1)) { + stuffcmd(self, "color "); + tc = TeamFortress_TeamGetColor(self.team_no) - 1; + st = ftos(tc); + stuffcmd(self, st); + stuffcmd(self, "\n"); + bprint2(PRINT_MEDIUM, self.netname, + " has been kicked for changing color\n"); + sprint(self, PRINT_HIGH, + "You have been kicked for changing your pants color\n"); + KickCheater(self); + return; } if (self.playerclass != 0) { st = infokey(self, "skin"); tc = 0; - sk = TeamFortress_GetSkin(self); + sk = TeamFortress_GetSkin(self.team_no, self.playerclass); if (st != sk) { TeamFortress_SetSkin(self); bprint2(PRINT_MEDIUM, self.netname, From 7c04f28d955182f252b108ddb4949b6d2848e56e Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 3 Feb 2019 23:24:30 +1100 Subject: [PATCH 0566/2474] fix for change of class not resetting colour of skin --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index 531ba01d..29d6e0d0 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1306,7 +1306,7 @@ void (entity p) TeamFortress_SetSkin = { local string st; p.immune_to_check = time + 10; - if (p.playerclass == PC_SPY) + if (p.playerclass == PC_SPY || p.last_playerclass == PC_SPY) { if (!p.is_undercover) { From 6518c07bd7c2fa56414b7519d92c9d05ab9ab6de Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Mon, 4 Feb 2019 21:35:09 +0000 Subject: [PATCH 0567/2474] partial --- actions.qc | 94 +++++++++++++----- client.qc | 17 +++- tfort.qc | 2 +- weapons.qc | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 358 insertions(+), 42 deletions(-) diff --git a/actions.qc b/actions.qc index e600777f..b56361d4 100644 --- a/actions.qc +++ b/actions.qc @@ -576,20 +576,41 @@ void () TeamFortress_ReloadCurrentWeapon = { void (float slot) TeamFortress_ReloadSlot = { local float weap = 0; - if (slot < 1 || slot > 3) - return; + if (!IsUsingOldImpulses()) { + if (slot < 1 || slot > 3) + return; - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + if (slot == 1) + weap = W_WeaponSlot1(); + else if (slot == 2) + weap = W_WeaponSlot2(); + else if (slot == 3) { + if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + return; + weap = W_WeaponSlot3(); + } + TeamFortress_ReloadWeapon(weap); + } + else { + if (slot < 1 || slot > 7) return; - weap = W_WeaponSlot3(); + if (slot == 1) + weap = W_OldWeaponSlot1(); + else if (slot == 2) + weap = W_OldWeaponSlot2(); + else if (slot == 3) + weap = W_OldWeaponSlot3(); + else if (slot == 4) + weap = W_OldWeaponSlot4(); + else if (slot == 5) + weap = W_OldWeaponSlot5(); + else if (slot == 6) + weap = W_OldWeaponSlot6(); + else if (slot == 7) + weap = W_OldWeaponSlot7(); + if (weap != 0) + TeamFortress_ReloadWeapon(weap); } - - TeamFortress_ReloadWeapon(weap); }; void () TeamFortress_ReloadNext = { @@ -603,23 +624,44 @@ void () TeamFortress_ReloadNext = { return; } - // then go through each slot - for (slot = 1; slot < 4; slot++) { - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + if (!IsUsingOldImpulses()) { + // then go through each slot + for (slot = 1; slot < 4; slot++) { + if (slot == 1) + weap = W_WeaponSlot1(); + else if (slot == 2) + weap = W_WeaponSlot2(); + else if (slot == 3) { + if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + break; + weap = W_WeaponSlot3(); + } + + if (CheckForAmmo(weap)) { + self.current_weapon = weap; + TeamFortress_ReloadWeapon(weap); + reload = 1; break; - weap = W_WeaponSlot3(); + } } - - if (CheckForAmmo(weap)) { - self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap); - reload = 1; - break; + } + else { + // then go through each slot + for (slot = 1; slot < 4; slot++) { + if (slot == 1) + weap = W_OldWeaponSlot1(); + else if (slot == 2) + weap = W_OldWeaponSlot2(); + else if (slot == 3) + weap = W_OldWeaponSlot3(); + else if (slot == 4) + weap = W_OldWeaponSlot4(); + else if (slot == 5) + weap = W_OldWeaponSlot5(); + else if (slot == 6) + weap = W_OldWeaponSlot6(); + else if (slot == 7) + weap = W_OldWeaponSlot7(); } } diff --git a/client.qc b/client.qc index 6ac0fa27..84d2f1df 100644 --- a/client.qc +++ b/client.qc @@ -54,6 +54,7 @@ void () StartTimer; void () StopTimer; void (string cl_pwd) Admin_Check; void () Admin_Aliases; +float () GetLastWeaponImpulse; string nextmap; @@ -1253,8 +1254,9 @@ void () PutClientInServer = { W_SetCurrentAmmo(self); if (self.current_weaponslot && self.last_playerclass == self.playerclass) W_ChangeWeapon(self.current_weaponslot); - else - W_ChangeWeapon(1); + else { + W_ChangeWeapon(W_BestWeaponSlot()); + } self.last_playerclass = self.playerclass; self.attack_finished = time + 0.3; @@ -2702,3 +2704,14 @@ void (entity targ, entity attacker) ClientObituary = { } }; + +float () IsUsingOldImpulses = { + return (infokey(self, "old_impulses") == "1"); +} + +float () GetLastWeaponImpulse = { + if (IsUsingOldImpulses()) + return 7; + else + return 4; +} diff --git a/tfort.qc b/tfort.qc index 75f218eb..3824224f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -293,7 +293,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(1); + W_ChangeWeapon(W_BestWeaponSlot()); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; diff --git a/weapons.qc b/weapons.qc index 2ecf1437..e7f7b93f 100644 --- a/weapons.qc +++ b/weapons.qc @@ -95,6 +95,7 @@ void () BioInfection_MonsterDecay; void (entity pl, float swap) W_WeaponState_Load; float (float weap) W_GetSlot; +float (float weap) W_OldGetSlot; float () W_BestWeaponSlot; void () W_FireFlame; void () W_FireIncendiaryCannon; @@ -107,6 +108,9 @@ void () TranquiliserTimer; void () TeamFortress_CTF_FlagInfo; void () ClanMode; +float () GetLastWeaponImpulse; +float () IsUsingOldImpulses; + void () W_Precache = { precache_sound("weapons/r_exp3.wav"); precache_sound("weapons/rocket1i.wav"); @@ -1612,6 +1616,12 @@ float () W_BestWeapon = { return WEAP_LIGHTNING; else if ((self.ammo_cells >= 7 && self.ammo_shells >= 1) && it & WEAP_ASSAULT_CANNON) return WEAP_ASSAULT_CANNON; + else if (self.ammo_rockets >= 1 && it & WEAP_GRENADE_LAUNCHER) + return WEAP_GRENADE_LAUNCHER; + else if (self.ammo_rockets >= 1 && it & WEAP_ROCKET_LAUNCHER) + return WEAP_ROCKET_LAUNCHER; + else if (self.ammo_rockets >= 3 && it & WEAP_INCENDIARY) + return WEAP_INCENDIARY; else if (self.ammo_cells >= 1 && it & WEAP_FLAMETHROWER) return WEAP_FLAMETHROWER; else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) @@ -1641,13 +1651,19 @@ float () W_BestWeaponSlot = { weap = W_BestWeapon(); - return W_GetSlot(weap); + if (!IsUsingOldImpulses()) + return W_GetSlot(weap); + else + return W_OldGetSlot(weap); }; void () W_ChangeToBestWeapon = { - local float slot = W_BestWeaponSlot(); - - W_WeaponSlot(slot); + local float slot = W_BestWeaponSlot(); + + if (!IsUsingOldImpulses()) + W_WeaponSlot(slot); + else + W_OldWeaponSlot(slot); //self.last_weaponslot = self.current_weaponslot; //self.last_weapon = self.current_weapon; @@ -2021,6 +2037,34 @@ float (float weap) W_GetSlot = { return 0; }; +float (float weap) W_OldGetSlot = { + if (weap == WEAP_AXE + || weap == WEAP_MEDIKIT + || weap == WEAP_SPANNER) + return 1; + else if (weap == WEAP_SHOTGUN + || weap == WEAP_SNIPER_RIFLE + || weap == WEAP_TRANQ + || weap == WEAP_LASER) + return 2; + else if (weap == WEAP_SUPER_SHOTGUN + || weap == WEAP_AUTO_RIFLE) + return 3; + else if (weap == WEAP_NAILGUN) + return 4; + else if (weap == WEAP_SUPER_NAILGUN + || weap == WEAP_FLAMETHROWER) + return 5; + else if (weap == WEAP_GRENADE_LAUNCHER + || weap == WEAP_FLAMETHROWER) + return 6; + else if (weap == WEAP_ROCKET_LAUNCHER + || weap == WEAP_ASSAULT_CANNON + || weap == WEAP_INCENDIARY) + return 7; + return 0; +}; + float (float inp) W_AmmoSlot = { self.noammo = 0; @@ -2086,6 +2130,186 @@ float (float inp) W_AmmoSlot = { return 1; }; +float (float inp) W_OldAmmoSlot = { + self.noammo = 0; + if (inp == 1) { + return 1; + } + else if (inp == 2) { + if ((self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_PYRO + || self.playerclass == PC_SPY) + && self.ammo_shells < 1) + self.noammo = 1; + else if (self.playerclass == PC_ENGINEER && self.ammo_nails < 1) + self.noammo = 1; + + } + else if (inp == 3) { + if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) + self.noammo = 1; + else if ((self.playerclass == PC_SOLDIER + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_SPY + || self.playerclass == PC_ENGINEER) + && self.ammo_shells < 2) + self.noammo = 1; + } + else if (inp == 4) { + if ((self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SPY) + && self.ammo_nails < 2) + self.noammo = 1; + } + else if (inp == 5) { + if (self.playerclass == PC_MEDIC && self.ammo_nails < 4) + self.noammo = 1; + else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) + self.noammo = 1; + } + else if (inp == 6) { + if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) + self.noammo = 1; + else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) + self.noammo = 1; + + } + else if (inp == 7) { + if (self.playerclass == PC_SOLDIER && self.ammo_rockets < 1) + self.noammo = 1; + else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) + self.noammo = 1; + else if (self.playerclass == PC_HVYWEAP) { + if (self.ammo_shells < 1) + self.noammo = 1; + else if (self.ammo_cells < 7) + self.noammo = 2; + } + else if (self.playerclass == PC_PYRO && self.ammo_rockets < 3) + self.noammo = 1; + + } + if (self.noammo > 0) + return 0; + else + return 1; +}; + +float () W_OldWeaponSlot1 = { + if (self.weapons_carried & WEAP_MEDIKIT) + return WEAP_MEDIKIT; + else if (self.weapons_carried & WEAP_SPANNER) + return WEAP_SPANNER; + else + return WEAP_AXE; +}; + +float () W_OldWeaponSlot2 = { + if (self.playerclass == PC_SCOUT + ||self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_PYRO) + return WEAP_SHOTGUN; + else if (self.playerclass == PC_SNIPER) + return WEAP_SNIPER_RIFLE; + else if (self.playerclass == PC_SPY) + return WEAP_TRANQ; + else if (self.playerclass == PC_ENGINEER) + return WEAP_LASER; + return 0; +}; + +float () W_OldWeaponSlot3 = { + if (self.playerclass == PC_SOLDIER + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_SPY + || self.playerclass == PC_ENGINEER) + return WEAP_SUPER_SHOTGUN; + else if (self.playerclass == PC_SNIPER) + return WEAP_AUTO_RIFLE; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_PYRO) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot4 = { + if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SPY) + return WEAP_NAILGUN; + else if (self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_PYRO + || self.playerclass == PC_ENGINEER) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot5 = { + if (self.playerclass == PC_MEDIC) + return WEAP_SUPER_NAILGUN; + else if (self.playerclass == PC_PYRO) + return WEAP_FLAMETHROWER; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_ENGINEER + || self.playerclass == PC_SPY) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot6 = { + if (self.playerclass == PC_DEMOMAN) { + self.weaponmode = 0; + return WEAP_GRENADE_LAUNCHER; + } + else if (self.playerclass == PC_PYRO) + return WEAP_FLAMETHROWER; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SOLDIER + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_ENGINEER + || self.playerclass == PC_SPY) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot7 = { + if (self.playerclass == PC_SOLDIER) + return WEAP_ROCKET_LAUNCHER; + else if (self.playerclass == PC_HVYWEAP) + return WEAP_ASSAULT_CANNON; + else if (self.playerclass == PC_PYRO) + return WEAP_INCENDIARY; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_ENGINEER + || self.playerclass == PC_SPY) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + float () W_WeaponSlot1 = { if (self.playerclass == PC_SCOUT) return WEAP_NAILGUN; @@ -2169,6 +2393,30 @@ void (float slot) W_WeaponSlot = { self.next_weapon = W_WeaponSlot4(); }; +void (float inp) W_OldWeaponSlot = { + if (inp == 1) { + self.next_weapon = W_OldWeaponSlot1(); + } + else if (inp == 2) { + self.next_weapon = W_OldWeaponSlot2(); + } + else if (inp == 3) { + self.next_weapon = W_OldWeaponSlot3(); + } + else if (inp == 4) { + self.next_weapon = W_OldWeaponSlot4(); + } + else if (inp == 5) { + self.next_weapon = W_OldWeaponSlot5(); + } + else if (inp == 6) { + self.next_weapon = W_OldWeaponSlot6(); + } + else if (inp == 7) { + self.next_weapon = W_OldWeaponSlot7(); + } +} + void () W_AmmoError = { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -2222,7 +2470,8 @@ float (entity pl) W_WeaponState_Check = { } void (float inp) W_ChangeWeapon = { - if (inp < 1 || inp > 4) + + if (inp < 1 || inp > GetLastWeaponImpulse()) return; if (self.playerclass == 0) @@ -2236,14 +2485,26 @@ void (float inp) W_ChangeWeapon = { if (!WeaponReady(self)) return; - // check for ammo - if (! W_AmmoSlot(inp)) { - W_AmmoError(); - self.queue_weaponslot = 0; - return; + if (IsUsingOldImpulses()) { + // check for ammo + if (! W_OldAmmoSlot(inp)) { + W_AmmoError(); + self.queue_weaponslot = 0; + return; + } + W_OldWeaponSlot(inp); } + else { + // check for ammo + if (! W_AmmoSlot(inp)) { + W_AmmoError(); + self.queue_weaponslot = 0; + return; + } - W_WeaponSlot(inp); + W_WeaponSlot(inp); + } + // don't update current/last weapon information if next weapon is the same as current if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { @@ -2681,8 +2942,8 @@ void () W_WeaponFrame = { } - // slot 1-4 binds - if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady(self) + // slot 1-4 (or 1-7) binds + if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && WeaponReady(self) && !self.is_building && !self.is_detpacking) { // load weapon state if current state doesn't match stored state From c1ff94f8ebee08b2a58cc827c4fb4a025241fe42 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Thu, 7 Feb 2019 01:52:46 +0000 Subject: [PATCH 0568/2474] added W_Old* functions and other helpers --- actions.qc | 33 ++++-- tfort.qc | 6 +- weapons.qc | 315 ++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 279 insertions(+), 75 deletions(-) diff --git a/actions.qc b/actions.qc index b56361d4..218e7b17 100644 --- a/actions.qc +++ b/actions.qc @@ -609,22 +609,22 @@ void (float slot) TeamFortress_ReloadSlot = { else if (slot == 7) weap = W_OldWeaponSlot7(); if (weap != 0) - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap); } }; void () TeamFortress_ReloadNext = { local float slot, reload = 0, weap = 0; - // reload current slot first - slot = W_GetSlot(self.current_weapon); - if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon); - reload = 1; - return; - } - if (!IsUsingOldImpulses()) { + // reload current slot first + slot = W_GetSlot(self.current_weapon); + if (CheckForAmmo(self.current_weapon)) { + TeamFortress_ReloadWeapon(self.current_weapon); + reload = 1; + return; + } + // then go through each slot for (slot = 1; slot < 4; slot++) { if (slot == 1) @@ -646,8 +646,14 @@ void () TeamFortress_ReloadNext = { } } else { + slot = W_OldGetSlot(self.current_weapon); + if (CheckForAmmo(self.current_weapon)) { + TeamFortress_ReloadWeapon(self.current_weapon); + reload = 1; + return; + } // then go through each slot - for (slot = 1; slot < 4; slot++) { + for (slot = 1; slot < GetLastWeaponImpulse(); slot++) { if (slot == 1) weap = W_OldWeaponSlot1(); else if (slot == 2) @@ -662,6 +668,13 @@ void () TeamFortress_ReloadNext = { weap = W_OldWeaponSlot6(); else if (slot == 7) weap = W_OldWeaponSlot7(); + + if (CheckForAmmo(weap)) { + self.current_weapon = weap; + TeamFortress_ReloadWeapon(weap); + reload = 1; + break; + } } } diff --git a/tfort.qc b/tfort.qc index 3824224f..3c666121 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1534,7 +1534,7 @@ void () TeamFortress_SetEquipment = { self.last_weapon = 0; self.weaponmode = 0; self.last_weaponmode = 0; - self.current_weaponslot = 1; + self.current_weaponslot = W_BestWeaponSlot(); self.last_weaponslot = 2; W_WeaponState_Save(self); } @@ -1647,7 +1647,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_SCOUT_MAXARMOR; - if (self.last_playerclass != self.playerclass) + if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_NAILGUN; self.items_allowed = PC_SCOUT_WEAPONS; @@ -2257,6 +2257,8 @@ void () TeamFortress_SetEquipment = { self.items = self.items | IT_ARMOR1; W_SetCurrentAmmo(self); + if (self.last_playerclass != self.playerclass) + self.current_weaponslot = W_BestWeaponSlot(); }; float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { diff --git a/weapons.qc b/weapons.qc index e7f7b93f..0fbb9e6a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -111,6 +111,8 @@ void () ClanMode; float () GetLastWeaponImpulse; float () IsUsingOldImpulses; +void (float inp) W_OldWeaponSlot; + void () W_Precache = { precache_sound("weapons/r_exp3.wav"); precache_sound("weapons/rocket1i.wav"); @@ -1626,16 +1628,18 @@ float () W_BestWeapon = { return WEAP_FLAMETHROWER; else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) return WEAP_SUPER_NAILGUN; - else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) - return WEAP_SUPER_SHOTGUN; else if (self.ammo_nails >= 1 && it & WEAP_LASER) return WEAP_LASER; + else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) + return WEAP_SUPER_SHOTGUN; + else if (self.ammo_shells >= 1 && it & WEAP_SNIPER_RIFLE) + return WEAP_SNIPER_RIFLE; + else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) + return WEAP_TRANQ; else if (self.ammo_nails >= 1 && it & WEAP_NAILGUN) return WEAP_NAILGUN; else if (self.ammo_shells >= 1 && it & WEAP_SHOTGUN) return WEAP_SHOTGUN; - else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) - return WEAP_TRANQ; else if (it & WEAP_MEDIKIT) return WEAP_MEDIKIT; else if (it & WEAP_SPANNER) @@ -2055,13 +2059,18 @@ float (float weap) W_OldGetSlot = { else if (weap == WEAP_SUPER_NAILGUN || weap == WEAP_FLAMETHROWER) return 5; - else if (weap == WEAP_GRENADE_LAUNCHER - || weap == WEAP_FLAMETHROWER) + else if (weap == WEAP_FLAMETHROWER) return 6; else if (weap == WEAP_ROCKET_LAUNCHER || weap == WEAP_ASSAULT_CANNON || weap == WEAP_INCENDIARY) return 7; + else if (weap == WEAP_GRENADE_LAUNCHER) { + if (self.weaponmode == 0) + return 6; + else + return 7; + } return 0; }; @@ -2237,10 +2246,6 @@ float () W_OldWeaponSlot3 = { return WEAP_SUPER_SHOTGUN; else if (self.playerclass == PC_SNIPER) return WEAP_AUTO_RIFLE; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_PYRO) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; @@ -2249,13 +2254,6 @@ float () W_OldWeaponSlot4 = { || self.playerclass == PC_SNIPER || self.playerclass == PC_SPY) return WEAP_NAILGUN; - else if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO - || self.playerclass == PC_ENGINEER) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; @@ -2264,49 +2262,28 @@ float () W_OldWeaponSlot5 = { return WEAP_SUPER_NAILGUN; else if (self.playerclass == PC_PYRO) return WEAP_FLAMETHROWER; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_ENGINEER - || self.playerclass == PC_SPY) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; float () W_OldWeaponSlot6 = { if (self.playerclass == PC_DEMOMAN) { - self.weaponmode = 0; + self.next_weaponmode = 0; return WEAP_GRENADE_LAUNCHER; } else if (self.playerclass == PC_PYRO) return WEAP_FLAMETHROWER; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_ENGINEER - || self.playerclass == PC_SPY) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; float () W_OldWeaponSlot7 = { if (self.playerclass == PC_SOLDIER) return WEAP_ROCKET_LAUNCHER; + if (self.playerclass == PC_DEMOMAN) + return WEAP_GRENADE_LAUNCHER; else if (self.playerclass == PC_HVYWEAP) return WEAP_ASSAULT_CANNON; else if (self.playerclass == PC_PYRO) return WEAP_INCENDIARY; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_ENGINEER - || self.playerclass == PC_SPY) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; @@ -2394,6 +2371,7 @@ void (float slot) W_WeaponSlot = { }; void (float inp) W_OldWeaponSlot = { + self.next_weaponmode = 0; if (inp == 1) { self.next_weapon = W_OldWeaponSlot1(); } @@ -2414,7 +2392,131 @@ void (float inp) W_OldWeaponSlot = { } else if (inp == 7) { self.next_weapon = W_OldWeaponSlot7(); + if (self.next_weapon == WEAP_GRENADE_LAUNCHER) + self.next_weaponmode = 1; } + if (self.next_weapon == 0) + sprint(self, PRINT_HIGH, "No weapon\n"); +} + +float (float newSlot) W_OldImpulseFromNewSlot = { + if (newSlot == 1) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_SNIPER_RIFLE); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_ROCKET_LAUNCHER); + } + else if (self.playerclass == PC_DEMOMAN) { + return 6; + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_SUPER_NAILGUN); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_ASSAULT_CANNON); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_INCENDIARY); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_TRANQ); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_LASER); + } + } + else if (newSlot == 2) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_AUTO_RIFLE); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_DEMOMAN) { + return 7; + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_FLAMETHROWER); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + } + else if (newSlot == 3) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_DEMOMAN) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_LASER); + } + } + else if (newSlot == 4) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_DEMOMAN) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_MEDIKIT); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_SPANNER); + } + } + return 0; } void () W_AmmoError = { @@ -2462,6 +2564,8 @@ void (entity pl, float swap) W_WeaponState_Load = { } float (entity pl) W_WeaponState_Check = { + // bprint(2,ftos(pl.current_weaponslot == pl.weaponstate_current_weaponslot)); + //bprint(2,"\n"); if (pl.current_weaponslot == pl.weaponstate_current_weaponslot && pl.last_weaponslot == pl.weaponstate_last_weaponslot) return 1; @@ -2504,7 +2608,6 @@ void (float inp) W_ChangeWeapon = { W_WeaponSlot(inp); } - // don't update current/last weapon information if next weapon is the same as current if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { @@ -2544,12 +2647,47 @@ void () CycleWeaponNext = { return; next = 0; - for (slot = 1; slot <= 4; slot++) { - next = (slot == 4) ? 1 : (slot + 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 4) ? 1 : (next + 1); - break; + if (!IsUsingOldImpulses()) { + for (slot = 1; slot <= 4; slot++) { + next = (slot == 4) ? 1 : (slot + 1); + if (self.current_weaponslot == slot) { + while (! W_AmmoSlot(next)) + next = (next == 4) ? 1 : (next + 1); + break; + } + } + } + else if (IsUsingOldImpulses()) { + for (slot = self.current_weaponslot; slot <= GetLastWeaponImpulse(); slot++) { + next = (slot == GetLastWeaponImpulse()) ? 1 : (slot + 1); + if (next == 1) { + if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) + break; + } + else if (next == 2) { + if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) + break; + } + else if (next == 3) { + if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) + break; + } + else if (next == 4) { + if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) + break; + } + else if (next == 5) { + if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) + break; + } + else if (next == 6) { + if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) + break; + } + else if (next == 7) { + if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) + break; + } } } W_ChangeWeapon(next); @@ -2562,14 +2700,51 @@ void () CycleWeaponPrev = { return; next = 0; - for (slot = 1; slot <= 4; slot++) { - next = (slot == 1) ? 4 : (slot - 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 1) ? 4 : (next - 1); - break; + if (!IsUsingOldImpulses()) { + for (slot = 1; slot <= 4; slot++) { + next = (slot == 1) ? 4 : (slot - 1); + if (self.current_weaponslot == slot) { + while (! W_AmmoSlot(next)) + next = (next == 1) ? 4 : (next - 1); + break; + } + } + } + else { + for (slot = self.current_weaponslot; slot >= 1; slot--) { + next = (slot == 1) ? GetLastWeaponImpulse() : (slot - 1); + if (next == 1) { + if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) + break; + } + else if (next == 2) { + if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) + break; + } + else if (next == 3) { + if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) + break; + } + else if (next == 4) { + if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) + break; + } + else if (next == 5) { + if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) + break; + } + else if (next == 6) { + if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) + break; + } + else if (next == 7) { + if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) + break; + } } } + + W_ChangeWeapon(next); }; @@ -2888,6 +3063,7 @@ void () DeadImpulses = { } }; + void () W_WeaponFrame = { if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 10) { @@ -2960,8 +3136,9 @@ void () W_WeaponFrame = { // load weapon state if current state doesn't match // stored state, if weapon is ready - if (!W_WeaponState_Check(self) && WeaponReady(self) && !(self.tfstate & TFSTATE_AIMING)) + if (!W_WeaponState_Check(self) && WeaponReady(self) && !(self.tfstate & TFSTATE_AIMING)) { W_WeaponState_Load(self, 0); + } // +slot1-4 quick fire } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 @@ -2971,14 +3148,26 @@ void () W_WeaponFrame = { self.has_quickfired = 0; if (WeaponReady(self)) { - if (self.impulse == TF_QUICKSLOT1) - W_ChangeWeapon(1); - else if (self.impulse == TF_QUICKSLOT2) - W_ChangeWeapon(2); - else if (self.impulse == TF_QUICKSLOT3) - W_ChangeWeapon(3); - else if (self.impulse == TF_QUICKSLOT4) - W_ChangeWeapon(4); + if (!IsUsingOldImpulses()) { + if (self.impulse == TF_QUICKSLOT1) + W_ChangeWeapon(1); + else if (self.impulse == TF_QUICKSLOT2) + W_ChangeWeapon(2); + else if (self.impulse == TF_QUICKSLOT3) + W_ChangeWeapon(3); + else if (self.impulse == TF_QUICKSLOT4) + W_ChangeWeapon(4); + } + else { + if (self.impulse == TF_QUICKSLOT1) + W_ChangeWeapon(W_OldImpulseFromNewSlot(1)); + else if (self.impulse == TF_QUICKSLOT2) + W_ChangeWeapon(W_OldImpulseFromNewSlot(2)); + else if (self.impulse == TF_QUICKSLOT3) + W_ChangeWeapon(W_OldImpulseFromNewSlot(3)); + else if (self.impulse == TF_QUICKSLOT4) + W_ChangeWeapon(W_OldImpulseFromNewSlot(4)); + } } // change weapon if queue_weaponslot has been set From a98cc2e925952fe1004bd0be060ea9e5baa81dd1 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Mon, 4 Feb 2019 21:35:09 +0000 Subject: [PATCH 0569/2474] partial --- actions.qc | 94 +++++++++++++----- client.qc | 17 +++- tfort.qc | 2 +- weapons.qc | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 358 insertions(+), 42 deletions(-) diff --git a/actions.qc b/actions.qc index e600777f..b56361d4 100644 --- a/actions.qc +++ b/actions.qc @@ -576,20 +576,41 @@ void () TeamFortress_ReloadCurrentWeapon = { void (float slot) TeamFortress_ReloadSlot = { local float weap = 0; - if (slot < 1 || slot > 3) - return; + if (!IsUsingOldImpulses()) { + if (slot < 1 || slot > 3) + return; - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + if (slot == 1) + weap = W_WeaponSlot1(); + else if (slot == 2) + weap = W_WeaponSlot2(); + else if (slot == 3) { + if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + return; + weap = W_WeaponSlot3(); + } + TeamFortress_ReloadWeapon(weap); + } + else { + if (slot < 1 || slot > 7) return; - weap = W_WeaponSlot3(); + if (slot == 1) + weap = W_OldWeaponSlot1(); + else if (slot == 2) + weap = W_OldWeaponSlot2(); + else if (slot == 3) + weap = W_OldWeaponSlot3(); + else if (slot == 4) + weap = W_OldWeaponSlot4(); + else if (slot == 5) + weap = W_OldWeaponSlot5(); + else if (slot == 6) + weap = W_OldWeaponSlot6(); + else if (slot == 7) + weap = W_OldWeaponSlot7(); + if (weap != 0) + TeamFortress_ReloadWeapon(weap); } - - TeamFortress_ReloadWeapon(weap); }; void () TeamFortress_ReloadNext = { @@ -603,23 +624,44 @@ void () TeamFortress_ReloadNext = { return; } - // then go through each slot - for (slot = 1; slot < 4; slot++) { - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + if (!IsUsingOldImpulses()) { + // then go through each slot + for (slot = 1; slot < 4; slot++) { + if (slot == 1) + weap = W_WeaponSlot1(); + else if (slot == 2) + weap = W_WeaponSlot2(); + else if (slot == 3) { + if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) + break; + weap = W_WeaponSlot3(); + } + + if (CheckForAmmo(weap)) { + self.current_weapon = weap; + TeamFortress_ReloadWeapon(weap); + reload = 1; break; - weap = W_WeaponSlot3(); + } } - - if (CheckForAmmo(weap)) { - self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap); - reload = 1; - break; + } + else { + // then go through each slot + for (slot = 1; slot < 4; slot++) { + if (slot == 1) + weap = W_OldWeaponSlot1(); + else if (slot == 2) + weap = W_OldWeaponSlot2(); + else if (slot == 3) + weap = W_OldWeaponSlot3(); + else if (slot == 4) + weap = W_OldWeaponSlot4(); + else if (slot == 5) + weap = W_OldWeaponSlot5(); + else if (slot == 6) + weap = W_OldWeaponSlot6(); + else if (slot == 7) + weap = W_OldWeaponSlot7(); } } diff --git a/client.qc b/client.qc index 6ac0fa27..84d2f1df 100644 --- a/client.qc +++ b/client.qc @@ -54,6 +54,7 @@ void () StartTimer; void () StopTimer; void (string cl_pwd) Admin_Check; void () Admin_Aliases; +float () GetLastWeaponImpulse; string nextmap; @@ -1253,8 +1254,9 @@ void () PutClientInServer = { W_SetCurrentAmmo(self); if (self.current_weaponslot && self.last_playerclass == self.playerclass) W_ChangeWeapon(self.current_weaponslot); - else - W_ChangeWeapon(1); + else { + W_ChangeWeapon(W_BestWeaponSlot()); + } self.last_playerclass = self.playerclass; self.attack_finished = time + 0.3; @@ -2702,3 +2704,14 @@ void (entity targ, entity attacker) ClientObituary = { } }; + +float () IsUsingOldImpulses = { + return (infokey(self, "old_impulses") == "1"); +} + +float () GetLastWeaponImpulse = { + if (IsUsingOldImpulses()) + return 7; + else + return 4; +} diff --git a/tfort.qc b/tfort.qc index 75f218eb..3824224f 100644 --- a/tfort.qc +++ b/tfort.qc @@ -293,7 +293,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(1); + W_ChangeWeapon(W_BestWeaponSlot()); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; diff --git a/weapons.qc b/weapons.qc index 2ecf1437..e7f7b93f 100644 --- a/weapons.qc +++ b/weapons.qc @@ -95,6 +95,7 @@ void () BioInfection_MonsterDecay; void (entity pl, float swap) W_WeaponState_Load; float (float weap) W_GetSlot; +float (float weap) W_OldGetSlot; float () W_BestWeaponSlot; void () W_FireFlame; void () W_FireIncendiaryCannon; @@ -107,6 +108,9 @@ void () TranquiliserTimer; void () TeamFortress_CTF_FlagInfo; void () ClanMode; +float () GetLastWeaponImpulse; +float () IsUsingOldImpulses; + void () W_Precache = { precache_sound("weapons/r_exp3.wav"); precache_sound("weapons/rocket1i.wav"); @@ -1612,6 +1616,12 @@ float () W_BestWeapon = { return WEAP_LIGHTNING; else if ((self.ammo_cells >= 7 && self.ammo_shells >= 1) && it & WEAP_ASSAULT_CANNON) return WEAP_ASSAULT_CANNON; + else if (self.ammo_rockets >= 1 && it & WEAP_GRENADE_LAUNCHER) + return WEAP_GRENADE_LAUNCHER; + else if (self.ammo_rockets >= 1 && it & WEAP_ROCKET_LAUNCHER) + return WEAP_ROCKET_LAUNCHER; + else if (self.ammo_rockets >= 3 && it & WEAP_INCENDIARY) + return WEAP_INCENDIARY; else if (self.ammo_cells >= 1 && it & WEAP_FLAMETHROWER) return WEAP_FLAMETHROWER; else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) @@ -1641,13 +1651,19 @@ float () W_BestWeaponSlot = { weap = W_BestWeapon(); - return W_GetSlot(weap); + if (!IsUsingOldImpulses()) + return W_GetSlot(weap); + else + return W_OldGetSlot(weap); }; void () W_ChangeToBestWeapon = { - local float slot = W_BestWeaponSlot(); - - W_WeaponSlot(slot); + local float slot = W_BestWeaponSlot(); + + if (!IsUsingOldImpulses()) + W_WeaponSlot(slot); + else + W_OldWeaponSlot(slot); //self.last_weaponslot = self.current_weaponslot; //self.last_weapon = self.current_weapon; @@ -2021,6 +2037,34 @@ float (float weap) W_GetSlot = { return 0; }; +float (float weap) W_OldGetSlot = { + if (weap == WEAP_AXE + || weap == WEAP_MEDIKIT + || weap == WEAP_SPANNER) + return 1; + else if (weap == WEAP_SHOTGUN + || weap == WEAP_SNIPER_RIFLE + || weap == WEAP_TRANQ + || weap == WEAP_LASER) + return 2; + else if (weap == WEAP_SUPER_SHOTGUN + || weap == WEAP_AUTO_RIFLE) + return 3; + else if (weap == WEAP_NAILGUN) + return 4; + else if (weap == WEAP_SUPER_NAILGUN + || weap == WEAP_FLAMETHROWER) + return 5; + else if (weap == WEAP_GRENADE_LAUNCHER + || weap == WEAP_FLAMETHROWER) + return 6; + else if (weap == WEAP_ROCKET_LAUNCHER + || weap == WEAP_ASSAULT_CANNON + || weap == WEAP_INCENDIARY) + return 7; + return 0; +}; + float (float inp) W_AmmoSlot = { self.noammo = 0; @@ -2086,6 +2130,186 @@ float (float inp) W_AmmoSlot = { return 1; }; +float (float inp) W_OldAmmoSlot = { + self.noammo = 0; + if (inp == 1) { + return 1; + } + else if (inp == 2) { + if ((self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_PYRO + || self.playerclass == PC_SPY) + && self.ammo_shells < 1) + self.noammo = 1; + else if (self.playerclass == PC_ENGINEER && self.ammo_nails < 1) + self.noammo = 1; + + } + else if (inp == 3) { + if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) + self.noammo = 1; + else if ((self.playerclass == PC_SOLDIER + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_SPY + || self.playerclass == PC_ENGINEER) + && self.ammo_shells < 2) + self.noammo = 1; + } + else if (inp == 4) { + if ((self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SPY) + && self.ammo_nails < 2) + self.noammo = 1; + } + else if (inp == 5) { + if (self.playerclass == PC_MEDIC && self.ammo_nails < 4) + self.noammo = 1; + else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) + self.noammo = 1; + } + else if (inp == 6) { + if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) + self.noammo = 1; + else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) + self.noammo = 1; + + } + else if (inp == 7) { + if (self.playerclass == PC_SOLDIER && self.ammo_rockets < 1) + self.noammo = 1; + else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) + self.noammo = 1; + else if (self.playerclass == PC_HVYWEAP) { + if (self.ammo_shells < 1) + self.noammo = 1; + else if (self.ammo_cells < 7) + self.noammo = 2; + } + else if (self.playerclass == PC_PYRO && self.ammo_rockets < 3) + self.noammo = 1; + + } + if (self.noammo > 0) + return 0; + else + return 1; +}; + +float () W_OldWeaponSlot1 = { + if (self.weapons_carried & WEAP_MEDIKIT) + return WEAP_MEDIKIT; + else if (self.weapons_carried & WEAP_SPANNER) + return WEAP_SPANNER; + else + return WEAP_AXE; +}; + +float () W_OldWeaponSlot2 = { + if (self.playerclass == PC_SCOUT + ||self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_PYRO) + return WEAP_SHOTGUN; + else if (self.playerclass == PC_SNIPER) + return WEAP_SNIPER_RIFLE; + else if (self.playerclass == PC_SPY) + return WEAP_TRANQ; + else if (self.playerclass == PC_ENGINEER) + return WEAP_LASER; + return 0; +}; + +float () W_OldWeaponSlot3 = { + if (self.playerclass == PC_SOLDIER + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_SPY + || self.playerclass == PC_ENGINEER) + return WEAP_SUPER_SHOTGUN; + else if (self.playerclass == PC_SNIPER) + return WEAP_AUTO_RIFLE; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_PYRO) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot4 = { + if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SPY) + return WEAP_NAILGUN; + else if (self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_PYRO + || self.playerclass == PC_ENGINEER) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot5 = { + if (self.playerclass == PC_MEDIC) + return WEAP_SUPER_NAILGUN; + else if (self.playerclass == PC_PYRO) + return WEAP_FLAMETHROWER; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SOLDIER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_ENGINEER + || self.playerclass == PC_SPY) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot6 = { + if (self.playerclass == PC_DEMOMAN) { + self.weaponmode = 0; + return WEAP_GRENADE_LAUNCHER; + } + else if (self.playerclass == PC_PYRO) + return WEAP_FLAMETHROWER; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_SOLDIER + || self.playerclass == PC_MEDIC + || self.playerclass == PC_HVYWEAP + || self.playerclass == PC_ENGINEER + || self.playerclass == PC_SPY) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + +float () W_OldWeaponSlot7 = { + if (self.playerclass == PC_SOLDIER) + return WEAP_ROCKET_LAUNCHER; + else if (self.playerclass == PC_HVYWEAP) + return WEAP_ASSAULT_CANNON; + else if (self.playerclass == PC_PYRO) + return WEAP_INCENDIARY; + else if (self.playerclass == PC_SCOUT + || self.playerclass == PC_SNIPER + || self.playerclass == PC_DEMOMAN + || self.playerclass == PC_MEDIC + || self.playerclass == PC_ENGINEER + || self.playerclass == PC_SPY) + sprint(self, PRINT_HIGH, "No weapon\n"); + return 0; +}; + float () W_WeaponSlot1 = { if (self.playerclass == PC_SCOUT) return WEAP_NAILGUN; @@ -2169,6 +2393,30 @@ void (float slot) W_WeaponSlot = { self.next_weapon = W_WeaponSlot4(); }; +void (float inp) W_OldWeaponSlot = { + if (inp == 1) { + self.next_weapon = W_OldWeaponSlot1(); + } + else if (inp == 2) { + self.next_weapon = W_OldWeaponSlot2(); + } + else if (inp == 3) { + self.next_weapon = W_OldWeaponSlot3(); + } + else if (inp == 4) { + self.next_weapon = W_OldWeaponSlot4(); + } + else if (inp == 5) { + self.next_weapon = W_OldWeaponSlot5(); + } + else if (inp == 6) { + self.next_weapon = W_OldWeaponSlot6(); + } + else if (inp == 7) { + self.next_weapon = W_OldWeaponSlot7(); + } +} + void () W_AmmoError = { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -2222,7 +2470,8 @@ float (entity pl) W_WeaponState_Check = { } void (float inp) W_ChangeWeapon = { - if (inp < 1 || inp > 4) + + if (inp < 1 || inp > GetLastWeaponImpulse()) return; if (self.playerclass == 0) @@ -2236,14 +2485,26 @@ void (float inp) W_ChangeWeapon = { if (!WeaponReady(self)) return; - // check for ammo - if (! W_AmmoSlot(inp)) { - W_AmmoError(); - self.queue_weaponslot = 0; - return; + if (IsUsingOldImpulses()) { + // check for ammo + if (! W_OldAmmoSlot(inp)) { + W_AmmoError(); + self.queue_weaponslot = 0; + return; + } + W_OldWeaponSlot(inp); } + else { + // check for ammo + if (! W_AmmoSlot(inp)) { + W_AmmoError(); + self.queue_weaponslot = 0; + return; + } - W_WeaponSlot(inp); + W_WeaponSlot(inp); + } + // don't update current/last weapon information if next weapon is the same as current if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { @@ -2681,8 +2942,8 @@ void () W_WeaponFrame = { } - // slot 1-4 binds - if (self.impulse >= 1 && self.impulse <= 4 && WeaponReady(self) + // slot 1-4 (or 1-7) binds + if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && WeaponReady(self) && !self.is_building && !self.is_detpacking) { // load weapon state if current state doesn't match stored state From 9c24df7ffd3e7d7fcf986a86eeb320ef9d3b4f48 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Thu, 7 Feb 2019 01:52:46 +0000 Subject: [PATCH 0570/2474] added W_Old* functions and other helpers --- actions.qc | 33 ++++-- tfort.qc | 6 +- weapons.qc | 315 ++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 279 insertions(+), 75 deletions(-) diff --git a/actions.qc b/actions.qc index b56361d4..218e7b17 100644 --- a/actions.qc +++ b/actions.qc @@ -609,22 +609,22 @@ void (float slot) TeamFortress_ReloadSlot = { else if (slot == 7) weap = W_OldWeaponSlot7(); if (weap != 0) - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap); } }; void () TeamFortress_ReloadNext = { local float slot, reload = 0, weap = 0; - // reload current slot first - slot = W_GetSlot(self.current_weapon); - if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon); - reload = 1; - return; - } - if (!IsUsingOldImpulses()) { + // reload current slot first + slot = W_GetSlot(self.current_weapon); + if (CheckForAmmo(self.current_weapon)) { + TeamFortress_ReloadWeapon(self.current_weapon); + reload = 1; + return; + } + // then go through each slot for (slot = 1; slot < 4; slot++) { if (slot == 1) @@ -646,8 +646,14 @@ void () TeamFortress_ReloadNext = { } } else { + slot = W_OldGetSlot(self.current_weapon); + if (CheckForAmmo(self.current_weapon)) { + TeamFortress_ReloadWeapon(self.current_weapon); + reload = 1; + return; + } // then go through each slot - for (slot = 1; slot < 4; slot++) { + for (slot = 1; slot < GetLastWeaponImpulse(); slot++) { if (slot == 1) weap = W_OldWeaponSlot1(); else if (slot == 2) @@ -662,6 +668,13 @@ void () TeamFortress_ReloadNext = { weap = W_OldWeaponSlot6(); else if (slot == 7) weap = W_OldWeaponSlot7(); + + if (CheckForAmmo(weap)) { + self.current_weapon = weap; + TeamFortress_ReloadWeapon(weap); + reload = 1; + break; + } } } diff --git a/tfort.qc b/tfort.qc index 3824224f..3c666121 100644 --- a/tfort.qc +++ b/tfort.qc @@ -1534,7 +1534,7 @@ void () TeamFortress_SetEquipment = { self.last_weapon = 0; self.weaponmode = 0; self.last_weaponmode = 0; - self.current_weaponslot = 1; + self.current_weaponslot = W_BestWeaponSlot(); self.last_weaponslot = 2; W_WeaponState_Save(self); } @@ -1647,7 +1647,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_SCOUT_MAXARMOR; - if (self.last_playerclass != self.playerclass) + if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_NAILGUN; self.items_allowed = PC_SCOUT_WEAPONS; @@ -2257,6 +2257,8 @@ void () TeamFortress_SetEquipment = { self.items = self.items | IT_ARMOR1; W_SetCurrentAmmo(self); + if (self.last_playerclass != self.playerclass) + self.current_weaponslot = W_BestWeaponSlot(); }; float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { diff --git a/weapons.qc b/weapons.qc index e7f7b93f..0fbb9e6a 100644 --- a/weapons.qc +++ b/weapons.qc @@ -111,6 +111,8 @@ void () ClanMode; float () GetLastWeaponImpulse; float () IsUsingOldImpulses; +void (float inp) W_OldWeaponSlot; + void () W_Precache = { precache_sound("weapons/r_exp3.wav"); precache_sound("weapons/rocket1i.wav"); @@ -1626,16 +1628,18 @@ float () W_BestWeapon = { return WEAP_FLAMETHROWER; else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) return WEAP_SUPER_NAILGUN; - else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) - return WEAP_SUPER_SHOTGUN; else if (self.ammo_nails >= 1 && it & WEAP_LASER) return WEAP_LASER; + else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) + return WEAP_SUPER_SHOTGUN; + else if (self.ammo_shells >= 1 && it & WEAP_SNIPER_RIFLE) + return WEAP_SNIPER_RIFLE; + else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) + return WEAP_TRANQ; else if (self.ammo_nails >= 1 && it & WEAP_NAILGUN) return WEAP_NAILGUN; else if (self.ammo_shells >= 1 && it & WEAP_SHOTGUN) return WEAP_SHOTGUN; - else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) - return WEAP_TRANQ; else if (it & WEAP_MEDIKIT) return WEAP_MEDIKIT; else if (it & WEAP_SPANNER) @@ -2055,13 +2059,18 @@ float (float weap) W_OldGetSlot = { else if (weap == WEAP_SUPER_NAILGUN || weap == WEAP_FLAMETHROWER) return 5; - else if (weap == WEAP_GRENADE_LAUNCHER - || weap == WEAP_FLAMETHROWER) + else if (weap == WEAP_FLAMETHROWER) return 6; else if (weap == WEAP_ROCKET_LAUNCHER || weap == WEAP_ASSAULT_CANNON || weap == WEAP_INCENDIARY) return 7; + else if (weap == WEAP_GRENADE_LAUNCHER) { + if (self.weaponmode == 0) + return 6; + else + return 7; + } return 0; }; @@ -2237,10 +2246,6 @@ float () W_OldWeaponSlot3 = { return WEAP_SUPER_SHOTGUN; else if (self.playerclass == PC_SNIPER) return WEAP_AUTO_RIFLE; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_PYRO) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; @@ -2249,13 +2254,6 @@ float () W_OldWeaponSlot4 = { || self.playerclass == PC_SNIPER || self.playerclass == PC_SPY) return WEAP_NAILGUN; - else if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO - || self.playerclass == PC_ENGINEER) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; @@ -2264,49 +2262,28 @@ float () W_OldWeaponSlot5 = { return WEAP_SUPER_NAILGUN; else if (self.playerclass == PC_PYRO) return WEAP_FLAMETHROWER; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_ENGINEER - || self.playerclass == PC_SPY) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; float () W_OldWeaponSlot6 = { if (self.playerclass == PC_DEMOMAN) { - self.weaponmode = 0; + self.next_weaponmode = 0; return WEAP_GRENADE_LAUNCHER; } else if (self.playerclass == PC_PYRO) return WEAP_FLAMETHROWER; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_ENGINEER - || self.playerclass == PC_SPY) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; float () W_OldWeaponSlot7 = { if (self.playerclass == PC_SOLDIER) return WEAP_ROCKET_LAUNCHER; + if (self.playerclass == PC_DEMOMAN) + return WEAP_GRENADE_LAUNCHER; else if (self.playerclass == PC_HVYWEAP) return WEAP_ASSAULT_CANNON; else if (self.playerclass == PC_PYRO) return WEAP_INCENDIARY; - else if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_ENGINEER - || self.playerclass == PC_SPY) - sprint(self, PRINT_HIGH, "No weapon\n"); return 0; }; @@ -2394,6 +2371,7 @@ void (float slot) W_WeaponSlot = { }; void (float inp) W_OldWeaponSlot = { + self.next_weaponmode = 0; if (inp == 1) { self.next_weapon = W_OldWeaponSlot1(); } @@ -2414,7 +2392,131 @@ void (float inp) W_OldWeaponSlot = { } else if (inp == 7) { self.next_weapon = W_OldWeaponSlot7(); + if (self.next_weapon == WEAP_GRENADE_LAUNCHER) + self.next_weaponmode = 1; } + if (self.next_weapon == 0) + sprint(self, PRINT_HIGH, "No weapon\n"); +} + +float (float newSlot) W_OldImpulseFromNewSlot = { + if (newSlot == 1) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_SNIPER_RIFLE); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_ROCKET_LAUNCHER); + } + else if (self.playerclass == PC_DEMOMAN) { + return 6; + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_SUPER_NAILGUN); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_ASSAULT_CANNON); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_INCENDIARY); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_TRANQ); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_LASER); + } + } + else if (newSlot == 2) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_AUTO_RIFLE); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_DEMOMAN) { + return 7; + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_FLAMETHROWER); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_SUPER_SHOTGUN); + } + } + else if (newSlot == 3) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_DEMOMAN) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_SHOTGUN); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_NAILGUN); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_LASER); + } + } + else if (newSlot == 4) { + if (self.playerclass == PC_SCOUT) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_SNIPER) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_SOLDIER) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_DEMOMAN) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_MEDIC) { + return W_OldGetSlot(WEAP_MEDIKIT); + } + else if (self.playerclass == PC_HVYWEAP) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_PYRO) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_SPY) { + return W_OldGetSlot(WEAP_AXE); + } + else if (self.playerclass == PC_ENGINEER) { + return W_OldGetSlot(WEAP_SPANNER); + } + } + return 0; } void () W_AmmoError = { @@ -2462,6 +2564,8 @@ void (entity pl, float swap) W_WeaponState_Load = { } float (entity pl) W_WeaponState_Check = { + // bprint(2,ftos(pl.current_weaponslot == pl.weaponstate_current_weaponslot)); + //bprint(2,"\n"); if (pl.current_weaponslot == pl.weaponstate_current_weaponslot && pl.last_weaponslot == pl.weaponstate_last_weaponslot) return 1; @@ -2504,7 +2608,6 @@ void (float inp) W_ChangeWeapon = { W_WeaponSlot(inp); } - // don't update current/last weapon information if next weapon is the same as current if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { @@ -2544,12 +2647,47 @@ void () CycleWeaponNext = { return; next = 0; - for (slot = 1; slot <= 4; slot++) { - next = (slot == 4) ? 1 : (slot + 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 4) ? 1 : (next + 1); - break; + if (!IsUsingOldImpulses()) { + for (slot = 1; slot <= 4; slot++) { + next = (slot == 4) ? 1 : (slot + 1); + if (self.current_weaponslot == slot) { + while (! W_AmmoSlot(next)) + next = (next == 4) ? 1 : (next + 1); + break; + } + } + } + else if (IsUsingOldImpulses()) { + for (slot = self.current_weaponslot; slot <= GetLastWeaponImpulse(); slot++) { + next = (slot == GetLastWeaponImpulse()) ? 1 : (slot + 1); + if (next == 1) { + if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) + break; + } + else if (next == 2) { + if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) + break; + } + else if (next == 3) { + if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) + break; + } + else if (next == 4) { + if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) + break; + } + else if (next == 5) { + if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) + break; + } + else if (next == 6) { + if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) + break; + } + else if (next == 7) { + if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) + break; + } } } W_ChangeWeapon(next); @@ -2562,14 +2700,51 @@ void () CycleWeaponPrev = { return; next = 0; - for (slot = 1; slot <= 4; slot++) { - next = (slot == 1) ? 4 : (slot - 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 1) ? 4 : (next - 1); - break; + if (!IsUsingOldImpulses()) { + for (slot = 1; slot <= 4; slot++) { + next = (slot == 1) ? 4 : (slot - 1); + if (self.current_weaponslot == slot) { + while (! W_AmmoSlot(next)) + next = (next == 1) ? 4 : (next - 1); + break; + } + } + } + else { + for (slot = self.current_weaponslot; slot >= 1; slot--) { + next = (slot == 1) ? GetLastWeaponImpulse() : (slot - 1); + if (next == 1) { + if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) + break; + } + else if (next == 2) { + if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) + break; + } + else if (next == 3) { + if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) + break; + } + else if (next == 4) { + if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) + break; + } + else if (next == 5) { + if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) + break; + } + else if (next == 6) { + if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) + break; + } + else if (next == 7) { + if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) + break; + } } } + + W_ChangeWeapon(next); }; @@ -2888,6 +3063,7 @@ void () DeadImpulses = { } }; + void () W_WeaponFrame = { if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 10) { @@ -2960,8 +3136,9 @@ void () W_WeaponFrame = { // load weapon state if current state doesn't match // stored state, if weapon is ready - if (!W_WeaponState_Check(self) && WeaponReady(self) && !(self.tfstate & TFSTATE_AIMING)) + if (!W_WeaponState_Check(self) && WeaponReady(self) && !(self.tfstate & TFSTATE_AIMING)) { W_WeaponState_Load(self, 0); + } // +slot1-4 quick fire } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 @@ -2971,14 +3148,26 @@ void () W_WeaponFrame = { self.has_quickfired = 0; if (WeaponReady(self)) { - if (self.impulse == TF_QUICKSLOT1) - W_ChangeWeapon(1); - else if (self.impulse == TF_QUICKSLOT2) - W_ChangeWeapon(2); - else if (self.impulse == TF_QUICKSLOT3) - W_ChangeWeapon(3); - else if (self.impulse == TF_QUICKSLOT4) - W_ChangeWeapon(4); + if (!IsUsingOldImpulses()) { + if (self.impulse == TF_QUICKSLOT1) + W_ChangeWeapon(1); + else if (self.impulse == TF_QUICKSLOT2) + W_ChangeWeapon(2); + else if (self.impulse == TF_QUICKSLOT3) + W_ChangeWeapon(3); + else if (self.impulse == TF_QUICKSLOT4) + W_ChangeWeapon(4); + } + else { + if (self.impulse == TF_QUICKSLOT1) + W_ChangeWeapon(W_OldImpulseFromNewSlot(1)); + else if (self.impulse == TF_QUICKSLOT2) + W_ChangeWeapon(W_OldImpulseFromNewSlot(2)); + else if (self.impulse == TF_QUICKSLOT3) + W_ChangeWeapon(W_OldImpulseFromNewSlot(3)); + else if (self.impulse == TF_QUICKSLOT4) + W_ChangeWeapon(W_OldImpulseFromNewSlot(4)); + } } // change weapon if queue_weaponslot has been set From fdb582cec91878a805641581064357284b92d978 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Thu, 7 Feb 2019 02:16:27 +0000 Subject: [PATCH 0571/2474] adjusting best weapons, ignoring class menu when using medic (impulse conflict) --- client.qc | 2 +- weapons.qc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client.qc b/client.qc index 84d2f1df..5e2401d3 100644 --- a/client.qc +++ b/client.qc @@ -2706,7 +2706,7 @@ void (entity targ, entity attacker) ClientObituary = { }; float () IsUsingOldImpulses = { - return (infokey(self, "old_impulses") == "1"); + return ((infokey(self, "old_weapon_impulses") == "1") || (infokey(self, "owi") == "1")); } float () GetLastWeaponImpulse = { diff --git a/weapons.qc b/weapons.qc index 0fbb9e6a..69868164 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1630,12 +1630,12 @@ float () W_BestWeapon = { return WEAP_SUPER_NAILGUN; else if (self.ammo_nails >= 1 && it & WEAP_LASER) return WEAP_LASER; + else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) + return WEAP_TRANQ; else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) return WEAP_SUPER_SHOTGUN; else if (self.ammo_shells >= 1 && it & WEAP_SNIPER_RIFLE) return WEAP_SNIPER_RIFLE; - else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) - return WEAP_TRANQ; else if (self.ammo_nails >= 1 && it & WEAP_NAILGUN) return WEAP_NAILGUN; else if (self.ammo_shells >= 1 && it & WEAP_SHOTGUN) @@ -3072,7 +3072,7 @@ void () W_WeaponFrame = { } } - if (self.impulse == TF_CLASSMENU) { + if (self.impulse == TF_CLASSMENU && self.playerclass != PC_MEDIC) { if (self.playerclass == PC_ENGINEER) Menu_Engineer(self); else if (self.playerclass == PC_SCOUT) From a9040af688f2426405a0e69f1c270e6de142b269 Mon Sep 17 00:00:00 2001 From: up2h Date: Fri, 8 Feb 2019 18:03:46 -0200 Subject: [PATCH 0572/2474] using pause builtin --- admin.qc | 75 +++++++++++++++++++++++++++++-------------------------- client.qc | 3 +++ defs.qc | 6 +++-- qw.qc | 3 +++ 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/admin.qc b/admin.qc index cfd1055b..ff308ed5 100644 --- a/admin.qc +++ b/admin.qc @@ -133,45 +133,50 @@ void () CeaseFire_think = void () Admin_CeaseFire = { local entity te; - if (!cease_fire) { - if (cb_prematch) { - StopTimer(); + if (!ceasefire_type) { + if (!cease_fire) { + if (cb_prematch) { + StopTimer(); + } + cease_fire = 1; + bprint(2, "CEASE FIRE\n"); + te = find(world, classname, "player"); + while (te) { + CenterPrint3(te, "CEASE FIRE\nCalled by: ", self.netname, "\n"); + te.immune_to_check = (time + 5); + te.tfstate = (te.tfstate | TFSTATE_CANT_MOVE); + TeamFortress_SetSpeed(te); + te = find(te, classname, "player"); + } + te = spawn(); + te.owner = self; + te.classname = "ceasefire"; + te.think = CeaseFire_think; + te.nextthink = (time + 5); } - cease_fire = 1; - bprint(2, "CEASE FIRE\n"); - te = find(world, classname, "player"); - while (te) { - CenterPrint3(te, "CEASE FIRE\nCalled by: ", self.netname, "\n"); - te.immune_to_check = (time + 5); - te.tfstate = (te.tfstate | TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(te); - te = find(te, classname, "player"); + else { + te = find(world, classname, "ceasefire"); + if (te) { + dremove(te); + } + cease_fire = 0; + if (cb_prematch) { + cb_prematch_time = 0; + StartTimer(); + } + bprint(2, "RESUME FIRE\n"); + te = find(world, classname, "player"); + while (te) { + CenterPrint3(te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); + te.immune_to_check = (time + 5); + te.tfstate = (te.tfstate - (te.tfstate & TFSTATE_CANT_MOVE)); + TeamFortress_SetSpeed (te); + te = find (te, classname, "player"); + } } - te = spawn(); - te.owner = self; - te.classname = "ceasefire"; - te.think = CeaseFire_think; - te.nextthink = (time + 5); } else { - te = find(world, classname, "ceasefire"); - if (te) { - dremove(te); - } - cease_fire = 0; - if (cb_prematch) { - cb_prematch_time = 0; - StartTimer(); - } - bprint(2, "RESUME FIRE\n"); - te = find(world, classname, "player"); - while (te) { - CenterPrint3(te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); - te.immune_to_check = (time + 5); - te.tfstate = (te.tfstate - (te.tfstate & TFSTATE_CANT_MOVE)); - TeamFortress_SetSpeed (te); - te = find (te, classname, "player"); - } + setpause(); } }; diff --git a/client.qc b/client.qc index 6ac0fa27..d42cc982 100644 --- a/client.qc +++ b/client.qc @@ -505,6 +505,9 @@ void () DecodeLevelParms = { // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass pyro_type = CF_GetSetting("pyrotype", "pyro_type", "1"); + // ceasefire type, 0: Default, 1: Pause + ceasefire_type = CF_GetSetting("ceasefire_type", "cft", "1"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/defs.qc b/defs.qc index 1af9de34..cd19bccf 100644 --- a/defs.qc +++ b/defs.qc @@ -416,7 +416,7 @@ float (string s) stof = #81; // convert string to float void (vector where, float set) multicast = #82; // sends the temp message to a set // of clients, possibly in PVS or PHS -void(string str) tokanize = #84; // tokanize text +void(string str) tokenize = #84; // tokenize text float() argc = #85; // returns number of tokens string(float num) argv_mvdsv = #86; // returns token for the given number @@ -431,7 +431,8 @@ string (string s, float start, float count) substr = #116; string (string s, ...) strzone = #118; void (string s, ...) strunzone = #119; -void() calltimeofday = #231; // force server to call mod function timeofday +void() calltimeofday = #231; // force server to call mod function timeofday + //In order to make it more useful, this header includes a timeofday function which just grabs the values for you to use in your qc code straight after calling calltimeofday. float tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; @@ -440,6 +441,7 @@ float tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; void(float s, float mi, float h, float d, float mo, float y, string tmp_timeofday) timeofday = { tod_sec = s; tod_min = mi; tod_hour = h; tod_day = d; tod_mon = (mo + 1); tod_year = y; }; +void() setpause = #531; //============================================================================ // diff --git a/qw.qc b/qw.qc index b2d4bed9..4cd1d74f 100644 --- a/qw.qc +++ b/qw.qc @@ -496,6 +496,9 @@ float sng_damage; float old_ng_rof; float impulse_queue; float pyro_type; +float ceasefire_type; +float pause_requested_by; +float is_paused; .float teamkills; From 04d1115c897285a0b58413b0c5917c6ecb62e964 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 9 Feb 2019 03:14:10 +0000 Subject: [PATCH 0573/2474] pause with countdown --- admin.qc | 24 ++++++++++++++++++++++- client.qc | 3 +++ mvdsv.qc | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- qw.qc | 7 +++++++ status.qc | 8 ++++++++ 5 files changed, 97 insertions(+), 3 deletions(-) diff --git a/admin.qc b/admin.qc index cfd1055b..85931806 100644 --- a/admin.qc +++ b/admin.qc @@ -175,6 +175,28 @@ void () Admin_CeaseFire = { } }; +void () Admin_Pause = { + if (!is_paused) { + setpause(1); + is_paused = 1; + pause_actor = self.netname; + bprint2(2, pause_actor, " paused the game\n"); + } + else { + pause_actor = self.netname; + if (!unpause_requested) { + bprint2(2, pause_actor, " has requested to unpause the game in 5 seconds\n"); + unpause_requested = 1; + } + else { + bprint2(2, pause_actor, " cancels unpause request\n"); + unpause_requested = 0; + unpause_countdown = 0; + unpause_lastcountnumber = 0; + } + } +} + void (entity p) CheckAutoKick = { local float rnum; local entity te; @@ -233,7 +255,7 @@ void () Admin_Aliases = TeamFortress_Alias("kick", 190, 0); TeamFortress_Alias("ban", 191, 0); TeamFortress_Alias("next", 195, 0); - TeamFortress_Alias("ceasefire", 193, 0); + stuffcmd(self,"alias ceasefire \"cmd ceasefire\"\n"); TeamFortress_Alias("listips", 198, 0); TeamFortress_Alias("clan", 207, 0); TeamFortress_Alias("adminmenu", 239, 0); diff --git a/client.qc b/client.qc index 6ac0fa27..4e71f678 100644 --- a/client.qc +++ b/client.qc @@ -505,6 +505,9 @@ void () DecodeLevelParms = { // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass pyro_type = CF_GetSetting("pyrotype", "pyro_type", "1"); + // ceasefire type - 0: default; 1: pause + ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/mvdsv.qc b/mvdsv.qc index 38e0ef5d..61768563 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -176,6 +176,13 @@ float () UserCmd = Admin_CycleDeal(); return (1); } + else if (argv_mvdsv(0) == "ceasefire") { + if (ceasefire_type) + Admin_Pause(); + else + Admin_CeaseFire(); + return (1); + } else if (argv_mvdsv(0) == "map") { if (self.is_admin) { if (clanbattle == 1 && !(cb_prematch)) { @@ -220,7 +227,7 @@ float () UserCmd = return (1); } } - return 0; + return (0); }; float () ConsoleCmd { @@ -275,4 +282,51 @@ float () ConsoleCmd { return (1); } return 0; -} \ No newline at end of file +} + +void (float duration) GE_PausedTic = { + if (unpause_requested && (unpause_countdown == 0)) { + unpause_countdown = duration + 5; + } + if (unpause_requested) { + if ((duration >= unpause_countdown)) { + is_paused = 0; + unpause_countdown = 0; + unpause_requested = 0; + setpause(0); + } + else { + if (ftos(duration) == ftos(unpause_countdown - 4)) { + if (unpause_lastcountnumber != 4) { + unpause_lastcountnumber = 4; + bprint(2, "Unpausing in 4 seconds\n" ); + } + } + else if (ftos(duration) == ftos(unpause_countdown - 3)) { + if (unpause_lastcountnumber != 3) { + unpause_lastcountnumber = 3; + bprint(2, "Unpausing in 3 seconds\n" ); + } + } + else if (ftos(duration) == ftos(unpause_countdown - 2)) { + if (unpause_lastcountnumber != 2) { + unpause_lastcountnumber = 2; + bprint(2, "Unpausing in 2 seconds\n" ); + } + } + else if (ftos(duration) == ftos(unpause_countdown - 1)) { + if (unpause_lastcountnumber != 1) { + unpause_lastcountnumber = 1; + bprint(2, "Unpausing in 1 second\n" ); + } + } + else if (ftos(duration) == ftos(unpause_countdown)) { + if (unpause_lastcountnumber != 0) { + unpause_lastcountnumber = 0; + bprint(2, "GAME UNPAUSED\n" ); + } + } + + } + } +} \ No newline at end of file diff --git a/qw.qc b/qw.qc index b2d4bed9..249eca55 100644 --- a/qw.qc +++ b/qw.qc @@ -496,6 +496,13 @@ float sng_damage; float old_ng_rof; float impulse_queue; float pyro_type; +float ceasefire_type; +float is_paused; +string pause_actor; +float unpause_requested; +float unpause_countdown; +float unpause_lastcountnumber; + .float teamkills; diff --git a/status.qc b/status.qc index f302702a..448b43a5 100644 --- a/status.qc +++ b/status.qc @@ -561,6 +561,14 @@ void (entity pl, string s1, string s2, string s3) CenterPrint3 = { Status_Print(pl, s1, s2, s3); }; +void (entity pl, string s1, string s2, string s3, string s4) CenterPrint4 = { + Status_Print(pl, s1, s2, s3, s4); +}; + +void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPrint5 = { + Status_Print(pl, s1, s2, s3, s4, s5); +}; + void (entity pl) RefreshStatusBar = { local string pad; local string s1; // will be used for grenade timers From e6cbee3a9fbba1347fbe679c2045fc87db7c079a Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 9 Feb 2019 03:30:57 +0000 Subject: [PATCH 0574/2474] replication ceasefire behaviour, after countdown started it should stop it if used --- admin.qc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/admin.qc b/admin.qc index 85931806..09108172 100644 --- a/admin.qc +++ b/admin.qc @@ -180,9 +180,21 @@ void () Admin_Pause = { setpause(1); is_paused = 1; pause_actor = self.netname; + if (cb_prematch && infokey(world, "status") == "Countdown") { + StopTimer(); + bprint2(2, pause_actor, " stops the countdown\n"); + return; + } bprint2(2, pause_actor, " paused the game\n"); } else { + if (cb_prematch) { + cb_prematch_time = 0; + StartTimer(); + setpause(0); + is_paused = 0; + return; + } pause_actor = self.netname; if (!unpause_requested) { bprint2(2, pause_actor, " has requested to unpause the game in 5 seconds\n"); From 44b606a1923df5f782fd1ca54cfdeea0c104c913 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 10 Feb 2019 23:44:36 +1300 Subject: [PATCH 0575/2474] make spy be able to unfeign with the 'feign' and 'sfeign' commands --- weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index 2ecf1437..9d1052f4 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2649,7 +2649,7 @@ void () W_WeaponFrame = { return; } - if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL && self.impulse != TF_MEDIC_HELPME) + if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL && self.impulse != TF_MEDIC_HELPME && self.impulse != TF_SPY_DIE && self.impulse != TF_SPY_SILENT_DIE) return; if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { From a1b67c7a58fbfd6a18822ab5de5dbb16ae7ac57a Mon Sep 17 00:00:00 2001 From: Leonard Wilson Date: Mon, 11 Feb 2019 04:01:04 +1100 Subject: [PATCH 0576/2474] added hitsounds --- combat.qc | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ weapons.qc | 3 +++ 2 files changed, 82 insertions(+) diff --git a/combat.qc b/combat.qc index 34489ee8..74bcd51c 100644 --- a/combat.qc +++ b/combat.qc @@ -86,6 +86,82 @@ void (entity targ, entity attacker) Killed = { self = oself; }; +void (entity targ, entity attacker, float damage, float T_AttackType) HitSound = { + + if((attacker.classname == "player") || (attacker.classname == "building_sentrygun")){ + + if((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")){ + + local entity trueattacker; + + if (attacker.classname == "building_sentrygun"){ // work out correct attacker + trueattacker = attacker.real_owner; + } + else { + trueattacker = attacker; + } + + if (trueattacker == targ) + { + return; + } + + + local string hitsound; + hitsound = infokey(trueattacker, "hitsound"); + + if(hitsound == "1" || hitsound == "2"){ + + local float crit; + + if((T_AttackType == 0) && (damage >= 80)){ //rocket direct + crit = 1; + } + if ((T_AttackType == 1) && (damage >= 40)){ //ssg meatshot + crit = 1; + } + if ((T_AttackType == 4) && (damage >= 95)){ //grens + crit = 1; + } + if((T_AttackType == 16) && (damage >= 40)){ //pyro rocket direct + crit = 1; + } + + local float sameteam; + + if (attacker.team_no == targ.team_no){ + sameteam = 1; + } + else { + sameteam = 0; + + if(targ.classname == "player"){ //spy disguise check + if(targ.playerclass == 8){ + if (targ.is_undercover == 1){ + sameteam = 1; + } + } + } + } + + if (sameteam == 0) { + if (crit == 1){ + stuffcmd(trueattacker, "play misc/hitsoundcrit.wav\n"); //sounds precached in weapons.qc + } + else { + stuffcmd(trueattacker, "play misc/hitsound.wav\n"); //sounds precached in weapons.qc + } + } + else { + if (hitsound == "2"){ + stuffcmd(trueattacker, "play misc/hitsoundteam.wav\n"); //sounds precached in weapons.qc + } + } + } + } + } +}; + void (entity targ, entity inflictor, entity attacker, float damage) T_Damage = { local vector dir; @@ -255,6 +331,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, } } } + + HitSound(targ, attacker, damage, T_AttackType); + damage_attacker = attacker; if (teamplay & (TEAMPLAY_LESSSCOREHELP | TEAMPLAY_LESSPLAYERSHELP)) diff --git a/weapons.qc b/weapons.qc index 9d1052f4..b34146d6 100644 --- a/weapons.qc +++ b/weapons.qc @@ -142,6 +142,9 @@ void () W_Precache = { precache_sound("weapons/asscan4.wav"); precache_sound("weapons/railgun.wav"); precache_sound("weapons/dartgun.wav"); + precache_sound("misc/hitsound.wav"); + precache_sound("misc/hitsoundcrit.wav"); + precache_sound("misc/hitsoundteam.wav"); }; float () crandom = { From 8917b262c52a02be2b664a0d97c6d169162746cf Mon Sep 17 00:00:00 2001 From: Leonard Wilson Date: Mon, 11 Feb 2019 13:21:07 +1100 Subject: [PATCH 0577/2474] added hitsounds --- combat.qc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/combat.qc b/combat.qc index 74bcd51c..a0e55908 100644 --- a/combat.qc +++ b/combat.qc @@ -86,7 +86,7 @@ void (entity targ, entity attacker) Killed = { self = oself; }; -void (entity targ, entity attacker, float damage, float T_AttackType) HitSound = { +void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { if((attacker.classname == "player") || (attacker.classname == "building_sentrygun")){ @@ -114,16 +114,16 @@ void (entity targ, entity attacker, float damage, float T_AttackType) HitSound = local float crit; - if((T_AttackType == 0) && (damage >= 80)){ //rocket direct + if((inflictor.weapon == DMSG_ROCKETL) && (damage >= 80)){ crit = 1; } - if ((T_AttackType == 1) && (damage >= 40)){ //ssg meatshot + if ((inflictor.weapon == DMSG_SSHOTGUN) && (damage >= 40)){ crit = 1; } - if ((T_AttackType == 4) && (damage >= 95)){ //grens + if ((inflictor.weapon == DMSG_GRENADEL) && (damage >= 85)){ crit = 1; } - if((T_AttackType == 16) && (damage >= 40)){ //pyro rocket direct + if((inflictor.weapon == DMSG_INCENDIARY) && (damage >= 40)){ crit = 1; } @@ -135,9 +135,12 @@ void (entity targ, entity attacker, float damage, float T_AttackType) HitSound = else { sameteam = 0; - if(targ.classname == "player"){ //spy disguise check - if(targ.playerclass == 8){ - if (targ.is_undercover == 1){ + if(targ.classname == "player"){ + if(targ.playerclass == PC_SPY){ + if (targ.is_feigning){ + return; + } + if (targ.is_undercover){ sameteam = 1; } } @@ -332,7 +335,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, } } - HitSound(targ, attacker, damage, T_AttackType); + HitSound(targ, inflictor, attacker, damage); damage_attacker = attacker; From 149064e27d720e6b170ec8fb570394a076729eed Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Mon, 11 Feb 2019 11:09:46 +0000 Subject: [PATCH 0578/2474] starting to port quadmode --- client.qc | 2 + commands.qc | 25 +++ quadmode.qc | 431 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 458 insertions(+) create mode 100644 quadmode.qc diff --git a/client.qc b/client.qc index 6ac0fa27..1944f00f 100644 --- a/client.qc +++ b/client.qc @@ -256,6 +256,8 @@ void () DecodeLevelParms = { autoteam_time = 30; clanbattle = CF_GetSetting("c", "clan", "off"); + quadmode = CF_GetSetting("quadmode", "quadmode", "off"); + if (clanbattle) { localcmd ("serverinfo status Standby\n"); diff --git a/commands.qc b/commands.qc index f856a16f..836f2fe0 100644 --- a/commands.qc +++ b/commands.qc @@ -1,3 +1,28 @@ +void () QuadMode = +{ + local string st; + + st = infokey (world, "quadmode"); + if ((st == "on")) + { + st = "off"; + localcmd ("localinfo clan off\n"); + localcmd ("localinfo quadmode off\n"); + localcmd ("rounds off"); + } + else + { + st = "on"; + localcmd ("localinfo clan on\n"); + localcmd ("localinfo quadmode on\n"); + localcmd ("localinfo rounds 2\n"); + localcmd ("timelimit 0\n"); + localcmd ("localinfo round_time 10\n"); + bprint (2, "Map Restart needed to take affect!\n"); + } + bprint3 (2, "Quad Mode set to ", st, "\n"); +}; + void () ClanMode = { local string st; diff --git a/quadmode.qc b/quadmode.qc new file mode 100644 index 00000000..ba228ef8 --- /dev/null +++ b/quadmode.qc @@ -0,0 +1,431 @@ +//=-=-=-=-= + +float () CheckWinningTeam = { + local float win_score = 0; + local float winning_team = 0; + + if (team1score > win_score) { + win_score = team1score; + winning_team = 1; + } + + if (team2score > win_score) { + win_score = team2score; + winning_team = 2; + } + else if (team2score == win_score) { + winning_team = 0; + } + + if (team3score > win_score) { + win_score = team3score; + winning_team = 3; + } + else if (team3score == win_score) { + winning_team = 0; + } + + if (team4score > win_score) { + win_score = team4score; + winning_team = 4; + } + else if (team4score == win_score) { + winning_team = 0; + } + return winning_team; +}; + +void () QuadRoundOver = { + local string st; + + round_over = 2; + + self.think = StartQuadRound; + self.nextthink = (time + 0.5); +}; + +void () QuadRoundThink = { + local string tmp; + local float fl; + + if (rounds < 2) { + if (CheckWinningTeam() != 0) { + if (quad_winner != CheckWinningTeam()) { + quad_winner = CheckWinningTeam(); + self.think = QuadRoundOver; + self.nextthink = (time + 0.1); + return; + } + } + } + + if (self.cnt == -1) + return; + + + if ( self.cnt == stof(infokey(world, "round_time")) - 1 && self.cnt2 == 59 ) { + localcmd("serverinfo status \""); + tmp = ftos (self.cnt + 1); + localcmd(tmp); + localcmd(" min left\"\n"); + } + + if (self.cnt2 == 1) { + localcmd("serverinfo status \""); + tmp = ftos (self.cnt); + localcmd(tmp); + localcmd(" min left\"\n"); + } + + if (self.cnt2 == -1) { + self.cnt2 = 59; + self.cnt = (self.cnt - 1); + } + + if (!cease_fire) + self.cnt2 = (self.cnt2 - 1); + + localcmd(sprintf("timelimit %s\n", ftos(stof(infokey(world, "round_time"))))); + if (!self.cnt2) { + if ((self.cnt == 1) || (self.cnt == 5)) { + tmp = ftos (self.cnt); + bprint3(2, "", tmp, "β€˜ minute"); + if (self.cnt != 1) + bprint(2, "s"); + bprint(2, " remaining\n"); + } + if (!self.cnt) { + if (rounds > 1) + bprint(2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); + +// lightstyle (0, "e"); + localcmd("serverinfo status Countdown\n"); + + self.think = QuadRoundOver; + self.nextthink = (time + 0.1); + return; + } + } + if (!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= enter))) { + fl = ceil (self.cnt2); + if (!(fl - self.cnt2)) { + tmp = ftos(self.cnt2); + bprint3(2, "", tmp, "β€˜ second"); + if ((self.cnt2 != 1)) + bprint(2, "s"); + bprint(2, " remaining\n"); + } + } + gametime++; + self.nextthink = (time + 1); +}; + +void () QuadRoundBegin = { + local entity te; + local entity oldself; + local string st; + local string tmp; + local float bomber; + local float counter; + + te = find(world, classname, "func_breakable"); + while (te) { + setmodel(te, te.mdl); + te.solid = 4; + te = find(te, classname, "func_breakable"); + } + te = find(world, classname, "player"); + while (te != world) { + oldself = self; + self = te; + if (self.hook_out) { + Reset_Grapple(self.hook); + Attack_Finished(0.75); + self.hook_out = 1; + } + TeamFortress_RemoveTimers(); + setspawnparms(self); + PutClientInServer(); + self = oldself; + te = find (te, classname, "player"); + } +// lightstyle (0, "m"); + + localcmd("serverinfo status \""); + + bprint(2, "QUAD ROUND BEGINS NOW\n"); + round_active = 1; + round_over = 0; + if (speedcap) { + self.invisible_time = time; + } + if (!self.cnt) { + self.cnt = stof(infokey (world, "round_time")) - 1; + self.cnt2 = 60; + } + else { + counter = floor(self.cnt); + if (counter < self.cnt) + self.cnt2 = ((self.cnt - counter) * 60); + else + self.cnt2 = 60; + if (self.cnt2 == 60) + self.cnt = (self.cnt - 1); + else + self.cnt = counter; + } + self.think = QuadRoundThink; + self.nextthink = (time + 0.1); +}; + +void () QuadRoundInit = { + local string num; + local float fl; + local entity p; + + fl = TeamFortress_NoTeams(); + if ((fl < 1) || cease_fire) { + self.nextthink = (time + 2); + if (self.cnt2 <= 5) + self.cnt2 = 10; + return; + } + self.cnt2 = (self.cnt2 - 1); + if (self.cnt2 == 2) + round_over = 2; + if (self.cnt2 == 1) { + p = find(world, classname, "player"); + while (p != world) + { + if (p.netname != "") + { + p.takedamage = 0; + p.solid = 0; + p.movetype = 0; + p.modelindex = 0; + p.model = string_null; + } + p = find(p, classname, "player"); + } + } + else { + if (!self.cnt2) { + self.nextthink = (time + 0.1); + self.think = QuadRoundBegin; + p = find(world, classname, "player"); + while (p != world) { + if (p.netname != "") { + p.takedamage = 2; + p.solid = 3; + p.movetype = 3; + } + p = find(p, classname, "player"); + } + return; + } + } + if (self.cnt2 <= 5) { + num = ftos (self.cnt2); + p = find (world, classname, "player"); + while (p != world) { + if (p.netname != "") { + CenterPrint3(p, "Round begins in: ", num, " second(s).\n"); + cease_fire = 0; + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find (p, classname, "player"); + } + } + self.nextthink = (time + 1); +}; + +void () StartQuadRound = +{ + local string st; + local float fl; + local entity te; + local entity te2; + local entity oldself; + local entity gren; + local entity p; + + + if (rounds == 1) { + quad_winner = CheckWinningTeam(); + if (quad_winner == 0) + bprint (2, "Round Drawn!\n"); + else if (quad_winner == 1) + bprint(2, "Blue Team Wins!\n"); + else if (quad_winner == 2) + bprint(2, "Red Team Wins!\n"); + else if (quad_winner == 3) + bprint(2, "Yellow Team Wins!\n"); + else if (quad_winner == 4) + bprint(2, "Green Team Wins!\n"); + p = find (world, classname, "player"); + while (p != world) { + if (p.netname != "") { + p.takedamage = 0; + p.solid = 0; + p.movetype = 0; + p.modelindex = 0; + p.model = string_null; + } + p = find(p, classname, "player"); + } + bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); + localcmd("stop\n"); + return; + } + if (rounds > 1) + rounds = (rounds - 1); + if (intermission_running) + return; + + tfs_winner = 0; + round_over = 1; + + te = find(world, classname, "info_tfgoal"); + while (te != world) { + if (te.netname == "blue_det" || te.netname == "red_det") { + te2 = self; + self = te; + self.goal_activation = 2; + self.solid = 1; + self.goal_state = 2; + self = te2; + } + te = find(te, classname, "info_tfgoal"); + } + te = find(world, classname, "door"); + while (te != world) { + te2 = self; + self = te; + door_go_down(); + self.think = LinkDoors; + self = te2; + te = find (te, classname, "door"); + } + + + if (round_active) + { + te = find (world, classname, "player"); + while (te != world) { + oldself = self; + self = te; + if (self.hook_out) { + Reset_Grapple (self.hook); + Attack_Finished (0.75); + self.hook_out = 1; + } + self.menu_count = 30; + self.current_menu = 1; + TeamFortress_ThrowGrenade (); + TeamFortress_RemoveTimers (); + if (self.playerclass == 9) { + Engineer_RemoveBuildings (self); + } + self = oldself; + te = find (te, classname, "player"); + } + round_active = 0; + } + gren = find (world, classname, "grenade"); + while (gren) + { + gren.think = SUB_Remove; + gren.nextthink = (time + 0.1); + gren = find (gren, classname, "grenade"); + } + gren = find (world, classname, "grentimer"); + while (gren) + { + gren.think = SUB_Remove; + gren.nextthink = (time + 0.1); + gren = find (gren, classname, "grentimer"); + } + te = find (world, classname, "detpack"); + while (te) + { + if ((te.weaponmode == 1)) + { + TeamFortress_SetSpeed (te.enemy); + dremove (te.oldenemy); + dremove (te.observer_list); + } + dremove (te.linked_list); + dremove (te); + te = find (te, classname, "detpack"); + } + te = find (world, classname, "item_tfgoal"); + while (te) + { + if ((te.origin != te.oldorigin)) + { + oldself = spawn (); + oldself.enemy = te; + oldself.weapon = 3; + oldself.nextthink = (time + 0.2); + oldself.think = ReturnItem; + } + te = find (te, classname, "item_tfgoal"); + } + te = find (world, classname, "item_ball"); + while (te) + { + if ((te.origin != te.oldorigin)) + { + te.nextthink = (time + 0.3); + te.think = ball_reset; + } + te = find (te, classname, "item_ball"); + } + te = find (world, classname, "ammobox"); + while (te) + { + te.nextthink = (time + 0.3); + te.think = TeamFortress_AmmoboxThink; + te = find (te, classname, "ammobox"); + } + te = find (world, classname, "round"); + st = infokey (world, "count"); + fl = stof (st); + if ((fl < 3) || (fl > 20)) + { + fl = enter; + } + te.cnt2 = 10; + st = infokey (world, "round_time"); + te.cnt = stof (st); + quad_winner = CheckWinningTeam(); + if (rounds > 1) { +// lightstyle (0, "e"); + localcmd("serverinfo status Countdown\n"); + te.think = QuadRoundBegin; + te.nextthink = (time + 0.01); + } + else { +// lightstyle (0, "e"); + localcmd("serverinfo status Countdown\n"); + te.think = QuadRoundInit; + te.nextthink = (time + 1); + } +}; + +void () EndRound = { + if (infokey(world, "quadmode") == "on") { + if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { + if (rounds > 1) { + bprint (2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); +// lightstyle (0, "e"); + localcmd("serverinfo status Countdown\n"); + self.think = QuadRoundOver; + self.nextthink = (time + 0.1); + } + else if (rounds == 1) { + StartQuadRound(); + } + } + } +}; From 9c40fd08eb0a535b3bf00d1dc66db1b95944cd1f Mon Sep 17 00:00:00 2001 From: up2h Date: Mon, 11 Feb 2019 19:03:06 -0200 Subject: [PATCH 0579/2474] getting the clock right for quadmode --- clan.qc | 212 +++++++++++++++++++++++++++++++++++++++++++++++----- client.qc | 16 +++- commands.qc | 2 +- mvdsv.qc | 5 ++ progs.src | 1 + quadmode.qc | 170 ++++++++++++++++------------------------- qw.qc | 13 ++++ weapons.qc | 3 + 8 files changed, 296 insertions(+), 126 deletions(-) diff --git a/clan.qc b/clan.qc index 96349cb1..c75c9628 100644 --- a/clan.qc +++ b/clan.qc @@ -1,3 +1,5 @@ +void () ReturnItem; + void () MatchThink = { local string tmp; @@ -90,7 +92,7 @@ void () StartMatch = self.frags = 0; self.real_frags = 0; setspawnparms(self); - if (infokey(world, "quadmode") != "on") + if (!quadmode) PutClientInServer(); self = oldself; te = find(te, classname, "player"); @@ -122,7 +124,7 @@ void () StartMatch = st = ftos(te.cnt); localcmd(st); localcmd(" min left\"\n"); - if (infokey(world, "quadmode") != "on") { + if (!quadmode) { te.think = MatchThink; te.nextthink = (time + 1); } @@ -143,7 +145,11 @@ void () StartMatch = localcmd(st); localcmd("\n"); - st = infokey(world, "quadmode"); + if (quadmode) { + if (rounds) { + StartQuadRound(); + } + } }; void () PreMatch_Think = { @@ -166,8 +172,7 @@ void () PreMatch_Think = { p = find(p, classname, "player"); } } - else - { + else { if (!self.cnt2) { self.nextthink = (time + 0.1); self.think = SUB_Remove; @@ -180,7 +185,10 @@ void () PreMatch_Think = { } p = find(p, classname, "player"); } - StartMatch(); + if (!quadmode) + StartMatch(); + else + StartQuadRound(); return; } } @@ -196,7 +204,6 @@ void () PreMatch_Think = { if (self.cnt2 <= 10) { if (self.cnt2 == 10) { lightstyle(0, "e"); - localcmd("serverinfo status Countdown\n"); if (stof(infokey(world, "demo_auto_left")) > 0) { if (infokey(world, "serverdemo") == "on") { @@ -279,15 +286,6 @@ void () StartTimer = } return; } - if (infokey(world, "status") == "Countdown") { - if (self != world) { - sprint(self, 2, "Countdown in progress....\n"); - } - else { - dprint("Countdown in progress....\n"); - } - return; - } timer = find(world, classname, "prematch"); while (timer != world) { dremove(timer); @@ -329,7 +327,6 @@ void () StartTimer = localcmd("\"\n"); } } - localcmd("serverinfo status Countdown\n"); p = find(world, classname, "player"); while (p != world) { if (p.netname != "") { @@ -757,3 +754,184 @@ void () TeamFortress_ShowIDs = { if (!got_one) sprint(self, PRINT_HIGH, "None\n"); }; + +void () ResetBreakAndReady = { + local entity te; + te = find (world, classname, "player"); + while (te != world) { + te.bvote = 0; + te.is_ready = 0; + v_break = 0; + v_ready = 0; + te = find (te, classname, "player"); + } +} + +void () PlayerBreak = +{ + local float f1; + local float f2; + local string tmp; + + if (intermission_running) { + return; + } + if (self.classname != "player") { + return; + } + if (infokey(world, "quadmode") == "on" && (infokey (world, "status") == "Countdown" || infokey(world, "status") == "Standby")) { + sprint(self, 2, "You cannot break at this time.\n"); + return; + } + tmp = infokey(world, "votetime"); + f1 = (stof(tmp) * 60); + if (f1 > time) { + sprint(self, 2, "You cannot break at this time.\n"); + return; + } + if (self.allowvote > time) { + return; + } + self.allowvote = (time + 3); + if (self.bvote) { + bprint2(2, self.netname, " \swithdraws\s his/her vote\n"); + self.bvote = 0; + v_break = (v_break - 1); + return; + } + if (quadmode) { + bprint2(3, self.netname, " votes for ending the round\n"); + } + else if (clanbattle) { + bprint2(3, self.netname, " votes for stopping the match\n"); + } + else { + bprint2(3, self.netname, " votes to end the current map\n"); + } + self.bvote = 1; + v_break = (v_break + 1); + f1 = TeamFortress_GetNoPlayers(); + f2 = (floor(f1 / 2) + 1); + if (v_break >= f2) { + if (quadmode) { + bprint(2, "Round ended by majority vote\n"); + ResetBreakAndReady(); + EndQuadRound(); + return; + } + if (clanbattle) { + bprint(2, "Match stopped by majority vote\n"); + } + else { + bprint(2, "Map ended by majority vote\n"); + } + StopTimer(); + NextLevel (); + return; + } + if (v_break != 0) { + f1 = (f2 - v_break); + tmp = ftos (f1); + bprint3(2, "\s", tmp, "\s more vote"); + if (f1 > 1) { + bprint(2, "s"); + } + bprint(2, " needed\n"); + } +}; + +void () PlayerReady = +{ + local float f1; + local string tmp; + local entity te; + + if (quadmode && (infokey (world, "status") == "Countdown")) { + sprint (self, 2, "Use 'break' to stop the countdown.\n"); + return; + } + if (quadmode && (infokey (world, "status") != "Standby")) { + sprint (self, 2, "You cannot do this after the match has started.\n"); + return; + } + if (self.team_no == 0) { + sprint (self, 2, "You must join a team first.\n"); + return; + } + if (self.playerclass == 0) { + sprint (self, 2, "You must choose a class first.\n"); + return; + } + if (intermission_running) + { + return; + } + if ((self.classname != "player")) + { + return; + } + tmp = infokey (world, "votetime"); + f1 = (stof (tmp) * 60); + if (f1 > time) { + sprint (self, 2, "You cannot be ready at this time.\n"); + return; + } + if (self.allowvote > time) { + return; + } + self.allowvote = (time + 3); + if (self.is_ready) { + bprint2 (2, self.netname, " is NOT ready anymore\n "); + self.is_ready = 0; + v_ready = (v_ready - 1); + return; + } + self.is_ready = 1; + v_ready = v_ready + 1; + bprint2 (3, self.netname, " is ready to start the match\n"); + f1 = TeamFortress_GetNoPlayers (); + if (v_ready == f1 ) { + bprint (2, "All players ready, starting match\n"); + cb_prematch_time = 0; + ResetBreakAndReady(); + StartTimer (); + return; + } + if (v_ready != 0) { + local string players_not_ready = "Not ready: "; + local float first = 1; + te = find (world, classname, "player"); + while (te != world) { + if (te.is_ready == 0) { + if (!first) + players_not_ready = strcat(players_not_ready, ", "); + else + first = 0; + players_not_ready = strcat(players_not_ready, te.netname); + } + te = find (te, classname, "player"); + } + players_not_ready = strcat(players_not_ready, "\n"); + bprint(1, players_not_ready); + te = find (world, classname, "player"); + while (te != world) { + if (te.is_ready == 0) + sprint (te, 2, "If you are ready, type 'ready' in the console\n"); + te = find (te, classname, "player"); + } + return; + } +}; + +void () RemoveVotes = { + if (self.bvote) { + bprint2(2, self.netname, " \swithdraws\s his/her vote\n"); + self.bvote = 0; + v_break = (v_break - 1); + } + if (self.is_ready) { + bprint2(2, self.netname, " is NOT ready anymore\n "); + self.is_ready = 0; + v_ready = (v_ready - 1); + } +}; \ No newline at end of file diff --git a/client.qc b/client.qc index 1944f00f..6f8b6be9 100644 --- a/client.qc +++ b/client.qc @@ -52,6 +52,7 @@ void () CTF_FlagCheck; void (entity pl) Sniper_ZoomReset; void () StartTimer; void () StopTimer; +void () StartQuadRound; void (string cl_pwd) Admin_Check; void () Admin_Aliases; @@ -257,7 +258,13 @@ void () DecodeLevelParms = { clanbattle = CF_GetSetting("c", "clan", "off"); quadmode = CF_GetSetting("quadmode", "quadmode", "off"); - + + rounds = CF_GetSetting("rounds","rounds","on"); + if (!rounds) + rounds = -1; + else if (rounds > 0) + rounds = rounds + 1; + if (clanbattle) { localcmd ("serverinfo status Standby\n"); @@ -301,6 +308,13 @@ void () DecodeLevelParms = { clanbattle = FALSE; localcmd ("serverinfo status Normal\n"); } + if (rounds) { + st = infokey (world, "round_time"); + te = spawn (); + te.owner = world; + te.classname = "round"; + te.cnt = stof(st); + } // automatically assign team [off] fl = CF_GetSetting("a", "autoteam", "off"); diff --git a/commands.qc b/commands.qc index 836f2fe0..703ad2c7 100644 --- a/commands.qc +++ b/commands.qc @@ -8,7 +8,7 @@ void () QuadMode = st = "off"; localcmd ("localinfo clan off\n"); localcmd ("localinfo quadmode off\n"); - localcmd ("rounds off"); + localcmd ("localinfo rounds 0"); } else { diff --git a/mvdsv.qc b/mvdsv.qc index 38e0ef5d..a2730b59 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -274,5 +274,10 @@ float () ConsoleCmd { ClanMode(); return (1); } + else if (argv_mvdsv (0) == "quadmode") + { + QuadMode (); + return (1); + } return 0; } \ No newline at end of file diff --git a/progs.src b/progs.src index c6f68aff..b9f9f7b0 100644 --- a/progs.src +++ b/progs.src @@ -37,6 +37,7 @@ spy.qc engineer.qc camera.qc clan.qc +quadmode.qc tfort.qc tforthlp.qc tfortmap.qc diff --git a/quadmode.qc b/quadmode.qc index ba228ef8..1e656deb 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -36,10 +36,7 @@ float () CheckWinningTeam = { }; void () QuadRoundOver = { - local string st; - round_over = 2; - self.think = StartQuadRound; self.nextthink = (time + 0.5); }; @@ -60,8 +57,7 @@ void () QuadRoundThink = { } if (self.cnt == -1) - return; - + return; if ( self.cnt == stof(infokey(world, "round_time")) - 1 && self.cnt2 == 59 ) { localcmd("serverinfo status \""); @@ -84,12 +80,11 @@ void () QuadRoundThink = { if (!cease_fire) self.cnt2 = (self.cnt2 - 1); - - localcmd(sprintf("timelimit %s\n", ftos(stof(infokey(world, "round_time"))))); + if (!self.cnt2) { if ((self.cnt == 1) || (self.cnt == 5)) { tmp = ftos (self.cnt); - bprint3(2, "", tmp, "β€˜ minute"); + bprint3(2, "\s[\s", tmp, "\s]\s minute"); if (self.cnt != 1) bprint(2, "s"); bprint(2, " remaining\n"); @@ -99,18 +94,17 @@ void () QuadRoundThink = { bprint(2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); // lightstyle (0, "e"); - localcmd("serverinfo status Countdown\n"); self.think = QuadRoundOver; self.nextthink = (time + 0.1); return; } } - if (!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= enter))) { + if (!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= 10))) { fl = ceil (self.cnt2); if (!(fl - self.cnt2)) { tmp = ftos(self.cnt2); - bprint3(2, "", tmp, "β€˜ second"); + bprint3(2, "\s[\s", tmp, "\s]\s second"); if ((self.cnt2 != 1)) bprint(2, "s"); bprint(2, " remaining\n"); @@ -121,13 +115,11 @@ void () QuadRoundThink = { }; void () QuadRoundBegin = { + local entity te; local entity oldself; - local string st; - local string tmp; - local float bomber; local float counter; - + localcmd(strcat(strcat("timelimit ", ftos(stof(infokey(world, "round_time")))), "\n")); te = find(world, classname, "func_breakable"); while (te) { setmodel(te, te.mdl); @@ -138,11 +130,6 @@ void () QuadRoundBegin = { while (te != world) { oldself = self; self = te; - if (self.hook_out) { - Reset_Grapple(self.hook); - Attack_Finished(0.75); - self.hook_out = 1; - } TeamFortress_RemoveTimers(); setspawnparms(self); PutClientInServer(); @@ -151,14 +138,9 @@ void () QuadRoundBegin = { } // lightstyle (0, "m"); - localcmd("serverinfo status \""); - bprint(2, "QUAD ROUND BEGINS NOW\n"); - round_active = 1; + round_active = 1; round_over = 0; - if (speedcap) { - self.invisible_time = time; - } if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; self.cnt2 = 60; @@ -174,17 +156,20 @@ void () QuadRoundBegin = { else self.cnt = counter; } + self.cnt2 = self.cnt2 + 1; + localcmd("serverinfo status \""); + local string tmp = ftos (self.cnt + 1); + localcmd(tmp); + localcmd(" min left\"\n"); self.think = QuadRoundThink; - self.nextthink = (time + 0.1); + self.nextthink = (time + 0.001); }; void () QuadRoundInit = { local string num; - local float fl; local entity p; - fl = TeamFortress_NoTeams(); - if ((fl < 1) || cease_fire) { + if ((number_of_teams < 1) || cease_fire) { self.nextthink = (time + 2); if (self.cnt2 <= 5) self.cnt2 = 10; @@ -195,10 +180,8 @@ void () QuadRoundInit = { round_over = 2; if (self.cnt2 == 1) { p = find(world, classname, "player"); - while (p != world) - { - if (p.netname != "") - { + while (p != world) { + if (p.netname != "") { p.takedamage = 0; p.solid = 0; p.movetype = 0; @@ -225,7 +208,7 @@ void () QuadRoundInit = { } } if (self.cnt2 <= 5) { - num = ftos (self.cnt2); + num = ftos(self.cnt2); p = find (world, classname, "player"); while (p != world) { if (p.netname != "") { @@ -233,7 +216,7 @@ void () QuadRoundInit = { cease_fire = 0; stuffcmd(p, "play buttons/switch04.wav\n"); } - p = find (p, classname, "player"); + p = find(p, classname, "player"); } } self.nextthink = (time + 1); @@ -249,6 +232,9 @@ void () StartQuadRound = local entity gren; local entity p; + lightstyle(0, "m"); + cb_prematch = 0; + cease_fire = 0; if (rounds == 1) { quad_winner = CheckWinningTeam(); @@ -282,7 +268,6 @@ void () StartQuadRound = if (intermission_running) return; - tfs_winner = 0; round_over = 1; te = find(world, classname, "info_tfgoal"); @@ -304,124 +289,95 @@ void () StartQuadRound = door_go_down(); self.think = LinkDoors; self = te2; - te = find (te, classname, "door"); + te = find(te, classname, "door"); } - if (round_active) - { - te = find (world, classname, "player"); + if (round_active) { + te = find(world, classname, "player"); while (te != world) { oldself = self; self = te; - if (self.hook_out) { - Reset_Grapple (self.hook); - Attack_Finished (0.75); - self.hook_out = 1; - } self.menu_count = 30; self.current_menu = 1; - TeamFortress_ThrowGrenade (); - TeamFortress_RemoveTimers (); + TeamFortress_ThrowGrenade(); + TeamFortress_RemoveTimers(); if (self.playerclass == 9) { - Engineer_RemoveBuildings (self); + Engineer_RemoveBuildings(self); } self = oldself; te = find (te, classname, "player"); } round_active = 0; } - gren = find (world, classname, "grenade"); - while (gren) - { + gren = find(world, classname, "grenade"); + while (gren) { gren.think = SUB_Remove; gren.nextthink = (time + 0.1); - gren = find (gren, classname, "grenade"); + gren = find(gren, classname, "grenade"); } - gren = find (world, classname, "grentimer"); - while (gren) - { + gren = find(world, classname, "grentimer"); + while (gren) { gren.think = SUB_Remove; gren.nextthink = (time + 0.1); - gren = find (gren, classname, "grentimer"); + gren = find(gren, classname, "grentimer"); } - te = find (world, classname, "detpack"); - while (te) - { - if ((te.weaponmode == 1)) - { + te = find(world, classname, "detpack"); + while (te){ + if (te.weaponmode == 1) { TeamFortress_SetSpeed (te.enemy); - dremove (te.oldenemy); - dremove (te.observer_list); + dremove(te.oldenemy); + dremove(te.observer_list); } - dremove (te.linked_list); - dremove (te); + dremove(te.linked_list); + dremove(te); te = find (te, classname, "detpack"); } - te = find (world, classname, "item_tfgoal"); - while (te) - { - if ((te.origin != te.oldorigin)) - { - oldself = spawn (); + te = find(world, classname, "item_tfgoal"); + while (te) { + bprint(2,"Goal Name: "); + bprint(2,te.netname); + bprint(2, "\n"); + if (te.origin != te.oldorigin) { + oldself = spawn(); oldself.enemy = te; oldself.weapon = 3; oldself.nextthink = (time + 0.2); oldself.think = ReturnItem; } - te = find (te, classname, "item_tfgoal"); - } - te = find (world, classname, "item_ball"); - while (te) - { - if ((te.origin != te.oldorigin)) - { - te.nextthink = (time + 0.3); - te.think = ball_reset; - } - te = find (te, classname, "item_ball"); - } - te = find (world, classname, "ammobox"); - while (te) - { - te.nextthink = (time + 0.3); - te.think = TeamFortress_AmmoboxThink; - te = find (te, classname, "ammobox"); - } - te = find (world, classname, "round"); - st = infokey (world, "count"); - fl = stof (st); - if ((fl < 3) || (fl > 20)) - { - fl = enter; + te = find(te, classname, "item_tfgoal"); + } + te = find(world, classname, "round"); + st = infokey(world, "count"); + fl = stof(st); + if ((fl < 3) || (fl > 20)) { + fl = 10; } te.cnt2 = 10; st = infokey (world, "round_time"); te.cnt = stof (st); - quad_winner = CheckWinningTeam(); + quad_winner = CheckWinningTeam(); + bprint(2, ftos(rounds)); + bprint(2, "\n"); + localcmd("serverinfo status Standby\n"); if (rounds > 1) { -// lightstyle (0, "e"); - localcmd("serverinfo status Countdown\n"); te.think = QuadRoundBegin; te.nextthink = (time + 0.01); } else { -// lightstyle (0, "e"); - localcmd("serverinfo status Countdown\n"); te.think = QuadRoundInit; te.nextthink = (time + 1); } }; -void () EndRound = { +void () EndQuadRound = { if (infokey(world, "quadmode") == "on") { if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { if (rounds > 1) { bprint (2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); -// lightstyle (0, "e"); - localcmd("serverinfo status Countdown\n"); - self.think = QuadRoundOver; - self.nextthink = (time + 0.1); + lightstyle (0, "e"); + self.think = QuadRoundOver; + self.nextthink = (time + 0.1); } else if (rounds == 1) { StartQuadRound(); diff --git a/qw.qc b/qw.qc index b2d4bed9..ee1bb69c 100644 --- a/qw.qc +++ b/qw.qc @@ -427,12 +427,21 @@ float clan_scores_dumped; float cb_prematch; float cb_prematch_time; float cb_ceasefire_time; +float v_break; +float v_ready; +.float allowvote; float game_locked; float team1frags; float team2frags; float team3frags; float team4frags; float last_id; +float quadmode; +float quad_winner; +float rounds; +float round_active; +float round_over; +float gametime; .float tf_id; @@ -502,6 +511,10 @@ float pyro_type; float autokick_time; float autokick_kills; +.float vote; +.float bvote; +.float is_ready; + .float is_admin; .float admin_mode; .entity admin_use; diff --git a/weapons.qc b/weapons.qc index 2ecf1437..25bdfe17 100644 --- a/weapons.qc +++ b/weapons.qc @@ -106,6 +106,9 @@ void () TranquiliserTimer; void () TeamFortress_CTF_FlagInfo; void () ClanMode; +void () QuadMode; +void () EndQuadRound; +void () PlayerReady; void () W_Precache = { precache_sound("weapons/r_exp3.wav"); From 75d49eca8b133248d747ef2bd63993c132e40d20 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Tue, 12 Feb 2019 10:26:46 +1100 Subject: [PATCH 0580/2474] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4c1109ba..dd1e362b 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsounds 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. * Increased nail velocity. Disable with `localinfo old_ng_velocity on`. From dad46b04ddd1bc467d4e9bb13af8a3245c1e9fba Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Tue, 12 Feb 2019 12:19:30 +1100 Subject: [PATCH 0581/2474] fix for engineer emp not damaging players when something near them is emp'd first --- engineer.qc | 3 ++- qw.qc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/engineer.qc b/engineer.qc index ac5b92fb..7e8a72d0 100644 --- a/engineer.qc +++ b/engineer.qc @@ -159,6 +159,7 @@ void () EMPGrenadeExplode = { te = findradius(self.origin, 240); while (te) { + te.chain2 = te.chain; if ((te.touch == ammo_touch) || (te.touch == weapon_touch)) { if (te.classname != "item_spikes") { te.solid = SOLID_NOT; @@ -235,7 +236,7 @@ void () EMPGrenadeExplode = { } } } - te = te.chain; + te = te.chain2; } dremove(self); }; diff --git a/qw.qc b/qw.qc index b2d4bed9..3c7f8de7 100644 --- a/qw.qc +++ b/qw.qc @@ -527,6 +527,7 @@ float intermission_exittime; .float max_grenades_1; .float max_grenades_2; +.entity chain2; // allows for nesting of findradius (use in EMPGrenadeExplode) //============================================================================ From 63873ccdc607dbfe786ac47f94e313e507dbbf7a Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 13 Feb 2019 23:05:59 +1100 Subject: [PATCH 0582/2474] fix for cuss sometimes not working due to medic immunity exiting function --- scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scout.qc b/scout.qc index 4a796bc5..09c26c39 100644 --- a/scout.qc +++ b/scout.qc @@ -560,7 +560,7 @@ void (entity inflictor, entity attacker, float bounce, head.flags = head.flags - FL_ONGROUND; } else { if (medicnocuss && head.playerclass == 5) { - return; + continue; } te = find(world, classname, "timer"); From 38dcef91a45086f7bfc01ea65a98c1a5f1f4ed62 Mon Sep 17 00:00:00 2001 From: up2h Date: Wed, 13 Feb 2019 16:49:37 -0200 Subject: [PATCH 0583/2474] now flag returns correctly after rounds, players can't move between rounds --- quadmode.qc | 74 +++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/quadmode.qc b/quadmode.qc index 1e656deb..e3304ecd 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -126,10 +126,15 @@ void () QuadRoundBegin = { te.solid = 4; te = find(te, classname, "func_breakable"); } + cb_prematch = 0; + te = find(world, classname, "player"); while (te != world) { oldself = self; self = te; + self.takedamage = 2; + self.solid = 3; + self.movetype = 3; TeamFortress_RemoveTimers(); setspawnparms(self); PutClientInServer(); @@ -178,19 +183,6 @@ void () QuadRoundInit = { self.cnt2 = (self.cnt2 - 1); if (self.cnt2 == 2) round_over = 2; - if (self.cnt2 == 1) { - p = find(world, classname, "player"); - while (p != world) { - if (p.netname != "") { - p.takedamage = 0; - p.solid = 0; - p.movetype = 0; - p.modelindex = 0; - p.model = string_null; - } - p = find(p, classname, "player"); - } - } else { if (!self.cnt2) { self.nextthink = (time + 0.1); @@ -233,9 +225,21 @@ void () StartQuadRound = local entity p; lightstyle(0, "m"); - cb_prematch = 0; + cb_prematch = 1; cease_fire = 0; + p = find(world, classname, "player"); + while (p != world) { + if (p.netname != "") { + p.takedamage = 0; + p.solid = 0; + p.movetype = 0; + p.modelindex = 0; + p.model = string_null; + } + p = find(p, classname, "player"); + } + if (rounds == 1) { quad_winner = CheckWinningTeam(); if (quad_winner == 0) @@ -270,18 +274,6 @@ void () StartQuadRound = round_over = 1; - te = find(world, classname, "info_tfgoal"); - while (te != world) { - if (te.netname == "blue_det" || te.netname == "red_det") { - te2 = self; - self = te; - self.goal_activation = 2; - self.solid = 1; - self.goal_state = 2; - self = te2; - } - te = find(te, classname, "info_tfgoal"); - } te = find(world, classname, "door"); while (te != world) { te2 = self; @@ -292,6 +284,19 @@ void () StartQuadRound = te = find(te, classname, "door"); } + te = find(world, classname, "item_tfgoal"); + while (te) { + if (te.origin != te.oldorigin) { + if (te.owner != world) + tfgoalitem_RemoveFromPlayer(te, te.owner, 1); + oldself = spawn(); + oldself.enemy = te; + oldself.weapon = 3; + oldself.nextthink = (time + 0.2); + oldself.think = ReturnItem; + } + te = find(te, classname, "item_tfgoal"); + } if (round_active) { te = find(world, classname, "player"); @@ -333,20 +338,7 @@ void () StartQuadRound = dremove(te); te = find (te, classname, "detpack"); } - te = find(world, classname, "item_tfgoal"); - while (te) { - bprint(2,"Goal Name: "); - bprint(2,te.netname); - bprint(2, "\n"); - if (te.origin != te.oldorigin) { - oldself = spawn(); - oldself.enemy = te; - oldself.weapon = 3; - oldself.nextthink = (time + 0.2); - oldself.think = ReturnItem; - } - te = find(te, classname, "item_tfgoal"); - } + te = find(world, classname, "round"); st = infokey(world, "count"); fl = stof(st); @@ -357,8 +349,6 @@ void () StartQuadRound = st = infokey (world, "round_time"); te.cnt = stof (st); quad_winner = CheckWinningTeam(); - bprint(2, ftos(rounds)); - bprint(2, "\n"); localcmd("serverinfo status Standby\n"); if (rounds > 1) { te.think = QuadRoundBegin; From bd4468ee09d8c045978c28881f156227f50c0d8b Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 14 Feb 2019 16:16:15 +1100 Subject: [PATCH 0584/2474] increase radius on change class at spawn, refactor code --- client.qc | 70 +++++++++++++++++++++---------------------------------- 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/client.qc b/client.qc index dae3f91a..790fc104 100644 --- a/client.qc +++ b/client.qc @@ -860,51 +860,35 @@ float () CloseToSpawnPoint = { local entity spot = nil; local entity te = nil; local float i; + string searchstr; - if (self.team_no == 1) { - spot = find(world, team_str_home, "ts1"); - for(i = 1; i < 30; i++) { - te = findradius(spot.origin, 85); - while (te != world) { - if (te == self) - return 1; - te = te.chain; - } - spot = find(spot, team_str_home, "ts1"); - } - } else if (self.team_no == 2) { - spot = find(world, team_str_home, "ts2"); - for(i = 1; i < 30; i++) { - te = findradius(spot.origin, 85); - while (te != world) { - if (te == self) - return 1; - te = te.chain; - } - spot = find(spot, team_str_home, "ts2"); - } - } else if (self.team_no == 3) { - spot = find(world, team_str_home, "ts3"); - for(i = 1; i < 30; i++) { - te = findradius(spot.origin, 85); - while (te != world) { - if (te == self) - return 1; - te = te.chain; - } - spot = find(spot, team_str_home, "ts3"); - } - } else if (self.team_no == 4) { - spot = find(world, team_str_home, "ts4"); - for(i = 1; i < 30; i++) { - te = findradius(spot.origin, 85); - while (te != world) { - if (te == self) - return 1; - te = te.chain; - } - spot = find(spot, team_str_home, "ts4"); + switch (self.team_no) + { + case 1: + searchstr = "ts1"; + break; + case 2: + searchstr = "ts2"; + break; + case 3: + searchstr = "ts3"; + break; + case 4: + searchstr = "ts4"; + break; + default: + return 0; + } + + spot = find(world, team_str_home, searchstr); + for(i = 1; i < 30; i++) { + te = findradius(spot.origin, 185); + while (te != world) { + if (te == self) + return 1; + te = te.chain; } + spot = find(spot, team_str_home, searchstr); } return 0; From 6cf2127db1afc9f95c98c33d2e3d887cfbd911ea Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 14 Feb 2019 16:20:08 +1100 Subject: [PATCH 0585/2474] spelling mistake from however many years ago... --- demoman.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demoman.qc b/demoman.qc index dee09745..c75b9d38 100644 --- a/demoman.qc +++ b/demoman.qc @@ -181,7 +181,7 @@ void (float timer) TeamFortress_SetDetpack = { if (timer < 5) { sprint(self, PRINT_HIGH, - "You cannot set detpacks for less that 5 seconds\n"); + "You cannot set detpacks for less than 5 seconds\n"); return; } From ffb9f62c503266f4ff2be44bc96f696871948372 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 14 Feb 2019 17:05:41 +1100 Subject: [PATCH 0586/2474] add SettingHasValue to check for settings that may have 0 value (and is not just unset) --- client.qc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 790fc104..4dc1a28b 100644 --- a/client.qc +++ b/client.qc @@ -132,12 +132,27 @@ void () autokick_think = { dremove(self); }; +float (string ps_short, string ps_setting) SettingHasValue = { + st = infokey(world, ps_short); + if (st == string_null) { + st = infokey(world, ps_setting); + if (st == string_null) { + return FALSE; + } + } + + return TRUE; +} + float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { local string st; st = infokey(world, ps_short); if (st == string_null) { st = infokey(world, ps_setting); + if (st == string_null) { + return FALSE; + } } if (st == "on") { @@ -154,7 +169,7 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { return stof(ps_default); } - return 0; + return FALSE; }; void () DecodeLevelParms = { From 4c062f4f274c7e54d2af8129dc85bf987e9a3afc Mon Sep 17 00:00:00 2001 From: fdittz Date: Thu, 14 Feb 2019 17:18:50 -0200 Subject: [PATCH 0587/2474] player ready and startmatch --- admin.qc | 2 +- clan.qc | 188 +++++++++++++++++----------------------------------- client.qc | 8 ++- defs.h | 6 +- qw.qc | 1 + tforthlp.qc | 2 + weapons.qc | 20 +++++- 7 files changed, 91 insertions(+), 136 deletions(-) diff --git a/admin.qc b/admin.qc index cfd1055b..80776ce6 100644 --- a/admin.qc +++ b/admin.qc @@ -160,7 +160,6 @@ void () Admin_CeaseFire = { } cease_fire = 0; if (cb_prematch) { - cb_prematch_time = 0; StartTimer(); } bprint(2, "RESUME FIRE\n"); @@ -237,4 +236,5 @@ void () Admin_Aliases = TeamFortress_Alias("listips", 198, 0); TeamFortress_Alias("clan", 207, 0); TeamFortress_Alias("adminmenu", 239, 0); + TeamFortress_Alias("startmatch", TF_FORCESTARTMATCH, 0); }; \ No newline at end of file diff --git a/clan.qc b/clan.qc index c75c9628..bae95738 100644 --- a/clan.qc +++ b/clan.qc @@ -71,7 +71,7 @@ void () StartMatch = local entity oldself; local entity gren; - lightstyle(0, "m"); + lightstyle(0, "m"); bprint(2, "MATCH BEGINS NOW\n"); team4score = 0; @@ -174,6 +174,7 @@ void () PreMatch_Think = { } else { if (!self.cnt2) { + is_countdown = 0; self.nextthink = (time + 0.1); self.think = SUB_Remove; p = find(world, classname, "player"); @@ -203,6 +204,7 @@ void () PreMatch_Think = { } if (self.cnt2 <= 10) { if (self.cnt2 == 10) { + is_countdown = 1; lightstyle(0, "e"); if (stof(infokey(world, "demo_auto_left")) > 0) { @@ -257,6 +259,18 @@ void () PreMatch_Think = { self.nextthink = (time + 1); }; +void () ResetBreakAndReady = { + local entity te; + te = find (world, classname, "player"); + while (te != world) { + te.bvote = 0; + te.is_ready = 0; + v_break = 0; + v_ready = 0; + te = find (te, classname, "player"); + } +} + void () StartTimer = { local entity timer; @@ -303,6 +317,7 @@ void () StartTimer = } } else { + ResetBreakAndReady(); lightstyle (0, "e"); if (stof(infokey(world, "demo_auto_left")) > 0) { if (infokey(world, "serverdemo") == "on") { @@ -755,90 +770,45 @@ void () TeamFortress_ShowIDs = { sprint(self, PRINT_HIGH, "None\n"); }; -void () ResetBreakAndReady = { +void () Broadcast_Players_NotReady = { local entity te; - te = find (world, classname, "player"); - while (te != world) { - te.bvote = 0; - te.is_ready = 0; - v_break = 0; - v_ready = 0; - te = find (te, classname, "player"); - } -} - -void () PlayerBreak = -{ - local float f1; - local float f2; - local string tmp; - - if (intermission_running) { - return; - } - if (self.classname != "player") { - return; - } - if (infokey(world, "quadmode") == "on" && (infokey (world, "status") == "Countdown" || infokey(world, "status") == "Standby")) { - sprint(self, 2, "You cannot break at this time.\n"); - return; - } - tmp = infokey(world, "votetime"); - f1 = (stof(tmp) * 60); - if (f1 > time) { - sprint(self, 2, "You cannot break at this time.\n"); - return; - } - if (self.allowvote > time) { - return; - } - self.allowvote = (time + 3); - if (self.bvote) { - bprint2(2, self.netname, " \swithdraws\s his/her vote\n"); - self.bvote = 0; - v_break = (v_break - 1); - return; - } - if (quadmode) { - bprint2(3, self.netname, " votes for ending the round\n"); - } - else if (clanbattle) { - bprint2(3, self.netname, " votes for stopping the match\n"); - } - else { - bprint2(3, self.netname, " votes to end the current map\n"); - } - self.bvote = 1; - v_break = (v_break + 1); - f1 = TeamFortress_GetNoPlayers(); - f2 = (floor(f1 / 2) + 1); - if (v_break >= f2) { - if (quadmode) { - bprint(2, "Round ended by majority vote\n"); - ResetBreakAndReady(); - EndQuadRound(); - return; - } - if (clanbattle) { - bprint(2, "Match stopped by majority vote\n"); - } - else { - bprint(2, "Map ended by majority vote\n"); + if (v_ready != 0) { + local string players_not_ready = "Not ready: "; + local float first = 1; + te = find (world, classname, "player"); + while (te != world) { + if (te.is_ready == 0) { + if (!first) + players_not_ready = strcat(players_not_ready, ", "); + else + first = 0; + players_not_ready = strcat(players_not_ready, te.netname); + } + te = find (te, classname, "player"); + } + players_not_ready = strcat(players_not_ready, "\n"); + bprint(1, players_not_ready); + te = find (world, classname, "player"); + while (te != world) { + if (te.is_ready == 0) + sprint(te, 2, "If you are ready, type 'ready' in the console\n"); + te = find(te, classname, "player"); } - StopTimer(); - NextLevel (); return; } - if (v_break != 0) { - f1 = (f2 - v_break); - tmp = ftos (f1); - bprint3(2, "\s", tmp, "\s more vote"); - if (f1 > 1) { - bprint(2, "s"); - } - bprint(2, " needed\n"); + else { + bprint(1, "No player is ready\n"); } -}; + +} + +void () PlayerNotReady = { + bprint2 (2, self.netname, " is NOT ready anymore\n "); + self.is_ready = 0; + v_ready = (v_ready - 1); + Broadcast_Players_NotReady(); + return; +} void () PlayerReady = { @@ -846,44 +816,28 @@ void () PlayerReady = local string tmp; local entity te; - if (quadmode && (infokey (world, "status") == "Countdown")) { - sprint (self, 2, "Use 'break' to stop the countdown.\n"); + if (is_countdown) { + sprint(self, 2, "You cannot do this after countdown has started.\n"); return; } - if (quadmode && (infokey (world, "status") != "Standby")) { - sprint (self, 2, "You cannot do this after the match has started.\n"); + if (infokey (world, "status") != "Standby") { + sprint(self, 2, "You cannot do this after the match has started.\n"); return; } if (self.team_no == 0) { - sprint (self, 2, "You must join a team first.\n"); + sprint(self, 2, "You must join a team first.\n"); return; } if (self.playerclass == 0) { - sprint (self, 2, "You must choose a class first.\n"); + sprint(self, 2, "You must choose a class first.\n"); return; } if (intermission_running) - { return; - } - if ((self.classname != "player")) - { + if (self.classname != "player") return; - } - tmp = infokey (world, "votetime"); - f1 = (stof (tmp) * 60); - if (f1 > time) { - sprint (self, 2, "You cannot be ready at this time.\n"); - return; - } - if (self.allowvote > time) { - return; - } - self.allowvote = (time + 3); if (self.is_ready) { - bprint2 (2, self.netname, " is NOT ready anymore\n "); - self.is_ready = 0; - v_ready = (v_ready - 1); + PlayerNotReady(); return; } self.is_ready = 1; @@ -893,34 +847,10 @@ void () PlayerReady = if (v_ready == f1 ) { bprint (2, "All players ready, starting match\n"); cb_prematch_time = 0; - ResetBreakAndReady(); StartTimer (); return; } - if (v_ready != 0) { - local string players_not_ready = "Not ready: "; - local float first = 1; - te = find (world, classname, "player"); - while (te != world) { - if (te.is_ready == 0) { - if (!first) - players_not_ready = strcat(players_not_ready, ", "); - else - first = 0; - players_not_ready = strcat(players_not_ready, te.netname); - } - te = find (te, classname, "player"); - } - players_not_ready = strcat(players_not_ready, "\n"); - bprint(1, players_not_ready); - te = find (world, classname, "player"); - while (te != world) { - if (te.is_ready == 0) - sprint (te, 2, "If you are ready, type 'ready' in the console\n"); - te = find (te, classname, "player"); - } - return; - } + Broadcast_Players_NotReady(); }; void () RemoveVotes = { diff --git a/client.qc b/client.qc index 6f8b6be9..bb0c2916 100644 --- a/client.qc +++ b/client.qc @@ -1292,8 +1292,14 @@ void () PutClientInServer = { if (self.playerclass != 0) spawn_tdeath(self.origin, self); + if (cb_prematch_time < time) { + bprint(2,"TEST PREMATCH\n"); + bprint(2,"TEST PREMATCH\n"); + bprint(2,"TEST PREMATCH\n"); + } if ((spot.classname == "info_player_teamspawn") && - (cb_prematch_time < time)) { + (!cb_prematch)) { + if (spot.items != 0) { te = Finditem(spot.items); if (te) diff --git a/defs.h b/defs.h index 4f504994..660abf9a 100644 --- a/defs.h +++ b/defs.h @@ -457,9 +457,9 @@ #define TF_VOTETRICK 132 // Vote to start voting for a trick map #define TF_VOTERACE 133 // Vote to start voting for a race map #define TF_FORCENEXT 134 // Vote to force a change to voted map -// unused 135 -// unused 136 -// unused 137 +#define TF_PLAYERREADY 135 +#define TF_PLAYERBREAK 136 +#define TF_FORCESTARTMATCH 137 // unused 138 // unused 139 // unused 140 diff --git a/qw.qc b/qw.qc index ee1bb69c..4ac3a5c6 100644 --- a/qw.qc +++ b/qw.qc @@ -442,6 +442,7 @@ float rounds; float round_active; float round_over; float gametime; +float is_countdown; .float tf_id; diff --git a/tforthlp.qc b/tforthlp.qc index 6d2f3f44..577e2f5b 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -179,6 +179,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); } else if (self.motd == 130) { stuffcmd(self, "is_aliased\n"); + TeamFortress_Alias ("ready", TF_PLAYERREADY, 0); + TeamFortress_Alias ("break", TF_PLAYERBREAK, 0); } else if (self.motd == 400 && self.team_no == 0) { Menu_Team(1); } diff --git a/weapons.qc b/weapons.qc index 25bdfe17..c5944012 100644 --- a/weapons.qc +++ b/weapons.qc @@ -109,6 +109,7 @@ void () ClanMode; void () QuadMode; void () EndQuadRound; void () PlayerReady; +void () StartTimer; void () W_Precache = { precache_sound("weapons/r_exp3.wav"); @@ -2532,10 +2533,10 @@ void () DeadImpulses = { else if ((self.impulse >= TF_CHANGEPC_SCOUT) && (self.impulse <= TF_CHANGEPC_RANDOM)) { TeamFortress_ChangeClass(self.impulse - TF_CHANGEPC_SCOUT + 1); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGETEAM) - && (deathmatch == 3) && (cb_prematch_time < time)) { + && (deathmatch == 3) && (!cb_prematch)) { Menu_Team(0); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGECLASS) - && (deathmatch == 3) && (cb_prematch_time < time)) { + && (deathmatch == 3) && (!cb_prematch)) { Menu_Class(0); } else if (self.is_admin) { if (self.impulse == 193) @@ -2558,6 +2559,9 @@ void () DeadImpulses = { self.current_menu_page = 1; Menu_Admin(); } + else if (self.impulse == TF_FORCESTARTMATCH) { + StartTimer(); + } } if (self.impulse == TF_HELP_MAP) TeamFortress_HelpMap(); @@ -2628,6 +2632,18 @@ void () DeadImpulses = { self.got_aliases = 1; self.impulse = 0; } + if (self.impulse == TF_PLAYERREADY) { + if (clanbattle == 1) { + if (!cb_prematch) { + sprint (self, 2, "Match already in progress...\n"); + self.impulse = 0; + return; + } + PlayerReady(); self.impulse = 0; + self.impulse = 0; + return; + } + } }; void () W_WeaponFrame = { From ec0c62a0117f0fd847dac065c511e624530daaf6 Mon Sep 17 00:00:00 2001 From: fdittz Date: Thu, 14 Feb 2019 18:21:33 -0200 Subject: [PATCH 0588/2474] prematch message --- clan.qc | 101 +++++++++++++++++++++++----------------------------- client.qc | 45 +++++------------------ defs.h | 6 ++-- player.qc | 2 +- qw.qc | 2 -- spy.qc | 2 +- tfort.qc | 6 ++-- tforthlp.qc | 4 +-- tfortmap.qc | 2 +- weapons.qc | 15 +++++++- world.qc | 2 +- 11 files changed, 78 insertions(+), 109 deletions(-) diff --git a/clan.qc b/clan.qc index bae95738..b065dd42 100644 --- a/clan.qc +++ b/clan.qc @@ -106,6 +106,7 @@ void () StartMatch = } cb_prematch = 0; cease_fire = 0; + te = find(world, classname, "prematch"); te.classname = "match"; te.cnt = (timelimit / 60); @@ -275,8 +276,7 @@ void () StartTimer = { local entity timer; local entity p; - local float f1; - local string tmp; + local entity te; if (clanbattle == 0) { if (self != world) { @@ -305,60 +305,33 @@ void () StartTimer = dremove(timer); timer = find(timer, classname, "prematch"); } - f1 = stof(infokey (world, "prematch")); + te = find(world,classname,"pmmessage"); + if (te != world) { + te.think = SUB_Remove; + te.nextthink = 0.01; + } + + ResetBreakAndReady(); timer = spawn(); timer.owner = world; timer.classname = "prematch"; timer.cnt = 0; - if (cb_prematch_time) { - timer.cnt2 = rint(cb_prematch_time * 60); - if (timer.cnt2 < 1) { - timer.cnt2 = 1; - } - } - else { - ResetBreakAndReady(); - lightstyle (0, "e"); - if (stof(infokey(world, "demo_auto_left")) > 0) { - if (infokey(world, "serverdemo") == "on") { - calltimeofday(); - - localcmd("record \""); - localcmd(ftos (tod_day)); // day - localcmd("-"); - localcmd(ftos (tod_mon)); // month - localcmd("-"); - localcmd(ftos (tod_year)); // year - localcmd("_"); - localcmd(ftos (tod_hour)); // hour - localcmd("-"); - localcmd(ftos (tod_min)); // minute - localcmd("-"); - localcmd(ftos (tod_sec)); // second - - localcmd("_["); - localcmd(mapname); - localcmd("]"); - localcmd("\"\n"); - } - } - p = find(world, classname, "player"); - while (p != world) { - if (p.netname != "") { - stuffcmd(p, "play items/protect2.wav\n"); - } - p = find(timer, classname, "player"); - } - timer.cnt2 = rint(stof(infokey(world, "count"))); - if (timer.cnt2 < 1) { - //By default, 10 seconds of countdown - timer.cnt2 = 10; - } + timer.cnt2 = rint(stof(infokey(world, "count"))); + if (timer.cnt2 < 1) { + //By default, 10 seconds of countdown + timer.cnt2 = 10; } timer.cnt2 = (timer.cnt2 + 1); timer.nextthink = (time + 0.1); - tmp = ftos(timer.cnt2); timer.think = PreMatch_Think; + + p = find(world, classname, "player"); + while (p != world) { + if (p.netname != "") { + stuffcmd(p, "play items/protect2.wav\n"); + } + p = find(timer, classname, "player"); + } }; void () StopTimer = @@ -803,18 +776,17 @@ void () Broadcast_Players_NotReady = { } void () PlayerNotReady = { - bprint2 (2, self.netname, " is NOT ready anymore\n "); - self.is_ready = 0; - v_ready = (v_ready - 1); - Broadcast_Players_NotReady(); - return; + if (self.is_ready) { + bprint2 (2, self.netname, " is NOT ready anymore\n "); + self.is_ready = 0; + v_ready = (v_ready - 1); + Broadcast_Players_NotReady(); + } } void () PlayerReady = { local float f1; - local string tmp; - local entity te; if (is_countdown) { sprint(self, 2, "You cannot do this after countdown has started.\n"); @@ -846,7 +818,6 @@ void () PlayerReady = f1 = TeamFortress_GetNoPlayers (); if (v_ready == f1 ) { bprint (2, "All players ready, starting match\n"); - cb_prematch_time = 0; StartTimer (); return; } @@ -864,4 +835,20 @@ void () RemoveVotes = { self.is_ready = 0; v_ready = (v_ready - 1); } -}; \ No newline at end of file +}; + +void () PreMatch_Message = { + local entity p = find (world, classname, "player"); + while (p != world) { + if (p.netname != "") { + sprint(p, "Game in \sPREMATCH\s mode.\n"); + if (p.is_ready) + sprint(p, "You are \sready\s to start the match.\n Type \s/notready\s in the console if you are not ready\n"); + else + sprint(p, "Type \s/ready\s in the console if you are ready to start the match\n"); + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find(p, classname, "player"); + } + self.nextthink = time + 30; +} \ No newline at end of file diff --git a/client.qc b/client.qc index bb0c2916..4ff95cba 100644 --- a/client.qc +++ b/client.qc @@ -55,6 +55,7 @@ void () StopTimer; void () StartQuadRound; void (string cl_pwd) Admin_Check; void () Admin_Aliases; +void () PreMatch_Message; string nextmap; @@ -270,37 +271,12 @@ void () DecodeLevelParms = { clan_scores_dumped = 0; game_locked = 0; - cb_prematch = 1; - cb_prematch_time = CF_GetSetting("pm", "prematch", "0"); - if (cb_prematch_time) - { - StartTimer(); - } - if (!cb_prematch_time) { - cb_ceasefire_time = CF_GetSetting("cft", "ceasefire_time", "0"); - if (cb_ceasefire_time) { - - cease_fire = 1; - bprint (2, "CEASE FIRE\n"); - te = find (world, classname, "player"); - while (te) - { - centerprint (te, "CEASE FIRE\n"); - te.immune_to_check = (time + 5); - te.tfstate = (te.tfstate | TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed (te); - te = find (te, classname, "player"); - } - te = spawn (); - te.classname = "ceasefire"; - te.think = CeaseFire_think; - te.nextthink = (time + 5); - te.weapon = 1; - StartTimer(); - - } - } + local entity pm_message = spawn(); + pm_message.owner = world; + pm_message.classname = "pmmessage"; + pm_message.think = PreMatch_Message; + pm_message.nextthink = 1; game_locked = CF_GetSetting("lg", "locked_game", "off"); @@ -1292,11 +1268,6 @@ void () PutClientInServer = { if (self.playerclass != 0) spawn_tdeath(self.origin, self); - if (cb_prematch_time < time) { - bprint(2,"TEST PREMATCH\n"); - bprint(2,"TEST PREMATCH\n"); - bprint(2,"TEST PREMATCH\n"); - } if ((spot.classname == "info_player_teamspawn") && (!cb_prematch)) { @@ -2068,7 +2039,7 @@ void () ClientConnect = { } } if (!got_one) { - if (game_locked && (cb_prematch_time < time)) { + if (game_locked && (!cb_prematch)) { sprint(self, PRINT_HIGH, "Closed server. Clan battle in progress.\n"); KickCheater(self); @@ -2630,7 +2601,7 @@ void (entity targ, entity attacker) ClientObituary = { Sniper_ZoomReset(targ); - if ((cb_prematch_time + 3) > time) + if (cb_prematch) return; deathstring = GetDeathMessage(targ, attacker, deathmsg); diff --git a/defs.h b/defs.h index 660abf9a..5c61a111 100644 --- a/defs.h +++ b/defs.h @@ -457,9 +457,9 @@ #define TF_VOTETRICK 132 // Vote to start voting for a trick map #define TF_VOTERACE 133 // Vote to start voting for a race map #define TF_FORCENEXT 134 // Vote to force a change to voted map -#define TF_PLAYERREADY 135 -#define TF_PLAYERBREAK 136 -#define TF_FORCESTARTMATCH 137 +#define TF_PLAYER_READY 135 +#define TF_PLAYER_NOT_READY 136 +#define TF_FORCESTARTMATCH 137 // unused 138 // unused 139 // unused 140 diff --git a/player.qc b/player.qc index bc767f04..1c85ffbb 100644 --- a/player.qc +++ b/player.qc @@ -44,7 +44,7 @@ void () player_touch = { } } } - if ((self.tfstate & 16) && (cb_prematch_time < time)) { + if ((self.tfstate & 16) && (!cb_prematch)) { if ((other.classname == "player") && (te.playerclass != 0)) { if (!(other.tfstate & 16)) { if (other.playerclass != 5) { diff --git a/qw.qc b/qw.qc index 4ac3a5c6..37acb210 100644 --- a/qw.qc +++ b/qw.qc @@ -425,8 +425,6 @@ float already_chosen_map; float clanbattle; float clan_scores_dumped; float cb_prematch; -float cb_prematch_time; -float cb_ceasefire_time; float v_break; float v_ready; .float allowvote; diff --git a/spy.qc b/spy.qc index b0480917..8b9a4dee 100644 --- a/spy.qc +++ b/spy.qc @@ -1350,7 +1350,7 @@ void (entity spy) Spy_RemoveDisguise = { }; void () Spy_DropBackpack = { - if ((cb_prematch_time + 3) > time) + if (cb_prematch) return; newmis = spawn(); diff --git a/tfort.qc b/tfort.qc index 75f218eb..ced249b0 100644 --- a/tfort.qc +++ b/tfort.qc @@ -141,7 +141,7 @@ void (float inp) TeamFortress_ChangeClass = { return; if (self.playerclass != 0) { - if ((deathmatch != 3) && (cb_prematch_time < time)) + if ((deathmatch != 3) && (!cb_prematch)) return; if (self.playerclass == inp) { @@ -252,7 +252,7 @@ void (float inp) TeamFortress_ChangeClass = { self.playerclass = 1 + floor(random() * 9); } if ((spot.classname == "info_player_teamspawn") && - (cb_prematch_time < time)) { + (!cb_prematch)) { if (spot.items != 0) { te = Finditem(spot.items); if (te) @@ -2463,7 +2463,7 @@ void (float Suicided) TeamFortress_SetupRespawn = { else restime = 0; - if (cb_prematch_time < time) { + if (!cb_prematch) { if (Suicided) { if (self.lives > 0) self.lives = self.lives - 1; diff --git a/tforthlp.qc b/tforthlp.qc index 577e2f5b..b5757015 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -179,8 +179,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); } else if (self.motd == 130) { stuffcmd(self, "is_aliased\n"); - TeamFortress_Alias ("ready", TF_PLAYERREADY, 0); - TeamFortress_Alias ("break", TF_PLAYERBREAK, 0); + TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); + TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); } else if (self.motd == 400 && self.team_no == 0) { Menu_Team(1); } diff --git a/tfortmap.qc b/tfortmap.qc index 9a693762..597f2181 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2782,7 +2782,7 @@ void (entity P) ForceRespawn = { if (self.playerclass != 0) spawn_tdeath(self.origin, self); if ((spot.classname == "info_player_teamspawn") && - (cb_prematch_time < time)) { + (!cb_prematch)) { if (spot.items != 0) { te = Finditem(spot.items); if (te) { diff --git a/weapons.qc b/weapons.qc index c5944012..7c4d44e6 100644 --- a/weapons.qc +++ b/weapons.qc @@ -109,6 +109,7 @@ void () ClanMode; void () QuadMode; void () EndQuadRound; void () PlayerReady; +void () PlayerNotReady; void () StartTimer; void () W_Precache = { @@ -2632,7 +2633,7 @@ void () DeadImpulses = { self.got_aliases = 1; self.impulse = 0; } - if (self.impulse == TF_PLAYERREADY) { + if (self.impulse == TF_PLAYER_READY) { if (clanbattle == 1) { if (!cb_prematch) { sprint (self, 2, "Match already in progress...\n"); @@ -2644,6 +2645,18 @@ void () DeadImpulses = { return; } } + else if (self.impulse == TF_PLAYER_NOT_READY) { + if (clanbattle == 1) { + if (!cb_prematch) { + sprint (self, 2, "Match already in progress...\n"); + self.impulse = 0; + return; + } + PlayerNotReady(); self.impulse = 0; + self.impulse = 0; + return; + } + } }; void () W_WeaponFrame = { diff --git a/world.qc b/world.qc index b3ab5f57..460b1f5e 100644 --- a/world.qc +++ b/world.qc @@ -340,7 +340,7 @@ void () InitBodyQue = { }; void (entity ent) CopyToBodyQue = { - if ((cb_prematch_time + 3) > time) + if (cb_prematch) return; bodyque_head.angles = ent.angles; From 17a6d1406706aa2628b81e3f91cdd7ce0f488e0c Mon Sep 17 00:00:00 2001 From: fdittz Date: Thu, 14 Feb 2019 19:34:47 -0200 Subject: [PATCH 0589/2474] syncing clock correctly in clan mode --- admin.qc | 1 + clan.qc | 17 +++++------------ client.qc | 2 +- defs.h | 2 +- weapons.qc | 6 ++++-- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/admin.qc b/admin.qc index 80776ce6..af3165fa 100644 --- a/admin.qc +++ b/admin.qc @@ -237,4 +237,5 @@ void () Admin_Aliases = TeamFortress_Alias("clan", 207, 0); TeamFortress_Alias("adminmenu", 239, 0); TeamFortress_Alias("startmatch", TF_FORCESTARTMATCH, 0); + TeamFortress_Alias("readystatus", TF_READYSTATUS, 0); }; \ No newline at end of file diff --git a/clan.qc b/clan.qc index b065dd42..83a34368 100644 --- a/clan.qc +++ b/clan.qc @@ -17,16 +17,9 @@ void () MatchThink = return; } - if ( self.cnt == cvar("timelimit") - 1 && self.cnt2 == 59 ) { - localcmd("serverinfo status \""); - tmp = ftos(self.cnt + 1); - localcmd(tmp); - localcmd(" min left\"\n"); - } - if (self.cnt2 == 1) { localcmd("serverinfo status \""); - tmp = ftos(self.cnt + 1); + tmp = ftos(self.cnt); localcmd(tmp); localcmd(" min left\"\n"); } @@ -764,7 +757,7 @@ void () Broadcast_Players_NotReady = { te = find (world, classname, "player"); while (te != world) { if (te.is_ready == 0) - sprint(te, 2, "If you are ready, type 'ready' in the console\n"); + sprint(te, 2, "If you are ready, type \s/ready\s in the console\n"); te = find(te, classname, "player"); } return; @@ -841,11 +834,11 @@ void () PreMatch_Message = { local entity p = find (world, classname, "player"); while (p != world) { if (p.netname != "") { - sprint(p, "Game in \sPREMATCH\s mode.\n"); + sprint(p, PRINT_HIGH, "Currently in \sprematch\s time\n"); if (p.is_ready) - sprint(p, "You are \sready\s to start the match.\n Type \s/notready\s in the console if you are not ready\n"); + sprint(p, PRINT_HIGH, "You are \sready\s to start the match.\n Type \s/notready\s in the console if you are not ready\n"); else - sprint(p, "Type \s/ready\s in the console if you are ready to start the match\n"); + sprint(p, PRINT_HIGH, "Type \s/ready\s in the console if you are ready to start the match\n"); stuffcmd(p, "play buttons/switch04.wav\n"); } p = find(p, classname, "player"); diff --git a/client.qc b/client.qc index 4ff95cba..3ffcf047 100644 --- a/client.qc +++ b/client.qc @@ -2055,7 +2055,7 @@ void () ClientConnect = { } } if (cb_prematch) - sprint(self, PRINT_HIGH, "Currently in prematch time\n"); + sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); }; void () ClientDisconnect = { diff --git a/defs.h b/defs.h index 5c61a111..2561a6b9 100644 --- a/defs.h +++ b/defs.h @@ -460,7 +460,7 @@ #define TF_PLAYER_READY 135 #define TF_PLAYER_NOT_READY 136 #define TF_FORCESTARTMATCH 137 -// unused 138 +#define TF_READYSTATUS 138 // unused 139 // unused 140 // unused 141 diff --git a/weapons.qc b/weapons.qc index 7c4d44e6..ebd8b28c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -110,6 +110,7 @@ void () QuadMode; void () EndQuadRound; void () PlayerReady; void () PlayerNotReady; +void () Broadcast_Players_NotReady; void () StartTimer; void () W_Precache = { @@ -2560,9 +2561,10 @@ void () DeadImpulses = { self.current_menu_page = 1; Menu_Admin(); } - else if (self.impulse == TF_FORCESTARTMATCH) { + else if (self.impulse == TF_FORCESTARTMATCH) StartTimer(); - } + else if (self.impulse == TF_READYSTATUS) + Broadcast_Players_NotReady(); } if (self.impulse == TF_HELP_MAP) TeamFortress_HelpMap(); From eff08e1bfa45613e825c075565977001d3182fbb Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Fri, 15 Feb 2019 10:38:14 +1100 Subject: [PATCH 0590/2474] fix for cf_getsetting --- client.qc | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/client.qc b/client.qc index 4dc1a28b..c0765a32 100644 --- a/client.qc +++ b/client.qc @@ -132,18 +132,6 @@ void () autokick_think = { dremove(self); }; -float (string ps_short, string ps_setting) SettingHasValue = { - st = infokey(world, ps_short); - if (st == string_null) { - st = infokey(world, ps_setting); - if (st == string_null) { - return FALSE; - } - } - - return TRUE; -} - float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { local string st; @@ -151,25 +139,19 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { if (st == string_null) { st = infokey(world, ps_setting); if (st == string_null) { - return FALSE; + st = ps_default; } } - if (st == "on") { - return TRUE; - } else if (st == "off") { - return FALSE; - } else if (stof(st) != 0) { - return stof(st); - } else if (ps_default == "on") { - return TRUE; - } else if (ps_default == "off") { - return FALSE; - } else if (stof(ps_default) != 0) { - return stof(ps_default); + switch (st) + { + case "on": + return TRUE; + case "off": + return FALSE; + default: + return stof(st); } - - return FALSE; }; void () DecodeLevelParms = { From 611fd3a0311db1b318cd2685a4196f0b11f16a5e Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 15 Feb 2019 20:25:19 +1100 Subject: [PATCH 0591/2474] fix for endless loop from concussion grenades --- scout.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/scout.qc b/scout.qc index 09c26c39..ff743084 100644 --- a/scout.qc +++ b/scout.qc @@ -560,6 +560,7 @@ void (entity inflictor, entity attacker, float bounce, head.flags = head.flags - FL_ONGROUND; } else { if (medicnocuss && head.playerclass == 5) { + head = head.chain; continue; } From ad5e76ca85ec6a0b77fd04c1511dd62e14654a90 Mon Sep 17 00:00:00 2001 From: fdittz Date: Fri, 15 Feb 2019 14:49:50 -0200 Subject: [PATCH 0592/2474] adding quadmode admin alias --- admin.qc | 1 + mvdsv.qc | 2 +- weapons.qc | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/admin.qc b/admin.qc index af3165fa..67ae4760 100644 --- a/admin.qc +++ b/admin.qc @@ -235,6 +235,7 @@ void () Admin_Aliases = TeamFortress_Alias("ceasefire", 193, 0); TeamFortress_Alias("listips", 198, 0); TeamFortress_Alias("clan", 207, 0); + TeamFortress_Alias("quadmode", 208, 0); TeamFortress_Alias("adminmenu", 239, 0); TeamFortress_Alias("startmatch", TF_FORCESTARTMATCH, 0); TeamFortress_Alias("readystatus", TF_READYSTATUS, 0); diff --git a/mvdsv.qc b/mvdsv.qc index a2730b59..ef7f62ca 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -276,7 +276,7 @@ float () ConsoleCmd { } else if (argv_mvdsv (0) == "quadmode") { - QuadMode (); + QuadMode(); return (1); } return 0; diff --git a/weapons.qc b/weapons.qc index cc86aed6..22481623 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2996,6 +2996,8 @@ void () DeadImpulses = { Admin_ListIPs(); else if (self.impulse == 207) ClanMode(); + else if (self.impulse == 208) + QuadMode(); else if (self.impulse == 239) { self.current_menu_page = 1; Menu_Admin(); From b217febbe3edde6e58a8edd5ae7a405caa62e3bf Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 19 Feb 2019 21:05:47 +1100 Subject: [PATCH 0593/2474] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd1e362b..576907f6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server v0.1.0 New features ------ -* Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsounds 2` +* Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. * Increased nail velocity. Disable with `localinfo old_ng_velocity on`. From fced034721a0099ca6465885cb387de627f2f093 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 20 Feb 2019 11:40:46 +1300 Subject: [PATCH 0594/2474] On DM/SP maps, player always spawns at 0 0 0 instead of dm/sp starts --- client.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 8030ee86..a14ac569 100644 --- a/client.qc +++ b/client.qc @@ -1092,9 +1092,10 @@ entity () SelectSpawnPoint = if (self.team_no != 0) { spot = FindTeamSpawnPoint(self.team_no); - if (spot != world) + if (spot != world) { self.last_spawn_spot = spot; return (spot); + } } if (coop) { lastspawn = find(lastspawn, classname, "info_player_coop"); From 528158ba667afe2b67071c16eed5dd02673db0e8 Mon Sep 17 00:00:00 2001 From: mehtty <47474496+mehtty@users.noreply.github.com> Date: Wed, 20 Feb 2019 12:02:13 +1300 Subject: [PATCH 0595/2474] On DM/SP maps, player always spawns at 0 0 0 instead of dm/sp starts (#64) --- client.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index c0765a32..ca26c3cf 100644 --- a/client.qc +++ b/client.qc @@ -1074,9 +1074,10 @@ entity () SelectSpawnPoint = if (self.team_no != 0) { spot = FindTeamSpawnPoint(self.team_no); - if (spot != world) + if (spot != world) { self.last_spawn_spot = spot; return (spot); + } } if (coop) { lastspawn = find(lastspawn, classname, "info_player_coop"); From 89b45f4620d224e7e85a8900c7405b0aaa99e7ba Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 20 Feb 2019 16:21:46 +1300 Subject: [PATCH 0596/2474] Fixed the server crash, spy still gets squished though --- spy.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spy.qc b/spy.qc index 86561de3..9a3d3810 100644 --- a/spy.qc +++ b/spy.qc @@ -376,6 +376,9 @@ void () CF_Spy_AirThink = { local float area_check = 0; if ((self.owner.deadflag >= 2) || (self.owner.playerclass != PC_SPY) || (!self.owner.is_feigning)) { + // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) + self.owner.movetype = MOVETYPE_NONE; + self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; dremove(self); return; } @@ -1411,4 +1414,4 @@ void () Spy_DropBackpack = { newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; \ No newline at end of file +}; From 02ce2c3227793674e072db84aaec8b18def08ce1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 20 Feb 2019 16:37:35 +1300 Subject: [PATCH 0597/2474] newline --- spy.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spy.qc b/spy.qc index 9a3d3810..9a4681e3 100644 --- a/spy.qc +++ b/spy.qc @@ -1414,4 +1414,4 @@ void () Spy_DropBackpack = { newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; +}; \ No newline at end of file From 1da0e6678b2209cdc4880ae475d5fa3bc18711f0 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 20 Feb 2019 16:41:58 +1300 Subject: [PATCH 0598/2474] indentation fix --- spy.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spy.qc b/spy.qc index 9a4681e3..d2976f7f 100644 --- a/spy.qc +++ b/spy.qc @@ -376,9 +376,9 @@ void () CF_Spy_AirThink = { local float area_check = 0; if ((self.owner.deadflag >= 2) || (self.owner.playerclass != PC_SPY) || (!self.owner.is_feigning)) { - // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) - self.owner.movetype = MOVETYPE_NONE; - self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; + // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) + self.owner.movetype = MOVETYPE_NONE; + self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; dremove(self); return; } From f81665611699385523e7119889169c0c7ff61a25 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 20 Feb 2019 17:00:48 +1300 Subject: [PATCH 0599/2474] fix to only affect dead players --- spy.qc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spy.qc b/spy.qc index d2976f7f..29228642 100644 --- a/spy.qc +++ b/spy.qc @@ -375,10 +375,14 @@ float (entity pe_player) Spy_CheckArea = { void () CF_Spy_AirThink = { local float area_check = 0; - if ((self.owner.deadflag >= 2) || (self.owner.playerclass != PC_SPY) || (!self.owner.is_feigning)) { - // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) - self.owner.movetype = MOVETYPE_NONE; - self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; + if(self.owner.deadflag >= 2) { + // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) + self.owner.movetype = MOVETYPE_NONE; + self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; + dremove(self); + return; + } + if ((self.owner.playerclass != PC_SPY) || (!self.owner.is_feigning)) { dremove(self); return; } From 47103d8771300557ec52856f74fd99544f733e1e Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 20 Feb 2019 23:13:34 +1100 Subject: [PATCH 0600/2474] get rid of annoying dprint --- tfortmap.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/tfortmap.qc b/tfortmap.qc index 9a693762..bbac3b37 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1965,7 +1965,6 @@ void () tfgoal_touch = { }; void () info_tfgoal_use = { - dprint("info_tfgoal_use\n"); AttemptToActivate(self, activator, self); }; From 4e670613db0241c76c25c92dff78b9685d2b5e66 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 20 Feb 2019 23:39:25 +1100 Subject: [PATCH 0601/2474] fix grammar --- commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands.qc b/commands.qc index 703ad2c7..53ebf22e 100644 --- a/commands.qc +++ b/commands.qc @@ -18,7 +18,7 @@ void () QuadMode = localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); - bprint (2, "Map Restart needed to take affect!\n"); + bprint (2, "Map Restart needed to take effect!\n"); } bprint3 (2, "Quad Mode set to ", st, "\n"); }; From 505a97c4ac397363dd457cf104bb4651a9888f69 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 20 Feb 2019 23:40:04 +1100 Subject: [PATCH 0602/2474] fix grammar --- commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands.qc b/commands.qc index 53ebf22e..04d4fd14 100644 --- a/commands.qc +++ b/commands.qc @@ -34,7 +34,7 @@ void () ClanMode = else { st = "on"; localcmd("localinfo clan on\n"); - bprint(2, "Map Restart needed to take affect!\n"); + bprint(2, "Map Restart needed to take effect!\n"); } bprint3(2, "Clan Mode set to ", st, "\n"); }; \ No newline at end of file From 3ec2648012a2c2c2a2e3fcbd18b0d222337e1ad7 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 21 Feb 2019 15:07:47 +1100 Subject: [PATCH 0603/2474] fix for issue 57 hitboop plays teammate sound for spy even when he is disguised as enemy team --- combat.qc | 146 +++++++++++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/combat.qc b/combat.qc index a0e55908..cf00e88f 100644 --- a/combat.qc +++ b/combat.qc @@ -88,79 +88,79 @@ void (entity targ, entity attacker) Killed = { void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { - if((attacker.classname == "player") || (attacker.classname == "building_sentrygun")){ - - if((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")){ - - local entity trueattacker; - - if (attacker.classname == "building_sentrygun"){ // work out correct attacker - trueattacker = attacker.real_owner; - } - else { - trueattacker = attacker; - } - - if (trueattacker == targ) - { - return; - } - - - local string hitsound; - hitsound = infokey(trueattacker, "hitsound"); - - if(hitsound == "1" || hitsound == "2"){ - - local float crit; - - if((inflictor.weapon == DMSG_ROCKETL) && (damage >= 80)){ - crit = 1; - } - if ((inflictor.weapon == DMSG_SSHOTGUN) && (damage >= 40)){ - crit = 1; - } - if ((inflictor.weapon == DMSG_GRENADEL) && (damage >= 85)){ - crit = 1; - } - if((inflictor.weapon == DMSG_INCENDIARY) && (damage >= 40)){ - crit = 1; - } - - local float sameteam; - - if (attacker.team_no == targ.team_no){ - sameteam = 1; - } - else { - sameteam = 0; - - if(targ.classname == "player"){ - if(targ.playerclass == PC_SPY){ - if (targ.is_feigning){ - return; - } - if (targ.is_undercover){ - sameteam = 1; - } - } - } - } - - if (sameteam == 0) { - if (crit == 1){ - stuffcmd(trueattacker, "play misc/hitsoundcrit.wav\n"); //sounds precached in weapons.qc - } - else { - stuffcmd(trueattacker, "play misc/hitsound.wav\n"); //sounds precached in weapons.qc - } - } - else { - if (hitsound == "2"){ - stuffcmd(trueattacker, "play misc/hitsoundteam.wav\n"); //sounds precached in weapons.qc - } - } - } + if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) + { + if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) + { + local entity trueattacker; + + if (attacker.classname == "building_sentrygun") + { // work out correct attacker + trueattacker = attacker.real_owner; + } + else + { + trueattacker = attacker; + } + + if (trueattacker == targ) + { + return; + } + + local string hitsound; + hitsound = infokey(trueattacker, "hitsound"); + + if (hitsound == "1" || hitsound == "2") + { + local float crit; + + if((inflictor.weapon == DMSG_ROCKETL) && (damage >= 80)) { + crit = 1; + } + if ((inflictor.weapon == DMSG_SSHOTGUN) && (damage >= 40)) { + crit = 1; + } + if ((inflictor.weapon == DMSG_GRENADEL) && (damage >= 85)) { + crit = 1; + } + if ((inflictor.weapon == DMSG_INCENDIARY) && (damage >= 40)) { + crit = 1; + } + + local float sameteam; + sameteam = 0; + + if (targ.playerclass == PC_SPY) + { + if (targ.is_feigning) + { + return; + } + if (targ.undercover_team == attacker.team_no) + { + sameteam = 1; + } + } + else if (attacker.team_no == targ.team_no) + { + sameteam = 1; + } + + if (sameteam == 0) { + if (crit == 1){ + stuffcmd(trueattacker, "play misc/hitsoundcrit.wav\n"); //sounds precached in weapons.qc + } + else { + stuffcmd(trueattacker, "play misc/hitsound.wav\n"); //sounds precached in weapons.qc + } + } + else { + if (hitsound == "2"){ + stuffcmd(trueattacker, "play misc/hitsoundteam.wav\n"); //sounds precached in weapons.qc + } + } + } } } }; From a5377ac92451e9c56e7935341bd0b91bec56ef37 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 21 Feb 2019 15:40:04 +1100 Subject: [PATCH 0604/2474] define consts for admin menu functions --- admin.qc | 24 ++++++++++++------------ defs.h | 25 +++++++++++++------------ spect.qc | 14 +++++++------- weapons.qc | 24 ++++++++++++------------ 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/admin.qc b/admin.qc index 67ae4760..acfd2afa 100644 --- a/admin.qc +++ b/admin.qc @@ -227,16 +227,16 @@ void (string cl_pwd) Admin_Check = void () Admin_Aliases = { - TeamFortress_Alias("countplayers", 192, 0); - TeamFortress_Alias("deal", 189, 0); - TeamFortress_Alias("kick", 190, 0); - TeamFortress_Alias("ban", 191, 0); - TeamFortress_Alias("next", 195, 0); - TeamFortress_Alias("ceasefire", 193, 0); - TeamFortress_Alias("listips", 198, 0); - TeamFortress_Alias("clan", 207, 0); - TeamFortress_Alias("quadmode", 208, 0); - TeamFortress_Alias("adminmenu", 239, 0); - TeamFortress_Alias("startmatch", TF_FORCESTARTMATCH, 0); - TeamFortress_Alias("readystatus", TF_READYSTATUS, 0); + TeamFortress_Alias("countplayers", TF_ADMIN_COUNTPLAYERS, 0); + TeamFortress_Alias("deal", TF_ADMIN_CYCLEDEAL, 0); + TeamFortress_Alias("kick", TF_ADMIN_KICK, 0); + TeamFortress_Alias("ban", TF_ADMIN_BAN, 0); + TeamFortress_Alias("next", TF_ADMIN_NEXT, 0); + TeamFortress_Alias("ceasefire", TF_ADMIN_CEASEFIRE, 0); + TeamFortress_Alias("listips", TF_ADMIN_LISTIPS, 0); + TeamFortress_Alias("clan", TF_ADMIN_CLANMODE, 0); + TeamFortress_Alias("quadmode", TF_ADMIN_QUADMODE, 0); + TeamFortress_Alias("adminmenu", TF_ADMIN_ADMINMENU, 0); + TeamFortress_Alias("startmatch", TF_ADMIN_FORCESTARTMATCH, 0); + TeamFortress_Alias("readystatus", TF_ADMIN_READYSTATUS, 0); }; \ No newline at end of file diff --git a/defs.h b/defs.h index 2561a6b9..978d51ac 100644 --- a/defs.h +++ b/defs.h @@ -459,8 +459,8 @@ #define TF_FORCENEXT 134 // Vote to force a change to voted map #define TF_PLAYER_READY 135 #define TF_PLAYER_NOT_READY 136 -#define TF_FORCESTARTMATCH 137 -#define TF_READYSTATUS 138 +#define TF_ADMIN_FORCESTARTMATCH 137 +#define TF_ADMIN_READYSTATUS 138 // unused 139 // unused 140 // unused 141 @@ -511,16 +511,16 @@ // unused 186 // unused 187 // unused 188 -// unused 189 -// unused 190 -// unused 191 -// unused 192 -// unused 193 +#define TF_ADMIN_CYCLEDEAL 189 +#define TF_ADMIN_KICK 190 +#define TF_ADMIN_BAN 191 +#define TF_ADMIN_COUNTPLAYERS 192 +#define TF_ADMIN_CEASEFIRE 193 // unused 194 -// unused 195 +#define TF_ADMIN_NEXT 195 // unused 196 // unused 197 -// unused 198 +#define TF_ADMIN_LISTIPS 198 // unused 199 // unused 200 // unused 201 @@ -529,8 +529,8 @@ // unused 204 // unused 205 // unused 206 -// unused 207 -// unused 208 +#define TF_ADMIN_CLANMODE 207 +#define TF_ADMIN_QUADMODE 208 // unused 209 // unused 210 // unused 211 @@ -561,7 +561,7 @@ // unused 236 // unused 237 // unused 238 -// unused 239 +#define TF_ADMIN_ADMINMENU 239 // unused 240 // unused 241 // unused 242 @@ -1234,6 +1234,7 @@ #define MENU_REFRESH_RATE 25 + /*======================================================*/ /* Misc defines */ /*======================================================*/ diff --git a/spect.qc b/spect.qc index 4c5bf367..40eac69d 100644 --- a/spect.qc +++ b/spect.qc @@ -82,19 +82,19 @@ void () SpectatorImpulseCommand = { return; } - if (self.impulse == 193) + if (self.impulse == TF_ADMIN_CEASEFIRE) Admin_CeaseFire(); - else if (self.impulse == 192) + else if (self.impulse == TF_ADMIN_COUNTPLAYERS) Admin_CountPlayers(); - else if (self.impulse == 189) + else if (self.impulse == TF_ADMIN_CYCLEDEAL) Admin_CycleDeal(); - else if ((self.impulse == 190) && (self.admin_mode == 1)) + else if ((self.impulse == TF_ADMIN_KICK) && (self.admin_mode == 1)) Admin_DoKick(); - else if ((self.impulse == 191) && (self.admin_mode == 1)) + else if ((self.impulse == TF_ADMIN_BAN) && (self.admin_mode == 1)) Admin_DoBan(); - else if ((self.impulse == 195) && (self.admin_mode == 1)) + else if ((self.impulse == TF_ADMIN_NEXT) && (self.admin_mode == 1)) Admin_CycleDeal(); - else if (self.impulse == 198) + else if (self.impulse == TF_ADMIN_LISTIPS) Admin_ListIPs(); self.impulse = 0; diff --git a/weapons.qc b/weapons.qc index 22481623..e624ac09 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2980,31 +2980,31 @@ void () DeadImpulses = { && (deathmatch == 3) && (!cb_prematch)) { Menu_Class(0); } else if (self.is_admin) { - if (self.impulse == 193) + if (self.impulse == TF_ADMIN_CEASEFIRE) Admin_CeaseFire(); - else if (self.impulse == 192) + else if (self.impulse == TF_ADMIN_COUNTPLAYERS) Admin_CountPlayers(); - else if (self.impulse == 189) + else if (self.impulse == TF_ADMIN_CYCLEDEAL) Admin_CycleDeal(); - else if ((self.impulse == 190) && (self.admin_mode == 1)) + else if ((self.impulse == TF_ADMIN_KICK) && (self.admin_mode == 1)) Admin_DoKick(); - else if ((self.impulse == 191) && (self.admin_mode == 1)) + else if ((self.impulse == TF_ADMIN_BAN) && (self.admin_mode == 1)) Admin_DoBan(); - else if ((self.impulse == 195) && (self.admin_mode == 1)) + else if ((self.impulse == TF_ADMIN_NEXT) && (self.admin_mode == 1)) Admin_CycleDeal(); - else if (self.impulse == 198) + else if (self.impulse == TF_ADMIN_LISTIPS) Admin_ListIPs(); - else if (self.impulse == 207) + else if (self.impulse == TF_ADMIN_CLANMODE) ClanMode(); - else if (self.impulse == 208) + else if (self.impulse == TF_ADMIN_QUADMODE) QuadMode(); - else if (self.impulse == 239) { + else if (self.impulse == TF_ADMIN_ADMINMENU) { self.current_menu_page = 1; Menu_Admin(); } - else if (self.impulse == TF_FORCESTARTMATCH) + else if (self.impulse == TF_ADMIN_FORCESTARTMATCH) StartTimer(); - else if (self.impulse == TF_READYSTATUS) + else if (self.impulse == TF_ADMIN_READYSTATUS) Broadcast_Players_NotReady(); } if (self.impulse == TF_HELP_MAP) From 79d721157931ae1179b1d1960b69622ec00d4c8b Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 21 Feb 2019 16:10:45 +1100 Subject: [PATCH 0605/2474] consts for admin menu types --- defs.h | 15 ++++++++ menu.qc | 105 +++++++++++++++++++++++++++++++------------------------- 2 files changed, 74 insertions(+), 46 deletions(-) diff --git a/defs.h b/defs.h index 978d51ac..65d130bc 100644 --- a/defs.h +++ b/defs.h @@ -320,6 +320,21 @@ #define PC_LASTCLASS 12 // Use this as the high-boundary for any loops // through the playerclass. +// admin menu page consts +// 1 = kick selection menu +// 2 = ban selection menu +// 3 = team 1's captain select menu +// 4 = team 2's captain select menu +// 5 = captain player selection menu +#define ADMIN_MENU_TYPE_MAIN 0 +#define ADMIN_MENU_TYPE_KICK 1 +#define ADMIN_MENU_TYPE_BAN 2 +#define ADMIN_MENU_TYPE_CAPTAINTEAMONE 3 +#define ADMIN_MENU_TYPE_CAPTAINTEAMTWO 4 +#define ADMIN_MENU_TYPE_CAPTAINSELECT 5 +#define ADMIN_MENU_TYPE_QUADMODE 6 + + /*======================================================*/ /* Impulse Defines */ /*======================================================*/ diff --git a/menu.qc b/menu.qc index 6a02e562..b5f5f533 100644 --- a/menu.qc +++ b/menu.qc @@ -1040,10 +1040,10 @@ void () Menu_Admin = s_menu1 = ""; s_menu2 = ""; - if (self.current_menu_type == 0) { + if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN) { s_menu1 = "FortressOne Admin Menu: \n\n"; if (self.current_menu_page == 1) { - s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[1]\s Not Used \n"); s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit \n"); s_menu1 = strcat(s_menu1, Q"\s[3]\s Kick \n"); s_menu1 = strcat(s_menu1, Q"\s[4]\s Ban \n"); @@ -1051,10 +1051,10 @@ void () Menu_Admin = s_menu1 = strcat(s_menu1, Q"\s[6]\s Randomize Teams \n"); s_menu1 = strcat(s_menu1, Q"\s[7]\s Restart current map \n"); } else if (self.current_menu_page == 2) { - s_menu1 = strcat(s_menu1, Q"\s[1]\s \n"); - s_menu1 = strcat(s_menu1, Q"\s[2]\s \n"); - s_menu1 = strcat(s_menu1, Q"\s[3]\s \n"); - s_menu1 = strcat(s_menu1, Q"\s[4]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s Quad Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[3]\s Pub Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[4]\s Duel Mode (Not implemented) \n"); s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); s_menu1 = strcat(s_menu1, Q"\s[6]\s \n"); s_menu1 = strcat(s_menu1, Q"\s[7]\s \n"); @@ -1073,16 +1073,16 @@ void () Menu_Admin = // 4 = team 2's captain select menu // 5 = captain player selection menu - if (self.current_menu_type == 1 || self.current_menu_type == 2 || self.current_menu_type == 3 || self.current_menu_type == 4 || self.current_menu_type == 5) { - if (self.current_menu_type == 1) { + if (self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) { + if (self.current_menu_type == ADMIN_MENU_TYPE_KICK) { s_menu1 = "Admin Kick Menu: \n\n"; - } else if (self.current_menu_type == 2) { + } else if (self.current_menu_type == ADMIN_MENU_TYPE_BAN) { s_menu1 = "Admin Ban Menu: \n\n"; - } else if (self.current_menu_type == 3) { + } else if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE) { s_menu1 = "Captain Team 1 Select Menu: \n\n"; - } else if (self.current_menu_type == 4) { + } else if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO) { s_menu1 = "Captain Team 2 Select Menu: \n\n"; - } else if (self.current_menu_type == 5) { + } else if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) { s_menu1 = strcat(Q"\[\sCaptain\s\] Team ", ftos(self.team_no)); s_menu1 = strcat(s_menu1, " : \n\n"); } @@ -1097,7 +1097,7 @@ void () Menu_Admin = te = find (world, classname, "player"); while (te != world) { - if ( (f_tmp < (self.current_menu_page * 7) ) && ( f_tmp >= ((self.current_menu_page - 1) * 7) ) && ( ( ( self.current_menu_type == 5 || self.current_menu_type == 4 ) && !te.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + if ( (f_tmp < (self.current_menu_page * 7) ) && ( f_tmp >= ((self.current_menu_page - 1) * 7) ) && ( ( ( self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO ) && !te.captain) || (self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMTWO) ) ) { f_tmp2 = f_tmp2 + 1; f_tmp = f_tmp + 1; s_menu2 = strcat( s_menu2, Q"\s[\s" ); @@ -1112,14 +1112,14 @@ void () Menu_Admin = s_menu2 = Menu_Indent_line(s_menu2, 30); } - if (( f_tmp < (self.current_menu_page - 1) * 7) && ( ( ( self.current_menu_type == 5 || self.current_menu_type == 4 ) && !te.captain) || ( self.current_menu_type != 5 && self.current_menu_type != 4 ) ) ) { + if (( f_tmp < (self.current_menu_page - 1) * 7) && ( ( ( self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO ) && !te.captain) || ( self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMTWO ) ) ) { f_tmp = f_tmp + 1; } te = find (te, classname, "player"); } - if (self.current_menu_type != 3 && self.current_menu_type != 4 && self.current_menu_type != 5 ) { + if (self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMONE && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMTWO && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT ) { te = find (world, classname, "observer"); while (te != world) { if ( (f_tmp <= (self.current_menu_page * 7) ) && (f_tmp > (self.current_menu_page - 1) * 7) && te.netname != "") { @@ -1141,7 +1141,7 @@ void () Menu_Admin = } } - if (f_tmp == 0 && ( self.current_menu_type == 5 || self.current_menu_type == 4 ) ) { + if (f_tmp == 0 && ( self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO ) ) { bprint(2, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s\n"); temp = self; te = find (world, classname, "player"); @@ -1149,7 +1149,7 @@ void () Menu_Admin = te.captain = 0; self = te; Menu_Close(self); - self.current_menu_type = 0; + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 0; te = find (te, classname, "player"); } @@ -1189,16 +1189,13 @@ void (float inp) Menu_Admin_Input = local float f_tmp; // Actions for AdminMenu Page 0 - if (self.current_menu_type == 0 && self.current_menu_page == 1) { + if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN && self.current_menu_page == 1) { /* - * Toggle Clanmode Option + * Unused */ if (inp == 1) { - localcmd("clan\n"); - Menu_Close(self); - self.current_menu_type = 0; - self.current_menu_page = 0; + return; } /* @@ -1226,7 +1223,7 @@ void (float inp) Menu_Admin_Input = * Kick Player Menu */ if (inp == 3) { - self.current_menu_type = 1; + self.current_menu_type = ADMIN_MENU_TYPE_KICK; self.current_menu_page = 1; Menu_Admin(); } @@ -1235,7 +1232,7 @@ void (float inp) Menu_Admin_Input = * Ban Player Menu */ if (inp == 4) { - self.current_menu_type = 2; + self.current_menu_type = ADMIN_MENU_TYPE_BAN; self.current_menu_page = 1; Menu_Admin(); } @@ -1266,7 +1263,7 @@ void (float inp) Menu_Admin_Input = if (inp == 5) { if (!captainmode) { captainmode = 1; - self.current_menu_type = 3; + self.current_menu_type = ADMIN_MENU_TYPE_CAPTAINTEAMONE; self.current_menu_page = 1; bprint(2, "\[\sCaptain Mode\s\]\s:\s is now \sON\s.\n"); @@ -1290,7 +1287,7 @@ void (float inp) Menu_Admin_Input = self = temppl; temppl.captain = 0; Menu_Close(self); - self.current_menu_type = 0; + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 0; temppl = find (temppl, classname, "player"); } @@ -1300,10 +1297,27 @@ void (float inp) Menu_Admin_Input = } // Actions for AdminMenu Page 1 - } else if (self.current_menu_type == 0 && self.current_menu_page == 2) { + } else if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN && self.current_menu_page == 2) { + + /* + * Toggle Clanmode Option + */ if (inp == 1) { - sprint(self, 2, "AdminMenu Page 2 Action 1\n"); + localcmd("clan\n"); + Menu_Close(self); + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + self.current_menu_page = 0; } + + /* + * quad mode, pub mode, duel mode + */ + if (inp == 3) { + self.current_menu_type = 6; + self.current_menu_page = 1; + Menu_Admin(); + } + else if (inp == 2) { sprint(self, 2, "AdminMenu Page 2 Action 2\n"); } @@ -1323,8 +1337,7 @@ void (float inp) Menu_Admin_Input = sprint(self, 2, "AdminMenu Page 2 Action 7\n"); } - - } else if ((self.current_menu_type == 1 || self.current_menu_type == 2 ) && inp >= 1 && inp <= 7) { // Kick / Ban Actions + } else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN ) && inp >= 1 && inp <= 7) { // Kick / Ban Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { @@ -1349,7 +1362,7 @@ void (float inp) Menu_Admin_Input = if (self.admin_use) { if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { self.admin_use.ip = infokey (self.admin_use, "ip"); - if (self.current_menu_type == 2) { + if (self.current_menu_type == ADMIN_MENU_TYPE_BAN) { localcmd("addip "); localcmd(self.admin_use.ip); localcmd("\n"); @@ -1357,31 +1370,31 @@ void (float inp) Menu_Admin_Input = Admin_DoKick(); } } - } else if ((self.current_menu_type == 3 || self.current_menu_type == 4 || self.current_menu_type == 5) && inp >= 1 && inp <= 7) { // Captain Actions + } else if ((self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) { // Captain Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { - if ( (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + if ( (f_tmp < ((self.current_menu_page - 1) * 7) + inp ) && ( ( (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO) && !self.admin_use.captain) || (self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMTWO) ) ) { f_tmp = f_tmp + 1; - } else if ( (f_tmp == ((self.current_menu_page - 1) * 7) + inp) && ( ( (self.current_menu_type == 5 || self.current_menu_type == 4) && !self.admin_use.captain) || (self.current_menu_type != 5 && self.current_menu_type != 4) ) ) { + } else if ( (f_tmp == ((self.current_menu_page - 1) * 7) + inp) && ( ( (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO) && !self.admin_use.captain) || (self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMTWO) ) ) { break; } self.admin_use = find (self.admin_use, classname, "player"); } - if (self.current_menu_type != 5) { + if (self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT) { if (self.admin_use != world) { if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { temp = self; self = self.admin_use; self.captain = 9; - if (temp.current_menu_type == 3) { + if (temp.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE) { // Captain for Team 1 self.team_no = 1; - temp.current_menu_type = 4; + temp.current_menu_type = ADMIN_MENU_TYPE_CAPTAINTEAMTWO; Menu_Admin(); - } else if (temp.current_menu_type == 4) { + } else if (temp.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO) { // Captain for Team 2 self.team_no = 2; @@ -1412,7 +1425,7 @@ void (float inp) Menu_Admin_Input = self = temp; bprint(2, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); Menu_Close(self); - self.current_menu_type = 0; + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 0; } self = temp; @@ -1437,7 +1450,7 @@ void (float inp) Menu_Admin_Input = nextCaptain(); Menu_Close(self); - self.current_menu_type = 0; + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 0; } } @@ -1457,7 +1470,7 @@ void (float inp) Menu_Admin_Input = //Closes menus, disables captain mode if (inp == 10) { - if (self.current_menu_type == 4 || self.current_menu_type == 5 || self.current_menu_type == 3) { + if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE) { captainmode = 0; bprint(2, "\[\sCaptain Mode\s\]\s:\s \scanceled by request of\s "); bprint(2, self.netname); @@ -1468,19 +1481,19 @@ void (float inp) Menu_Admin_Input = self = temp; temp.captain = 0; Menu_Close(self); - self.current_menu_type = 0; + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 0; temp = find (temp, classname, "player"); } self = te; } - if (self.current_menu_type == 0) { + if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN) { Menu_Close(self); - self.current_menu_type = 0; + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 0; } else if (self.is_admin) { - self.current_menu_type = 0; + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 1; Menu_Admin(); } From a9cf0044473222812213b994bd2c109556c9f727 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 21 Feb 2019 17:10:05 +1100 Subject: [PATCH 0606/2474] most of refactor done --- commands.qc | 56 ++++---- menu.qc | 371 +++++++++++++++++++++++++++------------------------- 2 files changed, 215 insertions(+), 212 deletions(-) diff --git a/commands.qc b/commands.qc index 04d4fd14..4e22359d 100644 --- a/commands.qc +++ b/commands.qc @@ -1,40 +1,28 @@ void () QuadMode = { - local string st; - - st = infokey (world, "quadmode"); - if ((st == "on")) - { - st = "off"; - localcmd ("localinfo clan off\n"); - localcmd ("localinfo quadmode off\n"); - localcmd ("localinfo rounds 0"); - } - else - { - st = "on"; - localcmd ("localinfo clan on\n"); - localcmd ("localinfo quadmode on\n"); - localcmd ("localinfo rounds 2\n"); - localcmd ("timelimit 0\n"); - localcmd ("localinfo round_time 10\n"); - bprint (2, "Map Restart needed to take effect!\n"); - } - bprint3 (2, "Quad Mode set to ", st, "\n"); + localcmd ("localinfo clan on\n"); + localcmd ("localinfo quadmode on\n"); + localcmd ("localinfo rounds 2\n"); + localcmd ("timelimit 0\n"); + localcmd ("localinfo round_time 10\n"); + bprint (2, "Map Restart needed to take effect!\n"); + bprint (2, "Quad Mode set to on\n"); }; void () ClanMode = { - local string st; - st = infokey(world, "clan"); - if (st == "on") { - st = "off"; - localcmd("localinfo clan off\n"); - } - else { - st = "on"; - localcmd("localinfo clan on\n"); - bprint(2, "Map Restart needed to take effect!\n"); - } - bprint3(2, "Clan Mode set to ", st, "\n"); -}; \ No newline at end of file + localcmd("localinfo clan on\n"); + bprint(2, "Map Restart needed to take effect!\n"); + bprint(2, "Clan Mode set to on\n"); +}; + +void () PubMode = +{ + localcmd("localinfo clan off"); + localcmd("localinfo quadmode off"); + localcmd("localinfo rounds 0"); + localcmd("timelimit 30\n"); + localcmd("localinfo round_time 0\n"); + bprint(2, "Map Restart needed to take effect!\n"); + bprint(2, "Pub Mode set to on\n"); +} \ No newline at end of file diff --git a/menu.qc b/menu.qc index b5f5f533..723a7bb9 100644 --- a/menu.qc +++ b/menu.qc @@ -1040,53 +1040,100 @@ void () Menu_Admin = s_menu1 = ""; s_menu2 = ""; - if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN) { - s_menu1 = "FortressOne Admin Menu: \n\n"; - if (self.current_menu_page == 1) { - s_menu1 = strcat(s_menu1, Q"\s[1]\s Not Used \n"); - s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit \n"); - s_menu1 = strcat(s_menu1, Q"\s[3]\s Kick \n"); - s_menu1 = strcat(s_menu1, Q"\s[4]\s Ban \n"); - s_menu1 = strcat(s_menu1, Q"\s[5]\s Captain \n"); - s_menu1 = strcat(s_menu1, Q"\s[6]\s Randomize Teams \n"); - s_menu1 = strcat(s_menu1, Q"\s[7]\s Restart current map \n"); - } else if (self.current_menu_page == 2) { - s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode \n"); - s_menu1 = strcat(s_menu1, Q"\s[2]\s Quad Mode \n"); - s_menu1 = strcat(s_menu1, Q"\s[3]\s Pub Mode \n"); - s_menu1 = strcat(s_menu1, Q"\s[4]\s Duel Mode (Not implemented) \n"); - s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); - s_menu1 = strcat(s_menu1, Q"\s[6]\s \n"); - s_menu1 = strcat(s_menu1, Q"\s[7]\s \n"); - } - s_menu1 = strcat(s_menu1, "\n\n"); - s_menu1 = strcat(s_menu1, Q"\s[8]\s Previous Page \n"); - s_menu1 = strcat(s_menu1, Q"\s[9]\s Next Page \n"); - s_menu1 = strcat(s_menu1, Q"\s[0]\s Exit Menu \n"); + switch (self.current_menu_type) + { + case ADMIN_MENU_TYPE_MAIN: + s_menu1 = "FortressOne Admin Menu: \n\n"; + if (self.current_menu_page == 1) { + s_menu1 = strcat(s_menu1, Q"\s[1]\s Not Used \n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit \n"); + s_menu1 = strcat(s_menu1, Q"\s[3]\s Kick \n"); + s_menu1 = strcat(s_menu1, Q"\s[4]\s Ban \n"); + s_menu1 = strcat(s_menu1, Q"\s[5]\s Captain \n"); + s_menu1 = strcat(s_menu1, Q"\s[6]\s Randomize Teams \n"); + s_menu1 = strcat(s_menu1, Q"\s[7]\s Restart current map \n"); + } else if (self.current_menu_page == 2) { + s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s Quad Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[3]\s Pub Mode \n"); + s_menu1 = strcat(s_menu1, Q"\s[4]\s Duel Mode (Not implemented) \n"); + s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[6]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[7]\s \n"); + } + s_menu1 = strcat(s_menu1, "\n\n"); + s_menu1 = strcat(s_menu1, Q"\s[8]\s Previous Page \n"); + s_menu1 = strcat(s_menu1, Q"\s[9]\s Next Page \n"); + s_menu1 = strcat(s_menu1, Q"\s[0]\s Exit Menu \n"); + + Status_Menu(self, Menu_Admin_Input, s_menu1); + break; + case ADMIN_MENU_TYPE_QUADMODE: + s_menu1 = "Quad Mode Admin Menu: \n\n"; + local string rounds, roundtime, pad; + local float roundlen, tlen, diff; + + exitpad = ""; + rounds = infokey(world, "rounds"); + roundlen = strlen(rounds); + + roundtime = infokey(world, "round_time"); + tlen = strlen(roundtime); + + diff = (roundlen - tlen); + + if (diff < 0) + { + while (diff < 0) + { + diff = diff + 1; + pad = strcat(" ", pad); + } + } + else if (diff > 0) + { + while (diff > 0) + { + diff = diff - 1; + pad = strcat(" ", pad); + } + } - Status_Menu(self, Menu_Admin_Input, s_menu1); - } + rounds = strcat("[", rounds, "]"); + roundtime = strcat("[", roundtime, "]"); + exitpad = strcat(" ", exitpad); -// 1 = kick selection menu -// 2 = ban selection menu -// 3 = team 1's captain select menu -// 4 = team 2's captain select menu -// 5 = captain player selection menu + s_menu1 = strcat(s_menu1, Q"\s[1]\s Rounds ", pad, rounds,"\n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s Round Timelimit ", pad, roundtime, "\n"); + s_menu1 = strcat(s_menu1, "\n\n"); + s_menu1 = strcat(s_menu1, Q"\s[0]\s Exit Menu ", pad, "\n"); - if (self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) { - if (self.current_menu_type == ADMIN_MENU_TYPE_KICK) { + Status_Menu(self, Menu_Admin_Input, s_menu1); + break; + case ADMIN_MENU_TYPE_KICK: s_menu1 = "Admin Kick Menu: \n\n"; - } else if (self.current_menu_type == ADMIN_MENU_TYPE_BAN) { + break; + case ADMIN_MENU_TYPE_BAN: s_menu1 = "Admin Ban Menu: \n\n"; - } else if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE) { + break; + case ADMIN_MENU_TYPE_CAPTAINTEAMONE: s_menu1 = "Captain Team 1 Select Menu: \n\n"; - } else if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO) { + break; + case ADMIN_MENU_TYPE_CAPTAINTEAMTWO: s_menu1 = "Captain Team 2 Select Menu: \n\n"; - } else if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) { + break; + case ADMIN_MENU_TYPE_CAPTAINSELECT: s_menu1 = strcat(Q"\[\sCaptain\s\] Team ", ftos(self.team_no)); s_menu1 = strcat(s_menu1, " : \n\n"); - } - + break; + } + + // jesus christ what is this, this should be separated out for the good of the people + // or maybe made understandable + if (self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) + { f_tmp = 0; f_tmp2 = 0; s_menu2 = strcat (s_menu2, "\bPlayers:\b \n"); @@ -1189,155 +1236,121 @@ void (float inp) Menu_Admin_Input = local float f_tmp; // Actions for AdminMenu Page 0 - if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN && self.current_menu_page == 1) { - - /* - * Unused - */ - if (inp == 1) { - return; - } - - /* - * Change Timelimit - */ - if (inp == 2) { - if (stof(infokey (world, "timelimit")) > 35) { - s_temp = "5"; - } else { - s_temp = ftos(timelimit/60 + 5); - } - - localcmd ("timelimit "); - localcmd(s_temp); - localcmd("\n"); - - bprint ( 2, self.netname); - bprint ( 2, " sets "); - bprint ( 2, "\stimelimit\s to: "); - bprint ( 2, s_temp); - bprint ( 2, "\n"); - } - - /* - * Kick Player Menu - */ - if (inp == 3) { - self.current_menu_type = ADMIN_MENU_TYPE_KICK; - self.current_menu_page = 1; - Menu_Admin(); - } - - /* - * Ban Player Menu - */ - if (inp == 4) { - self.current_menu_type = ADMIN_MENU_TYPE_BAN; - self.current_menu_page = 1; - Menu_Admin(); - } - - /* - * Restart Current Map Option - */ - if (inp == 7) { + if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN) { + if (self.current_menu_page == 1) + { + switch (inp) + { + case 1: // Unused + return; + case 2: // Change Timelimit + if (stof(infokey (world, "timelimit")) > 35) { + s_temp = "5"; + } else { + s_temp = ftos(timelimit/60 + 5); + } - bprint(2, self.netname); - bprint(2, " Has restarted the map.\n"); + localcmd ("timelimit "); + localcmd(s_temp); + localcmd("\n"); - localcmd ("map "); - localcmd (mapname); - localcmd ("\n"); - } + bprint ( 2, self.netname); + bprint ( 2, " sets "); + bprint ( 2, "\stimelimit\s to: "); + bprint ( 2, s_temp); + bprint ( 2, "\n"); + break; + case 3: // Kick Player Menu + self.current_menu_type = ADMIN_MENU_TYPE_KICK; + self.current_menu_page = 1; + Menu_Admin(); + break; + case 4: // Ban Player Menu + self.current_menu_type = ADMIN_MENU_TYPE_BAN; + self.current_menu_page = 1; + Menu_Admin(); + break; + case 5: // Toggle Captain (pickup) Mode + if (!captainmode) { + captainmode = 1; + self.current_menu_type = ADMIN_MENU_TYPE_CAPTAINTEAMONE; + self.current_menu_page = 1; + + bprint(2, "\[\sCaptain Mode\s\]\s:\s is now \sON\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + + temp = find (world, classname, "player"); + while (temp != world) { + temp.captain = 0; + temp = find (temp, classname, "player"); + } - /* - * Randomize Teams Option - */ - if (inp == 6) { - randomizeTeams(); - } + } else { // end captainmode1 + disableCaptain(); + local entity pl; + local entity temppl; + pl = self; + temppl = find (world, classname, "player"); + while (temppl != world) { + self = temppl; + temppl.captain = 0; + Menu_Close(self); + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + self.current_menu_page = 0; + temppl = find (temppl, classname, "player"); + } + self = pl; + } + Menu_Admin(); + break; + case 6: // Randomize Teams Option + randomizeTeams(); + break; - /* - * Toggle Captain (pickup) Mode - */ - if (inp == 5) { - if (!captainmode) { - captainmode = 1; - self.current_menu_type = ADMIN_MENU_TYPE_CAPTAINTEAMONE; - self.current_menu_page = 1; - - bprint(2, "\[\sCaptain Mode\s\]\s:\s is now \sON\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - - temp = find (world, classname, "player"); - while (temp != world) { - temp.captain = 0; - temp = find (temp, classname, "player"); - } + case 7: // Restart Current Map Option + bprint(2, self.netname); + bprint(2, " Has restarted the map.\n"); - } else { // end captainmode1 - disableCaptain(); - local entity pl; - local entity temppl; - pl = self; - temppl = find (world, classname, "player"); - while (temppl != world) { - self = temppl; - temppl.captain = 0; + localcmd ("map "); + localcmd (mapname); + localcmd ("\n"); + break; + } + } + else if (self.current_menu_page == 2) + { + switch (inp) + { + case 1: // Toggle Clanmode Option + ClanMode(); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 0; - temppl = find (temppl, classname, "player"); - } - self = pl; + break; + case 2: // quad mode + QuadMode(); + self.current_menu_type = ADMIN_MENU_TYPE_QUADMODE; + self.current_menu_page = 0; + Menu_Admin(); + break; + case 3: // pub mode + PubMode(); + Menu_Close(self); + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + self.current_menu_page = 0; + break; + case 4: // duel mode + bprint(2, "Not Implemented!\n"); + Menu_Close(self); + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + self.current_menu_page = 0; + break; } - Menu_Admin(); - - } - // Actions for AdminMenu Page 1 - } else if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN && self.current_menu_page == 2) { - - /* - * Toggle Clanmode Option - */ - if (inp == 1) { - localcmd("clan\n"); - Menu_Close(self); - self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; } - - /* - * quad mode, pub mode, duel mode - */ - if (inp == 3) { - self.current_menu_type = 6; - self.current_menu_page = 1; - Menu_Admin(); - } - - else if (inp == 2) { - sprint(self, 2, "AdminMenu Page 2 Action 2\n"); - } - else if (inp == 3) { - sprint(self, 2, "AdminMenu Page 2 Action 3\n"); - } - else if (inp == 4) { - sprint(self, 2, "AdminMenu Page 2 Action 4\n"); - } - else if (inp == 5) { - sprint(self, 2, "AdminMenu Page 2 Action 5\n"); - } - else if (inp == 6) { - sprint(self, 2, "AdminMenu Page 2 Action 6\n"); - } - else if (inp == 7) { - sprint(self, 2, "AdminMenu Page 2 Action 7\n"); - } - - } else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN ) && inp >= 1 && inp <= 7) { // Kick / Ban Actions + } else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN ) + && inp >= 1 && inp <= 7) { // Kick / Ban Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { @@ -1370,7 +1383,9 @@ void (float inp) Menu_Admin_Input = Admin_DoKick(); } } - } else if ((self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) { // Captain Actions + } else if ((self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) { // Captain Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { From eac730c8c526da04d53cd05c3db72690fed6d443 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 21 Feb 2019 22:12:38 +1300 Subject: [PATCH 0607/2474] Less squishing. Still some nuances --- spy.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spy.qc b/spy.qc index 29228642..11f53d19 100644 --- a/spy.qc +++ b/spy.qc @@ -399,9 +399,9 @@ void () CF_Spy_AirThink = { } } - // if spy is in the air, set movetype to walk (so he falls to ground) + // if spy is in the air, set movetype to walk^H^H^H^H toss (so he falls to ground) else { - self.owner.movetype = MOVETYPE_WALK; + self.owner.movetype = MOVETYPE_TOSS; } TeamFortress_SetSpeed(self.owner); @@ -1418,4 +1418,4 @@ void () Spy_DropBackpack = { newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; \ No newline at end of file +}; From d5fa60bd847f28b7314e8d76e121896ceb1e125f Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 22 Feb 2019 00:08:02 +1100 Subject: [PATCH 0608/2474] finish menus for quadmode etc --- commands.qc | 18 ++++---- defs.h | 7 +-- menu.qc | 124 ++++++++++++++++++++++++++++++++-------------------- 3 files changed, 88 insertions(+), 61 deletions(-) diff --git a/commands.qc b/commands.qc index 4e22359d..6debbc74 100644 --- a/commands.qc +++ b/commands.qc @@ -5,24 +5,24 @@ void () QuadMode = localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); - bprint (2, "Map Restart needed to take effect!\n"); bprint (2, "Quad Mode set to on\n"); + bprint (2, "Map Restart needed to take effect!\n"); }; void () ClanMode = { localcmd("localinfo clan on\n"); - bprint(2, "Map Restart needed to take effect!\n"); - bprint(2, "Clan Mode set to on\n"); + bprint(2, "Clan Mode set to on\n"); + bprint(2, "Map Restart needed to take effect!\n"); }; void () PubMode = { - localcmd("localinfo clan off"); - localcmd("localinfo quadmode off"); - localcmd("localinfo rounds 0"); - localcmd("timelimit 30\n"); + localcmd("localinfo clan off\n"); + localcmd("localinfo quadmode off\n"); + localcmd("localinfo rounds 0\n"); + localcmd("timelimit 20\n"); localcmd("localinfo round_time 0\n"); - bprint(2, "Map Restart needed to take effect!\n"); - bprint(2, "Pub Mode set to on\n"); + bprint(2, "Pub Mode set to on\n"); + bprint(2, "Map Restart needed to take effect!\n"); } \ No newline at end of file diff --git a/defs.h b/defs.h index 65d130bc..df00d68a 100644 --- a/defs.h +++ b/defs.h @@ -321,11 +321,6 @@ // through the playerclass. // admin menu page consts -// 1 = kick selection menu -// 2 = ban selection menu -// 3 = team 1's captain select menu -// 4 = team 2's captain select menu -// 5 = captain player selection menu #define ADMIN_MENU_TYPE_MAIN 0 #define ADMIN_MENU_TYPE_KICK 1 #define ADMIN_MENU_TYPE_BAN 2 @@ -333,6 +328,8 @@ #define ADMIN_MENU_TYPE_CAPTAINTEAMTWO 4 #define ADMIN_MENU_TYPE_CAPTAINSELECT 5 #define ADMIN_MENU_TYPE_QUADMODE 6 +#define ADMIN_MENU_TYPE_QUAD_ROUNDNUM 7 +#define ADMIN_MENU_TYPE_QUAD_ROUNDTL 8 /*======================================================*/ diff --git a/menu.qc b/menu.qc index 723a7bb9..4b23060a 100644 --- a/menu.qc +++ b/menu.qc @@ -1015,6 +1015,9 @@ void () Menu_Engineer_Cancel = { Status_Menu(self, Menu_Engineer_Cancel_Input, s_build, s_cancel); } +void () ClanMode; +void () QuadMode; +void () PubMode; void () Menu_Admin = { local string s_menu1; @@ -1070,43 +1073,25 @@ void () Menu_Admin = break; case ADMIN_MENU_TYPE_QUADMODE: s_menu1 = "Quad Mode Admin Menu: \n\n"; - local string rounds, roundtime, pad; - local float roundlen, tlen, diff; - exitpad = ""; - rounds = infokey(world, "rounds"); - roundlen = strlen(rounds); - - roundtime = infokey(world, "round_time"); - tlen = strlen(roundtime); - - diff = (roundlen - tlen); - - if (diff < 0) - { - while (diff < 0) - { - diff = diff + 1; - pad = strcat(" ", pad); - } - } - else if (diff > 0) - { - while (diff > 0) - { - diff = diff - 1; - pad = strcat(" ", pad); - } - } + s_menu1 = strcat(s_menu1, Q"\s[1]\s Rounds \n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s Round Timelimit \n"); + s_menu1 = strcat(s_menu1, "\n\n"); + s_menu1 = strcat(s_menu1, Q"\s[0]\s Exit Menu \n"); - rounds = strcat("[", rounds, "]"); - roundtime = strcat("[", roundtime, "]"); - exitpad = strcat(" ", exitpad); + Status_Menu(self, Menu_Admin_Input, s_menu1); + break; + case ADMIN_MENU_TYPE_QUAD_ROUNDNUM: + s_menu1 = "Number of Rounds Input Menu: \n\n"; + s_menu1 = strcat(s_menu1, "Enter a number between 1 and 10 \n"); + s_menu1 = strcat(s_menu1, "\n\n"); - s_menu1 = strcat(s_menu1, Q"\s[1]\s Rounds ", pad, rounds,"\n"); - s_menu1 = strcat(s_menu1, Q"\s[2]\s Round Timelimit ", pad, roundtime, "\n"); + Status_Menu(self, Menu_Admin_Input, s_menu1); + break; + case ADMIN_MENU_TYPE_QUAD_ROUNDTL: + s_menu1 = "Round Time Input Menu: \n\n"; + s_menu1 = strcat(s_menu1, "Enter a number between 1 and 10 \n"); s_menu1 = strcat(s_menu1, "\n\n"); - s_menu1 = strcat(s_menu1, Q"\s[0]\s Exit Menu ", pad, "\n"); Status_Menu(self, Menu_Admin_Input, s_menu1); break; @@ -1197,7 +1182,7 @@ void () Menu_Admin = self = te; Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; te = find (te, classname, "player"); } self = temp; @@ -1298,7 +1283,7 @@ void (float inp) Menu_Admin_Input = temppl.captain = 0; Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; temppl = find (temppl, classname, "player"); } self = pl; @@ -1327,30 +1312,32 @@ void (float inp) Menu_Admin_Input = ClanMode(); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; break; case 2: // quad mode QuadMode(); self.current_menu_type = ADMIN_MENU_TYPE_QUADMODE; - self.current_menu_page = 0; + self.current_menu_page = 1; Menu_Admin(); break; case 3: // pub mode PubMode(); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; break; case 4: // duel mode bprint(2, "Not Implemented!\n"); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; break; } } - } else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN ) - && inp >= 1 && inp <= 7) { // Kick / Ban Actions + } + else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN ) + && inp >= 1 && inp <= 7) + { // Kick / Ban Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { @@ -1383,9 +1370,11 @@ void (float inp) Menu_Admin_Input = Admin_DoKick(); } } - } else if ((self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE + } + else if ((self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) { // Captain Actions + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) + { // Captain Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { @@ -1441,7 +1430,7 @@ void (float inp) Menu_Admin_Input = bprint(2, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; } self = temp; } @@ -1466,20 +1455,61 @@ void (float inp) Menu_Admin_Input = nextCaptain(); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; } } + } + else if (self.current_menu_type == ADMIN_MENU_TYPE_QUADMODE) + { + switch (inp) + { + case 1: + // rounds + self.current_menu_type = ADMIN_MENU_TYPE_QUAD_ROUNDNUM; + self.current_menu_page = 1; + Menu_Admin(); + break; + case 2: + // round time limit + self.current_menu_type = ADMIN_MENU_TYPE_QUAD_ROUNDTL; + self.current_menu_page = 1; + Menu_Admin(); + break; + } } + else if (self.current_menu_type == ADMIN_MENU_TYPE_QUAD_ROUNDNUM) + { + local string cmd; + cmd = strcat("localinfo rounds ", ftos(inp), "\n"); + localcmd(cmd); + bprint(2, "Quad Round Number changed to ", ftos(inp), "\n"); + self.current_menu_type = ADMIN_MENU_TYPE_QUADMODE; + self.current_menu_page = 1; + Menu_Admin(); + } + else if (self.current_menu_type == ADMIN_MENU_TYPE_QUAD_ROUNDTL) + { + local string d; + d = strcat("localinfo round_time ", ftos(inp), "\n"); + localcmd(d); + bprint(2, "Quad Round Timelimit changed to ", ftos(inp), "\n"); + self.current_menu_type = ADMIN_MENU_TYPE_QUADMODE; + self.current_menu_page = 1; + Menu_Admin(); + } + //Previous page if (inp == 8) { if (self.current_menu_page > 1) { self.current_menu_page = self.current_menu_page - 1; + Menu_Admin(); } } //Next page if (inp == 9) { if (self.current_menu_page < 5) { self.current_menu_page = self.current_menu_page + 1; + Menu_Admin(); } } @@ -1497,7 +1527,7 @@ void (float inp) Menu_Admin_Input = temp.captain = 0; Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; temp = find (temp, classname, "player"); } self = te; @@ -1505,7 +1535,7 @@ void (float inp) Menu_Admin_Input = if (self.current_menu_type == ADMIN_MENU_TYPE_MAIN) { Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 0; + self.current_menu_page = 1; } else if (self.is_admin) { self.current_menu_type = ADMIN_MENU_TYPE_MAIN; From df8590a3b5dcd8d64bc3e915f1ee4af7ad09f5b4 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 23 Feb 2019 12:31:46 +1100 Subject: [PATCH 0609/2474] add more settings to game modes --- commands.qc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/commands.qc b/commands.qc index 6debbc74..ec2d5982 100644 --- a/commands.qc +++ b/commands.qc @@ -5,6 +5,10 @@ void () QuadMode = localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); + localcmd ("localinfo teamfrags on\n"); + localcmd ("localinfo fullteamscore off\n"); + localcmd ("password pineapple\n"); + localcmd ("fraglimit 0\n"); bprint (2, "Quad Mode set to on\n"); bprint (2, "Map Restart needed to take effect!\n"); }; @@ -20,9 +24,24 @@ void () PubMode = { localcmd("localinfo clan off\n"); localcmd("localinfo quadmode off\n"); + localcmd ("localinfo teamfrags off\n"); + localcmd ("localinfo fullteamscore off\n"); + localcmd ("password none\n"); localcmd("localinfo rounds 0\n"); localcmd("timelimit 20\n"); + localcmd ("fraglimit 0\n"); localcmd("localinfo round_time 0\n"); bprint(2, "Pub Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); +} + +void () DuelMode = +{ + localcmd ("localinfo teamfrags off\n"); + localcmd ("localinfo fullteamscore off\n"); + localcmd("localinfo clan off\n"); + localcmd("localinfo quadmode off\n"); + localcmd ("password none\n"); + localcmd("timelimit 0\n"); + localcmd ("fraglimit 30\n"); } \ No newline at end of file From 58e6475df94dfe0ba3d1fad22f59d8f5e802d02f Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 23 Feb 2019 12:32:18 +1100 Subject: [PATCH 0610/2474] bprints for duelmode --- commands.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commands.qc b/commands.qc index ec2d5982..c2d27564 100644 --- a/commands.qc +++ b/commands.qc @@ -44,4 +44,6 @@ void () DuelMode = localcmd ("password none\n"); localcmd("timelimit 0\n"); localcmd ("fraglimit 30\n"); + bprint(2, "Duel Mode set to on\n"); + bprint(2, "Map Restart needed to take effect!\n"); } \ No newline at end of file From f26f0eb4b17e37a556de372053e29fb55d384134 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 23 Feb 2019 16:01:46 +1100 Subject: [PATCH 0611/2474] q3f intermission support --- client.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client.qc b/client.qc index 429106c5..d8f6e02f 100644 --- a/client.qc +++ b/client.qc @@ -631,6 +631,12 @@ entity()FindIntermission = } return (spot); } + + // q3f + spot = find(world, classname, "info_player_intermission"); + if (spot) + return (spot); + objerror("FindIntermission: no spot"); return (world); }; From 474e82270dba51a70404c0308214032193d81285 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 23 Feb 2019 23:44:56 +1100 Subject: [PATCH 0612/2474] q3f intermission ent --- client.qc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index d8f6e02f..3a618a95 100644 --- a/client.qc +++ b/client.qc @@ -68,6 +68,15 @@ void () info_intermission = } }; +void () info_player_intermission = +{ + self.classname = "info_intermission"; + if (CheckExistence() == 0) { + dremove(self); + return; + } +}; + void () SetChangeParms = { if (self.health <= 0) { SetNewParms(); @@ -632,11 +641,6 @@ entity()FindIntermission = return (spot); } - // q3f - spot = find(world, classname, "info_player_intermission"); - if (spot) - return (spot); - objerror("FindIntermission: no spot"); return (world); }; From e6432a0d59f6e8dab4fd573246db34026221bf01 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 24 Feb 2019 11:47:28 +1100 Subject: [PATCH 0613/2474] fix for hwguy not able to attack on fte server --- player.qc | 4 ++-- weapons.qc | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/player.qc b/player.qc index 1c85ffbb..b38267f3 100644 --- a/player.qc +++ b/player.qc @@ -447,7 +447,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { player_assaultcannondown1(); return; } - Attack_Finished(0.1); + Attack_Finished(0.2); }; void () player_assaultcannon2 =[104, player_assaultcannon1] { @@ -477,7 +477,7 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { player_assaultcannondown1(); return; } - Attack_Finished(0.1); + Attack_Finished(0.2); }; void () player_assaultcannondown1 =[103, player_assaultcannondown1] { diff --git a/weapons.qc b/weapons.qc index e624ac09..d2d78158 100644 --- a/weapons.qc +++ b/weapons.qc @@ -164,10 +164,7 @@ float () crandom = { }; void (float att_delay) Attack_Finished = { - if (self.tfstate & 32768) - self.attack_finished = time + att_delay * 2; - else - self.attack_finished = time + att_delay; + self.attack_finished = time + att_delay; }; void () W_FireAxe = { @@ -1999,7 +1996,7 @@ float (entity pl) WeaponReady = { if (time >= pl.attack_finished && !(pl.tfstate & TFSTATE_RELOADING)) { return 1; } - + return 0; } @@ -3083,7 +3080,7 @@ void () DeadImpulses = { self.impulse = 0; return; } - PlayerReady(); self.impulse = 0; + PlayerReady(); self.impulse = 0; return; } @@ -3095,7 +3092,7 @@ void () DeadImpulses = { self.impulse = 0; return; } - PlayerNotReady(); self.impulse = 0; + PlayerNotReady(); self.impulse = 0; return; } From 77b3b4a2be4e167f4a548ff6a99c987b880f4a69 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 24 Feb 2019 12:51:18 +1100 Subject: [PATCH 0614/2474] more fte fixes for assault cannon --- player.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/player.qc b/player.qc index b38267f3..0d13b6c3 100644 --- a/player.qc +++ b/player.qc @@ -366,7 +366,7 @@ void () player_assaultcannonup1 =[103, player_assaultcannonup2] { sound(self, 1, "weapons/asscan1.wav", 1, 1); } SuperDamageSound(); - Attack_Finished(0.1); + Attack_Finished(0.2); if ((self.heat != 2) && (self.heat != 4)) { if (self.weaponframe >= 3) { self.weaponframe = 0; @@ -391,7 +391,7 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { return; } SuperDamageSound(); - Attack_Finished(0.1); + Attack_Finished(0.2); if (((self.heat != 2) && (self.heat != 4)) && (self.heat != 7)) { if ((self.weaponframe == 2) && (self.heat >= 9)) { self.weaponframe = 0; @@ -510,7 +510,7 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { } } self.count = self.count + 1; - Attack_Finished(0.1); + Attack_Finished(0.2); }; void () player_light1 =[105, player_light2] { From 075f2cf0451a980bc32474b036a2893dd35aae8f Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 24 Feb 2019 15:49:00 +1100 Subject: [PATCH 0615/2474] supress warning --- client.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/client.qc b/client.qc index 3a618a95..8ffbe80d 100644 --- a/client.qc +++ b/client.qc @@ -859,6 +859,7 @@ float () CloseToSpawnPoint = { local entity te = nil; local float i; string searchstr; + searchstr = ""; switch (self.team_no) { From da473db9393d40290ced44232085a96d4fdbcb03 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 24 Feb 2019 18:04:03 +1100 Subject: [PATCH 0616/2474] fix for tranq --- weapons.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/weapons.qc b/weapons.qc index d2d78158..ffc01b20 100644 --- a/weapons.qc +++ b/weapons.qc @@ -164,7 +164,10 @@ float () crandom = { }; void (float att_delay) Attack_Finished = { - self.attack_finished = time + att_delay; + if (self.tfstate & TFSTATE_TRANQUILISED) + self.attack_finished = time + att_delay * 2; + else + self.attack_finished = time + att_delay; }; void () W_FireAxe = { From 09f4cfccce92685e24004ebbbd023d88a2586d73 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 25 Feb 2019 16:37:50 +1100 Subject: [PATCH 0617/2474] update quadmode consts --- quadmode.qc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/quadmode.qc b/quadmode.qc index e3304ecd..91098408 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -132,9 +132,9 @@ void () QuadRoundBegin = { while (te != world) { oldself = self; self = te; - self.takedamage = 2; - self.solid = 3; - self.movetype = 3; + self.takedamage = DAMAGE_AIM; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_WALK; TeamFortress_RemoveTimers(); setspawnparms(self); PutClientInServer(); @@ -190,9 +190,9 @@ void () QuadRoundInit = { p = find(world, classname, "player"); while (p != world) { if (p.netname != "") { - p.takedamage = 2; - p.solid = 3; - p.movetype = 3; + p.takedamage = DAMAGE_AIM; + p.solid = SOLID_SLIDEBOX; + p.movetype = MOVETYPE_WALK; } p = find(p, classname, "player"); } @@ -231,9 +231,9 @@ void () StartQuadRound = p = find(world, classname, "player"); while (p != world) { if (p.netname != "") { - p.takedamage = 0; - p.solid = 0; - p.movetype = 0; + p.takedamage = DAMAGE_NO; + p.solid = SOLID_NOT; + p.movetype = MOVETYPE_NONE; p.modelindex = 0; p.model = string_null; } @@ -255,9 +255,9 @@ void () StartQuadRound = p = find (world, classname, "player"); while (p != world) { if (p.netname != "") { - p.takedamage = 0; - p.solid = 0; - p.movetype = 0; + p.takedamage = DAMAGE_NO; + p.solid = SOLID_NOT; + p.movetype = MOVETYPE_NONE; p.modelindex = 0; p.model = string_null; } From 95ac39bbf18ffd846cd021893705c3e43d044d7b Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 25 Feb 2019 17:18:43 +1100 Subject: [PATCH 0618/2474] execute a config file after setting defaults --- commands.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/commands.qc b/commands.qc index c2d27564..d88b2e45 100644 --- a/commands.qc +++ b/commands.qc @@ -5,10 +5,12 @@ void () QuadMode = localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); + localcmd ("localinfo round_delay_time 30\n"); localcmd ("localinfo teamfrags on\n"); localcmd ("localinfo fullteamscore off\n"); localcmd ("password pineapple\n"); localcmd ("fraglimit 0\n"); + localcmd ("exec of_quadmode.cfg\n"); bprint (2, "Quad Mode set to on\n"); bprint (2, "Map Restart needed to take effect!\n"); }; @@ -16,6 +18,7 @@ void () QuadMode = void () ClanMode = { localcmd("localinfo clan on\n"); + localcmd ("exec of_clanmode.cfg\n"); bprint(2, "Clan Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); }; @@ -31,6 +34,7 @@ void () PubMode = localcmd("timelimit 20\n"); localcmd ("fraglimit 0\n"); localcmd("localinfo round_time 0\n"); + localcmd ("exec of_pubmode.cfg\n"); bprint(2, "Pub Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); } @@ -44,6 +48,7 @@ void () DuelMode = localcmd ("password none\n"); localcmd("timelimit 0\n"); localcmd ("fraglimit 30\n"); + localcmd ("exec of_duelmode.cfg\n"); bprint(2, "Duel Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); } \ No newline at end of file From 2b36d9d51c1aa591059afdf75b9588bffd45aec1 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 25 Feb 2019 17:19:34 +1100 Subject: [PATCH 0619/2474] make round_delay_time localinfo used between rounds instead of default 10 seconds --- quadmode.qc | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/quadmode.qc b/quadmode.qc index 91098408..ec217843 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -91,7 +91,12 @@ void () QuadRoundThink = { } if (!self.cnt) { if (rounds > 1) - bprint(2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); + { + local string st; + st = infokey(world, "round_delay_time"); + bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); + } + // lightstyle (0, "e"); @@ -123,7 +128,7 @@ void () QuadRoundBegin = { te = find(world, classname, "func_breakable"); while (te) { setmodel(te, te.mdl); - te.solid = 4; + te.solid = SOLID_BSP; te = find(te, classname, "func_breakable"); } cb_prematch = 0; @@ -199,18 +204,21 @@ void () QuadRoundInit = { return; } } - if (self.cnt2 <= 5) { - num = ftos(self.cnt2); - p = find (world, classname, "player"); - while (p != world) { - if (p.netname != "") { - CenterPrint3(p, "Round begins in: ", num, " second(s).\n"); - cease_fire = 0; - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); - } - } + + num = ftos(self.cnt2); + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + CenterPrint3(p, "Round begins in: ", num, " second(s).\nEnsure correct class is chosen!\n"); + + if (self.cnt2 <= 5) + { + cease_fire = 0; + stuffcmd(p, "play buttons/switch04.wav\n"); + } + } + p = find(p, classname, "player"); + } self.nextthink = (time + 1); }; @@ -345,7 +353,11 @@ void () StartQuadRound = if ((fl < 3) || (fl > 20)) { fl = 10; } - te.cnt2 = 10; + + local float rdt; + st = infokey(world, "round_delay_time"); + rdt = ftos(st); + te.cnt2 = rdt; st = infokey (world, "round_time"); te.cnt = stof (st); quad_winner = CheckWinningTeam(); @@ -364,7 +376,9 @@ void () EndQuadRound = { if (infokey(world, "quadmode") == "on") { if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { if (rounds > 1) { - bprint (2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); + local string st; + st = infokey(world, "round_delay_time"); + bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); lightstyle (0, "e"); self.think = QuadRoundOver; self.nextthink = (time + 0.1); From 6765829f9fd6c8dd4b28663a40637380ab8625c1 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 25 Feb 2019 17:32:24 +1100 Subject: [PATCH 0620/2474] committed here instead --- commands.qc | 5 +++++ quadmode.qc | 46 ++++++++++++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/commands.qc b/commands.qc index c2d27564..d88b2e45 100644 --- a/commands.qc +++ b/commands.qc @@ -5,10 +5,12 @@ void () QuadMode = localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); + localcmd ("localinfo round_delay_time 30\n"); localcmd ("localinfo teamfrags on\n"); localcmd ("localinfo fullteamscore off\n"); localcmd ("password pineapple\n"); localcmd ("fraglimit 0\n"); + localcmd ("exec of_quadmode.cfg\n"); bprint (2, "Quad Mode set to on\n"); bprint (2, "Map Restart needed to take effect!\n"); }; @@ -16,6 +18,7 @@ void () QuadMode = void () ClanMode = { localcmd("localinfo clan on\n"); + localcmd ("exec of_clanmode.cfg\n"); bprint(2, "Clan Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); }; @@ -31,6 +34,7 @@ void () PubMode = localcmd("timelimit 20\n"); localcmd ("fraglimit 0\n"); localcmd("localinfo round_time 0\n"); + localcmd ("exec of_pubmode.cfg\n"); bprint(2, "Pub Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); } @@ -44,6 +48,7 @@ void () DuelMode = localcmd ("password none\n"); localcmd("timelimit 0\n"); localcmd ("fraglimit 30\n"); + localcmd ("exec of_duelmode.cfg\n"); bprint(2, "Duel Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); } \ No newline at end of file diff --git a/quadmode.qc b/quadmode.qc index 91098408..ec217843 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -91,7 +91,12 @@ void () QuadRoundThink = { } if (!self.cnt) { if (rounds > 1) - bprint(2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); + { + local string st; + st = infokey(world, "round_delay_time"); + bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); + } + // lightstyle (0, "e"); @@ -123,7 +128,7 @@ void () QuadRoundBegin = { te = find(world, classname, "func_breakable"); while (te) { setmodel(te, te.mdl); - te.solid = 4; + te.solid = SOLID_BSP; te = find(te, classname, "func_breakable"); } cb_prematch = 0; @@ -199,18 +204,21 @@ void () QuadRoundInit = { return; } } - if (self.cnt2 <= 5) { - num = ftos(self.cnt2); - p = find (world, classname, "player"); - while (p != world) { - if (p.netname != "") { - CenterPrint3(p, "Round begins in: ", num, " second(s).\n"); - cease_fire = 0; - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); - } - } + + num = ftos(self.cnt2); + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + CenterPrint3(p, "Round begins in: ", num, " second(s).\nEnsure correct class is chosen!\n"); + + if (self.cnt2 <= 5) + { + cease_fire = 0; + stuffcmd(p, "play buttons/switch04.wav\n"); + } + } + p = find(p, classname, "player"); + } self.nextthink = (time + 1); }; @@ -345,7 +353,11 @@ void () StartQuadRound = if ((fl < 3) || (fl > 20)) { fl = 10; } - te.cnt2 = 10; + + local float rdt; + st = infokey(world, "round_delay_time"); + rdt = ftos(st); + te.cnt2 = rdt; st = infokey (world, "round_time"); te.cnt = stof (st); quad_winner = CheckWinningTeam(); @@ -364,7 +376,9 @@ void () EndQuadRound = { if (infokey(world, "quadmode") == "on") { if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { if (rounds > 1) { - bprint (2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); + local string st; + st = infokey(world, "round_delay_time"); + bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); lightstyle (0, "e"); self.think = QuadRoundOver; self.nextthink = (time + 0.1); From 93c63dea7a5acba5335b5e5e6ca96997a656a1a7 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 25 Feb 2019 17:36:03 +1100 Subject: [PATCH 0621/2474] undo last two commits as they should be on a branch --- commands.qc | 5 ----- quadmode.qc | 48 +++++++++++++++++------------------------------- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/commands.qc b/commands.qc index d88b2e45..c2d27564 100644 --- a/commands.qc +++ b/commands.qc @@ -5,12 +5,10 @@ void () QuadMode = localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); - localcmd ("localinfo round_delay_time 30\n"); localcmd ("localinfo teamfrags on\n"); localcmd ("localinfo fullteamscore off\n"); localcmd ("password pineapple\n"); localcmd ("fraglimit 0\n"); - localcmd ("exec of_quadmode.cfg\n"); bprint (2, "Quad Mode set to on\n"); bprint (2, "Map Restart needed to take effect!\n"); }; @@ -18,7 +16,6 @@ void () QuadMode = void () ClanMode = { localcmd("localinfo clan on\n"); - localcmd ("exec of_clanmode.cfg\n"); bprint(2, "Clan Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); }; @@ -34,7 +31,6 @@ void () PubMode = localcmd("timelimit 20\n"); localcmd ("fraglimit 0\n"); localcmd("localinfo round_time 0\n"); - localcmd ("exec of_pubmode.cfg\n"); bprint(2, "Pub Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); } @@ -48,7 +44,6 @@ void () DuelMode = localcmd ("password none\n"); localcmd("timelimit 0\n"); localcmd ("fraglimit 30\n"); - localcmd ("exec of_duelmode.cfg\n"); bprint(2, "Duel Mode set to on\n"); bprint(2, "Map Restart needed to take effect!\n"); } \ No newline at end of file diff --git a/quadmode.qc b/quadmode.qc index ec217843..bf258c59 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -91,12 +91,7 @@ void () QuadRoundThink = { } if (!self.cnt) { if (rounds > 1) - { - local string st; - st = infokey(world, "round_delay_time"); - bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); - } - + bprint(2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); // lightstyle (0, "e"); @@ -128,7 +123,7 @@ void () QuadRoundBegin = { te = find(world, classname, "func_breakable"); while (te) { setmodel(te, te.mdl); - te.solid = SOLID_BSP; + te.solid = 4; te = find(te, classname, "func_breakable"); } cb_prematch = 0; @@ -204,21 +199,18 @@ void () QuadRoundInit = { return; } } - - num = ftos(self.cnt2); - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - CenterPrint3(p, "Round begins in: ", num, " second(s).\nEnsure correct class is chosen!\n"); - - if (self.cnt2 <= 5) - { - cease_fire = 0; - stuffcmd(p, "play buttons/switch04.wav\n"); - } - } - p = find(p, classname, "player"); - } + if (self.cnt2 <= 5) { + num = ftos(self.cnt2); + p = find (world, classname, "player"); + while (p != world) { + if (p.netname != "") { + CenterPrint3(p, "Round begins in: ", num, " second(s).\n"); + cease_fire = 0; + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find(p, classname, "player"); + } + } self.nextthink = (time + 1); }; @@ -353,11 +345,7 @@ void () StartQuadRound = if ((fl < 3) || (fl > 20)) { fl = 10; } - - local float rdt; - st = infokey(world, "round_delay_time"); - rdt = ftos(st); - te.cnt2 = rdt; + te.cnt2 = 10; st = infokey (world, "round_time"); te.cnt = stof (st); quad_winner = CheckWinningTeam(); @@ -376,9 +364,7 @@ void () EndQuadRound = { if (infokey(world, "quadmode") == "on") { if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { if (rounds > 1) { - local string st; - st = infokey(world, "round_delay_time"); - bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); + bprint (2, "ROUND TIME OVER\nNext round begins in 10 seconds\n"); lightstyle (0, "e"); self.think = QuadRoundOver; self.nextthink = (time + 0.1); @@ -388,4 +374,4 @@ void () EndQuadRound = { } } } -}; +}; \ No newline at end of file From e99cbaa25fd867bf0b7ae3d723635a5cf6c83759 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 25 Feb 2019 20:53:33 +1100 Subject: [PATCH 0622/2474] change function --- quadmode.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quadmode.qc b/quadmode.qc index ec217843..1d383469 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -356,7 +356,7 @@ void () StartQuadRound = local float rdt; st = infokey(world, "round_delay_time"); - rdt = ftos(st); + rdt = stof(st); te.cnt2 = rdt; st = infokey (world, "round_time"); te.cnt = stof (st); From c07fc931a71b1a44eff068bdf6f3feb48fe9fe7e Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 27 Feb 2019 23:06:16 +1100 Subject: [PATCH 0623/2474] fix spy disguise bug --- client.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client.qc b/client.qc index 8ffbe80d..8e9fdc9c 100644 --- a/client.qc +++ b/client.qc @@ -1222,6 +1222,8 @@ void () PutClientInServer = { if (self.playerclass != PC_ENGINEER) Engineer_RemoveBuildings(self); + self.skin = self.playerclass; + self.takedamage = 2; TeamFortress_PrintClassName(self, self.playerclass, From b8809988c311869807ee004943228c89eb878a15 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 1 Mar 2019 08:17:12 +1300 Subject: [PATCH 0624/2474] the setsize call seems to help --- tfortmap.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/tfortmap.qc b/tfortmap.qc index ace8c73d..9f525dc2 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -652,6 +652,7 @@ void (entity Goal) RestoreGoal = { Goal.goal_state = 2; if (Goal.mdl != string_null) { setmodel(Goal, Goal.mdl); + setsize(Goal, Goal.goal_min, Goal.goal_max); } if (Goal.model == "progs/tf_flag.mdl" || Goal.model == "progs/tf_stan.mdl") { Goal.effects = Goal.effects | EF_DIMLIGHT; From f634b890c45776dfde8471c191a79d8c02cc4306 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 8 Mar 2019 20:26:42 +1300 Subject: [PATCH 0625/2474] Works for most scenarios --- buttons.qc | 3 +++ doors.qc | 6 ++++++ plats.qc | 5 +++++ spy.qc | 24 ++++++++++++++++++++++-- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/buttons.qc b/buttons.qc index 62031067..d9d800fb 100644 --- a/buttons.qc +++ b/buttons.qc @@ -3,6 +3,7 @@ #define BUTTON_START_OUT 32 void () button_return; +void (entity pe_player, float stopdead) Spy_CheckForFuncTouch; void () button_wait = { self.state = STATE_TOP; @@ -70,6 +71,8 @@ void () button_touch = { if (other.classname != "player") return; + Spy_CheckForFuncTouch(other, 0); + if (self.goal_activation & TFGA_SPANNER) return; diff --git a/doors.qc b/doors.qc index a35b9db5..adddce58 100644 --- a/doors.qc +++ b/doors.qc @@ -1,6 +1,7 @@ void () door_go_down; void () door_go_up; +void (entity pe_player, float stopdead) Spy_CheckForFuncTouch; void () door_blocked = { if (other.classname == "detpack") { @@ -151,6 +152,9 @@ void () door_touch = { if (other.classname != "player") return; + + Spy_CheckForFuncTouch(other, 0); + if (self.owner.attack_finished > time) return; @@ -541,6 +545,8 @@ void () secret_touch = { if (other.classname != "player") return; + Spy_CheckForFuncTouch(other, 0); + if (self.attack_finished > time) return; diff --git a/plats.qc b/plats.qc index db586023..1625cf32 100644 --- a/plats.qc +++ b/plats.qc @@ -5,6 +5,7 @@ void () plat_trigger_use; void () plat_go_up; void () plat_go_down; void () plat_crush; +void (entity pe_player, float stopdead) Spy_CheckForFuncTouch; void () plat_spawn_inside_trigger = { local entity trigger; @@ -83,6 +84,8 @@ void () plat_center_touch = { if (other.playerclass == 0) return; + Spy_CheckForFuncTouch(other, 1); + if (!Activated(self, other)) { if (self.else_goal != 0) { te = Findgoal(self.else_goal); @@ -108,6 +111,8 @@ void () plat_outside_touch = { if (other.classname != "player") return; + Spy_CheckForFuncTouch(other, 0); + if (!Activated(self, other)) { if (self.else_goal != 0) { te = Findgoal(self.else_goal); diff --git a/spy.qc b/spy.qc index d816d3d7..78070a98 100644 --- a/spy.qc +++ b/spy.qc @@ -372,6 +372,20 @@ float (entity pe_player) Spy_CheckArea = { return 0; }; +void (entity pe_player, float stopdead) Spy_CheckForFuncTouch = { + if (pe_player.classname == "player" && pe_player.playerclass == PC_SPY) { + if(pe_player.is_feigning) { + pe_player.velocity_x = 0; + pe_player.velocity_y = 0; + pe_player.movetype = MOVETYPE_TOSS; + if(!stopdead) { + pe_player.tfstate = pe_player.tfstate | TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(pe_player); + } + } + } +}; + void () CF_Spy_AirThink = { local float area_check = 0; @@ -389,12 +403,18 @@ void () CF_Spy_AirThink = { // only do stuff when spy is no longer moving if (!self.owner.velocity) { - // if spy is on ground and an entity is not nearby, set movetype to none (so he can't move) if (self.owner.flags & FL_ONGROUND) { area_check = Spy_CheckArea(self.owner); if (area_check == 0) { - self.owner.movetype = MOVETYPE_NONE; + traceline(self.owner.origin, self.owner.origin, 0, self.owner); + if(trace_ent) { + if(trace_ent.classname == "door" || trace_ent.classname == "plat" || trace_ent.classname == "train") { + self.owner.movetype = MOVETYPE_TOSS; + } + } else { + self.owner.movetype = MOVETYPE_NONE; + } self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; } } From 1e159bde88c611f2462b8d9d9ecf2b4e1610b7b8 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 9 Mar 2019 12:53:19 +1300 Subject: [PATCH 0626/2474] Extra comments and fixed variable name --- buttons.qc | 2 +- doors.qc | 2 +- plats.qc | 2 +- spy.qc | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/buttons.qc b/buttons.qc index d9d800fb..d66f1222 100644 --- a/buttons.qc +++ b/buttons.qc @@ -3,7 +3,7 @@ #define BUTTON_START_OUT 32 void () button_return; -void (entity pe_player, float stopdead) Spy_CheckForFuncTouch; +void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch; void () button_wait = { self.state = STATE_TOP; diff --git a/doors.qc b/doors.qc index adddce58..0a405816 100644 --- a/doors.qc +++ b/doors.qc @@ -1,7 +1,7 @@ void () door_go_down; void () door_go_up; -void (entity pe_player, float stopdead) Spy_CheckForFuncTouch; +void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch; void () door_blocked = { if (other.classname == "detpack") { diff --git a/plats.qc b/plats.qc index 1625cf32..83636b46 100644 --- a/plats.qc +++ b/plats.qc @@ -5,7 +5,7 @@ void () plat_trigger_use; void () plat_go_up; void () plat_go_down; void () plat_crush; -void (entity pe_player, float stopdead) Spy_CheckForFuncTouch; +void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch; void () plat_spawn_inside_trigger = { local entity trigger; diff --git a/spy.qc b/spy.qc index 78070a98..61168ea0 100644 --- a/spy.qc +++ b/spy.qc @@ -372,13 +372,14 @@ float (entity pe_player) Spy_CheckArea = { return 0; }; -void (entity pe_player, float stopdead) Spy_CheckForFuncTouch = { +void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch = { if (pe_player.classname == "player" && pe_player.playerclass == PC_SPY) { if(pe_player.is_feigning) { pe_player.velocity_x = 0; pe_player.velocity_y = 0; pe_player.movetype = MOVETYPE_TOSS; - if(!stopdead) { + //This is needed for plats that have a virtual presence and this causes you to fall slowly when inside it + if(!dontstopdead) { pe_player.tfstate = pe_player.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(pe_player); } @@ -407,6 +408,7 @@ void () CF_Spy_AirThink = { if (self.owner.flags & FL_ONGROUND) { area_check = Spy_CheckArea(self.owner); if (area_check == 0) { + //This checks if something is trying to squish you, fixing some situations where the door or whatever would just go through you. traceline(self.owner.origin, self.owner.origin, 0, self.owner); if(trace_ent) { if(trace_ent.classname == "door" || trace_ent.classname == "plat" || trace_ent.classname == "train") { From 54db847d61dc30b66806161580c01b6ad492dba4 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Sat, 9 Mar 2019 01:17:18 +0000 Subject: [PATCH 0627/2474] adjustments to make clock work correctly in round 2 while using pause --- commands.qc | 1 - mvdsv.qc | 30 ++++++++++++++++++++++++++++++ quadmode.qc | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/commands.qc b/commands.qc index d88b2e45..ef0ab12b 100644 --- a/commands.qc +++ b/commands.qc @@ -8,7 +8,6 @@ void () QuadMode = localcmd ("localinfo round_delay_time 30\n"); localcmd ("localinfo teamfrags on\n"); localcmd ("localinfo fullteamscore off\n"); - localcmd ("password pineapple\n"); localcmd ("fraglimit 0\n"); localcmd ("exec of_quadmode.cfg\n"); bprint (2, "Quad Mode set to on\n"); diff --git a/mvdsv.qc b/mvdsv.qc index befc4e1e..b54d1ae2 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -290,6 +290,7 @@ float () ConsoleCmd { } void (float duration) GE_PausedTic = { + local entity p; if (unpause_requested && (unpause_countdown == 0)) { unpause_countdown = duration + 5; } @@ -304,24 +305,53 @@ void (float duration) GE_PausedTic = { if (ftos(duration) == ftos(unpause_countdown - 4)) { if (unpause_lastcountnumber != 4) { unpause_lastcountnumber = 4; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find(p, classname, "player"); + } + bprint(2, "Unpausing in 4 seconds\n" ); } } else if (ftos(duration) == ftos(unpause_countdown - 3)) { if (unpause_lastcountnumber != 3) { unpause_lastcountnumber = 3; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find(p, classname, "player"); + } bprint(2, "Unpausing in 3 seconds\n" ); } } else if (ftos(duration) == ftos(unpause_countdown - 2)) { if (unpause_lastcountnumber != 2) { unpause_lastcountnumber = 2; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find(p, classname, "player"); + } bprint(2, "Unpausing in 2 seconds\n" ); } } else if (ftos(duration) == ftos(unpause_countdown - 1)) { if (unpause_lastcountnumber != 1) { unpause_lastcountnumber = 1; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find(p, classname, "player"); + } bprint(2, "Unpausing in 1 second\n" ); } } diff --git a/quadmode.qc b/quadmode.qc index 4f48ecf7..f3ee628c 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -190,6 +190,7 @@ void () QuadRoundInit = { round_over = 2; else { if (!self.cnt2) { + localcmd("serverinfo status \"0 min left\"\n"); self.nextthink = (time + 0.1); self.think = QuadRoundBegin; p = find(world, classname, "player"); From ddf15c6bed6f1826cb372b7f5266175e69c58971 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 9 Mar 2019 23:25:04 +1100 Subject: [PATCH 0628/2474] add support for adminpwd to ftesrv through sv_parseclientcommand, keep mvdsv support --- commands.qc | 259 +++++++++++++++++++++++++++++++++++++++++++++++++--- mvdsv.qc | 233 ++-------------------------------------------- 2 files changed, 253 insertions(+), 239 deletions(-) diff --git a/commands.qc b/commands.qc index ef0ab12b..ebcfbcff 100644 --- a/commands.qc +++ b/commands.qc @@ -1,3 +1,238 @@ +float (string arg1, string arg2) ParseCmds = { + local float arg_num, processedCmd; + local string tmp; + processedCmd = FALSE; + + if (arg1) + arg_num = 1; + if (arg2) + arg_num = 2; + + if (arg1 == "adminpwd") + { + processedCmd = TRUE; + if (arg_num == 2) { + if (self.is_admin) { + sprint(self, PRINT_HIGH, "You are already an admin\n"); + } + Admin_Check(arg2); + if (self.is_admin) { + Admin_Aliases(); + } + } + if (arg_num == 1) { + sprint(self, PRINT_HIGH, "usage: cmd adminpwd password, where password is the admin password\n"); + sprint(self, PRINT_HIGH, "\n"); + } + return processedCmd; + } + + if (self.is_admin) + { + switch (arg1) + { + case "timelimit": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("timelimit "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + tmp = infokey(world, arg1); + sprint(self, PRINT_HIGH, "timelimit is "); + sprint(self, PRINT_HIGH, "\""); + sprint(self, PRINT_HIGH, tmp); + sprint(self, PRINT_HIGH, "\"\n"); + } + break; + case "prematch": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("prematch "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + tmp = infokey(world, arg1); + sprint(self, PRINT_HIGH, "prematch is "); + sprint(self, PRINT_HIGH, "\""); + sprint(self, PRINT_HIGH, tmp); + sprint(self, PRINT_HIGH, "\"\n"); + } + break; + case "fraglimit": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("fraglimit "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + tmp = infokey(world, arg1); + sprint(self, PRINT_HIGH, "fraglimit is "); + sprint(self, PRINT_HIGH, "\""); + sprint(self, PRINT_HIGH, tmp); + sprint(self, PRINT_HIGH, "\"\n"); + } + break; + case "teamplay": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("teamplay "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + tmp = infokey(world, arg1); + sprint(self, PRINT_HIGH, "teamplay is "); + sprint(self, PRINT_HIGH, "\""); + sprint(self, PRINT_HIGH, tmp); + sprint(self, PRINT_HIGH, "\"\n"); + } + break; + case "password": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("password "); + if (arg2 == "none") { + bprint(PRINT_HIGH, Q"\n\sServer Password removed!\s\n\n"); + localcmd("\"\""); + } + else { + bprint(PRINT_HIGH, Q"\n\sServer Password changed to \"", arg2, "\"\s\n\n"); + localcmd(arg2); + } + localcmd("\n"); + } + if (arg_num == 1) { + sprint(self, PRINT_HIGH, "usage: cmd password pwd\n"); + sprint(self, PRINT_HIGH, "\n"); + } + break; + case "record": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("record "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + sprint(self, PRINT_HIGH, "usage: cmd record demo, where demo is the demo name\n"); + sprint(self, PRINT_HIGH, "\n"); + } + break; + case "easyrecord": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("easyrecord "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + localcmd("easyrecord\n"); + } + break; + case "autorecord": + processedCmd = TRUE; + if (arg_num == 2) { + localcmd("localinfo demo_auto_left "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + tmp = infokey(world, "demo_auto_left"); + if (stof(tmp) > 0) { + sprint (self, PRINT_HIGH, "Auto-Recording off\n"); + localcmd ("localinfo demo_auto_left 0\n"); + } + else { + sprint(self, PRINT_HIGH, "Auto-Recording the next match\n"); + localcmd("localinfo demo_auto_left 1\n"); + } + } + break; + case "cancel": + localcmd ("cancel\n"); + processedCmd = TRUE; + break; + case "stop": + localcmd ("stop\n"); + processedCmd = TRUE; + break; + case "kick": + Admin_CycleDeal(); + processedCmd = TRUE; + break; + case "ceasefire": + if (ceasefire_type) + Admin_Pause(); + else + Admin_CeaseFire(); + processedCmd = TRUE; + break; + case "map": + processedCmd = TRUE; + if (clanbattle == 1 && !(cb_prematch)) + { + sprint(self, PRINT_HIGH, "Clan Battle in progress....\n"); + self.impulse = 0; + } + else + { + if (arg_num == 2) { + bprint(PRINT_HIGH, self.netname); + bprint(PRINT_HIGH, " has changed the map to "); + bprint(PRINT_HIGH, arg2); + bprint(PRINT_HIGH, "\n"); + localcmd("map "); + localcmd(arg2); + localcmd("\n"); + } + if (arg_num == 1) { + sprint (self, PRINT_HIGH, "usage: cmd map mapname, where mapname is the map name you wish to change to\n"); + sprint (self, PRINT_HIGH, "\n"); + } + } + break; + case "help": + case "list": + processedCmd = TRUE; + sprint(self, PRINT_HIGH, "Commands list:\n"); + sprint(self, PRINT_HIGH, "cmd adminpwd\n"); + sprint(self, PRINT_HIGH, "cmd timelimit\n"); + sprint(self, PRINT_HIGH, "cmd prematch\n"); + sprint(self, PRINT_HIGH, "cmd fraglimit\n"); + sprint(self, PRINT_HIGH, "cmd teamplay\n"); + sprint(self, PRINT_HIGH, "cmd password\n"); + sprint(self, PRINT_HIGH, "cmd map\n"); + sprint(self, PRINT_HIGH, "cmd record\n"); + sprint(self, PRINT_HIGH, "cmd easyrecord\n"); + sprint(self, PRINT_HIGH, "cmd autorecord\n"); + sprint(self, PRINT_HIGH, "cmd cancel\n"); + sprint(self, PRINT_HIGH, "cmd stop\n"); + sprint(self, PRINT_HIGH, "cmd kick\n"); + sprint(self, PRINT_HIGH, "cmd help || list (this command)\n"); + sprint(self, PRINT_HIGH, "\n"); + break; + } + } + + return processedCmd; +} + +void (string cmd) SV_ParseClientCommand = { + float isProcessed; + tokenize(cmd); + + isProcessed = ParseCmds(argv(0), argv(1)); + + if (!isProcessed) + { + clientcommand(self, cmd); + } +} + void () QuadMode = { localcmd ("localinfo clan on\n"); @@ -9,17 +244,17 @@ void () QuadMode = localcmd ("localinfo teamfrags on\n"); localcmd ("localinfo fullteamscore off\n"); localcmd ("fraglimit 0\n"); - localcmd ("exec of_quadmode.cfg\n"); - bprint (2, "Quad Mode set to on\n"); - bprint (2, "Map Restart needed to take effect!\n"); + localcmd ("exec fo_quadmode.cfg\n"); + bprint (PRINT_HIGH, "Quad Mode set to on\n"); + bprint (PRINT_HIGH, "Map Restart needed to take effect!\n"); }; void () ClanMode = { localcmd("localinfo clan on\n"); - localcmd ("exec of_clanmode.cfg\n"); - bprint(2, "Clan Mode set to on\n"); - bprint(2, "Map Restart needed to take effect!\n"); + localcmd ("exec fo_clanmode.cfg\n"); + bprint(PRINT_HIGH, "Clan Mode set to on\n"); + bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); }; void () PubMode = @@ -33,9 +268,9 @@ void () PubMode = localcmd("timelimit 20\n"); localcmd ("fraglimit 0\n"); localcmd("localinfo round_time 0\n"); - localcmd ("exec of_pubmode.cfg\n"); - bprint(2, "Pub Mode set to on\n"); - bprint(2, "Map Restart needed to take effect!\n"); + localcmd ("exec fo_pubmode.cfg\n"); + bprint(PRINT_HIGH, "Pub Mode set to on\n"); + bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); } void () DuelMode = @@ -47,7 +282,7 @@ void () DuelMode = localcmd ("password none\n"); localcmd("timelimit 0\n"); localcmd ("fraglimit 30\n"); - localcmd ("exec of_duelmode.cfg\n"); - bprint(2, "Duel Mode set to on\n"); - bprint(2, "Map Restart needed to take effect!\n"); + localcmd ("exec fo_duelmode.cfg\n"); + bprint(PRINT_HIGH, "Duel Mode set to on\n"); + bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); } \ No newline at end of file diff --git a/mvdsv.qc b/mvdsv.qc index b54d1ae2..4fe87e59 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -1,233 +1,12 @@ float () UserCmd = { - local float arg_num; - local string tmp; + float isProcessed; + string arg1, arg2; + arg1 = argv_mvdsv(0); + arg2 = argv_mvdsv(1); - arg_num = argc(); - if (arg_num == 0) { - return (0); - } - if (argv_mvdsv(0) == "adminpwd") { - if (arg_num == 2) { - if (self.is_admin) { - sprint(self, 2, "You are already an admin\n"); - return (1); - } - Admin_Check(argv_mvdsv(1)); - if (self.is_admin) { - Admin_Aliases(); - } - return (1); - } - if (arg_num == 1) { - sprint(self, 2, "usage: cmd adminpwd password, where password is the admin password\n"); - sprint(self, 2, "\n"); - return (1); - } - } - if (self.is_admin) { - //Adminpwd commands - if (argv_mvdsv(0) == "timelimit") { - if (arg_num == 2) { - localcmd("timelimit "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - tmp = infokey(world, argv_mvdsv(0)); - sprint(self, 2, "timelimit is "); - sprint(self, 2, "\""); - sprint(self, 2, tmp); - sprint(self, 2, "\"\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "prematch") { - if (arg_num == 2) { - localcmd("prematch "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - tmp = infokey(world, argv_mvdsv(0)); - sprint(self, 2, "prematch is "); - sprint(self, 2, "\""); - sprint(self, 2, tmp); - sprint(self, 2, "\"\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "fraglimit") { - if (arg_num == 2) { - localcmd("fraglimit "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - tmp = infokey(world, argv_mvdsv(0)); - sprint(self, 2, "fraglimit is "); - sprint(self, 2, "\""); - sprint(self, 2, tmp); - sprint(self, 2, "\"\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "teamplay") { - if (arg_num == 2) { - localcmd("teamplay "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - tmp = infokey(world, argv_mvdsv(0)); - sprint(self, 2, "teamplay is "); - sprint(self, 2, "\""); - sprint(self, 2, tmp); - sprint(self, 2, "\"\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "password") { - if (arg_num == 2) { - localcmd("password "); - if (argv_mvdsv(1) == "none") { - localcmd("\"\""); - } - else { - localcmd(argv_mvdsv(1)); - } - localcmd("\n"); - bprint("\n"); - argv_mvdsv(1); - if (argv_mvdsv(1) == "none") { - bprint(2, Q"\sServer Password removed!\s\n"); - } - else { - bprint3(2, Q"\sServer Password changed to \"", argv_mvdsv(1), "\"\s\n"); - } - bprint("\n"); - return (1); - } - if (arg_num == 1) { - sprint(self, 2, "usage: cmd password pwd\n"); - sprint(self, 2, "\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "record") { - if (arg_num == 2) { - localcmd("record "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - sprint(self, 2, "usage: cmd record demo, where demo is the demo name\n"); - sprint(self, 2, "\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "easyrecord") { - if (arg_num == 2) { - localcmd("easyrecord "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - localcmd("easyrecord\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "autorecord") { - if (arg_num == 2) { - localcmd("localinfo demo_auto_left "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - tmp = infokey(world, "demo_auto_left"); - if (stof(tmp) > 0) { - dprint ("Auto-Recording off\n"); - localcmd ("localinfo demo_auto_left 0\n"); - return (1); - } - else { - dprint("Auto-Recording the next match\n"); - localcmd("localinfo demo_auto_left 1\n"); - return (1); - } - } - } - else if (argv_mvdsv(0) == "cancel") { - localcmd ("cancel\n"); - return (1); - } - else if (argv_mvdsv(0) == "stop") { - localcmd ("stop\n"); - return (1); - } - else if (argv_mvdsv(0) == "kick") { - Admin_CycleDeal(); - return (1); - } - else if (argv_mvdsv(0) == "ceasefire") { - if (ceasefire_type) - Admin_Pause(); - else - Admin_CeaseFire(); - return (1); - } - else if (argv_mvdsv(0) == "map") { - if (self.is_admin) { - if (clanbattle == 1 && !(cb_prematch)) { - sprint(self, 2, "Clan Battle in progress....\n"); - self.impulse = 0; - return (1); - } - } - if (arg_num == 2) { - bprint(2, self.netname); - bprint(2, " Has changed the map to "); - bprint(2, argv_mvdsv(1)); - bprint(2, "\n"); - localcmd("map "); - localcmd(argv_mvdsv(1)); - localcmd("\n"); - return (1); - } - if (arg_num == 1) { - sprint (self, 2, "usage: cmd map mapname, where mapname is the map name you wish to change to\n"); - sprint (self, 2, "\n"); - return (1); - } - } - else if (argv_mvdsv(0) == "help" || argv_mvdsv(0) == "list") { - sprint(self, 2, "Commands list:\n"); - sprint(self, 2, "cmd adminpwd\n"); - sprint(self, 2, "cmd timelimit\n"); - sprint(self, 2, "cmd prematch\n"); - sprint(self, 2, "cmd fraglimit\n"); - sprint(self, 2, "cmd teamplay\n"); - sprint(self, 2, "cmd password\n"); - sprint(self, 2, "cmd map\n"); - sprint(self, 2, "cmd record\n"); - sprint(self, 2, "cmd easyrecord\n"); - sprint(self, 2, "cmd autorecord\n"); - sprint(self, 2, "cmd cancel\n"); - sprint(self, 2, "cmd stop\n"); - sprint(self, 2, "cmd kick\n"); - sprint(self, 2, "cmd help || list (this command)\n"); - sprint(self, 2, "\n"); - return (1); - } - } - return (0); + isProcessed = ParseCmds(arg1, arg2); + return (isProcessed); }; float () ConsoleCmd { From 2ed091063c164e1bb8c6bb298f4435d0b6a18e16 Mon Sep 17 00:00:00 2001 From: Leonard Wilson Date: Sun, 10 Mar 2019 02:07:24 +1100 Subject: [PATCH 0629/2474] a --- client.qc | 27 +++++++++++ defs.h | 17 ++++++- qw.qc | 11 +++++ tforthlp.qc | 1 + tsoldier.qc | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ weapons.qc | 3 ++ 6 files changed, 185 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 8e9fdc9c..aa8e39be 100644 --- a/client.qc +++ b/client.qc @@ -327,6 +327,33 @@ void () DecodeLevelParms = { toggleflags = toggleflags - (toggleflags & TFLAG_FULLTEAMSCORE); } + // nailgren types 0 = NGR_TYPE_DEFAULT, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST + nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_DEFAULT)); + + // how many rotations the nailgren does [2] + lasergren_rotationcount = CF_GetSetting("lgrc", "lasergren_rotationcount", ftos(NGR_LASER_DEFAULT_ROTATIONCOUNT)); + + // time each rotation takes [1] + lasergren_rotationtime = CF_GetSetting("lgrt", "lasergren_rotationtime", ftos(NGR_LASER_DEFAULT_ROTATIONTIME)); + + // damage [20] + lasergren_damage = CF_GetSetting("lgd", "lasergren_damage", ftos(NGR_LASER_DEFAULT_DAMAGE)); + + // think time for lightning, lower is smoother [0.1] + lasergren_thinktime = CF_GetSetting("lgtt", "lasergren_thinktime", "0.1"); //ftos cuts off after 1 dec place so using ftos here would result in 0 and crash + + // range of shaft [150] + lasergren_range = CF_GetSetting("lgr", "lasergren_range", ftos(NGR_LASER_DEFAULT_RANGE)); + + // how many bursts of nails [2] + burstgren_count = CF_GetSetting("bgc", "burstgren_count", ftos(NGR_BURST_DEFAULT_COUNT)); + + // time between each burst [0.7] + burstgren_interval = CF_GetSetting("bgi", "burstgren_interval", ftos(NGR_BURST_DEFAULT_INTERVAL)); + + // time before nail projectile destroys itself [0.3] + burstgren_range = CF_GetSetting("bgr", "burstgren_range", ftos(NGR_BURST_DEFAULT_RANGE)); + // use old concussion, gas and flash grenades [off] old_grens = CF_GetSetting("og", "old_grens", "off"); diff --git a/defs.h b/defs.h index df00d68a..e003d192 100644 --- a/defs.h +++ b/defs.h @@ -474,7 +474,7 @@ #define TF_ADMIN_FORCESTARTMATCH 137 #define TF_ADMIN_READYSTATUS 138 // unused 139 -// unused 140 +#define TF_NAILGREN_INFO 140 // unused 141 // unused 142 // unused 143 @@ -734,6 +734,21 @@ #define GR_TYPE_FLASH 9 #define GR_TYPE_CALTROP 10 +// NailGren Types +#define NGR_TYPE_DEFAULT 0 +#define NGR_TYPE_LASER 1 +#define NGR_TYPE_BURST 2 + +// NailGren Default Settings +#define NGR_LASER_DEFAULT_ROTATIONCOUNT 2 +#define NGR_LASER_DEFAULT_ROTATIONTIME 1 +#define NGR_LASER_DEFAULT_DAMAGE 20 +#define NGR_LASER_DEFAULT_RANGE 150 + +#define NGR_BURST_DEFAULT_COUNT 2 +#define NGR_BURST_DEFAULT_INTERVAL 0.7 +#define NGR_BURST_DEFAULT_RANGE 0.3 + // Defines for WeaponMode #define GL_NORMAL 0 #define GL_PIPEBOMB 1 diff --git a/qw.qc b/qw.qc index 4d09e3ac..a2d4182e 100644 --- a/qw.qc +++ b/qw.qc @@ -446,6 +446,17 @@ float is_countdown; float exec_map_cfgs; float spy_off; +float nailgren_type; +float lasergren_rotationcount; +float lasergren_rotationtime; +float lasergren_thinktime; +float lasergren_range; +float lasergren_damage; +float lasergren_reqthinks; +float lasergren_angleperthink; +float burstgren_count; +float burstgren_interval; +float burstgren_range; float old_grens; float invis_only; float flagem_checked; diff --git a/tforthlp.qc b/tforthlp.qc index b5757015..485dc505 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -181,6 +181,7 @@ void () TeamFortress_MOTD = { stuffcmd(self, "is_aliased\n"); TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); + TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); } else if (self.motd == 400 && self.team_no == 0) { Menu_Team(1); } diff --git a/tsoldier.qc b/tsoldier.qc index 77623476..b161f659 100644 --- a/tsoldier.qc +++ b/tsoldier.qc @@ -5,6 +5,8 @@ void () NailGrenadeExplode; void () NailGrenadeNailEm; void () NailGrenadeLaunchNail; +void () NailGrenLaser; +void () NailGrenBurst; void () NailGrenadeTouch = { if (other == self.owner) @@ -37,7 +39,20 @@ void () NailGrenadeExplode = { setorigin(self, self.origin + '0 0 32'); self.avelocity = '0 500 0'; self.nextthink = time + 0.7; + if (nailgren_type == NGR_TYPE_LASER) + { + self.playerclass = 0; + self.think = NailGrenLaser; + } + else if (nailgren_type == NGR_TYPE_BURST) + { + self.playerclass = 0; + self.think = NailGrenBurst; + } + else + { self.think = NailGrenadeNailEm; + } }; void () NailGrenadeNailEm = { @@ -77,3 +92,115 @@ void () NailGrenadeLaunchNail = { self.think = GrenadeExplode; } }; + +void () NailGrenLaser = { //using self.playerclass to count thinks + local float current_yaw; + local vector org; + + if(self.playerclass == 0){ + self.velocity = '0 0 0'; + self.real_owner = self.owner; + self.owner = world; //workaround because traceent wouldnt hit self or self.owner + current_yaw = 0; + lasergren_reqthinks = (lasergren_rotationcount * lasergren_rotationtime) / lasergren_thinktime; + lasergren_angleperthink = (lasergren_rotationcount * 360) / lasergren_reqthinks; + } + else{ + current_yaw = anglemod(self.angles_y + lasergren_angleperthink); + } + self.angles_y = current_yaw; + self.angles_x = 0; + self.angles_z = 0; + makevectors(self.angles); + + org = self.origin; + traceline(org, org + v_forward * lasergren_range, 0, self); + + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_LIGHTNING2); + WriteEntity(MSG_MULTICAST, self); + WriteCoord(MSG_MULTICAST, org_x); + WriteCoord(MSG_MULTICAST, org_y); + WriteCoord(MSG_MULTICAST, org_z); + WriteCoord(MSG_MULTICAST, trace_endpos_x); + WriteCoord(MSG_MULTICAST, trace_endpos_y); + WriteCoord(MSG_MULTICAST, trace_endpos_z); + multicast(org, MULTICAST_PHS); + + if (trace_ent.takedamage){ + + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_LIGHTNINGBLOOD); + WriteCoord(MSG_MULTICAST, trace_endpos_x); + WriteCoord(MSG_MULTICAST, trace_endpos_y); + WriteCoord(MSG_MULTICAST, trace_endpos_z); + multicast(trace_endpos, MULTICAST_PVS); + + deathmsg = DMSG_GREN_NAIL; + TF_T_Damage(trace_ent, self, self.real_owner, lasergren_damage, TF_TD_NOTTEAM, TF_TD_ELECTRICITY); + } + if (self.t_width < time) { + sound(self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); + self.t_width = time + 0.8; + } + + self.nextthink = time + lasergren_thinktime; + self.playerclass++; + current_yaw = anglemod(self.angles_y + lasergren_angleperthink); + + if (self.playerclass > lasergren_reqthinks) { //not >= to give an extra think so it hits start again + self.owner = self.real_owner; + self.weapon = DMSG_GREN_NAIL; + self.think = GrenadeExplode; + } +}; + +void () NailGrenBurst = { + local float i; + local float current_yaw; + current_yaw = 0; + i = 0; + self.velocity = '0 0 0'; + + while (i < 16){ + self.angles_y = current_yaw; + self.angles_x = 0; + self.angles_z = 0; + makevectors(self.angles); + + sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); + + deathmsg = DMSG_GREN_NAIL; + launch_spike(self.origin, v_forward); + newmis.velocity = v_forward * 1000; + newmis.touch = superspike_touch; + newmis.weapon = DMSG_GREN_NAIL; + newmis.nextthink = time + burstgren_range; + i++; + current_yaw = anglemod(self.angles_y + 22.5); + } + self.playerclass++; + self.nextthink = time + burstgren_interval; + + if (self.playerclass >= burstgren_count){ + self.nextthink = time + 0.1; + self.weapon = DMSG_GREN_NAIL; + self.think = GrenadeExplode; + } +}; + +void () TeamFortress_NailGrenInfo = { + sprint(self,2,Q"\n\snailgren info - num in brackets are default - num shown are to one dec place - updated on map change\s\n"); + sprint(self,2,Q"\n\s----------------------------------------------------------------------------------------------\s\n"); + sprint(self,2,Q"ngt nailgren_type ",ftos(nailgren_type)," (",ftos(NGR_TYPE_DEFAULT),") \s// 0 default, 1 laser, 2 burst \n\n"); + sprint(self,2,Q"lgrc lasergren_rotationcount ",ftos(lasergren_rotationcount)," (",ftos(NGR_LASER_DEFAULT_ROTATIONCOUNT),") \s// how many rotations to perform\n"); + sprint(self,2,Q"lgrt lasergren_rotationtime ",ftos(lasergren_rotationtime)," (",ftos(NGR_LASER_DEFAULT_ROTATIONTIME),") \s// time to complete one rotation\n"); + sprint(self,2,Q"lgr lasergren_range ",ftos(lasergren_range)," (",ftos(NGR_LASER_DEFAULT_RANGE),") \s// range\n"); + sprint(self,2,Q"lgd lasergren_damage ",ftos(lasergren_damage)," (",ftos(NGR_LASER_DEFAULT_DAMAGE),") \s// damage\n"); + sprint(self,2,Q"lgtt lasergren_thinktime ",ftos(lasergren_thinktime)," (0.1) \s// time between thinks, lower to smooth rotation \n\n"); + sprint(self,2,Q"bgc burstgren_count ",ftos(burstgren_count)," (",ftos(NGR_BURST_DEFAULT_COUNT),") \s// how many bursts of nails\n"); + sprint(self,2,Q"bgi burstgren_interval ",ftos(burstgren_interval)," (",ftos(NGR_BURST_DEFAULT_INTERVAL),") \s// time between bursts\n"); + sprint(self,2,Q"bgr burstgren_range ",ftos(burstgren_range)," (",ftos(NGR_BURST_DEFAULT_RANGE),") \s// time before nail projectiles destroyself\n"); + sprint(self,2,Q"\s----------------------------------------------------------------------------------------------\s\n"); + self.impulse = 0; +}; diff --git a/weapons.qc b/weapons.qc index ffc01b20..d4a1fe9c 100644 --- a/weapons.qc +++ b/weapons.qc @@ -89,6 +89,7 @@ void (entity gun) Engineer_UseSentryGun; void () TeamFortress_MOTD; void () TeamFortress_HelpMap; +void () TeamFortress_NailGrenInfo; void () BioInfection_Decay; void () BioInfection_MonsterDecay; @@ -3009,6 +3010,8 @@ void () DeadImpulses = { } if (self.impulse == TF_HELP_MAP) TeamFortress_HelpMap(); + else if (self.impulse == TF_NAILGREN_INFO) + TeamFortress_NailGrenInfo(); else if (self.impulse == TF_STATUS_QUERY) TeamFortress_StatusQuery(); else if (self.impulse == TF_TEAM_1) From b1f8f2901a53345a952085a33c0f6c154162e577 Mon Sep 17 00:00:00 2001 From: Leonard Wilson Date: Sun, 10 Mar 2019 02:26:49 +1100 Subject: [PATCH 0630/2474] Added NailGren Stuff --- client.qc | 2 +- defs.h | 2 +- qw.qc | 2 ++ tforthlp.qc | 2 +- tsoldier.qc | 2 +- weapons.qc | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index aa8e39be..791b3af5 100644 --- a/client.qc +++ b/client.qc @@ -340,7 +340,7 @@ void () DecodeLevelParms = { lasergren_damage = CF_GetSetting("lgd", "lasergren_damage", ftos(NGR_LASER_DEFAULT_DAMAGE)); // think time for lightning, lower is smoother [0.1] - lasergren_thinktime = CF_GetSetting("lgtt", "lasergren_thinktime", "0.1"); //ftos cuts off after 1 dec place so using ftos here would result in 0 and crash + lasergren_thinktime = CF_GetSetting("lgtt", "lasergren_thinktime", "0.1"); //ftos cuts off after 1 dec place, using ftos here would result in 0 and crash? // range of shaft [150] lasergren_range = CF_GetSetting("lgr", "lasergren_range", ftos(NGR_LASER_DEFAULT_RANGE)); diff --git a/defs.h b/defs.h index e003d192..22c57d00 100644 --- a/defs.h +++ b/defs.h @@ -734,7 +734,7 @@ #define GR_TYPE_FLASH 9 #define GR_TYPE_CALTROP 10 -// NailGren Types +// Defines for NailGren Types #define NGR_TYPE_DEFAULT 0 #define NGR_TYPE_LASER 1 #define NGR_TYPE_BURST 2 diff --git a/qw.qc b/qw.qc index a2d4182e..4dee4f6b 100644 --- a/qw.qc +++ b/qw.qc @@ -446,6 +446,7 @@ float is_countdown; float exec_map_cfgs; float spy_off; + float nailgren_type; float lasergren_rotationcount; float lasergren_rotationtime; @@ -457,6 +458,7 @@ float lasergren_angleperthink; float burstgren_count; float burstgren_interval; float burstgren_range; + float old_grens; float invis_only; float flagem_checked; diff --git a/tforthlp.qc b/tforthlp.qc index 485dc505..aa576908 100644 --- a/tforthlp.qc +++ b/tforthlp.qc @@ -181,7 +181,7 @@ void () TeamFortress_MOTD = { stuffcmd(self, "is_aliased\n"); TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); - TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); + TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo } else if (self.motd == 400 && self.team_no == 0) { Menu_Team(1); } diff --git a/tsoldier.qc b/tsoldier.qc index b161f659..f43bd953 100644 --- a/tsoldier.qc +++ b/tsoldier.qc @@ -100,7 +100,7 @@ void () NailGrenLaser = { //using self.playerclass to count thinks if(self.playerclass == 0){ self.velocity = '0 0 0'; self.real_owner = self.owner; - self.owner = world; //workaround because traceent wouldnt hit self or self.owner + self.owner = world; //work-around because traceent wouldnt hit self or self.owner current_yaw = 0; lasergren_reqthinks = (lasergren_rotationcount * lasergren_rotationtime) / lasergren_thinktime; lasergren_angleperthink = (lasergren_rotationcount * 360) / lasergren_reqthinks; diff --git a/weapons.qc b/weapons.qc index d4a1fe9c..64f4e413 100644 --- a/weapons.qc +++ b/weapons.qc @@ -3011,7 +3011,7 @@ void () DeadImpulses = { if (self.impulse == TF_HELP_MAP) TeamFortress_HelpMap(); else if (self.impulse == TF_NAILGREN_INFO) - TeamFortress_NailGrenInfo(); + TeamFortress_NailGrenInfo(); else if (self.impulse == TF_STATUS_QUERY) TeamFortress_StatusQuery(); else if (self.impulse == TF_TEAM_1) From 2c7afb4376b98a8060e0e3043893cea657100753 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 10 Mar 2019 13:22:06 +1100 Subject: [PATCH 0631/2474] change default lasergren rotation think to .01 --- client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 8955855f..2ceaed99 100644 --- a/client.qc +++ b/client.qc @@ -340,7 +340,7 @@ void () DecodeLevelParms = { lasergren_damage = CF_GetSetting("lgd", "lasergren_damage", ftos(NGR_LASER_DEFAULT_DAMAGE)); // think time for lightning, lower is smoother [0.1] - lasergren_thinktime = CF_GetSetting("lgtt", "lasergren_thinktime", "0.1"); //ftos cuts off after 1 dec place, using ftos here would result in 0 and crash? + lasergren_thinktime = CF_GetSetting("lgtt", "lasergren_thinktime", "0.01"); //ftos cuts off after 1 dec place, using ftos here would result in 0 and crash? // range of shaft [150] lasergren_range = CF_GetSetting("lgr", "lasergren_range", ftos(NGR_LASER_DEFAULT_RANGE)); From 07daa9f83430f1c7782cecc0d099f7f343ed5801 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 10 Mar 2019 13:24:22 +1100 Subject: [PATCH 0632/2474] set laser as default for staging/testing --- client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 2ceaed99..a2a0e75b 100644 --- a/client.qc +++ b/client.qc @@ -328,7 +328,7 @@ void () DecodeLevelParms = { } // nailgren types 0 = NGR_TYPE_DEFAULT, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST - nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_DEFAULT)); + nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_LASER)); // how many rotations the nailgren does [2] lasergren_rotationcount = CF_GetSetting("lgrc", "lasergren_rotationcount", ftos(NGR_LASER_DEFAULT_ROTATIONCOUNT)); From 616a86a012f9fec115ac393d6dedaeff7847c14e Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Tue, 12 Mar 2019 03:17:32 +0000 Subject: [PATCH 0633/2474] allowing admins to change map even with match in progress --- commands.qc | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/commands.qc b/commands.qc index ebcfbcff..8592cf85 100644 --- a/commands.qc +++ b/commands.qc @@ -173,26 +173,18 @@ float (string arg1, string arg2) ParseCmds = { break; case "map": processedCmd = TRUE; - if (clanbattle == 1 && !(cb_prematch)) - { - sprint(self, PRINT_HIGH, "Clan Battle in progress....\n"); - self.impulse = 0; + if (arg_num == 2) { + bprint(PRINT_HIGH, self.netname); + bprint(PRINT_HIGH, " has changed the map to "); + bprint(PRINT_HIGH, arg2); + bprint(PRINT_HIGH, "\n"); + localcmd("map "); + localcmd(arg2); + localcmd("\n"); } - else - { - if (arg_num == 2) { - bprint(PRINT_HIGH, self.netname); - bprint(PRINT_HIGH, " has changed the map to "); - bprint(PRINT_HIGH, arg2); - bprint(PRINT_HIGH, "\n"); - localcmd("map "); - localcmd(arg2); - localcmd("\n"); - } - if (arg_num == 1) { - sprint (self, PRINT_HIGH, "usage: cmd map mapname, where mapname is the map name you wish to change to\n"); - sprint (self, PRINT_HIGH, "\n"); - } + if (arg_num == 1) { + sprint (self, PRINT_HIGH, "usage: cmd map mapname, where mapname is the map name you wish to change to\n"); + sprint (self, PRINT_HIGH, "\n"); } break; case "help": From 83d64c736484ca2de13496dd368252339ce34769 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Tue, 12 Mar 2019 03:23:20 +0000 Subject: [PATCH 0634/2474] adding an else to cmd map to prevent an extra check --- commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands.qc b/commands.qc index 8592cf85..c71f40d6 100644 --- a/commands.qc +++ b/commands.qc @@ -182,7 +182,7 @@ float (string arg1, string arg2) ParseCmds = { localcmd(arg2); localcmd("\n"); } - if (arg_num == 1) { + else if (arg_num == 1) { sprint (self, PRINT_HIGH, "usage: cmd map mapname, where mapname is the map name you wish to change to\n"); sprint (self, PRINT_HIGH, "\n"); } From 55d96d638312fe03ad7ce1864e8e5b52284191dc Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Wed, 13 Mar 2019 04:43:39 +0000 Subject: [PATCH 0635/2474] fixing pause for ftesv, keeping mvdsv compatibility --- mvdsv.qc | 90 +++++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/mvdsv.qc b/mvdsv.qc index 4fe87e59..b78593ef 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -78,69 +78,59 @@ void (float duration) GE_PausedTic = { is_paused = 0; unpause_countdown = 0; unpause_requested = 0; + unpause_lastcountnumber = 0; setpause(0); } else { - if (ftos(duration) == ftos(unpause_countdown - 4)) { - if (unpause_lastcountnumber != 4) { - unpause_lastcountnumber = 4; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); + if (duration >= (unpause_countdown - 4) && (unpause_lastcountnumber == 0)) { + unpause_lastcountnumber = 4; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); } - - bprint(2, "Unpausing in 4 seconds\n" ); - } + p = find(p, classname, "player"); + } + bprint(PRINT_HIGH, "Unpausing in 4 seconds\n" ); + } - else if (ftos(duration) == ftos(unpause_countdown - 3)) { - if (unpause_lastcountnumber != 3) { - unpause_lastcountnumber = 3; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); + else if (duration >= (unpause_countdown - 3) && (unpause_lastcountnumber == 4)) { + unpause_lastcountnumber = 3; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); } - bprint(2, "Unpausing in 3 seconds\n" ); + p = find(p, classname, "player"); } + bprint(PRINT_HIGH, "Unpausing in 3 seconds\n" ); } - else if (ftos(duration) == ftos(unpause_countdown - 2)) { - if (unpause_lastcountnumber != 2) { - unpause_lastcountnumber = 2; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); + else if (duration >= (unpause_countdown - 2) && (unpause_lastcountnumber == 3)) { + unpause_lastcountnumber = 2; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); } - bprint(2, "Unpausing in 2 seconds\n" ); + p = find(p, classname, "player"); } + bprint(PRINT_HIGH, "Unpausing in 2 seconds\n" ); } - else if (ftos(duration) == ftos(unpause_countdown - 1)) { - if (unpause_lastcountnumber != 1) { - unpause_lastcountnumber = 1; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); + else if (duration >= (unpause_countdown - 1) && (unpause_lastcountnumber == 2)) { + unpause_lastcountnumber = 1; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") { + stuffcmd(p, "play buttons/switch04.wav\n"); } - bprint(2, "Unpausing in 1 second\n" ); - } - } - else if (ftos(duration) == ftos(unpause_countdown)) { - if (unpause_lastcountnumber != 0) { - unpause_lastcountnumber = 0; - bprint(2, "GAME UNPAUSED\n" ); + p = find(p, classname, "player"); } + bprint(PRINT_HIGH, "Unpausing in 1 second\n" ); } - } } -} \ No newline at end of file +} + +void(float pauseduration) SV_PausedTic = { + GE_PausedTic(pauseduration); +} \ No newline at end of file From 096b2455433c708eb540c0dc23fded9b78cf3fd2 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Thu, 14 Mar 2019 19:22:25 +0000 Subject: [PATCH 0636/2474] adding a toggle to prevent weapon change delay --- client.qc | 3 +++ qw.qc | 1 + weapons.qc | 29 +++++++++++++++++------------ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/client.qc b/client.qc index a2a0e75b..c124c744 100644 --- a/client.qc +++ b/client.qc @@ -533,6 +533,9 @@ void () DecodeLevelParms = { // ceasefire type - 0: default; 1: pause ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); + // wait until attack_finished is over before changing weapons + chweap_wait_attfinished = CF_GetSetting("cwaf", "chweap_wait_atk", "on"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/qw.qc b/qw.qc index 8a8181eb..99b35ff2 100644 --- a/qw.qc +++ b/qw.qc @@ -523,6 +523,7 @@ string pause_actor; float unpause_requested; float unpause_countdown; float unpause_lastcountnumber; +float chweap_wait_attfinished; .float teamkills; diff --git a/weapons.qc b/weapons.qc index 64f4e413..3d47458b 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2584,7 +2584,6 @@ float (entity pl) W_WeaponState_Check = { } void (float inp) W_ChangeWeapon = { - if (inp < 1 || inp > GetLastWeaponImpulse()) return; @@ -2596,9 +2595,9 @@ void (float inp) W_ChangeWeapon = { self.queue_weaponslot = inp; // halt if weapon is not ready to be fired - if (!WeaponReady(self)) + if (!WeaponReady(self) && chweap_wait_attfinished) return; - + if (IsUsingOldImpulses()) { // check for ammo if (! W_OldAmmoSlot(inp)) { @@ -3161,17 +3160,23 @@ void () W_WeaponFrame = { } // slot 1-4 (or 1-7) binds - if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && WeaponReady(self) + if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && (WeaponReady(self) || !chweap_wait_attfinished) && !self.is_building && !self.is_detpacking) { - // load weapon state if current state doesn't match stored state - if (!W_WeaponState_Check(self)) - W_WeaponState_Load(self, 0); - - // obviously not quickfiring if we're changing weapon - self.is_quickfiring = 0; - self.has_quickfired = 0; - W_ChangeWeapon(self.impulse); + if (!(self.tfstate & TFSTATE_RELOADING)) { + // load weapon state if current state doesn't match stored state + if (!W_WeaponState_Check(self)) + W_WeaponState_Load(self, 0); + + // obviously not quickfiring if we're changing weapon + self.is_quickfiring = 0; + self.has_quickfired = 0; + W_ChangeWeapon(self.impulse); + } + else if (!chweap_wait_attfinished) { + //clears impulse so it doesn't switch weapons just after reloading + self.impulse = 0; + } // regular attack (both +attack and -attack) } else if (!self.impulse && !self.is_quickfiring) { From 4f9217454653e76613f192698a8279548b86bb61 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 22 Mar 2019 00:40:16 +1300 Subject: [PATCH 0637/2474] Stop laser gren from spinning extra fast when detonated in mid-air. Changed messages to refer to it as shock rathar than nail grenade --- client.qc | 17 ++++++++++----- help.qc | 2 +- status.qc | 6 +++++- tfort.qc | 60 +++++++++++++++++++++++++++++++++++++---------------- tsoldier.qc | 30 ++++++++++++++------------- 5 files changed, 76 insertions(+), 39 deletions(-) diff --git a/client.qc b/client.qc index a2a0e75b..e1f29885 100644 --- a/client.qc +++ b/client.qc @@ -2196,9 +2196,11 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage return strcat(pe_target.netname, s_deathstring); } else if (pf_deathmsg == DMSG_GREN_NAIL) { - - return strcat(pe_target.netname, " hammers himself\n"); - + if (nailgren_type == NGR_TYPE_LASER) { + return strcat(pe_target.netname, " electrocutes himself\n"); + } else { + return strcat(pe_target.netname, " hammers himself\n"); + } } else if (pf_deathmsg == DMSG_GREN_MIRV) { if (pe_target.playerclass == PC_DEMOMAN) @@ -2306,8 +2308,13 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage } } else if (pf_deathmsg == DMSG_GREN_NAIL) { - s_deathstring = " gets flayed by "; - s_deathstring2 = "'s nail grenade\n"; + if (nailgren_type == NGR_TYPE_LASER) { + s_deathstring = " gets melted by "; + s_deathstring2 = "'s shock grenade\n"; + } else { + s_deathstring = " gets flayed by "; + s_deathstring2 = "'s nail grenade\n"; + } } else if (pf_deathmsg == DMSG_GREN_MIRV) { if (pe_attacker.playerclass == PC_DEMOMAN) { s_deathstring = " does a dance on "; diff --git a/help.qc b/help.qc index c6b27f6b..43b535a6 100644 --- a/help.qc +++ b/help.qc @@ -82,7 +82,7 @@ void () Help_ShowSoldier = { sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); sprint(self, PRINT_HIGH, Q"\s4\s - Equip Axe\n"); - sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Nail Grenade\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Nail/Shock Grenade\n"); sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); }; diff --git a/status.qc b/status.qc index 448b43a5..8b5a7434 100644 --- a/status.qc +++ b/status.qc @@ -232,7 +232,11 @@ string (float class) CF_GetRandomClassTip { line1 = "Use the super shotgun (2) at very close"; line2 = "range to avoid splash damage."; } else if (self.display_tip == 7) { - line1 = "Use a nail grenade (f) to clear a small"; + if (nailgren_type == NGR_TYPE_LASER) { + line1 = "Use a shock grenade (f) to clear a small"; + } else { + line1 = "Use a nail grenade (f) to clear a small"; + } line2 = "room or block a bottle neck."; } } diff --git a/tfort.qc b/tfort.qc index 5cb9340a..da29d366 100644 --- a/tfort.qc +++ b/tfort.qc @@ -410,9 +410,13 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, ftos(fl)); if (self.tp_grenades_1 == GR_TYPE_NORMAL) sprint(self, PRINT_HIGH, " normal grenade"); - else if (self.tp_grenades_1 == GR_TYPE_NAIL) - sprint(self, PRINT_HIGH, " nail grenade"); - else if (self.tp_grenades_1 == GR_TYPE_MIRV) + else if (self.tp_grenades_1 == GR_TYPE_NAIL) { + if (nailgren_type == NGR_TYPE_LASER) { + sprint(self, PRINT_HIGH, " shock grenade"); + } else { + sprint(self, PRINT_HIGH, " nail grenade"); + } + } else if (self.tp_grenades_1 == GR_TYPE_MIRV) sprint(self, PRINT_HIGH, " mirv grenade"); else if (self.tp_grenades_1 == GR_TYPE_NAPALM) sprint(self, PRINT_HIGH, " napalm grenade"); @@ -439,9 +443,13 @@ void () TeamFortress_Inventory = { sprint(self, PRINT_HIGH, " normal grenade"); else if (self.tp_grenades_2 == GR_TYPE_CONCUSSION) sprint(self, PRINT_HIGH, " concussion grenade"); - else if (self.tp_grenades_2 == GR_TYPE_NAIL) - sprint(self, PRINT_HIGH, " nail grenade"); - else if (self.tp_grenades_2 == GR_TYPE_MIRV) + else if (self.tp_grenades_2 == GR_TYPE_NAIL) { + if (nailgren_type == NGR_TYPE_LASER) { + sprint(self, PRINT_HIGH, " shock grenade"); + } else { + sprint(self, PRINT_HIGH, " nail grenade"); + } + } else if (self.tp_grenades_2 == GR_TYPE_MIRV) sprint(self, PRINT_HIGH, " mirv grenade"); else if (self.tp_grenades_2 == GR_TYPE_NAPALM) sprint(self, PRINT_HIGH, " napalm grenade"); @@ -712,9 +720,13 @@ void (float inp) TeamFortress_PrimeGrenade = { if (self.tp_grenades_1 == 2) gs = "Concussion grenade"; - else if (self.tp_grenades_1 == 3) - gs = "Nail grenade"; - else if (self.tp_grenades_1 == 4) + else if (self.tp_grenades_1 == 3) { + if (nailgren_type == NGR_TYPE_LASER) { + gs = "Shock grenade"; + } else { + gs = "Nail grenade"; + } + } else if (self.tp_grenades_1 == 4) gs = "Mirv grenade"; else if (self.tp_grenades_1 == 5) gs = "Napalm grenade"; @@ -774,9 +786,13 @@ void (float inp) TeamFortress_PrimeGrenade = { if (self.tp_grenades_2 == 2) gs = "Concussion grenade"; - else if (self.tp_grenades_2 == 3) - gs = "Nail grenade"; - else if (self.tp_grenades_2 == 4) + else if (self.tp_grenades_2 == 3) { + if (nailgren_type == NGR_TYPE_LASER) { + gs = "Shock grenade"; + } else { + gs = "Nail grenade"; + } + } else if (self.tp_grenades_2 == 4) gs = "Mirv grenade"; else if (self.tp_grenades_2 == 5) gs = "Napalm grenade"; @@ -993,9 +1009,13 @@ void () TeamFortress_GrenadeSwitch = { self.tp_grenade_switch = 0; if (self.tp_grenades_1 == 2) gs = "Concussion grenade"; - else if (self.tp_grenades_1 == 3) - gs = "Nail grenade"; - else if (self.tp_grenades_1 == 4) + else if (self.tp_grenades_1 == 3) { + if (nailgren_type == NGR_TYPE_LASER) { + gs = "Shock grenade"; + } else { + gs = "Nail grenade"; + } + } else if (self.tp_grenades_1 == 4) gs = "Mirv grenade"; else if (self.tp_grenades_1 == 5) gs = "Napalm grenade"; @@ -1011,9 +1031,13 @@ void () TeamFortress_GrenadeSwitch = { self.tp_grenade_switch = 1; if (self.tp_grenades_2 == 2) gs = "Concussion grenade"; - else if (self.tp_grenades_2 == 3) - gs = "Nail grenade"; - else if (self.tp_grenades_2 == 4) + else if (self.tp_grenades_2 == 3) { + if (nailgren_type == NGR_TYPE_LASER) { + gs = "Shock grenade"; + } else { + gs = "Nail grenade"; + } + } else if (self.tp_grenades_2 == 4) gs = "Mirv grenade"; else if (self.tp_grenades_2 == 5) gs = "Napalm grenade"; diff --git a/tsoldier.qc b/tsoldier.qc index f43bd953..178ba90d 100644 --- a/tsoldier.qc +++ b/tsoldier.qc @@ -98,20 +98,21 @@ void () NailGrenLaser = { //using self.playerclass to count thinks local vector org; if(self.playerclass == 0){ - self.velocity = '0 0 0'; - self.real_owner = self.owner; - self.owner = world; //work-around because traceent wouldnt hit self or self.owner - current_yaw = 0; - lasergren_reqthinks = (lasergren_rotationcount * lasergren_rotationtime) / lasergren_thinktime; + self.velocity = '0 0 0'; + self.real_owner = self.owner; + self.owner = world; //work-around because traceent wouldnt hit self or self.owner + current_yaw = 0; + lasergren_reqthinks = (lasergren_rotationcount * lasergren_rotationtime) / lasergren_thinktime; lasergren_angleperthink = (lasergren_rotationcount * 360) / lasergren_reqthinks; - } - else{ - current_yaw = anglemod(self.angles_y + lasergren_angleperthink); - } - self.angles_y = current_yaw; - self.angles_x = 0; - self.angles_z = 0; - makevectors(self.angles); + self.v_angle = self.angles; + } else { + current_yaw = anglemod(self.v_angle_y + lasergren_angleperthink); + } + self.v_angle_y = current_yaw; + self.v_angle_x = 0; + self.v_angle_z = 0; + self.angles = self.v_angle; + makevectors(self.v_angle); org = self.origin; traceline(org, org + v_forward * lasergren_range, 0, self); @@ -146,7 +147,8 @@ void () NailGrenLaser = { //using self.playerclass to count thinks self.nextthink = time + lasergren_thinktime; self.playerclass++; - current_yaw = anglemod(self.angles_y + lasergren_angleperthink); + //already did this above + //current_yaw = anglemod(self.angles_y + lasergren_angleperthink); if (self.playerclass > lasergren_reqthinks) { //not >= to give an extra think so it hits start again self.owner = self.real_owner; From b4cdd61dad2fd867d594da8de2342651f9dc76b6 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 31 Mar 2019 16:54:49 +1300 Subject: [PATCH 0638/2474] Flag messages and statusbar flaginfo --- README.md | 1 + status.qc | 71 +++++++++++++++++++++++++++++++++++++- tfortmap.qc | 98 ++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 142 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 576907f6..4e347922 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Option for statusbar flaginfo. `setinfo sbflaginfo on ` * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. diff --git a/status.qc b/status.qc index 8b5a7434..82267ad2 100644 --- a/status.qc +++ b/status.qc @@ -19,6 +19,8 @@ string(entity pl) DisguiseToString; string(entity pl) SentryDetailsToString; string(entity pl) BuildingToString; string(float pc) TeamFortress_GetClassName; +entity(float ino) Finditem; +void () tfgoalitem_droptouch; string (float class) CF_GetRandomClassTip { local string tiptype = ""; @@ -573,6 +575,42 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr Status_Print(pl, s1, s2, s3, s4, s5); }; +string (entity Player, entity Item) GetItemStatus = { + local string st = Item.netname; + if (Player.team_no == Item.owned_by) { + st = strcat(Q"\x10", st ,Q"\x11"); + //st = strcat("[", st ,"]"); + } + if (Item.goal_state == 1 && Item.owner != world) { + if (Player == Item.owner) { + st = strcat(st, Q"\s: Carried by \sYOU"); + } else { + st = strcat(st, Q"\s: Carried by \s", Item.owner.netname); + } + + } else { + if (Item.origin != Item.oldorigin) { + //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in + if((Item.nextthink - time) >= 0) { + if(Item.think == tfgoalitem_droptouch) { + // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.pausetime + Item.nextthink - time))); + st = strcat(st, Q"\s: Dropped \s"); + } else { + //tfgoalitem_dropthink is the normal countdown + // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); + st = strcat(st, Q"\s: Returning: \s", ftos(rint(Item.bubble_count - time))); + } + + } else { + st = strcat(st, Q"\s: Returning\s NOW!"); + } + } else { + st = strcat(st, Q"\s: Safe\s"); + } + } + return st; +} + void (entity pl) RefreshStatusBar = { local string pad; local string s1; // will be used for grenade timers @@ -583,6 +621,10 @@ void (entity pl) RefreshStatusBar = { local string ident; local float height; local float i; + local entity tfdet; //info_tfdetect entity + local entity te; + local string sbflaginfo; + sbflaginfo = infokey(pl, "sbflaginfo"); /* local float win, sec; */ pad = ""; @@ -615,7 +657,34 @@ void (entity pl) RefreshStatusBar = { ct = CF_GetRandomClassTip(pl.playerclass); } else { pl.display_tip = 0; - ct = strzone("\n\n\n\n\n\n"); + tfdet = find(world, classname, "info_tfdetect"); + if (!tfdet || sbflaginfo != "on") { + ct = strzone("\n\n\n\n\n\n"); + } else { + ct = ""; + if (tfdet.display_item_status1 != 0) { + te = Finditem(tfdet.display_item_status1); + if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); + } + ct = strcat(ct, "\n"); + if (tfdet.display_item_status2 != 0) { + te = Finditem(tfdet.display_item_status2); + if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); + } + ct = strcat(ct, "\n"); + if (tfdet.display_item_status3 != 0) { + te = Finditem(tfdet.display_item_status3); + if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); + } + ct = strcat(ct, "\n"); + if (tfdet.display_item_status4 != 0) { + te = Finditem(tfdet.display_item_status4); + if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); + } + ct = strcat(ct, "\n\n\n"); + + ct = strzone(ct); + } } // status line 1 column 1 - grenade timer diff --git a/tfortmap.qc b/tfortmap.qc index 9f525dc2..46054e75 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -233,34 +233,51 @@ void () TF_PlaceItem = { }; void () TF_StartItem = { - if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { - self.effects = self.effects | EF_DIMLIGHT; - - if (self.skin == 1.0) { + local entity tfdet; //info_tfdetect entity + tfdet = find(world, classname, "info_tfdetect"); + if (tfdet && (tfdet.display_item_status1 == self.goal_no || tfdet.display_item_status2 == self.goal_no || tfdet.display_item_status3 == self.goal_no || tfdet.display_item_status4 == self.goal_no)) { + if (self.owned_by == 1.0) { self.effects = self.effects | EF_BLUE; } - if (self.skin == 2.0) { + if (self.owned_by == 2.0) { self.effects = self.effects | EF_RED; } - if (self.skin == 3.0) { + if (self.owned_by == 3.0) { self.effects = self.effects | EF_RED; self.effects = self.effects | EF_MUZZLEFLASH; } - if (self.skin == 4.0) { + if (self.owned_by == 4.0) { self.effects = self.effects | EF_MUZZLEFLASH; } - } + } else { + if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { + self.effects = self.effects | EF_DIMLIGHT; - if (self.model == "progs/basrkey.bsp" ) { - self.effects = self.effects | EF_DIMLIGHT; - self.effects = self.effects | EF_RED; - } + if (self.skin == 1.0) { + self.effects = self.effects | EF_BLUE; + } + if (self.skin == 2.0) { + self.effects = self.effects | EF_RED; + } + if (self.skin == 3.0) { + self.effects = self.effects | EF_RED; + self.effects = self.effects | EF_MUZZLEFLASH; + } + if (self.skin == 4.0) { + self.effects = self.effects | EF_MUZZLEFLASH; + } + } - if (self.model == "progs/basbkey.bsp" ) { - self.effects = self.effects | EF_DIMLIGHT; - self.effects = self.effects | EF_BLUE; - } + if (self.model == "progs/basrkey.bsp" ) { + self.effects = self.effects | EF_DIMLIGHT; + self.effects = self.effects | EF_RED; + } + if (self.model == "progs/basbkey.bsp" ) { + self.effects = self.effects | EF_DIMLIGHT; + self.effects = self.effects | EF_BLUE; + } + } UpdateAbbreviations(self); self.nextthink = time + 0.2; self.think = TF_PlaceItem; @@ -2376,13 +2393,13 @@ void () tfgoalitem_dropthink = { self.movetype = 6; if (self.pausetime != 0) { pos = pointcontents(self.origin); - if (pos == -4) { + if (pos == -4) { //CONTENT_SLIME self.nextthink = time + (self.pausetime / 4); } else { - if (pos == -5) { + if (pos == -5) { //CONTENT_LAVA self.nextthink = time + 5; } else { - if ((pos == -2) || (pos == -6)) { + if ((pos == -2) || (pos == -6)) { //CONTENT_SOLID || CONTENT_SKY if (self.camdist < 3) { self.origin = self.camangle; setorigin(self, self.origin); @@ -2480,11 +2497,13 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { } Item.touch = SUB_Null; Item.nextthink = time + 0.75; + Item.bubble_count = time + Item.pausetime + 0.75 + 4.25; //used by the return timer Item.think = tfgoalitem_droptouch; } else { Item.touch = item_tfgoal_touch; Item.nextthink = time + 5; Item.think = tfgoalitem_dropthink; + Item.bubble_count = time + Item.pausetime + 5; //used by the return timer } Item.owner = world; }; @@ -2501,6 +2520,7 @@ void () tfgoalitem_remove = { te.weapon = 3; te.nextthink = time + 0.1; te.think = ReturnItem; + te.bubble_count = 0; //reset return time counter return; } dremove(self); @@ -2835,17 +2855,33 @@ void () DropGoalItems = { tfgoalitem_RemoveFromPlayer(te, self, 2); } } - else if (self.effects & EF_DIMLIGHT) { + //Always allow dropping 4096 + else if (self.effects & EF_DIMLIGHT || te.goal_activation & 4096) { te.angles = '0 0 0'; tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); - if (self.team_no == 1) - bprint(PRINT_HIGH, self.netname, Q" \sdropped red's flag!\s\n"); - else if (self.team_no == 2) - bprint(PRINT_HIGH, self.netname, Q" \sdropped blue's flag!\s\n"); - else - bprint(PRINT_HIGH, self.netname, Q" \sdropped the enemy's flag!\s\n"); - + if (!te.netname_team_drop || !te.netname_non_team_drop) { + if (te.netname) { + bprint(PRINT_HIGH, self.netname, Q" \sdropped ", te.netname ,"!\s\n"); + } else if (te.owned_by > 0) { + if (te.owned_by == 1) + bprint(PRINT_HIGH, self.netname, Q" \sdropped blue's flag!\s\n"); + else if (te.owned_by == 2) + bprint(PRINT_HIGH, self.netname, Q" \sdropped red's flag!\s\n"); + else if (te.owned_by == 3) + bprint(PRINT_HIGH, self.netname, Q" \sdropped yellow's flag!\s\n"); + else if (te.owned_by == 4) + bprint(PRINT_HIGH, self.netname, Q" \sdropped green's flag!\s\n"); + } else { + if (self.team_no == 1) + bprint(PRINT_HIGH, self.netname, Q" \sdropped red's flag!\s\n"); + else if (self.team_no == 2) + bprint(PRINT_HIGH, self.netname, Q" \sdropped blue's flag!\s\n"); + else + bprint(PRINT_HIGH, self.netname, Q" \sdropped the enemy's flag!\s\n"); + } + } + Status_Print(self, "\n\n\n", "You dropped the flag!"); search = find(world, classname, "player"); while (search) { @@ -2856,6 +2892,14 @@ void () DropGoalItems = { Status_Print(search, "\n\n\n", "The enemy dropped your flag!"); } search = find(search, classname, "player"); + if (te.owned_by > 0) { + if (te.netname_team_drop && te.netname_non_team_drop && search.team_no == te.owned_by) { + sprint(PRINT_HIGH, self.netname, te.netname_team_drop); + } + if (te.netname_team_drop && te.netname_non_team_drop && search.team_no != te.owned_by) { + sprint(PRINT_HIGH, self.netname, te.netname_non_team_drop); + } + } } } } From 8d344d6dfc60c887d47665000070f02980c3c9fe Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 3 Apr 2019 15:32:55 +1100 Subject: [PATCH 0639/2474] add centerprint with players names not ready --- clan.qc | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/clan.qc b/clan.qc index 83a34368..512793e0 100644 --- a/clan.qc +++ b/clan.qc @@ -145,7 +145,7 @@ void () StartMatch = } } }; - +void () CenterPrint_Players_NotReady; void () PreMatch_Think = { local entity p; local string num, tmp; @@ -250,6 +250,10 @@ void () PreMatch_Think = { } strunzone(num); } + + // centerprint those not ready + CenterPrint_Players_NotReady(); + self.nextthink = (time + 1); }; @@ -736,6 +740,43 @@ void () TeamFortress_ShowIDs = { sprint(self, PRINT_HIGH, "None\n"); }; +void () CenterPrint_Players_NotReady = { + string players_not_ready; + entity te; + players_not_ready = "Not ready: "; + + local float first = 0; + te = find (world, classname, "player"); + while (te) { + if (te.is_ready == 0) + { + first = first + 1; + if (first == 1) + { + players_not_ready = strcat(players_not_ready, te.netname); + } + else if (first > 1 && first < 5) + { + players_not_ready = strcat(players_not_ready, ", ", te.netname); + } + else if (first >= 5) + { + players_not_ready = strcat(players_not_ready, " and others..."); + break; + } + } + te = find (te, classname, "player"); + } + players_not_ready = strcat(players_not_ready, "\n", "If you are ready, type \s/ready\s in the console\n"); + + te = find(world, classname, "player"); + while (te) + { + centerprint(te, players_not_ready); + te = find(te, classname, "player"); + } +} + void () Broadcast_Players_NotReady = { local entity te; if (v_ready != 0) { From a81a4fbe16e743876addcf4dd7cf6d0bc58d250d Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 3 Apr 2019 15:37:11 +1100 Subject: [PATCH 0640/2474] stop broadcasting someone getting admin status when they already have it (allows for bind setting adminpwd and calling adminmenu) --- admin.qc | 4 ++++ commands.qc | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/admin.qc b/admin.qc index 3c886e5e..e335498f 100644 --- a/admin.qc +++ b/admin.qc @@ -243,6 +243,10 @@ void (entity p) CheckAutoKick = { void (string cl_pwd) Admin_Check = { + if (self.is_admin) { + sprint(self, PRINT_HIGH, "You are already an admin\n"); + return; + } local string st2; st2 = infokey(world, "adminpwd"); diff --git a/commands.qc b/commands.qc index c71f40d6..7b9b1d02 100644 --- a/commands.qc +++ b/commands.qc @@ -12,9 +12,6 @@ float (string arg1, string arg2) ParseCmds = { { processedCmd = TRUE; if (arg_num == 2) { - if (self.is_admin) { - sprint(self, PRINT_HIGH, "You are already an admin\n"); - } Admin_Check(arg2); if (self.is_admin) { Admin_Aliases(); From 013cfb29fe6c911f8c1daad847fce0ba5a2652d3 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 4 Apr 2019 00:12:45 +1100 Subject: [PATCH 0641/2474] ensure centerprint players not ready is on screen all of the time --- clan.qc | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/clan.qc b/clan.qc index 512793e0..6bf31f9b 100644 --- a/clan.qc +++ b/clan.qc @@ -145,7 +145,7 @@ void () StartMatch = } } }; -void () CenterPrint_Players_NotReady; + void () PreMatch_Think = { local entity p; local string num, tmp; @@ -251,9 +251,6 @@ void () PreMatch_Think = { strunzone(num); } - // centerprint those not ready - CenterPrint_Players_NotReady(); - self.nextthink = (time + 1); }; @@ -767,12 +764,12 @@ void () CenterPrint_Players_NotReady = { } te = find (te, classname, "player"); } - players_not_ready = strcat(players_not_ready, "\n", "If you are ready, type \s/ready\s in the console\n"); + players_not_ready = strcat(players_not_ready, "\n", "Type \s/ready\s in the console to toggle your ready status\n"); te = find(world, classname, "player"); while (te) { - centerprint(te, players_not_ready); + CenterPrint(te, players_not_ready); te = find(te, classname, "player"); } } @@ -872,17 +869,22 @@ void () RemoveVotes = { }; void () PreMatch_Message = { - local entity p = find (world, classname, "player"); - while (p != world) { - if (p.netname != "") { - sprint(p, PRINT_HIGH, "Currently in \sprematch\s time\n"); - if (p.is_ready) - sprint(p, PRINT_HIGH, "You are \sready\s to start the match.\n Type \s/notready\s in the console if you are not ready\n"); - else - sprint(p, PRINT_HIGH, "Type \s/ready\s in the console if you are ready to start the match\n"); - stuffcmd(p, "play buttons/switch04.wav\n"); + self.cnt2 = self.cnt2 + 1; + if (self.cnt2 % 30 == 0) + { + local entity p = find (world, classname, "player"); + while (p != world) { + if (p.netname != "") { + sprint(p, PRINT_HIGH, "Currently in \sprematch\s time\n"); + if (p.is_ready) + sprint(p, PRINT_HIGH, "You are \sready\s to start the match.\n Type \s/notready\s in the console if you are not ready\n"); + else + sprint(p, PRINT_HIGH, "Type \s/ready\s in the console if you are ready to start the match\n"); + stuffcmd(p, "play buttons/switch04.wav\n"); + } + p = find(p, classname, "player"); } - p = find(p, classname, "player"); } - self.nextthink = time + 30; + CenterPrint_Players_NotReady(); + self.nextthink = time + 1; } \ No newline at end of file From 5d1997f582613922fef5efbb4b4391778dc54508 Mon Sep 17 00:00:00 2001 From: fdittz Date: Wed, 10 Apr 2019 17:02:03 -0300 Subject: [PATCH 0642/2474] loc file support --- client.qc | 1 + locfiles.qc | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++ progs.src | 1 + qw.qc | 3 +++ 4 files changed, 78 insertions(+) create mode 100644 locfiles.qc diff --git a/client.qc b/client.qc index 4710a8c8..043a4552 100644 --- a/client.qc +++ b/client.qc @@ -185,6 +185,7 @@ void () DecodeLevelParms = { self.armortype = parm9 * 0.01; if (!(toggleflags & TFLAG_FIRSTENTRY)) { + loadloc(); toggleflags = parm10; flagem_checked = 0; diff --git a/locfiles.qc b/locfiles.qc new file mode 100644 index 00000000..0c0ffcfe --- /dev/null +++ b/locfiles.qc @@ -0,0 +1,73 @@ +#pragma target fte + +void loadloc() { + local float i; + local string ln; + local string out; + local float locfilehandle; + + local string path = strcat("locs/", mapname); + path = strcat(path, ".loc"); + locfilehandle = fopen(path, FILE_READ); + if (locfilehandle >= 0) { + ln = fgets(locfilehandle); + while (ln != string_null) { + numlocs++; + ln = fgets(locfilehandle); + } + fclose(locfilehandle); + + locs = memalloc(sizeof(*locs)*numlocs); + + locfilehandle = fopen(path, FILE_READ); + ln = fgets(locfilehandle); + i = 0; + while (ln != string_null && i < numlocs) { + float s1 = strstrofs(ln, " ", 0); + float s2 = strstrofs(ln, " ", s1+1); + float s3 = strstrofs(ln, " ", s2+1); + local string px = substring(ln, 0, s1); + local string py = substring(ln, s1+1, (s2-(s1+1))); + local string pz = substring(ln, s2+1, (s3-(s2+1))); + + locs[i].pos.x = stof(px); + locs[i].pos.y = stof(py); + locs[i].pos.z = stof(pz); + locs[i].desc = substring(ln, s3+1, strlen(ln)-s3+2); + i++; + ln = fgets(locfilehandle); + } + fclose(locfilehandle); + out = strcat("Loaded ", mapname); + out = strcat(out, ".loc with "); + out = strcat(out, ftos(numlocs)); + out = strcat(out, " locations\n"); + } + else { + out = strcat("Couldn't find ", mapname); + out = strcat(out, ".loc\n"); + } + dprint(out); +} + +string getLocationName(vector location) { + local float bestdist; + local string desc; + local float i; + + desc = "someplace"; + location = location * 8; + bestdist = 0; + for (i = 0; i < numlocs; i++) { + float dist = vlen(location - locs[i].pos); + if (bestdist == 0) { + bestdist = dist; + desc = locs[i].desc; + } + else if (dist < bestdist) { + bestdist = dist; + desc = locs[i].desc; + } + } + return desc; +} \ No newline at end of file diff --git a/progs.src b/progs.src index b9f9f7b0..d6933ca5 100644 --- a/progs.src +++ b/progs.src @@ -12,6 +12,7 @@ help.qc subs.qc combat.qc items.qc +locfiles.qc weapons.qc world.qc client.qc diff --git a/qw.qc b/qw.qc index 99b35ff2..fca50528 100644 --- a/qw.qc +++ b/qw.qc @@ -525,6 +525,9 @@ float unpause_countdown; float unpause_lastcountnumber; float chweap_wait_attfinished; +float numlocs; +typedef struct {vector pos; string desc;} loc_t; +loc_t *locs; .float teamkills; From d157000b4dd4b5b139730d206b9178e14c851770 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 12 Apr 2019 07:45:10 +1200 Subject: [PATCH 0643/2474] despawn backpacks between rounds; merge to master --- clan.qc | 40 ++++++++++++++++++++++++++-------------- items.qc | 1 + quadmode.qc | 36 ++++++++++++++++++++++++------------ spy.qc | 23 ++++++++++++----------- 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/clan.qc b/clan.qc index 6bf31f9b..b5b9f3ab 100644 --- a/clan.qc +++ b/clan.qc @@ -83,7 +83,7 @@ void () StartMatch = TeamFortress_RemoveTimers(); self.frags = 0; - self.real_frags = 0; + self.real_frags = 0; setspawnparms(self); if (!quadmode) PutClientInServer(); @@ -97,6 +97,18 @@ void () StartMatch = gren.nextthink = (time + 0.1); gren = find(gren, classname, "grenade"); } + te = find(world, classname, "detpack"); + while (te){ + if (te.weaponmode == 1) { + TeamFortress_SetSpeed (te.enemy); + dremove(te.oldenemy); + dremove(te.observer_list); + } + dremove(te.linked_list); + dremove(te); + te = find (te, classname, "detpack"); + } + cb_prematch = 0; cease_fire = 0; @@ -121,7 +133,7 @@ void () StartMatch = if (!quadmode) { te.think = MatchThink; te.nextthink = (time + 1); - } + } } st = infokey(world, "spectalk"); f2 = stof(st); @@ -182,7 +194,7 @@ void () PreMatch_Think = { } if (!quadmode) StartMatch(); - else + else StartQuadRound(); return; } @@ -263,7 +275,7 @@ void () ResetBreakAndReady = { v_break = 0; v_ready = 0; te = find (te, classname, "player"); - } + } } void () StartTimer = @@ -305,7 +317,7 @@ void () StartTimer = te.nextthink = 0.01; } - ResetBreakAndReady(); + ResetBreakAndReady(); timer = spawn(); timer.owner = world; timer.classname = "prematch"; @@ -426,13 +438,13 @@ void () DumpClanScores = { if ((no_teams == 2) && (((team1score == team2score) && teamfrags) || ((team1frags == team2frags) && !teamfrags))) { bprint(PRINT_HIGH, " draw "); - } + } else if ((no_teams == 3) && ((((team1score == team2score) == team3score) && teamfrags) || (((team1frags == team2frags) == team3frags) && !teamfrags))) { bprint(PRINT_HIGH, " draw "); - } + } else if ((no_teams == 3) && (((((team1score == team2score) == team3score) == team4score) @@ -441,7 +453,7 @@ void () DumpClanScores = { ((((team1frags == team2frags) == team3frags) == team4frags) && !teamfrags))) { bprint(PRINT_HIGH, " draw "); - } + } else { st = GetTeamName(winners); bprint(PRINT_HIGH, st, " defeated "); @@ -765,7 +777,7 @@ void () CenterPrint_Players_NotReady = { te = find (te, classname, "player"); } players_not_ready = strcat(players_not_ready, "\n", "Type \s/ready\s in the console to toggle your ready status\n"); - + te = find(world, classname, "player"); while (te) { @@ -785,11 +797,11 @@ void () Broadcast_Players_NotReady = { if (!first) players_not_ready = strcat(players_not_ready, ", "); else - first = 0; + first = 0; players_not_ready = strcat(players_not_ready, te.netname); } te = find (te, classname, "player"); - } + } players_not_ready = strcat(players_not_ready, "\n"); bprint(1, players_not_ready); te = find (world, classname, "player"); @@ -834,7 +846,7 @@ void () PlayerReady = if (self.playerclass == 0) { sprint(self, 2, "You must choose a class first.\n"); return; - } + } if (intermission_running) return; if (self.classname != "player") @@ -886,5 +898,5 @@ void () PreMatch_Message = { } } CenterPrint_Players_NotReady(); - self.nextthink = time + 1; -} \ No newline at end of file + self.nextthink = time + 1; +} diff --git a/items.qc b/items.qc index ae1790bd..c0a2b98f 100644 --- a/items.qc +++ b/items.qc @@ -1422,6 +1422,7 @@ void () DropBackpack = { setmodel(newmis, "progs/backpack.mdl"); setsize(newmis, '-16 -16 0', '16 16 56'); newmis.touch = BackpackTouch; + newmis.classname = "backpack"; newmis.nextthink = time + 120; newmis.think = SUB_Remove; diff --git a/quadmode.qc b/quadmode.qc index f3ee628c..f560814e 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -8,7 +8,7 @@ float () CheckWinningTeam = { win_score = team1score; winning_team = 1; } - + if (team2score > win_score) { win_score = team2score; winning_team = 2; @@ -57,7 +57,7 @@ void () QuadRoundThink = { } if (self.cnt == -1) - return; + return; if ( self.cnt == stof(infokey(world, "round_time")) - 1 && self.cnt2 == 59 ) { localcmd("serverinfo status \""); @@ -75,17 +75,17 @@ void () QuadRoundThink = { if (self.cnt2 == -1) { self.cnt2 = 59; - self.cnt = (self.cnt - 1); + self.cnt = (self.cnt - 1); } if (!cease_fire) self.cnt2 = (self.cnt2 - 1); - + if (!self.cnt2) { if ((self.cnt == 1) || (self.cnt == 5)) { tmp = ftos (self.cnt); bprint3(2, "\s[\s", tmp, "\s]\s minute"); - if (self.cnt != 1) + if (self.cnt != 1) bprint(2, "s"); bprint(2, " remaining\n"); } @@ -96,7 +96,7 @@ void () QuadRoundThink = { st = infokey(world, "round_delay_time"); bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); } - + // lightstyle (0, "e"); @@ -111,7 +111,7 @@ void () QuadRoundThink = { tmp = ftos(self.cnt2); bprint3(2, "\s[\s", tmp, "\s]\s second"); if ((self.cnt2 != 1)) - bprint(2, "s"); + bprint(2, "s"); bprint(2, " remaining\n"); } } @@ -152,12 +152,12 @@ void () QuadRoundBegin = { round_active = 1; round_over = 0; if (!self.cnt) { - self.cnt = stof(infokey (world, "round_time")) - 1; + self.cnt = stof(infokey (world, "round_time")) - 1; self.cnt2 = 60; } else { counter = floor(self.cnt); - if (counter < self.cnt) + if (counter < self.cnt) self.cnt2 = ((self.cnt - counter) * 60); else self.cnt2 = 60; @@ -211,7 +211,7 @@ void () QuadRoundInit = { while (p) { if (p.netname != "") { CenterPrint3(p, "Round begins in: ", num, " second(s).\nEnsure correct class is chosen!\n"); - + if (self.cnt2 <= 5) { cease_fire = 0; @@ -347,6 +347,18 @@ void () StartQuadRound = dremove(te); te = find (te, classname, "detpack"); } + te = find(world, classname, "backpack"); + while (te) { + te.think = SUB_Remove; + te.nextthink = (time + 0.1); + te = find(te, classname, "backpack"); + } + te = find(world, classname, "ammobox"); + while (te) { + te.think = SUB_Remove; + te.nextthink = (time + 0.1); + te = find(te, classname, "ammobox"); + } te = find(world, classname, "round"); st = infokey(world, "count"); @@ -369,7 +381,7 @@ void () StartQuadRound = } else { te.think = QuadRoundInit; - te.nextthink = (time + 1); + te.nextthink = (time + 1); } }; @@ -389,4 +401,4 @@ void () EndQuadRound = { } } } -}; \ No newline at end of file +}; diff --git a/spy.qc b/spy.qc index 61168ea0..35758771 100644 --- a/spy.qc +++ b/spy.qc @@ -708,17 +708,17 @@ void (entity own) Spy_SetClientSkins = { entity te; string color, dcolor, skin, dskin, sendcolor, sendskin; float dteam, dpc; - + dteam = own.undercover_team == 0 ? own.team_no : own.undercover_team; dpc = own.undercover_skin == 0 ? own.playerclass : own.undercover_skin; color = ftos(TeamFortress_TeamGetColor(own.team_no) - 1); dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); - + skin = TeamFortress_GetSkin(own.team_no, own.playerclass); dskin = TeamFortress_GetSkin(dteam, dpc); te = find(world, classname, "player"); - while (te) + while (te) { if (te.team_no) { @@ -731,9 +731,9 @@ void (entity own) Spy_SetClientSkins = { else // not on same team, send them disguise { sendcolor = dcolor; - sendskin = dskin; + sendskin = dskin; } - + msg_entity = te; // set skin @@ -747,14 +747,14 @@ void (entity own) Spy_SetClientSkins = { WriteByte(MSG_ONE, own.colormap-1); WriteString(MSG_ONE, "topcolor"); WriteString(MSG_ONE, sendcolor); - + // set bottom colour / color WriteByte(MSG_ONE, SVC_SETINFO); WriteByte(MSG_ONE, own.colormap-1); WriteString(MSG_ONE, "bottomcolor"); WriteString(MSG_ONE, sendcolor); } - + te = find(te, classname, "player"); } } @@ -796,7 +796,7 @@ void () CF_Spy_UndercoverThink = { self.owner.queue_skin = 0; self.owner.is_undercover = 1; TeamFortress_SetSkin(self.owner); - + if (self.owner.queue_team) { CF_Spy_ChangeColor(self.owner, self.owner.queue_team); } else { @@ -810,7 +810,7 @@ void () CF_Spy_UndercoverThink = { s_class = "Spy"; sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); } - + } else if (self.team) { self.owner.undercover_team = self.team; self.owner.last_team = self.team; @@ -829,7 +829,7 @@ void () CF_Spy_UndercoverThink = { sprint(self.owner, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); } } - + TeamFortress_SpyCalcName(self.owner); } @@ -837,7 +837,7 @@ void () CF_Spy_UndercoverThink = { Status_Refresh(self.owner); if (self.owner.menu_input == Menu_Spy_Input) Menu_Spy(self.owner); - + dremove(self); }; @@ -1437,6 +1437,7 @@ void () Spy_DropBackpack = { setmodel(newmis, "progs/backpack.mdl"); setsize(newmis, '-16 -16 0', '16 16 56'); newmis.touch = BackpackTouch; + newmis.classname = "backpack"; newmis.nextthink = time + 120; newmis.think = SUB_Remove; From b1e02df01d6c7778caa883e816c239f34e23a0d0 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 15 Apr 2019 22:45:38 +1000 Subject: [PATCH 0644/2474] remove scout dash restrictions --- scout.qc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scout.qc b/scout.qc index ff743084..fa70899d 100644 --- a/scout.qc +++ b/scout.qc @@ -24,17 +24,11 @@ void () CF_Scout_Dash = { if (!scoutdash || time < self.dash_cooldown) return; - // don't dash if scout is concussed or have damaged legs - if (self.leg_damage || self.is_concussed) - return; - // only dash if walking or slower - if (vlen(self.velocity) <= 450 && (self.flags & FL_ONGROUND)) { makevectors(self.angles); self.velocity = v_forward * 540; self.velocity_z = 181; sound(self, CHAN_BODY, "dash.wav", 1, ATTN_NORM); - } } void () CanisterTouch = From 0aaa57cc29e0db3e1dcea742384dd10246f2ae10 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 22 Apr 2019 20:47:56 +1000 Subject: [PATCH 0645/2474] actually give the dash a cooldown... --- scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scout.qc b/scout.qc index fa70899d..bc13245d 100644 --- a/scout.qc +++ b/scout.qc @@ -24,7 +24,7 @@ void () CF_Scout_Dash = { if (!scoutdash || time < self.dash_cooldown) return; - + self.dash_cooldown = time + 1; makevectors(self.angles); self.velocity = v_forward * 540; self.velocity_z = 181; From 18069954ef05de268110349454cb9e4e9b906695 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 26 Apr 2019 23:20:45 +1200 Subject: [PATCH 0646/2474] #113 - fix admin menu for (admin) spectators --- spect.qc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/spect.qc b/spect.qc index 40eac69d..54caeeaf 100644 --- a/spect.qc +++ b/spect.qc @@ -96,7 +96,23 @@ void () SpectatorImpulseCommand = { Admin_CycleDeal(); else if (self.impulse == TF_ADMIN_LISTIPS) Admin_ListIPs(); - + else if (self.impulse == TF_ADMIN_CLANMODE) + ClanMode(); + else if (self.impulse == TF_ADMIN_QUADMODE) + QuadMode(); + else if (self.impulse == TF_ADMIN_ADMINMENU) { + self.current_menu_page = 1; + Menu_Admin(); + } + else if (self.impulse == TF_ADMIN_FORCESTARTMATCH) + StartTimer(); + else if (self.impulse == TF_ADMIN_READYSTATUS) + Broadcast_Players_NotReady(); + + else if (self.impulse > 0 && self.impulse <= 10) { + self.menu_input(self.impulse); + } + self.impulse = 0; }; From 30f00b6c2822be5957cacd1db9601b8ab9c4485f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 26 Apr 2019 23:39:54 +1200 Subject: [PATCH 0647/2474] #92 - make team selection impulses check for total number of teams --- weapons.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/weapons.qc b/weapons.qc index 3d47458b..9906f16e 100644 --- a/weapons.qc +++ b/weapons.qc @@ -3013,13 +3013,13 @@ void () DeadImpulses = { TeamFortress_NailGrenInfo(); else if (self.impulse == TF_STATUS_QUERY) TeamFortress_StatusQuery(); - else if (self.impulse == TF_TEAM_1) + else if (self.impulse == TF_TEAM_1 && number_of_teams > 0) TeamFortress_TeamSet(1); - else if (self.impulse == TF_TEAM_2) + else if (self.impulse == TF_TEAM_2 && number_of_teams > 1) TeamFortress_TeamSet(2); - else if (self.impulse == TF_TEAM_3) + else if (self.impulse == TF_TEAM_3 && number_of_teams > 2) TeamFortress_TeamSet(3); - else if (self.impulse == TF_TEAM_4) + else if (self.impulse == TF_TEAM_4 && number_of_teams > 3) TeamFortress_TeamSet(4); else if (self.impulse == TF_TEAM_SCORES) TeamFortress_TeamShowScores(0); From 64fa6c76aa63fc7a33416c7027dce140d52235bc Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 27 Apr 2019 18:46:27 +1200 Subject: [PATCH 0648/2474] Added ceasefire, readystatus and forcestart to admin menu --- admin.qc | 10 +++++++--- clan.qc | 8 ++++++-- menu.qc | 25 ++++++++++++++++++++----- weapons.qc | 3 ++- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/admin.qc b/admin.qc index e335498f..b9270d54 100644 --- a/admin.qc +++ b/admin.qc @@ -132,6 +132,8 @@ void () CeaseFire_think = void () Admin_CeaseFire = { local entity te; + bprint(2, "Admin_CeaseFire, cb_prematch: ",ftos(cb_prematch)," is_countdown: ",ftos(is_countdown),"\n"); + bprint(2, "Admin_CeaseFire, v_ready: ",ftos(v_ready)," TeamFortress_GetNoPlayers: ",ftos(TeamFortress_GetNoPlayers()),"\n"); if (!cease_fire) { if (cb_prematch) { @@ -159,10 +161,12 @@ void () Admin_CeaseFire = { dremove(te); } cease_fire = 0; + bprint(2, "RESUME FIRE\n"); if (cb_prematch) { - StartTimer(); + if (is_countdown || v_ready == TeamFortress_GetNoPlayers () ) { + StartTimer(); + } } - bprint(2, "RESUME FIRE\n"); te = find(world, classname, "player"); while (te) { CenterPrint3(te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); @@ -277,4 +281,4 @@ void () Admin_Aliases = TeamFortress_Alias("startmatch", TF_ADMIN_FORCESTARTMATCH, 0); TeamFortress_Alias("readystatus", TF_ADMIN_READYSTATUS, 0); stuffcmd(self,"alias ceasefire \"cmd ceasefire\"\n"); -}; \ No newline at end of file +}; diff --git a/clan.qc b/clan.qc index b5b9f3ab..1ef22a4b 100644 --- a/clan.qc +++ b/clan.qc @@ -860,8 +860,12 @@ void () PlayerReady = bprint2 (3, self.netname, " is ready to start the match\n"); f1 = TeamFortress_GetNoPlayers (); if (v_ready == f1 ) { - bprint (2, "All players ready, starting match\n"); - StartTimer (); + if(cease_fire) { + bprint (2, "All players ready, match will start after ceasefire ends.\n"); + } else { + bprint (2, "All players ready, starting match\n"); + StartTimer (); + } return; } Broadcast_Players_NotReady(); diff --git a/menu.qc b/menu.qc index 4b23060a..c833ffcf 100644 --- a/menu.qc +++ b/menu.qc @@ -1048,7 +1048,7 @@ void () Menu_Admin = case ADMIN_MENU_TYPE_MAIN: s_menu1 = "FortressOne Admin Menu: \n\n"; if (self.current_menu_page == 1) { - s_menu1 = strcat(s_menu1, Q"\s[1]\s Not Used \n"); + s_menu1 = strcat(s_menu1, Q"\s[1]\s Ceasefire \n"); s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit \n"); s_menu1 = strcat(s_menu1, Q"\s[3]\s Kick \n"); s_menu1 = strcat(s_menu1, Q"\s[4]\s Ban \n"); @@ -1061,8 +1061,8 @@ void () Menu_Admin = s_menu1 = strcat(s_menu1, Q"\s[3]\s Pub Mode \n"); s_menu1 = strcat(s_menu1, Q"\s[4]\s Duel Mode (Not implemented) \n"); s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); - s_menu1 = strcat(s_menu1, Q"\s[6]\s \n"); - s_menu1 = strcat(s_menu1, Q"\s[7]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[6]\s Ready Status \n"); + s_menu1 = strcat(s_menu1, Q"\s[7]\s Force Match Start (Be Nice) \n"); } s_menu1 = strcat(s_menu1, "\n\n"); s_menu1 = strcat(s_menu1, Q"\s[8]\s Previous Page \n"); @@ -1226,7 +1226,8 @@ void (float inp) Menu_Admin_Input = { switch (inp) { - case 1: // Unused + case 1: // Ceasefire + self.impulse = TF_ADMIN_CEASEFIRE; return; case 2: // Change Timelimit if (stof(infokey (world, "timelimit")) > 35) { @@ -1332,6 +1333,20 @@ void (float inp) Menu_Admin_Input = self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 1; break; + case 5: // unused + return; + case 6: // ready status + self.impulse = TF_ADMIN_READYSTATUS; + Menu_Close(self); + return; + case 7: // force match start + if (clanbattle == 1 && cb_prematch == 1) { + bprint(PRINT_HIGH, self.netname); + bprint(PRINT_HIGH, " has forced the match start.\n"); + } + self.impulse = TF_ADMIN_FORCESTARTMATCH; + Menu_Close(self); + return; } } } @@ -1544,4 +1559,4 @@ void (float inp) Menu_Admin_Input = } } self.impulse = 0; -}; \ No newline at end of file +}; diff --git a/weapons.qc b/weapons.qc index 3d47458b..6f6a4238 100644 --- a/weapons.qc +++ b/weapons.qc @@ -3002,8 +3002,9 @@ void () DeadImpulses = { self.current_menu_page = 1; Menu_Admin(); } - else if (self.impulse == TF_ADMIN_FORCESTARTMATCH) + else if (self.impulse == TF_ADMIN_FORCESTARTMATCH) { StartTimer(); + } else if (self.impulse == TF_ADMIN_READYSTATUS) Broadcast_Players_NotReady(); } From 0028482945633c36f7eea25d03ab708396f15606 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 27 Apr 2019 18:54:07 +1200 Subject: [PATCH 0649/2474] Remove debug messages --- admin.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/admin.qc b/admin.qc index b9270d54..c72542a1 100644 --- a/admin.qc +++ b/admin.qc @@ -132,8 +132,6 @@ void () CeaseFire_think = void () Admin_CeaseFire = { local entity te; - bprint(2, "Admin_CeaseFire, cb_prematch: ",ftos(cb_prematch)," is_countdown: ",ftos(is_countdown),"\n"); - bprint(2, "Admin_CeaseFire, v_ready: ",ftos(v_ready)," TeamFortress_GetNoPlayers: ",ftos(TeamFortress_GetNoPlayers()),"\n"); if (!cease_fire) { if (cb_prematch) { From 3a572b80330d167175717315d9261c00a46b8d93 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 27 Apr 2019 19:30:14 +1200 Subject: [PATCH 0650/2474] Handle the 'pause'-style ceasefire --- admin.qc | 6 +++++- menu.qc | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/admin.qc b/admin.qc index c72542a1..d9b6c16d 100644 --- a/admin.qc +++ b/admin.qc @@ -161,6 +161,7 @@ void () Admin_CeaseFire = { cease_fire = 0; bprint(2, "RESUME FIRE\n"); if (cb_prematch) { + //Make sure you don't just start the countdown on resume when not everyone's readied up if (is_countdown || v_ready == TeamFortress_GetNoPlayers () ) { StartTimer(); } @@ -190,7 +191,10 @@ void () Admin_Pause = { } else { if (cb_prematch) { - StartTimer(); + //Make sure you don't just start the countdown on resume when not everyone's readied up + if (is_countdown || v_ready == TeamFortress_GetNoPlayers () ) { + StartTimer(); + } setpause(0); is_paused = 0; return; diff --git a/menu.qc b/menu.qc index c833ffcf..58ba9048 100644 --- a/menu.qc +++ b/menu.qc @@ -94,6 +94,11 @@ void () Menu_Admin; void (float inp) Menu_Admin_Input; void () Admin_DoKick; +void () Admin_Pause; +void () Admin_CeaseFire; +void () Broadcast_Players_NotReady; +void () StartTimer; + void (entity pl) Menu_Close = { pl.menu_input = nil; @@ -1227,7 +1232,10 @@ void (float inp) Menu_Admin_Input = switch (inp) { case 1: // Ceasefire - self.impulse = TF_ADMIN_CEASEFIRE; + if (ceasefire_type) + Admin_Pause(); + else + Admin_CeaseFire(); return; case 2: // Change Timelimit if (stof(infokey (world, "timelimit")) > 35) { @@ -1336,15 +1344,15 @@ void (float inp) Menu_Admin_Input = case 5: // unused return; case 6: // ready status - self.impulse = TF_ADMIN_READYSTATUS; + Broadcast_Players_NotReady(); Menu_Close(self); return; case 7: // force match start if (clanbattle == 1 && cb_prematch == 1) { bprint(PRINT_HIGH, self.netname); bprint(PRINT_HIGH, " has forced the match start.\n"); + StartTimer(); } - self.impulse = TF_ADMIN_FORCESTARTMATCH; Menu_Close(self); return; } From e501345de1811b661308ffb0645033cc9a9a6796 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 27 Apr 2019 21:50:17 +1200 Subject: [PATCH 0651/2474] Fix for door sounds sometimes looping --- doors.qc | 8 ++++++-- quadmode.qc | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doors.qc b/doors.qc index 0a405816..ad26ffe9 100644 --- a/doors.qc +++ b/doors.qc @@ -42,14 +42,18 @@ void () door_hit_bottom = { self.state = 1; }; -void () door_go_down = { - sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); +void () door_go_down_silent = { if (self.max_health) { self.takedamage = 1; self.health = self.max_health; } self.state = STATE_DOWN; SUB_CalcMove(self.pos1, self.speed, door_hit_bottom); +} + +void () door_go_down = { + sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + door_go_down_silent(); }; void () door_go_up = { diff --git a/quadmode.qc b/quadmode.qc index f560814e..4a4d7256 100644 --- a/quadmode.qc +++ b/quadmode.qc @@ -287,7 +287,8 @@ void () StartQuadRound = while (te != world) { te2 = self; self = te; - door_go_down(); + //door_go_down(); + door_go_down_silent(); self.think = LinkDoors; self = te2; te = find(te, classname, "door"); From 54bb5b8e8afe71ab4992574c889829b2eec0f66d Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 29 Apr 2019 23:03:23 +1000 Subject: [PATCH 0652/2474] change loadloc to be on worldspawn --- client.qc | 2 +- world.qc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client.qc b/client.qc index 043a4552..aa9a583c 100644 --- a/client.qc +++ b/client.qc @@ -185,7 +185,7 @@ void () DecodeLevelParms = { self.armortype = parm9 * 0.01; if (!(toggleflags & TFLAG_FIRSTENTRY)) { - loadloc(); + toggleflags = parm10; flagem_checked = 0; diff --git a/world.qc b/world.qc index 460b1f5e..c4b385f1 100644 --- a/world.qc +++ b/world.qc @@ -122,6 +122,8 @@ void () worldspawn = { WriteByte(MSG_INIT, 9/*svc_stufftext*/); WriteString(MSG_INIT, "set fo_serverscripts 1\n"); + loadloc(); + local string st; lastspawn = world; From 477961d4cc2bc0ceb3422dbcd512965f415d3f88 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 29 Apr 2019 23:05:40 +1000 Subject: [PATCH 0653/2474] remove old scores code for status bar, it's going away soon anyway --- status.qc | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/status.qc b/status.qc index 82267ad2..3145675f 100644 --- a/status.qc +++ b/status.qc @@ -745,34 +745,6 @@ void (entity pl) RefreshStatusBar = { s2 = strcat(s2, "\n"); s2 = strzone(s2); - // status line 3 column 1 - team 1 score - /* win = TeamFortress_TeamGetWinner(); */ - /* sec = TeamFortress_TeamGetSecond(); */ - /* if (win == 0) */ - /* st1 = BlueScoreToString(team1score); */ - /* else if (win == 1) */ - /* st1 = BlueScoreToString(team1score); */ - /* else if (win == 2) */ - /* st1 = RedScoreToString(team2score); */ - /* else if (win == 3) */ - /* st1 = YellowScoreToString(team3score); */ - /* else */ - /* st1 = GreenScoreToString(team4score); */ - /* // status line 3 column 2 - team 2 score */ - /* if (sec == 0) { */ - /* if (win < 2) */ - /* st2 = RedScoreToString(team2score); */ - /* else */ - /* st2 = BlueScoreToString(team1score); */ - /* } */ - /* else if (sec == 1) */ - /* st2 = BlueScoreToString(team1score); */ - /* else if (sec == 2) */ - /* st2 = RedScoreToString(team2score); */ - /* else if (sec == 3) */ - /* st2 = YellowScoreToString(team3score); */ - /* else */ - /* st2 = GreenScoreToString(team4score); */ st1 = ""; st2 = ""; From ac9afcf640eca1c28abcc2ea957ea3c52f7a070e Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 29 Apr 2019 23:43:34 +1000 Subject: [PATCH 0654/2474] hardcode flag names for now as it's smaller name and ugly with locs sometimes otherwise --- status.qc | 69 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/status.qc b/status.qc index 3145675f..33c9daba 100644 --- a/status.qc +++ b/status.qc @@ -575,8 +575,25 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr Status_Print(pl, s1, s2, s3, s4, s5); }; -string (entity Player, entity Item) GetItemStatus = { - local string st = Item.netname; +string getLocationName(vector location); + +string (entity Player, entity Item, float teamno) GetItemStatus = { + local string st; + switch (teamno) + { + case 1: + st = "Blue Flag"; + break; + case 2: + st = "Red Flag"; + break; + case 3: + st = "Yellow Flag"; + break; + case 4: + st = "Green Flag"; + break; + } if (Player.team_no == Item.owned_by) { st = strcat(Q"\x10", st ,Q"\x11"); //st = strcat("[", st ,"]"); @@ -592,13 +609,12 @@ string (entity Player, entity Item) GetItemStatus = { if (Item.origin != Item.oldorigin) { //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in if((Item.nextthink - time) >= 0) { - if(Item.think == tfgoalitem_droptouch) { // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.pausetime + Item.nextthink - time))); - st = strcat(st, Q"\s: Dropped \s"); - } else { + st = strcat(st, Q"\s: Dropped: \s", getLocationName(Item.origin)); + if(Item.think != tfgoalitem_droptouch) { //tfgoalitem_dropthink is the normal countdown // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); - st = strcat(st, Q"\s: Returning: \s", ftos(rint(Item.bubble_count - time))); + st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); } } else { @@ -662,24 +678,29 @@ void (entity pl) RefreshStatusBar = { ct = strzone("\n\n\n\n\n\n"); } else { ct = ""; - if (tfdet.display_item_status1 != 0) { - te = Finditem(tfdet.display_item_status1); - if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); - } - ct = strcat(ct, "\n"); - if (tfdet.display_item_status2 != 0) { - te = Finditem(tfdet.display_item_status2); - if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); - } - ct = strcat(ct, "\n"); - if (tfdet.display_item_status3 != 0) { - te = Finditem(tfdet.display_item_status3); - if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); - } - ct = strcat(ct, "\n"); - if (tfdet.display_item_status4 != 0) { - te = Finditem(tfdet.display_item_status4); - if (te) ct = strcat(ct, strpadr(GetItemStatus(pl, te),40)); + + for (float t = 1; t <= number_of_teams; t++) { + switch (t) + { + case 1: + te = Finditem(tfdet.display_item_status1); + break; + case 2: + te = Finditem(tfdet.display_item_status2); + break; + case 3: + te = Finditem(tfdet.display_item_status3); + break; + case 4: + te = Finditem(tfdet.display_item_status4); + break; + } + + if (te) + { + ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40)); + } + ct = strcat(ct, "\n"); } ct = strcat(ct, "\n\n\n"); From 569fda002659b56bb67ee18b09cc6fdf85bd45bc Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 29 Apr 2019 23:43:59 +1000 Subject: [PATCH 0655/2474] .. change some stuff for some reason --- tfort.qc | 57 +++++++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/tfort.qc b/tfort.qc index da29d366..81b8a044 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2818,46 +2818,39 @@ void () NormalGrenadeExplode = { }; void () TeamFortress_DisplayDetectionItems = { - local entity Goal; + local entity tfdet; local entity te; + te = world; - Goal = find(world, classname, "info_tfdetect"); - if (!Goal) + tfdet = find(world, classname, "info_tfdetect"); + if (!tfdet) return; - if (Goal.display_item_status1 != 0) { - te = Finditem(Goal.display_item_status1); - if (te) - DisplayItemStatus(Goal, self, te); - else - sprint(self, PRINT_HIGH, "Item is missing\n"); - } else - return; - - if (Goal.display_item_status2 != 0) { - te = Finditem(Goal.display_item_status2); - if (te) - DisplayItemStatus(Goal, self, te); - else - sprint(self, PRINT_HIGH, "Item is missing\n"); - } else - return; - - if (Goal.display_item_status3 != 0) { - te = Finditem(Goal.display_item_status3); - if (te) - DisplayItemStatus(Goal, self, te); - else - sprint(self, PRINT_HIGH, "Item is missing\n"); - } else - return; + for (float t = 1; t <= number_of_teams; t++) { + switch (t) + { + case 1: + te = Finditem(tfdet.display_item_status1); + break; + case 2: + te = Finditem(tfdet.display_item_status2); + break; + case 3: + te = Finditem(tfdet.display_item_status3); + break; + case 4: + te = Finditem(tfdet.display_item_status4); + break; + } - if (Goal.display_item_status4 != 0) { - te = Finditem(Goal.display_item_status4); if (te) - DisplayItemStatus(Goal, self, te); + { + sprint(self, PRINT_HIGH, strcat(GetItemStatus(self, te, t), "\n")); + } else + { sprint(self, PRINT_HIGH, "Item is missing\n"); + } } }; From ba0b2ade796ac9ebbff720c217374eff8d6f44b8 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 30 Apr 2019 22:40:58 +1200 Subject: [PATCH 0656/2474] Location on 2 lines if only 2 teams; basic button status support; need to fix permanent location still --- qw.qc | 3 ++- status.qc | 69 ++++++++++++++++++++++++++++++++++++++++++++--------- tfortmap.qc | 4 +++- 3 files changed, 63 insertions(+), 13 deletions(-) diff --git a/qw.qc b/qw.qc index fca50528..bb4d197d 100644 --- a/qw.qc +++ b/qw.qc @@ -332,6 +332,7 @@ float item_list_bit; // Global, used to determine what the bit of .float delay_time; // For delayed goal results .float dont_do_triggerwork; +.float track_goal; // Track this info_goal in the statusbar // Abbreviations for the above .float g_a; // goal_activation @@ -602,4 +603,4 @@ string (string s, float width) strpadr = }; float captainmode; -.float captain; \ No newline at end of file +.float captain; diff --git a/status.qc b/status.qc index 33c9daba..b31981bc 100644 --- a/status.qc +++ b/status.qc @@ -609,13 +609,27 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { if (Item.origin != Item.oldorigin) { //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in if((Item.nextthink - time) >= 0) { - // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.pausetime + Item.nextthink - time))); - st = strcat(st, Q"\s: Dropped: \s", getLocationName(Item.origin)); - if(Item.think != tfgoalitem_droptouch) { - //tfgoalitem_dropthink is the normal countdown - // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); - st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); - } + //if(number_of_teams < 3) { + // if(Item.think != tfgoalitem_droptouch) { + // //tfgoalitem_dropthink is the normal countdown + // // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); + // st = strpadr(strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time)), "\n"),40); + // dprint(st); + // } else { + // st = strpadr(strcat(st, Q"\s: Dropped: \s\n"),40); + // } + // st = strcat(st, strpadr(strcat(Q"\s Location: \s", getLocationName(Item.origin)),40)); + // dprint(st); + + //} else { + // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.pausetime + Item.nextthink - time))); + //st = strcat(st, Q"\s: Dropped: \s", getLocationName(Item.origin)); + if(Item.think != tfgoalitem_droptouch) { + //tfgoalitem_dropthink is the normal countdown + // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); + st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); + } + //} } else { st = strcat(st, Q"\s: Returning\s NOW!"); @@ -638,7 +652,8 @@ void (entity pl) RefreshStatusBar = { local float height; local float i; local entity tfdet; //info_tfdetect entity - local entity te; + local entity te, tg; + local string bi; //button info local string sbflaginfo; sbflaginfo = infokey(pl, "sbflaginfo"); /* local float win, sec; */ @@ -678,7 +693,7 @@ void (entity pl) RefreshStatusBar = { ct = strzone("\n\n\n\n\n\n"); } else { ct = ""; - + i = 0; // Extra newlines for (float t = 1; t <= number_of_teams; t++) { switch (t) { @@ -698,11 +713,43 @@ void (entity pl) RefreshStatusBar = { if (te) { - ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40)); + if(number_of_teams < 3) { + ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40),"\n"); + if(te.think != tfgoalitem_droptouch) { + ct = strcat(ct, strpadr(strcat("\s Location: \s", getLocationName(te.origin)),40)); + } + i += 1; + } else { + ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40)); + } } ct = strcat(ct, "\n"); } - ct = strcat(ct, "\n\n\n"); + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.track_goal && tg.goal_state == TFGS_DELAYED) { + bi = ""; + //only do this for named goals, otherwise there's no way to distinguish them (they don't ususally have owned_by or anything) + if(tg.netname) { + bi = tg.netname; + if(tg.team_str_moved) { + bi = strcat(bi,": ", tg.team_str_moved); + } else { + bi = strcat(bi,": \sOffline\s"); + } + bi = strcat(bi, " ", ftos(rint(tg.bubble_count - time))); + ct = strcat(ct, strpadr(bi,40),"\n"); + i += 1; + } + } + tg = find(tg, classname, "info_tfgoal"); + } + + + for (float t = 0; t < (3 - i); t++) + ct = strcat(ct, "\n"); + + //ct = strcat(ct, "\n\n\n"); ct = strzone(ct); } diff --git a/tfortmap.qc b/tfortmap.qc index 46054e75..39350ac3 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -1667,6 +1667,7 @@ void (entity Goal, entity AP, float addb) DoResults = { te.owner = AP; te.enemy = Goal; te.weapon = addb; + Goal.bubble_count = time + Goal.delay_time; return; } @@ -2842,7 +2843,8 @@ void (entity P) ForceRespawn = { void () DropGoalItems = { local entity te, search; - + + dprint("DropGoalItems requested"); newmis = spawn(); makevectors(self.v_angle); v_forward = normalize(v_forward) * 64; From 4ed9a4a6f13cd944a4601dae279452ef0ce0ed99 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 1 May 2019 00:10:49 +1200 Subject: [PATCH 0657/2474] All works --- status.qc | 7 +++++-- tfortmap.qc | 21 ++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/status.qc b/status.qc index b31981bc..1eb5c339 100644 --- a/status.qc +++ b/status.qc @@ -21,6 +21,7 @@ string(entity pl) BuildingToString; string(float pc) TeamFortress_GetClassName; entity(float ino) Finditem; void () tfgoalitem_droptouch; +void () tfgoalitem_dropthink; string (float class) CF_GetRandomClassTip { local string tiptype = ""; @@ -627,7 +628,9 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { if(Item.think != tfgoalitem_droptouch) { //tfgoalitem_dropthink is the normal countdown // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); - st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); + st = strcat(st, Q"\s: Returning: \s", ftos(rint(Item.bubble_count - time))); + } else { + st = strcat(st, Q"\s: Dropped\s"); } //} @@ -715,7 +718,7 @@ void (entity pl) RefreshStatusBar = { { if(number_of_teams < 3) { ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40),"\n"); - if(te.think != tfgoalitem_droptouch) { + if(te.think == tfgoalitem_dropthink && te.flags & FL_ONGROUND) { ct = strcat(ct, strpadr(strcat("\s Location: \s", getLocationName(te.origin)),40)); } i += 1; diff --git a/tfortmap.qc b/tfortmap.qc index 39350ac3..539fe26a 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -588,7 +588,7 @@ void (entity AD) ParseTFDetect = { entity(float ino) Finditem = { local entity tg; - local string st; + //local string st; tg = find(world, classname, "item_tfgoal"); while (tg) { @@ -596,10 +596,10 @@ entity(float ino) Finditem = return (tg); tg = find(tg, classname, "item_tfgoal"); } - dprint("Could not find an item with a goal_no of "); - st = ftos(ino); - dprint(st); - dprint(".\n"); + //dprint("Could not find an item with a goal_no of "); + //st = ftos(ino); + //dprint(st); + //dprint(".\n"); return world; }; @@ -2844,7 +2844,6 @@ void (entity P) ForceRespawn = { void () DropGoalItems = { local entity te, search; - dprint("DropGoalItems requested"); newmis = spawn(); makevectors(self.v_angle); v_forward = normalize(v_forward) * 64; @@ -2893,15 +2892,15 @@ void () DropGoalItems = { } else { Status_Print(search, "\n\n\n", "The enemy dropped your flag!"); } - search = find(search, classname, "player"); - if (te.owned_by > 0) { + if (te.owned_by) { if (te.netname_team_drop && te.netname_non_team_drop && search.team_no == te.owned_by) { - sprint(PRINT_HIGH, self.netname, te.netname_team_drop); + sprint(search, PRINT_HIGH, self.netname, te.netname_team_drop); } if (te.netname_team_drop && te.netname_non_team_drop && search.team_no != te.owned_by) { - sprint(PRINT_HIGH, self.netname, te.netname_non_team_drop); + sprint(search, PRINT_HIGH, self.netname, te.netname_non_team_drop); } - } + } + search = find(search, classname, "player"); } } } From 60d0ddfe1b01bc864f38db770b254ff5470ae28f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 1 May 2019 00:14:09 +1200 Subject: [PATCH 0658/2474] Cleaning up commented stuff --- status.qc | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/status.qc b/status.qc index 1eb5c339..ffed9802 100644 --- a/status.qc +++ b/status.qc @@ -610,30 +610,11 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { if (Item.origin != Item.oldorigin) { //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in if((Item.nextthink - time) >= 0) { - //if(number_of_teams < 3) { - // if(Item.think != tfgoalitem_droptouch) { - // //tfgoalitem_dropthink is the normal countdown - // // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); - // st = strpadr(strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time)), "\n"),40); - // dprint(st); - // } else { - // st = strpadr(strcat(st, Q"\s: Dropped: \s\n"),40); - // } - // st = strcat(st, strpadr(strcat(Q"\s Location: \s", getLocationName(Item.origin)),40)); - // dprint(st); - - //} else { - // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.pausetime + Item.nextthink - time))); - //st = strcat(st, Q"\s: Dropped: \s", getLocationName(Item.origin)); - if(Item.think != tfgoalitem_droptouch) { - //tfgoalitem_dropthink is the normal countdown - // st = strcat(st, Q"\s: Dropped \s", ftos(rint(Item.nextthink - time))); - st = strcat(st, Q"\s: Returning: \s", ftos(rint(Item.bubble_count - time))); - } else { - st = strcat(st, Q"\s: Dropped\s"); - } - //} - + if(Item.think != tfgoalitem_droptouch) { + st = strcat(st, Q"\s: Returning: \s", ftos(rint(Item.bubble_count - time))); + } else { + st = strcat(st, Q"\s: Dropped\s"); + } } else { st = strcat(st, Q"\s: Returning\s NOW!"); } @@ -716,7 +697,7 @@ void (entity pl) RefreshStatusBar = { if (te) { - if(number_of_teams < 3) { + if(number_of_teams < 4) { ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40),"\n"); if(te.think == tfgoalitem_dropthink && te.flags & FL_ONGROUND) { ct = strcat(ct, strpadr(strcat("\s Location: \s", getLocationName(te.origin)),40)); @@ -730,7 +711,7 @@ void (entity pl) RefreshStatusBar = { } tg = find(world, classname, "info_tfgoal"); while (tg) { - if (tg.track_goal && tg.goal_state == TFGS_DELAYED) { + if (tg.track_goal && tg.goal_state == TFGS_DELAYED && i < 3) { bi = ""; //only do this for named goals, otherwise there's no way to distinguish them (they don't ususally have owned_by or anything) if(tg.netname) { From 4e38b393c9e57379fe7d9ccee1dbf700e2dc36b0 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 1 May 2019 00:21:06 +1200 Subject: [PATCH 0659/2474] Cleaning up commented stuff --- status.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/status.qc b/status.qc index ffed9802..4d067224 100644 --- a/status.qc +++ b/status.qc @@ -22,6 +22,7 @@ string(float pc) TeamFortress_GetClassName; entity(float ino) Finditem; void () tfgoalitem_droptouch; void () tfgoalitem_dropthink; +void () tfgoalitem_remove; string (float class) CF_GetRandomClassTip { local string tiptype = ""; @@ -699,7 +700,7 @@ void (entity pl) RefreshStatusBar = { { if(number_of_teams < 4) { ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40),"\n"); - if(te.think == tfgoalitem_dropthink && te.flags & FL_ONGROUND) { + if((te.think == tfgoalitem_dropthink || te.think == tfgoalitem_remove) && !te.owner) { ct = strcat(ct, strpadr(strcat("\s Location: \s", getLocationName(te.origin)),40)); } i += 1; From 6443a5586b3a59d0739eb66d0a070f7f3cd44805 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 1 May 2019 00:35:49 +1200 Subject: [PATCH 0660/2474] 4 player format fix --- status.qc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/status.qc b/status.qc index 4d067224..3ad9022f 100644 --- a/status.qc +++ b/status.qc @@ -612,7 +612,7 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in if((Item.nextthink - time) >= 0) { if(Item.think != tfgoalitem_droptouch) { - st = strcat(st, Q"\s: Returning: \s", ftos(rint(Item.bubble_count - time))); + st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); } else { st = strcat(st, Q"\s: Dropped\s"); } @@ -705,7 +705,11 @@ void (entity pl) RefreshStatusBar = { } i += 1; } else { - ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40)); + if((te.think == tfgoalitem_dropthink || te.think == tfgoalitem_remove) && !te.owner) { + ct = strcat(ct, strpadr(strcat(GetItemStatus(pl, te, t),"\s: \s", getLocationName(te.origin)),40)); + } else { + ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40)); + } } } ct = strcat(ct, "\n"); From 07807ff77bbe97e21823d533548d43e13f1c0dbb Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 1 May 2019 09:52:11 +1000 Subject: [PATCH 0661/2474] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 576907f6..9b595c09 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ FortressOne Server v0.1.0 New features ------ +* Admin system created to allow for easy setup of pub/pug/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` +* Loc support added to server, show locations for dropped flag. +* Nailgrenades changed to "Shock/Laser Grenades" to lower spam/not stop bunnyhopping on hit (0 original, 1 laser, 2 burst). `localinfo nailgren_type 1` and `nginfo` in game for all configurable settings. +* Option for flaginfo on sbar. `setinfo sbflaginfo on` * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. From 84a2980fec1e74786e9ac1171f2796f3c2c919aa Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 4 May 2019 01:03:26 +1200 Subject: [PATCH 0662/2474] Don't crash the server when using weapon impulses as an admin spectator --- menu.qc | 3 ++- spect.qc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/menu.qc b/menu.qc index 58ba9048..8c450c31 100644 --- a/menu.qc +++ b/menu.qc @@ -124,7 +124,8 @@ void (float inp) Menu_Input = var f_void_float tmp; tmp = self.menu_input; self.menu_input = nil; self.impulse = 0; - tmp(inp); + if(tmp) + tmp(inp); Status_Print(self, ""); }; diff --git a/spect.qc b/spect.qc index 54caeeaf..8e2b9539 100644 --- a/spect.qc +++ b/spect.qc @@ -110,7 +110,7 @@ void () SpectatorImpulseCommand = { Broadcast_Players_NotReady(); else if (self.impulse > 0 && self.impulse <= 10) { - self.menu_input(self.impulse); + Menu_Input(self.impulse); } self.impulse = 0; From 1726caa35a92368b0be07ab3b53ffd8b34a72e51 Mon Sep 17 00:00:00 2001 From: fdittz Date: Fri, 3 May 2019 15:48:29 -0300 Subject: [PATCH 0663/2474] putting flag follow on toggles --- client.qc | 3 +++ tfortmap.qc | 12 +++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 4710a8c8..2a91064d 100644 --- a/client.qc +++ b/client.qc @@ -536,6 +536,9 @@ void () DecodeLevelParms = { // wait until attack_finished is over before changing weapons chweap_wait_attfinished = CF_GetSetting("cwaf", "chweap_wait_atk", "on"); + // enable flag model following the player who has it + flag_follow = CF_GetSetting("flagfollow", "flag_follow", "on"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/tfortmap.qc b/tfortmap.qc index 46054e75..e42292a4 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -2035,11 +2035,13 @@ void () item_tfgoal_touch = { if (trace_fraction < 1) return; - flw = spawn(); - flw.real_owner = other; - flw.owner = self; - flw.think = CF_FlagFollowPlayer; - flw.nextthink = time + 0.1; + if (flag_follow) { + flw = spawn(); + flw.real_owner = other; + flw.owner = self; + flw.think = CF_FlagFollowPlayer; + flw.nextthink = time + 0.1; + } if (CTF_Map == 1) { if (self.goal_no == 1) { From 5a3279513225c93fbb30fd4c19f09de97c5a7a0e Mon Sep 17 00:00:00 2001 From: fdittz Date: Fri, 3 May 2019 15:49:53 -0300 Subject: [PATCH 0664/2474] forgot to declare flag_follon in qw.qc --- qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/qw.qc b/qw.qc index fca50528..b1b255e6 100644 --- a/qw.qc +++ b/qw.qc @@ -517,6 +517,7 @@ float sng_damage; float old_ng_rof; float impulse_queue; float pyro_type; +float flag_follow; float ceasefire_type; float is_paused; string pause_actor; From fbcab773aa44d91a17f50c288ee0d852f672ffa7 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 7 May 2019 21:47:27 +1200 Subject: [PATCH 0665/2474] Fixed statusbar position jumping around sometimes. Fixed returned flags displaying location. Added option to override class tips with flag info after respawn. --- README.md | 2 +- status.qc | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4e347922..b21c8715 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server v0.1.0 New features ------ -* Option for statusbar flaginfo. `setinfo sbflaginfo on ` +* Option for statusbar flaginfo. `setinfo sbflaginfo on`. Setting it to `always` will skip the tf tips on respawn and show flag info all the time. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. diff --git a/status.qc b/status.qc index 3ad9022f..11231727 100644 --- a/status.qc +++ b/status.qc @@ -669,16 +669,16 @@ void (entity pl) RefreshStatusBar = { pad = strzone(pad); // class tip - if (((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) { + if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfo != "always") { ct = CF_GetRandomClassTip(pl.playerclass); } else { pl.display_tip = 0; tfdet = find(world, classname, "info_tfdetect"); - if (!tfdet || sbflaginfo != "on") { + if (!tfdet || (sbflaginfo != "on" && sbflaginfo != "always")) { ct = strzone("\n\n\n\n\n\n"); } else { ct = ""; - i = 0; // Extra newlines + i = number_of_teams; // Extra newlines for (float t = 1; t <= number_of_teams; t++) { switch (t) { @@ -700,12 +700,12 @@ void (entity pl) RefreshStatusBar = { { if(number_of_teams < 4) { ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40),"\n"); - if((te.think == tfgoalitem_dropthink || te.think == tfgoalitem_remove) && !te.owner) { + if((te.think == tfgoalitem_dropthink || te.think == tfgoalitem_remove) && !te.owner && (te.origin != te.oldorigin)) { ct = strcat(ct, strpadr(strcat("\s Location: \s", getLocationName(te.origin)),40)); } i += 1; } else { - if((te.think == tfgoalitem_dropthink || te.think == tfgoalitem_remove) && !te.owner) { + if((te.think == tfgoalitem_dropthink || te.think == tfgoalitem_remove) && !te.owner && (te.origin != te.oldorigin)) { ct = strcat(ct, strpadr(strcat(GetItemStatus(pl, te, t),"\s: \s", getLocationName(te.origin)),40)); } else { ct = strcat(ct, strpadr(GetItemStatus(pl, te, t),40)); @@ -716,7 +716,7 @@ void (entity pl) RefreshStatusBar = { } tg = find(world, classname, "info_tfgoal"); while (tg) { - if (tg.track_goal && tg.goal_state == TFGS_DELAYED && i < 3) { + if (tg.track_goal && tg.goal_state == TFGS_DELAYED && i < 6) { bi = ""; //only do this for named goals, otherwise there's no way to distinguish them (they don't ususally have owned_by or anything) if(tg.netname) { @@ -735,7 +735,7 @@ void (entity pl) RefreshStatusBar = { } - for (float t = 0; t < (3 - i); t++) + for (float t = 0; t < (6 - i); t++) ct = strcat(ct, "\n"); //ct = strcat(ct, "\n\n\n"); From 32c6b421a87e79f1129756e73ee9b595edf1b04e Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 7 May 2019 22:18:07 +1200 Subject: [PATCH 0666/2474] debugging flag lifecycle --- qw.qc | 2 +- tfortmap.qc | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/qw.qc b/qw.qc index fca50528..fef2e981 100644 --- a/qw.qc +++ b/qw.qc @@ -602,4 +602,4 @@ string (string s, float width) strpadr = }; float captainmode; -.float captain; \ No newline at end of file +.float captain; diff --git a/tfortmap.qc b/tfortmap.qc index 46054e75..37c227db 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -480,6 +480,7 @@ void () i_t_t = { }; void () item_tfgoal = { + dprint("item_tfgoal\n"); if (CheckExistence() == FALSE) { dremove(self); return; @@ -2000,6 +2001,7 @@ void () tfgoal_timer_tick = { void () CF_FlagFollowPlayer = { if ((self.owner.goal_state == 1) && (self.real_owner.items & (IT_KEY1 | IT_KEY2))) { + //dprint("CF_FlagFollowPlayer player is itemed!\n"); makevectors(self.real_owner.angles); self.owner.origin = self.real_owner.origin - v_forward * 25 - v_right * 0 + v_up * 10; self.owner.angles = self.real_owner.angles + '0 90 16'; @@ -2012,11 +2014,13 @@ void () CF_FlagFollowPlayer = { setmodel(self.owner, self.owner.mdl); self.nextthink = time + 0.1; } else { + dprint("CF_FlagFollowPlayer dremoving\n"); dremove(self); } }; void () item_tfgoal_touch = { + //dprint("item_tfgoal_touch\n"); local entity te, flw; if (other.classname != "player") @@ -2122,6 +2126,7 @@ void () item_tfgoal_touch = { }; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { + dprint("tfgoalitem_GiveToPlayer\n"); Item.effects = 0; Item.owner = AP; @@ -2177,6 +2182,7 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { }; void () ReturnItem = { + dprint("ReturnItem\n"); local entity te; self.enemy.goal_state = 2; @@ -2243,6 +2249,7 @@ void () ReturnItem = { }; void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { + dprint("tfgoalitem_RemoveFromPlayer\n"); local entity te; local entity DelayReturn; @@ -2333,6 +2340,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { }; void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { + dprint("tfgoalitem_RemoveEffectsFromPlayer\n"); local entity te; local float lighton = 0; local float slowon = 0; @@ -2388,6 +2396,7 @@ void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { }; void () tfgoalitem_dropthink = { + dprint("tfgoalitem_dropthink\n"); local float pos; self.movetype = 6; @@ -2419,6 +2428,7 @@ void () tfgoalitem_dropthink = { setsize(self, self.goal_min, self.goal_max); self.camdist = self.camdist + 1; self.nextthink = time + 5; + dprint("tfgoalitem_dropthink setting tfgoalitem_dropthink\n"); self.think = tfgoalitem_dropthink; return; } else { @@ -2434,12 +2444,14 @@ void () tfgoalitem_dropthink = { }; void () tfgoalitem_droptouch = { + dprint("tfgoalitem_droptouch\n"); self.touch = item_tfgoal_touch; self.nextthink = time + 4.25; self.think = tfgoalitem_dropthink; }; void (entity Item, float PAlive, entity P) tfgoalitem_drop = { + dprint("tfgoalitem_drop\n"); if (Item.model == "progs/tf_flag.mdl" || Item.model == "progs/tf_stan.mdl") { Item.effects = Item.effects | EF_DIMLIGHT; @@ -2498,8 +2510,10 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { Item.touch = SUB_Null; Item.nextthink = time + 0.75; Item.bubble_count = time + Item.pausetime + 0.75 + 4.25; //used by the return timer + dprint("tfgoalitem_drop setting tfgoalitem_droptouch\n"); Item.think = tfgoalitem_droptouch; } else { + dprint("tfgoalitem_drop setting tfgoalitem_dropthink\n"); Item.touch = item_tfgoal_touch; Item.nextthink = time + 5; Item.think = tfgoalitem_dropthink; @@ -2509,6 +2523,7 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { }; void () tfgoalitem_remove = { + dprint("tfgoalitem_remove\n"); local entity te; if (self.goal_state == 1) { From c76fe935bdad0a9ff986abce701d503c0d024220 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 7 May 2019 22:49:34 +1200 Subject: [PATCH 0667/2474] Works for both cases --- tfortmap.qc | 52 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 1fc30ddb..2a932e5d 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -480,7 +480,7 @@ void () i_t_t = { }; void () item_tfgoal = { - dprint("item_tfgoal\n"); + bprint(PRINT_HIGH, "item_tfgoal\n"); if (CheckExistence() == FALSE) { dremove(self); return; @@ -2015,11 +2015,15 @@ void () CF_FlagFollowPlayer = { setmodel(self.owner, self.owner.mdl); self.nextthink = time + 0.1; } else { - dprint("CF_FlagFollowPlayer dremoving\n"); + bprint(PRINT_HIGH, "CF_FlagFollowPlayer dremoving\n"); dremove(self); } }; +void () idle_think = { + self.nextthink = time + 0.1; +} + void () item_tfgoal_touch = { //dprint("item_tfgoal_touch\n"); local entity te, flw; @@ -2040,14 +2044,6 @@ void () item_tfgoal_touch = { if (trace_fraction < 1) return; - if (flag_follow) { - flw = spawn(); - flw.real_owner = other; - flw.owner = self; - flw.think = CF_FlagFollowPlayer; - flw.nextthink = time + 0.1; - } - if (CTF_Map == 1) { if (self.goal_no == 1) { if (self.origin != self.oldorigin) { @@ -2124,12 +2120,26 @@ void () item_tfgoal_touch = { if (te) { AttemptToActivate(te, other, self); } + } else { + //Make sure we don't try to follow someone who fails the criteria + return; } } + + if (flag_follow) { + flw = spawn(); + flw.real_owner = other; + flw.owner = self; + flw.think = CF_FlagFollowPlayer; + //flw.solid = SOLID_NOT; + //self.solid = SOLID_NOT; + self.think = idle_think; + flw.nextthink = time + 0.1; + } }; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { - dprint("tfgoalitem_GiveToPlayer\n"); + bprint(PRINT_HIGH, "tfgoalitem_GiveToPlayer\n"); Item.effects = 0; Item.owner = AP; @@ -2185,7 +2195,7 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { }; void () ReturnItem = { - dprint("ReturnItem\n"); + bprint(PRINT_HIGH, "ReturnItem\n"); local entity te; self.enemy.goal_state = 2; @@ -2252,7 +2262,7 @@ void () ReturnItem = { }; void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { - dprint("tfgoalitem_RemoveFromPlayer\n"); + bprint(PRINT_HIGH, "tfgoalitem_RemoveFromPlayer\n"); local entity te; local entity DelayReturn; @@ -2343,7 +2353,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { }; void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { - dprint("tfgoalitem_RemoveEffectsFromPlayer\n"); + bprint(PRINT_HIGH, "tfgoalitem_RemoveEffectsFromPlayer\n"); local entity te; local float lighton = 0; local float slowon = 0; @@ -2399,7 +2409,7 @@ void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { }; void () tfgoalitem_dropthink = { - dprint("tfgoalitem_dropthink\n"); + bprint(PRINT_HIGH, "tfgoalitem_dropthink\n"); local float pos; self.movetype = 6; @@ -2431,7 +2441,7 @@ void () tfgoalitem_dropthink = { setsize(self, self.goal_min, self.goal_max); self.camdist = self.camdist + 1; self.nextthink = time + 5; - dprint("tfgoalitem_dropthink setting tfgoalitem_dropthink\n"); + bprint(PRINT_HIGH, "tfgoalitem_dropthink setting tfgoalitem_dropthink\n"); self.think = tfgoalitem_dropthink; return; } else { @@ -2447,14 +2457,14 @@ void () tfgoalitem_dropthink = { }; void () tfgoalitem_droptouch = { - dprint("tfgoalitem_droptouch\n"); + bprint(PRINT_HIGH, "tfgoalitem_droptouch\n"); self.touch = item_tfgoal_touch; self.nextthink = time + 4.25; self.think = tfgoalitem_dropthink; }; void (entity Item, float PAlive, entity P) tfgoalitem_drop = { - dprint("tfgoalitem_drop\n"); + bprint(PRINT_HIGH, "tfgoalitem_drop\n"); if (Item.model == "progs/tf_flag.mdl" || Item.model == "progs/tf_stan.mdl") { Item.effects = Item.effects | EF_DIMLIGHT; @@ -2513,10 +2523,10 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { Item.touch = SUB_Null; Item.nextthink = time + 0.75; Item.bubble_count = time + Item.pausetime + 0.75 + 4.25; //used by the return timer - dprint("tfgoalitem_drop setting tfgoalitem_droptouch\n"); + bprint(PRINT_HIGH, "tfgoalitem_drop setting tfgoalitem_droptouch\n"); Item.think = tfgoalitem_droptouch; } else { - dprint("tfgoalitem_drop setting tfgoalitem_dropthink\n"); + bprint(PRINT_HIGH, "tfgoalitem_drop setting tfgoalitem_dropthink\n"); Item.touch = item_tfgoal_touch; Item.nextthink = time + 5; Item.think = tfgoalitem_dropthink; @@ -2526,7 +2536,7 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { }; void () tfgoalitem_remove = { - dprint("tfgoalitem_remove\n"); + bprint(PRINT_HIGH, "tfgoalitem_remove\n"); local entity te; if (self.goal_state == 1) { From 7db590762651de9e05f27bc1f723b959a04e6ed2 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 7 May 2019 22:52:11 +1200 Subject: [PATCH 0668/2474] Removing debugging messages --- tfortmap.qc | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tfortmap.qc b/tfortmap.qc index 2a932e5d..1c0849e4 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -480,7 +480,6 @@ void () i_t_t = { }; void () item_tfgoal = { - bprint(PRINT_HIGH, "item_tfgoal\n"); if (CheckExistence() == FALSE) { dremove(self); return; @@ -2002,7 +2001,6 @@ void () tfgoal_timer_tick = { void () CF_FlagFollowPlayer = { if ((self.owner.goal_state == 1) && (self.real_owner.items & (IT_KEY1 | IT_KEY2))) { - //dprint("CF_FlagFollowPlayer player is itemed!\n"); makevectors(self.real_owner.angles); self.owner.origin = self.real_owner.origin - v_forward * 25 - v_right * 0 + v_up * 10; self.owner.angles = self.real_owner.angles + '0 90 16'; @@ -2015,7 +2013,6 @@ void () CF_FlagFollowPlayer = { setmodel(self.owner, self.owner.mdl); self.nextthink = time + 0.1; } else { - bprint(PRINT_HIGH, "CF_FlagFollowPlayer dremoving\n"); dremove(self); } }; @@ -2025,7 +2022,6 @@ void () idle_think = { } void () item_tfgoal_touch = { - //dprint("item_tfgoal_touch\n"); local entity te, flw; if (other.classname != "player") @@ -2139,7 +2135,6 @@ void () item_tfgoal_touch = { }; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { - bprint(PRINT_HIGH, "tfgoalitem_GiveToPlayer\n"); Item.effects = 0; Item.owner = AP; @@ -2195,7 +2190,6 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { }; void () ReturnItem = { - bprint(PRINT_HIGH, "ReturnItem\n"); local entity te; self.enemy.goal_state = 2; @@ -2262,7 +2256,6 @@ void () ReturnItem = { }; void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { - bprint(PRINT_HIGH, "tfgoalitem_RemoveFromPlayer\n"); local entity te; local entity DelayReturn; @@ -2353,7 +2346,6 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { }; void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { - bprint(PRINT_HIGH, "tfgoalitem_RemoveEffectsFromPlayer\n"); local entity te; local float lighton = 0; local float slowon = 0; @@ -2409,7 +2401,6 @@ void (entity Item, entity AP) tfgoalitem_RemoveEffectsFromPlayer = { }; void () tfgoalitem_dropthink = { - bprint(PRINT_HIGH, "tfgoalitem_dropthink\n"); local float pos; self.movetype = 6; @@ -2441,7 +2432,6 @@ void () tfgoalitem_dropthink = { setsize(self, self.goal_min, self.goal_max); self.camdist = self.camdist + 1; self.nextthink = time + 5; - bprint(PRINT_HIGH, "tfgoalitem_dropthink setting tfgoalitem_dropthink\n"); self.think = tfgoalitem_dropthink; return; } else { @@ -2457,14 +2447,12 @@ void () tfgoalitem_dropthink = { }; void () tfgoalitem_droptouch = { - bprint(PRINT_HIGH, "tfgoalitem_droptouch\n"); self.touch = item_tfgoal_touch; self.nextthink = time + 4.25; self.think = tfgoalitem_dropthink; }; void (entity Item, float PAlive, entity P) tfgoalitem_drop = { - bprint(PRINT_HIGH, "tfgoalitem_drop\n"); if (Item.model == "progs/tf_flag.mdl" || Item.model == "progs/tf_stan.mdl") { Item.effects = Item.effects | EF_DIMLIGHT; @@ -2523,10 +2511,8 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { Item.touch = SUB_Null; Item.nextthink = time + 0.75; Item.bubble_count = time + Item.pausetime + 0.75 + 4.25; //used by the return timer - bprint(PRINT_HIGH, "tfgoalitem_drop setting tfgoalitem_droptouch\n"); Item.think = tfgoalitem_droptouch; } else { - bprint(PRINT_HIGH, "tfgoalitem_drop setting tfgoalitem_dropthink\n"); Item.touch = item_tfgoal_touch; Item.nextthink = time + 5; Item.think = tfgoalitem_dropthink; @@ -2536,7 +2522,6 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { }; void () tfgoalitem_remove = { - bprint(PRINT_HIGH, "tfgoalitem_remove\n"); local entity te; if (self.goal_state == 1) { From 36c4753df3f87e6219bcc13574e3a9bc7426ca66 Mon Sep 17 00:00:00 2001 From: gmtandi Date: Wed, 8 May 2019 22:26:47 +0000 Subject: [PATCH 0669/2474] Fix: Anti Anti-Fall Damage --- client.qc | 61 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/client.qc b/client.qc index 2a91064d..96647ea9 100644 --- a/client.qc +++ b/client.qc @@ -1958,8 +1958,6 @@ void () CheckPowerups = { }; void () PlayerPostThink = { - local float fdmg; - if (self.view_ofs == '0 0 0') { return; } @@ -1968,32 +1966,6 @@ void () PlayerPostThink = { self.impulse = 0; return; } - - if (((self.jump_flag < -300) && (self.flags & 512)) && - (self.health > 0)) { - if (self.watertype == -3) { - sound(self, 4, "player/h2ojump.wav", 1, ATTN_NORM); - } else { - if (self.jump_flag < -650) { - fdmg = 5; - fdmg = (fdmg * (self.jump_flag / 300)) * -1; - if (self.playerclass == 1) { - fdmg = fdmg / 2; - } else { - if (self.playerclass == 6) { - fdmg = fdmg * 1.5; - } - } - fdmg = rint(fdmg); - TF_T_Damage(self, world, world, fdmg, 1, 0); - sound(self, 2, "player/land2.wav", 1, ATTN_NORM); - self.deathtype = "falling"; - } else { - sound(self, 2, "player/land.wav", 1, ATTN_NORM); - } - } - } - self.jump_flag = self.velocity_z; CheckPowerups(); W_WeaponFrame(); @@ -2747,3 +2719,36 @@ float () GetLastWeaponImpulse = { else return 4; } + +void() SV_RunClientCommand = { + + local float fdmg; + + runstandardplayerphysics(self); + + if (((self.jump_flag < -300) && (self.flags & 512)) && + (self.health > 0)) { + if (self.watertype == -3) { + sound(self, 4, "player/h2ojump.wav", 1, ATTN_NORM); + } else { + if (self.jump_flag < -650) { + fdmg = 5; + fdmg = (fdmg * (self.jump_flag / 300)) * -1; + if (self.playerclass == 1) { + fdmg = fdmg / 2; + } else { + if (self.playerclass == 6) { + fdmg = fdmg * 1.5; + } + } + fdmg = rint(fdmg); + TF_T_Damage(self, world, world, fdmg, 1, 0); + sound(self, 2, "player/land2.wav", 1, ATTN_NORM); + self.deathtype = "falling"; + } else { + sound(self, 2, "player/land.wav", 1, ATTN_NORM); + } + } + } + self.jump_flag = self.velocity_z; +} From 444a262626107078d0ea7b494dd2197ee379d413 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 9 May 2019 19:13:12 +1200 Subject: [PATCH 0670/2474] change the sbflaginfo to use 0/1/2 values --- README.md | 2 +- status.qc | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b21c8715..404a385b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server v0.1.0 New features ------ -* Option for statusbar flaginfo. `setinfo sbflaginfo on`. Setting it to `always` will skip the tf tips on respawn and show flag info all the time. +* Option for statusbar flaginfo. `setinfo sbflaginfo 1` (default). Setting it to `2` will skip the tf tips on respawn and show flag info all the time. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. diff --git a/status.qc b/status.qc index 11231727..931059d3 100644 --- a/status.qc +++ b/status.qc @@ -641,7 +641,15 @@ void (entity pl) RefreshStatusBar = { local string bi; //button info local string sbflaginfo; sbflaginfo = infokey(pl, "sbflaginfo"); + local float sbflaginfostate = 1; //By default, show after tips; 0/off = off; 2 = always /* local float win, sec; */ + + if(sbflaginfo == "0" || sbflaginfo == "off") + sbflaginfostate = 0; + else if(sbflaginfo == "1" || sbflaginfo == "on") + sbflaginfostate = 1; + else if(sbflaginfo == "2") + sbflaginfostate = 2; pad = ""; @@ -669,12 +677,12 @@ void (entity pl) RefreshStatusBar = { pad = strzone(pad); // class tip - if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfo != "always") { + if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2) { ct = CF_GetRandomClassTip(pl.playerclass); } else { pl.display_tip = 0; tfdet = find(world, classname, "info_tfdetect"); - if (!tfdet || (sbflaginfo != "on" && sbflaginfo != "always")) { + if (!tfdet || !sbflaginfostate) { ct = strzone("\n\n\n\n\n\n"); } else { ct = ""; From d8c2947c43ecfe6b7ef221f1249e97d8f6e11d2a Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 10 May 2019 22:13:51 +1000 Subject: [PATCH 0671/2474] use classic fortress helper function --- status.qc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/status.qc b/status.qc index 931059d3..10b8fe1e 100644 --- a/status.qc +++ b/status.qc @@ -23,6 +23,7 @@ entity(float ino) Finditem; void () tfgoalitem_droptouch; void () tfgoalitem_dropthink; void () tfgoalitem_remove; +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; string (float class) CF_GetRandomClassTip { local string tiptype = ""; @@ -639,17 +640,9 @@ void (entity pl) RefreshStatusBar = { local entity tfdet; //info_tfdetect entity local entity te, tg; local string bi; //button info - local string sbflaginfo; - sbflaginfo = infokey(pl, "sbflaginfo"); - local float sbflaginfostate = 1; //By default, show after tips; 0/off = off; 2 = always + //By default, show after tips; 0/off = off; 2 = always + local float sbflaginfostate = CF_GetSetting("sbflaginfo", "sbflaginfo", "on"); /* local float win, sec; */ - - if(sbflaginfo == "0" || sbflaginfo == "off") - sbflaginfostate = 0; - else if(sbflaginfo == "1" || sbflaginfo == "on") - sbflaginfostate = 1; - else if(sbflaginfo == "2") - sbflaginfostate = 2; pad = ""; From 8f2b1bb9c0a7872bead13b9842d37af6819afd3f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 11 May 2019 20:37:29 +1200 Subject: [PATCH 0672/2474] Updated flagstatus to use new getuserinfo command --- client.qc | 11 ++++++++--- status.qc | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client.qc b/client.qc index 96647ea9..41f26593 100644 --- a/client.qc +++ b/client.qc @@ -142,12 +142,13 @@ void () autokick_think = { dremove(self); }; -float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { +//if ent is world, return serverinfo, if ent is a player, return that client's setinfo key +float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting = { local string st; - st = infokey(world, ps_short); + st = infokey(ent, ps_short); if (st == string_null) { - st = infokey(world, ps_setting); + st = infokey(ent, ps_setting); if (st == string_null) { st = ps_default; } @@ -164,6 +165,10 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { } }; +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { + return FO_GetUserSetting(world, ps_short, ps_setting, ps_default); +}; + void () DecodeLevelParms = { local float fl; local string st; diff --git a/status.qc b/status.qc index 10b8fe1e..b2cd87d6 100644 --- a/status.qc +++ b/status.qc @@ -23,7 +23,7 @@ entity(float ino) Finditem; void () tfgoalitem_droptouch; void () tfgoalitem_dropthink; void () tfgoalitem_remove; -float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; string (float class) CF_GetRandomClassTip { local string tiptype = ""; @@ -641,7 +641,7 @@ void (entity pl) RefreshStatusBar = { local entity te, tg; local string bi; //button info //By default, show after tips; 0/off = off; 2 = always - local float sbflaginfostate = CF_GetSetting("sbflaginfo", "sbflaginfo", "on"); + local float sbflaginfostate = FO_GetUserSetting(pl, "sbflaginfo", "sbflaginfo", "on"); /* local float win, sec; */ pad = ""; From 6a819c0532f940ea3491ab307f8f5915bcb3f155 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 12 May 2019 13:10:10 +1000 Subject: [PATCH 0673/2474] back out fix for avoiding fall damage as it breaks pm_airstep --- client.qc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/client.qc b/client.qc index 96647ea9..229264d8 100644 --- a/client.qc +++ b/client.qc @@ -1966,6 +1966,34 @@ void () PlayerPostThink = { self.impulse = 0; return; } + + local float fdmg; + + if (((self.jump_flag < -300) && (self.flags & 512)) && + (self.health > 0)) { + if (self.watertype == -3) { + sound(self, 4, "player/h2ojump.wav", 1, ATTN_NORM); + } else { + if (self.jump_flag < -650) { + fdmg = 5; + fdmg = (fdmg * (self.jump_flag / 300)) * -1; + if (self.playerclass == 1) { + fdmg = fdmg / 2; + } else { + if (self.playerclass == 6) { + fdmg = fdmg * 1.5; + } + } + fdmg = rint(fdmg); + TF_T_Damage(self, world, world, fdmg, 1, 0); + sound(self, 2, "player/land2.wav", 1, ATTN_NORM); + self.deathtype = "falling"; + } else { + sound(self, 2, "player/land.wav", 1, ATTN_NORM); + } + } + } + self.jump_flag = self.velocity_z; CheckPowerups(); W_WeaponFrame(); @@ -2720,6 +2748,8 @@ float () GetLastWeaponImpulse = { return 4; } +// this is to fix hack used to avoid fall damage, it currently breaks pm_airstep +/* void() SV_RunClientCommand = { local float fdmg; @@ -2752,3 +2782,4 @@ void() SV_RunClientCommand = { } self.jump_flag = self.velocity_z; } +*/ From d2baeb8182864aa6c51d3d03a3d5ec0c6057e336 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 12 May 2019 20:19:22 +1000 Subject: [PATCH 0674/2474] jam func_glass in despite warnings --- misc.qc | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/misc.qc b/misc.qc index 1d370301..e6a2d57c 100644 --- a/misc.qc +++ b/misc.qc @@ -609,3 +609,198 @@ void () misc_noisemaker = { self.nextthink = time + 0.1 + random(); self.think = noise_think; }; + +void() blocker_use = +{ + if (!(self.state)) + { + self.state = 1; + setorigin(self, self.origin - '8000 8000 8000'); + sound(self, 2, self.noise1, 1, 1); + } + else + { + self.state = 0; + setorigin(self, self.origin + '8000 8000 8000'); + sound(self, 2, self.noise, 1, 1); + } +}; + +void(entity attacker, float damage) glass_pain = +{ + if (self.spawnflags & 8) + { + self.health = self.max_health; + } +}; + +void() glass_die = +{ + local entity new; + local vector tmpvec; + while (self.color > 0) + { + new = spawn(); + new.origin = self.origin; + if (random() < 0.5) + { + setmodel(new, "progs/glass2.mdl"); + } + else + { + setmodel(new, "progs/glass1.mdl"); + } + setsize(new, '0 0 0', '0 0 0'); + if (self.height != 100) + { + new.velocity_x = 70 * crandom(); + new.velocity_y = 70 * crandom(); + new.velocity_z = 140 + 70 * random(); + } + else + { + new.velocity_x = 400 * crandom(); + new.velocity_y = 400 * crandom(); + new.velocity_z = 140 + 70 * random(); + } + new.movetype = 10; + new.solid = 2; + new.avelocity_x = random() * 600; + new.avelocity_y = random() * 600; + new.avelocity_z = random() * 600; + new.nextthink = time + 2 + random() * 3; + new.think = SUB_Remove; + self.absmin = self.origin + self.mins; + self.absmax = self.origin + self.maxs; + tmpvec_x = self.absmin_x + random() * (self.absmax_x - self.absmin_x); + tmpvec_y = self.absmin_y + random() * (self.absmax_y - self.absmin_y); + tmpvec_z = self.absmin_z + random() * (self.absmax_z - self.absmin_z); + setorigin(new, tmpvec); + self.color = self.color - 1; + } + if (self.noise2) + { + if (pointcontents(self.origin) == -3) + { + sound(self, 2, "effects/rcksplsh.wav", 1, 1); + } + else + { + sound(self, 2, self.noise2, 1, 1); + } + } + remove(self); +}; + +void() func_glass = +{ + local vector tmpvec; + self.movetype = 7; + self.solid = 4; + self.mdl = self.model; + setmodel(self, self.model); + setsize(self, self.mins, self.maxs); + setorigin(self, self.origin); + self.model = string_null; + precache_sound("misc/null.wav"); + if (self.health > 0) + { + if (!(self.color)) + { + tmpvec = self.maxs - self.mins; + tmpvec = tmpvec * 0.031; + if (tmpvec_x < 1) + { + tmpvec_x = 1; + } + if (tmpvec_y < 1) + { + tmpvec_y = 1; + } + if (tmpvec_z < 1) + { + tmpvec_z = 1; + } + self.color = tmpvec_x * tmpvec_y * tmpvec_z; + } + else + { + if (self.color == -1) + { + self.color = 0; + } + } + if (self.color > 16) + { + self.color = 16; + } + self.takedamage = 1; + self.max_health = self.health; + self.th_die = glass_die; + self.th_pain = glass_pain; + precache_model("progs/glass1.mdl"); + precache_model("progs/glass2.mdl"); + } + if (self.target) + { + if (!(self.speed)) + { + self.speed = 100; + } + if (!(self.dmg)) + { + self.dmg = 2; + } + if (self.sounds == 1) + { + if (!(self.noise)) + { + self.noise = "plats/train2.wav"; + } + if (!(self.noise1)) + { + self.noise1 = "plats/train1.wav"; + } + precache_sound(self.noise); + precache_sound(self.noise1); + } + self.cnt = 1; + self.blocked = train_blocked; + self.use = train_use; + self.classname = "train"; + self.think = func_train_find; + self.nextthink = self.ltime + 0.6; + } + else + { + self.use = blocker_use; + if (self.spawnflags & 4) + { + self.state = 0; + setorigin(self, self.origin + '8000 8000 8000'); + } + else + { + self.state = 1; + if (self.noise1) + { + sound(self, 2, self.noise1, 1, 1); + } + } + } + if (!(self.noise)) + { + self.noise = "misc/null.wav"; + } + if (!(self.noise1)) + { + self.noise1 = "misc/null.wav"; + } + if (!(self.noise2)) + { + self.noise2 = "effects/shatter.wav"; + } + precache_sound(self.noise); + precache_sound(self.noise1); + precache_sound(self.noise2); +}; From 5678d15bf65058e86824a8bfcdbbcd6d0a571e61 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 12 May 2019 20:23:53 +1000 Subject: [PATCH 0675/2474] fix precache --- .../ipch/584dfeeb401f2c0e/mmap_address.bin | Bin 0 -> 8 bytes .../ipch/897cd993fbad31b3/mmap_address.bin | Bin 0 -> 8 bytes .../ipch/c9e38738931be063/mmap_address.bin | Bin 0 -> 8 bytes .../ipch/df4dc764295579bf/mmap_address.bin | Bin 0 -> 8 bytes .vscode/ipch/df4dc764295579bf/qw.ipch | Bin 0 -> 1761280 bytes .../ipch/e1f2daf2731f2897/mmap_address.bin | Bin 0 -> 8 bytes .../ipch/f2dd25b4d0adb0f2/mmap_address.bin | Bin 0 -> 8 bytes .../ipch/f83e8003c6e46fce/mmap_address.bin | Bin 0 -> 8 bytes misc.qc | 1 + 9 files changed, 1 insertion(+) create mode 100644 .vscode/ipch/584dfeeb401f2c0e/mmap_address.bin create mode 100644 .vscode/ipch/897cd993fbad31b3/mmap_address.bin create mode 100644 .vscode/ipch/c9e38738931be063/mmap_address.bin create mode 100644 .vscode/ipch/df4dc764295579bf/mmap_address.bin create mode 100644 .vscode/ipch/df4dc764295579bf/qw.ipch create mode 100644 .vscode/ipch/e1f2daf2731f2897/mmap_address.bin create mode 100644 .vscode/ipch/f2dd25b4d0adb0f2/mmap_address.bin create mode 100644 .vscode/ipch/f83e8003c6e46fce/mmap_address.bin diff --git a/.vscode/ipch/584dfeeb401f2c0e/mmap_address.bin b/.vscode/ipch/584dfeeb401f2c0e/mmap_address.bin new file mode 100644 index 0000000000000000000000000000000000000000..b624b49c3a0bfab82285b464ab68e06419e9870e GIT binary patch literal 8 PcmZQzU|6%Mo`C@X2dM$x literal 0 HcmV?d00001 diff --git a/.vscode/ipch/897cd993fbad31b3/mmap_address.bin b/.vscode/ipch/897cd993fbad31b3/mmap_address.bin new file mode 100644 index 0000000000000000000000000000000000000000..8527a932d0a470d882fd399691391d4292aa2410 GIT binary patch literal 8 PcmZQzV8}76XJ7yT1bG1> literal 0 HcmV?d00001 diff --git a/.vscode/ipch/c9e38738931be063/mmap_address.bin b/.vscode/ipch/c9e38738931be063/mmap_address.bin new file mode 100644 index 0000000000000000000000000000000000000000..025671824345318c297ead88330829f871c83248 GIT binary patch literal 8 PcmZQzV7T(9j)4IH36=s+ literal 0 HcmV?d00001 diff --git a/.vscode/ipch/df4dc764295579bf/mmap_address.bin b/.vscode/ipch/df4dc764295579bf/mmap_address.bin new file mode 100644 index 0000000000000000000000000000000000000000..8d2c064c2155bf4cfa5ce11a6f5456a3057cd46a GIT binary patch literal 8 PcmZQzVA!Et&%gix1*rjB literal 0 HcmV?d00001 diff --git a/.vscode/ipch/df4dc764295579bf/qw.ipch b/.vscode/ipch/df4dc764295579bf/qw.ipch new file mode 100644 index 0000000000000000000000000000000000000000..e36d5fb55f665152e20ea5edee56f365a84c0c80 GIT binary patch literal 1761280 zcmeEP37lI+{okb=;WXTf2ZVwU#J1Txivrp1ZkvVeHgvZTP)JI#v#OrVH zz#tw`M5BL?sDCvcK)BZfjo=XlHKJfp!JsHnQQ`so-(=?ZUS=}$-n`^xcU#}`p_7^U zo!|NWelzdoB^euC>l#@#a{B46D`$4jZJXWU>R;(`xz}xaoy*nh>hW|Bxw?nW=ovi2 z(|y`O9i1H=9cL>4qrX*=*~@2EZP~PA$F@}~ubkUFyJcq8Ol;T84kTr6)#Y<5@ZieL z(de$(+3j;HJS%&8S9(@mx@||tiC6|DWCTf=o7t%tvf_%XqC00Vn_E@W_!5P<^Dx2@ z8XH|38d<+CFg`K1fs85B%BvdLaX_|lYAiH5HZn047#o=ity#YzG&MYNW;eyLTIqG} zLx#N6)QixRn+&bmJ-2h!_HCE0x@`02RWa{CXrOP!_H8?M$5vdnWB01TRoixK-oAUw zOrwA!DFL&aH*FWwuB2!Um95yiEjF{IQRVUVVu)c4HaD^z%3-6ZYUmzJhC-pK>Cur; zh{2Oy0ZeoL*oLX`^^*#%5=`CQJrj*mkD#S)oL&>^9^eb-koNXSk^0w9O^=Q8Nj10D zPHseQ4K^BixN2mLX5ILt5>lZvdmAZ_p(z8y(98{-ApL4-XNif-Gi;L0&mBMB%t8IVM`%@~mc#>e<1 z$Evoh8J`@V9t*7-p7w{@<;r`8$zqc1$64pqmZm! zJ2o{P8lD(mJGpMGwlF+15a#GF6k5MwbZkRtVtjg9@p5c(bbJ^U%k_Hchc@^@U1EV^yIu1*Q_>I*3=O{CJ%&P$Za_aAM11My+&+fR)wOcurT()Coi)-7CU4*L6SPh@R^oG&#HESqd zE{hh<7u3RnDC5$ivjqAJg)Tr@N=Wrh(xORWSvMR6u9`PoEhk|mik6KW7JY3RFLFlN ze2I;7k=dQQ48YT(81X8*v6O#ZsGwk;_Ie1LK+s3V#Vt zQ=LOghR1wnJH9z%v;UWevC)Un*tS^9Gn>EsFszo328u4jP%VY^~X^xuVVqE0H zN=JIlMA@{|_Q%?qa=g1$RnhTMuQuoyK zhSQW2Mcq&+R2wAuQdi31ghEsAQ0_PIq@Z!3DD9BDHW&;IuO1JP>#j4ql?&8H)!Lpg zRom&&W~`j+V}n~8Y3mM_e&rynk#6M>YlfgmuczIr{51-PdnTb!?L^KpASU$3xxm(f zO*_yF**W}Lu;9ZE%iCzH7A%Bg935!gE0iOU2BK?)s~c)#-CEaas|N;qw{`2rMr}?q zL=ITWwK-ZL4&livAsqBrS3nB~1+7}tE*F3kIH29gVLd|Ci(}}5@loXxk$Z@(BSj$u zl)UQ)?HUl_1eCpyD|L`+LTdp4qywDG3oRWjSDFIpLrs3R+Oj4W1h979ygp z^Mh}dc7ch=>l^`dbW0)PsdEK*pydUdwuA~V9ELS48gWza-lJ2uH-tmEkxUEvI=K)U z-bQ-Oah1LfER@lWJlg#ng-4+l*+K<}dT0k@c=eb*DAz76>ed44i-AQ7hY5=mYOsix zIoi2P#iwqi!6H~`PS8?SMPb!y5Qmt9n8E_~@#?n5fr5|?B>mMx9O6iNF@d@Ms;4eA zkjsq=p`9a;aGluDj$)eKbxRF^a?(yKP>54qY_x@Ns9(nMqHX~}545~grArC5ggkOO z1M$V4USezF(E?(6SaD9mY9~=3uUiy}c%%ytx#|Laya;PlShr41DXdF5IfZo#)|5hn z9MT}E#Uj0AyeNkwH%ScwA}lh*612P^;Yg@M6*!@llu!o~a6-$IK%L{z)hIY1fiYFp z5U*YY(Z{%YO<*3hJTtYDvUX%7G(I*G>hB-oy+5KYV;y1bjqZuDAdf-IyfqWkp|SIa zCqnDSrv2;Ddz_qiowSn0l21>Cy1fGf-JxDSr>01GKb=v;xz^A;Mv68JkB+13We%aX z3W#vsuu?xpm3zSoZC_())(#Me7}E_jl4<3uCQ~_@js*jXNcW2Fo_+}1x)ZIo0Rert zM`h_9G3LW z91RTgdi#64-u@wPclV&DuiM+(=k4q79vJHBpEX=g-{bA+ z>G2Nsdj^LFyo0?1{k?*M*$2-)oNb@Qy z<7xbxSuw~l@hnQ@=$P^*{JIdn-tSgC@9r7$_6_v)_Vjrbp9d8kijhP8-d;u5Q1?K0 z@63w6evVjeS4K$sho_WBM{1(E@4eDNhN#CUYj6FcH+(sFkhIhW>B@WSW7DBY{4QVP zLTE8Ix?0IXrfqTpB?n}4NoYuW^aAAJz5RnqqIkR$oGQSG#+Se#x@TpN64HZ8{&|%~dF-Xv z+v^$f^z`-&b`SO{!RhJq3@ACn7d=Kl^U&DXHvH9PoHO-oC+}f!^NU zfo^a2fFiwTW<~b^&+u_dI+Z}Gg1(hQiirM!zJ9Or-f-VQe_vnspwjmaDmgo#l!0y~ zs}%ct`gj`X7?95;v_@uf3Fr-SNi$~xM}fM{@J?^q=2fF6*~E!OEjh5*`gBq%FE5|8 zOA?hujd%BoJ|z@6fu_YgF<(t7MGI%2)HXDgUR9!~;B3R%eF-|Fcn=b2HKZopm_geD zRC8+e-#et_Sl>{;l4DBlDZ!s6jH^9(85)j*H(-=MO+3@Xn=4EFa7c$DJL7x_vxDQZ?~IoG{X$*dm5nn7hpQ8uf- zzTQ5MXHY25a}Fi0}ZB4vlGT?(jK#w+|UaMs{h$1>1q!#UW!LJb{FgPEfpFU=cd z*78RFc*m1ToyL@9uTLDwBOXtzwz*>Wsnn4_=J7;p)7&HxLvZr<# ztY#1Iz^A?Kqi9gb#YaBM79_YnefWnyZIi;n5lemkaF2Zys^mHzUw3tL4}KJ?gkDv` zJ^Ha6bPDkfe_Bl^j?~_^l|S{Z;T;begw~Qs{=CN(dUk!bD`;q0Bz@B3${k_kQfVZA z#^cInSKL${DL$IaBf?>jM^v3vuE*=IoVvR?mrmN-hDwYe2AoR098xMTYO?EdNpRxR z-ex26nQRiA`KVyWeyAG~|I|nAdcdJ(6#v{u6^EMh)cuCu0TMoS7gSWFf*Qej&f7nz z9ATMs6*yOdRU?a9cg6r$`DrZpTQmxmc z+?pF49O~;)u6u@hlw+fEjnl`M4EGR1A&8v%TM+{*`v&`!GiSGQlI!&=@}eQuBrOb@or#%FTNp?jqRW-pII_n7ci+YFT7nrZC%(6HMb8CI}?2IRDvP#rVbjH}>f_v}YZMQ0Kg1EQ-Eq*wE5SInVyJ%< z)~D{=rDZVKj&_Ejl|!|^v7rGTla`8@sV;!VR&Y7A_sTKH)W+2)GSC}~wV?K_ti4Sm zG?VhGc3Gz$4tS5tPzECMI*fb0Jsgl56#&S}ox{dO)J`jkKSV(dW#xYS=x8JTDP$;w z>PgN1dYCcT%D-dEjaMGKw&!DZ3h?fJ9t*r#1R4d1tM85}&O$g~tv zjIGhvp+C^w$Ah0r3ON4b>wJZSvjEfzgOb_`DD=IfoLie`)Gq<3&_Z2ZgT@zQipV~m z$OccTb?N1rp`AepIz|hlu8{gdSt^l}TCLbHwsu_kSn`HYV8hs&+WX{GH*_~gX+B>FHM1YBKl(Qd|0u2SouW$ zs8WBF3NaR(o*d?XN)6NyOWaSh zYmY_{+4v*1ifqoCp<3xA#LClK_~X3_y|=N{YF`GCc7&*mSZ#&C^f^XawqU$?Gy@1@ZZjbuvsf*G#e+UhGLf-fi0Xx0R$(8t+18?*Lc z4^mb8QVA}dwt?65i3v5OQ)6pGYo>TgX_~cM8cm_{^*5o~7vbt@@$_l=q$5XL z>D@cF#du;gvk`@nHDeQN_$1VUwf6Ac>hV$Z)ATQ9so6zh1$-toU^oEDL#`Gu!xqSDECeVh`c@_~;|0Pqr?}vgfp4t}O z99gwxYu}d5%FT7$@KSO`pcO9zD$2VroTVaKY-~wnEruG{~)G+Fw;MT=^x7U4`cc-VERs` ze>l@Wg6SX0^p9ftM>G9nnEtU$zkYSv^BM}KwDj0dFsQlz#cigDgCP71-0ruZ7B134 zZNddXVBZDNVk_C(5s--^8JeYr6SA3SH*ajI*}ga1vp3?ur~9<0+rKyGi|w0@K)Vsx zlk$I0vbEjoX3Mt`uo18kuo18ku=mBiD+ZP+?!f^W5>HSINDP73V4-pKJtd1Z)Is1Z)Hr9|836x9I=H zw{B@#VETdirRj!km5qRnfJp@GYci97+2mXVWa3DMhAVs#2a(M@yLn@aXy$*N>b(*F zJ>920-Twc&B(fd05wH+}Jt_b9BwH<9B3qP=fQ^8SfQ^8S02cv!U*y8F#}2}0C-&B7 zN?KhQJKkGG(B|Kh5U}HYPg*V8RvQ5u0UH4u0UH4u0UH4u0T~4L)@xn+>@KtVHjRyd zjew1Sjew1SjeuDMM4z3oKO-PU(#A%NjXh%{U?X57U?X57U?X57U?X57U?X57U?Z?} z5J=qvKhn2!Y--k$U?=<_qd5uXUGPJT`h4>@;UA22JPSVrsZU?nAKT+PusOT*rQ5U3 zB9Qap9|A3&13w7btR!=M5I>bG<>Jkpbeq~nz(&AEz(!!HBCu@PvcOgFo5@xhd4TdG z#pr*dzX##xyNw8y`P8TI4TlOZOBJI^5e7Ytx zvCqOD>RNRq@eID0K)*>3zf0e$OiTH%#)nlG$(!fv{$%tZav3_H0rAj>)~p=h6SbfR zT0~d>TEw@fjqhWj!LGL)kUQxb3k5E)DBoB2Z;So0e!M5jx|6+@Z%68L%P9Nevvglp zzEyONQ|0^${z1RyMvj#8BXOu49qV7@h=VBH*m+UE^n||Mz*pYysHWrtzw;$>IELSK zXiIuPU$bpF$+t8A3p(#pALYlds`mpgsQHn;g631_O}_BliShT}q_4O5OKbF%E~3{V zG04|jTHRc{irjaf&X42r?~kw~E_@F$ar{cYz92L1e2yO%B0pd}RlxWpkEQubtMNJ| zSJ30Yw^(iQ3-r2+?C_ngPnYlG#|y{{ys@=7&Ab$^o97Msc7Q%nn_5ZZ@BAQbS9%pa zFOmb}RYE`ih&jG_MlZ;dZ3FAg;gI{HHP@7`w_v^gx0=&0>z9bGdYn0YMRJVB-KQSY zRNcw`(ONwGoAG{PWG_4K{R3S$y%*}|CCe}B2QQ}c1n8>A;k>L`e9r>pL+d%1U$Nfa2jKA|We7)X}(KuVJf1%`s{mtc-bGICy_fGxzn;(~xlYNgMzdD=CS0j8QJy>7h zGQR!UIeuIi$&Fti=P$@9nxqH5#cG|Q1F8Dy{|nBO=wJ7&d?|b%=fC@d&DG(>!k^V! zaSQT>5IRq@_B_w(H|nQO(YMctUo;=wz~8U3f^m_YX2;!sF;^e5|2CH&g@4o6HRZq4 z{D~9!b*ou_%<@(5ru`4xL-%Fn<$BE3_l!VK+{@47xXWZcHlRpZqDw=N7_?27&rIWZf*eA_0%6R?nR~^xlhOI z7rdBWN0GyhPx13dM4w)!9}g^F>^3?M3QV7+x2o^H9qV-+rEhOEjB$z+daLvs$%&k$ zZ95r`G3**&g%D; z`8Y&>h3ioGEd6z>L~-5A-%7`0{0zQaR{wuXzj|$Z>umIF{=Q*^@BDT8ah(4oe_v~m z`zCAakL!Q2-t=GEi(7*qWT4<{4o{Hh+Jx;ddvSgy-%aNS&_P>`o6DErDKy?5!TX#b zzg=zdKm7XQ&zSSa$iB)bjD|5$PN8 zM+rSkm;QsC9c4*9Am4WvwzG1*oP6LDwf-;C_=)JO97u<>t8?2Ke0G<-YOi8}RS%^yI=hwCkve*QJ| zxybd?_SV~I4##8kHaae&x6^$V*61Dj^DMonU!J9L5Ya8w@vcv{*Z$;%be@-)K8s7` zBAT9^H|m$xwZ<=!@4p($otJz*TqMW)di}hL-izbXcRkiuAuY)BzmM;q?;yOdMh?bp z@(|qS4sC9~^*RjB(XZs&QC`8Xn_&N*)>iJI>zUC0Q~2-q7jKZmKlN=nI#z$>=LYM< zGPJ3m`0L)a?pDK;dV?VEf6QM$PgX$B7#6;{xwv7(Sk_Jbj;;&gceZzbvCMEuLCzES zc`nJ`QC_XTUYVcb`tSZbZo4+p_?3bAR}BnGyqB&w2IPj*sdre5Z+w`x&-qXO`zK&n zka=G%@Og|=?!~kmpkM6Pxtm^Bu&4BLbM|^oe!k4n-&`H`#P#bh*uP-yi%iy)h&fza z^&?0=FA(_wf1O*EZ^S>pSb86z<0N>!xw=pqHAi1&p3?$cBBADR?;_9rfttU_b#seMmVI` z%h{K@R4z}0SJC$|eJA04+_#d>&-`wz*KuKUahQoV$7h5G%zIuXhYQd*+xphgxCYJc za{|S=p4Q@)72EYgdi~gWtNO*0Y22d=q}M9@Q}@&BDUw^clOMm~Tln`mL~<5-yfRA1 zLF@+XZ)}oYH|HqbUuZjJ_4%J)nCCvC+wpq4-%8^rYv*FoIbJQdzq_BO>;7Wd%j$I> zD`!8;C);;8ah!V&$8GS4r5*RdIr_d%`mY$D*j3G4FI8sfeI|GTzpjb!^gnJbUg=fX z9?u=LT?wWyvPU$YoR!0;MD!GImBS%Lo(~l1jUPn&A)>QtJk{iV$WljZb~>l&xQtH9 z)sx6st<_V{;rRYY`B*F`)kVvzkiP#c{(ThxaWuVE>#(QENp7LnkG0=*c6;kEtIzWO zb8_c8S-tLk+KWfT!;e>4`&hcJf63){ILWW)`N8J!t29}Uz<&3zep~__+d5xO+goYz z^MHl7(YW}&t-t=>!}aH@WS}8s zk}Deb-n%f@6W&7%*1?72H~u)EE_Vx!hx1mtA9$hMc}IkUXgosnRBn?yAI&p%iR4!P zWbV2-6>ZMH$_M#zSb4lTdEig{^w#)6j#2CWGCv-S_&WS_Jp}qHIsZgFbbW()Xp2N| zpD*D77` zMR>iF_v1QR9H-AQT~E<<%1B@FARHfwgXuUaF@08!_Yj(%owurAHu-+8kNJK}ksaBC zaXl;_Vy-TV6Ti=#{Vad0{n#Xq@7!<9#dWKCqhGcrE>Z@c zYmA?+{~U*`AE_g8+~kkKZT0Bp;>d9gfB!2B&QrnTzLsJ>4`P*GBRM`&NAp!{*A4V~U!yPA`*rsYCJp;n;=GsTI-(Ic)3cuqF;8A2b(dp3VGy&hraC zuAb-k z+h$+Mzg_~md6RJie4^Ij*ViZFTd48id--)IcL^VNtL*Z8n!m3X_iZl!124q(Cf3Q> z9VYe2Du29_`g+3)90&Q&%H^F||I5qqK3cg;PQLFXdf&~ykH79_?Ew0?;P;qdUeqRk zz^~s)gMAI;6(#k$3;cZr-|@~?9D z3!H-I_k2&ATZfc@zMQ1@6X&n=&r8|v_QdP_ORzs#Cv6Yl*RHnfcyl-!*-;GYW%k}x(6Z-SjNAP`x+#R@$8_=_M8})N7J|~tC ze9xIkZ*G^h`%q5ud&Kgm^3SOvJ6jzOzlFb#v?^DYKlA9~?hmqdE;L<=eE)m(CTr@g zw`#7AWju32= zkLb^{^j7twck$0Hr7!Wv&FW1V)P?+!`t>bn_IvjX-d_d#QytX=b>4-Hhp^$h%nE)CO*(yeJJLb>z($REiFCr+vd&*PQh~{ z5y3cXQ0#m;y}=<|UkZ}+te$53;S;T0ufQj8-1wiMudBjq=<|*L?+bH(A#GAm)g-;^ zF@5~9Yx#cWLyL1BfH?6#E2rQ2E*!s!<+Pt&@8-vKVLLwGMajJ9S-$^Zhx_vOoCiU^ z*UPsP=Am_7Psb~a8@2J@(tKI+c|0RNqj{$r+np-YxU+nj-!@mLV>i&}nOJ{&*MYUW z-TmsX_2bS+zxOkk-+!Dw{(+J?JsFeqMs~9E(GSbzHOmM6+!6S^mfOY8o301&c#-^G zdWVOOBakE8rf;Y3N6YfHi*Ei1x%I4)=SF-pCa<>{!=2Ayyt|I%>vaphkAM-g;N9X^ z={R%l*IXSkGCX|-AD60N+(=%t^YbrhZJmwuc6|%yk?TD;zY3%UKKFI}e1!Qp%sV;&vie%3b9{gwH>}*uz8H_NBt6T&Q2ppR z=GLuCa-B;*P9#@z(BhzW>nmD^lg#X*K@kykLKMzg#@Y+LKvhEnXtM z;k3E9VdZ#7thF;Ncs?X27-#K)zT*zL_yqdJYNLH}_&dnw{8>ALzv25?S z<39Q!YxD$e!1%jT=H6G#RcZfO`;GdM*EF~8uKzPvp9|;GdfXFqzxXKjyEKH?)w7PC z&-_h)9aulRPUF)%K0uG>j==GjdXZe-vU*ZJb2za4&@Yc*yE1>p^*&ai*EN1GjR){S zTVj4cC4aDf9L4r+&R@{Sw&e?Hd%J!im&dG}cK0)P%dJ<^L*MtSo@vebKJ}uy_ht2E-)D`#vifA{98>(d9Ttqs$~8+@cx7vGRro(TPR;5U z(O1WCy@|dM*NO6l`t=9oBo1nC-dFyIZ%174dn(RP;5;dW6O;`JA~t z&fFlEhm|Rle!v1UZK~3oe;&d2s>ZLt^19A8=Qm?k)7|-yK7PK7XuGP+`vC4!`Ee9J zoFA7WLtO{b>r;Idtyjcn^?2|IYwAbp%QP;Dt>)q;`VN{t%=~_9exv@niEt_2M&m4^ zbAHp@`Z=zl{RO#>etJB6E8P!%i@)Cjzo^YTPOp=HE5;-CC%O9r#c^y$(Bj`i_5Xvm zOJx629S^MGuY2j`Wc*XjtyjDKjcv#4pJqOv*R0;+|Ka@eyqAv$$n}os*QwNt=y(S{ zt6Den`_NX&ZB>rrVRL?G-l&grgFPlcUl4qheqK3yvHrR>=o1X&dd%f}*x>uHBEQ9U zMx6NEm^_?+e#~|A^+wOO_BvMJwmKYm0NYpDM;}l3^>X`;D!5HAyq(SMn_y1i1MR7Q z<-hXR6Z9tjWv$-SdVPJM*QlL8%N(9vXJh*L|KZ2O{8_jT1ekh|ywhZTFfhEh1J|ca zn|{v))VrAbu`mv8;VSHx<0&~DUEBHB=^zhUcT5hiz%u?ifSe`M?x$a0SUW2>>hC}P z1bx0{`IlNhejUAkwQ67W0RFnCK1<_VChwoMs&A?AM=JcfS9+Si&ziM6^%xyj!8y4+ zWc8#*`Sqasj^^aC@=Hfr<1Z_>*?#g$8aEd?&o?X2Dn3_PAE&I~Igll1L z?&tnQ=NZ_WCG*g4wsriR#1<~+wHXId%E3klC#eUhlt?$ka@wlNM7l6e1Aps?07};_tb#TzlzR- zGIO0>BKOhCH)6WfM``*B(+9cG`fsA?y|0(M4g!9&ZF)aCj?y2-bvxWi=Yv_fR?&yA zX|MlQ*$Hw2@3kgBK%Ut)u#R3&v;4&^wEgaVn%l>#H_~#<+F?Xr_;z#G2c^!|>P6z` zd&zm>S{gsccx$+@>*fA7#wqN`Gx<0pJsd*eu?-+6%k^^l0qXgu|2>`(e- zIIm)<=I}AnBRikFn$GX&H?56>)I;?8bsfp~H`hbkVPt>#;pWbHAUFEc=JGgoXlr^w zKilS?rg578GuD%NlQq{tN#;48{Qem4$^qtZXYGc*|0X(a(#-GT0bSr@_PNJEke4(#A0@{1@yl=IpD$eJ^T$DN(cr$b|M}+Xhv#+t`~bbsdOv{U zCD-ElDD2nA2lUCd;RBoVTULJQB7PjO{Jsxc>lZ8E>b}$H^Vpqo{$!4$^U7*FGrz+4 z2b}aels`z9IypNm|e?|*8B*4L`vv0QWegRI_QlEzP#PefP#gSGy%dQyL2 z)|Vw{u^+s@J^QMWSq@##vh&UMy?<&g zenD?~KWpTGJZQ6(_Q(bKW?Q$5UcdNX>AqQcEWOu7`&(T_=RHgR-`3BbgYz_dGhH7X zx6pkSm*|_V!7Vc8|H1ocx5xv#(WpW=fSFm;; z2Rkzl(&r)=Un;FLj@Lc%YWm!e`77OL?ae#d6NjuG=oikQ>llnfTV9RdKXs1c);nhI z{nX$m?j%Bm-nvV$8ogD^HKWj*7Du=25ahYvBm2z zz;B`32&qR_>n*>8Uq9S$ZSH!4wJ-V`e*N%9a2+k>>3Q$Ne7$+W`>d=!=agLD`+tq~ zR8HdSW91e;Mcc{FFLXb7qrN@Glg-t6S^M3Wo6E!KQ*<3EKc;UtYsdWC_4iwrUexzK zN87>DMYr(tfTe4-Ki_NZbxf=F>@EDIs{T3Ezg2(z7aWKE%*BD{V*R{{ewW@~b3fIm zH|uYl**7BxVSUA~(fJuZu|0K%wKw^{v|h&(`s>f~8}(DarR5vZo1HKD==CzoANvcv zzS&%J_q#!FWSU>s=b7DmcN3ISREE{i3vbRw=RKJs}Q|K)VP%i0y*M&p)a`mCJ!*Uc^}e9u7ml$W#<8lgKv@9=Zx%*9HD9hV74CYyS ztNVexHP`d*7>-ZR>-6JPWWWDs{B^B7L+{V7tK{NSq=y|Ze_6k-2Hf<07WdKg`m*xc z)sKD>pIe;Ypz+AOKrXM%+T}3#oh$F_<<>cR&cfj3V7`CatiNXI9lOlo9={ypHNP*v zZqEM>pJ!6P!Ry-<v8Uh+K&i)}~s2l}|V9+In*&H54jBAuUkrmxD4 z(spJ(Z|?f3ayPy2xV}W|RrLs76u)eaULdCB;anQqk$We9UGf|B&jUsV#BS!FV{#Xo z!`nzt_TuLD)#_oGFY^M1-^uhD1A+$gsg?TtjJS@DZkj&-B!6FQ;1dkEKh<3Qc3eW+ zF+YOWDe`4&*Gpiw{O~EQ#ihKWr9tWHqU#lFRp3MV^DMo~hx0x7NjV(--^20bIgySJ zR&J~P=nt`;isW-wj-SiLdD!In)T|$c&++lkF?zGha6PR2lTQzN%geD}Nzz7ttWOVo zY#Ut5uj?$`Qt8JYY_0AY`Qds8A4h)`<5YSWpM(7-zc({2p!W>$^%>dO^8AzZ`Mza& zZ59xJzg!(+%_uSTDE`Lw>{Bl0^LBwsd-PPv^Yhv@q}FweH7>-5(N=*rw>0A~{3rdm z06Yr^>c>U=v*yl?rLm=n2l#8$R-V?6dn10U=TpC3TK0(i^RJ`pbaJ^|{E6h59Z$al zpU3iV){keia@{Xjpm<(xt)ASeeEi+y{VpRMQa>@5_eSzyJ~FOThMD+D|pV#NPdibuZP=3 z@6&On&&nwp%(L_h-H*OjKb}~7@{;tGL+E5A9M#YMPC=b!&-xj2tb z>ems+(faqb62H>7pY^BNzV8A3>t`dmiD%nv=SdjH;H&XEWG()^O(XyIl=-aFT>dSz zU+$;rJOcfR8=AYG2Yyi-_*`po4RWi?aC~R>#jWFK#NPdIKlUZQo*y(r8!hi7?`-hV;9sGXn2{(B$BZO4f?Pt(VdKEv3xkw4CmNp};^ znzPqPaF(oB@Gs5fk@IW%>m<_etLX0oBED9~qi@#VpE}mz{n0&%+w^(*`(-9$&i~ve zXbzu>$@kkm|7tF8T3v^w&Yvc~i`}Z7U4rlLi4W`7h1>=F`>=%yo&WK_(EV2J z1^(2(a6Kq}1k3mQ)tsJ^0lo9b{J0DL%-lW!_U2zJcV5naNbVd9a+gY5EMWYj*W&sS zdl|o8yDp{cOZ7MSK6m2X`gP1|KV9!J7cW-p2YHn%X*?2lm|OqYjppib<`o#{u5Z!t z?YqmIUa)_m+rmHO-WLJ8s#nl{1$NSXptHKonAJ14Fm|zimKXRwWc6x(U104p+fTxI zSCTP$tNuAFa}PhS{5R8lDIb3y6q%8Diq3ZtooIYMZcW`P{e#Yb&=)Whgth&=?g!>*G1I_SW^=Ur!-tACMDd-EdqH~oAD{}!qZ{+f?tHOwCeyHfu{@9(h#`M5bBz;s=b?}LGS ztJ?Bm3lp!!+x6>V0*E!kAKNn;K^hSPo+WmeTF`(-g&E0e>pPk2kl_a0LN*>Z24iP6m4&4_0?j8$Np~d^}aq_(_ ztXxsQNazbko2)ngmb>4ajp^rCcCNkqp~!Ee@#5q9*ZuLk>GOYb1k+c3gzH|{k8$h! ziGCf-_0jlvKCQ2pwc9^tj-KTg^%Ew)_orl%UZl7Bh(2B-KH2fe!Fbc071-lX3SQ`g&7VAJE0_Zf|^m9`6BicmjR1Z8?wY zi1R+Wo-`{D_%cKK^*mU$R-f|-I?nTF9E@7`TWPzE=#A!!-lgTA zk-aeQP3rH%-Vqun|JR%I)42xcum7Od^0;(UYy99hw82->{=s;DgE>9E@5r5tKt8mo zQTlwEu=sm?D?@Z1f?od_{BfAKs-54eUynLE_3Kgii~MtVm%;bsg8hkO`0ESv?P>#W z#ClVY)B9fKfQ31KfM4Z9X#dM!H5b<)XQA8l6?A;MzJ=o?aHl~$F@{DZX57BvOmVcq>yAH$n z=l|8-b#K<6%)f9QNZf+!K;{*ET$8>0IyWEJKkqbam(8~{5b(U!+WOIMuY8}T&j+UU zoowyC6!|C4kHS@Q`JeiAYxZY;VU7LKcgxuuxU@BUVSNfO(|^AY=oYH2z6xJQxKF3; z3cQ-Wz7W|{JcwUMMf6E>u1uKxeUp+Ted-7LagqKHe?Ic8x$`0GU-kFRUB`i(;ytwf z@CPui&JWV~Mwou;kMwoWJUjm$dLHyy-G*=B@0+Zi>SGwEq*pHQSpKH_f5Z5e7h12R z!Si3C*C`)p&v{bPoDSbb=FU4Qll1P>>A04)%ZSct@H;#H<7iwX0(ys&rZdu8dW2p- zBYLCx+=uveD)C-(>tdwG?0og_{B?7FT`vF4>SO71yUh9Dbv(VVWiO}eEGr-SnHSP} z!u!*GpflU1p0ws10eWN1{c;%J+uO*U&7Id{%=c!L2IbBbIKS@s0N2#M+tsBVAwSzp1a+`9yPZ!0K&xfBsN@eT?=k&UzQGqt9PXC*Qty z<6@Qk=sEgvVwE1N<-|XQ*THily&hKUVdc5bwFWQe3H&<7>Vtmp<9Ppzlj}z3x%ixu z`Y_I8_Z{Zsbrh`KPr=TGYIEDn<-hYa4E@D)y|l`1SC{_zH`3c&{CKVYoa`wko=?Av+~k^!S|Kx$dI2^}ujM7f2_59b9|hyH#I}c&Hk9bj)BYh_oX8DV!6rh;I{mBjBEbgG`@gO z>OQ_4m}lFpAD>6&ndb(9F5}|+1@qA69%^mh^4=_`2lPSfzY+TzKhm83=y%NF1p18H zFgbTdzo(ziA~~5G`0Fa7Un=8nm$|ypZo8A67)ReeG@dEa4-WFr;T49y@G_deU3NRZ zC>Q^+&&kn=?2O*hTHO23qVvpkBmX)vI7rip>|w_pX}Vsr^K9QwzGssihkou!bMk-> z+R8Wd@vfdh%TIhsKku`G=UYLa)otu5YvVT_vsNDK@BIDx__6eROW!+*7wh{|_$Yt>l+_<&>V+&H(4`*c>-RlD=Vxp?eZDIY zz2(d3^#i#^ZTTJg`|AAD{Jb-gYc%iviQMx9`KMaD4mGl))%mWC`uK_DSF%g9e&oJu z&Y$3Z=JGmvygB+jLm&C2T-=CoU+D4VvHEp~wI{K*xjbg&nC%yTw6t;cZlQ6EonS7G z3MT1|@T>l|xpj*DnSbBONMEb-ju-RsDnH2gBl#RX?q5aYKYy9I`W1{U?K;lln>dk= z7fT0y=Y#zH+j9(!TlxyR5B&eFZDvUB`evc=@&3l#`pepvc$=Ku0QtQVk=$yPA8#W1 zJ#9SOrh4Hf&!Ys~bbSMS9NYBkl;4NXNA3^fb&zCKD`A$K3m_k`T}5Z2E>X3j3)TddY~t~vi=Ch2AUO8 zs~?%2=I{~OGcWo4YS`es%gPVzYmI$5lX}69tjYV0z_(a!;>UD;CI!z`CED~k9q>E* zgnqo21$F_yQR{uHTznhJ*<0pa-3Imk&v;+;J)(cTX*C{>B7Z;6KV|M5YPDTvewmvu8ssstxpgy(SMs*@TyLb`N9S#(i1*LT1N!@@YX2O4PAaXY`yHq9<#@6*ZVA%&lkfGY zk~a8eyuN{F`EpzbVmTSXylN+TQDXG6^K3u$RU$vZ_{9<~P``2>#-nQrx4voIMmFMh zfy^+i#`Al6y+MHI<+#2l$h`Oe49*k4C}^`S-gjZe&I>*_z|t*LKlyeV$Mi09>z;Xx zpGOO2zpS3%XUzE}E7ypw>l|}=9{CIZd4eeU9%SE2jCbWe`rJ`{#nL#}rA(g7ORMSl zGr|+*D<<{$f8CrO&{ufK+H)hwHEP|zQj^y&iiC@-^;`Mah4PS%TH7!|R z!v5y!kgLs~<0+?_+s7kEVLn%hzD_A@ms_t=hkjnL`0uU#oQUY!HSWE6Y1O~-ORUA${b_u?6aGwV*FEjRALNz>={S!s(&sO|%klk+U>A72S7yf$xv!ZE|)2{s}_wF#G+fYx(*?F56Zv!MK)wN&8WJl8)QxAMm*_ zbqGDq%JUxE-1QqPXQBG;eQ+G)E|QBc)~>?8m$tuN@;w=>-B$I}_vpui`vCnq;dnit z-{GgvNse7~pS8dGc{+aC`K8j2rTBKnkJPV6rB~?hZ{GX$uiJvJG*=gl@XCLg&X=^{ zyqolzt9z{8(vS7?t18gT%CV|HzfFG~tkMH=lE2blSD>@14ZM+FSF7YMxSTuqb!EZr zAPT+vFKpac?Wg-c`gv$pU*R`&9n4R+2cKMTd*qt+w`}rU6pXZ1H_h57qOXwWF<{>R zH98JbzohF$<>mCc0-sUqxu4G0G^59eKX@~->#O?b4I?>=HD4s(8xudBUiT97IbYU3 zugUKLVELDNKmC3>E?TuWzQFf;%FOd4M)pVVw5DEVuch?Z&~Z z{KC=rded<)y?>jPV?-Z#H61@j^e~@zIlZnh-fA2DXLI(ns<&_keSKfr!M7v(9IpT2 z=jnaGJ4@61ze_)VlQ4Krz}H3dtNuLK+<7VX9(sK;e-zZcCk5lG0rZRFx%&Hkoca9~ zn!BST@KSU7SpJ3TyS`~n-uc!G)|EIC`4)X1PZ9daZkjK_K1XfWV=J*Se^vTzolUpYArBBm&r20R^ABXvNwW&qYYn4CM5`FHlN-oHWUB%C{;3?+T zALKRLMkKHI;z#rCa{NXvzMN*VyZ zex!b9P7ll9u72#k_SUa<*}YWc`fpm8>nq1a&Bfhf;Z*+0!rGhp1wW3X2jl!N{)f){ zW^qX_=U@MTyy!jF)M=2{?$-N0d>!Q&r0Zm}dfm74&nqH%;eYC{OX*qtb3;LJJ`(9m zm7A->sRwAk{3pxhy>}M#6&|CnS6TZ!bF^KNRXC1vKd1GweC6+B{KDVI@`Iw%F3+pW+T&luP47Rl{_ZVwNpe17{i(d%-2Gmb zzukQg`J51|r}$!iUH3jO7e58T_i%bYL+?|*&(eL?4zvCFADTQz2o(4;*4iadv)2q) z$otUw3v+wD`TxasfyAH(ritixYR*Q0WX2NtlN!xvjwflScoqI;S zls?JFUm7<9Lf04h*EjPoZjavd)pBuSV7B3O;?^ePj7avR`TYK?TZ@}m0LzVji(hXI z9a~@m&olh^u*!_;`{;OZ$M8N9y^x!rR1re^qg;(Qe6m#ZR&k6HixTlsoHPW6X! z_GjLzUzdD>@8hgqjrAwqET;$T+S}R$x!+Nq)UT)Dch^lA@8UDf<(vNsjJxx{{C+Ip zX}AA<2xKq7HOImHhD~C>{ckh@SUGlo z??S-Sq3z?<*uk|JOFXkL6>IU=;qeq{I|&4(w=K(^%*i`6pE`V*22`h`_Bwbd9mB6b z0F!{cj~;iO|j34`TJU&mx4>v6I%@V*$oOGo{DsMm+PI?=Lkc zPD~tHv)4)P&Agb5FDK(}GJX<~)9pI2#^)pB%aw72Pe%^N33`eC;M&!{FUHsL2l~Az z?}c#9i|L~Wi|>nJiuU~Ld6KpZ?kluM+u}*}TzNEgZ$Y)>x~FR|J8Q|<(cwH@$rR;} zbZf8ee{2M71Z)Is1Z)Is1Z)Is1Z)Is1Z)Is1Z)Is1Z)Is1R4=ohHkDYe>0>_+Rrp$ zKXzwcrmHk-pnz(&AEz(&AEz(&AEz(&AEz(&AEz(&AEz(&AEz(&AEzyN`L zYWLmdZ^h3&r=N%CpF64hap>7-^cQ#@)8k%8M$=E$akeHy(4e}GQ5%`tYn?!tbsI3rwML4=yY zB|~r)+0%Kbl0OaA1b-H!o+nAyq=)OYoy!hRo|cW3T&ej0cM^ z!sC@hpcy=}1YeOYod;|61SJhCJ5Bh5Z=iATUyb{K!^tW#GjPrdeP>_4#^=w#ahW1nXp`_JNu{6C8b zW!H+Q3+iXiz^=}N)Ot~?oviE(;ja?EL09=rG!Cc4pT7#tf&D-y+ZGu+ecvEBFyjb^ zvx!jFR-P`vAy07S(V#Ke^G24)30#By2fKZ7+*itP?GNw(Kgh6jQ)cW9eiP%t;*0R` z5vgYIC=q-`2AMr?%oBN8f&9qBS`mTugP-N}0~E-cOnmk}b>3@%+np2#5C^F{}elO_Jc zxgh;^j0c>*;Jg8Ti1doay^Ou7?_fMwd=Va_P2k}o@Ch|o3jd189{DF569LV{=m!RVT&K+RCNS|oj z&)AvCV;opq5e{pbz`;Z0iS!%c;3E8K;y2W}a;@sS|%(gX*Po4g+5qTEKR z{XG;p;Cl2z^#>12|C?v*cK#US!s3i@Sx2Or!6jAD&l@l_OZ-x9gVg>GEbb3eO|?!& zFW5Xay@8UKCwd{@mL2@)c8b7cr&HMgL!ro~xzM&9o44=YG7}1Q?Cb8>cYnnIbdRTF z-&&bdrB+ECMv1-d_tAOKbp!6h^~lKMZ+{zNhILW}NxsN2xMY8V*N2TCwBD0MCSa$h z0`6~ki98W)hQt@lgKTzPe8g`!Pdt0_+#i9bnYQydc3pPN#C91hj-n_D`9S>25xc;K z%=_{B98Ly)@W*>UgkA!!KquP<8T@h&;PqkG8?DcJA`~#x(*f(_Bl1MFo%?olbbGqH zVV;%k0sarraatjLs7tr~<@o2246q;M$+lt8Lm1{C#5l0HA{+vQhP9Qa3vlogc|004 zhH&u22DidIE89!>eIKN8@O%jO4i-gL>`X@jddzFKr|c>7U*xHK}Uedaejo(kB%F0AL`|Y zpPi_k>%b3@UeS1hvA0^pc(C{)Jf?{dGkC;_Jdu91-*fPQBV+?EVInU=Z~(c%k78V) ze!lV8Wly0w@CWE*+cazULl_qpXN1c}BGe2niCkJhjRQ|(XnqRbis&!ctdF2a1b3k zT*{EETRjf4I^#sH^W#kZq;Vhim);YmJqQc%OBNTP%QN=7e?``n8AteBK$uutK~{YW z^(0I1uAi%ajo$zD#Bdeax^-g%_G!W&Bz^<0{}VJ02d!1xM9ND%cHlvTcE}&-)1WpT!gT ze<2ad+RD=faWGHt%+Y)1M;MW8XW*p&h z5fN$zk0QZWWDnj~ATOZZDBM?aM4snU7zdE+`ZOIU?`VvDH1$+G-wRbbq{d-Cwy7rFYu>7i~Wal#k)_-pMvJVZlIHGtBiet z-w^+qapeESM5rnM37#T*kpI0s9RCSlh4>5nr3}6PzaE?WC7J`ffljuqGWG?2OZ;cX zk^h$vp{D#Nc#7;n{txtV{3m>#&tZRo-}QOihxaXa#h2G!g55wT+g2I-0>2~vGvmnr z5D{w1e}bpT9-;q)FGlT@w|FBP$V-#>=tz;2+EZL5rZf!`DVnQ`R*r9`MH{|TNVdxY^%_i$RU7U>aPW#T_Gj{M);jQ<993H>L0apEu7AI;MKAN|%tzJ%t$ZlIHG ztBif&Cy4*dIP!lB5o%`r%LGr6J+kNI0+CZ7{)4>vuV6fs+gY{0*Cwz04tfE8;8FR1 z9mId&@cxnD!T5pjm?1=F@RX605Hz3Ks7 zRuMzDOwprk@g3-#TQAE??8%bW_f@=(!0!1P?!!L!+1oBV8O_0Z0G(`GV*C$0iPwRR z6SS`6)^Nj_oTm%rFZwHzIKjQfe@$Qi5P3<014xX29peJ`p&vYgfPnf<&H(woKMRofpJqn)prN?zpx~)75Cx&+n0az&|8sguv?@@G#+E@D?Ww&XYoY-ZzDp?_#YjnsaocIlL zqB$CeeZGH44F|9v=w#bCV`sHOaA5F3IJ|}kHG@N($P?Mqd6ITtcWQiXXn1=4y77_5 zo4c&eAdy=lc!2!EZ5SVTzuU8RpWDzJ_yu&bZJM#a`WK83i#NjOwL~auD^C~HsW_3x zqd{Ycj(43NBYf`L={)JW1NY&+_O%bsY(jFtZuHvBUz)Y=Z`gkpPvrl0BG`=oiN9ib zBAblfKaLUp2=N=_1n} ze;g)qzJAedyML4g78;} z-yo-SH;u!Nn;$~#GDwX5~!QzYXh!UY@@W>K;MfTu20Z&&n-q%YL{y6a)i{PVSUq zKAgWV{>XIg^W)%;NWW;j%Ge$JH^zm<8R4?430z79XOVuRb47vhr-|PnC;1(WgM$qG z@|*DldI|Oeopek52Kv~4Fb*uP2#4K-$V_~65P2YxHC2f)5 zQM?)7Kgxd>;{)gK_g{-Y_XmE}%aVERV(gDSi}7LcM)=e=FhwY1GFJ`Mkq#n{ON3-8 z!g%kKR*7A%JoXpj+4()(hxdsfPrz=G9?`gqu`m7{_MgQQ`F|A=V#a?5ktfn`bndJY z`=Z2ekQ2TS<8UAuIOvvlK8ap}{Xi$%x*0n?9m{IpbHn0_aEKA1W^iynk8u^*)5Xk# zY*C(c5PBDBGXxKipSmC81D_k7`49g73GfT(mRjrSz;@3+k6Yy~EBU@5j0oTYcC&pL zZ?=W|Uq<|(x3dFwa+(9~=Q%pT4|<;MfjoBHY#-!o+Pw=d3u+=@{L-B>o8UeInt<`m zo95uQKSi&8ky356j(&E>u5CMZQ#|$Zw#;nZw0k@3tQy}I%BuSD-Is2!lLmIpZ0FlG zvtu`022=Jb9~PL|xq}$1G$3c|_SsFEHFe{&a5}_1K!4dRAHQvI6P>64di9HhnDN?o z>yRUTX8ZcJute-|3`r0sY*z*U!w>*`|)~+O%sM6p=dpbGvr# z-dqQWN`KY1U7O*CY#sfs*F|TPHB}V@{q7yxX6xWq{ZqelO69;WfbYuLZSb~RZ34!x zifpS716AJU*&TCr=Bnf5J9<Od zP-rukK;?&d<=N5tKW$z~z&geBIKxzLS7_Vio8XO#hH*W5zsekHxXmWV64pD7< zd~(hB~I6po)Jv=(PK`_5_M#<=H^%;##*Yxu# z8s}*R+WgktJ2umENP{-NX5-|@^!WOEaH#pfhOub{9X?r|98|%TFY=q+K`8@0s1DVy zK8%M#>M3K_p@8K&duzqw*iqh(jk3wwJcEzk+Qdi;I>pv zvJ8E_ts1?u({%TsO9tvso4-`q$+hs-#{~yvC2`>uo|5+We-u z`VE;HuVd22>59&b*Kx3Ruoa&_&kE4w^LK{Ed0K)tPx2J2RsYrIAx`EZySHv_*nl*; znJt%vu2fcJc4sZ>XmxeCg1k*zwkRn)#{`}xZ__TN09?9zS6xw8tmDj6nqZz@y?Q>h z-zghuh(0+2pOSZ*E{ks3ImZ$ZWa{W@g;@oxVIJXua)vUm&VDqHPB|PR%1=ZW-L-Se zwyj$^q?$d5?o#Ctz#(docNIDYa|vmAv(X(}^z7di**SX^MWFF3?@msRjfT)?Po^l6 z8d5-al5z-BHf~oaMAIuDQK9~T-uWeR{dB0@bqFOyq7yj`rNrvj!> zD6nC8?YiO6hOyBxWg{I6jRmJChu4kO6DzNQUc*7a#{dF+&My-@RJ$1kEq22%(8t5W z=oRBJIy^ll69<^iwS3*C*SWfTTs@xdq2-zr;I}J_{dTJMX*5>63OWt^X7q~vo*rK( zD+o#Ub$9{T1xDL$%KeZ#5bI!}a}kGkV2-Pfd@G$gDS}W5QeW z_p2nnRl77>t#}nULf>B(qu0RS^T#$!HJlldov?mdp4a?V=~0|_clS)NJ^`QSYZ!+L zV-HK;Y~O#RJ`Pk{y>G%&)VN?-+Q#a-%b@5DZl;er>2$7Ub{yiSZ|;c`+W;u?=qvm zSwC4m*D?BjJ5*eZ{2m)!tLtxVUhLAR2aQt9F+T2V-pkOQ)81;jp3liw}t~v&lUpJ|2we%1$Dhzc9|03ev!Wa zRYtGa|Fx4FM?$qj%lPC3x}edDy`mBP(fn_uug3uB{dW@o)perGZ@JU;Vgvsfy$1eM zJ|pA656171Ymhb_==^sPf7NxN>00eMU!w1Ch0$x^@4E5H_0%m|@PqM}(7Ae9`+?qn zH}-p8T@RMBwZ8LseZNbLUIV`a!_y=FiLvv?Cg?C1t#>`WtA6KG{l5qMpHtVTHGf%d z=LrV>GkV4TH}3UF7xIrtZ=e_=5Aqe|4Q$4_fOx zUHbkP8NFiv(G4r*(uLXe!4J)UicZ_@nKv|nFY*oIzq(GX`O9)UPc-nK(W~#ja%m#v zze=b1&%ALA{>Q#a{8!hB^`NzW#mIj~uh{>_y$x9gey~=;c=TJuKh+MFvbBC;xxxA} zdd2>&8J}SGZe$tw!CDF9k#A%FQmP#+Wo!M+N&5cf7`-C@@a<&nt$47XwGPI^_hP?d zs(zNTwSMAceZP{7UXfp+(CT63+}W^r;0J3Zj0eAi{R^meu#~O!!!OnMFUsf@`WM)_ z>9Wf=sm6f)>Hv8GJX)v27a(s!ni+= z{d1^xu#~O!U8m~%=VtVZ{X_Syr>2M31*nq}_`zBU#Y1L-ikP z5c@ZCKLe zx4YTV{LA$H%`tk#{_fngt?rRSuwV1DHt%BX1iHWvu%8Ll9+tATe&%$2Khum}k)O(Q zd(<;-U_bbY=6UxY0zbt5MO8am^M~b5y~BD|i?z75etLzzzfnf7*kAe{B5M`+1M922-%j15tle{TF&86sI0OqA2cK#$tD&`i zdZj)N5k{{Vhq`;pbtX0XUq^?XheuW^6o4=CW9+|QwX;sR1uv7U4E$&Giv5py2SVtZ z$LK%sLtB4LCyM*XPl&&&U9`MbdvT9}zl>fZf7whI`OChA2y~GLu)ki_u2wyy`D5Ms z{stMnVt?_s(=xXk)Ow|@Z#^9q(lx_WzaPYYyH)#WyIbu=di4GFGkV2-E6*$MZY=2F zhvqk-V*(rKB0t6cx>UPb^^oQd_UilVWAqCBMQ@LdtX~&U?mld&QvrUc{?^mg`3!X7 zpJ9KUs$F%$1TSm6ec*?Hhzw_dt`mnKe6JCFj>g0275S^L#dsF{4Q*7e`bWn`CZ+;o zBU7O@%H8;>;ku_pfKJ7aOJ4^hQ4M_IpJP1z;J2}9HDCh$a(K=I9l^7U$X9+AqxKhN z^tKyM6({^wR>K1rfQ!3{=Z+9>WIzs=GSCrR;Cs;yCb*;kH_~5VT(q0}ZFnvT;glSd z!^z<#be;HlO!z!C#7`D*TpXO*^86CQCkuWPzeJ6Dh{gxLZxV1SGB_`A93gxxf6fWv zQvkn3z>snO8T$BC8JrgwpSC;?h486>-v;=EU!jjr7b9ok@TomNVCnnl2p7jIiN6N8 z#DPvwpS^$^k+Z25e57f93O3KU#`4gztU6pX1!ty@)7+t^L{AH7w!B=zIl((QxAP8TtHv>1wLPAC2>It5pNdoK?6E} zfngd)*!SW4G>VMg1;cS_?7Yy()HG{4;L?C2p?CGu96(=r2;*3l#05z~yj8%57TeHE zt=7lU#mHGO9EV5F+c>^~{n(HiUkx}CdRGtaqKe}$F^)d)mnP%(5U+1UF0V^KNAjAD z#|Wc$!EjXabWC{%oplg!X~2=tvrn`EeT97ga{~Nj1#|j{H!&)QqkBw09C=Ujcf zij3a&;}saMf2@!fU&_1~uis$2Dw6&qP>_xy;J`&m8;nip&h9x2udP-`qXz z53Qe^5PZ*yR?iyg>#sQg@5*m6jxO+5gFyHS@w(Q@L*<*=xKclzpI8Fqp zH-`ZS6*n|rw`szB<#!mT2>2sJN1H&r{z*BUia0VLBK4 zg+PFJ<@Xpr2l%Oj1x(d=H^{|b8t6#g!u?FRj&(D77ZyJTM8!eCr6CS$q>W$#eWi?X z^nWmIwe1IDo^i3`FK@fHCeG@$brJ6|8i z4o1#`;W)Z}<7&84!{A=jOruMyU+oP^D!?ZqLYl?1;Z0R zPFjEDsaXWLG{hy)i{kQ67{{C>E=U>Dl>>Zg+Qt9)FQRc|D<4lcg z#80EEhYsi}f5y0VfPZ2L)EUHEk)%((ipCAT{TZHnb1`z-kK5|;wQH3R6oqQvFS>4w zK6Z1?I~@APbXNH)PhmX0;J1pJ_yxk#_iDL(E(0B@k8oWK&ntx)z3sc}Gd4Lo&i%euEuXpc$~Up~Qg`sx_^e<&6X3TPMs)`9CNGx5(|ZXWpMc{_h_o!D zccJi9qOK84#U{Xo#j~E?)z{m@e7&K{SN#jdvnYuVf&u9)0ZwQ@=PwbW@r3&~u-|kr zauy2Dz-Yh}p7r#u-o9?;?M@ZXj=y0%-Qc$lHZXh&(#+y z-?NC5Si9Y?;-ST5J)QFPo7}VqM6|eeJdN>;f!`X*|Fiez@vW3)|9=mgMG@jkku88g zQ8}i24!D%%Kv0&-qEV64BOEBo5?Qn=O57_V78Q&OTKBrw4Xcl0+~WdPK&&EC5wN&G z6p@N3zq#i6e3HzSxtlxlecIpiN6YKQow?`QKJU3_xo0Lh&QHR#xY>_q_Qlch$@>@k zBYMf?U3s25ad}?Ar`wm;3*LaHyKR zE6*4AeMXLxA55}ela3j;*1qwosm?L`Pwe;9>jKiyFC4p1^Bbqrw8MVS`48Xo8ZmiS znqz(Z>4kXsn`JBXJuu-kvc-?n9PRM_cI~iO;4@&yyzt_G@b~$EyZA=da{69JlV* zBW{P8DG&`j7lexfZD3 zCW=`W-{MRCxOScu9iP149sIM`;a|z*U1_fM@fZEQukdHSJoe`#zxyS;X2=1$T}|ff zC@+pf@~Rl_tIKO;e;-UZ%~QV%5c=(wxG7?||=|H=RZ5=Y#tA zYxvjR)jskiXzrgA59t1xrrs7@WVQIF&-L3s%e2FBkJr1rZ=ExFSDs^V*vs0pM;yNf zyR`nBD{1?W!GVP^nfSMI9HU<8Z1E=?#|nNNJ731}7(Ea3dT+wyT@{YaKYLg^pVr4= zz_DhR*27@)&urBEN)IZ>8BZ>PSUAp*k8~{ampd=Yk=KPh56_vrtHQB%*sB-L{WHR` zW*6C&Lnqo#{YUvNdGZiv@vV|e7|s2^iSy(6@w&Rp#90-7!HY`vkVqa8el@%1%R$;t z{a5*Asnd<3wnlt27x?YRbF{K$J&9eCXzg&9BXzsAjbamP8fs!bF<2`?8!%* z#kWFEVKn#u#$FNS$?F|n7cQ8*tHZN)z^fHb9#Nh(yZXR1=NS4eeqA}HsJ9l`{Xu+F z<9_3EmUd>I$8ni4c~^&H?Z8(PNgh#-HM>^RyW07B=^M&3Pu;Z)?hlfC^p$=*J6{z) zF8M9gag%rDc?O5eP4d;Sn1g1ZtC?$)eeBgF{Zijlp3|OugtGX~kdt&Q^Ot{hlqavp z)9{%yc~_BV?V#9LKDpG#X^m&iKJKcLe(7&1&m~Vjk~{Rh$Zvd3(+>MPpO5Sb5oz+q z@+$JI9Tbr|Y{(^sXU)F(>asqryRT86IqGfjlmtCCFj&@{dkUC9NphJKKDTEvdO#hJmosleE@Cd*=%1w z$=j>XI@e5Dxh{Hg5*(6yiM+ta)yx#*x$=4`W#X(R*V=)xq4?#v*6dqejn?@Ne@FQa zlS4x;*GH)#|2n^M+xhw^U%nT`-x3}(c~_Hf?LgTebUD5?`})8&SEqHZ`R^*%DNjyP zg5;hduZEi9K90U2o-4;~#pGR0uC)VZL*dJDt=TVgwMzf7?NQSKOY}OR(LVMvwdPm+zVaNQZs=OB5uW)s`SI*{ zb99{YeFfiBGoi6Oie7$v&+O;J)X6rVx(v{ z&zk+RJg0u7Jcp?}5UI5ZSmuj_fKX`-c{sUJ1{n?T!w4SewovKjqB`>mFuD> zC#gYlFOgScQ8AyVFO72Lyo&Fgrc9hwTeQ5`CGj17x8HuzaYb}{@HoToFO8YJE5ALC%;z^9a_CX~H{Ojx za;bAR_UWEXPfy*6_A}Qj$7x?KK?w1kCZBr9*iXY();NYK`MwJ8)6AK?E6?$S@Qb|i zDs#ivu42Y%gIzi^K6H9i9{J7Qp!}+yJS2+vE|N<$Y|~QlJyCvq51brRCeAAG%LTv7 zVe!TBtJ#J4PLBd4zw(XBFGHP81e!aGY!>7DrC^4z&yja%D`jMFr(gj>4%z~Fmu_3NJWf$1JT&_yQtcl<`j*OcdY z5qI&O<+wpSSCgNLA76Y9I%jyT!uYD4Xd7!Lj|QGKyI?ofv&iYEpVa6hpXryr8OJ;7 zwT3avq3?&6A1`#9q@B60;eMJnc~^@gc2kyF<6$|5!!lFHM{eD}Rc<-zt3`5u5Z~-a z{J1U9&T!-YKW6f-JU4#7IeMlbk2<%AUBj7zL$Tqc8}Oii_btk^NZoFXwKd{9@lijX znU6*HXWo~4BBD*1yerQ${9b(&W>5=x)OptJ8un+xJSj@E?w|dg@|^SJBN!z2JUL0n zGJl1SM|tx4kk5^(Chscn49^?SJL>S@_mAr{<`|xhcF`Yu2=vl^zoN;z^8Dnq+k`KMUxQt`kGJV+RBHTwul%N{vu5G`Aikw(KYp1{MfYD`KXV+G zP2QE~7f#ih0Fp<2{59I8Bfr%xWN1HfoAO)mW@{>DEYn(awhM}bJY2V9f;&n=NGYS z+LLKNa=Y>yqt19_kzVl~{j49qCEA(u2=6OQn7pgNui*e!mqi{8{2J_<@YVO@JCxrv zb=E^VKS{2s&-w8i{`~U$amD0ad49Zpwj)sGHgh!gk-fO#czCCBT=e83*(BE@`Dl9Q z|BGLUa^(2q{+u##R-R*c-P{DRnO~!wfd>X6dgPDFFGHP967?05t9!<89L~|saXm9) z@~%9;VE2^SiJ74^^J}zgIo+%8*Ne)tK;3n0&QFqi{EL1(hrbjZk32u~{>`MxyJ|cS zi^?OF15KKrC2E{s2Vm+~%q@{@AJcaa=TeRgs3%QfEN zDqc_4_J0#+<$23{EX@O$JnH-+b}gsa^w0ho#{=rNKw_4~H~SU8@w-Snb6(#UaYszv z)#Di*z~o_XM6kb^bA6yT`p|ylFUqw@{V^PEm-tS8)sJiD>gYJ-ae>#HvnKD#bHy-i zI#a1ia;bBS+S@Z0?dSfg9Opf`NH+1ECm&7k{D1LlHI89Q&b#@%y2Hd-d5#UgXJpP< zB7$7%9IbuBxvN1n{pRjgo@wfCuyK79-|ktzak)S{?C<2r?_uUl-qq!4@0PdXS$mk% z1lc~(A>a9Xly89?Tu>YO#dqTCetf&X5go7O%ipOjnY^pYH)h`_m)P+N`^H%l?U$;` zan6&A;1u6E@{x{Z{>J_%%8~E2^Y>|%Ox~5}7#t6?_9``QeAey4J>6)m@%x+d>!MC$ z7q=+Bsc-s?!)e-KKj(dO9zU}t@2c<%zByqJndDI)e*r(*;ZWJgg7zKvD!)8+HX1oT zi|@#{{PT-vAqsr)k3xeN=g65sCc_>IRh?aY47`$!`u@9Oa5 z0gsC6Jfi$)7XpkRB){(am0y86>mi+=#CPnwe*8MW7af0`*YNy2Y4WZPKOXSv63HXV zk9OcEJ9GV&i_n>VnI+{oXY#HNM;`F%b(2SwBkdYE z^1#?Q*$%?cKl?A`x#Y=5DhPdl;5RO(XovlpQZ#v2g?kKw0CGj1f^W)k5i|9DC`*q3WT}7Upq(n55OU!YS z_6_?rCpGoEJ@n6Sqg>0LoTLcxog=SERm}@y*GIW>|E_)i-Q-;rt^pyh{aftfUlXXE zZ^pJ&eqGerjG(DU_@!>}8<(@R!v^Di&iPE%3PawE6C1olAW`Z?X^e^Tso`@~QEBnDU(V z{r zn~tmC!mzDzNPCP!x#&5`aw6A-M<~}>Pfij?d@JN-1DoaXn`>OdlpK$H!EV9iT^+6g zA#>qF9u^e)qvKTkYZpWj7uqlGpj=bbZ@9!Qif{V2e&cnXc1Xza%JWXnZD&FG9x9fND^+5hQ~KG`{|T&?4({7kcNKA)w$p|4yS2{^Esbu^LjmF@~$Sw=2_439AO{% z?ku^_JW4r^P;Ub-*GKUk`Mn>R{t)HL`8a=b=Lk@kM$v;0`)nx+0|n%E`D zox8(tzh9)CdH&7uIcoB*D%ZBgXTWut@j3T6eA3=;e9k>yxz2lXlAOYIk-Vg1nZJp}C|7&@>@aawm1|q$GvK<+_*~do zIcBJL875pM95Z+Mjn6sSnfo3*e&$WymFF1VpKQ2*q$+JioBY+sr?n5pXTv=t+Ank| z$8qY_Fw6d5e8>Of$1(Hg`0+@NQzq{!a^!_iL@T+(aHM?*GJ2uZG_9;%&oAzxe9NA^ zq!_7Tp4=kUH7`v5CCZoAq5QeBMU!_G`SQdaDS8>cv~P=V$F9mZO%9Q4@e5Kz_OE{9 zw@N!42Q1&5$-9btdE$wPT!t_0+v3}`oAND^LnK@Lg49sD+mG+?JD0)P&znDt@%jF+;u7w@fR!GJo?Mm-Dp4e$Vek@p>w6@~%8bIiEKV%w~QO zyO#Sp{fGBdp5xTL3`edK-{Rl>c&6@+j!XW&6Te4ZGI>{?=aGjUw&|#ihiw`d*g!!+ zOCI&{*kG5g|4bI`@@eH(@#G+>#CMiFq+^-C{6C`Hc;A!z^`gnUs@ygmcHA)|M{mqG z)K4z4{AeG?aWCcALA?zzT_3|-_xX*#DcWIw=KW4yhjyF1E6?$Wqfgwl@wtZ_z3G^Z zC+3bjyy3S3MQ=05Ci`@z0SxW)dn?Br^)}eJK8kPdpMD%W?vIW~UJvp9Qo-b1eU2xd zu&F0IIM}nPuMsKv)W@ae+2|KR8)Bn>ejnvK>B}qd7T;-d3!}OJms^VRO~Z6Av}Kcb z<@p{S93$Hqr%m<^dwYFc=bxw?tDam$zHqFP4|uqm;=iIC?Ktf+aaNwAjJM+tIsB+r z|Bgn3T?4t=_}f>xWvR~vprK!UyC3k|zbmxEanhb|@+R-P;bO4enD~-{_V%Ha)x^s@&Ns5vWOS|H zaAK&7^|WwrTD@R&rCzAIET^Qpj%vyn-!TJSomhSLA@ku+d9$8)FL&=Owht{9q04eg zs_WSd+@hU>u7|^aps_R4sZqZId7tdeM+d~~# zPYd^^)!op+75URtm*tdH*GUZAqAixio^iWavYvP^ckc|g4=om; z%W_JptMT8IWRAEtwRQA5Ds{(BUlBXj6X&yB-vo5fX7&u-UY1i*UC(FW7Hv0l@%)wg zz!QETF07}8d(-Ms=-`UUG1X-`CDru;25!*~o9&g}X(Ie*##m1a_omfZ=-`U6GgX)6 zlvLNr4BVp48(mXpy(=d!tfz&0)9Ms-aK-RTRF~zHRM(3bxJ6qqy6ziW3U#rb7Vb@} z7mcp2m#QwyDXFegnli?BOc-77yY;4U>c)EFz1+QJY#&-wq04egs%sMiw`ixJi}wNk zl}*1)Tv$&F_ome)=-`UVS-QO}r=+?@8Ms9|3tc=O?zMTUA}*|_g?rQL0(5Z2)Y+=b za!RUeGXuA1=b(${u7731fqF3TyYt`{?Ki?#|~ybtiID}E4O zN3ot3?oF%H(7_cW=c+EtDXFeg8MsB;xs6_La2(!s#;rdU7uM6ly=nE5(bZj0U6xZ) zU0a$m#&@KRu224H{inr}^~8I*d*`ryY8Ee3U6xZ)UC*ioUj9QCx_F=M(1&)`f7TTB zEbraCb{gAuKTMw7O_`%$%p&tHbms)pc4^ z#`unc8Hazk;*^hwWv!lgH)n62I$$wzzUs1^lIjXiuFmZB6%%HAec`RYeXXozJ#|aJ zPZ{W-_2>nv%W_Jp>pTW-(N06x_OQGA6W`lMKC+$`?oF#Zp@S>37pgAHX{B{lpz9GR zq%`}X9{I?6Sf6jZV05KkuDUFzmDaTgT|6G%_PBI74q1<{9@@=f`*3*?x-6%px_-vM zt=et%yv*a_($pVcDK4z1mAhR(2_5V&ze2Z{<+Ree($K~2wav(%Un4cK9@gjEjzI_Q zOXI4`a!RV}S_W>>X3h5c#x*BDRa{t43-_kg!_dJMg;%OB%W0)`<)Mq$hgW>?VIP&6 zSP$#-ZM&d@_PJN7F3TyYt_v8rMO!fA@JAcBd#Sjvo)+#+tE)y=`qiq-a!RV}rlySX z9TU*S^Vj>obl#z2$$H|w+`ScSA6hIym*tdH*Xa!0qMe4WN5SsmPo5t>GGaX~+?!TU zK?hgNU8LK~a!RV}X`cUJ_?+2Zm;N~ujziYN`h44Q=%D@dYgCuzlvLNjp1P{g#q-z6 zSG?^isfqQlKHqi(I%r>ft?IIzlInW8r>@j?dS2%JsIR=>#*3vU*2DUI+ivKfeg0zA zWjQ6)^$bs4-O$DD^`56)bE(wCdRU)#3mvr26jhhylvG#0r>-1yJraey=V#}Xav`Y>Uuc?w`doji}U59e)Imf zi3{s#;oh`51sz;5{3g|9IVIIK#=x!Ghw1r?y6(F3>;EGztf!T`UB75_b-h`2Sxzgh zD{XWwY?b|z)XI8n-L00(*gmwYLYL)~RM(jd+@c+ZE}oaukG<+U;=+1bxHqjXK?he< z-lE&fa!RV}Tn28@jzZVNVfUTq9{O?l$a-41H?1x}2Uko@s4mMXsjdP8w`hyd#pB_R zXAj<8Tv$&F_omf3=-`U+x2i77X{B{dnQ=Jr>ev57YGOUC&$mrO2kl2LQC*f(Qe8h} z;1+G!Y_IZ-8}1Sp*3-hhY4wuP)%`ZrWjQ6)^`oYY@f{1$^%$()=9BZ``=YET-pk!P zhwVd)rMIgt%PFa@3IjXZ%B7lb4(;`5Z$^6y+CQSb3++G9{uAw1sCyf7XuYOqHw9b4C;b!;7!-?6pi zt_A7{Z|~GbLuaR6w{RYJ->D~r#~+TvnxW^1DR86t++{kx?EaB-JpY4%TeRKK#rxrV zp8fam5drII;oh`*96GpS`W>pva!RV}?+o0c9fmGmw+wvg;CG1&>uKTMw0Z7+N~-Ieri}3&73jj( z$2#8jvQLKBnXD(?%iTMJ?L&(N=(3!W>iQ`Iw`iB33tubf*!tpYza=iLr-ggd>IvxJ zirIJT_OhH-T37e>(dW4z8+%pw{GIi%KHqi}I%q$6h3c}LlImLTdA}|PUA(XL#GgEH zv(&_TSf6j3g$~+}U8%Y(r=+?DJ#~#j7w>$IhqqjETsRI{59{-77mcp2lIpUYlIrq(?l}crJTG5$-j(6hhxPdCpj?JMuq?PWP7)%6PoZqd#|7mpiP{Nl^M5f|3e z!o6vA0Xn#1>V2xqa$0F!Rio>XH~jY&sfqQlKHoM69kd^Rzv{A_lInUE1Gi{9AFk&w zzE|*=v){6>xUilU?oF%H(7_cWA5dME(@N{=hAz%i@`rDJP-hgV0cmle3-+1FyKfFU~Vm++Sw=EhTGau6J#qGv8E3Io9x_I2U>G>ZI zuQzJ-un^BSPaUwIm{MJqQ&L@Ho^@29>rt?O(^K?)B-Y~@re>Cb4t9)wSan%WNp)pC zuMexx#rwuj`NkpP`HS_iKHs(zI%uE$i0ZPOlIl9jQ&-m`^!!C#$3Ets6Qm~A!}@&N z1*0qVQPpKRCDnDLr>;(eRl`pygQ1F#-nJ+zy}_Tlm(bXiVGb^U~aTePFl#rwUR zp8coCiwo;%;oh`*5<0k|{4w2LmeWe>Dnb|UZlAf0UU{${*5})fK?m(iA6H$LQ&L^N z*YhRl+6jf6{P?q+@}gp@a5?PpB@-DXFg4FmQ`@7P?ZfyRdWLDf!5HtTJq?G$v- ze(qDcy)37sx}N2!D+gVVMIk>P`R_*g$a+|xZ#xbhw4eU8>av`Y>Uy@Pu7cTK-H$AO zNNQp|tk1U{fezXiKcl)Vr=+@$_S98^EV+Gjqex-6%px{mYIwE$hbj(Wstzq(s$Vm++Sx1Be- zQlD2{mQzw)$F|V5E?6Hd8ZAll~o5|1Nac{<4qDN7l`5-*(p2m!47mmZ#|FoRZp>%dsx}wS?e) zVP)&teZp@{#9KG%M?GWExh@#Udmpp;mFb?|bZ@3-!`>!LYA5Bv>zd#E{Bz+)>M-Ul z7c1EQH0=H&c$ogA<6#PX8Q->?ud;szc}JmhU2ubM@16|@4P+0>^ftigOhq{ycGJ#3 zml&*{@qF7kQ)l;=l!N7(l*2T*y6UkU%BUv~olX12qoVo`eR_3^#Ae;DJg)vZQ(xxG zs^9Vy{rruPcJ_;tUqGx zu`rMAPSea+z`^tjhizfh4u=_VWqjM(aZo|t#X;TP90&Ye!KFuQKj)=aeC^h7>c_fm z{8r2JroPNqRlnsa`uR>*Tl&G%Rfp9-hk81*QT_CZYA8^e_5b>T@0=l8S+}ol+RdB#GGBv!(=YmY4r)t3cru@D zoAe`Z?x1-63y;%&Zj0Z3x&PA=lXctpt(NCaeVJM4H~pf&RjkJKWHbYwjq4geH|a;- z^y8sFxUn{n$<$mb=;!`_>5gyzwyb2`HABx2^QOMxuS37-Pplt2UF9_CN8YZTp+C4j zy6~Ly&phLtEvKc=I`^D#ur~xN!;a^Z>!!~CfUKsD22-z(i>BV(H^9U6C*@HFUso|r zJdiit1s=i4I0i#U1?zd=;ef*z!sm#r-<8kRUo~~+{zo}ju1Psmz}1!Ca#%n;-MfH8 zu!Hq9IM1P<*98we=E^_FYS!Ig>h-Z|>dSpo^;@2a^@FFY7^{B~^>jbMp&$L+{)5+E z^G1oyx?Oo({Z&(6?px4r`bGb~IN0%+=ZY!)oHvbJ-QK)u5qZ0Jt?M6ZNHm9jo}<40 ziqkKb)vUY0)azpv+ndI@YoOosi+(-}ZbyH1UgI&oZFxLn|042s?N-;{$CW`_MnB*0 zyX3QHUL~tpcY~?d$11irjdS0Ie$y}d!wc}hupRxQ?dnI~)b4ft^|NB|y<_xqzuEu( z1J_IKteZM~+bXsZ=F79NV{JFRgpYhn*SQEe2{N-nW zM=GSa@d&<{Wc_E;Q69Muyy{S~p$==`YB>%4v@3j1>#=-= z2hZD91AQA?@>nwQ8*St>_j~qt!aj4h>SX`yUb@Wl#Ji7p@84w|>!qD<+XbDpAN#)Q zwj4z_ZG2j?sharK*Xri_Ds*zWw0BhZUmo_P@D@7jrJZk^f==3x{y=qGj!AVdn)uAa z)}?z6I%zk)kLu=p@&2!!d!MXhy|nXfJE4>I`5$7On|hP#UNG^QhpkKZG<4E#h{!6guhGxu5Fh`F`O|*N5+)vtHWywpCNt@Q+ou<(O1=1sq-V zxO5LgC;b+&%yE9=`?r6RtYf{j^KBPRUBf?7-Iilg-DPle)#K8g-e0$`^{b$t$G6$s zCBGLN)@|)uEian-az9o5mS()zEQ|HLfz`^t<aU`n3Uu=M5d8~JR{eZt_r%M;9iI1DH|>1eB~#zX&!OM+C)N+1u6pe8u!_9X z&}sFLJS95*tDoOizyE@|U3pynOQyd39Q2!h(f?drwDa2C6;t{-ubFF6SCf9^o%-uG z;d=+`f*oD%2dB*(Z}>pv!26-MZ@BM+l9%<%=eGW!n?7T|00&dQaCkC|+Tk#7;xiB1 zCJx9uw?%cX3wD%{gJaU0Td#J!PPpLGJ;VKiI+(||O+i2H$F5f%map&#FGvEzc6cnB z_{_uB@>l}D>C?a?NY+E+pv^s1`*~itFTH2@${Xu$F!lPFf?gVr-Jtp{PtiXN;ce+R z@tKFM)!zyG#p|(O82#Cd>gT=66SnOgmsqTuaednq^wNIpM(8(ni~d8B=r{41hi#L7 z+TRHM!E?jLLqd0t>gWC8N3MI}28qSG8P~T>K`-scehK}o11m)TQ}DU1?Qh~U58EdF zu&JPtc6Lh}i1J8PitYh7@^KCn!m-bcMhqgRLKfe=WYo%{v%jvstzlJdUSD7Pi1~lrXpKUoF#}Uu2=dz5mxb0nlU*~XidoN*` z`v3d!`&566Jj`d?lJTqFtokia(a&>VTlx{t=H;^J9|#s~%mVyI4vFd?J~X=he{$5@ zRDX*+%xBw@@vHt8`VAM+&u3q@RvS~6Yug|3;%q{@AXu;18-oJ;O3=&I6Ng3hf92A9 zRDX*+^tWxv_*HL#e#1rdbIjRVZA@9N=|{Xco6s%@7I$1Mz;6M1=|6XPRR4wRE>-<4 z^3dP5CF5899rPP6qM!E?+R~4BHZPZD{Pzb7Hf8~S-5aChzw3yo{ul05QvEIRFrRHp z#;{|RjW7J2Az+mi9C-Uj`Ki|E%M7HJ-< zHl{4swm;&<*@Skk?N7gFsb2b5vCQ$m_YbiBX-`AXwq*ROe}I0&Mf7tH(AM@xJXbl+ z?GL}qv!nXcN9!`j;)SnY3g1^{-L5>Y{*tM$dOP$RE~0;D1Zhh@;<@sR{@Ck3_>Ds^ z{l|_`{roP)<4%6hM`RuArk!tFGWAvOfPTY8^oKtH8U$`jKjOLS5&f~pfA~#7Fa0Nv zRsFmV_uZM>{v+#HH|>1elButHC-fUGqMzTXYfC@kx$1H1hu=K((!X+?>faF^pS~H*+`#LKm4Ykm;RF{sD92xw%+oY@HsW>rk!tFGWAve z1pS7K=-(Yd+tQDCu6jg&?DZe~7NM8^^Cw32KjWZNRDX*+^tWxv_*MT5{f3L^=Wp<~ zr62KZUM@TLfB0oiQoXcKKUbGI7rS=v=cxV`dFXH3lJTql1^Nva(Z460+tQDCHZPZ* z;~#$G&`bNV=c#^Pi*>#6i?gzhb<@tbEt&eNe}#U-Mf9f;v@QLJ=c-4J6Fq}5$3OU0 zpqKmUY(BdEYx{qTJg)pD<5#^K`VAM+zgH6di08`h-2U)OJwH1BJ6@p6d`JB1k6sjh zPla{6^0@j-roQSu&~Lbie%^^~Yx^UfE5B1e{BqDs|LhA@Kj&hDSMGSStYh7@^KDC} zzG@Zv4HwbB4}!L(AMsrEILANyO3=&S1DrTn^>Z%rpEuumu*7EFt~{>(lBsX$Z_sbJ zi2f%cNIUwAi08_`E_l(Vr?*co0mDBVy8!=1=%(HLiqAuak*WV+TMB$%}U4;JxbklBpR5@^7v~=0+ z=gT_QPdnds#?+a<58Kc53y1v?)Ycl8iyWrGHO@x*)&)EGrcK8kfB44ZHywS{i6fLIU2Lui#G3~P#;t6Qj*lRA`; z_qv^iO9OBJ`!@6LirC*2KCLJ39iPPsOH$Ef!RBDH> z$tvoFnRk-`Cpt|0Te;coAl!JeY=>J4@fhE>>+t@YjoAsmapI(WBVL@1^vUmv>91x4N0U>>HlGJWo1+tP%Fxev zGX>?r>ycBxeOCD16m`(fw;eY1PW=Zw3@72ii)mYHTrTqHM!Yy1>09@R`hFnqMcUY1 z@b7$?>SmlJER(~xFMd*ZeaiZ2=iBB?om2l+4wkEM7(h^4Yh11x2gHlBkv`Xck%nLH zJm~+d)|EX!Iu0)X(6htqQr7LtaUvk)@5C=!`Jr{>@KGt-IQY< zak_sI-Cw${kM1v94w?@47wWM2S}mubpLUbmfrrr{JYEZMM1se#=wz7ZKFf8kdXvO&amy zY@|=_M`p%PKb`As>=gVve;M6hmaxq8%j5|=gu{sSGoEidZ0eld9vloG;qW>HwYA3O zB8Oqbi?flwj9Jgv++XbZr3?01w8J+=`DA{j%e;U8sYk2}zfVS8t~y-(qo%&{!&Ak^TBDgES=Lp+zQe6L={2}g>JorV7-bTdwIUO5DpG2!2H_aFMUd|>_B>;L~T zQ|H1Xl!N6e9NvJiw$`|8SKaW>MIH|rVOHBN?MKZ>>j9^9U@zm6X#)a9zf)jwhC zTiikUSl+_tjR-;wu9(tKJ_W>c*~&ax$BB%UlbVjJqwr7vCc3|*ZjO$V!@qoJI8Io< zE1#=>($qP&qjIoZg~OW=q#X{`M`}D*{-Rxv;2bCP%Ro1CpTrdj+s5;HW2`aMvw(IS zc{yIjej7gy$*tXTQs7O$;!euTZcpL=W*CtHed1b<5q5oj>|88=EQJZQV;EX+ip|$bV|8c&cfv_2x@DM%SA33#EY|$zAn2S z!8tB#<0rT-s?!P_;g?3+^*ijpxSs92RhRkR66f92=c>omKVs^fd6aUp+=bHwg0#aa zi+Ha5dR;W+ye{g7|0r~)AJqE~BMZub_aEN<)`{@?nDx8zx%%^_&Y4Fm2g_AByfq02 z#B=3$J$K8n4(O$S>G!Ii&mAv3YE<>N$U}eI=8a$ZF{^>_T53Jjj$JIY(>YIC<>bE>a|D_4^=Mm49-*-F=BhD1`Gv4GK%7f!! zzhCb1K3PW{wDWDpO}%rE2M@zZc)T4!+Zhje#BRspp55q}#yaPen;(>Us{I2mZ3cm^H<@MqCUD5Htc{1yE<#F{-nEDoXQT>*u=$}lW zzkqnI{H^Y%jKY5ox>;}ePs)MU4dlT3UHM%7leW%X!NKqm4won3F!2P9=gQyi_4gR! zW&W%jSbzF2@mxBf$CcmJKW*yn+D&y>&cfxL3AjwPsH^}J+AXh8GaMcOaJk|seZoq_U*s!5x%#?x@qUzE}HuCY1MCeivI9IKM358 z{sr)K)zj{NQbxRaaA4fZ-<1pBXZq#AmxSd~5AD2LaG-sDFK{t>gv)zi)D{;LpLy8I zJT-Xy*~EGteyMw-`$fk;beYe8_y6MY7f3AD&A8qz^wK`Rx9Yb%MSlrKZRt1hnTM@Y zKm790OZ(h?s-M>zx81qZ9kPyf)6TnvUfSpPfqqlB=zlMa+R|_0GY?zQFE9AonDg+P zf?nEB{!{hyJAdi@U;Zpv$GU0f-9j(z^G}3+Q@7|3CwzgSt(CrwtsL*R~&pd2pKk4mn-lyi_SAkyI&;DEW2al`5zrxH3 za`@S2gh)ZRGR19fIF|@7U(Rj%|8+2RgPn zfa`6JdBhq1Pn1XIzq-u()=P&K!}9@kFrIIlf_~Z;o&+97hwzw!k*$@!jV*aBnfQ%1 z@>!n4Dv!P)!C_-B!haIF>0f+EIdEJQ-?US>yRv@T`Lmv)7xsD8^+ z^nV0KZRt1hnTM@#>I;5=!^W(_ZvuL0Kfaaf=XJsBFZj|;vW|7r&bRG?UfLH9gnm=E z=>I5;Y_0TdY-`)!#Ba2b&vIOpA2PNvtMHqHUiy`{R{cCLeCf59gy#j;O*`MV3wmi^ zS`YoEZqffS7};9s+t^Zn8u1#}HGW?Aq+t86@6YsRgD)Wu4)$dSdb8Pq4cVTap-g{I zwy!_iKhQI{p?6@*ll!tq#Bf6WnQfx`NqXBTr-{$MHRMEnjWzgu9yU74PX#B#PdJ4y zbO%A(;gmx>S1rP+XMNAmK>vpRzJW}(x3@PtG>{qEFqj?c8yx5x3OaiG2L`iS4vgj0 zh4_=;!aT+8loOAqo!kB5*RqcKXy@CG86ArmLLs0Bl5!$7t#ptqrCu%~a!f&Bw9 z``sAgk99`(yZrW1PG?{By{||O)aR zelyTZ|EY(o{>P%@sM1?sARk#b?R?u=Q(vlI^;@2z|5FHRYmLjr<8ui-<7}kQsULnz z&`bZtN2q?@w|dhrpEf4zSU2r_+gVdzY5@98zvvGq2tnYs^n<6X9;bfz4et;g|CvYX zatZ1eSyNwX2>MOG=>IH&wxu6DUG<3mo`D$s@GC8eM*hl_b@Cir!f+Qil7m}Hz(bbqK~ndi;N z_w0DR#)03N1aczhl-t0lj!}1j#UqDn_Yg{t&D1&dDjr7U;1U(tKv!#DF z_6+vYPdnds!PJ>OSUFg(!eItMZLM*+Y8=2d&PMuV9^aQ~ zp2yF^ZytK-UwN$R=R9_5^YAIMj&;+{w_PyxWuK<{El<(^MFee2KX|(836GOQ&Bw`E z_@y7Gdg-5fye{)RG4Ypoh35&@O*`Lq!PGbYbm%wzqW?<>+K&DX#B`(*Z4V> zU+?d^BFWZ;dkm>E~9qJkC3+61D{>)%7;a!H`5_NS&$6po8JWua; z?%erU8j6dO*>F*!R^anRkGQlv+ zWHZ_Rq29s1zP`bpY|mhTuXoFVJ%hF3*Hlv$c?-Kl`Hen7mwEi&z5LDay#?xa)#>V= zGWxQIC_lSBgx^;Yq#b_cVU6d?A3Of~*KY_24Gi`VWP_hX>mMBG@9!B3ma{{_&4t0> z9!yU#Sq{cuZ+{J-t!W&2tKh}_3%f@7z3r0cJWbY7H|>1e1*0!}sOq)bL-<{dptjby zT-<-l*dB2<(&w5d&B8CcTXg(%@2<<7C!g`Aoo|yktXn>}^S5B?%O0lsEl<%O4%8rc zTl&G%Rg+Uc{EE;^|H2-spY!C8e)lK$$U4?dJKuJ})R#RR`c1#+4}Y*W2;7!_@O0JV z)DOQ3^wNKJPu2e@blmWX1GbZotebYe?SiQ(1QwTk?T*Yp?(R7fgNGBcR{(i~esQY+L%l(^XM;{TK5bXBK`r z=%s&lZ`IHHB>ne)CA<`7-L&&<7fgM*Bcb2)i~j#X(026Cfv2k;`TaZ0lY@sC^@+00 zF^f1Q=x4l%eUu011HXIvvFl|WbQpBNn<`(3joJU&nd?Yvv)r~T+r%ER&%9^sA{7`DS>(ZpvS zw(GVH=E=dx;6&NRo`-*CU)4>&^nTHCv9NUYi)9__r=4%x3Ei|GdzNyrT!q6mFtWAM zx3T58sG9hVHu72S7X%}sm;E;O0{n~6O}oPW%7NGGyIgcqc;AHe)6Ta|K{xHko~;}# zSK$zTp*AqIwbHk-t#L5%8*SvX*vYRA+n9^+D?=~+X1Y~Bua~+%*EuZfSU2r_+Z6QD ze(Y$~Z+VLTGK_4k^lfZw`c3>s8~NqWi%TmU+HRWls)wQ`T+cw^~j?FYQXl zK)0~-BW_&!TO%;hTuLx|Av9!K0t7PAedVOH(7(}S$3c=6U=mn zf~74_mfhuO`r8^7p`-AmD6i2c>oR%WdBzJvUew8WzU{ElQ#lsA3`gPhT?DnY#^vI8 z89}@_8|f2Xee3%MdwYU;Y=2)*Pw;>@cn&_;8~isEJmVb-e!F{Upm#76Jg;1iR~Pck zgAemno}#>XJ@WZy?0=Z7qfXlSwgsc7dYtmI{Ds%|5VRd$~N1yKov;E#+3=IWO zcY{aa{r!FYnaogd11g)zWCu5F2xhZA!SsJaFuH8+9OCB=jE<}9dR^vqO6Sd=4eope zzklDN9#@?u51we?$zbTBjA&FeAh4JBkOkMarIYBed!aS-}Hz2>${8dbSndd>j=@7Y^KIu%z1ci?n112$Qv_{?M;Uxw^|X4Adj|ex=w_UmY;;_F;lYk@ zT(ExH`L+wD&g}D*gXJn5eukiJaR66WJ+Ak-XW`emA-Z2IVVUFLpz`RyBsS}I<#F{d znEJ9WQ2myt=)V?0+R_i6uKaTRhCe|TPC-L&&<7fgL)CquvK z7yUm+P+MzUE}j>v;2CEleR>`3`yRLZ{?9D)JUu#Is#qqkf1JNx$cs8%b-DUe;KTK$ z7l9Y^V}H*r4f(uZHxK8=lk4lUW?E%_KYa6{4;f#=iLX7{P_t|19jSZS}hM7 zJ>^rBm*p?K!VBCWU^~2Wi07(f-IK%nC4TR92e@qRF2tV)7v`x9D<>X@U;L5hhTkWl zKHB-VV@5}HlX9}$h12y2YHN+l#r<#`@#1WxPsf$-d)@AFHH^z$Dlf}lc-?@&ZSg`pS52<@OaXo+=%xR}VXB|=xxtOMeMQ!>Zrb^_ zB~xE@v+B1zMgNTm+LnIAbJgS255Gm|rT_fls()v6Y<){Ad>w;z)6Taonfj_PhJM3E z^#2k;+tQDCu6msM;g{X0dO7dxK0=r6e3o^)^0@j-roQT_&~Lbi{_wyQ1Zqn^;<@t6 zaV75k?gIRZ&`bZqk*c5P;e&<_I$PGUZrb^_B~xGZH0U>6ME|c4v@QLJ=c-5a$GzWO zfL|GUIq#gwseYbUIiF?St~{>(lCAG_=r>$M|9k@d6I(Q%D}VhtZSWTFGS6uXh?6=> z_1ET|&(dX{KRKW6fDTt)SO2uBH+2Sh7*4|D*9mx(TGUma-!K1ucM)+$p`Y{5k!MH8 z2j{ia;nMBupEdP%jbVG5e&O+(1U#m|*OkB3``wf9pN4MELrX_T#|7uNwfbEN9sOlf zXV;m^!EzN2;fusUoOX^AQ{?K%?|Q$x1ivNdw{O^;@2z z|F?+JmVWSb6%ZaLhnks|;FmjA_0m6koG$Y`vFm#e4$l*;n|8i!+0>VNDfF9u(SHkq zwxfRzJYDsyJ5c5yzOQp1A+Lgkf3}7a^2~q_^G%IJdHt=T=T+*Yoo`z;ddANJFVio) zeutp8*0@}phjbuboQ?DeFaOuK-MlK?&d*UkoQHNEugg3SbAC&muDV?PX`^TQY~^M7 z3$I%dq#a%v#B=4Bd7Jm^+I3t_$G9cvm;fKnN5@Z4UOZ28o=cssx?KGuM$h~?%FFT> zUJD4)4zE$fbLE%u<^Oti9hj}5n|V%DKAewMu}of^=TfJuE?0k%d0;SquJW?{h1c(4 zV{46z&HZr{@#1Wx&o$4ha~zD&z0Y)AAXC_OaJ-2>gRhN z&pkw+&#-RV`L;z<-~4&dZ@7s5+Yz*_?T>h_dcx;3J$+5b%RKxt&sV+lPrpEygV%b) zzb72}tvAUB)~&t%|1X;Q=Ff+I!$tJpfv|1qM?6<6noR5yaQ1$aZ z2j{u0+m*-FUo`bCUI6`ui|D^If&K#Gx$^tIpPfgXGW2(JYn?MED-T}J^Y_T8!l`_88)%UZnbK^U+hHTueGzt#KM%)A=Dc)jR5|c^fzNYUze}&Hf5z0=`ATd*(=QzUl!ODgy7Gs| z%faR`HbKA5s+ay%Ec1Nv?~h&+o-b;3)6lb>VIJ6LU#0pjPtpHp*t9ba%H-*&XWdgB z?A^=`Li`lAkWx~qrCE`>N0u#;s!mxQm3OVXZM29 zGxlomGX28qFNk7mjSJ4}>nixi*+`%8YUBN6C$CxLnFAlrOUtJzFP@J%-=$7hU9SEV z_;7vcBIRZI3$MSzs2yHu#AAHh>iv}9YsnjWgZGg8`?A6N@4>gc`!WLq8-|89^!El| zx!uqkywx3iy|%wbt9g7aLPu^(bbMt`*JYlshYo(@v!w>=wDq)F9yWR^uTfr>zwo*n z!P?<9f_SbvWPA;-?;jcn-g55=UP=|{Xc z8|ib+_j2&dpQ-veFU`F~m%9*<&vjY1E03$cVCt(Bq2F*3{eMFcyRG74*YqP^oQ?E3 z^}}xldO0thda3HS^Ig{M%H!%UnEEQOgMPzB^#2_}+R~4BuKdC&?zwIbeoN3x|HZRZ zKhMVpUHQlGYqG4HcD`-F)K_^u^cyas|6T-bOF!bd>Jj~M&vkR~%btz#kNH;jIl9dA zE9bkc+m*-FUoiE}zXAFU7t#NZ1o}r2&y~MEzgzyfZVquKpr7;7@pF|2&!3#{Qim(A ztG{UKU3?>W7*4|Dz63l9i08`h`&>7VIP=iYd1<8(9Uq+UQim(AtAEneTYZ!AuzZEb zKNIj6M?6>lR?l_E;Gce(>gK#ObzXE_aK6j>UHM%7B~xeh&C0=Y6%O|&;edFq{I2J^ z1^5-9m-Erl^Hsl{=dx~B9#?bE>a|56hDi08^59w%d->lWZwhF<#5T%h`S zp4fG1F+5MOZrb^_B~xGete`5-P1IYb0Ak0eQMF zR6fkt_3|jMzwNKQsFQZSZN=yrxdglnN8$AVg4$Z+a`C!q9{l5Mq)&LY@m$x*YYKTL z!H4tF;wzLF&%>POQm3mfSO1dHQ+%89viybDzY(MzUY&^N%FpNEUO&TiL=9Kd7@xy- z?i^P>oR2PHndfQFbE(r+m#e?q=$W}xd0GC#>%j!PvWVx(FXO9?=ejjuP1_84imy~& zoR1b>rOV{Sc`kLj>T>nxjh>meD=*7mc>N~{FT``@cg=G$@T)*C=cBW)R{eIK%eq~8 zT>W`d-^^vI-|`gw|4pJF@m%?x`r+4g5w<_(U7fGdWjoJh-L5>Y{=BJg<{i*)xQPCT zlITY~SAM5{_!Xd+^U=}Qs(w4qW!-qcrqC-fUGqJOId`g4fqs>1iVZU%93uT%Y; zk7i%5%RC=&o=Y9BysrK+Q}5inz{7A79$P2ikw-jN{`$Os`RBUBh*N@o&PONS5FHk8Kk07)3l+{#MU*N8rB*-JFlkzcD&4IL~GMu6(ZkqN#J? z3guwA3WseIa2P{8SN>Mdb@TAgzDad+UfTU;UAFUG*6+&a>Yp%mE?lV`ELY*MT@nt6 z=gKd~%edd&8in5k^wNL)EvldAi@)yt@bG-Wx@qUzPMG>qCDm_vivEWs&|i9w#&gx< ze6Ab+yHml7lRDu=DYdYp$WsL$u2`6e^7`J9+lRcUlXkxCtkE<4Uhpy;g;!?+UKQ|n z)zj{CT^FxOa-5;yak-Jp+a9)~ydz2UFyVPmxX|vrXF_2*1|Q&*{e%Tx64kVHS?x$-;p!*2n4IWL`ihw8WUUDoZ&G=$Bs=Mv9tw8vYgN=8D;OMLAr1*JU9G)=xX%cEr><{b6u0e1tYMq9>bE>a|DzJ<&mx{H z|GI|-&uumyxMAS%BSI594!Yq#0^N)=d}Wlw(|W!da$xz@-gLM`3jH6 zB;YZEc&>WZ1-}v=jEfowJ1&OdzX;uoGhb2;yiWMRt-axEwXC0ZzHPzOIsb9xV7Us1 z$0pz~ig>PivrXF^%qTji=R~emZ#`{d;g8aTmL!!rty$xUC__-T;&5%9z1_ihbynEf6~;uI1L_#lknI%2@k|`)CYB$=g*z4u7s~`v2NP=wv(p5>Zeq{X~+@DFMo zez@2mMa_H+{-e;%6(b*ta@g?ZABP-RKka^)tdck^~e^3wYeA_uwclYO&i{&g_c1ywqoL%+E`LwUU z`M5C+zZvM|d2i}ts-M>rJfE^|R~}dYoT)GS1=VkPivHab=r4n(D}Vht+h9+B!wD6s zYHrhv^KsSB^IjFpEF~Ief!z}!B zpNQ@k*-z>+pRe3ges*|@W&Moj+b)_qb6->rmaA~sGXaM=aCOzQZhM`71ph|G;qs3K zSPo_QPeM226sMyccDelMkOS+doo`z;br!y)94uGikWRp130z(E$iF|)bY88UU~3;X z24kjQKv_-|#9smzo(~s4rJT6m@H|U>u6kVkUEsp?<6l-zmb-A;D*>kt#AAHh;yl}@ zqotWc74_vlt-5(W%zj3fd0&_FRn~9wv|3J^I;Xy(94uGiuy+Cu-H7L^Lw?`Yo@Z+( z+}a13+3TKV$IBAxuYe2l%zjom@x1$&{kvym9re-9x6K(HQ(sk1mb-A;CkZFSYgLcc zpN3!RbE>!I|9M^J^Rfru`-Sl5(O7rQ&htag)K|G$^;@2z|A|TTBVMa=n)Jgj552DE z1UcA^e<8|gY(|$kzkA6?kNt$yKz*(1vFi&)N9AkaWcUfE{St5*K|Gt6%TE39n}J^L z_fua~{W~GRWv~74l6+*{jO*JLOnsGE)o*!<{{55aM?6wgppPEB0RgY6Y{PJIpj{n?OqWbTk{uX&$`3uIc@(t)W zTtxo?N%SM0E5B1e{L0Wv|Cz5w_5YFjTjZg?Z41V)@;}gTxQPBICDD&~HZPZ*`r+4o zb#(i8eJ!g0&(z-{5A)f!VEiiIgnq+C^glU?e#EnRx$M*rze(t&eQ{Rx?~0Bue)aB4 ze}Dqx$!G^~*1nb*!6q zzHPzOSGflI4HwaWU=sa^=c>o4AAZB%h>riv|LF3b2>6%7jz3pEvTj!%SAW6OSNS&d z8!n=MeG>hM=gRNY55FnsWu24Xbm(u9$CbZe{3>PWH(W&jQi7xeyQ(7w|~cXb(!bCf8TTS`z1E(cI9#P7fgMX??b=gBKrH1 z=tn$Pey4u;jX^K{^WTe(|CvMfD#$w4O*`MVVCt*<0QwCV(chm$KjOLSaq5R(8G7kI z^L^F77dozcl>RI<>!zJ=TQK!iehB@Bi|8Lnq95^G^@#r1-~WMM_Yb1uzw3v(%;Wz( z+kZX$8FAL_%H!%UnEEO|f_}qA^baP{k9e;9&g~Ds3FxK&_>WZoF6el|ukQS~d}Q6U z^KA>JzG?;f4HwZrlte$`x$1FlfA}pxugk6gyUrg+$H@|w`Mlz5-7os0)Ifc%dR+Y_ zqoev`a5DUa(}o0`#u3kzU-b6{D-pV8R)AmbCsF;`pXxH-Cq3}HXTL_ASa&Ue=ZBK1 zulf_!Z+VLTgOcb+JXblc_ks%Wn}lBa7k{Su`TXH2x8GWnb*!6qzHQ0WSN$pU8!n>% z;3WDH&sC3X|KKrh^Y(||JoM7Pa&2_`pRv#Pbo;l+Lx0L<&~Lbi{--6;k9amO zm!10Im%c7K{!>5K<;Nnxd*AZeXUIp^&A7g8$<$Z97Wxer(f{-$`Vr4nkLb?^D-pV8 zR)F6a^m0XhPW1<`--drbIqMzaKRd&^Y3JLPOnuespxm-c`jz*5R6ek7?e+hE$<$Z0XL zhL3RAn1I8?4I0l?Px#(^Ur%O8ZW;%FmcuywGrx}R59#0NGT%cu{=^er6b3;3;paB~ zH*M?urPgh^3Wp<-aA;AN>v&j%-vsnh()i7)KY0Bq{Cm`Q4-Vdp3;s}d__>Y$P22iz z!ge$LqW{Pw`difH)DOQI=%u8o->UxLYZu|)^KSincs!oTN_9~NE@b+B$4dbZQHzMG-n z^o#zZljv_zms3Cd%Fs(WGq*+c@BixA{layun}(k4w5{*A&~N%h|1nAQx2VghAAU>F zOF4^wQ2jfgG#_<mnxWr^Xl1{rM#NTh!&$55II(^-@miZ@SFq zf!80~sn@@(n}(k4w5{(>=r{eM|M^Mux2VghAAY0IOF1KdSN-A3QbFgB-}tZZh3i;1 z4L#dwTi+j{-}HEN`@>&~Q?3451iue6t~yP>aClJ?4&>@6$2ATn z;8%iPx=;OE^>ZGSx$%ABS1CIGgzZPe7A@zIGp4?&f3_FLm4^3eOaIb(Cmi*atN%Os zTy^;N+wte?*S6j8a7PCZ;(@c(U%c=C29MFdMeBGpcDTO=C*X6o?&w%}++%0=xwxYv z{jVL+s(ogcM~2IzPtbPq1=?l~($@0I{9XNR|H6>k7dJ=!h947MF7Kqv!+G>?9bIqZ za=Eml+RgnsKL1$1uJ8Jjt}k!&i<^E#)ULRlE>{kS_IEucx}4fKx?J8Zy3D#Kch&x- zXKK4}vbLko!ty@a(ms{b<@rpspX)Q5w7>eK`1RG@wZH3m(e>#)b$R;f+7=#*_AqVd z9Pgz>4%N2!kNE9J|FP$*UFku!n>s<4 zxt?w5aP1$)@o4z=XxzmkqJEtlbh-E|wX2+{%blkn&VEt*rTf(`KdSw?2XuMyztKFb zXLc~^KXqrk-CU>IEvB?h^=dmgpzYi zUOW%+d}7Z>UH{ed0N>|0<_%Z#)wVFRJq|j`sdbN;^TzPK(c={j<+y%I%)y=KCEBs= z#06Fs^|F8191q#=YI(doATW?~;kflT$NBXC(s|caPxSf(l zZ)$7J$DQ&ypZvga%q=bTHTEs{xf48S!|NKGSI}T4N7JxvxqqTwIxU!d>~Ga}VLzl^ z)@}8UY@>X5-M!T*j}G5QWPIx5a;vu6?Ekd4d4~s>VDn7?0Kc8&+|iARA4)?ZFK)~xo44=dRSMJuI)A6 z!x89!9q)RFd}Q6O__n{MA9=ZcYDx7s<)wjVOZ^KE^VE;L)RRM9R@cZQG~Odn$6M## zeYbpM-Ja!j)bt}S{igl}{e}zI`?l1ddAO&3h@k4==bQ zVO%~r)9|Ssb$?~O8xq&cCz2XBYvLZ9I4+MQ8h6yheP-ggoPlZF3B=|1(H`9Go9FAA z_WnQI!6TRY%_1(x*~c#WYr=8HD=v+@U^u+~6*v5;y-L-3xPwoUbh&dU9SZ9AM{VAr7oGOflgouC>G7uckjC+; zLVOpIua*78I;|^sK{`yyc?mgAnY{Kq!8%*zX|`b4Y$uPiE7`{K%$F zQBT_KbJ~{E&pc;Ky4gP6C*S|!AMFcIR*o6!rNJ_-_-3{OpJnW1)g0}>k^J}^IdAf= z4#&ec9(L3*haA1>@S~12Aju`lF=C(I(4d+2g{LUTaq4ZbaeWlu@vZ$hX10lrM;<50 zamwUf9gZ>{qXUsVqWnU;bl>{^OmDWguYYjx|D*0b;3GN8^#3+Eh%94*FxZR}h+umZ zRy(o*&w8!37B3XZHs;f)0bN~PH!4vwaZ@u-@+tt<8-J_<=rp8QWQ){MyT!L$E z$TT%)nm0AHv^H+)dscv7ajeg1X^|ld<&7!UUc=^1&8^K%o6?!a#>UL%P3g_8Et$$AAj=kG=?3O)-e8c%$)=`gJ8`G_gnbu9j z-AqH{rt*(ghHv`L-7HzmOat!X`P}D8@B>?_{Y1;op5*3pz6R$p9JekIiB#~ z+pgVvcII|Q(wQGzNo?3}Sx+o)PB%2RW|~`?n;M%lWWd-=I)G$!>!wT->4?^bmWHOj zbDKBGo`c_OY3}!$qkq&UTDJB!3qIC1avwXPy|T#go|f%=u$zzTpi_K=IW%K%g%u>f@gZ^I2ro~^B~xNmz8>}=b!8OJKKMWkDw=3Hl;U* zPV$z6pQ#M@v*hRxElta=gHIf1{O|N5v7fO2!tdzSDV!?#NzOl=@)2|?l8w!BBf-CP zEB7x8?UY4^_q1&06u13(1$1H@gnWegO_x${_56eU!i@x9l>J&-e@Zo_r3EF>XD;AA zPC|PzR{M#ToqUv=kEuuN^AL{Db4tC{@e!>Lp*Dgq*hi#KHNYYRDGB<_h1|y_M_*{A zwCoc2L%*>6n|=)T5%LgxEGhL?$48g-BtEYp>rScq`reU={eyi^X*h3l>*ki$rUtT% z)Y910uxWETL;glhaCLBkrQ&rKb)`Z#69%8@w`T|?y;FH;$_GSxs9IunXGhcy0NKobHnB) za+02IPPdSSCX3(2XNqyc)j#4BjcpEm6uy~W3XikqG0C&ub;-Zfa@Xlxc2gY;M`q+}yC4e9mkp z>wqm}skMPDMv-)HY{uTxs-T|ri@5(?;1do<`-zsFdAytdnJ3_UhxyrdL7r0Tt&acl zx)N?8_=5eH_0mZ{DGK_`7VhJ!qc5~pT6Puup%+{b!ouM9Q3r)BF;cgx2m(24OtU5DyW>aCuS(z=q=PVgn_qokLN1bt>J z_pt!&m6)ctv~1ytZa&tga6ZEP49;U`lzNZ7k2~DH_@d^YydXucK1(Z7ydadzY~y}rpxqk()URmS>{)L6 z^BU-s^-x$x=~C*gqMzD@0PscQC+Nw-R5LmE!e>@cuKiN(=M=PCHBa-ImYqJ^&Cm2X zI6q;3hQDtyuhd&DKViX1Z65fd`U(0}1IbQlgamzOJNI$L(HB}TExQ8#sDUV-C!d6U zgmrp2-UJG#iatV~p@_j3jgO#Dk*sV)g~$ge*R`GdnSyq!Ld|Ddw*JX(dASHWv7bX; z!hMeIO1;P4PqgM#ZXNg$`iOL?Mszhe^e_Kx?q31gStgp_(7N*VZvNFg1?MBIm%?#- zTB-Ng`^V-n$Q-$)Q6Hmv*-X&qpTm8ecl3qUNz2ZIKXMS7_l2ioA7LI2^T!pX-YWSR zS?B{l!aNl7M!L{PZo0{|l7+nH)=gv~k1X(!vu|=$iL8BOHZ`Tm($i-0sqblYf9JpE z5E=p8{0{E(x}$HDK+D!W%`IP7KqvNhm?yz~H+9etBD8AxtS<0@AF9t(M{dw-YH4gB zi%ZQ-4GrWjCvqcMOC$N;W^$v`=B7q+cUfagn%rq)@p)z^_qhxF5bd?S(3mEl?&fp* zxj3IypC^@itK@Te!A@BEI zO$}sSuN7xDaF=#*zn2{Sqw&$QCGb%VSoyqo9`+mN1+;&W8Y!^utlJ|lzOY=ySzY$8VSBAzRP-P^(6E$bs6_@-q9CYDXnWB{6SGf zKXf$ceT3uSic)VCeGC`qq_8bMhI+|K(5LorAJ-jyp;gkd>)?+RgYNBYBlZ!_3t%3R zQaDxgQCgr2BL`nJ`6%fnBSldtm)gty%tE_EwDBD++ur21f3JZ~%oo5%I6ufM^&Wda z$@3*mjmA67z?aZZRi8pPR)9XWkNY?c?KQd=ZlGnSo85d&ZNhm8*F9kWUQp_-mXGSf z9{8d9#~1cm%8dtI>T>SeilYw{K+7(HA7!HcO`!$*2KSZ0y571{Z?$|gE$o3Ws()oY zz0<656JCT8o=^u;S8zXTq1}30(6_YCy3KBRxClD2Kf`${?9Umc-fH>@3nFskY<_~C z-f^bha0cblS8_kQpxrXu@Sc{o`!oFA(kZ3hs`&{EbxIq-mq>nsKGo0| zuHJ|9pG+tBao*7vS}m<>9{f?_P(OBDfPI9#1V2}ldaLOpsuyq~!c`w0HQaXY1Os^z0;K?;0P^AYK#CmBJXc^>yM3+>f-p?*cn zW}o4 zeTL)vg+e!{)LS*5l?5sABjPh#kaB;b(d2Xf1>EP7qi@t68dL2>Zuz_dI&s`reXfOm z5WZK-=kfxRs25&LewX!hvDNJfM`Ss0XI{wt?gU?;V#_NnJDGL!yJHK^YdD_4^LCR; zz18wtUSN`&3cjfME$fNpu1`23&uKltUwjeweaX>BD7y}R%0X-1&s>ashvOgIzgkl2 zt(Ncd0+Spz_@eqQ>*ce5(3f)D$1Jp0h8o_}ve~U}`MU->F=Vd@TF8pZi!3 z?bX|XzNKaBFLleyMbL@;TwRyyQ0lFgk521S#6NMv*(PKF`B3(+hx=E6cB(?nXIeJj z?&e?ZcASSWuY&skrj>fDlLNmYWfN1^>Xmwi_TBb)AcF!iAX3H^m9K0XtxYEyr*Sr zp5vCEbD&d><8a?uy;5)0{Dk!;rH$ZA#81#GPey{i_5k;>1KO)_bsuTjjva13u7gha z2zd$fp`uc6HGPCUliLWs=zIh{eln7mhH`az?&l1&TZS9n)3UQW-TZ9dh4*uqU&3*G zQK`3Dexh|Jsh!}9>L=2pCnR}cC|5VY{akbOhnA*gOW+g78UH)K8~X`)34YcpoND>$ zv|h#LLHq_P*9RoG;oI}e$NRdgxX&5z!{}JJf%@Fp;g+{`mtmjbcn|lPbSm{$&1aYO zDsi08rQ9EkH2K_qko!FA=o@vL`n(AK(Jw6jruNume1w&Cna{+&(-mvtY@A( zJs62B2X1kY`&|RRDD~?;(z5BjZh0N-!+yi@?IHnAEA>{(Z+ZPmZX@`j`Yr2I?hiyF z&uKltpBv)77hQc6W#_<8IcUxM_RF#Fa2(t!w6jXR)$(0lf0DxnUsT^^y}T#@`juhs zW69AMS|=@A0)ONnH1B7w(EA9-!8(OgO&`Pcr!a8vMdxFvm!0Hgq1?&{_cH_S4$;PU zv~2cDxA9;NbYi}%u2*#_^;XkQY5l3(R`5mVr=*V<3guP`+|Ma!cbRN{L(5Kgy7`%Y zF3wMwm%(}Myi#vf{3Mt9O$%1w3-S}|QwM`U!essrsZOlv^9;e$G4kL#w7`7r-Ye7Tw#f7hyl)_k)#(3=~TDB(VmY?&W6Z<>lCmet3m3ph{C*+&d zO7KPNC+Ia#OhUQf2=}uC+AXn7Z)w@iE;m1eZhd~j{eDHI-m3YD7NWwIf-ez2kv`Sb z5*A_apj=In`#J0C4=GK{&Vf$~SN)jZkNt$>ILwQdlzOY?r?PMbenfoaH(F_*{L5_G zOrF$fY-yp7NRdbX_>+Iz&<&QrtvSklE;;%}eWYb;d))GN8Fb2VAI|S0sP$upPaXQi64cy zUv%`5mZoJ(;3vl!|GU_aeTU=R7ExkNskdsr%L`Ic^x#V*&t-k8<-F$2o5*0Q5^QkDF)r!&H=rTa6DX5 z>aD7e;eu2-bnr#%W2l#$yG}=(yZ)NZh1KmI&r*%`7X>WQsB2}QC0nv z7NkV=#I~wH5SS(y`1~n4(%_K&2MPg&Vz2gu7gha3VxR7ze>GT@wKV3GtoL0 z)}tG*%05nVA7`PxX8X!pXxZ68Hy<-Ycz=g=EEqqRlzOY?qsuxL_0MqQRoTC5xPNPo zeozx>*;Vj`eqs4HHH`g(c^0f=)hL{*`Bz?-!ohNhe9`&|dd-bjP;TXw+|MGkTVk8u(z25UH$PK{ zaDKvmeVTyJD)m;+Pgs}2tps19eu5s~cm?{kS8*Sg9DSj+(y~k74-O;psW6Itgn2#8 zi%LqpRrL|_Oo|$O(fSB_&5c)3uJmf|XDzf_Vw>L5vUOu_dASHWv7bX;!f`yK)LS(_ z(Rx(aQt&0>C(=i6yn=G2*Kj|(pxq(b_>Pv%kGuI)kW z#;c~rqU2oJ=WDso^Nzkz1TDJ^{z**T+v&sDXE@%&^Hj@9z18#CVf_k@^NDV}()*mc zj{95(e(20nzN0>8j=1G>P0{XiMya=IK9|>{aN{8VBI83@pWwzTY&ok4_#Ln1zE3*( zNDI@l^WZ0=ng26+6#EXxxhcvR+yo0R8;yxsL^Cuf#OHrDY2* zcJs0BB{+X!UIE9$8KvH;`WUW9m75B_XnhRzl9RkBl$(D8_jAF~A6lB0T?C&v&iLQL zOR=Bo`qipZZ&m%2)}hn}fInJarE;pVP;UN>+}9dtzgmIjGc8;9GPgWk0G(m|Dx=g} z6<=GLldWH2J^H2kvX5`#K6XKSHNL4|(Xw4Hck^)_bizk<{c1|7w`xARtY1<8#QIf6 zF`?|=H1}@~+NtPtA8FayNjLx6ufh8_%x7W!YDuZLYW^izzhZePuV0z(!r!FlMn92W{^fOE7Rs%@jr&;-?GDk#ceHH!TDSZxfllo2FmH!-tPZ8#s`=@%j>YFg z34ei|Jn|zgWR-n>JNLN=ei+>iH_);(Q*J(YUWfA*j{9(b(2P=V^?Y_%$AaTiqF-Rw z`&>K2eO`6+jk?YH=(TP>FN03xv+8pI{UExrYCf0Or9{Qz1@bR4A1LeHe}Nr4&MN?Z z_MP1KcJK#>q5VY57GLM)d;9Bge#1O$iy#-2daLHUye=iR5`2mHF6)#061!qP@C)za zzArlZNJFG$OW>yzv+nKm8?f(iJcRqO)|7gy=DWNuB?S(?M0}U^(jo!qXWz|z%s_i3 zrs*v$n|Y&K{;q;fnfJo+uuG}8sy>G6Qst(CFIpc%z2qb>3gu?6=YCE?yUS$r8(Mbi zO>TZ>rg2`vd>7^wb4tBc^;24pQd}}dH$<#j=isBBAe)U*;RdNv)sh8kMHF^)NcpTmNRa{9FQ^*x%uJ1?yQI zO1)L{5tdbyHi9oje8fMhOEt8e+q&rzn0wGRg5PuR=l%uIPSpU-XIggMQ9tu`>>vC-3;eD^O5s$^ zKay8Dscqm##6PM_wVv0?{uFA^W)cRJTl^sRa|+t6@O2+)+36WKKeO+|c?shq%!lTcdaLE< z-peoEwR_LbEj!pR0EQU~zNq=B=u_$Q()3?shllb@AL72QIQm3=re)W_FZzY$-_*OX zui)pCp^U<*im&YVtak0=*O(v>{tCVzUy+`yQ%glazw%-3V;b5kX-scv+4Q^J@^b}r z$~*|h%}%A>s`&`>8l{ooOT=R;Jm|zY0P`gHv)Ogf z4?L`(Dn8@ilM*%a7w`r7jPp#hT?1c7)65~5sw(~=7J_aAg`3mRdFrH2- z^;XYEnE2pkf-g}YK~E-1Ee*};ObN=>e@g8CuKtkfY1ujO35OH;)cz6dC#=80I_8p6 zZ}t3yi4P7Le2MxA`V?_9oGF1mbA#Bw9ets-(y}G+2Zs^)H2qP%kFfq$r*Nw0Bc3RM zA5s6Pj-8~Fzv_L7@$VUD=eds=Xm7-c=ohrk%$(c)y$(7tPQrC#7%w}OdaLIno-mnx zq`L9~QhCA@ebYwrv^iolaN9r4eVznAqP9l9p=D=3=H_$zzv6rapDz&9S*6~p`COhD z;pTxak-RPIY3?>fG8f7fZsdNhIr>9ur)5jv6AmZxY3bwGPjwuvRXA1iQ<)g4frCF0 zUzKu^2~~M!RenSKCn>G;0Pu^S5#t8->z+3IE{lM8R_(i%Px6-oHz?Zq2oCxuPw%_qn^a=CHOX^CIYk&u3Er`F9R~3F@F9 z#OMEWpBqIW;stzi_PNpE^DW%xcJKpNqy0qd&fo0jbNy#=KC3=YD)s)K`z);)(Z(nC zx!K_J=ef`Gj=n+N%itgV!t!tWb9SHClzRWqea_&&`5= zKE~a`a1`{37#tHyc9(iX|1Eu)``Q8R=U-d@OUrgGy7^lBWt_Kg9DAau zVN$8Ls(HJe+nkcJyBhY#(pR{zbB;byJE*S<;Fs{n^pgJy_7(0oh55pY zQg2m#-LZSur3Pam@3g++a>!UHxAax+YXI#x86(}2onfBPuGCu{ zf7!a^C0B0Qv#l|=b=&sbmc2WnapD#H!TGBxXUf}ea$k$keuc05Nb8(ha`Uz3TR3mw zz7{yH%_;RBYhOd3I`(Y2bmx}bp0-QKTL;kP4FS~jcr$s#yodu`%B;9esw~-z!b|Xtt0z=H@}ua zC;WPl;67Nq7LHFNzNocp^o9QhrJGJ8GXZj~NFCiac9bitWx2k^bY1`4ZWv{!R zLZ51AYDjOE?;;3~BkMolel9!uLp`Q`u7FSU3(LQ$pX&XD^^|p`-ed14yPmaoXKve$ zEtlqYU%s#7@_l>NQ8V->%u{_ib;1XE8r;r(O+ouD9>FGBHhqU%p3Z|#?Dug0I^=1G zQtz?%^`LZ?p!4q_x(^Qg1bUlCuqb z2=nY9S$t8mD)ck>G52d0+GX(xHqkn!{>#m;`k&$bwMIbTd}2YV_t^W@Gt%3a8zTQ1 z%#96o4-U%ig}#LTMfI|q;CJvJV%&4|h1x*NE`vY97t>4U&#{ki9D(EVx>E14_i^V= z`I!>%A@q%Hm#tz=16{Df{i=g@nHnyA&&sa4<=qtM#C{6-2In1VrQT!j*WSJ4QHOGC zz=zN;w%zR4Pq<(0(5^Dc{D#(%zSGUGMbH`i>Qd^hieHVAVWOE@--u2%4s^j!xo<^i zpV_YR7Fss{3pd}^K_`5J{DSk^8KvH1@7uP{y?b1I<2s{ncW~e4p?zg{%x|b~v%hrn zE&VH@Gx)Zw)O+lGqx;{^E&JNBcaTSTKjk{vJJ1FH$$eXM^ntob%dUVQ^b5$U^QhbR_%)poYkNCQJsxjHRdhlDf{cj3%;(7zj$6$Ru z4ZewPIM%-8audS?#jwx8htMy&J(5Oj-(jVG!Skpc+7+UV?`R$A|910h7Ib2qSI^VC zlzNY~U)YyO8kK$N_#V%rj;ANfqxSpUd|3va;ks23d=tHJtbNJl+IDP{M(}7JvF(vW z0$uP+aomG;8M7zcK+6_?=jKx`>Uq+aUl9QY;TFuipA3Hz#EcUe;Et(LEQcjp??EzK=zhC;rD<0bzomr$Q- zOgC&!w;z3F>b%8E9bkk4$OgQBYGT^06ifUO+LO4TQUEyp2HzC<|A#*E{zwbIm+yz;!inPe zz*`3GgTUc)_76M{I@Ep@LQ@{piv16Gfgukv55#$3kd-mMZ=gNC<(E(VzZp-~9svEt zBNx-zax?U!OL?>L%|`uD!LH*X%qeQv(MzR}``FaHiAvBnYCBTGFJ+cf9@j<=_l@=s zjvUE#j~*cZ@9RdiaQy4~BhULK$yK{F4|jR3Ajertu=H%vVjmLHyvGYu-UQ*H>tdtKOso&g`GLFLPoXQS~sd zQ@?lpyn2$7ccS2N0bDTx5_fEQogWuEARY)5WXfyIW3uT@Lg!hJJwU&|diL`wE=dzwo>Ygik7Oqj{BnuxnoNn&CJ( zS0l^bIfK#sUY$@PpS~Ox!l0;IDH&NOmx@A`MMBnSIhZ+hCGQY4?0smse9|1 zpJDJ=Z-xGBnVW>+bE%_4keU4)3r!Qiw->qWzjWDI7>Tn z8M|)qNcYjP+~7#h!Ce1nU!N={@1yk(JNg5 z|3aPJx3VtAud*)2r?M`_pRz8-m;S!d?t!sBBJV4VhZaWik&Rt+6bm)t=8;6ArB>h zjTg4w&I?_z>q0j)I+7sK)>?F^wN@SK>qvW{UVONUj-zFr+*(_`a%(lZv4I1_-Gijf z!#(ocI1=C3_{gXv&~I1F(9LTY2X(zZ@3~IydYcZLVXhaOVb+B^1gll&8yVR(i4ye% zbl4l4PEHhy4tZnIA#W@?{UZ~@y<=sJG!EHR@!UZLT#gUbuBzg>6HZ)JW#Nt#j_Qn1 z;x(wu+yi~%49i<+^4Fw_=kgZDaaEO>J1{)J1Gf5WQkl8K-J_%AstQ^PhbPD{eQ4;Co@Bd8WsaMSembnOf0$GjEN#V>dM)j|uzh+} zxIH}1jA?M8PPbLAN8*e}4V5^WtwzqUx!=ad3z4lR&S+1!vERnVqg%}!b6!)9y4A=T zRs)j#8I5eUaFi+)j zrTwYg&OYsY4t=X@SNHyrQO!KCeBVg-erbBAskghQCpR*j>+L%{Ae|XT+uPkUB7yYV z`&rxRfArhKi+P6aAwZA}y1{ZqR$VC5aL5Hlxa%#X*>$->sO0Z-`l}|$DO7LYSkLG{ zfgJ8p5u<*5w0o#9LVk20Jm%7Z8vTI-+K!w82gN~#`AFtMc?HC)7s?u=C z_Arg~+pT#>%I8CXx&2fZCYV(h%5?FJO$?Fy26^|C4Knk_yY1~K+rv{{O?`B`OZ%uU z4BQ$|h|||+^_$e=;?gq{Fu_N6De9?la4Z5bVCpgle zlYTMYsJpsvbi@)@4;tvB_0a9MexloLzLE0*=>VYPlkH&zB2t4cOo$kr3N-P;$W8vS z_*I#v-+J%>X^C%CdN4^B*XV&Tdj0k=9Nl(#pfhX_E3m{#2P(0-{9@omc0`jdjGQA4 zI#s6io9x)uxX5;=cG3Z&3=(g2aZ#NLH0jg^7<8&k*UtUYG|jL*j7n1vDIZp&*)H#% zIzHMx_2onR4BNv1&Hj>lT*m1hqO-QAZy?;PYY*8ThNFp>Y!3mt?M3Txpr@}`u=9(B zfpWU(`2!)q>=&s=ZYdY)dDiyO)gQ4KGCV?-fy%MbHyWO*&kc{Dr3h9&uAExJtY?cW zk-%K^y1-(~DS?^wY;7SyT%kT$T%w$FTy*g#5|*VO%X(c{vE`JobozlI=}BCTpLDxR zzEfS8$RbNMyut3Vv4Q@hx$&cg@SI4e8?hgU2S*Mxq(wF57d@vTtv0}$^G71ikn!t8BV3CR##QFX#26a|^3ZN)d|= zor73)PQ1`NQ#+*Y)3#GSo6yBG7EV|6<)vAkzI+&?c6+#4$1jW=3Hwx2o@@{MQolW{ zK(~E#Burq#_OJpGia{4vWYJBK6(#ACGE?e!L??HhMK?B4D3H}jNv+|L`v}7D4BK7W zNjV|N+)nwlO4qMsdsv+&9&|co*d79`aX8JBNqu3nboCvQPAm-Do#G*!up)EZWY7~E z$&02wvOTO$zdhV>4ckM2H4Z2LNIYS)boIp?&&C~(XX96g)o6XWT1roC9M=7$w};#< zFy2=T*ZQe7QBJQ;rqhk~4GDAg9I`#^22DL=d)Q#j_9NY+BrjWg2PgU@$9OebeLs1Ewl8iSo^T5z>~iw@2GtvV-OXtO5% z-T~`zr=M)Mwx4Xb^84k3f~NldF{krW@+(kbHJW~>+e3k-9y*zJ7=QYiE^IM%UzcZG z7uIOh4US0HoHcRL?P_(p_EDW$olZB@%|l`T)zmlCE!C#oF4dylF6Eqldsu;fdsu;P zyZw4{Ke@zi=iBG!{p4?wg$C*BAL+I8M|!RCkBo-5*XjDF&?8pT!YH))#cxxQMdZCE zUU56i#4vqUxld{vEvnN`jE55!!*=p3`Z}747w+MD-dGYIx$%Nrephax&~VX1+1l;W z1qH+Qu%m^~23^?U7Tw5x!$C*i4`V&@iJ6&uWYlfkVmg!2(RLl^9+E~1!}c7WrR(~i zaU6W)Iu&TB*THYb8+71l&eC-4$WI*TqbD(1` zFVbwn9*1s#HuWcs0}aq(XN=RU1GQD3sGX=gjr;d-!s9H}%iU>?m+92zS>w<&&!!It zU&}Z_;?;GdmFw8PM8{bgN3!jl=wEoT z>ZK9eu1m%}ECp=i5?usr*M|Ye=$yHuGdE3O@5y$S2l&gvcN(azdk%DKfiHrg9Ld}3+$*yxy(?&|zNP9~asq&k^s(Djgq zZ=|E8vE5vUQ-x){m5VKk*XIuR_2dfODl`sF{?ZT5}Fh0CERt?}VcR$Fby9$Kof8iwpoNDL(590+#IAFS4<(?5hZ4}LbMp@+ppEC)UX*}V zo@0D+0-AXvqhv|Dyu;abF8x7xPVrHl3r`Bpay%R=B)VQserp3ShM3!(XdRz%bq62| zKQzJKKJAR(#+7G2F}lbB)22_>KHXJ8+wuNT!uf~ps-TT8C8yPIa{XSt`NFPu?8oT6 zCQt zbm(uj*mU7tVdj1zJoJ!>g*WKPBNGB>g|%LCM@1;K)H_C=&?*D%x-dekPHM4T=g31X z=AoLo1^Uxtz5Uwkv-u^;X|vFwoHiTd%MEzON$+ro?kx`W`NcWr>E~F#Uz}t8o^g8m z$u2s3_&GM<87KYOU0ssKHVZsnrEI+fFy>Q*k=`EKR>;?yOnOMSW|bt~r? zr>CE~Bz1~YlcdIS{Kp*d-Se?>g@gKW-7ZCn+v|bxqQwAMI&s zbXb?}p}M@Z(rx1%a@4u3a~~ex-$Mn#Zfd<6N(HR2<(uzZjn;j^qBv^$Fuqt{TR+m!6C#iHDwyC(rhrU8Az$ zoMSn^I5kGb*EisHoG%ca%W;we3!zWIcbZQT z{}Room_C^=WC&1q1FJ8E=rv=zKAfmqb(-BHMxQKh&F*03`;9AOjig*8u=xFsmGc-^ zNI8vhPW5R9X2){L<2;n`e1_}QL^k&q*Q-0MMW66Ig?N={KVkZaP4;-k5{!S8AH6v( zhMyoFa%Y}&;%w$Jo$K=(J%`EN0F4gUF@-Mj=%yu(fkx@7OpGo`yoBp=oFl7DV`KOs zXtFQa;}}a6M@zHZLcXKg_*5T89;+Xd=@u^4CFvKUcNzc3s4jsY{KP^GSLGLT+=deo zQ8KQa`#8kwNk0Dba*-X>DL&~0#YyjTyrA)sF-M&!IM(OaF7pA{-e2YeaBMk4pfTl) zhQ^jN7#ds7BThO&72Q>SvDHKMkpq%Lf75bF_7|bY6KBVI3^rKCU2@x+d_wP3kFk4W z>harO#>jr=*Dk;P#WrEJ=Lf0J5NJ#}qoJ|oJoXnhK~5ego&d$?iFP7nX%9Q#32gZ# zPOlyy&3ZZpYEB$u+ri5jY_{Y(FK4hhu3U8D>lSBp0_<4MBThQuj$YV^uaA}U@RODE zjMK+YTAz=ftei)jbi&-LPM9tE%=8KJUppa>;YTLqX8n`9C+GDooKBf-YR5rNzF=+w#*2fFAN zql<)K(}Qfv6nxt|N zF>!%DVLj0sknHu8^-1diAIb?GQxE8q)&oAc)&u%v^$e09G0@~3t<>5sTn^RgP!2pP zx6QFWD3`Q8@Fr<}P%dG8<=jeGU%6b;`oNc@^+CC$^?@%*>w|L1>eJl>NotPGv#?y! z`oNcD?F(#1JP|m%+FvrSuS@SZ~ zqdI8em~s&h9ra1;0S{c;1NwyZlyk|kp0Yk^Jqdl&=UjaML~ls8_fJ{x-X8WxFvzN} z@>7t;dYGR6I+5;IV=Vb5m7{m^l{-khiLX!dkQ6B!Q_k?KF>d7`3FTPh>uc7`&g1Gc z{R)p;x#WKGU*Yj6=jo^ES9oIE$9{z;VVvliho!&d+sRFN)UTfK8F=L9NhS&dLqo;| zL+5hJo*P>(G7|A@buO2*KHW}X-VZ}xpj^WGObeTF?JJi{TA!z%<%QIw^?@()AmiX? z`OfcT^+g`qjqy?F!%E`x>Y|gIKAu0=+c$hz^2o%cfBZ&X8nWw1XG=`_)~+X=l}L|& zP)IInuLqZtqfAmxj@DXETGF!XGBIHz@kp`?*5>*uddt>)*vv_)PE0C&4#LaC1M3c$hwfyXfWM-Si3hlKD=2 z>1H|?z1+EO`ULTl&PwDz(T*$eH{3BCy3*tZQ55gC6~Mqmw=fpX|Je@}KKb0$KehdgX9q_lM~bK31P7{|UcY9vtHO zi|Ui)Khr0RKT&=Xexm%O`h@W-hcl!9edFX70L^KRDIbJBa@r81kDS)n_0iLr7=6Nc zqNgub{usOcQ1jQ!%;N;}X^gcaVY#91VRFlV!u!7u^pW2QpyeV)(7}fMGq;bIi*yh# z7FRCXQI6$2W^;JXdlwG?D6q(?!IX*d)edi^v!&^E2cfs%U#y^*q<)Ld$v_CT^Y0M z!a0aRcaV%fXeMOQ$v^L8YCq+K&GW zHl5sHn@(=9MJMCTJ`cP3H#Bk>{m{OtUZO)c;#zc4_L=*G@Z@E3V>`%SuavvPrjxtF zrgQR-{nboqmov4O{3flOe#Ux7Mp1Yc9SYB)le5L_^T_CU-`IE$4wAIX+#aUK!N%)x z(D8a4e60TJgz=NVf^J3sn)Ozl6s=V!MQPK?*=^NHu3B}D@yS_i;!O+}dJan2Yt=c# z$9N9D6zQ*hOFOZtUaFI-HI8dkC)r}vN#U7wI6Rw94$r2O!?Wq+@JzZvGR>NB82^|~ zJ`FSYJlH!_>=}!{{yErB{;ase^~}M+BZVG$;$fQ{3wF zi}R3YoQFK)JXF3>n71nYuf6}qJmVyf=6d;Q{Mm3@p5-0x|DsPC<>hNBmUg2*h-cMF z3sDx`gkyX}7hR3Da}({ygdgn{J3pG;R=ukq$;QnI-9nx{j)d(@FwPz+kR?3np>|Uo zOc#Hj4mtcC?jCgF5uF3?>Ym~8+(d)x`tKmuO96Te)agv&37zWk1YTJ2zqb)LY?MHRgEmJ*qZcg5O^l>Mr7YSuNbLBwWYy zxuJn!x4fh}m%J3ZNa~o{MfFMgjp`$COI{K^8Zj(!IOQef5g#HU*tiMXmnbjE?8aq% zpY(I|S~pF2bKGuuNw|sfa%6bG<$mlTt_$z*H^n(}Si8(%Y!}mOI?&43bf8VInJ!!7 z(Iu3XpD3Q*-iddd27xaEHlXw1V1g`!m%= zu$KLw>PcFJX!gz=H`RBS)iJtAATjz#AU3^pxy{->`PaN{JSiQlJbXsLt*~<=&9d{u z^oh|$?2XYUi$h8`D_5S0+kB8`)@B|3spoQfS?ZN*we1gMc{1@T1I_g^U1VwyqmOhz zydF;&WAvoMob`i_?WDRS?WFo7?G*Y%aVKe~w0D^Mz5Fwz<({|ir(7RtrZN8}(A5`n z98@P$P5mu&*fbKdO&>8WMjwIO^-eyMxSiGygf0?-rG1*K9acXQtshJbx{V)Hmt_5k z=pB7awtjG=dm#K{+m?Q#x^VTt=okJm3Nw%DB4Y)SoAQ$C<#dnHMbg2h*QL8fkGjF8 zOV~b??lvy*AxZnR>2Bf|y7!OCx1(5fq=B@{*gwPm#&|j-Y+@P3VL6Z)8~b+P|S<(kXNNxU*4IYa&*4OfWdxH4(+`HfNdn9oDkPYgPvQuy&-Zk%d!AXvvQn>ec zb5BL_E-2jlyt&X~j$c!_XHWa~+i57?x|4ao!QQfZ-aD3%!0|&iI2|dof_sYicIxim z{t5{kKV*X^B4u81VQ=Yc{olKh!0|&iNFn9467O~1@t%RW3kvsj-rO@0cU9rO$(wr? z;?_Kp=L7WH*S)#tAZ}W4VKkch>(bAW!0|&icoI@}3N8#{Pd)S8Un7Czhivd+y_*NSdIDW_m^+-7ZFyDF8+PgjHJI_Mg4#9;yJNSz8JdZ;cF>XruTNGS44*4H1vMAnJCEh{rc()+# zlENMK=3b1rC51cc&E1N)b&uhB2FHufyvMiS@L@bFxX^F4|LJ?2-^Sw2K8)`ddBKJK z!apA_MLtX`@t*7*Z#&{HDBM%Lx!VzURpCC?oBM3Ut$8fYhck~q-*Z3Sfw*bGg?vao z#_69#0>=;8;ButQ3hpDsx9`pSu18&gxLtx< zE55yO{NFu~n^z+4loIdzyyNX;+}SrgfUO_SDctvabDxXiT~fFo_U1khan}^?9p2m* zAa2d$c%H$$vcZek#+v*2dU2=V!u+@P zh97vY|K?DolS;hjc*om?xN{2k$==*<#9danPxI!Y%Vxp4;KKa(eJB3Vb3aCxp@P(@ zIL~hQ+GqcS8szvP8}uP%yWqlc^YW+e{|pj1e#i#>NLf(go%fFS0OHOl+#9{QdBj~* zxS#dr%6Ewe!J6R0e!SH7&Nriq9Y16P{HFqIAJ6jvu8U;$UVoD#3dyp;5c-@JTsRI5 zyzXw#{2fNzPQiu!;;Q3(xg&@>sl|#r{F`*Ng4)w~K7hZEIR6tTp^66bT$ZWP_I>WtZSW{@%25=kZA3_#qoiBIT6eLjD$haQlf!;P@dMT!WPJiVy#M zkT3TYh`XZ1d&oQ9S0Zk3I?o62Va%KRD#Wc=;8UH{N{;5ylzVw5R zDS%|z0CPJ87xMRv3x_6A0ml#7;8#dFDY!8HKKPVRdFC(Y&Yi>kovT>9cky_i#JMXK zi&t>LjWc+^!T$FBR~IK?Qp z;5SG<}F$A0L_Akw^*@w zk2{XmIxqTdR*Ba?A2>JP#Qj|q+>P&V$Fq3BsWric{cZaVFY(L=&aG?a@zy*U&(Hk# zw-Z>rU65yj3-S8rFXw^}9fAwv@5zO0o(bEMyk>)wkiV0H3*+zQm-Q|r;el4=&MN*s z^&h{7T@Q*ly=H?4vv`*`@qSxU{PmBQb0LT|!F`Yj$uBX4X$ltnpo@cP`dD}TZ zKMCqg@|q1eccq28x|Da6ey+?&0*XCm&D;KF?h_qUFF&Qs4u+b z!MTXrA-Hfe+Y|5D_qrH_c5^nk0C6W3?sxyR*OPl8;?4{1*&>R^cMomV1{CvUHh3oD zt_d#8&u+T&n`gx!w41ZRvk-9V zyx_vPGc)5muD2oXl;Fakd;2pQPmKvpyEz+Nin#NF3*+xOKlY7xJK`=YK6IVr%Y6>w zmK5%OZ|+XSt$jMqvwObpn`gTbH=}S%-rUO&w@Yv#&-%T6*o(N6f(zs1=!YJ;s!gPr zFSEgwh&wO1kY}G-^Ua4 dZ=_)wSc{NZ_sTM}FtcV6`s-+Xuh<1Rj)->+PEF3z*p zdUIcd;>`*!&c}K71aIyu8MoBR$A@}_>wjMOY7}p~;KI26v%7us;abEkDBM+V?sbg2egXGk zMsQ(&^FJ?q9piRf$hnIO*Z;im4akQz#fM*c`|u{ltsUUwWNjKBH!t~D-+p@wiZ>&; zu)qDI+jqZs7vgpbE{wmQU-TV+uV>uS=eZ9>g}dm@eJ|q{E)sdBaQ)8%W|0pIf(!fG z>kj(%+XoPLRpGwDoBJWgUE9iisA=GN2K$@;yyPQ{o4tf{(+byrUNVP#=oDP=_g}ny z_*ceV*}~(U6kNz(|M~hSP`tBBybt{PsOS0orx15Z;hx~looC$19o&bK;BGu0Zsh(7 zZe1hJGyi<~vS)o^j{D!{pE_3A~&ofX`gCOkj$U$6cOpw5~2IJ0&`A$*s!GFDaiE&~1V@7aczqt8E-~HlN#9dJ0{qBjr z`^C2rcSYge?#=xH;;t(`1fTQu;daEWYsUH8koA48}u6&k;AhiRT%_TXUmtysL=YCAd!z6{jA0#d9ErB(K@vPQ;xS+%pB_VG}<% zB?%9-+29w5yQIW>@e_UH{UzfrU%`(T>k8N3hhL$1>sxrgfe$NNf92`JU5q<r z_0ko-$G3YBw_R{y{5}4wzULReMcjhIeXuw8KE$07T)1xfk+*!_^Sa*e5qD8=VP10D zHeY}L2XR*wA9kgEk8giO+?ou}2RP3<=i9@c=Y@Yl+_b`dnm6~)h}$W+aNct1D}4R^ z3*r_P?oMy+UlDgk;hyPzKJ<6QT@YLtbU$_IZ+l@MPx4CcuSVQe!G-;JcgFX=m46~` zO)Ji`_MiBU5BDQ(T5#dMs}J0L?PQYngEku+_W*cLUptg|pZ*2k{q2E>TNGRvAKJG2 z=I;rJJ0rNTU)-Gcov)vSxC=_WJG|q4FygK#+-G}VCwmCut}8xVHtg%~!w|Rb0({)O z(wqAT#LWn9`Tml}z3DVL4_)79gGVB6m*B$h2s|d`J3c%bai;_q#+`%ffAt)99*em1 zf(y^bUVrx+JbgG7aaRNvZf5)UADoeL^;Fi8`!W$XxRB=q#C!A}-*}&Zxb=by@qX>( zGd<%y4RJdJ7y9jxcfXyExJAK*@%QjOzT@xtjJw{!=j$_q3*)5!x?BU}c3j4}3kuhN zU9JiFup+oH{@(s0-*IOX;;t*)pL%mQGj8V|?nB)(c>aRF{_AqBDBg_1J@igrA1*}P zPQe9#|Kl~j+-D+gQQ`iVH}@jMol&?ae$_YLEr`1yxG+E4`5WJP$yUT&Rk(Y-xowDB z^Gu#+a2)#Tl<#q<9dXlw3qBn8F5mg&vk|vbaAEv?=Lvs4Lp~0;z9+x`i@1}53;8=V z@4HUB3vp)^9}a!Z*M|>f~eQjxl>wn*CC*w}<;y!c;F66KO_3q~}?wa5h6|VpF%@;6ky|^wttN7r5-|LGQ z7xtq?g?s7^zT;#U;;t$_ysO^#Ja#|g)?CE%4Ek->o7>B{Q#*M+qy-oD3;*l>{fwIt z_f>QVE{r?=_owC=cUo`@3fKSs)Tt%Im~m&s{Uxi4 z5B~S378n=yiy+JM4CdAM-0M599%J0v9QQXRxUk;mzpgQX;%ygP$lve$&UZgP!nlhf z-n`&K{`#+L97XX?De>O!9q-kMJ14ksp7rc6-|u;T{8GkkKg9cOS#V(<<K+ck(=w*?=MfA|^S`OYg4H=}TW;>~>};&uuy^xN2*ef#Y-h&w5`@ci)uetO#t z<$XNCn{03$;?4^$JTLO|Ti!9809Te~gV!SNs^Y`VzdUhYS)AZaHh3N4)?Cc<0oJ+R z*R+&MfGbP0!Rrw>Ex6EcoB!80-Zvp`r{KcxeqC_g9q^NIX2hKnTo`|cz4zm{BJPsl!uWgZ*M0Znw>}&LD2hR-R|z!y#`U z-i5gJ3ipUN_j<%_7hLf7e(&?b_abgyaABVM$oqWH3*U#h(+c-AZ|*GOE+{@c=+nM= z_I|`&QR4k=$=8PuB5rUA&ol7%FW%e_Gj1lskMs3{3;FB+dkP;#@wN*tj5{BBjPJNJ zhq!sch5UWVwZ8Mde`VbD=W`#X6o37%OMjekJ6^!K^9tAhy7VWI4=aKT{q~QGe6PQK zl5uAa^5+iL6@UNk?e7gJ-nuqCKRa&9x8FXExEaBP{i5;FzUz}WF>dWX-fvxk3;z1w zk9afV7Q}r)lM2`WKD^H%A7&MQ-|784`YnjNsQ7!;Cw=|>0^+VI+=4gvONd*$jprH6 zQ;&ak#`8YBFC%VNaN#0h?e*_%Q|Cx7pR>VNIrmbYX9dB9JoA4J@N10QDY(;u3*)5! zbAaDKKFkX)oX?;91mAr47UHf5E}U;Jy!a%~^MG3sH@KAN1H^lucf7YDZoS|_ykGjf zZ@k}T+pi~no$n#;v=Z-Qy?>wJ`-nTQa8L8*{t$7O z1sCQeolo+em#i}G+6do|OM(k|=D*H$7mBy8o#!v~Ti30={q}3b%?K{!*+0F159A)i z?G#)%9%qMq$A|k6cT#Y{-#_j2U0?ql;?61Dzk72_h`X%#`)=?1jed`~CB@&jc|Uji z2gY5#gFi=Ax1Hx1^xM0=xqn6RW(61ax3+rU{p}x!+aYZ74E1v_lbzR zsQ57A{rhrfAnvN*!uszEPoFze-XC4xXM?jDH~V6q4>ixh^T{iIO35{fr1xbRTG zdmet!^EysF;&urx>=!?OfbTlNQxSJkaN#`bzYl(?;OeQY%LY$J+<7J5-+9M-9^)>) zj`!Pg#o|q)c!M20AK{``eo*Uvs-_U&*>`a3SNaiu)?olz9Dr z_u!d~yYfojZ?!w|{LFt|eG&2@Be-zA@W+pR!MEl1xxUW^TNt;n$bbJVFSw9rS9l-a zE=KWA2`-!mEG_!3uWv=%dBxvTy`R6h1aVgc7uE^B`ks?L*EQM@H`s;qA>|$KHpHzL zT!{B$r#{j%-b)d;LvW$r&VRh`akHIq7yii4TZ&4&>p!jYjQ2Sx-dVwg>%67<$9i&i zA?}jk!hQT#o?ZVW*L_UZWrGgHEeS5%NBZe=e)ASt@A^I)T*kSJ{CYs$Zk}flZ}U06 z@$NzKW(61G{cNvqyn7KhFSyWefA;RTD-d^DaA7jO2nNPTsUq%`5xc>;<<>s zqHxdk<~|>BgAP33x&DKLzje(mS(go7h`9BF3(sL+^7Y__vflN5Hh2-@b}I26`H*kC zImWGhJ3k&zRxI8w6z{y?!o2!B&p+WSu5Fif*`S+o7e&0Qf(zF#{QcdJ;;p@m=L5t$ z_X6K|dlqquK zS?*`o_t{_sao3f2pYqFxc=}L4-1f3Kc#+?%Ju2d}Eql~*E{H@trseXGg<7VE?{Y?w*#{2ChjJqbd zT@~ZLoN-}4nigE>x7)q@?Ha^g5L`Il9Q#E78=%f4ui4<0h`Xl5`%CY5uVviQ^}OF| z_wjt#c)Zu4c(Z~F>m~Od^*tWH5pnZMyq7(t+tc4^#GO&%{hN2ZZ)V(%_i}$1D;Dot zQM@I=h2!y-vybzfKfE1rQZrulXymJ-fE;4RGa91kE{VL-w32x1mmFl-8#tp=Nkr7-N*Zs%I zTRB%`XI^k&o#3n^J)ZN_+ZZ?XLEdlE74zXcDBeZEg`Mo)R^M^*yNp}^As%n3V(~6B z?uy{1IxCeAKR`Zo2rl$nqj$gkka5!=<~|fF7VnQ3cT)H;C%7B$w;wa^s)%=`V)3pp z?(|2v4>ixNRKNX{aqGo=JtMdmTnQkPoYZ3lG!1b@W#FNzR1x z>OV7X{uA7X+86MC+cjA@8@8=>4m{chURA+e9zf-~o(V{1o>$Q!(!GjJqtjg^F=cV%+*0c)W8J z67geg?9>%yS;ctiFZhSv}IO9&ubAKl*#;s-CRl%LF821#$ z&3u~2yIL{sqZoHuaBFjw8YdsaxNCx&tr)kCabf2#2rgWgeuMY*%_new#k_h(aN)S= zf4+G-<1W07_uG;ZumAPfGa0vZBj=VX7Vp`}-&7aR2bfP@bn39@^`R#-Zc(fgvui?(&ZJX^h)(6ZdzvV)34f;$0S8xT)mQ+v*^dA;q0uv%z_c+j%pOx2Bu- z+s3(R#+?`3Y{j^Z$cLif!g^}c`1?NQ)Nne@IcdcUF4CB^* zj>ntYU#Wh(fN{G-yq$u(aetr5xOoxpbj9L*7UR|}a37W`#?3NrL2!efO8I*+<1Ptq zrefSn7iT!xVJs+;hxtEFK68J7ev4H@qXL5 z4_7eml;E~2Tz?-r8Fy81iwf7@hvy@I=LGjmkswD;YI`B%N|IM{A0FebeUbaSTCsR@ zjGO%u=hpV~e%pAw-Hclj-1drbdl+{{a3=*9^31>A`WP4bWL|J#{Wtig?{%_%#9dLi zm)_>fJ%G5u0p4#gi99*ud%wm2;?^tN&S&^?4`^C>BFYAb z5Vu|77SDXYCwCNaCj}SsVcI(%#u#^gk>|sl;BGu0#u>Nf%bdHSaQ*XP0{Kug!21o( zkM9`m^SnRmFydwe7skoQ{p=Laxvu!-j>aODX0Q<#(FZ$k}`fB7u zR&e1W%Ud4in`hTC?#kDByoHK!U(dMdZ*cBx#kg-`+$q6bt{C^tjJqnh!9m_{8~68Z zjGOr;_aR*|?hNBXQg#V0>~BxKamaJM@7;(yrEpulx$i~Xd4+qzXME#*KjN+^+(&tH zKZLl!AkPQz_eBf7^QaFaZoR@C^5%XNaXS?5drH3kehhJo3ilJ<+>bME`?tjSpm6>D zy@7FO1$Rl|`ulq$@}Z<~TW|5rhno?%ZV2aDyEk`%ao2?pS%vGL4_{#1j$3)ZWUq;*og?p_x_iK#1CdTzu!G-HB{^RdA88^Gc{jC}1`2bx1@%L87 zoe|u$!u212zr(mC!R=JI{^Rd5Zq2tjcUj^3 z?{7b5+%CagSGfNB+X~|@eV50Z8o_zy@9%#xZt8oS+pci^{at0;PSI}#h3h~5{*rO$ z1$Rc_`j5ZAX56CiVNv1w=fmBMyDYeC3fDg$e#^KEBF}0II3N7S-`_EA?RR)SWE8Id z`1?PMJ0q^6cPU)|`w9NUxb0#+YD(eyU-w^UT$r!VE8M*I^U{B3+`M@Hctzp*KZpHK z6mM{d=L4*#etp(=y)QTcJfN@jf(!T4KL0C^^;~~Ao^j{J{i&UT3&&0W`=C!`+}YcC z{!Ugb-iI)5$B#I7zGB>3BAZ|)%CPAlApzTY?AVZ>cfxL19^ms>#GRfT)hn>&iQHAi?p!1dT4)can48%NxX z;KKb}|NP-8DHuDFyk>)I8Fy}#kCTOpabL^hy_0k2D#m>S<8}(}YQ?zIj5{y5bw%E9 z8~67uj9c>y?n6h#xNm3NF2S9u827`ByCArW730n^ZtX9*59<}PUl8CqVYVPmG zxu0j;)Lq<%_KI=8#JEMlovavlk#Uy=ccEh3uQG1^uelGUigCZexRZig|KdvZ+m9G` zMR2<+#$93D^l!KiGZo|B!MIa`yIe8u&lq=AaBE&tDSz)|+{_yHAzLx-uNW8h>!RSo zdFVb5|6u|9w~gKt9yGl=mC>@E30%{>ix6 zyLr4B!QHqI_cQK{;N}&szYoEQG#6^$&W{%}f(z#@``+aH`-l%{XOp5psEa1Z5N@tj&-;rjn>(j!p3GYa?m ze&2W>$+(@r<@?2w!u9vz(TqDUxa$hn--kNJt@&>rZ~e=8K0v?u`|x<=Z>QkG`TQ5& z?3=$&K-@{eh3Cf4KjU+73oPuCPOsVEG{#*JKFkX)+^6gB?-Ln!@jmYFYQ^GBF>c{^ zoLf7|`)%VsoQ3?&3NG~9t=|21Hsdadc=HvD_Z-Hp6WkfW-FUw}nQ@CHu^(3~-g?HZ z|2^lfSB!fu<95M*d=1`@{l}d&<1PyyIu)+}e$m9ZwPL@RQn>!(P7C9%2!9t8uD=hh zjGO)+-fwFP*WZU{Fz%G#*1ZDvo4*eiG4871wkuqJA1-Fx%pbT9MTP6{LmT5x3+|l4 z_4lEjan}TQMdAAU@Epd?{*n7o^Ge)r{yywt+!?{mC|rLZE@NCc80G~R#`PC?&wuwZ z?xfh?rUiH7$Du13xBXAt-$lXQ__+RD#_jks=awoK@AJ67f8pHJt15Lo&T+2jxDLUE zep~cD9(OZtN{s78h3kKu?_u0I;qR>AZoJ?67`IdSyIe7U`x$p(o%dVt>Pq$7LB{R+ z56(>sE}S3x-^Vn}xV3-f+^&kndx&ut1$Vk)+;PUO`x}pUv0~iAj0@vgNpMr*i?@F8 zF;9nWNnW$T)r`9&;;nxT&xeh3U&^?tzl(mW821{+Eeh^T#kj9x+-1RCt{C@P#;yNf z?nBMBmGbvG#?6cQWL9utob*56d_CjVi18t>aQ(;0H!|+JIKE9QT>sYb94_y`GewlGg;{19>aACdMe?8#qj63!J zSiAE8wW_ND;AmaYx?tUKM{5TI9_O5!;a=eJ?s>O=IB9bDao)M--gn<)8CoC8 zipyWm%HY;%oop&D|2*~xxH;Vy@%r<6H*w!r|B~e9m3*&Y zzmEAI$t{yBUR2t7U_IvNk6xABrjqa3?0nyl+`yl)A4GkZ+lyP@H^D7?v43OaihkhN z_iZWPw36@4KXKoe@vh_+6nEESx$b+CTUFc#_u_s}R6}yTr^(~?4BPz>-1JH~Zeeo8 zxbge!BX9%cCdhR^FFpp>PkokE^5w5P{{=TiZb_*xf8A+1yAXkjr zhkJ6zZ6$E?lyBfKrp9d*aAT`u9pc8^)xj;0n>FUHf%WxazGZU7`^owDW7h^ZPOj&4 ztgn054{nj%urYT-aJ_3_9a6^JO~6f%TQKHs25yPmnlX2Ca3i!n_|L#`6Z4I~PHqXV z?>kuED7o&}$so85v7V9Zex2MJ+;PgcXe{4tz)h`*b*LM2w*$8+*0VF^apSL(lff-h zzA)Fr19V0h%mZ^2}=ipY!O&W7| z2RF11)*)}q{Ux{=a;wJNUx8aA*LSw5`u-YRu`h{|E7r+J+1CO4N^Y85aew{jOS#_% z`5SPv>*BZ-jOBX(xOH-?#`66gxM6a==is=xUv~}yx8cV+M2xwIfE!&8-Lx@xD!6%a zi^kjmaGT`Tjk(jojjfM$2;@wSTN2y?xp8CeY;ZjrV7^&n?&09Z$t@dm=Ym@#*K@9^ z`VNEZ-4N>#Hs+3kn;(dmfIP$oJ9t zGnwBf{YS|SEAG|9T=!^n>Hb5KT(Pg_zus~jxPIDC<`kEIU*kk@ieTb{O>WkSgJ#kTrqBUu*dBZaH|12Z<6bN+%5$-L-j2gtM6st);Gg^>&DzG!L3og z{tK}m+>cuUTrp3gW4m{Po2CAZk}E#{$zLb$lJZR{`Cj`S zZXL$K4ZVPUmLpg68UObh{6osOOs@F;sVQe4x}}&iIzJ(W>+_mv>TWEn49PvB~ZfQ%bL&jLXkAv$AqFXYS?-SrA z$!!?R_bG74$qnRj+}zjq8F2kuVIAV+ihUoyAD#s_MQ+AezR!bOCU@LezAu3r_&&`y zWBJy=O_LkE#MFFy72FEBadO@F!|ULRxtb+c{NAbT?Fa5A{!Qm+#Pgx#mdV|mkad?G z|Fw=MVk4eUz^!hL(>+3$>|AHIZ2Hh~Z?(_W|+zh!XWBGmsZjIc6v3$P)H@q#@ zp=K=KWxcI2%#!QB49CrVeU}HfPHv1`_x<1nH}V6lL&jLX-v&2F?zpjhR|B^}Zqr!4 zK5(Ny#5#m7H#OhB2X3C+B)RVUAqZ}h+`O@Tw+1&B!a7uq<@*D03*`E)Fje2}!1Zj0 z`9{fgU*E~##>pKsmhTjBi{zG!<+~HO-bq-8hOvBq3~qwl;FYG9yI;0C8)9a6^f9Rzob z+`O@TXM$TLw`wfk+2DqD#5#DdHZ|W42bZR;Cqk}x|LnnR zpme9m~YIOdo;Ka zax>(LdCafxpTKR9J8mrB6TyxC2eb-@q#p@S^Po{4v{!Qnn^?IS?hRGH8e{Xr1>z*&U2_@eX z2Dt8plA9q{-1I%+<(D!#$1h?dp1kCale-xO9J<*2iN~ItV7jUzBhuKBG>mfQ}w+C+%maQ za^2Ur1a2ULbr>_2@15YL$t@Yn_ik`28?t|b~cfoPX7|Zuza6>;ww`45ee@b&IVJ7p2qeL|{3j$E%9TTO}Llb$aSBR+z7d%A69;l+Ye8J zTi+GuMUq_i{qPL9k=@YEDK5Vs{ta%5`m9W@c;Ddj!`$~zR;Btj$rbD5Gu2a=>)ErC z8@y3oe>Yv{RHpl!(20=-2LRMk~>DO=(Cq@z~05?Z&uq5{b zzkla|+aNctxcvSd0XG`MI%E`=-@iwIn>QlJCAL=H__1=l&Cfs+}?#+@LR@{>l+ckpIHn<^L zACij8Uw_vDH$!etarx`-y5NQn#BnPtE`Oc$gIg!Jskr?0Y(sD(2hsX_kK7OZ^=xx+ z#r`a=xNDcV>+e?JmhQ#Z^)iatmV)AO8lG7 z&xq$I;0C8*9enrVxVd+C0k?1={(j%6;+{D3bY{MLfLo<}$Bemqf*YESbtoBg_XamZ zZo`-x1Gh$Q@IHCm`1Rcn-0&dQAz{ot09?_VIda8yz+s!N$6U|i;MOVMvN87%a3fdY zy51yLyx#J^E4ihGZ^M}TM{tWtbOZl~{ouY1$ADX+eB;L4e=L^vk&Cx633quei5f z&UG)B+_K{C!QMYyA-N63eU|NB32t=`_L;vdpO5+Vy$amWTy!If%dhX%QXP`yivEqI zxcz%AxMTFb?X2Q1n9p_pD&<>J+~pT=-RmW{rnu*@-6FUd8aMAlazF6<_XcolKIKHO7S!hIjWa(%eBnR9jopKF@I8Y4AnLHkBiwxNm+BBESA0I;gk8D6 zN9_M3H>tSS?8bG=lABZ9o%i6n4@+)YasSD7ACcUq;_kiKiuZ}Vrp{06d-fzZ_$c;+ z7`OS~<+_hcZd`Gf-Gb{r0j}>7?B9&yp2>Efl=3Yp?$9{5AO0n|b;Zrz%XOcUT>n4i zaohBMuKTp)Miuuaw)+gY)imx?(~8Tl@4vwf9f58^aryPFf}0_?s<{06J_~M*T<>G@ zxbf@z9JpfchshP!h5MhveP8_ZlABQ6BTnVIFGy}iaaTT#>%J(tMa8{-Ib8P@$&D%Q^toL3Ka!hP+!wdwUcbF6 zxp~E1W-`}(Q*z6SyZIEZ`Wd}tf-Z#q9Co)y5Y9*grL z_$2n3dv|4UL&u>TH|DMeZid{9F?TI+Yvh)UxqfiN$73Dp#@r3T6=UuHmwdi>^D^%K zEPyWEKZ}qnt~dGbC)iZVH$`rM4&YmbR~Ct5(fJwiYzA)b1gvktn7bvo4RUM7+-<>) zo{0JSpTco-Ux!KH=E;p2b9V%{Np8lN`(top8LY#&F?Sbm3*~T99+%)AoZY%ETao(Hb)I&{Yr_jR^=KDe=Abc>4n z@_O9Y87>63Oz*p@kt;r*#sB@A7lRvk4)gUrC$H;wAI#17QgFq5i;yecpStFc_BmAi zo6gUO=PGd1ly6GO_n+*1uLHMvI<9AVWBJ|yZYYlRt&l6`#k=f&xCPuODa%N`K(45BGpuI0NfYBG-NY z-Yex>Cs(|G^3$o@&)wb+Zs{z{*Z%_cgZRF9{(O5#$~Q``$alE}H{Zv=O`eVUrj6zM zFDc&wxuSp9VfVwo!S$bm`Buqw-w)49`FdZ(aTE7{_uhm1`$C@wH~lBfH$<+OZ~Xhe zFG~5w$rW|jf8+g_>-tOJR&tnc#+dsWxVi75TOwEV1ONB)zAn|FPOccYL)hb12RBW1 z@V$in;C|fR1~+&v)*(!;`*C{*+{}6CCXKlbaK|X$9J%ht?L%L)FTkyzkNHN)b)WB7;0EdSi!{07bu#|zILofm z8nen}xR1&!b@=Wg?&~`1lzO4ps<_a9QF>=Lxo5UWsHNeeN9SY>SAGbBZja`KGtr)BCTHqEhM%VL-sc~Bm z+ydnrBG>)6t&i?39Jd6yV%)xFkK0Dz<}ScGWXN^D?rZ|CSl3HRzN@CW>%->Y`YyqI zYsT{30^Iao==%PH{UGim^1q*U8>tRqa>cy(!AacftRH~u&11d^a>expf8VzqxaCXH z%^GtjgB!RE-Em{?4&bKAZ5VTR1h+zN;8pAg_x0Tg+~DO{hnO*UXK=-Q8zWcT|K0Pk z#Xk`Lrt>r6`6;+#bpN+Vu2|3buXq0p+$zeIv8_7R@CXP+#XT-A)xRI-{ z4uRKk+}ykSftw>YZp=MEsza7s@ueE~-L%I}I>#?!Bc21njTW#DWn=Ck;O5Eoyn*#~ zpYK#~>(pmqaszZg{CP0|ZtQBTL&}&t9oz!B1!L|Ea2wQTHFDkeZxY=2HCPA#o2KT) z;oug@jTv+2g4?7%%aH57&*p=hxEAX$Zp>W(Zi(EcF?SKTH98N4>NsxVdk^^M<0HUL zUWau^7;}#Vcbwd;G508N{ePu#Gv*!*Zi?K7G4~j7%j5>$GBs|;Vtr4+I>g8o*BAWv ztsDogkKDB4^54I6JhrMXarYA}HHkEw$W9NGc zxMSC2zJa%~AKd4=M9MctuIPuKzQ?WapTP~$x|1f?{eJy4aAUh;9SVxe|2JTPZ z)ZsdI9WDYle-q}LQ1azpcV7%{liaN0^6QWXSDY`#$rb(kTXz3m25$IC?6bO3-}Hyv zb@B>uv*h~T!+sFsb|TxoN~%LxaeYI{cSVhKenvb6a2wyHejr!e|2<)2?(1Y%OZjHV z73;$aS8&&dYrqZs4f8FM>wf=x9k_Lx$2D@@pO60vZt^zF*Y`g5gZq512iIRhH)71a z0bC#Dnj6UN*J!A;QXLs@b~Kk(mYQwBFl zzgKyjT+zQ-_P9L^ZtYI2L!DgrpK5^Hcw0WHkEu2XXpDYxUqY1+yWnAKe*5L zc`4r*xuU-3%;bJgWKD9@~VVs+$7~&FqZFo;FhSqRdU^r+xy`9|AF=Od}3q@@- zepnIQ@PnAI?=w^V;03o%Zp4_o3b>In=9@C+t_E(7+`KV&4R9OeR*bo8gDcia&wp{; z#JuKuDA~1e{cSlQoadt#eKxbuibg_(%#ni zL&UQcxM{i{l~wZPzizrUxQR!x4&%o1-4+8 z!*Cf zsPjIW`HjTNz26vq1Meqw#^LSry zD>QB~a^3gCZ@~>cf%P3D*M0vU0PYyox2WXH?}s?J;U_WQnz4Kj0=G`C?@Lqj_)u`g zDKSE>*!P{n{{1Zj;5KQ0mLyl~ANbeD)4`3?ekV(=`+eUGa0|3Q8&~q>@B3zg8+{7< zp>8bSB-WQ)|5w-#?(1+ExS}7TP6>>#Cyvgo|EVu!xLsO|QzaLHqcZ})~Tn5L@eSOaaw?g^G z$#vfkXM>x00mm(4EZ-cs;TO>@8FSAESM)=jT=BZo9xHIa&+#H~LsSRfvN&$y^?80j zTmo){_9YQ=#pf3J_l+(Cw?_GUZQzyEZ?iZjlPU-#h7~yxS}6C-@%JfU25z3}5GU7tKNP`jP`()@Uw%K_2yUT9^VnFvH-j601>L$a z_cm}vKlqo!eh~Y~JbOQRJGegDM@7hWzn{DV+$^n=Npjs^XZ;=AamqKR*$8bbzk2q=1Yy1Bv-tD zXT9|{`mN|eou3iU3*aVbzGcZ3=QsX+t{1@_r}F+G4~yC zBX6PGH0Hh!ZjRib7yH3|9XwaE*3T~6!x-s{^ z;Kts;I`~&IHIF|BSFEj3a>YEpbtUfSsJ@Wgl;Zj~;JV*{o2B`dBiH@*B5@wm-fF^#pPcIYyfVJUPt$?g5&1?_4$p!&C=`AVa4UY zj=l-F6&klBx$f(`8Mwg@u^)1Z%dhYEz!mF5nOw2o+5Y3iq2k|kenvc7NN$tdEeN^u zl8>I$@kDIIv!&#QR>gkUi~_#D!DUyASe>5{&-W!aNv^2FOWpxy9kvEH{4tFix$f(* z4Y*lyE5_>ZLvSOXV7}hfu)gl|4S|~@H$txaahnWo?IT(z$ra9y^0awiZl2V7Q zcIVFHpP~C-%(rf=4!eMxr}_qb^0@K)_vhexo0xBmT=(O)8@O?*Lxx=UqEofhG@T2A=mx&#R4f`&ssQc;`NJVPT7O`Ig~}kfxguZwbxRuD`q$WJ31j&l zDc3;^pamfWgrs&yYxZyw;s>bsnbSh4=tEIck1kc$&;q0 z1_lR5rcK&m%0wjoNj$z+{M0!EBZs#=$Toh5?I!8OFLLNE+HO*~EfoG}mq#mJD-X@O zEVAOYe7(Aij!c_4TASmv;yMe{H(p8HKEAUsedD$K&cfLGZ4F}|r&*US4P)3s z*!x;_X{(A@6}rxUX&Tu)f0t_5yY1DmbGu9%yY*^OXBBMn7@9q6?y!S-192MtA>y6( zHN>}91as*doeo!;|)?%@0`>Db11 zNvC)G=*SF5J;x8@v|O!vEu7_SKeBL^v-6M@ z=dfOS=ON2=Sg$T;W83l7IuA`7nqjR-?MH}1*lYYSzCCjX@e8Gvg9q693#C@-A1{rN zgM6gQ_lX~#H!wJTU}S-E2tD&}kDod#HLP^Hv&ShHF;ADPJ;?~#rv&?i4;{YLcbmtNp#J)B|1Iav>9PMSS&60ka~ z*Kt~LZMzbixPj@@p;75SJw5A2FyfcPtS^*)%J>^ZQKF}-kgE-M3l|(&YA7# zb?TYc?I}mzT)BWfk0T`q_KX{zo^tfOR^03b+bs>X^JXuYxI^AMZe+eQZ)EH!`#EX#UwZ@gIu3~Iyv(w9HO}WPf23_@+2t{!vEN6xGZ8z#Ee+e_ z>yn0jd}kWH1>gJ}f<5E3Q4=o^f-mc_LRBm#SWM6Y=UHI*8ZWXNc!fOVjUp zta#S*=!r258i9Kd^2-7C`Dh+*m)n50ewW*N_VJqev@dja zeW|l9x9Zr6*BK|BbsYT8X=q!QF1PjU;-!t9OeXem%gX@vzFu8Mr|I>} zsOEfyc#S?7)ts*oujOkVujYIm)ts-RU2enMj<4oCggvWHeKhCcXe(aJ*Qx*Pxq9bA zig%n(D_-Y(Nby>}=J9IHFDsu`yiPt^^Q-0SjBhJm^LVx9m*s2CuU5QfK90_Zma8=n zDPCuswB}*U*BmFU^Wp5d&d!IeIQ8Pjx+Lm({-k(~y6Bw`TfSah^v;KtuQ^}!&W9~u zZ++4`AGUnG`7x?FU-iz1Rz8~Zwd0;l>k8bi-&*rlr{6T^q2Bq>I$o`LIB(%#YkoP- zpW^4tn4>-fZdCNFQ|oa$^M>MC&!f|St>>}gInSdt?$-0P;#tq5S+`byv7Se>Zmm9J zJkOkw!zXTW+w@B-u4Coz6W_72*~HJ+?0bl39PfP1zK3|$^XQG=d}iOz*V-S>TL|%- z)5EcD85&Hj0K{nqWoVEa6+6A7noT}}-4&%>-+mlK2i^DyhCIZy3Q47T}c z&QrS+gZ=a9%~QJ*gWdBi>au~ekJnq@7j?OjZRe-Eyz<^ZUY?kJ;;jRK%dDmU=^wA< zcMP1p-@0;Nno7UxzmfE`&MW;szUJ|E-pT9ZYaVZFqUs!P=ft+pr!_&f{Emk1$SQ z&(nE_see3Yd^#^A`aBPBo_4vz)aQA4^R&wyCi~}M&QrKBaJ){Bj@VpC^vO@N-+Ev0 z+dfa13yD7Qdh@Nzg@ldYB^#U9pXM!GqzXcizr?vAFX{+%h&0*R=no%w$=fi`fKe6tbDYtYbai)o?7Sg#dw{falCrhH7#GS zpY^V5TE5=+>Rs0?PD8v#{q?SETE1RC>s{AazUKVZyRK>ZdgBZ6I`z~T-_fBiSLrtE zImOG_^oj2{+Wzrcen&Uk`pMz851{lskB$zt;+(H*OXKCt`}iG|=^wA@tXNK?8~9f)y_VT&Rtxe zc)h+H>hf}vZJ%}S;%xI79dz(LIo8LKt+>t!YqKt4ywYIy@tuX~8?WVeHcT&nUi*iF ztu1cvIJqXh-2=?)vMX-(UHjC}@={AdP{*{y ze76Gis%I;{TS7MRT?=FvubEHhCe~)Wto#>t>mZwa7IrI;ZG4vk*~ND&kZpXI0@=oE zSp1$X}j|>bt`dmN6$)_;;JX>yi z0+dP5d|UBWEtV$SFFrXsbK+giz0VsXtvH>$DPBEO_RPB#uXCIfujT9Xo#nTEEWh`- zx8kh2=;Wbu-O#Fgw*}Fzjym(bUM6j%f{P2zH>nP#w&%ikMA5%yZ9l8#|alC z8hOA4gEHal^RVio!x$PI%4ImwSHT-A=;0zXCLA1ilw1_;*@T)S?4Xcy=-=FXBXSMon34n-}ZHpy~o+g zx8qBnt*Y4N-R(>GY~$MtLKW{9uNK@kzDr^3;#(IeO9$RTKJcxB$^&fuj&Ikqt!LZa z4EwnD>1*@+-L{{0<0-wUVdrZ0tJZbk$k5PyhyB`ZIBbtkvtQxMB9-B`_q!Cvu8!Tl z6wxMr;dWD!vo+>}6+faCKdJ2tXzlW_;?y+k>auY1B)z=1cbJD2r;RDS#gfeM;ND;qxbPy@z&ujU4HHI>{13> zw@Vpp;~n*fm9JKRP`p|YyW`aAkCxx1Ft&b|!q~*??JtH0y53;7^Sh*DH%?u@6xz<$ ztWVc3fwuAW&ey{Odgp5^UhBMS#XCCxVVv5Qc6DEsehX5KLPwRV-Tffeu%h#>g)kEuhkiqX#7~A~2G>Bb% z`vtjeT>FC2?>eCM%Q|${(N=u>!r{c%tV_2OjLq?mwl|D@TxVhW#w#=4KEAUsedD$K z&W5q|+Zx6`PO~mu8pht&tV@?2iM_8?m$s_d?4OihyJPeGU8-U4wpYW>?J{lb)~jyQ zrg!|Jfz;s0%>LK85I3=d>y__<8N+jj=FRH%7C3kgr;l5_G$Z^&zsGf}QR|UTAE*0# zot@?^Pw_a-=j(b7cW``5AE*0#%z7@}6X-sls0&tc;=g^yZ|R=G`SXn|P=9BzeI2d% z_K8ZV_0DT#!5nF)jt{Vp?|cILc&l0yC4xWM#!Giz9poeJgq_4|<|Ex%bKpxmQYZ16 z`AApZ4*V_~AKUu3R%B$C{?{&kZkGn?6W`H5ed0S3vXAdo4wH;rhgD<)i+N^VWdb`HMUB-tnVzQ_~MmN*|rD z?FSLB?p%B2(-yDnxZ!Df9*20GdMN##$BJh?k2N6}k8A%VsgvXB{6wk!@pSnD5qz3H zb?f{hk$%s^t6P^Z6mgW_{EkA{=ZEp#2B`1jlm>DV&w8F74P^g(?Z0`_N&j?yAxl5M z%Pj_YqJEE4%GRgfx_mK9~v2j0+1DH6yA{0e<9Zar{&AY? z)sW_Th4I}Er%zvZevwqa(fSGb7vhk)c<0B9@y_cH@f!8Vc+Gq?>fiE5Cd%Gx z{Tqh3iI3;o#7zpP20NG5UgJ4EWyO!^#g7b5l?UIN;dcJWh)#Ulmj&3mj=nFzs@q6g z)q3YSICEs$z{rfr%I%V#$3^i|wr^kLZ1NqPrRih5b3Zk^t&41qGj;gzXj{&`#%(Y) zXL?&$?>bm3=HPZyrj9I_k#ZbAd6HiIlVm6A};@f{0fpZJai+djT? z!R`~UnNR0}ZR@u!*!FP~OHZ%3*>e}9+9$4UoOM*~bFB4eyZDJ`?-Qrt&K(??J}_i; z$kfg~j9oqxkLws3IHX?3G4VKO`xy~G!pv`^_2o95r^B9go_Id3{5npdeU8856xu6( z-cWMl#blfQm?ytYx##iC8+PaoOK*Gb?OB`5_J;3y91z#pnD+5g2OPd$3HukTi3iks z=zaaE3ujE9ni`mX_|%b^v(wPKc75O4RKxSgkLx%v&F8h&&!tZdf3SUg+d^O;*O8X} zIF4x6yA`iIg?&C&yj^wm`dcO7%a#Bb6TA}p_yE=5c(&`i6aiwJ+ z-*KAglTXKK!Zv>5-AVSx*?vW4m#=(9*1z7?b?4k+3|snNd*6yzrnX&t`)Kxv8<{pu z-bmZUwQrz%#kDp^GrQdI=o8;DE&9ZFOk4Z->4GUNfK0>1peCwso&Qh0W&7&bGFR zUtqmeZeVD^;B4!2ClejsJD>LWiLF!L_z}w=)bJtRsc$83eL2g7-gACh^=ajg@e{g( z_(^Ta_g?2F{Pqu5If>t1({KOKlp|j%PoI9U>eK$=DJOpW;5v(MFMt1h+MCmn-}WJ@ zzVWG<(k9zceA_0)LHzvoO}wLc9p9QPTK$jl?E_#xf30|}{)hN>zR&nt@ml>4@tVF) z|F?Xd{;}e<`XA!;^4IGBmhUY8nKR~2pJDZ*_+PI+NDgc_XJpoPBCO|lV%)^VmW?-e zMtVW}Q-f_2KWyDQP;VdG$$L`iXpY}70o!hw!?&DfhXz2n$f3WpCcFlc!jpJ;6wsvaU64)yb z_)NYP+ZGC$+s3yA_l&ciyuBQ~;)WKbraSn2Ve9sTqyB`rF1MO{JwL>^C)#J+M7-1f zgm`P*oc4u?*YTb7bIaA~XNcFV3w$TMysY({=iqDBrSqz>_k01r^LBxKKApD2K9-zIz{f-KJgtZ znSFd`=k|%$%%`)n?EJy`6R(K(iR+j_ed6IeiR4P+nDu>J#}PYxT*pW_dR(&GcRjQo z*(c8=oR^d}!qMY+d3OB{KL^j(^}B5xJ&u>>2(zAWl4bPENVo6e>34j|wi~;4<2>Xr zZnW);Zs%EXTI-P&uQl&5Uan%Fd^$$iK7Qg1-6u}-IHg~K(i%S7`8NtT+;xuA`MNkd zt!*%E@@U0%9AuyP_QC8`zn0r=3ABsv7)1L#CI+!joaXUKgJ_d)x9wHW@wV#GIe4~t zOWPS6x9fJsF5Y3?y42nuM9o^39_2&YNm);TvPhju2zoKQE&*=0yscv8I(yLD(USs}3yvF=( z#p|p)5U-h!&i7Qde4Y2bL%e1_T|d*(V|-h_&i7_Oykk?W$e}m4?Lh3FcVw_FkW#geZ$I)r^UO+q#VfpBzmJSe(#s#>l_#*te?hka=o_!+ zcN{<;--?%?z&5_i0Q8NQdAs^A=r#a-e8>4)9|Ex6?lIMRo06l?J+wYF0P)J(j(X-l z5ih;1rhk0fYq_ln+3R?PzrFnNj{foT+m0N>>*a6#?iXo6vB`h-+}YLuSaY)d0e$0@ z1MV9ic09hF9}2Or|I+yObAnAiOXIDzed!_F#E;C->raSR-sWjHz7VgJvwytv{y|?J z-oC!${z)$w9+=*1cWX0m+8-xx@nB4Pjz`<$l&z=j<7Uno7;JwpXD^@PoL+A%RN^Nu zZ7BMK!{<>yZq;*q==s`P-N|uxZ2$V?CE|6DM?6mVcsjOOeex6Wy7`I6Y34Vvk+;vw z@pUTo&C+DQ-Q&>g8^_nh;&{aP>mHAIobK_6@mxCX`izf=*Ue8nPA|W<3q{+! zMh5lrvEtQlg0S~ToYiM!L^F>O%{vD?CaG2eDYBD zf1EtE9L1{_iPn)hf1K`db)RDWpHH;@(iU=9fAKioJjLTQ>p!BI-_j+N`#8nbe~VuMYEng&VIJ@0rC`e(S1JgILF5~JbiK7%fh|qDa2V- zP!j6dhpqULiD3IUJ-6-h$2Q;gH}>~>{@HU!W(@bf&D7Ixe_U&jCyo^VG24(prG_R4MGe#fhP zdbzK!-UjaHTc1YOI$rD3$WG(u&6zQO;uCSb>)48$_$D~}xQRE?*~g7eJTbLypZJLc zoW)Nh;w)bJ-C(VU*yl45ZWlLmU}$89a-@CZl_TvNuN-OLc%}6Hk4|Qu{ z_oPezE#mp(YD@o*^@nkC*P*|>sx^G4#$BTq54M275Toi6F1-E!3{5i>ZwA~txdmhHDd38lSIHIqa5K9f zPR05zOZ~l$sc}0E+$_~0M6UaB%YxgWd=tjo>~YJ1 zTch={Gh;?VPSGoI#JHah1hvOC_ zSIlGnx^ow}UaG?wx$gH-W8Pm75xw=SMa5Y;zHuBb16UH=cb(bcfNIb(Hr9o!t%x2)vL?}sZ^nq2q&u*~XW&1wBCkh?DZWqN1sesWjI zt&qDuxo0ooUJvaCu76FeuV)h+H~0De0^ITkc%2ng+&hj*GVjan4sPL|72y71j9js< zuMy_fH;VNgM>nmw@gH;DJuzQeC-da`Y25hh@80018(7~8xf_uicyEw-9lH;>V{21C z1h606yT1W9NN$K+_jUL!xK(l!#_~M?+{`*yhpaL8KyX9kjvK4Pq2SW+dm7{h=r2w< z`~3aIzv=vpcm}}Du8VaDZi@Zj-W>$DPHw`OI}6;1AM?!_a}NVIM{dQKI|tkbx!%o8 z)i(uhbUmy?#F#q*Zl2t&FI+#|q^t&er68*~2vZuLW4e*@peaTEK8eYfJC zkH^3*P`)v8-OsmU!HsW#b;uZVPXO0L?zpi!WWX(w+c1{z$>1h7#5x2wH#OgufSXB{!(J>(Ai2=SyykT+t7^o;QcN|GiLh(~A2L+r3zF^NL$#yO&6AS*h

)%4|vj?Yh-K)S&ZH((fgxs}ha`F53YAN3&xuVYo2e{WQ z*Gg_ysl(k5aO?0_$t{s9t~bwEg*z{D^05`lDj+=K&><9Px-X!H4B3F#t zqc?KvaEs)|$rbD5Wi{@&l_YnJT+zR8FE_}X$9I5RcpCRn1;t%*8F&4?2izvzPpyzE zt~dGjY3~I$OxG=*AohcB`PcLR05@>bvT$D`M6T$EBQNL9;|IXaZ;t&NC)fS`>N3`s z+>GM#>+mqR-v3}fl*ko*mS^|Fli(JX1|Fz_0Ji;Ci>j`j!=!-)FB#b!d_+=G(K2x%2Hc zaD73{H}HMz2lw;s4RDj>#uS%dhdQ|9=is_CMy}|G57_v*@uaTDjwz0crY4}B=PA;nFw-H#Qc_+7swEr3Lc)|73^?XCgmwzAT+u(+_p?SOw_JjL; zR{^(1Zrqr=x>VmRxney#^$PBK_8o8o-^V(X$aTM-ttI7KCs(|W>5Di1#C$*a+Tf-s zU;no9`paJ*{NP4@fOUwH>ptK0z-^G5Hs)>!Zhc!?f5{c=1OI%y3AimgZpv&A-IW2SckYVcQUvoax=!<9l-TX#(Yc0+%ULF za_h$2AA>8-+WruZo7hk89Od38_$jz?>W2uqVtwGxiwL;mREHF~?)&WL;CiVa@=Ct^ zd9fR~wer00=Gu_rj6x$ zFt{Od3rfEHaXS>;Y#8fXHJ0yGa3edR>z!}tja!*q_x(E;+&tymG?s4)+&bkO+#dTu zh2S=+z9pp&{Qbib;KnK6y0LtZ1h+u-_3vP6+>Qd*`xC5hlw9}Yb~Lypa?{4#W56v^ zeG5t*_~UjQxW1oa9jeCiJs#Wy)xkT()VO899jAQ5<6*`T_eqXJvIk!lKLS=u2|Rk^Wr>kD^!Ou za^3gY1>pLrABsx8{PWO7;8u6ReyADCHxF*+=ji&vIBxFia4EQ=A0p(6e)u!HAFc#< zjOvgi*L^=+4Q`FOa&2X36)f-(02aHBMCRdU_;ZyDSoyW}mW{bjfh*2$O>zVD7yme9t?A<5bbdxW{|0xQ@(umiR6jfi zu76LgZ-QL+`MwBlirk#Bd~4vA$t@ep_f>EMdtn_sKQUF`H^5Dk8zR?zecuANLT=Jn zzVCt?{1weNWBGmn?ijfhWBGmrZk1fmPjTGb*Y{I!#T*TjE8h3|`{%gtPi$K;D+|be8uBmjvLE&b#S9GtV7dSzTW{iPi`<`Y96l*Zj;;u zx$gUSU2tRjVjZ%^@?9U?0=Z>l`ECTR=QlKN#_|n-8z(oki>dkcU2u!!CdhR^-?jkP zyC2peXDr{Xz)g@_HkR);;Fies{M=N1e+aJcw^)Y|x$f&b3EU{XeYpfg6fr9rDKV zJpkMcxm9EN9tduYT<+{PAEttvB{yX(-)Z31$t@VmcLunTgRl-& zWBDe*&5`Td-PC+L9NY%E5pvznx4Ga(55_vAjpaKZ+&sAjWBD!sw@GfzSiXzEjU9q@ z@ax$fuNso<8#9W$2iY2YTOVjYUc+_S(PC%0zIJrCS4-PiE_635N`eWMG(^(U|n z5pp-7eKr4cC>Mj9rF>ILzWn=9d2q{=Z{AqGmx7xfz&ccnxtD{RqI^Ajni{t&z^zce zA#&Z1+g0EO$W18u^2e6sKIm)-9)PX;4cY)iad_8-c8n=7E zjglK8*ZsJSgIkz|^-UPd_damrNp!Qu-21_eQNH6!9r)w+f8Z7=--fY#9|YG!Zs6DQ z`Ix^>mcdQT#`?y{b-%7Z46g4mbjOUjkAj;dw`k0L9P4`xet$`g+|6h|dBn@_e@uVW z`VsLw3GO)M>)*%JJboHn|KV8QD7o(Qt%92(cg$G6&x2bgw`eTim%t4SVIAtm@_hx| zG`ap5j+^`Xz6NfE+!(p;=i8g$2ItUxGnVh$;Es`7GM4Xq;8w}48_Tx=ZfGvnA+WEh z`Svlm8FFLfy6=b2z^##+F_!QDzzxsCI+Tp%`z5$pavR3-{RZ4Rxq;u9ns3W~r?p^5 zQdoyLx$fuN^5Evk%^1tq3vPqlabx*@8{Fu8tV6?CzN>+oCpWmCsrj}BxJ`27Sj|{H>|^767+MZh~C*^X!CWi;`*3>UAQ~A<1}vm15Axu6xG9O&u7}hs& z_g@5VS?qtwb-!Of0^AbiTUYYsf6nqq%=Z`^H~%3xZtn9v3f%Oc(2W{%j{#TQ>`#*` zK1cP|gWS(i9gFp)`IaYF>>v2^_;_&rRNo4@?$@&uz)jM;@ciD?`g;<%)njqoLgc#7 z_hfK0$Dx}r<}LwO^h1_h@jbl@|I7WJ-mK)76nEby*F7EF6!k-mT=(DqdnULws;}=* z><9Pnb36;&0L|kFxguZwx|0Jpasu{4%2>YVg4-ZBZ_K>_T+wG0a>e(I{Aw@m_s(1l zZvA+yLz7(h=b=l$tRdgf?J^aM#*(QZhr&UdotD`Z7km+xFvE6#@rjh^__zG zR*ktggPSDRJ78+uZUuLo+^{jX1g==mlH`i@EcGkydUgl6Me5%yxuVbb^Wsi${iou% zjT@`OUEn6D&l*a;{PpZ^a05#)-@r6e{V)!0h1{4i_dak%Ka7zp_ED=ZJD2(U^&SAX zOygD{SL`47{qPXDQCfeig%13<0kUu_rpKI4V{Ml5GL1szK?@jBR6Tx z{TH~RA9Cc1zr23mjejftP3Ncey)%M?z7+q?#K6^ z`3A8c#P4r8W7Qc;bdF!dMm*1foBIp)L&TW-0=NxwQ^wqv!Hu4d`R0weHE{FfR*bp- z0k=u6XNIY9dmY^1pRo=ha>efv`!2YiGttc&b3Xt#PVTrd_aktN z3+oV=iT&Vy+?wDf$c>Tf{{Gn);Fic8Gv@@?^=ak}F=nxMIlwbDz3B zxOJ+7_b?nc_xbJsZeT5}Z%A?PI3~%w-kc)UAx^HizF3X@`)+pxw@UlIF>>AC*Z3*8 z8M=NeDlY$ea~E(cuhZvd6nDy^W$qI_sPi-8*;T5q?{Mq~QQxnZ=l(vby}`|2i2V>I z*L{8W0XIwinjO)Zodb&Nc9~fSM(Ww+@^x-y9Dc7G?woGxZ~v3jJbp0igEMJ!EqD! z`#yh|dmfr8xnXj}eXhS8cjaX9oH{=vo+P+QszZ`o_xI%v1GjuBj$6)HzC+-qFQa*E z%$*0Ws9lp>F>V__${n});8rN#z+CJH_v1DKZh+hvx$ehp6x^}PvA$!*@?8XO=n9(0 z#@xl=igBxvE6$s1ve(I@B-cAnUVp2vP1{mDr_Rra=V)|koeYsH)=B<-`(wbZ(zqoQ zm%siVE7c*Z)ZsaH9gYV#dnNWmNy(RAhZDiAlUr9@ejQGd>flew{qP>U4yS;dy9(J-M%UUkYx% zfOV*l>waEb4zBlFbUnj3ZtnNLSAyH5d_&}leEIXO0Iu&k%r{{y-)q1fCpT-%{TsNk zi!k4Dr4Ib-rO?J_~O1ZT$V{6>`P8^V`$7`?Kf4 zZBV{Va^26j7s1Wng!K(BG}RBUfV*@alPl`*S&3VRSFyg7?-;r6>+rgiZ&AtjCwFo4 zeG}Zm%~;>6v3%bGH+~Dc-bJR?-}k^Rk{dSWekj#9Nv`OJV|=rjueW>*uJ=}~L)KWn zpMsmB_YIDdEA}P)_osdaZiUwMx>5)JzT^vVOH>D6+EhP$4el77=Og5bapUhxJW$H< z+i={H#`0Yj+*AqOoH2I=G4!ycmB|(RlH>Q`?n}Jj)@c9GAlLoAWMy#6RENM3rq=aU zz|GQmK1Qy{m%lGr4cyA@IBsLc^7Vl`b_cpeWA0kuit}5IT=AEI2e|#PHV{dg7v9A< zZeqUi*N64Ntx_FATh0k?K1j$6i9zMF!Z{X4oPWA69B75z{r zSF8`4%;4S!-xAz3%?sa=*bid9@vmF90=G_eh>+|4x@Bu{gVbj!C13vfur0WayKvm{ z#`66kxcR%$tr&ABgWDw6^9NJs;~l|`-GljtjJZ35TOc=K%>5a-o^i}KORoDq+ZEh6 zx#Py%J-{uJ+c4(t1+MpAtV7@^Q|IG-z)g@FGv@9GZi(D6WA5+3_0aW2kz8?p<6mbT z2(IrwtZ$WE_vg2R!5t^p`$tprcq+L5e_+00WA1ct6LcMrBv;gzf1Nc0+!W=THJ0xz za0B;a9mdIZzdjreZkpVNF?Sxg;yfQX8v8-~#kleJeWT!3s17M| z-Or0OxMA8qPQKVW?yK(}ek9RpYNLvRfHLG1fZK8(BX`xCf1 z+V8~3b-(XB4%`~mVT@e&^X&w1qqN^CD*5vFeHn1;58}AhjOBYW*0+qV?-*0(<3EEd z`XNHD_{&`%;$9b?2E-W6izK=3*M~E~ZBQMueKxM-%U>VP1-JPSj$7SW zzUPBmco<#(pG=+SF9tV3ug6Bo73%~4b^lAi&C664DS90;L9Q4#{_FmK1Gh-ymL*rbKF_~T za6PyQs>8VA^2hB4aK$>=AXofljJ;0Y3PhgP2mf){5AN5=61cv9VxL9Gb-zyD0d9=e zos^Og?0b^rf> z+n{^{Ct^RiufuELCh7i8j9f8p{QFUFfSZ2`>zg)~ZyoFVG`a<2?z`X?$gLW48{n4d zzL7U0pO5+Xqdo%H^9hKk~X*$o>lzjR7l5fB*{Ts*4dy=VnybNp=l2vrW#@yw>4bbavNpi)$g#Wt#ia=Cp z|Bxlu{k~)+aL1_*%#`% zR-eal3zF+T-;Kb{ynt@pn7awMr7h9TkSqG(1$IAd3ho%yp{UfC-w&ICTcbKujn!du za6{yJPc_vK-vhV)BGxxVuKRx265QNN=q8N0TY)Rqhb+0GAKqg3!#3b%sSYKjzWjdJ z7TgBap=PWOKLj^Iu5XE{eh7ivd>O|rOs@NWm;`R2hHlcByFIvR`u@Hgx$u`(lZ5`r zeSK(0AX0SR94FWP{^3WM+ACOx2D$F{4?hMsK#62lI`Q>ptHI zxFvGOjJdmln|}yDzgZ*~{?h7)U$Fb(7eEwg+^R}_`S-c@0N3{_*4KL)j+^`X{u0~- z)i+G8`+nF9T>on{kB#NKH@IbTbH>~lxXJhF^StDW?^D=g1@8CW?g#ETja!3U_pb*W z0B(l9pCFLMesKRi4RLT&RNol6B47Uca1gk`H?SYZjOBX>xK(nC#@wmkHeaUiO(IwH z!y)W`7y!5OI?dz1;JAtU^4Evy;D+8rH%zYkewYF77}YnaT52m~YNlzO%ut zlUp|C4uM;2fZHUuV$59#uDHJNoFR|fVV85iex?ijf7cd;MFjpchRxJ7cC#_~M@Trge8@9E$s$@QIOs=jA|J5FwtT=(_Of$RSO z>o8_4-}Avuky|pB??vF&X#db4S6m11_a%97vvfWVoQ>lqT>k#yQgG7^tZ$55_xq^J zz^#xwrnvlkuK+hm?|&#NF8}>TSAiS+5bID=T>iLS4el7ZzH@NgM1A>nxE9+X z*WqvAhCaeNq!gE5hwH)3kegRrejRQAw?=M7art$)8Qk#4SO-r|9yfj+ZUHw-Zb)(Y zb+`@OI=KnO<=5eMaL10tI%LTe--FEmJ&t#R8#)f%amD5T-qgFmjogUWn+?UiU?%r_ zo9_WP`YGlcI2ZfDeI4!vH&1R%art%l2e?gg#}t=ehX=roeTH=?DlWet9t5{QZcTCd zb$AF|&wnvr-+A)5@$2v?xN&kLip#IVKfx`Mn^IhU9UceQ+r&EL6_;O!C%{dRTTxto z9i9TWM6Tz2dEEGQcm~|aCs>CNxndv1U)QVP=EzMbE`MEr4qS05nN{3%uU($`z2h%~ zoBSWvVVqp?dzkp+_KK8mgIsa_Hfh;&Q{q^3enve10e7784PJo#AoAt+!)xHCzrZ@g z$#tLa>)-~zL^o^9eN(D$nOxDom$CcdZEyorho(|rem}ee?ike}cp;9P`})2IZiVtq zkn6r5-Um1H6^)y*d>i0~zecxg%>4-51ifFwa}m~8+@IY3JRgIbrF=u= zitBm)JpL5i;Fq{RODg%k+wXs!T6l9<84A-;`uAa+|Q-s^&=^555FZ|QiF;{$QAu?@Ymda zSP|SX)geW$`+isn+#J;*Z>$b0gIlM3t4hB7epm(E{I_V_E-^K3tAZO_4&8_`cXe=S zdU?|1ihg*L-4EXZH%fIVkn6r5)&#deb*LJv!`k3BDPP~EIBp_eem|@OZgF`UH*(#t zXMS)KE1;V;=B^KJozCY)a^3F}HUPIo`PRsFzfaf*+#H>c{g>gmiG2C{gpI*Xu88%G zlIuR-0JwfHx?{%N&A=7&xJ0g)$G=!^1?KhN=HSMuf9vFmdBH!=e-GRg)xm$csdaJ- zaJ|%LF>*z|{COM%H@y;#o3VVi0ynrax+P=o*5HbMXpjqEYH9uDj!o|Gkq&{|cnkNx z{wr|Y#FO#gkGmZZd3xVKL~;4=bC?8f>>bQENv>EQ_`f%JGPt#GcPDV`602VqRp(74O?xW8aIWh=0@h8S(4_ zZiDhI8FP07H@X_up>E9G9o#&*{;P1@+}B}GaGT^tjk$Y+8(SUgkT&M-1FjhB0=b*e zUwrt%#Z$z;>HLg%euJ(L^Q{_l50LWp7UXf;HFOO#--E#|Qodnh?xEm%*T6a?jkyEh zCdkbha|gjKky|$A&H~r>9jrssn0pwwqBnzA%je@T`}^Aum)w}*?!k8Ffg3vm&&O$U z#s2J!RcA1NU+zM1Q)^;<3&z~VQXQ(~iv7c+!-tvoA&&w#uomX)y+%H7^4()G-)Hdm zFoek!@0)!p&;1^*47eHE?<9Pxo&j!X9dsj#%g^_0sSYV}MV~!z5qI3qmE0V; z;wJWfJ8|9fC3jrO_pOV$?uFnMe~+(I)X5d=!wdUy*N2P2jreig{MX6r1K+(A+#I=4 zWA5ePHpoqrD?Ts9&-ZWOM%TkS6pXpogPSL}YRoNy>)Qy=Z{EM+xQTi3>L=Vjy9Hcv zo)3{L=EZ5xbKP4dH%_h?w`~vN_U~Mmj$up1Z*< zZh(DOH|E|8u6IM4$A80qaG&q};3mk88gt9wmdH&Ta~}cMw-L=_WA0<%Rx7xFsFEx8 zB|F{D{ai=|+|U!~dalQD6K<64J_WAm%^$q zQF6t7m}icBXNpdqA~xcA9o%35^GzGew+?QV+@dk}9dO6UtsASu2jGgj_-~Nc-&@yz zZ;JRgou3g;1KirCSl_5I_hTvFG`V8`@YB7x=lRdT9i#7E$}2AadnW%2uKyV9-?HLv zUgqZ81UE%)Lve3;nCt!z-1?KauKRDqet^HU8eqv~-1Eg3K%{AXh>$C;-}vkAS0XiN z&y?b(KUj|Wy5854nF?AeV?rWZl2tl;_~}! zMR1$s`fkQ?bKhrPaK&Ip$Q9?!+bSPU5&x$1GvZlEa#Q4r*ZsGC{%B!@Cl|5Z)ulRw$PG}Tmh3fqP}EH4XTdr59Zac};F>;6h|o8*f7eXsrL;IPg-6R{D`KH$beIBvn)u^-&KzX7*EZrqr= zKh|M8%r|4qje{E}w`9yc7~CScbz|8Gsh5rtDU4P`DH1m9s05>rS>l-!Z4uUKC zE={iJvzgn*nf*IUatn$(o9!kgx2m|CY{kuYw&Z&6l;_)KZ1*t94U;R*^N;*^gxL>s zB{!+KkFni_lA9w}oG&7;b6>|fN^;AJyDQs0PI8-y`=8ag^*u#$gMY_<5OsK+?Vc{V zamC$gO>VyDN^VARw_&?^$t@}F7Sp)-7QoFOi0fosakpZ-MJZqZUGliinaR!fHpz`D zZi?;R4Q}ortV5by@&2gI_u{@k>H%;Ykzz0p2z(4cV%$L$c-y5fBjtp+$y;l#pSQResDuOVjW6~ z%U^#3;AY6JD=vTi4T4)E*FP?g8-M-%A-Lf%)*-66{PlMVxQz>F{Uul2f0#GIz5g%> zuGm-S$%V;c{iXL=?)BzOaI3d23!hUjEAC2cH!0=YAXoh5j$d&eFl05|sk?41dCBt;qbJDdR&0wM&thSPA*o@4=~mt}WnVUJ-C2nZzE-Rw@- zY%-gJ9Z+Pr!zDpH0;mK;h^P=0H6Cb?!*Cid33m{X$RR-mf?QwKdrTeap3GEczR&M@ zb|6zd)o=akt$)2;U0vNXOI%(rnQ^77zfA@=ZE+8C=B_iiJ;deTiF(-ieB5GihltD1 zDeSq~t5%IMrA%cw)MR;fIHyRaZKEa`+F8}D`p}$T`+&o z25y?TJq7dkJm3xzcer5wUI5(aQK&=t-Pmsv*Y{%Jwi7o_+=<7-rNHI*NE4UG-)je4 z|J{ho4Q@AadEWQN?@o8T?!E%J{=um4AaS`e_xt`=0%CX;a!c>Qew(e11Fq8?L{v_(SB*MIE{e=I@Qbt)TB; z3|L(E@3;I2xasq7J~>KUJ}$QYzUzGQCg3LN`N_zA7!S;Ke~$FW!0o0uixGF? z9i`(UMO?@f5#oNl{R|Lg^C%t)=I^b*9iiXp8?^j&|DDv^f!jy^mj1a=$MGG&jnMOF zmBi(EaDPtsSHMjkgZkDK%->%FH$ggd5En8h6c4{e9ganR`wHgo?|@rQI*eHUy2ryG zfIC3`M*0gC4|f5#ljbFH;zFj-*ZuzSpU~eeP~S9hd0o!^_ciWj*Wi57LtKvESDc?S zzZbcEv_5J1+wxP_^~paQ{+8Zvj=%qQ_V+>H4lO`^qr_!>-Ti$SxC7^+4mHH(`}04# z!u34=sG&nUaru7XXB+w|p+ob0^Svj4>n}nbdJD#V3b>ub9WEI6S>TQkxBLN&hl%Sj z1l(90b%+&=`!aC5h?^=H_ch=SUx0DeO+8Uc(s40BT%J$5k2`MwHxr%@ zV!!e8p06&v?xoDWJT`pqP2?`deyc1P_Z{F?5jR;d?)$*)A#QiUxE}$xbP4J(R4{G{ zEbY}0xBQ_(_1k8^?Imu!VBD>MTecK+XfGJI47ds6_7#l#dEoXDceG&KF95fE8R`&y zxKRDJJ8+Z4O%#l~4{$4oaXjlHE{|tJ@422g_Xlq3R^;|u+`W%+y&rHe>U$Y-M=WmR zrmp|4;-SDDrSnDkBZWG@RRXvBIE;rFaVI{me+jr1Cm=UfFn_-c+(F`Y7mRx}a0f2O zej6k%$JtrV{WcG{(JIuz`%9tv?HJ&uNrxzLC*E(1fICF~))dU&IB+{oL>)Q`#yuXm zqpPsr`iRTl*E``X*Y)Ze)OSAmJ4{@@@9(}|T?^dO7;?)8FdjJ0+}F8Q0Jrlbl((+;6L#`>h_hUF2_n!Tdc9xFe+RC~+s=ZwsW=c)zU$u6GJ@;|1d;f!lr`_FI~`+;5Ye{~hUO;C3uTf4hmx)jQbtnwiCCnVBD*LJ4D=(f^okG z+{%@xL*&Uq#lv;L?I3QvVB8ykJ51bk!MHyHu3v{b^c0NS4ct!R4i$|16X5a^VcB1? z-}t%K2DirI?%~Y6-Qc!c+_SfI_4gMBx5wgs!yQ^HEbNr3LjauA;Pjuz}&fwNq+%GwE?=-j_7Wdkd zT>br{!R@oSw>Wd}0&aW=<6(rjT-jq4uJe++0nvL2&UYe%7!Mq0k20dC)EIIedW%-=_Wn_Pq3!Gdug2X5qe zzr6t50n#@{+==(wi@=RGqQ0qu`TG)Zhltx< zFz(C1P0{f-NL=nW_xmER0JpLUb?}}oRKNWlxb37vl(-Y`x7UC>O#aps%-??iw=+q{ zalyE60Jq~HJa6_9cP~2W3{SuA$N8Lp*w*((fg4+g{*D%m`vGvdp6GKJ5B&W4n>W>c ziTCA``rdyHZVhqyd4i{QdTm-hJht_{4}m*MI&>Dy-;WG``-#iX8|`+r>+?|`1Gl@G z`mJF8eq#7r@x0k@zp1Hr?6*&W8z+COh&%Cq^LQwLuIwN#Ul*SB8Q1HJjSOzD#l6g# zyNSUaA}(LIe0YrO?=fu#T%X3BvKO%5IL_SXlck2gK5-*-;Ow@|9f$HUluzn=TLHJP z4dXXeFm9RQZx3<#`RZR?((bs9_&I|+L|pE-5$AsUJa7}FL)nXk>bD(%TYfs~>l1h4 z{q_amrq)xx6^t7JZj$`%A@0QcZ7<+*Yz`5ZGjF)w_51$&0HU)T=f7n`*l)}|`vzC; zzJN%lsNaao$FaM=`vZ57xJira?(YG>jh=!2c3C>O`+Ep*+lf11aozom0(XeG-b?23 z=I-xQ;8vcAIz%n5yT8+b+d5&A@}PzPNs>=@!&q5oeA6?;`R`i=Y8(u&ewojb2j=r zWO3cchjW43OWd-*o5!*H_;4O@%hKqtZ*kqnhYNt4Aa2s)x{nVR0hi}HUBu;ejreW5 z9nSmmNqz4U;0~RSIt&(!dpU3`FF%Dt^#hV7Jq*y zNn9QuzB%t4$MNA?z~w&aB5s5-9^3j`NASLUQs4WI!5y@?J8k32?F4RwuDi>IvER5d z_w}7?0pVXr#~X1cuJ8AN+ezFcaVM_t4}d#D+-{5Ou5TA`yDmZmZ<2wLRdI{=~BJRZX{UvZ~h}&)H;I8klf!j;m zA&cv-?{9#cxD<6Le*^n%;yT<3+&<#Qh&%D)xDUAHm(lTNaou&e8~v?7ZZC29IClSc zOYQ|OpA(0O%j@7Z9j?#s{Mq1^y@~y{8&%Xie6Hhp{t?u7Kh(h|F6-d_@2m_M{w9da zI^6s%R~;S$ZpAmy-_C;R@U-D?KXEzp+&x^^tDj{A^wcPE`S;I`{o&46aIEB$`rdN} zH~JRF1K;mHYsXz3xi1*pgvGtbnLA`~yNJv8FIsPMy`Fy=xIoVXL$_g&z25x1SV6F-jM2kt0w`z)@zz8?U0nBsSoxD!8) zKLT#|Rj6;p2=?2=_5B#Q-nWojL)?k$`zdg%h}&s#-SsVjC9TqLqrU?M(_vHK))2S! zokERgrNHeau5WSOb=V5Hd>p4N?vW!GIiBA>3*7SWqP{%^3dY?DxGCax6pXto>Oj{4{ltw>fVf|0?GD_Et5FB<->C1zxqAXP zP29?YalZ)MLE1l)@0c)z>+KW4wpxTMo@eR2kH zE3ZWz;sxU#0o)Gawik?hByfj`+gC8|OyK(8Lmfs7#yuLioy3j4Td01U1KbhfCJM$q z7Px#K>LM=R4_Ncb)sAtt0JyR5qrQU$^EVFMF5;HGhx$(3-^IWkC2owkJWjeFZ_9ui z{{iZdE||Y30JodCy#@34MBsYYp}!*q^Y<&jts-v4`-M6#P6cicachV>@pz~KZfO_l z&{;5lR{*z$xB~_Aw+^^`9G8xwzWf~Yd23yNmud}glQpPAl(_tmxcl!ZtTp_tvHbm} zv%gKi?YkcRZ7-O=>kNN;Eq_mKbk(=j;0{^bwa(l#3~uQM=JEE-_q%6utmKpW-VcDA z`XTD;7mRy7a0iH+Dj4@h;PxMb&oT87m)B_ro!4n^0&WF8Pdh|hUMFyW&irQJa-Wp_ z7yFHmw=U=P^=^af6PMT5FZ#`uy4LfT*J9f+{}5c)&#;&vSpy@#ny;I1lx$vbgTg z8~p;f9XHYVOI(gKcYW^wZV#ys6Y5JRqBL=N{Jn3D>;28U z4Q`Lc?RVzhV{nHo?vu{kdkt>cCm0W`!?VuZ`+ytY1pCb=F2~t#o%`+2hQA5o^7-P+ zY1i+Y_8Z(zi|adc?>D&p7I%R&_W^@DN?gvYsdc^I{U9UY$f)=f>9s=z#ZHYx&0P*Z)fh)z#aY! zaz`xgBxmk3hQ8$+nei~=7T5X1vj#V2aSwOqK4)-K7B}Y1ecs@9Tik`t+!uh`wKewJ zAaOZ<4|VRh7Y%>Cjm`0QWRC0aDGV9h3XA(MXYNY|H*Rr1b>{vJxRtl#d_6^69?#sz z-puRz0^DKZ4q9CI@%L5W`aee!v?qA;?8j9{=?w*Sll_z+}D9S`U|=~CN9UX`}q3?aN~DSJZx&lgZudV zCUConTWN9K$KSV5-(RA?35)AK{{9oVonOUyYA10ye&;*)+uOkHiqr2rS^oYt={k@4 zH|jtK+=#^;bmsoY;6^qxtpxzhfRSyKwPgB`;EEo>kpd&x8gSRH)?U+*B>?q zZko6?7T10Kp%l20-Eo}kATGz*70&&(1#tPe=p*jll=0oWcZ%@7d{W=r0k}PVsPAaO zxH|#2^e*bREifJ??(Z(Zts!orVBFn-+e_T8f^qi*ZrPtuhrxnz_W|z6&B!g=67}Wp zleyo|Y65N_`Rf;q+YH?DyV2id!MJU}?cIgeHHgd4uV46`YnSD7Jg}|rrGVQ{{tgz5 z`&HmZ?xB9$3j1y1{+&3)bvOsO1H?@ijC($CEAB-ddJD$A2)JqDjuec0 z32+CATk#p}w~6a}IdG%*p$;_#<6a5ecH(vxjC&Puhlo2+Fz$DNTlr_yq4cwb()SwR zb`aMm?!=F`?*Vt1xT%71uLG{%k2>@ejQd02b`p2EVEWz!+!5kNwk}k^{TR5h`%#Cg zf^mNeTps5;h|BY{H=Tbk^H$(i(S83u;&Nr~&w<4`|dV$h!dClZJBew-3#2F2hra&aVOqye+F(1 z>DxoxiTB(6!0mgO`mJExhk)Bl{zkSfRKGm}T#n5+aarGQHo87nF#y~o&41Ixo%r)| zj{&!f#`PZJPJABq1aMP-p?)hEcM!PckI?b99roMAj^zi$AygSe&JqrMaO_buQK6W1s1#PuBkuKzgdkSdtJ z{{n6&aeFMT`*ruffjdx(_i=`a%j;(c)*J)-IbL#2eeYc;7kdJAhH8^gy}zQrmBgL6z9leqtRil* zVE%3l+#cd~7tG&Hfm`|%>M&F=e@lT|L)`KmvEL@H@0P&rC2pL!JWjeFZ(9MkY!G#5 zFPOid1#W`4eFgJ(8{qa4ceG&sZVTMEJ$p*a^6)XHeg=olxJ2`@1u62Z$RZE*}@}{_YCgif7T^biw?M05?tC z-h%nNCvXReJ7RI&$A`Uv8zFrwzEG&~Y+vBEKZp9(5SRPS-QNn}4iUGrVE*n8+{)+C z-+_YpdmwN-h+DdIq4Yf%xICZpiObLLTydT2bGlK3o3OawbLLJqxE&Vv250V6gWGFy z5AJf+VY$;0~Yru&fKGb+i?)yKlXOTe&gfqvLCs|+0ll-6&CkuXYL$>8@IUL>8}39 z3~tKeUgpd_#^82Y+}FSA>hFBu#ty-8y`Q)d8aR)8^$f>#`$fR*dl|XjZWs>}=Pm|r z`76k+EEsngaFfJM7K~d3+WY_0jmjkzV7hK;-THI}%xpjuWT^9FB=ig~a0Jq}r*lz>G<@=`YI-CaFG;zHM z_8W8Eby#cY5G5}6+ehDaJr5-fZjHs=<~y$37K7VCTs{vy_`GZUwi(=Bi~E8zHwE0G z*XTGVF87-$~c_7FE&Fn_NBZs}X7LwCXa z{T}K|2mcUp_o2_TTb}(mpK*b0eeXKpmi-g`E#DjaZQ|S;fSVw0ykOiP89KBRm!B(c z+V?kK;f3Ey5BGVVm>^!^}VMIZrbARaJlR6T|I4ZyNS!c-*@AiuJe*- z4eo&DZ@II-FBsfW%irm5x%xW<+>T-VUPokKj0f(weVqM$8Mx`ScpVTUF6;Zoh^xP^ z0=MiQ`uE8!e-Ci>ci7Ok)AINFf4Tbmy20(U{Qb|nuE)h&26x!vzURz++u)Xc(TsX95@VDLK?&QpUAGkefjNcxMyRS3%WIi>( z&^c&v4|L|93f!`4nx9o*Jn;3~@4w-?&UHU<6ZAY{1#$U%b?(o-J_y`$`u)@@%ijl` z{e2j?-S43e>4N$D7vS>wu7|jMz4_K0*L9djkxS2~4iOh0w(van=e8d={4LuL`a5WG-TnP1a8txBJ-|GU-Ti$BxEv3a#O2Jx>b`m;@5?9k zz5g%*iX|-Wj;ma`?*X@CM>>v)%k$qQGhDAPJ}~_4v$)^6%$2(dU$TM@!xne_%dYdC z%?)nZffx^;qfR=dVb`Vk^cUOu-WCS8lDONG!RiNGb@+_ItsyR-FNW*Cbt?OiPwIPH z1GoERjE4^5^7-Po=Oi4j=eGgw@F&RaEttRC8ak-9;_oCzJ?zKfPcikp&%p2dd0q*a z;=3xvpR22vx79ba);Cty*G`#SeR^_5)7sT_YRNad-O3CwyWP4R?b=kuR3baKO*xR8 zy>cWs`}G;ebFx?FS^aKR&CG76nwQ;9H7mPap8B@tsc&nWawHeMTHBOhIoT`oZ0&5w zF@78Ba?`h=PBklgz4__eP?w*+!d^L&gI>a336_(+GSAx19OJj4HAj70RkO0!o2R~c z#&1KO@hj|=V7chqs?4*sv$1ZS8X$7u3VS7VZuUy>-0a5)KaT%n0((4r+oAF7m6F(i zaqMk#IxBi!(D|>mxlJ2E#^+0Wy92WMBkl8Pue7&2U_8Fv0pr?R4vlMXDLS6LWu8s{ z##IgVD_U39S5KN;S-rNlWetTWBw6aol$$(lx>LDnlP2e1uEo($QO?OvQ7$h(>zdb2 zUL}=Gt`zlUqzu(j*|+3p-%_8eef{LqYnxXF^)Am=1CC4K7nTcBEthgZs^w5FQ6K1N zHvPcQgp^}UIEBYOw=Yp2=;*lhC4&Xcp`4qa$(4?Nwz%n;l;P;0XR^i3&vk)rj^BUl z0^Q7^T%emdlyi*Fb&m15&LKV?l_s8*P zjQhFRj}7i|+YxdQ=1|VAEW5sA{bxVkvZ&!|4`h@FaLQf>X|8*Z+(t>X6DKH z*2lW!sb^+>onL(p^J~yEQ_iSv{Nu=BUXJx~H{@Gipqx4Q$>s8`FaPTRY+t6FQQ^4b zlEd`_)fXse4)w7x`NgNYUdgR}iQ1Jbm#eFlP`|)VEt+MwQ>$ND?N;W_R8U$>@~-8vR|(R&dokQ|22G8UDhjXxLr%z^5sg7tah3VS?zN1ui?xUjjbyK z*FdFYp?oUG2N}tmNyaM|c#w@--#SM>*9ESDN@uhCxh`-GG;6uFwJTays;~>?gWbA> zWa+PQ>>G4jxt-NscZ3R#V?V~B@$7AfvfFC`nUg>3)d7)-h>ylUhiTb!)zV)##`PRqfa;>jTJgw7`s9)8(Zh62Gb$I`2<+zEOt2vcpS92-X zB%UN{lV`BgCrxju&y)zQ$Fv`_CNo~Sb=9X=u2j{8A8%9-+K;Iwyj)T&OlMk=WqfaL z(w>eO$1WFt1y7x|vh#9kzu>7^Pj=qA9R1Tz2BG~V>Rq1;uO(5dKl~8N6LvZ2BJ6T% zudvIh9W9B59Q|v^(Z7Zq{cFg@zt*~z))m@Xb(nr+Cq@D-sKsV>d$smEj$K~d#xr$~ z(VuL5u(xU$&t7?+8{b^D&aTUuIqEI!EU(AoDzCG(?@YKinp;1fS=ZcD+n{ELVO(j~ zmK1}Yi4BX7_06kVme;n_O_`jZ{q(81+ON)&kM_Cq>s#yURyEYFZmDk58xf+<`ew~u zuO!qyxu&^IYio#Is&;u(b88NE%j;IxH|Ahh*Qk#|q4Ab#vTksN`6ulHrX68%0bD)k zvvGypm=kg~`+(_4Hb2zCBy`Kd%`Dhz@@BQqv3;3^*<88#w6D3PwMjo#!`cUSTEJ$t z(-g~Yrva&PVfHPxr`P4uercyuv+-7Fz^rx}Fq>UdQXPTg*l9#`BAdM?XJ|ahcDHEM zFrGYrYt0Vgt*EQdI?l`eV}1i5pgw7*KvZdf-KvHrBLu-R%+9Vj%+9Vjz^VoXn){0SD?@QUxfO;EO)}=_T;QhK&LFHFz2EqIFGZj`9W~V&KW~T)n zc^=H0J~bzvre+YQzO{N~UCWB*`lLB_$*RNb*Vi_$s&1}ZUENZDW?gk_?eYd=I0-A4 zsH;s@w>HuH)=&f>IpIhMFQ-b>l@Xf7_wjMNfb83PE#!0PFz=;C-q>x#00K! zrCo7Qz0%IEIKZx@wxO|2zXp~b2HPbQwdj84JJ{xUANvi(woEqGpHia`LO8uEicE1M8J`c4LF;m3FpyyRu~8NLz{4LWnHuJU4|h4 za=b2VSsyT91o4F3m;ocuE?^)CvWcuwQQ?$PvQPT?w-j)7E50(g2R!pG$qxE|>apyl!X!JG_!IKXao?b@}qnTFCvm|eAgaV>1a>~ioA>J^h%qv|kTuI*?TpJxPGKz(MQh3gR* zaACY0{Kt+p)Ckl!FaUz;4GMrDyMWVdP`@@vyBzuz>~d)@Ow4m=Z_orjupI#t_yD`6 z)moi_`zNWPI%K~sLy%rgt0zTm8A9x`jx&Oj(>NpTa;r~UoDOW?WYxUj{i>S4{c0H^ zxV_8A;cLqefqYdwn6KOm+~2tRw6#ic42FPujKd;izvf9+j^iS zu6S%a#8kYYNnbhy2LtTt)~-mHgSD^>wi_dFs9m-74d7s2@(ff>y$9N@Z88^C!~9FG z7y}ICwba>{6+!K2(iay3IAXsFli>ZTmjd>;RG(g3y`srwRdK6Hj$# zaQn5@fWY>(WQ!N!N6T0NLO4?+r0b?eXUR))miM67}@Pq zr6G2y*6P}3{p25NSG#Kb^{K|XR4dqx>mS+W;9qN#Sl2byG=p?WwW6I~aW*@>;sCp* zMlt@^HdL=}YHbpV;A^a1)AG~mR`V{Cd8UV1><-?q0Kxl}8-e@P?jSvy>sHmZuCNxW12{pKJApiTSybI7 zkD@iknqi1OZLQjDE1+Jne=IH7E>UYw$U^PLBE$N*tu^cUDJk}kg^jIOEb<3TEQ9RU z*4B%Agl0>!*s0(UEy!Z0ML~$&x;8c7fg0g=_l~J zz0xjdMvD%F*oPJfvKN!(y4BjT6RdxWIM=ER|fyA$E4PVLZFqP&=#IU^|T#;8$I1b!$S5PAjXEP2yNE2cAItvC9QP_13itJ8@55 ztW%3fp#I<_j9V?PG267OrT{xJ3s|1ReOh^EQ`lLN6UwuM47RIZRllOvxXGT?POCes zomO{{ogOrS`&TqsM_FK;);9_}%_ZoHFrMa8xSa+I;Qa~^ykB_{xL@rKiod`M z_5hBs3mw)%xZwo?_>FK|Pc=16&mgm)`q$|T6#?~${i?Fy{Ytoi{bGRB1`Il2gY4Rt z=X9PCUzE&CUuhp&Ai$5-+7)ZWFe4vyRClw(?8bl2u%$I%IV`9jT9b{rteds8Hm?v* zK(8>@0E7G!b~&uCNnS4Nj?&JoQ+8!=z2;h4xLr$9AB#fmR_Y_Tv%cLpX|&P;BY&01$eAotM*h-P&|wMYS;~E zr`VtMd?@!TKw$leY~!{luXYF3pW}V)R=f|b^{w0t@CWR)DxpMxUFh60gxge`)AN6= zO#zS91o@fc_f^CiVgN9pJx%L#dR|66Dw=g3D}KGTQ7wD~)Fbz+fBI*TP-vDPadU=z1~jJ0i5&x$j|LDJl`s=lGFdX*TOtLyAF6)9~t z`;<1)D7%&Qr>|TwMeiGvBlfq9vpzZgEV^2PqFe6c?(zvT>}g**p|1(fPBcN|nZ z$J$kE5tH3ceQ7zX-DIU=R=cS=+Es?ziMHm{UfnKRdriCW_8N9s+H2TlX|G`y-rnU+ zO%3ANjJ4usW*szKJnXH_g7mnDeh#$H(*6+pP#uEp!}SQZ57#BwK3pG&dk{t(2`XyF z=wjGq(ZjL})xoq2Z@+05-fq(_r}i4lrrP)iaiH-;q=g^vmR&CG6}+6C7PBoZG0@a%S~;h}ccS3R@XX|2u@|4q%+leAW6 z<`6i zCr8!523!6ac6x)e+o=X;wbNoftDV;1tae(1Z98#MmS}Ej6knPbL8rYeyVJ$@drh{S>^1pvve#s^?d91dm$)(PbU`e=EjuMdRy$3Atae(%v)XA5 zR(AaFg04t3HMP`Li?xvEz_?*MTo2StU~??5rFErTU$oZl*lyMV2SB;eHvD%?Ip5~G zelE+gAlF;sZIn}q9`ZNLn0aCQ$IBl%{r{~Vn~;MgUTL7K!>#=9&f;#i4>T5;tjC_B z!}rvTIDeLwCpS6Y%69&kYaDRz=h|+z4|9y$vF9wk)vA4mB%0RN9kQ~vv9bP;SxqbJ z4r!@t7Ee_jv~ImvYh2xO$h!3huTyuERJnomsK1@c`ZgASTyL0P>98F+<}<(ROckdx zkMl=UW_)nIYkT{MXQz_;sdzEJoc!UGo0Fyuwo9-7JpFsgY>_?Xa?=hrmeDiqUDDPV zSx|dMWYXlwq#1`zt2`_^IWjpqX~vcomN_fyR<#@)aNl@5eZtBOoq>9D+E1Tld~Uv} z>KDtM%ttt*nWm+$Qus1Mu4{%G#!cEw3oyI#9L*#7w0i?Kp_=ls1yL&XpGM8y8c zo^6e58k^QP>PHaUr5?wB_j-W(-GBvr*j(goA^v*5YQ|^A^lN5*QhhFwWj`zaWV!<4{yZDj$r>wW_DjVc`s zp8a7fks30QaYof26!ntMHu{pbAHd1_pc zWu>k%l`$+|y;i-&*0=I}^oQes_0{44{9=8CzO&}fo4s%;)dq#>df)LI&1MDyi@uJ zo#!n)Vdhe6dX~{o)0yld`t6*IUDvayb3*9>^@P3cBz8!htH@v5j@!ZcBJ_vjfpym60X*Y46gn?hv~Wo-I+I<*_)!4n^go9>4}|DOa%7S( zh%KpepVBY0Pi}BKI5SP{5}!+CS*f#3<=8A=BUZh|);ZaZI&(a*&RRTxU#ySNdG4a4 z7c4s3m{q8F*W#J%BF1k8FlXd>)VWgW0riBv?JRakoh!&++m748`NPVtM3$90%k+z6 zP-WFyY@G)$Mx8kxSZ6IBz%$lI=)7>z(wU3r&NfGA-mmG*cH){@jnQmZ{vzt!rSu>L zf|FfDw$!s)y$`orpVm5kLbTuE&*KLA3}Xgl@8SM;AB^kE%hADl!|}j6Yw-ZCvyMXN_{_yi=gpiS zAhxh%J56uHJ~Amfc`6X`jqN-BhPn@g=%^Ke&E3Vj)O|qdX_#=kIJ1-5DL$9TvhrLg z(<8*6e2rT57F+lBD^Pci57u3a5Acii5xT?d?wDl@;;@6>c)zB1#!f6~PE{i{7GV3n zmr?JS(nZIP*^Y=Dskcvl+Xmbo&M)myaUKzwa^4}+!^EF_C9Hajt@kMT!*RiSYjFX7 zu|7g?DfQyn^JmXoGFy!)ykFB>w~I`T&X^7$dSm;MS5WWX5dHKra(fT)C-v@8I?C+K zi`&B)$t#uKvaFm_%XAtU3|jRTTko20qCXrLthW{y;2G<)VA1ijm!24(EoLJN^(i0k zXT1%(fOWda-%;lZr3Wbxoa`;KrOxH#uWiNc;QT>lS0c+won^W|8N{r5i>-72Rj4z^ z1M95C19-+dX7oE@=KN#HXPNN+F*-}T$drsF+r?f(oja5s8JnODIUklfr^#R2hTFmU z{*Lt#jvhP-l(@)>(@O z@Qd}y=xnT#W{GEE7vVuskeJi?57fCv=>heGz3nG2XNI_lgXqML?> zO*yVgoqLsjrU|u!GgInwi7YGimFd1@Fl^OZY@HKVqs|-;tg{vm;2G`G)=sk2OvB!jqBZ?SbA zyoQc1s+V=v;sHEkeKI;PTqM?=)d=*IcW{4_Q{OG09Y}fyh^{Rd2ENj(-pR;kaPEwYUJkSkH{!V*Fh&Z^@E*^YvMt z(s7LL%04m!i1^0b%73EnrAi;oYV77gB1`ICO8(mx+%C=^P~7*urhIHht$K^C zd*Am_ca9I%U5gKJo%PA+ew0`mnWZ%6{bTe-J8_u~n9Lj7*Sw8-ri>#q~V3k28DK=Mq_V5Ai2cZg;uGDYpLIU8q0D z3HzbN3AoO>E?G2x-qCVN8*EYn*GD?6dW)@d*$wCq#{=uE#RIs``k;PG7tfnJ*SO`#`%Rt6PJ2v& z?FRpaIuC~E29;`W@=8?d+^_W0_KN2^s2!Zyu0EH@vhv=!Of&0#R=vg6IrT%-nd5g+2$GOVBtc_k`!j*`E&4Yz~yN0nWP zEW5q z@)cL5Rd2C%?!6gx=6GP8wRiy6S)au-7tWnsy+AButGS;v;Qg$#W@nrc*)H`y>YP@3 zKs{k^a;`3QPLjX29k+w?qunZ=W!cY*Kbh`823=OY#nw6UWAumPfpym60X$=UP``z< zXD%j(DdGL5&eBdh846pr>l#I!heLET={R4IIu9!S3=?h#XLeG%#OD$@*O241Or_rP zRcdjHt#kV=s58d{>#W5C_{I8AoX%5sWMFqjKU3!g^Nu!8hZ(#64^Zd0(gQ&u?}v+g zsk2Z1+GgC2O#V+)Jj=3j+>oi%TfUN3y~Wmfg#6)nV4byi0KZI~=h)$#(a+Rb*jcAS z=8XIob?yz(4Jy^%lEkvuDc7l}sBspY^5v#+WRP*{=K})HkAZ$gqMoU-ta^*BbEF6T;do%3wRjNTsW?QPMKD9IdJEQB z*oBPCiBC}H;Sk*v8MkJNMCv@K^fOGj9h})s?Gm3$WLX)U-EKad??z|m!=6GP8 zwRjNTSvoJCy(B*KgoQJYvKCP_J0q?&duy1^j3ZI+v+(_~xY7se4SSRK2c_tUqt7!)V}&+?6-6lcIJT1obHWL=T4;uaKhf? zX;|vq&i-14nRZaV|0^|a$g)yrnX=BkR=vg6Ir?k#hvR{D*5Uy?XMN@^t)5w>U3zmq z>x=uxJT{gYR|YmgeLbZE@WbAY5j&*5!y)$UKbP;O_K43Vvg~%^Po_NYD7QGp*0-}4 z_2oEVeYH3c-l_AU&~Hg>(bBog7D9IBEkI|o3mz}L%~0nWrALMpv~jG+lsd=BU)zS; z!TFKjs5q8oW&FyNbxvFL7F*}C-=aSp53I8m58yiMD0N;IpS?I(ZPg!ITpRZ0=%MT@ zHb>q2Lv#cuw72^?zy?XSS=)C9fgkXDuGUb=D^n-+^i?9mm8st8P7L&D_)$sC##aj^Kp$CWkSpd$-b4 z+bh;Tto+oSN_SaS#-U&59kla2kY)xezQJ8_qmH_FPwSw?CSY5#S;oK z<8ET0?zX-0MMma!ZHc-^ls<-z_6NBFBXy6E|Mq@v7w3;CyAoMeKA#}d-N_(k)mv=c zhyIAVb9}JwT6}<{wWYA~TTWsB9ccDKVAFR6;AK;m$`}}!xV@nrWD^k2)(>r6Q zf3uP8Mm~c&mnl6+f#Bpgku7!h$Y0xv+rjz$%C1C~mG{kMx)T{ht$K^CbMK!}XO0Kf zS&IkojP()mJ-ce@;+fSa%$^xvq$Y>FU(;E)Grrp>foxyCHR_#Gx{wmViM$OY^-hxC zwiUOB^P_jGxRzz*I4)Cu?y1wNx7d0|?m>SzE?93ZF2HrxN1i`pv**vZF55HuX?mlb z^-V|S_}ie)!y&psrP|w4u`P8TRQhRq#duEb;LJ|-xkQ$g>mxGdc}l6pDYnk-_oB`m z53I8m58yiMBXpKC4qN6Rox#rdlA|CoCsBqv$CVyXPuSZsu|w+YlfSkdw^N zs8oA9UTjO9yOn<0UNQf(@)LhnI?J+heMF}6c@X&;wCXLk&Q<;B561)R>{))ZK0@bN z0mDWnPBopu&i+m#bNaSJog+#Q6d>gN1d%UwE+c&!f&GA-ZJ>(8ft3l{yb8{R|Us2WNIsyTs=bSyt*SQyw?UEKad??sy1w z=6GP8wRjNTDSbGer$DZHWBqKMr-;jyL#L~YbheA{fI3$xJrpcp>nkEp>Kr3~Z4+(> z=a)UK;#roJI?I%GPFeL9TW9YP^oQetb=KkmTxWfR&ajRbn>};>QvT9|u;Bfg&YE3h z`m||NrUQuH*gm}@>fINjpI%08pDg~Q-n~jknXO*b9?nRr&n2>~)LEuHj~=q>Ew=V@}&H0+na(`sflu6M;wLymMddgAXsL}!WVQ;639a7(N z^3%3s|2cm^*_Ft$+loJ#^7tIH>MgdueFJoSQN66M76;%u>x23#;W*#aSNs<2^vRQ^ zs$n@3??XGGz8y*j;D^0ciyczm6#HozX8fmo|4}tw$g)yjnX1{5bBQb~ue)U$5r6VkW^szGchBRfH^&9*t;GfSRRZsxhk7rY zzi{^AnU>^+ovFKSFRojrR!%$A7_HU#?(c&7*C?H+=HO(x$d>vis2#Qyw~zB9PpEj8 zW#xLFO!p##cB|fE>tFUH`onR;`fG6lo@x3oSvF6uAmEGhHNEA2aoIBC&`HzAjyuU+ zQQx5uy_n0X{B3cmZ@_BR-eNvU2_*QyJ&-HEPvcY<-h|MSVFASYIs; zz%SNO#P@N_w5Q5AU(;9ak4&93W9pQs8nD@}Yd6%_S2_Sc>}{pkA@!{wKW#hqpYw;5 zU5P9!^_3~>TV>T-Y<&lwLVY<7SYIs;z;)I~=o?$KNZyIY7w2pG%KeebDV3GeqiTR= zyMf(N-!7#CqXN@9kt_9WCqHc?_Mh|PgKB(`Wu?9{Wqo_CdW)^E|1|o;alra&aR9Ef zKC>1rTq=J3w0ib}xOO&F<16cI*hLOf6F{ITdv6ca+f%xbMR1Z3*;4P(5PNP9m+qtX ziO(gntekhqbSLpAUlEH_Y`uG)LA^OHSZ^&Zz%N^G_kW31gVexGW!OHt zC+eM4x@gp~oAn|~>YX6JZ3}J>=SQDa@h!_ry=BUJcUbinTkpto=nuyQ>#fBFxX$`; z+}b}q%lmD;!7g&p6o6=NY+th%>OB;qpH>7mPZRG_??I)bVZ!a<%r0u5_*^2(O1)*u zdV3b9*m`$7k9u=lu-;l+2=CPK&w7h*ATH1zE6dE6ZN0%Ra*#SP0!{Hc_C~$qN*A&S zPS%KQsdtS0wyn55oL~Baif>s~>Mc{&J89KhY`sUxAC3#wTZ;>Do#T=9o>k z9DAe!b?#7lKs{k^O=5@CIZgiBcH9om_y4BiS(cUaKACP$20d22#nw6cGWx^uz&dO3 z0G^pTAGK)d(nazyxXg?9b39{zpq>6?D%-{OL!C!MbjyHgBPmj;^RUv-FyVG^W;eA< zd@hk?<+veJj^}cVQ*50(UqPKY9$05B9)x%5{Dt~0v%`7J`H=0xoVJ)oYj zw{>EN)HzQ6+IHLy&M$ja#j`BCo%oZfjBEKyTlE%OXYcRm561)Rti=QP#c_!G9lhuT z^(c+8-;8HzXMWR&Ih_Zf&ix^}0aSZy7TZ$iUZtP5S8P%{I5Vw2m&memypSnBcQ9<# zTWp<^uc6Ky53I8m58yiMbNuXC)r-Whs>~ZlXJr@pVl*QD`yya6Z_MjE5cQ5KT{1R7 z8?7Q!>Rmy8+cw-D&L35FC9DZdW)@l)$8aF#|P`K#RquKx+*2N>Rm>D+Xmbo&L2{CC9xE+iNKPq#-GHSg(|gt~i5 zA5tVZIYVSi-97T(w&Heie!sFSk!7XsGTnm=B38Y{*1h+is5{38>#oHIc*eReIeu2P z`1ds8V(nGG4LNpRXxK$2+Y3|7>zj;vr<5+FL~!yokuCL3lHax!w}Do%NA=A3JaU{Mq8)>?4y81t7gKcX$fw zJ{+Q>UPf-8CH|!D!%9z?oq2J)IHQN!DL$9TvQlrE^7A5P7N^*{cfEtUb9}JwT6_ra z)Hon@pCkX(lO?lfE!O@GAJ&h@7t1c9{S!V0uWTCXU88h?{b6rk7dxchRphsA$L-<# zihrp%mu2OB9GS}dzVel}>Mge3<^M*1I4)RkEiS+>)>G;@Pu$X348PQ=eX#(nRKMuD z>-Lc;QL@B@xs}sV_kj={jY8tX+2T*?KA`k8Ot@W~*+K0TpG#y}sk=;B_ff0fV(Xs% z59-eG!MbblA-q$1Lj2BKIMe>c3)WB9dk)w|rsy}(*skVK)H$Z~fO^8-(qf0yxsv>~ z?YJGBKdS6X(jrq{cgmF4QxaCa#nyTFUDTQ5fpym6L3n5CJnLxj#hF>^p0K`O*O}~$ zFM_eo?Ukr=kJ1C`341$7?2tNlk-xSbw}bN&@2PP_mX-5ynU<5mfK_j?b*_3J{o#0E zowaxX&sZNB&r9Tk?_$)RtzGN$eqCo}7nu?^Kk1o)dY3C*NQvO&T#+sHE+fBfD{c?x z4=TG7Sys+ZWXkiCN~_*t>)k(!dUIT`-dbFM>#Qf}ys~#9M?-W|C2;Ekkw~3~m41c^w}Uf#s9oZ7 zi7YF}5t;HhQf_gIt#j9hs58d{>#W6t@J{I{bzT-fTHMr$8{a79e$aJRb`kU8Y>ij( zCDgk{=>qkIytb4`+6$&n2>~ z)LW*k_lQ+*vGq=Wf_igYu-;l+fa|P})O*3QlTMmHd(Qls+P{dx`*poFyU3IofXTeE zedyVSi$>1mj7 zyEwCt+9^Jl$g)yzneHb3!eY zeO7feeZL->$c?wAy?j~k+0JqSfLivF)OEc-`gIz+%BKE6Zdxq;QFLP zlDK^R^xJb1Z|3BnW#oH10(Xe|p|fEA?gZS9671Lhf^l~SE;nP8xbk{Zz8?9vYrpMk za3cp}Jg~kqf3?<8--yAD5m(Nq;pSD=$EOyNSCkHU8WGaOExlZU=D(Ebg_=+=Ye? zqr~NSn04-Dj`6U_;FeFqIOBLY>&vb>9A|KSi+i3kcZtDG5SRPy#=Dvwi*XY=9HNZ`z(O;jq?C(FF{jD|pO<4XWr!_hHyWHS*5SROHigUlM zG`Ky)<@52t{tN2z3NSMEy*h(CMBKeN&K5p!n;Unv!7ZPH@xa%K{+ajhv5)EoY$h|A+c7ncHM=Yb@?f&iW<|Zo9?3=tEZ>)*0L$ zi+lK6uIJ5WgF9$(OYe2%wisM*ni&s0$GOH?D{@zE1mi=6#l6IL)wj*?H%?sne7Ss8 z-L>md+{*9W_tqQSl;!Vto%Kx_+%DqsbMQOeu$!a5XBymo;_^DduP(g(!Tc0JYv21C zaO3SbPL2|n$KM*~@%Jpl-}31gXMFuO@70GLujkVS*C#HI>s61s#@RUrH(_y4b>^OD za62sST|2q@dm(Upx5ah2UgGlg{3*{r;;3&saQlzL^ZXETdHw8-&sToNEzT}6bSOR4 z9CunTa~*dsHMmjYa{TtMah*S02He4K;BgTrF2~u%&f~*3fa@_zA6*zXuzpSXOyZPw*_ zymcDfgyrv@|8>>(YJ=NBT#ko7?B^N}*BIPhi+kN7SMIe2cgW&Kc5*$>f6w5S&cJwJ z9r}Od>hJdrZq(x5@GVz=e_(K{EbeX2I$URP(-!x#Ay*x`3~sl@z5S1_I$UpX2Q2On z_jdL727^0lao_*EtG_=qxRJxmID2xTtG_oQcV|4$$B4`GN%uJW5pWZ`A~$LI>(0H& z(4mvKJZU)h+ZUzX<_|X;++O1Hdf$Ghxvuwh8{9#Qdx$gl#|C%Q(&0R39d0qW<%eUO zu@247{{F<^R$APYGxw(kw~DwN4}H!${0zB$_&h<%^7pB)y2it;hQFN__jzaTZNM$1 z_1|9N^7`Z%r?{?z_W-wdGdzw5iOcg}_xo8t2X5Ks$Q>mv&wt(TXZ-@W3F1bM!1!gZ z`~9ptfSbA;=hZRdvJT#_UG@DXa0iH+u>3vwM%U|>Ujw&-t}i+)?s8}DZ-CoJ`u18} z_xpOk18#XK#={VC`8vS;zTWSFnwaJFPT-E5hS#xC;&Pmw^9R>?^&f!C z=ddc`@_h0qFCXl{Zrb9y-_Lp+xbbb!-)@WR zen0C;;BvnW5SRPy$NzR6AD%L}qZaozXYSJmH{xTQ@qGR6AGyv`pEbBXad|x3>mk?q z&hxlA^8_yfcbK^C7WV*W?n{OaJ(dnDoOO8F;0{>+*1h1W!>a~& z)Z(sj=DucdBQr71`1;~=&d)LZ!{GYF+S>HE+8{dcG%;I)CbKe4PKg}o8mJaUE zbG>co&}I3%_!-yZ?Hz;LXK|~Xx&H=k_sMkLv~-y391riJzo#JAJIai+1>pWBA)aTplMk{=Vz^ZCiueV{x}|=6=rL4iI;H4_}LJyXs)t%q#J|&qwqEqr~Oo z;;#LtIUW}~8{Eijj5EG}+<4hH9sS+I;Kqo{-%F}E;kl3X_T;)PzCUDelf>ocjaJ<_ z_&}~K-Ol&+H@IEIR;Lt-I{heiS)5PU|8+PuuIR>|jxO~32b?xDf{?0YH{lwkg z!`EYvzjFv}=9P%=sYUbxBNlhinY+l~mdDIE`%?d5jyfD?aDC#kzB|N^aO5sFxC!F2 zzOU`*s_#;R+hK9va^@ayaCbG~z#GxubJ z8znA3pSo;^%5vT5S-`FQDC*Xx$G2Dh8I z9KRQK9WjOL%qR7|CWAXbTprhNTjF}%vd-X+5|__I$6ppb;b;Cl4xvbfJUb1yKseZ=K{tKHAF-!3w^ zLl$?nGxuWPj*`CKe2g>J_jzX>E;0O#5SPcvpC0Two?VXINf>7_;&S}DuUCHqxMi2p zdK7W_d!gUodd(8g;pKZ*05?J0E=%7RH*$@KZvr=Y8Lbl#m*)>}t+_Ml;I0_Yt^zKX z9VRZHH@98ldY=E5!7W>WaVCFvOTIpLz3;Nvfw>O4y zRzuv0>-$~gPDXA!aamvYb^B|8E2Mx|4{`Z?eA-=$9nZ(tMhFSXAaVJ8yk_~YrtAB2 z-S)ljM-1DA7!S-{=ghs%;8qZq$A_J_cb)g$XmI1i<$mjO{$6vp!A)7*o1D2nHMm`t z4(F|M)!|ly+fQ7cM{QASKF{Ih`0~9TgF9;Z`@ZKo?%WRC?kFB_kwxbD&HcXVFARTu z;_`X^fOW3(l3yC!8jCy0nfp6~o3^<7m$;sX?gVZrjb~lN<>Sr$zUd!6w?(!U7zV~P39)aiM@;JsB9~XE3V0XUc%8TxM4*)k7r}++Xd0yhq zeHi^EZ&JkN`Pu6GsvOT3j~d)A;_`8El=FJ^V+Oa6xEyESyvcQZc--I)Tii}(?h^*L z>^O`EK3^R3wCnxjCk<{Tak<~hPCC)C-<~qKH5PXVXYSJmx1G4$Z`U~M`z&x{aXj97 zEPbDF*7teC-$9G}j5GH|;C9e`5pOZZ10NUe_w`;f{EZNI7Y|=sZ*|~dw3%1pdw+|_ z0&zNT#)-@Q=KdVhE5J>BnZEBtTprJ=TCRoXdt}}DynOHP5#7Fv8vO!A%mE`|Z3%k3Hgm71y!<0dC}YJa2Yd+>4#L?;8I05trBd9-MY@+Rfkh4DJwd z`FQ)#`T3|(;MT-&oGe{xo`+s={=LBufZI0@xlxPziZl1W!0rDW_FENk`Fh^{cU(RM zZuuJYH)U~`JO4h+$G{!k8@Zjt<#GLw&cE08DR4b{^;+C}ow+4@NMtwtPR^jE!zyPT zHU=*HJ4#%hSHFMx>re8&d{W=r6u9k&()HUij9;EtyFV9H3f!)*AU952J`cHbw=#4{ z6PL%|#09S7`qsehnT!5*6PM3J?(3f005{cu@jF0VKHk1?o9lIK8E{AF_hCke%g062 zJ+9pCfZMwSbtpUDoJX}ebIXA{v;%UZ#O3kV{daP{09=mwD&q2Sapzgv4e`EwQs3Lz z;HHVo$Hk2&ZSrzHJht_{-B90CQHLJl@^RtL-NW#A$kO4a6BfM0KID`7-rfec^aPBD z?FsU?hCau6$v(jCr{`&-#N~K!f1dUr;Fi~*zE#BK7 zBV5;M4>Pz)%ips%bzLtx+~9Uv{zm@j%KehT?ISLqH<#?}dfxo9!5y}AXuH|f-y?zB zPw`N8BE|z>54j(2K5!$ocwAHxm*c_xc$*2_0piwJT=(PRDBxBsM}ONbuKRd43%G;C z?XkG-@q09I`5ZH7aX)^>bv&C5+!X2SorLkg{pLQN%>{0nbf_RMk2~(;!#qQWxW!%n zCD(E17~qywV?3mY%h&Vn^N0C{zg@)T`OYq}vP zjE4kq`TD|r-Lo3F(MHs_-Qqsue4n8fxc*7#Z#QxIy2br^eg$wliQ8{+-LL2CfEzmu z{T;S+aR1)HYT$P5joi|c&H0Y|@6OZ%H@**Yqr~NL(*5^g)&SSr7r9jy*Zp@~)*_b< z>@;zC+?jmSL*L+IKA+V0lE5vc-@Waz{B{4m?RCJ7(sk^h#dZIE+GgO!c0zrPF{J=HwFZU5@=z4;txZ0mdH0=J9qqeqF$ z$Fci;^b3GH+=RzP4RLwB#GTu2=+I&5aR1M?dYIdmPwIP@0(X?wJ$o%3+}Az70o;)! z>M(5S;Lg3$(4o8<33Ir$xVlw4SkcAzaxiym#5fy;eGGN z2Dgj2JdfJJ`TpCl3~oPh`Ft_E+;zR=ZsfM$eg6^S@_Bx{*{3<4j|U8Y%WE+nm^)?Z z8b|I^z%8Y9aG$uWulxOg=YiXOGRAMh;=13*c?r1Xrz5w6xZH2<{=N#_zBc6c5|^JV zcGvfH;6~OXcZj$X@3#@)_LB~!%P}4%-f!;$mk-h?aX&*D_g{Tcn)l_C`rbzdH%?q0 z6cRVMUUz?NaFZ6d(V6>+!R@egc)(eQPYrI5!Hao3yx( z&1`Vw?q~ShLEP=BQM>H>xwPKCT(^Di2!q>8TwY&qI^b=d3g?OhJKsCf;0_U&kBg6& z|I?8>%ixyQVVtqQNoRlO8r-PGZFc4!V{of1?&;3lV}V=sb)4^{i97LlSOnZ2;&xm9 zy2ry};Fg|^{tgg#;_+}iaBGM=YWeFP4<`Y)m$;EtW}Lal!zsWmOQQ}ki|ZZ_rvjG` z(j;;Dx$TGdSoRw4%O@4T(_nDBh`Sp>s!#dnfAZn6t@w9d4ekJO`C;w4f4=F+tv9&d zYV0@mx5nAuwFWn8ahE%DlfWH)5dVG18jHKinY+&Lw}ZGmKJ2k>3!nQUpVar-fSant z^II=*dHg*xemh^v<%9KnFJ<^UL|h&pwtcq8k^41+TbeMBW8c}|w84#9+@qYi=Na58 zi#x}ed%nR<6PM%R!xqiw;?_HJ?=rYm#O3qFEpNK^+r0)iO=x{1rjn|nMwWcWK^`TGNBe+LZisKxDa=00w4BMs(x=tgJm69zX%T#kpGmTcvC z96x7pla{|fYxy}3L3s@mzV{+7-P{`cYhE3e8Q0%7xHZJ(aq{0M-^-``yzsvF zFN51|>9Ez|r@fRHFyrsL2DiuZ_dm}5jvCxSi~F84_d|p0HJaz4|2lI&F}M}P<<5Hd z&o9q#)Av*0#_0FNs)+jqf<67lt+U*?8||f+YbP#0|8VVoKXc@6W^j8gf1h#ocT0mi zY;m7+=6=@TmN#KMu)agi+^r36jJSLp?|0r_C+qs>y6t=08Qdgsd0c;Y|LxMbvUEG~ z`}V*sKZnj2#O3&PU$5TD@VDRc_dREScQv>p7I)N{8!@=$NsI^9_akTS9tPJZE}t)+ z+2q5SdVl1)?R)zGw~y9S6U5~>b6>BnF#PQxF3(dpI`PSUbM;ZT^SuLso1{4FwfuEo zuZ{w@pSVL7*L}Tu3UDLm;&D;B&OBeZuUAhs^onO%Zp%;=0Gf9N-QRchus#$HQFU zaz96!G0yn;oiz`g@_XKwPwIPBr~}1sjJSNBcfT)kBI-cg6mfSY=iKj$oNVaOOwaHkC2$9cTiSyC#yYs)7g-J5D6K13T3q-0A_?G@ z)A*1eE{{9z=b;AF_iEI)gSZnPcbZUN;`S1E;^R&W>U$0PJ7oFmKJKgsZaZ;HTQMG3 z2lsL3OyCX?H)?U+$DOYNmyeSw;`03Ao>%HPl-VSw)GsM9?9#;L=O-)fbNpUt$wmgZ z+tOjXjZbyEjxE{P;BNTv|F;4hXXCYEv<;8XY<4o@HX(xninmY2OJ;3G`F*F4&mq&C zl3e{C$)R59KOZ%NWY7L{yL#87|D`ER%WuMQF(+sLFBq*1sbkYkJ)#nr(7*m3Yb(TN+J*r31$1vV(KL4gelY*1i>0vic84UI*47=evbM3Y{*YNsE9(wvscSyHuKA#K>yyn*t6L6P zS+}a?;DqOupJ_ga|G)AaJ3n8{oi{*!^0!W=ZMQk>N>TgSF4y$<*^9xn+$!Jw1nSxK z0saoZ&RZ@XoR_t3p=X9{^Ve>o#0xRYWS5a0w~PJa_LYcA_iSri)7Z4WaZgdoeuh6n z<;%Wm_Gk2K_?dNk_Ye3D3~pz}fgCsDR(l4YM7`Kg9kW6>DIX8dN3R;<>71Z#pX|6j z>=(DIL_Ci!^^#i2m#tTv$|p%5wDP=;vrsQl9A3}4Jx`%t?59pz zDV&twU(H9a_P-)e=jhut&ujy~JCh_kZV&s#?UG+Vi;9A_PH8IFPr5LB`0J<>e;=m1 z_5&3iJIi^0OX@n&p3W{9{pL+sgwJM+LQ5%@}*9bMBTPd z-LyY)wt4*dY5dIJdush=-F(>=ZlB!F=QUupBmOk?zm+eUtAvyCdzAU;G)TIS=Tjfq zaeLS=ZdaI215_?ex^O*R=b%nFs(ap*j~so!+?Qz|8|IjfTJ1z zADukn>71bLVd@`l5BtUKk~&Qm1?_kmrE){0ONMcqZ|Ja_Y}av!%ZW0&Jb#A-*^ zv#1mMr(+VrN%{LGT(`c@-sbaP1@Y|t_UAIP>kS@#~xWLrup2t3Whup{QW4m0_q}7g*=TRs2Pv@K_bdtXtl#fm+;^~~A?HaP< z_OM^vE~(QLap2kUl%#Uy7oslAuDr<9>5OlFbc5W-?PI%K(@v`$ou*G6t5YYHOOr0l?rKM!=xc%ALC@ZQr`*TwW4m0_ zKC2!65Vni`(>V=7C;9v3`RLS7y6c>v?H;n@_OM^vF8Ou%Ns}wb#8V%Y8zx=aufX2{ zEWHGE;`5z1WsCb|z1+SaAF|~QTkS}^ggUW*dfBx?C;1}<`RFu4y6c>v?LoGq_OM^v zE~(SxY17B(G)(1UqzkhXmzwc(NW~8hl>4}SY?o_VM!K+l$KOyV_K)*r+9-6AzoU|m zPUXbYIf2_`$L(RixLs1GX_F?8(W#8e^^h*i9=Hs3;_t!FdGPFBxsTh&cDbgNRy+D$ zMxEF{ozo71bL3bNz&uwUG+5^(`CDLPqeKj~%K#g-5jUre< zA%H?bg$M!>6r-R

eVgP>J9W9I%4Qx7JzfpR@PwPVYJ2^W^!yz|Goc@3q(d|9{;% zO-|AlgN0AZG5&tmL3f|G8;`*!@}kDF`Hzr72I52Wu0GBKFDi)N_gS#!T$ZdDSDPc-~S@&LLJ1KGcWUd;RT(@t* zxj)4?yz0M`dS)G8yQ+Ec16}aNyjEt{1YUW*%d4jIlQZ`I8a+*p@prQ>+56Jqbsv2C zv@F%va{LtT6@Soa&V3t+d zr?k$?pJ_ktCeM;%oY!wZ;gVoK!JkjVQhj;HNAo`61byb*|09vlqK-J63R=&s<7;O% z4}PEvzL?W0n&@)M>%6*hLG9Mr_I`S1TJ{tCAunnyJ3hMi3n%C^>%4)I8A9i zvyQJ_(meQqF8E?jd@^@Am33a~)AoMK)@)9RvxF1;`7|umH{uPB=S(| zh{LJ&N2zDl@wKOsr+%OdzL?YDG|}ZWqw^}t1+{CR5l(o1uy*FOyLk-$kQX&Jpid{{ z{w%(r&#Y4+kYI0bO#VeUL7zGIB+_~qb;RM+RqkdTU%Rb&@B>}&#hmyTdQ-4&^Ez)* zxnOYmbM}6EMnm=!{2?!DOez=TS9`(<`q0nuT_o~36ytD8X+5)!uf3o;;0LjE{QWmfA3u3w6`vH-lMPh05{>!r(vnStm9+u0a*w7%(?F-kJwe4EsIay0n9pn32EUGT+^JKyv1lFn-=7p%~k6;62Fa?(?-{w$Bd zAM&EcY1hZ!g%k9db>2%_`8jbMPSw9jJ+qFlJ*9c@16}aNoP6)=P3yeO7lg~yZ{_dU z<Irn{}m7f#G;WQUfS55Qar>{%l?(LNFAz?_#TDxO%RiobBagu!@}kDJYXe*K+(uJ?Y@%Fl`8aOx=c9qDOm z9{fNTd@(2A>$|qjTTm`oC;cVi1g%dz;pDq`tnUwr5#xg6qw-JT1bt?iY0}EiiLtgh z=C*NuN@zWI+&%8<*9U%}3%;0>@Ach+&YM&&s5^b3aKifwg>xVJ1dqWV@}kC!<70L~ zI6@KkfO@BLOG)LtfNa zaD24>C7htotaCDHeI9kh;Z)RmW*uKUr+M%LUGT-6eCP3k&db(?3u+fHwjX!zIO^2n zc?|xL7d1{fK6(!cC+IWloI+ZkPaSbMRkWU2$Jd_JJotew_+n1J^Z1m`t0|Y_{rY!X zFR?j&@T;c;oZ!!=VX3~F<0JiV;RJo=+*3*G3#cOwr`d<4o>|A&u4*3qKo@*5C*OIz zhWeM<`ziBfImY{XZ@c#T;O`K?pHIV5eNC*RN%{YXFX%Jpevq`jm^$KcYAJWKj;}qZ zdGG^W@HOcC)YN&C$_2HjzapIQ{OOm+jQ*U*;179GW7qLf{;zO?KC{k;h*O?A;&AFI zce9SK-O)VwfiCzObbjjUyq0o7?e1mvpMq z*CmnIE%;m_Ug^@8B)H`q&ZQB_2S3wjl_niQ9dW*n^SUq0I=*&G^S~Rr;A7DFv!nCs z`gKF?))n@CzvmfmKb6Pe4|$QJazXy|ql6Rmp`YVNh|@U5IGmDN&#dEX_f!Y`B=i`* z2Aw|>T0eEAz2CE6m1CSgpY!$IUdQXgpHIV5eWQ+#`lE#t^qF%%N}P_QjyRmMTF||>$*b*swa?fcX9nx5PoI{h`s$9K z(VfK~beeNNLA;KkjySyLBI>GX9{lumY5$q{*V_n zwjCeEr0xT!pX+^+IPsgmaX599`;PQ9H4lEE3%&+D{@OY(^9|vWzewH}%3over)U4} zqt9XueSbR=%hm>(|=*=__x1Q?Q@l4|!2z#_=)xc+m}gW}O+*x{*5Ka2nNmW*uKUrFrlJUGT-6 zeD5=6Q2(341+_ER$uZt%eDs0cvv>^tkQX%;u#Qe>JwZ4@pIPTL(z=N{;&3WzJ+qFl zozpz{fiCz8-WQ^anIyrw6`)tSV6b+*aN0vVPQUKtcX1Q`kQX&hIX-&32q)+>>zqy^ zi_{T^Q$_2Ub$snf&4VB4f-mOe{rtPm>nRu1PBn$oF52;$v)>rJMFfAyiyCW=kMwTB z3Hr=BXAq~CP)8h2v%5+?vyQJ_)jartF8E?j-p{}5ypnQheOz9@RlX&h@HvQcCZE94 z6Y%HLuvA~u@sWR`_<}xj?wQ1CGj+t_)Kczd9bbD+^WX=%;A`OL-|=--E~wqTQ8+>C zQ6IVUXFLXf$cq}gj*oImI6+a$)_(NXQm~(tI_Yh9dXV&>NaXOYd;&3WxJ+qFl zJ*s)|16}aNuV0q@{5#gU+1^)~@7nw7@RP5+oY#j>pO&Ti%2-E}dV2~l=rrfnh}Ut{ z5r
zQ?Y?ULrf4|Ks7^IG!r?>fJ%e6U8fCA^^dzpwm3@ELmeL|)WbbNpnUB)p*0 ztn(S-#c#G?ZF9_R<9t=$OX|7f?r~M~;0LL$df*VP(ZZ)0XRzAst<@Isz zdp55}loxzjMIs!u96!aq#UFHaG4lG-}BFC?3 z_~!Cz>HOUH?Z;#37MoY%MA={PDb=FiFF1atpDetf)2wt3iF_$_#Nn0HdS)G8yQ^O( z_<=6?VqPnjAHEttkmB-M(D}2<2WvEM6<+vU$uGYCz(G6)pU8_EM;$+NY2gK(W}VNG z$d^$^99}uCXV&qx)0ziA&;?)2YxSyCEBNyod~ipCX?ERJfp&a9V$%Ed#mLDPs z_~dq+TgmY=zmM>OPP5jzB=Qy15rzQ?Y?SkgP4|KuT2wl)zwqjZKa6N;$yh=KM zO8H=onIGA_4pv_9iM*(>>i9`LMR-A{S?4?wxt%)V@T%=A^~^fHc182x2fE;kc`aYP zeA!Apfw{b@I=`)autu*fyzsi`xPRTZH;=(5@}kCu<0rqL_=8Tf&gV(wE2$$6ua@#R z>-gGr&4VB4f-mN^YWd3LIX!{7yc#+`|6}{{IC+~KF=z=fiwLH7#@MWvy z1m^Ne>-@}5?ERJhsm*KW?d5}&#k^K7TeEUSR!(3puY%5>Rz6r`_70oZcTQR!@Pbd|MU55L&;G&-I?Xy4kjU3i zM;u<&jMOvh_}XR7gCFREFXok7k;|>l$_dQnRnhtL%BR0ZM|cGn0jcvv5AJkdFs45H zc@Z0R$4~YE@duq|nJY7(nKFFK; zxy|dw&kHa3L|)X`ar{gksQba`=Xzfvk*}v1XMc5-|Bm#uG!K5D3%-=sz}Jr*o!?YG zSa1GLo7c+m#{~PU?-Pj;V-kEcf94s&3p&j*7ZR`kp^iAb(pt}~<7+Rd4)}pC_)=c{ zk;CBT?yn?t|3dg6ulP%w*V|8&{RN-MiyCu|pXM`#7j&9+E+Ua{ppH1a3R=&s<7|A&E@>Y8Ko@)|FaEKJ;O6eHvd&Nb+TLHIzma2n?*8n1KlEWP0H0DV`hCsu zlNl9W&}mk>m_)vbI^yuEA1w9EI=*&Q^WX=%;7fVo<@TceRnz%X$_H!A%nL7QK4tsS zC-E43A}?xeIerSy5`WNX*13duy@fikwmIgualNpu{M~W)xS@IQ16}aN?^FAJPNAjq zI?4rg7w)njhpBUSy@|)*4|!2z&+##Jh;V{Fv(BZYb&5LTa9U9AW*uL9Ui07wy5NgB z`F>8Jr}Of6+mFA=d*m4J1O4ut=LDxN`15I4sxPfvkW)KUI6)u!IewY6zLjDeP8qFd z*73EIng>771z*gGpFB{oZfTuYS1uTA{Z=?VUOU!Zvf_2zgg@j(jd{mM^Vz})`pi0C zA(3yRjyRkOTFC>`gpYlP@%rfBx zo#^Ly1&ORsjKeFf^~^eEdrH4vJ=Fm}2|b1{*=H-3XAa|kgZEiN*PB;P;GX!S%?)1{ z_%$^}Y3CeY&E>)kdd(VF5;uNw7l&Ix>zQ@Tc3tWIUs zwo>Yub$sn<&4VB4g0FxR{Q@AD(~Qo`|3$c<_GC|v@&3;b?|jQocntoK7d18D1-a(0Oyp1-07`2q%0V{=7RU58yHQ zLtfN4@A#NJTsT3WS?4Me`F`q%!>Oy>%{snzTl3%ty5NgBt)Lf%E~j~&H~Lq5KNbEa z$9Nw9gj=rpB(Dp9J`GFtC6x83z>+$@hZVRddexM7!0#5Y8 z(B+iW`ZLM}Ys~#!IN`d?>V2*XKJpEJ$cq}Yj*q!D!U_7!It>!}0qTguDW~whAunp2c741+I6yD4n7m6?FGwWPSB0oqSaX8II)K$|w`04A?{(uu*J$5Bgc52*{nA=^Sbco)38)u#_=(m7f#S;&b^*ERjDHmr%|nE*73Ddng>771z!QD zHH-ICM(52a7u25nuW;H!J6`jzosZ@w{2?!DEI2+|W5Nmg%sMv^r;kua98N{8XV&qx zbD9S~&;?)2X{G0RWUANJTG|K%`N^FDhc@WX;`Xn%JI=VLO4O6 zIk!oi_+%J|Q$_2Ub$snf&4VB4g0Fy+=lRo=&TIC6?}SvJACccff&H{Lapp651pa&) zmg=iHKGN%i6ZDyLzeSurMjdfD&90StW*uLS)IxqJq{C*CpUV5|~ zKUo($^{&hI}p9{fNTd%hm>pKf4yg&Ne)@KgkG5AAX)R=R8Gz!8A`pi1t zAx<;Y5rzQ?Y?NQBxALxQFe&3J2-7R{anbUba<$~I&#|bCAzDvL4hFKniKjcM? zla7!13E>2NW}TZ!>uJ;xhf`VWnRR^aqUOO5bio&MqKDlgPLn#Xq+C$D@_6C&cy}5q_QJRF82lkGYV0^ZN*ja|^qFQLt~Q|3rH~Wl}b$JCzgs*+q7IG>UaJ zwZ2I>L7!RS77}?jb;RM6)p}+fUpuXN@B>}&#hm!VcrK?=omW;as9oJ%IN^Ebhtn_T zALU5EAM&EcqT{1o6i(1**145LewsSsa4Km%vyQKw*F5-vF8E?j^s;3Ur=relD;L!6 z?IE1-I{4pddECJt@}kCy<743^!U_7!IzJ$-HR_1NX->ncewI4oaB3@e zvyQLb&^-8oF8JctEz3ODpISOEy|=xea!;0HoS!ajJn7}UF8uj4EY;U@d`xWldjb z4yUGaH|zM?bi&#dEXFQ^XqfiC!BPQL2}Nv&U2E~s5SKse#L%Kepn8FK>u zkQX&(9UpVA5Kho%*6EPei>M-gFk&4VB4f-mOed)<=Nc^&0axL$t0?81Te ze!B4K>**(%>G!`x)Z=O_IrBQ(g%k9d`9CME7gI+ZPLo>CtmA7JG!K5D3%;0>@B3Xz z=jESaKkg=+PSr`NXV&qxr!)_KpbNg3 zlkfZ8w9cz57u0SYWOLf@(a; z>(YMa1>O3*{yA)G@kT`d=M0jZa-ma5-{9Zx+!k6tlmkX{>fbkPZIx6vWFHqUm*d8HQm6e}IW9cK&cphMg^w;hp4XonZ@)nD@^iM%`VZ{+ z$y3G8)W_`p`g5hfbeG)^9i40Ky0s%DuUC`)+yQdj-C6c^>qhA>?Ir!?w@Lk(_xkHk zjrser{-9WWv&>6fF6-srC+iH#M}Koa$xrPe5&ekGr`dY4^K!g!r|hShJ)^CIdX)v$ z>ApYw6|9R=pzTED2%JvUa|B`yO`y{{h4LP3OMPl+1sh7EU zX}zT%OaAn268j4{joCNKc;;sk%e%_DGrLJ#sQKql-yq|)f5>?2opPM`w8ZKIdVJl| zI#Z96$B`o|G1-&(`Q2r_yobcmn$~qE=y85`)%y?08`bwC7QSoyNPWdV9#AgPEK8l* zt&-pQqQrDo`e$DvvGGfZsFT;f_ul%4-+z8je?R6U&L#YOFz&`eCz>yJ9*!5*+w+@0 zkmJTm+h6t~`#5u%eT;gY$J+JKk65}z=JkFoJkqyIT)0SL>MDuz-?Ho1KPblwX^Eo` zNFM4UW>4067mAMDMYf*qxz6$Hopq+|x~+%h{qM#O{yutZSE<{$z^(^fZmfM=@}}xC zuXeGmYySN*o_DUJ)xRTo#Y=3R$(Pyd<{px~sozRo_meVS_`dYd>?!*!b)-G7c!T73 z{%h-T^*687dLNYh(T#GPd9__Hb-&c<-eo^unf;c`Ykxpu?I-p;tXJJ>X&w20>HHr_ zoSKt5&Bxl0qlFjx>tmgo{$0W5yy#5*+0IXY-aek*F2}XU$U3=?>-twnL|r!)USrpp zOW4QVd+qt7k6YUR>^b&)tk?Xh-QT^#J{~>8UI+8=^T;?xoPM6n&wgKGa>Ulvxkl@M zPh$6LQh)kXIWAu>`SZWh@vmyWF3|m_jCX%2vG^DnU(mnXTl}l7xAF$bOWrE|z1`$^ z?lBVQzao$R z+&z&Z5@^YCs*OcRI#a{>Y5a*7!^D_UE?=Kif>^bjS zqQ8ELtd~4p>h#_$vC>q%xK5xG>U&H6R8jJZhsZJNwGNZx>KS%_?Ki@)s-HhAzFo%a z_t<%z8T;!yy|3-B-tm7us-Kj3-9JcvXG-d3UToK&xxud28L{`z^v~@2g_U-GqiG+* zH{#T5Wxd8;cHQ|Cq`&kxsh|C})S0{6UvKn!@zeaAjL-gF=1uKn*TuS(tL-||@0a;A z=gYd~_ektrBYD$bv^gg~Amj4~N`LM$yB^jlJMS;er(|Ao4~eB$NJM^VjeVRuN{%a^ z)p(Zre9*sM>rK+%d#dEkzC-3UJ|+E`ze+6pP2%XY?De3-jm1s=yvF;aKmTrfyt!76 ztGfvQ=C1y)1J)Vc$>y8+r#vq6|CKsZx7+nG53$#^_aXXs6c?5$uiZpnIwi64H_hp3uD8Kj_$(uY~V(vF~e(zjc$HIwnJoP)_Fj=t2 z=l*2#Ek7j3GY?B_{99smPS%XyGNar$oQuQnu3@4xiAa|s!rTQ70p#S*()L`QkK?Q8BDyWaH0_PDFF zrJt`U9j3lU?fmM5eO%Y;!MJXX>(97;&DX z`q#0M7%|T4I!K>jPVrS;4@zV?FZfFJ0BuR-ra zCAEH0xuEvcvu#c*Qm+U&!5{LX#;oIGPTx;}KC{kmh|`tS5r?i0m>&z3UuTn=GPLo>CtmA7J zG!K5D3%&-OpGrC}^Bm!V+WF_oG0so_^Tv~d_v_#fc~RrE>qDQ(n$4e)_u5PiuSM|3&>}_I}DNw>d4GDf^ig7q~l)IK67@C>~KhOnVyq|oZ<7w->DdmC%W>yF%yib1cPwzXB z$NK(|7%?t5J}M{c^8%-z%l($LUPCbsr-atqk({o6ec%VW;EOr=KF715^E%1}>nyAk zPWT-3SAO;_ekdg14|!2z#_=(Gig1EHv(E2GD}U37!)a9OnRR^al;*(?bir5f`CiZO zQ_1MO{3`o#H@Vv8beVF3Kc9xB`U;MZmcGviedgTX6Q^%dM;uN?t!LKpwR4&WKhOnV z%*pq6eG59Tu3S*Nb+~ZaSv&6g>=FEtwgmhkFKV1}eDw5v0O&L8+)JGJm*~dfRMC27 z9bbD=^WX=%;EOr={;uzo&P(R({WQ8pj_J=m1-JJ;{<5370e{jP{l4b-NPk!!chF~6 z>Jq0Ls3Q)i*$+i~UQpFM_<=6?8uWL4YdWv2T%fo5JmG}bEuT5`i+l1I{2?!DY&t&j zRq+LVW}QC}ryHpw4yTrKH|zM?bD9S~&;?(79`}9Du&MLf$_2H1&$l0U3wOLZc-+As z@}kDBi$;RJnVo%=}ZP1F&GQ%|{@b$soP=D`ni!PlVYnO&WieS!VBE56X?^vIQO z3OK=^Ps37uDdmEknU4x5=tDop`-#)HDaPTH)_P_gZ(H-=2fE;kIr*MvrgYwnazX96 z7YQdkFZk@-JNeX_fIs9#jXB3h<72`J`pi0iB(2|}jyRn1TFk zr<~4PP%fyQ&I>1;pKiVM$`9}u{2?!DoOFE5>-)XXXV&=>Y2|MkaX6K=o>|A&E@~e9 zKo@*5C*Sk&Nu4*TT-t}ob=v7M;RLN4-*WIUsq1??nzV@u5}&HR${_s`JXqC3&g*+)uS&bE^OBBLOG)^J!SBuju$_>*s}_&z$==;?$;&IGjoY zK7VA^<#t~4;0L?i0m>-?QK{g^u9 zaGKV7W*uL%(?#{PPb7<98PupT!LB0*PhWl_<=6?8gzb|)p>R0g4(V1Hm4h}6;AMnyr{9| z_$cVlsX(7u=Rx9hJ9Wh2)K>0h9kY#}i)m;c{6H6cF(=>i%$CkeZxAk+m)q#)1b?Q6 zDD9r(W2z?m3Hr<$|0JzHp^iA57IyISL8w2kdEf+H@Wq^bzwfE1^Qy`P_3E316RwY+ zo1J+fkHH`EqQ771z*g`_dGML^Lok! zwNozaX2-VyIIHAu4^9rKo@)sIzKgZ-mG##?dGw}LH+96})K%_g9bdbxdGG^W@HOcCG_Uj0$JzTSSCV5q&phQ<*WJPE z!kzQ@T_SCMjUPkla2fE;kIr-i< z&!YYb_I}E|)aI0W%X?qM>%yO@AxgW1bu_tizUYQNs|LN-_&e%|!)a3MS#>-I1_@Z!vKC=#M{XKQW;Z(gq>X~(X z?J3QJALxQFUfcJ+`LxdKDHqgEy+SzQJpPJ@-W}|xg!)5X)L3_XjDAUcL7!RYQKa== z>WIT>E~2iQ=D|;2m-aI!-}~lu9WN`F+8-VlJg=#47f!f7zWuMi@3I&8GkryAw;dnF z3-#;o^mDC8lU80V4yTTC-;tK4=D`ni!PlVo&D;38Di^G?Fe#ky{q9RQ9LO)Z5`BM2 zj2IUjAC-%Q6ZDy7b|OxHppH145?ar!<7;>I>jOW~1z*f*`Kr~6ey`|)&MUl9xS)3V zM4QvaKe#D)UI2f{iyAYIkJ-9#f_pcKvdj6UOK_v73D&Kk^K-AZ_f_dNa*WUYrhYBYH{sJN65*iY`ngp06?B>< zb|zkbq>ebes+Z__&n)C=mo*Q5pbNg3*YfO2ekv8*TwWEOUspcJYrR%@;k>@bJLJ5c zP@l+)8taaq?3cwKbeeUN#OqJg5rYA5+oxQ(u zWjTJ5&O3Db%{OurKD9e?=s12RzoPrW>F0uvBVK>z7@<0Uf9G3Q`ODGZ`}&HS!obf304T!wJmgmDF|8|KsehH^?#0_b0yN9R607fKQ*6rTTJ? zpXTMl3p&lYPas}=Q7jIxg4Q$Zm~H&tq*2X-ALxQF=Cxw^;j3{1b9v=-eogscjm8^= z7oNW#{lLxva`;4E)L3@>^yY*YbeeT`Azu8=I1aCh)-&t)+9l0{ALxQF=Cyj&sueha zxxC6cKlLVie`Vh+$9P?M_UC@YFVzz8>C>`QU(NB8zEXHWr#W|5;`Mjxh{J343aMw- z@wKa(2S3mSUxTji)pTA}xuACaEy4+(OK7h6(mp%}f5?j(n~snCSH&0fnRRv}PXC~e zIGkF_-K^tl&*AH%exM7!23_B4>b#zELG9FAZBD;jEu7#Fc~N86@lpPoaDqOw&J&5# zgVYg+Q%|{@b$soP=D`ni!PlVcdtIGZQZCJ>%IoLK+k_L|_j}ik&wdWC3x7ThOZBCc z3vy<@E}Wnb{Tx%oX@O!KPHC-Y*73GA4}PEvzL-;%Cc5XRl+J4^7u25rU*UxJ{jND> zUBC(ckQX)P93PFVgcJ0cb#^CC|DujKobp=FtYfzE`{PD64}PEvz6PD2ayoDH?ZO4M z3;$+NBm9?H($JZ`u9{fNTd<{B3O+v47 zLG8JB2q#>RdBKzK<3DYXfIs9#jaA1-@*Bbl`pi0e5~qi$BMzsThSW3bm~H%iwTkA! z4|KuTpz~7|_1|glr%XkT@jU9K*S_x8ye|Bi8ltr4u#P5YuMuC+XV%z@IQ^SC;&5sx zce9SKJ*#=}16}aNoP6&;%;~&}azX9dN%rIJ^f&+WFdlI9PV>s$tmA99G!K5D3%>aE7K_s__`{We(iS)Cp>?8y%&!6D0pBJ^E zT#!EfP2mK6=;ydMY5gz7IGmDN&#dEX_f!Y`B=i`*23-eDX#JvcLG7vc2q(PWo4Mtc z!KDTGLtfN4>iDQ%C!Cxd9>-gGf&4VB4g0Emd(GvrAKaJ|VmU2Pu z?tAU?(=I!`>JA=*KjcM?MaM_`df^0pW}P%~dQ?nKC9P-H@wM}s2S3mSU;Op)eZH)y z^YZT#E~q{EemUM#JI*e?@nCMkAM&EcisNJ92H^yKW}SVA)1zZ@n$~(|9bdbwdGG^W z@D;pIlglpJPZgclP%fz5nHEk@(T>~CIHti(_(NXQIP3Vxd`mb%pIK*L;!IklC$S;yCIXde7P7ku&KZW&FaVBK0euc2Hp*f~WwrL^OpGrxK#H{lO?QDe{X zF?Ex0fWSOD?2{AHw!1|Gv_{?IHh88n$mh^9bdbodGG^W z@HOc9cv)YC@}kBW$49CqoS@IFlOayK$K+J|uGBN@_}bH&2S3mS zU(Ct(d7v4cH?Lgg*Xr+S{g`mtO&9y$Gu{%s=LLU04NLVk93Q#wi7)6g=k8Bh_lU`< zsoc#vzII*n;0LN{Z>ngYW=Yk`6UHJ29SgLQ{@iF;* z;RJo=+yhAKo-sLfmAhHT*KTVb{6H6c1-gGp zng>771z$V*oJ&*Zr_QwZSN1G9#(Dmsk^8>F>%*r{%Tj$k$IsM{g%@<1b4Q8SeldA1 zD1Wn#uRX7M@B>}&#n0D$*Qa_quc};7yMDIK>0#vrf5?j()5-<;wcCUf^r4^Qvxw7E zV{*!9J+qFlozy(|fiC#s=U2YJC!a?BPuu$`Q?oh!TRFj>Ps37ud90&J&D(_&^qF%H zA+1k~$*G|A%sReyR`cKoy5NgBE%#iX%Imy}azX9dXM_`;hyLfP8{WZV@Q1vpvF!Nh z{zN!IpIPTn(wd3MX-eyvb$soT=D`ni!52U7eAlPSItBBOPk0Re zkQX)1I6hK$2q)+>>pYt{?H`jYaaYS7kn`%-}R{(oj0jmP<#4w!U^B^ zPCe_1d-E9lAunodI6iVe6JOA0);Wwg9T1aKQ@NXUeC@jC!4Gu77jyDmpK9p5j&ecm zg>!{d0EaqH`|-0Tc?|xz9p^Uh_?YYnC+IV4J%>0Q7?V?1xtn!-?Y8E@4|Ks7bMjrE zn%8-y^Mng(S3WPtcz^o)ME%O6!?*%r^e+ z>4NHjALxRw;QQU`#n(HNTEDGaP`fuPoYLAcmMaI>JK+y`QDfHeF?XkMfZsC zbM7+IdQePGlUmQLW47`4rwW<}KhOnV%*l6ss-*Ke$_2F-E)Y(5Ua;}#vo`Y>{2?!D zoOXTuN;pBES!X$EeO63P)n7_IvyR!G*7c?|4}PEvzWDs)dtNZD^9o-SE|^#TlAlvT z*E2OlY1bVeqrVnk&}Y_IL7WbW$!Tr}y6U=KP4mF1uS@#}Juj&1ctg2hUgttTC-^gc zMQOJkAI0D3*Wc;qS}Tdup)omil*1q`ZC$UadEf+H@HOapL0jjIUL;&FuTb}M>iZic zXh8phG=)9V8LG8xH!U;cj)m`=X zM|ceWkQX&(93QiH2`A_?>#QbD&yC4xRO^{_%r^d>cS`f%2fE;kInm3zMc2l{v;mc`^$)OuzeUpuFH@B>}&#hiTS z@q*4PD;LzRepxu-ebBF-dd+$sgFoa&jZ=<~-aWzz`ph~x;-gG}ng>77 z1z*g`_xf&1=e3m!YWKb(obdVbeJ1}IJb!{e*5uONtR*?t?O~*(6_u>os%o5Kd zPAg+_YAJWKj;}qZdGG^W@Wq^buY;R9Z&taWc5_ZR;rz7UhRYx1G5AAX)Yx@=lb&F?_I?_@(%w&J|Knx1@w)Km)38)u zO1U6srYoGF5B(fpK%7>`x!XNUY#+>7$@dx1qeP*2(5~sssa>{ExvyQJls(J7OUGT-64yTC}tXod!wUtZ# zC65h$A4%_P!s)S^ec|!#;H?+Z>|Fl7AFV&}YtlF>zWGlhe%o zQqQd8YgaT6exM7!n9~}XNWr>QbzV)mV6btuaKiJa3r-pj{;nSUAunp2b9`j~B)*`} ztdl2BFN(>jq1??nzV@uNo8Dl=+6epKiSOybtlZ@aNO8R9^?{ zXj19V!U_7!xnsoX#W6X}D|fSwuier-_<=6?3OLada(6#{BwvyQKw);#!uF8Jc} zlkau#sLm^V(|+8Qud_KlaEEY$Kc9xB`ihQ^_5;ER`pmiOh|`fVIhC}YS;yDTYaaYS z7kn`%-|OI_&TA?c)SkayIN^QHvtGLpyl#O%}&#hiSv zgUdRvqFhkB_C4W*>vUVsxHi~N@Q1vpamMkHdRRC?pIK);aoQ4-Q|%$CXV&qxr!^0L zpbNg3lkfS{jLw@^F8$iK*qpX0C;02vFX%JNY#>fsV{&RLce9S!u3z%R z;CfMA^WX=%;EOr=o`t+*m;?ie6BNZsMi{kuj`cRH*Y{Wxvv{vzjdr=!3=WDJd?X8KNJ3jWSI*7>2<=t6msg< z_BB3Eoy>nyeYiRBhyKiC!hO$k_osgx57dNdXWe1*Pd!%jV4r}$u}=bJ;KTg4jBmA1 zGL(UFle^|+R`C;0y&*3@E}T09xFH|$6VzbNt&ksvf(Reztg0_M9^tur(?5=Qy}jV9 zJ8aICorN>@12`M|fz*W@ne(>dy0NX}#r45}-hrRV8F`si{ESR)$SWTyobw?Mq zfXJJl5YCm5N57V@aXNJ}=d$W`bKnF0qq~Irndd%<{&D2MaLsNm(R}}@qIAi)EPGC>Tbdr`vIJd{Xpuh^YhlR&3%Nym^p56HuEz4n%lhL z>ylkBybB>0Gi_1(OzL6YdDZPEz)!#biQ&HHx%^9rIO26p*;#kkynCt#`vSa;eGy0p zAKKUJCypv?-8ixFsPOC?emxA{VP1w`xyuc8N*jc8V*oegBc4SK=3Ec?VJL|3fzEO& zT8{xUknIkyoopp!Jxw(gM#(n^2V?PAa!G|~>H*tddti!vXk(cqk zF0XGA&ef1du+E^nPtyQ%uBcu&4?fVJ-!t6LJa=#U$MMOUP{0mFnIUR(g_j8D$&g1s z$Jh7_bu#Co>UDGA1O4f}!+p(j)AWzyKAJG?tUGMZ$tQ~*><4f*_Cufy`;a-09Xqy# zuB~n>KhkTZDIO06%+HBJo-3VBXD;qm=?b=$ux6bUeaynKwu5 z>#nozuz63Vg*WyEcpLkI)P+2W_tx?C#>;JLhyIr4RDzBQe7 zht0Y86w!nI0M5pK2y}sud7kzGN1nmEf4)}m=IOnE-l-ic+>;@nVBJA?{Kqbsds6kg zdGLk)R+u-!bNTfPM|`d;>#RF$?v4F~JN5^-8~Y=W4xVcZV;i@RZQE+R6=sctcR$a$ zu!lO$kgZ9=4qk_`vIJd z{SYVvpMc+S<6}kpGDv@)TAU@%xT+VP_q!$G+#SG8arDCl)MCz^kY9g{8}Nb7n);&S z5uW=b`p1#a+k8tpb%xEk`gGxp{Q%C!eh73~oR8f!vDUd#jd6=}kmtXympVZ>7egMw zI)m=MNCV6{uX^1)_~`d%!u`y1c^`9R-h7*K)*UwIp6bDV0B2)A1iHX6*v}JN$2SDM z;T^^;&YWjn)T4CdtOIal5w_6RIfcs&)b~- zPIx@RbD1+oaLzmH4x4l9K;ex20M5pK2rPk5zsC4Z6FC2AKD>>UQ(s2mSeHg!`K3^6Ny7c>Pj$)*UwQ>@!6V_62ww`y!AI zK4V+AZrr|c(?;hs-9ImYcRz2y^NzV!2#RF$&gEwbXY2=XHuggx-Qv7u z>)6(bwLw4bFm9bUB+q*0fxOWZg>yFKfl}W1W$Iz%A@jSZd ztUGMZokR5TrR##Tu^$5I;3J=v*?!dc#_`Q##wTkq4$gL-bCRZt$j_Z5ylWwsV7)kgZ9>bar^`vIJd{SZh8ALUFh{E9(8?lA6f<~;9tdhR{Kxif$p>LPxX z8qB#B^21ON;RBsB>Whv?crKr(IpRFM;H*1r&eK`pjQs%4#(p4m;eH-Ja{CdR`TfKr zC&t%@FI)QOU2wMZoF{okz0P}ucRu72tT*WHY8qhPIo0jv!B4+`S-7uxF7IcKI8RSH z>kgZDPxWA5fVZ(P0_oVd#Bsy66HZt^ex&_I7sd_VMxJp3395x(zr_26_uK$}n%)l$ zYBBG6$gw}h4fsLl)bfxw&t={m!Mp9OJ8a&QD?|_W1$ZYMKj7Klx53qZxC;3hyybBa zkgZDYo+kUz5s7y zUj)*@hj_1>*xniz{{M&?d$0u^PLO1ad-a){pcvK z3HkC|=F1UZ?RjV2Ve>6LPxN3PfUmI+0_osGd^e9T{rrx`>C*?fU|RnU^Lrl@zM~gK75(E|(y23SzSA!fzSsxgYwUwS7x*yWvGw5vJM^1;X?)QO z66BRXB7BP>hoJtTyKmC~^UbMFHxK&JzYyk)@LcB0aa0q^&bq_q+kLU{#XbOEV;=;{ zz=!!xY@9Gp5!SfLne(iR8kC7TGanVsb0H5U;1A!SZst6zdfhDeK>uVuJWudk=FD-K zCbXS(ht0V-CVH?Rz}eUjfim!6&KtI^r_201J|FkSNARs@F|{5AX^w|zLei--Y|hnj;f(zN&c=QSl!1?MF3=TG6|4c{HfPSWzZD`c`zhgE z40+fEougamm^tTFuQQy0kADA=;eO`1{5p^0p_(w|tUGMZJ=KH#0M5pK2$X@3aHdbq zINu2|Zgb{5`#T}>N;AT_F@T%m=!aXW#hmLQzy26E-~*lIqe9L+mpOA>p$Q#l-C=Vs z6+{pA12`ufKj72<-ex_k3(vdYY~>l}Xw;cLO*m&l9!kI;enj2OIi-5tEcifwJIov5 zx%|3>J^v+l4tj~*j>uphwL*bjkp@G&?a8a@=g&bOt1E~Zw|)z4&#gWbC74Bq>cQAGlh34uX!#% zkLHNWSrup9Ve?LI6g}7%;BD-SKstDay!jKPQFsS=#w(VfT>tBnIa_$Q2Jn;Y@cwpc zGVf-{F&v~8{GhX{{^)pw=Q3}O&!c~Q>pJTWn|EcC@W#FXZ)0Bsx;(s(jmVqxjGw>{ z%Jq2{J}ta+As0y)aQ_qPXWm)W?WVyG`g>vC2+w8S9C3ZLNF0M5pK2y}rX^IJc$j()2|(A~eoxXD@ajBk#Vjl9}t zgmWt7(XZuebf}X#CsePS10U#bhIu1AcQ5+Kk$Lki>#RF$&U0IYGxh^G8~Y*91wO=i z1O5DL_=Z(58uBwZ2YK!{M$~D3RybEe9$LvCeoo!YxvYBKEcihG=+KV+O6(cJ>=+eNB*GC zjm>>QxMxB>O2i+2N8QXlqx#(}_(Fd#%p2jk%$*~C31Golci7zLUoPCSKfvACAA$76 z+>f2uxOU=*9X)>uzfQ=vKS_qVo%4lzE#wodJLvBBG{D?zs^86nFZ7pR5$<=M%im8q zzDyIE&bq_qUfM2tus^`v*dKv1@G&`VS&Y4Z-dMcfkDUneollsdZsLo=Jr(j%BK~kM zbu;&r>UXo?3;mriZ-nRa_fw81XhP0eci7xplfoVQ1Kf@M5hw#6aDU0RG3%Kl#$Dc= zxA@a$;rVFvOTxPva#0fg(4}tXJ*~RkEciix;g#V&=ecS6#}ViCy0h-EdFM_PJ=hoE zZS0FcI(UNj=CO5KwizEM!MMv?^D@g<;fhgEuK#!_UMRd52Jn;Y@cs|fWZu1yV>n1H z_(5kw{n7CV&*k$uM_dg`J9UQ5yZ$QSjeP;$#=anR;eG_~BerekU)dRqnd2^R&7UCxI;R0spay4HkKfyWAx&vpnnk z!3X5GFBaaVkc)!whd)v`^De4xHw%8ypMG7q-+Au7^pE57HKF3HJ8a&`vgpCS0B>Vo z1j@h%yw`79i%S>QxXYXKGApxd?6Z0JxJXx{2K#!24al6 zzfe2a{~=dnl=i>+LuV~K9^tte`p5BT`p36t$?(4Tr!xc_-> zhW>G!pnrUubk-d<|HPYh|LeNoZ|svm7x;kx+A;e0?1oLpx^E;Q&*k6G&#YdxYDIYV zM}G5i-S-1H1|p2R2dK^58zE0)l$z=boz?Jogy-_>RF3_9@2op)?v=ObzSniZ-Pj+2 zbnw}FF?;?*2go%((`=PGaAO_Ltroo>zD-Ul-tbypFe=b%)Kl@HWwd{Q%C!eh8F- zkL+*aw`F|&k*b*k#ustsJmXyrG6ROwEfDiOH!@Lom%bYnb z(}b+E?yxz}{jYGwegJ1ucVS{S!aAQ-nf2YJS)YQwKb`D?FIME^LB(!b#5)EPGC>30Zc><4f* z_Cp}c=DcxiV!i6sfN^_2bDnW>rd;GTt`g3LkcVB+IeLhWnR8C{I>QP0==Z-f+|N9h zIdeQn6UxrI!{*#mJ=hQ6Z0v_X8TiP4j_`Mug8kgjGtSUr6!qq>7T$9M_$iitc$iwu zyB>1vk8uNj&{?U3ym>BPSK*k|gtoKpuz8nH5)7v72n5I zet+NE`Bd75`3Y5KFk~8xlf^g9KpTdtUGM( z?RN=x><@4^_D3Kce1!Xv6PukEHW;^gbDsT9GxD<62!4I@ogvL)EPGK#(RY~_62ww`-0Sk zeAd$M?;0x}yNNz3cjTtcYscvs$8kY|-nra;`R1RkLH_hNh5J;<$1J<3&40(8xlgHn zHvzuTpMPJt&w1`MX@KL)G@<6KJ8bUR_lq9v4{$g3N1zOROpf$(@z&o6;zZ4!(rMCRTNdG^P+0bl5Bs82c`;knG6BeY8(pBC=eAK-56 zk3c&37#!Da+e}w!cl7rs!p8^lGs|-Lt`&Zr+Sd#B$&e3_dE=v%`=si3li&;e`45Eq zo#!%lj=1(vb=Dm=_w31{2m1rujr|cwUxGXRJ@&N|>vr&Z)ARMhyv&;L%g}$kEZiVp zht2@5;EA}CejU0YUkn8iKGE4w-*h~}bNTDQv8V}2r_Qjy4)s&y>wx`&uY<8)0%iC* zY~|mcwtX%Avc@gj`Ohj(SijvT+|M}gc=D|mq^O(umhS(Mj}q~RU1%bocP3T8n+0F! z&z>6Yf1dkP8sPXmO{hBS4x4-CgS!89U2r${N1zORlw)ChZ0p*>xc#0eCnC?`-p{vR zord{^8+E@A;HY@|VOLs+xpzXI{V{I97dq?ela5DtF27#li0fJjr_Qjs*FL2CUHyW) zu|ERo;3?eoUCwpm>&KiIOvtmjoB8%jRpd|IB;1Q3A0YF_-Do0nFRFew3BJ&u`f#}4 zdG3BRz!7iHR-AQ*%{@^SJ=h=MZtRahI`|0pZTNUAYz^4w+cr8cOZ$1XZwu$v0B-%l z+IXUJZiM{o6!n45N_afNbNT0pIN~~2*I9SioXZ~(&e#v&Z0v_Xy2}~+0=_VA@9S+F zm)kE(`<$EK5zg6=2TFNkiWcDgoKd}Q5`3V4KFk~8xqHz7$3rxs=&Uk7&l^0K zIdcT(hO_RlIp;qvdaxhB+1L+(a&Q#R{0I2#H`Xw2b4H%?A!n+H{8USLCqgbt${+Ti ziOhRpKtB9nc2oV)@d(e|hZ-EWX+p-SGi=^-pAg>I7vOE|i$EFp2ybS6LtE6?U0=DU}=Puza4V5Qs57r zHT6r!BRrR1Z*tsU6MD|N!{%Q-L-=E#fWNU%0%asIxG8^nu|K{6--~zv;|_Pp^Lzjo z`Q0A~??T8$78-EB4^3p=dDZQv!4LXVXNLQo=kk8%$gg|&R(94MHt)n)q6hl|yp4Sk z=mH<%ecTwG*Xbub$2ObqU2r1uZ0<(B^VwVEr+*~e8v{57B8R{Fp3CpcapceU^KIT)ci7x3XA5`i4{$g3N1zLQ==~z|#d`m;M36*x$P2mK`OanZ zetw}X+_NDcl=Q~^Xd&jFRsC)feD(W39qxCY%im8q;(eo%v+l6D_n=4D1$SeA1k%CN z;qJct>~kEzonD3-7jLOD>Q4PwxYq}8?DNycQ)wb|uS36+(D$YNm0HN1=Q4MWxQ^a- z)*UwY@@GU3_6N8p96#XWaCcvh_BjsVzJk7~T7*!ycAId|gnX<#_uy$Xk-2A7zdH_J z=?sJ~Y=XH+we%f%>9X9Xc=R^J z2gtnf0Gi0$r&Yh31YhVcofqzRp3D23BR_BFTiscA*xU=B7d_Y?;BM@XKo|J*x%2+j zkI9)oM1j0T+^u}~Dth?!%Kc3EFAU%rh%xRCqy?FOLVXxRK@FM6;)z}?s%fijX9-1^+tk8jz+-(cxI z>B9JWyq&IDOYnE*IhWo0=b!4&=_L9k5^Ubujizpu_uh2rk#yUj^hX+W*YIpFj9I{M?=TI0!i@8Gks4 z77Wh+>ch=~KlB&A7(Nbo?*25u@jy+Ob=Dm=|J;}KaiHshzp+mOWh61U@#A3G_O%no z(vL2VZCv6yyq!1j`DN!9dcGgPPnYe7XOR%*-3vMP$G8DM=xnGzIv(M<{JsZAeqPVF zv{Pr;yz3VVZ|n>3HugoJ%jCU0B5xzldQQm&Q7`c;;av{71nUjDJA@`O?@86|=D`p8 zM=uKZH_v6>9KpNltUGMp>AL8_z5s7yUj)*@hxhl2h`fzF=h&{mJEm;Sl)qLF9*03GU7=7n=(0JlCbZ9JDIGUs~8&q{$0be1m-IrH2n(*Q@l-p;p< zv+l4tm%c1|uphuV;rIa`;z!Rmw%Hd0NH@mu`~-RKH%R2o-X)wfA&kvXSS zubT%S=x>L4BRqFc8sNyE$KYGuS$Ei+n_m&m*bm@r?1w-X_%OeX6Z8qupf|k3xXC%l zbG|bouXVR@u7*6qVxHD=n#i0hs@F|{5A^3Q3->e6WxgEw=U(_$ch(&?=h4eW5B38% z8~Y*91wPDq)B1H2E@+IKoF&ix&D+T9-6NcP1Goi?8h0ybB6FS(`5B}1`8V}}&e`yI zgy%9}j{Nhtd`mfXhRu0qPB>#ffU~h50$t!koY#$S*tB8H`9vbd4bGZpKlMOf`gg*) z6!Hkx8FaUjCNk%O>UHzr1O3S>!u`y1nKMUlt~l!soAZL|!F~W|V?PAa!G}2WA8W&} zaeyt~`8miN^!{7^_rke3fLp(?HdZO;xsacg0w3s{x-#U7Cb3|VGUg10%@-WjDwO7+b-p^^(>n6Yl z`rBdN2+!sH%n|#!;H*1r&dsk0XY2=XHuggx9eij%7mwe(33mG248A;`IlP}C4a}eE z3g4NKgOh0=9!?X3?|-V(9;M%B=JaR39`0kF%lnuk_Ho@=ci4P0SBW0%1MoHWL0}1d z`1@b+_|PT#4ZbwK=w(U&>(Kav@a;KV!ish)M+-3DPRPwlfPQq=)DInx@Z3G9!I3%h zE$P%5Hs9*i!Wa7he2sk&=mJOLJHGKKdR5{)!N9n|8F`sCK?S)(-u!*Sxft>=vKBYj z&_w2(SG{fqeDwPp;XdZMe171_uTS_k<*Ykw&OOzG{Q%C!eh74d4{?@X1t0W=cNjM~ zOP=!q2;?RID4ZJuxP_Ia^&*T8{xUU zpE=@p80DRHht0Wpt#HPE0B2)A1k%BWIMdGvZVi4=5S}<<+~C~LqYs7mQ;}Etvv974 zJo-7l#u!ax&K1?`=D-K~3*QX)GtcGo1;+_Zs5|Qpn{)0u(S!W}&i@Z>Zvx+HRjvOw z;7~^@PH|3fsyOwG1jiiCDYSBia0Un}o&pY49EzeuQ7M8N1*Ix#oGXgP>E5c>YaPHi z*ExDctD?7FMe7{B>W%Ynt-aQhz22Rj^1h${Kkw&r&feL3t+k)$`|hT1(zmJE4^A2Q z?AS%0M@yH?dk-BxczR`$ei?r{@d^cT;2n#Py^l2iJK^3Lz!Ch=PSQfmz2kXe%C+!? z!It`@$2rcuJ9W6leGd7c&ak;JT_fDFKfvAW4<{WwLyjj;Cx0gsaf7&XynSy8@y(8K zpY?ozEZUw(iOhXg^@l<5h4Ip-{C?+L=FTm+F9hojoBMc6^k9F0yV)O3I{1X#PY7O+ zBW@6Pich@Lg!uOFh5On7j^Ky(BuZrNYn~^jTnk?qTv4C&ILEnsUkSI&pO4X?&ak;J ze_FU>e}KE$A5Itegxq)Ts2rrH8ve1&zP;wwe8dmppUg|X7sU%AzxxL{A63uI=^6Cj z6eaTcm{VV29QlOYe=VN^UU&YpIrYVun$B6psO=t&xF}~*Ga-7TOgIk=Bygy$q zW!UGV{W&=w*f%&IX5Tm+;4|QS(5Fcz?>t2O4V(|jGjDDoZ|YBS9%`N!5JuZaQ6is* zy7~!&;1lDspZ8xEoXem4#4UcGxf!fG?DJ6lg6P41!Fe$I#YqRB@I3I}RoSy|mwAQ~ zr-&bP9*~!O*UNuB%>7x;!-(evgwgh7T9D7fnEDBW;1lB=AD81?z8{EN+>bI5tUK)U zu=Yhc57;j_4`#nO>EIeW4~O^jhjQ&bgnPC*0r4B1hhCm}mkfE0|C94j_q?2rLI3Th zL_QA<^%KUyC&p_l{_BBr`RjpOd_61&>kj)o%zjDqV87rznEm3UgU{gea1g&Ll8C?I z^KfvteK!s3w7PO0#yl?|jJA6yk`H_Lt>6 zV87rznEm3UgAe`Q#ev=X4w`oo#2Mzn9dY)x0Y@Tk{V&3~;dw}*0skMMMECr!dc!dI z!1&Zx{C?-$B2936iUuqP>kgZ9>8qj#`vIKIesIc2qC1qIeEkSVA+CeC(%*&itmlyo3?3b#MCM#oy}|Sdd|*8Pb-$lEw@4G*;=Y7> zulN0{sg%f^Tb^Gc z1U@i0ufFJUj&qCD;TA7NI>EZb<~-LH&e#v&Z1#hbP7>WgoZWks{7#wi-nZCC|f_>+7FJ3oz$#)f)!D2gcWZT#j>#G{Nn|G@u%+J8aIY-xSW+58!O} zgHuKl-9eoBht7K^s|R&N8q6Ech>O4fK62FZJue&?S@b*-^}+{d&;rbPLG_07@PYBl zxBT-4=N4&#Tl`*jD_D2foXh_udaxhB+3W`=og}(LIal^io~k3#U_Ri?arW)^-hQs; zg!8E9k*F6wcpNRjoVx?!;RAWg>Wd!dIJZb0Zl^S0Jg75l&dqNNXY2=XHv7RTBZ=-% z&ipeB9gzm}0cVaYY%<>q5jTH?aGvu#67|9dhbfUcyT9zHN$xYqAy&Mndex6>N1 z5Ue|F&ST#ZJ=hQ6Z1#gwMiSjYocT`~?$|YXIB^Y)dBeFESJ>pgZ6dCDq;Osxz)hFy zH8YgRoL4-*-W+$}1A}$-MUQiwTci%Rcz*5%>kgZ9?YqJm`vIKIesI!BqB{)d#5FYL zBb@1X@waIBq z&Mndex8S@ItUGMZmG6rl><4f*`@u;kiS96*D+kR}2j(N3Ij*oNxFHMig_{cRG0#O; ziZ^FdBJ&4q;BEGWlTH%dk>u^4LNFia zO-~^uEuanJr$&YMyyub(3?4n65}9{RbqCWU@PqNG>-_%a+#*eI3*L*ty2IvO`l0B- zz5s8tFPwCe=nljCz-iO;*}yuE25}MY5?|P4Z`bNQf6v`axOWC{M18bRpoN%w$MeLL zYvBun%j%OJ=Qy`W9c~|~0r{ZLu(>yXB;2t-z}@T*r;H@JgSgY5iQIW|_@*A_4R0S8 zes~I1LVV-q!h6cP6h=AB;?J=hoE zZT5vzMiSj&dHZJ-&o9QC-rP%ED{>*!Yu!S4uMXfRtNQ<+M2XD1?K%2M>cI~N8|sf9 z=Qy`W9d6ImfNrqvuzA;iEWEKVz}xH#r;H@J!}2ySS9<(nyy?S%?5RoATfe37p7LCD zrFb(-LYQ}1b%#;#gYnV-@%x)|i!{OQnHn$~tUGMpUDbnq0p4a`IAtW!9hSF$)#CSS zjQ7^UW_xN9^~P>3yq5>?(`9?jlSv5kUh*7!bKHR+49@+;^XA+lO>ldr2CN3_4x9JP zPel**1$di%;gpd?cl3B4+?V(b2+a5Krntgpe`XL@I!ZW?dmg$%ym<;GGUvSN4Wr-# z<7+-H$GJtC;1;*MPX+4^n{)em;f(zN&SpP2=_Jt|#CiYZ?tMFU1wa16yy0x)=woWN zfHsJq857CG(DlNpky946k2iYz4M~`!yTci%R z;9Usn44e1Ty70!n0B^G|oOF`tjwEmYbd32pZ~9I-;PvIw(ZYMqbJ3OJ&C_Th<~^&r z!zlQ{`1mjU{^r~wO>hg|3&Fa>=AHkg=)t}KZ?i9)bdu;&9_Ki>NF8n;j)0)fusPR%C7iJzz}f5vr;H@J zqsRGh@<%n8@8j&^3Y!xzCaDtQM{X~?r#u&3Dc(GT5}9{db%#;#gYmIn`+d#1MVjCi zKYyGJ)*UwQk>7|O>i+*ZT8OzXd!Bxhd+G~=HUBurxkZ}b7T>y@_D*RWibVM4=8{UX3Y%#AY5m&jRaGvly67|9d=TahbE~wsc9zHO>=Hqgl zTcinYA*B+mJ8aJF-|5$zt_#j)KRD?m(H+Y9Nw^D&J>sYBsRp=^1`{{d1$40 z^Gr%)&UNSw!g@Y*e5&K0M>w}g+@7ETGr_vU=DhZ2;f(zN&SpP2WhBuZ?$2mW?>#Z`*fnv60Z?$-0VGs@0jP{>JIv^Mhh_C?tpmcNB*+< zp~pGSEmDWuQ#4>as55N7&A$j=>;v#M`@kt9iSBUx4)d=8>VP(wPjGf|g)R0qBH|Vb z!gD*>li{ zcyj?IGT(948Ad@r#@BpYj&qAN!7bh}s0Ql}n{WFc!Wa7he9b;^(n+E_h%dc5@gGru zal@DA3tRnL*NObmdkNn~&p|84o9EL4%(t#O!zk#-c;%n|d4h9`G{G&thb#x{4x4ZJ zU!n*50DR3paMDSlJCrYdXixH)0`mc9i7RZiF98$vChje~M?4o@Dc-z*7GmDr0rBvI z?DEK%yN{b5=Qy`W9d4&Jpb*p^yJ=MyOU4O6oI&q zJK_sl{cA!k`Twzz-#?hp`{P^x((~8jEQ+A3`Y(ycqPX81zsG=aZcjNv?t$m?dqYQ# zV)91# z9`4tMK3iu$X~li;c0ASxr%}ECI~K!ZYrngt`#R~U4)__-$2f0}6Fql^oJO=h?qhF! z^GH_@_nU*$lWr{h;ct+hLF40r58Q7JeKzj^al(DXck z__}M}1m8zuQS^6~J|*)D8V5hn1z(O6ygs*nu^2nHrg88CUGU{N(YrSxr;g@@_f6w|=G*8Z zf9+oO3hu(6T{}%bulGqK7WeT&AI7;oojBn>X*(Y4gHu883y#Iuu~ChKALxQF$BEu} z2|498uXmsG?9JVE0q#S-l`itr!xztT7yj(pY5L{B2kyUxK3n6_#0mE|+woW*oTl`C z-dKzso6tD;fiC#sdi*CYLr!JQ!~MyNua@gE+&>IX*DELZvumg6&jvnl-z@am8jm5Z zxG&j`$NJzjr}yE;V(eH|<`1>7l=QR#~pbNenr^xmAg64(y1LJ;OaQeA&fr1o)YAKmV=;EDsd4ZFUGU{NMXtw}H7~r67x&xZ`ssaN zkmo1(vumg6uLVAEpDFa&8jmARxR2M4$NJ#3uJ;MYV(eI35uCDw}{34q0onMZVwYD+<$AwV|{QM!~LeQAT!og9qr1o zG^6)<#$xQ)l*YjibitS76uBO+YF>E1D()-AYxc%JM?S~v!Jl0_O@BW0q4!flpRI8g zal-woc0ASxr~2*EeZQO2IQW4s_;Q>g*W>e=7v67*`$2E5;%;)y>F)Un_lw3fZ#32n zeBk~^=(D+J6DQnfYR6-Ja9UFCu^2nn&^Y+%>C$n>DRMpD)cNo}QQW^dri+Z<|2|LP zF8tZG)AZYc58S^PV2m-6yMS~_<=6?;(B~*Yj{20*1Yh(PTYTq z_cOn3>KBal#eUZ3-5!d707d-CqydM17wbS(H0w1_<5BhA4 zS>lBIBJFsr4^B0`4=@&E$7VDRexM7!9H+?j_?+g2_ch|aLtH;ybL?N;`zr8f*G|)K z1U_)z9rW26PbN;dpV5xT`rx#9*L2qfb&Z1`=z=fDDRMpD(7f<|MBF!s{q)#l_I-$T z!e31DMq{nO2kx7LKAZa#;)MGV?RcyYPAhu9V=TswEomJ5Ko@*DPLb>Jmga@`6XL!< zTxTA-?(x_2dhlo0PSalxeBk~!=(9D>Ax^lT(2mFY;MCFk6=N}WY*pjn2fE0oV)O6*G|(P)B6Gui~HB0598cEl{n$PKsz4mgHyhc?(1$u zOrg%{$iRp8Y=}paQ_+f+1#fQC*0R($76kP zDi_mn8rL}ZfiC!RoFdobCCv-(%ftP1xXyg+vA=&H>x93U=8eW?0w1`K4Ek*D(}@%A z%d_LLJ~++leQB{6J66#+_<=6?;(B~vVR$`0qj|Wmu63!rKaTt0ZmNrHI_4_3pWx4~ zou*$8eBgdC=(9DRL0WNtogI($!D->1>Go4i66$c;KTs zE}Wpx=0A%#U6_&6gx0flV*R|v!4Gu7m*W(<9v|1dCFO$J?IYyANN}3Idh{^Q!5`w% zww1s~`+mX+`fQ!^h|_#VPF1aE>%{tHje{TPf-lD@ay?$ryuy*a`&V80@{Qy%_Wo6e zFZm!(z+X(mMq{&uSd}Ko@*DPLb>Jn&#D&3u-rS zESzwidC3b;IE&}t4{>SR#lT150m2FTY@O#2rx#`9)V#mcvvp$q1&xCr=z=fDDRMo& zsCgabg4$y@6;4O%z}|lx?Vg|D4{>SRmB7c;1H~8g**fPFr;9UkYAbhJC)QuqIQW4s z_;Q>g*W)XiH>+GwyFQxSPoF;KUa#jl_(NRUwiEc6dysH~K3k_ooG!`8sjJ*=omhWO z)AT7{)EQC4|Kto;}p3bFKb>?xuEvSErk=V3(jxOJ5KP2xU}tT z;A4H0aDqNt=K|vN(u|zuw4SXK>sK`nexM7!9H+?j_^jsTZzWt-cgy{BrCTRC?SGGO zg1?xCjm8!NA7fjD6ZF~K=M$%TMox{*QqR_j_2)GXexM7!9H+?j_=4uul?!S&j}lJ! zdGO*3Pa^g7d-m!NacSG-z(;AT_<}xL=LNLV%QA9mrPS5bIQW4s_;Q>g*W=5Y*Htdi zo4<{4x}6T3dBxk_%U$?GT-tUm@G-MZI6$f!yexM7!9H+?j z_?qU;DHqgUI9fR2di)!AJM=rAgFnQjZAX<0;_KUm6ZB!6+Y5=)r5QPmX+2vf*6*qg z_<=6?a-1U94Y;%9q!4*n3Aww(xkEFCADpwHHsCr+1Tv+b204dHk_%Kfxd3(zeyW$7)G9L7%O25pjA& zMou$Y&(?|cr!)?JpbNenr^xkqRr8w41+`c1Ae?Ta0|)+m$bDo4{2?xFJ0JRZh;V{F zTjxc@>6IBd)sL5Ywoa@+r*ZHDUGT-6wnwhV=QXcz$K-x0=ac*C(6jFE_S1;^i)q+s ztQq(if2jC^KAU?nX}vrnr=^s-8X5;bJzYBPI7P0t@tF3{V&Q*u9@@v%ksQHt<~ zxU_9M@KJe~p8sH+>s>;e7BX^LRqi*Wr=@Z516}atI7P0<+o*r%WrMmwVtgL>yK$1{6H6cIZl!5 z@q*@clnZK)-95?a%a;l#_(NRUb}I0(@<`zXeYVa^iPLK`a;j)OTPM~pX&n4O7koKR zk?Zj(&6`y&s9nE@aKig^H~YtV?mjX2LtNT+F7VMQ3n%Eab?U_Fij16UTF=&r^=C8= zexM7!9H+?j_?+ggDVJXDqHwyc4(vZiIKf{pE@h_?_{g6ioS@H^c^PqfZAMOuJEWei z6YJMC4t}5uz8t5>^>{<`s>%hmYsVxxJ^gCo1b>K2+qME9<(=XS`fQz-6Q|c@JkG_S2(P`h)_)3wvI{E&zs&ViGUGU{NMXtx!HE-%(!UeTw@15jy()Gd#{t%b89aAodUzik5 z(1&quFC$KkjGXdX&(?|dHSQ$!16}aNoQ{iJkB@0yOSz!-+I@r*uAgrAm@D0N0sJ8@ zZCeU_ET1TxpwHHM1!;XlMowj|XY0iJ;~ED)&;?(PQ{;NQqs(Hp-jtEk!j#mrbz=RR#=#GC!I$F{xgM`; z-uSV}{WNudd5oV+o%@upU(V~oUrfVBV@rXLiARYq=(D*C#Oci$IV~%9TPN0E)HwKo zF8FesBG=> zzoK#Q16}atI7P0%4|Iy)7fB39V=A#QJ%SgCFREFUKizJwA^56UqHl*d&kfy5;THe)R>sF8swbY&2HE zIvUj8E1aOu=3YUZ7Bh0HYCT&g)-P)u{6H6cIZl!5@rvfvlnZJ%HVdcQ>%iVS-t`LZ z!XM(&wza@Vcb{;AK3nIt#OduBIn8T5TPN0^)j0TpF8FesBG=BHjDtB8a z)?d>&_<=6?5>A`?ICV5{O1Yr+Y$?gFk<*mc zvvp$q35|mv=z=fdw55+zS@ZG_5iY1*dT5f}&C7eoqoJO^Nd53U8 z?U@tgG44D3=x<*3Zk~fb#HDQ~0v}8I{v!0*I*Y{VQyDpxw4SXK>lZW*exM7!gwyeT zoF+7HNx7hQduNi?i26b>2>#S{XUbXgyme)}PWi_<=6? za-25xUyoNcudpk*pURW+81Fw_{hI$dkJp92n1+qU=0hKcg%kAI+$)LGr!#V@KThh| zI>iN4NLBV`C@KHNU zI6)AT7{+PzW4|KtoaO%GvFKAv(xuAAqcXB^HctrLS z{2?xFI~Dj?dAx9fK3nJA#OVteIaRcttrP2)G!A~C3%-O?|MmEk=5>?{YLD#|PWZX` zP0#*`+fVR^xU}tD;G^>d;RJoQPLnu&F(ap%*0XhD{TYpeALxQF;naUUKBsxJ$_2IS z`-BsI&iU>Kb=~z7{2?xF+X#H*pCp{1&(?Vlaazg9Y4M3t&(?|c>lz0?&;?(@ssDPs zp?Ryy1+}{s;e_|cf4=!QU*b9VLtNUn75FI6iZAH1b>2&yzLb&EigLGgV*MqJgCFRE zFX7aGJ>Js1>M6nnwQKw3F|MCZ|J`le^%MLdE^WIW_?UgNaDqNt=Y7QK%NaR!l)J5C z`{i%z{ZASPKhOnVjuU-QJ1w6$)-|uKTrk-=Ae`_zxcibfzKrMK4{>SRG3A2zg{KH7 z=)*X-?EZs<8{re zD;Lymo-Um5{?kKd9{m!YgFnQjZI=Qc6VDJ|&}Zu`5vOltkpmzQ-$*;So-F)UdJO_V>OWUpnKB{xV3HofE4-%(#Mow$W-PVcqS2PZO zpbNf)Q~&k&s^-lq7u2plRyg7JIe)%#DSjGRWb zo~;w>cT@-bjOb(d5>EZs<0D$Xtz1yMbB1uj{RKOp_rMy@!5`w%w&Q`1<}-y8^w~Ne zCQjeZ$Z10B**dnL|A(xX*EslrF8Fes=!3Os`NT1Dr8(s#?$1iS^4G2S3mSU&5*X`l+IMP33~xD>K3g*H72q z{ghAe9Q+|JZCeX`bk7q`&}Zv>ggAXCBd2+-XY0iJvl<6K&;?(@ssH+^rg`}@ll!T3 zR&qa`@EqAs@E6mt(b!_(qwpNz1bsI5KZ(Ytuf=olhq$!uO5kJaeDMW+w$4Y1(`rUeZRKw3#QMt`2S3mSU&5*X z`e{Y;I?4sL$DSaZa6Nw1lka$Mo`XNcrENQbkGYy~f<9YknK*qfBd4x%w{>FuHI0KG z=z=fd)PMcd(YzVug4**>6i)a#!n^Kq>kiMsAL7!sdF6um#&d-e^kJOaj}fQuXXI4S zdbUoiKdN!?16}YXocgby@|w4*Tu{6FB;l0Tfp2Ync8k04r^Bh6a^R!&JmCa=w$R6k z(+@Ion$mi;=LJ`fQm`5~m+!|4Cf<9a48uC7t zk<+?zw{>Fuw#LB^bitS7bbSAQTGPDp(}fFa&pbmO<9hr-j}lJshq$!usB%GkeO@?0 zAI7=;6fwF@Mowc|&(?|cyQ%|zpbNf)Q~&FhQLVqETu{3`C!Fwm8;?Hcz3%ff;SX_X z+lj!((nZ1v`fQyRF*-UUr;^sQbz=R3#=#GC!IyCAf88>nc@yU*_fzGW@)*xgoh!d` z6J8hoVj4CYs|G$+UnHEM&*pxb7~M7_rx~qh>%{s~8V5hn1z*Cc|8+}M^P0*9wO5`c zobdd#{c`!bgFnQjZRbNDmk1~5vvod0jBcNiQ~hG8XY0iJa~cOf&;?(@ssDO>Ui0$j z375vLB}Vy-oR(7RYG@q%^mOUC zaO%H)YU=!ga)I8Z=LjdZ zBc~CqXY0iJ>#84qpbNf)Q~!SIYTmqZLG8uo3MV{|U;VMOh&273o|Jk}2W=t9TdWHw z=tCU0Um!+1GIAQ%dbUoiKc;c;16}atIBn^_&MatNSGk~e{sQ5Iznk=`3;%cp&%qz! z(za89kCm4RC+M?vzDSHt&B&>u^=zG3zoc>S16}ZyqpzAxlqgTezQUB|Rg?>6=ANJA zRCx6}&*eGzLtNT+F7VNLxp0C$TW5tBotBYPP3ze@vHpz4!4Gu77jxQ7i6N&s&1)(b z)LwakaJmr&Zpok2I5Gl%7*5+Z0w4LygcJ1HI$t72)r_1LFO_<>POM)?oce(-_+n05 zC^6*JK;8?53u+fGOzx+@oPOu$@f`diE^XVwI+{>^h4_L#Tj$Hf==6-7R+PJ~6YDQ& z9Q;5Rd@-l3lo)bqXit~Y&5nW_?UgAaDqOY z`xRpJ=!~2?%H7t9^;b0xexM7!m=k>*Mjxkj&0A6~sNKFO$?2S*3n%zPT-tU_xgdVw za^VDh80Yq@#ON^@IpwvUtrP8Q9Q;5Rd@(2bIE+3{W12VmqU6`z_{H)V&rg52e$8z~ z_={@TV6YVUSY8lL&}UP>MvNYtkyBag**dZQxW>T`bio&MqL0Jq<5beT8Rdf7^Op!G z*+ujjsmJ{O13U+Rh)dhf1U}YYC7hto*7-UyIwK>eS*>U5#QGJDgCFREFXmLDM7JqS zff>zfDHlwwy*SCKe$8Lq-*tmO#HDTPfsfJG2q);Xb-qE29+#2R!mFj8trP3lG!A~C z3%-~WeH=y~r@H19UXuK}E5B48<9?O%j~{jK`@&yL!$xCEfsctR#2570+%_>foRQPA za<_G2{Y8y~ALxQFejk~Bt*npJlIGQw3u-s(!U@k$Pul!`w-w#t}W{6H6cIZkvz9)8`e;=C%CUhS6)C%l(`|9@WO?$3n3UR>Ia zazXg~>x2{ZVVv7<5u-CRavIfowoa_yQ62CzqL1OraiRmo*N4pbNen zC%PaHIaM@o>=nWVwI^OFkMVxyw|{@ZJkP-&;?lOYz(@BD!U_6pook8FlQVLf*Lt>2 ztUs%9@B>}&#ozB@ukUJ_S642m-Mm~l;eM5uU3=mJ&%qz!(zc6%kHVXT6ZF|S-yuf) zH_q|gXy?K{pMO4@Z3F8V5hn1z*f5_I|;l=5>_|R>;3fIN^QYC!8hw3H}h5 zwp|H)OuborL7%PjUGmO<<2(zewsN<1V*O=}gCFREFXj|`eYc`{bIJv^7hav*Pk+Dd zNp3&EAL7!soxsQ3TZ9wz**dGli2ufU7EWE|ZtKMQYZ?bX&;?(EICV5{O}X@HUy9PPqT+q7z?zcb}&<$it_`Fy%r%`3lNxS;k-Bgv`sm|r?h@Q1jx?Ly#V>`LJTeYVbZ#EAcfaF*w% z#@nTytrP3dYaIMQ7koKRk^AfyG_R#x+AlxCeci3SA<60c-@Vh1d0qI6Y1n9NIq*?> zhxmd%oBKmzbbdxoE#+?O#QIH*gCFREuR&jT%bHhuV{$)L-<0I^s$ZY$IKf{`!$xCk zfsdJY3Mc5Zxj!OCwTztBmAkDI>$f!yexM7!27SL<)4V0+QeV2M+fVH`3#U8iVh_B> zt}b`sFQ#Fmu~FrMnEF-13HmV3?SB)a3o>#V(|Wc}tlw1~@B>}&<-YFd5989ey~Hu9 z^(Wqv+)tIaCOQ4)emfl}_)8Q?@n9nGvGgwC1bw!|8Zml)MouNIXY0iJ1&xCr=z_07 zoF+7HNx7hQ`)$JM&N^`Yb*H%N0{BB*+O`__Sbeu}f<9a4$HeHujGSh)o~;w>PiY+d zKo@*5r>&9icU8?REhhI<_3iTbPP*7{$A5Y+?!sS8!$xECp^x_nC+M@e|3i%CGjggo zrJk*0`=dFzFM3Yn;0L?ioMzS8vDfse}j z^!x|oT~Te z@E6mt(O4nyvG@Vu1bsI5XT*sAW?7c&@o}wZ>%{tF8V5hn1z-Gr7JY0;-*rJj^IFPf zeO>M^SZfL={9NiWuetqsye|C3G;B0B75G^BH{k?*HuvYGmH%d07ETqdXY0iJC5?k0 z=z_07oTfBy{5{G2H1%G2jQi}*xc3DQ=5^sOreUM8xxh!~--Q$O+1zzv#DB9a3#Xda zvvp$q8I6M<=z=fi6#MzzoaQYkm&V!hzRJ@3lKbhTBQHOb*M+~BhKSRR^X%j zA@K!$w$3k!5&zAyESy%9yR8%JFKHb7Ko@*5C;D}%zUQZw=FKP<)Smx0;RLNmPha{n zo`XNcrES*(AG048PS9uT{ED>l-vq+ib}sC*FFrcTT^K_z&R(eHiEV*W{f)(>@EQywlZWBDV(3HofE-w>lWXXI4YdbUoi zKdy1`16}YnXg`%Suc2H}d-+32PA|Fir+?%*_(NRUb|&z#_MgHD`fQ!w5+nYs_AL8p zR_ob1v3^D4;0LON*@<4s9pU;azEYo+t;1T zbMS|_v~4Bu(bn?;eYVaYiP1YUa;j=QTPM~pYaIMQ7ks(*RW|kiesD$en#u*WS3Viv zPwZXa!d`a$( z@Oi4H`Gu>K`>K46JjU;x-{Bh<(W@Ui)Tirb_^%oGnP>?w=(MH&Osx1b+q3XmPN}P* zaq!dArQ^(N^TbxZlyXPNtEq8|$_H_+PYEwvC;aob*F2Kv;1h9a+tt9&%%_D{jQ{@; zEB@^EEWFm0{|)I`(Kz^lF8E?zTPKd^U*&K|$ZJ*e^R49mDt%fW-%j%mzVcZQ;cm~T zj;C!#!ABDoJ|n!K)7I${EB*}kEWGks&(?|cyQ%|zpbNg3S83Dne5;*1LSCb~PDA-1 zZuv993)ffs9)90v^BjC4E^S*1{IotRyr9$8`3te)&vMVgYf9_cIuc z!FAL2EhRjGg}h3dKl)kWv;KE^eKY%{t1je{TPf-mN^W%F^{@dOs~n$`Te^1&L-&kHYn&h6O`c!0a~f=|Sy zZ5x4~!WV=WblN(9BUbOt$gBBzsb}lN`gM(iALxQF=Cys>wk>!93wbp(zpH$(M*fS! z3)k^?ntu3IJO`hMOWUplekxxSf6!^`{GC|6FC(v2}&#k@9e-@Iw7K7ob2x|+YLd^%U(+}$74{Zf+Gk+VNr=Jnw-re&kC@xag0 zmxLE|+T4E zx4$Z!#&qD#m+pBnci|6lY1{eG$5(|D^d;)hYuk@zulS>xVzRMm~3IMEyl1Y&g^me2jlhd_kX0=GV5%896Pb)YZ^9 z`044=ao$h-y)gW`YwG->a)I8~H-r=3r@7=olkR>6_(NRUwjKDWd|l6fFwXUkAWr<* zrCGl2R+ak=>1k;k{6H6c4f?r6Tl4a5;evHa-;~F=e*fMdzJGw{dj1fYvh4;wYTpn} z&}YjWNt`~Jk<*CQvvp$qbv-}u16}aNocK~9+)rK2t1B1OZhlKR;eCg{-EsAMJO_V> zOWPI#AB%0_1bw#7jfm6L899w>JzFQ%AJaJafiC!BPFpB3AHwDV(6s7P>KUx+Wv1iq^ArY=7!ovR+B!;0LxdqkOISf<9YklsNHcxn=o& zx1!u_omhWK_;$}fKYr920Jh)dg! zDHp^qd{;O@AI7=8IdS?@MoxLHXX`}!8V5hn1z+xZJo0rnhWghf_fz4A@)*zK*T3Zs z?iDrsMKx?NSi(9Qv%D&tpwFh>f;fFOBd4;~vvp$qagBo?=z_07*99fbn^!KVz4#;H zg!k3&xap7Xb8X-cacSF`z{lG6gcJ1HI=3WF{8>p^zV2qVo~;w>S2PZOpbNeRT^Gz~ zURSxGc79Db;d%T~A3JZ3=im=W9$dQ3HofETM;MztfVZQ8sC?Cwoa^H(>VBn zF8Fdk59Axt^$4#w>zY5Od=R(r%Sih}t@B>}&(wdZ~+obdkneZF0PHqXHy z;?lOG$_4TD9|}&#hmy_D%?*KnpgOl za6#?z&*d?Ges#OTAKlMm;16+W+iKurbxk-ypRIE=apKP;$--$y>)AT7{*=bS4|Ks7 zbJ|3SA*ZV5Ehrb%URoDUc)#wqFS+_PJO_V>OWV$eKK@5IL7%O2TjIo@Ns@(A{l`+z z)`|7!G!A~C3%;0B?0u+t%^UqiazBm#QXb>^>8$H6bzgTQ>My2Yqp@b-WBe!L3;JyC z?T8b9CP@}fODT0VG!A}xx^#Td^HWpj=adWdF8nIV>BTR;%yEK0#HDT9fse{h_526p zT<`Y8i9eGh3#V1(enWa%8V5hn1z*gGUx0*PcWsu&b9^7vM| z*sp&iUw7~q)3DK4A@H&IGvNe%HusLi>AH-Z#VBnF8E?jv7fsX zG;c|{pmzIr!U?}8`i8e$#cv;vz#rn$wo`$Rm7fbI=(Bb5#ECzXB+GuPXgyme)-P!s z{6H6cF(&uAR{Ko@*5C;kz7$Z1aV=9LR-Fa9CWO+IBtgG5c%b1bw#7U5OKahC~)l9p!H8#QLim2S3mSU%a1UuUpnNudQ5A zyYpw^gzJJ={Pl5kYt!L{*`x*y7&;?)2 zDfYT$40``hxS;k-H_7RfzYtFFhq$zDDe$rUTj2zKw$9y&6Mu$87EWcYXY0iJ;~ED) z&;?)2DfYUhq;?n;dBpO?4G}wdM9_`FQ#Fmv6;Zf+V6xD^x52d5GVef z|16wlwVtgL>sK@mexM7!2639vyz*az{q#3^>^|&{7W~&API8>!FQ#Fmv3lTR^!LIE z`fP52IPvfNXW_Kak$SdHtY6bO_<=6?8uWEn*SxlJLG8}pg%j>G7`x)CHJ*b%#HDSQ z0v{895MR(|>lBF-|IU9FPRq*O)`|5OH4c8D3%>aKUF`EnmNc*WkK}%;{Zk&}=Tn8J zzvygU7ye=zHX2(Ed{qBeI6_hUTb562zkIru|d+IBqf(fpHef<9a4Uc`xi zmpu!o39V=A#QJ%SgCFREFWyfR59D z&}Vb+OSR#lT15FTx4>Y@PcOC;r{zES#EMsb}lN`U@Hd zKhOnVgRTn}HLs>zP`hzc;e^-0cevM)Z{<1oLtNT+CGauzSMddXw$3xaby5NgB#oo_c(Y$r#g4&}u6Ha)2_tB3X;W)t`;?lOAz{lL*gcJ1HI`<<^ z{JWu9ICYh~trP37X&n4O7kmx6e(GpmRk@&c?dHM>@B6loUH=)+!5`w%wt3}(_{QIb z6ZB!6+hd6n|IS_(P6e%J>%{t_8V5hn1z++!-v4)r^P0D!Tu^)c7QzWXmpZrgbH@q( z5SO+s2R>T=5Kho%>)f9>@$c$o;WVZ7Y@JwtLgU~Ey5NgBZGKQcr?TdiZYf+)yLu~m zjOX#w{`st@^BnvkE^Rv-_*nm^aDqNt=K-X3g#KmWG^h1!9owJygZy4=Rpa0Xy5MWj z^Z2ahEh-n(Zrxfq-9ZPo9{b3Lau@y(m$qF9eAGwedItJzod*&l{vD1ioEHBj+-;p$ ze_rF@2fE-ZM}Ng^`rzS{Cr{^hq59t^U(o!*QOSK3TPxkzt=;RMi4l37xc)D^enfrx z#zKeu?Ph%0R6 zZ{>*t@$>f;-ZP#{A})MzAtf^Js_G8s;RoY|BYXUFoLi&`Zg*JL#m|lRCx?<_&KjSJ=uw;!GTfZ;lJ^_5gl~BziDUiOhS& zb4-N54+iV%j~?eZw@4jsPtt%+uGxh^G zoBiOFkwkYW=Y5CVyDd6M4dw&R6j$&c7GvVN#|r1B=i!S*dM}~{m~%t*h9U5Q@!6aD z=MT;;(ge2^4Oj`*9X99csOZ6d0B5rwoHCN=4&uCPa?id!^pw48@?d4h&XaXQ8^jsj zL408=|J)V_;tLND?qi-0LZa=(l*ru2RDT!*Ul?!uxE$veX@c7mHJ}u%J8bT)n+bR9 z4{$g8!zm+)?r_}G@^*0r{`IKdfjUzU6wYc3w{>iEwh-*ApIL~+<2#K~Yp+x3fQN3Xhd|*6(E5ENfw@4G*PHVt? zuf0 zk$JZ~$3zJHV6d+K=y8s7i`3!vQ5vuwtUGMpwWEYL_62yGec_amM0Xh8(dXd^?`_1J zZ%s`csJFgJc$YkvL|piwPKnHWLUo7p@PqNLkIQjxktVnW?`p8_uz9bK32*ER@HYFx zNhgW!Al{V|_>yGb-W>YQ zbGPx&C!AZP32yN^awS-I*t}`&?wa0tc*mjrI}Z1~oa}Kl z-237S^m(Z`P`9*IxaU0|ghbnyQzCQEtNt(uzA(P(<8qu^qzP`PHJ}`N&=^b9`ZY@+BtfRvsqY3!aaz7;j!hiOjvA`ok#r!g$BWaWU>LzQBL|!XJpQJzTgqJRctv>Aji~ znR`R^havEV@!7lk{m!{Xn&8&`@S6IqVBKMJuiiuSV1IzS*&j|iNpy$heqd+cj~jZ= z8!_%KzOX&<{QL`@=~miS9^n-#cBI+^-YbATG+?#TT~wSDXHMY2}f^z3%xW3kQ#`poN%wUG)dk zBk+asYSHg^&Mndex43>;3f3Jq_o-t<5B3MRoBiRWlSFqUxbNFd*Xc>{h>LQU_`-Jc z3Ka33vTz^qe00Tl^IA$|?jx!{jDjzWw|!iWbBi>=ZCL}xgLQ|^y>(CFj{O1dW`8(k zB+(s~yZ!)8XQV+~jJw7cdLJfFDTvRXAlz%7Poi%4;B}P9+-s^ooQE%rPu>2Z#8i`3y3e)B<{VRK))k8sESfDW@ioOF`t4$FP&w37~H zxqf%?h2x^HPiJ=t_gT+JSBy6e62#nRReu--Ul=dl*Y9`EEz$(H@VgMKJ8bUbHBfJhtB%vjo5zY_`-4a)vAwQm=x}7132~;(9Ro35OZJiJQE@C zg~28DNsn`!Tci%R57&Uvpw6(lFWyhMV}F3V*&j|BNpy$hKDqa#>AjQ5Z>)%maYuXs zf6Rd@B7XTq;a>H8bj5h{MoMJvRn;Fx!57BIkM;YVbBi>=?G6o?57r$v_x$}u5B3MR zoBiRGkwkY`?kDU%6uj%`ImWnieBrqG>(#ZBgnN4cM_s2Z#8i`3!v1P$m0>kgZH{Q<%q`vcs~{&31jqB|`2{gb#GWMkeGS2!;5D%Ho2P7CiT z&qY^?H*Y2(%)6|*!zlQ{_}ByeKIhybO>nzI17?GDhs}HBL81ry0=&(>aLP!cJ1pWxqM{m!{Xn&1}iLso-zht0hMJ-RNqoBiRWlSFqAcYIqse8QpW z-PkWW-Q#HXdosRooOzY%pJ(QG3-{&#j;N3JZ6t`fH=!RB+V*_uUdEkgGLN_zca1L`haaL*3gVl4gnPmBk%9yM zU!+9lUQqpE7<^&8>*I2qTcinYPtky>VBKMJU*96!u|L4w><_1mB)TKuet>?ex8J^I zLfioE5??qj@miG&Bd@(z_%}Q!S$M$zZ>L1&zoKF7OBH6Uab{^I>Y9?c)W1NegJ2)ADncO=nin+tdG%P-t23~ zc{6dgv51>HAe?7C50r|w%aq8RtEx8)f)9-6AL92j=N4&#TX3!i>kgaq=tD&h_5(PZ z{otgNM0bEQ^y+Zz`NMJELY!?Z>NE}t=k@?@sEhVvl*pW0o*$-M3m+JqS6}ov$GJu7 za0@M+VBKMJo_m;Z#(n^2vmcyvlIRX_4qm+=6p8Sa;Z**B>sNu^+(M><1^EB)Wq*^ELPG9jDW6h&v8Whc|{I z&OCnv@dVzy&`13Gslt8H^U)RK%_k_4xi6~zFbcjfKJy6wJi@s}n&9>f4Oj`*9X9vM zBSjDP2e_O4;gpd?cM$gjQ~ORk7~CEj+ussLnC%OD)ETP^=e*~kE5w^mQX+F6RlQ*p zd|-Ul$K^P;NE6)RRaz-nci5a)%EB4@0i4Z#aMDSlJCyV8$&+^M-bptM9hf|zGtwZ= z>~H36B4>9^GVbVA6!j|%za+yHuMGoFjC6mLF7iOjpIy2B{=!FXYp-`AX5qzP{Ex_v%aci6ngCPfeS1$di% z;iQv9cMxxRUFe=nbdVa%8{Q_auxXQjsqT^xzw}t)-5$WtuOPh^B{J_7&oL1KKNxJN zKYEkgZD{Y2r7eF5HPUpVO`(H%YBm7VlKAF1w_6Yhv7^s(2It7i!J zvge~K#+y%*Am(0H{b3Y*VSMZ)zt1_hNE6)R=gYIfy2Iu^G9`MjKfvAW4=0@@x+B3o z-TiW&yWB6gX_I+@iMk_)h5PaVj=FrW`3xm8_hrwsH|IL)3xjq4ILEm~n&1|G*MfD2 z&Am1)+_68P!|V?yog}&=!9Csma-O^1FSltEUVZrIrSTczKH>T3it*;NB#60BsQxet zzIx-2^81~0i!{M4?o+G=>kgZH2YPf}a5wwINhgW!u-sGLFW2La`{g!m@~=Qqw{oU% zZw}z7%lDekQ6h71LVs^YIz3-HUOU-y=iDNVa|`b6VBKMJpWQ8bus^_kB=AEL-C?<> zykD-zUGA6Lw8^~u?0p}uoh950o{z2=Z$3|gn0rC>hf(l_@s5wnac+?&xW)7PRIu)_ zxv%XJ?${sTZuWW=xlf&X`e~Cp@QP065!ZJ;L*G|5p1!mCSEPtvJX^RoJRe;# z-h6=)nR`R^hf(l_@!7q8zjJPpCb$LnRz+%mW~{S9iOhRmb%!zV zgYoJqexGx0ktVps@3}OCb%)J+YQN~gz5s8tFPwCe=nl&pH%jP~YY-RXj(CC}yh`=_ z^G_1~-2pu9THOB@2-9Jhn*CGxEOzlFKn_O^n&>EtZ=V+KDuJO`7$Lk_nPVtqu>kUrGtLo zb8e9)xGihIVzBP8xsM+bJ=h=MZuW;$MiSjY+@~gYR}SyF;qRx2Bhda8D(cKWSvYqF zaMR^_%~vRqIj?zsy*ci{2L_w!iyr4Vw@4js@wtd&L7ic9Zk#Hdu^+(M><1^EB)Wt5 zH@}_B5Ov5kn78{HaRl1DB9$z}FFZwfS3MV7wy*zHN@U&@)g1=F561JS`F+i~MVjCi z-(70Ky2Iu@S`|Im7vOF7g_BMa-9fzF&ojgK&@pd#+c-k*UyE`f#4n#CyjKSBlU4oy zU!z3k-SQm$B=z72gLU;sk8_+`qz<>ZURe*;9X9XU>B1ZP0=&(>aMDSlJHUJQbn&3F_@snB^$9%A_IgW7qYi-1J&lAoi&qG&;H{Yd1<~*)?!zlQ`c*n=(IJZa> z+~V`&s=>O$=DhZJ;f(zN&SpP2=_Jt|#QDU1`*-#|fneTn?!^)4f!EoE=Lqjb&qY^? zH>|Z3PVPUv ze{#pJ4c~{gafCd1p^bV|=L_#K&qY^?H{YW~<~^#q!zlQ{_^OY~ac+?&xV@JKOa$u= zoA=6-gg5pDc$&Mndex8U9k)*UwY%9BM8_6N9|{o$mOM0XJP9lQ2S@0Dj4dI_`t z;GP`^cj7WuqoVwyd2|xY)ws`VJXg*`cL3MkLfZKO33U5k{e<)IiSacbm*d>~(ge51 zYQVTZPi|z`=b`-+IS<$`I1gsOI30cG!9Cr`OG%ZUh%@_N_?viQkGJW1si@z2o_-y8 zPQ92|=Q>Jc{&n>c#=sxOtLONy1I}gs+=72ISa;a`r=F@`2f8l!n|

gAaWj?A`(Auu zQ_1}F4e?_y5bib4M=QpgqmB^nHPs(R!57BMPxt$sbMH+P+>UF&VzBP8xlcSp^k9F0 zyV)O38Tj3v;r4F;xN4sF%!R^x z#&gk#cyk-&T~*y-6#QU(;#|MKIrknk!R;{`FdwWtY~F=uiXQ9>@HYFxDFe?QZ@L$E z??Jg#G;f#p_H7?`8&4-7d}9Fh>+{0DJ%A@TqCHyquX?VSaxMH}u&I9OagKBOd4=2i zYd|+xci8+J&l3LFC*W`PiBkqXp8w>I1Cu9C?@zuxumOL>6MX+RK`(ykBH>=~e3VGM zxvg@qsQxetzA&CY&+mKA<>z&7@w{FO)*UwY(PxVu><@4^`@>1^;~u=zi21(#&T)h~ z`Kr}F&#b;kc&`lL2X1I@ue@8HBc@ynKNwt4fAl!VxdrNQi|6(AVBKN!o_~(;#=Zb= zvoD-<@a*k#{=w#S#XiL(;`+F2JfTlqv!m|FCBnVr`M7$6{>v-(lIjoR;0xoU=lgxm zxy+l}`)I&SuiRPIZjC#GBrUl^RPdG4Ic*Xi8y>m@!`gLQ|^eeSuU2m1ru&Hiw@`naER zh_1ska7R3Gw;LXHD=!i5kgay`tyW4 z_6N9|{o$m8PjA1wS3i3u_a1^XX%W}A-+S?e&08X`lWH#&?u(vJvT*QdhjL$3{lWAI zd||wDf#2_(%imAA#rM;dVBKMJFF#-OV1IzS*&j|ic%C*jz2VPC-F(4crXz2$E?o28 zKafP*Q>dwoB>&gI5JwDp0D%Ymxl?Z`u3|24nTse1)Cb(t3e5?iQ z4x8)Lyy(IC2iK9n5BPO3f3Jq*Tsv3E6zW-n)C0Jfsg%+RGz>%xbkPC+SewSFTX;#*1Ugp9B&@2 zT&t=tjDl{AkG{z7SI#|(Cb;E&%f~{n?y$LbRS(WTxSI3tbb-&oikgZ1$vw1B+>S<%5_xrg+b7b@s^LvaV~S^7F^50y2IwW z^kU(P^AE1({5$F3vyXn6<0SJU4&&e|^9B3TA(6klAbjUN2cU_zXDHuU)fomsKgJ6$ z@%xr@nJ>5C+X&VjHs7(AiXQ9(@HP9uNe9Quq5YNJ8}OC+f_a4?&XK?ND&e~}fEPHS zeVp=L@!T-wTIk1MUH#DG9Op7$Zo#)3tUGMJwYu=dJ^){{51e%H*|lT;$suD7z&!S` zkE72vaTVl0#Erg2IF~&S6V=~6tehuQZx{g|7+>>oInKR3O>lch4VVem9X99o%Y-xb z12~)g;FN(6U1#~5acBnP;LG#$`*`Zc&re(-T$|p1FDBNRQLc5>7sfz0#;0EHpC34v z_b<1%(|}g6?y$L*E)_jE|KMuQzf%T&yf4FRTn@lI`1a!HwrjPPs8fBda31kIY*=6a zOy%4e5DyHzuaQ~7J@p%=G?eUIAcG6v)K<$Iyi=(QIB!()z73ipNt{S z5jX!j;XCU&NWg&q&r-e>)ft9CKgP#i;rB7;@;>Gk`*=QBci4PKUMYI855U*#11BAP zcz=ekfjI#4;EXuBZ^Px|Kg2a(FPv8fa6>%Wvz7C*=Z7h2)dvRa{&9|Tc^`9&eY_s5 zJ8aIi%Y`%c12~)g;G}~Oe-8BFo%;?Pq>l%rKf7=MzR)5Lyu*0=9t7tgzTFV+6P^!B zM%yPV_X*V>2EiA`yFM<*xp$!nZt?qe)nMIWb6;Q3uQy#6+|B-Q(!s}b+r`{~Q7d#iBindQx z-gVU-2Eh-;D_8h^&bhqLxy3$T3f3Jq@A7L!5B3Fkn|aMHn3c)JT0{#@wfCZ|ZmCAlZ#=@q+u$)2d+dYkZH8^F^A zoBy7r{MS8KGfVeBsy__2{No(w-km16Eo#7MP-ocum);=!u}{F?>=UO9Tn+!;W`;Lz z5f|a#i>LeB2l8KE6#g@wlP%xZKTrA3s*f-L{xDv8qu>9W%lx?o|9Y_Qu=$U_N%UZ! zfWO%%PCB>>|AW(eCL>Ss6p6Sb|75&<@Eq-<}8q^s!_r*8szE{8CZuW6B;k1gBR zuPOJc>JJ0p3*!@S@%x=~nLD@OJ|C<*Z0?1(iXQ9_a5wwINe3U{K1IJzaBwQN;}MtS z9>y0oZ3~`pkT>&A;oly>6CBZAp!`=oS4_DU{xGY0&MnXc zx8Pq3)*Uwg@wbZ}>=W=e`@~64^6y>h(C2(rqwmxpK6xHud4;X^>IZpC@6xY>0bIco z?S*!kIS*?CxPm9zi}XBnJYP(? z7Ctf9R^RkE$GLnSxW#!G3+fE}JhZNo^ML(=^I-OilMX(y^N@UpN1P&lqw^r|_#~c| zdS4IY@0If~>v>7x0sp^9&qGc9gkkWB@#?$$*8}JBdEgf3p%JV*?DH`7ZqbANg7aYZ zi<1tnvGcHF|DJvOVNhGdZ*(49USXU0YVg;!mG{Yc=nUW*EH`qoo`(_j6VAgY##=rv z$GLnSxW#!W`19mahJ7BEnsOenUvM7GesMa$)%{V;$d6Dk5AG(8?x2Tz&$;$~;au}P zd{CrUSI)DlHw=LfjE}#^?|07SpI32(v_SGq7d0j{6Cj9gNV;5LcPr;w;6VbJ_Ico3MZU2Ub+CUY_?2a> z@D)1)hh{Wy(VPeGQqHUgayIqgGb10*Ipc+s`%|3th0;(C=Z)cel=FJvK}4DM`QY3^ zzOfT^uz%^&aNdxyQqN*p&zsS_MRTsdTk~N(kh7@=pE@~u&KWO^+@IpCFNCQtf}r2b zdzJG{;6X&0_66WPg?wWt>R^9A_?2a>a289>)o9+LId8m2IkO(f+0=tioqUcT@*hzT z$6vg`{p6hZRkEMkn17#gZUr7hlxbfK&dbO*cA^gU&#i}gma+1DqSzB~=tT1t&AIYk z&4=|s&ZZuGX5=V8pmDNxfzuX^ttV_jFsmx#Pa#B zN))GP-s>Mx-mDAqHg(}sCr_>O+L7b-;TI9(z1)442R`V*4}H{wD%Q_Ea-RG5KaGzn z@8!S+k+RJt;N3*tu^08QzxvTo-!fLt-(rQk{A)+^7R`J1GR=o|LEfe=d|u?K98c8U z7n-`?jgG13aku`Jz2}_kL#E=kE>rH?IUK_XZM_lPw*$|V3w5!x3!QGeEMuj<#a7@j z6~!r<``YEoo%KQPrapXTDeiJTX`DKTU*(+i-&ROK#_L|Lyc>ZFNMxHgfp;Bw$6nOK z{>sNfoy%CMbFr-Rm1y3gc~5^_^I=_(x2X%CI{BD7&!8SSrq3_F&Po5wIrH-*jJx?U z<=)TXNPe_$2KRp8$z9%37dt!9>9)%2MfE^A^p${R!pH`XF~xA3ihk@!Z`X z5FK9Fzj*TC!imG~cfRet1p1}8$Nuih_Sw-Hp5scNQ2z6Q6Ubznw}5{QI$|&CWB*Jq z)V++YxE*5oJ(|sE-lF+WU7`7~PRQTXiBFw;Jpc0#E*x4sUUOfqkzy~7^h@!#{_ghv z9Wu`Eb3NtW%i-vgF#mfixc352v)6r}HFU9aEo_%%th{d&TYHFdnQZem@Slf{*o*quKlQ0l_cB(#=TR)5 zb6JY!Et>xh@?o8jzo`?SdW!#n!|sdm_a9i;<@b5~It4%X@${^!ee2G6?N2K2jU0aD zM%xAN^}vz4yrmv?u6{c3ma+1>Dz*ZLt!Un&d9Qp%^I=_(x2X%C8TojQ?)U5#P8>Xb za-X~GawI&vE{^m|ooCYi?i1>H=SHXbWL)o4%6~R+0-0>{cJQBrj@XO(*uN9}$};ve zw?i!Jy&lb5H2=Y8l|So*{7s$s)XCNJKX~AR+VR5&4qrf3IouP!%DLy9W4;{U4P(6F zr_hlgW^xet-xIcAX@qU%P=k7i8YS2HF3!%PctXyXl%fE~1M)MZUyZS}Vhjl^TrY?Nyk z_Z7YN&ARj8{uFQb1Eq^cE9dMzdv7)G{N3s+@0}ce^9z>LBKLpMVoxwpTn+*u#wZtBCQPM(fq z{HdPOQhtVe?4S9)WTh`D_gdhSiW_fifO`%3$NQ;^{WF`P-es&@e-V2c9G0Vbi{?J{ zHO+_hLGGqLd}fAw^r@1{)Y8vzkNoZ3=Ww2x{jzfJ<#0^TQYw7}+!widHsz1?4Q!5;?=*RysLpr z5;LoDIe5<@@7RZWlKy`PbuMG&^QTz8em0_ci{?EJz`w8%0 z4_vv+Tk2zH`=0`T87ut7lK*BjZ_)f)TR09dFZr7~@u`!m|GZ?MxA2cG9y)SSIQ6Ie zxeoc`+#gO5j_MIEpZe#p4l-8mbBN{dKQy9wi(ZEv z&dJe~En$l;$eLe6@xlk87 zSHBgw%UF5+6-&Ka(Y!@-U-=i!hxNfcOnvy&$uq^>RsGS3J^eDd(?4DEsrd8XK-~vU zM3-ql3;uJ^5j#;|(*NziU&hLHNU;xuLp_?eX#PXw!#W{pOwFjFtEIVtE~SGn%(( z?#tiRd{`gkUW)XPkLQl-!18?p?ot0;-|y%6n|Gc{hVk3~r2H#^6VYYbFMD|DxR6fe(>o+OL9p8~Mjh z)W!b#zlM63u~P41SvMQeyhU@L|2NHt^+E2YK78ur<8LXYKT@UklXviQ1y1qKGEVi| z%6TgAFkYk0uY>bWjz4v9dJ*oivWU-@CEXBjJe#maqE`PYu-Et>Q6 zziU3M2XZ#`;PWCM$M5*X^+k8~ILt#ZwV(BD{VEyf>(%cn=dB!WKB)QMH^I3d_?f-# zcT}K*o$at)ma)QFEIIE)^A^pyHBip12XZ#`;8P#veDsk0Fv|U-oW(Et<2o0S{_EdU z-t&PAQDxeH0`DsFj-9B7{Zs!D>RQIi-yw;W`%Ut1DVn!v-aE*LbwS>yE_`0(!+PC! zi?#^cXIfJ8MO5;;5`f+Q!doQ&UNT>+hrLm=WVe(Z_h+=iss$< znet{`khiG|pL)#OJ$jz{NpS9u>)QL7Cj#iV@&o1E3_OS^(|#MA8^||yq7L@Y3`1SZ zSgB{R{CnNiXx^eZPyJl;VLgzusRy4r`LM1pSV(_kJ@?0)ouB>LvZS6nKUB_}Io!yL z_B-I*3;ejtTk2qE3%cBPS;orqMPlVVBL9ZbyhU?f{)KX8J&?1h2cH)?lJnxBy6@-z zxIgCX{8A5e(XapS%DEbNFjS`fE;!F3-`I&d*gptR^B4SK+)NW97Ud zmgkLLG;h(IYyYMBupY?S)Pql*e8_p9`{LZAM?y_=f6N(vse1|%kp442Qr=U6i=Qv= zf7{?)Lf)|-^{{_4_?2a>ybg-x^DMK`yhZcw{aSgmF38)|g-@M)4iotP#q;HFDyWN= ze&ine+t2DUhW_(ER_-f-4?||!e+BmyWcCJI8 z+b+vkIiHB-`@ZQYPSLzO|E;`P7vyc~!lzC?3Gcg~IC{)fIroq7_I~Nl=n|0r?Vl*` zrNG6{m-oLPfOi9V$9~kq{`udA`j)Z6TP%6EqIrwvJ@-4!hjl^TrY?Ny#+h|u@m*Ozwy7}_>i%;c00t%y2!tFG;h)CQTsiP56sK;Fm>beBHz*V*uQXS!TtiV zcTdhY`Rk$MQeVpIhH{>%pW}5QhpWyK{{JJaLkW7q9&J%4`?rE$S;oq9bYgD_he}u{ z-&6ED^#7pizbWL1Txv?$Kco`jjZSaxk}L z9sNso@_KXX*O?6e+}D@JFLfQ~18=5~X@7!stbs@DL{99Vy%P17$}(2gQEc-457E3u zuj9;>H6PX+*U{9QPd%Uify2iak6vW&MacmA+v6#{4jfmRJL5b*MQWbbuXG)HIb6dC zZT%GMuo?KKT&R-lW%jI)R&6~Fsm%D)ykrTpTJpMifJI^zA*$NuT7gyTTQ%5fl;=dS~xRDp_FTi;t@Z&DE(811?uw9n1 z@;$O*uLp-gG;h(In^#lLtOs&7_24rjAIGnLpuTwbBZuxzNvZvYGyPI;RvBmKH_CY~ z@JPjrH+~7u733T5rw;ZHf?rw2%5ySe`FE`KXx^eZZ%yI&!o1{c>cOW@KJH}|x2)3- zC2@bkIqf%cgNpu@|5n~>feTS(+Fyfrn|ViGi5~Pft{%=GGFCn}i{H zSh?OTmb_=9d5h+~@yE)WbwS>yE_~|b>3G)`4jw#_uI|9k@D6_Nt%-f+P69IC^6!-Q zO5oz>%lqGN!Fw5b$9~kq{^~VDeal$6eusDu5L zYlXTlxv~EF4QI)DC7QQr&ePMH59@)PO+EP3$%O?9NeExKbwE-5BjMuPGbDkl3s_H51fcD(_R_;YtRup zQ6Kwft`q8C#>(Fbh~=lSW;Acn{HLy~`LIsN-_(guoqWvsWpSs!z34^%?JFtwYTyGR+2-otUPb<~7j?0J>iVJHW$bBg zhuD2^Sc>K?n)?p&VSSLhsSlqS`B?7q*Vl&@%}p)mNxv-a^v`-;a_Wzi`+5#X;7QCi zzagOKFHnFhfke6E%*8u-!nVn@17Jf ze_oKR)7({*`)uGtWSRC_;697|V<+lj|4#5L%UC(jh`k67^=RIrxesQPJL`koO?~*x zvbek7@|9ooqO_D>X1%L_>aVUDw{cbF-U)nCapR3^gL?=0$NQ;^{jD2?dY7^CoV(cj z!l56{TQv9O8*4tS4{|s4;WHy2Tfc`696rf&2ldg?Ka;;1ms$ijnB!Vk({-2$ycjyu zUI*(i3q7$Db+UgD{K_)+=5B}BB{lD8F5R zjMZ>Ixf{RKI~w|Rr%>;KM=D;tabs|9Bj0#Gb+EsF(@^g+Rz9za-3NzWG;h(I=Wm93 z$Gqfh>cMA5KHwMsc}G&G5oiDB9rg`7<7{4CIZp*1M3iZ70?s=*{?x(2edu!AWf?1+ z#V){MHi}a;=Z({pGwXqzO+EO`$OoJk8})-nM*n&#oEIYAiNAgCB7qrq=Nig=Iq(6I zY;#j^Uq=417j?0J{?9^v%UHSYC6=#7Ytg(#bDyhdKCBONH}&CDCm(V@xVZ25(F6Mq z98bMl4;*9e!9Vr*cEY`KP31nw;Yfb8Hv{)U;K^OyQWrbB(CN0zGFF~%6-(~ZQJkW= zubr;kSs&zX>cgiVaXaRX>d5d4_D>xaa_9x1DDexeoOnVwQ*O71RL>=s(zImu` z87t=%vHRfAismhvb7_y}!+IcRQx85f@~Q80mm80qaIcmZ9dc) zarp|QWX_vKq@KCBONFGYGXxw|jFIDauspMII#gMUOn94CWo zEB{L11Txv?R^UGi9kCbnv41D{m1V4a{t?T=wieA>H2=Y@@@Jipzo`?SI=R}q&-gj& zUC%fAv($TeDc?50PcsTZ8)y@{gUUi~YmkSC+AI zo)>!;ILt@$7R`P8w#uFLLGGqLd}ib`Qt$FDCKTr^{YJRE*H^zx;_sdl;Qbp8<+!Em zEB|)jM3+o^8}MI)j@XI%*uQ+cQ1>#n;&zDT`DP=Uw`l%Lf1&xXPRQTXiBFw;68=dY zrx$>JBm7hTqYJ=st2a>o(}5GwW!l?<{|t1*PSnT#LGUZf*wft(vHXk1YBX=r{I||f z{;U)7H+AAuC!d7BFXnyjPjZee9-}yC={LgP`kOD_p#S;}QTKt5i8|W69k{oVf9yeB z>~G#a)V++YxE*4faM+0EEt-2{4t0-t$=%e4&y0K$?nxbc_Q-x0?rHz@N#BiT{H+<~ zKNUD7v9lU~0shm_5&KYI(tl>)FJt9>j@a|zFc-~RH2)#;VV#h_sS}?W`6T@13-FE{ zwk4nP8>xHv>kkIY50F1O{oBFVlna*jr&u{}>BhP)t2vy3FEM9eUAlpHvQHY+&Cb@| zur4xI?mvlLfWvw;Z_(?re3s_J`r*2iB0c1jtc$$99y)Zy|B4O8IZMBhb+P{O%?~rK zaTDcV37kyy(dO;Je-=7o59&+$&kp=$Y{l&mdoMWDqIrwvKSVyP6Y@88;xi-H5&qE? zdiv$^*DLj@d#^G9$F**%{5v^3fhjR_;NJ~glYP>lK6bXw3H)Vj#qAJF{{3j)qWLeM ztNE}_$iEcnA)gWc(H&U&g5_ao-XkW~E5(@_68Jkz5}rM=+a z4O~+$)W^OXKIx=ecx_|HN|>_mO+pSnxnFJpzj zSn{t$^A^p22l=p0$luh7Pn~>5`A07R5K902b-)XOeF)8s<+$ZNI1X~SVw%L9i*;BJ ze3O0BpiXwS?;6%Y#>(q}SiTNyM)MZE4z0W4IKaGI2U9OTb@EBpfxqhHzg;*yFi*b` z{%QY;`#TgrGVlAm)^4HeFdKLgVWvF~>rjQB*oivXUzrcoC2b z`LJHN4yImw>g1cf4&g~0`t80Bdy{nt--}B^Y8hwqmbxD6IegQj-2FtXM?Y{*xlk`V zJJ9d8%Q9BhL+lb9wxW59UXS+Obv;-&Tn|$>J~Q$eSr2*Nb8>>?LjCQd;Hmgiw^IJ| zffLANn>&Di4LV{k>SKRpUpO9Qtne3me>gOwd5h*hy-^<|%Oo_Q8`1b?XWS=yskDVRpb=zebEBwWh{~(&TX#VX*<!I1*m__Oa7)#d|tcq59Ob5+?D@c^B|Cq9^MzVZiD*I;R*M|+!_4)forl) z8q~+m4)nV1vWyk}V#$9H&0948b`AB9dCA|@iBElm|MBxr9yq>uD86t_zY+fQub3yz z2}NL_-Mua9KX5W$qs_a3e+@cf59(uon&zboIm9qK=arjhDG;h)T*Dgf;V_xz%b>dSe*DU^{zlu5DI>@;ARsrWJoq^*Z@bY=&{cj%Y zP=}t_k2={ub1)nSGFHw%Vjm8N|GJAXF-Ou4iZnXQryB9cem$%fz&NlS9?XrxO=gGy&{W1ABh~_Ptck8h7 zW?hiCsSBSMc?RC@4NS&^p!6H%p7^Kk3edkkr`)T7kDoX1fBV6`iu_|g>SF)Ykx=I{ z_B6Lc?CEe=ismhv`wsG9eUQ7U51(1WC#iGCG5siF$}f|XWUQR$#qxVI8_~Q)ufq=V zVZCr2OuhKj$u+eOV?LLt=X-a&c>l`T_7W)L_Rm87=WrxH+6%yaJ@Di%Z>fu&tz&_^ zjFtKq%im?(ismhv`|@$rKjtNOQy)Hc@(JAijjf}HjvS@5l;3FGC;q8tgBW*sHtId_ zNyUvfYT!PL{Nw%9mGqwo+-2-(ZiiTMuSfG1&3%Y`SRdqW>cgi_K7l*y_teiLrt4k& z^PfkYIam32a(E^j(KrD9-M}^FLVfIPT@?7s*wft(vHX6~el%~<{Fm>g`LIsNzZB^i z<)74XY60lCOWkKK0LRUrr~E5{6VYYbdw~Bebi_{7m-IIRe;F(1d$By<*P?lg=08L} ztP}D#b>dSepHTny0nbET@_v1kzxB_*zSgXw{&RSSnY48w_;&->lneE-bM@lDU&fy9 zc8FboLqD3gX#OkrM*U-6@-IbtM)@c8pMEeDI_N*T4(V~J7XdexhLjI;s zeCql9PyO6bn*Z+44XxZ2^&dD9U8b#r{}Ob>PSnT#`TK?Xm$AZM>>fC@qIrwvKX-rB zKjtNWQzt&NeE#D<36WPv>qp4sy7XC+$744uim#yS$}NcJ`p#ZI@-Nyl#u- zaWECdDS92&AAsWkdbtj!UVQ506V5~aeGpIVl$X5!8GYSO`B%=h7cB$^BJ}5#|5D(T z#Lj9Q1^*^=#6Hx={`m)n<3Pp=f3f7h8qHfY|G5WgKCBb+H+AAuC!Y-dsTTtJ?ZV%` z5X28Ka@=r1`ETd&BuCm~;6DglxyxJXV`mR~-F8{V3V*TWKNZC(n*aKPl|So*{7s$s z)X67IF!1FrZ>f`=ThQ&c z%Q9B@i{)`J9mOen9r_Q&aR9ws2U9OTb@B=8kbWSP`e^Atx(?}a$pehhuYPcRb5Yl$ z8MtwZOnVX5qXk{D6ZNvc`LJ+Y$XGcp#PT>@i{>qQJsJVLSKl)~$D=X_m{ogBVlgtqR5^_YgPct7>Be;EAAGFH|@?Cs$&8`jJB z6ulnXkI?mC-Ecij-S|AncXU1E{f~W;PKD4ve?4?u{6HzkZC#-2uo`%QP_}7c9oC>H z_M%SquRJmw7cy4XLF^tlY((=Gy$;PsX+EqMu7jx;pBee&ti%7|xbW*R@?a_FDIL&t zm=3&%Fw_naH-wA$Y87u1`mg_Jd&0F+34E|czf%U?5F!kb7C!f)EaMzK{ z;XuFqjuRuraM1AZZ2EVe575-w$ ze?FSGX#U%Oqx@MX!c?(>U14Gz6%-lDnJAB(!jyyR}`!)Hc5QuprXEDppE(s94#ZTu?d z5&$gyJBM(d4_qS8^yW$MocZzmK8CkDVUIpYN52g2iGS)rIv+i}@9ZB|{;j|X9@%CI{8ynP_M$%aHy$7AUB=3D z6=LP}R{nLPd5h*>dxGY}Iw5~kCq6H7P4gdpppJgo{Plslz2=D``VWsN_fp{F=gs@y z{lLA1{9`}rV*hsVE6Z3pzlc2@4ztm`MRVU=QSPh{ayRwiGb5jfdw4L80%7T&!#|9x z*i{JiKXXrAhn2u9njyV;f2_kQ^rZKeO4P~z#uG#R%h)|`hgkk@Xg8X-=yj<5t>(je z;X0Ul@u`z*dL2d|sH0yte|?~CuX&)9{_{ss|A7yYW!eXTdkOi+PSnNzt>9Odu~PqH zPlv;7G;h(|`%gmsqi)FE)Q8WEd<=Jgp+A10j(!>36aU@L`^{sh`@o6lGVKGwzXct! z6ZNsb@#IkVGFHy}VtL;0MDrHSzxEW=J?15UQzt%kay9(j>!`2eQ$E*)_dC|#Jy^$Y z5LPmb-#)JVcXD`=BkhC0zXToZr=>n_ZwJ4!j1}%;`CL~etdAd3H2=-NQ~s?jsqDh>mZiv z(2eFTdL8O590!<}>tO1|r%pa*9qa>hl$YFR$>4AOD`$m2`A)^(z6h@afm0GYtML%< zpMs9qhx*t*2!3T5EBwXY77nw~yhZchdYbZQoshq&6Q5ZI|KvExdccnU8S9W9m;TtB ztlv~a*P#`75n-lnVjbGh6FX5S`#Vn$$AOI9<93MU{h9S>-lEr`{S3{A^}=;9_2N?} zS92U>K43?`4F0JH?DD^X@z@Ff*JuUI3;Qe24C^Li<$8tKB{Q(rza@-gcsughaS zUtwOy=|A#Tit)SmR{p&lp1_othk<`Ta833}gZkLnfnK*=ma%gF63f?*K{RjC{M*k~ z{;U)7H+AAuC!Y-dr+mI5;-C4T9pi7_NBPeOPDGb!9}fOC=!l)DkNuVBg!-4U!e1=; zH=}ur=0Clv`LIsN-_(guoqRI*pYr*Nh=1mTc8tGsU(|mNPjaMv1o-y@SMKtb`qd+HAQ78N7o)?Y-8N0{r5X<9WIhwcVb*MZa#{uT$I+%L#sgsXc2mgMECwA(i zrGLijcxqhU-{IFz>N@muxN;uaM`0bd0$=X(mO9zF0o`u9EMw((5X<9XCz`kDb?Cl8 z*MarIbujhfQzzG~bx6G+Kq&opTL=Hbzz0gAam!1(4)wqb9@*xvu?|bn6MIo7`{(~Y z91k*9)pCn2UPPE_AB}ZbhMw4oI@!O}4#$IxmGhBUUgvH{^A^1h^%rYC ztQW3>sTZF*`IvP`KS)P`u=LMZhxE9-2k@deg9qrk401R})0h4R>oNs>@qX%N|1kKK zW$YfeLo6@H%!GCGLyBIP?U(4fuzt8Mrha@LOL!13{i?(9l?Um1 zv;sGsAm{&&!FsGgSL{Z;>|c3lI8J1&tcO@WhqoThTl9J~U#9u6Znz$%ZhY$Gld&H1 zzQ{azq)O?(%X;Xz=m{i_Ydl!jVLI?4!c6;EtV0EQVkhcM`d=Q_LB`5Dh~@jJ`Dosv z*I|f!ST9@$Q!hSs^2u9=|HE5eo?c=cybI=nzQ78MS*TOo;Sa}~Mb`Kot(Y!^kL+MqT59@{NVCuzZc8Ya~4~K;3 zDb^uA9FlRH57l+(=5QrX+9zNgHUeMnQVX5zTn*c087u1`mg}$;&0F+3th`#+f%U?5 zF!kb7&sYaOXh&%&zYPBLPu-zl+?|Ih_qo6)6*t~k0rxrNKe9jS-wE4g8GD)=AeP?) z(}?CRn)~22I36)Cxtsd%lE}xMhxRWXI&x^?aQX}GxZm)$e$iP!ocAk_K%ECJF~ZdL zlfb*fyi>Amh=Thu=c+hrLmbuL!UH}Y>jnzv~F+pkyt ztP}D#b>j0PpEUomp35`*@myXtd{SoIbuVM( zJR|mWIP{`n}3IOs6bD8udDy4e;BsQGIoy}AePrF=A(IwUWe^VbRAePTnAGxUJ|*c*TFw( zk&;ZmZ2sQAa;CXbME~A0>Ob&F#f>+f3hryjKi*GW>~Fp?)W3|C`WJgT9D32bMRRYw z3H6V8$=%e4&y0KwcYi-%jOX%r-bwuJHw-fF;L)h}z=y~(Z42C|k$>z&UF;tOzp{*# z^SxMduSWA0&3)_5sCU#2xtsd%sgsZ4?#>^+ep8Qw(QlV}$75jWzeM1;>BlJl)xe49 zGVRmAzYQI+6ZNrw`7NRDWvsl;isk*Y^=RIr`7gay^I@Hkzo`?SI{6s>Ngbya07B`X zu@0$m?!m~^LU3I5vAPaZffo^G+NWb3W}qi_qE7Y?gI`(3$~uVUI#i>1i(ZHAx9K{t zUbqgXUVQ50W7fewUq^Y#`^OCa)<5@oyrst}|90S%#Lj9w1N_&ZBle*__OEoqaUf%b zzgRwxw-L=-H2>z?H6PXq`I|cNsb}y{>UqrP@kU+;{J7Mo-SGZr_3?N;2)u|e(>@dH zP=TJ1Oy0N~vZl=C`>f~e2U-CLW@)!pFGR|Mtf8>krIIi+UUg#1mN_|(ZKgMaEq82xtP?;pEJKZO*| zTeZJc{+l^G$&vOs;J+2Pa+kN%$If-=b=zebEBwWh|4uY-(fm8_QU0tG@;7zjQzzF9 z{;9_<=(h|1U7yEWeiG_Ga3Z=)y9)jd=!l)DkNws4Q2#Pk_=_d~m1y3g`Om%=^^bYU z-_(guom?~cXFYDQ+xsYk*cX>;l?Ce3e+b+x4J+2{^ z?_*0*oTArZ{e3tNpqJ}l>cywN%Q|Gfu+o2*;{oH+m$Eso_Y_@+M&Lz+nf7^DhbHvI zPSnZ%+WW)tAYb^RW)Yz&GVWo$TC%Zns^Qv2tD#%k$E76sPEQ=zUPvf%U?5 zF!kb7C)ccXNWCyaDE)U^2mb<{UWVj+Hr>*7Xa-)0oNZo!by$I(*o!*Z-}q2C9%QVn zgV;TASc~Q@dL3#X)_hnmTnAGxJ~ML7T8GpNG<48^w{_U#(_@>%e;9I+%L#d5~+?I%K_2(|@;hzzg+W zdq{BH($jSvRst^~%(O4WI;=uZ>_naHZ+;{k4>DHHM`C%Op&QLx^g1*?s`;>9xDKXX zeCp(rwGLS?)b!tN9kO1iId1hCx(=nliwHCAi?9yU&=WgRXVQOJSO*y^ug_w+4s+4G zMX$pU`LJHN4yImw>f~eAffpv^^6SWhM)c2EhxE8HpHE$Xrmo9s4(Eg~8f~mgH}Fom zP&YfqNcT=YO5=cznL*I_+}D|yns1nbZXe7Vb8>SSjJy4`kJ#>zT~<@?#~ zXx^gNq21GUV7+i1OuhKj$tQ0e{tw56Ux)ac@;FazRo9^!coAWyeJR$V20gJ8b+Ui< zif}y0SXl?LT!&^fZ_(>8^GVHz^}=;9_2N?}pNw^I*Dpp6hvf6YF6SpdE;<~Nam&xu zb?D`AB~RLyVI4LDU+(gjI@!4n-EO-qW99v<*gbFsOTHpmj+2-X~hX(Y-Uew9{*-wY#LB`5Dh~+x0MDrHC4l|$8 zd{{4B2U9OT^^A4k^QM%R^2^{)|I{5j#_c^{xo_rhOiki8UIFf#foIBvy4cx$A$8^+E2YK78ur+KT2a zn)~wSH6PXoxtsd%nURm>KKeB3?%efh)Uz_LPgGx|+-CzH5Xm;L0ry$tAA3<((*K3P zUB=4u*J62IsYmk`&3%Y`SRdqW>cgj=$vxv~RQipaUtGQ0r%==M!+I^Xm47FPXTlMU z*MfgHa80>TA3ImR82HOrc|8@&`v?7K-lF+8zohxFPRPF$=^ydh>PQUP1opz3#jn^$){#S;k7;i#-hkYtg(#bKm~5a%X*z zyQvSK8F?n${oR-NDb!HEBis{z`xI*MUw?^mUkiLcgi#!rh%eeEmibLDFx8yY-JBesnW%+}2B#|8(F) zbeZ-I;6DQ$u@m*Ne;EAAGPdG&h}{E+YBX=r{I@riKkJ12O`Z76$Y-?f(+fbq5&lWt zi+}#_U6)?2{M&&O$Yh%i_^&}n>_vU-U;bLCe;Iqa+aZ?M6E>oGi{`)dbcH0@;7zjGfVjJb8O~Qr-9=L|I|~b z@)7sK1IPJD>9O>eK4yLsq;|@!efx9E$-1qq;kXHWi9FN33F}se{@96J*gyNtux>I| z{$5k;5*(`0yhX3u%s=6{LEUlPOnv#xM%GPUhcg~>q2I{5S^trzPQ!W+U#0x}IXreO{&A>I;Ck^UjXBT?ic3H+&TtloJKk{!F&0948wJqh(Iw5~kCq6H7P0m~789m%W zzg+(Qp_Vh_$4-;_pLvb)uLVwi{=EOa1^nyK5&Kae`)B_-)W3|axE*5mz+pL>w`l$| z-_m?oC**JH#AimXBmAR>TIiR{Kl7>6Q2+Cro zz`qV1u^;uZf9~6%{$;Fi7t8mp%h9|=^RIjd^^bYU-_(guoqR_4<0Y8-Xz8E34t(i8 z)BLD~8_aR-*W)$b}>R``o0|D9;wqWO3JpYms&kiV%DpE|jY@=w1I(=VTY)>EaS{-@rE z`VX9lF4Mjf{2R~_J5e9|tKSdxFJpzjSiTOgMDrHSfA(Kd|CpEjO`Z7E$#s-}^g;}w z^v_=hydbBpUWav9IoU^`!1}*cHqlh-clz!d(iE+%Q9B@i`_$qC{EGqu>Nm2 z4xpFoVCuzZMy{jlko|&8|NM2}3v&9D#Bq%`>pC<7FA~bMmtq~7&=WgRC;MwZ2*-nr z75-xRdb}FVTl6|qf2jGeUbqgXUVQ50ldMDf=}^i`-q(!qPy6RSP0D#%Z_#zw&f%I& zh{n6I4#U7Vh;X0Ul@u`zf_Bw>egXp*W zI)tZ3_Z>OB@5HfV2aec>Ed-9AwN%=8tFA{gaKoN#^B$~63%X)2>Scdp5RMBOE9)Wl zY&f)|d5d0;+J9(1tQ)R}sT-de`HZZGy#F+h&CxG+J=EVk!J@)BZumCkzmvlgm=d!N z{w3&0cA!Ch?B5E0Wf?2{#qNPaC9IF{DVl%(N6MddLjI;sd>-VJ&3}U9!Sml6|IB+* z|1)n_{wskK$Yh)Mf`1D-VlV1rf8)oY{$;H27fb$~Xx^gv*Zx!UVV#h_sS}@iE`N93 z&Xj+`F}MD`fBdv)IRDJQ1NEQ7lN@Q^2mU4KU_UMOaeFKHm1XSdZiiS|2l-bC>*KeJ z=HLGb>K}T^-_(iEV^{v6{Kwz8SkMQSHpA-g5zmfWBxCj4K(bIq9QsurJ_%LLq{UEq6BmdZmy4XMe^HA?H_B6LcYz+=;(Y!@-pZkU8 z!}=h1Qy)Gv@`<=F96EC1@NtTBmVP%Ua)tPgTG_2DxkpM?9uiK7cA<%!*N&C_p$d)hz!(Mf38@|HT;xe48FyDVd69mMiaXs4q%MXy8ezfu3t%XKjI z;!`J|taWg|2fJ@E^(wr}dC05-#<@S_Ae}I-`vDvefmd+KXkCVNSb?6{g*w?^|7|!P zWUQ=%*d;iuMe`QD4)edm@ql@`4yImwX1lG!zWqqv8T##Z9PHa)Nxuk~aho4h{=*!e zVJ2-|4*olVYs!WC*x83(w_TR8!e8to;V=`$DVqPr|0sXf3Hh5k@tKipavU66xM=av z;>in+F6>)G?qcXS!r%HE{Pf@XkaAxRd`#5Q=EuN&8TrQ^)W!bl|AxAkvBF*Kv*556 z&0940+23nEtPgTG_2DxkAIH6R(Z%wRV)`%ixZm)$e&!v&3Z;K#LwOH!_yJ2|df>es zI41j~K|So;fIhcfma+0YqFDL7EB~gVI7RdB{y}-OF38)|h0lw83~zU(Z1gYn=$FAg z@lXGyo)4cKAGMDt|3=`X4mtn70{oYtBX*-c_Ai&NyRqk~eyc2F9Inzv~F zOJ&W6bwd88PBd8vNb}G7i#<4&uH|*km6T`e4{A$^eqAZ9SM5))>iy@ZwH~gAFfVxS z>-}kL6>%7ST+8|Czfs2V^?S{a{bJ8>>u_bPr|r*bm#?I~^N5$_WBV%bqaNl(UFEBl zO72FadYee@gKf(!jyS5r>RkNslLa=Bi6LQYeNXX9kGhsc9^O4z0@ zd3}&4Yhq3%#NPoI#-6#6a+*QMi!Qt99@3;f`i*O6BOTo-<;47KoUrBXL4)JW9 zto982sE2t`S01NXjB9}lV|Q+>ocyWsKKhMoS0Wud*HBK(&&D~| zF}lfwoLY!y<7Bm)@S`5)MO}HXcPkiI2N%X(zL|2GM#pp3zU_Zsh5G0>uI)rRD%Vs_ z%+JO-&oR2`gq*s6tnqA|taclI)Wf`}EARELgK>RuVeG+a%IP}jcOfs7p9i-N5)f-p9E4KT|G@y;MmbciT-p zKT#k3#CU787!+AfAnr)t-VM^)N5$$~*36 zFmC$h>3W*mquV_0ZhyW`7|2sE>Z*+GeC%J4Sy#A*W@; zvvIQ84fs(H^P(={bhdk=86S5|#=m8{o+^K?+y29foA3oU+_+TcrM|2jcI#_%9ym>3 zS2;01JN7Ov*IP}0bG=*pdZIr1 zjcYd|9o6e;-ptR&xvOI|J0YhYxZ5~c?JoSNhj~$#oX7XNyD)J*ZD8CExG?t2t(6nc zPv4!Hy_W2wKKhMow<8@(*H=!=&&Ii%V|42YISs(w#Wws>jbq!>chvpM@S`5)MO}I4 zrxwOF!G*C`=adsa2S4If5A?5hCFrByxV9VVXxv2eW_~u#e#c1eyy;3{1ul%;IV;WSho8CBb4v8laZEcK>FC}}^JacF%=wOyzei&`bK0!GImF9xD{bCI z=bM2a^)N5$lJoxFjO*#MjDL1iPv@jLUFF7FPt=!}PhNkW^T1*AG|ij&*>M-RT;(3k zB=yulJR8ThckZh5&BKp+m=|>kr>y%9b><5$jNLg`Iq|&TyX=tvoI`!|8`rKxI(Gg{ z^JacFPEFQyLQXBjvvF*@GOzPB;YU5pi@NgOzppU1=61@7 z`sg>V?MFIlH`lzGpN(@5$4KtcOu}gs+-)4&Ub;l*+khYSFfZ!LJMQ|7f5)hv?v&>A zl9qC!KAXch?IGuZ^YR|eoB7!o7dl3Ak7g21JK%2P*!Johb-r!*Q4jN?uDsW~A;z`9 zg|Rz#R!+R%_sronpCS9GkACCY8E~Qh+ATD1=Er`q2OT51M>7eh3gX!~w!Qu)oo@<$ z)Wf`}EAM^j48~2}C0$Rmchzm4#~<;XYkX4Xr9PX(IPLjJ$L1|HZ{}xX9CD209?c}2 z8i;4(*!Eyi=bM8c^)N5$D!U8g7aTq5f2->JgA2#__fYZs&UwUXgA?akzgwEyBf*V& z={K%jiF8ffN_8+_8|ScNCiiS6;nx0hjc4Q7cI5)y--I9aFfZyVy9-g|X8)Ey=C*=3 zmHBkN%`c?6z4Q9l^z}x)Hm7mg>yfUxS=GUOZHyz1ncTyfgxdzz!N#%eMos7Iz>j*E z7j?;Txz`PhIjv({2V5AtclR`>cYzc2(QjP473pZ)TJvUpHcs6!l6yFlaM}iU8^^X= z2XwwZ{HTX{QCHsehb@e&?2GDYzi#vW)z6w*Pt<2~7^@8~^ljZn^JaeR7kf{~NbccG z!f6WeY#iI}y+h|4A`j{*VVk=0IF%5;11^l+TTF8rf)n-8Z(KVY>FC~8^JacF&QZrm z?%_Jm;_&z;R;T;=?zo-WXB-sd{wxA*kdX{gWUFiyK3 z>DaoR=FR+UjAM?G+{2lK(-Pv@IJP}?o<4Ur4?pT*Uer}~5B$hCi5%OvaQN`z(UJ31 z9pgLT!#R32<;CmnbC(==sO+Oo`i*N_v7R%O7xT1njyqOzk75#DtAC;KY@Dq2GW@8A zc~O^MPd;aaQw!rN2co*Vhi>!z=+sqqKH=wuzN{Q}>+423W^b>$n4cYc!ZDJ26q9gT zA2Y8t_)$-i7y9$ww|B9>3ogvJf1z^vQ*>PRi}DwxNqzJi*KS5S>T_8Cs9)k;A{bBm=|@)dCJ`u9I2;GjGH-_uBYlD-R5(jTiaLrspOF8J5@r_{+&q2 z%9+ZE`C0dSIYx3#c@j<~#Itd1yLLq98(@8?hj~#~-sj~VjBA5SXIS$0yVegYC*D8( z<~@`X_1PT8X;&g0oxPej^RqD;j*(m=o`lmZ;@LP^?P>T?5A&if;dEBUb6D*UL2c~Ms$ zry9n!!G*Ec@0qTr^M9rFM1Axd*DgmohG%Qu%+JQTw__yNh$rE+f_OGgR(lD4)Wf`} zOU~nGXFPAcjB!&(mCO8#ukMe#*<-rR^V9dw8U94(rM|2jcI#Vln#3;z>C5!QIBO?Z(S=zIFIf5A&ifeg8E2+(M7>Pbe40u3V(syiPUs z=IcLE_E8`G#dNCZz_=E; z@IHR$Ug>(`eSYe*IgHbu1{eCa@1S`zKlY3LE5}H#5l_Nt2Jvhh+wQ(X=PSXFdYBh= z<$WHWX8eY7;eGtd#k$ScJKpD~KAXch?JDPi^Tr)DZ{}xXoOF!j8u28Y<`K`vvF*)Q z>U^{CqaNl(U3urHD#opX3uAZht(^FIcNUjl2 z!fE|Zs23Z^wAU}z{dM?J5A&j~@&P=zaP05__q`P-j~+PxVCn&eg%ih*Wb~$=atMz! z#Mk|nFn{$v$~U>ce_!3^>jCfolarA$R&z7rQOA9A>a;=b=UB_N{OC*J?3KAXch?MkGhb2l7M znBT^DfXh{`B~QX>7V&Hx+wQ$q=bMHf^)N5$%De7R!MF`@;r;!sCFR7|1K$6qKAXch z?OLRxKd*T+KO5tLj*(nTo`h2!@oXI19=uNHtHO_Zm=|>kr>y6ZYZy0wKjp&MOZV4p zz7PA!!u9<7FzTb1@UYg+wPy#`Ig{EJfBx9**La6T+;ok z@S`5)MO}Hv-5SQtKQOAN2ceJrw|38RyG;!aY`PoQK z$4IUrPr_*k?lz8X&p$vpZNZOvm=|^BaT;J;?IFsA_xGDk-R60m_y4KS<}gls8eHhx zIbZW;e(V?fP{&BFAy2|-7V&JHRQs(uUkQHH!@Q`g>@Jw|zWm`MM-MF=)F|=$&S}Ki z0w>|LA)bw6+ts(}d{y{S5A&j~ z=sA$1iwF{Pt1J>a zUhXQlW%yAK^P(;}F0-CzXkpwCTzG$f`jKf)y#HT@n@FPoIV0hi9R}x zX?G$WD+e`i=4Zn^$}y5_%#&~`A)bw6+x3U(d;_cx^)N5$%HypFY|gZ;@LP^?JE4Jhj~$# za5~owbSCw$hH*>a!uznT$0{d&e;n`AQeP^_7#quxjv?*?Gd~;R(TJQ4jN?uDt6m%NVx}E=laiD<|Indc_-WKf0+vF*m4{>0zcTZJF>FfZy7PJ7*r!nmH+Fs=bEjJ@&%<;2f5zrUgW zy$$uzZ(Q4pbj%-BUChtMd5p_duH{X_sSoZpj&08@>wN3*qaNl(U3r{(7`F{BN$e-4 z>*=Zo^*TKDC4OTz29b^??r$tF4@qOl7_Fm#2;iEqKjccosj*Sz_iTT+$k9WDswY*6<%_E+TW83Y= z=zO#AqaNl(UBYSZjOxhwsfuxpCo31;hh2G!Zu5Eq@6%GB&0(DOQlw)W_ko$8jqwDR zt6a;Qgi{moY#iI(c&u`&!;gBH7j@-vTEe((aA{t0HUGL$dTP3!F1Y-I{w09=Y!2hJ zS0f!$4b7YR*%&L1kzC80gj4%o8qdbD?d`|u{uTI95A&ifx!!r!nWOKYRxxe~To}96 zQcirmyZF6&U6}glH?Ccebj;!YCiAm#p6D3KwY*6lilx7v6`Rdb)Dr=N8_lr9PX(IPI-SNB7>EH}kVG{?;*)Yk8A!nnOGrC#&7Z`cMz^ zqOS6hvHxEF*a^8YeQfj(>Gc|1MzGe+wMG3=bMKg^)N5$%6t8+V_fB#%7wA# zpOxlx{kte9>Z9Mdb|uoWb6?Gy`Pn#6c8uiO-z1z`h-c&2cK>g6z9#&rhj~#~9;X$I z>wpVm_nw{RboPst6ZO$=T-%9sRQ^iyW_~u#Qye3?_BRQq?q6y=8^^YXPtyHu_)!n@ zqOQFAU>%IBJSVEBRo&+6!mnPYpM$8+<}gmXAL*#!J}2|DG5*dml52mHaM}cS8^^Y1 zo}!#K;72{oi@NeS^)apsF3J7a=PD<@ALIR6>a#hF(;h}TmT{kx`Pmpxb&TZN-z1!N zz}?2N?dDUJ(>DC5hj~#~9;YG3%{@=K@P2Il`DsqPUrT*9hjH37;6mTE`)S_HkNsj> zj*(pZn}kyZ@oXI1Znt#4Dfm$j^P;Z2_Zc%7w*fA^AG`H}G$-D#r9PX(IPLjJM-TUd znV*gEG{;D;{Y}EDhIlrPZErkHInBY3dYBh=<#C$FxcR?VF1#PR^g`XfF(%{vTI#bo zjMHvLItI8O%=~POr#nV+?QarJ%ZO*=*!K3*l~V(L)Wf`}OO8AFy{h>AQxoI*;KJC0 z7bz#6$Ip3e$KSu9KKhMo+mVjSgEVjEXX8A>F_LS4lW^)jP~+J+wmtVO-QR*A^)N5$ z8u$Kl8*!G}%87HeUYzE3F1S%I{l>NZNLS;*s)PC3IL~y<j*E7j>1dY3|#*FTi4qxZe7RGX$rdx_<7SercN9W8bCs3#pg!#xZS;l|4a^d~h$}4o6 z@2_~jmilZCOfs4K6Y zRxoaQO}Q}k+^ck(_rZShX1xzaee@gGb|M{>M`+&6&&GMKVOfs4K6Y`WUwZE{r|%TIIz1&u3rqnLo%r>Z9Mdb{Oecew1=zem2hY z9V5B+G6|<0aJO-6d-yfIueuFC>S12gm3Q4`h;b|6(!1I<{Pp;?*QJlUN6lR4buusY z*&N1c&wvYk*Zx{LF+cW;eSu>n*Ip*!R6#r&C#yXLKk8v#)FqtuR!8qY&tTjTTzEfr z`VGp7@7H<1min@C*sX6q($T~HVCHAX{=LgpuDwjcsfKtqj&09euIn-fKk8v#)Ro6+ z9^+QPg|XK<>3aI^6CsAXX9kG8}OqZ=0#op zxN{!>|#tRt~%MZA3b%xX;P_?AW$r^t1^% z^}yZ6vF-LJlw%iuy#LI+s7vZ;?u>Is>S+Vx2H?W`u~TnRPJBPk`?b_(a~P++9qCxY zeNN_QW4zeqD%V~nsiy(B+c>tp(Nj*F@S`5)MO}HEwlQuQTzEgW{nm6n@qR7!*&N1c zPk{@4S0Ar=Ge7o=eTicv*Ip*!G>v#Rj%{yWq4Vt^59(oF)FsDV*8S%x#2byWMslrX5>8dbvvF*D>Ql<80zc|uUeuNMetZt& zR=|a^*WRw2c>lTjV|~4&KKhMo8}Q+_9ExG?Vb&#QNDdw%z@VuEz%asE2t`mmI%YfA`$SxOH$z?!&$- z&58GEsn6yxPJ0;XSjPQL=4WHP!ZDI-G?Q@J0e2h6wl_bkoVMXdJ^$Qr#bOHE%n(P#%a%h3w_s~ta&p(_KSU`V=}A56t{*j5WtduF*`wsfKtqj%`;y zubk%KM?K7oy7D;9V_bDzxiEI)y}Hf&U%&g&LH~XC)JMN@Z8Op__&d#;`Pn$Ha*X5} z%_N+b5zofSYB%6VJkyr?Vheb@%ZZGsE$R}Vj!=EVEi z)Ms-Tr@bBNSi*f^=4WHP)-jT6G?Q=|fV+)j+iPD^PMh$f9_B?|d7QQ}uJIw|!u!=L zAJ%Q2pLjo;`fLv4w5Py@zN^pByqO>S#lFrll4~@RaGFLu8^^YLU)K3{kO%cJFY1!x zZg0kMH--4y;F84th;q6KIxfGB{vAE_C4OTz<{};I&(yq`pAGYR$4IWxOv0&(cs5Q} zy8=JzVP4dgcOIX^xF)#pzW(Y*l@s3=@V-CwW#zD2Un9~nc$RWves=5|93#0#GYO|< z#Itd1d+-&VuLeKrVP4cV?sE(c&Ucw|O781lp615;{?u!88mHanJaDey{y6isF*=T! zT(g;kTld+@#m2Gi%BJpb!H;^F7j@a^7!DmcdJ$v9*G=1q(*`Hr*I)lwnj7!?Q!nF< zYx|L|8t#`fUmNEV$4su_Ou}sw>tN&9cH?WxZ3BMP!@Q_Vj?1j)82T7D^Ks?E`});S zq&e}vKlRxh#%T{D9m~(vyqTYk@kYl;uHj6=X$RbG9NTVvUFX||AN4RV>dNCZ#JCQ) z@VOf zs4I`t493k~p=?lFELd~BQ1xWNlFZ{}zH-{Kg_wU-c~7eeB!(-_cVa{l>NJNXPUG zl@s%`ao*|}$!FzBIIaD?#)VKQR9~dJn4cZ{HpfUlD^J3y2kthGZP&JRzApTzhj~$#+}FwaJJk)0oBCY3 zo@V>H&F>$*{kLDZF7r~K&0(DOcBEset$8y)8>8!TmCwqPa2kNSjg!^hgdg=VFX|Fb zXSokH@%yK3jB9~Q@_pu?S5Ca2%I`a;zN{Q}>ze`>`mDZKIWa%>i+#JxRX!_E!f6`u zY@Dq24)UNL=0#n3oTeE63+Z~Qd@)^5Z+O;=d_7TLRt~%M&2b($t-nM$F+V%@9gdNF zR-S}Y74dAGtab%{)Wf`}OFk#xA>(uM9LBAH3x9`w?Mupu=O_M7JN0Gduv=dv(y{eY z<;48#*mpWc@>zKjPD_YqOfs7p9yJ;%_%xFNXk`^=}mqMZC6NxBL7 zedp9?a~P-HigmnP^JacF#=9IN`K&w%r`4BfJR2vgy$nCrg1v#(HH%+HR!)a5FljVIx>eu})R-_!Zl;72`4Ug%d& zqu+Di#r`3<@cYcCzm~2ie&0FuSzY6_HzOVOS7QC6eu?#N$LNv?IczJ2dMY8F zjg!?LV11~Ec~Mv1`|%x&8-fdCPyeHGnnuSjukl6ydPjZq8`oAM9m7{CC+274tUE^X zS$GmoD~M;~WVNT^M?K7oy2|&&a}0+T_aC_Mz;XLS^BI3KpZmA;x+DL4+$+eV3(ovr z^Zqx|$1%V6oV>C$?bf#zahZ9Ia;IK9_Pvg|e72s1d*{_SFW5jC?N#_u5A&ifIgYcQ zXIR6y*>5Trey@4$pVFN8z30@Ik;1NBy-3IWYgHHXvxDE~7|CbrNjUYv-Nwmkufvae zm=|@)>%y7tfrj|~eGlWh;KJ`U?{B3!@q5pyFDr-L`Ua7X=IfLb^Rr{$?{byT){}4= zg1e2A)!u?1^)N5$l6uN|?qh&)v;VAI_`T+}Z|OE)7x=yB)R&dRZhh0>LZ9~Ql@s%0 zzt|5rM)KKu5>7LSXX9kH;YU5pi@JnU*7vwiV_X+p7`y*3%8A!USD*N%j_jj8`i*O= zk&cZwC@1D;<9yIDlF!zYaGFOv8z-wh3qR^%Uex7}yNvG>t76>Tx0MTj&%XX0-RApN z{@y+HW#zD2-%_MwyQ7?#pB?)l$4EX~Pr|8*cs7o0_Xav&9e&iqyr?VhxLd-wb#USD z*>8R~&56HvPklCraoVeqj;S|l-ptR&_^@LnpRFh1)V@UH**La6_z&H`0zc|uUeuMx zX%*wIhlF!zYaM}iU z8^^Y*|Ecr!;YU5pi@NeSZDCyX`^tr}8~>`?yiec#`8A&*`>2n8V_R^cf9oxpH}hk^ z*pE6!^4WS4PE&|y<7Bmm$b))H*ru+$US;KGKXA7M8J^4HTp615y(Wl<5oObJ5i*(JrUAZw|JN9FanSA!1gj=Vp@ob!|_A30S zhj~#~-hHq&jB5;(3%@6S{5w<^^Rr_=?ik5uwlF!PMa2kTUjbq!DU+8>W@S`5)MP0%v>-m@g#x;JdTxM^h@mBsb&1ncu)Ms-T zr#%fW^liUO=V5;A7u$1;n93%OxJPD_H#Itd-+OzPZ9_B?|!pYqR8#(T( z7+3$Pa$)S{pXoNA``9;s#%Z#T`sg>VU5a#UzgsymKO5(hj*)y;o`h2q@ob!|b{&4y z!@Q^~ub!4Lt`9D)Yh2ZT-@ss~oOmDXm22O>LguButQ>ahTa9!~tt%(yXUBfZF_O>9 zlW=Ok2gj8Sl+j*+AN4RV>Jm;_=kZmHoBw&bo|b;0+k7ATneQ*Vzql)vs4pXhUAxvJ z9dqwhUChr8{B>S12gC7jN21D#3z+rqfo zuhR9@{4d?+`RQqUKIey0UnZu9RWe*c;)ret2~%gSN5zIvo%^MlHX z`Ps33$4EXaPr|8zcs5Q}dmet&!@Q_Vt|w%D&to0qHo>L)kZWpv{%>V8<`**ID4HvFiEc~Ms$ zrw+#T!G*C0|D&Av{a-)dY2Q}%Q6K%rwf#s(?IWs-`Pn#Mbd2P)%OspO!QIBmYHz@g zdYBh=38$?0PkoH5{%^XT8o$?Ve*f21ulV7wWnSvb%3-&@VWeaEqsoc-*|A@8jO4S+ zB%F4@-NwmkZ^Mszm=|^B-M1QI+y=OGpQ7Ijy7dR;#P(rI$G9DE zVeFYJD<{@d?iIp`4hXjkD=;mCr7da9aDg#kyr@e!W&Qrt2F5Le3%?JmeKqC8&n^7EEb7b3VYj~RNXOC@%8B{e zv0rz&%4e5JI1Rwv#>r}L!jF2G7j@-v+QzsYaN+l1&0IZQPyD_t>dVSux4tQGq0j0k zmDB&{?o8ktIja0`k&p-yg2(~l3K}wixSa{fid$yJ84a27C^M79VSy3LWnh=pvK$5i zh=m0M3y5>IoZ|L!1Q9NCi`(30As}v%KoB8^2m!?Xuh;MW)UV3ba<^w1cK`l-W~#dS z)vNdW*6YLSb_wyJoyu<*M)bQ&5>7esr~UZqBZ&ig5EpdO?=9Z-zr_EdaKU<5t?M%< zT<@@67WDaInAA4y=;(Z!IUzpX_nU?h{qB;4Q%U@3KfZcF?4Sp6K^NU;`abuahW}%j z3w#%jk zpetjZaq{|K`}fbBv-`lo?K5+8=E0|0+iPZiR&Q?jHf<1wdp|ZWajXbutc%sVfqfif z-7N6(X`0lw=5VQgjyXZE?)xpnoPHNd!o4T+sQvirU9p26#06b+zT4)x&sdXwrQ?_j z*2S8?q0I^FW*Py6T@M)bQ-5>7?&r~UZqIkAHt#06bZ z@5dCRU+G571?ytXAJ5ykE@0g(=<~%esjcGZSp5QXLVUXKcMK!?T__2ss`%4>eD#vp zK@Z}BF5={SZ?+=+y21tPJ@rpuPPiY#dQi~ki(yh*-O(}pB6C7~y6<-lBl=w^38zKz zr~UZqHL-&p#06bZ$6a0eRZe6sSnp}!B%2e~gMvO^43pYgj*k47nG@pEeZOZI(eFY@ zIJLjT{D z=y#zcoK}Uq_T#H}#14887jy;pt>%Wzy)WoWzxkUm7p(WRnCESGeJkkm#W1OD;OJQR zDsw`7y6+DRBl=w^38$fO*M5BUp4ef1E5rp|QTa5GetqGBb&RHN#++~-$2v#Q=Zj%d zTTZyZru{YMg!s@-UJS~s`3VVxuB z^~N-zvEu0JtuZ&mtGoWlFr(j%l5neuKkdg?FNq!WATH>NyKYlO{A6#zoUo2j@s>6> ztaAjtzL+MpHC$c)!`u+B?%Oxa=y#cotzC3es=j!W8!lkdHcW!ay< z6?4HlMx}ymivX;11btdpocfxhqxwymf2W;%U1Au~?>0#|^@RIIv2?`_dJq?MMdj0) z^lJ+jtYg&OVspYeM`L{(1?21>IXV_EW=@Dtn_p@e(eE}%I8BK^?Z;Oi$oxPL;({*X zy=y#hWoQmR4`|;It zVh25l3%ZDt@AIyL^lJ+j`0j3HPUh~{i8a=$tJlO1dJq?M(eHo0b(`wauOVFEyL~(6l#_-#znH)G z8~R`uw`@5&^511nh)?_ZnTeI|sgiJNe~0~PKe|5nE$?3vJLo}N&_$el&kI}9ZzNpc zJAZrTg!hQ9K5xe-Xdm>!E^gU%bd!siG zcs;R$9>fJ*!Ext#t~$WH3Ky(nl)ICCe!@CO(5GXFQ_l$(*fxK_aU(voQ+c^zME6ih zIOWBk_T#OK9rPeB=!*KhGbjBPgbREx-I+PzIsN@EnG4qQhd$WFElZA$l^-%E#HaoI z!Z4zHs3e@q;!pe0^`$@Zctx>;9>fJ*luy2On@ZAeAY8DHQTDFP3GeS=og?VeF~q6Y z93A~1aomVc`?$iyO7~DnI4y`j?Z;QIiXHSIF6fHlRFi%S!UevUrtN$>?dh-i8tsEV z*u^cE939yoGbhBS{ak4n(LGcWPR&01(|&Zl_h;U}D0a|;xS%Vze==`$y7x~@(yuRE z#=f^PCtUB&+sc2h41Hs}n3ayBWBL+~8}Vs3R~bfh50!+|ig4F{biFfmV(>m$TkN0* zaX}YxI`xe8oI294CS2gVaT;^N`=CGi!b_e?`=AeYam${gqkSoJLVViK)rJw>LnYx< z6o1-}uf8ht13icfx-z@u`SY&1?Xz<`cFpWNUq5UkpeySBqAvYL!UewbC7aXN%bZWp2fMgs%h8el8FNB>+RrtH5#5U= z;ncp2{b@hC-nuSxS`s_xL0r&9*G=Dh3@z!mC|uyXb$8~3>%qeoc^x9?gI(OR>*y#C zSQp~cetuH|l|!q1r#;?q8^HH_$9ED5KfaMyl(^`6*458{F@;^g~&mx1(K6fRhor*$uz z6V~m4K3@!z+H%4LHqFbK6XHWVmA^KO=w2)dr@Z*ne!O+DgC4{MT~VL+<)q(GxL{qL z+e!-j&pYHk_!-($1l5i@EKkdg?FNz)XATH<%exLUI-JtnC z%-}w*E?lrKPxHRa3GXRm-5%)k#W1O@=IH2O!Q&!6-S@YK5#5U=;j|$Bv>#u+Dt6F= zxS)%UyHihJfB#gIena5`-?~#E^fKx=*VBioDiS(Gct_m9x4f^ z_Lb~U`_c8KWBEM3D0a|;xS%WUbLS=TvnZS}R_lH?w+n!YPuV$TySNr*$ zVMg~CH}M@T^}CD+y*jV(1W<3i_Y`D=cyy<*AOo7 z-JZ2MeMC4xAME0m1xH8wm&^(AX+M83jOZRK38$j?(|&Y4pJPrrv4bAO1zp6+_k6wp z|7S86tT$8G$=kTU!g@5&r(=jyuV5T8UcH7nAwKQnkA@N5V~d9xDl_Me(Qo`06#W zgC4{MT~VCs=qFs@J9mHPgy&y_XTEX^?Snqp#VuQoj{L8g6XMf;{%jc0JysGz{3oksI_CX)) z;+6wP$AUcHM0}Q?Bd4b5nwNyrP`F!uJR3dOi5|oSUBUgj=kFp0(yy|Ix!^hM!W?ho zb5lI0g+5OR6Pt3v1xC#g=M&;XJCzy3iLQA`IOWBk_T#OK9rPeB=ps(O=gv9lw<28d z9JaTYIgPJ(^4uBvyfI8@EIB$>Jcpe>+s-FEr-eRW43pYwj*h-O2S$9l?-7O*UGtJ~S`dHQkFQ=8JLo}N&_(Ab z-}eR8q~Ee|f$!CQ%n8@Kskfi_WZDOPu!~zRIXbfPd=v3$KSvr)bj?e`sriS=*E{%M zgq`R?T+kKud-9U>E9_@3cn(`Wz}t8q4bN$z597uyJBUv@O#g{>AwKQrx`q>7^OA5{ z5$@WLuih3r=s{f2MaP}*xpPPQwS)_Nubji2@O=KLn;iEn+6R5Gi(B>_9rN;h6Y*(3 zM;T62=3f#{ec`VC`0A@-2R(=jx}rGsq+kAA=7Q(2rSt53!gE^a^TjZ+O}M~jTAptr zKD1MLv|&Woyd<2me~EY84J8ifnUZbj3htjg&z+~le^a>NIc#U1IpKPT=d{qLb^YI{ z^ZG8+vYyHOUs&Ii%opw~-TO;ypYpJWKjKl3eR!d|{b1$X^Mk+m-7_=4zdAd+qd@DY z;0N|tzXa>bV1HDJ^*(A^oMHVK_=dg1@xZ>BGiL*uFq9JZ5&Xk`)+~hjus#abt#RD1+r;`ZZPDWz zKquPOdL|j_dy3gX&#o)^H7s@Ly#|+2bC{DWZ-Jg!_2-td-p+_W#{J~*ca$N z8b9!h^;WPB4)#ZtSg$58@w;}=g?6luVzx8Xm-3&=En-l1)|pA0d;hwe|Huz;SNRb{ z20n`WuDM+Y)`5qehx^#RKwpUD{GcD!al!gJj@i0Rtb@}M9j*cNp&je4nC%Spy_Km@ zd22CPapo~?{6j`el&qQkX;KD1*!7qgwAzQmo%+lWEQ88>bIgDmq$o`Ao~lOQtiQT)gGY)ydZ zfW2oPtbXo9pdZ$s!MZ@=HnPC_J#EqB8bT-9v0jYX&QM>P2P!cSU1vVio`;3&%W)v% zVjfh!1fheEnup*Z*uHya|NhzikT-PIY$QL97WRuuOsRuDnv#-Umfcq^=17b*9Q8~j`erUc82=W`HMZ zeThGn;NOsZgnioli?V(W@&x=vz?*7#GguBH>MmvY4h*MdPT?+@K<>fgbqHQ{NJ~C`&qLGAW%x!PdE>8 zzXGkU6#k$e);GesQ=x^whV`KqM2~9)ooL5;L}oifeNQnJDsdbvNnXM}?RhB4x_vG3^C)%;zk=f2r zUpgMB#6092KWWcHSJqoXzF;0yz67Czk8d8V3xWuR{iJyaE)4c%d3-&=`b=0iOWZ~l zSl?<<^tgu5iFT}~WVSQZm*#=WQ^cSp`3d{9=b<9&79n3S4=P`RP{7qU57vc20*C#i zc?d2L>N9TYihfxC3F~r++sIM^uURxt2taYX_ZZ$NEoZJ41bm zKb1HyEj#m>_B<@e`cudk%!A68Aaw9i^RRQ@?A*+b*@N_P(?REBi*a6i=E3e)z_(q_ z?cKL$CcNPiU>JA2ewD1BCA%XFtOr&QeXb#NqaEu@ne7bqJ;hY0gsy34+_dLqB2m)>{LQs1oaw=sWY7_B=GV@bw${ zf_YH+5`+#uo_R2z8?8GW;#@a^e$L@A?uT{5u$~+EMU_~0ts;6{JLp8aTIVZ6ed#`m zN}3P)S&;nXE%V-!`9YmZ@X&3Wsl!iR*3&}1U>;Py1nyxUF%RzHFphJ=b%N$$Tfyl$ z9_O3;Py1fh@l zgzvu`IP>7H1G9VV56WTZ;SYQ32?gx2&KcI91FxtO>%>(ge%B7V(2jM<%yx$Qo@^>q z(sOJ2sXObtrOkaL>!cw+z+L4>5EuBE{I8zB&wRLj)-Lmn1K|($E8b(f!nW|74?C=r zhV|=0PyQO#nd?Zrt`&5kU9D@Dp}w^4H)rt)L)dxv2lnneV6ew}b65v37<9saKQ_$hz2ug}@0vmv+SU4S8R|=UPbKoc8_rA6 zC2j8WvJM;a1Kd@91aW{5@;>;`f8AS;(cH)O&J#2E#rkzvR}j3SO055vllWab=t4Wz zn={)P>PzQ&D#5+vtlO71_ugGN-;p2SuJR)Y9elvuoVSDgb>I1dT~xl4y?NKmtPE!V zpdZ%7!+M3b)%q>0E7%krt_Ad=U9Dr6p}ur|rIPOB>8In&W7_=ZWxY7$3HYl#3E~1D z@E_-~GXb!3`CIm$2|z!rw}*8QgTW{KhxH0`qQfiWp2g>kOvN zf9+Jxf8+`Ht2_xJ10V3$FV9KnmYvIA+ZVQ(Kje@f_{I8tSXUAIqe`rQxFqqrcF=`( zwccKa`cmFgd3Q1BIP;e__o}S-hx`C{l^;Q5-~;aCJa%5PgPqIWwlC02(d!X4W)BHTr!ztS5-|BEdJR#JY|h(d*iQ1KQR4e;Mja_eE6B zi$U9&@3iNsF6-QWLx5Q?VtN)p1p3g9 z^%Tu^hWc(X6)H~=gRV1=Y4cx@bqkRv;IHx|hzxwdKe*5FobX}i^0(~G%W@)jT%aG; zeZ+d4V}pna*3B%44%ZC&(2jK)&317rp+Bm`I-D(u-?f7-v}4^zvz?*71yiANix_mB`AeI7P1aXL zet^5mk03JeS;yTu@xv~XdvM}EbzS14AJ(VDx}kz4vcUSDd1swSbbvl=tMw!^)VE-E zPyc_3Umfd) zwnT?(1AS;$>r!T@FP(3w#OKZ{&OD~ge?iv8M4o`Z%99{;@Bx4Or8cND2enjP{1|Fe4Qh>pbvdzqYOr&{e^}>qIpk|uLnj*5I+_{kOY=Y_ z=ArA%XWGX@eU|4P`GR?va`b?&I}db!qu=s@UDQ0Vz4MZlVSs*E?-T2=f?HIH^-_zX z!?lCHal5R~X|^-em-thO`=H8>zw&V)@gPsYU*$;<`k0Tr-+=Q=z%#*d!1nIjRUv<@ zBZ~E1$J`<+Sci2v|5axm)6V~e3de&y0sko{?kN7|^BkT2 z<2;Va|G-}1hhMBqiuGbGh@K6s>spZbT@&a+`!KZ2P~U>tK_&60pGr6{!FJl*`@5Js z@&nveegtuVk9*!BjwQV(!Qfa98;e#Nl$sOKHJQ^&jlqe22aD5}WA+T6Rc&MNW)+*N)Aae$A>_x;uL*S*Fz=BIeW zuCPrV5b%R_SFs*$Fvx`eux{<5#Os%g%hI&ABwk^NM@` zXO#~@=-?xq&FRGZ8e0_avAy#e+t?oKxMF=>@QNz24(@P|otLnOE^K4nRkNL;zLeio zo-77=$4}bamu1~oebuRT{7s5}J*j-RyoxAt+|$P@5ac@jhht|9;64FyC! z=C_`EU{|2Ea`g}VVZBPz`fC9QixKZ}xoyp{gn zLF5iFZ{!7dtGoz80UzN_zwX$;C1BV&+{gCjeL+aG{9^rEtV?Vec{Z?q@aleloQ`2p@KKZ4M~)5&w^t*J@pnP8gMy|xCwSWg%09D`R> ziS>xf62EH)U1-Ppw`My-eNQ$ODz}Kig5)3U)8?L)b!L$t;I8r`2nBrHe0RaaE-K&G zffu3Zhjn_felj>jmPhjQ+3vaiyoWyY$GW;^J40(E)ALy>@wq_Xna8yGH|9BRON{lHgFz?!ml5tIiQhGaF0^OQAJ0#Q`cmFg ziPaiwl83NQoBK%OL4JU{%8wuv@O1Oud0lPH(cwNm&jQdi2e_;J2qFU?;qJbs7RB3oO-;Rk zX6`NL&K|#wrq_5wBR#j>d5-nBToef6n9uO{#}q@JLeO8(cOTF^&5K^w3LMa0d|)_F z)R+D~i%R@8U&R?W?Rm;Sh~q&%VV+bz1)+nF%#->3$@`kxn4@!iXnXyd+Sq>eI?R17 zf+P5$r0-H7?rR}W>Q-}OM;yCF~P3QFigV@q_J z?F{uL?o<}UVBn0KHut56Fn8n!xU2jKA_E_XyYrU9hTJ3GQV9E%<@=9IAtxc@FX%fY zh<{mhxK_}I_S`>&c~5-{W(SqH|ExLVrpuKZjwsXF* z?DdHreix4B^ZZH#NAN?L749n`Pwe7SbfIx6+|E#6y6>lQix~8sant6$_%P;<`~Y{A zA3bIBZ&uj0{$vb0!iQ_{PFq+eQdMQ`v>%V z(6*0$9c_G_$jbLrw;g^iUu+*M^Uw+TVpmW?CmNfN3g?0P7R(MR?;-}P&bVpML*vmL z5Ap@`pz;D|)JN2de9x4lBu5E=N$c?PeONz~!z0uFE3sZaE|3;gBe`^K9gm$6S@ z<#^$}Byqbo(1Z5cbIy~i_u*HCQ7-0-{A|Hdp6`_*|{4h3HPkT@9u{#v=2hN4E3e+4wYw$!L&1O+T43jV(!Qf za98;eLedpeT=gjSx-M4-3x#nx1>{F0s@9|LO&j_cAW{t2_xp2Oo#O{c^Iggk1!G|4YiMU-PBRe=6h@j34#i z&4qtfbhviVhxS2em!ZCNzfa}({>K?NZT`KdF@NL<_^Uh#LI+oufB5n-6mkjssCfwc z*=ug1-^$D6I0$*!12|i^ka=i|9%uIybfUfX^zb;KzFW->DsLwS9cSFM=b`!xISyo8 z%!A68ATscA=3(7Cw6KfdAJ`l6z%f2<`Y)IBf5>NSGlG?4WXs7%V&Erp>+jZ<6maF1V}w2qFU?&D~r_1MKcQwA2CiKK{C& zyYwUaP5&p)!zhBQ;2IaVl6lCAp79Q;KquMS*XY;yFS#Cs zyo8Xy*dp_g7d@^ObfSF}+GVIO9S>CE`BuppH|=>CJcs82`GR>+`4WTPjG7oLh;~GIH+S|_!j|b|z)$E`W=cTSQZrbzE zT;h0;FPI0FFG1+wqvv7WOV7p3+`g<>P+SujP5@MsN*+QvYq0c~}eis=em>KSU=QJK=VQ`qFue z%B^BBbjD449@;P9c|g8k9#p;rk%6mk9^7~1r~~XL&4c@nobEUOI-ZA0$Sa5=>c88_ zJj{z8*A6<-Uiy#lc%Z&C4^(0v7M*d^o`>QKIUeK-=0W945IVT}=7Am(Kp#rjPnrkn z7xjI=jo0%$tVM9eI4Ex`^Ux3ZVpmW?CmOq=+iYj3FUYE4m-8t$2`$_X4@6f5=uET!IZJvkukXH~#)PJ{=c~}rVt{rruz4GGlc%Z&p z%?>JYU%TXtoAx}Enj8=E1@oZtB?ui{^*jXkMG+SW*!$+e>gTNKiGFKu;Cbjra0O44 zMVW_T$QQeU5<1biCc4dbhWgU)7gXYYD(Cn~dmg$k;dwy5U>;Py1fheEcOEFeHIpd~150#g3JjfT! zgUXj6ba3^~gXaPP`-$@qTp;vcErsW$!kc*>h7nxB6XhLb9;QSO+EGF$w)>%7hWgSx zPNJQoPqPn-wOOV;RDc?-|OV#rGf`HMTs zJS>SG*9tn(zW9ppc%Z&?98iht!?H7O+VimRN{$Elf_YH+5`+#udLFEob@2dEgu>o8 z4|cx^FIyX5@Kb*)&&yQEPe$?=canK2h(6Z}y3wBf&v0I-?^d&eO1#82?TnlDyo@9s zp}sT^RAL_b&bVpML-RE} z56BnHgUXj6^hxtzK1Xs7hjCs{Iv#?45$`P(-@)@x3V8vcx15%FsE8id2s+VTd~J9< zP+z)_qH?PkEI8w)JrDWUaXiQu%!A68AhM0-!8sga&x2kwlm;4)^G=?JZUk4sH7-t- zc~}eij`vXoI?>n`-DW#OeQ6%3#5@e0anqiM=IePLkS~}Al`lc)V?OHrF}#!wZB)X} zcO1Z8KdFHI;=7o8CFG;suB&eo?iGpOHGnR(=i6caQ(t<2fXadx)SYqD=AL~6$AkO; zcaB7Am@*MA@3Ur~dB|6P^ zhWgTbdsJfGvw<^i+T54kDEThqg1gF(AaoyhbN-I=-rkt|*xr5EKrn()%=aU|Th99- zC)wjK&Jg}((cxM_AKLS83iF=&7R(MR>2p^4sX61O%|H8Qjt6-H{why`xWGr}z2O<> zy*T&XS9ubI9>qU={|*YdguOcNTk{b1D_FCEe))^!I0$*!12|hHnTLw#aduBZ zC))FG4UYrryVdNV67TITIOC>0581cLaUkPj9#p;rp@WZe9JsHKjn5|$`~!R6b+`Op zIsZp+1V5B_7w+AVCw2uTbfK{+I?Z;5`cnQ=SrCJPGj7`48_Ucc`2p@KKZ3}7+=J%> z&Ua)FYY1SOA^0p1zl**|96=0)VE-EP`O16YRh=chBo$vGSh!sVT6=X}+K5p%cMXaE*(5$~<&KzTUkI+5AojH8{ZGv{p^{*IN1;JJXAtnKPzP%Dset)IOC>057Y1Ec#toc z2bC{D=#%Eb^SZ@2uYK1A%tP?HMfj&Z);LQa<$35ua0O44Gcpf@kS}%xC3K>3Rdk!} z4E3dXpc3w=s4r1JrA{yay-Zv%!A68AoMXG^&D-S*PaUm z>?h8H=K_I#i=XCs$cDUt&|B`5dB}?%*9bb%J__wJ)R(RcRO0uCk~41F^Dy`r&ja!W z^Puu22pxR%@nFAK2Zdb1-Zu|+Kl{Xle(lfjJTyaI_5jXSMdqO`dYs);(24fO$HU`+ z`ffElsKj-;>x`TBJk&qI@gQF?4=P`R(7`8i9-J2|V87u!Z1c~<>SuW#@*yuE^p?A1 z9*UyJHG)pGXS?A%P+yt{DlrcgXWX>sVI=V&Uoa0UUxLuV)i)1xesW(lg8ig<;C}vj z7=DiDp&h{$JW<|X=Ajev#jc=)PBb<@8O{UsrFozd^RVWOoAx|3KE?4MUoa0UUxLuV zHF6#{aXbX`5OF-@S9u$88>Pz!LCFWt?88_{D$bN?7 zLB3!fRK5hEPnrkwIfZ*TjDH`SbUXz8?89N)ulxm`hfV}n@I<*==Aj$%#jc=)PBgYf zx7p56U%FqSa;q5hopIBihvsK_9*{4X2bC{DWE;(cb2yB7ZZr?h;V|yE@I{`7QpigP z`HMX=4;9hlT0tk;^PdZk2kJ}nKqcm3!5KI0dB}dA<3YY)9#p;rq5I|m@6kaUm9X>i zhrK=oVBh=_bMHoQ)MHS6PPlhNo|Xx8p|K%4&31WrH<_xUezJjf4lSNRb{2A%=; zeY0jY&i%6oXTm?2!G4Q(Xy?4e9-e=)Ut`|+kPA?G%kzbIPU3crpa<=1ptq^FU68kOQSW^UF+NtcO*O>EC$V0nZSAT$T zUX*xU1L#2e^jE^XroJ~ZJE+8IaM>9*ZO(6JTouR%bmwy;^cfm(01obDsJ-$Af$TXO#~@=-?A@p4)o>4514p>@42O-aS#ne)${BeI`K(Jha)m`a^{C65@3%#yX_E_Ra7-LVZs(?Nr`Z_OCeO zrp>u}F~@^^0B4mCL1f?)s*81`R*jcFM^gEZVo-F(O`HGfx0pZj1pHN=1d)Mjz@OH; z-*<3(Wp?{n`d*t1VQ2BT?F(nzO~fkuN{_iWLO!99r}j|c-jMiR6X-&F`P*UMQ(yYK zEh_6`u(rw4s%96fV0YnATsa?IM3|Zaqxb7 z=g!$b>wfK>FTeL4RQCGbkQ~Er>$}Xo7V;4y{^F6sy(aOyR?vm^!gs^`roMEaLgm?F zu;h%JHuv23I3DB&xU2jKA_Jd*`|R9~o#xaIO;lpPmEU5g?+Ibo{T_4fMR3!;slFhb zS3`c533Q;bCA!RZhWgTdIFf?2pxO^&U1SY?m95L$9#d( z{&RL8uyP!B7H`L1-yp(%@O|c94*39?w|tavFH8Kc5pk2xKnw5G3Yzvrp~u}-AZ`gul1Spa>yfe=BfRwaBd-9 z$7ZZU+UI{9o>!1muD|Ts>w6P&48K!9 zW$yDKA0gr|o+RAoC4Scmy3k(yS(xwCm$*~;5HV;tvKcRA$7>t~8)8@YP zbLNix0C$xiL1f@5+~Yhi-ev9_VP}1IMGoPw`ZMNT3AqRffAM7DU6#0AE9e=wUmoT; z^`$(g@*FW(aK=rW_fXUWwpl zIX4?m5zfmYKg$F<(75o6kTdnA&#$P&eQeJeH*L=IS8zPY2XLNp^ng#m`K;O5SobMp zSJ-yCeh>ja?VmH}LdXM%yya7cb57!Qji3YVz0fX0ed#`h${k`*cE(Mc^Xiq%8TkOt zDj$N#z$f5LAEMCjIO-D=?6>lHY*#q_ROiV9>{l;m-b*1Dpz@X%2=9i(?HWN3+N)QE zc};z9YIab0Z!uVQ#!Z`d`D%^_c>&%kFM`OxC*Zwf@7w{t=$YT;p^Qt|S==pq^QEKP z?l$fO`{6H``zV6rxPw%lCfr9MPs;?l(6}l(&31meT?^Ogh-Y`}8#&5Ap-tRel7Kfse&~&;FebcF%QFaVPtT-}5V1G50|PNAN@W zOyNEVd16;kLKhl4qSI_=s4uOPNF_c`$vJ+~=HC7lb4PxFyULFsbc;KmWA@MPMz;9w zQw;CW&Q5X?A9yv-7q4dCwUCSK@fXh)-t!W-YXv=M&tDtnIrXLcLMnHNLBkn0ZQj{m zb3Dik@K$*dL;!VmN_FIz**%(5Eu9aocX-4 zBiJGTVZX&$>=lopz4Rh{Aa8s^>>WhT)YRJzrfeth_MVHymP+#IqB{+|qant79 z_!DzRK7g~zhahxt1n0fGckI%jvESv)cKXc0Bw)YvTjpI3xv)XR|1TEaC5hWLgPw8w zpToSSzQmbIy3eDZnlofJ*l;`xV11_h! z^eaA)xzvBcoGK5pIbC$c?tl~YZ4{5Yzvbx2Uza%{K5c)DVRYSuoZ3gSKkdg?UlKd$ zL0r(4Il}zS+w}B0PA%!z7A~!yGNFhTWz4Bm<8AsoaQb=J;+xu3LLb$W{0tl& z3r902#HW4Tz%V*GA*Z2m*M5BUp4dST;({*XbgKCyGndmq`n7}$e6Ku&Ini@8`uWBC z_&Ni9+#3J?oNz&pW|lc2KD1MLoMA-Q&g<#Mh&ryDdGQxv7B-6=^dK(iiaI~#q+jkI zmuE(4ZpZ0S@Vw8|mS^Q}~zIsvYpa*e57jZh>bKI4r z-;!{F@8yTtoL=z+<^+APi(A$l9sTPwC&Z`yBP`39^D z@#((D8%A`^OTuYYxNASYdRy$E2XR4H#@wKrzucm4j5s*Aci$eoS?8YDJK`t1z?`~Q zGPmNRY;G3_H|X`nG^uUi=&B#b+z_wsdxBv`*T5v)MluiDkFVYnJLo}N(3LqRxRq=aiX2d6Adf67AE0U5P#Z_ zubve<=s{f2MaLt(TH@waUixJp!(0kO$*X^~IekPpL7y*%No{3EM>ofu5TEXQl3^5F z3w2{e9rp_r@fTq>Zk`r9=s{f26~(D6{Tjjr4%`34oN!=$tIvxa^dK(iB2M(SjGIpj(r+YO;5+}%HmAP`C+LG++_LHD z$eqBP5TEvQ6T^tEg-JNIj%R<`kFVYkJLo}N&=r+WP3cz`F0Ehjao4OfryI&(gJ-^S z3ss@d7sI5s6-P(uMAn7)bl<#TMAyP3oVvnY`|;J6#SVH97jzLPb6d48pH`$_U$~5Y zKaM%!zUuO;KAEL`&^NY=S?N1EY9}!##HZcd)G(rJUlL9O;jaDYdj7l{1ow+;Vh25l z3%ZDt`L%Byr@r*72^aWo{3~<9^TbEq4`#b+!5^n>y?(2@H{LjI&({5t^_#!5%^UtY@3iBt%jY}T zUpdy^kM=_?=YPMsc{$W^54C@-@8@`^ey84N`)zHvw>R=%J~dfBz+dtG_Bi>=kByc0 zr3>wT@P~5ktDB1l{WmIyS0~G#;>XgBXX*MIgVlleyR>3nE&aa4bstl!{$$@oXb zd$`+Ie-)m!_I>(Z?!$KSkm@;p~%eX@=8EL^d<<74#OWc}9e zW9Lz6m%Y6%&R^T-pT#@!_QE#1eO-0e=|&FD=*P?>Lw59ZyH$x0{>a`Yk4NE+5Os>B0@{<8}U7llv9FIXNHO zpNyxg{({NlxYJj;xgDpwKke=5&-l-GD`(hxOJA|KTNn9xwJuMlKP`QO_u27Ajng~J z&%b#4&FSb|mw8s6Z};!W_sP0(6fUT}llQ|eZn=D8_P4r^bq@D)nLmfi^0{2b_18Z= znf*q7M;H6g3%xzUZ7-LL`?y@af!}_kaSnC=%9{?a?n8~o?caG%GA_;2;^kTP0y}@* zahLyHxD5Sv?N@SpPu`mw{vjF1?r)Oma^w4JZ?Alx^)>Ed$Gv=4-X8tb)<3$pJrC1Q z^K*1{tensN%0J=z@%EMW`Q5euzq;N10_z%lF`mBVMm&ChEgsDW*zuH4v$qjPXNu>u zbh*91{29)dh4bt@LBGa9JD=)5x3^(;*vqV)--qgd`X07!_*;4`>sdX(`wQRR5m^e{@Ue=tbcg8#x2ez<8ipgJybv0UrzqKqJPpR^J#;?s@L@&uN!nr zZFlG8{`p(JKkHvR%g>?pM?b%X^X+_J{URGroHy08xvX3oFON1Fcl7Ca_e)WJ)_&sW3j5YY{y4iQPwt2QDD$sRW?z}%d9D0D z*?9!xp{$hs6jciKAs*8Z1!%rW;e|M3tvzWx{e9EXd^ z@+z5C|;V%)Wx@bR?t%XBzl9F+N|@HmUd z*t!-A_BQO3mP=dX>F6%m+zWB$CXtw>&8usL46 zqx^o|_;Wws9GAgMHka4KyV&!Tf7RsiOCRKM`ls9dTpe+@>wk!MAF%Q|JFe_oc^)e7 z=CXMl$Fp+7!xL9j{Hu4i=Rco|H?L9tlD0Qbw>c#3-&wQsq%dRqYdpl>j`H6)>CiZL zUL0?nsPWO>`;|Q(75V#f?Eh<(?Q8vdM!P5HN8=g(erd&B88ENno$R>QK4s^HJAPUI zUS+}gdkohO+x7d|{?Xp}1CP^sk3DbLAGd6N@6h^}ubHejZXAVM{dMOrZd@DLExuxM z+~tnFzw;;md}5rHtKyx<*WPOTMgNV;(Z6xO!n5P`AG|1De$-AmwDXu7cVkPu_}qR` z+qnb^Y;`?m0Ps+;QtKV%^NDKiKgt*LZvJD7)R&iS6ba*{=F{F4x|{WxE(L{+@V#;XkS@Ie(8I zWw-h%j-$OL**p$kduVZXPu|?|St)O>UzGmC-9G(s`?%i7fA^xzaa@sgDWm-NzHY}c zUE16@QU2Zb;=kJdNAI%7ckM^tJ-p|$h2tmZZ_QbE!Hwr|Z?8N#;`mNDQ00EMpQe0o zVw9WChuOX`Hu3J{-S@Kp#V6SF?Z(sDZO4uM{U6x_;KzqIA21%u z={Isb{RjHvf}L9~-jO-w<@;HycMxuO^z(81M{PH*Jv@5L^8KYz<7~FQ@eZ5Q{3j+K z&r##FZfWOPce_3RQT^h!cW-FN>Gm7s{QC>XaC`6OljpH}nZLg~4z>#;ey_gu$iu4> z{ueHG;`u0#Q~My7YxhbvZa-(w55`Gaj`IF-*Pg@e^%?*E#+w~INe7N;pSul@)3}E} zj+kyD%{o(lzoU2h+an!quw&(hhvu*F{ljzK*&xi=yXSw!@r?SD^I)-hc=9xMU>g`_ zpSj6-D2k3RaR1`m-&WV?dXu?tfMLA5FY9-Y8~#R>#=Q=Yo{hrKy`HZd?Ul*bk0?Kd z|K41jqf<9GUQ`^p4{R?QH;i$;I8?bbfO$@51_AXa;J zd>CeUjz2$gSK09wZ@;{YxLRc{OkD zw}W4|T#4O~4@Gg_>04FJI`G|?sn;FJMQ5rwqDmB+tWAY zacVd7kC*=}x3_+3?=OFjw--Kdx5IDTvY+F)v&VBeeS)pS^)qn37r@;=|E5EW$Mv_- zc79}!H~%gByx#hCym{DYoYHqDbJ?hW-2I)df1LhDn!Zs1WJhXW0+b460ilg}Pc>OA! zboEbv(VzFdH%~tQLf7&q(~S?~{9h>t&zn52^+))5A8vh}DLam(PQ3X%+;O=6mcL@_ z&uz2gbnQ3VZoPPN{w6i?%3|2y&o zaklQaIla?;o}Ws@diMP{+w-^jYnwC1pa03^`GMWI%=`U}_aCOp;>eC4ZgcPF_W5Nl zSFf5J|LAR-i#I3V7dCy6`?sIyj|Xx6t;^=TKfdgM%c5TH!|I@$ow{LQoaktV- z;&B{z`2VGH#AMz5emcDW*7z1)81H!4D9+rM|NrE(k?zB_zqE7m^;xBdMR& z-%mbn>d%>co*X=Ca(_3TQOnNP!hM;`C_kA`<>tx8amOwE&cCjB@3xc2b^W;8wTd0r ze9g~m?OumAjyvvVw>$T@B1_T~xxxR!R=$K_y$ zpPL&`Zc9A7+R$$|+;5ND{b<-ul-ZJ`GNgL<=R6IufL7PbN82a^7!?cc=M0`?PLAN8}|Qi zFRRxaT3!`?X3typ%ZKJ~@m03J&GPHN{?OvUxYgJAkMrD_hZbkIZ=dfl9?G>p@wnN) zOO}u5f2igB-8VVz#|{toUdBKE(uZvSD_^j;UERy~^v~0D$?qTim;dOWckDmhW&K3f z(LRaGwHw>I3ODoXh>D|g|H=BI`Xz18{m?%D)xTlKx$t||(fk9KD}Us&|0i1?#?9Y` z{Z(&k`^EmGW#QfF&SUlMejRb+EZv%Ub^qi)ALNer`)?d&w+}yT^IH0`z3s-6pSI_z z{X2WxwRg8`^85nd8;tM&#rFr(_Yt3JI+?=ysY}0seE%?ZW}m>{M|>k`c){t z3w$@8$eeB}4S&4TC10m1^uaD}*>!Z3<$Y(wr~TZ*Frx34Pr_++gXf^|-w`|LL0r&9 zoP6Ia-<5s?;R1izMdp-~hONsl`vz5^4|Z|OfumzV)&)d-+RrTwBl<4zB%FrMd*<4o zuJ^Tl-TNz%|N-Rz}Qg+AEDEpx&J_RW{_`4{n_ zoywC9Bl<4zB%Jc%Py6xK#SVH97j$KgFz2V~>2=3lPWttQOKY#3N1w`^PL#o3`No?D zoS@Ge!-U3?qhm$Z8Ag1%>#YnUI!7hpRNi3S;(C>J6~zvE5Epb2r_(%~O46?;T*@C| ze~k;6)6GP{pKo&E*;Iu-tt(Ew=IH3Zobw6sX&(i{h|W<-I4y`j?MK&JXS1%V*g+5C zg03h|HR(4HE(7tGeY%}bNA2e04*GNqaq3Hsj;#E>0^-v?wirfqj!MF*`HIQ+QQdva zX;JK;2XR3cou5vdUVnaCl72Pef_{x>*yktsg+8q-PQByknEp@Jh4{3OTN_4nj!MF5 zCF1Wy;I}5@x5W;65EpdO_3m`j$-OV=NWY$NS&_f<7&VwvUIu#0wl@T)bm+tQam${g zW4^_l5TEvQieW_Os3e^F!d?5(_1rm}Ppe`FJ%|gs=(wA{%Ngr9^`u|znal;g8~?`J zxPQ9r_}kx*_CX))Vwb`N_Kp8yPKXcfRBknl=p2=VQ&#+GKfd}<;((qh*@iCWblN&j zQ{sOhT(X~J?%8MC`Ly$+?+;QD`g}1=YAZTAmS4r35TEXQ8^egsQAs#Wi$Cp0*K6mo zuDsYm58{HZ;QVBMadD5kqV%f^m+4QjzvjO)CtUB&f6oa|rg5Q9#}KDpb#$z~nmHjp z?c=tF5uKxwaGDo?+K;X;&9knu*g+5Cf-X8gnbY_>PF3kQ5-#wae=c)6K^h*L|MF9* z3VpDPTP`{}reDjP5TEvQJHv?1QAs$hM11b2{Zf5F?4Sp6L09ICsj2g3XQ~JHS7+wt zX7^1US-8Ob3z~M%?6({CpHrRPcW{4Y?}44?%<)KW9xlpwZQ;508J@51l6|~Bf9>^r z{ueH8+#7B89R2gJW4_R(`xgycI=3a^+utCr;@`8bRk4E}#D)2$PP#X9fkpo^}P+dRMT6s2G3KbT8pmHo}XkhgLEzxL()`wsN!7~<5cj*hiAFek*P zecaJ7qH|jkPV?eV`_c9GgIQNu?4Sp6L08m$d{z2&g$sQ5U&Nen-}R-=?SlI*=!0F{ za?#N-dLwf}eA>^Q3?n*6CE?T%f7*|)z94qcgSeoJIBoNspBANG<;Bbez89J{r*m(~ zoS+YOam%)&qwr?tg!r_dI~zuHj!MF5`AzIk`|;JAVh25l3%UYM<`*9Kde@eIYr+M- zhcB@?J>g%N6ZF9@Zn^5{sJw-BAwKQrE`|}Eqmpo16YkoNu6J(3pTDn&9rPeB=%VwJ z?{lkF={NsUJD(O`#@jcS!JhN96NCFx=+iO8sSh0;^|vx7#HW4S)i9!SR1!`j;jaDY zdim*me(H-I^dK(iin>1?O258v$$gdmO}&CS;XHo&jkokcg#06bZ zoJP{G_*&-Del+K2<#oJ`=Ui95nV)k(pN=6;z2N9*U&x#gpZ0NvVMOPsB%F%kPy5mJ z#mBI&oY+AR;({*XgkVeth+k*g+5Cg0A2`-Sd38BK`7h<^tcPH}H1wVU%gCUwHg$X&>~#E^b+O zbPPMp3Grz^CBukvDha1W@u&Ux>NT;09>fJ*#L4%$R9*VDgiHRhoS!Riw2!;T=9v@p z`C^#V)^c>@FJexJPxrmMVMIBVgi~AA|IvPQeJHw?#14887jy-mx7=<0bNH6@%fE@a z;CXB5&Ag5KbUcrRJ{?1xde_lWelK%EeA>r73?s^^B%D@-yY{2&C3$Y!5j*HXT+kK8 zsVn{3!eyb(`P6-joligfBJHF6fFnj}N3@{;kXf{Yr1+ZJeLr7y5Jzaq2nY0^8>MnG@neJC*k`j3}p)aLS86 z?MK(U;3#&`gSen8ic?PdHH8bFw|179lly!b`g9C&>Lo|V$_JPe;?q9vZ5UBbCE-*S zf7*|(cjWnSQS9)18F4{Z6sMB(%l|iX!SmMA+j$%J<9HqmeL99X^_ruj|3T)2__UAv z7)F#+NjNQtKkY}?d-5E)Dt6F=xS%VFQ%(A{g$tgycHd#=6Q0LHpN=6;eaX?0{Sb3P zeA>r-4I|2_B%GQn>`(i#>hj!nQS6`xaY0uUrzPoEd?$0k^VZ6{cpKL{JdcGwD~1>w z9Y@FXhglcm(=N(}5#>}8PAkG)`_c8HJhyF&9rPeB=!)Xhk$xTF0^e&FGABG=zQf*A zA4>b64|Z|Oo};7o5$1&Ww4WKnh;k|kr-5+Seth*+v4bAO1znk}JYSxfpQZlp=XO2m zKmBgzgXgE!4sYXpj_0e;>5FAjTUPkMX6d8M3vr^I%KI5slv_!7<;0)%qw5`c-aC>w zpa*e5S5#hQ#s7+M!SmDJdu&d4z6yOhhB)`vO5#uZ(e<7@ z7cPh$^dK(iisCda{mK_H7d$_$z1QZ1=c~}CV~A6qcXaeV&YTdR_OZh-qMS;?sV4rk zAFD3UVJl(>J%|gsqBzYkpeu?~L;6+U&s^~QwEh9!#(fl?uTF_R9YdV@vZJH;N!Eq< zw2w0lBg&~HoH`rCRh8$kEwO{1aa__K#c5gg_k_#%`RNC3PI$fweOgzX`kJGo`YD-z zr=5K5G>j;xl5pw?_o!GF)n+W3&o3C~x@`l14gXdgK` z7C+6L5TEW=F^njul5m<5f7*|(x8*tPK;{Q}5EpbsaT-a#fpEd|)9go>ll#0F`g9C& z>IFwf`!mc5@o68s3?s^^B%F%kPy5mJRe9c<6FWRFMqJPp#i=0u>cR!jPn#cQPB@R_ z`6~437~<3`j*ivOGAG2RecazLqMS;?sVe@oA6*~H^Xih=K@Z}Bt|(3w={FKCcwUkpeu^gK>FoB&0O%DwDcL96P}|&pN=6;JttgX+x!x9LVReaa<5@TIhBM{Ui@i4 zy1s_z^ao?W1ZK zQBEb{R2F~QkFJ;hgLM_f4tfw5bVYG0Nx%H(m9rTN5tWIs7tnI$9cT{P7zcMOEm7UF=f0z`pT6%n9+Koyv0zqX#AA zlofy4kFKvhlh;8RN*vHLCEL&yb$*&cykB81@Lm0?oloyP{+55Deb5KHxMk7NvHT6@ zg!r_da}A>hC*(9O{ikrcel6hw-z#5ZPIwP$@!8Ltp?%N?ySQc5 z(XsYT=7jjPAG+2ZOvq_o{AoYFdRgqC2XR4H)cL6@{c>w|K23j}w}Y26&43So?A+sN zT&?GJtQHg%%gbRE(E@n=6F8s9u2+`t^j%^ox%U-XkA<%RWCn{%NnjfX0PBUksDl z^1=l+t?x1?#D{h&A7~goA|a=O_|txT^{m)I58{HZsQZGv^ecaxxxja=$J@Bx-Skz@ z4gP)u`d}BgEIT^7-(yaQPy3;Jr$;8_R1tsLkFP#0cF=>kpeyRWpe+4XgbRH4zQdew zKYmR9fj^^t&cUH*L*cNr9+=DhDmKrM@R05%n9-7zI5;OsDzwaKVW~_kFVYkJLo}N&=qxG z(3E~H;R4?)-?us4>zxm{0qui6*u^bZ937<}u`a}?{m{MBqZ4xK3U}>C*XN(k*Slr0 zgC4{MT~YT1E7C9b13RClf5_YTT;-MXum3TP3w=6J_nr9>fJ*QP;b9>DLu5@ZG-8PE(=} zc5%yPM@R88)`j@AAG#NRQbJChm~pkl4tmCMNqf}wZdvwsgbU(byNo&EdY8ZS5pSb? z&XiX+yU!8E z`Zfy4**|i0EDo3x;?w4IFaG3&oTkK|_M_`d^7;Hg<_FIa5Epb2C*SYEBk9)?F7r3y z?@e0yIdj72bYDN|+fSi!p-;yUr(SS$w13W=5TEuz_u@}U$f+p)v>#tRCw9<-xS%Uo zS7cjh-RA`b_`jUFz<1#nyp8*(S6=j@;Ccsru!~z(FphLsy_`8AKJAC@#h;pxQ&s$F zKfZcN?4Sp6L09m1c&D#lZ?Yo&7K96YFI~Z$%rYCnPxsWX1;5`xAME0mbw|hW7t9Iq zX+Lx?enCP`i{elF@zrZ$2R(=jx`@;1r*2!9Pj%_n6E5&Qx{^8JJpRPO8}3N^pbvI& z%a)^~a3ym>eA>@H8b(h`$Z7cs_NV>$>Pun=J%|gsGG^RUr?=6g&fv%Wysjnvt5?~_ zU;S#E*Lgob`)YCko$M|C|ErFk%2linacWQhWMXb4V2_; z9>fJ*QNO%wF7Dp>d(l7sI5syl{a{Ysj1sAKIz>XT#{(2{{$S zpZ4RcXT=VB5EpbsW_TEQ6n8t-ZUksDl%8riiFPRhK(|zlP z(Q^}Ws)#@B$5)>gJLo}N&=tk0EdBD=+WA!aHE#zW(wPDObm|K)rg5Rq7sI5s1xLr= z8s>!fbl-n5jFu8|s*6AE$5)>hJLo}N&=qyuEl9tHaDngkZ$>J71j9>fJ*#OXBC(Y@X^rQblfz;||Jb7~&< z$p_Lt=!0F{a>db6`Zeo9eA*9vR`>jboVvnY`|;J6#SVH97jzLPx;bz;tw_JBaDngo z?`%&0{K_u`uOdPp?BbSvM@Q{9%n9*nKlEAM3lnl02zTvA*IVD^`+_yGgC4{MT~X(! zzVurWF7Vy^y?uVV@U6@V`d}Bg%nBFSFa4G|AwININuSldC?Thu_|txT^^wE@J%|gs zqRvlQ@n84@bAj*jA9)+UzwEosEpAQwpbvI&%V|ePXT+QkpY}ta)x9_&r;_;7eth+U z*g+5Cg086JZd&>^g$sOl{$z8y?vAIKzs#PRf#HanxXLZeloND4v z`|;H)Vh25l3%ZDt@BPDh`2Vw=PldnmHm-LM$-N~wKS7@_hDmJ=j02-TFek)^W-95k zx|by6wDf!Sr~UZqb+LmU#06bZpKCUxUwP`J;5`iZu4Q-|_fKnAEb%Mlq7Qa)%VkGL z@sF$v@o7KwS=~z$a_Yp4t0i{OGmcBzqdwPMmi-;!f_T@i!<=wGe$CSdm(xDzgI(Nm z&CyZ)lgz)!@&y`wtS>qg@1BvPWAV?-3GwMp^jY1@6LOjof7*|)K9Ko=9>fJ*QJ-s$q~DTo zf$!z(GABOR%kYw$5c#~a$o`c~BesI3V zbrk!fN?h-{&h-WM(1C4re$7zd8=DAs@h5*oJ!@4dsTs+I@n{6*kZ>Xb=24+Sg=kU%Y4s1`~5y^ z-E&U(?EI1E`Td?}=XqeSv)B8z&sy)hxjDJ_+)xyI{-u`v@K`-h=Ni`RXEUx3L1paw zU2pr{@fZ6%%Y8w=)xHQTqd)L_R>fR)WJl&>eh0eD$l&d`=!-gjU*q@lNYG8d@4Jnt zH!fozoUg+7zu-96u;xuYGjdfGSJSg4#md0P0(+Spt$Qb*qt`phL)i*ywur-6lR}N!Sl38_{2IoNHL)w;6dIuq<}o-uAnG zkoBAUf_|%g5tdGW_ooSWK4-)aYd|-DH^b+A)Ek$v56&+ZU9Mq`&t|00C9(7N zw$H6=TA#Te=(E}nVd?b8_&j0ejEWf(CuVJF=C#k%Wz#=6!&-cx-^Y*sSg$1@A?g#p;_Cr`Y{ZT$=ZB*t{d>*MU{HW_3 zV0~WJjc@de<8AP{L;PbZ9N7mao6uKqoNHL)vl;1ger%oI_PJqg>ofNQeOCJ+ES>%s zpJ$DqF|#adH>W>uSY0Od`(Xa6*5^v`gBGQZx5MXh)EgJE56>PRZw)rt6860yYY>Fal8XQFBJcn3P<+A$(nV= zXTutw%}Ad+V(0B`pR3lh^>9DXXSE-~(&_VrX|pC}{}1%GGv@icp>_I_gSx7G>vN&_ zL5otyd*E{c>Wz!o2j|;Gmupz#uNnD%S$XWdz3p?``qpRe2l}k`Ls&ZfvHr~}pD}yV zoat;T7@5!Z89H^%L0$bo>vMznp;k+V_rm8o)Eif@56+itAp6;{#$PjelBf z@q-qnj`zdo3e+1Hu@BDYZzTKKu*P3AazEF_&fD8Q=WJ~2;eMdcYCnXf)1PoZPnuaa zy>vp^R5lfi%xC#box0?pE@!ayxvd-D)Y4)20DNu{|FR|MgOjy#oNHL)vl;1gXY9Pa z?Q``I>ofNQeOCJ+ES>&@KF^#neoEPFZF9QM(CI4yJZzpU~&}NCb|4V3zowv9BE+1y=;l7~X zYF~sM(Vyt~V_tc1OM^7aeB${d)WzNe3ozZf_!5_9 z9X|}eYfyJqGB{vAoG&hv{cTv|w;AboW9+=W?RVj(wjS;a`mOdwSUUX?zo$)}$u~;_ z1@lS2jV?1nzt?CMq`qw(>vv~2{)H!3e?0=fJH$to4em=uKb&lq<6OfUzs+dgcQjvl zv2}Xe@5arn-`p4UTkVUmF8U*WS4^(pn;C(E`J~@Qml+Xzxg^prTi5zsDZYf~>+Y{d z;dceCvjc*Zv;4%2zBK~Dd&<7{$p?*MTKFjAwml>g6s?J)kWCQDWk@ynkyZh^L_+5y) z<2v@k`7Y7r8g`=~Va6d4RK(8P+kSU$g@0!_Fa1{gBCL#lhWk45abD@{+3d`Y)TR4w z^qCRz)1*BARBvc~ZxVm97mgi00pFWge=HyMh54$j<@v<0#&Si~}e3sv#F8hsK>KZcE=K}E~d%@UID}2sFy|Hu-``~=L=yDCa zW{@zWd0sJJ#j*4Dw$E)Ntk2vJ^jYnPurB(epSR~tm@GGlgeuvuS$^aB+vqdqmqV*B zuG_Ma^}SB~QL1G4Bz&(!{c#2R;(W*fu$zE_DqS-SYaQ}DeC^~dw~Ax2f7i#(+uObujIs4_f6#ZeKf==K zkKNyMX3vPZ&V2U%rYet!^tM}7aZpr)?5#o zk=Nf{vGew}-wk7}-`p4UTkVUmboyico;9m<&eYlCOQ%oQ*M>$&UAFI9pMGC!n$t z@|4M0Kk+c1x{Ul@KKej?*Jjr59Px#c)bV-v z-PMhr{SaiaBlmSCwoY&R-Mo|aoBM)(t9=ocPJcqbX9pjL+?5^Kk@+mY zLtXGWJ|(3tvxW7!M*L8!WcUJnu0p+W1^eK9;m)$J4QsBq&B&iC8)E0}ZJ!HDY(3l$ z^jYnPuypzp`aHFCR@uyPGp4F%5azRdj&zxk**{In_tEk#t>5k4_($J3z6ie;i;ql& zBm3cGGx`gTa}8^rKg<|i|HaPR+kQ8eTEDq3=(pMzVd?ZU^m|s>^w~4#26vRq8#ia_ z)G}pz`t?X$pBb6`L#8n!JWKHV7Pqqgmy1uxqz^B_{|fXGSFu0NXU55XH*6+Im@)jN zPC;A~J8y6MpFiH#!+k>k)jkPJr$5&J@aN2_Ws}T(QDHjzi@L0RZ-35&K9lvyZ0Z}g zw!XJ@<70FJ1TVw)Ht{n{!oE1!h(3ekT*I2{Z!_}xds*zfz3qGb1nWEZ2YpxjBP^Z% zDBsJ=N+%?Yr!K{J>N6wN51rJv7Fpj*#2;FgI=%wmOHhAY#J)J6S0?-2up0ykGiD&D zj-9u+eeXg&+#mE^?T@fB`V;ydUXPSb<7ZZkfcY%HsmqLtznvNBJ4aZ*Te|TNwnW3L z@Oz>780AdBemGe-QT#Tnxo$BduUpz<=k0C3YbM!xxG(6p+81Hz^fSxvd8N~)#Xjgn zU8?V)J~K-H;7NV{DC>Kn_(RK5$Hnly5cS7J?2GfAqRTa`d44e?pI<6s=k0CZ+sm!* z+#mE^?T@f@`eUD8DuP#3)Gs3l6wGJ&Js5`me&>lV(VA(&>+m}Vb;mXAhx6^C%QdWd9x)?dpDm1?x3~Rnn_~UuzM$V~ zUxcM+`7PIf_D(@I7mUA6d!Zfc*`cIjfv)rTZR!{|t4RQTm6` zfZ}=!$6CL;y74bM0fIN-_cHM@OTvCQxe)yY$GL_z``wJ(?**}SdfV@&>DF)V3;M10 zMOZrh3H_cubMmA~4$tGzWk$(Qqg@A3R0t7iR+n^I1NJI{hgf(N*kVeQpvz;?`vye*m8w zP;XW;IA9-~ub3sz8-_Lhn$hfQ^VJ$VZ*TitGTYX}{Xn19ehBNLkM{W>_yBe|D}OPc z<+J$!w*F9XAg8W&N9%K*_#um>L?6QEu5R?~gJ=u-GN&}G@!5>@xiGd)Z~NRl$NJ3u zK%doq2ur6wq0f_pmkIxmpC3i1KBQxs4p$3)C(BOO=NjY()a4vd3)RU zF4V*QLEqK>2ur6w;r^akR#8?uyS!|wJZm$bwZBD|_`nYJ1>>yWE#3G>-#C5(zZZ&+ zOob!+;biR|;Whx(H7*6%{`g;u4GpTh49>W+)p59d2YmupzFzs<<~T^>7cZ~NW8m-UKCnZ5Lz(qEPkfHR_Fv*azo}s$^dq*4(#dM&7s97&~uo`<&U=*2DckpVfW{OQ%2dIegw` zQ^Cl5+~-i2{J2h}@0eu$?&!upb&4?j5`MRfk69A-!^tM}7aZpr*1R5KM&1XJ6I-XZ z{chOL`ptboztz47OQ)Za-{WUYoiUSLEywRrm;D(XLvg*l$=2@*@kJI*i8|qTIqHr} z*bnFP_m}-`So6B78F^h&6FYBj`<-)ut%v)9eye>EmQH^{zxi9Z*;FtxpS8cK%l@cN z)_O&|Sif7l@lTy148MZkE#hOg1pRQbQI2yBYxcJpxxYJN=k0C3>kqVkb6?PJwJ*Zb z>1UST^CnKNG#|pLD4QPKXvG$@^r`-5b6FqZ;dv^j*vFwr{K{HCey{|OLkaqc=h-Lc zGk=wRZ&-6(XvRVas$%Eu?Z+YiAk>5N@^Mi6C9I78Bp-+9%`~={rSJZ6h`6ke`0zY+ zQ|;r>(v7cKCkqai;&Esbf3qY}pO~#@-@!jw!qAW9RMd$Dy{`J`UV3d>qt% z2`i^R_W6GNj5%5FHgxm+6a1pPIl<>Kir+J$7xkUU>s$}>zd@e%0aRvL}e3$5Q z4Qs9!&B*J;s@QpZ+vm=MtvyyGLaS28 zZ{T+m>W+)p59ezRk>?k~n(wP-J=_=cTkVUmbov?kJ+o}$%(7YK z^MYR`UB<>RQkUhs)@R?g9DP6Tnqhq}5PxDTXCHnC-wRNGb~Y!6eQ~~1bh(DzAV`=o z13^jbyuIyv`(f61?hpE|_D5J5{S5wNfO)&mm^pQV`R&Hj%3|;Oq&%<0^x2=H5`AV@ z>wAOv14q(_U*LNK>W{0~7w4-Em;G*7b6sP`Jt1g`owv7ruQS3-^_}~JzN`HaRz`nhzngms$IYmWZF%aFzDN43El+*TEbDun_yb4MhhO1) z9qNy(*ca!^Yh=G0*7$D55(t`O=k0CZi;uGPaDUKuwLikj=nsDnz45mdfV@XM_a$S zFX*@07hz@elRo1Ab8-HE0wR6voeQqpI>-86E&jlf^x=2-UXA+WD)zyAU7C%@7@4i(}T9ZDVhu4w;XwJP)z7qL&y z7ab@2-mvDrPBU^})Wy!*+mA!$cv}zm3m*ryU&7MqPjKB{QM&u|;8wV)rE^mr0qW>~ zQlEa`Me$tgdwVxN(m#$X!uNLZlc{iIUs;p(AlI5`)B<>=5c*K!C;K%R4S3{#J=Ddd{Q&(Jeu{fcfdQ~9qw ztc!i*_RYx|Jz`|6`kb70a8)Y}Mt}B9b$Rx9pgqjld(nh46S6-{yASY%KwTf}6YJx= z8UG%5w4jGRFJFowT?F zI`+f5*q7N)Ba4zgRe)=QFI>BGfc0s0Osp~Ojxb_>)VYqeu|B$1v_7#uz0RqDN7wbx zr#h^s*GY@3p<_R+i+!2>v`qlU_fsvnl2xoPT)S#jd%PMZmb`sh@UJ!}hy79KIyS}n z$gE_2Vtsm@(*lp0dgxR0U+j8%owT?CI`+f5*q8BXL;%KpY67m0~&UI{y^--Q@`(k~1oznx4uJ55wi{ZOoN5@TDtQJ0>v_QvxSQq;;-|vdH8kO*= z4O}Kadq0&7w8#8@x8tNqdFH(APuJiQFN^h2v$FMx_31Uv2t2x>hdy<|cfC$p+yNc? zVO{LYJU@*{`F^(yTqAtp+AV{uPrQa%Y1j(kl?wZ#&UGw+FVr{ovp%st&YSVfz@uAw z=u-yk>2=cLJm}aD>tbKs{ktpR`m1N}r_37JKIOqD_Lo+}^5#l-9*A1|Tc22;X3q*d zYVM&=%72 z9AJH7eR`d<1CMU)p-(kfPp^{}S3<{rSQq;;K8*^%xKGvK7Q>fmz?v>l5qKY<=L-Z9Vjh6@%_{St_i+y?bfxkeVPTI*dKMSV@Irys(kAc>(lF;8+dd_4}I!{?|PlIcrkSB zhjp({^+uHCSn^=TDM%s#vB856QU>RiX7SRV@q zS)W*+Ug!M4qkDVkQ!&=l>!igQ=-3bIVqeCmwC{IC;M(B}*X~+Bdq1t(zWt6S$Ns2u z9V=sfw6AV`Vtsm@3j&Ys>!D9oSWmB`{gS?1y!+FXL0%_q$4PB^zY_yQ|tT zdq3su-SMb7FZwZKV>9amP`IY;i}mSsE($z)pocy!bgZipI`$LQ zg?Zys+V{I=l5qK@{0qHT6*YH4%XA_=(y(HL1AB=czoCo>tbKVr?CMT3|U`Y;5y+8lX;tD`!wO= zs_;6K{ZZ#SW@3Fbt!;f`eR`cs0*@Z*p-+WaPp^{}=R?PSSQq;;KBc|xn*mn|U$}Pd zuxy_`y2$#({-|>u%VT}Ctz&&+eR`cs1CJi=p-&Z9Pp^{}7emK>SQq;;K5ZL-@%>Z| zt_{AFob?yGKZj@g)Mwj$!~Mkm(rQ@VTurQxW$Rj>Sf6Gu3p{$Hhd$L}J-tp^Tm>Eb zVO{JieEliq_3;{T#f8=vu3folwomhltxxQaI@hr=)xsI)|K1w#QeX%~h zj(Lysu^#%=2H*8MY4Jkp&=2ckU!hOIznr*Ft>E%E&)!c(TV(I2ihYk)@1al2;JaQYEpCU7{je_f75WrhkjH)M1Xl-NxOUT))~7+3 zczx^_SDTRiQRh15!x!osGS(;7$9Xe01|B`pL!Sz;o?b`Cb)Vz?dFa>=>tbJ_Pr(Iw z+^2kSUGRl#7i?{P;_FW(v-bX*$+17`T*u;AA1xbMpIDz>=gPpN)*kv)g7x$|X>lQR z?1y!+uh6HI_YsQ0RlygoT~}m%%E!d66>n^BLiR_U>sS@*qhn+16YJCKToriqWDk9+ z#(H|4w73E~_QSf^SLjo4K_1^vRp8p;3)k)%VSNhUj0z^}pRYdH!iiC(6JxZ#lAwHf(!DvPxatRMp|FEcGalt{j^cP`@c3h z_D7xTxG>g7(I&Pp)~DAo_o_VAL!VmUyIv_VuSW=-3bIVqc+8 z!3BBTr*?3KqqFx@`51f5?{`=3^;&^BFZl5qKthra^*&g~-g!S|~X>kE`?1y!+uh6HI>+wQxdBxfLsc>6+%-6>cK4a$5=Dh4L zt%l{zRmA#Oys7nx^=a1JtMXhAeX7KIdY!bm1UmM^y4Y9fQ_A&t1-M%H!nGT>vp(_X zmUFk6)n;<+k2=?}Hr7YiX4WUxr`Iv}stbJ_Pbt^q zwctA7OSJY5+52hQ_4ajN_7~|KgQi#?nJuhOtWPgv?p1ldhdwoLZr9W6q{R);u^-mO zzCxc;uE(3eRlpanU9+S0iPz)59y{t1lVg9>xsGkIKFYVWeX%~h&OZZ>Ug)7ui{ZOo zCoOJ)j{UGM_7(b+ay{M#t_8ku?e?9lPrNP|x>MO;lVg9>xsJ zUhJVyUGQD6lNNVC$9`BB`wD$ZxgK8zu5f4TOa4yw_3`o&dmNe*oN&mVgJzravcI$% zmN!=bU#Mx^+WN%$IB&+A0*_wmp-&mCr`Jh~^Ppottc!hxKBZib7l3PqFI>B=)cVBh zr!St|J^cBO{ZZ#Smc;sKEwVnbKE2M(fk!X*(5G^&r`Jh~i=bmatc!hxKBZibmw?NR zv%Zik8E=nQ$H}-Z`%9}~d2`jVJ~~HOpIDz}&AoK5^w6gotf$w}aRJU>2_5@kUF<9L zDdl>+n)SjLuH7=h`o!y}HBPkO@7N!8u46;2kNi>AC)TIeG56BF+C!fjN80uDI%#no zbnJ(9u`lD(sFc^o8^Gn2Szowz;Y54Pe|N*je|@CMu|Miu$Cg+h#oO4vSf5_U+)KB( zhd#B!cfC$p+zcK2VO{Ji^eN?fyaikxeBs(nldMm?&OH30@vSDu{-|>uJ7RrQjkZ3q zKD~~)m+rM5`qT;E^*U+sV(8cp>tbJ_Pbt^q9eiBj3)jw@Y<=Q=_G3!VDls|sN1f}K z2VbbKA7g!DeVjL=xtH$s9{QAz_4GPvaTn@fKdg&=g+8TRkLO|iO88Ruu>E{X?Jm|Q zUKh-qXs-*{Us?^zn=6X-v2d*QiS=pL+)MXH4}B`edU~C-I0GH~VO{Ji^eN?fya-%7 ze5ssdub;Z6Wbdc@FR||jv%j<&mN!=!>!ZEc`o#J)duQO$n?3ZY3hU{0(&BRH*bnPs zU!hMa*W;Do%BNaixOVk4d(7vjTmN<7&L+qHsB<0b;(csqePVrjox1{$-s+)G_1oI@ z^g3yA4Rq{>b+NC|r>$fA@U&eoGGeqt10~j`dNvz3q$j>2>}U zc=Ub`eOl;PS0i-nC#nnc=Kg}T`!k!7FPLF{Y1!SrK3ZI1kNG;?8+SbTzUhVi>Aqaz z#j!prcEIBwn>TAM3_SXG4}EHf@7>kXd9UrO6*~6Ay4aWTDfo7mc-?m~xH|a4^EB;h zed6l{hacY-d>S~o|B3xk=s0%8`l#K}`o#M5GIs|aeb7Una!~ z>2=IK(H%YXsTS+$b<*N0=-3bIVqeCmwEHt_z-4x`zI1+I?-MK8-5&Gxf)N)S`i?m- z`%9}~d2@}iJ_^QJpIDz}%{|c{_t2-NQoEjBCoQgrj{UGM_GNrZyFarLTqAtp+AWpV zC;r^hck%b(Tj=bMI@hr^)zI3@Kk1=QZSY;MlNK+8j{UGM_GNrZyFarP zT;5#k3)e2(BipABfB*9!lVg9>xsIK&KB^~JpIDz>$J`VBX%Br`2H*8MX>mJr?1y!+ zFXL0%{h6KMYT*mlZrn55r;p$h`=icv%!e=3H!V|m^@;Uq z*4z{QMGt+d#(H|4w73E~_QSf^SLjp9>rYkW;0xF8m}h%NbFQW1VWnEg@bI@ZVf z$eV0^VtslYb5Hb_J@l!e+^(nBNsDWtV?V5meT6=yy#7=VuBgiT!nG^*wa0w_?&VkP z^EmsX&UIWE>!WBF+ZXH8>zI3@JA3F;3w+n>q{U6pu^-mOzCxc;UVmB$t_i+y?biLW z_tP&cUA>~ou|Miu$M#qsl~b%wtWU3F?uq`Yhdy<{cfC$p+y)){VO{Ji^eN@_r*?4p z`&(a{@3YsLMF-g9b#by?SGup-gzPV^hULz|7i#LJTAx@S=gnyDiC)q}pYpJtUMDSH zhC0|!4vyJZ=u^t;PdQk>5x#KkmIJeW8aU|Q&?ojso$FW_>!W#^^@;WAb<91{OMB>3 z5!Tb|q{Ri$u^-mOzCxc;-VZJWm-(ypg=?1_WRLl}%KCF}y~^a+A9b!{MXZm-)2&ae zPp@O{iT=8WK2>5py-r$O0v-EdUF<9LDdqj(3UKxCW%0iD_ii;;Tc7wme&I3a{%+38 z{?ck#-dt_0kFFWkC)TG~b5Ha)J@ly#>*;mU;%eyF59?xIp-(CA2iJn@f-hXV;1KK6 zKuiq3@3XT_$o{Bv9h+i(WOlVau|B7qt10~i}g`H)Aq&s^g8CA=wEv1(_;9p*GY?8pkqI* zi+zPYrTpB|2Cfsn)Gx9B?(z<|KJj&xSxqA=%z4>gS`EvaTNdl1W|sAd^=a1J6aAka z`qTyA^*U*B2XyR*b+NDT-(AXnS_ZBPzHsfjBeH!OdD43`Opg6g=Q!DBOSWmB$78gOsepna#GOw$oy*^$7uDr(j!nLc9vd4TLzo(&L zu*tDM>RiX_SRb9cS)W*+UdP-M{d*66s=<1CowT?TI`+f5*jIP2(^Z3Og)dyY<7n#> zuL}l0d-HUYV}I1Sjt#Ls@++-RtWU3F?uq`hhdwp#Zr9W6q{Vg6u^-mOzRbV7F)7dE z4d9CAXYZ$qW9)JGVU6H~{SR&l-#2G}X*Dcwt|it-@m$*%>(i{cC%SL&(2=IK(JS`Qr%w2;*GY>PL&ttt7yB~*?t*W337?_EAs#GhfI3AMgLSki31jqg3Vs%W}Fa%>b5oiV}T|A_0 zEP{!g2!yN0#p;-{-4RrCBG9ab= zoCt(#$HnTHvM&+*&WS*?j?%?L%Kktwq>m`pl`s*J8w&kY#jTf6%LKV;(4VQe^+lG5 z$ejiKgNoZAp_U19Eztj{xD7>?h{*i}{g!=2l94bGk=qLT{S>!RLM;>IPKN$w#SIl% zA|m%C^aEEA$#4l15xGIo&r)1rLM;>IW(GCrxGfTDnIQKq^rKgl+?En1B64G(pQ*U55^9+sHw*d(#ceIJL`1F``i~Vi zGNG0Ua-TrI{$C_FO2R}$ZUgA2C~ljCS|-R%h5kInjTTuVB6mLYixf8|p_U19Z$kf- z;OmRCT)G|SCd+4VtZfB7tB62gJ zKR|IM3AId+I}rL46jv&;L`3dy&|jvwaS63dkh>lF#}!v5vP4Ag3FzNY+{A=hCdj=B zeW&6ki7XM3`w{xQJdx}oVIm^8GV~iLZc0Ke6XZ68ep|&&6y0>=^{%+Pegjy!ZJqi5>ikm62L`3c* z=zmh&?1Wk-$o&lc$}3B5j)aMbTtDbHQrvC{wM>xP82Yh_+g)Udh}^c&&rsalgjy!Z zRX~4`;`R_(A|h7}{V9suGoh9Va&^!zP~2W3OGM0pKxkI2oQ*pt|Ro#A(I}7>+ zimU6El2^H|f&MyB1=T%wuOGS;_4G>nIJa@`lA(hj>r-bx%tpvpty4rYMCH+A@sK^?mUqt zB64>?|BB+yPpD;r+^f)kp|}e~mWarG3H|>RcVR*;6XbGNwR3A=G)E00OGM-bL%*fs zE>5Urg4|Znk5}9!B1=T%CP2TZ;x0|7WrEyZ&>yF`%S4ul$Q=*;MT)yTp_U194bV3$ z?h275B67Dv|AgZHkxalLGDNB2dpN!t0YWBHjyPFa_2#Rt>SJ^sAYoObaQ*jT9ED@2L1^uClYe}eOg4|)ypP{&iM3#ui zoeBL_ihDSrmI-oKLw}dz9uZk0BKI%o7b))1gjy!Zy$gN6L6Uo1!bC)_KlCMvdm^Eh z33Ah+KT&auM3#uiodo?t#XXf!%LKW*p>J2*(;`bmM}y(F?kMDD-PZ?c9+ zUX?HrksAj6EX6HOsAYoOZ0Ju>+-o9BMC9tAe^7C+C)6@Qt_Aw<759e75)ru{pdUV1 zByUQXh{$aV{dC2>lTgb9xf#&!uef%RB_eVMK!2R#-c6`wg52@YpQpI@M3#ui?YX8+ z-GtE`eVkCs1i71`|59x6!nwM6o%go%jU6zH#0+-C{3Opt4W{u{-8F0w>K z?px?57l`Bw2@?^yU7-J`;=W9%WrEy|(03`WQ)G#V+^^72U0WnyNtlSpO@qExaZ3_v znILxp^!F=nsmKx$xd)(Mrns*YYMCJSJ@ggpNbVa66A`&xp}$FS-zL;DLGEVgzf;_I zB1=T%mO)>qTdo~nIN|X z^m{7qcabF`a(h94n&SRQsAYoO>CnHTxIaafh{!F0zH9@Lu;vc&DiOOF`A=Q zn6#;^znOX@W2e8yXpUB8(x$ThX6l=aonB)jNw3DFOhpk>gQ4F^arsO}Y6+Oy8Tx9) z4P;W}QN+~2&_AZQK}<$!37C2u`V}^o-0DoqR1`6_BJ`DtTZ73+Edf*ignqH&)?!lR zQN+}1(0{ME0wyE11Wf$^{VGEww>Fb96-7*~3jG#}TZhR=Edf(oL4Shc)?-rSQN+~W zpnq0z>oXatC1C0~=vN;qxeb_{>P_f>Q5^4ej>IY; zx5_4Vau`N)v?-HH&ycC%(3dD~GbSlkBU7c&@1eNOnN)g)OzjE%F^b!QNs86T)aB6M zp}4J?RCZX}aR&ycBip#NHNqnM;vjZA$5eV<{H+=fY+ ziXx`^LcgZsMl%_yC17eT=(kXuzL#DI8(lmKTC1NOs0TL&4&IE z#cj*va=6E#U!u639Jr;>7Y&!icXr?og#J#&l{#=spwBCm^OZSpD?>kAar!e2vYL&! zWFhorikrk_914z^nh5<7iYsSwIoy%Z|3h(;9k@p5pHSQ`4qPkrpD1pM1NSNP{Wg_m zraEx_p&y~RX%5`y(2w3s&Ns_}8v}j4;$}N==Rp6S;^sJT??b=o=2GWw4%}wYAE-Ef zhDKJBh)WLK!p_acXpZ(~Qshy@)Ewv+C~hAnBeeufT?75+ikruz$fJma{_l!AkjY3b0aK?y|B>SU%B0Anh^Y?fOSXwY)Dke&2>lz1JB&$@M-fwRLciLG zD3x=Er5Qp;%b z8$dr#amO(ksU={l3i_KAcRZ6Kk0PdShW;1D)iN2WC1C15&`;e)awjk;Q&Gg!H0b}S zxW6$OsU=|QM(Dp&oc=7Q5H=#W4Ej-{MZwQ>%8W$hwt@a6#huKg$fJm;hE3TeNkw+0zw?e;Eapy1@sU=|QYv{MxR&wVuDN|9z)M)7cuDJ7< zjMNe^bqe&)EAD(IMIJ>=y#Rggc2O$l0w!fDikRvHeTm{OWHM4qz*H&prz`FvCPf}a zOq~J!vx;kAGEz&x)N|0Uu)X9iW>Ti2h^ZB!-&t{&Fd3;OV5$WAlNEO_ zjZBI>ikNx``kxhdC6kd_0;Ya}e$0-NyNXGfiXx`QLSL)6tC@_{5-@cF^baX+0h1z+ zBBmaO{tv}n!(^nEfT=&BFWE_Q*D@(nQN&a!^p_~^Iwm8v1Wa8D{ilj+Vp8N$#MEcd zkKQ>-W1z28+zm`dY6+P7q14We9w)g6n3Sm~VrmTZ)rxzN$w(~$QwKwT zwc=Ws6nPXewE+586!#F5ky-+#UWGn)yyPBcQl_GasXox}qqs+yjMNe^H4pl`6!$2T zB99`b{sn!X2~jHNF(zdyikRvP{UpUb&Sa#PfT?omuTqll@qq5o8Ii zMIJ>=eF%N-lqi++E|W49MNIX9eiOyL$7H0IfT>~7&rsa^Oo}{;n5uyO1jYTE$w(~$ zQ`bWOq~bngQshy@)M+#A)U6oJ(Q17nSt1~J8}u(JF5iKB8TxM(H_(Cm4*IocNlAko zxOJc}RovR|j6}PVg zcMSArD{emrt{(bp6}P_wxBEW!ak~VgIXc*ZyA=An6nBUN_b=#QRNSEs+)L1Zskp-& zxZj{(bDr(f{C%VYw-)px6<6cHO@;n2#m#r%4u}2%#U10oT@U@+iaXwcdk6XfRpLvn z16K(BE{Z$Rftv#T;fg!Sfx8O&Clz;!1GfnJuM}73z%7A(;J!K0*QpNNAn3PM+-VNn zcF^yuxYHfD|3N=^zo^WddIxSz=r>o~IS$+w(2rN#xenX}=;tc#JO^$M=#Ny~`3~Iw zpr5tB_;RrWclQBS|13sxbd>}5J@hLdDCb+?!1aTEW5r$Lzzu=ESaH`naN9z^o8qo> z;C6?8zT%o3xMQHdP;u8ga2G*;m*Q@4;Qj^u^NRbY1NQ>-OB8pb1Gg0VRsSlF`%Mnq zYS3?`xSJigt)bslakn^dGoe39am^0g(a>L}xLX~#%b~wlakn{e_d)-f;%;}~UWfi0 z#ogh+eGC1{2g&1irvtZTwbhTqXpSCm;KoCLu;TRZ{*@|hl#7W&pg&u2{2jn?#vGHY zhyF&zJ>*d51JJ*wxJMnh*P;JGagRB0KSDqFVCm*@2X0O1ixu~T19vR+S1E3h19uDb zpDFGc2kvv|%MX$Mo^{~nKtEq`&pU8+&_A!ZmmIhkpkL)ssqTVepx;w*?>lgNL4S}+(!=F zqtL&jxDE&IKhO_6TpssN9k@ZzZ?3q{9Jno@FH_v-4%`9IU#PfF2ks*1TNL+|1NRX0 zA1H2#1NR~HeUA`7mpX7OLSLx3ZydNyp|4Qfw+`H{&>yF`?;N;Gpub6RKR9qVL;r~4 z^#3IwZrO;}6CXj}rMO=l&i58!(YDU} zFq)&)9JsHbpD^F@=I?C;;?{NGWluc6=SIO%T#2X3X~t$rFtb2QX}n-2Y%ird72I}7^96*tU*djk5u)JlKD z9k`XCuTWf}1Gg*m7btF12kt`X-%{LW4&2+&Z*qe4x48p14EhTcw}k_DA@px3PXC`V zQiYB9JoqN`Yy3?V{J&#lMj~>9p+8h{TRYTw81#!2SLDDw1^wD5N-ZNCxOJdEMsXt@ zxMQJzS#hHrxL2Sbc9PV&jRQ9v`co7)+JUQs{yoKwap2yEe$2^I=U4}BEc90>uGoS5 z2lQQv+tz{m75Y8?E_H6_!0ieBNs8Ovfjb%cYZbSH19u(t-zsiL2W}bkLr;@= zfx8^~7RAkQ;2whheZ^HcaQ}w>e~R1Hfy+6~+BgKGIhyIf4TXM^;$}H;<A*)q#7P`ZL9WgB-YA=!Yt<+JV~y z`ZE-Fumg7{^tUSR5C`ry=wDIXp$^=u(Ep&g!yLFDpde2#c_ zx&yZ+^t&qV3g)~oF|XNMGoBB z&`(xeg9En<^tFn+*nv9%`UQ%+#DTj8`c}nV>cBk-{ilk%%z^t1`oEkneqQdttpxoh zio3#rn+*Maio4Q*+aLPV6nB*acRKXfEADCs?gr?eRonsx?m6f`Q`|KU+~?5uy+9s^ zYaO^1pdY5V>m0b@(C?zSCI@Z`^k*pUdI#=I=x{R#bs z7s=yyy91Yjew^a&aNx#6e~{wtbl|F?|A*r4a^M=Fe^GJ&a^PNq{#(T@bl|>&eqe+6 zdA9>M2>MZqyT^gs2KqUQyVrr+4f>-Mcb@|{ANq$CcfSMo2=psmEWSM8z~w=|m*O6D z;P!_8PQ|r2aCbrfmEs<9;FdtY^Ci;X!wy^t^w%lw5eKdb`T>{9`5txPR)PLv#XaW0 zErk9>#kD$cFG2r};+}NizJ-3(%cQ?W4%}+cZ=<-U9JtZY&r#gd4%}|gAFsG)9JpHO z7bxyo2ksi^pH$p)4%{N>zgAqE1NRN|`IpP%@Vo;z5c(q(_ksgg1N~)+d(nZr9Qub8 z_mTtmF!UcN?qvt=L+JZlA-=rg!1aZGxZ+-Q;0mGNMRAKAxGB&dp}5x^xFeyzRB^96 zaF;>wKHzH;CmhyEkQEpgyFpzm{)__EZ2>kIu*#eMC-Z32Cn;=XayINp+87*D>!h~(AO(&MF;L2=$jSy7YFWE=wDFWN)FtM&@WY7o&)za^aHLH zKUa3(R)Ky?#r1RGwt{|!;`%#q70{ooxB(8_-=S|-+$s*-tpO5iLqGWX zoak!<2X0O1w^Q7P4&3(8S1B&z!0ikDd5YV}fjb}ig^JtQfx8>}-xW8+f%^mc%ngy9 zIYS+|ji8^PxJ?|mGU!iJ+%O03bm*HEH{5}{75bMISLndK0{st)+th*k5&9AT6hAj} z;6_5fyW%!?;3}a%M{!#?aOXnbqPQ&`xQC$sKyh0+a34b7=SJ~mYX`0`^urWab9uDJ0I+!fG2q__zV+{4g+ptv#z?nCHv zZ;{7gq660l`r(S3qY`!>ttFwKEm0s0||o9@7!daFIp-5AZ$?hf2N)ZZp`RyuIG&`(m_TnDZk`im5| zhXeN{^xrFPZwKxN=!e`c{q5tx4TZi^aq}FwxzL}cxGD$kbm*T{+`bOnBIvigL;Bm# zf!hlDYZSM?1NRE_E8QvQ`>O+&2YsdD4szh;LVt(isvWpHq5oZR2Rm?oKtJ&=>F*E+ zZW8ndDDF@PZt}nEdCtRVj^;aX=R^N*#U10oeE@xCq4amG1Gf?MRf;>#f!i1QClzMy@6CJqUpdWjW^mmd2R}6i<;!bwp zUV?t$y>h-f2W}AbvlVx$19utp?K(YD&~LA}a~!xG zpr56lQ7zKn4G!E3(0{17 zTO7ELp#M>E%?{j8(D#2x>b%u~8vy+f#ogw>4TXMt#og|}?Ew8O#ogh+Erq`C!_wb9 z4%`aRudld!9k>mkAEUVY9JsO2S19g&2X0sB4^i9$4&0&8pRTwE9k?@~zgBTA4%~In zKcu*a9Jq&}e^YS}J8*A7zf5tDIB?%XKj0DBFONEKt3W?YagRB0!=az7xW^s1U7$Zq zaZfmKheLmc;#wWJGoim;aZfsMH$eZO;ubk@EzrNIxThSrx1e99xThVs@1bAqQF+{- zap3ZyAEvlx9k}7pmn!Z#2W}kndn&HYf!hoE;}rM219v?17b@-r2ks*1Z&Tch4&3d~ zzofXA9JrUEU#hs59k{Qd@Bf%Q?yop-1E3$KxK|yx;n0^UZm|P55&C(Gd(DBXg8n4M zz3#xB4E?o=d&7ad4*EwF_of5)DD-bB?kxvy-sARhtHo%J-gn?mfWAR-|90RmhW=K? zec-^|2K^$%edxeF1^xSq`^bU&H}ttr$iD7y;QBy6TyY;eaD~uMP~0aDTp9F-DDG1S z?ojA2R@`R}+$GSrDDHCy?jh)3RooX2++ygLD(*`M?rZ4tTIKQUbl_HoeyHNUa^N!kiJ#FiI9-}$x zyQ0(_k8&~bBJ@L_5ygrQ9MxRM*z{8H=P$vZ++gyvVEiihW4`(Zf4&a>{1W`>7yL2# ze!-vB0Gm9&FvY{@{~6i3`pCl%-1>lhk2vDst;ZjEz=2!OKk(?|4m^6xqmHjR`pARk zZyf 0) { if (!(self.color)) From 4dbd89a73b2b7a20e81c8a24d4f0c0c8214b076f Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 13 May 2019 22:44:40 +1000 Subject: [PATCH 0676/2474] fix bad megatf code --- misc.qc | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/misc.qc b/misc.qc index b4a1221c..8e78724b 100644 --- a/misc.qc +++ b/misc.qc @@ -638,7 +638,7 @@ void() glass_die = { local entity new; local vector tmpvec; - while (self.color > 0) + while (self.cnt2 > 0) { new = spawn(); new.origin = self.origin; @@ -676,7 +676,7 @@ void() glass_die = tmpvec_y = self.absmin_y + random() * (self.absmax_y - self.absmin_y); tmpvec_z = self.absmin_z + random() * (self.absmax_z - self.absmin_z); setorigin(new, tmpvec); - self.color = self.color - 1; + self.cnt2 = self.cnt2 - 1; } if (self.noise2) { @@ -704,9 +704,13 @@ void() func_glass = self.model = string_null; precache_sound("misc/null.wav"); precache_sound("effects/rcksplsh.wav"); + precache_sound("effects/shatter.wav"); + precache_model("progs/glass2.mdl"); + precache_model("progs/glass1.mdl"); + if (self.health > 0) { - if (!(self.color)) + if (!(self.cnt2)) { tmpvec = self.maxs - self.mins; tmpvec = tmpvec * 0.031; @@ -722,18 +726,18 @@ void() func_glass = { tmpvec_z = 1; } - self.color = tmpvec_x * tmpvec_y * tmpvec_z; + self.cnt2 = tmpvec_x * tmpvec_y * tmpvec_z; } else { - if (self.color == -1) + if (self.cnt2 == -1) { - self.color = 0; + self.cnt2 = 0; } } - if (self.color > 16) + if (self.cnt2 > 16) { - self.color = 16; + self.cnt2 = 16; } self.takedamage = 1; self.max_health = self.health; From e4bc09d1289ce7819c22625751586926181eadc4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 15 May 2019 23:43:18 +1200 Subject: [PATCH 0677/2474] CSQC flaginfo test --- Makefile | 1 + client.qc | 18 + commondefs.qc | 11 + csqc/csdefs.qc | 1431 +++++++++++++++++++++++++++++++++++++++++++ csqc/csextradefs.qc | 1 + csqc/csprogs.src | 5 + csqc/main.qc | 201 ++++++ progs.src | 3 +- status.qc | 71 +++ 9 files changed, 1741 insertions(+), 1 deletion(-) create mode 100644 commondefs.qc create mode 100644 csqc/csdefs.qc create mode 100644 csqc/csextradefs.qc create mode 100644 csqc/csprogs.src create mode 100644 csqc/main.qc diff --git a/Makefile b/Makefile index cb154967..ca0657eb 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ endif all: fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./csqc/csprogs.src clean: rm -f $(TARGET) qwprogs.lno files.dat progdefs.h diff --git a/client.qc b/client.qc index 84e2944d..1c9955b9 100644 --- a/client.qc +++ b/client.qc @@ -169,6 +169,12 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { return FO_GetUserSetting(world, ps_short, ps_setting, ps_default); }; +void (entity goalitem) SetFlagSendMethod = { + if(goalitem) { + goalitem.SendEntity = SendClientFlagStatus; + } +} + void () DecodeLevelParms = { local float fl; local string st; @@ -208,6 +214,11 @@ void () DecodeLevelParms = { if ((number_of_teams <= 0) || (number_of_teams >= 5)) number_of_teams = 4; + //SetFlagSendMethod(Finditem(ent.display_item_status1)); + //SetFlagSendMethod(Finditem(ent.display_item_status2)); + //SetFlagSendMethod(Finditem(ent.display_item_status3)); + //SetFlagSendMethod(Finditem(ent.display_item_status4)); + } else { ent = find(world, classname, "info_player_team1"); @@ -2093,6 +2104,13 @@ void () ClientConnect = { sprint(self, PRINT_HIGH, "Your battle ID is ", st, "\n"); } } + entity tfdet = find(world, classname, "info_tfdetect"); + if(tfdet) { + InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1)); + InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2)); + InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3)); + InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4)); + } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); }; diff --git a/commondefs.qc b/commondefs.qc new file mode 100644 index 00000000..6490dba8 --- /dev/null +++ b/commondefs.qc @@ -0,0 +1,11 @@ +#define MAX_FLAGINFO_LINES 10 + +#define MSG_FLAGINFOINIT 1 +#define MSG_FLAGINFO 2 + +#define FLAGINFO_HOME 1 +#define FLAGINFO_CARRIED 2 +#define FLAGINFO_DROPPED 3 +#define FLAGINFO_RETURNING 4 +#define FLAGINFO_LOCATION 5 +#define FLAGINFO_NOLOCATION 6 diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc new file mode 100644 index 00000000..1cf81f31 --- /dev/null +++ b/csqc/csdefs.qc @@ -0,0 +1,1431 @@ +/* +This file was automatically generated by FTE QuakeWorld v1.03 +This file can be regenerated by issuing the following command: +pr_dumpplatform -O csdefs -Tcs +Available options: +-Ffte - target only FTE (optimations and additional extensions) +-Tnq - dump specifically NQ fields +-Tqw - dump specifically QW fields +-Tcs - dump specifically CSQC fields +-Tmenu - dump specifically menuqc fields +-Fdefines - generate #defines instead of constants +-Faccessors - use accessors instead of basic types via defines +-O - write to a different qc file +*/ +#pragma noref 1 +#pragma warning error Q101 /*too many parms*/ +#pragma warning error Q105 /*too few parms*/ +#pragma warning enable F301 /*non-utf-8 strings*/ +#pragma warning enable F302 /*uninitialised locals*/ +#pragma target FTE +#ifndef CSQC +#define CSQC +#endif +#define strbuf float +#define searchhandle float +#define hashtable float +#define infostring string +#define filestream float +entity self; /* The magic me */ +entity other; /* Valid in touch functions, this is the entity that we touched. */ +entity world; /* The null entity. Hurrah. Readonly after map spawn time. */ +float time; /* The current game time. Stops when paused. */ +float cltime; /* A local timer that ticks relative to local time regardless of latency, packetloss, or pause. */ +float frametime; /* The time since the last physics/render/input frame. */ +float player_localentnum; /* This is entity number the player is seeing from/spectating, or the player themself, can change mid-map. */ +float player_localnum; /* The 0-based player index, valid for getplayerkeyvalue calls. */ +float maxclients; /* Maximum number of player slots on the server. */ +float clientcommandframe; /* This is the input-frame sequence. frames < clientcommandframe have been sent to the server. frame==clientcommandframe is still being generated and can still change. */ +float servercommandframe; /* This is the input-frame that was last acknowledged by the server. Input frames greater than this should be applied to the player's entity. */ +string mapname; /* The short name of the map. */ +float intermission; +vector v_forward, v_up, v_right; +vector view_angles; +float trace_allsolid, trace_startsolid, trace_fraction; +vector trace_endpos, trace_plane_normal; +float trace_plane_dist; +entity trace_ent; +float trace_inopen; +float trace_inwater; +float input_timelength; +vector input_angles; +vector input_movevalues; +float input_buttons; +float input_impulse; +void end_sys_globals; +.float modelindex; +.vector absmin; +.vector absmax; +.float entnum; /* The entity number as its known on the server. */ +.float drawmask; /* Acts as a filter in the addentities call. */ +.float() predraw; /* Called by addentities after the filter and before the entity is actually drawn. Do your interpolation and animation in here. Should return one of the PREDRAW_* constants. */ +.float movetype; +.float solid; +.vector origin; +.vector oldorigin; +.vector velocity; +.vector angles; +.vector avelocity; +.float pmove_flags; +.string classname; +.float renderflags; +.string model; +.float frame; +.float frame1time; /* The absolute time into the animation/framegroup specified by .frame. */ +.float frame2; +.float frame2time; /* The absolute time into the animation/framegroup specified by .frame2. */ +.float lerpfrac; /* If 0, use frame1 only. If 1, use frame2 only. Mix them together for values between. */ +.float skin; +.float effects; +.vector mins; +.vector maxs; +.vector size; +.void() touch; +.void() think; +.void() blocked; +.float nextthink; +.entity chain; +.entity enemy; +.float flags; +.float colormap; +.entity owner; +void end_sys_fields; + +.vector punchangle; +.float gravity; +.float hull; /* Overrides the hull used by the entity for walkmove/movetogoal and not traceline/tracebox. */ +.entity movechain; /* This is a linked list of entities which will be moved whenever this entity moves, logically they are attached to this entity. */ +.void() chainmoved; /* Called when the entity is moved as a result of being part of another entity's .movechain */ +.void(float old, float new) contentstransition; /* This function is called when the entity moves between water and air. If specified, default splash sounds will be disabled allowing you to provide your own. */ +.float dimension_solid; /* This is the bitmask of dimensions which the entity is solid within. */ +.float dimension_hit; /* This is the bitmask of dimensions which the entity will be blocked by. If other.dimension_solid & self.dimension_hit, our traces will impact and not proceed. If its false, the traces will NOT impact, allowing self to pass straight through. */ +.float hitcontentsmask; +.float scale; /* Multiplier that resizes the entity. 1 is normal sized, 2 is double sized. scale 0 is remapped to 1. In SSQC, this is limited to 1/16th precision, with a maximum just shy of 16. */ +.float fatness; /* How many QuakeUnits to push the entity's verticies along their normals by. */ +.float alpha; /* The transparency of the entity. 1 means opaque, 0.0001 means virtually invisible. 0 is remapped to 1, for compatibility. */ +.float modelflags; /* Used to override the flags set in the entity's model. Should be set according to the MF_ constants. Use effects|=EF_NOMODELFLAGS to ignore the model's flags completely. The traileffectnum field is more versatile. */ +.void() customphysics; /* Called once each physics frame, overriding the entity's .movetype field and associated logic. You'll probably want to use tracebox to move it through the world. Be sure to call .think as appropriate. */ +.entity tag_entity; +.float tag_index; +.float skeletonindex; /* This object serves as a container for the skeletal bone states used to override the animation data. */ +.vector colormod; +.vector glowmod; +.vector gravitydir; /* Specifies the direction in which gravity acts. Must be normalised. '0 0 0' also means down. Use '0 0 1' if you want the player to be able to run on ceilings. */ +.vector(vector org, vector ang) camera_transform; /* Provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc. */ +.float geomtype; +.float friction; +.float erp; +.float jointtype; +.float mass; +.float bouncefactor; +.float bouncestop; +.float idealpitch; +.float pitch_speed; +.float forceshader; /* Contains a shader handle used to replace all surfaces upon the entity. */ +.float baseframe; /* See basebone */ +.float baseframe2; /* See basebone */ +.float baseframe1time; /* See basebone */ +.float baseframe2time; /* See basebone */ +.float baselerpfrac; /* See basebone */ +.float basebone; /* The base* frame animations are equivelent to their non-base versions, except that they only affect bone numbers below the 'basebone' value. This means that the base* animation can affect the legs of a skeletal model independantly of the normal animation fields affecting the torso area. For more complex animation than this, use skeletal objects. */ +.float bonecontrol1; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol2; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol3; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol4; /* Halflife model format bone controller. On player models, this typically affects the spine's yaw. */ +.float bonecontrol5; /* Halflife model format bone controller. This typically affects the mouth. */ +.float subblendfrac; /* Weird animation value specific to halflife models. On player models, this typically affects the spine's pitch. */ +.float basesubblendfrac; /* See basebone */ +noref void(float reqid, float responsecode, string resourcebody) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */ +noref void(float apilevel, string enginename, float engineversion) CSQC_Init; /* Called at startup. enginename and engineversion are arbitary hints and can take any form. enginename should be consistant between revisions, but this cannot truely be relied upon. */ +noref void() CSQC_WorldLoaded; /* Called after model+sound precaches have been executed. Gives a chance for the qc to read the entity lump from the bsp. */ +noref void() CSQC_Shutdown; /* Specifies that the csqc is going down. Save your persistant settings here. */ +noref void(float vwidth, float vheight, float notmenu) CSQC_UpdateView; /* Called every single video frame. The CSQC is responsible for rendering the entire screen. */ +noref void(string msg) CSQC_Parse_StuffCmd; /* Gives the CSQC a chance to intercept stuffcmds. Use the tokenize builtin to parse the message. Unrecognised commands would normally be localcmded, but its probably better to drop unrecognised stuffcmds completely. */ +noref float(string msg) CSQC_Parse_CenterPrint; /* Gives the CSQC a chance to intercept centerprints. Return true if you wish the engine to otherwise ignore the centerprint. */ +noref void(string printmsg, float printlvl) CSQC_Parse_Print; /* Gives the CSQC a chance to intercept sprint/bprint builtin calls. CSQC should filter by the client's current msg setting and then pass the message on to the print command, or handle them itself. */ +noref void() CSQC_Parse_Event; /* Called when the client receives an SVC_CGAMEPACKET. The csqc should read the data or call the error builtin if it does not recognise the message. */ +noref float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent; /* Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */ +noref void() CSQC_Input_Frame; /* Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc. */ +noref float(string cmd) CSQC_ConsoleCommand; /* Called if the user uses any console command registed via registercommand. */ +noref float(string text, string info) CSQC_ConsoleLink; /* Called if the user clicks a ^[text\infokey\infovalue^] link. Use infoget to read/check each supported key. Return true if you wish the engine to not attempt to handle the link itself. */ +noref void(float isnew) CSQC_Ent_Update; +noref void() CSQC_Ent_Remove; +noref float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound; +noref float(string resname, string restype) CSQC_LoadResource; /* Called each time some resource is being loaded. CSQC can invoke various draw calls to provide a loading screen, until WorldLoaded is called. */ +noref float() CSQC_Parse_TempEntity; /* Please don't use this. Use CSQC_Parse_Event and multicasts instead. */ +noref void(string cmdtext) GameCommand; +var float physics_mode = 2; /* 0: original csqc - physics are not run +1: DP-compat. Thinks occur, but not true movetypes. +2: movetypes occur just as they do in ssqc. */ +float gamespeed; /* Set by the engine, this is the value of the sv_gamespeed cvar */ +float numclientseats; /* This is the number of splitscreen clients currently running on this client. */ +var vector drawfontscale = '1 1 0'; /* Specifies a scaler for all text rendering. There are other ways to implement this. */ +float drawfont; /* Allows you to choose exactly which font is to be used to draw text. Fonts can be registered/allocated with the loadfont builtin. */ +const float FONT_DEFAULT = 0; +const float TRUE = 1; +const float FALSE = 0; /* File not found... */ +const float M_PI = 3.14159; +const float MOVETYPE_NONE = 0; +const float MOVETYPE_WALK = 3; +const float MOVETYPE_STEP = 4; +const float MOVETYPE_FLY = 5; +const float MOVETYPE_TOSS = 6; +const float MOVETYPE_PUSH = 7; +const float MOVETYPE_NOCLIP = 8; +const float MOVETYPE_FLYMISSILE = 9; +const float MOVETYPE_BOUNCE = 10; +const float MOVETYPE_BOUNCEMISSILE = 11; +const float MOVETYPE_FOLLOW = 12; +const float MOVETYPE_WALLWALK = 31; /* Players using this movetype will be able to orient themselves to walls, and then run up them. */ +const float MOVETYPE_PHYSICS = 32; /* Enable the use of ODE physics upon this entity. */ +const float SOLID_NOT = 0; +const float SOLID_TRIGGER = 1; +const float SOLID_BBOX = 2; +const float SOLID_SLIDEBOX = 3; +const float SOLID_BSP = 4; +const float SOLID_CORPSE = 5; +const float SOLID_LADDER = 20; /* Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead. */ +const float SOLID_PHYSICS_BOX = 32; +const float SOLID_PHYSICS_SPHERE = 33; +const float SOLID_PHYSICS_CAPSULE = 34; +const float SOLID_PHYSICS_TRIMESH = 35; +const float SOLID_PHYSICS_CYLINDER = 36; +const float GEOMTYPE_NONE = -1; +const float GEOMTYPE_SOLID = 0; +const float GEOMTYPE_BOX = 1; +const float GEOMTYPE_SPHERE = 2; +const float GEOMTYPE_CAPSULE = 3; +const float GEOMTYPE_TRIMESH = 4; +const float GEOMTYPE_CYLINDER = 5; +const float GEOMTYPE_CAPSULE_X = 6; +const float GEOMTYPE_CAPSULE_Y = 7; +const float GEOMTYPE_CAPSULE_Z = 8; +const float GEOMTYPE_CYLINDER_X = 9; +const float GEOMTYPE_CYLINDER_Y = 10; +const float GEOMTYPE_CYLINDER_Z = 11; +const float JOINTTYPE_FIXED = -1; +const float JOINTTYPE_POINT = 1; +const float JOINTTYPE_HINGE = 2; +const float JOINTTYPE_SLIDER = 3; +const float JOINTTYPE_UNIVERSAL = 4; +const float JOINTTYPE_HINGE2 = 5; +const float GE_MAXENTS = -1; /* Valid for getentity, ignores the entity argument. Returns the maximum number of entities which may be valid, to avoid having to poll 65k when only 100 are used. */ +const float GE_ACTIVE = 0; /* Valid for getentity. Returns whether this entity is known to the client or not. */ +const float GE_ORIGIN = 1; /* Valid for getentity. Returns the interpolated .origin. */ +const float GE_FORWARD = 2; /* Valid for getentity. Returns the interpolated forward vector. */ +const float GE_RIGHT = 3; /* Valid for getentity. Returns the entity's right vector. */ +const float GE_UP = 4; /* Valid for getentity. Returns the entity's up vector. */ +const float GE_SCALE = 5; /* Valid for getentity. Returns the entity .scale. */ +const float GE_ORIGINANDVECTORS = 6; /* Valid for getentity. Returns interpolated .origin, but also sets v_forward, v_right, and v_up accordingly. Use vectoangles(v_forward,v_up) to determine the angles. */ +const float GE_ALPHA = 7; /* Valid for getentity. Returns the entity alpha. */ +const float GE_COLORMOD = 8; /* Valid for getentity. Returns the colormod vector. */ +const float GE_PANTSCOLOR = 9; /* Valid for getentity. Returns the entity's lower color (from .colormap), as a palette range value. */ +const float GE_SHIRTCOLOR = 10; /* Valid for getentity. Returns the entity's lower color (from .colormap), as a palette range value. */ +const float GE_SKIN = 11; /* Valid for getentity. Returns the entity's .skin index. */ +const float GE_MINS = 12; /* Valid for getentity. Guesses the entity's .min vector. */ +const float GE_MAXS = 13; /* Valid for getentity. Guesses the entity's .max vector. */ +const float GE_ABSMIN = 14; /* Valid for getentity. Guesses the entity's .absmin vector. */ +const float GE_ABSMAX = 15; /* Valid for getentity. Guesses the entity's .absmax vector. */ +const float CONTENT_EMPTY = -1; +const float CONTENT_SOLID = -2; +const float CONTENT_WATER = -3; +const float CONTENT_SLIME = -4; +const float CONTENT_LAVA = -5; +const float CONTENT_SKY = -6; +const float CONTENT_LADDER = -16; /* If this value is assigned to a solid_bsp's .skin field, the entity will become a ladder volume. */ +const float CHAN_AUTO = 0; /* The automatic channel, play as many sounds on this channel as you want, and they'll all play, however the other channels will replace each other. */ +const float CHAN_WEAPON = 1; +const float CHAN_VOICE = 2; +const float CHAN_ITEM = 3; +const float CHAN_BODY = 4; +const float ATTN_NONE = 0; /* Sounds with this attenuation can be heard throughout the map */ +const float ATTN_NORM = 1; /* Standard attenuation */ +const float ATTN_IDLE = 2; /* Extra attenuation so that sounds don't travel too far. */ +const float ATTN_STATIC = 3; /* Even more attenuation to avoid torches drowing out everything else throughout the map. */ +const string INFOKEY_P_PING = "ping"; /* The player's ping time, in milliseconds. */ +const string INFOKEY_P_NAME = "name"; /* The player's name. */ +const string INFOKEY_P_TOPCOLOR = "topcolor"; /* The player's upper/shirt colour (palette index). */ +const string INFOKEY_P_BOTTOMCOLOR = "bottomcolor"; /* The player's lower/pants/trouser colour (palette index). */ +const string INFOKEY_P_TOPCOLOR_RGB = "topcolor_rgb"; /* The player's upper/shirt colour as an rgb value in a format usable with stov. */ +const string INFOKEY_P_BOTTOMCOLOR_RGB = "bottomcolor_rgb"; /* The player's lower/pants/trouser colour as an rgb value in a format usable with stov. */ +const string INFOKEY_P_MUTED = "ignored"; /* 0: we can see the result of the player's say/say_team commands. 1: we see no say/say_team messages from this player. Use the ignore command to toggle this value. */ +const string INFOKEY_P_VOIP_MUTED = "vignored"; /* 0: we can hear this player when they speak (assuming voip is generally enabled). 1: we ignore everything this player says. Use cl_voip_mute to change the values. */ +const string INFOKEY_P_ENTERTIME = "entertime"; /* Reads the timestamp at which the player entered the game, in terms of csqc's time global. */ +const string INFOKEY_P_FRAGS = "frags"; /* Reads a player's frag count. */ +const string INFOKEY_P_PACKETLOSS = "pl"; /* Reads a player's packetloss, as a percentage. */ +const string INFOKEY_P_VOIPSPEAKING = "voipspeaking"; /* Boolean value that says whether the given player is currently sending voice information. */ +const string INFOKEY_P_VOIPLOUDNESS = "voiploudness"; /* Only valid for the local player. Gives a value between 0 and 1 to indicate to the user how loud their mic is. */ +const float FL_FLY = 1; +const float FL_SWIM = 2; +const float FL_CLIENT = 8; +const float FL_INWATER = 16; +const float FL_MONSTER = 32; +const float FL_ITEM = 256; +const float FL_ONGROUND = 512; +const float FL_PARTIALGROUND = 1024; +const float FL_WATERJUMP = 2048; +const float FL_JUMPRELEASED = 4096; +const float FL_FINDABLE_NONSOLID = 16384; /* Allows this entity to be found with findradius */ +const float MOVE_NORMAL = 0; +const float MOVE_NOMONSTERS = 1; /* The trace will ignore all non-solid_bsp entities. */ +const float MOVE_MISSILE = 2; /* The trace will use a bbox size of +/- 15 against entities with FL_MONSTER set. */ +const float MOVE_HITMODEL = 4; /* Traces will impact the actual mesh of the model instead of merely their bounding box. Should generally only be used for tracelines. Note that this flag is unreliable as an object can animate through projectiles. The bounding box MUST be set to completely encompass the entity or those extra areas will be non-solid (leaving a hole for things to go through). */ +const float MOVE_TRIGGERS = 16; /* This trace type will impact only triggers. It will ignore non-solid entities. */ +const float MOVE_EVERYTHING = 32; /* This type of trace will hit solids and triggers alike. Even non-solid entities. */ +const float MOVE_ENTCHAIN = 128; /* Returns a list of entities impacted via the trace_ent.chain field */ +const float RESTYPE_MODEL = 0; /* RESTYPE_* constants are used as arguments with the resourcestatus builtin. */ +const float RESTYPE_SOUND = 1; /* precache_sound */ +const float RESTYPE_PARTICLE = 2; /* particleeffectnum */ +const float RESTYPE_PIC = 3; /* precache_pic. Status results are an amalgomation of the textures used by the named shader. */ +const float RESTYPE_SKIN = 4; /* setcustomskin */ +const float RESTYPE_TEXTURE = 5; /* Individual textures within shaders. These are not directly usable, but may be named as part of a skin file, or a shader. */ +const float RESSTATE_NOTKNOWN = 0; /* RESSTATE_* constants are return values from the resourcestatus builtin. The engine doesn't know about the resource if it is in this state. This means you will need to precache it. Attempting to use it anyway may result in warnings, errors, or silently succeed, depending on engine version and resource type. */ +const float RESSTATE_NOTLOADED = 1; /* The resource was precached, but has been flushed and there has not been an attempt to reload it. If you use the resource normally, chances are it'll be loaded but at the cost of a stall. */ +const float RESSTATE_LOADING = 2; /* Resources in this this state are queued for loading, and will be loaded at the engine's convienience. If you attempt to query the resource now, the engine will stall until the result is available. sounds in this state may be delayed, while models/pics/shaders may be invisible. */ +const float RESSTATE_FAILED = 3; /* Resources in this state are unusable/could not be loaded. You will get placeholders or dummy results. Queries will not stall the engine. The engine may display placeholder content. */ +const float RESSTATE_LOADED = 4; /* Resources in this state are finally usable, everything will work okay. Hurrah. Queries will not stall the engine. */ +const float EF_BRIGHTFIELD = 1; +const float EF_MUZZLEFLASH = 2; +const float EF_BRIGHTLIGHT = 4; +const float EF_DIMLIGHT = 8; +const float EF_ADDITIVE = 32; +const float EF_BLUE = 64; +const float EF_RED = 128; +const float EF_FULLBRIGHT = 512; +const float EF_NODEPTHTEST = 8192; +const float MF_ROCKET = 1; +const float MF_GRENADE = 2; +const float MF_GIB = 4; +const float MF_ROTATE = 8; +const float MF_TRACER = 16; +const float MF_ZOMGIB = 32; +const float MF_TRACER2 = 64; +const float MF_TRACER3 = 128; +const float PFLAGS_NOSHADOW = 1; /* Associated RT lights attached will not cast shadows, making them significantly faster to draw. */ +const float PFLAGS_CORONA = 2; /* Enables support of coronas on the associated rtlights. */ +const float EV_STRING = 1; +const float EV_FLOAT = 2; +const float EV_VECTOR = 3; +const float EV_ENTITY = 4; +const float EV_FUNCTION = 6; +const float EV_POINTER = 7; +const float EV_INTEGER = 8; +const float EV_VARIANT = 9; +hashtable gamestate; /* Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted). */ +const float HASH_REPLACE = 256; /* Used with hash_add. Attempts to remove the old value instead of adding two values for a single key. */ +const float STAT_HEALTH = 0; +const float STAT_WEAPON = 2; +const float STAT_AMMO = 3; +const float STAT_ARMOUR = 4; +const float STAT_WEAPONFRAME = 5; +const float STAT_SHELLS = 6; +const float STAT_NAILS = 7; +const float STAT_ROCKETS = 8; +const float STAT_CELLS = 9; +const float STAT_ACTIVEWEAPON = 10; +const float STAT_TOTALSECRETS = 11; +const float STAT_TOTALMONSTERS = 12; +const float STAT_FOUNDSECRETS = 13; +const float STAT_KILLEDMONSTERS = 14; +const float STAT_ITEMS = 15; +const float STAT_VIEWHEIGHT = 16; +const float STAT_VIEW2 = 20; /* This stat contains the number of the entity in the server's .view2 field. */ +const float STAT_VIEWZOOM = 21; +const float VF_MIN = 1; /* The top-left of the 3d viewport in screenspace. The VF_ values are used via the setviewprop/getviewprop builtins. */ +const float VF_MIN_X = 2; +const float VF_MIN_Y = 3; +const float VF_SIZE = 4; /* The width+height of the 3d viewport in screenspace. */ +const float VF_SIZE_X = 5; +const float VF_SIZE_Y = 6; +const float VF_VIEWPORT = 7; /* vector+vector. Two argument shortcut for VF_MIN and VF_SIZE */ +const float VF_FOV = 8; /* sets both fovx and fovy. consider using afov instead. */ +const float VF_FOVX = 9; /* horizontal field of view. does not consider aspect at all. */ +const float VF_FOVY = 10; /* vertical field of view. does not consider aspect at all. */ +const float VF_ORIGIN = 11; /* The origin of the view. Not of the player. */ +const float VF_ORIGIN_X = 12; +const float VF_ORIGIN_Y = 13; +const float VF_ORIGIN_Z = 14; +const float VF_ANGLES = 15; /* The angles the view will be drawn at. Not the angle the client reports to the server. */ +const float VF_ANGLES_X = 16; +const float VF_ANGLES_Y = 17; +const float VF_ANGLES_Z = 18; +const float VF_DRAWWORLD = 19; /* boolean. If set to 1, the engine will draw the world and static/persistant rtlights. If 0, the world will be skipped and everything will be fullbright. */ +const float VF_DRAWENGINESBAR = 20; /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ +const float VF_DRAWCROSSHAIR = 21; /* boolean. If set to 1, the engine will draw its default crosshair. */ +const float VF_CL_VIEWANGLES = 33; +const float VF_CL_VIEWANGLES_X = 34; +const float VF_CL_VIEWANGLES_Y = 35; +const float VF_CL_VIEWANGLES_Z = 36; +const float VF_PERSPECTIVE = 200; /* 1: regular rendering. Fov specifies the angle. 0: isometric-style. Fov specifies the number of Quake Units each side of the viewport. */ +const float VF_LPLAYER = 202; /* The 'seat' number, used when running splitscreen. */ +const float VF_AFOV = 203; /* Aproximate fov. Matches the 'fov' cvar. The engine handles the aspect ratio for you. */ +const float VF_SCREENVSIZE = 204; /* Provides a reliable way to retrieve the current virtual screen size (even if the screen is automatically scaled to retain aspect). */ +const float VF_SCREENPSIZE = 205; /* Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect). */ +const float VF_VIEWENTITY = 206; /* Changes the RF_EXTERNALMODEL flag on entities to match the new selection, and removes entities flaged with RF_VIEWENTITY. Requires cunning use of .entnum and typically requires calling addentities(MASK_VIEWMODEL) too. */ +const float VF_RT_DESTCOLOUR = 212; /* The texture name to write colour info into, this includes both 3d and 2d drawing. +Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. +Written to by both 3d and 2d rendering. +Note that any rendertarget textures may be destroyed on video mode changes or so. Shaders can name render targets by prefixing texture names with '$rt:', or $sourcecolour. */ +const float VF_RT_SOURCECOLOUR = 209; /* The texture name to use with shaders that specify a $sourcecolour map. */ +const float VF_RT_DEPTH = 210; /* The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16bit=4,24bit=5,32bit=6), sizexy. */ +const float VF_RT_RIPPLE = 211; /* The texture name to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy. */ +const float RF_VIEWMODEL = 1; /* Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob. */ +const float RF_EXTERNALMODEL = 2; /* Specifies that this entity should be displayed in mirrors (and may still cast shadows), but will not otherwise be visible. */ +const float RF_DEPTHHACK = 4; /* Hacks the depth values such that the entity uses depth values as if it were closer to the screen. This is useful when combined with viewmodels to avoid weapons poking in to walls. */ +const float RF_ADDITIVE = 8; /* Shaders from this entity will temporarily be hacked to use an additive blend mode instead of their normal blend mode. */ +const float RF_USEAXIS = 16; /* The entity will be oriented according to the current v_forward+v_right+v_up vector values instead of the entity's .angles field. */ +const float RF_NOSHADOW = 32; /* This entity will not cast shadows. Often useful on view models. */ +const float RF_FRAMETIMESARESTARTTIMES = 64; /* Specifies that the frame1time, frame2time field are timestamps (denoting the start of the animation) rather than time into the animation. */ +const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ +const float IE_KEYUP = 1; /* Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired. */ +const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_MOUSEABS = 3; /* Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_ACCELEROMETER = 4; +const float IE_FOCUS = 5; /* Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged. */ +const float IE_JOYAXIS = 6; /* Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller. */ +const float FILE_READ = 0; /* The file may be read via fgets to read a single line at a time. */ +const float FILE_APPEND = 1; /* Like FILE_WRITE, but writing starts at the end of the file. */ +const float FILE_WRITE = 2; /* fputs will be used to write to the file. */ +const float FILE_READNL = 4; /* Like FILE_READ, except newlines are not special. fgets reads the entire file into a tempstring. */ +const float FILE_MMAP_READ = 5; /* The file will be loaded into memory. fgets returns a pointer to the first byte (and will always return the same value for this file). Cast this to your datatype. */ +const float FILE_MMAP_RW = 6; /* Like FILE_MMAP_READ, except any changes to the data will be written back to disk once the file is closed. */ +const float MASK_ENGINE = 1; /* Valid as an argument for addentities. If specified, all non-csqc entities will be added to the scene. */ +const float MASK_VIEWMODEL = 2; /* Valid as an argument for addentities. If specified, the regular engine viewmodel will be added to the scene. */ +const float PREDRAW_AUTOADD = 0; /* Valid as a return value from the predraw function. Returning this will cause the engine to automatically invoke addentity(self) for you. */ +const float PREDRAW_NEXT = 1; /* Valid as a return value from the predraw function. Returning this will simply move on to the next entity without the autoadd behaviour, so can be used for particle/invisible/special entites, or entities that were explicitly drawn with addentity. */ +const float LFIELD_ORIGIN = 0; +const float LFIELD_COLOUR = 1; +const float LFIELD_RADIUS = 2; +const float LFIELD_FLAGS = 3; +const float LFIELD_STYLE = 4; +const float LFIELD_ANGLES = 5; +const float LFIELD_FOV = 6; +const float LFIELD_CORONA = 7; +const float LFIELD_CORONASCALE = 8; +const float LFIELD_CUBEMAPNAME = 9; +const float LFIELD_AMBIENTSCALE = 10; +const float LFIELD_DIFFUSESCALE = 11; +const float LFIELD_SPECULARSCALE = 12; +const float LFIELD_ROTATION = 13; +const float LFLAG_NORMALMODE = 1; +const float LFLAG_REALTIMEMODE = 2; +const float LFLAG_LIGHTMAP = 4; +const float LFLAG_FLASHBLEND = 8; +const float LFLAG_NOSHADOWS = 256; +const float LFLAG_SHADOWMAP = 512; +const float LFLAG_CREPUSCULAR = 1024; +const float TEREDIT_RELOAD = 0; +const float TEREDIT_SAVE = 1; +const float TEREDIT_SETHOLE = 2; +const float TEREDIT_HEIGHT_SET = 3; +const float TEREDIT_HEIGHT_SMOOTH = 4; +const float TEREDIT_HEIGHT_SPREAD = 5; +const float TEREDIT_HEIGHT_RAISE = 6; +const float TEREDIT_HEIGHT_FLATTEN = 18; +const float TEREDIT_HEIGHT_LOWER = 7; +const float TEREDIT_TEX_KILL = 8; +const float TEREDIT_TEX_GET = 9; +const float TEREDIT_TEX_BLEND = 10; +const float TEREDIT_TEX_UNIFY = 11; +const float TEREDIT_TEX_NOISE = 12; +const float TEREDIT_TEX_BLUR = 13; +const float TEREDIT_WATER_SET = 14; +const float TEREDIT_MESH_ADD = 15; +const float TEREDIT_MESH_KILL = 16; +const float TEREDIT_TINT = 17; +const float TEREDIT_TEX_REPLACE = 19; +const float TEREDIT_RESET_SECT = 20; +const float TEREDIT_RELOAD_SECT = 21; +const float SLIST_HOSTCACHEVIEWCOUNT = 0; +const float SLIST_HOSTCACHETOTALCOUNT = 1; +const float SLIST_MASTERQUERYCOUNT = 2; +const float SLIST_MASTERREPLYCOUNT = 3; +const float SLIST_SERVERQUERYCOUNT = 4; +const float SLIST_SERVERREPLYCOUNT = 5; +const float SLIST_SORTFIELD = 6; +const float SLIST_SORTDESCENDING = 7; +const float SLIST_TEST_CONTAINS = 0; +const float SLIST_TEST_NOTCONTAIN = 1; +const float SLIST_TEST_LESSEQUAL = 2; +const float SLIST_TEST_LESS = 3; +const float SLIST_TEST_EQUAL = 4; +const float SLIST_TEST_GREATER = 5; +const float SLIST_TEST_GREATEREQUAL = 6; +const float SLIST_TEST_NOTEQUAL = 7; +const float SLIST_TEST_STARTSWITH = 8; +const float SLIST_TEST_NOTSTARTSWITH = 9; +void(vector vang) makevectors = #1; /* + Takes an angle vector (pitch,yaw,roll). Writes its results into v_forward, v_right, v_up vectors. */ + +void(entity e, vector o) setorigin = #2; /* + Changes e's origin to be equal to o. Also relinks collision state (as well as setting absmin+absmax), which is required after changing .solid */ + +void(entity e, string m) setmodel = #3; /* + Looks up m in the model precache list, and sets both e.model and e.modelindex to match. BSP models will set e.mins and e.maxs accordingly, other models depend upon the value of sv_gameplayfix_setmodelrealbox - for compatibility you should always call setsize after all pickups or non-bsp models. Also relinks collision state. */ + +void(entity e, vector min, vector max) setsize = #4; /* + Sets the e's mins and maxs fields. Also relinks collision state, which sets absmin and absmax too. */ + +float() random = #7; /* + Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays. */ + +void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags) sound = #8; /* + Starts a sound centered upon the given entity. + chan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample + 'samp' must have been precached first + if specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed. + flags&1 means the sound should be sent reliably. */ + +vector(vector v) normalize = #9; /* + Shorten or lengthen a direction vector such that it is only one quake unit long. */ + +void(string e) error = #10; /* + Ends the game with an easily readable error message. */ + +void(string e) objerror = #11; /* + Displays a non-fatal easily readable error message concerning the self entity, including a field dump. self will be removed! */ + +float(vector v) vlen = #12; /* + Returns the square root of the dotproduct of a vector with itself. Or in other words the length of a distance vector, in quake units. */ + +float(vector v, optional entity reference) vectoyaw = #13; /* + Given a direction vector, returns the yaw angle in which that direction vector points. If an entity is passed, the yaw angle will be relative to that entity's gravity direction. */ + +entity() spawn = #14; /* + Adds a brand new entity into the world! Hurrah, you're now a parent! */ + +void(entity e) remove = #15; /* + Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After two seconds, the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid. */ + +void(vector v1, vector v2, float flags, entity ent) traceline = #16; /* + Traces an infinitely thin line through the world from v1 towards v2. + Will not collide with ent, ent.owner, or any entity who's owner field refers to ent. + There are no side effects beyond the trace_* globals being written. + flags&MOVE_NOMONSTERS will not impact on non-bsp entities. + flags&MOVE_MISSILE will impact with increased size. + flags&MOVE_HITMODEL will impact upon model meshes, instead of their bounding boxes. + flags&MOVE_TRIGGERS will also stop on triggers + flags&MOVE_EVERYTHING will stop if it hits anything, even non-solid entities. + flags&MOVE_LAGGED will backdate entity positions for the purposes of this builtin according to the indicated player ent's latency, to provide lag compensation. */ + +entity(entity start, .string fld, string match) find = #18; /* + Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more. */ + +string(string s) precache_sound = #19; /* + Precaches a sound, making it known to clients and loading it from disk. This builtin (strongly) should be called during spawn functions. This builtin must be called for the sound before the sound builtin is called, or it might not even be heard. */ + +string(string s) precache_model = #20; /* + Precaches a model, making it known to clients and loading it from disk if it has a .bsp extension. This builtin (strongly) should be called during spawn functions. This must be called for each model name before setmodel may use that model name. + Modelindicies precached in SSQC will always be positive. CSQC precaches will be negative if they are not also on the server. */ + +entity(vector org, float rad) findradius = #22; /* + Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. */ + +void(string s, ...) dprint = #25; /* + NQ: Prints the given message on the server's console, but only if the developer cvar is set. Arguments will be concatenated into a single message. */ + +void(string s, ...) dprint = #25; /* + QW: Unconditionally prints the given message on the server's console. Arguments will be concatenated into a single message. */ + +string(float val) ftos = #26; /* + Returns a tempstring containing a representation of the given float. Precision depends upon engine. */ + +string(vector val) vtos = #27; /* + Returns a tempstring containing a representation of the given vector. Precision depends upon engine. */ + +void() coredump = #28; /* + Writes out a coredump. This contains stack, globals, and field info for all ents. This can be handy for debugging. */ + +void() traceon = #29; /* + Enables tracing. This may be spammy, slow, and stuff. Set debugger 1 in order to use fte's qc debugger. */ + +void() traceoff = #30; /* + Disables tracing again. */ + +void(entity e) eprint = #31; /* + Debugging builtin that prints all fields of the given entity to the console. */ + +float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /* + Attempt to walk the entity at a given angle for a given distance. + if settraceglobals is set, the trace_* globals will be set, showing the results of the movement. + This function will trigger touch events. */ + +float() droptofloor = #34; /* + Instantly moves the entity downwards until it hits the ground. If the entity would need to drop more than 'pr_droptofloorunits' quake units, its position will be considered invalid and the builtin will abort. */ + +void(float lightstyle, string stylestring, optional vector rgb) lightstyle = #35; /* + Specifies an auto-animating string that specifies the light intensity for entities using that lightstyle. + a is off, z is fully lit. Should be lower case only. + rgb will recolour all lights using that lightstyle. */ + +float(float) rint = #36; /* + Rounds the given float up or down to the closest integeral value. X.5 rounds away from 0 */ + +float(float) floor = #37; /* + Rounds the given float downwards, even when negative. */ + +float(float) ceil = #38; /* + Rounds the given float upwards, even when negative. */ + +float(entity ent) checkbottom = #40; /* + Expensive checks to ensure that the entity is actually sitting on something solid, returns true if it is. */ + +float(vector pos) pointcontents = #41; /* + Checks the given point to see what is there. Returns one of the SOLID_* constants. Just because a spot is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ + +float(float) fabs = #43; /* + Removes the sign of the float, making it positive if it is negative. */ + +float(string) cvar = #45; /* + Returns the numeric value of the named cvar */ + +void(string, ...) localcmd = #46; /* + Adds the string to the console command queue. Commands will not be executed immediately, but rather at the start of the following frame. */ + +entity(entity) nextent = #47; /* + Returns the following entity. Skips over removed entities. Returns world when passed the last valid entity. */ + +void(vector pos, vector dir, float colour, float count) particle = #48; /* + Spawn 'count' particles around 'pos' moving in the direction 'dir', with a palette colour index between 'colour' and 'colour+8'. */ + +#define ChangeYaw changeyaw +void() changeyaw = #49; /* + Changes the self.angles_y field towards self.ideal_yaw by up to self.yawspeed. */ + +vector(vector fwd, optional vector up) vectoangles = #51; /* + Returns the angles required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning. */ + +float(float angle) sin = #60; /* Part of DP_QC_SINCOSSQRTPOW*/ +float(float angle) cos = #61; /* Part of DP_QC_SINCOSSQRTPOW*/ +float(float value) sqrt = #62; /* Part of DP_QC_SINCOSSQRTPOW*/ +void(entity ent) changepitch = #63; /* Part of DP_QC_CHANGEPITCH*/ +void(entity ent, entity ignore) tracetoss = #64; +string(entity ent) etos = #65; /* Part of DP_QC_ETOS*/ +void(float step) movetogoal = #67; +string(string s) precache_file = #68; /* + This builtin does nothing. It was used only as a hint for pak generation. */ + +void(entity e) makestatic = #69; /* + Sends a copy of the entity's renderable fields to all clients, and REMOVES the entity, preventing further changes. This means it will be unmutable and non-solid. */ + +void(string cvarname, string valuetoset) cvar_set = #72; /* + Instantly sets a cvar to the given string value. */ + +void (vector pos, string samp, float vol, float atten) ambientsound = #74; +string(string str) precache_model2 = #75; +string(string str) precache_sound2 = #76; +string(string str) precache_file2 = #77; +float(string) stof = #81; /* Part of FRIK_FILE, FTE_STRINGS, QW_ENGINE, ZQ_QC_STRINGS*/ +void(vector start, vector mins, vector maxs, vector end, float nomonsters, entity ent) tracebox = #90; /* Part of DP_QC_TRACEBOX + Exactly like traceline, but a box instead of a uselessly thin point. Acceptable sizes are limited by bsp format, q1bsp has strict acceptable size values. */ + +vector() randomvec = #91; /* Part of DP_QC_RANDOMVEC + Returns a vector with random values. Each axis is independantly a value between -1 and 1 inclusive. */ + +vector(vector org) getlight = #92; +void(string cvarname, string defaultvalue) registercvar = #93; /* Part of DP_REGISTERCVAR + Creates a new cvar on the fly. If it does not already exist, it will be given the specified value. If it does exist, this is a no-op. + This builtin has the limitation that it does not apply to configs or commandlines. Such configs will need to use the set or seta command causing this builtin to be a noop. + In engines that support it, you will generally find the autocvar feature easier and more efficient to use. */ + +float(float a, float b, ...) min = #94; /* Part of DP_QC_MINMAXBOUND + Returns the lowest value of its arguments. */ + +float(float a, float b, ...) max = #95; /* Part of DP_QC_MINMAXBOUND + Returns the highest value of its arguments. */ + +float(float minimum, float val, float maximum) bound = #96; /* Part of DP_QC_MINMAXBOUND + Returns val, unless minimum is higher, or maximum is less. */ + +float(float value, float exp) pow = #97; /* Part of DP_QC_SINCOSSQRTPOW*/ +entity(entity start, .float fld, float match) findfloat = #98; /* Part of DP_QC_FINDFLOAT + Equivelent to the find builtin, but instead of comparing strings, this builtin compares floats. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value. + world is returned when there are no more entities. */ + +float(string extname) checkextension = #99; /* + Checks for an extension by its name (eg: checkextension("FRIK_FILE") says that its okay to go ahead and use strcat). + Use cvar("pr_checkextension") to see if this builtin exists. */ + +float(float value) anglemod = #102; +filestream(string filename, float mode, optional float mmapminsize) fopen = #110; /* Part of FRIK_FILE*/ +void(filestream fhandle) fclose = #111; /* Part of FRIK_FILE*/ +string(filestream fhandle) fgets = #112; /* Part of FRIK_FILE*/ +void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) fputs = #113; /* Part of FRIK_FILE*/ +float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s1, optional string s2, ...) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s, float start, float length) substring = #116; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +vector(string s) stov = #117; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +float(string modelname, optional float queryonly) getmodelindex = #200; /* + Acts as an alternative to precache_model(foo);setmodel(bar, foo); return bar.modelindex; + If queryonly is set and the model was not previously precached, the builtin will return 0 without needlessly precaching the model. */ + +__variant(float prnum, string funcname, ...) externcall = #201; /* Part of FTE_MULTIPROGS + Directly call a function in a different/same progs by its name. + prnum=0 is the 'default' or 'main' progs. + prnum=-1 means current progs. + prnum=-2 will scan through the active progs and will use the first it finds. */ + +float(string progsname) addprogs = #202; /* Part of FTE_MULTIPROGS + Loads an additional .dat file into the current qcvm. The returned handle can be used with any of the externcall/externset/externvalue builtins. + There are cvars that allow progs to be loaded automatically. */ + +__variant(float prnum, string varname) externvalue = #203; /* Part of FTE_MULTIPROGS + Reads a global in the named progs by the name of that global. + prnum=0 is the 'default' or 'main' progs. + prnum=-1 means current progs. + prnum=-2 will scan through the active progs and will use the first it finds. */ + +void(float prnum, __variant newval, string varname) externset = #204; /* Part of FTE_MULTIPROGS + Sets a global in the named progs by name. + prnum=0 is the 'default' or 'main' progs. + prnum=-1 means current progs. + prnum=-2 will scan through the active progs and will use the first it finds. */ + +float(string input, string token) instr = #206; /* Part of FTE_MULTIPROGS + Returns substring(input, strstrpos(input, token), -1), or the null string if token was not found in input. You're probably better off using strstrpos. */ + +void(entity portal, float state) openportal = #207; /* + Opens or closes the portals associated with a door or some such on q2 or q3 maps. On Q2BSPs, the entity should be the 'func_areaportal' entity - its style field will say which portal to open. On Q3BSPs, the entity is the door itself, the portal will be determined by the two areas found from a preceding setorigin call. */ + +void(optional __variant ret) abort = #211; /* Part of FTE_MULTITHREADED + QC execution is aborted. Parent QC functions on the stack will be skipped, effectively this forces all QC functions to 'return ret' until execution returns to the engine. If ret is ommited, it is assumed to be 0. */ + +void(vector org, vector dmin, vector dmax, float colour, float effect, float count) particle2 = #215; /* Part of FTE_HEXEN2*/ +void(vector org, vector box, float colour, float effect, float count) particle3 = #216; /* Part of FTE_HEXEN2*/ +void(vector org, float radius, float colour, float effect, float count) particle4 = #217; /* Part of FTE_HEXEN2*/ +float(float number, float quantity) bitshift = #218; /* Part of EXT_BITSHIFT*/ +void(vector pos) te_lightningblood = #219; /* Part of FTE_TE_STANDARDEFFECTBUILTINS*/ +float(string s1, string sub, optional float startidx) strstrofs = #221; /* Part of FTE_STRINGS + Returns the 0-based offset of sub within the s1 string, or -1 if sub is not in s1. + If startidx is set, this builtin will ignore matches before that 0-based offset. */ + +float(string str, float index) str2chr = #222; /* Part of FTE_STRINGS + Retrieves the character value at offset 'index'. */ + +string(float chr, ...) chr2str = #223; /* Part of FTE_STRINGS + The input floats are considered character values, and are concatenated. */ + +string(float ccase, float redalpha, float redchars, string str, ...) strconv = #224; /* Part of FTE_STRINGS + Converts quake chars in the input string amongst different representations. + ccase specifies the new case for letters. + 0: not changed. + 1: forced to lower case. + 2: forced to upper case. + redalpha and redchars switch between colour ranges. + 0: no change. + 1: Forced white. + 2: Forced red. + 3: Forced gold(low) (numbers only). + 4: Forced gold (high) (numbers only). + 5+6: Forced to white and red alternately. + You should not use this builtin in combination with UTF-8. */ + +string(float pad, string str1, ...) strpad = #225; /* Part of FTE_STRINGS + Pads the string with spaces, to ensure its a specific length (so long as a fixed-width font is used, anyway). If pad is negative, the spaces are added on the left. If positive the padding is on the right. */ + +string(infostring old, string key, string value) infoadd = #226; /* Part of FTE_STRINGS + Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \ character. */ + +string(infostring info, string key) infoget = #227; /* Part of FTE_STRINGS + Reads a named value from an infostring. The returned value is a tempstring */ + +#define strcmp strncmp +float(string s1, string s2, optional float len, optional float s1ofs, optional float s2ofs) strncmp = #228; /* Part of FTE_STRINGS + Compares up to 'len' chars in the two strings. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if the two strings are equal, a negative value if s1 appears numerically lower, and positive if s1 appears numerically higher. */ + +float(string s1, string s2) strcasecmp = #229; /* Part of FTE_STRINGS + Compares the two strings without case sensitivity. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +float(string s1, string s2, float len, optional float s1ofs, optional float s2ofs) strncasecmp = #230; /* Part of FTE_STRINGS + Compares up to 'len' chars in the two strings without case sensitivity. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +void() calltimeofday = #231; /* Part of FTE_CALLTIMEOFDAY + Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv. + timeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue) + The strftime builtin is more versatile and less weird. */ + +void(vector angle) rotatevectorsbyangle = #235; +void(vector fwd, vector right, vector up) rotatevectorsbyvectors = #236; +float(float mdlindex, string skinname) skinforname = #237; +float(string shadername, optional string defaultshader, ...) shaderforname = #238; /* Part of FTE_FORCESHADER + Caches the named shader and returns a handle to it. + If the shader could not be loaded from disk (missing file or ruleset_allow_shaders 0), it will be created from the 'defaultshader' string if specified, or a 'skin shader' default will be used. + defaultshader if not empty should include the outer {} that you would ordinarily find in a shader. */ + +void(vector org, optional float count) te_bloodqw = #239; /* Part of FTE_TE_STANDARDEFFECTBUILTINS*/ +float(vector viewpos, entity entity) checkpvs = #240; /* Part of FTE_QC_CHECKPVS*/ +vector(entity ent, float tagnum) rotatevectorsbytag = #244; +int(string) stoi = #259; /* Part of FTE_QC_INTCONV + Converts the given string into an integer. Base 8, 10, or 16 is determined based upon the format of the string. */ + +string(int) itos = #260; /* Part of FTE_QC_INTCONV + Converts the passed integer into a base10 string. */ + +int(string) stoh = #261; /* Part of FTE_QC_INTCONV + Reads a base-16 string (with or without 0x prefix) as an integer. Bugs out if given a base 8 or base 10 string. :P */ + +string(int) htos = #262; /* Part of FTE_QC_INTCONV + Formats an integer as a base16 string, with leading 0s and no prefix. Always returns 8 characters. */ + +float(float modlindex, optional float useabstransforms) skel_create = #263; /* Part of FTE_CSQC_SKELETONOBJECTS + Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model. + eg: self.skeletonobject = skel_create(self.modelindex); */ + +float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS + Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object. + If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */ + +float(float skel) skel_get_numbones = #265; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrives the number of bones in the model. The valid range is 1<=bone<=numbones. */ + +string(float skel, float bonenum) skel_get_bonename = #266; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrieves the name of the specified bone. Mostly only for debugging. */ + +float(float skel, float bonenum) skel_get_boneparent = #267; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrieves which bone this bone's position is relative to. Bone 0 refers to the entity's position rather than an actual bone */ + +float(float skel, string tagname) skel_find_bone = #268; /* Part of FTE_CSQC_SKELETONOBJECTS + Finds a bone by its name, from the model that was used to create the skeletal object. */ + +vector(float skel, float bonenum) skel_get_bonerel = #269; /* Part of FTE_CSQC_SKELETONOBJECTS + Gets the bone position and orientation relative to the bone's parent. Return value is the offset, and v_forward, v_right, v_up contain the orientation. */ + +vector(float skel, float bonenum) skel_get_boneabs = #270; /* Part of FTE_CSQC_SKELETONOBJECTS + Gets the bone position and orientation relative to the entity. Return value is the offset, and v_forward, v_right, v_up contain the orientation. + Use gettaginfo for world coord+orientation. */ + +void(float skel, float bonenum, vector org, optional vector fwd, optional vector right, optional vector up) skel_set_bone = #271; /* Part of FTE_CSQC_SKELETONOBJECTS + Sets a bone position relative to its parent. If the orientation arguments are not specified, v_forward+v_right+v_up are used instead. */ + +void(float skel, float bonenum, vector org, optional vector fwd, optional vector right, optional vector up) skel_mul_bone = #272; /* Part of FTE_CSQC_SKELETONOBJECTS + Transforms a single bone by a matrix. You can use makevectors to generate a rotation matrix from an angle. */ + +void(float skel, float startbone, float endbone, vector org, optional vector fwd, optional vector right, optional vector up) skel_mul_bones = #273; /* Part of FTE_CSQC_SKELETONOBJECTS + Transforms an entire consecutive range of bones by a matrix. You can use makevectors to generate a rotation matrix from an angle, but you'll probably want to divide the angle by the number of bones. */ + +void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; /* Part of FTE_CSQC_SKELETONOBJECTS + Copy bone data from one skeleton directly into another. */ + +void(float skel) skel_delete = #275; /* Part of FTE_CSQC_SKELETONOBJECTS + Deletes a skeletal object. The actual delete is delayed, allowing the skeletal object to be deleted in an entity's predraw function yet still be valid by the time the addentity+renderscene builtins need it. Also uninstanciates any ragdoll currently in effect on the skeletal object. */ + +float(float modidx, string framename) frameforname = #276; /* Part of FTE_CSQC_SKELETONOBJECTS + Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error. */ + +float(float modidx, float framenum) frameduration = #277; /* Part of FTE_CSQC_SKELETONOBJECTS + Retrieves the duration (in seconds) of the specified framegroup. */ + +void(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /* + Realtime terrain editing. Actions are the TEREDIT_ constants. */ + +void() touchtriggers = #279; /* + Triggers a touch events between self and every entity that it is in contact with. This should typically just be the triggers touch functions. */ + +float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* + Updates the skeletal object attached to the entity according to its origin and other properties. + if animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results. + If dollcmd is not set, the ragdoll will update (this should be done each frame). + If the doll is updated without having a valid doll, the model's default .doll will be instanciated. + commands: + doll foo.doll : sets up the entity to use the named doll file + dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix. + cleardoll : uninstanciates the doll without destroying the skeletal object. + animate 0.5 : specifies the strength of the ragdoll as a whole + animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body). + enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter. */ + +float*(float skel) skel_mmap = #282; /* + Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly). */ + +void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up) skel_set_bone_world = #283; /* + Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use. */ + +string(float modidx, float framenum) frametoname = #284; +string(float modidx, float skin) skintoname = #285; +float(float resourcetype, float tryload, string resourcename) resourcestatus = #286; /* + resourcetype must be one of the RESTYPE_ constants. Returns one of the RESSTATE_ constants. Tryload 0 is a query only. Tryload 1 will attempt to reload the content if it was flushed. */ + +hashtable(float tabsize, optional float defaulttype) hash_createtab = #287; /* Part of FTE_QC_HASHTABLES + Creates a hash table object with at least 'tabsize' slots. hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return). */ + +void(hashtable table) hash_destroytab = #288; /* Part of FTE_QC_HASHTABLES + Destroys a hash table object. */ + +void(hashtable table, string name, __variant value, optional float typeandflags) hash_add = #289; /* Part of FTE_QC_HASHTABLES + Adds the given key with the given value to the table. + If flags&HASH_REPLACE, the old value will be removed, if not set then multiple values may be added for a single key, they won't overwrite. + The type argument describes how the value should be stored and saved to files. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games. */ + +__variant(hashtable table, string name, optional __variant deflt, optional float requiretype, optional float index) hash_get = #290; /* Part of FTE_QC_HASHTABLES + looks up the specified key name in the hash table. returns deflt if key was not found. If stringsonly=1, the return value will be in the form of a tempstring, otherwise it'll be the original value argument exactly as it was. If requiretype is specified, then values not of the specified type will be ignored. Hurrah for multiple types with the same name. */ + +__variant(hashtable table, string name) hash_delete = #291; /* Part of FTE_QC_HASHTABLES + removes the named key. returns the value of the object that was destroyed, or 0 on error. */ + +string(hashtable table, float idx) hash_getkey = #292; /* Part of FTE_QC_HASHTABLES + gets some random key name. add+delete can change return values of this, so don't blindly increment the key index if you're removing all. */ + +float(string name) checkcommand = #294; /* Part of FTE_QC_CHECKCOMMAND + Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist. */ + +string(string s) argescape = #295; /* + Marks up a string so that it can be reliably tokenized as a single argument later. */ + +void() clearscene = #300; /* + Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values. */ + +void(float mask) addentities = #301; /* + Walks through all entities effectively doing this: + if (ent.drawmask&mask){ ent.predaw(); if (wasremoved(ent)||(ent.renderflags&RF_NOAUTOADD))continue; addentity(ent); } + If mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list. + If mask&MASK_STDVIEWMODEL then the default view model will also be added. */ + +void(entity ent) addentity = #302; /* + Copies the entity fields into a new rentity for later rendering via addscene. */ + +#define setviewprop setproperty +float(float property, ...) setproperty = #303; /* + Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats. */ + +void() renderscene = #304; /* + Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy. + The scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame. + You may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView. */ + +float(vector org, float radius, vector lightcolours, optional float style, optional string cubemapname, optional float pflags) dynamiclight_add = #305; /* + Adds a temporary dlight, ready to be drawn via addscene. Cubemap orientation will be read from v_forward/v_right/v_up. */ + +void(string texturename, optional float flags) R_BeginPolygon = #306; /* + Specifies the shader to use for the following polygons, along with optional flags. + If flags&4, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects. */ + +void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307; /* + Specifies a polygon vertex with its various properties. */ + +void() R_EndPolygon = #308; /* + Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader. */ + +#define getviewprop getproperty +__variant(float property) getproperty = #309; /* + Retrieve a currently-set (typically view) property, allowing you to read the current viewport or other things. Due to cheat protection, certain values may be unretrievable. */ + +vector (vector v) unproject = #310; /* + Transform a 2d screen-space point (with depth) into a 3d world-space point, according the various origin+angle+fov etc settings set via setproperty. */ + +vector (vector v) project = #311; /* + Transform a 3d world-space point into a 2d screen-space point, according the various origin+angle+fov etc settings set via setproperty. */ + +void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional float drawflag) drawline = #315; /* + Draws a 2d line between the two 2d points. */ + +float(string name) iscachedpic = #316; /* + Checks to see if the image is currently loaded. Engines might lie, or cache between maps. */ + +string(string name, optional float trywad) precache_pic = #317; /* + Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension. */ + +#define draw_getimagesize drawgetimagesize +vector(string picname) drawgetimagesize = #318; /* + Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution. */ + +void(string name) freepic = #319; /* + Tells the engine that the image is no longer needed. The image will appear to be new the next time its needed. */ + +float(vector position, float character, vector size, vector rgb, float alpha, optional float drawflag) drawcharacter = #320; /* + Draw the given quake character at the given position. + If flag&4, the function will consider the char to be a unicode char instead (or display as a ? if outside the 32-127 range). + size should normally be something like '8 8 0'. + rgb should normally be '1 1 1' + alpha normally 1. + Software engines may assume the named defaults. + Note that ALL text may be rescaled on the X axis due to variable width fonts. The X axis may even be ignored completely. */ + +float(vector position, string text, vector size, vector rgb, float alpha, optional float drawflag) drawrawstring = #321; /* + Draws the specified string without using any markup at all, even in engines that support it. + If UTF-8 is globally enabled in the engine, then that encoding is used (without additional markup), otherwise it is raw quake chars. + Software engines may assume a size of '8 8 0', rgb='1 1 1', alpha=1, flag&3=0, but it is not an error to draw out of the screen. */ + +float(vector position, string pic, vector size, vector rgb, float alpha, optional float drawflag) drawpic = #322; /* + Draws an shader within the given 2d screen box. Software engines may omit support for rgb+alpha, but must support rescaling, and must clip to the screen without crashing. */ + +float(vector position, vector size, vector rgb, float alpha, optional float drawflag) drawfill = #323; /* + Draws a solid block over the given 2d box, with given colour, alpha, and blend mode (specified via flags). + flags&3=0 simple blend. + flags&3=1 additive blend */ + +void(float x, float y, float width, float height) drawsetcliparea = #324; /* + Specifies a 2d clipping region (aka: scissor test). 2d draw calls will all be clipped to this 2d box, the area outside will not be modified by any 2d draw call (even 2d polygons). */ + +void(void) drawresetcliparea = #325; /* + Reverts the scissor/clip area to the whole screen. */ + +float(vector position, string text, vector size, vector rgb, float alpha, float drawflag) drawstring = #326; /* + Draws a string, interpreting markup and recolouring as appropriate. */ + +float(string text, float usecolours, optional vector fontsize) stringwidth = #327; /* + Calculates the width of the screen in virtual pixels. If usecolours is 1, markup that does not affect the string width will be ignored. Will always be decoded as UTF-8 if UTF-8 is globally enabled. + If the char size is not specified, '8 8 0' will be assumed. */ + +void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, optional float drawflag) drawsubpic = #328; /* + Draws a rescaled subsection of an image to the screen. */ + +float(float stnum) getstati = #330; /* + Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat (converted to a float). */ + +#define getstatbits getstatf +float(float stnum, optional float firstbit, optional float bitcount) getstatf = #331; /* + Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat. */ + +string(float firststnum) getstats = #332; /* + Retrieves the value of the given EV_STRING stat, as a tempstring. + Older engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but FTE QuakeWorld uses a separate namespace for string stats and has a much higher length limit. */ + +void(entity e, float mdlindex) setmodelindex = #333; /* + Sets a model by precache index instead of by name. Otherwise identical to setmodel. */ + +string(float mdlindex) modelnameforindex = #334; /* + Retrieves the name of the model based upon a precache index. This can be used to reduce csqc network traffic by enabling model matching. */ + +float(string effectname) particleeffectnum = #335; /* + Precaches the named particle effect. If your effect name is of the form 'foo.bar' then particles/foo.cfg will be loaded by the client if foo.bar was not already defined. + Different engines will have different particle systems, this specifies the QC API only. */ + +void(float effectnum, entity ent, vector start, vector end) trailparticles = #336; /* + Draws the given effect between the two named points. If ent is not world, distances will be cached in the entity in order to avoid framerate dependancies. The entity is not otherwise used. */ + +void(float effectnum, vector origin, optional vector dir, optional float count) pointparticles = #337; /* + Spawn a load of particles from the given effect at the given point traveling or aiming along the direction specified. The number of particles are scaled by the count argument. */ + +void(string s, ...) cprint = #338; /* + Print into the center of the screen just as ssqc's centerprint would appear. */ + +void(string s, ...) print = #339; /* + Unconditionally print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar). */ + +string(float keynum) keynumtostring = #340; /* + Returns a hunam-readable name for the given keycode, as a tempstring. */ + +float(string keyname) stringtokeynum = #341; /* + Looks up the key name in the same way that the bind command would, returning the keycode for that key. */ + +string(float keynum) getkeybind = #342; /* + Finds the current binding for the given key (ignores modifiers like shift/alt/ctrl). */ + +void(float usecursor, optional string cursorimage, optional vector hotspot, optional float scale) setcursormode = #343; /* + Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking). If the image name is specified, the engine will use that image for a cursor (use an empty string to clear it again), in a way that will not conflict with the console. Images specified this way will be hardware accelerated, if supported by the platform/port. */ + +vector() getmousepos = #344; /* + Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods. */ + +float(float inputsequencenum) getinputstate = #345; /* + Looks up an input frame from the log, setting the input_* globals accordingly. + The sequence number range used for prediction should normally be servercommandframe < sequence <= clientcommandframe. + The sequence equal to clientcommandframe will change between input frames. */ + +void(float sens) setsensitivityscaler = #346; /* + Temporarily scales the player's mouse sensitivity based upon something like zoom, avoiding potential cvar saving and thus corruption. */ + +void(entity ent) runstandardplayerphysics = #347; /* + Perform the engine's standard player movement prediction upon the given entity using the input_* globals to describe movement. */ + +string(float playernum, string keyname) getplayerkeyvalue = #348; /* + Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver. + Also includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness. */ + +float() isdemo = #349; /* + Returns if the client is currently playing a demo or not */ + +float() isserver = #350; /* + Returns if the client is acting as the server (aka: listen server) */ + +void(vector origin, vector forward, vector right, vector up, optional float inwater) SetListener = #351; /* + Sets the position of the view, as far as the audio subsystem is concerned. This should be called once per CSQC_UpdateView as it will otherwise revert to default. */ + +void(string cmdname) registercommand = #352; /* + Register the given console command, for easy console use. + Console commands that are later used will invoke CSQC_ConsoleCommand. */ + +float(entity ent) wasfreed = #353; /* + Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust. */ + +string(string key) serverkey = #354; /* + Look up a key in the server's public serverinfo string */ + +string(optional string resetstring) getentitytoken = #355; /* + Grab the next token in the map's entity lump. + If resetstring is not specified, the next token will be returned with no other sideeffects. + If empty, will reset from the map before returning the first token, probably {. + If not empty, will tokenize from that string instead. + Always returns tempstrings. */ + +float(string s) findfont = #356; /* + Looks up a named font slot. Matches the actual font name as a last resort. */ + +float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357; /* + too convoluted for me to even try to explain correct usage. Try drawfont = loadfont("foo", "cour", "16", 0, 0, 0); to switch to the courier font, if you have the freetype2 library in windows.. */ + +void(string evname, string evargs, ...) sendevent = #359; /* + Invoke Cmd_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors. */ + +float() readbyte = #360; +float() readchar = #361; +float() readshort = #362; +float() readlong = #363; +float() readcoord = #364; +float() readangle = #365; +string() readstring = #366; +float() readfloat = #367; +float() readentitynum = #368; +float(string modelname, float(float isnew) updatecallback, float flags) deltalisten = #371; /* + Specifies a per-modelindex callback to listen for engine-networking entity updates. Such entities are automatically interpolated by the engine (unless flags specifies not to). + The various standard entity fields will be overwritten each frame before the updatecallback function is called. */ + +__variant(float lno, float fld) dynamiclight_get = #372; /* + Retrieves a property from the given dynamic/rt light. Return type depends upon the light field requested. */ + +void(float lno, float fld, __variant value) dynamiclight_set = #373; /* + Changes a property on the given dynamic/rt light. Value type depends upon the light field to be changed. */ + +string(float efnum, float body) particleeffectquery = #374; /* + Retrieves either the name or the body of the effect with the given number. The effect body is regenerated from internal state, and can be changed before being reapplied via the localcmd builtin. */ + +void(string shadername, vector origin, vector up, vector side, vector rgb, float alpha) adddecal = #375; /* + Adds a temporary clipped decal shader to the scene, centered at the given point with given orientation. Will be drawn by the next renderscene call, and freed by the next clearscene call. */ + +void(entity e, string skinfilename, optional string skindata) setcustomskin = #376; /* + Sets an entity's skin overrides. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format: + surfacename,shadername - makes the named surface use the named shader + replace "surfacename" "shadername" - same. + compose "surfacename" "shader" "imagename@x,y:w,h?r,g,b,a" - compose a skin texture from multiple images. The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line. Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). */ + +__variant*(int size) memalloc = #384; /* Part of FTE_MEMALLOC + Allocate an arbitary block of memory */ + +void(__variant *ptr) memfree = #385; /* Part of FTE_MEMALLOC + Frees a block of memory that was allocated with memfree */ + +void(__variant *dst, __variant *src, int size) memcpy = #386; /* Part of FTE_MEMALLOC + Copys memory from one location to another */ + +void(__variant *dst, int val, int size) memfill8 = #387; /* Part of FTE_MEMALLOC + Sets an entire block of memory to a specified value. Pretty much always 0. */ + +__variant(__variant *dst, float ofs) memgetval = #388; /* + Looks up the 32bit value stored at a pointer-with-offset. */ + +void(__variant *dst, float ofs, __variant val) memsetval = #389; /* + Changes the 32bit value stored at the specified pointer-with-offset. */ + +__variant*(__variant *base, float ofs) memptradd = #390; /* + Perform some pointer maths. Woo. */ + +string(string conname, string field, optional string newvalue) con_getset = #391; /* Part of FTE_CSQC_ALTCONSOLES_WIP + Reads or sets a property from a console object. The old value is returned. Iterrate through consoles with the 'next' field. Valid properties: title, name, next, unseen, markup, forceutf8, close, clear, hidden, linecount */ + +void(string conname, string messagefmt, ...) con_printf = #392; /* Part of FTE_CSQC_ALTCONSOLES_WIP + Prints onto a named console. */ + +void(string conname, vector pos, vector size, float fontsize) con_draw = #393; /* Part of FTE_CSQC_ALTCONSOLES_WIP + Draws the named console. */ + +float(string conname, float inevtype, float parama, float paramb, float paramc) con_input = #394; /* Part of FTE_CSQC_ALTCONSOLES_WIP + Forwards input events to the named console. Mouse updates should be absolute only. */ + +void(entity from, entity to) copyentity = #400; /* Part of DP_QC_COPYENTITY*/ +entity(.string field, string match) findchain = #402; /* Part of DP_QC_FINDCHAIN*/ +entity(.float fld, float match) findchainfloat = #403; /* Part of DP_QC_FINDCHAINFLOAT*/ +void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404; /* Part of DP_SV_EFFECT + Spawns a self-animating sprite */ + +void(vector org, vector dir, float count) te_blood = #405; /* Part of DP_TE_BLOOD*/ +void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406; /* Part of DP_TE_BLOODSHOWER*/ +void(vector org, vector color) te_explosionrgb = #407; /* Part of DP_TE_EXPLOSIONRGB*/ +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408; /* Part of DP_TE_PARTICLECUBE*/ +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409; /* Part of _DP_TE_PARTICLERAIN*/ +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410; /* Part of _DP_TE_PARTICLESNOW*/ +void(vector org, vector vel, float howmany) te_spark = #411; /* Part of DP_TE_SPARK*/ +void(vector org) te_gunshotquad = #412; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_spikequad = #413; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_superspikequad = #414; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_explosionquad = #415; /* Part of _DP_TE_QUADEFFECTS1*/ +void(vector org) te_smallflash = #416; /* Part of DP_TE_SMALLFLASH*/ +void(vector org, float radius, float lifetime, vector color) te_customflash = #417; /* Part of DP_TE_CUSTOMFLASH*/ +void(vector org, optional float count) te_gunshot = #418; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_spike = #419; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_superspike = #420; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_explosion = #421; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_tarexplosion = #422; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_wizspike = #423; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_knightspike = #424; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_lavasplash = #425; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org) te_teleport = #426; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(vector org, float color, float colorlength) te_explosion2 = #427; /* Part of DP_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_lightning1 = #428; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_lightning2 = #429; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_lightning3 = #430; /* Part of DP_TE_STANDARDEFFECTBUILTINS, FTE_TE_STANDARDEFFECTBUILTINS*/ +void(entity own, vector start, vector end) te_beam = #431; /* Part of DP_TE_STANDARDEFFECTBUILTINS*/ +void(vector dir) vectorvectors = #432; /* Part of DP_QC_VECTORVECTORS*/ +void(vector org) te_plasmaburn = #433; /* Part of _DP_TE_PLASMABURN*/ +float(entity e, float s) getsurfacenumpoints = #434; /* Part of DP_QC_GETSURFACE*/ +vector(entity e, float s, float n) getsurfacepoint = #435; /* Part of DP_QC_GETSURFACE*/ +vector(entity e, float s) getsurfacenormal = #436; /* Part of DP_QC_GETSURFACE*/ +string(entity e, float s) getsurfacetexture = #437; /* Part of DP_QC_GETSURFACE*/ +float(entity e, vector p) getsurfacenearpoint = #438; /* Part of DP_QC_GETSURFACE*/ +vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; /* Part of DP_QC_GETSURFACE*/ +float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +string(float n) argv = #442; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +void(entity e, entity tagentity, string tagname) setattachment = #443; /* Part of DP_GFX_QUAKE3MODELTAGS*/ +searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #444; /* Part of DP_QC_FS_SEARCH + initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. */ + +void(searchhandle handle) search_end = #445; /* Part of DP_QC_FS_SEARCH*/ +float(searchhandle handle) search_getsize = #446; /* Part of DP_QC_FS_SEARCH + Retrieves the number of files that were found. */ + +string(searchhandle handle, float num) search_getfilename = #447; /* Part of DP_QC_FS_SEARCH + Retrieves name of one of the files that was found by the initial search. */ + +string(string cvarname) cvar_string = #448; /* Part of DP_QC_CVAR_STRING*/ +entity(entity start, .float fld, float match) findflags = #449; /* Part of DP_QC_FINDFLAGS*/ +entity(.float fld, float match) findchainflags = #450; /* Part of DP_QC_FINDCHAINFLAGS*/ +float(entity ent, string tagname) gettagindex = #451; /* Part of DP_MD3_TAGSINFO*/ +vector(entity ent, float tagindex) gettaginfo = #452; /* Part of DP_MD3_TAGSINFO + Obtains the current worldspace position+orientation of the bone or tag from the given entity. The return value is the world coord, v_forward, v_right, v_up are also set according to the bone/tag's orientation. */ + +entity(float entnum) edict_num = #459; /* Part of DP_QC_EDICT_NUM*/ +strbuf() buf_create = #460; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle) buf_del = #461; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle) buf_getsize = #462; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle_from, strbuf bufhandle_to) buf_copy = #463; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float sortprefixlen, float backward) buf_sort = #464; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, string glue) buf_implode = #465; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, float string_index) bufstr_get = #466; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index, string str) bufstr_set = #467; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle, string str, float order) bufstr_add = #468; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index) bufstr_free = #469; /* Part of DP_QC_STRINGBUFFERS*/ +float(float s) asin = #471; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float c) acos = #472; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float t) atan = #473; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float c, float s) atan2 = #474; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float a) tan = #475; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(string s) strlennocol = #476; /* Part of DP_QC_STRINGCOLORFUNCTIONS*/ +string(string s) strdecolorize = #477; /* Part of DP_QC_STRINGCOLORFUNCTIONS*/ +string(float uselocaltime, string format, ...) strftime = #478; /* Part of DP_QC_STRFTIME*/ +float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR*/ +string(string s) strtolower = #480; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ +string(string s) strtoupper = #481; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ +string(string s) cvar_defstring = #482; /* Part of DP_QC_CVAR_DEFSTRING*/ +void(vector origin, string sample, float volume, float attenuation) pointsound = #483; /* Part of DP_SV_POINTSOUND*/ +string(string search, string replace, string subject) strreplace = #484; /* Part of DP_QC_STRREPLACE*/ +string(string search, string replace, string subject) strireplace = #485; /* Part of DP_QC_STRREPLACE*/ +vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; /* Part of DP_QC_GETSURFACEPOINTATTRIBUTE*/ +float(string name) gecko_create = #487; /* Part of DP_GECKO_SUPPORT*/ +void(string name) gecko_destroy = #488; /* Part of DP_GECKO_SUPPORT*/ +void(string name, string URI) gecko_navigate = #489; /* Part of DP_GECKO_SUPPORT*/ +float(string name, float key, float eventtype) gecko_keyevent = #490; /* Part of DP_GECKO_SUPPORT*/ +void(string name, float x, float y) gecko_mousemove = #491; /* Part of DP_GECKO_SUPPORT*/ +void(string name, float w, float h) gecko_resize = #492; /* Part of DP_GECKO_SUPPORT*/ +vector(string name) gecko_get_texture_extent = #493; /* Part of DP_GECKO_SUPPORT*/ +float(float caseinsensitive, string s, ...) crc16 = #494; /* Part of DP_QC_CRC16*/ +float(string name) cvar_type = #495; /* Part of DP_QC_CVAR_TYPE*/ +float() numentityfields = #496; /* Part of DP_QC_ENTITYDATA*/ +string(float fieldnum) entityfieldname = #497; /* Part of DP_QC_ENTITYDATA*/ +float(float fieldnum) entityfieldtype = #498; /* Part of DP_QC_ENTITYDATA*/ +string(float fieldnum, entity ent) getentityfieldstring = #499; /* Part of DP_QC_ENTITYDATA*/ +float(float fieldnum, entity ent, string s) putentityfieldstring = #500; /* Part of DP_QC_ENTITYDATA*/ +void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, optional float flags) boxparticles = #502; +string(string filename, optional float makereferenced) whichpack = #503; /* Part of DP_QC_WHICHPACK + Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If makereferenced is true, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ + +__variant(float entnum, float fieldnum) getentity = #504; /* + Looks up fields from non-csqc-visible entities. The entity will need to be within the player's pvs. fieldnum should be one of the GE_ constants. */ + +string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE*/ +string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE*/ +float(entity ent) num_for_edict = #512; +float(string uril, float id, optional string postmimetype, optional string postdata) uri_get = #513; /* Part of DP_QC_URI_GET + uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned + returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string */ + +float(string str) tokenize_console = #514; +float(float idx) argv_start_index = #515; +float(float idx) argv_end_index = #516; +void(strbuf strbuf) buf_cvarlist = #517; +string(string cvarname) cvar_description = #518; +float(optional float timetype) gettime = #519; +string(float keynum) keynumtostring_omgwtf = #520; +string(string command, optional float bindmap) findkeysforcommand = #521; +void(string s) loadfromdata = #529; /* + Reads a set of entities from the given string. This string should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + +void(string s) loadfromfile = #530; /* + Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + +float(entity e, float channel) getsoundtime = #533; +float(string sample) soundlength = #534; +float(string filename, strbuf bufhandle) buf_loadfile = #535; +float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536; +void(entity e, float physics_enabled) physics_enable = #540; /* + Enable or disable the physics attached to a MOVETYPE_PHYSICS entity. Entities which have been disabled in this way will stop taking so much cpu time. */ + +void(entity e, vector force, vector relative_ofs) physics_addforce = #541; /* + Apply some impulse directional force upon a MOVETYPE_PHYSICS entity. */ + +void(entity e, vector torque) physics_addtorque = #542; /* + Apply some impulse rotational force upon a MOVETYPE_PHYSICS entity. */ + +void(float trg) setmousetarget = #603; +float() getmousetarget = #604; +void(.../*, string funcname*/) callfunction = #605; /* + Invokes the named function. The function name is always passed as the last parameter and must always be present. The others are passed to the named function as-is */ + +void(filestream fh, entity e) writetofile = #606; /* + Writes an entity's fields to the named frik_file file handle. */ + +float(string s) isfunction = #607; +vector(float vidmode, optional float forfullscreen) getresolution = #608; +string(float keynum) keynumtostring_menu = #609; +string(string command, optional float bindmap) findkeysforcommand_dp = #610; +float(float type) gethostcachevalue = #611; /* Part of FTE_CSQC_SERVERBROWSER*/ +string(float type, float hostnr) gethostcachestring = #612; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(entity e, string s) parseentitydata = #613; /* + Reads a single entity's fields into an already-spawned entity. s should contain field pairs like in a saved game: {"foo1" "bar" "foo2" "5"} */ + +float(string key) stringtokeynum_menu = #614; +void() resethostcachemasks = #615; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float mask, float fld, string str, float op) sethostcachemaskstring = #616; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float mask, float fld, float num, float op) sethostcachemasknumber = #617; /* Part of FTE_CSQC_SERVERBROWSER*/ +void() resorthostcache = #618; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float fld, float descending) sethostcachesort = #619; /* Part of FTE_CSQC_SERVERBROWSER*/ +void() refreshhostcache = #620; /* Part of FTE_CSQC_SERVERBROWSER*/ +float(float fld, float hostnr) gethostcachenumber = #621; /* Part of FTE_CSQC_SERVERBROWSER*/ +float(string key) gethostcacheindexforkey = #622; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(string key) addwantedhostcachekey = #623; /* Part of FTE_CSQC_SERVERBROWSER*/ +string() getextresponse = #624; /* Part of FTE_CSQC_SERVERBROWSER*/ +string(string dnsname, optional float defport) netaddress_resolve = #625; +string(string fmt, ...) sprintf = #627; +float(entity e, float s) getsurfacenumtriangles = #628; +vector(entity e, float s, float n) getsurfacetriangle = #629; +string(string digest, string data, ...) digest_hex = #639; +#if defined(CSQC) || defined(MENU) +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 +#define K_LALT 132 +#define K_RALT -245 +#define K_LCTRL 133 +#define K_RCTRL -246 +#define K_LSHIFT 134 +#define K_RSHIFT -247 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 +#define K_KP_HOME 164 +#define K_KP_UPARROW 165 +#define K_KP_PGUP 166 +#define K_KP_LEFTARROW 161 +#define K_KP_5 162 +#define K_KP_RIGHTARROW 163 +#define K_KP_END 158 +#define K_KP_DOWNARROW 159 +#define K_KP_PGDN 160 +#define K_KP_ENTER 172 +#define K_KP_INS 157 +#define K_KP_DEL 167 +#define K_KP_SLASH 168 +#define K_KP_MINUS 170 +#define K_KP_PLUS 171 +#define K_KP_NUMLOCK 154 +#define K_KP_STAR 169 +#define K_KP_EQUALS 173 +#define K_MOUSE1 512 +#define K_MOUSE2 513 +#define K_MOUSE3 514 +#define K_MOUSE4 517 +#define K_MOUSE5 518 +#define K_MOUSE6 519 +#define K_MOUSE7 520 +#define K_MOUSE8 521 +#define K_MOUSE9 522 +#define K_MOUSE10 523 +#define K_LWIN 239 +#define K_RWIN 240 +#define K_APP -241 +#define K_SEARCH -242 +#define K_POWER 130 +#define K_VOLUP -243 +#define K_VOLDOWN -244 +#define K_JOY1 768 +#define K_JOY2 769 +#define K_JOY3 770 +#define K_JOY4 771 +#define K_AUX1 784 +#define K_AUX2 785 +#define K_AUX3 786 +#define K_AUX4 787 +#define K_AUX5 788 +#define K_AUX6 789 +#define K_AUX7 790 +#define K_AUX8 791 +#define K_AUX9 792 +#define K_AUX10 793 +#define K_AUX11 794 +#define K_AUX12 795 +#define K_AUX13 796 +#define K_AUX14 797 +#define K_AUX15 798 +#define K_AUX16 799 +#define K_AUX17 800 +#define K_AUX18 801 +#define K_AUX19 802 +#define K_AUX20 803 +#define K_AUX21 804 +#define K_AUX22 805 +#define K_AUX23 806 +#define K_AUX24 807 +#define K_AUX25 808 +#define K_AUX26 809 +#define K_AUX27 810 +#define K_AUX28 811 +#define K_AUX29 812 +#define K_AUX30 813 +#define K_AUX31 814 +#define K_AUX32 815 +#define K_PAUSE 153 +#define K_MWHEELUP 515 +#define K_MWHEELDOWN 516 +#define K_PRINTSCREEN 174 +#define K_CAPSLOCK 155 +#define K_SCROLLLOCK 156 +#define K_SEMICOLON 59 +#define K_TILDE 126 +#define K_BACKQUOTE 96 +#define K_BACKSLASH 92 +#endif +#pragma noref 0 diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc new file mode 100644 index 00000000..69cf4781 --- /dev/null +++ b/csqc/csextradefs.qc @@ -0,0 +1 @@ +.float owned_by; diff --git a/csqc/csprogs.src b/csqc/csprogs.src new file mode 100644 index 00000000..c6d6e122 --- /dev/null +++ b/csqc/csprogs.src @@ -0,0 +1,5 @@ +../csprogs.dat +csdefs.qc +../commondefs.qc +csextradefs.qc +main.qc diff --git a/csqc/main.qc b/csqc/main.qc new file mode 100644 index 00000000..c1625dfe --- /dev/null +++ b/csqc/main.qc @@ -0,0 +1,201 @@ +noref void(float apiver, string enginename, float enginever) CSQC_Init = { + print("CSQC Started\n"); + precache_model("progs/weapons/v_rock.mdl"); +}; + +noref void() CSQC_WorldLoaded = { + print("CSQC World Loaded\n"); +} + +typedef struct { + float id; + string message; + //string model; + entity model; + float timeleft; + float state; + vector loc; + string carrier; + string locname; +} FlagInfoLine; + +var FlagInfoLine FlagInfoLines[10]; + +noref void(float width, float height, float menushown) CSQC_UpdateView = { + clearscene(); + setproperty(VF_DRAWWORLD, 1); // we want to draw our world! + setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + setproperty(VF_DRAWENGINESBAR, 1); /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ + //setviewprop(VF_ORIGIN, '0 0 0'); //view position of the scene (after view_ofs effects). + //setviewprop(VF_ANGLES, '0 0 0'); //override the view angles. input will work as normal. other players will see your player as normal. your screen will just be pointing a different direction. + //setviewprop(VF_DRAWWORLD, 1); //whether the world entity should be drawn. set to 0 if you want a completely empty scene. + //setviewprop(VF_MIN, '0 0 0'); //top-left coord (x,y) of the scene viewport in virtual pixels (or annoying physical pixels in dp). + //setviewprop(VF_SIZE, [width, height, 0]); //virtual size (width,height) of the scene viewport in virtual pixels (or annoying physical pixels in dp). + //setviewprop(VF_AFOV, cvar("fov”)); //note: fov_x and fov_y control individual axis. afov is general + //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. + addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view +/* + for(float i = 0; i < FlagInfoLines.length; i++) { + if(FlagInfoLines[i].id) { + //drawstring([16, 32 + 16 * i, 0], FlagInfoLines[i].message, '8 8', '1 1 1', 1, 0); + FlagInfoLines[i].model.origin = [random() * 100 - 50,random() * 100 - 50,random() * 100 - 50]; + addentity(FlagInfoLines[i].model); + } + } +*/ + renderscene(); + for(float i = 0; i < FlagInfoLines.length; i++) { + if(FlagInfoLines[i].id) { + string icon = "sb_key1"; + vector iconcolour = '1 1 1'; + float alpha = 1; + if(FlagInfoLines[i].model) { + switch(FlagInfoLines[i].model.owned_by) { + case 2: + icon = "sb_key2"; + break; + case 3: + iconcolour = '1 1 0'; + break; + case 4: + icon = "sb_key2"; + iconcolour = '0 1 0'; + break; + } + } + if(FlagInfoLines[i].state == FLAGINFO_HOME) { + alpha = 0.3; + } else if(FlagInfoLines[i].state == FLAGINFO_CARRIED) { + drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + } else if(FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { + drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + } + drawpic([8, 28 + 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); + //drawstring([32, 32 + 24 * i, 0], strcat(FlagInfoLines[i].message," ",ftos(FlagInfoLines[i].timeleft)), '8 8', '1 1 1', 1, 0); + //drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].message, '8 8', '1 1 1', 1, 0); + if(FlagInfoLines[i].timeleft >= 0) { + drawstring([24, 46 + 24 * i, 0], ftos(FlagInfoLines[i].timeleft), '6 6', '1 1 1', 1, 0); + } + //addentity(FlagInfoLines[i].model); + //drawstring([300, 32 + 16 * i, 0], strcat(vtos(FlagInfoLines[i].model.origin), " ", FlagInfoLines[i].model.model), '8 8', '1 1 1', 1, 0); + } + } + +} + +void GetSelf() = { + self = findfloat(world, entnum, player_localentnum); +} + +noref float(string cmd) CSQC_ConsoleCommand = { + tokenize(cmd); + //switch(argv(0)) { + //case "moregold": + //} + return FALSE; +}; + +float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { + return FALSE; +} + +void(float isnew) CSQC_Ent_Update = { + print("CSQC_Ent_Update, new: ", ftos(isnew), "\n"); + float etype = readbyte(); + string s; + switch (etype) { + case MSG_FLAGINFO: + s = readstring(); + print("CSQC_Ent_Update, Flag info: ", s, "\n"); + break; + default: + error("Unhandled CSQC entity\n"); //you can change it to a print, but if you're not using sv_csqcdebug 1 doing so would just confuse people over the real cause. + return; + } +}; +void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and will no longer be tracked... + print("CSQC_Ent_Remove\n"); + remove(self); +}; + +void() CSQC_Parse_Event = { + //print("CSQC_Parse_Event\n"); + float msgtype = readbyte(); + local float goalno; + switch (msgtype) { + case MSG_FLAGINFOINIT: + float index = readfloat(); + goalno = readfloat(); + string mdl = readstring(); + float skinindex = readfloat(); + float ownerteam = readfloat(); + if(index >= 0 && index < MAX_FLAGINFO_LINES) { + FlagInfoLines[index].id = goalno; + FlagInfoLines[index].message = ""; + if(mdl) + precache_model(mdl); + entity te = spawn(); + te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; + te.origin = [5, 0, 0]; + te.angles = '-60 0 0'; + //setmodel(te,mdl); + setmodel(te, "progs/weapons/v_rock.mdl"); + setsize(te, '-16 -16 0', '16 16 8'); + te.skin = skinindex; + te.owned_by = ownerteam; + FlagInfoLines[index].model = te; + } + break; + case MSG_FLAGINFO: + string message = ""; + goalno = readfloat(); + float state = readfloat(); + float timeleft = -1; + vector droploc = '0 0 0'; + string carrier = ""; + string locname = ""; + switch (state) { + case FLAGINFO_HOME: + message = "^2HOME"; + break; + case FLAGINFO_CARRIED: + carrier = readstring(); + message = strcat("^1CARRIED^7 by ",carrier); + break; + case FLAGINFO_DROPPED: + message = "^3DROPPED^7"; + timeleft = readfloat(); + float showloc = readfloat(); + if(showloc == FLAGINFO_LOCATION) { + droploc_x = readcoord(); + droploc_y = readcoord(); + droploc_z = readcoord(); + //message = strcat(message," at ", vtos(droploc)); + locname = readstring(); + message = strcat(message," at ", locname); + } + //if(timeleft >= 0) { + //message = strcat(message," returning in ", ftos(timeleft)); + //} + break; + case FLAGINFO_RETURNING: + message = "^4RETURNING"; + break; + } + for(float i = 0; i < FlagInfoLines.length; i++) { + if(FlagInfoLines[i].id == goalno) { + FlagInfoLines[i].message = message; + FlagInfoLines[i].timeleft = timeleft; + FlagInfoLines[i].state = state; + FlagInfoLines[i].loc = droploc; + FlagInfoLines[i].carrier = carrier; + FlagInfoLines[i].locname = locname; + } + } + + //print("CSQC_Parse_Event, Flag info: ", readstring(), "\n"); + break; + default: + print("CSQC_Parse_Event, unknown event: ",ftos(msgtype),"\n"); + } +} diff --git a/progs.src b/progs.src index d6933ca5..8b9d889d 100644 --- a/progs.src +++ b/progs.src @@ -1,6 +1,7 @@ qwprogs.dat defs.qc fteextensions.qc +commondefs.qc qw.qc q3defs.qc debug.qc @@ -48,4 +49,4 @@ coop.qc actions.qc spect.qc q3.qc -mvdsv.qc \ No newline at end of file +mvdsv.qc diff --git a/status.qc b/status.qc index b2cd87d6..2ac1309d 100644 --- a/status.qc +++ b/status.qc @@ -580,8 +580,79 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr string getLocationName(vector location); +void (entity Player, float index, entity Item) InitClientFlagStatus = { + float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); + if(csqcactive) { + msg_entity = Player; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAGINFOINIT); + WriteFloat(MSG_MULTICAST, index); + WriteFloat(MSG_MULTICAST, Item.goal_no); + WriteString(MSG_MULTICAST, Item.mdl); + WriteFloat(MSG_MULTICAST, Item.skin); + WriteFloat(MSG_MULTICAST, Item.owned_by); + multicast('0 0 0', MULTICAST_ONE_R); + } +} + +void (entity Player, entity Item) UpdateClientFlagStatus = { + //Check if client is running csqc + float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); + if(csqcactive) { + //bprint(PRINT_HIGH, "Player ", Player.netname, " is ", infokey(Player, INFOKEY_P_CSQCACTIVE), "\n"); + + msg_entity = Player; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAGINFO); + WriteFloat(MSG_MULTICAST, Item.goal_no); + if (Item.goal_state == 1 && Item.owner != world) { + WriteFloat(MSG_MULTICAST, FLAGINFO_CARRIED); + if (Player == Item.owner) { + WriteString(MSG_MULTICAST, "YOU"); + } else { + WriteString(MSG_MULTICAST, Item.owner.netname); + } + } else { + if (Item.origin != Item.oldorigin) { + if((Item.nextthink - time) >= 0) { + WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); + if(Item.think != tfgoalitem_droptouch) { + WriteFloat(MSG_MULTICAST, rint(Item.bubble_count - time)); + if((Item.think == tfgoalitem_dropthink || Item.think == tfgoalitem_remove) && !Item.owner) { + WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); + WriteCoord(MSG_MULTICAST, Item.origin_x); + WriteCoord(MSG_MULTICAST, Item.origin_y); + WriteCoord(MSG_MULTICAST, Item.origin_z); + WriteString(MSG_MULTICAST, getLocationName(Item.origin)); + } else { + WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); + } + } else { + WriteFloat(MSG_MULTICAST, -1); + WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); + } + } else { + WriteFloat(MSG_MULTICAST, FLAGINFO_RETURNING); + } + } else { + WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); + } + } + multicast('0 0 0', MULTICAST_ONE); + //multicast('0 0 0', MULTICAST_ONE_R); + } +} + +float(entity playerent, float changedflags) SendClientFlagStatus = { + bprint(PRINT_HIGH, "SendClientFlagStatus, for: ",playerent.netname,"\n"); + WriteByte (MSG_ENTITY, MSG_FLAGINFO); + WriteString (MSG_ENTITY, self.mdl); + return TRUE; +} + string (entity Player, entity Item, float teamno) GetItemStatus = { local string st; + UpdateClientFlagStatus(Player, Item); switch (teamno) { case 1: From 9d497a7943853d0b71cfe501de3ae62d307c3358 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 May 2019 08:15:55 +1200 Subject: [PATCH 0678/2474] Move flag status down --- csqc/main.qc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index c1625dfe..df8685c2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -44,7 +44,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } */ renderscene(); - for(float i = 0; i < FlagInfoLines.length; i++) { + float yoffset = height - 64; + for(float i = FlagInfoLines.length - 1; i >= 0; i--) { if(FlagInfoLines[i].id) { string icon = "sb_key1"; vector iconcolour = '1 1 1'; @@ -66,15 +67,19 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if(FlagInfoLines[i].state == FLAGINFO_HOME) { alpha = 0.3; } else if(FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + //drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if(FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([8, 28 + 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); + //drawpic([8, 28 + 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); + drawpic([8, yoffset - 4 - 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); //drawstring([32, 32 + 24 * i, 0], strcat(FlagInfoLines[i].message," ",ftos(FlagInfoLines[i].timeleft)), '8 8', '1 1 1', 1, 0); //drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].message, '8 8', '1 1 1', 1, 0); if(FlagInfoLines[i].timeleft >= 0) { - drawstring([24, 46 + 24 * i, 0], ftos(FlagInfoLines[i].timeleft), '6 6', '1 1 1', 1, 0); + string stime = ftos(FlagInfoLines[i].timeleft); + //drawstring([24, 46 + 24 * i, 0], ftos(FlagInfoLines[i].timeleft), '6 6', '1 1 1', 1, 0); + drawstring([30 - stringwidth(stime, 1, '6 6'), yoffset + 14 - 24 * i, 0], stime, '6 6', '1 1 1', 1, 0); } //addentity(FlagInfoLines[i].model); //drawstring([300, 32 + 16 * i, 0], strcat(vtos(FlagInfoLines[i].model.origin), " ", FlagInfoLines[i].model.model), '8 8', '1 1 1', 1, 0); From b3fca9b91e5cb52eb0c14f67abc4670f1a633a5d Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 18 May 2019 22:41:45 +1200 Subject: [PATCH 0679/2474] Basic class restriction override functionality + admin menu option. --- client.qc | 5 +++- defs.h | 1 + menu.qc | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- qw.qc | 1 + tfort.qc | 16 +++++++++--- 5 files changed, 90 insertions(+), 9 deletions(-) diff --git a/client.qc b/client.qc index 84e2944d..e5d5eaba 100644 --- a/client.qc +++ b/client.qc @@ -544,6 +544,9 @@ void () DecodeLevelParms = { // enable flag model following the player who has it flag_follow = CF_GetSetting("flagfollow", "flag_follow", "on"); + // override map-set class restrictions [off] + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; @@ -1250,7 +1253,7 @@ void () PutClientInServer = { if (self.tfstate & TFSTATE_RANDOMPC) { oldclass = self.playerclass; self.playerclass = 1 + floor(random() * (10 - 1)); - while (!IsLegalClass(self.playerclass) || + while ((!IsLegalClass(self.playerclass) && !override_mapclasses) || (self.playerclass == oldclass) || CF_ClassIsRestricted(self.team_no, self.playerclass)) { self.playerclass = 1 + floor(random() * (10 - 1)); diff --git a/defs.h b/defs.h index 22c57d00..ee8ed16b 100644 --- a/defs.h +++ b/defs.h @@ -330,6 +330,7 @@ #define ADMIN_MENU_TYPE_QUADMODE 6 #define ADMIN_MENU_TYPE_QUAD_ROUNDNUM 7 #define ADMIN_MENU_TYPE_QUAD_ROUNDTL 8 +#define ADMIN_MENU_TYPE_CLASSES 9 /*======================================================*/ diff --git a/menu.qc b/menu.qc index 8c450c31..d73a2da8 100644 --- a/menu.qc +++ b/menu.qc @@ -99,6 +99,8 @@ void () Admin_CeaseFire; void () Broadcast_Players_NotReady; void () StartTimer; +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; + void (entity pl) Menu_Close = { pl.menu_input = nil; @@ -240,13 +242,13 @@ void (float update) Menu_Team = { void (float inp) Menu_Class_Input = { if (!inp) return; - + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); // keep showing menu if class is invalid - if (inp > 10 || !IsLegalClass(inp) || CF_ClassIsRestricted(self.team_no, inp)) + if (inp > 10 || (!IsLegalClass(inp) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, inp)) Menu_Class(0); // don't try to change class if class is forbidden - if (!IsLegalClass(inp) || CF_GetClassRestriction(self.team_no, inp) == -1) + if ((!IsLegalClass(inp) && !override_mapclasses) || CF_GetClassRestriction(self.team_no, inp) == -1) return; // close menu if selected class is current class @@ -273,7 +275,8 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { local float f_max = CF_GetClassRestriction(self.team_no, pf_class); local float f_players = CF_GetClassPlayers(self.team_no, pf_class); - if (IsLegalClass(pf_class) && f_max >= 0) { + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + if ((IsLegalClass(pf_class) || override_mapclasses) && f_max >= 0) { if (f_players < 10) s_string = strpadl(ftos(f_players), (1 + f_gap)); else @@ -1028,6 +1031,7 @@ void () Menu_Admin = { local string s_menu1; local string s_menu2; + local string override; /* More menu lines, commented for the sake of unecessary warnings * local string s_menu3; @@ -1069,6 +1073,8 @@ void () Menu_Admin = s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); s_menu1 = strcat(s_menu1, Q"\s[6]\s Ready Status \n"); s_menu1 = strcat(s_menu1, Q"\s[7]\s Force Match Start (Be Nice) \n"); + } else if (self.current_menu_page == 3) { + s_menu1 = strcat(s_menu1, Q"\s[1]\s Class Settings \n"); } s_menu1 = strcat(s_menu1, "\n\n"); s_menu1 = strcat(s_menu1, Q"\s[8]\s Previous Page \n"); @@ -1117,6 +1123,39 @@ void () Menu_Admin = s_menu1 = strcat(Q"\[\sCaptain\s\] Team ", ftos(self.team_no)); s_menu1 = strcat(s_menu1, " : \n\n"); break; + case ADMIN_MENU_TYPE_CLASSES: + s_menu1 = "Class Management Menu: \n\n"; + //override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + //if(override_mapclasses) { + // override = "\x10 on\x11"; + //} else { + // override = "\x10off\x11"; + //} + if (self.current_menu_page == 1) { + //s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings ", override, "\n"); + s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings \n"); + //s_menu1 = strcat(s_menu1, Q"\s[2]\s Scout \n"); + //s_menu1 = strcat(s_menu1, Q"\s[3]\s Sniper \n"); + //s_menu1 = strcat(s_menu1, Q"\s[4]\s Soldier \n"); + //s_menu1 = strcat(s_menu1, Q"\s[5]\s Demoman \n"); + //s_menu1 = strcat(s_menu1, Q"\s[6]\s Medic \n"); + //s_menu1 = strcat(s_menu1, Q"\s[7]\s Heavy \n"); + } else if (self.current_menu_page == 2) { + //s_menu1 = strcat(s_menu1, Q"\s[1]\s Pyro \n"); + //s_menu1 = strcat(s_menu1, Q"\s[2]\s Spy \n"); + //s_menu1 = strcat(s_menu1, Q"\s[3]\s Engineer \n"); + //s_menu1 = strcat(s_menu1, Q"\s[4]\s RandomPC \n"); + //s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); + //s_menu1 = strcat(s_menu1, Q"\s[6]\s \n"); + //s_menu1 = strcat(s_menu1, Q"\s[7]\s \n"); + } + s_menu1 = strcat(s_menu1, "\n\n"); + s_menu1 = strcat(s_menu1, Q"\s[8]\s Previous Page \n"); + s_menu1 = strcat(s_menu1, Q"\s[9]\s Next Page \n"); + s_menu1 = strcat(s_menu1, Q"\s[0]\s Exit Menu \n"); + + Status_Menu(self, Menu_Admin_Input, s_menu1); + break; } // jesus christ what is this, this should be separated out for the good of the people @@ -1358,6 +1397,17 @@ void (float inp) Menu_Admin_Input = return; } } + else if (self.current_menu_page == 3) + { + switch (inp) + { + case 1: + self.current_menu_type = ADMIN_MENU_TYPE_CLASSES; + self.current_menu_page = 1; + Menu_Admin(); + return; + } + } } else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN ) && inp >= 1 && inp <= 7) @@ -1521,6 +1571,24 @@ void (float inp) Menu_Admin_Input = self.current_menu_page = 1; Menu_Admin(); } + else if (self.current_menu_type == ADMIN_MENU_TYPE_CLASSES) + { + if (self.current_menu_page == 1) + { + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + switch (inp) + { + case 1: + override_mapclasses = !override_mapclasses; + localcmd("localinfo omc "); + localcmd(ftos(override_mapclasses)); + localcmd("\n"); + bprint(PRINT_HIGH, self.netname, " has set server class overrides to ", ftos(override_mapclasses), "\n"); + Menu_Admin(); + return; + } + } + } //Previous page if (inp == 8) { diff --git a/qw.qc b/qw.qc index 59ae9653..74fbf89b 100644 --- a/qw.qc +++ b/qw.qc @@ -526,6 +526,7 @@ float unpause_requested; float unpause_countdown; float unpause_lastcountnumber; float chweap_wait_attfinished; +float override_mapclasses; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/tfort.qc b/tfort.qc index 81b8a044..b48afe71 100644 --- a/tfort.qc +++ b/tfort.qc @@ -140,6 +140,7 @@ void (float inp) TeamFortress_ChangeClass = { if ((intermission_running != 0) || (intermission_exittime > time)) return; + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); if (self.playerclass != 0) { if ((deathmatch != 3) && (!cb_prematch)) return; @@ -157,7 +158,7 @@ void (float inp) TeamFortress_ChangeClass = { sprint(self, PRINT_HIGH, "You cannot change class\n"); return; } - if (!IsLegalClass(inp)) { + if (!IsLegalClass(inp) && !override_mapclasses) { sprint(self, PRINT_HIGH, "Your team cannot play that class\n"); TeamFortress_DisplayLegalClasses(); @@ -202,7 +203,7 @@ void (float inp) TeamFortress_ChangeClass = { sprint(self, PRINT_HIGH, "You have no lives left\n"); return; } - if (!IsLegalClass(inp) && (inp != 11)) { + if (!IsLegalClass(inp) && !override_mapclasses && (inp != 11)) { sprint(self, PRINT_HIGH, "You cannot play that class on this map\n"); TeamFortress_DisplayLegalClasses(); @@ -307,9 +308,14 @@ void () TeamFortress_DisplayLegalClasses = { local float gotone; local float ill; + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); sprint(self, PRINT_HIGH, "Legal classes for your team are:\n"); gotone = 0; - ill = TeamFortress_TeamGetIllegalClasses(self.team_no); + if(override_mapclasses) { + ill = -1; //Nothing is illegal unless restricted on server + } else { + ill = TeamFortress_TeamGetIllegalClasses(self.team_no); + } if (!(illegalclasses & 1) && !(ill & 1)) { if (gotone) { sprint(self, PRINT_HIGH, ", "); @@ -668,6 +674,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Allow feign death while airborne", feign_air, "", 1); CF_PrintSetting("Drop feign backpack", feign_pack, "", 1); CF_PrintSetting("Print feign death message", feign_msg, "", 1); + CF_PrintSetting("Override Map Class Limits", override_mapclasses, "", 0); if (server_faithful) { sprint(self, PRINT_HIGH, "\nThis server is running faithful Team Fortress settings.\n"); @@ -1088,8 +1095,9 @@ float (float pc) IsLegalClass = { else if (pc == PC_RANDOM) bit = TF_ILL_RANDOMPC; + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); if ((illegalclasses & bit) || - (TeamFortress_TeamGetIllegalClasses(self.team_no) & bit)) + (TeamFortress_TeamGetIllegalClasses(self.team_no) & bit && !override_mapclasses)) return (FALSE); return (TRUE); From 18bff29b94e63f32b485038368a78d72cb23d3bb Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 31 May 2019 20:06:27 +1200 Subject: [PATCH 0680/2474] fixed class override status; added force spectator basics --- admin.qc | 7 +++++++ defs.h | 1 + menu.qc | 50 +++++++++++++++++++++++++++++++------------------- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/admin.qc b/admin.qc index d9b6c16d..1f73725c 100644 --- a/admin.qc +++ b/admin.qc @@ -115,6 +115,13 @@ void () Admin_DoBan = { self.admin_use = world; }; +void () Admin_ForceSpectator = { + bprint4(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); + stuffcmd(self.admin_use, "observe\n"); + self.admin_mode = 0; + self.admin_use = world; +}; + void () CeaseFire_think = { local entity te; diff --git a/defs.h b/defs.h index ee8ed16b..cb0fc5af 100644 --- a/defs.h +++ b/defs.h @@ -331,6 +331,7 @@ #define ADMIN_MENU_TYPE_QUAD_ROUNDNUM 7 #define ADMIN_MENU_TYPE_QUAD_ROUNDTL 8 #define ADMIN_MENU_TYPE_CLASSES 9 +#define ADMIN_MENU_TYPE_FORCESPEC 10 /*======================================================*/ diff --git a/menu.qc b/menu.qc index d73a2da8..686df117 100644 --- a/menu.qc +++ b/menu.qc @@ -93,6 +93,7 @@ void (float inp) Menu_Dispenser_Input; void () Menu_Admin; void (float inp) Menu_Admin_Input; void () Admin_DoKick; +void () Admin_ForceSpectator; void () Admin_Pause; void () Admin_CeaseFire; @@ -1070,7 +1071,7 @@ void () Menu_Admin = s_menu1 = strcat(s_menu1, Q"\s[2]\s Quad Mode \n"); s_menu1 = strcat(s_menu1, Q"\s[3]\s Pub Mode \n"); s_menu1 = strcat(s_menu1, Q"\s[4]\s Duel Mode (Not implemented) \n"); - s_menu1 = strcat(s_menu1, Q"\s[5]\s \n"); + s_menu1 = strcat(s_menu1, Q"\s[5]\s Force Spectate \n"); s_menu1 = strcat(s_menu1, Q"\s[6]\s Ready Status \n"); s_menu1 = strcat(s_menu1, Q"\s[7]\s Force Match Start (Be Nice) \n"); } else if (self.current_menu_page == 3) { @@ -1126,14 +1127,15 @@ void () Menu_Admin = case ADMIN_MENU_TYPE_CLASSES: s_menu1 = "Class Management Menu: \n\n"; //override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); - //if(override_mapclasses) { - // override = "\x10 on\x11"; - //} else { - // override = "\x10off\x11"; - //} + if(override_mapclasses) { + override = "\x10 on\x11"; + } else { + override = "\x10off\x11"; + } + //sprint(self, PRINT_HIGH, "Override: ", override, " float: ",ftos(override_mapclasses),"\n"); if (self.current_menu_page == 1) { - //s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings ", override, "\n"); - s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings \n"); + s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings ", override, "\n"); + //s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings \n"); //s_menu1 = strcat(s_menu1, Q"\s[2]\s Scout \n"); //s_menu1 = strcat(s_menu1, Q"\s[3]\s Sniper \n"); //s_menu1 = strcat(s_menu1, Q"\s[4]\s Soldier \n"); @@ -1162,7 +1164,7 @@ void () Menu_Admin = // or maybe made understandable if (self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) { f_tmp = 0; f_tmp2 = 0; @@ -1381,8 +1383,11 @@ void (float inp) Menu_Admin_Input = self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 1; break; - case 5: // unused - return; + case 5: // force spectator + self.current_menu_type = ADMIN_MENU_TYPE_FORCESPEC; + self.current_menu_page = 1; + Menu_Admin(); + break; case 6: // ready status Broadcast_Players_NotReady(); Menu_Close(self); @@ -1409,9 +1414,10 @@ void (float inp) Menu_Admin_Input = } } } - else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN ) + else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) && inp >= 1 && inp <= 7) { // Kick / Ban Actions + bprint(PRINT_HIGH, "Getting player ", ftos(inp), "\n"); f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { @@ -1434,14 +1440,20 @@ void (float inp) Menu_Admin_Input = } } if (self.admin_use) { + bprint(PRINT_HIGH, "Player found: ", ftos(f_tmp), ", ", ftos(((self.current_menu_page - 1) * 7) + inp),", ", self.admin_use.classname , "\n"); if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { - self.admin_use.ip = infokey (self.admin_use, "ip"); - if (self.current_menu_type == ADMIN_MENU_TYPE_BAN) { - localcmd("addip "); - localcmd(self.admin_use.ip); - localcmd("\n"); + if(self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) { + Admin_ForceSpectator(); + Menu_Close(self); + } else { + self.admin_use.ip = infokey (self.admin_use, "ip"); + if (self.current_menu_type == ADMIN_MENU_TYPE_BAN) { + localcmd("addip "); + localcmd(self.admin_use.ip); + localcmd("\n"); + } + Admin_DoKick(); } - Admin_DoKick(); } } } @@ -1580,7 +1592,7 @@ void (float inp) Menu_Admin_Input = { case 1: override_mapclasses = !override_mapclasses; - localcmd("localinfo omc "); + localcmd("serverinfo omc "); localcmd(ftos(override_mapclasses)); localcmd("\n"); bprint(PRINT_HIGH, self.netname, " has set server class overrides to ", ftos(override_mapclasses), "\n"); From eb879a0783c9f8562ff15ccbd3d32bc1fd2340d8 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 31 May 2019 20:43:21 +1200 Subject: [PATCH 0681/2474] Force spectator menu only shows non-spectators --- menu.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/menu.qc b/menu.qc index 686df117..16c13eeb 100644 --- a/menu.qc +++ b/menu.qc @@ -1132,7 +1132,6 @@ void () Menu_Admin = } else { override = "\x10off\x11"; } - //sprint(self, PRINT_HIGH, "Override: ", override, " float: ",ftos(override_mapclasses),"\n"); if (self.current_menu_page == 1) { s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings ", override, "\n"); //s_menu1 = strcat(s_menu1, Q"\s[1]\s Override Map Settings \n"); @@ -1198,7 +1197,7 @@ void () Menu_Admin = te = find (te, classname, "player"); } - if (self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMONE && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMTWO && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT ) { + if (self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMONE && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINTEAMTWO && self.current_menu_type != ADMIN_MENU_TYPE_CAPTAINSELECT && self.current_menu_type != ADMIN_MENU_TYPE_FORCESPEC ) { te = find (world, classname, "observer"); while (te != world) { if ( (f_tmp <= (self.current_menu_page * 7) ) && (f_tmp > (self.current_menu_page - 1) * 7) && te.netname != "") { From 81b37b928617eef0b33b4fe88217ba5831df0099 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 31 May 2019 21:01:11 +1200 Subject: [PATCH 0682/2474] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 404a385b..fe7011a2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Server option for overriding map class restrictions (except civilian). `serverinfo override_mapclasses 1` or `serverinfo omc 1`. * Option for statusbar flaginfo. `setinfo sbflaginfo 1` (default). Setting it to `2` will skip the tf tips on respawn and show flag info all the time. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. From 9ff3b7c83fb7c74572b8eb7907e6afdd04956ec7 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 31 May 2019 22:02:11 +1200 Subject: [PATCH 0683/2474] Instant reload on cap and optionally on any tfgoal restock --- README.md | 1 + client.qc | 5 ++++ qw.qc | 1 + tfort.qc | 1 + tfortmap.qc | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 77 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 404a385b..f720482a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Option to fully restock player's clip and finish reload immediately if in progress. `localinfo stock_reload 1` (`localinfo srd 1`) will trigger only on flag capture (with stock_on_cap enabled). `2` will trigger whenever any tfgoal gives you the appropriate ammo. * Option for statusbar flaginfo. `setinfo sbflaginfo 1` (default). Setting it to `2` will skip the tf tips on respawn and show flag info all the time. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. diff --git a/client.qc b/client.qc index 84e2944d..1154328f 100644 --- a/client.qc +++ b/client.qc @@ -482,6 +482,9 @@ void () DecodeLevelParms = { // stock on cap [on] stock_on_cap = CF_GetSetting("soc", "stock_on_cap", "on"); + // stock clip to full for reloading guns [on] + stock_reload = CF_GetSetting("srd", "stock_reload", "on"); + // display class tips [on] classtips = CF_GetSetting("ct", "classtips", "on"); @@ -586,6 +589,7 @@ void () DecodeLevelParms = { spawnfull = TRUE; stockfull = TRUE; stock_on_cap = TRUE; + stock_reload = TRUE; classtips = TRUE; sniperpower = TRUE; sniperreloadpercent = TRUE; @@ -637,6 +641,7 @@ void () DecodeLevelParms = { spawnfull = FALSE; stockfull = FALSE; stock_on_cap = FALSE; + stock_reload = FALSE; classtips = FALSE; sniperpower = FALSE; sniperreloadpercent = FALSE; diff --git a/qw.qc b/qw.qc index 59ae9653..a6b22e63 100644 --- a/qw.qc +++ b/qw.qc @@ -498,6 +498,7 @@ float sniperreload; float spawnfull; float stockfull; float stock_on_cap; +float stock_reload; float classtips; float cussgrentime; float medicnocuss; diff --git a/tfort.qc b/tfort.qc index 81b8a044..bea85378 100644 --- a/tfort.qc +++ b/tfort.qc @@ -585,6 +585,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Spawn with full health/armor", spawnfull, "", 1); CF_PrintSetting("Stock players with full health/armor", stockfull, "", 1); CF_PrintSetting("Stock player on cap", stock_on_cap, "", 1); + CF_PrintSetting("Stock reloadable clip", stock_reload, "", 1); CF_PrintSetting("Old dropflag behaviour", old_dropflag, "", 1); CF_PrintSetting("Remember weapon", remember_weapon, "", 1); CF_PrintSetting("Pick up discarded ammo", discammo_pickup, "", 1); diff --git a/tfortmap.qc b/tfortmap.qc index 1c0849e4..89162d3b 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -818,12 +818,71 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.ammo_cells = Player.ammo_cells + Goal.ammo_cells; Player.ammo_medikit = Player.ammo_medikit + Goal.ammo_medikit; Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack; + //refill the clip if stock_reload is 2 + if (stock_reload == 2) { + if(Goal.ammo_shells) { + if(Player.current_weapon == WEAP_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); + if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); + if(Player.current_weapon == WEAP_SNIPER_RIFLE) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); + } + if(Goal.ammo_rockets) { + if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); + if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); + } + } else { + //for use in map entities without specifically enabling the general override + if(Goal.reload_shotgun) { + if(Player.current_weapon == WEAP_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); + } + if(Goal.reload_super_shotgun) { + if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); + } + if(Goal.reload_sniper_rifle) { + if(Player.current_weapon == WEAP_SNIPER_RIFLE) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); + } + if(Goal.reload_grenade_launcher) { + if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); + } + if(Goal.reload_rocket_launcher) { + if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); + } + } Player.no_grenades_1 = Player.no_grenades_1 + Goal.no_grenades_1; Player.no_grenades_2 = Player.no_grenades_2 + Goal.no_grenades_2; - if (Player.no_grenades_1 > Player.max_grenades_1) { + if (Player.no_grenades_1 > Player.max_grenades_1) { Player.no_grenades_1 = Player.max_grenades_1; } if (Player.no_grenades_2 > Player.max_grenades_2) { @@ -970,6 +1029,15 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { te = find(Player, netname, "flashtimer"); dremove(te); } + //Refill the clip while restocking + if (stock_reload) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + Player.reload_shotgun = 0; + Player.reload_super_shotgun = 0; + Player.reload_grenade_launcher = 0; + Player.reload_rocket_launcher = 0; + Player.reload_sniper_rifle = 0; + } } } } From 65834740635fe72d0804d184fa64a24bd291f99d Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 3 Jun 2019 23:19:16 +1200 Subject: [PATCH 0684/2474] localinfo grenade limits --- client.qc | 58 +++++++++++++++++++++++++ qw.qc | 18 ++++++++ tfort.qc | 128 +++++++++++++++++++++++++++++++----------------------- 3 files changed, 150 insertions(+), 54 deletions(-) diff --git a/client.qc b/client.qc index 84e2944d..eabd208b 100644 --- a/client.qc +++ b/client.qc @@ -544,6 +544,28 @@ void () DecodeLevelParms = { // enable flag model following the player who has it flag_follow = CF_GetSetting("flagfollow", "flag_follow", "on"); + // Maximum number of primary grenades per class + max_gren1_scout = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); + max_gren1_sniper = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); + max_gren1_soldier = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); + max_gren1_demoman = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); + max_gren1_medic = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); + max_gren1_hwguy = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); + max_gren1_pyro = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); + max_gren1_spy = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); + max_gren1_engineer = CF_GetSetting("mg2_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); + + // Maximum number of secondary grenades per class + max_gren2_scout = CF_GetSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); + max_gren2_sniper = CF_GetSetting("mg2_2", "max_gren2_sniper", ftos(PC_SNIPER_GRENADE_MAX_2)); + max_gren2_soldier = CF_GetSetting("mg2_3", "max_gren2_soldier", ftos(PC_SOLDIER_GRENADE_MAX_2)); + max_gren2_demoman = CF_GetSetting("mg2_4", "max_gren2_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_2)); + max_gren2_medic = CF_GetSetting("mg2_5", "max_gren2_medic", ftos(PC_MEDIC_GRENADE_MAX_2)); + max_gren2_hwguy = CF_GetSetting("mg2_6", "max_gren2_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_2)); + max_gren2_pyro = CF_GetSetting("mg2_7", "max_gren2_pyro", ftos(PC_PYRO_GRENADE_MAX_2)); + max_gren2_spy = CF_GetSetting("mg2_8", "max_gren2_spy", ftos(PC_SPY_GRENADE_MAX_2)); + max_gren2_engineer = CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(PC_ENGINEER_GRENADE_MAX_2)); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; @@ -594,6 +616,24 @@ void () DecodeLevelParms = { ng_velocity = 1500; old_ng_rof = FALSE; pyro_type = 1; + max_gren1_scout = PC_SCOUT_GRENADE_MAX_1; + max_gren1_sniper = PC_SNIPER_GRENADE_MAX_1; + max_gren1_soldier = PC_SOLDIER_GRENADE_MAX_1; + max_gren1_demoman = PC_DEMOMAN_GRENADE_MAX_1; + max_gren1_medic = PC_MEDIC_GRENADE_MAX_1; + max_gren1_hwguy = PC_HVYWEAP_GRENADE_MAX_1; + max_gren1_pyro = PC_PYRO_GRENADE_MAX_1; + max_gren1_spy = PC_SPY_GRENADE_MAX_1; + max_gren1_engineer = PC_ENGINEER_GRENADE_MAX_1; + max_gren2_scout = PC_SCOUT_GRENADE_MAX_2; + max_gren2_sniper = PC_SNIPER_GRENADE_MAX_2; + max_gren2_soldier = PC_SOLDIER_GRENADE_MAX_2; + max_gren2_demoman = PC_DEMOMAN_GRENADE_MAX_2; + max_gren2_medic = PC_MEDIC_GRENADE_MAX_2; + max_gren2_hwguy = PC_HVYWEAP_GRENADE_MAX_2; + max_gren2_pyro = PC_PYRO_GRENADE_MAX_2; + max_gren2_spy = PC_SPY_GRENADE_MAX_2; + max_gren2_engineer = PC_ENGINEER_GRENADE_MAX_2; } st = infokey(world, "faithful"); @@ -645,6 +685,24 @@ void () DecodeLevelParms = { ng_velocity = 1000; old_ng_rof = TRUE; pyro_type = 0; + max_gren1_scout = 4; + max_gren1_sniper = 4; + max_gren1_soldier = 4; + max_gren1_demoman = 4; + max_gren1_medic = 4; + max_gren1_hwguy = 4; + max_gren1_pyro = 4; + max_gren1_spy = 4; + max_gren1_engineer = 4; + max_gren2_scout = 3; + max_gren2_sniper = 4; + max_gren2_soldier = 3; + max_gren2_demoman = 4; + max_gren2_medic = 3; + max_gren2_hwguy = 4; + max_gren2_pyro = 4; + max_gren2_spy = 4; + max_gren2_engineer = 4; } } diff --git a/qw.qc b/qw.qc index 59ae9653..835985ea 100644 --- a/qw.qc +++ b/qw.qc @@ -468,6 +468,24 @@ float drop_grenades; float drop_grenpack; float drop_gren1; float drop_gren2; +float max_gren1_scout; +float max_gren1_sniper; +float max_gren1_soldier; +float max_gren1_demoman; +float max_gren1_medic; +float max_gren1_hwguy; +float max_gren1_pyro; +float max_gren1_spy; +float max_gren1_engineer; +float max_gren2_scout; +float max_gren2_sniper; +float max_gren2_soldier; +float max_gren2_demoman; +float max_gren2_medic; +float max_gren2_hwguy; +float max_gren2_pyro; +float max_gren2_spy; +float max_gren2_engineer; float grentimers; float id_extended; float remember_weapon; diff --git a/tfort.qc b/tfort.qc index 81b8a044..2de8b6b8 100644 --- a/tfort.qc +++ b/tfort.qc @@ -600,6 +600,26 @@ void () TeamFortress_ShowTF = { } CF_PrintSetting("Grenade timers", grentimers, "", 1); + CF_PrintSetting("Scout max grenades type 1 (caltrops)", max_gren1_scout, "", PC_SCOUT_GRENADE_MAX_1); + CF_PrintSetting("Sniper max grenades type 1 (normal)", max_gren1_sniper, "", PC_SNIPER_GRENADE_MAX_1); + CF_PrintSetting("Soldier max grenades type 1 (normal)", max_gren1_soldier, "", PC_SOLDIER_GRENADE_MAX_1); + CF_PrintSetting("Demoman max grenades type 1 (normal)", max_gren1_demoman, "", PC_DEMOMAN_GRENADE_MAX_1); + CF_PrintSetting("Medic max grenades type 1 (normal)", max_gren1_medic, "", PC_MEDIC_GRENADE_MAX_1); + CF_PrintSetting("Heavy Weapons max grenades type 1 (normal)", max_gren1_hwguy, "", PC_HVYWEAP_GRENADE_MAX_1); + CF_PrintSetting("Pyro max grenades type 1 (normal)", max_gren1_pyro, "", PC_PYRO_GRENADE_MAX_1); + CF_PrintSetting("Spy max grenades type 1 (normal)", max_gren1_spy, "", PC_SPY_GRENADE_MAX_1); + CF_PrintSetting("Engineer max grenades type 1 (normal)", max_gren1_engineer, "", PC_ENGINEER_GRENADE_MAX_1); + + CF_PrintSetting("Scout max grenades type 2 (concussion)", max_gren2_scout, "", PC_SCOUT_GRENADE_MAX_2); + CF_PrintSetting("Sniper max grenades type 2 (flare)", max_gren2_sniper, "", PC_SNIPER_GRENADE_MAX_2); + CF_PrintSetting("Soldier max grenades type 2 (nail/shock)", max_gren2_soldier, "", PC_SOLDIER_GRENADE_MAX_2); + CF_PrintSetting("Demoman max grenades type 2 (mirv)", max_gren2_demoman, "", PC_DEMOMAN_GRENADE_MAX_2); + CF_PrintSetting("Medic max grenades type 2 (concussion)", max_gren2_medic, "", PC_MEDIC_GRENADE_MAX_2); + CF_PrintSetting("Heavy Weapons max grenades type 2 (mirv)", max_gren2_hwguy, "", PC_HVYWEAP_GRENADE_MAX_2); + CF_PrintSetting("Pyro max grenades type 2 (napalm)", max_gren2_pyro, "", PC_PYRO_GRENADE_MAX_2); + CF_PrintSetting("Spy max grenades type 2 (gas)", max_gren2_spy, "", PC_SPY_GRENADE_MAX_2); + CF_PrintSetting("Engineer max grenades type 2 (emp)", max_gren2_engineer, "", PC_ENGINEER_GRENADE_MAX_2); + sprint(self, PRINT_HIGH, "Concussion effect lasts "); sprint(self, PRINT_HIGH, ftos(cussgrentime)); sprint(self, PRINT_HIGH, " seconds"); @@ -1436,8 +1456,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.ammo_cells = PC_SCOUT_MAXAMMO_CELL; self.armortype = PC_SCOUT_MAXARMORTYPE; - self.no_grenades_1 = PC_SCOUT_GRENADE_MAX_1; - self.no_grenades_2 = PC_SCOUT_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_scout; + self.no_grenades_2 = max_gren2_scout; if (old_hp_armor) self.armorvalue = 50; else @@ -1448,8 +1468,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SCOUT_INITAMMO_SHOT; self.ammo_cells = PC_SCOUT_INITAMMO_CELL; self.armortype = PC_SCOUT_INITARMORTYPE; - self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1; - self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_SCOUT_GRENADE_INIT_1,max_gren1_scout); + self.no_grenades_2 = min(PC_SCOUT_GRENADE_INIT_2,max_gren2_scout); if (old_hp_armor) self.armorvalue = 25; @@ -1467,8 +1487,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL; self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL; - self.max_grenades_1 = PC_SCOUT_GRENADE_MAX_1; - self.max_grenades_2 = PC_SCOUT_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_scout; + self.max_grenades_2 = max_gren2_scout; if (old_grens == 1) self.tp_grenades_1 = GR_TYPE_FLASH; @@ -1503,8 +1523,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.ammo_cells = PC_SNIPER_MAXAMMO_CELL; self.armortype = PC_SNIPER_MAXARMORTYPE; - self.no_grenades_1 = PC_SNIPER_GRENADE_MAX_1; - self.no_grenades_2 = PC_SNIPER_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_sniper; + self.no_grenades_2 = max_gren2_sniper; if (old_hp_armor) self.armorvalue = 50; else @@ -1515,8 +1535,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SNIPER_INITAMMO_SHOT; self.ammo_cells = PC_SNIPER_INITAMMO_CELL; self.armortype = PC_SNIPER_INITARMORTYPE; - self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1; - self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_SNIPER_GRENADE_INIT_1,max_gren1_sniper); + self.no_grenades_2 = min(PC_SNIPER_GRENADE_INIT_2,max_gren2_sniper); if (old_hp_armor) self.armorvalue = 0; else @@ -1533,8 +1553,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL; self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL; - self.max_grenades_1 = PC_SNIPER_GRENADE_MAX_1; - self.max_grenades_2 = PC_SNIPER_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_sniper; + self.max_grenades_2 = max_gren2_sniper; self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2; @@ -1561,8 +1581,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.ammo_cells = PC_SOLDIER_MAXAMMO_CELL; self.armortype = PC_SOLDIER_MAXARMORTYPE; - self.no_grenades_1 = PC_SOLDIER_GRENADE_MAX_1; - self.no_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_soldier; + self.no_grenades_2 = max_gren2_soldier; if (old_hp_armor) self.armorvalue = 200; else @@ -1573,8 +1593,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT; self.ammo_cells = PC_SOLDIER_INITAMMO_CELL; self.armortype = PC_SOLDIER_INITARMORTYPE; - self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1; - self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_SOLDIER_GRENADE_INIT_1,max_gren1_soldier); + self.no_grenades_2 = min(PC_SOLDIER_GRENADE_INIT_2,max_gren2_soldier); if (old_hp_armor) self.armorvalue = 100; else @@ -1591,8 +1611,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL; self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL; - self.max_grenades_1 = PC_SOLDIER_GRENADE_MAX_1; - self.max_grenades_2 = PC_SOLDIER_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_soldier; + self.max_grenades_2 = max_gren2_soldier; self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2; @@ -1620,8 +1640,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_MAXAMMO_CELL; self.armortype = PC_DEMOMAN_MAXARMORTYPE; - self.no_grenades_1 = PC_DEMOMAN_GRENADE_MAX_1; - self.no_grenades_2 = PC_DEMOMAN_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_demoman; + self.no_grenades_2 = max_gren2_demoman; if (old_hp_armor) self.armorvalue = 120; else @@ -1632,8 +1652,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL; self.armortype = PC_DEMOMAN_INITARMORTYPE; - self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1; - self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_DEMOMAN_GRENADE_INIT_1,max_gren1_demoman); + self.no_grenades_2 = min(PC_DEMOMAN_GRENADE_INIT_2,max_gren2_demoman); if (old_hp_armor) self.armorvalue = 50; else @@ -1650,8 +1670,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL; - self.max_grenades_1 = PC_DEMOMAN_GRENADE_MAX_1; - self.max_grenades_2 = PC_DEMOMAN_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_demoman; + self.max_grenades_2 = max_gren2_demoman; self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1; self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2; @@ -1680,8 +1700,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.ammo_cells = PC_MEDIC_MAXAMMO_CELL; self.armortype = PC_MEDIC_MAXARMORTYPE; - self.no_grenades_1 = PC_MEDIC_GRENADE_MAX_1; - self.no_grenades_2 = PC_MEDIC_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_medic; + self.no_grenades_2 = max_gren2_medic; if (old_hp_armor) self.armorvalue = 100; else @@ -1692,8 +1712,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_MEDIC_INITAMMO_SHOT; self.ammo_cells = PC_MEDIC_INITAMMO_CELL; self.armortype = PC_MEDIC_INITARMORTYPE; - self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1; - self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_MEDIC_GRENADE_INIT_1,max_gren1_medic); + self.no_grenades_2 = min(PC_MEDIC_GRENADE_INIT_2,max_gren2_medic); if (old_hp_armor) self.armorvalue = 50; else @@ -1710,8 +1730,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL; self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL; - self.max_grenades_1 = PC_MEDIC_GRENADE_MAX_1; - self.max_grenades_2 = PC_MEDIC_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_medic; + self.max_grenades_2 = max_gren2_medic; self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1; self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2; @@ -1759,8 +1779,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_MAXAMMO_CELL; self.armortype = PC_HVYWEAP_MAXARMORTYPE; - self.no_grenades_1 = PC_HVYWEAP_GRENADE_MAX_1; - self.no_grenades_2 = PC_HVYWEAP_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_hwguy; + self.no_grenades_2 = max_gren2_hwguy; if (old_hp_armor) self.armorvalue = 300; @@ -1772,8 +1792,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL; self.armortype = PC_HVYWEAP_INITARMORTYPE; - self.no_grenades_1 = PC_HVYWEAP_GRENADE_INIT_1; - self.no_grenades_2 = PC_HVYWEAP_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_HVYWEAP_GRENADE_INIT_1,max_gren1_hwguy); + self.no_grenades_2 = min(PC_HVYWEAP_GRENADE_INIT_2,max_gren2_hwguy); if (old_hp_armor) self.armorvalue = 150; @@ -1791,8 +1811,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.maxammo_cells = PC_HVYWEAP_MAXAMMO_CELL; - self.max_grenades_1 = PC_HVYWEAP_GRENADE_MAX_1; - self.max_grenades_2 = PC_HVYWEAP_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_hwguy; + self.max_grenades_2 = max_gren2_hwguy; self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1; self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2; @@ -1820,8 +1840,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_PYRO_MAXAMMO_SHOT; self.ammo_cells = PC_PYRO_MAXAMMO_CELL; self.armortype = PC_PYRO_MAXARMORTYPE; - self.no_grenades_1 = PC_PYRO_GRENADE_MAX_1; - self.no_grenades_2 = PC_PYRO_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_pyro; + self.no_grenades_2 = max_gren2_pyro; if (old_hp_armor) self.armorvalue = 150; else @@ -1832,8 +1852,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_PYRO_INITAMMO_SHOT; self.ammo_cells = PC_PYRO_INITAMMO_CELL; self.armortype = PC_PYRO_INITARMORTYPE; - self.no_grenades_1 = PC_PYRO_GRENADE_INIT_1; - self.no_grenades_2 = PC_PYRO_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_PYRO_GRENADE_INIT_1,max_gren1_pyro); + self.no_grenades_2 = min(PC_PYRO_GRENADE_INIT_2,max_gren2_pyro); if (old_hp_armor) self.armorvalue = 50; else @@ -1850,8 +1870,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_PYRO_MAXAMMO_NAIL; self.maxammo_shells = PC_PYRO_MAXAMMO_SHOT; self.maxammo_cells = PC_PYRO_MAXAMMO_CELL; - self.max_grenades_1 = PC_PYRO_GRENADE_MAX_1; - self.max_grenades_2 = PC_PYRO_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_pyro; + self.max_grenades_2 = max_gren2_pyro; self.tp_grenades_1 = PC_PYRO_GRENADE_TYPE_1; self.tp_grenades_2 = PC_PYRO_GRENADE_TYPE_2; @@ -1936,8 +1956,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SPY_MAXAMMO_SHOT; self.ammo_cells = PC_SPY_MAXAMMO_CELL; self.armortype = PC_SPY_MAXARMORTYPE; - self.no_grenades_1 = PC_SPY_GRENADE_MAX_1; - self.no_grenades_2 = PC_SPY_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_spy; + self.no_grenades_2 = max_gren2_spy; if (old_hp_armor) self.armorvalue = 100; @@ -1949,8 +1969,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SPY_INITAMMO_SHOT; self.ammo_cells = PC_SPY_INITAMMO_CELL; self.armortype = PC_SPY_INITARMORTYPE; - self.no_grenades_1 = PC_SPY_GRENADE_INIT_1; - self.no_grenades_2 = PC_SPY_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_SPY_GRENADE_INIT_1,max_gren1_spy); + self.no_grenades_2 = min(PC_SPY_GRENADE_INIT_2,max_gren2_spy); if (old_hp_armor) self.armorvalue = 25; @@ -1968,8 +1988,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SPY_MAXAMMO_NAIL; self.maxammo_shells = PC_SPY_MAXAMMO_SHOT; self.maxammo_cells = PC_SPY_MAXAMMO_CELL; - self.max_grenades_1 = PC_SPY_GRENADE_MAX_1; - self.max_grenades_2 = PC_SPY_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_spy; + self.max_grenades_2 = max_gren2_spy; self.tp_grenades_1 = PC_SPY_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SPY_GRENADE_TYPE_2; @@ -2004,8 +2024,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.ammo_cells = PC_ENGINEER_MAXAMMO_CELL; self.armortype = PC_ENGINEER_MAXARMORTYPE; - self.no_grenades_1 = PC_ENGINEER_GRENADE_MAX_1; - self.no_grenades_2 = PC_ENGINEER_GRENADE_MAX_2; + self.no_grenades_1 = max_gren1_engineer; + self.no_grenades_2 = max_gren2_engineer; if (old_hp_armor) self.armorvalue = 50; @@ -2017,8 +2037,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_ENGINEER_INITAMMO_SHOT; self.ammo_cells = PC_ENGINEER_INITAMMO_CELL; self.armortype = PC_ENGINEER_INITARMORTYPE; - self.no_grenades_1 = PC_ENGINEER_GRENADE_INIT_1; - self.no_grenades_2 = PC_ENGINEER_GRENADE_INIT_2; + self.no_grenades_1 = min(PC_ENGINEER_GRENADE_INIT_1,max_gren1_engineer); + self.no_grenades_2 = min(PC_ENGINEER_GRENADE_INIT_2,max_gren2_engineer); if (old_hp_armor) self.armorvalue = 25; else @@ -2035,8 +2055,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_ENGINEER_MAXAMMO_NAIL; self.maxammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.maxammo_cells = PC_ENGINEER_MAXAMMO_CELL; - self.max_grenades_1 = PC_ENGINEER_GRENADE_MAX_1; - self.max_grenades_2 = PC_ENGINEER_GRENADE_MAX_2; + self.max_grenades_1 = max_gren1_engineer; + self.max_grenades_2 = max_gren2_engineer; self.tp_grenades_1 = PC_ENGINEER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_ENGINEER_GRENADE_TYPE_2; From eef219216f8adcbcbced1854d04db6787e61ad39 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 3 Jun 2019 23:27:06 +1200 Subject: [PATCH 0685/2474] add readme entry --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 404a385b..4c12575c 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Option for maximum grenades for all classes. `localinfo max_gren1_ `, short `localinfo mg1_ `. Works for gren1s and gren2s. Eg `localinfo max_gren1_scout 0` to remove caltrops or `localinfo mg2_9 2` to reduce max EMPs to 2. * Option for statusbar flaginfo. `setinfo sbflaginfo 1` (default). Setting it to `2` will skip the tf tips on respawn and show flag info all the time. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. From e11cef6761aabb986b2d2a870ae6727a6d1dad02 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 4 Jun 2019 08:18:30 +1200 Subject: [PATCH 0686/2474] Building engineers and feigning spies get a death message now --- combat.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/combat.qc b/combat.qc index cf00e88f..eca3f3c0 100644 --- a/combat.qc +++ b/combat.qc @@ -62,7 +62,9 @@ void (entity targ, entity attacker) Killed = { self.health = -99; if ((self.movetype == MOVETYPE_PUSH) || - (self.movetype == MOVETYPE_NONE)) { + //make sure unmovable players like those feigning/building are still given an obituary + //(self.movetype == MOVETYPE_NONE && !self.is_building && !self.is_detpacking && !self.is_feigning)) { + (self.movetype == MOVETYPE_NONE && self.classname != "player")) { self.th_die(); self = oself; From 6c84e60dc2c2016f351ee788f09f0e82d1f0c73c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 10 Jun 2019 12:49:22 +1000 Subject: [PATCH 0687/2474] Bump to 0.2.0 --- README.md | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9b595c09..198a2ad0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -FortressOne Server v0.1.0 +FortressOne Server ========================== New features diff --git a/VERSION b/VERSION index 6e8bf73a..0ea3a944 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0 +0.2.0 From 469c026e9c1cf7e6174e4027c5a351d4bf75228d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 10 Jun 2019 12:53:50 +1000 Subject: [PATCH 0688/2474] remove vscode files --- .../ipch/584dfeeb401f2c0e/mmap_address.bin | Bin 8 -> 0 bytes .../ipch/897cd993fbad31b3/mmap_address.bin | Bin 8 -> 0 bytes .../ipch/c9e38738931be063/mmap_address.bin | Bin 8 -> 0 bytes .../ipch/df4dc764295579bf/mmap_address.bin | Bin 8 -> 0 bytes .vscode/ipch/df4dc764295579bf/qw.ipch | Bin 1761280 -> 0 bytes .../ipch/e1f2daf2731f2897/mmap_address.bin | Bin 8 -> 0 bytes .../ipch/f2dd25b4d0adb0f2/mmap_address.bin | Bin 8 -> 0 bytes .../ipch/f83e8003c6e46fce/mmap_address.bin | Bin 8 -> 0 bytes 8 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .vscode/ipch/584dfeeb401f2c0e/mmap_address.bin delete mode 100644 .vscode/ipch/897cd993fbad31b3/mmap_address.bin delete mode 100644 .vscode/ipch/c9e38738931be063/mmap_address.bin delete mode 100644 .vscode/ipch/df4dc764295579bf/mmap_address.bin delete mode 100644 .vscode/ipch/df4dc764295579bf/qw.ipch delete mode 100644 .vscode/ipch/e1f2daf2731f2897/mmap_address.bin delete mode 100644 .vscode/ipch/f2dd25b4d0adb0f2/mmap_address.bin delete mode 100644 .vscode/ipch/f83e8003c6e46fce/mmap_address.bin diff --git a/.vscode/ipch/584dfeeb401f2c0e/mmap_address.bin b/.vscode/ipch/584dfeeb401f2c0e/mmap_address.bin deleted file mode 100644 index b624b49c3a0bfab82285b464ab68e06419e9870e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmZQzU|6%Mo`C@X2dM$x diff --git a/.vscode/ipch/897cd993fbad31b3/mmap_address.bin b/.vscode/ipch/897cd993fbad31b3/mmap_address.bin deleted file mode 100644 index 8527a932d0a470d882fd399691391d4292aa2410..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmZQzV8}76XJ7yT1bG1> diff --git a/.vscode/ipch/c9e38738931be063/mmap_address.bin b/.vscode/ipch/c9e38738931be063/mmap_address.bin deleted file mode 100644 index 025671824345318c297ead88330829f871c83248..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmZQzV7T(9j)4IH36=s+ diff --git a/.vscode/ipch/df4dc764295579bf/mmap_address.bin b/.vscode/ipch/df4dc764295579bf/mmap_address.bin deleted file mode 100644 index 8d2c064c2155bf4cfa5ce11a6f5456a3057cd46a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmZQzVA!Et&%gix1*rjB diff --git a/.vscode/ipch/df4dc764295579bf/qw.ipch b/.vscode/ipch/df4dc764295579bf/qw.ipch deleted file mode 100644 index e36d5fb55f665152e20ea5edee56f365a84c0c80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1761280 zcmeEP37lI+{okb=;WXTf2ZVwU#J1Txivrp1ZkvVeHgvZTP)JI#v#OrVH zz#tw`M5BL?sDCvcK)BZfjo=XlHKJfp!JsHnQQ`so-(=?ZUS=}$-n`^xcU#}`p_7^U zo!|NWelzdoB^euC>l#@#a{B46D`$4jZJXWU>R;(`xz}xaoy*nh>hW|Bxw?nW=ovi2 z(|y`O9i1H=9cL>4qrX*=*~@2EZP~PA$F@}~ubkUFyJcq8Ol;T84kTr6)#Y<5@ZieL z(de$(+3j;HJS%&8S9(@mx@||tiC6|DWCTf=o7t%tvf_%XqC00Vn_E@W_!5P<^Dx2@ z8XH|38d<+CFg`K1fs85B%BvdLaX_|lYAiH5HZn047#o=ity#YzG&MYNW;eyLTIqG} zLx#N6)QixRn+&bmJ-2h!_HCE0x@`02RWa{CXrOP!_H8?M$5vdnWB01TRoixK-oAUw zOrwA!DFL&aH*FWwuB2!Um95yiEjF{IQRVUVVu)c4HaD^z%3-6ZYUmzJhC-pK>Cur; zh{2Oy0ZeoL*oLX`^^*#%5=`CQJrj*mkD#S)oL&>^9^eb-koNXSk^0w9O^=Q8Nj10D zPHseQ4K^BixN2mLX5ILt5>lZvdmAZ_p(z8y(98{-ApL4-XNif-Gi;L0&mBMB%t8IVM`%@~mc#>e<1 z$Evoh8J`@V9t*7-p7w{@<;r`8$zqc1$64pqmZm! zJ2o{P8lD(mJGpMGwlF+15a#GF6k5MwbZkRtVtjg9@p5c(bbJ^U%k_Hchc@^@U1EV^yIu1*Q_>I*3=O{CJ%&P$Za_aAM11My+&+fR)wOcurT()Coi)-7CU4*L6SPh@R^oG&#HESqd zE{hh<7u3RnDC5$ivjqAJg)Tr@N=Wrh(xORWSvMR6u9`PoEhk|mik6KW7JY3RFLFlN ze2I;7k=dQQ48YT(81X8*v6O#ZsGwk;_Ie1LK+s3V#Vt zQ=LOghR1wnJH9z%v;UWevC)Un*tS^9Gn>EsFszo328u4jP%VY^~X^xuVVqE0H zN=JIlMA@{|_Q%?qa=g1$RnhTMuQuoyK zhSQW2Mcq&+R2wAuQdi31ghEsAQ0_PIq@Z!3DD9BDHW&;IuO1JP>#j4ql?&8H)!Lpg zRom&&W~`j+V}n~8Y3mM_e&rynk#6M>YlfgmuczIr{51-PdnTb!?L^KpASU$3xxm(f zO*_yF**W}Lu;9ZE%iCzH7A%Bg935!gE0iOU2BK?)s~c)#-CEaas|N;qw{`2rMr}?q zL=ITWwK-ZL4&livAsqBrS3nB~1+7}tE*F3kIH29gVLd|Ci(}}5@loXxk$Z@(BSj$u zl)UQ)?HUl_1eCpyD|L`+LTdp4qywDG3oRWjSDFIpLrs3R+Oj4W1h979ygp z^Mh}dc7ch=>l^`dbW0)PsdEK*pydUdwuA~V9ELS48gWza-lJ2uH-tmEkxUEvI=K)U z-bQ-Oah1LfER@lWJlg#ng-4+l*+K<}dT0k@c=eb*DAz76>ed44i-AQ7hY5=mYOsix zIoi2P#iwqi!6H~`PS8?SMPb!y5Qmt9n8E_~@#?n5fr5|?B>mMx9O6iNF@d@Ms;4eA zkjsq=p`9a;aGluDj$)eKbxRF^a?(yKP>54qY_x@Ns9(nMqHX~}545~grArC5ggkOO z1M$V4USezF(E?(6SaD9mY9~=3uUiy}c%%ytx#|Laya;PlShr41DXdF5IfZo#)|5hn z9MT}E#Uj0AyeNkwH%ScwA}lh*612P^;Yg@M6*!@llu!o~a6-$IK%L{z)hIY1fiYFp z5U*YY(Z{%YO<*3hJTtYDvUX%7G(I*G>hB-oy+5KYV;y1bjqZuDAdf-IyfqWkp|SIa zCqnDSrv2;Ddz_qiowSn0l21>Cy1fGf-JxDSr>01GKb=v;xz^A;Mv68JkB+13We%aX z3W#vsuu?xpm3zSoZC_())(#Me7}E_jl4<3uCQ~_@js*jXNcW2Fo_+}1x)ZIo0Rert zM`h_9G3LW z91RTgdi#64-u@wPclV&DuiM+(=k4q79vJHBpEX=g-{bA+ z>G2Nsdj^LFyo0?1{k?*M*$2-)oNb@Qy z<7xbxSuw~l@hnQ@=$P^*{JIdn-tSgC@9r7$_6_v)_Vjrbp9d8kijhP8-d;u5Q1?K0 z@63w6evVjeS4K$sho_WBM{1(E@4eDNhN#CUYj6FcH+(sFkhIhW>B@WSW7DBY{4QVP zLTE8Ix?0IXrfqTpB?n}4NoYuW^aAAJz5RnqqIkR$oGQSG#+Se#x@TpN64HZ8{&|%~dF-Xv z+v^$f^z`-&b`SO{!RhJq3@ACn7d=Kl^U&DXHvH9PoHO-oC+}f!^NU zfo^a2fFiwTW<~b^&+u_dI+Z}Gg1(hQiirM!zJ9Or-f-VQe_vnspwjmaDmgo#l!0y~ zs}%ct`gj`X7?95;v_@uf3Fr-SNi$~xM}fM{@J?^q=2fF6*~E!OEjh5*`gBq%FE5|8 zOA?hujd%BoJ|z@6fu_YgF<(t7MGI%2)HXDgUR9!~;B3R%eF-|Fcn=b2HKZopm_geD zRC8+e-#et_Sl>{;l4DBlDZ!s6jH^9(85)j*H(-=MO+3@Xn=4EFa7c$DJL7x_vxDQZ?~IoG{X$*dm5nn7hpQ8uf- zzTQ5MXHY25a}Fi0}ZB4vlGT?(jK#w+|UaMs{h$1>1q!#UW!LJb{FgPEfpFU=cd z*78RFc*m1ToyL@9uTLDwBOXtzwz*>Wsnn4_=J7;p)7&HxLvZr<# ztY#1Iz^A?Kqi9gb#YaBM79_YnefWnyZIi;n5lemkaF2Zys^mHzUw3tL4}KJ?gkDv` zJ^Ha6bPDkfe_Bl^j?~_^l|S{Z;T;begw~Qs{=CN(dUk!bD`;q0Bz@B3${k_kQfVZA z#^cInSKL${DL$IaBf?>jM^v3vuE*=IoVvR?mrmN-hDwYe2AoR098xMTYO?EdNpRxR z-ex26nQRiA`KVyWeyAG~|I|nAdcdJ(6#v{u6^EMh)cuCu0TMoS7gSWFf*Qej&f7nz z9ATMs6*yOdRU?a9cg6r$`DrZpTQmxmc z+?pF49O~;)u6u@hlw+fEjnl`M4EGR1A&8v%TM+{*`v&`!GiSGQlI!&=@}eQuBrOb@or#%FTNp?jqRW-pII_n7ci+YFT7nrZC%(6HMb8CI}?2IRDvP#rVbjH}>f_v}YZMQ0Kg1EQ-Eq*wE5SInVyJ%< z)~D{=rDZVKj&_Ejl|!|^v7rGTla`8@sV;!VR&Y7A_sTKH)W+2)GSC}~wV?K_ti4Sm zG?VhGc3Gz$4tS5tPzECMI*fb0Jsgl56#&S}ox{dO)J`jkKSV(dW#xYS=x8JTDP$;w z>PgN1dYCcT%D-dEjaMGKw&!DZ3h?fJ9t*r#1R4d1tM85}&O$g~tv zjIGhvp+C^w$Ah0r3ON4b>wJZSvjEfzgOb_`DD=IfoLie`)Gq<3&_Z2ZgT@zQipV~m z$OccTb?N1rp`AepIz|hlu8{gdSt^l}TCLbHwsu_kSn`HYV8hs&+WX{GH*_~gX+B>FHM1YBKl(Qd|0u2SouW$ zs8WBF3NaR(o*d?XN)6NyOWaSh zYmY_{+4v*1ifqoCp<3xA#LClK_~X3_y|=N{YF`GCc7&*mSZ#&C^f^XawqU$?Gy@1@ZZjbuvsf*G#e+UhGLf-fi0Xx0R$(8t+18?*Lc z4^mb8QVA}dwt?65i3v5OQ)6pGYo>TgX_~cM8cm_{^*5o~7vbt@@$_l=q$5XL z>D@cF#du;gvk`@nHDeQN_$1VUwf6Ac>hV$Z)ATQ9so6zh1$-toU^oEDL#`Gu!xqSDECeVh`c@_~;|0Pqr?}vgfp4t}O z99gwxYu}d5%FT7$@KSO`pcO9zD$2VroTVaKY-~wnEruG{~)G+Fw;MT=^x7U4`cc-VERs` ze>l@Wg6SX0^p9ftM>G9nnEtU$zkYSv^BM}KwDj0dFsQlz#cigDgCP71-0ruZ7B134 zZNddXVBZDNVk_C(5s--^8JeYr6SA3SH*ajI*}ga1vp3?ur~9<0+rKyGi|w0@K)Vsx zlk$I0vbEjoX3Mt`uo18kuo18ku=mBiD+ZP+?!f^W5>HSINDP73V4-pKJtd1Z)Is1Z)Hr9|836x9I=H zw{B@#VETdirRj!km5qRnfJp@GYci97+2mXVWa3DMhAVs#2a(M@yLn@aXy$*N>b(*F zJ>920-Twc&B(fd05wH+}Jt_b9BwH<9B3qP=fQ^8SfQ^8S02cv!U*y8F#}2}0C-&B7 zN?KhQJKkGG(B|Kh5U}HYPg*V8RvQ5u0UH4u0UH4u0UH4u0T~4L)@xn+>@KtVHjRyd zjew1Sjew1SjeuDMM4z3oKO-PU(#A%NjXh%{U?X57U?X57U?X57U?X57U?X57U?Z?} z5J=qvKhn2!Y--k$U?=<_qd5uXUGPJT`h4>@;UA22JPSVrsZU?nAKT+PusOT*rQ5U3 zB9Qap9|A3&13w7btR!=M5I>bG<>Jkpbeq~nz(&AEz(!!HBCu@PvcOgFo5@xhd4TdG z#pr*dzX##xyNw8y`P8TI4TlOZOBJI^5e7Ytx zvCqOD>RNRq@eID0K)*>3zf0e$OiTH%#)nlG$(!fv{$%tZav3_H0rAj>)~p=h6SbfR zT0~d>TEw@fjqhWj!LGL)kUQxb3k5E)DBoB2Z;So0e!M5jx|6+@Z%68L%P9Nevvglp zzEyONQ|0^${z1RyMvj#8BXOu49qV7@h=VBH*m+UE^n||Mz*pYysHWrtzw;$>IELSK zXiIuPU$bpF$+t8A3p(#pALYlds`mpgsQHn;g631_O}_BliShT}q_4O5OKbF%E~3{V zG04|jTHRc{irjaf&X42r?~kw~E_@F$ar{cYz92L1e2yO%B0pd}RlxWpkEQubtMNJ| zSJ30Yw^(iQ3-r2+?C_ngPnYlG#|y{{ys@=7&Ab$^o97Msc7Q%nn_5ZZ@BAQbS9%pa zFOmb}RYE`ih&jG_MlZ;dZ3FAg;gI{HHP@7`w_v^gx0=&0>z9bGdYn0YMRJVB-KQSY zRNcw`(ONwGoAG{PWG_4K{R3S$y%*}|CCe}B2QQ}c1n8>A;k>L`e9r>pL+d%1U$Nfa2jKA|We7)X}(KuVJf1%`s{mtc-bGICy_fGxzn;(~xlYNgMzdD=CS0j8QJy>7h zGQR!UIeuIi$&Fti=P$@9nxqH5#cG|Q1F8Dy{|nBO=wJ7&d?|b%=fC@d&DG(>!k^V! zaSQT>5IRq@_B_w(H|nQO(YMctUo;=wz~8U3f^m_YX2;!sF;^e5|2CH&g@4o6HRZq4 z{D~9!b*ou_%<@(5ru`4xL-%Fn<$BE3_l!VK+{@47xXWZcHlRpZqDw=N7_?27&rIWZf*eA_0%6R?nR~^xlhOI z7rdBWN0GyhPx13dM4w)!9}g^F>^3?M3QV7+x2o^H9qV-+rEhOEjB$z+daLvs$%&k$ zZ95r`G3**&g%D; z`8Y&>h3ioGEd6z>L~-5A-%7`0{0zQaR{wuXzj|$Z>umIF{=Q*^@BDT8ah(4oe_v~m z`zCAakL!Q2-t=GEi(7*qWT4<{4o{Hh+Jx;ddvSgy-%aNS&_P>`o6DErDKy?5!TX#b zzg=zdKm7XQ&zSSa$iB)bjD|5$PN8 zM+rSkm;QsC9c4*9Am4WvwzG1*oP6LDwf-;C_=)JO97u<>t8?2Ke0G<-YOi8}RS%^yI=hwCkve*QJ| zxybd?_SV~I4##8kHaae&x6^$V*61Dj^DMonU!J9L5Ya8w@vcv{*Z$;%be@-)K8s7` zBAT9^H|m$xwZ<=!@4p($otJz*TqMW)di}hL-izbXcRkiuAuY)BzmM;q?;yOdMh?bp z@(|qS4sC9~^*RjB(XZs&QC`8Xn_&N*)>iJI>zUC0Q~2-q7jKZmKlN=nI#z$>=LYM< zGPJ3m`0L)a?pDK;dV?VEf6QM$PgX$B7#6;{xwv7(Sk_Jbj;;&gceZzbvCMEuLCzES zc`nJ`QC_XTUYVcb`tSZbZo4+p_?3bAR}BnGyqB&w2IPj*sdre5Z+w`x&-qXO`zK&n zka=G%@Og|=?!~kmpkM6Pxtm^Bu&4BLbM|^oe!k4n-&`H`#P#bh*uP-yi%iy)h&fza z^&?0=FA(_wf1O*EZ^S>pSb86z<0N>!xw=pqHAi1&p3?$cBBADR?;_9rfttU_b#seMmVI` z%h{K@R4z}0SJC$|eJA04+_#d>&-`wz*KuKUahQoV$7h5G%zIuXhYQd*+xphgxCYJc za{|S=p4Q@)72EYgdi~gWtNO*0Y22d=q}M9@Q}@&BDUw^clOMm~Tln`mL~<5-yfRA1 zLF@+XZ)}oYH|HqbUuZjJ_4%J)nCCvC+wpq4-%8^rYv*FoIbJQdzq_BO>;7Wd%j$I> zD`!8;C);;8ah!V&$8GS4r5*RdIr_d%`mY$D*j3G4FI8sfeI|GTzpjb!^gnJbUg=fX z9?u=LT?wWyvPU$YoR!0;MD!GImBS%Lo(~l1jUPn&A)>QtJk{iV$WljZb~>l&xQtH9 z)sx6st<_V{;rRYY`B*F`)kVvzkiP#c{(ThxaWuVE>#(QENp7LnkG0=*c6;kEtIzWO zb8_c8S-tLk+KWfT!;e>4`&hcJf63){ILWW)`N8J!t29}Uz<&3zep~__+d5xO+goYz z^MHl7(YW}&t-t=>!}aH@WS}8s zk}Deb-n%f@6W&7%*1?72H~u)EE_Vx!hx1mtA9$hMc}IkUXgosnRBn?yAI&p%iR4!P zWbV2-6>ZMH$_M#zSb4lTdEig{^w#)6j#2CWGCv-S_&WS_Jp}qHIsZgFbbW()Xp2N| zpD*D77` zMR>iF_v1QR9H-AQT~E<<%1B@FARHfwgXuUaF@08!_Yj(%owurAHu-+8kNJK}ksaBC zaXl;_Vy-TV6Ti=#{Vad0{n#Xq@7!<9#dWKCqhGcrE>Z@c zYmA?+{~U*`AE_g8+~kkKZT0Bp;>d9gfB!2B&QrnTzLsJ>4`P*GBRM`&NAp!{*A4V~U!yPA`*rsYCJp;n;=GsTI-(Ic)3cuqF;8A2b(dp3VGy&hraC zuAb-k z+h$+Mzg_~md6RJie4^Ij*ViZFTd48id--)IcL^VNtL*Z8n!m3X_iZl!124q(Cf3Q> z9VYe2Du29_`g+3)90&Q&%H^F||I5qqK3cg;PQLFXdf&~ykH79_?Ew0?;P;qdUeqRk zz^~s)gMAI;6(#k$3;cZr-|@~?9D z3!H-I_k2&ATZfc@zMQ1@6X&n=&r8|v_QdP_ORzs#Cv6Yl*RHnfcyl-!*-;GYW%k}x(6Z-SjNAP`x+#R@$8_=_M8})N7J|~tC ze9xIkZ*G^h`%q5ud&Kgm^3SOvJ6jzOzlFb#v?^DYKlA9~?hmqdE;L<=eE)m(CTr@g zw`#7AWju32= zkLb^{^j7twck$0Hr7!Wv&FW1V)P?+!`t>bn_IvjX-d_d#QytX=b>4-Hhp^$h%nE)CO*(yeJJLb>z($REiFCr+vd&*PQh~{ z5y3cXQ0#m;y}=<|UkZ}+te$53;S;T0ufQj8-1wiMudBjq=<|*L?+bH(A#GAm)g-;^ zF@5~9Yx#cWLyL1BfH?6#E2rQ2E*!s!<+Pt&@8-vKVLLwGMajJ9S-$^Zhx_vOoCiU^ z*UPsP=Am_7Psb~a8@2J@(tKI+c|0RNqj{$r+np-YxU+nj-!@mLV>i&}nOJ{&*MYUW z-TmsX_2bS+zxOkk-+!Dw{(+J?JsFeqMs~9E(GSbzHOmM6+!6S^mfOY8o301&c#-^G zdWVOOBakE8rf;Y3N6YfHi*Ei1x%I4)=SF-pCa<>{!=2Ayyt|I%>vaphkAM-g;N9X^ z={R%l*IXSkGCX|-AD60N+(=%t^YbrhZJmwuc6|%yk?TD;zY3%UKKFI}e1!Qp%sV;&vie%3b9{gwH>}*uz8H_NBt6T&Q2ppR z=GLuCa-B;*P9#@z(BhzW>nmD^lg#X*K@kykLKMzg#@Y+LKvhEnXtM z;k3E9VdZ#7thF;Ncs?X27-#K)zT*zL_yqdJYNLH}_&dnw{8>ALzv25?S z<39Q!YxD$e!1%jT=H6G#RcZfO`;GdM*EF~8uKzPvp9|;GdfXFqzxXKjyEKH?)w7PC z&-_h)9aulRPUF)%K0uG>j==GjdXZe-vU*ZJb2za4&@Yc*yE1>p^*&ai*EN1GjR){S zTVj4cC4aDf9L4r+&R@{Sw&e?Hd%J!im&dG}cK0)P%dJ<^L*MtSo@vebKJ}uy_ht2E-)D`#vifA{98>(d9Ttqs$~8+@cx7vGRro(TPR;5U z(O1WCy@|dM*NO6l`t=9oBo1nC-dFyIZ%174dn(RP;5;dW6O;`JA~t z&fFlEhm|Rle!v1UZK~3oe;&d2s>ZLt^19A8=Qm?k)7|-yK7PK7XuGP+`vC4!`Ee9J zoFA7WLtO{b>r;Idtyjcn^?2|IYwAbp%QP;Dt>)q;`VN{t%=~_9exv@niEt_2M&m4^ zbAHp@`Z=zl{RO#>etJB6E8P!%i@)Cjzo^YTPOp=HE5;-CC%O9r#c^y$(Bj`i_5Xvm zOJx629S^MGuY2j`Wc*XjtyjDKjcv#4pJqOv*R0;+|Ka@eyqAv$$n}os*QwNt=y(S{ zt6Den`_NX&ZB>rrVRL?G-l&grgFPlcUl4qheqK3yvHrR>=o1X&dd%f}*x>uHBEQ9U zMx6NEm^_?+e#~|A^+wOO_BvMJwmKYm0NYpDM;}l3^>X`;D!5HAyq(SMn_y1i1MR7Q z<-hXR6Z9tjWv$-SdVPJM*QlL8%N(9vXJh*L|KZ2O{8_jT1ekh|ywhZTFfhEh1J|ca zn|{v))VrAbu`mv8;VSHx<0&~DUEBHB=^zhUcT5hiz%u?ifSe`M?x$a0SUW2>>hC}P z1bx0{`IlNhejUAkwQ67W0RFnCK1<_VChwoMs&A?AM=JcfS9+Si&ziM6^%xyj!8y4+ zWc8#*`Sqasj^^aC@=Hfr<1Z_>*?#g$8aEd?&o?X2Dn3_PAE&I~Igll1L z?&tnQ=NZ_WCG*g4wsriR#1<~+wHXId%E3klC#eUhlt?$ka@wlNM7l6e1Aps?07};_tb#TzlzR- zGIO0>BKOhCH)6WfM``*B(+9cG`fsA?y|0(M4g!9&ZF)aCj?y2-bvxWi=Yv_fR?&yA zX|MlQ*$Hw2@3kgBK%Ut)u#R3&v;4&^wEgaVn%l>#H_~#<+F?Xr_;z#G2c^!|>P6z` zd&zm>S{gsccx$+@>*fA7#wqN`Gx<0pJsd*eu?-+6%k^^l0qXgu|2>`(e- zIIm)<=I}AnBRikFn$GX&H?56>)I;?8bsfp~H`hbkVPt>#;pWbHAUFEc=JGgoXlr^w zKilS?rg578GuD%NlQq{tN#;48{Qem4$^qtZXYGc*|0X(a(#-GT0bSr@_PNJEke4(#A0@{1@yl=IpD$eJ^T$DN(cr$b|M}+Xhv#+t`~bbsdOv{U zCD-ElDD2nA2lUCd;RBoVTULJQB7PjO{Jsxc>lZ8E>b}$H^Vpqo{$!4$^U7*FGrz+4 z2b}aels`z9IypNm|e?|*8B*4L`vv0QWegRI_QlEzP#PefP#gSGy%dQyL2 z)|Vw{u^+s@J^QMWSq@##vh&UMy?<&g zenD?~KWpTGJZQ6(_Q(bKW?Q$5UcdNX>AqQcEWOu7`&(T_=RHgR-`3BbgYz_dGhH7X zx6pkSm*|_V!7Vc8|H1ocx5xv#(WpW=fSFm;; z2Rkzl(&r)=Un;FLj@Lc%YWm!e`77OL?ae#d6NjuG=oikQ>llnfTV9RdKXs1c);nhI z{nX$m?j%Bm-nvV$8ogD^HKWj*7Du=25ahYvBm2z zz;B`32&qR_>n*>8Uq9S$ZSH!4wJ-V`e*N%9a2+k>>3Q$Ne7$+W`>d=!=agLD`+tq~ zR8HdSW91e;Mcc{FFLXb7qrN@Glg-t6S^M3Wo6E!KQ*<3EKc;UtYsdWC_4iwrUexzK zN87>DMYr(tfTe4-Ki_NZbxf=F>@EDIs{T3Ezg2(z7aWKE%*BD{V*R{{ewW@~b3fIm zH|uYl**7BxVSUA~(fJuZu|0K%wKw^{v|h&(`s>f~8}(DarR5vZo1HKD==CzoANvcv zzS&%J_q#!FWSU>s=b7DmcN3ISREE{i3vbRw=RKJs}Q|K)VP%i0y*M&p)a`mCJ!*Uc^}e9u7ml$W#<8lgKv@9=Zx%*9HD9hV74CYyS ztNVexHP`d*7>-ZR>-6JPWWWDs{B^B7L+{V7tK{NSq=y|Ze_6k-2Hf<07WdKg`m*xc z)sKD>pIe;Ypz+AOKrXM%+T}3#oh$F_<<>cR&cfj3V7`CatiNXI9lOlo9={ypHNP*v zZqEM>pJ!6P!Ry-<v8Uh+K&i)}~s2l}|V9+In*&H54jBAuUkrmxD4 z(spJ(Z|?f3ayPy2xV}W|RrLs76u)eaULdCB;anQqk$We9UGf|B&jUsV#BS!FV{#Xo z!`nzt_TuLD)#_oGFY^M1-^uhD1A+$gsg?TtjJS@DZkj&-B!6FQ;1dkEKh<3Qc3eW+ zF+YOWDe`4&*Gpiw{O~EQ#ihKWr9tWHqU#lFRp3MV^DMo~hx0x7NjV(--^20bIgySJ zR&J~P=nt`;isW-wj-SiLdD!In)T|$c&++lkF?zGha6PR2lTQzN%geD}Nzz7ttWOVo zY#Ut5uj?$`Qt8JYY_0AY`Qds8A4h)`<5YSWpM(7-zc({2p!W>$^%>dO^8AzZ`Mza& zZ59xJzg!(+%_uSTDE`Lw>{Bl0^LBwsd-PPv^Yhv@q}FweH7>-5(N=*rw>0A~{3rdm z06Yr^>c>U=v*yl?rLm=n2l#8$R-V?6dn10U=TpC3TK0(i^RJ`pbaJ^|{E6h59Z$al zpU3iV){keia@{Xjpm<(xt)ASeeEi+y{VpRMQa>@5_eSzyJ~FOThMD+D|pV#NPdibuZP=3 z@6&On&&nwp%(L_h-H*OjKb}~7@{;tGL+E5A9M#YMPC=b!&-xj2tb z>ems+(faqb62H>7pY^BNzV8A3>t`dmiD%nv=SdjH;H&XEWG()^O(XyIl=-aFT>dSz zU+$;rJOcfR8=AYG2Yyi-_*`po4RWi?aC~R>#jWFK#NPdIKlUZQo*y(r8!hi7?`-hV;9sGXn2{(B$BZO4f?Pt(VdKEv3xkw4CmNp};^ znzPqPaF(oB@Gs5fk@IW%>m<_etLX0oBED9~qi@#VpE}mz{n0&%+w^(*`(-9$&i~ve zXbzu>$@kkm|7tF8T3v^w&Yvc~i`}Z7U4rlLi4W`7h1>=F`>=%yo&WK_(EV2J z1^(2(a6Kq}1k3mQ)tsJ^0lo9b{J0DL%-lW!_U2zJcV5naNbVd9a+gY5EMWYj*W&sS zdl|o8yDp{cOZ7MSK6m2X`gP1|KV9!J7cW-p2YHn%X*?2lm|OqYjppib<`o#{u5Z!t z?YqmIUa)_m+rmHO-WLJ8s#nl{1$NSXptHKonAJ14Fm|zimKXRwWc6x(U104p+fTxI zSCTP$tNuAFa}PhS{5R8lDIb3y6q%8Diq3ZtooIYMZcW`P{e#Yb&=)Whgth&=?g!>*G1I_SW^=Ur!-tACMDd-EdqH~oAD{}!qZ{+f?tHOwCeyHfu{@9(h#`M5bBz;s=b?}LGS ztJ?Bm3lp!!+x6>V0*E!kAKNn;K^hSPo+WmeTF`(-g&E0e>pPk2kl_a0LN*>Z24iP6m4&4_0?j8$Np~d^}aq_(_ ztXxsQNazbko2)ngmb>4ajp^rCcCNkqp~!Ee@#5q9*ZuLk>GOYb1k+c3gzH|{k8$h! ziGCf-_0jlvKCQ2pwc9^tj-KTg^%Ew)_orl%UZl7Bh(2B-KH2fe!Fbc071-lX3SQ`g&7VAJE0_Zf|^m9`6BicmjR1Z8?wY zi1R+Wo-`{D_%cKK^*mU$R-f|-I?nTF9E@7`TWPzE=#A!!-lgTA zk-aeQP3rH%-Vqun|JR%I)42xcum7Od^0;(UYy99hw82->{=s;DgE>9E@5r5tKt8mo zQTlwEu=sm?D?@Z1f?od_{BfAKs-54eUynLE_3Kgii~MtVm%;bsg8hkO`0ESv?P>#W z#ClVY)B9fKfQ31KfM4Z9X#dM!H5b<)XQA8l6?A;MzJ=o?aHl~$F@{DZX57BvOmVcq>yAH$n z=l|8-b#K<6%)f9QNZf+!K;{*ET$8>0IyWEJKkqbam(8~{5b(U!+WOIMuY8}T&j+UU zoowyC6!|C4kHS@Q`JeiAYxZY;VU7LKcgxuuxU@BUVSNfO(|^AY=oYH2z6xJQxKF3; z3cQ-Wz7W|{JcwUMMf6E>u1uKxeUp+Ted-7LagqKHe?Ic8x$`0GU-kFRUB`i(;ytwf z@CPui&JWV~Mwou;kMwoWJUjm$dLHyy-G*=B@0+Zi>SGwEq*pHQSpKH_f5Z5e7h12R z!Si3C*C`)p&v{bPoDSbb=FU4Qll1P>>A04)%ZSct@H;#H<7iwX0(ys&rZdu8dW2p- zBYLCx+=uveD)C-(>tdwG?0og_{B?7FT`vF4>SO71yUh9Dbv(VVWiO}eEGr-SnHSP} z!u!*GpflU1p0ws10eWN1{c;%J+uO*U&7Id{%=c!L2IbBbIKS@s0N2#M+tsBVAwSzp1a+`9yPZ!0K&xfBsN@eT?=k&UzQGqt9PXC*Qty z<6@Qk=sEgvVwE1N<-|XQ*THily&hKUVdc5bwFWQe3H&<7>Vtmp<9Ppzlj}z3x%ixu z`Y_I8_Z{Zsbrh`KPr=TGYIEDn<-hYa4E@D)y|l`1SC{_zH`3c&{CKVYoa`wko=?Av+~k^!S|Kx$dI2^}ujM7f2_59b9|hyH#I}c&Hk9bj)BYh_oX8DV!6rh;I{mBjBEbgG`@gO z>OQ_4m}lFpAD>6&ndb(9F5}|+1@qA69%^mh^4=_`2lPSfzY+TzKhm83=y%NF1p18H zFgbTdzo(ziA~~5G`0Fa7Un=8nm$|ypZo8A67)ReeG@dEa4-WFr;T49y@G_deU3NRZ zC>Q^+&&kn=?2O*hTHO23qVvpkBmX)vI7rip>|w_pX}Vsr^K9QwzGssihkou!bMk-> z+R8Wd@vfdh%TIhsKku`G=UYLa)otu5YvVT_vsNDK@BIDx__6eROW!+*7wh{|_$Yt>l+_<&>V+&H(4`*c>-RlD=Vxp?eZDIY zz2(d3^#i#^ZTTJg`|AAD{Jb-gYc%iviQMx9`KMaD4mGl))%mWC`uK_DSF%g9e&oJu z&Y$3Z=JGmvygB+jLm&C2T-=CoU+D4VvHEp~wI{K*xjbg&nC%yTw6t;cZlQ6EonS7G z3MT1|@T>l|xpj*DnSbBONMEb-ju-RsDnH2gBl#RX?q5aYKYy9I`W1{U?K;lln>dk= z7fT0y=Y#zH+j9(!TlxyR5B&eFZDvUB`evc=@&3l#`pepvc$=Ku0QtQVk=$yPA8#W1 zJ#9SOrh4Hf&!Ys~bbSMS9NYBkl;4NXNA3^fb&zCKD`A$K3m_k`T}5Z2E>X3j3)TddY~t~vi=Ch2AUO8 zs~?%2=I{~OGcWo4YS`es%gPVzYmI$5lX}69tjYV0z_(a!;>UD;CI!z`CED~k9q>E* zgnqo21$F_yQR{uHTznhJ*<0pa-3Imk&v;+;J)(cTX*C{>B7Z;6KV|M5YPDTvewmvu8ssstxpgy(SMs*@TyLb`N9S#(i1*LT1N!@@YX2O4PAaXY`yHq9<#@6*ZVA%&lkfGY zk~a8eyuN{F`EpzbVmTSXylN+TQDXG6^K3u$RU$vZ_{9<~P``2>#-nQrx4voIMmFMh zfy^+i#`Al6y+MHI<+#2l$h`Oe49*k4C}^`S-gjZe&I>*_z|t*LKlyeV$Mi09>z;Xx zpGOO2zpS3%XUzE}E7ypw>l|}=9{CIZd4eeU9%SE2jCbWe`rJ`{#nL#}rA(g7ORMSl zGr|+*D<<{$f8CrO&{ufK+H)hwHEP|zQj^y&iiC@-^;`Mah4PS%TH7!|R z!v5y!kgLs~<0+?_+s7kEVLn%hzD_A@ms_t=hkjnL`0uU#oQUY!HSWE6Y1O~-ORUA${b_u?6aGwV*FEjRALNz>={S!s(&sO|%klk+U>A72S7yf$xv!ZE|)2{s}_wF#G+fYx(*?F56Zv!MK)wN&8WJl8)QxAMm*_ zbqGDq%JUxE-1QqPXQBG;eQ+G)E|QBc)~>?8m$tuN@;w=>-B$I}_vpui`vCnq;dnit z-{GgvNse7~pS8dGc{+aC`K8j2rTBKnkJPV6rB~?hZ{GX$uiJvJG*=gl@XCLg&X=^{ zyqolzt9z{8(vS7?t18gT%CV|HzfFG~tkMH=lE2blSD>@14ZM+FSF7YMxSTuqb!EZr zAPT+vFKpac?Wg-c`gv$pU*R`&9n4R+2cKMTd*qt+w`}rU6pXZ1H_h57qOXwWF<{>R zH98JbzohF$<>mCc0-sUqxu4G0G^59eKX@~->#O?b4I?>=HD4s(8xudBUiT97IbYU3 zugUKLVELDNKmC3>E?TuWzQFf;%FOd4M)pVVw5DEVuch?Z&~Z z{KC=rded<)y?>jPV?-Z#H61@j^e~@zIlZnh-fA2DXLI(ns<&_keSKfr!M7v(9IpT2 z=jnaGJ4@61ze_)VlQ4Krz}H3dtNuLK+<7VX9(sK;e-zZcCk5lG0rZRFx%&Hkoca9~ zn!BST@KSU7SpJ3TyS`~n-uc!G)|EIC`4)X1PZ9daZkjK_K1XfWV=J*Se^vTzolUpYArBBm&r20R^ABXvNwW&qYYn4CM5`FHlN-oHWUB%C{;3?+T zALKRLMkKHI;z#rCa{NXvzMN*VyZ zex!b9P7ll9u72#k_SUa<*}YWc`fpm8>nq1a&Bfhf;Z*+0!rGhp1wW3X2jl!N{)f){ zW^qX_=U@MTyy!jF)M=2{?$-N0d>!Q&r0Zm}dfm74&nqH%;eYC{OX*qtb3;LJJ`(9m zm7A->sRwAk{3pxhy>}M#6&|CnS6TZ!bF^KNRXC1vKd1GweC6+B{KDVI@`Iw%F3+pW+T&luP47Rl{_ZVwNpe17{i(d%-2Gmb zzukQg`J51|r}$!iUH3jO7e58T_i%bYL+?|*&(eL?4zvCFADTQz2o(4;*4iadv)2q) z$otUw3v+wD`TxasfyAH(ritixYR*Q0WX2NtlN!xvjwflScoqI;S zls?JFUm7<9Lf04h*EjPoZjavd)pBuSV7B3O;?^ePj7avR`TYK?TZ@}m0LzVji(hXI z9a~@m&olh^u*!_;`{;OZ$M8N9y^x!rR1re^qg;(Qe6m#ZR&k6HixTlsoHPW6X! z_GjLzUzdD>@8hgqjrAwqET;$T+S}R$x!+Nq)UT)Dch^lA@8UDf<(vNsjJxx{{C+Ip zX}AA<2xKq7HOImHhD~C>{ckh@SUGlo z??S-Sq3z?<*uk|JOFXkL6>IU=;qeq{I|&4(w=K(^%*i`6pE`V*22`h`_Bwbd9mB6b z0F!{cj~;iO|j34`TJU&mx4>v6I%@V*$oOGo{DsMm+PI?=Lkc zPD~tHv)4)P&Agb5FDK(}GJX<~)9pI2#^)pB%aw72Pe%^N33`eC;M&!{FUHsL2l~Az z?}c#9i|L~Wi|>nJiuU~Ld6KpZ?kluM+u}*}TzNEgZ$Y)>x~FR|J8Q|<(cwH@$rR;} zbZf8ee{2M71Z)Is1Z)Is1Z)Is1Z)Is1Z)Is1Z)Is1Z)Is1R4=ohHkDYe>0>_+Rrp$ zKXzwcrmHk-pnz(&AEz(&AEz(&AEz(&AEz(&AEz(&AEz(&AEz(&AEzyN`L zYWLmdZ^h3&r=N%CpF64hap>7-^cQ#@)8k%8M$=E$akeHy(4e}GQ5%`tYn?!tbsI3rwML4=yY zB|~r)+0%Kbl0OaA1b-H!o+nAyq=)OYoy!hRo|cW3T&ej0cM^ z!sC@hpcy=}1YeOYod;|61SJhCJ5Bh5Z=iATUyb{K!^tW#GjPrdeP>_4#^=w#ahW1nXp`_JNu{6C8b zW!H+Q3+iXiz^=}N)Ot~?oviE(;ja?EL09=rG!Cc4pT7#tf&D-y+ZGu+ecvEBFyjb^ zvx!jFR-P`vAy07S(V#Ke^G24)30#By2fKZ7+*itP?GNw(Kgh6jQ)cW9eiP%t;*0R` z5vgYIC=q-`2AMr?%oBN8f&9qBS`mTugP-N}0~E-cOnmk}b>3@%+np2#5C^F{}elO_Jc zxgh;^j0c>*;Jg8Ti1doay^Ou7?_fMwd=Va_P2k}o@Ch|o3jd189{DF569LV{=m!RVT&K+RCNS|oj z&)AvCV;opq5e{pbz`;Z0iS!%c;3E8K;y2W}a;@sS|%(gX*Po4g+5qTEKR z{XG;p;Cl2z^#>12|C?v*cK#US!s3i@Sx2Or!6jAD&l@l_OZ-x9gVg>GEbb3eO|?!& zFW5Xay@8UKCwd{@mL2@)c8b7cr&HMgL!ro~xzM&9o44=YG7}1Q?Cb8>cYnnIbdRTF z-&&bdrB+ECMv1-d_tAOKbp!6h^~lKMZ+{zNhILW}NxsN2xMY8V*N2TCwBD0MCSa$h z0`6~ki98W)hQt@lgKTzPe8g`!Pdt0_+#i9bnYQydc3pPN#C91hj-n_D`9S>25xc;K z%=_{B98Ly)@W*>UgkA!!KquP<8T@h&;PqkG8?DcJA`~#x(*f(_Bl1MFo%?olbbGqH zVV;%k0sarraatjLs7tr~<@o2246q;M$+lt8Lm1{C#5l0HA{+vQhP9Qa3vlogc|004 zhH&u22DidIE89!>eIKN8@O%jO4i-gL>`X@jddzFKr|c>7U*xHK}Uedaejo(kB%F0AL`|Y zpPi_k>%b3@UeS1hvA0^pc(C{)Jf?{dGkC;_Jdu91-*fPQBV+?EVInU=Z~(c%k78V) ze!lV8Wly0w@CWE*+cazULl_qpXN1c}BGe2niCkJhjRQ|(XnqRbis&!ctdF2a1b3k zT*{EETRjf4I^#sH^W#kZq;Vhim);YmJqQc%OBNTP%QN=7e?``n8AteBK$uutK~{YW z^(0I1uAi%ajo$zD#Bdeax^-g%_G!W&Bz^<0{}VJ02d!1xM9ND%cHlvTcE}&-)1WpT!gT ze<2ad+RD=faWGHt%+Y)1M;MW8XW*p&h z5fN$zk0QZWWDnj~ATOZZDBM?aM4snU7zdE+`ZOIU?`VvDH1$+G-wRbbq{d-Cwy7rFYu>7i~Wal#k)_-pMvJVZlIHGtBiet z-w^+qapeESM5rnM37#T*kpI0s9RCSlh4>5nr3}6PzaE?WC7J`ffljuqGWG?2OZ;cX zk^h$vp{D#Nc#7;n{txtV{3m>#&tZRo-}QOihxaXa#h2G!g55wT+g2I-0>2~vGvmnr z5D{w1e}bpT9-;q)FGlT@w|FBP$V-#>=tz;2+EZL5rZf!`DVnQ`R*r9`MH{|TNVdxY^%_i$RU7U>aPW#T_Gj{M);jQ<993H>L0apEu7AI;MKAN|%tzJ%t$ZlIHG ztBif&Cy4*dIP!lB5o%`r%LGr6J+kNI0+CZ7{)4>vuV6fs+gY{0*Cwz04tfE8;8FR1 z9mId&@cxnD!T5pjm?1=F@RX605Hz3Ks7 zRuMzDOwprk@g3-#TQAE??8%bW_f@=(!0!1P?!!L!+1oBV8O_0Z0G(`GV*C$0iPwRR z6SS`6)^Nj_oTm%rFZwHzIKjQfe@$Qi5P3<014xX29peJ`p&vYgfPnf<&H(woKMRofpJqn)prN?zpx~)75Cx&+n0az&|8sguv?@@G#+E@D?Ww&XYoY-ZzDp?_#YjnsaocIlL zqB$CeeZGH44F|9v=w#bCV`sHOaA5F3IJ|}kHG@N($P?Mqd6ITtcWQiXXn1=4y77_5 zo4c&eAdy=lc!2!EZ5SVTzuU8RpWDzJ_yu&bZJM#a`WK83i#NjOwL~auD^C~HsW_3x zqd{Ycj(43NBYf`L={)JW1NY&+_O%bsY(jFtZuHvBUz)Y=Z`gkpPvrl0BG`=oiN9ib zBAblfKaLUp2=N=_1n} ze;g)qzJAedyML4g78;} z-yo-SH;u!Nn;$~#GDwX5~!QzYXh!UY@@W>K;MfTu20Z&&n-q%YL{y6a)i{PVSUq zKAgWV{>XIg^W)%;NWW;j%Ge$JH^zm<8R4?430z79XOVuRb47vhr-|PnC;1(WgM$qG z@|*DldI|Oeopek52Kv~4Fb*uP2#4K-$V_~65P2YxHC2f)5 zQM?)7Kgxd>;{)gK_g{-Y_XmE}%aVERV(gDSi}7LcM)=e=FhwY1GFJ`Mkq#n{ON3-8 z!g%kKR*7A%JoXpj+4()(hxdsfPrz=G9?`gqu`m7{_MgQQ`F|A=V#a?5ktfn`bndJY z`=Z2ekQ2TS<8UAuIOvvlK8ap}{Xi$%x*0n?9m{IpbHn0_aEKA1W^iynk8u^*)5Xk# zY*C(c5PBDBGXxKipSmC81D_k7`49g73GfT(mRjrSz;@3+k6Yy~EBU@5j0oTYcC&pL zZ?=W|Uq<|(x3dFwa+(9~=Q%pT4|<;MfjoBHY#-!o+Pw=d3u+=@{L-B>o8UeInt<`m zo95uQKSi&8ky356j(&E>u5CMZQ#|$Zw#;nZw0k@3tQy}I%BuSD-Is2!lLmIpZ0FlG zvtu`022=Jb9~PL|xq}$1G$3c|_SsFEHFe{&a5}_1K!4dRAHQvI6P>64di9HhnDN?o z>yRUTX8ZcJute-|3`r0sY*z*U!w>*`|)~+O%sM6p=dpbGvr# z-dqQWN`KY1U7O*CY#sfs*F|TPHB}V@{q7yxX6xWq{ZqelO69;WfbYuLZSb~RZ34!x zifpS716AJU*&TCr=Bnf5J9<Od zP-rukK;?&d<=N5tKW$z~z&geBIKxzLS7_Vio8XO#hH*W5zsekHxXmWV64pD7< zd~(hB~I6po)Jv=(PK`_5_M#<=H^%;##*Yxu# z8s}*R+WgktJ2umENP{-NX5-|@^!WOEaH#pfhOub{9X?r|98|%TFY=q+K`8@0s1DVy zK8%M#>M3K_p@8K&duzqw*iqh(jk3wwJcEzk+Qdi;I>pv zvJ8E_ts1?u({%TsO9tvso4-`q$+hs-#{~yvC2`>uo|5+We-u z`VE;HuVd22>59&b*Kx3Ruoa&_&kE4w^LK{Ed0K)tPx2J2RsYrIAx`EZySHv_*nl*; znJt%vu2fcJc4sZ>XmxeCg1k*zwkRn)#{`}xZ__TN09?9zS6xw8tmDj6nqZz@y?Q>h z-zghuh(0+2pOSZ*E{ks3ImZ$ZWa{W@g;@oxVIJXua)vUm&VDqHPB|PR%1=ZW-L-Se zwyj$^q?$d5?o#Ctz#(docNIDYa|vmAv(X(}^z7di**SX^MWFF3?@msRjfT)?Po^l6 z8d5-al5z-BHf~oaMAIuDQK9~T-uWeR{dB0@bqFOyq7yj`rNrvj!> zD6nC8?YiO6hOyBxWg{I6jRmJChu4kO6DzNQUc*7a#{dF+&My-@RJ$1kEq22%(8t5W z=oRBJIy^ll69<^iwS3*C*SWfTTs@xdq2-zr;I}J_{dTJMX*5>63OWt^X7q~vo*rK( zD+o#Ub$9{T1xDL$%KeZ#5bI!}a}kGkV2-Pfd@G$gDS}W5QeW z_p2nnRl77>t#}nULf>B(qu0RS^T#$!HJlldov?mdp4a?V=~0|_clS)NJ^`QSYZ!+L zV-HK;Y~O#RJ`Pk{y>G%&)VN?-+Q#a-%b@5DZl;er>2$7Ub{yiSZ|;c`+W;u?=qvm zSwC4m*D?BjJ5*eZ{2m)!tLtxVUhLAR2aQt9F+T2V-pkOQ)81;jp3liw}t~v&lUpJ|2we%1$Dhzc9|03ev!Wa zRYtGa|Fx4FM?$qj%lPC3x}edDy`mBP(fn_uug3uB{dW@o)perGZ@JU;Vgvsfy$1eM zJ|pA656171Ymhb_==^sPf7NxN>00eMU!w1Ch0$x^@4E5H_0%m|@PqM}(7Ae9`+?qn zH}-p8T@RMBwZ8LseZNbLUIV`a!_y=FiLvv?Cg?C1t#>`WtA6KG{l5qMpHtVTHGf%d z=LrV>GkV4TH}3UF7xIrtZ=e_=5Aqe|4Q$4_fOx zUHbkP8NFiv(G4r*(uLXe!4J)UicZ_@nKv|nFY*oIzq(GX`O9)UPc-nK(W~#ja%m#v zze=b1&%ALA{>Q#a{8!hB^`NzW#mIj~uh{>_y$x9gey~=;c=TJuKh+MFvbBC;xxxA} zdd2>&8J}SGZe$tw!CDF9k#A%FQmP#+Wo!M+N&5cf7`-C@@a<&nt$47XwGPI^_hP?d zs(zNTwSMAceZP{7UXfp+(CT63+}W^r;0J3Zj0eAi{R^meu#~O!!!OnMFUsf@`WM)_ z>9Wf=sm6f)>Hv8GJX)v27a(s!ni+= z{d1^xu#~O!U8m~%=VtVZ{X_Syr>2M31*nq}_`zBU#Y1L-ikP z5c@ZCKLe zx4YTV{LA$H%`tk#{_fngt?rRSuwV1DHt%BX1iHWvu%8Ll9+tATe&%$2Khum}k)O(Q zd(<;-U_bbY=6UxY0zbt5MO8am^M~b5y~BD|i?z75etLzzzfnf7*kAe{B5M`+1M922-%j15tle{TF&86sI0OqA2cK#$tD&`i zdZj)N5k{{Vhq`;pbtX0XUq^?XheuW^6o4=CW9+|QwX;sR1uv7U4E$&Giv5py2SVtZ z$LK%sLtB4LCyM*XPl&&&U9`MbdvT9}zl>fZf7whI`OChA2y~GLu)ki_u2wyy`D5Ms z{stMnVt?_s(=xXk)Ow|@Z#^9q(lx_WzaPYYyH)#WyIbu=di4GFGkV2-E6*$MZY=2F zhvqk-V*(rKB0t6cx>UPb^^oQd_UilVWAqCBMQ@LdtX~&U?mld&QvrUc{?^mg`3!X7 zpJ9KUs$F%$1TSm6ec*?Hhzw_dt`mnKe6JCFj>g0275S^L#dsF{4Q*7e`bWn`CZ+;o zBU7O@%H8;>;ku_pfKJ7aOJ4^hQ4M_IpJP1z;J2}9HDCh$a(K=I9l^7U$X9+AqxKhN z^tKyM6({^wR>K1rfQ!3{=Z+9>WIzs=GSCrR;Cs;yCb*;kH_~5VT(q0}ZFnvT;glSd z!^z<#be;HlO!z!C#7`D*TpXO*^86CQCkuWPzeJ6Dh{gxLZxV1SGB_`A93gxxf6fWv zQvkn3z>snO8T$BC8JrgwpSC;?h486>-v;=EU!jjr7b9ok@TomNVCnnl2p7jIiN6N8 z#DPvwpS^$^k+Z25e57f93O3KU#`4gztU6pX1!ty@)7+t^L{AH7w!B=zIl((QxAP8TtHv>1wLPAC2>It5pNdoK?6E} zfngd)*!SW4G>VMg1;cS_?7Yy()HG{4;L?C2p?CGu96(=r2;*3l#05z~yj8%57TeHE zt=7lU#mHGO9EV5F+c>^~{n(HiUkx}CdRGtaqKe}$F^)d)mnP%(5U+1UF0V^KNAjAD z#|Wc$!EjXabWC{%oplg!X~2=tvrn`EeT97ga{~Nj1#|j{H!&)QqkBw09C=Ujcf zij3a&;}saMf2@!fU&_1~uis$2Dw6&qP>_xy;J`&m8;nip&h9x2udP-`qXz z53Qe^5PZ*yR?iyg>#sQg@5*m6jxO+5gFyHS@w(Q@L*<*=xKclzpI8Fqp zH-`ZS6*n|rw`szB<#!mT2>2sJN1H&r{z*BUia0VLBK4 zg+PFJ<@Xpr2l%Oj1x(d=H^{|b8t6#g!u?FRj&(D77ZyJTM8!eCr6CS$q>W$#eWi?X z^nWmIwe1IDo^i3`FK@fHCeG@$brJ6|8i z4o1#`;W)Z}<7&84!{A=jOruMyU+oP^D!?ZqLYl?1;Z0R zPFjEDsaXWLG{hy)i{kQ67{{C>E=U>Dl>>Zg+Qt9)FQRc|D<4lcg z#80EEhYsi}f5y0VfPZ2L)EUHEk)%((ipCAT{TZHnb1`z-kK5|;wQH3R6oqQvFS>4w zK6Z1?I~@APbXNH)PhmX0;J1pJ_yxk#_iDL(E(0B@k8oWK&ntx)z3sc}Gd4Lo&i%euEuXpc$~Up~Qg`sx_^e<&6X3TPMs)`9CNGx5(|ZXWpMc{_h_o!D zccJi9qOK84#U{Xo#j~E?)z{m@e7&K{SN#jdvnYuVf&u9)0ZwQ@=PwbW@r3&~u-|kr zauy2Dz-Yh}p7r#u-o9?;?M@ZXj=y0%-Qc$lHZXh&(#+y z-?NC5Si9Y?;-ST5J)QFPo7}VqM6|eeJdN>;f!`X*|Fiez@vW3)|9=mgMG@jkku88g zQ8}i24!D%%Kv0&-qEV64BOEBo5?Qn=O57_V78Q&OTKBrw4Xcl0+~WdPK&&EC5wN&G z6p@N3zq#i6e3HzSxtlxlecIpiN6YKQow?`QKJU3_xo0Lh&QHR#xY>_q_Qlch$@>@k zBYMf?U3s25ad}?Ar`wm;3*LaHyKR zE6*4AeMXLxA55}ela3j;*1qwosm?L`Pwe;9>jKiyFC4p1^Bbqrw8MVS`48Xo8ZmiS znqz(Z>4kXsn`JBXJuu-kvc-?n9PRM_cI~iO;4@&yyzt_G@b~$EyZA=da{69JlV* zBW{P8DG&`j7lexfZD3 zCW=`W-{MRCxOScu9iP149sIM`;a|z*U1_fM@fZEQukdHSJoe`#zxyS;X2=1$T}|ff zC@+pf@~Rl_tIKO;e;-UZ%~QV%5c=(wxG7?||=|H=RZ5=Y#tA zYxvjR)jskiXzrgA59t1xrrs7@WVQIF&-L3s%e2FBkJr1rZ=ExFSDs^V*vs0pM;yNf zyR`nBD{1?W!GVP^nfSMI9HU<8Z1E=?#|nNNJ731}7(Ea3dT+wyT@{YaKYLg^pVr4= zz_DhR*27@)&urBEN)IZ>8BZ>PSUAp*k8~{ampd=Yk=KPh56_vrtHQB%*sB-L{WHR` zW*6C&Lnqo#{YUvNdGZiv@vV|e7|s2^iSy(6@w&Rp#90-7!HY`vkVqa8el@%1%R$;t z{a5*Asnd<3wnlt27x?YRbF{K$J&9eCXzg&9BXzsAjbamP8fs!bF<2`?8!%* z#kWFEVKn#u#$FNS$?F|n7cQ8*tHZN)z^fHb9#Nh(yZXR1=NS4eeqA}HsJ9l`{Xu+F z<9_3EmUd>I$8ni4c~^&H?Z8(PNgh#-HM>^RyW07B=^M&3Pu;Z)?hlfC^p$=*J6{z) zF8M9gag%rDc?O5eP4d;Sn1g1ZtC?$)eeBgF{Zijlp3|OugtGX~kdt&Q^Ot{hlqavp z)9{%yc~_BV?V#9LKDpG#X^m&iKJKcLe(7&1&m~Vjk~{Rh$Zvd3(+>MPpO5Sb5oz+q z@+$JI9Tbr|Y{(^sXU)F(>asqryRT86IqGfjlmtCCFj&@{dkUC9NphJKKDTEvdO#hJmosleE@Cd*=%1w z$=j>XI@e5Dxh{Hg5*(6yiM+ta)yx#*x$=4`W#X(R*V=)xq4?#v*6dqejn?@Ne@FQa zlS4x;*GH)#|2n^M+xhw^U%nT`-x3}(c~_Hf?LgTebUD5?`})8&SEqHZ`R^*%DNjyP zg5;hduZEi9K90U2o-4;~#pGR0uC)VZL*dJDt=TVgwMzf7?NQSKOY}OR(LVMvwdPm+zVaNQZs=OB5uW)s`SI*{ zb99{YeFfiBGoi6Oie7$v&+O;J)X6rVx(v{ z&zk+RJg0u7Jcp?}5UI5ZSmuj_fKX`-c{sUJ1{n?T!w4SewovKjqB`>mFuD> zC#gYlFOgScQ8AyVFO72Lyo&Fgrc9hwTeQ5`CGj17x8HuzaYb}{@HoToFO8YJE5ALC%;z^9a_CX~H{Ojx za;bAR_UWEXPfy*6_A}Qj$7x?KK?w1kCZBr9*iXY();NYK`MwJ8)6AK?E6?$S@Qb|i zDs#ivu42Y%gIzi^K6H9i9{J7Qp!}+yJS2+vE|N<$Y|~QlJyCvq51brRCeAAG%LTv7 zVe!TBtJ#J4PLBd4zw(XBFGHP81e!aGY!>7DrC^4z&yja%D`jMFr(gj>4%z~Fmu_3NJWf$1JT&_yQtcl<`j*OcdY z5qI&O<+wpSSCgNLA76Y9I%jyT!uYD4Xd7!Lj|QGKyI?ofv&iYEpVa6hpXryr8OJ;7 zwT3avq3?&6A1`#9q@B60;eMJnc~^@gc2kyF<6$|5!!lFHM{eD}Rc<-zt3`5u5Z~-a z{J1U9&T!-YKW6f-JU4#7IeMlbk2<%AUBj7zL$Tqc8}Oii_btk^NZoFXwKd{9@lijX znU6*HXWo~4BBD*1yerQ${9b(&W>5=x)OptJ8un+xJSj@E?w|dg@|^SJBN!z2JUL0n zGJl1SM|tx4kk5^(Chscn49^?SJL>S@_mAr{<`|xhcF`Yu2=vl^zoN;z^8Dnq+k`KMUxQt`kGJV+RBHTwul%N{vu5G`Aikw(KYp1{MfYD`KXV+G zP2QE~7f#ih0Fp<2{59I8Bfr%xWN1HfoAO)mW@{>DEYn(awhM}bJY2V9f;&n=NGYS z+LLKNa=Y>yqt19_kzVl~{j49qCEA(u2=6OQn7pgNui*e!mqi{8{2J_<@YVO@JCxrv zb=E^VKS{2s&-w8i{`~U$amD0ad49Zpwj)sGHgh!gk-fO#czCCBT=e83*(BE@`Dl9Q z|BGLUa^(2q{+u##R-R*c-P{DRnO~!wfd>X6dgPDFFGHP967?05t9!<89L~|saXm9) z@~%9;VE2^SiJ74^^J}zgIo+%8*Ne)tK;3n0&QFqi{EL1(hrbjZk32u~{>`MxyJ|cS zi^?OF15KKrC2E{s2Vm+~%q@{@AJcaa=TeRgs3%QfEN zDqc_4_J0#+<$23{EX@O$JnH-+b}gsa^w0ho#{=rNKw_4~H~SU8@w-Snb6(#UaYszv z)#Di*z~o_XM6kb^bA6yT`p|ylFUqw@{V^PEm-tS8)sJiD>gYJ-ae>#HvnKD#bHy-i zI#a1ia;bBS+S@Z0?dSfg9Opf`NH+1ECm&7k{D1LlHI89Q&b#@%y2Hd-d5#UgXJpP< zB7$7%9IbuBxvN1n{pRjgo@wfCuyK79-|ktzak)S{?C<2r?_uUl-qq!4@0PdXS$mk% z1lc~(A>a9Xly89?Tu>YO#dqTCetf&X5go7O%ipOjnY^pYH)h`_m)P+N`^H%l?U$;` zan6&A;1u6E@{x{Z{>J_%%8~E2^Y>|%Ox~5}7#t6?_9``QeAey4J>6)m@%x+d>!MC$ z7q=+Bsc-s?!)e-KKj(dO9zU}t@2c<%zByqJndDI)e*r(*;ZWJgg7zKvD!)8+HX1oT zi|@#{{PT-vAqsr)k3xeN=g65sCc_>IRh?aY47`$!`u@9Oa5 z0gsC6Jfi$)7XpkRB){(am0y86>mi+=#CPnwe*8MW7af0`*YNy2Y4WZPKOXSv63HXV zk9OcEJ9GV&i_n>VnI+{oXY#HNM;`F%b(2SwBkdYE z^1#?Q*$%?cKl?A`x#Y=5DhPdl;5RO(XovlpQZ#v2g?kKw0CGj1f^W)k5i|9DC`*q3WT}7Upq(n55OU!YS z_6_?rCpGoEJ@n6Sqg>0LoTLcxog=SERm}@y*GIW>|E_)i-Q-;rt^pyh{aftfUlXXE zZ^pJ&eqGerjG(DU_@!>}8<(@R!v^Di&iPE%3PawE6C1olAW`Z?X^e^Tso`@~QEBnDU(V z{r zn~tmC!mzDzNPCP!x#&5`aw6A-M<~}>Pfij?d@JN-1DoaXn`>OdlpK$H!EV9iT^+6g zA#>qF9u^e)qvKTkYZpWj7uqlGpj=bbZ@9!Qif{V2e&cnXc1Xza%JWXnZD&FG9x9fND^+5hQ~KG`{|T&?4({7kcNKA)w$p|4yS2{^Esbu^LjmF@~$Sw=2_439AO{% z?ku^_JW4r^P;Ub-*GKUk`Mn>R{t)HL`8a=b=Lk@kM$v;0`)nx+0|n%E`D zox8(tzh9)CdH&7uIcoB*D%ZBgXTWut@j3T6eA3=;e9k>yxz2lXlAOYIk-Vg1nZJp}C|7&@>@aawm1|q$GvK<+_*~do zIcBJL875pM95Z+Mjn6sSnfo3*e&$WymFF1VpKQ2*q$+JioBY+sr?n5pXTv=t+Ank| z$8qY_Fw6d5e8>Of$1(Hg`0+@NQzq{!a^!_iL@T+(aHM?*GJ2uZG_9;%&oAzxe9NA^ zq!_7Tp4=kUH7`v5CCZoAq5QeBMU!_G`SQdaDS8>cv~P=V$F9mZO%9Q4@e5Kz_OE{9 zw@N!42Q1&5$-9btdE$wPT!t_0+v3}`oAND^LnK@Lg49sD+mG+?JD0)P&znDt@%jF+;u7w@fR!GJo?Mm-Dp4e$Vek@p>w6@~%8bIiEKV%w~QO zyO#Sp{fGBdp5xTL3`edK-{Rl>c&6@+j!XW&6Te4ZGI>{?=aGjUw&|#ihiw`d*g!!+ zOCI&{*kG5g|4bI`@@eH(@#G+>#CMiFq+^-C{6C`Hc;A!z^`gnUs@ygmcHA)|M{mqG z)K4z4{AeG?aWCcALA?zzT_3|-_xX*#DcWIw=KW4yhjyF1E6?$Wqfgwl@wtZ_z3G^Z zC+3bjyy3S3MQ=05Ci`@z0SxW)dn?Br^)}eJK8kPdpMD%W?vIW~UJvp9Qo-b1eU2xd zu&F0IIM}nPuMsKv)W@ae+2|KR8)Bn>ejnvK>B}qd7T;-d3!}OJms^VRO~Z6Av}Kcb z<@p{S93$Hqr%m<^dwYFc=bxw?tDam$zHqFP4|uqm;=iIC?Ktf+aaNwAjJM+tIsB+r z|Bgn3T?4t=_}f>xWvR~vprK!UyC3k|zbmxEanhb|@+R-P;bO4enD~-{_V%Ha)x^s@&Ns5vWOS|H zaAK&7^|WwrTD@R&rCzAIET^Qpj%vyn-!TJSomhSLA@ku+d9$8)FL&=Owht{9q04eg zs_WSd+@hU>u7|^aps_R4sZqZId7tdeM+d~~# zPYd^^)!op+75URtm*tdH*GUZAqAixio^iWavYvP^ckc|g4=om; z%W_JptMT8IWRAEtwRQA5Ds{(BUlBXj6X&yB-vo5fX7&u-UY1i*UC(FW7Hv0l@%)wg zz!QETF07}8d(-Ms=-`UUG1X-`CDru;25!*~o9&g}X(Ie*##m1a_omfZ=-`U6GgX)6 zlvLNr4BVp48(mXpy(=d!tfz&0)9Ms-aK-RTRF~zHRM(3bxJ6qqy6ziW3U#rb7Vb@} z7mcp2m#QwyDXFegnli?BOc-77yY;4U>c)EFz1+QJY#&-wq04egs%sMiw`ixJi}wNk zl}*1)Tv$&F_ome)=-`UVS-QO}r=+?@8Ms9|3tc=O?zMTUA}*|_g?rQL0(5Z2)Y+=b za!RUeGXuA1=b(${u7731fqF3TyYt`{?Ki?#|~ybtiID}E4O zN3ot3?oF%H(7_cW=c+EtDXFeg8MsB;xs6_La2(!s#;rdU7uM6ly=nE5(bZj0U6xZ) zU0a$m#&@KRu224H{inr}^~8I*d*`ryY8Ee3U6xZ)UC*ioUj9QCx_F=M(1&)`f7TTB zEbraCb{gAuKTMw7O_`%$%p&tHbms)pc4^ z#`unc8Hazk;*^hwWv!lgH)n62I$$wzzUs1^lIjXiuFmZB6%%HAec`RYeXXozJ#|aJ zPZ{W-_2>nv%W_Jp>pTW-(N06x_OQGA6W`lMKC+$`?oF#Zp@S>37pgAHX{B{lpz9GR zq%`}X9{I?6Sf6jZV05KkuDUFzmDaTgT|6G%_PBI74q1<{9@@=f`*3*?x-6%px_-vM zt=et%yv*a_($pVcDK4z1mAhR(2_5V&ze2Z{<+Ree($K~2wav(%Un4cK9@gjEjzI_Q zOXI4`a!RV}S_W>>X3h5c#x*BDRa{t43-_kg!_dJMg;%OB%W0)`<)Mq$hgW>?VIP&6 zSP$#-ZM&d@_PJN7F3TyYt_v8rMO!fA@JAcBd#Sjvo)+#+tE)y=`qiq-a!RV}rlySX z9TU*S^Vj>obl#z2$$H|w+`ScSA6hIym*tdH*Xa!0qMe4WN5SsmPo5t>GGaX~+?!TU zK?hgNU8LK~a!RV}X`cUJ_?+2Zm;N~ujziYN`h44Q=%D@dYgCuzlvLNjp1P{g#q-z6 zSG?^isfqQlKHqi(I%r>ft?IIzlInW8r>@j?dS2%JsIR=>#*3vU*2DUI+ivKfeg0zA zWjQ6)^$bs4-O$DD^`56)bE(wCdRU)#3mvr26jhhylvG#0r>-1yJraey=V#}Xav`Y>Uuc?w`doji}U59e)Imf zi3{s#;oh`51sz;5{3g|9IVIIK#=x!Ghw1r?y6(F3>;EGztf!T`UB75_b-h`2Sxzgh zD{XWwY?b|z)XI8n-L00(*gmwYLYL)~RM(jd+@c+ZE}oaukG<+U;=+1bxHqjXK?he< z-lE&fa!RV}Tn28@jzZVNVfUTq9{O?l$a-41H?1x}2Uko@s4mMXsjdP8w`hyd#pB_R zXAj<8Tv$&F_omf3=-`U+x2i77X{B{dnQ=Jr>ev57YGOUC&$mrO2kl2LQC*f(Qe8h} z;1+G!Y_IZ-8}1Sp*3-hhY4wuP)%`ZrWjQ6)^`oYY@f{1$^%$()=9BZ``=YET-pk!P zhwVd)rMIgt%PFa@3IjXZ%B7lb4(;`5Z$^6y+CQSb3++G9{uAw1sCyf7XuYOqHw9b4C;b!;7!-?6pi zt_A7{Z|~GbLuaR6w{RYJ->D~r#~+TvnxW^1DR86t++{kx?EaB-JpY4%TeRKK#rxrV zp8fam5drII;oh`*96GpS`W>pva!RV}?+o0c9fmGmw+wvg;CG1&>uKTMw0Z7+N~-Ieri}3&73jj( z$2#8jvQLKBnXD(?%iTMJ?L&(N=(3!W>iQ`Iw`iB33tubf*!tpYza=iLr-ggd>IvxJ zirIJT_OhH-T37e>(dW4z8+%pw{GIi%KHqi}I%q$6h3c}LlImLTdA}|PUA(XL#GgEH zv(&_TSf6j3g$~+}U8%Y(r=+?DJ#~#j7w>$IhqqjETsRI{59{-77mcp2lIpUYlIrq(?l}crJTG5$-j(6hhxPdCpj?JMuq?PWP7)%6PoZqd#|7mpiP{Nl^M5f|3e z!o6vA0Xn#1>V2xqa$0F!Rio>XH~jY&sfqQlKHoM69kd^Rzv{A_lInUE1Gi{9AFk&w zzE|*=v){6>xUilU?oF%H(7_cWA5dME(@N{=hAz%i@`rDJP-hgV0cmle3-+1FyKfFU~Vm++Sw=EhTGau6J#qGv8E3Io9x_I2U>G>ZI zuQzJ-un^BSPaUwIm{MJqQ&L@Ho^@29>rt?O(^K?)B-Y~@re>Cb4t9)wSan%WNp)pC zuMexx#rwuj`NkpP`HS_iKHs(zI%uE$i0ZPOlIl9jQ&-m`^!!C#$3Ets6Qm~A!}@&N z1*0qVQPpKRCDnDLr>;(eRl`pygQ1F#-nJ+zy}_Tlm(bXiVGb^U~aTePFl#rwUR zp8coCiwo;%;oh`*5<0k|{4w2LmeWe>Dnb|UZlAf0UU{${*5})fK?m(iA6H$LQ&L^N z*YhRl+6jf6{P?q+@}gp@a5?PpB@-DXFg4FmQ`@7P?ZfyRdWLDf!5HtTJq?G$v- ze(qDcy)37sx}N2!D+gVVMIk>P`R_*g$a+|xZ#xbhw4eU8>av`Y>Uy@Pu7cTK-H$AO zNNQp|tk1U{fezXiKcl)Vr=+@$_S98^EV+Gjqex-6%px{mYIwE$hbj(Wstzq(s$Vm++Sx1Be- zQlD2{mQzw)$F|V5E?6Hd8ZAll~o5|1Nac{<4qDN7l`5-*(p2m!47mmZ#|FoRZp>%dsx}wS?e) zVP)&teZp@{#9KG%M?GWExh@#Udmpp;mFb?|bZ@3-!`>!LYA5Bv>zd#E{Bz+)>M-Ul z7c1EQH0=H&c$ogA<6#PX8Q->?ud;szc}JmhU2ubM@16|@4P+0>^ftigOhq{ycGJ#3 zml&*{@qF7kQ)l;=l!N7(l*2T*y6UkU%BUv~olX12qoVo`eR_3^#Ae;DJg)vZQ(xxG zs^9Vy{rruPcJ_;tUqGx zu`rMAPSea+z`^tjhizfh4u=_VWqjM(aZo|t#X;TP90&Ye!KFuQKj)=aeC^h7>c_fm z{8r2JroPNqRlnsa`uR>*Tl&G%Rfp9-hk81*QT_CZYA8^e_5b>T@0=l8S+}ol+RdB#GGBv!(=YmY4r)t3cru@D zoAe`Z?x1-63y;%&Zj0Z3x&PA=lXctpt(NCaeVJM4H~pf&RjkJKWHbYwjq4geH|a;- z^y8sFxUn{n$<$mb=;!`_>5gyzwyb2`HABx2^QOMxuS37-Pplt2UF9_CN8YZTp+C4j zy6~Ly&phLtEvKc=I`^D#ur~xN!;a^Z>!!~CfUKsD22-z(i>BV(H^9U6C*@HFUso|r zJdiit1s=i4I0i#U1?zd=;ef*z!sm#r-<8kRUo~~+{zo}ju1Psmz}1!Ca#%n;-MfH8 zu!Hq9IM1P<*98we=E^_FYS!Ig>h-Z|>dSpo^;@2a^@FFY7^{B~^>jbMp&$L+{)5+E z^G1oyx?Oo({Z&(6?px4r`bGb~IN0%+=ZY!)oHvbJ-QK)u5qZ0Jt?M6ZNHm9jo}<40 ziqkKb)vUY0)azpv+ndI@YoOosi+(-}ZbyH1UgI&oZFxLn|042s?N-;{$CW`_MnB*0 zyX3QHUL~tpcY~?d$11irjdS0Ie$y}d!wc}hupRxQ?dnI~)b4ft^|NB|y<_xqzuEu( z1J_IKteZM~+bXsZ=F79NV{JFRgpYhn*SQEe2{N-nW zM=GSa@d&<{Wc_E;Q69Muyy{S~p$==`YB>%4v@3j1>#=-= z2hZD91AQA?@>nwQ8*St>_j~qt!aj4h>SX`yUb@Wl#Ji7p@84w|>!qD<+XbDpAN#)Q zwj4z_ZG2j?sharK*Xri_Ds*zWw0BhZUmo_P@D@7jrJZk^f==3x{y=qGj!AVdn)uAa z)}?z6I%zk)kLu=p@&2!!d!MXhy|nXfJE4>I`5$7On|hP#UNG^QhpkKZG<4E#h{!6guhGxu5Fh`F`O|*N5+)vtHWywpCNt@Q+ou<(O1=1sq-V zxO5LgC;b+&%yE9=`?r6RtYf{j^KBPRUBf?7-Iilg-DPle)#K8g-e0$`^{b$t$G6$s zCBGLN)@|)uEian-az9o5mS()zEQ|HLfz`^t<aU`n3Uu=M5d8~JR{eZt_r%M;9iI1DH|>1eB~#zX&!OM+C)N+1u6pe8u!_9X z&}sFLJS95*tDoOizyE@|U3pynOQyd39Q2!h(f?drwDa2C6;t{-ubFF6SCf9^o%-uG z;d=+`f*oD%2dB*(Z}>pv!26-MZ@BM+l9%<%=eGW!n?7T|00&dQaCkC|+Tk#7;xiB1 zCJx9uw?%cX3wD%{gJaU0Td#J!PPpLGJ;VKiI+(||O+i2H$F5f%map&#FGvEzc6cnB z_{_uB@>l}D>C?a?NY+E+pv^s1`*~itFTH2@${Xu$F!lPFf?gVr-Jtp{PtiXN;ce+R z@tKFM)!zyG#p|(O82#Cd>gT=66SnOgmsqTuaednq^wNIpM(8(ni~d8B=r{41hi#L7 z+TRHM!E?jLLqd0t>gWC8N3MI}28qSG8P~T>K`-scehK}o11m)TQ}DU1?Qh~U58EdF zu&JPtc6Lh}i1J8PitYh7@^KCn!m-bcMhqgRLKfe=WYo%{v%jvstzlJdUSD7Pi1~lrXpKUoF#}Uu2=dz5mxb0nlU*~XidoN*` z`v3d!`&566Jj`d?lJTqFtokia(a&>VTlx{t=H;^J9|#s~%mVyI4vFd?J~X=he{$5@ zRDX*+%xBw@@vHt8`VAM+&u3q@RvS~6Yug|3;%q{@AXu;18-oJ;O3=&I6Ng3hf92A9 zRDX*+^tWxv_*HL#e#1rdbIjRVZA@9N=|{Xco6s%@7I$1Mz;6M1=|6XPRR4wRE>-<4 z^3dP5CF5899rPP6qM!E?+R~4BHZPZD{Pzb7Hf8~S-5aChzw3yo{ul05QvEIRFrRHp z#;{|RjW7J2Az+mi9C-Uj`Ki|E%M7HJ-< zHl{4swm;&<*@Skk?N7gFsb2b5vCQ$m_YbiBX-`AXwq*ROe}I0&Mf7tH(AM@xJXbl+ z?GL}qv!nXcN9!`j;)SnY3g1^{-L5>Y{*tM$dOP$RE~0;D1Zhh@;<@sR{@Ck3_>Ds^ z{l|_`{roP)<4%6hM`RuArk!tFGWAvOfPTY8^oKtH8U$`jKjOLS5&f~pfA~#7Fa0Nv zRsFmV_uZM>{v+#HH|>1elButHC-fUGqMzTXYfC@kx$1H1hu=K((!X+?>faF^pS~H*+`#LKm4Ykm;RF{sD92xw%+oY@HsW>rk!tFGWAve z1pS7K=-(Yd+tQDCu6jg&?DZe~7NM8^^Cw32KjWZNRDX*+^tWxv_*MT5{f3L^=Wp<~ zr62KZUM@TLfB0oiQoXcKKUbGI7rS=v=cxV`dFXH3lJTql1^Nva(Z460+tQDCHZPZ* z;~#$G&`bNV=c#^Pi*>#6i?gzhb<@tbEt&eNe}#U-Mf9f;v@QLJ=c-4J6Fq}5$3OU0 zpqKmUY(BdEYx{qTJg)pD<5#^K`VAM+zgH6di08`h-2U)OJwH1BJ6@p6d`JB1k6sjh zPla{6^0@j-roQSu&~Lbie%^^~Yx^UfE5B1e{BqDs|LhA@Kj&hDSMGSStYh7@^KDC} zzG@Zv4HwbB4}!L(AMsrEILANyO3=&S1DrTn^>Z%rpEuumu*7EFt~{>(lBsX$Z_sbJ zi2f%cNIUwAi08_`E_l(Vr?*co0mDBVy8!=1=%(HLiqAuak*WV+TMB$%}U4;JxbklBpR5@^7v~=0+ z=gT_QPdnds#?+a<58Kc53y1v?)Ycl8iyWrGHO@x*)&)EGrcK8kfB44ZHywS{i6fLIU2Lui#G3~P#;t6Qj*lRA`; z_qv^iO9OBJ`!@6LirC*2KCLJ39iPPsOH$Ef!RBDH> z$tvoFnRk-`Cpt|0Te;coAl!JeY=>J4@fhE>>+t@YjoAsmapI(WBVL@1^vUmv>91x4N0U>>HlGJWo1+tP%Fxev zGX>?r>ycBxeOCD16m`(fw;eY1PW=Zw3@72ii)mYHTrTqHM!Yy1>09@R`hFnqMcUY1 z@b7$?>SmlJER(~xFMd*ZeaiZ2=iBB?om2l+4wkEM7(h^4Yh11x2gHlBkv`Xck%nLH zJm~+d)|EX!Iu0)X(6htqQr7LtaUvk)@5C=!`Jr{>@KGt-IQY< zak_sI-Cw${kM1v94w?@47wWM2S}mubpLUbmfrrr{JYEZMM1se#=wz7ZKFf8kdXvO&amy zY@|=_M`p%PKb`As>=gVve;M6hmaxq8%j5|=gu{sSGoEidZ0eld9vloG;qW>HwYA3O zB8Oqbi?flwj9Jgv++XbZr3?01w8J+=`DA{j%e;U8sYk2}zfVS8t~y-(qo%&{!&Ak^TBDgES=Lp+zQe6L={2}g>JorV7-bTdwIUO5DpG2!2H_aFMUd|>_B>;L~T zQ|H1Xl!N6e9NvJiw$`|8SKaW>MIH|rVOHBN?MKZ>>j9^9U@zm6X#)a9zf)jwhC zTiikUSl+_tjR-;wu9(tKJ_W>c*~&ax$BB%UlbVjJqwr7vCc3|*ZjO$V!@qoJI8Io< zE1#=>($qP&qjIoZg~OW=q#X{`M`}D*{-Rxv;2bCP%Ro1CpTrdj+s5;HW2`aMvw(IS zc{yIjej7gy$*tXTQs7O$;!euTZcpL=W*CtHed1b<5q5oj>|88=EQJZQV;EX+ip|$bV|8c&cfv_2x@DM%SA33#EY|$zAn2S z!8tB#<0rT-s?!P_;g?3+^*ijpxSs92RhRkR66f92=c>omKVs^fd6aUp+=bHwg0#aa zi+Ha5dR;W+ye{g7|0r~)AJqE~BMZub_aEN<)`{@?nDx8zx%%^_&Y4Fm2g_AByfq02 z#B=3$J$K8n4(O$S>G!Ii&mAv3YE<>N$U}eI=8a$ZF{^>_T53Jjj$JIY(>YIC<>bE>a|D_4^=Mm49-*-F=BhD1`Gv4GK%7f!! zzhCb1K3PW{wDWDpO}%rE2M@zZc)T4!+Zhje#BRspp55q}#yaPen;(>Us{I2mZ3cm^H<@MqCUD5Htc{1yE<#F{-nEDoXQT>*u=$}lW zzkqnI{H^Y%jKY5ox>;}ePs)MU4dlT3UHM%7leW%X!NKqm4won3F!2P9=gQyi_4gR! zW&W%jSbzF2@mxBf$CcmJKW*yn+D&y>&cfxL3AjwPsH^}J+AXh8GaMcOaJk|seZoq_U*s!5x%#?x@qUzE}HuCY1MCeivI9IKM358 z{sr)K)zj{NQbxRaaA4fZ-<1pBXZq#AmxSd~5AD2LaG-sDFK{t>gv)zi)D{;LpLy8I zJT-Xy*~EGteyMw-`$fk;beYe8_y6MY7f3AD&A8qz^wK`Rx9Yb%MSlrKZRt1hnTM@Y zKm790OZ(h?s-M>zx81qZ9kPyf)6TnvUfSpPfqqlB=zlMa+R|_0GY?zQFE9AonDg+P zf?nEB{!{hyJAdi@U;Zpv$GU0f-9j(z^G}3+Q@7|3CwzgSt(CrwtsL*R~&pd2pKk4mn-lyi_SAkyI&;DEW2al`5zrxH3 za`@S2gh)ZRGR19fIF|@7U(Rj%|8+2RgPn zfa`6JdBhq1Pn1XIzq-u()=P&K!}9@kFrIIlf_~Z;o&+97hwzw!k*$@!jV*aBnfQ%1 z@>!n4Dv!P)!C_-B!haIF>0f+EIdEJQ-?US>yRv@T`Lmv)7xsD8^+ z^nV0KZRt1hnTM@#>I;5=!^W(_ZvuL0Kfaaf=XJsBFZj|;vW|7r&bRG?UfLH9gnm=E z=>I5;Y_0TdY-`)!#Ba2b&vIOpA2PNvtMHqHUiy`{R{cCLeCf59gy#j;O*`MV3wmi^ zS`YoEZqffS7};9s+t^Zn8u1#}HGW?Aq+t86@6YsRgD)Wu4)$dSdb8Pq4cVTap-g{I zwy!_iKhQI{p?6@*ll!tq#Bf6WnQfx`NqXBTr-{$MHRMEnjWzgu9yU74PX#B#PdJ4y zbO%A(;gmx>S1rP+XMNAmK>vpRzJW}(x3@PtG>{qEFqj?c8yx5x3OaiG2L`iS4vgj0 zh4_=;!aT+8loOAqo!kB5*RqcKXy@CG86ArmLLs0Bl5!$7t#ptqrCu%~a!f&Bw9 z``sAgk99`(yZrW1PG?{By{||O)aR zelyTZ|EY(o{>P%@sM1?sARk#b?R?u=Q(vlI^;@2z|5FHRYmLjr<8ui-<7}kQsULnz z&`bZtN2q?@w|dhrpEf4zSU2r_+gVdzY5@98zvvGq2tnYs^n<6X9;bfz4et;g|CvYX zatZ1eSyNwX2>MOG=>IH&wxu6DUG<3mo`D$s@GC8eM*hl_b@Cir!f+Qil7m}Hz(bbqK~ndi;N z_w0DR#)03N1aczhl-t0lj!}1j#UqDn_Yg{t&D1&dDjr7U;1U(tKv!#DF z_6+vYPdnds!PJ>OSUFg(!eItMZLM*+Y8=2d&PMuV9^aQ~ zp2yF^ZytK-UwN$R=R9_5^YAIMj&;+{w_PyxWuK<{El<(^MFee2KX|(836GOQ&Bw`E z_@y7Gdg-5fye{)RG4Ypoh35&@O*`Lq!PGbYbm%wzqW?<>+K&DX#B`(*Z4V> zU+?d^BFWZ;dkm>E~9qJkC3+61D{>)%7;a!H`5_NS&$6po8JWua; z?%erU8j6dO*>F*!R^anRkGQlv+ zWHZ_Rq29s1zP`bpY|mhTuXoFVJ%hF3*Hlv$c?-Kl`Hen7mwEi&z5LDay#?xa)#>V= zGWxQIC_lSBgx^;Yq#b_cVU6d?A3Of~*KY_24Gi`VWP_hX>mMBG@9!B3ma{{_&4t0> z9!yU#Sq{cuZ+{J-t!W&2tKh}_3%f@7z3r0cJWbY7H|>1e1*0!}sOq)bL-<{dptjby zT-<-l*dB2<(&w5d&B8CcTXg(%@2<<7C!g`Aoo|yktXn>}^S5B?%O0lsEl<%O4%8rc zTl&G%Rg+Uc{EE;^|H2-spY!C8e)lK$$U4?dJKuJ})R#RR`c1#+4}Y*W2;7!_@O0JV z)DOQ3^wNKJPu2e@blmWX1GbZotebYe?SiQ(1QwTk?T*Yp?(R7fgNGBcR{(i~esQY+L%l(^XM;{TK5bXBK`r z=%s&lZ`IHHB>ne)CA<`7-L&&<7fgM*Bcb2)i~j#X(026Cfv2k;`TaZ0lY@sC^@+00 zF^f1Q=x4l%eUu011HXIvvFl|WbQpBNn<`(3joJU&nd?Yvv)r~T+r%ER&%9^sA{7`DS>(ZpvS zw(GVH=E=dx;6&NRo`-*CU)4>&^nTHCv9NUYi)9__r=4%x3Ei|GdzNyrT!q6mFtWAM zx3T58sG9hVHu72S7X%}sm;E;O0{n~6O}oPW%7NGGyIgcqc;AHe)6Ta|K{xHko~;}# zSK$zTp*AqIwbHk-t#L5%8*SvX*vYRA+n9^+D?=~+X1Y~Bua~+%*EuZfSU2r_+Z6QD ze(Y$~Z+VLTGK_4k^lfZw`c3>s8~NqWi%TmU+HRWls)wQ`T+cw^~j?FYQXl zK)0~-BW_&!TO%;hTuLx|Av9!K0t7PAedVOH(7(}S$3c=6U=mn zf~74_mfhuO`r8^7p`-AmD6i2c>oR%WdBzJvUew8WzU{ElQ#lsA3`gPhT?DnY#^vI8 z89}@_8|f2Xee3%MdwYU;Y=2)*Pw;>@cn&_;8~isEJmVb-e!F{Upm#76Jg;1iR~Pck zgAemno}#>XJ@WZy?0=Z7qfXlSwgsc7dYtmI{Ds%|5VRd$~N1yKov;E#+3=IWO zcY{aa{r!FYnaogd11g)zWCu5F2xhZA!SsJaFuH8+9OCB=jE<}9dR^vqO6Sd=4eope zzklDN9#@?u51we?$zbTBjA&FeAh4JBkOkMarIYBed!aS-}Hz2>${8dbSndd>j=@7Y^KIu%z1ci?n112$Qv_{?M;Uxw^|X4Adj|ex=w_UmY;;_F;lYk@ zT(ExH`L+wD&g}D*gXJn5eukiJaR66WJ+Ak-XW`emA-Z2IVVUFLpz`RyBsS}I<#F{d znEJ9WQ2myt=)V?0+R_i6uKaTRhCe|TPC-L&&<7fgL)CquvK z7yUm+P+MzUE}j>v;2CEleR>`3`yRLZ{?9D)JUu#Is#qqkf1JNx$cs8%b-DUe;KTK$ z7l9Y^V}H*r4f(uZHxK8=lk4lUW?E%_KYa6{4;f#=iLX7{P_t|19jSZS}hM7 zJ>^rBm*p?K!VBCWU^~2Wi07(f-IK%nC4TR92e@qRF2tV)7v`x9D<>X@U;L5hhTkWl zKHB-VV@5}HlX9}$h12y2YHN+l#r<#`@#1WxPsf$-d)@AFHH^z$Dlf}lc-?@&ZSg`pS52<@OaXo+=%xR}VXB|=xxtOMeMQ!>Zrb^_ zB~xE@v+B1zMgNTm+LnIAbJgS255Gm|rT_fls()v6Y<){Ad>w;z)6Taonfj_PhJM3E z^#2k;+tQDCu6msM;g{X0dO7dxK0=r6e3o^)^0@j-roQT_&~Lbi{_wyQ1Zqn^;<@t6 zaV75k?gIRZ&`bZqk*c5P;e&<_I$PGUZrb^_B~xGZH0U>6ME|c4v@QLJ=c-5a$GzWO zfL|GUIq#gwseYbUIiF?St~{>(lCAG_=r>$M|9k@d6I(Q%D}VhtZSWTFGS6uXh?6=> z_1ET|&(dX{KRKW6fDTt)SO2uBH+2Sh7*4|D*9mx(TGUma-!K1ucM)+$p`Y{5k!MH8 z2j{ia;nMBupEdP%jbVG5e&O+(1U#m|*OkB3``wf9pN4MELrX_T#|7uNwfbEN9sOlf zXV;m^!EzN2;fusUoOX^AQ{?K%?|Q$x1ivNdw{O^;@2z z|F?+JmVWSb6%ZaLhnks|;FmjA_0m6koG$Y`vFm#e4$l*;n|8i!+0>VNDfF9u(SHkq zwxfRzJYDsyJ5c5yzOQp1A+Lgkf3}7a^2~q_^G%IJdHt=T=T+*Yoo`z;ddANJFVio) zeutp8*0@}phjbuboQ?DeFaOuK-MlK?&d*UkoQHNEugg3SbAC&muDV?PX`^TQY~^M7 z3$I%dq#a%v#B=4Bd7Jm^+I3t_$G9cvm;fKnN5@Z4UOZ28o=cssx?KGuM$h~?%FFT> zUJD4)4zE$fbLE%u<^Oti9hj}5n|V%DKAewMu}of^=TfJuE?0k%d0;SquJW?{h1c(4 zV{46z&HZr{@#1Wx&o$4ha~zD&z0Y)AAXC_OaJ-2>gRhN z&pkw+&#-RV`L;z<-~4&dZ@7s5+Yz*_?T>h_dcx;3J$+5b%RKxt&sV+lPrpEygV%b) zzb72}tvAUB)~&t%|1X;Q=Ff+I!$tJpfv|1qM?6<6noR5yaQ1$aZ z2j{u0+m*-FUo`bCUI6`ui|D^If&K#Gx$^tIpPfgXGW2(JYn?MED-T}J^Y_T8!l`_88)%UZnbK^U+hHTueGzt#KM%)A=Dc)jR5|c^fzNYUze}&Hf5z0=`ATd*(=QzUl!ODgy7Gs| z%faR`HbKA5s+ay%Ec1Nv?~h&+o-b;3)6lb>VIJ6LU#0pjPtpHp*t9ba%H-*&XWdgB z?A^=`Li`lAkWx~qrCE`>N0u#;s!mxQm3OVXZM29 zGxlomGX28qFNk7mjSJ4}>nixi*+`%8YUBN6C$CxLnFAlrOUtJzFP@J%-=$7hU9SEV z_;7vcBIRZI3$MSzs2yHu#AAHh>iv}9YsnjWgZGg8`?A6N@4>gc`!WLq8-|89^!El| zx!uqkywx3iy|%wbt9g7aLPu^(bbMt`*JYlshYo(@v!w>=wDq)F9yWR^uTfr>zwo*n z!P?<9f_SbvWPA;-?;jcn-g55=UP=|{Xc z8|ib+_j2&dpQ-veFU`F~m%9*<&vjY1E03$cVCt(Bq2F*3{eMFcyRG74*YqP^oQ?E3 z^}}xldO0thda3HS^Ig{M%H!%UnEEQOgMPzB^#2_}+R~4BuKdC&?zwIbeoN3x|HZRZ zKhMVpUHQlGYqG4HcD`-F)K_^u^cyas|6T-bOF!bd>Jj~M&vkR~%btz#kNH;jIl9dA zE9bkc+m*-FUoiE}zXAFU7t#NZ1o}r2&y~MEzgzyfZVquKpr7;7@pF|2&!3#{Qim(A ztG{UKU3?>W7*4|Dz63l9i08`h`&>7VIP=iYd1<8(9Uq+UQim(AtAEneTYZ!AuzZEb zKNIj6M?6>lR?l_E;Gce(>gK#ObzXE_aK6j>UHM%7B~xeh&C0=Y6%O|&;edFq{I2J^ z1^5-9m-Erl^Hsl{=dx~B9#?bE>a|56hDi08^59w%d->lWZwhF<#5T%h`S zp4fG1F+5MOZrb^_B~xGete`5-P1IYb0Ak0eQMF zR6fkt_3|jMzwNKQsFQZSZN=yrxdglnN8$AVg4$Z+a`C!q9{l5Mq)&LY@m$x*YYKTL z!H4tF;wzLF&%>POQm3mfSO1dHQ+%89viybDzY(MzUY&^N%FpNEUO&TiL=9Kd7@xy- z?i^P>oR2PHndfQFbE(r+m#e?q=$W}xd0GC#>%j!PvWVx(FXO9?=ejjuP1_84imy~& zoR1b>rOV{Sc`kLj>T>nxjh>meD=*7mc>N~{FT``@cg=G$@T)*C=cBW)R{eIK%eq~8 zT>W`d-^^vI-|`gw|4pJF@m%?x`r+4g5w<_(U7fGdWjoJh-L5>Y{=BJg<{i*)xQPCT zlITY~SAM5{_!Xd+^U=}Qs(w4qW!-qcrqC-fUGqJOId`g4fqs>1iVZU%93uT%Y; zk7i%5%RC=&o=Y9BysrK+Q}5inz{7A79$P2ikw-jN{`$Os`RBUBh*N@o&PONS5FHk8Kk07)3l+{#MU*N8rB*-JFlkzcD&4IL~GMu6(ZkqN#J? z3guwA3WseIa2P{8SN>Mdb@TAgzDad+UfTU;UAFUG*6+&a>Yp%mE?lV`ELY*MT@nt6 z=gKd~%edd&8in5k^wNL)EvldAi@)yt@bG-Wx@qUzPMG>qCDm_vivEWs&|i9w#&gx< ze6Ab+yHml7lRDu=DYdYp$WsL$u2`6e^7`J9+lRcUlXkxCtkE<4Uhpy;g;!?+UKQ|n z)zj{CT^FxOa-5;yak-Jp+a9)~ydz2UFyVPmxX|vrXF_2*1|Q&*{e%Tx64kVHS?x$-;p!*2n4IWL`ihw8WUUDoZ&G=$Bs=Mv9tw8vYgN=8D;OMLAr1*JU9G)=xX%cEr><{b6u0e1tYMq9>bE>a|DzJ<&mx{H z|GI|-&uumyxMAS%BSI594!Yq#0^N)=d}Wlw(|W!da$xz@-gLM`3jH6 zB;YZEc&>WZ1-}v=jEfowJ1&OdzX;uoGhb2;yiWMRt-axEwXC0ZzHPzOIsb9xV7Us1 z$0pz~ig>PivrXF^%qTji=R~emZ#`{d;g8aTmL!!rty$xUC__-T;&5%9z1_ihbynEf6~;uI1L_#lknI%2@k|`)CYB$=g*z4u7s~`v2NP=wv(p5>Zeq{X~+@DFMo zez@2mMa_H+{-e;%6(b*ta@g?ZABP-RKka^)tdck^~e^3wYeA_uwclYO&i{&g_c1ywqoL%+E`LwUU z`M5C+zZvM|d2i}ts-M>rJfE^|R~}dYoT)GS1=VkPivHab=r4n(D}Vht+h9+B!wD6s zYHrhv^KsSB^IjFpEF~Ief!z}!B zpNQ@k*-z>+pRe3ges*|@W&Moj+b)_qb6->rmaA~sGXaM=aCOzQZhM`71ph|G;qs3K zSPo_QPeM226sMyccDelMkOS+doo`z;br!y)94uGikWRp130z(E$iF|)bY88UU~3;X z24kjQKv_-|#9smzo(~s4rJT6m@H|U>u6kVkUEsp?<6l-zmb-A;D*>kt#AAHh;yl}@ zqotWc74_vlt-5(W%zj3fd0&_FRn~9wv|3J^I;Xy(94uGiuy+Cu-H7L^Lw?`Yo@Z+( z+}a13+3TKV$IBAxuYe2l%zjom@x1$&{kvym9re-9x6K(HQ(sk1mb-A;CkZFSYgLcc zpN3!RbE>!I|9M^J^Rfru`-Sl5(O7rQ&htag)K|G$^;@2z|A|TTBVMa=n)Jgj552DE z1UcA^e<8|gY(|$kzkA6?kNt$yKz*(1vFi&)N9AkaWcUfE{St5*K|Gt6%TE39n}J^L z_fua~{W~GRWv~74l6+*{jO*JLOnsGE)o*!<{{55aM?6wgppPEB0RgY6Y{PJIpj{n?OqWbTk{uX&$`3uIc@(t)W zTtxo?N%SM0E5B1e{L0Wv|Cz5w_5YFjTjZg?Z41V)@;}gTxQPBICDD&~HZPZ*`r+4o zb#(i8eJ!g0&(z-{5A)f!VEiiIgnq+C^glU?e#EnRx$M*rze(t&eQ{Rx?~0Bue)aB4 ze}Dqx$!G^~*1nb*!6q zzHPzOSGflI4HwaWU=sa^=c>o4AAZB%h>riv|LF3b2>6%7jz3pEvTj!%SAW6OSNS&d z8!n=MeG>hM=gRNY55FnsWu24Xbm(u9$CbZe{3>PWH(W&jQi7xeyQ(7w|~cXb(!bCf8TTS`z1E(cI9#P7fgMX??b=gBKrH1 z=tn$Pey4u;jX^K{^WTe(|CvMfD#$w4O*`MVVCt*<0QwCV(chm$KjOLSaq5R(8G7kI z^L^F77dozcl>RI<>!zJ=TQK!iehB@Bi|8Lnq95^G^@#r1-~WMM_Yb1uzw3v(%;Wz( z+kZX$8FAL_%H!%UnEEO|f_}qA^baP{k9e;9&g~Ds3FxK&_>WZoF6el|ukQS~d}Q6U z^KA>JzG?;f4HwZrlte$`x$1FlfA}pxugk6gyUrg+$H@|w`Mlz5-7os0)Ifc%dR+Y_ zqoev`a5DUa(}o0`#u3kzU-b6{D-pV8R)AmbCsF;`pXxH-Cq3}HXTL_ASa&Ue=ZBK1 zulf_!Z+VLTgOcb+JXblc_ks%Wn}lBa7k{Su`TXH2x8GWnb*!6qzHQ0WSN$pU8!n>% z;3WDH&sC3X|KKrh^Y(||JoM7Pa&2_`pRv#Pbo;l+Lx0L<&~Lbi{--6;k9amO zm!10Im%c7K{!>5K<;Nnxd*AZeXUIp^&A7g8$<$Z97Wxer(f{-$`Vr4nkLb?^D-pV8 zR)F6a^m0XhPW1<`--drbIqMzaKRd&^Y3JLPOnuespxm-c`jz*5R6ek7?e+hE$<$Z0XL zhL3RAn1I8?4I0l?Px#(^Ur%O8ZW;%FmcuywGrx}R59#0NGT%cu{=^er6b3;3;paB~ zH*M?urPgh^3Wp<-aA;AN>v&j%-vsnh()i7)KY0Bq{Cm`Q4-Vdp3;s}d__>Y$P22iz z!ge$LqW{Pw`difH)DOQI=%u8o->UxLYZu|)^KSincs!oTN_9~NE@b+B$4dbZQHzMG-n z^o#zZljv_zms3Cd%Fs(WGq*+c@BixA{layun}(k4w5{*A&~N%h|1nAQx2VghAAU>F zOF4^wQ2jfgG#_<mnxWr^Xl1{rM#NTh!&$55II(^-@miZ@SFq zf!80~sn@@(n}(k4w5{(>=r{eM|M^Mux2VghAAY0IOF1KdSN-A3QbFgB-}tZZh3i;1 z4L#dwTi+j{-}HEN`@>&~Q?3451iue6t~yP>aClJ?4&>@6$2ATn z;8%iPx=;OE^>ZGSx$%ABS1CIGgzZPe7A@zIGp4?&f3_FLm4^3eOaIb(Cmi*atN%Os zTy^;N+wte?*S6j8a7PCZ;(@c(U%c=C29MFdMeBGpcDTO=C*X6o?&w%}++%0=xwxYv z{jVL+s(ogcM~2IzPtbPq1=?l~($@0I{9XNR|H6>k7dJ=!h947MF7Kqv!+G>?9bIqZ za=Eml+RgnsKL1$1uJ8Jjt}k!&i<^E#)ULRlE>{kS_IEucx}4fKx?J8Zy3D#Kch&x- zXKK4}vbLko!ty@a(ms{b<@rpspX)Q5w7>eK`1RG@wZH3m(e>#)b$R;f+7=#*_AqVd z9Pgz>4%N2!kNE9J|FP$*UFku!n>s<4 zxt?w5aP1$)@o4z=XxzmkqJEtlbh-E|wX2+{%blkn&VEt*rTf(`KdSw?2XuMyztKFb zXLc~^KXqrk-CU>IEvB?h^=dmgpzYi zUOW%+d}7Z>UH{ed0N>|0<_%Z#)wVFRJq|j`sdbN;^TzPK(c={j<+y%I%)y=KCEBs= z#06Fs^|F8191q#=YI(doATW?~;kflT$NBXC(s|caPxSf(l zZ)$7J$DQ&ypZvga%q=bTHTEs{xf48S!|NKGSI}T4N7JxvxqqTwIxU!d>~Ga}VLzl^ z)@}8UY@>X5-M!T*j}G5QWPIx5a;vu6?Ekd4d4~s>VDn7?0Kc8&+|iARA4)?ZFK)~xo44=dRSMJuI)A6 z!x89!9q)RFd}Q6O__n{MA9=ZcYDx7s<)wjVOZ^KE^VE;L)RRM9R@cZQG~Odn$6M## zeYbpM-Ja!j)bt}S{igl}{e}zI`?l1ddAO&3h@k4==bQ zVO%~r)9|Ssb$?~O8xq&cCz2XBYvLZ9I4+MQ8h6yheP-ggoPlZF3B=|1(H`9Go9FAA z_WnQI!6TRY%_1(x*~c#WYr=8HD=v+@U^u+~6*v5;y-L-3xPwoUbh&dU9SZ9AM{VAr7oGOflgouC>G7uckjC+; zLVOpIua*78I;|^sK{`yyc?mgAnY{Kq!8%*zX|`b4Y$uPiE7`{K%$F zQBT_KbJ~{E&pc;Ky4gP6C*S|!AMFcIR*o6!rNJ_-_-3{OpJnW1)g0}>k^J}^IdAf= z4#&ec9(L3*haA1>@S~12Aju`lF=C(I(4d+2g{LUTaq4ZbaeWlu@vZ$hX10lrM;<50 zamwUf9gZ>{qXUsVqWnU;bl>{^OmDWguYYjx|D*0b;3GN8^#3+Eh%94*FxZR}h+umZ zRy(o*&w8!37B3XZHs;f)0bN~PH!4vwaZ@u-@+tt<8-J_<=rp8QWQ){MyT!L$E z$TT%)nm0AHv^H+)dscv7ajeg1X^|ld<&7!UUc=^1&8^K%o6?!a#>UL%P3g_8Et$$AAj=kG=?3O)-e8c%$)=`gJ8`G_gnbu9j z-AqH{rt*(ghHv`L-7HzmOat!X`P}D8@B>?_{Y1;op5*3pz6R$p9JekIiB#~ z+pgVvcII|Q(wQGzNo?3}Sx+o)PB%2RW|~`?n;M%lWWd-=I)G$!>!wT->4?^bmWHOj zbDKBGo`c_OY3}!$qkq&UTDJB!3qIC1avwXPy|T#go|f%=u$zzTpi_K=IW%K%g%u>f@gZ^I2ro~^B~xNmz8>}=b!8OJKKMWkDw=3Hl;U* zPV$z6pQ#M@v*hRxElta=gHIf1{O|N5v7fO2!tdzSDV!?#NzOl=@)2|?l8w!BBf-CP zEB7x8?UY4^_q1&06u13(1$1H@gnWegO_x${_56eU!i@x9l>J&-e@Zo_r3EF>XD;AA zPC|PzR{M#ToqUv=kEuuN^AL{Db4tC{@e!>Lp*Dgq*hi#KHNYYRDGB<_h1|y_M_*{A zwCoc2L%*>6n|=)T5%LgxEGhL?$48g-BtEYp>rScq`reU={eyi^X*h3l>*ki$rUtT% z)Y910uxWETL;glhaCLBkrQ&rKb)`Z#69%8@w`T|?y;FH;$_GSxs9IunXGhcy0NKobHnB) za+02IPPdSSCX3(2XNqyc)j#4BjcpEm6uy~W3XikqG0C&ub;-Zfa@Xlxc2gY;M`q+}yC4e9mkp z>wqm}skMPDMv-)HY{uTxs-T|ri@5(?;1do<`-zsFdAytdnJ3_UhxyrdL7r0Tt&acl zx)N?8_=5eH_0mZ{DGK_`7VhJ!qc5~pT6Puup%+{b!ouM9Q3r)BF;cgx2m(24OtU5DyW>aCuS(z=q=PVgn_qokLN1bt>J z_pt!&m6)ctv~1ytZa&tga6ZEP49;U`lzNZ7k2~DH_@d^YydXucK1(Z7ydadzY~y}rpxqk()URmS>{)L6 z^BU-s^-x$x=~C*gqMzD@0PscQC+Nw-R5LmE!e>@cuKiN(=M=PCHBa-ImYqJ^&Cm2X zI6q;3hQDtyuhd&DKViX1Z65fd`U(0}1IbQlgamzOJNI$L(HB}TExQ8#sDUV-C!d6U zgmrp2-UJG#iatV~p@_j3jgO#Dk*sV)g~$ge*R`GdnSyq!Ld|Ddw*JX(dASHWv7bX; z!hMeIO1;P4PqgM#ZXNg$`iOL?Mszhe^e_Kx?q31gStgp_(7N*VZvNFg1?MBIm%?#- zTB-Ng`^V-n$Q-$)Q6Hmv*-X&qpTm8ecl3qUNz2ZIKXMS7_l2ioA7LI2^T!pX-YWSR zS?B{l!aNl7M!L{PZo0{|l7+nH)=gv~k1X(!vu|=$iL8BOHZ`Tm($i-0sqblYf9JpE z5E=p8{0{E(x}$HDK+D!W%`IP7KqvNhm?yz~H+9etBD8AxtS<0@AF9t(M{dw-YH4gB zi%ZQ-4GrWjCvqcMOC$N;W^$v`=B7q+cUfagn%rq)@p)z^_qhxF5bd?S(3mEl?&fp* zxj3IypC^@itK@Te!A@BEI zO$}sSuN7xDaF=#*zn2{Sqw&$QCGb%VSoyqo9`+mN1+;&W8Y!^utlJ|lzOY=ySzY$8VSBAzRP-P^(6E$bs6_@-q9CYDXnWB{6SGf zKXf$ceT3uSic)VCeGC`qq_8bMhI+|K(5LorAJ-jyp;gkd>)?+RgYNBYBlZ!_3t%3R zQaDxgQCgr2BL`nJ`6%fnBSldtm)gty%tE_EwDBD++ur21f3JZ~%oo5%I6ufM^&Wda z$@3*mjmA67z?aZZRi8pPR)9XWkNY?c?KQd=ZlGnSo85d&ZNhm8*F9kWUQp_-mXGSf z9{8d9#~1cm%8dtI>T>SeilYw{K+7(HA7!HcO`!$*2KSZ0y571{Z?$|gE$o3Ws()oY zz0<656JCT8o=^u;S8zXTq1}30(6_YCy3KBRxClD2Kf`${?9Umc-fH>@3nFskY<_~C z-f^bha0cblS8_kQpxrXu@Sc{o`!oFA(kZ3hs`&{EbxIq-mq>nsKGo0| zuHJ|9pG+tBao*7vS}m<>9{f?_P(OBDfPI9#1V2}ldaLOpsuyq~!c`w0HQaXY1Os^z0;K?;0P^AYK#CmBJXc^>yM3+>f-p?*cn zW}o4 zeTL)vg+e!{)LS*5l?5sABjPh#kaB;b(d2Xf1>EP7qi@t68dL2>Zuz_dI&s`reXfOm z5WZK-=kfxRs25&LewX!hvDNJfM`Ss0XI{wt?gU?;V#_NnJDGL!yJHK^YdD_4^LCR; zz18wtUSN`&3cjfME$fNpu1`23&uKltUwjeweaX>BD7y}R%0X-1&s>ashvOgIzgkl2 zt(Ncd0+Spz_@eqQ>*ce5(3f)D$1Jp0h8o_}ve~U}`MU->F=Vd@TF8pZi!3 z?bX|XzNKaBFLleyMbL@;TwRyyQ0lFgk521S#6NMv*(PKF`B3(+hx=E6cB(?nXIeJj z?&e?ZcASSWuY&skrj>fDlLNmYWfN1^>Xmwi_TBb)AcF!iAX3H^m9K0XtxYEyr*Sr zp5vCEbD&d><8a?uy;5)0{Dk!;rH$ZA#81#GPey{i_5k;>1KO)_bsuTjjva13u7gha z2zd$fp`uc6HGPCUliLWs=zIh{eln7mhH`az?&l1&TZS9n)3UQW-TZ9dh4*uqU&3*G zQK`3Dexh|Jsh!}9>L=2pCnR}cC|5VY{akbOhnA*gOW+g78UH)K8~X`)34YcpoND>$ zv|h#LLHq_P*9RoG;oI}e$NRdgxX&5z!{}JJf%@Fp;g+{`mtmjbcn|lPbSm{$&1aYO zDsi08rQ9EkH2K_qko!FA=o@vL`n(AK(Jw6jruNume1w&Cna{+&(-mvtY@A( zJs62B2X1kY`&|RRDD~?;(z5BjZh0N-!+yi@?IHnAEA>{(Z+ZPmZX@`j`Yr2I?hiyF z&uKltpBv)77hQc6W#_<8IcUxM_RF#Fa2(t!w6jXR)$(0lf0DxnUsT^^y}T#@`juhs zW69AMS|=@A0)ONnH1B7w(EA9-!8(OgO&`Pcr!a8vMdxFvm!0Hgq1?&{_cH_S4$;PU zv~2cDxA9;NbYi}%u2*#_^;XkQY5l3(R`5mVr=*V<3guP`+|Ma!cbRN{L(5Kgy7`%Y zF3wMwm%(}Myi#vf{3Mt9O$%1w3-S}|QwM`U!essrsZOlv^9;e$G4kL#w7`7r-Ye7Tw#f7hyl)_k)#(3=~TDB(VmY?&W6Z<>lCmet3m3ph{C*+&d zO7KPNC+Ia#OhUQf2=}uC+AXn7Z)w@iE;m1eZhd~j{eDHI-m3YD7NWwIf-ez2kv`Sb z5*A_apj=In`#J0C4=GK{&Vf$~SN)jZkNt$>ILwQdlzOY?r?PMbenfoaH(F_*{L5_G zOrF$fY-yp7NRdbX_>+Iz&<&QrtvSklE;;%}eWYb;d))GN8Fb2VAI|S0sP$upPaXQi64cy zUv%`5mZoJ(;3vl!|GU_aeTU=R7ExkNskdsr%L`Ic^x#V*&t-k8<-F$2o5*0Q5^QkDF)r!&H=rTa6DX5 z>aD7e;eu2-bnr#%W2l#$yG}=(yZ)NZh1KmI&r*%`7X>WQsB2}QC0nv z7NkV=#I~wH5SS(y`1~n4(%_K&2MPg&Vz2gu7gha3VxR7ze>GT@wKV3GtoL0 z)}tG*%05nVA7`PxX8X!pXxZ68Hy<-Ycz=g=EEqqRlzOY?qsuxL_0MqQRoTC5xPNPo zeozx>*;Vj`eqs4HHH`g(c^0f=)hL{*`Bz?-!ohNhe9`&|dd-bjP;TXw+|MGkTVk8u(z25UH$PK{ zaDKvmeVTyJD)m;+Pgs}2tps19eu5s~cm?{kS8*Sg9DSj+(y~k74-O;psW6Itgn2#8 zi%LqpRrL|_Oo|$O(fSB_&5c)3uJmf|XDzf_Vw>L5vUOu_dASHWv7bX;!f`yK)LS(_ z(Rx(aQt&0>C(=i6yn=G2*Kj|(pxq(b_>Pv%kGuI)kW z#;c~rqU2oJ=WDso^Nzkz1TDJ^{z**T+v&sDXE@%&^Hj@9z18#CVf_k@^NDV}()*mc zj{95(e(20nzN0>8j=1G>P0{XiMya=IK9|>{aN{8VBI83@pWwzTY&ok4_#Ln1zE3*( zNDI@l^WZ0=ng26+6#EXxxhcvR+yo0R8;yxsL^Cuf#OHrDY2* zcJs0BB{+X!UIE9$8KvH;`WUW9m75B_XnhRzl9RkBl$(D8_jAF~A6lB0T?C&v&iLQL zOR=Bo`qipZZ&m%2)}hn}fInJarE;pVP;UN>+}9dtzgmIjGc8;9GPgWk0G(m|Dx=g} z6<=GLldWH2J^H2kvX5`#K6XKSHNL4|(Xw4Hck^)_bizk<{c1|7w`xARtY1<8#QIf6 zF`?|=H1}@~+NtPtA8FayNjLx6ufh8_%x7W!YDuZLYW^izzhZePuV0z(!r!FlMn92W{^fOE7Rs%@jr&;-?GDk#ceHH!TDSZxfllo2FmH!-tPZ8#s`=@%j>YFg z34ei|Jn|zgWR-n>JNLN=ei+>iH_);(Q*J(YUWfA*j{9(b(2P=V^?Y_%$AaTiqF-Rw z`&>K2eO`6+jk?YH=(TP>FN03xv+8pI{UExrYCf0Or9{Qz1@bR4A1LeHe}Nr4&MN?Z z_MP1KcJK#>q5VY57GLM)d;9Bge#1O$iy#-2daLHUye=iR5`2mHF6)#061!qP@C)za zzArlZNJFG$OW>yzv+nKm8?f(iJcRqO)|7gy=DWNuB?S(?M0}U^(jo!qXWz|z%s_i3 zrs*v$n|Y&K{;q;fnfJo+uuG}8sy>G6Qst(CFIpc%z2qb>3gu?6=YCE?yUS$r8(Mbi zO>TZ>rg2`vd>7^wb4tBc^;24pQd}}dH$<#j=isBBAe)U*;RdNv)sh8kMHF^)NcpTmNRa{9FQ^*x%uJ1?yQI zO1)L{5tdbyHi9oje8fMhOEt8e+q&rzn0wGRg5PuR=l%uIPSpU-XIggMQ9tu`>>vC-3;eD^O5s$^ zKay8Dscqm##6PM_wVv0?{uFA^W)cRJTl^sRa|+t6@O2+)+36WKKeO+|c?shq%!lTcdaLE< z-peoEwR_LbEj!pR0EQU~zNq=B=u_$Q()3?shllb@AL72QIQm3=re)W_FZzY$-_*OX zui)pCp^U<*im&YVtak0=*O(v>{tCVzUy+`yQ%glazw%-3V;b5kX-scv+4Q^J@^b}r z$~*|h%}%A>s`&`>8l{ooOT=R;Jm|zY0P`gHv)Ogf z4?L`(Dn8@ilM*%a7w`r7jPp#hT?1c7)65~5sw(~=7J_aAg`3mRdFrH2- z^;XYEnE2pkf-g}YK~E-1Ee*};ObN=>e@g8CuKtkfY1ujO35OH;)cz6dC#=80I_8p6 zZ}t3yi4P7Le2MxA`V?_9oGF1mbA#Bw9ets-(y}G+2Zs^)H2qP%kFfq$r*Nw0Bc3RM zA5s6Pj-8~Fzv_L7@$VUD=eds=Xm7-c=ohrk%$(c)y$(7tPQrC#7%w}OdaLIno-mnx zq`L9~QhCA@ebYwrv^iolaN9r4eVznAqP9l9p=D=3=H_$zzv6rapDz&9S*6~p`COhD z;pTxak-RPIY3?>fG8f7fZsdNhIr>9ur)5jv6AmZxY3bwGPjwuvRXA1iQ<)g4frCF0 zUzKu^2~~M!RenSKCn>G;0Pu^S5#t8->z+3IE{lM8R_(i%Px6-oHz?Zq2oCxuPw%_qn^a=CHOX^CIYk&u3Er`F9R~3F@F9 z#OMEWpBqIW;stzi_PNpE^DW%xcJKpNqy0qd&fo0jbNy#=KC3=YD)s)K`z);)(Z(nC zx!K_J=ef`Gj=n+N%itgV!t!tWb9SHClzRWqea_&&`5= zKE~a`a1`{37#tHyc9(iX|1Eu)``Q8R=U-d@OUrgGy7^lBWt_Kg9DAau zVN$8Ls(HJe+nkcJyBhY#(pR{zbB;byJE*S<;Fs{n^pgJy_7(0oh55pY zQg2m#-LZSur3Pam@3g++a>!UHxAax+YXI#x86(}2onfBPuGCu{ zf7!a^C0B0Qv#l|=b=&sbmc2WnapD#H!TGBxXUf}ea$k$keuc05Nb8(ha`Uz3TR3mw zz7{yH%_;RBYhOd3I`(Y2bmx}bp0-QKTL;kP4FS~jcr$s#yodu`%B;9esw~-z!b|Xtt0z=H@}ua zC;WPl;67Nq7LHFNzNocp^o9QhrJGJ8GXZj~NFCiac9bitWx2k^bY1`4ZWv{!R zLZ51AYDjOE?;;3~BkMolel9!uLp`Q`u7FSU3(LQ$pX&XD^^|p`-ed14yPmaoXKve$ zEtlqYU%s#7@_l>NQ8V->%u{_ib;1XE8r;r(O+ouD9>FGBHhqU%p3Z|#?Dug0I^=1G zQtz?%^`LZ?p!4q_x(^Qg1bUlCuqb z2=nY9S$t8mD)ck>G52d0+GX(xHqkn!{>#m;`k&$bwMIbTd}2YV_t^W@Gt%3a8zTQ1 z%#96o4-U%ig}#LTMfI|q;CJvJV%&4|h1x*NE`vY97t>4U&#{ki9D(EVx>E14_i^V= z`I!>%A@q%Hm#tz=16{Df{i=g@nHnyA&&sa4<=qtM#C{6-2In1VrQT!j*WSJ4QHOGC zz=zN;w%zR4Pq<(0(5^Dc{D#(%zSGUGMbH`i>Qd^hieHVAVWOE@--u2%4s^j!xo<^i zpV_YR7Fss{3pd}^K_`5J{DSk^8KvH1@7uP{y?b1I<2s{ncW~e4p?zg{%x|b~v%hrn zE&VH@Gx)Zw)O+lGqx;{^E&JNBcaTSTKjk{vJJ1FH$$eXM^ntob%dUVQ^b5$U^QhbR_%)poYkNCQJsxjHRdhlDf{cj3%;(7zj$6$Ru z4ZewPIM%-8audS?#jwx8htMy&J(5Oj-(jVG!Skpc+7+UV?`R$A|910h7Ib2qSI^VC zlzNY~U)YyO8kK$N_#V%rj;ANfqxSpUd|3va;ks23d=tHJtbNJl+IDP{M(}7JvF(vW z0$uP+aomG;8M7zcK+6_?=jKx`>Uq+aUl9QY;TFuipA3Hz#EcUe;Et(LEQcjp??EzK=zhC;rD<0bzomr$Q- zOgC&!w;z3F>b%8E9bkk4$OgQBYGT^06ifUO+LO4TQUEyp2HzC<|A#*E{zwbIm+yz;!inPe zz*`3GgTUc)_76M{I@Ep@LQ@{piv16Gfgukv55#$3kd-mMZ=gNC<(E(VzZp-~9svEt zBNx-zax?U!OL?>L%|`uD!LH*X%qeQv(MzR}``FaHiAvBnYCBTGFJ+cf9@j<=_l@=s zjvUE#j~*cZ@9RdiaQy4~BhULK$yK{F4|jR3Ajertu=H%vVjmLHyvGYu-UQ*H>tdtKOso&g`GLFLPoXQS~sd zQ@?lpyn2$7ccS2N0bDTx5_fEQogWuEARY)5WXfyIW3uT@Lg!hJJwU&|diL`wE=dzwo>Ygik7Oqj{BnuxnoNn&CJ( zS0l^bIfK#sUY$@PpS~Ox!l0;IDH&NOmx@A`MMBnSIhZ+hCGQY4?0smse9|1 zpJDJ=Z-xGBnVW>+bE%_4keU4)3r!Qiw->qWzjWDI7>Tn z8M|)qNcYjP+~7#h!Ce1nU!N={@1yk(JNg5 z|3aPJx3VtAud*)2r?M`_pRz8-m;S!d?t!sBBJV4VhZaWik&Rt+6bm)t=8;6ArB>h zjTg4w&I?_z>q0j)I+7sK)>?F^wN@SK>qvW{UVONUj-zFr+*(_`a%(lZv4I1_-Gijf z!#(ocI1=C3_{gXv&~I1F(9LTY2X(zZ@3~IydYcZLVXhaOVb+B^1gll&8yVR(i4ye% zbl4l4PEHhy4tZnIA#W@?{UZ~@y<=sJG!EHR@!UZLT#gUbuBzg>6HZ)JW#Nt#j_Qn1 z;x(wu+yi~%49i<+^4Fw_=kgZDaaEO>J1{)J1Gf5WQkl8K-J_%AstQ^PhbPD{eQ4;Co@Bd8WsaMSembnOf0$GjEN#V>dM)j|uzh+} zxIH}1jA?M8PPbLAN8*e}4V5^WtwzqUx!=ad3z4lR&S+1!vERnVqg%}!b6!)9y4A=T zRs)j#8I5eUaFi+)j zrTwYg&OYsY4t=X@SNHyrQO!KCeBVg-erbBAskghQCpR*j>+L%{Ae|XT+uPkUB7yYV z`&rxRfArhKi+P6aAwZA}y1{ZqR$VC5aL5Hlxa%#X*>$->sO0Z-`l}|$DO7LYSkLG{ zfgJ8p5u<*5w0o#9LVk20Jm%7Z8vTI-+K!w82gN~#`AFtMc?HC)7s?u=C z_Arg~+pT#>%I8CXx&2fZCYV(h%5?FJO$?Fy26^|C4Knk_yY1~K+rv{{O?`B`OZ%uU z4BQ$|h|||+^_$e=;?gq{Fu_N6De9?la4Z5bVCpgle zlYTMYsJpsvbi@)@4;tvB_0a9MexloLzLE0*=>VYPlkH&zB2t4cOo$kr3N-P;$W8vS z_*I#v-+J%>X^C%CdN4^B*XV&Tdj0k=9Nl(#pfhX_E3m{#2P(0-{9@omc0`jdjGQA4 zI#s6io9x)uxX5;=cG3Z&3=(g2aZ#NLH0jg^7<8&k*UtUYG|jL*j7n1vDIZp&*)H#% zIzHMx_2onR4BNv1&Hj>lT*m1hqO-QAZy?;PYY*8ThNFp>Y!3mt?M3Txpr@}`u=9(B zfpWU(`2!)q>=&s=ZYdY)dDiyO)gQ4KGCV?-fy%MbHyWO*&kc{Dr3h9&uAExJtY?cW zk-%K^y1-(~DS?^wY;7SyT%kT$T%w$FTy*g#5|*VO%X(c{vE`JobozlI=}BCTpLDxR zzEfS8$RbNMyut3Vv4Q@hx$&cg@SI4e8?hgU2S*Mxq(wF57d@vTtv0}$^G71ikn!t8BV3CR##QFX#26a|^3ZN)d|= zor73)PQ1`NQ#+*Y)3#GSo6yBG7EV|6<)vAkzI+&?c6+#4$1jW=3Hwx2o@@{MQolW{ zK(~E#Burq#_OJpGia{4vWYJBK6(#ACGE?e!L??HhMK?B4D3H}jNv+|L`v}7D4BK7W zNjV|N+)nwlO4qMsdsv+&9&|co*d79`aX8JBNqu3nboCvQPAm-Do#G*!up)EZWY7~E z$&02wvOTO$zdhV>4ckM2H4Z2LNIYS)boIp?&&C~(XX96g)o6XWT1roC9M=7$w};#< zFy2=T*ZQe7QBJQ;rqhk~4GDAg9I`#^22DL=d)Q#j_9NY+BrjWg2PgU@$9OebeLs1Ewl8iSo^T5z>~iw@2GtvV-OXtO5% z-T~`zr=M)Mwx4Xb^84k3f~NldF{krW@+(kbHJW~>+e3k-9y*zJ7=QYiE^IM%UzcZG z7uIOh4US0HoHcRL?P_(p_EDW$olZB@%|l`T)zmlCE!C#oF4dylF6Eqldsu;fdsu;P zyZw4{Ke@zi=iBG!{p4?wg$C*BAL+I8M|!RCkBo-5*XjDF&?8pT!YH))#cxxQMdZCE zUU56i#4vqUxld{vEvnN`jE55!!*=p3`Z}747w+MD-dGYIx$%Nrephax&~VX1+1l;W z1qH+Qu%m^~23^?U7Tw5x!$C*i4`V&@iJ6&uWYlfkVmg!2(RLl^9+E~1!}c7WrR(~i zaU6W)Iu&TB*THYb8+71l&eC-4$WI*TqbD(1` zFVbwn9*1s#HuWcs0}aq(XN=RU1GQD3sGX=gjr;d-!s9H}%iU>?m+92zS>w<&&!!It zU&}Z_;?;GdmFw8PM8{bgN3!jl=wEoT z>ZK9eu1m%}ECp=i5?usr*M|Ye=$yHuGdE3O@5y$S2l&gvcN(azdk%DKfiHrg9Ld}3+$*yxy(?&|zNP9~asq&k^s(Djgq zZ=|E8vE5vUQ-x){m5VKk*XIuR_2dfODl`sF{?ZT5}Fh0CERt?}VcR$Fby9$Kof8iwpoNDL(590+#IAFS4<(?5hZ4}LbMp@+ppEC)UX*}V zo@0D+0-AXvqhv|Dyu;abF8x7xPVrHl3r`Bpay%R=B)VQserp3ShM3!(XdRz%bq62| zKQzJKKJAR(#+7G2F}lbB)22_>KHXJ8+wuNT!uf~ps-TT8C8yPIa{XSt`NFPu?8oT6 zCQt zbm(uj*mU7tVdj1zJoJ!>g*WKPBNGB>g|%LCM@1;K)H_C=&?*D%x-dekPHM4T=g31X z=AoLo1^Uxtz5Uwkv-u^;X|vFwoHiTd%MEzON$+ro?kx`W`NcWr>E~F#Uz}t8o^g8m z$u2s3_&GM<87KYOU0ssKHVZsnrEI+fFy>Q*k=`EKR>;?yOnOMSW|bt~r? zr>CE~Bz1~YlcdIS{Kp*d-Se?>g@gKW-7ZCn+v|bxqQwAMI&s zbXb?}p}M@Z(rx1%a@4u3a~~ex-$Mn#Zfd<6N(HR2<(uzZjn;j^qBv^$Fuqt{TR+m!6C#iHDwyC(rhrU8Az$ zoMSn^I5kGb*EisHoG%ca%W;we3!zWIcbZQT z{}Room_C^=WC&1q1FJ8E=rv=zKAfmqb(-BHMxQKh&F*03`;9AOjig*8u=xFsmGc-^ zNI8vhPW5R9X2){L<2;n`e1_}QL^k&q*Q-0MMW66Ig?N={KVkZaP4;-k5{!S8AH6v( zhMyoFa%Y}&;%w$Jo$K=(J%`EN0F4gUF@-Mj=%yu(fkx@7OpGo`yoBp=oFl7DV`KOs zXtFQa;}}a6M@zHZLcXKg_*5T89;+Xd=@u^4CFvKUcNzc3s4jsY{KP^GSLGLT+=deo zQ8KQa`#8kwNk0Dba*-X>DL&~0#YyjTyrA)sF-M&!IM(OaF7pA{-e2YeaBMk4pfTl) zhQ^jN7#ds7BThO&72Q>SvDHKMkpq%Lf75bF_7|bY6KBVI3^rKCU2@x+d_wP3kFk4W z>harO#>jr=*Dk;P#WrEJ=Lf0J5NJ#}qoJ|oJoXnhK~5ego&d$?iFP7nX%9Q#32gZ# zPOlyy&3ZZpYEB$u+ri5jY_{Y(FK4hhu3U8D>lSBp0_<4MBThQuj$YV^uaA}U@RODE zjMK+YTAz=ftei)jbi&-LPM9tE%=8KJUppa>;YTLqX8n`9C+GDooKBf-YR5rNzF=+w#*2fFAN zql<)K(}Qfv6nxt|N zF>!%DVLj0sknHu8^-1diAIb?GQxE8q)&oAc)&u%v^$e09G0@~3t<>5sTn^RgP!2pP zx6QFWD3`Q8@Fr<}P%dG8<=jeGU%6b;`oNc@^+CC$^?@%*>w|L1>eJl>NotPGv#?y! z`oNcD?F(#1JP|m%+FvrSuS@SZ~ zqdI8em~s&h9ra1;0S{c;1NwyZlyk|kp0Yk^Jqdl&=UjaML~ls8_fJ{x-X8WxFvzN} z@>7t;dYGR6I+5;IV=Vb5m7{m^l{-khiLX!dkQ6B!Q_k?KF>d7`3FTPh>uc7`&g1Gc z{R)p;x#WKGU*Yj6=jo^ES9oIE$9{z;VVvliho!&d+sRFN)UTfK8F=L9NhS&dLqo;| zL+5hJo*P>(G7|A@buO2*KHW}X-VZ}xpj^WGObeTF?JJi{TA!z%<%QIw^?@()AmiX? z`OfcT^+g`qjqy?F!%E`x>Y|gIKAu0=+c$hz^2o%cfBZ&X8nWw1XG=`_)~+X=l}L|& zP)IInuLqZtqfAmxj@DXETGF!XGBIHz@kp`?*5>*uddt>)*vv_)PE0C&4#LaC1M3c$hwfyXfWM-Si3hlKD=2 z>1H|?z1+EO`ULTl&PwDz(T*$eH{3BCy3*tZQ55gC6~Mqmw=fpX|Je@}KKb0$KehdgX9q_lM~bK31P7{|UcY9vtHO zi|Ui)Khr0RKT&=Xexm%O`h@W-hcl!9edFX70L^KRDIbJBa@r81kDS)n_0iLr7=6Nc zqNgub{usOcQ1jQ!%;N;}X^gcaVY#91VRFlV!u!7u^pW2QpyeV)(7}fMGq;bIi*yh# z7FRCXQI6$2W^;JXdlwG?D6q(?!IX*d)edi^v!&^E2cfs%U#y^*q<)Ld$v_CT^Y0M z!a0aRcaV%fXeMOQ$v^L8YCq+K&GW zHl5sHn@(=9MJMCTJ`cP3H#Bk>{m{OtUZO)c;#zc4_L=*G@Z@E3V>`%SuavvPrjxtF zrgQR-{nboqmov4O{3flOe#Ux7Mp1Yc9SYB)le5L_^T_CU-`IE$4wAIX+#aUK!N%)x z(D8a4e60TJgz=NVf^J3sn)Ozl6s=V!MQPK?*=^NHu3B}D@yS_i;!O+}dJan2Yt=c# z$9N9D6zQ*hOFOZtUaFI-HI8dkC)r}vN#U7wI6Rw94$r2O!?Wq+@JzZvGR>NB82^|~ zJ`FSYJlH!_>=}!{{yErB{;ase^~}M+BZVG$;$fQ{3wF zi}R3YoQFK)JXF3>n71nYuf6}qJmVyf=6d;Q{Mm3@p5-0x|DsPC<>hNBmUg2*h-cMF z3sDx`gkyX}7hR3Da}({ygdgn{J3pG;R=ukq$;QnI-9nx{j)d(@FwPz+kR?3np>|Uo zOc#Hj4mtcC?jCgF5uF3?>Ym~8+(d)x`tKmuO96Te)agv&37zWk1YTJ2zqb)LY?MHRgEmJ*qZcg5O^l>Mr7YSuNbLBwWYy zxuJn!x4fh}m%J3ZNa~o{MfFMgjp`$COI{K^8Zj(!IOQef5g#HU*tiMXmnbjE?8aq% zpY(I|S~pF2bKGuuNw|sfa%6bG<$mlTt_$z*H^n(}Si8(%Y!}mOI?&43bf8VInJ!!7 z(Iu3XpD3Q*-iddd27xaEHlXw1V1g`!m%= zu$KLw>PcFJX!gz=H`RBS)iJtAATjz#AU3^pxy{->`PaN{JSiQlJbXsLt*~<=&9d{u z^oh|$?2XYUi$h8`D_5S0+kB8`)@B|3spoQfS?ZN*we1gMc{1@T1I_g^U1VwyqmOhz zydF;&WAvoMob`i_?WDRS?WFo7?G*Y%aVKe~w0D^Mz5Fwz<({|ir(7RtrZN8}(A5`n z98@P$P5mu&*fbKdO&>8WMjwIO^-eyMxSiGygf0?-rG1*K9acXQtshJbx{V)Hmt_5k z=pB7awtjG=dm#K{+m?Q#x^VTt=okJm3Nw%DB4Y)SoAQ$C<#dnHMbg2h*QL8fkGjF8 zOV~b??lvy*AxZnR>2Bf|y7!OCx1(5fq=B@{*gwPm#&|j-Y+@P3VL6Z)8~b+P|S<(kXNNxU*4IYa&*4OfWdxH4(+`HfNdn9oDkPYgPvQuy&-Zk%d!AXvvQn>ec zb5BL_E-2jlyt&X~j$c!_XHWa~+i57?x|4ao!QQfZ-aD3%!0|&iI2|dof_sYicIxim z{t5{kKV*X^B4u81VQ=Yc{olKh!0|&iNFn9467O~1@t%RW3kvsj-rO@0cU9rO$(wr? z;?_Kp=L7WH*S)#tAZ}W4VKkch>(bAW!0|&icoI@}3N8#{Pd)S8Un7Czhivd+y_*NSdIDW_m^+-7ZFyDF8+PgjHJI_Mg4#9;yJNSz8JdZ;cF>XruTNGS44*4H1vMAnJCEh{rc()+# zlENMK=3b1rC51cc&E1N)b&uhB2FHufyvMiS@L@bFxX^F4|LJ?2-^Sw2K8)`ddBKJK z!apA_MLtX`@t*7*Z#&{HDBM%Lx!VzURpCC?oBM3Ut$8fYhck~q-*Z3Sfw*bGg?vao z#_69#0>=;8;ButQ3hpDsx9`pSu18&gxLtx< zE55yO{NFu~n^z+4loIdzyyNX;+}SrgfUO_SDctvabDxXiT~fFo_U1khan}^?9p2m* zAa2d$c%H$$vcZek#+v*2dU2=V!u+@P zh97vY|K?DolS;hjc*om?xN{2k$==*<#9danPxI!Y%Vxp4;KKa(eJB3Vb3aCxp@P(@ zIL~hQ+GqcS8szvP8}uP%yWqlc^YW+e{|pj1e#i#>NLf(go%fFS0OHOl+#9{QdBj~* zxS#dr%6Ewe!J6R0e!SH7&Nriq9Y16P{HFqIAJ6jvu8U;$UVoD#3dyp;5c-@JTsRI5 zyzXw#{2fNzPQiu!;;Q3(xg&@>sl|#r{F`*Ng4)w~K7hZEIR6tTp^66bT$ZWP_I>WtZSW{@%25=kZA3_#qoiBIT6eLjD$haQlf!;P@dMT!WPJiVy#M zkT3TYh`XZ1d&oQ9S0Zk3I?o62Va%KRD#Wc=;8UH{N{;5ylzVw5R zDS%|z0CPJ87xMRv3x_6A0ml#7;8#dFDY!8HKKPVRdFC(Y&Yi>kovT>9cky_i#JMXK zi&t>LjWc+^!T$FBR~IK?Qp z;5SG<}F$A0L_Akw^*@w zk2{XmIxqTdR*Ba?A2>JP#Qj|q+>P&V$Fq3BsWric{cZaVFY(L=&aG?a@zy*U&(Hk# zw-Z>rU65yj3-S8rFXw^}9fAwv@5zO0o(bEMyk>)wkiV0H3*+zQm-Q|r;el4=&MN*s z^&h{7T@Q*ly=H?4vv`*`@qSxU{PmBQb0LT|!F`Yj$uBX4X$ltnpo@cP`dD}TZ zKMCqg@|q1eccq28x|Da6ey+?&0*XCm&D;KF?h_qUFF&Qs4u+b z!MTXrA-Hfe+Y|5D_qrH_c5^nk0C6W3?sxyR*OPl8;?4{1*&>R^cMomV1{CvUHh3oD zt_d#8&u+T&n`gx!w41ZRvk-9V zyx_vPGc)5muD2oXl;Fakd;2pQPmKvpyEz+Nin#NF3*+xOKlY7xJK`=YK6IVr%Y6>w zmK5%OZ|+XSt$jMqvwObpn`gTbH=}S%-rUO&w@Yv#&-%T6*o(N6f(zs1=!YJ;s!gPr zFSEgwh&wO1kY}G-^Ua4 dZ=_)wSc{NZ_sTM}FtcV6`s-+Xuh<1Rj)->+PEF3z*p zdUIcd;>`*!&c}K71aIyu8MoBR$A@}_>wjMOY7}p~;KI26v%7us;abEkDBM+V?sbg2egXGk zMsQ(&^FJ?q9piRf$hnIO*Z;im4akQz#fM*c`|u{ltsUUwWNjKBH!t~D-+p@wiZ>&; zu)qDI+jqZs7vgpbE{wmQU-TV+uV>uS=eZ9>g}dm@eJ|q{E)sdBaQ)8%W|0pIf(!fG z>kj(%+XoPLRpGwDoBJWgUE9iisA=GN2K$@;yyPQ{o4tf{(+byrUNVP#=oDP=_g}ny z_*ceV*}~(U6kNz(|M~hSP`tBBybt{PsOS0orx15Z;hx~looC$19o&bK;BGu0Zsh(7 zZe1hJGyi<~vS)o^j{D!{pE_3A~&ofX`gCOkj$U$6cOpw5~2IJ0&`A$*s!GFDaiE&~1V@7aczqt8E-~HlN#9dJ0{qBjr z`^C2rcSYge?#=xH;;t(`1fTQu;daEWYsUH8koA48}u6&k;AhiRT%_TXUmtysL=YCAd!z6{jA0#d9ErB(K@vPQ;xS+%pB_VG}<% zB?%9-+29w5yQIW>@e_UH{UzfrU%`(T>k8N3hhL$1>sxrgfe$NNf92`JU5q<r z_0ko-$G3YBw_R{y{5}4wzULReMcjhIeXuw8KE$07T)1xfk+*!_^Sa*e5qD8=VP10D zHeY}L2XR*wA9kgEk8giO+?ou}2RP3<=i9@c=Y@Yl+_b`dnm6~)h}$W+aNct1D}4R^ z3*r_P?oMy+UlDgk;hyPzKJ<6QT@YLtbU$_IZ+l@MPx4CcuSVQe!G-;JcgFX=m46~` zO)Ji`_MiBU5BDQ(T5#dMs}J0L?PQYngEku+_W*cLUptg|pZ*2k{q2E>TNGRvAKJG2 z=I;rJJ0rNTU)-Gcov)vSxC=_WJG|q4FygK#+-G}VCwmCut}8xVHtg%~!w|Rb0({)O z(wqAT#LWn9`Tml}z3DVL4_)79gGVB6m*B$h2s|d`J3c%bai;_q#+`%ffAt)99*em1 zf(y^bUVrx+JbgG7aaRNvZf5)UADoeL^;Fi8`!W$XxRB=q#C!A}-*}&Zxb=by@qX>( zGd<%y4RJdJ7y9jxcfXyExJAK*@%QjOzT@xtjJw{!=j$_q3*)5!x?BU}c3j4}3kuhN zU9JiFup+oH{@(s0-*IOX;;t*)pL%mQGj8V|?nB)(c>aRF{_AqBDBg_1J@igrA1*}P zPQe9#|Kl~j+-D+gQQ`iVH}@jMol&?ae$_YLEr`1yxG+E4`5WJP$yUT&Rk(Y-xowDB z^Gu#+a2)#Tl<#q<9dXlw3qBn8F5mg&vk|vbaAEv?=Lvs4Lp~0;z9+x`i@1}53;8=V z@4HUB3vp)^9}a!Z*M|>f~eQjxl>wn*CC*w}<;y!c;F66KO_3q~}?wa5h6|VpF%@;6ky|^wttN7r5-|LGQ z7xtq?g?s7^zT;#U;;t$_ysO^#Ja#|g)?CE%4Ek->o7>B{Q#*M+qy-oD3;*l>{fwIt z_f>QVE{r?=_owC=cUo`@3fKSs)Tt%Im~m&s{Uxi4 z5B~S378n=yiy+JM4CdAM-0M599%J0v9QQXRxUk;mzpgQX;%ygP$lve$&UZgP!nlhf z-n`&K{`#+L97XX?De>O!9q-kMJ14ksp7rc6-|u;T{8GkkKg9cOS#V(<<K+ck(=w*?=MfA|^S`OYg4H=}TW;>~>};&uuy^xN2*ef#Y-h&w5`@ci)uetO#t z<$XNCn{03$;?4^$JTLO|Ti!9809Te~gV!SNs^Y`VzdUhYS)AZaHh3N4)?Cc<0oJ+R z*R+&MfGbP0!Rrw>Ex6EcoB!80-Zvp`r{KcxeqC_g9q^NIX2hKnTo`|cz4zm{BJPsl!uWgZ*M0Znw>}&LD2hR-R|z!y#`U z-i5gJ3ipUN_j<%_7hLf7e(&?b_abgyaABVM$oqWH3*U#h(+c-AZ|*GOE+{@c=+nM= z_I|`&QR4k=$=8PuB5rUA&ol7%FW%e_Gj1lskMs3{3;FB+dkP;#@wN*tj5{BBjPJNJ zhq!sch5UWVwZ8Mde`VbD=W`#X6o37%OMjekJ6^!K^9tAhy7VWI4=aKT{q~QGe6PQK zl5uAa^5+iL6@UNk?e7gJ-nuqCKRa&9x8FXExEaBP{i5;FzUz}WF>dWX-fvxk3;z1w zk9afV7Q}r)lM2`WKD^H%A7&MQ-|784`YnjNsQ7!;Cw=|>0^+VI+=4gvONd*$jprH6 zQ;&ak#`8YBFC%VNaN#0h?e*_%Q|Cx7pR>VNIrmbYX9dB9JoA4J@N10QDY(;u3*)5! zbAaDKKFkX)oX?;91mAr47UHf5E}U;Jy!a%~^MG3sH@KAN1H^lucf7YDZoS|_ykGjf zZ@k}T+pi~no$n#;v=Z-Qy?>wJ`-nTQa8L8*{t$7O z1sCQeolo+em#i}G+6do|OM(k|=D*H$7mBy8o#!v~Ti30={q}3b%?K{!*+0F159A)i z?G#)%9%qMq$A|k6cT#Y{-#_j2U0?ql;?61Dzk72_h`X%#`)=?1jed`~CB@&jc|Uji z2gY5#gFi=Ax1Hx1^xM0=xqn6RW(61ax3+rU{p}x!+aYZ74E1v_lbzR zsQ57A{rhrfAnvN*!uszEPoFze-XC4xXM?jDH~V6q4>ixh^T{iIO35{fr1xbRTG zdmet!^EysF;&urx>=!?OfbTlNQxSJkaN#`bzYl(?;OeQY%LY$J+<7J5-+9M-9^)>) zj`!Pg#o|q)c!M20AK{``eo*Uvs-_U&*>`a3SNaiu)?olz9Dr z_u!d~yYfojZ?!w|{LFt|eG&2@Be-zA@W+pR!MEl1xxUW^TNt;n$bbJVFSw9rS9l-a zE=KWA2`-!mEG_!3uWv=%dBxvTy`R6h1aVgc7uE^B`ks?L*EQM@H`s;qA>|$KHpHzL zT!{B$r#{j%-b)d;LvW$r&VRh`akHIq7yii4TZ&4&>p!jYjQ2Sx-dVwg>%67<$9i&i zA?}jk!hQT#o?ZVW*L_UZWrGgHEeS5%NBZe=e)ASt@A^I)T*kSJ{CYs$Zk}flZ}U06 z@$NzKW(61G{cNvqyn7KhFSyWefA;RTD-d^DaA7jO2nNPTsUq%`5xc>;<<>s zqHxdk<~|>BgAP33x&DKLzje(mS(go7h`9BF3(sL+^7Y__vflN5Hh2-@b}I26`H*kC zImWGhJ3k&zRxI8w6z{y?!o2!B&p+WSu5Fif*`S+o7e&0Qf(zF#{QcdJ;;p@m=L5t$ z_X6K|dlqquK zS?*`o_t{_sao3f2pYqFxc=}L4-1f3Kc#+?%Ju2d}Eql~*E{H@trseXGg<7VE?{Y?w*#{2ChjJqbd zT@~ZLoN-}4nigE>x7)q@?Ha^g5L`Il9Q#E78=%f4ui4<0h`Xl5`%CY5uVviQ^}OF| z_wjt#c)Zu4c(Z~F>m~Od^*tWH5pnZMyq7(t+tc4^#GO&%{hN2ZZ)V(%_i}$1D;Dot zQM@I=h2!y-vybzfKfE1rQZrulXymJ-fE;4RGa91kE{VL-w32x1mmFl-8#tp=Nkr7-N*Zs%I zTRB%`XI^k&o#3n^J)ZN_+ZZ?XLEdlE74zXcDBeZEg`Mo)R^M^*yNp}^As%n3V(~6B z?uy{1IxCeAKR`Zo2rl$nqj$gkka5!=<~|fF7VnQ3cT)H;C%7B$w;wa^s)%=`V)3pp z?(|2v4>ixNRKNX{aqGo=JtMdmTnQkPoYZ3lG!1b@W#FNzR1x z>OV7X{uA7X+86MC+cjA@8@8=>4m{chURA+e9zf-~o(V{1o>$Q!(!GjJqtjg^F=cV%+*0c)W8J z67geg?9>%yS;ctiFZhSv}IO9&ubAKl*#;s-CRl%LF821#$ z&3u~2yIL{sqZoHuaBFjw8YdsaxNCx&tr)kCabf2#2rgWgeuMY*%_new#k_h(aN)S= zf4+G-<1W07_uG;ZumAPfGa0vZBj=VX7Vp`}-&7aR2bfP@bn39@^`R#-Zc(fgvui?(&ZJX^h)(6ZdzvV)34f;$0S8xT)mQ+v*^dA;q0uv%z_c+j%pOx2Bu- z+s3(R#+?`3Y{j^Z$cLif!g^}c`1?NQ)Nne@IcdcUF4CB^* zj>ntYU#Wh(fN{G-yq$u(aetr5xOoxpbj9L*7UR|}a37W`#?3NrL2!efO8I*+<1Ptq zrefSn7iT!xVJs+;hxtEFK68J7ev4H@qXL5 z4_7eml;E~2Tz?-r8Fy81iwf7@hvy@I=LGjmkswD;YI`B%N|IM{A0FebeUbaSTCsR@ zjGO%u=hpV~e%pAw-Hclj-1drbdl+{{a3=*9^31>A`WP4bWL|J#{Wtig?{%_%#9dLi zm)_>fJ%G5u0p4#gi99*ud%wm2;?^tN&S&^?4`^C>BFYAb z5Vu|77SDXYCwCNaCj}SsVcI(%#u#^gk>|sl;BGu0#u>Nf%bdHSaQ*XP0{Kug!21o( zkM9`m^SnRmFydwe7skoQ{p=Laxvu!-j>aODX0Q<#(FZ$k}`fB7u zR&e1W%Ud4in`hTC?#kDByoHK!U(dMdZ*cBx#kg-`+$q6bt{C^tjJqnh!9m_{8~68Z zjGOr;_aR*|?hNBXQg#V0>~BxKamaJM@7;(yrEpulx$i~Xd4+qzXME#*KjN+^+(&tH zKZLl!AkPQz_eBf7^QaFaZoR@C^5%XNaXS?5drH3kehhJo3ilJ<+>bME`?tjSpm6>D zy@7FO1$Rl|`ulq$@}Z<~TW|5rhno?%ZV2aDyEk`%ao2?pS%vGL4_{#1j$3)ZWUq;*og?p_x_iK#1CdTzu!G-HB{^RdA88^Gc{jC}1`2bx1@%L87 zoe|u$!u212zr(mC!R=JI{^Rd5Zq2tjcUj^3 z?{7b5+%CagSGfNB+X~|@eV50Z8o_zy@9%#xZt8oS+pci^{at0;PSI}#h3h~5{*rO$ z1$Rc_`j5ZAX56CiVNv1w=fmBMyDYeC3fDg$e#^KEBF}0II3N7S-`_EA?RR)SWE8Id z`1?PMJ0q^6cPU)|`w9NUxb0#+YD(eyU-w^UT$r!VE8M*I^U{B3+`M@Hctzp*KZpHK z6mM{d=L4*#etp(=y)QTcJfN@jf(!T4KL0C^^;~~Ao^j{J{i&UT3&&0W`=C!`+}YcC z{!Ugb-iI)5$B#I7zGB>3BAZ|)%CPAlApzTY?AVZ>cfxL19^ms>#GRfT)hn>&iQHAi?p!1dT4)can48%NxX z;KKb}|NP-8DHuDFyk>)I8Fy}#kCTOpabL^hy_0k2D#m>S<8}(}YQ?zIj5{y5bw%E9 z8~67uj9c>y?n6h#xNm3NF2S9u827`ByCArW730n^ZtX9*59<}PUl8CqVYVPmG zxu0j;)Lq<%_KI=8#JEMlovavlk#Uy=ccEh3uQG1^uelGUigCZexRZig|KdvZ+m9G` zMR2<+#$93D^l!KiGZo|B!MIa`yIe8u&lq=AaBE&tDSz)|+{_yHAzLx-uNW8h>!RSo zdFVb5|6u|9w~gKt9yGl=mC>@E30%{>ix6 zyLr4B!QHqI_cQK{;N}&szYoEQG#6^$&W{%}f(z#@``+aH`-l%{XOp5psEa1Z5N@tj&-;rjn>(j!p3GYa?m ze&2W>$+(@r<@?2w!u9vz(TqDUxa$hn--kNJt@&>rZ~e=8K0v?u`|x<=Z>QkG`TQ5& z?3=$&K-@{eh3Cf4KjU+73oPuCPOsVEG{#*JKFkX)+^6gB?-Ln!@jmYFYQ^GBF>c{^ zoLf7|`)%VsoQ3?&3NG~9t=|21Hsdadc=HvD_Z-Hp6WkfW-FUw}nQ@CHu^(3~-g?HZ z|2^lfSB!fu<95M*d=1`@{l}d&<1PyyIu)+}e$m9ZwPL@RQn>!(P7C9%2!9t8uD=hh zjGO)+-fwFP*WZU{Fz%G#*1ZDvo4*eiG4871wkuqJA1-Fx%pbT9MTP6{LmT5x3+|l4 z_4lEjan}TQMdAAU@Epd?{*n7o^Ge)r{yywt+!?{mC|rLZE@NCc80G~R#`PC?&wuwZ z?xfh?rUiH7$Du13xBXAt-$lXQ__+RD#_jks=awoK@AJ67f8pHJt15Lo&T+2jxDLUE zep~cD9(OZtN{s78h3kKu?_u0I;qR>AZoJ?67`IdSyIe7U`x$p(o%dVt>Pq$7LB{R+ z56(>sE}S3x-^Vn}xV3-f+^&kndx&ut1$Vk)+;PUO`x}pUv0~iAj0@vgNpMr*i?@F8 zF;9nWNnW$T)r`9&;;nxT&xeh3U&^?tzl(mW821{+Eeh^T#kj9x+-1RCt{C@P#;yNf z?nBMBmGbvG#?6cQWL9utob*56d_CjVi18t>aQ(;0H!|+JIKE9QT>sYb94_y`GewlGg;{19>aACdMe?8#qj63!J zSiAE8wW_ND;AmaYx?tUKM{5TI9_O5!;a=eJ?s>O=IB9bDao)M--gn<)8CoC8 zipyWm%HY;%oop&D|2*~xxH;Vy@%r<6H*w!r|B~e9m3*&Y zzmEAI$t{yBUR2t7U_IvNk6xABrjqa3?0nyl+`yl)A4GkZ+lyP@H^D7?v43OaihkhN z_iZWPw36@4KXKoe@vh_+6nEESx$b+CTUFc#_u_s}R6}yTr^(~?4BPz>-1JH~Zeeo8 zxbge!BX9%cCdhR^FFpp>PkokE^5w5P{{=TiZb_*xf8A+1yAXkjr zhkJ6zZ6$E?lyBfKrp9d*aAT`u9pc8^)xj;0n>FUHf%WxazGZU7`^owDW7h^ZPOj&4 ztgn054{nj%urYT-aJ_3_9a6^JO~6f%TQKHs25yPmnlX2Ca3i!n_|L#`6Z4I~PHqXV z?>kuED7o&}$so85v7V9Zex2MJ+;PgcXe{4tz)h`*b*LM2w*$8+*0VF^apSL(lff-h zzA)Fr19V0h%mZ^2}=ipY!O&W7| z2RF11)*)}q{Ux{=a;wJNUx8aA*LSw5`u-YRu`h{|E7r+J+1CO4N^Y85aew{jOS#_% z`5SPv>*BZ-jOBX(xOH-?#`66gxM6a==is=xUv~}yx8cV+M2xwIfE!&8-Lx@xD!6%a zi^kjmaGT`Tjk(jojjfM$2;@wSTN2y?xp8CeY;ZjrV7^&n?&09Z$t@dm=Ym@#*K@9^ z`VNEZ-4N>#Hs+3kn;(dmfIP$oJ9t zGnwBf{YS|SEAG|9T=!^n>Hb5KT(Pg_zus~jxPIDC<`kEIU*kk@ieTb{O>WkSgJ#kTrqBUu*dBZaH|12Z<6bN+%5$-L-j2gtM6st);Gg^>&DzG!L3og z{tK}m+>cuUTrp3gW4m{Po2CAZk}E#{$zLb$lJZR{`Cj`S zZXL$K4ZVPUmLpg68UObh{6osOOs@F;sVQe4x}}&iIzJ(W>+_mv>TWEn49PvB~ZfQ%bL&jLXkAv$AqFXYS?-SrA z$!!?R_bG74$qnRj+}zjq8F2kuVIAV+ihUoyAD#s_MQ+AezR!bOCU@LezAu3r_&&`y zWBJy=O_LkE#MFFy72FEBadO@F!|ULRxtb+c{NAbT?Fa5A{!Qm+#Pgx#mdV|mkad?G z|Fw=MVk4eUz^!hL(>+3$>|AHIZ2Hh~Z?(_W|+zh!XWBGmsZjIc6v3$P)H@q#@ zp=K=KWxcI2%#!QB49CrVeU}HfPHv1`_x<1nH}V6lL&jLX-v&2F?zpjhR|B^}Zqr!4 zK5(Ny#5#m7H#OhB2X3C+B)RVUAqZ}h+`O@Tw+1&B!a7uq<@*D03*`E)Fje2}!1Zj0 z`9{fgU*E~##>pKsmhTjBi{zG!<+~HO-bq-8hOvBq3~qwl;FYG9yI;0C8)9a6^f9Rzob z+`O@TXM$TLw`wfk+2DqD#5#DdHZ|W42bZR;Cqk}x|LnnR zpme9m~YIOdo;Ka zax>(LdCafxpTKR9J8mrB6TyxC2eb-@q#p@S^Po{4v{!Qnn^?IS?hRGH8e{Xr1>z*&U2_@eX z2Dt8plA9q{-1I%+<(D!#$1h?dp1kCale-xO9J<*2iN~ItV7jUzBhuKBG>mfQ}w+C+%maQ za^2Ur1a2ULbr>_2@15YL$t@Yn_ik`28?t|b~cfoPX7|Zuza6>;ww`45ee@b&IVJ7p2qeL|{3j$E%9TTO}Llb$aSBR+z7d%A69;l+Ye8J zTi+GuMUq_i{qPL9k=@YEDK5Vs{ta%5`m9W@c;Ddj!`$~zR;Btj$rbD5Gu2a=>)ErC z8@y3oe>Yv{RHpl!(20=-2LRMk~>DO=(Cq@z~05?Z&uq5{b zzkla|+aNctxcvSd0XG`MI%E`=-@iwIn>QlJCAL=H__1=l&Cfs+}?#+@LR@{>l+ckpIHn<^L zACij8Uw_vDH$!etarx`-y5NQn#BnPtE`Oc$gIg!Jskr?0Y(sD(2hsX_kK7OZ^=xx+ z#r`a=xNDcV>+e?JmhQ#Z^)iatmV)AO8lG7 z&xq$I;0C8*9enrVxVd+C0k?1={(j%6;+{D3bY{MLfLo<}$Bemqf*YESbtoBg_XamZ zZo`-x1Gh$Q@IHCm`1Rcn-0&dQAz{ot09?_VIda8yz+s!N$6U|i;MOVMvN87%a3fdY zy51yLyx#J^E4ihGZ^M}TM{tWtbOZl~{ouY1$ADX+eB;L4e=L^vk&Cx633quei5f z&UG)B+_K{C!QMYyA-N63eU|NB32t=`_L;vdpO5+Vy$amWTy!If%dhX%QXP`yivEqI zxcz%AxMTFb?X2Q1n9p_pD&<>J+~pT=-RmW{rnu*@-6FUd8aMAlazF6<_XcolKIKHO7S!hIjWa(%eBnR9jopKF@I8Y4AnLHkBiwxNm+BBESA0I;gk8D6 zN9_M3H>tSS?8bG=lABZ9o%i6n4@+)YasSD7ACcUq;_kiKiuZ}Vrp{06d-fzZ_$c;+ z7`OS~<+_hcZd`Gf-Gb{r0j}>7?B9&yp2>Efl=3Yp?$9{5AO0n|b;Zrz%XOcUT>n4i zaohBMuKTp)Miuuaw)+gY)imx?(~8Tl@4vwf9f58^aryPFf}0_?s<{06J_~M*T<>G@ zxbf@z9JpfchshP!h5MhveP8_ZlABQ6BTnVIFGy}iaaTT#>%J(tMa8{-Ib8P@$&D%Q^toL3Ka!hP+!wdwUcbF6 zxp~E1W-`}(Q*z6SyZIEZ`Wd}tf-Z#q9Co)y5Y9*grL z_$2n3dv|4UL&u>TH|DMeZid{9F?TI+Yvh)UxqfiN$73Dp#@r3T6=UuHmwdi>^D^%K zEPyWEKZ}qnt~dGbC)iZVH$`rM4&YmbR~Ct5(fJwiYzA)b1gvktn7bvo4RUM7+-<>) zo{0JSpTco-Ux!KH=E;p2b9V%{Np8lN`(top8LY#&F?Sbm3*~T99+%)AoZY%ETao(Hb)I&{Yr_jR^=KDe=Abc>4n z@_O9Y87>63Oz*p@kt;r*#sB@A7lRvk4)gUrC$H;wAI#17QgFq5i;yecpStFc_BmAi zo6gUO=PGd1ly6GO_n+*1uLHMvI<9AVWBJ|yZYYlRt&l6`#k=f&xCPuODa%N`K(45BGpuI0NfYBG-NY z-Yex>Cs(|G^3$o@&)wb+Zs{z{*Z%_cgZRF9{(O5#$~Q``$alE}H{Zv=O`eVUrj6zM zFDc&wxuSp9VfVwo!S$bm`Buqw-w)49`FdZ(aTE7{_uhm1`$C@wH~lBfH$<+OZ~Xhe zFG~5w$rW|jf8+g_>-tOJR&tnc#+dsWxVi75TOwEV1ONB)zAn|FPOccYL)hb12RBW1 z@V$in;C|fR1~+&v)*(!;`*C{*+{}6CCXKlbaK|X$9J%ht?L%L)FTkyzkNHN)b)WB7;0EdSi!{07bu#|zILofm z8nen}xR1&!b@=Wg?&~`1lzO4ps<_a9QF>=Lxo5UWsHNeeN9SY>SAGbBZja`KGtr)BCTHqEhM%VL-sc~Bm z+ydnrBG>)6t&i?39Jd6yV%)xFkK0Dz<}ScGWXN^D?rZ|CSl3HRzN@CW>%->Y`YyqI zYsT{30^Iao==%PH{UGim^1q*U8>tRqa>cy(!AacftRH~u&11d^a>expf8VzqxaCXH z%^GtjgB!RE-Em{?4&bKAZ5VTR1h+zN;8pAg_x0Tg+~DO{hnO*UXK=-Q8zWcT|K0Pk z#Xk`Lrt>r6`6;+#bpN+Vu2|3buXq0p+$zeIv8_7R@CXP+#XT-A)xRI-{ z4uRKk+}ykSftw>YZp=MEsza7s@ueE~-L%I}I>#?!Bc21njTW#DWn=Ck;O5Eoyn*#~ zpYK#~>(pmqaszZg{CP0|ZtQBTL&}&t9oz!B1!L|Ea2wQTHFDkeZxY=2HCPA#o2KT) z;oug@jTv+2g4?7%%aH57&*p=hxEAX$Zp>W(Zi(EcF?SKTH98N4>NsxVdk^^M<0HUL zUWau^7;}#Vcbwd;G508N{ePu#Gv*!*Zi?K7G4~j7%j5>$GBs|;Vtr4+I>g8o*BAWv ztsDogkKDB4^54I6JhrMXarYA}HHkEw$W9NGc zxMSC2zJa%~AKd4=M9MctuIPuKzQ?WapTP~$x|1f?{eJy4aAUh;9SVxe|2JTPZ z)ZsdI9WDYle-q}LQ1azpcV7%{liaN0^6QWXSDY`#$rb(kTXz3m25$IC?6bO3-}Hyv zb@B>uv*h~T!+sFsb|TxoN~%LxaeYI{cSVhKenvb6a2wyHejr!e|2<)2?(1Y%OZjHV z73;$aS8&&dYrqZs4f8FM>wf=x9k_Lx$2D@@pO60vZt^zF*Y`g5gZq512iIRhH)71a z0bC#Dnj6UN*J!A;QXLs@b~Kk(mYQwBFl zzgKyjT+zQ-_P9L^ZtYI2L!DgrpK5^Hcw0WHkEu2XXpDYxUqY1+yWnAKe*5L zc`4r*xuU-3%;bJgWKD9@~VVs+$7~&FqZFo;FhSqRdU^r+xy`9|AF=Od}3q@@- zepnIQ@PnAI?=w^V;03o%Zp4_o3b>In=9@C+t_E(7+`KV&4R9OeR*bo8gDcia&wp{; z#JuKuDA~1e{cSlQoadt#eKxbuibg_(%#ni zL&UQcxM{i{l~wZPzizrUxQR!x4&%o1-4+8 z!*Cf zsPjIW`HjTNz26vq1Meqw#^LSry zD>QB~a^3gCZ@~>cf%P3D*M0vU0PYyox2WXH?}s?J;U_WQnz4Kj0=G`C?@Lqj_)u`g zDKSE>*!P{n{{1Zj;5KQ0mLyl~ANbeD)4`3?ekV(=`+eUGa0|3Q8&~q>@B3zg8+{7< zp>8bSB-WQ)|5w-#?(1+ExS}7TP6>>#Cyvgo|EVu!xLsO|QzaLHqcZ})~Tn5L@eSOaaw?g^G z$#vfkXM>x00mm(4EZ-cs;TO>@8FSAESM)=jT=BZo9xHIa&+#H~LsSRfvN&$y^?80j zTmo){_9YQ=#pf3J_l+(Cw?_GUZQzyEZ?iZjlPU-#h7~yxS}6C-@%JfU25z3}5GU7tKNP`jP`()@Uw%K_2yUT9^VnFvH-j601>L$a z_cm}vKlqo!eh~Y~JbOQRJGegDM@7hWzn{DV+$^n=Npjs^XZ;=AamqKR*$8bbzk2q=1Yy1Bv-tD zXT9|{`mN|eou3iU3*aVbzGcZ3=QsX+t{1@_r}F+G4~yC zBX6PGH0Hh!ZjRib7yH3|9XwaE*3T~6!x-s{^ z;Kts;I`~&IHIF|BSFEj3a>YEpbtUfSsJ@Wgl;Zj~;JV*{o2B`dBiH@*B5@wm-fF^#pPcIYyfVJUPt$?g5&1?_4$p!&C=`AVa4UY zj=l-F6&klBx$f(`8Mwg@u^)1Z%dhYEz!mF5nOw2o+5Y3iq2k|kenvc7NN$tdEeN^u zl8>I$@kDIIv!&#QR>gkUi~_#D!DUyASe>5{&-W!aNv^2FOWpxy9kvEH{4tFix$f(* z4Y*lyE5_>ZLvSOXV7}hfu)gl|4S|~@H$txaahnWo?IT(z$ra9y^0awiZl2V7Q zcIVFHpP~C-%(rf=4!eMxr}_qb^0@K)_vhexo0xBmT=(O)8@O?*Lxx=UqEofhG@T2A=mx&#R4f`&ssQc;`NJVPT7O`Ig~}kfxguZwbxRuD`q$WJ31j&l zDc3;^pamfWgrs&yYxZyw;s>bsnbSh4=tEIck1kc$&;q0 z1_lR5rcK&m%0wjoNj$z+{M0!EBZs#=$Toh5?I!8OFLLNE+HO*~EfoG}mq#mJD-X@O zEVAOYe7(Aij!c_4TASmv;yMe{H(p8HKEAUsedD$K&cfLGZ4F}|r&*US4P)3s z*!x;_X{(A@6}rxUX&Tu)f0t_5yY1DmbGu9%yY*^OXBBMn7@9q6?y!S-192MtA>y6( zHN>}91as*doeo!;|)?%@0`>Db11 zNvC)G=*SF5J;x8@v|O!vEu7_SKeBL^v-6M@ z=dfOS=ON2=Sg$T;W83l7IuA`7nqjR-?MH}1*lYYSzCCjX@e8Gvg9q693#C@-A1{rN zgM6gQ_lX~#H!wJTU}S-E2tD&}kDod#HLP^Hv&ShHF;ADPJ;?~#rv&?i4;{YLcbmtNp#J)B|1Iav>9PMSS&60ka~ z*Kt~LZMzbixPj@@p;75SJw5A2FyfcPtS^*)%J>^ZQKF}-kgE-M3l|(&YA7# zb?TYc?I}mzT)BWfk0T`q_KX{zo^tfOR^03b+bs>X^JXuYxI^AMZe+eQZ)EH!`#EX#UwZ@gIu3~Iyv(w9HO}WPf23_@+2t{!vEN6xGZ8z#Ee+e_ z>yn0jd}kWH1>gJ}f<5E3Q4=o^f-mc_LRBm#SWM6Y=UHI*8ZWXNc!fOVjUp zta#S*=!r258i9Kd^2-7C`Dh+*m)n50ewW*N_VJqev@dja zeW|l9x9Zr6*BK|BbsYT8X=q!QF1PjU;-!t9OeXem%gX@vzFu8Mr|I>} zsOEfyc#S?7)ts*oujOkVujYIm)ts-RU2enMj<4oCggvWHeKhCcXe(aJ*Qx*Pxq9bA zig%n(D_-Y(Nby>}=J9IHFDsu`yiPt^^Q-0SjBhJm^LVx9m*s2CuU5QfK90_Zma8=n zDPCuswB}*U*BmFU^Wp5d&d!IeIQ8Pjx+Lm({-k(~y6Bw`TfSah^v;KtuQ^}!&W9~u zZ++4`AGUnG`7x?FU-iz1Rz8~Zwd0;l>k8bi-&*rlr{6T^q2Bq>I$o`LIB(%#YkoP- zpW^4tn4>-fZdCNFQ|oa$^M>MC&!f|St>>}gInSdt?$-0P;#tq5S+`byv7Se>Zmm9J zJkOkw!zXTW+w@B-u4Coz6W_72*~HJ+?0bl39PfP1zK3|$^XQG=d}iOz*V-S>TL|%- z)5EcD85&Hj0K{nqWoVEa6+6A7noT}}-4&%>-+mlK2i^DyhCIZy3Q47T}c z&QrS+gZ=a9%~QJ*gWdBi>au~ekJnq@7j?OjZRe-Eyz<^ZUY?kJ;;jRK%dDmU=^wA< zcMP1p-@0;Nno7UxzmfE`&MW;szUJ|E-pT9ZYaVZFqUs!P=ft+pr!_&f{Emk1$SQ z&(nE_see3Yd^#^A`aBPBo_4vz)aQA4^R&wyCi~}M&QrKBaJ){Bj@VpC^vO@N-+Ev0 z+dfa13yD7Qdh@Nzg@ldYB^#U9pXM!GqzXcizr?vAFX{+%h&0*R=no%w$=fi`fKe6tbDYtYbai)o?7Sg#dw{falCrhH7#GS zpY^V5TE5=+>Rs0?PD8v#{q?SETE1RC>s{AazUKVZyRK>ZdgBZ6I`z~T-_fBiSLrtE zImOG_^oj2{+Wzrcen&Uk`pMz851{lskB$zt;+(H*OXKCt`}iG|=^wA@tXNK?8~9f)y_VT&Rtxe zc)h+H>hf}vZJ%}S;%xI79dz(LIo8LKt+>t!YqKt4ywYIy@tuX~8?WVeHcT&nUi*iF ztu1cvIJqXh-2=?)vMX-(UHjC}@={AdP{*{y ze76Gis%I;{TS7MRT?=FvubEHhCe~)Wto#>t>mZwa7IrI;ZG4vk*~ND&kZpXI0@=oE zSp1$X}j|>bt`dmN6$)_;;JX>yi z0+dP5d|UBWEtV$SFFrXsbK+giz0VsXtvH>$DPBEO_RPB#uXCIfujT9Xo#nTEEWh`- zx8kh2=;Wbu-O#Fgw*}Fzjym(bUM6j%f{P2zH>nP#w&%ikMA5%yZ9l8#|alC z8hOA4gEHal^RVio!x$PI%4ImwSHT-A=;0zXCLA1ilw1_;*@T)S?4Xcy=-=FXBXSMon34n-}ZHpy~o+g zx8qBnt*Y4N-R(>GY~$MtLKW{9uNK@kzDr^3;#(IeO9$RTKJcxB$^&fuj&Ikqt!LZa z4EwnD>1*@+-L{{0<0-wUVdrZ0tJZbk$k5PyhyB`ZIBbtkvtQxMB9-B`_q!Cvu8!Tl z6wxMr;dWD!vo+>}6+faCKdJ2tXzlW_;?y+k>auY1B)z=1cbJD2r;RDS#gfeM;ND;qxbPy@z&ujU4HHI>{13> zw@Vpp;~n*fm9JKRP`p|YyW`aAkCxx1Ft&b|!q~*??JtH0y53;7^Sh*DH%?u@6xz<$ ztWVc3fwuAW&ey{Odgp5^UhBMS#XCCxVVv5Qc6DEsehX5KLPwRV-Tffeu%h#>g)kEuhkiqX#7~A~2G>Bb% z`vtjeT>FC2?>eCM%Q|${(N=u>!r{c%tV_2OjLq?mwl|D@TxVhW#w#=4KEAUsedD$K z&W5q|+Zx6`PO~mu8pht&tV@?2iM_8?m$s_d?4OihyJPeGU8-U4wpYW>?J{lb)~jyQ zrg!|Jfz;s0%>LK85I3=d>y__<8N+jj=FRH%7C3kgr;l5_G$Z^&zsGf}QR|UTAE*0# zot@?^Pw_a-=j(b7cW``5AE*0#%z7@}6X-sls0&tc;=g^yZ|R=G`SXn|P=9BzeI2d% z_K8ZV_0DT#!5nF)jt{Vp?|cILc&l0yC4xWM#!Giz9poeJgq_4|<|Ex%bKpxmQYZ16 z`AApZ4*V_~AKUu3R%B$C{?{&kZkGn?6W`H5ed0S3vXAdo4wH;rhgD<)i+N^VWdb`HMUB-tnVzQ_~MmN*|rD z?FSLB?p%B2(-yDnxZ!Df9*20GdMN##$BJh?k2N6}k8A%VsgvXB{6wk!@pSnD5qz3H zb?f{hk$%s^t6P^Z6mgW_{EkA{=ZEp#2B`1jlm>DV&w8F74P^g(?Z0`_N&j?yAxl5M z%Pj_YqJEE4%GRgfx_mK9~v2j0+1DH6yA{0e<9Zar{&AY? z)sW_Th4I}Er%zvZevwqa(fSGb7vhk)c<0B9@y_cH@f!8Vc+Gq?>fiE5Cd%Gx z{Tqh3iI3;o#7zpP20NG5UgJ4EWyO!^#g7b5l?UIN;dcJWh)#Ulmj&3mj=nFzs@q6g z)q3YSICEs$z{rfr%I%V#$3^i|wr^kLZ1NqPrRih5b3Zk^t&41qGj;gzXj{&`#%(Y) zXL?&$?>bm3=HPZyrj9I_k#ZbAd6HiIlVm6A};@f{0fpZJai+djT? z!R`~UnNR0}ZR@u!*!FP~OHZ%3*>e}9+9$4UoOM*~bFB4eyZDJ`?-Qrt&K(??J}_i; z$kfg~j9oqxkLws3IHX?3G4VKO`xy~G!pv`^_2o95r^B9go_Id3{5npdeU8856xu6( z-cWMl#blfQm?ytYx##iC8+PaoOK*Gb?OB`5_J;3y91z#pnD+5g2OPd$3HukTi3iks z=zaaE3ujE9ni`mX_|%b^v(wPKc75O4RKxSgkLx%v&F8h&&!tZdf3SUg+d^O;*O8X} zIF4x6yA`iIg?&C&yj^wm`dcO7%a#Bb6TA}p_yE=5c(&`i6aiwJ+ z-*KAglTXKK!Zv>5-AVSx*?vW4m#=(9*1z7?b?4k+3|snNd*6yzrnX&t`)Kxv8<{pu z-bmZUwQrz%#kDp^GrQdI=o8;DE&9ZFOk4Z->4GUNfK0>1peCwso&Qh0W&7&bGFR zUtqmeZeVD^;B4!2ClejsJD>LWiLF!L_z}w=)bJtRsc$83eL2g7-gACh^=ajg@e{g( z_(^Ta_g?2F{Pqu5If>t1({KOKlp|j%PoI9U>eK$=DJOpW;5v(MFMt1h+MCmn-}WJ@ zzVWG<(k9zceA_0)LHzvoO}wLc9p9QPTK$jl?E_#xf30|}{)hN>zR&nt@ml>4@tVF) z|F?Xd{;}e<`XA!;^4IGBmhUY8nKR~2pJDZ*_+PI+NDgc_XJpoPBCO|lV%)^VmW?-e zMtVW}Q-f_2KWyDQP;VdG$$L`iXpY}70o!hw!?&DfhXz2n$f3WpCcFlc!jpJ;6wsvaU64)yb z_)NYP+ZGC$+s3yA_l&ciyuBQ~;)WKbraSn2Ve9sTqyB`rF1MO{JwL>^C)#J+M7-1f zgm`P*oc4u?*YTb7bIaA~XNcFV3w$TMysY({=iqDBrSqz>_k01r^LBxKKApD2K9-zIz{f-KJgtZ znSFd`=k|%$%%`)n?EJy`6R(K(iR+j_ed6IeiR4P+nDu>J#}PYxT*pW_dR(&GcRjQo z*(c8=oR^d}!qMY+d3OB{KL^j(^}B5xJ&u>>2(zAWl4bPENVo6e>34j|wi~;4<2>Xr zZnW);Zs%EXTI-P&uQl&5Uan%Fd^$$iK7Qg1-6u}-IHg~K(i%S7`8NtT+;xuA`MNkd zt!*%E@@U0%9AuyP_QC8`zn0r=3ABsv7)1L#CI+!joaXUKgJ_d)x9wHW@wV#GIe4~t zOWPS6x9fJsF5Y3?y42nuM9o^39_2&YNm);TvPhju2zoKQE&*=0yscv8I(yLD(USs}3yvF=( z#p|p)5U-h!&i7Qde4Y2bL%e1_T|d*(V|-h_&i7_Oykk?W$e}m4?Lh3FcVw_FkW#geZ$I)r^UO+q#VfpBzmJSe(#s#>l_#*te?hka=o_!+ zcN{<;--?%?z&5_i0Q8NQdAs^A=r#a-e8>4)9|Ex6?lIMRo06l?J+wYF0P)J(j(X-l z5ih;1rhk0fYq_ln+3R?PzrFnNj{foT+m0N>>*a6#?iXo6vB`h-+}YLuSaY)d0e$0@ z1MV9ic09hF9}2Or|I+yObAnAiOXIDzed!_F#E;C->raSR-sWjHz7VgJvwytv{y|?J z-oC!${z)$w9+=*1cWX0m+8-xx@nB4Pjz`<$l&z=j<7Uno7;JwpXD^@PoL+A%RN^Nu zZ7BMK!{<>yZq;*q==s`P-N|uxZ2$V?CE|6DM?6mVcsjOOeex6Wy7`I6Y34Vvk+;vw z@pUTo&C+DQ-Q&>g8^_nh;&{aP>mHAIobK_6@mxCX`izf=*Ue8nPA|W<3q{+! zMh5lrvEtQlg0S~ToYiM!L^F>O%{vD?CaG2eDYBD zf1EtE9L1{_iPn)hf1K`db)RDWpHH;@(iU=9fAKioJjLTQ>p!BI-_j+N`#8nbe~VuMYEng&VIJ@0rC`e(S1JgILF5~JbiK7%fh|qDa2V- zP!j6dhpqULiD3IUJ-6-h$2Q;gH}>~>{@HU!W(@bf&D7Ixe_U&jCyo^VG24(prG_R4MGe#fhP zdbzK!-UjaHTc1YOI$rD3$WG(u&6zQO;uCSb>)48$_$D~}xQRE?*~g7eJTbLypZJLc zoW)Nh;w)bJ-C(VU*yl45ZWlLmU}$89a-@CZl_TvNuN-OLc%}6Hk4|Qu{ z_oPezE#mp(YD@o*^@nkC*P*|>sx^G4#$BTq54M275Toi6F1-E!3{5i>ZwA~txdmhHDd38lSIHIqa5K9f zPR05zOZ~l$sc}0E+$_~0M6UaB%YxgWd=tjo>~YJ1 zTch={Gh;?VPSGoI#JHah1hvOC_ zSIlGnx^ow}UaG?wx$gH-W8Pm75xw=SMa5Y;zHuBb16UH=cb(bcfNIb(Hr9o!t%x2)vL?}sZ^nq2q&u*~XW&1wBCkh?DZWqN1sesWjI zt&qDuxo0ooUJvaCu76FeuV)h+H~0De0^ITkc%2ng+&hj*GVjan4sPL|72y71j9js< zuMy_fH;VNgM>nmw@gH;DJuzQeC-da`Y25hh@80018(7~8xf_uicyEw-9lH;>V{21C z1h606yT1W9NN$K+_jUL!xK(l!#_~M?+{`*yhpaL8KyX9kjvK4Pq2SW+dm7{h=r2w< z`~3aIzv=vpcm}}Du8VaDZi@Zj-W>$DPHw`OI}6;1AM?!_a}NVIM{dQKI|tkbx!%o8 z)i(uhbUmy?#F#q*Zl2t&FI+#|q^t&er68*~2vZuLW4e*@peaTEK8eYfJC zkH^3*P`)v8-OsmU!HsW#b;uZVPXO0L?zpi!WWX(w+c1{z$>1h7#5x2wH#OgufSXB{!(J>(Ai2=SyykT+t7^o;QcN|GiLh(~A2L+r3zF^NL$#yO&6AS*h

)%4|vj?Yh-K)S&ZH((fgxs}ha`F53YAN3&xuVYo2e{WQ z*Gg_ysl(k5aO?0_$t{s9t~bwEg*z{D^05`lDj+=K&><9Px-X!H4B3F#t zqc?KvaEs)|$rbD5Wi{@&l_YnJT+zR8FE_}X$9I5RcpCRn1;t%*8F&4?2izvzPpyzE zt~dGjY3~I$OxG=*AohcB`PcLR05@>bvT$D`M6T$EBQNL9;|IXaZ;t&NC)fS`>N3`s z+>GM#>+mqR-v3}fl*ko*mS^|Fli(JX1|Fz_0Ji;Ci>j`j!=!-)FB#b!d_+=G(K2x%2Hc zaD73{H}HMz2lw;s4RDj>#uS%dhdQ|9=is_CMy}|G57_v*@uaTDjwz0crY4}B=PA;nFw-H#Qc_+7swEr3Lc)|73^?XCgmwzAT+u(+_p?SOw_JjL; zR{^(1Zrqr=x>VmRxney#^$PBK_8o8o-^V(X$aTM-ttI7KCs(|W>5Di1#C$*a+Tf-s zU;no9`paJ*{NP4@fOUwH>ptK0z-^G5Hs)>!Zhc!?f5{c=1OI%y3AimgZpv&A-IW2SckYVcQUvoax=!<9l-TX#(Yc0+%ULF za_h$2AA>8-+WruZo7hk89Od38_$jz?>W2uqVtwGxiwL;mREHF~?)&WL;CiVa@=Ct^ zd9fR~wer00=Gu_rj6x$ zFt{Od3rfEHaXS>;Y#8fXHJ0yGa3edR>z!}tja!*q_x(E;+&tymG?s4)+&bkO+#dTu zh2S=+z9pp&{Qbib;KnK6y0LtZ1h+u-_3vP6+>Qd*`xC5hlw9}Yb~Lypa?{4#W56v^ zeG5t*_~UjQxW1oa9jeCiJs#Wy)xkT()VO899jAQ5<6*`T_eqXJvIk!lKLS=u2|Rk^Wr>kD^!Ou za^3gY1>pLrABsx8{PWO7;8u6ReyADCHxF*+=ji&vIBxFia4EQ=A0p(6e)u!HAFc#< zjOvgi*L^=+4Q`FOa&2X36)f-(02aHBMCRdU_;ZyDSoyW}mW{bjfh*2$O>zVD7yme9t?A<5bbdxW{|0xQ@(umiR6jfi zu76LgZ-QL+`MwBlirk#Bd~4vA$t@ep_f>EMdtn_sKQUF`H^5Dk8zR?zecuANLT=Jn zzVCt?{1weNWBGmn?ijfhWBGmrZk1fmPjTGb*Y{I!#T*TjE8h3|`{%gtPi$K;D+|be8uBmjvLE&b#S9GtV7dSzTW{iPi`<`Y96l*Zj;;u zx$gUSU2tRjVjZ%^@?9U?0=Z>l`ECTR=QlKN#_|n-8z(oki>dkcU2u!!CdhR^-?jkP zyC2peXDr{Xz)g@_HkR);;Fies{M=N1e+aJcw^)Y|x$f&b3EU{XeYpfg6fr9rDKV zJpkMcxm9EN9tduYT<+{PAEttvB{yX(-)Z31$t@VmcLunTgRl-& zWBDe*&5`Td-PC+L9NY%E5pvznx4Ga(55_vAjpaKZ+&sAjWBD!sw@GfzSiXzEjU9q@ z@ax$fuNso<8#9W$2iY2YTOVjYUc+_S(PC%0zIJrCS4-PiE_635N`eWMG(^(U|n z5pp-7eKr4cC>Mj9rF>ILzWn=9d2q{=Z{AqGmx7xfz&ccnxtD{RqI^Ajni{t&z^zce zA#&Z1+g0EO$W18u^2e6sKIm)-9)PX;4cY)iad_8-c8n=7E zjglK8*ZsJSgIkz|^-UPd_damrNp!Qu-21_eQNH6!9r)w+f8Z7=--fY#9|YG!Zs6DQ z`Ix^>mcdQT#`?y{b-%7Z46g4mbjOUjkAj;dw`k0L9P4`xet$`g+|6h|dBn@_e@uVW z`VsLw3GO)M>)*%JJboHn|KV8QD7o(Qt%92(cg$G6&x2bgw`eTim%t4SVIAtm@_hx| zG`ap5j+^`Xz6NfE+!(p;=i8g$2ItUxGnVh$;Es`7GM4Xq;8w}48_Tx=ZfGvnA+WEh z`Svlm8FFLfy6=b2z^##+F_!QDzzxsCI+Tp%`z5$pavR3-{RZ4Rxq;u9ns3W~r?p^5 zQdoyLx$fuN^5Evk%^1tq3vPqlabx*@8{Fu8tV6?CzN>+oCpWmCsrj}BxJ`27Sj|{H>|^767+MZh~C*^X!CWi;`*3>UAQ~A<1}vm15Axu6xG9O&u7}hs& z_g@5VS?qtwb-!Of0^AbiTUYYsf6nqq%=Z`^H~%3xZtn9v3f%Oc(2W{%j{#TQ>`#*` zK1cP|gWS(i9gFp)`IaYF>>v2^_;_&rRNo4@?$@&uz)jM;@ciD?`g;<%)njqoLgc#7 z_hfK0$Dx}r<}LwO^h1_h@jbl@|I7WJ-mK)76nEby*F7EF6!k-mT=(DqdnULws;}=* z><9Pnb36;&0L|kFxguZwx|0Jpasu{4%2>YVg4-ZBZ_K>_T+wG0a>e(I{Aw@m_s(1l zZvA+yLz7(h=b=l$tRdgf?J^aM#*(QZhr&UdotD`Z7km+xFvE6#@rjh^__zG zR*ktggPSDRJ78+uZUuLo+^{jX1g==mlH`i@EcGkydUgl6Me5%yxuVbb^Wsi${iou% zjT@`OUEn6D&l*a;{PpZ^a05#)-@r6e{V)!0h1{4i_dak%Ka7zp_ED=ZJD2(U^&SAX zOygD{SL`47{qPXDQCfeig%13<0kUu_rpKI4V{Ml5GL1szK?@jBR6Tx z{TH~RA9Cc1zr23mjejftP3Ncey)%M?z7+q?#K6^ z`3A8c#P4r8W7Qc;bdF!dMm*1foBIp)L&TW-0=NxwQ^wqv!Hu4d`R0weHE{FfR*bp- z0k=u6XNIY9dmY^1pRo=ha>efv`!2YiGttc&b3Xt#PVTrd_aktN z3+oV=iT&Vy+?wDf$c>Tf{{Gn);Fic8Gv@@?^=ak}F=nxMIlwbDz3B zxOJ+7_b?nc_xbJsZeT5}Z%A?PI3~%w-kc)UAx^HizF3X@`)+pxw@UlIF>>AC*Z3*8 z8M=NeDlY$ea~E(cuhZvd6nDy^W$qI_sPi-8*;T5q?{Mq~QQxnZ=l(vby}`|2i2V>I z*L{8W0XIwinjO)Zodb&Nc9~fSM(Ww+@^x-y9Dc7G?woGxZ~v3jJbp0igEMJ!EqD! z`#yh|dmfr8xnXj}eXhS8cjaX9oH{=vo+P+QszZ`o_xI%v1GjuBj$6)HzC+-qFQa*E z%$*0Ws9lp>F>V__${n});8rN#z+CJH_v1DKZh+hvx$ehp6x^}PvA$!*@?8XO=n9(0 z#@xl=igBxvE6$s1ve(I@B-cAnUVp2vP1{mDr_Rra=V)|koeYsH)=B<-`(wbZ(zqoQ zm%siVE7c*Z)ZsaH9gYV#dnNWmNy(RAhZDiAlUr9@ejQGd>flew{qP>U4yS;dy9(J-M%UUkYx% zfOV*l>waEb4zBlFbUnj3ZtnNLSAyH5d_&}leEIXO0Iu&k%r{{y-)q1fCpT-%{TsNk zi!k4Dr4Ib-rO?J_~O1ZT$V{6>`P8^V`$7`?Kf4 zZBV{Va^26j7s1Wng!K(BG}RBUfV*@alPl`*S&3VRSFyg7?-;r6>+rgiZ&AtjCwFo4 zeG}Zm%~;>6v3%bGH+~Dc-bJR?-}k^Rk{dSWekj#9Nv`OJV|=rjueW>*uJ=}~L)KWn zpMsmB_YIDdEA}P)_osdaZiUwMx>5)JzT^vVOH>D6+EhP$4el77=Og5bapUhxJW$H< z+i={H#`0Yj+*AqOoH2I=G4!ycmB|(RlH>Q`?n}Jj)@c9GAlLoAWMy#6RENM3rq=aU zz|GQmK1Qy{m%lGr4cyA@IBsLc^7Vl`b_cpeWA0kuit}5IT=AEI2e|#PHV{dg7v9A< zZeqUi*N64Ntx_FATh0k?K1j$6i9zMF!Z{X4oPWA69B75z{r zSF8`4%;4S!-xAz3%?sa=*bid9@vmF90=G_eh>+|4x@Bu{gVbj!C13vfur0WayKvm{ z#`66kxcR%$tr&ABgWDw6^9NJs;~l|`-GljtjJZ35TOc=K%>5a-o^i}KORoDq+ZEh6 zx#Py%J-{uJ+c4(t1+MpAtV7@^Q|IG-z)g@FGv@9GZi(D6WA5+3_0aW2kz8?p<6mbT z2(IrwtZ$WE_vg2R!5t^p`$tprcq+L5e_+00WA1ct6LcMrBv;gzf1Nc0+!W=THJ0xz za0B;a9mdIZzdjreZkpVNF?Sxg;yfQX8v8-~#kleJeWT!3s17M| z-Or0OxMA8qPQKVW?yK(}ek9RpYNLvRfHLG1fZK8(BX`xCf1 z+V8~3b-(XB4%`~mVT@e&^X&w1qqN^CD*5vFeHn1;58}AhjOBYW*0+qV?-*0(<3EEd z`XNHD_{&`%;$9b?2E-W6izK=3*M~E~ZBQMueKxM-%U>VP1-JPSj$7SW zzUPBmco<#(pG=+SF9tV3ug6Bo73%~4b^lAi&C664DS90;L9Q4#{_FmK1Gh-ymL*rbKF_~T za6PyQs>8VA^2hB4aK$>=AXofljJ;0Y3PhgP2mf){5AN5=61cv9VxL9Gb-zyD0d9=e zos^Og?0b^rf> z+n{^{Ct^RiufuELCh7i8j9f8p{QFUFfSZ2`>zg)~ZyoFVG`a<2?z`X?$gLW48{n4d zzL7U0pO5+Xqdo%H^9hKk~X*$o>lzjR7l5fB*{Ts*4dy=VnybNp=l2vrW#@yw>4bbavNpi)$g#Wt#ia=Cp z|Bxlu{k~)+aL1_*%#`% zR-eal3zF+T-;Kb{ynt@pn7awMr7h9TkSqG(1$IAd3ho%yp{UfC-w&ICTcbKujn!du za6{yJPc_vK-vhV)BGxxVuKRx265QNN=q8N0TY)Rqhb+0GAKqg3!#3b%sSYKjzWjdJ z7TgBap=PWOKLj^Iu5XE{eh7ivd>O|rOs@NWm;`R2hHlcByFIvR`u@Hgx$u`(lZ5`r zeSK(0AX0SR94FWP{^3WM+ACOx2D$F{4?hMsK#62lI`Q>ptHI zxFvGOjJdmln|}yDzgZ*~{?h7)U$Fb(7eEwg+^R}_`S-c@0N3{_*4KL)j+^`X{u0~- z)i+G8`+nF9T>on{kB#NKH@IbTbH>~lxXJhF^StDW?^D=g1@8CW?g#ETja!3U_pb*W z0B(l9pCFLMesKRi4RLT&RNol6B47Uca1gk`H?SYZjOBX>xK(nC#@wmkHeaUiO(IwH z!y)W`7y!5OI?dz1;JAtU^4Evy;D+8rH%zYkewYF77}YnaT52m~YNlzO%ut zlUp|C4uM;2fZHUuV$59#uDHJNoFR|fVV85iex?ijf7cd;MFjpchRxJ7cC#_~M@Trge8@9E$s$@QIOs=jA|J5FwtT=(_Of$RSO z>o8_4-}Avuky|pB??vF&X#db4S6m11_a%97vvfWVoQ>lqT>k#yQgG7^tZ$55_xq^J zz^#xwrnvlkuK+hm?|&#NF8}>TSAiS+5bID=T>iLS4el7ZzH@NgM1A>nxE9+X z*WqvAhCaeNq!gE5hwH)3kegRrejRQAw?=M7art$)8Qk#4SO-r|9yfj+ZUHw-Zb)(Y zb+`@OI=KnO<=5eMaL10tI%LTe--FEmJ&t#R8#)f%amD5T-qgFmjogUWn+?UiU?%r_ zo9_WP`YGlcI2ZfDeI4!vH&1R%art%l2e?gg#}t=ehX=roeTH=?DlWet9t5{QZcTCd zb$AF|&wnvr-+A)5@$2v?xN&kLip#IVKfx`Mn^IhU9UceQ+r&EL6_;O!C%{dRTTxto z9i9TWM6Tz2dEEGQcm~|aCs>CNxndv1U)QVP=EzMbE`MEr4qS05nN{3%uU($`z2h%~ zoBSWvVVqp?dzkp+_KK8mgIsa_Hfh;&Q{q^3enve10e7784PJo#AoAt+!)xHCzrZ@g z$#tLa>)-~zL^o^9eN(D$nOxDom$CcdZEyorho(|rem}ee?ike}cp;9P`})2IZiVtq zkn6r5-Um1H6^)y*d>i0~zecxg%>4-51ifFwa}m~8+@IY3JRgIbrF=u= zitBm)JpL5i;Fq{RODg%k+wXs!T6l9<84A-;`uAa+|Q-s^&=^555FZ|QiF;{$QAu?@Ymda zSP|SX)geW$`+isn+#J;*Z>$b0gIlM3t4hB7epm(E{I_V_E-^K3tAZO_4&8_`cXe=S zdU?|1ihg*L-4EXZH%fIVkn6r5)&#deb*LJv!`k3BDPP~EIBp_eem|@OZgF`UH*(#t zXMS)KE1;V;=B^KJozCY)a^3F}HUPIo`PRsFzfaf*+#H>c{g>gmiG2C{gpI*Xu88%G zlIuR-0JwfHx?{%N&A=7&xJ0g)$G=!^1?KhN=HSMuf9vFmdBH!=e-GRg)xm$csdaJ- zaJ|%LF>*z|{COM%H@y;#o3VVi0ynrax+P=o*5HbMXpjqEYH9uDj!o|Gkq&{|cnkNx z{wr|Y#FO#gkGmZZd3xVKL~;4=bC?8f>>bQENv>EQ_`f%JGPt#GcPDV`602VqRp(74O?xW8aIWh=0@h8S(4_ zZiDhI8FP07H@X_up>E9G9o#&*{;P1@+}B}GaGT^tjk$Y+8(SUgkT&M-1FjhB0=b*e zUwrt%#Z$z;>HLg%euJ(L^Q{_l50LWp7UXf;HFOO#--E#|Qodnh?xEm%*T6a?jkyEh zCdkbha|gjKky|$A&H~r>9jrssn0pwwqBnzA%je@T`}^Aum)w}*?!k8Ffg3vm&&O$U z#s2J!RcA1NU+zM1Q)^;<3&z~VQXQ(~iv7c+!-tvoA&&w#uomX)y+%H7^4()G-)Hdm zFoek!@0)!p&;1^*47eHE?<9Pxo&j!X9dsj#%g^_0sSYV}MV~!z5qI3qmE0V; z;wJWfJ8|9fC3jrO_pOV$?uFnMe~+(I)X5d=!wdUy*N2P2jreig{MX6r1K+(A+#I=4 zWA5ePHpoqrD?Ts9&-ZWOM%TkS6pXpogPSL}YRoNy>)Qy=Z{EM+xQTi3>L=Vjy9Hcv zo)3{L=EZ5xbKP4dH%_h?w`~vN_U~Mmj$up1Z*< zZh(DOH|E|8u6IM4$A80qaG&q};3mk88gt9wmdH&Ta~}cMw-L=_WA0<%Rx7xFsFEx8 zB|F{D{ai=|+|U!~dalQD6K<64J_WAm%^$q zQF6t7m}icBXNpdqA~xcA9o%35^GzGew+?QV+@dk}9dO6UtsASu2jGgj_-~Nc-&@yz zZ;JRgou3g;1KirCSl_5I_hTvFG`V8`@YB7x=lRdT9i#7E$}2AadnW%2uKyV9-?HLv zUgqZ81UE%)Lve3;nCt!z-1?KauKRDqet^HU8eqv~-1Eg3K%{AXh>$C;-}vkAS0XiN z&y?b(KUj|Wy5854nF?AeV?rWZl2tl;_~}! zMR1$s`fkQ?bKhrPaK&Ip$Q9?!+bSPU5&x$1GvZlEa#Q4r*ZsGC{%B!@Cl|5Z)ulRw$PG}Tmh3fqP}EH4XTdr59Zac};F>;6h|o8*f7eXsrL;IPg-6R{D`KH$beIBvn)u^-&KzX7*EZrqr= zKh|M8%r|4qje{E}w`9yc7~CScbz|8Gsh5rtDU4P`DH1m9s05>rS>l-!Z4uUKC zE={iJvzgn*nf*IUatn$(o9!kgx2m|CY{kuYw&Z&6l;_)KZ1*t94U;R*^N;*^gxL>s zB{!+KkFni_lA9w}oG&7;b6>|fN^;AJyDQs0PI8-y`=8ag^*u#$gMY_<5OsK+?Vc{V zamC$gO>VyDN^VARw_&?^$t@}F7Sp)-7QoFOi0fosakpZ-MJZqZUGliinaR!fHpz`D zZi?;R4Q}ortV5by@&2gI_u{@k>H%;Ykzz0p2z(4cV%$L$c-y5fBjtp+$y;l#pSQResDuOVjW6~ z%U^#3;AY6JD=vTi4T4)E*FP?g8-M-%A-Lf%)*-66{PlMVxQz>F{Uul2f0#GIz5g%> zuGm-S$%V;c{iXL=?)BzOaI3d23!hUjEAC2cH!0=YAXoh5j$d&eFl05|sk?41dCBt;qbJDdR&0wM&thSPA*o@4=~mt}WnVUJ-C2nZzE-Rw@- zY%-gJ9Z+Pr!zDpH0;mK;h^P=0H6Cb?!*Cid33m{X$RR-mf?QwKdrTeap3GEczR&M@ zb|6zd)o=akt$)2;U0vNXOI%(rnQ^77zfA@=ZE+8C=B_iiJ;deTiF(-ieB5GihltD1 zDeSq~t5%IMrA%cw)MR;fIHyRaZKEa`+F8}D`p}$T`+&o z25y?TJq7dkJm3xzcer5wUI5(aQK&=t-Pmsv*Y{%Jwi7o_+=<7-rNHI*NE4UG-)je4 z|J{ho4Q@AadEWQN?@o8T?!E%J{=um4AaS`e_xt`=0%CX;a!c>Qew(e11Fq8?L{v_(SB*MIE{e=I@Qbt)TB; z3|L(E@3;I2xasq7J~>KUJ}$QYzUzGQCg3LN`N_zA7!S;Ke~$FW!0o0uixGF? z9i`(UMO?@f5#oNl{R|Lg^C%t)=I^b*9iiXp8?^j&|DDv^f!jy^mj1a=$MGG&jnMOF zmBi(EaDPtsSHMjkgZkDK%->%FH$ggd5En8h6c4{e9ganR`wHgo?|@rQI*eHUy2ryG zfIC3`M*0gC4|f5#ljbFH;zFj-*ZuzSpU~eeP~S9hd0o!^_ciWj*Wi57LtKvESDc?S zzZbcEv_5J1+wxP_^~paQ{+8Zvj=%qQ_V+>H4lO`^qr_!>-Ti$SxC7^+4mHH(`}04# z!u34=sG&nUaru7XXB+w|p+ob0^Svj4>n}nbdJD#V3b>ub9WEI6S>TQkxBLN&hl%Sj z1l(90b%+&=`!aC5h?^=H_ch=SUx0DeO+8Uc(s40BT%J$5k2`MwHxr%@ zV!!e8p06&v?xoDWJT`pqP2?`deyc1P_Z{F?5jR;d?)$*)A#QiUxE}$xbP4J(R4{G{ zEbY}0xBQ_(_1k8^?Imu!VBD>MTecK+XfGJI47ds6_7#l#dEoXDceG&KF95fE8R`&y zxKRDJJ8+Z4O%#l~4{$4oaXjlHE{|tJ@422g_Xlq3R^;|u+`W%+y&rHe>U$Y-M=WmR zrmp|4;-SDDrSnDkBZWG@RRXvBIE;rFaVI{me+jr1Cm=UfFn_-c+(F`Y7mRx}a0f2O zej6k%$JtrV{WcG{(JIuz`%9tv?HJ&uNrxzLC*E(1fICF~))dU&IB+{oL>)Q`#yuXm zqpPsr`iRTl*E``X*Y)Ze)OSAmJ4{@@@9(}|T?^dO7;?)8FdjJ0+}F8Q0Jrlbl((+;6L#`>h_hUF2_n!Tdc9xFe+RC~+s=ZwsW=c)zU$u6GJ@;|1d;f!lr`_FI~`+;5Ye{~hUO;C3uTf4hmx)jQbtnwiCCnVBD*LJ4D=(f^okG z+{%@xL*&Uq#lv;L?I3QvVB8ykJ51bk!MHyHu3v{b^c0NS4ct!R4i$|16X5a^VcB1? z-}t%K2DirI?%~Y6-Qc!c+_SfI_4gMBx5wgs!yQ^HEbNr3LjauA;Pjuz}&fwNq+%GwE?=-j_7Wdkd zT>br{!R@oSw>Wd}0&aW=<6(rjT-jq4uJe++0nvL2&UYe%7!Mq0k20dC)EIIedW%-=_Wn_Pq3!Gdug2X5qe zzr6t50n#@{+==(wi@=RGqQ0qu`TG)Zhltx< zFz(C1P0{f-NL=nW_xmER0JpLUb?}}oRKNWlxb37vl(-Y`x7UC>O#aps%-??iw=+q{ zalyE60Jq~HJa6_9cP~2W3{SuA$N8Lp*w*((fg4+g{*D%m`vGvdp6GKJ5B&W4n>W>c ziTCA``rdyHZVhqyd4i{QdTm-hJht_{4}m*MI&>Dy-;WG``-#iX8|`+r>+?|`1Gl@G z`mJF8eq#7r@x0k@zp1Hr?6*&W8z+COh&%Cq^LQwLuIwN#Ul*SB8Q1HJjSOzD#l6g# zyNSUaA}(LIe0YrO?=fu#T%X3BvKO%5IL_SXlck2gK5-*-;Ow@|9f$HUluzn=TLHJP z4dXXeFm9RQZx3<#`RZR?((bs9_&I|+L|pE-5$AsUJa7}FL)nXk>bD(%TYfs~>l1h4 z{q_amrq)xx6^t7JZj$`%A@0QcZ7<+*Yz`5ZGjF)w_51$&0HU)T=f7n`*l)}|`vzC; zzJN%lsNaao$FaM=`vZ57xJira?(YG>jh=!2c3C>O`+Ep*+lf11aozom0(XeG-b?23 z=I-xQ;8vcAIz%n5yT8+b+d5&A@}PzPNs>=@!&q5oeA6?;`R`i=Y8(u&ewojb2j=r zWO3cchjW43OWd-*o5!*H_;4O@%hKqtZ*kqnhYNt4Aa2s)x{nVR0hi}HUBu;ejreW5 z9nSmmNqz4U;0~RSIt&(!dpU3`FF%Dt^#hV7Jq*y zNn9QuzB%t4$MNA?z~w&aB5s5-9^3j`NASLUQs4WI!5y@?J8k32?F4RwuDi>IvER5d z_w}7?0pVXr#~X1cuJ8AN+ezFcaVM_t4}d#D+-{5Ou5TA`yDmZmZ<2wLRdI{=~BJRZX{UvZ~h}&)H;I8klf!j;m zA&cv-?{9#cxD<6Le*^n%;yT<3+&<#Qh&%D)xDUAHm(lTNaou&e8~v?7ZZC29IClSc zOYQ|OpA(0O%j@7Z9j?#s{Mq1^y@~y{8&%Xie6Hhp{t?u7Kh(h|F6-d_@2m_M{w9da zI^6s%R~;S$ZpAmy-_C;R@U-D?KXEzp+&x^^tDj{A^wcPE`S;I`{o&46aIEB$`rdN} zH~JRF1K;mHYsXz3xi1*pgvGtbnLA`~yNJv8FIsPMy`Fy=xIoVXL$_g&z25x1SV6F-jM2kt0w`z)@zz8?U0nBsSoxD!8) zKLT#|Rj6;p2=?2=_5B#Q-nWojL)?k$`zdg%h}&s#-SsVjC9TqLqrU?M(_vHK))2S! zokERgrNHeau5WSOb=V5Hd>p4N?vW!GIiBA>3*7SWqP{%^3dY?DxGCax6pXto>Oj{4{ltw>fVf|0?GD_Et5FB<->C1zxqAXP zP29?YalZ)MLE1l)@0c)z>+KW4wpxTMo@eR2kH zE3ZWz;sxU#0o)Gawik?hByfj`+gC8|OyK(8Lmfs7#yuLioy3j4Td01U1KbhfCJM$q z7Px#K>LM=R4_Ncb)sAtt0JyR5qrQU$^EVFMF5;HGhx$(3-^IWkC2owkJWjeFZ_9ui z{{iZdE||Y30JodCy#@34MBsYYp}!*q^Y<&jts-v4`-M6#P6cicachV>@pz~KZfO_l z&{;5lR{*z$xB~_Aw+^^`9G8xwzWf~Yd23yNmud}glQpPAl(_tmxcl!ZtTp_tvHbm} zv%gKi?YkcRZ7-O=>kNN;Eq_mKbk(=j;0{^bwa(l#3~uQM=JEE-_q%6utmKpW-VcDA z`XTD;7mRy7a0iH+Dj4@h;PxMb&oT87m)B_ro!4n^0&WF8Pdh|hUMFyW&irQJa-Wp_ z7yFHmw=U=P^=^af6PMT5FZ#`uy4LfT*J9f+{}5c)&#;&vSpy@#ny;I1lx$vbgTg z8~p;f9XHYVOI(gKcYW^wZV#ys6Y5JRqBL=N{Jn3D>;28U z4Q`Lc?RVzhV{nHo?vu{kdkt>cCm0W`!?VuZ`+ytY1pCb=F2~t#o%`+2hQA5o^7-P+ zY1i+Y_8Z(zi|adc?>D&p7I%R&_W^@DN?gvYsdc^I{U9UY$f)=f>9s=z#ZHYx&0P*Z)fh)z#aY! zaz`xgBxmk3hQ8$+nei~=7T5X1vj#V2aSwOqK4)-K7B}Y1ecs@9Tik`t+!uh`wKewJ zAaOZ<4|VRh7Y%>Cjm`0QWRC0aDGV9h3XA(MXYNY|H*Rr1b>{vJxRtl#d_6^69?#sz z-puRz0^DKZ4q9CI@%L5W`aee!v?qA;?8j9{=?w*Sll_z+}D9S`U|=~CN9UX`}q3?aN~DSJZx&lgZudV zCUConTWN9K$KSV5-(RA?35)AK{{9oVonOUyYA10ye&;*)+uOkHiqr2rS^oYt={k@4 zH|jtK+=#^;bmsoY;6^qxtpxzhfRSyKwPgB`;EEo>kpd&x8gSRH)?U+*B>?q zZko6?7T10Kp%l20-Eo}kATGz*70&&(1#tPe=p*jll=0oWcZ%@7d{W=r0k}PVsPAaO zxH|#2^e*bREifJ??(Z(Zts!orVBFn-+e_T8f^qi*ZrPtuhrxnz_W|z6&B!g=67}Wp zleyo|Y65N_`Rf;q+YH?DyV2id!MJU}?cIgeHHgd4uV46`YnSD7Jg}|rrGVQ{{tgz5 z`&HmZ?xB9$3j1y1{+&3)bvOsO1H?@ijC($CEAB-ddJD$A2)JqDjuec0 z32+CATk#p}w~6a}IdG%*p$;_#<6a5ecH(vxjC&Puhlo2+Fz$DNTlr_yq4cwb()SwR zb`aMm?!=F`?*Vt1xT%71uLG{%k2>@ejQd02b`p2EVEWz!+!5kNwk}k^{TR5h`%#Cg zf^mNeTps5;h|BY{H=Tbk^H$(i(S83u;&Nr~&w<4`|dV$h!dClZJBew-3#2F2hra&aVOqye+F(1 z>DxoxiTB(6!0mgO`mJExhk)Bl{zkSfRKGm}T#n5+aarGQHo87nF#y~o&41Ixo%r)| zj{&!f#`PZJPJABq1aMP-p?)hEcM!PckI?b99roMAj^zi$AygSe&JqrMaO_buQK6W1s1#PuBkuKzgdkSdtJ z{{n6&aeFMT`*ruffjdx(_i=`a%j;(c)*J)-IbL#2eeYc;7kdJAhH8^gy}zQrmBgL6z9leqtRil* zVE%3l+#cd~7tG&Hfm`|%>M&F=e@lT|L)`KmvEL@H@0P&rC2pL!JWjeFZ(9MkY!G#5 zFPOid1#W`4eFgJ(8{qa4ceG&sZVTMEJ$p*a^6)XHeg=olxJ2`@1u62Z$RZE*}@}{_YCgif7T^biw?M05?tC z-h%nNCvXReJ7RI&$A`Uv8zFrwzEG&~Y+vBEKZp9(5SRPS-QNn}4iUGrVE*n8+{)+C z-+_YpdmwN-h+DdIq4Yf%xICZpiObLLTydT2bGlK3o3OawbLLJqxE&Vv250V6gWGFy z5AJf+VY$;0~Yru&fKGb+i?)yKlXOTe&gfqvLCs|+0ll-6&CkuXYL$>8@IUL>8}39 z3~tKeUgpd_#^82Y+}FSA>hFBu#ty-8y`Q)d8aR)8^$f>#`$fR*dl|XjZWs>}=Pm|r z`76k+EEsngaFfJM7K~d3+WY_0jmjkzV7hK;-THI}%xpjuWT^9FB=ig~a0Jq}r*lz>G<@=`YI-CaFG;zHM z_8W8Eby#cY5G5}6+ehDaJr5-fZjHs=<~y$37K7VCTs{vy_`GZUwi(=Bi~E8zHwE0G z*XTGVF87-$~c_7FE&Fn_NBZs}X7LwCXa z{T}K|2mcUp_o2_TTb}(mpK*b0eeXKpmi-g`E#DjaZQ|S;fSVw0ykOiP89KBRm!B(c z+V?kK;f3Ey5BGVVm>^!^}VMIZrbARaJlR6T|I4ZyNS!c-*@AiuJe*- z4eo&DZ@II-FBsfW%irm5x%xW<+>T-VUPokKj0f(weVqM$8Mx`ScpVTUF6;Zoh^xP^ z0=MiQ`uE8!e-Ci>ci7Ok)AINFf4Tbmy20(U{Qb|nuE)h&26x!vzURz++u)Xc(TsX95@VDLK?&QpUAGkefjNcxMyRS3%WIi>( z&^c&v4|L|93f!`4nx9o*Jn;3~@4w-?&UHU<6ZAY{1#$U%b?(o-J_y`$`u)@@%ijl` z{e2j?-S43e>4N$D7vS>wu7|jMz4_K0*L9djkxS2~4iOh0w(van=e8d={4LuL`a5WG-TnP1a8txBJ-|GU-Ti$BxEv3a#O2Jx>b`m;@5?9k zz5g%*iX|-Wj;ma`?*X@CM>>v)%k$qQGhDAPJ}~_4v$)^6%$2(dU$TM@!xne_%dYdC z%?)nZffx^;qfR=dVb`Vk^cUOu-WCS8lDONG!RiNGb@+_ItsyR-FNW*Cbt?OiPwIPH z1GoERjE4^5^7-Po=Oi4j=eGgw@F&RaEttRC8ak-9;_oCzJ?zKfPcikp&%p2dd0q*a z;=3xvpR22vx79ba);Cty*G`#SeR^_5)7sT_YRNad-O3CwyWP4R?b=kuR3baKO*xR8 zy>cWs`}G;ebFx?FS^aKR&CG76nwQ;9H7mPap8B@tsc&nWawHeMTHBOhIoT`oZ0&5w zF@78Ba?`h=PBklgz4__eP?w*+!d^L&gI>a336_(+GSAx19OJj4HAj70RkO0!o2R~c z#&1KO@hj|=V7chqs?4*sv$1ZS8X$7u3VS7VZuUy>-0a5)KaT%n0((4r+oAF7m6F(i zaqMk#IxBi!(D|>mxlJ2E#^+0Wy92WMBkl8Pue7&2U_8Fv0pr?R4vlMXDLS6LWu8s{ z##IgVD_U39S5KN;S-rNlWetTWBw6aol$$(lx>LDnlP2e1uEo($QO?OvQ7$h(>zdb2 zUL}=Gt`zlUqzu(j*|+3p-%_8eef{LqYnxXF^)Am=1CC4K7nTcBEthgZs^w5FQ6K1N zHvPcQgp^}UIEBYOw=Yp2=;*lhC4&Xcp`4qa$(4?Nwz%n;l;P;0XR^i3&vk)rj^BUl z0^Q7^T%emdlyi*Fb&m15&LKV?l_s8*P zjQhFRj}7i|+YxdQ=1|VAEW5sA{bxVkvZ&!|4`h@FaLQf>X|8*Z+(t>X6DKH z*2lW!sb^+>onL(p^J~yEQ_iSv{Nu=BUXJx~H{@Gipqx4Q$>s8`FaPTRY+t6FQQ^4b zlEd`_)fXse4)w7x`NgNYUdgR}iQ1Jbm#eFlP`|)VEt+MwQ>$ND?N;W_R8U$>@~-8vR|(R&dokQ|22G8UDhjXxLr%z^5sg7tah3VS?zN1ui?xUjjbyK z*FdFYp?oUG2N}tmNyaM|c#w@--#SM>*9ESDN@uhCxh`-GG;6uFwJTays;~>?gWbA> zWa+PQ>>G4jxt-NscZ3R#V?V~B@$7AfvfFC`nUg>3)d7)-h>ylUhiTb!)zV)##`PRqfa;>jTJgw7`s9)8(Zh62Gb$I`2<+zEOt2vcpS92-X zB%UN{lV`BgCrxju&y)zQ$Fv`_CNo~Sb=9X=u2j{8A8%9-+K;Iwyj)T&OlMk=WqfaL z(w>eO$1WFt1y7x|vh#9kzu>7^Pj=qA9R1Tz2BG~V>Rq1;uO(5dKl~8N6LvZ2BJ6T% zudvIh9W9B59Q|v^(Z7Zq{cFg@zt*~z))m@Xb(nr+Cq@D-sKsV>d$smEj$K~d#xr$~ z(VuL5u(xU$&t7?+8{b^D&aTUuIqEI!EU(AoDzCG(?@YKinp;1fS=ZcD+n{ELVO(j~ zmK1}Yi4BX7_06kVme;n_O_`jZ{q(81+ON)&kM_Cq>s#yURyEYFZmDk58xf+<`ew~u zuO!qyxu&^IYio#Is&;u(b88NE%j;IxH|Ahh*Qk#|q4Ab#vTksN`6ulHrX68%0bD)k zvvGypm=kg~`+(_4Hb2zCBy`Kd%`Dhz@@BQqv3;3^*<88#w6D3PwMjo#!`cUSTEJ$t z(-g~Yrva&PVfHPxr`P4uercyuv+-7Fz^rx}Fq>UdQXPTg*l9#`BAdM?XJ|ahcDHEM zFrGYrYt0Vgt*EQdI?l`eV}1i5pgw7*KvZdf-KvHrBLu-R%+9Vj%+9Vjz^VoXn){0SD?@QUxfO;EO)}=_T;QhK&LFHFz2EqIFGZj`9W~V&KW~T)n zc^=H0J~bzvre+YQzO{N~UCWB*`lLB_$*RNb*Vi_$s&1}ZUENZDW?gk_?eYd=I0-A4 zsH;s@w>HuH)=&f>IpIhMFQ-b>l@Xf7_wjMNfb83PE#!0PFz=;C-q>x#00K! zrCo7Qz0%IEIKZx@wxO|2zXp~b2HPbQwdj84JJ{xUANvi(woEqGpHia`LO8uEicE1M8J`c4LF;m3FpyyRu~8NLz{4LWnHuJU4|h4 za=b2VSsyT91o4F3m;ocuE?^)CvWcuwQQ?$PvQPT?w-j)7E50(g2R!pG$qxE|>apyl!X!JG_!IKXao?b@}qnTFCvm|eAgaV>1a>~ioA>J^h%qv|kTuI*?TpJxPGKz(MQh3gR* zaACY0{Kt+p)Ckl!FaUz;4GMrDyMWVdP`@@vyBzuz>~d)@Ow4m=Z_orjupI#t_yD`6 z)moi_`zNWPI%K~sLy%rgt0zTm8A9x`jx&Oj(>NpTa;r~UoDOW?WYxUj{i>S4{c0H^ zxV_8A;cLqefqYdwn6KOm+~2tRw6#ic42FPujKd;izvf9+j^iS zu6S%a#8kYYNnbhy2LtTt)~-mHgSD^>wi_dFs9m-74d7s2@(ff>y$9N@Z88^C!~9FG z7y}ICwba>{6+!K2(iay3IAXsFli>ZTmjd>;RG(g3y`srwRdK6Hj$# zaQn5@fWY>(WQ!N!N6T0NLO4?+r0b?eXUR))miM67}@Pq zr6G2y*6P}3{p25NSG#Kb^{K|XR4dqx>mS+W;9qN#Sl2byG=p?WwW6I~aW*@>;sCp* zMlt@^HdL=}YHbpV;A^a1)AG~mR`V{Cd8UV1><-?q0Kxl}8-e@P?jSvy>sHmZuCNxW12{pKJApiTSybI7 zkD@iknqi1OZLQjDE1+Jne=IH7E>UYw$U^PLBE$N*tu^cUDJk}kg^jIOEb<3TEQ9RU z*4B%Agl0>!*s0(UEy!Z0ML~$&x;8c7fg0g=_l~J zz0xjdMvD%F*oPJfvKN!(y4BjT6RdxWIM=ER|fyA$E4PVLZFqP&=#IU^|T#;8$I1b!$S5PAjXEP2yNE2cAItvC9QP_13itJ8@55 ztW%3fp#I<_j9V?PG267OrT{xJ3s|1ReOh^EQ`lLN6UwuM47RIZRllOvxXGT?POCes zomO{{ogOrS`&TqsM_FK;);9_}%_ZoHFrMa8xSa+I;Qa~^ykB_{xL@rKiod`M z_5hBs3mw)%xZwo?_>FK|Pc=16&mgm)`q$|T6#?~${i?Fy{Ytoi{bGRB1`Il2gY4Rt z=X9PCUzE&CUuhp&Ai$5-+7)ZWFe4vyRClw(?8bl2u%$I%IV`9jT9b{rteds8Hm?v* zK(8>@0E7G!b~&uCNnS4Nj?&JoQ+8!=z2;h4xLr$9AB#fmR_Y_Tv%cLpX|&P;BY&01$eAotM*h-P&|wMYS;~E zr`VtMd?@!TKw$leY~!{luXYF3pW}V)R=f|b^{w0t@CWR)DxpMxUFh60gxge`)AN6= zO#zS91o@fc_f^CiVgN9pJx%L#dR|66Dw=g3D}KGTQ7wD~)Fbz+fBI*TP-vDPadU=z1~jJ0i5&x$j|LDJl`s=lGFdX*TOtLyAF6)9~t z`;<1)D7%&Qr>|TwMeiGvBlfq9vpzZgEV^2PqFe6c?(zvT>}g**p|1(fPBcN|nZ z$J$kE5tH3ceQ7zX-DIU=R=cS=+Es?ziMHm{UfnKRdriCW_8N9s+H2TlX|G`y-rnU+ zO%3ANjJ4usW*szKJnXH_g7mnDeh#$H(*6+pP#uEp!}SQZ57#BwK3pG&dk{t(2`XyF z=wjGq(ZjL})xoq2Z@+05-fq(_r}i4lrrP)iaiH-;q=g^vmR&CG6}+6C7PBoZG0@a%S~;h}ccS3R@XX|2u@|4q%+leAW6 z<`6i zCr8!523!6ac6x)e+o=X;wbNoftDV;1tae(1Z98#MmS}Ej6knPbL8rYeyVJ$@drh{S>^1pvve#s^?d91dm$)(PbU`e=EjuMdRy$3Atae(%v)XA5 zR(AaFg04t3HMP`Li?xvEz_?*MTo2StU~??5rFErTU$oZl*lyMV2SB;eHvD%?Ip5~G zelE+gAlF;sZIn}q9`ZNLn0aCQ$IBl%{r{~Vn~;MgUTL7K!>#=9&f;#i4>T5;tjC_B z!}rvTIDeLwCpS6Y%69&kYaDRz=h|+z4|9y$vF9wk)vA4mB%0RN9kQ~vv9bP;SxqbJ z4r!@t7Ee_jv~ImvYh2xO$h!3huTyuERJnomsK1@c`ZgASTyL0P>98F+<}<(ROckdx zkMl=UW_)nIYkT{MXQz_;sdzEJoc!UGo0Fyuwo9-7JpFsgY>_?Xa?=hrmeDiqUDDPV zSx|dMWYXlwq#1`zt2`_^IWjpqX~vcomN_fyR<#@)aNl@5eZtBOoq>9D+E1Tld~Uv} z>KDtM%ttt*nWm+$Qus1Mu4{%G#!cEw3oyI#9L*#7w0i?Kp_=ls1yL&XpGM8y8c zo^6e58k^QP>PHaUr5?wB_j-W(-GBvr*j(goA^v*5YQ|^A^lN5*QhhFwWj`zaWV!<4{yZDj$r>wW_DjVc`s zp8a7fks30QaYof26!ntMHu{pbAHd1_pc zWu>k%l`$+|y;i-&*0=I}^oQes_0{44{9=8CzO&}fo4s%;)dq#>df)LI&1MDyi@uJ zo#!n)Vdhe6dX~{o)0yld`t6*IUDvayb3*9>^@P3cBz8!htH@v5j@!ZcBJ_vjfpym60X*Y46gn?hv~Wo-I+I<*_)!4n^go9>4}|DOa%7S( zh%KpepVBY0Pi}BKI5SP{5}!+CS*f#3<=8A=BUZh|);ZaZI&(a*&RRTxU#ySNdG4a4 z7c4s3m{q8F*W#J%BF1k8FlXd>)VWgW0riBv?JRakoh!&++m748`NPVtM3$90%k+z6 zP-WFyY@G)$Mx8kxSZ6IBz%$lI=)7>z(wU3r&NfGA-mmG*cH){@jnQmZ{vzt!rSu>L zf|FfDw$!s)y$`orpVm5kLbTuE&*KLA3}Xgl@8SM;AB^kE%hADl!|}j6Yw-ZCvyMXN_{_yi=gpiS zAhxh%J56uHJ~Amfc`6X`jqN-BhPn@g=%^Ke&E3Vj)O|qdX_#=kIJ1-5DL$9TvhrLg z(<8*6e2rT57F+lBD^Pci57u3a5Acii5xT?d?wDl@;;@6>c)zB1#!f6~PE{i{7GV3n zmr?JS(nZIP*^Y=Dskcvl+Xmbo&M)myaUKzwa^4}+!^EF_C9Hajt@kMT!*RiSYjFX7 zu|7g?DfQyn^JmXoGFy!)ykFB>w~I`T&X^7$dSm;MS5WWX5dHKra(fT)C-v@8I?C+K zi`&B)$t#uKvaFm_%XAtU3|jRTTko20qCXrLthW{y;2G<)VA1ijm!24(EoLJN^(i0k zXT1%(fOWda-%;lZr3Wbxoa`;KrOxH#uWiNc;QT>lS0c+won^W|8N{r5i>-72Rj4z^ z1M95C19-+dX7oE@=KN#HXPNN+F*-}T$drsF+r?f(oja5s8JnODIUklfr^#R2hTFmU z{*Lt#jvhP-l(@)>(@O z@Qd}y=xnT#W{GEE7vVuskeJi?57fCv=>heGz3nG2XNI_lgXqML?> zO*yVgoqLsjrU|u!GgInwi7YGimFd1@Fl^OZY@HKVqs|-;tg{vm;2G`G)=sk2OvB!jqBZ?SbA zyoQc1s+V=v;sHEkeKI;PTqM?=)d=*IcW{4_Q{OG09Y}fyh^{Rd2ENj(-pR;kaPEwYUJkSkH{!V*Fh&Z^@E*^YvMt z(s7LL%04m!i1^0b%73EnrAi;oYV77gB1`ICO8(mx+%C=^P~7*urhIHht$K^C zd*Am_ca9I%U5gKJo%PA+ew0`mnWZ%6{bTe-J8_u~n9Lj7*Sw8-ri>#q~V3k28DK=Mq_V5Ai2cZg;uGDYpLIU8q0D z3HzbN3AoO>E?G2x-qCVN8*EYn*GD?6dW)@d*$wCq#{=uE#RIs``k;PG7tfnJ*SO`#`%Rt6PJ2v& z?FRpaIuC~E29;`W@=8?d+^_W0_KN2^s2!Zyu0EH@vhv=!Of&0#R=vg6IrT%-nd5g+2$GOVBtc_k`!j*`E&4Yz~yN0nWP zEW5q z@)cL5Rd2C%?!6gx=6GP8wRiy6S)au-7tWnsy+AButGS;v;Qg$#W@nrc*)H`y>YP@3 zKs{k^a;`3QPLjX29k+w?qunZ=W!cY*Kbh`823=OY#nw6UWAumPfpym60X$=UP``z< zXD%j(DdGL5&eBdh846pr>l#I!heLET={R4IIu9!S3=?h#XLeG%#OD$@*O241Or_rP zRcdjHt#kV=s58d{>#W5C_{I8AoX%5sWMFqjKU3!g^Nu!8hZ(#64^Zd0(gQ&u?}v+g zsk2Z1+GgC2O#V+)Jj=3j+>oi%TfUN3y~Wmfg#6)nV4byi0KZI~=h)$#(a+Rb*jcAS z=8XIob?yz(4Jy^%lEkvuDc7l}sBspY^5v#+WRP*{=K})HkAZ$gqMoU-ta^*BbEF6T;do%3wRjNTsW?QPMKD9IdJEQB z*oBPCiBC}H;Sk*v8MkJNMCv@K^fOGj9h})s?Gm3$WLX)U-EKad??z|m!=6GP8 zwRjNTSvoJCy(B*KgoQJYvKCP_J0q?&duy1^j3ZI+v+(_~xY7se4SSRK2c_tUqt7!)V}&+?6-6lcIJT1obHWL=T4;uaKhf? zX;|vq&i-14nRZaV|0^|a$g)yrnX=BkR=vg6Ir?k#hvR{D*5Uy?XMN@^t)5w>U3zmq z>x=uxJT{gYR|YmgeLbZE@WbAY5j&*5!y)$UKbP;O_K43Vvg~%^Po_NYD7QGp*0-}4 z_2oEVeYH3c-l_AU&~Hg>(bBog7D9IBEkI|o3mz}L%~0nWrALMpv~jG+lsd=BU)zS; z!TFKjs5q8oW&FyNbxvFL7F*}C-=aSp53I8m58yiMD0N;IpS?I(ZPg!ITpRZ0=%MT@ zHb>q2Lv#cuw72^?zy?XSS=)C9fgkXDuGUb=D^n-+^i?9mm8st8P7L&D_)$sC##aj^Kp$CWkSpd$-b4 z+bh;Tto+oSN_SaS#-U&59kla2kY)xezQJ8_qmH_FPwSw?CSY5#S;oK z<8ET0?zX-0MMma!ZHc-^ls<-z_6NBFBXy6E|Mq@v7w3;CyAoMeKA#}d-N_(k)mv=c zhyIAVb9}JwT6}<{wWYA~TTWsB9ccDKVAFR6;AK;m$`}}!xV@nrWD^k2)(>r6Q zf3uP8Mm~c&mnl6+f#Bpgku7!h$Y0xv+rjz$%C1C~mG{kMx)T{ht$K^CbMK!}XO0Kf zS&IkojP()mJ-ce@;+fSa%$^xvq$Y>FU(;E)Grrp>foxyCHR_#Gx{wmViM$OY^-hxC zwiUOB^P_jGxRzz*I4)Cu?y1wNx7d0|?m>SzE?93ZF2HrxN1i`pv**vZF55HuX?mlb z^-V|S_}ie)!y&psrP|w4u`P8TRQhRq#duEb;LJ|-xkQ$g>mxGdc}l6pDYnk-_oB`m z53I8m58yiMBXpKC4qN6Rox#rdlA|CoCsBqv$CVyXPuSZsu|w+YlfSkdw^N zs8oA9UTjO9yOn<0UNQf(@)LhnI?J+heMF}6c@X&;wCXLk&Q<;B561)R>{))ZK0@bN z0mDWnPBopu&i+m#bNaSJog+#Q6d>gN1d%UwE+c&!f&GA-ZJ>(8ft3l{yb8{R|Us2WNIsyTs=bSyt*SQyw?UEKad??sy1w z=6GP8wRjNTDSbGer$DZHWBqKMr-;jyL#L~YbheA{fI3$xJrpcp>nkEp>Kr3~Z4+(> z=a)UK;#roJI?I%GPFeL9TW9YP^oQetb=KkmTxWfR&ajRbn>};>QvT9|u;Bfg&YE3h z`m||NrUQuH*gm}@>fINjpI%08pDg~Q-n~jknXO*b9?nRr&n2>~)LEuHj~=q>Ew=V@}&H0+na(`sflu6M;wLymMddgAXsL}!WVQ;639a7(N z^3%3s|2cm^*_Ft$+loJ#^7tIH>MgdueFJoSQN66M76;%u>x23#;W*#aSNs<2^vRQ^ zs$n@3??XGGz8y*j;D^0ciyczm6#HozX8fmo|4}tw$g)yjnX1{5bBQb~ue)U$5r6VkW^szGchBRfH^&9*t;GfSRRZsxhk7rY zzi{^AnU>^+ovFKSFRojrR!%$A7_HU#?(c&7*C?H+=HO(x$d>vis2#Qyw~zB9PpEj8 zW#xLFO!p##cB|fE>tFUH`onR;`fG6lo@x3oSvF6uAmEGhHNEA2aoIBC&`HzAjyuU+ zQQx5uy_n0X{B3cmZ@_BR-eNvU2_*QyJ&-HEPvcY<-h|MSVFASYIs; zz%SNO#P@N_w5Q5AU(;9ak4&93W9pQs8nD@}Yd6%_S2_Sc>}{pkA@!{wKW#hqpYw;5 zU5P9!^_3~>TV>T-Y<&lwLVY<7SYIs;z;)I~=o?$KNZyIY7w2pG%KeebDV3GeqiTR= zyMf(N-!7#CqXN@9kt_9WCqHc?_Mh|PgKB(`Wu?9{Wqo_CdW)^E|1|o;alra&aR9Ef zKC>1rTq=J3w0ib}xOO&F<16cI*hLOf6F{ITdv6ca+f%xbMR1Z3*;4P(5PNP9m+qtX ziO(gntekhqbSLpAUlEH_Y`uG)LA^OHSZ^&Zz%N^G_kW31gVexGW!OHt zC+eM4x@gp~oAn|~>YX6JZ3}J>=SQDa@h!_ry=BUJcUbinTkpto=nuyQ>#fBFxX$`; z+}b}q%lmD;!7g&p6o6=NY+th%>OB;qpH>7mPZRG_??I)bVZ!a<%r0u5_*^2(O1)*u zdV3b9*m`$7k9u=lu-;l+2=CPK&w7h*ATH1zE6dE6ZN0%Ra*#SP0!{Hc_C~$qN*A&S zPS%KQsdtS0wyn55oL~Baif>s~>Mc{&J89KhY`sUxAC3#wTZ;>Do#T=9o>k z9DAe!b?#7lKs{k^O=5@CIZgiBcH9om_y4BiS(cUaKACP$20d22#nw6cGWx^uz&dO3 z0G^pTAGK)d(nazyxXg?9b39{zpq>6?D%-{OL!C!MbjyHgBPmj;^RUv-FyVG^W;eA< zd@hk?<+veJj^}cVQ*50(UqPKY9$05B9)x%5{Dt~0v%`7J`H=0xoVJ)oYj zw{>EN)HzQ6+IHLy&M$ja#j`BCo%oZfjBEKyTlE%OXYcRm561)Rti=QP#c_!G9lhuT z^(c+8-;8HzXMWR&Ih_Zf&ix^}0aSZy7TZ$iUZtP5S8P%{I5Vw2m&memypSnBcQ9<# zTWp<^uc6Ky53I8m58yiMbNuXC)r-Whs>~ZlXJr@pVl*QD`yya6Z_MjE5cQ5KT{1R7 z8?7Q!>Rmy8+cw-D&L35FC9DZdW)@l)$8aF#|P`K#RquKx+*2N>Rm>D+Xmbo&L2{CC9xE+iNKPq#-GHSg(|gt~i5 zA5tVZIYVSi-97T(w&Heie!sFSk!7XsGTnm=B38Y{*1h+is5{38>#oHIc*eReIeu2P z`1ds8V(nGG4LNpRXxK$2+Y3|7>zj;vr<5+FL~!yokuCL3lHax!w}Do%NA=A3JaU{Mq8)>?4y81t7gKcX$fw zJ{+Q>UPf-8CH|!D!%9z?oq2J)IHQN!DL$9TvQlrE^7A5P7N^*{cfEtUb9}JwT6_ra z)Hon@pCkX(lO?lfE!O@GAJ&h@7t1c9{S!V0uWTCXU88h?{b6rk7dxchRphsA$L-<# zihrp%mu2OB9GS}dzVel}>Mge3<^M*1I4)RkEiS+>)>G;@Pu$X348PQ=eX#(nRKMuD z>-Lc;QL@B@xs}sV_kj={jY8tX+2T*?KA`k8Ot@W~*+K0TpG#y}sk=;B_ff0fV(Xs% z59-eG!MbblA-q$1Lj2BKIMe>c3)WB9dk)w|rsy}(*skVK)H$Z~fO^8-(qf0yxsv>~ z?YJGBKdS6X(jrq{cgmF4QxaCa#nyTFUDTQ5fpym6L3n5CJnLxj#hF>^p0K`O*O}~$ zFM_eo?Ukr=kJ1C`341$7?2tNlk-xSbw}bN&@2PP_mX-5ynU<5mfK_j?b*_3J{o#0E zowaxX&sZNB&r9Tk?_$)RtzGN$eqCo}7nu?^Kk1o)dY3C*NQvO&T#+sHE+fBfD{c?x z4=TG7Sys+ZWXkiCN~_*t>)k(!dUIT`-dbFM>#Qf}ys~#9M?-W|C2;Ekkw~3~m41c^w}Uf#s9oZ7 zi7YF}5t;HhQf_gIt#j9hs58d{>#W6t@J{I{bzT-fTHMr$8{a79e$aJRb`kU8Y>ij( zCDgk{=>qkIytb4`+6$&n2>~ z)LW*k_lQ+*vGq=Wf_igYu-;l+fa|P})O*3QlTMmHd(Qls+P{dx`*poFyU3IofXTeE zedyVSi$>1mj7 zyEwCt+9^Jl$g)yzneHb3!eY zeO7feeZL->$c?wAy?j~k+0JqSfLivF)OEc-`gIz+%BKE6Zdxq;QFLP zlDK^R^xJb1Z|3BnW#oH10(Xe|p|fEA?gZS9671Lhf^l~SE;nP8xbk{Zz8?9vYrpMk za3cp}Jg~kqf3?<8--yAD5m(Nq;pSD=$EOyNSCkHU8WGaOExlZU=D(Ebg_=+=Ye? zqr~NSn04-Dj`6U_;FeFqIOBLY>&vb>9A|KSi+i3kcZtDG5SRPy#=Dvwi*XY=9HNZ`z(O;jq?C(FF{jD|pO<4XWr!_hHyWHS*5SROHigUlM zG`Ky)<@52t{tN2z3NSMEy*h(CMBKeN&K5p!n;Unv!7ZPH@xa%K{+ajhv5)EoY$h|A+c7ncHM=Yb@?f&iW<|Zo9?3=tEZ>)*0L$ zi+lK6uIJ5WgF9$(OYe2%wisM*ni&s0$GOH?D{@zE1mi=6#l6IL)wj*?H%?sne7Ss8 z-L>md+{*9W_tqQSl;!Vto%Kx_+%DqsbMQOeu$!a5XBymo;_^DduP(g(!Tc0JYv21C zaO3SbPL2|n$KM*~@%Jpl-}31gXMFuO@70GLujkVS*C#HI>s61s#@RUrH(_y4b>^OD za62sST|2q@dm(Upx5ah2UgGlg{3*{r;;3&saQlzL^ZXETdHw8-&sToNEzT}6bSOR4 z9CunTa~*dsHMmjYa{TtMah*S02He4K;BgTrF2~u%&f~*3fa@_zA6*zXuzpSXOyZPw*_ zymcDfgyrv@|8>>(YJ=NBT#ko7?B^N}*BIPhi+kN7SMIe2cgW&Kc5*$>f6w5S&cJwJ z9r}Od>hJdrZq(x5@GVz=e_(K{EbeX2I$URP(-!x#Ay*x`3~sl@z5S1_I$UpX2Q2On z_jdL727^0lao_*EtG_=qxRJxmID2xTtG_oQcV|4$$B4`GN%uJW5pWZ`A~$LI>(0H& z(4mvKJZU)h+ZUzX<_|X;++O1Hdf$Ghxvuwh8{9#Qdx$gl#|C%Q(&0R39d0qW<%eUO zu@247{{F<^R$APYGxw(kw~DwN4}H!${0zB$_&h<%^7pB)y2it;hQFN__jzaTZNM$1 z_1|9N^7`Z%r?{?z_W-wdGdzw5iOcg}_xo8t2X5Ks$Q>mv&wt(TXZ-@W3F1bM!1!gZ z`~9ptfSbA;=hZRdvJT#_UG@DXa0iH+u>3vwM%U|>Ujw&-t}i+)?s8}DZ-CoJ`u18} z_xpOk18#XK#={VC`8vS;zTWSFnwaJFPT-E5hS#xC;&Pmw^9R>?^&f!C z=ddc`@_h0qFCXl{Zrb9y-_Lp+xbbb!-)@WR zen0C;;BvnW5SRPy$NzR6AD%L}qZaozXYSJmH{xTQ@qGR6AGyv`pEbBXad|x3>mk?q z&hxlA^8_yfcbK^C7WV*W?n{OaJ(dnDoOO8F;0{>+*1h1W!>a~& z)Z(sj=DucdBQr71`1;~=&d)LZ!{GYF+S>HE+8{dcG%;I)CbKe4PKg}o8mJaUE zbG>co&}I3%_!-yZ?Hz;LXK|~Xx&H=k_sMkLv~-y391riJzo#JAJIai+1>pWBA)aTplMk{=Vz^ZCiueV{x}|=6=rL4iI;H4_}LJyXs)t%q#J|&qwqEqr~Oo z;;#LtIUW}~8{Eijj5EG}+<4hH9sS+I;Kqo{-%F}E;kl3X_T;)PzCUDelf>ocjaJ<_ z_&}~K-Ol&+H@IEIR;Lt-I{heiS)5PU|8+PuuIR>|jxO~32b?xDf{?0YH{lwkg z!`EYvzjFv}=9P%=sYUbxBNlhinY+l~mdDIE`%?d5jyfD?aDC#kzB|N^aO5sFxC!F2 zzOU`*s_#;R+hK9va^@ayaCbG~z#GxubJ z8znA3pSo;^%5vT5S-`FQDC*Xx$G2Dh8I z9KRQK9WjOL%qR7|CWAXbTprhNTjF}%vd-X+5|__I$6ppb;b;Cl4xvbfJUb1yKseZ=K{tKHAF-!3w^ zLl$?nGxuWPj*`CKe2g>J_jzX>E;0O#5SPcvpC0Two?VXINf>7_;&S}DuUCHqxMi2p zdK7W_d!gUodd(8g;pKZ*05?J0E=%7RH*$@KZvr=Y8Lbl#m*)>}t+_Ml;I0_Yt^zKX z9VRZHH@98ldY=E5!7W>WaVCFvOTIpLz3;Nvfw>O4y zRzuv0>-$~gPDXA!aamvYb^B|8E2Mx|4{`Z?eA-=$9nZ(tMhFSXAaVJ8yk_~YrtAB2 z-S)ljM-1DA7!S-{=ghs%;8qZq$A_J_cb)g$XmI1i<$mjO{$6vp!A)7*o1D2nHMm`t z4(F|M)!|ly+fQ7cM{QASKF{Ih`0~9TgF9;Z`@ZKo?%WRC?kFB_kwxbD&HcXVFARTu z;_`X^fOW3(l3yC!8jCy0nfp6~o3^<7m$;sX?gVZrjb~lN<>Sr$zUd!6w?(!U7zV~P39)aiM@;JsB9~XE3V0XUc%8TxM4*)k7r}++Xd0yhq zeHi^EZ&JkN`Pu6GsvOT3j~d)A;_`8El=FJ^V+Oa6xEyESyvcQZc--I)Tii}(?h^*L z>^O`EK3^R3wCnxjCk<{Tak<~hPCC)C-<~qKH5PXVXYSJmx1G4$Z`U~M`z&x{aXj97 zEPbDF*7teC-$9G}j5GH|;C9e`5pOZZ10NUe_w`;f{EZNI7Y|=sZ*|~dw3%1pdw+|_ z0&zNT#)-@Q=KdVhE5J>BnZEBtTprJ=TCRoXdt}}DynOHP5#7Fv8vO!A%mE`|Z3%k3Hgm71y!<0dC}YJa2Yd+>4#L?;8I05trBd9-MY@+Rfkh4DJwd z`FQ)#`T3|(;MT-&oGe{xo`+s={=LBufZI0@xlxPziZl1W!0rDW_FENk`Fh^{cU(RM zZuuJYH)U~`JO4h+$G{!k8@Zjt<#GLw&cE08DR4b{^;+C}ow+4@NMtwtPR^jE!zyPT zHU=*HJ4#%hSHFMx>re8&d{W=r6u9k&()HUij9;EtyFV9H3f!)*AU952J`cHbw=#4{ z6PL%|#09S7`qsehnT!5*6PM3J?(3f005{cu@jF0VKHk1?o9lIK8E{AF_hCke%g062 zJ+9pCfZMwSbtpUDoJX}ebIXA{v;%UZ#O3kV{daP{09=mwD&q2Sapzgv4e`EwQs3Lz z;HHVo$Hk2&ZSrzHJht_{-B90CQHLJl@^RtL-NW#A$kO4a6BfM0KID`7-rfec^aPBD z?FsU?hCau6$v(jCr{`&-#N~K!f1dUr;Fi~*zE#BK7 zBV5;M4>Pz)%ips%bzLtx+~9Uv{zm@j%KehT?ISLqH<#?}dfxo9!5y}AXuH|f-y?zB zPw`N8BE|z>54j(2K5!$ocwAHxm*c_xc$*2_0piwJT=(PRDBxBsM}ONbuKRd43%G;C z?XkG-@q09I`5ZH7aX)^>bv&C5+!X2SorLkg{pLQN%>{0nbf_RMk2~(;!#qQWxW!%n zCD(E17~qywV?3mY%h&Vn^N0C{zg@)T`OYq}vP zjE4kq`TD|r-Lo3F(MHs_-Qqsue4n8fxc*7#Z#QxIy2br^eg$wliQ8{+-LL2CfEzmu z{T;S+aR1)HYT$P5joi|c&H0Y|@6OZ%H@**Yqr~NL(*5^g)&SSr7r9jy*Zp@~)*_b< z>@;zC+?jmSL*L+IKA+V0lE5vc-@Waz{B{4m?RCJ7(sk^h#dZIE+GgO!c0zrPF{J=HwFZU5@=z4;txZ0mdH0=J9qqeqF$ z$Fci;^b3GH+=RzP4RLwB#GTu2=+I&5aR1M?dYIdmPwIP@0(X?wJ$o%3+}Az70o;)! z>M(5S;Lg3$(4o8<33Ir$xVlw4SkcAzaxiym#5fy;eGGN z2Dgj2JdfJJ`TpCl3~oPh`Ft_E+;zR=ZsfM$eg6^S@_Bx{*{3<4j|U8Y%WE+nm^)?Z z8b|I^z%8Y9aG$uWulxOg=YiXOGRAMh;=13*c?r1Xrz5w6xZH2<{=N#_zBc6c5|^JV zcGvfH;6~OXcZj$X@3#@)_LB~!%P}4%-f!;$mk-h?aX&*D_g{Tcn)l_C`rbzdH%?q0 z6cRVMUUz?NaFZ6d(V6>+!R@egc)(eQPYrI5!Hao3yx( z&1`Vw?q~ShLEP=BQM>H>xwPKCT(^Di2!q>8TwY&qI^b=d3g?OhJKsCf;0_U&kBg6& z|I?8>%ixyQVVtqQNoRlO8r-PGZFc4!V{of1?&;3lV}V=sb)4^{i97LlSOnZ2;&xm9 zy2ry};Fg|^{tgg#;_+}iaBGM=YWeFP4<`Y)m$;EtW}Lal!zsWmOQQ}ki|ZZ_rvjG` z(j;;Dx$TGdSoRw4%O@4T(_nDBh`Sp>s!#dnfAZn6t@w9d4ekJO`C;w4f4=F+tv9&d zYV0@mx5nAuwFWn8ahE%DlfWH)5dVG18jHKinY+&Lw}ZGmKJ2k>3!nQUpVar-fSant z^II=*dHg*xemh^v<%9KnFJ<^UL|h&pwtcq8k^41+TbeMBW8c}|w84#9+@qYi=Na58 zi#x}ed%nR<6PM%R!xqiw;?_HJ?=rYm#O3qFEpNK^+r0)iO=x{1rjn|nMwWcWK^`TGNBe+LZisKxDa=00w4BMs(x=tgJm69zX%T#kpGmTcvC z96x7pla{|fYxy}3L3s@mzV{+7-P{`cYhE3e8Q0%7xHZJ(aq{0M-^-``yzsvF zFN51|>9Ez|r@fRHFyrsL2DiuZ_dm}5jvCxSi~F84_d|p0HJaz4|2lI&F}M}P<<5Hd z&o9q#)Av*0#_0FNs)+jqf<67lt+U*?8||f+YbP#0|8VVoKXc@6W^j8gf1h#ocT0mi zY;m7+=6=@TmN#KMu)agi+^r36jJSLp?|0r_C+qs>y6t=08Qdgsd0c;Y|LxMbvUEG~ z`}V*sKZnj2#O3&PU$5TD@VDRc_dREScQv>p7I)N{8!@=$NsI^9_akTS9tPJZE}t)+ z+2q5SdVl1)?R)zGw~y9S6U5~>b6>BnF#PQxF3(dpI`PSUbM;ZT^SuLso1{4FwfuEo zuZ{w@pSVL7*L}Tu3UDLm;&D;B&OBeZuUAhs^onO%Zp%;=0Gf9N-QRchus#$HQFU zaz96!G0yn;oiz`g@_XKwPwIPBr~}1sjJSNBcfT)kBI-cg6mfSY=iKj$oNVaOOwaHkC2$9cTiSyC#yYs)7g-J5D6K13T3q-0A_?G@ z)A*1eE{{9z=b;AF_iEI)gSZnPcbZUN;`S1E;^R&W>U$0PJ7oFmKJKgsZaZ;HTQMG3 z2lsL3OyCX?H)?U+$DOYNmyeSw;`03Ao>%HPl-VSw)GsM9?9#;L=O-)fbNpUt$wmgZ z+tOjXjZbyEjxE{P;BNTv|F;4hXXCYEv<;8XY<4o@HX(xninmY2OJ;3G`F*F4&mq&C zl3e{C$)R59KOZ%NWY7L{yL#87|D`ER%WuMQF(+sLFBq*1sbkYkJ)#nr(7*m3Yb(TN+J*r31$1vV(KL4gelY*1i>0vic84UI*47=evbM3Y{*YNsE9(wvscSyHuKA#K>yyn*t6L6P zS+}a?;DqOupJ_ga|G)AaJ3n8{oi{*!^0!W=ZMQk>N>TgSF4y$<*^9xn+$!Jw1nSxK z0saoZ&RZ@XoR_t3p=X9{^Ve>o#0xRYWS5a0w~PJa_LYcA_iSri)7Z4WaZgdoeuh6n z<;%Wm_Gk2K_?dNk_Ye3D3~pz}fgCsDR(l4YM7`Kg9kW6>DIX8dN3R;<>71Z#pX|6j z>=(DIL_Ci!^^#i2m#tTv$|p%5wDP=;vrsQl9A3}4Jx`%t?59pz zDV&twU(H9a_P-)e=jhut&ujy~JCh_kZV&s#?UG+Vi;9A_PH8IFPr5LB`0J<>e;=m1 z_5&3iJIi^0OX@n&p3W{9{pL+sgwJM+LQ5%@}*9bMBTPd z-LyY)wt4*dY5dIJdush=-F(>=ZlB!F=QUupBmOk?zm+eUtAvyCdzAU;G)TIS=Tjfq zaeLS=ZdaI215_?ex^O*R=b%nFs(ap*j~so!+?Qz|8|IjfTJ1z zADukn>71bLVd@`l5BtUKk~&Qm1?_kmrE){0ONMcqZ|Ja_Y}av!%ZW0&Jb#A-*^ zv#1mMr(+VrN%{LGT(`c@-sbaP1@Y|t_UAIP>kS@#~xWLrup2t3Whup{QW4m0_q}7g*=TRs2Pv@K_bdtXtl#fm+;^~~A?HaP< z_OM^vE~(QLap2kUl%#Uy7oslAuDr<9>5OlFbc5W-?PI%K(@v`$ou*G6t5YYHOOr0l?rKM!=xc%ALC@ZQr`*TwW4m0_ zKC2!65Vni`(>V=7C;9v3`RLS7y6c>v?H;n@_OM^vF8Ou%Ns}wb#8V%Y8zx=aufX2{ zEWHGE;`5z1WsCb|z1+SaAF|~QTkS}^ggUW*dfBx?C;1}<`RFu4y6c>v?LoGq_OM^v zE~(SxY17B(G)(1UqzkhXmzwc(NW~8hl>4}SY?o_VM!K+l$KOyV_K)*r+9-6AzoU|m zPUXbYIf2_`$L(RixLs1GX_F?8(W#8e^^h*i9=Hs3;_t!FdGPFBxsTh&cDbgNRy+D$ zMxEF{ozo71bL3bNz&uwUG+5^(`CDLPqeKj~%K#g-5jUre< zA%H?bg$M!>6r-R

eVgP>J9W9I%4Qx7JzfpR@PwPVYJ2^W^!yz|Goc@3q(d|9{;% zO-|AlgN0AZG5&tmL3f|G8;`*!@}kDF`Hzr72I52Wu0GBKFDi)N_gS#!T$ZdDSDPc-~S@&LLJ1KGcWUd;RT(@t* zxj)4?yz0M`dS)G8yQ+Ec16}aNyjEt{1YUW*%d4jIlQZ`I8a+*p@prQ>+56Jqbsv2C zv@F%va{LtT6@Soa&V3t+d zr?k$?pJ_ktCeM;%oY!wZ;gVoK!JkjVQhj;HNAo`61byb*|09vlqK-J63R=&s<7;O% z4}PEvzL?W0n&@)M>%6*hLG9Mr_I`S1TJ{tCAunnyJ3hMi3n%C^>%4)I8A9i zvyQJ_(meQqF8E?jd@^@Am33a~)AoMK)@)9RvxF1;`7|umH{uPB=S(| zh{LJ&N2zDl@wKOsr+%OdzL?YDG|}ZWqw^}t1+{CR5l(o1uy*FOyLk-$kQX&Jpid{{ z{w%(r&#Y4+kYI0bO#VeUL7zGIB+_~qb;RM+RqkdTU%Rb&@B>}&#hmyTdQ-4&^Ez)* zxnOYmbM}6EMnm=!{2?!DOez=TS9`(<`q0nuT_o~36ytD8X+5)!uf3o;;0LjE{QWmfA3u3w6`vH-lMPh05{>!r(vnStm9+u0a*w7%(?F-kJwe4EsIay0n9pn32EUGT+^JKyv1lFn-=7p%~k6;62Fa?(?-{w$Bd zAM&EcY1hZ!g%k9db>2%_`8jbMPSw9jJ+qFlJ*9c@16}aNoP6)=P3yeO7lg~yZ{_dU z<Irn{}m7f#G;WQUfS55Qar>{%l?(LNFAz?_#TDxO%RiobBagu!@}kDJYXe*K+(uJ?Y@%Fl`8aOx=c9qDOm z9{fNTd@(2A>$|qjTTm`oC;cVi1g%dz;pDq`tnUwr5#xg6qw-JT1bt?iY0}EiiLtgh z=C*NuN@zWI+&%8<*9U%}3%;0>@Ach+&YM&&s5^b3aKifwg>xVJ1dqWV@}kC!<70L~ zI6@KkfO@BLOG)LtfNa zaD24>C7htotaCDHeI9kh;Z)RmW*uKUr+M%LUGT-6eCP3k&db(?3u+fHwjX!zIO^2n zc?|xL7d1{fK6(!cC+IWloI+ZkPaSbMRkWU2$Jd_JJotew_+n1J^Z1m`t0|Y_{rY!X zFR?j&@T;c;oZ!!=VX3~F<0JiV;RJo=+*3*G3#cOwr`d<4o>|A&u4*3qKo@*5C*OIz zhWeM<`ziBfImY{XZ@c#T;O`K?pHIV5eNC*RN%{YXFX%Jpevq`jm^$KcYAJWKj;}qZ zdGG^W@HOcC)YN&C$_2HjzapIQ{OOm+jQ*U*;179GW7qLf{;zO?KC{k;h*O?A;&AFI zce9SK-O)VwfiCzObbjjUyq0o7?e1mvpMq z*CmnIE%;m_Ug^@8B)H`q&ZQB_2S3wjl_niQ9dW*n^SUq0I=*&G^S~Rr;A7DFv!nCs z`gKF?))n@CzvmfmKb6Pe4|$QJazXy|ql6Rmp`YVNh|@U5IGmDN&#dEX_f!Y`B=i`* z2Aw|>T0eEAz2CE6m1CSgpY!$IUdQXgpHIV5eWQ+#`lE#t^qF%%N}P_QjyRmMTF||>$*b*swa?fcX9nx5PoI{h`s$9K z(VfK~beeNNLA;KkjySyLBI>GX9{lumY5$q{*V_n zwjCeEr0xT!pX+^+IPsgmaX599`;PQ9H4lEE3%&+D{@OY(^9|vWzewH}%3over)U4} zqt9XueSbR=%hm>(|=*=__x1Q?Q@l4|!2z#_=)xc+m}gW}O+*x{*5Ka2nNmW*uKUrFrlJUGT-6 zeD5=6Q2(341+_ER$uZt%eDs0cvv>^tkQX%;u#Qe>JwZ4@pIPTL(z=N{;&3WzJ+qFl zozpz{fiCz8-WQ^anIyrw6`)tSV6b+*aN0vVPQUKtcX1Q`kQX&hIX-&32q)+>>zqy^ zi_{T^Q$_2Ub$snf&4VB4f-mOe{rtPm>nRu1PBn$oF52;$v)>rJMFfAyiyCW=kMwTB z3Hr=BXAq~CP)8h2v%5+?vyQJ_)jartF8E?j-p{}5ypnQheOz9@RlX&h@HvQcCZE94 z6Y%HLuvA~u@sWR`_<}xj?wQ1CGj+t_)Kczd9bbD+^WX=%;A`OL-|=--E~wqTQ8+>C zQ6IVUXFLXf$cq}gj*oImI6+a$)_(NXQm~(tI_Yh9dXV&>NaXOYd;&3WxJ+qFl zJ*s)|16}aNuV0q@{5#gU+1^)~@7nw7@RP5+oY#j>pO&Ti%2-E}dV2~l=rrfnh}Ut{ z5r
zQ?Y?ULrf4|Ks7^IG!r?>fJ%e6U8fCA^^dzpwm3@ELmeL|)WbbNpnUB)p*0 ztn(S-#c#G?ZF9_R<9t=$OX|7f?r~M~;0LL$df*VP(ZZ)0XRzAst<@Isz zdp55}loxzjMIs!u96!aq#UFHaG4lG-}BFC?3 z_~!Cz>HOUH?Z;#37MoY%MA={PDb=FiFF1atpDetf)2wt3iF_$_#Nn0HdS)G8yQ^O( z_<=6?VqPnjAHEttkmB-M(D}2<2WvEM6<+vU$uGYCz(G6)pU8_EM;$+NY2gK(W}VNG z$d^$^99}uCXV&qx)0ziA&;?)2YxSyCEBNyod~ipCX?ERJfp&a9V$%Ed#mLDPs z_~dq+TgmY=zmM>OPP5jzB=Qy15rzQ?Y?SkgP4|KuT2wl)zwqjZKa6N;$yh=KM zO8H=onIGA_4pv_9iM*(>>i9`LMR-A{S?4?wxt%)V@T%=A^~^fHc182x2fE;kc`aYP zeA!Apfw{b@I=`)autu*fyzsi`xPRTZH;=(5@}kCu<0rqL_=8Tf&gV(wE2$$6ua@#R z>-gGr&4VB4f-mN^YWd3LIX!{7yc#+`|6}{{IC+~KF=z=fiwLH7#@MWvy z1m^Ne>-@}5?ERJhsm*KW?d5}&#k^K7TeEUSR!(3puY%5>Rz6r`_70oZcTQR!@Pbd|MU55L&;G&-I?Xy4kjU3i zM;u<&jMOvh_}XR7gCFREFXok7k;|>l$_dQnRnhtL%BR0ZM|cGn0jcvv5AJkdFs45H zc@Z0R$4~YE@duq|nJY7(nKFFK; zxy|dw&kHa3L|)X`ar{gksQba`=Xzfvk*}v1XMc5-|Bm#uG!K5D3%-=sz}Jr*o!?YG zSa1GLo7c+m#{~PU?-Pj;V-kEcf94s&3p&j*7ZR`kp^iAb(pt}~<7+Rd4)}pC_)=c{ zk;CBT?yn?t|3dg6ulP%w*V|8&{RN-MiyCu|pXM`#7j&9+E+Ua{ppH1a3R=&s<7|A&E@>Y8Ko@)|FaEKJ;O6eHvd&Nb+TLHIzma2n?*8n1KlEWP0H0DV`hCsu zlNl9W&}mk>m_)vbI^yuEA1w9EI=*&Q^WX=%;7fVo<@TceRnz%X$_H!A%nL7QK4tsS zC-E43A}?xeIerSy5`WNX*13duy@fikwmIgualNpu{M~W)xS@IQ16}aN?^FAJPNAjq zI?4rg7w)njhpBUSy@|)*4|!2z&+##Jh;V{Fv(BZYb&5LTa9U9AW*uL9Ui07wy5NgB z`F>8Jr}Of6+mFA=d*m4J1O4ut=LDxN`15I4sxPfvkW)KUI6)u!IewY6zLjDeP8qFd z*73EIng>771z*gGpFB{oZfTuYS1uTA{Z=?VUOU!Zvf_2zgg@j(jd{mM^Vz})`pi0C zA(3yRjyRkOTFC>`gpYlP@%rfBx zo#^Ly1&ORsjKeFf^~^eEdrH4vJ=Fm}2|b1{*=H-3XAa|kgZEiN*PB;P;GX!S%?)1{ z_%$^}Y3CeY&E>)kdd(VF5;uNw7l&Ix>zQ@Tc3tWIUs zwo>Yub$sn<&4VB4g0FxR{Q@AD(~Qo`|3$c<_GC|v@&3;b?|jQocntoK7d18D1-a(0Oyp1-07`2q%0V{=7RU58yHQ zLtfN4@A#NJTsT3WS?4Me`F`q%!>Oy>%{snzTl3%ty5NgBt)Lf%E~j~&H~Lq5KNbEa z$9Nw9gj=rpB(Dp9J`GFtC6x83z>+$@hZVRddexM7!0#5Y8 z(B+iW`ZLM}Ys~#!IN`d?>V2*XKJpEJ$cq}Yj*q!D!U_7!It>!}0qTguDW~whAunp2c741+I6yD4n7m6?FGwWPSB0oqSaX8II)K$|w`04A?{(uu*J$5Bgc52*{nA=^Sbco)38)u#_=(m7f#S;&b^*ERjDHmr%|nE*73Ddng>771z!QD zHH-ICM(52a7u25nuW;H!J6`jzosZ@w{2?!DEI2+|W5Nmg%sMv^r;kua98N{8XV&qx zbD9S~&;?)2X{G0RWUANJTG|K%`N^FDhc@WX;`Xn%JI=VLO4O6 zIk!oi_+%J|Q$_2Ub$snf&4VB4g0Fy+=lRo=&TIC6?}SvJACccff&H{Lapp651pa&) zmg=iHKGN%i6ZDyLzeSurMjdfD&90StW*uLS)IxqJq{C*CpUV5|~ zKUo($^{&hI}p9{fNTd%hm>pKf4yg&Ne)@KgkG5AAX)R=R8Gz!8A`pi1t zAx<;Y5rzQ?Y?NQBxALxQFe&3J2-7R{anbUba<$~I&#|bCAzDvL4hFKniKjcM? zla7!13E>2NW}TZ!>uJ;xhf`VWnRR^aqUOO5bio&MqKDlgPLn#Xq+C$D@_6C&cy}5q_QJRF82lkGYV0^ZN*ja|^qFQLt~Q|3rH~Wl}b$JCzgs*+q7IG>UaJ zwZ2I>L7!RS77}?jb;RM6)p}+fUpuXN@B>}&#hm!VcrK?=omW;as9oJ%IN^Ebhtn_T zALU5EAM&EcqT{1o6i(1**145LewsSsa4Km%vyQKw*F5-vF8E?j^s;3Ur=relD;L!6 z?IE1-I{4pddECJt@}kCy<743^!U_7!IzJ$-HR_1NX->ncewI4oaB3@e zvyQLb&^-8oF8JctEz3ODpISOEy|=xea!;0HoS!ajJn7}UF8uj4EY;U@d`xWldjb z4yUGaH|zM?bi&#dEXFQ^XqfiC!BPQL2}Nv&U2E~s5SKse#L%Kepn8FK>u zkQX&(9UpVA5Kho%*6EPei>M-gFk&4VB4f-mOed)<=Nc^&0axL$t0?81Te ze!B4K>**(%>G!`x)Z=O_IrBQ(g%k9d`9CME7gI+ZPLo>CtmA7JG!K5D3%;0>@B3Xz z=jESaKkg=+PSr`NXV&qxr!)_KpbNg3 zlkfZ8w9cz57u0SYWOLf@(a; z>(YMa1>O3*{yA)G@kT`d=M0jZa-ma5-{9Zx+!k6tlmkX{>fbkPZIx6vWFHqUm*d8HQm6e}IW9cK&cphMg^w;hp4XonZ@)nD@^iM%`VZ{+ z$y3G8)W_`p`g5hfbeG)^9i40Ky0s%DuUC`)+yQdj-C6c^>qhA>?Ir!?w@Lk(_xkHk zjrser{-9WWv&>6fF6-srC+iH#M}Koa$xrPe5&ekGr`dY4^K!g!r|hShJ)^CIdX)v$ z>ApYw6|9R=pzTED2%JvUa|B`yO`y{{h4LP3OMPl+1sh7EU zX}zT%OaAn268j4{joCNKc;;sk%e%_DGrLJ#sQKql-yq|)f5>?2opPM`w8ZKIdVJl| zI#Z96$B`o|G1-&(`Q2r_yobcmn$~qE=y85`)%y?08`bwC7QSoyNPWdV9#AgPEK8l* zt&-pQqQrDo`e$DvvGGfZsFT;f_ul%4-+z8je?R6U&L#YOFz&`eCz>yJ9*!5*+w+@0 zkmJTm+h6t~`#5u%eT;gY$J+JKk65}z=JkFoJkqyIT)0SL>MDuz-?Ho1KPblwX^Eo` zNFM4UW>4067mAMDMYf*qxz6$Hopq+|x~+%h{qM#O{yutZSE<{$z^(^fZmfM=@}}xC zuXeGmYySN*o_DUJ)xRTo#Y=3R$(Pyd<{px~sozRo_meVS_`dYd>?!*!b)-G7c!T73 z{%h-T^*687dLNYh(T#GPd9__Hb-&c<-eo^unf;c`Ykxpu?I-p;tXJJ>X&w20>HHr_ zoSKt5&Bxl0qlFjx>tmgo{$0W5yy#5*+0IXY-aek*F2}XU$U3=?>-twnL|r!)USrpp zOW4QVd+qt7k6YUR>^b&)tk?Xh-QT^#J{~>8UI+8=^T;?xoPM6n&wgKGa>Ulvxkl@M zPh$6LQh)kXIWAu>`SZWh@vmyWF3|m_jCX%2vG^DnU(mnXTl}l7xAF$bOWrE|z1`$^ z?lBVQzao$R z+&z&Z5@^YCs*OcRI#a{>Y5a*7!^D_UE?=Kif>^bjS zqQ8ELtd~4p>h#_$vC>q%xK5xG>U&H6R8jJZhsZJNwGNZx>KS%_?Ki@)s-HhAzFo%a z_t<%z8T;!yy|3-B-tm7us-Kj3-9JcvXG-d3UToK&xxud28L{`z^v~@2g_U-GqiG+* zH{#T5Wxd8;cHQ|Cq`&kxsh|C})S0{6UvKn!@zeaAjL-gF=1uKn*TuS(tL-||@0a;A z=gYd~_ektrBYD$bv^gg~Amj4~N`LM$yB^jlJMS;er(|Ao4~eB$NJM^VjeVRuN{%a^ z)p(Zre9*sM>rK+%d#dEkzC-3UJ|+E`ze+6pP2%XY?De3-jm1s=yvF;aKmTrfyt!76 ztGfvQ=C1y)1J)Vc$>y8+r#vq6|CKsZx7+nG53$#^_aXXs6c?5$uiZpnIwi64H_hp3uD8Kj_$(uY~V(vF~e(zjc$HIwnJoP)_Fj=t2 z=l*2#Ek7j3GY?B_{99smPS%XyGNar$oQuQnu3@4xiAa|s!rTQ70p#S*()L`QkK?Q8BDyWaH0_PDFF zrJt`U9j3lU?fmM5eO%Y;!MJXX>(97;&DX z`q#0M7%|T4I!K>jPVrS;4@zV?FZfFJ0BuR-ra zCAEH0xuEvcvu#c*Qm+U&!5{LX#;oIGPTx;}KC{kmh|`tS5r?i0m>&z3UuTn=GPLo>CtmA7J zG!K5D3%&-OpGrC}^Bm!V+WF_oG0so_^Tv~d_v_#fc~RrE>qDQ(n$4e)_u5PiuSM|3&>}_I}DNw>d4GDf^ig7q~l)IK67@C>~KhOnVyq|oZ<7w->DdmC%W>yF%yib1cPwzXB z$NK(|7%?t5J}M{c^8%-z%l($LUPCbsr-atqk({o6ec%VW;EOr=KF715^E%1}>nyAk zPWT-3SAO;_ekdg14|!2z#_=(Gig1EHv(E2GD}U37!)a9OnRR^al;*(?bir5f`CiZO zQ_1MO{3`o#H@Vv8beVF3Kc9xB`U;MZmcGviedgTX6Q^%dM;uN?t!LKpwR4&WKhOnV z%*pq6eG59Tu3S*Nb+~ZaSv&6g>=FEtwgmhkFKV1}eDw5v0O&L8+)JGJm*~dfRMC27 z9bbD=^WX=%;EOr={;uzo&P(R({WQ8pj_J=m1-JJ;{<5370e{jP{l4b-NPk!!chF~6 z>Jq0Ls3Q)i*$+i~UQpFM_<=6?8uWL4YdWv2T%fo5JmG}bEuT5`i+l1I{2?!DY&t&j zRq+LVW}QC}ryHpw4yTrKH|zM?bD9S~&;?(79`}9Du&MLf$_2H1&$l0U3wOLZc-+As z@}kDBi$;RJnVo%=}ZP1F&GQ%|{@b$soP=D`ni!PlVYnO&WieS!VBE56X?^vIQO z3OK=^Ps37uDdmEknU4x5=tDop`-#)HDaPTH)_P_gZ(H-=2fE;kIr*MvrgYwnazX96 z7YQdkFZk@-JNeX_fIs9#jXB3h<72`J`pi0iB(2|}jyRn1TFk zr<~4PP%fyQ&I>1;pKiVM$`9}u{2?!DoOFE5>-)XXXV&=>Y2|MkaX6K=o>|A&E@~e9 zKo@*5C*Sk&Nu4*TT-t}ob=v7M;RLN4-*WIUsq1??nzV@u5}&HR${_s`JXqC3&g*+)uS&bE^OBBLOG)^J!SBuju$_>*s}_&z$==;?$;&IGjoY zK7VA^<#t~4;0L?i0m>-?QK{g^u9 zaGKV7W*uL%(?#{PPb7<98PupT!LB0*PhWl_<=6?8gzb|)p>R0g4(V1Hm4h}6;AMnyr{9| z_$cVlsX(7u=Rx9hJ9Wh2)K>0h9kY#}i)m;c{6H6cF(=>i%$CkeZxAk+m)q#)1b?Q6 zDD9r(W2z?m3Hr<$|0JzHp^iA57IyISL8w2kdEf+H@Wq^bzwfE1^Qy`P_3E316RwY+ zo1J+fkHH`EqQ771z*g`_dGML^Lok! zwNozaX2-VyIIHAu4^9rKo@)sIzKgZ-mG##?dGw}LH+96})K%_g9bdbxdGG^W@HOcCG_Uj0$JzTSSCV5q&phQ<*WJPE z!kzQ@T_SCMjUPkla2fE;kIr-i< z&!YYb_I}E|)aI0W%X?qM>%yO@AxgW1bu_tizUYQNs|LN-_&e%|!)a3MS#>-I1_@Z!vKC=#M{XKQW;Z(gq>X~(X z?J3QJALxQFUfcJ+`LxdKDHqgEy+SzQJpPJ@-W}|xg!)5X)L3_XjDAUcL7!RYQKa== z>WIT>E~2iQ=D|;2m-aI!-}~lu9WN`F+8-VlJg=#47f!f7zWuMi@3I&8GkryAw;dnF z3-#;o^mDC8lU80V4yTTC-;tK4=D`ni!PlVo&D;38Di^G?Fe#ky{q9RQ9LO)Z5`BM2 zj2IUjAC-%Q6ZDy7b|OxHppH145?ar!<7;>I>jOW~1z*f*`Kr~6ey`|)&MUl9xS)3V zM4QvaKe#D)UI2f{iyAYIkJ-9#f_pcKvdj6UOK_v73D&Kk^K-AZ_f_dNa*WUYrhYBYH{sJN65*iY`ngp06?B>< zb|zkbq>ebes+Z__&n)C=mo*Q5pbNg3*YfO2ekv8*TwWEOUspcJYrR%@;k>@bJLJ5c zP@l+)8taaq?3cwKbeeUN#OqJg5rYA5+oxQ(u zWjTJ5&O3Db%{OurKD9e?=s12RzoPrW>F0uvBVK>z7@<0Uf9G3Q`ODGZ`}&HS!obf304T!wJmgmDF|8|KsehH^?#0_b0yN9R607fKQ*6rTTJ? zpXTMl3p&lYPas}=Q7jIxg4Q$Zm~H&tq*2X-ALxQF=Cxw^;j3{1b9v=-eogscjm8^= z7oNW#{lLxva`;4E)L3@>^yY*YbeeT`Azu8=I1aCh)-&t)+9l0{ALxQF=Cyj&sueha zxxC6cKlLVie`Vh+$9P?M_UC@YFVzz8>C>`QU(NB8zEXHWr#W|5;`Mjxh{J343aMw- z@wKa(2S3mSUxTji)pTA}xuACaEy4+(OK7h6(mp%}f5?j(n~snCSH&0fnRRv}PXC~e zIGkF_-K^tl&*AH%exM7!23_B4>b#zELG9FAZBD;jEu7#Fc~N86@lpPoaDqOw&J&5# zgVYg+Q%|{@b$soP=D`ni!PlVcdtIGZQZCJ>%IoLK+k_L|_j}ik&wdWC3x7ThOZBCc z3vy<@E}Wnb{Tx%oX@O!KPHC-Y*73GA4}PEvzL-;%Cc5XRl+J4^7u25rU*UxJ{jND> zUBC(ckQX)P93PFVgcJ0cb#^CC|DujKobp=FtYfzE`{PD64}PEvz6PD2ayoDH?ZO4M z3;$+NBm9?H($JZ`u9{fNTd<{B3O+v47 zLG8JB2q#>RdBKzK<3DYXfIs9#jaA1-@*Bbl`pi0e5~qi$BMzsThSW3bm~H%iwTkA! z4|KuTpz~7|_1|glr%XkT@jU9K*S_x8ye|Bi8ltr4u#P5YuMuC+XV%z@IQ^SC;&5sx zce9SKJ*#=}16}aNoP6&;%;~&}azX9dN%rIJ^f&+WFdlI9PV>s$tmA99G!K5D3%>aE7K_s__`{We(iS)Cp>?8y%&!6D0pBJ^E zT#!EfP2mK6=;ydMY5gz7IGmDN&#dEX_f!Y`B=i`*23-eDX#JvcLG7vc2q(PWo4Mtc z!KDTGLtfN4>iDQ%C!Cxd9>-gGf&4VB4g0Emd(GvrAKaJ|VmU2Pu z?tAU?(=I!`>JA=*KjcM?MaM_`df^0pW}P%~dQ?nKC9P-H@wM}s2S3mSU;Op)eZH)y z^YZT#E~q{EemUM#JI*e?@nCMkAM&EcisNJ92H^yKW}SVA)1zZ@n$~(|9bdbwdGG^W z@D;pIlglpJPZgclP%fz5nHEk@(T>~CIHti(_(NXQIP3Vxd`mb%pIK*L;!IklC$S;yCIXde7P7ku&KZW&FaVBK0euc2Hp*f~WwrL^OpGrxK#H{lO?QDe{X zF?Ex0fWSOD?2{AHw!1|Gv_{?IHh88n$mh^9bdbodGG^W z@HOc9cv)YC@}kBW$49CqoS@IFlOayK$K+J|uGBN@_}bH&2S3mS zU(Ct(d7v4cH?Lgg*Xr+S{g`mtO&9y$Gu{%s=LLU04NLVk93Q#wi7)6g=k8Bh_lU`< zsoc#vzII*n;0LN{Z>ngYW=Yk`6UHJ29SgLQ{@iF;* z;RJo=+yhAKo-sLfmAhHT*KTVb{6H6c1-gGp zng>771z$V*oJ&*Zr_QwZSN1G9#(Dmsk^8>F>%*r{%Tj$k$IsM{g%@<1b4Q8SeldA1 zD1Wn#uRX7M@B>}&#n0D$*Qa_quc};7yMDIK>0#vrf5?j()5-<;wcCUf^r4^Qvxw7E zV{*!9J+qFlozy(|fiC#s=U2YJC!a?BPuu$`Q?oh!TRFj>Ps37ud90&J&D(_&^qF%H zA+1k~$*G|A%sReyR`cKoy5NgBE%#iX%Imy}azX9dXM_`;hyLfP8{WZV@Q1vpvF!Nh z{zN!IpIPTn(wd3MX-eyvb$soT=D`ni!52U7eAlPSItBBOPk0Re zkQX)1I6hK$2q)+>>pYt{?H`jYaaYS7kn`%-}R{(oj0jmP<#4w!U^B^ zPCe_1d-E9lAunodI6iVe6JOA0);Wwg9T1aKQ@NXUeC@jC!4Gu77jyDmpK9p5j&ecm zg>!{d0EaqH`|-0Tc?|xz9p^Uh_?YYnC+IV4J%>0Q7?V?1xtn!-?Y8E@4|Ks7bMjrE zn%8-y^Mng(S3WPtcz^o)ME%O6!?*%r^e+ z>4NHjALxRw;QQU`#n(HNTEDGaP`fuPoYLAcmMaI>JK+y`QDfHeF?XkMfZsC zbM7+IdQePGlUmQLW47`4rwW<}KhOnV%*l6ss-*Ke$_2F-E)Y(5Ua;}#vo`Y>{2?!D zoOXTuN;pBES!X$EeO63P)n7_IvyR!G*7c?|4}PEvzWDs)dtNZD^9o-SE|^#TlAlvT z*E2OlY1bVeqrVnk&}Y_IL7WbW$!Tr}y6U=KP4mF1uS@#}Juj&1ctg2hUgttTC-^gc zMQOJkAI0D3*Wc;qS}Tdup)omil*1q`ZC$UadEf+H@HOapL0jjIUL;&FuTb}M>iZic zXh8phG=)9V8LG8xH!U;cj)m`=X zM|ceWkQX&(93QiH2`A_?>#QbD&yC4xRO^{_%r^d>cS`f%2fE;kInm3zMc2l{v;mc`^$)OuzeUpuFH@B>}&#hiTS z@q*4PD;LzRepxu-ebBF-dd+$sgFoa&jZ=<~-aWzz`ph~x;-gG}ng>77 z1z*g`_xf&1=e3m!YWKb(obdVbeJ1}IJb!{e*5uONtR*?t?O~*(6_u>os%o5Kd zPAg+_YAJWKj;}qZdGG^W@Wq^buY;R9Z&taWc5_ZR;rz7UhRYx1G5AAX)Yx@=lb&F?_I?_@(%w&J|Knx1@w)Km)38)u zO1U6srYoGF5B(fpK%7>`x!XNUY#+>7$@dx1qeP*2(5~sssa>{ExvyQJls(J7OUGT-64yTC}tXod!wUtZ# zC65h$A4%_P!s)S^ec|!#;H?+Z>|Fl7AFV&}YtlF>zWGlhe%o zQqQd8YgaT6exM7!n9~}XNWr>QbzV)mV6btuaKiJa3r-pj{;nSUAunp2b9`j~B)*`} ztdl2BFN(>jq1??nzV@uNo8Dl=+6epKiSOybtlZ@aNO8R9^?{ zXj19V!U_7!xnsoX#W6X}D|fSwuier-_<=6?3OLada(6#{BwvyQKw);#!uF8Jc} zlkau#sLm^V(|+8Qud_KlaEEY$Kc9xB`ihQ^_5;ER`pmiOh|`fVIhC}YS;yDTYaaYS z7kn`%-|OI_&TA?c)SkayIN^QHvtGLpyl#O%}&#hiSv zgUdRvqFhkB_C4W*>vUVsxHi~N@Q1vpamMkHdRRC?pIK);aoQ4-Q|%$CXV&qxr!^0L zpbNg3lkfS{jLw@^F8$iK*qpX0C;02vFX%JNY#>fsV{&RLce9S!u3z%R z;CfMA^WX=%;EOr=o`t+*m;?ie6BNZsMi{kuj`cRH*Y{Wxvv{vzjdr=!3=WDJd?X8KNJ3jWSI*7>2<=t6msg< z_BB3Eoy>nyeYiRBhyKiC!hO$k_osgx57dNdXWe1*Pd!%jV4r}$u}=bJ;KTg4jBmA1 zGL(UFle^|+R`C;0y&*3@E}T09xFH|$6VzbNt&ksvf(Reztg0_M9^tur(?5=Qy}jV9 zJ8aICorN>@12`M|fz*W@ne(>dy0NX}#r45}-hrRV8F`si{ESR)$SWTyobw?Mq zfXJJl5YCm5N57V@aXNJ}=d$W`bKnF0qq~Irndd%<{&D2MaLsNm(R}}@qIAi)EPGC>Tbdr`vIJd{Xpuh^YhlR&3%Nym^p56HuEz4n%lhL z>ylkBybB>0Gi_1(OzL6YdDZPEz)!#biQ&HHx%^9rIO26p*;#kkynCt#`vSa;eGy0p zAKKUJCypv?-8ixFsPOC?emxA{VP1w`xyuc8N*jc8V*oegBc4SK=3Ec?VJL|3fzEO& zT8{xUknIkyoopp!Jxw(gM#(n^2V?PAa!G|~>H*tddti!vXk(cqk zF0XGA&ef1du+E^nPtyQ%uBcu&4?fVJ-!t6LJa=#U$MMOUP{0mFnIUR(g_j8D$&g1s z$Jh7_bu#Co>UDGA1O4f}!+p(j)AWzyKAJG?tUGMZ$tQ~*><4f*_Cufy`;a-09Xqy# zuB~n>KhkTZDIO06%+HBJo-3VBXD;qm=?b=$ux6bUeaynKwu5 z>#nozuz63Vg*WyEcpLkI)P+2W_tx?C#>;JLhyIr4RDzBQe7 zht0Y86w!nI0M5pK2y}sud7kzGN1nmEf4)}m=IOnE-l-ic+>;@nVBJA?{Kqbsds6kg zdGLk)R+u-!bNTfPM|`d;>#RF$?v4F~JN5^-8~Y=W4xVcZV;i@RZQE+R6=sctcR$a$ zu!lO$kgZ9=4qk_`vIJd z{SYVvpMc+S<6}kpGDv@)TAU@%xT+VP_q!$G+#SG8arDCl)MCz^kY9g{8}Nb7n);&S z5uW=b`p1#a+k8tpb%xEk`gGxp{Q%C!eh73~oR8f!vDUd#jd6=}kmtXympVZ>7egMw zI)m=MNCV6{uX^1)_~`d%!u`y1c^`9R-h7*K)*UwIp6bDV0B2)A1iHX6*v}JN$2SDM z;T^^;&YWjn)T4CdtOIal5w_6RIfcs&)b~- zPIx@RbD1+oaLzmH4x4l9K;ex20M5pK2rPk5zsC4Z6FC2AKD>>UQ(s2mSeHg!`K3^6Ny7c>Pj$)*UwQ>@!6V_62ww`y!AI zK4V+AZrr|c(?;hs-9ImYcRz2y^NzV!2#RF$&gEwbXY2=XHuggx-Qv7u z>)6(bwLw4bFm9bUB+q*0fxOWZg>yFKfl}W1W$Iz%A@jSZd ztUGMZokR5TrR##Tu^$5I;3J=v*?!dc#_`Q##wTkq4$gL-bCRZt$j_Z5ylWwsV7)kgZ9>bar^`vIJd{SZh8ALUFh{E9(8?lA6f<~;9tdhR{Kxif$p>LPxX z8qB#B^21ON;RBsB>Whv?crKr(IpRFM;H*1r&eK`pjQs%4#(p4m;eH-Ja{CdR`TfKr zC&t%@FI)QOU2wMZoF{okz0P}ucRu72tT*WHY8qhPIo0jv!B4+`S-7uxF7IcKI8RSH z>kgZDPxWA5fVZ(P0_oVd#Bsy66HZt^ex&_I7sd_VMxJp3395x(zr_26_uK$}n%)l$ zYBBG6$gw}h4fsLl)bfxw&t={m!Mp9OJ8a&QD?|_W1$ZYMKj7Klx53qZxC;3hyybBa zkgZDYo+kUz5s7y zUj)*@hj_1>*xniz{{M&?d$0u^PLO1ad-a){pcvK z3HkC|=F1UZ?RjV2Ve>6LPxN3PfUmI+0_osGd^e9T{rrx`>C*?fU|RnU^Lrl@zM~gK75(E|(y23SzSA!fzSsxgYwUwS7x*yWvGw5vJM^1;X?)QO z66BRXB7BP>hoJtTyKmC~^UbMFHxK&JzYyk)@LcB0aa0q^&bq_q+kLU{#XbOEV;=;{ zz=!!xY@9Gp5!SfLne(iR8kC7TGanVsb0H5U;1A!SZst6zdfhDeK>uVuJWudk=FD-K zCbXS(ht0V-CVH?Rz}eUjfim!6&KtI^r_201J|FkSNARs@F|{5AX^w|zLei--Y|hnj;f(zN&c=QSl!1?MF3=TG6|4c{HfPSWzZD`c`zhgE z40+fEougamm^tTFuQQy0kADA=;eO`1{5p^0p_(w|tUGMZJ=KH#0M5pK2$X@3aHdbq zINu2|Zgb{5`#T}>N;AT_F@T%m=!aXW#hmLQzy26E-~*lIqe9L+mpOA>p$Q#l-C=Vs z6+{pA12`ufKj72<-ex_k3(vdYY~>l}Xw;cLO*m&l9!kI;enj2OIi-5tEcifwJIov5 zx%|3>J^v+l4tj~*j>uphwL*bjkp@G&?a8a@=g&bOt1E~Zw|)z4&#gWbC74Bq>cQAGlh34uX!#% zkLHNWSrup9Ve?LI6g}7%;BD-SKstDay!jKPQFsS=#w(VfT>tBnIa_$Q2Jn;Y@cwpc zGVf-{F&v~8{GhX{{^)pw=Q3}O&!c~Q>pJTWn|EcC@W#FXZ)0Bsx;(s(jmVqxjGw>{ z%Jq2{J}ta+As0y)aQ_qPXWm)W?WVyG`g>vC2+w8S9C3ZLNF0M5pK2y}rX^IJc$j()2|(A~eoxXD@ajBk#Vjl9}t zgmWt7(XZuebf}X#CsePS10U#bhIu1AcQ5+Kk$Lki>#RF$&U0IYGxh^G8~Y*91wO=i z1O5DL_=Z(58uBwZ2YK!{M$~D3RybEe9$LvCeoo!YxvYBKEcihG=+KV+O6(cJ>=+eNB*GC zjm>>QxMxB>O2i+2N8QXlqx#(}_(Fd#%p2jk%$*~C31Golci7zLUoPCSKfvACAA$76 z+>f2uxOU=*9X)>uzfQ=vKS_qVo%4lzE#wodJLvBBG{D?zs^86nFZ7pR5$<=M%im8q zzDyIE&bq_qUfM2tus^`v*dKv1@G&`VS&Y4Z-dMcfkDUneollsdZsLo=Jr(j%BK~kM zbu;&r>UXo?3;mriZ-nRa_fw81XhP0eci7xplfoVQ1Kf@M5hw#6aDU0RG3%Kl#$Dc= zxA@a$;rVFvOTxPva#0fg(4}tXJ*~RkEciix;g#V&=ecS6#}ViCy0h-EdFM_PJ=hoE zZS0FcI(UNj=CO5KwizEM!MMv?^D@g<;fhgEuK#!_UMRd52Jn;Y@cs|fWZu1yV>n1H z_(5kw{n7CV&*k$uM_dg`J9UQ5yZ$QSjeP;$#=anR;eG_~BerekU)dRqnd2^R&7UCxI;R0spay4HkKfyWAx&vpnnk z!3X5GFBaaVkc)!whd)v`^De4xHw%8ypMG7q-+Au7^pE57HKF3HJ8a&`vgpCS0B>Vo z1j@h%yw`79i%S>QxXYXKGApxd?6Z0JxJXx{2K#!24al6 zzfe2a{~=dnl=i>+LuV~K9^tte`p5BT`p36t$?(4Tr!xc_-> zhW>G!pnrUubk-d<|HPYh|LeNoZ|svm7x;kx+A;e0?1oLpx^E;Q&*k6G&#YdxYDIYV zM}G5i-S-1H1|p2R2dK^58zE0)l$z=boz?Jogy-_>RF3_9@2op)?v=ObzSniZ-Pj+2 zbnw}FF?;?*2go%((`=PGaAO_Ltroo>zD-Ul-tbypFe=b%)Kl@HWwd{Q%C!eh8F- zkL+*aw`F|&k*b*k#ustsJmXyrG6ROwEfDiOH!@Lom%bYnb z(}b+E?yxz}{jYGwegJ1ucVS{S!aAQ-nf2YJS)YQwKb`D?FIME^LB(!b#5)EPGC>30Zc><4f* z_Cp}c=DcxiV!i6sfN^_2bDnW>rd;GTt`g3LkcVB+IeLhWnR8C{I>QP0==Z-f+|N9h zIdeQn6UxrI!{*#mJ=hQ6Z0v_X8TiP4j_`Mug8kgjGtSUr6!qq>7T$9M_$iitc$iwu zyB>1vk8uNj&{?U3ym>BPSK*k|gtoKpuz8nH5)7v72n5I zet+NE`Bd75`3Y5KFk~8xlf^g9KpTdtUGM( z?RN=x><@4^_D3Kce1!Xv6PukEHW;^gbDsT9GxD<62!4I@ogvL)EPGK#(RY~_62ww`-0Sk zeAd$M?;0x}yNNz3cjTtcYscvs$8kY|-nra;`R1RkLH_hNh5J;<$1J<3&40(8xlgHn zHvzuTpMPJt&w1`MX@KL)G@<6KJ8bUR_lq9v4{$g3N1zOROpf$(@z&o6;zZ4!(rMCRTNdG^P+0bl5Bs82c`;knG6BeY8(pBC=eAK-56 zk3c&37#!Da+e}w!cl7rs!p8^lGs|-Lt`&Zr+Sd#B$&e3_dE=v%`=si3li&;e`45Eq zo#!%lj=1(vb=Dm=_w31{2m1rujr|cwUxGXRJ@&N|>vr&Z)ARMhyv&;L%g}$kEZiVp zht2@5;EA}CejU0YUkn8iKGE4w-*h~}bNTDQv8V}2r_Qjy4)s&y>wx`&uY<8)0%iC* zY~|mcwtX%Avc@gj`Ohj(SijvT+|M}gc=D|mq^O(umhS(Mj}q~RU1%bocP3T8n+0F! z&z>6Yf1dkP8sPXmO{hBS4x4-CgS!89U2r${N1zORlw)ChZ0p*>xc#0eCnC?`-p{vR zord{^8+E@A;HY@|VOLs+xpzXI{V{I97dq?ela5DtF27#li0fJjr_Qjs*FL2CUHyW) zu|ERo;3?eoUCwpm>&KiIOvtmjoB8%jRpd|IB;1Q3A0YF_-Do0nFRFew3BJ&u`f#}4 zdG3BRz!7iHR-AQ*%{@^SJ=h=MZtRahI`|0pZTNUAYz^4w+cr8cOZ$1XZwu$v0B-%l z+IXUJZiM{o6!n45N_afNbNT0pIN~~2*I9SioXZ~(&e#v&Z0v_Xy2}~+0=_VA@9S+F zm)kE(`<$EK5zg6=2TFNkiWcDgoKd}Q5`3V4KFk~8xqHz7$3rxs=&Uk7&l^0K zIdcT(hO_RlIp;qvdaxhB+1L+(a&Q#R{0I2#H`Xw2b4H%?A!n+H{8USLCqgbt${+Ti ziOhRpKtB9nc2oV)@d(e|hZ-EWX+p-SGi=^-pAg>I7vOE|i$EFp2ybS6LtE6?U0=DU}=Puza4V5Qs57r zHT6r!BRrR1Z*tsU6MD|N!{%Q-L-=E#fWNU%0%asIxG8^nu|K{6--~zv;|_Pp^Lzjo z`Q0A~??T8$78-EB4^3p=dDZQv!4LXVXNLQo=kk8%$gg|&R(94MHt)n)q6hl|yp4Sk z=mH<%ecTwG*Xbub$2ObqU2r1uZ0<(B^VwVEr+*~e8v{57B8R{Fp3CpcapceU^KIT)ci7x3XA5`i4{$g3N1zLQ==~z|#d`m;M36*x$P2mK`OanZ zetw}X+_NDcl=Q~^Xd&jFRsC)feD(W39qxCY%im8q;(eo%v+l6D_n=4D1$SeA1k%CN z;qJct>~kEzonD3-7jLOD>Q4PwxYq}8?DNycQ)wb|uS36+(D$YNm0HN1=Q4MWxQ^a- z)*UwY@@GU3_6N8p96#XWaCcvh_BjsVzJk7~T7*!ycAId|gnX<#_uy$Xk-2A7zdH_J z=?sJ~Y=XH+we%f%>9X9Xc=R^J z2gtnf0Gi0$r&Yh31YhVcofqzRp3D23BR_BFTiscA*xU=B7d_Y?;BM@XKo|J*x%2+j zkI9)oM1j0T+^u}~Dth?!%Kc3EFAU%rh%xRCqy?FOLVXxRK@FM6;)z}?s%fijX9-1^+tk8jz+-(cxI z>B9JWyq&IDOYnE*IhWo0=b!4&=_L9k5^Ubujizpu_uh2rk#yUj^hX+W*YIpFj9I{M?=TI0!i@8Gks4 z77Wh+>ch=~KlB&A7(Nbo?*25u@jy+Ob=Dm=|J;}KaiHshzp+mOWh61U@#A3G_O%no z(vL2VZCv6yyq!1j`DN!9dcGgPPnYe7XOR%*-3vMP$G8DM=xnGzIv(M<{JsZAeqPVF zv{Pr;yz3VVZ|n>3HugoJ%jCU0B5xzldQQm&Q7`c;;av{71nUjDJA@`O?@86|=D`p8 zM=uKZH_v6>9KpNltUGMp>AL8_z5s7yUj)*@hxhl2h`fzF=h&{mJEm;Sl)qLF9*03GU7=7n=(0JlCbZ9JDIGUs~8&q{$0be1m-IrH2n(*Q@l-p;p< zv+l4tm%c1|uphuV;rIa`;z!Rmw%Hd0NH@mu`~-RKH%R2o-X)wfA&kvXSS zubT%S=x>L4BRqFc8sNyE$KYGuS$Ei+n_m&m*bm@r?1w-X_%OeX6Z8qupf|k3xXC%l zbG|bouXVR@u7*6qVxHD=n#i0hs@F|{5A^3Q3->e6WxgEw=U(_$ch(&?=h4eW5B38% z8~Y*91wPDq)B1H2E@+IKoF&ix&D+T9-6NcP1Goi?8h0ybB6FS(`5B}1`8V}}&e`yI zgy%9}j{Nhtd`mfXhRu0qPB>#ffU~h50$t!koY#$S*tB8H`9vbd4bGZpKlMOf`gg*) z6!Hkx8FaUjCNk%O>UHzr1O3S>!u`y1nKMUlt~l!soAZL|!F~W|V?PAa!G}2WA8W&} zaeyt~`8miN^!{7^_rke3fLp(?HdZO;xsacg0w3s{x-#U7Cb3|VGUg10%@-WjDwO7+b-p^^(>n6Yl z`rBdN2+!sH%n|#!;H*1r&dsk0XY2=XHuggx9eij%7mwe(33mG248A;`IlP}C4a}eE z3g4NKgOh0=9!?X3?|-V(9;M%B=JaR39`0kF%lnuk_Ho@=ci4P0SBW0%1MoHWL0}1d z`1@b+_|PT#4ZbwK=w(U&>(Kav@a;KV!ish)M+-3DPRPwlfPQq=)DInx@Z3G9!I3%h zE$P%5Hs9*i!Wa7he2sk&=mJOLJHGKKdR5{)!N9n|8F`sCK?S)(-u!*Sxft>=vKBYj z&_w2(SG{fqeDwPp;XdZMe171_uTS_k<*Ykw&OOzG{Q%C!eh74d4{?@X1t0W=cNjM~ zOP=!q2;?RID4ZJuxP_Ia^&*T8{xUU zpE=@p80DRHht0Wpt#HPE0B2)A1k%BWIMdGvZVi4=5S}<<+~C~LqYs7mQ;}Etvv974 zJo-7l#u!ax&K1?`=D-K~3*QX)GtcGo1;+_Zs5|Qpn{)0u(S!W}&i@Z>Zvx+HRjvOw z;7~^@PH|3fsyOwG1jiiCDYSBia0Un}o&pY49EzeuQ7M8N1*Ix#oGXgP>E5c>YaPHi z*ExDctD?7FMe7{B>W%Ynt-aQhz22Rj^1h${Kkw&r&feL3t+k)$`|hT1(zmJE4^A2Q z?AS%0M@yH?dk-BxczR`$ei?r{@d^cT;2n#Py^l2iJK^3Lz!Ch=PSQfmz2kXe%C+!? z!It`@$2rcuJ9W6leGd7c&ak;JT_fDFKfvAW4<{WwLyjj;Cx0gsaf7&XynSy8@y(8K zpY?ozEZUw(iOhXg^@l<5h4Ip-{C?+L=FTm+F9hojoBMc6^k9F0yV)O3I{1X#PY7O+ zBW@6Pich@Lg!uOFh5On7j^Ky(BuZrNYn~^jTnk?qTv4C&ILEnsUkSI&pO4X?&ak;J ze_FU>e}KE$A5Itegxq)Ts2rrH8ve1&zP;wwe8dmppUg|X7sU%AzxxL{A63uI=^6Cj z6eaTcm{VV29QlOYe=VN^UU&YpIrYVun$B6psO=t&xF}~*Ga-7TOgIk=Bygy$q zW!UGV{W&=w*f%&IX5Tm+;4|QS(5Fcz?>t2O4V(|jGjDDoZ|YBS9%`N!5JuZaQ6is* zy7~!&;1lDspZ8xEoXem4#4UcGxf!fG?DJ6lg6P41!Fe$I#YqRB@I3I}RoSy|mwAQ~ zr-&bP9*~!O*UNuB%>7x;!-(evgwgh7T9D7fnEDBW;1lB=AD81?z8{EN+>bI5tUK)U zu=Yhc57;j_4`#nO>EIeW4~O^jhjQ&bgnPC*0r4B1hhCm}mkfE0|C94j_q?2rLI3Th zL_QA<^%KUyC&p_l{_BBr`RjpOd_61&>kj)o%zjDqV87rznEm3UgU{gea1g&Ll8C?I z^KfvteK!s3w7PO0#yl?|jJA6yk`H_Lt>6 zV87rznEm3UgAe`Q#ev=X4w`oo#2Mzn9dY)x0Y@Tk{V&3~;dw}*0skMMMECr!dc!dI z!1&Zx{C?-$B2936iUuqP>kgZ9>8qj#`vIKIesIc2qC1qIeEkSVA+CeC(%*&itmlyo3?3b#MCM#oy}|Sdd|*8Pb-$lEw@4G*;=Y7> zulN0{sg%f^Tb^Gc z1U@i0ufFJUj&qCD;TA7NI>EZb<~-LH&e#v&Z1#hbP7>WgoZWks{7#wi-nZCC|f_>+7FJ3oz$#)f)!D2gcWZT#j>#G{Nn|G@u%+J8aIY-xSW+58!O} zgHuKl-9eoBht7K^s|R&N8q6Ech>O4fK62FZJue&?S@b*-^}+{d&;rbPLG_07@PYBl zxBT-4=N4&#Tl`*jD_D2foXh_udaxhB+3W`=og}(LIal^io~k3#U_Ri?arW)^-hQs; zg!8E9k*F6wcpNRjoVx?!;RAWg>Wd!dIJZb0Zl^S0Jg75l&dqNNXY2=XHv7RTBZ=-% z&ipeB9gzm}0cVaYY%<>q5jTH?aGvu#67|9dhbfUcyT9zHN$xYqAy&Mndex6>N1 z5Ue|F&ST#ZJ=hQ6Z1#gwMiSjYocT`~?$|YXIB^Y)dBeFESJ>pgZ6dCDq;Osxz)hFy zH8YgRoL4-*-W+$}1A}$-MUQiwTci%Rcz*5%>kgZ9?YqJm`vIKIesI!BqB{)d#5FYL zBb@1X@waIBq z&Mndex8S@ItUGMZmG6rl><4f*`@u;kiS96*D+kR}2j(N3Ij*oNxFHMig_{cRG0#O; ziZ^FdBJ&4q;BEGWlTH%dk>u^4LNFia zO-~^uEuanJr$&YMyyub(3?4n65}9{RbqCWU@PqNG>-_%a+#*eI3*L*ty2IvO`l0B- zz5s8tFPwCe=nljCz-iO;*}yuE25}MY5?|P4Z`bNQf6v`axOWC{M18bRpoN%w$MeLL zYvBun%j%OJ=Qy`W9c~|~0r{ZLu(>yXB;2t-z}@T*r;H@JgSgY5iQIW|_@*A_4R0S8 zes~I1LVV-q!h6cP6h=AB;?J=hoE zZT5vzMiSj&dHZJ-&o9QC-rP%ED{>*!Yu!S4uMXfRtNQ<+M2XD1?K%2M>cI~N8|sf9 z=Qy`W9d6ImfNrqvuzA;iEWEKVz}xH#r;H@J!}2ySS9<(nyy?S%?5RoATfe37p7LCD zrFb(-LYQ}1b%#;#gYnV-@%x)|i!{OQnHn$~tUGMpUDbnq0p4a`IAtW!9hSF$)#CSS zjQ7^UW_xN9^~P>3yq5>?(`9?jlSv5kUh*7!bKHR+49@+;^XA+lO>ldr2CN3_4x9JP zPel**1$di%;gpd?cl3B4+?V(b2+a5Krntgpe`XL@I!ZW?dmg$%ym<;GGUvSN4Wr-# z<7+-H$GJtC;1;*MPX+4^n{)em;f(zN&SpP2=_Jt|#CiYZ?tMFU1wa16yy0x)=woWN zfHsJq857CG(DlNpky946k2iYz4M~`!yTci%R z;9Usn44e1Ty70!n0B^G|oOF`tjwEmYbd32pZ~9I-;PvIw(ZYMqbJ3OJ&C_Th<~^&r z!zlQ{`1mjU{^r~wO>hg|3&Fa>=AHkg=)t}KZ?i9)bdu;&9_Ki>NF8n;j)0)fusPR%C7iJzz}f5vr;H@J zqsRGh@<%n8@8j&^3Y!xzCaDtQM{X~?r#u&3Dc(GT5}9{db%#;#gYmIn`+d#1MVjCi zKYyGJ)*UwQk>7|O>i+*ZT8OzXd!Bxhd+G~=HUBurxkZ}b7T>y@_D*RWibVM4=8{UX3Y%#AY5m&jRaGvly67|9d=TahbE~wsc9zHO>=Hqgl zTcinYA*B+mJ8aJF-|5$zt_#j)KRD?m(H+Y9Nw^D&J>sYBsRp=^1`{{d1$40 z^Gr%)&UNSw!g@Y*e5&K0M>w}g+@7ETGr_vU=DhZ2;f(zN&SpP2WhBuZ?$2mW?>#Z`*fnv60Z?$-0VGs@0jP{>JIv^Mhh_C?tpmcNB*+< zp~pGSEmDWuQ#4>as55N7&A$j=>;v#M`@kt9iSBUx4)d=8>VP(wPjGf|g)R0qBH|Vb z!gD*>li{ zcyj?IGT(948Ad@r#@BpYj&qAN!7bh}s0Ql}n{WFc!Wa7he9b;^(n+E_h%dc5@gGru zal@DA3tRnL*NObmdkNn~&p|84o9EL4%(t#O!zk#-c;%n|d4h9`G{G&thb#x{4x4ZJ zU!n*50DR3paMDSlJCrYdXixH)0`mc9i7RZiF98$vChje~M?4o@Dc-z*7GmDr0rBvI z?DEK%yN{b5=Qy`W9d4&Jpb*p^yJ=MyOU4O6oI&q zJK_sl{cA!k`Twzz-#?hp`{P^x((~8jEQ+A3`Y(ycqPX81zsG=aZcjNv?t$m?dqYQ# zV)91# z9`4tMK3iu$X~li;c0ASxr%}ECI~K!ZYrngt`#R~U4)__-$2f0}6Fql^oJO=h?qhF! z^GH_@_nU*$lWr{h;ct+hLF40r58Q7JeKzj^al(DXck z__}M}1m8zuQS^6~J|*)D8V5hn1z(O6ygs*nu^2nHrg88CUGU{N(YrSxr;g@@_f6w|=G*8Z zf9+oO3hu(6T{}%bulGqK7WeT&AI7;oojBn>X*(Y4gHu883y#Iuu~ChKALxQF$BEu} z2|498uXmsG?9JVE0q#S-l`itr!xztT7yj(pY5L{B2kyUxK3n6_#0mE|+woW*oTl`C z-dKzso6tD;fiC#sdi*CYLr!JQ!~MyNua@gE+&>IX*DELZvumg6&jvnl-z@am8jm5Z zxG&j`$NJzjr}yE;V(eH|<`1>7l=QR#~pbNenr^xmAg64(y1LJ;OaQeA&fr1o)YAKmV=;EDsd4ZFUGU{NMXtw}H7~r67x&xZ`ssaN zkmo1(vumg6uLVAEpDFa&8jmARxR2M4$NJ#3uJ;MYV(eI35uCDw}{34q0onMZVwYD+<$AwV|{QM!~LeQAT!og9qr1o zG^6)<#$xQ)l*YjibitS76uBO+YF>E1D()-AYxc%JM?S~v!Jl0_O@BW0q4!flpRI8g zal-woc0ASxr~2*EeZQO2IQW4s_;Q>g*W>e=7v67*`$2E5;%;)y>F)Un_lw3fZ#32n zeBk~^=(D+J6DQnfYR6-Ja9UFCu^2nn&^Y+%>C$n>DRMpD)cNo}QQW^dri+Z<|2|LP zF8tZG)AZYc58S^PV2m-6yMS~_<=6?;(B~*Yj{20*1Yh(PTYTq z_cOn3>KBal#eUZ3-5!d707d-CqydM17wbS(H0w1_<5BhA4 zS>lBIBJFsr4^B0`4=@&E$7VDRexM7!9H+?j_?+g2_ch|aLtH;ybL?N;`zr8f*G|)K z1U_)z9rW26PbN;dpV5xT`rx#9*L2qfb&Z1`=z=fDDRMpD(7f<|MBF!s{q)#l_I-$T z!e31DMq{nO2kx7LKAZa#;)MGV?RcyYPAhu9V=TswEomJ5Ko@*DPLb>Jmga@`6XL!< zTxTA-?(x_2dhlo0PSalxeBk~!=(9D>Ax^lT(2mFY;MCFk6=N}WY*pjn2fE0oV)O6*G|(P)B6Gui~HB0598cEl{n$PKsz4mgHyhc?(1$u zOrg%{$iRp8Y=}paQ_+f+1#fQC*0R($76kP zDi_mn8rL}ZfiC!RoFdobCCv-(%ftP1xXyg+vA=&H>x93U=8eW?0w1`K4Ek*D(}@%A z%d_LLJ~++leQB{6J66#+_<=6?;(B~vVR$`0qj|Wmu63!rKaTt0ZmNrHI_4_3pWx4~ zou*$8eBgdC=(9DRL0WNtogI($!D->1>Go4i66$c;KTs zE}Wpx=0A%#U6_&6gx0flV*R|v!4Gu7m*W(<9v|1dCFO$J?IYyANN}3Idh{^Q!5`w% zww1s~`+mX+`fQ!^h|_#VPF1aE>%{tHje{TPf-lD@ay?$ryuy*a`&V80@{Qy%_Wo6e zFZm!(z+X(mMq{&uSd}Ko@*DPLb>Jn&#D&3u-rS zESzwidC3b;IE&}t4{>SR#lT150m2FTY@O#2rx#`9)V#mcvvp$q1&xCr=z=fDDRMo& zsCgabg4$y@6;4O%z}|lx?Vg|D4{>SRmB7c;1H~8g**fPFr;9UkYAbhJC)QuqIQW4s z_;Q>g*W)XiH>+GwyFQxSPoF;KUa#jl_(NRUwiEc6dysH~K3k_ooG!`8sjJ*=omhWO z)AT7{)EQC4|Kto;}p3bFKb>?xuEvSErk=V3(jxOJ5KP2xU}tT z;A4H0aDqNt=K|vN(u|zuw4SXK>sK`nexM7!9H+?j_^jsTZzWt-cgy{BrCTRC?SGGO zg1?xCjm8!NA7fjD6ZF~K=M$%TMox{*QqR_j_2)GXexM7!9H+?j_=4uul?!S&j}lJ! zdGO*3Pa^g7d-m!NacSG-z(;AT_<}xL=LNLV%QA9mrPS5bIQW4s_;Q>g*W=5Y*Htdi zo4<{4x}6T3dBxk_%U$?GT-tUm@G-MZI6$f!yexM7!9H+?j z_?qU;DHqgUI9fR2di)!AJM=rAgFnQjZAX<0;_KUm6ZB!6+Y5=)r5QPmX+2vf*6*qg z_<=6?a-1U94Y;%9q!4*n3Aww(xkEFCADpwHHsCr+1Tv+b204dHk_%Kfxd3(zeyW$7)G9L7%O25pjA& zMou$Y&(?|cr!)?JpbNenr^xkqRr8w41+`c1Ae?Ta0|)+m$bDo4{2?xFJ0JRZh;V{F zTjxc@>6IBd)sL5Ywoa@+r*ZHDUGT-6wnwhV=QXcz$K-x0=ac*C(6jFE_S1;^i)q+s ztQq(if2jC^KAU?nX}vrnr=^s-8X5;bJzYBPI7P0t@tF3{V&Q*u9@@v%ksQHt<~ zxU_9M@KJe~p8sH+>s>;e7BX^LRqi*Wr=@Z516}atI7P0<+o*r%WrMmwVtgL>yK$1{6H6cIZl!5 z@q*@clnZK)-95?a%a;l#_(NRUb}I0(@<`zXeYVa^iPLK`a;j)OTPM~pX&n4O7koKR zk?Zj(&6`y&s9nE@aKig^H~YtV?mjX2LtNT+F7VMQ3n%Eab?U_Fij16UTF=&r^=C8= zexM7!9H+?j_?+ggDVJXDqHwyc4(vZiIKf{pE@h_?_{g6ioS@H^c^PqfZAMOuJEWei z6YJMC4t}5uz8t5>^>{<`s>%hmYsVxxJ^gCo1b>K2+qME9<(=XS`fQz-6Q|c@JkG_S2(P`h)_)3wvI{E&zs&ViGUGU{NMXtx!HE-%(!UeTw@15jy()Gd#{t%b89aAodUzik5 z(1&quFC$KkjGXdX&(?|dHSQ$!16}aNoQ{iJkB@0yOSz!-+I@r*uAgrAm@D0N0sJ8@ zZCeU_ET1TxpwHHM1!;XlMowj|XY0iJ;~ED)&;?(PQ{;NQqs(Hp-jtEk!j#mrbz=RR#=#GC!I$F{xgM`; z-uSV}{WNudd5oV+o%@upU(V~oUrfVBV@rXLiARYq=(D*C#Oci$IV~%9TPN0E)HwKo zF8FesBG=> zzoK#Q16}atI7P0%4|Iy)7fB39V=A#QJ%SgCFREFUKizJwA^56UqHl*d&kfy5;THe)R>sF8swbY&2HE zIvUj8E1aOu=3YUZ7Bh0HYCT&g)-P)u{6H6cIZl!5@rvfvlnZJ%HVdcQ>%iVS-t`LZ z!XM(&wza@Vcb{;AK3nIt#OduBIn8T5TPN0^)j0TpF8FesBG=BHjDtB8a z)?d>&_<=6?5>A`?ICV5{O1Yr+Y$?gFk<*mc zvvp$q35|mv=z=fdw55+zS@ZG_5iY1*dT5f}&C7eoqoJO^Nd53U8 z?U@tgG44D3=x<*3Zk~fb#HDQ~0v}8I{v!0*I*Y{VQyDpxw4SXK>lZW*exM7!gwyeT zoF+7HNx7hQduNi?i26b>2>#S{XUbXgyme)}PWi_<=6? za-25xUyoNcudpk*pURW+81Fw_{hI$dkJp92n1+qU=0hKcg%kAI+$)LGr!#V@KThh| zI>iN4NLBV`C@KHNU zI6)AT7{+PzW4|KtoaO%GvFKAv(xuAAqcXB^HctrLS z{2?xFI~Dj?dAx9fK3nJA#OVteIaRcttrP2)G!A~C3%-O?|MmEk=5>?{YLD#|PWZX` zP0#*`+fVR^xU}tD;G^>d;RJoQPLnu&F(ap%*0XhD{TYpeALxQF;naUUKBsxJ$_2IS z`-BsI&iU>Kb=~z7{2?xF+X#H*pCp{1&(?Vlaazg9Y4M3t&(?|c>lz0?&;?(@ssDPs zp?Ryy1+}{s;e_|cf4=!QU*b9VLtNUn75FI6iZAH1b>2&yzLb&EigLGgV*MqJgCFRE zFX7aGJ>Js1>M6nnwQKw3F|MCZ|J`le^%MLdE^WIW_?UgNaDqNt=Y7QK%NaR!l)J5C z`{i%z{ZASPKhOnVjuU-QJ1w6$)-|uKTrk-=Ae`_zxcibfzKrMK4{>SRG3A2zg{KH7 z=)*X-?EZs<8{re zD;Lymo-Um5{?kKd9{m!YgFnQjZI=Qc6VDJ|&}Zu`5vOltkpmzQ-$*;So-F)UdJO_V>OWUpnKB{xV3HofE4-%(#Mow$W-PVcqS2PZO zpbNf)Q~&k&s^-lq7u2plRyg7JIe)%#DSjGRWb zo~;w>cT@-bjOb(d5>EZs<0D$Xtz1yMbB1uj{RKOp_rMy@!5`w%w&Q`1<}-y8^w~Ne zCQjeZ$Z10B**dnL|A(xX*EslrF8Fes=!3Os`NT1Dr8(s#?$1iS^4G2S3mSU&5*X`l+IMP33~xD>K3g*H72q z{ghAe9Q+|JZCeX`bk7q`&}Zv>ggAXCBd2+-XY0iJvl<6K&;?(@ssH+^rg`}@ll!T3 zR&qa`@EqAs@E6mt(b!_(qwpNz1bsI5KZ(Ytuf=olhq$!uO5kJaeDMW+w$4Y1(`rUeZRKw3#QMt`2S3mSU&5*X z`e{Y;I?4sL$DSaZa6Nw1lka$Mo`XNcrENQbkGYy~f<9YknK*qfBd4x%w{>FuHI0KG z=z=fd)PMcd(YzVug4**>6i)a#!n^Kq>kiMsAL7!sdF6um#&d-e^kJOaj}fQuXXI4S zdbUoiKdN!?16}YXocgby@|w4*Tu{6FB;l0Tfp2Ync8k04r^Bh6a^R!&JmCa=w$R6k z(+@Ion$mi;=LJ`fQm`5~m+!|4Cf<9a48uC7t zk<+?zw{>Fuw#LB^bitS7bbSAQTGPDp(}fFa&pbmO<9hr-j}lJshq$!usB%GkeO@?0 zAI7=;6fwF@Mowc|&(?|cyQ%|zpbNf)Q~&FhQLVqETu{3`C!Fwm8;?Hcz3%ff;SX_X z+lj!((nZ1v`fQyRF*-UUr;^sQbz=R3#=#GC!IyCAf88>nc@yU*_fzGW@)*xgoh!d` z6J8hoVj4CYs|G$+UnHEM&*pxb7~M7_rx~qh>%{s~8V5hn1z*Cc|8+}M^P0*9wO5`c zobdd#{c`!bgFnQjZRbNDmk1~5vvod0jBcNiQ~hG8XY0iJa~cOf&;?(@ssDO>Ui0$j z375vLB}Vy-oR(7RYG@q%^mOUC zaO%H)YU=!ga)I8Z=LjdZ zBc~CqXY0iJ>#84qpbNf)Q~!SIYTmqZLG8uo3MV{|U;VMOh&273o|Jk}2W=t9TdWHw z=tCU0Um!+1GIAQ%dbUoiKc;c;16}atIBn^_&MatNSGk~e{sQ5Iznk=`3;%cp&%qz! z(za89kCm4RC+M?vzDSHt&B&>u^=zG3zoc>S16}ZyqpzAxlqgTezQUB|Rg?>6=ANJA zRCx6}&*eGzLtNT+F7VNLxp0C$TW5tBotBYPP3ze@vHpz4!4Gu77jxQ7i6N&s&1)(b z)LwakaJmr&Zpok2I5Gl%7*5+Z0w4LygcJ1HI$t72)r_1LFO_<>POM)?oce(-_+n05 zC^6*JK;8?53u+fGOzx+@oPOu$@f`diE^XVwI+{>^h4_L#Tj$Hf==6-7R+PJ~6YDQ& z9Q;5Rd@-l3lo)bqXit~Y&5nW_?UgAaDqOY z`xRpJ=!~2?%H7t9^;b0xexM7!m=k>*Mjxkj&0A6~sNKFO$?2S*3n%zPT-tU_xgdVw za^VDh80Yq@#ON^@IpwvUtrP8Q9Q;5Rd@(2bIE+3{W12VmqU6`z_{H)V&rg52e$8z~ z_={@TV6YVUSY8lL&}UP>MvNYtkyBag**dZQxW>T`bio&MqL0Jq<5beT8Rdf7^Op!G z*+ujjsmJ{O13U+Rh)dhf1U}YYC7hto*7-UyIwK>eS*>U5#QGJDgCFREFXmLDM7JqS zff>zfDHlwwy*SCKe$8Lq-*tmO#HDTPfsfJG2q);Xb-qE29+#2R!mFj8trP3lG!A~C z3%-~WeH=y~r@H19UXuK}E5B48<9?O%j~{jK`@&yL!$xCEfsctR#2570+%_>foRQPA za<_G2{Y8y~ALxQFejk~Bt*npJlIGQw3u-s(!U@k$Pul!`w-w#t}W{6H6cIZkvz9)8`e;=C%CUhS6)C%l(`|9@WO?$3n3UR>Ia zazXg~>x2{ZVVv7<5u-CRavIfowoa_yQ62CzqL1OraiRmo*N4pbNen zC%PaHIaM@o>=nWVwI^OFkMVxyw|{@ZJkP-&;?lOYz(@BD!U_6pook8FlQVLf*Lt>2 ztUs%9@B>}&#ozB@ukUJ_S642m-Mm~l;eM5uU3=mJ&%qz!(zc6%kHVXT6ZF|S-yuf) zH_q|gXy?K{pMO4@Z3F8V5hn1z*f5_I|;l=5>_|R>;3fIN^QYC!8hw3H}h5 zwp|H)OuborL7%PjUGmO<<2(zewsN<1V*O=}gCFREFXj|`eYc`{bIJv^7hav*Pk+Dd zNp3&EAL7!soxsQ3TZ9wz**dGli2ufU7EWE|ZtKMQYZ?bX&;?(EICV5{O}X@HUy9PPqT+q7z?zcb}&<$it_`Fy%r%`3lNxS;k-Bgv`sm|r?h@Q1jx?Ly#V>`LJTeYVbZ#EAcfaF*w% z#@nTytrP3dYaIMQ7koKRk^AfyG_R#x+AlxCeci3SA<60c-@Vh1d0qI6Y1n9NIq*?> zhxmd%oBKmzbbdxoE#+?O#QIH*gCFREuR&jT%bHhuV{$)L-<0I^s$ZY$IKf{`!$xCk zfsdJY3Mc5Zxj!OCwTztBmAkDI>$f!yexM7!27SL<)4V0+QeV2M+fVH`3#U8iVh_B> zt}b`sFQ#Fmu~FrMnEF-13HmV3?SB)a3o>#V(|Wc}tlw1~@B>}&<-YFd5989ey~Hu9 z^(Wqv+)tIaCOQ4)emfl}_)8Q?@n9nGvGgwC1bw!|8Zml)MouNIXY0iJ1&xCr=z_07 zoF+7HNx7hQ`)$JM&N^`Yb*H%N0{BB*+O`__Sbeu}f<9a4$HeHujGSh)o~;w>PiY+d zKo@*5r>&9icU8?REhhI<_3iTbPP*7{$A5Y+?!sS8!$xECp^x_nC+M@e|3i%CGjggo zrJk*0`=dFzFM3Yn;0L?ioMzS8vDfse}j z^!x|oT~Te z@E6mt(O4nyvG@Vu1bsI5XT*sAW?7c&@o}wZ>%{tF8V5hn1z-Gr7JY0;-*rJj^IFPf zeO>M^SZfL={9NiWuetqsye|C3G;B0B75G^BH{k?*HuvYGmH%d07ETqdXY0iJC5?k0 z=z_07oTfBy{5{G2H1%G2jQi}*xc3DQ=5^sOreUM8xxh!~--Q$O+1zzv#DB9a3#Xda zvvp$q8I6M<=z=fi6#MzzoaQYkm&V!hzRJ@3lKbhTBQHOb*M+~BhKSRR^X%j zA@K!$w$3k!5&zAyESy%9yR8%JFKHb7Ko@*5C;D}%zUQZw=FKP<)Smx0;RLNmPha{n zo`XNcrES*(AG048PS9uT{ED>l-vq+ib}sC*FFrcTT^K_z&R(eHiEV*W{f)(>@EQywlZWBDV(3HofE-w>lWXXI4YdbUoi zKdy1`16}YnXg`%Suc2H}d-+32PA|Fir+?%*_(NRUb|&z#_MgHD`fQ!w5+nYs_AL8p zR_ob1v3^D4;0LON*@<4s9pU;azEYo+t;1T zbMS|_v~4Bu(bn?;eYVaYiP1YUa;j=QTPM~pYaIMQ7ks(*RW|kiesD$en#u*WS3Viv zPwZXa!d`a$( z@Oi4H`Gu>K`>K46JjU;x-{Bh<(W@Ui)Tirb_^%oGnP>?w=(MH&Osx1b+q3XmPN}P* zaq!dArQ^(N^TbxZlyXPNtEq8|$_H_+PYEwvC;aob*F2Kv;1h9a+tt9&%%_D{jQ{@; zEB@^EEWFm0{|)I`(Kz^lF8E?zTPKd^U*&K|$ZJ*e^R49mDt%fW-%j%mzVcZQ;cm~T zj;C!#!ABDoJ|n!K)7I${EB*}kEWGks&(?|cyQ%|zpbNg3S83Dne5;*1LSCb~PDA-1 zZuv993)ffs9)90v^BjC4E^S*1{IotRyr9$8`3te)&vMVgYf9_cIuc z!FAL2EhRjGg}h3dKl)kWv;KE^eKY%{t1je{TPf-mN^W%F^{@dOs~n$`Te^1&L-&kHYn&h6O`c!0a~f=|Sy zZ5x4~!WV=WblN(9BUbOt$gBBzsb}lN`gM(iALxQF=Cys>wk>!93wbp(zpH$(M*fS! z3)k^?ntu3IJO`hMOWUplekxxSf6!^`{GC|6FC(v2}&#k@9e-@Iw7K7ob2x|+YLd^%U(+}$74{Zf+Gk+VNr=Jnw-re&kC@xag0 zmxLE|+T4E zx4$Z!#&qD#m+pBnci|6lY1{eG$5(|D^d;)hYuk@zulS>xVzRMm~3IMEyl1Y&g^me2jlhd_kX0=GV5%896Pb)YZ^9 z`044=ao$h-y)gW`YwG->a)I8~H-r=3r@7=olkR>6_(NRUwjKDWd|l6fFwXUkAWr<* zrCGl2R+ak=>1k;k{6H6c4f?r6Tl4a5;evHa-;~F=e*fMdzJGw{dj1fYvh4;wYTpn} z&}YjWNt`~Jk<*CQvvp$qbv-}u16}aNocK~9+)rK2t1B1OZhlKR;eCg{-EsAMJO_V> zOWPI#AB%0_1bw#7jfm6L899w>JzFQ%AJaJafiC!BPFpB3AHwDV(6s7P>KUx+Wv1iq^ArY=7!ovR+B!;0LxdqkOISf<9YklsNHcxn=o& zx1!u_omhWK_;$}fKYr920Jh)dg! zDHp^qd{;O@AI7=8IdS?@MoxLHXX`}!8V5hn1z+xZJo0rnhWghf_fz4A@)*zK*T3Zs z?iDrsMKx?NSi(9Qv%D&tpwFh>f;fFOBd4;~vvp$qagBo?=z_07*99fbn^!KVz4#;H zg!k3&xap7Xb8X-cacSF`z{lG6gcJ1HI=3WF{8>p^zV2qVo~;w>S2PZOpbNeRT^Gz~ zURSxGc79Db;d%T~A3JZ3=im=W9$dQ3HofETM;MztfVZQ8sC?Cwoa^H(>VBn zF8Fdk59Axt^$4#w>zY5Od=R(r%Sih}t@B>}&(wdZ~+obdkneZF0PHqXHy z;?lOG$_4TD9|}&#hmy_D%?*KnpgOl za6#?z&*d?Ges#OTAKlMm;16+W+iKurbxk-ypRIE=apKP;$--$y>)AT7{*=bS4|Ks7 zbJ|3SA*ZV5Ehrb%URoDUc)#wqFS+_PJO_V>OWV$eKK@5IL7%O2TjIo@Ns@(A{l`+z z)`|7!G!A~C3%;0B?0u+t%^UqiazBm#QXb>^>8$H6bzgTQ>My2Yqp@b-WBe!L3;JyC z?T8b9CP@}fODT0VG!A}xx^#Td^HWpj=adWdF8nIV>BTR;%yEK0#HDT9fse{h_526p zT<`Y8i9eGh3#V1(enWa%8V5hn1z*gGUx0*PcWsu&b9^7vM| z*sp&iUw7~q)3DK4A@H&IGvNe%HusLi>AH-Z#VBnF8E?jv7fsX zG;c|{pmzIr!U?}8`i8e$#cv;vz#rn$wo`$Rm7fbI=(Bb5#ECzXB+GuPXgyme)-P!s z{6H6cF(&uAR{Ko@*5C;kz7$Z1aV=9LR-Fa9CWO+IBtgG5c%b1bw#7U5OKahC~)l9p!H8#QLim2S3mSU%a1UuUpnNudQ5A zyYpw^gzJJ={Pl5kYt!L{*`x*y7&;?)2 zDfYT$40``hxS;k-H_7RfzYtFFhq$zDDe$rUTj2zKw$9y&6Mu$87EWcYXY0iJ;~ED) z&;?)2DfYUhq;?n;dBpO?4G}wdM9_`FQ#Fmv6;Zf+V6xD^x52d5GVef z|16wlwVtgL>sK@mexM7!2639vyz*az{q#3^>^|&{7W~&API8>!FQ#Fmv3lTR^!LIE z`fP52IPvfNXW_Kak$SdHtY6bO_<=6?8uWEn*SxlJLG8}pg%j>G7`x)CHJ*b%#HDSQ z0v{895MR(|>lBF-|IU9FPRq*O)`|5OH4c8D3%>aKUF`EnmNc*WkK}%;{Zk&}=Tn8J zzvygU7ye=zHX2(Ed{qBeI6_hUTb562zkIru|d+IBqf(fpHef<9a4Uc`xi zmpu!o39V=A#QJ%SgCFREFWyfR59D z&}Vb+OSR#lT15FTx4>Y@PcOC;r{zES#EMsb}lN`U@Hd zKhOnVgRTn}HLs>zP`hzc;e^-0cevM)Z{<1oLtNT+CGauzSMddXw$3xaby5NgB#oo_c(Y$r#g4&}u6Ha)2_tB3X;W)t`;?lOAz{lL*gcJ1HI`<<^ z{JWu9ICYh~trP37X&n4O7kmx6e(GpmRk@&c?dHM>@B6loUH=)+!5`w%wt3}(_{QIb z6ZB!6+hd6n|IS_(P6e%J>%{t_8V5hn1z++!-v4)r^P0D!Tu^)c7QzWXmpZrgbH@q( z5SO+s2R>T=5Kho%>)f9>@$c$o;WVZ7Y@JwtLgU~Ey5NgBZGKQcr?TdiZYf+)yLu~m zjOX#w{`st@^BnvkE^Rv-_*nm^aDqNt=K-X3g#KmWG^h1!9owJygZy4=Rpa0Xy5MWj z^Z2ahEh-n(Zrxfq-9ZPo9{b3Lau@y(m$qF9eAGwedItJzod*&l{vD1ioEHBj+-;p$ ze_rF@2fE-ZM}Ng^`rzS{Cr{^hq59t^U(o!*QOSK3TPxkzt=;RMi4l37xc)D^enfrx z#zKeu?Ph%0R6 zZ{>*t@$>f;-ZP#{A})MzAtf^Js_G8s;RoY|BYXUFoLi&`Zg*JL#m|lRCx?<_&KjSJ=uw;!GTfZ;lJ^_5gl~BziDUiOhS& zb4-N54+iV%j~?eZw@4jsPtt%+uGxh^G zoBiOFkwkYW=Y5CVyDd6M4dw&R6j$&c7GvVN#|r1B=i!S*dM}~{m~%t*h9U5Q@!6aD z=MT;;(ge2^4Oj`*9X99csOZ6d0B5rwoHCN=4&uCPa?id!^pw48@?d4h&XaXQ8^jsj zL408=|J)V_;tLND?qi-0LZa=(l*ru2RDT!*Ul?!uxE$veX@c7mHJ}u%J8bT)n+bR9 z4{$g8!zm+)?r_}G@^*0r{`IKdfjUzU6wYc3w{>iEwh-*ApIL~+<2#K~Yp+x3fQN3Xhd|*6(E5ENfw@4G*PHVt? zuf0 zk$JZ~$3zJHV6d+K=y8s7i`3!vQ5vuwtUGMpwWEYL_62yGec_amM0Xh8(dXd^?`_1J zZ%s`csJFgJc$YkvL|piwPKnHWLUo7p@PqNLkIQjxktVnW?`p8_uz9bK32*ER@HYFx zNhgW!Al{V|_>yGb-W>YQ zbGPx&C!AZP32yN^awS-I*t}`&?wa0tc*mjrI}Z1~oa}Kl z-237S^m(Z`P`9*IxaU0|ghbnyQzCQEtNt(uzA(P(<8qu^qzP`PHJ}`N&=^b9`ZY@+BtfRvsqY3!aaz7;j!hiOjvA`ok#r!g$BWaWU>LzQBL|!XJpQJzTgqJRctv>Aji~ znR`R^havEV@!7lk{m!{Xn&8&`@S6IqVBKMJuiiuSV1IzS*&j|iNpy$heqd+cj~jZ= z8!_%KzOX&<{QL`@=~miS9^n-#cBI+^-YbATG+?#TT~wSDXHMY2}f^z3%xW3kQ#`poN%wUG)dk zBk+asYSHg^&Mndex43>;3f3Jq_o-t<5B3MRoBiRWlSFqUxbNFd*Xc>{h>LQU_`-Jc z3Ka33vTz^qe00Tl^IA$|?jx!{jDjzWw|!iWbBi>=ZCL}xgLQ|^y>(CFj{O1dW`8(k zB+(s~yZ!)8XQV+~jJw7cdLJfFDTvRXAlz%7Poi%4;B}P9+-s^ooQE%rPu>2Z#8i`3y3e)B<{VRK))k8sESfDW@ioOF`t4$FP&w37~H zxqf%?h2x^HPiJ=t_gT+JSBy6e62#nRReu--Ul=dl*Y9`EEz$(H@VgMKJ8bUbHBfJhtB%vjo5zY_`-4a)vAwQm=x}7132~;(9Ro35OZJiJQE@C zg~28DNsn`!Tci%R57&Uvpw6(lFWyhMV}F3V*&j|BNpy$hKDqa#>AjQ5Z>)%maYuXs zf6Rd@B7XTq;a>H8bj5h{MoMJvRn;Fx!57BIkM;YVbBi>=?G6o?57r$v_x$}u5B3MR zoBiRGkwkY`?kDU%6uj%`ImWnieBrqG>(#ZBgnN4cM_s2Z#8i`3!v1P$m0>kgZH{Q<%q`vcs~{&31jqB|`2{gb#GWMkeGS2!;5D%Ho2P7CiT z&qY^?H*Y2(%)6|*!zlQ{_}ByeKIhybO>nzI17?GDhs}HBL81ry0=&(>aLP!cJ1pWxqM{m!{Xn&1}iLso-zht0hMJ-RNqoBiRWlSFqAcYIqse8QpW z-PkWW-Q#HXdosRooOzY%pJ(QG3-{&#j;N3JZ6t`fH=!RB+V*_uUdEkgGLN_zca1L`haaL*3gVl4gnPmBk%9yM zU!+9lUQqpE7<^&8>*I2qTcinYPtky>VBKMJU*96!u|L4w><_1mB)TKuet>?ex8J^I zLfioE5??qj@miG&Bd@(z_%}Q!S$M$zZ>L1&zoKF7OBH6Uab{^I>Y9?c)W1NegJ2)ADncO=nin+tdG%P-t23~ zc{6dgv51>HAe?7C50r|w%aq8RtEx8)f)9-6AL92j=N4&#TX3!i>kgaq=tD&h_5(PZ z{otgNM0bEQ^y+Zz`NMJELY!?Z>NE}t=k@?@sEhVvl*pW0o*$-M3m+JqS6}ov$GJu7 za0@M+VBKMJo_m;Z#(n^2vmcyvlIRX_4qm+=6p8Sa;Z**B>sNu^+(M><1^EB)Wq*^ELPG9jDW6h&v8Whc|{I z&OCnv@dVzy&`13Gslt8H^U)RK%_k_4xi6~zFbcjfKJy6wJi@s}n&9>f4Oj`*9X9vM zBSjDP2e_O4;gpd?cM$gjQ~ORk7~CEj+ussLnC%OD)ETP^=e*~kE5w^mQX+F6RlQ*p zd|-Ul$K^P;NE6)RRaz-nci5a)%EB4@0i4Z#aMDSlJCyV8$&+^M-bptM9hf|zGtwZ= z>~H36B4>9^GVbVA6!j|%za+yHuMGoFjC6mLF7iOjpIy2B{=!FXYp-`AX5qzP{Ex_v%aci6ngCPfeS1$di% z;iQv9cMxxRUFe=nbdVa%8{Q_auxXQjsqT^xzw}t)-5$WtuOPh^B{J_7&oL1KKNxJN zKYEkgZD{Y2r7eF5HPUpVO`(H%YBm7VlKAF1w_6Yhv7^s(2It7i!J zvge~K#+y%*Am(0H{b3Y*VSMZ)zt1_hNE6)R=gYIfy2Iu^G9`MjKfvAW4=0@@x+B3o z-TiW&yWB6gX_I+@iMk_)h5PaVj=FrW`3xm8_hrwsH|IL)3xjq4ILEm~n&1|G*MfD2 z&Am1)+_68P!|V?yog}&=!9Csma-O^1FSltEUVZrIrSTczKH>T3it*;NB#60BsQxet zzIx-2^81~0i!{M4?o+G=>kgZH2YPf}a5wwINhgW!u-sGLFW2La`{g!m@~=Qqw{oU% zZw}z7%lDekQ6h71LVs^YIz3-HUOU-y=iDNVa|`b6VBKMJpWQ8bus^_kB=AEL-C?<> zykD-zUGA6Lw8^~u?0p}uoh950o{z2=Z$3|gn0rC>hf(l_@s5wnac+?&xW)7PRIu)_ zxv%XJ?${sTZuWW=xlf&X`e~Cp@QP065!ZJ;L*G|5p1!mCSEPtvJX^RoJRe;# z-h6=)nR`R^hf(l_@!7q8zjJPpCb$LnRz+%mW~{S9iOhRmb%!zV zgYoJqexGx0ktVps@3}OCb%)J+YQN~gz5s8tFPwCe=nl&pH%jP~YY-RXj(CC}yh`=_ z^G_1~-2pu9THOB@2-9Jhn*CGxEOzlFKn_O^n&>EtZ=V+KDuJO`7$Lk_nPVtqu>kUrGtLo zb8e9)xGihIVzBP8xsM+bJ=h=MZuW;$MiSjY+@~gYR}SyF;qRx2Bhda8D(cKWSvYqF zaMR^_%~vRqIj?zsy*ci{2L_w!iyr4Vw@4js@wtd&L7ic9Zk#Hdu^+(M><1^EB)Wt5 zH@}_B5Ov5kn78{HaRl1DB9$z}FFZwfS3MV7wy*zHN@U&@)g1=F561JS`F+i~MVjCi z-(70Ky2Iu@S`|Im7vOF7g_BMa-9fzF&ojgK&@pd#+c-k*UyE`f#4n#CyjKSBlU4oy zU!z3k-SQm$B=z72gLU;sk8_+`qz<>ZURe*;9X9XU>B1ZP0=&(>aMDSlJHUJQbn&3F_@snB^$9%A_IgW7qYi-1J&lAoi&qG&;H{Yd1<~*)?!zlQ`c*n=(IJZa> z+~V`&s=>O$=DhZJ;f(zN&SpP2=_Jt|#QDU1`*-#|fneTn?!^)4f!EoE=Lqjb&qY^? zH>|Z3PVPUv ze{#pJ4c~{gafCd1p^bV|=L_#K&qY^?H{YW~<~^#q!zlQ{_^OY~ac+?&xV@JKOa$u= zoA=6-gg5pDc$&Mndex8U9k)*UwY%9BM8_6N9|{o$mOM0XJP9lQ2S@0Dj4dI_`t z;GP`^cj7WuqoVwyd2|xY)ws`VJXg*`cL3MkLfZKO33U5k{e<)IiSacbm*d>~(ge51 zYQVTZPi|z`=b`-+IS<$`I1gsOI30cG!9Cr`OG%ZUh%@_N_?viQkGJW1si@z2o_-y8 zPQ92|=Q>Jc{&n>c#=sxOtLONy1I}gs+=72ISa;a`r=F@`2f8l!n|

gAaWj?A`(Auu zQ_1}F4e?_y5bib4M=QpgqmB^nHPs(R!57BMPxt$sbMH+P+>UF&VzBP8xlcSp^k9F0 zyV)O38Tj3v;r4F;xN4sF%!R^x z#&gk#cyk-&T~*y-6#QU(;#|MKIrknk!R;{`FdwWtY~F=uiXQ9>@HYFxDFe?QZ@L$E z??Jg#G;f#p_H7?`8&4-7d}9Fh>+{0DJ%A@TqCHyquX?VSaxMH}u&I9OagKBOd4=2i zYd|+xci8+J&l3LFC*W`PiBkqXp8w>I1Cu9C?@zuxumOL>6MX+RK`(ykBH>=~e3VGM zxvg@qsQxetzA&CY&+mKA<>z&7@w{FO)*UwY(PxVu><@4^`@>1^;~u=zi21(#&T)h~ z`Kr}F&#b;kc&`lL2X1I@ue@8HBc@ynKNwt4fAl!VxdrNQi|6(AVBKN!o_~(;#=Zb= zvoD-<@a*k#{=w#S#XiL(;`+F2JfTlqv!m|FCBnVr`M7$6{>v-(lIjoR;0xoU=lgxm zxy+l}`)I&SuiRPIZjC#GBrUl^RPdG4Ic*Xi8y>m@!`gLQ|^eeSuU2m1ru&Hiw@`naER zh_1ska7R3Gw;LXHD=!i5kgay`tyW4 z_6N9|{o$m8PjA1wS3i3u_a1^XX%W}A-+S?e&08X`lWH#&?u(vJvT*QdhjL$3{lWAI zd||wDf#2_(%imAA#rM;dVBKMJFF#-OV1IzS*&j|ic%C*jz2VPC-F(4crXz2$E?o28 zKafP*Q>dwoB>&gI5JwDp0D%Ymxl?Z`u3|24nTse1)Cb(t3e5?iQ z4x8)Lyy(IC2iK9n5BPO3f3Jq*Tsv3E6zW-n)C0Jfsg%+RGz>%xbkPC+SewSFTX;#*1Ugp9B&@2 zT&t=tjDl{AkG{z7SI#|(Cb;E&%f~{n?y$LbRS(WTxSI3tbb-&oikgZ1$vw1B+>S<%5_xrg+b7b@s^LvaV~S^7F^50y2IwW z^kU(P^AE1({5$F3vyXn6<0SJU4&&e|^9B3TA(6klAbjUN2cU_zXDHuU)fomsKgJ6$ z@%xr@nJ>5C+X&VjHs7(AiXQ9(@HP9uNe9Quq5YNJ8}OC+f_a4?&XK?ND&e~}fEPHS zeVp=L@!T-wTIk1MUH#DG9Op7$Zo#)3tUGMJwYu=dJ^){{51e%H*|lT;$suD7z&!S` zkE72vaTVl0#Erg2IF~&S6V=~6tehuQZx{g|7+>>oInKR3O>lch4VVem9X99o%Y-xb z12~)g;FN(6U1#~5acBnP;LG#$`*`Zc&re(-T$|p1FDBNRQLc5>7sfz0#;0EHpC34v z_b<1%(|}g6?y$L*E)_jE|KMuQzf%T&yf4FRTn@lI`1a!HwrjPPs8fBda31kIY*=6a zOy%4e5DyHzuaQ~7J@p%=G?eUIAcG6v)K<$Iyi=(QIB!()z73ipNt{S z5jX!j;XCU&NWg&q&r-e>)ft9CKgP#i;rB7;@;>Gk`*=QBci4PKUMYI855U*#11BAP zcz=ekfjI#4;EXuBZ^Px|Kg2a(FPv8fa6>%Wvz7C*=Z7h2)dvRa{&9|Tc^`9&eY_s5 zJ8aIi%Y`%c12~)g;G}~Oe-8BFo%;?Pq>l%rKf7=MzR)5Lyu*0=9t7tgzTFV+6P^!B zM%yPV_X*V>2EiA`yFM<*xp$!nZt?qe)nMIWb6;Q3uQy#6+|B-Q(!s}b+r`{~Q7d#iBindQx z-gVU-2Eh-;D_8h^&bhqLxy3$T3f3Jq@A7L!5B3Fkn|aMHn3c)JT0{#@wfCZ|ZmCAlZ#=@q+u$)2d+dYkZH8^F^A zoBy7r{MS8KGfVeBsy__2{No(w-km16Eo#7MP-ocum);=!u}{F?>=UO9Tn+!;W`;Lz z5f|a#i>LeB2l8KE6#g@wlP%xZKTrA3s*f-L{xDv8qu>9W%lx?o|9Y_Qu=$U_N%UZ! zfWO%%PCB>>|AW(eCL>Ss6p6Sb|75&<@Eq-<}8q^s!_r*8szE{8CZuW6B;k1gBR zuPOJc>JJ0p3*!@S@%x=~nLD@OJ|C<*Z0?1(iXQ9_a5wwINe3U{K1IJzaBwQN;}MtS z9>y0oZ3~`pkT>&A;oly>6CBZAp!`=oS4_DU{xGY0&MnXc zx8Pq3)*Uwg@wbZ}>=W=e`@~64^6y>h(C2(rqwmxpK6xHud4;X^>IZpC@6xY>0bIco z?S*!kIS*?CxPm9zi}XBnJYP(? z7Ctf9R^RkE$GLnSxW#!G3+fE}JhZNo^ML(=^I-OilMX(y^N@UpN1P&lqw^r|_#~c| zdS4IY@0If~>v>7x0sp^9&qGc9gkkWB@#?$$*8}JBdEgf3p%JV*?DH`7ZqbANg7aYZ zi<1tnvGcHF|DJvOVNhGdZ*(49USXU0YVg;!mG{Yc=nUW*EH`qoo`(_j6VAgY##=rv z$GLnSxW#!W`19mahJ7BEnsOenUvM7GesMa$)%{V;$d6Dk5AG(8?x2Tz&$;$~;au}P zd{CrUSI)DlHw=LfjE}#^?|07SpI32(v_SGq7d0j{6Cj9gNV;5LcPr;w;6VbJ_Ico3MZU2Ub+CUY_?2a> z@D)1)hh{Wy(VPeGQqHUgayIqgGb10*Ipc+s`%|3th0;(C=Z)cel=FJvK}4DM`QY3^ zzOfT^uz%^&aNdxyQqN*p&zsS_MRTsdTk~N(kh7@=pE@~u&KWO^+@IpCFNCQtf}r2b zdzJG{;6X&0_66WPg?wWt>R^9A_?2a>a289>)o9+LId8m2IkO(f+0=tioqUcT@*hzT z$6vg`{p6hZRkEMkn17#gZUr7hlxbfK&dbO*cA^gU&#i}gma+1DqSzB~=tT1t&AIYk z&4=|s&ZZuGX5=V8pmDNxfzuX^ttV_jFsmx#Pa#B zN))GP-s>Mx-mDAqHg(}sCr_>O+L7b-;TI9(z1)442R`V*4}H{wD%Q_Ea-RG5KaGzn z@8!S+k+RJt;N3*tu^08QzxvTo-!fLt-(rQk{A)+^7R`J1GR=o|LEfe=d|u?K98c8U z7n-`?jgG13aku`Jz2}_kL#E=kE>rH?IUK_XZM_lPw*$|V3w5!x3!QGeEMuj<#a7@j z6~!r<``YEoo%KQPrapXTDeiJTX`DKTU*(+i-&ROK#_L|Lyc>ZFNMxHgfp;Bw$6nOK z{>sNfoy%CMbFr-Rm1y3gc~5^_^I=_(x2X%CI{BD7&!8SSrq3_F&Po5wIrH-*jJx?U z<=)TXNPe_$2KRp8$z9%37dt!9>9)%2MfE^A^p${R!pH`XF~xA3ihk@!Z`X z5FK9Fzj*TC!imG~cfRet1p1}8$Nuih_Sw-Hp5scNQ2z6Q6Ubznw}5{QI$|&CWB*Jq z)V++YxE*5oJ(|sE-lF+WU7`7~PRQTXiBFw;Jpc0#E*x4sUUOfqkzy~7^h@!#{_ghv z9Wu`Eb3NtW%i-vgF#mfixc352v)6r}HFU9aEo_%%th{d&TYHFdnQZem@Slf{*o*quKlQ0l_cB(#=TR)5 zb6JY!Et>xh@?o8jzo`?SdW!#n!|sdm_a9i;<@b5~It4%X@${^!ee2G6?N2K2jU0aD zM%xAN^}vz4yrmv?u6{c3ma+1>Dz*ZLt!Un&d9Qp%^I=_(x2X%C8TojQ?)U5#P8>Xb za-X~GawI&vE{^m|ooCYi?i1>H=SHXbWL)o4%6~R+0-0>{cJQBrj@XO(*uN9}$};ve zw?i!Jy&lb5H2=Y8l|So*{7s$s)XCNJKX~AR+VR5&4qrf3IouP!%DLy9W4;{U4P(6F zr_hlgW^xet-xIcAX@qU%P=k7i8YS2HF3!%PctXyXl%fE~1M)MZUyZS}Vhjl^TrY?Nyk z_Z7YN&ARj8{uFQb1Eq^cE9dMzdv7)G{N3s+@0}ce^9z>LBKLpMVoxwpTn+*u#wZtBCQPM(fq z{HdPOQhtVe?4S9)WTh`D_gdhSiW_fifO`%3$NQ;^{WF`P-es&@e-V2c9G0Vbi{?J{ zHO+_hLGGqLd}fAw^r@1{)Y8vzkNoZ3=Ww2x{jzfJ<#0^TQYw7}+!widHsz1?4Q!5;?=*RysLpr z5;LoDIe5<@@7RZWlKy`PbuMG&^QTz8em0_ci{?EJz`w8%0 z4_vv+Tk2zH`=0`T87ut7lK*BjZ_)f)TR09dFZr7~@u`!m|GZ?MxA2cG9y)SSIQ6Ie zxeoc`+#gO5j_MIEpZe#p4l-8mbBN{dKQy9wi(ZEv z&dJe~En$l;$eLe6@xlk87 zSHBgw%UF5+6-&Ka(Y!@-U-=i!hxNfcOnvy&$uq^>RsGS3J^eDd(?4DEsrd8XK-~vU zM3-ql3;uJ^5j#;|(*NziU&hLHNU;xuLp_?eX#PXw!#W{pOwFjFtEIVtE~SGn%(( z?#tiRd{`gkUW)XPkLQl-!18?p?ot0;-|y%6n|Gc{hVk3~r2H#^6VYYbFMD|DxR6fe(>o+OL9p8~Mjh z)W!b#zlM63u~P41SvMQeyhU@L|2NHt^+E2YK78ur<8LXYKT@UklXviQ1y1qKGEVi| z%6TgAFkYk0uY>bWjz4v9dJ*oivWU-@CEXBjJe#maqE`PYu-Et>Q6 zziU3M2XZ#`;PWCM$M5*X^+k8~ILt#ZwV(BD{VEyf>(%cn=dB!WKB)QMH^I3d_?f-# zcT}K*o$at)ma)QFEIIE)^A^pyHBip12XZ#`;8P#veDsk0Fv|U-oW(Et<2o0S{_EdU z-t&PAQDxeH0`DsFj-9B7{Zs!D>RQIi-yw;W`%Ut1DVn!v-aE*LbwS>yE_`0(!+PC! zi?#^cXIfJ8MO5;;5`f+Q!doQ&UNT>+hrLm=WVe(Z_h+=iss$< znet{`khiG|pL)#OJ$jz{NpS9u>)QL7Cj#iV@&o1E3_OS^(|#MA8^||yq7L@Y3`1SZ zSgB{R{CnNiXx^eZPyJl;VLgzusRy4r`LM1pSV(_kJ@?0)ouB>LvZS6nKUB_}Io!yL z_B-I*3;ejtTk2qE3%cBPS;orqMPlVVBL9ZbyhU?f{)KX8J&?1h2cH)?lJnxBy6@-z zxIgCX{8A5e(XapS%DEbNFjS`fE;!F3-`I&d*gptR^B4SK+)NW97Ud zmgkLLG;h(IYyYMBupY?S)Pql*e8_p9`{LZAM?y_=f6N(vse1|%kp442Qr=U6i=Qv= zf7{?)Lf)|-^{{_4_?2a>ybg-x^DMK`yhZcw{aSgmF38)|g-@M)4iotP#q;HFDyWN= ze&ine+t2DUhW_(ER_-f-4?||!e+BmyWcCJI8 z+b+vkIiHB-`@ZQYPSLzO|E;`P7vyc~!lzC?3Gcg~IC{)fIroq7_I~Nl=n|0r?Vl*` zrNG6{m-oLPfOi9V$9~kq{`udA`j)Z6TP%6EqIrwvJ@-4!hjl^TrY?Ny#+h|u@m*Ozwy7}_>i%;c00t%y2!tFG;h)CQTsiP56sK;Fm>beBHz*V*uQXS!TtiV zcTdhY`Rk$MQeVpIhH{>%pW}5QhpWyK{{JJaLkW7q9&J%4`?rE$S;oq9bYgD_he}u{ z-&6ED^#7pizbWL1Txv?$Kco`jjZSaxk}L z9sNso@_KXX*O?6e+}D@JFLfQ~18=5~X@7!stbs@DL{99Vy%P17$}(2gQEc-457E3u zuj9;>H6PX+*U{9QPd%Uify2iak6vW&MacmA+v6#{4jfmRJL5b*MQWbbuXG)HIb6dC zZT%GMuo?KKT&R-lW%jI)R&6~Fsm%D)ykrTpTJpMifJI^zA*$NuT7gyTTQ%5fl;=dS~xRDp_FTi;t@Z&DE(811?uw9n1 z@;$O*uLp-gG;h(In^#lLtOs&7_24rjAIGnLpuTwbBZuxzNvZvYGyPI;RvBmKH_CY~ z@JPjrH+~7u733T5rw;ZHf?rw2%5ySe`FE`KXx^eZZ%yI&!o1{c>cOW@KJH}|x2)3- zC2@bkIqf%cgNpu@|5n~>feTS(+Fyfrn|ViGi5~Pft{%=GGFCn}i{H zSh?OTmb_=9d5h+~@yE)WbwS>yE_~|b>3G)`4jw#_uI|9k@D6_Nt%-f+P69IC^6!-Q zO5oz>%lqGN!Fw5b$9~kq{^~VDeal$6eusDu5L zYlXTlxv~EF4QI)DC7QQr&ePMH59@)PO+EP3$%O?9NeExKbwE-5BjMuPGbDkl3s_H51fcD(_R_;YtRup zQ6Kwft`q8C#>(Fbh~=lSW;Acn{HLy~`LIsN-_(guoqWvsWpSs!z34^%?JFtwYTyGR+2-otUPb<~7j?0J>iVJHW$bBg zhuD2^Sc>K?n)?p&VSSLhsSlqS`B?7q*Vl&@%}p)mNxv-a^v`-;a_Wzi`+5#X;7QCi zzagOKFHnFhfke6E%*8u-!nVn@17Jf ze_oKR)7({*`)uGtWSRC_;697|V<+lj|4#5L%UC(jh`k67^=RIrxesQPJL`koO?~*x zvbek7@|9ooqO_D>X1%L_>aVUDw{cbF-U)nCapR3^gL?=0$NQ;^{jD2?dY7^CoV(cj z!l56{TQv9O8*4tS4{|s4;WHy2Tfc`696rf&2ldg?Ka;;1ms$ijnB!Vk({-2$ycjyu zUI*(i3q7$Db+UgD{K_)+=5B}BB{lD8F5R zjMZ>Ixf{RKI~w|Rr%>;KM=D;tabs|9Bj0#Gb+EsF(@^g+Rz9za-3NzWG;h(I=Wm93 z$Gqfh>cMA5KHwMsc}G&G5oiDB9rg`7<7{4CIZp*1M3iZ70?s=*{?x(2edu!AWf?1+ z#V){MHi}a;=Z({pGwXqzO+EO`$OoJk8})-nM*n&#oEIYAiNAgCB7qrq=Nig=Iq(6I zY;#j^Uq=417j?0J{?9^v%UHSYC6=#7Ytg(#bDyhdKCBONH}&CDCm(V@xVZ25(F6Mq z98bMl4;*9e!9Vr*cEY`KP31nw;Yfb8Hv{)U;K^OyQWrbB(CN0zGFF~%6-(~ZQJkW= zubr;kSs&zX>cgiVaXaRX>d5d4_D>xaa_9x1DDexeoOnVwQ*O71RL>=s(zImu` z87t=%vHRfAismhvb7_y}!+IcRQx85f@~Q80mm80qaIcmZ9dc) zarp|QWX_vKq@KCBONFGYGXxw|jFIDauspMII#gMUOn94CWo zEB{L11Txv?R^UGi9kCbnv41D{m1V4a{t?T=wieA>H2=Y@@@Jipzo`?SI=R}q&-gj& zUC%fAv($TeDc?50PcsTZ8)y@{gUUi~YmkSC+AI zo)>!;ILt@$7R`P8w#uFLLGGqLd}ib`Qt$FDCKTr^{YJRE*H^zx;_sdl;Qbp8<+!Em zEB|)jM3+o^8}MI)j@XI%*uQ+cQ1>#n;&zDT`DP=Uw`l%Lf1&xXPRQTXiBFw;68=dY zrx$>JBm7hTqYJ=st2a>o(}5GwW!l?<{|t1*PSnT#LGUZf*wft(vHXk1YBX=r{I||f z{;U)7H+AAuC!d7BFXnyjPjZee9-}yC={LgP`kOD_p#S;}QTKt5i8|W69k{oVf9yeB z>~G#a)V++YxE*4faM+0EEt-2{4t0-t$=%e4&y0K$?nxbc_Q-x0?rHz@N#BiT{H+<~ zKNUD7v9lU~0shm_5&KYI(tl>)FJt9>j@a|zFc-~RH2)#;VV#h_sS}?W`6T@13-FE{ zwk4nP8>xHv>kkIY50F1O{oBFVlna*jr&u{}>BhP)t2vy3FEM9eUAlpHvQHY+&Cb@| zur4xI?mvlLfWvw;Z_(?re3s_J`r*2iB0c1jtc$$99y)Zy|B4O8IZMBhb+P{O%?~rK zaTDcV37kyy(dO;Je-=7o59&+$&kp=$Y{l&mdoMWDqIrwvKSVyP6Y@88;xi-H5&qE? zdiv$^*DLj@d#^G9$F**%{5v^3fhjR_;NJ~glYP>lK6bXw3H)Vj#qAJF{{3j)qWLeM ztNE}_$iEcnA)gWc(H&U&g5_ao-XkW~E5(@_68Jkz5}rM=+a z4O~+$)W^OXKIx=ecx_|HN|>_mO+pSnxnFJpzj zSn{t$^A^p22l=p0$luh7Pn~>5`A07R5K902b-)XOeF)8s<+$ZNI1X~SVw%L9i*;BJ ze3O0BpiXwS?;6%Y#>(q}SiTNyM)MZE4z0W4IKaGI2U9OTb@EBpfxqhHzg;*yFi*b` z{%QY;`#TgrGVlAm)^4HeFdKLgVWvF~>rjQB*oivXUzrcoC2b z`LJHN4yImw>g1cf4&g~0`t80Bdy{nt--}B^Y8hwqmbxD6IegQj-2FtXM?Y{*xlk`V zJJ9d8%Q9BhL+lb9wxW59UXS+Obv;-&Tn|$>J~Q$eSr2*Nb8>>?LjCQd;Hmgiw^IJ| zffLANn>&Di4LV{k>SKRpUpO9Qtne3me>gOwd5h*hy-^<|%Oo_Q8`1b?XWS=yskDVRpb=zebEBwWh{~(&TX#VX*<!I1*m__Oa7)#d|tcq59Ob5+?D@c^B|Cq9^MzVZiD*I;R*M|+!_4)forl) z8q~+m4)nV1vWyk}V#$9H&0948b`AB9dCA|@iBElm|MBxr9yq>uD86t_zY+fQub3yz z2}NL_-Mua9KX5W$qs_a3e+@cf59(uon&zboIm9qK=arjhDG;h)T*Dgf;V_xz%b>dSe*DU^{zlu5DI>@;ARsrWJoq^*Z@bY=&{cj%Y zP=}t_k2={ub1)nSGFHw%Vjm8N|GJAXF-Ou4iZnXQryB9cem$%fz&NlS9?XrxO=gGy&{W1ABh~_Ptck8h7 zW?hiCsSBSMc?RC@4NS&^p!6H%p7^Kk3edkkr`)T7kDoX1fBV6`iu_|g>SF)Ykx=I{ z_B6Lc?CEe=ismhv`wsG9eUQ7U51(1WC#iGCG5siF$}f|XWUQR$#qxVI8_~Q)ufq=V zVZCr2OuhKj$u+eOV?LLt=X-a&c>l`T_7W)L_Rm87=WrxH+6%yaJ@Di%Z>fu&tz&_^ zjFtKq%im?(ismhv`|@$rKjtNOQy)Hc@(JAijjf}HjvS@5l;3FGC;q8tgBW*sHtId_ zNyUvfYT!PL{Nw%9mGqwo+-2-(ZiiTMuSfG1&3%Y`SRdqW>cgi_K7l*y_teiLrt4k& z^PfkYIam32a(E^j(KrD9-M}^FLVfIPT@?7s*wft(vHX6~el%~<{Fm>g`LIsNzZB^i z<)74XY60lCOWkKK0LRUrr~E5{6VYYbdw~Bebi_{7m-IIRe;F(1d$By<*P?lg=08L} ztP}D#b>dSepHTny0nbET@_v1kzxB_*zSgXw{&RSSnY48w_;&->lneE-bM@lDU&fy9 zc8FboLqD3gX#OkrM*U-6@-IbtM)@c8pMEeDI_N*T4(V~J7XdexhLjI;s zeCql9PyO6bn*Z+44XxZ2^&dD9U8b#r{}Ob>PSnT#`TK?Xm$AZM>>fC@qIrwvKX-rB zKjtNWQzt&NeE#D<36WPv>qp4sy7XC+$744uim#yS$}NcJ`p#ZI@-Nyl#u- zaWECdDS92&AAsWkdbtj!UVQ506V5~aeGpIVl$X5!8GYSO`B%=h7cB$^BJ}5#|5D(T z#Lj9Q1^*^=#6Hx={`m)n<3Pp=f3f7h8qHfY|G5WgKCBb+H+AAuC!Y-dsTTtJ?ZV%` z5X28Ka@=r1`ETd&BuCm~;6DglxyxJXV`mR~-F8{V3V*TWKNZC(n*aKPl|So*{7s$s z)X67IF!1FrZ>f`=ThQ&c z%Q9B@i{)`J9mOen9r_Q&aR9ws2U9OTb@B=8kbWSP`e^Atx(?}a$pehhuYPcRb5Yl$ z8MtwZOnVX5qXk{D6ZNvc`LJ+Y$XGcp#PT>@i{>qQJsJVLSKl)~$D=X_m{ogBVlgtqR5^_YgPct7>Be;EAAGFH|@?Cs$&8`jJB z6ulnXkI?mC-Ecij-S|AncXU1E{f~W;PKD4ve?4?u{6HzkZC#-2uo`%QP_}7c9oC>H z_M%SquRJmw7cy4XLF^tlY((=Gy$;PsX+EqMu7jx;pBee&ti%7|xbW*R@?a_FDIL&t zm=3&%Fw_naH-wA$Y87u1`mg_Jd&0F+34E|czf%U?5F!kb7C!f)EaMzK{ z;XuFqjuRuraM1AZZ2EVe575-w$ ze?FSGX#U%Oqx@MX!c?(>U14Gz6%-lDnJAB(!jyyR}`!)Hc5QuprXEDppE(s94#ZTu?d z5&$gyJBM(d4_qS8^yW$MocZzmK8CkDVUIpYN52g2iGS)rIv+i}@9ZB|{;j|X9@%CI{8ynP_M$%aHy$7AUB=3D z6=LP}R{nLPd5h*>dxGY}Iw5~kCq6H7P4gdpppJgo{Plslz2=D``VWsN_fp{F=gs@y z{lLA1{9`}rV*hsVE6Z3pzlc2@4ztm`MRVU=QSPh{ayRwiGb5jfdw4L80%7T&!#|9x z*i{JiKXXrAhn2u9njyV;f2_kQ^rZKeO4P~z#uG#R%h)|`hgkk@Xg8X-=yj<5t>(je z;X0Ul@u`z*dL2d|sH0yte|?~CuX&)9{_{ss|A7yYW!eXTdkOi+PSnNzt>9Odu~PqH zPlv;7G;h(|`%gmsqi)FE)Q8WEd<=Jgp+A10j(!>36aU@L`^{sh`@o6lGVKGwzXct! z6ZNsb@#IkVGFHy}VtL;0MDrHSzxEW=J?15UQzt%kay9(j>!`2eQ$E*)_dC|#Jy^$Y z5LPmb-#)JVcXD`=BkhC0zXToZr=>n_ZwJ4!j1}%;`CL~etdAd3H2=-NQ~s?jsqDh>mZiv z(2eFTdL8O590!<}>tO1|r%pa*9qa>hl$YFR$>4AOD`$m2`A)^(z6h@afm0GYtML%< zpMs9qhx*t*2!3T5EBwXY77nw~yhZchdYbZQoshq&6Q5ZI|KvExdccnU8S9W9m;TtB ztlv~a*P#`75n-lnVjbGh6FX5S`#Vn$$AOI9<93MU{h9S>-lEr`{S3{A^}=;9_2N?} zS92U>K43?`4F0JH?DD^X@z@Ff*JuUI3;Qe24C^Li<$8tKB{Q(rza@-gcsughaS zUtwOy=|A#Tit)SmR{p&lp1_othk<`Ta833}gZkLnfnK*=ma%gF63f?*K{RjC{M*k~ z{;U)7H+AAuC!Y-dr+mI5;-C4T9pi7_NBPeOPDGb!9}fOC=!l)DkNuVBg!-4U!e1=; zH=}ur=0Clv`LIsN-_(guoqRI*pYr*Nh=1mTc8tGsU(|mNPjaMv1o-y@SMKtb`qd+HAQ78N7o)?Y-8N0{r5X<9WIhwcVb*MZa#{uT$I+%L#sgsXc2mgMECwA(i zrGLijcxqhU-{IFz>N@muxN;uaM`0bd0$=X(mO9zF0o`u9EMw((5X<9XCz`kDb?Cl8 z*MarIbujhfQzzG~bx6G+Kq&opTL=Hbzz0gAam!1(4)wqb9@*xvu?|bn6MIo7`{(~Y z91k*9)pCn2UPPE_AB}ZbhMw4oI@!O}4#$IxmGhBUUgvH{^A^1h^%rYC ztQW3>sTZF*`IvP`KS)P`u=LMZhxE9-2k@deg9qrk401R})0h4R>oNs>@qX%N|1kKK zW$YfeLo6@H%!GCGLyBIP?U(4fuzt8Mrha@LOL!13{i?(9l?Um1 zv;sGsAm{&&!FsGgSL{Z;>|c3lI8J1&tcO@WhqoThTl9J~U#9u6Znz$%ZhY$Gld&H1 zzQ{azq)O?(%X;Xz=m{i_Ydl!jVLI?4!c6;EtV0EQVkhcM`d=Q_LB`5Dh~@jJ`Dosv z*I|f!ST9@$Q!hSs^2u9=|HE5eo?c=cybI=nzQ78MS*TOo;Sa}~Mb`Kot(Y!^kL+MqT59@{NVCuzZc8Ya~4~K;3 zDb^uA9FlRH57l+(=5QrX+9zNgHUeMnQVX5zTn*c087u1`mg}$;&0F+3th`#+f%U?5 zF!kb7&sYaOXh&%&zYPBLPu-zl+?|Ih_qo6)6*t~k0rxrNKe9jS-wE4g8GD)=AeP?) z(}?CRn)~22I36)Cxtsd%lE}xMhxRWXI&x^?aQX}GxZm)$e$iP!ocAk_K%ECJF~ZdL zlfb*fyi>Amh=Thu=c+hrLmbuL!UH}Y>jnzv~F+pkyt ztP}D#b>j0PpEUomp35`*@myXtd{SoIbuVM( zJR|mWIP{`n}3IOs6bD8udDy4e;BsQGIoy}AePrF=A(IwUWe^VbRAePTnAGxUJ|*c*TFw( zk&;ZmZ2sQAa;CXbME~A0>Ob&F#f>+f3hryjKi*GW>~Fp?)W3|C`WJgT9D32bMRRYw z3H6V8$=%e4&y0KwcYi-%jOX%r-bwuJHw-fF;L)h}z=y~(Z42C|k$>z&UF;tOzp{*# z^SxMduSWA0&3)_5sCU#2xtsd%sgsZ4?#>^+ep8Qw(QlV}$75jWzeM1;>BlJl)xe49 zGVRmAzYQI+6ZNrw`7NRDWvsl;isk*Y^=RIr`7gay^I@Hkzo`?SI{6s>Ngbya07B`X zu@0$m?!m~^LU3I5vAPaZffo^G+NWb3W}qi_qE7Y?gI`(3$~uVUI#i>1i(ZHAx9K{t zUbqgXUVQ50W7fewUq^Y#`^OCa)<5@oyrst}|90S%#Lj9w1N_&ZBle*__OEoqaUf%b zzgRwxw-L=-H2>z?H6PXq`I|cNsb}y{>UqrP@kU+;{J7Mo-SGZr_3?N;2)u|e(>@dH zP=TJ1Oy0N~vZl=C`>f~e2U-CLW@)!pFGR|Mtf8>krIIi+UUg#1mN_|(ZKgMaEq82xtP?;pEJKZO*| zTeZJc{+l^G$&vOs;J+2Pa+kN%$If-=b=zebEBwWh|4uY-(fm8_QU0tG@;7zjQzzF9 z{;9_<=(h|1U7yEWeiG_Ga3Z=)y9)jd=!l)DkNws4Q2#Pk_=_d~m1y3g`Om%=^^bYU z-_(guom?~cXFYDQ+xsYk*cX>;l?Ce3e+b+x4J+2{^ z?_*0*oTArZ{e3tNpqJ}l>cywN%Q|Gfu+o2*;{oH+m$Eso_Y_@+M&Lz+nf7^DhbHvI zPSnZ%+WW)tAYb^RW)Yz&GVWo$TC%Zns^Qv2tD#%k$E76sPEQ=zUPvf%U?5 zF!kb7C)ccXNWCyaDE)U^2mb<{UWVj+Hr>*7Xa-)0oNZo!by$I(*o!*Z-}q2C9%QVn zgV;TASc~Q@dL3#X)_hnmTnAGxJ~ML7T8GpNG<48^w{_U#(_@>%e;9I+%L#d5~+?I%K_2(|@;hzzg+W zdq{BH($jSvRst^~%(O4WI;=uZ>_naHZ+;{k4>DHHM`C%Op&QLx^g1*?s`;>9xDKXX zeCp(rwGLS?)b!tN9kO1iId1hCx(=nliwHCAi?9yU&=WgRXVQOJSO*y^ug_w+4s+4G zMX$pU`LJHN4yImw>f~eAffpv^^6SWhM)c2EhxE8HpHE$Xrmo9s4(Eg~8f~mgH}Fom zP&YfqNcT=YO5=cznL*I_+}D|yns1nbZXe7Vb8>SSjJy4`kJ#>zT~<@?#~ zXx^gNq21GUV7+i1OuhKj$tQ0e{tw56Ux)ac@;FazRo9^!coAWyeJR$V20gJ8b+Ui< zif}y0SXl?LT!&^fZ_(>8^GVHz^}=;9_2N?}pNw^I*Dpp6hvf6YF6SpdE;<~Nam&xu zb?D`AB~RLyVI4LDU+(gjI@!4n-EO-qW99v<*gbFsOTHpmj+2-X~hX(Y-Uew9{*-wY#LB`5Dh~+x0MDrHC4l|$8 zd{{4B2U9OT^^A4k^QM%R^2^{)|I{5j#_c^{xo_rhOiki8UIFf#foIBvy4cx$A$8^+E2YK78ur+KT2a zn)~wSH6PXoxtsd%nURm>KKeB3?%efh)Uz_LPgGx|+-CzH5Xm;L0ry$tAA3<((*K3P zUB=4u*J62IsYmk`&3%Y`SRdqW>cgj=$vxv~RQipaUtGQ0r%==M!+I^Xm47FPXTlMU z*MfgHa80>TA3ImR82HOrc|8@&`v?7K-lF+8zohxFPRPF$=^ydh>PQUP1opz3#jn^$){#S;k7;i#-hkYtg(#bKm~5a%X*z zyQvSK8F?n${oR-NDb!HEBis{z`xI*MUw?^mUkiLcgi#!rh%eeEmibLDFx8yY-JBesnW%+}2B#|8(F) zbeZ-I;6DQ$u@m*Ne;EAAGPdG&h}{E+YBX=r{I@riKkJ12O`Z76$Y-?f(+fbq5&lWt zi+}#_U6)?2{M&&O$Yh%i_^&}n>_vU-U;bLCe;Iqa+aZ?M6E>oGi{`)dbcH0@;7zjGfVjJb8O~Qr-9=L|I|~b z@)7sK1IPJD>9O>eK4yLsq;|@!efx9E$-1qq;kXHWi9FN33F}se{@96J*gyNtux>I| z{$5k;5*(`0yhX3u%s=6{LEUlPOnv#xM%GPUhcg~>q2I{5S^trzPQ!W+U#0x}IXreO{&A>I;Ck^UjXBT?ic3H+&TtloJKk{!F&0948wJqh(Iw5~kCq6H7P0m~789m%W zzg+(Qp_Vh_$4-;_pLvb)uLVwi{=EOa1^nyK5&Kae`)B_-)W3|axE*5mz+pL>w`l$| z-_m?oC**JH#AimXBmAR>TIiR{Kl7>6Q2+Cro zz`qV1u^;uZf9~6%{$;Fi7t8mp%h9|=^RIjd^^bYU-_(guoqR_4<0Y8-Xz8E34t(i8 z)BLD~8_aR-*W)$b}>R``o0|D9;wqWO3JpYms&kiV%DpE|jY@=w1I(=VTY)>EaS{-@rE z`VX9lF4Mjf{2R~_J5e9|tKSdxFJpzjSiTOgMDrHSfA(Kd|CpEjO`Z7E$#s-}^g;}w z^v_=hydbBpUWav9IoU^`!1}*cHqlh-clz!d(iE+%Q9B@i`_$qC{EGqu>Nm2 z4xpFoVCuzZMy{jlko|&8|NM2}3v&9D#Bq%`>pC<7FA~bMmtq~7&=WgRC;MwZ2*-nr z75-xRdb}FVTl6|qf2jGeUbqgXUVQ50ldMDf=}^i`-q(!qPy6RSP0D#%Z_#zw&f%I& zh{n6I4#U7Vh;X0Ul@u`zf_Bw>egXp*W zI)tZ3_Z>OB@5HfV2aec>Ed-9AwN%=8tFA{gaKoN#^B$~63%X)2>Scdp5RMBOE9)Wl zY&f)|d5d0;+J9(1tQ)R}sT-de`HZZGy#F+h&CxG+J=EVk!J@)BZumCkzmvlgm=d!N z{w3&0cA!Ch?B5E0Wf?2{#qNPaC9IF{DVl%(N6MddLjI;sd>-VJ&3}U9!Sml6|IB+* z|1)n_{wskK$Yh)Mf`1D-VlV1rf8)oY{$;H27fb$~Xx^gv*Zx!UVV#h_sS}@iE`N93 z&Xj+`F}MD`fBdv)IRDJQ1NEQ7lN@Q^2mU4KU_UMOaeFKHm1XSdZiiS|2l-bC>*KeJ z=HLGb>K}T^-_(iEV^{v6{Kwz8SkMQSHpA-g5zmfWBxCj4K(bIq9QsurJ_%LLq{UEq6BmdZmy4XMe^HA?H_B6LcYz+=;(Y!@-pZkU8 z!}=h1Qy)Gv@`<=F96EC1@NtTBmVP%Ua)tPgTG_2DxkpM?9uiK7cA<%!*N&C_p$d)hz!(Mf38@|HT;xe48FyDVd69mMiaXs4q%MXy8ezfu3t%XKjI z;!`J|taWg|2fJ@E^(wr}dC05-#<@S_Ae}I-`vDvefmd+KXkCVNSb?6{g*w?^|7|!P zWUQ=%*d;iuMe`QD4)edm@ql@`4yImwX1lG!zWqqv8T##Z9PHa)Nxuk~aho4h{=*!e zVJ2-|4*olVYs!WC*x83(w_TR8!e8to;V=`$DVqPr|0sXf3Hh5k@tKipavU66xM=av z;>in+F6>)G?qcXS!r%HE{Pf@XkaAxRd`#5Q=EuN&8TrQ^)W!bl|AxAkvBF*Kv*556 z&0940+23nEtPgTG_2DxkAIH6R(Z%wRV)`%ixZm)$e&!v&3Z;K#LwOH!_yJ2|df>es zI41j~K|So;fIhcfma+0YqFDL7EB~gVI7RdB{y}-OF38)|h0lw83~zU(Z1gYn=$FAg z@lXGyo)4cKAGMDt|3=`X4mtn70{oYtBX*-c_Ai&NyRqk~eyc2F9Inzv~F zOJ&W6bwd88PBd8vNb}G7i#<4&uH|*km6T`e4{A$^eqAZ9SM5))>iy@ZwH~gAFfVxS z>-}kL6>%7ST+8|Czfs2V^?S{a{bJ8>>u_bPr|r*bm#?I~^N5$_WBV%bqaNl(UFEBl zO72FadYee@gKf(!jyS5r>RkNslLa=Bi6LQYeNXX9kGhsc9^O4z0@ zd3}&4Yhq3%#NPoI#-6#6a+*QMi!Qt99@3;f`i*O6BOTo-<;47KoUrBXL4)JW9 zto982sE2t`S01NXjB9}lV|Q+>ocyWsKKhMoS0Wud*HBK(&&D~| zF}lfwoLY!y<7Bm)@S`5)MO}HXcPkiI2N%X(zL|2GM#pp3zU_Zsh5G0>uI)rRD%Vs_ z%+JO-&oR2`gq*s6tnqA|taclI)Wf`}EARELgK>RuVeG+a%IP}jcOfs7p9i-N5)f-p9E4KT|G@y;MmbciT-p zKT#k3#CU787!+AfAnr)t-VM^)N5$$~*36 zFmC$h>3W*mquV_0ZhyW`7|2sE>Z*+GeC%J4Sy#A*W@; zvvIQ84fs(H^P(={bhdk=86S5|#=m8{o+^K?+y29foA3oU+_+TcrM|2jcI#_%9ym>3 zS2;01JN7Ov*IP}0bG=*pdZIr1 zjcYd|9o6e;-ptR&xvOI|J0YhYxZ5~c?JoSNhj~$#oX7XNyD)J*ZD8CExG?t2t(6nc zPv4!Hy_W2wKKhMow<8@(*H=!=&&Ii%V|42YISs(w#Wws>jbq!>chvpM@S`5)MO}I4 zrxwOF!G*C`=adsa2S4If5A?5hCFrByxV9VVXxv2eW_~u#e#c1eyy;3{1ul%;IV;WSho8CBb4v8laZEcK>FC}}^JacF%=wOyzei&`bK0!GImF9xD{bCI z=bM2a^)N5$lJoxFjO*#MjDL1iPv@jLUFF7FPt=!}PhNkW^T1*AG|ij&*>M-RT;(3k zB=yulJR8ThckZh5&BKp+m=|>kr>y%9b><5$jNLg`Iq|&TyX=tvoI`!|8`rKxI(Gg{ z^JacFPEFQyLQXBjvvF*@GOzPB;YU5pi@NgOzppU1=61@7 z`sg>V?MFIlH`lzGpN(@5$4KtcOu}gs+-)4&Ub;l*+khYSFfZ!LJMQ|7f5)hv?v&>A zl9qC!KAXch?IGuZ^YR|eoB7!o7dl3Ak7g21JK%2P*!Johb-r!*Q4jN?uDsW~A;z`9 zg|Rz#R!+R%_sronpCS9GkACCY8E~Qh+ATD1=Er`q2OT51M>7eh3gX!~w!Qu)oo@<$ z)Wf`}EAM^j48~2}C0$Rmchzm4#~<;XYkX4Xr9PX(IPLjJ$L1|HZ{}xX9CD209?c}2 z8i;4(*!Eyi=bM8c^)N5$D!U8g7aTq5f2->JgA2#__fYZs&UwUXgA?akzgwEyBf*V& z={K%jiF8ffN_8+_8|ScNCiiS6;nx0hjc4Q7cI5)y--I9aFfZyVy9-g|X8)Ey=C*=3 zmHBkN%`c?6z4Q9l^z}x)Hm7mg>yfUxS=GUOZHyz1ncTyfgxdzz!N#%eMos7Iz>j*E z7j?;Txz`PhIjv({2V5AtclR`>cYzc2(QjP473pZ)TJvUpHcs6!l6yFlaM}iU8^^X= z2XwwZ{HTX{QCHsehb@e&?2GDYzi#vW)z6w*Pt<2~7^@8~^ljZn^JaeR7kf{~NbccG z!f6WeY#iI}y+h|4A`j{*VVk=0IF%5;11^l+TTF8rf)n-8Z(KVY>FC~8^JacF&QZrm z?%_Jm;_&z;R;T;=?zo-WXB-sd{wxA*kdX{gWUFiyK3 z>DaoR=FR+UjAM?G+{2lK(-Pv@IJP}?o<4Ur4?pT*Uer}~5B$hCi5%OvaQN`z(UJ31 z9pgLT!#R32<;CmnbC(==sO+Oo`i*N_v7R%O7xT1njyqOzk75#DtAC;KY@Dq2GW@8A zc~O^MPd;aaQw!rN2co*Vhi>!z=+sqqKH=wuzN{Q}>+423W^b>$n4cYc!ZDJ26q9gT zA2Y8t_)$-i7y9$ww|B9>3ogvJf1z^vQ*>PRi}DwxNqzJi*KS5S>T_8Cs9)k;A{bBm=|@)dCJ`u9I2;GjGH-_uBYlD-R5(jTiaLrspOF8J5@r_{+&q2 z%9+ZE`C0dSIYx3#c@j<~#Itd1yLLq98(@8?hj~#~-sj~VjBA5SXIS$0yVegYC*D8( z<~@`X_1PT8X;&g0oxPej^RqD;j*(m=o`lmZ;@LP^?P>T?5A&if;dEBUb6D*UL2c~Ms$ zry9n!!G*Ec@0qTr^M9rFM1Axd*DgmohG%Qu%+JQTw__yNh$rE+f_OGgR(lD4)Wf`} zOU~nGXFPAcjB!&(mCO8#ukMe#*<-rR^V9dw8U94(rM|2jcI#Vln#3;z>C5!QIBO?Z(S=zIFIf5A&ifeg8E2+(M7>Pbe40u3V(syiPUs z=IcLE_E8`G#dNCZz_=E; z@IHR$Ug>(`eSYe*IgHbu1{eCa@1S`zKlY3LE5}H#5l_Nt2Jvhh+wQ(X=PSXFdYBh= z<$WHWX8eY7;eGtd#k$ScJKpD~KAXch?JDPi^Tr)DZ{}xXoOF!j8u28Y<`K`vvF*)Q z>U^{CqaNl(U3urHD#opX3uAZht(^FIcNUjl2 z!fE|Zs23Z^wAU}z{dM?J5A&j~@&P=zaP05__q`P-j~+PxVCn&eg%ih*Wb~$=atMz! z#Mk|nFn{$v$~U>ce_!3^>jCfolarA$R&z7rQOA9A>a;=b=UB_N{OC*J?3KAXch?MkGhb2l7M znBT^DfXh{`B~QX>7V&Hx+wQ$q=bMHf^)N5$%De7R!MF`@;r;!sCFR7|1K$6qKAXch z?OLRxKd*T+KO5tLj*(nTo`h2!@oXI19=uNHtHO_Zm=|>kr>y6ZYZy0wKjp&MOZV4p zz7PA!!u9<7FzTb1@UYg+wPy#`Ig{EJfBx9**La6T+;ok z@S`5)MO}Hv-5SQtKQOAN2ceJrw|38RyG;!aY`PoQK z$4IUrPr_*k?lz8X&p$vpZNZOvm=|^BaT;J;?IFsA_xGDk-R60m_y4KS<}gls8eHhx zIbZW;e(V?fP{&BFAy2|-7V&JHRQs(uUkQHH!@Q`g>@Jw|zWm`MM-MF=)F|=$&S}Ki z0w>|LA)bw6+ts(}d{y{S5A&j~ z=sA$1iwF{Pt1J>a zUhXQlW%yAK^P(;}F0-CzXkpwCTzG$f`jKf)y#HT@n@FPoIV0hi9R}x zX?G$WD+e`i=4Zn^$}y5_%#&~`A)bw6+x3U(d;_cx^)N5$%HypFY|gZ;@LP^?JE4Jhj~$# za5~owbSCw$hH*>a!uznT$0{d&e;n`AQeP^_7#quxjv?*?Gd~;R(TJQ4jN?uDt6m%NVx}E=laiD<|Indc_-WKf0+vF*m4{>0zcTZJF>FfZy7PJ7*r!nmH+Fs=bEjJ@&%<;2f5zrUgW zy$$uzZ(Q4pbj%-BUChtMd5p_duH{X_sSoZpj&08@>wN3*qaNl(U3r{(7`F{BN$e-4 z>*=Zo^*TKDC4OTz29b^??r$tF4@qOl7_Fm#2;iEqKjccosj*Sz_iTT+$k9WDswY*6<%_E+TW83Y= z=zO#AqaNl(UBYSZjOxhwsfuxpCo31;hh2G!Zu5Eq@6%GB&0(DOQlw)W_ko$8jqwDR zt6a;Qgi{moY#iI(c&u`&!;gBH7j@-vTEe((aA{t0HUGL$dTP3!F1Y-I{w09=Y!2hJ zS0f!$4b7YR*%&L1kzC80gj4%o8qdbD?d`|u{uTI95A&ifx!!r!nWOKYRxxe~To}96 zQcirmyZF6&U6}glH?Ccebj;!YCiAm#p6D3KwY*6lilx7v6`Rdb)Dr=N8_lr9PX(IPI-SNB7>EH}kVG{?;*)Yk8A!nnOGrC#&7Z`cMz^ zqOS6hvHxEF*a^8YeQfj(>Gc|1MzGe+wMG3=bMKg^)N5$%6t8+V_fB#%7wA# zpOxlx{kte9>Z9Mdb|uoWb6?Gy`Pn#6c8uiO-z1z`h-c&2cK>g6z9#&rhj~#~9;X$I z>wpVm_nw{RboPst6ZO$=T-%9sRQ^iyW_~u#Qye3?_BRQq?q6y=8^^YXPtyHu_)!n@ zqOQFAU>%IBJSVEBRo&+6!mnPYpM$8+<}gmXAL*#!J}2|DG5*dml52mHaM}cS8^^Y1 zo}!#K;72{oi@NeS^)apsF3J7a=PD<@ALIR6>a#hF(;h}TmT{kx`Pmpxb&TZN-z1!N zz}?2N?dDUJ(>DC5hj~#~9;YG3%{@=K@P2Il`DsqPUrT*9hjH37;6mTE`)S_HkNsj> zj*(pZn}kyZ@oXI1Znt#4Dfm$j^P;Z2_Zc%7w*fA^AG`H}G$-D#r9PX(IPLjJM-TUd znV*gEG{;D;{Y}EDhIlrPZErkHInBY3dYBh=<#C$FxcR?VF1#PR^g`XfF(%{vTI#bo zjMHvLItI8O%=~POr#nV+?QarJ%ZO*=*!K3*l~V(L)Wf`}OO8AFy{h>AQxoI*;KJC0 z7bz#6$Ip3e$KSu9KKhMo+mVjSgEVjEXX8A>F_LS4lW^)jP~+J+wmtVO-QR*A^)N5$ z8u$Kl8*!G}%87HeUYzE3F1S%I{l>NZNLS;*s)PC3IL~y<j*E7j>1dY3|#*FTi4qxZe7RGX$rdx_<7SercN9W8bCs3#pg!#xZS;l|4a^d~h$}4o6 z@2_~jmilZCOfs4K6Y zRxoaQO}Q}k+^ck(_rZShX1xzaee@gGb|M{>M`+&6&&GMKVOfs4K6Y`WUwZE{r|%TIIz1&u3rqnLo%r>Z9Mdb{Oecew1=zem2hY z9V5B+G6|<0aJO-6d-yfIueuFC>S12gm3Q4`h;b|6(!1I<{Pp;?*QJlUN6lR4buusY z*&N1c&wvYk*Zx{LF+cW;eSu>n*Ip*!R6#r&C#yXLKk8v#)FqtuR!8qY&tTjTTzEfr z`VGp7@7H<1min@C*sX6q($T~HVCHAX{=LgpuDwjcsfKtqj&09euIn-fKk8v#)Ro6+ z9^+QPg|XK<>3aI^6CsAXX9kG8}OqZ=0#op zxN{!>|#tRt~%MZA3b%xX;P_?AW$r^t1^% z^}yZ6vF-LJlw%iuy#LI+s7vZ;?u>Is>S+Vx2H?W`u~TnRPJBPk`?b_(a~P++9qCxY zeNN_QW4zeqD%V~nsiy(B+c>tp(Nj*F@S`5)MO}HEwlQuQTzEgW{nm6n@qR7!*&N1c zPk{@4S0Ar=Ge7o=eTicv*Ip*!G>v#Rj%{yWq4Vt^59(oF)FsDV*8S%x#2byWMslrX5>8dbvvF*D>Ql<80zc|uUeuNMetZt& zR=|a^*WRw2c>lTjV|~4&KKhMo8}Q+_9ExG?Vb&#QNDdw%z@VuEz%asE2t`mmI%YfA`$SxOH$z?!&$- z&58GEsn6yxPJ0;XSjPQL=4WHP!ZDI-G?Q@J0e2h6wl_bkoVMXdJ^$Qr#bOHE%n(P#%a%h3w_s~ta&p(_KSU`V=}A56t{*j5WtduF*`wsfKtqj%`;y zubk%KM?K7oy7D;9V_bDzxiEI)y}Hf&U%&g&LH~XC)JMN@Z8Op__&d#;`Pn$Ha*X5} z%_N+b5zofSYB%6VJkyr?Vheb@%ZZGsE$R}Vj!=EVEi z)Ms-Tr@bBNSi*f^=4WHP)-jT6G?Q=|fV+)j+iPD^PMh$f9_B?|d7QQ}uJIw|!u!=L zAJ%Q2pLjo;`fLv4w5Py@zN^pByqO>S#lFrll4~@RaGFLu8^^YLU)K3{kO%cJFY1!x zZg0kMH--4y;F84th;q6KIxfGB{vAE_C4OTz<{};I&(yq`pAGYR$4IWxOv0&(cs5Q} zy8=JzVP4dgcOIX^xF)#pzW(Y*l@s3=@V-CwW#zD2Un9~nc$RWves=5|93#0#GYO|< z#Itd1d+-&VuLeKrVP4cV?sE(c&Ucw|O781lp615;{?u!88mHanJaDey{y6isF*=T! zT(g;kTld+@#m2Gi%BJpb!H;^F7j@a^7!DmcdJ$v9*G=1q(*`Hr*I)lwnj7!?Q!nF< zYx|L|8t#`fUmNEV$4su_Ou}sw>tN&9cH?WxZ3BMP!@Q_Vj?1j)82T7D^Ks?E`});S zq&e}vKlRxh#%T{D9m~(vyqTYk@kYl;uHj6=X$RbG9NTVvUFX||AN4RV>dNCZ#JCQ) z@VOf zs4I`t493k~p=?lFELd~BQ1xWNlFZ{}zH-{Kg_wU-c~7eeB!(-_cVa{l>NJNXPUG zl@s%`ao*|}$!FzBIIaD?#)VKQR9~dJn4cZ{HpfUlD^J3y2kthGZP&JRzApTzhj~$#+}FwaJJk)0oBCY3 zo@V>H&F>$*{kLDZF7r~K&0(DOcBEset$8y)8>8!TmCwqPa2kNSjg!^hgdg=VFX|Fb zXSokH@%yK3jB9~Q@_pu?S5Ca2%I`a;zN{Q}>ze`>`mDZKIWa%>i+#JxRX!_E!f6`u zY@Dq24)UNL=0#n3oTeE63+Z~Qd@)^5Z+O;=d_7TLRt~%M&2b($t-nM$F+V%@9gdNF zR-S}Y74dAGtab%{)Wf`}OFk#xA>(uM9LBAH3x9`w?Mupu=O_M7JN0Gduv=dv(y{eY z<;48#*mpWc@>zKjPD_YqOfs7p9yJ;%_%xFNXk`^=}mqMZC6NxBL7 zedp9?a~P-HigmnP^JacF#=9IN`K&w%r`4BfJR2vgy$nCrg1v#(HH%+HR!)a5FljVIx>eu})R-_!Zl;72`4Ug%d& zqu+Di#r`3<@cYcCzm~2ie&0FuSzY6_HzOVOS7QC6eu?#N$LNv?IczJ2dMY8F zjg!?LV11~Ec~Mv1`|%x&8-fdCPyeHGnnuSjukl6ydPjZq8`oAM9m7{CC+274tUE^X zS$GmoD~M;~WVNT^M?K7oy2|&&a}0+T_aC_Mz;XLS^BI3KpZmA;x+DL4+$+eV3(ovr z^Zqx|$1%V6oV>C$?bf#zahZ9Ia;IK9_Pvg|e72s1d*{_SFW5jC?N#_u5A&ifIgYcQ zXIR6y*>5Trey@4$pVFN8z30@Ik;1NBy-3IWYgHHXvxDE~7|CbrNjUYv-Nwmkufvae zm=|@)>%y7tfrj|~eGlWh;KJ`U?{B3!@q5pyFDr-L`Ua7X=IfLb^Rr{$?{byT){}4= zg1e2A)!u?1^)N5$l6uN|?qh&)v;VAI_`T+}Z|OE)7x=yB)R&dRZhh0>LZ9~Ql@s%0 zzt|5rM)KKu5>7LSXX9kH;YU5pi@JnU*7vwiV_X+p7`y*3%8A!USD*N%j_jj8`i*O= zk&cZwC@1D;<9yIDlF!zYaGFOv8z-wh3qR^%Uex7}yNvG>t76>Tx0MTj&%XX0-RApN z{@y+HW#zD2-%_MwyQ7?#pB?)l$4EX~Pr|8*cs7o0_Xav&9e&iqyr?VhxLd-wb#USD z*>8R~&56HvPklCraoVeqj;S|l-ptR&_^@LnpRFh1)V@UH**La6_z&H`0zc|uUeuMx zX%*wIhlF!zYaM}iU z8^^Y*|Ecr!;YU5pi@NeSZDCyX`^tr}8~>`?yiec#`8A&*`>2n8V_R^cf9oxpH}hk^ z*pE6!^4WS4PE&|y<7Bmm$b))H*ru+$US;KGKXA7M8J^4HTp615y(Wl<5oObJ5i*(JrUAZw|JN9FanSA!1gj=Vp@ob!|_A30S zhj~#~-hHq&jB5;(3%@6S{5w<^^Rr_=?ik5uwlF!PMa2kTUjbq!DU+8>W@S`5)MP0%v>-m@g#x;JdTxM^h@mBsb&1ncu)Ms-T zr#%fW^liUO=V5;A7u$1;n93%OxJPD_H#Itd-+OzPZ9_B?|!pYqR8#(T( z7+3$Pa$)S{pXoNA``9;s#%Z#T`sg>VU5a#UzgsymKO5(hj*)y;o`h2q@ob!|b{&4y z!@Q^~ub!4Lt`9D)Yh2ZT-@ss~oOmDXm22O>LguButQ>ahTa9!~tt%(yXUBfZF_O>9 zlW=Ok2gj8Sl+j*+AN4RV>Jm;_=kZmHoBw&bo|b;0+k7ATneQ*Vzql)vs4pXhUAxvJ z9dqwhUChr8{B>S12gC7jN21D#3z+rqfo zuhR9@{4d?+`RQqUKIey0UnZu9RWe*c;)ret2~%gSN5zIvo%^MlHX z`Ps33$4EXaPr|8zcs5Q}dmet&!@Q_Vt|w%D&to0qHo>L)kZWpv{%>V8<`**ID4HvFiEc~Ms$ zrw+#T!G*C0|D&Av{a-)dY2Q}%Q6K%rwf#s(?IWs-`Pn#Mbd2P)%OspO!QIBmYHz@g zdYBh=38$?0PkoH5{%^XT8o$?Ve*f21ulV7wWnSvb%3-&@VWeaEqsoc-*|A@8jO4S+ zB%F4@-NwmkZ^Mszm=|^B-M1QI+y=OGpQ7Ijy7dR;#P(rI$G9DE zVeFYJD<{@d?iIp`4hXjkD=;mCr7da9aDg#kyr@e!W&Qrt2F5Le3%?JmeKqC8&n^7EEb7b3VYj~RNXOC@%8B{e zv0rz&%4e5JI1Rwv#>r}L!jF2G7j@-v+QzsYaN+l1&0IZQPyD_t>dVSux4tQGq0j0k zmDB&{?o8ktIja0`k&p-yg2(~l3K}wixSa{fid$yJ84a27C^M79VSy3LWnh=pvK$5i zh=m0M3y5>IoZ|L!1Q9NCi`(30As}v%KoB8^2m!?Xuh;MW)UV3ba<^w1cK`l-W~#dS z)vNdW*6YLSb_wyJoyu<*M)bQ&5>7esr~UZqBZ&ig5EpdO?=9Z-zr_EdaKU<5t?M%< zT<@@67WDaInAA4y=;(Z!IUzpX_nU?h{qB;4Q%U@3KfZcF?4Sp6K^NU;`abuahW}%j z3w#%jk zpetjZaq{|K`}fbBv-`lo?K5+8=E0|0+iPZiR&Q?jHf<1wdp|ZWajXbutc%sVfqfif z-7N6(X`0lw=5VQgjyXZE?)xpnoPHNd!o4T+sQvirU9p26#06b+zT4)x&sdXwrQ?_j z*2S8?q0I^FW*Py6T@M)bQ-5>7?&r~UZqIkAHt#06bZ z@5dCRU+G571?ytXAJ5ykE@0g(=<~%esjcGZSp5QXLVUXKcMK!?T__2ss`%4>eD#vp zK@Z}BF5={SZ?+=+y21tPJ@rpuPPiY#dQi~ki(yh*-O(}pB6C7~y6<-lBl=w^38zKz zr~UZqHL-&p#06bZ$6a0eRZe6sSnp}!B%2e~gMvO^43pYgj*k47nG@pEeZOZI(eFY@ zIJLjT{D z=y#zcoK}Uq_T#H}#14887jy;pt>%Wzy)WoWzxkUm7p(WRnCESGeJkkm#W1OD;OJQR zDsw`7y6+DRBl=w^38$fO*M5BUp4ef1E5rp|QTa5GetqGBb&RHN#++~-$2v#Q=Zj%d zTTZyZru{YMg!s@-UJS~s`3VVxuB z^~N-zvEu0JtuZ&mtGoWlFr(j%l5neuKkdg?FNq!WATH>NyKYlO{A6#zoUo2j@s>6> ztaAjtzL+MpHC$c)!`u+B?%Oxa=y#cotzC3es=j!W8!lkdHcW!ay< z6?4HlMx}ymivX;11btdpocfxhqxwymf2W;%U1Au~?>0#|^@RIIv2?`_dJq?MMdj0) z^lJ+jtYg&OVspYeM`L{(1?21>IXV_EW=@Dtn_p@e(eE}%I8BK^?Z;Oi$oxPL;({*X zy=y#hWoQmR4`|;It zVh25l3%ZDt@AIyL^lJ+j`0j3HPUh~{i8a=$tJlO1dJq?M(eHo0b(`wauOVFEyL~(6l#_-#znH)G z8~R`uw`@5&^511nh)?_ZnTeI|sgiJNe~0~PKe|5nE$?3vJLo}N&_$el&kI}9ZzNpc zJAZrTg!hQ9K5xe-Xdm>!E^gU%bd!siG zcs;R$9>fJ*!Ext#t~$WH3Ky(nl)ICCe!@CO(5GXFQ_l$(*fxK_aU(voQ+c^zME6ih zIOWBk_T#OK9rPeB=!*KhGbjBPgbREx-I+PzIsN@EnG4qQhd$WFElZA$l^-%E#HaoI z!Z4zHs3e@q;!pe0^`$@Zctx>;9>fJ*luy2On@ZAeAY8DHQTDFP3GeS=og?VeF~q6Y z93A~1aomVc`?$iyO7~DnI4y`j?Z;QIiXHSIF6fHlRFi%S!UevUrtN$>?dh-i8tsEV z*u^cE939yoGbhBS{ak4n(LGcWPR&01(|&Zl_h;U}D0a|;xS%Vze==`$y7x~@(yuRE z#=f^PCtUB&+sc2h41Hs}n3ayBWBL+~8}Vs3R~bfh50!+|ig4F{biFfmV(>m$TkN0* zaX}YxI`xe8oI294CS2gVaT;^N`=CGi!b_e?`=AeYam${gqkSoJLVViK)rJw>LnYx< z6o1-}uf8ht13icfx-z@u`SY&1?Xz<`cFpWNUq5UkpeySBqAvYL!UewbC7aXN%bZWp2fMgs%h8el8FNB>+RrtH5#5U= z;ncp2{b@hC-nuSxS`s_xL0r&9*G=Dh3@z!mC|uyXb$8~3>%qeoc^x9?gI(OR>*y#C zSQp~cetuH|l|!q1r#;?q8^HH_$9ED5KfaMyl(^`6*458{F@;^g~&mx1(K6fRhor*$uz z6V~m4K3@!z+H%4LHqFbK6XHWVmA^KO=w2)dr@Z*ne!O+DgC4{MT~VL+<)q(GxL{qL z+e!-j&pYHk_!-($1l5i@EKkdg?FNz)XATH<%exLUI-JtnC z%-}w*E?lrKPxHRa3GXRm-5%)k#W1O@=IH2O!Q&!6-S@YK5#5U=;j|$Bv>#u+Dt6F= zxS)%UyHihJfB#gIena5`-?~#E^fKx=*VBioDiS(Gct_m9x4f^ z_Lb~U`_c8KWBEM3D0a|;xS%WUbLS=TvnZS}R_lH?w+n!YPuV$TySNr*$ zVMg~CH}M@T^}CD+y*jV(1W<3i_Y`D=cyy<*AOo7 z-JZ2MeMC4xAME0m1xH8wm&^(AX+M83jOZRK38$j?(|&Y4pJPrrv4bAO1zp6+_k6wp z|7S86tT$8G$=kTU!g@5&r(=jyuV5T8UcH7nAwKQnkA@N5V~d9xDl_Me(Qo`06#W zgC4{MT~VCs=qFs@J9mHPgy&y_XTEX^?Snqp#VuQoj{L8g6XMf;{%jc0JysGz{3oksI_CX)) z;+6wP$AUcHM0}Q?Bd4b5nwNyrP`F!uJR3dOi5|oSUBUgj=kFp0(yy|Ix!^hM!W?ho zb5lI0g+5OR6Pt3v1xC#g=M&;XJCzy3iLQA`IOWBk_T#OK9rPeB=ps(O=gv9lw<28d z9JaTYIgPJ(^4uBvyfI8@EIB$>Jcpe>+s-FEr-eRW43pYwj*h-O2S$9l?-7O*UGtJ~S`dHQkFQ=8JLo}N&_(Ab z-}eR8q~Ee|f$!CQ%n8@Kskfi_WZDOPu!~zRIXbfPd=v3$KSvr)bj?e`sriS=*E{%M zgq`R?T+kKud-9U>E9_@3cn(`Wz}t8q4bN$z597uyJBUv@O#g{>AwKQrx`q>7^OA5{ z5$@WLuih3r=s{f2MaP}*xpPPQwS)_Nubji2@O=KLn;iEn+6R5Gi(B>_9rN;h6Y*(3 zM;T62=3f#{ec`VC`0A@-2R(=jx}rGsq+kAA=7Q(2rSt53!gE^a^TjZ+O}M~jTAptr zKD1MLv|&Woyd<2me~EY84J8ifnUZbj3htjg&z+~le^a>NIc#U1IpKPT=d{qLb^YI{ z^ZG8+vYyHOUs&Ii%opw~-TO;ypYpJWKjKl3eR!d|{b1$X^Mk+m-7_=4zdAd+qd@DY z;0N|tzXa>bV1HDJ^*(A^oMHVK_=dg1@xZ>BGiL*uFq9JZ5&Xk`)+~hjus#abt#RD1+r;`ZZPDWz zKquPOdL|j_dy3gX&#o)^H7s@Ly#|+2bC{DWZ-Jg!_2-td-p+_W#{J~*ca$N z8b9!h^;WPB4)#ZtSg$58@w;}=g?6luVzx8Xm-3&=En-l1)|pA0d;hwe|Huz;SNRb{ z20n`WuDM+Y)`5qehx^#RKwpUD{GcD!al!gJj@i0Rtb@}M9j*cNp&je4nC%Spy_Km@ zd22CPapo~?{6j`el&qQkX;KD1*!7qgwAzQmo%+lWEQ88>bIgDmq$o`Ao~lOQtiQT)gGY)ydZ zfW2oPtbXo9pdZ$s!MZ@=HnPC_J#EqB8bT-9v0jYX&QM>P2P!cSU1vVio`;3&%W)v% zVjfh!1fheEnup*Z*uHya|NhzikT-PIY$QL97WRuuOsRuDnv#-Umfcq^=17b*9Q8~j`erUc82=W`HMZ zeThGn;NOsZgnioli?V(W@&x=vz?*7#GguBH>MmvY4h*MdPT?+@K<>fgbqHQ{NJ~C`&qLGAW%x!PdE>8 zzXGkU6#k$e);GesQ=x^whV`KqM2~9)ooL5;L}oifeNQnJDsdbvNnXM}?RhB4x_vG3^C)%;zk=f2r zUpgMB#6092KWWcHSJqoXzF;0yz67Czk8d8V3xWuR{iJyaE)4c%d3-&=`b=0iOWZ~l zSl?<<^tgu5iFT}~WVSQZm*#=WQ^cSp`3d{9=b<9&79n3S4=P`RP{7qU57vc20*C#i zc?d2L>N9TYihfxC3F~r++sIM^uURxt2taYX_ZZ$NEoZJ41bm zKb1HyEj#m>_B<@e`cudk%!A68Aaw9i^RRQ@?A*+b*@N_P(?REBi*a6i=E3e)z_(q_ z?cKL$CcNPiU>JA2ewD1BCA%XFtOr&QeXb#NqaEu@ne7bqJ;hY0gsy34+_dLqB2m)>{LQs1oaw=sWY7_B=GV@bw${ zf_YH+5`+#uo_R2z8?8GW;#@a^e$L@A?uT{5u$~+EMU_~0ts;6{JLp8aTIVZ6ed#`m zN}3P)S&;nXE%V-!`9YmZ@X&3Wsl!iR*3&}1U>;Py1nyxUF%RzHFphJ=b%N$$Tfyl$ z9_O3;Py1fh@l zgzvu`IP>7H1G9VV56WTZ;SYQ32?gx2&KcI91FxtO>%>(ge%B7V(2jM<%yx$Qo@^>q z(sOJ2sXObtrOkaL>!cw+z+L4>5EuBE{I8zB&wRLj)-Lmn1K|($E8b(f!nW|74?C=r zhV|=0PyQO#nd?Zrt`&5kU9D@Dp}w^4H)rt)L)dxv2lnneV6ew}b65v37<9saKQ_$hz2ug}@0vmv+SU4S8R|=UPbKoc8_rA6 zC2j8WvJM;a1Kd@91aW{5@;>;`f8AS;(cH)O&J#2E#rkzvR}j3SO055vllWab=t4Wz zn={)P>PzQ&D#5+vtlO71_ugGN-;p2SuJR)Y9elvuoVSDgb>I1dT~xl4y?NKmtPE!V zpdZ%7!+M3b)%q>0E7%krt_Ad=U9Dr6p}ur|rIPOB>8In&W7_=ZWxY7$3HYl#3E~1D z@E_-~GXb!3`CIm$2|z!rw}*8QgTW{KhxH0`qQfiWp2g>kOvN zf9+Jxf8+`Ht2_xJ10V3$FV9KnmYvIA+ZVQ(Kje@f_{I8tSXUAIqe`rQxFqqrcF=`( zwccKa`cmFgd3Q1BIP;e__o}S-hx`C{l^;Q5-~;aCJa%5PgPqIWwlC02(d!X4W)BHTr!ztS5-|BEdJR#JY|h(d*iQ1KQR4e;Mja_eE6B zi$U9&@3iNsF6-QWLx5Q?VtN)p1p3g9 z^%Tu^hWc(X6)H~=gRV1=Y4cx@bqkRv;IHx|hzxwdKe*5FobX}i^0(~G%W@)jT%aG; zeZ+d4V}pna*3B%44%ZC&(2jK)&317rp+Bm`I-D(u-?f7-v}4^zvz?*71yiANix_mB`AeI7P1aXL zet^5mk03JeS;yTu@xv~XdvM}EbzS14AJ(VDx}kz4vcUSDd1swSbbvl=tMw!^)VE-E zPyc_3Umfd) zwnT?(1AS;$>r!T@FP(3w#OKZ{&OD~ge?iv8M4o`Z%99{;@Bx4Or8cND2enjP{1|Fe4Qh>pbvdzqYOr&{e^}>qIpk|uLnj*5I+_{kOY=Y_ z=ArA%XWGX@eU|4P`GR?va`b?&I}db!qu=s@UDQ0Vz4MZlVSs*E?-T2=f?HIH^-_zX z!?lCHal5R~X|^-em-thO`=H8>zw&V)@gPsYU*$;<`k0Tr-+=Q=z%#*d!1nIjRUv<@ zBZ~E1$J`<+Sci2v|5axm)6V~e3de&y0sko{?kN7|^BkT2 z<2;Va|G-}1hhMBqiuGbGh@K6s>spZbT@&a+`!KZ2P~U>tK_&60pGr6{!FJl*`@5Js z@&nveegtuVk9*!BjwQV(!Qfa98;e#Nl$sOKHJQ^&jlqe22aD5}WA+T6Rc&MNW)+*N)Aae$A>_x;uL*S*Fz=BIeW zuCPrV5b%R_SFs*$Fvx`eux{<5#Os%g%hI&ABwk^NM@` zXO#~@=-?xq&FRGZ8e0_avAy#e+t?oKxMF=>@QNz24(@P|otLnOE^K4nRkNL;zLeio zo-77=$4}bamu1~oebuRT{7s5}J*j-RyoxAt+|$P@5ac@jhht|9;64FyC! z=C_`EU{|2Ea`g}VVZBPz`fC9QixKZ}xoyp{gn zLF5iFZ{!7dtGoz80UzN_zwX$;C1BV&+{gCjeL+aG{9^rEtV?Vec{Z?q@aleloQ`2p@KKZ4M~)5&w^t*J@pnP8gMy|xCwSWg%09D`R> ziS>xf62EH)U1-Ppw`My-eNQ$ODz}Kig5)3U)8?L)b!L$t;I8r`2nBrHe0RaaE-K&G zffu3Zhjn_felj>jmPhjQ+3vaiyoWyY$GW;^J40(E)ALy>@wq_Xna8yGH|9BRON{lHgFz?!ml5tIiQhGaF0^OQAJ0#Q`cmFg ziPaiwl83NQoBK%OL4JU{%8wuv@O1Oud0lPH(cwNm&jQdi2e_;J2qFU?;qJbs7RB3oO-;Rk zX6`NL&K|#wrq_5wBR#j>d5-nBToef6n9uO{#}q@JLeO8(cOTF^&5K^w3LMa0d|)_F z)R+D~i%R@8U&R?W?Rm;Sh~q&%VV+bz1)+nF%#->3$@`kxn4@!iXnXyd+Sq>eI?R17 zf+P5$r0-H7?rR}W>Q-}OM;yCF~P3QFigV@q_J z?F{uL?o<}UVBn0KHut56Fn8n!xU2jKA_E_XyYrU9hTJ3GQV9E%<@=9IAtxc@FX%fY zh<{mhxK_}I_S`>&c~5-{W(SqH|ExLVrpuKZjwsXF* z?DdHreix4B^ZZH#NAN?L749n`Pwe7SbfIx6+|E#6y6>lQix~8sant6$_%P;<`~Y{A zA3bIBZ&uj0{$vb0!iQ_{PFq+eQdMQ`v>%V z(6*0$9c_G_$jbLrw;g^iUu+*M^Uw+TVpmW?CmNfN3g?0P7R(MR?;-}P&bVpML*vmL z5Ap@`pz;D|)JN2de9x4lBu5E=N$c?PeONz~!z0uFE3sZaE|3;gBe`^K9gm$6S@ z<#^$}Byqbo(1Z5cbIy~i_u*HCQ7-0-{A|Hdp6`_*|{4h3HPkT@9u{#v=2hN4E3e+4wYw$!L&1O+T43jV(!Qf za98;eLedpeT=gjSx-M4-3x#nx1>{F0s@9|LO&j_cAW{t2_xp2Oo#O{c^Iggk1!G|4YiMU-PBRe=6h@j34#i z&4qtfbhviVhxS2em!ZCNzfa}({>K?NZT`KdF@NL<_^Uh#LI+oufB5n-6mkjssCfwc z*=ug1-^$D6I0$*!12|i^ka=i|9%uIybfUfX^zb;KzFW->DsLwS9cSFM=b`!xISyo8 z%!A68ATscA=3(7Cw6KfdAJ`l6z%f2<`Y)IBf5>NSGlG?4WXs7%V&Erp>+jZ<6maF1V}w2qFU?&D~r_1MKcQwA2CiKK{C& zyYwUaP5&p)!zhBQ;2IaVl6lCAp79Q;KquMS*XY;yFS#Cs zyo8Xy*dp_g7d@^ObfSF}+GVIO9S>CE`BuppH|=>CJcs82`GR>+`4WTPjG7oLh;~GIH+S|_!j|b|z)$E`W=cTSQZrbzE zT;h0;FPI0FFG1+wqvv7WOV7p3+`g<>P+SujP5@MsN*+QvYq0c~}eis=em>KSU=QJK=VQ`qFue z%B^BBbjD449@;P9c|g8k9#p;rk%6mk9^7~1r~~XL&4c@nobEUOI-ZA0$Sa5=>c88_ zJj{z8*A6<-Uiy#lc%Z&C4^(0v7M*d^o`>QKIUeK-=0W945IVT}=7Am(Kp#rjPnrkn z7xjI=jo0%$tVM9eI4Ex`^Ux3ZVpmW?CmOq=+iYj3FUYE4m-8t$2`$_X4@6f5=uET!IZJvkukXH~#)PJ{=c~}rVt{rruz4GGlc%Z&p z%?>JYU%TXtoAx}Enj8=E1@oZtB?ui{^*jXkMG+SW*!$+e>gTNKiGFKu;Cbjra0O44 zMVW_T$QQeU5<1biCc4dbhWgU)7gXYYD(Cn~dmg$k;dwy5U>;Py1fheEcOEFeHIpd~150#g3JjfT! zgUXj6ba3^~gXaPP`-$@qTp;vcErsW$!kc*>h7nxB6XhLb9;QSO+EGF$w)>%7hWgSx zPNJQoPqPn-wOOV;RDc?-|OV#rGf`HMTs zJS>SG*9tn(zW9ppc%Z&?98iht!?H7O+VimRN{$Elf_YH+5`+#udLFEob@2dEgu>o8 z4|cx^FIyX5@Kb*)&&yQEPe$?=canK2h(6Z}y3wBf&v0I-?^d&eO1#82?TnlDyo@9s zp}sT^RAL_b&bVpML-RE} z56BnHgUXj6^hxtzK1Xs7hjCs{Iv#?45$`P(-@)@x3V8vcx15%FsE8id2s+VTd~J9< zP+z)_qH?PkEI8w)JrDWUaXiQu%!A68AhM0-!8sga&x2kwlm;4)^G=?JZUk4sH7-t- zc~}eij`vXoI?>n`-DW#OeQ6%3#5@e0anqiM=IePLkS~}Al`lc)V?OHrF}#!wZB)X} zcO1Z8KdFHI;=7o8CFG;suB&eo?iGpOHGnR(=i6caQ(t<2fXadx)SYqD=AL~6$AkO; zcaB7Am@*MA@3Ur~dB|6P^ zhWgTbdsJfGvw<^i+T54kDEThqg1gF(AaoyhbN-I=-rkt|*xr5EKrn()%=aU|Th99- zC)wjK&Jg}((cxM_AKLS83iF=&7R(MR>2p^4sX61O%|H8Qjt6-H{why`xWGr}z2O<> zy*T&XS9ubI9>qU={|*YdguOcNTk{b1D_FCEe))^!I0$*!12|hHnTLw#aduBZ zC))FG4UYrryVdNV67TITIOC>0581cLaUkPj9#p;rp@WZe9JsHKjn5|$`~!R6b+`Op zIsZp+1V5B_7w+AVCw2uTbfK{+I?Z;5`cnQ=SrCJPGj7`48_Ucc`2p@KKZ3}7+=J%> z&Ua)FYY1SOA^0p1zl**|96=0)VE-EP`O16YRh=chBo$vGSh!sVT6=X}+K5p%cMXaE*(5$~<&KzTUkI+5AojH8{ZGv{p^{*IN1;JJXAtnKPzP%Dset)IOC>057Y1Ec#toc z2bC{D=#%Eb^SZ@2uYK1A%tP?HMfj&Z);LQa<$35ua0O44Gcpf@kS}%xC3K>3Rdk!} z4E3dXpc3w=s4r1JrA{yay-Zv%!A68AoMXG^&D-S*PaUm z>?h8H=K_I#i=XCs$cDUt&|B`5dB}?%*9bb%J__wJ)R(RcRO0uCk~41F^Dy`r&ja!W z^Puu22pxR%@nFAK2Zdb1-Zu|+Kl{Xle(lfjJTyaI_5jXSMdqO`dYs);(24fO$HU`+ z`ffElsKj-;>x`TBJk&qI@gQF?4=P`R(7`8i9-J2|V87u!Z1c~<>SuW#@*yuE^p?A1 z9*UyJHG)pGXS?A%P+yt{DlrcgXWX>sVI=V&Uoa0UUxLuV)i)1xesW(lg8ig<;C}vj z7=DiDp&h{$JW<|X=Ajev#jc=)PBb<@8O{UsrFozd^RVWOoAx|3KE?4MUoa0UUxLuV zHF6#{aXbX`5OF-@S9u$88>Pz!LCFWt?88_{D$bN?7 zLB3!fRK5hEPnrkwIfZ*TjDH`SbUXz8?89N)ulxm`hfV}n@I<*==Aj$%#jc=)PBgYf zx7p56U%FqSa;q5hopIBihvsK_9*{4X2bC{DWE;(cb2yB7ZZr?h;V|yE@I{`7QpigP z`HMX=4;9hlT0tk;^PdZk2kJ}nKqcm3!5KI0dB}dA<3YY)9#p;rq5I|m@6kaUm9X>i zhrK=oVBh=_bMHoQ)MHS6PPlhNo|Xx8p|K%4&31WrH<_xUezJjf4lSNRb{2A%=; zeY0jY&i%6oXTm?2!G4Q(Xy?4e9-e=)Ut`|+kPA?G%kzbIPU3crpa<=1ptq^FU68kOQSW^UF+NtcO*O>EC$V0nZSAT$T zUX*xU1L#2e^jE^XroJ~ZJE+8IaM>9*ZO(6JTouR%bmwy;^cfm(01obDsJ-$Af$TXO#~@=-?A@p4)o>4514p>@42O-aS#ne)${BeI`K(Jha)m`a^{C65@3%#yX_E_Ra7-LVZs(?Nr`Z_OCeO zrp>u}F~@^^0B4mCL1f?)s*81`R*jcFM^gEZVo-F(O`HGfx0pZj1pHN=1d)Mjz@OH; z-*<3(Wp?{n`d*t1VQ2BT?F(nzO~fkuN{_iWLO!99r}j|c-jMiR6X-&F`P*UMQ(yYK zEh_6`u(rw4s%96fV0YnATsa?IM3|Zaqxb7 z=g!$b>wfK>FTeL4RQCGbkQ~Er>$}Xo7V;4y{^F6sy(aOyR?vm^!gs^`roMEaLgm?F zu;h%JHuv23I3DB&xU2jKA_Jd*`|R9~o#xaIO;lpPmEU5g?+Ibo{T_4fMR3!;slFhb zS3`c533Q;bCA!RZhWgTdIFf?2pxO^&U1SY?m95L$9#d( z{&RL8uyP!B7H`L1-yp(%@O|c94*39?w|tavFH8Kc5pk2xKnw5G3Yzvrp~u}-AZ`gul1Spa>yfe=BfRwaBd-9 z$7ZZU+UI{9o>!1muD|Ts>w6P&48K!9 zW$yDKA0gr|o+RAoC4Scmy3k(yS(xwCm$*~;5HV;tvKcRA$7>t~8)8@YP zbLNix0C$xiL1f@5+~Yhi-ev9_VP}1IMGoPw`ZMNT3AqRffAM7DU6#0AE9e=wUmoT; z^`$(g@*FW(aK=rW_fXUWwpl zIX4?m5zfmYKg$F<(75o6kTdnA&#$P&eQeJeH*L=IS8zPY2XLNp^ng#m`K;O5SobMp zSJ-yCeh>ja?VmH}LdXM%yya7cb57!Qji3YVz0fX0ed#`h${k`*cE(Mc^Xiq%8TkOt zDj$N#z$f5LAEMCjIO-D=?6>lHY*#q_ROiV9>{l;m-b*1Dpz@X%2=9i(?HWN3+N)QE zc};z9YIab0Z!uVQ#!Z`d`D%^_c>&%kFM`OxC*Zwf@7w{t=$YT;p^Qt|S==pq^QEKP z?l$fO`{6H``zV6rxPw%lCfr9MPs;?l(6}l(&31meT?^Ogh-Y`}8#&5Ap-tRel7Kfse&~&;FebcF%QFaVPtT-}5V1G50|PNAN@W zOyNEVd16;kLKhl4qSI_=s4uOPNF_c`$vJ+~=HC7lb4PxFyULFsbc;KmWA@MPMz;9w zQw;CW&Q5X?A9yv-7q4dCwUCSK@fXh)-t!W-YXv=M&tDtnIrXLcLMnHNLBkn0ZQj{m zb3Dik@K$*dL;!VmN_FIz**%(5Eu9aocX-4 zBiJGTVZX&$>=lopz4Rh{Aa8s^>>WhT)YRJzrfeth_MVHymP+#IqB{+|qant79 z_!DzRK7g~zhahxt1n0fGckI%jvESv)cKXc0Bw)YvTjpI3xv)XR|1TEaC5hWLgPw8w zpToSSzQmbIy3eDZnlofJ*l;`xV11_h! z^eaA)xzvBcoGK5pIbC$c?tl~YZ4{5Yzvbx2Uza%{K5c)DVRYSuoZ3gSKkdg?UlKd$ zL0r(4Il}zS+w}B0PA%!z7A~!yGNFhTWz4Bm<8AsoaQb=J;+xu3LLb$W{0tl& z3r902#HW4Tz%V*GA*Z2m*M5BUp4dST;({*XbgKCyGndmq`n7}$e6Ku&Ini@8`uWBC z_&Ni9+#3J?oNz&pW|lc2KD1MLoMA-Q&g<#Mh&ryDdGQxv7B-6=^dK(iiaI~#q+jkI zmuE(4ZpZ0S@Vw8|mS^Q}~zIsvYpa*e57jZh>bKI4r z-;!{F@8yTtoL=z+<^+APi(A$l9sTPwC&Z`yBP`39^D z@#((D8%A`^OTuYYxNASYdRy$E2XR4H#@wKrzucm4j5s*Aci$eoS?8YDJK`t1z?`~Q zGPmNRY;G3_H|X`nG^uUi=&B#b+z_wsdxBv`*T5v)MluiDkFVYnJLo}N(3LqRxRq=aiX2d6Adf67AE0U5P#Z_ zubve<=s{f2MaLt(TH@waUixJp!(0kO$*X^~IekPpL7y*%No{3EM>ofu5TEXQl3^5F z3w2{e9rp_r@fTq>Zk`r9=s{f26~(D6{Tjjr4%`34oN!=$tIvxa^dK(iB2M(SjGIpj(r+YO;5+}%HmAP`C+LG++_LHD z$eqBP5TEvQ6T^tEg-JNIj%R<`kFVYkJLo}N&=r+WP3cz`F0Ehjao4OfryI&(gJ-^S z3ss@d7sI5s6-P(uMAn7)bl<#TMAyP3oVvnY`|;J6#SVH97jzLPb6d48pH`$_U$~5Y zKaM%!zUuO;KAEL`&^NY=S?N1EY9}!##HZcd)G(rJUlL9O;jaDYdj7l{1ow+;Vh25l z3%ZDt`L%Byr@r*72^aWo{3~<9^TbEq4`#b+!5^n>y?(2@H{LjI&({5t^_#!5%^UtY@3iBt%jY}T zUpdy^kM=_?=YPMsc{$W^54C@-@8@`^ey84N`)zHvw>R=%J~dfBz+dtG_Bi>=kByc0 zr3>wT@P~5ktDB1l{WmIyS0~G#;>XgBXX*MIgVlleyR>3nE&aa4bstl!{$$@oXb zd$`+Ie-)m!_I>(Z?!$KSkm@;p~%eX@=8EL^d<<74#OWc}9e zW9Lz6m%Y6%&R^T-pT#@!_QE#1eO-0e=|&FD=*P?>Lw59ZyH$x0{>a`Yk4NE+5Os>B0@{<8}U7llv9FIXNHO zpNyxg{({NlxYJj;xgDpwKke=5&-l-GD`(hxOJA|KTNn9xwJuMlKP`QO_u27Ajng~J z&%b#4&FSb|mw8s6Z};!W_sP0(6fUT}llQ|eZn=D8_P4r^bq@D)nLmfi^0{2b_18Z= znf*q7M;H6g3%xzUZ7-LL`?y@af!}_kaSnC=%9{?a?n8~o?caG%GA_;2;^kTP0y}@* zahLyHxD5Sv?N@SpPu`mw{vjF1?r)Oma^w4JZ?Alx^)>Ed$Gv=4-X8tb)<3$pJrC1Q z^K*1{tensN%0J=z@%EMW`Q5euzq;N10_z%lF`mBVMm&ChEgsDW*zuH4v$qjPXNu>u zbh*91{29)dh4bt@LBGa9JD=)5x3^(;*vqV)--qgd`X07!_*;4`>sdX(`wQRR5m^e{@Ue=tbcg8#x2ez<8ipgJybv0UrzqKqJPpR^J#;?s@L@&uN!nr zZFlG8{`p(JKkHvR%g>?pM?b%X^X+_J{URGroHy08xvX3oFON1Fcl7Ca_e)WJ)_&sW3j5YY{y4iQPwt2QDD$sRW?z}%d9D0D z*?9!xp{$hs6jciKAs*8Z1!%rW;e|M3tvzWx{e9EXd^ z@+z5C|;V%)Wx@bR?t%XBzl9F+N|@HmUd z*t!-A_BQO3mP=dX>F6%m+zWB$CXtw>&8usL46 zqx^o|_;Wws9GAgMHka4KyV&!Tf7RsiOCRKM`ls9dTpe+@>wk!MAF%Q|JFe_oc^)e7 z=CXMl$Fp+7!xL9j{Hu4i=Rco|H?L9tlD0Qbw>c#3-&wQsq%dRqYdpl>j`H6)>CiZL zUL0?nsPWO>`;|Q(75V#f?Eh<(?Q8vdM!P5HN8=g(erd&B88ENno$R>QK4s^HJAPUI zUS+}gdkohO+x7d|{?Xp}1CP^sk3DbLAGd6N@6h^}ubHejZXAVM{dMOrZd@DLExuxM z+~tnFzw;;md}5rHtKyx<*WPOTMgNV;(Z6xO!n5P`AG|1De$-AmwDXu7cVkPu_}qR` z+qnb^Y;`?m0Ps+;QtKV%^NDKiKgt*LZvJD7)R&iS6ba*{=F{F4x|{WxE(L{+@V#;XkS@Ie(8I zWw-h%j-$OL**p$kduVZXPu|?|St)O>UzGmC-9G(s`?%i7fA^xzaa@sgDWm-NzHY}c zUE16@QU2Zb;=kJdNAI%7ckM^tJ-p|$h2tmZZ_QbE!Hwr|Z?8N#;`mNDQ00EMpQe0o zVw9WChuOX`Hu3J{-S@Kp#V6SF?Z(sDZO4uM{U6x_;KzqIA21%u z={Isb{RjHvf}L9~-jO-w<@;HycMxuO^z(81M{PH*Jv@5L^8KYz<7~FQ@eZ5Q{3j+K z&r##FZfWOPce_3RQT^h!cW-FN>Gm7s{QC>XaC`6OljpH}nZLg~4z>#;ey_gu$iu4> z{ueHG;`u0#Q~My7YxhbvZa-(w55`Gaj`IF-*Pg@e^%?*E#+w~INe7N;pSul@)3}E} zj+kyD%{o(lzoU2h+an!quw&(hhvu*F{ljzK*&xi=yXSw!@r?SD^I)-hc=9xMU>g`_ zpSj6-D2k3RaR1`m-&WV?dXu?tfMLA5FY9-Y8~#R>#=Q=Yo{hrKy`HZd?Ul*bk0?Kd z|K41jqf<9GUQ`^p4{R?QH;i$;I8?bbfO$@51_AXa;J zd>CeUjz2$gSK09wZ@;{YxLRc{OkD zw}W4|T#4O~4@Gg_>04FJI`G|?sn;FJMQ5rwqDmB+tWAY zacVd7kC*=}x3_+3?=OFjw--Kdx5IDTvY+F)v&VBeeS)pS^)qn37r@;=|E5EW$Mv_- zc79}!H~%gByx#hCym{DYoYHqDbJ?hW-2I)df1LhDn!Zs1WJhXW0+b460ilg}Pc>OA! zboEbv(VzFdH%~tQLf7&q(~S?~{9h>t&zn52^+))5A8vh}DLam(PQ3X%+;O=6mcL@_ z&uz2gbnQ3VZoPPN{w6i?%3|2y&o zaklQaIla?;o}Ws@diMP{+w-^jYnwC1pa03^`GMWI%=`U}_aCOp;>eC4ZgcPF_W5Nl zSFf5J|LAR-i#I3V7dCy6`?sIyj|Xx6t;^=TKfdgM%c5TH!|I@$ow{LQoaktV- z;&B{z`2VGH#AMz5emcDW*7z1)81H!4D9+rM|NrE(k?zB_zqE7m^;xBdMR& z-%mbn>d%>co*X=Ca(_3TQOnNP!hM;`C_kA`<>tx8amOwE&cCjB@3xc2b^W;8wTd0r ze9g~m?OumAjyvvVw>$T@B1_T~xxxR!R=$K_y$ zpPL&`Zc9A7+R$$|+;5ND{b<-ul-ZJ`GNgL<=R6IufL7PbN82a^7!?cc=M0`?PLAN8}|Qi zFRRxaT3!`?X3typ%ZKJ~@m03J&GPHN{?OvUxYgJAkMrD_hZbkIZ=dfl9?G>p@wnN) zOO}u5f2igB-8VVz#|{toUdBKE(uZvSD_^j;UERy~^v~0D$?qTim;dOWckDmhW&K3f z(LRaGwHw>I3ODoXh>D|g|H=BI`Xz18{m?%D)xTlKx$t||(fk9KD}Us&|0i1?#?9Y` z{Z(&k`^EmGW#QfF&SUlMejRb+EZv%Ub^qi)ALNer`)?d&w+}yT^IH0`z3s-6pSI_z z{X2WxwRg8`^85nd8;tM&#rFr(_Yt3JI+?=ysY}0seE%?ZW}m>{M|>k`c){t z3w$@8$eeB}4S&4TC10m1^uaD}*>!Z3<$Y(wr~TZ*Frx34Pr_++gXf^|-w`|LL0r&9 zoP6Ia-<5s?;R1izMdp-~hONsl`vz5^4|Z|OfumzV)&)d-+RrTwBl<4zB%FrMd*<4o zuJ^Tl-TNz%|N-Rz}Qg+AEDEpx&J_RW{_`4{n_ zoywC9Bl<4zB%Jc%Py6xK#SVH97j$KgFz2V~>2=3lPWttQOKY#3N1w`^PL#o3`No?D zoS@Ge!-U3?qhm$Z8Ag1%>#YnUI!7hpRNi3S;(C>J6~zvE5Epb2r_(%~O46?;T*@C| ze~k;6)6GP{pKo&E*;Iu-tt(Ew=IH3Zobw6sX&(i{h|W<-I4y`j?MK&JXS1%V*g+5C zg03h|HR(4HE(7tGeY%}bNA2e04*GNqaq3Hsj;#E>0^-v?wirfqj!MF*`HIQ+QQdva zX;JK;2XR3cou5vdUVnaCl72Pef_{x>*yktsg+8q-PQByknEp@Jh4{3OTN_4nj!MF5 zCF1Wy;I}5@x5W;65EpdO_3m`j$-OV=NWY$NS&_f<7&VwvUIu#0wl@T)bm+tQam${g zW4^_l5TEvQieW_Os3e^F!d?5(_1rm}Ppe`FJ%|gs=(wA{%Ngr9^`u|znal;g8~?`J zxPQ9r_}kx*_CX))Vwb`N_Kp8yPKXcfRBknl=p2=VQ&#+GKfd}<;((qh*@iCWblN&j zQ{sOhT(X~J?%8MC`Ly$+?+;QD`g}1=YAZTAmS4r35TEXQ8^egsQAs#Wi$Cp0*K6mo zuDsYm58{HZ;QVBMadD5kqV%f^m+4QjzvjO)CtUB&f6oa|rg5Q9#}KDpb#$z~nmHjp z?c=tF5uKxwaGDo?+K;X;&9knu*g+5Cf-X8gnbY_>PF3kQ5-#wae=c)6K^h*L|MF9* z3VpDPTP`{}reDjP5TEvQJHv?1QAs$hM11b2{Zf5F?4Sp6L09ICsj2g3XQ~JHS7+wt zX7^1US-8Ob3z~M%?6({CpHrRPcW{4Y?}44?%<)KW9xlpwZQ;508J@51l6|~Bf9>^r z{ueH8+#7B89R2gJW4_R(`xgycI=3a^+utCr;@`8bRk4E}#D)2$PP#X9fkpo^}P+dRMT6s2G3KbT8pmHo}XkhgLEzxL()`wsN!7~<5cj*hiAFek*P zecaJ7qH|jkPV?eV`_c9GgIQNu?4Sp6L08m$d{z2&g$sQ5U&Nen-}R-=?SlI*=!0F{ za?#N-dLwf}eA>^Q3?n*6CE?T%f7*|)z94qcgSeoJIBoNspBANG<;Bbez89J{r*m(~ zoS+YOam%)&qwr?tg!r_dI~zuHj!MF5`AzIk`|;JAVh25l3%UYM<`*9Kde@eIYr+M- zhcB@?J>g%N6ZF9@Zn^5{sJw-BAwKQrE`|}Eqmpo16YkoNu6J(3pTDn&9rPeB=%VwJ z?{lkF={NsUJD(O`#@jcS!JhN96NCFx=+iO8sSh0;^|vx7#HW4S)i9!SR1!`j;jaDY zdim*me(H-I^dK(iin>1?O258v$$gdmO}&CS;XHo&jkokcg#06bZ zoJP{G_*&-Del+K2<#oJ`=Ui95nV)k(pN=6;z2N9*U&x#gpZ0NvVMOPsB%F%kPy5mJ z#mBI&oY+AR;({*XgkVeth+k*g+5Cg0A2`-Sd38BK`7h<^tcPH}H1wVU%gCUwHg$X&>~#E^b+O zbPPMp3Grz^CBukvDha1W@u&Ux>NT;09>fJ*#L4%$R9*VDgiHRhoS!Riw2!;T=9v@p z`C^#V)^c>@FJexJPxrmMVMIBVgi~AA|IvPQeJHw?#14887jy-mx7=<0bNH6@%fE@a z;CXB5&Ag5KbUcrRJ{?1xde_lWelK%EeA>r73?s^^B%D@-yY{2&C3$Y!5j*HXT+kK8 zsVn{3!eyb(`P6-joligfBJHF6fFnj}N3@{;kXf{Yr1+ZJeLr7y5Jzaq2nY0^8>MnG@neJC*k`j3}p)aLS86 z?MK(U;3#&`gSen8ic?PdHH8bFw|179lly!b`g9C&>Lo|V$_JPe;?q9vZ5UBbCE-*S zf7*|(cjWnSQS9)18F4{Z6sMB(%l|iX!SmMA+j$%J<9HqmeL99X^_ruj|3T)2__UAv z7)F#+NjNQtKkY}?d-5E)Dt6F=xS%VFQ%(A{g$tgycHd#=6Q0LHpN=6;eaX?0{Sb3P zeA>r-4I|2_B%GQn>`(i#>hj!nQS6`xaY0uUrzPoEd?$0k^VZ6{cpKL{JdcGwD~1>w z9Y@FXhglcm(=N(}5#>}8PAkG)`_c8HJhyF&9rPeB=!)Xhk$xTF0^e&FGABG=zQf*A zA4>b64|Z|Oo};7o5$1&Ww4WKnh;k|kr-5+Seth*+v4bAO1znk}JYSxfpQZlp=XO2m zKmBgzgXgE!4sYXpj_0e;>5FAjTUPkMX6d8M3vr^I%KI5slv_!7<;0)%qw5`c-aC>w zpa*e5S5#hQ#s7+M!SmDJdu&d4z6yOhhB)`vO5#uZ(e<7@ z7cPh$^dK(iisCda{mK_H7d$_$z1QZ1=c~}CV~A6qcXaeV&YTdR_OZh-qMS;?sV4rk zAFD3UVJl(>J%|gsqBzYkpeu?~L;6+U&s^~QwEh9!#(fl?uTF_R9YdV@vZJH;N!Eq< zw2w0lBg&~HoH`rCRh8$kEwO{1aa__K#c5gg_k_#%`RNC3PI$fweOgzX`kJGo`YD-z zr=5K5G>j;xl5pw?_o!GF)n+W3&o3C~x@`l14gXdgK` z7C+6L5TEW=F^njul5m<5f7*|(x8*tPK;{Q}5EpbsaT-a#fpEd|)9go>ll#0F`g9C& z>IFwf`!mc5@o68s3?s^^B%F%kPy5mJRe9c<6FWRFMqJPp#i=0u>cR!jPn#cQPB@R_ z`6~437~<3`j*ivOGAG2RecazLqMS;?sVe@oA6*~H^Xih=K@Z}Bt|(3w={FKCcwUkpeu^gK>FoB&0O%DwDcL96P}|&pN=6;JttgX+x!x9LVReaa<5@TIhBM{Ui@i4 zy1s_z^ao?W1ZK zQBEb{R2F~QkFJ;hgLM_f4tfw5bVYG0Nx%H(m9rTN5tWIs7tnI$9cT{P7zcMOEm7UF=f0z`pT6%n9+Koyv0zqX#AA zlofy4kFKvhlh;8RN*vHLCEL&yb$*&cykB81@Lm0?oloyP{+55Deb5KHxMk7NvHT6@ zg!r_da}A>hC*(9O{ikrcel6hw-z#5ZPIwP$@!8Ltp?%N?ySQc5 z(XsYT=7jjPAG+2ZOvq_o{AoYFdRgqC2XR4H)cL6@{c>w|K23j}w}Y26&43So?A+sN zT&?GJtQHg%%gbRE(E@n=6F8s9u2+`t^j%^ox%U-XkA<%RWCn{%NnjfX0PBUksDl z^1=l+t?x1?#D{h&A7~goA|a=O_|txT^{m)I58{HZsQZGv^ecaxxxja=$J@Bx-Skz@ z4gP)u`d}BgEIT^7-(yaQPy3;Jr$;8_R1tsLkFP#0cF=>kpeyRWpe+4XgbRH4zQdew zKYmR9fj^^t&cUH*L*cNr9+=DhDmKrM@R05%n9-7zI5;OsDzwaKVW~_kFVYkJLo}N&=qxG z(3E~H;R4?)-?us4>zxm{0qui6*u^bZ937<}u`a}?{m{MBqZ4xK3U}>C*XN(k*Slr0 zgC4{MT~YT1E7C9b13RClf5_YTT;-MXum3TP3w=6J_nr9>fJ*QP;b9>DLu5@ZG-8PE(=} zc5%yPM@R88)`j@AAG#NRQbJChm~pkl4tmCMNqf}wZdvwsgbU(byNo&EdY8ZS5pSb? z&XiX+yU!8E z`Zfy4**|i0EDo3x;?w4IFaG3&oTkK|_M_`d^7;Hg<_FIa5Epb2C*SYEBk9)?F7r3y z?@e0yIdj72bYDN|+fSi!p-;yUr(SS$w13W=5TEuz_u@}U$f+p)v>#tRCw9<-xS%Uo zS7cjh-RA`b_`jUFz<1#nyp8*(S6=j@;Ccsru!~z(FphLsy_`8AKJAC@#h;pxQ&s$F zKfZcN?4Sp6L09m1c&D#lZ?Yo&7K96YFI~Z$%rYCnPxsWX1;5`xAME0mbw|hW7t9Iq zX+Lx?enCP`i{elF@zrZ$2R(=jx`@;1r*2!9Pj%_n6E5&Qx{^8JJpRPO8}3N^pbvI& z%a)^~a3ym>eA>@H8b(h`$Z7cs_NV>$>Pun=J%|gsGG^RUr?=6g&fv%Wysjnvt5?~_ zU;S#E*Lgob`)YCko$M|C|ErFk%2linacWQhWMXb4V2_; z9>fJ*QNO%wF7Dp>d(l7sI5syl{a{Ysj1sAKIz>XT#{(2{{$S zpZ4RcXT=VB5EpbsW_TEQ6n8t-ZUksDl%8riiFPRhK(|zlP z(Q^}Ws)#@B$5)>gJLo}N&=tk0EdBD=+WA!aHE#zW(wPDObm|K)rg5Rq7sI5s1xLr= z8s>!fbl-n5jFu8|s*6AE$5)>hJLo}N&=qyuEl9tHaDngkZ$>J71j9>fJ*#OXBC(Y@X^rQblfz;||Jb7~&< z$p_Lt=!0F{a>db6`Zeo9eA*9vR`>jboVvnY`|;J6#SVH97jzLPx;bz;tw_JBaDngo z?`%&0{K_u`uOdPp?BbSvM@Q{9%n9*nKlEAM3lnl02zTvA*IVD^`+_yGgC4{MT~X(! zzVurWF7Vy^y?uVV@U6@V`d}Bg%nBFSFa4G|AwININuSldC?Thu_|txT^^wE@J%|gs zqRvlQ@n84@bAj*jA9)+UzwEosEpAQwpbvI&%V|ePXT+QkpY}ta)x9_&r;_;7eth+U z*g+5Cg086JZd&>^g$sOl{$z8y?vAIKzs#PRf#HanxXLZeloND4v z`|;H)Vh25l3%ZDt@BPDh`2Vw=PldnmHm-LM$-N~wKS7@_hDmJ=j02-TFek)^W-95k zx|by6wDf!Sr~UZqb+LmU#06bZpKCUxUwP`J;5`iZu4Q-|_fKnAEb%Mlq7Qa)%VkGL z@sF$v@o7KwS=~z$a_Yp4t0i{OGmcBzqdwPMmi-;!f_T@i!<=wGe$CSdm(xDzgI(Nm z&CyZ)lgz)!@&y`wtS>qg@1BvPWAV?-3GwMp^jY1@6LOjof7*|)K9Ko=9>fJ*QJ-s$q~DTo zf$!z(GABOR%kYw$5c#~a$o`c~BesI3V zbrk!fN?h-{&h-WM(1C4re$7zd8=DAs@h5*oJ!@4dsTs+I@n{6*kZ>Xb=24+Sg=kU%Y4s1`~5y^ z-E&U(?EI1E`Td?}=XqeSv)B8z&sy)hxjDJ_+)xyI{-u`v@K`-h=Ni`RXEUx3L1paw zU2pr{@fZ6%%Y8w=)xHQTqd)L_R>fR)WJl&>eh0eD$l&d`=!-gjU*q@lNYG8d@4Jnt zH!fozoUg+7zu-96u;xuYGjdfGSJSg4#md0P0(+Spt$Qb*qt`phL)i*ywur-6lR}N!Sl38_{2IoNHL)w;6dIuq<}o-uAnG zkoBAUf_|%g5tdGW_ooSWK4-)aYd|-DH^b+A)Ek$v56&+ZU9Mq`&t|00C9(7N zw$H6=TA#Te=(E}nVd?b8_&j0ejEWf(CuVJF=C#k%Wz#=6!&-cx-^Y*sSg$1@A?g#p;_Cr`Y{ZT$=ZB*t{d>*MU{HW_3 zV0~WJjc@de<8AP{L;PbZ9N7mao6uKqoNHL)vl;1ger%oI_PJqg>ofNQeOCJ+ES>%s zpJ$DqF|#adH>W>uSY0Od`(Xa6*5^v`gBGQZx5MXh)EgJE56>PRZw)rt6860yYY>Fal8XQFBJcn3P<+A$(nV= zXTutw%}Ad+V(0B`pR3lh^>9DXXSE-~(&_VrX|pC}{}1%GGv@icp>_I_gSx7G>vN&_ zL5otyd*E{c>Wz!o2j|;Gmupz#uNnD%S$XWdz3p?``qpRe2l}k`Ls&ZfvHr~}pD}yV zoat;T7@5!Z89H^%L0$bo>vMznp;k+V_rm8o)Eif@56+itAp6;{#$PjelBf z@q-qnj`zdo3e+1Hu@BDYZzTKKu*P3AazEF_&fD8Q=WJ~2;eMdcYCnXf)1PoZPnuaa zy>vp^R5lfi%xC#box0?pE@!ayxvd-D)Y4)20DNu{|FR|MgOjy#oNHL)vl;1gXY9Pa z?Q``I>ofNQeOCJ+ES>&@KF^#neoEPFZF9QM(CI4yJZzpU~&}NCb|4V3zowv9BE+1y=;l7~X zYF~sM(Vyt~V_tc1OM^7aeB${d)WzNe3ozZf_!5_9 z9X|}eYfyJqGB{vAoG&hv{cTv|w;AboW9+=W?RVj(wjS;a`mOdwSUUX?zo$)}$u~;_ z1@lS2jV?1nzt?CMq`qw(>vv~2{)H!3e?0=fJH$to4em=uKb&lq<6OfUzs+dgcQjvl zv2}Xe@5arn-`p4UTkVUmF8U*WS4^(pn;C(E`J~@Qml+Xzxg^prTi5zsDZYf~>+Y{d z;dceCvjc*Zv;4%2zBK~Dd&<7{$p?*MTKFjAwml>g6s?J)kWCQDWk@ynkyZh^L_+5y) z<2v@k`7Y7r8g`=~Va6d4RK(8P+kSU$g@0!_Fa1{gBCL#lhWk45abD@{+3d`Y)TR4w z^qCRz)1*BARBvc~ZxVm97mgi00pFWge=HyMh54$j<@v<0#&Si~}e3sv#F8hsK>KZcE=K}E~d%@UID}2sFy|Hu-``~=L=yDCa zW{@zWd0sJJ#j*4Dw$E)Ntk2vJ^jYnPurB(epSR~tm@GGlgeuvuS$^aB+vqdqmqV*B zuG_Ma^}SB~QL1G4Bz&(!{c#2R;(W*fu$zE_DqS-SYaQ}DeC^~dw~Ax2f7i#(+uObujIs4_f6#ZeKf==K zkKNyMX3vPZ&V2U%rYet!^tM}7aZpr)?5#o zk=Nf{vGew}-wk7}-`p4UTkVUmboyico;9m<&eYlCOQ%oQ*M>$&UAFI9pMGC!n$t z@|4M0Kk+c1x{Ul@KKej?*Jjr59Px#c)bV-v z-PMhr{SaiaBlmSCwoY&R-Mo|aoBM)(t9=ocPJcqbX9pjL+?5^Kk@+mY zLtXGWJ|(3tvxW7!M*L8!WcUJnu0p+W1^eK9;m)$J4QsBq&B&iC8)E0}ZJ!HDY(3l$ z^jYnPuypzp`aHFCR@uyPGp4F%5azRdj&zxk**{In_tEk#t>5k4_($J3z6ie;i;ql& zBm3cGGx`gTa}8^rKg<|i|HaPR+kQ8eTEDq3=(pMzVd?ZU^m|s>^w~4#26vRq8#ia_ z)G}pz`t?X$pBb6`L#8n!JWKHV7Pqqgmy1uxqz^B_{|fXGSFu0NXU55XH*6+Im@)jN zPC;A~J8y6MpFiH#!+k>k)jkPJr$5&J@aN2_Ws}T(QDHjzi@L0RZ-35&K9lvyZ0Z}g zw!XJ@<70FJ1TVw)Ht{n{!oE1!h(3ekT*I2{Z!_}xds*zfz3qGb1nWEZ2YpxjBP^Z% zDBsJ=N+%?Yr!K{J>N6wN51rJv7Fpj*#2;FgI=%wmOHhAY#J)J6S0?-2up0ykGiD&D zj-9u+eeXg&+#mE^?T@fB`V;ydUXPSb<7ZZkfcY%HsmqLtznvNBJ4aZ*Te|TNwnW3L z@Oz>780AdBemGe-QT#Tnxo$BduUpz<=k0C3YbM!xxG(6p+81Hz^fSxvd8N~)#Xjgn zU8?V)J~K-H;7NV{DC>Kn_(RK5$Hnly5cS7J?2GfAqRTa`d44e?pI<6s=k0CZ+sm!* z+#mE^?T@f@`eUD8DuP#3)Gs3l6wGJ&Js5`me&>lV(VA(&>+m}Vb;mXAhx6^C%QdWd9x)?dpDm1?x3~Rnn_~UuzM$V~ zUxcM+`7PIf_D(@I7mUA6d!Zfc*`cIjfv)rTZR!{|t4RQTm6` zfZ}=!$6CL;y74bM0fIN-_cHM@OTvCQxe)yY$GL_z``wJ(?**}SdfV@&>DF)V3;M10 zMOZrh3H_cubMmA~4$tGzWk$(Qqg@A3R0t7iR+n^I1NJI{hgf(N*kVeQpvz;?`vye*m8w zP;XW;IA9-~ub3sz8-_Lhn$hfQ^VJ$VZ*TitGTYX}{Xn19ehBNLkM{W>_yBe|D}OPc z<+J$!w*F9XAg8W&N9%K*_#um>L?6QEu5R?~gJ=u-GN&}G@!5>@xiGd)Z~NRl$NJ3u zK%doq2ur6wq0f_pmkIxmpC3i1KBQxs4p$3)C(BOO=NjY()a4vd3)RU zF4V*QLEqK>2ur6w;r^akR#8?uyS!|wJZm$bwZBD|_`nYJ1>>yWE#3G>-#C5(zZZ&+ zOob!+;biR|;Whx(H7*6%{`g;u4GpTh49>W+)p59d2YmupzFzs<<~T^>7cZ~NW8m-UKCnZ5Lz(qEPkfHR_Fv*azo}s$^dq*4(#dM&7s97&~uo`<&U=*2DckpVfW{OQ%2dIegw` zQ^Cl5+~-i2{J2h}@0eu$?&!upb&4?j5`MRfk69A-!^tM}7aZpr*1R5KM&1XJ6I-XZ z{chOL`ptboztz47OQ)Za-{WUYoiUSLEywRrm;D(XLvg*l$=2@*@kJI*i8|qTIqHr} z*bnFP_m}-`So6B78F^h&6FYBj`<-)ut%v)9eye>EmQH^{zxi9Z*;FtxpS8cK%l@cN z)_O&|Sif7l@lTy148MZkE#hOg1pRQbQI2yBYxcJpxxYJN=k0C3>kqVkb6?PJwJ*Zb z>1UST^CnKNG#|pLD4QPKXvG$@^r`-5b6FqZ;dv^j*vFwr{K{HCey{|OLkaqc=h-Lc zGk=wRZ&-6(XvRVas$%Eu?Z+YiAk>5N@^Mi6C9I78Bp-+9%`~={rSJZ6h`6ke`0zY+ zQ|;r>(v7cKCkqai;&Esbf3qY}pO~#@-@!jw!qAW9RMd$Dy{`J`UV3d>qt% z2`i^R_W6GNj5%5FHgxm+6a1pPIl<>Kir+J$7xkUU>s$}>zd@e%0aRvL}e3$5Q z4Qs9!&B*J;s@QpZ+vm=MtvyyGLaS28 zZ{T+m>W+)p59ezRk>?k~n(wP-J=_=cTkVUmbov?kJ+o}$%(7YK z^MYR`UB<>RQkUhs)@R?g9DP6Tnqhq}5PxDTXCHnC-wRNGb~Y!6eQ~~1bh(DzAV`=o z13^jbyuIyv`(f61?hpE|_D5J5{S5wNfO)&mm^pQV`R&Hj%3|;Oq&%<0^x2=H5`AV@ z>wAOv14q(_U*LNK>W{0~7w4-Em;G*7b6sP`Jt1g`owv7ruQS3-^_}~JzN`HaRz`nhzngms$IYmWZF%aFzDN43El+*TEbDun_yb4MhhO1) z9qNy(*ca!^Yh=G0*7$D55(t`O=k0CZi;uGPaDUKuwLikj=nsDnz45mdfV@XM_a$S zFX*@07hz@elRo1Ab8-HE0wR6voeQqpI>-86E&jlf^x=2-UXA+WD)zyAU7C%@7@4i(}T9ZDVhu4w;XwJP)z7qL&y z7ab@2-mvDrPBU^})Wy!*+mA!$cv}zm3m*ryU&7MqPjKB{QM&u|;8wV)rE^mr0qW>~ zQlEa`Me$tgdwVxN(m#$X!uNLZlc{iIUs;p(AlI5`)B<>=5c*K!C;K%R4S3{#J=Ddd{Q&(Jeu{fcfdQ~9qw ztc!i*_RYx|Jz`|6`kb70a8)Y}Mt}B9b$Rx9pgqjld(nh46S6-{yASY%KwTf}6YJx= z8UG%5w4jGRFJFowT?F zI`+f5*q7N)Ba4zgRe)=QFI>BGfc0s0Osp~Ojxb_>)VYqeu|B$1v_7#uz0RqDN7wbx zr#h^s*GY@3p<_R+i+!2>v`qlU_fsvnl2xoPT)S#jd%PMZmb`sh@UJ!}hy79KIyS}n z$gE_2Vtsm@(*lp0dgxR0U+j8%owT?CI`+f5*q8BXL;%KpY67m0~&UI{y^--Q@`(k~1oznx4uJ55wi{ZOoN5@TDtQJ0>v_QvxSQq;;-|vdH8kO*= z4O}Kadq0&7w8#8@x8tNqdFH(APuJiQFN^h2v$FMx_31Uv2t2x>hdy<|cfC$p+yNc? zVO{LYJU@*{`F^(yTqAtp+AV{uPrQa%Y1j(kl?wZ#&UGw+FVr{ovp%st&YSVfz@uAw z=u-yk>2=cLJm}aD>tbKs{ktpR`m1N}r_37JKIOqD_Lo+}^5#l-9*A1|Tc22;X3q*d zYVM&=%72 z9AJH7eR`d<1CMU)p-(kfPp^{}S3<{rSQq;;K8*^%xKGvK7Q>fmz?v>l5qKY<=L-Z9Vjh6@%_{St_i+y?bfxkeVPTI*dKMSV@Irys(kAc>(lF;8+dd_4}I!{?|PlIcrkSB zhjp({^+uHCSn^=TDM%s#vB856QU>RiX7SRV@q zS)W*+Ug!M4qkDVkQ!&=l>!igQ=-3bIVqeCmwC{IC;M(B}*X~+Bdq1t(zWt6S$Ns2u z9V=sfw6AV`Vtsm@3j&Ys>!D9oSWmB`{gS?1y!+FXL0%_q$4PB^zY_yQ|tT zdq3su-SMb7FZwZKV>9amP`IY;i}mSsE($z)pocy!bgZipI`$LQ zg?Zys+V{I=l5qK@{0qHT6*YH4%XA_=(y(HL1AB=czoCo>tbKVr?CMT3|U`Y;5y+8lX;tD`!wO= zs_;6K{ZZ#SW@3Fbt!;f`eR`cs0*@Z*p-+WaPp^{}=R?PSSQq;;KBc|xn*mn|U$}Pd zuxy_`y2$#({-|>u%VT}Ctz&&+eR`cs1CJi=p-&Z9Pp^{}7emK>SQq;;K5ZL-@%>Z| zt_{AFob?yGKZj@g)Mwj$!~Mkm(rQ@VTurQxW$Rj>Sf6Gu3p{$Hhd$L}J-tp^Tm>Eb zVO{JieEliq_3;{T#f8=vu3folwomhltxxQaI@hr=)xsI)|K1w#QeX%~h zj(Lysu^#%=2H*8MY4Jkp&=2ckU!hOIznr*Ft>E%E&)!c(TV(I2ihYk)@1al2;JaQYEpCU7{je_f75WrhkjH)M1Xl-NxOUT))~7+3 zczx^_SDTRiQRh15!x!osGS(;7$9Xe01|B`pL!Sz;o?b`Cb)Vz?dFa>=>tbJ_Pr(Iw z+^2kSUGRl#7i?{P;_FW(v-bX*$+17`T*u;AA1xbMpIDz>=gPpN)*kv)g7x$|X>lQR z?1y!+uh6HI_YsQ0RlygoT~}m%%E!d66>n^BLiR_U>sS@*qhn+16YJCKToriqWDk9+ z#(H|4w73E~_QSf^SLjo4K_1^vRp8p;3)k)%VSNhUj0z^}pRYdH!iiC(6JxZ#lAwHf(!DvPxatRMp|FEcGalt{j^cP`@c3h z_D7xTxG>g7(I&Pp)~DAo_o_VAL!VmUyIv_VuSW=-3bIVqc+8 z!3BBTr*?3KqqFx@`51f5?{`=3^;&^BFZl5qKthra^*&g~-g!S|~X>kE`?1y!+uh6HI>+wQxdBxfLsc>6+%-6>cK4a$5=Dh4L zt%l{zRmA#Oys7nx^=a1JtMXhAeX7KIdY!bm1UmM^y4Y9fQ_A&t1-M%H!nGT>vp(_X zmUFk6)n;<+k2=?}Hr7YiX4WUxr`Iv}stbJ_Pbt^q zwctA7OSJY5+52hQ_4ajN_7~|KgQi#?nJuhOtWPgv?p1ldhdwoLZr9W6q{R);u^-mO zzCxc;uE(3eRlpanU9+S0iPz)59y{t1lVg9>xsGkIKFYVWeX%~h&OZZ>Ug)7ui{ZOo zCoOJ)j{UGM_7(b+ay{M#t_8ku?e?9lPrNP|x>MO;lVg9>xsJ zUhJVyUGQD6lNNVC$9`BB`wD$ZxgK8zu5f4TOa4yw_3`o&dmNe*oN&mVgJzravcI$% zmN!=bU#Mx^+WN%$IB&+A0*_wmp-&mCr`Jh~^Ppottc!hxKBZib7l3PqFI>B=)cVBh zr!St|J^cBO{ZZ#Smc;sKEwVnbKE2M(fk!X*(5G^&r`Jh~i=bmatc!hxKBZibmw?NR zv%Zik8E=nQ$H}-Z`%9}~d2`jVJ~~HOpIDz}&AoK5^w6gotf$w}aRJU>2_5@kUF<9L zDdl>+n)SjLuH7=h`o!y}HBPkO@7N!8u46;2kNi>AC)TIeG56BF+C!fjN80uDI%#no zbnJ(9u`lD(sFc^o8^Gn2Szowz;Y54Pe|N*je|@CMu|Miu$Cg+h#oO4vSf5_U+)KB( zhd#B!cfC$p+zcK2VO{Ji^eN?fyaikxeBs(nldMm?&OH30@vSDu{-|>uJ7RrQjkZ3q zKD~~)m+rM5`qT;E^*U+sV(8cp>tbJ_Pbt^q9eiBj3)jw@Y<=Q=_G3!VDls|sN1f}K z2VbbKA7g!DeVjL=xtH$s9{QAz_4GPvaTn@fKdg&=g+8TRkLO|iO88Ruu>E{X?Jm|Q zUKh-qXs-*{Us?^zn=6X-v2d*QiS=pL+)MXH4}B`edU~C-I0GH~VO{Ji^eN?fya-%7 ze5ssdub;Z6Wbdc@FR||jv%j<&mN!=!>!ZEc`o#J)duQO$n?3ZY3hU{0(&BRH*bnPs zU!hMa*W;Do%BNaixOVk4d(7vjTmN<7&L+qHsB<0b;(csqePVrjox1{$-s+)G_1oI@ z^g3yA4Rq{>b+NC|r>$fA@U&eoGGeqt10~j`dNvz3q$j>2>}U zc=Ub`eOl;PS0i-nC#nnc=Kg}T`!k!7FPLF{Y1!SrK3ZI1kNG;?8+SbTzUhVi>Aqaz z#j!prcEIBwn>TAM3_SXG4}EHf@7>kXd9UrO6*~6Ay4aWTDfo7mc-?m~xH|a4^EB;h zed6l{hacY-d>S~o|B3xk=s0%8`l#K}`o#M5GIs|aeb7Una!~ z>2=IK(H%YXsTS+$b<*N0=-3bIVqeCmwEHt_z-4x`zI1+I?-MK8-5&Gxf)N)S`i?m- z`%9}~d2@}iJ_^QJpIDz}%{|c{_t2-NQoEjBCoQgrj{UGM_GNrZyFarLTqAtp+AWpV zC;r^hck%b(Tj=bMI@hr^)zI3@Kk1=QZSY;MlNK+8j{UGM_GNrZyFarP zT;5#k3)e2(BipABfB*9!lVg9>xsIK&KB^~JpIDz>$J`VBX%Br`2H*8MX>mJr?1y!+ zFXL0%{h6KMYT*mlZrn55r;p$h`=icv%!e=3H!V|m^@;Uq z*4z{QMGt+d#(H|4w73E~_QSf^SLjp9>rYkW;0xF8m}h%NbFQW1VWnEg@bI@ZVf z$eV0^VtslYb5Hb_J@l!e+^(nBNsDWtV?V5meT6=yy#7=VuBgiT!nG^*wa0w_?&VkP z^EmsX&UIWE>!WBF+ZXH8>zI3@JA3F;3w+n>q{U6pu^-mOzCxc;UVmB$t_i+y?biLW z_tP&cUA>~ou|Miu$M#qsl~b%wtWU3F?uq`Yhdy<{cfC$p+y)){VO{Ji^eN@_r*?4p z`&(a{@3YsLMF-g9b#by?SGup-gzPV^hULz|7i#LJTAx@S=gnyDiC)q}pYpJtUMDSH zhC0|!4vyJZ=u^t;PdQk>5x#KkmIJeW8aU|Q&?ojso$FW_>!W#^^@;WAb<91{OMB>3 z5!Tb|q{Ri$u^-mOzCxc;-VZJWm-(ypg=?1_WRLl}%KCF}y~^a+A9b!{MXZm-)2&ae zPp@O{iT=8WK2>5py-r$O0v-EdUF<9LDdqj(3UKxCW%0iD_ii;;Tc7wme&I3a{%+38 z{?ck#-dt_0kFFWkC)TG~b5Ha)J@ly#>*;mU;%eyF59?xIp-(CA2iJn@f-hXV;1KK6 zKuiq3@3XT_$o{Bv9h+i(WOlVau|B7qt10~i}g`H)Aq&s^g8CA=wEv1(_;9p*GY?8pkqI* zi+zPYrTpB|2Cfsn)Gx9B?(z<|KJj&xSxqA=%z4>gS`EvaTNdl1W|sAd^=a1J6aAka z`qTyA^*U*B2XyR*b+NDT-(AXnS_ZBPzHsfjBeH!OdD43`Opg6g=Q!DBOSWmB$78gOsepna#GOw$oy*^$7uDr(j!nLc9vd4TLzo(&L zu*tDM>RiX_SRb9cS)W*+UdP-M{d*66s=<1CowT?TI`+f5*jIP2(^Z3Og)dyY<7n#> zuL}l0d-HUYV}I1Sjt#Ls@++-RtWU3F?uq`hhdwp#Zr9W6q{Vg6u^-mOzRbV7F)7dE z4d9CAXYZ$qW9)JGVU6H~{SR&l-#2G}X*Dcwt|it-@m$*%>(i{cC%SL&(2=IK(JS`Qr%w2;*GY>PL&ttt7yB~*?t*W337?_EAs#GhfI3AMgLSki31jqg3Vs%W}Fa%>b5oiV}T|A_0 zEP{!g2!yN0#p;-{-4RrCBG9ab= zoCt(#$HnTHvM&+*&WS*?j?%?L%Kktwq>m`pl`s*J8w&kY#jTf6%LKV;(4VQe^+lG5 z$ejiKgNoZAp_U19Eztj{xD7>?h{*i}{g!=2l94bGk=qLT{S>!RLM;>IPKN$w#SIl% zA|m%C^aEEA$#4l15xGIo&r)1rLM;>IW(GCrxGfTDnIQKq^rKgl+?En1B64G(pQ*U55^9+sHw*d(#ceIJL`1F``i~Vi zGNG0Ua-TrI{$C_FO2R}$ZUgA2C~ljCS|-R%h5kInjTTuVB6mLYixf8|p_U19Z$kf- z;OmRCT)G|SCd+4VtZfB7tB62gJ zKR|IM3AId+I}rL46jv&;L`3dy&|jvwaS63dkh>lF#}!v5vP4Ag3FzNY+{A=hCdj=B zeW&6ki7XM3`w{xQJdx}oVIm^8GV~iLZc0Ke6XZ68ep|&&6y0>=^{%+Pegjy!ZJqi5>ikm62L`3c* z=zmh&?1Wk-$o&lc$}3B5j)aMbTtDbHQrvC{wM>xP82Yh_+g)Udh}^c&&rsalgjy!Z zRX~4`;`R_(A|h7}{V9suGoh9Va&^!zP~2W3OGM0pKxkI2oQ*pt|Ro#A(I}7>+ zimU6El2^H|f&MyB1=T%wuOGS;_4G>nIJa@`lA(hj>r-bx%tpvpty4rYMCH+A@sK^?mUqt zB64>?|BB+yPpD;r+^f)kp|}e~mWarG3H|>RcVR*;6XbGNwR3A=G)E00OGM-bL%*fs zE>5Urg4|Znk5}9!B1=T%CP2TZ;x0|7WrEyZ&>yF`%S4ul$Q=*;MT)yTp_U194bV3$ z?h275B67Dv|AgZHkxalLGDNB2dpN!t0YWBHjyPFa_2#Rt>SJ^sAYoObaQ*jT9ED@2L1^uClYe}eOg4|)ypP{&iM3#ui zoeBL_ihDSrmI-oKLw}dz9uZk0BKI%o7b))1gjy!Zy$gN6L6Uo1!bC)_KlCMvdm^Eh z33Ah+KT&auM3#uiodo?t#XXf!%LKW*p>J2*(;`bmM}y(F?kMDD-PZ?c9+ zUX?HrksAj6EX6HOsAYoOZ0Ju>+-o9BMC9tAe^7C+C)6@Qt_Aw<759e75)ru{pdUV1 zByUQXh{$aV{dC2>lTgb9xf#&!uef%RB_eVMK!2R#-c6`wg52@YpQpI@M3#ui?YX8+ z-GtE`eVkCs1i71`|59x6!nwM6o%go%jU6zH#0+-C{3Opt4W{u{-8F0w>K z?px?57l`Bw2@?^yU7-J`;=W9%WrEy|(03`WQ)G#V+^^72U0WnyNtlSpO@qExaZ3_v znILxp^!F=nsmKx$xd)(Mrns*YYMCJSJ@ggpNbVa66A`&xp}$FS-zL;DLGEVgzf;_I zB1=T%mO)>qTdo~nIN|X z^m{7qcabF`a(h94n&SRQsAYoO>CnHTxIaafh{!F0zH9@Lu;vc&DiOOF`A=Q zn6#;^znOX@W2e8yXpUB8(x$ThX6l=aonB)jNw3DFOhpk>gQ4F^arsO}Y6+Oy8Tx9) z4P;W}QN+~2&_AZQK}<$!37C2u`V}^o-0DoqR1`6_BJ`DtTZ73+Edf*ignqH&)?!lR zQN+}1(0{ME0wyE11Wf$^{VGEww>Fb96-7*~3jG#}TZhR=Edf(oL4Shc)?-rSQN+~W zpnq0z>oXatC1C0~=vN;qxeb_{>P_f>Q5^4ej>IY; zx5_4Vau`N)v?-HH&ycC%(3dD~GbSlkBU7c&@1eNOnN)g)OzjE%F^b!QNs86T)aB6M zp}4J?RCZX}aR&ycBip#NHNqnM;vjZA$5eV<{H+=fY+ ziXx`^LcgZsMl%_yC17eT=(kXuzL#DI8(lmKTC1NOs0TL&4&IE z#cj*va=6E#U!u639Jr;>7Y&!icXr?og#J#&l{#=spwBCm^OZSpD?>kAar!e2vYL&! zWFhorikrk_914z^nh5<7iYsSwIoy%Z|3h(;9k@p5pHSQ`4qPkrpD1pM1NSNP{Wg_m zraEx_p&y~RX%5`y(2w3s&Ns_}8v}j4;$}N==Rp6S;^sJT??b=o=2GWw4%}wYAE-Ef zhDKJBh)WLK!p_acXpZ(~Qshy@)Ewv+C~hAnBeeufT?75+ikruz$fJma{_l!AkjY3b0aK?y|B>SU%B0Anh^Y?fOSXwY)Dke&2>lz1JB&$@M-fwRLciLG zD3x=Er5Qp;%b z8$dr#amO(ksU={l3i_KAcRZ6Kk0PdShW;1D)iN2WC1C15&`;e)awjk;Q&Gg!H0b}S zxW6$OsU=|QM(Dp&oc=7Q5H=#W4Ej-{MZwQ>%8W$hwt@a6#huKg$fJm;hE3TeNkw+0zw?e;Eapy1@sU=|QYv{MxR&wVuDN|9z)M)7cuDJ7< zjMNe^bqe&)EAD(IMIJ>=y#Rggc2O$l0w!fDikRvHeTm{OWHM4qz*H&prz`FvCPf}a zOq~J!vx;kAGEz&x)N|0Uu)X9iW>Ti2h^ZB!-&t{&Fd3;OV5$WAlNEO_ zjZBI>ikNx``kxhdC6kd_0;Ya}e$0-NyNXGfiXx`QLSL)6tC@_{5-@cF^baX+0h1z+ zBBmaO{tv}n!(^nEfT=&BFWE_Q*D@(nQN&a!^p_~^Iwm8v1Wa8D{ilj+Vp8N$#MEcd zkKQ>-W1z28+zm`dY6+P7q14We9w)g6n3Sm~VrmTZ)rxzN$w(~$QwKwT zwc=Ws6nPXewE+586!#F5ky-+#UWGn)yyPBcQl_GasXox}qqs+yjMNe^H4pl`6!$2T zB99`b{sn!X2~jHNF(zdyikRvP{UpUb&Sa#PfT?omuTqll@qq5o8Ii zMIJ>=eF%N-lqi++E|W49MNIX9eiOyL$7H0IfT>~7&rsa^Oo}{;n5uyO1jYTE$w(~$ zQ`bWOq~bngQshy@)M+#A)U6oJ(Q17nSt1~J8}u(JF5iKB8TxM(H_(Cm4*IocNlAko zxOJc}RovR|j6}PVg zcMSArD{emrt{(bp6}P_wxBEW!ak~VgIXc*ZyA=An6nBUN_b=#QRNSEs+)L1Zskp-& zxZj{(bDr(f{C%VYw-)px6<6cHO@;n2#m#r%4u}2%#U10oT@U@+iaXwcdk6XfRpLvn z16K(BE{Z$Rftv#T;fg!Sfx8O&Clz;!1GfnJuM}73z%7A(;J!K0*QpNNAn3PM+-VNn zcF^yuxYHfD|3N=^zo^WddIxSz=r>o~IS$+w(2rN#xenX}=;tc#JO^$M=#Ny~`3~Iw zpr5tB_;RrWclQBS|13sxbd>}5J@hLdDCb+?!1aTEW5r$Lzzu=ESaH`naN9z^o8qo> z;C6?8zT%o3xMQHdP;u8ga2G*;m*Q@4;Qj^u^NRbY1NQ>-OB8pb1Gg0VRsSlF`%Mnq zYS3?`xSJigt)bslakn^dGoe39am^0g(a>L}xLX~#%b~wlakn{e_d)-f;%;}~UWfi0 z#ogh+eGC1{2g&1irvtZTwbhTqXpSCm;KoCLu;TRZ{*@|hl#7W&pg&u2{2jn?#vGHY zhyF&zJ>*d51JJ*wxJMnh*P;JGagRB0KSDqFVCm*@2X0O1ixu~T19vR+S1E3h19uDb zpDFGc2kvv|%MX$Mo^{~nKtEq`&pU8+&_A!ZmmIhkpkL)ssqTVepx;w*?>lgNL4S}+(!=F zqtL&jxDE&IKhO_6TpssN9k@ZzZ?3q{9Jno@FH_v-4%`9IU#PfF2ks*1TNL+|1NRX0 zA1H2#1NR~HeUA`7mpX7OLSLx3ZydNyp|4Qfw+`H{&>yF`?;N;Gpub6RKR9qVL;r~4 z^#3IwZrO;}6CXj}rMO=l&i58!(YDU} zFq)&)9JsHbpD^F@=I?C;;?{NGWluc6=SIO%T#2X3X~t$rFtb2QX}n-2Y%ird72I}7^96*tU*djk5u)JlKD z9k`XCuTWf}1Gg*m7btF12kt`X-%{LW4&2+&Z*qe4x48p14EhTcw}k_DA@px3PXC`V zQiYB9JoqN`Yy3?V{J&#lMj~>9p+8h{TRYTw81#!2SLDDw1^wD5N-ZNCxOJdEMsXt@ zxMQJzS#hHrxL2Sbc9PV&jRQ9v`co7)+JUQs{yoKwap2yEe$2^I=U4}BEc90>uGoS5 z2lQQv+tz{m75Y8?E_H6_!0ieBNs8Ovfjb%cYZbSH19u(t-zsiL2W}bkLr;@= zfx8^~7RAkQ;2whheZ^HcaQ}w>e~R1Hfy+6~+BgKGIhyIf4TXM^;$}H;<A*)q#7P`ZL9WgB-YA=!Yt<+JV~y z`ZE-Fumg7{^tUSR5C`ry=wDIXp$^=u(Ep&g!yLFDpde2#c_ zx&yZ+^t&qV3g)~oF|XNMGoBB z&`(xeg9En<^tFn+*nv9%`UQ%+#DTj8`c}nV>cBk-{ilk%%z^t1`oEkneqQdttpxoh zio3#rn+*Maio4Q*+aLPV6nB*acRKXfEADCs?gr?eRonsx?m6f`Q`|KU+~?5uy+9s^ zYaO^1pdY5V>m0b@(C?zSCI@Z`^k*pUdI#=I=x{R#bs z7s=yyy91Yjew^a&aNx#6e~{wtbl|F?|A*r4a^M=Fe^GJ&a^PNq{#(T@bl|>&eqe+6 zdA9>M2>MZqyT^gs2KqUQyVrr+4f>-Mcb@|{ANq$CcfSMo2=psmEWSM8z~w=|m*O6D z;P!_8PQ|r2aCbrfmEs<9;FdtY^Ci;X!wy^t^w%lw5eKdb`T>{9`5txPR)PLv#XaW0 zErk9>#kD$cFG2r};+}NizJ-3(%cQ?W4%}+cZ=<-U9JtZY&r#gd4%}|gAFsG)9JpHO z7bxyo2ksi^pH$p)4%{N>zgAqE1NRN|`IpP%@Vo;z5c(q(_ksgg1N~)+d(nZr9Qub8 z_mTtmF!UcN?qvt=L+JZlA-=rg!1aZGxZ+-Q;0mGNMRAKAxGB&dp}5x^xFeyzRB^96 zaF;>wKHzH;CmhyEkQEpgyFpzm{)__EZ2>kIu*#eMC-Z32Cn;=XayINp+87*D>!h~(AO(&MF;L2=$jSy7YFWE=wDFWN)FtM&@WY7o&)za^aHLH zKUa3(R)Ky?#r1RGwt{|!;`%#q70{ooxB(8_-=S|-+$s*-tpO5iLqGWX zoak!<2X0O1w^Q7P4&3(8S1B&z!0ikDd5YV}fjb}ig^JtQfx8>}-xW8+f%^mc%ngy9 zIYS+|ji8^PxJ?|mGU!iJ+%O03bm*HEH{5}{75bMISLndK0{st)+th*k5&9AT6hAj} z;6_5fyW%!?;3}a%M{!#?aOXnbqPQ&`xQC$sKyh0+a34b7=SJ~mYX`0`^urWab9uDJ0I+!fG2q__zV+{4g+ptv#z?nCHv zZ;{7gq660l`r(S3qY`!>ttFwKEm0s0||o9@7!daFIp-5AZ$?hf2N)ZZp`RyuIG&`(m_TnDZk`im5| zhXeN{^xrFPZwKxN=!e`c{q5tx4TZi^aq}FwxzL}cxGD$kbm*T{+`bOnBIvigL;Bm# zf!hlDYZSM?1NRE_E8QvQ`>O+&2YsdD4szh;LVt(isvWpHq5oZR2Rm?oKtJ&=>F*E+ zZW8ndDDF@PZt}nEdCtRVj^;aX=R^N*#U10oeE@xCq4amG1Gf?MRf;>#f!i1QClzMy@6CJqUpdWjW^mmd2R}6i<;!bwp zUV?t$y>h-f2W}AbvlVx$19utp?K(YD&~LA}a~!xG zpr56lQ7zKn4G!E3(0{17 zTO7ELp#M>E%?{j8(D#2x>b%u~8vy+f#ogw>4TXMt#og|}?Ew8O#ogh+Erq`C!_wb9 z4%`aRudld!9k>mkAEUVY9JsO2S19g&2X0sB4^i9$4&0&8pRTwE9k?@~zgBTA4%~In zKcu*a9Jq&}e^YS}J8*A7zf5tDIB?%XKj0DBFONEKt3W?YagRB0!=az7xW^s1U7$Zq zaZfmKheLmc;#wWJGoim;aZfsMH$eZO;ubk@EzrNIxThSrx1e99xThVs@1bAqQF+{- zap3ZyAEvlx9k}7pmn!Z#2W}kndn&HYf!hoE;}rM219v?17b@-r2ks*1Z&Tch4&3d~ zzofXA9JrUEU#hs59k{Qd@Bf%Q?yop-1E3$KxK|yx;n0^UZm|P55&C(Gd(DBXg8n4M zz3#xB4E?o=d&7ad4*EwF_of5)DD-bB?kxvy-sARhtHo%J-gn?mfWAR-|90RmhW=K? zec-^|2K^$%edxeF1^xSq`^bU&H}ttr$iD7y;QBy6TyY;eaD~uMP~0aDTp9F-DDG1S z?ojA2R@`R}+$GSrDDHCy?jh)3RooX2++ygLD(*`M?rZ4tTIKQUbl_HoeyHNUa^N!kiJ#FiI9-}$x zyQ0(_k8&~bBJ@L_5ygrQ9MxRM*z{8H=P$vZ++gyvVEiihW4`(Zf4&a>{1W`>7yL2# ze!-vB0Gm9&FvY{@{~6i3`pCl%-1>lhk2vDst;ZjEz=2!OKk(?|4m^6xqmHjR`pARk zZyf Date: Fri, 14 Jun 2019 22:58:30 +1200 Subject: [PATCH 0689/2474] Add Basic TF-specific menu --- Makefile | 1 + menu.src | 142 ++++++++ menu/loadsave.qc | 164 +++++++++ menu/main.qc | 147 ++++++++ menu/newgame.qc | 238 ++++++++++++ menu/options.qc | 104 ++++++ menu/options_audio.qc | 74 ++++ menu/options_basic.qc | 155 ++++++++ menu/options_configs.qc | 57 +++ menu/options_effects.qc | 57 +++ menu/options_hud.qc | 68 ++++ menu/options_keys.qc | 130 +++++++ menu/options_particles.qc | 136 +++++++ menu/options_video.qc | 95 +++++ menu/presets.qc | 102 ++++++ menu/quit.qc | 46 +++ menu/servers.qc | 411 +++++++++++++++++++++ menusys/mitem_bind.qc | 108 ++++++ menusys/mitem_checkbox.qc | 69 ++++ menusys/mitem_colours.qc | 247 +++++++++++++ menusys/mitem_combo.qc | 303 ++++++++++++++++ menusys/mitem_console.qc | 58 +++ menusys/mitem_desktop.qc | 465 ++++++++++++++++++++++++ menusys/mitem_edittext.qc | 98 +++++ menusys/mitem_exmenu.qc | 58 +++ menusys/mitem_frame.qc | 675 +++++++++++++++++++++++++++++++++++ menusys/mitem_menu.qc | 332 +++++++++++++++++ menusys/mitem_slider.qc | 153 ++++++++ menusys/mitem_spinnymodel.qc | 164 +++++++++ menusys/mitem_tabs.qc | 168 +++++++++ menusys/mitems.qc | 439 +++++++++++++++++++++++ menusys/mitems_common.qc | 185 ++++++++++ menusys/readme.txt | 220 ++++++++++++ 33 files changed, 5869 insertions(+) create mode 100644 menu.src create mode 100644 menu/loadsave.qc create mode 100644 menu/main.qc create mode 100644 menu/newgame.qc create mode 100644 menu/options.qc create mode 100644 menu/options_audio.qc create mode 100644 menu/options_basic.qc create mode 100644 menu/options_configs.qc create mode 100644 menu/options_effects.qc create mode 100644 menu/options_hud.qc create mode 100644 menu/options_keys.qc create mode 100644 menu/options_particles.qc create mode 100644 menu/options_video.qc create mode 100644 menu/presets.qc create mode 100644 menu/quit.qc create mode 100644 menu/servers.qc create mode 100644 menusys/mitem_bind.qc create mode 100644 menusys/mitem_checkbox.qc create mode 100644 menusys/mitem_colours.qc create mode 100644 menusys/mitem_combo.qc create mode 100644 menusys/mitem_console.qc create mode 100644 menusys/mitem_desktop.qc create mode 100644 menusys/mitem_edittext.qc create mode 100644 menusys/mitem_exmenu.qc create mode 100644 menusys/mitem_frame.qc create mode 100644 menusys/mitem_menu.qc create mode 100644 menusys/mitem_slider.qc create mode 100644 menusys/mitem_spinnymodel.qc create mode 100644 menusys/mitem_tabs.qc create mode 100644 menusys/mitems.qc create mode 100644 menusys/mitems_common.qc create mode 100644 menusys/readme.txt diff --git a/Makefile b/Makefile index ca0657eb..51a1dafd 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ endif all: fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./csqc/csprogs.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./menu.src clean: rm -f $(TARGET) qwprogs.lno files.dat progdefs.h diff --git a/menu.src b/menu.src new file mode 100644 index 00000000..06b89b0d --- /dev/null +++ b/menu.src @@ -0,0 +1,142 @@ +#pragma progs_dat "../menu.dat" + +//#pragma target fte + +#define MENU //select the module + +#includelist +fteextensions.qc //also sets up system defs + +menusys/mitems.qc //root item type +menusys/mitems_common.qc //basic types +menusys/mitem_desktop.qc //other sort of root item +menusys/mitem_exmenu.qc //fullscreen/exclusive menus +menusys/mitem_edittext.qc //simple text editor +menusys/mitem_tabs.qc //tabs +menusys/mitem_colours.qc //colour picker +menusys/mitem_checkbox.qc //checkbox (boolean thingies) +menusys/mitem_slider.qc //scrollbars +menusys/mitem_combo.qc //multiple-choice thingies +menusys/mitem_bind.qc //key binding thingie +menusys/mitem_spinnymodel.qc //menu art +#endlist + + + +//might as well put this here. + +void(mitem_desktop desktop) M_Pop = +{ + mitem it = desktop.item_kactivechild; + if (it) + it.item_remove(); +}; + +//define the commands. +//cmd argments are: Name, Function, Sourcefile(may be empty) +#define concommandslist \ + cmd("m_main", M_Main, menu/main.qc) \ + cmd("m_pop", M_Pop, ) \ + cmd("m_options", M_Options, menu/options.qc) \ + cmd("m_keys", M_Options_Keys, menu/options_keys.qc) \ + cmd("m_basicopts", M_Options_Basic, menu/options_basic.qc) \ + cmd("m_video", M_Options_Video, menu/options_video.qc) \ + cmd("m_effects", M_Options_Effects, menu/options_effects.qc) \ + cmd("m_audio", M_Options_Audio, menu/options_audio.qc) \ + cmd("m_particles", M_Options_Particles, menu/options_particles.qc) \ + cmd("m_hud", M_Options_Hud, menu/options_hud.qc) \ + cmd("m_load", M_Load, menu/loadsave.qc) \ + cmd("m_save", M_Save, ) \ + cmd("m_quit", M_Quit, menu/quit.qc) \ + cmd("m_newgame", M_NewGame, menu/newgame.qc) \ + cmd("m_servers", M_Servers, menu/servers.qc) \ + cmd("m_configs", M_Configs, menu/options_configs.qc) \ + cmd("m_reset", M_Reset, ) \ + cmd("m_preset", M_Preset, menu/presets.qc) + + +#if 0 +#append concommandslist cmd("m_servers", M_Servers, menu/servers.qc) +#define serverbrowser "m_servers" +#else +#define serverbrowser "menu_servers" +#endif + +//make sure all the right files are included +#define cmd(n,fnc,inc) inc +#includelist + concommandslist +#endlist +#undef cmd + +mitem_desktop desktop; +void() m_shutdown = {}; +void(vector screensize) m_draw = {items_draw(desktop);}; +void(float scan, float chr) m_keydown = {items_keypress(desktop, scan, chr, TRUE);}; +void(float scan, float chr) m_keyup = {items_keypress(desktop, scan, chr, FALSE);}; +void(float mode) m_toggle +{ //mode is stupid. 1=enable,0=disable,-1=actually toggle. + if (mode < 0) + mode = !desktop.item_kactivechild; + if (mode) + M_Main(desktop); + else while(desktop.item_kactivechild) + { + mitem it = desktop.item_kactivechild; + if (it.item_flags & IF_NOKILL) + break; + it.item_remove(); + } + + items_updategrabs(TRUE); +}; + +var float autocvar_dp_workarounds_allow = TRUE; +var float autocvar_dp_workarounds_force = FALSE; +void() m_init = +{ + desktop = spawn(mitem_desktop); + + //register the console commands via the alias command. +#define cmd(n,f) localcmd("alias " n " \"menu_cmd " n " $*\"\n"); + concommandslist +#undef cmd + + //work around some dp differences/bugs. + //this check identifies one significant bug in DP. + //if anyone actually cares to fix DP, then there is no reason they cannot do so by just removing DP_QC_RENDERSCENE and then fixing anything else that arises. + if (checkextension("DP_QC_RENDER_SCENE") && !checkextension("DP_CON_SET")) + dp_workarounds = autocvar(dp_workarounds_allow, TRUE); + if (autocvar(dp_workarounds_force, FALSE)) + dp_workarounds = TRUE; + + if (dp_workarounds) + print("^1WORKING AROUND DP BUGS\n"); + + //for compat with DP, 'none' is the default cursor in menuqc. + //naturally this is not ideal. + if (checkextension("FTE_QC_HARDWARECURSORS")) + setcursormode(TRUE, ""); + else + print("No hardware cursors\n"); + + if (clientstate() == 1) //disconnected==1, supposedly + m_toggle(1); +}; +void(string cstr) GameCommand = +{ + tokenize(cstr); + string cmd = argv(0); + + switch(cmd) + { +//switch on the known commands. +#define cmd(n,f) case n: f(desktop); break; + concommandslist +#undef cmd + default: + print("unknown command ", cmd, "\n"); + break; + } + items_updategrabs(TRUE); +}; diff --git a/menu/loadsave.qc b/menu/loadsave.qc new file mode 100644 index 00000000..d5ca15f0 --- /dev/null +++ b/menu/loadsave.qc @@ -0,0 +1,164 @@ +#ifndef LOADSAVE_QC +#define LOADSAVE_QC + +//I'm feeling lazy, so I'm going to only provide X slots, like quake's menu. +static string savenames[] = +{ + "a0", + "a1", + "a2", + "quick", + "s0", + "s1", + "s2", + "s3", + "s4", + "s5", + "s6", + "s7", + "s8", + "s9", +}; +#define NUMSAVESLOTS savenames.length + +/* +class mitem_savescreeny : mitem +{ + virtual void(vector pos) item_draw = + { + string s = sprintf("saves/s%g/screeny.png", selectedsaveslot); + if not(whichpack(s)) + if (drawgetimagesize(s) != '0 0 0') + ui.drawpic(pos, s, item_size, item_rgb, item_alpha, 0); + }; +}; +*/ +class mitem_saveoption : mitem_text +{ + string slot; + float mode; + + virtual void() mitem_saveoption = + { + if (mode) + item_flags |= IF_SELECTABLE; + }; + + virtual void(vector pos) item_draw = + { + //some sort of pulsing if its active. + if (item_flags & IF_KFOCUSED) + ui.drawfill(pos, item_size, '1 0 0', sin(cltime)*0.125+0.150, 0); + float w = stringwidth(item_text, TRUE, '1 1 0'*item_scale); + ui.drawstring(pos + [(item_size_x-w)/2, 0], item_text, '1 1 0' * item_scale, menuitem_textcolour(this), item_alpha, 0); + }; + + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + if (!down) + return FALSE; + if (scan == K_ENTER || (scan == K_MOUSE1 && mouseinbox(pos, this.item_size))) + { + if (item_flags & IF_KFOCUSED) + { + switch(mode) + { + case 0: + break; //can't load a slot which is empty. + case 1: + localcmd(sprintf("m_pop;load %s\n", slot)); + break; + case 2: + //FTE has a savegame_legacy command if you want compatibility with other engines. + localcmd(sprintf("m_pop;wait;echo \"%s\";save %s\n", _("Saving Game"), slot)); + //localcmd(sprintf("m_pop;wait;screenshot saves/s%g/screeny.png;echo \"%s\";save s%g\n", slot, _("Saving Game"), slot)); + break; + } + } + else + { + item_parent.item_focuschange(this, IF_KFOCUSED); + } + return TRUE; + } + return FALSE; + }; +}; + +class mitem_savepreview : mitem +{ + //assumption: the only selectable children in the parent are save options. + virtual void(vector pos) item_draw = + { + mitem_saveoption sel; + sel = (mitem_saveoption)item_parent.item_kactivechild; + if (sel) + { + string s = sprintf("saves/%s/screeny.tga", sel.slot); + if (drawgetimagesize(s) != '0 0 0') + ui.drawpic(pos, s, item_size, item_rgb, item_alpha, 0); + } + }; +}; + +static string(string savename) scansave = +{ + string l; + float f = fopen(sprintf("saves/%s/info.fsv", savename), FILE_READ); + if (f < 0) + f = fopen(sprintf("%s.sav", savename), FILE_READ); + if (f < 0) + return __NULL__; //weird + + fgets(f); //should be the version + l = fgets(f); //description + if (l) + l = strreplace("_", " ", l); + fclose(f); + return l; +}; + +void(mitem_desktop desktop, float mode) M_LoadSave = +{ + mitem_exmenu m = spawn(mitem_exmenu, item_text:"Load/Save", item_flags:IF_SELECTABLE, item_command:"m_main"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + string l; + float i; + float smode; + float pos = NUMSAVESLOTS*16/-2; + + mitem_pic banner = spawn(mitem_pic, item_text:((mode==2)?"gfx/p_save.lmp":"gfx/p_load.lmp"), item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [(banner.item_size_x)*-0.5, pos-32], [(banner.item_size_x)*0.5, pos-8]); + + for (i = 0; i < NUMSAVESLOTS; i++) + { + l = scansave(savenames[i]); + smode = mode; + if (l=="") + { + l = "Empty Slot"; + if (mode==1) + smode = 0; + } + m.addm(spawn (mitem_saveoption, item_scale:16, slot:savenames[i], mode:smode, item_text:l), [-320, pos+i*16], [320, pos+(i+1)*16]); + } + + m.addm(spawn(mitem_savepreview), [-320, -240], [320, 240]); + addmenuback(m); +}; + +void(mitem_desktop desktop) M_Load = +{ + M_LoadSave(desktop, 1); +}; +void(mitem_desktop desktop) M_Save = +{ + if (!(isserver() || dp_workarounds)) + M_Main(desktop); //can't save when not connected. this should be rare, but can if you use the console or the main menu options are stale. + else + M_LoadSave(desktop, 2); +}; +#endif diff --git a/menu/main.qc b/menu/main.qc new file mode 100644 index 00000000..1d91a543 --- /dev/null +++ b/menu/main.qc @@ -0,0 +1,147 @@ +/* +The main / root menu. +Just a load of text with console commands attached. +Choice of buttons available is somewhat dynamic. + +There's also some generic kludge crap in here, like menu background tints +*/ + +/* +Adds a background tint to a (typically) exmenu parent. +In FTE, we use built-in stuff to give a sepia effect. +In DP, we just tint it black. +*/ +nonstatic void(mitem_frame m) addmenuback = +{ + if (iscachedpic("menutint")) //fte internal hacks! meh, admit it. its cool. + m.add(spawn (mitem_pic, item_text:"menutint", item_alpha:0.5), + RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, [0, 0], [0, 0]); + else + m.add(spawn (mitem_fill, item_rgb:'0 0 0.01', item_alpha:0.5), + RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, [0, 0], [0, 0]); +}; + +/* +helper functions to avoid blowing up in older clients. + +*/ +#define dp(dpc,qwc) (cvar_type(dpc)?dpc:qwc) +float(string cmd) assumetruecheckcommand = +{ + if (!checkextension("FTE_QC_CHECKCOMMAND")) + return TRUE; + return checkcommand(cmd); +}; +float(string cmd) assumefalsecheckcommand = +{ + if (!checkextension("FTE_QC_CHECKCOMMAND")) + return FALSE; + return checkcommand(cmd); +}; + + + +nonstatic void(mitem_desktop desktop) M_Main = +{ + local float y; + local mitem_exmenu m; + + //no dupes please. + m = (mitem_exmenu)desktop.findchildtext(_("Main Menu")); + if (m) + { + m.totop(); + return; + } + + //create a fullscreen frame + m = spawn(mitem_exmenu, item_text:_("Main Menu"), item_flags:IF_SELECTABLE); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + +// m.item_flags |= IF_NOKILL; +// m.adda(menuitempic_spawn ("gfx/qplaque.lmp", '32 144'), '16 4'); + + y = 7*-16/2; + + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_main.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [(160-banner.item_size_x)*0.5, y-32], [(160+banner.item_size_x)*0.5, y-8]); + + +//a macro, in a desperate attempt at readability +#define menuitemtext_cladd16(m,t,c,y) m.addm(spawn(mitem_text, item_text:t, item_command:c, item_scale:16, item_flags:IF_CENTERALIGN), [0, y], [160, y+16]) + +#ifdef CSQC + if (serverkey("constate") != "disconnected") {menuitemtext_cladd16(m, _("Return To Game"), "m_pop", y); y += 16;} + if (serverkey("constate") != "disconnected") {menuitemtext_cladd16(m, isserver?_("End Game"):_("Disconnect"),"m_pop;disconnect", y); y += 16;} else +#endif +#ifdef CSQC + if (checkextension("FTE_CSQC_SERVERBROWSER")) +#endif + {menuitemtext_cladd16(m, _("Join Server"), "m_pop;m_servers", y); y += 16;} + //if (assumetruecheckcommand("map")) {menuitemtext_cladd16(m, _("New Game"), "m_pop;m_newgame", y); y += 16;} + if (assumefalsecheckcommand("menu_demo")) {menuitemtext_cladd16(m, _("Demos"), "m_pop;menu_demo", y); y += 16;} + //if (assumetruecheckcommand("save") && (isserver()||dp_workarounds)) {menuitemtext_cladd16(m, _("Save"), "m_pop;m_save", y); y += 16;} + //if (assumetruecheckcommand("load")) {menuitemtext_cladd16(m, _("Load"), "m_pop;m_load", y); y += 16;} + //if (assumefalsecheckcommand("cef")) {menuitemtext_cladd16(m, _("Browser"), "m_pop;cef google.com", y); y += 16;} + //if (assumefalsecheckcommand("xmpp")) {menuitemtext_cladd16(m, _("Social"), "m_pop;xmpp", y); y += 16;} + //if (assumefalsecheckcommand("irc")) {menuitemtext_cladd16(m, _("IRC"), "m_pop;irc /info", y); y += 16;} + if (assumefalsecheckcommand("menu_download")) {menuitemtext_cladd16(m, _("Updates+Packages"), "m_pop;menu_download", y); y += 16;} + if (assumefalsecheckcommand("qi")) {menuitemtext_cladd16(m, _("Quake Injector"), "m_pop;qi", y); y += 16;} + {menuitemtext_cladd16(m, _("Options"), "m_pop;m_options", y); y += 16;} + {menuitemtext_cladd16(m, _("Quit"), "m_pop;m_quit", y); y += 16;} + +#if 1//def CSQC + //spinny quad/pent, for the luls + //local string it = (random()<0.9)?"progs/quaddama.mdl":"progs/invulner.mdl"; + local string skin = "tf_sold"; + local float r = random(), col = 13; //Blue + if(r > 0.89) + skin = "tf_scout"; + else if(r > 0.78) + skin = "tf_snipe"; + else if(r > 0.67) + skin = "tf_demo"; + else if(r > 0.56) + skin = "tf_medic"; + else if(r > 0.45) + skin = "tf_hwguy"; + else if(r > 0.34) + skin = "tf_pyro"; + else if(r > 0.23) + skin = "tf_spy"; + else if(r > 0.12) + skin = "tf_eng"; + + r = random(); + if(r > 0.95) + col = 11; //Green + else if(r > 0.9) + col = 12; //Yellow + else if(r > 0.45) + col = 4; //Red + + //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); + m.add(spawn (mitem_spinnymodel, + item_text: "progs/player.mdl", + firstframe:12, + framecount:5, + shootframe:119, + shootframes:6, + dontrotate:1, + startangle:'0 155 0', + skin:skin, + rotatespeed:10, + topcolour:col, + bottomcolour:col + ), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 16*-16/2], [-40, 16*16/2]); +#else + //menuqc doesn't support entities. shove some random crappy static image there instead. + local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); + m.addm(plaque, [(-160-plaque.item_size_x)*0.5, 12*-16/2], [(-160+plaque.item_size_x)*0.5, 12*16/2]); +#endif + + addmenuback(m); +}; diff --git a/menu/newgame.qc b/menu/newgame.qc new file mode 100644 index 00000000..639ce7da --- /dev/null +++ b/menu/newgame.qc @@ -0,0 +1,238 @@ +static string newgameinfo; +class mitem_newgame : mitem_exmenu +{ + virtual string(string key) get = + { + return infoget(newgameinfo, key); + }; + virtual void(string key, string newval) set = + { + string old = newgameinfo; + newgameinfo = strzone(infoadd(newgameinfo, key, newval)); + if (old) + strunzone(old); + }; +}; + +nonstatic void(mitem_desktop desktop) M_NewGame = +{ + mitem_pic banner; + string gametype = argv(1); + local float pos; + mitem_exmenu m; + if (gametype == "sp") + { + //single player has no options. the start map itself gives skill+episode options. + localcmd("\ndeathmatch 0; coop 0; maxplayers 0; timelimit 0; fraglimit 0; teamplay 0; samelevel 0; startmap_sp\n"); + return; + } + if (gametype == "begin") + { + cvar_set("hostname", infoget(newgameinfo, "hostname")); + cvar_set("deathmatch", infoget(newgameinfo, "deathmatch")); + cvar_set("coop", infoget(newgameinfo, "coop")); + cvar_set("teamplay", infoget(newgameinfo, "teamplay")); + cvar_set("sv_public", infoget(newgameinfo, "sv_public")); + cvar_set("maxclients", infoget(newgameinfo, "maxclients")); + cvar_set("timelimit", infoget(newgameinfo, "timelimit")); + cvar_set("fraglimit", infoget(newgameinfo, "fraglimit")); + string map = infoget(newgameinfo, "map"); + if (map == "") + map = sprintf("dm%g", floor(random(1, 6))); + localcmd(sprintf("\nmap \"%s\"\n", map)); + return; + } + + if (newgameinfo) + strunzone(newgameinfo); + newgameinfo = ""; + newgameinfo = infoadd(newgameinfo, "hostname", cvar_string("hostname")); + newgameinfo = infoadd(newgameinfo, "deathmatch", cvar_string("deathmatch")); + newgameinfo = infoadd(newgameinfo, "teamplay", cvar_string("teamplay")); + newgameinfo = infoadd(newgameinfo, "sv_public", cvar_string("sv_public")); + newgameinfo = infoadd(newgameinfo, "maxclients", cvar_string("maxclients")); + newgameinfo = infoadd(newgameinfo, "timelimit", cvar_string("timelimit")); + newgameinfo = infoadd(newgameinfo, "fraglimit", cvar_string("fraglimit")); + newgameinfo = strzone(newgameinfo); + + m = spawn(mitem_newgame, item_text:_("New Game"), item_flags:IF_SELECTABLE, item_command:"m_main"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + switch(gametype) + { + case "tdm": + case "dm": + case "coop": + case "sp": + break; + default: + //show game type selection + pos = (16/-2)*(4); + banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.addm(banner, [(160-banner.item_size_x)*0.5, pos-32], [(160+banner.item_size_x)*0.5, pos-8]); + m.addm(spawn(mitem_text, item_text:"Single Player", item_command:"m_pop;m_newgame sp", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; + m.addm(spawn(mitem_text, item_text:"Cooperative", item_command:"m_pop;m_newgame coop", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; + m.addm(spawn(mitem_text, item_text:"Deathmatch", item_command:"m_pop;m_newgame dm", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; + m.addm(spawn(mitem_text, item_text:"Team Deathmatch", item_command:"m_pop;m_newgame tdm", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; + +#if 1//def CSQC + m.add(spawn (mitem_spinnymodel, item_text: "progs/soldier.mdl",firstframe:73, framecount:8, shootframe:81, shootframes:9), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); +#else + //need some art for menuqc +#endif + return; + } + + pos = (16/-2)*(4); + + banner = spawn(mitem_pic, item_text:"gfx/p_multi.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.addm(banner, [(160-banner.item_size_x)*0.5, pos-32], [(160+banner.item_size_x)*0.5, pos-8]); + + m.addm(menuitemeditt_spawn(_("Hostname"), "hostname", '280 8'), [-160, pos], [160, pos+8]); pos += 8; + m.addm(menuitemcheck_spawn(_("Public"), "sv_public", '280 8'), [-160, pos], [160, pos+8]); pos += 8; + m.addm(menuitemcombo_spawn(_("Max Clients"), "maxclients", '280 8', _( + "2 \"Two\" " + "3 \"Three\" " + "4 \"Four\" " + "8 \"Eight\" " + "16 \"Sixteen\" " + "32 \"Thirty Two\" " + )), [-160, pos], [160, pos+8]); pos += 8; + + if (gametype == "dm" || gametype == "tdm") + { + if (m.get("deathmatch") == "0") + { + m.set("deathmatch", "1"); + m.set("coop", "0"); + } + m.addm(menuitemcombo_spawn(_("Deathmatch Mode"), "deathmatch", '280 8', _( + "1 \"Weapons Respawn\" " + "2 \"Weapons Stay\" " + "3 \"Powerups Respawn\" " + "4 \"Start With Weapons\" " + )), [-160, pos], [160, pos+8]); pos += 8; + } + else + { + if (m.get("coop") == "0") + { + m.set("deathmatch", "0"); + m.set("coop", "1"); + } + } + if (gametype == "tdm") + { + if (m.get("teamplay") == "0") + m.set("teamplay", "1"); + } + if (gametype == "dm") + { + if (m.get("teamplay") != "0") + m.set("teamplay", "0"); + } + if (gametype == "coop") + m.addm(menuitemcheck_spawn(_("No Friendly Fire"), "teamplay", '280 8'), [-160, pos], [160, pos+8]); pos += 8; +// if (gametype == "dm" || gametype == "tdm") + + if (gametype == "coop") + m.set("map", "start"); + else + { + m.addm(menuitemcombo_spawn(_("Time Limit"), "timelimit", '280 8', _( + "0 \"No Limit\" " + "5 \"5 minutes\" " + "10 \"10 minutes\" " + "15 \"15 minutes\" " + "20 \"20 minutes\" " + "25 \"25 minutes\" " + "30 \"30 minutes\" " + "35 \"35 minutes\" " + "40 \"40 minutes\" " + "45 \"45 minutes\" " + "50 \"50 minutes\" " + "55 \"55 minutes\" " + "60 \"1 hour\" " + )), [-160, pos], [160, pos+8]); pos += 8; + m.addm(menuitemcombo_spawn(_("Frag Limit"), "fraglimit", '280 8', _( + "0 \"No Limit\" " + "10 \"10 frags\" " + "20 \"20 frags\" " + "30 \"30 frags\" " + "40 \"40 frags\" " + "50 \"50 frags\" " + "60 \"60 frags\" " + "70 \"70 frags\" " + "80 \"80 frags\" " + "90 \"90 frags\" " + "100 \"100 frags\" " + )), [-160, pos], [160, pos+8]); pos += 8; + + m.set("map", ""); + m.addm(menuitemcombo_spawn(_("Initial Map"), "map", '280 8', _( + "dm1 \"DM1 (dm1)\" " + "dm2 \"DM2 (dm2)\" " + "dm3 \"DM3 (dm3)\" " + "dm4 \"DM4 (dm4)\" " + "dm5 \"DM5 (dm5)\" " + "dm6 \"DM6 (dm6)\" " + "start \"Start (Introduction)\" " + "e1m1 \"E1M1 (The Slipgate Complex)\" " + "e1m2 \"E1M2 (Castle Of The Damned)\" " + "e1m3 \"E1M3 (The Necropolis)\" " + "e1m4 \"E1M4 (The Grisly Grotto)\" " + "e1m5 \"E1M5 (Gloom Keep)\" " + "e1m6 \"E1M6 (The Door To Chthon)\" " + "e1m7 \"E1M7 (The House Of Chthon)\" " + "e1m8 \"E1M8 (Ziggarat Vertigo)\" " + "e2m1 \"E2M1 (The Installation)\" " + "e2m2 \"E2M2 (The Ogre Citadel)\" " + "e2m3 \"E2M3 (The Crypt Of Decay)\" " + "e2m4 \"E2M4 (The Ebon Fortress)\" " + "e2m5 \"E2M5 (The Wizard's Manse)\" " + "e2m6 \"E2M6 (The Dismal Oubliette\" " + "e2m7 \"E2M7 (The Underearth)\" " + "e3m1 \"E3M1 (Termination Central)\" " + "e3m2 \"E3M2 (The Vaults Of Zin)\" " + "e3m3 \"E3M3 (The Tomb Of Terror)\" " + "e3m4 \"E3M4 (Satan's Dark Delight)\" " + "e3m5 \"E3M5 (The Wind Tunnels)\" " + "e3m6 \"E3M6 (Chambers Of Torment)\" " + "e3m7 \"E3M7 (Tha Haunted Halls)\" " + "e4m1 \"E4M1 (The Sewage System)\" " + "e4m2 \"E4M2 (The Tower Of Despair)\" " + "e4m3 \"E4M3 (The Elder God Shrine)\" " + "e4m4 \"E4M4 (The Palace Of Hate)\" " + "e4m5 \"E4M5 (Hell's Atrium)\" " + "e4m6 \"E4M6 (The Pain Maze)\" " + "e4m7 \"E4M7 (Azure Agony)\" " + "e4m8 \"E4M8 (The Nameless City)\" " + "end \"End (Shub-Niggurath's Pit)\" " + )), [-160, pos], [160, pos+8]); pos += 8; + } + + m.addm(spawn(mitem_text, item_text:"BEGIN!", item_command:"m_pop;m_newgame begin", item_scale:16, item_flags:IF_CENTERALIGN), [-160, pos], [160, pos+16]); + + if (gametype == "coop") + { + //random art for style +#if 1//def CSQC + m.add(spawn (mitem_spinnymodel, item_text: "progs/soldier.mdl", firstframe:73, framecount:8, shootframe:81, shootframes:9), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, -240/2], [0, 240/2]); +#else + //need some art for menuqc +#endif + } + else + { + //random art for style +#if 1//def CSQC + m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); +#else + //need some art for menuqc +#endif + } + + addmenuback(m); +}; diff --git a/menu/options.qc b/menu/options.qc new file mode 100644 index 00000000..2d89d05e --- /dev/null +++ b/menu/options.qc @@ -0,0 +1,104 @@ +/*************************************************************************** +Options menu. +just a simple list. +*/ +nonstatic void(mitem_desktop desktop) M_Options = +{ + local float pos; + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Options"), item_flags:IF_SELECTABLE, item_command:"m_main"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + +/* //center the actual items + pos = (16/-2)*(9); + + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.addm(banner, [(-160-banner.item_size_x)*0.5, pos-32], [(-160+banner.item_size_x)*0.5, pos-8]); +*/ + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-80-banner.item_size_x*0.5, -h-32], [-80+banner.item_size_x*0.5, -h-8]); + + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160-160, -h], [0+160, h*2]); + + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + pos = 0; + + + + //and show the options. + if (assumefalsecheckcommand("fps_preset")) + {fr.add(spawn(mitem_text, item_text:"Graphical Presets", item_command:"m_pop;m_preset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} + fr.add(spawn(mitem_text, item_text:"Game Configs", item_command:"m_pop;m_configs", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; + fr.add(spawn(mitem_text, item_text:"Basic Setup", item_command:"m_pop;m_basicopts", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; + fr.add(spawn(mitem_text, item_text:"Audio", item_command:"m_pop;m_audio", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; + fr.add(spawn(mitem_text, item_text:"Video", item_command:"m_pop;m_video", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; + fr.add(spawn(mitem_text, item_text:"Effects", item_command:"m_pop;m_effects", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; + if (assumefalsecheckcommand("r_particledesc")) + {fr.add(spawn(mitem_text, item_text:"Particles", item_command:"m_pop;m_particles", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} + if (assumefalsecheckcommand("ezhud_nquake")) + {fr.add(spawn(mitem_text, item_text:"Hud", item_command:"m_pop;m_hud", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} + fr.add(spawn(mitem_text, item_text:"Keys", item_command:"m_pop;m_keys", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; + if (assumefalsecheckcommand("cfg_save")) + {fr.add(spawn(mitem_text, item_text:"Save Settings", item_command:"cfg_save", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} + if (assumefalsecheckcommand("cvarreset")) + {fr.add(spawn(mitem_text, item_text:"Reset to Defaults", item_command:"m_reset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} + + //random art for style +#if 1//def CSQC + //m.addm(spawn (mitem_spinnymodel, item_text: "progs/suit.mdl"), [0, 12*-16/2], [160, 12*16/2]); + m.add(spawn (mitem_spinnymodel, item_text: "progs/tf_flag.mdl", skin:"skin1",dontrotate:1, startangle:'0 192 0', firstframe:0, framecount:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [64, 12*-16/2], [160, 12*16/2]); +#else + //menuqc doesn't support entities. shove some random crappy static image there instead. + local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); + m.addm(plaque, [(160-plaque.item_size_x)*0.5, 12*-16/2], [(160+plaque.item_size_x)*0.5, 12*16/2]); +#endif + addmenuback(m); +}; + + + +static void(mitem_desktop desktop, string question, string affirmitive, string affirmitiveaction, string negative, string negativeaction) M_SimplePrompt = +{ + local float pos; + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Options"), item_flags:IF_SELECTABLE, item_command:""); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_exclusive = m; + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + //center the actual items + pos = (16/-2)*(2); + + //draw title art above the options +// mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); +// m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [(-160-banner.item_size_x)*0.5, pos-32], [(-160+banner.item_size_x)*0.5, pos-8]); + + m.add(spawn(mitem_text, item_text:question, item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos-(8+16)], [0, pos-8]); pos += 16; + + m.add(spawn(mitem_text, item_text:affirmitive, item_command:affirmitiveaction, item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos], [0, pos+16]); pos += 16; + m.add(spawn(mitem_text, item_text:negative, item_command:negativeaction, item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos], [0, pos+16]); pos += 16; + + //random art for style +#if 1//def CSQC + m.add(spawn (mitem_spinnymodel, item_text: "progs/suit.mdl"), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [0, 12*-16/2], [160, 12*16/2]); +#else + //menuqc doesn't support entities. shove some random crappy static image there instead. + local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); + m.addm(plaque, [(160-plaque.item_size_x)*0.5, 12*-16/2], [(160+plaque.item_size_x)*0.5, 12*16/2]); +#endif + addmenuback(m); +}; + +nonstatic void(mitem_desktop desktop) M_Reset = +{ + M_SimplePrompt(desktop, "Really Reset All Settings?", "Yes!", "m_pop;cvarreset *;exec default.cfg", "NOOOO! MY PRECIOUS!!!", "m_pop"); +}; diff --git a/menu/options_audio.qc b/menu/options_audio.qc new file mode 100644 index 00000000..cfd7dcee --- /dev/null +++ b/menu/options_audio.qc @@ -0,0 +1,74 @@ +nonstatic void(mitem_desktop desktop) M_Options_Audio = +{ + local float pos; + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Audio Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [banner.item_size_x*-0.5, -h-32], [banner.item_size_x*0.5, -h-8]); + + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); + + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + pos = 0; + + //add the options + fr.add(spawn(mitem_text, item_text:_("Restart Sound"), item_command:"snd_restart", item_scale:8, item_flags:IF_RIGHTALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [0, pos], [-8, 8]); pos += 8; + pos += 8; + fr.add(menuitemcombo_spawn(_("Sound Device"), "s_device", '280 8', cvar_string("_s_device_opts")), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Master Volume"), "volume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Ambient Volume"),"ambient_level", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Self Volume"), "s_localvolume", '0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Music Volume"), "bgmvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Channels"), "s_numspeakers", '1 6 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Audio Quality"), "s_khz", '280 8', _( + "11025 \"11025hz (vanilla quake)\" " + "22050 \"22050hz\" " + "44100 \"44100hz (cd quality)\" " + "48000 \"48000hz (dvd quality)\" " + "96000 \"96000hz\" " + "192000 \"192000hz\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Doppler"), "s_doppler", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("8bit audio"), "s_loadas8bit", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Swap Speakers"), "s_swapstereo", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Latency"), "s_mixahead", '0.1 0.3 0.01', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Disable Sound"), "nosound", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //ambient fade + fr.add(menuitemcheck_spawn(_("Static Sounds"), "cl_staticsounds", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Mix in Background"),"s_inactive", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + + pos += 8; + fr.add(menuitemcombo_spawn(_("Microphone Device"), "cl_voip_capturedevice", '280 8', cvar_string("_cl_voip_capturedevice_opts")), + fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("VOIP Playback Vol"),"cl_voip_play", '0 2 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("VOIP Test"), "cl_voip_test", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("VOIP Record Vol"), "cl_voip_micamp", '0 4 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("VOIP Mode"), "cl_voip_send", '280 8', _( + "0 \"Push-To-Talk\" 1 " + "\"Voice Activation\" " + "2 \"Continuous\"" + )), fl, [0, pos], [0, 8]); pos += 8; + //VAD threshhold + //ducking + //noise cancelation + fr.add(menuitemcombo_spawn(_("VOIP Codec"), "cl_voip_codec", '280 8',_( + "0 \"speex (narrow 11khz)\" " + //"1 \"raw (wasteful)\" " + "2 \"opus\" " + "3 \"speex (narrow 8khz)\" " + "4 \"speex (wide 16khz)\" " + "5 \"speex (ultrawide 32khz)\" " + )), fl, [0, pos], [0, 8]); pos += 8; + + fr.add(menuitemslider_spawn(_("Opus bitrate"), "cl_voip_bitrate", '0.5 128 0.5','280 8'), fl, [0, pos], [0, 8]); pos += 8; + + addmenuback(m); +}; \ No newline at end of file diff --git a/menu/options_basic.qc b/menu/options_basic.qc new file mode 100644 index 00000000..1547be18 --- /dev/null +++ b/menu/options_basic.qc @@ -0,0 +1,155 @@ +class mitem_playerpreview : mitem_spinnymodel +{ +#if 1//defined(FTE_QC_CUSTOMSKINS) + virtual void(vector pos) item_draw = + { + //if you wanted to get more advanced, you could use q3 skins here. + if (cvar("noskins")) + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\n\n", cvar_string("topcolor"), cvar_string("bottomcolor"))); + else if (cvar_string("cl_teamskin") != "") + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("cl_teamskin"))); + else + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("skin"))); + + super::item_draw(pos); + }; +#endif +}; + +static string() skinopts = +{ + string opts = ""; + float s = search_begin("skins/*.pcx", TRUE, TRUE); + if (s < 0) + return opts; + float n = search_getsize(s); + for (float i = 0; i < n; i++) + { + string f = substring(search_getfilename(s, i), 6, -5); + opts = strcat(opts, "\"", f, "\" \"", f, "\" "); + } + return opts; +}; + +var float autocvar_m_pitch = 0.022; +class options_basic : mitem_exmenu +{ + virtual float(string key) isvalid = + { + if (key == "m_pitchsign") + return TRUE; + if (key == "cl_run") + return TRUE; + return super::isvalid(key); + }; + virtual string(string key) get = + { + if (key == "m_pitchsign") + return (autocvar_m_pitch<0)?"1":"0"; + if (key == "cl_run") + return (stof(super::get("cl_forwardspeed")) > 200)?"1":"0"; + return super::get(key); + }; + virtual void(string key, string newval) set = + { + if (key == "m_pitchsign") + { + float invert; + if (stof(newval)) + invert = autocvar_m_pitch > 0; + else + invert = autocvar_m_pitch < 0; + if (invert) + cvar_set("m_pitch", ftos(-autocvar_m_pitch)); + } + else if (key == "cl_run") + { + float setbackspeed = (super::get("cl_backspeed") != ""); + if (stof(newval)) + { + super::set("cl_forwardspeed", "400"); + super::set("cl_sidespeed", "400"); + if (setbackspeed) + super::set("cl_backspeed", "400"); + super::set("cl_movespeedkey", "0.5"); //makes +speed act like +walk + } + else + { + //these are the defaults from winquake. + super::set("cl_forwardspeed", "200"); + super::set("cl_sidespeed", "350"); + if (setbackspeed) + super::set("cl_backspeed", "200"); + super::set("cl_movespeedkey", "2.0"); + } + } + else + super::set(key, newval); + }; +}; +nonstatic void(mitem_desktop desktop) M_Options_Basic = +{ + mitem_exmenu m; + m = spawn(options_basic, item_text:_("Basic Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-160-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + float pos = 0; + + + fr.add(menuitemeditt_spawn(_("Player Name"), dp("_cl_name", "name"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemeditt_spawn(_("Player Team"), "team", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemcombo_spawn(_("Player Skin"), "skin", '280 8', skinopts()), fl, [0, pos], [0, 8]); pos += 8; + + + //fr.add(menuitemcolour_spawn(_("Upper Colour"), "topcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemcolour_spawn(_("Lower Colour"), "bottomcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; /*aka: arse colour*/ + pos += 8; + fr.add(menuitemcheck_spawn (_("Always Run"), "cl_run", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Invert Mouse"), "m_pitchsign", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Sensitivity"), "sensitivity", '3 20 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Fov"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Viewmodel Fov"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.4 1.3 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.8 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'0.0 0.5 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Crosshair"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Show Speed"), "show_speed", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + + local string skin = "tf_sold"; + local float r = random(); + if(r > 0.89) + skin = "tf_scout"; + else if(r > 0.78) + skin = "tf_snipe"; + else if(r > 0.67) + skin = "tf_demo"; + else if(r > 0.56) + skin = "tf_medic"; + else if(r > 0.45) + skin = "tf_hwguy"; + else if(r > 0.34) + skin = "tf_pyro"; + else if(r > 0.23) + skin = "tf_spy"; + else if(r > 0.12) + skin = "tf_eng"; + + + //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); + m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', skin:skin, rotatespeed:10), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); +// m.add(spawn (mitem_playerpreview, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 12*-16/2], [-40, 12*16/2]); + + addmenuback(m); +}; diff --git a/menu/options_configs.qc b/menu/options_configs.qc new file mode 100644 index 00000000..fa9556f5 --- /dev/null +++ b/menu/options_configs.qc @@ -0,0 +1,57 @@ +/*************************************************************************** +Uses the engine command to apply the preset, and tries an exec instead if a config file exists. +Doesn't track the current one or anything. +Really simple and stupid menu. +no background tint, so the game is still visible so you can preview it. +*/ + +nonstatic void(mitem_desktop desktop) M_Configs = +{ + local float i; + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Game Presets / Configs"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + + float h = 200*0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-60-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); + + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); + + + + + float fs, y=0; + fs = search_begin("configs/game_*.cfg", TRUE, TRUE); + float c = search_getsize(fs); + for (i = 0; i < c; i++) + { + string fname = search_getfilename(fs, i); + string iname = strzone(substring(fname, 13, -5)); + string dname = GetFirstLineComment(fname, iname); + iname = sprintf("exec \"%s\"", fname); + if (dname && !fr.findchildcmd(iname)) + fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=16], '100 16'); + } + search_end(fs); + if (c <= 0) + fr.add(spawn(mitem_text, item_text:"No configs found", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], '100 16'); + + //random art for style +#if 1//def CSQC + m.addm(spawn (mitem_spinnymodel, item_text: "progs/g_rock2.mdl", zbias:-16), [-160-60, 12*-16/2], [-60, 12*16/2]); +#else + //menuqc doesn't support entities. shove some random crappy static image there instead. + local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); + m.addm(plaque, [(-160-plaque.item_size_x)*0.5, 12*-16/2], [(-160+plaque.item_size_x)*0.5, 12*16/2]); +#endif + + addmenuback(m); +}; + diff --git a/menu/options_effects.qc b/menu/options_effects.qc new file mode 100644 index 00000000..22e115e5 --- /dev/null +++ b/menu/options_effects.qc @@ -0,0 +1,57 @@ +nonstatic void(mitem_desktop desktop) M_Options_Effects = +{ + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Effects Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-160-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + float pos = 0; + + fr.add(menuitemcheck_spawn(_("Show Framerate"), dp("showfps", "show_fps"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Bloom"), "r_bloom", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Simple Textures"), "r_drawflat", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Paletted Rendering"), "r_softwarebanding", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("HDR"), "r_hdr_irisadaptation", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Coronas"), "r_coronas", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("High Res Textures"), "gl_load24bit", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Relief Mapping"), "r_glsl_offsetmapping", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Realtime Dynamic Lights"), "r_shadow_realtime_dlight", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Realtime World Lighting"), "r_shadow_realtime_world", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + + + fr.add(menuitemslider_spawn(_("Particle Density"), "r_part_density", '0.25 4 0.25', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + + fr.add(menuitemcombo_spawn(_("Water Effects"), "r_waterstyle", '280 8', _( + "1 \"Classic\" " + "2 \"Ripples\" " + "3 \"Reflections\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("View Projection"), "r_projection", '280 8', _( + "0 \"Standard\" " + "1 \"Stereographic / Pannini\" " + "2 \"Fish-Eye\" " + "3 \"Panoramic\" " + "4 \"Lambert Azimuthal Equal-Area\" " + "5 \"Equirectangular\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("View Projection Fov"), "ffov", '280 8', _( + "90 \"Normal\" " + "180 \"180 degrees\" " + "270 \"270 degrees\" " + "360 \"360 degrees\" " + )), fl, [0, pos], [0, 8]); pos += 8; + + fr.add(spawn(mitem_text, item_text:_("Apply"), item_command:"vid_restart", item_scale:8, item_flags:IF_RIGHTALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [0, pos], [-8, 8]); pos += 8; + + addmenuback(m); +}; + diff --git a/menu/options_hud.qc b/menu/options_hud.qc new file mode 100644 index 00000000..6e3381ca --- /dev/null +++ b/menu/options_hud.qc @@ -0,0 +1,68 @@ +nonstatic void(mitem_desktop desktop) M_Options_Hud = +{ + local float i; + local float h; + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Hud Configurations"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + h = 200; + h *= 0.5; //and halve it + + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [banner.item_size_x*-0.5, -h-32], [banner.item_size_x*0.5, -h-8]); + + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); + + float fs = search_begin("huds/*.cfg", TRUE, TRUE); + float fc = search_getsize(fs); + + float y = 0; + string fname = "huds/hud_default.cfg"; + string iname = "Default"; + string dname = iname; + if ((int)whichpack(fname)) + { + dname = GetFirstLineComment(fname, iname); + fr.add(spawn(mitem_text, item_text:dname, item_command:sprintf("set plug_sbar 3; cvarreset hud_*; exec \"%s\"; hud_recalculate", fname), item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], [0, 16]); + } + else + fr.add(spawn(mitem_text, item_text:dname, item_command:"cvarreset hud_*; set plug_sbar 0", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], [0, 16]); + y += 16; + + //add the options + for (i = 0; i < fc; i++) + { + fname = search_getfilename(fs, i); + iname = substring(fname, 5, -5); + if (iname == "hud_default") + continue; + if (substring(fname, 0, 4) == "hud_") + iname = substring(fname, 4, -1); + dname = GetFirstLineComment(fname, iname); +// print(sprintf("\"%s\" \"%s\" - \"%s\"\n", fname, iname, dname)); + if (dname) + { + fr.add(spawn(mitem_text, item_text:dname, item_command:sprintf("set plug_sbar 3; cvarreset hud_*; exec \"%s\"; hud_recalculate", fname), item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], [0, 16]); + y += 16; + } + } + search_end(fs); + + + //random art for style +#if 1//def CSQC + m.addm(spawn (mitem_spinnymodel, item_text: "progs/g_nail2.mdl", zbias:-16), [-160-60, 12*-16/2], [-60, 12*16/2]); +#else + //menuqc doesn't support entities. shove some random crappy static image there instead. + local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); + m.addm(plaque, [(-160-plaque.item_size_x)*0.5, 12*-16/2], [(-160+plaque.item_size_x)*0.5, 12*16/2]); +#endif + + addmenuback(m); +}; diff --git a/menu/options_keys.qc b/menu/options_keys.qc new file mode 100644 index 00000000..e0b91a8d --- /dev/null +++ b/menu/options_keys.qc @@ -0,0 +1,130 @@ +const static struct +{ + string name; + string cmd; +} binds[] = +{ + {_("Forwards"), "+forward"}, + {_("Back"), "+back"}, + {_("Move Left"), "+moveleft"}, + {_("Move Right"), "+moveright"}, + {_("Turn Left"), "+left"}, + {_("Turn Right"), "+right"}, + {_("Look Up"), "+lookup"}, + {_("Look Down"), "+lookdown"}, + {_("Swim Up"), "+moveup"}, + {_("Swim Down"), "+movedown"}, + {_("Center view"), "centerview"}, + {_("Jump"), "+jump"}, + {_("Attack"), "+attack"}, + {_("Next Weapon"), "impulse 10"}, + {_("Prev Weapon"), "impulse 12"}, + {_("Scores"), "+showscores"}, + {_("Server Chat"), "messagemode"}, + {_("Team Chat"), "messagemode2"}, + {_("Voice Chat"), "+voip"}, +// {_("Mouse Look"), "+mlook"}, +// {_("Keyboard Look"), "+klook"}, + {_("Strafe"), "+strafe"}, + {_("Run"), "+speed"}, + {0, 0}, + {_("Primary Weapon"), "weapon 1"}, + {_("Secondary Weapon"), "weapon 2"}, + {_("Last Resort"), "weapon 3"}, + {_("Melee"), "weapon 4"}, + {_("Quick Primary"), "+slot1"}, + {_("Quick Secondary"), "+slot2"}, + {_("Quick Tertiary"), "+slot3"}, + {_("Quick Melee"), "+slot4"}, + {_("Grenade 1"), "gren1"}, + {_("Grenade 2"), "gren2"}, + {_("Prime Grenade 1"), "primeone"}, + {_("Prime Grenade 2"), "primetwo"}, + {_("Throw Grenade"), "throwgren"}, + {0, 0}, + {_("Class Special"), "special"}, + {_("Class Menu"), "menu"}, + {_("Change Class"), "changeclass"}, + {_("Change Team"), "changeteam"}, + {_("Drop Flag"), "dropitems"}, + {_("Discard Ammo"), "discard"}, + {_("Call For Help"), "saveme"}, + {_("Inventory"), "inv"}, + {_("Flag Status"), "flaginfo"}, + {_("Map Help"), "maphelp"}, + + {0, 0}, + {_("Ready Up"), "ready"}, + {_("Break Match"), "break"}, + {_("Spectate"), "observe"}, + {_("Join Match"), "join"}, +}; +void(mitem_desktop desktop) M_Options_Keys = +{ + float i; + float h; + + //create the menu, give it focus, and make sure its displayed over everything else. + mitem_exmenu m = spawn(mitem_exmenu, item_text:_("Key Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + //figure out the size of the stuff +// h = sizeof(binds) / sizeof(binds[0]); +// h *= 8; + h = 200; + h *= 0.5; //and halve it + + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [banner.item_size_x*-0.5, -h-32], [banner.item_size_x*0.5, -h-8]); + + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_OWN_MIN, [-140, -h], [280, h*2]); + + float f = fopen("bindlist.lst", FILE_READ); + if (f >= 0) + { + //throw a load of bind options onto it by reading from the array. + for (i = 0; ; ) + { + string line = fgets(f); + if not (line) + break; //eof + float args = tokenize(line); + if (!args) + continue; //blank line + string c = argv(0); + string n = argv(1); + string t = argv(2); + if (c == "-") //command only + { + if (n != "") + { + mitem it = menuitemtext_spawn(n, "", 8); + it.item_flags &= ~IF_SELECTABLE; + fr.add(it, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_OWN_MIN|RS_Y_MAX_OWN_MIN, [-it.item_size_x/2, i], it.item_size); + } + } + else + fr.add(menuitembind_spawn(n, c, '280 8'), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, i], '0 8'); + i += 8; + } + fclose(f); + } + else + { + //throw a load of bind options onto it by reading from the array. + for (i = 0; i < sizeof(binds) / sizeof(binds[0]); i++) + { + if (binds[i].name == "") //no name is a spacer + continue; + fr.add(menuitembind_spawn(binds[i].name, binds[i].cmd, '280 8'), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, (i*8)], '0 8'); + } + } + + //and give us a suitable menu tint too, just because. + addmenuback(m); +}; diff --git a/menu/options_particles.qc b/menu/options_particles.qc new file mode 100644 index 00000000..fa52998a --- /dev/null +++ b/menu/options_particles.qc @@ -0,0 +1,136 @@ +//menu that configues r_particledesc according to the files available in the particles/ subdir, including the (known) internal effects. + +class particlesmenu : mitem_frame +{ + string thelist; + void() particlesmenu = + { + thelist = cvar_string("r_particledesc"); + }; + virtual void() item_remove = + { + cvar_set("r_particledesc", thelist); + }; + + //to reconfigure colours for when something changees. + nonvirtual void() UpdateSelections = + { + float sc = tokenize(thelist); + for (mitem ch = item_children; ch; ch = ch.item_next) + { + ch.item_rgb = '1 0.5 0.5'; + for (float i = 0; i < sc; i++) + { + if (!strcasecmp(argv(i), ch.item_command)) + { + ch.item_rgb = '1 1 1'; + break; + } + } + } + }; + virtual void(mitem fromitem, string cmd) item_execcommand = + { + float sc = tokenize(thelist); + for (float i = 0; i < sc; i++) + { + if (!strcasecmp(argv(i), cmd)) + { + thelist = strtrim(strcat(strtrim(substring(thelist, 0, argv_start_index(i))), " ", strtrim(substring(thelist, argv_end_index(i), -1)))); + UpdateSelections(); + return; + } + } + + if (strstrofs(cmd, "\t") >= 0 || strstrofs(cmd, " ") >= 0 || strstrofs(cmd, "\"") >= 0 || strstrofs(cmd, ";") >= 0 || strstrofs(cmd, "\n") >= 0) + thelist = strtrim(strcat(thelist, " \"", cmd, "\"")); + else + thelist = strtrim(strcat(thelist, " ", cmd)); + UpdateSelections(); + }; +}; + +string(string fname, string dflt) GetFirstLineComment = +{ + float f = fopen(fname, FILE_READ); + if (f < 0) + return 0; + string l = strtrim(fgets(f)); + fclose(f); + if (!strcasecmp(substring(l, 0, 9), "//private")) + return 0; + if (!strcasecmp(substring(l, 0, 8), "//hidden")) + return 0; + if (!strcasecmp(substring(l, 0, 7), "//desc:")) + return strtrim(substring(l, 7, -1)); +// if (substring(l, 0, 1) == "#") +// return strtrim(substring(l, 1, -1)); + return dflt; +}; + +nonstatic void(mitem_desktop desktop) M_Options_Particles = +{ + float y = -8; + float h; + + //create the menu, give it focus, and make sure its displayed over everything else. + mitem_exmenu m = spawn(mitem_exmenu, item_text:_("Particles Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + //figure out the size of the stuff +// h = sizeof(binds) / sizeof(binds[0]); +// h *= 8; + h = 200; + h *= 0.5; //and halve it + + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [banner.item_size_x*-0.5, -h-32], [banner.item_size_x*0.5, -h-8]); + + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + particlesmenu fr = spawn(particlesmenu, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); + + //FIXME: this stuff should be listed in order of selection, to reflect the priorities given to the various effects. + + //FIXME: these should not be listed if its a no-compat/no-legacy build. this'll do for now, but its a bit wrong + if (checkextension("FTE_PART_NAMESPACE_EFFECTINFO")) + { + fr.add(spawn(mitem_text, item_text:"Classic Particles", item_command:"classic", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); + fr.add(spawn(mitem_text, item_text:"High Quality", item_command:"high", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); + fr.add(spawn(mitem_text, item_text:"TimeServ's Shaft", item_command:"tsshaft", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); + + string efi = GetFirstLineComment("effectinfo.txt", "Effectinfo"); + if (efi) + fr.add(spawn(mitem_text, item_text:efi, item_command:"effectinfo", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); + } + + float fs; + fs = search_begin("particles/*.cfg", TRUE, TRUE); + for (float c = search_getsize(fs), float i = 0; i < c; i++) + { + string fname = search_getfilename(fs, i); + string iname = substring(fname, 10, -5); + string dname = GetFirstLineComment(fname, iname); + if (dname && !fr.findchildcmd(iname)) + fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); + } + search_end(fs); + fs = search_begin("particles/*/*.cfg", TRUE, TRUE); + for (float c = search_getsize(fs), float i = 0; i < c; i++) + { + string fname = search_getfilename(fs, i); + string iname = substring(fname, 10, -5); + string dname = GetFirstLineComment(fname, iname); + if (dname && !fr.findchildcmd(iname)) + fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); + } + search_end(fs); + + fr.UpdateSelections(); + + //and give us a suitable menu tint too, just because. + addmenuback(m); +}; diff --git a/menu/options_video.qc b/menu/options_video.qc new file mode 100644 index 00000000..5582e319 --- /dev/null +++ b/menu/options_video.qc @@ -0,0 +1,95 @@ +nonstatic void(mitem_desktop desktop) M_Options_Video = +{ + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Video Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-160-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + float pos = 0; + + pos += 8; + fr.add(spawn(mitem_text, item_text:_("Apply / Restart"), item_command:"vid_restart", item_scale:8, item_flags:IF_RIGHTALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [0, pos], [-8, 8]); pos += 8; + pos += 8; + + if (cvar_type("vid_renderer")) fr.add(menuitemcombo_spawn(_("Renderer"), "vid_renderer", '280 8', cvar_string("_vid_renderer_opts")), fl, [0, pos], [0, 8]); pos += 8; + + //add the options + if (!dp_workarounds) + { + fr.add(menuitemcombo_spawn(_("Display Mode"), "vid_fullscreen", '280 8', + "0 \"Windowed\" " + "1 \"Fullscreen\" " + "2 \"Borderless Windowed\" " + ), fl, [0, pos], [0, 8]); pos += 8; + } + else + { + fr.add(menuitemcheck_spawn(_("Fullscreen"), "vid_fullscreen", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + } + if (cvar_type("vid_resizable")) fr.add(menuitemcheck_spawn(_("Resizable"), "vid_resizable", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Anti-Aliasing"), dp("vid_samples", "vid_multisample"), '280 8', + "0 \"Off\" " + "2 \"2x\" " + "4 \"4x\" " + ), fl, [0, pos], [0, 8]); pos += 8; + + //as far as video mode selections go, this is shite. + //should probably have an aspect+modes option instead, but that makes the combo really messy. especially as that would be two cvars. + fr.add(menuitemcombo_spawn(_("Video Width"), "vid_width", '280 8', _( + "0 \"Default\" " + "640 \"640\" " + "800 \"800\" " + "1024 \"1024\" " + "1280 \"1280\" " + "1920 \"1920\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Video Height"), "vid_height", '280 8', _( + "0 \"Default\" " + "480 \"480\" " + "600 \"600\" " + "768 \"768\" " + "720 \"720\" " + "1080 \"1080\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Video Zoom"), "vid_conautoscale", '280 8', _( + "0 \"Default\" " + "1.5 \"x1.5\" " + "2 \"x2\" " + "4 \"x4\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Colour Depth"), dp("vid_bitsperpixel", "vid_bpp"), '280 8', _( + "16 \"16bit\" " + "32 \"24bit\" " //alpha doesn't count. + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Refresh Rate"), "vid_displayfrequency", '280 8', _( + "0 \"Default\" " + // "60 \"60\" " + // "75 \"75\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("VSync"), dp("vid_vsync", "vid_wait"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn(_("Show Framerate"), dp("showfps", "show_fps"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("View Size"), "viewsize", '50 120 10', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Field Of View"), "fov", '50 140 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Gamma"), "gamma", '1.3 0.5 -0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Contrast"), "contrast", '0.7 2 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Brightness"), "brightness", '0 0.4 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Hardware Gamma"), "vid_hardwaregamma", '280 8', + "0 \"Off\" " + "1 \"Auto\" " + "2 \"Soft\" " + "3 \"Hard\" " + "4 \"Scene Only\" " + ), fl, [0, pos], [0, 8]); pos += 8; + + addmenuback(m); +}; + diff --git a/menu/presets.qc b/menu/presets.qc new file mode 100644 index 00000000..601bd97d --- /dev/null +++ b/menu/presets.qc @@ -0,0 +1,102 @@ +/*************************************************************************** +Uses the engine command to apply the preset, and tries an exec instead if a config file exists. +Doesn't track the current one or anything. +Really simple and stupid menu. +no background tint, so the game is still visible so you can preview it. + +you should probably remove the fps_preset part. I left it in so that I don't have to bother with providing cfg files. note that this isn't a valid solution for dp, but whatever. +the great thing about providing source is that you can change it. +you can instead just shove your preset settings directly into the quotes instead of exec. +*/ + +struct +{ + string name; + string preset; + string config; +} presets[] = +{ + {"Simple", "286", "configs/preset_simple.cfg"}, + {"Fast", "fast", "configs/preset_fast.cfg"}, + {"Regression", "vanilla", "configs/preset_vanilla.cfg"}, + {"Faithful", "normal", "configs/preset_faithful.cfg"}, + {"Nice", "nice", "configs/preset_nice.cfg"}, + {"Realtime", "realtime", "configs/preset_realtime.cfg"} +}; +nonstatic float(string fname) checkfileexists = +{ + if (dp_workarounds) + { + float sh = search_begin(fname, FALSE, TRUE); + float result = FALSE; + if (sh >= 0) + { + result = !!search_getsize(sh); + search_end(sh); + } + return result; + } + else + { + //FTE's whichpack returns empty if its not in a pack, and null if its not found anywhere. + if (whichpack(fname)) + return TRUE; + return FALSE; + } +}; +nonstatic void(mitem_desktop desktop) M_Preset = +{ + local float i; + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Graphical Presets"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-60-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + + float fs, y=0; + fs = search_begin("configs/preset_*.cfg", TRUE, TRUE); + float c = search_getsize(fs); + for (i = 0; i < c; i++) + { + string fname = search_getfilename(fs, i); + string iname = substring(fname, 15, -5); + string dname = GetFirstLineComment(fname, iname); + iname = sprintf("exec \"configs/preset_%s.cfg\";vid_reload", iname); + if (dname && !fr.findchildcmd(iname)) + { + fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, y], '100 16'); + y+=16; + } + } + search_end(fs); + if (c <= 0) + { + //add the default options + for (i = 0, float pos = 0; i < presets.length; i++) + { + fr.add(spawn(mitem_text, item_text:presets[i].name, item_command:sprintf("fps_preset %s", presets[i].preset), item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [100, 16]); + pos += 16; + } + } + + //random art for style +#if 1//def CSQC + m.addm(spawn (mitem_spinnymodel, item_text: "progs/suit.mdl"), [-160, 12*-16/2], [0, 12*16/2]); +#else + //menuqc doesn't support entities. shove some random crappy static image there instead. + local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); + m.addm(plaque, [(-160-plaque.item_size_x)*0.5, 12*-16/2], [(-160+plaque.item_size_x)*0.5, 12*16/2]); +#endif + + addmenuback(m); +}; diff --git a/menu/quit.qc b/menu/quit.qc new file mode 100644 index 00000000..f8eb7b13 --- /dev/null +++ b/menu/quit.qc @@ -0,0 +1,46 @@ +/*************************************************************************** +Quit menu. Quite lame for now. +*/ +float() cvars_haveunsaved = #0; +nonstatic void(mitem_desktop desktop) M_Quit = +{ + local float pos; + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Options"), item_flags:IF_SELECTABLE, item_command:"m_main"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + //center the actual items + pos = (16/-2)*(2); + + //draw title art above the options +// mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); +// m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [(-160-banner.item_size_x)*0.5, pos-32], [(-160+banner.item_size_x)*0.5, pos-8]); + + if (cvars_haveunsaved()) + { + m.add(spawn(mitem_text, item_text:"Save configuration?", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos-(8+16)], [0, pos-8]); pos += 16; + + m.add(spawn(mitem_text, item_text:"Save and quit", item_command:"m_pop;cfg_save;quit", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos], [0, pos+16]); pos += 16; + m.add(spawn(mitem_text, item_text:"Quit and discard settings", item_command:"m_pop;quit", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos], [0, pos+16]); pos += 16; + m.add(spawn(mitem_text, item_text:"Keep playing.", item_command:"m_pop;m_main", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos], [0, pos+16]); pos += 16; + } + else + { + m.add(spawn(mitem_text, item_text:"Really Quit?", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos-(8+16)], [0, pos-8]); pos += 16; + + m.add(spawn(mitem_text, item_text:"Yes, I'm late for work.", item_command:"m_pop;quit", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos], [0, pos+16]); pos += 16; + m.add(spawn(mitem_text, item_text:"No, keep playing!", item_command:"m_pop;m_main", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, pos], [0, pos+16]); pos += 16; + } + + //random art for style +#if 1//def CSQC + m.add(spawn (mitem_spinnymodel, item_text: "progs/suit.mdl"), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [0, 12*-16/2], [160, 12*16/2]); +#else + //menuqc doesn't support entities. shove some random crappy static image there instead. + local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); + m.addm(plaque, [(160-plaque.item_size_x)*0.5, 12*-16/2], [(160+plaque.item_size_x)*0.5, 12*16/2]); +#endif + addmenuback(m); +}; \ No newline at end of file diff --git a/menu/servers.qc b/menu/servers.qc new file mode 100644 index 00000000..c2560c78 --- /dev/null +++ b/menu/servers.qc @@ -0,0 +1,411 @@ +//very very basic server browser. +//this was written as an example for the api, rather than a truely usable server browser. + +//WARNING: make sure you only create one server browser widget otherwise they'll fight each other + +#ifndef MOD_GAMEDIR +//look up what its meant to be. +//#define MOD_GAMEDIR cvar_string("game") +#endif + +#include "../menusys/mitem_menu.qc" //subwindow + +var float autocvar_sb_shownumplayers = 1; +var float autocvar_sb_showmaxplayers = 0; +var float autocvar_sb_showfraglimit = 0; +var float autocvar_sb_showtimelimit = 0; +var float autocvar_sb_showping = 1; +var float autocvar_sb_showgamedir = 0; +var float autocvar_sb_showaddress = 0; +var float autocvar_sb_showmap = 1; +var float autocvar_sb_showname = 1; + +//#define COLUMN(width, sortname, title, draw) +#define COLUMN_NUMPLAYERS COLUMN(2*8, numplayers, "Pl", ui.drawstring(pos, sprintf("%-2g", gethostcachenumber(field_numplayers, sv)), '8 8', col, 1, 0);) +#define COLUMN_MAXPLAYERS COLUMN(2*8, maxplayers, "MP", ui.drawstring(pos, sprintf("%-2g", gethostcachenumber(field_maxplayers, sv)), '8 8', col, 1, 0);) +#define COLUMN_PING COLUMN(4*8, ping, "Ping", ui.drawstring(pos, sprintf("%-4g", gethostcachenumber(field_ping, sv)), '8 8', col, 1, 0);) +#define COLUMN_FRAGLIMIT COLUMN(4*8, fraglimit, "FL", ui.drawstring(pos, sprintf("%-3g", gethostcachenumber(field_fraglimit, sv)), '8 8', col, 1, 0);) +#define COLUMN_TIMELIMIT COLUMN(4*8, timelimit, "TL", ui.drawstring(pos, sprintf("%-3g", gethostcachenumber(field_timelimit, sv)), '8 8', col, 1, 0);) +#define COLUMN_GAMEDIR COLUMN(8*8, gamedir, "Gamedir", ui.drawstring(pos, sprintf("%-.8s", gethostcachestring(field_gamedir, sv)), '8 8', col, 1, 0);) +#define COLUMN_ADDRESS COLUMN(16*8, address, "Address", ui.drawstring(pos, sprintf("%-.16s", gethostcachestring(field_address, sv)), '8 8', col, 1, 0);) +#define COLUMN_MAP COLUMN(8*8, map, "Map", ui.drawstring(pos, sprintf("%-.8s", gethostcachestring(field_map, sv)), '8 8', col, 1, 0);) +#define COLUMN_HOSTNAME COLUMN(64*8, name, "Name", ui.drawstring(pos, sprintf("%s", gethostcachestring(field_name, sv)), '8 8', col, 1, 0);) +//FIXME: add a little * icon before the hostname for favourites or something + +#define COLUMNS COLUMN_NUMPLAYERS COLUMN_MAXPLAYERS COLUMN_PING COLUMN_FRAGLIMIT COLUMN_TIMELIMIT COLUMN_GAMEDIR COLUMN_ADDRESS COLUMN_MAP COLUMN_HOSTNAME + +class mitem_servers : mitem +{ + float server_selected; + mitem_vslider slider; + float dbltime; + float dobound; + + void() mitem_servers = + { + dbltime = cltime - 10; + this.item_flags |= IF_SELECTABLE; + server_selected = -1; + + //clear the filter + resethostcachemasks(); +#ifdef MOD_GAMEDIR + if (MOD_GAMEDIR != "") + { + //constrain the list to only servers with the right gamedir. + sethostcachemaskstring(0, gethostcacheindexforkey("gamedir"), MOD_GAMEDIR, SLIST_TEST_EQUAL); + } +#endif + //sort by ping by default + sethostcachesort(gethostcacheindexforkey("ping"), FALSE); + //(re)query the servers. + refreshhostcache(); + + resorthostcache(); + }; + + virtual void(vector pos) item_draw = + { + local float sv, maxsv = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT); + local float maxy = self.item_size_y; + float left = pos_x; + + local vector omin = ui.drawrectmin, omax = ui.drawrectmax; + local vector cmin = pos + '0 8', cmax = pos + item_size; + + cmin_x = max(omin_x, cmin_x); + cmin_y = max(omin_y, cmin_y); + cmax_x = min(omax_x, cmax_x); + cmax_y = min(omax_y, cmax_y); + + slider.maxv = maxsv - (floor(maxy/8) - 1); + + //constrain the view the lazy way. + if (dobound) + { + dobound = FALSE; + if (slider.val < 0) + slider.val = 0; + while (slider.val + floor(maxy/8) - 1 <= server_selected) + slider.val+=1; + while (server_selected < slider.val && slider.val > 0) + slider.val-=1; + } + + float field_name = gethostcacheindexforkey("name"); + float field_ping = gethostcacheindexforkey("ping"); + float field_numplayers = gethostcacheindexforkey("numhumans"); + if (field_numplayers < 0) + field_numplayers = gethostcacheindexforkey("numplayers"); + float field_maxplayers = gethostcacheindexforkey("maxplayers"); + float field_gamedir = gethostcacheindexforkey("gamedir"); + if (field_gamedir < 0) + field_gamedir = gethostcacheindexforkey("mod"); + float field_address = gethostcacheindexforkey("cname"); + float field_map = gethostcacheindexforkey("map"); + float field_timelimit = gethostcacheindexforkey("timelimit"); + float field_fraglimit = gethostcacheindexforkey("fraglimit"); + + maxy = ceil(maxy/8) - 1; + if (maxsv > slider.val + maxy) + maxsv = slider.val + maxy; + + float sort = gethostcachevalue(SLIST_SORTFIELD); + string colkey; +#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {if (ui.mousepos[0] > pos_x && ui.mousepos[1] < pos_y+8) colkey = #sortname; pos_x += width+8;} + COLUMNS +#undef COLUMN + + vector col; + pos_x = left; +#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {col = '1 1 1'; if (sort == field_##sortname) col_z = 0; if (colkey == #sortname) col_x = 0; ui.drawstring(pos, title, '8 8', col, 1, 0); pos_x += width+8;} + COLUMNS +#undef COLUMN + + //make sure things get cut off if we have too many rows (or fractional start) + ui.setcliparea(cmin[0], cmin[1], cmax[0] - cmin[0], cmax[1] - cmin[1]); + + pos_y += 8 * (1-(slider.val-floor(slider.val))); + for (float y=pos_y, sv = max(0, floor(slider.val)); sv < maxsv; sv+=1) + { + col = (sv&1)?'0.1 0.1 0.1':'0.15 0.1 0.05'; + drawfill([left, y], [item_size_x,8], col, 0.8, 0); + y += 8; + } + for ( sv = max(0, floor(slider.val)); sv < maxsv; sv+=1) + { + col = ((server_selected==sv)?'1 1 0':'1 1 1'); + + //if isproxy + //if islocal + //if isfavorite + + pos_x = left; +#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {draw pos_x += width+8; } + COLUMNS +#undef COLUMN + pos_y += 8; + } + + ui.setcliparea(omin_x, omin_y, omax_x - omin_x, omax_y - omin_y); + }; + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + float displaysize; + string addr; + /*just sink all inputs*/ + if (!down) + return FALSE; + if (scan != K_MOUSE1) + dbltime = cltime - 10; + if (scan == K_MOUSE1) + { + float news = ui.mousepos[1] - (pos_y+8); + news = floor(news / 8); + if (news == -1) + { + string colkey = ""; +#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {if (ui.mousepos[0] > pos_x) colkey = #sortname; pos_x += width+8;} + COLUMNS +#undef COLUMN + if (colkey != "") + { + float fld = gethostcacheindexforkey(colkey); + if (colkey == "numplayers") + { + //favour descending order + sethostcachesort(fld, (gethostcachevalue(SLIST_SORTFIELD) != fld) || !gethostcachevalue(SLIST_SORTDESCENDING)); + } + else + { + //favour ascending order + sethostcachesort(fld, (gethostcachevalue(SLIST_SORTFIELD) == fld) && !gethostcachevalue(SLIST_SORTDESCENDING)); + } + resorthostcache(); //tell the engine that its okay to resort everything. + dobound = TRUE; + } + } + if (news < 0 || news >= gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT)) + return FALSE; + + news += floor(slider.val); + + if (server_selected == news && dbltime > cltime) + { + //connect on double clicks. because we can. + addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected); + if (addr) + localcmd(sprintf("m_pop;connect \"%s\"\n", addr)); + } + else + server_selected = news; + dobound = TRUE; + + dbltime = cltime + 0.5; + } + else if (scan == K_ENTER) + { //connect normally + addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected); + if (addr) + localcmd(sprintf("m_pop;connect \"%s\"\n", addr)); + } + else if (scan == 's') + { //s = join as a spectator + addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected); + if (addr) + localcmd(sprintf("m_pop;observe \"%s\"\n", addr)); + } + else if (scan == 'j') + { //s = join as a spectator + addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected); + if (addr) + localcmd(sprintf("m_pop;join \"%s\"\n", addr)); + } + else if (scan == K_UPARROW || scan == K_MWHEELUP) + { + this.server_selected -= 1; + if (this.server_selected < 0) + { + this.server_selected = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT); + if (this.server_selected) + this.server_selected -= 1; + } + dobound = TRUE; + } + else if (scan == K_DOWNARROW || scan == K_MWHEELDOWN) + { + this.server_selected += 1; + if (this.server_selected >= gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT)) + this.server_selected = 0; + dobound = TRUE; + } + else if (scan == K_PGUP) + { + displaysize = (item_size[1]-8)/(8); //this many rows + displaysize = floor(displaysize*0.5); + if (displaysize < 1) + displaysize = 1; + this.server_selected -= displaysize ; + if (this.server_selected < 0) + this.server_selected = 0; + dobound = TRUE; + } + else if (scan == K_PGDN) + { + displaysize = (item_size[1]-8)/(8); //this many rows + displaysize = floor(displaysize*0.5); + if (displaysize < 1) + displaysize = 1; + this.server_selected += displaysize; + if (this.server_selected >= gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT)) + this.server_selected = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT)-1; + dobound = TRUE; + } + else if (scan == K_HOME) + { + this.server_selected = 0; + dobound = TRUE; + } + else if (scan == K_END) + { + this.server_selected = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT)-1; + if (this.server_selected < 0) + this.server_selected = 0; + dobound = TRUE; + } + else if (char == 'r' || char == 'R' || scan == K_F5) + { + refreshhostcache(); + resorthostcache(); + } + else + return FALSE; + return TRUE; + }; +}; + +class mitem_servers_players : mitem +{ + mitem_servers listing; + + void() mitem_servers_players = + { +// this.item_flags |= IF_SELECTABLE; + }; + + virtual void(vector pos) item_draw = + { + float player; + float y; + float m; + vector opos = pos; + if (listing.server_selected < 0) + return; + for (player = 0, y = 0; player < 256; player++) + { + string playerinfo = gethostcachestring(gethostcacheindexforkey(sprintf("player%g", player)), listing.server_selected); + if (!playerinfo) + break; + tokenize(playerinfo); + float userid = stof(argv(0)); + float frags = stof(argv(1)); + float ontime = stof(argv(2)); + float ping = stof(argv(3)); + string name = argv(4); + string skin = argv(5); + vector top = stov(argv(6)); + vector bot = stov(argv(7)); + + drawfill(pos, '16 4', top, 1, 0); + drawfill(pos+'0 4 0', '16 4', bot, 1, 0); + drawstring(pos, sprintf("%g", frags), '8 8', '1 1 1', 1, 0); + drawstring(pos+'20 0', name, '8 8', '1 1 1', 1, 0); + pos_y += 8; + if (++y == 8) + { + y-= 8; + pos_y = opos_y; + pos_x += 16*8; + } + } + + if (y) + { + pos_y = opos_y; + pos_x += 16*6; + y = 0; + } +// drawtextfield(opos, item_size, 3, gethostcachestring(gethostcacheindexforkey("serverinfo"), listing.server_selected)); + m = tokenizebyseparator(gethostcachestring(gethostcacheindexforkey("serverinfo"), listing.server_selected), "\\"); + for(player = 1; player <= m; player += 2) + { + drawtextfield(pos, '64 8', 6, argv(player)); + drawtextfield(pos+'68 0', [32*8-40, 8], 3, argv(player+1)); + + pos_y += 8; + if (++y == 8) + { + y-= 8; + pos_y -= 8*8; + pos_x += 32*8; + } + } + }; +}; + + +nonstatic void(mitem_desktop desktop) M_Servers = +{ + mitem_menu o; + + if (assumefalsecheckcommand("menu_servers") && argv(1) != "force") + { + localcmd("menu_servers\n"); + return; + } + +#ifdef CSQC + if not (checkextension("FTE_CSQC_SERVERBROWSER")) + { + print(_("Sorry, your client does not support FTE_CSQC_SERVERBROWSER\n")); + return; + } +#endif + + o = (mitem_menu)desktop.findchildtext(_("Servers List")); + if (o) + o.totop(); + else + { +#if 1 + mitem_exmenu m; + m = spawn(mitem_exmenu, item_text:_("Options"), item_flags:IF_SELECTABLE, item_command:"m_main"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); +#else + mitem_menu m; + m = menu_spawn(desktop, _("Servers List"), '320 200'); + m.item_command = "m_main"; + m.item_flags |= IF_RESIZABLE; + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); +#endif + + mitem_vslider sl = spawn(mitem_vslider, stride:4, item_flags:IF_SELECTABLE); + mitem_servers ls = spawn(mitem_servers, slider:sl); + + m.add(ls, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '-16 -68'); + m.add(spawn(mitem_servers_players, listing:ls), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, [8*20, -8*8], [0, -8*0]); + m.add(sl, RS_X_MIN_PARENT_MAX|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, [-16, 8], [0, -68]); + + m.add(menuitemcheck_spawn(_("Ping"), "sb_showping", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*8], [8*20, -8*7]); + m.add(menuitemcheck_spawn(_("Address"), "sb_showaddress", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*7], [8*20, -8*6]); + m.add(menuitemcheck_spawn(_("Map"), "sb_showmap", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*6], [8*20, -8*5]); + m.add(menuitemcheck_spawn(_("Gamedir"), "sb_showgamedir", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*5], [8*20, -8*4]); + m.add(menuitemcheck_spawn(_("NumPlayers"), "sb_shownumplayers", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*4], [8*20, -8*3]); + m.add(menuitemcheck_spawn(_("MaxPlayers"), "sb_showmaxplayers", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*3], [8*20, -8*2]); + m.add(menuitemcheck_spawn(_("Fraglimit"), "sb_showfraglimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*2], [8*20, -8*1]); + m.add(menuitemcheck_spawn(_("Timelimit"), "sb_showtimelimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*1], [8*20, -8*0]); + } +}; \ No newline at end of file diff --git a/menusys/mitem_bind.qc b/menusys/mitem_bind.qc new file mode 100644 index 00000000..08ef94b7 --- /dev/null +++ b/menusys/mitem_bind.qc @@ -0,0 +1,108 @@ +/*************************************************************************** +key binding item. +interactable - queries binds for a command, and accepts new scan codes to bind for its given command. +*/ +class mitem_bind : mitem +{ + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void(mitem newfocus, float flag) item_focuschange; + + void() mitem_bind = + { + item_scale = item_size[1]; + + item_flags |= IF_SELECTABLE; + + item_text = strzone(item_text); + item_command = strzone(item_command); + }; + virtual void() item_remove = + { + strunzone(item_text); + strunzone(item_command); + }; +}; +#define menuitembind_spawn(text,command,sz) \ + spawn(mitem_bind, \ + item_text: text, \ + item_command: command, \ + item_size: sz \ + ) + +void(vector pos) mitem_bind::item_draw = +{ + /*this is not my API...*/ + tokenize(findkeysforcommand(self.item_command)); + string key1 = argv(0); + string key2 = argv(1); + if (key1 != "") key1 = (key1=="-1")?"":keynumtostring(stof(key1)); + if (key2 != "") key2 = (key2=="-1")?"":keynumtostring(stof(key2)); + + super::item_draw(pos); + pos_x += self.item_size_x / 2; + + if (self.item_flags & IF_INTERACT) + { + ui.drawstring(pos, "Please press a key", '1 1 0' * self.item_scale, menuitem_textcolour(self), self.item_alpha, 0); + } + else + { + ui.drawstring(pos, key1, '1 1 0' * self.item_scale, menuitem_textcolour(self), self.item_alpha, 0); + pos_x += stringwidth(key1, TRUE, '1 1 0'*self.item_scale); + + if (key2 != "") + { + ui.drawstring(pos, " or ", '1 1 0' * self.item_scale, menuitem_textcolour(self), self.item_alpha, 0); + pos_x += stringwidth(" or ", TRUE, '1 1 0'*self.item_scale); + + ui.drawstring(pos, key2, '1 1 0' * self.item_scale, menuitem_textcolour(self), self.item_alpha, 0); +// pos_x += stringwidth(key2, TRUE, '1 1 0'*self.item_scale); + } + } +}; +float(vector pos, float scan, float char, float down) mitem_bind::item_keypress = +{ + if (!down) + return FALSE; + + if (self.item_flags & IF_INTERACT) + { + if (scan == K_ESCAPE) + { + } + else if (scan) + localcmd(sprintf("bind \"%s\" \"%s\"\n", keynumtostring(scan), self.item_command)); + else + return FALSE; + self.item_flags -= IF_INTERACT; + return TRUE; + } + else + { + if (scan == K_ENTER || (scan == K_MOUSE1 && mouseinbox(pos, self.item_size))) + { + self.item_flags |= IF_INTERACT; + return TRUE; + } + if (scan == K_DEL || scan == K_BACKSPACE) + { + /*again, this is not my API...*/ + tokenize(findkeysforcommand(self.item_command)); + string key1 = argv(0); + string key2 = argv(1); + if (key1 != "") key1 = (key1=="-1")?"":keynumtostring(stof(key1)); + if (key2 != "") key2 = (key2=="-1")?"":keynumtostring(stof(key2)); + if (key1 != "") localcmd(sprintf("bind \"%s\" \"\"\n", key1)); + if (key2 != "") localcmd(sprintf("bind \"%s\" \"\"\n", key2)); + return TRUE; + } + return FALSE; + } +}; +void(mitem newfocus, float flag) mitem_bind::item_focuschange = +{ + if (!(self.item_flags & IF_KFOCUSED)) + self.item_flags = self.item_flags - (self.item_flags & IF_INTERACT); +}; + diff --git a/menusys/mitem_checkbox.qc b/menusys/mitem_checkbox.qc new file mode 100644 index 00000000..b6ebd129 --- /dev/null +++ b/menusys/mitem_checkbox.qc @@ -0,0 +1,69 @@ +/*************************************************************************** +checkbox, directly linked to a cvar. +*/ +class mitem_check : mitem +{ + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + if (!down) + return FALSE; + + if (scan == K_ENTER || scan == K_SPACE || scan == K_LEFTARROW || scan == K_RIGHTARROW || scan == K_MOUSE1) + { + pos_x += this.item_size_x / 2; +// if (ui.mousepos[0] > pos_x || scan != K_MOUSE1) //don't do anything if they clicked the bit on the left to select it + set(item_command, ftos(!stof(get(item_command)))); + return TRUE; + } + else if (scan == K_DEL && down && cvar_type(item_command)) + set(item_command, cvar_defstring(item_command)); + return FALSE; + }; + virtual void(vector pos) item_draw = + { + vector rgb = item_rgb; + if (!(item_flags & IF_SELECTABLE)) + rgb *= 0.2; + local float truth = stof(get(item_command)); + + super::item_draw(pos); + pos_x += item_size_x / 2; + + if (dp_workarounds) + { //lame, but whatever + ui.drawstring(pos, chr2str(0xe080, 0xe082), '1 1 0' * this.item_scale, rgb, this.item_alpha, 0); + if (truth) + ui.drawstring(pos + '4 0', chr2str(0xe083), '1 1 0' * this.item_scale, rgb, this.item_alpha, 0); + } + else + { + ui.drawstring(pos, "^{e080}^{e082}", '1 1 0' * this.item_scale, rgb, this.item_alpha, 0); + if (truth) + ui.drawstring(pos + '4 0', "^{e083}", '1 1 0' * this.item_scale, rgb, this.item_alpha, 0); + } + }; + void() mitem_check = + { + if (!item_scale) + item_scale = 8; + if (!item_size_y) + item_size_y = item_scale; + if (isvalid(item_command)) + item_flags |= IF_SELECTABLE; + }; + + virtual void() item_resized = + { + if (isvalid(item_command)) + item_flags |= IF_SELECTABLE; + else + item_flags &= ~IF_SELECTABLE; + super::item_resized(); + }; +}; + +//optional, can spawn direcly +mitem_check(string text, string command, vector sz) menuitemcheck_spawn = +{ + return spawn(mitem_check, item_scale: sz_y, item_text: text, item_size: sz, item_command: command); +}; diff --git a/menusys/mitem_colours.qc b/menusys/mitem_colours.qc new file mode 100644 index 00000000..1588baba --- /dev/null +++ b/menusys/mitem_colours.qc @@ -0,0 +1,247 @@ +/*************************************************************************** +hue selection thing, directly linked to a cvar. +We hard code 1 in the saturation+value arguments for the selection + +Screw Quake colours, they're too brown! +*/ +class mitem_colours : mitem +{ + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress; + + virtual void() item_resized = + { + if (isvalid(item_command)) + item_flags |= IF_SELECTABLE; + else + item_flags &= ~IF_SELECTABLE; + super::item_resized(); + }; +}; + +//http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c +static vector(vector rgb) rgbtohsv = +{ + float r = rgb_x, g = rgb_y, b = rgb_z; + float maxc = max(r, g, b), minc = min(r, g, b); + float h, s, l = (maxc + minc) / 2; + + local float d = maxc - minc; + if (maxc) + s = d / maxc; + else + s = 0; + + if(maxc == minc) + { + h = 0; // achromatic + } + else + { + if (maxc == r) + h = (g - b) / d + ((g < b) ? 6 : 0); + else if (maxc == g) + h = (b - r) / d + 2; + else + h = (r - g) / d + 4; + h /= 6; + } + + return [h, s, l]; +}; + +//http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c +static vector(vector hsv) hsvtorgb = +{ + float h = hsv_x, s = hsv_y, v = hsv_z; + float r=0, g=1, b=0; + + while(h < 0) + h+=1; + while(h >= 1) + h-=1; + + float i = floor(h * 6); + float f = h * 6 - i; + float p = v * (1 - s); + float q = v * (1 - f * s); + float t = v * (1 - (1 - f) * s); + switch(i) + { + case 0: r = v, g = t, b = p; break; + case 1: r = q, g = v, b = p; break; + case 2: r = p, g = v, b = t; break; + case 3: r = p, g = q, b = v; break; + case 4: r = t, g = p, b = v; break; + case 5: r = v, g = p, b = q; break; + } + + return [r, g, b]; +}; + +float(float chr) nibbletofloat = +{ + chr = chr&0xff; + if (chr >= '0' && chr <= '9') + return chr - '0'; + if (chr >= 'a' && chr <= 'f') + return chr - 'a' + 10; + if (chr >= 'A' && chr <= 'F') + return chr - 'A' + 10; + return 0; +}; + +static vector(string v) hextorgb = +{ + if (!strncmp(v, "0x", 2)) + { + vector r; + r_x = (nibbletofloat(str2chr(v, 2))*16 + nibbletofloat(str2chr(v, 3)))/255; + r_y = (nibbletofloat(str2chr(v, 4))*16 + nibbletofloat(str2chr(v, 5)))/255; + r_z = (nibbletofloat(str2chr(v, 6))*16 + nibbletofloat(str2chr(v, 7)))/255; + return r; + } + else + { + float legacycolour = stof(v); + switch(legacycolour) + { + case 0: return [0xeb, 0xeb, 0xeb]/255; + case 1: return [0x8f, 0x6f, 0x23]/255; + case 2: return [0x8b, 0x8b, 0xcb]/255; + case 3: return [0x6b, 0x6b, 0x0f]/255; + case 4: return [0x7f, 0x00, 0x00]/255; + case 5: return [0xaf, 0x67, 0x23]/255; + case 6: return [0xff, 0xf3, 0x1b]/255; + case 7: return [0xe3, 0xb3, 0x97]/255; + + case 8: return [0xab, 0x8b, 0xa3]/255; + case 9: return [0xbb, 0x73, 0x97]/255; + case 10: return [0xdb, 0xc3, 0xbb]/255; + case 11: return [0x6f, 0x83, 0x7b]/255; + case 12: return [0xff, 0xf3, 0x1b]/255; + case 13: return [0x00, 0x00, 0xff]/255; + //14+15 are fullbrights, so not valid. + + default: + return '0 0 0'; + } + } +}; +static string(vector v) rgbtohex = +{ + v *= 255; + return sprintf("0x%02x%02x%02x", v_x, v_y, v_z); +}; + +void(vector pos) mitem_colours::item_draw = +{ + local float step; + local float stride; + local string curval; + local vector rgb; + + super::item_draw(pos); + + //calculate the rgb from hue at each step across the colour block +#define STEPS 32 + pos_x += item_size_x / 2; + + if (ui.mgrabs == this) + { + float frac; + //if we're sliding it, update the value + frac = (ui.mousepos[1] - pos_x-(item_size_y+4)) / (item_size_x / 2 - (item_size_y+4)); + if (frac >= 0 && frac <= 1) + { + set(item_command, rgbtohex(hsvtorgb([frac, 1, 1]))); + } + } + curval = get(item_command); + + stride = (item_size_x / 2 - (item_size_y+4)) / STEPS; + + ui.drawfill(pos, [item_size_y, item_size_y], hextorgb(curval), item_alpha, 0); + pos_x += item_size_y+4; + + pos_y += 1; +#if defined(MENU) || 1 + for (step = 0; step < STEPS; step += 1, pos_x += stride) + { + rgb = hsvtorgb([step/STEPS, 1, 1]); + if (!(item_flags & IF_SELECTABLE)) + rgb *= 0.2; + ui.drawfill(pos, [stride, item_size_y-2], rgb, item_alpha, 0); + } +#else +//FIXME: WTF is going on here? it comes out as black? wtf? + //draw quads (we should probably not use an internal-to-engine shader here...) + R_BeginPolygon("fill_opaque", 4); //outside so we can skip it for faster reuse by avoiding lookups + rgb = hsvtorgb([0, 1, 1]); + for (step = 0; step < STEPS;) + { + R_PolygonVertex([pos_x, pos_y+item_size_y-2], '0 1', rgb, item_alpha); + R_PolygonVertex([pos_x, pos_y], '0 0', rgb, 1); + + pos_x += stride; + step += 1; + rgb = hsvtorgb([step/STEPS, 1, 1]); + + R_PolygonVertex([pos_x, pos_y], '1 0', rgb, 1); + R_PolygonVertex([pos_x, pos_y+item_size_y-2], '1 1', rgb, item_alpha); + + R_EndPolygon(); + } +#endif +#undef STEPS +}; + +float(vector pos, float scan, float char, float down) mitem_colours::item_keypress = +{ + if (!down) + { + if (ui.mgrabs == this) + ui.mgrabs = __NULL__; + return FALSE; + } + local float curval = rgbtohsv(hextorgb(get(item_command)))[0]; + if (scan == K_MWHEELUP || scan == K_MWHEELDOWN) + { + if (mouseinbox(pos, item_size)) + scan = ((scan == K_MWHEELDOWN)?K_LEFTARROW:K_RIGHTARROW); + } + if (scan == K_MOUSE1) + { + pos_x += item_size_x / 2; + pos_x += item_size_y+4; + curval = (ui.mousepos[0] - pos_x) / (item_size_x / 2 - item_size_y+4); + if (curval < 0 || curval > 1) + return FALSE; + curval = curval; + set(item_command, rgbtohex(hsvtorgb([(curval), 1, 1]))); + ui.mgrabs = this; + } + else if (scan == K_LEFTARROW || scan == K_SPACE) + { + set(item_command, rgbtohex(hsvtorgb([curval - (1/64.0), 1, 1]))); //yay autorepeat + } + else if (scan == K_RIGHTARROW || scan == K_ENTER) + { + set(item_command, rgbtohex(hsvtorgb([curval + (1/64.0), 1, 1]))); + } + else + return FALSE; + return TRUE; +}; +mitem_colours(string text, string command, vector sz) menuitemcolour_spawn = +{ + mitem_colours n = spawn(mitem_colours); + n.item_scale = sz_y; + n.item_text = text; + n.item_size = sz; + + n.item_command = command; + n.item_flags |= IF_SELECTABLE; + return n; +}; + diff --git a/menusys/mitem_combo.qc b/menusys/mitem_combo.qc new file mode 100644 index 00000000..23f419bd --- /dev/null +++ b/menusys/mitem_combo.qc @@ -0,0 +1,303 @@ +/*************************************************************************** +combo item. +No longer using pointers, now using a tokenized string. Less efficient, but saves creating lots of different arrays, just pass a string. +The string list is doubled, first is the actual value, second is the friendly text. +Will show actual value when focused, and will show readable value when not. +The possible values is a separate popup. +*/ + +//FIXME: should probably set up a grabs to intercept right-click / escape outside of the item + +class mitem_combo; +class mitem_combo_popup; + +class mitem_combo : mitem +{ + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void(mitem newfocus, float changedflag) item_focuschange; + + mitem_combo_popup cfriend; + string mstrlist; + float firstrow; + float visrows; + + virtual void() item_remove; + + virtual void() item_resized = + { + if (isvalid(item_command)) + item_flags |= IF_SELECTABLE; + else + item_flags &= ~IF_SELECTABLE; + super::item_resized(); + }; +}; + +class mitem_combo_popup : mitem +{ + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void(mitem newfocus, float changedflag) item_focuschange; + + mitem_combo pfriend; + + virtual void() item_remove = + { + if (pfriend) + pfriend.cfriend = 0; + super::item_remove(); + }; +}; + +void() mitem_combo::item_remove = +{ + mitem_combo_popup p = cfriend; + if (p) + p.item_remove(); + strunzone(mstrlist); + super::item_remove(); +}; + +void(vector pos) mitem_combo::item_draw = +{ + local float i, v; + local string curval = get(item_command); + vector rgb = item_rgb; + if (!(item_flags & IF_SELECTABLE)) + rgb *= 0.2; + + if (cfriend) + cfriend.item_position = pos + [item_size_x / 2, item_size_y]; + + super::item_draw(pos); + + v = tokenize(mstrlist); + + //display the friendly string if the current value matches +// if (!(item_flags & IF_KFOCUSED) && (!cfriend || !(cfriend.item_flags & IF_KFOCUSED))) + { + for (i = 0; i < v; i+=2) + { + if (argv(i) == curval) + { + curval = argv(i+1); + break; + } + } + } + + pos_x += item_size_x / 2; + + +/* //border + ui.drawfill(pos, [item_size_x/2, 1], TD_BOT, item_alpha, 0); + ui.drawfill(pos, [1, item_size_y - 1], TD_RGT, item_alpha, 0); + ui.drawfill(pos + [item_size_x/2-1, 1], [1, item_size_y - 1], TD_LFT, item_alpha, 0); + ui.drawfill(pos + [0, item_size_y-1], [item_size_x/2, 1], TD_TOP, item_alpha, 0); +*/ + //silly strings need to get cut off properly. + ui.setcliparea(pos[0], pos[1], item_size_x/2, item_size_y); + pos_y += (item_size_y - item_scale)*0.5; + pos_x += 1; + ui.drawstring(pos, curval, '1 1 0' * item_scale, rgb, item_alpha, 0); + ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]); +}; +void(mitem newfocus, float flag) mitem_combo::item_focuschange = +{ + if (!cfriend || !(flag & IF_KFOCUSED)) + return; //don't care + if (newfocus != (mitem)this && newfocus != (mitem)cfriend) + { + cfriend.item_size = cfriend.maxs = '0 0'; + cfriend.item_flags &~= IF_SELECTABLE; + } +}; +void(mitem newfocus, float flag) mitem_combo_popup::item_focuschange = +{ + pfriend.item_focuschange(newfocus, flag); +}; +void(vector pos) mitem_combo_popup::item_draw = +{ + vector col; + if (item_size_y < 1) + return; + + local mitem_combo f = pfriend; + item_command = f.item_command; + local string curval = f.get(f.item_command); + local float i, m, c, v; + + if (!((f.item_flags | item_flags) & IF_KFOCUSED)) + { + item_size = maxs = '0 0'; + item_flags &~= IF_SELECTABLE; + return; + } + + ui.drawfill(pos, item_size, item_rgb, item_alpha, 0); + +/* //border + ui.drawfill(pos, [item_size_x, 1], TD_BOT, item_alpha, 0); + ui.drawfill(pos, [1, item_size_y - 1], TD_RGT, item_alpha, 0); + ui.drawfill(pos + [item_size_x-1, 1], [1, item_size_y - 1], TD_LFT, item_alpha, 0); + ui.drawfill(pos + [0, item_size_y-1], [item_size_x, 1], TD_TOP, item_alpha, 0); +*/ pos_x += 1; + + v = tokenize(f.mstrlist); + for (c = 0; c < v; c += 2) + if (argv(c) == curval) + break; + if (c >= v) + c = 0; + + i = f.firstrow; + i = i*2; + if (!f.visrows) + i = 0; + else + { + //bound the displayed position + if (c < i) + i = c; + if (i < c - (f.visrows-1)*2) + i = c - (f.visrows-1)*2; + } + m = i + f.visrows*2; + f.firstrow = floor(i*0.5); + + //constrain the drawing so it doesn't overflow the combo + ui.setcliparea(pos[0], pos[1], item_size[0], item_size[1]); + + for (; i < m && i < v ; i+=2) + { + col = f.item_rgb; + if (item_flags & IF_MFOCUSED) + if (mouseinbox(pos, [item_size_x, item_scale])) + col_z = 0; + if (c == i) + col_x = 0; + + ui.drawstring(pos, argv(i+1), '1 1 0' * item_scale, col, f.item_alpha, 0); + pos_y += item_scale; + } + + //reset the clip area + ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]); +}; +float(vector pos, float scan, float char, float down) mitem_combo_popup::item_keypress = +{ + return pfriend.item_keypress(pos - [0, pfriend.item_size_y], scan, char, down); +}; +float(vector pos, float scan, float char, float down) mitem_combo::item_keypress = +{ + if (!down) + return FALSE; + + local string curval = get(item_command); + local float i, c; + local float f; + c = tokenize(mstrlist); + + //find which one is active + for (i = 0; i < c; i+=2) + { + if (argv(i) == curval) + { + break; + } + } + + if (scan == K_ESCAPE || scan == K_MOUSE2) + { + if (cfriend) + { + cfriend.item_remove(); + return TRUE; + } + return FALSE; + } + else if (scan == K_MWHEELUP || (scan == K_UPARROW && cfriend)) + { + i -= 2; + if (i < 0) + i = c - 2; + curval = argv(i); + } + else if (scan == K_MWHEELDOWN || (scan == K_DOWNARROW && cfriend)) + { + i += 2; + if (i >= c) + i = 0; + curval = argv(i); + } + else if (scan == K_MOUSE1 || scan == K_ENTER) + { + if (scan == K_ENTER && cfriend) + { + cfriend.item_remove(); + return TRUE; + } + + visrows = ((c>18)?18/2:c/2); + if (!cfriend) + { + cfriend = spawn(mitem_combo_popup); + cfriend.pfriend = this; + cfriend.item_scale = 8; + cfriend.item_rgb = MENUBACK_RGB; + cfriend.item_alpha = MENUBACK_ALPHA; + pos = item_position; + mitem_frame fr = item_parent; + while (fr.item_parent) + { //try to inject the combo thingie into the desktop item. this is to avoid scissoring. + pos += fr.item_position; + fr = fr.item_parent; + } + fr.addr(cfriend, RS_X_MIN_PARENT_MIN | RS_X_MAX_OWN_MIN | RS_Y_MIN_PARENT_MIN | RS_Y_MAX_OWN_MIN, pos + [self.item_size_x / 2, self.item_size_y], [item_size_x*0.5, item_size_y*visrows]); + } + cfriend.item_size = cfriend.maxs = [item_size_x*0.5, item_size_y*visrows]; + cfriend.item_flags |= IF_SELECTABLE; + cfriend.totop(); + + if (scan == K_MOUSE1 && (cfriend.item_flags & IF_MFOCUSED)) + { + //if they clicked inside the popup, change the selected item. + f = ui.mousepos[1] - (pos_y + item_size_y); + f /= cfriend.item_scale; + f += firstrow; + i = floor(f) * 2; + if (i < c) + { + curval = argv(i); + cfriend.item_flags &~= IF_SELECTABLE; + cfriend.item_size = cfriend.maxs = '0 0'; + item_parent.item_focuschange(this, IF_MFOCUSED|IF_KFOCUSED); + + cfriend.item_remove(); + } + } + } + else if (scan == K_BACKSPACE || scan == K_DEL) + curval = substring(curval, 0, -2); + else if (char >= ' ') + curval = strcat(curval, chr2str(char)); + else + return FALSE; + + set(item_command, curval); + return TRUE; +}; +mitem_combo(string text, string command, vector sz, string valuelist) menuitemcombo_spawn = +{ + mitem_combo n = spawn(mitem_combo); + n.item_scale = sz_y; + n.item_text = text; + n.item_size = sz; + n.mstrlist = strzone(valuelist); + + n.item_command = command; + if (n.isvalid(command)) + n.item_flags |= IF_SELECTABLE; + return n; +}; diff --git a/menusys/mitem_console.qc b/menusys/mitem_console.qc new file mode 100644 index 00000000..30d9b381 --- /dev/null +++ b/menusys/mitem_console.qc @@ -0,0 +1,58 @@ +/*************************************************************************** +Embed a (sub) console in a menu item thing. + +you can print to these consoles with con_print("consolename", "text to be printed\n"); +they can be detached from the system console with con_getset("consolename", "hidden", "1"). be sure to getset(con, "close", "1") or unhide afterwards. +you can enumerate the active consoles with con="";while((con=con_getset(con,"next"))!=""){print(con_getset(con,"title"));} this is useful for finding xmpp conversations. you might then want to hide them afterwards. +*/ + +class mitem_console : mitem +{ + virtual void() item_remove = + { + strunzone(item_command); + super::item_remove(); + }; + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + local float ret; + if (scan == K_ESCAPE) //let the owning menu take it. + return FALSE; + if (down) + { + ret = con_input(item_command, IE_KEYDOWN, scan, char, 0); + if (scan == K_MOUSE1 || scan == K_MOUSE2) //grab mouse, so we still receive mouse up events. + { + ui.mgrabs = this; + ret = TRUE; + local mitem_frame p = item_parent; + p.item_focuschange(this, IF_KFOCUSED); + } + } + else + { + ret = con_input(item_command, IE_KEYUP, scan, char, 0); //note the engine never tries to cancel key up events anyway. + if (ui.mgrabs == this) + ui.mgrabs = __NULL__; + } + return ret; + }; + virtual void(mitem newfocus, float flag) item_focuschange = + { + con_input(item_command, IE_FOCUS, !!(item_flags&IF_MFOCUSED), !!(item_flags&IF_KFOCUSED), 0); + }; + virtual void(vector pos) item_draw = + { + con_input(item_command, IE_MOUSEABS, ui.mousepos[0] - pos_x, ui.mousepos[1] - pos_y, 0); + con_draw(item_command, pos, item_size, 12); //use a 12-point font, if we can. + }; + void() mitem_console = + { + item_flags |= IF_SELECTABLE; + item_command = strzone(item_command); + }; +}; + +#define menuitemconsole_spawn(conname) spawn(mitem_console, item_command:conname) + + diff --git a/menusys/mitem_desktop.qc b/menusys/mitem_desktop.qc new file mode 100644 index 00000000..36032da1 --- /dev/null +++ b/menusys/mitem_desktop.qc @@ -0,0 +1,465 @@ +/*************************************************************************** +desktop and top-level functions. +*/ + +#ifdef USEPOINTERS +typedef mitem mitem_desktop; +#else +class mitem_desktop : mitem_frame +{ + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void(mitem newfocus, float flag) item_focuschange; + virtual void(vector pos) item_draw; //draws the game, then calls mitem_frame::item_draw for children. +#ifndef MENU + virtual void(float seat, vector minpos, vector size) drawgame = __NULL__; //if overridden, should call renderscene and then draw whatever hud it needs to. this will do splitscreen efficiently and automatically. +#endif + void() mitem_desktop; //the constructor. uninteresting. just ensures the size defaults to fullscreen. +}; +#endif + +#if !defined(MENU) && !defined(CSQC_SIMPLE) +float sb_showscores; +#endif + +float drawfont; +float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357; + +void() mitem_desktop::mitem_desktop = +{ +#define menu_font_win autocvar(menu_font_win, "cour") +#define menu_font autocvar(menu_font, "") +#define menu_font_fallback autocvar(gl_font, "") + queryscreensize(); + + if (checkextension("DP_GFX_FONTS")) + { + //make sure we have a font that can cope with slightly up-scaled stuff. + //windows is special because we can load from the system fonts + string fontname = menu_font_fallback; + if (menu_font_win != "" && !strncasecmp(cvar_string("sys_platform"), "Win", 3)) + fontname = menu_font_win; + else if (menu_font != "") + fontname = menu_font; + drawfont = loadfont("", fontname, "8 12 16", -1); + } + + item_text = "desktop"; + if (!item_flags) + { + item_size = ui.screensize; + item_flags = IF_SELECTABLE | IF_MFOCUSED | IF_KFOCUSED | IF_RESIZABLE | IF_NOCURSOR; + } + + if (!ui.kgrabs && !ui.mgrabs && (item_flags & IF_NOCURSOR)) + { + ui.kgrabs = this; + ui.mgrabs = this; + } +}; + +void(mitem newfocus, float flag) mitem_desktop::item_focuschange = +{ + super::item_focuschange(newfocus, flag); + + if (flag & IF_KFOCUSED) + { + //if we're deselecting the current one, reenable grabs + if (newfocus == __NULL__) + { + if(item_flags & IF_NOCURSOR) + { + ui.kgrabs = this; + ui.mgrabs = this; + } + } + else + { + if (ui.kgrabs == this) + { + ui.kgrabs = __NULL__; + ui.mgrabs = __NULL__; + } + } + } +}; + +//the interact flag says that the mouse is held down on the desktop +float(vector pos, float scan, float char, float down) mitem_desktop::item_keypress = +{ + float oldfl = item_flags; + + if (down & 2) + { + down &= 1; + //if we're grabbing, then cancel if they press escape, otherwise block other items from taking the keys. + if (scan >= K_MOUSE1 && scan <= K_MOUSE5) + return 2; //block other wigits, don't cancel the event so the engine still does its thing + else + { + if (scan == K_ESCAPE && down) + { + local mitem sc; + //block the keyevent if we already have menus loaded but not focused (select one if we do). + for (sc = item_children; sc; sc = sc.item_next) + { + if (sc.item_flags & IF_SELECTABLE) + { + if (!item_kactivechild) + item_focuschange(sc, IF_KFOCUSED); + return 3; + } + } + //make sure our code takes it, instead of showing the engine menu... +#ifdef MENU + m_toggle(0); + return 3; +#else + return 2|CSQC_ConsoleCommand("togglemenu"); +#endif + } + return 2; + } + } + + if (mitem_frame::item_keypress(pos, scan, char, down)) + return TRUE; + + if (scan == K_MOUSE1 && down) + { +#if defined(CSQC) && defined(FTE_SPLITSCREEN) + if (numclientseats) + localcmd("in_forcesplitclient 0\n"); +#endif + if (item_flags & IF_NOCURSOR) + { + ui.kgrabs = this; + ui.mgrabs = this; + } + return TRUE; + } + if (scan == K_MOUSE2 && down) + { +#if defined(CSQC) && defined(FTE_SPLITSCREEN) + if (numclientseats > 3) + localcmd(strcat("in_forcesplitclient ", ftos(1 + ((ui.mousepos[0]>ui.screensize[0]/2)?1:0) + ((ui.mousepos[1]>ui.screensize[1]/2)?2:0)), "\n")); + else if (numclientseats > 1) + localcmd(strcat("in_forcesplitclient ", ftos(1 + floor(ui.mousepos[1]*numclientseats/ui.screensize[1])), "\n")); + else if (numclientseats) + localcmd("in_forcesplitclient 0\n"); +#endif + if (item_flags & IF_NOCURSOR) + { + ui.kgrabs = this; + ui.mgrabs = this; + } + return TRUE; + } + +#ifdef CSQC + //catch otherwise unhangled escape presses, just to be sure we can use escape to toggle the menu + if (scan == K_ESCAPE && down) + { + return CSQC_ConsoleCommand("togglemenu"); + } +#endif + return FALSE; +}; + +#if !defined(MENU) && !defined(CSQC_SIMPLE) +static vector(vector v) vtodpp = +{ + //so fucking disgustingly ugly. + if (dp_workarounds) + { + v_x *= cvar("vid_width") / cvar("vid_conwidth"); + v_y *= cvar("vid_height") / cvar("vid_conheight"); + } + return v; +}; + +//vector pmove_org; +void(float seat, vector minpos, vector size) mitem_desktop::drawgame_helper = +{ + if not(seat) + { + clearscene(); + addentities(MASK_ENGINE|MASK_VIEWMODEL); + } + else + { + setviewprop(VF_LPLAYER, seat); + setproperty(VF_VIEWENTITY, player_localentnum); + addentities(MASK_VIEWMODEL); //don't do mask_engine because that's already done + } +// if (dp_workarounds) +// setproperty(VF_ORIGIN, pmove_org); + setproperty(VF_MIN, minpos); + setproperty(VF_SIZE, vtodpp(size)); + + setproperty(VF_DRAWCROSSHAIR, (ui.mgrabs == this)); + + drawgame(seat, minpos, size); + if (mouseinbox(minpos, size)) + { + ui.havemouseworld = TRUE; + ui.mouseworldnear = unproject([ui.mousepos[0], ui.mousepos[1], 0]); + ui.mouseworldfar = unproject([ui.mousepos[0], ui.mousepos[1], 100000]); + } +}; +#endif + +void(vector pos) mitem_desktop::item_draw = +{ +#if !defined(MENU) && !defined(CSQC_SIMPLE) +//menuqc picks up the game/console as a background + string constate = serverkey("constate"); + if (constate != "" && constate != "active") //allow empty, so things still kinda work with dp too. + { + drawfill(pos, ui.screensize, '0 0 0', 1, 0); + } + else if (this.drawgame != __NULL__) + { +#ifdef FTE_SPLITSCREEN + if (numclientseats > 3) + { + drawgame_helper(0, [0, 0], 0.5*ui.screensize); + drawgame_helper(1, [ui.screensize[0]*0.5, 0], 0.5*ui.screensize); + drawgame_helper(2, [0, ui.screensize[1]*0.5], 0.5*ui.screensize); + drawgame_helper(3, [ui.screensize[0]*0.5, ui.screensize[1]*0.5], 0.5*ui.screensize); + setviewprop(VF_LPLAYER, 0); + } + else if (numclientseats > 2) + { + drawgame_helper(0, [0, 0], [ui.screensize[0], ui.screensize[1]*0.333]); + drawgame_helper(1, [0, ui.screensize[1]*0.333], [ui.screensize[0], ui.screensize[1]*0.333]); + drawgame_helper(2, [0, ui.screensize[1]*0.666], [ui.screensize[0], ui.screensize[1]*0.333]); + setviewprop(VF_LPLAYER, 0); + } + else if (numclientseats > 1) + { + drawgame(0, [0, 0], [ui.screensize[0], ui.screensize[1]*0.5]); + drawgame(1, [0, ui.screensize[1]*0.5], [ui.screensize[0], ui.screensize[1]*0.5]); + setviewprop(VF_LPLAYER, 0); + } + else +#endif + { + drawgame_helper(0, '0 0', ui.screensize); + } + } +#endif + super::item_draw(pos); + + if (ui.kgrabs == this) + { +#if defined(CSQC) && !defined(CSQC_SIMPLE) + if (sb_showscores && ui.mgrabs == this) + ui.mgrabs = __NULL__; + else +#endif + if (!ui.mgrabs) + ui.mgrabs = this; + } +}; + + +var string autocvar_cl_cursor = "gfx/cursor.lmp"; +var float autocvar_cl_cursorsize = 32; +var float autocvar_cl_cursorbias = 4; + +static var float oldgrabstate; //to work around a DP bug (as well as unnecessary spam) + +void(float force) items_updategrabs = +{ + if (!ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR)) + { + if (!oldgrabstate || force) + { + oldgrabstate = TRUE; +#ifdef MENU + setkeydest(2); + setmousetarget(2); +#else + setcursormode(TRUE); + //setcursormode(TRUE, autocvar_cl_cursor, autocvar_cl_cursorbias*'1 1', autocvar_cl_cursorscale); +#endif + } + } + else if (oldgrabstate || force) + { + oldgrabstate = FALSE; +#ifdef MENU + setkeydest(0); + setmousetarget(1); +#else + setcursormode(FALSE); +#endif + } +}; + +void(mitem_desktop desktop) items_draw = +{ + queryscreensize(); + +#ifdef MENU + ui.mousepos = getmousepos(); +#else + if (ui.havemouseworld) + ui.havemouseworld = 2; //stale, but not too stale +#endif + + if (desktop.item_size != ui.screensize) + { + desktop.item_size = ui.screensize; + desktop.item_resized(); + } + ui.drawrectmax = ui.screensize; + + desktop.item_draw(desktop.item_position); + drawresetcliparea(); + + items_updategrabs(FALSE); + if (dp_workarounds && oldgrabstate) + { + if (drawgetimagesize(autocvar_cl_cursor) == '0 0') + ui.drawcharacter(ui.mousepos - [stringwidth("+", TRUE, '4 4')*0.5, 4], '+', '8 8', '1 1 1', 1, 0); + else + ui.drawpic(ui.mousepos - autocvar_cl_cursorbias*'1 1', autocvar_cl_cursor, autocvar_cl_cursorsize*'1 1', '1 1 1', 1, 0); + } + +#ifndef MENU + if (ui.havemouseworld == 2) //if its still stale then its totally invalid. + ui.havemouseworld = FALSE; +#endif + ui.oldmousepos = ui.mousepos; +}; + +#ifdef CSQC +//items_keypress has quite strong dimorphism. These are meant to tailored to the target's available event notifications, rather than being really rather annoying. +csqconly float(mitem_desktop desktop, float evtype, float scanx, float chary, float devid) items_keypress = +{ + local float result = FALSE; + vector pos; + mitem p; + switch(evtype) + { + case IE_KEYDOWN: + case IE_KEYUP: + if (scanx == K_SHIFT) + ui.shiftheld = evtype==IE_KEYDOWN; +#ifdef HEIRACHYDEBUG + if (scanx == K_F1 && evtype == IE_KEYDOWN) + { + mitem_printtree(desktop, "items_keypress", __LINE__); + return TRUE; + } +#endif + if (scanx >= K_MOUSE1 && scanx <= K_MOUSE5) + { + if (ui.mgrabs) + { + pos = '0 0 0'; + for (p = ui.mgrabs; p; p = p.item_parent) + pos += p.item_position; + result = ui.mgrabs.item_keypress(pos, scanx, chary, (evtype == IE_KEYDOWN)|2); + if (result & 2) + { + ui.mousedown = 0; + return result & 1; + } + } + } + else + { + if (ui.kgrabs) + { + pos = '0 0 0'; + for (p = ui.kgrabs; p; p = p.item_parent) + pos += p.item_position; + result = ui.kgrabs.item_keypress(pos, scanx, chary, (evtype == IE_KEYDOWN)|2); + if (result & 2) + return result & 1; + } + } + if (desktop && desktop.item_keypress) + result = desktop.item_keypress(desktop.item_position, scanx, chary, evtype == IE_KEYDOWN); + if (scanx >= K_MOUSE1 && scanx <= K_MOUSE5) + { + if (evtype == IE_KEYDOWN) + ui.mousedown |= pow(1, scanx-K_MOUSE1); + else + ui.mousedown &~= pow(1, scanx-K_MOUSE1); + } + result = result & 1; + break; + case IE_MOUSEDELTA: + result = !ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR); + if (result) + { + queryscreensize(); + ui.mousepos[0] = bound(0, ui.mousepos[0]+scanx, ui.screensize[0]); + ui.mousepos[1] = bound(0, ui.mousepos[1]+chary, ui.screensize[1]); + } + break; + case IE_MOUSEABS: + ui.mousepos[0] = scanx; + ui.mousepos[1] = chary; + result = !ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR); + break; + } + return result; +}; +#endif + +#ifdef MENU +menuonly float(mitem_desktop desktop, float scan, float char, float down) items_keypress = +{ + local float result = FALSE; + local vector pos; + local mitem p; + ui.mousepos = getmousepos(); + queryscreensize(); +#ifdef HEIRACHYDEBUG + if (scan == K_F1 && down) + { + mitem_printtree(desktop, "items_keypress", __LINE__); + return TRUE; + } +#endif + + if (scan >= K_MOUSE1 && scan <= K_MOUSE5) + { + if (ui.mgrabs) + { + pos = '0 0 0'; + for (p = ui.mgrabs; p; p = p.item_parent) + pos += p.item_position; + result = ui.mgrabs.item_keypress(pos, scan, char, (down)|2); + if (result & 2) + { + ui.mousedown = 0; + return result & 1; + } + } + } + else + { + if (ui.kgrabs) + { + pos = '0 0 0'; + for (p = ui.kgrabs; p; p = p.item_parent) + pos += p.item_position; + result = ui.kgrabs.item_keypress(pos, scan, char, (down)|2); + if (result & 2) + return result & 1; + } + } + + if (desktop && desktop.item_keypress) + result = desktop.item_keypress(desktop.item_position, scan, char, down); + + return result; +}; +#endif + + diff --git a/menusys/mitem_edittext.qc b/menusys/mitem_edittext.qc new file mode 100644 index 00000000..825065a5 --- /dev/null +++ b/menusys/mitem_edittext.qc @@ -0,0 +1,98 @@ +/*************************************************************************** +editable text, directly linked to a cvar. +FIXME: This can only edit the end of the string. +*/ +class mitem_edit : mitem +{ + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void() item_remove; + float spos; + + virtual void() item_resized = + { + if (isvalid(item_command)) + item_flags |= IF_SELECTABLE; + else + item_flags &= ~IF_SELECTABLE; + super::item_resized(); + }; +}; + +void() mitem_edit::item_remove = +{ + strunzone(item_text); + strunzone(item_command); + super::item_remove(); +}; + +void(vector pos) mitem_edit::item_draw = +{ + local string curval = get(item_command); + + super::item_draw(pos); + + pos_x += item_size_x / 2; +/* ui.drawfill(pos, [item_size_x/2, 1], TD_BOT, item_alpha, 0); + ui.drawfill(pos, [1, self.item_size_y - 1], TD_RGT, item_alpha, 0); + ui.drawfill(pos + [item_size_x/2-1, 1], [1, item_size_y - 1], TD_LFT, item_alpha, 0); + ui.drawfill(pos + [0, item_size_y-1], [item_size_x/2, 1], TD_TOP, item_alpha, 0); +*/ pos_y += (item_size_y - item_scale)*0.5; + pos_x += 1; + + spos = min(spos, strlen(curval)); + if (((cltime*4)&1) && (item_flags & IF_KFOCUSED)) + curval = strcat(substring(curval, 0, spos), chr2str(0xe00b), substring(curval, spos+1, -1)); //replace the char with a box... ugly, whatever + ui.drawstring(pos, curval, '1 1 0' * item_scale, item_rgb, item_alpha, 0); +}; +float(vector pos, float scan, float char, float down) mitem_edit::item_keypress = +{ + if (!down) + return FALSE; + + local string curval = get(item_command); + spos = min(spos, strlen(curval)); + + if (scan == K_ESCAPE) + return FALSE; + else if (scan == K_LEFTARROW) + spos = max(spos-1, 0); + else if (scan == K_RIGHTARROW) + spos+=1; +/* else if (scan == K_MOUSE1) + { + //FIXME: figure out the spos for the cursor + return TRUE; + }*/ + else if (scan == K_BACKSPACE || scan == K_DEL) + { + if (spos) + { + curval = strcat(substring(curval, 0, spos-1), substring(curval, spos, -1)); + spos -= 1; + } + } + else if (char >= ' ') + { + curval = strcat(substring(curval, 0, spos), chr2str(char), substring(curval, spos, -1)); + spos += strlen(chr2str(char)); + } + else + return FALSE; + + set(item_command, curval); + return TRUE; +}; +mitem_edit(string text, string command, vector sz) menuitemeditt_spawn = +{ + mitem_edit n = spawn(mitem_edit); + n.item_scale = sz_y; + n.item_text = strzone(text); + n.item_size = sz; + n.spos = 100000; //will be clipped so meh + + n.item_command = strzone(command); + n.item_flags |= IF_SELECTABLE; + return n; +}; + diff --git a/menusys/mitem_exmenu.qc b/menusys/mitem_exmenu.qc new file mode 100644 index 00000000..7dbd8f46 --- /dev/null +++ b/menusys/mitem_exmenu.qc @@ -0,0 +1,58 @@ +/*************************************************************************** +fullscreen exclusive menu +you should only have ONE of these visible at once. +interactable - basically just a container for the items in the menu, but also handles killing them+itself when the user presses escape. +will keep stealing focus from the desktop, so you won't be able to play while one of these is active. +will not steal focus from siblings. this means console slideouts or whatever are still usable. + +these items will automatically be added to the desktop/workspace thing +Call it.item_remove() to pop the menu. +Regular items can be added to the menu by first spawning them, then calling menu_additem to actually add it to the desired menu in the right place. +*/ + +class mitem_exmenu : mitem_frame +{ + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + local float ret = super::item_keypress(pos, scan, char, down); + if (!ret && down) + { + ret = TRUE; + if (scan == K_MOUSE2 || scan == K_ESCAPE) + { + localcmd(strcat(item_command, "\n")); //console command to exec if someone clicks the close button. + item_remove(); + } + else if (scan == K_UPARROW && down) + menu_selectnextitem(this, TRUE); + else if (scan == K_DOWNARROW && down) + menu_selectnextitem(this, FALSE); + else if (scan >= K_F1 && scan <= K_F12) //allow f1-f12 to work, but every other button event gets canceled. + ret = FALSE; + } + return ret; + }; + virtual void(vector pos) item_draw = + { + if (ui.mgrabs == item_parent || ui.kgrabs == item_parent) //if our parent has grabs, steal it instead, this means you can select the console, but the game never gets focus + { + if (item_flags & IF_SELECTABLE) + { + ui.mgrabs = __NULL__; + ui.kgrabs = __NULL__; + item_parent.item_focuschange(this, IF_KFOCUSED); + } + } + super::item_draw(pos); + }; + + //same as mitem, but does not propogate to parent. + virtual string(string key) get = + { + return cvar_string(key); + }; + virtual void(string key, string newval) set = + { + cvar_set(key, newval); + }; +}; \ No newline at end of file diff --git a/menusys/mitem_frame.qc b/menusys/mitem_frame.qc new file mode 100644 index 00000000..9a119766 --- /dev/null +++ b/menusys/mitem_frame.qc @@ -0,0 +1,675 @@ +/*************************************************************************** +Basic frame, containing sub-items. +Logically the parent of menu objects. Also used for tabs. +*/ + +#ifndef MITEM_FRAME_QC__ +#define MITEM_FRAME_QC__ + +class mitem_vslider : mitem +{ + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void(vector pos) item_draw; + void() mitem_vslider; + float val; + float minv; + float maxv; + float stride; //size of one 'notch' +}; + +class mitem_frame : mitem +{ + virtual void(mitem newfocus, float changedflag) item_focuschange; + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void() item_resized; + virtual void(vector pos) item_draw; + virtual void() item_remove; + virtual void(mitem fromitem, string cmd) item_execcommand; + + mitem item_children; + mitem item_mactivechild; + mitem item_kactivechild; + mitem item_exclusive; + + mitem_vslider vslider; //displayed if any client item's max[y] > our item_size[y] + vector item_framesize; //x=sides, y=top, z=bottom + float frame_hasscroll; + + static mitem(string title) findchildtext; + static mitem(string title) findchildcmd; + static void(mitem newitem, float originflags, vector originmin, vector originmax) add; + static void(mitem newitem, vector pos) adda; + static void(mitem newitem, vector originmin, vector originmax) addm; + static void(mitem newitem, float originflags, vector originmin, vector originmax) addr; + static void(mitem newitem, float ypos) addc; + + void() mitem_frame = + { + item_flags |= IF_ISFRAME; + }; +}; + +void(mitem fromitem, string cmd) mitem_frame::item_execcommand = +{ + if (item_parent) + item_parent.item_execcommand(fromitem, cmd); + else + localcmd(strcat(cmd, "\n")); +}; + +mitem(string title) mitem_frame::findchildtext = +{ + mitem ch; + for (ch = item_children; ch; ch = ch.item_next) + { + if (ch.item_text == title) + return ch; + } + return __NULL__; +}; +mitem(string title) mitem_frame::findchildcmd = +{ + mitem ch; + for (ch = item_children; ch; ch = ch.item_next) + { + if (ch.item_command == title) + return ch; + } + return __NULL__; +}; + + +//adds an item with the desired origin settings +void(mitem newitem, float originflags, vector originmin, vector originmax) mitem_frame::add = +{ + newitem.item_next = item_children; + item_children = newitem; + newitem.item_parent = this; + + //set up position and resize + newitem.resizeflags = originflags; + newitem.mins = originmin; + newitem.maxs = originmax; + mitem_parentresized(newitem, [item_size[0] - item_framesize[0]*2, item_size[1] - (item_framesize[1] + item_framesize[2])]); + newitem.item_resized(); + + item_flags |= IF_CLIENTMOVED; //make sure it happens. + +// if (!item_kactivechild && (newitem.item_flags & IF_SELECTABLE)) +// item_focuschange(newitem, IF_KFOCUSED); +}; + +//adds an item to the parent with an absolute position relative to the parent's top-left. objects are expected to already have a size specified. +void(mitem newitem, vector pos) mitem_frame::adda = +{ + local vector parentsize = [item_size[0] - item_framesize[0]*2, item_size[1] - (item_framesize[1] + item_framesize[2])]; + newitem.item_next = item_children; + item_children = newitem; + newitem.item_parent = this; + + newitem.resizeflags = RS_X_MIN_PARENT_MIN | RS_X_MAX_OWN_MIN | RS_Y_MIN_PARENT_MIN | RS_Y_MAX_OWN_MIN; + newitem.mins = pos; + newitem.maxs = newitem.item_size; + + mitem_parentresized(newitem, parentsize); + newitem.item_resized(); + + item_flags |= IF_CLIENTMOVED; //make sure it happens. + +// if (!item_kactivechild && (newitem.item_flags & IF_SELECTABLE)) +// item_focuschange(newitem, IF_KFOCUSED); +}; + +//adds an item to the parent in reverse order (ie: at the tail, so the actual order in code) +void(mitem newitem, float originflags, vector originmin, vector originmax) mitem_frame::addr = +{ + local vector parentsize = [item_size[0] - item_framesize[0]*2, item_size[1] - (item_framesize[1] + item_framesize[2])]; + if (item_children) + { + local mitem prev; + for (prev = item_children; prev.item_next; prev = prev.item_next) + ; + prev.item_next = newitem; + newitem.item_next = __NULL__; + } + else + { + newitem.item_next = item_children; + item_children = newitem; + } + newitem.item_parent = this; + + newitem.resizeflags = originflags; + newitem.mins = originmin; + newitem.maxs = originmax; + mitem_parentresized(newitem, parentsize); + newitem.item_resized(); + + item_flags |= IF_CLIENTMOVED; //make sure it happens. + +// if (!item_kactivechild && (newitem.item_flags & IF_SELECTABLE)) +// item_focuschange(newitem, IF_KFOCUSED); +}; + +//adds an item on the parent with the x coord centered, and absolute y. +//if multiple items are at the same ypos, it will recenter all with respect to the others +void(mitem newitem, float ypos) mitem_frame::addc = +{ + float w, c; + local mitem prev; + local vector parentsize = [item_size[0] - item_framesize[0]*2, item_size[1] - (item_framesize[1] + item_framesize[2])]; + + newitem.item_next = item_children; + item_children = newitem; + newitem.item_position[1] = ypos; + newitem.item_position[0] = (parentsize[0] - newitem.item_size[0])*0.5; + newitem.item_parent = this; + + + newitem.resizeflags = RS_X_MIN_PARENT_MID | RS_X_MAX_OWN_MIN | RS_Y_MIN_PARENT_MIN | RS_Y_MAX_OWN_MIN; + newitem.mins[0] = 0; + newitem.mins[1] = ypos; + newitem.maxs = newitem.item_size; + + //count the width of the other items at this height. + w = 0; + c = 0; + for (prev = item_children; prev; prev = prev.item_next) + if (prev.resizeflags == newitem.resizeflags && prev.mins[1] == ypos && prev.maxs[1] == newitem.maxs[1]) + { + w += prev.maxs[0]; + c += 1; + } + + //distribute them evenly (from the right, because its add-at-head) + w += (c-1)*16; //this much gap space + for (prev = item_children; prev; prev = prev.item_next) + { + if (prev.resizeflags == newitem.resizeflags && prev.mins[1] == ypos && prev.maxs[1] == newitem.maxs[1]) + { + w -= prev.maxs[0]; + prev.mins[0] = (w+prev.maxs[0])/-2; + mitem_parentresized(prev, parentsize); + w -= 16; + } + } + newitem.item_resized(); + + item_flags |= IF_CLIENTMOVED; //make sure it happens. + +// if (!item_kactivechild && (newitem.item_flags & IF_SELECTABLE)) +// item_focuschange(newitem, IF_KFOCUSED); +}; + +//Adds the item in the exact middle of the parent, in both axis +void(mitem newitem, vector min, vector max) mitem_frame::addm = +{ + this.add(newitem, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, min, max); +}; + +//updates this.item_activechild, and calls focus notifications to ensure things get the message. +//flag should be IF_MFOCUSED or IF_KFOCUSED +void(mitem newfocus, float flag) mitem_frame::item_focuschange = +{ + local mitem it; + + if (newfocus == this) + { + //our focus didn't change, but the parent is telling us that *it* got changed while we're the focus + if (flag & IF_MFOCUSED) + { + if (item_parent.item_flags & IF_MFOCUSED && item_parent.item_mactivechild == this) + item_flags |= IF_MFOCUSED; + else + item_flags = item_flags - (item_flags&IF_MFOCUSED); + //and tell the child + it = item_mactivechild; + if (it) + if (it.item_focuschange) + it.item_focuschange(it, IF_MFOCUSED); + } + if (flag & IF_KFOCUSED) + { + if (item_parent.item_flags & IF_KFOCUSED && item_parent.item_kactivechild == this) + item_flags |= IF_KFOCUSED; + else + item_flags = item_flags - (item_flags&IF_KFOCUSED); + //and tell the child + it = item_kactivechild; + if (it) + if (it.item_focuschange) + it.item_focuschange(it, IF_KFOCUSED); + } + return; + } + + if ((flag & IF_MFOCUSED) && item_mactivechild != newfocus) + { + //make key focus follow the mouse cursor. this should probably only apply to button menus or something? :s + if (newfocus && (item_flags & IF_FOCUSFOLLOWSMOUSE)) + flag |= IF_KFOCUSED; + + it = item_mactivechild; + item_mactivechild = newfocus; + if (it) + { + it.item_flags = it.item_flags - (it.item_flags&IF_MFOCUSED); + if (it.item_focuschange) + it.item_focuschange(it, IF_MFOCUSED); + } + it = item_mactivechild; + if (it) + { + it.item_flags = it.item_flags | (item_flags & IF_MFOCUSED); + if (it.item_focuschange) + it.item_focuschange(it, IF_MFOCUSED); + } + } + + if ((flag & IF_KFOCUSED) && item_kactivechild != newfocus) + { + it = item_kactivechild; + item_kactivechild = newfocus; + if (it) + { + it.item_flags = it.item_flags - (it.item_flags&IF_KFOCUSED); + if (it.item_focuschange) + it.item_focuschange(it, IF_KFOCUSED); + } + it = item_kactivechild; + if (it) + { + it.item_flags = it.item_flags | (item_flags & IF_KFOCUSED); + if (it.item_focuschange) + it.item_focuschange(it, IF_KFOCUSED); + } + } +}; + + +float(vector pos, float scan, float char, float down) mitem_vslider::item_keypress = +{ + if (down != 1) + { + if (scan == K_MOUSE1 && ui.mgrabs == this) + ui.mgrabs = __NULL__; + return FALSE; + } + if (scan == K_MWHEELDOWN) + val = bound(minv, val+stride, maxv); + else if (scan == K_MWHEELUP) + val = bound(minv, val-stride, maxv); + else if (scan == K_MOUSE1) + ui.mgrabs = this; + else + return FALSE; + return TRUE; +}; +void(vector pos) mitem_vslider::item_draw = +{ + float f; + float w = item_size[0]; + float h = item_size[1]; + float isize = w; + + vector v = drawgetimagesize("scrollbars/slider.tga"); + + if (v != '0 0 0') + { + ui.drawpic(pos, "scrollbars/arrow_up.tga", [w, w], '1 1 1', item_alpha, 0); //top + pos_y += w; + h -= w*2; + ui.drawpic(pos + [0, h], "scrollbars/arrow_down.tga", [w, w], '1 1 1', item_alpha, 0); //bottom + ui.drawpic(pos, "scrollbars/slidebg.tga", [w, h], '1 1 1', item_alpha, 0); //back-middle + + isize = (v_y * w) / (v_x); + if (isize > h/2) + isize = h/2; + } + else + { +// ui.drawfill(pos, [w, w], '1 1 1', item_alpha, 0); //top +// pos_y += w; +// h -= w*2; +// ui.drawfill(pos + [0, h], [w, w], '1 1 1', item_alpha, 0); //bottom + ui.drawfill(pos, [w, h], '0.5 0.5 0.5', item_alpha, 0); //back-middle + } + + if (ui.mgrabs == this) + { + f = (ui.mousepos[1] - pos_y - (isize/2))/(h - isize); + f = bound(0, f, 1); + val = minv + (f * (maxv - minv)); + } + else + f = bound(0, (val - minv) / (maxv - minv), 1); + + h -= isize; + if (v != '0 0 0') + ui.drawpic(pos + [0, h*f], "scrollbars/slider.tga", [w, isize], '1 1 1', item_alpha, 0); //back-middle + else + ui.drawfill(pos + [0, h*f], [w, isize], '1 1 1', item_alpha, 0); //back-middle +}; +void() mitem_vslider::mitem_vslider = +{ + item_size[0] = 16; + item_size[1] = 128; +}; + +//does NOT wrap. +//does NOT pass go. +static mitem(mitem item, float upwards) menu_simplenextitem = +{ + mitem_frame menu = item.item_parent; + mitem prev; + if (upwards) + { + if (item) + { + item = item.item_next; + if (!item) + return __NULL__; + return item; + } + else + return __NULL__; + } + else + { + for(prev = menu.item_children; prev.item_next; prev = prev.item_next) + { + if (prev.item_next == item) + return prev; + } + return __NULL__; + } +}; + +//finds the next/prev item through multiple children, returning NULL when it runs out of items in the sequence. +//call this with item==null to find the first item in the sequence (to handle wraps). +static mitem(mitem_frame menu, float upwards, mitem item) menu_findnextitem = +{ + mitem_frame frame; + mitem citem; + + if (item && (item.item_flags & IF_ISFRAME)) + { + frame = (mitem_frame)item; + citem = menu_findnextitem(frame, upwards, frame.item_kactivechild?frame.item_kactivechild:frame.item_mactivechild); + if (citem) + return citem; + } + + for(;;) + { + if (!item) + { //we go for the opposite end here, as we assume to be starting/unfocused + item = menu.item_children; + if (!upwards && item) + { + while(item.item_next) + item = item.item_next; + } + } + else + item = menu_simplenextitem(item, upwards); + + if (!item) + { //we reached the end of the list, let the parent frame try its next + return __NULL__; + } + + if (item.item_flags & IF_ISFRAME) + { //if the next item is a frame, try and select its first element instead + frame = (mitem_frame)item; + citem = menu_findnextitem(frame, upwards, __NULL__); + if (citem) + return citem; + } + + if (item.item_flags & IF_INVISIBLE) + continue; + if (item.item_flags & IF_SELECTABLE) + return item; + } + +}; +static void(mitem item) menu_deselectitem = +{ + if (!item) + return; + if (item && (item.item_flags & IF_ISFRAME)) + { + mitem_frame frame = (mitem_frame)item; + if (frame.item_kactivechild) + menu_deselectitem(frame.item_kactivechild); + } + item.item_focuschange(__NULL__, IF_KFOCUSED); //deselect the previous one +}; +static void(mitem item) menu_selectitem = +{ + if (!item) + return; + mitem_frame menu = item.item_parent; + if (menu) + { + if (menu.item_kactivechild != item) + menu_deselectitem(menu.item_kactivechild); + menu_selectitem(menu); + menu.item_focuschange(item, IF_KFOCUSED); //focus on the new + } +}; +void(mitem_frame rootmenu, float upwards) menu_selectnextitem = +{ + mitem item = menu_findnextitem(rootmenu, upwards, rootmenu.item_kactivechild?rootmenu.item_kactivechild:rootmenu.item_mactivechild); + if (!item) + item = menu_findnextitem(rootmenu, upwards, __NULL__); + + menu_selectitem(item); + item.item_focuschange(item, IF_KFOCUSED); //focus on the new +}; + +float(vector pos, float scan, float char, float down) mitem_frame::item_keypress = +{ + mitem ch; + float handled = FALSE; + + //compensate for the frame + pos[0] += item_framesize[0]; + pos[1] += item_framesize[1]; + + if (scan >= K_MOUSE1 && scan <= K_MOUSE5 && scan != K_MWHEELUP && scan != K_MWHEELDOWN) + { + if (item_exclusive) + ch = item_exclusive; + else + ch = item_mactivechild; + if (down) //keyboard focus follows on mouse click. + { + item_focuschange(ch, IF_KFOCUSED); + } + } + else + { + ch = item_kactivechild; + if (!ch && down) + { + //if there's no key child active, then go and pick one so you can just start using keyboard access etc. + if (item_exclusive) + ch = item_exclusive; + else if (item_mactivechild) + ch = item_mactivechild; + else + { + mitem c; + for (c = item_children; c; c = c.item_next) + { + if (c.item_flags & IF_SELECTABLE) + ch = c; + } + } + if (ch) + item_focuschange(ch, IF_KFOCUSED); + ch = item_kactivechild; + } + } + + if (vslider) + pos[1] -= vslider.val; + + if (ch) + { + if (ch.item_keypress) + handled = ch.item_keypress(pos + ch.item_position, scan, char, down); + } + if (vslider && !handled && (scan == K_MWHEELUP || scan == K_MWHEELDOWN)) //give mwheel to the slider if its visible. + handled = vslider.item_keypress(pos + vslider.item_position, scan, char, down); + + return handled; +}; +void() mitem_frame::item_remove = +{ + local mitem ch; + while (this.item_children) + { + ch = this.item_children; + this.item_children = ch.item_next; + ch.item_remove(); + } + super::item_remove(); +}; +void() mitem_frame::item_resized = +{ + mitem ch; + vector framemax = [item_size[0] - item_framesize[0]*2, item_size[1] - (item_framesize[1] + item_framesize[2])]; + for (ch = this.item_children; ch; ch = ch.item_next) + { + vector os = ch.item_size; + mitem_parentresized(ch, framemax); + if (ch.item_resized && ch.item_size != os) + ch.item_resized(); + } + item_flags |= IF_CLIENTMOVED; //make sure it happens. + + super::item_resized(); +}; +void(vector pos) mitem_frame::item_draw = +{ + local vector omin = ui.drawrectmin, omax = ui.drawrectmax; + local mitem ch; + local vector clientpos; + local vector clientsize; + + if (frame_hasscroll && (item_flags & IF_CLIENTMOVED)) + { + //if a client object moved, make sure the scrollbar is updated + item_flags &~= IF_CLIENTMOVED; + clientsize= '0 0'; + for(ch = item_children; ch; ch = ch.item_next) + { + if (clientsize[0] < ch.item_position[0] + ch.item_size[0]) + clientsize[0] = ch.item_position[0] + ch.item_size[0]; + if (clientsize[1] < ch.item_position[1] + ch.item_size[1]) + clientsize[1] = ch.item_position[1] + ch.item_size[1]; + } +// if (clientsize[0] > item_size[0] - item_framesize[0]*2) +// //add hscroll + if (clientsize[1] > item_size[1] - (item_framesize[1]+item_framesize[2])) + { + if (!vslider) + { + local mitem_vslider tmp; + tmp = spawn(mitem_vslider, val:0, stride:8); + vslider = tmp; + } + vslider.maxv = clientsize[1] - (item_size[1] - (item_framesize[1]+item_framesize[2])); + } + else if (vslider) + { + vslider.item_remove(); + vslider = (mitem_vslider)__NULL__; + } + } + else if (!frame_hasscroll && this.vslider) + { + vslider.item_remove(); + vslider = (mitem_vslider)__NULL__; + } + + + //compensate for the frame + pos[0] += item_framesize[0]; + pos[1] += item_framesize[1]; + + clientpos = pos; + clientsize = this.item_size; + clientsize[0] -= item_framesize[0]*2; + clientsize[1] -= (item_framesize[1]+item_framesize[2]); + + if (vslider) + { + //scroll+shrink the client area to fit the slider on it. + clientpos[1] -= vslider.val; + clientsize[0] -= vslider.item_size[0]; + } + + + if (ui.mousepos != ui.oldmousepos) + { + local mitem newfocus = __NULL__; + //if the mouse moved, select the new item + if (item_exclusive) + newfocus = item_exclusive; + else + { + for(ch = item_children; ch; ch = ch.item_next) + { + if (ch.item_flags & IF_SELECTABLE) + if (mouseinbox(clientpos + ch.item_position, ch.item_size)) + { + newfocus = ch; + } + } + } + if (vslider) + if (mouseinbox(pos + [clientsize[0], 0], vslider.item_size)) + newfocus = vslider; + this.item_focuschange(newfocus, IF_MFOCUSED); + } + + //clip the draw rect to our area, so children don't draw outside it. don't draw if its inverted. + if (pos_x > ui.drawrectmin[0]) + ui.drawrectmin[0] = pos_x; + if (pos_y > ui.drawrectmin[1]) + ui.drawrectmin[1] = pos_y; + if (pos_x+clientsize_x < ui.drawrectmax[0]) + ui.drawrectmax[0] = pos_x+clientsize_x; + if (pos_y+clientsize_y < ui.drawrectmax[1]) + ui.drawrectmax[1] = pos_y+clientsize[1]; + if (ui.drawrectmax[0] > ui.drawrectmin[0] && ui.drawrectmax[1] > ui.drawrectmin[1]) + { + ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]); + if (item_exclusive) + item_exclusive.item_draw(clientpos + ch.item_position); + else + { + for(ch = item_children; ch; ch = ch.item_next) + { + if not (ch.item_flags & IF_INVISIBLE) + ch.item_draw(clientpos + ch.item_position); + } + } + ui.setcliparea(omin_x, omin_y, omax_x - omin_x, omax_y - omin_y); + + if (vslider) + { + vslider.item_size[1] = clientsize[1]; + vslider.item_draw(pos + [clientsize[0], 0]); + } + } + ui.drawrectmin = omin; + ui.drawrectmax = omax; +}; +#define menuitemframe_spawn(sz) spawn(mitem_frame, item_size:sz) + +#endif //MITEM_FRAME_QC__ diff --git a/menusys/mitem_menu.qc b/menusys/mitem_menu.qc new file mode 100644 index 00000000..ab7f261f --- /dev/null +++ b/menusys/mitem_menu.qc @@ -0,0 +1,332 @@ +/*************************************************************************** +window-like menu. +interactable - basically just a container for the items in the menu, but also handles killing them+itself when the user presses escape. + +these items will automatically be added to the desktop/workspace thing +Call it.item_remove() to pop the menu. +Regular items can be added to the menu by first spawning them, then calling menu_additem to actually add it to the desired menu in the right place. +*/ + +class mitem_menu : mitem_frame +{ + vector draginfo; //x, y, resizeflags={0:none, 1:left, 2:bottom, 4:right, 8:top, 16:move} + + virtual float(vector pos, float scan, float char, float down) item_keypress; + virtual void(mitem newfocus, float flag) item_focuschange; + virtual void(vector pos) item_draw; + + virtual void() item_remove = + { + strunzone(item_text); + super::item_remove(); + }; + + nonvirtual float(vector pos) whichgrabhandle; + nonvirtual void(vector pos, float handle) drawgrabhandle; + void() mitem_menu = + { + item_text = strzone(item_text); + item_scale = 8; + item_rgb = MENUBACK_RGB; + item_alpha = MENUBACK_ALPHA; + + if (item_framesize == '0 0 0') + item_framesize = '4 16 4'; + + item_size[0] += item_framesize[0]; + item_size[1] += item_framesize[1]+item_framesize[2]; + + item_flags |= IF_SELECTABLE; + +#ifdef CSQC + cprint(""); +#endif + }; + + //same as mitem, but does not propogate to parent. + virtual string(string key) get = + { + return cvar_string(key); + }; + virtual void(string key, string newval) set = + { + cvar_set(key, newval); + }; +}; + +void(mitem newfocus, float flag) mitem_menu::item_focuschange = +{ + if (flag & IF_KFOCUSED) + { + //move the window to the top of the z-order when it gets focus. + if (item_flags & IF_KFOCUSED) + totop(); + //release grabs if someone else took focus. + else if (ui.mgrabs == this) + { + ui.mgrabs = __NULL__; + draginfo[2] = 0; + } + } + + super::item_focuschange(newfocus, flag); +}; + +void(vector pos, float handle) mitem_menu::drawgrabhandle = +{ + if ((handle & 3) == 3) + { + //bottom left + drawfill(pos + [0, item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]], '1 1 0', 1, 0); + handle &~= 3; + } + if ((handle & 6) == 6) + { + //bottom right + drawfill(pos + [item_size[0]-item_framesize[0], item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]], '1 1 0', 1, 0); + handle &~= 6; + } + if (handle & 1) + { + //left + drawfill(pos + [0, 0], [item_framesize[0], item_size[1]], '1 1 0', 1, 0); + } + if (handle & 2) + { + //bottom + drawfill(pos + [0, item_size[1]-item_framesize[2]], [item_size[0], item_framesize[2]], '1 1 0', 1, 0); + } + if (handle & 4) + { + //right + drawfill(pos + [item_size[0]-item_framesize[0], 0], [item_framesize[0], item_size[1]], '1 1 0', 1, 0); + } +}; + +float(vector pos) mitem_menu::whichgrabhandle = +{ + //handle dragging and resizing. + if (mouseinbox(pos, [item_size[0]-item_framesize[1], item_framesize[1]])) + { + //drag + return 16; + } + else if (this.item_flags & IF_RESIZABLE) + { + if (mouseinbox(pos + [0, item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]])) + { + //bottom-left + return 3; + } + else if (mouseinbox(pos + [item_size[0]-item_framesize[0], item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]])) + { + //bottom-right + return 6; + } + else if (mouseinbox(pos + [0, 0], [item_framesize[0], item_size[1]])) + { + //left + return 1; + } + else if (mouseinbox(pos + [0, item_size[1]-item_framesize[2]], [item_size[0], item_framesize[2]])) + { + //bottom + return 2; + } + else if (mouseinbox(pos + [item_size[0]-item_framesize[0], 0], [item_framesize[0], item_size[1]])) + { + //right + return 4; + } + } + return 0; +}; + +float(vector pos, float scan, float char, float down) mitem_menu::item_keypress = +{ + if (scan == K_MOUSE1 && (down&1)) + { + if (!(item_flags & IF_NOKILL) && mouseinbox(pos + [item_size[0]-item_framesize[1], 0], item_framesize[1] * '1 1')) + { + localcmd(strcat(item_command, "\n")); //console command to exec if someone clicks the close button. + this.item_remove(); + return TRUE; + } + draginfo[2] = this::whichgrabhandle(pos); + if (draginfo[2]) + ui.mgrabs = this; + if (draginfo[2] & (1|16)) + draginfo[0] = ui.mousepos[0] - pos_x; + if (draginfo[2] & 2) + draginfo[1] = (ui.mousepos[1] - pos_y - item_size[1]) + item_position[1]; + if (draginfo[2] & 4) + draginfo[0] = ui.mousepos[0] - pos_x - item_size[0] + item_position[0]; + if (draginfo[2] & (8|16)) + draginfo[1] = ui.mousepos[1] - pos_y; + if (draginfo[2]) + return TRUE; + } + else if (scan == K_MOUSE1 && draginfo[2]) + { + if (!draginfo[2] && (item_flags & IF_RESIZABLE)) + { + //if they dropped the window at the top of the screen, make sure its fullscreened to match how it was drawn... + queryscreensize(); + if (ui.mousepos[1] < 8) + item_size = ui.screensize; + if (this.item_resized) + item_resized(); + } + ui.mgrabs = __NULL__; + draginfo[2] = 0; + return TRUE; + } + + if (!super::item_keypress(pos, scan, char, down)) + { + down &= 1; + if (scan == K_ESCAPE && down) + { + if (this.item_flags & IF_NOKILL) + return FALSE; + else + { + localcmd(strcat(this.item_command, "\n")); //console command to exec if someone clicks the close button. + this.item_remove(); + return TRUE; + } + } + else if (scan == K_UPARROW && down) + menu_selectnextitem(this, TRUE); + else if (scan == K_DOWNARROW && down) + menu_selectnextitem(this, FALSE); + else if (scan == K_MOUSE2 && down && !(this.item_flags & IF_NOKILL)) + { //unhandled right click closes menus, if we're allowed + localcmd(strcat(item_command, "\n")); //console command to exec if someone clicks the close button. + this.item_remove(); + return TRUE; + } + else if (scan >= K_MOUSE1 && scan <= K_MWHEELDOWN) + return TRUE; //don't let the parent take unhandled mouse events. + else + return FALSE; + } + return TRUE; +}; +void(vector pos) mitem_menu::item_draw = +{ + float inset; + vector efsize = item_size; + if (draginfo[2]) + { + if (draginfo[2] & 1) + { //resize left + local float nmax = item_position[0] + item_size[0]; + local float nmin = item_position[0] + item_size[0]; + nmin = ui.mousepos[0] - (pos_x - item_position[0]) - draginfo[0]; + if (nmax-nmin < 128) + nmin = nmax - 128; + pos_x -= item_position[0]; + item_position[0] = nmin; + pos_x += item_position[0]; + item_size[0] = nmax - nmin; + if (item_resized) + item_resized(); + } + if (draginfo[2] & 2) + { //resize bottom + item_size[1] = ui.mousepos[1] - (pos_y - item_position[1]) - draginfo[1]; + if (item_size[1] < 16) + item_size[1] = 16; + if (item_resized) + item_resized(); + } + if (draginfo[2] & 4) + { //resize right + item_size[0] = ui.mousepos[0] - (pos_x - item_position[0]) - draginfo[0]; + if (item_size[0] < 128) + item_size[0] = 128; + if (item_resized) + item_resized(); + } + efsize = item_size; + if (draginfo[2]&16) + { + queryscreensize(); + if (ui.mousepos[1] < 8 && (item_flags & IF_RESIZABLE)) + { + //make it look as though its fullscreen, without destroying its actual size. + //yes, we will fake-resize everything inside. + item_position = '0 0'; + + item_size = ui.screensize; + if (this.item_resized) + this.item_resized(); + item_size = efsize; + efsize = ui.screensize; + } + else if (item_size == ui.screensize && (item_flags & IF_RESIZABLE)) + { + item_size = item_size*0.5; + draginfo[0] = draginfo[0]*0.5; + if (this.item_resized) + this.item_resized(); + efsize = item_size; + } + else + { + item_position = ui.mousepos - (pos - item_position) - draginfo; + item_position[2] = 0; + if (item_flags & IF_RESIZABLE) + if (item_resized) + item_resized(); + } + } + } + + //bound it to the screen... just in case the screen got resized or something + if (item_position[0] > ui.screensize[0] - item_size[0]*0.25) + item_position[0] = ui.screensize[0] - item_size[0]*0.25; + if (item_position[1] > ui.screensize[1] - item_framesize[1]) + item_position[1] = ui.screensize[1] - item_framesize[1]; + if (item_position[0] < item_size[0]*-0.75) + item_position[0] = item_size[0]*-0.75; + if (item_position[1] < 0) + item_position[1] = 0; + + local float drag = 0; + if (draginfo[2]) + drag = draginfo[2]; + else if (item_flags & IF_MFOCUSED) + drag = this::whichgrabhandle(pos); + if (drag) + this::drawgrabhandle(pos, drag); + + ui.drawfill(pos, efsize, item_rgb, item_alpha, 0); + local vector col = '1 1 1'; + if (item_flags & IF_KFOCUSED) + col_x = 0; + if ((item_flags & IF_MFOCUSED) && mouseinbox(pos, [efsize_x-item_framesize[1], item_framesize[1]])) + col_z = 0; + inset = (item_framesize[1]-item_scale)*0.5; + ui.drawstring(pos + '1 1'*inset, item_text, item_scale*'1 1', col, 1, 0); + if (!(item_flags & IF_NOKILL)) + { + if (mouseinbox(pos + [efsize_x-item_framesize[1], 0], item_framesize[1]*'1 1')) + col = '1 1 0'; + else + col = '1 1 1'; + ui.drawstring(pos + [efsize_x+inset-item_framesize[1], inset], "X", item_scale*'1 1', col, 1, 0); + } + super::item_draw(pos); +}; +mitem_menu(mitem_frame desktop, string mname, vector sz) menu_spawn = +{ + mitem_menu n = spawn(mitem_menu, item_text:mname, item_framesize:'4 16 4', item_size:sz); + +// n.item_flags |= IF_RESIZABLE; + + if (desktop) + desktop.addr(n, RS_X_MIN_PARENT_MIN | RS_X_MAX_OWN_MIN | RS_Y_MIN_PARENT_MIN | RS_Y_MAX_OWN_MIN, (desktop.item_size - n.item_size) * 0.5, n.item_size); + return n; +}; diff --git a/menusys/mitem_slider.qc b/menusys/mitem_slider.qc new file mode 100644 index 00000000..c671df85 --- /dev/null +++ b/menusys/mitem_slider.qc @@ -0,0 +1,153 @@ +/*************************************************************************** +slider item, directly attached to a cvar. +interactable - executes a given console command. +*/ +class mitem_hslider : mitem +{ + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress; + + vector item_slidercontrols; //min, max, step + + virtual void() item_resized = + { + if (isvalid(item_command)) + item_flags |= IF_SELECTABLE; + else + item_flags &= ~IF_SELECTABLE; + super::item_resized(); + }; +}; +void(vector pos) mitem_hslider::item_draw = +{ + local float curval; + vector rgb = self.item_rgb; + if (!(item_flags & IF_SELECTABLE)) + rgb *= 0.2; + + super::item_draw(pos); + pos_x += item_size_x / 2; + + if (ui.mgrabs == this) + { + //if we're sliding it, update the value + curval = (ui.mousepos[0] - pos_x-8) / (10*8); + curval = bound(0, curval, 1); + curval = curval * (item_slidercontrols_y - item_slidercontrols_x); + if (!ui.shiftheld) + curval = rint(curval / item_slidercontrols_z) * item_slidercontrols_z; //round it. + curval += item_slidercontrols_x; + set(item_command, sprintf("%g", curval)); + } + curval = stof(get(item_command)); + + if (dp_workarounds) + { //no ^U markup support. chr2str avoids warnings about non-utf8 strings which at least allows bi-compat to work. + string s = strcat(chr2str(0xe080, 0xe081, 0xe081, 0xe081, 0xe081, 0xe081), chr2str(0xe081, 0xe081, 0xe081, 0xe081, 0xe081, 0xe082)); + //slider background uses the fallback quake chars + ui.drawstring(pos, sprintf("%s (%g)", s, curval), '1 1 0' * self.item_scale, rgb, self.item_alpha, 0); + //now draw an indicater char in the right place. + //the inner side of the boundary is 4 pixels wide so we can overlap the ends by that many pixels. + curval = (curval - self.item_slidercontrols_x) / (self.item_slidercontrols_y - self.item_slidercontrols_x); //fractionize it + curval = bound(0, curval, 1); + ui.drawstring(pos + [4 + curval*10*8, 0], chr2str(0xe083), '1 1 0' * self.item_scale, rgb, self.item_alpha, 0); + } + else + { + //slider background uses the fallback quake chars + ui.drawstring(pos, sprintf("^{e080}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e081}^{e082} (%g)", curval), '1 1 0' * self.item_scale, rgb, self.item_alpha, 0); + //now draw an indicater char in the right place. + //the inner side of the boundary is 4 pixels wide so we can overlap the ends by that many pixels. + curval = (curval - self.item_slidercontrols_x) / (self.item_slidercontrols_y - self.item_slidercontrols_x); //fractionize it + curval = bound(0, curval, 1); + ui.drawstring(pos + [4 + curval*10*8, 0], "^{e083}", '1 1 0' * self.item_scale, rgb, self.item_alpha, 0); + } +}; +float(vector pos, float scan, float char, float down) mitem_hslider::item_keypress = +{ + if (down&2) + { + //we have grabs, and mouse was released? + if (scan == K_MOUSE1 && !(down&1)) + { //we're done here. + ui.mgrabs = __NULL__; + return TRUE; + } + return FALSE; //not handled, don't inhibit + } + if (down) + { + local float curval = stof(get(item_command)); + if (scan == K_MWHEELUP || scan == K_MWHEELDOWN) + { + if (ui.mousepos[0] > pos_x + item_size[0]/2) + scan = ((scan == K_MWHEELDOWN)?K_LEFTARROW:K_RIGHTARROW); + } + if (scan == K_MOUSE1 && down) + { + pos_x += item_size_x / 2; + if (ui.mousepos[0] < pos_x) + return TRUE;//goto keyenter; + curval = (ui.mousepos[0] - pos_x-8) / (10*8); + if (curval < 0 || curval > 1) + return FALSE; + curval = curval * (item_slidercontrols_y - item_slidercontrols_x) + item_slidercontrols_x; + set(item_command, sprintf("%g", curval)); + ui.mgrabs = this; + } + else if (scan == K_DEL && down && cvar_type(item_command)) + set(item_command, cvar_defstring(item_command)); + else if ((scan == K_LEFTARROW || scan == K_MWHEELUP) && down) + { + if (item_slidercontrols_x > item_slidercontrols_y) + set(item_command, sprintf("%g", min(curval - item_slidercontrols_z, item_slidercontrols_x))); + else + set(item_command, sprintf("%g", max(curval - item_slidercontrols_z, item_slidercontrols_x))); + } + else if ((scan == K_RIGHTARROW || scan == K_MWHEELDOWN) && down) + { + if (item_slidercontrols_x > item_slidercontrols_y) + set(item_command, sprintf("%g", max(curval + item_slidercontrols_z, item_slidercontrols_y))); + else + set(item_command, sprintf("%g", min(curval + item_slidercontrols_z, item_slidercontrols_y))); + } + else if ((scan == K_ENTER || scan == K_SPACE) && down) + { +//keyenter: + if (item_slidercontrols_x > item_slidercontrols_y) + { + if (curval-0.001 <= item_slidercontrols_y) + set(item_command, sprintf("%g", item_slidercontrols_x)); + else + set(item_command, sprintf("%g", max(curval + item_slidercontrols_z, item_slidercontrols_y))); + } + else + { + if (curval+0.001 >= item_slidercontrols_y) + set(item_command, sprintf("%g", item_slidercontrols_x)); + else + set(item_command, sprintf("%g", min(curval + item_slidercontrols_z, item_slidercontrols_y))); + } + } + else + return FALSE; + return TRUE; + } + else if (scan == K_MOUSE1 && ui.mgrabs == this) + ui.mgrabs = __NULL__; + return FALSE; +}; +mitem_hslider(string text, string command, vector controls, vector sz) menuitemslider_spawn = +{ + mitem_hslider n = spawn(mitem_hslider); + n.item_scale = sz_y; + n.item_text = text; + n.item_size = sz; + + n.item_slidercontrols = controls; + + n.item_command = command; + if (n.isvalid(command)) + n.item_flags |= IF_SELECTABLE; + return n; +}; diff --git a/menusys/mitem_spinnymodel.qc b/menusys/mitem_spinnymodel.qc new file mode 100644 index 00000000..28df0386 --- /dev/null +++ b/menusys/mitem_spinnymodel.qc @@ -0,0 +1,164 @@ +/* +renderscene stuff is always available in csqc. +If the engine supports DP_QC_RENDER_SCENE then its meant to be available in menuqc too. +In practise, DP advertises this to menuqc even though it has never officially supported it. +At the time of writing, FTE's dev builds can do it (and only advertise the extension in builds that try to support it). + +Note: the basemenu mod does not make use of this in menuqc if only because its vaugely trying to support both engines, and its easier to just use an ifdef. + +The mitem_spinnymodel item just shows a rotating model centered on the z axis. Simple as that. +For the sake of fun gimmicks, you can specify frame information with firstframe and framecount. +Additionally, you can cause it to switch to a different animation when it faces towards the camera with shootframe and shootframes. +This style of animation shouldn't really be considered very complex, but might help give a small demo of the basic concept of animation. +*/ +/* +Note - DP Bugs: +1: viewport positions are interpreted in physical pixels in DP. + there is no reliable way to know how many physical pixels there actually are. + custom viewports are thus near unusable. +2: failure to revert the viewport to default afterwards fucks over any 2d stuff drawn afterwards. + including the console. +3: bloom on worldless models draws the world. +4: lighting is applied on models even if there's no world. + enabling rtlights really fucks everything up. +5: gamma/contrast/brightness are applied to the 3d view. even if there's no world. + this results in horrible squares if these settings are used. +6: DP_QC_RENDER_SCENE is advertised in menuqc, but renderscene is not supported there at all. +7: avoid the use of cltime. DP doesn't support it. + +probably others. it really wouldn't surprise me. +*/ + +//helper function to work around a DP bug. +static vector(vector v) vtodpp = +{ +#ifndef CSQC_SIMPLE + //so fucking disgustingly ugly. + if (dp_workarounds) + { + v_x *= cvar("vid_width") / cvar("vid_conwidth"); + v_y *= cvar("vid_height") / cvar("vid_conheight"); + } +#endif + return v; +}; +//make sure the fields are all defined if we're in menuqc or something +noref .vector origin; +noref .vector angles; +noref .vector mins; +noref .vector maxs; +noref .string model; +noref .float frame, frame2, lerpfrac, renderflags; +float frametime; +class mitem_spinnymodel : mitem +{ + float zbias; + float firstframe; + float framecount; + float shootframe; + float shootframes; + float dontrotate; + float rotatespeed; + vector startangle; + string skin; + float topcolour; + float bottomcolour; + + //angles.y = startangle; +#ifndef EXT_CSQC + virtual void(vector pos) item_draw = {}; +#else + + //might as well use the class as the entity that is drawn. + //it might end up clobbering any fields used for multiple things... + virtual void(vector pos) item_draw = + { + vector orgbias; + orgbias = '0 0 0'; + if (dp_workarounds) + orgbias = (vector)getviewprop(VF_ORIGIN); //DP still lights the entity even if the world isn't drawn. this results in inconsistant/buggy light levels. there's nothing we can do about that other than stopping it from being completely black. + origin = orgbias; + origin_z += zbias; + +// angles_y = cltime*90;//frametime*90; +// angles_y += frametime*90; + if(dontrotate) { + angles = startangle; + } else { + if(!rotatespeed) + rotatespeed = 90; + angles_y += frametime*rotatespeed; + } + + clearscene(); //wipe the scene, and apply the default rendering values. + setviewprop(VF_MIN, vtodpp(pos)); //min pos + setviewprop(VF_SIZE, vtodpp(item_size)); //size=maxpos-minpos + if (dp_workarounds) + setviewprop(VF_FOV, [25, atan(item_size_y/(item_size_x/tan(25/360*6.28))) * 360/6.28]); //set an explicit fov. this thing had better be square. DP doesn't support VF_AFOV + else + setviewprop(VF_AFOV, 30); //set the aproximate fov (ie: engine takes care of aspect ratio). +#ifdef CSQC + setproperty(VF_DRAWENGINESBAR, FALSE); + setproperty(VF_DRAWWORLD, FALSE); + setproperty(VF_DRAWCROSSHAIR, FALSE); +#endif + setviewprop(VF_ORIGIN, orgbias + '-128 0 0'); //look towards it. + setviewprop(VF_ANGLES, '0 0 0'); + + //animate it a bit + lerpfrac -= frametime*10; + while(lerpfrac < 0) + { + lerpfrac += 1; + frame2 = frame; + frame += 1; + if (angles_y >= 170 && shootframes && !dontrotate) + { + if (frame == shootframe+shootframes) + { //reached the last frame. clear the shooting 'flag' and go back to idle + frame = firstframe; + angles_y -= 360; + } + else if (frame < shootframe || frame >= shootframe+shootframes) + frame = shootframe; //we were still idle, apparently. + } + else + { + if (frame < firstframe || frame >= firstframe+framecount) + frame = firstframe; + } + } + + addentity(this); + renderscene(); + if (dp_workarounds) + { //dp fucks up 2d stuff if we don't explicitly restore the 3d view to fullscreen + setviewprop(VF_MIN, vtodpp('0 0 0')); + setviewprop(VF_SIZE, vtodpp(ui.screensize)); + } + setcustomskin(self, "", sprintf("q1upper \"%f\"\nq1lower \"%f\"\nqwskin \"%s\"\n", topcolour, bottomcolour, skin)); + //setcustomskin(self, skin, ""); + //setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\n\n", cvar_string("topcolor"), cvar_string("bottomcolor"))); + }; + + virtual void(vector pos) dp_draw = + { + }; + + void() mitem_spinnymodel = + { +#if defined(MENU) || defined(CSQC_SIMPLE) + if (!checkextension("DP_QC_RENDER_SCENE") || dp_workarounds) + { + item_draw = dp_draw; + return; + } +#endif + precache_model(item_text); + setmodel(this, item_text); //use the size information from the engine, woo for unreliability. + zbias += (mins_z - maxs_z)/2 - mins_z; //center the model on its z axis, so the whole thing is visible. + frame = firstframe; + }; +#endif +}; + diff --git a/menusys/mitem_tabs.qc b/menusys/mitem_tabs.qc new file mode 100644 index 00000000..47ef7e66 --- /dev/null +++ b/menusys/mitem_tabs.qc @@ -0,0 +1,168 @@ +/*************************************************************************** +tabs/tab widgets. +the 'tabs' widget is simply a tab-selection control. horizontal multiple choice. it draws only its currently active child. +the 'tab' widget is merely a container of other widgets, no different from a standard frame object, just has a name and a specific size. +*/ +class mitem_tabs : mitem_frame /*frame... but not really*/ +{ + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress; +// virtual void() item_resize; + + void() mitem_tabs = + { + item_framesize = '2 16 2'; + item_flags |= IF_SELECTABLE|IF_RESIZABLE; + }; +}; + +class mitem_tab : mitem_frame +{ + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + if (scan == K_UPARROW && down) + menu_selectnextitem(this, TRUE); + else if (scan == K_DOWNARROW && down) + menu_selectnextitem(this, FALSE); + else if (super::item_keypress(pos, scan, char, down)) + return TRUE; + else + return FALSE; + return TRUE; + }; + + void() mitem_tab = + { + item_framesize = '0 0 0'; + item_flags |= IF_SELECTABLE|IF_RESIZABLE; + }; +}; + +void(vector pos) mitem_tabs::item_draw = +{ + local mitem ch; + local vector tpos = pos; + local float w; + local vector col; + + //to highlight the active tab, we draw the top line 1 pixel higher, and no bottom line + for (ch = item_children; ch; ch = ch.item_next) + { + w = stringwidth(ch.item_text, TRUE, '8 8') + 8; + + ui.drawfill(tpos + '0 1', [1, 15], TD_LFT, item_alpha, 0); + ui.drawfill(tpos + [w-1, 1], [1, 14], TD_RGT, item_alpha, 0); + if (ch == item_kactivechild) + { + //top line + ui.drawfill(tpos, [w, 1], TD_TOP, item_alpha, 0); + } + else + { + //top line + ui.drawfill(tpos + '0 1', [w, 1], TD_TOP, item_alpha, 0); + //bottom + ui.drawfill(tpos + '0 15', [w, 1], TD_TOP, item_alpha, 0); + } + + col = item_rgb; + if (!(ch.item_flags & IF_SELECTABLE)) + col *= 0.2; + else + { + if (!item_kactivechild) + item_focuschange(ch, IF_KFOCUSED); + if (mouseinbox(tpos, [w, 16])) + col_z = 0; + if (ch.item_flags & IF_KFOCUSED) + col_x = 0; + } + + ui.drawstring(tpos + '4 4', ch.item_text, '8 8', col, item_alpha, 0); + tpos_x += w; + } + ui.drawfill(tpos + '0 15', [pos_x + item_size_x - tpos_x, 1], TD_TOP, item_alpha, 0); //top + ui.drawfill(pos + '0 16', [1, item_size_y - 16], TD_LFT, item_alpha, 0); //left + ui.drawfill(pos + [item_size_x-1, 16], [1, item_size_y - 17], TD_RGT, item_alpha, 0); //right + ui.drawfill(pos + [1, item_size_y-1], [item_size_x-1, 1], TD_BOT, item_alpha, 0); //bottom + + if (item_mactivechild != item_kactivechild) + item_focuschange(item_kactivechild, IF_MFOCUSED); //give the tab full focus. + ch = item_kactivechild; + if (ch) + ch.item_draw(pos + ch.item_position + [item_framesize[0], item_framesize[1]]); +}; +float(vector pos, float scan, float char, float down) mitem_tabs::item_keypress = +{ + local mitem ch; + local vector tpos = pos; + local vector sz; + local float result; + + if (down && (scan == K_MOUSE1 || scan == K_MOUSE2 || scan == K_MOUSE3)) + { + sz_y = 16; + //to highlight the active tab, we draw the top line 1 pixel higher, and no bottom line + for (ch = this.item_children; ch; ch = ch.item_next) + { + sz_x = stringwidth(ch.item_text, TRUE, '8 8') + 8; + if (mouseinbox(tpos, sz)) + { + item_focuschange(ch, IF_KFOCUSED); //give the tab full focus. + return TRUE; + } + + tpos_x += sz_x; + } + } + ch = item_kactivechild; + if (ch) + { + result = ch.item_keypress(pos + [item_framesize[0], item_framesize[1]] + ch.item_position, scan, char, down); + if (!result && down) + { + if (scan == K_TAB || scan == K_RIGHTARROW) + { + ch = ch.item_next; + if (!ch) + ch = item_children; + item_focuschange(ch, IF_KFOCUSED); + result = TRUE; + } +// else if (scan == K_LEFTARROW) +// { +// ch = ch.item_next; +// if (!ch) +// ch = item_children; +// item_focuschange((ch.item_next?ch.item_next:this.item_children), IF_KFOCUSED); +// result = TRUE; +// } + } + } + else + result = FALSE; + return result; +}; +/*void() mitem_tabs::item_resize = +{ + local mitem ch; + for (ch = this.item_children; ch; ch = ch.item_next) + { + ch.item_size = this.item_size; + if (ch.item_resized) + ch.item_resized(); + } +};*/ + +mitem_tabs(vector sz) menuitemtabs_spawn = +{ + return spawn(mitem_tabs, item_size:sz); +}; +mitem_tab(mitem_tabs tabs, string itname) menuitemtab_spawn = +{ + //a tab itself is little different from a frame, just has no implicit focus, and has a title + mitem_tab n = spawn(mitem_tab, item_text:itname, frame_hasscroll:TRUE); + + tabs.addr(n, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + return n; +}; diff --git a/menusys/mitems.qc b/menusys/mitems.qc new file mode 100644 index 00000000..782b580f --- /dev/null +++ b/menusys/mitems.qc @@ -0,0 +1,439 @@ +/*all these .funcs etc need self assigned properly first, as is customary with qc*/ + +#ifdef MENU +#define cltime time +#endif + +#ifdef CSQC +#define csqconly +#else +#define csqconly __strip +#endif +#ifdef MENU +#define menuonly +#else +#define menuonly __strip +#endif + + + +//#include "mitems.qh" + +__strip var float dp_workarounds; + +#define IF_SELECTABLE (1<<0) //can accept KFOCUSED/MFOCUSED and key events etc. cannot be selected otherwise. +#define IF_INTERACT (1<<1) //generic interaction flag for use by the widgets themselves. +#define IF_RESIZABLE (1<<2) //may be resized, either by parent (it takes the full space) or by user. +#define IF_MFOCUSED (1<<3) //mouse is currently sitting over it +#define IF_KFOCUSED (1<<4) //has keyboard focus +#define IF_NOKILL (1<<5) //kill button is disabled. move to frame/menu? +#define IF_DRAGGABLE (1<<6) //can be dragged. this is stupid. +#define IF_DROPPABLE (1<<7) //dragged items can be dropped on this item. +#define IF_CLIENTMOVED (1<<8) //recalc required client dimensions (and toggle scrollbars if needed). move to frame? +#define IF_CENTERALIGN (1<<9) // +#define IF_RIGHTALIGN (1<<10) // +#define IF_NOCURSOR (1<<11) //when mgrabbed, the cursor will not be shown +#define IF_ISFRAME (1<<12) //is derived from mitem_frame (helps debugging recurion). +#define IF_FOCUSFOLLOWSMOUSE (1<<13) //on frames, child keyboard focus (mostly) follows the mouse cursor. not like windows, but handy on things with lots of buttons. annoying on the desktop. move to frame? +#define IF_INVISIBLE (1<<14) + +#define RS_X_MIN_PARENT_MIN 0x0000 +#define RS_X_MIN_PARENT_MID 0x0001 +#define RS_X_MIN_PARENT_MAX 0x0002 +#define RS_X_FRACTION 0x0004 + +#define RS_X_MAX_OWN_MIN 0x0000 +#define RS_X_MAX_PARENT_MIN 0x0010 +#define RS_X_MAX_PARENT_MID 0x0020 +#define RS_X_MAX_PARENT_MAX 0x0040 + +#define RS_Y_MIN_PARENT_MIN 0x0000 +#define RS_Y_MIN_PARENT_MID 0x0100 +#define RS_Y_MIN_PARENT_MAX 0x0200 +#define RS_Y_FRACTION 0x0400 + +#define RS_Y_MAX_OWN_MIN 0x0000 +#define RS_Y_MAX_PARENT_MIN 0x1000 +#define RS_Y_MAX_PARENT_MID 0x2000 +#define RS_Y_MAX_PARENT_MAX 0x4000 + +//the 3d effect needs some sort of fake lighting values. +//these are for bumps. invert for inset things. +#define TD_TOP '0.8 0.8 0.8' +#define TD_LFT '0.6 0.6 0.6' +#define TD_RGT '0.2 0.2 0.2' +#define TD_BOT '0.0 0.0 0.0' + +#ifndef MENUBACK_RGB +#define MENUBACK_RGB '0.4 0.365 0.29' +//#define MENUBACK_RGB '0.5 0.5 0.6' +#endif +#ifndef MENUBACK_ALPHA +#define MENUBACK_ALPHA 0.8 +#endif + +//#ifdef TARGET_FTE +//#pragma TARGET FTE +//#endif + +//#define HEIRACHYDEBUG //enable this and press f1 to print out the current menuitem tree + +class mitem_frame; +.vector mins; //gravity mins +.vector maxs; //gravity mins +class mitem +{ + void() mitem; + virtual void(vector pos) item_draw; + virtual float(vector pos, float scan, float char, float down) item_keypress = {return FALSE;}; + virtual void(mitem newfocus, float changedflag) item_focuschange; //move into frame? + virtual string(string key) get; + virtual void(string key, string newval) set; + virtual float(string key) isvalid; + virtual void() item_remove; + virtual void() item_resized; + float item_flags; //contains IF_ flags + vector item_position; //relative to the parent's client area. which is admittedly not well defined... + vector item_size; //interaction bounding box. + float item_scale; //text etc scale + vector item_rgb; //colours! + float item_alpha; //transparency value + string item_text; //used as a unique identifier + string item_command; //something to do when clicked. move out? + mitem_frame item_parent; //the item that contains us. make mitem_frame? + mitem item_next; //the next child within the parent + + float resizeflags; + + + static void() totop; +}; + +//this struct is used to access the various drawing functions. this allows the functions to be replaced for worldspace stuff +typedef struct uiinfo_s +{ + void(float min_x, float min_y, float max_x, float max_y) setcliparea; + float(vector min, string imagename, vector size, vector col, float alph, float drawflag) drawpic; + float(vector min, vector size, vector col, float alph, float drawflag) drawfill; + float(vector min, float charcode, vector scale, vector col, float alph, float drawflag) drawcharacter; + float(vector min, string text, vector scale, vector col, float alph, float drawflag) drawstring; + + mitem kgrabs; //kfocused or mfocused or both or none to say what sort of grabs is in effect. + mitem mgrabs; //says who has stolen all input events. + + float shiftheld; //shift is held. + float mousedown; //which mouse buttons are currently held. + vector oldmousepos; //old mouse position, to track whether its moved. + vector mousepos; //current mouse position. + vector screensize; //total screen size + vector drawrectmin; //minimum scissor region, to clamp children to within the confines of its parent. + vector drawrectmax; //maximum scissor region + +#ifndef MENU + //menuqc has no concept of the world and cannot display or query 3d positions nor projections. Any related UI elements are thus not available to menuqc. + //these globals are not part of the ui struct either, because they're illegal in world UIs. + float havemouseworld; //whether the mouseworld stuff is valid - ie: that the cursor is in a 3d view + vector mouseworldnear; //position of the mouse cursor upon the near clip plane in world space + vector mouseworldfar; //position of the mouse cursor upon the far(ish) clip plane in world space +#endif +} uiinfo_t; +var uiinfo_t ui = +{ + drawsetcliparea, + drawpic, + drawfill, + drawcharacter, + drawstring +}; + + + +void() queryscreensize = +{ +#ifdef MENU + //there is no proper way to do this. + //fte thus has special checks for these cvars, and they should not be autocvars if you want them to work properly. + ui.screensize[0] = cvar("vid_conwidth"); + ui.screensize[1] = cvar("vid_conheight"); + ui.screensize[2] = 0; +#endif +#ifdef CSQC + #ifdef CSQC_SIMPLE + ui.screensize = screensize; + #else + //make sure the screensize is set. + normalize('0 0 1'); //when getproperty fails to return a meaningful value, make sure that we don't read some random stale value. + ui.screensize = (vector)getproperty(VF_SCREENVSIZE); + if (ui.screensize[2]) //lingering return value from normalize. + { + ui.screensize[2] = 0; + ui.screensize[0] = cvar("vid_conwidth"); + ui.screensize[1] = cvar("vid_conheight"); + } + #endif +#endif +}; + +//helper function +float(vector minp, vector sz) mouseinbox = +{ + if (ui.mousepos[0] < minp_x) + return FALSE; + if (ui.mousepos[1] < minp_y) + return FALSE; + if (ui.mousepos[0] >= minp_x + sz_x) + return FALSE; + if (ui.mousepos[1] >= minp_y + sz_y) + return FALSE; + + return TRUE; +}; + + +void(mitem ch, vector parentsize) mitem_parentresized = +{ + float f = ch.resizeflags; + + if (f & RS_X_FRACTION) + ch.item_position[0] = parentsize[0] * ch.mins[0]; + else if (f & RS_X_MIN_PARENT_MAX) + ch.item_position[0] = parentsize[0] + ch.mins[0]; + else if (f & RS_X_MIN_PARENT_MID) + ch.item_position[0] = parentsize[0]/2 + ch.mins[0]; + else //if (f & RS_X_MIN_PARENT_MIN) + ch.item_position[0] = ch.mins[0]; + + if (f & RS_X_FRACTION) + ch.item_position[0] = parentsize[0] * ch.maxs[0]; + else if (f & RS_X_MAX_PARENT_MIN) + ch.item_size[0] = ch.maxs[0] - ch.item_position[0]; + else if (f & RS_X_MAX_PARENT_MID) + ch.item_size[0] = ch.maxs[0]+parentsize[0]/2 - ch.item_position[0]; + else if (f & RS_X_MAX_PARENT_MAX) + ch.item_size[0] = ch.maxs[0]+parentsize[0] - ch.item_position[0]; + else //if (f & RS_X_MAX_OWN_MIN) + ch.item_size[0] = ch.maxs[0]; + + if (f & RS_Y_FRACTION) + ch.item_position[1] = parentsize[1] * ch.mins[1]; + else if (f & RS_Y_MIN_PARENT_MAX) + ch.item_position[1] = parentsize[1] + ch.mins[1]; + else if (f & RS_Y_MIN_PARENT_MID) + ch.item_position[1] = parentsize[1]/2 + ch.mins[1]; + else //if (f & RS_Y_MIN_PARENT_MIN) + ch.item_position[1] = ch.mins[1]; + + if (f & RS_Y_FRACTION) + ch.item_position[1] = parentsize[1] * ch.maxs[1]; + else if (f & RS_Y_MAX_PARENT_MIN) + ch.item_size[1] = ch.maxs[1] - ch.item_position[1]; + else if (f & RS_Y_MAX_PARENT_MID) + ch.item_size[1] = ch.maxs[1]+parentsize[1]/2 - ch.item_position[1]; + else if (f & RS_Y_MAX_PARENT_MAX) + ch.item_size[1] = ch.maxs[1]+parentsize[1] - ch.item_position[1]; + else //if (f & RS_Y_MAX_OWN_MIN) + ch.item_size[1] = ch.maxs[1]; +}; + +#include "mitem_frame.qc" +void() mitem::item_resized = +{ + if (this.item_parent) + this.item_parent.item_flags |= IF_CLIENTMOVED; +}; + + +#ifdef HEIRACHYDEBUG +void mitem_printnode(float depth, mitem root, string prefix) +{ + mitem ch; + string col = ""; + if (root.item_flags & IF_KFOCUSED && root.item_flags & IF_MFOCUSED) + col = "^2"; + else if (root.item_flags & IF_KFOCUSED) + col = "^5"; + else if (root.item_flags & IF_MFOCUSED) + col = "^3"; + + print(sprintf("%s%s%i:%s%s\n", col, strpad(depth, ""), root, prefix, root.item_text)); + + //can only recurse into items which are actually frames. + if (root.item_flags & IF_ISFRAME) + { + mitem_frame fr = (mitem_frame)root; + depth+=1; + for(ch = fr.item_children; ch; ch = ch.item_next) + { + if (ch.item_parent != root) + print("corrupt parent\n"); + if (ch.item_next == ch) + { + print("infinite loop\n"); + break; + } + string pre = ""; + if (fr.item_mactivechild == ch) + pre = strcat(pre, "m"); + if (fr.item_kactivechild == ch) + pre = strcat(pre, "k"); + if (pre) + pre = strcat(pre, " "); + mitem_printnode(depth, ch, pre); + } + } +}; +void mitem_printtree(mitem_frame root, string from, float line) +{ + print(sprintf("%s:%g\n", from, line)); + mitem_printnode(0, root, ""); +} +#endif + +string(string key) mitem::get = +{ + //walk through to the parent for menu parents to track all this. + if (this.item_parent) + return this.item_parent.get(key); + else //no parent, just assume its a cvar. + return cvar_string(key); +}; +void(string key, string newval) mitem::set = +{ + //walk through to the parent for menu parents to track all this. + if (this.item_parent) + this.item_parent.set(key, newval); + else //no parent, just assume its a cvar. + cvar_set(key, newval); +}; +float(string key) mitem::isvalid = +{ + //walk through to the parent for menu parents to track all this. + if (this.item_parent) + return this.item_parent.isvalid(key); + else //no parent, just assume its a cvar. + return cvar_type(key); +}; + + +/*************************************************************************** +basic 'null' item, for completeness, every other item logically inherits from this. +drawing this just shows its text right-aligned at w/2. most things will want to override this. +*/ +void(mitem newfocus, float flag) mitem::item_focuschange = +{ +}; + +//z order is determined by the list order. the ones at the end (oldest) are on top. +void() mitem::totop = +{ + mitem_frame p = item_parent; + mitem prev; + //unlink it + if (p.item_children == this) + prev = p.item_children = item_next; + else + { + for (prev = p.item_children; prev; prev = prev.item_next) + { + if (prev.item_next == this) + { + prev.item_next = item_next; + break; + } + } + } + + item_next = __NULL__; + if (prev) + { + //add it on the end + while(prev.item_next) + prev = prev.item_next; + prev.item_next = this; + } + else + p.item_children = this; +}; + +vector(mitem it) menuitem_textcolour = +{ + local vector col; + col = it.item_rgb; + if (!(it.item_flags & IF_SELECTABLE) && it.item_keypress && it.item_command != "") + col *= 0.2; + else + { + if (it.item_flags & IF_MFOCUSED) + col_z = 0; + if (it.item_flags & IF_KFOCUSED) + col_x = 0; + } + return col; +}; +void(vector pos) mitem::item_draw = +{ + vector col; + pos_x += this.item_size[0] / 2 - stringwidth(this.item_text, TRUE, '1 1 0'*this.item_scale) - 8; + col = menuitem_textcolour(this); + ui.drawstring(pos, this.item_text, '1 1 0' * this.item_scale, col, this.item_alpha, 0); +}; +void() mitem::item_remove = +{ + local mitem ch; + //any children got removed by the frame code. + + //make sure the item is removed from its parent. + local mitem_frame p = this.item_parent; + if (p) + { + if (p.item_exclusive == this) + p.item_exclusive = __NULL__; + + if (p.item_children == this) + p.item_children = this.item_next; + else + { + for(ch = p.item_children; ch; ch = ch.item_next) + { + if (ch.item_next == this) + { + ch.item_next = this.item_next; + break; + } + } + } + } + + //pick a different item on the parent. + if (p.item_mactivechild == this) + p.item_focuschange(__NULL__, IF_MFOCUSED); + if (p.item_kactivechild == this) + { + for (ch = p.item_children; ch; ch = ch.item_next) + { + if (ch.item_flags & IF_SELECTABLE) + break; + } + p.item_focuschange(ch, IF_KFOCUSED); + } + if (ui.kgrabs == this) + ui.kgrabs = __NULL__; + if (ui.mgrabs == this) + ui.mgrabs = __NULL__; + remove((entity)this); + + //force mousefocus to update + ui.oldmousepos = '-1 -1'; +}; +void() mitem::mitem = +{ + if (!this.item_scale) + this.item_scale = 1; + if (!this.item_rgb) + this.item_rgb = '1 1 1'; + if (!this.item_alpha) + this.item_alpha = 1; + + //force mousefocus to update + ui.oldmousepos = '-1 -1'; +}; diff --git a/menusys/mitems_common.qc b/menusys/mitems_common.qc new file mode 100644 index 00000000..b8b73a3b --- /dev/null +++ b/menusys/mitems_common.qc @@ -0,0 +1,185 @@ +/*************************************************************************** +simple block-fill item +non-interactable. +*/ +class mitem_fill : mitem +{ + virtual void(vector pos) item_draw = + { + ui.drawfill(pos, this.item_size, this.item_rgb, this.item_alpha, 0); + }; +}; +#define menuitemfill_spawn(sz,rgb,alph) spawn(mitem_fill, item_size:sz, item_rgb:rgb, item_alpha:alph) + +/*************************************************************************** +basic picture item. +non-interactable. + +item_text: the normal image to use +item_text_mactive: the image to use when the mouse is over it. +item_size: if not set, will be set to the size of the image named by item_text. if only y is set, x will be sized to match aspect with y. +*/ +class mitem_pic : mitem +{ + string item_text_mactive; + virtual void(vector pos) item_draw = + { + if (item_text_mactive != "" && (item_flags & IF_MFOCUSED)) + ui.drawpic(pos, item_text_mactive, item_size, item_rgb, item_alpha, 0); + else + ui.drawpic(pos, item_text, item_size, item_rgb, item_alpha, 0); + }; + void() mitem_pic = + { + if (dp_workarounds) + { + if (substring(item_text, -4, 4) == ".lmp") + item_text = substring(item_text, 0, -5); + if (substring(item_text_mactive , -4, 5) == ".lmp") + item_text_mactive = substring(item_text_mactive, 0, -4); + } + + item_text = strzone(item_text); + precache_pic(item_text); + if (item_text_mactive) + { + item_text_mactive = strzone(item_text_mactive); + precache_pic(item_text_mactive); + } + + if (!item_size[0]) + { + float y = item_size[1]; + item_size = drawgetimagesize(item_text); + if (y) //rescale x to ma + { + if (!item_size[1]) //bad image? don't glitch out too much. + item_size = item_size[0] * '1 1 0'; + else + item_size = [item_size[0] * (y / item_size[1]), y, 0]; + } + } + }; + virtual void() item_remove = + { + strunzone(item_text); + if (item_text_mactive) + strunzone(item_text_mactive); + super::item_remove(); + }; +}; +#define menuitempic_spawn(img,sz) spawn(mitem_pic, item_text:img, item_size:sz) + +/*************************************************************************** +basic text item. +interactable - executes a given console command. +*/ +class mitem_text : mitem +{ + virtual void(vector pos) item_draw = + { + vector rgb = menuitem_textcolour(this); + float w; + if (item_flags & IF_CENTERALIGN) + { + w = stringwidth(item_text, TRUE, '1 1 0'*item_scale); + ui.drawstring(pos + [(item_size_x-w)/2, 0], item_text, '1 1 0' * item_scale, rgb, item_alpha, 0); + } + else if (item_flags & IF_RIGHTALIGN) + { + w = stringwidth(item_text, TRUE, '1 1 0'*item_scale); + ui.drawstring(pos + [(item_size_x-w), 0], item_text, '1 1 0' * item_scale, rgb, item_alpha, 0); + } + else + ui.drawstring(pos, item_text, '1 1 0' * item_scale, rgb, item_alpha, 0); + }; + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + if (this.item_command) + { + if (!down) + return FALSE; + if (scan == K_ENTER || (scan == K_MOUSE1 && mouseinbox(pos, this.item_size))) + { + item_parent.item_execcommand(this, this.item_command); +// localcmd(strcat(this.item_command, "\n")); + return TRUE; + } + } + return FALSE; + }; + + //zone+unzone input strings as needed + virtual void() item_remove = + { + strunzone(item_text); + if (item_command) + strunzone(item_command); + super::item_remove(); + }; + void() mitem_text = + { + item_text = strzone(item_text); + if (item_command != "") + { + item_command = strzone(item_command); + item_flags |= IF_SELECTABLE; + } + }; +}; +mitem(string text, string command, float height) menuitemtext_spawn = +{ + return spawn(mitem_text, item_scale:height, item_text:text, item_command:command, item_size:[stringwidth(text, TRUE, '1 1 0'*height), height, 0]); +}; + + +/*************************************************************************** +basic text item. +identical to text, but includes a 3dish border. +*/ +class mitem_button : mitem +{ + virtual void(vector pos) item_draw = + { + ui.drawfill(pos, [this.item_size[0], 1], TD_TOP, this.item_alpha, 0); + ui.drawfill(pos, [1, this.item_size[1] - 1], TD_LFT, this.item_alpha, 0); + ui.drawfill(pos + [this.item_size[0]-1, 1], [1, this.item_size[1] - 1], TD_RGT, this.item_alpha, 0); + ui.drawfill(pos + [0, this.item_size[1]-1], [this.item_size[0], 1], TD_BOT, this.item_alpha, 0); + + pos_x += (this.item_size[0] - stringwidth(this.item_text, TRUE, '1 1 0'*this.item_scale)) * 0.5; + pos_y += (this.item_size[1] - this.item_scale)*0.5; + ui.drawstring(pos, this.item_text, '1 1 0' * this.item_scale, menuitem_textcolour(this), this.item_alpha, 0); + }; + virtual float(vector pos, float scan, float char, float down) item_keypress = + { + if (!down) + return FALSE; + if (scan == K_ENTER || (scan == K_MOUSE1 && mouseinbox(pos, this.item_size))) + item_parent.item_execcommand(this, item_command); + else + return FALSE; + return TRUE; + }; + virtual void() item_remove = + { + strunzone(item_text); + if (item_command) + strunzone(item_command); + super::item_remove(); + }; +}; +mitem_button(string text, string command, vector sz) menuitembutton_spawn = +{ + mitem_button n = spawn(mitem_button); + n.item_scale = sz_y - 4; + n.item_text = strzone(text); + n.item_size = sz; + + if (command != "") + { + n.item_command = strzone(command); + n.item_flags |= IF_SELECTABLE; + } + return n; +}; + diff --git a/menusys/readme.txt b/menusys/readme.txt new file mode 100644 index 00000000..2d8a3f3a --- /dev/null +++ b/menusys/readme.txt @@ -0,0 +1,220 @@ +integrating into an existing mod: +the csqc/menu needs to instanciate a mitem_desktop (or derived class). items_keypress+items_draw need to be called in the relevent places with the relevent arguments, then you can start creating children and throwing them at the screen. +the desktop is the root object, and tracks whether the mouse/keys should be grabbed. + +general overview: +The menu system is build from a heirachy/tree of mitem nodes. +To draw the menu, the tree is walked from the root (the 'desktop' object) through its children (pictures, text, or whatever). +Each mitem inherits its various properties from a parent object using classes. For instance, the desktop inherits from mitem_frame(read: a container object), which in turn inherits from mitem(the root type). +When a container is moved or resized, all of its children (and their children) will automatically be resized accordingly. Once the container is destroyed, the children will also be automatically destroyed. +Drawing items is fairly simple. The root node is told to draw itself. Once it has drawn its background, it walks through its children asking them to draw themselves (telling the child exactly where it is on the scree). Other containers(like windows) do the same. In this way the entire tree is drawn. +Input happens in a somewhat similar manner. The parent decides which child the mouse is over, and sends mouse or keyboard to the relevent focused child. As a special exception, if an element has set ui.*grabs to refer to itself, that object gets to snoop on input first before even the desktop gets a chance. +To make a quake-style menu, you should create an mitem_exmenu, and then call the desktop's .add method to insert it. Then you need to spawn things like cvar sliders/combos/etc and use one of the menu's add methods to place it on the menu/window. Check the example code. + +Items that don't specify a method will inherit that method from its parent. +If you want only a minor change, for instance drawing a background under the item, you can make an item_draw method which draws the background then calls super::item_draw() with the same arguments in order to provide the parent's normal behaviour. Doing this with a menu's get+set methods allows you to use slider/etc mitems with things other than direct cvars (if you want an 'apply changes' button or so). + + +globals: +autocvar_menu_font: defaults to 'cour', which will only work in windows, fallback font otherwise. The menu code will register+use a font with this name suitable for 8 vpixels high, and 16vpixels. +dp_workarounds: needed to work around DP bugs. Set to 1 if you detect that the code is running inside DP. +ui: a struct containing the current ui state. Can be temporarily overwritten for alternative menu systems (like ones drawn on walls or whatever). + probably would have been nicer if it was a pointer, but I didn't want to depend upon those. + Within the ui struct are a few functions which typically just map to the equivelent builtins. + Placing a copy of these in the ui struct allows them to be overridden in order to project a menu/ui upon a wall efficiently without extra code. + these are the functions available: setcliparea, drawpic, drawfill, drawcharacter, drawstring +ui.mousedown: the mouse buttons that are currently pressed. +ui.oldmousepos: the mouse position that was set in the previous frame. this can be used to detect whether the mouse has moved. +ui.mousepos: the current virtual screen position of the mouse cursor. +ui.screensize: the virtual resolution of the screen - the dimensions the UI needs to fill. +ui.drawrectmin: the current viewport scissor min position (so over-sized items can draw outside of their containing frames without issue). +ui.drawrectmax: the current viewport scissor max position (so over-sized items can draw outside of their containing frames without issue). +ui.havemouseworld: whether the mouseworld[near/far] globals are valid - ie: that the cursor is in a 3d view. only exists in csqc. +ui.mouseworldnear: position of the mouse cursor upon the near clip plane in world space. +ui.mouseworldfar: position of the mouse cursor upon the far(ish) clip plane in world space. You can trace a line between these two vectors to detect which entities the mouse should interact with. +ui.kgrabs: set this global in order to redirect all keyboard buttons to this object. +ui.mgrabs: set this global in order to redirect all mouse buttons to this object. If the object that has focus also has item_flags&IF_NOCURSOR, the mouse cursor will be hidden. + +helper functions: +mouseinbox: returns whether ui.mousepos is within the box specified by the min+size arguments. + +mitems.qc:class mitem + root menuitem object that all else inherits from + + EVENTS: + void item_draw(pos): override this to replace how the item displays. the default is quite lame. pos is the virtual screen position. + float item_keypress(vector pos,float scan,float char, float down): the object got a keyboard or mouse click. pos is the virtual screen position. scan is the K_FOO scancode constant. char is the unicode value of the codepoint. either may be 0. some systems might always use 0 for one of scan+char. down says that the key was just pressed, false means it just got released. + void item_focuschange(mitem newfocus, float changedflag): the object's focus changed. newfocus is the item that gained focus, changedflag is either IF_MFOCUSED, IF_KFOCUSED, or both. check this against newfocus to see if this object gained focus. + string(string key) get: helper function. calls the parent's get method. + void(string key, string newval) set: helper function. calls the parent's set method. + void() item_remove: the item got removed. this callback can be used to free memory. be sure to notify super. + void() item_resized: the item has been resized or moved. provided to resize+move helper objects to match a parent, or recalculate cached extents or whatever. + + FIELDS: + item_flags: various flags + IF_SELECTABLE: item can be selected, either with mouse or keyboard. + IF_INTERACT: flag reserved for child classes to use. + IF_RESIZABLE: item can be resized. menus will show resize corners. + IF_MFOCUSED: item has mouse focus (parents will retain the flag) + IF_KFOCUSED: item has keyboard focus (parents will retain the flag) + IF_NOKILL: item has been marked as resisting closure. This applies to menus and will disable the implicit 'x' button. + IF_NOCURSOR: if the item grabs the mouse, the cursor will be hidden, allowing mlook to still work when some widget is grabbing everything (eg: an exmenu using right-click to look). + item_position: the (virtual) position of the object relative to its parent. + item_size: the current (virtual) size of the object. + item_scale: typically serves to rescale text. not used by the menu framework itself. + item_rgb: the colour field for the item. typically defaults to '1 1 1' if not otherwise set. + item_alpha: the alpha value for the item. typically defaults to 1. + item_text: typically used as the caption. also used as a searchable item name. + item_command: the cvar or console command associated with the object. potentially other uses. yay for repurposing fields. + item_parent: the frame that contains this object. + item_next: the next sibling within the parent. + mins: the resize gravity bias for the 'min' pos. + maxs: the resize gravity bias for the 'max' pos. + resizeflags: controls the meaning of the mins+maxs positions. + RS_[X/Y]_[MIN/MAX]_PARENT_MIN: the min/max position is relative to the top/left of the parent. + RS_[X/Y]_[MIN/MAX]_PARENT_MID: the min/max position is relative to the center of the parent. + RS_[X/Y]_[MIN/MAX]_PARENT_MAX: the min/max position is relative to the bottom/right of the parent. + RS_[X/Y]_FRACTION: the min+max positions are 0-1 values scaled within the min/max position of the parent. + RS_[X/Y]_MAX_OWN_MIN: the max position is set relative to the objects own minimum size, giving an absolute object size. + + static functions: + totop(): moves the object to the top of the parent's z-order. drawn last, this object will now appear over everything else. does not affect focus. + + non-member functions (FIXME): + mitem_printtree: debug function to print out a list of the items children+siblings. + queryscreensize: updates the screensize global. + mitem_parentresized: updates an item's position and size according to its resizeflags. + menuitem_textcolour: helper function. determines the text colour to use for cvar widgets based upon selectable and mouse/keyboard focus. + +mitem_frame.qc:class mitem_frame : mitem + generic borderless container object for other items. + + FIELDS: + item_framesize_x: border width. children will not overlap this. + item_framesize_y: border at top. children will not overlap this. + item_framesize_z: border at bottom. children will not overlap this. + frame_hasscroll: if true, enables a vertical slider so the frame is still usable if the screen is too small. + item_children: the first child object of the frame + item_mactivechild: the current child that has the mouse over it. + item_kactivechild: the current child that has keyboard focus. + + static functions: + findchild(string title): scans through a frame's children looking for an item with a matching item_text. + add(mitem newitem, float resizeflags, vector originmin, vector originmax): adds an item to a frame, with specified gravity+position etc settings. see mitem::resizeflags for details. + adda(mitem newitem, vector pos): adds an item to a frame with preset item_size and position relative to the top-left of the parent frame. + addr(mitem newitem, float resizeflags, vector originmin, vector originmax): adds an item to a frame, with specified gravity+position etc settings, with reversed z order. this item will be drawn over the top of the previous objects, and is the more natural ordering. + addc(mitem newitem, float ypos): adds an item to a frame with a preset item_size at a specific y position. multiple objects with the same mins_y+maxs_y will automatically be spread across horizontally with a gap between each. + +mitem_bind.qc:class mitem_bind : mitem + a widget to change a key binding. up to two keys will be listed. additional keys will currently remain hidden. + item_text: the description of the key binding (ie: "Attack") + item_command: the console command to bind the key to (ie: "+attack") + +mitem_checkbox.qc:class mitem_check : mitem + a true/false cvar checkbox. + item_text: the description of the setting + item_command: the name of the cvar to toggle + + optional factory: mitem_check(string text, string command, vector sz) menuitemcheck_spawn; + +mitem_colours.qc:class mitem_colours : mitem + A simple colour picker. supports only hue. + item_text: the description of the setting + item_command: the name of the cvar to change (sets to 0xRRGGBB notation). + + factory: mitem_colours(string text, string command, vector sz) menuitemcolour_spawn; + +mitem_combo.qc:class mitem_combo : mitem + multiple choice widget. + item_text: the description of the setting + mstrlist: a list of the valid settings, in "\"value\" \"description\" \"value\" \"description\"" notation. + FIXME: must spawn through: mitem_combo(string text, string command, vector sz, string valuelist) menuitemcombo_spawn; + +mitem_combo.qc:class mitem_combo_popup : mitem + internal friend class of the combo. + this holds the list of options when clicked. + you should not use this class directly. + +mitem_desktop.qc:class mitem_desktop : mitem_frame + the root item that should be used as the parent of all other elements in order to be visible. + forces itself to fullscreen, handles grabs, etc. + in csqc, will display the default game view (including split screen views). + + csqc + float(mitem_desktop desktop, float evtype, float scanx, float chary, float devid) items_keypress + menuqc: + float(mitem_desktop desktop, float scan, float char, float down) items_keypress + both: + void(mitem_desktop desktop) items_draw + + +mitem_edittext.qc:class mitem_edit : mitem + text entry widget (typically) attached to a cvar. + item_text: the short description of the setting. + item_command: the name of the cvar to receive a new value/be displayed + +mitem_exmenu.qc:class mitem_exmenu : mitem_frame + 'exclusive' menu object. + this container has no borders. + does not provide a background. use a mitem_pic or mitem_fill for that. + not much more than a frame, but can take unhandled escape/right click to close the menu. + typically used fullscreen. + item_text: a searchable identifier for the object + item_command: the console command to execute when the item is removed. used to restore the parent menu. + +mitem_frame.qc:class mitem_vslider : mitem + vertical up/down slider not attached to a cvar. + used to scroll frames up+down for when you have too many items in there for the current video mode. + fixme: document + + factory macro: menuitemframe_spawn(sz) + typically created via inheritance. + +mitem_menu.qc:class mitem_menu : mitem_frame + movable resizable window + + item_flags: + IF_RESIZABLE: enables resize handles on left+bottom+right+lower corners. + IF_NOKILL: disables the 'x' button on the top-right. + non-member construtor: + menu_spawn(mitem_frame desktop, string mname, vector sz): centers and automatically adds the object. required for the default border size. do not call any of the add* methods yourself if you use this. + +mitem_slider.qc:class mitem_hslider : mitem + horizontal slider attached to a cvar. + item_text: the short description of the setting. + item_command: the name of the cvar to change. + item_slidercontrols_x: the minimum value. + item_slidercontrols_y: the maximum value. + item_slidercontrols_z: how much to change the cvar by each time the user uses the left/right arrows to change its value. + +mitem_tabs.qc:class mitem_tabs : mitem_frame + tabstrip object that appears presenting the various tab options. + acts as a container only for mitem_tab objects which are the real containers. + +mitem_tabs.qc:class mitem_tab : mitem_frame + child of a tabstrip that contains the various elements sited upon a single tab. + item_text: the caption displayed for the tab. + +mitems_common.qc:class mitem_fill : mitem + fills the screen region with a block of colour. + item_rgb: colour to fill it with. + item_alpha: alpha blended by this much. 1 for full block colour. + +mitems_common.qc:class mitem_pic : mitem + simple image display. + item_text: the default image to display. + item_text_mactive: if specified, the image to display when the object has mouse focus. + item_command: console command to execute when clicked. + +mitems_common.qc:class mitem_text : mitem + simple plain text + item_text: the text to display. + item_command: the console command to execute when clicked. + item_scale: the height of the text, in virtual pixels, so ideally 8 or more. + +mitems_common.qc:class mitem_button : mitem + centered text with a noticable border that just seems to say 'click me'... + item_text: the text to display. + item_command: the console command to execute when clicked. + item_scale: the height of the text, in virtual pixels, so ideally 8 or more. + From c47a6364e23c1585507fb7ad17df3d70c228c2f3 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 14 Jun 2019 23:48:35 +1200 Subject: [PATCH 0690/2474] better options menu flag model --- menu/options.qc | 11 ++++++++++- menusys/mitem_spinnymodel.qc | 7 +++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/menu/options.qc b/menu/options.qc index 2d89d05e..742d5d42 100644 --- a/menu/options.qc +++ b/menu/options.qc @@ -54,7 +54,16 @@ nonstatic void(mitem_desktop desktop) M_Options = //random art for style #if 1//def CSQC //m.addm(spawn (mitem_spinnymodel, item_text: "progs/suit.mdl"), [0, 12*-16/2], [160, 12*16/2]); - m.add(spawn (mitem_spinnymodel, item_text: "progs/tf_flag.mdl", skin:"skin1",dontrotate:1, startangle:'0 192 0', firstframe:0, framecount:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [64, 12*-16/2], [160, 12*16/2]); + m.add(spawn ( + mitem_spinnymodel, + item_text: "progs/tf_stan.mdl", + skin:"", + dontrotate:0, + startangle:'0 192 0', + firstframe:0, + framecount:1, + fov:40 + ), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [64, 12*-16/2], [160, 12*16/2]); #else //menuqc doesn't support entities. shove some random crappy static image there instead. local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); diff --git a/menusys/mitem_spinnymodel.qc b/menusys/mitem_spinnymodel.qc index 28df0386..f31308bb 100644 --- a/menusys/mitem_spinnymodel.qc +++ b/menusys/mitem_spinnymodel.qc @@ -63,6 +63,7 @@ class mitem_spinnymodel : mitem string skin; float topcolour; float bottomcolour; + float fov; //angles.y = startangle; #ifndef EXT_CSQC @@ -93,10 +94,12 @@ class mitem_spinnymodel : mitem clearscene(); //wipe the scene, and apply the default rendering values. setviewprop(VF_MIN, vtodpp(pos)); //min pos setviewprop(VF_SIZE, vtodpp(item_size)); //size=maxpos-minpos + if(!fov) + fov = 30; if (dp_workarounds) - setviewprop(VF_FOV, [25, atan(item_size_y/(item_size_x/tan(25/360*6.28))) * 360/6.28]); //set an explicit fov. this thing had better be square. DP doesn't support VF_AFOV + setviewprop(VF_FOV, [fov, atan(item_size_y/(item_size_x/tan(fov/360*6.28))) * 360/6.28]); //set an explicit fov. this thing had better be square. DP doesn't support VF_AFOV else - setviewprop(VF_AFOV, 30); //set the aproximate fov (ie: engine takes care of aspect ratio). + setviewprop(VF_AFOV, fov); //set the aproximate fov (ie: engine takes care of aspect ratio). #ifdef CSQC setproperty(VF_DRAWENGINESBAR, FALSE); setproperty(VF_DRAWWORLD, FALSE); From e7bd0ba3daeefa8040a2a20bcaa92c9434d8a1af Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 15 Jun 2019 20:52:38 +1200 Subject: [PATCH 0691/2474] non-blocking detpack --- demoman.qc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/demoman.qc b/demoman.qc index c75b9d38..e0897d84 100644 --- a/demoman.qc +++ b/demoman.qc @@ -268,7 +268,7 @@ void () TeamFortress_DetpackSet = { newmis.owner = self.owner; newmis.origin = (self.owner.origin - '0 0 23'); newmis.movetype = MOVETYPE_BOUNCE; - newmis.solid = SOLID_BBOX; + newmis.solid = SOLID_TRIGGER; //so that scout can disarm newmis.classname = "detpack"; newmis.flags = FL_ITEM; newmis.angles = '90 0 0'; @@ -388,11 +388,15 @@ void () TeamFortress_DetpackTouch = { return; makevectors(other.v_angle); - source = other.origin + '0 0 16'; - - traceline(source, source + v_forward * 64, 0, other); - if ((trace_fraction == 1) || (trace_ent != self)) + //source = other.origin + '0 0 16'; + source = other.origin + other.view_ofs; + + self.solid = SOLID_BBOX; + traceline(source, source + v_forward * 64, MOVE_HITMODEL | MOVE_EVERYTHING | MOVE_TRIGGERS, other); + self.solid = SOLID_TRIGGER; + if ((trace_fraction == 1) || (trace_ent != self)) { return; + } other.immune_to_check = time + 5; other.tfstate = other.tfstate | TFSTATE_CANT_MOVE; @@ -420,7 +424,7 @@ void () TeamFortress_DetpackDisarm = { } bprint(PRINT_MEDIUM, self.enemy.owner.netname, "'s detpack was defused by ", self.owner.netname, "\n"); - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 65536); + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_CANT_MOVE); TF_AddFrags(self.owner, 1); TeamFortress_SetSpeed(self.owner); self.enemy.owner.detpack_left = 0; From ea639eaab0a40cba03181b75958a1954c93a7148 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 15 Jun 2019 21:06:04 +1200 Subject: [PATCH 0692/2474] localinfo toggle for solid_detpack --- README.md | 1 + client.qc | 5 +++++ demoman.qc | 9 +++++++-- qw.qc | 1 + tfort.qc | 1 + 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 74419322..2bc2cc69 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Server option for setting detpack to solid (blocking). Off by default. `localinfo solid_detpack 1` or `localinfo sdp 1`. * Server option for overriding map class restrictions (except civilian). `serverinfo override_mapclasses 1` or `serverinfo omc 1`. * Option for maximum grenades for all classes. `localinfo max_gren1_ `, short `localinfo mg1_ `. Works for gren1s and gren2s. Eg `localinfo max_gren1_scout 0` to remove caltrops or `localinfo mg2_9 2` to reduce max EMPs to 2. * Option to fully restock player's clip and finish reload immediately if in progress. `localinfo stock_reload 1` (`localinfo srd 1`) will trigger only on flag capture (with stock_on_cap enabled). `2` will trigger whenever any tfgoal gives you the appropriate ammo. diff --git a/client.qc b/client.qc index 9c79061f..b5ba1b0f 100644 --- a/client.qc +++ b/client.qc @@ -571,6 +571,9 @@ void () DecodeLevelParms = { max_gren2_spy = CF_GetSetting("mg2_8", "max_gren2_spy", ftos(PC_SPY_GRENADE_MAX_2)); max_gren2_engineer = CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(PC_ENGINEER_GRENADE_MAX_2)); + // solid detpack toggle [0] + solid_detpack = CF_GetSetting("sdp", "solid_detpack", "0"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; @@ -640,6 +643,7 @@ void () DecodeLevelParms = { max_gren2_pyro = PC_PYRO_GRENADE_MAX_2; max_gren2_spy = PC_SPY_GRENADE_MAX_2; max_gren2_engineer = PC_ENGINEER_GRENADE_MAX_2; + solid_detpack = FALSE; } st = infokey(world, "faithful"); @@ -710,6 +714,7 @@ void () DecodeLevelParms = { max_gren2_pyro = 4; max_gren2_spy = 4; max_gren2_engineer = 4; + solid_detpack = TRUE; } } diff --git a/demoman.qc b/demoman.qc index e0897d84..f286c952 100644 --- a/demoman.qc +++ b/demoman.qc @@ -268,7 +268,11 @@ void () TeamFortress_DetpackSet = { newmis.owner = self.owner; newmis.origin = (self.owner.origin - '0 0 23'); newmis.movetype = MOVETYPE_BOUNCE; - newmis.solid = SOLID_TRIGGER; //so that scout can disarm + if(solid_detpack) { + newmis.solid = SOLID_BBOX; + } else { + newmis.solid = SOLID_TRIGGER; //so that scout can disarm + } newmis.classname = "detpack"; newmis.flags = FL_ITEM; newmis.angles = '90 0 0'; @@ -393,7 +397,8 @@ void () TeamFortress_DetpackTouch = { self.solid = SOLID_BBOX; traceline(source, source + v_forward * 64, MOVE_HITMODEL | MOVE_EVERYTHING | MOVE_TRIGGERS, other); - self.solid = SOLID_TRIGGER; + if(!solid_detpack) + self.solid = SOLID_TRIGGER; if ((trace_fraction == 1) || (trace_ent != self)) { return; } diff --git a/qw.qc b/qw.qc index 0b6d06e4..760cca4d 100644 --- a/qw.qc +++ b/qw.qc @@ -546,6 +546,7 @@ float unpause_countdown; float unpause_lastcountnumber; float chweap_wait_attfinished; float override_mapclasses; +float solid_detpack; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/tfort.qc b/tfort.qc index cebf3ee1..dca8fa53 100644 --- a/tfort.qc +++ b/tfort.qc @@ -696,6 +696,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Drop feign backpack", feign_pack, "", 1); CF_PrintSetting("Print feign death message", feign_msg, "", 1); CF_PrintSetting("Override Map Class Limits", override_mapclasses, "", 0); + CF_PrintSetting("Solid Detpack", solid_detpack, "", 0); if (server_faithful) { sprint(self, PRINT_HIGH, "\nThis server is running faithful Team Fortress settings.\n"); From 578d4361715e84d13148ccb67e1191079d999eb1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 15 Jun 2019 21:50:28 +1200 Subject: [PATCH 0693/2474] engineer now dismantles enemy buildings (and gets cells and a frag as a reward) --- engineer.qc | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/engineer.qc b/engineer.qc index 7e8a72d0..c9001c79 100644 --- a/engineer.qc +++ b/engineer.qc @@ -889,6 +889,20 @@ void () Dispenser_Die = { void (entity disp) Engineer_UseDispenser = { local entity dist_checker; + // engineer hits enemy dispenser - dismantle + if(!(disp.team_no > 0 && disp.team_no == self.team_no)) { + self.ammo_cells = self.ammo_cells + 50; + disp.real_owner.has_dispenser = 0; + bprint(PRINT_HIGH, self.netname, " dismantled ", disp.real_owner.netname, "'s dispenser\n"); + TF_AddFrags(self, 1); + sprint(disp.real_owner, PRINT_HIGH, "Your dispenser was dismantled by ",self.netname,"\n"); + dremove (disp); + ThrowGib("progs/dgib1.mdl", -30); + ThrowGib("progs/dgib2.mdl", -50); + ThrowGib("progs/dgib3.mdl", -50); + return; + } + if (disp.health < disp.max_health && !old_spanner) { Engineer_Dispenser_Repair(disp); return; @@ -1031,16 +1045,30 @@ void (entity gun) Engineer_UseSentryGun = { // automate tasks if old_spanner setting is disabled if (!old_spanner) { - if (gun.weapon < 3 && self.ammo_cells >= 130) { - Engineer_SentryGun_Upgrade(gun); - return; - } else if (gun.health < gun.max_health && self.ammo_cells > 0) { - Engineer_SentryGun_Repair(gun); - return; - } else if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) - || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets - && self.ammo_rockets > 0)) { - Engineer_SentryGun_InsertAmmo(gun); + if(gun.team_no > 0 && gun.team_no == self.team_no) { + if (gun.weapon < 3 && self.ammo_cells >= 130) { + Engineer_SentryGun_Upgrade(gun); + return; + } else if (gun.health < gun.max_health && self.ammo_cells > 0) { + Engineer_SentryGun_Repair(gun); + return; + } else if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) + || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets + && self.ammo_rockets > 0)) { + Engineer_SentryGun_InsertAmmo(gun); + return; + } + } else { // hit enemy sentry + self.ammo_cells = self.ammo_cells + 65; + gun.real_owner.has_sentry = 0; + bprint(PRINT_HIGH, self.netname, " dismantled ", gun.real_owner.netname, "'s sentry gun\n"); + TF_AddFrags(self, 1); + sprint(gun.real_owner, PRINT_HIGH, "Your sentry gun was dismantled by ",self.netname,"\n"); + dremove (gun.trigger_field); + dremove (gun); + ThrowGib("progs/tgib1.mdl", -30); + ThrowGib("progs/tgib2.mdl", -50); + ThrowGib("progs/tgib3.mdl", -50); return; } } From 3bf2375d322747713b8820e4dcc07a6db37c227f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 19 Jun 2019 01:04:32 +1200 Subject: [PATCH 0694/2474] Add toggle for all walls to block EMPs; Add spawnflag for entity-level block --- README.md | 1 + client.qc | 4 ++ defs.h | 2 + engineer.qc | 126 ++++++++++++++++++++++++++++------------------------ qw.qc | 1 + tfort.qc | 1 + 6 files changed, 77 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 2bc2cc69..2a331614 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Server option for making all walls block EMP. Off by default. `localinfo walls_block_emp 1` or `localinfo wbe 1`. (SPAWNFLAG_BLOCK_EMP 4096 will work regardless) * Server option for setting detpack to solid (blocking). Off by default. `localinfo solid_detpack 1` or `localinfo sdp 1`. * Server option for overriding map class restrictions (except civilian). `serverinfo override_mapclasses 1` or `serverinfo omc 1`. * Option for maximum grenades for all classes. `localinfo max_gren1_ `, short `localinfo mg1_ `. Works for gren1s and gren2s. Eg `localinfo max_gren1_scout 0` to remove caltrops or `localinfo mg2_9 2` to reduce max EMPs to 2. diff --git a/client.qc b/client.qc index b5ba1b0f..a88028ee 100644 --- a/client.qc +++ b/client.qc @@ -573,6 +573,8 @@ void () DecodeLevelParms = { // solid detpack toggle [0] solid_detpack = CF_GetSetting("sdp", "solid_detpack", "0"); + // All Walls Block EMP [0] + walls_block_emp = CF_GetSetting("wbp", "walls_block_emp", "0"); st = infokey(world, "default"); if (st == "on") { @@ -644,6 +646,7 @@ void () DecodeLevelParms = { max_gren2_spy = PC_SPY_GRENADE_MAX_2; max_gren2_engineer = PC_ENGINEER_GRENADE_MAX_2; solid_detpack = FALSE; + walls_block_emp = FALSE; } st = infokey(world, "faithful"); @@ -715,6 +718,7 @@ void () DecodeLevelParms = { max_gren2_spy = 4; max_gren2_engineer = 4; solid_detpack = TRUE; + walls_block_emp = FALSE; } } diff --git a/defs.h b/defs.h index cb0fc5af..9c68564f 100644 --- a/defs.h +++ b/defs.h @@ -636,6 +636,8 @@ #define BUILD_HEALTH_DISPENSER 150 #define BUILD_HEALTH_SENTRYGUN 150 +#define SPAWNFLAG_BLOCK_EMP 4096 + // Dispenser's maximum carrying capability #define BUILD_DISPENSER_MAX_SHELLS 400 #define BUILD_DISPENSER_MAX_NAILS 600 diff --git a/engineer.qc b/engineer.qc index c9001c79..2076edb9 100644 --- a/engineer.qc +++ b/engineer.qc @@ -149,6 +149,7 @@ void () EMPGrenadeExplode = { local float expsize; local entity te; local entity oldself; + local float candamage; WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_TAREXPLOSION); @@ -160,73 +161,45 @@ void () EMPGrenadeExplode = { te = findradius(self.origin, 240); while (te) { te.chain2 = te.chain; - if ((te.touch == ammo_touch) || (te.touch == weapon_touch)) { - if (te.classname != "item_spikes") { + candamage = TRUE; + if(walls_block_emp) + candamage = CanDamage(te, self); + traceline(self.origin, te.origin, MOVE_NOMONSTERS, self); + if(trace_ent && trace_ent.spawnflags & SPAWNFLAG_BLOCK_EMP) { + candamage = FALSE; + } + if(candamage) { + if ((te.touch == ammo_touch) || (te.touch == weapon_touch)) { + if (te.classname != "item_spikes") { + te.solid = SOLID_NOT; + te.enemy = self.owner; + te.nextthink = time + 1 + random() * 2; + te.think = EMPExplode; + } + } else if (te.think == TeamFortress_DetpackExplode) { te.solid = SOLID_NOT; - te.enemy = self.owner; te.nextthink = time + 1 + random() * 2; - te.think = EMPExplode; - } - } else if (te.think == TeamFortress_DetpackExplode) { - te.solid = SOLID_NOT; - te.nextthink = time + 1 + random() * 2; - dremove(te.oldenemy); - } else if (te.classname == "pipebomb") { - te.nextthink = time + 0.1; - } else if ((te.classname == "building_dispenser") || - (te.classname == "building_sentrygun")) { - if (! - (((teamplay & 16) && (te.team_no > 0)) && - (te.team_no == self.owner.team_no))) { - TF_T_Damage(te, self, self.owner, 200, 0, TF_TD_EXPLOSION); - } - } else if (te.classname == "ammobox") { - expsize = 0; - expsize = expsize + te.ammo_shells * 0.75; - expsize = expsize + te.ammo_rockets * 0.75 * 2; - expsize = expsize + te.ammo_cells * 0.75 * 2; - if (expsize > 0) { - te.solid = 0; - deathmsg = 30; - T_RadiusDamage(te, self.owner, expsize, te); - te.think = SUB_Remove; + dremove(te.oldenemy); + } else if (te.classname == "pipebomb") { te.nextthink = time + 0.1; - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, te.origin_x); - WriteCoord(MSG_MULTICAST, te.origin_y); - WriteCoord(MSG_MULTICAST, te.origin_z); - multicast(te.origin, MULTICAST_PHS); - } - } else if ((te.classname == "player") || - (te.touch == BackpackTouch)) { - if (! - ((teamplay & 16) && (te.team_no > 0) && - (te.team_no == self.owner.team_no))) { + } else if ((te.classname == "building_dispenser") || + (te.classname == "building_sentrygun")) { + if (! + (((teamplay & 16) && (te.team_no > 0)) && + (te.team_no == self.owner.team_no))) { + TF_T_Damage(te, self, self.owner, 200, 0, TF_TD_EXPLOSION); + } + } else if (te.classname == "ammobox") { expsize = 0; expsize = expsize + te.ammo_shells * 0.75; expsize = expsize + te.ammo_rockets * 0.75 * 2; - if (te.playerclass != PC_ENGINEER) { - expsize = expsize + te.ammo_cells * 0.75; - } + expsize = expsize + te.ammo_cells * 0.75 * 2; if (expsize > 0) { + te.solid = 0; deathmsg = 30; T_RadiusDamage(te, self.owner, expsize, te); - if (te.touch != BackpackTouch) { - TF_T_Damage(te, self, self.owner, expsize, 2, 4); - te.ammo_shells = ceil(te.ammo_shells * 0.25); - te.ammo_rockets = ceil(te.ammo_rockets * 0.25); - if (te.playerclass != PC_ENGINEER) { - te.ammo_cells = ceil(te.ammo_cells * 0.25); - } - oldself = self; - self = te; - W_SetCurrentAmmo(self); - self = oldself; - } else { - te.think = SUB_Remove; - te.nextthink = time + 0.1; - } + te.think = SUB_Remove; + te.nextthink = time + 0.1; WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_EXPLOSION); WriteCoord(MSG_MULTICAST, te.origin_x); @@ -234,6 +207,43 @@ void () EMPGrenadeExplode = { WriteCoord(MSG_MULTICAST, te.origin_z); multicast(te.origin, MULTICAST_PHS); } + } else if ((te.classname == "player") || + (te.touch == BackpackTouch)) { + if (! + ((teamplay & 16) && (te.team_no > 0) && + (te.team_no == self.owner.team_no))) { + expsize = 0; + expsize = expsize + te.ammo_shells * 0.75; + expsize = expsize + te.ammo_rockets * 0.75 * 2; + if (te.playerclass != PC_ENGINEER) { + expsize = expsize + te.ammo_cells * 0.75; + } + if (expsize > 0) { + deathmsg = 30; + T_RadiusDamage(te, self.owner, expsize, te); + if (te.touch != BackpackTouch) { + TF_T_Damage(te, self, self.owner, expsize, 2, 4); + te.ammo_shells = ceil(te.ammo_shells * 0.25); + te.ammo_rockets = ceil(te.ammo_rockets * 0.25); + if (te.playerclass != PC_ENGINEER) { + te.ammo_cells = ceil(te.ammo_cells * 0.25); + } + oldself = self; + self = te; + W_SetCurrentAmmo(self); + self = oldself; + } else { + te.think = SUB_Remove; + te.nextthink = time + 0.1; + } + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, te.origin_x); + WriteCoord(MSG_MULTICAST, te.origin_y); + WriteCoord(MSG_MULTICAST, te.origin_z); + multicast(te.origin, MULTICAST_PHS); + } + } } } te = te.chain2; diff --git a/qw.qc b/qw.qc index 760cca4d..eba85343 100644 --- a/qw.qc +++ b/qw.qc @@ -547,6 +547,7 @@ float unpause_lastcountnumber; float chweap_wait_attfinished; float override_mapclasses; float solid_detpack; +float walls_block_emp; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/tfort.qc b/tfort.qc index dca8fa53..a6cd776d 100644 --- a/tfort.qc +++ b/tfort.qc @@ -697,6 +697,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Print feign death message", feign_msg, "", 1); CF_PrintSetting("Override Map Class Limits", override_mapclasses, "", 0); CF_PrintSetting("Solid Detpack", solid_detpack, "", 0); + CF_PrintSetting("EMP Blocked By Walls", walls_block_emp, "", 0); if (server_faithful) { sprint(self, PRINT_HIGH, "\nThis server is running faithful Team Fortress settings.\n"); From 94e8a1a177cd9d3345463ae4851287762cb3aaaf Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 21 Jun 2019 20:26:00 +1200 Subject: [PATCH 0695/2474] Add support for spacers. Some skins experimentation --- menu/main.qc | 2 +- menu/options.qc | 5 +++-- menu/options_basic.qc | 2 +- menu/options_keys.qc | 12 +++++++++--- menusys/mitem_spinnymodel.qc | 7 +++++-- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/menu/main.qc b/menu/main.qc index 1d91a543..ce0b52ba 100644 --- a/menu/main.qc +++ b/menu/main.qc @@ -132,7 +132,7 @@ nonstatic void(mitem_desktop desktop) M_Main = shootframes:6, dontrotate:1, startangle:'0 155 0', - skin:skin, + customskin:skin, rotatespeed:10, topcolour:col, bottomcolour:col diff --git a/menu/options.qc b/menu/options.qc index 742d5d42..dda7fd38 100644 --- a/menu/options.qc +++ b/menu/options.qc @@ -45,7 +45,7 @@ nonstatic void(mitem_desktop desktop) M_Options = {fr.add(spawn(mitem_text, item_text:"Particles", item_command:"m_pop;m_particles", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} if (assumefalsecheckcommand("ezhud_nquake")) {fr.add(spawn(mitem_text, item_text:"Hud", item_command:"m_pop;m_hud", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} - fr.add(spawn(mitem_text, item_text:"Keys", item_command:"m_pop;m_keys", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; + fr.add(spawn(mitem_text, item_text:"Controls", item_command:"m_pop;m_keys", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; if (assumefalsecheckcommand("cfg_save")) {fr.add(spawn(mitem_text, item_text:"Save Settings", item_command:"cfg_save", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} if (assumefalsecheckcommand("cvarreset")) @@ -57,7 +57,8 @@ nonstatic void(mitem_desktop desktop) M_Options = m.add(spawn ( mitem_spinnymodel, item_text: "progs/tf_stan.mdl", - skin:"", + customskin:"skin2", + trueskin:"skin2", dontrotate:0, startangle:'0 192 0', firstframe:0, diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 1547be18..28345d36 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -148,7 +148,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); - m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', skin:skin, rotatespeed:10), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); + m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', customskin:skin, rotatespeed:10), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); // m.add(spawn (mitem_playerpreview, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 12*-16/2], [-40, 12*16/2]); addmenuback(m); diff --git a/menu/options_keys.qc b/menu/options_keys.qc index e0b91a8d..053e856c 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -4,6 +4,7 @@ const static struct string cmd; } binds[] = { + {_(""), "Movement"}, {_("Forwards"), "+forward"}, {_("Back"), "+back"}, {_("Move Left"), "+moveleft"}, @@ -27,7 +28,7 @@ const static struct // {_("Keyboard Look"), "+klook"}, {_("Strafe"), "+strafe"}, {_("Run"), "+speed"}, - {0, 0}, + {_(""), "Weapons"}, {_("Primary Weapon"), "weapon 1"}, {_("Secondary Weapon"), "weapon 2"}, {_("Last Resort"), "weapon 3"}, @@ -119,9 +120,14 @@ void(mitem_desktop desktop) M_Options_Keys = //throw a load of bind options onto it by reading from the array. for (i = 0; i < sizeof(binds) / sizeof(binds[0]); i++) { - if (binds[i].name == "") //no name is a spacer + if (binds[i].name == "") { //no name is a spacer + if(binds[i].cmd) { + fr.add(spawn(mitem_text, item_text:strcat("^{e080} ^a",binds[i].cmd,"^d ^{e082}"), item_command:"", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [0, (i*8)], [0, 8]); + i ++; + } continue; - fr.add(menuitembind_spawn(binds[i].name, binds[i].cmd, '280 8'), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, (i*8)], '0 8'); + } + fr.add(menuitembind_spawn(binds[i].name, binds[i].cmd, '280 8'), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, (i*8) + 4], '0 8'); } } diff --git a/menusys/mitem_spinnymodel.qc b/menusys/mitem_spinnymodel.qc index f31308bb..b52c10af 100644 --- a/menusys/mitem_spinnymodel.qc +++ b/menusys/mitem_spinnymodel.qc @@ -49,6 +49,7 @@ noref .vector mins; noref .vector maxs; noref .string model; noref .float frame, frame2, lerpfrac, renderflags; +noref .string skin; float frametime; class mitem_spinnymodel : mitem { @@ -60,7 +61,8 @@ class mitem_spinnymodel : mitem float dontrotate; float rotatespeed; vector startangle; - string skin; + string customskin; + string trueskin; float topcolour; float bottomcolour; float fov; @@ -139,7 +141,8 @@ class mitem_spinnymodel : mitem setviewprop(VF_MIN, vtodpp('0 0 0')); setviewprop(VF_SIZE, vtodpp(ui.screensize)); } - setcustomskin(self, "", sprintf("q1upper \"%f\"\nq1lower \"%f\"\nqwskin \"%s\"\n", topcolour, bottomcolour, skin)); + setcustomskin(self, "", sprintf("q1upper \"%f\"\nq1lower \"%f\"\nqwskin \"%s\"\n", topcolour, bottomcolour, customskin)); + skin = trueskin; //setcustomskin(self, skin, ""); //setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\n\n", cvar_string("topcolor"), cvar_string("bottomcolor"))); }; From 5c23bf8d2e2d453e5e3c2ae93583a1814849691f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 22 Jun 2019 21:12:05 +1200 Subject: [PATCH 0696/2474] allow randompc to change to the current (random) class --- tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfort.qc b/tfort.qc index dca8fa53..0ac69274 100644 --- a/tfort.qc +++ b/tfort.qc @@ -145,7 +145,7 @@ void (float inp) TeamFortress_ChangeClass = { if ((deathmatch != 3) && (!cb_prematch)) return; - if (self.playerclass == inp) { + if (self.playerclass == inp && !(self.tfstate & TFSTATE_RANDOMPC)) { sprint(self, PRINT_HIGH, "You are already playing as a "); TeamFortress_PrintClassName(self, inp, 0); return; From 997a6e55933383feb39a256adddeeebcf45e7a27 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 25 Jun 2019 21:11:40 +1200 Subject: [PATCH 0697/2474] Supress generic kill messages when killed by a tf goal with a message --- client.qc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client.qc b/client.qc index a88028ee..047b0743 100644 --- a/client.qc +++ b/client.qc @@ -2653,9 +2653,12 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage strcat(pe_attacker.real_owner.netname, s_deathstring2))); } - - } else { - + //only do world-based deaths if not caused by a tf goal with a defined custom death (or broadcast) message + } else if (!(( + pe_attacker.classname == "info_tfgoal" || + pe_attacker.classname == "info_tfgoal_timer" || + pe_attacker.classname == "item_tfgoal" + ) && (pe_attacker.deathtype || pe_attacker.n_b || pe_attacker.netname_broadcast))) { rnum = pe_target.watertype; if (rnum == -3) { From f07f0d0e670bf6df123e4fc3b3bda7ed4773f069 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 25 Jun 2019 22:42:41 +1200 Subject: [PATCH 0698/2474] Duelmode variable + adminmenu; ready-up fix for disconnected players --- clan.qc | 6 +++--- client.qc | 1 + commands.qc | 21 ++++++++++++--------- defs.h | 2 +- menu.qc | 45 +++++++++++++++++++++++++++++++++++++-------- qw.qc | 1 + spect.qc | 2 ++ weapons.qc | 2 ++ 8 files changed, 59 insertions(+), 21 deletions(-) diff --git a/clan.qc b/clan.qc index 1ef22a4b..04a8a031 100644 --- a/clan.qc +++ b/clan.qc @@ -757,7 +757,7 @@ void () CenterPrint_Players_NotReady = { local float first = 0; te = find (world, classname, "player"); while (te) { - if (te.is_ready == 0) + if (te.is_ready == 0 && !te.has_disconnected) { first = first + 1; if (first == 1) @@ -793,7 +793,7 @@ void () Broadcast_Players_NotReady = { local float first = 1; te = find (world, classname, "player"); while (te != world) { - if (te.is_ready == 0) { + if (te.is_ready == 0 && !te.has_disconnected) { if (!first) players_not_ready = strcat(players_not_ready, ", "); else @@ -806,7 +806,7 @@ void () Broadcast_Players_NotReady = { bprint(1, players_not_ready); te = find (world, classname, "player"); while (te != world) { - if (te.is_ready == 0) + if (te.is_ready == 0 && !te.has_disconnected) sprint(te, 2, "If you are ready, type \s/ready\s in the console\n"); te = find(te, classname, "player"); } diff --git a/client.qc b/client.qc index 047b0743..8b58ae63 100644 --- a/client.qc +++ b/client.qc @@ -270,6 +270,7 @@ void () DecodeLevelParms = { clanbattle = CF_GetSetting("c", "clan", "off"); quadmode = CF_GetSetting("quadmode", "quadmode", "off"); + duelmode = CF_GetSetting("duelmode", "duelmode", "off"); rounds = CF_GetSetting("rounds","rounds","on"); if (!rounds) diff --git a/commands.qc b/commands.qc index 7b9b1d02..0cc3a0ed 100644 --- a/commands.qc +++ b/commands.qc @@ -226,6 +226,7 @@ void () QuadMode = { localcmd ("localinfo clan on\n"); localcmd ("localinfo quadmode on\n"); + localcmd ("localinfo duelmode off\n"); localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); @@ -248,15 +249,16 @@ void () ClanMode = void () PubMode = { - localcmd("localinfo clan off\n"); - localcmd("localinfo quadmode off\n"); + localcmd ("localinfo clan off\n"); + localcmd ("localinfo quadmode off\n"); + localcmd ("localinfo duelmode off\n"); localcmd ("localinfo teamfrags off\n"); localcmd ("localinfo fullteamscore off\n"); localcmd ("password none\n"); - localcmd("localinfo rounds 0\n"); - localcmd("timelimit 20\n"); + localcmd ("localinfo rounds 0\n"); + localcmd ("timelimit 20\n"); localcmd ("fraglimit 0\n"); - localcmd("localinfo round_time 0\n"); + localcmd ("localinfo round_time 0\n"); localcmd ("exec fo_pubmode.cfg\n"); bprint(PRINT_HIGH, "Pub Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -266,12 +268,13 @@ void () DuelMode = { localcmd ("localinfo teamfrags off\n"); localcmd ("localinfo fullteamscore off\n"); - localcmd("localinfo clan off\n"); - localcmd("localinfo quadmode off\n"); + localcmd ("localinfo clan on\n"); + localcmd ("localinfo quadmode off\n"); + localcmd ("localinfo duelmode on\n"); localcmd ("password none\n"); - localcmd("timelimit 0\n"); + localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); localcmd ("exec fo_duelmode.cfg\n"); bprint(PRINT_HIGH, "Duel Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); -} \ No newline at end of file +} diff --git a/defs.h b/defs.h index 9c68564f..3dece95b 100644 --- a/defs.h +++ b/defs.h @@ -545,7 +545,7 @@ // unused 206 #define TF_ADMIN_CLANMODE 207 #define TF_ADMIN_QUADMODE 208 -// unused 209 +#define TF_ADMIN_DUELMODE 209 // unused 210 // unused 211 // unused 212 diff --git a/menu.qc b/menu.qc index 16c13eeb..64d3d02f 100644 --- a/menu.qc +++ b/menu.qc @@ -1028,11 +1028,13 @@ void () Menu_Engineer_Cancel = { void () ClanMode; void () QuadMode; void () PubMode; +void () DuelMode; void () Menu_Admin = { local string s_menu1; local string s_menu2; local string override; + local string blanks = " "; /* More menu lines, commented for the sake of unecessary warnings * local string s_menu3; @@ -1060,17 +1062,44 @@ void () Menu_Admin = s_menu1 = "FortressOne Admin Menu: \n\n"; if (self.current_menu_page == 1) { s_menu1 = strcat(s_menu1, Q"\s[1]\s Ceasefire \n"); - s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit \n"); + override = strcat("\x10",ftos(timelimit/60),"\x11"); + override = strcat(substring(blanks, 0, 19 - strlen(override)), override); + s_menu1 = strcat(s_menu1, Q"\s[2]\s Timelimit ", override, "\n"); s_menu1 = strcat(s_menu1, Q"\s[3]\s Kick \n"); s_menu1 = strcat(s_menu1, Q"\s[4]\s Ban \n"); - s_menu1 = strcat(s_menu1, Q"\s[5]\s Captain \n"); + if(captainmode) { + override = " \x10on\x11"; + } else { + override = "\x10off\x11"; + } + s_menu1 = strcat(s_menu1, Q"\s[5]\s Captain ",override,"\n"); s_menu1 = strcat(s_menu1, Q"\s[6]\s Randomize Teams \n"); s_menu1 = strcat(s_menu1, Q"\s[7]\s Restart current map \n"); } else if (self.current_menu_page == 2) { - s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode \n"); - s_menu1 = strcat(s_menu1, Q"\s[2]\s Quad Mode \n"); - s_menu1 = strcat(s_menu1, Q"\s[3]\s Pub Mode \n"); - s_menu1 = strcat(s_menu1, Q"\s[4]\s Duel Mode (Not implemented) \n"); + if(clanbattle) { + override = " \x10on\x11"; + } else { + override = "\x10off\x11"; + } + s_menu1 = strcat(s_menu1, Q"\s[1]\s Clan Mode ",override,"\n"); + if(quadmode) { + override = " \x10on\x11"; + } else { + override = "\x10off\x11"; + } + s_menu1 = strcat(s_menu1, Q"\s[2]\s Quad Mode ",override,"\n"); + if(!clanbattle && !quadmode && !duelmode) { + override = " \x10on\x11"; + } else { + override = "\x10off\x11"; + } + s_menu1 = strcat(s_menu1, Q"\s[3]\s Pub Mode ",override,"\n"); + if(duelmode) { + override = " \x10on\x11"; + } else { + override = "\x10off\x11"; + } + s_menu1 = strcat(s_menu1, Q"\s[4]\s Duel Mode ",override,"\n"); s_menu1 = strcat(s_menu1, Q"\s[5]\s Force Spectate \n"); s_menu1 = strcat(s_menu1, Q"\s[6]\s Ready Status \n"); s_menu1 = strcat(s_menu1, Q"\s[7]\s Force Match Start (Be Nice) \n"); @@ -1128,7 +1157,7 @@ void () Menu_Admin = s_menu1 = "Class Management Menu: \n\n"; //override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); if(override_mapclasses) { - override = "\x10 on\x11"; + override = " \x10on\x11"; } else { override = "\x10off\x11"; } @@ -1377,7 +1406,7 @@ void (float inp) Menu_Admin_Input = self.current_menu_page = 1; break; case 4: // duel mode - bprint(2, "Not Implemented!\n"); + DuelMode(); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 1; diff --git a/qw.qc b/qw.qc index eba85343..850975fc 100644 --- a/qw.qc +++ b/qw.qc @@ -442,6 +442,7 @@ float round_active; float round_over; float gametime; float is_countdown; +float duelmode; .float tf_id; diff --git a/spect.qc b/spect.qc index 8e2b9539..77802e32 100644 --- a/spect.qc +++ b/spect.qc @@ -100,6 +100,8 @@ void () SpectatorImpulseCommand = { ClanMode(); else if (self.impulse == TF_ADMIN_QUADMODE) QuadMode(); + else if (self.impulse == TF_ADMIN_DUELMODE) + DuelMode(); else if (self.impulse == TF_ADMIN_ADMINMENU) { self.current_menu_page = 1; Menu_Admin(); diff --git a/weapons.qc b/weapons.qc index 8afc4b90..3f5c2e48 100644 --- a/weapons.qc +++ b/weapons.qc @@ -2998,6 +2998,8 @@ void () DeadImpulses = { ClanMode(); else if (self.impulse == TF_ADMIN_QUADMODE) QuadMode(); + else if (self.impulse == TF_ADMIN_DUELMODE) + DuelMode(); else if (self.impulse == TF_ADMIN_ADMINMENU) { self.current_menu_page = 1; Menu_Admin(); From 3980e5d5d437fcb7ff90f1b8671f8b7399c6c026 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 26 Jun 2019 00:52:58 +1200 Subject: [PATCH 0699/2474] Duel mode auto-reset/reload --- README.md | 1 + client.qc | 25 +++++++++++++++++++++++++ combat.qc | 2 ++ commands.qc | 1 + mvdsv.qc | 7 ++++++- 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a331614..d77e6bd9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Admin option to enable duel mode. Will auto-reset/resup the not dead player. * Server option for making all walls block EMP. Off by default. `localinfo walls_block_emp 1` or `localinfo wbe 1`. (SPAWNFLAG_BLOCK_EMP 4096 will work regardless) * Server option for setting detpack to solid (blocking). Off by default. `localinfo solid_detpack 1` or `localinfo sdp 1`. * Server option for overriding map class restrictions (except civilian). `serverinfo override_mapclasses 1` or `serverinfo omc 1`. diff --git a/client.qc b/client.qc index 8b58ae63..a5ead74a 100644 --- a/client.qc +++ b/client.qc @@ -1009,6 +1009,29 @@ float () CloseToSpawnPoint = { return 0; }; +void () ResetPlayers = { + if(cb_prematch) + return; + local entity te, oldself; + te = find(world, classname, "player"); + while (te != world) { + if(!te.has_disconnected && !te.deadflag) { + oldself = self; + self = te; + //self.takedamage = DAMAGE_AIM; + //self.solid = SOLID_SLIDEBOX; + //self.movetype = MOVETYPE_WALK; + TeamFortress_RemoveTimers(); + setspawnparms(self); + PutClientInServer(); + + self = oldself; + } + te = find (te, classname, "player"); + } + +} + void () ClientKill = { local entity te; local float timeleft; @@ -1288,6 +1311,8 @@ void () PutClientInServer = { self.reload_super_shotgun = 0; self.reload_grenade_launcher = 0; self.reload_rocket_launcher = 0; + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RELOADING); + self.reload_sniper_rifle = 0; self.immune_to_check = time + 10; self.fire_held_down = 0; diff --git a/combat.qc b/combat.qc index eca3f3c0..6a88098b 100644 --- a/combat.qc +++ b/combat.qc @@ -1,6 +1,7 @@ void () T_MissileTouch; void () info_player_start; void (entity targ, entity attacker) ClientObituary; +void () ResetPlayers; void (entity Goal, entity AP, float addb) DoResults; float (entity Goal, entity AP) Activated; @@ -86,6 +87,7 @@ void (entity targ, entity attacker) Killed = { monster_death_use(); self.th_die(); self = oself; + ResetPlayers(); }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { diff --git a/commands.qc b/commands.qc index 0cc3a0ed..95a354d3 100644 --- a/commands.qc +++ b/commands.qc @@ -271,6 +271,7 @@ void () DuelMode = localcmd ("localinfo clan on\n"); localcmd ("localinfo quadmode off\n"); localcmd ("localinfo duelmode on\n"); + localcmd ("localinfo sf on\n"); //spawnfull, ie spawn fully stocked localcmd ("password none\n"); localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); diff --git a/mvdsv.qc b/mvdsv.qc index b78593ef..d5048dd2 100644 --- a/mvdsv.qc +++ b/mvdsv.qc @@ -65,6 +65,11 @@ float () ConsoleCmd { QuadMode(); return (1); } + else if (argv_mvdsv (0) == "duelmode") + { + DuelMode(); + return (1); + } return 0; } @@ -133,4 +138,4 @@ void (float duration) GE_PausedTic = { void(float pauseduration) SV_PausedTic = { GE_PausedTic(pauseduration); -} \ No newline at end of file +} From f8a7efc8a506329d1ae1451a5a2d9d593917aeb6 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 26 Jun 2019 23:52:29 +1200 Subject: [PATCH 0700/2474] only reset in duel mode --- combat.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/combat.qc b/combat.qc index 6a88098b..7f9f594d 100644 --- a/combat.qc +++ b/combat.qc @@ -87,7 +87,8 @@ void (entity targ, entity attacker) Killed = { monster_death_use(); self.th_die(); self = oself; - ResetPlayers(); + if(duelmode) + ResetPlayers(); }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { From bb89f5032739dedcb70cfee6cec2172a58083898 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 27 Jun 2019 00:10:57 +1200 Subject: [PATCH 0701/2474] Add configurable delay to duelmode reset --- README.md | 1 + client.qc | 2 ++ combat.qc | 19 ++++++++++++++++--- commands.qc | 3 ++- qw.qc | 1 + 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d77e6bd9..8aab9cd3 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* Server setting for duelmode reset delay `localinfo drd 0.5` (`localinfo duel_reset_delay 0.5`) * Admin option to enable duel mode. Will auto-reset/resup the not dead player. * Server option for making all walls block EMP. Off by default. `localinfo walls_block_emp 1` or `localinfo wbe 1`. (SPAWNFLAG_BLOCK_EMP 4096 will work regardless) * Server option for setting detpack to solid (blocking). Off by default. `localinfo solid_detpack 1` or `localinfo sdp 1`. diff --git a/client.qc b/client.qc index a5ead74a..74e798cd 100644 --- a/client.qc +++ b/client.qc @@ -576,6 +576,8 @@ void () DecodeLevelParms = { solid_detpack = CF_GetSetting("sdp", "solid_detpack", "0"); // All Walls Block EMP [0] walls_block_emp = CF_GetSetting("wbp", "walls_block_emp", "0"); + // For duelmode, how soon to reset the winning player (allows for double KOs) + duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "0"); st = infokey(world, "default"); if (st == "on") { diff --git a/combat.qc b/combat.qc index 7f9f594d..ef541ef4 100644 --- a/combat.qc +++ b/combat.qc @@ -51,8 +51,14 @@ float (entity targ, entity inflictor) CanDamage = { return (FALSE); }; +void () ResetPlayersDelayed = { + ResetPlayers(); + dremove(self); +}; + + void (entity targ, entity attacker) Killed = { - local entity oself; + local entity oself, reset_timer; if (attacker == world && (targ.classname == "building_dispenser" || targ.classname == "building_sentrygun")) attacker = targ; @@ -87,8 +93,15 @@ void (entity targ, entity attacker) Killed = { monster_death_use(); self.th_die(); self = oself; - if(duelmode) - ResetPlayers(); + if(duelmode) { + if(duel_reset_delay) { + reset_timer = spawn(); + reset_timer.nextthink = time + duel_reset_delay; + reset_timer.think = ResetPlayersDelayed; + } else { + ResetPlayers(); + } + } }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { diff --git a/commands.qc b/commands.qc index 95a354d3..4e3c700e 100644 --- a/commands.qc +++ b/commands.qc @@ -271,7 +271,8 @@ void () DuelMode = localcmd ("localinfo clan on\n"); localcmd ("localinfo quadmode off\n"); localcmd ("localinfo duelmode on\n"); - localcmd ("localinfo sf on\n"); //spawnfull, ie spawn fully stocked + localcmd ("localinfo sf on\n"); // spawnfull, ie spawn fully stocked + localcmd ("localinfo drd 0.5\n"); // wait half a second before resetting the winner localcmd ("password none\n"); localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); diff --git a/qw.qc b/qw.qc index 850975fc..db7d39a8 100644 --- a/qw.qc +++ b/qw.qc @@ -443,6 +443,7 @@ float round_over; float gametime; float is_countdown; float duelmode; +float duel_reset_delay; .float tf_id; From 2832c58b58216f4556aac86e2a401fec2a41085b Mon Sep 17 00:00:00 2001 From: Leonard Wilson Date: Fri, 5 Jul 2019 16:19:12 +1000 Subject: [PATCH 0702/2474] spurs --- client.qc | 11 +++++++++++ engineer.qc | 10 ++++++++++ qw.qc | 9 +++++++++ weapons.qc | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+) diff --git a/client.qc b/client.qc index 74e798cd..684cbfdd 100644 --- a/client.qc +++ b/client.qc @@ -332,6 +332,17 @@ void () DecodeLevelParms = { } else { toggleflags = toggleflags - (toggleflags & TFLAG_FULLTEAMSCORE); } + + // climbing spikes + spurs_scout = CF_GetSetting("spscout", "spurs_scout" , "1"); // scouts allowed to spawn spurs + spurs_spy = CF_GetSetting("spspy", "spurs_spy" , "1"); // spy allowed to spawn spurs + spurs_engineer = CF_GetSetting("speng", "spurs_engineer" , "1"); // engineer allowed to spawn spurs + spurs_duration = CF_GetSetting("spd", "spurs_duration" , "2"); // how long until self destroy + spurs_boost = CF_GetSetting("spb", "spurs_boost" , "300"); // height gained from touch + spurs_enabled = CF_GetSetting("spe", "spurs_enabled" , "0"); // 0 = OFF , 1 = useable by owner , 2 = useable by owners team, 3 = useable by both teams + spurs_consume = CF_GetSetting("spc", "spurs_consume" , "0"); // destroy on touch + spurs_flag = CF_GetSetting("spf", "spurs_flag" , "0"); // can climb with flag + // nailgren types 0 = NGR_TYPE_DEFAULT, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_LASER)); diff --git a/engineer.qc b/engineer.qc index 2076edb9..09f7dc8c 100644 --- a/engineer.qc +++ b/engineer.qc @@ -68,8 +68,18 @@ void () LaserBolt_Touch = { WriteCoord(MSG_MULTICAST, self.origin_y); WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); + + if(other.classname == "worldspawn" && spurs_enabled > 0) + { + if(self.owner.playerclass == PC_ENGINEER && spurs_engineer == 1) + { + ConvertToSpurs(self); + return; + } } + dremove(self); +} }; void () W_FireLaser = { diff --git a/qw.qc b/qw.qc index db7d39a8..53558b4d 100644 --- a/qw.qc +++ b/qw.qc @@ -450,6 +450,15 @@ float duel_reset_delay; float exec_map_cfgs; float spy_off; +float spurs_scout; +float spurs_spy; +float spurs_engineer; +float spurs_duration; +float spurs_enabled; +float spurs_boost; +float spurs_consume; +float spurs_flag; + float nailgren_type; float lasergren_rotationcount; float lasergren_rotationtime; diff --git a/weapons.qc b/weapons.qc index 3f5c2e48..10787dde 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1373,6 +1373,50 @@ void (float ox) W_FireSpikes = { KickPlayer(-3, self); }; +void () t_climb = { + + if (time < self.heat) + return; + + self.heat = time + 0.1; + + if (other.classname != "player") + return; + + if (spurs_enabled == 0) + return; + + if (other.items & IT_KEY1 && spurs_flag == 0 ) + return; + + if (other.items & IT_KEY2 && spurs_flag == 0 ) + return; + + if(other == self.owner || spurs_enabled == 3 || ((self.owner.team_no == other.team_no) && spurs_enabled == 2)) + { + if (self.origin_z > other.origin_z){ + other.velocity_z = spurs_boost; + + } + + if(spurs_consume) + dremove(self); + } + +}; + +void (entity e) ConvertToSpurs = +{ + e.origin = self.origin + ( normalize(self.velocity) * -5); + e.movetype = MOVETYPE_NONE; + e.velocity = '0 0 0'; + e.solid = SOLID_TRIGGER; + e.touch = t_climb; + e.think = SUB_Remove; + e.nextthink = time + spurs_duration; + e.heat = time; +}; + .float hit_z; void () spike_touch = { @@ -1397,6 +1441,9 @@ void () spike_touch = { TF_T_Damage(other, self, self.owner, ng_damage, TF_TD_NOTTEAM, TF_TD_NAIL); } + + dremove(self); + } else { WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); if (self.classname == "wizspike") @@ -1409,8 +1456,18 @@ void () spike_touch = { WriteCoord(MSG_MULTICAST, self.origin_y); WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); + + if(other.classname == "worldspawn" && spurs_enabled > 0) + { + if(self.owner.playerclass == PC_SCOUT && spurs_scout == 1 || self.owner.playerclass == PC_SPY && spurs_spy == 1) + { + ConvertToSpurs(self); + return; + } } + dremove(self); + } }; void () superspike_touch = { From 1511fa5d27c9070cb4596548cd902d848f96e87c Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 6 Jul 2019 21:53:31 +1200 Subject: [PATCH 0703/2474] Modified duelmode to allow for doublekills; semi-ceasefire inbetween rounds; countdown --- README.md | 2 +- client.qc | 3 ++- combat.qc | 41 ++++++++++++++++++++++++++++++++++------- commands.qc | 2 +- qw.qc | 2 ++ tfort.qc | 3 +++ weapons.qc | 3 +++ 7 files changed, 46 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8aab9cd3..d2e35671 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server v0.1.0 New features ------ * Server setting for duelmode reset delay `localinfo drd 0.5` (`localinfo duel_reset_delay 0.5`) -* Admin option to enable duel mode. Will auto-reset/resup the not dead player. +* Admin option to enable duel mode. Will auto-reset/resup the not dead player. Main option - `localinfo duelmode on` * Server option for making all walls block EMP. Off by default. `localinfo walls_block_emp 1` or `localinfo wbe 1`. (SPAWNFLAG_BLOCK_EMP 4096 will work regardless) * Server option for setting detpack to solid (blocking). Off by default. `localinfo solid_detpack 1` or `localinfo sdp 1`. * Server option for overriding map class restrictions (except civilian). `serverinfo override_mapclasses 1` or `serverinfo omc 1`. diff --git a/client.qc b/client.qc index 74e798cd..627e39a9 100644 --- a/client.qc +++ b/client.qc @@ -1012,12 +1012,13 @@ float () CloseToSpawnPoint = { }; void () ResetPlayers = { + no_fire_mode = 0; if(cb_prematch) return; local entity te, oldself; te = find(world, classname, "player"); while (te != world) { - if(!te.has_disconnected && !te.deadflag) { + if(!te.has_disconnected) { oldself = self; self = te; //self.takedamage = DAMAGE_AIM; diff --git a/combat.qc b/combat.qc index ef541ef4..3c61a599 100644 --- a/combat.qc +++ b/combat.qc @@ -52,13 +52,25 @@ float (entity targ, entity inflictor) CanDamage = { }; void () ResetPlayersDelayed = { - ResetPlayers(); - dremove(self); + if(duel_reset_timer < 1 && duel_reset_timer > 0) { + self.nextthink = time + duel_reset_timer; + duel_reset_timer = 0; + } else if(duel_reset_timer <= 0) { + ResetPlayers(); + dremove(self); + } else { + bprint(PRINT_HIGH, Q"\sReset in \x10", ftos(duel_reset_timer), "\x11\s\n"); + sound(self, CHAN_AUTO, "buttons/switch04.wav", 1, ATTN_NONE); + //stuffcmd (p, "play buttons/switch04.wav\n"); + duel_reset_timer--; + self.nextthink = time + 1; + } }; void (entity targ, entity attacker) Killed = { local entity oself, reset_timer; + local float remainder; if (attacker == world && (targ.classname == "building_dispenser" || targ.classname == "building_sentrygun")) attacker = targ; @@ -94,12 +106,27 @@ void (entity targ, entity attacker) Killed = { self.th_die(); self = oself; if(duelmode) { - if(duel_reset_delay) { - reset_timer = spawn(); - reset_timer.nextthink = time + duel_reset_delay; - reset_timer.think = ResetPlayersDelayed; - } else { + //Already in no fire mode - implies you're not the first to die + if(no_fire_mode) { + reset_timer = find(world, classname, "duel_reset_timer"); + while (reset_timer != world) { + oself = reset_timer; + reset_timer = find (reset_timer, classname, "duel_reset_timer"); + dremove(oself); + } ResetPlayers(); + } else { + no_fire_mode = 1; + if(duel_reset_delay) { + remainder = duel_reset_delay % 1; + duel_reset_timer = duel_reset_delay - remainder; + reset_timer = spawn(); + reset_timer.classname = "duel_reset_timer"; + reset_timer.nextthink = time + remainder; + reset_timer.think = ResetPlayersDelayed; + } else { + ResetPlayers(); + } } } }; diff --git a/commands.qc b/commands.qc index 4e3c700e..f79ecd50 100644 --- a/commands.qc +++ b/commands.qc @@ -272,7 +272,7 @@ void () DuelMode = localcmd ("localinfo quadmode off\n"); localcmd ("localinfo duelmode on\n"); localcmd ("localinfo sf on\n"); // spawnfull, ie spawn fully stocked - localcmd ("localinfo drd 0.5\n"); // wait half a second before resetting the winner + localcmd ("localinfo drd 3\n"); // wait half a second before resetting the winner localcmd ("password none\n"); localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); diff --git a/qw.qc b/qw.qc index db7d39a8..4269cc0d 100644 --- a/qw.qc +++ b/qw.qc @@ -444,6 +444,8 @@ float gametime; float is_countdown; float duelmode; float duel_reset_delay; +float duel_reset_timer; +float no_fire_mode; .float tf_id; diff --git a/tfort.qc b/tfort.qc index 3a0dd707..91834e04 100644 --- a/tfort.qc +++ b/tfort.qc @@ -743,6 +743,9 @@ void (float inp) TeamFortress_PrimeGrenade = { if ((self.tfstate & TFSTATE_GRENPRIMED) || (self.tfstate & TFSTATE_GRENTHROWING)) return; + + if (no_fire_mode) + return; if ( (inp == 1 && self.tp_grenade_switch != 1) || (inp == 2 && self.tp_grenade_switch == 1)) { diff --git a/weapons.qc b/weapons.qc index 3f5c2e48..c2a3563b 100644 --- a/weapons.qc +++ b/weapons.qc @@ -1850,6 +1850,9 @@ void () W_Attack = { if (self.tfstate & TFSTATE_RELOADING) return; + + if(no_fire_mode) + return; if ((self.is_undercover || (self.undercover_team != 0)) || (self.undercover_skin != 0)) From d55338a33faef685c858ddce07e3992c6c27a37b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 9 Jul 2019 20:19:56 +1200 Subject: [PATCH 0704/2474] Remove packs; end match on everyone leaving; remove all player-owned stuff on reset --- clan.qc | 10 ++++ client.qc | 132 +++++++++++++++++++++++++++++++--------------------- combat.qc | 2 +- commands.qc | 3 +- tfort.qc | 2 +- tfortmap.qc | 12 ++--- 6 files changed, 98 insertions(+), 63 deletions(-) diff --git a/clan.qc b/clan.qc index 04a8a031..8fb65945 100644 --- a/clan.qc +++ b/clan.qc @@ -108,6 +108,16 @@ void () StartMatch = dremove(te); te = find (te, classname, "detpack"); } + if(duelmode) { + //Hide all packs + te = find(world, classname, "info_tfgoal"); + while (te){ + if (te.mdl) { + setmodel(te, string_null); + } + te = find (te, classname, "info_tfgoal"); + } + } cb_prematch = 0; cease_fire = 0; diff --git a/client.qc b/client.qc index 5b224165..78fe6698 100644 --- a/client.qc +++ b/client.qc @@ -169,6 +169,21 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { return FO_GetUserSetting(world, ps_short, ps_setting, ps_default); }; +void () InitPrematch = { + localcmd ("serverinfo status Standby\n"); + + clan_scores_dumped = 0; + game_locked = 0; + cb_prematch = 1; + local entity pm_message = spawn(); + pm_message.owner = world; + pm_message.classname = "pmmessage"; + pm_message.think = PreMatch_Message; + pm_message.nextthink = 1; + + game_locked = CF_GetSetting("lg", "locked_game", "off"); +} + void () DecodeLevelParms = { local float fl; local string st; @@ -279,19 +294,7 @@ void () DecodeLevelParms = { rounds = rounds + 1; if (clanbattle) { - localcmd ("serverinfo status Standby\n"); - - clan_scores_dumped = 0; - game_locked = 0; - cb_prematch = 1; - local entity pm_message = spawn(); - pm_message.owner = world; - pm_message.classname = "pmmessage"; - pm_message.think = PreMatch_Message; - pm_message.nextthink = 1; - - game_locked = CF_GetSetting("lg", "locked_game", "off"); - + InitPrematch(); } else { clanbattle = FALSE; localcmd ("serverinfo status Normal\n"); @@ -1022,6 +1025,54 @@ float () CloseToSpawnPoint = { return 0; }; +void () RemovePlayerOwnedEnts = { + local entity te; + + TeamFortress_RemoveTimers(); + RemoveGasTimers(); + Engineer_RemoveBuildings(self); + te = find(world, classname, "detpack"); + while (te) { + if (te.owner == self) { + if (te.weaponmode == 1) { + TeamFortress_SetSpeed(te.enemy); + dremove(te.oldenemy); + dremove(te.observer_list); + } + dremove(te); + te = world; + } + te = find(te, classname, "detpack"); + } + te = find(world, classname, "countdown_timer"); + while (te) { + if (te.owner == self) { + if (te.weaponmode == 1) { + TeamFortress_SetSpeed(te.enemy); + dremove(te.oldenemy); + dremove(te.observer_list); + } + dremove(te); + te = world; + } + te = find(te, classname, "countdown_timer"); + } + RemoveGrenades(); + if (clanbattle && (self.tf_id != 0)) { + te = spawn(); + te.classname = "ghost"; + te.tf_id = self.tf_id; + te.team_no = self.team_no; + te.frags = self.frags; + te.real_frags = self.real_frags; + te.netname = self.netname; + te.playerclass = self.playerclass; + if (self.tfstate & 8) { + te.tfstate = 8; + } + } +} + void () ResetPlayers = { no_fire_mode = 0; if(cb_prematch) @@ -1035,7 +1086,8 @@ void () ResetPlayers = { //self.takedamage = DAMAGE_AIM; //self.solid = SOLID_SLIDEBOX; //self.movetype = MOVETYPE_WALK; - TeamFortress_RemoveTimers(); + //TeamFortress_RemoveTimers(); + RemovePlayerOwnedEnts(); setspawnparms(self); PutClientInServer(); @@ -2212,7 +2264,6 @@ void () ClientConnect = { }; void () ClientDisconnect = { - local entity te; local string st; local float fr; @@ -2222,47 +2273,20 @@ void () ClientDisconnect = { " frags\n"); sound(self, 4, "player/tornoff2.wav", 1, ATTN_NONE); self.has_disconnected = 1; - TeamFortress_RemoveTimers(); - RemoveGasTimers(); - Engineer_RemoveBuildings(self); - te = find(world, classname, "detpack"); - while (te) { - if (te.owner == self) { - if (te.weaponmode == 1) { - TeamFortress_SetSpeed(te.enemy); - dremove(te.oldenemy); - dremove(te.observer_list); - } - dremove(te); - te = world; - } - te = find(te, classname, "detpack"); - } - te = find(world, classname, "countdown_timer"); - while (te) { - if (te.owner == self) { - if (te.weaponmode == 1) { - TeamFortress_SetSpeed(te.enemy); - dremove(te.oldenemy); - dremove(te.observer_list); + RemovePlayerOwnedEnts(); + + if (duelmode && clanbattle && !cb_prematch) { + //In duelmode, reset back to prematch if everyone leaves half-way through a round + local float playersleft = 0; + local entity te = find (world, classname, "player"); + while (te) { + if (!te.has_disconnected) { + playersleft = playersleft + 1; } - dremove(te); - te = world; + te = find (te, classname, "player"); } - te = find(te, classname, "countdown_timer"); - } - RemoveGrenades(); - if (clanbattle && (self.tf_id != 0)) { - te = spawn(); - te.classname = "ghost"; - te.tf_id = self.tf_id; - te.team_no = self.team_no; - te.frags = self.frags; - te.real_frags = self.real_frags; - te.netname = self.netname; - te.playerclass = self.playerclass; - if (self.tfstate & 8) { - te.tfstate = 8; + if (!playersleft) { + InitPrematch(); } } set_suicide_frame(); diff --git a/combat.qc b/combat.qc index 3c61a599..ad2def12 100644 --- a/combat.qc +++ b/combat.qc @@ -105,7 +105,7 @@ void (entity targ, entity attacker) Killed = { monster_death_use(); self.th_die(); self = oself; - if(duelmode) { + if(duelmode && targ.classname == "player") { //Already in no fire mode - implies you're not the first to die if(no_fire_mode) { reset_timer = find(world, classname, "duel_reset_timer"); diff --git a/commands.qc b/commands.qc index f79ecd50..19a1d969 100644 --- a/commands.qc +++ b/commands.qc @@ -272,7 +272,8 @@ void () DuelMode = localcmd ("localinfo quadmode off\n"); localcmd ("localinfo duelmode on\n"); localcmd ("localinfo sf on\n"); // spawnfull, ie spawn fully stocked - localcmd ("localinfo drd 3\n"); // wait half a second before resetting the winner + localcmd ("localinfo drd 3.9\n"); // wait before resetting the winner long enough for grens to go off + localcmd ("localinfo rd 3.9\n"); // wait before respawning the loser localcmd ("password none\n"); localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); diff --git a/tfort.qc b/tfort.qc index 91834e04..47e3f712 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2379,7 +2379,7 @@ void (float Suicided) TeamFortress_SetupRespawn = { } } self.respawn_time = time + restime; - if (restime > 3) { + if (restime > 3 && !duelmode) { db = ftos(restime); sprint(self, PRINT_HIGH, db, " seconds till respawn\n"); } diff --git a/tfortmap.qc b/tfortmap.qc index 89162d3b..11dd5ba6 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -649,8 +649,9 @@ void (entity Goal) InactivateGoal = { Goal.solid = SOLID_TRIGGER; } Goal.goal_state = 2; - if (Goal.mdl != string_null) + if (Goal.mdl != string_null && !duelmode) { setmodel(Goal, Goal.mdl); + } } }; @@ -776,7 +777,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } } if (addb) { - if (Player.health > 0) { + if (Player.health > 0 && !duelmode) { if (Goal.health > 0) { if (stockfull) T_Heal(Player, Player.max_health, 0); @@ -792,8 +793,6 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { 0); } } - } - if (Player.health > 0) { if (stockfull) { if (Goal.armortype > 0) { Player.armortype = Player.armor_allowed; @@ -2131,7 +2130,7 @@ void () item_tfgoal_touch = { self.origin = self.oldorigin; setmodel(self, self.mdl); setorigin(self, self.origin); - sound(self, 2, "items/itembk2.wav", 1, 1); + sound(self, 2, "items/itembk2.wav", 1, 1); return; } } else { @@ -2299,8 +2298,9 @@ void () ReturnItem = { self.enemy.effects = self.enemy.effects | EF_BLUE; } - if (self.enemy.mdl != string_null) + if (self.enemy.mdl != string_null) { setmodel(self.enemy, self.enemy.mdl); + } setorigin(self.enemy, self.enemy.origin); tfgoalitem_checkgoalreturn(self.enemy); From eca9a57b8be8e284389a4ac9cfb5a434e421fd68 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 9 Jul 2019 22:35:24 +1200 Subject: [PATCH 0705/2474] duelmode: suicide support; f_respawn support; server option for spawning with all grens or only primaries (and emps); server option for no packs --- README.md | 2 ++ clan.qc | 2 +- client.qc | 24 +++++++++++++++++++----- engineer.qc | 25 +++++++++++++++++++++++-- qw.qc | 2 ++ tfort.qc | 6 ++++++ tfortmap.qc | 4 ++-- 7 files changed, 55 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d2e35671..c5a876d8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ FortressOne Server v0.1.0 New features ------ +* Server option for duelmode to respawn with all grens `localinfo duel_all_grens 1`/`localinfo dag 1` +* Server option to remove packs in duel mode `localinfo duel_no_packs 1`/`localinfo dnp 1` * Server setting for duelmode reset delay `localinfo drd 0.5` (`localinfo duel_reset_delay 0.5`) * Admin option to enable duel mode. Will auto-reset/resup the not dead player. Main option - `localinfo duelmode on` * Server option for making all walls block EMP. Off by default. `localinfo walls_block_emp 1` or `localinfo wbe 1`. (SPAWNFLAG_BLOCK_EMP 4096 will work regardless) diff --git a/clan.qc b/clan.qc index 8fb65945..c07bf634 100644 --- a/clan.qc +++ b/clan.qc @@ -108,7 +108,7 @@ void () StartMatch = dremove(te); te = find (te, classname, "detpack"); } - if(duelmode) { + if(duelmode && duel_no_packs) { //Hide all packs te = find(world, classname, "info_tfgoal"); while (te){ diff --git a/client.qc b/client.qc index 78fe6698..f3acd3ad 100644 --- a/client.qc +++ b/client.qc @@ -25,6 +25,7 @@ void () RemoveGasTimers; void () RemoveGrenades; void (entity eng) Engineer_RemoveBuildings; +void (entity eng) Engineer_QuietlyRemoveBuildings; void (string halias, float himpulse1, float himpulse2) TeamFortress_Alias; @@ -592,6 +593,10 @@ void () DecodeLevelParms = { walls_block_emp = CF_GetSetting("wbp", "walls_block_emp", "0"); // For duelmode, how soon to reset the winning player (allows for double KOs) duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "0"); + // remove packs in duelmode [1] + duel_no_packs = CF_GetSetting("dnp", "duel_no_packs", "1"); + // spawn with all possible grenades [0] + duel_all_grens = CF_GetSetting("dag", "duel_all_grens", "0"); st = infokey(world, "default"); if (st == "on") { @@ -1028,9 +1033,16 @@ float () CloseToSpawnPoint = { void () RemovePlayerOwnedEnts = { local entity te; + te = find(world, classname, "pipebomb"); + while (te) { + if (te.owner == self) { + dremove(te); + } + te = find(te, classname, "pipebomb"); + } TeamFortress_RemoveTimers(); RemoveGasTimers(); - Engineer_RemoveBuildings(self); + Engineer_QuietlyRemoveBuildings(self); te = find(world, classname, "detpack"); while (te) { if (te.owner == self) { @@ -1081,12 +1093,11 @@ void () ResetPlayers = { te = find(world, classname, "player"); while (te != world) { if(!te.has_disconnected) { + if(te.health > 0) { + stuffcmd(te, "f_respawn\n"); + } oldself = self; self = te; - //self.takedamage = DAMAGE_AIM; - //self.solid = SOLID_SLIDEBOX; - //self.movetype = MOVETYPE_WALK; - //TeamFortress_RemoveTimers(); RemovePlayerOwnedEnts(); setspawnparms(self); PutClientInServer(); @@ -1157,6 +1168,9 @@ void () ClientKill = { self.deadflag = DEAD_RESPAWNABLE; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; self.takedamage = 0; + if(duelmode) { + ResetPlayers(); + } }; entity lastspawn_team1; diff --git a/engineer.qc b/engineer.qc index 09f7dc8c..8c706411 100644 --- a/engineer.qc +++ b/engineer.qc @@ -1243,7 +1243,7 @@ void () CheckDistance = { self.nextthink = time + 0.3; }; -void (entity eng, string bld) DestroyBuilding = { +void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { local entity te; local entity oldself; local float pos; @@ -1264,13 +1264,34 @@ void (entity eng, string bld) DestroyBuilding = { Menu_Close(te.real_owner); te.real_owner.building = world; } - TF_T_Damage(te, world, world, 500, 0, 0); + if(explode) { + TF_T_Damage(te, world, world, 500, 0, 0); + } else { + if(bld == "building_dispenser") + te.real_owner.has_dispenser = 0; + if(bld == "building_sentrygun") { + te.real_owner.has_sentry = 0; + dremove (te.trigger_field); + } + spawn_tfog(te.origin); + dremove (te); + } } te = find(te, classname, bld); } }; +void (entity eng, string bld) DestroyBuilding = { + DestroyBuildingWithOptions(eng, bld, TRUE); +} + +void (entity eng) Engineer_QuietlyRemoveBuildings = { + DestroyBuildingWithOptions(eng, "building_dispenser", FALSE); + DestroyBuildingWithOptions(eng, "building_sentrygun", FALSE); +}; + void (entity eng) Engineer_RemoveBuildings = { DestroyBuilding(eng, "building_dispenser"); DestroyBuilding(eng, "building_sentrygun"); }; + diff --git a/qw.qc b/qw.qc index 87515cc7..201ce467 100644 --- a/qw.qc +++ b/qw.qc @@ -446,6 +446,8 @@ float duelmode; float duel_reset_delay; float duel_reset_timer; float no_fire_mode; +float duel_all_grens; +float duel_no_packs; .float tf_id; diff --git a/tfort.qc b/tfort.qc index 47e3f712..945451dd 100644 --- a/tfort.qc +++ b/tfort.qc @@ -2123,6 +2123,12 @@ void () TeamFortress_SetEquipment = { setmodel(self, string_null); } + if(duelmode && !duel_all_grens) { + //unless duel_all_grens is set, remove all secondary grens except emps + if(self.playerclass != PC_ENGINEER) { + self.no_grenades_2 = 0; + } + } if (self.armortype >= 0.8) self.items = self.items | IT_ARMOR3; diff --git a/tfortmap.qc b/tfortmap.qc index 11dd5ba6..e56f1d3c 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -649,7 +649,7 @@ void (entity Goal) InactivateGoal = { Goal.solid = SOLID_TRIGGER; } Goal.goal_state = 2; - if (Goal.mdl != string_null && !duelmode) { + if (Goal.mdl != string_null && !(duelmode && duel_no_packs)) { setmodel(Goal, Goal.mdl); } } @@ -777,7 +777,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } } if (addb) { - if (Player.health > 0 && !duelmode) { + if (Player.health > 0 && !(duelmode && duel_no_packs)) { if (Goal.health > 0) { if (stockfull) T_Heal(Player, Player.max_health, 0); From effaf08b0b1feaf5c05975af0c6daa45c1e680a4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 9 Jul 2019 23:13:20 +1200 Subject: [PATCH 0706/2474] precache_sound added, fix tfgoals not killing player --- client.qc | 3 + combat.qc | 2 +- tfortmap.qc | 298 ++++++++++++++++++++++++++-------------------------- 3 files changed, 154 insertions(+), 149 deletions(-) diff --git a/client.qc b/client.qc index f3acd3ad..20bb2bff 100644 --- a/client.qc +++ b/client.qc @@ -2275,6 +2275,8 @@ void () ClientConnect = { } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); + if (duelmode) + precache_sound("buttons/switch04.wav"); }; void () ClientDisconnect = { @@ -2300,6 +2302,7 @@ void () ClientDisconnect = { te = find (te, classname, "player"); } if (!playersleft) { + bprint(PRINT_HIGH, "Match \sabandoned\s, resetting to prematch\n"); InitPrematch(); } } diff --git a/combat.qc b/combat.qc index ad2def12..0e9d5860 100644 --- a/combat.qc +++ b/combat.qc @@ -105,7 +105,7 @@ void (entity targ, entity attacker) Killed = { monster_death_use(); self.th_die(); self = oself; - if(duelmode && targ.classname == "player") { + if(duelmode && targ.classname == "player" && !cb_prematch) { //Already in no fire mode - implies you're not the first to die if(no_fire_mode) { reset_timer = find(world, classname, "duel_reset_timer"); diff --git a/tfortmap.qc b/tfortmap.qc index e56f1d3c..2c8a41b0 100644 --- a/tfortmap.qc +++ b/tfortmap.qc @@ -777,8 +777,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } } if (addb) { - if (Player.health > 0 && !(duelmode && duel_no_packs)) { - if (Goal.health > 0) { + if (Player.health > 0) { + if (Goal.health > 0 && !(duelmode && duel_no_packs)) { if (stockfull) T_Heal(Player, Player.max_health, 0); else @@ -793,173 +793,175 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { 0); } } - if (stockfull) { - if (Goal.armortype > 0) { - Player.armortype = Player.armor_allowed; - Player.armorvalue = Player.maxarmor; - } else if (Goal.armorvalue > 0) { - Player.armortype = Player.armor_allowed; - Player.armorvalue = Player.maxarmor; - } - } else { - if (Goal.armortype > 0) - Player.armortype = Goal.armortype; - else if (Goal.armorvalue > 0) - Player.armortype = Player.armor_allowed; - Player.armorvalue = Player.armorvalue + Goal.armorvalue; - } - if (Goal.armorclass > 0) - Player.armorclass = Goal.armorclass; - - Player.ammo_shells = Player.ammo_shells + Goal.ammo_shells; - Player.ammo_nails = Player.ammo_nails + Goal.ammo_nails; - Player.ammo_rockets = Player.ammo_rockets + Goal.ammo_rockets; - Player.ammo_cells = Player.ammo_cells + Goal.ammo_cells; - Player.ammo_medikit = Player.ammo_medikit + Goal.ammo_medikit; - Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack; - //refill the clip if stock_reload is 2 - if (stock_reload == 2) { - if(Goal.ammo_shells) { - if(Player.current_weapon == WEAP_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + if(!(duelmode && duel_no_packs)) { + if (stockfull) { + if (Goal.armortype > 0) { + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.maxarmor; + } else if (Goal.armorvalue > 0) { + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.maxarmor; } - Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); - if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } else { + if (Goal.armortype > 0) + Player.armortype = Goal.armortype; + else if (Goal.armorvalue > 0) + Player.armortype = Player.armor_allowed; + Player.armorvalue = Player.armorvalue + Goal.armorvalue; + } + if (Goal.armorclass > 0) + Player.armorclass = Goal.armorclass; + + Player.ammo_shells = Player.ammo_shells + Goal.ammo_shells; + Player.ammo_nails = Player.ammo_nails + Goal.ammo_nails; + Player.ammo_rockets = Player.ammo_rockets + Goal.ammo_rockets; + Player.ammo_cells = Player.ammo_cells + Goal.ammo_cells; + Player.ammo_medikit = Player.ammo_medikit + Goal.ammo_medikit; + Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack; + //refill the clip if stock_reload is 2 + if (stock_reload == 2) { + if(Goal.ammo_shells) { + if(Player.current_weapon == WEAP_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); + if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); + if(Player.current_weapon == WEAP_SNIPER_RIFLE) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); } - Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); - if(Player.current_weapon == WEAP_SNIPER_RIFLE) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + if(Goal.ammo_rockets) { + if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); + if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); } - Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); - } - if(Goal.ammo_rockets) { - if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } else { + //for use in map entities without specifically enabling the general override + if(Goal.reload_shotgun) { + if(Player.current_weapon == WEAP_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); } - Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); - if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + if(Goal.reload_super_shotgun) { + if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); } - Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); - } - } else { - //for use in map entities without specifically enabling the general override - if(Goal.reload_shotgun) { - if(Player.current_weapon == WEAP_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + if(Goal.reload_sniper_rifle) { + if(Player.current_weapon == WEAP_SNIPER_RIFLE) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); } - Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); - } - if(Goal.reload_super_shotgun) { - if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + if(Goal.reload_grenade_launcher) { + if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); } - Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); - } - if(Goal.reload_sniper_rifle) { - if(Player.current_weapon == WEAP_SNIPER_RIFLE) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + if(Goal.reload_rocket_launcher) { + if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); } - Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); } - if(Goal.reload_grenade_launcher) { - if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); + Player.no_grenades_1 = + Player.no_grenades_1 + Goal.no_grenades_1; + Player.no_grenades_2 = + Player.no_grenades_2 + Goal.no_grenades_2; + + if (Player.no_grenades_1 > Player.max_grenades_1) { + Player.no_grenades_1 = Player.max_grenades_1; } - if(Goal.reload_rocket_launcher) { - if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); + if (Player.no_grenades_2 > Player.max_grenades_2) { + Player.no_grenades_2 = Player.max_grenades_2; } - } - Player.no_grenades_1 = - Player.no_grenades_1 + Goal.no_grenades_1; - Player.no_grenades_2 = - Player.no_grenades_2 + Goal.no_grenades_2; - - if (Player.no_grenades_1 > Player.max_grenades_1) { - Player.no_grenades_1 = Player.max_grenades_1; - } - if (Player.no_grenades_2 > Player.max_grenades_2) { - Player.no_grenades_2 = Player.max_grenades_2; - } - if (Player.ammo_detpack > Player.maxammo_detpack) { - Player.ammo_detpack = Player.maxammo_detpack; - } - if (Player.tfstate & TFSTATE_GRENPRIMED) { - te = find(world, classname, "primer"); - while (te) { - if (te.owner == Player) { - if ((te.impulse == TF_GRENADE_2) && - (Player.no_grenades_2 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); - dremove(te); - } else if ((te.impulse == TF_GRENADE_1) && - (Player.no_grenades_1 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); - dremove(te); + if (Player.ammo_detpack > Player.maxammo_detpack) { + Player.ammo_detpack = Player.maxammo_detpack; + } + if (Player.tfstate & TFSTATE_GRENPRIMED) { + te = find(world, classname, "primer"); + while (te) { + if (te.owner == Player) { + if ((te.impulse == TF_GRENADE_2) && + (Player.no_grenades_2 <= 0)) { + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENPRIMED); + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENTHROWING); + dremove(te); + } else if ((te.impulse == TF_GRENADE_1) && + (Player.no_grenades_1 <= 0)) { + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENPRIMED); + Player.tfstate = + Player.tfstate - + (Player.tfstate & TFSTATE_GRENTHROWING); + dremove(te); + } + te = world; + } else { + te = find(te, classname, "primer"); } - te = world; - } else { - te = find(te, classname, "primer"); } } - } - if (Goal.invincible_finished > 0) { - Player.items = Player.items | IT_INVULNERABILITY; - Player.invincible_time = 1; - Player.invincible_finished = - time + Goal.invincible_finished; - if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_INVINCIBLE; - Player.invincible_finished = time + 666; + if (Goal.invincible_finished > 0) { + Player.items = Player.items | IT_INVULNERABILITY; + Player.invincible_time = 1; + Player.invincible_finished = + time + Goal.invincible_finished; + if (Goal.classname == "item_tfgoal") { + Player.tfstate = Player.tfstate | TFSTATE_INVINCIBLE; + Player.invincible_finished = time + 666; + } } - } - if (Goal.invisible_finished > 0) { - Player.items = Player.items | IT_INVISIBILITY; - Player.invisible_time = 1; - Player.invisible_finished = time + Goal.invisible_finished; - if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_INVISIBLE; - Player.invisible_finished = time + 666; + if (Goal.invisible_finished > 0) { + Player.items = Player.items | IT_INVISIBILITY; + Player.invisible_time = 1; + Player.invisible_finished = time + Goal.invisible_finished; + if (Goal.classname == "item_tfgoal") { + Player.tfstate = Player.tfstate | TFSTATE_INVISIBLE; + Player.invisible_finished = time + 666; + } } - } - if (Goal.super_damage_finished > 0) { - Player.items = Player.items | IT_QUAD; - Player.super_time = 1; - Player.super_damage_finished = - time + Goal.super_damage_finished; - if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_QUAD; - Player.super_damage_finished = time + 666; + if (Goal.super_damage_finished > 0) { + Player.items = Player.items | IT_QUAD; + Player.super_time = 1; + Player.super_damage_finished = + time + Goal.super_damage_finished; + if (Goal.classname == "item_tfgoal") { + Player.tfstate = Player.tfstate | TFSTATE_QUAD; + Player.super_damage_finished = time + 666; + } } - } - if (Goal.radsuit_finished > 0) { - Player.items = Player.items | IT_SUIT; - Player.rad_time = 1; - Player.radsuit_finished = time + Goal.radsuit_finished; - if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_RADSUIT; - Player.radsuit_finished = time + 666; + if (Goal.radsuit_finished > 0) { + Player.items = Player.items | IT_SUIT; + Player.rad_time = 1; + Player.radsuit_finished = time + Goal.radsuit_finished; + if (Goal.classname == "item_tfgoal") { + Player.tfstate = Player.tfstate | TFSTATE_RADSUIT; + Player.radsuit_finished = time + 666; + } } } } - Player.lives = Player.lives + Goal.lives; + Player.lives = Player.lives + Goal.lives; if (Goal.frags) { if ((Goal.goal_effects == TFGE_AP) || !(toggleflags & TFLAG_FULLTEAMSCORE)) { From 5533219a8d7c54b398c8340e7df501f809f2a877 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 10 Jul 2019 22:49:00 +1200 Subject: [PATCH 0707/2474] Eng fix --- engineer.qc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/engineer.qc b/engineer.qc index 8c706411..49c3d768 100644 --- a/engineer.qc +++ b/engineer.qc @@ -68,18 +68,17 @@ void () LaserBolt_Touch = { WriteCoord(MSG_MULTICAST, self.origin_y); WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); - - if(other.classname == "worldspawn" && spurs_enabled > 0) - { - if(self.owner.playerclass == PC_ENGINEER && spurs_engineer == 1) - { - ConvertToSpurs(self); - return; - } + + if(other.classname == "worldspawn" && spurs_enabled > 0) + { + if(self.owner.playerclass == PC_ENGINEER && spurs_engineer == 1) + { + ConvertToSpurs(self); + return; + } + } } - dremove(self); -} }; void () W_FireLaser = { From aefd5e966c3790ec4d3c21afe97bd1b4c5a7e70a Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 24 Jul 2019 22:08:37 +1000 Subject: [PATCH 0708/2474] finish csqc fixes --- client.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client.qc b/client.qc index 3485fbc0..67499467 100644 --- a/client.qc +++ b/client.qc @@ -170,7 +170,8 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { return FO_GetUserSetting(world, ps_short, ps_setting, ps_default); }; -void () InitPrematch = { +void InitPrematch() +{ localcmd ("serverinfo status Standby\n"); clan_scores_dumped = 0; @@ -184,6 +185,8 @@ void () InitPrematch = { game_locked = CF_GetSetting("lg", "locked_game", "off"); +} + void (entity goalitem) SetFlagSendMethod = { if(goalitem) { goalitem.SendEntity = SendClientFlagStatus; @@ -763,7 +766,7 @@ void () DecodeLevelParms = { self.is_admin = parm15; }; -entity()FindIntermission = +entity() FindIntermission = { local entity spot; local float cyc; From b6f656994d1d655bf28730cccace98726a1a5a91 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 24 Jul 2019 22:21:13 +1000 Subject: [PATCH 0709/2474] rearrange project structure --- Makefile | 4 +- csqc/csprogs.src | 2 +- menu.src => menu/menu.src | 62 +++++++++++----------- commondefs.qc => share/commondefs.qc | 0 fteextensions.qc => share/fteextensions.qc | 0 actions.qc => ssqc/actions.qc | 0 admin.qc => ssqc/admin.qc | 0 boss.qc => ssqc/boss.qc | 0 buttons.qc => ssqc/buttons.qc | 0 camera.qc => ssqc/camera.qc | 0 clan.qc => ssqc/clan.qc | 0 client.qc => ssqc/client.qc | 0 combat.qc => ssqc/combat.qc | 0 commands.qc => ssqc/commands.qc | 0 coop.qc => ssqc/coop.qc | 0 ctf.qc => ssqc/ctf.qc | 0 debug.qc => ssqc/debug.qc | 0 defs.h => ssqc/defs.h | 0 defs.qc => ssqc/defs.qc | 0 demoman.qc => ssqc/demoman.qc | 0 doors.qc => ssqc/doors.qc | 0 engineer.qc => ssqc/engineer.qc | 0 flare.qc => ssqc/flare.qc | 0 functions.qc => ssqc/functions.qc | 0 help.qc => ssqc/help.qc | 0 items.qc => ssqc/items.qc | 0 locfiles.qc => ssqc/locfiles.qc | 0 medic.qc => ssqc/medic.qc | 0 menu.qc => ssqc/menu.qc | 0 misc.qc => ssqc/misc.qc | 0 monsters.qc => ssqc/monsters.qc | 0 mvdsv.qc => ssqc/mvdsv.qc | 0 plats.qc => ssqc/plats.qc | 0 player.qc => ssqc/player.qc | 0 progs.src => ssqc/progs.src | 6 +-- pyro.qc => ssqc/pyro.qc | 0 q3.qc => ssqc/q3.qc | 0 q3defs.qc => ssqc/q3defs.qc | 0 quadmode.qc => ssqc/quadmode.qc | 0 qw.qc => ssqc/qw.qc | 0 scout.qc => ssqc/scout.qc | 0 sentry.qc => ssqc/sentry.qc | 0 sniper.qc => ssqc/sniper.qc | 0 spect.qc => ssqc/spect.qc | 0 spy.qc => ssqc/spy.qc | 0 status.qc => ssqc/status.qc | 0 subs.qc => ssqc/subs.qc | 0 tfort.qc => ssqc/tfort.qc | 0 tforthlp.qc => ssqc/tforthlp.qc | 0 tfortmap.qc => ssqc/tfortmap.qc | 0 tforttm.qc => ssqc/tforttm.qc | 0 triggers.qc => ssqc/triggers.qc | 0 tsoldier.qc => ssqc/tsoldier.qc | 0 vote.qc => ssqc/vote.qc | 0 weapons.qc => ssqc/weapons.qc | 0 world.qc => ssqc/world.qc | 0 56 files changed, 36 insertions(+), 38 deletions(-) rename menu.src => menu/menu.src (62%) rename commondefs.qc => share/commondefs.qc (100%) rename fteextensions.qc => share/fteextensions.qc (100%) rename actions.qc => ssqc/actions.qc (100%) rename admin.qc => ssqc/admin.qc (100%) rename boss.qc => ssqc/boss.qc (100%) rename buttons.qc => ssqc/buttons.qc (100%) rename camera.qc => ssqc/camera.qc (100%) rename clan.qc => ssqc/clan.qc (100%) rename client.qc => ssqc/client.qc (100%) rename combat.qc => ssqc/combat.qc (100%) rename commands.qc => ssqc/commands.qc (100%) rename coop.qc => ssqc/coop.qc (100%) rename ctf.qc => ssqc/ctf.qc (100%) rename debug.qc => ssqc/debug.qc (100%) rename defs.h => ssqc/defs.h (100%) rename defs.qc => ssqc/defs.qc (100%) rename demoman.qc => ssqc/demoman.qc (100%) rename doors.qc => ssqc/doors.qc (100%) rename engineer.qc => ssqc/engineer.qc (100%) rename flare.qc => ssqc/flare.qc (100%) rename functions.qc => ssqc/functions.qc (100%) rename help.qc => ssqc/help.qc (100%) rename items.qc => ssqc/items.qc (100%) rename locfiles.qc => ssqc/locfiles.qc (100%) rename medic.qc => ssqc/medic.qc (100%) rename menu.qc => ssqc/menu.qc (100%) rename misc.qc => ssqc/misc.qc (100%) rename monsters.qc => ssqc/monsters.qc (100%) rename mvdsv.qc => ssqc/mvdsv.qc (100%) rename plats.qc => ssqc/plats.qc (100%) rename player.qc => ssqc/player.qc (100%) rename progs.src => ssqc/progs.src (88%) rename pyro.qc => ssqc/pyro.qc (100%) rename q3.qc => ssqc/q3.qc (100%) rename q3defs.qc => ssqc/q3defs.qc (100%) rename quadmode.qc => ssqc/quadmode.qc (100%) rename qw.qc => ssqc/qw.qc (100%) rename scout.qc => ssqc/scout.qc (100%) rename sentry.qc => ssqc/sentry.qc (100%) rename sniper.qc => ssqc/sniper.qc (100%) rename spect.qc => ssqc/spect.qc (100%) rename spy.qc => ssqc/spy.qc (100%) rename status.qc => ssqc/status.qc (100%) rename subs.qc => ssqc/subs.qc (100%) rename tfort.qc => ssqc/tfort.qc (100%) rename tforthlp.qc => ssqc/tforthlp.qc (100%) rename tfortmap.qc => ssqc/tfortmap.qc (100%) rename tforttm.qc => ssqc/tforttm.qc (100%) rename triggers.qc => ssqc/triggers.qc (100%) rename tsoldier.qc => ssqc/tsoldier.qc (100%) rename vote.qc => ssqc/vote.qc (100%) rename weapons.qc => ssqc/weapons.qc (100%) rename world.qc => ssqc/world.qc (100%) diff --git a/Makefile b/Makefile index 51a1dafd..7c49e420 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ ifndef REV endif all: - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./ssqc/progs.src fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./csqc/csprogs.src - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./menu.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./menu/menu.src clean: rm -f $(TARGET) qwprogs.lno files.dat progdefs.h diff --git a/csqc/csprogs.src b/csqc/csprogs.src index c6d6e122..615bc766 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,5 +1,5 @@ ../csprogs.dat csdefs.qc -../commondefs.qc +../share/commondefs.qc csextradefs.qc main.qc diff --git a/menu.src b/menu/menu.src similarity index 62% rename from menu.src rename to menu/menu.src index 06b89b0d..fcc72df9 100644 --- a/menu.src +++ b/menu/menu.src @@ -5,24 +5,22 @@ #define MENU //select the module #includelist -fteextensions.qc //also sets up system defs - -menusys/mitems.qc //root item type -menusys/mitems_common.qc //basic types -menusys/mitem_desktop.qc //other sort of root item -menusys/mitem_exmenu.qc //fullscreen/exclusive menus -menusys/mitem_edittext.qc //simple text editor -menusys/mitem_tabs.qc //tabs -menusys/mitem_colours.qc //colour picker -menusys/mitem_checkbox.qc //checkbox (boolean thingies) -menusys/mitem_slider.qc //scrollbars -menusys/mitem_combo.qc //multiple-choice thingies -menusys/mitem_bind.qc //key binding thingie -menusys/mitem_spinnymodel.qc //menu art +../share/fteextensions.qc //also sets up system defs + +../menusys/mitems.qc //root item type +../menusys/mitems_common.qc //basic types +../menusys/mitem_desktop.qc //other sort of root item +../menusys/mitem_exmenu.qc //fullscreen/exclusive menus +../menusys/mitem_edittext.qc //simple text editor +../menusys/mitem_tabs.qc //tabs +../menusys/mitem_colours.qc //colour picker +../menusys/mitem_checkbox.qc //checkbox (boolean thingies) +../menusys/mitem_slider.qc //scrollbars +../menusys/mitem_combo.qc //multiple-choice thingies +../menusys/mitem_bind.qc //key binding thingie +../menusys/mitem_spinnymodel.qc //menu art #endlist - - //might as well put this here. void(mitem_desktop desktop) M_Pop = @@ -35,28 +33,28 @@ void(mitem_desktop desktop) M_Pop = //define the commands. //cmd argments are: Name, Function, Sourcefile(may be empty) #define concommandslist \ - cmd("m_main", M_Main, menu/main.qc) \ + cmd("m_main", M_Main, main.qc) \ cmd("m_pop", M_Pop, ) \ - cmd("m_options", M_Options, menu/options.qc) \ - cmd("m_keys", M_Options_Keys, menu/options_keys.qc) \ - cmd("m_basicopts", M_Options_Basic, menu/options_basic.qc) \ - cmd("m_video", M_Options_Video, menu/options_video.qc) \ - cmd("m_effects", M_Options_Effects, menu/options_effects.qc) \ - cmd("m_audio", M_Options_Audio, menu/options_audio.qc) \ - cmd("m_particles", M_Options_Particles, menu/options_particles.qc) \ - cmd("m_hud", M_Options_Hud, menu/options_hud.qc) \ - cmd("m_load", M_Load, menu/loadsave.qc) \ + cmd("m_options", M_Options, options.qc) \ + cmd("m_keys", M_Options_Keys, options_keys.qc) \ + cmd("m_basicopts", M_Options_Basic, options_basic.qc) \ + cmd("m_video", M_Options_Video, options_video.qc) \ + cmd("m_effects", M_Options_Effects, options_effects.qc) \ + cmd("m_audio", M_Options_Audio, options_audio.qc) \ + cmd("m_particles", M_Options_Particles, options_particles.qc) \ + cmd("m_hud", M_Options_Hud, options_hud.qc) \ + cmd("m_load", M_Load, loadsave.qc) \ cmd("m_save", M_Save, ) \ - cmd("m_quit", M_Quit, menu/quit.qc) \ - cmd("m_newgame", M_NewGame, menu/newgame.qc) \ - cmd("m_servers", M_Servers, menu/servers.qc) \ - cmd("m_configs", M_Configs, menu/options_configs.qc) \ + cmd("m_quit", M_Quit, quit.qc) \ + cmd("m_newgame", M_NewGame, newgame.qc) \ + cmd("m_servers", M_Servers, servers.qc) \ + cmd("m_configs", M_Configs, options_configs.qc) \ cmd("m_reset", M_Reset, ) \ - cmd("m_preset", M_Preset, menu/presets.qc) + cmd("m_preset", M_Preset, presets.qc) #if 0 -#append concommandslist cmd("m_servers", M_Servers, menu/servers.qc) +#append concommandslist cmd("m_servers", M_Servers, servers.qc) #define serverbrowser "m_servers" #else #define serverbrowser "menu_servers" diff --git a/commondefs.qc b/share/commondefs.qc similarity index 100% rename from commondefs.qc rename to share/commondefs.qc diff --git a/fteextensions.qc b/share/fteextensions.qc similarity index 100% rename from fteextensions.qc rename to share/fteextensions.qc diff --git a/actions.qc b/ssqc/actions.qc similarity index 100% rename from actions.qc rename to ssqc/actions.qc diff --git a/admin.qc b/ssqc/admin.qc similarity index 100% rename from admin.qc rename to ssqc/admin.qc diff --git a/boss.qc b/ssqc/boss.qc similarity index 100% rename from boss.qc rename to ssqc/boss.qc diff --git a/buttons.qc b/ssqc/buttons.qc similarity index 100% rename from buttons.qc rename to ssqc/buttons.qc diff --git a/camera.qc b/ssqc/camera.qc similarity index 100% rename from camera.qc rename to ssqc/camera.qc diff --git a/clan.qc b/ssqc/clan.qc similarity index 100% rename from clan.qc rename to ssqc/clan.qc diff --git a/client.qc b/ssqc/client.qc similarity index 100% rename from client.qc rename to ssqc/client.qc diff --git a/combat.qc b/ssqc/combat.qc similarity index 100% rename from combat.qc rename to ssqc/combat.qc diff --git a/commands.qc b/ssqc/commands.qc similarity index 100% rename from commands.qc rename to ssqc/commands.qc diff --git a/coop.qc b/ssqc/coop.qc similarity index 100% rename from coop.qc rename to ssqc/coop.qc diff --git a/ctf.qc b/ssqc/ctf.qc similarity index 100% rename from ctf.qc rename to ssqc/ctf.qc diff --git a/debug.qc b/ssqc/debug.qc similarity index 100% rename from debug.qc rename to ssqc/debug.qc diff --git a/defs.h b/ssqc/defs.h similarity index 100% rename from defs.h rename to ssqc/defs.h diff --git a/defs.qc b/ssqc/defs.qc similarity index 100% rename from defs.qc rename to ssqc/defs.qc diff --git a/demoman.qc b/ssqc/demoman.qc similarity index 100% rename from demoman.qc rename to ssqc/demoman.qc diff --git a/doors.qc b/ssqc/doors.qc similarity index 100% rename from doors.qc rename to ssqc/doors.qc diff --git a/engineer.qc b/ssqc/engineer.qc similarity index 100% rename from engineer.qc rename to ssqc/engineer.qc diff --git a/flare.qc b/ssqc/flare.qc similarity index 100% rename from flare.qc rename to ssqc/flare.qc diff --git a/functions.qc b/ssqc/functions.qc similarity index 100% rename from functions.qc rename to ssqc/functions.qc diff --git a/help.qc b/ssqc/help.qc similarity index 100% rename from help.qc rename to ssqc/help.qc diff --git a/items.qc b/ssqc/items.qc similarity index 100% rename from items.qc rename to ssqc/items.qc diff --git a/locfiles.qc b/ssqc/locfiles.qc similarity index 100% rename from locfiles.qc rename to ssqc/locfiles.qc diff --git a/medic.qc b/ssqc/medic.qc similarity index 100% rename from medic.qc rename to ssqc/medic.qc diff --git a/menu.qc b/ssqc/menu.qc similarity index 100% rename from menu.qc rename to ssqc/menu.qc diff --git a/misc.qc b/ssqc/misc.qc similarity index 100% rename from misc.qc rename to ssqc/misc.qc diff --git a/monsters.qc b/ssqc/monsters.qc similarity index 100% rename from monsters.qc rename to ssqc/monsters.qc diff --git a/mvdsv.qc b/ssqc/mvdsv.qc similarity index 100% rename from mvdsv.qc rename to ssqc/mvdsv.qc diff --git a/plats.qc b/ssqc/plats.qc similarity index 100% rename from plats.qc rename to ssqc/plats.qc diff --git a/player.qc b/ssqc/player.qc similarity index 100% rename from player.qc rename to ssqc/player.qc diff --git a/progs.src b/ssqc/progs.src similarity index 88% rename from progs.src rename to ssqc/progs.src index 8b9d889d..955962cb 100644 --- a/progs.src +++ b/ssqc/progs.src @@ -1,7 +1,7 @@ -qwprogs.dat +../qwprogs.dat defs.qc -fteextensions.qc -commondefs.qc +../share/fteextensions.qc +../share/commondefs.qc qw.qc q3defs.qc debug.qc diff --git a/pyro.qc b/ssqc/pyro.qc similarity index 100% rename from pyro.qc rename to ssqc/pyro.qc diff --git a/q3.qc b/ssqc/q3.qc similarity index 100% rename from q3.qc rename to ssqc/q3.qc diff --git a/q3defs.qc b/ssqc/q3defs.qc similarity index 100% rename from q3defs.qc rename to ssqc/q3defs.qc diff --git a/quadmode.qc b/ssqc/quadmode.qc similarity index 100% rename from quadmode.qc rename to ssqc/quadmode.qc diff --git a/qw.qc b/ssqc/qw.qc similarity index 100% rename from qw.qc rename to ssqc/qw.qc diff --git a/scout.qc b/ssqc/scout.qc similarity index 100% rename from scout.qc rename to ssqc/scout.qc diff --git a/sentry.qc b/ssqc/sentry.qc similarity index 100% rename from sentry.qc rename to ssqc/sentry.qc diff --git a/sniper.qc b/ssqc/sniper.qc similarity index 100% rename from sniper.qc rename to ssqc/sniper.qc diff --git a/spect.qc b/ssqc/spect.qc similarity index 100% rename from spect.qc rename to ssqc/spect.qc diff --git a/spy.qc b/ssqc/spy.qc similarity index 100% rename from spy.qc rename to ssqc/spy.qc diff --git a/status.qc b/ssqc/status.qc similarity index 100% rename from status.qc rename to ssqc/status.qc diff --git a/subs.qc b/ssqc/subs.qc similarity index 100% rename from subs.qc rename to ssqc/subs.qc diff --git a/tfort.qc b/ssqc/tfort.qc similarity index 100% rename from tfort.qc rename to ssqc/tfort.qc diff --git a/tforthlp.qc b/ssqc/tforthlp.qc similarity index 100% rename from tforthlp.qc rename to ssqc/tforthlp.qc diff --git a/tfortmap.qc b/ssqc/tfortmap.qc similarity index 100% rename from tfortmap.qc rename to ssqc/tfortmap.qc diff --git a/tforttm.qc b/ssqc/tforttm.qc similarity index 100% rename from tforttm.qc rename to ssqc/tforttm.qc diff --git a/triggers.qc b/ssqc/triggers.qc similarity index 100% rename from triggers.qc rename to ssqc/triggers.qc diff --git a/tsoldier.qc b/ssqc/tsoldier.qc similarity index 100% rename from tsoldier.qc rename to ssqc/tsoldier.qc diff --git a/vote.qc b/ssqc/vote.qc similarity index 100% rename from vote.qc rename to ssqc/vote.qc diff --git a/weapons.qc b/ssqc/weapons.qc similarity index 100% rename from weapons.qc rename to ssqc/weapons.qc diff --git a/world.qc b/ssqc/world.qc similarity index 100% rename from world.qc rename to ssqc/world.qc From 12600d65f2acc4ce803973eb974a989457d1c73f Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 25 Jul 2019 19:28:36 +1000 Subject: [PATCH 0710/2474] hwguy projectile --- ssqc/client.qc | 3 ++ ssqc/defs.h | 2 + ssqc/hwguy.qc | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ ssqc/progs.src | 1 + ssqc/qw.qc | 1 + ssqc/weapons.qc | 24 +++++++---- ssqc/world.qc | 1 + 7 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 ssqc/hwguy.qc diff --git a/ssqc/client.qc b/ssqc/client.qc index 67499467..d02d7104 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -481,6 +481,9 @@ void () DecodeLevelParms = { // assault cannon accuracy (0 = cf, 1 = tf 2.8, 2 = tf 2.9) [0] cannon_accuracy = CF_GetSetting("cac", "cannon_accuracy", "0"); + // projectile FO style hwguy + fo_hwguy = CF_GetSetting("fohw", "fo_hwguy", "on"); + // allow feign death in air [on] feign_air = CF_GetSetting("fa", "feign_air", "on"); diff --git a/ssqc/defs.h b/ssqc/defs.h index 3dece95b..f3f493d6 100644 --- a/ssqc/defs.h +++ b/ssqc/defs.h @@ -986,6 +986,8 @@ #define PC_HVYWEAP_GRENADE_MAX_1 4 #define PC_HVYWEAP_GRENADE_MAX_2 2 #define PC_HVYWEAP_TF_ITEMS 0 +#define PC_HVYWEAP_PROJSPEED 5000 +#define MODEL_PROJ_DIAM2 "progs/proj_diam2.mdl" // Class Details for PYRO diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc new file mode 100644 index 00000000..2745dd5d --- /dev/null +++ b/ssqc/hwguy.qc @@ -0,0 +1,108 @@ +void AssCanBulletTouch() +{ + if (self.voided) + return; // Marked for removal + + self.voided = TRUE; + + if (pointcontents(self.origin) == CONTENT_SKY) { + dremove(self); + return; + } + + if (other == self.owner) + return; // Touching self, do nothing + + if (other.health) + { + TF_T_Damage(other, self, self.owner, 8, TF_TD_NOTTEAM, + TF_TD_OTHER); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_BLOOD); + WriteByte(MSG_MULTICAST, 1); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PVS); + } + else + { + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_GUNSHOT); + WriteByte(MSG_MULTICAST, 1); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PVS); + } + + dremove(self); +}; + +//====================================================================== +// Vector randomizer, used mostly for avelocity setups + +vector(float base, float rndmix, float plusminus) vecrand = +{ + local vector vecmix; + if (plusminus) { + vecmix_x = base + crandom() * rndmix; + vecmix_y = base + crandom() * rndmix; + vecmix_z = base + crandom() * rndmix; + } + else { + vecmix_x = base + random() * rndmix; + vecmix_y = base + random() * rndmix; + vecmix_z = base + random() * rndmix; + } + return vecmix; +}; + +void LaunchAssCan(vector org, vector dir, float proj_speed) +{ + newmis = spawn(); + newmis.owner = self; + newmis.classname = "proj_bullet"; + + newmis.movetype = MOVETYPE_FLY; // Small collision + + newmis.solid = SOLID_BBOX; + newmis.touch = AssCanBulletTouch; + + newmis.think = SUB_Remove; + newmis.nextthink = time + 5; // Stop projectile going forever + + newmis.mdl = MODEL_PROJ_DIAM2; + setmodel(newmis, newmis.mdl); // Diamond model + newmis.frame = random()*15; // Full range of sizes + newmis.skin = 16 + random()*7; // Bright colours + + newmis.velocity = dir * proj_speed; // Constant speed multiplier + newmis.angles = vectoangles(dir); // Create direction angle + setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); // Zero size + setorigin (newmis, org); // Move to starting position + + newmis.avelocity = vecrand(100, 200, FALSE); +} + +void FireAssCan (float shotcount, vector dir, vector spread) +{ + vector bullet_dir, spread_dir, rand_dir, org; + float bullet_speed, var_speed; + + makevectors(self.v_angle); + // Infront of player model and down towards gun + bullet_speed = PC_HVYWEAP_PROJSPEED; + bullet_dir = normalize(v_forward * bullet_speed); + + while (shotcount > 0) { + var_speed = crandom()*10 + bullet_speed; // Slight speed variance + rand_dir = (crandom()*spread_x) * v_right + (crandom()*spread_y) * v_up; + spread_dir = bullet_dir + rand_dir; + org = self.origin + rand_dir; + + LaunchAssCan(org, spread_dir, var_speed); + + shotcount = shotcount - 1; + } +} diff --git a/ssqc/progs.src b/ssqc/progs.src index 955962cb..6d8ce7a9 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -34,6 +34,7 @@ sniper.qc tsoldier.qc demoman.qc medic.qc +hwguy.qc pyro.qc spy.qc engineer.qc diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 201ce467..8ac2f80d 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -523,6 +523,7 @@ float cannon_move; float cannon_movespin; float cannon_conc; float cannon_accuracy; +float fo_hwguy; float feign_air; float feign_pack; float feign_msg; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index cce01725..596be2cb 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -947,6 +947,7 @@ void () W_FireAutoRifle = { FireSniperBullet(dir, 8); }; +void FireAssCan (float shotcount, vector dir, vector spread); void () W_FireAssaultCannon = { local vector dir; @@ -955,15 +956,22 @@ void () W_FireAssaultCannon = { self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_ASSAULTCANNON; - - if (cannon_accuracy == 1) - FireBullets(5, dir, '0 0 0'); - else if (cannon_accuracy == 2) - FireBullets(5, dir, '0.1 0.1 0'); - else if (vlen(self.velocity) < 50) - FireBullets(5, dir, '0.075 0.075 0'); + + if (fo_hwguy == FALSE) + { + if (cannon_accuracy == 1) + FireBullets(5, dir, '0 0 0'); + else if (cannon_accuracy == 2) + FireBullets(5, dir, '0.1 0.1 0'); + else if (vlen(self.velocity) < 50) + FireBullets(5, dir, '0.075 0.075 0'); + else + FireBullets(5, dir, '0.15 0.15 0'); + } else - FireBullets(5, dir, '0.15 0.15 0'); + { + FireAssCan(5, dir, '0.04 0.04 0'); + } }; void (entity pe_flame) CF_ExtinguishFlame = { diff --git a/ssqc/world.qc b/ssqc/world.qc index c4b385f1..dbf4d1fd 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -298,6 +298,7 @@ void () worldspawn = { precache_sound2("speech/saveme2.wav"); precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); + precache_model2(MODEL_PROJ_DIAM2); precache_sound("grentimer.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); From 0e12c24e28b14a86cc3926bf60141252af522c5a Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 25 Jul 2019 19:33:49 +1000 Subject: [PATCH 0711/2474] make hwguy projectiles slower --- ssqc/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/defs.h b/ssqc/defs.h index f3f493d6..b3f61a4a 100644 --- a/ssqc/defs.h +++ b/ssqc/defs.h @@ -986,7 +986,7 @@ #define PC_HVYWEAP_GRENADE_MAX_1 4 #define PC_HVYWEAP_GRENADE_MAX_2 2 #define PC_HVYWEAP_TF_ITEMS 0 -#define PC_HVYWEAP_PROJSPEED 5000 +#define PC_HVYWEAP_PROJSPEED 3000 #define MODEL_PROJ_DIAM2 "progs/proj_diam2.mdl" From 23325d88849cf40543332529599c94d29cb5771c Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 25 Jul 2019 20:57:57 +1000 Subject: [PATCH 0712/2474] add clip to ass can --- ssqc/actions.qc | 63 ++++++++++++++++++++++++++++++++++++++---------- ssqc/client.qc | 1 + ssqc/defs.h | 1 + ssqc/hwguy.qc | 6 ++++- ssqc/player.qc | 19 +++++++++++++++ ssqc/qw.qc | 1 + ssqc/status.qc | 52 +++++++++++++++++++++++++++------------ ssqc/tfortmap.qc | 13 ++++++++++ ssqc/weapons.qc | 29 ++++++++++++++++++++++ 9 files changed, 155 insertions(+), 30 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 218e7b17..ab8be355 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -256,7 +256,6 @@ void (entity pe_player, float f_type) CF_Identify = { // sentry gun is found } else if (trace_ent.classname == "building_sentrygun" || trace_ent.classname == "building_sentrygun_base") { - if (pe_player == trace_ent.real_owner) s_name = "Your sentry gun"; else { @@ -269,16 +268,12 @@ void (entity pe_player, float f_type) CF_Identify = { } s_class = ""; - } else { - return; - } // set name + health (if medic) if (f_maxhealth && (f_friendly || f_fakefriendly)) { - s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_health)); if (id_extended) { @@ -289,7 +284,6 @@ void (entity pe_player, float f_type) CF_Identify = { // set name + armor (if engineer) } else if (f_maxarmor && (f_friendly || f_fakefriendly)) { - s_id_string = strcat(s_name, "\n"); s_id_string = strcat(s_id_string, ftos(f_armor)); if (id_extended) { @@ -300,7 +294,6 @@ void (entity pe_player, float f_type) CF_Identify = { // set name + health (if sentry + engineer) } else if (f_maxsentryhealth) { - s_id_string = strcat(s_name, "\n"); if (id_extended) { s_id_string = strcat(s_id_string, ftos(floor(f_sentryhealth))); @@ -312,10 +305,8 @@ void (entity pe_player, float f_type) CF_Identify = { // just set name (if other class) } else { - s_id_string = strcat("\n", s_name); s_id_string = strcat(s_id_string, "\n"); - } // set friendly/enemy @@ -341,12 +332,11 @@ void (entity pe_player, float f_type) CF_Identify = { // refresh status bar pe_player.ident_string = strzone(s_id_string); Status_Refresh(pe_player); - } - }; -void (float weap) TeamFortress_ReloadWeapon = { +void TeamFortress_ReloadWeapon(float weap) +{ local float reloadtime = 0; local float reloadamount = 0; local entity tWeapon, tClip; @@ -557,7 +547,54 @@ void (float weap) TeamFortress_ReloadWeapon = { } else { sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); } + } else if (weap == WEAP_ASSAULT_CANNON) { + if (fo_hwguy) + { + if (self.ammo_shells == 0) { + sprint(self, PRINT_HIGH, "Out of shells\n"); + return; + } + + if (self.reload_assault_cannon == 0) { + sprint(self, PRINT_HIGH, "Clip full\n"); + return; + } + + if ((PC_HVYWEAP_ASSCAN_CLIPSIZE - self.reload_assault_cannon) == self.ammo_shells) { + sprint(self, PRINT_HIGH, "All shells are in the clip\n"); + return; + } + + if (self.ammo_shells >= 1) { + self.current_weapon = weap; + if (self.reload_assault_cannon >= self.ammo_shells) + reloadamount = self.ammo_shells; + else + reloadamount = self.reload_assault_cannon; + Attack_Finished(0.8); + self.reload_clipsize = (PC_HVYWEAP_ASSCAN_CLIPSIZE - reloadamount); + reloadtime = (PC_HVYWEAP_ASSCAN_CLIPSIZE - reloadamount) / PC_HVYWEAP_ASSCAN_CLIPSIZE; + reloadtime = 4 - (4 * reloadtime); + self.reload_assault_cannon = 0; + if (self.ammo_shells < PC_HVYWEAP_ASSCAN_CLIPSIZE) { + self.reload_assault_cannon = PC_HVYWEAP_ASSCAN_CLIPSIZE - self.ammo_shells; + } + sprint(self, PRINT_HIGH, "Reloading Assault Cannon...\n"); + self.tfstate = self.tfstate | TFSTATE_RELOADING; + Status_Refresh(self); + tWeapon = spawn(); + tWeapon.owner = self; + tWeapon.classname = "timer"; + tWeapon.nextthink = time + reloadtime; + tWeapon.think = W_Reload_assault_cannon; + self.weaponmodel = ""; + self.weaponframe = 0; + } else { + sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); + } + } } + if (reloadamount && reloadtime) { self.reload_time = time + reloadtime; self.reload_tick = reloadtime / reloadamount; @@ -567,7 +604,7 @@ void (float weap) TeamFortress_ReloadWeapon = { tClip.nextthink = time + self.reload_tick; tClip.think = TeamFortress_ClipTick; } -}; +} void () TeamFortress_ReloadCurrentWeapon = { TeamFortress_ReloadWeapon(self.current_weapon); diff --git a/ssqc/client.qc b/ssqc/client.qc index d02d7104..ba21a0fe 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1409,6 +1409,7 @@ void () PutClientInServer = { self.reload_rocket_launcher = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RELOADING); self.reload_sniper_rifle = 0; + self.reload_assault_cannon = 0; self.immune_to_check = time + 10; self.fire_held_down = 0; diff --git a/ssqc/defs.h b/ssqc/defs.h index b3f61a4a..06e77d38 100644 --- a/ssqc/defs.h +++ b/ssqc/defs.h @@ -987,6 +987,7 @@ #define PC_HVYWEAP_GRENADE_MAX_2 2 #define PC_HVYWEAP_TF_ITEMS 0 #define PC_HVYWEAP_PROJSPEED 3000 +#define PC_HVYWEAP_ASSCAN_CLIPSIZE 100 #define MODEL_PROJ_DIAM2 "progs/proj_diam2.mdl" diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 2745dd5d..2a6520d3 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -87,6 +87,10 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) void FireAssCan (float shotcount, vector dir, vector spread) { + self.reload_assault_cannon = self.reload_assault_cannon + 1; + Status_Refresh(self); + CheckForReload(); + vector bullet_dir, spread_dir, rand_dir, org; float bullet_speed, var_speed; @@ -95,7 +99,7 @@ void FireAssCan (float shotcount, vector dir, vector spread) bullet_speed = PC_HVYWEAP_PROJSPEED; bullet_dir = normalize(v_forward * bullet_speed); - while (shotcount > 0) { + while (shotcount > 0) { var_speed = crandom()*10 + bullet_speed; // Slight speed variance rand_dir = (crandom()*spread_x) * v_right + (crandom()*spread_y) * v_up; spread_dir = bullet_dir + rand_dir; diff --git a/ssqc/player.qc b/ssqc/player.qc index 0d13b6c3..bf5777e7 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -411,6 +411,16 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { }; void () player_assaultcannon1 =[103, player_assaultcannon2] { + if (fo_hwguy) + { + if (self.tfstate & TFSTATE_RELOADING) + { + self.count = 1; + player_assaultcannondown1(); + return; + } + } + if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) <= 30) && !(self.tfstate & TFSTATE_LOCK)) { muzzleflash(); @@ -451,6 +461,15 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { }; void () player_assaultcannon2 =[104, player_assaultcannon1] { + if (fo_hwguy) + { + if (self.tfstate & TFSTATE_RELOADING) + { + self.count = 1; + player_assaultcannondown1(); + return; + } + } if (vlen(self.velocity) < 30 && !(self.tfstate & TFSTATE_LOCK)) { if (self.weaponframe == 2) { self.weaponframe = 4; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 8ac2f80d..f2644122 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -209,6 +209,7 @@ float coop; .float reload_sniper_rifle; .float reload_grenade_launcher; .float reload_rocket_launcher; +.float reload_assault_cannon; .float reload_tick; // how often the status bar should be refreshed during reload .float reload_time; // when the reload will finish .float reload_clipsize; // how much ammo is currently in the reloading clip diff --git a/ssqc/status.qc b/ssqc/status.qc index 2ac1309d..f1a5c3be 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -988,11 +988,19 @@ string(entity pl) ClipSizeToString = if ((max - pl.reload_rocket_launcher) > pl.ammo_rockets) pl.reload_rocket_launcher = (max - pl.ammo_rockets); num = (max - pl.reload_rocket_launcher); + } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { + if (fo_hwguy) + { + if ((max - pl.reload_assault_cannon) > pl.ammo_shells) + pl.reload_assault_cannon = (max - pl.ammo_shells); + num = (max - pl.reload_assault_cannon); + } } else return ""; - if (num > 99) - num = 99; + // TODO - can we up this to 100 for ass can? + if (num > 999) + num = 999; st = Q"\sClip\s: "; st = strcat(st, strpadl(ftos(floor(num)), 2)); @@ -1002,21 +1010,33 @@ string(entity pl) ClipSizeToString = return st; }; -float(entity pl) GetClipSize = +float GetClipSize(entity pl) { - if (pl.current_weapon == WEAP_SHOTGUN) - return 8; - else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) - return 16; - else if (pl.current_weapon == WEAP_SNIPER_RIFLE) - return 1; - else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) - return 6; - else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) - return 4; - else - return 0; -}; + switch (pl.current_weapon) + { + case WEAP_SHOTGUN: + return 8; + case WEAP_SUPER_SHOTGUN: + return 16; + case WEAP_SNIPER_RIFLE: + return 1; + case WEAP_GRENADE_LAUNCHER: + return 6; + case WEAP_ROCKET_LAUNCHER: + return 4; + case WEAP_ASSAULT_CANNON: + if (fo_hwguy) + { + return PC_HVYWEAP_ASSCAN_CLIPSIZE; + } + else + { + return 0; + } + default: + return 0; + } +} string(float num) TeamToString = { diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 2c8a41b0..247c8aa6 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -833,6 +833,11 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); } Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); + + if(Player.current_weapon == WEAP_ASSAULT_CANNON) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_assault_cannon = max(Player.reload_assault_cannon - Goal.ammo_shells, 0); } if(Goal.ammo_rockets) { if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { @@ -876,6 +881,13 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); } + if (Goal.reload_assault_cannon) + { + if(Player.current_weapon == WEAP_ASSAULT_CANNON) { + Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); + } + Player.reload_assault_cannon = max(Player.reload_assault_cannon - Goal.ammo_shells, 0); + } } Player.no_grenades_1 = Player.no_grenades_1 + Goal.no_grenades_1; @@ -1038,6 +1050,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.reload_grenade_launcher = 0; Player.reload_rocket_launcher = 0; Player.reload_sniper_rifle = 0; + Player.reload_assault_cannon = 0; } } } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 596be2cb..1b2c0f11 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1834,6 +1834,15 @@ void () W_Reload_rocket_launcher = { Status_Refresh(self.owner); }; +void () W_Reload_assault_cannon = { + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); + self.owner.weaponmodel = "progs/v_asscan.mdl"; + sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); + dremove(self); + W_WeaponState_Load(self.owner, 0); + Status_Refresh(self.owner); +}; + float () CheckForReload = { if (self.current_weapon == WEAP_SHOTGUN) { if (self.reload_shotgun >= 8 && self.ammo_shells > 0) { @@ -1860,6 +1869,14 @@ float () CheckForReload = { TeamFortress_ReloadCurrentWeapon(); return 1; } + } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { + if (fo_hwguy) + { + if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > 0) { + TeamFortress_ReloadCurrentWeapon(); + return 1; + } + } } return 0; }; @@ -1880,6 +1897,12 @@ float (float weap) CheckForAmmo = { } else if (weap == WEAP_ROCKET_LAUNCHER) { if (self.reload_rocket_launcher >= 1 && self.ammo_rockets > self.reload_rocket_launcher) return 1; + } else if (weap == WEAP_ASSAULT_CANNON) { + if (fo_hwguy) + { + if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > self.reload_assault_cannon) + return 1; + } } return 0; }; @@ -2004,6 +2027,12 @@ void () W_Attack = { W_FireAutoRifle(); Attack_Finished(0.1); } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { + if (fo_hwguy) + { + if (CheckForReload() == TRUE) + return; + } + if (self.ammo_cells < 7) { if (time >= self.antispam_assault_cannon) { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); From 125da5de882b6457ef3cfe22f9006cab2e8f4932 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 25 Jul 2019 23:53:10 +1000 Subject: [PATCH 0713/2474] slow medics once they are near ground --- ssqc/scout.qc | 56 +++++++++++++++++++++++++++++++++++++++++++++++--- ssqc/status.qc | 1 - 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index bc13245d..cf6a9b6a 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -526,6 +526,46 @@ void () TeamFortress_Scan = { return; }; +void CussSpeedBump() +{ + entity p; + p = self.owner; + self.nextthink = time + .3; + + if (!self.cnt2) + { + makevectors(p.v_angle); + + // if medic within x units of ground, slow + traceline(p.origin, (v_up * -1000), MOVE_NOMONSTERS, p); + + if (vlen(p.origin - trace_endpos) <= 100) + { + // near ground + self.cnt2 = 1; + } + } + + if (self.cnt2) + { + self.cnt = self.cnt + 1; + + if (vlen(p.velocity) > 1000) + { + if (self.cnt < 10) + { + p.velocity = p.velocity *.9; + } + } + } + + + if (self.cnt >= 10) + { + dremove(self); + } +} + void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce = { local float points; @@ -553,9 +593,19 @@ void (entity inflictor, entity attacker, float bounce, if (head.flags & FL_ONGROUND) head.flags = head.flags - FL_ONGROUND; } else { - if (medicnocuss && head.playerclass == 5) { - head = head.chain; - continue; + if (head.playerclass == PC_MEDIC) + { + if (medicnocuss) + { + entity speedbump; + speedbump = spawn(); + speedbump.think = CussSpeedBump; + speedbump.nextthink = time + 1; + speedbump.owner = head; + + head = head.chain; + continue; + } } te = find(world, classname, "timer"); diff --git a/ssqc/status.qc b/ssqc/status.qc index f1a5c3be..30a19118 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -998,7 +998,6 @@ string(entity pl) ClipSizeToString = } else return ""; - // TODO - can we up this to 100 for ass can? if (num > 999) num = 999; From 2809ddd3b07801f2a163931a50429803053c6e41 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 26 Jul 2019 19:24:24 +1200 Subject: [PATCH 0714/2474] extra precache kicks everyone off the server (except fte). oops. --- client.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/client.qc b/client.qc index 20bb2bff..ae79a08f 100644 --- a/client.qc +++ b/client.qc @@ -2275,8 +2275,6 @@ void () ClientConnect = { } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); - if (duelmode) - precache_sound("buttons/switch04.wav"); }; void () ClientDisconnect = { From ef4421e3750f62ee9af0bb189fbbb8f529f1d636 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 26 Jul 2019 20:41:16 +1000 Subject: [PATCH 0715/2474] remove bigger dispenser explosion --- ssqc/client.qc | 5 ----- ssqc/engineer.qc | 13 +++---------- ssqc/qw.qc | 1 - ssqc/tfort.qc | 1 - 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ba21a0fe..a6af8f1f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -454,9 +454,6 @@ void () DecodeLevelParms = { // enable flamethrower knockback [on] flame_knockback = CF_GetSetting("fk", "flame_knockback", "on"); - // bigger dispenser explosions [on] - disp_explosion = CF_GetSetting("de", "disp_explosion", "on"); - // allow building in water [on] build_water = CF_GetSetting("bw", "build_water", "on"); @@ -648,7 +645,6 @@ void () DecodeLevelParms = { old_spanner = FALSE; old_railgun = FALSE; old_dispenser = FALSE; - disp_explosion = TRUE; build_water = TRUE; feign_air = TRUE; feign_pack = TRUE; @@ -720,7 +716,6 @@ void () DecodeLevelParms = { old_spanner = TRUE; old_railgun = TRUE; old_dispenser = TRUE; - disp_explosion = FALSE; build_water = FALSE; feign_air = FALSE; feign_pack = FALSE; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 49c3d768..6d8dcd96 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -873,16 +873,9 @@ void () Dispenser_Explode = { if (self.real_owner.has_disconnected != 1) { deathmsg = 39; - if (disp_explosion) { - sdmg = 45 + self.ammo_rockets * 3 + self.ammo_cells; - if (sdmg > 350) { - sdmg = 350; - } - } else { - sdmg = 25 + self.ammo_rockets * 3 + self.ammo_cells; - if (sdmg > 250) { - sdmg = 250; - } + sdmg = 25 + self.ammo_rockets * 3 + self.ammo_cells; + if (sdmg > 250) { + sdmg = 250; } T_RadiusDamage(self, self.real_owner, sdmg, self); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index f2644122..9780d5b3 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -516,7 +516,6 @@ float medicaura; float old_medikit; float old_biodamage; float flame_knockback; -float disp_explosion; float build_water; float cannon_lock; float cannon_air; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 945451dd..7bb4d2f0 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -688,7 +688,6 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Old spanner behaviour", old_spanner, "", 1); CF_PrintSetting("Old railgun behaviour", old_railgun, "", 1); CF_PrintSetting("Old dispenser behaviour", old_dispenser, "", 1); - CF_PrintSetting("Bigger dispenser explosions", disp_explosion, "", 1); CF_PrintSetting("Build status in status bar", buildstatus, "", 1); sprint(self, PRINT_HIGH, "\n== Spy ==\n"); From 8dcf6b31e0f5ecb7fb0c86a8f6cab8dd68d72bbc Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 26 Jul 2019 20:45:01 +1000 Subject: [PATCH 0716/2474] remove railgun "non penetration" option, update readme --- README.md | 2 -- ssqc/client.qc | 5 ----- ssqc/engineer.qc | 17 +++++++---------- ssqc/qw.qc | 1 - ssqc/tfort.qc | 1 - 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c5a876d8..05e8d54b 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,6 @@ Engineer * Upgrade/repair/restock Sentry Gun on spanner hit. * Dispenser automatically stocks nearby team members. * Dispenser restock rate increases with more players on team. -* Rocket ammo in Dispenser increase explosions more than before. * Repair Dispenser on spanner hit. * Dismantle Sentry Gun/Dispenser using build menu when standing close. * Stop building by pressing last weapon key. @@ -146,7 +145,6 @@ Engineer * Added dismantle message to show how many cells were returned to Engineer. * Changed class special to detonate dispenser. * Engineers can now only dismantle own buildings and rotate own Sentry Gun. -* Railgun no longer penetrates targets. Compilation diff --git a/ssqc/client.qc b/ssqc/client.qc index a6af8f1f..642d973f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -445,9 +445,6 @@ void () DecodeLevelParms = { // use old tf style spanner (non-automated) [off] old_spanner = CF_GetSetting("os", "old_spanner", "off"); - // use old tf style railgun (penetrate target) [off] - old_railgun = CF_GetSetting("or", "old_railgun", "off"); - // use old tf style dispenser (non-auto stocking) [off] old_dispenser = CF_GetSetting("od", "old_dispenser", "off"); @@ -643,7 +640,6 @@ void () DecodeLevelParms = { cannon_accuracy = 0; flame_knockback = TRUE; old_spanner = FALSE; - old_railgun = FALSE; old_dispenser = FALSE; build_water = TRUE; feign_air = TRUE; @@ -714,7 +710,6 @@ void () DecodeLevelParms = { cannon_accuracy = 1; flame_knockback = FALSE; old_spanner = TRUE; - old_railgun = TRUE; old_dispenser = TRUE; build_water = FALSE; feign_air = FALSE; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 6d8dcd96..15313872 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -51,16 +51,13 @@ void () LaserBolt_Touch = { deathmsg = DMSG_LASERBOLT; TF_T_Damage(other, self, self.enemy, 25, 2, TF_TD_ELECTRICITY); - // create a new projectile on other side of target if old_railgun is enabled - if (old_railgun) { - self.velocity = self.oldorigin; - self.owner = other; - setmodel(self, string_null); - self.touch = SUB_Null; - self.nextthink = time + 0.1; - self.think = LaserBolt_Think; - return; - } + // create a new projectile on other side of target + self.velocity = self.oldorigin; + self.owner = other; + setmodel(self, string_null); + self.touch = SUB_Null; + self.nextthink = time + 0.1; + self.think = LaserBolt_Think; } else { WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_SPIKE); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9780d5b3..b3cd5905 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -543,7 +543,6 @@ float server_default; float server_faithful; float old_spanner; -float old_railgun; float old_dispenser; float old_hp_armor; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 7bb4d2f0..488bb4ff 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -686,7 +686,6 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "\n== Engineer ==\n"); CF_PrintSetting("Old spanner behaviour", old_spanner, "", 1); - CF_PrintSetting("Old railgun behaviour", old_railgun, "", 1); CF_PrintSetting("Old dispenser behaviour", old_dispenser, "", 1); CF_PrintSetting("Build status in status bar", buildstatus, "", 1); From 025894e814f3196f055eaf011b81a12bbe50d106 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 27 Jul 2019 23:16:45 +1200 Subject: [PATCH 0717/2474] Fix ready-status with disconnecting players; team-wide duelmode --- ssqc/clan.qc | 40 ++++++++++++++++++++++++++------------- ssqc/client.qc | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- ssqc/combat.qc | 37 ++++++++++++++++++++---------------- 3 files changed, 98 insertions(+), 30 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index c07bf634..16ac6f69 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -837,10 +837,33 @@ void () PlayerNotReady = { } } -void () PlayerReady = -{ +float () CheckAllPlayersReady = { local float f1; + if (is_countdown) { + return 0; + } + if (infokey (world, "status") != "Standby") { + return 0; + } + if (intermission_running) + return 0; + + f1 = TeamFortress_GetNoPlayers (); + bprint (PRINT_HIGH, "Checking readiness - ",ftos(v_ready),"/",ftos(f1),".\n"); + if (v_ready == f1 ) { + if(cease_fire) { + bprint (2, "All players ready, match will start after ceasefire ends.\n"); + } else { + bprint (2, "All players ready, starting match\n"); + StartTimer (); + } + return 1; + } + return 0; +} +void () PlayerReady = +{ if (is_countdown) { sprint(self, 2, "You cannot do this after countdown has started.\n"); return; @@ -868,17 +891,8 @@ void () PlayerReady = self.is_ready = 1; v_ready = v_ready + 1; bprint2 (3, self.netname, " is ready to start the match\n"); - f1 = TeamFortress_GetNoPlayers (); - if (v_ready == f1 ) { - if(cease_fire) { - bprint (2, "All players ready, match will start after ceasefire ends.\n"); - } else { - bprint (2, "All players ready, starting match\n"); - StartTimer (); - } - return; - } - Broadcast_Players_NotReady(); + if(!CheckAllPlayersReady()) + Broadcast_Players_NotReady(); }; void () RemoveVotes = { diff --git a/ssqc/client.qc b/ssqc/client.qc index d2a55299..570bd507 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -58,6 +58,8 @@ void (string cl_pwd) Admin_Check; void () Admin_Aliases; void () PreMatch_Message; float () GetLastWeaponImpulse; +float () CheckAllPlayersReady; +string(float)TeamFortress_TeamGetColorString; string nextmap; @@ -1122,7 +1124,43 @@ void () ResetPlayers = { } te = find (te, classname, "player"); } +} +float () CountRemainingTeams = { + local float teamsleft, teamflags, playersleft; + local entity te, lastplayer; + te = find(world, classname, "player"); + while (te != world) { + if(!te.has_disconnected && te.health > 0) { + teamflags = teamflags | pow(2, te.team_no); + lastplayer = te; + playersleft++; + } + te = find (te, classname, "player"); + } + teamsleft = 0; + if(teamflags & 2) { + teamsleft++; + } + if(teamflags & 4) { + teamsleft++; + } + if(teamflags & 8) { + teamsleft++; + } + if(teamflags & 16) { + teamsleft++; + } + if(teamsleft == 1) { + if(playersleft == 1) { + bprint(PRINT_HIGH, lastplayer.netname, " of team ", TeamFortress_TeamGetColorString(lastplayer.team_no) ,", wins the round!\n"); + } else { + bprint(PRINT_HIGH, TeamFortress_TeamGetColorString(lastplayer.team_no), " team wins the round!\n"); + } + } else if(teamsleft == 0) { + bprint(PRINT_HIGH, "Everybody died! It's a draw.\n"); + } + return teamsleft; } void () ClientKill = { @@ -1185,7 +1223,9 @@ void () ClientKill = { self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; self.takedamage = 0; if(duelmode) { - ResetPlayers(); + if(CountRemainingTeams() < 2) { + ResetPlayers(); + } } }; @@ -2336,6 +2376,15 @@ void () ClientDisconnect = { if (self.StatusString) strunzone(self.StatusString); self.StatusString = string_null; + + if(cb_prematch) { + //Check in case the player leaving is the last not-readied player + if(self.is_ready) { + v_ready = (v_ready - 1); + } else { + CheckAllPlayersReady(); + } + } }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 0e9d5860..11c5f825 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -6,6 +6,7 @@ void () ResetPlayers; void (entity Goal, entity AP, float addb) DoResults; float (entity Goal, entity AP) Activated; float (entity targ, entity attacker, float damage) TeamEqualiseDamage; +float () CountRemainingTeams; void () monster_death_use = { if (self.flags & FL_FLY) @@ -108,24 +109,28 @@ void (entity targ, entity attacker) Killed = { if(duelmode && targ.classname == "player" && !cb_prematch) { //Already in no fire mode - implies you're not the first to die if(no_fire_mode) { - reset_timer = find(world, classname, "duel_reset_timer"); - while (reset_timer != world) { - oself = reset_timer; - reset_timer = find (reset_timer, classname, "duel_reset_timer"); - dremove(oself); + if(CountRemainingTeams() == 0) { + reset_timer = find(world, classname, "duel_reset_timer"); + while (reset_timer != world) { + oself = reset_timer; + reset_timer = find (reset_timer, classname, "duel_reset_timer"); + dremove(oself); + } + ResetPlayers(); } - ResetPlayers(); } else { - no_fire_mode = 1; - if(duel_reset_delay) { - remainder = duel_reset_delay % 1; - duel_reset_timer = duel_reset_delay - remainder; - reset_timer = spawn(); - reset_timer.classname = "duel_reset_timer"; - reset_timer.nextthink = time + remainder; - reset_timer.think = ResetPlayersDelayed; - } else { - ResetPlayers(); + if(CountRemainingTeams() < 2) { + no_fire_mode = 1; + if(duel_reset_delay) { + remainder = duel_reset_delay % 1; + duel_reset_timer = duel_reset_delay - remainder; + reset_timer = spawn(); + reset_timer.classname = "duel_reset_timer"; + reset_timer.nextthink = time + remainder; + reset_timer.think = ResetPlayersDelayed; + } else { + ResetPlayers(); + } } } } From 9a61846732677442e3624d769d0b1d31956c3577 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 27 Jul 2019 22:19:25 +1000 Subject: [PATCH 0718/2474] make defs shared, add some hud defines --- {ssqc => share}/defs.h | 11 +++++++++++ ssqc/qw.qc | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) rename {ssqc => share}/defs.h (99%) diff --git a/ssqc/defs.h b/share/defs.h similarity index 99% rename from ssqc/defs.h rename to share/defs.h index 06e77d38..7be24847 100644 --- a/ssqc/defs.h +++ b/share/defs.h @@ -1291,3 +1291,14 @@ #define RESPAWN_DELAY_TIME 5 // this is the respawn delay, if the RESPAWN_DELAY option is // turned on with temp1. QuakeWorld servers can use // serverinfo respawn_delay to set their own time. + + +// CSQC defines +#define FO_HUD_GROW_UP 1 +#define FO_HUD_GROW_DOWN 2 +#define FO_HUD_GROW_LEFT 3 +#define FO_HUD_GROW_RIGHT 4 + +#define FO_HUD_INSERT_AFTER 1 +#define FO_HUD_INSERT_BEFORE 1 + diff --git a/ssqc/qw.qc b/ssqc/qw.qc index b3cd5905..40bc320c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -1,4 +1,4 @@ -#include "defs.h" +#include "../share/defs.h" void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate; typedef void (float n) f_void_float; @@ -544,6 +544,7 @@ float server_faithful; float old_spanner; float old_dispenser; +float old_emp_radius; float old_hp_armor; float ng_velocity; From 1acfcda3114150b22947f6ebc82053c977d471e4 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 27 Jul 2019 22:19:42 +1000 Subject: [PATCH 0719/2474] add ability to reposition panels in fo_hud_editor mode --- csqc/csextradefs.qc | 38 ++ csqc/csprogs.src | 4 + csqc/hud.qc | 93 +++++ csqc/hud_helpers.qc | 84 ++++ csqc/input.qc | 34 ++ csqc/main.qc | 89 +---- csqc/sui_sys.qc | 939 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1210 insertions(+), 71 deletions(-) create mode 100644 csqc/hud.qc create mode 100644 csqc/hud_helpers.qc create mode 100644 csqc/input.qc create mode 100644 csqc/sui_sys.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 69cf4781..12b18703 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -1 +1,39 @@ +#include "../share/defs.h" + .float owned_by; +float fo_hud_editor; + +typedef struct +{ + float x; + float y; +} MouseStruct; + +MouseStruct Mouse; + +typedef struct { + float id; + string message; + //string model; + entity model; + float timeleft; + float state; + vector loc; + string carrier; + string locname; +} FlagInfoLine; + +FlagInfoLine FlagInfoLines[10]; + +typedef struct { + vector Position; + float GrowDirection; + float NodeInsertLoc; +} FO_Hud_FlagIcon; + +typedef struct { + FO_Hud_FlagIcon FlagIcon; + vector MousePos; +} FO_Hud_Settings; + +FO_Hud_Settings HudSettings; \ No newline at end of file diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 615bc766..49b164d5 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -2,4 +2,8 @@ csdefs.qc ../share/commondefs.qc csextradefs.qc +sui_sys.qc +input.qc main.qc +hud_helpers.qc +hud.qc \ No newline at end of file diff --git a/csqc/hud.qc b/csqc/hud.qc new file mode 100644 index 00000000..2352decc --- /dev/null +++ b/csqc/hud.qc @@ -0,0 +1,93 @@ +void FO_Hud_Editor() +{ + if (fo_hud_editor) + { + fo_hud_editor = FALSE; + setcursormode(FALSE); + } + else + { + fo_hud_editor = TRUE; + setcursormode(TRUE); + } +} + +void FO_Hud_Editor_LoadSettings(float height) +{ + fo_hud_editor = FALSE; + HudSettings.MousePos = [0, 0]; + // check struct, put defaults in + float yoffset = height - 64; + FO_Hud_FlagIcon HudFlagIcon; + HudFlagIcon.Position = [32, yoffset]; + HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; + HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; + + HudSettings.FlagIcon = HudFlagIcon; + + // check if file exists + + // if exists, load all data overwriting struct + +} + +void Hud_Draw(float width, float height) +{ + vector pos = [0, 0]; + vector fillsize = [width*.2, height*.2]; + if (hud_panel("flagiconpanel", HudSettings.FlagIcon.Position, fillsize)) + { + if (fo_hud_editor) + { + print("clicky!\n"); + + } + + } + + float yoffset = height - 64; + for (float i = FlagInfoLines.length - 1; i >= 0; i--) + { + if (FlagInfoLines[i].id) + { + string icon = "sb_key1"; + vector iconcolour = '1 1 1'; + float alpha = 1; + if (FlagInfoLines[i].model) { + switch (FlagInfoLines[i].model.owned_by) + { + case 2: + icon = "sb_key2"; + break; + case 3: + iconcolour = '1 1 0'; + break; + case 4: + icon = "sb_key2"; + iconcolour = '0 1 0'; + break; + } + } + if (FlagInfoLines[i].state == FLAGINFO_HOME) + { + alpha = 0.3; + } + else if (FlagInfoLines[i].state == FLAGINFO_CARRIED) + { + drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + } + else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) + { + drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + } + + drawpic([8, yoffset - 4 - 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); + + if (FlagInfoLines[i].timeleft >= 0) + { + string stime = ftos(FlagInfoLines[i].timeleft); + drawstring([30 - stringwidth(stime, 1, '6 6'), yoffset + 14 - 24 * i, 0], stime, '6 6', '1 1 1', 1, 0); + } + } + } +} \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc new file mode 100644 index 00000000..dbb333ff --- /dev/null +++ b/csqc/hud_helpers.qc @@ -0,0 +1,84 @@ +vector MENU_BG = '0.2 0.3 0.4'; +vector MENU_BG_DARK = '0.1 0.15 0.2'; +vector MENU_BORDER = '0.3 0.4 0.5'; +vector MENU_SELECTED = '0 1 0'; +vector MENU_BUTTON = '0.3 0.4 0.5'; +vector MENU_BUTTON_BORDER = '0.35 0.45 0.55'; +vector MENU_TEXT_1 = '1 1 1'; +vector MENU_TEXT_2 = '0.7 0.75 0.75'; +vector MENU_HIGHLIGHT = '1 1 1'; +vector MENU_DARKEN = '1 1 1'; + +vector MENU_TEXT_SMALL = '8 8 0'; +vector MENU_TEXT_MEDIUM = '16 16 0'; +vector MENU_TEXT_LARGE = '24 24 0'; +float MENU_START_CONTENT = 32; + +float(string id, vector pos, vector size, string text) hud_button = +{ + sui_push_frame(pos, size); + vector basecolor = sui_is_hovered(id) ? MENU_BUTTON + MENU_HIGHLIGHT * 0.1 : MENU_BUTTON; + basecolor = sui_is_held(id) ? MENU_BUTTON - MENU_DARKEN * 0.1 : basecolor; + sui_fill([0, 0], size, basecolor, 0.6, 0); + sui_border_box([0, 0], size, 1, MENU_BUTTON_BORDER, 0.4, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_text([0, 0], MENU_TEXT_SMALL, text, MENU_TEXT_1, 1, 0); + sui_action_element([0, 0], size, id, sui_noop); + sui_pop_frame(); + + return sui_is_clicked(id); +}; + +vector UpdatePos(string id, vector mousepos) +{ + vector pos; + switch (id) + { + case "flagiconpanel": + if (HudSettings.MousePos != [0, 0]) + { + pos = HudSettings.FlagIcon.Position + mousepos - HudSettings.MousePos; + HudSettings.FlagIcon.Position = pos; + } + HudSettings.MousePos = mousepos; + + break; + } + + return pos; +} + +float(string id, vector pos, vector size) hud_panel = +{ + if (fo_hud_editor) + { + if (sui_is_last_clicked(id)) + { + sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); + } + + if (sui_is_held(id)) + { + pos = [Mouse.x, Mouse.y]; + pos = UpdatePos(id, pos); + sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); + } + else + { + HudSettings.MousePos = [0, 0]; + } + + } + + sui_push_frame(pos, size); + vector basecolor = sui_is_hovered(id) ? MENU_BG + MENU_HIGHLIGHT * 0.1 : MENU_BG; + basecolor = sui_is_held(id) ? MENU_BG - MENU_DARKEN * 0.1 : basecolor; + sui_fill([0, 0], size, basecolor, 0.6, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_action_element([0, 0], size, id, sui_noop); + sui_pop_frame(); + + return sui_is_clicked(id); +}; diff --git a/csqc/input.qc b/csqc/input.qc new file mode 100644 index 00000000..78abdfa9 --- /dev/null +++ b/csqc/input.qc @@ -0,0 +1,34 @@ +float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { + float used = sui_input_event(evtype, scanx, chary, devid); + if (fo_hud_editor) + { + switch (evtype) + { + case IE_KEYUP: + switch (scanx) + { + case K_MOUSE1: + // work out if on a button + break; + } + break; + case IE_KEYDOWN: + switch (scanx) + { + case K_MOUSE1: + // work out if on a button + return TRUE; + break; + } + break; + case IE_MOUSEDELTA: + return TRUE; + case IE_MOUSEABS: + Mouse.x = scanx; + Mouse.y = chary; + return TRUE; + default: + } + } + return FALSE; +} \ No newline at end of file diff --git a/csqc/main.qc b/csqc/main.qc index df8685c2..34c10b5f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -1,26 +1,21 @@ +void FO_Hud_Editor(); +void Hud_Draw(float width, float height); +void FO_Hud_Editor_LoadSettings(float height); + noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); precache_model("progs/weapons/v_rock.mdl"); + registercommand("fo_hud_editor"); + + vector vsize = (vector)getproperty(VF_SCREENVSIZE); + + FO_Hud_Editor_LoadSettings(vsize_y); }; noref void() CSQC_WorldLoaded = { print("CSQC World Loaded\n"); } -typedef struct { - float id; - string message; - //string model; - entity model; - float timeleft; - float state; - vector loc; - string carrier; - string locname; -} FlagInfoLine; - -var FlagInfoLine FlagInfoLines[10]; - noref void(float width, float height, float menushown) CSQC_UpdateView = { clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! @@ -34,58 +29,12 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { //setviewprop(VF_AFOV, cvar("fov”)); //note: fov_x and fov_y control individual axis. afov is general //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view -/* - for(float i = 0; i < FlagInfoLines.length; i++) { - if(FlagInfoLines[i].id) { - //drawstring([16, 32 + 16 * i, 0], FlagInfoLines[i].message, '8 8', '1 1 1', 1, 0); - FlagInfoLines[i].model.origin = [random() * 100 - 50,random() * 100 - 50,random() * 100 - 50]; - addentity(FlagInfoLines[i].model); - } - } -*/ + renderscene(); - float yoffset = height - 64; - for(float i = FlagInfoLines.length - 1; i >= 0; i--) { - if(FlagInfoLines[i].id) { - string icon = "sb_key1"; - vector iconcolour = '1 1 1'; - float alpha = 1; - if(FlagInfoLines[i].model) { - switch(FlagInfoLines[i].model.owned_by) { - case 2: - icon = "sb_key2"; - break; - case 3: - iconcolour = '1 1 0'; - break; - case 4: - icon = "sb_key2"; - iconcolour = '0 1 0'; - break; - } - } - if(FlagInfoLines[i].state == FLAGINFO_HOME) { - alpha = 0.3; - } else if(FlagInfoLines[i].state == FLAGINFO_CARRIED) { - //drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); - drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); - } else if(FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); - } - //drawpic([8, 28 + 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); - drawpic([8, yoffset - 4 - 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); - //drawstring([32, 32 + 24 * i, 0], strcat(FlagInfoLines[i].message," ",ftos(FlagInfoLines[i].timeleft)), '8 8', '1 1 1', 1, 0); - //drawstring([32, 32 + 24 * i, 0], FlagInfoLines[i].message, '8 8', '1 1 1', 1, 0); - if(FlagInfoLines[i].timeleft >= 0) { - string stime = ftos(FlagInfoLines[i].timeleft); - //drawstring([24, 46 + 24 * i, 0], ftos(FlagInfoLines[i].timeleft), '6 6', '1 1 1', 1, 0); - drawstring([30 - stringwidth(stime, 1, '6 6'), yoffset + 14 - 24 * i, 0], stime, '6 6', '1 1 1', 1, 0); - } - //addentity(FlagInfoLines[i].model); - //drawstring([300, 32 + 16 * i, 0], strcat(vtos(FlagInfoLines[i].model.origin), " ", FlagInfoLines[i].model.model), '8 8', '1 1 1', 1, 0); - } - } + sui_begin(width, height); + Hud_Draw(width, height); + sui_end(); } void GetSelf() = { @@ -94,16 +43,14 @@ void GetSelf() = { noref float(string cmd) CSQC_ConsoleCommand = { tokenize(cmd); - //switch(argv(0)) { - //case "moregold": - //} + switch(argv(0)) { + case "fo_hud_editor": + FO_Hud_Editor(); + break; + } return FALSE; }; -float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { - return FALSE; -} - void(float isnew) CSQC_Ent_Update = { print("CSQC_Ent_Update, new: ", ftos(isnew), "\n"); float etype = readbyte(); diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc new file mode 100644 index 00000000..20ac85de --- /dev/null +++ b/csqc/sui_sys.qc @@ -0,0 +1,939 @@ +// Shpuld's Simple UI lib - sui +// Created 11/2018 +// +// sui is a simple QuakeC UI lib for drawing and handling game interfaces. +// The API is made simple and easy to build upon, but cuts have been made +// to keep complexity low. +// +#define printf(x, ...) print(sprintf(x, __VA_ARGS__)) + +#ifdef MENU +const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ +const float IE_KEYUP = 1; /* Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired. */ +const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_MOUSEABS = 3; /* Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_ACCELEROMETER = 4; +const float IE_FOCUS = 5; /* Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged. */ +const float IE_JOYAXIS = 6; /* Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller. */ + +#define printf(x, ...) print(sprintf(x, __VA_ARGS__)) + +#endif +float _sui_draw_initialized; + + +// framing + +// pseudo windowing, sets a new "frame" for whatever we're drawing, instead of +// always using screen [0, 0] as min and [screen_width, screen_height] as max. +// also allows for aligning content to frame start/end/center on both axis + +struct _frame_t { + vector pos; + vector size; + vector align; +}; +const float MAX_FRAMES = 64; +_frame_t _frames[MAX_FRAMES]; +float _frame_index; + +const float SUI_ALIGN_START = 0; +const float SUI_ALIGN_CENTER = 1; +const float SUI_ALIGN_END = 2; + +void() sui_reset_align = +{ + _frames[_frame_index].align = [SUI_ALIGN_START, SUI_ALIGN_START]; +}; + +void(float align) sui_set_x_align = +{ + _frames[_frame_index].align.x = align; +}; + +void(float align) sui_set_y_align = +{ + _frames[_frame_index].align.y = align; +}; + +void(vector align) sui_set_align = +{ + _frames[_frame_index].align = align; +}; + +void(__inout vector point) sui_transform_point = +{ + int idx = _frame_index; + switch (_frames[idx].align.x) + { + case SUI_ALIGN_START: point_x += _frames[idx].pos.x; break; + case SUI_ALIGN_CENTER: point_x += _frames[idx].pos.x + _frames[idx].size.x * 0.5; break; + case SUI_ALIGN_END: point_x += _frames[idx].pos.x + _frames[idx].size.x; break; + default: break; + } + switch (_frames[idx].align.y) + { + case SUI_ALIGN_START: point_y += _frames[idx].pos.y; break; + case SUI_ALIGN_CENTER: point_y += _frames[idx].pos.y + _frames[idx].size.y * 0.5; break; + case SUI_ALIGN_END: point_y += _frames[idx].pos.y + _frames[idx].size.y; break; + default: break; + } +}; + +void(__inout vector point, vector size) sui_transform_box = +{ + int idx = _frame_index; + switch (_frames[idx].align.x) + { + case SUI_ALIGN_START: + point_x += _frames[idx].pos.x; + break; + case SUI_ALIGN_CENTER: + point_x += _frames[idx].pos.x + _frames[idx].size.x * 0.5 - size_x * 0.5; + break; + case SUI_ALIGN_END: + point_x += _frames[idx].pos.x + _frames[idx].size.x - size_x; + break; + default: break; + } + switch (_frames[idx].align.y) + { + case SUI_ALIGN_START: + point_y += _frames[idx].pos.y; + break; + case SUI_ALIGN_CENTER: + point_y += _frames[idx].pos.y + _frames[idx].size.y * 0.5 - size_y * 0.5; + break; + case SUI_ALIGN_END: + point_y += _frames[idx].pos.y + _frames[idx].size.y - size_y; + break; + default: break; + } +}; + +vector() sui_current_frame_pos = +{ + return _frames[_frame_index].pos; +}; + +vector() sui_current_frame_size = +{ + return _frames[_frame_index].size; +}; + +float _sui_is_clipping; +vector _sui_clip_area_mins; +vector _sui_clip_area_maxs; +void() sui_clip_to_frame = +{ + vector pos = _frames[_frame_index].pos; + vector size = _frames[_frame_index].size; + _sui_is_clipping = TRUE; + _sui_clip_area_mins = pos; + _sui_clip_area_maxs = pos + size; + drawsetcliparea(pos.x, pos.y, size.x, size.y); +}; + +void() sui_reset_clip = +{ + _sui_is_clipping = FALSE; + drawresetcliparea(); +}; + +float() sui_is_clipping = +{ + return _sui_is_clipping; +}; + +void(vector pos, vector size) sui_push_frame = +{ + sui_transform_box(pos, size); + + _frame_index += 1; + if (_frame_index >= MAX_FRAMES) + { + printf("^3sui warning: amount of frames = %.0f exceeds MAX_FRAMES = %.0f, consider increasing MAX_FRAMES\n", _frame_index, MAX_FRAMES); + return; + } + + _frames[_frame_index].pos = pos; + _frames[_frame_index].size = size; + _frames[_frame_index].align = [SUI_ALIGN_START, SUI_ALIGN_START]; // TODO allow customizing this +}; + +void() sui_pop_frame = +{ + if (_frame_index > 0) _frame_index -= 1; +}; + +void() sui_reset_frame = +{ + _frame_index = 0; + sui_reset_align(); +}; + + +// actions + +// interaction for sui elements, relies a lot on reading globals to see which +// element id is under cursor or held or whatever, not the most elegant +// solution but in this highly imperative world of QuakeC we can live with it + +float _holding_click; +vector _cursor_click; +vector _cursor_position; +vector _cursor_relative_click; +vector _cursor_relative_hover; +struct _action_element_t { + vector pos; + vector size; + string id; + void(float index, vector click_ratios) action; +}; +const float MAX_ACTION_ELEMENTS = 256; +_action_element_t _action_elements[MAX_ACTION_ELEMENTS]; +float _action_elements_index; + + +// TODO better naming +float(vector point, vector min, vector max) is_2dpoint_in_bounds = +{ + if (point_x <= min_x || point_y <= min_y) return FALSE; + if (point_x > max_x || point_y > max_y) return FALSE; + return TRUE; +}; + +// TODO better naming +float(vector point, vector pos, vector size) is_2dpoint_in_bbox = +{ + return is_2dpoint_in_bounds(point, pos, pos + size); +}; + +void() _action_element_count_sanity = +{ + if (_action_elements_index > MAX_ACTION_ELEMENTS) + { + // let the user know if they're hitting the bounds + printf("^3sui warning: amount of action elements = %.0f exceeds MAX_ACTION_ELEMENTS = %.0f, consider increasing MAX_ACTION_ELEMENTS\n", _action_elements_index, MAX_ACTION_ELEMENTS); + } +}; + +const float MAX_MOUSE_ACTIONS = 16; +string _hover_actions[MAX_MOUSE_ACTIONS]; +string _click_actions[MAX_MOUSE_ACTIONS]; +string _hold_actions[MAX_MOUSE_ACTIONS]; +string _release_actions[MAX_MOUSE_ACTIONS]; +string _last_clicked_actions[MAX_MOUSE_ACTIONS]; + +float _hover_action_count; +float _click_action_count; +float _hold_action_count; +float _release_action_count; +float _last_clicked_action_count; + + +// Resets things you might want to persist normally +void() sui_reset_actions = +{ + _hover_action_count = 0; + _click_action_count = 0; + _hold_action_count = 0; + _release_action_count = 0; + _last_clicked_action_count = 0; + _holding_click = FALSE; +}; + +// Per frame reset? +void() sui_reset_click = +{ + _hold_action_count = 0; + _click_action_count = 0; + _holding_click = FALSE; +}; + +float() sui_click_held = { return _holding_click; }; + + +// click: on mouse1 button down AND button op, once + +// Returns true if id was the topmost click (what usually is cared about the most) +float(string id) sui_is_clicked = +{ + return _click_action_count > 0 && _click_actions[0] == id; +}; + +// Returns the index of the clicked id, -1 if wasn't hit at all. 0 is topmost +float(string id) sui_click_index = +{ + for (int i = 0; i < _click_action_count; i++) + { + if (_click_actions[i] == id) return i; + } + return -1; +}; + + +// hover: mouse is on top of the action element id + +float(string id) sui_is_hovered = +{ + return _hover_action_count > 0 && _hover_actions[0] == id; +}; + +float(string id) sui_hover_index = +{ + for (int i = 0; i < _hover_action_count; i++) + { + if (_hover_actions[i] == id) return i; + } + return -1; +}; + + +// hold: mouse button was clicked on top of this id and is held down, but not necessarily over this id anymore + +float(string id) sui_is_held = +{ + return _hold_action_count > 0 && _hold_actions[0] == id; +}; + +float(string id) sui_hold_index = +{ + for (int i = 0; i < _hold_action_count; i++) + { + if (_hold_actions[i] == id) return i; + } + return -1; +}; + + +// last clicked: is this the last action element that was clicked, good for focusing on input boxes for example + +float(string id) sui_is_last_clicked = +{ + return _last_clicked_action_count > 0 && _last_clicked_actions[0] == id; +}; + +float(string id) sui_last_clicked_index = +{ + for (int i = 0; i < _last_clicked_action_count; i++) + { + if (_last_clicked_actions[i] == id) return i; + } + return -1; +}; + + +// release: a thing was held, but now it was released, once + +float(string id) sui_is_released = +{ + return _release_action_count > 0 && _release_actions[0] == id; +}; + +float(string id) sui_release_index = +{ + for (int i = 0; i < _release_action_count; i++) + { + if (_release_actions[i] == id) return i; + } + return -1; +}; + + +float(float num) mouse_action_sanity = +{ + if (num >= MAX_MOUSE_ACTIONS) + { + printf("^3sui warning: you have exceeded the amount of overlapping action elements with %.0f, MAX_MOUSE_ACTIONS = %.0f\n", num, MAX_MOUSE_ACTIONS); + return TRUE; + } + return FALSE; +}; + +// mouse move, mostly just update hovers + +void(vector pos) _sui_mouse_move = +{ + _cursor_position = pos; + _action_element_count_sanity(); + + // Reset hover, it'll be back to what it used to be before draw gets called if mouse is still on same element + _hover_action_count = 0; + + // Iterate front to back, so topmost element gets the click/hover + for (int i = min(MAX_ACTION_ELEMENTS, _action_elements_index) - 1; i >= 0; i--) + { + if (is_2dpoint_in_bbox(_cursor_position, _action_elements[i].pos, _action_elements[i].size)) + { + if (mouse_action_sanity(_hover_action_count)) break; + + if (_hover_action_count == 0) _cursor_relative_hover = _cursor_position - _action_elements[i].pos; + _hover_actions[_hover_action_count] = _action_elements[i].id; + _hover_action_count += 1; + } + } +}; + +// JERK ALERT: hard to pass input params for it without them just being the globals +// ... so it just straight up uses the globals... optimization +void() _sui_mouse1_down = +{ + // Cheap but it should work... + _cursor_click = _cursor_position; + _cursor_relative_click = _cursor_relative_hover; + for (int i = 0; i < _hover_action_count; i++) _hold_actions[i] = _hover_actions[i]; + _hold_action_count = _hover_action_count; + _holding_click = TRUE; + _last_clicked_action_count = 0; +}; + +void() _sui_mouse1_up = +{ + // Can't be cheap here, we have to get the action fn of the element anyway so.. + _action_element_count_sanity(); + + // Assume we won't hit anything + _click_action_count = 0; + _last_clicked_action_count = 0; + + // Iterate front to back, so topmost element gets the click/hover + for (int i = min(MAX_ACTION_ELEMENTS, _action_elements_index) - 1; i >= 0; i--) + { + // If the thing wasn't the same thing we started pressing down on, ignore + for (int j = 0; j < _hold_action_count; j++) + { + if (_hold_actions[j] == _action_elements[i].id) // yes this element was held + { + // Still in bounds? + if (is_2dpoint_in_bbox(_cursor_position, _action_elements[i].pos, _action_elements[i].size)) + { + if (mouse_action_sanity(_click_action_count)) break; + + // Register click + _click_actions[_click_action_count] = _action_elements[i].id; + _last_clicked_actions[_last_clicked_action_count] = _action_elements[i].id; + _click_action_count += 1; + _last_clicked_action_count += 1; + } + } + } + } + + // In case someone is keeping state on hold and wants to do stuff on release, even if cursor has moved + for (int i = 0; i < _hold_action_count; i++) _release_actions[i] = _hold_actions[i]; + _release_action_count = _hold_action_count; + _hold_action_count = 0; + _holding_click = FALSE; +}; + +void(vector pos, vector size, string id, void(float index, vector click_ratios) action) sui_action_element = +{ + if (!_sui_draw_initialized) + { + print("^1sui error: adding sui elements before sui_pre_draw!\n^1 Always do your sui menus between sui_pre_draw and sui_draw!\n"); + } + if (_action_elements_index >= MAX_ACTION_ELEMENTS) + { + // Silently fail here, sui will let us know another way, increase the count + // so that the error in click/mousemove handlers prints correct numbers. + _action_elements_index += 1; + return; + } + + sui_transform_box(pos, size); + + if (_sui_is_clipping) + { + vector oldpos = pos; + pos_x = max(pos_x, _sui_clip_area_mins_x); + pos_y = max(pos_y, _sui_clip_area_mins_y); + + size -= pos - oldpos; + + size_x -= bound(0, (pos_x + size_x - _sui_clip_area_maxs_x), size_x); + size_y -= bound(0, (pos_y + size_y - _sui_clip_area_maxs_y), size_y); + } + + _action_elements[_action_elements_index].pos = pos; + _action_elements[_action_elements_index].size = size; + _action_elements[_action_elements_index].id = id; + _action_elements[_action_elements_index].action = action; + + _action_elements_index += 1; +}; + + +// Input related stuff + +string _sui_binding_command; +string _sui_binding_command_name; + +struct _input_t { + float char; + float scan; +}; +const float MAX_INPUTS = 64; + +_input_t _input_buffer[MAX_INPUTS]; +float _input_index; +float _input_length; + + +// probably good to use it like while (sui_get_input(char, scan)) { ... }; +float(__inout float char, __inout float scan) sui_get_input = +{ + if (_input_index >= _input_length) return FALSE; + + char = _input_buffer[_input_index].char; + scan = _input_buffer[_input_index].scan; + _input_index++; + + return TRUE; +}; + +// if 2 controls want to read the same input for some reason.. +void() sui_reread_input = +{ + _input_index = 0; +}; + +void() sui_clear_input = +{ + _input_length = 0; + _input_index = 0; +}; + +float(float char, float scan) _sui_add_input = +{ + // TODO check if input was listened, return FALSE if not + if (_input_length >= MAX_INPUTS) + { + printf("^3sui warning: exceeded amount of per frame inputs count MAX_INPUTS = %.0f\n" + "^3 - make sure sui_input_event isn't being called without sui_draw being called in update loop\n" + "^3 - consider increasing MAX_INPUTS\n", MAX_INPUTS); + return TRUE; + } + _input_buffer[_input_length].char = char; + _input_buffer[_input_length].scan = scan; + _input_length += 1; + return TRUE; +}; + +// Listen to a certain keycode if it was pressed, this way sui know it was requested +float(float keycode) sui_listen_keycode_down = +{ + return FALSE; +}; + +// all text that was input between last and current frame +string() sui_listen_text_input = +{ + return ""; +}; + +void(float char, float scan, __inout string text, __inout float cursor) sui_handle_text_input = +{ + float maxlen = 128; + + string prev = text; + string pre_cursor, post_cursor; + float length = strlen(prev); + if (char > 31 && char < 128) //an actual input + { + if (length >= maxlen) return; + pre_cursor = substring(prev, 0, cursor); + post_cursor = substring(prev, cursor, length); + + text = sprintf("%s%s%s", pre_cursor, chr2str(char), post_cursor); + cursor += 1; + } + else if (char == 8) // backspace + { + if (cursor <= 0) return; + pre_cursor = substring(prev, 0, cursor - 1); + post_cursor = substring(prev, cursor, length); + cursor -= 1; + cursor = max(0, cursor); + text = strcat(pre_cursor, post_cursor); + } + else if (scan == K_DEL) + { + if (cursor >= length) return; + pre_cursor = substring(prev, 0, cursor); + post_cursor = substring(prev, cursor + 1, length); + text = strcat(pre_cursor, post_cursor); + } + else if (char == 13 || char == 27) // enter or escape + { + // Commit and deselect... + // Let's try a hack.. + _last_clicked_action_count = 0; + } + else if (scan == K_LEFTARROW) + { + cursor -= 1; + cursor = max(0, cursor); + } + else if (scan == K_RIGHTARROW) + { + cursor += 1; + cursor = min(strlen(prev), cursor); + } +}; + +void(float maxlen, __inout string text, __inout float cursor) sui_cap_input_length = +{ + if (strlen(text) > maxlen) + { + text = substring(text, 0, strlen(text)); + cursor = strlen(text); + } +}; + +void(string command) _sui_unbind = +{ + tokenize(findkeysforcommand(command)); + string keyname = keynumtostring(stof(argv(0))); + string altkeyname = keynumtostring(stof(argv(1))); + localcmd(sprintf("unbind %s\n", keyname)); + localcmd(sprintf("unbind %s\n", altkeyname)); +}; + +void(float scan, string command) _sui_do_keybind = +{ + if (scan == K_ESCAPE) + { + _sui_binding_command = ""; + _sui_binding_command_name = ""; + return; + } + if (scan == K_BACKSPACE) + { + _sui_unbind(command); + _sui_binding_command = ""; + _sui_binding_command_name = ""; + return; + } + string keyname = keynumtostring(scan); + _sui_unbind(command); + localcmd(sprintf("bind %s %s\n", keyname, command)); + _sui_binding_command = ""; + _sui_binding_command_name = ""; +}; + +void(string command, string command_name) sui_start_bind = +{ + _sui_binding_command = command; + _sui_binding_command_name = command_name; +}; + +// void(float evtype, float scanx, float chary, float devid) sui_input_event +// same args is CSQC_InputEvent. +// return value tells you if sui used the event or not, in case you want to +// not let engine handle it if it was used. +// Sets all the internal sui action stuff, call it in CSQC_InputEvent +float(float evtype, float scanx, float chary, float devid) sui_input_event = +{ + switch (evtype) + { + case IE_MOUSEABS: + _sui_mouse_move([scanx, chary]); + return TRUE; + break; + case IE_MOUSEDELTA: + // Big question mark... + // maybe make our own delta based sui_cursor here.. + // maybe just ignore delta and let user fake mouseabs with their own + // delta cursor by passing different params to this func...? + // for MVP let's just use mouseabs only + return FALSE; + break; + case IE_KEYDOWN: + if (_sui_binding_command != "") + { + // Nothing + return TRUE; + } + else if (scanx == K_MOUSE1) + { + _sui_mouse1_down(); + return TRUE; + } + else + { + if ((scanx == K_ESCAPE || scanx == K_BACKSPACE) && _sui_binding_command != "") + return TRUE; + else if (scanx == K_ESCAPE) + return FALSE; + return _sui_add_input(chary, scanx); + } + break; + case IE_KEYUP: + if (_sui_binding_command != "") + { + _sui_do_keybind(scanx, _sui_binding_command); + return TRUE; + } + else if (scanx == K_MOUSE1) + { + _sui_mouse1_up(); + return TRUE; + } + break; + default: + break; + } + + return FALSE; +}; + + +// void() sui_pre_draw +// Resets state for sui actions so that no trouble happens. +// Call it before your menu code per frame in your draw/updateview. +void(float width, float height) sui_begin = +{ + _action_elements_index = 0; + _sui_draw_initialized = TRUE; + + sui_reset_frame(); + sui_push_frame([0, 0], [width, height]); +} + +void() sui_draw_bind_overlay; + +// void() sui_end +// Call after your menu code per frame in your draw/updateview. +void() sui_end = +{ + // Todo: move overlay drawing elsewhere: + sui_draw_bind_overlay(); + // Dirty part: + _sui_draw_initialized = FALSE; + // reset "once" type actions + _click_action_count = 0; + _release_action_count = 0; + // empty input buffer + sui_clear_input(); +}; + + +// Different draw components: + +void(vector pos, vector size, vector color, float alpha, float flags) sui_fill = +{ + sui_transform_box(pos, size); + drawfill(pos, size, color, alpha, flags); +}; + +void(vector pos, vector size, string pic, vector color, float alpha, float flags) sui_pic = +{ + sui_transform_box(pos, size); + + drawpic(pos, pic, size, color, alpha, flags); +}; + +void(vector pos, vector size, float width, vector color, float alpha, float flags) sui_border_box = +{ + sui_transform_box(pos, size); + + // Top line + drawfill(pos, [size_x, width], color, alpha, flags); + // Bottom line + drawfill([pos_x, pos_y + size_y - width], [size_x, width], color, alpha, flags); + // Left line + drawfill([pos_x, pos_y + width], [width, size_y - width * 2], color, alpha, flags); + // Right line + drawfill([pos_x + size_x - width, pos_y + width], [width, size_y - width * 2], color, alpha, flags); +}; + + +void(vector pos, vector size, string text, vector color, float alpha, float flags) sui_text = +{ + sui_transform_box(pos, [stringwidth(text, 1, size), size_y]); + + drawstring(pos, text, size, color, alpha, flags); +}; + +void(float index, vector click_ratios) sui_noop = {}; + +void(float value) sui_slider_noop = {}; + +float(string id, vector pos, vector size, vector minmaxsteps, float value, void(float value) action) sui_slidercontrol = +{ + sui_action_element(pos, size, id, sui_noop); + float newvalue = value; + + sui_transform_box(pos, size); + // user is clicking and holding the slider + if (sui_is_held(id)) + { + float min = minmaxsteps[0]; + float max = minmaxsteps[1]; + float steps = minmaxsteps[2]; + float click_ratio = (_cursor_position_x - pos_x) / size_x; + click_ratio = bound(0, click_ratio, 1); + if (steps > 0) click_ratio = rint(click_ratio * steps) / steps; + newvalue = min + click_ratio * (max - min); + if (newvalue != value) action(newvalue); + } + return newvalue; +}; + +void(string id, vector pos, vector size, __inout string text, __inout float cursor) sui_text_input = +{ + sui_action_element(pos, size, id, sui_noop); + if (sui_is_clicked(id)) cursor = strlen(text); + if (sui_is_last_clicked(id)) + { + float char = 0; + float scan = 0; + while(sui_get_input(char, scan)) sui_handle_text_input(char, scan, text, cursor); + } +}; + + +void(string id, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scrollbar = +{ + vector maxoffset = contentsize - size; + maxoffset_x = max(0, maxoffset_x); + maxoffset_y = max(0, maxoffset_y); + sui_push_frame([0, 0], size); + float ofs; + float length; + vector barpos, barsize; + float scan = 0; + float char = 0; + string barname; + if (maxoffset_y > 0 && contentsize_y > 0) + { + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]); + sui_push_frame([0, 0], [scrollbar_widths_y, size_y]); + ofs = (offset_y / contentsize_y) * size_y; + length = (size_y / contentsize_y) * size_y; + barpos = [0, ofs]; + barsize = [scrollbar_widths_y, length]; + barname = strcat(id, "vbar"); + + if (sui_is_held(barname)) + { + vector anchor = barpos + _cursor_relative_click; + sui_transform_point(anchor); + float diff = _cursor_position_y - anchor_y; + offset_y += (diff * contentsize_y) / size_y; // * contentsize_y; // (size_y / contentsize_y); + } + + sui_fill(barpos, barsize, '0.1 0.1 0.1' * (1 - sui_is_hovered(barname)), 0.66, 0); + sui_action_element(barpos, barsize, barname, sui_noop); + sui_pop_frame(); + } + sui_pop_frame(); +}; + +void(string id, vector pos, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scroll_view_begin = +{ + // make space for scrollbars + sui_push_frame(pos, size - [scrollbar_widths_y, scrollbar_widths_x]); + sui_action_element([0, 0], size, id, sui_noop); + + if (sui_hover_index(id) > -1) + { + float scrollamount = 0; + float char = 0; + float scan = 0; + sui_reread_input(); + while (sui_get_input(char, scan)) + { + if (scan == K_MWHEELUP) scrollamount -= 20; + if (scan == K_MWHEELDOWN) scrollamount += 20; + } + offset_y += scrollamount; + } + + vector maxoffset = contentsize - size; + maxoffset_x = max(0, maxoffset_x); + maxoffset_y = max(0, maxoffset_y); + offset_x = bound(0, offset_x, maxoffset_x); + offset_y = bound(0, offset_y, maxoffset_y); + + sui_scrollbar(id, size, contentsize, offset, scrollbar_widths); + + offset_x = bound(0, offset_x, maxoffset_x); + offset_y = bound(0, offset_y, maxoffset_y); + + sui_clip_to_frame(); + + + sui_push_frame(-1 * offset, contentsize); +}; + +void() sui_scroll_view_end = +{ + sui_pop_frame(); + sui_reset_clip(); + sui_pop_frame(); +}; + +float _sui_list_item_height; +float _sui_list_first; +float _sui_list_last; +float _sui_list_pos; +int _sui_list_index; +void(string id, vector pos, vector size, vector itemsize, float numitems, __inout vector offset, vector scrollbar_widths) sui_list_view_begin = +{ + vector contentsize = [itemsize_x, itemsize_y * numitems]; + sui_scroll_view_begin(id, pos, size, contentsize, offset, scrollbar_widths); + + _sui_list_item_height = itemsize_y; + float hidden_above = floor(offset_y / itemsize_y); + _sui_list_first = max(0, hidden_above); // Index of first elem + _sui_list_last = min(_sui_list_first + rint(size_y / itemsize_y) + 1, numitems); + _sui_list_pos = hidden_above * itemsize_y; + _sui_list_index = _sui_list_first; +}; + +float(__inout vector pos) sui_list_item = +{ + if (_sui_list_index >= _sui_list_last) return -1; + pos = _sui_list_index * [0, _sui_list_item_height]; + _sui_list_index += 1; + return _sui_list_index - 1; +}; + +void() sui_list_view_end = +{ + sui_scroll_view_end(); +}; + +string(string id, vector pos, vector size, string name, string command) sui_binder = +{ + sui_action_element(pos, size, id, sui_noop); + if (sui_is_released(id)) + { + sui_start_bind(command, name); + } + + tokenize(findkeysforcommand(command)); + string keyname = keynumtostring(stof(argv(0))); + if (keyname == "01") keyname = "unbound"; + + return keyname; +}; + +void() sui_draw_bind_overlay = +{ + if (_sui_binding_command != "") + { + vector size = sui_current_frame_size(); + sui_fill([0, 0], size, '0 0 0', 0.5, 0); + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + float textsize = 16; + sui_text([0, -16], [textsize, textsize], "Press a key for", '1 1 1', 1, 0); + sui_text([0, 0], [textsize, textsize], sprintf("'%s'", _sui_binding_command_name), '1 1 1', 1, 0); + sui_text([0, 16], [textsize - 4, textsize - 4], "ESC to cancel, BACKSPACE to remove", '1 1 1', 1, 0); + } +}; + + +// -------------------- END OF SUI SYSTEM STUFF -------------------- \ No newline at end of file From f75f86ccc37ab3d9c71edadb4f5c02d94109368e Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 28 Jul 2019 15:39:38 +1000 Subject: [PATCH 0720/2474] moving panel etc working fine but still a little bit less flexible then what we want --- csqc/hud.qc | 49 +++++++++++++++++++++++++++------------------ csqc/hud_helpers.qc | 20 ++++++++++++++---- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 2352decc..c4c6c14e 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -4,6 +4,8 @@ void FO_Hud_Editor() { fo_hud_editor = FALSE; setcursormode(FALSE); + + // TODO - save file with new panel positions } else { @@ -11,7 +13,7 @@ void FO_Hud_Editor() setcursormode(TRUE); } } - +float firstrun; void FO_Hud_Editor_LoadSettings(float height) { fo_hud_editor = FALSE; @@ -19,40 +21,51 @@ void FO_Hud_Editor_LoadSettings(float height) // check struct, put defaults in float yoffset = height - 64; FO_Hud_FlagIcon HudFlagIcon; - HudFlagIcon.Position = [32, yoffset]; + HudFlagIcon.Position = [8, yoffset]; + firstrun = TRUE; + + // TODO - maybe implement these to allow for pivoting of items HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; HudSettings.FlagIcon = HudFlagIcon; - // check if file exists + // TODO - check if file exists - // if exists, load all data overwriting struct + // TODO - if exists, load all data overwriting struct } void Hud_Draw(float width, float height) { - vector pos = [0, 0]; + vector pos; + if (firstrun) + { + firstrun = FALSE; + pos = HudSettings.FlagIcon.Position; + pos_y = pos_y - 4 - 24 * 2; + HudSettings.FlagIcon.Position = pos; + } + vector fillsize = [width*.2, height*.2]; - if (hud_panel("flagiconpanel", HudSettings.FlagIcon.Position, fillsize)) + float alpha = 0; + if (hud_panel("flagiconpanel", HudSettings.FlagIcon.Position, fillsize, alpha)) { + // click event if (fo_hud_editor) { - print("clicky!\n"); - + } - } - float yoffset = height - 64; + pos = HudSettings.FlagIcon.Position; for (float i = FlagInfoLines.length - 1; i >= 0; i--) { if (FlagInfoLines[i].id) { string icon = "sb_key1"; vector iconcolour = '1 1 1'; - float alpha = 1; + alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; if (FlagInfoLines[i].model) { switch (FlagInfoLines[i].model.owned_by) { @@ -68,25 +81,21 @@ void Hud_Draw(float width, float height) break; } } - if (FlagInfoLines[i].state == FLAGINFO_HOME) - { - alpha = 0.3; - } - else if (FlagInfoLines[i].state == FLAGINFO_CARRIED) + if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([32, yoffset + 4 - 24 * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([8, yoffset - 4 - 24 * i, 0], icon, '24 24 0', iconcolour, alpha, 1); + drawpic([pos_x, pos_y - 24 * (i - 1), 0], icon, '24 24 0', iconcolour, alpha, 1); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([30 - stringwidth(stime, 1, '6 6'), yoffset + 14 - 24 * i, 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - 24 * (i - 1), 0], stime, '6 6', '1 1 1', 1, 0); } } } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index dbb333ff..72341bc4 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -49,8 +49,10 @@ vector UpdatePos(string id, vector mousepos) return pos; } -float(string id, vector pos, vector size) hud_panel = +float(string id, vector pos, vector size, float alpha) hud_panel = { + vector basecolor = MENU_BG; + if (fo_hud_editor) { if (sui_is_last_clicked(id)) @@ -69,12 +71,22 @@ float(string id, vector pos, vector size) hud_panel = HudSettings.MousePos = [0, 0]; } + if (sui_is_hovered(id)) + { + alpha = 0.6; + basecolor = MENU_BG + MENU_HIGHLIGHT * 0.1; + } + + if (sui_is_held(id)) + { + alpha = 0.6; + basecolor = MENU_BG - MENU_DARKEN * 0.1; + } } sui_push_frame(pos, size); - vector basecolor = sui_is_hovered(id) ? MENU_BG + MENU_HIGHLIGHT * 0.1 : MENU_BG; - basecolor = sui_is_held(id) ? MENU_BG - MENU_DARKEN * 0.1 : basecolor; - sui_fill([0, 0], size, basecolor, 0.6, 0); + + sui_fill([0, 0], size, basecolor, alpha, 0); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); sui_action_element([0, 0], size, id, sui_noop); From 56edd9adc54652f28761ad3f013e2c55ecdc8e68 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 28 Jul 2019 18:49:23 +1200 Subject: [PATCH 0721/2474] added info_empblock entity --- README.md | 1 + ssqc/engineer.qc | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c5a876d8..c10bf355 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. * Server option for duelmode to respawn with all grens `localinfo duel_all_grens 1`/`localinfo dag 1` * Server option to remove packs in duel mode `localinfo duel_no_packs 1`/`localinfo dnp 1` * Server setting for duelmode reset delay `localinfo drd 0.5` (`localinfo duel_reset_delay 0.5`) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 49c3d768..02b27fb1 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -156,9 +156,9 @@ void () EMPGrenadeTouch = { void () EMPGrenadeExplode = { local float expsize; - local entity te; + local entity te, te2; local entity oldself; - local float candamage; + local float candamage, empblockinrage; WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_TAREXPLOSION); @@ -167,11 +167,22 @@ void () EMPGrenadeExplode = { WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); + te2 = find(world, classname, "info_empblock"); + while(te2) { + //bprint(PRINT_HIGH, "Found EMP Block at ", vtos(te2.origin), " with radius ", ftos(te2.t_length), "\n"); + //bprint(PRINT_HIGH, "Block is ", ftos(vlen(te2.origin - self.origin)), " units away\n"); + if(vlen(te2.origin - self.origin) <= te2.t_length) { + empblockinrage = TRUE; + break; + } + te2 = find(te2, classname, "info_empblock"); + } + te = findradius(self.origin, 240); while (te) { te.chain2 = te.chain; candamage = TRUE; - if(walls_block_emp) + if(walls_block_emp || empblockinrage) candamage = CanDamage(te, self); traceline(self.origin, te.origin, MOVE_NOMONSTERS, self); if(trace_ent && trace_ent.spawnflags & SPAWNFLAG_BLOCK_EMP) { @@ -1294,3 +1305,7 @@ void (entity eng) Engineer_RemoveBuildings = { DestroyBuilding(eng, "building_sentrygun"); }; +void () info_empblock = { + self.weapon = 512; + self.netname = "EMP Block"; +}; From b3b1aef912c5b5405a87be0fa3b100cc1878932b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 28 Jul 2019 20:09:32 +1200 Subject: [PATCH 0722/2474] info_empblock now takes goal_effect 16 flag to make it optionally not go through walls --- README.md | 1 + ssqc/engineer.qc | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c10bf355..0cd3ce71 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* `info_empblock` has a new field `goal_effects`. Setting it to 16 will prevent it from blocking emps if there is a wall between it and the explosion. * New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. * Server option for duelmode to respawn with all grens `localinfo duel_all_grens 1`/`localinfo dag 1` * Server option to remove packs in duel mode `localinfo duel_no_packs 1`/`localinfo dnp 1` diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 02b27fb1..e7c43097 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -172,8 +172,17 @@ void () EMPGrenadeExplode = { //bprint(PRINT_HIGH, "Found EMP Block at ", vtos(te2.origin), " with radius ", ftos(te2.t_length), "\n"); //bprint(PRINT_HIGH, "Block is ", ftos(vlen(te2.origin - self.origin)), " units away\n"); if(vlen(te2.origin - self.origin) <= te2.t_length) { - empblockinrage = TRUE; - break; + if(te2.goal_effects & 16) { + traceline(self.origin, te2.origin, 0, self); + //bprint(PRINT_HIGH, "Block wall check is ", ftos(trace_fraction), "\n"); + if (trace_fraction == 1) { + empblockinrage = TRUE; + break; + } + } else { + empblockinrage = TRUE; + break; + } } te2 = find(te2, classname, "info_empblock"); } From b3d865ed343c6685bb3cf08df00fb19978632e28 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 28 Jul 2019 23:58:39 +1000 Subject: [PATCH 0723/2474] get panel drawing in correct place for 2 and 4 team games --- csqc/hud.qc | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index c4c6c14e..8a1186a6 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -39,15 +39,28 @@ void FO_Hud_Editor_LoadSettings(float height) void Hud_Draw(float width, float height) { vector pos; - if (firstrun) + + float flagInfoCount = 0; + for (float i = FlagInfoLines.length - 1; i >= 0; i--) { - firstrun = FALSE; - pos = HudSettings.FlagIcon.Position; - pos_y = pos_y - 4 - 24 * 2; - HudSettings.FlagIcon.Position = pos; + if (FlagInfoLines[i].id) + { + flagInfoCount++; + } } + + if (firstrun) + { + if (flagInfoCount > 0) + { + firstrun = FALSE; + pos = HudSettings.FlagIcon.Position; + pos_y = pos_y - 4 - 24 * (flagInfoCount - 2); + HudSettings.FlagIcon.Position = pos; + } + } - vector fillsize = [width*.2, height*.2]; + vector fillsize = [width*.2, 24 * flagInfoCount]; float alpha = 0; if (hud_panel("flagiconpanel", HudSettings.FlagIcon.Position, fillsize, alpha)) { @@ -83,19 +96,19 @@ void Hud_Draw(float width, float height) } if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - 24 * (i - 1), 0], icon, '24 24 0', iconcolour, alpha, 1); + drawpic([pos_x, pos_y - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], icon, '24 24 0', iconcolour, alpha, 1); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - 24 * (i - 1), 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } } From 54887e04155266a8cd378fc9f8ba866c8d4e5c80 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 1 Aug 2019 23:24:01 +1000 Subject: [PATCH 0724/2474] flag csqc becomes a moveable panel, start of a csqc hud config (loads/saves) --- csqc/csextradefs.qc | 15 ++++++++++++- csqc/csprogs.src | 5 ++++- csqc/hud.qc | 55 ++++++++++++++++++++++++++++++++++++++++----- csqc/hud_helpers.qc | 30 +++++++++++++++++++++++++ share/defs.h | 5 ++++- 5 files changed, 101 insertions(+), 9 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 12b18703..3c3b65b2 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -36,4 +36,17 @@ typedef struct { vector MousePos; } FO_Hud_Settings; -FO_Hud_Settings HudSettings; \ No newline at end of file +FO_Hud_Settings HudSettings; + +#pragma noref 1 +#pragma warning error Q101 /*too many parms*/ +#pragma warning error Q105 /*too few parms*/ +#pragma warning enable F301 /*non-utf-8 strings*/ +#pragma warning enable F302 /*uninitialised locals*/ +#pragma target FTE +#ifndef CSQC +#define CSQC +#endif + +string(string s) strtrim = #0:strtrim; /* + Trims the whitespace from the start+end of the string. */ \ No newline at end of file diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 49b164d5..2cff60e6 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,7 +1,10 @@ ../csprogs.dat csdefs.qc -../share/commondefs.qc csextradefs.qc +//fteextensions.qc +../share/commondefs.qc + + sui_sys.qc input.qc main.qc diff --git a/csqc/hud.qc b/csqc/hud.qc index 8a1186a6..5f91bc24 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -5,7 +5,7 @@ void FO_Hud_Editor() fo_hud_editor = FALSE; setcursormode(FALSE); - // TODO - save file with new panel positions + WriteHudCfg(FO_HUD_CONFIG_PATH); } else { @@ -13,6 +13,7 @@ void FO_Hud_Editor() setcursormode(TRUE); } } + float firstrun; void FO_Hud_Editor_LoadSettings(float height) { @@ -27,13 +28,55 @@ void FO_Hud_Editor_LoadSettings(float height) // TODO - maybe implement these to allow for pivoting of items HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; - HudSettings.FlagIcon = HudFlagIcon; - // TODO - check if file exists - - // TODO - if exists, load all data overwriting struct - + // fte does weird stuff and writes/reads this to/from a "gamedir/data/file" + float filehandle; + filehandle = fopen(FO_HUD_CONFIG_PATH, FILE_READ); + if (filehandle >= 0) { + // get number of lines + string ln; + ln = fgets(filehandle); + while (ln) + { + if (strlen(ln) > 0) + { + ln = strreplace("\n", "", ln); + string val, field; + + float count = tokenizebyseparator(ln, ":"); + field = argv(0); + field = strtrim(field); + val = argv(1); + val = strtrim(val); + + print(strcat("field: ", field, " val: ", val, "\n")); + + switch(field) + { + case "hudflagicon.position": + count = tokenizebyseparator(val, ","); + float x = stof(argv(0)); + float y = stof(argv(1)); + HudSettings.FlagIcon.Position = [x, y]; + break; + case "hudflagicon.growdirection": + HudSettings.FlagIcon.GrowDirection = stof(val); + break; + case "hudflagicon.nodeinsertloc": + HudSettings.FlagIcon.NodeInsertLoc = stof(val); + break; + } + } + ln = fgets(filehandle); + } + fclose(filehandle); + } + else + { + // write a new file + WriteHudCfg(FO_HUD_CONFIG_PATH); + } } void Hud_Draw(float width, float height) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 72341bc4..6014ce4e 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -94,3 +94,33 @@ float(string id, vector pos, vector size, float alpha) hud_panel = return sui_is_clicked(id); }; + + +string FormatHudCfgString(string line, string field, string value) +{ + line = strcat(line, "\n", field, ":", value); + + return line; +} + +string FormatHudCfgVector(string line, string field, vector value) +{ + line = strcat(line, "\n", field, ":", strcat(ftos(value_x), ",", ftos(value_y))); + + return line; +} + +void WriteHudCfg(string path) +{ + // this overwrites + float filehandle; + filehandle = fopen(path, FILE_WRITE); + string line; + + line = FormatHudCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); + line = FormatHudCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); + line = FormatHudCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); + + fputs(filehandle, line); + fclose(filehandle); +} \ No newline at end of file diff --git a/share/defs.h b/share/defs.h index 7be24847..5954bc5d 100644 --- a/share/defs.h +++ b/share/defs.h @@ -29,6 +29,7 @@ #define FL_ONGROUND 512 // standing on something #define FL_PARTIALGROUND 1024 // not all corners are valid #define FL_WATERJUMP 2048 // player jumping out of water + #define FL_JUMPRELEASED 4096 // for jump debouncing // edict.movetype values @@ -100,6 +101,7 @@ #define IT_HOOK 8388608 // point content values + #define CONTENT_EMPTY -1 #define CONTENT_SOLID -2 #define CONTENT_WATER -3 @@ -158,6 +160,7 @@ // sound channels // channel 0 never willingly overrides // other channels (1-7) allways override a playing sound on that channel + #define CHAN_AUTO 0 #define CHAN_WEAPON 1 #define CHAN_VOICE 2 @@ -1301,4 +1304,4 @@ #define FO_HUD_INSERT_AFTER 1 #define FO_HUD_INSERT_BEFORE 1 - +#define FO_HUD_CONFIG_PATH "fortressone_hud.focfg" From 4e519999c2c71777e42fc0da8bc4d34b15f291cd Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 1 Aug 2019 23:26:01 +1000 Subject: [PATCH 0725/2474] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 05e8d54b..1c8eaea5 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server v0.1.0 New features ------ +* CSQC - fo_hud_editor to move panels and save to config * Server option for duelmode to respawn with all grens `localinfo duel_all_grens 1`/`localinfo dag 1` * Server option to remove packs in duel mode `localinfo duel_no_packs 1`/`localinfo dnp 1` * Server setting for duelmode reset delay `localinfo drd 0.5` (`localinfo duel_reset_delay 0.5`) From 504004f1857c8f7d3e251da2d3d2cd4d2fe1b931 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 2 Aug 2019 10:33:32 +1000 Subject: [PATCH 0726/2474] enable auto bunnyhop on jump being held --- ssqc/client.qc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 069c5555..a95bbd49 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2972,6 +2972,13 @@ float () GetLastWeaponImpulse = { return 4; } + +void SV_RunClientCommand() +{ + self.pmove_flags &= ~1; + runstandardplayerphysics(self); +} + // this is to fix hack used to avoid fall damage, it currently breaks pm_airstep /* void() SV_RunClientCommand = { From f33cc55903b44e4a38141c6740245730325c7192 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 2 Aug 2019 11:18:11 +1000 Subject: [PATCH 0727/2474] fix spelling mistake in var, it's driving me crazy --- ssqc/engineer.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 4a8e56e2..9a5ea288 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -155,7 +155,7 @@ void () EMPGrenadeExplode = { local float expsize; local entity te, te2; local entity oldself; - local float candamage, empblockinrage; + local float candamage, empblockinrange; WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_TAREXPLOSION); @@ -173,11 +173,11 @@ void () EMPGrenadeExplode = { traceline(self.origin, te2.origin, 0, self); //bprint(PRINT_HIGH, "Block wall check is ", ftos(trace_fraction), "\n"); if (trace_fraction == 1) { - empblockinrage = TRUE; + empblockinrange = TRUE; break; } } else { - empblockinrage = TRUE; + empblockinrange = TRUE; break; } } @@ -188,7 +188,7 @@ void () EMPGrenadeExplode = { while (te) { te.chain2 = te.chain; candamage = TRUE; - if(walls_block_emp || empblockinrage) + if(walls_block_emp || empblockinrange) candamage = CanDamage(te, self); traceline(self.origin, te.origin, MOVE_NOMONSTERS, self); if(trace_ent && trace_ent.spawnflags & SPAWNFLAG_BLOCK_EMP) { From 9e79404774390947d04f04a67fbc473f8affa901 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 2 Aug 2019 15:00:09 +1000 Subject: [PATCH 0728/2474] implement hard coded damage values for emp, reduced emp range --- share/defs.h | 2 ++ ssqc/client.qc | 9 +++++++ ssqc/engineer.qc | 64 +++++++++++++++++++++++++++++++++++++++++++----- ssqc/qw.qc | 2 +- ssqc/tfort.qc | 4 +-- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/share/defs.h b/share/defs.h index 5954bc5d..b2787060 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1081,6 +1081,8 @@ #define PC_ENGINEER_GRENADE_MAX_1 4 #define PC_ENGINEER_GRENADE_MAX_2 4 #define PC_ENGINEER_TF_ITEMS 0 +#define PC_ENGINEER_GRENADE_TYPE_2_OLDRANGE 240 +#define PC_ENGINEER_GRENADE_TYPE_2_NEWRANGE 180 // normal grenade range // Class Details for CIVILIAN #define PC_CIVILIAN_SKIN 22 diff --git a/ssqc/client.qc b/ssqc/client.qc index a95bbd49..92326e32 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -603,6 +603,10 @@ void () DecodeLevelParms = { solid_detpack = CF_GetSetting("sdp", "solid_detpack", "0"); // All Walls Block EMP [0] walls_block_emp = CF_GetSetting("wbp", "walls_block_emp", "0"); + + // new emp range and set damage values (so no dropammo to reduce) + new_emp = CF_GetSetting("nemp", "new_emp", "1"); + // For duelmode, how soon to reset the winning player (allows for double KOs) duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "0"); // remove packs in duelmode [1] @@ -1119,6 +1123,11 @@ void () ResetPlayers = { float () CountRemainingTeams = { local float teamsleft, teamflags, playersleft; local entity te, lastplayer; + + lastplayer = world; + teamflags = 0; + playersleft = 0; + te = find(world, classname, "player"); while (te != world) { if(!te.has_disconnected && te.health > 0) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 9a5ea288..f448f7ee 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -156,6 +156,7 @@ void () EMPGrenadeExplode = { local entity te, te2; local entity oldself; local float candamage, empblockinrange; + empblockinrange = FALSE; WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_TAREXPLOSION); @@ -184,7 +185,17 @@ void () EMPGrenadeExplode = { te2 = find(te2, classname, "info_empblock"); } - te = findradius(self.origin, 240); + float emprange; + if (new_emp) + { + emprange = PC_ENGINEER_GRENADE_TYPE_2_NEWRANGE; + } + else + { + emprange = PC_ENGINEER_GRENADE_TYPE_2_OLDRANGE; + } + + te = findradius(self.origin, emprange); while (te) { te.chain2 = te.chain; candamage = TRUE; @@ -239,13 +250,54 @@ void () EMPGrenadeExplode = { ((teamplay & 16) && (te.team_no > 0) && (te.team_no == self.owner.team_no))) { expsize = 0; - expsize = expsize + te.ammo_shells * 0.75; - expsize = expsize + te.ammo_rockets * 0.75 * 2; - if (te.playerclass != PC_ENGINEER) { - expsize = expsize + te.ammo_cells * 0.75; + + if (new_emp) + { + // we assume player has discarded non-needed ammo for damage calcs + expsize = expsize + te.maxammo_shells * .75; + expsize = expsize + te.maxammo_rockets * .75 * 2; + expsize = expsize + te.maxammo_cells * 0.75; + + // remove discard ammo amount + switch (te.playerclass) + { + case PC_SCOUT: + expsize = expsize - te.maxammo_rockets * .75 * 2; + break; + case PC_MEDIC: + expsize = expsize - te.maxammo_rockets * .75 * 2; + if (!medicaura && old_medikit) { + expsize = expsize - te.maxammo_cells * .75; + } + break; + case PC_SNIPER: + case PC_SPY: + case PC_ENGINEER: + expsize = expsize - te.maxammo_rockets * .75 * 2; + expsize = expsize - te.maxammo_cells * .75; + break; + case PC_SOLDIER: + case PC_DEMOMAN: + expsize = expsize - te.maxammo_cells * .75; + break; + case PC_HVYWEAP: + expsize = expsize - te.maxammo_rockets * .75 * 2; + break; + default: + } + } + else + { + expsize = expsize + te.ammo_shells * 0.75; + expsize = expsize + te.ammo_rockets * 0.75 * 2; + if (te.playerclass != PC_ENGINEER) { + expsize = expsize + te.ammo_cells * 0.75; + } } + + if (expsize > 0) { - deathmsg = 30; + deathmsg = DMSG_GREN_EMP; T_RadiusDamage(te, self.owner, expsize, te); if (te.touch != BackpackTouch) { TF_T_Damage(te, self, self.owner, expsize, 2, 4); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 40bc320c..109bd0ac 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -544,7 +544,6 @@ float server_faithful; float old_spanner; float old_dispenser; -float old_emp_radius; float old_hp_armor; float ng_velocity; @@ -564,6 +563,7 @@ float chweap_wait_attfinished; float override_mapclasses; float solid_detpack; float walls_block_emp; +float new_emp; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 488bb4ff..b4df8ec1 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -777,7 +777,7 @@ void (float inp) TeamFortress_PrimeGrenade = { if (self.no_grenades_1 > 0) { self.has_throwngren = TRUE; self.no_grenades_1 = self.no_grenades_1 - 1; - if (gtype == 6) { + if (gtype == GR_TYPE_FLARE) { newmis = spawn(); newmis.owner = self; newmis.movetype = 6; @@ -841,7 +841,7 @@ void (float inp) TeamFortress_PrimeGrenade = { if (self.no_grenades_2 > 0) { self.has_throwngren = TRUE; self.no_grenades_2 = self.no_grenades_2 - 1; - if (gtype == 6) { + if (gtype == GR_TYPE_FLARE) { newmis = spawn(); newmis.owner = self; newmis.movetype = 6; From cbcf019f806ebe4562f2d25cbf82f28624cd88ca Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 2 Aug 2019 15:53:31 +1000 Subject: [PATCH 0729/2474] remove server side auto bhop --- ssqc/client.qc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 92326e32..ceefb34c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2981,13 +2981,6 @@ float () GetLastWeaponImpulse = { return 4; } - -void SV_RunClientCommand() -{ - self.pmove_flags &= ~1; - runstandardplayerphysics(self); -} - // this is to fix hack used to avoid fall damage, it currently breaks pm_airstep /* void() SV_RunClientCommand = { From bfe9b7685b83d0031445f4f9da602b026064cfb7 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 2 Aug 2019 15:53:52 +1000 Subject: [PATCH 0730/2474] enable csqc auto bhop command --- csqc/csextradefs.qc | 2 ++ csqc/main.qc | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3c3b65b2..d26844b0 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -2,6 +2,8 @@ .float owned_by; float fo_hud_editor; +float jumptime; +float fo_autohop; typedef struct { diff --git a/csqc/main.qc b/csqc/main.qc index 34c10b5f..659919bb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -6,6 +6,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); precache_model("progs/weapons/v_rock.mdl"); registercommand("fo_hud_editor"); + registercommand("fo_autohop"); vector vsize = (vector)getproperty(VF_SCREENVSIZE); @@ -43,10 +44,24 @@ void GetSelf() = { noref float(string cmd) CSQC_ConsoleCommand = { tokenize(cmd); + float val; switch(argv(0)) { case "fo_hud_editor": FO_Hud_Editor(); break; + case "fo_autohop": + val = stof(argv(1)); + if (val == 1) + { + fo_autohop = TRUE; + print("auto bunnyhop has been enabled\n"); + } + else if (val == 0) + { + fo_autohop = FALSE; + print("auto bunnyhop has been disabled\n"); + } + break; } return FALSE; }; @@ -70,6 +85,22 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; +noref void CSQC_Input_Frame() +{ + if (fo_autohop) + { + if (input_buttons&2) + { + // jump is held + if (jumptime <= time - .2) + { + input_buttons &= ~2; + jumptime = time; + } + } + } +} + void() CSQC_Parse_Event = { //print("CSQC_Parse_Event\n"); float msgtype = readbyte(); From 63c4eac345be21b26ee2bbcb702bd26ae8b7c9ad Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 10:21:36 +1000 Subject: [PATCH 0731/2474] track which players have csqc --- ssqc/client.qc | 4 +++- ssqc/qw.qc | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ceefb34c..78cf9f5c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2253,12 +2253,14 @@ void () PlayerPostThink = { } }; -void () ClientConnect = { +void (optional float csqcactive) ClientConnect = { local entity te; local string st; local float got_one; stuffcmd(self, "set fortressone 1\n"); + + self.hascsqc = csqcactive; bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 109bd0ac..05cdd23f 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -604,6 +604,7 @@ float intermission_exittime; .float max_grenades_2; .entity chain2; // allows for nesting of findradius (use in EMPGrenadeExplode) +.float hascsqc; //============================================================================ From 7b4098bea1a81d2d82f1fc28d7a593d7062fc280 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 10:31:33 +1000 Subject: [PATCH 0732/2474] if csqc is active, don't show flag info on sbar, just use the hud icons --- ssqc/status.qc | 141 ++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 30a19118..09546868 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -596,51 +596,44 @@ void (entity Player, float index, entity Item) InitClientFlagStatus = { } void (entity Player, entity Item) UpdateClientFlagStatus = { - //Check if client is running csqc - float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); - if(csqcactive) { - //bprint(PRINT_HIGH, "Player ", Player.netname, " is ", infokey(Player, INFOKEY_P_CSQCACTIVE), "\n"); - - msg_entity = Player; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_FLAGINFO); - WriteFloat(MSG_MULTICAST, Item.goal_no); - if (Item.goal_state == 1 && Item.owner != world) { - WriteFloat(MSG_MULTICAST, FLAGINFO_CARRIED); - if (Player == Item.owner) { - WriteString(MSG_MULTICAST, "YOU"); - } else { - WriteString(MSG_MULTICAST, Item.owner.netname); - } + msg_entity = Player; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAGINFO); + WriteFloat(MSG_MULTICAST, Item.goal_no); + if (Item.goal_state == 1 && Item.owner != world) { + WriteFloat(MSG_MULTICAST, FLAGINFO_CARRIED); + if (Player == Item.owner) { + WriteString(MSG_MULTICAST, "YOU"); } else { - if (Item.origin != Item.oldorigin) { - if((Item.nextthink - time) >= 0) { - WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); - if(Item.think != tfgoalitem_droptouch) { - WriteFloat(MSG_MULTICAST, rint(Item.bubble_count - time)); - if((Item.think == tfgoalitem_dropthink || Item.think == tfgoalitem_remove) && !Item.owner) { - WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); - WriteCoord(MSG_MULTICAST, Item.origin_x); - WriteCoord(MSG_MULTICAST, Item.origin_y); - WriteCoord(MSG_MULTICAST, Item.origin_z); - WriteString(MSG_MULTICAST, getLocationName(Item.origin)); - } else { - WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); - } + WriteString(MSG_MULTICAST, Item.owner.netname); + } + } else { + if (Item.origin != Item.oldorigin) { + if((Item.nextthink - time) >= 0) { + WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); + if(Item.think != tfgoalitem_droptouch) { + WriteFloat(MSG_MULTICAST, rint(Item.bubble_count - time)); + if((Item.think == tfgoalitem_dropthink || Item.think == tfgoalitem_remove) && !Item.owner) { + WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); + WriteCoord(MSG_MULTICAST, Item.origin_x); + WriteCoord(MSG_MULTICAST, Item.origin_y); + WriteCoord(MSG_MULTICAST, Item.origin_z); + WriteString(MSG_MULTICAST, getLocationName(Item.origin)); } else { - WriteFloat(MSG_MULTICAST, -1); WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); } } else { - WriteFloat(MSG_MULTICAST, FLAGINFO_RETURNING); + WriteFloat(MSG_MULTICAST, -1); + WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); } } else { - WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); + WriteFloat(MSG_MULTICAST, FLAGINFO_RETURNING); } + } else { + WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); } - multicast('0 0 0', MULTICAST_ONE); - //multicast('0 0 0', MULTICAST_ONE_R); } + multicast('0 0 0', MULTICAST_ONE); } float(entity playerent, float changedflags) SendClientFlagStatus = { @@ -651,50 +644,56 @@ float(entity playerent, float changedflags) SendClientFlagStatus = { } string (entity Player, entity Item, float teamno) GetItemStatus = { - local string st; - UpdateClientFlagStatus(Player, Item); - switch (teamno) - { - case 1: - st = "Blue Flag"; - break; - case 2: - st = "Red Flag"; - break; - case 3: - st = "Yellow Flag"; - break; - case 4: - st = "Green Flag"; - break; + local string st = ""; + + float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); + if(csqcactive) { + UpdateClientFlagStatus(Player, Item); } - if (Player.team_no == Item.owned_by) { - st = strcat(Q"\x10", st ,Q"\x11"); - //st = strcat("[", st ,"]"); - } - if (Item.goal_state == 1 && Item.owner != world) { - if (Player == Item.owner) { - st = strcat(st, Q"\s: Carried by \sYOU"); - } else { - st = strcat(st, Q"\s: Carried by \s", Item.owner.netname); + else + { + switch (teamno) + { + case 1: + st = "Blue Flag"; + break; + case 2: + st = "Red Flag"; + break; + case 3: + st = "Yellow Flag"; + break; + case 4: + st = "Green Flag"; + break; } - - } else { - if (Item.origin != Item.oldorigin) { - //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in - if((Item.nextthink - time) >= 0) { - if(Item.think != tfgoalitem_droptouch) { - st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); + if (Player.team_no == Item.owned_by) { + st = strcat(Q"\x10", st ,Q"\x11"); + } + if (Item.goal_state == 1 && Item.owner != world) { + if (Player == Item.owner) { + st = strcat(st, Q"\s: Carried by \sYOU"); + } else { + st = strcat(st, Q"\s: Carried by \s", Item.owner.netname); + } + } else { + if (Item.origin != Item.oldorigin) { + //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in + if((Item.nextthink - time) >= 0) { + if(Item.think != tfgoalitem_droptouch) { + st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); + } else { + st = strcat(st, Q"\s: Dropped\s"); + } } else { - st = strcat(st, Q"\s: Dropped\s"); + st = strcat(st, Q"\s: Returning\s NOW!"); } } else { - st = strcat(st, Q"\s: Returning\s NOW!"); + st = strcat(st, Q"\s: Safe\s"); } - } else { - st = strcat(st, Q"\s: Safe\s"); } } + return st; } From f4efa0485bcd787de8b41c15f028f48b5f52f32d Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 10:32:43 +1000 Subject: [PATCH 0733/2474] turns out we don't need to track csqc this way --- ssqc/client.qc | 1 - ssqc/qw.qc | 1 - 2 files changed, 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 78cf9f5c..28f0df1d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2260,7 +2260,6 @@ void (optional float csqcactive) ClientConnect = { stuffcmd(self, "set fortressone 1\n"); - self.hascsqc = csqcactive; bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 05cdd23f..109bd0ac 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -604,7 +604,6 @@ float intermission_exittime; .float max_grenades_2; .entity chain2; // allows for nesting of findradius (use in EMPGrenadeExplode) -.float hascsqc; //============================================================================ From c9a1e671278d8ff95dfc90b7dbf5250e35febabe Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 10:55:48 +1000 Subject: [PATCH 0734/2474] stop sending sb flaginfo for csqc clients, only send info for the hud icons --- ssqc/status.qc | 113 +++++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 46 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 09546868..fc00be2e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -645,55 +645,47 @@ float(entity playerent, float changedflags) SendClientFlagStatus = { string (entity Player, entity Item, float teamno) GetItemStatus = { local string st = ""; - - float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); - if(csqcactive) { - UpdateClientFlagStatus(Player, Item); - } - else + switch (teamno) { - switch (teamno) - { - case 1: - st = "Blue Flag"; - break; - case 2: - st = "Red Flag"; - break; - case 3: - st = "Yellow Flag"; - break; - case 4: - st = "Green Flag"; - break; - } - if (Player.team_no == Item.owned_by) { - st = strcat(Q"\x10", st ,Q"\x11"); - } - if (Item.goal_state == 1 && Item.owner != world) { - if (Player == Item.owner) { - st = strcat(st, Q"\s: Carried by \sYOU"); - } else { - st = strcat(st, Q"\s: Carried by \s", Item.owner.netname); - } + case 1: + st = "Blue Flag"; + break; + case 2: + st = "Red Flag"; + break; + case 3: + st = "Yellow Flag"; + break; + case 4: + st = "Green Flag"; + break; + } + if (Player.team_no == Item.owned_by) { + st = strcat(Q"\x10", st ,Q"\x11"); + } + if (Item.goal_state == 1 && Item.owner != world) { + if (Player == Item.owner) { + st = strcat(st, Q"\s: Carried by \sYOU"); } else { - if (Item.origin != Item.oldorigin) { - //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in - if((Item.nextthink - time) >= 0) { - if(Item.think != tfgoalitem_droptouch) { - st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); - } else { - st = strcat(st, Q"\s: Dropped\s"); - } + st = strcat(st, Q"\s: Carried by \s", Item.owner.netname); + } + } else { + if (Item.origin != Item.oldorigin) { + //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in + if((Item.nextthink - time) >= 0) { + if(Item.think != tfgoalitem_droptouch) { + st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); } else { - st = strcat(st, Q"\s: Returning\s NOW!"); + st = strcat(st, Q"\s: Dropped\s"); } } else { - st = strcat(st, Q"\s: Safe\s"); + st = strcat(st, Q"\s: Returning\s NOW!"); } + } else { + st = strcat(st, Q"\s: Safe\s"); } } - + return st; } @@ -745,9 +737,41 @@ void (entity pl) RefreshStatusBar = { } else { pl.display_tip = 0; tfdet = find(world, classname, "info_tfdetect"); - if (!tfdet || !sbflaginfostate) { + + float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); + // we get flag info from tfdetect + if (!tfdet || (!sbflaginfostate && !csqcactive)) + { ct = strzone("\n\n\n\n\n\n"); - } else { + } + else if (csqcactive) // has csqc + { + for (float t = 1; t <= number_of_teams; t++) + { + switch (t) + { + case 1: + te = Finditem(tfdet.display_item_status1); + break; + case 2: + te = Finditem(tfdet.display_item_status2); + break; + case 3: + te = Finditem(tfdet.display_item_status3); + break; + case 4: + te = Finditem(tfdet.display_item_status4); + break; + } + + if (te) + { + UpdateClientFlagStatus(pl, te); + } + } + } + else // no csqc but has sbflaginfo on + { ct = ""; i = number_of_teams; // Extra newlines for (float t = 1; t <= number_of_teams; t++) { @@ -804,13 +828,10 @@ void (entity pl) RefreshStatusBar = { } tg = find(tg, classname, "info_tfgoal"); } - for (float t = 0; t < (6 - i); t++) ct = strcat(ct, "\n"); - //ct = strcat(ct, "\n\n\n"); - ct = strzone(ct); } } From cda329c16b194a01acd0d3448e5c9cd593f3838b Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 11:04:20 +1000 Subject: [PATCH 0735/2474] autohop bug fix --- csqc/main.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 659919bb..c7e3156a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -92,10 +92,10 @@ noref void CSQC_Input_Frame() if (input_buttons&2) { // jump is held - if (jumptime <= time - .2) + if (jumptime <= time) { input_buttons &= ~2; - jumptime = time; + jumptime = time + .3; } } } From cc4c747f325a83e8aacc921bd2f2b89b55c435f7 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 11:30:33 +1000 Subject: [PATCH 0736/2474] spawn hwguy projectiles 10 units higher, even if this breaks the angle and he's no longer shooting straight --- ssqc/hwguy.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 2a6520d3..ed40a458 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -95,6 +95,7 @@ void FireAssCan (float shotcount, vector dir, vector spread) float bullet_speed, var_speed; makevectors(self.v_angle); + // Infront of player model and down towards gun bullet_speed = PC_HVYWEAP_PROJSPEED; bullet_dir = normalize(v_forward * bullet_speed); @@ -103,7 +104,7 @@ void FireAssCan (float shotcount, vector dir, vector spread) var_speed = crandom()*10 + bullet_speed; // Slight speed variance rand_dir = (crandom()*spread_x) * v_right + (crandom()*spread_y) * v_up; spread_dir = bullet_dir + rand_dir; - org = self.origin + rand_dir; + org = self.origin + '0 0 10' + rand_dir; LaunchAssCan(org, spread_dir, var_speed); From 26efbfc91e3cb8156916e932c29ec948d90728fb Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 21:12:45 +1000 Subject: [PATCH 0737/2474] move flag status bar to own function --- csqc/hud.qc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 5f91bc24..a2c93476 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -50,8 +50,6 @@ void FO_Hud_Editor_LoadSettings(float height) val = argv(1); val = strtrim(val); - print(strcat("field: ", field, " val: ", val, "\n")); - switch(field) { case "hudflagicon.position": @@ -79,7 +77,7 @@ void FO_Hud_Editor_LoadSettings(float height) } } -void Hud_Draw(float width, float height) +void Hud_DrawFlagStatusBar(float width) { vector pos; @@ -113,7 +111,7 @@ void Hud_Draw(float width, float height) } } - + pos = HudSettings.FlagIcon.Position; for (float i = FlagInfoLines.length - 1; i >= 0; i--) { @@ -155,4 +153,10 @@ void Hud_Draw(float width, float height) } } } +} + +void Hud_Draw(float width, float height) +{ + Hud_DrawFlagStatusBar(width); + } \ No newline at end of file From 96f9e6f0723816a2e91e52e07fa4dcd2e24be239 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 3 Aug 2019 23:30:18 +1000 Subject: [PATCH 0738/2474] fix death message defines, fix hwguy death messages not being set --- share/defs.h | 5 +++++ ssqc/client.qc | 24 ++++++++---------------- ssqc/combat.qc | 6 ++---- ssqc/engineer.qc | 2 +- ssqc/hwguy.qc | 2 ++ ssqc/player.qc | 2 +- ssqc/scout.qc | 2 +- ssqc/sentry.qc | 2 +- 8 files changed, 21 insertions(+), 24 deletions(-) diff --git a/share/defs.h b/share/defs.h index b2787060..8521ab0c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1246,6 +1246,11 @@ #define DMSG_SENTRYGUN_ROCKET 34 #define DMSG_GREN_FLASH 35 #define DMSG_TRIGGER 36 +#define DMSG_TEAMKILL 37 +#define DMSG_SENTRYGUN_EXPLODE 38 +#define DMSG_DISPENSER_EXPLODE 39 +#define DMSG_GREN_PIPE_AIR 40 +#define DMSG_GREN_CALTROP 41 /*======================================================*/ /* Menus */ diff --git a/ssqc/client.qc b/ssqc/client.qc index 28f0df1d..251f9d88 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2403,7 +2403,7 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage strcat(" was telefragged by ", strcat(pe_attacker.owner.netname, "\n"))); } - if (pf_deathmsg == 37) { + if (pf_deathmsg == DMSG_TEAMKILL) { return strcat(pe_attacker.netname, " shoots his teammate one too many times\n"); } if (pe_attacker.classname == "player" || pe_attacker.classname == "bot") { @@ -2429,9 +2429,7 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage s_deathstring = " stared at his grenade too long\n"; else s_deathstring = " grenades himself\n"; - return strcat(pe_target.netname, s_deathstring); - } else if (pf_deathmsg == DMSG_GREN_NAIL) { if (nailgren_type == NGR_TYPE_LASER) { return strcat(pe_target.netname, " electrocutes himself\n"); @@ -2439,29 +2437,23 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage return strcat(pe_target.netname, " hammers himself\n"); } } else if (pf_deathmsg == DMSG_GREN_MIRV) { - if (pe_target.playerclass == PC_DEMOMAN) s_deathstring = " practiced his own Mirv dance\n"; else if (pe_target.playerclass == PC_HVYWEAP) s_deathstring = " allowed his Mirv to turn against him\n"; else s_deathstring = " goes to pieces\n"; - return strcat(pe_target.netname, s_deathstring); - } else if (pf_deathmsg == DMSG_GREN_PIPE) { - return strcat(pe_target.netname, " ambushes himself with his own pipebombs\n"); - } - - else if (pf_deathmsg == 40) + else if (pf_deathmsg == DMSG_GREN_PIPE_AIR) s_deathstring = " tried to juggle his own pipebombs\n"; else if (pf_deathmsg == DMSG_GREN_GAS) s_deathstring = " chokes on his own gas\n"; else if (pf_deathmsg == DMSG_GREN_EMP) s_deathstring = " explodes his ammo and body\n"; - else if (pf_deathmsg == 41) + else if (pf_deathmsg == DMSG_GREN_CALTROP) s_deathstring = " stepped on too many of his own caltrops\n"; else if (pf_deathmsg == DMSG_GREN_FLASH) s_deathstring = " is charred by his own flash grenade\n"; @@ -2484,9 +2476,9 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage s_deathstring = " torches himself\n"; else if (pf_deathmsg == DMSG_LIGHTNING && pe_target.waterlevel > 1) s_deathstring = " discharges into the water\n"; - else if (pf_deathmsg == 38) + else if (pf_deathmsg == DMSG_SENTRYGUN_EXPLODE) s_deathstring = " gets too friendly with his sentry gun\n"; - else if (pf_deathmsg == 39) + else if (pf_deathmsg == DMSG_DISPENSER_EXPLODE) s_deathstring = " dispenses with himself\n"; return strcat(pe_target.netname, s_deathstring); @@ -2572,7 +2564,7 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage } else if (pf_deathmsg == DMSG_GREN_EMP) { s_deathstring = "'s ammo detonates him as "; s_deathstring2 = "'s EMP fries it\n"; - } else if (pf_deathmsg == 41) { + } else if (pf_deathmsg == DMSG_GREN_CALTROP) { s_deathstring = " stepped on too many of "; s_deathstring2 = "'s caltrops\n"; } else if (pf_deathmsg == DMSG_GREN_FLASH) { @@ -2756,10 +2748,10 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage } else if (pf_deathmsg == DMSG_INCENDIARY) { s_deathstring = " gets well done by "; s_deathstring2 = "'s incendiary rocket\n"; - } else if (pf_deathmsg == 38) { + } else if (pf_deathmsg == DMSG_SENTRYGUN_EXPLODE) { s_deathstring = " gets destroyed by "; s_deathstring2 = "'s exploding sentrygun\n"; - } else if (pf_deathmsg == 39) { + } else if (pf_deathmsg == DMSG_DISPENSER_EXPLODE) { s_deathstring = " didn't insert the correct change into "; s_deathstring2 = "'s dispenser.\n"; } diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 11c5f825..9227b786 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -529,10 +529,8 @@ void (entity targ, entity inflictor, entity attacker, float damage, else if (teamplay & TEAMPLAY_HALFDIRECT) take = take / 2; } - } - if (targ.playerclass == PC_SPY) { targ.attacked_by = attacker; targ.feignmsg = deathmsg; @@ -564,7 +562,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (T_AttackType & TF_TD_EXPLOSION) { - deathmsg = 37; + deathmsg = DMSG_TEAMKILL; if (teamplay & 16384) TF_T_Damage(attacker, world, world, take, 1, 0); else if (teamplay & 8192) @@ -572,7 +570,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, } else { - deathmsg = 37; + deathmsg = DMSG_TEAMKILL; if (teamplay & 4096) TF_T_Damage(attacker, world, world, take, 1, 0); else if (teamplay & 2048) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f448f7ee..d49cae80 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -941,7 +941,7 @@ void () Dispenser_Explode = { local float sdmg; if (self.real_owner.has_disconnected != 1) { - deathmsg = 39; + deathmsg = DMSG_DISPENSER_EXPLODE; sdmg = 25 + self.ammo_rockets * 3 + self.ammo_cells; if (sdmg > 250) { sdmg = 250; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index ed40a458..4ba35e36 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -13,6 +13,7 @@ void AssCanBulletTouch() if (other == self.owner) return; // Touching self, do nothing + deathmsg = self.weapon; if (other.health) { TF_T_Damage(other, self, self.owner, 8, TF_TD_NOTTEAM, @@ -76,6 +77,7 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) setmodel(newmis, newmis.mdl); // Diamond model newmis.frame = random()*15; // Full range of sizes newmis.skin = 16 + random()*7; // Bright colours + newmis.weapon = DMSG_ASSAULTCANNON; newmis.velocity = dir * proj_speed; // Constant speed multiplier newmis.angles = vectoangles(dir); // Create direction angle diff --git a/ssqc/player.qc b/ssqc/player.qc index bf5777e7..9ca8f593 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -702,7 +702,7 @@ void () player_axpain6 =[34, player_run] { void (entity et, float f) player_pain = { if (self.weaponframe) { - if (deathmsg == 37) + if (deathmsg == DMSG_TEAMKILL) PainSound(); return; } diff --git a/ssqc/scout.qc b/ssqc/scout.qc index cf6a9b6a..25b31a40 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -51,7 +51,7 @@ void () CaltropTouch = { sprint(other, PRINT_HIGH, "Ow, ow, ow! Caltrops!\n"); other.leg_damage = other.leg_damage + 2; TeamFortress_SetSpeed(other); - deathmsg = 41; + deathmsg = DMSG_GREN_CALTROP; T_Damage(other, self, self.owner, 10); dremove(self); }; diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index e85ed4aa..701c2745 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -238,7 +238,7 @@ void () Sentry_Explode = { ThrowGib("progs/tgib3.mdl", -70); if (self.real_owner.has_disconnected != 1) { - deathmsg = 38; + deathmsg = DMSG_SENTRYGUN_EXPLODE; T_RadiusDamage(self, self.real_owner, 75 + self.ammo_rockets * 8, self); } From ab56a21a9b3eb56ffa3b8a967e7691c8a71012bc Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 4 Aug 2019 11:48:10 +1000 Subject: [PATCH 0739/2474] up branch for sanity check - adding of clipsize to hud --- csqc/csextradefs.qc | 14 +++++++- csqc/csprogs.src | 1 + csqc/events.qc | 82 +++++++++++++++++++++++++++++++++++++++++++ csqc/hud.qc | 56 ++++++++++++++++++++++++------ csqc/hud_helpers.qc | 2 ++ csqc/main.qc | 84 ++------------------------------------------- share/commondefs.qc | 1 + ssqc/status.qc | 69 +++++++++++++++++++++++++++++++------ 8 files changed, 204 insertions(+), 105 deletions(-) create mode 100644 csqc/events.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d26844b0..4320ea9a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -4,6 +4,7 @@ float fo_hud_editor; float jumptime; float fo_autohop; +string ClipSizeMsg; typedef struct { @@ -27,6 +28,13 @@ typedef struct { FlagInfoLine FlagInfoLines[10]; +// hud stuff + +typedef struct { + vector Position; + float Scale; +} FO_Hud_ClipSize; + typedef struct { vector Position; float GrowDirection; @@ -35,11 +43,15 @@ typedef struct { typedef struct { FO_Hud_FlagIcon FlagIcon; + FO_Hud_ClipSize ClipSize; vector MousePos; } FO_Hud_Settings; - FO_Hud_Settings HudSettings; +#define HUD_FLAGICON_SIZE 24 +#define FO_HUD_CLIPSIZE_PANEL_X 50 +#define FO_HUD_CLIPSIZE_PANEL_Y 50 + #pragma noref 1 #pragma warning error Q101 /*too many parms*/ #pragma warning error Q105 /*too few parms*/ diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 2cff60e6..5746e4d0 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -8,5 +8,6 @@ csextradefs.qc sui_sys.qc input.qc main.qc +events.qc hud_helpers.qc hud.qc \ No newline at end of file diff --git a/csqc/events.qc b/csqc/events.qc new file mode 100644 index 00000000..17203f73 --- /dev/null +++ b/csqc/events.qc @@ -0,0 +1,82 @@ +void() CSQC_Parse_Event = { + float msgtype = readbyte(); + local float goalno; + switch (msgtype) { + case MSG_FLAGINFOINIT: + float index = readfloat(); + goalno = readfloat(); + string mdl = readstring(); + float skinindex = readfloat(); + float ownerteam = readfloat(); + if(index >= 0 && index < MAX_FLAGINFO_LINES) + { + FlagInfoLines[index].id = goalno; + FlagInfoLines[index].message = ""; + if(mdl) + precache_model(mdl); + entity te = spawn(); + te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; + te.origin = [5, 0, 0]; + te.angles = '-60 0 0'; + //setmodel(te,mdl); + setmodel(te, "progs/weapons/v_rock.mdl"); + setsize(te, '-16 -16 0', '16 16 8'); + te.skin = skinindex; + te.owned_by = ownerteam; + FlagInfoLines[index].model = te; + } + break; + case MSG_FLAGINFO: + string message = ""; + goalno = readfloat(); + float state = readfloat(); + float timeleft = -1; + vector droploc = '0 0 0'; + string carrier = ""; + string locname = ""; + switch (state) { + case FLAGINFO_HOME: + message = "^2HOME"; + break; + case FLAGINFO_CARRIED: + carrier = readstring(); + message = strcat("^1CARRIED^7 by ",carrier); + break; + case FLAGINFO_DROPPED: + message = "^3DROPPED^7"; + timeleft = readfloat(); + float showloc = readfloat(); + if(showloc == FLAGINFO_LOCATION) { + droploc_x = readcoord(); + droploc_y = readcoord(); + droploc_z = readcoord(); + locname = readstring(); + message = strcat(message," at ", locname); + } + break; + case FLAGINFO_RETURNING: + message = "^4RETURNING"; + break; + } + for(float i = 0; i < FlagInfoLines.length; i++) { + if(FlagInfoLines[i].id == goalno) { + FlagInfoLines[i].message = message; + FlagInfoLines[i].timeleft = timeleft; + FlagInfoLines[i].state = state; + FlagInfoLines[i].loc = droploc; + FlagInfoLines[i].carrier = carrier; + FlagInfoLines[i].locname = locname; + } + } + break; + case MSG_CLIPSIZE: + print("reading clipsize\n"); + string test; + test = readstring(); + + ClipSizeMsg = test; + break; + default: + print("CSQC_Parse_Event, unknown event: ",ftos(msgtype),"\n"); + } +} \ No newline at end of file diff --git a/csqc/hud.qc b/csqc/hud.qc index a2c93476..bb75de2d 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,3 +1,5 @@ +// TODO - reset to defaults command +// TODO - implement scale on elements void FO_Hud_Editor() { if (fo_hud_editor) @@ -15,7 +17,7 @@ void FO_Hud_Editor() } float firstrun; -void FO_Hud_Editor_LoadSettings(float height) +void FO_Hud_Editor_LoadSettings(float width, float height) { fo_hud_editor = FALSE; HudSettings.MousePos = [0, 0]; @@ -28,8 +30,14 @@ void FO_Hud_Editor_LoadSettings(float height) // TODO - maybe implement these to allow for pivoting of items HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; + HudSettings.FlagIcon = HudFlagIcon; + FO_Hud_ClipSize HudClipSize; + HudClipSize.Position = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; + HudClipSize.Scale = 1; + HudSettings.ClipSize = HudClipSize; + // fte does weird stuff and writes/reads this to/from a "gamedir/data/file" float filehandle; filehandle = fopen(FO_HUD_CONFIG_PATH, FILE_READ); @@ -44,6 +52,7 @@ void FO_Hud_Editor_LoadSettings(float height) ln = strreplace("\n", "", ln); string val, field; + float x = 0, y = 0; float count = tokenizebyseparator(ln, ":"); field = argv(0); field = strtrim(field); @@ -54,8 +63,8 @@ void FO_Hud_Editor_LoadSettings(float height) { case "hudflagicon.position": count = tokenizebyseparator(val, ","); - float x = stof(argv(0)); - float y = stof(argv(1)); + x = stof(argv(0)); + y = stof(argv(1)); HudSettings.FlagIcon.Position = [x, y]; break; case "hudflagicon.growdirection": @@ -64,6 +73,14 @@ void FO_Hud_Editor_LoadSettings(float height) case "hudflagicon.nodeinsertloc": HudSettings.FlagIcon.NodeInsertLoc = stof(val); break; + case "hudclipsize.position": + count = tokenizebyseparator(val, ","); + x = stof(argv(0)); + y = stof(argv(1)); + HudSettings.ClipSize.Position = [x, y]; + break; + case "hudclipsize.scale": + break; } } ln = fgets(filehandle); @@ -100,10 +117,10 @@ void Hud_DrawFlagStatusBar(float width) HudSettings.FlagIcon.Position = pos; } } - + pos = HudSettings.FlagIcon.Position; vector fillsize = [width*.2, 24 * flagInfoCount]; float alpha = 0; - if (hud_panel("flagiconpanel", HudSettings.FlagIcon.Position, fillsize, alpha)) + if (hud_panel("flagiconpanel", pos, fillsize, alpha)) { // click event if (fo_hud_editor) @@ -112,7 +129,6 @@ void Hud_DrawFlagStatusBar(float width) } } - pos = HudSettings.FlagIcon.Position; for (float i = FlagInfoLines.length - 1; i >= 0; i--) { if (FlagInfoLines[i].id) @@ -137,26 +153,44 @@ void Hud_DrawFlagStatusBar(float width) } if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + HUD_FLAGICON_SIZE, pos_y + 4 - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + HUD_FLAGICON_SIZE, pos_y + 4 - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], icon, '24 24 0', iconcolour, alpha, 1); + drawpic([pos_x, pos_y - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], icon, [HUD_FLAGICON_SIZE, HUD_FLAGICON_SIZE, 0], iconcolour, alpha, 1); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } } } +void Hud_DrawClipSize(float width) +{ + vector pos = HudSettings.ClipSize.Position; + vector fillsize = [FO_HUD_CLIPSIZE_PANEL_X, FO_HUD_CLIPSIZE_PANEL_Y]; + float alpha = 0; + + if (hud_panel("clipsizepanel", pos, fillsize, alpha)) + { + // click event + if (fo_hud_editor) + { + + } + } + + drawstring([pos_x + 2, pos_y + 2, 0], ClipSizeMsg, '8 8', '1 1 1', 1, 0); +} + void Hud_Draw(float width, float height) { Hud_DrawFlagStatusBar(width); - + Hud_DrawClipSize(width); } \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 6014ce4e..5ab7c3a2 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -120,6 +120,8 @@ void WriteHudCfg(string path) line = FormatHudCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); line = FormatHudCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); line = FormatHudCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); + line = FormatHudCfgVector(line, "hudclipsize.position", HudSettings.ClipSize.Position); + line = FormatHudCfgString(line, "hudclipsize.scale", ftos(HudSettings.ClipSize.Scale)); fputs(filehandle, line); fclose(filehandle); diff --git a/csqc/main.qc b/csqc/main.qc index c7e3156a..28e232ec 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -1,6 +1,6 @@ void FO_Hud_Editor(); void Hud_Draw(float width, float height); -void FO_Hud_Editor_LoadSettings(float height); +void FO_Hud_Editor_LoadSettings(float width, float height); noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); @@ -10,7 +10,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vector vsize = (vector)getproperty(VF_SCREENVSIZE); - FO_Hud_Editor_LoadSettings(vsize_y); + FO_Hud_Editor_LoadSettings(vsize_x, vsize_y); }; noref void() CSQC_WorldLoaded = { @@ -101,84 +101,4 @@ noref void CSQC_Input_Frame() } } -void() CSQC_Parse_Event = { - //print("CSQC_Parse_Event\n"); - float msgtype = readbyte(); - local float goalno; - switch (msgtype) { - case MSG_FLAGINFOINIT: - float index = readfloat(); - goalno = readfloat(); - string mdl = readstring(); - float skinindex = readfloat(); - float ownerteam = readfloat(); - if(index >= 0 && index < MAX_FLAGINFO_LINES) { - FlagInfoLines[index].id = goalno; - FlagInfoLines[index].message = ""; - if(mdl) - precache_model(mdl); - entity te = spawn(); - te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; - te.origin = [5, 0, 0]; - te.angles = '-60 0 0'; - //setmodel(te,mdl); - setmodel(te, "progs/weapons/v_rock.mdl"); - setsize(te, '-16 -16 0', '16 16 8'); - te.skin = skinindex; - te.owned_by = ownerteam; - FlagInfoLines[index].model = te; - } - break; - case MSG_FLAGINFO: - string message = ""; - goalno = readfloat(); - float state = readfloat(); - float timeleft = -1; - vector droploc = '0 0 0'; - string carrier = ""; - string locname = ""; - switch (state) { - case FLAGINFO_HOME: - message = "^2HOME"; - break; - case FLAGINFO_CARRIED: - carrier = readstring(); - message = strcat("^1CARRIED^7 by ",carrier); - break; - case FLAGINFO_DROPPED: - message = "^3DROPPED^7"; - timeleft = readfloat(); - float showloc = readfloat(); - if(showloc == FLAGINFO_LOCATION) { - droploc_x = readcoord(); - droploc_y = readcoord(); - droploc_z = readcoord(); - //message = strcat(message," at ", vtos(droploc)); - locname = readstring(); - message = strcat(message," at ", locname); - } - //if(timeleft >= 0) { - //message = strcat(message," returning in ", ftos(timeleft)); - //} - break; - case FLAGINFO_RETURNING: - message = "^4RETURNING"; - break; - } - for(float i = 0; i < FlagInfoLines.length; i++) { - if(FlagInfoLines[i].id == goalno) { - FlagInfoLines[i].message = message; - FlagInfoLines[i].timeleft = timeleft; - FlagInfoLines[i].state = state; - FlagInfoLines[i].loc = droploc; - FlagInfoLines[i].carrier = carrier; - FlagInfoLines[i].locname = locname; - } - } - //print("CSQC_Parse_Event, Flag info: ", readstring(), "\n"); - break; - default: - print("CSQC_Parse_Event, unknown event: ",ftos(msgtype),"\n"); - } -} diff --git a/share/commondefs.qc b/share/commondefs.qc index 6490dba8..9cebd87f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -2,6 +2,7 @@ #define MSG_FLAGINFOINIT 1 #define MSG_FLAGINFO 2 +#define MSG_CLIPSIZE 2 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/status.qc b/ssqc/status.qc index fc00be2e..65a13878 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -7,7 +7,7 @@ string(float num) BlueScoreToString; string(float num) RedScoreToString; string(float num) YellowScoreToString; string(float num) GreenScoreToString; -string(entity pl) ClipSizeToString; +string(entity pl, float csqcactive) ClipSizeToString; float(entity pl) GetClipSize; string(entity pl) SniperPowerToString; string(entity pl) DetpackToString; @@ -689,6 +689,36 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { return st; } +void UpdateClientClipStatus(entity pl) +{ + string msg = "0"; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIPSIZE); + + if (pl.tfstate & TFSTATE_RELOADING) + { + if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { + msg = strcat(ftos(25 * pl.reload_sniper_ticks), "%"); + } else { + if (reload_cliptick) + msg = ftos(pl.reload_clipsize); + else + msg = "0"; + msg = strcat(msg, "/"); + msg = strcat(msg, ftos(GetClipSize(pl))); + } + } + else + { + msg = ClipSizeToString(pl, TRUE); + } + + WriteString(MSG_MULTICAST, msg); + multicast('0 0 0', MULTICAST_ONE); +} + void (entity pl) RefreshStatusBar = { local string pad; local string s1; // will be used for grenade timers @@ -731,6 +761,8 @@ void (entity pl) RefreshStatusBar = { pad = strcat(pad, "\n"); pad = strzone(pad); + float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); + // class tip if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2) { ct = CF_GetRandomClassTip(pl.playerclass); @@ -738,7 +770,6 @@ void (entity pl) RefreshStatusBar = { pl.display_tip = 0; tfdet = find(world, classname, "info_tfdetect"); - float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); // we get flag info from tfdetect if (!tfdet || (!sbflaginfostate && !csqcactive)) { @@ -898,7 +929,12 @@ void (entity pl) RefreshStatusBar = { st2 = ""; // status line 3 column 2 - clip size - if (pl.tfstate & TFSTATE_RELOADING) { + if (csqcactive) + { + UpdateClientClipStatus(pl); + } + else if (pl.tfstate & TFSTATE_RELOADING) + { st2 = Q"\sClip\s: "; if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { st2 = strcat(st2, strpadl(ftos(25 * pl.reload_sniper_ticks), 3)); @@ -911,8 +947,10 @@ void (entity pl) RefreshStatusBar = { st2 = strcat(st2, "/"); st2 = strcat(st2, strpadr(ftos(GetClipSize(pl)), 3)); } - } else { - st2 = ClipSizeToString(pl); + } + else + { + st2 = ClipSizeToString(pl, FALSE); } // status line 3 column 3 - grenade 1 count @@ -980,9 +1018,9 @@ string(float num) GreenScoreToString = return strcat(Q"\sGren\s:", strpadl(ftos(floor(num)), 3)); }; -string(entity pl) ClipSizeToString = +string(entity pl, float csqcactive) ClipSizeToString = { - local string st; + local string st = ""; local float num, max; max = GetClipSize(pl); @@ -1021,10 +1059,19 @@ string(entity pl) ClipSizeToString = if (num > 999) num = 999; - st = Q"\sClip\s: "; - st = strcat(st, strpadl(ftos(floor(num)), 2)); - st = strcat(st, "/"); - st = strcat(st, strpadr(ftos(max), 3)); + if (csqcactive) + { + st = strcat(ftos(floor(num)), "/", ftos(max)); + } + else + { + st = Q"\sClip\s: "; + st = strcat(st, strpadl(ftos(floor(num)), 2)); + st = strcat(st, "/"); + st = strcat(st, strpadr(ftos(max), 3)); + } + + return st; }; From d543d55c299a48e8f94091e087b58419a5b803c0 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 4 Aug 2019 15:53:11 +1000 Subject: [PATCH 0740/2474] minimal implementation of clipsize panel --- csqc/csextradefs.qc | 3 ++- csqc/events.qc | 1 - csqc/hud.qc | 16 +++++++++------- csqc/hud_helpers.qc | 13 +++++++------ share/commondefs.qc | 2 +- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 4320ea9a..e83c478b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -48,7 +48,8 @@ typedef struct { } FO_Hud_Settings; FO_Hud_Settings HudSettings; -#define HUD_FLAGICON_SIZE 24 +#define HUD_FLAGICON_SIZE_X 24 +#define HUD_FLAGICON_SIZE_Y 24 #define FO_HUD_CLIPSIZE_PANEL_X 50 #define FO_HUD_CLIPSIZE_PANEL_Y 50 diff --git a/csqc/events.qc b/csqc/events.qc index 17203f73..a45fef48 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -70,7 +70,6 @@ void() CSQC_Parse_Event = { } break; case MSG_CLIPSIZE: - print("reading clipsize\n"); string test; test = readstring(); diff --git a/csqc/hud.qc b/csqc/hud.qc index bb75de2d..51f100fe 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -113,12 +113,12 @@ void Hud_DrawFlagStatusBar(float width) { firstrun = FALSE; pos = HudSettings.FlagIcon.Position; - pos_y = pos_y - 4 - 24 * (flagInfoCount - 2); + pos_y = pos_y - 4 - HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2); HudSettings.FlagIcon.Position = pos; } } pos = HudSettings.FlagIcon.Position; - vector fillsize = [width*.2, 24 * flagInfoCount]; + vector fillsize = [HUD_FLAGICON_SIZE_X * 4, HUD_FLAGICON_SIZE_Y * flagInfoCount]; float alpha = 0; if (hud_panel("flagiconpanel", pos, fillsize, alpha)) { @@ -153,19 +153,19 @@ void Hud_DrawFlagStatusBar(float width) } if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + HUD_FLAGICON_SIZE, pos_y + 4 - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + HUD_FLAGICON_SIZE_X, pos_y + 4 - HUD_FLAGICON_SIZE_Y * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + HUD_FLAGICON_SIZE, pos_y + 4 - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + HUD_FLAGICON_SIZE_X, pos_y + 4 - HUD_FLAGICON_SIZE_Y * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], icon, [HUD_FLAGICON_SIZE, HUD_FLAGICON_SIZE, 0], iconcolour, alpha, 1); + drawpic([pos_x, pos_y - HUD_FLAGICON_SIZE_X * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], icon, [HUD_FLAGICON_SIZE_X, HUD_FLAGICON_SIZE_Y, 0], iconcolour, alpha, 1); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - HUD_FLAGICON_SIZE * (i - 1) + HUD_FLAGICON_SIZE * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - HUD_FLAGICON_SIZE_Y * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } } @@ -186,11 +186,13 @@ void Hud_DrawClipSize(float width) } } - drawstring([pos_x + 2, pos_y + 2, 0], ClipSizeMsg, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + 2, pos_y + 2, 0], ClipSizeMsg, '20 20', '1 1 1', 1, 0); } void Hud_Draw(float width, float height) { Hud_DrawFlagStatusBar(width); Hud_DrawClipSize(width); + + HudSettings.MousePos = [Mouse.x, Mouse.y]; } \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 5ab7c3a2..ad07d784 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -41,8 +41,13 @@ vector UpdatePos(string id, vector mousepos) pos = HudSettings.FlagIcon.Position + mousepos - HudSettings.MousePos; HudSettings.FlagIcon.Position = pos; } - HudSettings.MousePos = mousepos; - + break; + case "clipsizepanel": + if (HudSettings.MousePos != [0, 0]) + { + pos = HudSettings.ClipSize.Position + mousepos - HudSettings.MousePos; + HudSettings.ClipSize.Position = pos; + } break; } @@ -66,10 +71,6 @@ float(string id, vector pos, vector size, float alpha) hud_panel = pos = UpdatePos(id, pos); sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); } - else - { - HudSettings.MousePos = [0, 0]; - } if (sui_is_hovered(id)) { diff --git a/share/commondefs.qc b/share/commondefs.qc index 9cebd87f..257862f1 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -2,7 +2,7 @@ #define MSG_FLAGINFOINIT 1 #define MSG_FLAGINFO 2 -#define MSG_CLIPSIZE 2 +#define MSG_CLIPSIZE 3 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 From 34a93f45181bc30d8783208a72ba8a84b0687f5e Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 4 Aug 2019 16:05:29 +1000 Subject: [PATCH 0741/2474] add in hud reload and reset to defaults --- csqc/csextradefs.qc | 1 + csqc/hud.qc | 26 ++++++++++++++++++++------ csqc/main.qc | 15 +++++++++++---- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e83c478b..687c1c9d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -39,6 +39,7 @@ typedef struct { vector Position; float GrowDirection; float NodeInsertLoc; + float Scale; } FO_Hud_FlagIcon; typedef struct { diff --git a/csqc/hud.qc b/csqc/hud.qc index 51f100fe..189cca90 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -16,27 +16,41 @@ void FO_Hud_Editor() } } -float firstrun; -void FO_Hud_Editor_LoadSettings(float width, float height) +void FO_Hud_Editor_LoadDefaultSettings() { - fo_hud_editor = FALSE; - HudSettings.MousePos = [0, 0]; + vector vsize = (vector)getproperty(VF_SCREENVSIZE); + float width = vsize_x; + float height = vsize_y; + // check struct, put defaults in float yoffset = height - 64; FO_Hud_FlagIcon HudFlagIcon; HudFlagIcon.Position = [8, yoffset]; - firstrun = TRUE; // TODO - maybe implement these to allow for pivoting of items HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; - + HudFlagIcon.Scale = 1; HudSettings.FlagIcon = HudFlagIcon; FO_Hud_ClipSize HudClipSize; HudClipSize.Position = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; HudClipSize.Scale = 1; HudSettings.ClipSize = HudClipSize; +} + +float firstrun; +void FO_Hud_Editor_LoadSettings() +{ + vector vsize = (vector)getproperty(VF_SCREENVSIZE); + float width = vsize_x; + float height = vsize_y; + fo_hud_editor = FALSE; + + FO_Hud_Editor_LoadDefaultSettings(); + + HudSettings.MousePos = [0, 0]; + firstrun = TRUE; // fte does weird stuff and writes/reads this to/from a "gamedir/data/file" float filehandle; diff --git a/csqc/main.qc b/csqc/main.qc index 28e232ec..01dbc789 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -1,16 +1,17 @@ void FO_Hud_Editor(); void Hud_Draw(float width, float height); -void FO_Hud_Editor_LoadSettings(float width, float height); +void FO_Hud_Editor_LoadSettings(); +void FO_Hud_Editor_LoadDefaultSettings(); noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); precache_model("progs/weapons/v_rock.mdl"); registercommand("fo_hud_editor"); + registercommand("fo_hud_reload"); + registercommand("fo_hud_reset"); registercommand("fo_autohop"); - - vector vsize = (vector)getproperty(VF_SCREENVSIZE); - FO_Hud_Editor_LoadSettings(vsize_x, vsize_y); + FO_Hud_Editor_LoadSettings(); }; noref void() CSQC_WorldLoaded = { @@ -49,6 +50,12 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_hud_editor": FO_Hud_Editor(); break; + case "fo_hud_reload": + FO_Hud_Editor_LoadSettings(); + break; + case "fo_hud_reset": + FO_Hud_Editor_LoadDefaultSettings(); + break; case "fo_autohop": val = stof(argv(1)); if (val == 1) From 9a83b3e72f4cdec5814cfa00c7c7cc939b9954d2 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 4 Aug 2019 20:48:27 +1200 Subject: [PATCH 0742/2474] Team Duelmode; fix ready message; fix all compile warnings --- ssqc/clan.qc | 2 +- ssqc/client.qc | 9 ++++++--- ssqc/defs.qc | 30 +++++++++++++++--------------- ssqc/menu.qc | 4 ++-- ssqc/monsters.qc | 4 ++-- ssqc/player.qc | 17 ++++++++++++----- ssqc/progs.src | 4 +++- 7 files changed, 41 insertions(+), 29 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 16ac6f69..e84d070a 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -849,7 +849,7 @@ float () CheckAllPlayersReady = { return 0; f1 = TeamFortress_GetNoPlayers (); - bprint (PRINT_HIGH, "Checking readiness - ",ftos(v_ready),"/",ftos(f1),".\n"); + bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); if (v_ready == f1 ) { if(cease_fire) { bprint (2, "All players ready, match will start after ceasefire ends.\n"); diff --git a/ssqc/client.qc b/ssqc/client.qc index ceefb34c..7721bf9a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1113,6 +1113,7 @@ void () ResetPlayers = { RemovePlayerOwnedEnts(); setspawnparms(self); PutClientInServer(); + self.respawn_time = 0; self = oldself; } @@ -1193,7 +1194,8 @@ void () ClientKill = { self.suicide_time = time + 5 + random() * 5; if (self.clientkillfree == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { - TeamFortress_SetupRespawn(FALSE); + if(!duelmode) + TeamFortress_SetupRespawn(FALSE); } else { bprint(PRINT_MEDIUM, self.netname, " suicides\n"); @@ -1211,7 +1213,8 @@ void () ClientKill = { logfrag(self, self); TF_AddFrags(self, -1); - TeamFortress_SetupRespawn(TRUE); + if(!duelmode) + TeamFortress_SetupRespawn(TRUE); self.th_die(); } @@ -2253,7 +2256,7 @@ void () PlayerPostThink = { } }; -void () ClientConnect = { +void (optional float csqcactive) ClientConnect = { local entity te; local string st; local float got_one; diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 614b96a9..a4012a5a 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -61,7 +61,7 @@ void () PlayerPreThink; // Called every frame before physics are run void () PlayerPostThink; // Called every frame after physics are run void () ClientKill; // Player entered the suicide command -void () ClientConnect; // called when a player connects to a server +//void () ClientConnect; // called when a player connects to a server void () PutClientInServer; // call after setting the parm1... parms void () ClientDisconnect; // called when a player disconnects from a server @@ -316,12 +316,12 @@ void (entity e, vector min, vector max) setsize = #4; // #5 was removed // #6 was removed (was: break) float () random = #7; // returns 0 - 1 -void (entity e, float chan, string samp, float vol, float atten) sound = #8; +//void (entity e, float chan, string samp, float vol, float atten) sound = #8; vector(vector v) normalize = #9; void (string e) error = #10; void (string e) objerror = #11; float (vector v) vlen = #12; -float (vector v) vectoyaw = #13; +//float (vector v) vectoyaw = #13; entity()spawn = #14; void (entity e) remove = #15; @@ -337,12 +337,12 @@ entity(entity start,.string fld, string match) find = #18; string(string s) precache_sound = #19; string(string s) precache_model = #20; void (entity client, string s) stuffcmd = #21; -entity(vector org, float rad) findradius = #22; -void (...) bprint = #23; +//entity(vector org, float rad) findradius = #22; +//void (...) bprint = #23; void (...) bprint2 = #23; void (...) bprint3 = #23; void (...) bprint4 = #23; -void (...) sprint = #24; +//void (...) sprint = #24; void (...) sprint2 = #24; void (...) sprint3 = #24; //void (...) dprint = #25; @@ -352,10 +352,10 @@ void () coredump = #28; // prints all edicts void () traceon = #29; // turns statment trace on void () traceoff = #30; void (entity e) eprint = #31; // prints an entire edict -float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE +//float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE // #33 was removed float () droptofloor = #34; // TRUE if landed on floor -void (float style, string value) lightstyle = #35; +//void (float style, string value) lightstyle = #35; float (float v) rint = #36; // round to nearest int float (float v) floor = #37; // largest integer <= v float (float v) ceil = #38; // smallest integer >= v @@ -372,7 +372,7 @@ void (vector o, vector d, float color, float count) particle = #48; void () ChangeYaw = #49; // turn towards self.ideal_yaw // at self.yaw_speed // #50 was removed -vector(vector v) vectoangles = #51; +//vector(vector v) vectoangles = #51; // // direct client message generation @@ -392,13 +392,13 @@ void (float step) movetogoal = #67; string(string s) precache_file = #68; // no effect except for -copy void (entity e) makestatic = #69; -void (string s) changelevel = #70; +//void (string s) changelevel = #70; //#71 was removed void (string var, string val) cvar_set = #72; // sets cvar.value -void (...) centerprint = #73; // sprint, but in middle +//void (...) centerprint = #73; // sprint, but in middle void (vector pos, string samp, float vol, float atten) ambientsound = #74; @@ -416,7 +416,7 @@ float (string s) stof = #81; // convert string to float void (vector where, float set) multicast = #82; // sends the temp message to a set // of clients, possibly in PVS or PHS -void(string str) tokenize = #84; // tokenize text +//void(string str) tokenize = #84; // tokenize text float() argc = #85; // returns number of tokens string(float num) argv_mvdsv = #86; // returns token for the given number @@ -426,10 +426,10 @@ float (float min, float value, float max) bound = #96; float (float x, float y) pow = #97; float (string s) strlen = #114; -string (string s1, string s2) strcat = #115; +//string (string s1, string s2) strcat = #115; string (string s, float start, float count) substr = #116; string (string s, ...) strzone = #118; -void (string s, ...) strunzone = #119; +//void (string s, ...) strunzone = #119; void() calltimeofday = #231; // force server to call mod function timeofday @@ -464,4 +464,4 @@ float (entity e, float healamount, float ignore) T_Heal; // health functi float (entity targ, entity inflictor) CanDamage; // enable qw in fteextensions -#define QUAKEWORLD \ No newline at end of file +#define QUAKEWORLD diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 64d3d02f..6b68c357 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1445,7 +1445,7 @@ void (float inp) Menu_Admin_Input = else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) && inp >= 1 && inp <= 7) { // Kick / Ban Actions - bprint(PRINT_HIGH, "Getting player ", ftos(inp), "\n"); + //bprint(PRINT_HIGH, "Getting player ", ftos(inp), "\n"); f_tmp = 1; self.admin_use = find (world, classname, "player"); while (self.admin_use != world) { @@ -1468,7 +1468,7 @@ void (float inp) Menu_Admin_Input = } } if (self.admin_use) { - bprint(PRINT_HIGH, "Player found: ", ftos(f_tmp), ", ", ftos(((self.current_menu_page - 1) * 7) + inp),", ", self.admin_use.classname , "\n"); + //bprint(PRINT_HIGH, "Player found: ", ftos(f_tmp), ", ", ftos(((self.current_menu_page - 1) * 7) + inp),", ", self.admin_use.classname , "\n"); if (f_tmp == ((self.current_menu_page - 1) * 7) + inp) { if(self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) { Admin_ForceSpectator(); diff --git a/ssqc/monsters.qc b/ssqc/monsters.qc index 0cbafdd1..e871395e 100644 --- a/ssqc/monsters.qc +++ b/ssqc/monsters.qc @@ -111,7 +111,7 @@ void () t_movetarget = { } }; - +/* float (float v) anglemod = { while (v >= 360) v = v - 360; @@ -119,7 +119,7 @@ float (float v) anglemod = { v = v + 360; return (v); }; - +*/ float (entity targ) range = { local vector spot1; local vector spot2; diff --git a/ssqc/player.qc b/ssqc/player.qc index bf5777e7..8115000b 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -892,15 +892,19 @@ void () GibPlayer = { } else { self.deadflag = 2; } - TeamFortress_SetupRespawn(0); + if(!duelmode) { + TeamFortress_SetupRespawn(0); + } else { + self.respawn_time = 9999; + } if (damage_attacker.classname == "teledeath") { sound(self, 2, "player/teledth1.wav", 1, 0); - self.respawn_time = (self.respawn_time + 2) + (random() * 2); + if(!duelmode) self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; } if (damage_attacker.classname == "teledeath2") { sound(self, 2, "player/teledth1.wav", 1, 0); - self.respawn_time = (self.respawn_time + 2) + (random() * 2); + if(!duelmode) self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; } if (random() < 0.5) { @@ -955,7 +959,8 @@ void () PlayerDie = { self.angles_z = 0; if (self.current_weapon <= 16) { player_die_ax1(); - TeamFortress_SetupRespawn(0); + if(!duelmode) + TeamFortress_SetupRespawn(0); return; } i = 1 + floor(random() * 6); @@ -970,7 +975,9 @@ void () PlayerDie = { else player_diee1(); - TeamFortress_SetupRespawn(0); + self.respawn_time = 9999; + if(!duelmode) + TeamFortress_SetupRespawn(0); }; void () set_suicide_frame = { diff --git a/ssqc/progs.src b/ssqc/progs.src index 6d8ce7a9..7e376fcd 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -1,6 +1,8 @@ ../qwprogs.dat -defs.qc + +#define QWSSQC ../share/fteextensions.qc +defs.qc ../share/commondefs.qc qw.qc q3defs.qc From feca216138be08c6308469843a6190fae69dfb27 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 4 Aug 2019 20:56:47 +1200 Subject: [PATCH 0743/2474] team duelmode is much simpler like this... --- ssqc/client.qc | 6 ++---- ssqc/commands.qc | 2 +- ssqc/player.qc | 17 +++++------------ 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 7721bf9a..8311068b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1194,8 +1194,7 @@ void () ClientKill = { self.suicide_time = time + 5 + random() * 5; if (self.clientkillfree == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { - if(!duelmode) - TeamFortress_SetupRespawn(FALSE); + TeamFortress_SetupRespawn(FALSE); } else { bprint(PRINT_MEDIUM, self.netname, " suicides\n"); @@ -1213,8 +1212,7 @@ void () ClientKill = { logfrag(self, self); TF_AddFrags(self, -1); - if(!duelmode) - TeamFortress_SetupRespawn(TRUE); + TeamFortress_SetupRespawn(TRUE); self.th_die(); } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 19a1d969..e8980d5f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -273,7 +273,7 @@ void () DuelMode = localcmd ("localinfo duelmode on\n"); localcmd ("localinfo sf on\n"); // spawnfull, ie spawn fully stocked localcmd ("localinfo drd 3.9\n"); // wait before resetting the winner long enough for grens to go off - localcmd ("localinfo rd 3.9\n"); // wait before respawning the loser + localcmd ("localinfo rd 9999\n"); // wait before respawning the loser localcmd ("password none\n"); localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); diff --git a/ssqc/player.qc b/ssqc/player.qc index 8115000b..bf5777e7 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -892,19 +892,15 @@ void () GibPlayer = { } else { self.deadflag = 2; } - if(!duelmode) { - TeamFortress_SetupRespawn(0); - } else { - self.respawn_time = 9999; - } + TeamFortress_SetupRespawn(0); if (damage_attacker.classname == "teledeath") { sound(self, 2, "player/teledth1.wav", 1, 0); - if(!duelmode) self.respawn_time = (self.respawn_time + 2) + (random() * 2); + self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; } if (damage_attacker.classname == "teledeath2") { sound(self, 2, "player/teledth1.wav", 1, 0); - if(!duelmode) self.respawn_time = (self.respawn_time + 2) + (random() * 2); + self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; } if (random() < 0.5) { @@ -959,8 +955,7 @@ void () PlayerDie = { self.angles_z = 0; if (self.current_weapon <= 16) { player_die_ax1(); - if(!duelmode) - TeamFortress_SetupRespawn(0); + TeamFortress_SetupRespawn(0); return; } i = 1 + floor(random() * 6); @@ -975,9 +970,7 @@ void () PlayerDie = { else player_diee1(); - self.respawn_time = 9999; - if(!duelmode) - TeamFortress_SetupRespawn(0); + TeamFortress_SetupRespawn(0); }; void () set_suicide_frame = { From 723f41dc48bb4a7e3d5e08c6a7cc60397e57fbde Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 4 Aug 2019 21:58:58 +1200 Subject: [PATCH 0744/2474] Reset the round when only one team left because of someone disconnecting --- ssqc/client.qc | 13 +++++++++++-- ssqc/combat.qc | 40 +++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ecd811b7..4a9a3371 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1098,10 +1098,16 @@ void () RemovePlayerOwnedEnts = { } void () ResetPlayers = { + local entity te, oldself, reset_timer; no_fire_mode = 0; + reset_timer = find(world, classname, "duel_reset_timer"); + while (reset_timer != world) { + oldself = reset_timer; + reset_timer = find (reset_timer, classname, "duel_reset_timer"); + dremove(oldself); + } if(cb_prematch) return; - local entity te, oldself; te = find(world, classname, "player"); while (te != world) { if(!te.has_disconnected) { @@ -1224,7 +1230,7 @@ void () ClientKill = { self.takedamage = 0; if(duelmode) { if(CountRemainingTeams() < 2) { - ResetPlayers(); + ResetPlayersWithCountdown(); } } }; @@ -2367,7 +2373,10 @@ void () ClientDisconnect = { if (!playersleft) { bprint(PRINT_HIGH, "Match \sabandoned\s, resetting to prematch\n"); InitPrematch(); + } else if(CountRemainingTeams() < 2) { + ResetPlayersWithCountdown(); } + } set_suicide_frame(); self.netname = string_null; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 9227b786..ed9edb8b 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -68,10 +68,28 @@ void () ResetPlayersDelayed = { } }; +void () ResetPlayersWithCountdown = { + local entity reset_timer; + local float remainder; + no_fire_mode = 1; + if(duel_reset_delay) { + reset_timer = find(world, classname, "duel_reset_timer"); + if(!reset_timer) { + remainder = duel_reset_delay % 1; + duel_reset_timer = duel_reset_delay - remainder; + reset_timer = spawn(); + reset_timer.classname = "duel_reset_timer"; + reset_timer.nextthink = time + remainder; + reset_timer.think = ResetPlayersDelayed; + } + } else { + ResetPlayers(); + } + +} void (entity targ, entity attacker) Killed = { - local entity oself, reset_timer; - local float remainder; + local entity oself; if (attacker == world && (targ.classname == "building_dispenser" || targ.classname == "building_sentrygun")) attacker = targ; @@ -110,27 +128,11 @@ void (entity targ, entity attacker) Killed = { //Already in no fire mode - implies you're not the first to die if(no_fire_mode) { if(CountRemainingTeams() == 0) { - reset_timer = find(world, classname, "duel_reset_timer"); - while (reset_timer != world) { - oself = reset_timer; - reset_timer = find (reset_timer, classname, "duel_reset_timer"); - dremove(oself); - } ResetPlayers(); } } else { if(CountRemainingTeams() < 2) { - no_fire_mode = 1; - if(duel_reset_delay) { - remainder = duel_reset_delay % 1; - duel_reset_timer = duel_reset_delay - remainder; - reset_timer = spawn(); - reset_timer.classname = "duel_reset_timer"; - reset_timer.nextthink = time + remainder; - reset_timer.think = ResetPlayersDelayed; - } else { - ResetPlayers(); - } + ResetPlayersWithCountdown(); } } } From 849071fa85fdcda487a4ae83927ce5ae2b1b7fbe Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 4 Aug 2019 21:06:36 +1000 Subject: [PATCH 0745/2474] rename and initial drawvalue helper for clip --- csqc/hud.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 189cca90..5f22fbc0 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -7,7 +7,7 @@ void FO_Hud_Editor() fo_hud_editor = FALSE; setcursormode(FALSE); - WriteHudCfg(FO_HUD_CONFIG_PATH); + Hud_WriteCfg(FO_HUD_CONFIG_PATH); } else { @@ -104,7 +104,7 @@ void FO_Hud_Editor_LoadSettings() else { // write a new file - WriteHudCfg(FO_HUD_CONFIG_PATH); + Hud_WriteCfg(FO_HUD_CONFIG_PATH); } } From 133580187959639bbfd42b8d456ef44be6d38e29 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 4 Aug 2019 21:06:43 +1000 Subject: [PATCH 0746/2474] helper --- csqc/hud_helpers.qc | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index ad07d784..2e50bfec 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -96,6 +96,31 @@ float(string id, vector pos, vector size, float alpha) hud_panel = return sui_is_clicked(id); }; +void(vector pos, float value, float threshhold, float size) Hud_DrawLargeValue = { + float c; + float len, i; + string s; + if (!size) size = 24; + vector vsize = [size, size, 0]; + if (value < 0) + value = 0; //hrm + s = ftos(floor(value)); + len = strlen(s); + i = 0; + if (value <= threshhold) { //use alternate (red) numbers + while(i Date: Sun, 4 Aug 2019 21:48:10 +1000 Subject: [PATCH 0747/2474] clipsize panel now has scaling enabled --- csqc/csextradefs.qc | 2 +- csqc/hud.qc | 5 +++-- csqc/hud_helpers.qc | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 687c1c9d..9712621e 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -51,7 +51,7 @@ FO_Hud_Settings HudSettings; #define HUD_FLAGICON_SIZE_X 24 #define HUD_FLAGICON_SIZE_Y 24 -#define FO_HUD_CLIPSIZE_PANEL_X 50 +#define FO_HUD_CLIPSIZE_PANEL_X 125 #define FO_HUD_CLIPSIZE_PANEL_Y 50 #pragma noref 1 diff --git a/csqc/hud.qc b/csqc/hud.qc index 5f22fbc0..00b5ed41 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -94,6 +94,7 @@ void FO_Hud_Editor_LoadSettings() HudSettings.ClipSize.Position = [x, y]; break; case "hudclipsize.scale": + HudSettings.ClipSize.Scale = stof(val); break; } } @@ -188,7 +189,7 @@ void Hud_DrawFlagStatusBar(float width) void Hud_DrawClipSize(float width) { vector pos = HudSettings.ClipSize.Position; - vector fillsize = [FO_HUD_CLIPSIZE_PANEL_X, FO_HUD_CLIPSIZE_PANEL_Y]; + vector fillsize = [FO_HUD_CLIPSIZE_PANEL_X * HudSettings.ClipSize.Scale, FO_HUD_CLIPSIZE_PANEL_Y * HudSettings.ClipSize.Scale]; float alpha = 0; if (hud_panel("clipsizepanel", pos, fillsize, alpha)) @@ -200,7 +201,7 @@ void Hud_DrawClipSize(float width) } } - drawstring([pos_x + 2, pos_y + 2, 0], ClipSizeMsg, '20 20', '1 1 1', 1, 0); + Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], ClipSizeMsg, 24 * HudSettings.ClipSize.Scale); } void Hud_Draw(float width, float height) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 2e50bfec..6ef5c251 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -96,7 +96,9 @@ float(string id, vector pos, vector size, float alpha) hud_panel = return sui_is_clicked(id); }; -void(vector pos, float value, float threshhold, float size) Hud_DrawLargeValue = { +// this draws backwards, haven't bothered to change as we don't use it +void Hud_DrawLargeValue(vector pos, float value, float threshhold, float size) +{ float c; float len, i; string s; @@ -120,7 +122,33 @@ void(vector pos, float value, float threshhold, float size) Hud_DrawLargeValue = drawpic(pos - [i * size, 0, 0], sprintf("num_%g", c-'0'), vsize, '1 1 1', 1, 0); } } -}; +} + +void Hud_DrawStringLMP(vector pos, string value, float size) +{ + float c; + float len, i; + string s; + if (!size) size = 24; + vector vsize = [size, size, 0]; + s = value; + len = strlen(s); + i = 0; + + while(i Date: Sun, 4 Aug 2019 21:54:37 +1000 Subject: [PATCH 0748/2474] add scaling for hud flag icon --- csqc/hud.qc | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 00b5ed41..3cfbb6aa 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -81,6 +81,9 @@ void FO_Hud_Editor_LoadSettings() y = stof(argv(1)); HudSettings.FlagIcon.Position = [x, y]; break; + case "hudflagicon.scale": + HudSettings.FlagIcon.Scale = stof(val); + break; case "hudflagicon.growdirection": HudSettings.FlagIcon.GrowDirection = stof(val); break; @@ -112,6 +115,10 @@ void FO_Hud_Editor_LoadSettings() void Hud_DrawFlagStatusBar(float width) { vector pos; + pos = HudSettings.FlagIcon.Position; + float sizey, sizex; + sizey = HUD_FLAGICON_SIZE_Y * HudSettings.FlagIcon.Scale; + sizex = HUD_FLAGICON_SIZE_X * HudSettings.FlagIcon.Scale; float flagInfoCount = 0; for (float i = FlagInfoLines.length - 1; i >= 0; i--) @@ -121,19 +128,18 @@ void Hud_DrawFlagStatusBar(float width) flagInfoCount++; } } - + if (firstrun) { if (flagInfoCount > 0) { firstrun = FALSE; - pos = HudSettings.FlagIcon.Position; - pos_y = pos_y - 4 - HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2); + pos_y = pos_y - 4 - sizey * (flagInfoCount - 2); HudSettings.FlagIcon.Position = pos; } - } - pos = HudSettings.FlagIcon.Position; - vector fillsize = [HUD_FLAGICON_SIZE_X * 4, HUD_FLAGICON_SIZE_Y * flagInfoCount]; + } + + vector fillsize = [sizex * 4, sizey * flagInfoCount]; float alpha = 0; if (hud_panel("flagiconpanel", pos, fillsize, alpha)) { @@ -168,19 +174,19 @@ void Hud_DrawFlagStatusBar(float width) } if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + HUD_FLAGICON_SIZE_X, pos_y + 4 - HUD_FLAGICON_SIZE_Y * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + HUD_FLAGICON_SIZE_X, pos_y + 4 - HUD_FLAGICON_SIZE_Y * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - HUD_FLAGICON_SIZE_X * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], icon, [HUD_FLAGICON_SIZE_X, HUD_FLAGICON_SIZE_Y, 0], iconcolour, alpha, 1); + drawpic([pos_x, pos_y - sizex * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 1); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - HUD_FLAGICON_SIZE_Y * (i - 1) + HUD_FLAGICON_SIZE_Y * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } } From 066e04e482c679bf1104f966cfe5230adeddc3db Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 4 Aug 2019 22:10:26 +1000 Subject: [PATCH 0749/2474] rename to .cfg file for hud --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 8521ab0c..564efd01 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1311,4 +1311,4 @@ #define FO_HUD_INSERT_AFTER 1 #define FO_HUD_INSERT_BEFORE 1 -#define FO_HUD_CONFIG_PATH "fortressone_hud.focfg" +#define FO_HUD_CONFIG_PATH "fortressone_hud.cfg" From 72cfeb9f39e368933fd1aa0607581340914a3a3d Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 4 Aug 2019 22:41:17 +1000 Subject: [PATCH 0750/2474] load/save csqc settings (autohop etc) --- csqc/csextradefs.qc | 6 ++++- csqc/csprogs.src | 6 ++--- csqc/hud_helpers.qc | 16 ++++++------ csqc/main.qc | 12 ++++++--- csqc/settings.qc | 59 +++++++++++++++++++++++++++++++++++++++++++++ share/defs.h | 1 + 6 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 csqc/settings.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9712621e..1e589a59 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -3,7 +3,6 @@ .float owned_by; float fo_hud_editor; float jumptime; -float fo_autohop; string ClipSizeMsg; typedef struct @@ -49,6 +48,11 @@ typedef struct { } FO_Hud_Settings; FO_Hud_Settings HudSettings; +typedef struct { + float Autohop; +} FO_Settings; +FO_Settings Settings; + #define HUD_FLAGICON_SIZE_X 24 #define HUD_FLAGICON_SIZE_Y 24 #define FO_HUD_CLIPSIZE_PANEL_X 125 diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 5746e4d0..855f0396 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,13 +1,11 @@ ../csprogs.dat csdefs.qc csextradefs.qc -//fteextensions.qc ../share/commondefs.qc - - sui_sys.qc input.qc main.qc events.qc hud_helpers.qc -hud.qc \ No newline at end of file +hud.qc +settings.qc \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 6ef5c251..1ebe2059 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -150,14 +150,14 @@ void Hud_DrawStringLMP(vector pos, string value, float size) } } -string FormatHudCfgString(string line, string field, string value) +string FormatCfgString(string line, string field, string value) { line = strcat(line, "\n", field, ":", value); return line; } -string FormatHudCfgVector(string line, string field, vector value) +string FormatCfgVector(string line, string field, vector value) { line = strcat(line, "\n", field, ":", strcat(ftos(value_x), ",", ftos(value_y))); @@ -171,12 +171,12 @@ void Hud_WriteCfg(string path) filehandle = fopen(path, FILE_WRITE); string line; - line = FormatHudCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); - line = FormatHudCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); - line = FormatHudCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); - line = FormatHudCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); - line = FormatHudCfgVector(line, "hudclipsize.position", HudSettings.ClipSize.Position); - line = FormatHudCfgString(line, "hudclipsize.scale", ftos(HudSettings.ClipSize.Scale)); + line = FormatCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); + line = FormatCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); + line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); + line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); + line = FormatCfgVector(line, "hudclipsize.position", HudSettings.ClipSize.Position); + line = FormatCfgString(line, "hudclipsize.scale", ftos(HudSettings.ClipSize.Scale)); fputs(filehandle, line); fclose(filehandle); diff --git a/csqc/main.qc b/csqc/main.qc index 01dbc789..8282e5e7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -2,6 +2,8 @@ void FO_Hud_Editor(); void Hud_Draw(float width, float height); void FO_Hud_Editor_LoadSettings(); void FO_Hud_Editor_LoadDefaultSettings(); +void FO_LoadSettings(); +void FO_WriteSettings(); noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); @@ -12,6 +14,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_autohop"); FO_Hud_Editor_LoadSettings(); + FO_LoadSettings(); }; noref void() CSQC_WorldLoaded = { @@ -60,14 +63,15 @@ noref float(string cmd) CSQC_ConsoleCommand = { val = stof(argv(1)); if (val == 1) { - fo_autohop = TRUE; + Settings.Autohop = 1; print("auto bunnyhop has been enabled\n"); } else if (val == 0) { - fo_autohop = FALSE; + Settings.Autohop = 0; print("auto bunnyhop has been disabled\n"); - } + } + FO_WriteSettings(); break; } return FALSE; @@ -94,7 +98,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { - if (fo_autohop) + if (Settings.Autohop == 1) { if (input_buttons&2) { diff --git a/csqc/settings.qc b/csqc/settings.qc new file mode 100644 index 00000000..9006cd02 --- /dev/null +++ b/csqc/settings.qc @@ -0,0 +1,59 @@ +void FO_WriteSettings() +{ + // this overwrites + float filehandle; + filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); + string line; + + line = FormatCfgString(line, "fo_autohop", ftos(Settings.Autohop)); + + fputs(filehandle, line); + fclose(filehandle); +} + +void FO_LoadDefaultSettings() +{ + Settings.Autohop = 0; +} + +void FO_LoadSettings() +{ + FO_LoadDefaultSettings(); + + float filehandle; + filehandle = fopen(FO_CONFIG_PATH, FILE_READ); + if (filehandle >= 0) { + // get number of lines + string ln; + ln = fgets(filehandle); + while (ln) + { + if (strlen(ln) > 0) + { + ln = strreplace("\n", "", ln); + string val, field; + + float x = 0, y = 0; + float count = tokenizebyseparator(ln, ":"); + field = argv(0); + field = strtrim(field); + val = argv(1); + val = strtrim(val); + + switch(field) + { + case "fo_autohop": + Settings.Autohop = stof(val); + break; + } + } + ln = fgets(filehandle); + } + fclose(filehandle); + } + else + { + // write a new file + FO_WriteSettings(); + } +} \ No newline at end of file diff --git a/share/defs.h b/share/defs.h index 564efd01..e86fc876 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1312,3 +1312,4 @@ #define FO_HUD_INSERT_AFTER 1 #define FO_HUD_INSERT_BEFORE 1 #define FO_HUD_CONFIG_PATH "fortressone_hud.cfg" +#define FO_CONFIG_PATH "fortressone_csqc.cfg" From 6a00a3246a704bafa71ca55131853aaa569a75ee Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 15:39:07 +1000 Subject: [PATCH 0751/2474] change to single csqc SB function for messages, use single function for clip string gen --- ssqc/status.qc | 71 +++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 65a13878..a13fd47f 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -689,33 +689,43 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { return st; } -void UpdateClientClipStatus(entity pl) +string GetSBClipString(entity pl, float csqcactive) { - string msg = "0"; - - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CLIPSIZE); - + string msg = ""; if (pl.tfstate & TFSTATE_RELOADING) { if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { - msg = strcat(ftos(25 * pl.reload_sniper_ticks), "%"); + msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); } else { if (reload_cliptick) - msg = ftos(pl.reload_clipsize); + msg = csqcactive ? ftos(pl.reload_clipsize) : strpadl(ftos(pl.reload_clipsize), 2); else - msg = "0"; + msg = csqcactive ? "0" : " 0"; + msg = strcat(msg, "/"); - msg = strcat(msg, ftos(GetClipSize(pl))); + msg = strcat(msg, (csqcactive ? ftos(GetClipSize(pl), strpadr(ftos(GetClipSize(pl)), 3)))); } } else { - msg = ClipSizeToString(pl, TRUE); + msg = ClipSizeToString(pl, csqcactive); } - WriteString(MSG_MULTICAST, msg); + return msg; +} + +void UpdateClientStatusBar(entity pl) +{ + // if we ever change to fte only, this could be changed to stats + string msg = ""; + msg_entity = pl; + + string clipMsg = GetSBClipString(pl, TRUE); + + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_SBAR); + WriteString(MSG_MULTICAST, clipMsg); + multicast('0 0 0', MULTICAST_ONE); } @@ -736,6 +746,14 @@ void (entity pl) RefreshStatusBar = { local float sbflaginfostate = FO_GetUserSetting(pl, "sbflaginfo", "sbflaginfo", "on"); /* local float win, sec; */ + + float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); + if (csqcactive) + { + UpdateClientStatusBar(pl) + return; // csqc ends here + } + pad = ""; if (pl.StatusStringLines > 0 && pl.StatusStringTime <= time && !pl.menu_input) { @@ -761,8 +779,6 @@ void (entity pl) RefreshStatusBar = { pad = strcat(pad, "\n"); pad = strzone(pad); - float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); - // class tip if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2) { ct = CF_GetRandomClassTip(pl.playerclass); @@ -929,29 +945,8 @@ void (entity pl) RefreshStatusBar = { st2 = ""; // status line 3 column 2 - clip size - if (csqcactive) - { - UpdateClientClipStatus(pl); - } - else if (pl.tfstate & TFSTATE_RELOADING) - { - st2 = Q"\sClip\s: "; - if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { - st2 = strcat(st2, strpadl(ftos(25 * pl.reload_sniper_ticks), 3)); - st2 = strcat(st2, "% "); - } else { - if (reload_cliptick) - st2 = strcat(st2, strpadl(ftos(pl.reload_clipsize), 2)); - else - st2 = strcat(st2, " 0"); - st2 = strcat(st2, "/"); - st2 = strcat(st2, strpadr(ftos(GetClipSize(pl)), 3)); - } - } - else - { - st2 = ClipSizeToString(pl, FALSE); - } + st2 = strcat(Q"\sClip\s: ", GetSBClipString(pl, csqcactive)); + // status line 3 column 3 - grenade 1 count st3 = strcat(Q"\sGren1\s: ", ftos(pl.no_grenades_1)); From a96a8a4d1b4cda0534714a8f7a62bc5dbb4e47f1 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 15:45:22 +1000 Subject: [PATCH 0752/2474] separate flaginfo to csqc section --- ssqc/status.qc | 60 ++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index a13fd47f..91fc6262 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -745,12 +745,41 @@ void (entity pl) RefreshStatusBar = { //By default, show after tips; 0/off = off; 2 = always local float sbflaginfostate = FO_GetUserSetting(pl, "sbflaginfo", "sbflaginfo", "on"); /* local float win, sec; */ + tfdet = find(world, classname, "info_tfdetect"); float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); if (csqcactive) { UpdateClientStatusBar(pl) + + // flag info + if (tfdet) + { + for (float t = 1; t <= number_of_teams; t++) + { + switch (t) + { + case 1: + te = Finditem(tfdet.display_item_status1); + break; + case 2: + te = Finditem(tfdet.display_item_status2); + break; + case 3: + te = Finditem(tfdet.display_item_status3); + break; + case 4: + te = Finditem(tfdet.display_item_status4); + break; + } + + if (te) + { + UpdateClientFlagStatus(pl, te); + } + } + } return; // csqc ends here } @@ -784,40 +813,13 @@ void (entity pl) RefreshStatusBar = { ct = CF_GetRandomClassTip(pl.playerclass); } else { pl.display_tip = 0; - tfdet = find(world, classname, "info_tfdetect"); // we get flag info from tfdetect - if (!tfdet || (!sbflaginfostate && !csqcactive)) + if (!tfdet || !sbflaginfostate) { ct = strzone("\n\n\n\n\n\n"); } - else if (csqcactive) // has csqc - { - for (float t = 1; t <= number_of_teams; t++) - { - switch (t) - { - case 1: - te = Finditem(tfdet.display_item_status1); - break; - case 2: - te = Finditem(tfdet.display_item_status2); - break; - case 3: - te = Finditem(tfdet.display_item_status3); - break; - case 4: - te = Finditem(tfdet.display_item_status4); - break; - } - - if (te) - { - UpdateClientFlagStatus(pl, te); - } - } - } - else // no csqc but has sbflaginfo on + else // has sbflaginfo on { ct = ""; i = number_of_teams; // Extra newlines From 4993d941b4ba8dba85cc28be2f6180ddf3aeab06 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 15:46:46 +1000 Subject: [PATCH 0753/2474] remove unused code --- ssqc/status.qc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 91fc6262..17b26f21 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1,8 +1,6 @@ float (float tno) TeamFortress_TeamGetScore; float () TeamFortress_TeamGetWinner; float () TeamFortress_TeamGetSecond; -string(float num) NumberToString1000; - string(float num) BlueScoreToString; string(float num) RedScoreToString; string(float num) YellowScoreToString; @@ -975,14 +973,6 @@ void (entity pl) RefreshStatusBar = { strunzone(pad); strunzone(ct); strunzone(s1); strunzone(s2); strunzone(s3); }; -string(float num) NumberToString1000 = -{ - if (num > 999) - return "999"; - - return strpadl(ftos(floor(num)), 3); -}; - string(float num) BlueScoreToString = { if (num > 999) From 43d3ea29693413728acc135925dea967d79bd96f Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 16:26:03 +1000 Subject: [PATCH 0754/2474] scout writebytes done --- ssqc/status.qc | 103 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 23 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 17b26f21..5a262c1c 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -712,6 +712,29 @@ string GetSBClipString(entity pl, float csqcactive) return msg; } +string GetSBClassInfo(entity pl, float csqcactive) +{ + string st1 = ""; + if (pl.playerclass == PC_SCOUT) + st1 = ScannerToString(pl); + else if (pl.playerclass == PC_SNIPER && (pl.tfstate & TFSTATE_AIMING)) + st1 = SniperPowerToString(pl); + else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) + st1 = DetpackToString(pl); + else if (pl.playerclass == PC_MEDIC) + st1 = AuraToString(pl); + else if (pl.playerclass == PC_HVYWEAP) + st1 = AssaultCannonToString(pl); + else if (pl.playerclass == PC_SPY) + st1 = DisguiseToString(pl); + else if (pl.playerclass == PC_ENGINEER && pl.has_sentry) + st1 = SentryDetailsToString(pl); + if (pl.playerclass == PC_ENGINEER && pl.is_building) + st1 = BuildingToString(pl); + + return st1; +} + void UpdateClientStatusBar(entity pl) { // if we ever change to fte only, this could be changed to stats @@ -719,14 +742,62 @@ void UpdateClientStatusBar(entity pl) msg_entity = pl; string clipMsg = GetSBClipString(pl, TRUE); + string classMsg = GetSBClassInfo(pl, TRUE); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SBAR); WriteString(MSG_MULTICAST, clipMsg); + WriteFloat(MSG_MULTICAST, pl.fragstreak); + WriteFloat(MSG_MULTICAST, pl.caps); + WriteFloat(MSG_MULTICAST, pl.playerclass); // just in case we get a packet from "last life" after changing playerclass + + // class info + switch (pl.playerclass) + { + case PC_SCOUT: + // off, on + WriteFloat(MSG_MULTICAST, pl.ScannerOn); + // going to send info whether it's on or not, csqc can figure it out + entity te; + te = find(world, netname, "scanner"); + while ((te != world) && (te.owner != pl)) { + te = find(te, netname, "scanner"); + } + WriteFloat(MSG_MULTICAST, te.health); // range to person, 0 or less if no one + WriteFloat(MSG_MULTICAST, te.team_no); + WriteFloat(MSG_MULTICAST, te.playerclass); + WriteFloat(MSG_MULTICAST, te.tf_items_flags); // nothing, friendly, enemy + break; + case PC_SNIPER: + // damage + // damage maxed + break; + case PC_DEMOMAN: + // seconds left on detpack + break; + case PC_MEDIC: + // aura on/off + // out of power, recharging + // healed x players for y health + break; + case PC_HVYWEAP: + // ass can locked + break; + case PC_SPY: + // invivislbe in x secs + // disguising + // disguised as + break; + case PC_ENGINEER: + // sg - shells rockets, health, level + // disp - health + break; + } multicast('0 0 0', MULTICAST_ONE); } + void (entity pl) RefreshStatusBar = { local string pad; local string s1; // will be used for grenade timers @@ -919,23 +990,8 @@ void (entity pl) RefreshStatusBar = { s1 = strzone(s1); // status line 2 column 1 - class specific information - st1 = ""; - if (pl.playerclass == PC_SCOUT) - st1 = ScannerToString(pl); - else if (pl.playerclass == PC_SNIPER && (pl.tfstate & TFSTATE_AIMING)) - st1 = SniperPowerToString(pl); - else if (pl.playerclass == PC_DEMOMAN && pl.detpack_left) - st1 = DetpackToString(pl); - else if (pl.playerclass == PC_MEDIC) - st1 = AuraToString(pl); - else if (pl.playerclass == PC_HVYWEAP) - st1 = AssaultCannonToString(pl); - else if (pl.playerclass == PC_SPY) - st1 = DisguiseToString(pl); - else if (pl.playerclass == PC_ENGINEER && pl.has_sentry) - st1 = SentryDetailsToString(pl); - if (pl.playerclass == PC_ENGINEER && pl.is_building) - st1 = BuildingToString(pl); + st1 = GetSBClassInfo(pl, csqcactive); + // status line 2 s2 = strpadr(st1, 40); s2 = strcat(s2, "\n"); @@ -1288,17 +1344,18 @@ string(entity pl) ScannerToString = local string range = ""; local float pad; + st = Q"\sScanner\s: "; + + if (pl.ScannerOn != TRUE) { + return strcat(st, "off"); + } + te = find(world, netname, "scanner"); while ((te != world) && (te.owner != pl)) { te = find(te, netname, "scanner"); } - if (pl.ScannerOn != 1) { - return Q"\sScanner\s: off"; - } - if (te.health > 0) { - st = Q"\sScanner\s: "; st = strcat(st, TeamToString(te.team_no)); st = strcat(st, " "); st = strcat(st, ClassToString(te.playerclass)); @@ -1309,7 +1366,7 @@ string(entity pl) ScannerToString = st = strpadr(st, pad); st = strcat(st, range); } else { - st = Q"\sScanner\s: on"; + st = strcat(st, "on"); st = strcat(st, Q" \sScanning\s: "); if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { From 9d5fcf249c746c91b1dd7a5d5ef7118c379488b1 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 16:31:06 +1000 Subject: [PATCH 0755/2474] sniper writebytes --- ssqc/status.qc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 5a262c1c..0151090e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -769,8 +769,17 @@ void UpdateClientStatusBar(entity pl) WriteFloat(MSG_MULTICAST, te.tf_items_flags); // nothing, friendly, enemy break; case PC_SNIPER: - // damage - // damage maxed + float dam, max; + dam = 0; + max = FALSE; + if (sniperpower) + { + dam = pl.heat; + max = pl.power_full; + } + + WriteFloat(MSG_MULTICAST, dam); + WriteFloat(MSG_MULTICAST, max); break; case PC_DEMOMAN: // seconds left on detpack From b0ea20c3a66e93f85a5818152b4e5881a1758ecb Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 16:35:02 +1000 Subject: [PATCH 0756/2474] demoman writebytes --- ssqc/status.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/status.qc b/ssqc/status.qc index 0151090e..308ab464 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -783,6 +783,8 @@ void UpdateClientStatusBar(entity pl) break; case PC_DEMOMAN: // seconds left on detpack + WriteFloat(MSG_MULTICAST, pl.is_detpacking); + WriteFloat(MSG_MULTICAST, pl.detpack_left); break; case PC_MEDIC: // aura on/off From b3202c7698fe71ea69c18e44d225c05e36f99245 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 16:37:21 +1000 Subject: [PATCH 0757/2474] only send scanner info if it's on or something scanned --- ssqc/status.qc | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 308ab464..68d0333e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -757,16 +757,22 @@ void UpdateClientStatusBar(entity pl) case PC_SCOUT: // off, on WriteFloat(MSG_MULTICAST, pl.ScannerOn); - // going to send info whether it's on or not, csqc can figure it out - entity te; - te = find(world, netname, "scanner"); - while ((te != world) && (te.owner != pl)) { - te = find(te, netname, "scanner"); + + if (pl.ScannerOn) + { + entity te; + te = find(world, netname, "scanner"); + while ((te != world) && (te.owner != pl)) { + te = find(te, netname, "scanner"); + } + WriteFloat(MSG_MULTICAST, te.health); // range to person, 0 or less if no one + if (te.health) + { + WriteFloat(MSG_MULTICAST, te.team_no); + WriteFloat(MSG_MULTICAST, te.playerclass); + WriteFloat(MSG_MULTICAST, te.tf_items_flags); // nothing, friendly, enemy + } } - WriteFloat(MSG_MULTICAST, te.health); // range to person, 0 or less if no one - WriteFloat(MSG_MULTICAST, te.team_no); - WriteFloat(MSG_MULTICAST, te.playerclass); - WriteFloat(MSG_MULTICAST, te.tf_items_flags); // nothing, friendly, enemy break; case PC_SNIPER: float dam, max; From 4482403875938527a2cc1d6b407154d9898e4509 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 16:47:26 +1000 Subject: [PATCH 0758/2474] medic writebytes --- share/defs.h | 3 +++ ssqc/status.qc | 30 ++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/share/defs.h b/share/defs.h index e86fc876..bed4a4d5 100644 --- a/share/defs.h +++ b/share/defs.h @@ -961,6 +961,9 @@ #define PC_MEDIC_CELL_REGEN_PERCENT 10 // Percentage of max cells regenerated each cell regen. #define PC_MEDIC_CELL_REGEN_CD 5 // Seconds to cooldown cell regeneration after healing with medikit. #define PC_MEDIC_SAVEME_GRACE 5 // Seconds after which /saveme gives grace period to medikit (no cell regeneration cooldown) +#define PC_MEDIC_AURA_ACTIVE 1 +#define PC_MEDIC_AURA_RECHARGING 2 +#define PC_MEDIC_AURA_OUTOFPOWER 3 // Class Details for HVYWEAP #define PC_HVYWEAP_SKIN 2 diff --git a/ssqc/status.qc b/ssqc/status.qc index 68d0333e..fb63be23 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -788,14 +788,36 @@ void UpdateClientStatusBar(entity pl) WriteFloat(MSG_MULTICAST, max); break; case PC_DEMOMAN: - // seconds left on detpack WriteFloat(MSG_MULTICAST, pl.is_detpacking); WriteFloat(MSG_MULTICAST, pl.detpack_left); break; case PC_MEDIC: - // aura on/off - // out of power, recharging - // healed x players for y health + WriteFloat(MSG_MULTICAST, medicaura); + + if (medicaura) + { + WriteFloat(MSG_MULTICAST, pl.aura_active); + + if (pl.aura_active) + { + float c, a; + c = (time < pl.aura_healtime) ? pl.aura_healcount : 0; + a = (time < pl.aura_healtime) ? pl.aura_healamount : 0; + WriteFloat(MSG_MULTICAST, c); + WriteFloat(MSG_MULTICAST, a); + // state + float s = PC_MEDIC_AURA_ACTIVE; + if (pl.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) + { + s = PC_MEDIC_AURA_OUTOFPOWER; + } + else if (pl.ammo_cells < floor(PC_MEDIC_MAXAMMO_CELL * 0.95)) + { + s = PC_MEDIC_AURA_RECHARGING; + } + WriteFloat(MSG_MULTICAST, s); + } + } break; case PC_HVYWEAP: // ass can locked From e4b940fa445992c323497592154414f0b24d62e5 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 16:53:55 +1000 Subject: [PATCH 0759/2474] hwguy writebytes --- ssqc/status.qc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ssqc/status.qc b/ssqc/status.qc index fb63be23..f1c6e957 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -821,6 +821,13 @@ void UpdateClientStatusBar(entity pl) break; case PC_HVYWEAP: // ass can locked + float l = FALSE; + if (pl.tfstate & TFSTATE_LOCK) + { + l = TRUE; + } + + WriteFloat(MSG_MULTICAST, l); break; case PC_SPY: // invivislbe in x secs From 9489553ed632447a00921da3eaca121e8935a690 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 5 Aug 2019 17:05:10 +1000 Subject: [PATCH 0760/2474] spy writebytes --- ssqc/status.qc | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index f1c6e957..8770578f 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -830,9 +830,25 @@ void UpdateClientStatusBar(entity pl) WriteFloat(MSG_MULTICAST, l); break; case PC_SPY: - // invivislbe in x secs - // disguising - // disguised as + WriteFloat(MSG_MULTICAST, pl.is_undercover); + + if (pl.is_undercover == 1) + { + WriteFloat(MSG_MULTICAST, invis_only); + WriteFloat(MSG_MULTICAST, pl.undercover_team); + WriteFloat(MSG_MULTICAST, pl.undercover_skin); + } + else if (pl.is_undercover == 2) + { + WriteFloat(MSG_MULTICAST, invis_only); + WriteFloat(MSG_MULTICAST, pl.undercover_timer); + WriteFloat(MSG_MULTICAST, pl.undercover_team); + WriteFloat(MSG_MULTICAST, pl.disguise_team); + WriteFloat(MSG_MULTICAST, pl.queue_team); + WriteFloat(MSG_MULTICAST, pl.undercover_skin); + WriteFloat(MSG_MULTICAST, pl.disguise_skin); + WriteFloat(MSG_MULTICAST, pl.queue_skin); + } break; case PC_ENGINEER: // sg - shells rockets, health, level From 9928f12300690d0e9fa2d364ea124d18c5d76881 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 5 Aug 2019 21:00:02 +1000 Subject: [PATCH 0761/2474] engineer changes, finish send sbar --- csqc/settings.qc | 2 +- share/commondefs.qc | 1 + ssqc/status.qc | 54 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/csqc/settings.qc b/csqc/settings.qc index 9006cd02..ac977741 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -4,7 +4,7 @@ void FO_WriteSettings() float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); string line; - + line = ""; line = FormatCfgString(line, "fo_autohop", ftos(Settings.Autohop)); fputs(filehandle, line); diff --git a/share/commondefs.qc b/share/commondefs.qc index 257862f1..37eba714 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -3,6 +3,7 @@ #define MSG_FLAGINFOINIT 1 #define MSG_FLAGINFO 2 #define MSG_CLIPSIZE 3 +#define MSG_SBAR 4 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/status.qc b/ssqc/status.qc index 8770578f..28199b40 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -701,7 +701,7 @@ string GetSBClipString(entity pl, float csqcactive) msg = csqcactive ? "0" : " 0"; msg = strcat(msg, "/"); - msg = strcat(msg, (csqcactive ? ftos(GetClipSize(pl), strpadr(ftos(GetClipSize(pl)), 3)))); + msg = strcat(msg, (csqcactive ? ftos(GetClipSize(pl)) : strpadr(ftos(GetClipSize(pl)), 3))); } } else @@ -749,7 +749,19 @@ void UpdateClientStatusBar(entity pl) WriteString(MSG_MULTICAST, clipMsg); WriteFloat(MSG_MULTICAST, pl.fragstreak); WriteFloat(MSG_MULTICAST, pl.caps); + // identify + if (pl.ident_string && time < pl.ident_time) { + WriteString(MSG_MULTICAST, pl.ident_string); + } else { + WriteString(MSG_MULTICAST, ""); + } + WriteFloat(MSG_MULTICAST, pl.playerclass); // just in case we get a packet from "last life" after changing playerclass + if (pl.playerclass) + { + WriteFloat(MSG_MULTICAST, pl.no_grenades_1); + WriteFloat(MSG_MULTICAST, pl.no_grenades_2); + } // class info switch (pl.playerclass) @@ -851,15 +863,43 @@ void UpdateClientStatusBar(entity pl) } break; case PC_ENGINEER: - // sg - shells rockets, health, level - // disp - health + // building status?? + WriteFloat(MSG_MULTICAST, pl.is_building); + if (pl.is_building) + { + WriteFloat(MSG_MULTICAST, pl.building_percentage); + } + + WriteFloat(MSG_MULTICAST, pl.has_sentry); + if (pl.has_sentry) + { + WriteFloat(MSG_MULTICAST, pl.sentry_ent.weapon); // level + WriteFloat(MSG_MULTICAST, pl.sentry_ent.health); + WriteFloat(MSG_MULTICAST, pl.sentry_ent.ammo_shells); + WriteFloat(MSG_MULTICAST, pl.sentry_ent.ammo_rockets); + + } + + WriteFloat(MSG_MULTICAST, pl.has_dispenser); + if (pl.has_dispenser) + { + entity disp; + disp = find(world, classname, "building_dispenser"); + while (disp) + { + if (disp.real_owner == pl) + { + WriteFloat(MSG_MULTICAST, disp.health); + } + disp = find(disp, classname, "building_dispenser"); + } + } break; } multicast('0 0 0', MULTICAST_ONE); } - void (entity pl) RefreshStatusBar = { local string pad; local string s1; // will be used for grenade timers @@ -875,14 +915,13 @@ void (entity pl) RefreshStatusBar = { local string bi; //button info //By default, show after tips; 0/off = off; 2 = always local float sbflaginfostate = FO_GetUserSetting(pl, "sbflaginfo", "sbflaginfo", "on"); - /* local float win, sec; */ tfdet = find(world, classname, "info_tfdetect"); - float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); if (csqcactive) { - UpdateClientStatusBar(pl) + pl.StatusRefreshTime = time + 1; + UpdateClientStatusBar(pl); // flag info if (tfdet) @@ -1064,7 +1103,6 @@ void (entity pl) RefreshStatusBar = { // status line 3 column 2 - clip size st2 = strcat(Q"\sClip\s: ", GetSBClipString(pl, csqcactive)); - // status line 3 column 3 - grenade 1 count st3 = strcat(Q"\sGren1\s: ", ftos(pl.no_grenades_1)); From 06672a1065101c1581e9ef27fb1c1556c9549567 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 5 Aug 2019 21:59:33 +1000 Subject: [PATCH 0762/2474] sbar read bytes impemented --- csqc/csextradefs.qc | 51 ++++++++++++++++++++- csqc/events.qc | 109 ++++++++++++++++++++++++++++++++++++++++++-- csqc/hud.qc | 2 +- share/commondefs.qc | 2 +- ssqc/status.qc | 3 +- 5 files changed, 157 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1e589a59..9a692ed2 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -3,7 +3,6 @@ .float owned_by; float fo_hud_editor; float jumptime; -string ClipSizeMsg; typedef struct { @@ -53,6 +52,56 @@ typedef struct { } FO_Settings; FO_Settings Settings; +typedef struct { + string ClipSize; + float FragStreak; + float Caps; + string Identify; + float PlayerClass; + float Gren1; + float Gren2; + // scout + float ScannerOn; + float ScannerRange; + float ScannerTeamNo; + float ScannerPlayerClass; + float ScannerTFItemsFlags; + // sniper + float SniperDam; + float SniperMax; + // demoman + float IsDetpacking; + float DetpackLeft; + // medic + float AuraActive; + float HealCount; + float HealAmount; + float AuraStatus; + // hwguy + float LockedCannon; + // spy + float IsUndercover; + float InvisOnly; + float UndercoverTeam; + float UndercoverSkin; + float UndercoverTimer; + float DisguiseTeam; + float QueueTeam; + float DisguiseSkin; + float QueueSkin; + // engineer + float IsBuilding; + float BuildingPercentage; + float HasSentry; + float SentryLevel; + float SentryHealth; + float SentryAmmoShells; + float SentryAmmoRockets; + float HasDispenser; + float DispenserHealth; +} FO_SBAR; +FO_SBAR SBAR; + #define HUD_FLAGICON_SIZE_X 24 #define HUD_FLAGICON_SIZE_Y 24 #define FO_HUD_CLIPSIZE_PANEL_X 125 diff --git a/csqc/events.qc b/csqc/events.qc index a45fef48..a2ff88e9 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,3 +1,5 @@ +void ParseSBAR(); + void() CSQC_Parse_Event = { float msgtype = readbyte(); local float goalno; @@ -69,13 +71,110 @@ void() CSQC_Parse_Event = { } } break; - case MSG_CLIPSIZE: - string test; - test = readstring(); - - ClipSizeMsg = test; + case MSG_SBAR: + ParseSBAR(); break; default: print("CSQC_Parse_Event, unknown event: ",ftos(msgtype),"\n"); } +} + +void ParseSBAR() +{ + SBAR.ClipSize = readstring(); + SBAR.FragStreak = readfloat(); + SBAR.Caps = readfloat(); + SBAR.Identify = readstring(); + SBAR.PlayerClass = readfloat(); + + if (SBAR.PlayerClass) + { + SBAR.Gren1 = readfloat(); + SBAR.Gren2 = readfloat(); + } + + switch (SBAR.PlayerClass) + { + case PC_SCOUT: + SBAR.ScannerOn = readfloat(); + if (SBAR.ScannerOn) + { + SBAR.ScannerRange = readfloat(); + + if (SBAR.ScannerRange) + { + SBAR.ScannerTeamNo = readfloat(); + SBAR.ScannerPlayerClass = readfloat(); + SBAR.ScannerTFItemsFlags = readfloat(); + } + } + break; + case PC_SNIPER: + SBAR.SniperDam = readfloat(); + SBAR.SniperMax = readfloat(); + break; + case PC_DEMOMAN: + SBAR.IsDetpacking = readfloat(); + SBAR.DetpackLeft = readfloat(); + break; + case PC_MEDIC: + float medicaura = readfloat(); + if (medicaura) + { + SBAR.AuraActive = readfloat(); + if (SBAR.AuraActive) + { + SBAR.HealCount = readfloat(); + SBAR.HealAmount = readfloat(); + SBAR.AuraStatus = readfloat(); + } + } + break; + case PC_HVYWEAP: + SBAR.LockedCannon = readfloat(); + break; + case PC_SPY: + SBAR.IsUndercover = readfloat(); + + if (SBAR.IsUndercover == 1) + { + SBAR.InvisOnly = readfloat(); + SBAR.UndercoverTeam = readfloat(); + SBAR.UndercoverSkin = readfloat(); + } + else if (SBAR.IsUndercover == 2) + { + SBAR.InvisOnly = readfloat(); + SBAR.UndercoverTimer = readfloat(); + SBAR.UndercoverTeam = readfloat(); + SBAR.DisguiseTeam = readfloat(); + SBAR.QueueTeam = readfloat(); + SBAR.UndercoverSkin = readfloat(); + SBAR.DisguiseSkin = readfloat(); + SBAR.QueueSkin = readfloat(); + } + break; + case PC_ENGINEER: + SBAR.IsBuilding = readfloat(); + if (SBAR.IsBuilding) + { + SBAR.BuildingPercentage = readfloat(); + } + + SBAR.HasSentry = readfloat(); + if (SBAR.HasSentry) + { + SBAR.SentryLevel = readfloat(); + SBAR.SentryHealth = readfloat(); + SBAR.SentryAmmoShells = readfloat(); + SBAR.SentryAmmoRockets = readfloat(); + } + + SBAR.HasDispenser = readfloat(); + if (SBAR.HasDispenser) + { + SBAR.DispenserHealth = readfloat(); + } + break; + } } \ No newline at end of file diff --git a/csqc/hud.qc b/csqc/hud.qc index 3cfbb6aa..15f396c3 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -207,7 +207,7 @@ void Hud_DrawClipSize(float width) } } - Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], ClipSizeMsg, 24 * HudSettings.ClipSize.Scale); + Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], SBAR.ClipSize, 24 * HudSettings.ClipSize.Scale); } void Hud_Draw(float width, float height) diff --git a/share/commondefs.qc b/share/commondefs.qc index 37eba714..62b41af8 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -2,7 +2,7 @@ #define MSG_FLAGINFOINIT 1 #define MSG_FLAGINFO 2 -#define MSG_CLIPSIZE 3 + #define MSG_SBAR 4 #define FLAGINFO_HOME 1 diff --git a/ssqc/status.qc b/ssqc/status.qc index 28199b40..d113e342 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -742,7 +742,6 @@ void UpdateClientStatusBar(entity pl) msg_entity = pl; string clipMsg = GetSBClipString(pl, TRUE); - string classMsg = GetSBClassInfo(pl, TRUE); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SBAR); @@ -920,7 +919,7 @@ void (entity pl) RefreshStatusBar = { float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); if (csqcactive) { - pl.StatusRefreshTime = time + 1; + //pl.StatusRefreshTime = time + 1; UpdateClientStatusBar(pl); // flag info From 2b4c0bf9d2ae6c936cc4356e69f277b2349ca7d1 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 5 Aug 2019 22:07:48 +1000 Subject: [PATCH 0763/2474] implement display on clipsize and flag panels --- csqc/csextradefs.qc | 2 ++ csqc/hud.qc | 20 ++++++++++++++++++-- csqc/hud_helpers.qc | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9a692ed2..9e3441ca 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -31,6 +31,7 @@ FlagInfoLine FlagInfoLines[10]; typedef struct { vector Position; float Scale; + float Display; } FO_Hud_ClipSize; typedef struct { @@ -38,6 +39,7 @@ typedef struct { float GrowDirection; float NodeInsertLoc; float Scale; + float Display; } FO_Hud_FlagIcon; typedef struct { diff --git a/csqc/hud.qc b/csqc/hud.qc index 15f396c3..0f5fd129 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,5 +1,3 @@ -// TODO - reset to defaults command -// TODO - implement scale on elements void FO_Hud_Editor() { if (fo_hud_editor) @@ -31,11 +29,13 @@ void FO_Hud_Editor_LoadDefaultSettings() HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; HudFlagIcon.Scale = 1; + HudFlagIcon.Display = 1; HudSettings.FlagIcon = HudFlagIcon; FO_Hud_ClipSize HudClipSize; HudClipSize.Position = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; HudClipSize.Scale = 1; + HudClipSize.Display = 1; HudSettings.ClipSize = HudClipSize; } @@ -90,6 +90,9 @@ void FO_Hud_Editor_LoadSettings() case "hudflagicon.nodeinsertloc": HudSettings.FlagIcon.NodeInsertLoc = stof(val); break; + case "hudflagicon.display": + HudSettings.FlagIcon.Display = stof(val); + break; case "hudclipsize.position": count = tokenizebyseparator(val, ","); x = stof(argv(0)); @@ -99,6 +102,9 @@ void FO_Hud_Editor_LoadSettings() case "hudclipsize.scale": HudSettings.ClipSize.Scale = stof(val); break; + case "hudclipsize.display": + HudSettings.ClipSize.Display = stof(val); + break; } } ln = fgets(filehandle); @@ -114,6 +120,9 @@ void FO_Hud_Editor_LoadSettings() void Hud_DrawFlagStatusBar(float width) { + if (!HudSettings.FlagIcon.Display) + return; + vector pos; pos = HudSettings.FlagIcon.Position; float sizey, sizex; @@ -194,6 +203,9 @@ void Hud_DrawFlagStatusBar(float width) void Hud_DrawClipSize(float width) { + if (!HudSettings.ClipSize.Display) + return; + vector pos = HudSettings.ClipSize.Position; vector fillsize = [FO_HUD_CLIPSIZE_PANEL_X * HudSettings.ClipSize.Scale, FO_HUD_CLIPSIZE_PANEL_Y * HudSettings.ClipSize.Scale]; float alpha = 0; @@ -208,12 +220,16 @@ void Hud_DrawClipSize(float width) } Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], SBAR.ClipSize, 24 * HudSettings.ClipSize.Scale); + } void Hud_Draw(float width, float height) { Hud_DrawFlagStatusBar(width); Hud_DrawClipSize(width); + + + HudSettings.MousePos = [Mouse.x, Mouse.y]; } \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 1ebe2059..a8387faa 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -175,8 +175,10 @@ void Hud_WriteCfg(string path) line = FormatCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); + line = FormatCfgString(line, "hudflagicon.display", ftos(HudSettings.FlagIcon.Display)); line = FormatCfgVector(line, "hudclipsize.position", HudSettings.ClipSize.Position); line = FormatCfgString(line, "hudclipsize.scale", ftos(HudSettings.ClipSize.Scale)); + line = FormatCfgString(line, "hudclipsize.display", ftos(HudSettings.ClipSize.Display)); fputs(filehandle, line); fclose(filehandle); From b57e94abc366f809053b459429204ae989bda59e Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 5 Aug 2019 23:55:21 +1000 Subject: [PATCH 0764/2474] get frag streak drawing --- csqc/csextradefs.qc | 8 ++++++ csqc/hud.qc | 66 ++++++++++++++++++++++++++++++++++++++++++--- csqc/hud_helpers.qc | 3 +++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9e3441ca..a2cd1a3b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -42,9 +42,17 @@ typedef struct { float Display; } FO_Hud_FlagIcon; +typedef struct { + vector Position; + vector FillSize; + float Scale; + float Display; +} FO_Hud_Panel; + typedef struct { FO_Hud_FlagIcon FlagIcon; FO_Hud_ClipSize ClipSize; + FO_Hud_Panel FragStreak; vector MousePos; } FO_Hud_Settings; FO_Hud_Settings HudSettings; diff --git a/csqc/hud.qc b/csqc/hud.qc index 0f5fd129..62dac5ff 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,3 +1,6 @@ +FO_Hud_Panel DrawPanel; +FO_Hud_Panel NewPanel; + void FO_Hud_Editor() { if (fo_hud_editor) @@ -14,6 +17,18 @@ void FO_Hud_Editor() } } +void GetNewPanel(vector pos, vector fillSize, float scale, float display) +{ + FO_Hud_Panel pnl; + + pnl.Position = pos; + pnl.FillSize = fillSize; + pnl.Scale = scale; + pnl.Display = display; + + NewPanel = pnl; +} + void FO_Hud_Editor_LoadDefaultSettings() { vector vsize = (vector)getproperty(VF_SCREENVSIZE); @@ -32,11 +47,24 @@ void FO_Hud_Editor_LoadDefaultSettings() HudFlagIcon.Display = 1; HudSettings.FlagIcon = HudFlagIcon; + vector pos, fill; + float scale, display; + + pos = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; FO_Hud_ClipSize HudClipSize; - HudClipSize.Position = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; + HudClipSize.Position = pos; HudClipSize.Scale = 1; HudClipSize.Display = 1; HudSettings.ClipSize = HudClipSize; + + pos = [pos_x, pos_y - 2 - 50]; + fill = [50, 50]; + scale = 1; + display = 1; + + GetNewPanel(pos, fill, scale, display); + FO_Hud_Panel HudFragStreak = NewPanel; + HudSettings.FragStreak = HudFragStreak; } float firstrun; @@ -105,6 +133,18 @@ void FO_Hud_Editor_LoadSettings() case "hudclipsize.display": HudSettings.ClipSize.Display = stof(val); break; + case "hudfragstreak.position": + count = tokenizebyseparator(val, ","); + x = stof(argv(0)); + y = stof(argv(1)); + HudSettings.FragStreak.Position = [x, y]; + break; + case "hudfragstreak.scale": + HudSettings.FragStreak.Scale = stof(val); + break; + case "hudfragstreak.display": + HudSettings.FragStreak.Display = stof(val); + break; } } ln = fgets(filehandle); @@ -220,7 +260,27 @@ void Hud_DrawClipSize(float width) } Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], SBAR.ClipSize, 24 * HudSettings.ClipSize.Scale); +} + +void Hud_DrawPanelLMP(string id, float val) +{ + if (!DrawPanel.Display) + return; + + vector pos; + pos = DrawPanel.Position; + + if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) + { + // click event + if (fo_hud_editor) + { + + } + } + + Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], ftos(val), 24 * DrawPanel.Scale); } void Hud_Draw(float width, float height) @@ -228,8 +288,8 @@ void Hud_Draw(float width, float height) Hud_DrawFlagStatusBar(width); Hud_DrawClipSize(width); - - + DrawPanel = HudSettings.FragStreak; + Hud_DrawPanelLMP("fragstreakpanel", SBAR.FragStreak); HudSettings.MousePos = [Mouse.x, Mouse.y]; } \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index a8387faa..b5239685 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -179,6 +179,9 @@ void Hud_WriteCfg(string path) line = FormatCfgVector(line, "hudclipsize.position", HudSettings.ClipSize.Position); line = FormatCfgString(line, "hudclipsize.scale", ftos(HudSettings.ClipSize.Scale)); line = FormatCfgString(line, "hudclipsize.display", ftos(HudSettings.ClipSize.Display)); + line = FormatCfgVector(line, "hudfragstreak.position", HudSettings.FragStreak.Position); + line = FormatCfgString(line, "hudfragstreak.scale", ftos(HudSettings.FragStreak.Scale)); + line = FormatCfgString(line, "hudfragstreak.display", ftos(HudSettings.FragStreak.Display)); fputs(filehandle, line); fclose(filehandle); From 23ef4983207d68dd5437816cc4d52777ff12138a Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 6 Aug 2019 13:28:01 +1000 Subject: [PATCH 0765/2474] icon implementation, more generic panel building --- csqc/csextradefs.qc | 36 +++++++++++++++++++++--------- csqc/hud.qc | 54 +++++++++++++++------------------------------ csqc/main.qc | 7 ++++++ share/defs.h | 22 ++++++++++++++++++ 4 files changed, 72 insertions(+), 47 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index a2cd1a3b..b07ee778 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -28,12 +28,6 @@ FlagInfoLine FlagInfoLines[10]; // hud stuff -typedef struct { - vector Position; - float Scale; - float Display; -} FO_Hud_ClipSize; - typedef struct { vector Position; float GrowDirection; @@ -51,7 +45,7 @@ typedef struct { typedef struct { FO_Hud_FlagIcon FlagIcon; - FO_Hud_ClipSize ClipSize; + FO_Hud_Panel ClipSize; FO_Hud_Panel FragStreak; vector MousePos; } FO_Hud_Settings; @@ -112,10 +106,30 @@ typedef struct { } FO_SBAR; FO_SBAR SBAR; -#define HUD_FLAGICON_SIZE_X 24 -#define HUD_FLAGICON_SIZE_Y 24 -#define FO_HUD_CLIPSIZE_PANEL_X 125 -#define FO_HUD_CLIPSIZE_PANEL_Y 50 +typedef struct +{ + string icon; +} FO_Hud_Icons; +FO_Hud_Icons HudIcons[16] = { + {ICON_SCOUT}, + {ICON_SNIPER}, + {ICON_SOLDIER}, + {ICON_DEMOMAN}, + {ICON_MEDIC}, + {ICON_HWGUY}, + {ICON_PYRO}, + {ICON_SPY}, + {ICON_ENGINEER_SG}, + {ICON_ENGINEER_DISP}, + {ICON_CLIPSIZE}, + {ICON_FRAGSTREAK}, + {ICON_CAPS}, + {ICON_IDENTIFY}, + {ICON_GREN1}, + {ICON_GREN2} +}; + +vector FO_Hud_Icon_Size = [24, 24, 0]; #pragma noref 1 #pragma warning error Q101 /*too many parms*/ diff --git a/csqc/hud.qc b/csqc/hud.qc index 62dac5ff..aa6f8552 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -49,18 +49,17 @@ void FO_Hud_Editor_LoadDefaultSettings() vector pos, fill; float scale, display; - pos = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; - FO_Hud_ClipSize HudClipSize; - HudClipSize.Position = pos; - HudClipSize.Scale = 1; - HudClipSize.Display = 1; + scale = 1; + display = 1; + fill = [FO_HUD_CLIPSIZE_PANEL_X, FO_HUD_CLIPSIZE_PANEL_Y]; + + GetNewPanel(pos, fill, scale, display); + FO_Hud_Panel HudClipSize = NewPanel; HudSettings.ClipSize = HudClipSize; pos = [pos_x, pos_y - 2 - 50]; fill = [50, 50]; - scale = 1; - display = 1; GetNewPanel(pos, fill, scale, display); FO_Hud_Panel HudFragStreak = NewPanel; @@ -166,8 +165,8 @@ void Hud_DrawFlagStatusBar(float width) vector pos; pos = HudSettings.FlagIcon.Position; float sizey, sizex; - sizey = HUD_FLAGICON_SIZE_Y * HudSettings.FlagIcon.Scale; - sizex = HUD_FLAGICON_SIZE_X * HudSettings.FlagIcon.Scale; + sizey = FO_Hud_Icon_Size_y * HudSettings.FlagIcon.Scale; + sizex = FO_Hud_Icon_Size_x * HudSettings.FlagIcon.Scale; float flagInfoCount = 0; for (float i = FlagInfoLines.length - 1; i >= 0; i--) @@ -241,29 +240,7 @@ void Hud_DrawFlagStatusBar(float width) } } -void Hud_DrawClipSize(float width) -{ - if (!HudSettings.ClipSize.Display) - return; - - vector pos = HudSettings.ClipSize.Position; - vector fillsize = [FO_HUD_CLIPSIZE_PANEL_X * HudSettings.ClipSize.Scale, FO_HUD_CLIPSIZE_PANEL_Y * HudSettings.ClipSize.Scale]; - float alpha = 0; - - if (hud_panel("clipsizepanel", pos, fillsize, alpha)) - { - // click event - if (fo_hud_editor) - { - - } - } - - Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], SBAR.ClipSize, 24 * HudSettings.ClipSize.Scale); -} - - -void Hud_DrawPanelLMP(string id, float val) +void Hud_DrawPanelLMP(string id, string val, string icon) { if (!DrawPanel.Display) return; @@ -279,17 +256,22 @@ void Hud_DrawPanelLMP(string id, float val) } } - - Hud_DrawStringLMP([pos_x + 2, pos_y + 2, 0], ftos(val), 24 * DrawPanel.Scale); + vector size = FO_Hud_Icon_Size * DrawPanel.Scale; + pos = [pos_x + 2, pos_y + 2, 0]; + drawpic(pos, icon, size, '1 1 1', 1, 1); + pos = [pos_x + 2 + size_x, pos_y, 0]; + Hud_DrawStringLMP(pos, val, 24 * DrawPanel.Scale); } void Hud_Draw(float width, float height) { Hud_DrawFlagStatusBar(width); - Hud_DrawClipSize(width); + + DrawPanel = HudSettings.ClipSize; + Hud_DrawPanelLMP("fragstreakpanel", SBAR.ClipSize, HudIcons[13].icon); DrawPanel = HudSettings.FragStreak; - Hud_DrawPanelLMP("fragstreakpanel", SBAR.FragStreak); + Hud_DrawPanelLMP("fragstreakpanel", ftos(SBAR.FragStreak), HudIcons[12].icon); HudSettings.MousePos = [Mouse.x, Mouse.y]; } \ No newline at end of file diff --git a/csqc/main.qc b/csqc/main.qc index 8282e5e7..f6069f38 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -7,7 +7,14 @@ void FO_WriteSettings(); noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); + precache_model("progs/weapons/v_rock.mdl"); + + for (float i = 0; i < HudIcons.length; i++) + { + precache_pic(HudIcons[i].icon); + } + registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); diff --git a/share/defs.h b/share/defs.h index bed4a4d5..41406ffd 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1316,3 +1316,25 @@ #define FO_HUD_INSERT_BEFORE 1 #define FO_HUD_CONFIG_PATH "fortressone_hud.cfg" #define FO_CONFIG_PATH "fortressone_csqc.cfg" + +#define HUD_ICON_SIZE_X 24 +#define HUD_ICON_SIZE_Y 24 +#define FO_HUD_CLIPSIZE_PANEL_X 125 +#define FO_HUD_CLIPSIZE_PANEL_Y 50 + +#define ICON_CLIPSIZE "progs/gfx/hud/clipsize.png" +#define ICON_FRAGSTREAK "progs/gfx/hud/fragstreak.png" +#define ICON_CAPS "progs/gfx/hud/caps.png" +#define ICON_IDENTIFY "progs/gfx/hud/identify.png" +#define ICON_GREN1 "progs/gfx/hud/gren1.png" +#define ICON_GREN2 "progs/gfx/hud/gren2.png" +#define ICON_SCOUT "progs/gfx/hud/scout.png" +#define ICON_SNIPER "progs/gfx/hud/sniper.png" +#define ICON_SOLDIER "progs/gfx/hud/soldier.png" +#define ICON_DEMOMAN "progs/gfx/hud/demoman.png" +#define ICON_MEDIC "progs/gfx/hud/medic.png" +#define ICON_HWGUY "progs/gfx/hud/hwguy.png" +#define ICON_PYRO "progs/gfx/hud/pyro.png" +#define ICON_SPY "progs/gfx/hud/spy.png" +#define ICON_ENGINEER_SG "progs/gfx/hud/engineer_sg.png" +#define ICON_ENGINEER_DISP "progs/gfx/hud/engineer_disp.png" From 378361452ee3d61952d1edbe7826e96532926bee Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 6 Aug 2019 13:59:10 +1000 Subject: [PATCH 0766/2474] implement node insert/before, make writing of panel settings easier --- csqc/csextradefs.qc | 4 ++ csqc/hud.qc | 90 +++++++++++++++++++++++++++++---------------- csqc/hud_helpers.qc | 22 ++++++++--- share/defs.h | 4 +- 4 files changed, 81 insertions(+), 39 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index b07ee778..90d814b6 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -41,8 +41,12 @@ typedef struct { vector FillSize; float Scale; float Display; + float NodeInsertLoc; } FO_Hud_Panel; +FO_Hud_Panel DrawPanel; +FO_Hud_Panel NewPanel; + typedef struct { FO_Hud_FlagIcon FlagIcon; FO_Hud_Panel ClipSize; diff --git a/csqc/hud.qc b/csqc/hud.qc index aa6f8552..db97c6ba 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,5 +1,3 @@ -FO_Hud_Panel DrawPanel; -FO_Hud_Panel NewPanel; void FO_Hud_Editor() { @@ -17,7 +15,7 @@ void FO_Hud_Editor() } } -void GetNewPanel(vector pos, vector fillSize, float scale, float display) +void GetNewPanel(vector pos, vector fillSize, float scale, float display, float nodeInsertLoc) { FO_Hud_Panel pnl; @@ -25,6 +23,7 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display) pnl.FillSize = fillSize; pnl.Scale = scale; pnl.Display = display; + pnl.NodeInsertLoc = nodeInsertLoc; NewPanel = pnl; } @@ -48,20 +47,21 @@ void FO_Hud_Editor_LoadDefaultSettings() HudSettings.FlagIcon = HudFlagIcon; vector pos, fill; - float scale, display; + float scale, display, nodeInsertLoc; pos = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; scale = 1; display = 1; + nodeInsertLoc = FO_HUD_INSERT_BEFORE; fill = [FO_HUD_CLIPSIZE_PANEL_X, FO_HUD_CLIPSIZE_PANEL_Y]; - GetNewPanel(pos, fill, scale, display); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc); FO_Hud_Panel HudClipSize = NewPanel; HudSettings.ClipSize = HudClipSize; pos = [pos_x, pos_y - 2 - 50]; fill = [50, 50]; - GetNewPanel(pos, fill, scale, display); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc); FO_Hud_Panel HudFragStreak = NewPanel; HudSettings.FragStreak = HudFragStreak; } @@ -120,29 +120,50 @@ void FO_Hud_Editor_LoadSettings() case "hudflagicon.display": HudSettings.FlagIcon.Display = stof(val); break; - case "hudclipsize.position": - count = tokenizebyseparator(val, ","); - x = stof(argv(0)); - y = stof(argv(1)); - HudSettings.ClipSize.Position = [x, y]; - break; - case "hudclipsize.scale": - HudSettings.ClipSize.Scale = stof(val); - break; - case "hudclipsize.display": - HudSettings.ClipSize.Display = stof(val); - break; - case "hudfragstreak.position": - count = tokenizebyseparator(val, ","); - x = stof(argv(0)); - y = stof(argv(1)); - HudSettings.FragStreak.Position = [x, y]; - break; - case "hudfragstreak.scale": - HudSettings.FragStreak.Scale = stof(val); - break; - case "hudfragstreak.display": - HudSettings.FragStreak.Display = stof(val); + default: + count = tokenizebyseparator(field, "."); + string pnl; + pnl = argv(0); + switch (pnl) + { + case "hudclipsize": + DrawPanel = HudSettings.ClipSize; + break; + case "hudfragstreak": + DrawPanel = HudSettings.FragStreak; + break; + } + + switch (argv(1)) + { + case "position": + count = tokenizebyseparator(val, ","); + x = stof(argv(0)); + y = stof(argv(1)); + DrawPanel.Position = [x, y]; + break; + case "scale": + DrawPanel.Scale = stof(val); + break; + case "display": + DrawPanel.Display = stof(val); + break; + case "nodeinsertloc": + DrawPanel.NodeInsertLoc = stof(val); + break; + } + + // is this necessary? how does qc copy + switch (pnl) + { + case "hudclipsize": + HudSettings.ClipSize = DrawPanel; + break; + case "hudfragstreak": + HudSettings.FragStreak = DrawPanel; + break; + } + break; } } @@ -240,6 +261,7 @@ void Hud_DrawFlagStatusBar(float width) } } +// draws value string using lmps void Hud_DrawPanelLMP(string id, string val, string icon) { if (!DrawPanel.Display) @@ -256,10 +278,16 @@ void Hud_DrawPanelLMP(string id, string val, string icon) } } + vector size = FO_Hud_Icon_Size * DrawPanel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; drawpic(pos, icon, size, '1 1 1', 1, 1); - pos = [pos_x + 2 + size_x, pos_y, 0]; + + float len; + len = strlen(val); + float offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_AFTER) ? 2 + size_x : (2 + (size_x * len)) * -1; + + pos = [pos_x + offset, pos_y, 0]; Hud_DrawStringLMP(pos, val, 24 * DrawPanel.Scale); } @@ -268,7 +296,7 @@ void Hud_Draw(float width, float height) Hud_DrawFlagStatusBar(width); DrawPanel = HudSettings.ClipSize; - Hud_DrawPanelLMP("fragstreakpanel", SBAR.ClipSize, HudIcons[13].icon); + Hud_DrawPanelLMP("clipsizepanel", SBAR.ClipSize, HudIcons[13].icon); DrawPanel = HudSettings.FragStreak; Hud_DrawPanelLMP("fragstreakpanel", ftos(SBAR.FragStreak), HudIcons[12].icon); diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index b5239685..1c1898c2 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -164,6 +164,16 @@ string FormatCfgVector(string line, string field, vector value) return line; } +string GetPanelString(string line, string name) +{ + line = FormatCfgVector(line, strcat(name, ".position"), DrawPanel.Position); + line = FormatCfgString(line, strcat(name, ".scale"), ftos(DrawPanel.Scale)); + line = FormatCfgString(line, strcat(name, ".display"), ftos(DrawPanel.Display)); + line = FormatCfgString(line, strcat(name, ".nodeinsertloc"), ftos(DrawPanel.NodeInsertLoc)); + + return line; +} + void Hud_WriteCfg(string path) { // this overwrites @@ -176,12 +186,12 @@ void Hud_WriteCfg(string path) line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); line = FormatCfgString(line, "hudflagicon.display", ftos(HudSettings.FlagIcon.Display)); - line = FormatCfgVector(line, "hudclipsize.position", HudSettings.ClipSize.Position); - line = FormatCfgString(line, "hudclipsize.scale", ftos(HudSettings.ClipSize.Scale)); - line = FormatCfgString(line, "hudclipsize.display", ftos(HudSettings.ClipSize.Display)); - line = FormatCfgVector(line, "hudfragstreak.position", HudSettings.FragStreak.Position); - line = FormatCfgString(line, "hudfragstreak.scale", ftos(HudSettings.FragStreak.Scale)); - line = FormatCfgString(line, "hudfragstreak.display", ftos(HudSettings.FragStreak.Display)); + + DrawPanel = HudSettings.ClipSize; + line = GetPanelString(line, "hudclipsize"); + + DrawPanel = HudSettings.FragStreak; + line = GetPanelString(line, "hudfragstreak"); fputs(filehandle, line); fclose(filehandle); diff --git a/share/defs.h b/share/defs.h index 41406ffd..f0ef1c10 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1312,8 +1312,6 @@ #define FO_HUD_GROW_LEFT 3 #define FO_HUD_GROW_RIGHT 4 -#define FO_HUD_INSERT_AFTER 1 -#define FO_HUD_INSERT_BEFORE 1 #define FO_HUD_CONFIG_PATH "fortressone_hud.cfg" #define FO_CONFIG_PATH "fortressone_csqc.cfg" @@ -1321,6 +1319,8 @@ #define HUD_ICON_SIZE_Y 24 #define FO_HUD_CLIPSIZE_PANEL_X 125 #define FO_HUD_CLIPSIZE_PANEL_Y 50 +#define FO_HUD_INSERT_BEFORE 0 +#define FO_HUD_INSERT_AFTER 1 #define ICON_CLIPSIZE "progs/gfx/hud/clipsize.png" #define ICON_FRAGSTREAK "progs/gfx/hud/fragstreak.png" From 19a19bcfa0e5a137119b5b2ff42dd5f3a951f5a0 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 6 Aug 2019 14:19:58 +1000 Subject: [PATCH 0767/2474] add caps panel, make code a little easier to manage --- csqc/csextradefs.qc | 1 + csqc/hud.qc | 40 ++++++++++++++-------------------- csqc/hud_helpers.qc | 52 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 63 insertions(+), 30 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 90d814b6..537b2ff3 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -51,6 +51,7 @@ typedef struct { FO_Hud_FlagIcon FlagIcon; FO_Hud_Panel ClipSize; FO_Hud_Panel FragStreak; + FO_Hud_Panel Caps; vector MousePos; } FO_Hud_Settings; FO_Hud_Settings HudSettings; diff --git a/csqc/hud.qc b/csqc/hud.qc index db97c6ba..84a08b71 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -58,12 +58,19 @@ void FO_Hud_Editor_LoadDefaultSettings() FO_Hud_Panel HudClipSize = NewPanel; HudSettings.ClipSize = HudClipSize; - pos = [pos_x, pos_y - 2 - 50]; - fill = [50, 50]; + pos = [pos_x, pos_y - 2 - 24]; + fill = [50, 26]; GetNewPanel(pos, fill, scale, display, nodeInsertLoc); FO_Hud_Panel HudFragStreak = NewPanel; HudSettings.FragStreak = HudFragStreak; + + pos = [pos_x, pos_y - 2 - 24]; + fill = [50, 26]; + + GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + FO_Hud_Panel HudCaps = NewPanel; + HudSettings.Caps = HudCaps; } float firstrun; @@ -124,15 +131,7 @@ void FO_Hud_Editor_LoadSettings() count = tokenizebyseparator(field, "."); string pnl; pnl = argv(0); - switch (pnl) - { - case "hudclipsize": - DrawPanel = HudSettings.ClipSize; - break; - case "hudfragstreak": - DrawPanel = HudSettings.FragStreak; - break; - } + GetDrawPanel(pnl); switch (argv(1)) { @@ -153,17 +152,7 @@ void FO_Hud_Editor_LoadSettings() break; } - // is this necessary? how does qc copy - switch (pnl) - { - case "hudclipsize": - HudSettings.ClipSize = DrawPanel; - break; - case "hudfragstreak": - HudSettings.FragStreak = DrawPanel; - break; - } - + SetDrawPanel(pnl); break; } } @@ -296,10 +285,13 @@ void Hud_Draw(float width, float height) Hud_DrawFlagStatusBar(width); DrawPanel = HudSettings.ClipSize; - Hud_DrawPanelLMP("clipsizepanel", SBAR.ClipSize, HudIcons[13].icon); + Hud_DrawPanelLMP("clipsizepanel", SBAR.ClipSize, HudIcons[10].icon); DrawPanel = HudSettings.FragStreak; - Hud_DrawPanelLMP("fragstreakpanel", ftos(SBAR.FragStreak), HudIcons[12].icon); + Hud_DrawPanelLMP("fragstreakpanel", ftos(SBAR.FragStreak), HudIcons[11].icon); + + DrawPanel = HudSettings.Caps; + Hud_DrawPanelLMP("capspanel", ftos(SBAR.Caps), HudIcons[12].icon); HudSettings.MousePos = [Mouse.x, Mouse.y]; } \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 1c1898c2..2f6e562c 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -30,6 +30,44 @@ float(string id, vector pos, vector size, string text) hud_button = return sui_is_clicked(id); }; +void GetDrawPanel(string id) +{ + switch (id) + { + case "hudclipsize": + case "clipsizepanel": + DrawPanel = HudSettings.ClipSize; + break; + case "hudfragstreak": + case "fragstreakpanel": + DrawPanel = HudSettings.FragStreak; + break; + case "hudcaps": + case "capspanel": + DrawPanel = HudSettings.Caps; + break; + } +} + +void SetDrawPanel(string id) +{ + switch (id) + { + case "hudclipsize": + case "clipsizepanel": + HudSettings.ClipSize = DrawPanel; + break; + case "hudfragstreak": + case "fragstreakpanel": + HudSettings.FragStreak = DrawPanel; + break; + case "hudcaps": + case "capspanel": + HudSettings.Caps = DrawPanel; + break; + } +} + vector UpdatePos(string id, vector mousepos) { vector pos; @@ -42,12 +80,11 @@ vector UpdatePos(string id, vector mousepos) HudSettings.FlagIcon.Position = pos; } break; - case "clipsizepanel": - if (HudSettings.MousePos != [0, 0]) - { - pos = HudSettings.ClipSize.Position + mousepos - HudSettings.MousePos; - HudSettings.ClipSize.Position = pos; - } + default: + GetDrawPanel(id); + pos = DrawPanel.Position + mousepos - HudSettings.MousePos; + DrawPanel.Position = pos; + SetDrawPanel(id); break; } @@ -193,6 +230,9 @@ void Hud_WriteCfg(string path) DrawPanel = HudSettings.FragStreak; line = GetPanelString(line, "hudfragstreak"); + DrawPanel = HudSettings.Caps; + line = GetPanelString(line, "hudcaps"); + fputs(filehandle, line); fclose(filehandle); } \ No newline at end of file From b7931e23a540cb675da71b86adc1abe9fe73d8f1 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 6 Aug 2019 19:13:44 +1000 Subject: [PATCH 0768/2474] gren1 and gren2 panels --- csqc/csextradefs.qc | 2 ++ csqc/hud.qc | 24 +++++++++++++++++++++++- csqc/hud_helpers.qc | 21 +++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 537b2ff3..c5fe1d00 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -52,6 +52,8 @@ typedef struct { FO_Hud_Panel ClipSize; FO_Hud_Panel FragStreak; FO_Hud_Panel Caps; + FO_Hud_Panel Gren1; + FO_Hud_Panel Gren2; vector MousePos; } FO_Hud_Settings; FO_Hud_Settings HudSettings; diff --git a/csqc/hud.qc b/csqc/hud.qc index 84a08b71..3b3450af 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -71,6 +71,20 @@ void FO_Hud_Editor_LoadDefaultSettings() GetNewPanel(pos, fill, scale, display, nodeInsertLoc); FO_Hud_Panel HudCaps = NewPanel; HudSettings.Caps = HudCaps; + + pos = [pos_x, pos_y - 2 - 24]; + fill = [50, 26]; + + GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + FO_Hud_Panel HudGren1 = NewPanel; + HudSettings.Gren1 = HudGren1; + + pos = [pos_x, pos_y - 2 - 24]; + fill = [50, 26]; + + GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + FO_Hud_Panel HudGren2 = NewPanel; + HudSettings.Gren2 = HudGren2; } float firstrun; @@ -274,7 +288,7 @@ void Hud_DrawPanelLMP(string id, string val, string icon) float len; len = strlen(val); - float offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_AFTER) ? 2 + size_x : (2 + (size_x * len)) * -1; + float offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; pos = [pos_x + offset, pos_y, 0]; Hud_DrawStringLMP(pos, val, 24 * DrawPanel.Scale); @@ -293,5 +307,13 @@ void Hud_Draw(float width, float height) DrawPanel = HudSettings.Caps; Hud_DrawPanelLMP("capspanel", ftos(SBAR.Caps), HudIcons[12].icon); + // identify + + DrawPanel = HudSettings.Gren1; + Hud_DrawPanelLMP("gren1panel", ftos(SBAR.Gren1), HudIcons[13].icon); + + DrawPanel = HudSettings.Gren2; + Hud_DrawPanelLMP("gren2panel", ftos(SBAR.Gren2), HudIcons[14].icon); + HudSettings.MousePos = [Mouse.x, Mouse.y]; } \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 2f6e562c..f97cef2a 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -46,6 +46,14 @@ void GetDrawPanel(string id) case "capspanel": DrawPanel = HudSettings.Caps; break; + case "hudgren1": + case "gren1panel": + DrawPanel = HudSettings.Gren1; + break; + case "hudgren2": + case "gren2panel": + DrawPanel = HudSettings.Gren2; + break; } } @@ -65,6 +73,14 @@ void SetDrawPanel(string id) case "capspanel": HudSettings.Caps = DrawPanel; break; + case "hudgren1": + case "gren1panel": + HudSettings.Gren1 = DrawPanel; + break; + case "hudgren2": + case "gren2panel": + HudSettings.Gren2 = DrawPanel; + break; } } @@ -233,6 +249,11 @@ void Hud_WriteCfg(string path) DrawPanel = HudSettings.Caps; line = GetPanelString(line, "hudcaps"); + DrawPanel = HudSettings.Gren1; + line = GetPanelString(line, "hudgren1"); + DrawPanel = HudSettings.Gren2; + line = GetPanelString(line, "hudgren2"); + fputs(filehandle, line); fclose(filehandle); } \ No newline at end of file From aff9ef8dd3791c38f33f0fbfbe211fa0a1e36394 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 6 Aug 2019 22:11:48 +1200 Subject: [PATCH 0769/2474] Fix order of flaginfo icons; add basic button timer icons --- csqc/csextradefs.qc | 8 ++++++- csqc/hud.qc | 32 +++++++------------------ csqc/main.qc | 57 ++++++++++++++++++++++++++++++++++++++++++++- share/commondefs.qc | 3 +++ ssqc/client.qc | 19 +++++++++++---- ssqc/status.qc | 50 ++++++++++++++++++++++++++++++++++++--- 6 files changed, 137 insertions(+), 32 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d26844b0..7c568a85 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -13,6 +13,11 @@ typedef struct MouseStruct Mouse; +typedef struct { + string filename; + vector colour; +} HUDIcon; + typedef struct { float id; string message; @@ -23,6 +28,7 @@ typedef struct { vector loc; string carrier; string locname; + HUDIcon icon; } FlagInfoLine; FlagInfoLine FlagInfoLines[10]; @@ -51,4 +57,4 @@ FO_Hud_Settings HudSettings; #endif string(string s) strtrim = #0:strtrim; /* - Trims the whitespace from the start+end of the string. */ \ No newline at end of file + Trims the whitespace from the start+end of the string. */ diff --git a/csqc/hud.qc b/csqc/hud.qc index 5f91bc24..33ca6552 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -116,43 +116,29 @@ void Hud_Draw(float width, float height) pos = HudSettings.FlagIcon.Position; for (float i = FlagInfoLines.length - 1; i >= 0; i--) + //for (float i = 0; i < FlagInfoLines.length; i++) { if (FlagInfoLines[i].id) { - string icon = "sb_key1"; - vector iconcolour = '1 1 1'; - alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; - if (FlagInfoLines[i].model) { - switch (FlagInfoLines[i].model.owned_by) - { - case 2: - icon = "sb_key2"; - break; - case 3: - iconcolour = '1 1 0'; - break; - case 4: - icon = "sb_key2"; - iconcolour = '0 1 0'; - break; - } - } + alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; + string icon = FlagInfoLines[i].icon.filename; + vector iconcolour = FlagInfoLines[i].icon.colour; if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + 24, pos_y + 4 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], icon, '24 24 0', iconcolour, alpha, 1); + drawpic([pos_x, pos_y + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], icon, '24 24 0', iconcolour, alpha, 1); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } } -} \ No newline at end of file +} diff --git a/csqc/main.qc b/csqc/main.qc index c7e3156a..1e52b03c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -102,9 +102,10 @@ noref void CSQC_Input_Frame() } void() CSQC_Parse_Event = { - //print("CSQC_Parse_Event\n"); + //print("MEHT: CSQC_Parse_Event\n"); float msgtype = readbyte(); local float goalno; + //print("MEHT: CSQC_Parse_Event MessageType: ",ftos(msgtype),"\n"); switch (msgtype) { case MSG_FLAGINFOINIT: float index = readfloat(); @@ -112,6 +113,24 @@ void() CSQC_Parse_Event = { string mdl = readstring(); float skinindex = readfloat(); float ownerteam = readfloat(); + float iconindex = readfloat(); + print("MEHT: CSQC_Parse_Event index: ",ftos(index),"\n"); + print("MEHT: CSQC_Parse_Event goalno: ",ftos(goalno),"\n"); + print("MEHT: CSQC_Parse_Event mdl: ",mdl,"\n"); + print("MEHT: CSQC_Parse_Event skinindex: ",ftos(skinindex),"\n"); + print("MEHT: CSQC_Parse_Event team: ",ftos(ownerteam),"\n"); + print("MEHT: CSQC_Parse_Event icon: ",ftos(iconindex),"\n"); + + //use next available + if(index < 0) { + for(float i = 0; i < FlagInfoLines.length; i++) { + if(FlagInfoLines[i].id == 0) { + index = i; + break; + } + } + } + print("MEHT: CSQC_Parse_Event final index: ",ftos(index),"\n"); if(index >= 0 && index < MAX_FLAGINFO_LINES) { FlagInfoLines[index].id = goalno; FlagInfoLines[index].message = ""; @@ -126,6 +145,42 @@ void() CSQC_Parse_Event = { setsize(te, '-16 -16 0', '16 16 8'); te.skin = skinindex; te.owned_by = ownerteam; + + string iconname = "sb_key1"; + vector iconcolour = '1 1 1'; + if(iconindex == FLAGINFO_ICON_FLAG) { + //iconname = "sb_key1"; + //iconcolour = '1 1 1'; + switch (ownerteam) { + case 2: + iconname = "sb_key2"; + break; + case 3: + iconcolour = '1 1 0'; + break; + case 4: + iconname = "sb_key2"; + iconcolour = '0 1 0'; + break; + } + } else if(iconindex == FLAGINFO_ICON_BUTTON) { + iconname = "net"; + switch (ownerteam) { + case 1: + iconcolour = '0 0 0.5'; + case 2: + iconcolour = '1 0 0'; + break; + case 3: + iconcolour = '1 1 0'; + break; + case 4: + iconcolour = '0 1 0'; + break; + } + } + FlagInfoLines[index].icon.filename = iconname; + FlagInfoLines[index].icon.colour = iconcolour; FlagInfoLines[index].model = te; } break; diff --git a/share/commondefs.qc b/share/commondefs.qc index 6490dba8..807eba0c 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -9,3 +9,6 @@ #define FLAGINFO_RETURNING 4 #define FLAGINFO_LOCATION 5 #define FLAGINFO_NOLOCATION 6 + +#define FLAGINFO_ICON_FLAG 0 +#define FLAGINFO_ICON_BUTTON 1 diff --git a/ssqc/client.qc b/ssqc/client.qc index 251f9d88..ad485ae6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2332,10 +2332,21 @@ void (optional float csqcactive) ClientConnect = { } entity tfdet = find(world, classname, "info_tfdetect"); if(tfdet) { - InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1)); - InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2)); - InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3)); - InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4)); + InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4), FLAGINFO_ICON_FLAG); + } + bprint(PRINT_HIGH, "MEHT Client connected: ", self.netname, ", csqcactive: ",ftos(csqcactive),"\n"); + if(csqcactive) { + tfdet = find(world, classname, "info_tfgoal"); + while (tfdet) { + if (tfdet.track_goal) { + bprint(PRINT_HIGH, "MEHT Sending button info: ", tfdet.netname, "\n"); + InitClientFlagStatus(self, -1, tfdet, FLAGINFO_ICON_BUTTON); + } + tfdet = find(tfdet, classname, "info_tfgoal"); + } } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/status.qc b/ssqc/status.qc index fc00be2e..98926c88 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -580,7 +580,7 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr string getLocationName(vector location); -void (entity Player, float index, entity Item) InitClientFlagStatus = { +void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); if(csqcactive) { msg_entity = Player; @@ -591,9 +591,44 @@ void (entity Player, float index, entity Item) InitClientFlagStatus = { WriteString(MSG_MULTICAST, Item.mdl); WriteFloat(MSG_MULTICAST, Item.skin); WriteFloat(MSG_MULTICAST, Item.owned_by); + WriteFloat(MSG_MULTICAST, icon); multicast('0 0 0', MULTICAST_ONE_R); } } +float laststate; +void (entity Player, entity Goal) UpdateClientButtonStatus = { + //dprint("MEHT: changing state from ", ftos(laststate), " to ", ftos(Goal.goal_state), "\n"); + //dprint("MEHT: nextthink ", ftos(Goal.nextthink - time), " bubbles: ", ftos(rint(Goal.bubble_count - time)), "\n"); + msg_entity = Player; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAGINFO); + WriteFloat(MSG_MULTICAST, Goal.goal_no); + if(Goal.goal_no == 11) { + if(Goal.goal_state != laststate) { + bprint(PRINT_HIGH, "MEHT: changing state from ", ftos(laststate), " to ", ftos(Goal.goal_state), "\n"); + laststate = Goal.goal_state; + } + bprint(PRINT_HIGH, "MEHT: nextthink ", ftos(Goal.nextthink - time), " bubbles: ", ftos(rint(Goal.bubble_count - time)), "\n"); + } + if(Goal.goal_state == TFGS_DELAYED) { + WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); + WriteFloat(MSG_MULTICAST, rint(Goal.bubble_count - time)); + //WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); + WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); + WriteCoord(MSG_MULTICAST, Goal.origin_x); + WriteCoord(MSG_MULTICAST, Goal.origin_y); + WriteCoord(MSG_MULTICAST, Goal.origin_z); + //WriteString(MSG_MULTICAST, getLocationName(Item.origin)); + if(Goal.team_str_moved) { + WriteString(MSG_MULTICAST, Goal.team_str_moved); + } else { + WriteString(MSG_MULTICAST,"\sOffline\s"); + } + } else { + WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); + } + multicast('0 0 0', MULTICAST_ONE); +} void (entity Player, entity Item) UpdateClientFlagStatus = { msg_entity = Player; @@ -702,6 +737,7 @@ void (entity pl) RefreshStatusBar = { local entity tfdet; //info_tfdetect entity local entity te, tg; local string bi; //button info + local float csqcactive; //By default, show after tips; 0/off = off; 2 = always local float sbflaginfostate = FO_GetUserSetting(pl, "sbflaginfo", "sbflaginfo", "on"); /* local float win, sec; */ @@ -738,7 +774,7 @@ void (entity pl) RefreshStatusBar = { pl.display_tip = 0; tfdet = find(world, classname, "info_tfdetect"); - float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); + csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); // we get flag info from tfdetect if (!tfdet || (!sbflaginfostate && !csqcactive)) { @@ -769,6 +805,13 @@ void (entity pl) RefreshStatusBar = { UpdateClientFlagStatus(pl, te); } } + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.track_goal) { + UpdateClientButtonStatus(pl, tg); + } + tg = find(tg, classname, "info_tfgoal"); + } } else // no csqc but has sbflaginfo on { @@ -809,9 +852,10 @@ void (entity pl) RefreshStatusBar = { } ct = strcat(ct, "\n"); } +// dprint("MEHT: checking track_goals for ", pl.netname, ", csqc: ", ftos(csqcactive), "\n"); tg = find(world, classname, "info_tfgoal"); while (tg) { - if (tg.track_goal && tg.goal_state == TFGS_DELAYED && i < 6) { + if (tg.track_goal && i < 6 && tg.goal_state == TFGS_DELAYED) { bi = ""; //only do this for named goals, otherwise there's no way to distinguish them (they don't ususally have owned_by or anything) if(tg.netname) { From 23fdb7a2e9f11b323829fd455b65f5eacf0ec5ef Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 6 Aug 2019 22:53:51 +1200 Subject: [PATCH 0770/2474] Remove debug messages, fix hud editor bounds --- csqc/hud.qc | 12 ++++++------ csqc/main.qc | 9 --------- ssqc/client.qc | 2 -- ssqc/status.qc | 5 ----- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 33ca6552..83c776b4 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -98,7 +98,7 @@ void Hud_Draw(float width, float height) { firstrun = FALSE; pos = HudSettings.FlagIcon.Position; - pos_y = pos_y - 4 - 24 * (flagInfoCount - 2); + pos_y = pos_y - 4;// - 24 * (flagInfoCount - 2); HudSettings.FlagIcon.Position = pos; } } @@ -116,28 +116,28 @@ void Hud_Draw(float width, float height) pos = HudSettings.FlagIcon.Position; for (float i = FlagInfoLines.length - 1; i >= 0; i--) - //for (float i = 0; i < FlagInfoLines.length; i++) { if (FlagInfoLines[i].id) { alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; string icon = FlagInfoLines[i].icon.filename; vector iconcolour = FlagInfoLines[i].icon.colour; + float yoffset = 24; if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], icon, '24 24 0', iconcolour, alpha, 1); + drawpic([pos_x, pos_y + 24 * (i - 1) + yoffset, 0], icon, '24 24 0', iconcolour, alpha, 1); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 + 24 * (i - 1) + 24 * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 + 24 * (i - 1) + yoffset, 0], stime, '6 6', '1 1 1', 1, 0); } } } diff --git a/csqc/main.qc b/csqc/main.qc index 1e52b03c..a031e27f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -102,10 +102,8 @@ noref void CSQC_Input_Frame() } void() CSQC_Parse_Event = { - //print("MEHT: CSQC_Parse_Event\n"); float msgtype = readbyte(); local float goalno; - //print("MEHT: CSQC_Parse_Event MessageType: ",ftos(msgtype),"\n"); switch (msgtype) { case MSG_FLAGINFOINIT: float index = readfloat(); @@ -114,12 +112,6 @@ void() CSQC_Parse_Event = { float skinindex = readfloat(); float ownerteam = readfloat(); float iconindex = readfloat(); - print("MEHT: CSQC_Parse_Event index: ",ftos(index),"\n"); - print("MEHT: CSQC_Parse_Event goalno: ",ftos(goalno),"\n"); - print("MEHT: CSQC_Parse_Event mdl: ",mdl,"\n"); - print("MEHT: CSQC_Parse_Event skinindex: ",ftos(skinindex),"\n"); - print("MEHT: CSQC_Parse_Event team: ",ftos(ownerteam),"\n"); - print("MEHT: CSQC_Parse_Event icon: ",ftos(iconindex),"\n"); //use next available if(index < 0) { @@ -130,7 +122,6 @@ void() CSQC_Parse_Event = { } } } - print("MEHT: CSQC_Parse_Event final index: ",ftos(index),"\n"); if(index >= 0 && index < MAX_FLAGINFO_LINES) { FlagInfoLines[index].id = goalno; FlagInfoLines[index].message = ""; diff --git a/ssqc/client.qc b/ssqc/client.qc index ad485ae6..9e6c5343 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2337,12 +2337,10 @@ void (optional float csqcactive) ClientConnect = { InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3), FLAGINFO_ICON_FLAG); InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4), FLAGINFO_ICON_FLAG); } - bprint(PRINT_HIGH, "MEHT Client connected: ", self.netname, ", csqcactive: ",ftos(csqcactive),"\n"); if(csqcactive) { tfdet = find(world, classname, "info_tfgoal"); while (tfdet) { if (tfdet.track_goal) { - bprint(PRINT_HIGH, "MEHT Sending button info: ", tfdet.netname, "\n"); InitClientFlagStatus(self, -1, tfdet, FLAGINFO_ICON_BUTTON); } tfdet = find(tfdet, classname, "info_tfgoal"); diff --git a/ssqc/status.qc b/ssqc/status.qc index 98926c88..a7f5ceea 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -597,18 +597,14 @@ void (entity Player, float index, entity Item, float icon) InitClientFlagStatus } float laststate; void (entity Player, entity Goal) UpdateClientButtonStatus = { - //dprint("MEHT: changing state from ", ftos(laststate), " to ", ftos(Goal.goal_state), "\n"); - //dprint("MEHT: nextthink ", ftos(Goal.nextthink - time), " bubbles: ", ftos(rint(Goal.bubble_count - time)), "\n"); msg_entity = Player; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_FLAGINFO); WriteFloat(MSG_MULTICAST, Goal.goal_no); if(Goal.goal_no == 11) { if(Goal.goal_state != laststate) { - bprint(PRINT_HIGH, "MEHT: changing state from ", ftos(laststate), " to ", ftos(Goal.goal_state), "\n"); laststate = Goal.goal_state; } - bprint(PRINT_HIGH, "MEHT: nextthink ", ftos(Goal.nextthink - time), " bubbles: ", ftos(rint(Goal.bubble_count - time)), "\n"); } if(Goal.goal_state == TFGS_DELAYED) { WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); @@ -852,7 +848,6 @@ void (entity pl) RefreshStatusBar = { } ct = strcat(ct, "\n"); } -// dprint("MEHT: checking track_goals for ", pl.netname, ", csqc: ", ftos(csqcactive), "\n"); tg = find(world, classname, "info_tfgoal"); while (tg) { if (tg.track_goal && i < 6 && tg.goal_state == TFGS_DELAYED) { From 0140c447d0c3763860132bb5fe0f48887015e1f4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 7 Aug 2019 00:55:37 +1200 Subject: [PATCH 0771/2474] use custom icons --- csqc/main.qc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index a031e27f..773f4e61 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -140,8 +140,9 @@ void() CSQC_Parse_Event = { string iconname = "sb_key1"; vector iconcolour = '1 1 1'; if(iconindex == FLAGINFO_ICON_FLAG) { - //iconname = "sb_key1"; - //iconcolour = '1 1 1'; + iconname = strcat("flag_", ftos(ownerteam));; + iconcolour = '1 1 1'; + /* switch (ownerteam) { case 2: iconname = "sb_key2"; @@ -154,7 +155,11 @@ void() CSQC_Parse_Event = { iconcolour = '0 1 0'; break; } + */ } else if(iconindex == FLAGINFO_ICON_BUTTON) { + iconname = strcat("off_icon_glow_", ftos(ownerteam));; + iconcolour = '1 1 1'; + /* iconname = "net"; switch (ownerteam) { case 1: @@ -169,6 +174,7 @@ void() CSQC_Parse_Event = { iconcolour = '0 1 0'; break; } + */ } FlagInfoLines[index].icon.filename = iconname; FlagInfoLines[index].icon.colour = iconcolour; From b29fd37739ad093cc6ab9e83520c1ac43f148019 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 6 Aug 2019 23:15:49 +1000 Subject: [PATCH 0772/2474] class panel for scout and sniper implemented --- csqc/csextradefs.qc | 4 + csqc/csprogs.src | 1 + csqc/hud.qc | 315 +++++++++++++++++++++++----------------- csqc/hud_helpers.qc | 222 ++++++++++++++++++---------- csqc/main.qc | 9 +- share/common_helpers.qc | 16 ++ share/commondefs.qc | 2 +- share/defs.h | 4 + ssqc/progs.src | 1 + ssqc/status.qc | 18 --- ssqc/world.qc | 2 + 11 files changed, 365 insertions(+), 229 deletions(-) create mode 100644 share/common_helpers.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c5fe1d00..9b4dda11 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -54,6 +54,7 @@ typedef struct { FO_Hud_Panel Caps; FO_Hud_Panel Gren1; FO_Hud_Panel Gren2; + FO_Hud_Panel PlayerClass; vector MousePos; } FO_Hud_Settings; FO_Hud_Settings HudSettings; @@ -136,7 +137,10 @@ FO_Hud_Icons HudIcons[16] = { {ICON_GREN2} }; +float team_no; + vector FO_Hud_Icon_Size = [24, 24, 0]; +vector FO_Hud_Icon_Font_Size = [24, 24, 0]; #pragma noref 1 #pragma warning error Q101 /*too many parms*/ diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 855f0396..47e57831 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -2,6 +2,7 @@ csdefs.qc csextradefs.qc ../share/commondefs.qc +../share/common_helpers.qc sui_sys.qc input.qc main.qc diff --git a/csqc/hud.qc b/csqc/hud.qc index 3b3450af..8193e79b 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,31 +1,99 @@ -void FO_Hud_Editor() +void GetDrawPanel(string id) { - if (fo_hud_editor) + switch (id) { - fo_hud_editor = FALSE; - setcursormode(FALSE); - - Hud_WriteCfg(FO_HUD_CONFIG_PATH); + case "hudclipsize": + case "clipsizepanel": + DrawPanel = HudSettings.ClipSize; + break; + case "hudfragstreak": + case "fragstreakpanel": + DrawPanel = HudSettings.FragStreak; + break; + case "hudcaps": + case "capspanel": + DrawPanel = HudSettings.Caps; + break; + case "hudgren1": + case "gren1panel": + DrawPanel = HudSettings.Gren1; + break; + case "hudgren2": + case "gren2panel": + DrawPanel = HudSettings.Gren2; + break; + case "hudplayerclass": + case "playerclasspanel": + DrawPanel = HudSettings.PlayerClass; + break; } - else +} + +void SetDrawPanel(string id) +{ + switch (id) { - fo_hud_editor = TRUE; - setcursormode(TRUE); + case "hudclipsize": + case "clipsizepanel": + HudSettings.ClipSize = DrawPanel; + break; + case "hudfragstreak": + case "fragstreakpanel": + HudSettings.FragStreak = DrawPanel; + break; + case "hudcaps": + case "capspanel": + HudSettings.Caps = DrawPanel; + break; + case "hudgren1": + case "gren1panel": + HudSettings.Gren1 = DrawPanel; + break; + case "hudgren2": + case "gren2panel": + HudSettings.Gren2 = DrawPanel; + break; + case "hudplayerclass": + case "playerclasspanel": + HudSettings.PlayerClass = DrawPanel; + break; } } -void GetNewPanel(vector pos, vector fillSize, float scale, float display, float nodeInsertLoc) + +void Hud_WriteCfg(string path) { - FO_Hud_Panel pnl; + // this overwrites + float filehandle; + filehandle = fopen(path, FILE_WRITE); + string line; + + line = FormatCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); + line = FormatCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); + line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); + line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); + line = FormatCfgString(line, "hudflagicon.display", ftos(HudSettings.FlagIcon.Display)); + + DrawPanel = HudSettings.ClipSize; + line = GetPanelString(line, "hudclipsize"); + + DrawPanel = HudSettings.FragStreak; + line = GetPanelString(line, "hudfragstreak"); + + DrawPanel = HudSettings.Caps; + line = GetPanelString(line, "hudcaps"); + + DrawPanel = HudSettings.Gren1; + line = GetPanelString(line, "hudgren1"); + DrawPanel = HudSettings.Gren2; + line = GetPanelString(line, "hudgren2"); - pnl.Position = pos; - pnl.FillSize = fillSize; - pnl.Scale = scale; - pnl.Display = display; - pnl.NodeInsertLoc = nodeInsertLoc; + DrawPanel = HudSettings.PlayerClass; + line = GetPanelString(line, "hudplayerclass"); - NewPanel = pnl; + fputs(filehandle, line); + fclose(filehandle); } void FO_Hud_Editor_LoadDefaultSettings() @@ -85,100 +153,14 @@ void FO_Hud_Editor_LoadDefaultSettings() GetNewPanel(pos, fill, scale, display, nodeInsertLoc); FO_Hud_Panel HudGren2 = NewPanel; HudSettings.Gren2 = HudGren2; -} - -float firstrun; -void FO_Hud_Editor_LoadSettings() -{ - vector vsize = (vector)getproperty(VF_SCREENVSIZE); - float width = vsize_x; - float height = vsize_y; - fo_hud_editor = FALSE; - - FO_Hud_Editor_LoadDefaultSettings(); - - HudSettings.MousePos = [0, 0]; - firstrun = TRUE; - // fte does weird stuff and writes/reads this to/from a "gamedir/data/file" - float filehandle; - filehandle = fopen(FO_HUD_CONFIG_PATH, FILE_READ); - if (filehandle >= 0) { - // get number of lines - string ln; - ln = fgets(filehandle); - while (ln) - { - if (strlen(ln) > 0) - { - ln = strreplace("\n", "", ln); - string val, field; - - float x = 0, y = 0; - float count = tokenizebyseparator(ln, ":"); - field = argv(0); - field = strtrim(field); - val = argv(1); - val = strtrim(val); + pos = [pos_x, pos_y - 2 - 24]; + fill = [50, 26]; + nodeInsertLoc = FO_HUD_INSERT_AFTER; - switch(field) - { - case "hudflagicon.position": - count = tokenizebyseparator(val, ","); - x = stof(argv(0)); - y = stof(argv(1)); - HudSettings.FlagIcon.Position = [x, y]; - break; - case "hudflagicon.scale": - HudSettings.FlagIcon.Scale = stof(val); - break; - case "hudflagicon.growdirection": - HudSettings.FlagIcon.GrowDirection = stof(val); - break; - case "hudflagicon.nodeinsertloc": - HudSettings.FlagIcon.NodeInsertLoc = stof(val); - break; - case "hudflagicon.display": - HudSettings.FlagIcon.Display = stof(val); - break; - default: - count = tokenizebyseparator(field, "."); - string pnl; - pnl = argv(0); - GetDrawPanel(pnl); - - switch (argv(1)) - { - case "position": - count = tokenizebyseparator(val, ","); - x = stof(argv(0)); - y = stof(argv(1)); - DrawPanel.Position = [x, y]; - break; - case "scale": - DrawPanel.Scale = stof(val); - break; - case "display": - DrawPanel.Display = stof(val); - break; - case "nodeinsertloc": - DrawPanel.NodeInsertLoc = stof(val); - break; - } - - SetDrawPanel(pnl); - break; - } - } - ln = fgets(filehandle); - } - fclose(filehandle); - } - else - { - // write a new file - Hud_WriteCfg(FO_HUD_CONFIG_PATH); - } + GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + FO_Hud_Panel HudPlayerClass = NewPanel; + HudSettings.PlayerClass = HudPlayerClass; } void Hud_DrawFlagStatusBar(float width) @@ -264,56 +246,127 @@ void Hud_DrawFlagStatusBar(float width) } } -// draws value string using lmps -void Hud_DrawPanelLMP(string id, string val, string icon) +void Hud_DrawClassInfoPanel(string id, float playerclass) { if (!DrawPanel.Display) return; - vector pos; - pos = DrawPanel.Position; + switch (SBAR.PlayerClass) + { + case PC_SOLDIER: + case PC_PYRO: + return; + } - if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) + if (SBAR.PlayerClass) { - // click event - if (fo_hud_editor) + vector pos; + pos = DrawPanel.Position; + + if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) { + // click event + if (fo_hud_editor) + { + } } - } - vector size = FO_Hud_Icon_Size * DrawPanel.Scale; - pos = [pos_x + 2, pos_y + 2, 0]; - drawpic(pos, icon, size, '1 1 1', 1, 1); + float val; + vector size = FO_Hud_Icon_Size * DrawPanel.Scale; + vector fontSize = FO_Hud_Icon_Font_Size * DrawPanel.Scale; + pos = [pos_x + 2, pos_y + 2, 0]; + vector basepos = pos; + string icon = ""; + string msg = ""; - float len; - len = strlen(val); - float offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + icon = HudIcons[playerclass-1].icon; + drawpic(pos, icon, size, '1 1 1', 1, 1); + + float len = 0, offset = 0; + + switch (playerclass) + { + case PC_SCOUT: + msg = SBAR.ScannerOn ? "Scanning" : "Offline"; + len = strlen(msg); + offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + pos = [pos_x + offset, pos_y, 0]; + drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + if (SBAR.ScannerOn) + { + msg = SBAR.ScannerRange ? strcat("Dist: ", ftos(SBAR.ScannerRange)) : "No targets"; + len = strlen(msg); + offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + pos = [basepos_x + offset, pos_y + 2 + fontSize_y, 0]; + drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + if (SBAR.ScannerRange) + { + msg = (SBAR.ScannerTeamNo == team_no) ? "Friendly" : "Enemy"; + msg = strcat(msg, " ", ClassToString(SBAR.ScannerPlayerClass)); + len = strlen(msg); + offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + pos = [basepos_x + offset, pos_y + 2 + fontSize_y, 0]; + drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + } + } + break; + case PC_SNIPER: + if (SBAR.SniperDam) + { + msg = strcat("Dam: ", ftos(SBAR.SniperDam)); + len = strlen(msg); + offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + pos = [pos_x + offset, pos_y, 0]; + drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + + if (SBAR.SniperMax) + { + msg = "(100%)"; + len = strlen(msg); + offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + pos = [basepos_x + offset, pos_y + 2 + fontSize_y, 0]; + drawstring(pos, msg, fontSize, '0 0 1', 1, 0); + } + } + break; + case PC_DEMOMAN: - pos = [pos_x + offset, pos_y, 0]; - Hud_DrawStringLMP(pos, val, 24 * DrawPanel.Scale); + break; + } + + } } void Hud_Draw(float width, float height) { Hud_DrawFlagStatusBar(width); - DrawPanel = HudSettings.ClipSize; - Hud_DrawPanelLMP("clipsizepanel", SBAR.ClipSize, HudIcons[10].icon); + if (SBAR.ClipSize) + { + GetDrawPanel("clipsizepanel"); + Hud_DrawPanelLMP("clipsizepanel", SBAR.ClipSize, HudIcons[10].icon); + } - DrawPanel = HudSettings.FragStreak; + GetDrawPanel("fragstreakpanel"); Hud_DrawPanelLMP("fragstreakpanel", ftos(SBAR.FragStreak), HudIcons[11].icon); - DrawPanel = HudSettings.Caps; + GetDrawPanel("capspanel"); Hud_DrawPanelLMP("capspanel", ftos(SBAR.Caps), HudIcons[12].icon); // identify - DrawPanel = HudSettings.Gren1; + GetDrawPanel("gren1panel"); Hud_DrawPanelLMP("gren1panel", ftos(SBAR.Gren1), HudIcons[13].icon); - DrawPanel = HudSettings.Gren2; + GetDrawPanel("gren2panel"); Hud_DrawPanelLMP("gren2panel", ftos(SBAR.Gren2), HudIcons[14].icon); + if (SBAR.PlayerClass) + { + GetDrawPanel("playerclasspanel"); + Hud_DrawClassInfoPanel("playerclasspanel", SBAR.PlayerClass); + } + HudSettings.MousePos = [Mouse.x, Mouse.y]; } \ No newline at end of file diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index f97cef2a..29b2c915 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -14,6 +14,26 @@ vector MENU_TEXT_MEDIUM = '16 16 0'; vector MENU_TEXT_LARGE = '24 24 0'; float MENU_START_CONTENT = 32; +void Hud_WriteCfg(string path); +void GetDrawPanel(string id); +void SetDrawPanel(string id); + +void FO_Hud_Editor() +{ + if (fo_hud_editor) + { + fo_hud_editor = FALSE; + setcursormode(FALSE); + + Hud_WriteCfg(FO_HUD_CONFIG_PATH); + } + else + { + fo_hud_editor = TRUE; + setcursormode(TRUE); + } +} + float(string id, vector pos, vector size, string text) hud_button = { sui_push_frame(pos, size); @@ -30,60 +50,6 @@ float(string id, vector pos, vector size, string text) hud_button = return sui_is_clicked(id); }; -void GetDrawPanel(string id) -{ - switch (id) - { - case "hudclipsize": - case "clipsizepanel": - DrawPanel = HudSettings.ClipSize; - break; - case "hudfragstreak": - case "fragstreakpanel": - DrawPanel = HudSettings.FragStreak; - break; - case "hudcaps": - case "capspanel": - DrawPanel = HudSettings.Caps; - break; - case "hudgren1": - case "gren1panel": - DrawPanel = HudSettings.Gren1; - break; - case "hudgren2": - case "gren2panel": - DrawPanel = HudSettings.Gren2; - break; - } -} - -void SetDrawPanel(string id) -{ - switch (id) - { - case "hudclipsize": - case "clipsizepanel": - HudSettings.ClipSize = DrawPanel; - break; - case "hudfragstreak": - case "fragstreakpanel": - HudSettings.FragStreak = DrawPanel; - break; - case "hudcaps": - case "capspanel": - HudSettings.Caps = DrawPanel; - break; - case "hudgren1": - case "gren1panel": - HudSettings.Gren1 = DrawPanel; - break; - case "hudgren2": - case "gren2panel": - HudSettings.Gren2 = DrawPanel; - break; - } -} - vector UpdatePos(string id, vector mousepos) { vector pos; @@ -227,33 +193,139 @@ string GetPanelString(string line, string name) return line; } -void Hud_WriteCfg(string path) +float firstrun; +void FO_Hud_Editor_LoadSettings() { - // this overwrites + vector vsize = (vector)getproperty(VF_SCREENVSIZE); + float width = vsize_x; + float height = vsize_y; + fo_hud_editor = FALSE; + + FO_Hud_Editor_LoadDefaultSettings(); + + HudSettings.MousePos = [0, 0]; + firstrun = TRUE; + + // fte does weird stuff and writes/reads this to/from a "gamedir/data/file" float filehandle; - filehandle = fopen(path, FILE_WRITE); - string line; + filehandle = fopen(FO_HUD_CONFIG_PATH, FILE_READ); + if (filehandle >= 0) { + // get number of lines + string ln; + ln = fgets(filehandle); + while (ln) + { + if (strlen(ln) > 0) + { + ln = strreplace("\n", "", ln); + string val, field; - line = FormatCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); - line = FormatCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); - line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); - line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); - line = FormatCfgString(line, "hudflagicon.display", ftos(HudSettings.FlagIcon.Display)); + float x = 0, y = 0; + float count = tokenizebyseparator(ln, ":"); + field = argv(0); + field = strtrim(field); + val = argv(1); + val = strtrim(val); - DrawPanel = HudSettings.ClipSize; - line = GetPanelString(line, "hudclipsize"); + switch(field) + { + case "hudflagicon.position": + count = tokenizebyseparator(val, ","); + x = stof(argv(0)); + y = stof(argv(1)); + HudSettings.FlagIcon.Position = [x, y]; + break; + case "hudflagicon.scale": + HudSettings.FlagIcon.Scale = stof(val); + break; + case "hudflagicon.growdirection": + HudSettings.FlagIcon.GrowDirection = stof(val); + break; + case "hudflagicon.nodeinsertloc": + HudSettings.FlagIcon.NodeInsertLoc = stof(val); + break; + case "hudflagicon.display": + HudSettings.FlagIcon.Display = stof(val); + break; + default: + count = tokenizebyseparator(field, "."); + string pnl; + pnl = argv(0); + GetDrawPanel(pnl); - DrawPanel = HudSettings.FragStreak; - line = GetPanelString(line, "hudfragstreak"); + switch (argv(1)) + { + case "position": + count = tokenizebyseparator(val, ","); + x = stof(argv(0)); + y = stof(argv(1)); + DrawPanel.Position = [x, y]; + break; + case "scale": + DrawPanel.Scale = stof(val); + break; + case "display": + DrawPanel.Display = stof(val); + break; + case "nodeinsertloc": + DrawPanel.NodeInsertLoc = stof(val); + break; + } + + SetDrawPanel(pnl); + break; + } + } + ln = fgets(filehandle); + } + fclose(filehandle); + } + else + { + // write a new file + Hud_WriteCfg(FO_HUD_CONFIG_PATH); + } +} + +void GetNewPanel(vector pos, vector fillSize, float scale, float display, float nodeInsertLoc) +{ + FO_Hud_Panel pnl; + + pnl.Position = pos; + pnl.FillSize = fillSize; + pnl.Scale = scale; + pnl.Display = display; + pnl.NodeInsertLoc = nodeInsertLoc; + + NewPanel = pnl; +} + +// draws value string using lmps +void Hud_DrawPanelLMP(string id, string val, string icon) +{ + if (!DrawPanel.Display) + return; + + vector pos; + pos = DrawPanel.Position; + + if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) + { + // click event + if (fo_hud_editor) + { + + } + } - DrawPanel = HudSettings.Caps; - line = GetPanelString(line, "hudcaps"); + vector size = FO_Hud_Icon_Size * DrawPanel.Scale; + pos = [pos_x + 2, pos_y + 2, 0]; + drawpic(pos, icon, size, '1 1 1', 1, 1); - DrawPanel = HudSettings.Gren1; - line = GetPanelString(line, "hudgren1"); - DrawPanel = HudSettings.Gren2; - line = GetPanelString(line, "hudgren2"); + float len; + len = strlen(val); + float offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; - fputs(filehandle, line); - fclose(filehandle); + pos = [pos_x + offset, pos_y, 0]; + Hud_DrawStringLMP(pos, val, 24 * DrawPanel.Scale); } \ No newline at end of file diff --git a/csqc/main.qc b/csqc/main.qc index f6069f38..ce544912 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -5,6 +5,10 @@ void FO_Hud_Editor_LoadDefaultSettings(); void FO_LoadSettings(); void FO_WriteSettings(); +void GetSelf() = { + self = findfloat(world, entnum, player_localentnum); +} + noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); @@ -29,6 +33,7 @@ noref void() CSQC_WorldLoaded = { } noref void(float width, float height, float menushown) CSQC_UpdateView = { + team_no = getstatf(STAT_TEAMNO); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -49,10 +54,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { sui_end(); } -void GetSelf() = { - self = findfloat(world, entnum, player_localentnum); -} - noref float(string cmd) CSQC_ConsoleCommand = { tokenize(cmd); float val; diff --git a/share/common_helpers.qc b/share/common_helpers.qc new file mode 100644 index 00000000..2851dce9 --- /dev/null +++ b/share/common_helpers.qc @@ -0,0 +1,16 @@ +string ClassToString(float num) +{ + if (num == 1) return "Scout"; + if (num == 2) return "Sniper"; + if (num == 3) return "Soldier"; + if (num == 4) return "Demoman"; + if (num == 5) return "Medic"; + if (num == 6) return "HWGuy"; + if (num == 7) return "Pyro"; + if (num == 8) return "Spy"; + if (num == 9) return "Engineer"; + if (num == 11) return "Civilian"; + if (num == 13) return "Sentry Gun"; + if (num == 14) return "Goal Item"; + return ""; +} \ No newline at end of file diff --git a/share/commondefs.qc b/share/commondefs.qc index 62b41af8..df5a811f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -10,4 +10,4 @@ #define FLAGINFO_DROPPED 3 #define FLAGINFO_RETURNING 4 #define FLAGINFO_LOCATION 5 -#define FLAGINFO_NOLOCATION 6 +#define FLAGINFO_NOLOCATION 6 \ No newline at end of file diff --git a/share/defs.h b/share/defs.h index f0ef1c10..41dd1815 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1338,3 +1338,7 @@ #define ICON_SPY "progs/gfx/hud/spy.png" #define ICON_ENGINEER_SG "progs/gfx/hud/engineer_sg.png" #define ICON_ENGINEER_DISP "progs/gfx/hud/engineer_disp.png" + +// stats +// first 32 are reserved +#define STAT_TEAMNO 33 \ No newline at end of file diff --git a/ssqc/progs.src b/ssqc/progs.src index 7e376fcd..b2769e94 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -4,6 +4,7 @@ ../share/fteextensions.qc defs.qc ../share/commondefs.qc +../share/common_helpers.qc qw.qc q3defs.qc debug.qc diff --git a/ssqc/status.qc b/ssqc/status.qc index d113e342..8c14cc63 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1255,24 +1255,6 @@ string(float num) TeamToString = return " "; }; -string(float num) ClassToString = -{ - if (num == 1) return "Scout"; - if (num == 2) return "Sniper"; - if (num == 3) return "Soldier"; - if (num == 4) return "Demoman"; - if (num == 5) return "Medic"; - if (num == 6) return "HWGuy"; - if (num == 7) return "Pyro"; - if (num == 8) return "Spy"; - if (num == 9) return "Engineer"; - if (num == 11) return "Civilian"; - if (num == 13) return "Sentry Gun"; - if (num == 14) return "Goal Item"; - return ""; -}; - - string(entity pl) DisguiseToString = { local string st = ""; diff --git a/ssqc/world.qc b/ssqc/world.qc index dbf4d1fd..14a17899 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -313,6 +313,8 @@ void () worldspawn = { lightstyle(10, "mmamammmmammamamaaamammma"); lightstyle(11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); lightstyle(63, "a"); + + clientstat(STAT_TEAMNO, EV_FLOAT, team_no); }; void () StartFrame = { From 0f76b7160d46a9a53a73fbb2b911b433ca4a7620 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 7 Aug 2019 12:03:06 +1000 Subject: [PATCH 0773/2474] all class info in --- csqc/hud.qc | 156 ++++++++++++++++++++++++++++++++++------ csqc/hud_helpers.qc | 19 +++++ share/common_helpers.qc | 9 +++ ssqc/status.qc | 9 --- 4 files changed, 164 insertions(+), 29 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 8193e79b..ede79eaa 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -277,6 +277,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) vector fontSize = FO_Hud_Icon_Font_Size * DrawPanel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; vector basepos = pos; + vector colour = '1 1 1'; string icon = ""; string msg = ""; @@ -289,25 +290,16 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) { case PC_SCOUT: msg = SBAR.ScannerOn ? "Scanning" : "Offline"; - len = strlen(msg); - offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; - pos = [pos_x + offset, pos_y, 0]; - drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.ScannerOn) { msg = SBAR.ScannerRange ? strcat("Dist: ", ftos(SBAR.ScannerRange)) : "No targets"; - len = strlen(msg); - offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; - pos = [basepos_x + offset, pos_y + 2 + fontSize_y, 0]; - drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); if (SBAR.ScannerRange) { msg = (SBAR.ScannerTeamNo == team_no) ? "Friendly" : "Enemy"; msg = strcat(msg, " ", ClassToString(SBAR.ScannerPlayerClass)); - len = strlen(msg); - offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; - pos = [basepos_x + offset, pos_y + 2 + fontSize_y, 0]; - drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); } } break; @@ -315,23 +307,147 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) if (SBAR.SniperDam) { msg = strcat("Dam: ", ftos(SBAR.SniperDam)); - len = strlen(msg); - offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; - pos = [pos_x + offset, pos_y, 0]; - drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.SniperMax) { msg = "(100%)"; - len = strlen(msg); - offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; - pos = [basepos_x + offset, pos_y + 2 + fontSize_y, 0]; - drawstring(pos, msg, fontSize, '0 0 1', 1, 0); + colour = '1 0 0'; + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); } } break; case PC_DEMOMAN: + if (SBAR.IsDetpacking) + { + msg = "Setting"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + msg = strcat(ftos(SBAR.DetpackLeft), " (", ftos(SBAR.IsDetpacking), ") secs left"); + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + } + else if (SBAR.DetpackLeft) + { + msg = strcat(ftos(SBAR.DetpackLeft), " secs left"); + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } + break; + case PC_MEDIC: + msg = SBAR.AuraActive ? "On" : "Off"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + if (SBAR.AuraActive) + { + if (SBAR.HealCount) + { + msg = strcat(ftos(SBAR.HealCount), " players healed"); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + + msg = strcat("for ", ftos(SBAR.HealAmount), " hp"); + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + } + else + { + if (SBAR.AuraStatus == PC_MEDIC_AURA_OUTOFPOWER) + { + msg = "Out of power"; + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + } + else if (SBAR.AuraStatus == PC_MEDIC_AURA_RECHARGING) + { + msg = "Recharging"; + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + } + } + } + break; + case PC_HVYWEAP: + if (SBAR.LockedCannon) + { + msg = "Assault Cannon Locked"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } + break; + case PC_SPY: + if (SBAR.IsUndercover == 1) + { + if (SBAR.InvisOnly) + { + msg = "Invisible"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } + else + { + msg = "Undercover"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + msg = strcat(TeamToString(SBAR.UndercoverTeam), " ", ClassToString(SBAR.UndercoverSkin)); + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + } + } + else if (SBAR.IsUndercover == 2) + { + if (SBAR.InvisOnly) + { + msg = "Invisible"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + msg = strcat("In ", ftos(SBAR.UndercoverTimer), " secs"); + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + } + else + { + msg = "Disguising"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + if (SBAR.DisguiseTeam) + { + msg = strcat("(", TeamToString(SBAR.DisguiseTeam), SBAR.QueueSkin ? "" : ") "); + } + else if (SBAR.QueueTeam) + { + msg = strcat("(", TeamToString(SBAR.QueueTeam), " "); + } + else if (SBAR.UndercoverTeam) + { + msg = strcat(TeamToString(SBAR.UndercoverTeam), " "); + } + string msg2 = ""; + if (SBAR.DisguiseSkin) + { + msg2 = strcat(SBAR.QueueTeam ? "" : "(", ClassToString(SBAR.DisguiseSkin), ")"); + } + else if (SBAR.QueueSkin) + { + msg2 = strcat(" ", ClassToString(SBAR.QueueSkin), ")"); + } + else if (SBAR.UndercoverSkin) + { + msg2 = strcat(ClassToString(SBAR.UndercoverSkin)); + } + msg = strcat(msg, msg2); + DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + } + } + break; + case PC_ENGINEER: + if (SBAR.HasSentry) + { + msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(SBAR.SentryHealth), " S: ", ftos(SBAR.SentryAmmoShells), " R: ", ftos(SBAR.SentryAmmoRockets)); + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } + else if (SBAR.IsBuilding) + { + msg = strcat(ftos(SBAR.BuildingPercentage), "%"); + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } + + // disp + pos = [pos_x, pos_y - size_y - 2]; + basepos = pos; + icon = HudIcons[playerclass].icon; + drawpic(pos, icon, size, '1 1 1', 1, 1); + if (SBAR.HasDispenser) + { + msg = strcat("H: ", ftos(SBAR.DispenserHealth)); + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } break; } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 29b2c915..45a20cc3 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -328,4 +328,23 @@ void Hud_DrawPanelLMP(string id, string val, string icon) pos = [pos_x + offset, pos_y, 0]; Hud_DrawStringLMP(pos, val, 24 * DrawPanel.Scale); +} + + +vector GetStringOffsetPos(string msg, vector size, vector fontSize, vector pos, vector basepos, float newline) +{ + float len, offset; + len = strlen(msg); + offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + pos = [basepos_x + offset, newline ? pos_y + 2 + fontSize_y : pos_y, 0]; + + return pos; +} + +vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, vector basepos, float newline, vector colour) +{ + pos = GetStringOffsetPos(msg, size, fontSize, pos, basepos, newline); + drawstring(pos, msg, fontSize, colour, 1, 0); + + return pos; } \ No newline at end of file diff --git a/share/common_helpers.qc b/share/common_helpers.qc index 2851dce9..33ac352f 100644 --- a/share/common_helpers.qc +++ b/share/common_helpers.qc @@ -13,4 +13,13 @@ string ClassToString(float num) if (num == 13) return "Sentry Gun"; if (num == 14) return "Goal Item"; return ""; +} + +string TeamToString(float num) +{ + if (num == 1) return "Blue"; + if (num == 2) return "Red"; + if (num == 3) return "Yellow"; + if (num == 4) return "Green"; + return " "; } \ No newline at end of file diff --git a/ssqc/status.qc b/ssqc/status.qc index 8c14cc63..a060f43b 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1246,15 +1246,6 @@ float GetClipSize(entity pl) } } -string(float num) TeamToString = -{ - if (num == 1) return "Blue"; - if (num == 2) return "Red"; - if (num == 3) return "Yellow"; - if (num == 4) return "Green"; - return " "; -}; - string(entity pl) DisguiseToString = { local string st = ""; From 506ca051e1f6a2c4939d372fa6bafd91d0b0f4d9 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 7 Aug 2019 12:16:29 +1000 Subject: [PATCH 0774/2474] make font small for hud elements --- csqc/csextradefs.qc | 2 +- csqc/hud.qc | 15 +++++++-------- csqc/hud_helpers.qc | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9b4dda11..9bbfe997 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -140,7 +140,7 @@ FO_Hud_Icons HudIcons[16] = { float team_no; vector FO_Hud_Icon_Size = [24, 24, 0]; -vector FO_Hud_Icon_Font_Size = [24, 24, 0]; +vector FO_Hud_Icon_Font_Size = [8, 8, 0]; #pragma noref 1 #pragma warning error Q101 /*too many parms*/ diff --git a/csqc/hud.qc b/csqc/hud.qc index ede79eaa..2eb65de9 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -290,7 +290,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) { case PC_SCOUT: msg = SBAR.ScannerOn ? "Scanning" : "Offline"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.ScannerOn) { msg = SBAR.ScannerRange ? strcat("Dist: ", ftos(SBAR.ScannerRange)) : "No targets"; @@ -307,7 +307,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) if (SBAR.SniperDam) { msg = strcat("Dam: ", ftos(SBAR.SniperDam)); - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.SniperMax) { @@ -321,7 +321,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) if (SBAR.IsDetpacking) { msg = "Setting"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat(ftos(SBAR.DetpackLeft), " (", ftos(SBAR.IsDetpacking), ") secs left"); DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); @@ -334,7 +334,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) break; case PC_MEDIC: msg = SBAR.AuraActive ? "On" : "Off"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.AuraActive) { if (SBAR.HealCount) @@ -378,7 +378,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) else { msg = "Undercover"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat(TeamToString(SBAR.UndercoverTeam), " ", ClassToString(SBAR.UndercoverSkin)); DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); } @@ -388,14 +388,14 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) if (SBAR.InvisOnly) { msg = "Invisible"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat("In ", ftos(SBAR.UndercoverTimer), " secs"); DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); } else { msg = "Disguising"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.DisguiseTeam) { msg = strcat("(", TeamToString(SBAR.DisguiseTeam), SBAR.QueueSkin ? "" : ") "); @@ -450,7 +450,6 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } break; } - } } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 45a20cc3..aab73a04 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -335,8 +335,8 @@ vector GetStringOffsetPos(string msg, vector size, vector fontSize, vector pos, { float len, offset; len = strlen(msg); - offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; - pos = [basepos_x + offset, newline ? pos_y + 2 + fontSize_y : pos_y, 0]; + offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + size_x + (fontSize_x * len)) * -1; + pos = [basepos_x + offset, newline ? pos_y + 2 + ((size_y - fontSize_y) * .5) : pos_y + ((size_y - fontSize_y) * .5), 0]; return pos; } From c701ef16e2d0d835cc00b3c67fe34b7a70d6d780 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 7 Aug 2019 12:45:46 +1000 Subject: [PATCH 0775/2474] dodgy identify panel --- csqc/csextradefs.qc | 1 + csqc/hud.qc | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9bbfe997..f538d466 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -55,6 +55,7 @@ typedef struct { FO_Hud_Panel Gren1; FO_Hud_Panel Gren2; FO_Hud_Panel PlayerClass; + FO_Hud_Panel Identify; vector MousePos; } FO_Hud_Settings; FO_Hud_Settings HudSettings; diff --git a/csqc/hud.qc b/csqc/hud.qc index 2eb65de9..354773dd 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -27,6 +27,10 @@ void GetDrawPanel(string id) case "playerclasspanel": DrawPanel = HudSettings.PlayerClass; break; + case "hudidentify": + case "identifypanel": + DrawPanel = HudSettings.Identify; + break; } } @@ -58,6 +62,10 @@ void SetDrawPanel(string id) case "playerclasspanel": HudSettings.PlayerClass = DrawPanel; break; + case "hudidentify": + case "identifypanel": + HudSettings.Identify = DrawPanel; + break; } } @@ -92,6 +100,9 @@ void Hud_WriteCfg(string path) DrawPanel = HudSettings.PlayerClass; line = GetPanelString(line, "hudplayerclass"); + DrawPanel = HudSettings.Identify; + line = GetPanelString(line, "hudidentify"); + fputs(filehandle, line); fclose(filehandle); } @@ -161,6 +172,13 @@ void FO_Hud_Editor_LoadDefaultSettings() GetNewPanel(pos, fill, scale, display, nodeInsertLoc); FO_Hud_Panel HudPlayerClass = NewPanel; HudSettings.PlayerClass = HudPlayerClass; + + pos = [pos_x, pos_y - 2 - 24]; + fill = [50, 26]; + + GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + FO_Hud_Panel HudIdentify = NewPanel; + HudSettings.Identify = HudIdentify; } void Hud_DrawFlagStatusBar(float width) @@ -453,6 +471,27 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } } +void Hud_DrawIdentifyPanel(string id, string identify) +{ + if (!DrawPanel.Display) + return; + + vector pos; + pos = DrawPanel.Position; + + if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) + { + // click event + if (fo_hud_editor) + { + + } + } + + vector fontSize = FO_Hud_Icon_Font_Size * DrawPanel.Scale; + drawstring(pos, identify, fontSize, '1 1 1', 1, 0); +} + void Hud_Draw(float width, float height) { Hud_DrawFlagStatusBar(width); @@ -470,6 +509,11 @@ void Hud_Draw(float width, float height) Hud_DrawPanelLMP("capspanel", ftos(SBAR.Caps), HudIcons[12].icon); // identify + if (strlen(SBAR.Identify) > 0) + { + GetDrawPanel("identifypanel"); + Hud_DrawIdentifyPanel("identifypanel", SBAR.Identify); + } GetDrawPanel("gren1panel"); Hud_DrawPanelLMP("gren1panel", ftos(SBAR.Gren1), HudIcons[13].icon); From cfeaa3c8a426eb30dd79b3df110b2f63eac26a5a Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 7 Aug 2019 13:42:59 +1000 Subject: [PATCH 0776/2474] Revert "Track goals csqc" --- csqc/csextradefs.qc | 8 +-- csqc/events.qc | 132 +---------------------------------------- csqc/hud.qc | 35 ++++++----- csqc/main.qc | 2 + csqc/settings.qc | 6 +- docs/hud_statusbar.txt | 37 ------------ share/commondefs.qc | 3 - ssqc/client.qc | 17 ++---- ssqc/status.qc | 45 +------------- 9 files changed, 34 insertions(+), 251 deletions(-) delete mode 100644 docs/hud_statusbar.txt diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index a5c160ec..1e589a59 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -13,11 +13,6 @@ typedef struct MouseStruct Mouse; -typedef struct { - string filename; - vector colour; -} HUDIcon; - typedef struct { float id; string message; @@ -28,7 +23,6 @@ typedef struct { vector loc; string carrier; string locname; - HUDIcon icon; } FlagInfoLine; FlagInfoLine FlagInfoLines[10]; @@ -75,4 +69,4 @@ FO_Settings Settings; #endif string(string s) strtrim = #0:strtrim; /* - Trims the whitespace from the start+end of the string. */ + Trims the whitespace from the start+end of the string. */ \ No newline at end of file diff --git a/csqc/events.qc b/csqc/events.qc index 7ff39347..a45fef48 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,4 +1,3 @@ -/* void() CSQC_Parse_Event = { float msgtype = readbyte(); local float goalno; @@ -79,133 +78,4 @@ void() CSQC_Parse_Event = { default: print("CSQC_Parse_Event, unknown event: ",ftos(msgtype),"\n"); } -} -*/ -void() CSQC_Parse_Event = { - float msgtype = readbyte(); - local float goalno; - switch (msgtype) { - case MSG_FLAGINFOINIT: - float index = readfloat(); - goalno = readfloat(); - string mdl = readstring(); - float skinindex = readfloat(); - float ownerteam = readfloat(); - float iconindex = readfloat(); - - //use next available - if(index < 0) { - for(float i = 0; i < FlagInfoLines.length; i++) { - if(FlagInfoLines[i].id == 0) { - index = i; - break; - } - } - } - if(index >= 0 && index < MAX_FLAGINFO_LINES) { - FlagInfoLines[index].id = goalno; - FlagInfoLines[index].message = ""; - if(mdl) - precache_model(mdl); - entity te = spawn(); - te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; - te.origin = [5, 0, 0]; - te.angles = '-60 0 0'; - //setmodel(te,mdl); - //setmodel(te, "progs/weapons/v_rock.mdl"); - //setsize(te, '-16 -16 0', '16 16 8'); - te.skin = skinindex; - te.owned_by = ownerteam; - - string iconname = "sb_key1"; - vector iconcolour = '1 1 1'; - if(iconindex == FLAGINFO_ICON_FLAG) { - iconname = strcat("flag_", ftos(ownerteam)); - iconcolour = '1 1 1'; - /* - switch (ownerteam) { - case 2: - iconname = "sb_key2"; - break; - case 3: - iconcolour = '1 1 0'; - break; - case 4: - iconname = "sb_key2"; - iconcolour = '0 1 0'; - break; - } - */ - } else if(iconindex == FLAGINFO_ICON_BUTTON) { - iconname = strcat("off_icon_glow_", ftos(ownerteam)); - iconcolour = '1 1 1'; - /* - iconname = "net"; - switch (ownerteam) { - case 1: - iconcolour = '0 0 0.5'; - case 2: - iconcolour = '1 0 0'; - break; - case 3: - iconcolour = '1 1 0'; - break; - case 4: - iconcolour = '0 1 0'; - break; - } - */ - } - FlagInfoLines[index].icon.filename = iconname; - FlagInfoLines[index].icon.colour = iconcolour; - FlagInfoLines[index].model = te; - } - break; - case MSG_FLAGINFO: - string message = ""; - goalno = readfloat(); - float state = readfloat(); - float timeleft = -1; - vector droploc = '0 0 0'; - string carrier = ""; - string locname = ""; - switch (state) { - case FLAGINFO_HOME: - message = "^2HOME"; - break; - case FLAGINFO_CARRIED: - carrier = readstring(); - message = strcat("^1CARRIED^7 by ",carrier); - break; - case FLAGINFO_DROPPED: - message = "^3DROPPED^7"; - timeleft = readfloat(); - float showloc = readfloat(); - if(showloc == FLAGINFO_LOCATION) { - droploc_x = readcoord(); - droploc_y = readcoord(); - droploc_z = readcoord(); - //message = strcat(message," at ", vtos(droploc)); - locname = readstring(); - message = strcat(message," at ", locname); - } - //if(timeleft >= 0) { - //message = strcat(message," returning in ", ftos(timeleft)); - //} - break; - case FLAGINFO_RETURNING: - message = "^4RETURNING"; - break; - } - for(float i = 0; i < FlagInfoLines.length; i++) { - if(FlagInfoLines[i].id == goalno) { - FlagInfoLines[i].message = message; - FlagInfoLines[i].timeleft = timeleft; - FlagInfoLines[i].state = state; - FlagInfoLines[i].loc = droploc; - FlagInfoLines[i].carrier = carrier; - FlagInfoLines[i].locname = locname; - } - } - } -} +} \ No newline at end of file diff --git a/csqc/hud.qc b/csqc/hud.qc index 2c096269..3cfbb6aa 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -134,8 +134,6 @@ void Hud_DrawFlagStatusBar(float width) if (flagInfoCount > 0) { firstrun = FALSE; - pos = HudSettings.FlagIcon.Position; - //pos_y = pos_y - 4;// - 24 * (flagInfoCount - 2); pos_y = pos_y - 4 - sizey * (flagInfoCount - 2); HudSettings.FlagIcon.Position = pos; } @@ -156,20 +154,26 @@ void Hud_DrawFlagStatusBar(float width) { if (FlagInfoLines[i].id) { - alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; - string icon = FlagInfoLines[i].icon.filename; - vector iconcolour = FlagInfoLines[i].icon.colour; - float yoffset = 24; + string icon = "sb_key1"; + vector iconcolour = '1 1 1'; + alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; + if (FlagInfoLines[i].model) { + switch (FlagInfoLines[i].model.owned_by) + { + case 2: + icon = "sb_key2"; + break; + case 3: + iconcolour = '1 1 0'; + break; + case 4: + icon = "sb_key2"; + iconcolour = '0 1 0'; + break; + } + } if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { -// drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); -// } -// else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) -// { -// drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); -// } - -// drawpic([pos_x, pos_y + 24 * (i - 1) + yoffset, 0], icon, '24 24 0', iconcolour, alpha, 1); drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) @@ -182,7 +186,6 @@ void Hud_DrawFlagStatusBar(float width) if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); -// drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 + 24 * (i - 1) + yoffset, 0], stime, '6 6', '1 1 1', 1, 0); drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } @@ -213,4 +216,4 @@ void Hud_Draw(float width, float height) Hud_DrawClipSize(width); HudSettings.MousePos = [Mouse.x, Mouse.y]; -} +} \ No newline at end of file diff --git a/csqc/main.qc b/csqc/main.qc index 86cb59b9..8282e5e7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -111,3 +111,5 @@ noref void CSQC_Input_Frame() } } } + + diff --git a/csqc/settings.qc b/csqc/settings.qc index baba5065..9006cd02 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,7 +3,9 @@ void FO_WriteSettings() // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", "fo_autohop", ftos(Settings.Autohop)); + string line; + + line = FormatCfgString(line, "fo_autohop", ftos(Settings.Autohop)); fputs(filehandle, line); fclose(filehandle); @@ -54,4 +56,4 @@ void FO_LoadSettings() // write a new file FO_WriteSettings(); } -} +} \ No newline at end of file diff --git a/docs/hud_statusbar.txt b/docs/hud_statusbar.txt deleted file mode 100644 index 016a2a51..00000000 --- a/docs/hud_statusbar.txt +++ /dev/null @@ -1,37 +0,0 @@ -The status bar shows TF-specific info, and it works in different ways depending on the client: -For fte, it will detect that csqc is active and send messages directly to the csqc part of the client to display individual HUD icons and statuses. -For ezquake (and basically everything else), it will use a centerprint hack to permanently display the status bar. - -It can be enabled using the client setting - setinfo sb 40 -(or any positive integer). The integer is relevant for the non-fte version, as it dictates how many empty "lines" to skip before drawing it, thus allowing basic control of its veritcal position. - -A specific sub-component can be enabled using the command - setinfo sbflaginfo 1|2 -Setting it to 0 will turn it off, setting it to 1 will enable it, but only 6 seconds after spawn (after the class tips finish displaying) and a setting of 2 will make it permanent. - -The sb flaginfo will display the current status of any flags/item_tfgoals that have been tagged by the mapper. The logic is the same as the stock "flaginfo" command, which is marking up to 4 goalitems in the info_tfdetect -entity using the fields display_item_status1 - display_item_status4 using the items' goal_no numbers. This is further documented in the tf reference docs. -This does limit the number of trackable items to 4 however. -The flaginfo functionality is extended by having it also display who it's currenly carried by, or, if dropped, the location (based on the loc file) and time to return. -Note that currently, the item names are hard-coded to be "blue/red/yellow/green flag", to cover most cases, where mappers didn't necessarily name them nicely. - -The sb flaginfo component also displays the "button" countdowns (such as lasers/security being down), if available, and there is room. -This functions in a similar way to the flag info, but, while technically unlimited, -the combined number of all sbar items (flags and buttons) is 10 for fte and 6 for ezquake. -For ezquake, the buttons will be distinguished by name, and will not appear until they are actually triggered and have a countdown active. -For fte, the buttons are distinguished by team colours and will display a different icon to the flag, but otherwise function similarly. - -For a map to allow these to be tracked, the following needs to be set for each button: -- It must be set on an info_tfgoal entity -- It must have the field "track_goal" be set to 1 -- It must have a "goal_no" field set -- It must have the field "delay_time" set to the countdown time -- It must be triggered at the start of the countdown either via goal_no or targetname. It doesn't have to be part of the main trigger chain however. -- For ezquake, it must have a "netname" field set to distinguish the goals. -- For FTE, it should have the "owned_by" field set which will determine the icon colour. -- Optionally, it can have the field "team_str_moved" set to set a custom string to be displayed while the countdown is active. If not set, the default is "Offline". - -For FTE, the icons for the above are in the same location as the normal hud elements: -ie fortress/textures/wad/ -They are named "flag_" for the flag icons and "off_icon_glow_" for the button icons. diff --git a/share/commondefs.qc b/share/commondefs.qc index a943de70..257862f1 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -10,6 +10,3 @@ #define FLAGINFO_RETURNING 4 #define FLAGINFO_LOCATION 5 #define FLAGINFO_NOLOCATION 6 - -#define FLAGINFO_ICON_FLAG 0 -#define FLAGINFO_ICON_BUTTON 1 diff --git a/ssqc/client.qc b/ssqc/client.qc index 73989a66..4a9a3371 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2339,19 +2339,10 @@ void (optional float csqcactive) ClientConnect = { } entity tfdet = find(world, classname, "info_tfdetect"); if(tfdet) { - InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1), FLAGINFO_ICON_FLAG); - InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2), FLAGINFO_ICON_FLAG); - InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3), FLAGINFO_ICON_FLAG); - InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4), FLAGINFO_ICON_FLAG); - } - if(csqcactive) { - tfdet = find(world, classname, "info_tfgoal"); - while (tfdet) { - if (tfdet.track_goal) { - InitClientFlagStatus(self, -1, tfdet, FLAGINFO_ICON_BUTTON); - } - tfdet = find(tfdet, classname, "info_tfgoal"); - } + InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1)); + InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2)); + InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3)); + InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4)); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/status.qc b/ssqc/status.qc index fc78dbb9..65a13878 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -580,7 +580,7 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr string getLocationName(vector location); -void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { +void (entity Player, float index, entity Item) InitClientFlagStatus = { float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); if(csqcactive) { msg_entity = Player; @@ -591,40 +591,9 @@ void (entity Player, float index, entity Item, float icon) InitClientFlagStatus WriteString(MSG_MULTICAST, Item.mdl); WriteFloat(MSG_MULTICAST, Item.skin); WriteFloat(MSG_MULTICAST, Item.owned_by); - WriteFloat(MSG_MULTICAST, icon); multicast('0 0 0', MULTICAST_ONE_R); } } -float laststate; -void (entity Player, entity Goal) UpdateClientButtonStatus = { - msg_entity = Player; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_FLAGINFO); - WriteFloat(MSG_MULTICAST, Goal.goal_no); - if(Goal.goal_no == 11) { - if(Goal.goal_state != laststate) { - laststate = Goal.goal_state; - } - } - if(Goal.goal_state == TFGS_DELAYED) { - WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); - WriteFloat(MSG_MULTICAST, rint(Goal.bubble_count - time)); - //WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); - WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); - WriteCoord(MSG_MULTICAST, Goal.origin_x); - WriteCoord(MSG_MULTICAST, Goal.origin_y); - WriteCoord(MSG_MULTICAST, Goal.origin_z); - //WriteString(MSG_MULTICAST, getLocationName(Item.origin)); - if(Goal.team_str_moved) { - WriteString(MSG_MULTICAST, Goal.team_str_moved); - } else { - WriteString(MSG_MULTICAST,"\sOffline\s"); - } - } else { - WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); - } - multicast('0 0 0', MULTICAST_ONE); -} void (entity Player, entity Item) UpdateClientFlagStatus = { msg_entity = Player; @@ -763,7 +732,6 @@ void (entity pl) RefreshStatusBar = { local entity tfdet; //info_tfdetect entity local entity te, tg; local string bi; //button info - local float csqcactive; //By default, show after tips; 0/off = off; 2 = always local float sbflaginfostate = FO_GetUserSetting(pl, "sbflaginfo", "sbflaginfo", "on"); /* local float win, sec; */ @@ -793,7 +761,7 @@ void (entity pl) RefreshStatusBar = { pad = strcat(pad, "\n"); pad = strzone(pad); - csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); + float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); // class tip if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2) { @@ -832,13 +800,6 @@ void (entity pl) RefreshStatusBar = { UpdateClientFlagStatus(pl, te); } } - tg = find(world, classname, "info_tfgoal"); - while (tg) { - if (tg.track_goal) { - UpdateClientButtonStatus(pl, tg); - } - tg = find(tg, classname, "info_tfgoal"); - } } else // no csqc but has sbflaginfo on { @@ -881,7 +842,7 @@ void (entity pl) RefreshStatusBar = { } tg = find(world, classname, "info_tfgoal"); while (tg) { - if (tg.track_goal && i < 6 && tg.goal_state == TFGS_DELAYED) { + if (tg.track_goal && tg.goal_state == TFGS_DELAYED && i < 6) { bi = ""; //only do this for named goals, otherwise there's no way to distinguish them (they don't ususally have owned_by or anything) if(tg.netname) { From 87225eba5ed71a44cb4707dc802e80289b187e31 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Wed, 7 Aug 2019 14:00:09 +1000 Subject: [PATCH 0777/2474] Revert "Revert "Track goals csqc"" --- csqc/csextradefs.qc | 8 ++- csqc/events.qc | 132 ++++++++++++++++++++++++++++++++++++++++- csqc/hud.qc | 35 +++++------ csqc/main.qc | 2 - csqc/settings.qc | 6 +- docs/hud_statusbar.txt | 37 ++++++++++++ share/commondefs.qc | 3 + ssqc/client.qc | 17 ++++-- ssqc/status.qc | 45 +++++++++++++- 9 files changed, 251 insertions(+), 34 deletions(-) create mode 100644 docs/hud_statusbar.txt diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1e589a59..a5c160ec 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -13,6 +13,11 @@ typedef struct MouseStruct Mouse; +typedef struct { + string filename; + vector colour; +} HUDIcon; + typedef struct { float id; string message; @@ -23,6 +28,7 @@ typedef struct { vector loc; string carrier; string locname; + HUDIcon icon; } FlagInfoLine; FlagInfoLine FlagInfoLines[10]; @@ -69,4 +75,4 @@ FO_Settings Settings; #endif string(string s) strtrim = #0:strtrim; /* - Trims the whitespace from the start+end of the string. */ \ No newline at end of file + Trims the whitespace from the start+end of the string. */ diff --git a/csqc/events.qc b/csqc/events.qc index a45fef48..7ff39347 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,3 +1,4 @@ +/* void() CSQC_Parse_Event = { float msgtype = readbyte(); local float goalno; @@ -78,4 +79,133 @@ void() CSQC_Parse_Event = { default: print("CSQC_Parse_Event, unknown event: ",ftos(msgtype),"\n"); } -} \ No newline at end of file +} +*/ +void() CSQC_Parse_Event = { + float msgtype = readbyte(); + local float goalno; + switch (msgtype) { + case MSG_FLAGINFOINIT: + float index = readfloat(); + goalno = readfloat(); + string mdl = readstring(); + float skinindex = readfloat(); + float ownerteam = readfloat(); + float iconindex = readfloat(); + + //use next available + if(index < 0) { + for(float i = 0; i < FlagInfoLines.length; i++) { + if(FlagInfoLines[i].id == 0) { + index = i; + break; + } + } + } + if(index >= 0 && index < MAX_FLAGINFO_LINES) { + FlagInfoLines[index].id = goalno; + FlagInfoLines[index].message = ""; + if(mdl) + precache_model(mdl); + entity te = spawn(); + te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; + te.origin = [5, 0, 0]; + te.angles = '-60 0 0'; + //setmodel(te,mdl); + //setmodel(te, "progs/weapons/v_rock.mdl"); + //setsize(te, '-16 -16 0', '16 16 8'); + te.skin = skinindex; + te.owned_by = ownerteam; + + string iconname = "sb_key1"; + vector iconcolour = '1 1 1'; + if(iconindex == FLAGINFO_ICON_FLAG) { + iconname = strcat("flag_", ftos(ownerteam)); + iconcolour = '1 1 1'; + /* + switch (ownerteam) { + case 2: + iconname = "sb_key2"; + break; + case 3: + iconcolour = '1 1 0'; + break; + case 4: + iconname = "sb_key2"; + iconcolour = '0 1 0'; + break; + } + */ + } else if(iconindex == FLAGINFO_ICON_BUTTON) { + iconname = strcat("off_icon_glow_", ftos(ownerteam)); + iconcolour = '1 1 1'; + /* + iconname = "net"; + switch (ownerteam) { + case 1: + iconcolour = '0 0 0.5'; + case 2: + iconcolour = '1 0 0'; + break; + case 3: + iconcolour = '1 1 0'; + break; + case 4: + iconcolour = '0 1 0'; + break; + } + */ + } + FlagInfoLines[index].icon.filename = iconname; + FlagInfoLines[index].icon.colour = iconcolour; + FlagInfoLines[index].model = te; + } + break; + case MSG_FLAGINFO: + string message = ""; + goalno = readfloat(); + float state = readfloat(); + float timeleft = -1; + vector droploc = '0 0 0'; + string carrier = ""; + string locname = ""; + switch (state) { + case FLAGINFO_HOME: + message = "^2HOME"; + break; + case FLAGINFO_CARRIED: + carrier = readstring(); + message = strcat("^1CARRIED^7 by ",carrier); + break; + case FLAGINFO_DROPPED: + message = "^3DROPPED^7"; + timeleft = readfloat(); + float showloc = readfloat(); + if(showloc == FLAGINFO_LOCATION) { + droploc_x = readcoord(); + droploc_y = readcoord(); + droploc_z = readcoord(); + //message = strcat(message," at ", vtos(droploc)); + locname = readstring(); + message = strcat(message," at ", locname); + } + //if(timeleft >= 0) { + //message = strcat(message," returning in ", ftos(timeleft)); + //} + break; + case FLAGINFO_RETURNING: + message = "^4RETURNING"; + break; + } + for(float i = 0; i < FlagInfoLines.length; i++) { + if(FlagInfoLines[i].id == goalno) { + FlagInfoLines[i].message = message; + FlagInfoLines[i].timeleft = timeleft; + FlagInfoLines[i].state = state; + FlagInfoLines[i].loc = droploc; + FlagInfoLines[i].carrier = carrier; + FlagInfoLines[i].locname = locname; + } + } + } +} diff --git a/csqc/hud.qc b/csqc/hud.qc index 3cfbb6aa..2c096269 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -134,6 +134,8 @@ void Hud_DrawFlagStatusBar(float width) if (flagInfoCount > 0) { firstrun = FALSE; + pos = HudSettings.FlagIcon.Position; + //pos_y = pos_y - 4;// - 24 * (flagInfoCount - 2); pos_y = pos_y - 4 - sizey * (flagInfoCount - 2); HudSettings.FlagIcon.Position = pos; } @@ -154,26 +156,20 @@ void Hud_DrawFlagStatusBar(float width) { if (FlagInfoLines[i].id) { - string icon = "sb_key1"; - vector iconcolour = '1 1 1'; - alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; - if (FlagInfoLines[i].model) { - switch (FlagInfoLines[i].model.owned_by) - { - case 2: - icon = "sb_key2"; - break; - case 3: - iconcolour = '1 1 0'; - break; - case 4: - icon = "sb_key2"; - iconcolour = '0 1 0'; - break; - } - } + alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; + string icon = FlagInfoLines[i].icon.filename; + vector iconcolour = FlagInfoLines[i].icon.colour; + float yoffset = 24; if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { +// drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); +// } +// else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) +// { +// drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); +// } + +// drawpic([pos_x, pos_y + 24 * (i - 1) + yoffset, 0], icon, '24 24 0', iconcolour, alpha, 1); drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) @@ -186,6 +182,7 @@ void Hud_DrawFlagStatusBar(float width) if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); +// drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 + 24 * (i - 1) + yoffset, 0], stime, '6 6', '1 1 1', 1, 0); drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } @@ -216,4 +213,4 @@ void Hud_Draw(float width, float height) Hud_DrawClipSize(width); HudSettings.MousePos = [Mouse.x, Mouse.y]; -} \ No newline at end of file +} diff --git a/csqc/main.qc b/csqc/main.qc index 8282e5e7..86cb59b9 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -111,5 +111,3 @@ noref void CSQC_Input_Frame() } } } - - diff --git a/csqc/settings.qc b/csqc/settings.qc index 9006cd02..baba5065 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,9 +3,7 @@ void FO_WriteSettings() // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line; - - line = FormatCfgString(line, "fo_autohop", ftos(Settings.Autohop)); + string line = FormatCfgString("", "fo_autohop", ftos(Settings.Autohop)); fputs(filehandle, line); fclose(filehandle); @@ -56,4 +54,4 @@ void FO_LoadSettings() // write a new file FO_WriteSettings(); } -} \ No newline at end of file +} diff --git a/docs/hud_statusbar.txt b/docs/hud_statusbar.txt new file mode 100644 index 00000000..016a2a51 --- /dev/null +++ b/docs/hud_statusbar.txt @@ -0,0 +1,37 @@ +The status bar shows TF-specific info, and it works in different ways depending on the client: +For fte, it will detect that csqc is active and send messages directly to the csqc part of the client to display individual HUD icons and statuses. +For ezquake (and basically everything else), it will use a centerprint hack to permanently display the status bar. + +It can be enabled using the client setting + setinfo sb 40 +(or any positive integer). The integer is relevant for the non-fte version, as it dictates how many empty "lines" to skip before drawing it, thus allowing basic control of its veritcal position. + +A specific sub-component can be enabled using the command + setinfo sbflaginfo 1|2 +Setting it to 0 will turn it off, setting it to 1 will enable it, but only 6 seconds after spawn (after the class tips finish displaying) and a setting of 2 will make it permanent. + +The sb flaginfo will display the current status of any flags/item_tfgoals that have been tagged by the mapper. The logic is the same as the stock "flaginfo" command, which is marking up to 4 goalitems in the info_tfdetect +entity using the fields display_item_status1 - display_item_status4 using the items' goal_no numbers. This is further documented in the tf reference docs. +This does limit the number of trackable items to 4 however. +The flaginfo functionality is extended by having it also display who it's currenly carried by, or, if dropped, the location (based on the loc file) and time to return. +Note that currently, the item names are hard-coded to be "blue/red/yellow/green flag", to cover most cases, where mappers didn't necessarily name them nicely. + +The sb flaginfo component also displays the "button" countdowns (such as lasers/security being down), if available, and there is room. +This functions in a similar way to the flag info, but, while technically unlimited, +the combined number of all sbar items (flags and buttons) is 10 for fte and 6 for ezquake. +For ezquake, the buttons will be distinguished by name, and will not appear until they are actually triggered and have a countdown active. +For fte, the buttons are distinguished by team colours and will display a different icon to the flag, but otherwise function similarly. + +For a map to allow these to be tracked, the following needs to be set for each button: +- It must be set on an info_tfgoal entity +- It must have the field "track_goal" be set to 1 +- It must have a "goal_no" field set +- It must have the field "delay_time" set to the countdown time +- It must be triggered at the start of the countdown either via goal_no or targetname. It doesn't have to be part of the main trigger chain however. +- For ezquake, it must have a "netname" field set to distinguish the goals. +- For FTE, it should have the "owned_by" field set which will determine the icon colour. +- Optionally, it can have the field "team_str_moved" set to set a custom string to be displayed while the countdown is active. If not set, the default is "Offline". + +For FTE, the icons for the above are in the same location as the normal hud elements: +ie fortress/textures/wad/ +They are named "flag_" for the flag icons and "off_icon_glow_" for the button icons. diff --git a/share/commondefs.qc b/share/commondefs.qc index 257862f1..a943de70 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -10,3 +10,6 @@ #define FLAGINFO_RETURNING 4 #define FLAGINFO_LOCATION 5 #define FLAGINFO_NOLOCATION 6 + +#define FLAGINFO_ICON_FLAG 0 +#define FLAGINFO_ICON_BUTTON 1 diff --git a/ssqc/client.qc b/ssqc/client.qc index 4a9a3371..73989a66 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2339,10 +2339,19 @@ void (optional float csqcactive) ClientConnect = { } entity tfdet = find(world, classname, "info_tfdetect"); if(tfdet) { - InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1)); - InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2)); - InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3)); - InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4)); + InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4), FLAGINFO_ICON_FLAG); + } + if(csqcactive) { + tfdet = find(world, classname, "info_tfgoal"); + while (tfdet) { + if (tfdet.track_goal) { + InitClientFlagStatus(self, -1, tfdet, FLAGINFO_ICON_BUTTON); + } + tfdet = find(tfdet, classname, "info_tfgoal"); + } } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/status.qc b/ssqc/status.qc index 65a13878..fc78dbb9 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -580,7 +580,7 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr string getLocationName(vector location); -void (entity Player, float index, entity Item) InitClientFlagStatus = { +void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); if(csqcactive) { msg_entity = Player; @@ -591,9 +591,40 @@ void (entity Player, float index, entity Item) InitClientFlagStatus = { WriteString(MSG_MULTICAST, Item.mdl); WriteFloat(MSG_MULTICAST, Item.skin); WriteFloat(MSG_MULTICAST, Item.owned_by); + WriteFloat(MSG_MULTICAST, icon); multicast('0 0 0', MULTICAST_ONE_R); } } +float laststate; +void (entity Player, entity Goal) UpdateClientButtonStatus = { + msg_entity = Player; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAGINFO); + WriteFloat(MSG_MULTICAST, Goal.goal_no); + if(Goal.goal_no == 11) { + if(Goal.goal_state != laststate) { + laststate = Goal.goal_state; + } + } + if(Goal.goal_state == TFGS_DELAYED) { + WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); + WriteFloat(MSG_MULTICAST, rint(Goal.bubble_count - time)); + //WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); + WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); + WriteCoord(MSG_MULTICAST, Goal.origin_x); + WriteCoord(MSG_MULTICAST, Goal.origin_y); + WriteCoord(MSG_MULTICAST, Goal.origin_z); + //WriteString(MSG_MULTICAST, getLocationName(Item.origin)); + if(Goal.team_str_moved) { + WriteString(MSG_MULTICAST, Goal.team_str_moved); + } else { + WriteString(MSG_MULTICAST,"\sOffline\s"); + } + } else { + WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); + } + multicast('0 0 0', MULTICAST_ONE); +} void (entity Player, entity Item) UpdateClientFlagStatus = { msg_entity = Player; @@ -732,6 +763,7 @@ void (entity pl) RefreshStatusBar = { local entity tfdet; //info_tfdetect entity local entity te, tg; local string bi; //button info + local float csqcactive; //By default, show after tips; 0/off = off; 2 = always local float sbflaginfostate = FO_GetUserSetting(pl, "sbflaginfo", "sbflaginfo", "on"); /* local float win, sec; */ @@ -761,7 +793,7 @@ void (entity pl) RefreshStatusBar = { pad = strcat(pad, "\n"); pad = strzone(pad); - float csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); + csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); // class tip if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2) { @@ -800,6 +832,13 @@ void (entity pl) RefreshStatusBar = { UpdateClientFlagStatus(pl, te); } } + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.track_goal) { + UpdateClientButtonStatus(pl, tg); + } + tg = find(tg, classname, "info_tfgoal"); + } } else // no csqc but has sbflaginfo on { @@ -842,7 +881,7 @@ void (entity pl) RefreshStatusBar = { } tg = find(world, classname, "info_tfgoal"); while (tg) { - if (tg.track_goal && tg.goal_state == TFGS_DELAYED && i < 6) { + if (tg.track_goal && i < 6 && tg.goal_state == TFGS_DELAYED) { bi = ""; //only do this for named goals, otherwise there's no way to distinguish them (they don't ususally have owned_by or anything) if(tg.netname) { From 2a4d0fc20a6be42a2782a3013d9762cc64f599af Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 7 Aug 2019 14:17:44 +1000 Subject: [PATCH 0778/2474] reenable clipsize parsing to stop crashes --- csqc/events.qc | 127 +++---------------------------------------------- 1 file changed, 7 insertions(+), 120 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 7ff39347..b597b77c 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,86 +1,3 @@ -/* -void() CSQC_Parse_Event = { - float msgtype = readbyte(); - local float goalno; - switch (msgtype) { - case MSG_FLAGINFOINIT: - float index = readfloat(); - goalno = readfloat(); - string mdl = readstring(); - float skinindex = readfloat(); - float ownerteam = readfloat(); - if(index >= 0 && index < MAX_FLAGINFO_LINES) - { - FlagInfoLines[index].id = goalno; - FlagInfoLines[index].message = ""; - if(mdl) - precache_model(mdl); - entity te = spawn(); - te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; - te.origin = [5, 0, 0]; - te.angles = '-60 0 0'; - //setmodel(te,mdl); - setmodel(te, "progs/weapons/v_rock.mdl"); - setsize(te, '-16 -16 0', '16 16 8'); - te.skin = skinindex; - te.owned_by = ownerteam; - FlagInfoLines[index].model = te; - } - break; - case MSG_FLAGINFO: - string message = ""; - goalno = readfloat(); - float state = readfloat(); - float timeleft = -1; - vector droploc = '0 0 0'; - string carrier = ""; - string locname = ""; - switch (state) { - case FLAGINFO_HOME: - message = "^2HOME"; - break; - case FLAGINFO_CARRIED: - carrier = readstring(); - message = strcat("^1CARRIED^7 by ",carrier); - break; - case FLAGINFO_DROPPED: - message = "^3DROPPED^7"; - timeleft = readfloat(); - float showloc = readfloat(); - if(showloc == FLAGINFO_LOCATION) { - droploc_x = readcoord(); - droploc_y = readcoord(); - droploc_z = readcoord(); - locname = readstring(); - message = strcat(message," at ", locname); - } - break; - case FLAGINFO_RETURNING: - message = "^4RETURNING"; - break; - } - for(float i = 0; i < FlagInfoLines.length; i++) { - if(FlagInfoLines[i].id == goalno) { - FlagInfoLines[i].message = message; - FlagInfoLines[i].timeleft = timeleft; - FlagInfoLines[i].state = state; - FlagInfoLines[i].loc = droploc; - FlagInfoLines[i].carrier = carrier; - FlagInfoLines[i].locname = locname; - } - } - break; - case MSG_CLIPSIZE: - string test; - test = readstring(); - - ClipSizeMsg = test; - break; - default: - print("CSQC_Parse_Event, unknown event: ",ftos(msgtype),"\n"); - } -} -*/ void() CSQC_Parse_Event = { float msgtype = readbyte(); local float goalno; @@ -111,9 +28,6 @@ void() CSQC_Parse_Event = { te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; te.origin = [5, 0, 0]; te.angles = '-60 0 0'; - //setmodel(te,mdl); - //setmodel(te, "progs/weapons/v_rock.mdl"); - //setsize(te, '-16 -16 0', '16 16 8'); te.skin = skinindex; te.owned_by = ownerteam; @@ -122,39 +36,9 @@ void() CSQC_Parse_Event = { if(iconindex == FLAGINFO_ICON_FLAG) { iconname = strcat("flag_", ftos(ownerteam)); iconcolour = '1 1 1'; - /* - switch (ownerteam) { - case 2: - iconname = "sb_key2"; - break; - case 3: - iconcolour = '1 1 0'; - break; - case 4: - iconname = "sb_key2"; - iconcolour = '0 1 0'; - break; - } - */ } else if(iconindex == FLAGINFO_ICON_BUTTON) { iconname = strcat("off_icon_glow_", ftos(ownerteam)); iconcolour = '1 1 1'; - /* - iconname = "net"; - switch (ownerteam) { - case 1: - iconcolour = '0 0 0.5'; - case 2: - iconcolour = '1 0 0'; - break; - case 3: - iconcolour = '1 1 0'; - break; - case 4: - iconcolour = '0 1 0'; - break; - } - */ } FlagInfoLines[index].icon.filename = iconname; FlagInfoLines[index].icon.colour = iconcolour; @@ -185,13 +69,9 @@ void() CSQC_Parse_Event = { droploc_x = readcoord(); droploc_y = readcoord(); droploc_z = readcoord(); - //message = strcat(message," at ", vtos(droploc)); locname = readstring(); message = strcat(message," at ", locname); } - //if(timeleft >= 0) { - //message = strcat(message," returning in ", ftos(timeleft)); - //} break; case FLAGINFO_RETURNING: message = "^4RETURNING"; @@ -207,5 +87,12 @@ void() CSQC_Parse_Event = { FlagInfoLines[i].locname = locname; } } + break; + case MSG_CLIPSIZE: + string test; + test = readstring(); + + ClipSizeMsg = test; + break; } } From 604224720def334f2d7c00d0d90a8a7dfd54eb8e Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 7 Aug 2019 16:22:38 +1000 Subject: [PATCH 0779/2474] clean up commented out code, make specs not disconnect if ezquake clients --- csqc/hud.qc | 11 ----------- ssqc/status.qc | 10 ++++------ 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 250998e8..cceb2342 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,4 +1,3 @@ - void GetDrawPanel(string id) { switch (id) @@ -207,7 +206,6 @@ void Hud_DrawFlagStatusBar(float width) { firstrun = FALSE; pos = HudSettings.FlagIcon.Position; - //pos_y = pos_y - 4;// - 24 * (flagInfoCount - 2); pos_y = pos_y - 4 - sizey * (flagInfoCount - 2); HudSettings.FlagIcon.Position = pos; } @@ -234,14 +232,6 @@ void Hud_DrawFlagStatusBar(float width) float yoffset = 24; if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { -// drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); -// } -// else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) -// { -// drawstring([pos_x + 28, pos_y + 8 + 24 * (i - 1) + yoffset, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); -// } - -// drawpic([pos_x, pos_y + 24 * (i - 1) + yoffset, 0], icon, '24 24 0', iconcolour, alpha, 1); drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) @@ -254,7 +244,6 @@ void Hud_DrawFlagStatusBar(float width) if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); -// drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 + 24 * (i - 1) + yoffset, 0], stime, '6 6', '1 1 1', 1, 0); drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); } } diff --git a/ssqc/status.qc b/ssqc/status.qc index 0f309a41..9ab6863a 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -590,7 +590,7 @@ void (entity Player, float index, entity Item, float icon) InitClientFlagStatus WriteFloat(MSG_MULTICAST, Item.skin); WriteFloat(MSG_MULTICAST, Item.owned_by); WriteFloat(MSG_MULTICAST, icon); - multicast('0 0 0', MULTICAST_ONE_R); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } } float laststate; @@ -621,7 +621,7 @@ void (entity Player, entity Goal) UpdateClientButtonStatus = { } else { WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); } - multicast('0 0 0', MULTICAST_ONE); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void (entity Player, entity Item) UpdateClientFlagStatus = { @@ -662,7 +662,7 @@ void (entity Player, entity Item) UpdateClientFlagStatus = { WriteFloat(MSG_MULTICAST, FLAGINFO_HOME); } } - multicast('0 0 0', MULTICAST_ONE); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); } float(entity playerent, float changedflags) SendClientFlagStatus = { @@ -927,7 +927,7 @@ void UpdateClientStatusBar(entity pl) break; } - multicast('0 0 0', MULTICAST_ONE); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void (entity pl) RefreshStatusBar = { @@ -1149,8 +1149,6 @@ void (entity pl) RefreshStatusBar = { // status line 3 column 4 - grenade 2 count st4 = strcat(Q"\sGren2\s: ", ftos(pl.no_grenades_2)); - - // status line 3 s3 = strcat(st1, st2); From 97a63c112ac0fd0a1a24238519adc7abb9a32803 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 7 Aug 2019 17:32:33 +1000 Subject: [PATCH 0780/2474] update files to be like meht's structure --- share/defs.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/share/defs.h b/share/defs.h index 41dd1815..cf36a0db 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1322,22 +1322,22 @@ #define FO_HUD_INSERT_BEFORE 0 #define FO_HUD_INSERT_AFTER 1 -#define ICON_CLIPSIZE "progs/gfx/hud/clipsize.png" -#define ICON_FRAGSTREAK "progs/gfx/hud/fragstreak.png" -#define ICON_CAPS "progs/gfx/hud/caps.png" -#define ICON_IDENTIFY "progs/gfx/hud/identify.png" -#define ICON_GREN1 "progs/gfx/hud/gren1.png" -#define ICON_GREN2 "progs/gfx/hud/gren2.png" -#define ICON_SCOUT "progs/gfx/hud/scout.png" -#define ICON_SNIPER "progs/gfx/hud/sniper.png" -#define ICON_SOLDIER "progs/gfx/hud/soldier.png" -#define ICON_DEMOMAN "progs/gfx/hud/demoman.png" -#define ICON_MEDIC "progs/gfx/hud/medic.png" -#define ICON_HWGUY "progs/gfx/hud/hwguy.png" -#define ICON_PYRO "progs/gfx/hud/pyro.png" -#define ICON_SPY "progs/gfx/hud/spy.png" -#define ICON_ENGINEER_SG "progs/gfx/hud/engineer_sg.png" -#define ICON_ENGINEER_DISP "progs/gfx/hud/engineer_disp.png" +#define ICON_CLIPSIZE "clipsize.png" +#define ICON_FRAGSTREAK "fragstreak.png" +#define ICON_CAPS "caps.png" +#define ICON_IDENTIFY "identify.png" +#define ICON_GREN1 "gren1.png" +#define ICON_GREN2 "gren2.png" +#define ICON_SCOUT "scout.png" +#define ICON_SNIPER "sniper.png" +#define ICON_SOLDIER "soldier.png" +#define ICON_DEMOMAN "demoman.png" +#define ICON_MEDIC "medic.png" +#define ICON_HWGUY "hwguy.png" +#define ICON_PYRO "pyro.png" +#define ICON_SPY "spy.png" +#define ICON_ENGINEER_SG "engineer_sg.png" +#define ICON_ENGINEER_DISP "engineer_disp.png" // stats // first 32 are reserved From d727d86da7c2a44592030b409eee982f25963d17 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 10 Aug 2019 20:56:54 +1000 Subject: [PATCH 0781/2474] split the identify string up so it prints better via csqc --- csqc/hud.qc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index cceb2342..7b090bd8 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -475,7 +475,23 @@ void Hud_DrawIdentifyPanel(string id, string identify) } vector fontSize = FO_Hud_Icon_Font_Size * DrawPanel.Scale; - drawstring(pos, identify, fontSize, '1 1 1', 1, 0); + + float count = tokenizebyseparator(identify, "\n"); + float msgcount = 0; + string msg = ""; + for (float f = 0; f <= count; f++) + { + msg = argv(f); + // tokenize doesn't handle newlines very well + msg = strreplace("\n", "", msg); + msg = strtrim(msg); + if (strlen(msg) > 0) + { + pos = pos + [0, (fontSize_y * msgcount), 0]; + drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + msgcount++; + } + } } void Hud_Draw(float width, float height) From 44c125b47bf0de603ebd4b01d54c0c4b1141d394 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 11 Aug 2019 19:54:05 +1200 Subject: [PATCH 0782/2474] Respawn bug fix. Track duel points. Optionally display survivor health. --- ssqc/clan.qc | 32 ++++++++++++++------------ ssqc/client.qc | 59 ++++++++++++++++++++++++++++++++++++++++++++---- ssqc/commands.qc | 4 ++++ ssqc/engineer.qc | 1 + ssqc/pyro.qc | 2 ++ ssqc/qw.qc | 4 ++++ ssqc/spy.qc | 1 + ssqc/tfort.qc | 55 ++++++++++++++++++++++++++++++++++++++++++++ ssqc/weapons.qc | 1 + 9 files changed, 139 insertions(+), 20 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index e84d070a..3cc08baf 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -75,21 +75,6 @@ void () StartMatch = team3frags = 0; team2frags = 0; team1frags = 0; - te = find(world, classname, "player"); - - while (te) { - oldself = self; - self = te; - - TeamFortress_RemoveTimers(); - self.frags = 0; - self.real_frags = 0; - setspawnparms(self); - if (!quadmode) - PutClientInServer(); - self = oldself; - te = find(te, classname, "player"); - } gren = find(world, classname, "grenade"); while (gren) { @@ -118,6 +103,20 @@ void () StartMatch = te = find (te, classname, "info_tfgoal"); } } + te = find(world, classname, "player"); + while (te) { + oldself = self; + self = te; + + TeamFortress_RemoveTimers(); + self.frags = 0; + self.real_frags = 0; + setspawnparms(self); + if (!quadmode) + PutClientInServer(); + self = oldself; + te = find(te, classname, "player"); + } cb_prematch = 0; cease_fire = 0; @@ -166,6 +165,9 @@ void () StartMatch = StartQuadRound(); } } + if (duelmode) { + ResetPlayers(); + } }; void () PreMatch_Think = { diff --git a/ssqc/client.qc b/ssqc/client.qc index 4a9a3371..4023c294 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -60,6 +60,7 @@ void () PreMatch_Message; float () GetLastWeaponImpulse; float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; +void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; string nextmap; @@ -613,6 +614,8 @@ void () DecodeLevelParms = { duel_no_packs = CF_GetSetting("dnp", "duel_no_packs", "1"); // spawn with all possible grenades [0] duel_all_grens = CF_GetSetting("dag", "duel_all_grens", "0"); + // After a duel round, print the winners' health stats + round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); st = infokey(world, "default"); if (st == "on") { @@ -1097,8 +1100,17 @@ void () RemovePlayerOwnedEnts = { } } +void (string cn) RemoveAllEntsByClassname = { + local entity te = find(world, classname, cn); + while (te) { + dremove(te); + te = find(te, classname, cn); + } +} + void () ResetPlayers = { local entity te, oldself, reset_timer; + local float teamsleft; no_fire_mode = 0; reset_timer = find(world, classname, "duel_reset_timer"); while (reset_timer != world) { @@ -1108,11 +1120,43 @@ void () ResetPlayers = { } if(cb_prematch) return; + + teamsleft = CountRemainingTeams(); + if(teamsleft == 1) { + if(round_winner) { + bprint(PRINT_HIGH, round_winner.netname, " of team ", TeamFortress_TeamGetColorString(round_winner.team_no) ,", wins the round!\n"); + if(round_winner_print_health && round_winner.health == round_winner.max_health && round_winner.armorvalue == round_winner.maxarmor ) { + bprint(PRINT_HIGH, "\t\t\t \sFLAWLESS VICTORY\s \t\t\t\n"); + } + } else { + bprint(PRINT_HIGH, TeamFortress_TeamGetColorString(round_winner_team), " team wins the round!\n"); + } + TeamFortress_TeamIncreaseScore(round_winner_team, 1); + } else if(teamsleft == 0) { + bprint(PRINT_HIGH, "Everybody died! It's a draw.\n"); + } + TeamFortress_TeamShowScores(2); + + RemoveAllEntsByClassname("proj_bullet"); + RemoveAllEntsByClassname("proj_rocket"); + RemoveAllEntsByClassname("grenade"); + RemoveAllEntsByClassname("pipebomb"); + RemoveAllEntsByClassname("spike"); + RemoveAllEntsByClassname("railslug"); + RemoveAllEntsByClassname("pyro_flame"); + RemoveAllEntsByClassname("fire"); + RemoveAllEntsByClassname("flamerflame"); + RemoveAllEntsByClassname("pyro_rocket"); + RemoveAllEntsByClassname("proj_tranq"); + te = find(world, classname, "player"); while (te != world) { if(!te.has_disconnected) { if(te.health > 0) { stuffcmd(te, "f_respawn\n"); + if(round_winner_print_health) { + bprint(PRINT_HIGH, te.netname, ": \sHealth:\s ", ftos(te.health), " \sArmour:\s " , ftos(te.armorvalue), "\n"); + } } oldself = self; self = te; @@ -1157,14 +1201,19 @@ float () CountRemainingTeams = { if(teamflags & 16) { teamsleft++; } + round_winner_team = 0; + round_winner = world; if(teamsleft == 1) { if(playersleft == 1) { - bprint(PRINT_HIGH, lastplayer.netname, " of team ", TeamFortress_TeamGetColorString(lastplayer.team_no) ,", wins the round!\n"); + //bprint(PRINT_HIGH, lastplayer.netname, " of team ", TeamFortress_TeamGetColorString(lastplayer.team_no) ,", wins the round!\n"); + round_winner = lastplayer; + round_winner_team = lastplayer.team_no; } else { - bprint(PRINT_HIGH, TeamFortress_TeamGetColorString(lastplayer.team_no), " team wins the round!\n"); + //bprint(PRINT_HIGH, TeamFortress_TeamGetColorString(lastplayer.team_no), " team wins the round!\n"); + round_winner_team = lastplayer.team_no; } - } else if(teamsleft == 0) { - bprint(PRINT_HIGH, "Everybody died! It's a draw.\n"); + //} else if(teamsleft == 0) { + //bprint(PRINT_HIGH, "Everybody died! It's a draw.\n"); } return teamsleft; } @@ -1228,7 +1277,7 @@ void () ClientKill = { self.deadflag = DEAD_RESPAWNABLE; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; self.takedamage = 0; - if(duelmode) { + if(duelmode && !cb_prematch) { if(CountRemainingTeams() < 2) { ResetPlayersWithCountdown(); } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index e8980d5f..0c52e824 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -234,6 +234,7 @@ void () QuadMode = localcmd ("localinfo teamfrags on\n"); localcmd ("localinfo fullteamscore off\n"); localcmd ("fraglimit 0\n"); + localcmd ("localinfo rd 0\n"); localcmd ("exec fo_quadmode.cfg\n"); bprint (PRINT_HIGH, "Quad Mode set to on\n"); bprint (PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -242,6 +243,7 @@ void () QuadMode = void () ClanMode = { localcmd("localinfo clan on\n"); + localcmd ("localinfo rd 0\n"); localcmd ("exec fo_clanmode.cfg\n"); bprint(PRINT_HIGH, "Clan Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -259,6 +261,7 @@ void () PubMode = localcmd ("timelimit 20\n"); localcmd ("fraglimit 0\n"); localcmd ("localinfo round_time 0\n"); + localcmd ("localinfo rd 0\n"); localcmd ("exec fo_pubmode.cfg\n"); bprint(PRINT_HIGH, "Pub Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -274,6 +277,7 @@ void () DuelMode = localcmd ("localinfo sf on\n"); // spawnfull, ie spawn fully stocked localcmd ("localinfo drd 3.9\n"); // wait before resetting the winner long enough for grens to go off localcmd ("localinfo rd 9999\n"); // wait before respawning the loser + localcmd ("localinfo dph 1\n"); // print health of duel survivors localcmd ("password none\n"); localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index d49cae80..fa7655d8 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -107,6 +107,7 @@ void () W_FireLaser = { newmis.nextthink = time + 5; newmis.think = SUB_Remove; newmis.touch = LaserBolt_Touch; + newmis.classname = "railslug"; }; void () EMPExplode = { diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index ade987ea..66773876 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -52,6 +52,7 @@ entity(string type, entity p_owner) FlameSpawn = setsize(newmis, '0 0 0', '0 0 0'); } newmis.owner = p_owner; + newmis.classname = "pyro_flame"; return (newmis); }; @@ -714,6 +715,7 @@ void () W_FireIncendiaryCannon = { newmis.touch = T_IncendiaryTouch; newmis.nextthink = time + 5; newmis.weapon = DMSG_INCENDIARY; + newmis.classname = "pyro_rocket"; setmodel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 109bd0ac..3b9dae79 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -154,6 +154,10 @@ float team2advantage; // stores the damage ratio players take/give float team3advantage; float team4advantage; +float round_winner_team; +entity round_winner; +float round_winner_print_health; + .float team_no; // The team you belong to .float lives; // The number of lives you have left diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 35758771..72edbab6 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1305,6 +1305,7 @@ void () W_FireTranq = { newmis.touch = T_TranqDartTouch; newmis.think = SUB_Remove; newmis.nextthink = time + 6; + newmis.classname = "proj_tranq"; setmodel(newmis, "progs/spike.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b4df8ec1..c5c816d3 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1292,6 +1292,61 @@ void () TeamFortress_SetHealth = { self.health = self.max_health; }; +float (float pc) TeamFortress_GetMaxHealth = { + if (pc == PC_SCOUT) { + if (old_hp_armor) + return 75; + else + return PC_SCOUT_MAXHEALTH; + } else if (pc == PC_SNIPER) { + if (old_hp_armor) + return 90; + else + return PC_SNIPER_MAXHEALTH; + } else if (pc == PC_SOLDIER) { + if (old_hp_armor) + return 100; + else + return PC_SOLDIER_MAXHEALTH; + } else if (pc == PC_DEMOMAN) { + if (old_hp_armor) + return 90; + else + return PC_DEMOMAN_MAXHEALTH; + } else if (pc == PC_MEDIC) { + if (old_hp_armor) + return 90; + else + return PC_MEDIC_MAXHEALTH; + } else if (pc == PC_HVYWEAP) { + if (old_hp_armor) + return 100; + else + return PC_HVYWEAP_MAXHEALTH; + } else if (pc == PC_PYRO) { + if (old_hp_armor) + return 100; + else + return PC_PYRO_MAXHEALTH; + } else if (pc == PC_CIVILIAN) { + if (old_hp_armor) + return 50; + else + return PC_CIVILIAN_MAXHEALTH; + } else if (pc == PC_SPY) { + if (old_hp_armor) + return 90; + else + return PC_SPY_MAXHEALTH; + } else if (pc == PC_ENGINEER) { + if (old_hp_armor) + return 80; + else + return PC_ENGINEER_MAXHEALTH; + } + return 1; +}; + string (float tn) TeamFortress_GetColorSkin = { string s; s = ""; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1b2c0f11..e656c015 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1097,6 +1097,7 @@ void () W_FireRocket = { newmis.think = SUB_Remove; newmis.weapon = DMSG_ROCKETL; + newmis.classname = "proj_rocket"; setmodel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); From 95ae26c221b08ee4ff15ef3fafb1431b82db0820 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 11 Aug 2019 21:17:48 +1000 Subject: [PATCH 0783/2474] fix flag disappearing if it returns whilst in a door --- ssqc/tfortmap.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 247c8aa6..848e5aba 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2313,18 +2313,19 @@ void () ReturnItem = { self.enemy.effects = self.enemy.effects | EF_BLUE; } - if (self.enemy.mdl != string_null) { + if (self.enemy.mdl) { + bprint(PRINT_HIGH, "enemy mdl set\n"); setmodel(self.enemy, self.enemy.mdl); } + setsize(self.enemy, VEC_HULL_MIN, VEC_HULL_MAX); setorigin(self.enemy, self.enemy.origin); tfgoalitem_checkgoalreturn(self.enemy); sound(self.enemy, 2, "items/itembk2.wav", 1, 1); if (self.weapon != 2) { - if ((self.enemy.noise3 != string_null) || - (self.enemy.noise4 != string_null)) { + if ((self.enemy.noise3) || (self.enemy.noise4)) { te = find(world, classname, "player"); while (te) { if (te.team_no == self.enemy.owned_by) From 22c79c13c62f5ef38c574ca4bf70245424de122b Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 11 Aug 2019 21:27:13 +1000 Subject: [PATCH 0784/2474] take out debug bprint --- ssqc/tfortmap.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 848e5aba..62e443b7 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2314,7 +2314,6 @@ void () ReturnItem = { } if (self.enemy.mdl) { - bprint(PRINT_HIGH, "enemy mdl set\n"); setmodel(self.enemy, self.enemy.mdl); } From 45d19cde48c00bbfd6284d36d56e4df4c2c9e06d Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 11 Aug 2019 21:46:36 +1000 Subject: [PATCH 0785/2474] apply glow to all tf items --- ssqc/tfortmap.qc | 191 ++++++++++++++++------------------------------- 1 file changed, 66 insertions(+), 125 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 62e443b7..25fa3ee9 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -232,52 +232,59 @@ void () TF_PlaceItem = { item_list_bit = item_list_bit * 2; }; -void () TF_StartItem = { +float TF_Item_GetGlow(float team) +{ + float ret = 0; + switch (team) + { + case 1: + ret = EF_BLUE; + break; + case 2: + ret = EF_RED; + break; + case 3: + ret = EF_RED + EF_MUZZLEFLASH; + break; + case 4: + ret = EF_MUZZLEFLASH; + break; + default: + ret = EF_DIMLIGHT; + } + + return ret; +} + +void TF_Item_ApplyGlow() +{ local entity tfdet; //info_tfdetect entity tfdet = find(world, classname, "info_tfdetect"); + if (tfdet && (tfdet.display_item_status1 == self.goal_no || tfdet.display_item_status2 == self.goal_no || tfdet.display_item_status3 == self.goal_no || tfdet.display_item_status4 == self.goal_no)) { - if (self.owned_by == 1.0) { - self.effects = self.effects | EF_BLUE; - } - if (self.owned_by == 2.0) { - self.effects = self.effects | EF_RED; - } - if (self.owned_by == 3.0) { - self.effects = self.effects | EF_RED; - self.effects = self.effects | EF_MUZZLEFLASH; - } - if (self.owned_by == 4.0) { - self.effects = self.effects | EF_MUZZLEFLASH; - } + self.effects = self.effects | TF_Item_GetGlow(self.owned_by); } else { - if (self.model == "progs/tf_flag.mdl" || self.model == "progs/tf_stan.mdl") { - self.effects = self.effects | EF_DIMLIGHT; - - if (self.skin == 1.0) { - self.effects = self.effects | EF_BLUE; - } - if (self.skin == 2.0) { - self.effects = self.effects | EF_RED; - } - if (self.skin == 3.0) { - self.effects = self.effects | EF_RED; - self.effects = self.effects | EF_MUZZLEFLASH; - } - if (self.skin == 4.0) { - self.effects = self.effects | EF_MUZZLEFLASH; - } - } - - if (self.model == "progs/basrkey.bsp" ) { - self.effects = self.effects | EF_DIMLIGHT; - self.effects = self.effects | EF_RED; - } - - if (self.model == "progs/basbkey.bsp" ) { - self.effects = self.effects | EF_DIMLIGHT; - self.effects = self.effects | EF_BLUE; - } + if (self.model) + { + switch (self.model) + { + case "progs/basrkey.bsp": + self.effects = self.effects | EF_DIMLIGHT; + self.effects = self.effects | EF_RED; + break; + case "progs/basbkey.bsp": + self.effects = self.effects | EF_DIMLIGHT; + self.effects = self.effects | EF_BLUE; + break; + default: + self.effects = self.effects | TF_Item_GetGlow(self.owned_by); + } + } } +} + +void () TF_StartItem = { + TF_Item_ApplyGlow(); UpdateAbbreviations(self); self.nextthink = time + 0.2; self.think = TF_PlaceItem; @@ -668,36 +675,14 @@ void (entity Goal) RestoreGoal = { Goal.nextthink = time + Goal.search_time; } Goal.goal_state = 2; - if (Goal.mdl != string_null) { + if (Goal.model) { setmodel(Goal, Goal.mdl); setsize(Goal, Goal.goal_min, Goal.goal_max); - } - if (Goal.model == "progs/tf_flag.mdl" || Goal.model == "progs/tf_stan.mdl") { - Goal.effects = Goal.effects | EF_DIMLIGHT; - - if (Goal.skin == 1.0) { - Goal.effects = Goal.effects | EF_BLUE; - } - if (Goal.skin == 2.0) { - Goal.effects = Goal.effects | EF_RED; - } - if (Goal.skin == 3.0) { - Goal.effects = Goal.effects | EF_RED; - Goal.effects = Goal.effects | EF_MUZZLEFLASH; - } - if (Goal.skin == 4.0) { - Goal.effects = Goal.effects | EF_MUZZLEFLASH; - } - } - - if (Goal.model == "progs/basrkey.bsp" ) { - Goal.effects = Goal.effects | EF_DIMLIGHT; - Goal.effects = Goal.effects | EF_RED; - } - - if (Goal.model == "progs/basbkey.bsp" ) { - Goal.effects = Goal.effects | EF_DIMLIGHT; - Goal.effects = Goal.effects | EF_BLUE; + entity oldself; + oldself = self; + self = Goal; + TF_Item_ApplyGlow(); + self = oldself; } } }; @@ -2285,35 +2270,13 @@ void () ReturnItem = { self.enemy.touch = item_tfgoal_touch; self.enemy.origin = self.enemy.oldorigin; - if (self.enemy.model == "progs/tf_flag.mdl" || self.enemy.model == "progs/tf_stan.mdl") { - self.enemy.effects = self.effects | EF_DIMLIGHT; - - if (self.enemy.skin == 1.0) { - self.enemy.effects = self.enemy.effects | EF_BLUE; - } - if (self.enemy.skin == 2.0) { - self.enemy.effects = self.enemy.effects | EF_RED; - } - if (self.enemy.skin == 3.0) { - self.enemy.effects = self.enemy.effects | EF_RED; - self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; - } - if (self.enemy.skin == 4.0) { - self.enemy.effects = self.enemy.effects | EF_MUZZLEFLASH; - } - } - - if (self.enemy.model == "progs/basrkey.bsp" ) { - self.enemy.effects = self.effects | EF_DIMLIGHT; - self.enemy.effects = self.enemy.effects | EF_RED; - } - - if (self.enemy.model == "progs/basbkey.bsp" ) { - self.enemy.effects = self.effects | EF_DIMLIGHT; - self.enemy.effects = self.enemy.effects | EF_BLUE; - } - - if (self.enemy.mdl) { + if (self.enemy.model) + { + entity oldself; + oldself = self; + self = self.enemy; + TF_Item_ApplyGlow(); + self = oldself; setmodel(self.enemy, self.enemy.mdl); } @@ -2536,33 +2499,11 @@ void () tfgoalitem_droptouch = { }; void (entity Item, float PAlive, entity P) tfgoalitem_drop = { - if (Item.model == "progs/tf_flag.mdl" || Item.model == "progs/tf_stan.mdl") { - Item.effects = Item.effects | EF_DIMLIGHT; - - if (Item.skin == 1.0) { - Item.effects = Item.effects | EF_BLUE; - } - if (Item.skin == 2.0) { - Item.effects = Item.effects | EF_RED; - } - if (Item.skin == 3.0) { - Item.effects = Item.effects | EF_RED; - Item.effects = Item.effects | EF_MUZZLEFLASH; - } - if (Item.skin == 4.0) { - Item.effects = Item.effects | EF_MUZZLEFLASH; - } - } - - if (Item.model == "progs/basrkey.bsp" ) { - Item.effects = Item.effects | EF_DIMLIGHT; - Item.effects = Item.effects | EF_RED; - } - - if (Item.model == "progs/basbkey.bsp" ) { - Item.effects = Item.effects | EF_DIMLIGHT; - Item.effects = Item.effects | EF_BLUE; - } + entity oldself; + oldself = self; + self = Item; + TF_Item_ApplyGlow(); + self = oldself; Item.origin = Item.owner.origin; setorigin(Item, Item.origin); From de53e03da6a8540d120d14876780466a60dce3e2 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 11 Aug 2019 22:05:30 +1000 Subject: [PATCH 0786/2474] change weapon messages to print_high for triggers --- ssqc/weapons.qc | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e656c015..d7748640 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2103,18 +2103,24 @@ float (entity pl) WeaponReady = { } void () W_PrintWeaponMessage = { - if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - if (self.weaponmode == GL_NORMAL) - sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); - else if (cb_prematch) - sprint(self, PRINT_MEDIUM, - "Pipebomb mode not available in prematch\n"); - else if (self.weaponmode == GL_PIPEBOMB) - sprint(self, PRINT_MEDIUM, "Pipebomb mode\n"); - } else if (self.current_weapon == WEAP_SNIPER_RIFLE) - sprint(self, PRINT_MEDIUM, "Sniper rifle ready\n"); - else if (self.current_weapon == WEAP_AUTO_RIFLE) - sprint(self, PRINT_MEDIUM, "Sniper rifle on fully automatic mode\n"); + switch (self.current_weapon) + { + case WEAP_GRENADE_LAUNCHER: + if (self.weaponmode == GL_NORMAL) + sprint(self, PRINT_HIGH, "Normal grenade mode\n"); + else if (cb_prematch) + sprint(self, PRINT_HIGH, + "Pipebomb mode not available in prematch\n"); + else if (self.weaponmode == GL_PIPEBOMB) + sprint(self, PRINT_HIGH, "Pipebomb mode\n"); + break; + case WEAP_SNIPER_RIFLE: + sprint(self, PRINT_HIGH, "Sniper rifle ready\n"); + break; + case WEAP_AUTO_RIFLE: + sprint(self, PRINT_HIGH, "Sniper rifle on fully automatic mode\n"); + break; + } }; float (float weap) W_GetSlot = { From 52f3bc2a11d50fea7a0b2bab255fca4889bf421d Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 11 Aug 2019 22:58:10 +1000 Subject: [PATCH 0787/2474] fixes hwguy sometimes locked out of firing all weapons --- ssqc/player.qc | 2 +- ssqc/weapons.qc | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 9ca8f593..1b00ad9c 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -502,9 +502,9 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { void () player_assaultcannondown1 =[103, player_assaultcannondown1] { if (self.count == 1) { sound(self, 1, "weapons/asscan3.wav", 0.8, 1); + self.heat = 0; } if (self.count >= 15) { - self.heat = 0; self.fire_held_down = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); if (!cannon_move) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d7748640..138bb302 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3405,7 +3405,10 @@ void () W_WeaponFrame = { if (cease_fire) return; - if (self.button0 && !self.fire_held_down) { + if (self.button0 + && (!self.fire_held_down + || + (self.fire_held_down && self.heat == 0 && self.playerclass == PC_HVYWEAP))) { if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) { From c449bc180cadb52e4975d01ebcfbc522786aed46 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 11 Aug 2019 23:50:15 +1000 Subject: [PATCH 0788/2474] precache pk3 instead of loose files --- csqc/main.qc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1540ce72..ee8bb230 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,10 +14,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { precache_model("progs/weapons/v_rock.mdl"); - for (float i = 0; i < HudIcons.length; i++) - { - precache_pic(HudIcons[i].icon); - } + precache_file("fo_hud.pk3"); registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); From 8681613fd8e8db4ab2a3bbf33fa574f3dbef2311 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 12 Aug 2019 22:59:13 +1200 Subject: [PATCH 0789/2474] Fix duel mode bugs when players leave --- ssqc/clan.qc | 5 +++-- ssqc/client.qc | 33 ++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 3cc08baf..04c83398 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -166,7 +166,8 @@ void () StartMatch = } } if (duelmode) { - ResetPlayers(); + //ResetPlayers(); + CountMatchPlayersAndReset(); } }; @@ -852,7 +853,7 @@ float () CheckAllPlayersReady = { f1 = TeamFortress_GetNoPlayers (); bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); - if (v_ready == f1 ) { + if (v_ready == f1 && v_ready > 0) { if(cease_fire) { bprint (2, "All players ready, match will start after ceasefire ends.\n"); } else { diff --git a/ssqc/client.qc b/ssqc/client.qc index 4023c294..0d2a714d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2397,6 +2397,23 @@ void (optional float csqcactive) ClientConnect = { sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); }; +void () CountMatchPlayersAndReset = { + local float playersleft = 0; + local entity te = find (world, classname, "player"); + while (te) { + if (!te.has_disconnected) { + playersleft = playersleft + 1; + } + te = find (te, classname, "player"); + } + if (!playersleft) { + bprint(PRINT_HIGH, "Match \sabandoned\s, resetting to prematch\n"); + InitPrematch(); + } else if(CountRemainingTeams() < 2) { + ResetPlayersWithCountdown(); + } +} + void () ClientDisconnect = { local string st; local float fr; @@ -2411,21 +2428,7 @@ void () ClientDisconnect = { if (duelmode && clanbattle && !cb_prematch) { //In duelmode, reset back to prematch if everyone leaves half-way through a round - local float playersleft = 0; - local entity te = find (world, classname, "player"); - while (te) { - if (!te.has_disconnected) { - playersleft = playersleft + 1; - } - te = find (te, classname, "player"); - } - if (!playersleft) { - bprint(PRINT_HIGH, "Match \sabandoned\s, resetting to prematch\n"); - InitPrematch(); - } else if(CountRemainingTeams() < 2) { - ResetPlayersWithCountdown(); - } - + CountMatchPlayersAndReset(); } set_suicide_frame(); self.netname = string_null; From d6419dff5ba342b525c9111b6fd02a606867e3d1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 12 Aug 2019 23:01:19 +1200 Subject: [PATCH 0790/2474] remvoe redundant function --- ssqc/tfort.qc | 55 --------------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c5c816d3..b4df8ec1 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1292,61 +1292,6 @@ void () TeamFortress_SetHealth = { self.health = self.max_health; }; -float (float pc) TeamFortress_GetMaxHealth = { - if (pc == PC_SCOUT) { - if (old_hp_armor) - return 75; - else - return PC_SCOUT_MAXHEALTH; - } else if (pc == PC_SNIPER) { - if (old_hp_armor) - return 90; - else - return PC_SNIPER_MAXHEALTH; - } else if (pc == PC_SOLDIER) { - if (old_hp_armor) - return 100; - else - return PC_SOLDIER_MAXHEALTH; - } else if (pc == PC_DEMOMAN) { - if (old_hp_armor) - return 90; - else - return PC_DEMOMAN_MAXHEALTH; - } else if (pc == PC_MEDIC) { - if (old_hp_armor) - return 90; - else - return PC_MEDIC_MAXHEALTH; - } else if (pc == PC_HVYWEAP) { - if (old_hp_armor) - return 100; - else - return PC_HVYWEAP_MAXHEALTH; - } else if (pc == PC_PYRO) { - if (old_hp_armor) - return 100; - else - return PC_PYRO_MAXHEALTH; - } else if (pc == PC_CIVILIAN) { - if (old_hp_armor) - return 50; - else - return PC_CIVILIAN_MAXHEALTH; - } else if (pc == PC_SPY) { - if (old_hp_armor) - return 90; - else - return PC_SPY_MAXHEALTH; - } else if (pc == PC_ENGINEER) { - if (old_hp_armor) - return 80; - else - return PC_ENGINEER_MAXHEALTH; - } - return 1; -}; - string (float tn) TeamFortress_GetColorSkin = { string s; s = ""; From be43ff432889643f7b043257032e83ba5d645abe Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 12 Aug 2019 22:34:03 +1000 Subject: [PATCH 0791/2474] undo message level --- ssqc/weapons.qc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 138bb302..398929c0 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2107,18 +2107,18 @@ void () W_PrintWeaponMessage = { { case WEAP_GRENADE_LAUNCHER: if (self.weaponmode == GL_NORMAL) - sprint(self, PRINT_HIGH, "Normal grenade mode\n"); + sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); else if (cb_prematch) - sprint(self, PRINT_HIGH, + sprint(self, PRINT_MEDIUM, "Pipebomb mode not available in prematch\n"); else if (self.weaponmode == GL_PIPEBOMB) - sprint(self, PRINT_HIGH, "Pipebomb mode\n"); + sprint(self, PRINT_MEDIUM, "Pipebomb mode\n"); break; case WEAP_SNIPER_RIFLE: - sprint(self, PRINT_HIGH, "Sniper rifle ready\n"); + sprint(self, PRINT_MEDIUM, "Sniper rifle ready\n"); break; case WEAP_AUTO_RIFLE: - sprint(self, PRINT_HIGH, "Sniper rifle on fully automatic mode\n"); + sprint(self, PRINT_MEDIUM, "Sniper rifle on fully automatic mode\n"); break; } }; From c90f9f6ec4fef703605a81642f78b73ab5000d19 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 12 Aug 2019 23:07:15 +1000 Subject: [PATCH 0792/2474] back to precache pic, haven't put paths etc into defs as i don't see the point... someone else can decide --- csqc/csextradefs.qc | 16 ++++++++++++++-- csqc/main.qc | 5 ++++- share/defs.h | 32 ++++++++++++++++---------------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index db42c2c4..895fe2ea 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -125,7 +125,7 @@ typedef struct { string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[16] = { +FO_Hud_Icons HudIcons[28] = { {ICON_SCOUT}, {ICON_SNIPER}, {ICON_SOLDIER}, @@ -141,7 +141,19 @@ FO_Hud_Icons HudIcons[16] = { {ICON_CAPS}, {ICON_IDENTIFY}, {ICON_GREN1}, - {ICON_GREN2} + {ICON_GREN2}, + {"textures/wad/off_icon_glow_4.png"}, + {"textures/wad/off_icon_glow_3.png"}, + {"textures/wad/off_icon_glow_2.png"}, + {"textures/wad/off_icon_glow_1.png"}, + {"textures/wad/off_icon_glow_0.png"}, + {"textures/wad/flag_4.png"}, + {"textures/wad/flag_3.png"}, + {"textures/wad/flag_2.png"}, + {"textures/wad/flag_1.png"}, + {"textures/wad/flag_0.png"}, + {"textures/wad/num_percent.png"}, + {"textures/wad/anum_percent.png"} }; float team_no; diff --git a/csqc/main.qc b/csqc/main.qc index ee8bb230..1540ce72 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,7 +14,10 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { precache_model("progs/weapons/v_rock.mdl"); - precache_file("fo_hud.pk3"); + for (float i = 0; i < HudIcons.length; i++) + { + precache_pic(HudIcons[i].icon); + } registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); diff --git a/share/defs.h b/share/defs.h index cf36a0db..6b326ab1 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1322,22 +1322,22 @@ #define FO_HUD_INSERT_BEFORE 0 #define FO_HUD_INSERT_AFTER 1 -#define ICON_CLIPSIZE "clipsize.png" -#define ICON_FRAGSTREAK "fragstreak.png" -#define ICON_CAPS "caps.png" -#define ICON_IDENTIFY "identify.png" -#define ICON_GREN1 "gren1.png" -#define ICON_GREN2 "gren2.png" -#define ICON_SCOUT "scout.png" -#define ICON_SNIPER "sniper.png" -#define ICON_SOLDIER "soldier.png" -#define ICON_DEMOMAN "demoman.png" -#define ICON_MEDIC "medic.png" -#define ICON_HWGUY "hwguy.png" -#define ICON_PYRO "pyro.png" -#define ICON_SPY "spy.png" -#define ICON_ENGINEER_SG "engineer_sg.png" -#define ICON_ENGINEER_DISP "engineer_disp.png" +#define ICON_CLIPSIZE "textures/wad/clipsize.png" +#define ICON_FRAGSTREAK "textures/wad/fragstreak.png" +#define ICON_CAPS "textures/wad/caps.png" +#define ICON_IDENTIFY "textures/wad/identify.png" +#define ICON_GREN1 "textures/wad/gren1.png" +#define ICON_GREN2 "textures/wad/gren2.png" +#define ICON_SCOUT "textures/wad/scout.png" +#define ICON_SNIPER "textures/wad/sniper.png" +#define ICON_SOLDIER "textures/wad/soldier.png" +#define ICON_DEMOMAN "textures/wad/demoman.png" +#define ICON_MEDIC "textures/wad/medic.png" +#define ICON_HWGUY "textures/wad/hwguy.png" +#define ICON_PYRO "textures/wad/pyro.png" +#define ICON_SPY "textures/wad/spy.png" +#define ICON_ENGINEER_SG "textures/wad/engineer_sg.png" +#define ICON_ENGINEER_DISP "textures/wad/engineer_disp.png" // stats // first 32 are reserved From 0b26b2fa3c237176042c192eefbb6d260518ac34 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 15 Aug 2019 20:27:25 +1200 Subject: [PATCH 0793/2474] More useful options in quad round time menu --- ssqc/menu.qc | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 6b68c357..4203a23e 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1132,8 +1132,19 @@ void () Menu_Admin = break; case ADMIN_MENU_TYPE_QUAD_ROUNDTL: s_menu1 = "Round Time Input Menu: \n\n"; - s_menu1 = strcat(s_menu1, "Enter a number between 1 and 10 \n"); - s_menu1 = strcat(s_menu1, "\n\n"); + //s_menu1 = strcat(s_menu1, "Enter a number between 1 and 10 \n"); + //s_menu1 = strcat(s_menu1, "\n\n"); + + s_menu1 = strcat(s_menu1, Q"\s[1]\s 1 minute \n"); + s_menu1 = strcat(s_menu1, Q"\s[2]\s 5 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[3]\s 10 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[4]\s 25 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[5]\s 20 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[6]\s 25 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[7]\s 30 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[8]\s 35 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[9]\s 45 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[0]\s 60 minutes \n"); Status_Menu(self, Menu_Admin_Input, s_menu1); break; @@ -1604,9 +1615,21 @@ void (float inp) Menu_Admin_Input = else if (self.current_menu_type == ADMIN_MENU_TYPE_QUAD_ROUNDTL) { local string d; - d = strcat("localinfo round_time ", ftos(inp), "\n"); + local float rt = (inp - 1) * 5; + switch(inp) { + case 1: + rt = 1; + break; + case 9: + rt = 45; + break; + case 10: + rt = 60; + break; + } + d = strcat("localinfo round_time ", ftos(rt), "\n"); localcmd(d); - bprint(2, "Quad Round Timelimit changed to ", ftos(inp), "\n"); + bprint(2, "Quad Round Timelimit changed to ", ftos(rt), "\n"); self.current_menu_type = ADMIN_MENU_TYPE_QUADMODE; self.current_menu_page = 1; Menu_Admin(); From d9984d4c9f1f4a7b4f0c05b4e8a520fb14997b48 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 15 Aug 2019 20:29:27 +1200 Subject: [PATCH 0794/2474] Fix typo --- ssqc/menu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 4203a23e..8790d18b 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1138,7 +1138,7 @@ void () Menu_Admin = s_menu1 = strcat(s_menu1, Q"\s[1]\s 1 minute \n"); s_menu1 = strcat(s_menu1, Q"\s[2]\s 5 minutes \n"); s_menu1 = strcat(s_menu1, Q"\s[3]\s 10 minutes \n"); - s_menu1 = strcat(s_menu1, Q"\s[4]\s 25 minutes \n"); + s_menu1 = strcat(s_menu1, Q"\s[4]\s 15 minutes \n"); s_menu1 = strcat(s_menu1, Q"\s[5]\s 20 minutes \n"); s_menu1 = strcat(s_menu1, Q"\s[6]\s 25 minutes \n"); s_menu1 = strcat(s_menu1, Q"\s[7]\s 30 minutes \n"); From b1cc835cdea60d4f70d5abdb1db7592c2323e0b8 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 25 Aug 2019 19:16:56 +1000 Subject: [PATCH 0795/2474] fix blend type on drawpic for hud icons --- csqc/hud.qc | 6 +++--- csqc/hud_helpers.qc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 7b090bd8..0f21bb82 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -239,7 +239,7 @@ void Hud_DrawFlagStatusBar(float width) drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - sizex * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 1); + drawpic([pos_x, pos_y - sizex * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); if (FlagInfoLines[i].timeleft >= 0) { @@ -286,7 +286,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) string msg = ""; icon = HudIcons[playerclass-1].icon; - drawpic(pos, icon, size, '1 1 1', 1, 1); + drawpic(pos, icon, size, '1 1 1', 1, 0); float len = 0, offset = 0; @@ -446,7 +446,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) pos = [pos_x, pos_y - size_y - 2]; basepos = pos; icon = HudIcons[playerclass].icon; - drawpic(pos, icon, size, '1 1 1', 1, 1); + drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.HasDispenser) { msg = strcat("H: ", ftos(SBAR.DispenserHealth)); diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index aab73a04..f7da038d 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -320,7 +320,7 @@ void Hud_DrawPanelLMP(string id, string val, string icon) vector size = FO_Hud_Icon_Size * DrawPanel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; - drawpic(pos, icon, size, '1 1 1', 1, 1); + drawpic(pos, icon, size, '1 1 1', 1, 0); float len; len = strlen(val); From da9b646bd569b8438106779b9820479ffb6d31f4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 25 Aug 2019 23:03:41 +1200 Subject: [PATCH 0796/2474] Flaginfo now a normal panel. Everything is arrays --- csqc/csextradefs.qc | 272 +++++++++++++++++++++++++++++--------------- csqc/hud.qc | 240 ++++++++++++++++++++++++++------------ csqc/hud_helpers.qc | 57 +++++----- csqc/settings.qc | 1 + share/defs.h | 23 +++- 5 files changed, 399 insertions(+), 194 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 895fe2ea..912d149a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -4,6 +4,98 @@ float fo_hud_editor; float jumptime; +float(string) GetDrawPanel; +void(string, string, string) Hud_DrawPanelLMP; +void(string id, string identify) Hud_DrawIdentifyPanel; +void (string panelid, float display, string text, string icon) Hud_DrawHudOptionsPanel; +void (string id, float playerclass) Hud_DrawClassInfoPanel; +void (string panelid) Hud_DrawFlagStatusBar; + +typedef struct +{ + string icon; +} FO_Hud_Icons; +FO_Hud_Icons HudIcons[28] = { + {ICON_CLIPSIZE}, + {ICON_FRAGSTREAK}, + {ICON_CAPS}, + {ICON_GREN1}, + {ICON_GREN2}, + {ICON_IDENTIFY}, + {ICON_SCOUT}, + {ICON_SNIPER}, + {ICON_SOLDIER}, + {ICON_DEMOMAN}, + {ICON_MEDIC}, + {ICON_HWGUY}, + {ICON_PYRO}, + {ICON_SPY}, + {ICON_ENGINEER_SG}, + {ICON_ENGINEER_DISP}, + {ICON_SECURITY_BUTTON_GREEN}, + {ICON_SECURITY_BUTTON_YELLOW}, + {ICON_SECURITY_BUTTON_RED}, + {ICON_SECURITY_BUTTON_BLUE}, + {ICON_SECURITY_BUTTON_ANY}, + {ICON_FLAG_ANY}, + {ICON_FLAG_BLUE}, + {ICON_FLAG_RED}, + {ICON_FLAG_YELLOW}, + {ICON_FLAG_GREEN}, + {"textures/wad/num_percent.png"}, + {"textures/wad/anum_percent.png"} +}; + +typedef struct { + string ClipSize; + float FragStreak; + float Caps; + string Identify; + float PlayerClass; + float Gren1; + float Gren2; + // scout + float ScannerOn; + float ScannerRange; + float ScannerTeamNo; + float ScannerPlayerClass; + float ScannerTFItemsFlags; + // sniper + float SniperDam; + float SniperMax; + // demoman + float IsDetpacking; + float DetpackLeft; + // medic + float AuraActive; + float HealCount; + float HealAmount; + float AuraStatus; + // hwguy + float LockedCannon; + // spy + float IsUndercover; + float InvisOnly; + float UndercoverTeam; + float UndercoverSkin; + float UndercoverTimer; + float DisguiseTeam; + float QueueTeam; + float DisguiseSkin; + float QueueSkin; + // engineer + float IsBuilding; + float BuildingPercentage; + float HasSentry; + float SentryLevel; + float SentryHealth; + float SentryAmmoShells; + float SentryAmmoRockets; + float HasDispenser; + float DispenserHealth; +} FO_SBAR; +FO_SBAR SBAR; + typedef struct { float x; @@ -33,7 +125,7 @@ typedef struct { FlagInfoLine FlagInfoLines[10]; // hud stuff - +/* typedef struct { vector Position; float GrowDirection; @@ -41,120 +133,114 @@ typedef struct { float Scale; float Display; } FO_Hud_FlagIcon; - +*/ typedef struct { + string id; + string Name; vector Position; vector FillSize; float Scale; float Display; float NodeInsertLoc; + void(string panelid, float display, string text, string icon) drawPanel; + string() getValue; } FO_Hud_Panel; FO_Hud_Panel DrawPanel; FO_Hud_Panel NewPanel; typedef struct { - FO_Hud_FlagIcon FlagIcon; - FO_Hud_Panel ClipSize; - FO_Hud_Panel FragStreak; - FO_Hud_Panel Caps; - FO_Hud_Panel Gren1; - FO_Hud_Panel Gren2; - FO_Hud_Panel PlayerClass; - FO_Hud_Panel Identify; +// FO_Hud_FlagIcon FlagIcon; +// FO_Hud_Panel ClipSize; +// FO_Hud_Panel FragStreak; +// FO_Hud_Panel Caps; +// FO_Hud_Panel Gren1; +// FO_Hud_Panel Gren2; +// FO_Hud_Panel PlayerClass; +// FO_Hud_Panel Identify; +// FO_Hud_Panel GrenTimer; +// FO_Hud_Panel HudOptions; vector MousePos; } FO_Hud_Settings; + +void(string panelid, float display, string text, string icon) drawClipSize = { + if (SBAR.ClipSize || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, text, icon); + } +}; + +void(string panelid, float display, string text, string icon) drawIdentify = { + if (strlen(SBAR.Identify) > 0 || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawIdentifyPanel(panelid, text); + } +}; + +void(string panelid, float display, string text, string icon) drawFlagInfo = { + if (display || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawFlagStatusBar(panelid); + } +}; + +void(string panelid, float display, string text, string icon) drawIconPanel = { + if (display || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, text, icon); + } +}; +void(string panelid, float display, string text, string icon) drawSpecial = { + if (SBAR.PlayerClass || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawClassInfoPanel(panelid, SBAR.PlayerClass); + } +}; FO_Hud_Settings HudSettings; + +void(string panelid, float display, string text, string icon) doNothing = {}; + +enum { + HUD_PANEL_CLIPSIZE, + HUD_PANEL_FRAGSTREAK, + HUD_PANEL_CAPS, + HUD_PANEL_GREN1, + HUD_PANEL_GREN2, + HUD_PANEL_PLAYERCLASS, + HUD_PANEL_IDENTIFY, + HUD_PANEL_HUDOPTIONS, + HUD_PANEL_FLAGINFO, + HUD_PANEL_GRENTIMER +}; + +var FO_Hud_Panel Hud_Panels[] = { + {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'0 0','50 26',1,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, + {"capspanel",FO_HUD_CAPS_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, + {"playerclasspanel",FO_HUD_SPECIAL_NAME,'0 0','50 26',1,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,1,0, drawIdentify, {return "";}}, + {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'0 0','150 260',1,1,0, doNothing, {return DrawPanel.id;}}, + {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,1,0, drawFlagInfo, {return DrawPanel.id;}} //, + //{"grentimerpanel","Grenade Timer",'0 0','50 26',1,1,0, doNothing, {return "";}} +}; + + + + typedef struct { float Autohop; } FO_Settings; FO_Settings Settings; -typedef struct { - string ClipSize; - float FragStreak; - float Caps; - string Identify; - float PlayerClass; - float Gren1; - float Gren2; - // scout - float ScannerOn; - float ScannerRange; - float ScannerTeamNo; - float ScannerPlayerClass; - float ScannerTFItemsFlags; - // sniper - float SniperDam; - float SniperMax; - // demoman - float IsDetpacking; - float DetpackLeft; - // medic - float AuraActive; - float HealCount; - float HealAmount; - float AuraStatus; - // hwguy - float LockedCannon; - // spy - float IsUndercover; - float InvisOnly; - float UndercoverTeam; - float UndercoverSkin; - float UndercoverTimer; - float DisguiseTeam; - float QueueTeam; - float DisguiseSkin; - float QueueSkin; - // engineer - float IsBuilding; - float BuildingPercentage; - float HasSentry; - float SentryLevel; - float SentryHealth; - float SentryAmmoShells; - float SentryAmmoRockets; - float HasDispenser; - float DispenserHealth; -} FO_SBAR; -FO_SBAR SBAR; -typedef struct -{ - string icon; -} FO_Hud_Icons; -FO_Hud_Icons HudIcons[28] = { - {ICON_SCOUT}, - {ICON_SNIPER}, - {ICON_SOLDIER}, - {ICON_DEMOMAN}, - {ICON_MEDIC}, - {ICON_HWGUY}, - {ICON_PYRO}, - {ICON_SPY}, - {ICON_ENGINEER_SG}, - {ICON_ENGINEER_DISP}, - {ICON_CLIPSIZE}, - {ICON_FRAGSTREAK}, - {ICON_CAPS}, - {ICON_IDENTIFY}, - {ICON_GREN1}, - {ICON_GREN2}, - {"textures/wad/off_icon_glow_4.png"}, - {"textures/wad/off_icon_glow_3.png"}, - {"textures/wad/off_icon_glow_2.png"}, - {"textures/wad/off_icon_glow_1.png"}, - {"textures/wad/off_icon_glow_0.png"}, - {"textures/wad/flag_4.png"}, - {"textures/wad/flag_3.png"}, - {"textures/wad/flag_2.png"}, - {"textures/wad/flag_1.png"}, - {"textures/wad/flag_0.png"}, - {"textures/wad/num_percent.png"}, - {"textures/wad/anum_percent.png"} -}; float team_no; diff --git a/csqc/hud.qc b/csqc/hud.qc index 7b090bd8..65a834a8 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,71 +1,95 @@ -void GetDrawPanel(string id) +float GetDrawPanel(string id) { + for(float i = 0; i < Hud_Panels.length; i++) { + if(Hud_Panels[i].id == id) { + DrawPanel = Hud_Panels[i]; + return i; + } + } + return -1; +/* switch (id) { - case "hudclipsize": + //case "hudclipsize": case "clipsizepanel": - DrawPanel = HudSettings.ClipSize; + DrawPanel = Hud_Panels[HUD_PANEL_CLIPSIZE]; break; - case "hudfragstreak": + //case "hudfragstreak": case "fragstreakpanel": - DrawPanel = HudSettings.FragStreak; + DrawPanel = Hud_Panels[HUD_PANEL_FRAGSTREAK]; break; - case "hudcaps": + //case "hudcaps": case "capspanel": - DrawPanel = HudSettings.Caps; + DrawPanel = Hud_Panels[HUD_PANEL_CAPS]; break; - case "hudgren1": + //case "hudgren1": case "gren1panel": - DrawPanel = HudSettings.Gren1; + DrawPanel = Hud_Panels[HUD_PANEL_GREN1]; break; - case "hudgren2": + //case "hudgren2": case "gren2panel": - DrawPanel = HudSettings.Gren2; + DrawPanel = Hud_Panels[HUD_PANEL_GREN2]; break; - case "hudplayerclass": + //case "hudplayerclass": case "playerclasspanel": - DrawPanel = HudSettings.PlayerClass; + DrawPanel = Hud_Panels[HUD_PANEL_PLAYERCLASS]; break; - case "hudidentify": + //case "hudidentify": case "identifypanel": - DrawPanel = HudSettings.Identify; + DrawPanel = Hud_Panels[HUD_PANEL_IDENTIFY]; + break; + //case "hudoptions": + case "hudoptionspanel": + DrawPanel = Hud_Panels[HUD_PANEL_HUDOPTIONS]; break; } +*/ } void SetDrawPanel(string id) { + for(float i = 0; i < Hud_Panels.length; i++) { + if(Hud_Panels[i].id == id) { + Hud_Panels[i] = DrawPanel; + } + } +/* switch (id) { - case "hudclipsize": + //case "hudclipsize": case "clipsizepanel": - HudSettings.ClipSize = DrawPanel; + Hud_Panels[HUD_PANEL_CLIPSIZE] = DrawPanel; break; - case "hudfragstreak": + //case "hudfragstreak": case "fragstreakpanel": - HudSettings.FragStreak = DrawPanel; + Hud_Panels[HUD_PANEL_FRAGSTREAK] = DrawPanel; break; - case "hudcaps": + //case "hudcaps": case "capspanel": - HudSettings.Caps = DrawPanel; + Hud_Panels[HUD_PANEL_CAPS] = DrawPanel; break; - case "hudgren1": + //case "hudgren1": case "gren1panel": - HudSettings.Gren1 = DrawPanel; + Hud_Panels[HUD_PANEL_GREN1] = DrawPanel; break; - case "hudgren2": + //case "hudgren2": case "gren2panel": - HudSettings.Gren2 = DrawPanel; + Hud_Panels[HUD_PANEL_GREN2] = DrawPanel; break; - case "hudplayerclass": + //case "hudplayerclass": case "playerclasspanel": - HudSettings.PlayerClass = DrawPanel; + Hud_Panels[HUD_PANEL_PLAYERCLASS]= DrawPanel; break; - case "hudidentify": + //case "hudidentify": case "identifypanel": - HudSettings.Identify = DrawPanel; + Hud_Panels[HUD_PANEL_IDENTIFY] = DrawPanel; + break; + //case "hudoptions": + case "hudoptionspanel": + Hud_Panels[HUD_PANEL_HUDOPTIONS] = DrawPanel; break; } +*/ } @@ -76,32 +100,40 @@ void Hud_WriteCfg(string path) filehandle = fopen(path, FILE_WRITE); string line; - line = FormatCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); - line = FormatCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); - line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); - line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); - line = FormatCfgString(line, "hudflagicon.display", ftos(HudSettings.FlagIcon.Display)); +// line = FormatCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); +// line = FormatCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); +// line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); +// line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); +// line = FormatCfgString(line, "hudflagicon.display", ftos(HudSettings.FlagIcon.Display)); + for(float i = 0; i < Hud_Panels.length; i++) { + DrawPanel = Hud_Panels[i]; + line = GetPanelString(line, Hud_Panels[i].id); + } +/* DrawPanel = HudSettings.ClipSize; - line = GetPanelString(line, "hudclipsize"); + line = GetPanelString(line, "clipsizepanel"); DrawPanel = HudSettings.FragStreak; - line = GetPanelString(line, "hudfragstreak"); + line = GetPanelString(line, "fragstreakpanel"); DrawPanel = HudSettings.Caps; - line = GetPanelString(line, "hudcaps"); + line = GetPanelString(line, "capspanel"); DrawPanel = HudSettings.Gren1; - line = GetPanelString(line, "hudgren1"); + line = GetPanelString(line, "gren1panel"); DrawPanel = HudSettings.Gren2; - line = GetPanelString(line, "hudgren2"); + line = GetPanelString(line, "gren2panel"); DrawPanel = HudSettings.PlayerClass; - line = GetPanelString(line, "hudplayerclass"); + line = GetPanelString(line, "playerclasspanel"); DrawPanel = HudSettings.Identify; - line = GetPanelString(line, "hudidentify"); + line = GetPanelString(line, "identifypanel"); + DrawPanel = HudSettings.HudOptions; + line = GetPanelString(line, "hudoptionspanel"); +*/ fputs(filehandle, line); fclose(filehandle); } @@ -114,15 +146,15 @@ void FO_Hud_Editor_LoadDefaultSettings() // check struct, put defaults in float yoffset = height - 64; - FO_Hud_FlagIcon HudFlagIcon; - HudFlagIcon.Position = [8, yoffset]; +// FO_Hud_FlagIcon HudFlagIcon; +// HudFlagIcon.Position = [8, yoffset]; // TODO - maybe implement these to allow for pivoting of items - HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; - HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; - HudFlagIcon.Scale = 1; - HudFlagIcon.Display = 1; - HudSettings.FlagIcon = HudFlagIcon; +// HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; +// HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; +// HudFlagIcon.Scale = 1; +// HudFlagIcon.Display = 1; +// HudSettings.FlagIcon = HudFlagIcon; vector pos, fill; float scale, display, nodeInsertLoc; @@ -132,35 +164,46 @@ void FO_Hud_Editor_LoadDefaultSettings() nodeInsertLoc = FO_HUD_INSERT_BEFORE; fill = [FO_HUD_CLIPSIZE_PANEL_X, FO_HUD_CLIPSIZE_PANEL_Y]; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + for(float i = 0; i < Hud_Panels.length; i++) { + pos = [pos_x, pos_y - 2 - 24]; + Hud_Panels[i].Position = pos; + //Hud_Panels[i].FillSize = fillSize; + Hud_Panels[i].Scale = scale; + Hud_Panels[i].Display = display; + Hud_Panels[i].NodeInsertLoc = nodeInsertLoc; + //pnl.Name = name; + } + +/* + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_CLIPSIZE_NAME); FO_Hud_Panel HudClipSize = NewPanel; HudSettings.ClipSize = HudClipSize; pos = [pos_x, pos_y - 2 - 24]; fill = [50, 26]; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_FRAGSTREAK_NAME); FO_Hud_Panel HudFragStreak = NewPanel; HudSettings.FragStreak = HudFragStreak; pos = [pos_x, pos_y - 2 - 24]; fill = [50, 26]; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_CAPS_NAME); FO_Hud_Panel HudCaps = NewPanel; HudSettings.Caps = HudCaps; pos = [pos_x, pos_y - 2 - 24]; fill = [50, 26]; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_GREN1_NAME); FO_Hud_Panel HudGren1 = NewPanel; HudSettings.Gren1 = HudGren1; pos = [pos_x, pos_y - 2 - 24]; fill = [50, 26]; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_GREN2_NAME); FO_Hud_Panel HudGren2 = NewPanel; HudSettings.Gren2 = HudGren2; @@ -168,28 +211,36 @@ void FO_Hud_Editor_LoadDefaultSettings() fill = [50, 26]; nodeInsertLoc = FO_HUD_INSERT_AFTER; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_SPECIAL_NAME); FO_Hud_Panel HudPlayerClass = NewPanel; HudSettings.PlayerClass = HudPlayerClass; pos = [pos_x, pos_y - 2 - 24]; fill = [50, 26]; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc); + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_IDENTIFY_NAME); FO_Hud_Panel HudIdentify = NewPanel; HudSettings.Identify = HudIdentify; + + pos = [pos_x, pos_y - 2 - 24]; + fill = [150, 260]; + GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_OPTIONS_NAME); + FO_Hud_Panel HudOptions = NewPanel; + HudSettings.HudOptions = HudOptions; +*/ + } -void Hud_DrawFlagStatusBar(float width) +void Hud_DrawFlagStatusBar(string panelid) { - if (!HudSettings.FlagIcon.Display) - return; +// if (!HudSettings.FlagIcon.Display && !fo_hud_editor) +// return; vector pos; - pos = HudSettings.FlagIcon.Position; + pos = Hud_Panels[HUD_PANEL_FLAGINFO].Position; float sizey, sizex; - sizey = FO_Hud_Icon_Size_y * HudSettings.FlagIcon.Scale; - sizex = FO_Hud_Icon_Size_x * HudSettings.FlagIcon.Scale; + sizey = FO_Hud_Icon_Size_y * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; + sizex = FO_Hud_Icon_Size_x * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; float flagInfoCount = 0; for (float i = FlagInfoLines.length - 1; i >= 0; i--) @@ -205,15 +256,15 @@ void Hud_DrawFlagStatusBar(float width) if (flagInfoCount > 0) { firstrun = FALSE; - pos = HudSettings.FlagIcon.Position; + pos = Hud_Panels[HUD_PANEL_FLAGINFO].Position; pos_y = pos_y - 4 - sizey * (flagInfoCount - 2); - HudSettings.FlagIcon.Position = pos; + Hud_Panels[HUD_PANEL_FLAGINFO].Position = pos; } } vector fillsize = [sizex * 4, sizey * flagInfoCount]; float alpha = 0; - if (hud_panel("flagiconpanel", pos, fillsize, alpha)) + if (hud_panel(panelid, pos, fillsize, alpha)) { // click event if (fo_hud_editor) @@ -239,7 +290,7 @@ void Hud_DrawFlagStatusBar(float width) drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - sizex * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 1); + drawpic([pos_x, pos_y - sizex * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); if (FlagInfoLines[i].timeleft >= 0) { @@ -250,9 +301,38 @@ void Hud_DrawFlagStatusBar(float width) } } +float Hud_GetSelectedPanel() { + for(float i = 0; i < Hud_Panels.length; i++) { + if(sui_is_last_clicked(Hud_Panels[i].id)) { + return i; + } + } + return -1; +} + +void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string icon) +{ + if(!fo_hud_editor) + return; + + vector pos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; + if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale, 0)) + { + // click event + } + float selectedPanelIndex = Hud_GetSelectedPanel(); + if(selectedPanelIndex < 0) + return; + + FO_Hud_Panel selectedPanel = Hud_Panels[selectedPanelIndex]; + + drawstring(pos + [4,4], selectedPanel.Name, [8,8], MENU_SELECTED, 1, 0); + +} + void Hud_DrawClassInfoPanel(string id, float playerclass) { - if (!DrawPanel.Display) + if (!DrawPanel.Display && !fo_hud_editor) return; switch (SBAR.PlayerClass) @@ -286,7 +366,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) string msg = ""; icon = HudIcons[playerclass-1].icon; - drawpic(pos, icon, size, '1 1 1', 1, 1); + drawpic(pos, icon, size, '1 1 1', 1, 0); float len = 0, offset = 0; @@ -446,7 +526,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) pos = [pos_x, pos_y - size_y - 2]; basepos = pos; icon = HudIcons[playerclass].icon; - drawpic(pos, icon, size, '1 1 1', 1, 1); + drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.HasDispenser) { msg = strcat("H: ", ftos(SBAR.DispenserHealth)); @@ -459,7 +539,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) void Hud_DrawIdentifyPanel(string id, string identify) { - if (!DrawPanel.Display) + if (!DrawPanel.Display && !fo_hud_editor) return; vector pos; @@ -496,14 +576,17 @@ void Hud_DrawIdentifyPanel(string id, string identify) void Hud_Draw(float width, float height) { - Hud_DrawFlagStatusBar(width); + //Hud_DrawFlagStatusBar(width); - if (SBAR.ClipSize) + for(float i = 0; i < Hud_Panels.length; i++) { + Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); + } +/* + if (SBAR.ClipSize || fo_hud_editor) { GetDrawPanel("clipsizepanel"); Hud_DrawPanelLMP("clipsizepanel", SBAR.ClipSize, HudIcons[10].icon); } - GetDrawPanel("fragstreakpanel"); Hud_DrawPanelLMP("fragstreakpanel", ftos(SBAR.FragStreak), HudIcons[11].icon); @@ -511,7 +594,7 @@ void Hud_Draw(float width, float height) Hud_DrawPanelLMP("capspanel", ftos(SBAR.Caps), HudIcons[12].icon); // identify - if (strlen(SBAR.Identify) > 0) + if (strlen(SBAR.Identify) > 0 || fo_hud_editor) { GetDrawPanel("identifypanel"); Hud_DrawIdentifyPanel("identifypanel", SBAR.Identify); @@ -523,11 +606,20 @@ void Hud_Draw(float width, float height) GetDrawPanel("gren2panel"); Hud_DrawPanelLMP("gren2panel", ftos(SBAR.Gren2), HudIcons[14].icon); - if (SBAR.PlayerClass) + if (SBAR.PlayerClass || fo_hud_editor) { GetDrawPanel("playerclasspanel"); Hud_DrawClassInfoPanel("playerclasspanel", SBAR.PlayerClass); } + if (fo_hud_editor) + { + //GetDrawPanel("hudoptionspanel"); + //Hud_DrawPanelLMP("hudoptionspanel", ftos(SBAR.Gren2), HudIcons[14].icon); + //Hud_DrawHudOptionsPanel(); + + } +*/ + HudSettings.MousePos = [Mouse.x, Mouse.y]; } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index aab73a04..5b1737dd 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -15,7 +15,7 @@ vector MENU_TEXT_LARGE = '24 24 0'; float MENU_START_CONTENT = 32; void Hud_WriteCfg(string path); -void GetDrawPanel(string id); +float GetDrawPanel(string id); void SetDrawPanel(string id); void FO_Hud_Editor() @@ -53,22 +53,23 @@ float(string id, vector pos, vector size, string text) hud_button = vector UpdatePos(string id, vector mousepos) { vector pos; - switch (id) - { - case "flagiconpanel": - if (HudSettings.MousePos != [0, 0]) - { - pos = HudSettings.FlagIcon.Position + mousepos - HudSettings.MousePos; - HudSettings.FlagIcon.Position = pos; - } - break; - default: +// switch (id) +// { +// case "flagiconpanel": +// if (HudSettings.MousePos != [0, 0]) +// { +// pos = HudSettings.FlagIcon.Position + mousepos - HudSettings.MousePos; +// HudSettings.FlagIcon.Position = pos; +// } +// break; + +// default: GetDrawPanel(id); pos = DrawPanel.Position + mousepos - HudSettings.MousePos; DrawPanel.Position = pos; SetDrawPanel(id); - break; - } +// break; +// } return pos; } @@ -79,6 +80,7 @@ float(string id, vector pos, vector size, float alpha) hud_panel = if (fo_hud_editor) { + sui_border_box(pos, size, 1, MENU_BORDER, 0.4, 0); if (sui_is_last_clicked(id)) { sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); @@ -104,15 +106,15 @@ float(string id, vector pos, vector size, float alpha) hud_panel = } } - sui_push_frame(pos, size); - - sui_fill([0, 0], size, basecolor, alpha, 0); - - sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_action_element([0, 0], size, id, sui_noop); - sui_pop_frame(); - - return sui_is_clicked(id); + sui_push_frame(pos, size); + + sui_fill([0, 0], size, basecolor, alpha, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_action_element([0, 0], size, id, sui_noop); + sui_pop_frame(); + + return sui_is_clicked(id); }; // this draws backwards, haven't bothered to change as we don't use it @@ -229,6 +231,7 @@ void FO_Hud_Editor_LoadSettings() switch(field) { +/* case "hudflagicon.position": count = tokenizebyseparator(val, ","); x = stof(argv(0)); @@ -247,6 +250,7 @@ void FO_Hud_Editor_LoadSettings() case "hudflagicon.display": HudSettings.FlagIcon.Display = stof(val); break; +*/ default: count = tokenizebyseparator(field, "."); string pnl; @@ -287,7 +291,7 @@ void FO_Hud_Editor_LoadSettings() } } -void GetNewPanel(vector pos, vector fillSize, float scale, float display, float nodeInsertLoc) +void GetNewPanel(vector pos, vector fillSize, float scale, float display, float nodeInsertLoc, string name) { FO_Hud_Panel pnl; @@ -296,6 +300,7 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float pnl.Scale = scale; pnl.Display = display; pnl.NodeInsertLoc = nodeInsertLoc; + pnl.Name = name; NewPanel = pnl; } @@ -303,7 +308,7 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float // draws value string using lmps void Hud_DrawPanelLMP(string id, string val, string icon) { - if (!DrawPanel.Display) + if (!DrawPanel.Display && !fo_hud_editor) return; vector pos; @@ -320,7 +325,7 @@ void Hud_DrawPanelLMP(string id, string val, string icon) vector size = FO_Hud_Icon_Size * DrawPanel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; - drawpic(pos, icon, size, '1 1 1', 1, 1); + drawpic(pos, icon, size, '1 1 1', 1, 0); float len; len = strlen(val); @@ -347,4 +352,4 @@ vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, ve drawstring(pos, msg, fontSize, colour, 1, 0); return pos; -} \ No newline at end of file +} diff --git a/csqc/settings.qc b/csqc/settings.qc index baba5065..f08288b1 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -16,6 +16,7 @@ void FO_LoadDefaultSettings() void FO_LoadSettings() { + Hud_Panels[HUD_PANEL_HUDOPTIONS].drawPanel = Hud_DrawHudOptionsPanel; FO_LoadDefaultSettings(); float filehandle; diff --git a/share/defs.h b/share/defs.h index 6b326ab1..44650441 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1322,6 +1322,17 @@ #define FO_HUD_INSERT_BEFORE 0 #define FO_HUD_INSERT_AFTER 1 +#define FO_HUD_CLIPSIZE_NAME "Clip Size" +#define FO_HUD_FRAGSTREAK_NAME "Frag Streak" +#define FO_HUD_CAPS_NAME "Caps" +#define FO_HUD_IDENTIFY_NAME "ID" +#define FO_HUD_GREN1_NAME "Gren 1" +#define FO_HUD_GREN2_NAME "Gren 2" +#define FO_HUD_SPECIAL_NAME "Class Special" +#define FO_HUD_GRENTIMER_NAME "Grenade Timer" +#define FO_HUD_OPTIONS_NAME "Options" +#define FO_HUD_FLAGINFO_NAME "Flag Status" + #define ICON_CLIPSIZE "textures/wad/clipsize.png" #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" #define ICON_CAPS "textures/wad/caps.png" @@ -1338,7 +1349,17 @@ #define ICON_SPY "textures/wad/spy.png" #define ICON_ENGINEER_SG "textures/wad/engineer_sg.png" #define ICON_ENGINEER_DISP "textures/wad/engineer_disp.png" +#define ICON_SECURITY_BUTTON_ANY "textures/wad/off_icon_glow_0.png" +#define ICON_SECURITY_BUTTON_BLUE "textures/wad/off_icon_glow_1.png" +#define ICON_SECURITY_BUTTON_RED "textures/wad/off_icon_glow_2.png" +#define ICON_SECURITY_BUTTON_YELLOW "textures/wad/off_icon_glow_3.png" +#define ICON_SECURITY_BUTTON_GREEN "textures/wad/off_icon_glow_4.png" +#define ICON_FLAG_ANY "textures/wad/flag_0.png" +#define ICON_FLAG_BLUE "textures/wad/flag_1.png" +#define ICON_FLAG_RED "textures/wad/flag_2.png" +#define ICON_FLAG_YELLOW "textures/wad/flag_3.png" +#define ICON_FLAG_GREEN "textures/wad/flag_4.png" // stats // first 32 are reserved -#define STAT_TEAMNO 33 \ No newline at end of file +#define STAT_TEAMNO 33 From a909766df9abb4a08cb4c83a051947f07d1fc747 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 26 Aug 2019 00:06:34 +1200 Subject: [PATCH 0797/2474] Fix double 'clip:' on legacy statusbar --- ssqc/status.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 9ab6863a..610fb50b 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1248,8 +1248,7 @@ string(entity pl, float csqcactive) ClipSizeToString = } else { - st = Q"\sClip\s: "; - st = strcat(st, strpadl(ftos(floor(num)), 2)); + st = strpadl(ftos(floor(num)), 2); st = strcat(st, "/"); st = strcat(st, strpadr(ftos(max), 3)); } From 904ea78e04f08e963051892ac8eb9ee2a9289a3c Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 26 Aug 2019 23:11:49 +1000 Subject: [PATCH 0798/2474] change demo name format --- ssqc/clan.qc | 12 ++++++------ ssqc/defs.qc | 9 +++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 04c83398..8c64ed5b 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -231,17 +231,17 @@ void () PreMatch_Think = { calltimeofday(); localcmd("record \""); - localcmd(ftos (tod_day)); // day + localcmd(tod_year); // year localcmd("-"); - localcmd(ftos (tod_mon)); // month + localcmd(tod_mon); // month localcmd("-"); - localcmd(ftos (tod_year)); // year + localcmd(tod_day); // day localcmd("_"); - localcmd(ftos (tod_hour)); // hour + localcmd(tod_hour); // hour localcmd("-"); - localcmd(ftos (tod_min)); // minute + localcmd(tod_min); // minute localcmd("-"); - localcmd(ftos (tod_sec)); // second + localcmd(tod_sec); // second localcmd("_["); localcmd(mapname); diff --git a/ssqc/defs.qc b/ssqc/defs.qc index a4012a5a..6be7b357 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -435,11 +435,16 @@ void() calltimeofday = #231; // force server to ca //In order to make it more useful, this header includes a timeofday function which just grabs the values for you to use in your qc code straight after calling calltimeofday. -float tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; +string tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; //This function is to facilitate use, and need not be modified. +string zeropad(float val) +{ + return (val < 10 ? strcat("0", ftos(val)) : ftos(val)); +} + void(float s, float mi, float h, float d, float mo, float y, string tmp_timeofday) timeofday = -{ tod_sec = s; tod_min = mi; tod_hour = h; tod_day = d; tod_mon = (mo + 1); tod_year = y; }; +{ tod_sec = zeropad(s); tod_min = zeropad(mi); tod_hour = zeropad(h); tod_day = zeropad(d); tod_mon = zeropad((mo + 1)); tod_year = zeropad(y); }; //============================================================================ From d93d55a925a62a76bf56e5bc332876e000df2d5e Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 10 Sep 2019 00:01:44 +1200 Subject: [PATCH 0799/2474] Hud editor scaling --- csqc/csextradefs.qc | 9 ++++-- csqc/csprogs.src | 2 +- csqc/hud.qc | 73 +++++++++++++++++++++++++++++++-------------- csqc/hud_helpers.qc | 30 ++++++++++++++++--- csqc/main.qc | 2 +- 5 files changed, 84 insertions(+), 32 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 912d149a..d633be53 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -15,7 +15,8 @@ typedef struct { string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[28] = { +FO_Hud_Icons HudIcons[29] = { + {""}, {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, @@ -148,6 +149,8 @@ typedef struct { FO_Hud_Panel DrawPanel; FO_Hud_Panel NewPanel; +FO_Hud_Panel Editor_SelectedPanel; +float Editor_SelectedPanel_Index; typedef struct { // FO_Hud_FlagIcon FlagIcon; @@ -207,6 +210,7 @@ FO_Hud_Settings HudSettings; void(string panelid, float display, string text, string icon) doNothing = {}; enum { + HUD_PANEL_HUDOPTIONS, HUD_PANEL_CLIPSIZE, HUD_PANEL_FRAGSTREAK, HUD_PANEL_CAPS, @@ -214,12 +218,12 @@ enum { HUD_PANEL_GREN2, HUD_PANEL_PLAYERCLASS, HUD_PANEL_IDENTIFY, - HUD_PANEL_HUDOPTIONS, HUD_PANEL_FLAGINFO, HUD_PANEL_GRENTIMER }; var FO_Hud_Panel Hud_Panels[] = { + {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'0 0','150 150',1,1,0, doNothing, {return DrawPanel.id;}}, {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'0 0','50 26',1,1,0, drawClipSize, { return SBAR.ClipSize; }}, {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, {"capspanel",FO_HUD_CAPS_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, @@ -227,7 +231,6 @@ var FO_Hud_Panel Hud_Panels[] = { {"gren2panel",FO_HUD_GREN2_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, {"playerclasspanel",FO_HUD_SPECIAL_NAME,'0 0','50 26',1,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,1,0, drawIdentify, {return "";}}, - {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'0 0','150 260',1,1,0, doNothing, {return DrawPanel.id;}}, {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,1,0, drawFlagInfo, {return DrawPanel.id;}} //, //{"grentimerpanel","Grenade Timer",'0 0','50 26',1,1,0, doNothing, {return "";}} }; diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 47e57831..a5c2cc3d 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -9,4 +9,4 @@ main.qc events.qc hud_helpers.qc hud.qc -settings.qc \ No newline at end of file +settings.qc diff --git a/csqc/hud.qc b/csqc/hud.qc index 65a834a8..ae0f69de 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -92,6 +92,14 @@ void SetDrawPanel(string id) */ } +float GetPanelById(string id) = { + for(float i = 0; i < Hud_Panels.length; i++) { + if(Hud_Panels[i].id == id) { + return i; + } + } + return 0; +} void Hud_WriteCfg(string path) { @@ -251,6 +259,7 @@ void Hud_DrawFlagStatusBar(string panelid) } } + /* if (firstrun) { if (flagInfoCount > 0) @@ -261,10 +270,11 @@ void Hud_DrawFlagStatusBar(string panelid) Hud_Panels[HUD_PANEL_FLAGINFO].Position = pos; } } + */ vector fillsize = [sizex * 4, sizey * flagInfoCount]; float alpha = 0; - if (hud_panel(panelid, pos, fillsize, alpha)) + if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_FLAGINFO].Display)) { // click event if (fo_hud_editor) @@ -273,7 +283,7 @@ void Hud_DrawFlagStatusBar(string panelid) } } - for (float i = FlagInfoLines.length - 1; i >= 0; i--) + for (float i = 0; i < flagInfoCount; i++) { if (FlagInfoLines[i].id) { @@ -283,51 +293,64 @@ void Hud_DrawFlagStatusBar(string panelid) float yoffset = 24; if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + //drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + drawstring([pos_x + sizex, pos_y + 4 + sizey * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + //drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + drawstring([pos_x + sizex, pos_y + 4 + sizey * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - drawpic([pos_x, pos_y - sizex * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); + //drawpic([pos_x, pos_y - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); + drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); - drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); + float smallfont = 6 * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; + //drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); + drawstring([pos_x + sizex - stringwidth(stime, 1, [smallfont, smallfont]), pos_y + sizey * (i + 1) - smallfont, 0], stime, [smallfont, smallfont], '1 1 1', 1, 0); } } } } -float Hud_GetSelectedPanel() { - for(float i = 0; i < Hud_Panels.length; i++) { - if(sui_is_last_clicked(Hud_Panels[i].id)) { - return i; - } - } - return -1; -} - void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string icon) { - if(!fo_hud_editor) + if(!fo_hud_editor || !Editor_SelectedPanel_Index) return; vector pos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; - if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale, 0)) + if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale, 0, Hud_Panels[HUD_PANEL_HUDOPTIONS].Display)) { // click event } - float selectedPanelIndex = Hud_GetSelectedPanel(); - if(selectedPanelIndex < 0) - return; + //drawfill(pos, Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale, MENU_HIGHLIGHT, 0, 0); + + + + //float selectedPanelIndex = Hud_GetSelectedPanel(); + //if(selectedPanelIndex < 0) + // return; - FO_Hud_Panel selectedPanel = Hud_Panels[selectedPanelIndex]; + FO_Hud_Panel selectedPanel = Hud_Panels[Editor_SelectedPanel_Index]; drawstring(pos + [4,4], selectedPanel.Name, [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [4,12], strcat("Scale: ",ftos(selectedPanel.Scale)), [8,8], MENU_SELECTED, 1, 0); + float fval = selectedPanel.Scale; + hud_slider("hud_option_scale_scroll", pos + [4,24], [140,8], [0.2,5.0,24], fval); + if(fval != selectedPanel.Scale) { + Hud_Panels[Editor_SelectedPanel_Index].Scale = fval; + } + if(hud_button("hud_option_show_hide_toggle", pos + [4,34], [140, 20], selectedPanel.Display ? "Hide" : "Show")) { + Hud_Panels[Editor_SelectedPanel_Index].Display = !selectedPanel.Display; + } + drawstring(pos + [4,64],"Position: ", [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [10,72], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [10,80], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); + } void Hud_DrawClassInfoPanel(string id, float playerclass) @@ -347,7 +370,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) vector pos; pos = DrawPanel.Position; - if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) + if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) { // click event if (fo_hud_editor) @@ -545,7 +568,7 @@ void Hud_DrawIdentifyPanel(string id, string identify) vector pos; pos = DrawPanel.Position; - if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) + if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) { // click event if (fo_hud_editor) @@ -580,6 +603,10 @@ void Hud_Draw(float width, float height) for(float i = 0; i < Hud_Panels.length; i++) { Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); + if(sui_is_last_clicked(Hud_Panels[i].id)) { + Editor_SelectedPanel = Hud_Panels[i]; + Editor_SelectedPanel_Index = i; + } } /* if (SBAR.ClipSize || fo_hud_editor) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 5b1737dd..357ad517 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -2,6 +2,7 @@ vector MENU_BG = '0.2 0.3 0.4'; vector MENU_BG_DARK = '0.1 0.15 0.2'; vector MENU_BORDER = '0.3 0.4 0.5'; vector MENU_SELECTED = '0 1 0'; +vector MENU_UNSELECTED = '1 0 0'; vector MENU_BUTTON = '0.3 0.4 0.5'; vector MENU_BUTTON_BORDER = '0.35 0.45 0.55'; vector MENU_TEXT_1 = '1 1 1'; @@ -17,6 +18,7 @@ float MENU_START_CONTENT = 32; void Hud_WriteCfg(string path); float GetDrawPanel(string id); void SetDrawPanel(string id); +float GetPanelById(string id); void FO_Hud_Editor() { @@ -50,6 +52,23 @@ float(string id, vector pos, vector size, string text) hud_button = return sui_is_clicked(id); }; +void(string id, vector pos, vector size, vector minmaxsteps, __inout float value) hud_slider = +{ + sui_push_frame(pos, size); + + value = sui_slidercontrol(id, [0, 0], size, minmaxsteps, value, sui_slider_noop); + float maxval = minmaxsteps[1]; + float sliderx = (value / maxval) * size_x; + sui_fill([0, size_y * 0.25], [size_x, size_y * 0.5], MENU_BG_DARK, 1.0, 0); + + float is_active = sui_is_held(id) || (sui_is_hovered(id) && !sui_click_held()); + vector slider_ctrl_color = is_active ? MENU_BUTTON + MENU_HIGHLIGHT * 0.1 : MENU_BUTTON; + sui_fill([sliderx - 2, 0], [4, size_y], slider_ctrl_color, 1.0, 0); + + sui_pop_frame(); +}; + + vector UpdatePos(string id, vector mousepos) { vector pos; @@ -74,13 +93,14 @@ vector UpdatePos(string id, vector mousepos) return pos; } -float(string id, vector pos, vector size, float alpha) hud_panel = +float(string id, vector pos, vector size, float alpha, float enabled) hud_panel = { vector basecolor = MENU_BG; + vector outlinecolour = enabled ? MENU_BORDER : MENU_UNSELECTED; if (fo_hud_editor) { - sui_border_box(pos, size, 1, MENU_BORDER, 0.4, 0); + sui_border_box(pos, size, 1, outlinecolour, 0.4, 0); if (sui_is_last_clicked(id)) { sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); @@ -96,7 +116,9 @@ float(string id, vector pos, vector size, float alpha) hud_panel = if (sui_is_hovered(id)) { alpha = 0.6; - basecolor = MENU_BG + MENU_HIGHLIGHT * 0.1; + basecolor = MENU_BG + MENU_HIGHLIGHT * 0.1; + //FO_Hud_Panel hoverpanel = GetPanelById(id); + //drawstring([Mouse.x, Mouse.y], hoverpanel.Name, '8 8', '1 0 0', 1, 0); } if (sui_is_held(id)) @@ -314,7 +336,7 @@ void Hud_DrawPanelLMP(string id, string val, string icon) vector pos; pos = DrawPanel.Position; - if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0)) + if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) { // click event if (fo_hud_editor) diff --git a/csqc/main.qc b/csqc/main.qc index 1540ce72..a2d08441 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -12,7 +12,7 @@ void GetSelf() = { noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); - precache_model("progs/weapons/v_rock.mdl"); +// precache_model("progs/weapons/v_rock.mdl"); for (float i = 0; i < HudIcons.length; i++) { From 42fe6cb8dbdd8275f1415b77fb661abb50fd4d75 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 10 Sep 2019 00:33:38 +1200 Subject: [PATCH 0800/2474] Clean up comments and unused code --- csqc/csextradefs.qc | 20 ---- csqc/hud.qc | 234 -------------------------------------------- csqc/hud_helpers.qc | 21 +--- 3 files changed, 1 insertion(+), 274 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d633be53..1ec643cc 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -126,15 +126,6 @@ typedef struct { FlagInfoLine FlagInfoLines[10]; // hud stuff -/* -typedef struct { - vector Position; - float GrowDirection; - float NodeInsertLoc; - float Scale; - float Display; -} FO_Hud_FlagIcon; -*/ typedef struct { string id; string Name; @@ -149,20 +140,9 @@ typedef struct { FO_Hud_Panel DrawPanel; FO_Hud_Panel NewPanel; -FO_Hud_Panel Editor_SelectedPanel; float Editor_SelectedPanel_Index; typedef struct { -// FO_Hud_FlagIcon FlagIcon; -// FO_Hud_Panel ClipSize; -// FO_Hud_Panel FragStreak; -// FO_Hud_Panel Caps; -// FO_Hud_Panel Gren1; -// FO_Hud_Panel Gren2; -// FO_Hud_Panel PlayerClass; -// FO_Hud_Panel Identify; -// FO_Hud_Panel GrenTimer; -// FO_Hud_Panel HudOptions; vector MousePos; } FO_Hud_Settings; diff --git a/csqc/hud.qc b/csqc/hud.qc index ae0f69de..12243705 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -7,43 +7,6 @@ float GetDrawPanel(string id) } } return -1; -/* - switch (id) - { - //case "hudclipsize": - case "clipsizepanel": - DrawPanel = Hud_Panels[HUD_PANEL_CLIPSIZE]; - break; - //case "hudfragstreak": - case "fragstreakpanel": - DrawPanel = Hud_Panels[HUD_PANEL_FRAGSTREAK]; - break; - //case "hudcaps": - case "capspanel": - DrawPanel = Hud_Panels[HUD_PANEL_CAPS]; - break; - //case "hudgren1": - case "gren1panel": - DrawPanel = Hud_Panels[HUD_PANEL_GREN1]; - break; - //case "hudgren2": - case "gren2panel": - DrawPanel = Hud_Panels[HUD_PANEL_GREN2]; - break; - //case "hudplayerclass": - case "playerclasspanel": - DrawPanel = Hud_Panels[HUD_PANEL_PLAYERCLASS]; - break; - //case "hudidentify": - case "identifypanel": - DrawPanel = Hud_Panels[HUD_PANEL_IDENTIFY]; - break; - //case "hudoptions": - case "hudoptionspanel": - DrawPanel = Hud_Panels[HUD_PANEL_HUDOPTIONS]; - break; - } -*/ } void SetDrawPanel(string id) @@ -53,43 +16,6 @@ void SetDrawPanel(string id) Hud_Panels[i] = DrawPanel; } } -/* - switch (id) - { - //case "hudclipsize": - case "clipsizepanel": - Hud_Panels[HUD_PANEL_CLIPSIZE] = DrawPanel; - break; - //case "hudfragstreak": - case "fragstreakpanel": - Hud_Panels[HUD_PANEL_FRAGSTREAK] = DrawPanel; - break; - //case "hudcaps": - case "capspanel": - Hud_Panels[HUD_PANEL_CAPS] = DrawPanel; - break; - //case "hudgren1": - case "gren1panel": - Hud_Panels[HUD_PANEL_GREN1] = DrawPanel; - break; - //case "hudgren2": - case "gren2panel": - Hud_Panels[HUD_PANEL_GREN2] = DrawPanel; - break; - //case "hudplayerclass": - case "playerclasspanel": - Hud_Panels[HUD_PANEL_PLAYERCLASS]= DrawPanel; - break; - //case "hudidentify": - case "identifypanel": - Hud_Panels[HUD_PANEL_IDENTIFY] = DrawPanel; - break; - //case "hudoptions": - case "hudoptionspanel": - Hud_Panels[HUD_PANEL_HUDOPTIONS] = DrawPanel; - break; - } -*/ } float GetPanelById(string id) = { @@ -108,40 +34,11 @@ void Hud_WriteCfg(string path) filehandle = fopen(path, FILE_WRITE); string line; -// line = FormatCfgString(line, "hudflagicon.growdirection", ftos(HudSettings.FlagIcon.GrowDirection)); -// line = FormatCfgString(line, "hudflagicon.nodeinsertloc", ftos(HudSettings.FlagIcon.NodeInsertLoc)); -// line = FormatCfgVector(line, "hudflagicon.position", HudSettings.FlagIcon.Position); -// line = FormatCfgString(line, "hudflagicon.scale", ftos(HudSettings.FlagIcon.Scale)); -// line = FormatCfgString(line, "hudflagicon.display", ftos(HudSettings.FlagIcon.Display)); - for(float i = 0; i < Hud_Panels.length; i++) { DrawPanel = Hud_Panels[i]; line = GetPanelString(line, Hud_Panels[i].id); } -/* - DrawPanel = HudSettings.ClipSize; - line = GetPanelString(line, "clipsizepanel"); - - DrawPanel = HudSettings.FragStreak; - line = GetPanelString(line, "fragstreakpanel"); - - DrawPanel = HudSettings.Caps; - line = GetPanelString(line, "capspanel"); - DrawPanel = HudSettings.Gren1; - line = GetPanelString(line, "gren1panel"); - DrawPanel = HudSettings.Gren2; - line = GetPanelString(line, "gren2panel"); - - DrawPanel = HudSettings.PlayerClass; - line = GetPanelString(line, "playerclasspanel"); - - DrawPanel = HudSettings.Identify; - line = GetPanelString(line, "identifypanel"); - - DrawPanel = HudSettings.HudOptions; - line = GetPanelString(line, "hudoptionspanel"); -*/ fputs(filehandle, line); fclose(filehandle); } @@ -154,15 +51,8 @@ void FO_Hud_Editor_LoadDefaultSettings() // check struct, put defaults in float yoffset = height - 64; -// FO_Hud_FlagIcon HudFlagIcon; -// HudFlagIcon.Position = [8, yoffset]; // TODO - maybe implement these to allow for pivoting of items -// HudFlagIcon.GrowDirection = FO_HUD_GROW_UP; -// HudFlagIcon.NodeInsertLoc = FO_HUD_INSERT_AFTER; -// HudFlagIcon.Scale = 1; -// HudFlagIcon.Display = 1; -// HudSettings.FlagIcon = HudFlagIcon; vector pos, fill; float scale, display, nodeInsertLoc; @@ -181,69 +71,10 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[i].NodeInsertLoc = nodeInsertLoc; //pnl.Name = name; } - -/* - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_CLIPSIZE_NAME); - FO_Hud_Panel HudClipSize = NewPanel; - HudSettings.ClipSize = HudClipSize; - - pos = [pos_x, pos_y - 2 - 24]; - fill = [50, 26]; - - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_FRAGSTREAK_NAME); - FO_Hud_Panel HudFragStreak = NewPanel; - HudSettings.FragStreak = HudFragStreak; - - pos = [pos_x, pos_y - 2 - 24]; - fill = [50, 26]; - - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_CAPS_NAME); - FO_Hud_Panel HudCaps = NewPanel; - HudSettings.Caps = HudCaps; - - pos = [pos_x, pos_y - 2 - 24]; - fill = [50, 26]; - - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_GREN1_NAME); - FO_Hud_Panel HudGren1 = NewPanel; - HudSettings.Gren1 = HudGren1; - - pos = [pos_x, pos_y - 2 - 24]; - fill = [50, 26]; - - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_GREN2_NAME); - FO_Hud_Panel HudGren2 = NewPanel; - HudSettings.Gren2 = HudGren2; - - pos = [pos_x, pos_y - 2 - 24]; - fill = [50, 26]; - nodeInsertLoc = FO_HUD_INSERT_AFTER; - - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_SPECIAL_NAME); - FO_Hud_Panel HudPlayerClass = NewPanel; - HudSettings.PlayerClass = HudPlayerClass; - - pos = [pos_x, pos_y - 2 - 24]; - fill = [50, 26]; - - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_IDENTIFY_NAME); - FO_Hud_Panel HudIdentify = NewPanel; - HudSettings.Identify = HudIdentify; - - pos = [pos_x, pos_y - 2 - 24]; - fill = [150, 260]; - GetNewPanel(pos, fill, scale, display, nodeInsertLoc, FO_HUD_OPTIONS_NAME); - FO_Hud_Panel HudOptions = NewPanel; - HudSettings.HudOptions = HudOptions; -*/ - } void Hud_DrawFlagStatusBar(string panelid) { -// if (!HudSettings.FlagIcon.Display && !fo_hud_editor) -// return; - vector pos; pos = Hud_Panels[HUD_PANEL_FLAGINFO].Position; float sizey, sizex; @@ -259,19 +90,6 @@ void Hud_DrawFlagStatusBar(string panelid) } } - /* - if (firstrun) - { - if (flagInfoCount > 0) - { - firstrun = FALSE; - pos = Hud_Panels[HUD_PANEL_FLAGINFO].Position; - pos_y = pos_y - 4 - sizey * (flagInfoCount - 2); - Hud_Panels[HUD_PANEL_FLAGINFO].Position = pos; - } - } - */ - vector fillsize = [sizex * 4, sizey * flagInfoCount]; float alpha = 0; if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_FLAGINFO].Display)) @@ -293,23 +111,19 @@ void Hud_DrawFlagStatusBar(string panelid) float yoffset = 24; if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - //drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); drawstring([pos_x + sizex, pos_y + 4 + sizey * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - //drawstring([pos_x + sizex, pos_y + 4 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); drawstring([pos_x + sizex, pos_y + 4 + sizey * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); } - //drawpic([pos_x, pos_y - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); float smallfont = 6 * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; - //drawstring([pos_x + 22 - stringwidth(stime, 1, '6 6'), pos_y + 18 - sizey * (i - 1) + sizey * (flagInfoCount - 2), 0], stime, '6 6', '1 1 1', 1, 0); drawstring([pos_x + sizex - stringwidth(stime, 1, [smallfont, smallfont]), pos_y + sizey * (i + 1) - smallfont, 0], stime, [smallfont, smallfont], '1 1 1', 1, 0); } } @@ -326,13 +140,6 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string { // click event } - //drawfill(pos, Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale, MENU_HIGHLIGHT, 0, 0); - - - - //float selectedPanelIndex = Hud_GetSelectedPanel(); - //if(selectedPanelIndex < 0) - // return; FO_Hud_Panel selectedPanel = Hud_Panels[Editor_SelectedPanel_Index]; @@ -599,54 +406,13 @@ void Hud_DrawIdentifyPanel(string id, string identify) void Hud_Draw(float width, float height) { - //Hud_DrawFlagStatusBar(width); for(float i = 0; i < Hud_Panels.length; i++) { Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); if(sui_is_last_clicked(Hud_Panels[i].id)) { - Editor_SelectedPanel = Hud_Panels[i]; Editor_SelectedPanel_Index = i; } } -/* - if (SBAR.ClipSize || fo_hud_editor) - { - GetDrawPanel("clipsizepanel"); - Hud_DrawPanelLMP("clipsizepanel", SBAR.ClipSize, HudIcons[10].icon); - } - GetDrawPanel("fragstreakpanel"); - Hud_DrawPanelLMP("fragstreakpanel", ftos(SBAR.FragStreak), HudIcons[11].icon); - - GetDrawPanel("capspanel"); - Hud_DrawPanelLMP("capspanel", ftos(SBAR.Caps), HudIcons[12].icon); - - // identify - if (strlen(SBAR.Identify) > 0 || fo_hud_editor) - { - GetDrawPanel("identifypanel"); - Hud_DrawIdentifyPanel("identifypanel", SBAR.Identify); - } - - GetDrawPanel("gren1panel"); - Hud_DrawPanelLMP("gren1panel", ftos(SBAR.Gren1), HudIcons[13].icon); - - GetDrawPanel("gren2panel"); - Hud_DrawPanelLMP("gren2panel", ftos(SBAR.Gren2), HudIcons[14].icon); - - if (SBAR.PlayerClass || fo_hud_editor) - { - GetDrawPanel("playerclasspanel"); - Hud_DrawClassInfoPanel("playerclasspanel", SBAR.PlayerClass); - } - - if (fo_hud_editor) - { - //GetDrawPanel("hudoptionspanel"); - //Hud_DrawPanelLMP("hudoptionspanel", ftos(SBAR.Gren2), HudIcons[14].icon); - //Hud_DrawHudOptionsPanel(); - - } -*/ HudSettings.MousePos = [Mouse.x, Mouse.y]; } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 357ad517..55c662df 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -253,26 +253,7 @@ void FO_Hud_Editor_LoadSettings() switch(field) { -/* - case "hudflagicon.position": - count = tokenizebyseparator(val, ","); - x = stof(argv(0)); - y = stof(argv(1)); - HudSettings.FlagIcon.Position = [x, y]; - break; - case "hudflagicon.scale": - HudSettings.FlagIcon.Scale = stof(val); - break; - case "hudflagicon.growdirection": - HudSettings.FlagIcon.GrowDirection = stof(val); - break; - case "hudflagicon.nodeinsertloc": - HudSettings.FlagIcon.NodeInsertLoc = stof(val); - break; - case "hudflagicon.display": - HudSettings.FlagIcon.Display = stof(val); - break; -*/ + default: count = tokenizebyseparator(field, "."); string pnl; From 25178b9f7c64b6898c7549cfa3e6ba62d2468665 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 12 Sep 2019 14:41:23 +1000 Subject: [PATCH 0801/2474] stop topcolor changing --- ssqc/commands.qc | 54 ++++++++++++++++++++++++++++++++++-------------- ssqc/mvdsv.qc | 5 +++-- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 0c52e824..815cf941 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1,4 +1,4 @@ -float (string arg1, string arg2) ParseCmds = { +float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num, processedCmd; local string tmp; processedCmd = FALSE; @@ -7,23 +7,45 @@ float (string arg1, string arg2) ParseCmds = { arg_num = 1; if (arg2) arg_num = 2; - - if (arg1 == "adminpwd") + + switch (arg1) { - processedCmd = TRUE; - if (arg_num == 2) { - Admin_Check(arg2); - if (self.is_admin) { - Admin_Aliases(); + case "adminpwd": + processedCmd = TRUE; + if (arg_num == 2) { + Admin_Check(arg2); + if (self.is_admin) { + Admin_Aliases(); + } } - } - if (arg_num == 1) { - sprint(self, PRINT_HIGH, "usage: cmd adminpwd password, where password is the admin password\n"); - sprint(self, PRINT_HIGH, "\n"); - } - return processedCmd; + if (arg_num == 1) { + sprint(self, PRINT_HIGH, "usage: cmd adminpwd password, where password is the admin password\n"); + sprint(self, PRINT_HIGH, "\n"); + } + break; + case "setinfo": + if (arg2) + { + if (arg2 == "topcolor" || arg2 == "bottomcolor") + { + float arg3f = stof(arg3); + if ((self.team_no > 0) && (teamplay > 0)) { + if (arg3f != (TeamFortress_TeamGetColor(self.team_no) - 1)) { + arg3f = TeamFortress_TeamGetColor(self.team_no) - 1; + string st; + st = ftos(arg3f); + //forceinfokey(self, "topcolor", st); + stuffcmd(self, strcat("color ", st, "\n")); + sprint(self, PRINT_HIGH, + "Your color has been changed to your team color\n"); + processedCmd = TRUE; + } + } + } + } + break; } - + if (self.is_admin) { switch (arg1) @@ -214,7 +236,7 @@ void (string cmd) SV_ParseClientCommand = { float isProcessed; tokenize(cmd); - isProcessed = ParseCmds(argv(0), argv(1)); + isProcessed = ParseCmds(argv(0), argv(1), argv(2)); if (!isProcessed) { diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index d5048dd2..ed4bb933 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -1,11 +1,12 @@ float () UserCmd = { float isProcessed; - string arg1, arg2; + string arg1, arg2, arg3; arg1 = argv_mvdsv(0); arg2 = argv_mvdsv(1); + arg3 = argv_mvdsv(2); - isProcessed = ParseCmds(arg1, arg2); + isProcessed = ParseCmds(arg1, arg2, arg3); return (isProcessed); }; From dee7f4b48ba602fc6fb85dade0afcf178957c18d Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 12 Sep 2019 14:44:25 +1000 Subject: [PATCH 0802/2474] remove kick for color change --- ssqc/tforttm.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index d962e259..b89d2a84 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -279,11 +279,11 @@ void () TeamFortress_CheckTeamCheats = { st = ftos(tc); stuffcmd(self, st); stuffcmd(self, "\n"); - bprint2(PRINT_MEDIUM, self.netname, + /*bprint2(PRINT_MEDIUM, self.netname, " has been kicked for changing color\n"); sprint(self, PRINT_HIGH, "You have been kicked for changing your pants color\n"); - KickCheater(self); + KickCheater(self);*/ return; } if (self.playerclass != 0) { From 68f9c589c9b5d17cb292d69e08746766143548ee Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 15 Sep 2019 22:21:24 +1200 Subject: [PATCH 0803/2474] #206, #207 - hud editor options for text scaling, text alignment --- csqc/csextradefs.qc | 21 ++++++------- csqc/hud.qc | 72 +++++++++++++++++++++++++++++++++------------ csqc/hud_helpers.qc | 7 ++++- 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1ec643cc..d2e69211 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -132,6 +132,7 @@ typedef struct { vector Position; vector FillSize; float Scale; + float TextScale; float Display; float NodeInsertLoc; void(string panelid, float display, string text, string icon) drawPanel; @@ -203,16 +204,16 @@ enum { }; var FO_Hud_Panel Hud_Panels[] = { - {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'0 0','150 150',1,1,0, doNothing, {return DrawPanel.id;}}, - {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'0 0','50 26',1,1,0, drawClipSize, { return SBAR.ClipSize; }}, - {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, - {"capspanel",FO_HUD_CAPS_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'0 0','50 26',1,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, - {"playerclasspanel",FO_HUD_SPECIAL_NAME,'0 0','50 26',1,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,1,0, drawIdentify, {return "";}}, - {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,1,0, drawFlagInfo, {return DrawPanel.id;}} //, - //{"grentimerpanel","Grenade Timer",'0 0','50 26',1,1,0, doNothing, {return "";}} + {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'0 0','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, + {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'0 0','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, + {"capspanel",FO_HUD_CAPS_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, + {"playerclasspanel",FO_HUD_SPECIAL_NAME,'0 0','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,0,1,0, drawIdentify, {return "";}}, + {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,0,1,0, drawFlagInfo, {return DrawPanel.id;}} //, + //{"grentimerpanel","Grenade Timer",'0 0','50 26',1,0,1,0, doNothing, {return "";}} }; diff --git a/csqc/hud.qc b/csqc/hud.qc index 12243705..144b0a0a 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -73,6 +73,13 @@ void FO_Hud_Editor_LoadDefaultSettings() } } +float GetTextAlignOffset(float pos, float iconsize, string text, float textsize, float align) { + if(align == FO_HUD_INSERT_AFTER) { + return pos - strlen(text) * textsize; + } + return pos + iconsize; +} + void Hud_DrawFlagStatusBar(string panelid) { vector pos; @@ -108,14 +115,17 @@ void Hud_DrawFlagStatusBar(string panelid) alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; string icon = FlagInfoLines[i].icon.filename; vector iconcolour = FlagInfoLines[i].icon.colour; - float yoffset = 24; + float bigfont = 8 * (Hud_Panels[HUD_PANEL_FLAGINFO].TextScale ? Hud_Panels[HUD_PANEL_FLAGINFO].TextScale : Hud_Panels[HUD_PANEL_FLAGINFO].Scale); + float bigfontvoffset = sizey / 2 - bigfont / 2; //Center text against the icon if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - drawstring([pos_x + sizex, pos_y + 4 + sizey * i, 0], FlagInfoLines[i].carrier, '8 8', '1 0 0', 1, 0); + // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,FlagInfoLines[i].carrier,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - drawstring([pos_x + sizex, pos_y + 4 + sizey * i, 0], FlagInfoLines[i].locname, '8 8', '1 1 1', 1, 0); + // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,FlagInfoLines[i].locname,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); } drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); @@ -136,7 +146,8 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string return; vector pos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; - if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale, 0, Hud_Panels[HUD_PANEL_HUDOPTIONS].Display)) + vector size = Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale; + if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, size, 0, Hud_Panels[HUD_PANEL_HUDOPTIONS].Display)) { // click event } @@ -144,25 +155,47 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string FO_Hud_Panel selectedPanel = Hud_Panels[Editor_SelectedPanel_Index]; drawstring(pos + [4,4], selectedPanel.Name, [8,8], MENU_SELECTED, 1, 0); - drawstring(pos + [4,12], strcat("Scale: ",ftos(selectedPanel.Scale)), [8,8], MENU_SELECTED, 1, 0); - float fval = selectedPanel.Scale; - hud_slider("hud_option_scale_scroll", pos + [4,24], [140,8], [0.2,5.0,24], fval); - if(fval != selectedPanel.Scale) { - Hud_Panels[Editor_SelectedPanel_Index].Scale = fval; + float fscale = selectedPanel.Scale; + drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); + hud_slider("hud_option_scale_scroll", pos + [8,24], [136,8], [0.2,5.0,24], fscale); + if(fscale != selectedPanel.Scale) { + Hud_Panels[Editor_SelectedPanel_Index].Scale = fscale; } - if(hud_button("hud_option_show_hide_toggle", pos + [4,34], [140, 20], selectedPanel.Display ? "Hide" : "Show")) { + float ftscale = selectedPanel.TextScale; + drawstring(pos + [4,34], strcat("Text Scale: ",ftos(rint(ftscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); + hud_slider("hud_option_textscale_scroll", pos + [8,44], [136,8], [0,5.0,25], ftscale); + if(ftscale != selectedPanel.TextScale) { + Hud_Panels[Editor_SelectedPanel_Index].TextScale = ftscale; + } + float ftextalign = selectedPanel.NodeInsertLoc; + //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.NodeInsertLoc ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); + if(hud_button("hud_option_textalign_toggle", pos + [size.x - 6 - 48,56], [48, 16], selectedPanel.NodeInsertLoc ? "Left" : "Right")) { + Hud_Panels[Editor_SelectedPanel_Index].NodeInsertLoc = !selectedPanel.NodeInsertLoc; + } + //hud_slider("hud_option_textalign_scroll", pos + [8,64], [32,8], [0,1,1], ftextalign); + //if(ftextalign != selectedPanel.NodeInsertLoc) { + // Hud_Panels[Editor_SelectedPanel_Index].NodeInsertLoc = ftextalign; + //} + if(hud_button("hud_option_show_hide_toggle", pos + [4,74], [140, 20], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { Hud_Panels[Editor_SelectedPanel_Index].Display = !selectedPanel.Display; } - drawstring(pos + [4,64],"Position: ", [8,8], MENU_SELECTED, 1, 0); - drawstring(pos + [10,72], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); - drawstring(pos + [10,80], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [10,116], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); } void Hud_DrawClassInfoPanel(string id, float playerclass) { - if (!DrawPanel.Display && !fo_hud_editor) + if(fo_hud_editor && !SBAR.PlayerClass) { + hud_panel(id, DrawPanel.Position, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display); + + return; + } + + if (!fo_hud_editor && !DrawPanel.Display) return; switch (SBAR.PlayerClass) @@ -188,14 +221,15 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) float val; vector size = FO_Hud_Icon_Size * DrawPanel.Scale; - vector fontSize = FO_Hud_Icon_Font_Size * DrawPanel.Scale; + vector fontSize = FO_Hud_Icon_Font_Size * (DrawPanel.TextScale ? DrawPanel.TextScale : DrawPanel.Scale); pos = [pos_x + 2, pos_y + 2, 0]; vector basepos = pos; vector colour = '1 1 1'; string icon = ""; string msg = ""; - icon = HudIcons[playerclass-1].icon; + //icon = HudIcons[playerclass-1].icon; + icon = HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); float len = 0, offset = 0; @@ -343,7 +377,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_ENGINEER: if (SBAR.HasSentry) { - msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(SBAR.SentryHealth), " S: ", ftos(SBAR.SentryAmmoShells), " R: ", ftos(SBAR.SentryAmmoRockets)); + msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(rint(SBAR.SentryHealth)), " S: ", ftos(rint(SBAR.SentryAmmoShells)), " R: ", ftos(rint(SBAR.SentryAmmoRockets))); DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } else if (SBAR.IsBuilding) @@ -355,11 +389,11 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) // disp pos = [pos_x, pos_y - size_y - 2]; basepos = pos; - icon = HudIcons[playerclass].icon; + icon = HudIcons[playerclass + 7].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.HasDispenser) { - msg = strcat("H: ", ftos(SBAR.DispenserHealth)); + msg = strcat("H: ", ftos(rint(SBAR.DispenserHealth))); DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } break; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 55c662df..e992946e 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -211,6 +211,7 @@ string GetPanelString(string line, string name) { line = FormatCfgVector(line, strcat(name, ".position"), DrawPanel.Position); line = FormatCfgString(line, strcat(name, ".scale"), ftos(DrawPanel.Scale)); + line = FormatCfgString(line, strcat(name, ".textscale"), ftos(DrawPanel.TextScale)); line = FormatCfgString(line, strcat(name, ".display"), ftos(DrawPanel.Display)); line = FormatCfgString(line, strcat(name, ".nodeinsertloc"), ftos(DrawPanel.NodeInsertLoc)); @@ -271,6 +272,9 @@ void FO_Hud_Editor_LoadSettings() case "scale": DrawPanel.Scale = stof(val); break; + case "textscale": + DrawPanel.TextScale = stof(val); + break; case "display": DrawPanel.Display = stof(val); break; @@ -335,7 +339,8 @@ void Hud_DrawPanelLMP(string id, string val, string icon) float offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; pos = [pos_x + offset, pos_y, 0]; - Hud_DrawStringLMP(pos, val, 24 * DrawPanel.Scale); + float textScale = DrawPanel.TextScale ? DrawPanel.TextScale : DrawPanel.Scale; + Hud_DrawStringLMP(pos, val, 24 * textScale); } From d0c3acc2127061f54684db39b891b4a7f73d0a4f Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 16 Sep 2019 20:55:31 +1000 Subject: [PATCH 0804/2474] fix as per spike for mvd recording --- ssqc/tfort.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b4df8ec1..61efa321 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1362,6 +1362,7 @@ void (entity p) TeamFortress_SetSkin = { local string st; p.immune_to_check = time + 10; + if (p.playerclass == PC_SPY || p.last_playerclass == PC_SPY) { if (!p.is_undercover) @@ -1370,6 +1371,8 @@ void (entity p) TeamFortress_SetSkin = { st = TeamFortress_GetSkin(p.team_no, p.playerclass); stuffcmd(p, st); stuffcmd(p, "\n"); + // please fix mvd recording + forceinfokey(p, "skin", st); } Spy_SetClientSkins(p); } @@ -1382,6 +1385,9 @@ void (entity p) TeamFortress_SetSkin = { st = TeamFortress_GetSkin(p.team_no, p.playerclass); stuffcmd(p, st); stuffcmd(p, "\n"); + + // please fix mvd recording + forceinfokey(p, "skin", st); } else { From bc2f299142e78ef639f061c30d5a50dbcf64523b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 22 Sep 2019 21:37:35 +1200 Subject: [PATCH 0805/2474] Force new menu. Add some spacing in control config menu. --- csqc/main.qc | 1 + menu/options_keys.qc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index a2d08441..fb983f8b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -30,6 +30,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { noref void() CSQC_WorldLoaded = { print("CSQC World Loaded\n"); + localcmd("menu_restart"); } noref void(float width, float height, float menushown) CSQC_UpdateView = { diff --git a/menu/options_keys.qc b/menu/options_keys.qc index 053e856c..da53908d 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -28,6 +28,8 @@ const static struct // {_("Keyboard Look"), "+klook"}, {_("Strafe"), "+strafe"}, {_("Run"), "+speed"}, + {0, 0}, + {0, 0}, {_(""), "Weapons"}, {_("Primary Weapon"), "weapon 1"}, {_("Secondary Weapon"), "weapon 2"}, From a7032f6133d1863bb71574df2736bf9bf903915c Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 25 Sep 2019 00:03:37 +1200 Subject: [PATCH 0806/2474] csqc grentimer, fixed csqc id, fixed csqc options panel, show names in fo_hud_editor mode --- csqc/csextradefs.qc | 49 ++++++++++++++++++++++++++++++++++++++++++--- csqc/events.qc | 8 +++++++- csqc/hud.qc | 4 ++++ csqc/hud_helpers.qc | 15 ++++++++++++++ share/commondefs.qc | 3 ++- share/defs.h | 1 + ssqc/status.qc | 8 ++++++++ ssqc/tfort.qc | 4 ++++ 8 files changed, 87 insertions(+), 5 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d2e69211..57679020 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -147,6 +147,14 @@ typedef struct { vector MousePos; } FO_Hud_Settings; +typedef struct { + float grentype; + float expires; + float icon_index; +} FO_Hud_Grentimer; + +FO_Hud_Grentimer FO_Hud_Grentimers[5]; + void(string panelid, float display, string text, string icon) drawClipSize = { if (SBAR.ClipSize || fo_hud_editor) { @@ -185,6 +193,41 @@ void(string panelid, float display, string text, string icon) drawSpecial = { Hud_DrawClassInfoPanel(panelid, SBAR.PlayerClass); } }; +void(string panelid, float display, string text, string icon) drawGrenTimerPanel = { + local float timeleft; + if (display || fo_hud_editor) + { + GetDrawPanel(panelid); + float Scale = DrawPanel.Scale; + float TextScale = DrawPanel.TextScale; + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + if(FO_Hud_Grentimers[i].grentype > 0) { + timeleft = floor(FO_Hud_Grentimers[i].expires - time); + if(timeleft < 0) { + //Expire and fill the gap if there are any active grentimers afterwards + FO_Hud_Grentimers[i].grentype = 0; + for(float j = i + 1; j < FO_Hud_Grentimers.length; j++) { + FO_Hud_Grentimers[j - 1].grentype = FO_Hud_Grentimers[j].grentype; + FO_Hud_Grentimers[j - 1].expires = FO_Hud_Grentimers[j].expires; + FO_Hud_Grentimers[j - 1].icon_index = FO_Hud_Grentimers[j].icon_index; + } + FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].grentype = 0; + FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].expires = 0; + FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].icon_index = 0; + continue; + } + DrawPanel.Position = DrawPanel.Position + [0, 24 * DrawPanel.Scale]; + if(i) { + DrawPanel.Scale = Scale * 0.8; + DrawPanel.TextScale = TextScale * 0.8; + } + Hud_DrawPanelLMP(panelid, ftos(timeleft), HudIcons[FO_Hud_Grentimers[i].icon_index].icon); + } + } + } +}; + + FO_Hud_Settings HudSettings; @@ -211,9 +254,9 @@ var FO_Hud_Panel Hud_Panels[] = { {"gren1panel",FO_HUD_GREN1_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, {"gren2panel",FO_HUD_GREN2_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, {"playerclasspanel",FO_HUD_SPECIAL_NAME,'0 0','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,0,1,0, drawIdentify, {return "";}}, - {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,0,1,0, drawFlagInfo, {return DrawPanel.id;}} //, - //{"grentimerpanel","Grenade Timer",'0 0','50 26',1,0,1,0, doNothing, {return "";}} + {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,0,1,0, drawIdentify, {return SBAR.Identify;}}, + {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,0,1,0, drawFlagInfo, {return "";}}, + {"grentimerpanel","Grenade Timer",'0 0','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}} }; diff --git a/csqc/events.qc b/csqc/events.qc index c375ba3a..e892e73f 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,4 +1,5 @@ void ParseSBAR(); +void AddGrenTimer(float grentype); void() CSQC_Parse_Event = { float msgtype = readbyte(); @@ -93,6 +94,11 @@ void() CSQC_Parse_Event = { case MSG_SBAR: ParseSBAR(); break; + case MSG_GRENPRIMED: + float grentype = readfloat(); + print("Grenade Primed type ", ftos(grentype) ,"\n"); + AddGrenTimer(grentype); + break; } } @@ -194,4 +200,4 @@ void ParseSBAR() } break; } -} \ No newline at end of file +} diff --git a/csqc/hud.qc b/csqc/hud.qc index 144b0a0a..166dce7d 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -446,6 +446,10 @@ void Hud_Draw(float width, float height) if(sui_is_last_clicked(Hud_Panels[i].id)) { Editor_SelectedPanel_Index = i; } + //Draw panel names when editing + if(fo_hud_editor && Hud_Panels[i].id != "hudoptionspanel") { + drawstring(Hud_Panels[i].Position + [2,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); + } } HudSettings.MousePos = [Mouse.x, Mouse.y]; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index e992946e..f028d4bc 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -126,6 +126,10 @@ float(string id, vector pos, vector size, float alpha, float enabled) hud_panel alpha = 0.6; basecolor = MENU_BG - MENU_DARKEN * 0.1; } + // Make options panel switch back to last selected element after dragging + if(sui_is_released(id) && id == "hudoptionspanel") { + _last_clicked_actions[0] = Hud_Panels[Editor_SelectedPanel_Index].id; + } } sui_push_frame(pos, size); @@ -361,3 +365,14 @@ vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, ve return pos; } + +void AddGrenTimer(float grentype) { + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + if(FO_Hud_Grentimers[i].grentype == 0) { + FO_Hud_Grentimers[i].grentype = grentype; + FO_Hud_Grentimers[i].expires = time + 3.8; + FO_Hud_Grentimers[i].icon_index = 4; + break; + } + } +} diff --git a/share/commondefs.qc b/share/commondefs.qc index f50dc950..5f3ecd0e 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -4,6 +4,7 @@ #define MSG_FLAGINFO 2 #define MSG_SBAR 4 +#define MSG_GRENPRIMED 5 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 @@ -13,4 +14,4 @@ #define FLAGINFO_NOLOCATION 6 #define FLAGINFO_ICON_FLAG 0 -#define FLAGINFO_ICON_BUTTON 1 \ No newline at end of file +#define FLAGINFO_ICON_BUTTON 1 diff --git a/share/defs.h b/share/defs.h index 44650441..eeab7057 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1321,6 +1321,7 @@ #define FO_HUD_CLIPSIZE_PANEL_Y 50 #define FO_HUD_INSERT_BEFORE 0 #define FO_HUD_INSERT_AFTER 1 +#define FO_HUD_INSERT_MIDDLE 2 #define FO_HUD_CLIPSIZE_NAME "Clip Size" #define FO_HUD_FRAGSTREAK_NAME "Frag Streak" diff --git a/ssqc/status.qc b/ssqc/status.qc index 610fb50b..d7f31c7e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -766,6 +766,14 @@ string GetSBClassInfo(entity pl, float csqcactive) return st1; } +void UpdateClientGrenadePrimed(entity pl, float grentype) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); + WriteFloat(MSG_MULTICAST, grentype); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientStatusBar(entity pl) { // if we ever change to fte only, this could be changed to stats diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 61efa321..aa8834fc 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -909,6 +909,10 @@ void (float inp) TeamFortress_PrimeGrenade = { if (!notimers) { stuffcmd(self, "play grentimer\n"); } + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (csqcactive) { + UpdateClientGrenadePrimed(self, gtype); + } } } From 42d53e324470db8dfc512a2995b510a2906b96c0 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 25 Sep 2019 19:25:10 +1200 Subject: [PATCH 0807/2474] add client-side grentimer --- csqc/csextradefs.qc | 5 +++-- csqc/events.qc | 4 +++- csqc/main.qc | 9 +++++++++ csqc/settings.qc | 9 ++++++--- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 57679020..1fe0553a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -259,11 +259,12 @@ var FO_Hud_Panel Hud_Panels[] = { {"grentimerpanel","Grenade Timer",'0 0','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}} }; - - +#define FOCMD_AUTOHOP "fo_autohop" +#define FOCMD_GRENTIMER "fo_grentimer" typedef struct { float Autohop; + float Grentimer; } FO_Settings; FO_Settings Settings; diff --git a/csqc/events.qc b/csqc/events.qc index e892e73f..fb059f8e 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -96,8 +96,10 @@ void() CSQC_Parse_Event = { break; case MSG_GRENPRIMED: float grentype = readfloat(); - print("Grenade Primed type ", ftos(grentype) ,"\n"); AddGrenTimer(grentype); + if(Settings.Grentimer == 1) { + localcmd("play grentimer.wav\n"); + } break; } } diff --git a/csqc/main.qc b/csqc/main.qc index a2d08441..1b6be9d4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -81,6 +81,15 @@ noref float(string cmd) CSQC_ConsoleCommand = { } FO_WriteSettings(); break; + case FOCMD_GRENTIMER: + val = stof(argv(1)); + if(val == 1) { + Settings.Grentimer = 1; + } else if(val == 0) { + Settings.Grentimer = 0; + } + FO_WriteSettings(); + break; } return FALSE; }; diff --git a/csqc/settings.qc b/csqc/settings.qc index f08288b1..ca89613b 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,8 +3,8 @@ void FO_WriteSettings() // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", "fo_autohop", ftos(Settings.Autohop)); - + string line = FormatCfgString("", FOCMD_AUTOHOP, ftos(Settings.Autohop)); + line = FormatCfgString(line, FOCMD_GRENTIMER, ftos(Settings.Grentimer)); fputs(filehandle, line); fclose(filehandle); } @@ -41,9 +41,12 @@ void FO_LoadSettings() switch(field) { - case "fo_autohop": + case FOCMD_AUTOHOP: Settings.Autohop = stof(val); break; + case FOCMD_GRENTIMER: + Settings.Grentimer = stof(val); + break; } } ln = fgets(filehandle); From b869290a8aaaf0491f4f3d8317a26aa3144dc4c0 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 25 Sep 2019 20:43:55 +1200 Subject: [PATCH 0808/2474] back out attempt to add options for grentimer/autohop --- csqc/main.qc | 43 ++++++++++++++++++++++++++----------------- menu/options_basic.qc | 4 ++++ 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index be36b9bf..51e289e0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -23,6 +23,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); registercommand("fo_autohop"); + registercommand(FOCMD_GRENTIMER); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -69,27 +70,35 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Hud_Editor_LoadDefaultSettings(); break; case "fo_autohop": - val = stof(argv(1)); - if (val == 1) - { - Settings.Autohop = 1; - print("auto bunnyhop has been enabled\n"); - } - else if (val == 0) - { - Settings.Autohop = 0; - print("auto bunnyhop has been disabled\n"); + if(!argv(1)) { + print("Autohop is ",Settings.Autohop?"on":"off","\n"); + } else { + val = stof(argv(1)); + if (val == 1) + { + Settings.Autohop = 1; + print("auto bunnyhop has been enabled\n"); + } + else if (val == 0) + { + Settings.Autohop = 0; + print("auto bunnyhop has been disabled\n"); + } + FO_WriteSettings(); } - FO_WriteSettings(); break; case FOCMD_GRENTIMER: - val = stof(argv(1)); - if(val == 1) { - Settings.Grentimer = 1; - } else if(val == 0) { - Settings.Grentimer = 0; + if(!argv(1)) { + print("Client-side Grenade timer is ",Settings.Grentimer?"on":"off","\n"); + } else { + val = stof(argv(1)); + if(val == 1) { + Settings.Grentimer = 1; + } else if(val == 0) { + Settings.Grentimer = 0; + } + FO_WriteSettings(); } - FO_WriteSettings(); break; } return FALSE; diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 28345d36..ce7742da 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -48,6 +48,8 @@ class options_basic : mitem_exmenu return (autocvar_m_pitch<0)?"1":"0"; if (key == "cl_run") return (stof(super::get("cl_forwardspeed")) > 200)?"1":"0"; + //if (key == "fo_grentimer") + // return getplayerkeyvalue(player_localnum, "nt"); return super::get(key); }; virtual void(string key, string newval) set = @@ -124,6 +126,8 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'0.0 0.5 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Crosshair"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcheck_spawn (_("Show Speed"), "show_speed", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //pos += 8; + //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; From 8d938781f6613b15b0fd3e71640b3bc16c4c7149 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 25 Sep 2019 21:11:26 +1200 Subject: [PATCH 0809/2474] client-side grentimer --- csqc/csextradefs.qc | 11 ++++++++--- csqc/events.qc | 1 + ssqc/tfort.qc | 8 ++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1fe0553a..bd77576d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -195,8 +195,8 @@ void(string panelid, float display, string text, string icon) drawSpecial = { }; void(string panelid, float display, string text, string icon) drawGrenTimerPanel = { local float timeleft; - if (display || fo_hud_editor) - { + local float timercount = 0; + if (display) { GetDrawPanel(panelid); float Scale = DrawPanel.Scale; float TextScale = DrawPanel.TextScale; @@ -216,15 +216,20 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].icon_index = 0; continue; } - DrawPanel.Position = DrawPanel.Position + [0, 24 * DrawPanel.Scale]; if(i) { DrawPanel.Scale = Scale * 0.8; DrawPanel.TextScale = TextScale * 0.8; } Hud_DrawPanelLMP(panelid, ftos(timeleft), HudIcons[FO_Hud_Grentimers[i].icon_index].icon); + DrawPanel.Position = DrawPanel.Position + [0, 24 * DrawPanel.Scale]; + timercount++; } } } + if(fo_hud_editor && (!display || !timercount)) { + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, "0", ICON_GREN1); + } }; diff --git a/csqc/events.qc b/csqc/events.qc index fb059f8e..af7ab659 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -98,6 +98,7 @@ void() CSQC_Parse_Event = { float grentype = readfloat(); AddGrenTimer(grentype); if(Settings.Grentimer == 1) { + print("playing grentimer!\n"); localcmd("play grentimer.wav\n"); } break; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index aa8834fc..957b998b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -898,6 +898,7 @@ void (float inp) TeamFortress_PrimeGrenade = { RemoveGrenadeTimers(); + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); local float notimers = stof(infokey(self, "nt")); if (grentimers && notimers != 1) { timer = spawn(); @@ -909,10 +910,9 @@ void (float inp) TeamFortress_PrimeGrenade = { if (!notimers) { stuffcmd(self, "play grentimer\n"); } - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if (csqcactive) { - UpdateClientGrenadePrimed(self, gtype); - } + } + if (grentimers && csqcactive) { + UpdateClientGrenadePrimed(self, gtype); } } From d32409a08eb3f3443bafa02a812fadb9b765ecc2 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 28 Sep 2019 22:29:01 +1000 Subject: [PATCH 0810/2474] fix unable to change class by typing classname when reloading during quad intermission --- ssqc/weapons.qc | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 398929c0..685d3cea 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3326,20 +3326,15 @@ void () W_WeaponFrame = { // change weapon if queue_weaponslot has been set } else if (self.queue_weaponslot > 0) { - W_ChangeWeapon(self.queue_weaponslot); - // load weapon state } else if (self.queue_weaponstate && WeaponReady(self)) { - // load weaponstate saved from before quick fire started if (self.queue_weaponstate == 1) W_WeaponState_Load(self, 0); - // load swapped weaponstate else W_WeaponState_Load(self, 1); - } if (self.impulse == TF_CHANGETEAM) { @@ -3383,16 +3378,31 @@ void () W_WeaponFrame = { } } - // class specials and grenade impulses always possible, also detpipe - if (self.impulse == TF_SPECIAL_SKILL ||(self.impulse >= TF_GRENADE_1 && self.impulse <= TF_GRENADE_SWITCH) - || self.impulse == TF_PB_DETONATE) { - ImpulseCommands(); - return; + // whitelist of commands that can be used even when reloading + switch (self.impulse) + { + case TF_SPECIAL_SKILL: + case TF_PB_DETONATE: + case TF_MEDIC_HELPME: + case TF_DASH: + case TF_DISCARD: + case TF_DROPFLAG: + case TF_CHANGEPC_SCOUT: + case TF_CHANGEPC_SNIPER: + case TF_CHANGEPC_SOLDIER: + case TF_CHANGEPC_DEMOMAN: + case TF_CHANGEPC_MEDIC: + case TF_CHANGEPC_HVYWEAP: + case TF_CHANGEPC_PYRO: + case TF_CHANGEPC_SPY: + case TF_CHANGEPC_ENGINEER: + case TF_CHANGEPC_RANDOM: + ImpulseCommands(); + return; } - // /saveme, /dash, /discard, /dropflag - if (self.impulse == TF_MEDIC_HELPME || self.impulse == TF_DASH || self.impulse == TF_DISCARD - || self.impulse == TF_DROPFLAG) { + // grenade impulses always possible + if ((self.impulse >= TF_GRENADE_1 && self.impulse <= TF_GRENADE_SWITCH)) { ImpulseCommands(); return; } From 4ebe184bcf906aea5e62244cc1e5a17c38a1fd45 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 29 Sep 2019 20:16:10 +1300 Subject: [PATCH 0811/2474] added fo settings to the menu --- csqc/csextradefs.qc | 10 +++++----- csqc/events.qc | 2 +- csqc/main.qc | 14 +++++++++++--- csqc/settings.qc | 11 ++++++----- menu/options_basic.qc | 5 +++-- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index bd77576d..f7473d2d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -267,11 +267,11 @@ var FO_Hud_Panel Hud_Panels[] = { #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" -typedef struct { - float Autohop; - float Grentimer; -} FO_Settings; -FO_Settings Settings; +//typedef struct { +// float Autohop; +// float Grentimer; +//} FO_Settings; +//FO_Settings Settings; diff --git a/csqc/events.qc b/csqc/events.qc index af7ab659..c64ba3fe 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -97,7 +97,7 @@ void() CSQC_Parse_Event = { case MSG_GRENPRIMED: float grentype = readfloat(); AddGrenTimer(grentype); - if(Settings.Grentimer == 1) { + if(cvar(FOCMD_GRENTIMER) == 1) { print("playing grentimer!\n"); localcmd("play grentimer.wav\n"); } diff --git a/csqc/main.qc b/csqc/main.qc index 51e289e0..df7aee4b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -22,8 +22,10 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); - registercommand("fo_autohop"); - registercommand(FOCMD_GRENTIMER); + //registercommand("fo_autohop"); + registercvar(FOCMD_AUTOHOP, "0"); + //registercommand(FOCMD_GRENTIMER); + registercvar(FOCMD_GRENTIMER, "1"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -69,6 +71,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_hud_reset": FO_Hud_Editor_LoadDefaultSettings(); break; +/* case "fo_autohop": if(!argv(1)) { print("Autohop is ",Settings.Autohop?"on":"off","\n"); @@ -100,6 +103,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_WriteSettings(); } break; +*/ } return FALSE; }; @@ -125,7 +129,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { - if (Settings.Autohop == 1) + if (cvar(FOCMD_AUTOHOP) == 1) { if (input_buttons&2) { @@ -138,3 +142,7 @@ noref void CSQC_Input_Frame() } } } + +void CSQC_Shutdown() = { + FO_WriteSettings(); +} diff --git a/csqc/settings.qc b/csqc/settings.qc index ca89613b..715e8773 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,15 +3,16 @@ void FO_WriteSettings() // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", FOCMD_AUTOHOP, ftos(Settings.Autohop)); - line = FormatCfgString(line, FOCMD_GRENTIMER, ftos(Settings.Grentimer)); + string line = FormatCfgString("", FOCMD_AUTOHOP, ftos(cvar(FOCMD_AUTOHOP))); + line = FormatCfgString(line, FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); fputs(filehandle, line); fclose(filehandle); } void FO_LoadDefaultSettings() { - Settings.Autohop = 0; + cvar_set(FOCMD_AUTOHOP, "0"); + cvar_set(FOCMD_GRENTIMER, "1"); } void FO_LoadSettings() @@ -42,10 +43,10 @@ void FO_LoadSettings() switch(field) { case FOCMD_AUTOHOP: - Settings.Autohop = stof(val); + cvar_set(FOCMD_AUTOHOP, val); break; case FOCMD_GRENTIMER: - Settings.Grentimer = stof(val); + cvar_set(FOCMD_GRENTIMER, val); break; } } diff --git a/menu/options_basic.qc b/menu/options_basic.qc index ce7742da..4d135307 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -126,8 +126,9 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'0.0 0.5 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Crosshair"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcheck_spawn (_("Show Speed"), "show_speed", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //pos += 8; - //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + pos += 8; + fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; From 0380dd323c13fd943787a863bf95d3620551eb22 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 2 Oct 2019 20:33:24 +1300 Subject: [PATCH 0812/2474] Grentimer now explodes on '0'! --- csqc/csextradefs.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f7473d2d..68505129 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -202,8 +202,8 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel float TextScale = DrawPanel.TextScale; for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype > 0) { - timeleft = floor(FO_Hud_Grentimers[i].expires - time); - if(timeleft < 0) { + timeleft = floor(FO_Hud_Grentimers[i].expires - time) + 1; + if(timeleft < 1) { //Expire and fill the gap if there are any active grentimers afterwards FO_Hud_Grentimers[i].grentype = 0; for(float j = i + 1; j < FO_Hud_Grentimers.length; j++) { From b7c3d4f0eb626eab388a2705413e659e840e37e1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 4 Oct 2019 23:44:07 +1300 Subject: [PATCH 0813/2474] Client-side menu basis; basic team and class menus --- csqc/csextradefs.qc | 46 +++++++- csqc/csprogs.src | 3 +- csqc/events.qc | 21 +++- csqc/hud.qc | 4 +- csqc/hud_helpers.qc | 33 ------ csqc/input.qc | 53 ++++++++- csqc/main.qc | 31 +++++- csqc/menu.qc | 251 ++++++++++++++++++++++++++++++++++++++++++ csqc/sui_sys.qc | 23 +++- menu/main.qc | 33 ++++-- menu/options_basic.qc | 2 +- share/commondefs.qc | 5 + ssqc/commands.qc | 71 ++++++++++++ ssqc/menu.qc | 35 +++++- ssqc/tforthlp.qc | 36 ++++-- 15 files changed, 575 insertions(+), 72 deletions(-) create mode 100644 csqc/menu.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 68505129..676373d4 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -1,8 +1,29 @@ #include "../share/defs.h" +vector MENU_BG = '0.2 0.3 0.4'; +vector MENU_BG_DARK = '0.1 0.15 0.2'; +vector MENU_BORDER = '0.3 0.4 0.5'; +vector MENU_SELECTED = '0 1 0'; +vector MENU_UNSELECTED = '1 0 0'; +vector MENU_BUTTON = '0.3 0.4 0.5'; +//vector MENU_BUTTON_BORDER = '0.35 0.45 0.55'; +vector MENU_TEXT_1 = '1 1 1'; +vector MENU_TEXT_2 = '0.7 0.75 0.75'; +vector MENU_TEXT_3 = '1 1 0'; +vector MENU_HIGHLIGHT = '1 1 1'; +vector MENU_DARKEN = '1 1 1'; + +vector MENU_TEXT_SMALL = '8 8 0'; +vector MENU_TEXT_MEDIUM = '16 16 0'; +vector MENU_TEXT_LARGE = '24 24 0'; +float MENU_START_CONTENT = 32; + .float owned_by; float fo_hud_editor; +float fo_hud_menu_active; float jumptime; +vector ScreenSize; +float number_of_teams; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; @@ -10,6 +31,9 @@ void(string id, string identify) Hud_DrawIdentifyPanel; void (string panelid, float display, string text, string icon) Hud_DrawHudOptionsPanel; void (string id, float playerclass) Hud_DrawClassInfoPanel; void (string panelid) Hud_DrawFlagStatusBar; +float(string id, vector pos, vector size, float alpha, float enabled) hud_panel; +vector(float panelid) getPosition; +vector(float panelid) getFillSize; typedef struct { @@ -232,7 +256,6 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel } }; - FO_Hud_Settings HudSettings; @@ -248,9 +271,18 @@ enum { HUD_PANEL_PLAYERCLASS, HUD_PANEL_IDENTIFY, HUD_PANEL_FLAGINFO, - HUD_PANEL_GRENTIMER + HUD_PANEL_GRENTIMER, + HUD_PANEL_MENU }; +void(string panelid, float display, string text, string icon) drawSimplePanel = { + if (fo_hud_editor) { + if (hud_panel(panelid, getPosition(HUD_PANEL_MENU), getFillSize(HUD_PANEL_MENU), 0.3, 1)) { + // click event + } + } +} + var FO_Hud_Panel Hud_Panels[] = { {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'0 0','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'0 0','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, @@ -261,9 +293,17 @@ var FO_Hud_Panel Hud_Panels[] = { {"playerclasspanel",FO_HUD_SPECIAL_NAME,'0 0','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,0,1,0, drawIdentify, {return SBAR.Identify;}}, {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimerpanel","Grenade Timer",'0 0','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}} + {"grentimerpanel","Grenade Timer",'0 0','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, + {"menupanel","Menu",'0 0','200 200',1,0,1,0, drawSimplePanel, {return "";}} }; +vector(float panelid) getPosition = { + return Hud_Panels[panelid].Position; +} +vector(float panelid) getFillSize = { + return Hud_Panels[panelid].FillSize; +} + #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" diff --git a/csqc/csprogs.src b/csqc/csprogs.src index a5c2cc3d..0a73723b 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -4,9 +4,10 @@ csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc sui_sys.qc -input.qc +menu.qc main.qc events.qc hud_helpers.qc hud.qc settings.qc +input.qc diff --git a/csqc/events.qc b/csqc/events.qc index c64ba3fe..376eeca7 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -98,10 +98,29 @@ void() CSQC_Parse_Event = { float grentype = readfloat(); AddGrenTimer(grentype); if(cvar(FOCMD_GRENTIMER) == 1) { - print("playing grentimer!\n"); localcmd("play grentimer.wav\n"); } break; + case MSG_CLIENT_MENU: + float menutype = readfloat(); + switch (menutype) { + case CLIENT_MENU_TEAM: + number_of_teams = readfloat(); + for(float i = 0; i < 4; i++) { + if(i < number_of_teams) { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; + } + } + FO_Menu_Team(FALSE); + break; + case CLIENT_MENU_CLASS: + float allowedclasses = readfloat(); + FO_Menu_Class(FALSE); + break; + } + break; } } diff --git a/csqc/hud.qc b/csqc/hud.qc index 166dce7d..383458fd 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -96,7 +96,9 @@ void Hud_DrawFlagStatusBar(string panelid) flagInfoCount++; } } - + if(fo_hud_editor && !flagInfoCount) { + flagInfoCount = 1; + } vector fillsize = [sizex * 4, sizey * flagInfoCount]; float alpha = 0; if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_FLAGINFO].Display)) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index f028d4bc..a86bf42e 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -1,20 +1,3 @@ -vector MENU_BG = '0.2 0.3 0.4'; -vector MENU_BG_DARK = '0.1 0.15 0.2'; -vector MENU_BORDER = '0.3 0.4 0.5'; -vector MENU_SELECTED = '0 1 0'; -vector MENU_UNSELECTED = '1 0 0'; -vector MENU_BUTTON = '0.3 0.4 0.5'; -vector MENU_BUTTON_BORDER = '0.35 0.45 0.55'; -vector MENU_TEXT_1 = '1 1 1'; -vector MENU_TEXT_2 = '0.7 0.75 0.75'; -vector MENU_HIGHLIGHT = '1 1 1'; -vector MENU_DARKEN = '1 1 1'; - -vector MENU_TEXT_SMALL = '8 8 0'; -vector MENU_TEXT_MEDIUM = '16 16 0'; -vector MENU_TEXT_LARGE = '24 24 0'; -float MENU_START_CONTENT = 32; - void Hud_WriteCfg(string path); float GetDrawPanel(string id); void SetDrawPanel(string id); @@ -36,22 +19,6 @@ void FO_Hud_Editor() } } -float(string id, vector pos, vector size, string text) hud_button = -{ - sui_push_frame(pos, size); - vector basecolor = sui_is_hovered(id) ? MENU_BUTTON + MENU_HIGHLIGHT * 0.1 : MENU_BUTTON; - basecolor = sui_is_held(id) ? MENU_BUTTON - MENU_DARKEN * 0.1 : basecolor; - sui_fill([0, 0], size, basecolor, 0.6, 0); - sui_border_box([0, 0], size, 1, MENU_BUTTON_BORDER, 0.4, 0); - - sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_text([0, 0], MENU_TEXT_SMALL, text, MENU_TEXT_1, 1, 0); - sui_action_element([0, 0], size, id, sui_noop); - sui_pop_frame(); - - return sui_is_clicked(id); -}; - void(string id, vector pos, vector size, vector minmaxsteps, __inout float value) hud_slider = { sui_push_frame(pos, size); diff --git a/csqc/input.qc b/csqc/input.qc index 78abdfa9..cc3998c8 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -1,12 +1,26 @@ +void Menu_Cancel(); +void FO_Menu_Game(float); + float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { float used = sui_input_event(evtype, scanx, chary, devid); - if (fo_hud_editor) + //if(evtype == IE_KEYUP) print("Key up: ", ftos(scanx), ", char: ", ftos(chary), "\n"); + if (fo_hud_editor || fo_hud_menu_active) { switch (evtype) { case IE_KEYUP: switch (scanx) { + case K_ESCAPE: + if(fo_hud_menu_active) { + Menu_Cancel(); + return TRUE; + } + if(fo_hud_editor) { + fo_hud_editor = FALSE; + return TRUE; + } + break; case K_MOUSE1: // work out if on a button break; @@ -15,11 +29,24 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case IE_KEYDOWN: switch (scanx) { + case K_ESCAPE: + if(fo_hud_menu_active) { + //Menu_Cancel(); + return TRUE; + } + if(fo_hud_editor) { + //fo_hud_editor = FALSE; + return TRUE; + } + break; case K_MOUSE1: // work out if on a button return TRUE; break; } + if(fo_hud_menu_active) { + return fo_menu_process_input(CurrentMenu, scanx); + } break; case IE_MOUSEDELTA: return TRUE; @@ -29,6 +56,28 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; default: } + } else { + switch (evtype) + { + case IE_KEYUP: + switch (scanx) + { + case K_ESCAPE: + FO_Menu_Game(TRUE); + return TRUE; + break; + } + break; + case IE_KEYDOWN: + switch (scanx) + { + case K_ESCAPE: + return TRUE; + break; + } + break; + default: + } } return FALSE; -} \ No newline at end of file +} diff --git a/csqc/main.qc b/csqc/main.qc index df7aee4b..fed76c4e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -26,9 +26,15 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_AUTOHOP, "0"); //registercommand(FOCMD_GRENTIMER); registercvar(FOCMD_GRENTIMER, "1"); + registercvar("fo_menu_test", "0"); + registercommand("fo_menu_game"); + registercommand("fo_menu_team"); + registercommand("fo_menu_class"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); + + CurrentMenu = FO_MENU_TEAM; }; noref void() CSQC_WorldLoaded = { @@ -37,7 +43,8 @@ noref void() CSQC_WorldLoaded = { } noref void(float width, float height, float menushown) CSQC_UpdateView = { - team_no = getstatf(STAT_TEAMNO); + ScreenSize = [width, height, menushown]; + team_no = getstatf(STAT_TEAMNO); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -53,9 +60,16 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); - sui_begin(width, height); - Hud_Draw(width, height); - sui_end(); + sui_begin(width, height); + //if(cvar("fo_menu_test")) { + // FO_MENU_TEST.active = 1; + //} else { + // FO_MENU_TEST.active = 0; + //} + //fo_hud_menu_active = cvar("fo_menu_test"); + Menu_Draw(width, height, menushown); + Hud_Draw(width, height); + sui_end(); } noref float(string cmd) CSQC_ConsoleCommand = { @@ -71,6 +85,15 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_hud_reset": FO_Hud_Editor_LoadDefaultSettings(); break; + case "fo_menu_game": + FO_Menu_Game(TRUE); + break; + case "fo_menu_team": + FO_Menu_Team(TRUE); + break; + case "fo_menu_class": + FO_Menu_Class(TRUE); + break; /* case "fo_autohop": if(!argv(1)) { diff --git a/csqc/menu.qc b/csqc/menu.qc new file mode 100644 index 00000000..fd85a47b --- /dev/null +++ b/csqc/menu.qc @@ -0,0 +1,251 @@ +#define FO_MENU_FLAG_USE_MOUSE 1 +#define FO_MENU_FLAG_CENTER 2 + +#define FO_MENU_STATE_HIDDEN 0 +#define FO_MENU_STATE_NORMAL 1 +#define FO_MENU_STATE_DISABLED 2 + +typedef struct { + string shortcut; //key to press. if omitted - mouse only + string name; //what to display + string value; //optional - displays current value/state + string description; //optional + float state; //active/disabled + void() action; + vector colour; +} fo_menu_option; + +typedef struct { + vector position; + vector size; + string title; + float flags; + fo_menu_option options[20]; + float num_opts; + float active; + //float alpha; +} fo_menu; + +void FO_Menu_Team(float); +void Menu_Cancel() ; + +fo_menu InProgressMenu; +fo_menu CurrentMenu; + +var fo_menu FO_MENU_GAME = { + [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + {"1","Change Team", "","",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, + {"2","Change Class","","",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, + {"3","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, + {"4","Join", "","",FO_MENU_STATE_NORMAL,{localcmd("join!\n"); Menu_Cancel();},MENU_BUTTON}, + {}, + {"5","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, + }, 6, TRUE +}; +var fo_menu FO_MENU_TEAM = { + [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + {"1","Blue team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, + {"2","Red team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, + {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, + {"4","Green team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 4\n");Menu_Cancel();},'0.4 0.7 0.3'}, + {}, + {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam auto\n");Menu_Cancel();},'0.4 0.4 0.4'}, + }, 6, TRUE +}; +var fo_menu FO_MENU_CLASS = { + [0,0], [300,200], "Select Class", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + {"1","Scout","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 1\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Sniper","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 2\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Soldier","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 3\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Demoman","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 4\n");Menu_Cancel();},MENU_BUTTON}, + {"5","Medic","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 5\n");Menu_Cancel();},MENU_BUTTON}, + {"6","Heavy Weapons","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 6\n");Menu_Cancel();},MENU_BUTTON}, + {"7","Pyro","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 7\n");Menu_Cancel();},MENU_BUTTON}, + {"8","Spy","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 8\n");Menu_Cancel();},MENU_BUTTON}, + {"9","Engineer","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 9\n");Menu_Cancel();},MENU_BUTTON}, + {"0","Random Playerclass","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 10\n");Menu_Cancel();},MENU_BUTTON}, + }, 10, TRUE +}; + +void fo_menu_start(vector position, vector size, string title, float flags) = { + InProgressMenu.position = position; + InProgressMenu.size = size; + InProgressMenu.title = title; + InProgressMenu.flags = flags; + InProgressMenu.active = 0; + //InProgressMenu.alpha = 0.6; + fo_menu_option fmo; + for(float i = 0; i < InProgressMenu.options.length; i++) { + InProgressMenu.options[i] = fmo; + } + InProgressMenu.num_opts = 0; +} + +void fo_menu_add_option(fo_menu_option option) { + if(InProgressMenu.num_opts < InProgressMenu.options.length) { + InProgressMenu.options[InProgressMenu.num_opts] = option; + InProgressMenu.num_opts++; + } else { + print("Ran out of room to add option #", ftos(InProgressMenu.num_opts), " to menu\n"); + } +} + +void fo_menu_add_option2(string shortcut, string name, string value, string description, float state, void() action) { + fo_menu_option option = {shortcut, name, value, description, state, action }; + if(InProgressMenu.num_opts < InProgressMenu.options.length) { + InProgressMenu.options[InProgressMenu.num_opts] = option; + InProgressMenu.num_opts++; + } else { + print("Ran out of room to add option #", ftos(InProgressMenu.num_opts), " to menu\n"); + } +} + +vector fo_menu_draw(fo_menu menu) = { + //print("Active? ", ftos(menu.active), "\n"); + vector position; + if(menu.flags & FO_MENU_FLAG_CENTER) { + //position = [ScreenSize.x / 2 - menu.size.x / 2, ScreenSize.y / 2 - menu.size.y / 2]; + position = Hud_Panels[HUD_PANEL_MENU].Position; + } else { + position = menu.position; + } + + + if(fo_hud_editor) return position; + if(!menu.active) { + //print("menu inactive\n"); + setcursormode(FALSE); + //fo_hud_menu_active = FALSE; + return position; + } + if(menu.flags & FO_MENU_FLAG_USE_MOUSE) { + setcursormode(TRUE); + //fo_hud_menu_active = TRUE; + } + + local float padding = 4, titleoffset = 36; + local vector buttonsize = [menu.size.x - padding * 2, 24]; + local string id = strcat("fo_menu_",menu.title); + local vector tempcolour; + + menu.size.y = titleoffset + menu.num_opts * (buttonsize.y + padding); + + if (sui_is_held(id)) { + position = position + [Mouse.x, Mouse.y] - HudSettings.MousePos; +// sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); + } + + + sui_border_box(position, menu.size, 1, MENU_BORDER, 0.4, 0); + sui_push_frame(position, menu.size); + + sui_fill([0, 0], menu.size, MENU_BG, 0.4, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_action_element([0, 0], menu.size, id, sui_noop); + sui_pop_frame(); + + drawstring( + position + [menu.size.x / 2 - stringwidth(menu.title,1,MENU_TEXT_MEDIUM)/2,padding], + menu.title, + MENU_TEXT_MEDIUM, + MENU_TEXT_2, + 1, + 0 + ); + + for(float i = 0; i < menu.num_opts; i++) { + if(menu.options[i].state & FO_MENU_STATE_NORMAL) { + if(menu.options[i].name) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour)) { + menu.options[i].action(); + } + if(menu.options[i].shortcut) { + drawstring( + position + [padding*3, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], + menu.options[i].shortcut, + MENU_TEXT_SMALL, + MENU_TEXT_3, + 1, + 0 + ); + } + } + + } else if(menu.options[i].state & FO_MENU_STATE_DISABLED) { + if(menu.options[i].name) { + sui_border_box(position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, 1, MENU_BG_DARK, 0.4, 0); + drawstring( + position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,MENU_TEXT_SMALL) / 2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], + menu.options[i].name, + MENU_TEXT_SMALL, + MENU_TEXT_2, + 1, + 0 + ); + } + + } + } + return position; +} + +float fo_menu_process_input(fo_menu menu, float scan) = { + local string button = ""; + if(scan > 47 && scan < 58) { + button = ftos(scan - 48); + for(float i = 0; i < menu.num_opts; i++) { + if(menu.options[i].state & FO_MENU_STATE_NORMAL) { + if(menu.options[i].shortcut == button) { + menu.options[i].action(); + return TRUE; + } + } + } + } + return FALSE; +} + +void Menu_Cancel() = { + if(fo_hud_menu_active) { + setcursormode(FALSE); + fo_hud_menu_active = FALSE; + } + //CurrentMenu.active = FALSE; +} + +void Menu_Draw(float width, float height, float menushown) = { + if(fo_hud_menu_active) { + //CurrentMenu.active = cvar("fo_menu_test"); + CurrentMenu.position = fo_menu_draw(CurrentMenu); + Hud_Panels[HUD_PANEL_MENU].Position = CurrentMenu.position; + } else { + Menu_Cancel(); + } +} + +void FO_Menu_Game(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = FO_MENU_GAME; + fo_hud_menu_active = TRUE; +} + +void FO_Menu_Team(float force) = { + if(fo_hud_menu_active && !force) + return; + if(team_no) { + FO_MENU_TEAM.num_opts = number_of_teams; + } else { + FO_MENU_TEAM.num_opts = 6; + } + CurrentMenu = FO_MENU_TEAM; + fo_hud_menu_active = TRUE; +} + +void FO_Menu_Class(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = FO_MENU_CLASS; + fo_hud_menu_active = TRUE; +} diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 20ac85de..ef373436 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -935,5 +935,26 @@ void() sui_draw_bind_overlay = } }; +float(string id, vector pos, vector size, string text, vector colour) hud_colour_button = +{ + sui_push_frame(pos, size); + vector basecolor = sui_is_hovered(id) ? colour + MENU_HIGHLIGHT * 0.1 : colour; + vector bordercolour = colour + '0.05 0.05 0.05'; + basecolor = sui_is_held(id) ? colour - MENU_DARKEN * 0.1 : basecolor; + sui_fill([0, 0], size, basecolor, 0.6, 0); + sui_border_box([0, 0], size, 1, bordercolour, 0.4, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_text([0, 0], MENU_TEXT_SMALL, text, MENU_TEXT_1, 1, 0); + sui_action_element([0, 0], size, id, sui_noop); + sui_pop_frame(); + + return sui_is_clicked(id); +}; + +float(string id, vector pos, vector size, string text) hud_button = { + return hud_colour_button(id, pos, size, text, MENU_BUTTON); +} + -// -------------------- END OF SUI SYSTEM STUFF -------------------- \ No newline at end of file +// -------------------- END OF SUI SYSTEM STUFF -------------------- diff --git a/menu/main.qc b/menu/main.qc index ce0b52ba..d7959c8e 100644 --- a/menu/main.qc +++ b/menu/main.qc @@ -96,32 +96,41 @@ nonstatic void(mitem_desktop desktop) M_Main = #if 1//def CSQC //spinny quad/pent, for the luls //local string it = (random()<0.9)?"progs/quaddama.mdl":"progs/invulner.mdl"; - local string skin = "tf_sold"; + local string skin = "sol"; local float r = random(), col = 13; //Blue + if(r > 0.89) - skin = "tf_scout"; + skin = "sco"; else if(r > 0.78) - skin = "tf_snipe"; + skin = "sni"; else if(r > 0.67) - skin = "tf_demo"; + skin = "dem"; else if(r > 0.56) - skin = "tf_medic"; + skin = "med"; else if(r > 0.45) - skin = "tf_hwguy"; + skin = "hwg"; else if(r > 0.34) - skin = "tf_pyro"; + skin = "pyr"; else if(r > 0.23) - skin = "tf_spy"; + skin = "spy"; else if(r > 0.12) - skin = "tf_eng"; + skin = "eng"; + //skin = "player_red"; + r = random(); - if(r > 0.95) + if(r > 0.95) { col = 11; //Green - else if(r > 0.9) + skin = strcat("gren_", skin); + } else if(r > 0.9) { col = 12; //Yellow - else if(r > 0.45) + skin = strcat("yell_", skin); + } else if(r > 0.45) { col = 4; //Red + skin = strcat("red_", skin); + } else { + skin = strcat("blue_", skin); + } //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); m.add(spawn (mitem_spinnymodel, diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 4d135307..740f5c45 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -153,7 +153,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); - m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', customskin:skin, rotatespeed:10), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); + m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', customskin:skin, rotatespeed:10, topcolour:0, bottomcolour:0), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); // m.add(spawn (mitem_playerpreview, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 12*-16/2], [-40, 12*16/2]); addmenuback(m); diff --git a/share/commondefs.qc b/share/commondefs.qc index 5f3ecd0e..b8c3f343 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -6,6 +6,8 @@ #define MSG_SBAR 4 #define MSG_GRENPRIMED 5 +#define MSG_CLIENT_MENU 6 + #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 #define FLAGINFO_DROPPED 3 @@ -15,3 +17,6 @@ #define FLAGINFO_ICON_FLAG 0 #define FLAGINFO_ICON_BUTTON 1 + +#define CLIENT_MENU_TEAM 1 +#define CLIENT_MENU_CLASS 2 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 815cf941..d33df494 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -44,6 +44,77 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } } break; + case "changeteam": + if(self.classname == "observer") { + sprint(self, PRINT_HIGH, "You can't join a team while spectating! Join the game first.\n"); + break; + } + if(teamplay == 0) { + sprint(self, PRINT_HIGH, "You can't join a team when teamplay is disabled!\n"); + break; + } + if (arg2) { + if(arg2 == "auto") { + if(self.team_no == 0) { + TeamFortress_TeamPutPlayerInTeam(); + UpdateClientMenu_Class(self); + break; + } else { + sprint(self, PRINT_HIGH, "You can't auto team when you're already playing!\n"); + break; + } + } + if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { + float newteam = stof(arg2), oldteam = self.team_no; + if(number_of_teams == 0 || newteam <= number_of_teams) { + TeamFortress_TeamSet(newteam); + if(!oldteam) { + UpdateClientMenu_Class(self); + } + break; + } + } + sprint(self, PRINT_HIGH, "Invalid team choice. Please use values 1-",number_of_teams?ftos(number_of_teams):"4",self.team_no?"":" or 'auto'",".\n"); + } else { + UpdateClientMenu_Team(self); + } + break; + case "changeclass": + if(self.classname == "observer") { + sprint(self, PRINT_HIGH, "You can't pick a class while spectating! Join the game first.\n"); + break; + } + if (arg2) { + float newclass = stof(arg2); + + if (!newclass) { + sprint(self, PRINT_HIGH, "Invalid class choice. Please use values 1-10.\n"); + break; + } + + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + + // keep showing menu if class is invalid + if (newclass > 10 || (!IsLegalClass(newclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, newclass)) { + UpdateClientMenu_Class(self); + break; + } + + // don't try to change class if class is forbidden + if ((!IsLegalClass(newclass) && !override_mapclasses) || CF_GetClassRestriction(self.team_no, newclass) == -1) { + break; + } + + // close menu if selected class is current class + //if (self.playerclass == newclass || (newclass == 10 && (self.tfstate & TFSTATE_RANDOMPC))) { + // break; + //} + + TeamFortress_ChangeClass(newclass); + } else { + UpdateClientMenu_Class(self); + } + break; } if (self.is_admin) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 8790d18b..6913295e 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -188,13 +188,39 @@ string (float pf_team_no, string ps_team) Menu_Team_TeamString = { return strzone(s_string); }; +void UpdateClientMenu_Team(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_TEAM); + WriteFloat(MSG_MULTICAST, number_of_teams); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_Class(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_CLASS); + WriteFloat(MSG_MULTICAST, number_of_teams); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void (float update) Menu_Team = { local entity timer; - + if (self.classname == "observer") /* Status_Menu(self, Menu_Team_Input, ""); */ return; + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Team(self); + return; + } + // allow toggling team menu using any method to show it if (!update && self.menu_input == Menu_Team_Input) { Menu_Input(0); @@ -302,6 +328,13 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { void (float update) Menu_Class = { local entity timer; + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own class menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Class(self); + return; + } // allow toggling team menu using any method to show it if (!update && self.menu_input == Menu_Class_Input) { Menu_Input(0); diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index aa576908..ef6b9e33 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -15,23 +15,35 @@ void () TeamFortress_MOTD = { local string st1; local string st2; local string ya; + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + + if(csqcactive) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + //return; + } if (self.motd == 5) { - sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); + if(csqcactive) { + UpdateClientMenu_Team(self); + } else { + sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); - st1 = infokey(world, "motd1"); - if (st1 != string_null) { - st2 = infokey(world, "motd2"); - if (st2 != string_null) { - st1 = strcat(strcat(st1, "\n"), st2); + st1 = infokey(world, "motd1"); + if (st1 != string_null) { + st2 = infokey(world, "motd2"); + if (st2 != string_null) { + st1 = strcat(strcat(st1, "\n"), st2); + } + } else { + st1 = "Welcome to FortressOne\n==================================\nwww.github.com/FortressOne"; } - } else { - st1 = "Welcome to FortressOne\n==================================\nwww.github.com/FortressOne"; - } - sprint(self, PRINT_HIGH, st1); - sprint(self, PRINT_HIGH, "\n\n\n"); - Status_Menu(self, MOTD_Input, st1); + sprint(self, PRINT_HIGH, st1); + sprint(self, PRINT_HIGH, "\n\n\n"); + Status_Menu(self, MOTD_Input, st1); + } } if (self.motd == 20) { From bd7bbf7dd27ba4bd9da332e95456991e933a8ec2 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 5 Oct 2019 08:47:37 +1300 Subject: [PATCH 0814/2474] fix for menus appearing offscreen; added menu scaling --- csqc/csextradefs.qc | 22 +++++++++++----------- csqc/hud.qc | 1 + csqc/menu.qc | 36 +++++++++++++++++++++--------------- csqc/settings.qc | 1 - csqc/sui_sys.qc | 6 +++--- ssqc/commands.qc | 2 ++ 6 files changed, 38 insertions(+), 30 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 676373d4..ad14e799 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -284,17 +284,17 @@ void(string panelid, float display, string text, string icon) drawSimplePanel = } var FO_Hud_Panel Hud_Panels[] = { - {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'0 0','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, - {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'0 0','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, - {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, - {"capspanel",FO_HUD_CAPS_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'0 0','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, - {"playerclasspanel",FO_HUD_SPECIAL_NAME,'0 0','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identifypanel",FO_HUD_IDENTIFY_NAME,'0 0','50 26',1,0,1,0, drawIdentify, {return SBAR.Identify;}}, - {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'0 0','150 260',1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimerpanel","Grenade Timer",'0 0','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, - {"menupanel","Menu",'0 0','200 200',1,0,1,0, drawSimplePanel, {return "";}} + {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, + {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 30','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, + {"capspanel",FO_HUD_CAPS_NAME,'10 40','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'10 60','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, + {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 70','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 80','50 26',1,0,1,0, drawIdentify, {return SBAR.Identify;}}, + {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 90','150 260',1,0,1,0, drawFlagInfo, {return "";}}, + {"grentimerpanel","Grenade Timer",'10 100','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, + {"menupanel","Menu",'10 110','200 200',1,0,1,0, drawSimplePanel, {return "";}} }; vector(float panelid) getPosition = { diff --git a/csqc/hud.qc b/csqc/hud.qc index 383458fd..03769118 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -45,6 +45,7 @@ void Hud_WriteCfg(string path) void FO_Hud_Editor_LoadDefaultSettings() { + Hud_Panels[HUD_PANEL_HUDOPTIONS].drawPanel = Hud_DrawHudOptionsPanel; vector vsize = (vector)getproperty(VF_SCREENVSIZE); float width = vsize_x; float height = vsize_y; diff --git a/csqc/menu.qc b/csqc/menu.qc index fd85a47b..04bcee5c 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -122,13 +122,19 @@ vector fo_menu_draw(fo_menu menu) = { setcursormode(TRUE); //fo_hud_menu_active = TRUE; } + local float scale = Hud_Panels[HUD_PANEL_MENU].Scale, textscale = Hud_Panels[HUD_PANEL_MENU].TextScale; + if(!textscale) { + textscale = scale; + } - local float padding = 4, titleoffset = 36; - local vector buttonsize = [menu.size.x - padding * 2, 24]; + local float padding = 4 * scale, titleoffset = 36 * scale; + local vector menusize = menu.size * scale; + local vector buttonsize = [menusize.x - padding * 2, 24]; + local vector smalltext = MENU_TEXT_SMALL * textscale, mediumtext = MENU_TEXT_MEDIUM * textscale; local string id = strcat("fo_menu_",menu.title); local vector tempcolour; - menu.size.y = titleoffset + menu.num_opts * (buttonsize.y + padding); + menusize.y = titleoffset + menu.num_opts * (buttonsize.y + padding); if (sui_is_held(id)) { position = position + [Mouse.x, Mouse.y] - HudSettings.MousePos; @@ -136,19 +142,19 @@ vector fo_menu_draw(fo_menu menu) = { } - sui_border_box(position, menu.size, 1, MENU_BORDER, 0.4, 0); - sui_push_frame(position, menu.size); + sui_border_box(position, menusize, 1, MENU_BORDER, 0.4, 0); + sui_push_frame(position, menusize); - sui_fill([0, 0], menu.size, MENU_BG, 0.4, 0); + sui_fill([0, 0], menusize, MENU_BG, 0.4, 0); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_action_element([0, 0], menu.size, id, sui_noop); + sui_action_element([0, 0], menusize, id, sui_noop); sui_pop_frame(); drawstring( - position + [menu.size.x / 2 - stringwidth(menu.title,1,MENU_TEXT_MEDIUM)/2,padding], + position + [menusize.x / 2 - stringwidth(menu.title,1,mediumtext)/2,padding], menu.title, - MENU_TEXT_MEDIUM, + mediumtext, MENU_TEXT_2, 1, 0 @@ -157,14 +163,14 @@ vector fo_menu_draw(fo_menu menu) = { for(float i = 0; i < menu.num_opts; i++) { if(menu.options[i].state & FO_MENU_STATE_NORMAL) { if(menu.options[i].name) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour)) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext)) { menu.options[i].action(); } if(menu.options[i].shortcut) { drawstring( - position + [padding*3, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], + position + [padding*3, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], menu.options[i].shortcut, - MENU_TEXT_SMALL, + smalltext, MENU_TEXT_3, 1, 0 @@ -176,9 +182,9 @@ vector fo_menu_draw(fo_menu menu) = { if(menu.options[i].name) { sui_border_box(position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, 1, MENU_BG_DARK, 0.4, 0); drawstring( - position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,MENU_TEXT_SMALL) / 2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], + position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], menu.options[i].name, - MENU_TEXT_SMALL, + smalltext, MENU_TEXT_2, 1, 0 @@ -186,7 +192,7 @@ vector fo_menu_draw(fo_menu menu) = { } } - } + } return position; } diff --git a/csqc/settings.qc b/csqc/settings.qc index 715e8773..d6c17d04 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -17,7 +17,6 @@ void FO_LoadDefaultSettings() void FO_LoadSettings() { - Hud_Panels[HUD_PANEL_HUDOPTIONS].drawPanel = Hud_DrawHudOptionsPanel; FO_LoadDefaultSettings(); float filehandle; diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index ef373436..8327f7a2 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -935,7 +935,7 @@ void() sui_draw_bind_overlay = } }; -float(string id, vector pos, vector size, string text, vector colour) hud_colour_button = +float(string id, vector pos, vector size, string text, vector colour, vector textsize) hud_colour_button = { sui_push_frame(pos, size); vector basecolor = sui_is_hovered(id) ? colour + MENU_HIGHLIGHT * 0.1 : colour; @@ -945,7 +945,7 @@ float(string id, vector pos, vector size, string text, vector colour) hud_colour sui_border_box([0, 0], size, 1, bordercolour, 0.4, 0); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_text([0, 0], MENU_TEXT_SMALL, text, MENU_TEXT_1, 1, 0); + sui_text([0, 0], textsize, text, MENU_TEXT_1, 1, 0); sui_action_element([0, 0], size, id, sui_noop); sui_pop_frame(); @@ -953,7 +953,7 @@ float(string id, vector pos, vector size, string text, vector colour) hud_colour }; float(string id, vector pos, vector size, string text) hud_button = { - return hud_colour_button(id, pos, size, text, MENU_BUTTON); + return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL); } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index d33df494..df4ad8fa 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -45,6 +45,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "changeteam": + processedCmd = TRUE; if(self.classname == "observer") { sprint(self, PRINT_HIGH, "You can't join a team while spectating! Join the game first.\n"); break; @@ -80,6 +81,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "changeclass": + processedCmd = TRUE; if(self.classname == "observer") { sprint(self, PRINT_HIGH, "You can't pick a class while spectating! Join the game first.\n"); break; From 44ddae367016951ac0fa7e4bd9d46c6f5cad3ce4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 5 Oct 2019 09:11:22 +1300 Subject: [PATCH 0815/2474] remove commented out stuff --- csqc/csextradefs.qc | 7 ------- csqc/main.qc | 50 --------------------------------------------- csqc/menu.qc | 8 -------- 3 files changed, 65 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index ad14e799..3a538a1d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -307,13 +307,6 @@ vector(float panelid) getFillSize = { #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" -//typedef struct { -// float Autohop; -// float Grentimer; -//} FO_Settings; -//FO_Settings Settings; - - float team_no; diff --git a/csqc/main.qc b/csqc/main.qc index fed76c4e..aafedde2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -22,14 +22,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); - //registercommand("fo_autohop"); registercvar(FOCMD_AUTOHOP, "0"); - //registercommand(FOCMD_GRENTIMER); registercvar(FOCMD_GRENTIMER, "1"); - registercvar("fo_menu_test", "0"); registercommand("fo_menu_game"); - registercommand("fo_menu_team"); - registercommand("fo_menu_class"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -61,12 +56,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); sui_begin(width, height); - //if(cvar("fo_menu_test")) { - // FO_MENU_TEST.active = 1; - //} else { - // FO_MENU_TEST.active = 0; - //} - //fo_hud_menu_active = cvar("fo_menu_test"); Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); @@ -88,45 +77,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_game": FO_Menu_Game(TRUE); break; - case "fo_menu_team": - FO_Menu_Team(TRUE); - break; - case "fo_menu_class": - FO_Menu_Class(TRUE); - break; -/* - case "fo_autohop": - if(!argv(1)) { - print("Autohop is ",Settings.Autohop?"on":"off","\n"); - } else { - val = stof(argv(1)); - if (val == 1) - { - Settings.Autohop = 1; - print("auto bunnyhop has been enabled\n"); - } - else if (val == 0) - { - Settings.Autohop = 0; - print("auto bunnyhop has been disabled\n"); - } - FO_WriteSettings(); - } - break; - case FOCMD_GRENTIMER: - if(!argv(1)) { - print("Client-side Grenade timer is ",Settings.Grentimer?"on":"off","\n"); - } else { - val = stof(argv(1)); - if(val == 1) { - Settings.Grentimer = 1; - } else if(val == 0) { - Settings.Grentimer = 0; - } - FO_WriteSettings(); - } - break; -*/ } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index 04bcee5c..1bc1213e 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -101,10 +101,8 @@ void fo_menu_add_option2(string shortcut, string name, string value, string desc } vector fo_menu_draw(fo_menu menu) = { - //print("Active? ", ftos(menu.active), "\n"); vector position; if(menu.flags & FO_MENU_FLAG_CENTER) { - //position = [ScreenSize.x / 2 - menu.size.x / 2, ScreenSize.y / 2 - menu.size.y / 2]; position = Hud_Panels[HUD_PANEL_MENU].Position; } else { position = menu.position; @@ -113,14 +111,11 @@ vector fo_menu_draw(fo_menu menu) = { if(fo_hud_editor) return position; if(!menu.active) { - //print("menu inactive\n"); setcursormode(FALSE); - //fo_hud_menu_active = FALSE; return position; } if(menu.flags & FO_MENU_FLAG_USE_MOUSE) { setcursormode(TRUE); - //fo_hud_menu_active = TRUE; } local float scale = Hud_Panels[HUD_PANEL_MENU].Scale, textscale = Hud_Panels[HUD_PANEL_MENU].TextScale; if(!textscale) { @@ -138,7 +133,6 @@ vector fo_menu_draw(fo_menu menu) = { if (sui_is_held(id)) { position = position + [Mouse.x, Mouse.y] - HudSettings.MousePos; -// sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); } @@ -217,12 +211,10 @@ void Menu_Cancel() = { setcursormode(FALSE); fo_hud_menu_active = FALSE; } - //CurrentMenu.active = FALSE; } void Menu_Draw(float width, float height, float menushown) = { if(fo_hud_menu_active) { - //CurrentMenu.active = cvar("fo_menu_test"); CurrentMenu.position = fo_menu_draw(CurrentMenu); Hud_Panels[HUD_PANEL_MENU].Position = CurrentMenu.position; } else { From a1fc6b61c5ce1b63fff4f4e3a150d82c9aaccf46 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 5 Oct 2019 12:37:04 +1300 Subject: [PATCH 0816/2474] get rid of impulses for team/class commands --- csqc/events.qc | 2 +- csqc/menu.qc | 16 ++++++++------- ssqc/tforthlp.qc | 51 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 376eeca7..054e7b6f 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -107,7 +107,7 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_TEAM: number_of_teams = readfloat(); for(float i = 0; i < 4; i++) { - if(i < number_of_teams) { + if(i < number_of_teams && (i + 1) != team_no) { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; } else { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; diff --git a/csqc/menu.qc b/csqc/menu.qc index 1bc1213e..11ff4603 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -34,13 +34,15 @@ fo_menu CurrentMenu; var fo_menu FO_MENU_GAME = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { - {"1","Change Team", "","",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, - {"2","Change Class","","",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, - {"3","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, - {"4","Join", "","",FO_MENU_STATE_NORMAL,{localcmd("join!\n"); Menu_Cancel();},MENU_BUTTON}, + {"1","Select Team", "","",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, + {"2","Select Class","","",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, + {"3","Ready", "","",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, + {}, + {"4","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, {}, {"5","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, - }, 6, TRUE + {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 8, TRUE }; var fo_menu FO_MENU_TEAM = { [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { @@ -146,7 +148,7 @@ vector fo_menu_draw(fo_menu menu) = { sui_pop_frame(); drawstring( - position + [menusize.x / 2 - stringwidth(menu.title,1,mediumtext)/2,padding], + position + [menusize.x / 2 - stringwidth(menu.title,1,mediumtext)/2,padding*2], menu.title, mediumtext, MENU_TEXT_2, @@ -174,7 +176,7 @@ vector fo_menu_draw(fo_menu menu) = { } else if(menu.options[i].state & FO_MENU_STATE_DISABLED) { if(menu.options[i].name) { - sui_border_box(position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, 1, MENU_BG_DARK, 0.4, 0); + sui_border_box(position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, 1, MENU_BG, 0.4, 0); drawstring( position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], menu.options[i].name, diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index ef6b9e33..b5eeb413 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -74,25 +74,44 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("+slot4", "impulse 23;+attack"); TeamFortress_AliasString("-slot4", "-attack;impulse 24"); } else if (self.motd == 30) { - TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); - TeamFortress_Alias("teamblue", TF_TEAM_1, 0); - TeamFortress_Alias("teamred", TF_TEAM_2, 0); - TeamFortress_Alias("teamyellow", TF_TEAM_3, 0); - TeamFortress_Alias("teamgreen", TF_TEAM_4, 0); - TeamFortress_Alias("changeclass", TF_CHANGECLASS, 0); + if(csqcactive) { + TeamFortress_AliasString("changeteam", "cmd changeteam"); + TeamFortress_AliasString("teamblue", "cmd changeteam 1"); + TeamFortress_AliasString("teamred", "cmd changeteam 2"); + TeamFortress_AliasString("teamyellow", "cmd changeteam 3"); + TeamFortress_AliasString("teamgreen", "cmd changeteam 4"); + TeamFortress_AliasString("changeclass", "cmd changeclass"); + TeamFortress_AliasString("scout", "cmd changeclass 1"); + TeamFortress_AliasString("sniper", "cmd changeclass 2"); + TeamFortress_AliasString("soldier", "cmd changeclass 3"); + TeamFortress_AliasString("demoman", "cmd changeclass 4"); + TeamFortress_AliasString("medic", "cmd changeclass 5"); + TeamFortress_AliasString("hwguy", "cmd changeclass 6"); + TeamFortress_AliasString("pyro", "cmd changeclass 7"); + TeamFortress_AliasString("spy", "cmd changeclass 8"); + TeamFortress_AliasString("engineer", "cmd changeclass 9"); + TeamFortress_AliasString("randompc", "cmd changeclass 10"); + } else { + TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); + TeamFortress_Alias("teamblue", TF_TEAM_1, 0); + TeamFortress_Alias("teamred", TF_TEAM_2, 0); + TeamFortress_Alias("teamyellow", TF_TEAM_3, 0); + TeamFortress_Alias("teamgreen", TF_TEAM_4, 0); + TeamFortress_Alias("changeclass", TF_CHANGECLASS, 0); + TeamFortress_Alias("scout", TF_CHANGEPC_SCOUT, 0); + TeamFortress_Alias("sniper", TF_CHANGEPC_SNIPER, 0); + TeamFortress_Alias("soldier", TF_CHANGEPC_SOLDIER, 0); + TeamFortress_Alias("demoman", TF_CHANGEPC_DEMOMAN, 0); + TeamFortress_Alias("medic", TF_CHANGEPC_MEDIC, 0); + TeamFortress_Alias("hwguy", TF_CHANGEPC_HVYWEAP, 0); + TeamFortress_Alias("pyro", TF_CHANGEPC_PYRO, 0); + TeamFortress_Alias("spy", TF_CHANGEPC_SPY, 0); + TeamFortress_Alias("engineer", TF_CHANGEPC_ENGINEER, 0); + TeamFortress_Alias("randompc", TF_CHANGEPC_RANDOM, 0); + } TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); TeamFortress_Alias("legalclasses", TF_SHOWLEGALCLASSES, 0); TeamFortress_Alias("classhelp", TF_CLASSHELP, 0); - TeamFortress_Alias("scout", TF_CHANGEPC_SCOUT, 0); - TeamFortress_Alias("sniper", TF_CHANGEPC_SNIPER, 0); - TeamFortress_Alias("soldier", TF_CHANGEPC_SOLDIER, 0); - TeamFortress_Alias("demoman", TF_CHANGEPC_DEMOMAN, 0); - TeamFortress_Alias("medic", TF_CHANGEPC_MEDIC, 0); - TeamFortress_Alias("hwguy", TF_CHANGEPC_HVYWEAP, 0); - TeamFortress_Alias("pyro", TF_CHANGEPC_PYRO, 0); - TeamFortress_Alias("spy", TF_CHANGEPC_SPY, 0); - TeamFortress_Alias("engineer", TF_CHANGEPC_ENGINEER, 0); - TeamFortress_Alias("randompc", TF_CHANGEPC_RANDOM, 0); } else if (self.motd == 40) { TeamFortress_Alias("query", TF_STATUS_QUERY, 0); TeamFortress_Alias("inv", TF_INVENTORY, 0); From 84d23a0455320209884dc3b07bdf57d536dcd6da Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 6 Oct 2019 20:28:15 +1300 Subject: [PATCH 0817/2474] separate spectator menu; autojoin if only 1 team (eg try7) --- csqc/csextradefs.qc | 1 + csqc/main.qc | 1 + csqc/menu.qc | 23 +++++++++++++++++++++-- ssqc/commands.qc | 8 ++++++++ ssqc/menu.qc | 10 ++++++++++ ssqc/tforthlp.qc | 3 ++- 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3a538a1d..23495200 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -309,6 +309,7 @@ vector(float panelid) getFillSize = { float team_no; +float is_spectator; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index aafedde2..5a553c52 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -40,6 +40,7 @@ noref void() CSQC_WorldLoaded = { noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); + is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! diff --git a/csqc/menu.qc b/csqc/menu.qc index 11ff4603..cce8b5ab 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -40,10 +40,20 @@ var fo_menu FO_MENU_GAME = { {}, {"4","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, {}, - {"5","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, + {"9","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 8, TRUE }; +var fo_menu FO_MENU_GAME_SPECTATOR = { + [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, + {"2","Tracking Sidebar", "","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BUTTON}, + {}, + {"9","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, + {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 6, TRUE +}; + var fo_menu FO_MENU_TEAM = { [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { {"1","Blue team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, @@ -227,7 +237,13 @@ void Menu_Draw(float width, float height, float menushown) = { void FO_Menu_Game(float force) = { if(fo_hud_menu_active && !force) return; - CurrentMenu = FO_MENU_GAME; + if(is_spectator) { + //print(getplayerkeyvalue(player_localnum, "name"), " is a spectator!\n"); + CurrentMenu = FO_MENU_GAME_SPECTATOR; + } else { + //print(getplayerkeyvalue(player_localnum, "name"), " is playing a game!\n"); + CurrentMenu = FO_MENU_GAME; + } fo_hud_menu_active = TRUE; } @@ -235,6 +251,9 @@ void FO_Menu_Team(float force) = { if(fo_hud_menu_active && !force) return; if(team_no) { + if(number_of_teams < 2) { + return; + } FO_MENU_TEAM.num_opts = number_of_teams; } else { FO_MENU_TEAM.num_opts = 6; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index df4ad8fa..fe478063 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -54,6 +54,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "You can't join a team when teamplay is disabled!\n"); break; } + if(number_of_teams == 1) { + if(self.team_no == 0) { + TeamFortress_TeamSet(1); + } else { + sprint(self, PRINT_HIGH, "Only one team is available on this map.\n"); + } + break; + } if (arg2) { if(arg2 == "auto") { if(self.team_no == 0) { diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 6913295e..c3c79c14 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -213,6 +213,16 @@ void (float update) Menu_Team = { /* Status_Menu(self, Menu_Team_Input, ""); */ return; + //If there's only one team, just join it + if (number_of_teams == 1 && self.team_no == 0) { + Menu_Close(self); + TeamFortress_TeamSet(1); + if ((self.playerclass == 0) && (self.lives != 0)) { + Menu_Class(0); + } + return; + } + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { //fte+csqc has its own team menu //ask the client to activate it diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index b5eeb413..4dbf8fa3 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -26,7 +26,8 @@ void () TeamFortress_MOTD = { if (self.motd == 5) { if(csqcactive) { - UpdateClientMenu_Team(self); + //UpdateClientMenu_Team(self); + Menu_Team(0); } else { sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); From b7d1dcb3c1d2a4d4ade45f355cf6ba8ad175bfd1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 6 Oct 2019 23:08:41 +1300 Subject: [PATCH 0818/2474] Fix change team/class restrictions --- ssqc/client.qc | 13 +++++++------ ssqc/commands.qc | 8 ++++++-- ssqc/menu.qc | 11 ++++++++--- ssqc/tfort.qc | 47 ++++++++++++++++++++++++++--------------------- ssqc/tforttm.qc | 30 +++++++++++++++++++++++++++++- 5 files changed, 76 insertions(+), 33 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ee3ea9ca..c5077f48 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1522,14 +1522,11 @@ void () PutClientInServer = { DecodeLevelParms(); - if (self.playerclass == 0) { - if (TeamFortress_TeamIsCivilian(self.team_no)) { - TeamFortress_ChangeClass(11); - } + if (self.playerclass != PC_CIVILIAN && TeamFortress_TeamIsCivilian(self.team_no)) { + TeamFortress_ChangeClass(11); } - if ((deathmatch == 3) && (self.nextpc != 0)) { + if (deathmatch == 3) { self.playerclass = self.nextpc; - self.nextpc = 0; if (self.playerclass == PC_RANDOM) self.tfstate = self.tfstate | TFSTATE_RANDOMPC; else { @@ -1538,6 +1535,10 @@ void () PutClientInServer = { TeamFortress_ExecClassScript(self); } } + + if (self.playerclass == 0 && self.team_no > 0) { + Menu_Class(0); + } if (self.tfstate & TFSTATE_RANDOMPC) { oldclass = self.playerclass; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index fe478063..cfaaa09f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -66,7 +66,8 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if(arg2 == "auto") { if(self.team_no == 0) { TeamFortress_TeamPutPlayerInTeam(); - UpdateClientMenu_Class(self); + //UpdateClientMenu_Class(self); + Menu_Class(0); break; } else { sprint(self, PRINT_HIGH, "You can't auto team when you're already playing!\n"); @@ -78,7 +79,8 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if(number_of_teams == 0 || newteam <= number_of_teams) { TeamFortress_TeamSet(newteam); if(!oldteam) { - UpdateClientMenu_Class(self); + //UpdateClientMenu_Class(self); + Menu_Class(0); } break; } @@ -106,12 +108,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { // keep showing menu if class is invalid if (newclass > 10 || (!IsLegalClass(newclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, newclass)) { + sprint(self, PRINT_HIGH, "Invalid class for this team!\n"); UpdateClientMenu_Class(self); break; } // don't try to change class if class is forbidden if ((!IsLegalClass(newclass) && !override_mapclasses) || CF_GetClassRestriction(self.team_no, newclass) == -1) { + sprint(self, PRINT_HIGH, "Forbidden class for this team!\n"); break; } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index c3c79c14..502a778f 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -337,6 +337,11 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { void (float update) Menu_Class = { local entity timer; + if (TeamFortress_TeamIsCivilian(self.team_no)) { + Status_Print(self, "Your team can only be civilians\n"); + Menu_Close(self); + return; + } if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { //fte+csqc has its own class menu @@ -414,9 +419,9 @@ void (float update) Menu_Class = { // print out class menu self.menu_input = nil; - if (TeamFortress_TeamIsCivilian(self.team_no)) - Status_Print(self, "Your team can only be civilians\n"); - else +// if (TeamFortress_TeamIsCivilian(self.team_no)) +// Status_Print(self, "Your team can only be civilians\n"); +// else Status_Menu(self, Menu_Class_Input, s_select, s_scout, s_sniper, s_soldier, s_demoman, s_medic, s_hwguy, s_pyro, s_spy, s_engineer, s_randompc); strunzone(s_scout); strunzone(s_sniper); strunzone(s_soldier); strunzone(s_demoman); strunzone(s_medic); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 957b998b..6fa1d251 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -145,7 +145,7 @@ void (float inp) TeamFortress_ChangeClass = { if ((deathmatch != 3) && (!cb_prematch)) return; - if (self.playerclass == inp && !(self.tfstate & TFSTATE_RANDOMPC)) { + if (self.playerclass == inp && !(self.tfstate & TFSTATE_RANDOMPC) && self.nextpc == inp) { sprint(self, PRINT_HIGH, "You are already playing as a "); TeamFortress_PrintClassName(self, inp, 0); return; @@ -154,26 +154,30 @@ void (float inp) TeamFortress_ChangeClass = { return; } - if (TeamFortress_TeamIsCivilian(self.team_no)) { - sprint(self, PRINT_HIGH, "You cannot change class\n"); - return; - } - if (!IsLegalClass(inp) && !override_mapclasses) { - sprint(self, PRINT_HIGH, - "Your team cannot play that class\n"); - TeamFortress_DisplayLegalClasses(); - return; - } - if ((spy_off == 1) && (inp == 8)) { - sprint(self, PRINT_HIGH, - "The spy class has been disabled on the server by the administrator\n"); - return; - } - if (CF_ClassIsRestricted(self.team_no, inp)) { - sprint(self, PRINT_HIGH, - "Your team already has enough of that class\n"); - return; + + if(inp > 0) { + if (TeamFortress_TeamIsCivilian(self.team_no) && self.playerclass == PC_CIVILIAN) { + sprint(self, PRINT_HIGH, "You cannot change class\n"); + return; + } + if (!IsLegalClass(inp) && !override_mapclasses) { + sprint(self, PRINT_HIGH, + "Your team cannot play that class\n"); + TeamFortress_DisplayLegalClasses(); + return; + } + if ((spy_off == 1) && (inp == 8)) { + sprint(self, PRINT_HIGH, + "The spy class has been disabled on the server by the administrator\n"); + return; + } + if (CF_ClassIsRestricted(self.team_no, inp)) { + sprint(self, PRINT_HIGH, + "Your team already has enough of that class\n"); + return; + } } + self.nextpc = inp; if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint()) { self.has_changedclass = 1; @@ -221,7 +225,8 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_ExecClassScript(self); self.playerclass = inp; - self.nextpc = 0; + //self.nextpc = 0; + self.nextpc = inp; self.takedamage = 2; self.movetype = 3; self.flags = FL_CLIENT | FL_ONGROUND; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index b89d2a84..3b2ed91f 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -235,6 +235,26 @@ float (float tno) TeamFortress_TeamSet = { st = ftos(tc); stuffcmd(self, st); stuffcmd(self, "\n"); + if(self.playerclass == PC_CIVILIAN) { + if (TeamFortress_TeamIsCivilian(tno)) { + self.team_no = tno; + TeamFortress_ChangeClass(11); + } else { + TeamFortress_ChangeClass(0); + Menu_Class(0); + } + } else { + if (self.playerclass == 0) { + } else { + //Make sure the current class is still legal on the new team + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + if (CF_GetClassRestriction(tno, self.playerclass) == -1 || CF_ClassIsRestricted(tno, self.playerclass)) { + TeamFortress_ChangeClass(0); + Menu_Class(0); + } + + } + } self.team_no = tno; self.immune_to_check = time + 10; self.lives = TeamFortress_TeamGetLives(tno); @@ -245,10 +265,18 @@ float (float tno) TeamFortress_TeamSet = { TeamFortress_TeamShowMemberClasses(self); SetTeamName(self); if (self.playerclass == 0) { - if (TeamFortress_TeamIsCivilian(self.team_no)) { + if (TeamFortress_TeamIsCivilian(tno)) { + self.team_no = tno; TeamFortress_ChangeClass(11); } + } else { + // force to change class if class is forbidden on the new team + if (!IsLegalClass(self.playerclass) && !override_mapclasses) { + TeamFortress_ChangeClass(0); + Menu_Class(0); + } } + return (1); }; From 6cd1f09c29c381cc79df5a28f1cd444de30bd3df Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 9 Oct 2019 14:42:01 +1100 Subject: [PATCH 0819/2474] eng emp range revert --- share/defs.h | 2 +- ssqc/engineer.qc | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/share/defs.h b/share/defs.h index eeab7057..70858cec 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1084,7 +1084,7 @@ #define PC_ENGINEER_GRENADE_MAX_1 4 #define PC_ENGINEER_GRENADE_MAX_2 4 #define PC_ENGINEER_TF_ITEMS 0 -#define PC_ENGINEER_GRENADE_TYPE_2_OLDRANGE 240 +#define PC_ENGINEER_GRENADE_TYPE_2_RANGE 240 #define PC_ENGINEER_GRENADE_TYPE_2_NEWRANGE 180 // normal grenade range // Class Details for CIVILIAN diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index fa7655d8..357fbaf7 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -185,18 +185,8 @@ void () EMPGrenadeExplode = { } te2 = find(te2, classname, "info_empblock"); } - - float emprange; - if (new_emp) - { - emprange = PC_ENGINEER_GRENADE_TYPE_2_NEWRANGE; - } - else - { - emprange = PC_ENGINEER_GRENADE_TYPE_2_OLDRANGE; - } - - te = findradius(self.origin, emprange); + + te = findradius(self.origin, PC_ENGINEER_GRENADE_TYPE_2_RANGE); while (te) { te.chain2 = te.chain; candamage = TRUE; From 2f7d906799fe20fffae310c76c63e559c91819cc Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 9 Oct 2019 14:43:14 +1100 Subject: [PATCH 0820/2474] remove old def --- share/defs.h | 1 - 1 file changed, 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 70858cec..0f378c76 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1085,7 +1085,6 @@ #define PC_ENGINEER_GRENADE_MAX_2 4 #define PC_ENGINEER_TF_ITEMS 0 #define PC_ENGINEER_GRENADE_TYPE_2_RANGE 240 -#define PC_ENGINEER_GRENADE_TYPE_2_NEWRANGE 180 // normal grenade range // Class Details for CIVILIAN #define PC_CIVILIAN_SKIN 22 From 1493d3b950c2cdd7745543516554607113ce6ccd Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 9 Oct 2019 22:45:00 +1300 Subject: [PATCH 0821/2474] fixed percent sign on clipsize panel; fix out of bounds menus; send menu values for teams and classes --- csqc/csextradefs.qc | 1 + csqc/events.qc | 34 +++++++++++++++++++---- csqc/hud.qc | 2 ++ csqc/hud_helpers.qc | 12 +++++++- csqc/menu.qc | 67 ++++++++++++++++++++++++++++++--------------- csqc/sui_sys.qc | 6 ++-- share/commondefs.qc | 2 ++ ssqc/commands.qc | 4 +-- ssqc/menu.qc | 37 +++++++++++++++++++++++-- ssqc/tforttm.qc | 7 ++++- 10 files changed, 134 insertions(+), 38 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 23495200..ebf0e7c3 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -10,6 +10,7 @@ vector MENU_BUTTON = '0.3 0.4 0.5'; vector MENU_TEXT_1 = '1 1 1'; vector MENU_TEXT_2 = '0.7 0.75 0.75'; vector MENU_TEXT_3 = '1 1 0'; +vector MENU_TEXT_4 = '0.8 0.5 0'; vector MENU_HIGHLIGHT = '1 1 1'; vector MENU_DARKEN = '1 1 1'; diff --git a/csqc/events.qc b/csqc/events.qc index 054e7b6f..b683e620 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -107,19 +107,41 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_TEAM: number_of_teams = readfloat(); for(float i = 0; i < 4; i++) { - if(i < number_of_teams && (i + 1) != team_no) { - FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; - } else { - FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; - } + if(i < number_of_teams) { + FO_MENU_TEAM.options[i].value = ftos(readbyte()); + if((i + 1) != team_no) { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; + } + } } FO_Menu_Team(FALSE); break; case CLIENT_MENU_CLASS: - float allowedclasses = readfloat(); + //float civonly = readbyte(); + FO_Menu_Class(FALSE); break; } + break; + case MSG_CLASSES_UPDATE: + float civonly = readbyte(); + for(float i = 0; i < 10; i++) { + if(civonly) { + FO_MENU_CLASS.options[i].value = "-"; + } else { + float class_max = readfloat(); + if(class_max < 0) { + FO_MENU_CLASS.options[i].value = "-"; + FO_MENU_CLASS.options[i].state = FO_MENU_STATE_DISABLED; + } else { + FO_MENU_CLASS.options[i].value = strcat(ftos(readbyte()),"/",ftos(class_max)); + FO_MENU_CLASS.options[i].state = FO_MENU_STATE_NORMAL; + } + } + } + break; } } diff --git a/csqc/hud.qc b/csqc/hud.qc index 03769118..3d2d73f5 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -72,6 +72,8 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[i].NodeInsertLoc = nodeInsertLoc; //pnl.Name = name; } + //Default menus to centre of the screen + Hud_Panels[HUD_PANEL_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), height / 2 - Hud_Panels[HUD_PANEL_MENU].FillSize.y / 2]; } float GetTextAlignOffset(float pos, float iconsize, string text, float textsize, float align) { diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index a86bf42e..1c43c947 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -156,6 +156,10 @@ void Hud_DrawStringLMP(vector pos, string value, float size) // because i'm dodgy drawpic(pos + [i * size, 0, 0], "NUM_SLASH", vsize, '1 1 1', 1, 0); } + else if (c == 37) // "%" + { + drawpic(pos + [i * size, 0, 0], "num_percent", vsize, '1 1 1', 1, 0); + } else { drawpic(pos + [i * size, 0, 0], sprintf("num_%g", c-'0'), vsize, '1 1 1', 1, 0); @@ -266,7 +270,13 @@ void FO_Hud_Editor_LoadSettings() { // write a new file Hud_WriteCfg(FO_HUD_CONFIG_PATH); - } + } + if(Hud_Panels[HUD_PANEL_MENU].Position.x < 0) Hud_Panels[HUD_PANEL_MENU].Position.x = 10; + if(Hud_Panels[HUD_PANEL_MENU].Position.y < 0) Hud_Panels[HUD_PANEL_MENU].Position.y = 10; + if(Hud_Panels[HUD_PANEL_MENU].Position.x + Hud_Panels[HUD_PANEL_MENU].FillSize.x > vsize_x) Hud_Panels[HUD_PANEL_MENU].Position.x = vsize_x / 2 - Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2; + if(Hud_Panels[HUD_PANEL_MENU].Position.y + Hud_Panels[HUD_PANEL_MENU].FillSize.y > vsize_y) Hud_Panels[HUD_PANEL_MENU].Position.y = 64; + + } void GetNewPanel(vector pos, vector fillSize, float scale, float display, float nodeInsertLoc, string name) diff --git a/csqc/menu.qc b/csqc/menu.qc index cce8b5ab..372f187c 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -1,5 +1,7 @@ #define FO_MENU_FLAG_USE_MOUSE 1 #define FO_MENU_FLAG_CENTER 2 +#define FO_MENU_FLAG_SHOW_SHORTCUTS 4 +#define FO_MENU_FLAG_SHOW_VALUES 8 #define FO_MENU_STATE_HIDDEN 0 #define FO_MENU_STATE_NORMAL 1 @@ -23,7 +25,6 @@ typedef struct { fo_menu_option options[20]; float num_opts; float active; - //float alpha; } fo_menu; void FO_Menu_Team(float); @@ -33,7 +34,7 @@ fo_menu InProgressMenu; fo_menu CurrentMenu; var fo_menu FO_MENU_GAME = { - [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Select Team", "","",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, {"2","Select Class","","",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, {"3","Ready", "","",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, @@ -45,17 +46,17 @@ var fo_menu FO_MENU_GAME = { }, 8, TRUE }; var fo_menu FO_MENU_GAME_SPECTATOR = { - [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, {"2","Tracking Sidebar", "","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BUTTON}, {}, {"9","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - }, 6, TRUE + }, 5, TRUE }; var fo_menu FO_MENU_TEAM = { - [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { {"1","Blue team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, {"2","Red team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, @@ -65,7 +66,7 @@ var fo_menu FO_MENU_TEAM = { }, 6, TRUE }; var fo_menu FO_MENU_CLASS = { - [0,0], [300,200], "Select Class", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER, { + [0,0], [300,200], "Select Class", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { {"1","Scout","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 1\n");Menu_Cancel();},MENU_BUTTON}, {"2","Sniper","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 2\n");Menu_Cancel();},MENU_BUTTON}, {"3","Soldier","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 3\n");Menu_Cancel();},MENU_BUTTON}, @@ -119,7 +120,7 @@ vector fo_menu_draw(fo_menu menu) = { } else { position = menu.position; } - + if(fo_hud_editor) return position; if(!menu.active) { @@ -167,26 +168,25 @@ vector fo_menu_draw(fo_menu menu) = { ); for(float i = 0; i < menu.num_opts; i++) { + vector shortcutoffset = [0,0], valueoffset = [0,0]; + + if(menu.flags & FO_MENU_FLAG_SHOW_SHORTCUTS) { + shortcutoffset = [padding * 3 + smalltext.x, 0]; + } + if(menu.flags & FO_MENU_FLAG_SHOW_VALUES) { + valueoffset = [padding * 4 + smalltext.x * 1, 0]; + } + if(menu.options[i].state & FO_MENU_STATE_NORMAL) { if(menu.options[i].name) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext)) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + i * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_CENTER)) { menu.options[i].action(); } - if(menu.options[i].shortcut) { - drawstring( - position + [padding*3, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], - menu.options[i].shortcut, - smalltext, - MENU_TEXT_3, - 1, - 0 - ); - } } } else if(menu.options[i].state & FO_MENU_STATE_DISABLED) { if(menu.options[i].name) { - sui_border_box(position + [padding, titleoffset + i * (buttonsize.y + padding)], buttonsize, 1, MENU_BG, 0.4, 0); + sui_border_box(position + [padding, titleoffset + i * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); drawstring( position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], menu.options[i].name, @@ -198,6 +198,26 @@ vector fo_menu_draw(fo_menu menu) = { } } + if(menu.options[i].shortcut) { + drawstring( + position + [padding*2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + menu.options[i].shortcut, + smalltext, + MENU_TEXT_3, + 1, + 0 + ); + } + if(menu.options[i].value) { + drawstring( + position + [menusize.x - padding*4 - smalltext.x , titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + menu.options[i].value, + smalltext, + MENU_TEXT_4, + 1, + 0 + ); + } } return position; } @@ -207,11 +227,14 @@ float fo_menu_process_input(fo_menu menu, float scan) = { if(scan > 47 && scan < 58) { button = ftos(scan - 48); for(float i = 0; i < menu.num_opts; i++) { - if(menu.options[i].state & FO_MENU_STATE_NORMAL) { - if(menu.options[i].shortcut == button) { + if(menu.options[i].shortcut == button) { + if(menu.options[i].state & FO_MENU_STATE_NORMAL) { menu.options[i].action(); - return TRUE; } + //If a shortcut matches, always absorb it, even if disabled + //To avoid weird things like accidentally switching weapons + //While trying to pick a disabled option + return TRUE; } } } diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 8327f7a2..3227d735 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -935,7 +935,7 @@ void() sui_draw_bind_overlay = } }; -float(string id, vector pos, vector size, string text, vector colour, vector textsize) hud_colour_button = +float(string id, vector pos, vector size, string text, vector colour, vector textsize, float alignment) hud_colour_button = { sui_push_frame(pos, size); vector basecolor = sui_is_hovered(id) ? colour + MENU_HIGHLIGHT * 0.1 : colour; @@ -944,7 +944,7 @@ float(string id, vector pos, vector size, string text, vector colour, vector tex sui_fill([0, 0], size, basecolor, 0.6, 0); sui_border_box([0, 0], size, 1, bordercolour, 0.4, 0); - sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_set_align([alignment, SUI_ALIGN_CENTER]); sui_text([0, 0], textsize, text, MENU_TEXT_1, 1, 0); sui_action_element([0, 0], size, id, sui_noop); sui_pop_frame(); @@ -953,7 +953,7 @@ float(string id, vector pos, vector size, string text, vector colour, vector tex }; float(string id, vector pos, vector size, string text) hud_button = { - return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL); + return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL, SUI_ALIGN_CENTER); } diff --git a/share/commondefs.qc b/share/commondefs.qc index b8c3f343..12325e3e 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -7,6 +7,8 @@ #define MSG_GRENPRIMED 5 #define MSG_CLIENT_MENU 6 +#define MSG_TEAMS_UPDATE 7 +#define MSG_CLASSES_UPDATE 8 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index cfaaa09f..32c70d48 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -109,7 +109,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { // keep showing menu if class is invalid if (newclass > 10 || (!IsLegalClass(newclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, newclass)) { sprint(self, PRINT_HIGH, "Invalid class for this team!\n"); - UpdateClientMenu_Class(self); + Menu_Class(0); break; } @@ -126,7 +126,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { TeamFortress_ChangeClass(newclass); } else { - UpdateClientMenu_Class(self); + Menu_Class(0); } break; } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 502a778f..1c5df4db 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -194,15 +194,45 @@ void UpdateClientMenu_Team(entity pl) = { WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); WriteFloat(MSG_MULTICAST, CLIENT_MENU_TEAM); WriteFloat(MSG_MULTICAST, number_of_teams); + for(float i = 0; i < number_of_teams; i++) { + WriteByte(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(i+1)); + } + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientClasses(entity pl, float team) = { + local float civilian_team = TeamFortress_TeamIsCivilian(pl.team_no); + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLASSES_UPDATE); + WriteByte(MSG_MULTICAST, civilian_team); + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + if(!civilian_team) { + for(float i = 0; i < 10; i++) { + local float f_max = CF_GetClassRestriction(team, i+1); + local float f_players = CF_GetClassPlayers(team, i+1); + + if ((IsLegalClass(i+1) || override_mapclasses) && f_max >= 0) { + WriteFloat(MSG_MULTICAST, f_max); + WriteByte(MSG_MULTICAST, f_players); + } else { + WriteFloat(MSG_MULTICAST, -1); + } + } + } multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void UpdateClientMenu_Class(entity pl) = { + //local byte civilian_team = TeamFortress_TeamIsCivilian(pl.team_no); msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); WriteFloat(MSG_MULTICAST, CLIENT_MENU_CLASS); - WriteFloat(MSG_MULTICAST, number_of_teams); + //WriteByte(MSG_MULTICAST, civilian_team); + //if(!civilian_team) { + // WriteFloat(MSG_MULTICAST, number_of_teams); + //} multicast('0 0 0', MULTICAST_ONE_NOSPECS); } @@ -222,7 +252,7 @@ void (float update) Menu_Team = { } return; } - + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { //fte+csqc has its own team menu //ask the client to activate it @@ -338,7 +368,7 @@ string (float pf_class, string ps_class) Menu_Class_ClassString = { void (float update) Menu_Class = { local entity timer; if (TeamFortress_TeamIsCivilian(self.team_no)) { - Status_Print(self, "Your team can only be civilians\n"); + sprint(self, PRINT_HIGH, "Your team can only be civilians\n"); Menu_Close(self); return; } @@ -347,6 +377,7 @@ void (float update) Menu_Class = { //fte+csqc has its own class menu //ask the client to activate it Menu_Close(self); + UpdateClientClasses(self, self.team_no); UpdateClientMenu_Class(self); return; } diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 3b2ed91f..50441007 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -165,7 +165,7 @@ float (float tno) TeamFortress_TeamSet = { if (!CF_TeamIsValid) { return 0; } - + if (tno == 1) team = "blue team"; else if (tno == 2) @@ -175,6 +175,11 @@ float (float tno) TeamFortress_TeamSet = { else team = "green team"; + if (tno > 0 && tno == self.team_no) { + sprint(self, PRINT_HIGH, "You are already on the ", team, "!\n"); + return 0; + } + if (TeamFortress_TeamGetColor(tno) == 0) { TeamFortress_TeamSetColor(tno); if (TeamFortress_TeamGetColor(tno) == 0) { From f16728055a771834147c8006777a54e60bcc2724 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 9 Oct 2019 23:18:45 +1300 Subject: [PATCH 0822/2474] Add menu spacers to allow skipping invisible options (for variable menus) --- csqc/menu.qc | 93 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index 372f187c..d5f44758 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -6,6 +6,7 @@ #define FO_MENU_STATE_HIDDEN 0 #define FO_MENU_STATE_NORMAL 1 #define FO_MENU_STATE_DISABLED 2 +#define FO_MENU_STATE_SPACER 3 typedef struct { string shortcut; //key to press. if omitted - mouse only @@ -33,14 +34,16 @@ void Menu_Cancel() ; fo_menu InProgressMenu; fo_menu CurrentMenu; +fo_menu_option MenuSpacer = {"","","","",FO_MENU_STATE_SPACER}; + var fo_menu FO_MENU_GAME = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Select Team", "","",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, {"2","Select Class","","",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, - {"3","Ready", "","",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, - {}, + {"3","Ready","","",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, {"4","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, - {}, + MenuSpacer, {"9","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 8, TRUE @@ -49,7 +52,7 @@ var fo_menu FO_MENU_GAME_SPECTATOR = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, {"2","Tracking Sidebar", "","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BUTTON}, - {}, + MenuSpacer, {"9","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE @@ -61,7 +64,7 @@ var fo_menu FO_MENU_TEAM = { {"2","Red team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, {"4","Green team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 4\n");Menu_Cancel();},'0.4 0.7 0.3'}, - {}, + MenuSpacer, {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam auto\n");Menu_Cancel();},'0.4 0.4 0.4'}, }, 6, TRUE }; @@ -166,10 +169,18 @@ vector fo_menu_draw(fo_menu menu) = { 1, 0 ); - + float row = 0; for(float i = 0; i < menu.num_opts; i++) { vector shortcutoffset = [0,0], valueoffset = [0,0]; + if(menu.options[i].state == FO_MENU_STATE_HIDDEN) { + continue; + } + if(menu.options[i].state == FO_MENU_STATE_SPACER) { + row++; + continue; + } + if(menu.flags & FO_MENU_FLAG_SHOW_SHORTCUTS) { shortcutoffset = [padding * 3 + smalltext.x, 0]; } @@ -177,68 +188,70 @@ vector fo_menu_draw(fo_menu menu) = { valueoffset = [padding * 4 + smalltext.x * 1, 0]; } - if(menu.options[i].state & FO_MENU_STATE_NORMAL) { - if(menu.options[i].name) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + i * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_CENTER)) { + if(menu.options[i].name) { + if(menu.options[i].state == FO_MENU_STATE_NORMAL) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_CENTER)) { menu.options[i].action(); } + } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { + if(menu.options[i].name) { + sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); + drawstring( + position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], + menu.options[i].name, + smalltext, + MENU_TEXT_2, + 1, + 0 + ); + } + } - - } else if(menu.options[i].state & FO_MENU_STATE_DISABLED) { - if(menu.options[i].name) { - sui_border_box(position + [padding, titleoffset + i * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); + if(menu.options[i].shortcut) { drawstring( - position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], - menu.options[i].name, + position + [padding*2, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + menu.options[i].shortcut, smalltext, - MENU_TEXT_2, + MENU_TEXT_3, + 1, + 0 + ); + } + if(menu.options[i].value) { + drawstring( + position + [menusize.x - padding*4 - smalltext.x , titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + menu.options[i].value, + smalltext, + MENU_TEXT_4, 1, 0 ); } - - } - if(menu.options[i].shortcut) { - drawstring( - position + [padding*2, titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], - menu.options[i].shortcut, - smalltext, - MENU_TEXT_3, - 1, - 0 - ); - } - if(menu.options[i].value) { - drawstring( - position + [menusize.x - padding*4 - smalltext.x , titleoffset + i * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], - menu.options[i].value, - smalltext, - MENU_TEXT_4, - 1, - 0 - ); } + row++; } return position; } float fo_menu_process_input(fo_menu menu, float scan) = { local string button = ""; + local float found = FALSE; if(scan > 47 && scan < 58) { button = ftos(scan - 48); for(float i = 0; i < menu.num_opts; i++) { if(menu.options[i].shortcut == button) { - if(menu.options[i].state & FO_MENU_STATE_NORMAL) { + if(menu.options[i].state == FO_MENU_STATE_NORMAL) { menu.options[i].action(); } //If a shortcut matches, always absorb it, even if disabled //To avoid weird things like accidentally switching weapons //While trying to pick a disabled option - return TRUE; + found = TRUE; } } } - return FALSE; + //Trigger all of them + return found; } void Menu_Cancel() = { From d408848b41e35a866c3e8bc9d0371673440da6aa Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 10 Oct 2019 08:41:37 +1300 Subject: [PATCH 0823/2474] make menu buttons look better --- csqc/menu.qc | 14 ++++++++------ csqc/sui_sys.qc | 9 ++++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index d5f44758..bd22fd8e 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -59,7 +59,7 @@ var fo_menu FO_MENU_GAME_SPECTATOR = { }; var fo_menu FO_MENU_TEAM = { - [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { + [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Blue team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, {"2","Red team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, @@ -182,7 +182,7 @@ vector fo_menu_draw(fo_menu menu) = { } if(menu.flags & FO_MENU_FLAG_SHOW_SHORTCUTS) { - shortcutoffset = [padding * 3 + smalltext.x, 0]; + shortcutoffset = [padding * 4 + smalltext.x, 0]; } if(menu.flags & FO_MENU_FLAG_SHOW_VALUES) { valueoffset = [padding * 4 + smalltext.x * 1, 0]; @@ -190,12 +190,14 @@ vector fo_menu_draw(fo_menu menu) = { if(menu.options[i].name) { if(menu.options[i].state == FO_MENU_STATE_NORMAL) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_CENTER)) { + //if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, padding * 3 + smalltext.x)) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, shortcutoffset.x)) { menu.options[i].action(); } } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { if(menu.options[i].name) { - sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); + //sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); + sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, 1, MENU_BG, 0.4, 0); drawstring( position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], menu.options[i].name, @@ -209,7 +211,7 @@ vector fo_menu_draw(fo_menu menu) = { } if(menu.options[i].shortcut) { drawstring( - position + [padding*2, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + position + [padding*3, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], menu.options[i].shortcut, smalltext, MENU_TEXT_3, @@ -219,7 +221,7 @@ vector fo_menu_draw(fo_menu menu) = { } if(menu.options[i].value) { drawstring( - position + [menusize.x - padding*4 - smalltext.x , titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + position + [menusize.x - padding*4 - stringwidth(menu.options[i].value,1,smalltext) , titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], menu.options[i].value, smalltext, MENU_TEXT_4, diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 3227d735..a0f674f0 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -935,7 +935,7 @@ void() sui_draw_bind_overlay = } }; -float(string id, vector pos, vector size, string text, vector colour, vector textsize, float alignment) hud_colour_button = +float(string id, vector pos, vector size, string text, vector colour, vector textsize, float alignment, float padding) hud_colour_button = { sui_push_frame(pos, size); vector basecolor = sui_is_hovered(id) ? colour + MENU_HIGHLIGHT * 0.1 : colour; @@ -945,7 +945,10 @@ float(string id, vector pos, vector size, string text, vector colour, vector tex sui_border_box([0, 0], size, 1, bordercolour, 0.4, 0); sui_set_align([alignment, SUI_ALIGN_CENTER]); - sui_text([0, 0], textsize, text, MENU_TEXT_1, 1, 0); + if(!padding && alignment == SUI_ALIGN_START) { + padding = 4; + } + sui_text([padding, 0], textsize, text, MENU_TEXT_1, 1, 0); sui_action_element([0, 0], size, id, sui_noop); sui_pop_frame(); @@ -953,7 +956,7 @@ float(string id, vector pos, vector size, string text, vector colour, vector tex }; float(string id, vector pos, vector size, string text) hud_button = { - return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL, SUI_ALIGN_CENTER); + return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL, SUI_ALIGN_CENTER, 0); } From b1a37581bc516e7f4d3550295f459c17535bd7f1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 12 Oct 2019 00:44:41 +1300 Subject: [PATCH 0824/2474] fix some menus; fix class select menu popping up when rejoining clan game --- csqc/menu.qc | 118 +++++++++++++++++++++++++---------------------- ssqc/client.qc | 13 ++++-- ssqc/commands.qc | 3 +- ssqc/tforthlp.qc | 5 +- ssqc/tforttm.qc | 58 +++++++++++++---------- 5 files changed, 108 insertions(+), 89 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index bd22fd8e..b2b3b2e1 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -44,18 +44,16 @@ var fo_menu FO_MENU_GAME = { MenuSpacer, {"4","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, MenuSpacer, - {"9","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, - {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - }, 8, TRUE + {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, + }, 7, TRUE }; var fo_menu FO_MENU_GAME_SPECTATOR = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, {"2","Tracking Sidebar", "","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BUTTON}, MenuSpacer, - {"9","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, - {"0","Return to Game","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - }, 5, TRUE + {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, + }, 4, TRUE }; var fo_menu FO_MENU_TEAM = { @@ -65,8 +63,10 @@ var fo_menu FO_MENU_TEAM = { {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, {"4","Green team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 4\n");Menu_Cancel();},'0.4 0.7 0.3'}, MenuSpacer, - {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam auto\n");Menu_Cancel();},'0.4 0.4 0.4'}, - }, 6, TRUE + {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam auto\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"0","Spectate","","",FO_MENU_STATE_NORMAL,{localcmd("observe\n");Menu_Cancel();},MENU_BUTTON}, + }, 8, TRUE }; var fo_menu FO_MENU_CLASS = { [0,0], [300,200], "Select Class", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { @@ -174,63 +174,63 @@ vector fo_menu_draw(fo_menu menu) = { vector shortcutoffset = [0,0], valueoffset = [0,0]; if(menu.options[i].state == FO_MENU_STATE_HIDDEN) { - continue; - } - if(menu.options[i].state == FO_MENU_STATE_SPACER) { + //continue; + } else if(menu.options[i].state == FO_MENU_STATE_SPACER) { row++; - continue; - } - - if(menu.flags & FO_MENU_FLAG_SHOW_SHORTCUTS) { - shortcutoffset = [padding * 4 + smalltext.x, 0]; - } - if(menu.flags & FO_MENU_FLAG_SHOW_VALUES) { - valueoffset = [padding * 4 + smalltext.x * 1, 0]; - } - - if(menu.options[i].name) { - if(menu.options[i].state == FO_MENU_STATE_NORMAL) { - //if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, padding * 3 + smalltext.x)) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, shortcutoffset.x)) { - menu.options[i].action(); + //continue; + } else { + if(menu.flags & FO_MENU_FLAG_SHOW_SHORTCUTS) { + shortcutoffset = [padding * 4 + smalltext.x, 0]; + } + if(menu.flags & FO_MENU_FLAG_SHOW_VALUES) { + valueoffset = [padding * 4 + smalltext.x * 1, 0]; + } + + if(menu.options[i].name) { + if(menu.options[i].state == FO_MENU_STATE_NORMAL) { + //if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, padding * 3 + smalltext.x)) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, shortcutoffset.x)) { + menu.options[i].action(); + } + } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { + if(menu.options[i].name) { + //sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); + sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, 1, MENU_BG, 0.4, 0); + drawstring( + position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], + menu.options[i].name, + smalltext, + MENU_TEXT_2, + 1, + 0 + ); + } + } - } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { - if(menu.options[i].name) { - //sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); - sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, 1, MENU_BG, 0.4, 0); + if(menu.options[i].shortcut) { drawstring( - position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], - menu.options[i].name, + position + [padding*3, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + menu.options[i].shortcut, smalltext, - MENU_TEXT_2, + MENU_TEXT_3, + 1, + 0 + ); + } + if(menu.options[i].value) { + drawstring( + position + [menusize.x - padding*4 - stringwidth(menu.options[i].value,1,smalltext) , titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], + menu.options[i].value, + //strcat(ftos(row),"/",ftos(i)), + smalltext, + MENU_TEXT_4, 1, 0 ); } - - } - if(menu.options[i].shortcut) { - drawstring( - position + [padding*3, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], - menu.options[i].shortcut, - smalltext, - MENU_TEXT_3, - 1, - 0 - ); - } - if(menu.options[i].value) { - drawstring( - position + [menusize.x - padding*4 - stringwidth(menu.options[i].value,1,smalltext) , titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (smalltext.y / 2)], - menu.options[i].value, - smalltext, - MENU_TEXT_4, - 1, - 0 - ); } + row++; } - row++; } return position; } @@ -292,9 +292,15 @@ void FO_Menu_Team(float force) = { if(number_of_teams < 2) { return; } + //Hide autoteam option FO_MENU_TEAM.num_opts = number_of_teams; + //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_HIDDEN; + //FO_MENU_TEAM.options[5].state = FO_MENU_STATE_HIDDEN; } else { - FO_MENU_TEAM.num_opts = 6; + //Show autoteam option + FO_MENU_TEAM.num_opts = 8; + //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_NORMAL; + //FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; } CurrentMenu = FO_MENU_TEAM; fo_hud_menu_active = TRUE; diff --git a/ssqc/client.qc b/ssqc/client.qc index c5077f48..19f0daf5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -61,6 +61,7 @@ float () GetLastWeaponImpulse; float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; +float (float tno, float skipclasscheck) TeamFortress_TeamSet_Options; string nextmap; @@ -1094,8 +1095,8 @@ void () RemovePlayerOwnedEnts = { te.real_frags = self.real_frags; te.netname = self.netname; te.playerclass = self.playerclass; - if (self.tfstate & 8) { - te.tfstate = 8; + if (self.tfstate & TFSTATE_RANDOMPC) { + te.tfstate = TFSTATE_RANDOMPC; } } } @@ -1509,7 +1510,7 @@ void () PutClientInServer = { self.immune_to_check = time + 10; self.fire_held_down = 0; - if (! self.last_playerclass) + if (self.last_playerclass == 0) self.last_playerclass = self.playerclass; // remove prime timers to avoid getting an old grenade in your face @@ -1526,7 +1527,9 @@ void () PutClientInServer = { TeamFortress_ChangeClass(11); } if (deathmatch == 3) { - self.playerclass = self.nextpc; + if(self.nextpc) { + self.playerclass = self.nextpc; + } if (self.playerclass == PC_RANDOM) self.tfstate = self.tfstate | TFSTATE_RANDOMPC; else { @@ -2356,7 +2359,7 @@ void (optional float csqcactive) ClientConnect = { while (te) { if (te.tf_id == self.tf_id) { got_one = 1; - TeamFortress_TeamSet(te.team_no); + TeamFortress_TeamSet_Options(te.team_no, TRUE); self.frags = te.frags; self.real_frags = te.real_frags; if (!(toggleflags & TFLAG_TEAMFRAGS) && diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 32c70d48..9b4bbe32 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -87,7 +87,8 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } sprint(self, PRINT_HIGH, "Invalid team choice. Please use values 1-",number_of_teams?ftos(number_of_teams):"4",self.team_no?"":" or 'auto'",".\n"); } else { - UpdateClientMenu_Team(self); + //UpdateClientMenu_Team(self); + Menu_Team(0); } break; case "changeclass": diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 4dbf8fa3..c40452c6 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -26,8 +26,9 @@ void () TeamFortress_MOTD = { if (self.motd == 5) { if(csqcactive) { - //UpdateClientMenu_Team(self); - Menu_Team(0); + if(self.team_no == 0) { + Menu_Team(0); + } } else { sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 50441007..aa3e2a72 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -154,7 +154,7 @@ float (float tno) CF_TeamIsValid = { return 1; } -float (float tno) TeamFortress_TeamSet = { +float (float tno, float skipclasscheck) TeamFortress_TeamSet_Options = { local string st; local float tc; local string team; @@ -240,24 +240,26 @@ float (float tno) TeamFortress_TeamSet = { st = ftos(tc); stuffcmd(self, st); stuffcmd(self, "\n"); - if(self.playerclass == PC_CIVILIAN) { - if (TeamFortress_TeamIsCivilian(tno)) { - self.team_no = tno; - TeamFortress_ChangeClass(11); - } else { - TeamFortress_ChangeClass(0); - Menu_Class(0); - } - } else { - if (self.playerclass == 0) { - } else { - //Make sure the current class is still legal on the new team - override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); - if (CF_GetClassRestriction(tno, self.playerclass) == -1 || CF_ClassIsRestricted(tno, self.playerclass)) { + if(!skipclasscheck) { + if(self.playerclass == PC_CIVILIAN) { + if (TeamFortress_TeamIsCivilian(tno)) { + self.team_no = tno; + TeamFortress_ChangeClass(11); + } else { TeamFortress_ChangeClass(0); Menu_Class(0); } + } else { + if (self.playerclass == 0) { + } else { + //Make sure the current class is still legal on the new team + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + if (CF_GetClassRestriction(tno, self.playerclass) == -1 || CF_ClassIsRestricted(tno, self.playerclass)) { + TeamFortress_ChangeClass(0); + Menu_Class(0); + } + } } } self.team_no = tno; @@ -269,22 +271,28 @@ float (float tno) TeamFortress_TeamSet = { } TeamFortress_TeamShowMemberClasses(self); SetTeamName(self); - if (self.playerclass == 0) { - if (TeamFortress_TeamIsCivilian(tno)) { - self.team_no = tno; - TeamFortress_ChangeClass(11); - } - } else { - // force to change class if class is forbidden on the new team - if (!IsLegalClass(self.playerclass) && !override_mapclasses) { - TeamFortress_ChangeClass(0); - Menu_Class(0); + if(!skipclasscheck) { + if (self.playerclass == 0) { + if (TeamFortress_TeamIsCivilian(tno)) { + self.team_no = tno; + TeamFortress_ChangeClass(11); + } + } else { + // force to change class if class is forbidden on the new team + if (!IsLegalClass(self.playerclass) && !override_mapclasses) { + TeamFortress_ChangeClass(0); + Menu_Class(0); + } } } return (1); }; +float (float tno) TeamFortress_TeamSet = { + return TeamFortress_TeamSet_Options(tno, FALSE); +} + void () TeamFortress_CheckTeamCheats = { local string st; local string sk; From df8eb0ec24ee781232879b34126328f60cb8f7a3 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 12 Oct 2019 23:06:33 +1300 Subject: [PATCH 0825/2474] dropammo menu; also fixed no-mouse-menu input logic --- csqc/events.qc | 6 +++++ csqc/input.qc | 5 ++-- csqc/menu.qc | 59 +++++++++++++++++++++++++++++++++++++++++---- share/commondefs.qc | 1 + ssqc/commands.qc | 13 ++++++++++ ssqc/menu.qc | 49 +++++++++++++++++++++++++++++++++---- 6 files changed, 121 insertions(+), 12 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index b683e620..c3b22b43 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -123,6 +123,12 @@ void() CSQC_Parse_Event = { FO_Menu_Class(FALSE); break; + case CLIENT_MENU_DROPAMMO: + float ammotypes = readfloat(); + float ammomakes = readfloat(); + + FO_Menu_DropAmmo(FALSE, ammotypes, ammomakes); + break; } break; case MSG_CLASSES_UPDATE: diff --git a/csqc/input.qc b/csqc/input.qc index cc3998c8..fc6d79b3 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -4,6 +4,7 @@ void FO_Menu_Game(float); float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { float used = sui_input_event(evtype, scanx, chary, devid); //if(evtype == IE_KEYUP) print("Key up: ", ftos(scanx), ", char: ", ftos(chary), "\n"); + float menu_mouse = (fo_hud_menu_active && (CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)); if (fo_hud_editor || fo_hud_menu_active) { switch (evtype) @@ -49,11 +50,11 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } break; case IE_MOUSEDELTA: - return TRUE; + return (fo_hud_editor || menu_mouse); case IE_MOUSEABS: Mouse.x = scanx; Mouse.y = chary; - return TRUE; + return (fo_hud_editor || menu_mouse); default: } } else { diff --git a/csqc/menu.qc b/csqc/menu.qc index b2b3b2e1..f7d83786 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -82,6 +82,16 @@ var fo_menu FO_MENU_CLASS = { {"0","Random Playerclass","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 10\n");Menu_Cancel();},MENU_BUTTON}, }, 10, TRUE }; +var fo_menu FO_MENU_DROPAMMO = { + [0,0], [300,150], "Drop Ammo", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { + {"1","Shells","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dropammo 1\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Nails","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dropammo 2\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Rockets","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dropammo 3\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Cells","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dropammo 4\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 6, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; @@ -130,9 +140,7 @@ vector fo_menu_draw(fo_menu menu) = { setcursormode(FALSE); return position; } - if(menu.flags & FO_MENU_FLAG_USE_MOUSE) { - setcursormode(TRUE); - } + setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); local float scale = Hud_Panels[HUD_PANEL_MENU].Scale, textscale = Hud_Panels[HUD_PANEL_MENU].TextScale; if(!textscale) { textscale = scale; @@ -144,6 +152,7 @@ vector fo_menu_draw(fo_menu menu) = { local vector smalltext = MENU_TEXT_SMALL * textscale, mediumtext = MENU_TEXT_MEDIUM * textscale; local string id = strcat("fo_menu_",menu.title); local vector tempcolour; + local float alignment = SUI_ALIGN_START; menusize.y = titleoffset + menu.num_opts * (buttonsize.y + padding); @@ -189,15 +198,21 @@ vector fo_menu_draw(fo_menu menu) = { if(menu.options[i].name) { if(menu.options[i].state == FO_MENU_STATE_NORMAL) { //if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, padding * 3 + smalltext.x)) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, shortcutoffset.x)) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, alignment, shortcutoffset.x)) { menu.options[i].action(); } } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { if(menu.options[i].name) { //sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, 1, MENU_BG, 0.4, 0); + float disabledtextoffset = 0; + if(alignment == SUI_ALIGN_START) { + disabledtextoffset = padding + shortcutoffset.x; + } else { + padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2; //Centered + } drawstring( - position + [padding + (buttonsize.x / 2) - stringwidth(menu.options[i].name,1,smalltext) / 2, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], + position + [disabledtextoffset, titleoffset + row * (buttonsize.y + padding) + (buttonsize.y / 2) - (MENU_TEXT_SMALL.y / 2)], menu.options[i].name, smalltext, MENU_TEXT_2, @@ -312,3 +327,37 @@ void FO_Menu_Class(float force) = { CurrentMenu = FO_MENU_CLASS; fo_hud_menu_active = TRUE; } + +void FO_Menu_DropAmmo(float force, float ammotypes, float ammomakes) { + if(fo_hud_menu_active && !force) + return; + if(!ammotypes) { + Menu_Cancel(); + } + if(ammomakes) { + FO_MENU_DROPAMMO.title = "Drop or Make Ammo"; + } else { + FO_MENU_DROPAMMO.title = "Drop Ammo"; + } + for(float i = 0; i < 4; i++) { + if(ammotypes & pow(2,i)) { + FO_MENU_DROPAMMO.options[i].state = FO_MENU_STATE_NORMAL; + } else { + if(ammomakes & pow(2,i)) { + FO_MENU_DROPAMMO.options[i].value = "(make)"; + FO_MENU_DROPAMMO.options[i].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_DROPAMMO.options[i].value = ""; + FO_MENU_DROPAMMO.options[i].state = FO_MENU_STATE_DISABLED; + } + } + if(ammomakes & pow(2,i)) { + FO_MENU_DROPAMMO.options[i].value = "(make)"; + } else { + FO_MENU_DROPAMMO.options[i].value = ""; + } + } + + CurrentMenu = FO_MENU_DROPAMMO; + fo_hud_menu_active = TRUE; +} diff --git a/share/commondefs.qc b/share/commondefs.qc index 12325e3e..a27af7e4 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -22,3 +22,4 @@ #define CLIENT_MENU_TEAM 1 #define CLIENT_MENU_CLASS 2 +#define CLIENT_MENU_DROPAMMO 3 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 9b4bbe32..1314d33f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -130,6 +130,19 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Class(0); } break; + case "dropammo": + processedCmd = TRUE; + if (arg2) { + if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { + float inp = stof(arg2); + TeamFortress_DropAmmo(inp); + Menu_Drop(); + break; + } + sprint(self, PRINT_HIGH, "Invalid team choice. Please use values 1-4.\n"); + } + Menu_Drop(); + break; } if (self.is_admin) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 1c5df4db..5bee50ba 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -224,15 +224,20 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { - //local byte civilian_team = TeamFortress_TeamIsCivilian(pl.team_no); msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); WriteFloat(MSG_MULTICAST, CLIENT_MENU_CLASS); - //WriteByte(MSG_MULTICAST, civilian_team); - //if(!civilian_team) { - // WriteFloat(MSG_MULTICAST, number_of_teams); - //} + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_DropAmmo(entity pl, float ammotypes, float ammomakes) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_DROPAMMO); + WriteFloat(MSG_MULTICAST, ammotypes); + WriteFloat(MSG_MULTICAST, ammomakes); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } @@ -479,6 +484,38 @@ void () Menu_Drop = { return; } + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + float ammotypes = (1 | 2 | 4 | 8), ammomakes = 0; + if (self.ammo_shells < DROP_SHELLS) + ammotypes -= 1; + if (self.ammo_nails < DROP_NAILS) + ammotypes -= 2; + if (self.ammo_rockets < DROP_ROCKETS) + ammotypes -= 4; + if (self.ammo_cells < DROP_CELLS) + ammotypes -= 8; + + if (self.playerclass == PC_ENGINEER) { + ammomakes = 0; + if ((self.ammo_shells < DROP_SHELLS) && ((self.ammo_cells / AMMO_COST_SHELLS) >= (DROP_SHELLS - self.ammo_shells))) + ammomakes += 1; + if ((self.ammo_nails < DROP_NAILS) && ((self.ammo_cells / AMMO_COST_NAILS) >= (DROP_NAILS - self.ammo_nails))) + ammomakes += 2; + if ((self.ammo_rockets < DROP_ROCKETS) && ((self.ammo_cells / AMMO_COST_ROCKETS) >= (DROP_ROCKETS - self.ammo_rockets))) + ammomakes += 4; + } + + Menu_Close(self); + if(ammotypes) { + UpdateClientMenu_DropAmmo(self, ammotypes, ammomakes); + } else { + sprint(self, PRINT_HIGH, "Not enough ammo\n"); + } + return; + } + if (self.ammo_shells < DROP_SHELLS) s_shells = "\n"; if (self.ammo_nails < DROP_NAILS) @@ -502,6 +539,8 @@ void () Menu_Drop = { if (s_shells == "\n" && s_nails == "\n" && s_rockets == "\n" && s_cells == "\n") return; + + self.menu_input = nil; if (self.playerclass == PC_ENGINEER) s_drop = "Drop or make:\n\n"; From 5f464627fea5e8ac1e11b2b0dc06c13261e75bd8 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 13 Oct 2019 21:51:56 +1300 Subject: [PATCH 0826/2474] Scout scanner menu --- csqc/events.qc | 6 ++++++ csqc/menu.qc | 21 +++++++++++++++++++++ share/commondefs.qc | 2 ++ share/defs.h | 3 ++- ssqc/commands.qc | 46 ++++++++++++++++++++++++++++++++++++++++++--- ssqc/menu.qc | 18 ++++++++++++++++++ 6 files changed, 92 insertions(+), 4 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index c3b22b43..2d658aa0 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -129,6 +129,12 @@ void() CSQC_Parse_Event = { FO_Menu_DropAmmo(FALSE, ammotypes, ammomakes); break; + case CLIENT_MENU_SCOUT: + float scanner_on = readbyte(); + float scanner_flags = readfloat(); + + FO_Menu_Scout(FALSE, scanner_on, scanner_flags); + break; } break; case MSG_CLASSES_UPDATE: diff --git a/csqc/menu.qc b/csqc/menu.qc index f7d83786..489e59c9 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -92,6 +92,16 @@ var fo_menu FO_MENU_DROPAMMO = { {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 6, TRUE }; +var fo_menu FO_MENU_SCOUT = { + [0,0], [300,150], "Scanner", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { + {"1","Scanner","","",FO_MENU_STATE_NORMAL,{localcmd("cmd autoscan\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Scan for enemies","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scane\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Scan for friendlies","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scanf\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Scan sound","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scansound\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 6, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; @@ -361,3 +371,14 @@ void FO_Menu_DropAmmo(float force, float ammotypes, float ammomakes) { CurrentMenu = FO_MENU_DROPAMMO; fo_hud_menu_active = TRUE; } + +void FO_Menu_Scout(float force, float scanner_on, float scanner_flags) = { + if(fo_hud_menu_active && !force) + return; + FO_MENU_SCOUT.options[0].value = (scanner_on?"on":"off"); + FO_MENU_SCOUT.options[1].value = ((scanner_flags & 1)?"on":"off"); + FO_MENU_SCOUT.options[2].value = ((scanner_flags & 2)?"on":"off"); + FO_MENU_SCOUT.options[3].value = ((scanner_flags & 4)?"on":"off"); + CurrentMenu = FO_MENU_SCOUT; + fo_hud_menu_active = TRUE; +} diff --git a/share/commondefs.qc b/share/commondefs.qc index a27af7e4..1f2713ee 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -23,3 +23,5 @@ #define CLIENT_MENU_TEAM 1 #define CLIENT_MENU_CLASS 2 #define CLIENT_MENU_DROPAMMO 3 +#define CLIENT_MENU_SCOUT 4 + diff --git a/share/defs.h b/share/defs.h index eeab7057..f12d341c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -781,7 +781,8 @@ /*======================================================*/ #define NIT_SCANNER_ENEMY 1 // Detect enemies #define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) -#define NIT_SCANNER_MOVEMENT 4 // Motion detection. Only report moving entities. +//#define NIT_SCANNER_MOVEMENT 4 // Motion detection. Only report moving entities. +#define NIT_SCANNER_SOUND 4 // Scanner makes a sound /*======================================================*/ /* New Item Related Defines */ diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1314d33f..3941e3e1 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1,5 +1,5 @@ float (string arg1, string arg2, string arg3) ParseCmds = { - local float arg_num, processedCmd; + local float arg_num, processedCmd, inp; local string tmp; processedCmd = FALSE; @@ -134,7 +134,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; if (arg2) { if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { - float inp = stof(arg2); + inp = stof(arg2); TeamFortress_DropAmmo(inp); Menu_Drop(); break; @@ -143,7 +143,47 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } Menu_Drop(); break; - } + case "dropammo": + processedCmd = TRUE; + if (arg2) { + if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { + inp = stof(arg2); + TeamFortress_DropAmmo(inp); + Menu_Drop(); + break; + } + sprint(self, PRINT_HIGH, "Invalid team choice. Please use values 1-4.\n"); + } + Menu_Drop(); + break; + case "menu": + switch(self.playerclass) { + case PC_SCOUT: + Menu_Scout(); + break; + } + break; + case "autoscan": + if(self.playerclass == PC_SCOUT) { + ScannerSwitch(); + } + break; + case "scansound": + if(self.playerclass == PC_SCOUT) { + self.impulse = TF_SCAN_SOUND; + } + break; + case "scanf": + if(self.playerclass == PC_SCOUT) { + self.impulse = TF_SCAN_FRIENDLY; + } + break; + case "scane": + if(self.playerclass == PC_SCOUT) { + self.impulse = TF_SCAN_ENEMY; + } + break; + } if (self.is_admin) { diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 5bee50ba..ca261506 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -241,6 +241,16 @@ void UpdateClientMenu_DropAmmo(entity pl, float ammotypes, float ammomakes) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMenu_Scout(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_SCOUT); + WriteByte(MSG_MULTICAST, pl.ScannerOn); + WriteFloat(MSG_MULTICAST, pl.tf_items_flags); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void (float update) Menu_Team = { local entity timer; @@ -567,6 +577,14 @@ void () Menu_Scout = { local string s_scan, s_scane, s_scanf, s_scansound; local string s_nothing = Q"\n\s[5]\s Nothing \n\n"; + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Scout(self); + return; + } + if (!self.ScannerOn) s_scan = Q"\s[1]\s Turn Scanner on \n"; else From 74c1dbce3d2c79d8a17f9144c0175e62239a611b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 17 Oct 2019 19:20:23 +1300 Subject: [PATCH 0827/2474] fix team menu; fix clan mode reconnect menu; fix team changes to illegal classes; play with classes as menu definitions --- csqc/csextradefs.qc | 1 + csqc/events.qc | 2 ++ csqc/menu.qc | 68 +++++++++++++++++++++++++++++++++++++++++++++ share/commondefs.qc | 7 ++++- ssqc/client.qc | 4 ++- ssqc/commands.qc | 48 ++++++++++++++++++++++++++++++-- ssqc/menu.qc | 19 +++++++++++++ 7 files changed, 144 insertions(+), 5 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index ebf0e7c3..d02c015a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -20,6 +20,7 @@ vector MENU_TEXT_LARGE = '24 24 0'; float MENU_START_CONTENT = 32; .float owned_by; +.string netname; float fo_hud_editor; float fo_hud_menu_active; float jumptime; diff --git a/csqc/events.qc b/csqc/events.qc index 2d658aa0..757dfc39 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -114,6 +114,8 @@ void() CSQC_Parse_Event = { } else { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; } + } else { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; } } FO_Menu_Team(FALSE); diff --git a/csqc/menu.qc b/csqc/menu.qc index 489e59c9..eefc4c8f 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -8,6 +8,28 @@ #define FO_MENU_STATE_DISABLED 2 #define FO_MENU_STATE_SPACER 3 +class fo_menu_option_2 { + string shortcut; //key to press. if omitted - mouse only + string name; //what to display + string value; //optional - displays current value/state + string description; //optional + float state; //active/disabled + virtual void() action = {}; + vector colour; + fo_menu_option_2 next; +}; + +class fo_menu_2 { + vector position; + vector size; + string title; + float flags; + fo_menu_option_2 options; + float num_opts; + float active; +}; + + typedef struct { string shortcut; //key to press. if omitted - mouse only string name; //what to display @@ -55,6 +77,11 @@ var fo_menu FO_MENU_GAME_SPECTATOR = { {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, }, 4, TRUE }; +var fo_menu FO_MENU_SPECTATOR_TRACK = { + [0,0], [300,200], "Track", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("track 1\n"); },MENU_BUTTON}, + }, 0, TRUE +}; var fo_menu FO_MENU_TEAM = { [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { @@ -102,6 +129,18 @@ var fo_menu FO_MENU_SCOUT = { {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 6, TRUE }; +//var fo_menu_option FO_MENU_SPY; +var fo_menu FO_MENU_SPY = { + [0,0], [300,150], "Spy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { + {"1","Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Become Invisible","","",FO_MENU_STATE_NORMAL,{localcmd("cmd autoscan\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Scan for enemies","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scane\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Scan for friendlies","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scanf\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Scan sound","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scansound\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 6, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; @@ -265,6 +304,17 @@ float fo_menu_process_input(fo_menu menu, float scan) = { local float found = FALSE; if(scan > 47 && scan < 58) { button = ftos(scan - 48); + } else { + switch(scan) { + case 45: + button = "-"; + break; + case 61: + button = "+"; + break; + } + } + if(button != "") { for(float i = 0; i < menu.num_opts; i++) { if(menu.options[i].shortcut == button) { if(menu.options[i].state == FO_MENU_STATE_NORMAL) { @@ -310,6 +360,24 @@ void FO_Menu_Game(float force) = { fo_hud_menu_active = TRUE; } +void FO_Menu_Track() = { + if(!is_spectator) + return; + + local float i = 0; + local entity e = find(world, classname, "player"); + while(e) { + if(i > 19) break; + FO_MENU_SPECTATOR_TRACK.options[i].name = e.netname; + FO_MENU_SPECTATOR_TRACK.options[i].shortcut = ftos(i+1); + //FO_MENU_SPECTATOR_TRACK.options[i].action = void(){}; + i++; + e = find(e, classname, "player"); + } + FO_MENU_SPECTATOR_TRACK.num_opts = i; + FO_MENU_SPECTATOR_TRACK.position = fo_menu_draw(FO_MENU_SPECTATOR_TRACK); +} + void FO_Menu_Team(float force) = { if(fo_hud_menu_active && !force) return; diff --git a/share/commondefs.qc b/share/commondefs.qc index 1f2713ee..90000ea9 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -3,7 +3,7 @@ #define MSG_FLAGINFOINIT 1 #define MSG_FLAGINFO 2 -#define MSG_SBAR 4 +#define MSG_SBAR 4 #define MSG_GRENPRIMED 5 #define MSG_CLIENT_MENU 6 @@ -20,8 +20,13 @@ #define FLAGINFO_ICON_FLAG 0 #define FLAGINFO_ICON_BUTTON 1 +#define MSG_MENU_SPY_FLAG_IVIS_ONLY 1 +#define MSG_MENU_SPY_FLAG_UNDERCOVER 2 +#define MSG_MENU_SPY_FLAG_FEIGNING 4 + #define CLIENT_MENU_TEAM 1 #define CLIENT_MENU_CLASS 2 #define CLIENT_MENU_DROPAMMO 3 #define CLIENT_MENU_SCOUT 4 +#define CLIENT_MENU_SPY 5 diff --git a/ssqc/client.qc b/ssqc/client.qc index 19f0daf5..defe540d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1527,7 +1527,8 @@ void () PutClientInServer = { TeamFortress_ChangeClass(11); } if (deathmatch == 3) { - if(self.nextpc) { + sprint(self, PRINT_HIGH, "MEHT: nextpc: ", ftos(self.nextpc), ", pc: ", ftos(self.playerclass), "\n"); + if(self.nextpc != self.playerclass) { self.playerclass = self.nextpc; } if (self.playerclass == PC_RANDOM) @@ -2367,6 +2368,7 @@ void (optional float csqcactive) ClientConnect = { self.frags = self.real_frags; } self.playerclass = te.playerclass; + self.nextpc = te.playerclass; self.tfstate = te.tfstate; dremove(te); te = world; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 3941e3e1..5d5a9f32 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -170,17 +170,59 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "scansound": if(self.playerclass == PC_SCOUT) { - self.impulse = TF_SCAN_SOUND; + //self.impulse = TF_SCAN_SOUND; + sprint(self, PRINT_HIGH, "Scanner sound: "); + if (self.tf_items_flags & 4) { + self.tf_items_flags = self.tf_items_flags - 4; + sprint(self, PRINT_HIGH, "off\n"); + } else { + self.tf_items_flags = self.tf_items_flags | 4; + sprint(self, PRINT_HIGH, "on\n"); + } } break; case "scanf": if(self.playerclass == PC_SCOUT) { - self.impulse = TF_SCAN_FRIENDLY; + //self.impulse = TF_SCAN_FRIENDLY; + sprint(self, PRINT_HIGH, "Scanning for: "); + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { + self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_FRIENDLY; + if (self.tf_items_flags & NIT_SCANNER_ENEMY) { + sprint(self, PRINT_HIGH, "Enemies only\n"); + } else { + sprint(self, PRINT_HIGH, "Nothing\n"); + } + } else { + self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_FRIENDLY; + if (self.tf_items_flags & NIT_SCANNER_ENEMY) { + sprint(self, PRINT_HIGH, "Friendlies and enemies\n"); + } else { + sprint(self, PRINT_HIGH, "Friendlies only\n"); + } + } + Status_Refresh(self); } break; case "scane": if(self.playerclass == PC_SCOUT) { - self.impulse = TF_SCAN_ENEMY; + //self.impulse = TF_SCAN_ENEMY; + sprint(self, PRINT_HIGH, "Scanning for: "); + if (self.tf_items_flags & NIT_SCANNER_ENEMY) { + self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_ENEMY; + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { + sprint(self, PRINT_HIGH, "Friendlies only\n"); + } else { + sprint(self, PRINT_HIGH, "Nothing\n"); + } + } else { + self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY; + if (self.tf_items_flags & NIT_SCANNER_FRIENDLY) { + sprint(self, PRINT_HIGH, "Friendlies and enemies\n"); + } else { + sprint(self, PRINT_HIGH, "Enemies only\n"); + } + Status_Refresh(self); + } } break; } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index ca261506..c508ee3b 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -251,6 +251,25 @@ void UpdateClientMenu_Scout(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMenu_Spy(entity pl) = { + msg_entity = pl; + local float flags = 0; + if(invis_only) { + flags += MSG_MENU_SPY_FLAG_IVIS_ONLY; + } + if(pl.is_undercover) { + flags += MSG_MENU_SPY_FLAG_UNDERCOVER; + } + if(pl.is_feigning) { + flags += MSG_MENU_SPY_FLAG_FEIGNING; + } + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY); + WriteFloat(MSG_MULTICAST, flags); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void (float update) Menu_Team = { local entity timer; From 32c73ce3b3e441df3a46010881a3bb63320361c3 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 20 Oct 2019 21:58:34 +1300 Subject: [PATCH 0828/2474] spy menu --- csqc/csextradefs.qc | 2 + csqc/events.qc | 12 +++++ csqc/menu.qc | 83 +++++++++++++++++++++++++++++-- share/commondefs.qc | 2 + ssqc/client.qc | 1 - ssqc/commands.qc | 31 +++++++++--- ssqc/csmenu.qc | 90 +++++++++++++++++++++++++++++++++ ssqc/menu.qc | 118 +++++++++++++------------------------------- ssqc/progs.src | 1 + 9 files changed, 244 insertions(+), 96 deletions(-) create mode 100644 ssqc/csmenu.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d02c015a..f734538a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -26,6 +26,8 @@ float fo_hud_menu_active; float jumptime; vector ScreenSize; float number_of_teams; +float last_skin; +float last_team; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index 757dfc39..ab170f66 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -137,6 +137,18 @@ void() CSQC_Parse_Event = { FO_Menu_Scout(FALSE, scanner_on, scanner_flags); break; + case CLIENT_MENU_SPY: + SBAR.InvisOnly = readfloat(); + last_skin = readfloat(); + last_team = readfloat(); + FO_Menu_Spy(FALSE); + break; + case CLIENT_MENU_SPY_SKIN: + FO_Menu_Spy_Skin(FALSE); + break; + case CLIENT_MENU_SPY_TEAM: + FO_Menu_Spy_Team(FALSE); + break; } break; case MSG_CLASSES_UPDATE: diff --git a/csqc/menu.qc b/csqc/menu.qc index eefc4c8f..d1566e66 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -133,10 +133,35 @@ var fo_menu FO_MENU_SCOUT = { var fo_menu FO_MENU_SPY = { [0,0], [300,150], "Spy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { {"1","Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise\n");Menu_Cancel();},MENU_BUTTON}, - {"1","Become Invisible","","",FO_MENU_STATE_NORMAL,{localcmd("cmd autoscan\n");Menu_Cancel();},MENU_BUTTON}, - {"2","Scan for enemies","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scane\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Scan for friendlies","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scanf\n");Menu_Cancel();},MENU_BUTTON}, - {"4","Scan sound","","",FO_MENU_STATE_NORMAL,{localcmd("cmd scansound\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Invisibility","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Last Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise last\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Feign","","",FO_MENU_STATE_NORMAL,{localcmd("feign\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Reset Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise none\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 7, TRUE +}; +var fo_menu FO_MENU_SPY_SKIN = { + [0,0], [300,200], "Disguise as enemy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { + {"1","Scout","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 1\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Sniper","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 2\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Soldier","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 3\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Demoman","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 4\n");Menu_Cancel();},MENU_BUTTON}, + {"5","Medic","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 5\n");Menu_Cancel();},MENU_BUTTON}, + {"6","Heavy Weapons","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 6\n");Menu_Cancel();},MENU_BUTTON}, + {"7","Pyro","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 7\n");Menu_Cancel();},MENU_BUTTON}, + {"8","Spy","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 8\n");Menu_Cancel();},MENU_BUTTON}, + {"9","Engineer","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 9\n");Menu_Cancel();},MENU_BUTTON}, + {"0","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + {"-","Civilian","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 11\n");Menu_Cancel();},MENU_BUTTON}, + }, 11, TRUE +}; +var fo_menu FO_MENU_SPY_TEAM = { + [0,0], [300,200], "Disguise as", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Blue team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise team 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, + {"2","Red team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise team 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, + {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise team 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, + {"4","Green team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise team 4\n");Menu_Cancel();},'0.4 0.7 0.3'}, MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 6, TRUE @@ -450,3 +475,53 @@ void FO_Menu_Scout(float force, float scanner_on, float scanner_flags) = { CurrentMenu = FO_MENU_SCOUT; fo_hud_menu_active = TRUE; } +void FO_Menu_Spy(float force) = { + if(fo_hud_menu_active && !force) + return; + if(SBAR.InvisOnly) { + FO_MENU_SPY.options[0].state = FO_MENU_STATE_HIDDEN; + FO_MENU_SPY.options[1].state = FO_MENU_STATE_NORMAL; + FO_MENU_SPY.options[1].value = (SBAR.IsUndercover?"on":"off"); + FO_MENU_SPY.options[2].state = FO_MENU_STATE_HIDDEN; + } else { + FO_MENU_SPY.options[0].state = FO_MENU_STATE_NORMAL; + FO_MENU_SPY.options[1].state = FO_MENU_STATE_HIDDEN; + FO_MENU_SPY.options[0].value = (SBAR.IsUndercover?"on":"off"); + if(last_skin || last_team) { + FO_MENU_SPY.options[2].state = FO_MENU_STATE_NORMAL; + FO_MENU_SPY.options[2].value = strcat(TeamToString(last_team)," ",ClassToString(last_skin)); + } else { + FO_MENU_SPY.options[2].state = FO_MENU_STATE_HIDDEN; + } + FO_MENU_SPY.options[4].state = (SBAR.IsUndercover?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN); + } + CurrentMenu = FO_MENU_SPY; + fo_hud_menu_active = TRUE; +} + +void FO_Menu_Spy_Team(float force) = { + if(fo_hud_menu_active && !force) + return; + if(team_no) { + if(number_of_teams < 2 || team_no >= number_of_teams) { + return; + } + for(float i = 0; i < 4; i++) { + if((i + 1) == team_no) { + FO_MENU_SPY_TEAM.options[i].state = FO_MENU_STATE_HIDDEN; + } else { + FO_MENU_SPY_TEAM.options[i].state = FO_MENU_STATE_NORMAL; + } + + } + } + CurrentMenu = FO_MENU_SPY_TEAM; + fo_hud_menu_active = TRUE; +} + +void FO_Menu_Spy_Skin(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = FO_MENU_SPY_SKIN; + fo_hud_menu_active = TRUE; +} diff --git a/share/commondefs.qc b/share/commondefs.qc index 90000ea9..a3f2d651 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -29,4 +29,6 @@ #define CLIENT_MENU_DROPAMMO 3 #define CLIENT_MENU_SCOUT 4 #define CLIENT_MENU_SPY 5 +#define CLIENT_MENU_SPY_SKIN 6 +#define CLIENT_MENU_SPY_TEAM 7 diff --git a/ssqc/client.qc b/ssqc/client.qc index defe540d..c016adba 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1527,7 +1527,6 @@ void () PutClientInServer = { TeamFortress_ChangeClass(11); } if (deathmatch == 3) { - sprint(self, PRINT_HIGH, "MEHT: nextpc: ", ftos(self.nextpc), ", pc: ", ftos(self.playerclass), "\n"); if(self.nextpc != self.playerclass) { self.playerclass = self.nextpc; } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5d5a9f32..2a693b60 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -139,28 +139,43 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Drop(); break; } - sprint(self, PRINT_HIGH, "Invalid team choice. Please use values 1-4.\n"); + sprint(self, PRINT_HIGH, "Invalid choice. Please use values 1-4.\n"); } Menu_Drop(); break; - case "dropammo": + + case "disguise": processedCmd = TRUE; if (arg2) { - if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { - inp = stof(arg2); - TeamFortress_DropAmmo(inp); - Menu_Drop(); + if(arg2 == "last") { + Menu_Spy_Input(2); + break; + } + if(arg2 == "none") { + Menu_Spy_Input(4); break; } - sprint(self, PRINT_HIGH, "Invalid team choice. Please use values 1-4.\n"); + if(arg2 == "skin" && arg3) { + Menu_Spy_Skin_Input(stof(arg3)); + break; + } + if(arg2 == "team" && arg3) { + Menu_Spy_Color_Input(stof(arg3)); + break; + } + sprint(self, PRINT_HIGH, "Invalid choice. Please use values 'none', 'last', 'skin #' or 'team #'.\n"); + } else { + Menu_Spy_Input(1); } - Menu_Drop(); break; case "menu": switch(self.playerclass) { case PC_SCOUT: Menu_Scout(); break; + case PC_SPY: + Menu_Spy(self); + break; } break; case "autoscan": diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc new file mode 100644 index 00000000..8c640ca2 --- /dev/null +++ b/ssqc/csmenu.qc @@ -0,0 +1,90 @@ +void UpdateClientMenu_Team(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_TEAM); + WriteFloat(MSG_MULTICAST, number_of_teams); + for(float i = 0; i < number_of_teams; i++) { + WriteByte(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(i+1)); + } + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientClasses(entity pl, float team) = { + local float civilian_team = TeamFortress_TeamIsCivilian(pl.team_no); + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLASSES_UPDATE); + WriteByte(MSG_MULTICAST, civilian_team); + override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + if(!civilian_team) { + for(float i = 0; i < 10; i++) { + local float f_max = CF_GetClassRestriction(team, i+1); + local float f_players = CF_GetClassPlayers(team, i+1); + + if ((IsLegalClass(i+1) || override_mapclasses) && f_max >= 0) { + WriteFloat(MSG_MULTICAST, f_max); + WriteByte(MSG_MULTICAST, f_players); + } else { + WriteFloat(MSG_MULTICAST, -1); + } + } + } + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_Class(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_CLASS); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_DropAmmo(entity pl, float ammotypes, float ammomakes) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_DROPAMMO); + WriteFloat(MSG_MULTICAST, ammotypes); + WriteFloat(MSG_MULTICAST, ammomakes); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_Scout(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_SCOUT); + WriteByte(MSG_MULTICAST, pl.ScannerOn); + WriteFloat(MSG_MULTICAST, pl.tf_items_flags); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_Spy(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY); + WriteFloat(MSG_MULTICAST, invis_only); + WriteFloat(MSG_MULTICAST, pl.last_skin); + WriteFloat(MSG_MULTICAST, pl.last_team); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_Spy_Skin(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY_SKIN); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_Spy_Team(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY_TEAM); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + diff --git a/ssqc/menu.qc b/ssqc/menu.qc index c508ee3b..311a3b76 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -102,6 +102,15 @@ void () StartTimer; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +void (entity pl) UpdateClientMenu_Team; +void (entity pl, float team) UpdateClientClasses; +void (entity pl) UpdateClientMenu_Class; +void (entity pl, float ammotypes, float ammomakes) UpdateClientMenu_DropAmmo; +void (entity pl) UpdateClientMenu_Scout; +void (entity pl) UpdateClientMenu_Spy; +void (entity pl) UpdateClientMenu_Spy_Skin; +void (entity pl) UpdateClientMenu_Spy_Team; + void (entity pl) Menu_Close = { pl.menu_input = nil; @@ -188,88 +197,6 @@ string (float pf_team_no, string ps_team) Menu_Team_TeamString = { return strzone(s_string); }; -void UpdateClientMenu_Team(entity pl) = { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); - WriteFloat(MSG_MULTICAST, CLIENT_MENU_TEAM); - WriteFloat(MSG_MULTICAST, number_of_teams); - for(float i = 0; i < number_of_teams; i++) { - WriteByte(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(i+1)); - } - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - -void UpdateClientClasses(entity pl, float team) = { - local float civilian_team = TeamFortress_TeamIsCivilian(pl.team_no); - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CLASSES_UPDATE); - WriteByte(MSG_MULTICAST, civilian_team); - override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); - if(!civilian_team) { - for(float i = 0; i < 10; i++) { - local float f_max = CF_GetClassRestriction(team, i+1); - local float f_players = CF_GetClassPlayers(team, i+1); - - if ((IsLegalClass(i+1) || override_mapclasses) && f_max >= 0) { - WriteFloat(MSG_MULTICAST, f_max); - WriteByte(MSG_MULTICAST, f_players); - } else { - WriteFloat(MSG_MULTICAST, -1); - } - } - } - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - -void UpdateClientMenu_Class(entity pl) = { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); - WriteFloat(MSG_MULTICAST, CLIENT_MENU_CLASS); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - -void UpdateClientMenu_DropAmmo(entity pl, float ammotypes, float ammomakes) = { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); - WriteFloat(MSG_MULTICAST, CLIENT_MENU_DROPAMMO); - WriteFloat(MSG_MULTICAST, ammotypes); - WriteFloat(MSG_MULTICAST, ammomakes); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - -void UpdateClientMenu_Scout(entity pl) = { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); - WriteFloat(MSG_MULTICAST, CLIENT_MENU_SCOUT); - WriteByte(MSG_MULTICAST, pl.ScannerOn); - WriteFloat(MSG_MULTICAST, pl.tf_items_flags); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - -void UpdateClientMenu_Spy(entity pl) = { - msg_entity = pl; - local float flags = 0; - if(invis_only) { - flags += MSG_MENU_SPY_FLAG_IVIS_ONLY; - } - if(pl.is_undercover) { - flags += MSG_MENU_SPY_FLAG_UNDERCOVER; - } - if(pl.is_feigning) { - flags += MSG_MENU_SPY_FLAG_FEIGNING; - } - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); - WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY); - WriteFloat(MSG_MULTICAST, flags); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - void (float update) Menu_Team = { local entity timer; @@ -668,6 +595,13 @@ void (entity pe_player) Menu_Spy = { if (pe_player.effects & (EF_DIMLIGHT | EF_BRIGHTLIGHT) || pe_player.is_unabletospy == 1) { return; } + if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(pe_player); + UpdateClientMenu_Spy(pe_player); + return; + } if (invis_only) { if (pe_player.is_undercover == 1) @@ -716,7 +650,9 @@ void (float inp) Menu_Spy_Skin_Input = { if (self.skin != inp) CF_Spy_ChangeSkin(self, inp); - if (number_of_teams > 2) + if (number_of_teams == 1) + sprint(self, PRINT_HIGH, "There is no other team\n"); + else if (number_of_teams > 2) Menu_Spy_Color(); else if (self.team_no == 1) CF_Spy_ChangeColor(self, 2); @@ -729,6 +665,14 @@ void () Menu_Spy_Skin = { if (self.is_unabletospy == 1) return; + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Spy_Skin(self); + return; + } + local string s_disguise = "Disguise as enemy:\n\n"; local string s_scout = Q"\s[1]\s Scout \n"; local string s_sniper = Q"\s[2]\s Sniper \n"; @@ -772,6 +716,14 @@ void () Menu_Spy_Color = { sprint(self, PRINT_HIGH, "No color changing allowed in deathmatch\n"); return; } + + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Spy_Team(self); + return; + } // don't display your own team if (color == 13) diff --git a/ssqc/progs.src b/ssqc/progs.src index b2769e94..9b42fd1a 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -11,6 +11,7 @@ debug.qc status.qc functions.qc menu.qc +csmenu.qc vote.qc help.qc subs.qc From afde4dc1958c74bb3551bd8f0f923be3f3befadd Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 20 Oct 2019 22:29:58 +1300 Subject: [PATCH 0829/2474] Detpack menu --- csqc/events.qc | 3 +++ csqc/menu.qc | 18 +++++++++++++++++- share/commondefs.qc | 1 + ssqc/commands.qc | 18 +++++++++++++++++- ssqc/csmenu.qc | 7 +++++++ ssqc/menu.qc | 9 +++++++++ 6 files changed, 54 insertions(+), 2 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index ab170f66..458fa0ae 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -149,6 +149,9 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_SPY_TEAM: FO_Menu_Spy_Team(FALSE); break; + case CLIENT_MENU_DETPACK: + FO_Menu_Detpack(FALSE); + break; } break; case MSG_CLASSES_UPDATE: diff --git a/csqc/menu.qc b/csqc/menu.qc index d1566e66..9949fb26 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -157,7 +157,7 @@ var fo_menu FO_MENU_SPY_SKIN = { }, 11, TRUE }; var fo_menu FO_MENU_SPY_TEAM = { - [0,0], [300,200], "Disguise as", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + [0,0], [300,200], "Disguise as", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Blue team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise team 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, {"2","Red team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise team 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise team 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, @@ -166,6 +166,16 @@ var fo_menu FO_MENU_SPY_TEAM = { {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 6, TRUE }; +var fo_menu FO_MENU_DETPACK = { + [0,0], [300,200], "Set detpack for", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","5 Seconds","","",FO_MENU_STATE_NORMAL,{localcmd("cmd detpack 5\n");Menu_Cancel();},MENU_BUTTON}, + {"2","20 Seconds","","",FO_MENU_STATE_NORMAL,{localcmd("cmd detpack 20\n");Menu_Cancel();},MENU_BUTTON}, + {"3","50 Seconds","","",FO_MENU_STATE_NORMAL,{localcmd("cmd detpack 50\n");Menu_Cancel();},MENU_BUTTON}, + {"4","255 Seconds","","",FO_MENU_STATE_NORMAL,{localcmd("cmd detpack 255\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 6, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; @@ -525,3 +535,9 @@ void FO_Menu_Spy_Skin(float force) = { CurrentMenu = FO_MENU_SPY_SKIN; fo_hud_menu_active = TRUE; } +void FO_Menu_Detpack(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = FO_MENU_DETPACK; + fo_hud_menu_active = TRUE; +} diff --git a/share/commondefs.qc b/share/commondefs.qc index a3f2d651..451a91cd 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -31,4 +31,5 @@ #define CLIENT_MENU_SPY 5 #define CLIENT_MENU_SPY_SKIN 6 #define CLIENT_MENU_SPY_TEAM 7 +#define CLIENT_MENU_DETPACK 8 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 2a693b60..859f2140 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -176,6 +176,9 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case PC_SPY: Menu_Spy(self); break; + case PC_DEMOMAN: + Menu_Demoman(); + break; } break; case "autoscan": @@ -240,7 +243,20 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } } break; - } + case "detpack": + processedCmd = TRUE; + if (arg2) { + local float farg2 = stof(arg2); + if(farg2) { + TeamFortress_SetDetpack(farg2); + break; + } + sprint(self, PRINT_HIGH, "Invalid choice. Please use integer values 5+.\n"); + } else { + Menu_Demoman(); + } + break; + } if (self.is_admin) { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 8c640ca2..78f1122a 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -87,4 +87,11 @@ void UpdateClientMenu_Spy_Team(entity pl) = { WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY_TEAM); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMenu_Detpack(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_DETPACK); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 311a3b76..3ea40483 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -110,6 +110,7 @@ void (entity pl) UpdateClientMenu_Scout; void (entity pl) UpdateClientMenu_Spy; void (entity pl) UpdateClientMenu_Spy_Skin; void (entity pl) UpdateClientMenu_Spy_Team; +void (entity pl) UpdateClientMenu_Detpack; void (entity pl) Menu_Close = { @@ -758,6 +759,14 @@ void (float inp) Menu_Demoman_Input = { }; void () Menu_Demoman = { + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Detpack(self); + return; + } + local string s_detpack = "Set detpack for:\n\n"; local string s_5 = Q"\s[1]\s 5 seconds \n"; local string s_20 = Q"\s[2]\s 20 seconds \n"; From 479205a13d7d9b7efa6764faa25161d7d72e7647 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 20 Oct 2019 23:56:29 +1300 Subject: [PATCH 0830/2474] detpack cancel menu --- csqc/events.qc | 2 +- csqc/menu.qc | 13 +++++++++++-- ssqc/commands.qc | 23 +++++++++++++++++++++-- ssqc/csmenu.qc | 3 ++- ssqc/menu.qc | 11 +++++++++-- ssqc/tforthlp.qc | 3 ++- 6 files changed, 46 insertions(+), 9 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 458fa0ae..4ccd5988 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -150,7 +150,7 @@ void() CSQC_Parse_Event = { FO_Menu_Spy_Team(FALSE); break; case CLIENT_MENU_DETPACK: - FO_Menu_Detpack(FALSE); + FO_Menu_Detpack(FALSE, readbyte()); break; } break; diff --git a/csqc/menu.qc b/csqc/menu.qc index 9949fb26..62a4c457 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -176,6 +176,11 @@ var fo_menu FO_MENU_DETPACK = { {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 6, TRUE }; +var fo_menu FO_MENU_DETPACK_CANCEL = { + [0,0], [300,200], "Setting detpack...", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Cancel","","",FO_MENU_STATE_NORMAL,{localcmd("cmd detpack cancel\n");Menu_Cancel();},MENU_BUTTON}, + }, 1, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; @@ -535,9 +540,13 @@ void FO_Menu_Spy_Skin(float force) = { CurrentMenu = FO_MENU_SPY_SKIN; fo_hud_menu_active = TRUE; } -void FO_Menu_Detpack(float force) = { +void FO_Menu_Detpack(float force, float cancel_detpack) = { if(fo_hud_menu_active && !force) return; - CurrentMenu = FO_MENU_DETPACK; + if(cancel_detpack) { + CurrentMenu = FO_MENU_DETPACK_CANCEL; + } else { + CurrentMenu = FO_MENU_DETPACK; + } fo_hud_menu_active = TRUE; } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 859f2140..ba8256ad 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -173,11 +173,21 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case PC_SCOUT: Menu_Scout(); break; + case PC_DEMOMAN: + if(self.is_detpacking) { + Menu_Demoman_Cancel(); + break; + } + Menu_Demoman(); + break; case PC_SPY: Menu_Spy(self); break; - case PC_DEMOMAN: - Menu_Demoman(); + case PC_ENGINEER: + Menu_Engineer(self); + break; + default: + sprint(self, PRINT_HIGH, "This class doesn't have a menu\n"); break; } break; @@ -246,6 +256,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "detpack": processedCmd = TRUE; if (arg2) { + if(arg2 == "cancel") { + TeamFortress_DetpackStop(); + break; + } + if(self.is_detpacking) { + Menu_Demoman_Cancel(); + break; + } local float farg2 = stof(arg2); if(farg2) { TeamFortress_SetDetpack(farg2); @@ -435,6 +453,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "cmd cancel\n"); sprint(self, PRINT_HIGH, "cmd stop\n"); sprint(self, PRINT_HIGH, "cmd kick\n"); + sprint(self, PRINT_HIGH, "cmd ceasefire\n"); sprint(self, PRINT_HIGH, "cmd help || list (this command)\n"); sprint(self, PRINT_HIGH, "\n"); break; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 78f1122a..31bcef14 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -87,11 +87,12 @@ void UpdateClientMenu_Spy_Team(entity pl) = { WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY_TEAM); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -void UpdateClientMenu_Detpack(entity pl) = { +void UpdateClientMenu_Detpack(entity pl, float cancel_detpack) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); WriteFloat(MSG_MULTICAST, CLIENT_MENU_DETPACK); + WriteByte(MSG_MULTICAST, cancel_detpack); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 3ea40483..62e2b17c 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -110,7 +110,7 @@ void (entity pl) UpdateClientMenu_Scout; void (entity pl) UpdateClientMenu_Spy; void (entity pl) UpdateClientMenu_Spy_Skin; void (entity pl) UpdateClientMenu_Spy_Team; -void (entity pl) UpdateClientMenu_Detpack; +void (entity pl, float cancel_detpack) UpdateClientMenu_Detpack; void (entity pl) Menu_Close = { @@ -763,7 +763,7 @@ void () Menu_Demoman = { //fte+csqc has its own team menu //ask the client to activate it Menu_Close(self); - UpdateClientMenu_Detpack(self); + UpdateClientMenu_Detpack(self, FALSE); return; } @@ -785,6 +785,13 @@ void (float inp) Menu_Demoman_Cancel_Input = { } void () Menu_Demoman_Cancel = { + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Detpack(self, TRUE); + return; + } local string s_detpack = "Setting detpack...\n\n"; local string s_cancel = Q"\s[1]\s Cancel!\n\n\n\n\n"; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index c40452c6..c1621d27 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -62,7 +62,8 @@ void () TeamFortress_MOTD = { return; } - TeamFortress_Alias("menu", TF_CLASSMENU, 0); + //TeamFortress_Alias("menu", TF_CLASSMENU, 0); + TeamFortress_AliasString("menu", "cmd menu"); TeamFortress_Alias("slot1", TF_SLOT1, 0); TeamFortress_Alias("slot2", TF_SLOT2, 0); TeamFortress_Alias("slot3", TF_SLOT3, 0); From 390c29d4ca3c709270ab8765f1625e6622aa5fa6 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 21 Oct 2019 23:31:25 +1300 Subject: [PATCH 0831/2474] fall back to engine main menu if menu.dat is missing --- csqc/main.qc | 10 ++++++++++ csqc/menu.qc | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 5a553c52..262abd66 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -25,6 +25,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); registercommand("fo_menu_game"); + registercommand("fo_main_menu"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -78,6 +79,15 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_game": FO_Menu_Game(TRUE); break; + case "fo_main_menu": + if(checkcommand("m_main")) { + //Use menuqc main menu + localcmd("m_main\n"); + } else { + //If menu.dat is missing, fall back to engine menus + localcmd("menu_main\n"); + } + break; } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index 62a4c457..37feaee4 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -66,7 +66,7 @@ var fo_menu FO_MENU_GAME = { MenuSpacer, {"4","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, MenuSpacer, - {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, + {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, }, 7, TRUE }; var fo_menu FO_MENU_GAME_SPECTATOR = { From 803b61f04bcc6fcb729ff464ac7cca5c8b634841 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 1 Nov 2019 10:58:24 +1300 Subject: [PATCH 0832/2474] sentry + dispenser maintain and use menus; fix ammo not updating on dismantle --- csqc/csextradefs.qc | 3 + csqc/events.qc | 19 ++++ csqc/input.qc | 3 + csqc/main.qc | 10 +- csqc/menu.qc | 257 ++++++++++++++++++++++++++++++++++++++------ share/commondefs.qc | 11 +- ssqc/commands.qc | 116 +++++++++++++++++++- ssqc/csmenu.qc | 33 ++++++ ssqc/demoman.qc | 8 +- ssqc/engineer.qc | 43 +++++++- ssqc/menu.qc | 59 ++++++++-- ssqc/spy.qc | 3 + 12 files changed, 516 insertions(+), 49 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f734538a..e6038df7 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -28,6 +28,9 @@ vector ScreenSize; float number_of_teams; float last_skin; float last_team; +vector sentry_pos; +vector dispenser_pos; +vector touched_dispenser_pos; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index 4ccd5988..426b3b97 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -152,6 +152,19 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_DETPACK: FO_Menu_Detpack(FALSE, readbyte()); break; + case CLIENT_MENU_BUILD: + FO_Menu_Build(FALSE); + break; + case CLIENT_MENU_ROTATE_SENTRY: + FO_Menu_Rotate_Sentry(FALSE); + break; + case CLIENT_MENU_FIX_DISPENSER: + FO_Menu_Dispenser_Fix(FALSE, readbyte()); + break; + case CLIENT_MENU_USE_DISPENSER: + touched_dispenser_pos = [readfloat(),readfloat(),readfloat()]; + FO_Menu_Dispenser_Use(FALSE); + break; } break; case MSG_CLASSES_UPDATE: @@ -171,6 +184,12 @@ void() CSQC_Parse_Event = { } } + break; + case MSG_SENTRY_POS: + sentry_pos = [readfloat(),readfloat(),readfloat()]; + break; + case MSG_DISPENSER_POS: + dispenser_pos = [readfloat(),readfloat(),readfloat()]; break; } } diff --git a/csqc/input.qc b/csqc/input.qc index fc6d79b3..ed23bef1 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -41,6 +41,9 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } break; case K_MOUSE1: + if(!fo_hud_editor && fo_hud_menu_active && !(CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)) { + break; + } // work out if on a button return TRUE; break; diff --git a/csqc/main.qc b/csqc/main.qc index 262abd66..756ee93f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -30,12 +30,12 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); - CurrentMenu = FO_MENU_TEAM; + CurrentMenu = &FO_MENU_TEAM; }; noref void() CSQC_WorldLoaded = { print("CSQC World Loaded\n"); - localcmd("menu_restart"); + localcmd("menu_restart\n"); } noref void(float width, float height, float menushown) CSQC_UpdateView = { @@ -79,6 +79,12 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_game": FO_Menu_Game(TRUE); break; + case "fo_menu_team": + FO_Menu_Team(TRUE); + break; + case "fo_menu_class": + FO_Menu_Class(TRUE); + break; case "fo_main_menu": if(checkcommand("m_main")) { //Use menuqc main menu diff --git a/csqc/menu.qc b/csqc/menu.qc index 37feaee4..0063f94f 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -8,53 +8,56 @@ #define FO_MENU_STATE_DISABLED 2 #define FO_MENU_STATE_SPACER 3 -class fo_menu_option_2 { +void (float force) FO_Menu_Build; + +typedef struct { string shortcut; //key to press. if omitted - mouse only string name; //what to display string value; //optional - displays current value/state string description; //optional float state; //active/disabled - virtual void() action = {}; + void() action; vector colour; - fo_menu_option_2 next; -}; +} fo_menu_option; -class fo_menu_2 { +typedef struct { vector position; vector size; string title; float flags; - fo_menu_option_2 options; + fo_menu_option options[20]; float num_opts; float active; -}; - + void() update; +} fo_menu; -typedef struct { +class fo_menu_option_2 { string shortcut; //key to press. if omitted - mouse only string name; //what to display string value; //optional - displays current value/state string description; //optional float state; //active/disabled - void() action; + virtual void() action = {}; vector colour; -} fo_menu_option; + fo_menu_option_2 next; +}; -typedef struct { +class fo_menu_2 { vector position; vector size; string title; float flags; - fo_menu_option options[20]; + fo_menu_option_2 options; float num_opts; float active; -} fo_menu; + virtual void() update = {}; +}; void FO_Menu_Team(float); void Menu_Cancel() ; -fo_menu InProgressMenu; -fo_menu CurrentMenu; +fo_menu* InProgressMenu; +fo_menu* CurrentMenu; fo_menu_option MenuSpacer = {"","","","",FO_MENU_STATE_SPACER}; @@ -179,7 +182,120 @@ var fo_menu FO_MENU_DETPACK = { var fo_menu FO_MENU_DETPACK_CANCEL = { [0,0], [300,200], "Setting detpack...", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Cancel","","",FO_MENU_STATE_NORMAL,{localcmd("cmd detpack cancel\n");Menu_Cancel();},MENU_BUTTON}, - }, 1, TRUE + }, 1, TRUE, { + if(!SBAR.IsDetpacking) { + Menu_Cancel(); + } + } +}; +var fo_menu FO_MENU_BUILD_CANCEL = { + [0,0], [300,200], "Building...", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Cancel","","",FO_MENU_STATE_NORMAL,{localcmd("cmd build cancel\n");Menu_Cancel();},MENU_BUTTON}, + }, 1, TRUE, { + if(!SBAR.IsBuilding) { + Menu_Cancel(); + } + } +}; +var fo_menu FO_MENU_BUILD = { + [0,0], [300,200], "Engineering", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Build Sentry Gun","","",FO_MENU_STATE_NORMAL,{localcmd("cmd build sentry\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Build Dispenser","","",FO_MENU_STATE_NORMAL,{localcmd("cmd build dispenser\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Destroy Sentry Gun","","",FO_MENU_STATE_NORMAL,{localcmd("cmd build destroy sentry\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Dismantle Sentry Gun","","",FO_MENU_STATE_NORMAL,{localcmd("cmd build destroy sentry\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Destroy Dispenser","","",FO_MENU_STATE_NORMAL,{localcmd("cmd build destroy dispenser\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Dismantle Dispenser","","",FO_MENU_STATE_NORMAL,{localcmd("cmd build destroy dispenser\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 8, TRUE, { + if(SBAR.IsBuilding) { + Menu_Cancel(); + //CurrentMenu = &FO_MENU_BUILD_CANCEL; + FO_Menu_Build(FALSE); + return; + } + vector org = (vector)getentity(player_localentnum, GE_ORIGIN); + if(SBAR.HasSentry) { + FO_MENU_BUILD.options[0].state = FO_MENU_STATE_HIDDEN; //Build + if(vlen(org - sentry_pos) <= ENG_BUILDING_DISMANGLE_DISTANCE) { + FO_MENU_BUILD.options[2].state = FO_MENU_STATE_HIDDEN; //Destroy + FO_MENU_BUILD.options[3].state = FO_MENU_STATE_NORMAL; //Dismantle + } else { + FO_MENU_BUILD.options[2].state = FO_MENU_STATE_NORMAL; //Destroy + FO_MENU_BUILD.options[3].state = FO_MENU_STATE_HIDDEN; //Dismantle + } + } else { + if(getstatf(STAT_CELLS) > ENG_SENTRY_COST) { + FO_MENU_BUILD.options[0].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_BUILD.options[0].state = FO_MENU_STATE_DISABLED; + } + FO_MENU_BUILD.options[2].state = FO_MENU_STATE_HIDDEN; + FO_MENU_BUILD.options[3].state = FO_MENU_STATE_HIDDEN; + } + if(SBAR.HasDispenser) { + FO_MENU_BUILD.options[1].state = FO_MENU_STATE_HIDDEN; + if(vlen(org - dispenser_pos) <= ENG_BUILDING_DISMANGLE_DISTANCE) { + FO_MENU_BUILD.options[4].state = FO_MENU_STATE_HIDDEN; + FO_MENU_BUILD.options[5].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_BUILD.options[4].state = FO_MENU_STATE_NORMAL; + FO_MENU_BUILD.options[5].state = FO_MENU_STATE_HIDDEN; + } + } else { + if(getstatf(STAT_CELLS) > ENG_DISPENSER_COST) { + FO_MENU_BUILD.options[1].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_BUILD.options[1].state = FO_MENU_STATE_DISABLED; + } + FO_MENU_BUILD.options[4].state = FO_MENU_STATE_HIDDEN; + FO_MENU_BUILD.options[5].state = FO_MENU_STATE_HIDDEN; + } + } +}; +var fo_menu FO_MENU_SENTRY_ROTATE = { + [0,0], [300,200], "Rotate Sentry Gun", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, + {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 5, TRUE, { + vector org = (vector)getentity(player_localentnum, GE_ORIGIN); + if(vlen(org - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { + Menu_Cancel(); + return; + } + } +}; +var fo_menu FO_MENU_DISPENSER_MAINTAIN = { + [0,0], [300,200], "Dispenser", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Insert Ammo","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser ammo\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Insert Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser armour\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Repair","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser repair\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 5, TRUE, { + vector org = (vector)getentity(player_localentnum, GE_ORIGIN); + if(vlen(org - dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { + Menu_Cancel(); + return; + } + } +}; +var fo_menu FO_MENU_DISPENSER_USE = { + [0,0], [300,200], "Use Dispenser", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Withdraw Ammo","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw ammo\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Withdraw Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armour\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 4, TRUE, { + vector org = (vector)getentity(player_localentnum, GE_ORIGIN); + if(vlen(org - touched_dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { + Menu_Cancel(); + return; + } + } }; void fo_menu_start(vector position, vector size, string title, float flags) = { @@ -215,7 +331,7 @@ void fo_menu_add_option2(string shortcut, string name, string value, string desc } } -vector fo_menu_draw(fo_menu menu) = { +vector fo_menu_draw(fo_menu * menu) = { vector position; if(menu.flags & FO_MENU_FLAG_CENTER) { position = Hud_Panels[HUD_PANEL_MENU].Position; @@ -229,7 +345,13 @@ vector fo_menu_draw(fo_menu menu) = { setcursormode(FALSE); return position; } + setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); + + if(menu.update) { + menu.update(); + } + local float scale = Hud_Panels[HUD_PANEL_MENU].Scale, textscale = Hud_Panels[HUD_PANEL_MENU].TextScale; if(!textscale) { textscale = scale; @@ -339,7 +461,7 @@ vector fo_menu_draw(fo_menu menu) = { return position; } -float fo_menu_process_input(fo_menu menu, float scan) = { +float fo_menu_process_input(fo_menu * menu, float scan) = { local string button = ""; local float found = FALSE; if(scan > 47 && scan < 58) { @@ -388,14 +510,18 @@ void Menu_Draw(float width, float height, float menushown) = { } void FO_Menu_Game(float force) = { + if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_GAME || CurrentMenu == &FO_MENU_GAME_SPECTATOR)) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; if(is_spectator) { //print(getplayerkeyvalue(player_localnum, "name"), " is a spectator!\n"); - CurrentMenu = FO_MENU_GAME_SPECTATOR; + CurrentMenu = &FO_MENU_GAME_SPECTATOR; } else { //print(getplayerkeyvalue(player_localnum, "name"), " is playing a game!\n"); - CurrentMenu = FO_MENU_GAME; + CurrentMenu = &FO_MENU_GAME; } fo_hud_menu_active = TRUE; } @@ -415,10 +541,14 @@ void FO_Menu_Track() = { e = find(e, classname, "player"); } FO_MENU_SPECTATOR_TRACK.num_opts = i; - FO_MENU_SPECTATOR_TRACK.position = fo_menu_draw(FO_MENU_SPECTATOR_TRACK); + //FO_MENU_SPECTATOR_TRACK.position = fo_menu_draw(FO_MENU_SPECTATOR_TRACK); } void FO_Menu_Team(float force) = { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_TEAM && !force) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; if(team_no) { @@ -435,18 +565,26 @@ void FO_Menu_Team(float force) = { //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_NORMAL; //FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; } - CurrentMenu = FO_MENU_TEAM; + CurrentMenu = &FO_MENU_TEAM; fo_hud_menu_active = TRUE; } void FO_Menu_Class(float force) = { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; - CurrentMenu = FO_MENU_CLASS; + CurrentMenu = &FO_MENU_CLASS; fo_hud_menu_active = TRUE; } void FO_Menu_DropAmmo(float force, float ammotypes, float ammomakes) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_DROPAMMO) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; if(!ammotypes) { @@ -476,21 +614,29 @@ void FO_Menu_DropAmmo(float force, float ammotypes, float ammomakes) { } } - CurrentMenu = FO_MENU_DROPAMMO; + CurrentMenu = &FO_MENU_DROPAMMO; fo_hud_menu_active = TRUE; } void FO_Menu_Scout(float force, float scanner_on, float scanner_flags) = { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SCOUT) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; FO_MENU_SCOUT.options[0].value = (scanner_on?"on":"off"); FO_MENU_SCOUT.options[1].value = ((scanner_flags & 1)?"on":"off"); FO_MENU_SCOUT.options[2].value = ((scanner_flags & 2)?"on":"off"); FO_MENU_SCOUT.options[3].value = ((scanner_flags & 4)?"on":"off"); - CurrentMenu = FO_MENU_SCOUT; + CurrentMenu = &FO_MENU_SCOUT; fo_hud_menu_active = TRUE; } void FO_Menu_Spy(float force) = { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; if(SBAR.InvisOnly) { @@ -510,7 +656,7 @@ void FO_Menu_Spy(float force) = { } FO_MENU_SPY.options[4].state = (SBAR.IsUndercover?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN); } - CurrentMenu = FO_MENU_SPY; + CurrentMenu = &FO_MENU_SPY; fo_hud_menu_active = TRUE; } @@ -530,23 +676,72 @@ void FO_Menu_Spy_Team(float force) = { } } - CurrentMenu = FO_MENU_SPY_TEAM; + CurrentMenu = &FO_MENU_SPY_TEAM; fo_hud_menu_active = TRUE; } void FO_Menu_Spy_Skin(float force) = { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY_SKIN) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; - CurrentMenu = FO_MENU_SPY_SKIN; + CurrentMenu = &FO_MENU_SPY_SKIN; fo_hud_menu_active = TRUE; } void FO_Menu_Detpack(float force, float cancel_detpack) = { + if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_DETPACK_CANCEL || CurrentMenu == &FO_MENU_DETPACK)) { + Menu_Cancel(); + return; + } if(fo_hud_menu_active && !force) return; if(cancel_detpack) { - CurrentMenu = FO_MENU_DETPACK_CANCEL; + CurrentMenu = &FO_MENU_DETPACK_CANCEL; + } else { + CurrentMenu = &FO_MENU_DETPACK; + } + fo_hud_menu_active = TRUE; +} +void FO_Menu_Build(float force) = { + if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_BUILD_CANCEL || CurrentMenu == &FO_MENU_BUILD)) { + Menu_Cancel(); + return; + } + if(fo_hud_menu_active && !force) + return; + if(SBAR.IsBuilding) { + CurrentMenu = &FO_MENU_BUILD_CANCEL; + } else { + CurrentMenu = &FO_MENU_BUILD; + } + fo_hud_menu_active = TRUE; +} +void FO_Menu_Rotate_Sentry(float force) = { + if(fo_hud_menu_active && !force) + return; + if(SBAR.IsBuilding) { + return; + } else { + CurrentMenu = &FO_MENU_SENTRY_ROTATE; + } + fo_hud_menu_active = TRUE; +} +void FO_Menu_Dispenser_Fix(float force, float old_spanner) = { + if(fo_hud_menu_active && !force) + return; + FO_MENU_DISPENSER_MAINTAIN.options[2].state = (old_spanner?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN); + CurrentMenu = &FO_MENU_DISPENSER_MAINTAIN; + fo_hud_menu_active = TRUE; +} +void FO_Menu_Dispenser_Use(float force) = { + if(fo_hud_menu_active && !force) + return; + if(SBAR.IsBuilding) { + return; } else { - CurrentMenu = FO_MENU_DETPACK; + CurrentMenu = &FO_MENU_DISPENSER_USE; } fo_hud_menu_active = TRUE; } diff --git a/share/commondefs.qc b/share/commondefs.qc index 451a91cd..f8844741 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,4 +1,8 @@ #define MAX_FLAGINFO_LINES 10 +#define ENG_BUILDING_DISMANGLE_DISTANCE 100 +#define ENG_BUILDING_MAINT_DISTANCE 80 +#define ENG_DISPENSER_COST 100 +#define ENG_SENTRY_COST 130 #define MSG_FLAGINFOINIT 1 #define MSG_FLAGINFO 2 @@ -9,6 +13,8 @@ #define MSG_CLIENT_MENU 6 #define MSG_TEAMS_UPDATE 7 #define MSG_CLASSES_UPDATE 8 +#define MSG_SENTRY_POS 9 +#define MSG_DISPENSER_POS 10 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 @@ -32,4 +38,7 @@ #define CLIENT_MENU_SPY_SKIN 6 #define CLIENT_MENU_SPY_TEAM 7 #define CLIENT_MENU_DETPACK 8 - +#define CLIENT_MENU_BUILD 9 +#define CLIENT_MENU_ROTATE_SENTRY 10 +#define CLIENT_MENU_FIX_DISPENSER 11 +#define CLIENT_MENU_USE_DISPENSER 12 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index ba8256ad..c2cfe6d2 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -130,8 +130,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Class(0); } break; + +//These only work when alive case "dropammo": processedCmd = TRUE; + if(self.health <= 0) { + sprint(self, PRINT_HIGH, "You've already dropped all your ammo when you died!\n"); + break; + } if (arg2) { if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { inp = stof(arg2); @@ -146,6 +152,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "disguise": processedCmd = TRUE; + if(self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't spy while dead!\n"); + break; + } if (arg2) { if(arg2 == "last") { Menu_Spy_Input(2); @@ -169,6 +179,11 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "menu": + processedCmd = TRUE; + if(self.health <= 0 && self.playerclass != PC_SCOUT) { + sprint(self, PRINT_HIGH, "Menus are for the living!\n"); + break; + } switch(self.playerclass) { case PC_SCOUT: Menu_Scout(); @@ -187,16 +202,18 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Engineer(self); break; default: - sprint(self, PRINT_HIGH, "This class doesn't have a menu\n"); + sprint(self, PRINT_HIGH, "This class doesn't have a menu.\n"); break; } break; case "autoscan": + processedCmd = TRUE; if(self.playerclass == PC_SCOUT) { ScannerSwitch(); } break; case "scansound": + processedCmd = TRUE; if(self.playerclass == PC_SCOUT) { //self.impulse = TF_SCAN_SOUND; sprint(self, PRINT_HIGH, "Scanner sound: "); @@ -210,6 +227,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "scanf": + processedCmd = TRUE; if(self.playerclass == PC_SCOUT) { //self.impulse = TF_SCAN_FRIENDLY; sprint(self, PRINT_HIGH, "Scanning for: "); @@ -232,6 +250,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "scane": + processedCmd = TRUE; if(self.playerclass == PC_SCOUT) { //self.impulse = TF_SCAN_ENEMY; sprint(self, PRINT_HIGH, "Scanning for: "); @@ -255,6 +274,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "detpack": processedCmd = TRUE; + if(self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't set detpacks while dead.\n"); + break; + } if (arg2) { if(arg2 == "cancel") { TeamFortress_DetpackStop(); @@ -274,6 +297,95 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Demoman(); } break; + case "build": + processedCmd = TRUE; + if(self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't build while dead.\n"); + break; + } + if (arg2) { + if(arg2 == "cancel") { + TeamFortress_EngineerBuildStop(); + break; + } + if(arg2 == "sentry") { + Menu_Engineer_Input(1); + break; + } + if(arg2 == "dispenser") { + Menu_Engineer_Input(2); + break; + } + if(arg2 == "destroy" && arg3) { + if(arg3 == "sentry") { + Menu_Engineer_Input(3); + break; + } + if(arg3 == "dispenser") { + Menu_Engineer_Input(4); + break; + } + } + sprint(self, PRINT_HIGH, "Invalid choice.\n"); + } else { + Menu_Engineer(self); + } + break; + case "sentry": + processedCmd = TRUE; + if(self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); + break; + } + if (arg2 && arg3) { + if(arg2 == "rotate") { + local float farg3 = stof(arg3); + if(farg3 < 0) { + sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); + } else { + sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3)," degrees anticlockwise...\n"); + } + self.building.waitmin = anglemod(self.building.waitmin + farg3); + self.building.waitmax = anglemod(self.building.waitmax + farg3); + break; + } + sprint(self, PRINT_HIGH, "Invalid choice.\n"); + } else { + Menu_EngineerFix_SentryGun_Rotate(); + } + break; + case "dispenser": + processedCmd = TRUE; + if(self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't dispense while dead.\n"); + break; + } + if (arg2) { + if(arg2 == "ammo") { + Menu_EngineerFix_Dispenser_Input(1); + break; + } + if(arg2 == "armour" || arg2 == "armor") { + Menu_EngineerFix_Dispenser_Input(2); + break; + } + if(arg2 == "repair") { + Menu_EngineerFix_Dispenser_Input(3); + break; + } + if(arg2 == "withdraw" && arg3) { + if(arg3 == "ammo") { + Menu_Dispenser_Input(1); + break; + } + if(arg3 == "armour" || arg3 == "armor") { + Menu_Dispenser_Input(2); + break; + } + } + } + sprint(self, PRINT_HIGH, "Invalid choice. Choices are [ammo|armo[u]r|repair|withdraw ammo|withdraw armo[u]r].\n"); + break; } if (self.is_admin) @@ -459,7 +571,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } } - + return processedCmd; } diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 31bcef14..0fecd085 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -96,3 +96,36 @@ void UpdateClientMenu_Detpack(entity pl, float cancel_detpack) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMenu_Build(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_BUILD); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} +void UpdateClientMenu_FixSentry(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_ROTATE_SENTRY); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} +void UpdateClientMenu_FixDispenser(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_FIX_DISPENSER); + WriteByte(MSG_MULTICAST, old_spanner); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} +void UpdateClientMenu_UseDispenser(entity pl, entity disp) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_USE_DISPENSER); + WriteFloat(MSG_MULTICAST, disp.origin.x); + WriteFloat(MSG_MULTICAST, disp.origin.y); + WriteFloat(MSG_MULTICAST, disp.origin.z); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index f286c952..15ac9984 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -133,11 +133,15 @@ void (float timer) TeamFortress_SetDetpack = { self.impulse = 0; self.last_impulse = 0; - if (!(self.weapons_carried & WEAP_DETPACK)) + if (!(self.weapons_carried & WEAP_DETPACK)) { + sprint(self, PRINT_HIGH, "You don't have a detpack\n"); return; + } - if (self.ammo_detpack <= 0) + if (self.ammo_detpack <= 0) { + sprint(self, PRINT_HIGH, "You don't have any detpacks left\n"); return; + } at_spot = findradius(self.origin, 65); while (at_spot != world) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index fa7655d8..4dba5d37 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -791,12 +791,36 @@ void () DispenserThink = { self.nextthink = time + 0.3; }; +void UpdateClient_Sentry(entity pl, entity sent) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_SENTRY_POS); + WriteFloat(MSG_MULTICAST, sent.origin.x); + WriteFloat(MSG_MULTICAST, sent.origin.y); + WriteFloat(MSG_MULTICAST, sent.origin.z); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClient_Dispenser(entity pl, entity disp) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_DISPENSER_POS); + WriteFloat(MSG_MULTICAST, disp.origin.x); + WriteFloat(MSG_MULTICAST, disp.origin.y); + WriteFloat(MSG_MULTICAST, disp.origin.z); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + + void () TeamFortress_FinishedBuilding = { local entity oldself; if (self.owner.is_building != 1) { return; } + + local float csqcactive = infokeyf(self.owner, INFOKEY_P_CSQCACTIVE); + oldself = self; self = self.owner; oldself.owner = world; @@ -814,7 +838,7 @@ void () TeamFortress_FinishedBuilding = { sprint(self, PRINT_HIGH, "You finish building the dispenser\n"); teamsprint(self.team_no, self, self.netname); teamsprint(self.team_no, self, " has built a dispenser\n"); - self.ammo_cells = self.ammo_cells - 100; + self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; oldself.classname = "building_dispenser"; oldself.netname = "dispenser"; oldself.blocked = T_Dispenser; @@ -848,6 +872,9 @@ void () TeamFortress_FinishedBuilding = { setmodel(oldself, oldself.mdl); setsize(oldself, '-8 -8 0', '8 8 24'); setorigin(oldself, (oldself.origin + '0 0 8')); + if(csqcactive) { + UpdateClient_Dispenser(self, oldself); + } } else if (oldself.weapon == 2) { self.has_sentry = TRUE; sprint(self, PRINT_HIGH, "You finish building the sentry gun\n"); @@ -858,7 +885,7 @@ void () TeamFortress_FinishedBuilding = { oldself.takedamage = DAMAGE_NO; oldself.th_die = Sentry_Die; oldself.team_no = self.team_no; - self.ammo_cells = self.ammo_cells - 130; + self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; setsize(oldself, '-16 -16 0', '16 16 4'); newmis = spawn(); newmis.classname = "building_sentrygun"; @@ -904,6 +931,9 @@ void () TeamFortress_FinishedBuilding = { newmis.ammo_shells = 25; newmis.maxammo_shells = 100; newmis.maxammo_rockets = 20; + if(csqcactive) { + UpdateClient_Sentry(self, oldself); + } } W_SetCurrentAmmo(self); self = oldself; @@ -982,6 +1012,7 @@ void (entity disp) Engineer_UseDispenser = { ThrowGib("progs/dgib1.mdl", -30); ThrowGib("progs/dgib2.mdl", -50); ThrowGib("progs/dgib3.mdl", -50); + W_SetCurrentAmmo(self); return; } @@ -1125,10 +1156,12 @@ void (entity disp) Engineer_Dispenser_Repair = { void (entity gun) Engineer_UseSentryGun = { + self.building = gun; // automate tasks if old_spanner setting is disabled if (!old_spanner) { if(gun.team_no > 0 && gun.team_no == self.team_no) { - if (gun.weapon < 3 && self.ammo_cells >= 130) { + Menu_EngineerFix_SentryGun_Rotate(); + if (gun.weapon < 3 && self.ammo_cells >= ENG_SENTRY_COST) { Engineer_SentryGun_Upgrade(gun); return; } else if (gun.health < gun.max_health && self.ammo_cells > 0) { @@ -1151,6 +1184,7 @@ void (entity gun) Engineer_UseSentryGun = { ThrowGib("progs/tgib1.mdl", -30); ThrowGib("progs/tgib2.mdl", -50); ThrowGib("progs/tgib3.mdl", -50); + W_SetCurrentAmmo(self); return; } } @@ -1181,7 +1215,6 @@ void (entity gun) Engineer_UseSentryGun = { } sprint(self, PRINT_HIGH, "\n"); - self.building = gun; Engineer_SentryGun_ShowMenu(self.building); }; @@ -1296,7 +1329,7 @@ void () CheckDistance = { return; } dist = self.enemy.origin - self.owner.origin; - if (vlen(dist) > 80) { + if (vlen(dist) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Close(self.owner); self.owner.building = world; dremove(self); diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 62e2b17c..576a8b34 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -111,6 +111,10 @@ void (entity pl) UpdateClientMenu_Spy; void (entity pl) UpdateClientMenu_Spy_Skin; void (entity pl) UpdateClientMenu_Spy_Team; void (entity pl, float cancel_detpack) UpdateClientMenu_Detpack; +void (entity pl) UpdateClientMenu_Build; +void (entity pl) UpdateClientMenu_FixSentry; +void (entity pl) UpdateClientMenu_FixDispenser; +void (entity pl, entity disp) UpdateClientMenu_UseDispenser; void (entity pl) Menu_Close = { @@ -814,14 +818,14 @@ void (float inp) Menu_Engineer_Input = { dismantle_sentrygun = 0; dismantle_dispenser = 0; - if (inp == 1 && !self.has_sentry && self.ammo_cells >= 130) + if (inp == 1 && !self.has_sentry && self.ammo_cells >= ENG_SENTRY_COST) TeamFortress_Build(2); - if (inp == 2 && !self.has_dispenser && self.ammo_cells >= 100) + if (inp == 2 && !self.has_dispenser && self.ammo_cells >= ENG_DISPENSER_COST) TeamFortress_Build(1); if (inp == 3 && self.has_sentry) { - te = findradius(self.origin, 100); + te = findradius(self.origin, ENG_BUILDING_DISMANGLE_DISTANCE); while (te) { if (te.classname == "building_sentrygun") { if (te.real_owner == self){ @@ -831,6 +835,7 @@ void (float inp) Menu_Engineer_Input = { dremove (te); self.has_sentry = 0; dismantle_sentrygun = 1; + W_SetCurrentAmmo(self); } } te = te.chain; @@ -840,7 +845,7 @@ void (float inp) Menu_Engineer_Input = { } if (inp == 4 && self.has_dispenser) { - te = findradius(self.origin, 100); + te = findradius(self.origin, ENG_BUILDING_DISMANGLE_DISTANCE); while (te) { if (te.classname == "building_dispenser") { if (te.real_owner == self) { @@ -849,6 +854,7 @@ void (float inp) Menu_Engineer_Input = { dremove (te); self.has_dispenser = 0; dismantle_dispenser = 1; + W_SetCurrentAmmo(self); } } te = te.chain; @@ -868,6 +874,14 @@ void (entity player) Menu_Engineer = { local string s_ddisp = "\n"; local string s_nothing = Q"\n\s[5]\s Nothing "; + if(infokeyf(player, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(player); + UpdateClientMenu_Build(player); + return; + } + if (player.has_sentry) { s_sentry = "\n"; s_dsentry = Q"\s[3]\s Destroy sentry gun \n"; @@ -935,6 +949,14 @@ void (float inp) Menu_EngineerFix_Dispenser_Input = { }; void () Menu_EngineerFix_Dispenser = { + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_FixDispenser(self); + return; + } + local string s_action = "Dispenser maintenance:\n\n"; local string s_ammo, s_armor, s_repair; local string s_nothing = Q"\n\s[5]\s Nothing \n\n"; @@ -983,10 +1005,20 @@ void () Menu_EngineerFix_SentryGun_Rotate = { local string rotr = Q"\s[3]\s clockwise \n"; local string nothing = Q"\n\s[5]\s Nothing \n"; + if (!self.building.real_owner.has_sentry || self.building.real_owner != self - || self.classname != "player" || self.building == world) + || self.classname != "player" || self.building == world) { return; - + } + + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_FixSentry(self); + return; + } + Status_Menu(self, Menu_EngineerFix_SentryGun_Rotate_Input, action, rotl, rot180, rotr, nothing); }; @@ -1118,6 +1150,14 @@ void () Menu_Dispenser = { local string s_ammo, s_armor; local string s_nothing = Q"\n\s[5]\s Nothing \n\n"; + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_UseDispenser(self, self.building); + return; + } + if ((self.building.ammo_shells > 0 && self.ammo_shells < self.maxammo_shells) || (self.building.ammo_nails > 0 && self.ammo_nails < self.maxammo_nails) || (self.building.ammo_rockets > 0 && self.ammo_rockets < self.maxammo_rockets) @@ -1142,6 +1182,13 @@ void (float inp) Menu_Engineer_Cancel_Input = { } void () Menu_Engineer_Cancel = { + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Build(self); + return; + } local string s_build = "Building...\n\n"; local string s_cancel = Q"\s[1]\s Cancel!\n\n\n\n\n"; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 72edbab6..adb6cb05 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -877,6 +877,9 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { // prepare disguise if (!pe_player.undercover_team) sprint(pe_player, PRINT_HIGH, "Going undercover...\n"); + else if(pe_player.undercover_skin != pf_class) + sprint(pe_player, PRINT_HIGH, "Changing costumes...\n"); + pe_player.is_undercover = 2; pe_player.disguise_skin = pf_class; pe_player.disguise_team = 0; From 82cf3a392b5d10c33e3039c24b70a16354a958c2 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 5 Nov 2019 21:07:25 +1100 Subject: [PATCH 0833/2474] initial attempt, non working --- ssqc/q3.qc | 3 +-- ssqc/triggers.qc | 63 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/ssqc/q3.qc b/ssqc/q3.qc index d73e5133..c4d4eaf5 100644 --- a/ssqc/q3.qc +++ b/ssqc/q3.qc @@ -156,8 +156,7 @@ void () target_kill = { info_tfgoal(); } -/* void () target_position = { self.classname = "info_notnull"; info_notnull(); -};*/ \ No newline at end of file +}; \ No newline at end of file diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index be6f25ef..7781ae61 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -501,18 +501,63 @@ void () trigger_push_touch = { } return; } - if (other.classname == "grenade") - other.velocity = self.speed * self.movedir * 10; - else if (other.health > 0) { - other.velocity = self.speed * self.movedir * 10; - if (other.classname == "player") { - if (other.fly_sound < time) { - other.fly_sound = time + 1.5; - sound(other, CHAN_AUTO, "ambience/windfly.wav", 1, - ATTN_NORM); + + if (self.target) + { + float height, gravity, airtime; + vector org, targorg, dist, forward, origin2; + + entity ent = find(world, targetname, self.target); + if (!ent) + { + dprint("no targ found\n"); + return; + } + org = self.origin; + org_x = 0; + org_y = 0; + targorg = ent.origin; + targorg_x = 0; + targorg_y = 0; + height = vlen(org - targorg); + gravity = cvar("sv_gravity"); + airtime = sqrt(height / (.5 * gravity)); + + if (!airtime) + { + dprint("airtime is 0\n"); + return; + } + + origin2 = ent.origin - self.origin; + origin2_z = 0; + dist = normalize(origin2); + + forward = dist / airtime; + // scale forward direction to velocity??? + origin2_x = origin2_x * forward_x; + origin2_y = origin2_y * forward_y; + origin2_z = airtime * gravity; + + other.velocity = origin2; + + } + else + { + if (other.classname == "grenade") + other.velocity = self.speed * self.movedir * 10; + else if (other.health > 0) { + other.velocity = self.speed * self.movedir * 10; + if (other.classname == "player") { + if (other.fly_sound < time) { + other.fly_sound = time + 1.5; + sound(other, CHAN_AUTO, "ambience/windfly.wav", 1, + ATTN_NORM); + } } } } + if (self.spawnflags & PUSH_ONCE) dremove(self); }; From 59ad55c0cd36c8031d791a4510c746d2da08edc5 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 6 Nov 2019 00:23:25 +1300 Subject: [PATCH 0834/2474] spy manual team select option --- csqc/menu.qc | 53 ++++++++++++++++++++++++++++++++++++++++----- share/commondefs.qc | 2 +- ssqc/commands.qc | 27 ++++++++++++++++++----- ssqc/menu.qc | 25 +++++++++++++-------- ssqc/tforthlp.qc | 2 +- 5 files changed, 86 insertions(+), 23 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index 0063f94f..497bdd64 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -142,7 +142,13 @@ var fo_menu FO_MENU_SPY = { {"4","Reset Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise none\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - }, 7, TRUE + MenuSpacer, + {"0","Manual Colour Changes","","",FO_MENU_STATE_NORMAL,{ + local float smt = !stof(getplayerkeyvalue(player_localnum, "smt")); + localcmd("setinfo smt ", ftos(smt), "\n"); + FO_MENU_SPY.options[8].value = (smt?"on":"off"); + },MENU_BUTTON}, + }, 9, TRUE }; var fo_menu FO_MENU_SPY_SKIN = { [0,0], [300,200], "Disguise as enemy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { @@ -217,7 +223,7 @@ var fo_menu FO_MENU_BUILD = { vector org = (vector)getentity(player_localentnum, GE_ORIGIN); if(SBAR.HasSentry) { FO_MENU_BUILD.options[0].state = FO_MENU_STATE_HIDDEN; //Build - if(vlen(org - sentry_pos) <= ENG_BUILDING_DISMANGLE_DISTANCE) { + if(vlen(org - sentry_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { FO_MENU_BUILD.options[2].state = FO_MENU_STATE_HIDDEN; //Destroy FO_MENU_BUILD.options[3].state = FO_MENU_STATE_NORMAL; //Dismantle } else { @@ -235,7 +241,7 @@ var fo_menu FO_MENU_BUILD = { } if(SBAR.HasDispenser) { FO_MENU_BUILD.options[1].state = FO_MENU_STATE_HIDDEN; - if(vlen(org - dispenser_pos) <= ENG_BUILDING_DISMANGLE_DISTANCE) { + if(vlen(org - dispenser_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { FO_MENU_BUILD.options[4].state = FO_MENU_STATE_HIDDEN; FO_MENU_BUILD.options[5].state = FO_MENU_STATE_NORMAL; } else { @@ -253,6 +259,22 @@ var fo_menu FO_MENU_BUILD = { } } }; +var fo_menu FO_MENU_SENTRY_MAINTAIN = { + [0,0], [300,200], "Sentry Gun", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, + {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 5, TRUE, { + vector org = (vector)getentity(player_localentnum, GE_ORIGIN); + if(vlen(org - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { + Menu_Cancel(); + return; + } + } +}; + var fo_menu FO_MENU_SENTRY_ROTATE = { [0,0], [300,200], "Rotate Sentry Gun", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, @@ -297,6 +319,21 @@ var fo_menu FO_MENU_DISPENSER_USE = { } } }; +var fo_menu FO_MENU_ADMIN_MAIN = { + [0,0], [300,200], "Server Admin", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + {"1","Ceasefire","","",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");Menu_Cancel();},MENU_BUTTON}, + {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armour\n");},MENU_BUTTON}, + {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armour\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 4, TRUE, { + vector org = (vector)getentity(player_localentnum, GE_ORIGIN); + if(vlen(org - touched_dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { + Menu_Cancel(); + return; + } + } +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; @@ -656,20 +693,24 @@ void FO_Menu_Spy(float force) = { } FO_MENU_SPY.options[4].state = (SBAR.IsUndercover?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN); } + local float smt = stof(getplayerkeyvalue(player_localnum, "smt")); + FO_MENU_SPY.options[8].value = (smt?"on":"off"); CurrentMenu = &FO_MENU_SPY; fo_hud_menu_active = TRUE; } void FO_Menu_Spy_Team(float force) = { + print("MEHT: client-side spy team menu\n"); if(fo_hud_menu_active && !force) return; if(team_no) { - if(number_of_teams < 2 || team_no >= number_of_teams) { + if(number_of_teams < 2 || team_no > number_of_teams) { return; } for(float i = 0; i < 4; i++) { - if((i + 1) == team_no) { - FO_MENU_SPY_TEAM.options[i].state = FO_MENU_STATE_HIDDEN; + //if((i + 1) == SBAR.DisguiseTeam || i >= number_of_teams) { + if(i >= number_of_teams) { + FO_MENU_SPY_TEAM.options[i].state = FO_MENU_STATE_DISABLED; } else { FO_MENU_SPY_TEAM.options[i].state = FO_MENU_STATE_NORMAL; } diff --git a/share/commondefs.qc b/share/commondefs.qc index f8844741..71884910 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,5 +1,5 @@ #define MAX_FLAGINFO_LINES 10 -#define ENG_BUILDING_DISMANGLE_DISTANCE 100 +#define ENG_BUILDING_DISMANTLE_DISTANCE 100 #define ENG_BUILDING_MAINT_DISTANCE 80 #define ENG_DISPENSER_COST 100 #define ENG_SENTRY_COST 130 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index c2cfe6d2..93c0fe50 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1,6 +1,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num, processedCmd, inp; local string tmp; + local float farg3; processedCmd = FALSE; if (arg1) @@ -165,13 +166,27 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Spy_Input(4); break; } - if(arg2 == "skin" && arg3) { - Menu_Spy_Skin_Input(stof(arg3)); + if(arg2 == "skin") { + if(arg3) { + Menu_Spy_Skin_Input(stof(arg3)); + } else { + Menu_Spy_Skin(); + } break; } - if(arg2 == "team" && arg3) { - Menu_Spy_Color_Input(stof(arg3)); - break; + if(arg2 == "team") { + if(arg3) { + //Menu_Spy_Color_Input(stof(arg3)); + farg3 = stof(arg3); + if (farg3 > 0 && farg3 <= number_of_teams) + CF_Spy_ChangeColor(self, farg3); + else + Menu_Spy_Input(1); + break; + } else { + Menu_Spy_Color(); + break; + } } sprint(self, PRINT_HIGH, "Invalid choice. Please use values 'none', 'last', 'skin #' or 'team #'.\n"); } else { @@ -339,7 +354,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } if (arg2 && arg3) { if(arg2 == "rotate") { - local float farg3 = stof(arg3); + farg3 = stof(arg3); if(farg3 < 0) { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); } else { diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 576a8b34..4347b3e8 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -655,14 +655,19 @@ void (float inp) Menu_Spy_Skin_Input = { if (self.skin != inp) CF_Spy_ChangeSkin(self, inp); - if (number_of_teams == 1) - sprint(self, PRINT_HIGH, "There is no other team\n"); - else if (number_of_teams > 2) + if(infokeyf(self, "smt")) { + sprint(self, PRINT_HIGH, "MEHT: smt set, forcing colour menu\n"); Menu_Spy_Color(); - else if (self.team_no == 1) - CF_Spy_ChangeColor(self, 2); - else - CF_Spy_ChangeColor(self, 1); + } else { + if (number_of_teams == 1) + sprint(self, PRINT_HIGH, "There is no other team\n"); + else if (number_of_teams > 2) + Menu_Spy_Color(); + else if (self.team_no == 1) + CF_Spy_ChangeColor(self, 2); + else + CF_Spy_ChangeColor(self, 1); + } }; @@ -722,7 +727,9 @@ void () Menu_Spy_Color = { return; } + sprint(self, PRINT_HIGH, "MEHT: showing colour menu\n"); if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + sprint(self, PRINT_HIGH, "MEHT: csqc active\n"); //fte+csqc has its own team menu //ask the client to activate it Menu_Close(self); @@ -825,7 +832,7 @@ void (float inp) Menu_Engineer_Input = { TeamFortress_Build(1); if (inp == 3 && self.has_sentry) { - te = findradius(self.origin, ENG_BUILDING_DISMANGLE_DISTANCE); + te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); while (te) { if (te.classname == "building_sentrygun") { if (te.real_owner == self){ @@ -845,7 +852,7 @@ void (float inp) Menu_Engineer_Input = { } if (inp == 4 && self.has_dispenser) { - te = findradius(self.origin, ENG_BUILDING_DISMANGLE_DISTANCE); + te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); while (te) { if (te.classname == "building_dispenser") { if (te.real_owner == self) { diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index c1621d27..f8625141 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -216,7 +216,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo - } else if (self.motd == 400 && self.team_no == 0) { + } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { Menu_Team(1); } From a57386a21e5d8916b03acb72ff98363f18de910a Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 5 Nov 2019 23:05:57 +1100 Subject: [PATCH 0835/2474] finish bounce pads --- ssqc/triggers.qc | 112 +++++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 42 deletions(-) diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 7781ae61..0af1323d 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -502,45 +502,13 @@ void () trigger_push_touch = { return; } - if (self.target) + if (self.target) // this could test for movedir but i want to be explicit, it's a bounce pad { - float height, gravity, airtime; - vector org, targorg, dist, forward, origin2; - - entity ent = find(world, targetname, self.target); - if (!ent) - { - dprint("no targ found\n"); - return; - } - org = self.origin; - org_x = 0; - org_y = 0; - targorg = ent.origin; - targorg_x = 0; - targorg_y = 0; - height = vlen(org - targorg); - gravity = cvar("sv_gravity"); - airtime = sqrt(height / (.5 * gravity)); - - if (!airtime) + if (other.classname == "grenade" || other.health > 0) { - dprint("airtime is 0\n"); - return; + sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); + other.velocity = self.movedir; } - - origin2 = ent.origin - self.origin; - origin2_z = 0; - dist = normalize(origin2); - - forward = dist / airtime; - // scale forward direction to velocity??? - origin2_x = origin2_x * forward_x; - origin2_y = origin2_y * forward_y; - origin2_z = airtime * gravity; - - other.velocity = origin2; - } else { @@ -551,8 +519,7 @@ void () trigger_push_touch = { if (other.classname == "player") { if (other.fly_sound < time) { other.fly_sound = time + 1.5; - sound(other, CHAN_AUTO, "ambience/windfly.wav", 1, - ATTN_NORM); + sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); } } } @@ -562,6 +529,45 @@ void () trigger_push_touch = { dremove(self); }; +void trigger_push_setup() +{ + /* + this is based off of ioq3 gpl code + https://github.com/ioquake/ioq3 + void AimAtTarget( gentity_t *self ) + */ + float height, gravity, airtime, dist, forward; + vector org, targorg, origin2; + + org = (self.absmin + self.absmax) * .5; + + entity ent = find(world, targetname, self.target); + if (!ent) + { + return; + } + + targorg = ent.origin; + height = targorg_z - org_z; + gravity = cvar("sv_gravity"); + airtime = sqrt(height / (.5 * gravity)); + + if (!airtime) + { + return; + } + + origin2 = ent.origin - org; + origin2_z = 0; + dist = vlen(origin2); + origin2 = normalize(origin2); + + forward = dist / airtime; + origin2 = origin2 * forward; + origin2_z = airtime * gravity; + self.movedir = origin2; +} + void () trigger_push = { if (CheckExistence() == FALSE) { dremove(self); @@ -569,11 +575,33 @@ void () trigger_push = { } InitTrigger(); - precache_sound("ambience/windfly.wav"); - self.touch = trigger_push_touch; + if (self.target) + { + // the target ent might not be processed yet, so we do setup after map starts + self.think = trigger_push_setup; + self.nextthink = time + 1; + } + else + { + if (!self.speed) + self.speed = 1000; + } + + if (!self.noise) + { + if (self.target) + { + // bound pads + self.noise = "world/bouncepad.wav"; + } + else + { + self.noise = "ambience/windfly.wav"; + } + } - if (!self.speed) - self.speed = 1000; + precache_sound(self.noise); + self.touch = trigger_push_touch; }; void () trigger_monsterjump_touch = { From 607f5f0ff1daed8342e77e7b52759aa93efa66ec Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 5 Nov 2019 23:09:05 +1100 Subject: [PATCH 0836/2474] not sure why this was renamed --- ssqc/q3.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/ssqc/q3.qc b/ssqc/q3.qc index c4d4eaf5..06adfac6 100644 --- a/ssqc/q3.qc +++ b/ssqc/q3.qc @@ -157,6 +157,4 @@ void () target_kill = { } void () target_position = { - self.classname = "info_notnull"; - info_notnull(); }; \ No newline at end of file From 597b8a55cf0b003655cc8f79a64e286b3f9ea183 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 6 Nov 2019 14:51:53 +1100 Subject: [PATCH 0837/2474] enable q3f detpack ents from last resort --- share/defs.h | 7 +++ ssqc/demoman.qc | 21 ++++++-- ssqc/misc.qc | 17 ++++++ ssqc/q3.qc | 136 +++++++++++++++++++++++++++++++++++++++++++----- ssqc/q3defs.qc | 9 +++- 5 files changed, 172 insertions(+), 18 deletions(-) diff --git a/share/defs.h b/share/defs.h index 8213a067..0c4965d4 100644 --- a/share/defs.h +++ b/share/defs.h @@ -114,6 +114,13 @@ #define STATE_UP 2 #define STATE_DOWN 3 +// q3 states +#define STATE_NONE 0 +#define STATE_DISABLED 4 +#define STATE_INACTIVE 5 +#define STATE_ACTIVE 6 +#define STATE_INVISIBLE 7 + #define VEC_ORIGIN '0 0 0' #define VEC_HULL_MIN '-16 -16 -24' #define VEC_HULL_MAX '16 16 32' diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 15ac9984..57f1323c 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -16,6 +16,7 @@ void () TeamFortress_DetpackExplode; void () TeamFortress_DetpackTouch; void () TeamFortress_DetpackDisarm; void () TeamFortress_DetpackCountDown; +void CheckStateQ3Goal(entity trig); float (float force) TeamFortress_DetonatePipebombs = { local entity e; @@ -322,11 +323,9 @@ void () TeamFortress_DetpackExplode = { self.owner.detpack_left = 0; bprint(PRINT_MEDIUM, "FIRE IN THE HOLE!\n"); sound(self, CHAN_WEAPON, "weapons/detpack.wav", 1, ATTN_NONE); - pos = pointcontents(self.origin); if ((pos != CONTENT_SOLID) && (pos != CONTENT_SKY) && (self.owner.has_disconnected != 1)) { - deathmsg = DMSG_DETPACK; head = findradius(self.origin, 1500); while (head) { @@ -344,8 +343,22 @@ void () TeamFortress_DetpackExplode = { } } } - } else if (head.takedamage && - (vlen((head.origin - self.origin)) <= 700)) { + } + else if (head.classname == "info_notnull") + { + // q3 detpackable goals + if (strstrofs(head.flagsq3, "chargeable") >= 0) + { + traceline(self.origin, head.origin, 1, self); + if (trace_fraction == 1) + { + CheckStateQ3Goal(head); + } + } + } + else if (head.takedamage && + (vlen((head.origin - self.origin)) <= 700)) + { org = head.origin + (head.mins + head.maxs) * 0.5; points = 0.5 * vlen(self.origin - org); if (points < 0) diff --git a/ssqc/misc.qc b/ssqc/misc.qc index 8e78724b..407d9af1 100644 --- a/ssqc/misc.qc +++ b/ssqc/misc.qc @@ -1,9 +1,26 @@ +float GetQ3State(string st); void () info_null = { dremove(self); }; void () info_notnull = { + self.state = GetQ3State(self.initialstate); + + for (int i = 1; i < (tokenize(__fullspawndata) - 1); i += 2) { + switch (argv(i)) { + case "flags": + string s = argv(i + 1); + if (s == "chargeable") + { + self.flagsq3 = s; + self.flags = FL_FINDABLE_NONSOLID; + } + break; + default: + break; + } + } }; void () light_use = { diff --git a/ssqc/q3.qc b/ssqc/q3.qc index 06adfac6..23b1a58f 100644 --- a/ssqc/q3.qc +++ b/ssqc/q3.qc @@ -12,6 +12,113 @@ string (string s) prepq3fstring = { return (ret); } +float GetQ3State(string st) +{ + float stf = 0; + st = strtrim(prepq3fstring(st)); + + switch (st) + { + case "disabled": + stf = STATE_DISABLED; + break; + case "inactive": + stf = STATE_INACTIVE; + break; + case "active": + stf = STATE_ACTIVE; + break; + case "invisible": + stf = STATE_INVISIBLE; + break; + } + return stf; +} + +void ActivateQ3Goal(entity trig, float active) +{ + string msg = ""; + string targets = ""; + if (active) + { + msg = prepq3fstring(trig.active_all_message); + targets = trig.activetarget; + } + else + { + //msg = prepq3fstring(trig.active_all_message); + targets = trig.failtarget; + } + if (msg != "") + bprint(PRINT_HIGH, msg, "\n"); + + float count = tokenizebyseparator(targets, ","); + for (float i = 0; i <= count; i++) + { + string s = argv(i); + float count2 = tokenizebyseparator(s, "="); + if (count2 >= 2) + { + string gname = argv(0); + float chkstate = GetQ3State(argv(1)); + entity targ = find(world, groupname, gname); + while (targ) + { + if (targ.state == STATE_INVISIBLE && targ.state != chkstate) + { + setmodel(targ, targ.mdl); + } + targ.state = chkstate; + msg = ""; + switch(chkstate) + { + case STATE_INVISIBLE: + targ.mdl = targ.model; + setmodel(targ, ""); + break; + case STATE_DISABLED: + msg = prepq3fstring(targ.disabled_all_message); + break; + } + if (msg != "") + { + bprint(PRINT_HIGH, msg, "\n"); + } + targ = find(targ, groupname, gname); + } + } + tokenizebyseparator(targets, ","); + } +} + +void CheckStateQ3Goal(entity trig) +{ + float count = tokenizebyseparator(trig.checkstate, ","); + float triggered = TRUE; + for (float i = 0; i <= count; i++) + { + string s = argv(i); + float count2 = tokenizebyseparator(s, "="); + if (count2 >= 2) + { + string gname = argv(0); + float chkstate = GetQ3State(argv(1)); + + entity targ = find(world, groupname, gname); + if (!targ) + continue; + + if (targ.state != chkstate) + { + triggered = FALSE; + } + } + } + + ActivateQ3Goal(trig, triggered); +} + + // backpacks, cap points etc void () func_goalinfo = { self.classname = "info_tfgoal"; @@ -60,6 +167,8 @@ void () func_goalinfo = { loc = strstrofs(s, "="); gtype = substring(s, 0, loc); + if (gtype == "") + continue; gop = substring(s, loc, loc + 1); gamt = substring(s, loc + 1, slen); if (gop == "-") { @@ -67,38 +176,41 @@ void () func_goalinfo = { } else { val = stof(gamt); } - dprint(gtype); - dprint(gop); - dprint(gamt); switch (gtype) { case "health": self.health = val; - break; + break; case "armor": self.armorvalue = val; - break; + break; case "ammo_shells": self.ammo_shells = val; - break; - case "ammo_bullets": + break; + case "ammo_nails": self.ammo_nails = val; - break; + break; case "ammo_rockets": self.ammo_rockets = val; - break; + break; case "ammo_cells": self.ammo_cells = val; - break; + break; case "gren1": self.no_grenades_1 = val; - break; + break; case "gren2": self.no_grenades_2 = val; - break; + break; + case "ammo_medikit": + self.ammo_medikit = val; + break; default: dprint("gtype not found, discarding\n"); + dprint("gtype: ", gtype, "\n"); + dprint("gop: ", gop, "\n"); + dprint("gamt: ", gamt, "\n"); } } diff --git a/ssqc/q3defs.qc b/ssqc/q3defs.qc index 3c28a175..8c24f12d 100644 --- a/ssqc/q3defs.qc +++ b/ssqc/q3defs.qc @@ -6,7 +6,6 @@ .float teamscore; .string active_all_message; .string holding; -.string give; .string groupname; .string carried_all_message; .string carried_message; @@ -14,4 +13,10 @@ .string inactive_all_message; .string activetarget; .string checkstate; -.float active; \ No newline at end of file +.float active; +.string initialstate; +.string flagsq3; // .float flags already exists and q3 uses it as a string +.string failtarget; +.string disabled_all_message; + +string __fullspawndata; // due to flags/flagsq3 \ No newline at end of file From df167bd5d8dd62fcedd120e7796c3bd2527f9208 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 10 Nov 2019 14:39:49 +1300 Subject: [PATCH 0838/2474] fix engy maint menu not going away; client-side instant grentimer option; half of admin menu done --- csqc/csextradefs.qc | 35 +++++++++ csqc/events.qc | 13 +++- csqc/main.qc | 38 +++++++++ csqc/menu.qc | 99 +++++++++++++++++++----- menu/options_basic.qc | 7 +- share/commondefs.qc | 2 + ssqc/admin.qc | 4 +- ssqc/commands.qc | 174 +++++++++++++++++++++++++++--------------- ssqc/csmenu.qc | 14 ++++ ssqc/engineer.qc | 45 ++++++----- ssqc/menu.qc | 26 +++---- ssqc/tfort.qc | 2 +- ssqc/tforthlp.qc | 24 ++++-- 13 files changed, 357 insertions(+), 126 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e6038df7..115dd65e 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -3,6 +3,8 @@ vector MENU_BG = '0.2 0.3 0.4'; vector MENU_BG_DARK = '0.1 0.15 0.2'; vector MENU_BORDER = '0.3 0.4 0.5'; +vector MENU_BG_WARNING = '0.4 0.3 0.2'; +vector MENU_BORDER_WARNING = '0.5 0.4 0.3'; vector MENU_SELECTED = '0 1 0'; vector MENU_UNSELECTED = '1 0 0'; vector MENU_BUTTON = '0.3 0.4 0.5'; @@ -12,6 +14,7 @@ vector MENU_TEXT_2 = '0.7 0.75 0.75'; vector MENU_TEXT_3 = '1 1 0'; vector MENU_TEXT_4 = '0.8 0.5 0'; vector MENU_HIGHLIGHT = '1 1 1'; +vector MENU_TEXT_WARNING = '0.8 0 0'; vector MENU_DARKEN = '1 1 1'; vector MENU_TEXT_SMALL = '8 8 0'; @@ -128,6 +131,38 @@ typedef struct { } FO_SBAR; FO_SBAR SBAR; +typedef struct { + float ceasefire; + float pubmode; + float clanmode; + float quadmode; + float duelmode; + float quad_rounds; + float quad_round_time; + float captainmode; + float timelimit; + float fraglimit; + float class_override; + float class_limit_scout; + float class_limit_sniper; + float class_limit_soldier; + float class_limit_demoman; + float class_limit_medic; + float class_limit_hwguy; + float class_limit_pyro; + float class_limit_spy; + float class_limit_engineer; + float spurs_on; + float spurs_scout; + float spurs_spy; + float spurs_engineer; + float spurs_duration; + float spurs_boost; + float spurs_consume; + float spurs_flag; +} SERVER_SETTINGS; +SERVER_SETTINGS SERVER_ADMIN; + typedef struct { float x; diff --git a/csqc/events.qc b/csqc/events.qc index 426b3b97..7c7392c3 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -96,8 +96,11 @@ void() CSQC_Parse_Event = { break; case MSG_GRENPRIMED: float grentype = readfloat(); - AddGrenTimer(grentype); - if(cvar(FOCMD_GRENTIMER) == 1) { + float timertype = cvar(FOCMD_GRENTIMER); + if(timertype != 2) { + AddGrenTimer(grentype); + } + if(timertype == 1) { localcmd("play grentimer.wav\n"); } break; @@ -165,6 +168,9 @@ void() CSQC_Parse_Event = { touched_dispenser_pos = [readfloat(),readfloat(),readfloat()]; FO_Menu_Dispenser_Use(FALSE); break; + case CLIENT_MENU_ADMIN: + FO_Menu_Admin_Main(TRUE); + break; } break; case MSG_CLASSES_UPDATE: @@ -191,6 +197,9 @@ void() CSQC_Parse_Event = { case MSG_DISPENSER_POS: dispenser_pos = [readfloat(),readfloat(),readfloat()]; break; + case MSG_SERVER_ADMIN_INFO: + SERVER_ADMIN.ceasefire = readbyte(); + break; } } diff --git a/csqc/main.qc b/csqc/main.qc index 756ee93f..e96501a5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -4,6 +4,7 @@ void FO_Hud_Editor_LoadSettings(); void FO_Hud_Editor_LoadDefaultSettings(); void FO_LoadSettings(); void FO_WriteSettings(); +void AddGrenTimer(float grentype); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -26,7 +27,13 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_GRENTIMER, "1"); registercommand("fo_menu_game"); registercommand("fo_main_menu"); + registercommand("fo_menu_admin"); + registercommand("primeone"); + registercommand("primetwo"); + registercommand("gren1"); + registercommand("gren2"); + FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -94,6 +101,37 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("menu_main\n"); } break; + case "fo_menu_admin": + FO_Menu_Admin_Main(TRUE); + break; + case "primeone": + if(cvar(FOCMD_GRENTIMER) == 2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(1); + } + localcmd("primeone_server"); + break; + case "primetwo": + if(cvar(FOCMD_GRENTIMER) == 2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(2); + } + localcmd("primetwo_server"); + break; + case "gren1": + if(cvar(FOCMD_GRENTIMER) == 2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(1); + } + localcmd("gren1_server"); + break; + case "gren2": + if(cvar(FOCMD_GRENTIMER) == 2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(2); + } + localcmd("gren2_server"); + break; } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index 497bdd64..be211165 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -2,13 +2,19 @@ #define FO_MENU_FLAG_CENTER 2 #define FO_MENU_FLAG_SHOW_SHORTCUTS 4 #define FO_MENU_FLAG_SHOW_VALUES 8 +#define FO_MENU_FLAG_WARNING 16 #define FO_MENU_STATE_HIDDEN 0 #define FO_MENU_STATE_NORMAL 1 #define FO_MENU_STATE_DISABLED 2 #define FO_MENU_STATE_SPACER 3 +#define FO_MENU_TRANSPARENCY 0.2 + void (float force) FO_Menu_Build; +void (float force) FO_Menu_Admin_Main; +void (float force) FO_Menu_Admin_Modes; +void (float force) FO_Menu_Admin_Settings; typedef struct { string shortcut; //key to press. if omitted - mouse only @@ -320,21 +326,54 @@ var fo_menu FO_MENU_DISPENSER_USE = { } }; var fo_menu FO_MENU_ADMIN_MAIN = { - [0,0], [300,200], "Server Admin", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Ceasefire","","",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");Menu_Cancel();},MENU_BUTTON}, - {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armour\n");},MENU_BUTTON}, - {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armour\n");Menu_Cancel();},MENU_BUTTON}, + [0,0], [300,300], "Server Admin [1/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","Ceasefire","","",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");},MENU_BORDER_WARNING}, + {"2","Kick...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"3","Ban...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"4","Force Spectate...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd randomise\n");},MENU_BORDER_WARNING}, + {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd restart\n"); Menu_Cancel();},MENU_BORDER_WARNING}, MenuSpacer, - {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - }, 4, TRUE, { - vector org = (vector)getentity(player_localentnum, GE_ORIGIN); - if(vlen(org - touched_dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { - Menu_Cancel(); - return; - } + {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"+","Next - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, + {"-","Prev - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, + }, 11, TRUE, { + FO_MENU_ADMIN_MAIN.options[0].value = SERVER_ADMIN.ceasefire?"on":"off"; } }; - +var fo_menu FO_MENU_ADMIN_MODES = { + [0,0], [300,300], "Server Modes [2/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","Pub Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd pubmode\n");},MENU_BORDER_WARNING}, + {"2","Clan Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd clanmode\n");},MENU_BORDER_WARNING}, + {"3","Quad Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd quadmode\n");},MENU_BORDER_WARNING}, + {"4","Duel Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, + {"5","Quad Rounds...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"6","Quad Round Time...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"7","Captains Mode","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"8","Force Start","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, + MenuSpacer, + {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"+","Next - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, + {"-","Prev - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + }, 13, TRUE +}; +var fo_menu FO_MENU_ADMIN_SETTINGS = { + [0,0], [300,300], "Settings [3/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","Timelimit","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"3","Override Classes","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"4","Class Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"5","Spurs","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"6","Spur Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + MenuSpacer, + {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"+","Next - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + {"-","Prev - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, + }, 11, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; InProgressMenu.size = size; @@ -401,6 +440,8 @@ vector fo_menu_draw(fo_menu * menu) = { local string id = strcat("fo_menu_",menu.title); local vector tempcolour; local float alignment = SUI_ALIGN_START; + local vector bgcolour = (menu.flags & FO_MENU_FLAG_WARNING)?MENU_BG_WARNING:MENU_BG; + local vector bordercolour = (menu.flags & FO_MENU_FLAG_WARNING)?MENU_BORDER_WARNING:MENU_BORDER; menusize.y = titleoffset + menu.num_opts * (buttonsize.y + padding); @@ -409,10 +450,10 @@ vector fo_menu_draw(fo_menu * menu) = { } - sui_border_box(position, menusize, 1, MENU_BORDER, 0.4, 0); + sui_border_box(position, menusize, 1, bordercolour, FO_MENU_TRANSPARENCY, 0); sui_push_frame(position, menusize); - sui_fill([0, 0], menusize, MENU_BG, 0.4, 0); + sui_fill([0, 0], menusize, bgcolour, FO_MENU_TRANSPARENCY, 0); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); sui_action_element([0, 0], menusize, id, sui_noop); @@ -422,7 +463,7 @@ vector fo_menu_draw(fo_menu * menu) = { position + [menusize.x / 2 - stringwidth(menu.title,1,mediumtext)/2,padding*2], menu.title, mediumtext, - MENU_TEXT_2, + (menu.flags & FO_MENU_FLAG_WARNING)?MENU_TEXT_WARNING:MENU_TEXT_2, 1, 0 ); @@ -451,8 +492,8 @@ vector fo_menu_draw(fo_menu * menu) = { } } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { if(menu.options[i].name) { - //sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, MENU_BG, 0.4, 0); - sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, 1, MENU_BG, 0.4, 0); + //sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, bgcolour, 0.4, 0); + sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, 1, bgcolour, 0.4, 0); float disabledtextoffset = 0; if(alignment == SUI_ALIGN_START) { disabledtextoffset = padding + shortcutoffset.x; @@ -700,7 +741,6 @@ void FO_Menu_Spy(float force) = { } void FO_Menu_Spy_Team(float force) = { - print("MEHT: client-side spy team menu\n"); if(fo_hud_menu_active && !force) return; if(team_no) { @@ -786,3 +826,26 @@ void FO_Menu_Dispenser_Use(float force) = { } fo_hud_menu_active = TRUE; } +void FO_Menu_Admin_Main(float force) = { + if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_ADMIN_MAIN || CurrentMenu == &FO_MENU_ADMIN_MODES || CurrentMenu == &FO_MENU_ADMIN_SETTINGS)) { + Menu_Cancel(); + return; + } + if(fo_hud_menu_active && !force) + return; + localcmd("cmd adminrefresh\n"); + CurrentMenu = &FO_MENU_ADMIN_MAIN; + fo_hud_menu_active = TRUE; +} +void FO_Menu_Admin_Modes(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_MODES; + fo_hud_menu_active = TRUE; +} +void FO_Menu_Admin_Settings(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_SETTINGS; + fo_hud_menu_active = TRUE; +} diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 740f5c45..31c120cd 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -127,7 +127,12 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = fr.add(menuitemslider_spawn(_("Crosshair"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcheck_spawn (_("Show Speed"), "show_speed", '280 8'), fl, [0, pos], [0, 8]); pos += 8; pos += 8; - fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( + "0 \"None\" " + "1 \"Server\" " + "2 \"Immediate\" " + )), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; diff --git a/share/commondefs.qc b/share/commondefs.qc index 71884910..cc816249 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -15,6 +15,7 @@ #define MSG_CLASSES_UPDATE 8 #define MSG_SENTRY_POS 9 #define MSG_DISPENSER_POS 10 +#define MSG_SERVER_ADMIN_INFO 11 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 @@ -42,3 +43,4 @@ #define CLIENT_MENU_ROTATE_SENTRY 10 #define CLIENT_MENU_FIX_DISPENSER 11 #define CLIENT_MENU_USE_DISPENSER 12 +#define CLIENT_MENU_ADMIN 13 diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 1f73725c..5569037c 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -1,5 +1,6 @@ void (entity p) BanCheater; +void (string halias, string commands) TeamFortress_AliasString; void () Admin_CountPlayers = { local string st; @@ -286,7 +287,8 @@ void () Admin_Aliases = TeamFortress_Alias("listips", TF_ADMIN_LISTIPS, 0); TeamFortress_Alias("clan", TF_ADMIN_CLANMODE, 0); TeamFortress_Alias("quadmode", TF_ADMIN_QUADMODE, 0); - TeamFortress_Alias("adminmenu", TF_ADMIN_ADMINMENU, 0); + //TeamFortress_Alias("adminmenu", TF_ADMIN_ADMINMENU, 0); + TeamFortress_AliasString("adminmenu", "cmd adminmenu"); TeamFortress_Alias("startmatch", TF_ADMIN_FORCESTARTMATCH, 0); TeamFortress_Alias("readystatus", TF_ADMIN_READYSTATUS, 0); stuffcmd(self,"alias ceasefire \"cmd ceasefire\"\n"); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 93c0fe50..500cf15a 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1,3 +1,84 @@ +void () RestartMap = { + bprint(PRINT_HIGH, self.netname); + bprint(PRINT_HIGH, " Has restarted the map.\n"); + + localcmd ("map "); + localcmd (mapname); + localcmd ("\n"); +} + +void () ForceStartMatch = { + if (clanbattle == 1 && cb_prematch == 1) { + bprint(PRINT_HIGH, self.netname); + bprint(PRINT_HIGH, " has forced the match start.\n"); + StartTimer(); + } +} + +void () QuadMode = +{ + localcmd ("localinfo clan on\n"); + localcmd ("localinfo quadmode on\n"); + localcmd ("localinfo duelmode off\n"); + localcmd ("localinfo rounds 2\n"); + localcmd ("timelimit 0\n"); + localcmd ("localinfo round_time 10\n"); + localcmd ("localinfo round_delay_time 30\n"); + localcmd ("localinfo teamfrags on\n"); + localcmd ("localinfo fullteamscore off\n"); + localcmd ("fraglimit 0\n"); + localcmd ("localinfo rd 0\n"); + localcmd ("exec fo_quadmode.cfg\n"); + bprint (PRINT_HIGH, "Quad Mode set to on\n"); + bprint (PRINT_HIGH, "Map Restart needed to take effect!\n"); +}; + +void () ClanMode = +{ + localcmd("localinfo clan on\n"); + localcmd ("localinfo rd 0\n"); + localcmd ("exec fo_clanmode.cfg\n"); + bprint(PRINT_HIGH, "Clan Mode set to on\n"); + bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); +}; + +void () PubMode = +{ + localcmd ("localinfo clan off\n"); + localcmd ("localinfo quadmode off\n"); + localcmd ("localinfo duelmode off\n"); + localcmd ("localinfo teamfrags off\n"); + localcmd ("localinfo fullteamscore off\n"); + localcmd ("password none\n"); + localcmd ("localinfo rounds 0\n"); + localcmd ("timelimit 20\n"); + localcmd ("fraglimit 0\n"); + localcmd ("localinfo round_time 0\n"); + localcmd ("localinfo rd 0\n"); + localcmd ("exec fo_pubmode.cfg\n"); + bprint(PRINT_HIGH, "Pub Mode set to on\n"); + bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); +} + +void () DuelMode = +{ + localcmd ("localinfo teamfrags off\n"); + localcmd ("localinfo fullteamscore off\n"); + localcmd ("localinfo clan on\n"); + localcmd ("localinfo quadmode off\n"); + localcmd ("localinfo duelmode on\n"); + localcmd ("localinfo sf on\n"); // spawnfull, ie spawn fully stocked + localcmd ("localinfo drd 3.9\n"); // wait before resetting the winner long enough for grens to go off + localcmd ("localinfo rd 9999\n"); // wait before respawning the loser + localcmd ("localinfo dph 1\n"); // print health of duel survivors + localcmd ("password none\n"); + localcmd ("timelimit 0\n"); + localcmd ("fraglimit 30\n"); + localcmd ("exec fo_duelmode.cfg\n"); + bprint(PRINT_HIGH, "Duel Mode set to on\n"); + bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); +} + float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num, processedCmd, inp; local string tmp; @@ -407,6 +488,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { { switch (arg1) { + case "adminmenu": + processedCmd = TRUE; + Menu_Admin(); + break; case "timelimit": processedCmd = TRUE; if (arg_num == 2) { @@ -563,6 +648,30 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint (self, PRINT_HIGH, "\n"); } break; + case "restart": + RestartMap(); + break; + case "randomise": + randomizeTeams(); + break; + case "adminrefresh": + Update_ServerAdminInfo(self); + break; + case "pubmode": + PubMode(); + break; + case "clanmode": + ClanMode(); + break; + case "quadmode": + QuadMode(); + break; + case "duelmode": + DuelMode(); + break; + case "forcestart": + ForceStartMatch(); + break; case "help": case "list": processedCmd = TRUE; @@ -581,6 +690,8 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "cmd stop\n"); sprint(self, PRINT_HIGH, "cmd kick\n"); sprint(self, PRINT_HIGH, "cmd ceasefire\n"); + sprint(self, PRINT_HIGH, "cmd restart\n"); + sprint(self, PRINT_HIGH, "cmd randomise\n"); sprint(self, PRINT_HIGH, "cmd help || list (this command)\n"); sprint(self, PRINT_HIGH, "\n"); break; @@ -602,66 +713,3 @@ void (string cmd) SV_ParseClientCommand = { } } -void () QuadMode = -{ - localcmd ("localinfo clan on\n"); - localcmd ("localinfo quadmode on\n"); - localcmd ("localinfo duelmode off\n"); - localcmd ("localinfo rounds 2\n"); - localcmd ("timelimit 0\n"); - localcmd ("localinfo round_time 10\n"); - localcmd ("localinfo round_delay_time 30\n"); - localcmd ("localinfo teamfrags on\n"); - localcmd ("localinfo fullteamscore off\n"); - localcmd ("fraglimit 0\n"); - localcmd ("localinfo rd 0\n"); - localcmd ("exec fo_quadmode.cfg\n"); - bprint (PRINT_HIGH, "Quad Mode set to on\n"); - bprint (PRINT_HIGH, "Map Restart needed to take effect!\n"); -}; - -void () ClanMode = -{ - localcmd("localinfo clan on\n"); - localcmd ("localinfo rd 0\n"); - localcmd ("exec fo_clanmode.cfg\n"); - bprint(PRINT_HIGH, "Clan Mode set to on\n"); - bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); -}; - -void () PubMode = -{ - localcmd ("localinfo clan off\n"); - localcmd ("localinfo quadmode off\n"); - localcmd ("localinfo duelmode off\n"); - localcmd ("localinfo teamfrags off\n"); - localcmd ("localinfo fullteamscore off\n"); - localcmd ("password none\n"); - localcmd ("localinfo rounds 0\n"); - localcmd ("timelimit 20\n"); - localcmd ("fraglimit 0\n"); - localcmd ("localinfo round_time 0\n"); - localcmd ("localinfo rd 0\n"); - localcmd ("exec fo_pubmode.cfg\n"); - bprint(PRINT_HIGH, "Pub Mode set to on\n"); - bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); -} - -void () DuelMode = -{ - localcmd ("localinfo teamfrags off\n"); - localcmd ("localinfo fullteamscore off\n"); - localcmd ("localinfo clan on\n"); - localcmd ("localinfo quadmode off\n"); - localcmd ("localinfo duelmode on\n"); - localcmd ("localinfo sf on\n"); // spawnfull, ie spawn fully stocked - localcmd ("localinfo drd 3.9\n"); // wait before resetting the winner long enough for grens to go off - localcmd ("localinfo rd 9999\n"); // wait before respawning the loser - localcmd ("localinfo dph 1\n"); // print health of duel survivors - localcmd ("password none\n"); - localcmd ("timelimit 0\n"); - localcmd ("fraglimit 30\n"); - localcmd ("exec fo_duelmode.cfg\n"); - bprint(PRINT_HIGH, "Duel Mode set to on\n"); - bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); -} diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 0fecd085..03c82034 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -128,4 +128,18 @@ void UpdateClientMenu_UseDispenser(entity pl, entity disp) = { WriteFloat(MSG_MULTICAST, disp.origin.z); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMenu_Admin(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_ADMIN); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} +void Update_ServerAdminInfo(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_SERVER_ADMIN_INFO); + WriteByte(MSG_MULTICAST, is_paused || cease_fire); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 4dba5d37..a6fa0991 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -955,12 +955,14 @@ void () T_Dispenser = { if ((other.building == world) && (other.building_wait < time)) { other.building = self; - dist_checker = spawn(); - dist_checker.classname = "timer"; - dist_checker.owner = other; - dist_checker.enemy = self; - dist_checker.think = CheckDistance; - dist_checker.nextthink = time + 0.3; + if(!infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + dist_checker = spawn(); + dist_checker.classname = "timer"; + dist_checker.owner = other; + dist_checker.enemy = self; + dist_checker.think = CheckDistance; + dist_checker.nextthink = time + 0.3; + } oldself = self; self = other; Menu_Dispenser(); @@ -1038,12 +1040,14 @@ void (entity disp) Engineer_UseDispenser = { self.building = disp; Menu_EngineerFix_Dispenser(); - dist_checker = spawn(); - dist_checker.classname = "timer"; - dist_checker.owner = self; - dist_checker.enemy = disp; - dist_checker.think = CheckDistance; - dist_checker.nextthink = time + 0.3; + if(!infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + dist_checker = spawn(); + dist_checker.classname = "timer"; + dist_checker.owner = self; + dist_checker.enemy = disp; + dist_checker.think = CheckDistance; + dist_checker.nextthink = time + 0.3; + } }; void (entity disp) Engineer_Dispenser_InsertAmmo = { @@ -1160,7 +1164,8 @@ void (entity gun) Engineer_UseSentryGun = { // automate tasks if old_spanner setting is disabled if (!old_spanner) { if(gun.team_no > 0 && gun.team_no == self.team_no) { - Menu_EngineerFix_SentryGun_Rotate(); + //Menu_EngineerFix_SentryGun_Rotate(); + Engineer_SentryGun_ShowMenu(self.building); if (gun.weapon < 3 && self.ammo_cells >= ENG_SENTRY_COST) { Engineer_SentryGun_Upgrade(gun); return; @@ -1221,12 +1226,14 @@ void (entity gun) Engineer_UseSentryGun = { void (entity gun) Engineer_SentryGun_ShowMenu = { local entity dist_checker; - dist_checker = spawn(); - dist_checker.classname = "timer"; - dist_checker.owner = self; - dist_checker.enemy = gun; - dist_checker.think = CheckDistance; - dist_checker.nextthink = time + 0.3; + if(!infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + dist_checker = spawn(); + dist_checker.classname = "timer"; + dist_checker.owner = self; + dist_checker.enemy = gun; + dist_checker.think = CheckDistance; + dist_checker.nextthink = time + 0.3; + } Menu_EngineerFix_SentryGun(); }; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 4347b3e8..295d51d3 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -99,6 +99,7 @@ void () Admin_Pause; void () Admin_CeaseFire; void () Broadcast_Players_NotReady; void () StartTimer; +void () ForceStartMatch; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; @@ -115,6 +116,7 @@ void (entity pl) UpdateClientMenu_Build; void (entity pl) UpdateClientMenu_FixSentry; void (entity pl) UpdateClientMenu_FixDispenser; void (entity pl, entity disp) UpdateClientMenu_UseDispenser; +void (entity pl) UpdateClientMenu_Admin; void (entity pl) Menu_Close = { @@ -656,7 +658,6 @@ void (float inp) Menu_Spy_Skin_Input = { CF_Spy_ChangeSkin(self, inp); if(infokeyf(self, "smt")) { - sprint(self, PRINT_HIGH, "MEHT: smt set, forcing colour menu\n"); Menu_Spy_Color(); } else { if (number_of_teams == 1) @@ -727,9 +728,7 @@ void () Menu_Spy_Color = { return; } - sprint(self, PRINT_HIGH, "MEHT: showing colour menu\n"); if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - sprint(self, PRINT_HIGH, "MEHT: csqc active\n"); //fte+csqc has its own team menu //ask the client to activate it Menu_Close(self); @@ -1206,8 +1205,16 @@ void () ClanMode; void () QuadMode; void () PubMode; void () DuelMode; +void () RestartMap; void () Menu_Admin = { +// if(self.is_admin && infokeyf(self, INFOKEY_P_CSQCACTIVE)) { +// //fte+csqc has its own team menu +// //ask the client to activate it +// Menu_Close(self); +// UpdateClientMenu_Admin(self); +// return; +// } local string s_menu1; local string s_menu2; local string override; @@ -1562,12 +1569,7 @@ void (float inp) Menu_Admin_Input = break; case 7: // Restart Current Map Option - bprint(2, self.netname); - bprint(2, " Has restarted the map.\n"); - - localcmd ("map "); - localcmd (mapname); - localcmd ("\n"); + RestartMap(); break; } } @@ -1609,11 +1611,7 @@ void (float inp) Menu_Admin_Input = Menu_Close(self); return; case 7: // force match start - if (clanbattle == 1 && cb_prematch == 1) { - bprint(PRINT_HIGH, self.netname); - bprint(PRINT_HIGH, " has forced the match start.\n"); - StartTimer(); - } + ForceStartMatch(); Menu_Close(self); return; } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 6fa1d251..a2c6e2a4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -912,7 +912,7 @@ void (float inp) TeamFortress_PrimeGrenade = { timer.heat = 4; timer.owner = self; timer.classname = "gtimer"; - if (!notimers) { + if (!notimers && !csqcactive) { stuffcmd(self, "play grentimer\n"); } } diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index f8625141..46146a39 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -153,16 +153,26 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("reload3", TF_RELOAD_SLOT3, 0); TeamFortress_Alias("reloadnext", TF_RELOAD_NEXT, 0); } else if (self.motd == 70) { - TeamFortress_Alias("primeone", TF_GRENADE_1, 0); - TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); - TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); TeamFortress_Alias("grenswitch", TF_GRENADE_SWITCH, 0); - TeamFortress_Alias("+gren1", TF_GRENADE_1, 0); - TeamFortress_Alias("+gren2", TF_GRENADE_2, 0); + TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); TeamFortress_Alias("-gren1", TF_GRENADE_T, 0); TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); - TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); - TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); + //Don't send to fte - these are handled client-side + if(!csqcactive) { + TeamFortress_Alias("primeone", TF_GRENADE_1, 0); + TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); + TeamFortress_Alias("+gren1", TF_GRENADE_1, 0); + TeamFortress_Alias("+gren2", TF_GRENADE_2, 0); + TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); + TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); + } else { + TeamFortress_Alias("primeone_server", TF_GRENADE_1, 0); + TeamFortress_Alias("primetwo_server", TF_GRENADE_2, 0); + TeamFortress_Alias("gren1_server", TF_GRENADE_PT_1, 0); + TeamFortress_Alias("gren2_server", TF_GRENADE_PT_2, 0); + TeamFortress_AliasString("+gren1", "primeone"); + TeamFortress_AliasString("+gren2", "primetwo"); + } } else if (self.motd == 80) { TeamFortress_Alias("dash", TF_DASH, 0); TeamFortress_Alias("autoscan", TF_SCAN, 0); From b8bfdedfbe3aecc98fff36c80e90e045e4885439 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 11 Nov 2019 23:19:59 +1100 Subject: [PATCH 0839/2474] fix for q3 func_goalinfo not having field causing player name to spam on touch --- ssqc/tfortmap.qc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 25fa3ee9..6eccc973 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1404,9 +1404,8 @@ void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate = { if (cb_prematch) return; - // q3f support - if (Goal.checkstate != string_null) { + if (Goal.checkstate != "") { string cname, cstate; float slen, idx; entity targ; @@ -1715,7 +1714,7 @@ void () DelayedResult = { dremove(self); }; -void (entity Goal, entity AP, float addb) DoResults = { +void (entity Goal, entity AP, float addb) DoResults = { local entity te; local float winners; local float gotone; @@ -1933,7 +1932,7 @@ void (entity Goal, entity AP, float addb) DoResults = { if ((Goal.broadcast != string_null) && (CTF_Map == 0)) { CenterPrint2(te, "\n\n\n", Goal.broadcast); } - if ((Goal.netname_broadcast != string_null) && (CTF_Map == 0)) { + if ((strtrim(Goal.netname_broadcast) != "") && (CTF_Map == 0)) { sprint(te, PRINT_HIGH, AP.netname, Goal.netname_broadcast); } if (AP == te) { From ea90d829278881f9882989daec2fa6b200719f27 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 12 Nov 2019 22:54:01 +1300 Subject: [PATCH 0840/2474] kick/ban/forcespec admin menus in --- README.md | 6 +++ csqc/csextradefs.qc | 3 ++ csqc/events.qc | 3 ++ csqc/main.qc | 22 ++++++++ csqc/menu.qc | 124 ++++++++++++++++++++++++++++++++++++++++++-- share/commondefs.qc | 3 ++ ssqc/commands.qc | 71 ++++++++++++++++++++++++- ssqc/csmenu.qc | 8 +++ ssqc/menu.qc | 14 ++--- 9 files changed, 242 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 03aeed87..acababf9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ FortressOne Server v0.1.0 New features ------ +* CSQC - fo_main_menu main menu - either from menu.dat or engine +* CSQC - fo_menu_game in-game menu +* CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press +* CSQC - fo_autohop 0/1 enable bunnyhop assist +* CSQC - fo_hud_reset resets HUD to defaults +* CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config * `info_empblock` has a new field `goal_effects`. Setting it to 16 will prevent it from blocking emps if there is a wall between it and the explosion. * New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 115dd65e..467f9ba1 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -24,6 +24,7 @@ float MENU_START_CONTENT = 32; .float owned_by; .string netname; +.float playerid; float fo_hud_editor; float fo_hud_menu_active; float jumptime; @@ -34,6 +35,8 @@ float last_team; vector sentry_pos; vector dispenser_pos; vector touched_dispenser_pos; +//entity player_list_head; +float player_menu_type; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index 7c7392c3..0c9b6af8 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -171,6 +171,9 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_ADMIN: FO_Menu_Admin_Main(TRUE); break; + case CLIENT_MENU_ADMIN_KICK: + FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_KICK, 0); + break; } break; case MSG_CLASSES_UPDATE: diff --git a/csqc/main.qc b/csqc/main.qc index e96501a5..5c6d78a4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,6 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_game"); registercommand("fo_main_menu"); registercommand("fo_menu_admin"); + registercommand("meht_test"); registercommand("primeone"); registercommand("primetwo"); @@ -38,6 +39,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_LoadSettings(); CurrentMenu = &FO_MENU_TEAM; + player_menu_type = 0; }; noref void() CSQC_WorldLoaded = { @@ -132,6 +134,26 @@ noref float(string cmd) CSQC_ConsoleCommand = { } localcmd("gren2_server"); break; + case "meht_test": + float c = 0; + entity e = find(world, classname, "player"); + string n = ""; + while(e) { + print("MEHT: found player: ", ftos(e.entnum), "\n"); + c++; + e = find(e, classname, "player"); + } + print("MEHT: total players: ", ftos(c), "\n"); + c = 0; + for(float i = 0; i < 100; i++) { + n = getplayerkeyvalue(i,"name"); + if(n) { + print("MEHT: found player: ", n, " id: ", ftos(i) , " userid: ",getplayerkeyvalue(i, "userid"),"\n"); + c++; + } + } + print("MEHT: other total players: ", ftos(c), "\n"); + break; } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index be211165..b41c1d45 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -15,6 +15,7 @@ void (float force) FO_Menu_Build; void (float force) FO_Menu_Admin_Main; void (float force) FO_Menu_Admin_Modes; void (float force) FO_Menu_Admin_Settings; +void FO_Menu_Admin_Players(float force, float type, float page); typedef struct { string shortcut; //key to press. if omitted - mouse only @@ -35,6 +36,7 @@ typedef struct { float num_opts; float active; void() update; + float page; } fo_menu; class fo_menu_option_2 { @@ -328,9 +330,9 @@ var fo_menu FO_MENU_DISPENSER_USE = { var fo_menu FO_MENU_ADMIN_MAIN = { [0,0], [300,300], "Server Admin [1/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { {"1","Ceasefire","","",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");},MENU_BORDER_WARNING}, - {"2","Kick...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, - {"3","Ban...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, - {"4","Force Spectate...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"2","Kick...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_KICK, 0);},MENU_BORDER_WARNING}, + {"3","Ban...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_BAN, 0);},MENU_BORDER_WARNING}, + {"4","Force Spectate...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_FORCE_SPEC, 0);},MENU_BORDER_WARNING}, {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd randomise\n");},MENU_BORDER_WARNING}, {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd restart\n"); Menu_Cancel();},MENU_BORDER_WARNING}, MenuSpacer, @@ -374,6 +376,48 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { {"-","Prev - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, }, 11, TRUE }; +var void execute_admin_players(float choice, float page) { + print("not implemented ", ftos(choice + (page * 9)),"\n"); +} +void execute_admin_players_unknown(float choice, float page) { + print("not implemented ", ftos(choice + (page * 9)),"\n"); +} +void execute_admin_players_kick(float choice, float page) { + string userid = getplayerkeyvalue(choice + (page * 9), "userid"); + localcmd("cmd kick ", userid, "\n"); + Menu_Cancel(); + FO_Menu_Admin_Main(TRUE); +} +void execute_admin_players_ban(float choice, float page) { + string userid = getplayerkeyvalue(choice + (page * 9), "userid"); + localcmd("cmd ban ", userid, "\n"); + Menu_Cancel(); + FO_Menu_Admin_Main(TRUE); +} +void execute_admin_players_force_spec(float choice, float page) { + string userid = getplayerkeyvalue(choice + (page * 9), "userid"); + localcmd("cmd forcespec ", userid, "\n"); + Menu_Cancel(); + FO_Menu_Admin_Main(TRUE); +} +var fo_menu FO_MENU_ADMIN_PLAYERS = { + [0,0], [300,300], "Players", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(0, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"2","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(1, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"3","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(2, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"4","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(3, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"5","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(4, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"6","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(5, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"7","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(6, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"8","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(7, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + {"9","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(8, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + MenuSpacer, + {"+","Next","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Players(TRUE, player_menu_type, FO_MENU_ADMIN_PLAYERS.page + 1);},MENU_BUTTON}, + {"-","Prev","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Players(TRUE, player_menu_type, FO_MENU_ADMIN_PLAYERS.page - 1);},MENU_BUTTON}, + }, 14, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; InProgressMenu.size = size; @@ -849,3 +893,77 @@ void FO_Menu_Admin_Settings(float force) = { CurrentMenu = &FO_MENU_ADMIN_SETTINGS; fo_hud_menu_active = TRUE; } +void FO_Menu_Admin_Players(float force, float type, float page) = { + print("MEHT: FO_Menu_Admin_Players(", ftos(force), ", ", ftos(type), ", ", ftos(page), "\n"); + if(fo_hud_menu_active && !force) + return; + if(page < 0) { + //or(float i = 0; i < 100; i++) { + // if(!getplayerkeyvalue(i,"name")) { + // page = floor(i / 9); + // break; + // } + //} + page = 0; + } + //if(!(getplayerkeyvalue(page * 9,"name"))) page = 0; + if(page < 0) page = 4; + if(page > 4) page = 0; + FO_MENU_ADMIN_PLAYERS.page = page; + player_menu_type = type; + if(type == CLIENT_MENU_ADMIN_KICK) { + FO_MENU_ADMIN_PLAYERS.title = strcat("Kick ", ftos(page + 1), "/5"); + execute_admin_players = execute_admin_players_kick; + } else if(type == CLIENT_MENU_ADMIN_BAN) { + FO_MENU_ADMIN_PLAYERS.title = strcat("Ban ", ftos(page + 1), "/5"); + execute_admin_players = execute_admin_players_ban; + } else if(type == CLIENT_MENU_ADMIN_FORCE_SPEC) { + FO_MENU_ADMIN_PLAYERS.title = strcat("Force Spec ", ftos(page + 1), "/5"); + execute_admin_players = execute_admin_players_force_spec; + } else { + FO_MENU_ADMIN_PLAYERS.title = strcat("Page ", ftos(page + 1), "/5"); + execute_admin_players = execute_admin_players_unknown; + } + string n; + float c = 0, p = 0, spec = 0; +/* + * for(float i = 0; i < 32, c < 9; i++) { + n = getplayerkeyvalue(i,"name"); + if(n) { + p++; + } + if(p > page * 9 && p <= (page + 1) * 9) { + spec = stof(getplayerkeyvalue(i, "*spectator")); + //print("MEHT: found player: ", n, " id: ", ftos(i) , " userid: ",getplayerkeyvalue(i + (page * 9), "userid"),"\n"); + FO_MENU_ADMIN_PLAYERS.options[c].state = FO_MENU_STATE_NORMAL; + FO_MENU_ADMIN_PLAYERS.options[c].name = n; + FO_MENU_ADMIN_PLAYERS.options[c].value = spec?"Spectator":""; + c++; + } + } + for(float i = c; i < 9; i++) { + FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_HIDDEN; + } +*/ + for(float i = 0; i < 9; i++) { + n = getplayerkeyvalue(i + (page * 9),"name"); + spec = stof(getplayerkeyvalue(i + (page * 9), "*spectator")); + if(n && (type != CLIENT_MENU_ADMIN_FORCE_SPEC || !spec)) { + //print("MEHT: found player: ", n, " id: ", ftos(i) , " userid: ",getplayerkeyvalue(i + (page * 9), "userid"),"\n"); + FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_NORMAL; + FO_MENU_ADMIN_PLAYERS.options[i].name = n; + FO_MENU_ADMIN_PLAYERS.options[i].value = spec?"Spectator":""; + FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_WARNING; + c++; + } else { + FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_DISABLED; + FO_MENU_ADMIN_PLAYERS.options[i].name = ""; + FO_MENU_ADMIN_PLAYERS.options[i].value = ""; + FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_DARK; + } + } + //FO_MENU_ADMIN_PLAYERS.num_opts = c + 5; + + CurrentMenu = &FO_MENU_ADMIN_PLAYERS; + fo_hud_menu_active = TRUE; +} diff --git a/share/commondefs.qc b/share/commondefs.qc index cc816249..b12935ca 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -44,3 +44,6 @@ #define CLIENT_MENU_FIX_DISPENSER 11 #define CLIENT_MENU_USE_DISPENSER 12 #define CLIENT_MENU_ADMIN 13 +#define CLIENT_MENU_ADMIN_KICK 14 +#define CLIENT_MENU_ADMIN_BAN 15 +#define CLIENT_MENU_ADMIN_FORCE_SPEC 16 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 500cf15a..e6e58ac3 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -83,6 +83,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num, processedCmd, inp; local string tmp; local float farg3; + local entity ent; processedCmd = FALSE; if (arg1) @@ -622,8 +623,59 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; break; case "kick": - Admin_CycleDeal(); processedCmd = TRUE; + if(arg2) { + //make sure it's a number so there's no funny business + farg2 = stof(arg2); + if(farg2) { + localcmd("kick ", ftos(farg2), "\n"); + } + } else { + Admin_CycleDeal(); + } + break; + case "ban": + processedCmd = TRUE; + if(arg2) { + //make sure it's a number so there's no funny business + farg2 = stof(arg2); + if(farg2) { + ent = find(world, classname, "player"); + while(ent) { + if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { + bprint4(PRINT_HIGH, ent, " was banned by ", self.netname, ".\n"); + localcmd("addip "); + localcmd(infokey(ent, INFOKEY_P_IP)); + localcmd("\n"); + break; + } + ent = find(ent, classname, "player"); + } + localcmd("kick ", ftos(farg2), "\n"); + } + } else { + sprint(self, PRINT_HIGH, "ban requires a userid parameter\n"); + } + break; + case "forcespec": + processedCmd = TRUE; + if(arg2) { + //make sure it's a number so there's no funny business + farg2 = stof(arg2); + if(farg2) { + ent = find(world, classname, "player"); + while(ent) { + if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { + bprint4(PRINT_HIGH, ent, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); + stuffcmd(ent, "observe\n"); + break; + } + ent = find(ent, classname, "player"); + } + } + } else { + sprint(self, PRINT_HIGH, "forcespec requires a userid parameter\n"); + } break; case "ceasefire": if (ceasefire_type) @@ -649,29 +701,42 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "restart": + processedCmd = TRUE; RestartMap(); break; case "randomise": + processedCmd = TRUE; randomizeTeams(); break; case "adminrefresh": + processedCmd = TRUE; Update_ServerAdminInfo(self); break; case "pubmode": + processedCmd = TRUE; PubMode(); break; case "clanmode": + processedCmd = TRUE; ClanMode(); break; case "quadmode": + processedCmd = TRUE; QuadMode(); break; case "duelmode": + processedCmd = TRUE; DuelMode(); break; case "forcestart": + processedCmd = TRUE; ForceStartMatch(); break; + //case "kicklist": + //processedCmd = TRUE; + //Update_ServerAdmin_Players(self); + //UpdateClientMenu_Admin_Kick(self); + //break; case "help": case "list": processedCmd = TRUE; @@ -688,7 +753,9 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "cmd autorecord\n"); sprint(self, PRINT_HIGH, "cmd cancel\n"); sprint(self, PRINT_HIGH, "cmd stop\n"); - sprint(self, PRINT_HIGH, "cmd kick\n"); + sprint(self, PRINT_HIGH, "cmd kick [userid]\n"); + sprint(self, PRINT_HIGH, "cmd ban \n"); + sprint(self, PRINT_HIGH, "cmd forcespec \n"); sprint(self, PRINT_HIGH, "cmd ceasefire\n"); sprint(self, PRINT_HIGH, "cmd restart\n"); sprint(self, PRINT_HIGH, "cmd randomise\n"); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 03c82034..780c1c23 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -143,3 +143,11 @@ void Update_ServerAdminInfo(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMenu_Admin_Kick(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_ADMIN_KICK); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 295d51d3..9296047b 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1208,13 +1208,13 @@ void () DuelMode; void () RestartMap; void () Menu_Admin = { -// if(self.is_admin && infokeyf(self, INFOKEY_P_CSQCACTIVE)) { -// //fte+csqc has its own team menu -// //ask the client to activate it -// Menu_Close(self); -// UpdateClientMenu_Admin(self); -// return; -// } + if(self.is_admin && infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(self); + UpdateClientMenu_Admin(self); + return; + } local string s_menu1; local string s_menu2; local string override; From 9cf49fc9734b8fb244c2c4f79b0c98596fcb928a Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 14 Nov 2019 08:34:44 +1300 Subject: [PATCH 0841/2474] quad and time/frag limit menus --- csqc/csextradefs.qc | 3 +- csqc/events.qc | 5 ++ csqc/main.qc | 1 + csqc/menu.qc | 113 ++++++++++++++++++++++++++++++++++++++++++-- share/commondefs.qc | 3 ++ ssqc/commands.qc | 53 +++++++++++++++++++-- ssqc/csmenu.qc | 5 ++ ssqc/menu.qc | 6 +-- 8 files changed, 174 insertions(+), 15 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 467f9ba1..6824022e 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -37,6 +37,7 @@ vector dispenser_pos; vector touched_dispenser_pos; //entity player_list_head; float player_menu_type; +float admin_menu_next_update; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; @@ -351,7 +352,7 @@ vector(float panelid) getFillSize = { #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" - +#define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" float team_no; float is_spectator; diff --git a/csqc/events.qc b/csqc/events.qc index 0c9b6af8..cad68596 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -202,6 +202,11 @@ void() CSQC_Parse_Event = { break; case MSG_SERVER_ADMIN_INFO: SERVER_ADMIN.ceasefire = readbyte(); + SERVER_ADMIN.quad_rounds = readfloat(); + SERVER_ADMIN.quad_round_time = readfloat(); + SERVER_ADMIN.timelimit = readfloat(); + SERVER_ADMIN.fraglimit = readfloat(); + //print("MEHT: updated: rounds ", ftos(SERVER_ADMIN.quad_rounds), "\n"); break; } } diff --git a/csqc/main.qc b/csqc/main.qc index 5c6d78a4..57776086 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -29,6 +29,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_main_menu"); registercommand("fo_menu_admin"); registercommand("meht_test"); + registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("primeone"); registercommand("primetwo"); diff --git a/csqc/menu.qc b/csqc/menu.qc index b41c1d45..7730f55d 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -15,6 +15,9 @@ void (float force) FO_Menu_Build; void (float force) FO_Menu_Admin_Main; void (float force) FO_Menu_Admin_Modes; void (float force) FO_Menu_Admin_Settings; +void (float force) FO_Menu_Admin_Rounds; +void (float force) FO_Menu_Admin_Timelimit; +void (float force) FO_Menu_Admin_Fraglimit; void FO_Menu_Admin_Players(float force, float type, float page); typedef struct { @@ -327,6 +330,14 @@ var fo_menu FO_MENU_DISPENSER_USE = { } } }; + +void updateAdminMenuInfo() = { + if(admin_menu_next_update < time) { + localcmd("cmd adminrefresh\n"); + admin_menu_next_update = time + cvar(FOCMD_ADMIN_MENU_UPDATE_TIME); + } +} + var fo_menu FO_MENU_ADMIN_MAIN = { [0,0], [300,300], "Server Admin [1/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { {"1","Ceasefire","","",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");},MENU_BORDER_WARNING}, @@ -341,6 +352,7 @@ var fo_menu FO_MENU_ADMIN_MAIN = { {"+","Next - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, {"-","Prev - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, }, 11, TRUE, { + updateAdminMenuInfo(); FO_MENU_ADMIN_MAIN.options[0].value = SERVER_ADMIN.ceasefire?"on":"off"; } }; @@ -350,7 +362,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"2","Clan Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd clanmode\n");},MENU_BORDER_WARNING}, {"3","Quad Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd quadmode\n");},MENU_BORDER_WARNING}, {"4","Duel Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, - {"5","Quad Rounds...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"5","Quad Rounds...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, {"6","Quad Round Time...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, {"7","Captains Mode","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, {"8","Force Start","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, @@ -359,12 +371,17 @@ var fo_menu FO_MENU_ADMIN_MODES = { MenuSpacer, {"+","Next - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, {"-","Prev - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, - }, 13, TRUE + }, 13, TRUE, { + updateAdminMenuInfo(); + FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); + FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); + //print("MEHT: updating stuff: ", FO_MENU_ADMIN_MODES.options[4].value, " should be ", ftos(SERVER_ADMIN.quad_rounds), "\n"); + } }; var fo_menu FO_MENU_ADMIN_SETTINGS = { [0,0], [300,300], "Settings [3/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { - {"1","Timelimit","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, - {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"1","Timelimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Timelimit(TRUE);},MENU_BORDER_WARNING}, + {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Fraglimit(TRUE);},MENU_BORDER_WARNING}, {"3","Override Classes","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, {"4","Class Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, {"5","Spurs","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, @@ -374,7 +391,11 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { MenuSpacer, {"+","Next - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, {"-","Prev - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, - }, 11, TRUE + }, 11, TRUE, { + updateAdminMenuInfo(); + FO_MENU_ADMIN_SETTINGS.options[0].value = ftos(SERVER_ADMIN.timelimit); + FO_MENU_ADMIN_SETTINGS.options[1].value = ftos(SERVER_ADMIN.fraglimit); + } }; var void execute_admin_players(float choice, float page) { print("not implemented ", ftos(choice + (page * 9)),"\n"); @@ -418,6 +439,67 @@ var fo_menu FO_MENU_ADMIN_PLAYERS = { {"-","Prev","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Players(TRUE, player_menu_type, FO_MENU_ADMIN_PLAYERS.page - 1);},MENU_BUTTON}, }, 14, TRUE }; +var fo_menu FO_MENU_ADMIN_ROUNDS = { + [0,0], [300,300], "Quad Rounds", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","1","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"2","2","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 2\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"3","3","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 3\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"4","4","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 4\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"5","5","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 5\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"6","6","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 6\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"7","7","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 7\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"8","8","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 8\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"9","9","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 9\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, + }, 11, TRUE +}; +var fo_menu FO_MENU_ADMIN_QUAD_TIMELIMIT = { + [0,0], [300,200], "Quad Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","1","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"2","5","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 5\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"3","10","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 10\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"4","15","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 15\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"5","20","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 20\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"6","25","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 25\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"7","30","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 30\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"8","45","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 45\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"9","60","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 60\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, + }, 11, TRUE +}; +var fo_menu FO_MENU_ADMIN_TIMELIMIT = { + [0,0], [300,200], "Set Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","0 (infinite)","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 0\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"2","5","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 5\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"3","10","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 10\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"4","15","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 15\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"5","20","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 20\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"6","30","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 30\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"7","45","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 45\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"8","60","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 60\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"9","120","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 120\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, + }, 11, TRUE +}; +var fo_menu FO_MENU_ADMIN_FRAGLIMIT = { + [0,0], [300,200], "Set Fraglimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + {"1","0 (infinite)","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 0\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"2","5","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 5\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"3","10","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 10\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"4","15","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 15\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"5","20","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 20\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"6","30","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 30\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"7","50","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 50\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"8","100","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 100\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"9","200","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 200\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, + }, 11, TRUE +}; + void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; InProgressMenu.size = size; @@ -884,15 +966,36 @@ void FO_Menu_Admin_Main(float force) = { void FO_Menu_Admin_Modes(float force) = { if(fo_hud_menu_active && !force) return; + localcmd("cmd adminrefresh\n"); CurrentMenu = &FO_MENU_ADMIN_MODES; fo_hud_menu_active = TRUE; } void FO_Menu_Admin_Settings(float force) = { if(fo_hud_menu_active && !force) return; + localcmd("cmd adminrefresh\n"); CurrentMenu = &FO_MENU_ADMIN_SETTINGS; fo_hud_menu_active = TRUE; } +void FO_Menu_Admin_Rounds(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_ROUNDS; + fo_hud_menu_active = TRUE; +} +void FO_Menu_Admin_Timelimit(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_TIMELIMIT; + fo_hud_menu_active = TRUE; +} +void FO_Menu_Admin_Fraglimit(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_FRAGLIMIT; + fo_hud_menu_active = TRUE; +} + void FO_Menu_Admin_Players(float force, float type, float page) = { print("MEHT: FO_Menu_Admin_Players(", ftos(force), ", ", ftos(type), ", ", ftos(page), "\n"); if(fo_hud_menu_active && !force) diff --git a/share/commondefs.qc b/share/commondefs.qc index b12935ca..50a3adc5 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -47,3 +47,6 @@ #define CLIENT_MENU_ADMIN_KICK 14 #define CLIENT_MENU_ADMIN_BAN 15 #define CLIENT_MENU_ADMIN_FORCE_SPEC 16 +#define CLIENT_MENU_ADMIN_QUAD_TIMELIMIT 17 +#define CLIENT_MENU_ADMIN_TIMELIMIT 18 +#define CLIENT_MENU_ADMIN_FRAGLIMIT 19 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index e6e58ac3..d0a92824 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1,3 +1,20 @@ +void () UpdateAllAdmins = { + local entity ent = find(world, classname, "player"); + while(ent) { + if(ent.is_admin) { + Update_ServerAdminInfo(ent); + } + ent = find(ent, classname, "player"); + } + ent = find(world, classname, "observer"); + while(ent) { + if(ent.is_admin) { + Update_ServerAdminInfo(ent); + } + ent = find(ent, classname, "observer"); + } +} + void () RestartMap = { bprint(PRINT_HIGH, self.netname); bprint(PRINT_HIGH, " Has restarted the map.\n"); @@ -15,6 +32,16 @@ void () ForceStartMatch = { } } +void (float inp) SetQuadRounds = { + rounds = inp; + local string cmd; + cmd = strcat("localinfo rounds ", ftos(inp), "\n"); + localcmd(cmd); + bprint(2, "Quad Round Number changed to ", ftos(inp), "\n"); + UpdateAllAdmins(); +} + + void () QuadMode = { localcmd ("localinfo clan on\n"); @@ -732,11 +759,27 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; ForceStartMatch(); break; - //case "kicklist": - //processedCmd = TRUE; - //Update_ServerAdmin_Players(self); - //UpdateClientMenu_Admin_Kick(self); - //break; + case "rounds": + processedCmd = TRUE; + if(arg2) { + //make sure it's a number so there's no funny business + farg2 = stof(arg2); + if(farg2) { + SetQuadRounds(farg2); + } + } + break; + case "roundtime": + processedCmd = TRUE; + if(arg2) { + //make sure it's a number so there's no funny business + farg2 = stof(arg2); + if(farg2) { + localcmd ("localinfo round_time ",farg2,"\n"); + UpdateAllAdmins(); + } + } + break; case "help": case "list": processedCmd = TRUE; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 780c1c23..5518b5a2 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -140,6 +140,11 @@ void Update_ServerAdminInfo(entity pl) = { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SERVER_ADMIN_INFO); WriteByte(MSG_MULTICAST, is_paused || cease_fire); + //WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); + WriteFloat(MSG_MULTICAST, rounds); + WriteFloat(MSG_MULTICAST, infokeyf(world, "round_time")); + WriteFloat(MSG_MULTICAST, infokeyf(world, "timelimit")); + WriteFloat(MSG_MULTICAST, infokeyf(world, "fraglimit")); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 9296047b..6503d158 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -100,6 +100,7 @@ void () Admin_CeaseFire; void () Broadcast_Players_NotReady; void () StartTimer; void () ForceStartMatch; +void (float inp) SetQuadRounds; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; @@ -1779,10 +1780,7 @@ void (float inp) Menu_Admin_Input = } else if (self.current_menu_type == ADMIN_MENU_TYPE_QUAD_ROUNDNUM) { - local string cmd; - cmd = strcat("localinfo rounds ", ftos(inp), "\n"); - localcmd(cmd); - bprint(2, "Quad Round Number changed to ", ftos(inp), "\n"); + SetQuadRounds(inp); self.current_menu_type = ADMIN_MENU_TYPE_QUADMODE; self.current_menu_page = 1; Menu_Admin(); From 4495b32d09baf4191b4d2b5c01e7d25b439f5e05 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 14 Nov 2019 19:22:49 +1300 Subject: [PATCH 0842/2474] all admin works except captains --- csqc/events.qc | 4 ++++ csqc/menu.qc | 24 ++++++++++++++++++------ ssqc/commands.qc | 2 +- ssqc/csmenu.qc | 3 +++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index cad68596..abd7086b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -206,6 +206,10 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.quad_round_time = readfloat(); SERVER_ADMIN.timelimit = readfloat(); SERVER_ADMIN.fraglimit = readfloat(); + SERVER_ADMIN.clanmode = readfloat(); + SERVER_ADMIN.quadmode = readfloat(); + SERVER_ADMIN.duelmode = readfloat(); + SERVER_ADMIN.pubmode = !SERVER_ADMIN.clanmode && SERVER_ADMIN.quadmode && !SERVER_ADMIN.duelmode; //print("MEHT: updated: rounds ", ftos(SERVER_ADMIN.quad_rounds), "\n"); break; } diff --git a/csqc/menu.qc b/csqc/menu.qc index 7730f55d..8d430e82 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -18,6 +18,7 @@ void (float force) FO_Menu_Admin_Settings; void (float force) FO_Menu_Admin_Rounds; void (float force) FO_Menu_Admin_Timelimit; void (float force) FO_Menu_Admin_Fraglimit; +void (float force) FO_Menu_Admin_QuadTimelimit; void FO_Menu_Admin_Players(float force, float type, float page); typedef struct { @@ -354,6 +355,7 @@ var fo_menu FO_MENU_ADMIN_MAIN = { }, 11, TRUE, { updateAdminMenuInfo(); FO_MENU_ADMIN_MAIN.options[0].value = SERVER_ADMIN.ceasefire?"on":"off"; + FO_MENU_ADMIN_MAIN.options[6].value = mapname; } }; var fo_menu FO_MENU_ADMIN_MODES = { @@ -363,7 +365,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"3","Quad Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd quadmode\n");},MENU_BORDER_WARNING}, {"4","Duel Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, {"5","Quad Rounds...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, - {"6","Quad Round Time...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"6","Quad Round Time...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, {"7","Captains Mode","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, {"8","Force Start","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, MenuSpacer, @@ -373,6 +375,10 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"-","Prev - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, }, 13, TRUE, { updateAdminMenuInfo(); + FO_MENU_ADMIN_MODES.options[0].value = SERVER_ADMIN.pubmode?"on":"off"; + FO_MENU_ADMIN_MODES.options[1].value = SERVER_ADMIN.clanmode?"on":"off"; + FO_MENU_ADMIN_MODES.options[2].value = SERVER_ADMIN.quadmode?"on":"off"; + FO_MENU_ADMIN_MODES.options[3].value = SERVER_ADMIN.duelmode?"on":"off"; FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); //print("MEHT: updating stuff: ", FO_MENU_ADMIN_MODES.options[4].value, " should be ", ftos(SERVER_ADMIN.quad_rounds), "\n"); @@ -382,16 +388,16 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { [0,0], [300,300], "Settings [3/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { {"1","Timelimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Timelimit(TRUE);},MENU_BORDER_WARNING}, {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Fraglimit(TRUE);},MENU_BORDER_WARNING}, - {"3","Override Classes","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, - {"4","Class Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, - {"5","Spurs","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, - {"6","Spur Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, +// {"3","Override Classes","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, +// {"4","Class Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, +// {"5","Spurs","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, +// {"6","Spur Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"+","Next - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, {"-","Prev - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, - }, 11, TRUE, { + }, 7, TRUE, { updateAdminMenuInfo(); FO_MENU_ADMIN_SETTINGS.options[0].value = ftos(SERVER_ADMIN.timelimit); FO_MENU_ADMIN_SETTINGS.options[1].value = ftos(SERVER_ADMIN.fraglimit); @@ -983,6 +989,12 @@ void FO_Menu_Admin_Rounds(float force) = { CurrentMenu = &FO_MENU_ADMIN_ROUNDS; fo_hud_menu_active = TRUE; } +void FO_Menu_Admin_QuadTimelimit(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_QUAD_TIMELIMIT; + fo_hud_menu_active = TRUE; +} void FO_Menu_Admin_Timelimit(float force) = { if(fo_hud_menu_active && !force) return; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index d0a92824..f2dc740a 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -775,7 +775,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { //make sure it's a number so there's no funny business farg2 = stof(arg2); if(farg2) { - localcmd ("localinfo round_time ",farg2,"\n"); + localcmd ("localinfo round_time ",arg2,"\n"); UpdateAllAdmins(); } } diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 5518b5a2..f7f89c2d 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -145,6 +145,9 @@ void Update_ServerAdminInfo(entity pl) = { WriteFloat(MSG_MULTICAST, infokeyf(world, "round_time")); WriteFloat(MSG_MULTICAST, infokeyf(world, "timelimit")); WriteFloat(MSG_MULTICAST, infokeyf(world, "fraglimit")); + WriteFloat(MSG_MULTICAST, clanbattle); + WriteFloat(MSG_MULTICAST, quadmode); + WriteFloat(MSG_MULTICAST, duelmode); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } From 1b90d2efea3ab247297511f3f2968963c868d2b1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 14 Nov 2019 20:15:42 +1300 Subject: [PATCH 0843/2474] remove debugging prints --- csqc/events.qc | 1 - csqc/main.qc | 21 --------------------- csqc/menu.qc | 5 ----- 3 files changed, 27 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index abd7086b..40892b13 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -210,7 +210,6 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.quadmode = readfloat(); SERVER_ADMIN.duelmode = readfloat(); SERVER_ADMIN.pubmode = !SERVER_ADMIN.clanmode && SERVER_ADMIN.quadmode && !SERVER_ADMIN.duelmode; - //print("MEHT: updated: rounds ", ftos(SERVER_ADMIN.quad_rounds), "\n"); break; } } diff --git a/csqc/main.qc b/csqc/main.qc index 57776086..a0a03fbc 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,7 +28,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_game"); registercommand("fo_main_menu"); registercommand("fo_menu_admin"); - registercommand("meht_test"); registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("primeone"); @@ -135,26 +134,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { } localcmd("gren2_server"); break; - case "meht_test": - float c = 0; - entity e = find(world, classname, "player"); - string n = ""; - while(e) { - print("MEHT: found player: ", ftos(e.entnum), "\n"); - c++; - e = find(e, classname, "player"); - } - print("MEHT: total players: ", ftos(c), "\n"); - c = 0; - for(float i = 0; i < 100; i++) { - n = getplayerkeyvalue(i,"name"); - if(n) { - print("MEHT: found player: ", n, " id: ", ftos(i) , " userid: ",getplayerkeyvalue(i, "userid"),"\n"); - c++; - } - } - print("MEHT: other total players: ", ftos(c), "\n"); - break; } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index 8d430e82..d25efc90 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -381,7 +381,6 @@ var fo_menu FO_MENU_ADMIN_MODES = { FO_MENU_ADMIN_MODES.options[3].value = SERVER_ADMIN.duelmode?"on":"off"; FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); - //print("MEHT: updating stuff: ", FO_MENU_ADMIN_MODES.options[4].value, " should be ", ftos(SERVER_ADMIN.quad_rounds), "\n"); } }; var fo_menu FO_MENU_ADMIN_SETTINGS = { @@ -1009,7 +1008,6 @@ void FO_Menu_Admin_Fraglimit(float force) = { } void FO_Menu_Admin_Players(float force, float type, float page) = { - print("MEHT: FO_Menu_Admin_Players(", ftos(force), ", ", ftos(type), ", ", ftos(page), "\n"); if(fo_hud_menu_active && !force) return; if(page < 0) { @@ -1049,7 +1047,6 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { } if(p > page * 9 && p <= (page + 1) * 9) { spec = stof(getplayerkeyvalue(i, "*spectator")); - //print("MEHT: found player: ", n, " id: ", ftos(i) , " userid: ",getplayerkeyvalue(i + (page * 9), "userid"),"\n"); FO_MENU_ADMIN_PLAYERS.options[c].state = FO_MENU_STATE_NORMAL; FO_MENU_ADMIN_PLAYERS.options[c].name = n; FO_MENU_ADMIN_PLAYERS.options[c].value = spec?"Spectator":""; @@ -1064,7 +1061,6 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { n = getplayerkeyvalue(i + (page * 9),"name"); spec = stof(getplayerkeyvalue(i + (page * 9), "*spectator")); if(n && (type != CLIENT_MENU_ADMIN_FORCE_SPEC || !spec)) { - //print("MEHT: found player: ", n, " id: ", ftos(i) , " userid: ",getplayerkeyvalue(i + (page * 9), "userid"),"\n"); FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_NORMAL; FO_MENU_ADMIN_PLAYERS.options[i].name = n; FO_MENU_ADMIN_PLAYERS.options[i].value = spec?"Spectator":""; @@ -1077,7 +1073,6 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_DARK; } } - //FO_MENU_ADMIN_PLAYERS.num_opts = c + 5; CurrentMenu = &FO_MENU_ADMIN_PLAYERS; fo_hud_menu_active = TRUE; From 4d5d92efc650f82ce907fbd89de289eeb56e4729 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 20 Nov 2019 11:25:30 +1100 Subject: [PATCH 0844/2474] fix hardcore loc file issue, support q3 entity locs (target_location) --- ssqc/locfiles.qc | 34 +++++++++++++++++++++++++++++++++- ssqc/q3.qc | 5 ++++- ssqc/world.qc | 15 ++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/ssqc/locfiles.qc b/ssqc/locfiles.qc index 0c0ffcfe..f580b5c4 100644 --- a/ssqc/locfiles.qc +++ b/ssqc/locfiles.qc @@ -1,6 +1,9 @@ #pragma target fte +string prepq3fstring (string s); +float locationMultiplier; void loadloc() { + locationMultiplier = TRUE; local float i; local string ln; local string out; @@ -23,9 +26,11 @@ void loadloc() { ln = fgets(locfilehandle); i = 0; while (ln != string_null && i < numlocs) { + ln = strtrim(ln); float s1 = strstrofs(ln, " ", 0); float s2 = strstrofs(ln, " ", s1+1); float s3 = strstrofs(ln, " ", s2+1); + local string px = substring(ln, 0, s1); local string py = substring(ln, s1+1, (s2-(s1+1))); local string pz = substring(ln, s2+1, (s3-(s2+1))); @@ -46,6 +51,33 @@ void loadloc() { else { out = strcat("Couldn't find ", mapname); out = strcat(out, ".loc\n"); + + // check for q3f target_locations + numlocs = 0; + entity targ; + targ = find(world, classname, "target_location"); + while (targ) + { + numlocs++; + targ = find(targ, classname, "target_location"); + } + + if (numlocs > 0) + { + locationMultiplier = FALSE; + locs = memalloc(sizeof(*locs)*numlocs); + targ = find(world, classname, "target_location"); + i = 0; + while (targ) + { + locs[i].pos = targ.origin; + locs[i].desc = strtrim(prepq3fstring(targ.message)); + i++; + targ = find(targ, classname, "target_location"); + } + + out = "Loaded locs from target_location entities\n"; + } } dprint(out); } @@ -56,7 +88,7 @@ string getLocationName(vector location) { local float i; desc = "someplace"; - location = location * 8; + location = location * ((locationMultiplier == TRUE) ? 8 : 1); bestdist = 0; for (i = 0; i < numlocs; i++) { float dist = vlen(location - locs[i].pos); diff --git a/ssqc/q3.qc b/ssqc/q3.qc index 23b1a58f..fb8bb7ba 100644 --- a/ssqc/q3.qc +++ b/ssqc/q3.qc @@ -1,4 +1,5 @@ -string (string s) prepq3fstring = { +string prepq3fstring (string s) +{ string ret; ret = strireplace("%n", "", s); @@ -118,6 +119,8 @@ void CheckStateQ3Goal(entity trig) ActivateQ3Goal(trig, triggered); } +void () target_location = { +} // backpacks, cap points etc void () func_goalinfo = { diff --git a/ssqc/world.qc b/ssqc/world.qc index 14a17899..489c6c29 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -116,13 +116,21 @@ void () main = { entity lastspawn; +// use this for post world being setup (and entities loaded) +void WorldSpawnPost() +{ + loadloc(); + + dremove(self); +} + void () worldspawn = { // Set this variable on connect so the client knows it has access to // FortressOne aliases. WriteByte(MSG_INIT, 9/*svc_stufftext*/); WriteString(MSG_INIT, "set fo_serverscripts 1\n"); - loadloc(); + local string st; @@ -315,6 +323,11 @@ void () worldspawn = { lightstyle(63, "a"); clientstat(STAT_TEAMNO, EV_FLOAT, team_no); + + entity worldspawnent; + worldspawnent = spawn(); + worldspawnent.think = WorldSpawnPost; + worldspawnent.nextthink = time + 2; }; void () StartFrame = { From 99fd6ffb974475b613c5f1faebc9d4f962c77a5a Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 20 Nov 2019 19:30:51 +1100 Subject: [PATCH 0845/2474] fix locs so they can process blank lines in files --- ssqc/locfiles.qc | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/ssqc/locfiles.qc b/ssqc/locfiles.qc index f580b5c4..532dfadc 100644 --- a/ssqc/locfiles.qc +++ b/ssqc/locfiles.qc @@ -14,8 +14,12 @@ void loadloc() { locfilehandle = fopen(path, FILE_READ); if (locfilehandle >= 0) { ln = fgets(locfilehandle); - while (ln != string_null) { - numlocs++; + while (ln) { // test for null + if (ln != "") // test for empty + { + numlocs++; + } + ln = fgets(locfilehandle); } fclose(locfilehandle); @@ -25,21 +29,25 @@ void loadloc() { locfilehandle = fopen(path, FILE_READ); ln = fgets(locfilehandle); i = 0; - while (ln != string_null && i < numlocs) { + while (ln && i < numlocs) { ln = strtrim(ln); - float s1 = strstrofs(ln, " ", 0); - float s2 = strstrofs(ln, " ", s1+1); - float s3 = strstrofs(ln, " ", s2+1); + if (ln != "") + { + float s1 = strstrofs(ln, " ", 0); + float s2 = strstrofs(ln, " ", s1+1); + float s3 = strstrofs(ln, " ", s2+1); - local string px = substring(ln, 0, s1); - local string py = substring(ln, s1+1, (s2-(s1+1))); - local string pz = substring(ln, s2+1, (s3-(s2+1))); + local string px = substring(ln, 0, s1); + local string py = substring(ln, s1+1, (s2-(s1+1))); + local string pz = substring(ln, s2+1, (s3-(s2+1))); - locs[i].pos.x = stof(px); - locs[i].pos.y = stof(py); - locs[i].pos.z = stof(pz); - locs[i].desc = substring(ln, s3+1, strlen(ln)-s3+2); - i++; + locs[i].pos.x = stof(px); + locs[i].pos.y = stof(py); + locs[i].pos.z = stof(pz); + locs[i].desc = substring(ln, s3+1, strlen(ln)-s3+2); + i++; + } + ln = fgets(locfilehandle); } fclose(locfilehandle); @@ -73,6 +81,8 @@ void loadloc() { locs[i].pos = targ.origin; locs[i].desc = strtrim(prepq3fstring(targ.message)); i++; + targ.nextthink = time + 0.01; + targ.think = SUB_Remove; targ = find(targ, classname, "target_location"); } From 96b1cdd204b1f2bf92d498dcf55a9c89220be1c0 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 20 Nov 2019 19:31:01 +1100 Subject: [PATCH 0846/2474] change post world spawn to earlier timer --- ssqc/world.qc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ssqc/world.qc b/ssqc/world.qc index 489c6c29..d55fef71 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -130,8 +130,6 @@ void () worldspawn = { WriteByte(MSG_INIT, 9/*svc_stufftext*/); WriteString(MSG_INIT, "set fo_serverscripts 1\n"); - - local string st; lastspawn = world; @@ -327,7 +325,7 @@ void () worldspawn = { entity worldspawnent; worldspawnent = spawn(); worldspawnent.think = WorldSpawnPost; - worldspawnent.nextthink = time + 2; + worldspawnent.nextthink = time + .01; }; void () StartFrame = { From bb98d11fa76893daf5fea9553d20f1661b0c0c1b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 21 Nov 2019 00:58:40 +1300 Subject: [PATCH 0847/2474] vote menu works maybe, captain menus sort of work --- csqc/csextradefs.qc | 5 + csqc/events.qc | 23 +++++ csqc/main.qc | 1 + csqc/menu.qc | 93 ++++++++++++++++--- share/commondefs.qc | 5 + ssqc/admin.qc | 4 +- ssqc/client.qc | 4 +- ssqc/commands.qc | 218 +++++++++++++++++++++++++++++++++++++++++++- ssqc/csmenu.qc | 36 ++++++++ ssqc/qw.qc | 5 + ssqc/tforthlp.qc | 7 -- ssqc/tforttm.qc | 99 ++++++++++---------- ssqc/vote.qc | 15 +-- 13 files changed, 439 insertions(+), 76 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6824022e..3c620d84 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -38,6 +38,11 @@ vector touched_dispenser_pos; //entity player_list_head; float player_menu_type; float admin_menu_next_update; +float captain1; +float captain2; +float captain1_temp; +float captain2_temp; +float is_admin; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index 40892b13..57f014ad 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -174,6 +174,23 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_ADMIN_KICK: FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_KICK, 0); break; + case CLIENT_MENU_VOTE: + FO_MENU_VOTE.title = strcat("Map Vote (", ftos(readfloat()), "s left)"); + FO_MENU_VOTE.options[0].name = readstring(); + FO_MENU_VOTE.options[0].value = ftos(readfloat()); + FO_MENU_VOTE.options[1].name = readstring(); + FO_MENU_VOTE.options[1].value = ftos(readfloat()); + FO_MENU_VOTE.options[2].name = readstring(); + FO_MENU_VOTE.options[2].value = ftos(readfloat()); + FO_MENU_VOTE.options[3].name = readstring(); + FO_MENU_VOTE.options[3].value = ftos(readfloat()); + FO_MENU_VOTE.options[4].name = readstring(); + FO_MENU_VOTE.options[4].value = ftos(readfloat()); + FO_Menu_Vote(FALSE); + break; + case CLIENT_MENU_CAPTAIN_PICK: + FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0); + break; } break; case MSG_CLASSES_UPDATE: @@ -201,6 +218,7 @@ void() CSQC_Parse_Event = { dispenser_pos = [readfloat(),readfloat(),readfloat()]; break; case MSG_SERVER_ADMIN_INFO: + is_admin = TRUE; SERVER_ADMIN.ceasefire = readbyte(); SERVER_ADMIN.quad_rounds = readfloat(); SERVER_ADMIN.quad_round_time = readfloat(); @@ -210,6 +228,11 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.quadmode = readfloat(); SERVER_ADMIN.duelmode = readfloat(); SERVER_ADMIN.pubmode = !SERVER_ADMIN.clanmode && SERVER_ADMIN.quadmode && !SERVER_ADMIN.duelmode; + SERVER_ADMIN.captainmode = readfloat(); + break; + case MSG_CAPTAINS: + captain1 = readfloat(); + captain2 = readfloat(); break; } } diff --git a/csqc/main.qc b/csqc/main.qc index a0a03fbc..a57019cf 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -40,6 +40,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; + is_admin = FALSE; }; noref void() CSQC_WorldLoaded = { diff --git a/csqc/menu.qc b/csqc/menu.qc index d25efc90..3580f6f8 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -9,6 +9,8 @@ #define FO_MENU_STATE_DISABLED 2 #define FO_MENU_STATE_SPACER 3 +#define FO_MENU_MAX_OPTIONS 20 + #define FO_MENU_TRANSPARENCY 0.2 void (float force) FO_Menu_Build; @@ -36,7 +38,7 @@ typedef struct { vector size; string title; float flags; - fo_menu_option options[20]; + fo_menu_option options[FO_MENU_MAX_OPTIONS]; float num_opts; float active; void() update; @@ -80,17 +82,21 @@ var fo_menu FO_MENU_GAME = { {"3","Ready","","",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"4","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, + {"5","Server Admin", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + {"6","Captain's Menu", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0);},MENU_BUTTON}, MenuSpacer, {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, - }, 7, TRUE + }, 9, TRUE }; var fo_menu FO_MENU_GAME_SPECTATOR = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, - {"2","Tracking Sidebar", "","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BUTTON}, + {"2","Tracking Sidebar", "","",FO_MENU_STATE_HIDDEN,{print("not implemented\n");},MENU_BUTTON}, + MenuSpacer, + {"3","Server Admin", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, MenuSpacer, {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, - }, 4, TRUE + }, 6, TRUE }; var fo_menu FO_MENU_SPECTATOR_TRACK = { [0,0], [300,200], "Track", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { @@ -366,7 +372,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"4","Duel Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, {"5","Quad Rounds...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, {"6","Quad Round Time...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, - {"7","Captains Mode","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + {"7","Captains Mode","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BG_DARK}, {"8","Force Start","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, @@ -381,6 +387,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { FO_MENU_ADMIN_MODES.options[3].value = SERVER_ADMIN.duelmode?"on":"off"; FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); + FO_MENU_ADMIN_MODES.options[6].value = ftos(SERVER_ADMIN.captainmode); } }; var fo_menu FO_MENU_ADMIN_SETTINGS = { @@ -426,6 +433,27 @@ void execute_admin_players_force_spec(float choice, float page) { Menu_Cancel(); FO_Menu_Admin_Main(TRUE); } +void execute_admin_players_captain1(float choice, float page) { + string userid = getplayerkeyvalue(choice + (page * 9), "userid"); + captain1_temp = stof(userid); + print("MEHT captain 1: ", ftos(choice + (page * 9)),"\n"); + FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_2, 0); +} +void execute_admin_players_captain2(float choice, float page) { + string userid = getplayerkeyvalue(choice + (page * 9), "userid"); + captain2_temp = stof(userid); + print("MEHT captain 2: ", ftos(choice + (page * 9)),"\n"); + //Send server cmd setting captains; reset everyone to observer; spam out captains set message + localcmd("cmd captainmode ", ftos(captain1_temp), " ", userid, "\n"); + FO_Menu_Admin_Main(TRUE); +} +void execute_admin_players_captain_pick(float choice, float page) { + string userid = getplayerkeyvalue(choice + (page * 9), "userid"); + localcmd("cmd captainpick ", userid, "\n"); + //print("not implemented ", ftos(choice + (page * 9)),"\n"); + //Menu_Cancel(); +} + var fo_menu FO_MENU_ADMIN_PLAYERS = { [0,0], [300,300], "Players", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { {"1","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(0, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, @@ -504,7 +532,18 @@ var fo_menu FO_MENU_ADMIN_FRAGLIMIT = { {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, }, 11, TRUE }; - +var fo_menu FO_MENU_VOTE = { + [0,0], [300,200], "Map Vote", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { + {"1","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[0].name,"\n");Menu_Cancel();},MENU_BUTTON}, + {"2","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[1].name,"\n");Menu_Cancel();},MENU_BUTTON}, + {"3","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[2].name,"\n");Menu_Cancel();},MENU_BUTTON}, + {"4","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[3].name,"\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"5","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[4].name,"\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + }, 8, TRUE +}; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; InProgressMenu.size = size; @@ -599,7 +638,7 @@ vector fo_menu_draw(fo_menu * menu) = { 0 ); float row = 0; - for(float i = 0; i < menu.num_opts; i++) { + for(float i = 0; i < FO_MENU_MAX_OPTIONS; i++) { vector shortcutoffset = [0,0], valueoffset = [0,0]; if(menu.options[i].state == FO_MENU_STATE_HIDDEN) { @@ -727,9 +766,17 @@ void FO_Menu_Game(float force) = { return; if(is_spectator) { //print(getplayerkeyvalue(player_localnum, "name"), " is a spectator!\n"); - CurrentMenu = &FO_MENU_GAME_SPECTATOR; + FO_MENU_GAME_SPECTATOR.num_opts = 3; + FO_MENU_GAME_SPECTATOR.options[3].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; + if(is_admin) FO_MENU_GAME_SPECTATOR.num_opts++; + CurrentMenu = &FO_MENU_GAME_SPECTATOR; } else { //print(getplayerkeyvalue(player_localnum, "name"), " is playing a game!\n"); + FO_MENU_GAME.num_opts = 7; + FO_MENU_GAME.options[5].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; + if(is_admin) FO_MENU_GAME.num_opts++; + FO_MENU_GAME.options[6].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; + if(is_admin) FO_MENU_GAME.num_opts++; CurrentMenu = &FO_MENU_GAME; } fo_hud_menu_active = TRUE; @@ -1033,12 +1080,23 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { } else if(type == CLIENT_MENU_ADMIN_FORCE_SPEC) { FO_MENU_ADMIN_PLAYERS.title = strcat("Force Spec ", ftos(page + 1), "/5"); execute_admin_players = execute_admin_players_force_spec; + } else if(type == CLIENT_MENU_CAPTAIN_1) { + captain1_temp = 0; + captain2_temp = 0; + FO_MENU_ADMIN_PLAYERS.title = strcat("Select Captain 1 ", ftos(page + 1), "/5"); + execute_admin_players = execute_admin_players_captain1; + } else if(type == CLIENT_MENU_CAPTAIN_2) { + FO_MENU_ADMIN_PLAYERS.title = strcat("Select Captain 2 ", ftos(page + 1), "/5"); + execute_admin_players = execute_admin_players_captain2; + } else if(type == CLIENT_MENU_CAPTAIN_PICK) { + FO_MENU_ADMIN_PLAYERS.title = strcat("Pick teammate ", ftos(page + 1), "/5"); + execute_admin_players = execute_admin_players_captain_pick; } else { FO_MENU_ADMIN_PLAYERS.title = strcat("Page ", ftos(page + 1), "/5"); execute_admin_players = execute_admin_players_unknown; } - string n; - float c = 0, p = 0, spec = 0; + string n, team; + float c = 0, p = 0, spec = 0, userid = 0, enable = FALSE; /* * for(float i = 0; i < 32, c < 9; i++) { n = getplayerkeyvalue(i,"name"); @@ -1060,7 +1118,12 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { for(float i = 0; i < 9; i++) { n = getplayerkeyvalue(i + (page * 9),"name"); spec = stof(getplayerkeyvalue(i + (page * 9), "*spectator")); - if(n && (type != CLIENT_MENU_ADMIN_FORCE_SPEC || !spec)) { + team = getplayerkeyvalue(i + (page * 9), "team"); + userid = stof(getplayerkeyvalue(i + (page * 9), "userid")); + if(n && ( + type != CLIENT_MENU_ADMIN_FORCE_SPEC || + !spec + ) && !(type == CLIENT_MENU_CAPTAIN_PICK && (team || i + (page * 9) == player_localnum || (userid && (userid == captain1_temp || userid == captain2_temp))))) { FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_NORMAL; FO_MENU_ADMIN_PLAYERS.options[i].name = n; FO_MENU_ADMIN_PLAYERS.options[i].value = spec?"Spectator":""; @@ -1068,7 +1131,7 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { c++; } else { FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_DISABLED; - FO_MENU_ADMIN_PLAYERS.options[i].name = ""; + FO_MENU_ADMIN_PLAYERS.options[i].name = n; FO_MENU_ADMIN_PLAYERS.options[i].value = ""; FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_DARK; } @@ -1077,3 +1140,9 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { CurrentMenu = &FO_MENU_ADMIN_PLAYERS; fo_hud_menu_active = TRUE; } +void FO_Menu_Vote(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_VOTE; + fo_hud_menu_active = TRUE; +} diff --git a/share/commondefs.qc b/share/commondefs.qc index 50a3adc5..f2099218 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -16,6 +16,7 @@ #define MSG_SENTRY_POS 9 #define MSG_DISPENSER_POS 10 #define MSG_SERVER_ADMIN_INFO 11 +#define MSG_CAPTAINS 12 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 @@ -50,3 +51,7 @@ #define CLIENT_MENU_ADMIN_QUAD_TIMELIMIT 17 #define CLIENT_MENU_ADMIN_TIMELIMIT 18 #define CLIENT_MENU_ADMIN_FRAGLIMIT 19 +#define CLIENT_MENU_VOTE 20 +#define CLIENT_MENU_CAPTAIN_1 21 +#define CLIENT_MENU_CAPTAIN_2 22 +#define CLIENT_MENU_CAPTAIN_PICK 23 diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 5569037c..48b8a2f6 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -118,7 +118,9 @@ void () Admin_DoBan = { void () Admin_ForceSpectator = { bprint4(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); - stuffcmd(self.admin_use, "observe\n"); + //stuffcmd(self.admin_use, "observe\n"); + forceinfokey(self.admin_use, "*spectator", "1"); + //clientcommand(player, "observe") self.admin_mode = 0; self.admin_use = world; }; diff --git a/ssqc/client.qc b/ssqc/client.qc index c016adba..f590c1bf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -61,7 +61,7 @@ float () GetLastWeaponImpulse; float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; -float (float tno, float skipclasscheck) TeamFortress_TeamSet_Options; +float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options; string nextmap; @@ -2359,7 +2359,7 @@ void (optional float csqcactive) ClientConnect = { while (te) { if (te.tf_id == self.tf_id) { got_one = 1; - TeamFortress_TeamSet_Options(te.team_no, TRUE); + TeamFortress_TeamSet_Options(te, te.team_no, TRUE); self.frags = te.frags; self.real_frags = te.real_frags; if (!(toggleflags & TFLAG_TEAMFRAGS) && diff --git a/ssqc/commands.qc b/ssqc/commands.qc index f2dc740a..4c9f6672 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -106,6 +106,167 @@ void () DuelMode = bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); } +void (entity pe) SetEquipmentForPlayer = { + entity oldself = self; + self = pe; + TeamFortress_SetEquipment(); + //self.immune_to_check = time + 10; + //self.undercover_team = 0; + stuffcmd(self, "color "); + string st = ftos(TeamFortress_TeamGetColor(self.team_no) - 1); + stuffcmd(self, st); + stuffcmd(self, "\n"); + + self = oldself; +} + +void (float cap1, float cap2) CaptainMode = { + captainmode = 1; + bprint(PRINT_HIGH, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); + local string st = 0; + local float userid = 0, csqcactive = 0; + local entity oldself;// = self; + local entity te = find (world, classname, "player"); + while (te != world) { + userid = infokeyf(te, INFOKEY_P_USERID); + csqcactive = infokeyf(te, INFOKEY_P_CSQCACTIVE); + //te.immune_to_check = time + 10; + if(userid == cap1 || userid == cap2) { + te.captain = 9; + te.playerclass = 0; + if(userid == cap1) { + //playerSetTeam(1); + te.team_no = 1; + SetTeamName(te); + TeamFortress_TeamSet_Options(te, 1, TRUE); + //stuffcmd(self, "color "); + //st = ftos(TeamFortress_TeamGetColor (1) - 1); + //stuffcmd(self, st); + //stuffcmd(self, "\n"); + //SetTeamName(self); + } + if(userid == cap2) { + //playerSetTeam(2); + te.team_no = 2; + SetTeamName(te); + TeamFortress_TeamSet_Options(te, 2, TRUE); + //stuffcmd(self, "color "); + //st = ftos(TeamFortress_TeamGetColor (2) - 1); + //stuffcmd(self, st); + //stuffcmd(self, "\n"); + //SetTeamName(self); + } + bprint(PRINT_HIGH, "\[\sCaptain Mode\s\]\s:\s "); + bprint(PRINT_HIGH, te.netname); + bprint(PRINT_HIGH, " \bis the captain for team\b "); + bprint(PRINT_HIGH, TeamToString(te.team_no)); + bprint(PRINT_HIGH, "\b.\b\n"); + if(csqcactive) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(te); + UpdateClientMenu_Captain(te); + } else { + //self = te; + Menu_Close(te); + te.current_menu_type = ADMIN_MENU_TYPE_CAPTAINSELECT; + te.current_menu_page = 1; + //Menu_Admin(); + } + } else { + te.captain = 0; + //self = te; + //playerSetTeam(-1); + te.team_no = 0; + te.playerclass = 0; + oldself = self; + self = te; + TeamFortress_ChangeClass(0); + self = oldself; + SetTeamName(te); + //TeamFortress_TeamSet_Options(te, 0, TRUE); + //stuffcmd(te, "color 0 0\n"); + //SetTeamName(te); + + te.current_menu = 0; + te.impulse = 0; + bprint(PRINT_HIGH, "MEHT: Setting ", te.netname, " to observer\n"); + } + if(csqcactive) { + UpdateClient_Captains(te, cap1, cap2); + } + SetEquipmentForPlayer(te); + te = find (te, classname, "player"); + } + //self = oldself; +} + +void (entity cap1, entity cap2) StopCaptainMode = { + if(captainmode){ + local entity oldself = self; + self = cap1; + TeamFortress_TeamSet(cap1.team_no); + self = cap2; + TeamFortress_TeamSet(cap2.team_no); + captainmode = 0; + self = oldself; + } +} + +void (entity cap, float pick) CaptainPick = { + if(!cap.captain) { + sprint(self, PRINT_HIGH, "You are not a captain, sorry\n"); + return; + } + local float countleft = 0, userid = 0; + local entity picked = world, othercap = world, oldself; + local entity te = find (world, classname, "player"); + while (te != world) { + userid = infokeyf(te, INFOKEY_P_USERID); + if(userid == pick) { + picked = te; + } + if(!te.team_no) { + countleft++; + } + if(te != cap && te.captain) { + othercap = te; + } + te = find (te, classname, "player"); + } + if(picked != world) { + if(picked == cap) { + sprint(self, PRINT_HIGH, "You don't have to pick yourself, it's implied...\n"); + return; + } + if(picked.captain) { + sprint(self, PRINT_HIGH, picked.netname ," is a captain, thus unpickable!\n"); + return; + } + if(picked.team_no) { + sprint(self, PRINT_HIGH, picked.netname ," has already been picked!\n"); + return; + } + bprint(PRINT_HIGH, "\[\bCaptain Mode\b\]\b:\b "); + bprint(PRINT_HIGH, picked.netname); + bprint(PRINT_HIGH, " \bcalled\b "); + bprint(PRINT_HIGH, cap.netname); + bprint(PRINT_HIGH, " \bfor team\b "); + bprint(PRINT_HIGH, TeamToString(cap.team_no)); + bprint(PRINT_HIGH, "\b.\b\n"); + oldself = self; + self = picked; + TeamFortress_TeamSet(cap.team_no); + self = oldself; + } else { + sprint(self, PRINT_HIGH, "Sorry, couldn't pick ", picked.netname ,"\n"); + } + if(!countleft) { + bprint(PRINT_HIGH, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s\n"); + StopCaptainMode(cap, othercap); + } +} + float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num, processedCmd, inp; local string tmp; @@ -510,6 +671,36 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } sprint(self, PRINT_HIGH, "Invalid choice. Choices are [ammo|armo[u]r|repair|withdraw ammo|withdraw armo[u]r].\n"); break; + case "votemap": + processedCmd = TRUE; + switch(arg2) { + case vote1_map: + Vote_Input(1); + break; + case vote2_map: + Vote_Input(2); + break; + case vote3_map: + Vote_Input(3); + break; + case vote4_map: + Vote_Input(4); + break; + case vote5_map: + Vote_Input(5); + break; + default: + Vote_Menu(self); + break; + } + break; + case "captainpick": + processedCmd = TRUE; + if(arg2) { + farg2 = stof(arg2); + CaptainPick(self, farg2); + } + break; } if (self.is_admin) @@ -518,6 +709,9 @@ float (string arg1, string arg2, string arg3) ParseCmds = { { case "adminmenu": processedCmd = TRUE; + Menu_Close(self); + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + self.current_menu_page = 1; Menu_Admin(); break; case "timelimit": @@ -694,7 +888,9 @@ float (string arg1, string arg2, string arg3) ParseCmds = { while(ent) { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { bprint4(PRINT_HIGH, ent, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); - stuffcmd(ent, "observe\n"); + //stuffcmd(ent, "observe\n"); + forceinfokey(ent, "*spectator", "1"); + //clientcommand(player, "observe") break; } ent = find(ent, classname, "player"); @@ -780,6 +976,26 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } } break; + case "captainmode": + processedCmd = TRUE; + if(arg2 && arg3) { + farg2 = stof(arg2); + farg3 = stof(arg3); + if(farg2 && farg3) { + CaptainMode(farg2, farg3); + } else { + sprint(self, PRINT_HIGH, "Captain mode requires 2 userids\n"); + } + break; + } + if(arg2 == "stop") { + local entity cap1 = findfloat(world, captain, 1); + local entity cap2 = findfloat(cap1, captain, 1); + StopCaptainMode(cap1, cap2); + break; + } + Menu_Admin(); + break; case "help": case "list": processedCmd = TRUE; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index f7f89c2d..dd51cdc2 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -148,6 +148,7 @@ void Update_ServerAdminInfo(entity pl) = { WriteFloat(MSG_MULTICAST, clanbattle); WriteFloat(MSG_MULTICAST, quadmode); WriteFloat(MSG_MULTICAST, duelmode); + WriteFloat(MSG_MULTICAST, captainmode); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } @@ -158,4 +159,39 @@ void UpdateClientMenu_Admin_Kick(entity pl) = { WriteFloat(MSG_MULTICAST, CLIENT_MENU_ADMIN_KICK); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMenu_Vote(entity pl, float timeleft) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_VOTE); + WriteFloat(MSG_MULTICAST, timeleft); + WriteString(MSG_MULTICAST, vote1_map); + WriteFloat(MSG_MULTICAST, vote1_cnt); + WriteString(MSG_MULTICAST, vote2_map); + WriteFloat(MSG_MULTICAST, vote2_cnt); + WriteString(MSG_MULTICAST, vote3_map); + WriteFloat(MSG_MULTICAST, vote3_cnt); + WriteString(MSG_MULTICAST, vote4_map); + WriteFloat(MSG_MULTICAST, vote4_cnt); + WriteString(MSG_MULTICAST, vote5_map); + WriteFloat(MSG_MULTICAST, vote5_cnt); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientMenu_Captain(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_CAPTAIN_PICK); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClient_Captains(entity pl, float cap1, float cap2) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CAPTAINS); + WriteFloat(MSG_MULTICAST, cap1); + WriteFloat(MSG_MULTICAST, cap2); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 3b9dae79..ae9a3eb5 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -609,6 +609,11 @@ float intermission_exittime; .entity chain2; // allows for nesting of findradius (use in EMPGrenadeExplode) +// global variables for voting +float vote1_cnt, vote2_cnt, vote3_cnt, vote4_cnt, vote5_cnt; +string vote1_map, vote2_map, vote3_map, vote4_map, vote5_map, vote_result; +float vote_started, vote_update, vote_winnercount, vote_decider, vote_abort; + //============================================================================ void (float psize, entity p) KickPlayer = { diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 46146a39..88f71c09 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -17,13 +17,6 @@ void () TeamFortress_MOTD = { local string ya; local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if(csqcactive) { - //fte+csqc has its own team menu - //ask the client to activate it - Menu_Close(self); - //return; - } - if (self.motd == 5) { if(csqcactive) { if(self.team_no == 0) { diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index aa3e2a72..f0385b95 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -48,7 +48,7 @@ float (float tno) TeamFortress_TeamGetColor = { return (YELLOW); if (tno == 4) return (DARKGREEN); - return (0); + return (1); }; void (float tno) TeamFortress_TeamSetColor = { @@ -154,17 +154,19 @@ float (float tno) CF_TeamIsValid = { return 1; } -float (float tno, float skipclasscheck) TeamFortress_TeamSet_Options = { +float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options = { local string st; local float tc; local string team; + bprint(PRINT_HIGH, "MEHT: Setting team to ", ftos(tno), "\n"); if ((intermission_running != 0) || (intermission_exittime > time)) return (0); if (!CF_TeamIsValid) { return 0; } + bprint(PRINT_HIGH, "MEHT: team is valid\n"); if (tno == 1) team = "blue team"; @@ -175,82 +177,84 @@ float (float tno, float skipclasscheck) TeamFortress_TeamSet_Options = { else team = "green team"; - if (tno > 0 && tno == self.team_no) { - sprint(self, PRINT_HIGH, "You are already on the ", team, "!\n"); + if (tno > 0 && tno == pe.team_no) { + sprint(pe, PRINT_HIGH, "You are already on the ", team, "!\n"); return 0; } - if (TeamFortress_TeamGetColor(tno) == 0) { + bprint(PRINT_HIGH, "MEHT: Team colour is ", ftos(TeamFortress_TeamGetColor(tno)), "\n"); + if (TeamFortress_TeamGetColor(tno) == 0 && !teamplay) { TeamFortress_TeamSetColor(tno); if (TeamFortress_TeamGetColor(tno) == 0) { - sprint(self, PRINT_HIGH, + sprint(pe, PRINT_HIGH, "You cannot start a new team with your color, since another "); - sprint(self, PRINT_HIGH, + sprint(pe, PRINT_HIGH, "already using that color. Change your pants color, then try again.\n"); return (0); } - bprint(PRINT_HIGH, self.netname, " has started the "); + bprint(PRINT_HIGH, pe.netname, " has started the "); bprint(PRINT_HIGH, team, "\n"); - self.immune_to_check = time + 10; + pe.immune_to_check = time + 10; if ((toggleflags & TFLAG_TEAMFRAGS) || (toggleflags & TFLAG_FULLTEAMSCORE)) { - self.frags = TeamFortress_TeamGetScore(tno); + pe.frags = TeamFortress_TeamGetScore(tno); } - stuffcmd(self, "color "); + stuffcmd(pe, "color "); tc = TeamFortress_TeamGetColor(tno) - 1; st = ftos(tc); - stuffcmd(self, st); - stuffcmd(self, "\n"); - self.team_no = tno; - self.lives = TeamFortress_TeamGetLives(tno); - SetTeamName(self); - if (self.playerclass == 0) { - if (TeamFortress_TeamIsCivilian(self.team_no)) { + stuffcmd(pe, st); + stuffcmd(pe, "\n"); + pe.team_no = tno; + pe.lives = TeamFortress_TeamGetLives(tno); + SetTeamName(pe); + if (pe.playerclass == 0) { + if (TeamFortress_TeamIsCivilian(pe.team_no)) { TeamFortress_ChangeClass(11); } } return (1); } - if (!self.deadflag) { - if (self.health == self.max_health && (self.spawn_time + 10) > time && CloseToSpawnPoint() && self.suicide_time <= time) { - self.has_changedteam = 1; - self.clientkillforce = 1; - self.clientkillfree = 1; + bprint(PRINT_HIGH, "MEHT: Checking deadflag\n"); + if (!pe.deadflag) { + if (pe.health == pe.max_health && (pe.spawn_time + 10) > time && CloseToSpawnPoint() && pe.suicide_time <= time) { + pe.has_changedteam = 1; + pe.clientkillforce = 1; + pe.clientkillfree = 1; ClientKill(); - self.has_changedteam = 0; + pe.has_changedteam = 0; } else { - self.clientkillforce = 1; - self.clientkillfree = 0; + pe.clientkillforce = 1; + pe.clientkillfree = 0; ClientKill(); } } // remove engineer buildings - if (self.playerclass == PC_ENGINEER) - Engineer_RemoveBuildings(self); + if (pe.playerclass == PC_ENGINEER) + Engineer_RemoveBuildings(pe); // swap colors for spy last disguise - if (self.playerclass == PC_SPY && self.undercover_team == tno) - self.last_team = self.team_no; + if (pe.playerclass == PC_SPY && pe.undercover_team == tno) + pe.last_team = pe.team_no; // remove existing gas grenades RemoveGasTimers(); - bprint(PRINT_HIGH, self.netname, " has joined the "); + bprint(PRINT_HIGH, pe.netname, " has joined the "); bprint(PRINT_HIGH, team, "\n"); - stuffcmd(self, "color "); + stuffcmd(pe, "color "); tc = TeamFortress_TeamGetColor(tno) - 1; st = ftos(tc); - stuffcmd(self, st); - stuffcmd(self, "\n"); + stuffcmd(pe, st); + stuffcmd(pe, "\n"); if(!skipclasscheck) { - if(self.playerclass == PC_CIVILIAN) { + if(pe.playerclass == PC_CIVILIAN) { if (TeamFortress_TeamIsCivilian(tno)) { - self.team_no = tno; + pe.team_no = tno; TeamFortress_ChangeClass(11); } else { TeamFortress_ChangeClass(0); Menu_Class(0); } } else { - if (self.playerclass == 0) { + if (pe.playerclass == 0) { } else { //Make sure the current class is still legal on the new team override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); @@ -262,35 +266,36 @@ float (float tno, float skipclasscheck) TeamFortress_TeamSet_Options = { } } } - self.team_no = tno; - self.immune_to_check = time + 10; - self.lives = TeamFortress_TeamGetLives(tno); + pe.team_no = tno; + pe.immune_to_check = time + 10; + pe.lives = TeamFortress_TeamGetLives(tno); if ((toggleflags & TFLAG_TEAMFRAGS) || (toggleflags & TFLAG_FULLTEAMSCORE)) { - self.frags = TeamFortress_TeamGetScore(tno); + pe.frags = TeamFortress_TeamGetScore(tno); } - TeamFortress_TeamShowMemberClasses(self); - SetTeamName(self); + TeamFortress_TeamShowMemberClasses(pe); + SetTeamName(pe); if(!skipclasscheck) { - if (self.playerclass == 0) { + if (pe.playerclass == 0) { if (TeamFortress_TeamIsCivilian(tno)) { - self.team_no = tno; + pe.team_no = tno; TeamFortress_ChangeClass(11); } } else { // force to change class if class is forbidden on the new team - if (!IsLegalClass(self.playerclass) && !override_mapclasses) { + if (!IsLegalClass(pe.playerclass) && !override_mapclasses) { TeamFortress_ChangeClass(0); Menu_Class(0); } } } + bprint(PRINT_HIGH, "MEHT: Tdone\n"); return (1); }; float (float tno) TeamFortress_TeamSet = { - return TeamFortress_TeamSet_Options(tno, FALSE); + return TeamFortress_TeamSet_Options(self, tno, FALSE); } void () TeamFortress_CheckTeamCheats = { diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 94efb7cf..75c361be 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -36,11 +36,6 @@ void () Vote_DropLosers; float (string ps_list) List_Count; string (string ps_list, float pf_idx) List_Index; -// global variables -float vote1_cnt, vote2_cnt, vote3_cnt, vote4_cnt, vote5_cnt; -string vote1_map, vote2_map, vote3_map, vote4_map, vote5_map, vote_result; -float vote_started, vote_update, vote_winnercount, vote_decider, vote_abort; - // opens the map voting early // called from weapons.qc:ImpulseCommands() void (entity pe_player) Vote_NextMap = { @@ -533,6 +528,14 @@ void (entity pe_player) Vote_Menu = { else if (time - pe_player.menu_time < CF_MAPVOTE_FORCESHOW) f_timeleft = CF_MAPVOTE_FORCESHOW - (time - pe_player.menu_time); + if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { + //fte+csqc has its own team menu + //ask the client to activate it + Menu_Close(pe_player); + UpdateClientMenu_Vote(pe_player, floor(f_timeleft - 0.1)); + return; + } + s_choose = strzone(strcat("Vote for next map (closes in ", strcat(ftos(floor(f_timeleft - 0.1)), "s):\n\n"))); s_tmp1 = strzone(""); s_tmp2 = strzone(""); @@ -1078,4 +1081,4 @@ string (string ps_list, float pf_idx) List_Index = { return strzone(substr(ps_list, f_start, i - f_start)); return strzone(string_null); -}; \ No newline at end of file +}; From 1421bc99b39fb8549824022e021c2747fa7fb575 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 21 Nov 2019 18:57:40 +1300 Subject: [PATCH 0848/2474] live updates for player lists in admin menu --- csqc/csextradefs.qc | 3 ++ csqc/menu.qc | 108 +++++++++++++++++++++++++++----------------- 2 files changed, 69 insertions(+), 42 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3c620d84..b737cd1c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -54,6 +54,9 @@ float(string id, vector pos, vector size, float alpha, float enabled) hud_panel; vector(float panelid) getPosition; vector(float panelid) getFillSize; +void () SUB_Null = { +}; + typedef struct { string icon; diff --git a/csqc/menu.qc b/csqc/menu.qc index 3580f6f8..430a033c 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -472,6 +472,69 @@ var fo_menu FO_MENU_ADMIN_PLAYERS = { {"-","Prev","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Players(TRUE, player_menu_type, FO_MENU_ADMIN_PLAYERS.page - 1);},MENU_BUTTON}, }, 14, TRUE }; +void action_admin_players(float type) = { + string n, team; + float c = 0, p = 0, spec = 0, userid = 0, enable; + float page = FO_MENU_ADMIN_PLAYERS.page; + for(float i = 0; i < 9; i++) { + n = getplayerkeyvalue(i + (page * 9),"name"); + spec = stof(getplayerkeyvalue(i + (page * 9), "*spectator")); + team = getplayerkeyvalue(i + (page * 9), "team"); + userid = stof(getplayerkeyvalue(i + (page * 9), "userid")); + enable = TRUE; + if(!n){ + enable = FALSE; + print("MEHT: disable ", n ," - no name\n"); + } + if(type == CLIENT_MENU_ADMIN_FORCE_SPEC && spec){ + enable = FALSE; + print("MEHT: disable ", n ," - spectator (force spec)\n"); + } + if(type == CLIENT_MENU_CAPTAIN_PICK) { + if(spec) { + enable = FALSE; + print("MEHT: disable ", n ," - spectator (capt pick)\n"); + } + if(team) { + enable = FALSE; + print("MEHT: disable ", n ," - already picked\n"); + } + if(i + (page * 9) == player_localnum) { + enable = FALSE; + print("MEHT: disable ", n ," - yourself\n"); + } + } + if(type == CLIENT_MENU_CAPTAIN_1 || type == CLIENT_MENU_CAPTAIN_2) { + if(spec) { + enable = FALSE; + print("MEHT: disable ", n ," - spectator (capt select)\n"); + } + if(userid == captain1_temp) { + enable = FALSE; + print("MEHT: disable ", n ," - first captain\n"); + } + } + //if(n && ( + // type != CLIENT_MENU_ADMIN_FORCE_SPEC || + // !spec + //) && !(type == CLIENT_MENU_CAPTAIN_PICK && (team || i + (page * 9) == player_localnum || (userid && (userid == captain1_temp || userid == captain2_temp))))) { + if(enable) { + FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_NORMAL; + FO_MENU_ADMIN_PLAYERS.options[i].name = n; + FO_MENU_ADMIN_PLAYERS.options[i].value = spec?"Spectator":""; + FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_WARNING; + c++; + } else { + FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_DISABLED; + FO_MENU_ADMIN_PLAYERS.options[i].name = n; + FO_MENU_ADMIN_PLAYERS.options[i].value = ""; + FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_DARK; + } + } +} +void action_admin_players_captain_pick() = { + action_admin_players(CLIENT_MENU_CAPTAIN_PICK); +} var fo_menu FO_MENU_ADMIN_ROUNDS = { [0,0], [300,300], "Quad Rounds", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { {"1","1","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, @@ -1071,6 +1134,7 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { if(page > 4) page = 0; FO_MENU_ADMIN_PLAYERS.page = page; player_menu_type = type; + FO_MENU_ADMIN_PLAYERS.update = SUB_Null; if(type == CLIENT_MENU_ADMIN_KICK) { FO_MENU_ADMIN_PLAYERS.title = strcat("Kick ", ftos(page + 1), "/5"); execute_admin_players = execute_admin_players_kick; @@ -1091,52 +1155,12 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { } else if(type == CLIENT_MENU_CAPTAIN_PICK) { FO_MENU_ADMIN_PLAYERS.title = strcat("Pick teammate ", ftos(page + 1), "/5"); execute_admin_players = execute_admin_players_captain_pick; + FO_MENU_ADMIN_PLAYERS.update = action_admin_players_captain_pick; } else { FO_MENU_ADMIN_PLAYERS.title = strcat("Page ", ftos(page + 1), "/5"); execute_admin_players = execute_admin_players_unknown; } - string n, team; - float c = 0, p = 0, spec = 0, userid = 0, enable = FALSE; -/* - * for(float i = 0; i < 32, c < 9; i++) { - n = getplayerkeyvalue(i,"name"); - if(n) { - p++; - } - if(p > page * 9 && p <= (page + 1) * 9) { - spec = stof(getplayerkeyvalue(i, "*spectator")); - FO_MENU_ADMIN_PLAYERS.options[c].state = FO_MENU_STATE_NORMAL; - FO_MENU_ADMIN_PLAYERS.options[c].name = n; - FO_MENU_ADMIN_PLAYERS.options[c].value = spec?"Spectator":""; - c++; - } - } - for(float i = c; i < 9; i++) { - FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_HIDDEN; - } -*/ - for(float i = 0; i < 9; i++) { - n = getplayerkeyvalue(i + (page * 9),"name"); - spec = stof(getplayerkeyvalue(i + (page * 9), "*spectator")); - team = getplayerkeyvalue(i + (page * 9), "team"); - userid = stof(getplayerkeyvalue(i + (page * 9), "userid")); - if(n && ( - type != CLIENT_MENU_ADMIN_FORCE_SPEC || - !spec - ) && !(type == CLIENT_MENU_CAPTAIN_PICK && (team || i + (page * 9) == player_localnum || (userid && (userid == captain1_temp || userid == captain2_temp))))) { - FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_NORMAL; - FO_MENU_ADMIN_PLAYERS.options[i].name = n; - FO_MENU_ADMIN_PLAYERS.options[i].value = spec?"Spectator":""; - FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_WARNING; - c++; - } else { - FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_DISABLED; - FO_MENU_ADMIN_PLAYERS.options[i].name = n; - FO_MENU_ADMIN_PLAYERS.options[i].value = ""; - FO_MENU_ADMIN_PLAYERS.options[i].colour = MENU_BG_DARK; - } - } - + action_admin_players(type); CurrentMenu = &FO_MENU_ADMIN_PLAYERS; fo_hud_menu_active = TRUE; } From 3ddd4dac2248e6b69fc977c70324f08ce776ac3e Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 21 Nov 2019 18:59:32 +1300 Subject: [PATCH 0849/2474] live updates for player lists in admin menu --- csqc/menu.qc | 15 --------------- ssqc/commands.qc | 1 - ssqc/tforttm.qc | 5 ----- 3 files changed, 21 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index 430a033c..33366a3f 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -436,13 +436,11 @@ void execute_admin_players_force_spec(float choice, float page) { void execute_admin_players_captain1(float choice, float page) { string userid = getplayerkeyvalue(choice + (page * 9), "userid"); captain1_temp = stof(userid); - print("MEHT captain 1: ", ftos(choice + (page * 9)),"\n"); FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_2, 0); } void execute_admin_players_captain2(float choice, float page) { string userid = getplayerkeyvalue(choice + (page * 9), "userid"); captain2_temp = stof(userid); - print("MEHT captain 2: ", ftos(choice + (page * 9)),"\n"); //Send server cmd setting captains; reset everyone to observer; spam out captains set message localcmd("cmd captainmode ", ftos(captain1_temp), " ", userid, "\n"); FO_Menu_Admin_Main(TRUE); @@ -450,8 +448,6 @@ void execute_admin_players_captain2(float choice, float page) { void execute_admin_players_captain_pick(float choice, float page) { string userid = getplayerkeyvalue(choice + (page * 9), "userid"); localcmd("cmd captainpick ", userid, "\n"); - //print("not implemented ", ftos(choice + (page * 9)),"\n"); - //Menu_Cancel(); } var fo_menu FO_MENU_ADMIN_PLAYERS = { @@ -484,40 +480,29 @@ void action_admin_players(float type) = { enable = TRUE; if(!n){ enable = FALSE; - print("MEHT: disable ", n ," - no name\n"); } if(type == CLIENT_MENU_ADMIN_FORCE_SPEC && spec){ enable = FALSE; - print("MEHT: disable ", n ," - spectator (force spec)\n"); } if(type == CLIENT_MENU_CAPTAIN_PICK) { if(spec) { enable = FALSE; - print("MEHT: disable ", n ," - spectator (capt pick)\n"); } if(team) { enable = FALSE; - print("MEHT: disable ", n ," - already picked\n"); } if(i + (page * 9) == player_localnum) { enable = FALSE; - print("MEHT: disable ", n ," - yourself\n"); } } if(type == CLIENT_MENU_CAPTAIN_1 || type == CLIENT_MENU_CAPTAIN_2) { if(spec) { enable = FALSE; - print("MEHT: disable ", n ," - spectator (capt select)\n"); } if(userid == captain1_temp) { enable = FALSE; - print("MEHT: disable ", n ," - first captain\n"); } } - //if(n && ( - // type != CLIENT_MENU_ADMIN_FORCE_SPEC || - // !spec - //) && !(type == CLIENT_MENU_CAPTAIN_PICK && (team || i + (page * 9) == player_localnum || (userid && (userid == captain1_temp || userid == captain2_temp))))) { if(enable) { FO_MENU_ADMIN_PLAYERS.options[i].state = FO_MENU_STATE_NORMAL; FO_MENU_ADMIN_PLAYERS.options[i].name = n; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 4c9f6672..31d3905c 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -190,7 +190,6 @@ void (float cap1, float cap2) CaptainMode = { te.current_menu = 0; te.impulse = 0; - bprint(PRINT_HIGH, "MEHT: Setting ", te.netname, " to observer\n"); } if(csqcactive) { UpdateClient_Captains(te, cap1, cap2); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index f0385b95..42bb1f5d 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -159,14 +159,12 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options local float tc; local string team; - bprint(PRINT_HIGH, "MEHT: Setting team to ", ftos(tno), "\n"); if ((intermission_running != 0) || (intermission_exittime > time)) return (0); if (!CF_TeamIsValid) { return 0; } - bprint(PRINT_HIGH, "MEHT: team is valid\n"); if (tno == 1) team = "blue team"; @@ -182,7 +180,6 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options return 0; } - bprint(PRINT_HIGH, "MEHT: Team colour is ", ftos(TeamFortress_TeamGetColor(tno)), "\n"); if (TeamFortress_TeamGetColor(tno) == 0 && !teamplay) { TeamFortress_TeamSetColor(tno); if (TeamFortress_TeamGetColor(tno) == 0) { @@ -214,7 +211,6 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options } return (1); } - bprint(PRINT_HIGH, "MEHT: Checking deadflag\n"); if (!pe.deadflag) { if (pe.health == pe.max_health && (pe.spawn_time + 10) > time && CloseToSpawnPoint() && pe.suicide_time <= time) { pe.has_changedteam = 1; @@ -290,7 +286,6 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options } } - bprint(PRINT_HIGH, "MEHT: Tdone\n"); return (1); }; From d8433461b411f3eab8c1314a8af3f60ff396f697 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 21 Nov 2019 19:11:32 +1300 Subject: [PATCH 0850/2474] revert force specator to not use forceinfokey until all issues are considered --- ssqc/admin.qc | 4 ++-- ssqc/commands.qc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 48b8a2f6..e3030c26 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -119,8 +119,8 @@ void () Admin_DoBan = { void () Admin_ForceSpectator = { bprint4(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); //stuffcmd(self.admin_use, "observe\n"); - forceinfokey(self.admin_use, "*spectator", "1"); - //clientcommand(player, "observe") + //forceinfokey(self.admin_use, "*spectator", "1"); + clientcommand(self.admin_use, "observe"); self.admin_mode = 0; self.admin_use = world; }; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 31d3905c..665216c1 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -888,8 +888,8 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { bprint4(PRINT_HIGH, ent, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); //stuffcmd(ent, "observe\n"); - forceinfokey(ent, "*spectator", "1"); - //clientcommand(player, "observe") + //forceinfokey(ent, "*spectator", "1"); + clientcommand(ent, "observe"); break; } ent = find(ent, classname, "player"); From de67f60c5a3b69f006f25bfcc52c630f0f14f95a Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 21 Nov 2019 19:34:20 +1300 Subject: [PATCH 0851/2474] fix main menu captiain mode button logic --- csqc/menu.qc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index 33366a3f..939b7440 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -819,11 +819,12 @@ void FO_Menu_Game(float force) = { if(is_admin) FO_MENU_GAME_SPECTATOR.num_opts++; CurrentMenu = &FO_MENU_GAME_SPECTATOR; } else { - //print(getplayerkeyvalue(player_localnum, "name"), " is playing a game!\n"); + float userid = stof(getplayerkeyvalue(player_localnum, "userid")); + FO_MENU_GAME.num_opts = 7; FO_MENU_GAME.options[5].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; if(is_admin) FO_MENU_GAME.num_opts++; - FO_MENU_GAME.options[6].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; + FO_MENU_GAME.options[6].state = (userid == captain1 || userid == captain2)?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; if(is_admin) FO_MENU_GAME.num_opts++; CurrentMenu = &FO_MENU_GAME; } @@ -1132,10 +1133,10 @@ void FO_Menu_Admin_Players(float force, float type, float page) = { } else if(type == CLIENT_MENU_CAPTAIN_1) { captain1_temp = 0; captain2_temp = 0; - FO_MENU_ADMIN_PLAYERS.title = strcat("Select Captain 1 ", ftos(page + 1), "/5"); + FO_MENU_ADMIN_PLAYERS.title = strcat("Captain 1 ", ftos(page + 1), "/5"); execute_admin_players = execute_admin_players_captain1; } else if(type == CLIENT_MENU_CAPTAIN_2) { - FO_MENU_ADMIN_PLAYERS.title = strcat("Select Captain 2 ", ftos(page + 1), "/5"); + FO_MENU_ADMIN_PLAYERS.title = strcat("Captain 2 ", ftos(page + 1), "/5"); execute_admin_players = execute_admin_players_captain2; } else if(type == CLIENT_MENU_CAPTAIN_PICK) { FO_MENU_ADMIN_PLAYERS.title = strcat("Pick teammate ", ftos(page + 1), "/5"); From a511223de3dc19c42794477fd7fdf26cb83482e4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 24 Nov 2019 19:36:35 +1300 Subject: [PATCH 0852/2474] fix quad rounds counter in admin menu --- ssqc/csmenu.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index dd51cdc2..79b8faee 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -140,8 +140,7 @@ void Update_ServerAdminInfo(entity pl) = { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SERVER_ADMIN_INFO); WriteByte(MSG_MULTICAST, is_paused || cease_fire); - //WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); - WriteFloat(MSG_MULTICAST, rounds); + WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); WriteFloat(MSG_MULTICAST, infokeyf(world, "round_time")); WriteFloat(MSG_MULTICAST, infokeyf(world, "timelimit")); WriteFloat(MSG_MULTICAST, infokeyf(world, "fraglimit")); From d8f48b9ff36eeffe52c45cfbf0f0ddab25d3052f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 24 Nov 2019 20:36:30 +1300 Subject: [PATCH 0853/2474] fix quad rounds breaking if set without map restart --- ssqc/commands.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 665216c1..930a9cad 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -33,7 +33,8 @@ void () ForceStartMatch = { } void (float inp) SetQuadRounds = { - rounds = inp; + //No idea - for some reason quad rounds have a +1 count to the actual number + rounds = inp + 1; local string cmd; cmd = strcat("localinfo rounds ", ftos(inp), "\n"); localcmd(cmd); From 1b28fae5c6b961a7fecb66130e09aa41b65fa1fe Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 27 Nov 2019 21:02:46 +1300 Subject: [PATCH 0854/2474] panels for descriptions --- csqc/csextradefs.qc | 118 ++----------------------------- csqc/csprogs.src | 1 + csqc/status.qc | 164 ++++++++++++++++++++++++++++++++++++++++++++ share/defs.h | 2 + 4 files changed, 173 insertions(+), 112 deletions(-) create mode 100644 csqc/status.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6824022e..8bc98fdd 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -93,6 +93,8 @@ typedef struct { float PlayerClass; float Gren1; float Gren2; + string MOTD; + string Hint; // scout float ScannerOn; float ScannerRange; @@ -216,6 +218,7 @@ float Editor_SelectedPanel_Index; typedef struct { vector MousePos; } FO_Hud_Settings; +FO_Hud_Settings HudSettings; typedef struct { float grentype; @@ -225,88 +228,6 @@ typedef struct { FO_Hud_Grentimer FO_Hud_Grentimers[5]; -void(string panelid, float display, string text, string icon) drawClipSize = { - if (SBAR.ClipSize || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, text, icon); - } -}; - -void(string panelid, float display, string text, string icon) drawIdentify = { - if (strlen(SBAR.Identify) > 0 || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawIdentifyPanel(panelid, text); - } -}; - -void(string panelid, float display, string text, string icon) drawFlagInfo = { - if (display || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawFlagStatusBar(panelid); - } -}; - -void(string panelid, float display, string text, string icon) drawIconPanel = { - if (display || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, text, icon); - } -}; -void(string panelid, float display, string text, string icon) drawSpecial = { - if (SBAR.PlayerClass || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawClassInfoPanel(panelid, SBAR.PlayerClass); - } -}; -void(string panelid, float display, string text, string icon) drawGrenTimerPanel = { - local float timeleft; - local float timercount = 0; - if (display) { - GetDrawPanel(panelid); - float Scale = DrawPanel.Scale; - float TextScale = DrawPanel.TextScale; - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - if(FO_Hud_Grentimers[i].grentype > 0) { - timeleft = floor(FO_Hud_Grentimers[i].expires - time) + 1; - if(timeleft < 1) { - //Expire and fill the gap if there are any active grentimers afterwards - FO_Hud_Grentimers[i].grentype = 0; - for(float j = i + 1; j < FO_Hud_Grentimers.length; j++) { - FO_Hud_Grentimers[j - 1].grentype = FO_Hud_Grentimers[j].grentype; - FO_Hud_Grentimers[j - 1].expires = FO_Hud_Grentimers[j].expires; - FO_Hud_Grentimers[j - 1].icon_index = FO_Hud_Grentimers[j].icon_index; - } - FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].grentype = 0; - FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].expires = 0; - FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].icon_index = 0; - continue; - } - if(i) { - DrawPanel.Scale = Scale * 0.8; - DrawPanel.TextScale = TextScale * 0.8; - } - Hud_DrawPanelLMP(panelid, ftos(timeleft), HudIcons[FO_Hud_Grentimers[i].icon_index].icon); - DrawPanel.Position = DrawPanel.Position + [0, 24 * DrawPanel.Scale]; - timercount++; - } - } - } - if(fo_hud_editor && (!display || !timercount)) { - GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, "0", ICON_GREN1); - } -}; - -FO_Hud_Settings HudSettings; - - -void(string panelid, float display, string text, string icon) doNothing = {}; - enum { HUD_PANEL_HUDOPTIONS, HUD_PANEL_CLIPSIZE, @@ -318,38 +239,11 @@ enum { HUD_PANEL_IDENTIFY, HUD_PANEL_FLAGINFO, HUD_PANEL_GRENTIMER, - HUD_PANEL_MENU + HUD_PANEL_MENU, + HUD_PANEL_MOTD, + HUD_PANEL_MENU_HINT }; -void(string panelid, float display, string text, string icon) drawSimplePanel = { - if (fo_hud_editor) { - if (hud_panel(panelid, getPosition(HUD_PANEL_MENU), getFillSize(HUD_PANEL_MENU), 0.3, 1)) { - // click event - } - } -} - -var FO_Hud_Panel Hud_Panels[] = { - {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, - {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, - {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 30','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, - {"capspanel",FO_HUD_CAPS_NAME,'10 40','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'10 60','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, - {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 70','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 80','50 26',1,0,1,0, drawIdentify, {return SBAR.Identify;}}, - {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 90','150 260',1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimerpanel","Grenade Timer",'10 100','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, - {"menupanel","Menu",'10 110','200 200',1,0,1,0, drawSimplePanel, {return "";}} -}; - -vector(float panelid) getPosition = { - return Hud_Panels[panelid].Position; -} -vector(float panelid) getFillSize = { - return Hud_Panels[panelid].FillSize; -} - #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 0a73723b..2a9c46e4 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -4,6 +4,7 @@ csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc sui_sys.qc +status.qc menu.qc main.qc events.qc diff --git a/csqc/status.qc b/csqc/status.qc new file mode 100644 index 00000000..1a3fc8ae --- /dev/null +++ b/csqc/status.qc @@ -0,0 +1,164 @@ +void(string panelid, float display, string text, string icon) drawClipSize = { + if (SBAR.ClipSize || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, text, icon); + } +}; + +void(string panelid, float display, string text, string icon) drawIdentify = { + if (strlen(SBAR.Identify) > 0 || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawIdentifyPanel(panelid, text); + } +}; + +void(string panelid, float display, string text, string icon) drawFlagInfo = { + if (display || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawFlagStatusBar(panelid); + } +}; + +void(string panelid, float display, string text, string icon) drawIconPanel = { + if (display || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, text, icon); + } +}; +void(string panelid, float display, string text, string icon) drawSpecial = { + if (SBAR.PlayerClass || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawClassInfoPanel(panelid, SBAR.PlayerClass); + } +}; +void(string panelid, float display, string text, string icon) drawGrenTimerPanel = { + local float timeleft; + local float timercount = 0; + if (display) { + GetDrawPanel(panelid); + float Scale = DrawPanel.Scale; + float TextScale = DrawPanel.TextScale; + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + if(FO_Hud_Grentimers[i].grentype > 0) { + timeleft = floor(FO_Hud_Grentimers[i].expires - time) + 1; + if(timeleft < 1) { + //Expire and fill the gap if there are any active grentimers afterwards + FO_Hud_Grentimers[i].grentype = 0; + for(float j = i + 1; j < FO_Hud_Grentimers.length; j++) { + FO_Hud_Grentimers[j - 1].grentype = FO_Hud_Grentimers[j].grentype; + FO_Hud_Grentimers[j - 1].expires = FO_Hud_Grentimers[j].expires; + FO_Hud_Grentimers[j - 1].icon_index = FO_Hud_Grentimers[j].icon_index; + } + FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].grentype = 0; + FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].expires = 0; + FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].icon_index = 0; + continue; + } + if(i) { + DrawPanel.Scale = Scale * 0.8; + DrawPanel.TextScale = TextScale * 0.8; + } + Hud_DrawPanelLMP(panelid, ftos(timeleft), HudIcons[FO_Hud_Grentimers[i].icon_index].icon); + DrawPanel.Position = DrawPanel.Position + [0, 24 * DrawPanel.Scale]; + timercount++; + } + } + } + if(fo_hud_editor && (!display || !timercount)) { + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, "0", ICON_GREN1); + } +}; + +void(string panelid, float display, string text, string icon) doNothing = {}; + +void(string panelid, float display, string text, string icon) drawSimplePanel = { + if (fo_hud_editor) { + if (hud_panel(panelid, getPosition(HUD_PANEL_MENU), getFillSize(HUD_PANEL_MENU), 0.3, 1)) { + // click event + } + } +} + +float(string panelid) getHudPanel; +FO_Hud_Panel* (float panelid) getHudPanelPointer; + +void(string panelid, float display, string text, string icon) drawTextPanel = { + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + + vector position = getPosition(id); + vector size = getFillSize(id); + vector mediumtext = MENU_TEXT_MEDIUM * panel.Scale; + local float padding = 4 * panel.Scale; + local float transparency = 0.3; + if (fo_hud_editor) { + if (hud_panel(panelid, position, size, 0.3, 1)) { + // click event + } + } else { + if(text) { + sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); + sui_push_frame(position, size); + + sui_fill([0, 0], size, MENU_BG, transparency, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_action_element([0, 0], size, panelid, sui_noop); + sui_pop_frame(); + drawstring( + position + [size.x / 2 - stringwidth(text,1,mediumtext)/2,padding*2], + text, + mediumtext, + MENU_TEXT_2, + 1, + 0 + ); + } + } +} + +var FO_Hud_Panel Hud_Panels[] = { + {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, + {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 30','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, + {"capspanel",FO_HUD_CAPS_NAME,'10 40','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'10 60','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, + {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 70','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 80','50 26',1,0,1,0, drawIdentify, {return SBAR.Identify;}}, + {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 90','150 260',1,0,1,0, drawFlagInfo, {return "";}}, + {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'10 100','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, + {"menupanel","Menu",'10 110','200 200',1,0,1,0, drawSimplePanel, {return "";}}, + {"motdpanel",FO_HUD_MOTD_NAME,'-10 100','50 26',1,0,1,0, drawTextPanel, {return SBAR.MOTD;}}, + {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'10 100','50 26',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, +}; + +float(string panelid) getHudPanel = { + for(float i = 0; i < Hud_Panels.length; i++) { + if(Hud_Panels[i].id == panelid) { + return i; + } + } + return -1; +}; + +FO_Hud_Panel* (float panelid) getHudPanelPointer = { + return &(Hud_Panels[panelid]); +}; + +vector(float panelid) getPosition = { + return Hud_Panels[panelid].Position; +} +vector(float panelid) getFillSize = { + return Hud_Panels[panelid].FillSize; +} diff --git a/share/defs.h b/share/defs.h index 0c4965d4..251d0ee7 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1340,6 +1340,8 @@ #define FO_HUD_GRENTIMER_NAME "Grenade Timer" #define FO_HUD_OPTIONS_NAME "Options" #define FO_HUD_FLAGINFO_NAME "Flag Status" +#define FO_HUD_MOTD_NAME "MOTD" +#define FO_HUD_MENU_HINT_NAME "Menu Hints" #define ICON_CLIPSIZE "textures/wad/clipsize.png" #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" From 64aa4ec68e79b8bb22399873c1bb2b8dde7475c5 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 28 Nov 2019 19:31:24 +1300 Subject: [PATCH 0855/2474] quadmode etc pending status added for menu --- csqc/csextradefs.qc | 12 ++++++++++++ csqc/events.qc | 9 ++++++++- csqc/hud.qc | 6 +++--- csqc/menu.qc | 40 +++++++++++++++++++++++++++++++++------- ssqc/csmenu.qc | 12 +++++++++--- 5 files changed, 65 insertions(+), 14 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index dad839e1..d224cf55 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -57,6 +57,18 @@ vector(float panelid) getFillSize; void () SUB_Null = { }; +enum { + HUD_ALIGN_RIGHT, + HUD_ALIGN_LEFT, + HUD_ALIGN_CENTER +}; + +string HUD_ALIGN[] = { + "Right", + "Left", + "Center" +}; + typedef struct { string icon; diff --git a/csqc/events.qc b/csqc/events.qc index 57f014ad..7d7c1e90 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -227,8 +227,15 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.clanmode = readfloat(); SERVER_ADMIN.quadmode = readfloat(); SERVER_ADMIN.duelmode = readfloat(); - SERVER_ADMIN.pubmode = !SERVER_ADMIN.clanmode && SERVER_ADMIN.quadmode && !SERVER_ADMIN.duelmode; + //SERVER_ADMIN.pubmode = !SERVER_ADMIN.clanmode && !SERVER_ADMIN.quadmode && !SERVER_ADMIN.duelmode; + SERVER_ADMIN.pubmode = (((SERVER_ADMIN.clanmode & 1) || (SERVER_ADMIN.quadmode & 1) || (SERVER_ADMIN.duelmode & 1))?1:0) + + (((SERVER_ADMIN.clanmode & 2) || (SERVER_ADMIN.quadmode & 2) || (SERVER_ADMIN.duelmode & 2))?2:0); + SERVER_ADMIN.pubmode = 3 - SERVER_ADMIN.pubmode; //Invert SERVER_ADMIN.captainmode = readfloat(); + print("MEHT: client clanmode: ", ftos(SERVER_ADMIN.clanmode), "\n"); + print("MEHT: client quadmode: ", ftos(SERVER_ADMIN.quadmode), "\n"); + print("MEHT: client duelmode: ", ftos(SERVER_ADMIN.duelmode), "\n"); + print("MEHT: client pub: ", ftos(SERVER_ADMIN.pubmode), "\n"); break; case MSG_CAPTAINS: captain1 = readfloat(); diff --git a/csqc/hud.qc b/csqc/hud.qc index 3d2d73f5..93f9f550 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -157,7 +157,7 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string // click event } - FO_Hud_Panel selectedPanel = Hud_Panels[Editor_SelectedPanel_Index]; + FO_Hud_Panel* selectedPanel = &Hud_Panels[Editor_SelectedPanel_Index]; drawstring(pos + [4,4], selectedPanel.Name, [8,8], MENU_SELECTED, 1, 0); @@ -176,8 +176,8 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string float ftextalign = selectedPanel.NodeInsertLoc; //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.NodeInsertLoc ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); - if(hud_button("hud_option_textalign_toggle", pos + [size.x - 6 - 48,56], [48, 16], selectedPanel.NodeInsertLoc ? "Left" : "Right")) { - Hud_Panels[Editor_SelectedPanel_Index].NodeInsertLoc = !selectedPanel.NodeInsertLoc; + if(hud_button("hud_option_textalign_toggle", pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.NodeInsertLoc])) { + Hud_Panels[Editor_SelectedPanel_Index].NodeInsertLoc = (selectedPanel.NodeInsertLoc + 1) % 3; } //hud_slider("hud_option_textalign_scroll", pos + [8,64], [32,8], [0,1,1], ftextalign); //if(ftextalign != selectedPanel.NodeInsertLoc) { diff --git a/csqc/menu.qc b/csqc/menu.qc index 939b7440..ebd5bdd4 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -364,6 +364,22 @@ var fo_menu FO_MENU_ADMIN_MAIN = { FO_MENU_ADMIN_MAIN.options[6].value = mapname; } }; + +//Basically bitfields - bit 1 is what the server is currently at, bit 2 what is requested +string (float m) modeStatus = { + switch(m) { + case 0: + return "off"; + case 1: + return "pending off"; + case 2: + return "pending on"; + case 3: + return "on"; + } + return ""; +} + var fo_menu FO_MENU_ADMIN_MODES = { [0,0], [300,300], "Server Modes [2/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { {"1","Pub Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd pubmode\n");},MENU_BORDER_WARNING}, @@ -381,13 +397,13 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"-","Prev - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, }, 13, TRUE, { updateAdminMenuInfo(); - FO_MENU_ADMIN_MODES.options[0].value = SERVER_ADMIN.pubmode?"on":"off"; - FO_MENU_ADMIN_MODES.options[1].value = SERVER_ADMIN.clanmode?"on":"off"; - FO_MENU_ADMIN_MODES.options[2].value = SERVER_ADMIN.quadmode?"on":"off"; - FO_MENU_ADMIN_MODES.options[3].value = SERVER_ADMIN.duelmode?"on":"off"; + FO_MENU_ADMIN_MODES.options[0].value = modeStatus(SERVER_ADMIN.pubmode); + FO_MENU_ADMIN_MODES.options[1].value = modeStatus(SERVER_ADMIN.clanmode); + FO_MENU_ADMIN_MODES.options[2].value = modeStatus(SERVER_ADMIN.quadmode); + FO_MENU_ADMIN_MODES.options[3].value = modeStatus(SERVER_ADMIN.duelmode); FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); - FO_MENU_ADMIN_MODES.options[6].value = ftos(SERVER_ADMIN.captainmode); + FO_MENU_ADMIN_MODES.options[6].value = SERVER_ADMIN.captainmode?"on":"off"; } }; var fo_menu FO_MENU_ADMIN_SETTINGS = { @@ -654,6 +670,8 @@ vector fo_menu_draw(fo_menu * menu) = { local float padding = 4 * scale, titleoffset = 36 * scale; local vector menusize = menu.size * scale; local vector buttonsize = [menusize.x - padding * 2, 24]; + local vector buttonpos = position; + local float buttonhover = FALSE; local vector smalltext = MENU_TEXT_SMALL * textscale, mediumtext = MENU_TEXT_MEDIUM * textscale; local string id = strcat("fo_menu_",menu.title); local vector tempcolour; @@ -703,15 +721,23 @@ vector fo_menu_draw(fo_menu * menu) = { } if(menu.options[i].name) { + buttonpos = position + [padding, titleoffset + row * (buttonsize.y + padding)]; + buttonhover = (Mouse.x > buttonpos.x && Mouse.y > buttonpos.y && Mouse.x < (buttonpos.x + buttonsize.x) && Mouse.y < (buttonpos.y + buttonsize.y)); + if(buttonhover) { + SBAR.Hint = "Hover!!"; + } else { + SBAR.Hint = ""; + } + if(menu.options[i].state == FO_MENU_STATE_NORMAL) { //if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, padding * 3 + smalltext.x)) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, alignment, shortcutoffset.x)) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), buttonpos, buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, alignment, shortcutoffset.x)) { menu.options[i].action(); } } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { if(menu.options[i].name) { //sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, 1, bgcolour, 0.4, 0); - sui_border_box(position + [padding, titleoffset + row * (buttonsize.y + padding)], buttonsize, 1, bgcolour, 0.4, 0); + sui_border_box(buttonpos, buttonsize, 1, bgcolour, 0.4, 0); float disabledtextoffset = 0; if(alignment == SUI_ALIGN_START) { disabledtextoffset = padding + shortcutoffset.x; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 79b8faee..1a571037 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -137,6 +137,12 @@ void UpdateClientMenu_Admin(entity pl) = { } void Update_ServerAdminInfo(entity pl) = { msg_entity = pl; + local float cm = CF_GetSetting("c", "clan", "off"), + qm = CF_GetSetting("quadmode", "quadmode", "off"), + dm = CF_GetSetting("duelmode", "duelmode", "off"); + sprint(pl, PRINT_HIGH, "MEHT: clanmode: ", ftos(cm), "\n"); + sprint(pl, PRINT_HIGH, "MEHT: quadmode: ", ftos(qm), "\n"); + sprint(pl, PRINT_HIGH, "MEHT: duelmode: ", ftos(dm), "\n"); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SERVER_ADMIN_INFO); WriteByte(MSG_MULTICAST, is_paused || cease_fire); @@ -144,9 +150,9 @@ void Update_ServerAdminInfo(entity pl) = { WriteFloat(MSG_MULTICAST, infokeyf(world, "round_time")); WriteFloat(MSG_MULTICAST, infokeyf(world, "timelimit")); WriteFloat(MSG_MULTICAST, infokeyf(world, "fraglimit")); - WriteFloat(MSG_MULTICAST, clanbattle); - WriteFloat(MSG_MULTICAST, quadmode); - WriteFloat(MSG_MULTICAST, duelmode); + WriteFloat(MSG_MULTICAST, (clanbattle?1:0) + (cm?2:0)); + WriteFloat(MSG_MULTICAST, (quadmode?1:0) + (qm?2:0)); + WriteFloat(MSG_MULTICAST, (duelmode?1:0) + (dm?2:0)); WriteFloat(MSG_MULTICAST, captainmode); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } From c6655cd57bb31855f126f9ec62179605b77e7fc5 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 28 Nov 2019 19:32:49 +1300 Subject: [PATCH 0856/2474] remove debugging --- csqc/events.qc | 5 ----- ssqc/csmenu.qc | 3 --- 2 files changed, 8 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 7d7c1e90..448ebfe3 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -227,15 +227,10 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.clanmode = readfloat(); SERVER_ADMIN.quadmode = readfloat(); SERVER_ADMIN.duelmode = readfloat(); - //SERVER_ADMIN.pubmode = !SERVER_ADMIN.clanmode && !SERVER_ADMIN.quadmode && !SERVER_ADMIN.duelmode; SERVER_ADMIN.pubmode = (((SERVER_ADMIN.clanmode & 1) || (SERVER_ADMIN.quadmode & 1) || (SERVER_ADMIN.duelmode & 1))?1:0) + (((SERVER_ADMIN.clanmode & 2) || (SERVER_ADMIN.quadmode & 2) || (SERVER_ADMIN.duelmode & 2))?2:0); SERVER_ADMIN.pubmode = 3 - SERVER_ADMIN.pubmode; //Invert SERVER_ADMIN.captainmode = readfloat(); - print("MEHT: client clanmode: ", ftos(SERVER_ADMIN.clanmode), "\n"); - print("MEHT: client quadmode: ", ftos(SERVER_ADMIN.quadmode), "\n"); - print("MEHT: client duelmode: ", ftos(SERVER_ADMIN.duelmode), "\n"); - print("MEHT: client pub: ", ftos(SERVER_ADMIN.pubmode), "\n"); break; case MSG_CAPTAINS: captain1 = readfloat(); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 1a571037..16e1ba9c 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -140,9 +140,6 @@ void Update_ServerAdminInfo(entity pl) = { local float cm = CF_GetSetting("c", "clan", "off"), qm = CF_GetSetting("quadmode", "quadmode", "off"), dm = CF_GetSetting("duelmode", "duelmode", "off"); - sprint(pl, PRINT_HIGH, "MEHT: clanmode: ", ftos(cm), "\n"); - sprint(pl, PRINT_HIGH, "MEHT: quadmode: ", ftos(qm), "\n"); - sprint(pl, PRINT_HIGH, "MEHT: duelmode: ", ftos(dm), "\n"); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SERVER_ADMIN_INFO); WriteByte(MSG_MULTICAST, is_paused || cease_fire); From e6d5e722972c1d52df8988172ed15da320b010a6 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 30 Nov 2019 14:52:09 +1300 Subject: [PATCH 0857/2474] MOTD client display, custom + default --- csqc/csextradefs.qc | 4 ++ csqc/events.qc | 5 +++ csqc/main.qc | 1 + csqc/menu.qc | 62 +++++++++++++++--------------- csqc/status.qc | 93 +++++++++++++++++++++++++++++++++++++-------- share/commondefs.qc | 1 + ssqc/client.qc | 1 + ssqc/csmenu.qc | 9 +++++ 8 files changed, 129 insertions(+), 47 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d224cf55..06523508 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -22,6 +22,8 @@ vector MENU_TEXT_MEDIUM = '16 16 0'; vector MENU_TEXT_LARGE = '24 24 0'; float MENU_START_CONTENT = 32; +#define MOTD_TIME 30 + .float owned_by; .string netname; .float playerid; @@ -43,6 +45,7 @@ float captain2; float captain1_temp; float captain2_temp; float is_admin; +float motd_expiry; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; @@ -115,6 +118,7 @@ typedef struct { float Gren2; string MOTD; string Hint; + float GameMode; // scout float ScannerOn; float ScannerRange; diff --git a/csqc/events.qc b/csqc/events.qc index 448ebfe3..ef98124a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -236,6 +236,11 @@ void() CSQC_Parse_Event = { captain1 = readfloat(); captain2 = readfloat(); break; + case MSG_MOTD: + SBAR.MOTD = strcat(readstring(), "\n", readstring()); + SBAR.GameMode = readfloat(); + motd_expiry = time + MOTD_TIME; + break; } } diff --git a/csqc/main.qc b/csqc/main.qc index a57019cf..4cfcff60 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -52,6 +52,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); + SBAR.Hint = ""; clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! diff --git a/csqc/menu.qc b/csqc/menu.qc index ebd5bdd4..078d8da1 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -43,6 +43,7 @@ typedef struct { float active; void() update; float page; + string description; } fo_menu; class fo_menu_option_2 { @@ -77,12 +78,12 @@ fo_menu_option MenuSpacer = {"","","","",FO_MENU_STATE_SPACER}; var fo_menu FO_MENU_GAME = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Select Team", "","",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, - {"2","Select Class","","",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, - {"3","Ready","","",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, + {"1","Select Team", "","Join a team",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, + {"2","Select Class","","Each class has unique strenghts and weaknesses.",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, + {"3","Ready","","Only applies to organised games",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, MenuSpacer, - {"4","Spectate", "","",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, - {"5","Server Admin", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + {"4","Spectate", "","Do not participate in the game, but observe as a ghost",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, + {"5","Server Admin", "","Admin options for the server",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, {"6","Captain's Menu", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0);},MENU_BUTTON}, MenuSpacer, {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, @@ -106,10 +107,10 @@ var fo_menu FO_MENU_SPECTATOR_TRACK = { var fo_menu FO_MENU_TEAM = { [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Blue team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, - {"2","Red team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, - {"3","Yellow team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, - {"4","Green team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 4\n");Menu_Cancel();},'0.4 0.7 0.3'}, + {"1","Blue team","","Known for cunning and strategy, Blues like to attack first",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, + {"2","Red team","","Excellent at standing their ground, Reds won't stand for being attacked",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, + {"3","Yellow team","","The best team",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, + {"4","Green team","","Also okay",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 4\n");Menu_Cancel();},'0.4 0.7 0.3'}, MenuSpacer, {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam auto\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, @@ -118,15 +119,15 @@ var fo_menu FO_MENU_TEAM = { }; var fo_menu FO_MENU_CLASS = { [0,0], [300,200], "Select Class", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { - {"1","Scout","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 1\n");Menu_Cancel();},MENU_BUTTON}, - {"2","Sniper","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 2\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Soldier","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 3\n");Menu_Cancel();},MENU_BUTTON}, - {"4","Demoman","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 4\n");Menu_Cancel();},MENU_BUTTON}, - {"5","Medic","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 5\n");Menu_Cancel();},MENU_BUTTON}, - {"6","Heavy Weapons","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 6\n");Menu_Cancel();},MENU_BUTTON}, - {"7","Pyro","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 7\n");Menu_Cancel();},MENU_BUTTON}, - {"8","Spy","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 8\n");Menu_Cancel();},MENU_BUTTON}, - {"9","Engineer","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 9\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Scout","","Fastest but weakest. Has a scanner (menu) and a `dash` (special)",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 1\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Sniper","","Long charge times but powerful hits.",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 2\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Soldier","","All-rounder. Has a rocket launcher",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 3\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Demoman","","'special' to detonate pipebombs. 'menu' for detpack",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 4\n");Menu_Cancel();},MENU_BUTTON}, + {"5","Medic","","Fast and immune to concussions and disease. \nBioweapon can heal/supercharge teammates and infect enemies\n'special' allows automatically healing nearby teammates",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 5\n");Menu_Cancel();},MENU_BUTTON}, + {"6","Heavy Weapons","","Toughest of the classes. 'special' allows spinning the cannon without firing",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 6\n");Menu_Cancel();},MENU_BUTTON}, + {"7","Pyro","","Can still pull off smaller rjs. ",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 7\n");Menu_Cancel();},MENU_BUTTON}, + {"8","Spy","","Can disguise as the enemy and feign death",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 8\n");Menu_Cancel();},MENU_BUTTON}, + {"9","Engineer","","Can build sentry guns and ammo dispensers. Also has powerful EMP grenades as secondaries",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 9\n");Menu_Cancel();},MENU_BUTTON}, {"0","Random Playerclass","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 10\n");Menu_Cancel();},MENU_BUTTON}, }, 10, TRUE }; @@ -347,10 +348,10 @@ void updateAdminMenuInfo() = { var fo_menu FO_MENU_ADMIN_MAIN = { [0,0], [300,300], "Server Admin [1/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { - {"1","Ceasefire","","",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");},MENU_BORDER_WARNING}, + {"1","Ceasefire","","Pause the game",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");},MENU_BORDER_WARNING}, {"2","Kick...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_KICK, 0);},MENU_BORDER_WARNING}, {"3","Ban...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_BAN, 0);},MENU_BORDER_WARNING}, - {"4","Force Spectate...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_FORCE_SPEC, 0);},MENU_BORDER_WARNING}, + {"4","Force Spectate...","","Force someone to be a spectator",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_FORCE_SPEC, 0);},MENU_BORDER_WARNING}, {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd randomise\n");},MENU_BORDER_WARNING}, {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd restart\n"); Menu_Cancel();},MENU_BORDER_WARNING}, MenuSpacer, @@ -382,14 +383,14 @@ string (float m) modeStatus = { var fo_menu FO_MENU_ADMIN_MODES = { [0,0], [300,300], "Server Modes [2/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { - {"1","Pub Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd pubmode\n");},MENU_BORDER_WARNING}, - {"2","Clan Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd clanmode\n");},MENU_BORDER_WARNING}, - {"3","Quad Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd quadmode\n");},MENU_BORDER_WARNING}, - {"4","Duel Mode","","",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, - {"5","Quad Rounds...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, - {"6","Quad Round Time...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, - {"7","Captains Mode","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BG_DARK}, - {"8","Force Start","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, + {"1","Pub Mode","","Public play, anything goes",FO_MENU_STATE_NORMAL,{localcmd("cmd pubmode\n");},MENU_BORDER_WARNING}, + {"2","Clan Mode","","Game has a prematch",FO_MENU_STATE_NORMAL,{localcmd("cmd clanmode\n");},MENU_BORDER_WARNING}, + {"3","Quad Mode","","Play for a set number of rounds, designed for attack vs defence",FO_MENU_STATE_NORMAL,{localcmd("cmd quadmode\n");},MENU_BORDER_WARNING}, + {"4","Duel Mode","","Simplifies 1 on 1 action",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, + {"5","Quad Rounds...","","Number of rounds in Quad mode. Usually 2",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, + {"6","Quad Round Time...","","Round time for each quad round",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, + {"7","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BG_DARK}, + {"8","Force Start","","Skip prematch and start the game\nPlease use sparingly",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, MenuSpacer, @@ -704,6 +705,7 @@ vector fo_menu_draw(fo_menu * menu) = { 0 ); float row = 0; + SBAR.Hint = menu.description; for(float i = 0; i < FO_MENU_MAX_OPTIONS; i++) { vector shortcutoffset = [0,0], valueoffset = [0,0]; @@ -724,9 +726,7 @@ vector fo_menu_draw(fo_menu * menu) = { buttonpos = position + [padding, titleoffset + row * (buttonsize.y + padding)]; buttonhover = (Mouse.x > buttonpos.x && Mouse.y > buttonpos.y && Mouse.x < (buttonpos.x + buttonsize.x) && Mouse.y < (buttonpos.y + buttonsize.y)); if(buttonhover) { - SBAR.Hint = "Hover!!"; - } else { - SBAR.Hint = ""; + SBAR.Hint = menu.options[i].description; } if(menu.options[i].state == FO_MENU_STATE_NORMAL) { diff --git a/csqc/status.qc b/csqc/status.qc index 1a3fc8ae..bbb25cb9 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -98,7 +98,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { vector position = getPosition(id); vector size = getFillSize(id); - vector mediumtext = MENU_TEXT_MEDIUM * panel.Scale; + vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; local float transparency = 0.3; if (fo_hud_editor) { @@ -106,23 +106,84 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { // click event } } else { - if(text) { - sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); - sui_push_frame(position, size); + if(text && text != "") { + //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); + //sui_push_frame(position, size); - sui_fill([0, 0], size, MENU_BG, transparency, 0); + //sui_fill([0, 0], size, MENU_BG, transparency, 0); - sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_action_element([0, 0], size, panelid, sui_noop); - sui_pop_frame(); - drawstring( - position + [size.x / 2 - stringwidth(text,1,mediumtext)/2,padding*2], - text, - mediumtext, - MENU_TEXT_2, - 1, - 0 - ); + //sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + //sui_action_element([0, 0], size, panelid, sui_noop); + //sui_pop_frame(); + if(id == HUD_PANEL_MOTD) { + if(!intermission && time < motd_expiry && !team_no) { + local string motd = serverkey("hostname"); + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2], + motd, + mediumtext*1.5, + MENU_TEXT_4, + 1, + 0 + ); + if(strlen(SBAR.MOTD) <= 1) { + motd = "Welcome to FortressOne"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*2], + motd, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + motd = "www.github.com/FortressOne"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*3], + motd, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + motd = "FortressOne.org"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*4], + motd, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + } else { + local float lines = tokenizebyseparator(SBAR.MOTD, "\n"); + for (float i = 0; i <= lines; i++) { + motd = argv(i); + // tokenize doesn't handle newlines very well + motd = strreplace("\n", "", motd); + motd = strtrim(motd); + if (strlen(motd) > 0) { + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(i+2)], + motd, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + } + } + } + } + } else { + drawstring( + position + [size.x / 2 - stringwidth(text,1,mediumtext)/2,padding*2], + text, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + } } } } diff --git a/share/commondefs.qc b/share/commondefs.qc index f2099218..8d641c06 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -17,6 +17,7 @@ #define MSG_DISPENSER_POS 10 #define MSG_SERVER_ADMIN_INFO 11 #define MSG_CAPTAINS 12 +#define MSG_MOTD 13 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/client.qc b/ssqc/client.qc index f590c1bf..9ae38e4c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2406,6 +2406,7 @@ void (optional float csqcactive) ClientConnect = { } tfdet = find(tfdet, classname, "info_tfgoal"); } + UpdateClientMOTD(self); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 16e1ba9c..9623ac3b 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -197,3 +197,12 @@ void UpdateClient_Captains(entity pl, float cap1, float cap2) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientMOTD(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_MOTD); + WriteString(MSG_MULTICAST, infokey(world, "motd1")); + WriteString(MSG_MULTICAST, infokey(world, "motd2")); + WriteFloat(MSG_MULTICAST, (clanbattle?1:0) + (quadmode?2:0) + (duelmode?4:0)); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} From 1e020014315e8b5e1c7f2b4666dc573aff06cbf3 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 1 Dec 2019 18:56:21 +1300 Subject: [PATCH 0858/2474] fix multiline hints --- csqc/status.qc | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index bbb25cb9..e03ac8cc 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -101,6 +101,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; local float transparency = 0.3; + local float lines; if (fo_hud_editor) { if (hud_panel(panelid, position, size, 0.3, 1)) { // click event @@ -155,7 +156,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { 0 ); } else { - local float lines = tokenizebyseparator(SBAR.MOTD, "\n"); + lines = tokenizebyseparator(SBAR.MOTD, "\n"); for (float i = 0; i <= lines; i++) { motd = argv(i); // tokenize doesn't handle newlines very well @@ -175,14 +176,24 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { } } } else { - drawstring( - position + [size.x / 2 - stringwidth(text,1,mediumtext)/2,padding*2], - text, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); + lines = tokenizebyseparator(text, "\n"); + local string line; + for (float i = 0; i <= lines; i++) { + line = argv(i); + // tokenize doesn't handle newlines very well + line = strreplace("\n", "", line); + line = strtrim(line); + if (strlen(line) > 0) { + drawstring( + position + [size.x / 2 - stringwidth(line,1,mediumtext)/2,padding*2 + mediumtext.y*i], + line, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + } + } } } } From b195c33cfca5fd13ee9a426264e893191de72e96 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 7 Dec 2019 23:31:44 +1300 Subject: [PATCH 0859/2474] fix some reconnect and spec join bugs; motd displays your ready status in quadmode etc --- csqc/csextradefs.qc | 4 ++++ csqc/events.qc | 7 ++++++ csqc/main.qc | 1 + csqc/status.qc | 53 +++++++++++++++++++++++++++++++++++++++++++++ share/commondefs.qc | 1 + share/defs.h | 1 + ssqc/clan.qc | 15 ++++++++++--- ssqc/client.qc | 18 ++++++++++++--- ssqc/csmenu.qc | 11 +++++++++- ssqc/quadmode.qc | 6 +++++ ssqc/world.qc | 1 + 11 files changed, 111 insertions(+), 7 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 06523508..aaead0ab 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -15,6 +15,7 @@ vector MENU_TEXT_3 = '1 1 0'; vector MENU_TEXT_4 = '0.8 0.5 0'; vector MENU_HIGHLIGHT = '1 1 1'; vector MENU_TEXT_WARNING = '0.8 0 0'; +vector MENU_TEXT_GREEN = '0 0.8 0'; vector MENU_DARKEN = '1 1 1'; vector MENU_TEXT_SMALL = '8 8 0'; @@ -118,7 +119,10 @@ typedef struct { float Gren2; string MOTD; string Hint; + //1 = Clanmode, 2 = Quadmode, 4 = Duelmode, 8 = Prematch float GameMode; + float Ready; + float CountdownStarted; // scout float ScannerOn; float ScannerRange; diff --git a/csqc/events.qc b/csqc/events.qc index ef98124a..e2527fee 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -239,6 +239,13 @@ void() CSQC_Parse_Event = { case MSG_MOTD: SBAR.MOTD = strcat(readstring(), "\n", readstring()); SBAR.GameMode = readfloat(); + SBAR.CountdownStarted = FALSE; + motd_expiry = time + MOTD_TIME; + break; + case MSG_PREMATCH: + float prematch = readbyte(); + SBAR.CountdownStarted = readbyte(); + SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 8) + (prematch?8:0); motd_expiry = time + MOTD_TIME; break; } diff --git a/csqc/main.qc b/csqc/main.qc index 4cfcff60..877b1f81 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -51,6 +51,7 @@ noref void() CSQC_WorldLoaded = { noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); + SBAR.Ready = getstatf(STAT_READY); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); SBAR.Hint = ""; clearscene(); diff --git a/csqc/status.qc b/csqc/status.qc index e03ac8cc..928432ab 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -102,6 +102,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { local float padding = 4 * panel.Scale; local float transparency = 0.3; local float lines; + local string gamemode; if (fo_hud_editor) { if (hud_panel(panelid, position, size, 0.3, 1)) { // click event @@ -155,6 +156,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { 1, 0 ); + lines = 3; } else { lines = tokenizebyseparator(SBAR.MOTD, "\n"); for (float i = 0; i <= lines; i++) { @@ -175,6 +177,57 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { } } } + //Prematch + if(SBAR.GameMode & 8) { + if(SBAR.GameMode & 4) { + gamemode = "^4Duel^7"; + } else if(SBAR.GameMode & 2) { + gamemode = "^3Quad^7"; + } else if(SBAR.GameMode & 1) { + gamemode = "^1Clan Battle^7"; + } + motd = strcat("This Server is set to ", gamemode, " Mode (prematch)"); + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(lines+3)], + motd, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + if(team_no && !SBAR.CountdownStarted) { + motd = "You are"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(lines+4)], + motd, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + if(SBAR.Ready) { + motd = "Ready"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2 + mediumtext.y*(lines+5)], + motd, + mediumtext*1.5, + MENU_TEXT_GREEN, + 1, + 0 + ); + } else { + motd = "NOT Ready"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2 + mediumtext.y*(lines+5)], + motd, + mediumtext*1.5, + MENU_TEXT_WARNING, + 1, + 0 + ); + } + } + } } else { lines = tokenizebyseparator(text, "\n"); local string line; diff --git a/share/commondefs.qc b/share/commondefs.qc index 8d641c06..c54262db 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -18,6 +18,7 @@ #define MSG_SERVER_ADMIN_INFO 11 #define MSG_CAPTAINS 12 #define MSG_MOTD 13 +#define MSG_PREMATCH 14 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/share/defs.h b/share/defs.h index 251d0ee7..32de5585 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1373,3 +1373,4 @@ // stats // first 32 are reserved #define STAT_TEAMNO 33 +#define STAT_READY 34 diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 8c64ed5b..1439b598 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -103,6 +103,9 @@ void () StartMatch = te = find (te, classname, "info_tfgoal"); } } + cb_prematch = 0; + cease_fire = 0; + te = find(world, classname, "player"); while (te) { oldself = self; @@ -114,13 +117,13 @@ void () StartMatch = setspawnparms(self); if (!quadmode) PutClientInServer(); + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(self, TRUE); + } self = oldself; te = find(te, classname, "player"); } - cb_prematch = 0; - cease_fire = 0; - te = find(world, classname, "prematch"); te.classname = "match"; te.cnt = (timelimit / 60); @@ -287,6 +290,9 @@ void () ResetBreakAndReady = { te.is_ready = 0; v_break = 0; v_ready = 0; + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(te, TRUE); + } te = find (te, classname, "player"); } } @@ -924,6 +930,9 @@ void () PreMatch_Message = { else sprint(p, PRINT_HIGH, "Type \s/ready\s in the console if you are ready to start the match\n"); stuffcmd(p, "play buttons/switch04.wav\n"); + if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(p, FALSE); + } } p = find(p, classname, "player"); } diff --git a/ssqc/client.qc b/ssqc/client.qc index 9ae38e4c..e4ebed84 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -188,7 +188,7 @@ void InitPrematch() pm_message.nextthink = 1; game_locked = CF_GetSetting("lg", "locked_game", "off"); - + } void (entity goalitem) SetFlagSendMethod = { @@ -767,6 +767,16 @@ void () DecodeLevelParms = { self.playerclass = parm12; if (parm15) self.is_admin = parm15; + + local entity p = find(world, classname, "player"); + while (p != world) { + if (p.netname != "") { + if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { + UpdateClientMOTD(p); + } + } + p = find(p, classname, "player"); + } }; entity() FindIntermission = @@ -2313,6 +2323,7 @@ void () PlayerPostThink = { } }; +//do not rely on csqcactive - it may misbehave when using `join` from spectator void (optional float csqcactive) ClientConnect = { local entity te; local string st; @@ -2359,7 +2370,7 @@ void (optional float csqcactive) ClientConnect = { while (te) { if (te.tf_id == self.tf_id) { got_one = 1; - TeamFortress_TeamSet_Options(te, te.team_no, TRUE); + TeamFortress_TeamSet_Options(self, te.team_no, TRUE); self.frags = te.frags; self.real_frags = te.real_frags; if (!(toggleflags & TFLAG_TEAMFRAGS) && @@ -2398,7 +2409,7 @@ void (optional float csqcactive) ClientConnect = { InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3), FLAGINFO_ICON_FLAG); InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4), FLAGINFO_ICON_FLAG); } - if(csqcactive) { + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { tfdet = find(world, classname, "info_tfgoal"); while (tfdet) { if (tfdet.track_goal) { @@ -2407,6 +2418,7 @@ void (optional float csqcactive) ClientConnect = { tfdet = find(tfdet, classname, "info_tfgoal"); } UpdateClientMOTD(self); + //UpdateClientPrematch(self); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 9623ac3b..fdb13889 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -203,6 +203,15 @@ void UpdateClientMOTD(entity pl) = { WriteByte(MSG_MULTICAST, MSG_MOTD); WriteString(MSG_MULTICAST, infokey(world, "motd1")); WriteString(MSG_MULTICAST, infokey(world, "motd2")); - WriteFloat(MSG_MULTICAST, (clanbattle?1:0) + (quadmode?2:0) + (duelmode?4:0)); + WriteFloat(MSG_MULTICAST, ((clanbattle?1:0) + (quadmode?2:0) + (duelmode?4:0) + (cb_prematch?8:0))); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientPrematch(entity pl, float countdownstarted) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_PREMATCH); + WriteByte(MSG_MULTICAST, cb_prematch?1:0); + WriteByte(MSG_MULTICAST, countdownstarted); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 4a4d7256..2c94ceb6 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -143,6 +143,9 @@ void () QuadRoundBegin = { TeamFortress_RemoveTimers(); setspawnparms(self); PutClientInServer(); + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(self, TRUE); + } self = oldself; te = find (te, classname, "player"); } @@ -245,6 +248,9 @@ void () StartQuadRound = p.movetype = MOVETYPE_NONE; p.modelindex = 0; p.model = string_null; + if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(p, TRUE); + } } p = find(p, classname, "player"); } diff --git a/ssqc/world.qc b/ssqc/world.qc index d55fef71..477af0f6 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -321,6 +321,7 @@ void () worldspawn = { lightstyle(63, "a"); clientstat(STAT_TEAMNO, EV_FLOAT, team_no); + clientstat(STAT_READY, EV_FLOAT, is_ready); entity worldspawnent; worldspawnent = spawn(); From c48a759c5cfe438756ca9c4c36ad7787a6f93310 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 13 Dec 2019 23:06:37 +1300 Subject: [PATCH 0860/2474] +showscores hides menus and MOTD, extra round info in MOTD display, addressed some 'white ghost' scenarios --- csqc/csextradefs.qc | 3 +++ csqc/events.qc | 6 +++++- csqc/main.qc | 6 ++++++ csqc/menu.qc | 16 +++++++------- csqc/status.qc | 51 +++++++++++++++++++++++++++++++++++++++++++-- ssqc/clan.qc | 4 ++-- ssqc/client.qc | 3 ++- ssqc/csmenu.qc | 6 ++++-- ssqc/quadmode.qc | 42 +++++++++++++++++++++---------------- ssqc/tforthlp.qc | 2 +- 10 files changed, 104 insertions(+), 35 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index aaead0ab..82193db9 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -47,6 +47,9 @@ float captain1_temp; float captain2_temp; float is_admin; float motd_expiry; +float quad_round; +float quad_rounds_total; +float showingscores; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index e2527fee..55a358ae 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -241,12 +241,16 @@ void() CSQC_Parse_Event = { SBAR.GameMode = readfloat(); SBAR.CountdownStarted = FALSE; motd_expiry = time + MOTD_TIME; + quad_rounds_total = readfloat(); break; case MSG_PREMATCH: float prematch = readbyte(); SBAR.CountdownStarted = readbyte(); - SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 8) + (prematch?8:0); + SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 8) + ((prematch & 1)?8:0); + SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 16) + ((prematch & 2)?16:0); + SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 32) + ((prematch & 4)?32:0); motd_expiry = time + MOTD_TIME; + quad_round = readfloat(); break; } } diff --git a/csqc/main.qc b/csqc/main.qc index 877b1f81..425a83b7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -137,6 +137,12 @@ noref float(string cmd) CSQC_ConsoleCommand = { } localcmd("gren2_server"); break; + case "+showscores": + showingscores = TRUE; + break; + case "-showscores": + showingscores = FALSE; + break; } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index 078d8da1..d990d502 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -96,7 +96,7 @@ var fo_menu FO_MENU_GAME_SPECTATOR = { MenuSpacer, {"3","Server Admin", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, MenuSpacer, - {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("m_main\n"); Menu_Cancel();},MENU_BUTTON}, + {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, }, 6, TRUE }; var fo_menu FO_MENU_SPECTATOR_TRACK = { @@ -652,11 +652,11 @@ vector fo_menu_draw(fo_menu * menu) = { if(fo_hud_editor) return position; - if(!menu.active) { + if(!menu.active || showingscores) { setcursormode(FALSE); return position; } - + setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); if(menu.update) { @@ -840,18 +840,18 @@ void FO_Menu_Game(float force) = { return; if(is_spectator) { //print(getplayerkeyvalue(player_localnum, "name"), " is a spectator!\n"); - FO_MENU_GAME_SPECTATOR.num_opts = 3; + //FO_MENU_GAME_SPECTATOR.num_opts = 3; FO_MENU_GAME_SPECTATOR.options[3].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; - if(is_admin) FO_MENU_GAME_SPECTATOR.num_opts++; + //if(is_admin) FO_MENU_GAME_SPECTATOR.num_opts++; CurrentMenu = &FO_MENU_GAME_SPECTATOR; } else { float userid = stof(getplayerkeyvalue(player_localnum, "userid")); - FO_MENU_GAME.num_opts = 7; + //FO_MENU_GAME.num_opts = 7; FO_MENU_GAME.options[5].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; - if(is_admin) FO_MENU_GAME.num_opts++; + //if(is_admin) FO_MENU_GAME.num_opts++; FO_MENU_GAME.options[6].state = (userid == captain1 || userid == captain2)?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; - if(is_admin) FO_MENU_GAME.num_opts++; + //if(is_admin) FO_MENU_GAME.num_opts++; CurrentMenu = &FO_MENU_GAME; } fo_hud_menu_active = TRUE; diff --git a/csqc/status.qc b/csqc/status.qc index 928432ab..a84504c9 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -108,6 +108,27 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { // click event } } else { + if(showingscores) { + return; + } + /* + drawstring( + [50,350], + strcat("MEHT: Prematch: ", ftos(SBAR.GameMode & 8), ", Round Active: ", ftos(SBAR.GameMode & 16), ", Round Over: ", ftos(SBAR.GameMode & 32), ", CountdownStarted: ", ftos(SBAR.CountdownStarted)), + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + drawstring( + [50,370], + strcat("MEHT: Round: ", ftos(quad_round), "/", ftos(quad_rounds_total)), + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + */ if(text && text != "") { //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); //sui_push_frame(position, size); @@ -186,7 +207,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { } else if(SBAR.GameMode & 1) { gamemode = "^1Clan Battle^7"; } - motd = strcat("This Server is set to ", gamemode, " Mode (prematch)"); + motd = strcat("This Server is set to ", gamemode, " Mode", (((SBAR.GameMode & 8) && !(SBAR.GameMode & 16))?" (prematch)":"")); drawstring( position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(lines+3)], motd, @@ -195,7 +216,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { 1, 0 ); - if(team_no && !SBAR.CountdownStarted) { + if(team_no && !SBAR.CountdownStarted && !(SBAR.GameMode & 16)) { motd = "You are"; drawstring( position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(lines+4)], @@ -228,6 +249,32 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { } } } + //Quad mode only + if(SBAR.GameMode & 2) { + if(SBAR.CountdownStarted) { + if(quad_round <= 1) { + motd = "Match over"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], + motd, + mediumtext*1.2, + MENU_TEXT_2, + 1, + 0 + ); + } else { + motd = strcat("Starting Round ", ftos(quad_rounds_total + 2 - quad_round), " of ", ftos(quad_rounds_total)); + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], + motd, + mediumtext*1.2, + MENU_TEXT_2, + 1, + 0 + ); + } + } + } } else { lines = tokenizebyseparator(text, "\n"); local string line; diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 1439b598..6bb21ecc 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -183,7 +183,7 @@ void () PreMatch_Think = { if (self.cnt2 == 1) { p = find(world, classname, "player"); while (p != world) { - if (p.netname != "") { + if (p.netname != "" && p.team_no && p.playerclass) { p.respawn_time = (time + 2); p.takedamage = 0; p.solid = 0; @@ -201,7 +201,7 @@ void () PreMatch_Think = { self.think = SUB_Remove; p = find(world, classname, "player"); while (p != world) { - if (p.netname != "") { + if (p.netname != "" && p.team_no && p.playerclass) { p.takedamage = 2; p.solid = 3; p.movetype = 3; diff --git a/ssqc/client.qc b/ssqc/client.qc index e4ebed84..91a66469 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2418,7 +2418,8 @@ void (optional float csqcactive) ClientConnect = { tfdet = find(tfdet, classname, "info_tfgoal"); } UpdateClientMOTD(self); - //UpdateClientPrematch(self); + if(quadmode) + UpdateClientPrematch(self, !cb_prematch); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index fdb13889..9036a42b 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -203,7 +203,8 @@ void UpdateClientMOTD(entity pl) = { WriteByte(MSG_MULTICAST, MSG_MOTD); WriteString(MSG_MULTICAST, infokey(world, "motd1")); WriteString(MSG_MULTICAST, infokey(world, "motd2")); - WriteFloat(MSG_MULTICAST, ((clanbattle?1:0) + (quadmode?2:0) + (duelmode?4:0) + (cb_prematch?8:0))); + WriteFloat(MSG_MULTICAST, ((clanbattle?1:0) + (quadmode?2:0) + (duelmode?4:0) + (cb_prematch?8:0) + (round_active?16:0) + (round_over?32:0))); + WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } @@ -211,7 +212,8 @@ void UpdateClientPrematch(entity pl, float countdownstarted) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_PREMATCH); - WriteByte(MSG_MULTICAST, cb_prematch?1:0); + WriteByte(MSG_MULTICAST, ((cb_prematch?1:0 + (round_active?2:0) + (round_over?4:0)))); WriteByte(MSG_MULTICAST, countdownstarted); + WriteFloat(MSG_MULTICAST, rounds); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 2c94ceb6..8382dae8 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -132,19 +132,23 @@ void () QuadRoundBegin = { te = find(te, classname, "func_breakable"); } cb_prematch = 0; + round_active = 1; + round_over = 0; te = find(world, classname, "player"); while (te != world) { oldself = self; self = te; - self.takedamage = DAMAGE_AIM; - self.solid = SOLID_SLIDEBOX; - self.movetype = MOVETYPE_WALK; - TeamFortress_RemoveTimers(); - setspawnparms(self); - PutClientInServer(); + if(self.team_no && self.playerclass) { + self.takedamage = DAMAGE_AIM; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_WALK; + TeamFortress_RemoveTimers(); + setspawnparms(self); + PutClientInServer(); + } if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - UpdateClientPrematch(self, TRUE); + UpdateClientPrematch(self, FALSE); } self = oldself; te = find (te, classname, "player"); @@ -152,8 +156,7 @@ void () QuadRoundBegin = { // lightstyle (0, "m"); bprint(2, "QUAD ROUND BEGINS NOW\n"); - round_active = 1; - round_over = 0; + if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; self.cnt2 = 60; @@ -198,7 +201,7 @@ void () QuadRoundInit = { self.think = QuadRoundBegin; p = find(world, classname, "player"); while (p != world) { - if (p.netname != "") { + if (p.netname != "" && p.team_no && p.playerclass) { p.takedamage = DAMAGE_AIM; p.solid = SOLID_SLIDEBOX; p.movetype = MOVETYPE_WALK; @@ -237,24 +240,26 @@ void () StartQuadRound = local entity p; lightstyle(0, "m"); - cb_prematch = 1; cease_fire = 0; p = find(world, classname, "player"); while (p != world) { - if (p.netname != "") { + if (p.netname != "" && p.team_no && p.playerclass) { p.takedamage = DAMAGE_NO; p.solid = SOLID_NOT; p.movetype = MOVETYPE_NONE; p.modelindex = 0; p.model = string_null; - if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { - UpdateClientPrematch(p, TRUE); - } } + if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(p, TRUE); + } p = find(p, classname, "player"); } + cb_prematch = 1; + round_over = 1; + if (rounds == 1) { quad_winner = CheckWinningTeam(); if (quad_winner == 0) @@ -269,13 +274,16 @@ void () StartQuadRound = bprint(2, "Green Team Wins!\n"); p = find (world, classname, "player"); while (p != world) { - if (p.netname != "") { + if (p.netname != "" && p.team_no && p.playerclass) { p.takedamage = DAMAGE_NO; p.solid = SOLID_NOT; p.movetype = MOVETYPE_NONE; p.modelindex = 0; p.model = string_null; } + if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(p, TRUE); + } p = find(p, classname, "player"); } bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); @@ -287,8 +295,6 @@ void () StartQuadRound = if (intermission_running) return; - round_over = 1; - te = find(world, classname, "door"); while (te != world) { te2 = self; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 88f71c09..f6f1281c 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -19,7 +19,7 @@ void () TeamFortress_MOTD = { if (self.motd == 5) { if(csqcactive) { - if(self.team_no == 0) { + if(self.team_no == 0 && !intermission_running) { Menu_Team(0); } } else { From 8bb8ca7001020c52aae5c16761edebb70e36b3c3 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 13 Dec 2019 23:56:54 +1300 Subject: [PATCH 0861/2474] Display different icons on grentimer; reset the grentimer display upon death --- csqc/hud_helpers.qc | 6 +++++- csqc/main.qc | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 1c43c947..876ad37b 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -348,7 +348,11 @@ void AddGrenTimer(float grentype) { if(FO_Hud_Grentimers[i].grentype == 0) { FO_Hud_Grentimers[i].grentype = grentype; FO_Hud_Grentimers[i].expires = time + 3.8; - FO_Hud_Grentimers[i].icon_index = 4; + if(grentype == GR_TYPE_NORMAL) { + FO_Hud_Grentimers[i].icon_index = 4; + } else { + FO_Hud_Grentimers[i].icon_index = 5; + } break; } } diff --git a/csqc/main.qc b/csqc/main.qc index 425a83b7..20f7c2e7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -54,6 +54,15 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { SBAR.Ready = getstatf(STAT_READY); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); SBAR.Hint = ""; + //stop grentimer on death + if(getstatf(STAT_HEALTH) <= 0) { + //localcmd("stopsound\n"); + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + FO_Hud_Grentimers[i].grentype = 0; + FO_Hud_Grentimers[i].expires = 0; + FO_Hud_Grentimers[i].icon_index = 0; + } + } clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -110,28 +119,28 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Admin_Main(TRUE); break; case "primeone": - if(cvar(FOCMD_GRENTIMER) == 2) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); AddGrenTimer(1); } localcmd("primeone_server"); break; case "primetwo": - if(cvar(FOCMD_GRENTIMER) == 2) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); AddGrenTimer(2); } localcmd("primetwo_server"); break; case "gren1": - if(cvar(FOCMD_GRENTIMER) == 2) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); AddGrenTimer(1); } localcmd("gren1_server"); break; case "gren2": - if(cvar(FOCMD_GRENTIMER) == 2) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); AddGrenTimer(2); } From 3ccadd13b8a3b4dd59a5449962450a41dd6d85c6 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 16 Dec 2019 00:33:15 +1300 Subject: [PATCH 0862/2474] fix changeteam limits and messages --- ssqc/commands.qc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 930a9cad..ed42b4ae 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -378,8 +378,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + // close menu if selected class is current class + if ((newclass == self.playerclass && !(self.tfstate & TFSTATE_RANDOMPC)) || (newclass == 10 && (self.tfstate & TFSTATE_RANDOMPC))) { + sprint(self, PRINT_HIGH, "You're already playing that class!\n"); + break; + } + // keep showing menu if class is invalid - if (newclass > 10 || (!IsLegalClass(newclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, newclass)) { + if (newclass < 1 || newclass > 10 || (!IsLegalClass(newclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, newclass)) { sprint(self, PRINT_HIGH, "Invalid class for this team!\n"); Menu_Class(0); break; From 6e0010e629fd1c88e9cfb8fccea23e36717a48d7 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 16 Dec 2019 07:37:03 +1300 Subject: [PATCH 0863/2474] even better class change logic --- ssqc/commands.qc | 13 ++++--------- ssqc/tfort.qc | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index ed42b4ae..eab23b4e 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -379,29 +379,24 @@ float (string arg1, string arg2, string arg3) ParseCmds = { override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); // close menu if selected class is current class - if ((newclass == self.playerclass && !(self.tfstate & TFSTATE_RANDOMPC)) || (newclass == 10 && (self.tfstate & TFSTATE_RANDOMPC))) { - sprint(self, PRINT_HIGH, "You're already playing that class!\n"); + if (newclass == self.nextpc) { + sprint(self, PRINT_HIGH, "You're already going to play that class!\n"); break; } // keep showing menu if class is invalid - if (newclass < 1 || newclass > 10 || (!IsLegalClass(newclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, newclass)) { + if (newclass < 1 || newclass > 10 || (!IsLegalClass(newclass) && !override_mapclasses) || (self.playerclass != newclass && CF_ClassIsRestricted(self.team_no, newclass))) { sprint(self, PRINT_HIGH, "Invalid class for this team!\n"); Menu_Class(0); break; } // don't try to change class if class is forbidden - if ((!IsLegalClass(newclass) && !override_mapclasses) || CF_GetClassRestriction(self.team_no, newclass) == -1) { + if ((!IsLegalClass(newclass) && !override_mapclasses) || (self.playerclass != newclass && CF_GetClassRestriction(self.team_no, newclass) == -1)) { sprint(self, PRINT_HIGH, "Forbidden class for this team!\n"); break; } - // close menu if selected class is current class - //if (self.playerclass == newclass || (newclass == 10 && (self.tfstate & TFSTATE_RANDOMPC))) { - // break; - //} - TeamFortress_ChangeClass(newclass); } else { Menu_Class(0); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index a2c6e2a4..e9da2933 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -171,7 +171,7 @@ void (float inp) TeamFortress_ChangeClass = { "The spy class has been disabled on the server by the administrator\n"); return; } - if (CF_ClassIsRestricted(self.team_no, inp)) { + if (self.playerclass != inp && CF_ClassIsRestricted(self.team_no, inp)) { sprint(self, PRINT_HIGH, "Your team already has enough of that class\n"); return; From 1de43c4a5f5d155fce1024d7d453a66cc83fde19 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 18:38:20 +1100 Subject: [PATCH 0864/2474] Create workflow.yml --- .github/workflows/workflow.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/workflow.yml diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 00000000..dc8d2aa4 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,30 @@ +name: Compile and Upload + +on: + push: + branches: + - master + - staging + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Compile + run: | + wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 + chmod +x fteqcc64 + mv fteqcc64 /bin + make + mkdir -p dats/${{ github.ref }} + cp *.dat dats/${{ github.ref }} + - uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read --follow-symlinks + env: + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_REGION: 'ap-southeast-2' + SOURCE_DIR: 'dats/' From 560ec24942f30adc35b4affa4e6fc47613e0a773 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 18:41:10 +1100 Subject: [PATCH 0865/2474] Update workflow.yml --- .github/workflows/workflow.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index dc8d2aa4..8b9ee1ac 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -15,7 +15,6 @@ jobs: run: | wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 chmod +x fteqcc64 - mv fteqcc64 /bin make mkdir -p dats/${{ github.ref }} cp *.dat dats/${{ github.ref }} From 8002f15e71b93364ac89fa2c02001da9c36fd319 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 18:49:36 +1100 Subject: [PATCH 0866/2474] Update workflow.yml --- .github/workflows/workflow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 8b9ee1ac..3afb9353 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -15,6 +15,7 @@ jobs: run: | wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 chmod +x fteqcc64 + echo "::add-path::${GITHUB_WORKSPACE}" make mkdir -p dats/${{ github.ref }} cp *.dat dats/${{ github.ref }} From 990c1a6fe05b16e260c22404a9b5d45671119eb9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 18:52:08 +1100 Subject: [PATCH 0867/2474] debug workflow.yml --- .github/workflows/workflow.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 3afb9353..ddc22993 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -15,7 +15,9 @@ jobs: run: | wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 chmod +x fteqcc64 + echo $PATH echo "::add-path::${GITHUB_WORKSPACE}" + echo $PATH make mkdir -p dats/${{ github.ref }} cp *.dat dats/${{ github.ref }} From 8bb48466417eedd6a2c2dc985dc8c25050d5c609 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 18:54:19 +1100 Subject: [PATCH 0868/2474] Update workflow.yml --- .github/workflows/workflow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index ddc22993..9f334f6f 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -15,6 +15,7 @@ jobs: run: | wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 chmod +x fteqcc64 + cp fteqcc64 /usr/local/bin/ echo $PATH echo "::add-path::${GITHUB_WORKSPACE}" echo $PATH From 71780c663d764f3f4678b65d868aedf62eec21f1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 19:01:05 +1100 Subject: [PATCH 0869/2474] debug workflow.yml --- .github/workflows/workflow.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 9f334f6f..0e2808bf 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -15,9 +15,9 @@ jobs: run: | wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 chmod +x fteqcc64 - cp fteqcc64 /usr/local/bin/ echo $PATH - echo "::add-path::${GITHUB_WORKSPACE}" + echo $GITHUB_WORKSPACE + export PATH=$GITHUB_WORKSPACE:$PATH echo $PATH make mkdir -p dats/${{ github.ref }} From 1d3ca7535cfef7364e782c2bdb31f7a9bef75c29 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 22:15:49 +1100 Subject: [PATCH 0870/2474] Update workflow.yml --- .github/workflows/workflow.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 0e2808bf..3a32a090 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -15,10 +15,7 @@ jobs: run: | wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 chmod +x fteqcc64 - echo $PATH - echo $GITHUB_WORKSPACE export PATH=$GITHUB_WORKSPACE:$PATH - echo $PATH make mkdir -p dats/${{ github.ref }} cp *.dat dats/${{ github.ref }} @@ -30,4 +27,4 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_REGION: 'ap-southeast-2' - SOURCE_DIR: 'dats/' + SOURCE_DIR: 'dats/refs/heads/' From 4c3d07aab48cdf1497ec7f6cdfaf957e2332ee1c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 22:18:37 +1100 Subject: [PATCH 0871/2474] Version bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index acababf9..fc578bf4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -FortressOne Server v0.1.0 +FortressOne Server v1.0.0 ========================== New features From ab67f561d0ccb34b30e8d0aa08fc8b0fddf5aad2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 23:43:06 +1100 Subject: [PATCH 0872/2474] Don't put a version number in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fcf2424e..45817f22 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -FortressOne Server v1.0.0 +FortressOne Server New features ------ From 499274c18742b89ddd33e7d95a10c0c691e28d39 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 28 Dec 2019 23:44:00 +1100 Subject: [PATCH 0873/2474] Restore underline --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 45817f22..0673571f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ FortressOne Server +================== New features ------ From 6fe9c3c7bc50ace66c0ca1781d93f95790a791fe Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 29 Dec 2019 14:06:23 +1100 Subject: [PATCH 0874/2474] Don't refer to clan mode as pug mode --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0673571f..221a1808 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ New features * Option for maximum grenades for all classes. `localinfo max_gren1_ `, short `localinfo mg1_ `. Works for gren1s and gren2s. Eg `localinfo max_gren1_scout 0` to remove caltrops or `localinfo mg2_9 2` to reduce max EMPs to 2. * Option to fully restock player's clip and finish reload immediately if in progress. `localinfo stock_reload 1` (`localinfo srd 1`) will trigger only on flag capture (with stock_on_cap enabled). `2` will trigger whenever any tfgoal gives you the appropriate ammo. * Option for statusbar flaginfo. `setinfo sbflaginfo 1` (default). Setting it to `2` will skip the tf tips on respawn and show flag info all the time. -* Admin system created to allow for easy setup of pub/pug/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` +* Admin system created to allow for easy setup of pub/clan/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` * Loc support added to server, show locations for dropped flag. * Nailgrenades changed to "Shock/Laser Grenades" to lower spam/not stop bunnyhopping on hit (0 original, 1 laser, 2 burst). `localinfo nailgren_type 1` and `nginfo` in game for all configurable settings. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` From d9234eb8e8be9beb9a4c84e1537e5501daff8fae Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 29 Dec 2019 16:21:07 +1100 Subject: [PATCH 0875/2474] Use fo instead of cf --- ssqc/world.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/world.qc b/ssqc/world.qc index 477af0f6..d9454738 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -145,10 +145,10 @@ void () worldspawn = { cvar_set("sv_waterfriction", "1"); if (teamplay == 0) cvar_set("teamplay", "1"); - localcmd("serverinfo cf_rev \""); + localcmd("serverinfo fo_rev \""); localcmd(REV); localcmd("\"\n"); - localcmd("serverinfo gametype \"cfortress\"\n"); + localcmd("serverinfo gametype \"fortressone\"\n"); st = infokey(world, "*sv_gamedir"); if ((st != string_null) && (st != "fortress")) From 3dcb55e66e6f4170734b9c4861ef3b87b4735181 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 31 Dec 2019 00:39:26 +1300 Subject: [PATCH 0876/2474] add a targetsequence field to trigger_teleport --- ssqc/defs.qc | 2 ++ ssqc/triggers.qc | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 6be7b357..74a1c518 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -164,6 +164,8 @@ void end_sys_globals; .string target; .string targetname; +.string targetsequence; +.float lasttarget; // damage is accumulated through a frame. and sent as one single // message, so the super shotgun doesn't generate huge messages diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 0af1323d..e78a930f 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -291,8 +291,9 @@ void (vector org, entity death_owner) spawn_tdeath = { }; void () teleport_touch = { - local entity t, te; + local entity t = world, te; local vector org; + local float targetcount; if (self.targetname) { if (self.nextthink < time) { @@ -320,10 +321,17 @@ void () teleport_touch = { // put a tfog where the player was spawn_tfog(other.origin); - t = find(world, targetname, self.target); + if(self.targetsequence && self.targetsequence != "") { + targetcount = tokenizebyseparator(self.targetsequence, ","); + self.lasttarget = (self.lasttarget + 1) % targetcount; + t = find(world, targetname, argv(self.lasttarget)); + } + if(!t) { + t = find(world, targetname, self.target); + } if (!t) objerror("couldn't find target"); - + // spawn a tfog flash in front of the destination makevectors(t.mangle); org = t.origin + 32 * v_forward; @@ -389,6 +397,7 @@ void () trigger_teleport = { o = (self.mins + self.maxs) * 0.5; ambientsound(o, "ambience/hum1.wav", 0.5, ATTN_STATIC); } + self.lasttarget = -1; }; void () trigger_skill_touch = { From 0ab3e0dff4e108d55fe17a59d3c40e7fffead184 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 1 Jan 2020 12:09:25 +1300 Subject: [PATCH 0877/2474] improved fte voting menu --- csqc/csextradefs.qc | 1 + csqc/events.qc | 6 +++--- csqc/main.qc | 4 ++++ csqc/menu.qc | 24 ++++++++++++++---------- ssqc/vote.qc | 1 + 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 82193db9..20eda7af 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -50,6 +50,7 @@ float motd_expiry; float quad_round; float quad_rounds_total; float showingscores; +float mapvote_expiry; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index 55a358ae..588fc73d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -175,7 +175,7 @@ void() CSQC_Parse_Event = { FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_KICK, 0); break; case CLIENT_MENU_VOTE: - FO_MENU_VOTE.title = strcat("Map Vote (", ftos(readfloat()), "s left)"); + mapvote_expiry = time + readfloat(); FO_MENU_VOTE.options[0].name = readstring(); FO_MENU_VOTE.options[0].value = ftos(readfloat()); FO_MENU_VOTE.options[1].name = readstring(); @@ -184,8 +184,8 @@ void() CSQC_Parse_Event = { FO_MENU_VOTE.options[2].value = ftos(readfloat()); FO_MENU_VOTE.options[3].name = readstring(); FO_MENU_VOTE.options[3].value = ftos(readfloat()); - FO_MENU_VOTE.options[4].name = readstring(); - FO_MENU_VOTE.options[4].value = ftos(readfloat()); + FO_MENU_VOTE.options[5].name = readstring(); + FO_MENU_VOTE.options[5].value = ftos(readfloat()); FO_Menu_Vote(FALSE); break; case CLIENT_MENU_CAPTAIN_PICK: diff --git a/csqc/main.qc b/csqc/main.qc index 20f7c2e7..d3b001d9 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,6 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_game"); registercommand("fo_main_menu"); registercommand("fo_menu_admin"); + registercommand("fo_menu_vote"); registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("primeone"); @@ -118,6 +119,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_admin": FO_Menu_Admin_Main(TRUE); break; + case "fo_menu_vote": + FO_Menu_Vote(TRUE); + break; case "primeone": if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); diff --git a/csqc/menu.qc b/csqc/menu.qc index d990d502..c1e01bd7 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -83,8 +83,8 @@ var fo_menu FO_MENU_GAME = { {"3","Ready","","Only applies to organised games",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"4","Spectate", "","Do not participate in the game, but observe as a ghost",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, - {"5","Server Admin", "","Admin options for the server",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, - {"6","Captain's Menu", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0);},MENU_BUTTON}, + {"5","Server Admin", "","Admin options for the server",FO_MENU_STATE_DISABLED,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + {"6","Captain's Menu", "","",FO_MENU_STATE_DISABLED,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0);},MENU_BUTTON}, MenuSpacer, {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, }, 9, TRUE @@ -92,12 +92,11 @@ var fo_menu FO_MENU_GAME = { var fo_menu FO_MENU_GAME_SPECTATOR = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, - {"2","Tracking Sidebar", "","",FO_MENU_STATE_HIDDEN,{print("not implemented\n");},MENU_BUTTON}, MenuSpacer, - {"3","Server Admin", "","",FO_MENU_STATE_HIDDEN,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + {"3","Server Admin", "","",FO_MENU_STATE_DISABLED,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, MenuSpacer, {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, - }, 6, TRUE + }, 5, TRUE }; var fo_menu FO_MENU_SPECTATOR_TRACK = { [0,0], [300,200], "Track", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { @@ -604,10 +603,15 @@ var fo_menu FO_MENU_VOTE = { {"3","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[2].name,"\n");Menu_Cancel();},MENU_BUTTON}, {"4","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[3].name,"\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, - {"5","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[4].name,"\n");Menu_Cancel();},MENU_BUTTON}, + {"5","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[5].name,"\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - }, 8, TRUE + }, 8, TRUE, { + FO_MENU_VOTE.title = strcat("Map Vote (", ftos(ceil(mapvote_expiry - time)), "s left)"); + if((mapvote_expiry - time) < 0) { + Menu_Cancel(); + } + } }; void fo_menu_start(vector position, vector size, string title, float flags) = { InProgressMenu.position = position; @@ -841,16 +845,16 @@ void FO_Menu_Game(float force) = { if(is_spectator) { //print(getplayerkeyvalue(player_localnum, "name"), " is a spectator!\n"); //FO_MENU_GAME_SPECTATOR.num_opts = 3; - FO_MENU_GAME_SPECTATOR.options[3].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; + FO_MENU_GAME_SPECTATOR.options[2].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_DISABLED; //if(is_admin) FO_MENU_GAME_SPECTATOR.num_opts++; CurrentMenu = &FO_MENU_GAME_SPECTATOR; } else { float userid = stof(getplayerkeyvalue(player_localnum, "userid")); //FO_MENU_GAME.num_opts = 7; - FO_MENU_GAME.options[5].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; + FO_MENU_GAME.options[5].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_DISABLED; //if(is_admin) FO_MENU_GAME.num_opts++; - FO_MENU_GAME.options[6].state = (userid == captain1 || userid == captain2)?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN; + FO_MENU_GAME.options[6].state = (userid == captain1 || userid == captain2)?FO_MENU_STATE_NORMAL:FO_MENU_STATE_DISABLED; //if(is_admin) FO_MENU_GAME.num_opts++; CurrentMenu = &FO_MENU_GAME; } diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 75c361be..76f6c267 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -532,6 +532,7 @@ void (entity pe_player) Vote_Menu = { //fte+csqc has its own team menu //ask the client to activate it Menu_Close(pe_player); + pe_player.vote_close = 1; UpdateClientMenu_Vote(pe_player, floor(f_timeleft - 0.1)); return; } From 563ff27e0717ff1fd0a529637bb0ee882fea37f1 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 3 Jan 2020 08:23:00 +1300 Subject: [PATCH 0878/2474] basic voting map support --- README.md | 3 + ssqc/client.qc | 171 +++++++++++++++++++++++----- ssqc/combat.qc | 3 + ssqc/commands.qc | 53 +++++---- ssqc/qw.qc | 5 + ssqc/spect.qc | 4 +- ssqc/tforthlp.qc | 2 +- ssqc/vote.qc | 288 +++++++++++++++++++++++++++++++++++++++++++++++ ssqc/world.qc | 18 ++- 9 files changed, 494 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 221a1808..f9e152f0 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ FortressOne Server New features ------ +* localinfo vote_time 60 - seconds since the first vote is cast until voting is decided. 0 means majority vote only. +* localinfo vote_map - map to designate for voting +* localinfo vote_style 1 - got to voting map after round is over instead of asking using menus * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press diff --git a/ssqc/client.qc b/ssqc/client.qc index 91a66469..408c6ed9 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -147,6 +147,19 @@ void () autokick_think = { dremove(self); }; +string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString = { + local string st; + + st = infokey(ent, ps_short); + if (st == string_null) { + st = infokey(ent, ps_setting); + if (st == string_null) { + st = ps_default; + } + } + + return st; +}; //if ent is world, return serverinfo, if ent is a player, return that client's setinfo key float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting = { local string st; @@ -767,7 +780,7 @@ void () DecodeLevelParms = { self.playerclass = parm12; if (parm15) self.is_admin = parm15; - +/* local entity p = find(world, classname, "player"); while (p != world) { if (p.netname != "") { @@ -777,6 +790,7 @@ void () DecodeLevelParms = { } p = find(p, classname, "player"); } +*/ }; entity() FindIntermission = @@ -946,10 +960,26 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_y); WriteAngle(MSG_ALL, pos.mangle_z); + local string nextmapstring = vote_result; + if (!clanbattle && CF_GetSetting("vs", "vote_style", "0")){ + if(votemode && vote_result) { + localcmd ("localinfo votemode off\n"); + //changelevel(vote_result); + } else { + vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + localcmd ("localinfo votemode on\n"); + //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "start")); + } + } + //if(!votemode) { + // vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + // nextmapstring = strcat(vote_result, " \b(voting)\b"); + //} + other = find(world, classname, "player"); while (other != world) { if (vote_result != string_null) - sprint(other, PRINT_HIGH, "Next up: ", vote_result, "\n"); + sprint(other, PRINT_HIGH, "Next up: ", nextmapstring, "\n"); other.takedamage = DAMAGE_NO; other.solid = SOLID_NOT; other.movetype = MOVETYPE_NONE; @@ -1004,6 +1034,9 @@ void () respawn = { return; if (cease_fire) return; + if (votemode && vote_anarchy_mode) { + return; + } if (coop) { CopyToBodyQue(self); @@ -1478,6 +1511,51 @@ void () TeamFortress_SetEquipment; void () TeamFortress_StartTimers; void () player_touch; + +void (entity p) SetVoteParams = { + p.items = 0; + p.health = 100; + p.armorvalue = 0; + p.ammo_shells = 0; + p.ammo_nails = 0; + p.ammo_rockets = 0; + p.ammo_cells = 0; + p.armortype = 0; + p.team_no = 0; + p.playerclass = 0; + p.skin = rint(random() * 9); //self.playerclass; + stuffcmd(p, strcat("color ", ftos(rint(random() * 12)), " ", ftos(rint(random() * 12)), "\n")); + + p.takedamage = DAMAGE_AIM; //DAMAGE_YES; + p.attack_finished = time + 0.3; + p.th_pain = player_pain; + p.th_die = PlayerDie; + p.height = 0; + Sniper_ZoomReset(p); + + p.deadflag = 0; + p.pausetime = 0; + + TeamFortress_StartTimers(); + + local entity spot = SelectSpawnPoint(); + + p.observer_list = spot; + p.origin = spot.origin + '0 0 1'; + p.angles = spot.angles; + p.fixangle = 1; + + setmodel(p, "progs/player.mdl"); + setsize(p, VEC_HULL_MIN, VEC_HULL_MAX); + + p.view_ofs = '0 0 22'; + p.velocity = '0 0 0'; + player_stand1(); + + makevectors(p.angles); + spawn_tfog(p.origin + v_forward * 20); +} + void () PutClientInServer = { local float oldclass; local entity spot; @@ -1519,6 +1597,20 @@ void () PutClientInServer = { self.immune_to_check = time + 10; self.fire_held_down = 0; + + setmodel(self, string_null); + modelindex_null = self.modelindex; + + setmodel(self, "progs/eyes.mdl"); + modelindex_eyes = self.modelindex; + + setmodel(self, "progs/player.mdl"); + modelindex_player = self.modelindex; + + if(votemode) { + SetVoteParams(self); + return; + } if (self.last_playerclass == 0) self.last_playerclass = self.playerclass; @@ -1638,14 +1730,6 @@ void () PutClientInServer = { spot.think = SUB_Remove; } } - setmodel(self, string_null); - modelindex_null = self.modelindex; - - setmodel(self, "progs/eyes.mdl"); - modelindex_eyes = self.modelindex; - - setmodel(self, "progs/player.mdl"); - modelindex_player = self.modelindex; if (self.playerclass == 0) { self.modelindex = modelindex_null; @@ -1771,6 +1855,16 @@ void () NextLevel = { return; already_cycled = 1; + if (!clanbattle && CF_GetSetting("vs", "vote_style", "0")){ + intermission_running = 0; + if(votemode && vote_result) { + localcmd ("localinfo votemode off\n"); + nextmap = vote_result; + } else { + localcmd ("localinfo votemode on\n"); + nextmap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + } + } o = spawn(); o.map = nextmap; o.think = execute_changelevel; @@ -1957,16 +2051,24 @@ void () WaterMove = { } if (self.watertype == -5) { if (self.dmgtime < time) { - if (self.radsuit_finished > time) - self.dmgtime = time + 1; - else - self.dmgtime = time + 0.2; - TF_T_Damage(self, world, world, (10 * self.waterlevel), 0, 16); + if(votemode && !vote_anarchy_mode) { + respawn(); + } else { + if (self.radsuit_finished > time) + self.dmgtime = time + 1; + else + self.dmgtime = time + 0.2; + TF_T_Damage(self, world, world, (10 * self.waterlevel), 0, 16); + } } } else if (self.watertype == -4) { if ((self.dmgtime < time) && (self.radsuit_finished < time)) { - self.dmgtime = time + 1; - T_Damage(self, world, world, (4 * self.waterlevel)); + if(votemode && !vote_anarchy_mode) { + respawn(); + } else { + self.dmgtime = time + 1; + T_Damage(self, world, world, (4 * self.waterlevel)); + } } } if (!(self.flags & 16)) { @@ -2044,7 +2146,7 @@ void () PlayerPreThink = { // Check if timelimit/fraglimit has been met CheckRules(); - if (self.playerclass != 0) { + if (self.playerclass != 0 || votemode) { WaterMove(); } if (self.deadflag >= 2) { @@ -2306,20 +2408,27 @@ void () PlayerPostThink = { } self.jump_flag = self.velocity_z; - CheckPowerups(); - W_WeaponFrame(); - if (self.motd <= 400) { - TeamFortress_MOTD(); + if(votemode) { + if (time >= self.StatusRefreshTime) + RefreshStatusBar(self); + + W_WeaponFrame(); } else { - if (self.cheat_check == 0) { - self.cheat_check = time + 5; + CheckPowerups(); + W_WeaponFrame(); + if (self.motd <= 400) { + TeamFortress_MOTD(); + } else { + if (self.cheat_check == 0) { + self.cheat_check = time + 5; + } + } + if (time >= self.StatusRefreshTime) + RefreshStatusBar(self); + if (self.cheat_check <= time) { + TeamFortress_CheckTeamCheats(); + self.cheat_check = time + 3; } - } - if (time >= self.StatusRefreshTime) - RefreshStatusBar(self); - if (self.cheat_check <= time) { - TeamFortress_CheckTeamCheats(); - self.cheat_check = time + 3; } }; @@ -2475,6 +2584,8 @@ void () ClientDisconnect = { CheckAllPlayersReady(); } } + + UnvoteForMap(self); }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { diff --git a/ssqc/combat.qc b/ssqc/combat.qc index ed9edb8b..c272ee3c 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -136,6 +136,9 @@ void (entity targ, entity attacker) Killed = { } } } + if(vote_anarchy_mode) { + UnvoteForMap(targ); + } }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index eab23b4e..144ee6bf 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -674,27 +674,42 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "votemap": processedCmd = TRUE; - switch(arg2) { - case vote1_map: - Vote_Input(1); - break; - case vote2_map: - Vote_Input(2); - break; - case vote3_map: - Vote_Input(3); - break; - case vote4_map: - Vote_Input(4); - break; - case vote5_map: - Vote_Input(5); - break; - default: - Vote_Menu(self); - break; + if(votemode) { + if(arg2) { + VoteForMap(self, arg2); + } + } else { + switch(arg2) { + case vote1_map: + Vote_Input(1); + break; + case vote2_map: + Vote_Input(2); + break; + case vote3_map: + Vote_Input(3); + break; + case vote4_map: + Vote_Input(4); + break; + case vote5_map: + Vote_Input(5); + break; + default: + Vote_Menu(self); + break; + } } break; + case "showvotes": + processedCmd = TRUE; + PrintVoting(self); + break; + case "listmaps": + case "maplist": + processedCmd = TRUE; + ListVoteMaps(self); + break; case "captainpick": processedCmd = TRUE; if(arg2) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ae9a3eb5..462ef663 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -453,6 +453,11 @@ float duel_reset_timer; float no_fire_mode; float duel_all_grens; float duel_no_packs; +float votemode; +float voting_started; +float voting_expires; +.entity vote_map; +float vote_anarchy_mode; .float tf_id; diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 77802e32..4fe72913 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -122,8 +122,8 @@ void () SpectatorThink = { if (self.impulse) SpectatorImpulseCommand(); - if (self.motd <= 400) - TeamFortress_MOTD(); + //if (self.motd <= 400) + // TeamFortress_MOTD(); if (time >= self.StatusRefreshTime) RefreshStatusBar(self); }; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index f6f1281c..6907f7d9 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -9,7 +9,7 @@ void (float inp) MOTD_Input = { }; void () TeamFortress_MOTD = { - if (self.classname == "observer") + if (self.classname == "observer" || votemode) return; local string st1; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 76f6c267..1e1eb929 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -12,6 +12,7 @@ float () Vote_GetTrickVotes; float () Vote_GetRaceVotes; void (entity pe_player) Vote_ForceNext; void () GotoNextMap; +void () execute_changelevel; float () Vote_GetForceNextVotes; void () Vote_Check; void (float pf_decider) Vote_SetupVote; @@ -1083,3 +1084,290 @@ string (string ps_list, float pf_idx) List_Index = { return strzone(string_null); }; + + +/* ====== Vote Ball ======= */ + +float() crandom; + +void (vector o, float z) ball_kick = { + + local vector v; + + v_x = ((o_x * 1.65) + (random() * 20) ); + v_y = ((o_y * 1.65) + (random() * 20) ); + + if (o_x < 0.000) { + o_x = o_x * -1.000; + } + if (o_y < 0.000) { + o_y = o_y * -1.000; + } + + v_z = ((100 + (random() * 30)) + ((o_y + o_x) * 0.20) + (z * 2.5) ); + + + self.flags = self.flags - ( self.flags & 512.000); + self.velocity = v; + +}; + +void (vector o) ball_fly = { + local vector v; + + v_x = (o_x * 0.600) + (crandom() * 40); + v_y = (o_y * 0.600) + (crandom() * 40); + + if (o_x < 0.000) { + o_x = o_x * -1.000; + } + if (o_y < 0.000) { + o_y = o_y * -1.000; + } + + + v_z = (140 + (crandom() * 40)) + ((o_y + o_x) * 0.20); + + self.flags = self.flags - ( self.flags & 512.000); + self.velocity = v; + + +}; + +void () ball_touch = { + if (self.watertype == CONTENT_LAVA) { + /*self.velocity_x = 0; + self.velocity_y = 100; + self.velocity_z = 0;*/ + setorigin (self,self.oldorigin); + return; + } + + if (other.classname == "worldspawn") { + return; + } + + if (other.classname == "player") { + self.oldenemy = other; + ball_kick(other.velocity, (other.v_angle_x * -1.000)); + return; + + } + self.oldenemy = other.owner; + ball_fly(other.velocity); + return; +}; + +void () item_ball = { + self.solid = 1.000; + self.movetype = 10.000; + //self.flags= 256.000; + + if ( self.mdl ) { + precache_model (self.mdl); + precache_model2 (self.mdl); + setmodel (self,self.mdl); + + } else { + self.mdl = "progs/lavaball.mdl"; + setmodel (self,self.mdl); + } + + if ( !self.netname ) { + self.netname = "ball"; + } + setsize (self,'-0.000 -0.000 -0.000','24.000 24.000 24.000'); + setorigin (self,self.origin); + self.oldorigin = self.origin; + self.touch = ball_touch; +}; + +/* ====== Vote System ======= */ + +void() map_candidate = {}; + +/* +"netname" "amth1" //map name +"broadcast" "Duel arena, ctf and Sniper War" //description +"team_broadcast" "Duel/Arena" //group +"ex_skill_min" "2" //min players +"ex_skill_max" "8" //max players +"team_no" "4" //supported teams + +.cnt = number of current votes +*/ +void (entity p) ListVoteMaps = { + sprint(p, PRINT_HIGH, "Maps eligible for voting:\n"); + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + sprint(p, PRINT_HIGH, "\b", mc.netname, "\b: ", mc.broadcast, "\n"); + mc = find(mc, classname, "map_candidate"); + } + sprint(p, PRINT_HIGH, "Use \bcmd votemap \b to cast your vote.\n"); +}; + +void () AnarchyMode = { + if(vote_anarchy_mode) + return; + vote_anarchy_mode = TRUE; + local entity e = find(world, classname, "player"); + while(e) { + e.items_allowed = IT_AXE | IT_QUAD; + e.items = IT_AXE; + e.weapons_carried = IT_AXE; + e.current_weapon = WEAP_AXE; + W_SetCurrentAmmo(e); + if(e.vote_map) { + e.items |= IT_QUAD; + e.tfstate &= 128; + e.super_damage_finished = time + 666; + } + e = find(e, classname, "player"); + } + bprint(PRINT_HIGH, "\bDemocracy has failed!\b Let the result be decided in \bBATTLE\b\n"); +}; + +void () StartVoting = { + voting_started = TRUE; + vote_anarchy_mode = FALSE; + bprint(PRINT_HIGH, "Voting has started!\n"); +}; + +void () EndVoting = { + voting_started = FALSE; + vote_anarchy_mode = FALSE; + local entity e = find(world, classname, "vote_timer"); + if(e) { + dremove(e); + } + + e = find(world, classname, "player"); + while(e) { + e.vote_map = world; + e.items = 0; + e.weapons_carried = 0; + e.current_weapon = 0; + W_SetCurrentAmmo(e); + e = find(e, classname, "player"); + } + e = find(world, classname, "map_candidate"); + while(e) { + e.cnt = 0; + e = find(e, classname, "map_candidate"); + } +}; + +void (string map_name) ChangeToVotedMap = { + vote_result = map_name; + EndVoting(); + //GotoNextMap(); + execute_changelevel(); +}; + +void () CheckVoting = { + local float numplayers = 0, votedplayers = 0; + local entity e = find(world, classname, "player"); + while(e) { + if((e.health > 0 || !vote_anarchy_mode) && !e.has_disconnected) { + numplayers++; + if(e.vote_map) { + votedplayers++; + } + } + e = find(e, classname, "player"); + } + + if(numplayers <= 0 || votedplayers <= 0) { + bprint(PRINT_HIGH, "\bVoting reset...\b\n"); + EndVoting(); + return; + } + + e = find(world, classname, "map_candidate"); + while(e) { + //unanimous - change immediately + if(e.cnt >= numplayers) { + bprint(PRINT_HIGH, "\bUnanimous choice:\b ", e.netname, "\n"); + ChangeToVotedMap(e.netname); + break; + } else if(voting_expires < time) { + if(e.cnt > (numplayers/2)) { + bprint(PRINT_HIGH, "\bTime's up!\b Majority choice: ", e.netname, "\n"); + ChangeToVotedMap(e.netname); + } else { + AnarchyMode(); + } + } + e = find(e, classname, "map_candidate"); + } +}; + +void (entity p) PrintVoting = { + sprint(p, PRINT_HIGH, "Current votes:\n"); + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(mc.cnt > 0) { + if(p.vote_map == mc) { + sprint(p, PRINT_HIGH, "\b", mc.netname, "\b: ", ftos(mc.cnt), " (Your vote)\n"); + } else { + sprint(p, PRINT_HIGH, "\b", mc.netname, "\b: ", ftos(mc.cnt), "\n"); + } + } + mc = find(mc, classname, "map_candidate"); + } +}; + +void() vote_think = { + CheckVoting(); + self.nextthink = time + 1; +}; + +void (entity p, string vote) VoteForMap = { + local float expires = CF_GetSetting("votetime", "vote_time", "60"); + entity te; + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(mc.netname == vote) { + if(!voting_started) { + StartVoting(); + bprint(PRINT_HIGH, p.netname, " suggests \b", vote, "\b\n"); + if(expires) { + bprint(PRINT_HIGH, "Voting closes in ", ftos(expires), " seconds. \bBe quick!\b\n"); + voting_expires = time + expires; + te = spawn(); + te.think = vote_think; + te.classname = "vote_timer"; + te.nextthink = time + 1; + } else { + bprint(PRINT_HIGH, "No voting timelimit configured, so will require unanimous decision\n"); + } + + } else { + if(p.vote_map) { + bprint(PRINT_HIGH, p.netname, " changes vote to \b", vote, "\b\n"); + p.vote_map.cnt--; + } else { + bprint(PRINT_HIGH, p.netname, " has voted for \b", vote, "\b\n"); + } + } + p.vote_map = mc; + mc.cnt++; + CheckVoting(); + return; + } + mc = find(mc, classname, "map_candidate"); + } + sprint(p, PRINT_HIGH, "\bUnfortunately, \b", vote, "\b doesn't appear to be a valid map.\nUse \bcmd listmaps\b to for a list of valid maps.\b\n"); +}; + +void (entity p) UnvoteForMap = { + if(p.vote_map) { + if(vote_anarchy_mode) { + bprint(PRINT_HIGH, p.netname, " \brecinds vote for\b ", p.vote_map.netname, " \bin battle\b\n"); + } else { + bprint(PRINT_HIGH, p.netname, " \babandons vote for\b ", p.vote_map.netname, "\n"); + } + p.vote_map.cnt--; + } + CheckVoting(); +}; diff --git a/ssqc/world.qc b/ssqc/world.qc index d9454738..a0397762 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -1,4 +1,5 @@ void () InitBodyQue; +string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; void () main = { dprint("main function\n"); @@ -327,6 +328,18 @@ void () worldspawn = { worldspawnent = spawn(); worldspawnent.think = WorldSpawnPost; worldspawnent.nextthink = time + .01; + votemode = CF_GetSetting("vm", "votemode", "off"); + /* + if(votemode) { + string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + if(world.model != strcat("maps/",votemap,".bsp")) { + bprint(PRINT_HIGH, "MEHT: need to change to se2!\n"); + changelevel(votemap); + } else { + bprint(PRINT_HIGH, "MEHT: already se2, carry on.\n"); + } + } + */ }; void () StartFrame = { @@ -335,7 +348,10 @@ void () StartFrame = { fraglimit = cvar("fraglimit"); deathmatch = cvar("deathmatch"); framecount = framecount + 1; - Vote_Check(); + if(!votemode) { + //TODO: make this optional + Vote_Check(); + } }; entity bodyque_head; From 2dff710eeef94d629f4d7fed27a53101fae48bee Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 4 Jan 2020 00:49:31 +1300 Subject: [PATCH 0879/2474] more voting stuff --- ssqc/client.qc | 3 +++ ssqc/commands.qc | 3 +++ ssqc/vote.qc | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 408c6ed9..02546416 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1513,6 +1513,9 @@ void () player_touch; void (entity p) SetVoteParams = { + sprint(p, PRINT_HIGH, "Voting time! Use \bcmd listmaps\b to see available maps\n"); + sprint(p, PRINT_HIGH, "Use \bcmd votemap \b to state your preference\n"); + sprint(p, PRINT_HIGH, "Use \bcmd showvotes\b to see the current voting status\n"); p.items = 0; p.health = 100; p.armorvalue = 0; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 144ee6bf..ad9c80c5 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -56,6 +56,7 @@ void () QuadMode = localcmd ("localinfo fullteamscore off\n"); localcmd ("fraglimit 0\n"); localcmd ("localinfo rd 0\n"); + localcmd ("localinfo votemode 0\n"); localcmd ("exec fo_quadmode.cfg\n"); bprint (PRINT_HIGH, "Quad Mode set to on\n"); bprint (PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -65,6 +66,7 @@ void () ClanMode = { localcmd("localinfo clan on\n"); localcmd ("localinfo rd 0\n"); + localcmd ("localinfo votemode 0\n"); localcmd ("exec fo_clanmode.cfg\n"); bprint(PRINT_HIGH, "Clan Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -102,6 +104,7 @@ void () DuelMode = localcmd ("password none\n"); localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); + localcmd ("localinfo votemode 0\n"); localcmd ("exec fo_duelmode.cfg\n"); bprint(PRINT_HIGH, "Duel Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 1e1eb929..3519c402 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1303,7 +1303,11 @@ void () CheckVoting = { }; void (entity p) PrintVoting = { - sprint(p, PRINT_HIGH, "Current votes:\n"); + if(!voting_started) { + sprint(p, PRINT_HIGH, "No votes.\n"); + return; + } + sprint(p, PRINT_HIGH, ftos(rint(voting_expires - time)), " seconds remain. \bCurrent votes:\b\n"); local entity mc = find(world, classname, "map_candidate"); while(mc) { if(mc.cnt > 0) { From d0368f0919ce4b7470ce421a410c04b5e89cf181 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 4 Jan 2020 13:24:49 +1300 Subject: [PATCH 0880/2474] default vote_style to new mode --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 02546416..29655cc8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -961,7 +961,7 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_z); local string nextmapstring = vote_result; - if (!clanbattle && CF_GetSetting("vs", "vote_style", "0")){ + if (!clanbattle && CF_GetSetting("vs", "vote_style", "1")){ if(votemode && vote_result) { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); @@ -1858,7 +1858,7 @@ void () NextLevel = { return; already_cycled = 1; - if (!clanbattle && CF_GetSetting("vs", "vote_style", "0")){ + if (!clanbattle && CF_GetSetting("vs", "vote_style", "1")){ intermission_running = 0; if(votemode && vote_result) { localcmd ("localinfo votemode off\n"); From fd01254ef0c0b4c6d39c39414f4d4c7f4217eb80 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 4 Jan 2020 13:36:34 +1300 Subject: [PATCH 0881/2474] default vote_style to new mode --- ssqc/vote.qc | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 3519c402..b7dd6b5b 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1147,6 +1147,9 @@ void () ball_touch = { return; } + if (round_over) { + return; + } if (other.classname == "player") { self.oldenemy = other; ball_kick(other.velocity, (other.v_angle_x * -1.000)); @@ -1176,12 +1179,63 @@ void () item_ball = { if ( !self.netname ) { self.netname = "ball"; } - setsize (self,'-0.000 -0.000 -0.000','24.000 24.000 24.000'); + + if ( (self.goal_min == '0.000 0.000 0.000') ) { + self.goal_min = '-12.000 -12.000 -12.000'; + } + if ( (self.goal_max == '0.000 0.000 0.000') ) { + self.goal_max = '12.000 12.000 12.000'; + } + setsize (self,self.goal_min,self.goal_max); + + //setsize (self,'-0.000 -0.000 -0.000','24.000 24.000 24.000'); setorigin (self,self.origin); self.oldorigin = self.origin; self.touch = ball_touch; }; +void () soccer_goal_touch = { + if (round_over) return; + + if (cb_prematch) return; + + if (other.classname == "item_ball") { + if (other.solid) { + TeamFortress_TeamIncreaseScore (self.owned_by,self.count); + TeamFortress_TeamShowScores (2.000); + sound (self,2.000,self.noise,1.000,0.000); + //round_winner = self.pteam; + other.solid = 0.000; + } + return; + } +}; + +void () info_soccer_goal = { + if (!self.noise ) { + self.noise = "items/tf2kfgc.wav"; + } + + precache_sound (self.noise); + + if (self.owned_by == 1) { + //self.pteam = pteam1; + } + else if (self.owned_by == 2) { + //self.pteam = pteam2; + } + else if (self.owned_by == 3) { + //self.pteam = pteam3; + } + else if (self.owned_by == 4) { + //self.pteam = pteam4; + } + InitTrigger(); + + self.touch = soccer_goal_touch; + + }; + /* ====== Vote System ======= */ void() map_candidate = {}; From a9d06fe9e76ce64f0f80507b1cfd3ec9be10dfa4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 4 Jan 2020 14:09:01 +1300 Subject: [PATCH 0882/2474] add a basic info_soccer_goal entity --- ssqc/extraents.qc | 153 ++++++++++++++++++++++++++++++++++++++++++++++ ssqc/progs.src | 1 + ssqc/vote.qc | 152 +-------------------------------------------- 3 files changed, 155 insertions(+), 151 deletions(-) create mode 100644 ssqc/extraents.qc diff --git a/ssqc/extraents.qc b/ssqc/extraents.qc new file mode 100644 index 00000000..445252f4 --- /dev/null +++ b/ssqc/extraents.qc @@ -0,0 +1,153 @@ +void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; +void (float all) TeamFortress_TeamShowScores; +void () InitTrigger; + +/* ====== Vote Ball ======= */ + +float() crandom; + +void (vector o, float z) ball_kick = { + + local vector v; + + v_x = ((o_x * 1.65) + (random() * 20) ); + v_y = ((o_y * 1.65) + (random() * 20) ); + + if (o_x < 0.000) { + o_x = o_x * -1.000; + } + if (o_y < 0.000) { + o_y = o_y * -1.000; + } + + v_z = ((100 + (random() * 30)) + ((o_y + o_x) * 0.20) + (z * 2.5) ); + + + self.flags = self.flags - ( self.flags & 512.000); + self.velocity = v; + +}; + +void (vector o) ball_fly = { + local vector v; + + v_x = (o_x * 0.600) + (crandom() * 40); + v_y = (o_y * 0.600) + (crandom() * 40); + + if (o_x < 0.000) { + o_x = o_x * -1.000; + } + if (o_y < 0.000) { + o_y = o_y * -1.000; + } + + + v_z = (140 + (crandom() * 40)) + ((o_y + o_x) * 0.20); + + self.flags = self.flags - ( self.flags & 512.000); + self.velocity = v; + + +}; + +void () ball_touch = { + if (self.watertype == CONTENT_LAVA) { + /*self.velocity_x = 0; + self.velocity_y = 100; + self.velocity_z = 0;*/ + setorigin (self,self.oldorigin); + return; + } + + if (other.classname == "worldspawn") { + return; + } + + if (round_over) { + return; + } + if (other.classname == "player") { + self.oldenemy = other; + ball_kick(other.velocity, (other.v_angle_x * -1.000)); + return; + + } + self.oldenemy = other.owner; + ball_fly(other.velocity); + return; +}; + +void () item_ball = { + self.solid = 1.000; + self.movetype = 10.000; + //self.flags= 256.000; + + if ( self.mdl ) { + precache_model (self.mdl); + precache_model2 (self.mdl); + setmodel (self,self.mdl); + + } else { + self.mdl = "progs/lavaball.mdl"; + setmodel (self,self.mdl); + } + + if ( !self.netname ) { + self.netname = "ball"; + } + + if ( (self.goal_min == '0.000 0.000 0.000') ) { + self.goal_min = '-12.000 -12.000 -12.000'; + } + if ( (self.goal_max == '0.000 0.000 0.000') ) { + self.goal_max = '12.000 12.000 12.000'; + } + setsize (self,self.goal_min,self.goal_max); + + //setsize (self,'-0.000 -0.000 -0.000','24.000 24.000 24.000'); + setorigin (self,self.origin); + self.oldorigin = self.origin; + self.touch = ball_touch; +}; + +void () soccer_goal_touch = { + if (round_over) return; + + if (cb_prematch) return; + + if (other.classname == "item_ball") { + if (other.solid) { + TeamFortress_TeamIncreaseScore (self.owned_by,self.count); + TeamFortress_TeamShowScores (2.000); + sound (self,2.000,self.noise,1.000,0.000); + //round_winner = self.pteam; + other.solid = 0.000; + } + return; + } +}; + +void () info_soccer_goal = { + if (!self.noise ) { + self.noise = "items/tf2kfgc.wav"; + } + + precache_sound (self.noise); + + if (self.owned_by == 1) { + //self.pteam = pteam1; + } + else if (self.owned_by == 2) { + //self.pteam = pteam2; + } + else if (self.owned_by == 3) { + //self.pteam = pteam3; + } + else if (self.owned_by == 4) { + //self.pteam = pteam4; + } + InitTrigger(); + + self.touch = soccer_goal_touch; + + }; diff --git a/ssqc/progs.src b/ssqc/progs.src index 9b42fd1a..e921e52b 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -13,6 +13,7 @@ functions.qc menu.qc csmenu.qc vote.qc +extraents.qc help.qc subs.qc combat.qc diff --git a/ssqc/vote.qc b/ssqc/vote.qc index b7dd6b5b..1996ba85 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1086,157 +1086,7 @@ string (string ps_list, float pf_idx) List_Index = { }; -/* ====== Vote Ball ======= */ - -float() crandom; - -void (vector o, float z) ball_kick = { - - local vector v; - - v_x = ((o_x * 1.65) + (random() * 20) ); - v_y = ((o_y * 1.65) + (random() * 20) ); - - if (o_x < 0.000) { - o_x = o_x * -1.000; - } - if (o_y < 0.000) { - o_y = o_y * -1.000; - } - - v_z = ((100 + (random() * 30)) + ((o_y + o_x) * 0.20) + (z * 2.5) ); - - - self.flags = self.flags - ( self.flags & 512.000); - self.velocity = v; - -}; - -void (vector o) ball_fly = { - local vector v; - - v_x = (o_x * 0.600) + (crandom() * 40); - v_y = (o_y * 0.600) + (crandom() * 40); - - if (o_x < 0.000) { - o_x = o_x * -1.000; - } - if (o_y < 0.000) { - o_y = o_y * -1.000; - } - - - v_z = (140 + (crandom() * 40)) + ((o_y + o_x) * 0.20); - - self.flags = self.flags - ( self.flags & 512.000); - self.velocity = v; - - -}; - -void () ball_touch = { - if (self.watertype == CONTENT_LAVA) { - /*self.velocity_x = 0; - self.velocity_y = 100; - self.velocity_z = 0;*/ - setorigin (self,self.oldorigin); - return; - } - - if (other.classname == "worldspawn") { - return; - } - - if (round_over) { - return; - } - if (other.classname == "player") { - self.oldenemy = other; - ball_kick(other.velocity, (other.v_angle_x * -1.000)); - return; - - } - self.oldenemy = other.owner; - ball_fly(other.velocity); - return; -}; - -void () item_ball = { - self.solid = 1.000; - self.movetype = 10.000; - //self.flags= 256.000; - - if ( self.mdl ) { - precache_model (self.mdl); - precache_model2 (self.mdl); - setmodel (self,self.mdl); - - } else { - self.mdl = "progs/lavaball.mdl"; - setmodel (self,self.mdl); - } - - if ( !self.netname ) { - self.netname = "ball"; - } - - if ( (self.goal_min == '0.000 0.000 0.000') ) { - self.goal_min = '-12.000 -12.000 -12.000'; - } - if ( (self.goal_max == '0.000 0.000 0.000') ) { - self.goal_max = '12.000 12.000 12.000'; - } - setsize (self,self.goal_min,self.goal_max); - - //setsize (self,'-0.000 -0.000 -0.000','24.000 24.000 24.000'); - setorigin (self,self.origin); - self.oldorigin = self.origin; - self.touch = ball_touch; -}; - -void () soccer_goal_touch = { - if (round_over) return; - - if (cb_prematch) return; - - if (other.classname == "item_ball") { - if (other.solid) { - TeamFortress_TeamIncreaseScore (self.owned_by,self.count); - TeamFortress_TeamShowScores (2.000); - sound (self,2.000,self.noise,1.000,0.000); - //round_winner = self.pteam; - other.solid = 0.000; - } - return; - } -}; - -void () info_soccer_goal = { - if (!self.noise ) { - self.noise = "items/tf2kfgc.wav"; - } - - precache_sound (self.noise); - - if (self.owned_by == 1) { - //self.pteam = pteam1; - } - else if (self.owned_by == 2) { - //self.pteam = pteam2; - } - else if (self.owned_by == 3) { - //self.pteam = pteam3; - } - else if (self.owned_by == 4) { - //self.pteam = pteam4; - } - InitTrigger(); - - self.touch = soccer_goal_touch; - - }; - -/* ====== Vote System ======= */ +/* ====== New Vote System ======= */ void() map_candidate = {}; From 85ae113a2d2b8c6205379a751cf5f5e365f194df Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 6 Jan 2020 20:08:34 +1300 Subject: [PATCH 0883/2474] item_ball now resets after scoring. Votemode now handles suicide --- ssqc/buttons.qc | 2 +- ssqc/client.qc | 28 +++++++++------ ssqc/commands.qc | 18 +++++++++- ssqc/extraents.qc | 39 +++++++++++++++------ ssqc/tfort.qc | 2 +- ssqc/vote.qc | 86 ++++++++++++++++++++++++++++++++--------------- ssqc/world.qc | 2 ++ 7 files changed, 126 insertions(+), 51 deletions(-) diff --git a/ssqc/buttons.qc b/ssqc/buttons.qc index d66f1222..45a8cb12 100644 --- a/ssqc/buttons.qc +++ b/ssqc/buttons.qc @@ -117,7 +117,7 @@ void () func_button = { precache_sound("buttons/switch02.wav"); self.noise = "buttons/switch02.wav"; } else if (self.sounds == 3) { - precache_sound("buttons/switch04.wav"); + //precache_sound("buttons/switch04.wav"); self.noise = "buttons/switch04.wav"; } diff --git a/ssqc/client.qc b/ssqc/client.qc index 29655cc8..8304e04e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -961,7 +961,7 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_z); local string nextmapstring = vote_result; - if (!clanbattle && CF_GetSetting("vs", "vote_style", "1")){ + if (!clanbattle && CF_GetSetting("vs", "vote_style", ftos(!clanbattle))){ if(votemode && vote_result) { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); @@ -1270,13 +1270,15 @@ void () ClientKill = { return; if (self.deadflag) return; - if (self.playerclass == PC_UNDEFINED) - return; + if(!votemode) { + if (self.playerclass == PC_UNDEFINED) + return; - if (self.suicide_time > time && self.clientkillforce == 0) { - timeleft = self.suicide_time - time; - sprint(self, PRINT_HIGH, "You have to wait ", ftos(ceil(timeleft)), " more seconds to suicide\n"); - return; + if (self.suicide_time > time && self.clientkillforce == 0) { + timeleft = self.suicide_time - time; + sprint(self, PRINT_HIGH, "You have to wait ", ftos(ceil(timeleft)), " more seconds to suicide\n"); + return; + } } Sniper_ZoomReset(self); @@ -1326,6 +1328,9 @@ void () ClientKill = { ResetPlayersWithCountdown(); } } + if(votemode && vote_anarchy_mode) { + CheckVoting(); + } }; entity lastspawn_team1; @@ -1526,6 +1531,7 @@ void (entity p) SetVoteParams = { p.armortype = 0; p.team_no = 0; p.playerclass = 0; + p.flags |= FL_ONGROUND; p.skin = rint(random() * 9); //self.playerclass; stuffcmd(p, strcat("color ", ftos(rint(random() * 12)), " ", ftos(rint(random() * 12)), "\n")); @@ -1549,6 +1555,7 @@ void (entity p) SetVoteParams = { p.fixangle = 1; setmodel(p, "progs/player.mdl"); + p.modelindex = modelindex_player; setsize(p, VEC_HULL_MIN, VEC_HULL_MAX); p.view_ofs = '0 0 22'; @@ -1858,7 +1865,7 @@ void () NextLevel = { return; already_cycled = 1; - if (!clanbattle && CF_GetSetting("vs", "vote_style", "1")){ + if (!clanbattle && CF_GetSetting("vs", "vote_style", ftos(!clanbattle))){ intermission_running = 0; if(votemode && vote_result) { localcmd ("localinfo votemode off\n"); @@ -2147,7 +2154,7 @@ void () PlayerPreThink = { } // Check if timelimit/fraglimit has been met - CheckRules(); + if(!votemode) CheckRules(); if (self.playerclass != 0 || votemode) { WaterMove(); @@ -2217,7 +2224,7 @@ void () CheckPowerups = { if (self.health <= 0) { return; } - if (self.playerclass == 0) { + if (self.playerclass == 0 && !votemode) { self.modelindex = modelindex_null; } else { if ((self.is_undercover == 1) && (invis_only == 1)) { @@ -2415,6 +2422,7 @@ void () PlayerPostThink = { if (time >= self.StatusRefreshTime) RefreshStatusBar(self); + CheckPowerups(); W_WeaponFrame(); } else { CheckPowerups(); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index ad9c80c5..014a9e2b 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -57,6 +57,7 @@ void () QuadMode = localcmd ("fraglimit 0\n"); localcmd ("localinfo rd 0\n"); localcmd ("localinfo votemode 0\n"); + localcmd ("localinfo vote_style 0\n"); localcmd ("exec fo_quadmode.cfg\n"); bprint (PRINT_HIGH, "Quad Mode set to on\n"); bprint (PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -67,6 +68,7 @@ void () ClanMode = localcmd("localinfo clan on\n"); localcmd ("localinfo rd 0\n"); localcmd ("localinfo votemode 0\n"); + localcmd ("localinfo vote_style 0\n"); localcmd ("exec fo_clanmode.cfg\n"); bprint(PRINT_HIGH, "Clan Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -85,6 +87,8 @@ void () PubMode = localcmd ("fraglimit 0\n"); localcmd ("localinfo round_time 0\n"); localcmd ("localinfo rd 0\n"); + localcmd ("localinfo votemode 0\n"); + localcmd ("localinfo vote_style 1\n"); localcmd ("exec fo_pubmode.cfg\n"); bprint(PRINT_HIGH, "Pub Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -101,10 +105,12 @@ void () DuelMode = localcmd ("localinfo drd 3.9\n"); // wait before resetting the winner long enough for grens to go off localcmd ("localinfo rd 9999\n"); // wait before respawning the loser localcmd ("localinfo dph 1\n"); // print health of duel survivors - localcmd ("password none\n"); + localcmd ("localinfo stockfull on\n"); // all packs fully restock + localcmd ("localinfo stock_reload on\n"); // all packs insta-reload localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); localcmd ("localinfo votemode 0\n"); + localcmd ("localinfo vote_style 0\n"); localcmd ("exec fo_duelmode.cfg\n"); bprint(PRINT_HIGH, "Duel Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -713,6 +719,12 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; ListVoteMaps(self); break; + case "break": + processedCmd = TRUE; + if(votemode) { + UnvoteForMap(self); + } + break; case "captainpick": processedCmd = TRUE; if(arg2) { @@ -720,6 +732,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { CaptainPick(self, farg2); } break; + case "reportmodel": + processedCmd = TRUE; + sprint(self, PRINT_HIGH, "Model: ", self.model, " index: ", ftos(self.modelindex), "\n"); + break; } if (self.is_admin) diff --git a/ssqc/extraents.qc b/ssqc/extraents.qc index 445252f4..c2e91047 100644 --- a/ssqc/extraents.qc +++ b/ssqc/extraents.qc @@ -77,10 +77,25 @@ void () ball_touch = { return; }; -void () item_ball = { +void () ball_reset = { self.solid = 1.000; - self.movetype = 10.000; - //self.flags= 256.000; + self.velocity = '0 0 0'; + self.origin = self.oldorigin; + setorigin (self,self.origin); + + if ( !droptofloor () ) { + dprint ("GoalItem (ball) fell out of level at "); + dprint (vtos (self.origin)); + dprint ("\n"); + dremove (self); + return ; + } +}; + +void () item_ball = { + self.solid = SOLID_TRIGGER; + self.movetype = MOVETYPE_BOUNCE; + //self.flags= FL_ITEM; if ( self.mdl ) { precache_model (self.mdl); @@ -96,15 +111,15 @@ void () item_ball = { self.netname = "ball"; } - if ( (self.goal_min == '0.000 0.000 0.000') ) { - self.goal_min = '-12.000 -12.000 -12.000'; + if ( (self.goal_min == '0 0 0') ) { + self.goal_min = '-12 -12 -12'; } - if ( (self.goal_max == '0.000 0.000 0.000') ) { - self.goal_max = '12.000 12.000 12.000'; + if ( (self.goal_max == '0 0 0') ) { + self.goal_max = '12 12 12'; } setsize (self,self.goal_min,self.goal_max); - //setsize (self,'-0.000 -0.000 -0.000','24.000 24.000 24.000'); + //setsize (self,'-0 -0 -0','24 24 24'); setorigin (self,self.origin); self.oldorigin = self.origin; self.touch = ball_touch; @@ -118,10 +133,12 @@ void () soccer_goal_touch = { if (other.classname == "item_ball") { if (other.solid) { TeamFortress_TeamIncreaseScore (self.owned_by,self.count); - TeamFortress_TeamShowScores (2.000); - sound (self,2.000,self.noise,1.000,0.000); + TeamFortress_TeamShowScores (2); + sound (self,FL_ITEM,self.noise,1,ATTN_NONE); //round_winner = self.pteam; - other.solid = 0.000; + other.solid = SOLID_NOT; + other.nextthink = (time + 0.3); + other.think = ball_reset; } return; } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e9da2933..893dfb44 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2359,7 +2359,7 @@ void (float Suicided) TeamFortress_SetupRespawn = { else restime = 0; - if (!cb_prematch) { + if (!cb_prematch && !votemode) { if (Suicided) { if (self.lives > 0) self.lives = self.lives - 1; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 1996ba85..6f40d669 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1120,21 +1120,17 @@ void () AnarchyMode = { e.items = IT_AXE; e.weapons_carried = IT_AXE; e.current_weapon = WEAP_AXE; - W_SetCurrentAmmo(e); if(e.vote_map) { e.items |= IT_QUAD; e.tfstate &= 128; e.super_damage_finished = time + 666; + //e.effects = e.effects | EF_BLUE; } + W_SetCurrentAmmo(e); e = find(e, classname, "player"); } bprint(PRINT_HIGH, "\bDemocracy has failed!\b Let the result be decided in \bBATTLE\b\n"); -}; - -void () StartVoting = { - voting_started = TRUE; - vote_anarchy_mode = FALSE; - bprint(PRINT_HIGH, "Voting has started!\n"); + sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); }; void () EndVoting = { @@ -1151,6 +1147,8 @@ void () EndVoting = { e.items = 0; e.weapons_carried = 0; e.current_weapon = 0; + e.super_damage_finished = 0; + //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; W_SetCurrentAmmo(e); e = find(e, classname, "player"); } @@ -1168,10 +1166,14 @@ void (string map_name) ChangeToVotedMap = { execute_changelevel(); }; -void () CheckVoting = { - local float numplayers = 0, votedplayers = 0; +float () CheckVoting = { + if(intermission_running) { + return FALSE; + } + local float totalplayers = 0, numplayers = 0, votedplayers = 0; local entity e = find(world, classname, "player"); while(e) { + totalplayers++; if((e.health > 0 || !vote_anarchy_mode) && !e.has_disconnected) { numplayers++; if(e.vote_map) { @@ -1184,13 +1186,13 @@ void () CheckVoting = { if(numplayers <= 0 || votedplayers <= 0) { bprint(PRINT_HIGH, "\bVoting reset...\b\n"); EndVoting(); - return; + return FALSE; } e = find(world, classname, "map_candidate"); while(e) { //unanimous - change immediately - if(e.cnt >= numplayers) { + if(e.cnt >= totalplayers) { bprint(PRINT_HIGH, "\bUnanimous choice:\b ", e.netname, "\n"); ChangeToVotedMap(e.netname); break; @@ -1204,6 +1206,7 @@ void () CheckVoting = { } e = find(e, classname, "map_candidate"); } + return TRUE; }; void (entity p) PrintVoting = { @@ -1211,7 +1214,14 @@ void (entity p) PrintVoting = { sprint(p, PRINT_HIGH, "No votes.\n"); return; } - sprint(p, PRINT_HIGH, ftos(rint(voting_expires - time)), " seconds remain. \bCurrent votes:\b\n"); + local float expires = rint(voting_expires - time); + if(expires > 0) { + sprint(p, PRINT_HIGH, ftos(expires), " seconds remain. "); + } + if(vote_anarchy_mode) { + sprint(p, PRINT_HIGH, "\bANRACHY MODE!\b "); + } + sprint(p, PRINT_HIGH, "\bCurrent votes:\b\n"); local entity mc = find(world, classname, "map_candidate"); while(mc) { if(mc.cnt > 0) { @@ -1226,30 +1236,51 @@ void (entity p) PrintVoting = { }; void() vote_think = { - CheckVoting(); - self.nextthink = time + 1; + if(CheckVoting()) { + if(vote_anarchy_mode) { + bprint(PRINT_HIGH, "\bANARCHY MODE!\b\n"); + sound(self, CHAN_AUTO, "items/damage.wav", 1, ATTN_NONE); + self.nextthink = time + 5; + } else { + local float expires = floor(voting_expires - time); + if(expires < 10 || expires % 30 == 0) { + bprint(PRINT_HIGH, "\x10",ftos(expires),"\x11 seconds left\n"); + sound(self, CHAN_AUTO, "buttons/switch04.wav", 1, ATTN_NONE); + } + self.nextthink = time + 1; + } + } }; -void (entity p, string vote) VoteForMap = { +void () StartVoting = { + if(voting_started) + return; local float expires = CF_GetSetting("votetime", "vote_time", "60"); - entity te; + local entity te; + voting_started = TRUE; + vote_anarchy_mode = FALSE; + bprint(PRINT_HIGH, "Voting has started!\n"); + sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); + if(expires) { + bprint(PRINT_HIGH, "Voting closes in ", ftos(expires), " seconds. \bBe quick!\b\n"); + voting_expires = time + expires; + te = spawn(); + te.think = vote_think; + te.classname = "vote_timer"; + te.nextthink = time + 1; + } else { + bprint(PRINT_HIGH, "No voting timelimit configured, so will require unanimous decision\n"); + } +}; + + +void (entity p, string vote) VoteForMap = { local entity mc = find(world, classname, "map_candidate"); while(mc) { if(mc.netname == vote) { if(!voting_started) { StartVoting(); bprint(PRINT_HIGH, p.netname, " suggests \b", vote, "\b\n"); - if(expires) { - bprint(PRINT_HIGH, "Voting closes in ", ftos(expires), " seconds. \bBe quick!\b\n"); - voting_expires = time + expires; - te = spawn(); - te.think = vote_think; - te.classname = "vote_timer"; - te.nextthink = time + 1; - } else { - bprint(PRINT_HIGH, "No voting timelimit configured, so will require unanimous decision\n"); - } - } else { if(p.vote_map) { bprint(PRINT_HIGH, p.netname, " changes vote to \b", vote, "\b\n"); @@ -1276,6 +1307,7 @@ void (entity p) UnvoteForMap = { bprint(PRINT_HIGH, p.netname, " \babandons vote for\b ", p.vote_map.netname, "\n"); } p.vote_map.cnt--; + p.vote_map = world; } CheckVoting(); }; diff --git a/ssqc/world.qc b/ssqc/world.qc index a0397762..a98be34c 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -307,6 +307,8 @@ void () worldspawn = { precache_model2("progs/grenade3.mdl"); precache_model2(MODEL_PROJ_DIAM2); precache_sound("grentimer.wav"); + precache_sound("buttons/switch04.wav"); + precache_sound("boss2/pop2.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); From 8d27269d5fd0e72a236c4544e1da6fc0e994ecaf Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 7 Jan 2020 20:51:11 +1300 Subject: [PATCH 0884/2474] added command to vote to end the current map --- csqc/menu.qc | 14 ++++++++-- ssqc/client.qc | 24 ++++++++++------ ssqc/commands.qc | 8 +++++- ssqc/tforthlp.qc | 1 + ssqc/vote.qc | 72 ++++++++++++++++++++++++++++++++++++++++++++++-- ssqc/world.qc | 15 ++++++---- 6 files changed, 114 insertions(+), 20 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index c1e01bd7..d83e76f4 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -114,7 +114,11 @@ var fo_menu FO_MENU_TEAM = { {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam auto\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"0","Spectate","","",FO_MENU_STATE_NORMAL,{localcmd("observe\n");Menu_Cancel();},MENU_BUTTON}, - }, 8, TRUE + }, 8, TRUE, { + if(intermission) { + Menu_Cancel(); + } + } }; var fo_menu FO_MENU_CLASS = { [0,0], [300,200], "Select Class", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { @@ -128,7 +132,11 @@ var fo_menu FO_MENU_CLASS = { {"8","Spy","","Can disguise as the enemy and feign death",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 8\n");Menu_Cancel();},MENU_BUTTON}, {"9","Engineer","","Can build sentry guns and ammo dispensers. Also has powerful EMP grenades as secondaries",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 9\n");Menu_Cancel();},MENU_BUTTON}, {"0","Random Playerclass","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 10\n");Menu_Cancel();},MENU_BUTTON}, - }, 10, TRUE + }, 10, TRUE, { + if(intermission) { + Menu_Cancel(); + } + } }; var fo_menu FO_MENU_DROPAMMO = { [0,0], [300,150], "Drop Ammo", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { @@ -656,7 +664,7 @@ vector fo_menu_draw(fo_menu * menu) = { if(fo_hud_editor) return position; - if(!menu.active || showingscores) { + if(!menu.active || showingscores || (intermission && !(menu.flags & FO_MENU_FLAG_USE_MOUSE))) { setcursormode(FALSE); return position; } diff --git a/ssqc/client.qc b/ssqc/client.qc index 8304e04e..d0381c96 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -961,14 +961,17 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_z); local string nextmapstring = vote_result; - if (!clanbattle && CF_GetSetting("vs", "vote_style", ftos(!clanbattle))){ - if(votemode && vote_result) { + local float vote_style = CF_GetSetting("vs", "vote_style", ftos(!clanbattle)); + if (vote_style || votemode == 2){ + if(votemode == 1 && vote_result) { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); - } else { + } else if(vote_style == 1 || votemode == 2) { vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); localcmd ("localinfo votemode on\n"); //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "start")); + } else { + vote_result = mapname; } } //if(!votemode) { @@ -1865,14 +1868,17 @@ void () NextLevel = { return; already_cycled = 1; - if (!clanbattle && CF_GetSetting("vs", "vote_style", ftos(!clanbattle))){ - intermission_running = 0; - if(votemode && vote_result) { + local float vote_style = CF_GetSetting("vs", "vote_style", ftos(!clanbattle)); + if (vote_style || votemode == 2){ + if(votemode == 1 && nextmap) { localcmd ("localinfo votemode off\n"); - nextmap = vote_result; - } else { - localcmd ("localinfo votemode on\n"); + //changelevel(vote_result); + } else if(vote_style == 1 || votemode == 2) { nextmap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + localcmd ("localinfo votemode on\n"); + //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "start")); + } else { + nextmap = mapname; } } o = spawn(); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 014a9e2b..177a46a1 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -722,7 +722,13 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "break": processedCmd = TRUE; if(votemode) { - UnvoteForMap(self); + if(self.vote_map) { + UnvoteForMap(self); + } else { + sprint(self, PRINT_HIGH, "You haven't voted yet!\n"); + } + } else { + VoteToEndMap(self); } break; case "captainpick": diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 6907f7d9..2e308035 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -219,6 +219,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo + TeamFortress_AliasString("break", "cmd break"); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { Menu_Team(1); } diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 6f40d669..cd57fead 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -36,6 +36,7 @@ float (float pf_from, float pf_to) RandomRange; void () Vote_DropLosers; float (string ps_list) List_Count; string (string ps_list, float pf_idx) List_Index; +string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; // opens the map voting early // called from weapons.qc:ImpulseCommands() @@ -1100,6 +1101,34 @@ void() map_candidate = {}; .cnt = number of current votes */ + +void (string name, string desc, string votemap) AddVoteMap = { + if(!name || name == votemap) { + return; + } + local entity mc = spawn(); + mc.classname = "map_candidate"; + mc.netname = name; + mc.broadcast = desc; +}; + +void () InitVoteMaps = { + string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + //No point adding the vote map if it is the current one, and thus known to be missing the ents + if(votemap != mapname) { + //Otherwise, assume we somehow ended up on the wrong map and offer to vote for the correct one + local entity mc = spawn(); + mc.classname = "map_candidate"; + mc.netname = votemap; + mc.broadcast = "Currently configured vote map"; + } + AddVoteMap("2fort5r", "Basic CTF", votemap); + AddVoteMap("1on1r", "Basic Duel", votemap); + AddVoteMap("2fort5r", "Basic CTF", votemap); + AddVoteMap("2fort5r", "Basic CTF", votemap); + AddVoteMap("2fort5r", "Basic CTF", votemap); +}; + void (entity p) ListVoteMaps = { sprint(p, PRINT_HIGH, "Maps eligible for voting:\n"); local entity mc = find(world, classname, "map_candidate"); @@ -1167,7 +1196,7 @@ void (string map_name) ChangeToVotedMap = { }; float () CheckVoting = { - if(intermission_running) { + if(intermission_running || vote_result) { return FALSE; } local float totalplayers = 0, numplayers = 0, votedplayers = 0; @@ -1185,6 +1214,7 @@ float () CheckVoting = { if(numplayers <= 0 || votedplayers <= 0) { bprint(PRINT_HIGH, "\bVoting reset...\b\n"); + sound(self, CHAN_AUTO, "items/qpi2.wav", 1, ATTN_NONE); EndVoting(); return FALSE; } @@ -1196,6 +1226,11 @@ float () CheckVoting = { bprint(PRINT_HIGH, "\bUnanimous choice:\b ", e.netname, "\n"); ChangeToVotedMap(e.netname); break; + } else if(vote_anarchy_mode) { + if(e.cnt >= numplayers) { + bprint(PRINT_HIGH, "\bAnarchy succeeded!\b Winner by combat: ", e.netname, "\n"); + ChangeToVotedMap(e.netname); + } } else if(voting_expires < time) { if(e.cnt > (numplayers/2)) { bprint(PRINT_HIGH, "\bTime's up!\b Majority choice: ", e.netname, "\n"); @@ -1242,13 +1277,15 @@ void() vote_think = { sound(self, CHAN_AUTO, "items/damage.wav", 1, ATTN_NONE); self.nextthink = time + 5; } else { - local float expires = floor(voting_expires - time); + local float expires = ceil(voting_expires - time); if(expires < 10 || expires % 30 == 0) { bprint(PRINT_HIGH, "\x10",ftos(expires),"\x11 seconds left\n"); sound(self, CHAN_AUTO, "buttons/switch04.wav", 1, ATTN_NONE); } self.nextthink = time + 1; } + } else { + dremove(self); } }; @@ -1311,3 +1348,34 @@ void (entity p) UnvoteForMap = { } CheckVoting(); }; + +void (entity p) VoteToEndMap = { + if(CF_GetSetting("vs", "vote_style", ftos(!clanbattle))) { + if(p.vote_next) { + bprint(PRINT_HIGH, p.netname, " desides to keep playing.\n"); + } else { + bprint(PRINT_HIGH, p.netname, " \bvotes to end the current map.\b.\n"); + } + p.vote_next = !p.vote_next; + local float numplayers = 0, numvoted = 0; + local entity te = find (world, classname, "player"); + while (te) { + if (!te.has_disconnected) { + numplayers = numplayers + 1; + if(te.vote_next) { + numvoted++; + } + } + te = find (te, classname, "player"); + } + if(numvoted > (numplayers / 2)) { + bprint(PRINT_HIGH, "\bMap ended by majority vote.\b.\n"); + vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + votemode = 2; + execute_changelevel(); + } else { + bprint(PRINT_HIGH, "\x10",ftos((floor(numplayers/2) + 1) - numvoted),"\x11 more votes required to end the current map.\n"); + bprint(PRINT_HIGH, "Type \bbreak\b to toggle your vote.\n"); + } + } +}; diff --git a/ssqc/world.qc b/ssqc/world.qc index a98be34c..f4e2ebd3 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -309,6 +309,7 @@ void () worldspawn = { precache_sound("grentimer.wav"); precache_sound("buttons/switch04.wav"); precache_sound("boss2/pop2.wav"); + precache_sound("items/qpi2.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); @@ -331,17 +332,21 @@ void () worldspawn = { worldspawnent.think = WorldSpawnPost; worldspawnent.nextthink = time + .01; votemode = CF_GetSetting("vm", "votemode", "off"); - /* + if(votemode) { + //No map candidates in map! Add some defaults... + if(!find(world, classname, "map_candidate")) { + InitVoteMaps(); + } string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); if(world.model != strcat("maps/",votemap,".bsp")) { - bprint(PRINT_HIGH, "MEHT: need to change to se2!\n"); - changelevel(votemap); + bprint(PRINT_HIGH, "\bDisabling vote mode as map is not\b ",votemap,"\n"); + //changelevel(votemap); + localcmd ("localinfo votemode 0\n"); + votemode = FALSE; } else { - bprint(PRINT_HIGH, "MEHT: already se2, carry on.\n"); } } - */ }; void () StartFrame = { From 1e935611c78732b0c7d765606d824305599594f9 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 7 Jan 2020 21:29:18 +1300 Subject: [PATCH 0885/2474] allow other game modes to break out of maps to vote --- README.md | 3 ++- ssqc/client.qc | 4 ++-- ssqc/commands.qc | 6 +++--- ssqc/vote.qc | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f9e152f0..3bd0ecc0 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ FortressOne Server New features ------ +* `break` will vote to end the current map or recind your vote in a vote map * localinfo vote_time 60 - seconds since the first vote is cast until voting is decided. 0 means majority vote only. * localinfo vote_map - map to designate for voting -* localinfo vote_style 1 - got to voting map after round is over instead of asking using menus +* localinfo vote_style 1 - got to voting map after round is over instead of asking using menus, 2 - maps restart upon time/frag limit, but a `break` concensus will exit them to the votemap. * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press diff --git a/ssqc/client.qc b/ssqc/client.qc index d0381c96..fdb68075 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -961,7 +961,7 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_z); local string nextmapstring = vote_result; - local float vote_style = CF_GetSetting("vs", "vote_style", ftos(!clanbattle)); + local float vote_style = CF_GetSetting("vs", "vote_style", "2"); if (vote_style || votemode == 2){ if(votemode == 1 && vote_result) { localcmd ("localinfo votemode off\n"); @@ -1868,7 +1868,7 @@ void () NextLevel = { return; already_cycled = 1; - local float vote_style = CF_GetSetting("vs", "vote_style", ftos(!clanbattle)); + local float vote_style = CF_GetSetting("vs", "vote_style", "2"); if (vote_style || votemode == 2){ if(votemode == 1 && nextmap) { localcmd ("localinfo votemode off\n"); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 177a46a1..48cd6ac5 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -57,7 +57,7 @@ void () QuadMode = localcmd ("fraglimit 0\n"); localcmd ("localinfo rd 0\n"); localcmd ("localinfo votemode 0\n"); - localcmd ("localinfo vote_style 0\n"); + localcmd ("localinfo vote_style 2\n"); localcmd ("exec fo_quadmode.cfg\n"); bprint (PRINT_HIGH, "Quad Mode set to on\n"); bprint (PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -68,7 +68,7 @@ void () ClanMode = localcmd("localinfo clan on\n"); localcmd ("localinfo rd 0\n"); localcmd ("localinfo votemode 0\n"); - localcmd ("localinfo vote_style 0\n"); + localcmd ("localinfo vote_style 2\n"); localcmd ("exec fo_clanmode.cfg\n"); bprint(PRINT_HIGH, "Clan Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); @@ -110,7 +110,7 @@ void () DuelMode = localcmd ("timelimit 0\n"); localcmd ("fraglimit 30\n"); localcmd ("localinfo votemode 0\n"); - localcmd ("localinfo vote_style 0\n"); + localcmd ("localinfo vote_style 2\n"); localcmd ("exec fo_duelmode.cfg\n"); bprint(PRINT_HIGH, "Duel Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); diff --git a/ssqc/vote.qc b/ssqc/vote.qc index cd57fead..8230b6c0 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1350,7 +1350,7 @@ void (entity p) UnvoteForMap = { }; void (entity p) VoteToEndMap = { - if(CF_GetSetting("vs", "vote_style", ftos(!clanbattle))) { + if(CF_GetSetting("vs", "vote_style", "0")) { if(p.vote_next) { bprint(PRINT_HIGH, p.netname, " desides to keep playing.\n"); } else { From bb0e3824800f3061993de0417b1debfd87b811ad Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 7 Jan 2020 22:53:21 +1300 Subject: [PATCH 0886/2474] autoid for votes --- ssqc/actions.qc | 79 ++++++++++++++++++++++++++++++------------------- ssqc/status.qc | 5 ++-- ssqc/vote.qc | 1 + 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index ab8be355..788a6ce2 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -210,38 +210,46 @@ void (entity pe_player, float f_type) CF_Identify = { // alive player is found if (trace_ent.classname == "player" && trace_ent.health) { - - // set class and name - s_class = TeamFortress_GetClassName(trace_ent.playerclass); + s_name = trace_ent.netname; + if(votemode) { + if(trace_ent.vote_map) { + s_class = trace_ent.vote_map.netname; + } else { + s_class = "Has not voted"; + } + } else { + // set class and name + s_class = TeamFortress_GetClassName(trace_ent.playerclass); - // set health if you're a medic - if (pe_player.playerclass == PC_MEDIC) { - f_health = trace_ent.health; - f_maxhealth = trace_ent.max_health; - } + // set health if you're a medic + if (pe_player.playerclass == PC_MEDIC) { + f_health = trace_ent.health; + f_maxhealth = trace_ent.max_health; + } - // set armor if you're an engineer - else if (pe_player.playerclass == PC_ENGINEER) { - f_armor = trace_ent.armorvalue; - f_maxarmor = trace_ent.maxarmor; - } + // set armor if you're an engineer + else if (pe_player.playerclass == PC_ENGINEER) { + f_armor = trace_ent.armorvalue; + f_maxarmor = trace_ent.maxarmor; + } - // target is an enemy spy - if (trace_ent.playerclass == PC_SPY && !f_friendly) { + // target is an enemy spy + if (trace_ent.playerclass == PC_SPY && !f_friendly) { - // don't identify feigning enemy spies - if (trace_ent.is_feigning) - return; + // don't identify feigning enemy spies + if (trace_ent.is_feigning) + return; - // use undercover name if available - if (trace_ent.undercover_name != string_null) - s_name = trace_ent.undercover_name; + // use undercover name if available + if (trace_ent.undercover_name != string_null) + s_name = trace_ent.undercover_name; - // set class to undercover skin - if (trace_ent.undercover_skin) - s_class = TeamFortress_GetClassName(trace_ent.undercover_skin); + // set class to undercover skin + if (trace_ent.undercover_skin) + s_class = TeamFortress_GetClassName(trace_ent.undercover_skin); + } } // dispenser is found @@ -309,12 +317,23 @@ void (entity pe_player, float f_type) CF_Identify = { s_id_string = strcat(s_id_string, "\n"); } - // set friendly/enemy - if (f_friendly || f_fakefriendly) - s_id_string = strcat(s_id_string, "Friendly"); - else - s_id_string = strcat(s_id_string, "Hostile"); - + if (votemode) { + // in a voting scenario, set same vs different vote indicator + if(pe_player.vote_map && trace_ent.vote_map) { + if(pe_player.vote_map == trace_ent.vote_map) { + s_id_string = strcat(s_id_string, "\bComrade\b\n"); + } else { + s_id_string = strcat(s_id_string, "\bOpposition\b\n"); + } + } + } else { + // set friendly/enemy + if (f_friendly || f_fakefriendly) + s_id_string = strcat(s_id_string, "Friendly"); + else + s_id_string = strcat(s_id_string, "Hostile"); + } + // set class if (s_class != "") { s_id_string = strcat(s_id_string, " "); diff --git a/ssqc/status.qc b/ssqc/status.qc index d7f31c7e..fa4a98fa 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -971,7 +971,7 @@ void (entity pl) RefreshStatusBar = { height = height - pl.StatusStringLines - 13; // no sbar can be displayed - if (height <= 0 || pl.playerclass == PC_UNDEFINED) { + if (height <= 0 || (pl.playerclass == PC_UNDEFINED && !votemode)) { centerprint(pl, pl.StatusString); pl.StatusRefreshTime = time + 1.5; return; @@ -994,7 +994,8 @@ void (entity pl) RefreshStatusBar = { { ct = strzone("\n\n\n\n\n\n"); } - else if (csqcactive) // has csqc + //else + if (csqcactive) // has csqc { //pl.StatusRefreshTime = time + 1; UpdateClientStatusBar(pl); diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 8230b6c0..f7300f73 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1232,6 +1232,7 @@ float () CheckVoting = { ChangeToVotedMap(e.netname); } } else if(voting_expires < time) { + // do we want this to trigger during anarchy too when hitting majority? if(e.cnt > (numplayers/2)) { bprint(PRINT_HIGH, "\bTime's up!\b Majority choice: ", e.netname, "\n"); ChangeToVotedMap(e.netname); From fd77fa0aa777d14fc5f07c44a364be98943ee3a7 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 8 Jan 2020 20:34:58 +1300 Subject: [PATCH 0887/2474] updated --- README.md | 1 + csqc/menu.qc | 5 ++-- ssqc/commands.qc | 66 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3bd0ecc0..4755b2bf 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* `cmd forcebreak` - new admin command to end the map (and go to vote) * `break` will vote to end the current map or recind your vote in a vote map * localinfo vote_time 60 - seconds since the first vote is cast until voting is decided. 0 means majority vote only. * localinfo vote_map - map to designate for voting diff --git a/csqc/menu.qc b/csqc/menu.qc index d83e76f4..f891662e 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -361,15 +361,16 @@ var fo_menu FO_MENU_ADMIN_MAIN = { {"4","Force Spectate...","","Force someone to be a spectator",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_FORCE_SPEC, 0);},MENU_BORDER_WARNING}, {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd randomise\n");},MENU_BORDER_WARNING}, {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd restart\n"); Menu_Cancel();},MENU_BORDER_WARNING}, + {"8","End Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcebreak\n"); Menu_Cancel();},MENU_BORDER_WARNING}, MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"+","Next - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, {"-","Prev - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, - }, 11, TRUE, { + }, 12, TRUE, { updateAdminMenuInfo(); FO_MENU_ADMIN_MAIN.options[0].value = SERVER_ADMIN.ceasefire?"on":"off"; - FO_MENU_ADMIN_MAIN.options[6].value = mapname; + FO_MENU_ADMIN_MAIN.options[5].value = mapname; } }; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 48cd6ac5..8f182b18 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -742,6 +742,36 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; sprint(self, PRINT_HIGH, "Model: ", self.model, " index: ", ftos(self.modelindex), "\n"); break; + case "help": + case "list": + processedCmd = TRUE; + sprint(self, PRINT_HIGH, "\bUser Commands list:\b\n"); + sprint(self, PRINT_HIGH, "cmd adminpwd \n"); + if(votemode) { + sprint(self, PRINT_HIGH, "cmd listmaps\b: list votable maps\b\n"); + sprint(self, PRINT_HIGH, "cmd votemap \b: vote for the specified map\b\n"); + sprint(self, PRINT_HIGH, "cmd showvotes\b: List current voting summary\b\n"); + sprint(self, PRINT_HIGH, "cmd break\b: Cancel current vote\b\n"); + } else { + sprint(self, PRINT_HIGH, "cmd changeteam [#|auto]\n"); + sprint(self, PRINT_HIGH, "cmd changeclass [#]\n"); + sprint(self, PRINT_HIGH, "cmd dropammo [1-4]\n"); + sprint(self, PRINT_HIGH, "cmd disguise [last|none|skin #|team #]\n"); + sprint(self, PRINT_HIGH, "cmd menu\n"); + sprint(self, PRINT_HIGH, "cmd autoscan\n"); + sprint(self, PRINT_HIGH, "cmd scansound\n"); + sprint(self, PRINT_HIGH, "cmd scanf\n"); + sprint(self, PRINT_HIGH, "cmd scane\n"); + sprint(self, PRINT_HIGH, "cmd detpack [#|cancel]\n"); + sprint(self, PRINT_HIGH, "cmd build [cancel|sentry|dispenser|destroy {sentry|dispenser}]\n"); + sprint(self, PRINT_HIGH, "cmd sentry [rotate #]\n"); + sprint(self, PRINT_HIGH, "cmd dispenser [ammo|armour|repair|withdraw {ammo|armour}]\n"); + sprint(self, PRINT_HIGH, "cmd captainpick #\n"); + sprint(self, PRINT_HIGH, "cmd break\b: end current map\b\n"); + } + sprint(self, PRINT_HIGH, "cmd help || list (this command)\n"); + sprint(self, PRINT_HIGH, "\n"); + break; } if (self.is_admin) @@ -1037,20 +1067,26 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } Menu_Admin(); break; + case "forcebreak": + processedCmd = TRUE; + bprint(PRINT_HIGH, "\bMap ended by admin\b ",self.netname,".\n"); + vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + votemode = 2; + execute_changelevel(); + break; case "help": case "list": processedCmd = TRUE; - sprint(self, PRINT_HIGH, "Commands list:\n"); - sprint(self, PRINT_HIGH, "cmd adminpwd\n"); + sprint(self, PRINT_HIGH, "\bAdmin Commands list:\b\n"); sprint(self, PRINT_HIGH, "cmd timelimit\n"); - sprint(self, PRINT_HIGH, "cmd prematch\n"); - sprint(self, PRINT_HIGH, "cmd fraglimit\n"); - sprint(self, PRINT_HIGH, "cmd teamplay\n"); - sprint(self, PRINT_HIGH, "cmd password\n"); - sprint(self, PRINT_HIGH, "cmd map\n"); - sprint(self, PRINT_HIGH, "cmd record\n"); - sprint(self, PRINT_HIGH, "cmd easyrecord\n"); - sprint(self, PRINT_HIGH, "cmd autorecord\n"); + sprint(self, PRINT_HIGH, "cmd prematch [#]\n"); + sprint(self, PRINT_HIGH, "cmd fraglimit [#]\n"); + sprint(self, PRINT_HIGH, "cmd teamplay [#]\n"); + sprint(self, PRINT_HIGH, "cmd password {|none}\n"); + sprint(self, PRINT_HIGH, "cmd map \n"); + sprint(self, PRINT_HIGH, "cmd record \n"); + sprint(self, PRINT_HIGH, "cmd easyrecord []\n"); + sprint(self, PRINT_HIGH, "cmd autorecord [0|1]\n"); sprint(self, PRINT_HIGH, "cmd cancel\n"); sprint(self, PRINT_HIGH, "cmd stop\n"); sprint(self, PRINT_HIGH, "cmd kick [userid]\n"); @@ -1059,7 +1095,15 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "cmd ceasefire\n"); sprint(self, PRINT_HIGH, "cmd restart\n"); sprint(self, PRINT_HIGH, "cmd randomise\n"); - sprint(self, PRINT_HIGH, "cmd help || list (this command)\n"); + sprint(self, PRINT_HIGH, "cmd pubmode\n"); + sprint(self, PRINT_HIGH, "cmd clanmode\n"); + sprint(self, PRINT_HIGH, "cmd quaddmode\n"); + sprint(self, PRINT_HIGH, "cmd duelmode\n"); + sprint(self, PRINT_HIGH, "cmd forcestart\n"); + sprint(self, PRINT_HIGH, "cmd rounds #\b: Set number of Quad rounds\b\n"); + sprint(self, PRINT_HIGH, "cmd roundtime #\b: Set Quad round time\b\n"); + sprint(self, PRINT_HIGH, "cmd captainmode { | stop} \n"); + sprint(self, PRINT_HIGH, "cmd forcebreak\b: End current map\b\n"); sprint(self, PRINT_HIGH, "\n"); break; } From 5a745b42903dafe203927214ec1c0e8eb9c9786d Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 8 Jan 2020 21:27:38 +1300 Subject: [PATCH 0888/2474] vote logic tweaks --- ssqc/vote.qc | 9 ++++++++- ssqc/world.qc | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ssqc/vote.qc b/ssqc/vote.qc index f7300f73..80938070 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1224,21 +1224,27 @@ float () CheckVoting = { //unanimous - change immediately if(e.cnt >= totalplayers) { bprint(PRINT_HIGH, "\bUnanimous choice:\b ", e.netname, "\n"); + sound(self, CHAN_AUTO, "shalrath/death.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); - break; + return FALSE; } else if(vote_anarchy_mode) { if(e.cnt >= numplayers) { bprint(PRINT_HIGH, "\bAnarchy succeeded!\b Winner by combat: ", e.netname, "\n"); + sound(self, CHAN_AUTO, "shalrath/attack2.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); + return FALSE; } } else if(voting_expires < time) { // do we want this to trigger during anarchy too when hitting majority? if(e.cnt > (numplayers/2)) { bprint(PRINT_HIGH, "\bTime's up!\b Majority choice: ", e.netname, "\n"); + sound(self, CHAN_AUTO, "blob/sight1.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); + return FALSE; } else { AnarchyMode(); } + break; } e = find(e, classname, "map_candidate"); } @@ -1324,6 +1330,7 @@ void (entity p, string vote) VoteForMap = { bprint(PRINT_HIGH, p.netname, " changes vote to \b", vote, "\b\n"); p.vote_map.cnt--; } else { + sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, p.netname, " has voted for \b", vote, "\b\n"); } } diff --git a/ssqc/world.qc b/ssqc/world.qc index f4e2ebd3..8eeae4b1 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -310,6 +310,9 @@ void () worldspawn = { precache_sound("buttons/switch04.wav"); precache_sound("boss2/pop2.wav"); precache_sound("items/qpi2.wav"); + precache_sound("shalrath/death.wav"); + precache_sound("shalrath/attack2.wav"); + precache_sound("blob/sight1.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); From 28bfde8b5a30c7b8138b5d497c16bb307cc8011a Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 12 Jan 2020 14:53:48 +1300 Subject: [PATCH 0889/2474] more default maps; change vote_map default to se2 --- ssqc/client.qc | 10 +++++----- ssqc/commands.qc | 2 +- ssqc/tfort.qc | 2 +- ssqc/vote.qc | 23 +++++++++++++++-------- ssqc/world.qc | 2 +- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index fdb68075..fe2fe2c3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -967,15 +967,15 @@ void () execute_changelevel = { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); } else if(vote_style == 1 || votemode == 2) { - vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); localcmd ("localinfo votemode on\n"); - //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "start")); + //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); } else { vote_result = mapname; } } //if(!votemode) { - // vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + // vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); // nextmapstring = strcat(vote_result, " \b(voting)\b"); //} @@ -1874,9 +1874,9 @@ void () NextLevel = { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); } else if(vote_style == 1 || votemode == 2) { - nextmap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + nextmap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); localcmd ("localinfo votemode on\n"); - //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "start")); + //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); } else { nextmap = mapname; } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 8f182b18..44f9cec3 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1070,7 +1070,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "forcebreak": processedCmd = TRUE; bprint(PRINT_HIGH, "\bMap ended by admin\b ",self.netname,".\n"); - vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); votemode = 2; execute_changelevel(); break; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 893dfb44..691d1e8b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1181,7 +1181,7 @@ void (entity p) TeamFortress_SetSpeed = { } else if (p.playerclass == PC_PYRO) { p.maxfbspeed = PC_PYRO_MAXSPEED; p.maxstrafespeed = PC_PYRO_MAXSTRAFESPEED; - } else if (p.playerclass == PC_CIVILIAN) { + } else if (p.playerclass == PC_CIVILIAN || votemode) { p.maxfbspeed = PC_CIVILIAN_MAXSPEED; p.maxstrafespeed = PC_CIVILIAN_MAXSTRAFESPEED; } else if (p.playerclass == PC_SPY) { diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 80938070..fe2d1ade 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -37,6 +37,8 @@ void () Vote_DropLosers; float (string ps_list) List_Count; string (string ps_list, float pf_idx) List_Index; string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; +void (entity ent) TeamFortress_SetSpeed; + // opens the map voting early // called from weapons.qc:ImpulseCommands() @@ -1113,7 +1115,7 @@ void (string name, string desc, string votemap) AddVoteMap = { }; void () InitVoteMaps = { - string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); //No point adding the vote map if it is the current one, and thus known to be missing the ents if(votemap != mapname) { //Otherwise, assume we somehow ended up on the wrong map and offer to vote for the correct one @@ -1124,9 +1126,12 @@ void () InitVoteMaps = { } AddVoteMap("2fort5r", "Basic CTF", votemap); AddVoteMap("1on1r", "Basic Duel", votemap); - AddVoteMap("2fort5r", "Basic CTF", votemap); - AddVoteMap("2fort5r", "Basic CTF", votemap); - AddVoteMap("2fort5r", "Basic CTF", votemap); + AddVoteMap("sq1", "Basic Arena", votemap); + AddVoteMap("mbasesr", "Futuristic CTF", votemap); + AddVoteMap("amth1", "Basic Everything", votemap); + AddVoteMap("well6", "CTF", votemap); + AddVoteMap("genders2", "Small CTF", votemap); + AddVoteMap("frozen1", "CTF with buttons", votemap); }; void (entity p) ListVoteMaps = { @@ -1156,6 +1161,7 @@ void () AnarchyMode = { //e.effects = e.effects | EF_BLUE; } W_SetCurrentAmmo(e); + TeamFortress_SetSpeed(e); e = find(e, classname, "player"); } bprint(PRINT_HIGH, "\bDemocracy has failed!\b Let the result be decided in \bBATTLE\b\n"); @@ -1179,6 +1185,7 @@ void () EndVoting = { e.super_damage_finished = 0; //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; W_SetCurrentAmmo(e); + TeamFortress_SetSpeed(e); e = find(e, classname, "player"); } e = find(world, classname, "map_candidate"); @@ -1268,9 +1275,9 @@ void (entity p) PrintVoting = { while(mc) { if(mc.cnt > 0) { if(p.vote_map == mc) { - sprint(p, PRINT_HIGH, "\b", mc.netname, "\b: ", ftos(mc.cnt), " (Your vote)\n"); + sprint(p, PRINT_HIGH, "", mc.netname, ": ", ftos(mc.cnt), " \b(Your vote)\b\n"); } else { - sprint(p, PRINT_HIGH, "\b", mc.netname, "\b: ", ftos(mc.cnt), "\n"); + sprint(p, PRINT_HIGH, "", mc.netname, ": ", ftos(mc.cnt), "\n"); } } mc = find(mc, classname, "map_candidate"); @@ -1373,12 +1380,12 @@ void (entity p) VoteToEndMap = { if(te.vote_next) { numvoted++; } - } + } te = find (te, classname, "player"); } if(numvoted > (numplayers / 2)) { bprint(PRINT_HIGH, "\bMap ended by majority vote.\b.\n"); - vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); votemode = 2; execute_changelevel(); } else { diff --git a/ssqc/world.qc b/ssqc/world.qc index 8eeae4b1..47e97222 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -341,7 +341,7 @@ void () worldspawn = { if(!find(world, classname, "map_candidate")) { InitVoteMaps(); } - string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "start"); + string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); if(world.model != strcat("maps/",votemap,".bsp")) { bprint(PRINT_HIGH, "\bDisabling vote mode as map is not\b ",votemap,"\n"); //changelevel(votemap); From 95afcd222d8e694c3d4dbec29682411ef587f064 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jan 2020 22:48:05 +1100 Subject: [PATCH 0890/2474] Bump version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3eefcb9d..7dea76ed 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 From b6654fb50abe053b9fd0b548c37102421551ca1b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 13 Jan 2020 19:12:14 +1300 Subject: [PATCH 0891/2474] fix max speed for voting; make sure anarchy mode message doesn't show on map end; make sure map reset message doesn't show when there's nothign to reset --- ssqc/client.qc | 3 +++ ssqc/qw.qc | 1 + ssqc/vote.qc | 42 +++++++++++++++++++++++++++++++++++------- ssqc/world.qc | 1 + 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index fe2fe2c3..386bd7fd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -11,6 +11,7 @@ float modelindex_null; float (entity pe_player) Spy_CheckArea; void () TeamFortress_CheckTeamCheats; +void () TeamFortress_CheckforCheats; void (entity Viewer, float pc, float rpc) TeamFortress_PrintClassName; void () TeamFortress_RemoveTimers; void (float Suicided) TeamFortress_SetupRespawn; @@ -2430,6 +2431,8 @@ void () PlayerPostThink = { CheckPowerups(); W_WeaponFrame(); + //TeamFortress_CheckforCheats(); + TeamFortress_SetSpeed(self); } else { CheckPowerups(); W_WeaponFrame(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 462ef663..715444be 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -458,6 +458,7 @@ float voting_started; float voting_expires; .entity vote_map; float vote_anarchy_mode; +float vote_total_votes; .float tf_id; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index fe2d1ade..876cf870 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1144,8 +1144,22 @@ void (entity p) ListVoteMaps = { sprint(p, PRINT_HIGH, "Use \bcmd votemap \b to cast your vote.\n"); }; +void () anarchy_timer_think = { + local entity e = find(world, classname, "player"); + while(e) { + if(e.vote_map) { + e.items |= IT_QUAD; + e.tfstate &= 128; + e.super_damage_finished = time + 666; + //e.effects = e.effects | EF_BLUE; + } + TeamFortress_SetSpeed(e); + e = find(e, classname, "player"); + } +}; + void () AnarchyMode = { - if(vote_anarchy_mode) + if(vote_anarchy_mode || !voting_started || vote_total_votes <= 0) return; vote_anarchy_mode = TRUE; local entity e = find(world, classname, "player"); @@ -1166,16 +1180,24 @@ void () AnarchyMode = { } bprint(PRINT_HIGH, "\bDemocracy has failed!\b Let the result be decided in \bBATTLE\b\n"); sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); + //e = spawn(); + //e.classname = "anarchy_timer"; + //e.think = anarchy_timer_think; + //e.nextthink = time + 1; }; void () EndVoting = { voting_started = FALSE; vote_anarchy_mode = FALSE; + vote_total_votes = 0; local entity e = find(world, classname, "vote_timer"); if(e) { dremove(e); } - + e = find(world, classname, "anarchy_timer"); + if(e) { + dremove(e); + } e = find(world, classname, "player"); while(e) { e.vote_map = world; @@ -1209,11 +1231,13 @@ float () CheckVoting = { local float totalplayers = 0, numplayers = 0, votedplayers = 0; local entity e = find(world, classname, "player"); while(e) { - totalplayers++; - if((e.health > 0 || !vote_anarchy_mode) && !e.has_disconnected) { - numplayers++; - if(e.vote_map) { - votedplayers++; + if(!e.has_disconnected) { + totalplayers++; + if(e.health > 0 || !vote_anarchy_mode) { + numplayers++; + if(e.vote_map) { + votedplayers++; + } } } e = find(e, classname, "player"); @@ -1310,6 +1334,7 @@ void () StartVoting = { local entity te; voting_started = TRUE; vote_anarchy_mode = FALSE; + vote_total_votes = 0; bprint(PRINT_HIGH, "Voting has started!\n"); sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); if(expires) { @@ -1332,6 +1357,7 @@ void (entity p, string vote) VoteForMap = { if(!voting_started) { StartVoting(); bprint(PRINT_HIGH, p.netname, " suggests \b", vote, "\b\n"); + vote_total_votes++; } else { if(p.vote_map) { bprint(PRINT_HIGH, p.netname, " changes vote to \b", vote, "\b\n"); @@ -1339,6 +1365,7 @@ void (entity p, string vote) VoteForMap = { } else { sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, p.netname, " has voted for \b", vote, "\b\n"); + vote_total_votes++; } } p.vote_map = mc; @@ -1360,6 +1387,7 @@ void (entity p) UnvoteForMap = { } p.vote_map.cnt--; p.vote_map = world; + vote_total_votes--; } CheckVoting(); }; diff --git a/ssqc/world.qc b/ssqc/world.qc index 47e97222..27cc8817 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -335,6 +335,7 @@ void () worldspawn = { worldspawnent.think = WorldSpawnPost; worldspawnent.nextthink = time + .01; votemode = CF_GetSetting("vm", "votemode", "off"); + vote_total_votes = 0; if(votemode) { //No map candidates in map! Add some defaults... From 12659c9985ca7386dd1032d067585f1fe682904d Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 13 Jan 2020 20:06:47 +1300 Subject: [PATCH 0892/2474] fix class commands not being restricted to classes --- ssqc/commands.qc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index eab23b4e..964d0459 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -424,6 +424,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "disguise": processedCmd = TRUE; + if(self.playerclass != PC_SPY) { + sprint(self, PRINT_HIGH, "Only spies can disguise!\n"); + break; + } if(self.health <= 0) { sprint(self, PRINT_HIGH, "Can't spy while dead!\n"); break; @@ -560,6 +564,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "detpack": processedCmd = TRUE; + if(self.playerclass != PC_DEMOMAN) { + sprint(self, PRINT_HIGH, "Only demomen are entrusted with such power!\n"); + break; + } if(self.health <= 0) { sprint(self, PRINT_HIGH, "Can't set detpacks while dead.\n"); break; @@ -585,6 +593,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "build": processedCmd = TRUE; + if(self.playerclass != PC_ENGINEER) { + sprint(self, PRINT_HIGH, "You are not qualified to build anything!\n"); + break; + } if(self.health <= 0) { sprint(self, PRINT_HIGH, "Can't build while dead.\n"); break; @@ -619,6 +631,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "sentry": processedCmd = TRUE; + if(self.playerclass != PC_ENGINEER) { + sprint(self, PRINT_HIGH, "Only engineers can do that!\n"); + break; + } if(self.health <= 0) { sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); break; @@ -642,6 +658,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "dispenser": processedCmd = TRUE; + if(self.playerclass != PC_ENGINEER) { + sprint(self, PRINT_HIGH, "Only engineers can do that!\n"); + break; + } if(self.health <= 0) { sprint(self, PRINT_HIGH, "Can't dispense while dead.\n"); break; From 10a8b4894997b4ca7ffcdc39f97820f0135d139f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 13 Jan 2020 23:14:49 +1300 Subject: [PATCH 0893/2474] remove vote reset from normal play --- ssqc/client.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 386bd7fd..0f3ae4ae 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2605,7 +2605,9 @@ void () ClientDisconnect = { } } - UnvoteForMap(self); + if(votemode) { + UnvoteForMap(self); + } }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { From 714fd382fe7140554f994546ee341af5ab0ebde0 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 13 Jan 2020 23:29:08 +1300 Subject: [PATCH 0894/2474] disable vote menu when vote_style > 0; reset voter health upon reset --- ssqc/client.qc | 4 ++-- ssqc/qw.qc | 1 + ssqc/vote.qc | 15 ++++++++------- ssqc/world.qc | 3 ++- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 0f3ae4ae..c25e5e3d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -962,7 +962,7 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_z); local string nextmapstring = vote_result; - local float vote_style = CF_GetSetting("vs", "vote_style", "2"); + vote_style = CF_GetSetting("vs", "vote_style", "2"); if (vote_style || votemode == 2){ if(votemode == 1 && vote_result) { localcmd ("localinfo votemode off\n"); @@ -1869,7 +1869,7 @@ void () NextLevel = { return; already_cycled = 1; - local float vote_style = CF_GetSetting("vs", "vote_style", "2"); + vote_style = CF_GetSetting("vs", "vote_style", "1"); if (vote_style || votemode == 2){ if(votemode == 1 && nextmap) { localcmd ("localinfo votemode off\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 715444be..bf35eae8 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -459,6 +459,7 @@ float voting_expires; .entity vote_map; float vote_anarchy_mode; float vote_total_votes; +float vote_style; .float tf_id; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 876cf870..ae706b11 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -45,7 +45,7 @@ void (entity ent) TeamFortress_SetSpeed; void (entity pe_player) Vote_NextMap = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle) + if (clanbattle || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_next) @@ -86,7 +86,7 @@ void (entity pe_player) Vote_NextMap = { void (entity pe_player) Vote_TrickMap = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle) + if (clanbattle || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_trick) @@ -127,7 +127,7 @@ void (entity pe_player) Vote_TrickMap = { void (entity pe_player) Vote_RaceMap = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle) + if (clanbattle || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_race) @@ -167,7 +167,7 @@ void (entity pe_player) Vote_RaceMap = { // called from weapons.qc:ImpulseCommands() void (entity pe_player) Vote_ToggleMenu = { - if (clanbattle) + if (clanbattle || vote_style) return; if (vote_started > 0 && !vote_abort) { @@ -239,7 +239,7 @@ float () Vote_GetRaceVotes = { void (entity pe_player) Vote_ForceNext = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle) + if (clanbattle || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass) @@ -290,7 +290,7 @@ float () Vote_GetForceNextVotes = { // called from world.qc:StartFrame() void () Vote_Check = { - if (clanbattle) + if (clanbattle || vote_style) return; local float closetime = timelimit - CF_MAPVOTE_FINISH; @@ -1208,6 +1208,7 @@ void () EndVoting = { //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; W_SetCurrentAmmo(e); TeamFortress_SetSpeed(e); + e.health = 100; e = find(e, classname, "player"); } e = find(world, classname, "map_candidate"); @@ -1393,7 +1394,7 @@ void (entity p) UnvoteForMap = { }; void (entity p) VoteToEndMap = { - if(CF_GetSetting("vs", "vote_style", "0")) { + if(CF_GetSetting("vs", "vote_style", "1")) { if(p.vote_next) { bprint(PRINT_HIGH, p.netname, " desides to keep playing.\n"); } else { diff --git a/ssqc/world.qc b/ssqc/world.qc index 27cc8817..33913af8 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -335,7 +335,8 @@ void () worldspawn = { worldspawnent.think = WorldSpawnPost; worldspawnent.nextthink = time + .01; votemode = CF_GetSetting("vm", "votemode", "off"); - vote_total_votes = 0; + vote_total_votes = 0; + vote_style = CF_GetSetting("vs", "vote_style", "1"); if(votemode) { //No map candidates in map! Add some defaults... From de4baf6855ca460204118ab67921fea40ce61309 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 16 Jan 2020 16:37:31 +1100 Subject: [PATCH 0895/2474] set team to fix r_enemyskincolor cheat in clients --- ssqc/spy.qc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index adb6cb05..56351794 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -706,7 +706,7 @@ void () CF_Spy_DisguiseLast = { void (entity own) Spy_SetClientSkins = { entity te; - string color, dcolor, skin, dskin, sendcolor, sendskin; + string color, dcolor, skin, dskin, sendcolor, sendskin, pteam, dsteam, sendteam; float dteam, dpc; dteam = own.undercover_team == 0 ? own.team_no : own.undercover_team; @@ -717,6 +717,9 @@ void (entity own) Spy_SetClientSkins = { skin = TeamFortress_GetSkin(own.team_no, own.playerclass); dskin = TeamFortress_GetSkin(dteam, dpc); + pteam = infokey(world, strcat("team", ftos(own.team_no))); + dsteam = infokey(world, strcat("team", ftos(dteam))); + te = find(world, classname, "player"); while (te) { @@ -727,11 +730,13 @@ void (entity own) Spy_SetClientSkins = { // on same team, send them spy/team (initial spawn etc) sendcolor = color; sendskin = skin; + sendteam = pteam; } else // not on same team, send them disguise { sendcolor = dcolor; sendskin = dskin; + sendteam = dsteam; } msg_entity = te; @@ -753,6 +758,12 @@ void (entity own) Spy_SetClientSkins = { WriteByte(MSG_ONE, own.colormap-1); WriteString(MSG_ONE, "bottomcolor"); WriteString(MSG_ONE, sendcolor); + + // set team to fix r_enemyskincolor cheat in clients + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, own.colormap-1); + WriteString(MSG_ONE, "team"); + WriteString(MSG_ONE, sendteam); } te = find(te, classname, "player"); From 1d8d483d428923c294257baf51b6e64fce70a8b5 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Thu, 16 Jan 2020 17:00:13 +1100 Subject: [PATCH 0896/2474] small half done bit value update --- share/defs.h | 10 +++++++++ ssqc/camera.qc | 6 +++--- ssqc/client.qc | 4 ++-- ssqc/combat.qc | 10 ++++----- ssqc/items.qc | 58 +++++++++++++++++++++++++------------------------- ssqc/spy.qc | 10 ++++----- ssqc/tfort.qc | 2 +- 7 files changed, 55 insertions(+), 45 deletions(-) diff --git a/share/defs.h b/share/defs.h index 32de5585..b89a23c1 100644 --- a/share/defs.h +++ b/share/defs.h @@ -268,6 +268,16 @@ #define CF_MAPVOTE_DURATION 180 // Seconds to show map vote menu #define CF_MAPVOTE_DURATION_DECIDER 90 // Seconds to show map decider menu +// team play vals +#define TP_HALFDIRECT 128 +#define TP_NODIRECT 256 +#define TP_HALFAOE 512 +#define TP_NOAOE 1024 +#define TP_HALFMIRRORDIRECT 2048 +#define TP_FULLMIRRORDIRECT 4096 +#define TP_HALFMIRRORAOE 8192 +#define TP_FULLMIRRORAOE 16384 + /*======================================================*/ /* Toggleable Game Settings */ /*======================================================*/ diff --git a/ssqc/camera.qc b/ssqc/camera.qc index 12756e2e..5540fd6e 100644 --- a/ssqc/camera.qc +++ b/ssqc/camera.qc @@ -22,12 +22,12 @@ void () CamLock = { }; void () CamDistLock = { - if (self.tfstate & 4096) { + if (self.tfstate & TFSTATE_LOCK) { sprint(self, PRINT_HIGH, "Distance lock off\n"); - self.tfstate = self.tfstate - (self.tfstate & 4096); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); } else { sprint(self, PRINT_HIGH, "Distance lock on\n"); - self.tfstate = self.tfstate | 4096; + self.tfstate = self.tfstate | TFSTATE_LOCK; if (self.enemy) { self.camdist = vlen((self.enemy.origin - self.origin)); } diff --git a/ssqc/client.qc b/ssqc/client.qc index c25e5e3d..7f85e98d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2262,7 +2262,7 @@ void () CheckPowerups = { } } if (self.invisible_finished < time) { - self.items = self.items - 524288; + self.items = self.items - IT_INVISIBILITY; self.invisible_finished = 0; self.invisible_time = 0; } @@ -2336,7 +2336,7 @@ void () CheckPowerups = { } } if (self.super_damage_finished < time) { - self.items = self.items - 4194304; + self.items = self.items - IT_QUAD; self.super_damage_finished = 0; self.super_time = 0; } diff --git a/ssqc/combat.qc b/ssqc/combat.qc index c272ee3c..c8c48b02 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -468,7 +468,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, } if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && - !(targ.tfstate & 65536)) { + !(targ.tfstate & TFSTATE_CANT_MOVE)) { if (deathmsg != DMSG_GREN_NAIL) { @@ -568,17 +568,17 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (T_AttackType & TF_TD_EXPLOSION) { deathmsg = DMSG_TEAMKILL; - if (teamplay & 16384) + if (teamplay & TP_FULLMIRRORAOE) TF_T_Damage(attacker, world, world, take, 1, 0); - else if (teamplay & 8192) + else if (teamplay & TP_HALFMIRRORAOE) TF_T_Damage(attacker, world, world, take / 2, 1, 0); } else { deathmsg = DMSG_TEAMKILL; - if (teamplay & 4096) + if (teamplay & TP_FULLMIRRORDIRECT) TF_T_Damage(attacker, world, world, take, 1, 0); - else if (teamplay & 2048) + else if (teamplay & TP_HALFMIRRORDIRECT) TF_T_Damage(attacker, world, world, take / 2, 1, 0); } deathmsg = olddmsg; diff --git a/ssqc/items.qc b/ssqc/items.qc index c0a2b98f..348f007e 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -223,7 +223,7 @@ void () health_touch = { if (other.is_feigning) { return; } - if ((other.tfstate & 65536) || (other.tfstate & 2048)) { + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) { return; } if (cb_prematch == 1) { @@ -329,7 +329,7 @@ void () armor_touch = { if (other.is_feigning) { return; } - if ((other.tfstate & 65536) || (other.tfstate & 2048)) { + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) { return; } if (cb_prematch == 1) { @@ -338,16 +338,16 @@ void () armor_touch = { if (self.classname == "item_armor1") { type = 0.300; value = 100; - bit = 8192; + bit = IT_ARMOR1; } else { if (self.classname == "item_armor2") { type = 0.600; value = 150; - bit = 16384; + bit = IT_ARMOR2; } else { type = 0.800; value = 200; - bit = 32768; + bit = IT_ARMOR3; } } if ((other.armortype * other.armorvalue) >= (type * value)) { @@ -407,7 +407,7 @@ void () armor_touch = { other.armortype = type; other.armorvalue = value; other.items = - (other.items - (other.items & ((8192 | 16384) | 32768))) + bit; + (other.items - (other.items & ((IT_ARMOR1 | IT_ARMOR2) | IT_ARMOR3))) + bit; } if (self.armorclass > 0) { other.armorclass = self.armorclass; @@ -548,7 +548,7 @@ void () weapon_touch = { return; if (other.is_feigning) return; - if ((other.tfstate & 65536) || (other.tfstate & 2048)) + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; if (cb_prematch == 1) return; @@ -563,69 +563,69 @@ void () weapon_touch = { leave = 0; } if (self.classname == "weapon_nailgun") { - if (leave && (other.weapons_carried & 512)) { + if (leave && (other.weapons_carried & WEAP_NAILGUN)) { return; } - if (!TeamFortress_CanGetWeapon(other, 512)) { + if (!TeamFortress_CanGetWeapon(other, WEAP_NAILGUN)) { return; } hadammo = other.ammo_nails; - new = 512; + new = WEAP_NAILGUN; other.ammo_nails = other.ammo_nails + 30; } else { if (self.classname == "weapon_supernailgun") { - if (leave && (other.weapons_carried & 1024)) { + if (leave && (other.weapons_carried & WEAP_SUPER_NAILGUN)) { return; } - if (!TeamFortress_CanGetWeapon(other, 1024)) { + if (!TeamFortress_CanGetWeapon(other, WEAP_SUPER_NAILGUN)) { return; } hadammo = other.ammo_rockets; - new = 1024; + new = WEAP_SUPER_NAILGUN; other.ammo_nails = other.ammo_nails + 30; } else { if (self.classname == "weapon_supershotgun") { - if (leave && (other.weapons_carried & 256)) { + if (leave && (other.weapons_carried & WEAP_SUPER_SHOTGUN)) { return; } - if (!TeamFortress_CanGetWeapon(other, 256)) { + if (!TeamFortress_CanGetWeapon(other, WEAP_SUPER_SHOTGUN)) { return; } hadammo = other.ammo_rockets; - new = 256; + new = WEAP_SUPER_SHOTGUN; other.ammo_shells = other.ammo_shells + 5; } else { if (self.classname == "weapon_rocketlauncher") { - if (leave && (other.weapons_carried & 8192)) { + if (leave && (other.weapons_carried & WEAP_ROCKET_LAUNCHER)) { return; } - if (!TeamFortress_CanGetWeapon(other, 8192)) { + if (!TeamFortress_CanGetWeapon(other, WEAP_ROCKET_LAUNCHER)) { return; } hadammo = other.ammo_rockets; - new = 8192; + new = WEAP_ROCKET_LAUNCHER; other.ammo_rockets = other.ammo_rockets + 5; } else { if (self.classname == "weapon_grenadelauncher") { - if (leave && (other.weapons_carried & 2048)) { + if (leave && (other.weapons_carried & WEAP_GRENADE_LAUNCHER)) { return; } - if (!TeamFortress_CanGetWeapon(other, 2048)) { + if (!TeamFortress_CanGetWeapon(other, WEAP_GRENADE_LAUNCHER)) { return; } hadammo = other.ammo_rockets; - new = 2048; + new = WEAP_GRENADE_LAUNCHER; other.ammo_rockets = other.ammo_rockets + 5; } else { if (self.classname == "weapon_lightning") { - if (leave && (other.weapons_carried & 65536)) { + if (leave && (other.weapons_carried & WEAP_LIGHTNING)) { return; } - if (!TeamFortress_CanGetWeapon(other, 65536)) { + if (!TeamFortress_CanGetWeapon(other, WEAP_LIGHTNING)) { return; } hadammo = other.ammo_rockets; - new = 65536; + new = WEAP_LIGHTNING; other.ammo_cells = other.ammo_cells + 15; } else { objerror("weapon_touch: unknown classname"); @@ -818,7 +818,7 @@ void () ammo_touch = { if (other.health <= 0) { return; } - if ((other.tfstate & 65536) || (other.tfstate & 2048)) { + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) { return; } if (cb_prematch == 1) { @@ -1025,7 +1025,7 @@ void () key_touch = { if (other.is_feigning) { return; } - if ((other.tfstate & 65536) || (other.tfstate & 2048)) { + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) { return; } if (cb_prematch == 1) { @@ -1126,7 +1126,7 @@ void () sigil_touch = { return; if (other.is_feigning) return; - if ((other.tfstate & 65536) || (other.tfstate & 2048)) + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; if (cb_prematch == 1) return; @@ -1179,7 +1179,7 @@ void () powerup_touch = { return; if (other.is_feigning) return; - if ((other.tfstate & 65536) || (other.tfstate & 2048)) + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; if (cb_prematch == 1) return; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 56351794..d84668d2 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1062,7 +1062,7 @@ void () GasGrenadeMakeGas = { (te.has_disconnected != 1)) { deathmsg = 24; TF_T_Damage(te, world, self.owner, 10, (1 | 2), 0); - if (te.tfstate & 16384) { + if (te.tfstate & TFSTATE_HALLUCINATING) { timer = find(world, classname, "timer"); while (((timer.owner != te) || (timer.think != HallucinationTimer)) && @@ -1151,13 +1151,13 @@ void () HallucinationTimer = { if (((self.health <= 0) || (self.owner.deadflag != 0)) || (self.owner.has_disconnected == 1)) { self.owner.tfstate = - self.owner.tfstate - (self.owner.tfstate & 16384); + self.owner.tfstate - (self.owner.tfstate & TFSTATE_HALLUCINATING); } if ((self.owner.deadflag != 0) || (self.owner.has_disconnected == 1)) { dremove(self); return; } - if (!(self.owner.tfstate & 16384)) { + if (!(self.owner.tfstate & TFSTATE_HALLUCINATING)) { if (old_grens == 1) stuffcmd(self.owner, "v_cshift; wait; bf\n"); sprint(self.owner, 2, "You feel a little better now\n"); @@ -1417,10 +1417,10 @@ void (entity spy) Spy_RemoveDisguise = { coverblown = 1; spy.is_undercover = 0; spy.modelindex = modelindex_player; - if (spy.items & 524288) { + if (spy.items & IT_INVISIBILITY) { spy.invisible_finished = 0; spy.invisible_time = 0; - spy.items = spy.items - 524288; + spy.items = spy.items - IT_INVISIBILITY; } Status_Refresh(self); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 691d1e8b..514f440e 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2586,7 +2586,7 @@ void () TeamFortress_AmmoboxTouch = { took = 0; if ((other == self.enemy) && (time < (self.health + 2))) return; - if ((other.tfstate & 65536) || (other.tfstate & 2048)) + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; if (other.classname != "player") return; From 0b309389a9b2a28fe884ea11a3ebe877df0cb17c Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 16 Jan 2020 21:31:48 +1100 Subject: [PATCH 0897/2474] fix for spy cheat in ezquake --- ssqc/spy.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 56351794..af57ecb5 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -717,8 +717,8 @@ void (entity own) Spy_SetClientSkins = { skin = TeamFortress_GetSkin(own.team_no, own.playerclass); dskin = TeamFortress_GetSkin(dteam, dpc); - pteam = infokey(world, strcat("team", ftos(own.team_no))); - dsteam = infokey(world, strcat("team", ftos(dteam))); + pteam = GetTeamName(own.team_no); + dsteam = GetTeamName(dteam); te = find(world, classname, "player"); while (te) From 30d05ed893b929dc25b2f9ef45aea084bc64ecb6 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 16 Jan 2020 22:06:45 +1100 Subject: [PATCH 0898/2474] fix hitsound playing at wrong time for spies --- ssqc/combat.qc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index c272ee3c..13e5ce6a 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -182,9 +182,6 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { if ((inflictor.weapon == DMSG_INCENDIARY) && (damage >= 40)) { crit = 1; } - - local float sameteam; - sameteam = 0; if (targ.playerclass == PC_SPY) { @@ -192,17 +189,12 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { { return; } - if (targ.undercover_team == attacker.team_no) - { - sameteam = 1; - } - } - else if (attacker.team_no == targ.team_no) - { - sameteam = 1; } + + float targteam; + targteam = (targ.undercover_team == 0) ? targ.team_no : targ.undercover_team; - if (sameteam == 0) { + if (targteam != attacker.team_no) { if (crit == 1){ stuffcmd(trueattacker, "play misc/hitsoundcrit.wav\n"); //sounds precached in weapons.qc } From 246e572067b66fc48141f80737679a199d48e829 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 18 Jan 2020 12:58:15 +1100 Subject: [PATCH 0899/2474] start of spy icon addition --- ssqc/spy.qc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index af57ecb5..ddeacd00 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -705,6 +705,23 @@ void () CF_Spy_DisguiseLast = { }; void (entity own) Spy_SetClientSkins = { + entity icon, ownicon; + icon = find(world, classname, "spyicon"); + while (icon) + { + if (icon.owner == own) + ownicon = icon; + icon = find(icon, classname, "spyicon"); + } + + if (!ownicon) + { + ownicon = spawn(); + ownicon.owner = own; + ownicon.classname = "spyicon"; + ownicon.movetype = MOVETYPE_FOLLOW; + } + entity te; string color, dcolor, skin, dskin, sendcolor, sendskin, pteam, dsteam, sendteam; float dteam, dpc; From 4fb937125f35b8f0e2e104f9fdf9c62036033a83 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 18 Jan 2020 13:48:58 +1100 Subject: [PATCH 0900/2474] fix players going invisible on new player connecting --- ssqc/client.qc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 7f85e98d..7c0fdb3a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1745,6 +1745,15 @@ void () PutClientInServer = { } } + setmodel(self, string_null); + modelindex_null = self.modelindex; + + setmodel(self, "progs/eyes.mdl"); + modelindex_eyes = self.modelindex; + + setmodel(self, "progs/player.mdl"); + modelindex_player = self.modelindex; + if (self.playerclass == 0) { self.modelindex = modelindex_null; self.menu_input = nil; From ae6455acda2c88925c6d19e53c982968392fb01e Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 19 Jan 2020 08:34:35 +1300 Subject: [PATCH 0901/2474] team menu frame and autoteam fix --- csqc/menu.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index d990d502..ec497d8a 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -887,14 +887,14 @@ void FO_Menu_Team(float force) = { return; } //Hide autoteam option - FO_MENU_TEAM.num_opts = number_of_teams; + //FO_MENU_TEAM.num_opts = number_of_teams; //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_HIDDEN; - //FO_MENU_TEAM.options[5].state = FO_MENU_STATE_HIDDEN; + FO_MENU_TEAM.options[5].state = FO_MENU_STATE_DISABLED; } else { //Show autoteam option - FO_MENU_TEAM.num_opts = 8; + //FO_MENU_TEAM.num_opts = 8; //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_NORMAL; - //FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; + FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; } CurrentMenu = &FO_MENU_TEAM; fo_hud_menu_active = TRUE; From f329f2f5442ac2389353f96393d24dc11c52e837 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 27 Jan 2020 01:02:04 +1300 Subject: [PATCH 0902/2474] disallow shooting while detpacking --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 685d3cea..452248d3 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1937,7 +1937,7 @@ void () W_Attack = { if (self.has_disconnected == TRUE) return; - if (self.tfstate & TFSTATE_RELOADING) + if (self.tfstate & TFSTATE_RELOADING || self.is_detpacking) return; if(no_fire_mode) From d04f6b9cff161fb9c4905da5713f205503af75ca Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 28 Jan 2020 10:57:19 +1300 Subject: [PATCH 0903/2474] fix found nail/shock gren message --- ssqc/items.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ssqc/items.qc b/ssqc/items.qc index 348f007e..aae2dea2 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -744,7 +744,11 @@ void (entity pl, float typ) PrintGrenadeType = { } else if (typ == 2) { st = "concussion"; } else if (typ == 3) { - st = "nail"; + if (nailgren_type == NGR_TYPE_LASER) { + st = "shock"; + } else { + st = "nail"; + } } else if (typ == 4) { st = "mirv"; } else if (typ == 5) { From 1c58c76f18efc56a7b91d69a95cb386aa0a105ec Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 8 Feb 2020 12:20:05 +1300 Subject: [PATCH 0904/2474] fo_grentimer updates --- csqc/csextradefs.qc | 1 + csqc/events.qc | 3 +++ csqc/main.qc | 45 +++++++++++++++++++++++++++++---------------- ssqc/status.qc | 2 +- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 20eda7af..8173c86f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -51,6 +51,7 @@ float quad_round; float quad_rounds_total; float showingscores; float mapvote_expiry; +float grentimer_waiting; //grenade primed, but not thrown float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index 588fc73d..f9316144 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -353,4 +353,7 @@ void ParseSBAR() } break; } + if(!readfloat()) { + grentimer_waiting = FALSE; + } } diff --git a/csqc/main.qc b/csqc/main.qc index d3b001d9..265b3704 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -42,6 +42,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; is_admin = FALSE; + grentimer_waiting = FALSE; }; noref void() CSQC_WorldLoaded = { @@ -123,31 +124,43 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Vote(TRUE); break; case "primeone": - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(1); - } + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(1); + } + grentimer_waiting = TRUE; + } localcmd("primeone_server"); break; case "primetwo": - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(2); - } + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(2); + } + grentimer_waiting = TRUE; + } localcmd("primetwo_server"); break; case "gren1": - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(1); - } + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(1); + } + grentimer_waiting = TRUE; + } localcmd("gren1_server"); break; case "gren2": - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(2); - } + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(2); + } + grentimer_waiting = TRUE; + } localcmd("gren2_server"); break; case "+showscores": diff --git a/ssqc/status.qc b/ssqc/status.qc index fa4a98fa..6241e209 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -934,7 +934,7 @@ void UpdateClientStatusBar(entity pl) } break; } - + WriteFloat(MSG_MULTICAST, ((te.tfstate & TFSTATE_GRENPRIMED) == TFSTATE_GRENPRIMED)); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } From d0cf2b656fd0892c2266319592c4ecf6e8360720 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 9 Feb 2020 22:56:00 +1300 Subject: [PATCH 0905/2474] instant class menu and spy menu --- csqc/events.qc | 2 +- csqc/main.qc | 4 ++ csqc/menu.qc | 103 +++++++++++++++++++++++++++++++++++-------------- 3 files changed, 79 insertions(+), 30 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index f9316144..7c049f67 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -147,7 +147,7 @@ void() CSQC_Parse_Event = { FO_Menu_Spy(FALSE); break; case CLIENT_MENU_SPY_SKIN: - FO_Menu_Spy_Skin(FALSE); + FO_Menu_Spy_Skin(2); break; case CLIENT_MENU_SPY_TEAM: FO_Menu_Spy_Team(FALSE); diff --git a/csqc/main.qc b/csqc/main.qc index 265b3704..4ba8f665 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -29,6 +29,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_main_menu"); registercommand("fo_menu_admin"); registercommand("fo_menu_vote"); + registercommand("fo_menu_special"); registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("primeone"); @@ -123,6 +124,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_vote": FO_Menu_Vote(TRUE); break; + case "fo_menu_special": + FO_Menu_Special(TRUE); + break; case "primeone": if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { diff --git a/csqc/menu.qc b/csqc/menu.qc index 2c6345ae..f9eae128 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -3,6 +3,7 @@ #define FO_MENU_FLAG_SHOW_SHORTCUTS 4 #define FO_MENU_FLAG_SHOW_VALUES 8 #define FO_MENU_FLAG_WARNING 16 +#define FO_MENU_FLAG_ALLOW_INTERMISSION 32 #define FO_MENU_STATE_HIDDEN 0 #define FO_MENU_STATE_NORMAL 1 @@ -21,6 +22,8 @@ void (float force) FO_Menu_Admin_Rounds; void (float force) FO_Menu_Admin_Timelimit; void (float force) FO_Menu_Admin_Fraglimit; void (float force) FO_Menu_Admin_QuadTimelimit; +void (float force) FO_Menu_Spy_Skin; +void (float force) FO_Menu_Spy_Team; void FO_Menu_Admin_Players(float force, float type, float page); typedef struct { @@ -77,7 +80,7 @@ fo_menu* CurrentMenu; fo_menu_option MenuSpacer = {"","","","",FO_MENU_STATE_SPACER}; var fo_menu FO_MENU_GAME = { - [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Select Team", "","Join a team",FO_MENU_STATE_NORMAL,{FO_Menu_Team(TRUE); },MENU_BUTTON}, {"2","Select Class","","Each class has unique strenghts and weaknesses.",FO_MENU_STATE_NORMAL,{localcmd("changeclass\n"); Menu_Cancel(); },MENU_BUTTON}, {"3","Ready","","Only applies to organised games",FO_MENU_STATE_NORMAL,{localcmd("ready\n"); Menu_Cancel();},MENU_BUTTON}, @@ -90,7 +93,7 @@ var fo_menu FO_MENU_GAME = { }, 9, TRUE }; var fo_menu FO_MENU_GAME_SPECTATOR = { - [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { + [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, MenuSpacer, {"3","Server Admin", "","",FO_MENU_STATE_DISABLED,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, @@ -124,14 +127,14 @@ var fo_menu FO_MENU_CLASS = { [0,0], [300,200], "Select Class", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { {"1","Scout","","Fastest but weakest. Has a scanner (menu) and a `dash` (special)",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 1\n");Menu_Cancel();},MENU_BUTTON}, {"2","Sniper","","Long charge times but powerful hits.",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 2\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Soldier","","All-rounder. Has a rocket launcher",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 3\n");Menu_Cancel();},MENU_BUTTON}, - {"4","Demoman","","'special' to detonate pipebombs. 'menu' for detpack",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 4\n");Menu_Cancel();},MENU_BUTTON}, - {"5","Medic","","Fast and immune to concussions and disease. \nBioweapon can heal/supercharge teammates and infect enemies\n'special' allows automatically healing nearby teammates",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 5\n");Menu_Cancel();},MENU_BUTTON}, - {"6","Heavy Weapons","","Toughest of the classes. 'special' allows spinning the cannon without firing",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 6\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Soldier","","All-rounder. Has a rocket launcher.",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 3\n");Menu_Cancel();},MENU_BUTTON}, + {"4","Demoman","","Area-denial expert. 'special' to detonate pipebombs. 'menu' for detpack.",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 4\n");Menu_Cancel();},MENU_BUTTON}, + {"5","Medic","","Fast and immune to concussions and disease. \nBioweapon can heal/supercharge teammates and infect enemies\n'special' allows to automatically heal nearby teammates",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 5\n");Menu_Cancel();},MENU_BUTTON}, + {"6","Heavy Weapons","","Toughest of the classes. 'special' allows spinning the cannon without firing.",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 6\n");Menu_Cancel();},MENU_BUTTON}, {"7","Pyro","","Can still pull off smaller rjs. ",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 7\n");Menu_Cancel();},MENU_BUTTON}, {"8","Spy","","Can disguise as the enemy and feign death",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 8\n");Menu_Cancel();},MENU_BUTTON}, {"9","Engineer","","Can build sentry guns and ammo dispensers. Also has powerful EMP grenades as secondaries",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 9\n");Menu_Cancel();},MENU_BUTTON}, - {"0","Random Playerclass","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 10\n");Menu_Cancel();},MENU_BUTTON}, + {"0","Random Playerclass","","Class will be randomly chosen upon each spawn.",FO_MENU_STATE_NORMAL,{localcmd("cmd changeclass 10\n");Menu_Cancel();},MENU_BUTTON}, }, 10, TRUE, { if(intermission) { Menu_Cancel(); @@ -161,7 +164,7 @@ var fo_menu FO_MENU_SCOUT = { //var fo_menu_option FO_MENU_SPY; var fo_menu FO_MENU_SPY = { [0,0], [300,150], "Spy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { - {"1","Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Disguise","","",FO_MENU_STATE_NORMAL,{FO_Menu_Spy_Skin(TRUE);localcmd("cmd disguise\n");},MENU_BUTTON}, {"1","Invisibility","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise\n");Menu_Cancel();},MENU_BUTTON}, {"2","Last Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise last\n");Menu_Cancel();},MENU_BUTTON}, {"3","Feign","","",FO_MENU_STATE_NORMAL,{localcmd("feign\n");Menu_Cancel();},MENU_BUTTON}, @@ -176,19 +179,30 @@ var fo_menu FO_MENU_SPY = { },MENU_BUTTON}, }, 9, TRUE }; + +void sendDisguiseCommand(float skinno) = { + localcmd("cmd disguise skin ",ftos(skinno),"\n"); + local float smt = !stof(getplayerkeyvalue(player_localnum, "smt")); + if (smt) { + FO_Menu_Spy_Team(TRUE); + } else { + Menu_Cancel(); + } +}; + var fo_menu FO_MENU_SPY_SKIN = { [0,0], [300,200], "Disguise as enemy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { - {"1","Scout","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 1\n");Menu_Cancel();},MENU_BUTTON}, - {"2","Sniper","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 2\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Soldier","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 3\n");Menu_Cancel();},MENU_BUTTON}, - {"4","Demoman","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 4\n");Menu_Cancel();},MENU_BUTTON}, - {"5","Medic","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 5\n");Menu_Cancel();},MENU_BUTTON}, - {"6","Heavy Weapons","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 6\n");Menu_Cancel();},MENU_BUTTON}, - {"7","Pyro","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 7\n");Menu_Cancel();},MENU_BUTTON}, - {"8","Spy","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 8\n");Menu_Cancel();},MENU_BUTTON}, - {"9","Engineer","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 9\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Scout","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(1);},MENU_BUTTON}, + {"2","Sniper","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(2);},MENU_BUTTON}, + {"3","Soldier","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(3);},MENU_BUTTON}, + {"4","Demoman","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(4);},MENU_BUTTON}, + {"5","Medic","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(5);},MENU_BUTTON}, + {"6","Heavy Weapons","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(6);},MENU_BUTTON}, + {"7","Pyro","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(7);},MENU_BUTTON}, + {"8","Spy","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(8);},MENU_BUTTON}, + {"9","Engineer","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(9);},MENU_BUTTON}, {"0","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - {"-","Civilian","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise skin 11\n");Menu_Cancel();},MENU_BUTTON}, + {"-","Civilian","","",FO_MENU_STATE_NORMAL,{sendDisguiseCommand(11);},MENU_BUTTON}, }, 11, TRUE }; var fo_menu FO_MENU_SPY_TEAM = { @@ -354,7 +368,7 @@ void updateAdminMenuInfo() = { } var fo_menu FO_MENU_ADMIN_MAIN = { - [0,0], [300,300], "Server Admin [1/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,300], "Server Admin [1/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Ceasefire","","Pause the game",FO_MENU_STATE_NORMAL,{localcmd("cmd ceasefire\n");},MENU_BORDER_WARNING}, {"2","Kick...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_KICK, 0);},MENU_BORDER_WARNING}, {"3","Ban...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_BAN, 0);},MENU_BORDER_WARNING}, @@ -390,7 +404,7 @@ string (float m) modeStatus = { } var fo_menu FO_MENU_ADMIN_MODES = { - [0,0], [300,300], "Server Modes [2/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,300], "Server Modes [2/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Pub Mode","","Public play, anything goes",FO_MENU_STATE_NORMAL,{localcmd("cmd pubmode\n");},MENU_BORDER_WARNING}, {"2","Clan Mode","","Game has a prematch",FO_MENU_STATE_NORMAL,{localcmd("cmd clanmode\n");},MENU_BORDER_WARNING}, {"3","Quad Mode","","Play for a set number of rounds, designed for attack vs defence",FO_MENU_STATE_NORMAL,{localcmd("cmd quadmode\n");},MENU_BORDER_WARNING}, @@ -416,7 +430,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { } }; var fo_menu FO_MENU_ADMIN_SETTINGS = { - [0,0], [300,300], "Settings [3/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,300], "Settings [3/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Timelimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Timelimit(TRUE);},MENU_BORDER_WARNING}, {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Fraglimit(TRUE);},MENU_BORDER_WARNING}, // {"3","Override Classes","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, @@ -476,7 +490,7 @@ void execute_admin_players_captain_pick(float choice, float page) { } var fo_menu FO_MENU_ADMIN_PLAYERS = { - [0,0], [300,300], "Players", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,300], "Players", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(0, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, {"2","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(1, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, {"3","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(2, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, @@ -546,7 +560,7 @@ void action_admin_players_captain_pick() = { action_admin_players(CLIENT_MENU_CAPTAIN_PICK); } var fo_menu FO_MENU_ADMIN_ROUNDS = { - [0,0], [300,300], "Quad Rounds", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,300], "Quad Rounds", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","1","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, {"2","2","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 2\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, {"3","3","","",FO_MENU_STATE_NORMAL,{localcmd("cmd rounds 3\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, @@ -561,7 +575,7 @@ var fo_menu FO_MENU_ADMIN_ROUNDS = { }, 11, TRUE }; var fo_menu FO_MENU_ADMIN_QUAD_TIMELIMIT = { - [0,0], [300,200], "Quad Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,200], "Quad Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","1","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, {"2","5","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 5\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, {"3","10","","",FO_MENU_STATE_NORMAL,{localcmd("cmd roundtime 10\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, @@ -576,7 +590,7 @@ var fo_menu FO_MENU_ADMIN_QUAD_TIMELIMIT = { }, 11, TRUE }; var fo_menu FO_MENU_ADMIN_TIMELIMIT = { - [0,0], [300,200], "Set Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,200], "Set Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","0 (infinite)","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 0\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"2","5","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 5\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"3","10","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 10\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, @@ -591,7 +605,7 @@ var fo_menu FO_MENU_ADMIN_TIMELIMIT = { }, 11, TRUE }; var fo_menu FO_MENU_ADMIN_FRAGLIMIT = { - [0,0], [300,200], "Set Fraglimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING, { + [0,0], [300,200], "Set Fraglimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","0 (infinite)","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 0\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"2","5","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 5\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"3","10","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 10\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, @@ -665,7 +679,7 @@ vector fo_menu_draw(fo_menu * menu) = { if(fo_hud_editor) return position; - if(!menu.active || showingscores || (intermission && !(menu.flags & FO_MENU_FLAG_USE_MOUSE))) { + if(!menu.active || showingscores || (intermission && !(menu.flags & FO_MENU_FLAG_ALLOW_INTERMISSION))) { setcursormode(FALSE); return position; } @@ -1028,11 +1042,11 @@ void FO_Menu_Spy_Team(float force) = { } void FO_Menu_Spy_Skin(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY_SKIN) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY_SKIN && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) return; CurrentMenu = &FO_MENU_SPY_SKIN; fo_hud_menu_active = TRUE; @@ -1195,3 +1209,34 @@ void FO_Menu_Vote(float force) = { CurrentMenu = &FO_MENU_VOTE; fo_hud_menu_active = TRUE; } + +void FO_Menu_Special(float force) = { + if(fo_hud_menu_active && force != 1) + return; + + fo_menu* NewMenu; + switch (SBAR.PlayerClass) { + case PC_SCOUT: + NewMenu = &FO_MENU_SCOUT; + break; + case PC_DEMOMAN: + NewMenu = &FO_MENU_DETPACK; + break; + case PC_SPY: + NewMenu = &FO_MENU_SPY; + break; + case PC_ENGINEER: + NewMenu = &FO_MENU_BUILD; + break; + default: + //no class menu + return; + } + + if(fo_hud_menu_active && CurrentMenu == NewMenu && force != 2) { + Menu_Cancel(); + return; + } + CurrentMenu = NewMenu; + fo_hud_menu_active = TRUE; +}; From ac7cee8532e5240e357be508f934033875f92df0 Mon Sep 17 00:00:00 2001 From: fdittz Date: Mon, 17 Feb 2020 19:24:19 -0300 Subject: [PATCH 0906/2474] porting events and login system from HueTF --- ssqc/clan.qc | 146 +++++++++++++++++++++++++++++++++++++++------- ssqc/client.qc | 26 ++++++++- ssqc/combat.qc | 10 +++- ssqc/commands.qc | 13 ++++- ssqc/demoman.qc | 1 + ssqc/functions.qc | 36 ++++++++++++ ssqc/progs.src | 1 + ssqc/pyro.qc | 1 + ssqc/quadmode.qc | 6 +- ssqc/qw.qc | 17 ++++++ ssqc/scout.qc | 1 + ssqc/status.qc | 4 ++ ssqc/tfort.qc | 26 +++++++++ ssqc/tfortmap.qc | 6 ++ ssqc/weapons.qc | 24 ++++++++ 15 files changed, 292 insertions(+), 26 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 6bb21ecc..5820be5d 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -52,6 +52,7 @@ void () MatchThink = } bprint(2, " remaining\n"); } + gametime++; self.nextthink = (time + 1); }; @@ -65,8 +66,7 @@ void () StartMatch = local entity gren; lightstyle(0, "m"); - bprint(2, "MATCH BEGINS NOW\n"); - + bprint(2, "MATCH BEGINS NOW\n"); team4score = 0; team3score = 0; team2score = 0; @@ -119,7 +119,7 @@ void () StartMatch = PutClientInServer(); if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { UpdateClientPrematch(self, TRUE); - } + } self = oldself; te = find(te, classname, "player"); } @@ -174,9 +174,107 @@ void () StartMatch = } }; +float () GetPlayerCount +{ + local entity te; + local float tmp = 0; + te = find (world, classname, "player"); + while (te != world) { + if (te.playerclass) { + tmp = tmp + 1; + } + te = find (te, classname, "player"); + } + return tmp; +} + +string () GetPlayersName +{ + local entity te; + local float tmp = 0; + local float tmp2 = 0; + local string st = ""; + local string plname; + + while (tmp < number_of_teams) { + tmp = tmp + 1; + tmp2 = 0; + te = find (world, classname, "player"); + while (te != world) { + if (te.team_no == tmp && te.playerclass) { + tmp2 = 1; + if (loginRequired) + plname = te.login; + else + plname = te.netname; + st = strcat (st, "_"); + if (strlen(plname) <= 13) { + st = strcat( st, plname ); + } else { + st = strcat( st, substr(plname,0,12)); + } + } + te = find (te, classname, "player"); + } + if (tmp2 == 1 && tmp != number_of_teams) { + st = strcat ( st, "_VS"); + } + } + return (st); +}; + +string () GetGameFileName = { + local float i; + local string tmp; + local entity t; + local string str; + + str = ""; + i = 0; + t = find (world, classname, "prematch"); + if (t != world) + { + calltimeofday (); + str = strcat(str, tod_year); // year + str = strcat(str, "-"); + str = strcat(str, tod_mon); // month + str = strcat(str, "-"); + str = strcat(str, tod_day); // day + str = strcat(str, "_"); + str = strcat(str, tod_hour); // hour + str = strcat(str, "-"); + str = strcat(str, tod_min); // minute + str = strcat(str, "-"); + str = strcat(str, tod_sec); // second + } + str = strcat(str, "_["); + str = strcat(str, mapname); + str = strcat(str, "]_"); + + if (GetPlayerCount() < 9) { + str = strcat(str, GetPlayersName()); + str = clearString(str); + return str; + } + + while ((i < number_of_teams)) + { + i = (i + 1); + tmp = GetTeamName (i); + str = strcat(str,"_"); + str = strcat(str,tmp); + if ((i < number_of_teams)) + { + str = strcat(str, "_vs"); + } + } + str = clearString(str); + return str; +} + void () PreMatch_Think = { local entity p; - local string num, tmp; + local string num, tmp, str; local float fl; self.cnt2 = (self.cnt2 - 1); @@ -199,6 +297,9 @@ void () PreMatch_Think = { is_countdown = 0; self.nextthink = (time + 0.1); self.think = SUB_Remove; + gametime = 0; + canlog = 1; + LogEventGameStart(); p = find(world, classname, "player"); while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { @@ -206,12 +307,15 @@ void () PreMatch_Think = { p.solid = 3; p.movetype = 3; } + p.classtime = gametime; + LogEventPlayerStart(p); p = find(p, classname, "player"); } if (!quadmode) StartMatch(); - else + else { StartQuadRound(); + } return; } } @@ -234,22 +338,15 @@ void () PreMatch_Think = { calltimeofday(); localcmd("record \""); - localcmd(tod_year); // year - localcmd("-"); - localcmd(tod_mon); // month - localcmd("-"); - localcmd(tod_day); // day - localcmd("_"); - localcmd(tod_hour); // hour - localcmd("-"); - localcmd(tod_min); // minute - localcmd("-"); - localcmd(tod_sec); // second - - localcmd("_["); - localcmd(mapname); - localcmd("]"); + str = strzone(GetGameFileName()); + localcmd(strzone(str)); localcmd("\"\n"); + + str = strcat(str,".json"); + str = strcat(str); + fclose(logfilehandle); + logfilehandle = fopen(str,FILE_WRITE); + strunzone(str); } } } @@ -365,6 +462,8 @@ void () StopTimer = if (infokey(world, "serverdemo") != string_null) { localcmd("cancel\n"); + if (logfilehandle > 0) + fclose(logfilehandle); } if (cb_prematch) { t = find(world, classname, "prematch"); @@ -723,6 +822,13 @@ void () DumpClanScores = { if (st != string_null) { stuffcmd(te, "screenshot\n"); } + + if (te.playerclass != 0) { + local float timeplayed = gametime - te.classtime; + LogEventChangeClass(te, te.playerclass, 0, timeplayed); + te.classtime = gametime; + } + te = find(te, classname, "player"); } }; diff --git a/ssqc/client.qc b/ssqc/client.qc index 7c0fdb3a..ca0b3131 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -632,6 +632,18 @@ void () DecodeLevelParms = { // After a duel round, print the winners' health stats round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); + // enforces login + loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); + + // login request https endpoint + loginUrl = infokey(world, "loginurl"); + + // server webpage address (required for login to work) + webpageUrl = infokey(world, "webpageurl"); + + if (loginRequired && (!loginUrl || !webpageUrl)) + loginRequired = 0; + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; @@ -910,7 +922,8 @@ void () IntermissionThink = { return; if ((!self.button0 && !self.button1) && !self.button2) return; - + if (logfilehandle > 0) + fclose(logfilehandle); dprint("Intermission think\n"); GotoNextMap(); }; @@ -993,6 +1006,7 @@ void () execute_changelevel = { } if (!clan_scores_dumped) { DumpClanScores(); + MapEndSequence(); clan_scores_dumped = 1; } }; @@ -1644,6 +1658,11 @@ void () PutClientInServer = { } if (deathmatch == 3) { if(self.nextpc != self.playerclass) { + if (self.playerclass != 0) { + local float timeplayed = gametime - self.classtime; + LogEventChangeClass(self, self.playerclass, self.nextpc, timeplayed); + self.classtime = gametime; + } self.playerclass = self.nextpc; } if (self.playerclass == PC_RANDOM) @@ -2586,6 +2605,11 @@ void () ClientDisconnect = { fr = rint(self.frags); st = ftos(fr); + + local float timeplayed = gametime - self.classtime; + LogEventChangeClass(self, self.playerclass, 0, timeplayed); + self.classtime = gametime; + bprint4(PRINT_HIGH, self.netname, " left the game with ", st, " frags\n"); sound(self, 4, "player/tornoff2.wav", 1, ATTN_NONE); diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 97f300f4..00ba3dcf 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -318,7 +318,11 @@ void (entity targ, entity inflictor, entity attacker, targ.armorclass = 0; targ.armorvalue = 0; } + if ((attacker.classname == "player" || targ.classname == "player") && (take + save > 0)) { + LogEventDamage(attacker, targ, inflictor, take + save); + } if (targ.health <= 0) { + LogEventKill(attacker, targ, inflictor); Killed(targ, attacker); return; } @@ -579,7 +583,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (no_damage == TRUE) return; - + if ((attacker.classname == "player" || targ.classname == "player") && (take + save > 0)) { + LogEventDamage(attacker, targ, inflictor, take + save); + } if (targ.armorvalue < 1) { targ.armorclass = 0; targ.armorvalue = 0; @@ -590,7 +596,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, if ((inflictor.classname == "detpack") && (inflictor.weaponmode == 1) && (inflictor.enemy == targ)) deathmsg = DMSG_DETPACK_DIS; - + LogEventKill(attacker, targ, inflictor); Killed(targ, attacker); return; } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5cf2b516..1f6730cb 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -19,7 +19,7 @@ void () RestartMap = { bprint(PRINT_HIGH, self.netname); bprint(PRINT_HIGH, " Has restarted the map.\n"); - localcmd ("map "); + localcmd ("changelevel "); localcmd (mapname); localcmd ("\n"); } @@ -1005,7 +1005,16 @@ float (string arg1, string arg2, string arg3) ParseCmds = { bprint(PRINT_HIGH, " has changed the map to "); bprint(PRINT_HIGH, arg2); bprint(PRINT_HIGH, "\n"); - localcmd("map "); + if (!clan_scores_dumped) { + if (quadmode) { + rounds = 1; + QuadRoundOver(); + } + DumpClanScores(); + MapEndSequence(); + clan_scores_dumped = 1; + } + localcmd("changelevel "); localcmd(arg2); localcmd("\n"); } diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 57f1323c..7f70bff2 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -85,6 +85,7 @@ void (vector org, entity shooter) MirvGrenadeLaunch = { newmis.solid = SOLID_BBOX; newmis.classname = "grenade"; + newmis.grenadename = "mirvsinglegrenade"; newmis.weapon = DMSG_GREN_MIRV; newmis.touch = NormalGrenadeTouch; newmis.think = NormalGrenadeExplode; diff --git a/ssqc/functions.qc b/ssqc/functions.qc index 57cbbb00..8879831b 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -113,3 +113,39 @@ void () randomizeTeams = { te = find(te, classname, "player"); } }; + +string (string text) clearString = { + local float i; + string specialChars[60] = {"οΏ½", "", "","","","","","",""," "," "," ","","","","","","","",""," ","?","","β€š","Ζ’","β€ž","…","†","‑","Λ†","‰","Ε ","β€Ή","Ε’","","Ε½","","","β€˜","Ε“","Γ…","Γ…β€œ","","ΕΎ","ΕΈ", "<", ">", "|", ":", "*", "?", "\\", "/", "\"", "&", "~", "`", ",", " ", "."}; + text = strconv(1,1,1,text); + text = strireplace("__", "_", text); + for (i = 0; i < 58; i++) { + text = strireplace(specialChars[i], "", text); + } + + return text; +} + +void () PrintLoginMessage = { + CenterPrint6(self, "\n\n\n\n\n\nžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžŸ\n", "Login required, please use\n\s\"cmd login \"\s \nbefore joining the game\n", "žžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžŸ\n", "If you don't have an account, visit\n\s", webpageUrl,"\s\n"); + return; +} + +void () MapEndSequence = { + local entity player; + player = find (world, classname, "player"); + while (player) + { + if (player.playerclass != 0) { + local float timeplayed = gametime - player.classtime; + LogEventChangeClass(player, player.playerclass, 0, timeplayed); + player.classtime = gametime; + } + player = find (player, classname, "player"); + } + LogEventTeamScores(); + LogEventGameEnd(); + if (logfilehandle > 0) + fclose(logfilehandle); + canlog = 0; +} \ No newline at end of file diff --git a/ssqc/progs.src b/ssqc/progs.src index e921e52b..d2fa14f6 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -6,6 +6,7 @@ defs.qc ../share/commondefs.qc ../share/common_helpers.qc qw.qc +events.qc q3defs.qc debug.qc status.qc diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 66773876..62e4fcc3 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -187,6 +187,7 @@ void () NapalmGrenadeExplode = { head = spawn(); head.think = NapalmGrenadeNetThink; head.classname = "grentimer"; + head.grenadename = "napalmfire"; head.nextthink = time + 0.1; head.heat = 0; head.origin = self.origin; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 8382dae8..ed9f47fe 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -156,7 +156,6 @@ void () QuadRoundBegin = { // lightstyle (0, "m"); bprint(2, "QUAD ROUND BEGINS NOW\n"); - if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; self.cnt2 = 60; @@ -287,6 +286,11 @@ void () StartQuadRound = p = find(p, classname, "player"); } bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); + if (!clan_scores_dumped) { + DumpClanScores(); + MapEndSequence(); + clan_scores_dumped = 1; + } localcmd("stop\n"); return; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bf35eae8..c4dfed6c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -659,3 +659,20 @@ string (string s, float width) strpadr = float captainmode; .float captain; + + +//Player ID +float loginRequired; +string loginUrl; +string webpageUrl; +.string login; +.float login_in_progress; + + +//Logging fields +float gametime; +string gametimestamp; +float logfilehandle; +float canlog; +.string grenadename; +.float classtime; \ No newline at end of file diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 25b31a40..3056eab7 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -100,6 +100,7 @@ void () ScatterCaltrops = { while (num > 0) { e = spawn(); e.classname = "grenade"; + e.grenadename = "caltrop"; e.weapon = 10; e.owner = self.owner; e.team_no = self.owner.team_no; diff --git a/ssqc/status.qc b/ssqc/status.qc index fa4a98fa..ca41da4f 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -576,6 +576,10 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr Status_Print(pl, s1, s2, s3, s4, s5); }; +void (entity pl, string s1, string s2, string s3, string s4, string s5, string s6) CenterPrint6 = { + Status_Print(pl, s1, s2, s3, s4, s5, s6); +}; + string getLocationName(vector location); void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 514f440e..2a95d782 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -971,30 +971,38 @@ void () TeamFortress_GrenadePrimed = { if (self.weapon == GR_TYPE_NORMAL) { newmis.touch = NormalGrenadeTouch; newmis.think = NormalGrenadeExplode; + newmis.grenadename = "normalgrenade"; newmis.skin = 0; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_CONCUSSION) { newmis.touch = ConcussionGrenadeTouch; newmis.think = ConcussionGrenadeExplode; + newmis.grenadename = "concussiongrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; + if (nailgren_type == NGR_TYPE_LASER) + newmis.grenadename = "shockgrenade"; + else + newmis.grenadename = "nailgrenade"; newmis.skin = 1; newmis.avelocity = '0 300 0'; setmodel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_MIRV) { newmis.touch = MirvGrenadeTouch; newmis.think = MirvGrenadeExplode; + newmis.grenadename = "mirvgrenade"; newmis.skin = 0; newmis.avelocity = '0 300 0'; setmodel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; newmis.think = NapalmGrenadeExplode; + newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; setmodel(newmis, "progs/biggren.mdl"); @@ -1002,6 +1010,7 @@ void () TeamFortress_GrenadePrimed = { newmis.touch = FlareGrenadeTouch; newmis.weapon = self.team_no; newmis.think = FlareGrenadeExplode; + newmis.grenadename = "flaregrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; newmis.mdl = "flare"; @@ -1009,23 +1018,27 @@ void () TeamFortress_GrenadePrimed = { } else if (self.weapon == GR_TYPE_GAS) { newmis.touch = GasGrenadeTouch; newmis.think = GasGrenadeExplode; + newmis.grenadename = "gasgrenade"; newmis.skin = 3; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_EMP) { newmis.touch = EMPGrenadeTouch; newmis.think = EMPGrenadeExplode; + newmis.grenadename = "empgrenade"; newmis.skin = 4; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_CALTROP) { newmis.touch = CanisterTouch; newmis.think = ScatterCaltrops; + newmis.grenadename = "caltropgrenade"; newmis.skin = 0; newmis.avelocity = '0 0 0'; } else if (self.weapon == GR_TYPE_FLASH) { newmis.touch = FlashGrenadeTouch; newmis.think = FlashGrenadeExplode; + newmis.grenadename = "flashgrenade"; newmis.skin = 2; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/hgren2.mdl"); @@ -2745,35 +2758,44 @@ void () TeamFortress_ExplodePerson = { if (self.weapon == GR_TYPE_NORMAL) { newmis.touch = NormalGrenadeTouch; newmis.think = NormalGrenadeExplode; + newmis.grenadename = "normalgrenade"; newmis.skin = 0; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_CONCUSSION) { newmis.touch = ConcussionGrenadeTouch; newmis.think = ConcussionGrenadeExplode; + newmis.grenadename = "concussiongrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; + if (nailgren_type == NGR_TYPE_LASER) + newmis.grenadename = "shockgrenade"; + else + newmis.grenadename = "nailgrenade"; newmis.skin = 1; newmis.avelocity = '0 300 0'; setmodel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_MIRV) { newmis.touch = MirvGrenadeTouch; newmis.think = MirvGrenadeExplode; + newmis.grenadename = "mirvgrenade"; newmis.skin = 0; newmis.avelocity = '0 300 0'; setmodel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; newmis.think = NapalmGrenadeExplode; + newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; setmodel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_FLARE) { sprint(self.owner, PRINT_HIGH, "Flare lit\n"); + newmis.grenadename = "flaregrenade"; te = spawn(); te.touch = SUB_Null; te.think = RemoveFlare; @@ -2787,21 +2809,25 @@ void () TeamFortress_ExplodePerson = { } else if (self.weapon == GR_TYPE_GAS) { newmis.touch = GasGrenadeTouch; newmis.think = GasGrenadeExplode; + newmis.grenadename = "gasgrenade"; newmis.skin = 2; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_EMP) { newmis.touch = EMPGrenadeTouch; newmis.think = EMPGrenadeExplode; + newmis.grenadename = "empgrenade"; newmis.skin = 4; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_CALTROP) { newmis.touch = CaltropTouch; newmis.think = ScatterCaltrops; + newmis.grenadename = "caltropgrenade"; } else if (self.weapon == GR_TYPE_FLASH) { newmis.touch = FlashGrenadeTouch; newmis.think = FlashGrenadeExplode; + newmis.grenadename = "flashgrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; setmodel(newmis, "progs/grenade2.mdl"); diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 6eccc973..abbbd2fa 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -755,6 +755,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player == AP) { if (Goal.count > 0) { if (Player.team_no > 0) { + LogEventGoal(Player); TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count); TeamFortress_TeamShowScores(2); Player.caps = Player.caps + 1; @@ -1769,6 +1770,7 @@ void (entity Goal, entity AP, float addb) DoResults = { } if (winners == 1) { TeamFortress_TeamShowScores(2); + LogEventGoal(AP); } if (CTF_Map == 1) { if (AP != world) { @@ -2318,6 +2320,10 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { RemoveResults(Item, te); te = find(te, classname, "player"); } + //Flag + if ((Item.goal_activation & 1)) + LogEventFumble(AP); + if ((method == 0) || (method == 2)) { te = find(world, classname, "player"); while (te != world) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 685d3cea..1e3454f4 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -972,6 +972,7 @@ void () W_FireAssaultCannon = { { FireAssCan(5, dir, '0.04 0.04 0'); } + LogEventAttack(self); }; void (entity pe_flame) CF_ExtinguishFlame = { @@ -1349,6 +1350,7 @@ void () W_FireSuperSpikes = { self.currentammo = self.ammo_nails; dir = aim(self, 1000); launch_spike(self.origin + '0 0 16', dir); + LogEventAttack(self); newmis.touch = superspike_touch; newmis.weapon = DMSG_SNAILGUN; setmodel(newmis, "progs/s_spike.mdl"); @@ -1379,6 +1381,7 @@ void (float ox) W_FireSpikes = { } dir = aim(self, 1000); launch_spike(self.origin + '0 0 16' + v_right * ox, dir); + LogEventAttack(self); KickPlayer(-3, self); }; @@ -2092,6 +2095,12 @@ void () W_Attack = { W_FireLaser(); Attack_Finished(0.4); } + + //These weapons have to log each projectile launched/bullet fired + if (self.current_weapon != WEAP_ASSAULT_CANNON || + self.current_weapon != WEAP_NAILGUN || + self.current_weapon != WEAP_SUPER_NAILGUN) + LogEventAttack(self); }; float (entity pl) WeaponReady = { @@ -3079,6 +3088,10 @@ void () DeadImpulses = { TeamFortress_ChangeClass(self.impulse - TF_CHANGEPC_SCOUT + 1); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGETEAM) && (deathmatch == 3) && (!cb_prematch)) { + if (loginRequired && !self.login) { + sprint (self, 2, "Login required, please use \"cmd login \" before joining the game\n"); + return; + } Menu_Team(0); } else if ((self.playerclass != 0) && (self.impulse == TF_CHANGECLASS) && (deathmatch == 3) && (!cb_prematch)) { @@ -3213,6 +3226,17 @@ void () DeadImpulses = { void () W_WeaponFrame = { + + if (self.login_in_progress) { + CenterPrint(self, "Trying to log in..."); + } + + if (loginRequired && !self.login) { + PrintLoginMessage(); + self.impulse = 0; + return; + } + if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 10) { Menu_Input(self.impulse); From a84c293f524634f08cde90f93fa52a3842ecdeae Mon Sep 17 00:00:00 2001 From: fdittz Date: Mon, 17 Feb 2020 20:34:02 -0300 Subject: [PATCH 0907/2474] logging flag running time --- ssqc/clan.qc | 5 +++-- ssqc/qw.qc | 3 ++- ssqc/tfortmap.qc | 10 +++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 5820be5d..df4df652 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -66,7 +66,8 @@ void () StartMatch = local entity gren; lightstyle(0, "m"); - bprint(2, "MATCH BEGINS NOW\n"); + bprint(2, "MATCH BEGINS NOW\n"); + team4score = 0; team3score = 0; team2score = 0; @@ -119,7 +120,7 @@ void () StartMatch = PutClientInServer(); if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { UpdateClientPrematch(self, TRUE); - } + } self = oldself; te = find(te, classname, "player"); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index c4dfed6c..d0684d9a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -675,4 +675,5 @@ string gametimestamp; float logfilehandle; float canlog; .string grenadename; -.float classtime; \ No newline at end of file +.float classtime; +.float goalrunningtime; \ No newline at end of file diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index abbbd2fa..1da696cd 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2255,6 +2255,8 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { Status_Refresh(AP); DoResults(Item, AP, 1); DoItemGroupWork(Item, AP); + AP.goalrunningtime = gametime; + LogEventPickupGoal(AP); }; void () ReturnItem = { @@ -2321,9 +2323,11 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { te = find(te, classname, "player"); } //Flag - if ((Item.goal_activation & 1)) - LogEventFumble(AP); - + if ((Item.goal_activation & 1)) { + local float timecarried = gametime - self.goalrunningtime; + LogEventFumble(AP, timecarried); + } + if ((method == 0) || (method == 2)) { te = find(world, classname, "player"); while (te != world) { From a931357d4dcbfbf6cdce15c01cc11302da3ce7df Mon Sep 17 00:00:00 2001 From: fdittz Date: Tue, 18 Feb 2020 15:23:52 -0300 Subject: [PATCH 0908/2474] improving flag running/drop flag, fixing bugs --- ssqc/tfortmap.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 1da696cd..ce5c150c 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2324,7 +2324,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { } //Flag if ((Item.goal_activation & 1)) { - local float timecarried = gametime - self.goalrunningtime; + local float timecarried = gametime - AP.goalrunningtime; LogEventFumble(AP, timecarried); } @@ -2888,6 +2888,7 @@ void (entity P) ForceRespawn = { void () DropGoalItems = { local entity te, search; + local float timecarried; newmis = spawn(); makevectors(self.v_angle); @@ -2903,6 +2904,8 @@ void () DropGoalItems = { } //Always allow dropping 4096 else if (self.effects & EF_DIMLIGHT || te.goal_activation & 4096) { + timecarried = gametime - self.goalrunningtime; + LogEventFumble(self, timecarried); te.angles = '0 0 0'; tfgoalitem_RemoveEffectsFromPlayer(te, self); tfgoalitem_drop(te, 1, self); From f9e92ca764eceb980f4d4784378257147016c097 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 19 Feb 2020 21:49:09 +1300 Subject: [PATCH 0909/2474] spy menu shape fix --- csqc/main.qc | 8 ++++++++ csqc/menu.qc | 29 +++++++++++++++-------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 4ba8f665..c7db0102 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -173,6 +173,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; + case "impulse": + print("MEHT impulsing ", argv(1) ,"\n"); + if(argv(1) == "5") { + print("MEHT impulsing the menu\n"); + FO_Menu_Special(TRUE); + return TRUE; + } + break; } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index f9eae128..3a8a97d3 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -164,8 +164,7 @@ var fo_menu FO_MENU_SCOUT = { //var fo_menu_option FO_MENU_SPY; var fo_menu FO_MENU_SPY = { [0,0], [300,150], "Spy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { - {"1","Disguise","","",FO_MENU_STATE_NORMAL,{FO_Menu_Spy_Skin(TRUE);localcmd("cmd disguise\n");},MENU_BUTTON}, - {"1","Invisibility","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Disguise","","",FO_MENU_STATE_NORMAL,{ if(SBAR.IsUndercover) { FO_Menu_Spy_Skin(TRUE); } localcmd("cmd disguise\n");},MENU_BUTTON}, {"2","Last Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise last\n");Menu_Cancel();},MENU_BUTTON}, {"3","Feign","","",FO_MENU_STATE_NORMAL,{localcmd("feign\n");Menu_Cancel();},MENU_BUTTON}, {"4","Reset Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise none\n");Menu_Cancel();},MENU_BUTTON}, @@ -177,7 +176,7 @@ var fo_menu FO_MENU_SPY = { localcmd("setinfo smt ", ftos(smt), "\n"); FO_MENU_SPY.options[8].value = (smt?"on":"off"); },MENU_BUTTON}, - }, 9, TRUE + }, 8, TRUE }; void sendDisguiseCommand(float skinno) = { @@ -998,24 +997,26 @@ void FO_Menu_Spy(float force) = { if(fo_hud_menu_active && !force) return; if(SBAR.InvisOnly) { - FO_MENU_SPY.options[0].state = FO_MENU_STATE_HIDDEN; - FO_MENU_SPY.options[1].state = FO_MENU_STATE_NORMAL; - FO_MENU_SPY.options[1].value = (SBAR.IsUndercover?"on":"off"); - FO_MENU_SPY.options[2].state = FO_MENU_STATE_HIDDEN; + //FO_MENU_SPY.options[0].state = FO_MENU_STATE_HIDDEN; + //FO_MENU_SPY.options[1].state = FO_MENU_STATE_NORMAL; + FO_MENU_SPY.options[0].name = "Invisibility"; + FO_MENU_SPY.options[0].value = (SBAR.IsUndercover?"on":"off"); + FO_MENU_SPY.options[1].state = FO_MENU_STATE_DISABLED; } else { - FO_MENU_SPY.options[0].state = FO_MENU_STATE_NORMAL; - FO_MENU_SPY.options[1].state = FO_MENU_STATE_HIDDEN; + //FO_MENU_SPY.options[0].state = FO_MENU_STATE_NORMAL; + //FO_MENU_SPY.options[1].state = FO_MENU_STATE_HIDDEN; + FO_MENU_SPY.options[0].name = "Disguise"; FO_MENU_SPY.options[0].value = (SBAR.IsUndercover?"on":"off"); if(last_skin || last_team) { - FO_MENU_SPY.options[2].state = FO_MENU_STATE_NORMAL; - FO_MENU_SPY.options[2].value = strcat(TeamToString(last_team)," ",ClassToString(last_skin)); + FO_MENU_SPY.options[1].state = FO_MENU_STATE_NORMAL; + FO_MENU_SPY.options[1].value = strcat(TeamToString(last_team)," ",ClassToString(last_skin)); } else { - FO_MENU_SPY.options[2].state = FO_MENU_STATE_HIDDEN; + FO_MENU_SPY.options[1].state = FO_MENU_STATE_DISABLED; } - FO_MENU_SPY.options[4].state = (SBAR.IsUndercover?FO_MENU_STATE_NORMAL:FO_MENU_STATE_HIDDEN); + FO_MENU_SPY.options[3].state = (SBAR.IsUndercover?FO_MENU_STATE_NORMAL:FO_MENU_STATE_DISABLED); } local float smt = stof(getplayerkeyvalue(player_localnum, "smt")); - FO_MENU_SPY.options[8].value = (smt?"on":"off"); + FO_MENU_SPY.options[7].value = (smt?"on":"off"); CurrentMenu = &FO_MENU_SPY; fo_hud_menu_active = TRUE; } From f152c2318f5faa12a9d177fc80682e76d7f51deb Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 19 Feb 2020 22:27:49 +1300 Subject: [PATCH 0910/2474] csqc grentimer --- csqc/events.qc | 3 +++ csqc/main.qc | 9 +++++++++ share/commondefs.qc | 1 + ssqc/status.qc | 9 ++++++++- ssqc/tfort.qc | 4 ++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index 7c049f67..69e4788b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -252,6 +252,9 @@ void() CSQC_Parse_Event = { motd_expiry = time + MOTD_TIME; quad_round = readfloat(); break; + case MSG_GRENTHROWN: + grentimer_waiting = FALSE; + break; } } diff --git a/csqc/main.qc b/csqc/main.qc index c7db0102..1c1a913b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -85,6 +85,13 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); + + //reset grentimer status if all there are no more active grentimers + if(grentimer_waiting) { + if(FO_Hud_Grentimers[0].grentype == 0) { + grentimer_waiting = FALSE; + } + } } noref float(string cmd) CSQC_ConsoleCommand = { @@ -173,6 +180,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; + /* case "impulse": print("MEHT impulsing ", argv(1) ,"\n"); if(argv(1) == "5") { @@ -181,6 +189,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { return TRUE; } break; + */ } return FALSE; }; diff --git a/share/commondefs.qc b/share/commondefs.qc index c54262db..d6422289 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -19,6 +19,7 @@ #define MSG_CAPTAINS 12 #define MSG_MOTD 13 #define MSG_PREMATCH 14 +#define MSG_GRENTHROWN 15 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/status.qc b/ssqc/status.qc index 6241e209..cdbb7ec6 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -774,6 +774,13 @@ void UpdateClientGrenadePrimed(entity pl, float grentype) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientGrenadeThrown(entity pl) = { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_GRENTHROWN); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientStatusBar(entity pl) { // if we ever change to fte only, this could be changed to stats @@ -934,7 +941,7 @@ void UpdateClientStatusBar(entity pl) } break; } - WriteFloat(MSG_MULTICAST, ((te.tfstate & TFSTATE_GRENPRIMED) == TFSTATE_GRENPRIMED)); + WriteFloat(MSG_MULTICAST, ((pl.tfstate & TFSTATE_GRENPRIMED) == TFSTATE_GRENPRIMED)); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 514f440e..385f249c 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -943,6 +943,10 @@ void () TeamFortress_GrenadePrimed = { user.tfstate = user.tfstate - (user.tfstate & TFSTATE_GRENPRIMED); user.tfstate = user.tfstate - (user.tfstate & TFSTATE_GRENTHROWING); + if (grentimers && infokeyf(user, INFOKEY_P_CSQCACTIVE)) { + UpdateClientGrenadeThrown(user); + } + sound(user, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); KickPlayer(-1, user); newmis = spawn(); From 7a3fdbe0aba9ceaac42c70deedba99122f4ff4f9 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Thu, 20 Feb 2020 05:01:35 +1100 Subject: [PATCH 0911/2474] Add files via upload --- ssqc/weapons.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 685d3cea..5a733972 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -158,6 +158,8 @@ void () W_Precache = { precache_sound("misc/hitsound.wav"); precache_sound("misc/hitsoundcrit.wav"); precache_sound("misc/hitsoundteam.wav"); + precache_sound("misc/killsound.wav"); + precache_sound("misc/killsoundteam.wav"); }; float () crandom = { From f02799e26c2b038371dab4c56d89811b2c66e12b Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Thu, 20 Feb 2020 05:03:56 +1100 Subject: [PATCH 0912/2474] killsound --- ssqc/combat.qc | 47 +++++++++++++++++++++++++++++++++++++++++++++-- ssqc/spy.qc | 2 ++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 97f300f4..50b8bd1f 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -2,7 +2,7 @@ void () T_MissileTouch; void () info_player_start; void (entity targ, entity attacker) ClientObituary; void () ResetPlayers; - +void (entity targ, entity attacker) KillSound; void (entity Goal, entity AP, float addb) DoResults; float (entity Goal, entity AP) Activated; float (entity targ, entity attacker, float damage) TeamEqualiseDamage; @@ -90,7 +90,7 @@ void () ResetPlayersWithCountdown = { void (entity targ, entity attacker) Killed = { local entity oself; - + KillSound(targ, attacker); if (attacker == world && (targ.classname == "building_dispenser" || targ.classname == "building_sentrygun")) attacker = targ; @@ -139,6 +139,8 @@ void (entity targ, entity attacker) Killed = { if(vote_anarchy_mode) { UnvoteForMap(targ); } + + }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { @@ -212,6 +214,47 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { } }; +void (entity targ, entity attacker) KillSound = { + + if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { + if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) { + + local entity trueattacker; + if (attacker.classname == "building_sentrygun") { + trueattacker = attacker.real_owner; + } + else { + trueattacker = attacker; + } + + local string killsound = infokey(trueattacker, "killsound"); + + if (killsound == "1" || killsound == "2" || killsound == "3"){ + + if (targ.team_no != trueattacker.team_no) { + stuffcmd(trueattacker, "play misc/killsound.wav\n"); + return; + } + else { + + if (trueattacker == targ) { + if(killsound == "3") { + stuffcmd(trueattacker, "play misc/killsoundteam.wav\n"); + } + return; + } + + if (killsound == "2" || killsound == "3") + { + stuffcmd(trueattacker, "play misc/killsoundteam.wav\n"); + } + + } + } + } + } +}; + void (entity targ, entity inflictor, entity attacker, float damage) T_Damage = { local vector dir; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 34fb662d..4518e63e 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -4,6 +4,7 @@ void () CF_Spy_UndercoverThink; void () GasGrenadeMakeGas; void () T_TranqDartTouch; void () Spy_DropBackpack; +void (entity targ, entity attacker) KillSound; void () spy_diea1 =[50, spy_diea2] { }; @@ -555,6 +556,7 @@ void (float issilent) CF_Spy_FeignDeath = { if (feign_msg) { deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); bprint(PRINT_MEDIUM, deathstring); + KillSound(self, self.attacked_by); } // set movement speed to 0 if currently in the air to disable manipulation of trajectory From 5b89a1d0d8f75584f1e4aa21afeadd9228f97d6a Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Thu, 20 Feb 2020 05:05:12 +1100 Subject: [PATCH 0913/2474] killsound From 0caa46d2c8d86f891935d8ad166a212ed79e910b Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Thu, 20 Feb 2020 05:13:38 +1100 Subject: [PATCH 0914/2474] killsound --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5a733972..9573fa11 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -159,7 +159,7 @@ void () W_Precache = { precache_sound("misc/hitsoundcrit.wav"); precache_sound("misc/hitsoundteam.wav"); precache_sound("misc/killsound.wav"); - precache_sound("misc/killsoundteam.wav"); + precache_sound("misc/ksoundteam.wav"); }; float () crandom = { From 4db6b300a09c6a86b46d1728da1ee8e83f09bdc8 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Thu, 20 Feb 2020 05:14:49 +1100 Subject: [PATCH 0915/2474] killsound --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 9573fa11..5a733972 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -159,7 +159,7 @@ void () W_Precache = { precache_sound("misc/hitsoundcrit.wav"); precache_sound("misc/hitsoundteam.wav"); precache_sound("misc/killsound.wav"); - precache_sound("misc/ksoundteam.wav"); + precache_sound("misc/killsoundteam.wav"); }; float () crandom = { From 64a57a9d0dec0fe90b74b9166b53dc2b5d6861f4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 20 Feb 2020 10:52:33 +1300 Subject: [PATCH 0916/2474] instant csqc team/class menus --- csqc/csextradefs.qc | 1 + csqc/events.qc | 4 +--- csqc/main.qc | 3 +++ csqc/menu.qc | 20 +++++++++++++++----- share/defs.h | 1 + ssqc/csmenu.qc | 3 +++ ssqc/tforthlp.qc | 4 ++-- ssqc/world.qc | 1 + 8 files changed, 27 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 8173c86f..a627edd2 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -283,6 +283,7 @@ enum { float team_no; float is_spectator; +float player_class; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/events.qc b/csqc/events.qc index 69e4788b..f37be15d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -124,9 +124,7 @@ void() CSQC_Parse_Event = { FO_Menu_Team(FALSE); break; case CLIENT_MENU_CLASS: - //float civonly = readbyte(); - - FO_Menu_Class(FALSE); + FO_Menu_Class(2); break; case CLIENT_MENU_DROPAMMO: float ammotypes = readfloat(); diff --git a/csqc/main.qc b/csqc/main.qc index 1c1a913b..03b4a650 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -27,6 +27,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_GRENTIMER, "1"); registercommand("fo_menu_game"); registercommand("fo_main_menu"); + registercommand("fo_menu_team"); + registercommand("fo_menu_class"); registercommand("fo_menu_admin"); registercommand("fo_menu_vote"); registercommand("fo_menu_special"); @@ -54,6 +56,7 @@ noref void() CSQC_WorldLoaded = { noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); + player_class = getstatf(STAT_CLASS); SBAR.Ready = getstatf(STAT_READY); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); SBAR.Hint = ""; diff --git a/csqc/menu.qc b/csqc/menu.qc index 3a8a97d3..6b1b508f 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -24,6 +24,7 @@ void (float force) FO_Menu_Admin_Fraglimit; void (float force) FO_Menu_Admin_QuadTimelimit; void (float force) FO_Menu_Spy_Skin; void (float force) FO_Menu_Spy_Team; +void (float force) FO_Menu_Class; void FO_Menu_Admin_Players(float force, float type, float page); typedef struct { @@ -107,14 +108,23 @@ var fo_menu FO_MENU_SPECTATOR_TRACK = { }, 0, TRUE }; +void teamChosen(string team) = { + localcmd("cmd changeteam ", team, "\n"); + if(player_class) { + Menu_Cancel(); + } else { + FO_Menu_Class(TRUE); + } +}; + var fo_menu FO_MENU_TEAM = { [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Blue team","","Known for cunning and strategy, Blues like to attack first",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 1\n");Menu_Cancel();},'0.3 0.4 0.7'}, - {"2","Red team","","Excellent at standing their ground, Reds won't stand for being attacked",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 2\n");Menu_Cancel();},'0.7 0.4 0.3'}, - {"3","Yellow team","","The best team",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 3\n");Menu_Cancel();},'0.7 0.7 0.3'}, - {"4","Green team","","Also okay",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam 4\n");Menu_Cancel();},'0.4 0.7 0.3'}, + {"1","Blue team","","Known for cunning and strategy, Blues like to attack first",FO_MENU_STATE_NORMAL,{teamChosen("1");},'0.3 0.4 0.7'}, + {"2","Red team","","Excellent at standing their ground, Reds won't stand for being attacked",FO_MENU_STATE_NORMAL,{teamChosen("2");},'0.7 0.4 0.3'}, + {"3","Yellow team","","The best team",FO_MENU_STATE_NORMAL,{teamChosen("3");},'0.7 0.7 0.3'}, + {"4","Green team","","Also okay",FO_MENU_STATE_NORMAL,{teamChosen("4");},'0.4 0.7 0.3'}, MenuSpacer, - {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{localcmd("cmd changeteam auto\n");Menu_Cancel();},MENU_BUTTON}, + {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{teamChosen("auto");},MENU_BUTTON}, MenuSpacer, {"0","Spectate","","",FO_MENU_STATE_NORMAL,{localcmd("observe\n");Menu_Cancel();},MENU_BUTTON}, }, 8, TRUE, { diff --git a/share/defs.h b/share/defs.h index b89a23c1..24248077 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1384,3 +1384,4 @@ // first 32 are reserved #define STAT_TEAMNO 33 #define STAT_READY 34 +#define STAT_CLASS 35 diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 9036a42b..0dca21fe 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -34,6 +34,9 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { + if(!pl.playerclass) { + return; + } msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 2e308035..0882a274 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -71,12 +71,12 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("-slot4", "-attack;impulse 24"); } else if (self.motd == 30) { if(csqcactive) { - TeamFortress_AliasString("changeteam", "cmd changeteam"); + TeamFortress_AliasString("changeteam", "fo_menu_team"); TeamFortress_AliasString("teamblue", "cmd changeteam 1"); TeamFortress_AliasString("teamred", "cmd changeteam 2"); TeamFortress_AliasString("teamyellow", "cmd changeteam 3"); TeamFortress_AliasString("teamgreen", "cmd changeteam 4"); - TeamFortress_AliasString("changeclass", "cmd changeclass"); + TeamFortress_AliasString("changeclass", "fo_menu_class"); TeamFortress_AliasString("scout", "cmd changeclass 1"); TeamFortress_AliasString("sniper", "cmd changeclass 2"); TeamFortress_AliasString("soldier", "cmd changeclass 3"); diff --git a/ssqc/world.qc b/ssqc/world.qc index 33913af8..03a2242e 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -329,6 +329,7 @@ void () worldspawn = { clientstat(STAT_TEAMNO, EV_FLOAT, team_no); clientstat(STAT_READY, EV_FLOAT, is_ready); + clientstat(STAT_CLASS, EV_FLOAT, playerclass); entity worldspawnent; worldspawnent = spawn(); From afe37d95e1f4ae60655da860ea3ac03eaa9ba4df Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Thu, 20 Feb 2020 18:47:33 +1100 Subject: [PATCH 0917/2474] killsound --- ssqc/combat.qc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 50b8bd1f..8b1414ab 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -226,7 +226,7 @@ void (entity targ, entity attacker) KillSound = { else { trueattacker = attacker; } - + local string killsound = infokey(trueattacker, "killsound"); if (killsound == "1" || killsound == "2" || killsound == "3"){ @@ -244,8 +244,7 @@ void (entity targ, entity attacker) KillSound = { return; } - if (killsound == "2" || killsound == "3") - { + if (killsound == "2" || killsound == "3") { stuffcmd(trueattacker, "play misc/killsoundteam.wav\n"); } @@ -253,6 +252,14 @@ void (entity targ, entity attacker) KillSound = { } } } + else { + if (targ.classname == "player") { + local string targkillsound = infokey(targ, "killsound"); + if (targkillsound == "3") { + stuffcmd(targ, "play misc/killsoundteam.wav\n"); + } + } + } }; void (entity targ, entity inflictor, entity attacker, From b9bfb9199efda11522a4add9675739c109c44dab Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 4 Mar 2020 23:54:45 +1300 Subject: [PATCH 0918/2474] fix spy special menu --- csqc/events.qc | 2 +- csqc/input.qc | 19 +++++++++++++++++ csqc/menu.qc | 58 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index f37be15d..3c727781 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -142,7 +142,7 @@ void() CSQC_Parse_Event = { SBAR.InvisOnly = readfloat(); last_skin = readfloat(); last_team = readfloat(); - FO_Menu_Spy(FALSE); + FO_Menu_Spy(2); break; case CLIENT_MENU_SPY_SKIN: FO_Menu_Spy_Skin(2); diff --git a/csqc/input.qc b/csqc/input.qc index ed23bef1..ee2bf319 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -83,5 +83,24 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { default: } } +/* + * better not + if(evtype == IE_KEYUP) { + tokenize(findkeysforcommand("impulse 5")); + float imp5_1 = stof(argv(0)); + float imp5_2 = stof(argv(1)); + tokenize(findkeysforcommand("menu")); + float menucmd_1 = stof(argv(0)); + float menucmd_2 = stof(argv(1)); + switch (scanx) { + case imp5_1: + case imp5_2: + case menucmd_1: + case menucmd_2: + FO_Menu_Special(TRUE); + return TRUE; + } + } +*/ return FALSE; } diff --git a/csqc/menu.qc b/csqc/menu.qc index 6b1b508f..3e0d16e2 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -22,6 +22,7 @@ void (float force) FO_Menu_Admin_Rounds; void (float force) FO_Menu_Admin_Timelimit; void (float force) FO_Menu_Admin_Fraglimit; void (float force) FO_Menu_Admin_QuadTimelimit; +void (float force) FO_Menu_Spy; void (float force) FO_Menu_Spy_Skin; void (float force) FO_Menu_Spy_Team; void (float force) FO_Menu_Class; @@ -174,7 +175,7 @@ var fo_menu FO_MENU_SCOUT = { //var fo_menu_option FO_MENU_SPY; var fo_menu FO_MENU_SPY = { [0,0], [300,150], "Spy", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { - {"1","Disguise","","",FO_MENU_STATE_NORMAL,{ if(SBAR.IsUndercover) { FO_Menu_Spy_Skin(TRUE); } localcmd("cmd disguise\n");},MENU_BUTTON}, + {"1","Disguise","","",FO_MENU_STATE_NORMAL,{ FO_Menu_Spy_Skin(TRUE); localcmd("cmd disguise\n");},MENU_BUTTON}, {"2","Last Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise last\n");Menu_Cancel();},MENU_BUTTON}, {"3","Feign","","",FO_MENU_STATE_NORMAL,{localcmd("feign\n");Menu_Cancel();},MENU_BUTTON}, {"4","Reset Disguise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd disguise none\n");Menu_Cancel();},MENU_BUTTON}, @@ -184,14 +185,30 @@ var fo_menu FO_MENU_SPY = { {"0","Manual Colour Changes","","",FO_MENU_STATE_NORMAL,{ local float smt = !stof(getplayerkeyvalue(player_localnum, "smt")); localcmd("setinfo smt ", ftos(smt), "\n"); - FO_MENU_SPY.options[8].value = (smt?"on":"off"); },MENU_BUTTON}, - }, 8, TRUE + }, 8, TRUE, { + if(SBAR.InvisOnly) { + FO_MENU_SPY.options[0].name = "Invisibility"; + FO_MENU_SPY.options[0].value = (SBAR.IsUndercover?"on":"off"); + FO_MENU_SPY.options[1].state = FO_MENU_STATE_DISABLED; + } else { + FO_MENU_SPY.options[0].name = "Disguise"; + FO_MENU_SPY.options[0].value = (SBAR.IsUndercover?"on":"off"); + if(last_skin || last_team) { + FO_MENU_SPY.options[1].state = FO_MENU_STATE_NORMAL; + FO_MENU_SPY.options[1].value = strcat(TeamToString(last_team)," ",ClassToString(last_skin)); + } else { + FO_MENU_SPY.options[1].state = FO_MENU_STATE_DISABLED; + } + FO_MENU_SPY.options[3].state = (SBAR.IsUndercover?FO_MENU_STATE_NORMAL:FO_MENU_STATE_DISABLED); + } + FO_MENU_SPY.options[7].value = (stof(getplayerkeyvalue(player_localnum, "smt"))?"on":"off"); + } }; void sendDisguiseCommand(float skinno) = { localcmd("cmd disguise skin ",ftos(skinno),"\n"); - local float smt = !stof(getplayerkeyvalue(player_localnum, "smt")); + local float smt = stof(getplayerkeyvalue(player_localnum, "smt")); if (smt) { FO_Menu_Spy_Team(TRUE); } else { @@ -1000,11 +1017,11 @@ void FO_Menu_Scout(float force, float scanner_on, float scanner_flags) = { fo_hud_menu_active = TRUE; } void FO_Menu_Spy(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) return; if(SBAR.InvisOnly) { //FO_MENU_SPY.options[0].state = FO_MENU_STATE_HIDDEN; @@ -1059,6 +1076,8 @@ void FO_Menu_Spy_Skin(float force) = { } if(fo_hud_menu_active && force != 1) return; + if(!fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY_SKIN && force == 2) + return; CurrentMenu = &FO_MENU_SPY_SKIN; fo_hud_menu_active = TRUE; } @@ -1226,18 +1245,23 @@ void FO_Menu_Special(float force) = { return; fo_menu* NewMenu; + //void(float) nm; switch (SBAR.PlayerClass) { case PC_SCOUT: NewMenu = &FO_MENU_SCOUT; + //nm = FO_Menu_Scout; break; case PC_DEMOMAN: NewMenu = &FO_MENU_DETPACK; + //nm = FO_Menu_Detpack; break; case PC_SPY: NewMenu = &FO_MENU_SPY; + //nm = FO_Menu_Spy; break; case PC_ENGINEER: NewMenu = &FO_MENU_BUILD; + //nm = FO_Menu_Build; break; default: //no class menu @@ -1248,6 +1272,24 @@ void FO_Menu_Special(float force) = { Menu_Cancel(); return; } - CurrentMenu = NewMenu; - fo_hud_menu_active = TRUE; + //CurrentMenu = NewMenu; + switch (SBAR.PlayerClass) { + case PC_SCOUT: + FO_Menu_Scout(force, FALSE, FALSE); //TODO: fix scanner settings + break; + case PC_DEMOMAN: + FO_Menu_Detpack(force, FALSE); //TODO: fix cancel + break; + case PC_SPY: + FO_Menu_Spy(force); + break; + case PC_ENGINEER: + FO_Menu_Build(force); + break; + default: + //no class menu + return; + } + localcmd("cmd menu\n"); + //fo_hud_menu_active = TRUE; }; From 2265c4bae4295b35fce41b4409aa5bb049dd6182 Mon Sep 17 00:00:00 2001 From: fdittz Date: Thu, 5 Mar 2020 10:08:11 -0300 Subject: [PATCH 0919/2474] missing files events.qc and login.qc --- ssqc/events.qc | 419 +++++++++++++++++++++++++++++++++++++++++++++++++ ssqc/login.qc | 48 ++++++ 2 files changed, 467 insertions(+) create mode 100644 ssqc/events.qc create mode 100644 ssqc/login.qc diff --git a/ssqc/events.qc b/ssqc/events.qc new file mode 100644 index 00000000..4620f1e1 --- /dev/null +++ b/ssqc/events.qc @@ -0,0 +1,419 @@ +string (string text) clearString; +string (float tno) GetTeamName; + +string () ISOTimemillis = { + local string padding = string_null; + local string timeuse = strftime(0,"%Y-%m-%dT%H:%M:%S."); + local float randmillis = rint((random()*1000*random())); + if (randmillis < 10) + padding = "00"; + else if (randmillis < 100) + padding = "0"; + local string padded = strcat(padding, ftos(randmillis)); + timeuse = strcat(timeuse, padded); + timeuse = strcat(timeuse, "Z"); + return timeuse; +} + +string (entity pl) getEntityNameOrLogin = { + if (loginRequired) + return pl.login; + else + return clearString(pl.netname); +} + +void (string evt) logevent = { + local string st = infokey (world, "event_debug"); + if (stof(st) > 0) { + bprint2(PRINT_HIGH, evt, "\n"); + } + fputs(logfilehandle, evt); +} + +void (entity player) LogEventPlayerStart = { + if (canlog == 0) + return; + + local string event; + event = sprintf(",\n{\"type\": \"playerStart\", \"player\": \"%s\", \"classtime\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(player), ftos(player.classtime), ftos(gametime), gametimestamp); + logevent(event); +} + +void () LogEventGameStart = { + gametimestamp = ISOTimemillis(); + if (canlog == 0) + return; + local string event; + local entity player; + local float numplayers = 0; + player = find (world, classname, "player"); + + while (player) + { + numplayers++; + player = find (player, classname, "player"); + } + + event = sprintf("{\"type\": \"gameStart\", \"map\": \"%s\", \"numPlayers\": %s, \"numTeams\": %s, \"time\": %s, \"demo\": \"%s\", \"gameTimeStamp\": \"%s\"}", mapname, ftos(numplayers), ftos(number_of_teams), ftos(gametime), cvar_string("serverdemo"), gametimestamp); + logevent(event); +} + +void (entity player, float previous, float next, float timeplayed) LogEventChangeClass = { + if (canlog == 0) + return; + if (previous == 0) { + return; + } + local string event; + event = sprintf(",\n{\"type\": \"changeClass\", \"player\": \"%s\", \"playerClass\": %s, \"nextClass\": %s, \"team\": %s, \"timePlayed\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", + getEntityNameOrLogin(player), + ftos(previous), + ftos(next), + ftos(player.team_no), + ftos(timeplayed), + ftos(gametime), + gametimestamp + ); + logevent(event); +} + +string (float code, float mode) GetWeaponName = { + if (code == 1) { + return "hook"; + } + else if (code == 4) { + return "medikit"; + } + else if (code == 8) { + return "spanner"; + } + else if (code == 16) { + return "axe"; + } + else if (code == 32) { + return "sniperrifle"; + } + else if (code == 64) { + return "autorifle"; + } + else if (code == 128) { + return "shotgun"; + } + else if (code == 256) { + return "supershotgun"; + } + else if (code == 512) { + return "nailgun"; + } + else if (code == 1024) { + return "supernailgun"; + } + else if (code == 2048) { + if (mode == 0) + return "grenadelauncher"; + else if (mode == 1) + return "pipebomblauncher"; + } + else if (code == 4096) { + return "flamethrower"; + } + else if (code == 8192) { + return "rocketlauncher"; + } + else if (code == 16384) { + return "incendiary"; + } + else if (code == 32768) { + return "assaultcannon"; + } + else if (code == 65536) { + return "lightning"; + } + else if (code == 131072) { + return "plasmagun"; + } + else if (code == 262144) { + return "tranquilizer"; + } + else if (code == 524288) { + return "railgun"; + } + else if (code == 1048576) { + return "tribolt"; + } + else if (code == 2097152) { + return "sniperrail"; + } + else + return "undefined"; +} + + +void (entity attacker, entity target, entity inflictor, float damage) LogEventDamage = { + if (canlog == 0) + return; + + local string event; + local string attackEvent; + local string targetEvent; + local string part1attack; + local string part1target; + local string part2; + local string damageKind; + local string attackername; + local string targetname; + local string inflictorId; + + attackername = getEntityNameOrLogin(attacker); + targetname = getEntityNameOrLogin(target); + if (attacker == target) + damageKind = "self"; + else if (attacker.team_no == target.team_no) + damageKind = "team"; + else + damageKind = "enemy"; + + + if (inflictor.classname == "player") + inflictorId = GetWeaponName(attacker.current_weapon, attacker.weaponmode); + else { + inflictorId = inflictor.classname; + if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { + inflictorId = "nailgrenspike"; + } + else if ((inflictor.classname == "spike") && (attacker.playerclass == 5)) { + inflictorId = "superspike"; + } + if (inflictorId == "worldspawn") + attackername = "world"; + else if (inflictorId == "building_sentrygun") { + attackername = getEntityNameOrLogin(attacker.real_owner); + if (damageKind == "damageTeam") + return; + } + else if ((inflictorId == "grenade") && (inflictor.grenadename != "")) + inflictorId = inflictor.grenadename; + } + + + if (getEntityNameOrLogin(target) != "") { + part1attack = sprintf(",\n{\"type\": \"damageDone\", \"kind\": \"%s\", \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, \"target\": \"%s\", \"targetClass\": %s, \"targetTeam\": %s, ", + damageKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + getEntityNameOrLogin(target), + ftos(target.playerclass), + ftos(target.team_no)); + part1target = sprintf(",\n{\"type\": \"damageTaken\", \"kind\": \"%s\", \"attacker\": \"%s\", \"attackerClass\": %s, \"attackerTeam\": %s, \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, ", + damageKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + getEntityNameOrLogin(target), + ftos(target.playerclass), + ftos(target.team_no)); + + + part2 = sprintf("\"inflictor\": \"%s\", \"damage\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", + inflictorId, + ftos(damage), + ftos(gametime), + gametimestamp + ); + + attackEvent = strcat(part1attack, part2); + targetEvent = strcat(part1target, part2); + event = strcat(attackEvent, targetEvent); + logevent(event); + } +} + +void (entity attacker, entity target, entity inflictor) LogEventKill = { + if (canlog == 0) + return; + + if ((target.classname != "player") && (target.classname != "building_sentrygun")) + return; + + local string killKind; + local string attackername; + local string targetname; + local string inflictorId; + + attackername = getEntityNameOrLogin(attacker); + targetname = getEntityNameOrLogin(target); + if (attacker == target) + killKind = "self"; + else if (attacker.team_no == target.team_no) + killKind = "team"; + else + killKind = "enemy"; + + if (inflictor.classname == "player") + inflictorId = GetWeaponName(attacker.current_weapon, attacker.weaponmode); + else { + inflictorId = inflictor.classname; + if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { + inflictorId = "nailgrenspike"; + } + else if ((inflictor.classname == "spike") && (attacker.playerclass == 5)) { + inflictorId = "superspike"; + } + if (inflictorId == "worldspawn") + attackername = "world"; + else if (inflictorId == "building_sentrygun") + attackername = getEntityNameOrLogin(attacker.real_owner); + else if ((inflictorId == "grenade") && (inflictor.grenadename != "")) + inflictorId = inflictor.grenadename; + } + + + local string event; + local string attackEvent; + local string targetEvent; + local string part1attack; + local string part1target; + local string part2; + + part1attack = sprintf(",\n{\"type\": \"kill\", \"kind\": \"%s\", \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, \"target\": \"%s\", \"targetClass\": %s, \"targetTeam\": %s, ", + killKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + targetname, + ftos(target.playerclass), + ftos(target.team_no)); + part1target = sprintf(",\n{\"type\": \"death\", \"kind\": \"%s\", \"attacker\": \"%s\", \"attackerClass\": %s, \"attackerTeam\": %s, \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, ", + killKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + targetname, + ftos(target.playerclass), + ftos(target.team_no)); + part2 = sprintf("\"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", + inflictorId, + ftos(gametime), + gametimestamp + ); + attackEvent = strcat(part1attack, part2); + targetEvent = strcat(part1target, part2); + event = strcat(attackEvent, targetEvent); + logevent(event); +} + + +void (entity player) LogEventGoal = { + if (canlog == 0) + return; + local string event; + event = sprintf(",\n{\"type\": \"goal\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", + ftos(player.team_no), + getEntityNameOrLogin(player), + ftos(player.playerclass), + ftos(gametime), + gametimestamp); + logevent(event); +} + + +void (entity player) LogEventPickupGoal = { + if (canlog == 0) + return; + local string event; + event = sprintf(",\n{\"type\": \"pickup\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", + ftos(player.team_no), + getEntityNameOrLogin(player), + ftos(player.playerclass), + ftos(gametime), + gametimestamp); + logevent(event); +} + +void (entity player, float timecarried) LogEventFumble = { + if (canlog == 0) + return; + local string event; + event = sprintf(",\n{\"type\": \"fumble\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"timeCarried\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", + ftos(player.team_no), + getEntityNameOrLogin(player), + ftos(player.playerclass), + ftos(timecarried), + ftos(gametime), + gametimestamp); + logevent(event); +} + +void (entity attacker) LogEventAttack = { + if (canlog == 0) + return; + local string event; + event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(attacker.current_weapon, attacker.weaponmode), ftos(gametime), gametimestamp); + logevent(event); +} + +void () LogEventGameEnd = { + if (canlog == 0) + return; + local string event; + event = sprintf(",\n{\"type\": \"gameEnd\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", ftos(gametime), gametimestamp); + logevent(event); +} + +void () LogEventTeamScores = { + local float win_score = 0; + local float winning_team = 0; + + if (team1score > win_score) { + win_score = team1score; + winning_team = 1; + } + + if (team2score > win_score) { + win_score = team2score; + winning_team = 2; + } + else if (team2score == win_score) { + winning_team = 0; + } + + + if (team3score > win_score) { + win_score = team3score; + winning_team = 3; + } + else if (team3score == win_score) { + winning_team = 0; + } + + if (team4score > win_score) { + win_score = team4score; + winning_team = 4; + } + else if (team4score == win_score) { + winning_team = 0; + } + + local string teamscores; + teamscores = sprintf("\"team1Score\": %s", ftos(team1score)); + if (number_of_teams > 1) + teamscores = strcat(teamscores, sprintf(", \"team2Score\": %s", ftos(team2score))); + if (number_of_teams > 2) + teamscores = strcat(teamscores, sprintf(", \"team3Score\": %s", ftos(team3score))); + if (number_of_teams > 3) + teamscores = strcat(teamscores, sprintf(", \"team4Score\": %s", ftos(team4score))); + + local string teamnames; + teamnames = sprintf("\"team1Name\": \"%s\"", GetTeamName(1)); + if (number_of_teams > 1) + teamnames = strcat(teamnames, sprintf(", \"team2Name\": \"%s\"", GetTeamName(2))); + if (number_of_teams > 2) + teamnames = strcat(teamnames, sprintf(", \"team3Name\": \"%s\"", GetTeamName(3))); + if (number_of_teams > 3) + teamnames = strcat(teamnames, sprintf(", \"team4Name\": \"%s\"", GetTeamName(4))); + + local string event; + event = sprintf(",\n{\"type\": \"teamScores\", %s, %s, \"winningTeam\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", teamscores, teamnames, ftos(winning_team), ftos(gametime), gametimestamp); + logevent(event); +} \ No newline at end of file diff --git a/ssqc/login.qc b/ssqc/login.qc new file mode 100644 index 00000000..777ba58a --- /dev/null +++ b/ssqc/login.qc @@ -0,0 +1,48 @@ +void (entity player, string login, string secret) performLogin = { + string data = strcat("login=", login); + data = strcat(data,"&secret="); + data = strcat(data,secret); + uri_get(loginUrl, 10, "application/x-www-form-urlencoded", data); + self.login_in_progress = 1; + dprint(infokey(self,"name")); + dprint(" ["); + dprint(infokey(self,"ip")); + dprint("]"); + dprint(" trying to login as "); + dprint(login); + dprint("\n"); +} + +void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { + self.login_in_progress = 0; + if (!responsecode) { + float num_args = tokenizebyseparator(resourcebody,";"); + self.login = argv(0); + forceinfokey(self,"*login", self.login); + bprint(2, infokey(self,"name")); + bprint(2, " has logged in as \s"); + bprint(2, self.login); + bprint(2, "\s\n"); + dprint(infokey(self,"name")); + dprint(" logged in as "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, "You have logged in as ", self.login, "\n"); + if (num_args > 1) { + if (argv(1) == "true") { + self.is_admin = 3; + Admin_Aliases (); + bprint2 (2, self.netname, " \sgains full admin status!\s\n"); +// bprint (3, "\n"); + sprint (self, 2, "Type \scommands\s for admin commands.\n"); + } + } + } + else { + dprint(infokey(self,"name")); + dprint(" login failed: "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, ftos(responsecode), " - Login FAILED, invalid Login/Secret", "\n"); + } +} From 22f83960511c1c18d021c94a4794dc7b2852cef0 Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Wed, 11 Mar 2020 17:43:41 -0300 Subject: [PATCH 0920/2474] fixing login when user joins server --- ssqc/client.qc | 3 ++- ssqc/commands.qc | 42 +++++++++++++++++++++++++++++++++++++++++- ssqc/login.qc | 9 ++++++++- ssqc/menu.qc | 20 +++++++++++++++++++- ssqc/progs.src | 1 + ssqc/tforthlp.qc | 12 +++++++++--- 6 files changed, 80 insertions(+), 7 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ca0b3131..e0712452 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -641,8 +641,9 @@ void () DecodeLevelParms = { // server webpage address (required for login to work) webpageUrl = infokey(world, "webpageurl"); - if (loginRequired && (!loginUrl || !webpageUrl)) + if (loginRequired && (!loginUrl || !webpageUrl)) { loginRequired = 0; + } st = infokey(world, "default"); if (st == "on") { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1f6730cb..5e5d4c23 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -280,7 +280,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num, processedCmd, inp; local string tmp; local float farg3; - local entity ent; + local entity ent, pl; processedCmd = FALSE; if (arg1) @@ -792,6 +792,46 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "cmd help || list (this command)\n"); sprint(self, PRINT_HIGH, "\n"); break; + case "login": + processedCmd = TRUE; + if (arg_num == 2) { + if (self.login != string_null) { + sprint (self, PRINT_HIGH, "You are already logged in\n"); + } + else { + performLogin(self,arg2,arg3); + } + } + else { + sprint (self, PRINT_HIGH, "Missing username/password\n"); + } + break; + case "login-silent" : + processedCmd = TRUE; + if (arg3 != string_null) { + performLogin(self,arg2,arg3); + } + break; + case "who": + processedCmd = TRUE; + pl = find (world, classname, "player"); + string msg; + while (pl) { + msg = string_null; + msg = strcat(msg, infokey(pl,"name")); + msg = strcat(msg, " - "); + if (pl.login != string_null) + msg = strcat(msg, pl.login); + else + msg = strcat(msg, "NOT LOGGED IN"); + if (pl.is_admin) { + msg = strcat(msg, " (admin)"); + } + msg = strcat(msg, "\n"); + sprint(self, PRINT_HIGH, msg); + pl = find (pl, classname, "player"); + } + break; } if (self.is_admin) diff --git a/ssqc/login.qc b/ssqc/login.qc index 777ba58a..66981303 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -15,6 +15,7 @@ void (entity player, string login, string secret) performLogin = { void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { self.login_in_progress = 0; + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); if (!responsecode) { float num_args = tokenizebyseparator(resourcebody,";"); self.login = argv(0); @@ -30,13 +31,19 @@ void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { CenterPrint3(self, "You have logged in as ", self.login, "\n"); if (num_args > 1) { if (argv(1) == "true") { - self.is_admin = 3; + self.is_admin = TRUE; Admin_Aliases (); bprint2 (2, self.netname, " \sgains full admin status!\s\n"); // bprint (3, "\n"); sprint (self, 2, "Type \scommands\s for admin commands.\n"); } } + if(self.team_no == 0 && !intermission_running ) { + if (csqcactive) + Menu_Team(0); + else + Menu_Team(1); + } } else { dprint(infokey(self,"name")); diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 6503d158..bf452e66 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -205,9 +205,27 @@ string (float pf_team_no, string ps_team) Menu_Team_TeamString = { return strzone(s_string); }; +void (float inp) Menu_No_Input = { + return; +} + +void () Menu_Login = { + local string st1, st2, st3; + + sprint (self, 2, "Login required, please use \"cmd login \" before joining the game\n"); + st1 = "Login required, please use\n\s\"cmd login \"\s \nbefore joining the game\n"; + st2 = "If you don't have an account, visit\n\s"; + st3 = webpageUrl; + st3 = strcat(st3, "\s\n"); + st2 = strcat(st2, st3); + st1 = strcat(st1, st2); + Status_Menu(self, Menu_No_Input, st1); + return; +} + void (float update) Menu_Team = { local entity timer; - + if (self.classname == "observer") /* Status_Menu(self, Menu_Team_Input, ""); */ return; diff --git a/ssqc/progs.src b/ssqc/progs.src index d2fa14f6..56649f55 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -50,6 +50,7 @@ quadmode.qc tfort.qc tforthlp.qc tfortmap.qc +login.qc commands.qc ctf.qc coop.qc diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 2e308035..14675272 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -19,8 +19,11 @@ void () TeamFortress_MOTD = { if (self.motd == 5) { if(csqcactive) { - if(self.team_no == 0 && !intermission_running) { - Menu_Team(0); + if(self.team_no == 0 && !intermission_running ) { + if (loginRequired && !self.login) + Menu_Login(); + else + Menu_Team(0); } } else { sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); @@ -221,7 +224,10 @@ void () TeamFortress_MOTD = { TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo TeamFortress_AliasString("break", "cmd break"); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { - Menu_Team(1); + if (loginRequired && !self.login) + Menu_Login(); + else + Menu_Team(1); } self.motd = self.motd + 1; From c7403687217b12b28075ba1c223e4a51494554fd Mon Sep 17 00:00:00 2001 From: Fabio Dittz Date: Thu, 12 Mar 2020 17:29:40 -0300 Subject: [PATCH 0921/2474] making login persistent when changing maps --- ssqc/client.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index e0712452..b3052bb6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2497,6 +2497,11 @@ void (optional float csqcactive) ClientConnect = { if (self.netname == string_null) KickCheater(self); + if (infokey(self,"*login")) + self.login = infokey(self,"*login"); + if (self.login == string_null) + sprint(self,2, "Login required, please use \"cmd login \" \nbefore joining the game\n"); + TeamFortress_Alias("id", TF_ID, 0); TeamFortress_ExecMapScript(self); From 1f8f519656d424b95ce5a8e5641b13a971b5fd5e Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 13 Mar 2020 23:58:03 +1300 Subject: [PATCH 0922/2474] slightly better scout/demo/eng class menu init --- csqc/events.qc | 6 +++--- csqc/menu.qc | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 3c727781..c21aa747 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -136,7 +136,7 @@ void() CSQC_Parse_Event = { float scanner_on = readbyte(); float scanner_flags = readfloat(); - FO_Menu_Scout(FALSE, scanner_on, scanner_flags); + FO_Menu_Scout(2, scanner_on, scanner_flags); break; case CLIENT_MENU_SPY: SBAR.InvisOnly = readfloat(); @@ -151,10 +151,10 @@ void() CSQC_Parse_Event = { FO_Menu_Spy_Team(FALSE); break; case CLIENT_MENU_DETPACK: - FO_Menu_Detpack(FALSE, readbyte()); + FO_Menu_Detpack(2, readbyte()); break; case CLIENT_MENU_BUILD: - FO_Menu_Build(FALSE); + FO_Menu_Build(2); break; case CLIENT_MENU_ROTATE_SENTRY: FO_Menu_Rotate_Sentry(FALSE); diff --git a/csqc/menu.qc b/csqc/menu.qc index 3e0d16e2..30fb1ef5 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -1003,11 +1003,11 @@ void FO_Menu_DropAmmo(float force, float ammotypes, float ammomakes) { } void FO_Menu_Scout(float force, float scanner_on, float scanner_flags) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SCOUT) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_SCOUT && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) return; FO_MENU_SCOUT.options[0].value = (scanner_on?"on":"off"); FO_MENU_SCOUT.options[1].value = ((scanner_flags & 1)?"on":"off"); @@ -1082,11 +1082,11 @@ void FO_Menu_Spy_Skin(float force) = { fo_hud_menu_active = TRUE; } void FO_Menu_Detpack(float force, float cancel_detpack) = { - if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_DETPACK_CANCEL || CurrentMenu == &FO_MENU_DETPACK)) { + if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_DETPACK_CANCEL || CurrentMenu == &FO_MENU_DETPACK) && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) return; if(cancel_detpack) { CurrentMenu = &FO_MENU_DETPACK_CANCEL; @@ -1096,11 +1096,11 @@ void FO_Menu_Detpack(float force, float cancel_detpack) = { fo_hud_menu_active = TRUE; } void FO_Menu_Build(float force) = { - if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_BUILD_CANCEL || CurrentMenu == &FO_MENU_BUILD)) { + if(fo_hud_menu_active && (CurrentMenu == &FO_MENU_BUILD_CANCEL || CurrentMenu == &FO_MENU_BUILD) && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) return; if(SBAR.IsBuilding) { CurrentMenu = &FO_MENU_BUILD_CANCEL; From aa841895eaf92138fa38381c5b5b85036421ea34 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 26 Mar 2020 20:07:45 +1300 Subject: [PATCH 0923/2474] fix setspeed flood on the voting map --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 7c0fdb3a..3c3320f9 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2441,7 +2441,7 @@ void () PlayerPostThink = { CheckPowerups(); W_WeaponFrame(); //TeamFortress_CheckforCheats(); - TeamFortress_SetSpeed(self); + //TeamFortress_SetSpeed(self); } else { CheckPowerups(); W_WeaponFrame(); From 0b27cdc9016099ede84ab6eb8921e27ee89ebfb0 Mon Sep 17 00:00:00 2001 From: LouisTheDog Date: Sun, 5 Apr 2020 17:00:00 -0400 Subject: [PATCH 0924/2474] Adding configurable pyro setting to rocketjump like the soldier class. --- README.md | 1 + ssqc/client.qc | 4 ++++ ssqc/pyro.qc | 6 +++++- ssqc/qw.qc | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4755b2bf..526450d0 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ New features * Dropping flag now possible on all maps using /dropflag. * Allow team changing. * Any non-valid impulse now closes the active menu. +* Option for pyro to rocket jump with incendiary cannnon rockets like soldier `localinfo pyro_soldiercannon on`. == Removed === diff --git a/ssqc/client.qc b/ssqc/client.qc index 7c0fdb3a..f10e0525 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -582,6 +582,10 @@ void () DecodeLevelParms = { // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass pyro_type = CF_GetSetting("pyrotype", "pyro_type", "1"); + // pyro setting to rocketjump like soldier + pyro_soldiercannon = CF_GetSetting("pyrosold", "pyro_soldiercannon", "off"); + + // ceasefire type - 0: default; 1: pause ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 66773876..0ce22593 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -622,7 +622,11 @@ void () IncendiaryRadius = { local float damg; - damg = 72; + if(pyro_soldiercannon) + damg = 92; + else + damg = 72; + deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bf35eae8..368c007e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -563,6 +563,7 @@ float sng_damage; float old_ng_rof; float impulse_queue; float pyro_type; +float pyro_soldiercannon; float flag_follow; float ceasefire_type; float is_paused; From 9e632127a665438c8e672b78baf9576a7969121b Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 13 Apr 2020 21:15:11 +1000 Subject: [PATCH 0925/2474] i hate repeated code and nested ifs --- ssqc/tfort.qc | 100 ++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 52 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index ba339ce0..6640fbad 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -394,6 +394,43 @@ void () TeamFortress_DisplayLegalClasses = { sprint(self, PRINT_HIGH, "\n"); }; +string GetGrenName(float type) +{ + string s = ""; + switch (type) + { + case GR_TYPE_NORMAL: + s = "normal grenade"; + break; + case GR_TYPE_NAIL: + s = (nailgren_type == NGR_TYPE_LASER) ? "shock grenade" : "nail grenade"; + break; + case GR_TYPE_MIRV: + s = "mirv grenade"; + break; + case GR_TYPE_NAPALM: + s = "napalm grenade"; + break; + case GR_TYPE_FLARE: + s = "flare"; + break; + case GR_TYPE_GAS: + s = "hallucinogenic grenade"; + break; + case GR_TYPE_EMP: + s = "EMP grenade"; + break; + case GR_TYPE_CALTROP: + s = "caltrop canister"; + break; + case GR_TYPE_FLASH: + s = "flash grenade"; + break; + } + + return s; +} + void () TeamFortress_Inventory = { local entity en; local string st; @@ -418,65 +455,24 @@ void () TeamFortress_Inventory = { fl = self.no_grenades_1; if (fl > 0) { - sprint(self, PRINT_HIGH, ftos(fl)); - if (self.tp_grenades_1 == GR_TYPE_NORMAL) - sprint(self, PRINT_HIGH, " normal grenade"); - else if (self.tp_grenades_1 == GR_TYPE_NAIL) { - if (nailgren_type == NGR_TYPE_LASER) { - sprint(self, PRINT_HIGH, " shock grenade"); - } else { - sprint(self, PRINT_HIGH, " nail grenade"); - } - } else if (self.tp_grenades_1 == GR_TYPE_MIRV) - sprint(self, PRINT_HIGH, " mirv grenade"); - else if (self.tp_grenades_1 == GR_TYPE_NAPALM) - sprint(self, PRINT_HIGH, " napalm grenade"); - else if (self.tp_grenades_1 == GR_TYPE_FLARE) - sprint(self, PRINT_HIGH, " flare"); - else if (self.tp_grenades_1 == GR_TYPE_GAS) - sprint(self, PRINT_HIGH, " hallucinogenic grenade"); - else if (self.tp_grenades_1 == GR_TYPE_EMP) - sprint(self, PRINT_HIGH, " EMP grenade"); - else if (self.tp_grenades_1 == GR_TYPE_CALTROP) - sprint(self, PRINT_HIGH, " caltrop canister"); - else if (self.tp_grenades_1 == GR_TYPE_FLASH) - sprint(self, PRINT_HIGH, " flash grenade"); - + string g1 = strcat(ftos(fl), " ", GetGrenName(self.tp_grenades_1)); if (fl > 1) - sprint(self, PRINT_HIGH, "s"); - sprint(self, PRINT_HIGH, "\n"); + g1 = strcat(g1, "s"); + + g1 = strcat(g1, "\n"); + sprint(self, PRINT_HIGH, g1); } fl = self.no_grenades_2; if (fl > 0) { - sprint(self, PRINT_HIGH, ftos(fl)); - if (self.tp_grenades_2 == GR_TYPE_NORMAL) - sprint(self, PRINT_HIGH, " normal grenade"); - else if (self.tp_grenades_2 == GR_TYPE_CONCUSSION) - sprint(self, PRINT_HIGH, " concussion grenade"); - else if (self.tp_grenades_2 == GR_TYPE_NAIL) { - if (nailgren_type == NGR_TYPE_LASER) { - sprint(self, PRINT_HIGH, " shock grenade"); - } else { - sprint(self, PRINT_HIGH, " nail grenade"); - } - } else if (self.tp_grenades_2 == GR_TYPE_MIRV) - sprint(self, PRINT_HIGH, " mirv grenade"); - else if (self.tp_grenades_2 == GR_TYPE_NAPALM) - sprint(self, PRINT_HIGH, " napalm grenade"); - else if (self.tp_grenades_2 == GR_TYPE_FLARE) - sprint(self, PRINT_HIGH, " flare"); - else if (self.tp_grenades_2 == GR_TYPE_GAS) - sprint(self, PRINT_HIGH, " hallucinogenic grenade"); - else if (self.tp_grenades_2 == GR_TYPE_EMP) - sprint(self, PRINT_HIGH, " EMP grenade"); - else if (self.tp_grenades_2 == GR_TYPE_FLASH) - sprint(self, PRINT_HIGH, " flash grenade"); - + string g2 = strcat(ftos(fl), " ", GetGrenName(self.tp_grenades_2)); if (fl > 1) - sprint(self, PRINT_HIGH, "s"); - sprint(self, PRINT_HIGH, "\n"); + g2 = strcat(g1, "s"); + + g2 = strcat(g2, "\n"); + sprint(self, PRINT_HIGH, g2); } + if (self.tf_items & NIT_SCANNER) sprint(self, PRINT_HIGH, "Scanner\n"); From 266c60e08bc9bc7e983e9a54890ec336182ad096 Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 13 Apr 2020 21:16:38 +1000 Subject: [PATCH 0926/2474] fix bad variable --- ssqc/tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 6640fbad..504905d0 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -467,7 +467,7 @@ void () TeamFortress_Inventory = { if (fl > 0) { string g2 = strcat(ftos(fl), " ", GetGrenName(self.tp_grenades_2)); if (fl > 1) - g2 = strcat(g1, "s"); + g2 = strcat(g2, "s"); g2 = strcat(g2, "\n"); sprint(self, PRINT_HIGH, g2); From 5c892a5f2dfcdcd11497c6a1325682f28bc1701e Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 14 Apr 2020 07:47:41 +1200 Subject: [PATCH 0927/2474] split game mode and ready status into 2 new HUD elements and fix the display logic --- csqc/csextradefs.qc | 8 +- csqc/events.qc | 10 +- csqc/status.qc | 385 ++++++++++++++++++++++++++++---------------- share/defs.h | 2 + ssqc/clan.qc | 14 ++ ssqc/client.qc | 5 +- ssqc/csmenu.qc | 5 +- ssqc/quadmode.qc | 21 +++ ssqc/spect.qc | 4 + 9 files changed, 306 insertions(+), 148 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index a627edd2..fbd98f8f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -49,6 +49,10 @@ float is_admin; float motd_expiry; float quad_round; float quad_rounds_total; +//float game_started; +float prematch; +float round_active; +float round_over; float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown @@ -274,7 +278,9 @@ enum { HUD_PANEL_GRENTIMER, HUD_PANEL_MENU, HUD_PANEL_MOTD, - HUD_PANEL_MENU_HINT + HUD_PANEL_MENU_HINT, + HUD_PANEL_GAME_MODE, + HUD_PANEL_READY }; #define FOCMD_AUTOHOP "fo_autohop" diff --git a/csqc/events.qc b/csqc/events.qc index c21aa747..dd600ba4 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -240,15 +240,21 @@ void() CSQC_Parse_Event = { SBAR.CountdownStarted = FALSE; motd_expiry = time + MOTD_TIME; quad_rounds_total = readfloat(); + print("MEHT: MOTD Event: Game Mode: ", ftos(SBAR.GameMode), ", Round Total: ", ftos(quad_rounds_total), ", CountdownStarted: ", ftos(SBAR.CountdownStarted), "\n"); break; case MSG_PREMATCH: - float prematch = readbyte(); + prematch = readbyte(); + round_active = readbyte(); + round_over = readbyte(); SBAR.CountdownStarted = readbyte(); SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 8) + ((prematch & 1)?8:0); SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 16) + ((prematch & 2)?16:0); SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 32) + ((prematch & 4)?32:0); - motd_expiry = time + MOTD_TIME; + //motd_expiry = time + MOTD_TIME; quad_round = readfloat(); + //game_started = readbyte(); + print("MEHT: Prematch Event: ", ftos(prematch), ", Round Active: ", ftos(round_active), ", Round Over: ", ftos(round_over)); + print(", Quad Round: ", ftos(quad_round), ", CountdownStarted: ", ftos(SBAR.CountdownStarted), "\n"); break; case MSG_GRENTHROWN: grentimer_waiting = FALSE; diff --git a/csqc/status.qc b/csqc/status.qc index a84504c9..4fd60fb1 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -96,6 +96,60 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { FO_Hud_Panel* panel = getHudPanelPointer(id); + vector position = getPosition(id); + vector size = getFillSize(id); + vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + local float padding = 4 * panel.Scale; + local float transparency = 0.3; + local float lines; + local string gamemode; + if (fo_hud_editor) { + if (hud_panel(panelid, position, size, 0.3, 1)) { + // click event + } + } else { + if(showingscores) { + return; + } + if(text && text != "") { + //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); + //sui_push_frame(position, size); + + //sui_fill([0, 0], size, MENU_BG, transparency, 0); + + //sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + //sui_action_element([0, 0], size, panelid, sui_noop); + //sui_pop_frame(); + lines = tokenizebyseparator(text, "\n"); + local string line; + for (float i = 0; i <= lines; i++) { + line = argv(i); + // tokenize doesn't handle newlines very well + line = strreplace("\n", "", line); + line = strtrim(line); + if (strlen(line) > 0) { + drawstring( + position + [size.x / 2 - stringwidth(line,1,mediumtext)/2,padding*2 + mediumtext.y*i], + line, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + } + } + } + } +} + +void(string panelid, float display, string text, string icon) drawMOTDPanel = { + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + vector position = getPosition(id); vector size = getFillSize(id); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; @@ -130,170 +184,215 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { ); */ if(text && text != "") { - //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); - //sui_push_frame(position, size); - - //sui_fill([0, 0], size, MENU_BG, transparency, 0); - - //sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - //sui_action_element([0, 0], size, panelid, sui_noop); - //sui_pop_frame(); - if(id == HUD_PANEL_MOTD) { - if(!intermission && time < motd_expiry && !team_no) { - local string motd = serverkey("hostname"); + if(!intermission && time < motd_expiry && !team_no) { + local string motd = serverkey("hostname"); + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2], + motd, + mediumtext*1.5, + MENU_TEXT_4, + 1, + 0 + ); + if(strlen(SBAR.MOTD) <= 1) { + motd = "Welcome to FortressOne"; drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2], + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*2], motd, - mediumtext*1.5, - MENU_TEXT_4, + mediumtext, + MENU_TEXT_1, 1, 0 ); - if(strlen(SBAR.MOTD) <= 1) { - motd = "Welcome to FortressOne"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*2], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - motd = "www.github.com/FortressOne"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*3], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - motd = "FortressOne.org"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*4], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - lines = 3; - } else { - lines = tokenizebyseparator(SBAR.MOTD, "\n"); - for (float i = 0; i <= lines; i++) { - motd = argv(i); - // tokenize doesn't handle newlines very well - motd = strreplace("\n", "", motd); - motd = strtrim(motd); - if (strlen(motd) > 0) { - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(i+2)], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - } - } - } - } - //Prematch - if(SBAR.GameMode & 8) { - if(SBAR.GameMode & 4) { - gamemode = "^4Duel^7"; - } else if(SBAR.GameMode & 2) { - gamemode = "^3Quad^7"; - } else if(SBAR.GameMode & 1) { - gamemode = "^1Clan Battle^7"; - } - motd = strcat("This Server is set to ", gamemode, " Mode", (((SBAR.GameMode & 8) && !(SBAR.GameMode & 16))?" (prematch)":"")); + motd = "www.github.com/FortressOne"; drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(lines+3)], + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*3], motd, mediumtext, MENU_TEXT_1, 1, 0 ); - if(team_no && !SBAR.CountdownStarted && !(SBAR.GameMode & 16)) { - motd = "You are"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(lines+4)], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - if(SBAR.Ready) { - motd = "Ready"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2 + mediumtext.y*(lines+5)], - motd, - mediumtext*1.5, - MENU_TEXT_GREEN, - 1, - 0 - ); - } else { - motd = "NOT Ready"; + motd = "FortressOne.org"; + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*4], + motd, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + lines = 3; + } else { + lines = tokenizebyseparator(SBAR.MOTD, "\n"); + for (float i = 0; i <= lines; i++) { + motd = argv(i); + // tokenize doesn't handle newlines very well + motd = strreplace("\n", "", motd); + motd = strtrim(motd); + if (strlen(motd) > 0) { drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2 + mediumtext.y*(lines+5)], + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(i+2)], motd, - mediumtext*1.5, - MENU_TEXT_WARNING, + mediumtext, + MENU_TEXT_1, 1, 0 ); } } } - //Quad mode only - if(SBAR.GameMode & 2) { - if(SBAR.CountdownStarted) { - if(quad_round <= 1) { - motd = "Match over"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], - motd, - mediumtext*1.2, - MENU_TEXT_2, - 1, - 0 - ); - } else { - motd = strcat("Starting Round ", ftos(quad_rounds_total + 2 - quad_round), " of ", ftos(quad_rounds_total)); - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], - motd, - mediumtext*1.2, - MENU_TEXT_2, - 1, - 0 - ); - } + } + } + } +} + +void(string panelid, float display, string text, string icon) drawGameModePanel = { + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + + vector position = getPosition(id); + vector size = getFillSize(id); + vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + local float padding = 4 * panel.Scale; + local float transparency = 0.3; + local float lines; + local string message; + if (fo_hud_editor) { + if (hud_panel(panelid, position, size, 0.3, 1)) { + // click event + } + } else { + if(showingscores) { + return; + } + drawstring( + [50,350], + strcat("MEHT: Prematch: ", ftos(prematch), ", Round Active: ", ftos(round_active), ", Round Over: ", ftos(round_over), ", CountdownStarted: ", ftos(SBAR.CountdownStarted)), + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + drawstring( + [50,370], + strcat("MEHT: Round: ", ftos(quad_round), "/", ftos(quad_rounds_total)), + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); + //sui_push_frame(position, size); + + //sui_fill([0, 0], size, MENU_BG, transparency, 0); + + //sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + //sui_action_element([0, 0], size, panelid, sui_noop); + //sui_pop_frame(); + if(SBAR.GameMode & 4) { + message = "^4Duel Mode^7"; + } else if(SBAR.GameMode & 2) { + message = "^3Quad Mode^7"; + } else if(SBAR.GameMode & 1) { + message = "^1Clan Battle^7"; + } + if(prematch && !round_over) { + message = strcat(message, " (prematch)"); + } else { + //Quad mode only + if(SBAR.GameMode & 2) { + // if(SBAR.CountdownStarted) { + if(round_over) { + if(prematch) { + message = strcat(message, " (Match over)"); + } else { + message = strcat(message, " (Intermission)"); } + /* + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], + motd, + mediumtext*1.2, + MENU_TEXT_2, + 1, + 0 + ); + */ + } else if(quad_round > 0) { + message = strcat(message, " Round ", ftos(quad_rounds_total + 1 - quad_round), "/", ftos(quad_rounds_total)); + /* + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], + motd, + mediumtext*1.2, + MENU_TEXT_2, + 1, + 0 + ); + */ } + //} + } + } + drawstring( + position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y], + message, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + } +} +void(string panelid, float display, string text, string icon) drawReadyPanel = { + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + + vector position = getPosition(id); + vector size = getFillSize(id); + vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + local float padding = 4 * panel.Scale; + local float transparency = 0.3; + local float lines; + local string message; + if (fo_hud_editor) { + if (hud_panel(panelid, position, size, 0.3, 1)) { + // click event + } + } else { + if(showingscores) { + return; + } + if(prematch && team_no && !SBAR.CountdownStarted && !is_spectator) { + if(SBAR.Ready) { + message = "Ready"; + drawstring( + position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y], + message, + mediumtext, + MENU_TEXT_GREEN, + 1, + 0 + ); } else { - lines = tokenizebyseparator(text, "\n"); - local string line; - for (float i = 0; i <= lines; i++) { - line = argv(i); - // tokenize doesn't handle newlines very well - line = strreplace("\n", "", line); - line = strtrim(line); - if (strlen(line) > 0) { - drawstring( - position + [size.x / 2 - stringwidth(line,1,mediumtext)/2,padding*2 + mediumtext.y*i], - line, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - } - } + message = "NOT Ready"; + drawstring( + position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y], + message, + mediumtext, + MENU_TEXT_WARNING, + 1, + 0 + ); } } } @@ -311,8 +410,10 @@ var FO_Hud_Panel Hud_Panels[] = { {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 90','150 260',1,0,1,0, drawFlagInfo, {return "";}}, {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'10 100','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, {"menupanel","Menu",'10 110','200 200',1,0,1,0, drawSimplePanel, {return "";}}, - {"motdpanel",FO_HUD_MOTD_NAME,'-10 100','50 26',1,0,1,0, drawTextPanel, {return SBAR.MOTD;}}, + {"motdpanel",FO_HUD_MOTD_NAME,'-10 100','50 26',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'10 100','50 26',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, + {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'10 100','50 26',1,0,1,0, drawGameModePanel, {return "";}}, + {"readypanel",FO_HUD_READY_NAME,'10 100','50 26',1,0,1,0, drawReadyPanel, {return SBAR.Hint;}}, }; float(string panelid) getHudPanel = { diff --git a/share/defs.h b/share/defs.h index 24248077..29a52d50 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1352,6 +1352,8 @@ #define FO_HUD_FLAGINFO_NAME "Flag Status" #define FO_HUD_MOTD_NAME "MOTD" #define FO_HUD_MENU_HINT_NAME "Menu Hints" +#define FO_HUD_GAME_MODE_NAME "Game Mode" +#define FO_HUD_READY_NAME "Ready Status" #define ICON_CLIPSIZE "textures/wad/clipsize.png" #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 6bb21ecc..d5d6ce75 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -123,6 +123,13 @@ void () StartMatch = self = oldself; te = find(te, classname, "player"); } + te = find(world, classname, "observer"); + while (te) { + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(te, TRUE); + } + te = find(te, classname, "observer"); + } te = find(world, classname, "prematch"); te.classname = "match"; @@ -295,6 +302,13 @@ void () ResetBreakAndReady = { } te = find (te, classname, "player"); } + te = find(world, classname, "observer"); + while (te) { + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(te, TRUE); + } + te = find(te, classname, "observer"); + } } void () StartTimer = diff --git a/ssqc/client.qc b/ssqc/client.qc index 7c0fdb3a..4bc33244 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -202,7 +202,8 @@ void InitPrematch() pm_message.nextthink = 1; game_locked = CF_GetSetting("lg", "locked_game", "off"); - + UpdateClientPrematch(self, !cb_prematch); + UpdateClientMOTD(self); } void (entity goalitem) SetFlagSendMethod = { @@ -2556,7 +2557,7 @@ void (optional float csqcactive) ClientConnect = { tfdet = find(tfdet, classname, "info_tfgoal"); } UpdateClientMOTD(self); - if(quadmode) + //if(quadmode) UpdateClientPrematch(self, !cb_prematch); } if (cb_prematch) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 0dca21fe..c31bcaf6 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -215,8 +215,11 @@ void UpdateClientPrematch(entity pl, float countdownstarted) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_PREMATCH); - WriteByte(MSG_MULTICAST, ((cb_prematch?1:0 + (round_active?2:0) + (round_over?4:0)))); + WriteByte(MSG_MULTICAST, cb_prematch); + WriteByte(MSG_MULTICAST, round_active); + WriteByte(MSG_MULTICAST, round_over); WriteByte(MSG_MULTICAST, countdownstarted); WriteFloat(MSG_MULTICAST, rounds); + //WriteByte(MSG_MULTICAST, countdownstarted); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 8382dae8..a85144b1 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -154,6 +154,13 @@ void () QuadRoundBegin = { te = find (te, classname, "player"); } // lightstyle (0, "m"); + te = find(world, classname, "observer"); + while (te) { + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(te, FALSE); + } + te = find(te, classname, "observer"); + } bprint(2, "QUAD ROUND BEGINS NOW\n"); @@ -256,6 +263,13 @@ void () StartQuadRound = } p = find(p, classname, "player"); } + te = find(world, classname, "observer"); + while (te) { + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(te, TRUE); + } + te = find(te, classname, "observer"); + } cb_prematch = 1; round_over = 1; @@ -286,6 +300,13 @@ void () StartQuadRound = } p = find(p, classname, "player"); } + te = find(world, classname, "observer"); + while (te) { + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(te, TRUE); + } + te = find(te, classname, "observer"); + } bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); localcmd("stop\n"); return; diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 4fe72913..6f1d9ced 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -44,6 +44,10 @@ void () SpectatorConnect = { stuffcmd(self, ".cfg\n"); } self.motd = 0; + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + UpdateClientMOTD(self); + UpdateClientPrematch(self, !cb_prematch); + } }; void () SpectatorDisconnect = { From c2913fc8f1ba8648ad84b3aade913d10e52860db Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 14 Apr 2020 15:47:34 +1200 Subject: [PATCH 0928/2474] hud alignment and default positioning fixes --- csqc/events.qc | 3 - csqc/hud.qc | 35 ++++++++--- csqc/main.qc | 10 --- csqc/status.qc | 164 ++++++++++++++++++------------------------------- 4 files changed, 86 insertions(+), 126 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index dd600ba4..dd67a456 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -240,7 +240,6 @@ void() CSQC_Parse_Event = { SBAR.CountdownStarted = FALSE; motd_expiry = time + MOTD_TIME; quad_rounds_total = readfloat(); - print("MEHT: MOTD Event: Game Mode: ", ftos(SBAR.GameMode), ", Round Total: ", ftos(quad_rounds_total), ", CountdownStarted: ", ftos(SBAR.CountdownStarted), "\n"); break; case MSG_PREMATCH: prematch = readbyte(); @@ -253,8 +252,6 @@ void() CSQC_Parse_Event = { //motd_expiry = time + MOTD_TIME; quad_round = readfloat(); //game_started = readbyte(); - print("MEHT: Prematch Event: ", ftos(prematch), ", Round Active: ", ftos(round_active), ", Round Over: ", ftos(round_over)); - print(", Quad Round: ", ftos(quad_round), ", CountdownStarted: ", ftos(SBAR.CountdownStarted), "\n"); break; case MSG_GRENTHROWN: grentimer_waiting = FALSE; diff --git a/csqc/hud.qc b/csqc/hud.qc index 93f9f550..63823793 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -54,7 +54,7 @@ void FO_Hud_Editor_LoadDefaultSettings() float yoffset = height - 64; // TODO - maybe implement these to allow for pivoting of items - +/* vector pos, fill; float scale, display, nodeInsertLoc; pos = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; @@ -72,13 +72,26 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[i].NodeInsertLoc = nodeInsertLoc; //pnl.Name = name; } - //Default menus to centre of the screen +*/ + //Default menus, id, ready and MOTD to centre of the screen Hud_Panels[HUD_PANEL_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), height / 2 - Hud_Panels[HUD_PANEL_MENU].FillSize.y / 2]; + Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height / 2 + Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.y]; + Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 130]; + Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 200]; } - -float GetTextAlignOffset(float pos, float iconsize, string text, float textsize, float align) { +/* + * pos = x coord of the UI box + * width = x width of the UI box + * iconsize = x width of the icon (text will start before/after it); offset + * text = actual text to display + * textsize = fontsize + * align = alignment + */ +float GetTextAlignOffset(float pos, float width, float iconsize, string text, float textsize, float align) { if(align == FO_HUD_INSERT_AFTER) { - return pos - strlen(text) * textsize; + return pos - strlen(text) * textsize + width - iconsize; + } else if(align == FO_HUD_INSERT_MIDDLE) { + return pos + (width / 2) - ((strlen(text) * textsize) / 2); } return pos + iconsize; } @@ -125,12 +138,12 @@ void Hud_DrawFlagStatusBar(string panelid) if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,FlagInfoLines[i].carrier,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,FlagInfoLines[i].locname,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); } drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); @@ -194,9 +207,9 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string void Hud_DrawClassInfoPanel(string id, float playerclass) { - if(fo_hud_editor && !SBAR.PlayerClass) { + if(fo_hud_editor) { hud_panel(id, DrawPanel.Position, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display); - + drawpic(DrawPanel.Position, "textures/wad/face1.png", FO_Hud_Icon_Size * DrawPanel.Scale, '1 1 1', 1, 0); return; } @@ -410,6 +423,10 @@ void Hud_DrawIdentifyPanel(string id, string identify) { if (!DrawPanel.Display && !fo_hud_editor) return; + + if(fo_hud_editor && !identify) { + identify = "\n"; + } vector pos; pos = DrawPanel.Position; diff --git a/csqc/main.qc b/csqc/main.qc index 03b4a650..9721ce78 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -183,16 +183,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; - /* - case "impulse": - print("MEHT impulsing ", argv(1) ,"\n"); - if(argv(1) == "5") { - print("MEHT impulsing the menu\n"); - FO_Menu_Special(TRUE); - return TRUE; - } - break; - */ } return FALSE; }; diff --git a/csqc/status.qc b/csqc/status.qc index 4fd60fb1..c5839dcf 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1,3 +1,5 @@ +float GetTextAlignOffset(float pos, float width, float iconsize, string text, float textsize, float align); + void(string panelid, float display, string text, string icon) drawClipSize = { if (SBAR.ClipSize || fo_hud_editor) { @@ -102,13 +104,20 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { local float padding = 4 * panel.Scale; local float transparency = 0.3; local float lines; - local string gamemode; if (fo_hud_editor) { - if (hud_panel(panelid, position, size, 0.3, 1)) { + drawstring( + [GetTextAlignOffset(position.x,size.x,padding,panelid,mediumtext.x,panel.NodeInsertLoc), padding*2 + position.y], + panelid, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); + if (hud_panel(panelid, position, size, 0.3, panel.Display)) { // click event } } else { - if(showingscores) { + if(showingscores || !panel.Display) { return; } if(text && text != "") { @@ -129,7 +138,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { line = strtrim(line); if (strlen(line) > 0) { drawstring( - position + [size.x / 2 - stringwidth(line,1,mediumtext)/2,padding*2 + mediumtext.y*i], + [GetTextAlignOffset(position.x,size.x,padding,line,mediumtext.x,panel.NodeInsertLoc), position.y + padding + mediumtext.y*i], line, mediumtext, MENU_TEXT_1, @@ -158,31 +167,22 @@ void(string panelid, float display, string text, string icon) drawMOTDPanel = { local float lines; local string gamemode; if (fo_hud_editor) { - if (hud_panel(panelid, position, size, 0.3, 1)) { - // click event - } - } else { - if(showingscores) { - return; - } - /* - drawstring( - [50,350], - strcat("MEHT: Prematch: ", ftos(SBAR.GameMode & 8), ", Round Active: ", ftos(SBAR.GameMode & 16), ", Round Over: ", ftos(SBAR.GameMode & 32), ", CountdownStarted: ", ftos(SBAR.CountdownStarted)), - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); drawstring( - [50,370], - strcat("MEHT: Round: ", ftos(quad_round), "/", ftos(quad_rounds_total)), + position + [size.x / 2 - (22 * mediumtext.x)/2,padding*2 + mediumtext.y*2], + "Welcome to FortressOne", mediumtext, - MENU_TEXT_1, + MENU_TEXT_4, 1, 0 ); - */ + + if (hud_panel(panelid, position, size, 0.3, panel.Display)) { + // click event + } + } else { + if(showingscores || !panel.Display) { + return; + } if(text && text != "") { if(!intermission && time < motd_expiry && !team_no) { local string motd = serverkey("hostname"); @@ -263,37 +263,14 @@ void(string panelid, float display, string text, string icon) drawGameModePanel local float lines; local string message; if (fo_hud_editor) { - if (hud_panel(panelid, position, size, 0.3, 1)) { + message = "Game Mode"; + if (hud_panel(panelid, position, size, 0.3, panel.Display)) { // click event } } else { - if(showingscores) { + if(showingscores || !panel.Display) { return; } - drawstring( - [50,350], - strcat("MEHT: Prematch: ", ftos(prematch), ", Round Active: ", ftos(round_active), ", Round Over: ", ftos(round_over), ", CountdownStarted: ", ftos(SBAR.CountdownStarted)), - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - drawstring( - [50,370], - strcat("MEHT: Round: ", ftos(quad_round), "/", ftos(quad_rounds_total)), - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); - //sui_push_frame(position, size); - - //sui_fill([0, 0], size, MENU_BG, transparency, 0); - - //sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - //sui_action_element([0, 0], size, panelid, sui_noop); - //sui_pop_frame(); if(SBAR.GameMode & 4) { message = "^4Duel Mode^7"; } else if(SBAR.GameMode & 2) { @@ -306,41 +283,21 @@ void(string panelid, float display, string text, string icon) drawGameModePanel } else { //Quad mode only if(SBAR.GameMode & 2) { - // if(SBAR.CountdownStarted) { if(round_over) { if(prematch) { message = strcat(message, " (Match over)"); } else { message = strcat(message, " (Intermission)"); } - /* - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], - motd, - mediumtext*1.2, - MENU_TEXT_2, - 1, - 0 - ); - */ } else if(quad_round > 0) { message = strcat(message, " Round ", ftos(quad_rounds_total + 1 - quad_round), "/", ftos(quad_rounds_total)); - /* - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.2)/2,padding*2 + mediumtext.y*(lines+7)], - motd, - mediumtext*1.2, - MENU_TEXT_2, - 1, - 0 - ); - */ } - //} } } + } + if(message) { drawstring( - position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y], + [GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.NodeInsertLoc), position.y], message, mediumtext, MENU_TEXT_1, @@ -360,60 +317,59 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { vector position = getPosition(id); vector size = getFillSize(id); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + vector textcolour = MENU_TEXT_4; local float padding = 4 * panel.Scale; - local float transparency = 0.3; local float lines; + local float pos_aligned; local string message; if (fo_hud_editor) { - if (hud_panel(panelid, position, size, 0.3, 1)) { + message = "Ready Status"; + if (hud_panel(panelid, position, size, 0.3, panel.Display)) { // click event } } else { - if(showingscores) { + if(showingscores || !panel.Display) { return; } if(prematch && team_no && !SBAR.CountdownStarted && !is_spectator) { if(SBAR.Ready) { message = "Ready"; - drawstring( - position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y], - message, - mediumtext, - MENU_TEXT_GREEN, - 1, - 0 - ); + textcolour = MENU_TEXT_GREEN; } else { message = "NOT Ready"; - drawstring( - position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y], - message, - mediumtext, - MENU_TEXT_WARNING, - 1, - 0 - ); + textcolour = MENU_TEXT_WARNING; } } } + if(message) { + pos_aligned = GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.NodeInsertLoc); + drawstring( + [pos_aligned, position.y], + message, + mediumtext, + textcolour, + 1, + 0 + ); + } } var FO_Hud_Panel Hud_Panels[] = { {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, - {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 30','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, - {"capspanel",FO_HUD_CAPS_NAME,'10 40','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'10 60','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, - {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 70','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 80','50 26',1,0,1,0, drawIdentify, {return SBAR.Identify;}}, - {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 90','150 260',1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'10 100','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, + {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, + {"capspanel",FO_HUD_CAPS_NAME,'10 80','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'10 110','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'10 140','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, + {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, + {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 230','150 260',1,0,1,0, drawFlagInfo, {return "";}}, + {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'100 110','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, {"menupanel","Menu",'10 110','200 200',1,0,1,0, drawSimplePanel, {return "";}}, - {"motdpanel",FO_HUD_MOTD_NAME,'-10 100','50 26',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, - {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'10 100','50 26',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, - {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'10 100','50 26',1,0,1,0, drawGameModePanel, {return "";}}, - {"readypanel",FO_HUD_READY_NAME,'10 100','50 26',1,0,1,0, drawReadyPanel, {return SBAR.Hint;}}, + {"motdpanel",FO_HUD_MOTD_NAME,'150 100','100 24',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, + {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'100 300','100 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, + {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, + {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, }; float(string panelid) getHudPanel = { From 82a0fec98e3fc44890a9fd9b1ef551e673890312 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 14 Apr 2020 19:34:46 +1200 Subject: [PATCH 0929/2474] fix ezquake dropping on prematch init --- ssqc/client.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 4bc33244..3550d0cc 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -202,8 +202,10 @@ void InitPrematch() pm_message.nextthink = 1; game_locked = CF_GetSetting("lg", "locked_game", "off"); - UpdateClientPrematch(self, !cb_prematch); - UpdateClientMOTD(self); + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(self, !cb_prematch); + UpdateClientMOTD(self); + } } void (entity goalitem) SetFlagSendMethod = { From 918f312cd452a5dd340ee365f53dc69d6a62c296 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 15 Apr 2020 00:13:30 +1200 Subject: [PATCH 0930/2474] tracktarget command for spectators --- README.md | 1 + csqc/events.qc | 6 +++--- csqc/main.qc | 4 ++++ csqc/status.qc | 42 +++++++++++++++++++++++------------------- share/commondefs.qc | 5 +++++ ssqc/actions.qc | 17 +++++++++++++++++ ssqc/commands.qc | 6 ++++++ ssqc/csmenu.qc | 7 ++++++- ssqc/tforthlp.qc | 11 +++++++++-- 9 files changed, 74 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 4755b2bf..a860245d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* new spectator command `tracktarget` lets you track whoever you're pointing at * `cmd forcebreak` - new admin command to end the map (and go to vote) * `break` will vote to end the current map or recind your vote in a vote map * localinfo vote_time 60 - seconds since the first vote is cast until voting is decided. 0 means majority vote only. diff --git a/csqc/events.qc b/csqc/events.qc index dd67a456..7c93ba99 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -246,9 +246,9 @@ void() CSQC_Parse_Event = { round_active = readbyte(); round_over = readbyte(); SBAR.CountdownStarted = readbyte(); - SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 8) + ((prematch & 1)?8:0); - SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 16) + ((prematch & 2)?16:0); - SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 32) + ((prematch & 4)?32:0); + //SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 8) + ((prematch & 1)?8:0); + //SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 16) + ((prematch & 2)?16:0); + //SBAR.GameMode = SBAR.GameMode - (SBAR.GameMode & 32) + ((prematch & 4)?32:0); //motd_expiry = time + MOTD_TIME; quad_round = readfloat(); //game_started = readbyte(); diff --git a/csqc/main.qc b/csqc/main.qc index 9721ce78..7528d0b4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -38,6 +38,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("primetwo"); registercommand("gren1"); registercommand("gren2"); + registercommand("tracktarget"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -183,6 +184,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; + case "tracktarget": + localcmd("cmd tracktarget\n"); + break; } return FALSE; }; diff --git a/csqc/status.qc b/csqc/status.qc index c5839dcf..ac2326c5 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1,7 +1,7 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, float textsize, float align); void(string panelid, float display, string text, string icon) drawClipSize = { - if (SBAR.ClipSize || fo_hud_editor) + if (SBAR.ClipSize != "" || fo_hud_editor) { GetDrawPanel(panelid); Hud_DrawPanelLMP(panelid, text, icon); @@ -271,26 +271,30 @@ void(string panelid, float display, string text, string icon) drawGameModePanel if(showingscores || !panel.Display) { return; } - if(SBAR.GameMode & 4) { - message = "^4Duel Mode^7"; - } else if(SBAR.GameMode & 2) { - message = "^3Quad Mode^7"; - } else if(SBAR.GameMode & 1) { - message = "^1Clan Battle^7"; - } - if(prematch && !round_over) { - message = strcat(message, " (prematch)"); + if(SBAR.GameMode & GAMEMODE_VOTE) { + message = "^5Vote Mode^7"; } else { - //Quad mode only - if(SBAR.GameMode & 2) { - if(round_over) { - if(prematch) { - message = strcat(message, " (Match over)"); - } else { - message = strcat(message, " (Intermission)"); + if(SBAR.GameMode & GAMEMODE_DUEL) { + message = "^4Duel Mode^7"; + } else if(SBAR.GameMode & GAMEMODE_QUAD) { + message = "^3Quad Mode^7"; + } else if(SBAR.GameMode & GAMEMODE_CLAN) { + message = "^1Clan Battle^7"; + } + if(prematch && !round_over) { + message = strcat(message, " (prematch)"); + } else { + //Quad mode only + if(SBAR.GameMode & 2) { + if(round_over) { + if(prematch) { + message = strcat(message, " (Match over)"); + } else { + message = strcat(message, " (Intermission)"); + } + } else if(quad_round > 0) { + message = strcat(message, " Round ", ftos(quad_rounds_total + 1 - quad_round), "/", ftos(quad_rounds_total)); } - } else if(quad_round > 0) { - message = strcat(message, " Round ", ftos(quad_rounds_total + 1 - quad_round), "/", ftos(quad_rounds_total)); } } } diff --git a/share/commondefs.qc b/share/commondefs.qc index d6422289..034fad1c 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -4,6 +4,11 @@ #define ENG_DISPENSER_COST 100 #define ENG_SENTRY_COST 130 +#define GAMEMODE_CLAN 1 +#define GAMEMODE_QUAD 2 +#define GAMEMODE_DUEL 4 +#define GAMEMODE_VOTE 8 + #define MSG_FLAGINFOINIT 1 #define MSG_FLAGINFO 2 diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 788a6ce2..75e96b05 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -164,6 +164,23 @@ void () TeamFortress_SaveMe = { self.saveme_time = time; }; +void (entity pe_player) FO_SpecTrackPoint = { + if(pe_player.classname != "observer") { + return; + } + local vector v_source; + + makevectors(pe_player.v_angle); + v_source = pe_player.origin + v_forward * 10; + traceline(pe_player.origin, pe_player.origin + v_forward * 2048, 0, pe_player); + + if (trace_ent != world) { + if(trace_ent.classname == "player") { + stuffcmd(pe_player, strcat("track ", trace_ent.netname, "\n")); + } + } +} + void (entity pe_player, float f_type) CF_Identify = { local vector v_source; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5cf2b516..1c4b7a57 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1,3 +1,5 @@ +void (entity pe_player) FO_SpecTrackPoint; + void () UpdateAllAdmins = { local entity ent = find(world, classname, "player"); while(ent) { @@ -762,6 +764,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; sprint(self, PRINT_HIGH, "Model: ", self.model, " index: ", ftos(self.modelindex), "\n"); break; + case "tracktarget": + processedCmd = TRUE; + FO_SpecTrackPoint(self); + break; case "help": case "list": processedCmd = TRUE; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index c31bcaf6..402dc4c2 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -206,7 +206,12 @@ void UpdateClientMOTD(entity pl) = { WriteByte(MSG_MULTICAST, MSG_MOTD); WriteString(MSG_MULTICAST, infokey(world, "motd1")); WriteString(MSG_MULTICAST, infokey(world, "motd2")); - WriteFloat(MSG_MULTICAST, ((clanbattle?1:0) + (quadmode?2:0) + (duelmode?4:0) + (cb_prematch?8:0) + (round_active?16:0) + (round_over?32:0))); + WriteFloat(MSG_MULTICAST, ( + (clanbattle?GAMEMODE_CLAN:0) + + (quadmode?GAMEMODE_QUAD:0) + + (duelmode?GAMEMODE_DUEL:0) + + (votemode?GAMEMODE_VOTE:0) + )); WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 0882a274..f1b2821e 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -9,13 +9,20 @@ void (float inp) MOTD_Input = { }; void () TeamFortress_MOTD = { - if (self.classname == "observer" || votemode) + if (votemode) { return; + } + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (self.classname == "observer") { + if(!csqcactive) { + TeamFortress_AliasString("tracktarget", "cmd tracktarget"); + } + return; + } local string st1; local string st2; local string ya; - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); if (self.motd == 5) { if(csqcactive) { From 0990193b5a8350d49b89b8fefaf58443efb87761 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 Apr 2020 22:02:32 +1000 Subject: [PATCH 0931/2474] Update readme for killsounds --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4755b2bf..ff00f388 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* `setinfo killsound 1/2/3` 1 enemies, 2 enemies and teammates, 3 enemies teammates and self * `cmd forcebreak` - new admin command to end the map (and go to vote) * `break` will vote to end the current map or recind your vote in a vote map * localinfo vote_time 60 - seconds since the first vote is cast until voting is decided. 0 means majority vote only. From 27fa3a10034df563c034b98a02f12d08275a1ea2 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 Apr 2020 01:25:30 +1200 Subject: [PATCH 0932/2474] spectator flag/button info works --- ssqc/client.qc | 18 +++----------- ssqc/spect.qc | 4 +++- ssqc/status.qc | 64 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 3550d0cc..9114792a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2543,24 +2543,12 @@ void (optional float csqcactive) ClientConnect = { sprint(self, PRINT_HIGH, "Your battle ID is ", st, "\n"); } } - entity tfdet = find(world, classname, "info_tfdetect"); - if(tfdet) { - InitClientFlagStatus(self, 0, Finditem(tfdet.display_item_status1), FLAGINFO_ICON_FLAG); - InitClientFlagStatus(self, 1, Finditem(tfdet.display_item_status2), FLAGINFO_ICON_FLAG); - InitClientFlagStatus(self, 2, Finditem(tfdet.display_item_status3), FLAGINFO_ICON_FLAG); - InitClientFlagStatus(self, 3, Finditem(tfdet.display_item_status4), FLAGINFO_ICON_FLAG); - } + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - tfdet = find(world, classname, "info_tfgoal"); - while (tfdet) { - if (tfdet.track_goal) { - InitClientFlagStatus(self, -1, tfdet, FLAGINFO_ICON_BUTTON); - } - tfdet = find(tfdet, classname, "info_tfgoal"); - } + InitAllStatuses(self); UpdateClientMOTD(self); //if(quadmode) - UpdateClientPrematch(self, !cb_prematch); + UpdateClientPrematch(self, !cb_prematch); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 6f1d9ced..3941da7b 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -45,6 +45,7 @@ void () SpectatorConnect = { } self.motd = 0; if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + InitAllStatuses(self); UpdateClientMOTD(self); UpdateClientPrematch(self, !cb_prematch); } @@ -128,6 +129,7 @@ void () SpectatorThink = { //if (self.motd <= 400) // TeamFortress_MOTD(); - if (time >= self.StatusRefreshTime) + if (time >= self.StatusRefreshTime) { RefreshStatusBar(self); + } }; diff --git a/ssqc/status.qc b/ssqc/status.qc index cdbb7ec6..8da9ac5a 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -579,8 +579,8 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5) CenterPr string getLocationName(vector location); void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { - float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); - if(csqcactive) { + //float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); + //if(csqcactive) { msg_entity = Player; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_FLAGINFOINIT); @@ -591,8 +591,26 @@ void (entity Player, float index, entity Item, float icon) InitClientFlagStatus WriteFloat(MSG_MULTICAST, Item.owned_by); WriteFloat(MSG_MULTICAST, icon); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); - } + //} } + +void (entity Player) InitAllStatuses = { + entity tfdet = find(world, classname, "info_tfdetect"); + if(tfdet) { + InitClientFlagStatus(Player, 0, Finditem(tfdet.display_item_status1), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(Player, 1, Finditem(tfdet.display_item_status2), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(Player, 2, Finditem(tfdet.display_item_status3), FLAGINFO_ICON_FLAG); + InitClientFlagStatus(Player, 3, Finditem(tfdet.display_item_status4), FLAGINFO_ICON_FLAG); + } + tfdet = find(world, classname, "info_tfgoal"); + while (tfdet) { + if (tfdet.track_goal) { + InitClientFlagStatus(Player, -1, tfdet, FLAGINFO_ICON_BUTTON); + } + tfdet = find(tfdet, classname, "info_tfgoal"); + } +}; + float laststate; void (entity Player, entity Goal) UpdateClientButtonStatus = { msg_entity = Player; @@ -977,6 +995,45 @@ void (entity pl) RefreshStatusBar = { height = 300; height = height - pl.StatusStringLines - 13; + csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); + if(pl.classname == "observer" && csqcactive) { + if (tfdet) + { + for (float t = 1; t <= number_of_teams; t++) + { + switch (t) + { + case 1: + te = Finditem(tfdet.display_item_status1); + break; + case 2: + te = Finditem(tfdet.display_item_status2); + break; + case 3: + te = Finditem(tfdet.display_item_status3); + break; + case 4: + te = Finditem(tfdet.display_item_status4); + break; + } + + if (te) + { + UpdateClientFlagStatus(pl, te); + } + } + } + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.track_goal) { + UpdateClientButtonStatus(pl, tg); + } + tg = find(tg, classname, "info_tfgoal"); + } + + return; + } + // no sbar can be displayed if (height <= 0 || (pl.playerclass == PC_UNDEFINED && !votemode)) { centerprint(pl, pl.StatusString); @@ -988,7 +1045,6 @@ void (entity pl) RefreshStatusBar = { pad = strcat(pad, "\n"); pad = strzone(pad); - csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); // class tip if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2) { From 7c7111e6c228e40f86a764bd925b1701f95a2525 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 16 Apr 2020 01:00:18 +1000 Subject: [PATCH 0933/2474] Fix RJ but with autohop on --- csqc/main.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 03b4a650..49310422 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -220,10 +220,10 @@ noref void CSQC_Input_Frame() { if (cvar(FOCMD_AUTOHOP) == 1) { - if (input_buttons&2) + if (input_buttons&2 && !input_buttons&1) { // jump is held - if (jumptime <= time) + if (jumptime < time) { input_buttons &= ~2; jumptime = time + .3; From 26508e18036f7945f5d3f299fb3271caf06b0ee2 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 Apr 2020 12:02:33 +1200 Subject: [PATCH 0934/2474] fo_hud_save and fo_hud commands for scripting --- README.md | 1 + csqc/hud.qc | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ csqc/main.qc | 36 ++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/README.md b/README.md index a860245d..a1a3c2d8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* hud commands: `fo_hud [element] [setting] [value]` lets you manually configure the extra hud elements' settings and `fo_hud_save` saves them. * new spectator command `tracktarget` lets you track whoever you're pointing at * `cmd forcebreak` - new admin command to end the map (and go to vote) * `break` will vote to end the current map or recind your vote in a vote map diff --git a/csqc/hud.qc b/csqc/hud.qc index 63823793..d6505716 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -79,6 +79,111 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 130]; Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 200]; } + +void FO_Hud_Editor_List_Panels() = { + print("^1Available HUD Elements:^7\n"); + for(float i = 0; i < Hud_Panels.length; i++) { + print(Hud_Panels[i].id, ": ", Hud_Panels[i].Name, "\n"); + } +} + +string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { + float id = getHudPanel(panelid); + if(id < 0) { + print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + return ""; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + switch (setting) { + case "id": + return panel.id; + case "name": + return panel.Name; + case "position": + return vtos(panel.Position); + case "size": + return vtos(panel.FillSize); + case "scale": + return ftos(panel.Scale); + case "textscale": + return ftos(panel.TextScale); + case "show": + return ftos(panel.Display); + case "orientation": + return ftos(panel.NodeInsertLoc); + default: + print("^1Setting^7 '", setting, "' does not exist!\n"); + break; + } + return ""; +} + +void FO_Hud_Editor_Show_Panel(string panelid) = { + float id = getHudPanel(panelid); + if(id < 0) { + print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + print("^1id^7: ", panel.id, "\n"); + print("\tname: ", panel.Name, "\n"); + print("\tposition: ", vtos(panel.Position), "\n"); + print("\tsize: ", vtos(panel.FillSize), "\n"); + print("\tscale: ", ftos(panel.Scale), "\n"); + print("\ttextscale: ", ftos(panel.TextScale), "\n"); + print("\tshow: ", ftos(panel.Display), "\n"); + print("\torientation: ", ftos(panel.NodeInsertLoc), "\n"); +} + +void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting) = { + if(setting == "") { + FO_Hud_Editor_Show_Panel(panelid); + } else { + print(FO_Hud_Editor_Get_Panel_Setting(panelid, setting), "\n"); + } +} + +void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string value) = { + float id = getHudPanel(panelid); + if(id < 0) { + print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + switch (setting) { + case "id": + print("^5id ^1can't be changed^7!\n"); + break; + case "name": + print("^5name ^1can't be changed^7!\n"); + break; + case "position": + panel.Position = stov(value); + break; + case "size": + panel.FillSize = stov(value); + break; + case "scale": + panel.Scale = stof(value); + break; + case "textscale": + panel.TextScale = stof(value); + break; + case "show": + panel.Display = stof(value); + break; + case "orientation": + panel.NodeInsertLoc = stof(value); + break; + default: + print("^1Setting^7 '", setting, "' does not exist!\n"); + break; + } +} + /* * pos = x coord of the UI box * width = x width of the UI box diff --git a/csqc/main.qc b/csqc/main.qc index 7528d0b4..5bfc42d0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -2,6 +2,11 @@ void FO_Hud_Editor(); void Hud_Draw(float width, float height); void FO_Hud_Editor_LoadSettings(); void FO_Hud_Editor_LoadDefaultSettings(); +void FO_Hud_Editor_List_Panels(); +void FO_Hud_Editor_Show_Panel(string panelid); +void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting); +void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string value); +void Hud_WriteCfg(string path) void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); @@ -23,6 +28,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); + registercommand("fo_hud"); + registercommand("fo_hud_save"); registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); registercommand("fo_menu_game"); @@ -111,6 +118,35 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_hud_reset": FO_Hud_Editor_LoadDefaultSettings(); break; + case "fo_hud": + if(argv(1) == "") { + FO_Hud_Editor_List_Panels(); + } else if(argv(3) == "") { + FO_Hud_Editor_Print_Panel_Setting(argv(1), argv(2)); + } else { + FO_Hud_Editor_Set_Panel_Setting(argv(1), argv(2), argv(3)); + } + /* + switch(argv(1)) { + case "list": + FO_Hud_Editor_List_Panels(); + break; + case "show": + case "get": + FO_Hud_Editor_Print_Panel_Setting(argv(2), argv(3)); + break; + case "set": + FO_Hud_Editor_Set_Panel_Setting(argv(2), argv(3), argv(4)); + break; + default: + print("^1Usage:^7 fo_hud [ | | ]\n"); + break; + } + */ + break; + case "fo_hud_save": + Hud_WriteCfg(FO_HUD_CONFIG_PATH); + break; case "fo_menu_game": FO_Menu_Game(TRUE); break; From 3dc548f3424cd4e7ed7e5e514371277b7e46ef56 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 16 Apr 2020 21:00:15 +1000 Subject: [PATCH 0935/2474] put in fo_flash setting --- share/defs.h | 4 ++ ssqc/actions.qc | 8 ++-- ssqc/boss.qc | 18 ++++---- ssqc/buttons.qc | 2 +- ssqc/client.qc | 49 +++++++++++--------- ssqc/combat.qc | 6 +-- ssqc/coop.qc | 12 ++--- ssqc/demoman.qc | 14 +++--- ssqc/doors.qc | 44 +++++++++--------- ssqc/engineer.qc | 26 +++++------ ssqc/extraents.qc | 6 +-- ssqc/flare.qc | 2 +- ssqc/hwguy.qc | 2 +- ssqc/items.qc | 112 +++++++++++++++++++++++----------------------- ssqc/medic.qc | 2 +- ssqc/misc.qc | 50 ++++++++++----------- ssqc/plats.qc | 12 ++--- ssqc/player.qc | 46 +++++++++---------- ssqc/pyro.qc | 40 ++++++++--------- ssqc/q3.qc | 2 +- ssqc/qw.qc | 6 ++- ssqc/scout.qc | 90 +++++++++++++++++++++++-------------- ssqc/sentry.qc | 10 ++--- ssqc/sniper.qc | 2 +- ssqc/spy.qc | 8 ++-- ssqc/subs.qc | 18 +++++++- ssqc/tfort.qc | 52 ++++++++++----------- ssqc/tfortmap.qc | 40 ++++++++--------- ssqc/triggers.qc | 10 ++--- ssqc/tsoldier.qc | 4 +- ssqc/vote.qc | 19 ++++---- ssqc/weapons.qc | 68 ++++++++++++++-------------- ssqc/world.qc | 18 ++++++++ 33 files changed, 437 insertions(+), 365 deletions(-) diff --git a/share/defs.h b/share/defs.h index 24248077..c8216c9d 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1385,3 +1385,7 @@ #define STAT_TEAMNO 33 #define STAT_READY 34 #define STAT_CLASS 35 + +// Dimensions +#define DMN_FLASH 1 // when flashed, we set dimension see to this +#define DMN_NOFLASH 256 // see all the things \ No newline at end of file diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 788a6ce2..68cc3c9a 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -53,7 +53,7 @@ void () TeamFortress_Discard = { self.ammo_cells = 0; } W_SetCurrentAmmo(self); - sound(self, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); newmis.enemy = self; newmis.health = time; newmis.weapon = 0; @@ -75,7 +75,7 @@ void () TeamFortress_Discard = { newmis.nextthink = time + 30; newmis.think = SUB_Remove; newmis.touch = TeamFortress_AmmoboxTouch; - setmodel(newmis, "progs/backpack.mdl"); + FO_SetModel(newmis, "progs/backpack.mdl"); }; void () TeamFortress_Discard_DropAmmo = { @@ -127,9 +127,9 @@ void () TeamFortress_SaveMe = { if (self.last_saveme_sound < time) { if (random() < 0.8) - sound(self, CHAN_WEAPON, "speech/saveme1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "speech/saveme1.wav", 1, ATTN_NORM); else - sound(self, CHAN_WEAPON, "speech/saveme2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "speech/saveme2.wav", 1, ATTN_NORM); self.last_saveme_sound = time + 4; } diff --git a/ssqc/boss.qc b/ssqc/boss.qc index 66183b44..50d12de4 100644 --- a/ssqc/boss.qc +++ b/ssqc/boss.qc @@ -14,11 +14,11 @@ void () boss_face = { }; void () boss_rise1 =[0, boss_rise2] { - sound(self, CHAN_WEAPON, "boss1/out1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "boss1/out1.wav", 1, ATTN_NORM); }; void () boss_rise2 =[1, boss_rise3] { - sound(self, CHAN_VOICE, "boss1/sight1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "boss1/sight1.wav", 1, ATTN_NORM); }; void () boss_rise3 =[2, boss_rise4] { @@ -374,7 +374,7 @@ void () boss_shockc10 =[105, boss_death1] { }; void () boss_death1 =[48, boss_death2] { - sound(self, CHAN_VOICE, "boss1/death.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "boss1/death.wav", 1, ATTN_NORM); }; void () boss_death2 =[49, boss_death3] { @@ -399,7 +399,7 @@ void () boss_death8 =[55, boss_death9] { }; void () boss_death9 =[56, boss_death10] { - sound(self, CHAN_BODY, "boss1/out1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "boss1/out1.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_LAVASPLASH); WriteCoord(MSG_MULTICAST, self.origin_x); @@ -436,14 +436,14 @@ void (vector p) boss_missile = { vec = normalize(d - org); launch_spike(org, vec); - setmodel(newmis, "progs/lavaball.mdl"); + FO_SetModel(newmis, "progs/lavaball.mdl"); newmis.avelocity = '200 100 300'; setsize(newmis, '0 0 0', '0 0 0'); newmis.velocity = vec * 300; newmis.touch = T_MissileTouch; - sound(self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM); if (self.enemy.health <= 0) boss_idle1(); @@ -454,7 +454,7 @@ void () boss_awake = { self.movetype = MOVETYPE_STEP; self.takedamage = DAMAGE_NO; - setmodel(self, "progs/boss.mdl"); + FO_SetModel(self, "progs/boss.mdl"); setsize(self, '-128 -128 -24', '128 128 256'); if (skill == 0) @@ -552,7 +552,7 @@ void () lightning_use = { lightning_end = time + 1; - sound(self, CHAN_VOICE, "misc/power.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "misc/power.wav", 1, ATTN_NORM); lightning_fire(); self = find(world, classname, "monster_boss"); @@ -561,7 +561,7 @@ void () lightning_use = { self.enemy = activator; if ((le1.state == 0) && (self.health > 0)) { - sound(self, CHAN_VOICE, "boss1/pain.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "boss1/pain.wav", 1, ATTN_NORM); self.health = self.health - 1; if (self.health >= 2) { diff --git a/ssqc/buttons.qc b/ssqc/buttons.qc index 45a8cb12..93435c9d 100644 --- a/ssqc/buttons.qc +++ b/ssqc/buttons.qc @@ -51,7 +51,7 @@ void () button_fire = { targ = find(targ, targetname, targname); targ.active = TFGS_ACTIVE; - sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_UP; SUB_CalcMove(self.pos2, self.speed, button_wait); diff --git a/ssqc/client.qc b/ssqc/client.qc index b3052bb6..c37bfb35 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -409,6 +409,9 @@ void () DecodeLevelParms = { // use old concussion, gas and flash grenades [off] old_grens = CF_GetSetting("og", "old_grens", "off"); + // use fortress one flash + fo_flash = CF_GetSetting("ff", "fo_flash", "off"); + // drop primed hand grenades to ground when dying [on] drop_grenades = CF_GetSetting("dg", "drop_grenades", "on"); @@ -1573,7 +1576,7 @@ void (entity p) SetVoteParams = { p.angles = spot.angles; p.fixangle = 1; - setmodel(p, "progs/player.mdl"); + FO_SetModel(p, "progs/player.mdl"); p.modelindex = modelindex_player; setsize(p, VEC_HULL_MIN, VEC_HULL_MAX); @@ -1773,6 +1776,8 @@ void () PutClientInServer = { setmodel(self, "progs/player.mdl"); modelindex_player = self.modelindex; + self.dimension_see = DMN_NOFLASH; + self.dimension_seen = DMN_NOFLASH - (DMN_NOFLASH & DMN_FLASH); if (self.playerclass == 0) { self.modelindex = modelindex_null; @@ -1998,9 +2003,9 @@ void () PlayerJump = { if (self.swim_flag < time) { self.swim_flag = time + 1; if (random() < 0.5) - sound(self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM); else - sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { self.tfstate = self.tfstate | TFSTATE_AIMING; @@ -2022,7 +2027,7 @@ void () PlayerJump = { self.flags = self.flags - (self.flags & FL_JUMPRELEASED); self.button2 = 0; - sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { if (!cannon_air) { @@ -2073,9 +2078,9 @@ void () WaterMove = { if (self.waterlevel != 3) { if (self.air_finished < time) { - sound(self, 2, "player/gasp2.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/gasp2.wav", 1, 1); } else if (self.air_finished < (time + 9)) { - sound(self, 2, "player/gasp1.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/gasp1.wav", 1, 1); } self.air_finished = time + 12; self.dmg = 2; @@ -2090,7 +2095,7 @@ void () WaterMove = { } if (!self.waterlevel) { if (self.flags & 16) { - sound(self, 4, "misc/outwater.wav", 1, 1); + FO_Sound(self, CHAN_BODY, "misc/outwater.wav", 1, 1); self.flags = self.flags - 16; } return; @@ -2119,13 +2124,13 @@ void () WaterMove = { } if (!(self.flags & 16)) { if (self.watertype == -5) { - sound(self, 4, "player/inlava.wav", 1, 1); + FO_Sound(self, CHAN_BODY, "player/inlava.wav", 1, 1); } if (self.watertype == -3) { - sound(self, 4, "player/inh2o.wav", 1, 1); + FO_Sound(self, CHAN_BODY, "player/inh2o.wav", 1, 1); } if (self.watertype == -4) { - sound(self, 4, "player/slimbrn2.wav", 1, 1); + FO_Sound(self, CHAN_BODY, "player/slimbrn2.wav", 1, 1); } self.flags = self.flags + 16; self.dmgtime = 0; @@ -2274,7 +2279,7 @@ void () CheckPowerups = { } } if (self.invisible_sound < time) { - sound(self, 0, "items/inv3.wav", 0.5, 2); + FO_Sound(self, CHAN_AUTO, "items/inv3.wav", 0.5, 2); self.invisible_sound = time + ((random() * 3) + 1); } if (self.invisible_finished < (time + 3)) { @@ -2282,7 +2287,7 @@ void () CheckPowerups = { sprint(self, PRINT_HIGH, "Ring of shadows magic is fading\n"); stuffcmd(self, "bf\n"); - sound(self, 0, "items/inv2.wav", 1, 1); + FO_Sound(self, CHAN_AUTO, "items/inv2.wav", 1, 1); self.invisible_time = time + 1; } if (self.invisible_time < time) { @@ -2313,7 +2318,7 @@ void () CheckPowerups = { sprint(self, PRINT_HIGH, "Protection is almost burned out\n"); stuffcmd(self, "bf\n"); - sound(self, 0, "items/protect2.wav", 1, 1); + FO_Sound(self, CHAN_AUTO, "items/protect2.wav", 1, 1); self.invincible_time = time + 1; } if (self.invincible_time < time) { @@ -2356,7 +2361,7 @@ void () CheckPowerups = { if (self.super_time == 1) { sprint(self, PRINT_HIGH, "Quad damage is wearing off\n"); stuffcmd(self, "bf\n"); - sound(self, 0, "items/damage2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_AUTO, "items/damage2.wav", 1, ATTN_NORM); self.super_time = time + 1; } if (self.super_time < time) { @@ -2400,7 +2405,7 @@ void () CheckPowerups = { sprint(self, PRINT_HIGH, "Air supply in biosuit expiring\n"); stuffcmd(self, "bf\n"); - sound(self, 0, "items/suit2.wav", 1, 1); + FO_Sound(self, CHAN_AUTO, "items/suit2.wav", 1, 1); self.rad_time = time + 1; } if (self.rad_time < time) { @@ -2431,7 +2436,7 @@ void () PlayerPostThink = { if (((self.jump_flag < -300) && (self.flags & 512)) && (self.health > 0)) { if (self.watertype == -3) { - sound(self, 4, "player/h2ojump.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM); } else { if (self.jump_flag < -650) { fdmg = 5; @@ -2445,10 +2450,10 @@ void () PlayerPostThink = { } fdmg = rint(fdmg); TF_T_Damage(self, world, world, fdmg, 1, 0); - sound(self, 2, "player/land2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); self.deathtype = "falling"; } else { - sound(self, 2, "player/land.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); } } } @@ -2618,7 +2623,7 @@ void () ClientDisconnect = { bprint4(PRINT_HIGH, self.netname, " left the game with ", st, " frags\n"); - sound(self, 4, "player/tornoff2.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE); self.has_disconnected = 1; RemovePlayerOwnedEnts(); @@ -3247,7 +3252,7 @@ void() SV_RunClientCommand = { if (((self.jump_flag < -300) && (self.flags & 512)) && (self.health > 0)) { if (self.watertype == -3) { - sound(self, 4, "player/h2ojump.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM); } else { if (self.jump_flag < -650) { fdmg = 5; @@ -3261,10 +3266,10 @@ void() SV_RunClientCommand = { } fdmg = rint(fdmg); TF_T_Damage(self, world, world, fdmg, 1, 0); - sound(self, 2, "player/land2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); self.deathtype = "falling"; } else { - sound(self, 2, "player/land.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); } } } diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 00ba3dcf..89f63ef2 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -61,7 +61,7 @@ void () ResetPlayersDelayed = { dremove(self); } else { bprint(PRINT_HIGH, Q"\sReset in \x10", ftos(duel_reset_timer), "\x11\s\n"); - sound(self, CHAN_AUTO, "buttons/switch04.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "buttons/switch04.wav", 1, ATTN_NONE); //stuffcmd (p, "play buttons/switch04.wav\n"); duel_reset_timer--; self.nextthink = time + 1; @@ -291,7 +291,7 @@ void (entity targ, entity inflictor, entity attacker, if (targ.invincible_finished >= time) { if (self.invincible_sound < time) { - sound(targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM); + FO_Sound(targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM); self.invincible_sound = time + 2; } return; @@ -503,7 +503,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (targ.invincible_finished >= time) { if (self.invincible_sound < time) { - sound(targ, 3, "items/protect3.wav", 1, 1); + FO_Sound(targ, CHAN_ITEM, "items/protect3.wav", 1, 1); self.invincible_sound = time + 2; } return; diff --git a/ssqc/coop.qc b/ssqc/coop.qc index d9819db8..64f1a8ad 100644 --- a/ssqc/coop.qc +++ b/ssqc/coop.qc @@ -15,15 +15,15 @@ void () DropKey = { self.items = self.items - (self.items & IT_KEY1); newmis.items = IT_KEY1; if (world.worldtype == 0) { - setmodel(newmis, "progs/w_s_key.mdl"); + FO_SetModel(newmis, "progs/w_s_key.mdl"); newmis.netname = "silver key"; newmis.noise = "misc/medkey.wav"; } else if (world.worldtype == 1) { - setmodel(newmis, "progs/m_s_key.mdl"); + FO_SetModel(newmis, "progs/m_s_key.mdl"); newmis.netname = "silver runekey"; newmis.noise = "misc/runekey.wav"; } else if (world.worldtype == 2) { - setmodel(newmis, "progs/b_s_key.mdl"); + FO_SetModel(newmis, "progs/b_s_key.mdl"); newmis.netname = "silver keycard"; newmis.noise = "misc/basekey.wav"; } @@ -31,15 +31,15 @@ void () DropKey = { self.items = self.items - (self.items & IT_KEY2); newmis.items = IT_KEY2; if (world.worldtype == 0) { - setmodel(newmis, "progs/w_g_key.mdl"); + FO_SetModel(newmis, "progs/w_g_key.mdl"); newmis.netname = "gold key"; newmis.noise = "misc/medkey.wav"; } else if (world.worldtype == 1) { - setmodel(newmis, "progs/m_g_key.mdl"); + FO_SetModel(newmis, "progs/m_g_key.mdl"); newmis.netname = "gold runekey"; newmis.noise = "misc/runekey.wav"; } else if (world.worldtype == 2) { - setmodel(newmis, "progs/b_g_key.mdl"); + FO_SetModel(newmis, "progs/b_g_key.mdl"); newmis.netname = "gold keycard"; newmis.noise = "misc/basekey.wav"; } diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 7f70bff2..1b3a9194 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -36,13 +36,13 @@ float (float force) TeamFortress_DetonatePipebombs = { }; void () PipebombTouch = { - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; void () MirvGrenadeTouch = { - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; @@ -96,7 +96,7 @@ void (vector org, entity shooter) MirvGrenadeLaunch = { newmis.velocity_z = zdir * 15; newmis.avelocity = '250 300 400'; - setmodel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/grenade2.mdl"); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin(newmis, org); @@ -261,7 +261,7 @@ void () TeamFortress_DetpackSet = { Menu_Close(self.owner); self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self.owner); - sound(self.owner, CHAN_VOICE, "doors/medtry.wav", 1, ATTN_NORM); + FO_Sound(self.owner, CHAN_VOICE, "doors/medtry.wav", 1, ATTN_NORM); oldself = self; self = self.owner; self.is_detpacking = 0; @@ -288,7 +288,7 @@ void () TeamFortress_DetpackSet = { newmis.weaponmode = 0; newmis.touch = TeamFortress_DetpackTouch; - setmodel(newmis, "progs/detpack.mdl"); + FO_SetModel(newmis, "progs/detpack.mdl"); setsize(newmis, '-16 -16 0', '16 16 8'); setorigin(newmis, self.owner.origin); @@ -323,7 +323,7 @@ void () TeamFortress_DetpackExplode = { self.owner.detpack_left = 0; bprint(PRINT_MEDIUM, "FIRE IN THE HOLE!\n"); - sound(self, CHAN_WEAPON, "weapons/detpack.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_WEAPON, "weapons/detpack.wav", 1, ATTN_NONE); pos = pointcontents(self.origin); if ((pos != CONTENT_SOLID) && (pos != CONTENT_SKY) && (self.owner.has_disconnected != 1)) { @@ -473,7 +473,7 @@ void () TeamFortress_DetpackCountDown = { sprint(self.owner, PRINT_HIGH, cd, "...\n"); if ((self.health < 5) && (self.has_disconnected == 0)) { - sound(self.enemy, CHAN_VOICE, "doors/baseuse.wav", 1, + FO_Sound(self.enemy, CHAN_VOICE, "doors/baseuse.wav", 1, ATTN_NORM); self.has_disconnected = 1; } diff --git a/ssqc/doors.qc b/ssqc/doors.qc index ad26ffe9..98f5e986 100644 --- a/ssqc/doors.qc +++ b/ssqc/doors.qc @@ -27,7 +27,7 @@ void () door_blocked = { }; void () door_hit_top = { - sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = 0; if (self.spawnflags & 32) return; @@ -38,7 +38,7 @@ void () door_hit_top = { void () door_hit_bottom = { self.goal_state = 2; - sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = 1; }; @@ -52,7 +52,7 @@ void () door_go_down_silent = { } void () door_go_down = { - sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); door_go_down_silent(); }; @@ -64,7 +64,7 @@ void () door_go_up = { self.nextthink = self.ltime + self.wait; return; } - sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); self.state = STATE_UP; SUB_CalcMove(self.pos2, self.speed, door_hit_top); SUB_UseTargets(); @@ -78,7 +78,7 @@ void () door_fire = { objerror("door_fire: self.owner != self"); } if (self.items) { - sound(self, CHAN_VOICE, self.noise4, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise4, 1, ATTN_NORM); } self.message = string_null; oself = self; @@ -173,7 +173,7 @@ void () door_touch = { self.owner.attack_finished = time + 2; if (self.owner.message != "") { CenterPrint(other, self.owner.message); - sound(other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); + FO_Sound(other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); } if (!self.items) return; @@ -182,23 +182,23 @@ void () door_touch = { if (self.owner.items == IT_KEY1) { if (world.worldtype == 2) { CenterPrint(other, "You need the silver keycard"); - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); } else if (world.worldtype == 1) { CenterPrint(other, "You need the silver runekey"); - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); } else if (world.worldtype == 0) { CenterPrint(other, "You need the silver key"); - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); } } else if (world.worldtype == 2) { CenterPrint(other, "You need the gold keycard\n"); - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); } else if (world.worldtype == 1) { CenterPrint(other, "You need the gold runekey"); - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); } else if (world.worldtype == 0) { CenterPrint(other, "You need the gold key"); - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); } return; } @@ -464,7 +464,7 @@ void () fd_secret_use = { self.takedamage = 0; } self.velocity = '0 0 0'; - sound(self, 2, self.noise1, 1, 1); + FO_Sound(self, CHAN_VOICE, self.noise1, 1, 1); self.nextthink = self.ltime + 0.1; temp = 1 - (self.spawnflags & 2); makevectors(self.mangle); @@ -485,7 +485,7 @@ void () fd_secret_use = { } self.dest2 = self.dest1 + (v_forward * self.t_length); SUB_CalcMove(self.dest1, self.speed, fd_secret_move1); - sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); }; void (entity e, float f) fd_secret_pain = { @@ -495,16 +495,16 @@ void (entity e, float f) fd_secret_pain = { void () fd_secret_move1 = { self.nextthink = self.ltime + 1; self.think = fd_secret_move2; - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); }; void () fd_secret_move2 = { - sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); SUB_CalcMove(self.dest2, self.speed, fd_secret_move3); }; void () fd_secret_move3 = { - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); if (!(self.spawnflags & 1)) { self.nextthink = self.ltime + self.wait; self.think = fd_secret_move4; @@ -512,18 +512,18 @@ void () fd_secret_move3 = { }; void () fd_secret_move4 = { - sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); SUB_CalcMove(self.dest1, self.speed, fd_secret_move5); }; void () fd_secret_move5 = { self.nextthink = self.ltime + 1; self.think = fd_secret_move6; - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); }; void () fd_secret_move6 = { - sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done); }; @@ -534,7 +534,7 @@ void () fd_secret_done = { self.th_pain = fd_secret_pain; self.th_die = fd_secret_use; } - sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); }; void () secret_blocked = { @@ -560,7 +560,7 @@ void () secret_touch = { self.attack_finished = time + 2; if (self.message) { CenterPrint(other, self.message); - sound(other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); + FO_Sound(other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); } }; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 19e8154b..a81842c7 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -25,7 +25,7 @@ void () LaserBolt_Think = { self.movetype = MOVETYPE_FLYMISSILE; self.velocity = self.oldorigin; self.touch = LaserBolt_Touch; - setmodel(self, "progs/e_spike2.mdl"); + FO_SetModel(self, "progs/e_spike2.mdl"); self.nextthink = time + 1; self.think = SUB_Remove; }; @@ -95,7 +95,7 @@ void () W_FireLaser = { newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_TRIGGER; - setmodel(newmis, "progs/e_spike1.mdl"); + FO_SetModel(newmis, "progs/e_spike1.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, org + '0 0 16'); @@ -146,7 +146,7 @@ void () EMPExplode = { }; void () EMPGrenadeTouch = { - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') { self.avelocity = '0 0 0'; } @@ -527,7 +527,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.velocity = '0 0 8'; newmis.movetype = 6; newmis.solid = 2; - setmodel(newmis, newmis.mdl); + FO_SetModel(newmis, newmis.mdl); setsize(newmis, tmp1, tmp2); setorigin(newmis, newmis.origin); newmis.flags = newmis.flags - (newmis.flags & 512); @@ -757,7 +757,7 @@ void (entity disp, entity pl) Dispenser_StockPlayer = { // only play dispenser restock sound if something was given if ((shells + nails + rockets + cells + armor) > 0) - sound(pl, 3, "items/r_item1.wav", 0.7, 1); + FO_Sound(pl, CHAN_ITEM, "items/r_item1.wav", 0.7, 1); pl.duse = time; }; @@ -859,7 +859,7 @@ void () TeamFortress_FinishedBuilding = { self.ammo_cells = ceil(self.ammo_cells * 0.75); self.armorvalue = ceil(self.armorvalue * 0.75); oldself.solid = SOLID_BBOX; - setmodel(oldself, oldself.mdl); + FO_SetModel(oldself, oldself.mdl); setsize(oldself, '-8 -8 0', '8 8 24'); setorigin(oldself, (oldself.origin + '0 0 8')); if(csqcactive) { @@ -886,9 +886,9 @@ void () TeamFortress_FinishedBuilding = { newmis.th_pain = Sentry_Pain; newmis.mdl = "progs/turrgun.mdl"; self.sentry_ent = newmis; - sound(oldself, 3, "weapons/turrset.wav", 1, 1); + FO_Sound(oldself, CHAN_ITEM, "weapons/turrset.wav", 1, 1); newmis.solid = SOLID_BBOX; - setmodel(newmis, newmis.mdl); + FO_SetModel(newmis, newmis.mdl); setsize(newmis, '-16 -16 0', '16 16 48'); setorigin(newmis, oldself.origin + '0 0 8'); newmis.view_ofs = '0 0 22'; @@ -1144,7 +1144,7 @@ void (entity disp) Engineer_Dispenser_Repair = { if (metalcost > 0) { Status_Print(self, "\n\n\n\n\n\n\n", ftos(healamount), " hp repaired"); - sound(self, 3, "items/r_item2.wav", 1, 1); + FO_Sound(self, CHAN_ITEM, "items/r_item2.wav", 1, 1); } }; @@ -1261,7 +1261,7 @@ void (entity gun) Engineer_SentryGun_InsertAmmo = { } ammo = strcat(ammo, " into sentry gun"); Status_Print(self, "\n\n\n\n\n\n\n", ammo); - sound(self, 3, "edge/backpack.wav", 1, 1); + FO_Sound(self, CHAN_ITEM, "edge/backpack.wav", 1, 1); } }; @@ -1275,11 +1275,11 @@ void (entity gun) Engineer_SentryGun_Upgrade = { gun.health = gun.max_health; gun.maxammo_shells = gun.maxammo_shells * 1.2; if (gun.weapon == 2) { - sound(gun, 3, "weapons/turrset.wav", 1, 1); + FO_Sound(gun, CHAN_ITEM, "weapons/turrset.wav", 1, 1); gun.think = lvl2_sentry_stand; gun.skin = 1; } else { - sound(gun, 3, "weapons/turrset.wav", 1, 1); + FO_Sound(gun, CHAN_ITEM, "weapons/turrset.wav", 1, 1); gun.think = lvl3_sentry_stand; gun.skin = 2; } @@ -1302,7 +1302,7 @@ void (entity gun) Engineer_SentryGun_Repair = { if (metalcost > 0) { Status_Print(self, "\n\n\n\n\n\n\n", ftos(healamount), " hp repaired"); - sound(self, 3, "items/r_item2.wav", 1, 1); + FO_Sound(self, CHAN_ITEM, "items/r_item2.wav", 1, 1); } }; diff --git a/ssqc/extraents.qc b/ssqc/extraents.qc index c2e91047..d60181af 100644 --- a/ssqc/extraents.qc +++ b/ssqc/extraents.qc @@ -1,6 +1,7 @@ void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; void (float all) TeamFortress_TeamShowScores; void () InitTrigger; +void FO_SetModel(entity e, string fomdl); /* ====== Vote Ball ======= */ @@ -100,11 +101,10 @@ void () item_ball = { if ( self.mdl ) { precache_model (self.mdl); precache_model2 (self.mdl); - setmodel (self,self.mdl); - + FO_SetModel (self,self.mdl); } else { self.mdl = "progs/lavaball.mdl"; - setmodel (self,self.mdl); + FO_SetModel (self,self.mdl); } if ( !self.netname ) { diff --git a/ssqc/flare.qc b/ssqc/flare.qc index 4379617e..77b505e5 100644 --- a/ssqc/flare.qc +++ b/ssqc/flare.qc @@ -4,7 +4,7 @@ //==================================== void () FlareGrenadeTouch = { - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (pointcontents(self.origin) == CONTENT_SKY) { dremove(self); return; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 4ba35e36..b6186821 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -74,7 +74,7 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) newmis.nextthink = time + 5; // Stop projectile going forever newmis.mdl = MODEL_PROJ_DIAM2; - setmodel(newmis, newmis.mdl); // Diamond model + FO_SetModel(newmis, newmis.mdl); // Diamond model newmis.frame = random()*15; // Full range of sizes newmis.skin = 16 + random()*7; // Bright colours newmis.weapon = DMSG_ASSAULTCANNON; diff --git a/ssqc/items.qc b/ssqc/items.qc index aae2dea2..c4329ddf 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -9,7 +9,7 @@ void () tfgoal_touch; void () SUB_regen = { self.model = self.mdl; self.solid = SOLID_TRIGGER; - sound(self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM); setorigin(self, self.origin); }; @@ -30,7 +30,7 @@ void () q_touch = { return; self.mdl = self.model; - sound(other, CHAN_VOICE, self.noise, 1, ATTN_NORM); + FO_Sound(other, CHAN_VOICE, self.noise, 1, ATTN_NORM); stuffcmd(other, "bf\n"); self.solid = SOLID_NOT; other.items = other.items | IT_QUAD; @@ -56,7 +56,7 @@ void (float timeleft) DropQuad = { item.solid = SOLID_TRIGGER; item.movetype = MOVETYPE_TOSS; item.noise = "items/damage.wav"; - setmodel(item, "progs/quaddama.mdl"); + FO_SetModel(item, "progs/quaddama.mdl"); setsize(item, VEC_HULL_MIN, VEC_HULL_MAX); item.cnt = time + timeleft; item.touch = q_touch; @@ -74,7 +74,7 @@ void () r_touch = { return; self.mdl = self.model; - sound(other, CHAN_VOICE, self.noise, 1, ATTN_NORM); + FO_Sound(other, CHAN_VOICE, self.noise, 1, ATTN_NORM); stuffcmd(other, "bf\n"); self.solid = 0; other.items = other.items | IT_INVISIBILITY; @@ -100,7 +100,7 @@ void (float timeleft) DropRing = { item.solid = SOLID_TRIGGER; item.movetype = MOVETYPE_TOSS; item.noise = "items/inv1.wav"; - setmodel(item, "progs/invisibl.mdl"); + FO_SetModel(item, "progs/invisibl.mdl"); setsize(item, VEC_HULL_MIN, VEC_HULL_MAX); item.cnt = time + timeleft; item.touch = r_touch; @@ -190,21 +190,21 @@ void () item_health = { if (self.spawnflags & H_ROTTEN) { precache_model("maps/b_bh10.bsp"); precache_sound("items/r_item1.wav"); - setmodel(self, "maps/b_bh10.bsp"); + FO_SetModel(self, "maps/b_bh10.bsp"); self.noise = "items/r_item1.wav"; self.healamount = 15; self.healtype = 0; } else if (self.spawnflags & H_MEGA) { precache_model("maps/b_bh100.bsp"); precache_sound("items/r_item2.wav"); - setmodel(self, "maps/b_bh100.bsp"); + FO_SetModel(self, "maps/b_bh100.bsp"); self.noise = "items/r_item2.wav"; self.healamount = 100; self.healtype = 2; } else { precache_model("maps/b_bh25.bsp"); precache_sound("items/health1.wav"); - setmodel(self, "maps/b_bh25.bsp"); + FO_SetModel(self, "maps/b_bh25.bsp"); self.noise = "items/health1.wav"; self.healamount = 25; self.healtype = 1; @@ -251,7 +251,7 @@ void () health_touch = { s = ftos(self.healamount); sprint(other, PRINT_LOW, "You gather ", s, " medikit ammo\n"); - sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + FO_Sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); stuffcmd(other, "bf\n"); self.model = string_null; self.solid = 0; @@ -277,7 +277,7 @@ void () health_touch = { s = ftos(self.healamount); sprint(other, PRINT_LOW, "You receive ", s, " health\n"); } - sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + FO_Sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); stuffcmd(other, "bf\n"); self.model = string_null; self.solid = 0; @@ -421,7 +421,7 @@ void () armor_touch = { self.nextthink = time + 40; } self.think = SUB_regen; - sound(other, 3, "items/armor1.wav", 1, 1); + FO_Sound(other, CHAN_ITEM, "items/armor1.wav", 1, 1); stuffcmd(other, "bf\n"); activator = other; SUB_UseTargets(); @@ -434,7 +434,7 @@ void () item_armor1 = { } self.touch = armor_touch; precache_model("progs/armor.mdl"); - setmodel(self, "progs/armor.mdl"); + FO_SetModel(self, "progs/armor.mdl"); self.skin = 0; setsize(self, '-16 -16 0', '16 16 56'); StartItem(); @@ -447,7 +447,7 @@ void () item_armor2 = { } self.touch = armor_touch; precache_model("progs/armor.mdl"); - setmodel(self, "progs/armor.mdl"); + FO_SetModel(self, "progs/armor.mdl"); self.skin = 1; setsize(self, '-16 -16 0', '16 16 56'); StartItem(); @@ -460,7 +460,7 @@ void () item_armorInv = { } self.touch = armor_touch; precache_model("progs/armor.mdl"); - setmodel(self, "progs/armor.mdl"); + FO_SetModel(self, "progs/armor.mdl"); self.skin = 2; setsize(self, '-16 -16 0', '16 16 56'); StartItem(); @@ -636,7 +636,7 @@ void () weapon_touch = { } } sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); - sound(other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM); + FO_Sound(other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM); stuffcmd(other, "bf\n"); bound_other_ammo(other); old = other.weapons_carried; @@ -657,7 +657,7 @@ void () weapon_supershotgun = { return; } precache_model("progs/g_shot.mdl"); - setmodel(self, "progs/g_shot.mdl"); + FO_SetModel(self, "progs/g_shot.mdl"); self.weapon = WEAP_SUPER_SHOTGUN; self.netname = "Double-barrelled Shotgun"; self.touch = weapon_touch; @@ -671,7 +671,7 @@ void () weapon_nailgun = { return; } precache_model("progs/g_nail.mdl"); - setmodel(self, "progs/g_nail.mdl"); + FO_SetModel(self, "progs/g_nail.mdl"); self.weapon = 512; self.netname = "nailgun"; self.touch = weapon_touch; @@ -685,7 +685,7 @@ void () weapon_supernailgun = { return; } precache_model("progs/g_nail2.mdl"); - setmodel(self, "progs/g_nail2.mdl"); + FO_SetModel(self, "progs/g_nail2.mdl"); self.weapon = 1024; self.netname = "Super Nailgun"; self.touch = weapon_touch; @@ -699,7 +699,7 @@ void () weapon_grenadelauncher = { return; } precache_model("progs/g_rock.mdl"); - setmodel(self, "progs/g_rock.mdl"); + FO_SetModel(self, "progs/g_rock.mdl"); self.weapon = 3; self.netname = "Grenade Launcher"; self.touch = weapon_touch; @@ -713,7 +713,7 @@ void () weapon_rocketlauncher = { return; } precache_model("progs/g_rock2.mdl"); - setmodel(self, "progs/g_rock2.mdl"); + FO_SetModel(self, "progs/g_rock2.mdl"); self.weapon = 3; self.netname = "Rocket Launcher"; self.touch = weapon_touch; @@ -727,7 +727,7 @@ void () weapon_lightning = { return; } precache_model("progs/g_light.mdl"); - setmodel(self, "progs/g_light.mdl"); + FO_SetModel(self, "progs/g_light.mdl"); self.weapon = 3; self.netname = "Thunderbolt"; self.touch = weapon_touch; @@ -870,7 +870,7 @@ void () ammo_touch = { if (!gotbox && !gotgren) { return; } - sound(other, 3, "weapons/lock4.wav", 1, 1); + FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); if (gotbox) { bound_other_ammo(other); @@ -891,11 +891,11 @@ void () item_shells = { self.touch = ammo_touch; if (self.spawnflags & 1) { precache_model("maps/b_shell1.bsp"); - setmodel(self, "maps/b_shell1.bsp"); + FO_SetModel(self, "maps/b_shell1.bsp"); self.aflag = 40; } else { precache_model("maps/b_shell0.bsp"); - setmodel(self, "maps/b_shell0.bsp"); + FO_SetModel(self, "maps/b_shell0.bsp"); self.aflag = 20; } self.weapon = 1; @@ -912,11 +912,11 @@ void () item_spikes = { self.touch = ammo_touch; if (self.spawnflags & 1) { precache_model("maps/b_nail1.bsp"); - setmodel(self, "maps/b_nail1.bsp"); + FO_SetModel(self, "maps/b_nail1.bsp"); self.aflag = 50; } else { precache_model("maps/b_nail0.bsp"); - setmodel(self, "maps/b_nail0.bsp"); + FO_SetModel(self, "maps/b_nail0.bsp"); self.aflag = 25; } self.weapon = 2; @@ -933,11 +933,11 @@ void () item_rockets = { self.touch = ammo_touch; if (self.spawnflags & 1) { precache_model("maps/b_rock1.bsp"); - setmodel(self, "maps/b_rock1.bsp"); + FO_SetModel(self, "maps/b_rock1.bsp"); self.aflag = 10; } else { precache_model("maps/b_rock0.bsp"); - setmodel(self, "maps/b_rock0.bsp"); + FO_SetModel(self, "maps/b_rock0.bsp"); self.aflag = 5; } self.weapon = 3; @@ -954,11 +954,11 @@ void () item_cells = { self.touch = ammo_touch; if (self.spawnflags & 1) { precache_model("maps/b_batt1.bsp"); - setmodel(self, "maps/b_batt1.bsp"); + FO_SetModel(self, "maps/b_batt1.bsp"); self.aflag = 12; } else { precache_model("maps/b_batt0.bsp"); - setmodel(self, "maps/b_batt0.bsp"); + FO_SetModel(self, "maps/b_batt0.bsp"); self.aflag = 6; } self.weapon = 4; @@ -976,11 +976,11 @@ void () item_weapon = { if (self.spawnflags & 1) { if (self.spawnflags & 8) { precache_model("maps/b_shell1.bsp"); - setmodel(self, "maps/b_shell1.bsp"); + FO_SetModel(self, "maps/b_shell1.bsp"); self.aflag = 40; } else { precache_model("maps/b_shell0.bsp"); - setmodel(self, "maps/b_shell0.bsp"); + FO_SetModel(self, "maps/b_shell0.bsp"); self.aflag = 20; } self.weapon = 1; @@ -989,11 +989,11 @@ void () item_weapon = { if (self.spawnflags & 4) { if (self.spawnflags & 8) { precache_model("maps/b_nail1.bsp"); - setmodel(self, "maps/b_nail1.bsp"); + FO_SetModel(self, "maps/b_nail1.bsp"); self.aflag = 40; } else { precache_model("maps/b_nail0.bsp"); - setmodel(self, "maps/b_nail0.bsp"); + FO_SetModel(self, "maps/b_nail0.bsp"); self.aflag = 20; } self.weapon = 2; @@ -1002,11 +1002,11 @@ void () item_weapon = { if (self.spawnflags & 2) { if (self.spawnflags & 8) { precache_model("maps/b_rock1.bsp"); - setmodel(self, "maps/b_rock1.bsp"); + FO_SetModel(self, "maps/b_rock1.bsp"); self.aflag = 10; } else { precache_model("maps/b_rock0.bsp"); - setmodel(self, "maps/b_rock0.bsp"); + FO_SetModel(self, "maps/b_rock0.bsp"); self.aflag = 5; } self.weapon = 3; @@ -1036,7 +1036,7 @@ void () key_touch = { return; } sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); - sound(other, 3, self.noise, 1, 1); + FO_Sound(other, CHAN_ITEM, self.noise, 1, 1); stuffcmd(other, "bf\n"); other.items = other.items | self.items; if (!coop) { @@ -1074,17 +1074,17 @@ void () item_key1 = { } if (world.worldtype == 0) { precache_model("progs/w_s_key.mdl"); - setmodel(self, "progs/w_s_key.mdl"); + FO_SetModel(self, "progs/w_s_key.mdl"); self.netname = "silver key"; } else { if (world.worldtype == 1) { precache_model("progs/m_s_key.mdl"); - setmodel(self, "progs/m_s_key.mdl"); + FO_SetModel(self, "progs/m_s_key.mdl"); self.netname = "silver runekey"; } else { if (world.worldtype == 2) { precache_model2("progs/b_s_key.mdl"); - setmodel(self, "progs/b_s_key.mdl"); + FO_SetModel(self, "progs/b_s_key.mdl"); self.netname = "silver keycard"; } } @@ -1103,17 +1103,17 @@ void () item_key2 = { } if (world.worldtype == 0) { precache_model("progs/w_g_key.mdl"); - setmodel(self, "progs/w_g_key.mdl"); + FO_SetModel(self, "progs/w_g_key.mdl"); self.netname = "gold key"; } if (world.worldtype == 1) { precache_model("progs/m_g_key.mdl"); - setmodel(self, "progs/m_g_key.mdl"); + FO_SetModel(self, "progs/m_g_key.mdl"); self.netname = "gold runekey"; } if (world.worldtype == 2) { precache_model2("progs/b_g_key.mdl"); - setmodel(self, "progs/b_g_key.mdl"); + FO_SetModel(self, "progs/b_g_key.mdl"); self.netname = "gold keycard"; } key_setsounds(); @@ -1135,7 +1135,7 @@ void () sigil_touch = { if (cb_prematch == 1) return; - sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + FO_Sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); stuffcmd(other, "bf\n"); self.solid = SOLID_NOT; self.model = string_null; @@ -1157,19 +1157,19 @@ void () item_sigil = { self.noise = "misc/runekey.wav"; if (self.spawnflags & 1) { precache_model("progs/end1.mdl"); - setmodel(self, "progs/end1.mdl"); + FO_SetModel(self, "progs/end1.mdl"); } if (self.spawnflags & 2) { precache_model2("progs/end2.mdl"); - setmodel(self, "progs/end2.mdl"); + FO_SetModel(self, "progs/end2.mdl"); } if (self.spawnflags & 4) { precache_model2("progs/end3.mdl"); - setmodel(self, "progs/end3.mdl"); + FO_SetModel(self, "progs/end3.mdl"); } if (self.spawnflags & 8) { precache_model2("progs/end4.mdl"); - setmodel(self, "progs/end4.mdl"); + FO_SetModel(self, "progs/end4.mdl"); } self.touch = sigil_touch; setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); @@ -1210,7 +1210,7 @@ void () powerup_touch = { self.think = SUB_regen; } } - sound(other, 2, self.noise, 1, 1); + FO_Sound(other, CHAN_VOICE, self.noise, 1, 1); stuffcmd(other, "bf\n"); self.solid = 0; other.items = other.items | self.items; @@ -1246,7 +1246,7 @@ void () item_artifact_invulnerability = { precache_sound("items/protect2.wav"); precache_sound("items/protect3.wav"); self.noise = "items/protect.wav"; - setmodel(self, "progs/invulner.mdl"); + FO_SetModel(self, "progs/invulner.mdl"); self.effects = self.effects | EF_RED; self.netname = "Pentagram of Protection"; self.items = IT_INVULNERABILITY; @@ -1264,7 +1264,7 @@ void () item_artifact_envirosuit = { precache_sound("items/suit.wav"); precache_sound("items/suit2.wav"); self.noise = "items/suit.wav"; - setmodel(self, "progs/suit.mdl"); + FO_SetModel(self, "progs/suit.mdl"); self.netname = "Biosuit"; self.items = IT_SUIT; setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); @@ -1282,7 +1282,7 @@ void () item_artifact_invisibility = { precache_sound("items/inv2.wav"); precache_sound("items/inv3.wav"); self.noise = "items/inv1.wav"; - setmodel(self, "progs/invisibl.mdl"); + FO_SetModel(self, "progs/invisibl.mdl"); self.netname = "Ring of Shadows"; self.items = IT_INVISIBILITY; setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); @@ -1300,7 +1300,7 @@ void () item_artifact_super_damage = { precache_sound("items/damage2.wav"); precache_sound("items/damage3.wav"); self.noise = "items/damage.wav"; - setmodel(self, "progs/quaddama.mdl"); + FO_SetModel(self, "progs/quaddama.mdl"); self.effects = self.effects | EF_BLUE; self.netname = "Quad Damage"; self.items = IT_QUAD; @@ -1372,7 +1372,7 @@ void () BackpackTouch = { } } sprint(other, PRINT_LOW, "\n"); - sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); + FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); stuffcmd(other, "bf\n"); dremove(self); self = other; @@ -1423,11 +1423,11 @@ void () DropBackpack = { newmis.flags = FL_ITEM; newmis.solid = SOLID_TRIGGER; newmis.movetype = MOVETYPE_TOSS; - setmodel(newmis, "progs/backpack.mdl"); + FO_SetModel(newmis, "progs/backpack.mdl"); setsize(newmis, '-16 -16 0', '16 16 56'); newmis.touch = BackpackTouch; newmis.classname = "backpack"; newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; +}; \ No newline at end of file diff --git a/ssqc/medic.qc b/ssqc/medic.qc index 0221ebcb..ccb8a4a5 100644 --- a/ssqc/medic.qc +++ b/ssqc/medic.qc @@ -57,7 +57,7 @@ void () CF_Medic_AuraFindPlayers = { } if (f_healtotal) { - sound(self.owner, 3, "items/r_item2.wav", 1, 1); + FO_Sound(self.owner, CHAN_ITEM, "items/r_item2.wav", 1, 1); if (time < self.owner.aura_healtime) self.owner.aura_healamount = self.owner.aura_healamount + f_healtotal; else diff --git a/ssqc/misc.qc b/ssqc/misc.qc index 407d9af1..f8c7c557 100644 --- a/ssqc/misc.qc +++ b/ssqc/misc.qc @@ -166,7 +166,7 @@ void () fire_fly = { newmis.velocity_y = random() * 100 - 50; newmis.velocity_z = self.speed + random() * 200; newmis.classname = "fireball"; - setmodel(newmis, "progs/lavaball.mdl"); + FO_SetModel(newmis, "progs/lavaball.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin); newmis.nextthink = time + 5; @@ -206,7 +206,7 @@ void () misc_explobox = { self.solid = 2; self.movetype = 0; precache_model("maps/b_explob.bsp"); - setmodel(self, "maps/b_explob.bsp"); + FO_SetModel(self, "maps/b_explob.bsp"); setsize(self, '0 0 0', '32 32 64'); precache_sound("weapons/r_exp3.wav"); self.health = 20; @@ -234,7 +234,7 @@ void () misc_explobox2 = { self.solid = 2; self.movetype = 0; precache_model2("maps/b_exbox2.bsp"); - setmodel(self, "maps/b_exbox2.bsp"); + FO_SetModel(self, "maps/b_exbox2.bsp"); setsize(self, '0 0 0', '32 32 32'); precache_sound("weapons/r_exp3.wav"); self.health = 20; @@ -264,7 +264,7 @@ void () Laser_Touch = { dremove(self); return; } - sound(self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC); + FO_Sound(self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC); org = self.origin - 8 * normalize(self.velocity); if (other.health) { SpawnBlood(org, 15); @@ -283,7 +283,7 @@ void () Laser_Touch = { void (vector org, vector vec) LaunchLaser = { if (self.classname == "monster_enforcer") - sound(self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM); vec = normalize(vec); newmis = spawn(); @@ -291,7 +291,7 @@ void (vector org, vector vec) LaunchLaser = { newmis.movetype = MOVETYPE_FLY; newmis.solid = SOLID_BBOX; newmis.effects = EF_DIMLIGHT; - setmodel(newmis, "progs/laser.mdl"); + FO_SetModel(newmis, "progs/laser.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, org); newmis.velocity = vec * 600; @@ -303,10 +303,10 @@ void (vector org, vector vec) LaunchLaser = { void () spikeshooter_use = { if (self.spawnflags & 2) { - sound(self, CHAN_VOICE, "enforcer/enfire.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "enforcer/enfire.wav", 1, ATTN_NORM); LaunchLaser(self.origin, self.movedir); } else { - sound(self, CHAN_VOICE, "weapons/spike2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "weapons/spike2.wav", 1, ATTN_NORM); launch_spike(self.origin, self.movedir); newmis.velocity = self.movedir * 500; @@ -365,7 +365,7 @@ void () air_bubbles = { void () make_bubbles = { newmis = spawn(); - setmodel(newmis, "progs/s_bubble.spr"); + FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, self.origin); newmis.movetype = MOVETYPE_NOCLIP; newmis.solid = SOLID_NOT; @@ -383,7 +383,7 @@ void () make_bubbles = { void () bubble_split = { newmis = spawn(); - setmodel(newmis, "progs/s_bubble.spr"); + FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, self.origin); newmis.movetype = MOVETYPE_NOCLIP; newmis.solid = SOLID_NOT; @@ -453,7 +453,7 @@ void () viewthing = { self.movetype = MOVETYPE_NONE; self.solid = SOLID_NOT; precache_model("progs/player.mdl"); - setmodel(self, "progs/player.mdl"); + FO_SetModel(self, "progs/player.mdl"); }; void () func_wall_use = { @@ -598,13 +598,13 @@ void () ambient_swamp2 = { void () noise_think = { self.nextthink = time + 0.5; - sound(self, 1, "enforcer/enfire.wav", 1, ATTN_NORM); - sound(self, 2, "enforcer/enfstop.wav", 1, ATTN_NORM); - sound(self, 3, "enforcer/sight1.wav", 1, ATTN_NORM); - sound(self, 4, "enforcer/sight2.wav", 1, ATTN_NORM); - sound(self, 5, "enforcer/sight3.wav", 1, ATTN_NORM); - sound(self, 6, "enforcer/sight4.wav", 1, ATTN_NORM); - sound(self, 7, "enforcer/pain1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "enforcer/enfstop.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_ITEM, "enforcer/sight1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "enforcer/sight2.wav", 1, ATTN_NORM); + FO_Sound(self, 5, "enforcer/sight3.wav", 1, ATTN_NORM); + FO_Sound(self, 6, "enforcer/sight4.wav", 1, ATTN_NORM); + FO_Sound(self, 7, "enforcer/pain1.wav", 1, ATTN_NORM); }; @@ -633,13 +633,13 @@ void() blocker_use = { self.state = 1; setorigin(self, self.origin - '8000 8000 8000'); - sound(self, 2, self.noise1, 1, 1); + sound(self, CHAN_VOICE, self.noise1, 1, 1); } else { self.state = 0; setorigin(self, self.origin + '8000 8000 8000'); - sound(self, 2, self.noise, 1, 1); + sound(self, CHAN_VOICE, self.noise, 1, 1); } }; @@ -661,11 +661,11 @@ void() glass_die = new.origin = self.origin; if (random() < 0.5) { - setmodel(new, "progs/glass2.mdl"); + FO_SetModel(new, "progs/glass2.mdl"); } else { - setmodel(new, "progs/glass1.mdl"); + FO_SetModel(new, "progs/glass1.mdl"); } setsize(new, '0 0 0', '0 0 0'); if (self.height != 100) @@ -699,11 +699,11 @@ void() glass_die = { if (pointcontents(self.origin) == -3) { - sound(self, 2, "effects/rcksplsh.wav", 1, 1); + sound(self, CHAN_VOICE, "effects/rcksplsh.wav", 1, 1); } else { - sound(self, 2, self.noise2, 1, 1); + sound(self, CHAN_VOICE, self.noise2, 1, 1); } } remove(self); @@ -806,7 +806,7 @@ void() func_glass = self.state = 1; if (self.noise1) { - sound(self, 2, self.noise1, 1, 1); + sound(self, CHAN_VOICE, self.noise1, 1, 1); } } } diff --git a/ssqc/plats.qc b/ssqc/plats.qc index 83636b46..daf4d877 100644 --- a/ssqc/plats.qc +++ b/ssqc/plats.qc @@ -52,25 +52,25 @@ void () plat_spawn_inside_trigger = { }; void () plat_hit_top = { - sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_TOP; self.think = plat_go_down; self.nextthink = self.ltime + 3; }; void () plat_hit_bottom = { - sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_BOTTOM; }; void () plat_go_down = { - sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_DOWN; SUB_CalcMove(self.pos2, self.speed, plat_hit_bottom); }; void () plat_go_up = { - sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_UP; SUB_CalcMove(self.pos1, self.speed, plat_hit_top); }; @@ -242,7 +242,7 @@ void () train_use = { void () train_wait = { if (self.wait) { self.nextthink = self.ltime + self.wait; - sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); } else self.nextthink = self.ltime + 0.1; @@ -262,7 +262,7 @@ void () train_next = { else self.wait = 0; - sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); SUB_CalcMove(targ.origin - self.mins, self.speed, train_wait); }; diff --git a/ssqc/player.qc b/ssqc/player.qc index 1b00ad9c..274dff41 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -363,7 +363,7 @@ void () player_assaultcannonup1 =[103, player_assaultcannonup2] { } self.fire_held_down = 1; if (self.heat == 1) { - sound(self, 1, "weapons/asscan1.wav", 1, 1); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); } SuperDamageSound(); Attack_Finished(0.2); @@ -424,7 +424,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) <= 30) && !(self.tfstate & TFSTATE_LOCK)) { muzzleflash(); - sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); if (self.weaponframe == 2) self.weaponframe = 4; @@ -440,7 +440,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { W_FireAssaultCannon(); } else { - sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); if (self.weaponframe == 2) self.weaponframe = 0; @@ -501,7 +501,7 @@ void () player_assaultcannon2 =[104, player_assaultcannon1] { void () player_assaultcannondown1 =[103, player_assaultcannondown1] { if (self.count == 1) { - sound(self, 1, "weapons/asscan3.wav", 0.8, 1); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); self.heat = 0; } if (self.count >= 15) { @@ -595,31 +595,31 @@ void () PainSound = { return; } if (damage_attacker.classname == "teledeath") { - sound(self, 2, "player/teledth1.wav", 1, 0); + FO_Sound(self, CHAN_VOICE, "player/teledth1.wav", 1, 0); return; } if ((self.watertype == -3) && (self.waterlevel == 3)) { DeathBubbles(1); if (random() > 0.5) { - sound(self, 2, "player/drown1.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/drown1.wav", 1, 1); } else { - sound(self, 2, "player/drown2.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/drown2.wav", 1, 1); } return; } if (self.watertype == -4) { if (random() > 0.5) { - sound(self, 2, "player/lburn1.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/lburn1.wav", 1, 1); } else { - sound(self, 2, "player/lburn2.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/lburn2.wav", 1, 1); } return; } if (self.watertype == -5) { if (random() > 0.5) { - sound(self, 2, "player/lburn1.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/lburn1.wav", 1, 1); } else { - sound(self, 2, "player/lburn2.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/lburn2.wav", 1, 1); } return; } @@ -630,7 +630,7 @@ void () PainSound = { self.pain_finished = time + 0.5; if (self.axhitme == 1) { self.axhitme = 0; - sound(self, 2, "player/axhit1.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "player/axhit1.wav", 1, 1); return; } rs = rint(((random() * 5) + 1)); @@ -656,7 +656,7 @@ void () PainSound = { } } } - sound(self, 2, self.noise, 1, 1); + FO_Sound(self, CHAN_VOICE, self.noise, 1, 1); return; }; @@ -734,7 +734,7 @@ void () DeathBubblesSpawn = { return; newmis = spawn(); - setmodel(newmis, "progs/s_bubble.spr"); + FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, (self.owner.origin + '0 0 24')); newmis.movetype = 8; newmis.solid = 0; @@ -776,7 +776,7 @@ void () DeathSound = { else DeathBubbles(10); - sound(self, 2, "player/h2odeath.wav", 1, 0); + FO_Sound(self, CHAN_VOICE, "player/h2odeath.wav", 1, 0); return; } rs = rint(random() * 4 + 1); @@ -791,7 +791,7 @@ void () DeathSound = { else self.noise = "player/death5.wav"; - sound(self, 2, self.noise, 1, 0); + FO_Sound(self, CHAN_VOICE, self.noise, 1, 0); return; }; @@ -820,7 +820,7 @@ void (string gibname, float dm) ThrowGib = { newmis = spawn(); newmis.origin = self.origin; - setmodel(newmis, gibname); + FO_SetModel(newmis, gibname); setsize(newmis, '0 0 0', '0 0 0'); newmis.velocity = VelocityForDamage(dm); @@ -840,7 +840,7 @@ void (string gibname, float dm) ThrowGib = { }; void (string gibname, float dm) ThrowHead = { - setmodel(self, gibname); + FO_SetModel(self, gibname); self.skin = 0; self.frame = 0; self.nextthink = -1; @@ -858,7 +858,7 @@ void (string gibname, float dm) ThrowHead = { }; void (string gibname) HeadShotThrowHead = { - setmodel(self, gibname); + FO_SetModel(self, gibname); self.frame = 0; self.nextthink = -1; @@ -894,19 +894,19 @@ void () GibPlayer = { } TeamFortress_SetupRespawn(0); if (damage_attacker.classname == "teledeath") { - sound(self, 2, "player/teledth1.wav", 1, 0); + FO_Sound(self, CHAN_VOICE, "player/teledth1.wav", 1, 0); self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; } if (damage_attacker.classname == "teledeath2") { - sound(self, 2, "player/teledth1.wav", 1, 0); + FO_Sound(self, CHAN_VOICE, "player/teledth1.wav", 1, 0); self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; } if (random() < 0.5) { - sound(self, 2, "player/gib.wav", 1, 0); + FO_Sound(self, CHAN_VOICE, "player/gib.wav", 1, 0); } else { - sound(self, 2, "player/udeath.wav", 1, 0); + FO_Sound(self, CHAN_VOICE, "player/udeath.wav", 1, 0); } }; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 62e4fcc3..59c36fe7 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -28,27 +28,27 @@ entity(string type, entity p_owner) FlameSpawn = newmis.solid = SOLID_BBOX; newmis.effects = EF_DIMLIGHT; newmis.flame_id = "1"; - setmodel(newmis, "progs/flame2.mdl"); + FO_SetModel(newmis, "progs/flame2.mdl"); setsize(newmis, '0 0 0', '0 0 0'); } else if (type == "2") { newmis.movetype = MOVETYPE_BOUNCE; newmis.solid = SOLID_BBOX; newmis.flame_id = "2"; - setmodel(newmis, "progs/flame2.mdl"); + FO_SetModel(newmis, "progs/flame2.mdl"); newmis.frame = 1; setsize(newmis, '0 0 0', '0 0 0'); } else if (type == "3") { newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_BBOX; newmis.flame_id = "3"; - setmodel(newmis, "progs/flame2.mdl"); + FO_SetModel(newmis, "progs/flame2.mdl"); setsize(newmis, '0 0 0', '0 0 0'); } else if (type == "4") { newmis.movetype = MOVETYPE_FLYMISSILE; newmis.flame_id = "4"; newmis.frame = 1; newmis.solid = SOLID_BBOX; - setmodel(newmis, "progs/flame2.mdl"); + FO_SetModel(newmis, "progs/flame2.mdl"); setsize(newmis, '0 0 0', '0 0 0'); } newmis.owner = p_owner; @@ -103,7 +103,7 @@ void () Remove = { void () NapalmGrenadeFollow = { traceline(self.origin, self.origin, TRUE, self); if (trace_inwater == 1) { - sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, ATTN_NORM); FlameDestroy(self); } if (self.velocity == '0 0 0') { @@ -113,7 +113,7 @@ void () NapalmGrenadeFollow = { }; void () NapalmGrenadeTouch = { - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; @@ -144,7 +144,7 @@ void () NapalmGrenadeNetThink = { makevectors(self.v_angle); traceline(self.origin, self.origin, 1, self); if (trace_inwater == 1) { - sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, ATTN_NORM); RemoveGrenade(); return; } @@ -177,7 +177,7 @@ void () NapalmGrenadeNetThink = { void () NapalmGrenadeExplode = { local entity head; - sound(self, CHAN_AUTO, "weapons/flmgrexp.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_AUTO, "weapons/flmgrexp.wav", 1, ATTN_NORM); traceline(self.origin, self.origin, 1, self); if (trace_inwater == 1) { dremove(self); @@ -283,7 +283,7 @@ void () FlameFollow = { setorigin(self, vtemp); if (self.model != "progs/flame2.mdl") { self.model = "progs/flame2.mdl"; - setmodel(self, self.model); + FO_SetModel(self, self.model); } } else { if (self.model == "progs/flame2.mdl") { @@ -292,7 +292,7 @@ void () FlameFollow = { } } if ((self.enemy.waterlevel > 1) || (self.enemy.classname != "player" && self.enemy.waterlevel > 0)) { - sound(self, 2, "misc/vapeur2.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, 1); self.enemy.numflames = self.enemy.numflames - 1; FlameDestroy(self); return; @@ -336,7 +336,7 @@ void () OnPlayerFlame_touch = { } if (other.numflames < 1) { flame = FlameSpawn("1", other); - sound(flame, 2, "ambience/fire1.wav", 1, 1); + FO_Sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, 1); } else { flame = FlameSpawn("3", other); if (flame == world) { @@ -394,7 +394,7 @@ void () WorldFlame_touch = { } if (other.numflames < 1) { flame = FlameSpawn("1", other); - sound(flame, 2, "ambience/fire1.wav", 1, 1); + FO_Sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, 1); } else { flame = FlameSpawn("3", other); if (flame == world) { @@ -455,7 +455,7 @@ void () Flamer_stream_touch = { } if (other.numflames < 1) { flame = FlameSpawn("1", other); - sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, + FO_Sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, ATTN_NORM); } else { flame = FlameSpawn("3", other); @@ -523,7 +523,7 @@ void () Napalm_touch = { (other.team_no == self.owner.team_no)) { return; } - sound(other, CHAN_VOICE, "ambience/fire1.wav", 1, ATTN_NORM); + FO_Sound(other, CHAN_VOICE, "ambience/fire1.wav", 1, ATTN_NORM); CenterPrint(other, "You are on fire!\n"); stuffcmd(other, "bf\n"); } @@ -594,15 +594,15 @@ void () W_FireFlame = { NewBubbles(2, self.origin + v_forward * 64); rn = random(); if (rn < 0.5) { - sound(self, CHAN_WEAPON, "misc/water1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "misc/water1.wav", 1, ATTN_NORM); } else { - sound(self, CHAN_WEAPON, "misc/water2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "misc/water2.wav", 1, ATTN_NORM); } return; } self.ammo_cells = self.ammo_cells - 1; self.currentammo = self.ammo_cells; - sound(self, CHAN_AUTO, "weapons/flmfire2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_AUTO, "weapons/flmfire2.wav", 1, ATTN_NORM); flame = spawn(); flame.owner = self; flame.movetype = MOVETYPE_FLYMISSILE; @@ -614,7 +614,7 @@ void () W_FireFlame = { flame.touch = Flamer_stream_touch; flame.think = s_explode1; flame.nextthink = time + 0.15; - setmodel(flame, "progs/s_explod.spr"); + FO_SetModel(flame, "progs/s_explod.spr"); setsize(flame, '0 0 0', '0 0 0'); setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); }; @@ -696,7 +696,7 @@ void () W_FireIncendiaryCannon = { } self.ammo_rockets = self.ammo_rockets - 3; self.currentammo = self.ammo_rockets; - sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); KickPlayer(-3, self); newmis = spawn(); newmis.owner = self; @@ -717,7 +717,7 @@ void () W_FireIncendiaryCannon = { newmis.nextthink = time + 5; newmis.weapon = DMSG_INCENDIARY; newmis.classname = "pyro_rocket"; - setmodel(newmis, "progs/missile.mdl"); + FO_SetModel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); }; diff --git a/ssqc/q3.qc b/ssqc/q3.qc index fb8bb7ba..13054704 100644 --- a/ssqc/q3.qc +++ b/ssqc/q3.qc @@ -67,7 +67,7 @@ void ActivateQ3Goal(entity trig, float active) { if (targ.state == STATE_INVISIBLE && targ.state != chkstate) { - setmodel(targ, targ.mdl); + FO_SetModel(targ, targ.mdl); } targ.state = chkstate; msg = ""; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d0684d9a..dd323581 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -488,6 +488,7 @@ float burstgren_interval; float burstgren_range; float old_grens; +float fo_flash; float invis_only; float flagem_checked; float cease_fire; @@ -676,4 +677,7 @@ float logfilehandle; float canlog; .string grenadename; .float classtime; -.float goalrunningtime; \ No newline at end of file +.float goalrunningtime; + +// flash stuff +float FO_FlashDimension; \ No newline at end of file diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 3056eab7..a459658d 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -28,12 +28,12 @@ void () CF_Scout_Dash = { makevectors(self.angles); self.velocity = v_forward * 540; self.velocity_z = 181; - sound(self, CHAN_BODY, "dash.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "dash.wav", 1, ATTN_NORM); } void () CanisterTouch = { - sound(self, 1, "weapons/tink1.wav", 1, 1); + FO_Sound(self, CHAN_WEAPON, "weapons/tink1.wav", 1, 1); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; @@ -66,7 +66,7 @@ void () CaltropScatterThink = { self.movetype = MOVETYPE_TOSS; self.touch = CaltropTouch; self.angles = '90 90 90'; - sound(self, CHAN_AUTO, "weapons/tink1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_AUTO, "weapons/tink1.wav", 1, ATTN_NORM); setorigin(self, self.origin); return; } else { @@ -104,7 +104,7 @@ void () ScatterCaltrops = { e.weapon = 10; e.owner = self.owner; e.team_no = self.owner.team_no; - setmodel(e, "progs/caltrop.mdl"); + FO_SetModel(e, "progs/caltrop.mdl"); e.mins = '-4 -4 -8'; e.maxs = '4 4 4'; e.angles = '0 0 0'; @@ -128,39 +128,51 @@ void () ScatterCaltrops = { }; void () FlashGrenadeTouch = { - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; +void StuffFlash(entity te, float amt) +{ + string st = ftos(amt * 10); + string cmd = strcat("v_cshift ", st, " ", st); + cmd = strcat(cmd, " ", st, " ", st, "\n"); + stuffcmd(te, cmd); +} + void () FlashTimer = { local entity te; - local string st; te = self.owner; te.FlashTime = te.FlashTime - 0.6; if (te.FlashTime < 5) { - te.FlashTime = 0; + te.FlashTime = 1; stuffcmd(te, "v_cshift; wait; bf\n"); remove(self); + te.dimension_see = DMN_NOFLASH; + te.dimension_seen = DMN_NOFLASH; return; } - st = ftos(te.FlashTime * 10); - stuffcmd(te, "v_cshift "); - stuffcmd(te, st); - stuffcmd(te, " "); - stuffcmd(te, st); - stuffcmd(te, " "); - stuffcmd(te, st); - stuffcmd(te, " "); - stuffcmd(te, st); - stuffcmd(te, "\n"); + + StuffFlash(te, te.FlashTime); + self.nextthink = time + 0.6; }; +void SetFlashDimension(entity te) +{ + FO_FlashDimension = ((FO_FlashDimension + 1) == 8) ? DMN_FLASH : FO_FlashDimension + 1; + + float playerdimension = 1< 0) { - if (te.FlashTime == 0) { + entity ft; + ft = find(world, classname, "flashtimer"); + float found; + found = FALSE; + + while (ft) + { + if (ft.owner == te) + { + found = TRUE; + ft.nextthink = time + 1; + } + ft = find(ft, classname, "flashtimer"); + } + + if (!found) + { newmis = spawn(); newmis.classname = "timer"; newmis.netname = "flashtimer"; @@ -189,21 +217,17 @@ void () FlashGrenadeExplode = { newmis.think = FlashTimer; newmis.nextthink = time + 1; } - if (te == self.owner) + + if (fo_flash) + te.FlashTime = 10; + else if (te != self.owner) te.FlashTime = 16; else te.FlashTime = 24; - st = ftos(te.FlashTime * 10); - stuffcmd(te, "v_cshift "); - stuffcmd(te, st); - stuffcmd(te, " "); - stuffcmd(te, st); - stuffcmd(te, " "); - stuffcmd(te, st); - stuffcmd(te, " "); - stuffcmd(te, st); - stuffcmd(te, "\n"); + StuffFlash(te, te.FlashTime); + + SetFlashDimension(te); } } } @@ -213,7 +237,7 @@ void () FlashGrenadeExplode = { }; void () ConcussionGrenadeTouch = { - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; @@ -238,7 +262,7 @@ void () OldConcussionGrenadeTimer = { return; } newmis = spawn(); - setmodel(newmis, "progs/s_bubble.spr"); + FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, self.owner.origin); newmis.movetype = 8; newmis.solid = 0; @@ -293,7 +317,7 @@ void () ConcussionGrenadeTimer = { (self.health == 600) || (self.health == 800) || (self.health == 1000)) { newmis = spawn(); - setmodel(newmis, "progs/s_bubble.spr"); + FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, self.owner.origin); newmis.movetype = MOVETYPE_NOCLIP; newmis.solid = SOLID_NOT; diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 701c2745..204b30bf 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -129,7 +129,7 @@ void () Sentry_Rotate = { CheckBelowBuilding(self.trigger_field); self.heat = 1; if (random() < 0.1) - sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, + FO_Sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, ATTN_NORM); } } else { @@ -205,7 +205,7 @@ float () Sentry_FindTarget = { void () Sentry_FoundTarget = { if ((self.ammo_shells > 0) || ((self.ammo_rockets > 0) && (self.weapon == 3))) - sound(self, CHAN_VOICE, "weapons/turrspot.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "weapons/turrspot.wav", 1, ATTN_NORM); Sentry_HuntTarget(); @@ -284,7 +284,7 @@ float () Sentry_Fire = { if ((self.weapon == 3) && (self.ammo_rockets > 0) && (self.super_damage_finished < time)) { Sentry_MuzzleFlash(); - sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); newmis = spawn(); newmis.owner = self; @@ -299,7 +299,7 @@ float () Sentry_Fire = { newmis.nextthink = time + 5; newmis.think = SUB_Remove; - setmodel(newmis, "progs/missile.mdl"); + FO_SetModel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); @@ -316,7 +316,7 @@ float () Sentry_Fire = { return (0); } Sentry_MuzzleFlash(); - sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); deathmsg = DMSG_SENTRYGUN_BULLET; diff --git a/ssqc/sniper.qc b/ssqc/sniper.qc index e3002350..a5d7bb61 100644 --- a/ssqc/sniper.qc +++ b/ssqc/sniper.qc @@ -157,7 +157,7 @@ void () SniperSight_Create = { sight.movetype = MOVETYPE_NOCLIP; sight.solid = SOLID_NOT; - setmodel(sight, "progs/sight.spr"); + FO_SetModel(sight, "progs/sight.spr"); sight.classname = "timer"; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 1f4e8e35..7cf19083 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1007,7 +1007,7 @@ void (entity spy) TeamFortress_SpyCalcName = { }; void () GasGrenadeTouch = { - sound(self, 1, "weapons/bounce.wav", 1, 1); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, 1); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; @@ -1032,7 +1032,7 @@ void () GasGrenadeExplode = { pos = 0; while (pos < 10) { newmis = spawn(); - setmodel(newmis, "progs/s_bubble.spr"); + FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, self.origin); newmis.movetype = 8; newmis.solid = 0; @@ -1337,7 +1337,7 @@ void () W_FireTranq = { newmis.think = SUB_Remove; newmis.nextthink = time + 6; newmis.classname = "proj_tranq"; - setmodel(newmis, "progs/spike.mdl"); + FO_SetModel(newmis, "progs/spike.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); }; @@ -1466,7 +1466,7 @@ void () Spy_DropBackpack = { newmis.flags = FL_ITEM; newmis.solid = SOLID_TRIGGER; newmis.movetype = MOVETYPE_TOSS; - setmodel(newmis, "progs/backpack.mdl"); + FO_SetModel(newmis, "progs/backpack.mdl"); setsize(newmis, '-16 -16 0', '16 16 56'); newmis.touch = BackpackTouch; newmis.classname = "backpack"; diff --git a/ssqc/subs.qc b/ssqc/subs.qc index fefa0757..d0bae51a 100644 --- a/ssqc/subs.qc +++ b/ssqc/subs.qc @@ -1,6 +1,22 @@ void (entity Goal, entity AP) DoGoalWork; void (entity Goal, entity AP) DoGroupWork; +void FO_SetModel(entity e, string fomdl) +{ + //e.dimension_seen = e.dimension_seen - (e.dimension_seen & DMN_FLASH); + e.dimension_seen = DMN_NOFLASH; + setmodel(e, fomdl); +} + +void FO_Sound(entity e, float chan, string samp, float vol, float atten) +{ + float olddimens = e.dimension_seen; + // make the sound go to no flash, so it isn't heard by those that are flashed + e.dimension_seen = DMN_NOFLASH; + sound(e, chan, samp, vol, atten); + e.dimension_seen = olddimens; +} + void () SUB_Null = { }; @@ -148,7 +164,7 @@ void () SUB_UseTargets = { CenterPrint(activator, self.message); if (!self.noise) - sound(activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); + FO_Sound(activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); } if (activator.classname == "player") { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 504905d0..fa4671fc 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -243,7 +243,7 @@ void (float inp) TeamFortress_ChangeClass = { modelindex_null = self.modelindex; setmodel(self, "progs/eyes.mdl"); modelindex_eyes = self.modelindex; - setmodel(self, "progs/player.mdl"); + FO_SetModel(self, "progs/player.mdl"); modelindex_player = self.modelindex; setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); self.view_ofs = '0 0 22'; @@ -794,7 +794,7 @@ void (float inp) TeamFortress_PrimeGrenade = { newmis.touch = FlareGrenadeTouch; newmis.skin = 1; newmis.mdl = "flare"; - setmodel(newmis, "progs/flare.mdl"); + FO_SetModel(newmis, "progs/flare.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin); return; @@ -863,7 +863,7 @@ void (float inp) TeamFortress_PrimeGrenade = { newmis.touch = FlareGrenadeTouch; newmis.skin = 1; newmis.mdl = "flare"; - setmodel(newmis, "progs/flare.mdl"); + FO_SetModel(newmis, "progs/flare.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin); return; @@ -943,7 +943,7 @@ void () TeamFortress_GrenadePrimed = { UpdateClientGrenadeThrown(user); } - sound(user, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + FO_Sound(user, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); KickPlayer(-1, user); newmis = spawn(); newmis.owner = user; @@ -974,14 +974,14 @@ void () TeamFortress_GrenadePrimed = { newmis.grenadename = "normalgrenade"; newmis.skin = 0; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_CONCUSSION) { newmis.touch = ConcussionGrenadeTouch; newmis.think = ConcussionGrenadeExplode; newmis.grenadename = "concussiongrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; @@ -991,21 +991,21 @@ void () TeamFortress_GrenadePrimed = { newmis.grenadename = "nailgrenade"; newmis.skin = 1; newmis.avelocity = '0 300 0'; - setmodel(newmis, "progs/biggren.mdl"); + FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_MIRV) { newmis.touch = MirvGrenadeTouch; newmis.think = MirvGrenadeExplode; newmis.grenadename = "mirvgrenade"; newmis.skin = 0; newmis.avelocity = '0 300 0'; - setmodel(newmis, "progs/biggren.mdl"); + FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; newmis.think = NapalmGrenadeExplode; newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; - setmodel(newmis, "progs/biggren.mdl"); + FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_FLARE) { newmis.touch = FlareGrenadeTouch; newmis.weapon = self.team_no; @@ -1014,21 +1014,21 @@ void () TeamFortress_GrenadePrimed = { newmis.skin = 1; newmis.avelocity = '300 300 300'; newmis.mdl = "flare"; - setmodel(newmis, "progs/flare.mdl"); + FO_SetModel(newmis, "progs/flare.mdl"); } else if (self.weapon == GR_TYPE_GAS) { newmis.touch = GasGrenadeTouch; newmis.think = GasGrenadeExplode; newmis.grenadename = "gasgrenade"; newmis.skin = 3; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_EMP) { newmis.touch = EMPGrenadeTouch; newmis.think = EMPGrenadeExplode; newmis.grenadename = "empgrenade"; newmis.skin = 4; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_CALTROP) { newmis.touch = CanisterTouch; newmis.think = ScatterCaltrops; @@ -1041,7 +1041,7 @@ void () TeamFortress_GrenadePrimed = { newmis.grenadename = "flashgrenade"; newmis.skin = 2; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/hgren2.mdl"); } setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, user.origin); @@ -1530,7 +1530,7 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = max_gren1_scout; self.max_grenades_2 = max_gren2_scout; - if (old_grens == 1) + if (old_grens == 1 || fo_flash == TRUE) self.tp_grenades_1 = GR_TYPE_FLASH; else self.tp_grenades_1 = GR_TYPE_CALTROP; @@ -2589,7 +2589,7 @@ void (float type) TeamFortress_DropAmmo = { newmis.touch = TeamFortress_AmmoboxTouch; newmis.skin = type - 1; - setmodel(newmis, "progs/ammobox.mdl"); + FO_SetModel(newmis, "progs/ammobox.mdl"); }; void () TeamFortress_AmmoboxTouch = { @@ -2616,7 +2616,7 @@ void () TeamFortress_AmmoboxTouch = { other.ammo_cells = other.ammo_cells + self.ammo_cells; dremove(self); bound_other_ammo(other); - sound(other, 3, "weapons/lock4.wav", 1, 1); + FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); self = other; W_SetCurrentAmmo(self); @@ -2705,7 +2705,7 @@ void () TeamFortress_AmmoboxTouch = { dremove(self); } bound_other_ammo(other); - sound(other, 3, "weapons/lock4.wav", 1, 1); + FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); self = other; W_SetCurrentAmmo(self); @@ -2761,14 +2761,14 @@ void () TeamFortress_ExplodePerson = { newmis.grenadename = "normalgrenade"; newmis.skin = 0; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_CONCUSSION) { newmis.touch = ConcussionGrenadeTouch; newmis.think = ConcussionGrenadeExplode; newmis.grenadename = "concussiongrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; @@ -2778,21 +2778,21 @@ void () TeamFortress_ExplodePerson = { newmis.grenadename = "nailgrenade"; newmis.skin = 1; newmis.avelocity = '0 300 0'; - setmodel(newmis, "progs/biggren.mdl"); + FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_MIRV) { newmis.touch = MirvGrenadeTouch; newmis.think = MirvGrenadeExplode; newmis.grenadename = "mirvgrenade"; newmis.skin = 0; newmis.avelocity = '0 300 0'; - setmodel(newmis, "progs/biggren.mdl"); + FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; newmis.think = NapalmGrenadeExplode; newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; - setmodel(newmis, "progs/biggren.mdl"); + FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_FLARE) { sprint(self.owner, PRINT_HIGH, "Flare lit\n"); newmis.grenadename = "flaregrenade"; @@ -2812,14 +2812,14 @@ void () TeamFortress_ExplodePerson = { newmis.grenadename = "gasgrenade"; newmis.skin = 2; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_EMP) { newmis.touch = EMPGrenadeTouch; newmis.think = EMPGrenadeExplode; newmis.grenadename = "empgrenade"; newmis.skin = 4; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/grenade2.mdl"); } else if (self.weapon == GR_TYPE_CALTROP) { newmis.touch = CaltropTouch; newmis.think = ScatterCaltrops; @@ -2830,7 +2830,7 @@ void () TeamFortress_ExplodePerson = { newmis.grenadename = "flashgrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; - setmodel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/grenade2.mdl"); } setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.owner.origin); @@ -2877,7 +2877,7 @@ void () NormalGrenadeTouch = { if (other == self.owner) return; - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index ce5c150c..7dd1e62a 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -411,7 +411,7 @@ void () info_tfgoal = { if (self.mdl) { precache_model(self.mdl); precache_model2(self.mdl); - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); } if (self.noise) { precache_sound(self.noise); @@ -457,7 +457,7 @@ void () info_tfgoal_timer = { if (self.mdl) { precache_model(self.mdl); precache_model2(self.mdl); - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); } if (self.noise) { precache_sound(self.noise); @@ -494,7 +494,7 @@ void () item_tfgoal = { if (self.mdl) { precache_model(self.mdl); precache_model2(self.mdl); - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); } else { self.mdl = ""; setmodel(self, ""); @@ -657,7 +657,7 @@ void (entity Goal) InactivateGoal = { } Goal.goal_state = 2; if (Goal.mdl != string_null && !(duelmode && duel_no_packs)) { - setmodel(Goal, Goal.mdl); + FO_SetModel(Goal, Goal.mdl); } } }; @@ -676,7 +676,7 @@ void (entity Goal) RestoreGoal = { } Goal.goal_state = 2; if (Goal.model) { - setmodel(Goal, Goal.mdl); + FO_SetModel(Goal, Goal.mdl); setsize(Goal, Goal.goal_min, Goal.goal_max); entity oldself; oldself = self; @@ -691,7 +691,7 @@ void (entity Goal) RemoveGoal = { Goal.solid = 0; Goal.goal_state = 3; if (Goal.mdl != string_null) - setmodel(Goal, string_null); + FO_SetModel(Goal, string_null); }; float (entity Goal, entity Player, entity AP) IsAffectedBy = { @@ -1018,7 +1018,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } if (Player.numflames > 0) { - sound(Player, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); + FO_Sound(Player, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); Player.numflames = 0; } @@ -1746,9 +1746,9 @@ void (entity Goal, entity AP, float addb) DoResults = { if (Goal.noise) { if (other == world) { - sound(Goal, 3, Goal.noise, 1, 1); + FO_Sound(Goal, CHAN_ITEM, Goal.noise, 1, 1); } else { - sound(other, 3, Goal.noise, 1, 1); + FO_Sound(other, CHAN_ITEM, Goal.noise, 1, 1); } } winners = 0; @@ -2078,7 +2078,7 @@ void () CF_FlagFollowPlayer = { self.owner.origin_z = self.owner.origin_z - 6; } setorigin(self.owner, self.owner.origin); - setmodel(self.owner, self.owner.mdl); + FO_SetModel(self.owner, self.owner.mdl); self.nextthink = time + 0.1; } else { dremove(self); @@ -2129,9 +2129,9 @@ void () item_tfgoal_touch = { self.solid = 1; self.touch = item_tfgoal_touch; self.origin = self.oldorigin; - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); setorigin(self, self.origin); - sound(self, 2, "items/itembk2.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "items/itembk2.wav", 1, 1); return; } } else { @@ -2160,9 +2160,9 @@ void () item_tfgoal_touch = { self.solid = 1; self.touch = item_tfgoal_touch; self.origin = self.oldorigin; - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); setorigin(self, self.origin); - sound(self, 2, "items/itembk2.wav", 1, 1); + FO_Sound(self, CHAN_VOICE, "items/itembk2.wav", 1, 1); return; } } else { @@ -2280,14 +2280,14 @@ void () ReturnItem = { self = self.enemy; TF_Item_ApplyGlow(); self = oldself; - setmodel(self.enemy, self.enemy.mdl); + FO_SetModel(self.enemy, self.enemy.mdl); } setsize(self.enemy, VEC_HULL_MIN, VEC_HULL_MAX); setorigin(self.enemy, self.enemy.origin); tfgoalitem_checkgoalreturn(self.enemy); - sound(self.enemy, 2, "items/itembk2.wav", 1, 1); + FO_Sound(self.enemy, CHAN_VOICE, "items/itembk2.wav", 1, 1); if (self.weapon != 2) { if ((self.enemy.noise3) || (self.enemy.noise4)) { @@ -2482,7 +2482,7 @@ void () tfgoalitem_dropthink = { self.solid = 1; } if (self.mdl != string_null) { - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); } setsize(self, self.goal_min, self.goal_max); self.camdist = self.camdist + 1; @@ -2529,7 +2529,7 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { Item.solid = 1; } if (Item.mdl != string_null) { - setmodel(Item, Item.mdl); + FO_SetModel(Item, Item.mdl); } setsize(Item, Item.goal_min, Item.goal_max); if (PAlive == 1) { @@ -2664,7 +2664,7 @@ void () item_flag_team2 = { } self.skin = 0; - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); self.goal_no = 1; self.goal_activation = TFGI_GLOW | TFGI_DROP | TFGI_REMOVE | TFGI_RETURN_REMOVE | @@ -2740,7 +2740,7 @@ void () item_flag_team1 = { self.origin_z = self.origin_z + 6; } - setmodel(self, self.mdl); + FO_SetModel(self, self.mdl); self.skin = 1; self.goal_no = 2; self.goal_activation = 1 | 4 | 128 | 32 | 16 | 512; diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index e78a930f..cd1a1cf1 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -29,7 +29,7 @@ void () multi_trigger = { WriteByte(MSG_ALL, SVC_FOUNDSECRET); } if (self.noise) { - sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); } self.takedamage = DAMAGE_NO; activator = self.enemy; @@ -229,7 +229,7 @@ void () play_teleport = { else tmpstr = "misc/r_tele5.wav"; - sound(self, CHAN_VOICE, tmpstr, 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, tmpstr, 1, ATTN_NORM); remove(self); }; @@ -446,7 +446,7 @@ void () trigger_onlyregistered_touch = { remove(self); } else if (self.message != "") { CenterPrint(other, self.message); - sound(other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); + FO_Sound(other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); } }; @@ -515,7 +515,7 @@ void () trigger_push_touch = { { if (other.classname == "grenade" || other.health > 0) { - sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); + FO_Sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); other.velocity = self.movedir; } } @@ -528,7 +528,7 @@ void () trigger_push_touch = { if (other.classname == "player") { if (other.fly_sound < time) { other.fly_sound = time + 1.5; - sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); + FO_Sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); } } } diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 178ba90d..e9ed2599 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -13,7 +13,7 @@ void () NailGrenadeTouch = { return; // If the Nail Grenade hits a player, it just bounces off - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; }; @@ -141,7 +141,7 @@ void () NailGrenLaser = { //using self.playerclass to count thinks TF_T_Damage(trace_ent, self, self.real_owner, lasergren_damage, TF_TD_NOTTEAM, TF_TD_ELECTRICITY); } if (self.t_width < time) { - sound(self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); self.t_width = time + 0.8; } diff --git a/ssqc/vote.qc b/ssqc/vote.qc index ae706b11..04c75331 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -38,6 +38,7 @@ float (string ps_list) List_Count; string (string ps_list, float pf_idx) List_Index; string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; void (entity ent) TeamFortress_SetSpeed; +void FO_Sound(entity e, float chan, string samp, float vol, float atten); // opens the map voting early @@ -1179,7 +1180,7 @@ void () AnarchyMode = { e = find(e, classname, "player"); } bprint(PRINT_HIGH, "\bDemocracy has failed!\b Let the result be decided in \bBATTLE\b\n"); - sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); //e = spawn(); //e.classname = "anarchy_timer"; //e.think = anarchy_timer_think; @@ -1246,7 +1247,7 @@ float () CheckVoting = { if(numplayers <= 0 || votedplayers <= 0) { bprint(PRINT_HIGH, "\bVoting reset...\b\n"); - sound(self, CHAN_AUTO, "items/qpi2.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "items/qpi2.wav", 1, ATTN_NONE); EndVoting(); return FALSE; } @@ -1256,13 +1257,13 @@ float () CheckVoting = { //unanimous - change immediately if(e.cnt >= totalplayers) { bprint(PRINT_HIGH, "\bUnanimous choice:\b ", e.netname, "\n"); - sound(self, CHAN_AUTO, "shalrath/death.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "shalrath/death.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); return FALSE; } else if(vote_anarchy_mode) { if(e.cnt >= numplayers) { bprint(PRINT_HIGH, "\bAnarchy succeeded!\b Winner by combat: ", e.netname, "\n"); - sound(self, CHAN_AUTO, "shalrath/attack2.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "shalrath/attack2.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); return FALSE; } @@ -1270,7 +1271,7 @@ float () CheckVoting = { // do we want this to trigger during anarchy too when hitting majority? if(e.cnt > (numplayers/2)) { bprint(PRINT_HIGH, "\bTime's up!\b Majority choice: ", e.netname, "\n"); - sound(self, CHAN_AUTO, "blob/sight1.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "blob/sight1.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); return FALSE; } else { @@ -1313,13 +1314,13 @@ void() vote_think = { if(CheckVoting()) { if(vote_anarchy_mode) { bprint(PRINT_HIGH, "\bANARCHY MODE!\b\n"); - sound(self, CHAN_AUTO, "items/damage.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "items/damage.wav", 1, ATTN_NONE); self.nextthink = time + 5; } else { local float expires = ceil(voting_expires - time); if(expires < 10 || expires % 30 == 0) { bprint(PRINT_HIGH, "\x10",ftos(expires),"\x11 seconds left\n"); - sound(self, CHAN_AUTO, "buttons/switch04.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "buttons/switch04.wav", 1, ATTN_NONE); } self.nextthink = time + 1; } @@ -1337,7 +1338,7 @@ void () StartVoting = { vote_anarchy_mode = FALSE; vote_total_votes = 0; bprint(PRINT_HIGH, "Voting has started!\n"); - sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); if(expires) { bprint(PRINT_HIGH, "Voting closes in ", ftos(expires), " seconds. \bBe quick!\b\n"); voting_expires = time + expires; @@ -1364,7 +1365,7 @@ void (entity p, string vote) VoteForMap = { bprint(PRINT_HIGH, p.netname, " changes vote to \b", vote, "\b\n"); p.vote_map.cnt--; } else { - sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, p.netname, " has voted for \b", vote, "\b\n"); vote_total_votes++; } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fc0102f9..1beeaa84 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -215,7 +215,7 @@ void () W_FireAxe = { } } } else { // hit wall - sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_GUNSHOT); WriteByte(MSG_MULTICAST, 3); @@ -262,7 +262,7 @@ void () W_FireSpanner = { AttemptToActivate(te, self, trace_ent); } else { - sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_GUNSHOT); WriteByte(MSG_MULTICAST, 3); @@ -317,7 +317,7 @@ void () W_FireSpanner = { self.ammo_cells = self.ammo_cells - healam; - sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, + FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); @@ -340,7 +340,7 @@ void () W_FireSpanner = { TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); } } else { - sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_GUNSHOT); WriteByte(MSG_MULTICAST, 3); @@ -499,7 +499,7 @@ void () W_FireMedikit = { } if (trace_ent.numflames > 0) { - sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, + FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); trace_ent.numflames = 0; @@ -513,7 +513,7 @@ void () W_FireMedikit = { if (healam > 0 && trace_ent.health < trace_ent.max_health) { - sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); + FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); trace_ent.axhitme = 1; SpawnBlood(org, 20); T_Heal(trace_ent, healam, 0); @@ -525,7 +525,7 @@ void () W_FireMedikit = { healam = self.ammo_medikit * 5; if (healam > 0) { - sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); + FO_Sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); T_Heal(trace_ent, healam, 1); self.ammo_medikit = self.ammo_medikit - rint(healam / 5); @@ -546,12 +546,12 @@ void () W_FireMedikit = { self.ammo_cells = 0; if (trace_ent.saveme_time <= (time - PC_MEDIC_SAVEME_GRACE)) self.regen_cooldown = time + PC_MEDIC_CELL_REGEN_CD; - sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); + FO_Sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); } else { healam = min(10, ((trace_ent.max_health + 50) - trace_ent.health)); self.ammo_cells = self.ammo_cells - min(self.ammo_cells, ceil((PC_MEDIC_MAXAMMO_CELL / 20))); - sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); + FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); } if (self.current_weapon == WEAP_MEDIKIT) @@ -598,7 +598,7 @@ void () W_FireMedikit = { } } else { // hit wall - sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_GUNSHOT); WriteByte(MSG_MULTICAST, 3); @@ -635,7 +635,7 @@ void (vector org, vector vel) SpawnMeatSpray = { missile.avelocity = '3000 1000 2000'; missile.nextthink = time + 1; missile.think = SUB_Remove; - setmodel(missile, "progs/zom_gib.mdl"); + FO_SetModel(missile, "progs/zom_gib.mdl"); setsize(missile, '0 0 0', '0 0 0'); setorigin(missile, org); }; @@ -777,7 +777,7 @@ void (float shotcount, vector dir, vector spread) FireBullets = { void () W_FireShotgun = { local vector dir; - sound(self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM); KickPlayer(-2, self); self.ammo_shells = self.ammo_shells - 1; @@ -794,7 +794,7 @@ void () W_FireSuperShotgun = { W_FireShotgun(); return; } - sound(self, CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM); KickPlayer(-4, self); self.ammo_shells = self.ammo_shells - 2; @@ -835,7 +835,7 @@ void () W_FireSniperRifle = { local vector h; dir = '0 0 0'; - sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); KickPlayer(-2, self); self.ammo_shells = self.ammo_shells - 1; self.currentammo = self.ammo_shells; @@ -936,7 +936,7 @@ void () W_FireSniperRifle = { void () W_FireAutoRifle = { local vector dir; - sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); KickPlayer(-1, self); self.ammo_shells = self.ammo_shells - 1; @@ -980,9 +980,9 @@ void (entity pe_flame) CF_ExtinguishFlame = { rn = random(); if (rn < 0.5) { - sound(pe_flame, CHAN_VOICE, "misc/water1.wav", 1, ATTN_NORM); + FO_Sound(pe_flame, CHAN_VOICE, "misc/water1.wav", 1, ATTN_NORM); } else { - sound(pe_flame, CHAN_VOICE, "misc/water2.wav", 1, ATTN_NORM); + FO_Sound(pe_flame, CHAN_VOICE, "misc/water2.wav", 1, ATTN_NORM); } dremove(pe_flame); }; @@ -1078,7 +1078,7 @@ void () T_MissileTouch = { void () W_FireRocket = { self.ammo_rockets = self.ammo_rockets - 1; self.currentammo = self.ammo_rockets; - sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); KickPlayer(-2, self); newmis = spawn(); @@ -1099,7 +1099,7 @@ void () W_FireRocket = { newmis.weapon = DMSG_ROCKETL; newmis.classname = "proj_rocket"; - setmodel(newmis, "progs/missile.mdl"); + FO_SetModel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); }; @@ -1166,7 +1166,7 @@ void () W_FireLightning = { return; } if (self.t_width < time) { - sound(self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); self.t_width = time + 0.6; } KickPlayer(-2, self); @@ -1237,7 +1237,7 @@ void () GrenadeTouch = { GrenadeExplode(); return; } - sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') self.avelocity = '0 0 0'; @@ -1271,7 +1271,7 @@ void () ExplodeOldestPipebomb = { void () W_FireGrenade = { self.ammo_rockets = self.ammo_rockets - 1; self.currentammo = self.ammo_rockets; - sound(self, 1, "weapons/grenade.wav", 1, 1); + FO_Sound(self, CHAN_WEAPON, "weapons/grenade.wav", 1, 1); KickPlayer(-2, self); newmis = spawn(); newmis.voided = 0; @@ -1310,7 +1310,7 @@ void () W_FireGrenade = { newmis.avelocity = '300 300 300'; newmis.angles = vectoangles(newmis.velocity); newmis.think = GrenadeExplode; - setmodel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/grenade2.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin); }; @@ -1331,7 +1331,7 @@ void (vector org, vector dir) launch_spike = { newmis.classname = "spike"; newmis.think = SUB_Remove; newmis.nextthink = time + 6; - setmodel(newmis, "progs/spike.mdl"); + FO_SetModel(newmis, "progs/spike.mdl"); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin(newmis, org); @@ -1341,7 +1341,7 @@ void (vector org, vector dir) launch_spike = { void () W_FireSuperSpikes = { local vector dir; - sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); if (old_ng_rof) self.ammo_nails = self.ammo_nails - 4; @@ -1353,7 +1353,7 @@ void () W_FireSuperSpikes = { LogEventAttack(self); newmis.touch = superspike_touch; newmis.weapon = DMSG_SNAILGUN; - setmodel(newmis, "progs/s_spike.mdl"); + FO_SetModel(newmis, "progs/s_spike.mdl"); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); KickPlayer(-3, self); }; @@ -1371,7 +1371,7 @@ void (float ox) W_FireSpikes = { W_ChangeToBestWeapon(); return; } - sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); if ((self.ammo_nails == 1) || !old_ng_rof) { self.ammo_nails = self.ammo_nails - 1; self.currentammo = self.ammo_nails; @@ -1955,7 +1955,7 @@ void () W_Attack = { if (self.current_weapon == WEAP_AXE) { Attack_Finished(0.5); - sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.25) player_axe1(); @@ -1967,7 +1967,7 @@ void () W_Attack = { player_axed1(); } else if (self.current_weapon == WEAP_SPANNER) { Attack_Finished(0.5); - sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); player_axe1(); } else if (self.current_weapon == WEAP_SHOTGUN) { if (CheckForReload() == TRUE) @@ -2012,7 +2012,7 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_LIGHTNING) { player_light1(); Attack_Finished(0.1); - sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.flags & FL_ONGROUND) { if (CheckForReload() == TRUE) @@ -2073,7 +2073,7 @@ void () W_Attack = { self.antispam_incendiary_cannon = time + 3; } } else if (self.current_weapon == WEAP_MEDIKIT) { - sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.25) player_medikit1(); @@ -2085,12 +2085,12 @@ void () W_Attack = { player_medikitd1(); Attack_Finished(0.5); } else if (self.current_weapon == WEAP_TRANQ) { - sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); player_shot1(); W_FireTranq(); Attack_Finished(1.5); } else if (self.current_weapon == WEAP_LASER) { - sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireLaser(); Attack_Finished(0.4); @@ -3496,7 +3496,7 @@ void () SuperDamageSound = { if (self.super_damage_finished > time) { if (self.super_sound < time) { self.super_sound = time + 1; - sound(self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM); } } return; diff --git a/ssqc/world.qc b/ssqc/world.qc index 03a2242e..ebb9811e 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -121,6 +121,7 @@ entity lastspawn; void WorldSpawnPost() { loadloc(); + FO_FlashDimension = -1; dremove(self); } @@ -353,6 +354,8 @@ void () worldspawn = { } else { } } + + dimension_send = DMN_NOFLASH; }; void () StartFrame = { @@ -402,3 +405,18 @@ void (entity ent) CopyToBodyQue = { setsize(bodyque_head, ent.mins, ent.maxs); bodyque_head = bodyque_head.owner; }; + + +// this is used for spawning world objects on map load.. not player, projectiles etc - also disables the engine's conditional spawning based on spawnflags, you're expected to do that part yourself +void(void() fnc)CheckSpawn = { + if(fnc) + { + self.dimension_seen = DMN_NOFLASH | DMN_FLASH; + //bprint(PRINT_HIGH, strcat("spawning: ", self.classname, "\n")); + fnc(); + } + else + { + remove(self); + } +}; \ No newline at end of file From f2c54963a5b383762cceaea5fd1c62f9d0dda31b Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 16 Apr 2020 21:13:44 +1000 Subject: [PATCH 0936/2474] remove icon code from other branch --- ssqc/spy.qc | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 7cf19083..006ea4b5 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -705,23 +705,6 @@ void () CF_Spy_DisguiseLast = { }; void (entity own) Spy_SetClientSkins = { - entity icon, ownicon; - icon = find(world, classname, "spyicon"); - while (icon) - { - if (icon.owner == own) - ownicon = icon; - icon = find(icon, classname, "spyicon"); - } - - if (!ownicon) - { - ownicon = spawn(); - ownicon.owner = own; - ownicon.classname = "spyicon"; - ownicon.movetype = MOVETYPE_FOLLOW; - } - entity te; string color, dcolor, skin, dskin, sendcolor, sendskin, pteam, dsteam, sendteam; float dteam, dpc; From 7f890670f4f904be9766764ea715c6499ed3cf5d Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 16 Apr 2020 21:50:05 +1000 Subject: [PATCH 0937/2474] put a time setting on --- ssqc/scout.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index a459658d..8237fe66 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -10,6 +10,7 @@ void () FlashTimer; void () FlashGrenadeExplode; void () ConcussionGrenadeTouch; void () ConcussionGrenadeExplode; +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce; @@ -219,7 +220,11 @@ void () FlashGrenadeExplode = { } if (fo_flash) - te.FlashTime = 10; + { + float fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "10"); + te.FlashTime = fo_flashtime; + } + else if (te != self.owner) te.FlashTime = 16; else From 046b15df766393019c13b664d391faa2e3361020 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 17 Apr 2020 16:30:37 +1000 Subject: [PATCH 0938/2474] apply damage and duration based on distance from gren --- ssqc/scout.qc | 110 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 26 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 8237fe66..902f49e6 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -172,26 +172,22 @@ void SetFlashDimension(entity te) te.dimension_seen = playerdimension | DMN_NOFLASH; } -void () FlashGrenadeExplode = { - local entity te; - - self.effects = self.effects | EF_BRIGHTLIGHT; - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_TAREXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); - - te = findradius(self.origin, 300); +void FO_FlashExplode() +{ + vector org; + float dam, frac; + entity te; + float rad = 300; + te = findradius(self.origin, rad); while (te) { if (te.classname == "player") { traceline(self.origin, te.origin, 1, self); if (trace_fraction == 1) { - if (vlen(self.origin - te.origin) <= 200) { - deathmsg = DMSG_GREN_FLASH; - TF_T_Damage(te, self, self.owner, 60, 2, 16 | 4); - } + org = te.origin + (te.mins + te.maxs) * 0.5; + frac = (rad - vlen(self.origin - org)) / rad; + dam = 60 * frac; + TF_T_Damage(te, self, self.owner, dam, 0, TF_TD_OTHER); + if (te.health > 0) { entity ft; ft = find(world, classname, "flashtimer"); @@ -219,16 +215,9 @@ void () FlashGrenadeExplode = { newmis.nextthink = time + 1; } - if (fo_flash) - { - float fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "10"); - te.FlashTime = fo_flashtime; - } - - else if (te != self.owner) - te.FlashTime = 16; - else - te.FlashTime = 24; + float fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "10"); + fo_flashtime = fo_flashtime * frac; + te.FlashTime = fo_flashtime; StuffFlash(te, te.FlashTime); @@ -238,6 +227,75 @@ void () FlashGrenadeExplode = { } te = te.chain; } +} + +void () FlashGrenadeExplode = { + local entity te; + + self.effects = self.effects | EF_BRIGHTLIGHT; + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_TAREXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PHS); + + if (fo_flash) + { + FO_FlashExplode(); + } + else + { + te = findradius(self.origin, 300); + while (te) { + if (te.classname == "player") { + traceline(self.origin, te.origin, 1, self); + if (trace_fraction == 1) { + if (vlen(self.origin - te.origin) <= 200) { + TF_T_Damage(te, self, self.owner, 60, 2, 16 | 4); + } + if (te.health > 0) { + entity ft; + ft = find(world, classname, "flashtimer"); + float found; + found = FALSE; + + while (ft) + { + if (ft.owner == te) + { + found = TRUE; + ft.nextthink = time + 1; + } + ft = find(ft, classname, "flashtimer"); + } + + if (!found) + { + newmis = spawn(); + newmis.classname = "timer"; + newmis.netname = "flashtimer"; + newmis.team_no = self.owner.team_no; + newmis.owner = te; + newmis.think = FlashTimer; + newmis.nextthink = time + 1; + } + + if (te != self.owner) + te.FlashTime = 16; + else + te.FlashTime = 24; + + StuffFlash(te, te.FlashTime); + + SetFlashDimension(te); + } + } + } + te = te.chain; + } + } + dremove(self); }; From 70c5bb3cbed67a8629277608eb15cb1b82b8d121 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 17 Apr 2020 21:07:52 +1000 Subject: [PATCH 0939/2474] separate out fo flash timer so values make more sense... --- ssqc/scout.qc | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 902f49e6..5b7f6a70 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -136,7 +136,7 @@ void () FlashGrenadeTouch = { void StuffFlash(entity te, float amt) { - string st = ftos(amt * 10); + string st = ftos(amt); string cmd = strcat("v_cshift ", st, " ", st); cmd = strcat(cmd, " ", st, " ", st, "\n"); stuffcmd(te, cmd); @@ -156,11 +156,30 @@ void () FlashTimer = { return; } - StuffFlash(te, te.FlashTime); + StuffFlash(te, (te.FlashTime*10)); self.nextthink = time + 0.6; }; +void FO_FlashTimer() +{ + local entity te; + + te = self.owner; + te.FlashTime = te.FlashTime - .1; + if (te.FlashTime <= 0) { + stuffcmd(te, "v_cshift; wait; bf\n"); + remove(self); + te.dimension_see = DMN_NOFLASH; + te.dimension_seen = DMN_NOFLASH; + return; + } + + StuffFlash(te, (te.FlashTime*10)); + + self.nextthink = time + .1; +} + void SetFlashDimension(entity te) { FO_FlashDimension = ((FO_FlashDimension + 1) == 8) ? DMN_FLASH : FO_FlashDimension + 1; @@ -199,7 +218,7 @@ void FO_FlashExplode() if (ft.owner == te) { found = TRUE; - ft.nextthink = time + 1; + ft.nextthink = time + .1; } ft = find(ft, classname, "flashtimer"); } @@ -211,15 +230,15 @@ void FO_FlashExplode() newmis.netname = "flashtimer"; newmis.team_no = self.owner.team_no; newmis.owner = te; - newmis.think = FlashTimer; - newmis.nextthink = time + 1; + newmis.think = FO_FlashTimer; + newmis.nextthink = time + .1; } - float fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "10"); - fo_flashtime = fo_flashtime * frac; + float fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "2"); + fo_flashtime = fo_flashtime * (frac + frac * 0.5); // fall off is awful, let's half it te.FlashTime = fo_flashtime; - StuffFlash(te, te.FlashTime); + StuffFlash(te, (te.FlashTime * 10)); SetFlashDimension(te); } @@ -286,7 +305,7 @@ void () FlashGrenadeExplode = { else te.FlashTime = 24; - StuffFlash(te, te.FlashTime); + StuffFlash(te, (te.FlashTime * 10)); SetFlashDimension(te); } From 4436a2c420326d6e2fbf444550d64d442cae95ac Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 17 Apr 2020 21:55:52 +1000 Subject: [PATCH 0940/2474] make it so specs can always see through flash --- ssqc/spect.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 3941da7b..3a541944 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -124,6 +124,9 @@ void () SpectatorImpulseCommand = { }; void () SpectatorThink = { + + self.dimension_see = DMN_NOFLASH; + if (self.impulse) SpectatorImpulseCommand(); From 9b2cb31021648cc7cdc83bb9e057bbdc437760f6 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 17 Apr 2020 21:58:57 +1000 Subject: [PATCH 0941/2474] fix death messages --- ssqc/scout.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 5b7f6a70..84448e1b 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -205,6 +205,7 @@ void FO_FlashExplode() org = te.origin + (te.mins + te.maxs) * 0.5; frac = (rad - vlen(self.origin - org)) / rad; dam = 60 * frac; + deathmsg = DMSG_GREN_FLASH; TF_T_Damage(te, self, self.owner, dam, 0, TF_TD_OTHER); if (te.health > 0) { @@ -271,6 +272,7 @@ void () FlashGrenadeExplode = { traceline(self.origin, te.origin, 1, self); if (trace_fraction == 1) { if (vlen(self.origin - te.origin) <= 200) { + deathmsg = DMSG_GREN_FLASH; TF_T_Damage(te, self, self.owner, 60, 2, 16 | 4); } if (te.health > 0) { From 1fc1f267b24586a09524011f6a5210b9b072679c Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 17 Apr 2020 22:29:06 +1000 Subject: [PATCH 0942/2474] fix damage call --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 84448e1b..cea2a5da 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -206,7 +206,7 @@ void FO_FlashExplode() frac = (rad - vlen(self.origin - org)) / rad; dam = 60 * frac; deathmsg = DMSG_GREN_FLASH; - TF_T_Damage(te, self, self.owner, dam, 0, TF_TD_OTHER); + TF_T_Damage(te, self, self.owner, dam, 2, 16 | 4); if (te.health > 0) { entity ft; From e69e208bb0bcc208dfa50288a8817c543a56289f Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 18 Apr 2020 12:16:12 +1000 Subject: [PATCH 0943/2474] fix for client view at 0 0 0 if server in votemode --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 181f7320..93c5669e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1636,6 +1636,8 @@ void () PutClientInServer = { self.immune_to_check = time + 10; self.fire_held_down = 0; + self.dimension_see = DMN_NOFLASH; + self.dimension_seen = DMN_NOFLASH - (DMN_NOFLASH & DMN_FLASH); setmodel(self, string_null); modelindex_null = self.modelindex; @@ -1783,8 +1785,6 @@ void () PutClientInServer = { setmodel(self, "progs/player.mdl"); modelindex_player = self.modelindex; - self.dimension_see = DMN_NOFLASH; - self.dimension_seen = DMN_NOFLASH - (DMN_NOFLASH & DMN_FLASH); if (self.playerclass == 0) { self.modelindex = modelindex_null; From 43ecb11aef8cbf8a947132e486f245843d303de4 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 18 Apr 2020 13:49:05 +1000 Subject: [PATCH 0944/2474] flash gren qol updates - new model, sound, brightness change, messages etc --- ssqc/client.qc | 3 +++ ssqc/qw.qc | 1 + ssqc/scout.qc | 21 ++++++++++++++++++--- ssqc/tfort.qc | 8 ++++---- ssqc/weapons.qc | 1 + ssqc/world.qc | 1 + 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 93c5669e..6c03faa4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -655,6 +655,9 @@ void () DecodeLevelParms = { loginRequired = 0; } + // fortress one flash time in seconds + fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "2"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 0f99c787..4a65c6b2 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -577,6 +577,7 @@ float override_mapclasses; float solid_detpack; float walls_block_emp; float new_emp; +float fo_flashtime; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index cea2a5da..5a007e44 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -161,6 +161,15 @@ void () FlashTimer = { self.nextthink = time + 0.6; }; +float FO_CalcFlash(float timeleft) +{ + float flashAmt = 240; + float perc = timeleft / fo_flashtime; + + flashAmt = flashAmt * perc; + return flashAmt; +} + void FO_FlashTimer() { local entity te; @@ -168,6 +177,7 @@ void FO_FlashTimer() te = self.owner; te.FlashTime = te.FlashTime - .1; if (te.FlashTime <= 0) { + sprint(te, PRINT_HIGH, "Flash has worn off\n"); stuffcmd(te, "v_cshift; wait; bf\n"); remove(self); te.dimension_see = DMN_NOFLASH; @@ -175,7 +185,8 @@ void FO_FlashTimer() return; } - StuffFlash(te, (te.FlashTime*10)); + float flashamount = FO_CalcFlash(te.FlashTime); + StuffFlash(te, flashamount); self.nextthink = time + .1; } @@ -202,11 +213,14 @@ void FO_FlashExplode() if (te.classname == "player") { traceline(self.origin, te.origin, 1, self); if (trace_fraction == 1) { + sprint(te, PRINT_HIGH, "You have been flashed!\n"); org = te.origin + (te.mins + te.maxs) * 0.5; frac = (rad - vlen(self.origin - org)) / rad; dam = 60 * frac; deathmsg = DMSG_GREN_FLASH; TF_T_Damage(te, self, self.owner, dam, 2, 16 | 4); + + stuffcmd(te, "play weapons/flashgren.wav\n"); if (te.health > 0) { entity ft; @@ -235,11 +249,12 @@ void FO_FlashExplode() newmis.nextthink = time + .1; } - float fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "2"); fo_flashtime = fo_flashtime * (frac + frac * 0.5); // fall off is awful, let's half it te.FlashTime = fo_flashtime; - StuffFlash(te, (te.FlashTime * 10)); + float flashamount = FO_CalcFlash(te.FlashTime); + + StuffFlash(te, flashamount); SetFlashDimension(te); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index fa4671fc..5cebf247 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1039,9 +1039,9 @@ void () TeamFortress_GrenadePrimed = { newmis.touch = FlashGrenadeTouch; newmis.think = FlashGrenadeExplode; newmis.grenadename = "flashgrenade"; - newmis.skin = 2; + newmis.skin = 0; newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/flashgren.mdl"); } setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, user.origin); @@ -2828,9 +2828,9 @@ void () TeamFortress_ExplodePerson = { newmis.touch = FlashGrenadeTouch; newmis.think = FlashGrenadeExplode; newmis.grenadename = "flashgrenade"; - newmis.skin = 1; + newmis.skin = 0; newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/grenade2.mdl"); + FO_SetModel(newmis, "progs/flashgren.mdl"); } setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.owner.origin); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1beeaa84..da4e54b0 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -158,6 +158,7 @@ void () W_Precache = { precache_sound("misc/hitsound.wav"); precache_sound("misc/hitsoundcrit.wav"); precache_sound("misc/hitsoundteam.wav"); + precache_sound("weapons/flashgren.wav"); }; float () crandom = { diff --git a/ssqc/world.qc b/ssqc/world.qc index ebb9811e..a5e5d0ea 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -276,6 +276,7 @@ void () worldspawn = { precache_model2("progs/tf_stan.mdl"); precache_model2("progs/v_medi.mdl"); precache_model2("progs/hgren2.mdl"); + precache_model2("progs/flashgren.mdl"); precache_model2("progs/biggren.mdl"); precache_model2("progs/flare.mdl"); precache_model2("progs/v_srifle.mdl"); From cb9b2855bc2bfd7cc35799a5acec3234d5d6b6bb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 18 Apr 2020 13:59:02 +1000 Subject: [PATCH 0945/2474] Fix autohop --- csqc/csdefs.qc | 1 + csqc/main.qc | 9 ++------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 1cf81f31..12f20ca7 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -53,6 +53,7 @@ vector input_movevalues; float input_buttons; float input_impulse; void end_sys_globals; +float pmove_onground; .float modelindex; .vector absmin; .vector absmax; diff --git a/csqc/main.qc b/csqc/main.qc index 49310422..47dcd76f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -220,14 +220,9 @@ noref void CSQC_Input_Frame() { if (cvar(FOCMD_AUTOHOP) == 1) { - if (input_buttons&2 && !input_buttons&1) + if (input_buttons&2 && !pmove_onground) { - // jump is held - if (jumptime < time) - { - input_buttons &= ~2; - jumptime = time + .3; - } + input_buttons &= ~2; } } } From bb29ffbb186a2fb05370039d5f8c72bac1205e64 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 18 Apr 2020 14:14:14 +1000 Subject: [PATCH 0946/2474] fix for flash time --- ssqc/scout.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 5a007e44..9e5063c6 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -248,9 +248,9 @@ void FO_FlashExplode() newmis.think = FO_FlashTimer; newmis.nextthink = time + .1; } - - fo_flashtime = fo_flashtime * (frac + frac * 0.5); // fall off is awful, let's half it - te.FlashTime = fo_flashtime; + float ftime = fo_flashtime; + ftime = ftime * (frac + frac * 0.5); // fall off is awful, let's half it + te.FlashTime = ftime; float flashamount = FO_CalcFlash(te.FlashTime); From 86098ddd35086b56a6ef84a4700e8d0a3f6a7852 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 18 Apr 2020 15:24:26 +1000 Subject: [PATCH 0947/2474] Autoindent --- csqc/main.qc | 104 +++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 47dcd76f..1f6c6b0c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -13,18 +13,18 @@ void GetSelf() = { noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); -// precache_model("progs/weapons/v_rock.mdl"); - - for (float i = 0; i < HudIcons.length; i++) - { - precache_pic(HudIcons[i].icon); - } - - registercommand("fo_hud_editor"); - registercommand("fo_hud_reload"); - registercommand("fo_hud_reset"); - registercvar(FOCMD_AUTOHOP, "0"); - registercvar(FOCMD_GRENTIMER, "1"); + // precache_model("progs/weapons/v_rock.mdl"); + + for (float i = 0; i < HudIcons.length; i++) + { + precache_pic(HudIcons[i].icon); + } + + registercommand("fo_hud_editor"); + registercommand("fo_hud_reload"); + registercommand("fo_hud_reset"); + registercvar(FOCMD_AUTOHOP, "0"); + registercvar(FOCMD_GRENTIMER, "1"); registercommand("fo_menu_game"); registercommand("fo_main_menu"); registercommand("fo_menu_team"); @@ -32,15 +32,15 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_admin"); registercommand("fo_menu_vote"); registercommand("fo_menu_special"); - registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); + registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("primeone"); registercommand("primetwo"); registercommand("gren1"); registercommand("gren2"); - - FO_Hud_Editor_LoadSettings(); - FO_LoadSettings(); + + FO_Hud_Editor_LoadSettings(); + FO_LoadSettings(); CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; @@ -54,7 +54,7 @@ noref void() CSQC_WorldLoaded = { } noref void(float width, float height, float menushown) CSQC_UpdateView = { - ScreenSize = [width, height, menushown]; + ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); player_class = getstatf(STAT_CLASS); SBAR.Ready = getstatf(STAT_READY); @@ -88,7 +88,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); - + //reset grentimer status if all there are no more active grentimers if(grentimer_waiting) { if(FO_Hud_Grentimers[0].grentype == 0) { @@ -99,17 +99,17 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { noref float(string cmd) CSQC_ConsoleCommand = { tokenize(cmd); - float val; + float val; switch(argv(0)) { - case "fo_hud_editor": - FO_Hud_Editor(); - break; - case "fo_hud_reload": - FO_Hud_Editor_LoadSettings(); - break; - case "fo_hud_reset": - FO_Hud_Editor_LoadDefaultSettings(); - break; + case "fo_hud_editor": + FO_Hud_Editor(); + break; + case "fo_hud_reload": + FO_Hud_Editor_LoadSettings(); + break; + case "fo_hud_reset": + FO_Hud_Editor_LoadDefaultSettings(); + break; case "fo_menu_game": FO_Menu_Game(TRUE); break; @@ -183,16 +183,16 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; - /* - case "impulse": - print("MEHT impulsing ", argv(1) ,"\n"); - if(argv(1) == "5") { - print("MEHT impulsing the menu\n"); - FO_Menu_Special(TRUE); - return TRUE; - } - break; - */ + /* + case "impulse": + print("MEHT impulsing ", argv(1) ,"\n"); + if(argv(1) == "5") { + print("MEHT impulsing the menu\n"); + FO_Menu_Special(TRUE); + return TRUE; + } + break; + */ } return FALSE; }; @@ -202,13 +202,13 @@ void(float isnew) CSQC_Ent_Update = { float etype = readbyte(); string s; switch (etype) { - case MSG_FLAGINFO: - s = readstring(); - print("CSQC_Ent_Update, Flag info: ", s, "\n"); - break; - default: - error("Unhandled CSQC entity\n"); //you can change it to a print, but if you're not using sv_csqcdebug 1 doing so would just confuse people over the real cause. - return; + case MSG_FLAGINFO: + s = readstring(); + print("CSQC_Ent_Update, Flag info: ", s, "\n"); + break; + default: + error("Unhandled CSQC entity\n"); //you can change it to a print, but if you're not using sv_csqcdebug 1 doing so would just confuse people over the real cause. + return; } }; void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and will no longer be tracked... @@ -218,13 +218,13 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { - if (cvar(FOCMD_AUTOHOP) == 1) - { - if (input_buttons&2 && !pmove_onground) - { - input_buttons &= ~2; - } - } + if (cvar(FOCMD_AUTOHOP) == 1) + { + if (!pmove_onground) + { + input_buttons &= ~2; + } + } } void CSQC_Shutdown() = { From 51940bdf189e38c26f04d9f4d2e1f50f6c29e2b7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 18 Apr 2020 20:24:32 +1000 Subject: [PATCH 0948/2474] Add new fo_jump command to allow rj scripts while autohopping --- README.md | 2 +- csqc/csextradefs.qc | 2 +- csqc/main.qc | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 526450d0..99b46e1b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ New features * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press -* CSQC - fo_autohop 0/1 enable bunnyhop assist +* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+fo_jump` to use with rj scripts) * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index a627edd2..0a7b179b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -30,7 +30,6 @@ float MENU_START_CONTENT = 32; .float playerid; float fo_hud_editor; float fo_hud_menu_active; -float jumptime; vector ScreenSize; float number_of_teams; float last_skin; @@ -52,6 +51,7 @@ float quad_rounds_total; float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown +float jump_counter; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/main.qc b/csqc/main.qc index 1f6c6b0c..96af7ea0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -38,6 +38,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("primetwo"); registercommand("gren1"); registercommand("gren2"); + registercommand("+fo_jump"); + registercommand("-fo_jump"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -46,6 +48,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { player_menu_type = 0; is_admin = FALSE; grentimer_waiting = FALSE; + jump_counter = 0; }; noref void() CSQC_WorldLoaded = { @@ -183,6 +186,17 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; + case "+fo_jump": + jump_counter = jump_counter + 1; + localcmd("+jump"); + break; + case "-fo_jump": + jump_counter = jump_counter - 1; + if (jump_counter <= 0) + { + localcmd("-jump"); + } + break; /* case "impulse": print("MEHT impulsing ", argv(1) ,"\n"); From bbe321c79ca7990b6d67638deb10b0030bcb2933 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 00:59:30 +1000 Subject: [PATCH 0949/2474] Fix autohop water issues, maybe respawn issue --- csqc/csdefs.qc | 1 + csqc/csextradefs.qc | 1 + csqc/main.qc | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 12f20ca7..91f05dbe 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -54,6 +54,7 @@ float input_buttons; float input_impulse; void end_sys_globals; float pmove_onground; +float waterlevel; .float modelindex; .vector absmin; .vector absmax; diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 0a7b179b..6e0c0c94 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -52,6 +52,7 @@ float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown float jump_counter; +float onground_last_frame; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/main.qc b/csqc/main.qc index 96af7ea0..c86891f4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -49,6 +49,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { is_admin = FALSE; grentimer_waiting = FALSE; jump_counter = 0; + onground_last_frame = 1; }; noref void() CSQC_WorldLoaded = { @@ -234,8 +235,12 @@ noref void CSQC_Input_Frame() { if (cvar(FOCMD_AUTOHOP) == 1) { - if (!pmove_onground) + if (pmove_onground && !onground_last_frame) { + onground_last_frame = 1; + } + if (!pmove_onground && onground_last_frame) { + onground_last_frame = 0; input_buttons &= ~2; } } From 69abe8a923af9a1fd4d10571248150b924064668 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 01:01:57 +1000 Subject: [PATCH 0950/2474] Remove unusued variable --- csqc/csdefs.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 91f05dbe..12f20ca7 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -54,7 +54,6 @@ float input_buttons; float input_impulse; void end_sys_globals; float pmove_onground; -float waterlevel; .float modelindex; .vector absmin; .vector absmax; From 7242cfd45bb37adcda951198444e8e2e44990dd6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 01:44:03 +1000 Subject: [PATCH 0951/2474] Don't bother with autohop logic if user not pressing button 2 --- csqc/main.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index c86891f4..25e7239b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -65,6 +65,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); SBAR.Hint = ""; //stop grentimer on death + if(getstatf(STAT_HEALTH) <= 0) { //localcmd("stopsound\n"); for(float i = 0; i < FO_Hud_Grentimers.length; i++) { @@ -233,15 +234,15 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { - if (cvar(FOCMD_AUTOHOP) == 1) + if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2) { if (pmove_onground && !onground_last_frame) { onground_last_frame = 1; } if (!pmove_onground && onground_last_frame) { - onground_last_frame = 0; input_buttons &= ~2; + onground_last_frame = 0; } } } From 1c19544560ea192b2c1b7447553d7c194ac3b708 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 01:49:05 +1000 Subject: [PATCH 0952/2474] Add helpful comments --- csqc/main.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index 25e7239b..315381f4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -236,9 +236,12 @@ noref void CSQC_Input_Frame() { if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2) { + // frame after landing if (pmove_onground && !onground_last_frame) { onground_last_frame = 1; } + + // frame after jumping if (!pmove_onground && onground_last_frame) { input_buttons &= ~2; From a11a118773acac7b6c219533f949567be911ddc4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 01:59:53 +1000 Subject: [PATCH 0953/2474] Consisten styling --- csqc/main.qc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 315381f4..a7f8c1d9 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -232,18 +232,14 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; -noref void CSQC_Input_Frame() -{ - if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2) - { +noref void CSQC_Input_Frame() { + if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2) { // frame after landing if (pmove_onground && !onground_last_frame) { onground_last_frame = 1; } - // frame after jumping - if (!pmove_onground && onground_last_frame) - { + if (!pmove_onground && onground_last_frame) { input_buttons &= ~2; onground_last_frame = 0; } From 6ae31cde2e78322e76556ea48c490ae02d59a249 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 02:04:31 +1000 Subject: [PATCH 0954/2474] Consistent styling --- csqc/main.qc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index a7f8c1d9..55f9ef00 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -15,8 +15,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_model("progs/weapons/v_rock.mdl"); - for (float i = 0; i < HudIcons.length; i++) - { + for (float i = 0; i < HudIcons.length; i++) { precache_pic(HudIcons[i].icon); } @@ -194,8 +193,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; case "-fo_jump": jump_counter = jump_counter - 1; - if (jump_counter <= 0) - { + if (jump_counter <= 0) { localcmd("-jump"); } break; From 9295f16bbdbc57e87a7a71e4e81f8ad376ab248f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 02:20:55 +1000 Subject: [PATCH 0955/2474] Disable autohop when dead to prevent insta-spawn --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 55f9ef00..4b1b8016 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -231,7 +231,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { - if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2) { + if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2 && getstatf(STAT_HEALTH) > 0) { // frame after landing if (pmove_onground && !onground_last_frame) { onground_last_frame = 1; From bf17774aec22f880b701f8b4843f81bbee1b31b7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 02:34:10 +1000 Subject: [PATCH 0956/2474] Don't prime grens when dead --- csqc/main.qc | 92 +++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 03b4a650..43bf9372 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -99,17 +99,17 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { noref float(string cmd) CSQC_ConsoleCommand = { tokenize(cmd); - float val; + float val; switch(argv(0)) { - case "fo_hud_editor": - FO_Hud_Editor(); - break; - case "fo_hud_reload": - FO_Hud_Editor_LoadSettings(); - break; - case "fo_hud_reset": - FO_Hud_Editor_LoadDefaultSettings(); - break; + case "fo_hud_editor": + FO_Hud_Editor(); + break; + case "fo_hud_reload": + FO_Hud_Editor_LoadSettings(); + break; + case "fo_hud_reset": + FO_Hud_Editor_LoadDefaultSettings(); + break; case "fo_menu_game": FO_Menu_Game(TRUE); break; @@ -138,44 +138,52 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Special(TRUE); break; case "primeone": - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(1); + if(getstatf(STAT_HEALTH) > 0) { + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(1); + } + grentimer_waiting = TRUE; } - grentimer_waiting = TRUE; + localcmd("primeone_server"); } - localcmd("primeone_server"); break; case "primetwo": - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(2); - } - grentimer_waiting = TRUE; + if(getstatf(STAT_HEALTH) > 0) { + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(2); + } + grentimer_waiting = TRUE; + } + localcmd("primetwo_server"); } - localcmd("primetwo_server"); break; case "gren1": - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(1); - } - grentimer_waiting = TRUE; + if(getstatf(STAT_HEALTH) > 0) { + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(1); + } + grentimer_waiting = TRUE; + } + localcmd("gren1_server"); } - localcmd("gren1_server"); break; case "gren2": - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { - localcmd("play grentimer.wav\n"); - AddGrenTimer(2); - } - grentimer_waiting = TRUE; + if(getstatf(STAT_HEALTH) > 0) { + if(!grentimer_waiting) { + if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { + localcmd("play grentimer.wav\n"); + AddGrenTimer(2); + } + grentimer_waiting = TRUE; + } + localcmd("gren2_server"); } - localcmd("gren2_server"); break; case "+showscores": showingscores = TRUE; @@ -183,16 +191,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; - /* - case "impulse": - print("MEHT impulsing ", argv(1) ,"\n"); - if(argv(1) == "5") { - print("MEHT impulsing the menu\n"); - FO_Menu_Special(TRUE); - return TRUE; - } - break; - */ } return FALSE; }; From 807a4bc7483f8fe7db0f3fb99eef83906446de55 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 16:18:49 +1000 Subject: [PATCH 0957/2474] Don't release jump until 3rd frame off ground --- csqc/csextradefs.qc | 2 +- csqc/main.qc | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6e0c0c94..277aade3 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -52,7 +52,7 @@ float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown float jump_counter; -float onground_last_frame; +float frames_since_onground; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/main.qc b/csqc/main.qc index 4b1b8016..c6192b01 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -48,7 +48,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { is_admin = FALSE; grentimer_waiting = FALSE; jump_counter = 0; - onground_last_frame = 1; }; noref void() CSQC_WorldLoaded = { @@ -232,14 +231,19 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2 && getstatf(STAT_HEALTH) > 0) { - // frame after landing - if (pmove_onground && !onground_last_frame) { - onground_last_frame = 1; - } - // frame after jumping - if (!pmove_onground && onground_last_frame) { - input_buttons &= ~2; - onground_last_frame = 0; + if (pmove_onground) { + frames_since_onground = 0; + } else { + + // next two frames after leaving ground + if (frames_since_onground <= 2) { + frames_since_onground = frames_since_onground + 1; + + // third frame after leaving ground + } else if (frames_since_onground = 3) { + input_buttons &= ~2; + frames_since_onground = frames_since_onground + 1; + } } } } From c6237152c3a3dc033a6bfb2f2f4d1741f8901b4a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 17:52:22 +1000 Subject: [PATCH 0958/2474] I can't believe that worked --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index c6192b01..18f87714 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -240,7 +240,7 @@ noref void CSQC_Input_Frame() { frames_since_onground = frames_since_onground + 1; // third frame after leaving ground - } else if (frames_since_onground = 3) { + } else if (frames_since_onground == 3) { input_buttons &= ~2; frames_since_onground = frames_since_onground + 1; } From 64c9f57f213cbcda8aa61bada898d165d4cab886 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Apr 2020 18:35:42 +1000 Subject: [PATCH 0959/2474] Rename fo_jump, ensure jump_count doesn't go negative --- README.md | 2 +- csqc/main.qc | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 99b46e1b..fed27d04 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ New features * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press -* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+fo_jump` to use with rj scripts) +* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+aux_jump` to use with rj scripts) * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/main.qc b/csqc/main.qc index 18f87714..d6296203 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -37,8 +37,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("primetwo"); registercommand("gren1"); registercommand("gren2"); - registercommand("+fo_jump"); - registercommand("-fo_jump"); + registercommand("+aux_jump"); + registercommand("-aux_jump"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -186,13 +186,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-showscores": showingscores = FALSE; break; - case "+fo_jump": + case "+aux_jump": jump_counter = jump_counter + 1; localcmd("+jump"); break; - case "-fo_jump": + case "-aux_jump": jump_counter = jump_counter - 1; if (jump_counter <= 0) { + jump_counter = 0; localcmd("-jump"); } break; From d552b94c5c883f3d45570f30bf58054ae04ec9dc Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 21 Apr 2020 20:39:56 +1200 Subject: [PATCH 0960/2474] localinfo keep_teams allows keeping same teams on map change --- README.md | 1 + csqc/events.qc | 3 ++- csqc/main.qc | 10 ---------- csqc/menu.qc | 22 ++++++++++++++++++---- csqc/status.qc | 18 ------------------ ssqc/client.qc | 39 ++++++++++++++++++++++++++++++++------- ssqc/csmenu.qc | 4 +--- ssqc/qw.qc | 1 + ssqc/tforthlp.qc | 4 +++- 9 files changed, 58 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index fed27d04..a7a5f712 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* localinfo keep_teams 1/2 - keeps teams upon map change. 1 = same team. 2 = rotate teams * `cmd forcebreak` - new admin command to end the map (and go to vote) * `break` will vote to end the current map or recind your vote in a vote map * localinfo vote_time 60 - seconds since the first vote is cast until voting is decided. 0 means majority vote only. diff --git a/csqc/events.qc b/csqc/events.qc index c21aa747..871c944a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -121,7 +121,7 @@ void() CSQC_Parse_Event = { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; } } - FO_Menu_Team(FALSE); + FO_Menu_Team(2); break; case CLIENT_MENU_CLASS: FO_Menu_Class(2); @@ -240,6 +240,7 @@ void() CSQC_Parse_Event = { SBAR.CountdownStarted = FALSE; motd_expiry = time + MOTD_TIME; quad_rounds_total = readfloat(); + number_of_teams = readfloat(); break; case MSG_PREMATCH: float prematch = readbyte(); diff --git a/csqc/main.qc b/csqc/main.qc index d6296203..68a1c50e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -197,16 +197,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("-jump"); } break; - /* - case "impulse": - print("MEHT impulsing ", argv(1) ,"\n"); - if(argv(1) == "5") { - print("MEHT impulsing the menu\n"); - FO_Menu_Special(TRUE); - return TRUE; - } - break; - */ } return FALSE; }; diff --git a/csqc/menu.qc b/csqc/menu.qc index 30fb1ef5..73a4777e 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -929,12 +929,13 @@ void FO_Menu_Track() = { } void FO_Menu_Team(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_TEAM && !force) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_TEAM && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) { return; + } if(team_no) { if(number_of_teams < 2) { return; @@ -949,16 +950,29 @@ void FO_Menu_Team(float force) = { //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_NORMAL; FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; } + for(float i = 0; i < 4; i++) { + if(i < number_of_teams) { + //FO_MENU_TEAM.options[i].value = ftos(readbyte()); + if((i + 1) != team_no) { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; + } + } else { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; + } + } + localcmd("cmd changeteam\n"); CurrentMenu = &FO_MENU_TEAM; fo_hud_menu_active = TRUE; } void FO_Menu_Class(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) return; CurrentMenu = &FO_MENU_CLASS; fo_hud_menu_active = TRUE; diff --git a/csqc/status.qc b/csqc/status.qc index a84504c9..b6ccdbf8 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -111,24 +111,6 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { if(showingscores) { return; } - /* - drawstring( - [50,350], - strcat("MEHT: Prematch: ", ftos(SBAR.GameMode & 8), ", Round Active: ", ftos(SBAR.GameMode & 16), ", Round Over: ", ftos(SBAR.GameMode & 32), ", CountdownStarted: ", ftos(SBAR.CountdownStarted)), - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - drawstring( - [50,370], - strcat("MEHT: Round: ", ftos(quad_round), "/", ftos(quad_rounds_total)), - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - */ if(text && text != "") { //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); //sui_push_frame(position, size); diff --git a/ssqc/client.qc b/ssqc/client.qc index f10e0525..711b8918 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -63,6 +63,7 @@ float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options; +float (float tno) TeamFortress_TeamGetLives; string nextmap; @@ -84,7 +85,7 @@ void () info_player_intermission = }; void () SetChangeParms = { - if (self.health <= 0) { + if (self.health <= 0 && !cb_keepteams) { SetNewParms(); return; } @@ -114,8 +115,8 @@ void () SetChangeParms = { parm9 = self.armortype * 100; parm10 = 0; parm11 = 0; - parm12 = 0; - parm13 = 0; + parm12 = cb_keepteams?self.playerclass:0; + parm13 = self.team_no; parm14 = 0; parm15 = self.is_admin; }; @@ -636,6 +637,9 @@ void () DecodeLevelParms = { // After a duel round, print the winners' health stats round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); + // keep teams on map change [on] + cb_keepteams = CF_GetSetting("kt", "keep_teams", "2"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; @@ -781,10 +785,25 @@ void () DecodeLevelParms = { if (parm11) self.tfstate = parm11; - if (self.playerclass == 0) - self.playerclass = parm12; + if (cb_keepteams && parm13 && parm13 > 0 && parm13 <= number_of_teams) { + // 1 = same, 2+ = rotate + if(cb_keepteams == 1) { + //self.team_no = parm13; + TeamFortress_TeamSet(parm13); + } else { + //self.team_no = (parm13 % number_of_teams) + 1; + TeamFortress_TeamSet((parm13 % number_of_teams) + 1); + } + self.lives = TeamFortress_TeamGetLives(parm13); + //Menu_Class(0); + } + if (self.playerclass == 0 && self.team_no) { + TeamFortress_ChangeClass(parm12); + } if (parm15) self.is_admin = parm15; + + /* local entity p = find(world, classname, "player"); while (p != world) { @@ -1659,10 +1678,12 @@ void () PutClientInServer = { } } - if (self.playerclass == 0 && self.team_no > 0) { +/* + if ((!IsLegalClass(self.playerclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, self.playerclass)) { + TeamFortress_ChangeClass(0); Menu_Class(0); } - +*/ if (self.tfstate & TFSTATE_RANDOMPC) { oldclass = self.playerclass; self.playerclass = 1 + floor(random() * (10 - 1)); @@ -1784,6 +1805,10 @@ void () PutClientInServer = { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } + + if (self.playerclass == 0 && self.team_no > 0) { + Menu_Class(0); + } }; //void () info_player_start = { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 0dca21fe..77cc620f 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -34,9 +34,6 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { - if(!pl.playerclass) { - return; - } msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -208,6 +205,7 @@ void UpdateClientMOTD(entity pl) = { WriteString(MSG_MULTICAST, infokey(world, "motd2")); WriteFloat(MSG_MULTICAST, ((clanbattle?1:0) + (quadmode?2:0) + (duelmode?4:0) + (cb_prematch?8:0) + (round_active?16:0) + (round_over?32:0))); WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); + WriteFloat(MSG_MULTICAST, number_of_teams); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 368c007e..fa61c534 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -576,6 +576,7 @@ float override_mapclasses; float solid_detpack; float walls_block_emp; float new_emp; +float cb_keepteams; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 0882a274..420fc209 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -37,7 +37,9 @@ void () TeamFortress_MOTD = { sprint(self, PRINT_HIGH, st1); sprint(self, PRINT_HIGH, "\n\n\n"); - Status_Menu(self, MOTD_Input, st1); + if(self.team_no == 0 && !intermission_running) { + Status_Menu(self, MOTD_Input, st1); + } } } From 9c3c70976a59106e532fb7e3324de1a7d1687fa9 Mon Sep 17 00:00:00 2001 From: mehtty <47474496+mehtty@users.noreply.github.com> Date: Wed, 22 Apr 2020 01:11:21 +1200 Subject: [PATCH 0961/2474] Revert "Quadmode qol staging" --- README.md | 3 +-- csqc/events.qc | 3 +-- csqc/main.qc | 8 ++------ csqc/menu.qc | 22 ++++------------------ csqc/status.qc | 5 ----- ssqc/client.qc | 39 +++++++-------------------------------- ssqc/csmenu.qc | 4 +++- ssqc/qw.qc | 3 +-- ssqc/tforthlp.qc | 4 +--- 9 files changed, 20 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 6cc9b4f2..4bcd1040 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ FortressOne Server New features ------ -* localinfo keep_teams 1/2 - keeps teams upon map change. 1 = same team. 2 = rotate teams * hud commands: `fo_hud [element] [setting] [value]` lets you manually configure the extra hud elements' settings and `fo_hud_save` saves them. * new spectator command `tracktarget` lets you track whoever you're pointing at * `setinfo killsound 1/2/3` 1 enemies, 2 enemies and teammates, 3 enemies teammates and self @@ -15,7 +14,7 @@ New features * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press -* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+aux_jump` to use with rj scripts) +* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+fo_jump` to use with rj scripts) * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/events.qc b/csqc/events.qc index 52433569..7c93ba99 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -121,7 +121,7 @@ void() CSQC_Parse_Event = { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; } } - FO_Menu_Team(2); + FO_Menu_Team(FALSE); break; case CLIENT_MENU_CLASS: FO_Menu_Class(2); @@ -240,7 +240,6 @@ void() CSQC_Parse_Event = { SBAR.CountdownStarted = FALSE; motd_expiry = time + MOTD_TIME; quad_rounds_total = readfloat(); - number_of_teams = readfloat(); break; case MSG_PREMATCH: prematch = readbyte(); diff --git a/csqc/main.qc b/csqc/main.qc index ab6dce23..335cd14c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -44,8 +44,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("primetwo"); registercommand("gren1"); registercommand("gren2"); - registercommand("+aux_jump"); - registercommand("-aux_jump"); registercommand("tracktarget"); registercommand("+fo_jump"); registercommand("-fo_jump"); @@ -219,15 +217,13 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "tracktarget": localcmd("cmd tracktarget\n"); break; - case "+aux_jump": case "+fo_jump": jump_counter = jump_counter + 1; localcmd("+jump"); break; - case "-aux_jump": + case "-fo_jump": jump_counter = jump_counter - 1; if (jump_counter <= 0) { - jump_counter = 0; localcmd("-jump"); } break; @@ -265,7 +261,7 @@ noref void CSQC_Input_Frame() { frames_since_onground = frames_since_onground + 1; // third frame after leaving ground - } else if (frames_since_onground == 3) { + } else if (frames_since_onground = 3) { input_buttons &= ~2; frames_since_onground = frames_since_onground + 1; } diff --git a/csqc/menu.qc b/csqc/menu.qc index 73a4777e..30fb1ef5 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -929,13 +929,12 @@ void FO_Menu_Track() = { } void FO_Menu_Team(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_TEAM && force != 2) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_TEAM && !force) { Menu_Cancel(); return; } - if(fo_hud_menu_active && force != 1) { + if(fo_hud_menu_active && !force) return; - } if(team_no) { if(number_of_teams < 2) { return; @@ -950,29 +949,16 @@ void FO_Menu_Team(float force) = { //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_NORMAL; FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; } - for(float i = 0; i < 4; i++) { - if(i < number_of_teams) { - //FO_MENU_TEAM.options[i].value = ftos(readbyte()); - if((i + 1) != team_no) { - FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; - } else { - FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; - } - } else { - FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; - } - } - localcmd("cmd changeteam\n"); CurrentMenu = &FO_MENU_TEAM; fo_hud_menu_active = TRUE; } void FO_Menu_Class(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS && force != 2) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS) { Menu_Cancel(); return; } - if(fo_hud_menu_active && force != 1) + if(fo_hud_menu_active && !force) return; CurrentMenu = &FO_MENU_CLASS; fo_hud_menu_active = TRUE; diff --git a/csqc/status.qc b/csqc/status.qc index 18a0fdf0..ac2326c5 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -105,11 +105,6 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { local float transparency = 0.3; local float lines; if (fo_hud_editor) { - if (hud_panel(panelid, position, size, 0.3, 1)) { - // click event - } - } else { - if(showingscores) { drawstring( [GetTextAlignOffset(position.x,size.x,padding,panelid,mediumtext.x,panel.NodeInsertLoc), padding*2 + position.y], panelid, diff --git a/ssqc/client.qc b/ssqc/client.qc index 4788c70d..6c03faa4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -63,7 +63,6 @@ float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options; -float (float tno) TeamFortress_TeamGetLives; string nextmap; @@ -85,7 +84,7 @@ void () info_player_intermission = }; void () SetChangeParms = { - if (self.health <= 0 && !cb_keepteams) { + if (self.health <= 0) { SetNewParms(); return; } @@ -115,8 +114,8 @@ void () SetChangeParms = { parm9 = self.armortype * 100; parm10 = 0; parm11 = 0; - parm12 = cb_keepteams?self.playerclass:0; - parm13 = self.team_no; + parm12 = 0; + parm13 = 0; parm14 = 0; parm15 = self.is_admin; }; @@ -643,9 +642,6 @@ void () DecodeLevelParms = { // After a duel round, print the winners' health stats round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); - // keep teams on map change [on] - cb_keepteams = CF_GetSetting("kt", "keep_teams", "2"); - // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); @@ -807,25 +803,10 @@ void () DecodeLevelParms = { if (parm11) self.tfstate = parm11; - if (cb_keepteams && parm13 && parm13 > 0 && parm13 <= number_of_teams) { - // 1 = same, 2+ = rotate - if(cb_keepteams == 1) { - //self.team_no = parm13; - TeamFortress_TeamSet(parm13); - } else { - //self.team_no = (parm13 % number_of_teams) + 1; - TeamFortress_TeamSet((parm13 % number_of_teams) + 1); - } - self.lives = TeamFortress_TeamGetLives(parm13); - //Menu_Class(0); - } - if (self.playerclass == 0 && self.team_no) { - TeamFortress_ChangeClass(parm12); - } + if (self.playerclass == 0) + self.playerclass = parm12; if (parm15) self.is_admin = parm15; - - /* local entity p = find(world, classname, "player"); while (p != world) { @@ -1709,12 +1690,10 @@ void () PutClientInServer = { } } -/* - if ((!IsLegalClass(self.playerclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, self.playerclass)) { - TeamFortress_ChangeClass(0); + if (self.playerclass == 0 && self.team_no > 0) { Menu_Class(0); } -*/ + if (self.tfstate & TFSTATE_RANDOMPC) { oldclass = self.playerclass; self.playerclass = 1 + floor(random() * (10 - 1)); @@ -1836,10 +1815,6 @@ void () PutClientInServer = { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } - - if (self.playerclass == 0 && self.team_no > 0) { - Menu_Class(0); - } }; //void () info_player_start = { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 217ad66b..402dc4c2 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -34,6 +34,9 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { + if(!pl.playerclass) { + return; + } msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -210,7 +213,6 @@ void UpdateClientMOTD(entity pl) = { (votemode?GAMEMODE_VOTE:0) )); WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); - WriteFloat(MSG_MULTICAST, number_of_teams); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ae3cf3a4..4a65c6b2 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -577,7 +577,6 @@ float override_mapclasses; float solid_detpack; float walls_block_emp; float new_emp; -float cb_keepteams; float fo_flashtime; float numlocs; @@ -683,4 +682,4 @@ float canlog; .float goalrunningtime; // flash stuff -float FO_FlashDimension; +float FO_FlashDimension; \ No newline at end of file diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 29f911ac..8209c6c3 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -47,9 +47,7 @@ void () TeamFortress_MOTD = { sprint(self, PRINT_HIGH, st1); sprint(self, PRINT_HIGH, "\n\n\n"); - if(self.team_no == 0 && !intermission_running) { - Status_Menu(self, MOTD_Input, st1); - } + Status_Menu(self, MOTD_Input, st1); } } From 84fe80b0b743f4b9b45a51bbc78199cbd93ec05f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 22 Apr 2020 20:44:12 +1200 Subject: [PATCH 0962/2474] Revert "Revert "Quadmode qol staging"" This reverts commit 9c3c70976a59106e532fb7e3324de1a7d1687fa9. Conflicts: csqc/main.qc --- README.md | 2 +- csqc/events.qc | 3 ++- csqc/main.qc | 2 ++ csqc/menu.qc | 22 ++++++++++++++++++---- csqc/status.qc | 5 +++++ ssqc/client.qc | 39 ++++++++++++++++++++++++++++++++------- ssqc/csmenu.qc | 4 +--- ssqc/qw.qc | 3 ++- ssqc/tforthlp.qc | 4 +++- 9 files changed, 66 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index ffc6162c..6cc9b4f2 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ New features * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press -* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+fo_jump` to use with rj scripts) +* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+aux_jump` to use with rj scripts) * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/events.qc b/csqc/events.qc index 7c93ba99..52433569 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -121,7 +121,7 @@ void() CSQC_Parse_Event = { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; } } - FO_Menu_Team(FALSE); + FO_Menu_Team(2); break; case CLIENT_MENU_CLASS: FO_Menu_Class(2); @@ -240,6 +240,7 @@ void() CSQC_Parse_Event = { SBAR.CountdownStarted = FALSE; motd_expiry = time + MOTD_TIME; quad_rounds_total = readfloat(); + number_of_teams = readfloat(); break; case MSG_PREMATCH: prematch = readbyte(); diff --git a/csqc/main.qc b/csqc/main.qc index bc1d5733..0294d9d9 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -46,6 +46,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("gren2"); registercommand("+aux_jump"); registercommand("-aux_jump"); + registercommand("tracktarget"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -221,6 +222,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-aux_jump": jump_counter = jump_counter - 1; if (jump_counter <= 0) { + jump_counter = 0; localcmd("-jump"); } } diff --git a/csqc/menu.qc b/csqc/menu.qc index 30fb1ef5..73a4777e 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -929,12 +929,13 @@ void FO_Menu_Track() = { } void FO_Menu_Team(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_TEAM && !force) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_TEAM && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) { return; + } if(team_no) { if(number_of_teams < 2) { return; @@ -949,16 +950,29 @@ void FO_Menu_Team(float force) = { //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_NORMAL; FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; } + for(float i = 0; i < 4; i++) { + if(i < number_of_teams) { + //FO_MENU_TEAM.options[i].value = ftos(readbyte()); + if((i + 1) != team_no) { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; + } else { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; + } + } else { + FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; + } + } + localcmd("cmd changeteam\n"); CurrentMenu = &FO_MENU_TEAM; fo_hud_menu_active = TRUE; } void FO_Menu_Class(float force) = { - if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS && force != 2) { Menu_Cancel(); return; } - if(fo_hud_menu_active && !force) + if(fo_hud_menu_active && force != 1) return; CurrentMenu = &FO_MENU_CLASS; fo_hud_menu_active = TRUE; diff --git a/csqc/status.qc b/csqc/status.qc index ac2326c5..18a0fdf0 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -105,6 +105,11 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { local float transparency = 0.3; local float lines; if (fo_hud_editor) { + if (hud_panel(panelid, position, size, 0.3, 1)) { + // click event + } + } else { + if(showingscores) { drawstring( [GetTextAlignOffset(position.x,size.x,padding,panelid,mediumtext.x,panel.NodeInsertLoc), padding*2 + position.y], panelid, diff --git a/ssqc/client.qc b/ssqc/client.qc index 6c03faa4..4788c70d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -63,6 +63,7 @@ float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options; +float (float tno) TeamFortress_TeamGetLives; string nextmap; @@ -84,7 +85,7 @@ void () info_player_intermission = }; void () SetChangeParms = { - if (self.health <= 0) { + if (self.health <= 0 && !cb_keepteams) { SetNewParms(); return; } @@ -114,8 +115,8 @@ void () SetChangeParms = { parm9 = self.armortype * 100; parm10 = 0; parm11 = 0; - parm12 = 0; - parm13 = 0; + parm12 = cb_keepteams?self.playerclass:0; + parm13 = self.team_no; parm14 = 0; parm15 = self.is_admin; }; @@ -642,6 +643,9 @@ void () DecodeLevelParms = { // After a duel round, print the winners' health stats round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); + // keep teams on map change [on] + cb_keepteams = CF_GetSetting("kt", "keep_teams", "2"); + // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); @@ -803,10 +807,25 @@ void () DecodeLevelParms = { if (parm11) self.tfstate = parm11; - if (self.playerclass == 0) - self.playerclass = parm12; + if (cb_keepteams && parm13 && parm13 > 0 && parm13 <= number_of_teams) { + // 1 = same, 2+ = rotate + if(cb_keepteams == 1) { + //self.team_no = parm13; + TeamFortress_TeamSet(parm13); + } else { + //self.team_no = (parm13 % number_of_teams) + 1; + TeamFortress_TeamSet((parm13 % number_of_teams) + 1); + } + self.lives = TeamFortress_TeamGetLives(parm13); + //Menu_Class(0); + } + if (self.playerclass == 0 && self.team_no) { + TeamFortress_ChangeClass(parm12); + } if (parm15) self.is_admin = parm15; + + /* local entity p = find(world, classname, "player"); while (p != world) { @@ -1690,10 +1709,12 @@ void () PutClientInServer = { } } - if (self.playerclass == 0 && self.team_no > 0) { +/* + if ((!IsLegalClass(self.playerclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, self.playerclass)) { + TeamFortress_ChangeClass(0); Menu_Class(0); } - +*/ if (self.tfstate & TFSTATE_RANDOMPC) { oldclass = self.playerclass; self.playerclass = 1 + floor(random() * (10 - 1)); @@ -1815,6 +1836,10 @@ void () PutClientInServer = { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } + + if (self.playerclass == 0 && self.team_no > 0) { + Menu_Class(0); + } }; //void () info_player_start = { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 402dc4c2..217ad66b 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -34,9 +34,6 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { - if(!pl.playerclass) { - return; - } msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -213,6 +210,7 @@ void UpdateClientMOTD(entity pl) = { (votemode?GAMEMODE_VOTE:0) )); WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); + WriteFloat(MSG_MULTICAST, number_of_teams); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4a65c6b2..ae3cf3a4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -577,6 +577,7 @@ float override_mapclasses; float solid_detpack; float walls_block_emp; float new_emp; +float cb_keepteams; float fo_flashtime; float numlocs; @@ -682,4 +683,4 @@ float canlog; .float goalrunningtime; // flash stuff -float FO_FlashDimension; \ No newline at end of file +float FO_FlashDimension; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 8209c6c3..29f911ac 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -47,7 +47,9 @@ void () TeamFortress_MOTD = { sprint(self, PRINT_HIGH, st1); sprint(self, PRINT_HIGH, "\n\n\n"); - Status_Menu(self, MOTD_Input, st1); + if(self.team_no == 0 && !intermission_running) { + Status_Menu(self, MOTD_Input, st1); + } } } From 4571ff27051f055bdcc505595e2ec9ff0bb991c4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 22 Apr 2020 22:27:44 +1200 Subject: [PATCH 0963/2474] meeeerge --- csqc/main.qc | 1 - csqc/status.qc | 5 ----- 2 files changed, 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 0294d9d9..956e0768 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -50,7 +50,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); - registercommand("tracktarget"); CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; diff --git a/csqc/status.qc b/csqc/status.qc index 18a0fdf0..ac2326c5 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -105,11 +105,6 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { local float transparency = 0.3; local float lines; if (fo_hud_editor) { - if (hud_panel(panelid, position, size, 0.3, 1)) { - // click event - } - } else { - if(showingscores) { drawstring( [GetTextAlignOffset(position.x,size.x,padding,panelid,mediumtext.x,panel.NodeInsertLoc), padding*2 + position.y], panelid, From 9dc8063d247204fe679f69a609a877f62b5d5c09 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 23 Apr 2020 08:35:54 +1200 Subject: [PATCH 0964/2474] make keep_team default to 1 for now --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 4788c70d..0f717ea4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -644,7 +644,7 @@ void () DecodeLevelParms = { round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); // keep teams on map change [on] - cb_keepteams = CF_GetSetting("kt", "keep_teams", "2"); + cb_keepteams = CF_GetSetting("kt", "keep_teams", "1"); // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); From 8a17feb676e46136ce1ca287608a53a0f738ba02 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 23 Apr 2020 15:30:57 +1000 Subject: [PATCH 0965/2474] configurable limits of flash so evilant stops complaining, change sound too --- ssqc/scout.qc | 21 ++++++++++++++++----- ssqc/weapons.qc | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 9e5063c6..dd8bcb8b 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -161,12 +161,23 @@ void () FlashTimer = { self.nextthink = time + 0.6; }; -float FO_CalcFlash(float timeleft) +float FO_CalcFlash(entity te) { - float flashAmt = 240; + float timeleft = te.FlashTime; + float flashAmtMax = 240; + float flashAmtMin = 100; + float flashAmtMaxMult = stof(infokey(te, "maxflash")); + float flashAmtMinMult = stof(infokey(te, "minflash")); + float flashAmt; + + + flashAmt = (flashAmtMaxMult > 0) ? flashAmtMax * flashAmtMaxMult : flashAmtMax; + flashAmtMin = (flashAmtMinMult > 0) ? flashAmtMin * flashAmtMinMult : flashAmtMin; + float perc = timeleft / fo_flashtime; flashAmt = flashAmt * perc; + flashAmt = flashAmt < flashAmtMin ? flashAmtMin : flashAmt; return flashAmt; } @@ -185,7 +196,7 @@ void FO_FlashTimer() return; } - float flashamount = FO_CalcFlash(te.FlashTime); + float flashamount = FO_CalcFlash(te); StuffFlash(te, flashamount); self.nextthink = time + .1; @@ -220,7 +231,7 @@ void FO_FlashExplode() deathmsg = DMSG_GREN_FLASH; TF_T_Damage(te, self, self.owner, dam, 2, 16 | 4); - stuffcmd(te, "play weapons/flashgren.wav\n"); + stuffcmd(te, "play weapons/flashgrenburst.wav\n"); if (te.health > 0) { entity ft; @@ -252,7 +263,7 @@ void FO_FlashExplode() ftime = ftime * (frac + frac * 0.5); // fall off is awful, let's half it te.FlashTime = ftime; - float flashamount = FO_CalcFlash(te.FlashTime); + float flashamount = FO_CalcFlash(te); StuffFlash(te, flashamount); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ef6de2a8..401547ec 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -158,7 +158,7 @@ void () W_Precache = { precache_sound("misc/hitsound.wav"); precache_sound("misc/hitsoundcrit.wav"); precache_sound("misc/hitsoundteam.wav"); - precache_sound("weapons/flashgren.wav"); + precache_sound("weapons/flashgrenburst.wav"); precache_sound("misc/killsound.wav"); precache_sound("misc/killsoundteam.wav"); }; From 43a68c66187432b13bc538b1b85cde681ab89a01 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 23 Apr 2020 16:32:15 +1000 Subject: [PATCH 0966/2474] fix broken specs --- ssqc/spect.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 3a541944..14b2946b 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -15,6 +15,10 @@ void () SpectatorThink; void () Admin_Aliases; void () SpectatorConnect = { + + self.dimension_see = DMN_NOFLASH; + self.dimension_seen = DMN_NOFLASH; + local string st; self.playerclass = PC_UNDEFINED; @@ -125,8 +129,6 @@ void () SpectatorImpulseCommand = { void () SpectatorThink = { - self.dimension_see = DMN_NOFLASH; - if (self.impulse) SpectatorImpulseCommand(); From 06d366144cd2c4d31e84e41fa54e73b376369164 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 23 Apr 2020 22:50:59 +1200 Subject: [PATCH 0967/2474] disable for now --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 0f717ea4..1ad3a2b8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -644,7 +644,7 @@ void () DecodeLevelParms = { round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); // keep teams on map change [on] - cb_keepteams = CF_GetSetting("kt", "keep_teams", "1"); + cb_keepteams = CF_GetSetting("kt", "keep_teams", "0"); // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); From 6f0e17fcd065e41376b7f871beef9322dc502e2e Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 27 Apr 2020 11:57:53 +1200 Subject: [PATCH 0968/2474] attack and defend roles --- ssqc/client.qc | 133 ++++++++++++++++++++++----------------- ssqc/commands.qc | 8 +++ ssqc/progs.src | 1 + ssqc/quadmode.qc | 9 +++ ssqc/qw.qc | 6 +- ssqc/roles.qc | 114 ++++++++++++++++++++++++++++++++++ ssqc/tfort.qc | 158 ++++++++++++++++++++++++----------------------- ssqc/tforttm.qc | 9 ++- ssqc/weapons.qc | 4 +- 9 files changed, 304 insertions(+), 138 deletions(-) create mode 100644 ssqc/roles.qc diff --git a/ssqc/client.qc b/ssqc/client.qc index 711b8918..4fa7dac4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -444,7 +444,7 @@ void () DecodeLevelParms = { old_sniperrange = CF_GetSetting("os", "old_sniperrange", "off"); // maximum amount of pipebombs per demoman [6] - detpipe_limit = CF_GetSetting("dl", "detpipe_limit", "6"); + Role_None.detpipe_limit = CF_GetSetting("dl", "detpipe_limit", "6"); // maximum amount of pipebombs in game [unlimited] detpipe_limit_world = CF_GetSetting("dw", "detpipe_limit_world", "-1"); @@ -552,12 +552,12 @@ void () DecodeLevelParms = { old_hp_armor = CF_GetSetting("oh", "old_hp_armor", "off"); // delay respawning by this many seconds [0] - respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); - if (respawn_delay_time) { + Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); + if (Role_None.respawn_delay_time) { toggleflags = toggleflags | TFLAG_RESPAWNDELAY; } - if ((toggleflags & TFLAG_RESPAWNDELAY) && !respawn_delay_time) { - respawn_delay_time = RESPAWN_DELAY_TIME; + if ((toggleflags & TFLAG_RESPAWNDELAY) && !Role_None.respawn_delay_time) { + Role_None.respawn_delay_time = RESPAWN_DELAY_TIME; } if (toggleflags & TFLAG_AUTOTEAM) { @@ -599,6 +599,7 @@ void () DecodeLevelParms = { // override map-set class restrictions [off] override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); // Maximum number of primary grenades per class + /* max_gren1_scout = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); max_gren1_sniper = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); max_gren1_soldier = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); @@ -608,17 +609,28 @@ void () DecodeLevelParms = { max_gren1_pyro = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); max_gren1_spy = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); max_gren1_engineer = CF_GetSetting("mg2_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); + */ + Role_None.gren1_limits[0] = 0; + Role_None.gren1_limits[1] = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); + Role_None.gren1_limits[2] = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); + Role_None.gren1_limits[3] = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); + Role_None.gren1_limits[4] = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); + Role_None.gren1_limits[5] = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); + Role_None.gren1_limits[6] = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); + Role_None.gren1_limits[7] = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); + Role_None.gren1_limits[8] = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); + Role_None.gren1_limits[9] = CF_GetSetting("mg2_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); // Maximum number of secondary grenades per class - max_gren2_scout = CF_GetSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); - max_gren2_sniper = CF_GetSetting("mg2_2", "max_gren2_sniper", ftos(PC_SNIPER_GRENADE_MAX_2)); - max_gren2_soldier = CF_GetSetting("mg2_3", "max_gren2_soldier", ftos(PC_SOLDIER_GRENADE_MAX_2)); - max_gren2_demoman = CF_GetSetting("mg2_4", "max_gren2_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_2)); - max_gren2_medic = CF_GetSetting("mg2_5", "max_gren2_medic", ftos(PC_MEDIC_GRENADE_MAX_2)); - max_gren2_hwguy = CF_GetSetting("mg2_6", "max_gren2_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_2)); - max_gren2_pyro = CF_GetSetting("mg2_7", "max_gren2_pyro", ftos(PC_PYRO_GRENADE_MAX_2)); - max_gren2_spy = CF_GetSetting("mg2_8", "max_gren2_spy", ftos(PC_SPY_GRENADE_MAX_2)); - max_gren2_engineer = CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(PC_ENGINEER_GRENADE_MAX_2)); + Role_None.gren2_limits[1] = CF_GetSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); + Role_None.gren2_limits[2] = CF_GetSetting("mg2_2", "max_gren2_sniper", ftos(PC_SNIPER_GRENADE_MAX_2)); + Role_None.gren2_limits[3] = CF_GetSetting("mg2_3", "max_gren2_soldier", ftos(PC_SOLDIER_GRENADE_MAX_2)); + Role_None.gren2_limits[4] = CF_GetSetting("mg2_4", "max_gren2_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_2)); + Role_None.gren2_limits[5] = CF_GetSetting("mg2_5", "max_gren2_medic", ftos(PC_MEDIC_GRENADE_MAX_2)); + Role_None.gren2_limits[6] = CF_GetSetting("mg2_6", "max_gren2_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_2)); + Role_None.gren2_limits[7] = CF_GetSetting("mg2_7", "max_gren2_pyro", ftos(PC_PYRO_GRENADE_MAX_2)); + Role_None.gren2_limits[8] = CF_GetSetting("mg2_8", "max_gren2_spy", ftos(PC_SPY_GRENADE_MAX_2)); + Role_None.gren2_limits[9] = CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(PC_ENGINEER_GRENADE_MAX_2)); // solid detpack toggle [0] solid_detpack = CF_GetSetting("sdp", "solid_detpack", "0"); @@ -637,8 +649,15 @@ void () DecodeLevelParms = { // After a duel round, print the winners' health stats round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); - // keep teams on map change [on] - cb_keepteams = CF_GetSetting("kt", "keep_teams", "2"); + // keep teams on map change [off] + cb_keepteams = CF_GetSetting("kt", "keep_teams", "0"); + + // use att/def roles in quad mode [off] + quad_roles = CF_GetSetting("qr", "quad_roles", "0"); + + LoadRole(&Role_Attack); + LoadRole(&Role_Defence); + InitTeamRoles(); st = infokey(world, "default"); if (st == "on") { @@ -658,7 +677,7 @@ void () DecodeLevelParms = { scoutdash = TRUE; sniperreload = TRUE; old_sniperrange = FALSE; - detpipe_limit = 6; + Role_None.detpipe_limit = 6; detpipe_limit_world = -1; old_pipecooldown = FALSE; medicaura = TRUE; @@ -689,24 +708,24 @@ void () DecodeLevelParms = { ng_velocity = 1500; old_ng_rof = FALSE; pyro_type = 1; - max_gren1_scout = PC_SCOUT_GRENADE_MAX_1; - max_gren1_sniper = PC_SNIPER_GRENADE_MAX_1; - max_gren1_soldier = PC_SOLDIER_GRENADE_MAX_1; - max_gren1_demoman = PC_DEMOMAN_GRENADE_MAX_1; - max_gren1_medic = PC_MEDIC_GRENADE_MAX_1; - max_gren1_hwguy = PC_HVYWEAP_GRENADE_MAX_1; - max_gren1_pyro = PC_PYRO_GRENADE_MAX_1; - max_gren1_spy = PC_SPY_GRENADE_MAX_1; - max_gren1_engineer = PC_ENGINEER_GRENADE_MAX_1; - max_gren2_scout = PC_SCOUT_GRENADE_MAX_2; - max_gren2_sniper = PC_SNIPER_GRENADE_MAX_2; - max_gren2_soldier = PC_SOLDIER_GRENADE_MAX_2; - max_gren2_demoman = PC_DEMOMAN_GRENADE_MAX_2; - max_gren2_medic = PC_MEDIC_GRENADE_MAX_2; - max_gren2_hwguy = PC_HVYWEAP_GRENADE_MAX_2; - max_gren2_pyro = PC_PYRO_GRENADE_MAX_2; - max_gren2_spy = PC_SPY_GRENADE_MAX_2; - max_gren2_engineer = PC_ENGINEER_GRENADE_MAX_2; + Role_None.gren1_limits[1] = PC_SCOUT_GRENADE_MAX_1; + Role_None.gren1_limits[2] = PC_SNIPER_GRENADE_MAX_1; + Role_None.gren1_limits[3] = PC_SOLDIER_GRENADE_MAX_1; + Role_None.gren1_limits[4] = PC_DEMOMAN_GRENADE_MAX_1; + Role_None.gren1_limits[5] = PC_MEDIC_GRENADE_MAX_1; + Role_None.gren1_limits[6] = PC_HVYWEAP_GRENADE_MAX_1; + Role_None.gren1_limits[7] = PC_PYRO_GRENADE_MAX_1; + Role_None.gren1_limits[8] = PC_SPY_GRENADE_MAX_1; + Role_None.gren1_limits[9] = PC_ENGINEER_GRENADE_MAX_1; + Role_None.gren2_limits[1] = PC_SCOUT_GRENADE_MAX_2; + Role_None.gren2_limits[2] = PC_SNIPER_GRENADE_MAX_2; + Role_None.gren2_limits[3] = PC_SOLDIER_GRENADE_MAX_2; + Role_None.gren2_limits[4] = PC_DEMOMAN_GRENADE_MAX_2; + Role_None.gren2_limits[5] = PC_MEDIC_GRENADE_MAX_2; + Role_None.gren2_limits[6] = PC_HVYWEAP_GRENADE_MAX_2; + Role_None.gren2_limits[7] = PC_PYRO_GRENADE_MAX_2; + Role_None.gren2_limits[8] = PC_SPY_GRENADE_MAX_2; + Role_None.gren2_limits[9] = PC_ENGINEER_GRENADE_MAX_2; solid_detpack = FALSE; walls_block_emp = FALSE; } @@ -728,7 +747,7 @@ void () DecodeLevelParms = { scoutdash = FALSE; sniperreload = FALSE; old_sniperrange = TRUE; - detpipe_limit = 7; + Role_None.detpipe_limit = 7; detpipe_limit_world = 7; old_pipecooldown = TRUE; medicaura = FALSE; @@ -759,24 +778,24 @@ void () DecodeLevelParms = { ng_velocity = 1000; old_ng_rof = TRUE; pyro_type = 0; - max_gren1_scout = 4; - max_gren1_sniper = 4; - max_gren1_soldier = 4; - max_gren1_demoman = 4; - max_gren1_medic = 4; - max_gren1_hwguy = 4; - max_gren1_pyro = 4; - max_gren1_spy = 4; - max_gren1_engineer = 4; - max_gren2_scout = 3; - max_gren2_sniper = 4; - max_gren2_soldier = 3; - max_gren2_demoman = 4; - max_gren2_medic = 3; - max_gren2_hwguy = 4; - max_gren2_pyro = 4; - max_gren2_spy = 4; - max_gren2_engineer = 4; + Role_None.gren1_limits[1] = 4; + Role_None.gren1_limits[2] = 4; + Role_None.gren1_limits[3] = 4; + Role_None.gren1_limits[4] = 4; + Role_None.gren1_limits[5] = 4; + Role_None.gren1_limits[6] = 4; + Role_None.gren1_limits[7] = 4; + Role_None.gren1_limits[8] = 4; + Role_None.gren1_limits[9] = 4; + Role_None.gren2_limits[1] = 3; + Role_None.gren2_limits[2] = 4; + Role_None.gren2_limits[3] = 3; + Role_None.gren2_limits[4] = 4; + Role_None.gren2_limits[5] = 3; + Role_None.gren2_limits[6] = 4; + Role_None.gren2_limits[7] = 4; + Role_None.gren2_limits[8] = 4; + Role_None.gren2_limits[9] = 4; solid_detpack = TRUE; walls_block_emp = FALSE; } @@ -785,7 +804,7 @@ void () DecodeLevelParms = { if (parm11) self.tfstate = parm11; - if (cb_keepteams && parm13 && parm13 > 0 && parm13 <= number_of_teams) { + if (!self.team_no && cb_keepteams && clanbattle && parm13 && parm13 > 0 && parm13 <= number_of_teams) { // 1 = same, 2+ = rotate if(cb_keepteams == 1) { //self.team_no = parm13; @@ -1711,6 +1730,10 @@ void () PutClientInServer = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_StartTimers(); + + if(quadmode && quad_roles) { + sprint(self, PRINT_HIGH, "\sRole:\s ", GetTeamRole(self.team_no).name, "\n"); + } stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5cf2b516..382eab82 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -762,6 +762,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; sprint(self, PRINT_HIGH, "Model: ", self.model, " index: ", ftos(self.modelindex), "\n"); break; + case "showroles": + processedCmd = TRUE; + PrintRoleStatus(self); + PrintRole(self, &Role_None); + PrintRole(self, &Role_Attack); + PrintRole(self, &Role_Defence); + PrintTeamRoles(self); + break; case "help": case "list": processedCmd = TRUE; diff --git a/ssqc/progs.src b/ssqc/progs.src index e921e52b..e06e231e 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -6,6 +6,7 @@ defs.qc ../share/commondefs.qc ../share/common_helpers.qc qw.qc +roles.qc q3defs.qc debug.qc status.qc diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 8382dae8..9a23a342 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -396,6 +396,15 @@ void () StartQuadRound = te.think = QuadRoundInit; te.nextthink = (time + 1); } + if(quad_roles) { + if(rounds % 2) { + Team1_Role = &Role_Defence; + Team2_Role = &Role_Attack; + } else { + Team1_Role = &Role_Attack; + Team2_Role = &Role_Defence; + } + } }; void () EndQuadRound = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index fa61c534..0b621b6c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -120,7 +120,7 @@ typedef void (float n) f_void_float; float toggleflags; // toggleable flags -float respawn_delay_time; +//float respawn_delay_time; // // FortressMap stuff @@ -495,6 +495,7 @@ float drop_grenades; float drop_grenpack; float drop_gren1; float drop_gren2; +/* float max_gren1_scout; float max_gren1_sniper; float max_gren1_soldier; @@ -513,6 +514,7 @@ float max_gren2_hwguy; float max_gren2_pyro; float max_gren2_spy; float max_gren2_engineer; +*/ float grentimers; float id_extended; float remember_weapon; @@ -520,7 +522,7 @@ float discammo_pickup; float old_dropflag; float reload_cliptick; float old_sniperrange; -float detpipe_limit; +//float detpipe_limit; float detpipe_limit_world; float old_pipecooldown; float medicaura; diff --git a/ssqc/roles.qc b/ssqc/roles.qc new file mode 100644 index 00000000..7406732d --- /dev/null +++ b/ssqc/roles.qc @@ -0,0 +1,114 @@ +#pragma target fte + +typedef struct { + string name; + string prefix; + float detpipe_limit; + float respawn_delay_time; + float gren1_limits[10]; + float gren2_limits[10]; + float class_limits[11]; +} Team_Role; + +float quad_roles; +var Team_Role Role_None = {"Default", "", 6}; +var Team_Role Role_Attack = {"Attack", "att_", 6}; +var Team_Role Role_Defence = {"Defence", "def_", 6}; +Team_Role * Team1_Role; +Team_Role * Team2_Role; +Team_Role * Team3_Role; +Team_Role * Team4_Role; + +const string CLASSES [11] = { + "observer", + "scout", + "sniper", + "soldier", + "demoman", + "medic", + "hwguy", + "pyro", + "spy", + "engineer", + "randompc" +}; + +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; + +void (Team_Role * role) LoadRole = { + role.detpipe_limit = CF_GetSetting(strcat(role.prefix,"dl"), strcat(role.prefix,"detpipe_limit"), ftos(Role_None.detpipe_limit)); + role.respawn_delay_time = CF_GetSetting(strcat(role.prefix,"rd"), strcat(role.prefix,"respawn_delay"), ftos(Role_None.respawn_delay_time)); + role.gren1_limits[0] = 0; + role.gren2_limits[0] = 0; + role.class_limits[0] = 0; + for(float i = 1; i < 10; i++) { + role.gren1_limits[i] = CF_GetSetting(strcat(role.prefix,"mg1_",ftos(i)), strcat(role.prefix,"max_gren1_",CLASSES[i]), ftos(Role_None.gren1_limits[i])); + role.gren2_limits[i] = CF_GetSetting(strcat(role.prefix,"mg2_",ftos(i)), strcat(role.prefix,"max_gren2_",CLASSES[i]), ftos(Role_None.gren2_limits[i])); + role.class_limits[i] = CF_GetSetting(strcat(role.prefix,"cr_",CLASSES[i]), strcat(role.prefix,"cr_",CLASSES[i]), ftos(Role_None.class_limits[i])); + } +}; + +void (entity e) PrintRoleStatus = { + float current = CF_GetSetting("qr", "quad_roles", "0"); + sprint(e, PRINT_HIGH, "Roles are ", quad_roles?"\sENABLED\s":"\sDISABLED\s"); + if(!quadmode) { + sprint(e, PRINT_HIGH, ", however it requires \squadmode\s to work. Set it from the admin menu."); + } + if(current != quad_roles) { + sprint(e, PRINT_HIGH, "\nNote that the setting will be ", current?"\sENABLED\s":"\sDISABLED\s", " after map restart."); + } + sprint(e, PRINT_HIGH, "\n"); +}; + +void (entity e, Team_Role * role) PrintRole = { + sprint(e, PRINT_HIGH, "\sRole:\s ", role.name, "\n"); + sprint(e, PRINT_HIGH, "Detpipe Limit: ", ftos(role.detpipe_limit), "\n"); + sprint(e, PRINT_HIGH, "Respawn Delay: ", ftos(role.respawn_delay_time), "\n"); + for(float i = 1; i < 10; i++) { + sprint(e, PRINT_HIGH, CLASSES[i],": \n"); + sprint(e, PRINT_HIGH, "\tGren 1: ", ftos(role.gren1_limits[i]), "\n"); + sprint(e, PRINT_HIGH, "\tGren 2: ", ftos(role.gren2_limits[i]), "\n"); + sprint(e, PRINT_HIGH, "\tClass Limit: ", ftos(role.class_limits[i]), "\n"); + } + sprint(e, PRINT_HIGH, CLASSES[10],": \n"); + sprint(e, PRINT_HIGH, "\tClass Limit: ", ftos(role.class_limits[10]), "\n"); +} + +void () InitTeamRoles = { + Team1_Role = &Role_None; + Team2_Role = &Role_None; + Team3_Role = &Role_None; + Team4_Role = &Role_None; +}; + +string(float tno) GetTeamName; + +void (entity e) PrintTeamRoles = { + sprint(e, PRINT_HIGH, "\sTeam Roles:\s\n"); + if(number_of_teams > 0) { + sprint(e, PRINT_HIGH, GetTeamName(1), ": ", Team1_Role.name, "\n"); + } + if(number_of_teams > 1) { + sprint(e, PRINT_HIGH, GetTeamName(2), ": ", Team2_Role.name, "\n"); + } + if(number_of_teams > 2) { + sprint(e, PRINT_HIGH, GetTeamName(3), ": ", Team3_Role.name, "\n"); + } + if(number_of_teams > 3) { + sprint(e, PRINT_HIGH, GetTeamName(4), ": ", Team4_Role.name, "\n"); + } +}; + +Team_Role* (float tno) GetTeamRole = { + switch (tno) { + case 1: + return Team1_Role; + case 2: + return Team2_Role; + case 3: + return Team3_Role; + case 4: + return Team4_Role; + } + return &Role_None; +}; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 385f249c..477f8013 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -570,7 +570,7 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "Respawn delay "); if (toggleflags & TFLAG_RESPAWNDELAY) { - st = ftos(respawn_delay_time); + st = ftos(Role_None.respawn_delay_time); } else { st = "off"; } @@ -612,25 +612,25 @@ void () TeamFortress_ShowTF = { } CF_PrintSetting("Grenade timers", grentimers, "", 1); - CF_PrintSetting("Scout max grenades type 1 (caltrops)", max_gren1_scout, "", PC_SCOUT_GRENADE_MAX_1); - CF_PrintSetting("Sniper max grenades type 1 (normal)", max_gren1_sniper, "", PC_SNIPER_GRENADE_MAX_1); - CF_PrintSetting("Soldier max grenades type 1 (normal)", max_gren1_soldier, "", PC_SOLDIER_GRENADE_MAX_1); - CF_PrintSetting("Demoman max grenades type 1 (normal)", max_gren1_demoman, "", PC_DEMOMAN_GRENADE_MAX_1); - CF_PrintSetting("Medic max grenades type 1 (normal)", max_gren1_medic, "", PC_MEDIC_GRENADE_MAX_1); - CF_PrintSetting("Heavy Weapons max grenades type 1 (normal)", max_gren1_hwguy, "", PC_HVYWEAP_GRENADE_MAX_1); - CF_PrintSetting("Pyro max grenades type 1 (normal)", max_gren1_pyro, "", PC_PYRO_GRENADE_MAX_1); - CF_PrintSetting("Spy max grenades type 1 (normal)", max_gren1_spy, "", PC_SPY_GRENADE_MAX_1); - CF_PrintSetting("Engineer max grenades type 1 (normal)", max_gren1_engineer, "", PC_ENGINEER_GRENADE_MAX_1); - - CF_PrintSetting("Scout max grenades type 2 (concussion)", max_gren2_scout, "", PC_SCOUT_GRENADE_MAX_2); - CF_PrintSetting("Sniper max grenades type 2 (flare)", max_gren2_sniper, "", PC_SNIPER_GRENADE_MAX_2); - CF_PrintSetting("Soldier max grenades type 2 (nail/shock)", max_gren2_soldier, "", PC_SOLDIER_GRENADE_MAX_2); - CF_PrintSetting("Demoman max grenades type 2 (mirv)", max_gren2_demoman, "", PC_DEMOMAN_GRENADE_MAX_2); - CF_PrintSetting("Medic max grenades type 2 (concussion)", max_gren2_medic, "", PC_MEDIC_GRENADE_MAX_2); - CF_PrintSetting("Heavy Weapons max grenades type 2 (mirv)", max_gren2_hwguy, "", PC_HVYWEAP_GRENADE_MAX_2); - CF_PrintSetting("Pyro max grenades type 2 (napalm)", max_gren2_pyro, "", PC_PYRO_GRENADE_MAX_2); - CF_PrintSetting("Spy max grenades type 2 (gas)", max_gren2_spy, "", PC_SPY_GRENADE_MAX_2); - CF_PrintSetting("Engineer max grenades type 2 (emp)", max_gren2_engineer, "", PC_ENGINEER_GRENADE_MAX_2); + CF_PrintSetting("Scout max grenades type 1 (caltrops)", Role_None.gren1_limits[1], "", PC_SCOUT_GRENADE_MAX_1); + CF_PrintSetting("Sniper max grenades type 1 (normal)", Role_None.gren1_limits[2], "", PC_SNIPER_GRENADE_MAX_1); + CF_PrintSetting("Soldier max grenades type 1 (normal)", Role_None.gren1_limits[3], "", PC_SOLDIER_GRENADE_MAX_1); + CF_PrintSetting("Demoman max grenades type 1 (normal)", Role_None.gren1_limits[4], "", PC_DEMOMAN_GRENADE_MAX_1); + CF_PrintSetting("Medic max grenades type 1 (normal)", Role_None.gren1_limits[5], "", PC_MEDIC_GRENADE_MAX_1); + CF_PrintSetting("Heavy Weapons max grenades type 1 (normal)", Role_None.gren1_limits[6], "", PC_HVYWEAP_GRENADE_MAX_1); + CF_PrintSetting("Pyro max grenades type 1 (normal)", Role_None.gren1_limits[7], "", PC_PYRO_GRENADE_MAX_1); + CF_PrintSetting("Spy max grenades type 1 (normal)", Role_None.gren1_limits[8], "", PC_SPY_GRENADE_MAX_1); + CF_PrintSetting("Engineer max grenades type 1 (normal)", Role_None.gren1_limits[9], "", PC_ENGINEER_GRENADE_MAX_1); + + CF_PrintSetting("Scout max grenades type 2 (concussion)", Role_None.gren2_limits[1], "", PC_SCOUT_GRENADE_MAX_2); + CF_PrintSetting("Sniper max grenades type 2 (flare)", Role_None.gren2_limits[2], "", PC_SNIPER_GRENADE_MAX_2); + CF_PrintSetting("Soldier max grenades type 2 (nail/shock)", Role_None.gren2_limits[3], "", PC_SOLDIER_GRENADE_MAX_2); + CF_PrintSetting("Demoman max grenades type 2 (mirv)", Role_None.gren2_limits[4], "", PC_DEMOMAN_GRENADE_MAX_2); + CF_PrintSetting("Medic max grenades type 2 (concussion)", Role_None.gren2_limits[5], "", PC_MEDIC_GRENADE_MAX_2); + CF_PrintSetting("Heavy Weapons max grenades type 2 (mirv)", Role_None.gren2_limits[6], "", PC_HVYWEAP_GRENADE_MAX_2); + CF_PrintSetting("Pyro max grenades type 2 (napalm)", Role_None.gren2_limits[7], "", PC_PYRO_GRENADE_MAX_2); + CF_PrintSetting("Spy max grenades type 2 (gas)", Role_None.gren2_limits[8], "", PC_SPY_GRENADE_MAX_2); + CF_PrintSetting("Engineer max grenades type 2 (emp)", Role_None.gren2_limits[9], "", PC_ENGINEER_GRENADE_MAX_2); sprint(self, PRINT_HIGH, "Concussion effect lasts "); sprint(self, PRINT_HIGH, ftos(cussgrentime)); @@ -649,9 +649,9 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Medic immune to concussion grenade", medicnocuss, "", 1); sprint(self, PRINT_HIGH, "\n== Demolitions Man ==\n"); - if (detpipe_limit > 0) { - CF_PrintSetting("Pipebomb limit (per demoman)", detpipe_limit, "", 0); - } else if (detpipe_limit == 0) { + if (Role_None.detpipe_limit > 0) { + CF_PrintSetting("Pipebomb limit (per demoman)", Role_None.detpipe_limit, "", 0); + } else if (Role_None.detpipe_limit == 0) { sprint(self, PRINT_HIGH, "Pipebomb limit (per demoman): 0 (disallow)\n"); } else { sprint(self, PRINT_HIGH, "Pipebomb limit (per demoman): unlimited\n"); @@ -1417,6 +1417,8 @@ void () TeamFortress_SetEquipment = { if (self.classname != "player") return; + Team_Role * role = GetTeamRole(self.team_no); + kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); self.items = 0; @@ -1487,8 +1489,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.ammo_cells = PC_SCOUT_MAXAMMO_CELL; self.armortype = PC_SCOUT_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_scout; - self.no_grenades_2 = max_gren2_scout; + self.no_grenades_1 = role.gren1_limits[1]; + self.no_grenades_2 = role.gren2_limits[1]; if (old_hp_armor) self.armorvalue = 50; else @@ -1499,8 +1501,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SCOUT_INITAMMO_SHOT; self.ammo_cells = PC_SCOUT_INITAMMO_CELL; self.armortype = PC_SCOUT_INITARMORTYPE; - self.no_grenades_1 = min(PC_SCOUT_GRENADE_INIT_1,max_gren1_scout); - self.no_grenades_2 = min(PC_SCOUT_GRENADE_INIT_2,max_gren2_scout); + self.no_grenades_1 = min(PC_SCOUT_GRENADE_INIT_1,role.gren1_limits[1]); + self.no_grenades_2 = min(PC_SCOUT_GRENADE_INIT_2,role.gren2_limits[1]); if (old_hp_armor) self.armorvalue = 25; @@ -1518,8 +1520,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL; self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT; self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_scout; - self.max_grenades_2 = max_gren2_scout; + self.max_grenades_1 = role.gren1_limits[1]; + self.max_grenades_2 = role.gren2_limits[1]; if (old_grens == 1) self.tp_grenades_1 = GR_TYPE_FLASH; @@ -1554,8 +1556,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.ammo_cells = PC_SNIPER_MAXAMMO_CELL; self.armortype = PC_SNIPER_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_sniper; - self.no_grenades_2 = max_gren2_sniper; + self.no_grenades_1 = role.gren1_limits[2]; + self.no_grenades_2 = role.gren2_limits[2]; if (old_hp_armor) self.armorvalue = 50; else @@ -1566,8 +1568,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SNIPER_INITAMMO_SHOT; self.ammo_cells = PC_SNIPER_INITAMMO_CELL; self.armortype = PC_SNIPER_INITARMORTYPE; - self.no_grenades_1 = min(PC_SNIPER_GRENADE_INIT_1,max_gren1_sniper); - self.no_grenades_2 = min(PC_SNIPER_GRENADE_INIT_2,max_gren2_sniper); + self.no_grenades_1 = min(PC_SNIPER_GRENADE_INIT_1,role.gren1_limits[2]); + self.no_grenades_2 = min(PC_SNIPER_GRENADE_INIT_2,role.gren2_limits[2]); if (old_hp_armor) self.armorvalue = 0; else @@ -1584,8 +1586,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL; self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT; self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_sniper; - self.max_grenades_2 = max_gren2_sniper; + self.max_grenades_1 = role.gren1_limits[2]; + self.max_grenades_2 = role.gren2_limits[2]; self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2; @@ -1612,8 +1614,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.ammo_cells = PC_SOLDIER_MAXAMMO_CELL; self.armortype = PC_SOLDIER_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_soldier; - self.no_grenades_2 = max_gren2_soldier; + self.no_grenades_1 = role.gren1_limits[3]; + self.no_grenades_2 = role.gren2_limits[3]; if (old_hp_armor) self.armorvalue = 200; else @@ -1624,8 +1626,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT; self.ammo_cells = PC_SOLDIER_INITAMMO_CELL; self.armortype = PC_SOLDIER_INITARMORTYPE; - self.no_grenades_1 = min(PC_SOLDIER_GRENADE_INIT_1,max_gren1_soldier); - self.no_grenades_2 = min(PC_SOLDIER_GRENADE_INIT_2,max_gren2_soldier); + self.no_grenades_1 = min(PC_SOLDIER_GRENADE_INIT_1,role.gren1_limits[3]); + self.no_grenades_2 = min(PC_SOLDIER_GRENADE_INIT_2,role.gren2_limits[3]); if (old_hp_armor) self.armorvalue = 100; else @@ -1642,8 +1644,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL; self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT; self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_soldier; - self.max_grenades_2 = max_gren2_soldier; + self.max_grenades_1 = role.gren1_limits[3]; + self.max_grenades_2 = role.gren2_limits[3]; self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2; @@ -1671,8 +1673,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_MAXAMMO_CELL; self.armortype = PC_DEMOMAN_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_demoman; - self.no_grenades_2 = max_gren2_demoman; + self.no_grenades_1 = role.gren1_limits[4]; + self.no_grenades_2 = role.gren2_limits[4]; if (old_hp_armor) self.armorvalue = 120; else @@ -1683,8 +1685,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT; self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL; self.armortype = PC_DEMOMAN_INITARMORTYPE; - self.no_grenades_1 = min(PC_DEMOMAN_GRENADE_INIT_1,max_gren1_demoman); - self.no_grenades_2 = min(PC_DEMOMAN_GRENADE_INIT_2,max_gren2_demoman); + self.no_grenades_1 = min(PC_DEMOMAN_GRENADE_INIT_1,role.gren1_limits[4]); + self.no_grenades_2 = min(PC_DEMOMAN_GRENADE_INIT_2,role.gren2_limits[4]); if (old_hp_armor) self.armorvalue = 50; else @@ -1701,8 +1703,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT; self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_demoman; - self.max_grenades_2 = max_gren2_demoman; + self.max_grenades_1 = role.gren1_limits[4]; + self.max_grenades_2 = role.gren2_limits[4]; self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1; self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2; @@ -1731,8 +1733,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.ammo_cells = PC_MEDIC_MAXAMMO_CELL; self.armortype = PC_MEDIC_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_medic; - self.no_grenades_2 = max_gren2_medic; + self.no_grenades_1 = role.gren1_limits[5]; + self.no_grenades_2 = role.gren2_limits[5]; if (old_hp_armor) self.armorvalue = 100; else @@ -1743,8 +1745,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_MEDIC_INITAMMO_SHOT; self.ammo_cells = PC_MEDIC_INITAMMO_CELL; self.armortype = PC_MEDIC_INITARMORTYPE; - self.no_grenades_1 = min(PC_MEDIC_GRENADE_INIT_1,max_gren1_medic); - self.no_grenades_2 = min(PC_MEDIC_GRENADE_INIT_2,max_gren2_medic); + self.no_grenades_1 = min(PC_MEDIC_GRENADE_INIT_1,role.gren1_limits[5]); + self.no_grenades_2 = min(PC_MEDIC_GRENADE_INIT_2,role.gren2_limits[5]); if (old_hp_armor) self.armorvalue = 50; else @@ -1761,8 +1763,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL; self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT; self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_medic; - self.max_grenades_2 = max_gren2_medic; + self.max_grenades_1 = role.gren1_limits[5]; + self.max_grenades_2 = role.gren2_limits[5]; self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1; self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2; @@ -1810,8 +1812,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_MAXAMMO_CELL; self.armortype = PC_HVYWEAP_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_hwguy; - self.no_grenades_2 = max_gren2_hwguy; + self.no_grenades_1 = role.gren1_limits[6]; + self.no_grenades_2 = role.gren2_limits[6]; if (old_hp_armor) self.armorvalue = 300; @@ -1823,8 +1825,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT; self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL; self.armortype = PC_HVYWEAP_INITARMORTYPE; - self.no_grenades_1 = min(PC_HVYWEAP_GRENADE_INIT_1,max_gren1_hwguy); - self.no_grenades_2 = min(PC_HVYWEAP_GRENADE_INIT_2,max_gren2_hwguy); + self.no_grenades_1 = min(PC_HVYWEAP_GRENADE_INIT_1,role.gren1_limits[6]); + self.no_grenades_2 = min(PC_HVYWEAP_GRENADE_INIT_2,role.gren2_limits[6]); if (old_hp_armor) self.armorvalue = 150; @@ -1842,8 +1844,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT; self.maxammo_cells = PC_HVYWEAP_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_hwguy; - self.max_grenades_2 = max_gren2_hwguy; + self.max_grenades_1 = role.gren1_limits[6]; + self.max_grenades_2 = role.gren2_limits[6]; self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1; self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2; @@ -1871,8 +1873,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_PYRO_MAXAMMO_SHOT; self.ammo_cells = PC_PYRO_MAXAMMO_CELL; self.armortype = PC_PYRO_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_pyro; - self.no_grenades_2 = max_gren2_pyro; + self.no_grenades_1 = role.gren1_limits[7]; + self.no_grenades_2 = role.gren2_limits[7]; if (old_hp_armor) self.armorvalue = 150; else @@ -1883,8 +1885,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_PYRO_INITAMMO_SHOT; self.ammo_cells = PC_PYRO_INITAMMO_CELL; self.armortype = PC_PYRO_INITARMORTYPE; - self.no_grenades_1 = min(PC_PYRO_GRENADE_INIT_1,max_gren1_pyro); - self.no_grenades_2 = min(PC_PYRO_GRENADE_INIT_2,max_gren2_pyro); + self.no_grenades_1 = min(PC_PYRO_GRENADE_INIT_1,role.gren1_limits[7]); + self.no_grenades_2 = min(PC_PYRO_GRENADE_INIT_2,role.gren2_limits[7]); if (old_hp_armor) self.armorvalue = 50; else @@ -1901,8 +1903,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_PYRO_MAXAMMO_NAIL; self.maxammo_shells = PC_PYRO_MAXAMMO_SHOT; self.maxammo_cells = PC_PYRO_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_pyro; - self.max_grenades_2 = max_gren2_pyro; + self.max_grenades_1 = role.gren1_limits[7]; + self.max_grenades_2 = role.gren2_limits[7]; self.tp_grenades_1 = PC_PYRO_GRENADE_TYPE_1; self.tp_grenades_2 = PC_PYRO_GRENADE_TYPE_2; @@ -1987,8 +1989,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SPY_MAXAMMO_SHOT; self.ammo_cells = PC_SPY_MAXAMMO_CELL; self.armortype = PC_SPY_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_spy; - self.no_grenades_2 = max_gren2_spy; + self.no_grenades_1 = role.gren1_limits[8]; + self.no_grenades_2 = role.gren2_limits[8]; if (old_hp_armor) self.armorvalue = 100; @@ -2000,8 +2002,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_SPY_INITAMMO_SHOT; self.ammo_cells = PC_SPY_INITAMMO_CELL; self.armortype = PC_SPY_INITARMORTYPE; - self.no_grenades_1 = min(PC_SPY_GRENADE_INIT_1,max_gren1_spy); - self.no_grenades_2 = min(PC_SPY_GRENADE_INIT_2,max_gren2_spy); + self.no_grenades_1 = min(PC_SPY_GRENADE_INIT_1,role.gren1_limits[8]); + self.no_grenades_2 = min(PC_SPY_GRENADE_INIT_2,role.gren2_limits[8]); if (old_hp_armor) self.armorvalue = 25; @@ -2019,8 +2021,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_SPY_MAXAMMO_NAIL; self.maxammo_shells = PC_SPY_MAXAMMO_SHOT; self.maxammo_cells = PC_SPY_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_spy; - self.max_grenades_2 = max_gren2_spy; + self.max_grenades_1 = role.gren1_limits[8]; + self.max_grenades_2 = role.gren2_limits[8]; self.tp_grenades_1 = PC_SPY_GRENADE_TYPE_1; self.tp_grenades_2 = PC_SPY_GRENADE_TYPE_2; @@ -2055,8 +2057,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.ammo_cells = PC_ENGINEER_MAXAMMO_CELL; self.armortype = PC_ENGINEER_MAXARMORTYPE; - self.no_grenades_1 = max_gren1_engineer; - self.no_grenades_2 = max_gren2_engineer; + self.no_grenades_1 = role.gren1_limits[9]; + self.no_grenades_2 = role.gren2_limits[9]; if (old_hp_armor) self.armorvalue = 50; @@ -2068,8 +2070,8 @@ void () TeamFortress_SetEquipment = { self.ammo_shells = PC_ENGINEER_INITAMMO_SHOT; self.ammo_cells = PC_ENGINEER_INITAMMO_CELL; self.armortype = PC_ENGINEER_INITARMORTYPE; - self.no_grenades_1 = min(PC_ENGINEER_GRENADE_INIT_1,max_gren1_engineer); - self.no_grenades_2 = min(PC_ENGINEER_GRENADE_INIT_2,max_gren2_engineer); + self.no_grenades_1 = min(PC_ENGINEER_GRENADE_INIT_1,role.gren1_limits[9]); + self.no_grenades_2 = min(PC_ENGINEER_GRENADE_INIT_2,role.gren2_limits[9]); if (old_hp_armor) self.armorvalue = 25; else @@ -2086,8 +2088,8 @@ void () TeamFortress_SetEquipment = { self.maxammo_nails = PC_ENGINEER_MAXAMMO_NAIL; self.maxammo_shells = PC_ENGINEER_MAXAMMO_SHOT; self.maxammo_cells = PC_ENGINEER_MAXAMMO_CELL; - self.max_grenades_1 = max_gren1_engineer; - self.max_grenades_2 = max_gren2_engineer; + self.max_grenades_1 = role.gren1_limits[9]; + self.max_grenades_2 = role.gren2_limits[9]; self.tp_grenades_1 = PC_ENGINEER_GRENADE_TYPE_1; self.tp_grenades_2 = PC_ENGINEER_GRENADE_TYPE_2; @@ -2359,7 +2361,7 @@ void (float Suicided) TeamFortress_SetupRespawn = { return; if (toggleflags & TFLAG_RESPAWNDELAY) - restime = respawn_delay_time; + restime = GetTeamRole(self.team_no).respawn_delay_time; else restime = 0; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 42bb1f5d..828d4e90 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -953,9 +953,11 @@ float (float tno) TeamFortress_TeamIsCivilian = { float (float pf_team_no, float pf_class) CF_GetClassRestriction = { local float f_max = 0, f_players = TeamFortress_TeamGetNoPlayers(pf_team_no); - local string s_string; + //local string s_string; + Team_Role * role = GetTeamRole(pf_team_no); // set maximum number based on settings +/* if (pf_class == PC_SCOUT) { s_string = infokey(world, "cr_scout"); f_max = stof(s_string); @@ -989,7 +991,10 @@ float (float pf_team_no, float pf_class) CF_GetClassRestriction = { s_string = infokey(world, "cr_randompc"); f_max = stof(s_string); } - +*/ + if (pf_class == PC_SPY && spy_off) return -1; + + f_max = rint(role.class_limits[pf_class]); if (f_max == 0 || f_players < f_max) return f_players; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 452248d3..d8bec852 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1247,7 +1247,9 @@ void () ExplodeOldestPipebomb = { local entity oldest = world; local float numpipes = 0; local float numpipes_total = 0; - + local float detpipe_limit = rint(GetTeamRole(self.team_no)->detpipe_limit); + Team_Role * r = GetTeamRole(self.team_no); + pipe = find(world, classname, "pipebomb"); while (pipe != world) { if (pipe.owner == self) { From 39006505bc6bc38dd5d7c082bdc3797bdf99218d Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 27 Apr 2020 15:48:13 +1200 Subject: [PATCH 0969/2474] when quad roles are active, remove attackers' flag --- ssqc/quadmode.qc | 43 ++++++++++++++++++++++++++++++++--------- ssqc/roles.qc | 50 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 14 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 9a23a342..40fe72f7 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -123,6 +123,7 @@ void () QuadRoundBegin = { local entity te; local entity oldself; + //local entity tfdet; local float counter; localcmd(strcat(strcat("timelimit ", ftos(stof(infokey(world, "round_time")))), "\n")); te = find(world, classname, "func_breakable"); @@ -134,6 +135,39 @@ void () QuadRoundBegin = { cb_prematch = 0; round_active = 1; round_over = 0; + + if(quad_roles) { + //tfdet = find(world, classname, "info_tfdetect"); + if(rounds % 2) { + Team1_Role = &Role_Defence; + Team2_Role = &Role_Attack; + //te = Finditem(tfdet.display_item_status1); + //if(te && te.owned_by == 1) { + //Quad_HideFlag(te); + //} + //te = Finditem(tfdet.display_item_status2); + } else { + Team1_Role = &Role_Attack; + Team2_Role = &Role_Defence; + } + te = find(world, classname, "item_tfgoal"); + while (te) { + if(rounds % 2) { + if(te.team_no == 2 && te.owned_by == 1) { + Quad_UnHideFlag(te); + } else if(te.team_no == 1 && te.owned_by == 2) { + Quad_HideFlag(te); + } + } else { + if(te.team_no == 2 && te.owned_by == 1) { + Quad_HideFlag(te); + } else if(te.team_no == 1 && te.owned_by == 2) { + Quad_UnHideFlag(te); + } + } + te = find(te, classname, "item_tfgoal"); + } + } te = find(world, classname, "player"); while (te != world) { @@ -396,15 +430,6 @@ void () StartQuadRound = te.think = QuadRoundInit; te.nextthink = (time + 1); } - if(quad_roles) { - if(rounds % 2) { - Team1_Role = &Role_Defence; - Team2_Role = &Role_Attack; - } else { - Team1_Role = &Role_Attack; - Team2_Role = &Role_Defence; - } - } }; void () EndQuadRound = { diff --git a/ssqc/roles.qc b/ssqc/roles.qc index 7406732d..5976ef90 100644 --- a/ssqc/roles.qc +++ b/ssqc/roles.qc @@ -1,5 +1,13 @@ #pragma target fte +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +string(float tno) GetTeamName; +void () item_tfgoal_touch; +void CenterPrint(entity, string); + + +float quad_roles; + typedef struct { string name; string prefix; @@ -10,7 +18,6 @@ typedef struct { float class_limits[11]; } Team_Role; -float quad_roles; var Team_Role Role_None = {"Default", "", 6}; var Team_Role Role_Attack = {"Attack", "att_", 6}; var Team_Role Role_Defence = {"Defence", "def_", 6}; @@ -33,8 +40,6 @@ const string CLASSES [11] = { "randompc" }; -float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; - void (Team_Role * role) LoadRole = { role.detpipe_limit = CF_GetSetting(strcat(role.prefix,"dl"), strcat(role.prefix,"detpipe_limit"), ftos(Role_None.detpipe_limit)); role.respawn_delay_time = CF_GetSetting(strcat(role.prefix,"rd"), strcat(role.prefix,"respawn_delay"), ftos(Role_None.respawn_delay_time)); @@ -81,8 +86,6 @@ void () InitTeamRoles = { Team4_Role = &Role_None; }; -string(float tno) GetTeamName; - void (entity e) PrintTeamRoles = { sprint(e, PRINT_HIGH, "\sTeam Roles:\s\n"); if(number_of_teams > 0) { @@ -112,3 +115,40 @@ Team_Role* (float tno) GetTeamRole = { } return &Role_None; }; + +void () item_tfgoal_hidden_touch = { + + if (other.classname != "player") + return; + if (other.health <= 0) + return; + if (cb_prematch) + return; + if (other.is_feigning) + return; + if (other == self.owner) + return; + + // check if a wall or something is in the way of the flag + traceline(other.origin, self.origin, TRUE, world); + if (trace_fraction < 1) + return; + + if(self.owned_by == other.team_no) { + CenterPrint(other, "Unfortunately, your flag is in another castle\n\nYou are Attacking the other base\n"); + } else { + CenterPrint(other, "You are defending the wrong flag!\n\nGet back to your base quickly\n"); + } +} + +void Quad_HideFlag(entity flag) = { + flag.touch = item_tfgoal_hidden_touch; + setmodel(flag, ""); + setsize(flag, flag.goal_min, flag.goal_max); +}; + +void Quad_UnHideFlag(entity flag) = { + flag.touch = item_tfgoal_touch; + setmodel(flag, flag.mdl); + setsize(flag, flag.goal_min, flag.goal_max); +}; From e73138dd187249795e4cb9f319e7bdefccee51ad Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 27 Apr 2020 15:59:16 +1200 Subject: [PATCH 0970/2474] readme update --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a7a5f712..ce6394f3 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ FortressOne Server New features ------ +* localinfo quad_roles 1 enables the use of quad roles. Only works in quad mode: Blue gets the "attack" role first and Red gets the "defence" role. + These roles can be configured by adding the "att_" and "def_" prefix to localinfo settings. Only detpipe_limit, respawn_time, gren limits and class limits are currently supported. + Use `cmd showroles` to see the current configuration. + The team with the "attack" role also has its flag hidden to avoid confusion. * localinfo keep_teams 1/2 - keeps teams upon map change. 1 = same team. 2 = rotate teams * `cmd forcebreak` - new admin command to end the map (and go to vote) * `break` will vote to end the current map or recind your vote in a vote map From d17cca432b8d81457c91f9e2dd9fe7ff6d6b7029 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 27 Apr 2020 16:07:31 +1200 Subject: [PATCH 0971/2474] only keep teams in clan mode --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 1ad3a2b8..ff2f6cb8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -807,7 +807,7 @@ void () DecodeLevelParms = { if (parm11) self.tfstate = parm11; - if (cb_keepteams && parm13 && parm13 > 0 && parm13 <= number_of_teams) { + if (!self.team_no && cb_keepteams && clanbattle && parm13 && parm13 > 0 && parm13 <= number_of_teams) { // 1 = same, 2+ = rotate if(cb_keepteams == 1) { //self.team_no = parm13; From 47b763e968a55eaca1074aeb2af6100f51848e38 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 27 Apr 2020 21:26:49 +1000 Subject: [PATCH 0972/2474] Increase default duel reset delay to 3 seconds --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index f10e0525..9d7b1294 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -628,7 +628,7 @@ void () DecodeLevelParms = { new_emp = CF_GetSetting("nemp", "new_emp", "1"); // For duelmode, how soon to reset the winning player (allows for double KOs) - duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "0"); + duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "3"); // remove packs in duelmode [1] duel_no_packs = CF_GetSetting("dnp", "duel_no_packs", "1"); // spawn with all possible grenades [0] From 15c0a4a119c947706ea6d64404653d3d8a592299 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 19 May 2020 11:43:47 +1000 Subject: [PATCH 0973/2474] cap flash damage to 10, min of 1 --- ssqc/scout.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index dd8bcb8b..ebee8a95 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -227,8 +227,12 @@ void FO_FlashExplode() sprint(te, PRINT_HIGH, "You have been flashed!\n"); org = te.origin + (te.mins + te.maxs) * 0.5; frac = (rad - vlen(self.origin - org)) / rad; - dam = 60 * frac; + dam = 10 * frac; deathmsg = DMSG_GREN_FLASH; + if (dam < 1) + { + dam = 1; + } TF_T_Damage(te, self, self.owner, dam, 2, 16 | 4); stuffcmd(te, "play weapons/flashgrenburst.wav\n"); From 594cbc06765e6c18622f5d4625a73d5b79159ed0 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 19 May 2020 20:54:10 +1000 Subject: [PATCH 0974/2474] fix incorrect name on forcespec --- ssqc/commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 88fd7701..623225da 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1031,7 +1031,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { ent = find(world, classname, "player"); while(ent) { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { - bprint4(PRINT_HIGH, ent, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); + bprint4(PRINT_HIGH, ent.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); //stuffcmd(ent, "observe\n"); //forceinfokey(ent, "*spectator", "1"); clientcommand(ent, "observe"); From f17501262836b67711c517889a5b0162e7694397 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 27 May 2020 08:22:26 +1200 Subject: [PATCH 0975/2474] map vote setup and menu --- csqc/csextradefs.qc | 9 +++ csqc/csprogs.src | 2 + csqc/vote.qc | 69 ++++++++++++++++++ share/common_vote.qc | 1 + share/fteextensions.qc | 4 +- ssqc/commands.qc | 5 ++ ssqc/mvdsv.qc | 43 ++++++++--- ssqc/progs.src | 1 + ssqc/vote.qc | 161 +++++++++++++++++++++++++++++++++++++---- ssqc/world.qc | 9 ++- 10 files changed, 274 insertions(+), 30 deletions(-) create mode 100644 csqc/vote.qc create mode 100644 share/common_vote.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 277aade3..53fb4859 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -54,6 +54,15 @@ float grentimer_waiting; //grenade primed, but not thrown float jump_counter; float frames_since_onground; +.string name; +.string description; +.string groupname; +.entity group; +.float team_num; +.float min_val; +.float max_val; +.float cnt; + float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; void(string id, string identify) Hud_DrawIdentifyPanel; diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 2a9c46e4..ff603ed3 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -3,6 +3,7 @@ csdefs.qc csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc +../share/common_vote.qc sui_sys.qc status.qc menu.qc @@ -12,3 +13,4 @@ hud_helpers.qc hud.qc settings.qc input.qc +vote.qc diff --git a/csqc/vote.qc b/csqc/vote.qc new file mode 100644 index 00000000..8dc08f4c --- /dev/null +++ b/csqc/vote.qc @@ -0,0 +1,69 @@ + +/* +"name" "amth1" //map name +"description" "Duel arena, ctf and Sniper War" //description +"groupname" "Duel/Arena" //group +"group" +"min_val" "2" //min players +"max_val" "8" //max players +"team_num" "4" //supported teams + +.cnt = number of current votes +*/ + +entity (string n) AddVoteMapGroup = { + if(!n) { + return world; + } + local entity mg = find(world, classname, "map_group"); + while(mg) { + if(mg.netname == n) { + return mg; + } + mg = find(mg, classname, "map_group"); + } + + mg = spawn(); + mg.classname = "map_group"; + mg.name = n; + return mg; +}; + +entity (string n, string desc, string mapgroup, float num_teams, float min_players, float max_players) AddVoteMap = { + if(!n) { + return world; + } + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(mc.name == n) { + return mc; + } + mc = find(mc, classname, "map_candidate"); + } + + mc = spawn(); + mc.classname = "map_candidate"; + mc.name = n; + mc.description = desc; + mc.groupname = mapgroup; + mc.group = AddVoteMapGroup(mapgroup); + mc.team_num = num_teams?num_teams:2; + mc.min_val = min_players?min_players:6; + mc.max_val = max_players?max_players:16; + return mc; +}; + +float (string n) RemoveVoteMap = { + if(!n) { + return FALSE; + } + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(mc.name == n) { + remove(mc); + return TRUE; + } + mc = find(mc, classname, "map_candidate"); + } + return FALSE; +} diff --git a/share/common_vote.qc b/share/common_vote.qc new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/share/common_vote.qc @@ -0,0 +1 @@ + diff --git a/share/fteextensions.qc b/share/fteextensions.qc index 5bf20380..ba76135f 100644 --- a/share/fteextensions.qc +++ b/share/fteextensions.qc @@ -2706,7 +2706,7 @@ void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, void(entity e, string s) clientcommand = #440; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ #endif #if defined(CSQC) || defined(SSQC) -float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ /* return value is the number of parts created, ie argc */ string(float n) argv = #442; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ void(entity e, entity tagentity, string tagname) setattachment = #443; /* Part of DP_GFX_QUAKE3MODELTAGS*/ searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #444; /* Part of DP_QC_FS_SEARCH @@ -3203,4 +3203,4 @@ accessor filestream : float inline set string = {fputs(this,value);}; }; #endif -#pragma noref 0 \ No newline at end of file +#pragma noref 0 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5cf2b516..8655713d 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -758,6 +758,11 @@ float (string arg1, string arg2, string arg3) ParseCmds = { CaptainPick(self, farg2); } break; + case "mapmenu": + processedCmd = TRUE; + self.current_menu_page = 1; + Vote_Menu_Map(0); + break; case "reportmodel": processedCmd = TRUE; sprint(self, PRINT_HIGH, "Model: ", self.model, " index: ", ftos(self.modelindex), "\n"); diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index ed4bb933..3cafaf66 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -10,23 +10,46 @@ float () UserCmd = return (isProcessed); }; -float () ConsoleCmd { +float (string cmd) ConsoleCmd { local float arg_num; + local string arg_val0, arg_val1, arg_val2; local string tmp; - arg_num = argc(); + if(cmd) { + //FTESV implementation + arg_num = tokenize(cmd); + arg_val0 = argv(0); + arg_val1 = argv(1); + arg_val2 = argv(2); + switch(argv(0)) { + case "vote_addmap": + AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6))); + return TRUE; + case "vote_removemap": + RemoveVoteMap(argv(1)); + return TRUE; + } + } else { + //MVDSV implementation + arg_val0 = argv_mvdsv(0); + arg_val1 = argv_mvdsv(1); + arg_val2 = argv_mvdsv(2); + arg_num = argc(); + } + dprint("MEHT: ConsoleCmd: ",ftos(arg_num),", ", arg_val0, ", ", arg_val1, "\n"); + dprint("MEHT: ConsoleCmd 2: ", cmd, "\n"); if (arg_num == 0) { return (0); } - if (argv_mvdsv(0) == "prematch") { + if (arg_val0 == "prematch") { if (arg_num == 2) { localcmd("localinfo prematch "); - localcmd(argv_mvdsv(1)); + localcmd(arg_val1); localcmd("\n"); return (1); } if (arg_num == 1) { - tmp = infokey (world, argv_mvdsv(0)); + tmp = infokey (world, arg_val0); dprint("prematch is "); dprint("\""); dprint(tmp); @@ -34,11 +57,11 @@ float () ConsoleCmd { return (1); } } - else if (argv_mvdsv(0) == "autorecord") + else if (arg_val0 == "autorecord") { if (arg_num == 2) { localcmd("localinfo demo_auto_left "); - localcmd(argv_mvdsv(1)); + localcmd(arg_val1); localcmd("\n"); return (1); } @@ -56,17 +79,17 @@ float () ConsoleCmd { } } } - else if (argv_mvdsv(0) == "clan") + else if (arg_val0 == "clan") { ClanMode(); return (1); } - else if (argv_mvdsv (0) == "quadmode") + else if (arg_val0 == "quadmode") { QuadMode(); return (1); } - else if (argv_mvdsv (0) == "duelmode") + else if (arg_val0 == "duelmode") { DuelMode(); return (1); diff --git a/ssqc/progs.src b/ssqc/progs.src index e921e52b..07785063 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -12,6 +12,7 @@ status.qc functions.qc menu.qc csmenu.qc +../share/common_vote.qc vote.qc extraents.qc help.qc diff --git a/ssqc/vote.qc b/ssqc/vote.qc index ae706b11..7d2c9320 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1091,8 +1091,6 @@ string (string ps_list, float pf_idx) List_Index = { /* ====== New Vote System ======= */ -void() map_candidate = {}; - /* "netname" "amth1" //map name "broadcast" "Duel arena, ctf and Sniper War" //description @@ -1104,17 +1102,71 @@ void() map_candidate = {}; .cnt = number of current votes */ -void (string name, string desc, string votemap) AddVoteMap = { - if(!name || name == votemap) { - return; +entity (string name) AddVoteMapGroup = { + if(!name) { + return world; + } + local entity mg = find(world, classname, "map_group"); + while(mg) { + if(mg.netname == name) { + return mg; + } + mg = find(mg, classname, "map_group"); + } + + mg = spawn(); + mg.classname = "map_group"; + mg.netname = name; + return mg; +}; + +entity (string name, string desc, string mapgroup, float num_teams, float min_players, float max_players) AddVoteMap = { + if(!name) { + return world; } - local entity mc = spawn(); + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(mc.netname == name) { + return mc; + } + mc = find(mc, classname, "map_candidate"); + } + + mc = spawn(); mc.classname = "map_candidate"; mc.netname = name; mc.broadcast = desc; + mc.team_broadcast = mapgroup; + mc.owner = AddVoteMapGroup(mapgroup); + mc.team_no = num_teams?num_teams:2; + mc.ex_skill_min = min_players?min_players:6; + mc.ex_skill_max = max_players?max_players:16; + return mc; +}; + +float (string name) RemoveVoteMap = { + if(!name) { + return FALSE; + } + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(mc.netname == name) { + dremove(mc); + return TRUE; + } + mc = find(mc, classname, "map_candidate"); + } + return FALSE; +} + +void() map_candidate = { + if(self.team_broadcast && self.team_broadcast != "") { + self.owner = AddVoteMapGroup(self.team_broadcast); + } }; void () InitVoteMaps = { + dprint("MEHT: InitVoteMaps\n"); string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); //No point adding the vote map if it is the current one, and thus known to be missing the ents if(votemap != mapname) { @@ -1124,14 +1176,14 @@ void () InitVoteMaps = { mc.netname = votemap; mc.broadcast = "Currently configured vote map"; } - AddVoteMap("2fort5r", "Basic CTF", votemap); - AddVoteMap("1on1r", "Basic Duel", votemap); - AddVoteMap("sq1", "Basic Arena", votemap); - AddVoteMap("mbasesr", "Futuristic CTF", votemap); - AddVoteMap("amth1", "Basic Everything", votemap); - AddVoteMap("well6", "CTF", votemap); - AddVoteMap("genders2", "Small CTF", votemap); - AddVoteMap("frozen1", "CTF with buttons", votemap); + AddVoteMap("2fort5r", "Basic CTF", "CTF", 2, 8, 20); + AddVoteMap("1on1r", "Basic Duel", "Duel", 2, 2, 2); + AddVoteMap("sq1", "Basic Arena", "Arena", 2, 2, 8); + AddVoteMap("mbasesr", "Futuristic CTF", "CTF", 2, 6, 16); + AddVoteMap("amth1", "Basic Everything", "Duel", 4, 2, 8); + AddVoteMap("well6", "The Well (6)", "CTF", 2, 6, 20); + AddVoteMap("genders2", "Small CTF", "CTF", 2, 6, 20); + AddVoteMap("frozen1", "CTF with buttons", "CTF", 2, 6, 16); }; void (entity p) ListVoteMaps = { @@ -1413,13 +1465,94 @@ void (entity p) VoteToEndMap = { te = find (te, classname, "player"); } if(numvoted > (numplayers / 2)) { + sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, "\bMap ended by majority vote.\b.\n"); vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); votemode = 2; execute_changelevel(); } else { + sound(self, CHAN_AUTO, "misc/secret.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, "\x10",ftos((floor(numplayers/2) + 1) - numvoted),"\x11 more votes required to end the current map.\n"); bprint(PRINT_HIGH, "Type \bbreak\b to toggle your vote.\n"); } } }; + +entity (float index) Vote_Menu_Map_GetMapCandidate = { + local float count = 1; + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(count == index) { + return mc; + } + count++; + mc = find(mc, classname, "map_candidate"); + } + return world; +}; + +void (float update) Vote_Menu_Map; +void (float inp) Vote_Menu_Map_Input = { + sprint(self, PRINT_HIGH, "MEHT: You have chosen... ", ftos(inp), "\n"); + if(inp < 0 || inp > 9) { + Vote_Menu_Map(1); + return; + } + switch (inp) { + case 8: + self.current_menu_page--; + if(self.current_menu_page < 1) { + self.current_menu_page = 1; + } + Vote_Menu_Map(0); + return; + case 9: + self.current_menu_page++; + Vote_Menu_Map(0); + return; + case 0: + return; + } + local entity mc = Vote_Menu_Map_GetMapCandidate((self.current_menu_page - 1) * 7 + inp); + if(mc) { + bprint(PRINT_HIGH, self.netname, " is changing the map to ", mc.netname, "\n"); + if(mc.is_admin) { + ChangeToVotedMap(mc.netname); + } else { + //rcon, but only from clientside to make sure it's allowed + stuffcmd(self, strcat("rcon map ", mc.netname,"\n")); + } + } +}; +void (float update) Vote_Menu_Map = { + // allow toggling team menu using any method to show it + if (!update && self.menu_input == Vote_Menu_Map_Input) { + Menu_Input(0); + return; + } + + // prepare menu strings + local string s_title = strcat("Equations, page ",ftos(self.current_menu_page),"\n\n"); + local string s_8 = Q"\s[8]\s Previous\n"; + local string s_9 = Q"\s[9]\s Next\n"; + local string s_0 = Q"\s[0]\s Exit\n"; + local string s_choices = ""; + local float count = 0, remainder = 0, page = 0; + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + page = floor(count / 7); + if(page == (self.current_menu_page - 1)) { + remainder = count % 7; + s_choices = strcat(s_choices, "\s[\s", ftos(remainder + 1), "\s]\s ", mc.netname, "\n"); + } else if(page >= self.current_menu_page) { + break; + } + count++; + mc = find(mc, classname, "map_candidate"); + } + + Status_Menu(self, Vote_Menu_Map_Input, s_title, s_choices, "\n", s_8, s_9, s_0); + //self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + + strunzone(s_choices); strunzone(s_title); +}; diff --git a/ssqc/world.qc b/ssqc/world.qc index 03a2242e..ebbe8b07 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -313,6 +313,7 @@ void () worldspawn = { precache_sound("shalrath/death.wav"); precache_sound("shalrath/attack2.wav"); precache_sound("blob/sight1.wav"); + precache_sound("misc/secret.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); @@ -339,11 +340,11 @@ void () worldspawn = { vote_total_votes = 0; vote_style = CF_GetSetting("vs", "vote_style", "1"); + //No map candidates in map! Add some defaults... + if(!find(world, classname, "map_candidate")) { + InitVoteMaps(); + } if(votemode) { - //No map candidates in map! Add some defaults... - if(!find(world, classname, "map_candidate")) { - InitVoteMaps(); - } string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); if(world.model != strcat("maps/",votemap,".bsp")) { bprint(PRINT_HIGH, "\bDisabling vote mode as map is not\b ",votemap,"\n"); From 5985ddedcfd904f33133d743d6735beb79695348 Mon Sep 17 00:00:00 2001 From: mehtty <47474496+mehtty@users.noreply.github.com> Date: Wed, 27 May 2020 20:46:41 +1200 Subject: [PATCH 0976/2474] stray bracket --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index f629acf2..a5876058 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1387,7 +1387,7 @@ #define STAT_TEAMNO 33 #define STAT_READY 34 #define STAT_CLASS 35 -] + // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this #define DMN_NOFLASH 256 // see all the things From 367f1f290c371005085b246067a5dae9a0337788 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 28 May 2020 23:20:50 +1200 Subject: [PATCH 0977/2474] general vote mode + map menu allows choosing votes or admin map change --- README.md | 5 +++ csqc/main.qc | 10 ----- csqc/status.qc | 18 --------- ssqc/client.qc | 39 +++++++++++++----- ssqc/commands.qc | 15 +++---- ssqc/mvdsv.qc | 2 - ssqc/qw.qc | 1 + ssqc/vote.qc | 103 +++++++++++++++++++++++++++++++++++++---------- 8 files changed, 124 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index a16e2fc0..96d04c38 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,11 @@ FortressOne Server New features ------ +* `cmd votemap`/`cmd showvotes`/`cmd listmaps` can now be used at any time and are part of the same system +* new server command `vote_removemap ` removes them +* new server command `vote_addmap [mapgroup] [num_teams] [min_players] [max_players]` can be used to add maps to the below menu +* `cmd mapmenu` brings up a map selection menu, which can then either be voted for or changed immediately, provided you have adminpwd/rcon set up +* localinfo vote_threshold 0.5 will set the portion of players required to win a vote * `setinfo killsound 1/2/3` 1 enemies, 2 enemies and teammates, 3 enemies teammates and self * `cmd forcebreak` - new admin command to end the map (and go to vote) * `break` will vote to end the current map or recind your vote in a vote map diff --git a/csqc/main.qc b/csqc/main.qc index d6296203..68a1c50e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -197,16 +197,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("-jump"); } break; - /* - case "impulse": - print("MEHT impulsing ", argv(1) ,"\n"); - if(argv(1) == "5") { - print("MEHT impulsing the menu\n"); - FO_Menu_Special(TRUE); - return TRUE; - } - break; - */ } return FALSE; }; diff --git a/csqc/status.qc b/csqc/status.qc index a84504c9..b6ccdbf8 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -111,24 +111,6 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { if(showingscores) { return; } - /* - drawstring( - [50,350], - strcat("MEHT: Prematch: ", ftos(SBAR.GameMode & 8), ", Round Active: ", ftos(SBAR.GameMode & 16), ", Round Over: ", ftos(SBAR.GameMode & 32), ", CountdownStarted: ", ftos(SBAR.CountdownStarted)), - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - drawstring( - [50,370], - strcat("MEHT: Round: ", ftos(quad_round), "/", ftos(quad_rounds_total)), - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - */ if(text && text != "") { //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); //sui_push_frame(position, size); diff --git a/ssqc/client.qc b/ssqc/client.qc index f10e0525..d8f1447e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -635,7 +635,14 @@ void () DecodeLevelParms = { duel_all_grens = CF_GetSetting("dag", "duel_all_grens", "0"); // After a duel round, print the winners' health stats round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); - + + //Proportion required to trigger a map change + vote_threshold = CF_GetSetting("vt", "vote_threshold", "0.5"); + if(vote_threshold <= 0 || vote_threshold > 1) { + dprint("localinfo vote_threshold was outside of valid range, defaulting to 0.5\n"); + vote_threshold = 0.5; + } + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; @@ -947,8 +954,6 @@ void () PutClientInIntermission = void () execute_changelevel = { local entity pos; - dprint("execute_changelevel()\n"); - intermission_running = 1; intermission_exittime = time + 5; @@ -966,16 +971,17 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_z); local string nextmapstring = vote_result; + local string vm = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); vote_style = CF_GetSetting("vs", "vote_style", "2"); if (vote_style || votemode == 2){ - if(votemode == 1 && vote_result) { + if(votemode == 1 && vote_result && vote_result != vm) { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); - } else if(vote_style == 1 || votemode == 2) { - vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); + } else if((vote_style == 1 && (vote_result == vm || vote_result == "")) || votemode == 2) { + vote_result = vm; localcmd ("localinfo votemode on\n"); //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); - } else { + } else if(vote_style == 2 && (vote_result == vm || vote_result == "")) { vote_result = mapname; } } @@ -1526,6 +1532,18 @@ void () player_touch; void (entity p) SetVoteParams = { + if (!(toggleflags & TFLAG_FIRSTENTRY)) { + toggleflags = parm10; + toggleflags = (toggleflags | TFLAG_FIRSTENTRY); + + //Proportion required to trigger a map change + vote_threshold = CF_GetSetting("vt", "vote_threshold", "0.5"); + if(vote_threshold <= 0 || vote_threshold > 1) { + dprint("localinfo vote_threshold was outside of valid range, defaulting to 0.5\n"); + vote_threshold = 0.5; + } + } + sprint(p, PRINT_HIGH, "Voting time! Use \bcmd listmaps\b to see available maps\n"); sprint(p, PRINT_HIGH, "Use \bcmd votemap \b to state your preference\n"); sprint(p, PRINT_HIGH, "Use \bcmd showvotes\b to see the current voting status\n"); @@ -1880,15 +1898,16 @@ void () NextLevel = { if (already_cycled) return; - + already_cycled = 1; vote_style = CF_GetSetting("vs", "vote_style", "1"); + local string vm = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); if (vote_style || votemode == 2){ - if(votemode == 1 && nextmap) { + if(votemode == 1 && nextmap && nextmap != vm) { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); } else if(vote_style == 1 || votemode == 2) { - nextmap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); + nextmap = vm; localcmd ("localinfo votemode on\n"); //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); } else { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 8655713d..0fac20c8 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -703,7 +703,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "votemap": processedCmd = TRUE; - if(votemode) { + if(vote_style) { if(arg2) { VoteForMap(self, arg2); } @@ -741,14 +741,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "break": processedCmd = TRUE; - if(votemode) { - if(self.vote_map) { - UnvoteForMap(self); - } else { + if(self.vote_map) { + UnvoteForMap(self); + } else { + if(votemode) { sprint(self, PRINT_HIGH, "You haven't voted yet!\n"); + } else { + VoteToEndMap(self); } - } else { - VoteToEndMap(self); } break; case "captainpick": @@ -772,6 +772,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; sprint(self, PRINT_HIGH, "\bUser Commands list:\b\n"); sprint(self, PRINT_HIGH, "cmd adminpwd \n"); + sprint(self, PRINT_HIGH, "cmd mapmenu\b: menu for changing maps\b\n"); if(votemode) { sprint(self, PRINT_HIGH, "cmd listmaps\b: list votable maps\b\n"); sprint(self, PRINT_HIGH, "cmd votemap \b: vote for the specified map\b\n"); diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index 3cafaf66..21a36421 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -36,8 +36,6 @@ float (string cmd) ConsoleCmd { arg_val2 = argv_mvdsv(2); arg_num = argc(); } - dprint("MEHT: ConsoleCmd: ",ftos(arg_num),", ", arg_val0, ", ", arg_val1, "\n"); - dprint("MEHT: ConsoleCmd 2: ", cmd, "\n"); if (arg_num == 0) { return (0); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 368c007e..d124e66d 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -460,6 +460,7 @@ float voting_expires; float vote_anarchy_mode; float vote_total_votes; float vote_style; +float vote_threshold; .float tf_id; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 7d2c9320..5d717945 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1166,7 +1166,6 @@ void() map_candidate = { }; void () InitVoteMaps = { - dprint("MEHT: InitVoteMaps\n"); string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); //No point adding the vote map if it is the current one, and thus known to be missing the ents if(votemap != mapname) { @@ -1272,6 +1271,9 @@ void () EndVoting = { void (string map_name) ChangeToVotedMap = { vote_result = map_name; +// if(!votemode) { +// votemode = 2; +// } EndVoting(); //GotoNextMap(); execute_changelevel(); @@ -1281,7 +1283,7 @@ float () CheckVoting = { if(intermission_running || vote_result) { return FALSE; } - local float totalplayers = 0, numplayers = 0, votedplayers = 0; + local float totalplayers = 0, numplayers = 0, votedplayers = 0, prettythreshold = 0; local entity e = find(world, classname, "player"); while(e) { if(!e.has_disconnected) { @@ -1303,8 +1305,18 @@ float () CheckVoting = { return FALSE; } + prettythreshold = ceil(numplayers * vote_threshold); + if(prettythreshold == (numplayers * vote_threshold)) { + //divides evenly, but need a strict excess, but written in integers + prettythreshold++; + } + + if(!votemode) bprint(PRINT_HIGH, "\bCurrent votes (total of \b",ftos(prettythreshold),"\b needed to change):\b\n"); e = find(world, classname, "map_candidate"); while(e) { + if(e.cnt > 0 && !votemode) { + bprint(PRINT_HIGH, "", e.netname, ": ", ftos(e.cnt), "\n"); + } //unanimous - change immediately if(e.cnt >= totalplayers) { bprint(PRINT_HIGH, "\bUnanimous choice:\b ", e.netname, "\n"); @@ -1318,17 +1330,17 @@ float () CheckVoting = { ChangeToVotedMap(e.netname); return FALSE; } - } else if(voting_expires < time) { + } else if(voting_expires < time || (vote_style && !votemode)) { // do we want this to trigger during anarchy too when hitting majority? - if(e.cnt > (numplayers/2)) { + if(e.cnt > (numplayers * vote_threshold)) { bprint(PRINT_HIGH, "\bTime's up!\b Majority choice: ", e.netname, "\n"); sound(self, CHAN_AUTO, "blob/sight1.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); return FALSE; - } else { + } else if(votemode) { AnarchyMode(); } - break; + if(votemode) break; } e = find(e, classname, "map_candidate"); } @@ -1389,6 +1401,9 @@ void () StartVoting = { vote_anarchy_mode = FALSE; vote_total_votes = 0; bprint(PRINT_HIGH, "Voting has started!\n"); + if(!votemode) { + return; + } sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); if(expires) { bprint(PRINT_HIGH, "Voting closes in ", ftos(expires), " seconds. \bBe quick!\b\n"); @@ -1464,7 +1479,7 @@ void (entity p) VoteToEndMap = { } te = find (te, classname, "player"); } - if(numvoted > (numplayers / 2)) { + if(numvoted > (numplayers * vote_threshold)) { sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, "\bMap ended by majority vote.\b.\n"); vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); @@ -1472,7 +1487,7 @@ void (entity p) VoteToEndMap = { execute_changelevel(); } else { sound(self, CHAN_AUTO, "misc/secret.wav", 1, ATTN_NONE); - bprint(PRINT_HIGH, "\x10",ftos((floor(numplayers/2) + 1) - numvoted),"\x11 more votes required to end the current map.\n"); + bprint(PRINT_HIGH, "\x10",ftos((floor(numplayers * vote_threshold) + 1) - numvoted),"\x11 more votes required to end the current map.\n"); bprint(PRINT_HIGH, "Type \bbreak\b to toggle your vote.\n"); } } @@ -1492,9 +1507,56 @@ entity (float index) Vote_Menu_Map_GetMapCandidate = { }; void (float update) Vote_Menu_Map; +void (float update) Vote_Menu_Map_Action; +void (float inp) Vote_Menu_Map_Action_Input = { + switch (inp) { + case 1: + Menu_Close(self); + VoteForMap(self, self.admin_use.netname); + return; + case 2: + Menu_Close(self); + bprint(PRINT_HIGH, self.netname, " is changing the map to ", self.admin_use.netname, "\n"); + if(self.is_admin) { + ChangeToVotedMap(self.admin_use.netname); + } else { + //rcon, but only from clientside to make sure it's allowed + stuffcmd(self, strcat("rcon map ", self.admin_use.netname,"\n")); + } + return; + case 10: + Vote_Menu_Map(0); + return; + } +}; +void (float update) Vote_Menu_Map_Action = { + // allow toggling team menu using any method to show it + if (!update && self.menu_input == Vote_Menu_Map_Action_Input) { + Menu_Input(0); + return; + } + + //self.admin_use is a map_candidate + if(self.admin_use) { + // prepare menu strings + local string s_title = strcat("\sActions for map\s\n", self.admin_use.netname ,"\n\n"); + local string s_1 = Q"\s[1]\s Vote \n"; + local string s_2 = Q"\s[2]\s Change (Admin)\n"; + local string s_0 = Q"\s[0]\s Back \n"; + + Status_Menu(self, Vote_Menu_Map_Action_Input, s_title, s_1, s_2, "\n", s_0); + + strunzone(s_title); + } else { + sprint(self, PRINT_HIGH, "Something went wrong in the map menu\n"); + Vote_Menu_Map(0); + } + + +}; + void (float inp) Vote_Menu_Map_Input = { - sprint(self, PRINT_HIGH, "MEHT: You have chosen... ", ftos(inp), "\n"); - if(inp < 0 || inp > 9) { + if(inp < 0 || inp > 10) { Vote_Menu_Map(1); return; } @@ -1511,17 +1573,14 @@ void (float inp) Vote_Menu_Map_Input = { Vote_Menu_Map(0); return; case 0: + case 10: + Menu_Close(self); return; } local entity mc = Vote_Menu_Map_GetMapCandidate((self.current_menu_page - 1) * 7 + inp); if(mc) { - bprint(PRINT_HIGH, self.netname, " is changing the map to ", mc.netname, "\n"); - if(mc.is_admin) { - ChangeToVotedMap(mc.netname); - } else { - //rcon, but only from clientside to make sure it's allowed - stuffcmd(self, strcat("rcon map ", mc.netname,"\n")); - } + self.admin_use = mc; + Vote_Menu_Map_Action(0); } }; void (float update) Vote_Menu_Map = { @@ -1532,10 +1591,10 @@ void (float update) Vote_Menu_Map = { } // prepare menu strings - local string s_title = strcat("Equations, page ",ftos(self.current_menu_page),"\n\n"); - local string s_8 = Q"\s[8]\s Previous\n"; - local string s_9 = Q"\s[9]\s Next\n"; - local string s_0 = Q"\s[0]\s Exit\n"; + local string s_title = strcat("\sEquations\s\nPage ",ftos(self.current_menu_page),"\n\n"); + local string s_8 = Q"\s[8]\s Previous \n"; + local string s_9 = Q"\s[9]\s Next \n"; + local string s_0 = Q"\s[0]\s Exit \n"; local string s_choices = ""; local float count = 0, remainder = 0, page = 0; local entity mc = find(world, classname, "map_candidate"); @@ -1543,7 +1602,7 @@ void (float update) Vote_Menu_Map = { page = floor(count / 7); if(page == (self.current_menu_page - 1)) { remainder = count % 7; - s_choices = strcat(s_choices, "\s[\s", ftos(remainder + 1), "\s]\s ", mc.netname, "\n"); + s_choices = strcat(s_choices, "\s[\s", ftos(remainder + 1), "\s]\s ", strpadr(mc.netname, 20), "\n"); } else if(page >= self.current_menu_page) { break; } From fe0e4fe6ffd979cbe1c3bc3b293e782f7c9f29cb Mon Sep 17 00:00:00 2001 From: lordee Date: Fri, 29 May 2020 09:52:26 +1000 Subject: [PATCH 0978/2474] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index af376031..68280329 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* scout has "new" flash grenades - localinfo fo_flash on (default off) * localinfo quad_roles 1 enables the use of quad roles. Only works in quad mode: Blue gets the "attack" role first and Red gets the "defence" role. These roles can be configured by adding the "att_" and "def_" prefix to localinfo settings. Only detpipe_limit, respawn_time, gren limits and class limits are currently supported. Use `cmd showroles` to see the current configuration. From b86238896bbf0f18e45de6f8efa6b499ddc1f13f Mon Sep 17 00:00:00 2001 From: lordee Date: Fri, 29 May 2020 09:57:01 +1000 Subject: [PATCH 0979/2474] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 68280329..d953a5a5 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ * scout has "new" flash grenades - localinfo fo_flash on (default off) +* ability to set client side min and max flash amounts - localinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) * localinfo quad_roles 1 enables the use of quad roles. Only works in quad mode: Blue gets the "attack" role first and Red gets the "defence" role. These roles can be configured by adding the "att_" and "def_" prefix to localinfo settings. Only detpipe_limit, respawn_time, gren limits and class limits are currently supported. Use `cmd showroles` to see the current configuration. From f7ad434abd67d572ab89fd4640101a62306a0b72 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 29 May 2020 18:33:40 +1200 Subject: [PATCH 0980/2474] add lordy's readme line --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9d51e51c..2b4361c9 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ New features * new server command `vote_addmap [mapgroup] [num_teams] [min_players] [max_players]` can be used to add maps to the below menu * `cmd mapmenu` brings up a map selection menu, which can then either be voted for or changed immediately, provided you have adminpwd/rcon set up * localinfo vote_threshold 0.5 will set the portion of players required to win a vote +* scout has "new" flash grenades - localinfo fo_flash on (default off) * localinfo quad_roles 1 enables the use of quad roles. Only works in quad mode: Blue gets the "attack" role first and Red gets the "defence" role. These roles can be configured by adding the "att_" and "def_" prefix to localinfo settings. Only detpipe_limit, respawn_time, gren limits and class limits are currently supported. Use `cmd showroles` to see the current configuration. From 27d20b65c73d3039639c78b12a6123f3ec77fe35 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 29 May 2020 20:00:32 +1200 Subject: [PATCH 0981/2474] add nohitsounds; fix noreturn flagtimers --- README.md | 2 ++ ssqc/client.qc | 6 ++++++ ssqc/combat.qc | 3 +++ ssqc/qw.qc | 2 ++ ssqc/status.qc | 8 ++++++-- ssqc/tfortmap.qc | 6 +++++- 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d953a5a5..e833e87b 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ FortressOne Server New features ------ +* localinfo nohitsounds 1 - disables hitsounds server-wide +* localinfo noreturn 1 - prevents goalitems from returning (will still return from lava) * scout has "new" flash grenades - localinfo fo_flash on (default off) * ability to set client side min and max flash amounts - localinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) * localinfo quad_roles 1 enables the use of quad roles. Only works in quad mode: Blue gets the "attack" role first and Red gets the "defence" role. diff --git a/ssqc/client.qc b/ssqc/client.qc index f4ca82b8..3f751f84 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -681,6 +681,12 @@ void () DecodeLevelParms = { LoadRole(&Role_Defence); InitTeamRoles(); + // never return the goalitems [off] + noreturn = CF_GetSetting("nr", "noreturn", "0"); + + // disable hit sounds [off] + nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index fba912ea..d5a814c3 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -144,6 +144,9 @@ void (entity targ, entity attacker) Killed = { }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { + if(nohitsounds) { + return; + } if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index c9c2d039..50baea53 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -581,6 +581,8 @@ float walls_block_emp; float new_emp; float cb_keepteams; float fo_flashtime; +float noreturn; +float nohitsounds; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/status.qc b/ssqc/status.qc index f6d9dda2..df37bf55 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -663,7 +663,11 @@ void (entity Player, entity Item) UpdateClientFlagStatus = { if((Item.nextthink - time) >= 0) { WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); if(Item.think != tfgoalitem_droptouch) { - WriteFloat(MSG_MULTICAST, rint(Item.bubble_count - time)); + if(noreturn) { + WriteFloat(MSG_MULTICAST, -1); + } else { + WriteFloat(MSG_MULTICAST, rint(Item.bubble_count - time)); + } if((Item.think == tfgoalitem_dropthink || Item.think == tfgoalitem_remove) && !Item.owner) { WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); WriteCoord(MSG_MULTICAST, Item.origin_x); @@ -724,7 +728,7 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { if (Item.origin != Item.oldorigin) { //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in if((Item.nextthink - time) >= 0) { - if(Item.think != tfgoalitem_droptouch) { + if(Item.think != tfgoalitem_droptouch && !noreturn) { st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); } else { st = strcat(st, Q"\s: Dropped\s"); diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 7dd1e62a..c6c1d3b1 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2466,6 +2466,8 @@ void () tfgoalitem_dropthink = { } else { if (pos == -5) { //CONTENT_LAVA self.nextthink = time + 5; + self.think = tfgoalitem_remove; + return; } else { if ((pos == -2) || (pos == -6)) { //CONTENT_SOLID || CONTENT_SKY if (self.camdist < 3) { @@ -2497,7 +2499,9 @@ void () tfgoalitem_dropthink = { } } } - self.think = tfgoalitem_remove; + if(!noreturn) { + self.think = tfgoalitem_remove; + } } }; From 22de942de796bec4b05dd945ed713317cb755955 Mon Sep 17 00:00:00 2001 From: fdittz Date: Tue, 2 Jun 2020 12:06:12 -0300 Subject: [PATCH 0982/2474] fixing bug when selecting a weapon that you don't have - issue #403 --- ssqc/weapons.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 3bd63869..42e13d8e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2523,8 +2523,10 @@ void (float inp) W_OldWeaponSlot = { if (self.next_weapon == WEAP_GRENADE_LAUNCHER) self.next_weaponmode = 1; } - if (self.next_weapon == 0) + if (self.next_weapon == 0) { + self.next_weapon = self.current_weapon; sprint(self, PRINT_HIGH, "No weapon\n"); + } } float (float newSlot) W_OldImpulseFromNewSlot = { From 5e2c0e5ade8e9c5ea517efa854ed84955d2f58ec Mon Sep 17 00:00:00 2001 From: fdittz Date: Sat, 6 Jun 2020 13:55:57 -0300 Subject: [PATCH 0983/2474] whitelisting flaginfo and inv, allowing their use while reloading --- ssqc/weapons.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 42e13d8e..355bfb1d 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3428,6 +3428,8 @@ void () W_WeaponFrame = { case TF_CHANGEPC_SPY: case TF_CHANGEPC_ENGINEER: case TF_CHANGEPC_RANDOM: + case TF_INVENTORY: + case FLAG_INFO: ImpulseCommands(); return; } From 4e8a2a6ab7282a8ad4935adb9e81c9ada59cb46d Mon Sep 17 00:00:00 2001 From: fdittz Date: Sat, 6 Jun 2020 14:38:02 -0300 Subject: [PATCH 0984/2474] allows setting detpack while reloading on toggle, defaults to off --- ssqc/client.qc | 3 +++ ssqc/qw.qc | 1 + ssqc/weapons.qc | 10 ++++++++++ 3 files changed, 14 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 309148da..d304a3cd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -586,6 +586,9 @@ void () DecodeLevelParms = { // ensures detpipe impulse isn't cleared at end of function impulse_queue = CF_GetSetting("impulsequeue", "impulse_queue", "off"); + // whitelists detpack impulses on the list of commands that you're allowed to use while reloading [off] + detpack_when_reloading = CF_GetSetting("detreload", "detpack_while_reloading", "off"); + // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass pyro_type = CF_GetSetting("pyrotype", "pyro_type", "1"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index f6f2cfe6..10a65121 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -566,6 +566,7 @@ float ng_damage; float sng_damage; float old_ng_rof; float impulse_queue; +float detpack_when_reloading; float pyro_type; float pyro_soldiercannon; float flag_follow; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 355bfb1d..d8ffb247 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3432,6 +3432,16 @@ void () W_WeaponFrame = { case FLAG_INFO: ImpulseCommands(); return; + // allows setting detpack while reloading on toggle, defaults to off + case TF_DEMOMAN_DETPACK: + case TF_DETPACK: + case TF_DETPACK_STOP: + case TF_DETPACK_5: + case TF_DETPACK_20: + case TF_DETPACK_50: + if (detpack_when_reloading) + ImpulseCommands(); + return; } // grenade impulses always possible From 4b53f55878fedd49366ed9250a91ea24503f9eca Mon Sep 17 00:00:00 2001 From: Fabio Date: Sat, 6 Jun 2020 19:51:43 -0300 Subject: [PATCH 0985/2474] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8b4681a7..c1aed863 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ New features * Allow team changing. * Any non-valid impulse now closes the active menu. * Option for pyro to rocket jump with incendiary cannnon rockets like soldier `localinfo pyro_soldiercannon on`. +* Option to allow a demoman to place a detpack while reloading his weapon `localinfo detreload on` == Removed === From 90f1597d353a70df83b966fc26898d146f2d4f5d Mon Sep 17 00:00:00 2001 From: fdittz Date: Sun, 7 Jun 2020 23:59:04 -0300 Subject: [PATCH 0986/2474] correcting detreload bug --- ssqc/weapons.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d8ffb247..8e67e7f3 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3439,9 +3439,10 @@ void () W_WeaponFrame = { case TF_DETPACK_5: case TF_DETPACK_20: case TF_DETPACK_50: - if (detpack_when_reloading) + if (detpack_when_reloading) { ImpulseCommands(); - return; + return; + } } // grenade impulses always possible From 41700b2ba094a11bf2a4427877b1c73e5d4b76be Mon Sep 17 00:00:00 2001 From: fdittz Date: Mon, 8 Jun 2020 23:31:31 -0300 Subject: [PATCH 0987/2474] fixing bug when sometimes you switch weapons to axe when reloading + detpacking --- ssqc/demoman.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 1b3a9194..e72f65a0 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -197,6 +197,7 @@ void (float timer) TeamFortress_SetDetpack = { self.immune_to_check = time + 10; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; self.weapon = self.current_weapon; + self.next_weapon = self.current_weapon; self.current_weapon = 0; self.weaponmodel = ""; self.weaponframe = 0; @@ -238,7 +239,7 @@ void () TeamFortress_DetpackStop = { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); self.is_detpacking = 0; self.detpack_left = 0; - self.current_weapon = self.weapon; + self.current_weapon = self.next_weapon; Status_Refresh(self); W_SetCurrentAmmo(self); @@ -265,7 +266,7 @@ void () TeamFortress_DetpackSet = { oldself = self; self = self.owner; self.is_detpacking = 0; - self.current_weapon = self.weapon; + self.current_weapon = self.next_weapon; Status_Refresh(self); W_SetCurrentAmmo(self); self = oldself; From 5a80bd381d7986f8be49099bc9f59ffb5325ec4a Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 21 Jun 2020 12:36:31 +1000 Subject: [PATCH 0988/2474] make flag follow not get in front of player, remove some thinks, make it better behaved, fixes #44 --- ssqc/tfortmap.qc | 64 +++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index c6c1d3b1..4697bc69 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2067,30 +2067,8 @@ void () tfgoal_timer_tick = { } }; -void () CF_FlagFollowPlayer = { - if ((self.owner.goal_state == 1) && (self.real_owner.items & (IT_KEY1 | IT_KEY2))) { - makevectors(self.real_owner.angles); - self.owner.origin = self.real_owner.origin - v_forward * 25 - v_right * 0 + v_up * 10; - self.owner.angles = self.real_owner.angles + '0 90 16'; - if (self.owner.mdl == "progs/tf_flag.mdl") { - self.owner.origin_z = self.owner.origin_z + 6; - } else { - self.owner.origin_z = self.owner.origin_z - 6; - } - setorigin(self.owner, self.owner.origin); - FO_SetModel(self.owner, self.owner.mdl); - self.nextthink = time + 0.1; - } else { - dremove(self); - } -}; - -void () idle_think = { - self.nextthink = time + 0.1; -} - void () item_tfgoal_touch = { - local entity te, flw; + local entity te; if (other.classname != "player") return; @@ -2191,17 +2169,39 @@ void () item_tfgoal_touch = { } if (flag_follow) { - flw = spawn(); - flw.real_owner = other; - flw.owner = self; - flw.think = CF_FlagFollowPlayer; - //flw.solid = SOLID_NOT; - //self.solid = SOLID_NOT; - self.think = idle_think; - flw.nextthink = time + 0.1; + newmis = spawn(); + newmis.owner = other; + newmis.classname = "flagfollow"; + newmis.solid = SOLID_NOT; + newmis.mdl = self.mdl; + FO_SetModel(newmis, self.mdl); + setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); + vector org; + org = other.origin + '-25 0 10'; + setorigin (newmis, org); + newmis.skin = self.skin; + newmis.movetype = MOVETYPE_FOLLOW; + newmis.aiment = other; + newmis.view_ofs = newmis.origin - other.origin; } }; +void RemoveFlagFollow(entity player) +{ + if (flag_follow) + { + entity ff = find(world, classname, "flagfollow"); + while (ff) + { + if (ff.owner == player) + { + dremove(ff); + } + ff = find(ff, classname, "flagfollow"); + } + } +} + void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { Item.effects = 0; @@ -2325,6 +2325,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { //Flag if ((Item.goal_activation & 1)) { local float timecarried = gametime - AP.goalrunningtime; + RemoveFlagFollow(AP); LogEventFumble(AP, timecarried); } @@ -2909,6 +2910,7 @@ void () DropGoalItems = { //Always allow dropping 4096 else if (self.effects & EF_DIMLIGHT || te.goal_activation & 4096) { timecarried = gametime - self.goalrunningtime; + RemoveFlagFollow(self); LogEventFumble(self, timecarried); te.angles = '0 0 0'; tfgoalitem_RemoveEffectsFromPlayer(te, self); From 4a84bffd76b36abcfbed4b8f3c11b5c287f65a32 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 28 Jun 2020 20:04:02 +1000 Subject: [PATCH 0989/2474] make plats use team_no if set --- ssqc/plats.qc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ssqc/plats.qc b/ssqc/plats.qc index daf4d877..d42cb627 100644 --- a/ssqc/plats.qc +++ b/ssqc/plats.qc @@ -81,6 +81,14 @@ void () plat_center_touch = { if (other.classname != "player") return; + if (self.team_no != 0) + { + if (other.team_no != self.team_no) + { + return; + } + } + if (other.playerclass == 0) return; @@ -198,6 +206,17 @@ void () func_plat = { setmodel(self, self.model); setsize(self, self.mins, self.maxs); + switch(self.allowteams) + { + case "blue": + self.team_no = 1; + break; + case "red": + self.team_no = 2; + break; + default: + } + self.blocked = plat_crush; if (!self.speed) From c4f39d9de3f794a7337771c85d44f8409e0a903b Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 29 Jun 2020 09:20:02 +1000 Subject: [PATCH 0990/2474] allow teleport to be affected by goal_state, add default goal state function for map entities --- share/defs.h | 1 + ssqc/qw.qc | 4 +++ ssqc/tfortmap.qc | 70 +++++++++++++++++++++++++++++++++++++++++------- ssqc/triggers.qc | 5 ++++ 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/share/defs.h b/share/defs.h index a5876058..7ddb66af 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1187,6 +1187,7 @@ #define TFSP_REMOVESELF 1 // Remove itself after being spawned on // Defines for Goal States +#define TFGS_NONE 0 #define TFGS_ACTIVE 1 #define TFGS_INACTIVE 2 #define TFGS_REMOVED 3 diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 10a65121..cd19e6b1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -690,3 +690,7 @@ float canlog; // flash stuff float FO_FlashDimension; + + +// allow for default goal state +.float default_group_no; \ No newline at end of file diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index c6c1d3b1..87e08952 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -288,7 +288,7 @@ void () TF_StartItem = { UpdateAbbreviations(self); self.nextthink = time + 0.2; self.think = TF_PlaceItem; - if (self.goal_state == 3) + if (self.goal_state == TFGS_REMOVED) RemoveGoal(self); }; @@ -328,7 +328,7 @@ void () TF_StartGoal = { self.nextthink = time + 0.2; self.think = TF_PlaceGoal; self.use = info_tfgoal_use; - if (self.goal_state == 3) + if (self.goal_state == TFGS_REMOVED) RemoveGoal(self); }; @@ -647,7 +647,7 @@ entity(float gno) Findteamspawn = }; void (entity Goal) InactivateGoal = { - if (Goal.goal_state == 1) { + if (Goal.goal_state == TFGS_ACTIVE) { if (Goal.search_time == 0) { if ((Goal.goal_activation & 8192) && (Goal.classname == "item_tfgoal")) @@ -655,26 +655,37 @@ void (entity Goal) InactivateGoal = { else Goal.solid = SOLID_TRIGGER; } - Goal.goal_state = 2; + Goal.goal_state = TFGS_INACTIVE; if (Goal.mdl != string_null && !(duelmode && duel_no_packs)) { FO_SetModel(Goal, Goal.mdl); } } }; +void DefaultGoalState (entity Goal) +{ + if ((Goal.goal_activation & 8192) && + (Goal.classname == "item_tfgoal")) { + Goal.solid = SOLID_BBOX; + } else { + Goal.solid = SOLID_TRIGGER; + } + Goal.goal_state = TFGS_NONE; +} + void (entity Goal) RestoreGoal = { - if (Goal.goal_state == 3) { + if (Goal.goal_state == TFGS_REMOVED) { if (Goal.search_time == 0) { if ((Goal.goal_activation & 8192) && (Goal.classname == "item_tfgoal")) { - Goal.solid = 2; + Goal.solid = SOLID_BBOX; } else { - Goal.solid = 1; + Goal.solid = SOLID_TRIGGER; } } else { Goal.nextthink = time + Goal.search_time; } - Goal.goal_state = 2; + Goal.goal_state = TFGS_INACTIVE; if (Goal.model) { FO_SetModel(Goal, Goal.mdl); setsize(Goal, Goal.goal_min, Goal.goal_max); @@ -689,7 +700,7 @@ void (entity Goal) RestoreGoal = { void (entity Goal) RemoveGoal = { Goal.solid = 0; - Goal.goal_state = 3; + Goal.goal_state = TFGS_REMOVED; if (Goal.mdl != string_null) FO_SetModel(Goal, string_null); }; @@ -1556,6 +1567,14 @@ void (entity Goal, entity AP) DoGroupWork = { } tg = find(tg, classname, "info_tfgoal"); } + + tg = find(world, classname, "trigger_teleport"); + while (tg) { + if (tg.group_no == Goal.inactivate_group_no) { + InactivateGoal(tg); + } + tg = find(tg, classname, "trigger_teleport"); + } } if (Goal.remove_group_no != 0) { tg = find(world, classname, "info_tfgoal"); @@ -1565,6 +1584,14 @@ void (entity Goal, entity AP) DoGroupWork = { } tg = find(tg, classname, "info_tfgoal"); } + + tg = find(world, classname, "trigger_teleport"); + while (tg) { + if (tg.group_no == Goal.remove_group_no) { + RemoveGoal(tg); + } + tg = find(tg, classname, "trigger_teleport"); + } } if (Goal.restore_group_no != 0) { tg = find(world, classname, "info_tfgoal"); @@ -1574,7 +1601,32 @@ void (entity Goal, entity AP) DoGroupWork = { } tg = find(tg, classname, "info_tfgoal"); } + tg = find(world, classname, "trigger_teleport"); + while (tg) { + if (tg.group_no == Goal.restore_group_no) { + RestoreGoal(tg); + } + tg = find(tg, classname, "trigger_teleport"); + } + } + if (Goal.default_group_no != 0) + { + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.group_no == Goal.default_group_no) { + DefaultGoalState(tg); + } + tg = find(tg, classname, "info_tfgoal"); + } + tg = find(world, classname, "trigger_teleport"); + while (tg) { + if (tg.group_no == Goal.default_group_no) { + DefaultGoalState(tg); + } + tg = find(tg, classname, "trigger_teleport"); + } } + if (Goal.remove_spawngroup != 0) { tg = find(world, classname, "info_player_teamspawn"); while (tg) { diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index cd1a1cf1..a239e258 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -312,6 +312,11 @@ void () teleport_touch = { } return; } + + + if (self.goal_state == TFGS_REMOVED) + return; + // only teleport living creatures if ((other.health <= 0) || (other.solid != 3)) return; From 5c59c81d943abe366e9434c5a6cf9971207545fc Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 29 Jun 2020 22:52:27 +1000 Subject: [PATCH 0991/2474] Move default placings a little --- csqc/hud.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/csqc/hud.qc b/csqc/hud.qc index d6505716..d4d61e32 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -78,6 +78,10 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height / 2 + Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.y]; Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 130]; Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 200]; + Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_CLIPSIZE].FillSize.x / 2), height - 50]; + Hud_Panels[HUD_PANEL_GREN1].Position = [0, height - 320]; + Hud_Panels[HUD_PANEL_GREN2].Position = [0, height - 320 + Hud_Panels[HUD_PANEL_GREN1].FillSize.y]; + Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_GRENTIMER].FillSize.x / 2), height - 100]; } void FO_Hud_Editor_List_Panels() = { From 710c8645e5e4a23078891720a974323dd30076c9 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 30 Jun 2020 00:01:58 +1000 Subject: [PATCH 0992/2474] add hip rotate ents --- ssqc/progs.src | 1 + ssqc/rotate.qc | 1197 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1198 insertions(+) create mode 100644 ssqc/rotate.qc diff --git a/ssqc/progs.src b/ssqc/progs.src index f540de1b..a8cf2a8c 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -60,3 +60,4 @@ actions.qc spect.qc q3.qc mvdsv.qc +rotate.qc \ No newline at end of file diff --git a/ssqc/rotate.qc b/ssqc/rotate.qc new file mode 100644 index 00000000..a7add9a6 --- /dev/null +++ b/ssqc/rotate.qc @@ -0,0 +1,1197 @@ +/* Rotate QuickC program + By Jim Dose' 10/17/96 + Copyright (c)1996 Hipnotic Interactive, Inc. + All rights reserved. + Distributed (unsupported) on 3.12.97 +*/ + +float ROT_STATE_ACTIVE = 0; +float ROT_STATE_INACTIVE = 1; +float ROT_STATE_SPEEDINGUP = 2; +float ROT_STATE_SLOWINGDOWN = 3; + +float ROT_STATE_CLOSED = 4; +float ROT_STATE_OPEN = 5; +float ROT_STATE_OPENING = 6; +float ROT_STATE_CLOSING = 7; + +float ROT_STATE_WAIT = 0; +float ROT_STATE_MOVE = 1; +float ROT_STATE_STOP = 2; +float ROT_STATE_FIND = 3; +float ROT_STATE_NEXT = 4; + +float ROT_OBJECT_ROTATE = 0; +float ROT_OBJECT_MOVEWALL = 1; +float ROT_OBJECT_SETORIGIN = 2; + +// spawnflags for func_rotate_entity +float ROT_ROTATE_ENTITY_TOGGLE = 1; +float ROT_ROTATE_ENTITY_START_ON = 2; + +// spawnflags for path_rotate +float ROT_PATH_ROTATE_ROTATION = 1; +float ROT_PATH_ROTATE_ANGLES = 2; +float ROT_PATH_ROTATE_STOP = 4; +float ROT_PATH_ROTATE_NO_ROTATE = 8; +float ROT_PATH_ROTATE_DAMAGE = 16; +float ROT_PATH_ROTATE_MOVETIME = 32; +float ROT_PATH_ROTATE_SET_DAMAGE = 64; + +// spawnflags for func_rotate_door +float ROT_ROTATE_DOOR_STAYOPEN = 1; + +// spawnflags for func_movewall +float ROT_MOVEWALL_VISIBLE = 1; +float ROT_MOVEWALL_TOUCH = 2; +float ROT_MOVEWALL_NONBLOCKING = 4; + +.float rotate_type; +.vector neworigin; +.vector rotate; +.float endtime; +.float duration; +.vector finalangle; +.string path; +.string group; +.string event; + + +//========================= +// +// SUB_NormalizeAngles +// +//========================= + +vector (vector ang) SUB_NormalizeAngles = +{ + while( ang_x > 360 ) + { + ang_x = ang_x - 360; + } + while( ang_x < 0 ) + { + ang_x = ang_x + 360; + } + + while( ang_y > 360 ) + { + ang_y = ang_y - 360; + } + while( ang_y < 0 ) + { + ang_y = ang_y + 360; + } + + while( ang_z > 360 ) + { + ang_z = ang_z - 360; + } + while( ang_z < 0 ) + { + ang_z = ang_z + 360; + } + + return ang; +}; + +/*QUAKED info_rotate (0 0.5 0) (-4 -4 -4) (4 4 4) +Used as the point of rotation for rotatable objects. +*/ +void() info_rotate = +{ +// remove self after a little while, to make sure that entities that +// have targeted it have had a chance to spawn + self.nextthink = time + 2; + self.think = SUB_Remove; +}; + +void() RotateTargets = +{ + local entity ent; + local vector vx; + local vector vy; + local vector vz; + local vector org; + + makevectors (self.angles); + + ent = find( world, targetname, self.target); + while( ent ) + { + if ( ent.rotate_type == ROT_OBJECT_SETORIGIN ) + { + org = ent.oldorigin; + vx = ( v_forward * org_x ); + vy = ( v_right * org_y ); + vy = vy * -1; + vz = ( v_up * org_z ); + ent.neworigin = vx + vy + vz; + setorigin( ent, ent.neworigin + self.origin ); + } + else if ( ent.rotate_type == ROT_OBJECT_ROTATE ) + { + ent.angles = self.angles; + org = ent.oldorigin; + vx = ( v_forward * org_x ); + vy = ( v_right * org_y ); + vy = vy * -1; + vz = ( v_up * org_z ); + ent.neworigin = vx + vy + vz; + setorigin( ent, ent.neworigin + self.origin ); + } + else + { + org = ent.oldorigin; + vx = ( v_forward * org_x ); + vy = ( v_right * org_y ); + vy = vy * -1; + vz = ( v_up * org_z ); + ent.neworigin = vx + vy + vz; + ent.neworigin = self.origin - self.oldorigin + (ent.neworigin - ent.oldorigin); + ent.velocity = (ent.neworigin-ent.origin)*25; + } + ent = find( ent, targetname, self.target); + } +}; + +void() RotateTargetsFinal = + { + local entity ent; + + ent = find( world, targetname, self.target); + while( ent ) + { + ent.velocity = '0 0 0'; + if ( ent.rotate_type == ROT_OBJECT_ROTATE ) + { + ent.angles = self.angles; + } + ent = find( ent, targetname, self.target); + } + }; + +void() SetTargetOrigin = + { + local entity ent; + + ent = find( world, targetname, self.target); + while( ent ) + { + if ( ent.rotate_type == ROT_OBJECT_MOVEWALL ) + { + setorigin( ent, self.origin - self.oldorigin + + (ent.neworigin - ent.oldorigin) ); + } + else + { + setorigin( ent, ent.neworigin + self.origin ); + } + ent = find( ent, targetname, self.target); + } + }; + +void() LinkRotateTargets = + { + local entity ent; + local vector tempvec; + + self.oldorigin = self.origin; + ent = find( world, targetname, self.target); + while( ent ) + { + if ( ent.classname == "rotate_object" ) + { + ent.rotate_type = ROT_OBJECT_ROTATE; + ent.oldorigin = ent.origin - self.oldorigin; + ent.neworigin = ent.origin - self.oldorigin; + ent.owner = self; + } + else if ( ent.classname == "func_movewall" ) + { + ent.rotate_type = ROT_OBJECT_MOVEWALL; + tempvec = ( ent.absmin + ent.absmax ) * 0.5; + ent.oldorigin = tempvec - self.oldorigin; + ent.neworigin = ent.oldorigin; + ent.owner = self; + } + else + { + ent.rotate_type = ROT_OBJECT_SETORIGIN; + ent.oldorigin = ent.origin - self.oldorigin; + ent.neworigin = ent.origin - self.oldorigin; + } + ent = find (ent, targetname, self.target); + } + }; + +void( entity ent, float amount ) hurt_setdamage = + { + ent.dmg = amount; + if ( !amount ) + { + ent.solid = SOLID_NOT; + } + else + { + ent.solid = SOLID_TRIGGER; + } + ent.nextthink = -1; + }; + +void( float amount ) SetDamageOnTargets = + { + local entity ent; + + ent = find( world, targetname, self.target); + while( ent ) + { + if ( ent.classname == "trigger_hurt" ) + { + hurt_setdamage( ent, amount ); + } + else if ( ent.classname == "func_movewall" ) + { + ent.dmg = amount; + } + ent = find( ent, targetname, self.target); + } + }; + + +//************************************************ +// +// Simple continual rotatation +// +//************************************************ + +void() rotate_entity_think = + { + local float t; + + t = time - self.ltime; + self.ltime = time; + + if ( self.state == ROT_STATE_SPEEDINGUP ) + { + self.count = self.count + self.cnt * t; + if ( self.count > 1 ) + { + self.count = 1; + } + + // get rate of rotation + t = t * self.count; + } + else if ( self.state == ROT_STATE_SLOWINGDOWN ) + { + self.count = self.count - self.cnt * t; + if ( self.count < 0 ) + { + RotateTargetsFinal(); + self.state = ROT_STATE_INACTIVE; + self.think = SUB_Null; + return; + } + + // get rate of rotation + t = t * self.count; + } + + self.angles = self.angles + ( self.rotate * t ); + self.angles = SUB_NormalizeAngles( self.angles ); + RotateTargets(); + self.nextthink = time + 0.02; + }; + +void() rotate_entity_use = + { + // change to alternate textures + self.frame = 1 - self.frame; + + if ( self.state == ROT_STATE_ACTIVE ) + { + if ( self.spawnflags & ROT_ROTATE_ENTITY_TOGGLE ) + { + if ( self.speed ) + { + self.count = 1; + self.state = ROT_STATE_SLOWINGDOWN; + } + else + { + self.state = ROT_STATE_INACTIVE; + self.think = SUB_Null; + } + } + } + else if ( self.state == ROT_STATE_INACTIVE ) + { + self.think = rotate_entity_think; + self.nextthink = time + 0.02; + self.ltime = time; + if ( self.speed ) + { + self.count = 0; + self.state = ROT_STATE_SPEEDINGUP; + } + else + { + self.state = ROT_STATE_ACTIVE; + } + } + else if ( self.state == ROT_STATE_SPEEDINGUP ) + { + if ( self.spawnflags & ROT_ROTATE_ENTITY_TOGGLE ) + { + self.state = ROT_STATE_SLOWINGDOWN; + } + } + else + { + self.state = ROT_STATE_SPEEDINGUP; + } + }; + +void() rotate_entity_firstthink = + { + LinkRotateTargets(); + if ( self.spawnflags & ROT_ROTATE_ENTITY_START_ON ) + { + self.state = ROT_STATE_ACTIVE; + self.think = rotate_entity_think; + self.nextthink = time + 0.02; + self.ltime = time; + } + else + { + self.state = ROT_STATE_INACTIVE; + self.think = SUB_Null; + } + self.use = rotate_entity_use; + }; + +/*QUAKED func_rotate_entity (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE START_ON +Creates an entity that continually rotates. Can be toggled on and +off if targeted. + +TOGGLE = allows the rotation to be toggled on/off + +START_ON = wether the entity is spinning when spawned. If TOGGLE is 0, entity can be turned on, but not off. + +If "deathtype" is set with a string, this is the message that will appear when a player is killed by the train. + +"rotate" is the rate to rotate. +"target" is the center of rotation. +"speed" is how long the entity takes to go from standing still to full speed and vice-versa. +*/ + +void() func_rotate_entity = +{ + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_NONE; + + setmodel (self, self.model); + setsize( self, self.mins, self.maxs ); + + if ( self.speed != 0 ) + { + self.cnt = 1 / self.speed; + } + + self.think = rotate_entity_firstthink; + self.nextthink = time + 0.1; + self.ltime = time; +}; + +//************************************************ +// +// Train with rotation functionality +// +//************************************************ + +/*QUAKED path_rotate (0.5 0.3 0) (-8 -8 -8) (8 8 8) ROTATION ANGLES STOP NO_ROTATE DAMAGE MOVETIME SET_DAMAGE + Path for rotate_train. + + ROTATION tells train to rotate at rate specified by "rotate". Use '0 0 0' to stop rotation. + + ANGLES tells train to rotate to the angles specified by "angles" while traveling to this path_rotate. Use values < 0 or > 360 to guarantee that it turns in a certain direction. Having this flag set automatically clears any rotation. + + STOP tells the train to stop and wait to be retriggered. + + NO_ROTATE tells the train to stop rotating when waiting to be triggered. + + DAMAGE tells the train to cause damage based on "dmg". + + MOVETIME tells the train to interpret "speed" as the length of time to take moving from one corner to another. + + SET_DAMAGE tells the train to set all targets damage to "dmg" + + "noise" contains the name of the sound to play when train stops. + "noise1" contains the name of the sound to play when train moves. + "event" is a target to trigger when train arrives at path_rotate. +*/ +void() path_rotate = +{ + if ( self.noise != "" ) + { + precache_sound( self.noise ); + } + if ( self.noise1 != "" ) + { + precache_sound( self.noise1 ); + } +}; + + +void() rotate_train; +void() rotate_train_next; +void() rotate_train_find; + +void() rotate_train_think = + { + local float t; + local float timeelapsed; + + t = time - self.ltime; + self.ltime = time; + + if ( ( self.endtime ) && ( time >= self.endtime ) ) + { + self.endtime = 0; + if ( self.state == ROT_STATE_MOVE ) + { + setorigin(self, self.finaldest); + self.velocity = '0 0 0'; + } + + if (self.think1) + self.think1(); + } + else + { + timeelapsed = (time - self.cnt) * self.duration; + if ( timeelapsed > 1 ) + timeelapsed = 1; + setorigin( self, self.dest1 + ( self.dest2 * timeelapsed ) ); + } + + self.angles = self.angles + ( self.rotate * t ); + self.angles = SUB_NormalizeAngles( self.angles ); + RotateTargets(); + + self.nextthink = time + 0.02; + }; + +void() rotate_train_use = + { + if (self.think1 != rotate_train_find) + { + if ( self.velocity != '0 0 0' ) + return; // already activated + if ( self.think1 ) + { + self.think1(); + } + } + }; + +void() rotate_train_wait = + { + self.state = ROT_STATE_WAIT; + + if ( self.goalentity.noise != "" ) + { + sound (self, CHAN_VOICE, self.goalentity.noise, 1, ATTN_NORM); + } + else + { + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + } + if ( self.goalentity.spawnflags & ROT_PATH_ROTATE_ANGLES ) + { + self.rotate = '0 0 0'; + self.angles = self.finalangle; + } + if ( self.goalentity.spawnflags & ROT_PATH_ROTATE_NO_ROTATE ) + { + self.rotate = '0 0 0'; + } + self.endtime = self.ltime + self.goalentity.wait; + self.think1 = rotate_train_next; + }; + +void() rotate_train_stop = + { + self.state = ROT_STATE_STOP; + + if ( self.goalentity.noise != "" ) + { + sound (self, CHAN_VOICE, self.goalentity.noise, 1, ATTN_NORM); + } + else + { + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + } + if ( self.goalentity.spawnflags & ROT_PATH_ROTATE_ANGLES ) + { + self.rotate = '0 0 0'; + self.angles = self.finalangle; + } + if ( self.goalentity.spawnflags & ROT_PATH_ROTATE_NO_ROTATE ) + { + self.rotate = '0 0 0'; + } + + self.dmg = 0; + self.think1 = rotate_train_next; + }; + +void() rotate_train_next = +{ + local entity targ; + local entity current; + local vector vdestdelta; + local float len, traveltime, div; + local string temp; + + self.state = ROT_STATE_NEXT; + + current = self.goalentity; + targ = find (world, targetname, self.path); + if ( targ.classname != "path_rotate" ) + objerror( "Next target is not path_rotate" ); + + if ( self.goalentity.noise1 != "" ) + { + self.noise1 = self.goalentity.noise1; + } + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + + self.goalentity = targ; + self.path = targ.target; + if (!self.path ) + objerror ("rotate_train_next: no next target"); + + if ( targ.spawnflags & ROT_PATH_ROTATE_STOP ) + { + self.think1 = rotate_train_stop; + } + else if (targ.wait) + { + self.think1 = rotate_train_wait; + } + else + { + self.think1 = rotate_train_next; + } + + if ( current.event != "" ) + { + // Trigger any events that should happen at the corner. + temp = self.target; + self.target = current.event; + self.message = current.message; + SUB_UseTargets(); + self.target = temp; + self.message = string_null; + } + + if ( current.spawnflags & ROT_PATH_ROTATE_ANGLES ) + { + self.rotate = '0 0 0'; + self.angles = self.finalangle; + } + + if ( current.spawnflags & ROT_PATH_ROTATE_ROTATION ) + { + self.rotate = current.rotate; + } + + if ( current.spawnflags & ROT_PATH_ROTATE_DAMAGE ) + { + self.dmg = current.dmg; + } + + if ( current.spawnflags & ROT_PATH_ROTATE_SET_DAMAGE ) + { + SetDamageOnTargets( current.dmg ); + } + + if ( current.speed == -1 ) + { + // Warp to the next path_corner + setorigin( self, targ.origin ); + self.endtime = self.ltime + 0.01; + SetTargetOrigin(); + + if ( targ.spawnflags & ROT_PATH_ROTATE_ANGLES ) + { + self.angles = targ.angles; + } + + self.duration = 1; // 1 / duration + self.cnt = time; // start time + self.dest2 = '0 0 0'; // delta + self.dest1 = self.origin; // original position + self.finaldest = self.origin; + } + else + { + self.state = ROT_STATE_MOVE; + + self.finaldest = targ.origin; + if (self.finaldest == self.origin) + { + self.velocity = '0 0 0'; + self.endtime = self.ltime + 0.1; + + self.duration = 1; // 1 / duration + self.cnt = time; // start time + self.dest2 = '0 0 0'; // delta + self.dest1 = self.origin; // original position + self.finaldest = self.origin; + return; + } + // set destdelta to the vector needed to move + vdestdelta = self.finaldest - self.origin; + + // calculate length of vector + len = vlen (vdestdelta); + + if ( current.spawnflags & ROT_PATH_ROTATE_MOVETIME ) + { + traveltime = current.speed; + } + else + { + // check if there's a speed change + if (current.speed>0) + self.speed = current.speed; + + if (!self.speed) + objerror("No speed is defined!"); + + // divide by speed to get time to reach dest + traveltime = len / self.speed; + } + + if (traveltime < 0.1) + { + self.velocity = '0 0 0'; + self.endtime = self.ltime + 0.1; + if ( targ.spawnflags & ROT_PATH_ROTATE_ANGLES ) + { + self.angles = targ.angles; + } + return; + } + + // qcc won't take vec/float + div = 1 / traveltime; + + if ( targ.spawnflags & ROT_PATH_ROTATE_ANGLES ) + { + self.finalangle = SUB_NormalizeAngles( targ.angles ); + self.rotate = ( targ.angles - self.angles ) * div; + } + + // set endtime to trigger a think when dest is reached + self.endtime = self.ltime + traveltime; + + // scale the destdelta vector by the time spent traveling to get velocity + self.velocity = vdestdelta * div; + + self.duration = div; // 1 / duration + self.cnt = time; // start time + self.dest2 = vdestdelta; // delta + self.dest1 = self.origin; // original position + } + }; + +void() rotate_train_find = + { + local entity targ; + + self.state = ROT_STATE_FIND; + + LinkRotateTargets(); + + // the first target is the point of rotation. + // the second target is the path. + targ = find ( world, targetname, self.path); + if ( targ.classname != "path_rotate" ) + objerror( "Next target is not path_rotate" ); + + // Save the current entity + self.goalentity = targ; + + if ( targ.spawnflags & ROT_PATH_ROTATE_ANGLES ) + { + self.angles = targ.angles; + self.finalangle = SUB_NormalizeAngles( targ.angles ); + } + + self.path = targ.target; + setorigin (self, targ.origin ); + SetTargetOrigin(); + RotateTargetsFinal(); + self.think1 = rotate_train_next; + if (!self.targetname) + { + // not triggered, so start immediately + self.endtime = self.ltime + 0.1; + } + else + { + self.endtime = 0; + } + + self.duration = 1; // 1 / duration + self.cnt = time; // start time + self.dest2 = '0 0 0'; // delta + self.dest1 = self.origin; // original position + }; + +/*QUAKED func_rotate_train (0 .5 .8) (-8 -8 -8) (8 8 8) +In path_rotate, set speed to be the new speed of the train after it reaches +the path change. If speed is -1, the train will warp directly to the next +path change after the specified wait time. If MOVETIME is set on the +path_rotate, the train to interprets "speed" as the length of time to +take moving from one corner to another. + +"noise" contains the name of the sound to play when train stops. +"noise1" contains the name of the sound to play when train moves. +Both "noise" and "noise1" defaults depend upon "sounds" variable and +can be overridden by the "noise" and "noise1" variable in path_rotate. + +Also in path_rotate, if STOP is set, the train will wait until it is +retriggered before moving on to the next goal. + +Trains are moving platforms that players can ride. +"path" specifies the first path_rotate and is the starting position. +If the train is the target of a button or trigger, it will not begin moving until activated. +The func_rotate_train entity is the center of rotation of all objects targeted by it. + +If "deathtype" is set with a string, this is the message that will appear when a player is killed by the train. + +speed default 100 +dmg default 0 +sounds +1) ratchet metal +*/ + +void() rotate_train = + { + objerror ("rotate_train entities should be changed to rotate_object with\nfunc_rotate_train controllers\n"); + }; + +void() func_rotate_train = +{ + if (!self.speed) + self.speed = 100; + if (!self.target) + objerror ("rotate_train without a target"); + + if ( !self.noise ) + { + if (self.sounds == 0) + { + self.noise = ("misc/null.wav"); + } + + if (self.sounds == 1) + { + self.noise = ("plats/train2.wav"); + } + } + if ( !self.noise1 ) + { + if (self.sounds == 0) + { + self.noise1 = ("misc/null.wav"); + } + if (self.sounds == 1) + { + self.noise1 = ("plats/train1.wav"); + } + } + + precache_sound( self.noise ); + precache_sound( self.noise1 ); + + self.cnt = 1; + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_STEP; + self.use = rotate_train_use; + + setmodel (self, self.model); + setsize (self, self.mins, self.maxs); + setorigin (self, self.origin); + +// start trains on the second frame, to make sure their targets have had +// a chance to spawn + self.ltime = time; + self.nextthink = self.ltime + 0.1; + self.endtime = self.ltime + 0.1; + self.think = rotate_train_think; + self.think1 = rotate_train_find; + self.state = ROT_STATE_FIND; + + self.duration = 1; // 1 / duration + self.cnt = 0.1; // start time + self.dest2 = '0 0 0'; // delta + self.dest1 = self.origin; // original position + + + self.flags = self.flags | FL_ONGROUND; +}; + +//************************************************ +// +// Moving clip walls +// +//************************************************ + +void() rotate_door_reversedirection; +void() rotate_door_group_reversedirection; + +void() movewall_touch = + { + if (time < self.owner.attack_finished) + return; + + if ( self.dmg ) + { + T_Damage (other, self, self.owner, self.dmg); + self.owner.attack_finished = time + 0.5; + } + else if ( self.owner.dmg ) + { + T_Damage (other, self, self.owner, self.owner.dmg); + self.owner.attack_finished = time + 0.5; + } + }; + +void() movewall_blocked = + { + local entity temp; + + if (time < self.owner.attack_finished) + return; + + self.owner.attack_finished = time + 0.5; + + if ( self.owner.classname == "func_rotate_door" ) + { + temp = self; + self = self.owner; + rotate_door_group_reversedirection(); + self = temp; + } + + if ( self.dmg ) + { + T_Damage (other, self, self.owner, self.dmg); + self.owner.attack_finished = time + 0.5; + } + else if ( self.owner.dmg ) + { + T_Damage (other, self, self.owner, self.owner.dmg); + self.owner.attack_finished = time + 0.5; + } + }; + +void() movewall_think = + { + self.ltime = time; + self.nextthink = time + 0.02; + }; + +/*QUAKED func_movewall (0 .5 .8) ? VISIBLE TOUCH NONBLOCKING +Used to emulate collision on rotating objects. + +VISIBLE causes brush to be displayed. + +TOUCH specifies whether to cause damage when touched by player. + +NONBLOCKING makes the brush non-solid. This is useless if VISIBLE is set. + +"dmg" specifies the damage to cause when touched or blocked. +*/ +void() func_movewall = +{ + self.angles = '0 0 0'; + self.movetype = MOVETYPE_PUSH; + if ( self.spawnflags & ROT_MOVEWALL_NONBLOCKING ) + { + self.solid = SOLID_NOT; + } + else + { + self.solid = SOLID_BSP; + self.blocked = movewall_blocked; + } + if ( self.spawnflags & ROT_MOVEWALL_TOUCH ) + { + self.touch = movewall_touch; + } + setmodel (self,self.model); + if ( !( self.spawnflags & ROT_MOVEWALL_VISIBLE ) ) + { + self.model = string_null; + } + self.think = movewall_think; + self.nextthink = time + 0.02; + self.ltime = time; +}; + +/*QUAKED rotate_object (0 .5 .8) ? +This defines an object to be rotated. Used as the target of func_rotate_door. +*/ +void() rotate_object = +{ + self.classname = "rotate_object"; + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_NONE; + setmodel (self,self.model); + setsize( self, self.mins, self.maxs ); + self.think = SUB_Null; +}; + +//************************************************ +// +// Rotating doors +// +//************************************************ + +void() rotate_door_think2 = + { + local float t; + + t = time - self.ltime; + self.ltime = time; + + // change to alternate textures + self.frame = 1 - self.frame; + + self.angles = self.dest; + + if ( self.state == ROT_STATE_OPENING ) + { + self.state = ROT_STATE_OPEN; + } + else + { + if ( self.spawnflags & ROT_ROTATE_DOOR_STAYOPEN ) + { + rotate_door_group_reversedirection(); + return; + } + self.state = ROT_STATE_CLOSED; + } + + sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + self.think = SUB_Null; + + RotateTargetsFinal(); + }; + +void() rotate_door_think = + { + local float t; + + t = time - self.ltime; + self.ltime = time; + + if ( time < self.endtime ) + { + self.angles = self.angles + ( self.rotate * t ); + RotateTargets(); + } + else + { + self.angles = self.dest; + RotateTargets(); + self.think = rotate_door_think2; + } + + self.nextthink = time + 0.01; + }; + +void() rotate_door_reversedirection = + { + local vector start; + + // change to alternate textures + self.frame = 1 - self.frame; + + if ( self.state == ROT_STATE_CLOSING ) + { + start = self.dest1; + self.dest = self.dest2; + self.state = ROT_STATE_OPENING; + } + else + { + start = self.dest2; + self.dest = self.dest1; + self.state = ROT_STATE_CLOSING; + } + + sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + + self.rotate = ( self.dest - start ) * ( 1 / self.speed ); + self.think = rotate_door_think; + self.nextthink = time + 0.02; + self.endtime = time + self.speed - ( self.endtime - time ); + self.ltime = time; + }; + +void() rotate_door_group_reversedirection = + { + local string name; + + // tell all associated rotaters to reverse direction + if ( self.group != "" ) + { + name = self.group; + self = find( world, group, name); + while( self ) + { + rotate_door_reversedirection(); + self = find( self, group, name); + } + } + else + { + rotate_door_reversedirection(); + } + }; + +void() rotate_door_use = + { + local vector start; + + if ( ( self.state != ROT_STATE_OPEN ) && ( self.state != ROT_STATE_CLOSED ) ) + return; + + if ( !self.cnt ) + { + self.cnt = 1; + LinkRotateTargets(); + } + + // change to alternate textures + self.frame = 1 - self.frame; + + if ( self.state == ROT_STATE_CLOSED ) + { + start = self.dest1; + self.dest = self.dest2; + self.state = ROT_STATE_OPENING; + } + else + { + start = self.dest2; + self.dest = self.dest1; + self.state = ROT_STATE_CLOSING; + } + + sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + + self.rotate = ( self.dest - start ) * ( 1 / self.speed ); + self.think = rotate_door_think; + self.nextthink = time + 0.01; + self.endtime = time + self.speed; + self.ltime = time; + }; + + +/*QUAKED func_rotate_door (0 .5 .8) (-8 -8 -8) (8 8 8) STAYOPEN +Creates a door that rotates between two positions around a point of +rotation each time it's triggered. + +STAYOPEN tells the door to reopen after closing. This prevents a trigger- +once door from closing again when it's blocked. + +"dmg" specifies the damage to cause when blocked. Defaults to 2. Negative numbers indicate no damage. +"speed" specifies how the time it takes to rotate + +"sounds" +1) medieval (default) +2) metal +3) base +*/ + +void() func_rotate_door = // added slinet option - sounds 4 -- dumptruck_ds +{ + if (!self.target) + { + objerror( "rotate_door without target." ); + } + + self.dest1 = '0 0 0'; + self.dest2 = self.angles; + self.angles = self.dest1; + + // default to 2 seconds + if ( !self.speed ) + { + self.speed = 2; + } + + self.cnt = 0; + + if (!self.dmg) + self.dmg = 2; + else if ( self.dmg < 0 ) + { + self.dmg = 0; + } + + if (self.sounds == 0) + self.sounds = 1; + if (self.sounds == 1) + { + precache_sound ("doors/latch2.wav"); + precache_sound ("doors/winch2.wav"); + precache_sound ("doors/drclos4.wav"); + self.noise1 = "doors/latch2.wav"; + self.noise2 = "doors/winch2.wav"; + self.noise3 = "doors/drclos4.wav"; + } + if (self.sounds == 2) + { + precache_sound ("doors/airdoor1.wav"); + precache_sound ("doors/airdoor2.wav"); + self.noise2 = "doors/airdoor1.wav"; + self.noise1 = "doors/airdoor2.wav"; + self.noise3 = "doors/airdoor2.wav"; + } + if (self.sounds == 3) + { + precache_sound ("doors/basesec1.wav"); + precache_sound ("doors/basesec2.wav"); + self.noise2 = "doors/basesec1.wav"; + self.noise1 = "doors/basesec2.wav"; + self.noise3 = "doors/basesec2.wav"; + } + if (self.sounds == 4) + { + precache_sound ("misc/null.wav"); + precache_sound ("misc/null.wav"); + self.noise2 = "misc/null.wav"; + self.noise1 = "misc/null.wav"; + self.noise3 = "misc/null.wav"; + } + + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_NONE; + setmodel (self, self.model); + setorigin( self, self.origin ); + setsize( self, self.mins, self.maxs ); + self.state = ROT_STATE_CLOSED; + self.use = rotate_door_use; + self.think = SUB_Null; +}; \ No newline at end of file From cd465bffaf24938cfb7ebf1ba34cdd7049b0ef96 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Jun 2020 03:16:07 +1000 Subject: [PATCH 0993/2474] Add some more fo hud defaults --- csqc/hud.qc | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index d4d61e32..172d3747 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -75,13 +75,33 @@ void FO_Hud_Editor_LoadDefaultSettings() */ //Default menus, id, ready and MOTD to centre of the screen Hud_Panels[HUD_PANEL_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), height / 2 - Hud_Panels[HUD_PANEL_MENU].FillSize.y / 2]; - Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height / 2 + Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.y]; + Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height / 2]; Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 130]; Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 200]; - Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_CLIPSIZE].FillSize.x / 2), height - 50]; - Hud_Panels[HUD_PANEL_GREN1].Position = [0, height - 320]; - Hud_Panels[HUD_PANEL_GREN2].Position = [0, height - 320 + Hud_Panels[HUD_PANEL_GREN1].FillSize.y]; - Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_GRENTIMER].FillSize.x / 2), height - 100]; + Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) + 16, height - 50]; + Hud_Panels[HUD_PANEL_GREN2].Position = [(width / 2) - 16 - Hud_Panels[HUD_PANEL_GREN2].FillSize.x * 0.75, height - 50]; + Hud_Panels[HUD_PANEL_GREN1].Position = [(width / 2) - 16 - (Hud_Panels[HUD_PANEL_GREN1].FillSize.x * 2), height - 50]; + Hud_Panels[HUD_PANEL_CLIPSIZE].Scale = 0.75; + Hud_Panels[HUD_PANEL_GREN1].Scale = 0.75; + Hud_Panels[HUD_PANEL_GREN2].Scale = 0.75; + Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, height - 224]; + Hud_Panels[HUD_PANEL_FRAGSTREAK].Display = 0; + Hud_Panels[HUD_PANEL_CAPS].Display = 0; + /* HUD_PANEL_HUDOPTIONS, */ + /* HUD_PANEL_CLIPSIZE, */ + /* HUD_PANEL_FRAGSTREAK, */ + /* HUD_PANEL_CAPS, */ + /* HUD_PANEL_GREN1, */ + /* HUD_PANEL_GREN2, */ + /* HUD_PANEL_PLAYERCLASS, */ + /* HUD_PANEL_IDENTIFY, */ + /* HUD_PANEL_FLAGINFO, */ + /* HUD_PANEL_GRENTIMER, */ + /* HUD_PANEL_MENU, */ + /* HUD_PANEL_MOTD, */ + /* HUD_PANEL_MENU_HINT, */ + /* HUD_PANEL_GAME_MODE, */ + /* HUD_PANEL_READY */ } void FO_Hud_Editor_List_Panels() = { From 2e4f26f970b0551d2b781a30d47d37ab2c2d142b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 30 Jun 2020 19:10:42 +1200 Subject: [PATCH 0994/2474] fix civilians --- ssqc/roles.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/roles.qc b/ssqc/roles.qc index 5976ef90..431a8dbf 100644 --- a/ssqc/roles.qc +++ b/ssqc/roles.qc @@ -15,7 +15,7 @@ typedef struct { float respawn_delay_time; float gren1_limits[10]; float gren2_limits[10]; - float class_limits[11]; + float class_limits[12]; } Team_Role; var Team_Role Role_None = {"Default", "", 6}; @@ -26,7 +26,7 @@ Team_Role * Team2_Role; Team_Role * Team3_Role; Team_Role * Team4_Role; -const string CLASSES [11] = { +const string CLASSES [12] = { "observer", "scout", "sniper", @@ -37,7 +37,8 @@ const string CLASSES [11] = { "pyro", "spy", "engineer", - "randompc" + "randompc", + "civilian" }; void (Team_Role * role) LoadRole = { From 8f14de58d5f79dbaf7a1cc598e1e7c240666d241 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 1 Jul 2020 01:40:44 +1000 Subject: [PATCH 0995/2474] Move hud element defaults --- csqc/hud.qc | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 172d3747..cf8ae293 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -79,14 +79,17 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 130]; Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 200]; Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) + 16, height - 50]; - Hud_Panels[HUD_PANEL_GREN2].Position = [(width / 2) - 16 - Hud_Panels[HUD_PANEL_GREN2].FillSize.x * 0.75, height - 50]; - Hud_Panels[HUD_PANEL_GREN1].Position = [(width / 2) - 16 - (Hud_Panels[HUD_PANEL_GREN1].FillSize.x * 2), height - 50]; Hud_Panels[HUD_PANEL_CLIPSIZE].Scale = 0.75; + Hud_Panels[HUD_PANEL_GREN1].Position = [(width / 2) - 16 - (Hud_Panels[HUD_PANEL_GREN1].FillSize.x * 2), height - 50]; Hud_Panels[HUD_PANEL_GREN1].Scale = 0.75; + Hud_Panels[HUD_PANEL_GREN2].Position = [(width / 2) - 16 - Hud_Panels[HUD_PANEL_GREN2].FillSize.x * 0.75, height - 50]; Hud_Panels[HUD_PANEL_GREN2].Scale = 0.75; Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, height - 224]; + Hud_Panels[HUD_PANEL_GRENTIMER].Scale = 0.75; + Hud_Panels[HUD_PANEL_FLAGINFO].Position = [0, height - 150]; Hud_Panels[HUD_PANEL_FRAGSTREAK].Display = 0; Hud_Panels[HUD_PANEL_CAPS].Display = 0; + Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; /* HUD_PANEL_HUDOPTIONS, */ /* HUD_PANEL_CLIPSIZE, */ /* HUD_PANEL_FRAGSTREAK, */ @@ -376,14 +379,17 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) string msg = ""; //icon = HudIcons[playerclass-1].icon; - icon = HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + /* icon = HudIcons[playerclass+6].icon; */ + /* drawpic(pos, icon, size, '1 1 1', 1, 0); */ float len = 0, offset = 0; switch (playerclass) { case PC_SCOUT: + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = SBAR.ScannerOn ? "Scanning" : "Offline"; pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.ScannerOn) @@ -401,6 +407,9 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_SNIPER: if (SBAR.SniperDam) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = strcat("Dam: ", ftos(SBAR.SniperDam)); pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); @@ -415,6 +424,9 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_DEMOMAN: if (SBAR.IsDetpacking) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = "Setting"; pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); @@ -423,11 +435,17 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } else if (SBAR.DetpackLeft) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = strcat(ftos(SBAR.DetpackLeft), " secs left"); DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } break; case PC_MEDIC: + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = SBAR.AuraActive ? "On" : "Off"; pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.AuraActive) @@ -458,6 +476,9 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_HVYWEAP: if (SBAR.LockedCannon) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = "Assault Cannon Locked"; DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } @@ -465,6 +486,9 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_SPY: if (SBAR.IsUndercover == 1) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + if (SBAR.InvisOnly) { msg = "Invisible"; @@ -480,6 +504,9 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } else if (SBAR.IsUndercover == 2) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + if (SBAR.InvisOnly) { msg = "Invisible"; @@ -524,22 +551,29 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_ENGINEER: if (SBAR.HasSentry) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(rint(SBAR.SentryHealth)), " S: ", ftos(rint(SBAR.SentryAmmoShells)), " R: ", ftos(rint(SBAR.SentryAmmoRockets))); DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } else if (SBAR.IsBuilding) { + icon = HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = strcat(ftos(SBAR.BuildingPercentage), "%"); DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } // disp - pos = [pos_x, pos_y - size_y - 2]; + pos = [pos_x, pos_y + size_y + 2]; basepos = pos; - icon = HudIcons[playerclass + 7].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.HasDispenser) { + icon = HudIcons[playerclass + 7].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = strcat("H: ", ftos(rint(SBAR.DispenserHealth))); DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } From b4335a090ed4e706d773408233ca8fa1a544cac4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 5 Jul 2020 14:21:59 +1000 Subject: [PATCH 0996/2474] Reposition flaginfo --- csqc/hud.qc | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index cf8ae293..ce5a7740 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -86,25 +86,11 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_GREN2].Scale = 0.75; Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, height - 224]; Hud_Panels[HUD_PANEL_GRENTIMER].Scale = 0.75; - Hud_Panels[HUD_PANEL_FLAGINFO].Position = [0, height - 150]; + Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc = FO_HUD_INSERT_AFTER; + Hud_Panels[HUD_PANEL_FLAGINFO].Position = [width - 24, 246]; Hud_Panels[HUD_PANEL_FRAGSTREAK].Display = 0; Hud_Panels[HUD_PANEL_CAPS].Display = 0; Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; - /* HUD_PANEL_HUDOPTIONS, */ - /* HUD_PANEL_CLIPSIZE, */ - /* HUD_PANEL_FRAGSTREAK, */ - /* HUD_PANEL_CAPS, */ - /* HUD_PANEL_GREN1, */ - /* HUD_PANEL_GREN2, */ - /* HUD_PANEL_PLAYERCLASS, */ - /* HUD_PANEL_IDENTIFY, */ - /* HUD_PANEL_FLAGINFO, */ - /* HUD_PANEL_GRENTIMER, */ - /* HUD_PANEL_MENU, */ - /* HUD_PANEL_MOTD, */ - /* HUD_PANEL_MENU_HINT, */ - /* HUD_PANEL_GAME_MODE, */ - /* HUD_PANEL_READY */ } void FO_Hud_Editor_List_Panels() = { From 364882a6fd06babd4716711f82286072a7ff5bf3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jul 2020 14:13:44 +1000 Subject: [PATCH 0997/2474] Use screen height to position flaginfo --- csqc/hud.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index ce5a7740..58892c21 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -87,7 +87,7 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, height - 224]; Hud_Panels[HUD_PANEL_GRENTIMER].Scale = 0.75; Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc = FO_HUD_INSERT_AFTER; - Hud_Panels[HUD_PANEL_FLAGINFO].Position = [width - 24, 246]; + Hud_Panels[HUD_PANEL_FLAGINFO].Position = [width - 24, (height / 2) - 8]; Hud_Panels[HUD_PANEL_FRAGSTREAK].Display = 0; Hud_Panels[HUD_PANEL_CAPS].Display = 0; Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; From 75a07c5eca95bac9b914c351117b4ca6b3625bd8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jul 2020 18:36:34 +1000 Subject: [PATCH 0998/2474] Reposition gren timer hud element --- csqc/hud.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 58892c21..12579177 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -84,7 +84,7 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_GREN1].Scale = 0.75; Hud_Panels[HUD_PANEL_GREN2].Position = [(width / 2) - 16 - Hud_Panels[HUD_PANEL_GREN2].FillSize.x * 0.75, height - 50]; Hud_Panels[HUD_PANEL_GREN2].Scale = 0.75; - Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, height - 224]; + Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, (height / 2) + 32]; Hud_Panels[HUD_PANEL_GRENTIMER].Scale = 0.75; Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc = FO_HUD_INSERT_AFTER; Hud_Panels[HUD_PANEL_FLAGINFO].Position = [width - 24, (height / 2) - 8]; From 94c7cb220fbef81359c17c0cac40112b05b6f8c2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 14 Jul 2020 01:25:22 +1000 Subject: [PATCH 0999/2474] Clean up and add missing binds to controls menu --- menu/options_keys.qc | 77 ++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/menu/options_keys.qc b/menu/options_keys.qc index da53908d..4ec726e3 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -5,62 +5,75 @@ const static struct } binds[] = { {_(""), "Movement"}, - {_("Forwards"), "+forward"}, - {_("Back"), "+back"}, + {0, 0}, + {_("Move Forward"), "+forward"}, + {_("Move Back"), "+back"}, {_("Move Left"), "+moveleft"}, {_("Move Right"), "+moveright"}, - {_("Turn Left"), "+left"}, - {_("Turn Right"), "+right"}, - {_("Look Up"), "+lookup"}, - {_("Look Down"), "+lookdown"}, + {_("Jump"), "+jump"}, {_("Swim Up"), "+moveup"}, {_("Swim Down"), "+movedown"}, - {_("Center view"), "centerview"}, - {_("Jump"), "+jump"}, - {_("Attack"), "+attack"}, - {_("Next Weapon"), "impulse 10"}, - {_("Prev Weapon"), "impulse 12"}, - {_("Scores"), "+showscores"}, - {_("Server Chat"), "messagemode"}, - {_("Team Chat"), "messagemode2"}, - {_("Voice Chat"), "+voip"}, -// {_("Mouse Look"), "+mlook"}, -// {_("Keyboard Look"), "+klook"}, - {_("Strafe"), "+strafe"}, - {_("Run"), "+speed"}, + /* {_("Turn Left"), "+left"}, */ + /* {_("Turn Right"), "+right"}, */ + /* {_("Look Up"), "+lookup"}, */ + /* {_("Look Down"), "+lookdown"}, */ + /* {_("Center view"), "centerview"}, */ {0, 0}, {0, 0}, - {_(""), "Weapons"}, - {_("Primary Weapon"), "weapon 1"}, - {_("Secondary Weapon"), "weapon 2"}, - {_("Last Resort"), "weapon 3"}, - {_("Melee"), "weapon 4"}, + {_(""), "Attack"}, + {0, 0}, + {_("Attack"), "+attack"}, {_("Quick Primary"), "+slot1"}, {_("Quick Secondary"), "+slot2"}, {_("Quick Tertiary"), "+slot3"}, {_("Quick Melee"), "+slot4"}, + {_("Class Special"), "special"}, + {_("Class Menu"), "menu"}, {_("Grenade 1"), "gren1"}, {_("Grenade 2"), "gren2"}, {_("Prime Grenade 1"), "primeone"}, {_("Prime Grenade 2"), "primetwo"}, {_("Throw Grenade"), "throwgren"}, {0, 0}, - {_("Class Special"), "special"}, - {_("Class Menu"), "menu"}, + {0, 0}, + {_(""), "Weapon Select"}, + {0, 0}, + {_("Primary Weapon"), "weapon 1"}, + {_("Secondary Weapon"), "weapon 2"}, + {_("Tertiary Weapon"), "weapon 3"}, + {_("Melee"), "weapon 4"}, + {_("Next Weapon"), "weapnext"}, + {_("Prev Weapon"), "weapprev"}, + {_("Last Weapon"), "weaplast"}, + {0, 0}, + {0, 0}, + {_(""), "Actions"}, {_("Change Class"), "changeclass"}, {_("Change Team"), "changeteam"}, {_("Drop Flag"), "dropitems"}, - {_("Discard Ammo"), "discard"}, + {_("Discard Backpack"), "discard"}, + {_("Discard Ammo"), "dropammo"}, {_("Call For Help"), "saveme"}, {_("Inventory"), "inv"}, {_("Flag Status"), "flaginfo"}, - {_("Map Help"), "maphelp"}, - {0, 0}, + {0, 0}, + {0, 0}, + {_(""), "Misc"}, + {0, 0}, + {_("Scores"), "+showscores"}, {_("Ready Up"), "ready"}, - {_("Break Match"), "break"}, - {_("Spectate"), "observe"}, - {_("Join Match"), "join"}, + {_("Server Chat"), "messagemode"}, + {_("Team Chat"), "messagemode2"}, + {_("Map Help"), "maphelp"}, + /* {_("Break Match"), "break"}, */ + /* {_("Voice Chat"), "+voip"}, */ +// {_("Mouse Look"), "+mlook"}, +// {_("Keyboard Look"), "+klook"}, + /* {_("Strafe"), "+strafe"}, */ + /* {_("Run"), "+speed"}, */ + /* {_("Spectate"), "observe"}, */ + /* {_("Join Match"), "join"}, */ }; void(mitem_desktop desktop) M_Options_Keys = { From 5432c1b1964e2c968dd72887145a6f4acd13415e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 14 Jul 2020 01:27:50 +1000 Subject: [PATCH 1000/2474] Add reload and reloadnext --- menu/options_keys.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/menu/options_keys.qc b/menu/options_keys.qc index 4ec726e3..2edd9ce3 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -48,6 +48,8 @@ const static struct {0, 0}, {0, 0}, {_(""), "Actions"}, + {_("Reload"), "reload"}, + {_("Reload Next"), "reloadnext"}, {_("Change Class"), "changeclass"}, {_("Change Team"), "changeteam"}, {_("Drop Flag"), "dropitems"}, From a11d80ccc8154b9e3d998a484bcb1a5a0da55e8b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 14 Jul 2020 01:39:31 +1000 Subject: [PATCH 1001/2474] Add reload, use proper alias names --- menu/options_keys.qc | 52 ++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/menu/options_keys.qc b/menu/options_keys.qc index 2edd9ce3..bc335ba1 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -20,45 +20,49 @@ const static struct /* {_("Center view"), "centerview"}, */ {0, 0}, {0, 0}, - {_(""), "Attack"}, + {_(""), "Actions"}, {0, 0}, - {_("Attack"), "+attack"}, - {_("Quick Primary"), "+slot1"}, - {_("Quick Secondary"), "+slot2"}, - {_("Quick Tertiary"), "+slot3"}, - {_("Quick Melee"), "+slot4"}, + {_("Fire"), "+attack"}, {_("Class Special"), "special"}, - {_("Class Menu"), "menu"}, + {_("Class Menu"), "fo_menu_special"}, {_("Grenade 1"), "gren1"}, {_("Grenade 2"), "gren2"}, - {_("Prime Grenade 1"), "primeone"}, - {_("Prime Grenade 2"), "primetwo"}, - {_("Throw Grenade"), "throwgren"}, + {_("Reload"), "reload"}, + {_("Reload Next"), "reloadnext"}, + {_("Change Class"), "changeclass"}, + {_("Change Team"), "changeteam"}, + {_("Drop Flag"), "dropflag"}, + {_("Discard Backpack"), "discard"}, + {_("Discard Ammo"), "dropammo"}, + {_("Call For Help"), "saveme"}, {0, 0}, {0, 0}, {_(""), "Weapon Select"}, {0, 0}, + {_("Next Weapon"), "weapnext"}, + {_("Prev Weapon"), "weapprev"}, + {_("Last Weapon"), "weaplast"}, {_("Primary Weapon"), "weapon 1"}, {_("Secondary Weapon"), "weapon 2"}, {_("Tertiary Weapon"), "weapon 3"}, {_("Melee"), "weapon 4"}, - {_("Next Weapon"), "weapnext"}, - {_("Prev Weapon"), "weapprev"}, - {_("Last Weapon"), "weaplast"}, {0, 0}, {0, 0}, - {_(""), "Actions"}, - {_("Reload"), "reload"}, - {_("Reload Next"), "reloadnext"}, - {_("Change Class"), "changeclass"}, - {_("Change Team"), "changeteam"}, - {_("Drop Flag"), "dropitems"}, - {_("Discard Backpack"), "discard"}, - {_("Discard Ammo"), "dropammo"}, - {_("Call For Help"), "saveme"}, - {_("Inventory"), "inv"}, - {_("Flag Status"), "flaginfo"}, + {_(""), "Advanced Weaponry"}, {0, 0}, + {_("Fire Primary"), "+fire1"}, + {_("Fire Secondary"), "+fire2"}, + {_("Fire Tertiary"), "+fire3"}, + {_("Fire Melee"), "+fire4"}, + {_("Quick Primary"), "+slot1"}, + {_("Quick Secondary"), "+slot2"}, + {_("Quick Tertiary"), "+slot3"}, + {_("Quick Melee"), "+slot4"}, + {_("Prime Grenade 1"), "primeone"}, + {_("Prime Grenade 2"), "primetwo"}, + {_("Throw Grenade"), "throwgren"}, + /* {_("Inventory"), "inv"}, */ + /* {_("Flag Status"), "flaginfo"}, */ {0, 0}, {0, 0}, {_(""), "Misc"}, From ff345578eb59ae0cdfdccdf2b335f7077856f792 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 14 Jul 2020 11:25:25 +1200 Subject: [PATCH 1002/2474] #420 - ignore sbflaginfo when using csqc --- ssqc/status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index f6d9dda2..2dab3b1f 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1051,7 +1051,7 @@ void (entity pl) RefreshStatusBar = { // class tip - if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2) { + if ((((time - 6) < pl.spawn_time) || ((time - 6) < pl.tip_time)) && sbflaginfostate < 2 && !csqcactive) { ct = CF_GetRandomClassTip(pl.playerclass); } else { pl.display_tip = 0; From 763f5e43846ca5303b1c1ab1be3da9032caf44e4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 Jul 2020 01:37:32 +1000 Subject: [PATCH 1003/2474] Remove Updates+Packages menu for now --- menu/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/main.qc b/menu/main.qc index d7959c8e..f333453c 100644 --- a/menu/main.qc +++ b/menu/main.qc @@ -88,7 +88,7 @@ nonstatic void(mitem_desktop desktop) M_Main = //if (assumefalsecheckcommand("cef")) {menuitemtext_cladd16(m, _("Browser"), "m_pop;cef google.com", y); y += 16;} //if (assumefalsecheckcommand("xmpp")) {menuitemtext_cladd16(m, _("Social"), "m_pop;xmpp", y); y += 16;} //if (assumefalsecheckcommand("irc")) {menuitemtext_cladd16(m, _("IRC"), "m_pop;irc /info", y); y += 16;} - if (assumefalsecheckcommand("menu_download")) {menuitemtext_cladd16(m, _("Updates+Packages"), "m_pop;menu_download", y); y += 16;} + //if (assumefalsecheckcommand("menu_download")) {menuitemtext_cladd16(m, _("Updates+Packages"), "m_pop;menu_download", y); y += 16;} if (assumefalsecheckcommand("qi")) {menuitemtext_cladd16(m, _("Quake Injector"), "m_pop;qi", y); y += 16;} {menuitemtext_cladd16(m, _("Options"), "m_pop;m_options", y); y += 16;} {menuitemtext_cladd16(m, _("Quit"), "m_pop;m_quit", y); y += 16;} From ec16e8d890631bacb98ec09076cfc36d50dd2800 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 Jul 2020 02:41:51 +1000 Subject: [PATCH 1004/2474] Hide not ready centreprint on FTE --- ssqc/clan.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 23646339..c90810d0 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -921,7 +921,10 @@ void () CenterPrint_Players_NotReady = { te = find(world, classname, "player"); while (te) { - CenterPrint(te, players_not_ready); + if(!infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + CenterPrint(te, players_not_ready); + } + te = find(te, classname, "player"); } } From 499a735ae880bb7b0bbb46f1e8679d71f122a538 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 Jul 2020 03:01:45 +1000 Subject: [PATCH 1005/2474] Hide ready status on class select --- csqc/status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/status.qc b/csqc/status.qc index ac2326c5..8455eded 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -335,7 +335,7 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { if(showingscores || !panel.Display) { return; } - if(prematch && team_no && !SBAR.CountdownStarted && !is_spectator) { + if(prematch && team_no && player_class && !SBAR.CountdownStarted && !is_spectator) { if(SBAR.Ready) { message = "Ready"; textcolour = MENU_TEXT_GREEN; From 10a8c8f8d8c0d910aba6f838e7c00f5280c2b1e7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 Jul 2020 03:27:13 +1000 Subject: [PATCH 1006/2474] Tell played the key to press to ready up --- csqc/status.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csqc/status.qc b/csqc/status.qc index ac2326c5..0737bcfc 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -340,7 +340,8 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { message = "Ready"; textcolour = MENU_TEXT_GREEN; } else { - message = "NOT Ready"; + tokenize(findkeysforcommand("ready")); + message = strcat("Press ", keynumtostring(stof(argv(0))), " to ready up"); textcolour = MENU_TEXT_WARNING; } } From 4bd6dcbe9676505a40a1d12dd3bae713a471de75 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 Jul 2020 20:21:37 +1200 Subject: [PATCH 1007/2474] fix inv for concussion grens --- ssqc/tfort.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 19e77556..a813d43b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -426,6 +426,12 @@ string GetGrenName(float type) case GR_TYPE_FLASH: s = "flash grenade"; break; + case GR_TYPE_CONCUSSION: + s = "concussion grenade"; + break; + case GR_TYPE_NONE: + s = "no grenade"; + break; } return s; From afc3e3e4fe7533f848a85543e2cb4f8a2ac7839b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 Jul 2020 21:08:29 +1200 Subject: [PATCH 1008/2474] option for solid nailgrens --- README.md | 1 + ssqc/client.qc | 5 +++++ ssqc/qw.qc | 1 + ssqc/tsoldier.qc | 3 +++ 4 files changed, 10 insertions(+) diff --git a/README.md b/README.md index d953a5a5..f7dd1466 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * scout has "new" flash grenades - localinfo fo_flash on (default off) * ability to set client side min and max flash amounts - localinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) * localinfo quad_roles 1 enables the use of quad roles. Only works in quad mode: Blue gets the "attack" role first and Red gets the "defence" role. diff --git a/ssqc/client.qc b/ssqc/client.qc index f4ca82b8..8a30bffa 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -681,6 +681,9 @@ void () DecodeLevelParms = { LoadRole(&Role_Defence); InitTeamRoles(); + // whether the nailgren can be jumped off of + solid_nailgren = CF_GetSetting("sng", "solid_nailgren", "1"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; @@ -750,6 +753,7 @@ void () DecodeLevelParms = { Role_None.gren2_limits[9] = PC_ENGINEER_GRENADE_MAX_2; solid_detpack = FALSE; walls_block_emp = FALSE; + solid_nailgren = FALSE; } st = infokey(world, "faithful"); @@ -820,6 +824,7 @@ void () DecodeLevelParms = { Role_None.gren2_limits[9] = 4; solid_detpack = TRUE; walls_block_emp = FALSE; + solid_nailgren = TRUE; } } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index c9c2d039..9de502e4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -581,6 +581,7 @@ float walls_block_emp; float new_emp; float cb_keepteams; float fo_flashtime; +float solid_nailgren; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index e9ed2599..6bbb56e7 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -37,6 +37,9 @@ void () NailGrenadeExplode = { self.no_active_nail_grens = self.owner.no_active_nail_grens; self.movetype = MOVETYPE_FLY; setorigin(self, self.origin + '0 0 32'); + if(solid_nailgren) { + setsize(self, '-1 -1 -1', '1 1 1'); + } self.avelocity = '0 500 0'; self.nextthink = time + 0.7; if (nailgren_type == NGR_TYPE_LASER) From ce24f442c45a7f6495dffcc241b3d64ce166247d Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 Jul 2020 21:12:57 +1200 Subject: [PATCH 1009/2474] fix id angles --- ssqc/actions.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index e8aca7e8..3cf44226 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -172,7 +172,8 @@ void (entity pe_player) FO_SpecTrackPoint = { makevectors(pe_player.v_angle); v_source = pe_player.origin + v_forward * 10; - traceline(pe_player.origin, pe_player.origin + v_forward * 2048, 0, pe_player); + v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; + traceline(v_source, v_source + v_forward * 2048, 0, pe_player); if (trace_ent != world) { if(trace_ent.classname == "player") { @@ -183,7 +184,8 @@ void (entity pe_player) FO_SpecTrackPoint = { void (entity pe_player, float f_type) CF_Identify = { local vector v_source; - + + makevectors(pe_player.v_angle); v_source = pe_player.origin + v_forward * 10; v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; From ff03e3d5f339d8929c6fc07f47f2a4134ddf4157 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 Jul 2020 21:16:22 +1200 Subject: [PATCH 1010/2474] fix tracktarget case statement --- ssqc/commands.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 623225da..4480dbcc 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -767,6 +767,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "tracktarget": processedCmd = TRUE; FO_SpecTrackPoint(self); + break; case "showroles": processedCmd = TRUE; PrintRoleStatus(self); From 611114e87b49616af69b3b549b17094d45131d70 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 16 Jul 2020 19:18:53 +1000 Subject: [PATCH 1011/2474] Deal with player not having ready bound --- csqc/status.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 0737bcfc..06fa3e75 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -340,8 +340,11 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { message = "Ready"; textcolour = MENU_TEXT_GREEN; } else { - tokenize(findkeysforcommand("ready")); - message = strcat("Press ", keynumtostring(stof(argv(0))), " to ready up"); + if(tokenize(findkeysforcommand("ready"))) { + message = strcat("Press ", keynumtostring(stof(argv(0))), " to ready up"); + } else { + message = "Type 'ready' in the console to ready up"; + } textcolour = MENU_TEXT_WARNING; } } From d6fe949cc346bf0d124f18ac483c401d8147ddf0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 16 Jul 2020 21:20:49 +1000 Subject: [PATCH 1012/2474] Only tell player to press button to ready if it's bound --- csqc/status.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 06fa3e75..ec3af553 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -340,8 +340,10 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { message = "Ready"; textcolour = MENU_TEXT_GREEN; } else { - if(tokenize(findkeysforcommand("ready"))) { - message = strcat("Press ", keynumtostring(stof(argv(0))), " to ready up"); + tokenize(findkeysforcommand("ready")); + string keynum = argv(0); + if(keynum != "-1") { + message = strcat("Press ", keynumtostring(stof(keynum)), " to ready up"); } else { message = "Type 'ready' in the console to ready up"; } From 67de5722c60d824c3892232a45e2a6cdae0b8efa Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 16 Jul 2020 23:41:01 +1200 Subject: [PATCH 1013/2474] update spectator id and autoid --- csqc/events.qc | 4 ++- share/commondefs.qc | 1 + ssqc/actions.qc | 62 +++++++++++++++++++++++++++++++++++++++++---- ssqc/commands.qc | 4 +++ ssqc/qw.qc | 1 + ssqc/spect.qc | 3 +++ ssqc/status.qc | 29 +++++++++++++++------ 7 files changed, 90 insertions(+), 14 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index f4363477..02a738aa 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -94,6 +94,9 @@ void() CSQC_Parse_Event = { case MSG_SBAR: ParseSBAR(); break; + case MSG_ID: + SBAR.Identify = readstring(); + break; case MSG_GRENPRIMED: float grentype = readfloat(); float timertype = cvar(FOCMD_GRENTIMER); @@ -268,7 +271,6 @@ void ParseSBAR() SBAR.ClipSize = readstring(); SBAR.FragStreak = readfloat(); SBAR.Caps = readfloat(); - SBAR.Identify = readstring(); SBAR.PlayerClass = readfloat(); if (SBAR.PlayerClass) diff --git a/share/commondefs.qc b/share/commondefs.qc index 034fad1c..1a6a4a44 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -25,6 +25,7 @@ #define MSG_MOTD 13 #define MSG_PREMATCH 14 #define MSG_GRENTHROWN 15 +#define MSG_ID 16 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 3cf44226..b3665f09 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -168,21 +168,73 @@ void (entity pe_player) FO_SpecTrackPoint = { if(pe_player.classname != "observer") { return; } - local vector v_source; makevectors(pe_player.v_angle); - v_source = pe_player.origin + v_forward * 10; - v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; - traceline(v_source, v_source + v_forward * 2048, 0, pe_player); + traceline(pe_player.origin, pe_player.origin + v_forward * 4096, 0, pe_player); + + if (trace_ent != world) { + if(trace_ent.classname == "player") { + stuffcmd(pe_player, strcat("track \"", trace_ent.netname, "\"\n")); + } + } +} + +void (entity pe_player) FO_Spectator_Identify = { + if(pe_player.classname != "observer") { + return; + } + + makevectors(pe_player.v_angle); + traceline(pe_player.origin, pe_player.origin + v_forward * 4096, MOVE_EVERYTHING, pe_player); if (trace_ent != world) { + local string s_id_string = ""; if(trace_ent.classname == "player") { - stuffcmd(pe_player, strcat("track ", trace_ent.netname, "\n")); + s_id_string = strcat(trace_ent.netname, "\n", TeamFortress_TeamGetColorString(trace_ent.team_no), " ", TeamFortress_GetClassName(trace_ent.playerclass), "\n"); + if(trace_ent.playerclass == PC_SPY) { + if (trace_ent.undercover_team || trace_ent.undercover_skin) { + s_id_string = strcat(s_id_string, "\sDisguised as: \s "); + if (trace_ent.undercover_team != 0) + s_id_string = strcat(s_id_string, TeamFortress_TeamGetColorString(trace_ent.undercover_team)); + if (trace_ent.undercover_skin != 0) + s_id_string = strcat(s_id_string, " ", TeamFortress_GetClassName(trace_ent.undercover_skin)); + s_id_string = strcat(s_id_string, "\n"); + } + } + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "/", ftos(trace_ent.max_health)); + s_id_string = strcat(s_id_string, " \sA:\s ", ftos(trace_ent.armorvalue), "/", ftos(trace_ent.maxarmor), "\n"); + } else if(trace_ent.classname == "building_sentrygun") { + s_id_string = strcat(trace_ent.real_owner.netname, "'s Sentry Gun (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); + s_id_string = strcat(s_id_string, "\sLevel:\s ", ftos(trace_ent.weapon), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "/", ftos(trace_ent.max_health), "\n"); + } else if(trace_ent.classname == "building_sentrygun_base") { + s_id_string = strcat(trace_ent.real_owner.netname, "'s Sentry Gun (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); + s_id_string = strcat(s_id_string, "\sLevel:\s ", ftos(trace_ent.oldenemy.weapon), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.oldenemy.health), "/", ftos(trace_ent.oldenemy.max_health), "\n"); + } else if(trace_ent.classname == "building_dispenser") { + s_id_string = strcat(trace_ent.real_owner.netname, "'s Dispenser (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "/", ftos(trace_ent.max_health), "\n"); + } else if(trace_ent.classname == "detpack") { + s_id_string = strcat(trace_ent.owner.netname, "'s Detpack (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); + s_id_string = strcat(s_id_string, "\sTime Left:\s ", ftos(trace_ent.detpack_left), " seconds\n"); + } + + // refresh status bar + pe_player.ident_time = time + 0.5; + if(pe_player.ident_string != s_id_string) { + pe_player.ident_string = s_id_string; + //Status_Refresh(pe_player); + UpdateClientIDString(pe_player); } } } void (entity pe_player, float f_type) CF_Identify = { + if(pe_player.classname == "observer") { + FO_Spectator_Identify(pe_player); + return; + } + local vector v_source; makevectors(pe_player.v_angle); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 4480dbcc..008de6d5 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -768,6 +768,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; FO_SpecTrackPoint(self); break; + case "id": + processedCmd = TRUE; + CF_Identify(self, 0); + break; case "showroles": processedCmd = TRUE; PrintRoleStatus(self); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9de502e4..0f961a64 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -89,6 +89,7 @@ typedef void (float n) f_void_float; // Identify variables .string ident_string; // Status bar string for identify +.string last_ident_string; // Last Status bar string for identify .float ident_time; // The time when last identify found a player .float autoid_type; // 0 = ignore noone, 1 = ignore teammates, 2 = ignore enemies .float autoid_time; // Time when autoid settings were last checked diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 14b2946b..e125602f 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -53,9 +53,12 @@ void () SpectatorConnect = { UpdateClientMOTD(self); UpdateClientPrematch(self, !cb_prematch); } + + TeamFortress_StartTimers(); }; void () SpectatorDisconnect = { + RemoveAutoIdTimer(); }; void () SpectatorImpulseCommand = { diff --git a/ssqc/status.qc b/ssqc/status.qc index f6d9dda2..d3039302 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -803,6 +803,23 @@ void UpdateClientGrenadeThrown(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientIDString(entity pl) { + // only send updates + //if(time < pl.ident_time && pl.ident_string == pl.last_ident_string) + // return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_ID); + // identify + if (pl.ident_string && time < pl.ident_time) { + WriteString(MSG_MULTICAST, pl.ident_string); + } else { + WriteString(MSG_MULTICAST, ""); + } + multicast('0 0 0', MULTICAST_ONE_NOSPECS); + pl.last_ident_string = pl.ident_string; +} + void UpdateClientStatusBar(entity pl) { // if we ever change to fte only, this could be changed to stats @@ -816,12 +833,6 @@ void UpdateClientStatusBar(entity pl) WriteString(MSG_MULTICAST, clipMsg); WriteFloat(MSG_MULTICAST, pl.fragstreak); WriteFloat(MSG_MULTICAST, pl.caps); - // identify - if (pl.ident_string && time < pl.ident_time) { - WriteString(MSG_MULTICAST, pl.ident_string); - } else { - WriteString(MSG_MULTICAST, ""); - } WriteFloat(MSG_MULTICAST, pl.playerclass); // just in case we get a packet from "last life" after changing playerclass if (pl.playerclass) @@ -1034,7 +1045,8 @@ void (entity pl) RefreshStatusBar = { } tg = find(tg, classname, "info_tfgoal"); } - + UpdateClientIDString(pl); + return; } @@ -1066,7 +1078,8 @@ void (entity pl) RefreshStatusBar = { { //pl.StatusRefreshTime = time + 1; UpdateClientStatusBar(pl); - + UpdateClientIDString(pl); + // flag info if (tfdet) { From 5e6ca0b0b0ff79ae374da1ea1902b1234fc70fc0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 17 Jul 2020 01:07:37 +1000 Subject: [PATCH 1014/2474] no csqc gren timer during prematch --- csqc/main.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 0d215c3d..cdbf5683 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -186,7 +186,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren1": - if(getstatf(STAT_HEALTH) > 0) { + if(getstatf(STAT_HEALTH) > 0 && round_active) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); @@ -198,7 +198,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren2": - if(getstatf(STAT_HEALTH) > 0) { + if(getstatf(STAT_HEALTH) > 0 && round_active) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); From 72fa9d28d40ac1adce1fb0f7fb33bf20c542cb06 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 17 Jul 2020 01:20:27 +1000 Subject: [PATCH 1015/2474] Fix couldn't load skin skins/skin2.pcx --- menu/options.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/menu/options.qc b/menu/options.qc index dda7fd38..6f0f9fcc 100644 --- a/menu/options.qc +++ b/menu/options.qc @@ -57,8 +57,6 @@ nonstatic void(mitem_desktop desktop) M_Options = m.add(spawn ( mitem_spinnymodel, item_text: "progs/tf_stan.mdl", - customskin:"skin2", - trueskin:"skin2", dontrotate:0, startangle:'0 192 0', firstframe:0, From 2b044de6123eca6ea9a02e5a7cebdf2a61d400f5 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 17 Jul 2020 11:35:36 +1200 Subject: [PATCH 1016/2474] toggle build sentry/disp using cmd build commands --- ssqc/commands.qc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 623225da..b0413075 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -618,10 +618,18 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } if(arg2 == "sentry") { + if(self.is_building) { + TeamFortress_EngineerBuildStop(); + break; + } Menu_Engineer_Input(1); break; } if(arg2 == "dispenser") { + if(self.is_building) { + TeamFortress_EngineerBuildStop(); + break; + } Menu_Engineer_Input(2); break; } From 804d718f24cbeb3639314f870e8439a3a8acbae5 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 17 Jul 2020 21:26:49 +1200 Subject: [PATCH 1017/2474] fix spec id for tracking and don't crash ezquake --- ssqc/actions.qc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index b3665f09..dbdcbe9e 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -185,7 +185,8 @@ void (entity pe_player) FO_Spectator_Identify = { } makevectors(pe_player.v_angle); - traceline(pe_player.origin, pe_player.origin + v_forward * 4096, MOVE_EVERYTHING, pe_player); + //start just forward of the player in case you're speccing someone + traceline(pe_player.origin + v_forward * 32, pe_player.origin + v_forward * 4096, MOVE_EVERYTHING, pe_player); if (trace_ent != world) { local string s_id_string = ""; @@ -223,8 +224,11 @@ void (entity pe_player) FO_Spectator_Identify = { pe_player.ident_time = time + 0.5; if(pe_player.ident_string != s_id_string) { pe_player.ident_string = s_id_string; - //Status_Refresh(pe_player); - UpdateClientIDString(pe_player); + if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { + UpdateClientIDString(pe_player); + } else { + Status_Refresh(pe_player); + } } } } From 00882720eee43eed5e867a5a737223f17736601f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 17 Jul 2020 21:53:46 +1200 Subject: [PATCH 1018/2474] only allow csqc spec id --- ssqc/actions.qc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index dbdcbe9e..e087d4f5 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -180,7 +180,8 @@ void (entity pe_player) FO_SpecTrackPoint = { } void (entity pe_player) FO_Spectator_Identify = { - if(pe_player.classname != "observer") { + //ezquake draws player ids over their heads + if(pe_player.classname != "observer" || !infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { return; } @@ -224,11 +225,11 @@ void (entity pe_player) FO_Spectator_Identify = { pe_player.ident_time = time + 0.5; if(pe_player.ident_string != s_id_string) { pe_player.ident_string = s_id_string; - if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { + //if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { UpdateClientIDString(pe_player); - } else { - Status_Refresh(pe_player); - } + //} else { + // Status_Refresh(pe_player); + //} } } } From 31d20ee49aaafd85aa2935a12cb855910e01f711 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 18 Jul 2020 20:16:14 +1200 Subject: [PATCH 1019/2474] cd /home/me/games/fortresstwo/build --- ssqc/actions.qc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index e087d4f5..3fad7de8 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -187,12 +187,13 @@ void (entity pe_player) FO_Spectator_Identify = { makevectors(pe_player.v_angle); //start just forward of the player in case you're speccing someone - traceline(pe_player.origin + v_forward * 32, pe_player.origin + v_forward * 4096, MOVE_EVERYTHING, pe_player); + traceline(pe_player.origin + v_forward * 96, pe_player.origin + v_forward * 4096, MOVE_EVERYTHING, pe_player); if (trace_ent != world) { local string s_id_string = ""; if(trace_ent.classname == "player") { - s_id_string = strcat(trace_ent.netname, "\n", TeamFortress_TeamGetColorString(trace_ent.team_no), " ", TeamFortress_GetClassName(trace_ent.playerclass), "\n"); + //s_id_string = strcat(trace_ent.netname, "\n", TeamFortress_TeamGetColorString(trace_ent.team_no), " ", TeamFortress_GetClassName(trace_ent.playerclass), "\n"); + s_id_string = strcat(trace_ent.netname, "\n"); if(trace_ent.playerclass == PC_SPY) { if (trace_ent.undercover_team || trace_ent.undercover_skin) { s_id_string = strcat(s_id_string, "\sDisguised as: \s "); @@ -203,19 +204,19 @@ void (entity pe_player) FO_Spectator_Identify = { s_id_string = strcat(s_id_string, "\n"); } } - s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "/", ftos(trace_ent.max_health)); - s_id_string = strcat(s_id_string, " \sA:\s ", ftos(trace_ent.armorvalue), "/", ftos(trace_ent.maxarmor), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health)); + s_id_string = strcat(s_id_string, " \sA:\s ", ftos(trace_ent.armorvalue), "\n"); } else if(trace_ent.classname == "building_sentrygun") { s_id_string = strcat(trace_ent.real_owner.netname, "'s Sentry Gun (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); s_id_string = strcat(s_id_string, "\sLevel:\s ", ftos(trace_ent.weapon), "\n"); - s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "/", ftos(trace_ent.max_health), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "\n"); } else if(trace_ent.classname == "building_sentrygun_base") { s_id_string = strcat(trace_ent.real_owner.netname, "'s Sentry Gun (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); s_id_string = strcat(s_id_string, "\sLevel:\s ", ftos(trace_ent.oldenemy.weapon), "\n"); - s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.oldenemy.health), "/", ftos(trace_ent.oldenemy.max_health), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.oldenemy.health), "\n"); } else if(trace_ent.classname == "building_dispenser") { s_id_string = strcat(trace_ent.real_owner.netname, "'s Dispenser (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); - s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "/", ftos(trace_ent.max_health), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "\n"); } else if(trace_ent.classname == "detpack") { s_id_string = strcat(trace_ent.owner.netname, "'s Detpack (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); s_id_string = strcat(s_id_string, "\sTime Left:\s ", ftos(trace_ent.detpack_left), " seconds\n"); From f0e36294b7f855cea7a325976f44b9d747fd6196 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Jul 2020 19:01:21 +1000 Subject: [PATCH 1020/2474] Move default hud elements around --- csqc/hud.qc | 13 +++++++++---- csqc/status.qc | 33 ++++++++++++--------------------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 12579177..2f81a099 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -73,11 +73,16 @@ void FO_Hud_Editor_LoadDefaultSettings() //pnl.Name = name; } */ + //Default menus, id, ready and MOTD to centre of the screen - Hud_Panels[HUD_PANEL_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), height / 2 - Hud_Panels[HUD_PANEL_MENU].FillSize.y / 2]; - Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height / 2]; - Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 130]; - Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 200]; + Hud_Panels[HUD_PANEL_GAME_MODE].Position = [width - Hud_Panels[HUD_PANEL_GAME_MODE].FillSize.x, 30]; + Hud_Panels[HUD_PANEL_GAME_MODE].NodeInsertLoc = FO_HUD_INSERT_AFTER; + Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 30]; + Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 30]; + Hud_Panels[HUD_PANEL_MENU_HINT].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), 80]; + Hud_Panels[HUD_PANEL_MENU_HINT].NodeInsertLoc = FO_HUD_INSERT_MIDDLE; + Hud_Panels[HUD_PANEL_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), 120]; + Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height - 100]; Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) + 16, height - 50]; Hud_Panels[HUD_PANEL_CLIPSIZE].Scale = 0.75; Hud_Panels[HUD_PANEL_GREN1].Position = [(width / 2) - 16 - (Hud_Panels[HUD_PANEL_GREN1].FillSize.x * 2), height - 50]; diff --git a/csqc/status.qc b/csqc/status.qc index a3c3155c..d475e288 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -204,7 +204,7 @@ void(string panelid, float display, string text, string icon) drawMOTDPanel = { 1, 0 ); - motd = "www.github.com/FortressOne"; + motd = "www.fortressone.org"; drawstring( position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*3], motd, @@ -213,16 +213,7 @@ void(string panelid, float display, string text, string icon) drawMOTDPanel = { 1, 0 ); - motd = "FortressOne.org"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*4], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - lines = 3; + lines = 2; } else { lines = tokenizebyseparator(SBAR.MOTD, "\n"); for (float i = 0; i <= lines; i++) { @@ -272,28 +263,28 @@ void(string panelid, float display, string text, string icon) drawGameModePanel return; } if(SBAR.GameMode & GAMEMODE_VOTE) { - message = "^5Vote Mode^7"; + message = "Vote Mode"; } else { if(SBAR.GameMode & GAMEMODE_DUEL) { - message = "^4Duel Mode^7"; + message = "Duel Mode"; } else if(SBAR.GameMode & GAMEMODE_QUAD) { - message = "^3Quad Mode^7"; + message = "Quad Mode"; } else if(SBAR.GameMode & GAMEMODE_CLAN) { - message = "^1Clan Battle^7"; + message = "Clan Battle"; } if(prematch && !round_over) { - message = strcat(message, " (prematch)"); + message = strcat(message, ": prematch"); } else { //Quad mode only if(SBAR.GameMode & 2) { if(round_over) { if(prematch) { - message = strcat(message, " (Match over)"); + message = strcat(message, ": match over"); } else { - message = strcat(message, " (Intermission)"); + message = strcat(message, ": intermission"); } } else if(quad_round > 0) { - message = strcat(message, " Round ", ftos(quad_rounds_total + 1 - quad_round), "/", ftos(quad_rounds_total)); + message = strcat(message, ": round ", ftos(quad_rounds_total + 1 - quad_round), "/", ftos(quad_rounds_total)); } } } @@ -375,9 +366,9 @@ var FO_Hud_Panel Hud_Panels[] = { {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 230','150 260',1,0,1,0, drawFlagInfo, {return "";}}, {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'100 110','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, - {"menupanel","Menu",'10 110','200 200',1,0,1,0, drawSimplePanel, {return "";}}, + {"menupanel","Menu",'10 110','300 200',1,0,1,0, drawSimplePanel, {return "";}}, {"motdpanel",FO_HUD_MOTD_NAME,'150 100','100 24',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, - {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'100 300','100 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, + {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'100 300','300 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, }; From a70657dd6dc1aecc6f2e2e429715365d6a86587c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Jul 2020 19:36:46 +1000 Subject: [PATCH 1021/2474] Remove the Graphical Presets menu for now --- menu/options.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/menu/options.qc b/menu/options.qc index dda7fd38..6ff73f98 100644 --- a/menu/options.qc +++ b/menu/options.qc @@ -34,8 +34,8 @@ nonstatic void(mitem_desktop desktop) M_Options = //and show the options. - if (assumefalsecheckcommand("fps_preset")) - {fr.add(spawn(mitem_text, item_text:"Graphical Presets", item_command:"m_pop;m_preset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} + /* if (assumefalsecheckcommand("fps_preset")) */ + /* {fr.add(spawn(mitem_text, item_text:"Graphical Presets", item_command:"m_pop;m_preset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} */ fr.add(spawn(mitem_text, item_text:"Game Configs", item_command:"m_pop;m_configs", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; fr.add(spawn(mitem_text, item_text:"Basic Setup", item_command:"m_pop;m_basicopts", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; fr.add(spawn(mitem_text, item_text:"Audio", item_command:"m_pop;m_audio", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; From bd4c42885f4967b061ba843b7a092166db423fcf Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 21 Jul 2020 20:36:02 +1000 Subject: [PATCH 1022/2474] Fix no csqc grens in not quadmode --- csqc/main.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index cdbf5683..c44a709e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -162,7 +162,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Special(TRUE); break; case "primeone": - if(getstatf(STAT_HEALTH) > 0) { + if(getstatf(STAT_HEALTH) > 0 && !prematch) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); @@ -174,7 +174,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "primetwo": - if(getstatf(STAT_HEALTH) > 0) { + if(getstatf(STAT_HEALTH) > 0 && !prematch) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); @@ -186,7 +186,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren1": - if(getstatf(STAT_HEALTH) > 0 && round_active) { + if(getstatf(STAT_HEALTH) > 0 && !prematch) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); @@ -198,7 +198,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren2": - if(getstatf(STAT_HEALTH) > 0 && round_active) { + if(getstatf(STAT_HEALTH) > 0 && !prematch) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); From 1f6e3a4f904c469395d55f12734523c042f73c05 Mon Sep 17 00:00:00 2001 From: lordee Date: Thu, 23 Jul 2020 23:30:45 +1000 Subject: [PATCH 1023/2474] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d953a5a5..ffbed466 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server New features ------ * scout has "new" flash grenades - localinfo fo_flash on (default off) -* ability to set client side min and max flash amounts - localinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) +* ability to set client side min and max flash amounts - setinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) * localinfo quad_roles 1 enables the use of quad roles. Only works in quad mode: Blue gets the "attack" role first and Red gets the "defence" role. These roles can be configured by adding the "att_" and "def_" prefix to localinfo settings. Only detpipe_limit, respawn_time, gren limits and class limits are currently supported. Use `cmd showroles` to see the current configuration. From 3d57cd3d40570ff3d4c41e32ff9b23ccf98e6bae Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 25 Jul 2020 01:51:48 +1000 Subject: [PATCH 1024/2474] only play grentimer in pub or while round_active --- csqc/main.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index c44a709e..32cddafa 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -162,7 +162,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Special(TRUE); break; case "primeone": - if(getstatf(STAT_HEALTH) > 0 && !prematch) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); @@ -174,7 +174,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "primetwo": - if(getstatf(STAT_HEALTH) > 0 && !prematch) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); @@ -186,7 +186,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren1": - if(getstatf(STAT_HEALTH) > 0 && !prematch) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); @@ -198,7 +198,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren2": - if(getstatf(STAT_HEALTH) > 0 && !prematch) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); From 35a9cbedfccf2056e6282767b1fa6fa6002321e4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 26 Jul 2020 08:58:53 +1200 Subject: [PATCH 1025/2474] handle +showteamscores --- csqc/main.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index 0d215c3d..7eeab4fe 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -210,9 +210,11 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "+showscores": + case "+showteamscores": showingscores = TRUE; break; case "-showscores": + case "-showteamscores": showingscores = FALSE; break; case "tracktarget": From 4e74c143e11fabc0f1a6d5ef3d635f9b49fcae63 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 26 Jul 2020 09:20:27 +1200 Subject: [PATCH 1026/2474] make 'special' in prematch toggle god mode --- ssqc/weapons.qc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 3bd63869..1e3521d1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3080,6 +3080,20 @@ void () PreMatchImpulses = { TeamFortress_DisplayDetectionItems(); } else if (self.impulse == TF_DISPLAYLOCATION) display_location(); + + if (self.impulse == TF_SPECIAL_SKILL) { + if(self.tfstate & TFSTATE_INVINCIBLE) { + self.items = self.items - (self.items & IT_INVULNERABILITY); + self.invincible_time = 0; + self.invincible_finished = 0; + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_INVINCIBLE); + } else { + self.items = self.items | IT_INVULNERABILITY; + self.invincible_time = 1; + self.tfstate = self.tfstate | TFSTATE_INVINCIBLE; + self.invincible_finished = time + 666; + } + } }; void () DeadImpulses = { From 902109ebfbdc3de80cddeb62f0985ea85bd3e43b Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 29 Jul 2020 10:49:34 +1000 Subject: [PATCH 1027/2474] halfway implemented --- csqc/csextradefs.qc | 43 ++++++- csqc/csprogs.src | 3 + csqc/hud.qc | 1 + csqc/main.qc | 54 +++++++++ csqc/menu.qc | 18 --- csqc/status.qc | 270 ++++++++++++++++++++++++++++++++++++++++++++ share/defs.h | 2 + ssqc/admin.qc | 2 - ssqc/client.qc | 2 + ssqc/commands.qc | 3 - ssqc/events.qc | 59 +++++++++- ssqc/qw.qc | 14 ++- ssqc/tfort.qc | 3 + ssqc/tforttm.qc | 1 + 14 files changed, 446 insertions(+), 29 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index bee87b2d..1fdbd08d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -23,6 +23,22 @@ vector MENU_TEXT_MEDIUM = '16 16 0'; vector MENU_TEXT_LARGE = '24 24 0'; float MENU_START_CONTENT = 32; +#define FO_MENU_FLAG_USE_MOUSE 1 +#define FO_MENU_FLAG_CENTER 2 +#define FO_MENU_FLAG_SHOW_SHORTCUTS 4 +#define FO_MENU_FLAG_SHOW_VALUES 8 +#define FO_MENU_FLAG_WARNING 16 +#define FO_MENU_FLAG_ALLOW_INTERMISSION 32 + +#define FO_MENU_STATE_HIDDEN 0 +#define FO_MENU_STATE_NORMAL 1 +#define FO_MENU_STATE_DISABLED 2 +#define FO_MENU_STATE_SPACER 3 + +#define FO_MENU_MAX_OPTIONS 20 + +#define FO_MENU_TRANSPARENCY 0.2 + #define MOTD_TIME 30 .float owned_by; @@ -275,6 +291,30 @@ typedef struct { FO_Hud_Grentimer FO_Hud_Grentimers[5]; +// scoreboard stuff +typedef struct { + float ping; + float pl; + string classtext; + string name; + float team_no; + float score; + float caps; + float touches; + float kills; + float teamkills; + float deaths; + float afflicted; + float teamafflicted; + float damagegiven; + float damagetaken; +} FO_ScoreBoardLine; + +// fte maxclients is 255, right? +#define FO_SCOREBOARDLINES_LENGTH 32 + +string FO_ScoreBoardColumns[14]; + enum { HUD_PANEL_HUDOPTIONS, HUD_PANEL_CLIPSIZE, @@ -290,7 +330,8 @@ enum { HUD_PANEL_MOTD, HUD_PANEL_MENU_HINT, HUD_PANEL_GAME_MODE, - HUD_PANEL_READY + HUD_PANEL_READY, + HUD_PANEL_SHOWSCORES }; #define FOCMD_AUTOHOP "fo_autohop" diff --git a/csqc/csprogs.src b/csqc/csprogs.src index ff603ed3..8a760487 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,6 +1,9 @@ ../csprogs.dat csdefs.qc +//csqcdefs.qc +../share/fteextensions.qc csextradefs.qc + ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc diff --git a/csqc/hud.qc b/csqc/hud.qc index 2f81a099..4225886f 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -96,6 +96,7 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_FRAGSTREAK].Display = 0; Hud_Panels[HUD_PANEL_CAPS].Display = 0; Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; + Hud_Panels[HUD_PANEL_SHOWSCORES].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_SHOWSCORES].FillSize.x / 2), 30]; } void FO_Hud_Editor_List_Panels() = { diff --git a/csqc/main.qc b/csqc/main.qc index ca625719..1def1328 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -48,6 +48,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("+aux_jump"); registercommand("-aux_jump"); registercommand("tracktarget"); + registercommand("+fo_showscores"); + registercommand("-fo_showscores"); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -64,6 +66,40 @@ noref void() CSQC_WorldLoaded = { localcmd("menu_restart\n"); } +void(vector viewsize, float scoresshown) CSQC_DrawScores = { + print("showing scores\n"); + string panelid = "showscorespanel"; + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + + vector position = getPosition(id); + vector size = getFillSize(id); + vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + vector textcolour = MENU_TEXT_4; + local float padding = 4 * panel.Scale; + local float lines; + local float pos_aligned; + local string message; + if (fo_hud_editor) { + message = "Show Scores"; + if (hud_panel(panelid, position, size, 0.3, panel.Display)) { + // click event + } + } else { + if(!panel.Display) { + return; + } + message = "draw"; + if (hud_panel(panelid, position, size, 0.3, panel.Display)) { + // click event + } + } +}; + noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); @@ -209,11 +245,29 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("gren2_server"); } break; + case "+fo_showscores": + case "+showteamscores": case "+showscores": showingscores = TRUE; + float id = getHudPanel("showscorespanel"); + if(id < 0) { + return FALSE; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + panel.Display = TRUE; break; + case "-fo_showscores": + case "-showteamscores": case "-showscores": showingscores = FALSE; + float id = getHudPanel("showscorespanel"); + if(id < 0) { + return FALSE; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + panel.Display = FALSE; break; case "tracktarget": localcmd("cmd tracktarget\n"); diff --git a/csqc/menu.qc b/csqc/menu.qc index 73a4777e..e7baaa0c 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -1,19 +1,3 @@ -#define FO_MENU_FLAG_USE_MOUSE 1 -#define FO_MENU_FLAG_CENTER 2 -#define FO_MENU_FLAG_SHOW_SHORTCUTS 4 -#define FO_MENU_FLAG_SHOW_VALUES 8 -#define FO_MENU_FLAG_WARNING 16 -#define FO_MENU_FLAG_ALLOW_INTERMISSION 32 - -#define FO_MENU_STATE_HIDDEN 0 -#define FO_MENU_STATE_NORMAL 1 -#define FO_MENU_STATE_DISABLED 2 -#define FO_MENU_STATE_SPACER 3 - -#define FO_MENU_MAX_OPTIONS 20 - -#define FO_MENU_TRANSPARENCY 0.2 - void (float force) FO_Menu_Build; void (float force) FO_Menu_Admin_Main; void (float force) FO_Menu_Admin_Modes; @@ -703,7 +687,6 @@ vector fo_menu_draw(fo_menu * menu) = { position = menu.position; } - if(fo_hud_editor) return position; if(!menu.active || showingscores || (intermission && !(menu.flags & FO_MENU_FLAG_ALLOW_INTERMISSION))) { setcursormode(FALSE); @@ -738,7 +721,6 @@ vector fo_menu_draw(fo_menu * menu) = { if (sui_is_held(id)) { position = position + [Mouse.x, Mouse.y] - HudSettings.MousePos; } - sui_border_box(position, menusize, 1, bordercolour, FO_MENU_TRANSPARENCY, 0); sui_push_frame(position, menusize); diff --git a/csqc/status.qc b/csqc/status.qc index d475e288..0b5d07a7 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -301,6 +301,7 @@ void(string panelid, float display, string text, string icon) drawGameModePanel ); } } + void(string panelid, float display, string text, string icon) drawReadyPanel = { float id = getHudPanel(panelid); if(id < 0) { @@ -355,6 +356,274 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { } } +void (vector position, vector size, string val, vector textcolour, float alpha + , float flags, string colname, optional float padright = FALSE) drawShowScoresColumnVal = { + float valwidth, colwidth; + + colwidth = strlen(colname); + if (padright == TRUE) + { + val = strpad(colwidth, val); + } + else + { + val = strpad(colwidth * -1, val); + } + + sui_text(position, size, val, textcolour, 1, 0); +}; +void (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id + , float padding, vector columnColour) drawShowScoresTeamPanel = { + + vector textcolour = MENU_TEXT_1; + vector smalltext = MENU_TEXT_SMALL * panel.Scale; + vector yspacer = [0, 20]; + vector position = [0, 0]; + vector size = getFillSize(id); + + position += yspacer; + size_y = smalltext_y; + + sui_push_frame(position, size); + position = [0,0]; + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); + size = [size_x, smalltext_y]; + sui_fill(position, size, MENU_BG, 1, 0); + + for (float i = 0; i < FO_ScoreBoardColumns.length; i++) + { + string colname = FO_ScoreBoardColumns[i]; + sui_text(position, smalltext, colname, columnColour, .7, 0); + float txtlength = strlen(colname) * smalltext.x; + position_x += txtlength + padding; + } + + position = [0, smalltext.y]; + float lineCount = 1; + for (float i = 0; i < FO_SCOREBOARDLINES_LENGTH; i++) + { + string name = lines[i].name; + if (!name) + continue; + + lineCount++; + float trans = 1; + if (i % 2 == 0) + { + trans = .7; + } + else + { + trans = .3; + } + + sui_fill(position, size, columnColour, trans, 0); + + float col = 0, alpha = 1, flags = 0; + string val = ftos(lines[i].ping); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].pl); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + sui_text(position, smalltext, lines[i].classtext, textcolour, 1, 0); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].score); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + sui_text(position, smalltext, lines[i].name, textcolour, 1, 0); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].caps); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].touches); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].kills); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].teamkills); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].deaths); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].afflicted); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].teamafflicted); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].damagegiven); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + val = ftos(lines[i].damagetaken); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + + position_x = 0; + position_y += smalltext_y; + } + + position = [0,0]; + size_y = smalltext.y * lineCount; + sui_border_box(position, size, 1, MENU_BORDER, FO_MENU_TRANSPARENCY, 0); +}; + +void(string panelid, float display, string text, string icon) drawShowScoresPanel = { + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + + vector position = getPosition(id); + vector size = getFillSize(id); + vector mediumtext = MENU_TEXT_SMALL * panel.Scale * 2; + vector textcolour = MENU_TEXT_1; + float padding = 4 * panel.Scale; + + if (fo_hud_editor) { + if (hud_panel(panelid, position, size, 0.3, panel.Display)) { + // click event + } + } else { + if(!panel.Display) { + return; + } + // columns + FO_ScoreBoardColumns[0] = "ping"; + FO_ScoreBoardColumns[1] = "pl"; + FO_ScoreBoardColumns[2] = "class"; + FO_ScoreBoardColumns[3] = "score"; + FO_ScoreBoardColumns[4] = "name"; + FO_ScoreBoardColumns[5] = "caps"; + FO_ScoreBoardColumns[6] = "tchs"; + FO_ScoreBoardColumns[7] = "kils"; + FO_ScoreBoardColumns[8] = "tkil"; + FO_ScoreBoardColumns[9] = "dths"; + FO_ScoreBoardColumns[10] = "affl"; + FO_ScoreBoardColumns[11] = "taffl"; + FO_ScoreBoardColumns[12] = "dmgg"; + FO_ScoreBoardColumns[13] = "dmgt"; + + FO_ScoreBoardLine FO_ScoreBoardLines_Blue[FO_SCOREBOARDLINES_LENGTH]; + FO_ScoreBoardLine FO_ScoreBoardLines_Red[FO_SCOREBOARDLINES_LENGTH]; + FO_ScoreBoardLine FO_ScoreBoardLines_Yellow[FO_SCOREBOARDLINES_LENGTH]; + FO_ScoreBoardLine FO_ScoreBoardLines_Green[FO_SCOREBOARDLINES_LENGTH]; + FO_ScoreBoardLine FO_ScoreBoardLines_Specs[FO_SCOREBOARDLINES_LENGTH]; + + sui_push_frame(position, [size.x, 1]); + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); + position = [0,0]; + sui_text(position, mediumtext, "Scoreboard", textcolour, 1, 0); + + float bluecount = 0, redcount = 0, yellowcount = 0, greencount = 0, speccount = 0; + for (float i = 0; i < FO_SCOREBOARDLINES_LENGTH; i++) + { + FO_ScoreBoardLine sbl; + sbl.ping = getplayerkeyfloat(i, INFOKEY_P_PING); + sbl.pl = getplayerkeyfloat(i, INFOKEY_P_PACKETLOSS); + float class = getplayerkeyfloat(i, "playerclass"); + sbl.classtext = ClassToString(class); + sbl.name = getplayerkeyvalue(i, INFOKEY_P_NAME); + sbl.score = getplayerkeyfloat(i, INFOKEY_P_FRAGS); + sbl.caps = getplayerkeyfloat(i, "caps"); + sbl.touches = getplayerkeyfloat(i, "touches"); + sbl.kills = getplayerkeyfloat(i, "kills"); + sbl.teamkills = getplayerkeyfloat(i, "teamkills"); + sbl.deaths = getplayerkeyfloat(i, "deaths"); + sbl.afflicted = getplayerkeyfloat(i, "afflicted"); + sbl.teamafflicted = getplayerkeyfloat(i, "teamafflicted"); + sbl.damagegiven = getplayerkeyfloat(i, "damagegiven"); + sbl.damagetaken = getplayerkeyfloat(i, "damagetaken"); + sbl.team_no = getplayerkeyfloat(i, "team_no"); + + switch (sbl.team_no) + { + case 1: + FO_ScoreBoardLines_Blue[bluecount++] = sbl; + break; + case 2: + FO_ScoreBoardLines_Red[redcount++] = sbl; + break; + case 3: + FO_ScoreBoardLines_Yellow[yellowcount++] = sbl; + break; + case 4: + FO_ScoreBoardLines_Green[greencount++] = sbl; + break; + default: + float spec = getplayerkeyfloat(i, "*spectator"); + sbl.team_no = (spec == 1) ? 9 : 99; // TODO - use defines... + FO_ScoreBoardLines_Specs[speccount++] = sbl; + break; + } + } + + vector red = '0.7 0.4 0.3'; + vector blue = '0.3 0.4 0.7'; + vector yellow = '0.7 0.7 0.3'; + vector green = '0.4 0.7 0.3'; + vector spec = '0.1 0.1 0.1'; + float sbCount = 0; + if (FO_ScoreBoardLines_Blue[0].name) + { + drawShowScoresTeamPanel(FO_ScoreBoardLines_Blue, panel, id, padding, blue); + sbCount++; + } + + if (FO_ScoreBoardLines_Red[0].name) + { + drawShowScoresTeamPanel(FO_ScoreBoardLines_Red, panel, id, padding, red); + sbCount++; + } + + if (FO_ScoreBoardLines_Yellow[0].name) + { + drawShowScoresTeamPanel(FO_ScoreBoardLines_Yellow, panel, id, padding, yellow); + sbCount++; + } + + if (FO_ScoreBoardLines_Green[0].name) + { + drawShowScoresTeamPanel(FO_ScoreBoardLines_Green, panel, id, padding, green); + sbCount++; + } + + if (FO_ScoreBoardLines_Specs[0].name) + { + drawShowScoresTeamPanel(FO_ScoreBoardLines_Specs, panel, id, padding, spec); + sbCount++; + } + + for (float i = 0; i < sbCount; i++) + { + sui_pop_frame(); + } + + // FIXME - reset damage numbers etc on map change + // FIXME - class isn't set on first spawn + // FIXME - specs/observers aren't shown + // FIXME - afflictions aren't implemented + sui_pop_frame(); + } +} + var FO_Hud_Panel Hud_Panels[] = { {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, @@ -371,6 +640,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'100 300','300 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, + {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',2,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, }; float(string panelid) getHudPanel = { diff --git a/share/defs.h b/share/defs.h index 7ddb66af..8ac18323 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1355,6 +1355,8 @@ #define FO_HUD_MENU_HINT_NAME "Menu Hints" #define FO_HUD_GAME_MODE_NAME "Game Mode" #define FO_HUD_READY_NAME "Ready Status" +#define FO_HUD_SHOWSCORES_NAME "Show Scores" + #define ICON_CLIPSIZE "textures/wad/clipsize.png" #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" diff --git a/ssqc/admin.qc b/ssqc/admin.qc index e3030c26..25ec1fa0 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -118,8 +118,6 @@ void () Admin_DoBan = { void () Admin_ForceSpectator = { bprint4(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); - //stuffcmd(self.admin_use, "observe\n"); - //forceinfokey(self.admin_use, "*spectator", "1"); clientcommand(self.admin_use, "observe"); self.admin_mode = 0; self.admin_use = world; diff --git a/ssqc/client.qc b/ssqc/client.qc index 93c6010f..0f920243 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1787,6 +1787,8 @@ void () PutClientInServer = { self.takedamage = 2; + forceinfokey(self, "playerclass", ftos(self.playerclass)); + TeamFortress_PrintClassName(self, self.playerclass, self.tfstate & TFSTATE_RANDOMPC); TeamFortress_SetEquipment(); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 016da231..56083d87 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -316,7 +316,6 @@ float (string arg1, string arg2, string arg3) ParseCmds = { arg3f = TeamFortress_TeamGetColor(self.team_no) - 1; string st; st = ftos(arg3f); - //forceinfokey(self, "topcolor", st); stuffcmd(self, strcat("color ", st, "\n")); sprint(self, PRINT_HIGH, "Your color has been changed to your team color\n"); @@ -1051,8 +1050,6 @@ float (string arg1, string arg2, string arg3) ParseCmds = { while(ent) { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { bprint4(PRINT_HIGH, ent.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); - //stuffcmd(ent, "observe\n"); - //forceinfokey(ent, "*spectator", "1"); clientcommand(ent, "observe"); break; } diff --git a/ssqc/events.qc b/ssqc/events.qc index 4620f1e1..1bc46f0a 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -148,8 +148,38 @@ string (float code, float mode) GetWeaponName = { return "undefined"; } +void (entity attacker, entity target, string afflictionType) LogAffliction = { + if (attacker.classname == "player" && target.classname == "player") + { + if (attacker.team_no == target.team_no) + { + attacker.afflicted = attacker.afflicted + 1; + forceinfokey(attacker, "afflicted", ftos(attacker.afflicted)); + } + else + { + attacker.teamafflicted = attacker.teamafflicted + 1; + forceinfokey(attacker, "teamafflicted", ftos(attacker.teamafflicted)); + } + } +} void (entity attacker, entity target, entity inflictor, float damage) LogEventDamage = { + if (attacker) + { + if (attacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) + { + attacker.damagegiven = attacker.damagegiven + damage; + forceinfokey(attacker, "damagegiven", ftos(attacker.damagegiven)); + } + } + + if (target.classname == "player") + { + target.damagetaken = target.damagetaken + damage; + forceinfokey(target, "damagetaken", ftos(target.damagetaken)); + } + if (canlog == 0) return; @@ -230,12 +260,34 @@ void (entity attacker, entity target, entity inflictor, float damage) LogEventDa } void (entity attacker, entity target, entity inflictor) LogEventKill = { + if (attacker) + { + if (attacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) + { + if (attacker.team_no == target.team_no) + { + attacker.teamkills = attacker.teamkills + 1; + } + else + { + attacker.kills = attacker.kills + 1; + forceinfokey(attacker, "kills", ftos(attacker.kills)); + } + } + } + + if (target.classname == "player") + { + target.deaths = target.deaths + 1; + forceinfokey(target, "deaths", ftos(target.deaths)); + } + if (canlog == 0) return; if ((target.classname != "player") && (target.classname != "building_sentrygun")) return; - + local string killKind; local string attackername; local string targetname; @@ -268,7 +320,6 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { inflictorId = inflictor.grenadename; } - local string event; local string attackEvent; local string targetEvent; @@ -305,6 +356,8 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { void (entity player) LogEventGoal = { + player.caps = player.caps + 1; + forceinfokey(player, "caps", ftos(player.caps)); if (canlog == 0) return; local string event; @@ -319,6 +372,8 @@ void (entity player) LogEventGoal = { void (entity player) LogEventPickupGoal = { + player.touches = player.touches + 1; + forceinfokey(player, "touches", ftos(player.touches)); if (canlog == 0) return; local string event; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ba9c82aa..9107b686 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -672,7 +672,6 @@ string (string s, float width) strpadr = float captainmode; .float captain; - //Player ID float loginRequired; string loginUrl; @@ -680,7 +679,6 @@ string webpageUrl; .string login; .float login_in_progress; - //Logging fields float gametime; string gametimestamp; @@ -690,9 +688,19 @@ float canlog; .float classtime; .float goalrunningtime; +// csqc scoreboard fields +.float caps; +.float touches; +.float kills; +.float teamkills; +.float deaths; +.float afflicted; +.float teamafflicted; +.float damagegiven; +.float damagetaken; + // flash stuff float FO_FlashDimension; - // allow for default goal state .float default_group_no; \ No newline at end of file diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index a813d43b..a2569a52 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -223,7 +223,10 @@ void (float inp) TeamFortress_ChangeClass = { return; } TeamFortress_ExecClassScript(self); + + // FIXME - should this be using putclientinserver instead? self.playerclass = inp; + forceinfokey(self, "playerclass", ftos(self.playerclass)); //self.nextpc = 0; self.nextpc = inp; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 828d4e90..fe17191b 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -286,6 +286,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options } } + forceinfokey(pe, "team_no", ftos(tno)); return (1); }; From b3d1df8279193fe0bb9460395b1e2758f60d8233 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 29 Jul 2020 22:05:54 +1200 Subject: [PATCH 1028/2474] cmd sentry rotate possible fix; remove glow in prematch godmode --- ssqc/commands.qc | 9 +++++++++ ssqc/weapons.qc | 1 + 2 files changed, 10 insertions(+) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 008de6d5..1ef48e0f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -650,6 +650,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); break; } + if (!self.building.real_owner.has_sentry || self.building.real_owner != self + || self.classname != "player" || self.building == world) { + break; + } if (arg2 && arg3) { if(arg2 == "rotate") { farg3 = stof(arg3); @@ -764,6 +768,11 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; sprint(self, PRINT_HIGH, "Model: ", self.model, " index: ", ftos(self.modelindex), "\n"); break; + case "reportloc": + processedCmd = TRUE; + sprint(self, PRINT_HIGH, "Origin: ", vtos(self.origin), " OldOrigin: ", vtos(self.oldorigin)); + sprint(self, PRINT_HIGH, " view_ofs: ", vtos(self.view_ofs), "\n"); + break; case "tracktarget": processedCmd = TRUE; FO_SpecTrackPoint(self); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1e3521d1..3bfa4d84 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3087,6 +3087,7 @@ void () PreMatchImpulses = { self.invincible_time = 0; self.invincible_finished = 0; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_INVINCIBLE); + self.effects = self.effects - (self.effects & (EF_RED + EF_DIMLIGHT + EF_BRIGHTLIGHT)); } else { self.items = self.items | IT_INVULNERABILITY; self.invincible_time = 1; From 501e697d65416248ff40931f4c1d88ce4977a451 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 1 Aug 2020 22:45:09 +1200 Subject: [PATCH 1029/2474] menu-less sentry rotate --- ssqc/commands.qc | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1ef48e0f..700556ff 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -650,20 +650,35 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); break; } - if (!self.building.real_owner.has_sentry || self.building.real_owner != self - || self.classname != "player" || self.building == world) { + + //find sentry first + ent = findradius(self.origin, ENG_BUILDING_MAINT_DISTANCE); + while (ent) { + if (ent.classname == "building_sentrygun") { + if (ent.real_owner == self) + break; + } + ent = ent.chain; + } + if (!ent) { + sprint(self, PRINT_HIGH, "No sentry in range\n"); break; } if (arg2 && arg3) { if(arg2 == "rotate") { farg3 = stof(arg3); + if (!ent.real_owner.has_sentry || ent.real_owner != self + || self.classname != "player" || ent == world) { + sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); + break; + } if(farg3 < 0) { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); } else { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3)," degrees anticlockwise...\n"); } - self.building.waitmin = anglemod(self.building.waitmin + farg3); - self.building.waitmax = anglemod(self.building.waitmax + farg3); + ent.waitmin = anglemod(ent.waitmin + farg3); + ent.waitmax = anglemod(ent.waitmax + farg3); break; } sprint(self, PRINT_HIGH, "Invalid choice.\n"); From e63652508f94d1a76c0438680a02b73ca6293ec2 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 00:26:59 +1000 Subject: [PATCH 1030/2474] first pass draft scoreboard --- csqc/csextradefs.qc | 30 +++++++- csqc/csprogs.src | 2 - csqc/main.qc | 44 +++++++---- csqc/settings.qc | 5 ++ csqc/status.qc | 174 ++++++++++++++++++++++++++++++++------------ share/defs.h | 3 + ssqc/client.qc | 28 ++++++- ssqc/combat.qc | 8 +- ssqc/events.qc | 27 ++++--- ssqc/medic.qc | 3 +- ssqc/player.qc | 8 +- ssqc/scout.qc | 3 + ssqc/spect.qc | 12 +++ ssqc/spy.qc | 10 ++- ssqc/tfort.qc | 1 - ssqc/weapons.qc | 1 + 16 files changed, 271 insertions(+), 88 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1fdbd08d..54f86070 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -23,6 +23,12 @@ vector MENU_TEXT_MEDIUM = '16 16 0'; vector MENU_TEXT_LARGE = '24 24 0'; float MENU_START_CONTENT = 32; +vector MENU_TEXT_BLUE_FO = '0.3 0.4 0.7'; +vector MENU_TEXT_RED_FO = '0.7 0.4 0.3'; +vector MENU_TEXT_YELLOW_FO = '0.7 0.7 0.3'; +vector MENU_TEXT_GREEN_FO = '0.4 0.7 0.3'; +vector MENU_TEXT_SPEC_FO = '0.1 0.1 0.1'; + #define FO_MENU_FLAG_USE_MOUSE 1 #define FO_MENU_FLAG_CENTER 2 #define FO_MENU_FLAG_SHOW_SHORTCUTS 4 @@ -41,6 +47,9 @@ float MENU_START_CONTENT = 32; #define MOTD_TIME 30 +#define TEAM_SPECTATOR 9 +#define TEAM_OBSERVER 99 + .float owned_by; .string netname; .float playerid; @@ -308,12 +317,28 @@ typedef struct { float teamafflicted; float damagegiven; float damagetaken; + float ready; } FO_ScoreBoardLine; // fte maxclients is 255, right? #define FO_SCOREBOARDLINES_LENGTH 32 -string FO_ScoreBoardColumns[14]; +string FO_ScoreBoardColumns[] = { + "ping", + "pl", + "class", + "score", + "name", + "caps", + "tchs", + "kils", + "tkil", + "dths", + "affl", + "tafl", + "dmgg", + "dmgt" +}; enum { HUD_PANEL_HUDOPTIONS, @@ -334,6 +359,7 @@ enum { HUD_PANEL_SHOWSCORES }; +#define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" @@ -357,3 +383,5 @@ vector FO_Hud_Icon_Font_Size = [8, 8, 0]; string(string s) strtrim = #0:strtrim; /* Trims the whitespace from the start+end of the string. */ +float(float playernum, string keyname, optional float assumevalue) getplayerkeyfloat = #0:getplayerkeyfloat; /* + Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ \ No newline at end of file diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 8a760487..06ab8a94 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,7 +1,5 @@ ../csprogs.dat csdefs.qc -//csqcdefs.qc -../share/fteextensions.qc csextradefs.qc ../share/commondefs.qc diff --git a/csqc/main.qc b/csqc/main.qc index 1def1328..bd96fac5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -32,6 +32,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); + registercvar(FOCMD_OLDSCOREBOARD, "0"); + registercommand("fo_menu_game"); registercommand("fo_main_menu"); registercommand("fo_menu_team"); @@ -246,28 +248,42 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "+fo_showscores": + if (cvar(FOCMD_OLDSCOREBOARD) == 1) + { + tokenize(findkeysforcommand(argv(0))); + + string kn = keynumtostring(stof(argv(0))); + string akn = keynumtostring(stof(argv(1))); + localcmd(sprintf("unbind %s\n", kn)); + localcmd(sprintf("unbind %s\n", akn)); + + localcmd(sprintf("bind %s +showscores\n", kn)); + localcmd(sprintf("bind %s +showscores\n", akn)); + } + FO_Show_Scores(TRUE); + break; + case "-fo_showscores": + FO_Show_Scores(FALSE); + break; case "+showteamscores": case "+showscores": showingscores = TRUE; - float id = getHudPanel("showscorespanel"); - if(id < 0) { - return FALSE; + if (cvar(FOCMD_OLDSCOREBOARD) != 1) + { + tokenize(findkeysforcommand(argv(0))); + + string keyname = keynumtostring(stof(argv(0))); + string altkeyname = keynumtostring(stof(argv(1))); + localcmd(sprintf("unbind %s\n", keyname)); + localcmd(sprintf("unbind %s\n", altkeyname)); + + localcmd(sprintf("bind %s +fo_showscores\n", keyname)); + localcmd(sprintf("bind %s +fo_showscores\n", altkeyname)); } - - FO_Hud_Panel* panel = getHudPanelPointer(id); - panel.Display = TRUE; break; - case "-fo_showscores": case "-showteamscores": case "-showscores": showingscores = FALSE; - float id = getHudPanel("showscorespanel"); - if(id < 0) { - return FALSE; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); - panel.Display = FALSE; break; case "tracktarget": localcmd("cmd tracktarget\n"); diff --git a/csqc/settings.qc b/csqc/settings.qc index d6c17d04..049cd25b 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -5,6 +5,7 @@ void FO_WriteSettings() filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); string line = FormatCfgString("", FOCMD_AUTOHOP, ftos(cvar(FOCMD_AUTOHOP))); line = FormatCfgString(line, FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); + line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(cvar(FOCMD_OLDSCOREBOARD))); fputs(filehandle, line); fclose(filehandle); } @@ -13,6 +14,7 @@ void FO_LoadDefaultSettings() { cvar_set(FOCMD_AUTOHOP, "0"); cvar_set(FOCMD_GRENTIMER, "1"); + cvar_set(FOCMD_OLDSCOREBOARD, "0"); } void FO_LoadSettings() @@ -47,6 +49,9 @@ void FO_LoadSettings() case FOCMD_GRENTIMER: cvar_set(FOCMD_GRENTIMER, val); break; + case FOCMD_OLDSCOREBOARD: + cvar_set(FOCMD_OLDSCOREBOARD, val); + break; } } ln = fgets(filehandle); diff --git a/csqc/status.qc b/csqc/status.qc index 0b5d07a7..f38a9376 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -372,30 +372,57 @@ void (vector position, vector size, string val, vector textcolour, float alpha sui_text(position, size, val, textcolour, 1, 0); }; -void (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id +vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id , float padding, vector columnColour) drawShowScoresTeamPanel = { vector textcolour = MENU_TEXT_1; vector smalltext = MENU_TEXT_SMALL * panel.Scale; vector yspacer = [0, 20]; vector position = [0, 0]; - vector size = getFillSize(id); - - position += yspacer; - size_y = smalltext_y; + vector size = getFillSize(id); - sui_push_frame(position, size); position = [0,0]; sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); size = [size_x, smalltext_y]; sui_fill(position, size, MENU_BG, 1, 0); + // FIXME - hardcoded 4 length on all column names... (pl has 2, name and score have 5) + // of just never have any other columns with more than 4 chars + float txtlength = strlen("name") * smalltext.x; + float namespace = size_x - ((txtlength + padding) * (FO_ScoreBoardColumns.length - 1) - padding); + + float classspace = strlen("class") * smalltext.x; + for (float i = 0; i < FO_ScoreBoardColumns.length; i++) { string colname = FO_ScoreBoardColumns[i]; - sui_text(position, smalltext, colname, columnColour, .7, 0); - float txtlength = strlen(colname) * smalltext.x; - position_x += txtlength + padding; + if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) + { + switch (colname) + { + case "class": + colname = "type"; + case "ping": + case "pl": + case "name": + sui_text(position, smalltext, colname, columnColour, .7, 0); + break; + } + } + else + { + sui_text(position, smalltext, colname, columnColour, .7, 0); + } + + txtlength = strlen(colname) * smalltext.x; + if (colname == "name") + { + position_x += namespace; + } + else + { + position_x += txtlength + padding; + } } position = [0, smalltext.y]; @@ -408,7 +435,7 @@ void (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id lineCount++; float trans = 1; - if (i % 2 == 0) + if (lineCount % 2 == 0) { trans = .7; } @@ -419,6 +446,20 @@ void (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id sui_fill(position, size, columnColour, trans, 0); + if (prematch && lines[i].team_no && !SBAR.CountdownStarted + && lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) + { + float ready = lines[i].ready; + if (ready) + { + textcolour = MENU_TEXT_GREEN_FO; + } + else + { + textcolour = MENU_TEXT_RED_FO; + } + } + float col = 0, alpha = 1, flags = 0; string val = ftos(lines[i].ping); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); @@ -428,15 +469,47 @@ void (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - sui_text(position, smalltext, lines[i].classtext, textcolour, 1, 0); + if (team_no == lines[i].team_no || lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) + { + string c = lines[i].classtext; + if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) + { + float cspace = strlen(c) * smalltext.x; + if (cspace > classspace) + { + float max = classspace / smalltext.x; + // TODO - maybe make this ok with non fixed width fonts one day... we're 90% of the way there + c = substring(c, 0, max); + } + } + + sui_text(position, smalltext, c, textcolour, 1, 0); + } + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].score); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) + { + val = ftos(lines[i].score); + drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + } position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - sui_text(position, smalltext, lines[i].name, textcolour, 1, 0); - position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; + string n = lines[i].name; + if (strlen(n) * smalltext.x >= (namespace - padding)) + { + float diff = (namespace - padding) / smalltext.x; + n = substring(n, 0, diff); + } + sui_text(position, smalltext, n, textcolour, 1, 0); + position_x += namespace; + + if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) + { + position_y += smalltext_y; + position_x = 0; + continue; + } val = ftos(lines[i].caps); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); @@ -478,9 +551,9 @@ void (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id position_y += smalltext_y; } - position = [0,0]; size_y = smalltext.y * lineCount; - sui_border_box(position, size, 1, MENU_BORDER, FO_MENU_TRANSPARENCY, 0); + sui_border_box([0, 0], size, 1, MENU_BORDER, FO_MENU_TRANSPARENCY, 0); + return position; }; void(string panelid, float display, string text, string icon) drawShowScoresPanel = { @@ -505,21 +578,6 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane if(!panel.Display) { return; } - // columns - FO_ScoreBoardColumns[0] = "ping"; - FO_ScoreBoardColumns[1] = "pl"; - FO_ScoreBoardColumns[2] = "class"; - FO_ScoreBoardColumns[3] = "score"; - FO_ScoreBoardColumns[4] = "name"; - FO_ScoreBoardColumns[5] = "caps"; - FO_ScoreBoardColumns[6] = "tchs"; - FO_ScoreBoardColumns[7] = "kils"; - FO_ScoreBoardColumns[8] = "tkil"; - FO_ScoreBoardColumns[9] = "dths"; - FO_ScoreBoardColumns[10] = "affl"; - FO_ScoreBoardColumns[11] = "taffl"; - FO_ScoreBoardColumns[12] = "dmgg"; - FO_ScoreBoardColumns[13] = "dmgt"; FO_ScoreBoardLine FO_ScoreBoardLines_Blue[FO_SCOREBOARDLINES_LENGTH]; FO_ScoreBoardLine FO_ScoreBoardLines_Red[FO_SCOREBOARDLINES_LENGTH]; @@ -552,6 +610,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane sbl.damagegiven = getplayerkeyfloat(i, "damagegiven"); sbl.damagetaken = getplayerkeyfloat(i, "damagetaken"); sbl.team_no = getplayerkeyfloat(i, "team_no"); + sbl.ready = getplayerkeyfloat(i, "ready"); switch (sbl.team_no) { @@ -569,61 +628,80 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane break; default: float spec = getplayerkeyfloat(i, "*spectator"); - sbl.team_no = (spec == 1) ? 9 : 99; // TODO - use defines... + sbl.team_no = (spec == 1) ? TEAM_SPECTATOR : TEAM_OBSERVER; + sbl.classtext = (spec == 1) ? "Spectator" : "Observer"; FO_ScoreBoardLines_Specs[speccount++] = sbl; break; } } - vector red = '0.7 0.4 0.3'; - vector blue = '0.3 0.4 0.7'; - vector yellow = '0.7 0.7 0.3'; - vector green = '0.4 0.7 0.3'; - vector spec = '0.1 0.1 0.1'; float sbCount = 0; + + vector smalltext = MENU_TEXT_SMALL * panel.Scale; + vector yspacer = [0, 20]; + size_y = smalltext_y; + if (FO_ScoreBoardLines_Blue[0].name) { - drawShowScoresTeamPanel(FO_ScoreBoardLines_Blue, panel, id, padding, blue); + position += yspacer; + sui_push_frame(position, size); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Blue, panel, id, padding, MENU_TEXT_BLUE_FO); sbCount++; } if (FO_ScoreBoardLines_Red[0].name) { - drawShowScoresTeamPanel(FO_ScoreBoardLines_Red, panel, id, padding, red); + position += yspacer; + sui_push_frame(position, size); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Red, panel, id, padding, MENU_TEXT_RED_FO); sbCount++; } if (FO_ScoreBoardLines_Yellow[0].name) { - drawShowScoresTeamPanel(FO_ScoreBoardLines_Yellow, panel, id, padding, yellow); + position += yspacer; + sui_push_frame(position, size); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Yellow, panel, id, padding, MENU_TEXT_YELLOW_FO); sbCount++; } if (FO_ScoreBoardLines_Green[0].name) { - drawShowScoresTeamPanel(FO_ScoreBoardLines_Green, panel, id, padding, green); + position += yspacer; + sui_push_frame(position, size); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Green, panel, id, padding, MENU_TEXT_GREEN_FO); sbCount++; } if (FO_ScoreBoardLines_Specs[0].name) { - drawShowScoresTeamPanel(FO_ScoreBoardLines_Specs, panel, id, padding, spec); + position += yspacer; + sui_push_frame(position, size); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Specs, panel, id, padding, MENU_TEXT_SPEC_FO); sbCount++; } - + for (float i = 0; i < sbCount; i++) { sui_pop_frame(); } - // FIXME - reset damage numbers etc on map change - // FIXME - class isn't set on first spawn - // FIXME - specs/observers aren't shown - // FIXME - afflictions aren't implemented + // TODO - Width - make adjustable?? we have panel scaling which is used sui_pop_frame(); } } +void (float show) FO_Show_Scores = { + showingscores = show; + float id = getHudPanel("showscorespanel"); + if(id < 0) { + return FALSE; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + panel.Display = show; +}; + var FO_Hud_Panel Hud_Panels[] = { {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, diff --git a/share/defs.h b/share/defs.h index 8ac18323..fc223627 100644 --- a/share/defs.h +++ b/share/defs.h @@ -248,6 +248,9 @@ #define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating #define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised #define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack +// FIXME - concussion and flash states aren't set or tested... +#define TFSTATE_CONCUSSED 131072 +#define TFSTATE_FLASHED 262144 // Defines used by TF_T_Damage (see combat.qc) #define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target diff --git a/ssqc/client.qc b/ssqc/client.qc index 0f920243..c8ecf3b2 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1669,6 +1669,30 @@ void (entity p) SetVoteParams = { spawn_tfog(p.origin + v_forward * 20); } +void (entity player, string field, float fieldval) CheckSetInfoKey = +{ + float val; + val = infokeyf(player, field); + + if (val != fieldval) + forceinfokey(player, field, ftos(fieldval)); +}; + +void (entity player) UpdateScoreboardInfo = { + + CheckSetInfoKey(player, "afflicted", player.afflicted); + CheckSetInfoKey(player, "teamafflicted", player.teamafflicted); + CheckSetInfoKey(player, "damagegiven", player.damagegiven); + CheckSetInfoKey(player, "damagetaken", player.damagetaken); + CheckSetInfoKey(player, "kills", player.kills); + CheckSetInfoKey(player, "deaths", player.deaths); + CheckSetInfoKey(player, "caps", player.caps); + CheckSetInfoKey(player, "touches", player.touches); + CheckSetInfoKey(player, "team_no", player.team_no); + CheckSetInfoKey(player, "playerclass", player.playerclass); + CheckSetInfoKey(player, "ready", player.is_ready); +}; + void () PutClientInServer = { local float oldclass; local entity spot; @@ -1787,8 +1811,6 @@ void () PutClientInServer = { self.takedamage = 2; - forceinfokey(self, "playerclass", ftos(self.playerclass)); - TeamFortress_PrintClassName(self, self.playerclass, self.tfstate & TFSTATE_RANDOMPC); TeamFortress_SetEquipment(); @@ -2516,6 +2538,8 @@ void () CheckPowerups = { }; void () PlayerPostThink = { + UpdateScoreboardInfo(self); + if (self.view_ofs == '0 0 0') { return; } diff --git a/ssqc/combat.qc b/ssqc/combat.qc index d5a814c3..1f9a2796 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -365,6 +365,7 @@ void (entity targ, entity inflictor, entity attacker, if ((take < 1) && (take != 0)) take = 1; + float damh = (take > targ.health) ? targ.health : take; targ.health = targ.health - take; if (targ.armorvalue < 1) { @@ -372,7 +373,7 @@ void (entity targ, entity inflictor, entity attacker, targ.armorvalue = 0; } if ((attacker.classname == "player" || targ.classname == "player") && (take + save > 0)) { - LogEventDamage(attacker, targ, inflictor, take + save); + LogEventDamage(attacker, targ, inflictor, take + save, damh + save); } if (targ.health <= 0) { LogEventKill(attacker, targ, inflictor); @@ -599,6 +600,8 @@ void (entity targ, entity inflictor, entity attacker, float damage, take = rint(take); + float damh = (take > targ.health) ? targ.health : take; + if (no_damage == 0) targ.health = (targ.health - take); @@ -636,8 +639,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (no_damage == TRUE) return; + if ((attacker.classname == "player" || targ.classname == "player") && (take + save > 0)) { - LogEventDamage(attacker, targ, inflictor, take + save); + LogEventDamage(attacker, targ, inflictor, take + save, damh + save); } if (targ.armorvalue < 1) { targ.armorclass = 0; diff --git a/ssqc/events.qc b/ssqc/events.qc index 1bc46f0a..d875b1e1 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -154,30 +154,26 @@ void (entity attacker, entity target, string afflictionType) LogAffliction = { if (attacker.team_no == target.team_no) { attacker.afflicted = attacker.afflicted + 1; - forceinfokey(attacker, "afflicted", ftos(attacker.afflicted)); } else { attacker.teamafflicted = attacker.teamafflicted + 1; - forceinfokey(attacker, "teamafflicted", ftos(attacker.teamafflicted)); } } } -void (entity attacker, entity target, entity inflictor, float damage) LogEventDamage = { +void (entity attacker, entity target, entity inflictor, float damage, float truedam) LogEventDamage = { if (attacker) { if (attacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) { - attacker.damagegiven = attacker.damagegiven + damage; - forceinfokey(attacker, "damagegiven", ftos(attacker.damagegiven)); + attacker.damagegiven = attacker.damagegiven + truedam; } } if (target.classname == "player") { - target.damagetaken = target.damagetaken + damage; - forceinfokey(target, "damagetaken", ftos(target.damagetaken)); + target.damagetaken = target.damagetaken + truedam; } if (canlog == 0) @@ -271,7 +267,6 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { else { attacker.kills = attacker.kills + 1; - forceinfokey(attacker, "kills", ftos(attacker.kills)); } } } @@ -279,7 +274,6 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { if (target.classname == "player") { target.deaths = target.deaths + 1; - forceinfokey(target, "deaths", ftos(target.deaths)); } if (canlog == 0) @@ -354,10 +348,22 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { logevent(event); } +void (entity attacker, entity target, float tfstate) LogEventAffliction = { + if (attacker != target) + { + if (attacker.team_no == target.team_no) + { + attacker.teamafflicted = attacker.teamafflicted + 1; + } + else + { + attacker.afflicted = attacker.afflicted + 1; + } + } +}; void (entity player) LogEventGoal = { player.caps = player.caps + 1; - forceinfokey(player, "caps", ftos(player.caps)); if (canlog == 0) return; local string event; @@ -373,7 +379,6 @@ void (entity player) LogEventGoal = { void (entity player) LogEventPickupGoal = { player.touches = player.touches + 1; - forceinfokey(player, "touches", ftos(player.touches)); if (canlog == 0) return; local string event; diff --git a/ssqc/medic.qc b/ssqc/medic.qc index ccb8a4a5..10a8d27c 100644 --- a/ssqc/medic.qc +++ b/ssqc/medic.qc @@ -183,7 +183,8 @@ void () BioInfection_Decay = { te.tfstate = te.tfstate | TFSTATE_INFECTED; te.infection_team_no = self.owner.infection_team_no; - + LogEventAffliction(self.enemy, te, TFSTATE_INFECTED); + LogEventAffliction(self.owner, te, TFSTATE_INFECTED); sprint(te, PRINT_MEDIUM, "You have been infected by ", self.owner.netname, "\n"); sprint(self.owner, PRINT_MEDIUM, "You have infected ", te.netname, "\n"); } diff --git a/ssqc/player.qc b/ssqc/player.qc index 274dff41..c2415600 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -44,9 +44,9 @@ void () player_touch = { } } } - if ((self.tfstate & 16) && (!cb_prematch)) { + if ((self.tfstate & TFSTATE_INFECTED) && (!cb_prematch)) { if ((other.classname == "player") && (te.playerclass != 0)) { - if (!(other.tfstate & 16)) { + if (!(other.tfstate & TFSTATE_INFECTED)) { if (other.playerclass != 5) { if (!((teamplay & 16) && (self.owner.team_no == self.enemy.team_no) @@ -67,8 +67,10 @@ void () player_touch = { Bio.owner = other; Bio.classname = "timer"; Bio.enemy = te.enemy; - other.tfstate = other.tfstate | 16; + other.tfstate = other.tfstate | TFSTATE_INFECTED; other.infection_team_no = self.infection_team_no; + LogEventAffliction(te.enemy, other, TFSTATE_INFECTED); + LogEventAffliction(self, other, TFSTATE_INFECTED); sprint(other, PRINT_MEDIUM, "You have been infected by ", self.netname, "\n"); diff --git a/ssqc/scout.qc b/ssqc/scout.qc index ebee8a95..f386cc11 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -224,6 +224,7 @@ void FO_FlashExplode() if (te.classname == "player") { traceline(self.origin, te.origin, 1, self); if (trace_fraction == 1) { + LogEventAffliction(self.owner, te, TFSTATE_FLASHED); sprint(te, PRINT_HIGH, "You have been flashed!\n"); org = te.origin + (te.mins + te.maxs) * 0.5; frac = (rad - vlen(self.origin - org)) / rad; @@ -301,6 +302,7 @@ void () FlashGrenadeExplode = { if (te.classname == "player") { traceline(self.origin, te.origin, 1, self); if (trace_fraction == 1) { + LogEventAffliction(self.owner, te, TFSTATE_FLASHED); if (vlen(self.origin - te.origin) <= 200) { deathmsg = DMSG_GREN_FLASH; TF_T_Damage(te, self, self.owner, 60, 2, 16 | 4); @@ -771,6 +773,7 @@ void (entity inflictor, entity attacker, float bounce, te.nextthink = time + 0.25; } } else { + LogEventAffliction(attacker, head, TFSTATE_CONCUSSED); if (old_grens == TRUE) { stuffcmd(head, "v_idlescale 100\n"); stuffcmd(head, "fov 130\n"); diff --git a/ssqc/spect.qc b/ssqc/spect.qc index e125602f..94b68aee 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -132,6 +132,18 @@ void () SpectatorImpulseCommand = { void () SpectatorThink = { + self.playerclass = 0; + self.afflicted = 0; + self.teamafflicted = 0; + self.damagegiven = 0; + self.damagetaken = 0; + self.kills = 0; + self.deaths = 0; + self.caps = 0; + self.touches = 0; + self.team_no = 0; + UpdateScoreboardInfo(self); + if (self.impulse) SpectatorImpulseCommand(); diff --git a/ssqc/spy.qc b/ssqc/spy.qc index fb015508..3dd6ec00 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1086,6 +1086,7 @@ void () GasGrenadeMakeGas = { } } } else { + LogEventAffliction(self.owner, te, TFSTATE_HALLUCINATING); if (old_grens == 1) { stuffcmd(te, "v_cshift 50 25 50 -50\n"); sprint(te, PRINT_HIGH, "Far out man!\n"); @@ -1341,7 +1342,10 @@ void () T_TranqDartTouch = { if ((other.classname == "player") && !((other.team_no == self.owner.team_no) && (teamplay & (2 | 4)))) { - if (other.tfstate & 32768) { + + LogEventAffliction(self.owner, other, TFSTATE_TRANQUILISED); + + if (other.tfstate & TFSTATE_TRANQUILISED) { timer = find(world, classname, "timer"); while (((timer.owner != other) || (timer.think != TranquiliserTimer)) && @@ -1353,7 +1357,7 @@ void () T_TranqDartTouch = { } } else { sprint(other, 2, "You feel tired...\n"); - other.tfstate = other.tfstate | 32768; + other.tfstate = other.tfstate | TFSTATE_TRANQUILISED; timer = spawn(); timer.nextthink = time + 15; timer.think = TranquiliserTimer; @@ -1386,7 +1390,7 @@ void () T_TranqDartTouch = { }; void () TranquiliserTimer = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 32768); + self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_TRANQUILISED); TeamFortress_SetSpeed(self.owner); sprint(self.owner, PRINT_HIGH, "You feel more alert now\n"); dremove(self); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index a2569a52..46fd4498 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -226,7 +226,6 @@ void (float inp) TeamFortress_ChangeClass = { // FIXME - should this be using putclientinserver instead? self.playerclass = inp; - forceinfokey(self, "playerclass", ftos(self.playerclass)); //self.nextpc = 0; self.nextpc = inp; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 8e67e7f3..7e74fbd6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -594,6 +594,7 @@ void () W_FireMedikit = { BioInfection.nextthink = time + 1; BioInfection.think = BioInfection_Decay; BioInfection.enemy = self; + LogEventAffliction(self, trace_ent, TFSTATE_INFECTED); trace_ent.infection_team_no = self.team_no; } } else { From 52c3be29e05f374931cf4494f675ad042653e068 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 00:37:30 +1000 Subject: [PATCH 1031/2474] remove drawscores as it isn't used --- csqc/main.qc | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index bd96fac5..5b7eac49 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -68,40 +68,6 @@ noref void() CSQC_WorldLoaded = { localcmd("menu_restart\n"); } -void(vector viewsize, float scoresshown) CSQC_DrawScores = { - print("showing scores\n"); - string panelid = "showscorespanel"; - float id = getHudPanel(panelid); - if(id < 0) { - return; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); - - vector position = getPosition(id); - vector size = getFillSize(id); - vector mediumtext = MENU_TEXT_SMALL * panel.Scale; - vector textcolour = MENU_TEXT_4; - local float padding = 4 * panel.Scale; - local float lines; - local float pos_aligned; - local string message; - if (fo_hud_editor) { - message = "Show Scores"; - if (hud_panel(panelid, position, size, 0.3, panel.Display)) { - // click event - } - } else { - if(!panel.Display) { - return; - } - message = "draw"; - if (hud_panel(panelid, position, size, 0.3, panel.Display)) { - // click event - } - } -}; - noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); From 427b7ebb2ff9f7f61b447a852563eaafc2c7cac1 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 00:53:18 +1000 Subject: [PATCH 1032/2474] remove extra showscores --- csqc/main.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index fdf0717d..13a29d52 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -231,7 +231,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-fo_showscores": FO_Show_Scores(FALSE); break; - case "+showteamscores": case "+showscores": case "+showteamscores": showingscores = TRUE; @@ -248,7 +247,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd(sprintf("bind %s +fo_showscores\n", altkeyname)); } break; - case "-showteamscores": case "-showscores": case "-showteamscores": showingscores = FALSE; From f4f5e06b3a01008c36c1b493b6205c4655ab25a5 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 00:55:04 +1000 Subject: [PATCH 1033/2474] Revert "menu-less sentry rotate" This reverts commit 501e697d65416248ff40931f4c1d88ce4977a451. --- ssqc/commands.qc | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index eb225b92..a7ec7124 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -657,35 +657,20 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); break; } - - //find sentry first - ent = findradius(self.origin, ENG_BUILDING_MAINT_DISTANCE); - while (ent) { - if (ent.classname == "building_sentrygun") { - if (ent.real_owner == self) - break; - } - ent = ent.chain; - } - if (!ent) { - sprint(self, PRINT_HIGH, "No sentry in range\n"); + if (!self.building.real_owner.has_sentry || self.building.real_owner != self + || self.classname != "player" || self.building == world) { break; } if (arg2 && arg3) { if(arg2 == "rotate") { farg3 = stof(arg3); - if (!ent.real_owner.has_sentry || ent.real_owner != self - || self.classname != "player" || ent == world) { - sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); - break; - } if(farg3 < 0) { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); } else { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3)," degrees anticlockwise...\n"); } - ent.waitmin = anglemod(ent.waitmin + farg3); - ent.waitmax = anglemod(ent.waitmax + farg3); + self.building.waitmin = anglemod(self.building.waitmin + farg3); + self.building.waitmax = anglemod(self.building.waitmax + farg3); break; } sprint(self, PRINT_HIGH, "Invalid choice.\n"); From c25e72506471f331384e7ac2d522ed565e44acdb Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 00:59:42 +1000 Subject: [PATCH 1034/2474] disable fo_showscores for now --- csqc/main.qc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index fdf0717d..03274f02 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -213,7 +213,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("gren2_server"); } break; - case "+fo_showscores": + /*case "+fo_showscores": if (cvar(FOCMD_OLDSCOREBOARD) == 1) { tokenize(findkeysforcommand(argv(0))); @@ -230,12 +230,11 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; case "-fo_showscores": FO_Show_Scores(FALSE); - break; - case "+showteamscores": + break;*/ case "+showscores": case "+showteamscores": showingscores = TRUE; - if (cvar(FOCMD_OLDSCOREBOARD) != 1) + /*if (cvar(FOCMD_OLDSCOREBOARD) != 1) { tokenize(findkeysforcommand(argv(0))); @@ -246,9 +245,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd(sprintf("bind %s +fo_showscores\n", keyname)); localcmd(sprintf("bind %s +fo_showscores\n", altkeyname)); - } + }*/ break; - case "-showteamscores": case "-showscores": case "-showteamscores": showingscores = FALSE; From 3c4effc099686a0f6b91381b077e97916fbc9c54 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 01:01:23 +1000 Subject: [PATCH 1035/2474] Revert "Revert "menu-less sentry rotate"" This reverts commit f4f5e06b3a01008c36c1b493b6205c4655ab25a5. --- ssqc/commands.qc | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a7ec7124..eb225b92 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -657,20 +657,35 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); break; } - if (!self.building.real_owner.has_sentry || self.building.real_owner != self - || self.classname != "player" || self.building == world) { + + //find sentry first + ent = findradius(self.origin, ENG_BUILDING_MAINT_DISTANCE); + while (ent) { + if (ent.classname == "building_sentrygun") { + if (ent.real_owner == self) + break; + } + ent = ent.chain; + } + if (!ent) { + sprint(self, PRINT_HIGH, "No sentry in range\n"); break; } if (arg2 && arg3) { if(arg2 == "rotate") { farg3 = stof(arg3); + if (!ent.real_owner.has_sentry || ent.real_owner != self + || self.classname != "player" || ent == world) { + sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); + break; + } if(farg3 < 0) { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); } else { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3)," degrees anticlockwise...\n"); } - self.building.waitmin = anglemod(self.building.waitmin + farg3); - self.building.waitmax = anglemod(self.building.waitmax + farg3); + ent.waitmin = anglemod(ent.waitmin + farg3); + ent.waitmax = anglemod(ent.waitmax + farg3); break; } sprint(self, PRINT_HIGH, "Invalid choice.\n"); From 36e53ff6ded4995c456908fe0a6c25cec85fd3ee Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 14:54:13 +1000 Subject: [PATCH 1036/2474] fix default scaling --- csqc/status.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index f38a9376..52036358 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -686,7 +686,6 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane sui_pop_frame(); } - // TODO - Width - make adjustable?? we have panel scaling which is used sui_pop_frame(); } } @@ -718,7 +717,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'100 300','300 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, - {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',2,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, + {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, }; float(string panelid) getHudPanel = { From 86ffb0e49655def63639593093ab14830708ff9c Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 14:57:53 +1000 Subject: [PATCH 1037/2474] only rebind if key exists --- csqc/main.qc | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 13a29d52..fb74d4e3 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -220,11 +220,17 @@ noref float(string cmd) CSQC_ConsoleCommand = { string kn = keynumtostring(stof(argv(0))); string akn = keynumtostring(stof(argv(1))); - localcmd(sprintf("unbind %s\n", kn)); - localcmd(sprintf("unbind %s\n", akn)); + if (kn != "") + { + localcmd(sprintf("unbind %s\n", kn)); + localcmd(sprintf("bind %s +showscores\n", kn)); + } - localcmd(sprintf("bind %s +showscores\n", kn)); - localcmd(sprintf("bind %s +showscores\n", akn)); + if (akn != "") + { + localcmd(sprintf("unbind %s\n", akn)); + localcmd(sprintf("bind %s +showscores\n", akn)); + } } FO_Show_Scores(TRUE); break; @@ -240,11 +246,17 @@ noref float(string cmd) CSQC_ConsoleCommand = { string keyname = keynumtostring(stof(argv(0))); string altkeyname = keynumtostring(stof(argv(1))); - localcmd(sprintf("unbind %s\n", keyname)); - localcmd(sprintf("unbind %s\n", altkeyname)); + if (keyname != "") + { + localcmd(sprintf("unbind %s\n", keyname)); + localcmd(sprintf("bind %s +fo_showscores\n", keyname)); + } - localcmd(sprintf("bind %s +fo_showscores\n", keyname)); - localcmd(sprintf("bind %s +fo_showscores\n", altkeyname)); + if (altkeyname != "") + { + localcmd(sprintf("unbind %s\n", altkeyname)); + localcmd(sprintf("bind %s +fo_showscores\n", altkeyname)); + } } break; case "-showscores": From 52593abd9843906379e673365df9554bf5c73994 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 19:50:33 +1000 Subject: [PATCH 1038/2474] better key checking for rebind --- csqc/main.qc | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index fb74d4e3..38a4ba1a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -116,6 +116,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { noref float(string cmd) CSQC_ConsoleCommand = { tokenize(cmd); float val; + string key1, key2; switch(argv(0)) { case "fo_hud_editor": FO_Hud_Editor(); @@ -218,18 +219,21 @@ noref float(string cmd) CSQC_ConsoleCommand = { { tokenize(findkeysforcommand(argv(0))); - string kn = keynumtostring(stof(argv(0))); - string akn = keynumtostring(stof(argv(1))); - if (kn != "") + key1 = argv(0); + key2 = argv(1); + if (key1 != "") key1 = (key1=="-1")?"":keynumtostring(stof(key1)); + if (key2 != "") key2 = (key2=="-1")?"":keynumtostring(stof(key2)); + + if (key1 != "") { - localcmd(sprintf("unbind %s\n", kn)); - localcmd(sprintf("bind %s +showscores\n", kn)); + localcmd(sprintf("unbind %s\n", key1)); + localcmd(sprintf("bind %s +showscores\n", key1)); } - if (akn != "") + if (key2 != "") { - localcmd(sprintf("unbind %s\n", akn)); - localcmd(sprintf("bind %s +showscores\n", akn)); + localcmd(sprintf("unbind %s\n", key2)); + localcmd(sprintf("bind %s +showscores\n", key2)); } } FO_Show_Scores(TRUE); @@ -244,18 +248,21 @@ noref float(string cmd) CSQC_ConsoleCommand = { { tokenize(findkeysforcommand(argv(0))); - string keyname = keynumtostring(stof(argv(0))); - string altkeyname = keynumtostring(stof(argv(1))); - if (keyname != "") + key1 = argv(0); + key2 = argv(1); + if (key1 != "") key1 = (key1=="-1")?"":keynumtostring(stof(key1)); + if (key2 != "") key2 = (key2=="-1")?"":keynumtostring(stof(key2)); + + if (key1 != "") { - localcmd(sprintf("unbind %s\n", keyname)); - localcmd(sprintf("bind %s +fo_showscores\n", keyname)); + localcmd(sprintf("unbind %s\n", key1)); + localcmd(sprintf("bind %s +fo_showscores\n", key1)); } - if (altkeyname != "") + if (key2 != "") { - localcmd(sprintf("unbind %s\n", altkeyname)); - localcmd(sprintf("bind %s +fo_showscores\n", altkeyname)); + localcmd(sprintf("unbind %s\n", key2)); + localcmd(sprintf("bind %s +fo_showscores\n", key2)); } } break; From 9fe4dff82330d3f9a2cf696d2c4e4cc0184e2834 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 2 Aug 2020 19:53:42 +1000 Subject: [PATCH 1039/2474] default flash grens on --- README.md | 2 +- ssqc/client.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 27c414cc..ed6dd03f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ New features * optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * localinfo nohitsounds 1 - disables hitsounds server-wide * localinfo noreturn 1 - prevents goalitems from returning (will still return from lava) -* scout has "new" flash grenades - localinfo fo_flash on (default off) +* scout has "new" flash grenades - localinfo fo_flash on (default on) * ability to set client side min and max flash amounts - localinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) * `cmd votemap`/`cmd showvotes`/`cmd listmaps` can now be used at any time and are part of the same system * new server command `vote_removemap ` removes them diff --git a/ssqc/client.qc b/ssqc/client.qc index c8ecf3b2..181cdea3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -414,7 +414,7 @@ void () DecodeLevelParms = { old_grens = CF_GetSetting("og", "old_grens", "off"); // use fortress one flash - fo_flash = CF_GetSetting("ff", "fo_flash", "off"); + fo_flash = CF_GetSetting("ff", "fo_flash", "on"); // drop primed hand grenades to ground when dying [on] drop_grenades = CF_GetSetting("dg", "drop_grenades", "on"); From e1ea95ca457a4b44c4d440018d99284198728914 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 3 Aug 2020 12:58:08 +1000 Subject: [PATCH 1040/2474] Use older fteqcc in CI for now --- .github/workflows/workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 3a32a090..d0b157fa 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v1 - name: Compile run: | - wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 + wget http://fte.triptohell.info/moodles/autoup/linux_amd64/fteqcc64 chmod +x fteqcc64 export PATH=$GITHUB_WORKSPACE:$PATH make From af30f182b0db49c68d46ee07a50d5948ddbf93c5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 3 Aug 2020 19:16:19 +1000 Subject: [PATCH 1041/2474] Default showscores hud scaling to 100% --- csqc/hud.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/hud.qc b/csqc/hud.qc index 4225886f..d6c62734 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -97,6 +97,7 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_CAPS].Display = 0; Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; Hud_Panels[HUD_PANEL_SHOWSCORES].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_SHOWSCORES].FillSize.x / 2), 30]; + Hud_Panels[HUD_PANEL_SHOWSCORES].Scale = 1.00; } void FO_Hud_Editor_List_Panels() = { From e15c5e7ef1db76a0b239f1e56575b1131be0f1ae Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 4 Aug 2020 16:39:19 +1200 Subject: [PATCH 1042/2474] add csqcactive filters to all client messages --- ssqc/csmenu.qc | 42 ++++++++++++++++++++++++++++++++++++++++++ ssqc/engineer.qc | 4 ++++ ssqc/status.qc | 14 ++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 6e4f6053..c66f8812 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -1,4 +1,6 @@ void UpdateClientMenu_Team(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -11,6 +13,8 @@ void UpdateClientMenu_Team(entity pl) = { } void UpdateClientClasses(entity pl, float team) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; local float civilian_team = TeamFortress_TeamIsCivilian(pl.team_no); msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); @@ -34,6 +38,8 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; if(!pl.playerclass) { return; } @@ -45,6 +51,8 @@ void UpdateClientMenu_Class(entity pl) = { } void UpdateClientMenu_DropAmmo(entity pl, float ammotypes, float ammomakes) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -55,6 +63,8 @@ void UpdateClientMenu_DropAmmo(entity pl, float ammotypes, float ammomakes) = { } void UpdateClientMenu_Scout(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -65,6 +75,8 @@ void UpdateClientMenu_Scout(entity pl) = { } void UpdateClientMenu_Spy(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -76,6 +88,8 @@ void UpdateClientMenu_Spy(entity pl) = { } void UpdateClientMenu_Spy_Skin(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -84,6 +98,8 @@ void UpdateClientMenu_Spy_Skin(entity pl) = { } void UpdateClientMenu_Spy_Team(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -91,6 +107,8 @@ void UpdateClientMenu_Spy_Team(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void UpdateClientMenu_Detpack(entity pl, float cancel_detpack) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -100,6 +118,8 @@ void UpdateClientMenu_Detpack(entity pl, float cancel_detpack) = { } void UpdateClientMenu_Build(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -107,6 +127,8 @@ void UpdateClientMenu_Build(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void UpdateClientMenu_FixSentry(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -114,6 +136,8 @@ void UpdateClientMenu_FixSentry(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void UpdateClientMenu_FixDispenser(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -122,6 +146,8 @@ void UpdateClientMenu_FixDispenser(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void UpdateClientMenu_UseDispenser(entity pl, entity disp) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -132,6 +158,8 @@ void UpdateClientMenu_UseDispenser(entity pl, entity disp) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void UpdateClientMenu_Admin(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -139,6 +167,8 @@ void UpdateClientMenu_Admin(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void Update_ServerAdminInfo(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; local float cm = CF_GetSetting("c", "clan", "off"), qm = CF_GetSetting("quadmode", "quadmode", "off"), @@ -158,6 +188,8 @@ void Update_ServerAdminInfo(entity pl) = { } void UpdateClientMenu_Admin_Kick(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -165,6 +197,8 @@ void UpdateClientMenu_Admin_Kick(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } void UpdateClientMenu_Vote(entity pl, float timeleft) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -184,6 +218,8 @@ void UpdateClientMenu_Vote(entity pl, float timeleft) = { } void UpdateClientMenu_Captain(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); @@ -192,6 +228,8 @@ void UpdateClientMenu_Captain(entity pl) = { } void UpdateClient_Captains(entity pl, float cap1, float cap2) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CAPTAINS); @@ -201,6 +239,8 @@ void UpdateClient_Captains(entity pl, float cap1, float cap2) = { } void UpdateClientMOTD(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_MOTD); @@ -218,6 +258,8 @@ void UpdateClientMOTD(entity pl) = { } void UpdateClientPrematch(entity pl, float countdownstarted) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_PREMATCH); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index a81842c7..98da57b9 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -782,6 +782,8 @@ void () DispenserThink = { }; void UpdateClient_Sentry(entity pl, entity sent) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SENTRY_POS); @@ -792,6 +794,8 @@ void UpdateClient_Sentry(entity pl, entity sent) = { } void UpdateClient_Dispenser(entity pl, entity disp) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_DISPENSER_POS); diff --git a/ssqc/status.qc b/ssqc/status.qc index 7c5ac232..f3f62dba 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -583,6 +583,8 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5, string s string getLocationName(vector location); void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + return; //float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); //if(csqcactive) { msg_entity = Player; @@ -617,6 +619,8 @@ void (entity Player) InitAllStatuses = { float laststate; void (entity Player, entity Goal) UpdateClientButtonStatus = { + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = Player; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_FLAGINFO); @@ -647,6 +651,8 @@ void (entity Player, entity Goal) UpdateClientButtonStatus = { } void (entity Player, entity Item) UpdateClientFlagStatus = { + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = Player; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_FLAGINFO); @@ -793,6 +799,8 @@ string GetSBClassInfo(entity pl, float csqcactive) } void UpdateClientGrenadePrimed(entity pl, float grentype) = { + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); @@ -801,6 +809,8 @@ void UpdateClientGrenadePrimed(entity pl, float grentype) = { } void UpdateClientGrenadeThrown(entity pl) = { + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENTHROWN); @@ -808,6 +818,8 @@ void UpdateClientGrenadeThrown(entity pl) = { } void UpdateClientIDString(entity pl) { + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + return; // only send updates //if(time < pl.ident_time && pl.ident_string == pl.last_ident_string) // return; @@ -826,6 +838,8 @@ void UpdateClientIDString(entity pl) { void UpdateClientStatusBar(entity pl) { + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + return; // if we ever change to fte only, this could be changed to stats string msg = ""; msg_entity = pl; From 1c540907284d3fe2fbeb9611467c7baa05cbc68b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 4 Aug 2020 16:42:46 +1200 Subject: [PATCH 1043/2474] variable names --- ssqc/status.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index f3f62dba..e6adafbb 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -799,7 +799,7 @@ string GetSBClassInfo(entity pl, float csqcactive) } void UpdateClientGrenadePrimed(entity pl, float grentype) = { - if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); @@ -809,7 +809,7 @@ void UpdateClientGrenadePrimed(entity pl, float grentype) = { } void UpdateClientGrenadeThrown(entity pl) = { - if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); @@ -818,7 +818,7 @@ void UpdateClientGrenadeThrown(entity pl) = { } void UpdateClientIDString(entity pl) { - if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; // only send updates //if(time < pl.ident_time && pl.ident_string == pl.last_ident_string) @@ -838,7 +838,7 @@ void UpdateClientIDString(entity pl) { void UpdateClientStatusBar(entity pl) { - if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; // if we ever change to fte only, this could be changed to stats string msg = ""; From 93fd36df3418911ba8775bf939a27db618ea924f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 4 Aug 2020 18:10:22 +1000 Subject: [PATCH 1044/2474] Use latest fteqcc in CI --- .github/workflows/workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index d0b157fa..3a32a090 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v1 - name: Compile run: | - wget http://fte.triptohell.info/moodles/autoup/linux_amd64/fteqcc64 + wget http://fte.triptohell.info/moodles/linux_amd64/fteqcc64 chmod +x fteqcc64 export PATH=$GITHUB_WORKSPACE:$PATH make From 73700eb3461890c419ee3adc8d3ef20d465f6771 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 4 Aug 2020 19:37:13 +1000 Subject: [PATCH 1045/2474] weapon 1 doesn't work so use impulses --- menu/options_keys.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/menu/options_keys.qc b/menu/options_keys.qc index bc335ba1..9107c268 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -42,10 +42,10 @@ const static struct {_("Next Weapon"), "weapnext"}, {_("Prev Weapon"), "weapprev"}, {_("Last Weapon"), "weaplast"}, - {_("Primary Weapon"), "weapon 1"}, - {_("Secondary Weapon"), "weapon 2"}, - {_("Tertiary Weapon"), "weapon 3"}, - {_("Melee"), "weapon 4"}, + {_("Primary Weapon"), "impulse 1"}, + {_("Secondary Weapon"), "impulse 2"}, + {_("Tertiary Weapon"), "impulse 3"}, + {_("Melee"), "impulse 4"}, {0, 0}, {0, 0}, {_(""), "Advanced Weaponry"}, From 0ac1b9f7361ec40947bcaaf2327cf5bbb68a9d77 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 5 Aug 2020 22:08:38 +1000 Subject: [PATCH 1046/2474] count sentry gun kills in stats --- ssqc/events.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/events.qc b/ssqc/events.qc index d875b1e1..3f5c9996 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -258,8 +258,13 @@ void (entity attacker, entity target, entity inflictor, float damage, float true void (entity attacker, entity target, entity inflictor) LogEventKill = { if (attacker) { - if (attacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) + if (attacker.classname == "player" || attacker.classname == "building_sentrygun" && (target.classname == "player" || target.classname == "building_sentrygun")) { + if (attacker.classname == "building_sentrygun") + { + attacker = attacker.real_owner; + } + if (attacker.team_no == target.team_no) { attacker.teamkills = attacker.teamkills + 1; From 0a6a2e751dcb6005d4fd9eb9cd482179659b7d74 Mon Sep 17 00:00:00 2001 From: danni Date: Wed, 5 Aug 2020 22:11:14 +1000 Subject: [PATCH 1047/2474] count sentrygun damage for owner --- ssqc/events.qc | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/ssqc/events.qc b/ssqc/events.qc index 3f5c9996..57e6a09b 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -165,9 +165,13 @@ void (entity attacker, entity target, string afflictionType) LogAffliction = { void (entity attacker, entity target, entity inflictor, float damage, float truedam) LogEventDamage = { if (attacker) { - if (attacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) + entity realattacker = attacker; + if (attacker.classname == "building_sentrygun") + realattacker = attacker.real_owner; + + if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) { - attacker.damagegiven = attacker.damagegiven + truedam; + realattacker.damagegiven = realattacker.damagegiven + truedam; } } @@ -258,20 +262,24 @@ void (entity attacker, entity target, entity inflictor, float damage, float true void (entity attacker, entity target, entity inflictor) LogEventKill = { if (attacker) { - if (attacker.classname == "player" || attacker.classname == "building_sentrygun" && (target.classname == "player" || target.classname == "building_sentrygun")) + entity realattacker = attacker; + if (attacker.classname == "building_sentrygun") + realattacker = attacker.real_owner; + + if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) { - if (attacker.classname == "building_sentrygun") + if (realattacker.classname == "building_sentrygun") { - attacker = attacker.real_owner; + realattacker = attacker.real_owner; } - - if (attacker.team_no == target.team_no) + + if (realattacker.team_no == target.team_no) { - attacker.teamkills = attacker.teamkills + 1; + realattacker.teamkills = realattacker.teamkills + 1; } else { - attacker.kills = attacker.kills + 1; + realattacker.kills = realattacker.kills + 1; } } } From b6f593159e04fc1748cd46e0f203b8cf6767d4a9 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 7 Aug 2020 00:02:51 +1000 Subject: [PATCH 1048/2474] dmggiven and dmgtaken no longer includes self damage sg damage now counted for owner sg kills now counted for everyone damage from disp now counting for owner all numbers abreviated when 4 or more digits long damage and kills no longer counted in prematch team kills now tracked --- csqc/status.qc | 74 ++++++++++++++++++++++++++++++++++++++++++-------- ssqc/client.qc | 1 + ssqc/events.qc | 48 +++++++++++++++++--------------- ssqc/qw.qc | 2 +- 4 files changed, 90 insertions(+), 35 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 52036358..d8450a9d 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -356,6 +356,39 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { } } +float (float val) AbbreviateNumber = { + val = val / 1000; + val = rint(val); + return val; +}; + +string (float val) AbbreviateNumberToString = { + string abbr = ""; + + int count = 0; + while (val >= 1000) + { + val = AbbreviateNumber(val); + count++; + } + + switch (count) + { + case 1: + abbr = "k"; + break; + case 2: + abbr = "m"; + break; + case 3: + abbr = "b"; + break; + } + + string s = strcat(ftos(val), abbr); + return s; +}; + void (vector position, vector size, string val, vector textcolour, float alpha , float flags, string colname, optional float padright = FALSE) drawShowScoresColumnVal = { float valwidth, colwidth; @@ -372,6 +405,7 @@ void (vector position, vector size, string val, vector textcolour, float alpha sui_text(position, size, val, textcolour, 1, 0); }; + vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id , float padding, vector columnColour) drawShowScoresTeamPanel = { @@ -461,11 +495,11 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id } float col = 0, alpha = 1, flags = 0; - string val = ftos(lines[i].ping); + string val = AbbreviateNumberToString(lines[i].ping); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].pl); + val = AbbreviateNumberToString(lines[i].pl); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; @@ -490,7 +524,7 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { - val = ftos(lines[i].score); + val = AbbreviateNumberToString(lines[i].score); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); } position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; @@ -511,39 +545,39 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id continue; } - val = ftos(lines[i].caps); + val = AbbreviateNumberToString(lines[i].caps); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].touches); + val = AbbreviateNumberToString(lines[i].touches); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].kills); + val = AbbreviateNumberToString(lines[i].kills); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].teamkills); + val = AbbreviateNumberToString(lines[i].teamkills); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].deaths); + val = AbbreviateNumberToString(lines[i].deaths); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].afflicted); + val = AbbreviateNumberToString(lines[i].afflicted); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].teamafflicted); + val = AbbreviateNumberToString(lines[i].teamafflicted); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].damagegiven); + val = AbbreviateNumberToString(lines[i].damagegiven); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - val = ftos(lines[i].damagetaken); + val = AbbreviateNumberToString(lines[i].damagetaken); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; @@ -681,6 +715,22 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane sbCount++; } + + /* + // FIXME + maybe some colours on some columns to help differentiate them + cloudy and 32s gives credit for 2 caps...` + + Sometimes specs/observers seem to disappear, possibly after client disconnect that is on a team + If possible, have AFK/msg indicators + Reset between rounds + Make a summary one for end of game too + allow specs to see all classes of both teams + show who you are on scoreboard + show who you are speccing + when player comes in after caps occur, they aren't getting team score + */ + for (float i = 0; i < sbCount; i++) { sui_pop_frame(); diff --git a/ssqc/client.qc b/ssqc/client.qc index 181cdea3..ab3cbca4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1685,6 +1685,7 @@ void (entity player) UpdateScoreboardInfo = { CheckSetInfoKey(player, "damagegiven", player.damagegiven); CheckSetInfoKey(player, "damagetaken", player.damagetaken); CheckSetInfoKey(player, "kills", player.kills); + CheckSetInfoKey(player, "teamkills", player.sbteamkills); CheckSetInfoKey(player, "deaths", player.deaths); CheckSetInfoKey(player, "caps", player.caps); CheckSetInfoKey(player, "touches", player.touches); diff --git a/ssqc/events.qc b/ssqc/events.qc index 57e6a09b..2519ee8b 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -163,23 +163,32 @@ void (entity attacker, entity target, string afflictionType) LogAffliction = { } void (entity attacker, entity target, entity inflictor, float damage, float truedam) LogEventDamage = { - if (attacker) + if (!cb_prematch) { entity realattacker = attacker; - if (attacker.classname == "building_sentrygun") + if (attacker.classname == "building_sentrygun" || attacker.classname == "building_dispenser") + { realattacker = attacker.real_owner; + } - if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) + if (realattacker.team_no != target.team_no) { - realattacker.damagegiven = realattacker.damagegiven + truedam; + // superfluous + if (realattacker != target && realattacker != target.real_owner) + { + if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) + { + realattacker.damagegiven = realattacker.damagegiven + truedam; + } + + if (target.classname == "player") + { + target.damagetaken = target.damagetaken + truedam; + } + } } } - if (target.classname == "player") - { - target.damagetaken = target.damagetaken + truedam; - } - if (canlog == 0) return; @@ -260,34 +269,29 @@ void (entity attacker, entity target, entity inflictor, float damage, float true } void (entity attacker, entity target, entity inflictor) LogEventKill = { - if (attacker) + if (!cb_prematch) { + bprint(PRINT_HIGH, "logeventkill\n"); entity realattacker = attacker; - if (attacker.classname == "building_sentrygun") + if (attacker.classname == "building_sentrygun" || attacker.classname == "building_dispenser") + { realattacker = attacker.real_owner; + } if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) { - if (realattacker.classname == "building_sentrygun") - { - realattacker = attacker.real_owner; - } - if (realattacker.team_no == target.team_no) { - realattacker.teamkills = realattacker.teamkills + 1; + realattacker.sbteamkills = realattacker.sbteamkills + 1; } else { realattacker.kills = realattacker.kills + 1; } + + target.deaths = target.deaths + 1; } } - - if (target.classname == "player") - { - target.deaths = target.deaths + 1; - } if (canlog == 0) return; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9107b686..d9004047 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -692,7 +692,7 @@ float canlog; .float caps; .float touches; .float kills; -.float teamkills; +.float sbteamkills; .float deaths; .float afflicted; .float teamafflicted; From 8d3e2c50521f4d10c84ea735b52012abe1135cfb Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 7 Aug 2020 00:07:58 +1000 Subject: [PATCH 1049/2474] stop double counting caps --- ssqc/tfortmap.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 5f65f693..7f4c062b 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -769,7 +769,6 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { LogEventGoal(Player); TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count); TeamFortress_TeamShowScores(2); - Player.caps = Player.caps + 1; } } } From e624440c43713fec65f487ddf98e31a950ccd54c Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Fri, 7 Aug 2020 14:02:22 +1200 Subject: [PATCH 1050/2474] remove logeventkill broadcast --- ssqc/events.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/events.qc b/ssqc/events.qc index 2519ee8b..6953dd64 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -271,7 +271,6 @@ void (entity attacker, entity target, entity inflictor, float damage, float true void (entity attacker, entity target, entity inflictor) LogEventKill = { if (!cb_prematch) { - bprint(PRINT_HIGH, "logeventkill\n"); entity realattacker = attacker; if (attacker.classname == "building_sentrygun" || attacker.classname == "building_dispenser") { From e069e4f802a941b116f5d70862934b5ff24c27fe Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 8 Aug 2020 12:10:01 +1000 Subject: [PATCH 1051/2474] don't count self kills as team kills --- csqc/status.qc | 4 +--- ssqc/events.qc | 16 +++++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index d8450a9d..a78ce619 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -718,9 +718,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane /* // FIXME - maybe some colours on some columns to help differentiate them - cloudy and 32s gives credit for 2 caps...` - + maybe some colours on some columns to help differentiate them Sometimes specs/observers seem to disappear, possibly after client disconnect that is on a team If possible, have AFK/msg indicators Reset between rounds diff --git a/ssqc/events.qc b/ssqc/events.qc index 6953dd64..0e0c6434 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -173,7 +173,6 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (realattacker.team_no != target.team_no) { - // superfluous if (realattacker != target && realattacker != target.real_owner) { if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) @@ -279,13 +278,16 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) { - if (realattacker.team_no == target.team_no) - { - realattacker.sbteamkills = realattacker.sbteamkills + 1; - } - else + if (realattacker != target && realattacker != target.real_owner) { - realattacker.kills = realattacker.kills + 1; + if (realattacker.team_no == target.team_no) + { + realattacker.sbteamkills = realattacker.sbteamkills + 1; + } + else + { + realattacker.kills = realattacker.kills + 1; + } } target.deaths = target.deaths + 1; From 09fdd517a7c5faae852ee93c7f8bba0c0b4dbfd9 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 8 Aug 2020 12:52:03 +1000 Subject: [PATCH 1052/2474] fix specs disappearing on client drop allow specs to see classes of both teams --- csqc/csextradefs.qc | 1 + csqc/main.qc | 5 +++++ csqc/status.qc | 9 +++++++-- ssqc/client.qc | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 54f86070..fd24cb1d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -367,6 +367,7 @@ enum { float team_no; float is_spectator; float player_class; +float is_observer; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index 38a4ba1a..64742708 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -71,9 +71,14 @@ noref void() CSQC_WorldLoaded = { noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; team_no = getstatf(STAT_TEAMNO); + is_observer = FALSE; + if (team_no == 0) + is_observer = TRUE; player_class = getstatf(STAT_CLASS); SBAR.Ready = getstatf(STAT_READY); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); + if (is_spectator) + is_observer = FALSE; SBAR.Hint = ""; //stop grentimer on death diff --git a/csqc/status.qc b/csqc/status.qc index a78ce619..ad0a8db5 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -503,7 +503,8 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - if (team_no == lines[i].team_no || lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) + if (team_no == lines[i].team_no || lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER + || is_spectator || is_observer) { string c = lines[i].classtext; if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) @@ -629,6 +630,10 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane { FO_ScoreBoardLine sbl; sbl.ping = getplayerkeyfloat(i, INFOKEY_P_PING); + if (!sbl.ping) + { + continue; + } sbl.pl = getplayerkeyfloat(i, INFOKEY_P_PACKETLOSS); float class = getplayerkeyfloat(i, "playerclass"); sbl.classtext = ClassToString(class); @@ -723,10 +728,10 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane If possible, have AFK/msg indicators Reset between rounds Make a summary one for end of game too - allow specs to see all classes of both teams show who you are on scoreboard show who you are speccing when player comes in after caps occur, they aren't getting team score + */ for (float i = 0; i < sbCount; i++) diff --git a/ssqc/client.qc b/ssqc/client.qc index ab3cbca4..85b8fc35 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1674,6 +1674,7 @@ void (entity player, string field, float fieldval) CheckSetInfoKey = float val; val = infokeyf(player, field); + // TODO - this isn't needed on later versions of fte, we can spam set the value if (val != fieldval) forceinfokey(player, field, ftos(fieldval)); }; From 20f9558045a84f72c06a0fbd0000d961e12c8309 Mon Sep 17 00:00:00 2001 From: danni Date: Sat, 8 Aug 2020 12:52:32 +1000 Subject: [PATCH 1053/2474] update fixme list --- csqc/status.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/csqc/status.qc b/csqc/status.qc index ad0a8db5..7f2f07e1 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -724,7 +724,6 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane /* // FIXME maybe some colours on some columns to help differentiate them - Sometimes specs/observers seem to disappear, possibly after client disconnect that is on a team If possible, have AFK/msg indicators Reset between rounds Make a summary one for end of game too From b5d2967053b731783730e7ebaa35197b98f5c0c8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 9 Aug 2020 01:39:13 +1000 Subject: [PATCH 1054/2474] Make duel reset delay default consistent --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index f6069cd8..8b9be8b6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -647,7 +647,7 @@ void () DecodeLevelParms = { new_emp = CF_GetSetting("nemp", "new_emp", "1"); // For duelmode, how soon to reset the winning player (allows for double KOs) - duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "3"); + duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "3.9"); // remove packs in duelmode [1] duel_no_packs = CF_GetSetting("dnp", "duel_no_packs", "1"); // spawn with all possible grenades [0] From 32eca2564c41a74f8b1925430cd4f8bc2d68a202 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 9 Aug 2020 15:34:16 +1000 Subject: [PATCH 1055/2474] Fix silly merge conflict resolution --- csqc/events.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 02a738aa..0e0ea914 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -260,9 +260,6 @@ void() CSQC_Parse_Event = { case MSG_GRENTHROWN: grentimer_waiting = FALSE; break; - case MSG_GRENTHROWN: - grentimer_waiting = FALSE; - break; } } From 495b7968fb6a49ccf5752956d625b86db7a786ae Mon Sep 17 00:00:00 2001 From: danni Date: Mon, 10 Aug 2020 16:01:31 +1000 Subject: [PATCH 1056/2474] add spawnflags to suppress trigger_push sound, allow tfitem entities to be affected, ignore all other entities --- share/defs.h | 5 ++++ ssqc/triggers.qc | 60 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/share/defs.h b/share/defs.h index fc223627..8b789333 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1398,3 +1398,8 @@ #define DMN_FLASH 1 // when flashed, we set dimension see to this #define DMN_NOFLASH 256 // see all the things +// trigger_push +#define PUSH_ONCE 1 +#define PUSH_INCLUDETFITEM 2 +#define PUSH_EXCLUDEOTHER 4 // bad names, bad bits, bad coder +#define PUSH_NONOISE 8 \ No newline at end of file diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index a239e258..05135e19 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -502,8 +502,6 @@ void () trigger_hurt = { self.dmg = 5; }; -#define PUSH_ONCE 1 - void () trigger_push_touch = { local entity te; @@ -516,24 +514,42 @@ void () trigger_push_touch = { return; } - if (self.target) // this could test for movedir but i want to be explicit, it's a bounce pad + float push = FALSE; + if (other.classname == "item_tfgoal") { - if (other.classname == "grenade" || other.health > 0) + if (self.spawnflags & PUSH_INCLUDETFITEM) { - FO_Sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); - other.velocity = self.movedir; + push = TRUE; } } + else if (self.spawnflags & PUSH_EXCLUDEOTHER) + { + return; + } else { - if (other.classname == "grenade") - other.velocity = self.speed * self.movedir * 10; - else if (other.health > 0) { + if (other.classname == "grenade" || other.health > 0) + { + push = TRUE; + } + } + + if (push) + { + if (self.target) // this could test for movedir but i want to be explicit, it's a bounce pad + { + if (!(self.spawnflags & PUSH_NONOISE)) + FO_Sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); + other.velocity = self.movedir; + } + else + { other.velocity = self.speed * self.movedir * 10; if (other.classname == "player") { if (other.fly_sound < time) { other.fly_sound = time + 1.5; - FO_Sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); + if (!(self.spawnflags & PUSH_NONOISE)) + FO_Sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); } } } @@ -601,20 +617,24 @@ void () trigger_push = { self.speed = 1000; } - if (!self.noise) + if (!(self.spawnflags & PUSH_NONOISE)) { - if (self.target) + if (!self.noise) { - // bound pads - self.noise = "world/bouncepad.wav"; - } - else - { - self.noise = "ambience/windfly.wav"; + if (self.target) + { + // bound pads + self.noise = "world/bouncepad.wav"; + } + else + { + self.noise = "ambience/windfly.wav"; + } } - } - precache_sound(self.noise); + precache_sound(self.noise); + } + self.touch = trigger_push_touch; }; From e1afdc6dbb97c17de98bba3e7421f3860112d026 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 10 Aug 2020 16:58:31 +1000 Subject: [PATCH 1057/2474] Add team1score --- csqc/csextradefs.qc | 6 ++++-- csqc/events.qc | 3 +++ csqc/status.qc | 29 +++++++++++++++++++++++++++++ share/commondefs.qc | 1 + share/defs.h | 1 + ssqc/tfort.qc | 6 ++++++ 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index fd24cb1d..4946901c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -80,6 +80,7 @@ float round_over; float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown +float team1score; float jump_counter; float frames_since_onground; @@ -356,7 +357,8 @@ enum { HUD_PANEL_MENU_HINT, HUD_PANEL_GAME_MODE, HUD_PANEL_READY, - HUD_PANEL_SHOWSCORES + HUD_PANEL_SHOWSCORES, + HUD_PANEL_TEAM_SCORE }; #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" @@ -385,4 +387,4 @@ vector FO_Hud_Icon_Font_Size = [8, 8, 0]; string(string s) strtrim = #0:strtrim; /* Trims the whitespace from the start+end of the string. */ float(float playernum, string keyname, optional float assumevalue) getplayerkeyfloat = #0:getplayerkeyfloat; /* - Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ \ No newline at end of file + Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ diff --git a/csqc/events.qc b/csqc/events.qc index 02a738aa..423fbc15 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -263,6 +263,9 @@ void() CSQC_Parse_Event = { case MSG_GRENTHROWN: grentimer_waiting = FALSE; break; + case MSG_TEAM_ONE_SCORE: + team1score = readfloat(); + break; } } diff --git a/csqc/status.qc b/csqc/status.qc index 7f2f07e1..04738081 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -38,6 +38,7 @@ void(string panelid, float display, string text, string icon) drawSpecial = { Hud_DrawClassInfoPanel(panelid, SBAR.PlayerClass); } }; + void(string panelid, float display, string text, string icon) drawGrenTimerPanel = { local float timeleft; local float timercount = 0; @@ -753,6 +754,33 @@ void (float show) FO_Show_Scores = { panel.Display = show; }; +void(string panelid, float display, string text, string icon) drawTeamScorePanel = { + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + + vector position = getPosition(id); + vector size = getFillSize(id); + vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + local float padding = 4 * panel.Scale; + + local string message = ftos(getplayerkeyfloat(0, INFOKEY_P_FRAGS)); + + + drawstring( + position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y*2], + message, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); +}; + + var FO_Hud_Panel Hud_Panels[] = { {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, @@ -770,6 +798,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, + {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, }; float(string panelid) getHudPanel = { diff --git a/share/commondefs.qc b/share/commondefs.qc index 1a6a4a44..d439d0bc 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -26,6 +26,7 @@ #define MSG_PREMATCH 14 #define MSG_GRENTHROWN 15 #define MSG_ID 16 +#define MSG_TEAM_ONE_SCORE 17 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/share/defs.h b/share/defs.h index fc223627..42506c70 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1359,6 +1359,7 @@ #define FO_HUD_GAME_MODE_NAME "Game Mode" #define FO_HUD_READY_NAME "Ready Status" #define FO_HUD_SHOWSCORES_NAME "Show Scores" +#define FO_HUD_TEAM_SCORE_NAME "Team Score" #define ICON_CLIPSIZE "textures/wad/clipsize.png" diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 46fd4498..5802de50 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -3109,6 +3109,12 @@ void (entity pl, float fr) TF_AddFrags = { if (toggleflags & TFLAG_FULLTEAMSCORE) { e = find(world, classname, "player"); while (e) { + msg_entity = e; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_ONE_SCORE); + WriteFloat(MSG_MULTICAST, team1score); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); + if (e.team_no == pl.team_no) e.frags = TeamFortress_TeamGetScore(e.team_no); e = find(e, classname, "player"); From 999cf61b41f8a723832a80a98e6bbcdf8c1756c0 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 11 Aug 2020 12:22:25 +1000 Subject: [PATCH 1058/2474] include info_tfgoal --- ssqc/triggers.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 05135e19..ce62a02e 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -515,7 +515,7 @@ void () trigger_push_touch = { } float push = FALSE; - if (other.classname == "item_tfgoal") + if (other.classname == "item_tfgoal" || other.classname == "info_tfgoal") { if (self.spawnflags & PUSH_INCLUDETFITEM) { From bf90bd7fdb810feea3b6a7f71bd89b198cf63aea Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 11 Aug 2020 12:29:46 +1000 Subject: [PATCH 1059/2474] add broadcast without player name prepended to allow for things like "blue lasers are up" --- ssqc/qw.qc | 4 +++- ssqc/tfortmap.qc | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d9004047..cca1c976 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -703,4 +703,6 @@ float canlog; float FO_FlashDimension; // allow for default goal state -.float default_group_no; \ No newline at end of file +.float default_group_no; + +.string broadcast_high; \ No newline at end of file diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 7f4c062b..a0005d98 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1985,6 +1985,9 @@ void (entity Goal, entity AP, float addb) DoResults = { if ((Goal.broadcast != string_null) && (CTF_Map == 0)) { CenterPrint2(te, "\n\n\n", Goal.broadcast); } + if ((strtrim(Goal.broadcast_high) != "") && (CTF_Map == 0)) { + bprint(PRINT_HIGH, Goal.broadcast_high); + } if ((strtrim(Goal.netname_broadcast) != "") && (CTF_Map == 0)) { sprint(te, PRINT_HIGH, AP.netname, Goal.netname_broadcast); } From 2fb17571eb61e7dc3274a24312388a6424208a24 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 11 Aug 2020 12:31:54 +1000 Subject: [PATCH 1060/2474] update entity ref --- docs/tfentref.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/tfentref.txt b/docs/tfentref.txt index 71d9d518..cedfe919 100644 --- a/docs/tfentref.txt +++ b/docs/tfentref.txt @@ -374,6 +374,8 @@ return_item_no Return this GoalItem, if it's not being carried. broadcast Message centerprinted to everyone except the AP. e.g. "Clean-up on isle 4!" +broadcast_high Message printed high to everyone. + e.g. "Clean-up on isle 4!" message Message centerprinted to AP. e.g. "You activated this goal!" From 7cd693e35541b1c23b697ab9d04d272eeddb93c5 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 11 Aug 2020 12:33:00 +1000 Subject: [PATCH 1061/2474] another update to ent ref --- docs/tfentref.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/tfentref.txt b/docs/tfentref.txt index cedfe919..d2cef29a 100644 --- a/docs/tfentref.txt +++ b/docs/tfentref.txt @@ -843,6 +843,8 @@ netname_non_team_drop Broadcast to all members not in the team that own this i broadcast Message centerprinted to everyone except the AP. e.g. "Clean-up on isle 4!" +broadcast_high Message printed high to everyone. + e.g. "Clean-up on isle 4!" message Message centerprinted to AP. e.g. "You activated this goal!" From 6f554a4c9818eddafc307cc7f6ad102e275c1341 Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 11 Aug 2020 13:06:26 +1000 Subject: [PATCH 1062/2474] no glow spawnflag for goals that have a .mdl --- docs/tfentref.txt | 6 ++++++ share/defs.h | 3 +++ ssqc/tfortmap.qc | 3 +++ 3 files changed, 12 insertions(+) diff --git a/docs/tfentref.txt b/docs/tfentref.txt index d2cef29a..4b3fbb66 100644 --- a/docs/tfentref.txt +++ b/docs/tfentref.txt @@ -344,6 +344,9 @@ playerclass AP must be this playerclass to meet this Goal's criteria 7 : Only allow a Pyro to activate 8 : Only allow a Spy to activate 9 : Only allow an Engineer to activate + +spawnflags 1 : By default, when a GoalItem has a .mdl set, it will glow based on team_no. + This spawnflag will stop that glow. if_goal_is_active This Goal must be in ACTIVE state. if_goal_is_inactive This Goal must be in INACTIVE state. @@ -717,6 +720,9 @@ goal_effects Determines what players are affected. If nothing is spec in the group and then applies it's results invididually to any of them that pass. +spawnflags 1 : By default, when a GoalItem has a .mdl set, it will glow based on team_no. + This spawnflag will stop that glow. + maxammo_shells All members of this team are affected. maxammo_nails All members not of this team are affected. diff --git a/share/defs.h b/share/defs.h index 8b789333..41485f25 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1208,6 +1208,9 @@ #define TF_ILL_SPY 256 #define TF_ILL_ENGINEER 512 +// spawnflags +#define TFGI_NOGLOW 1 // stop the automatic glow applied in fortressone to goals with a .mdl set based on team + /*======================================================================*/ /* Flamethrower */ /*======================================================================*/ diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index a0005d98..61e827cd 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -258,6 +258,9 @@ float TF_Item_GetGlow(float team) void TF_Item_ApplyGlow() { + if (self.spawnflags & TFGI_NOGLOW) + return; + local entity tfdet; //info_tfdetect entity tfdet = find(world, classname, "info_tfdetect"); From d99d8eefc39201038767c72784f92ab3498cd5ea Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 13 Aug 2020 18:43:40 +1200 Subject: [PATCH 1063/2474] address most of the compile warnings --- csqc/hud.qc | 2 +- csqc/menu.qc | 34 +--------------------------------- csqc/status.qc | 4 ++-- ssqc/combat.qc | 2 +- ssqc/commands.qc | 2 +- ssqc/status.qc | 14 +++++++------- 6 files changed, 13 insertions(+), 45 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index d6c62734..f2464bbe 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -32,7 +32,7 @@ void Hud_WriteCfg(string path) // this overwrites float filehandle; filehandle = fopen(path, FILE_WRITE); - string line; + string line = ""; for(float i = 0; i < Hud_Panels.length; i++) { DrawPanel = Hud_Panels[i]; diff --git a/csqc/menu.qc b/csqc/menu.qc index e7baaa0c..33208b77 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -646,38 +646,6 @@ var fo_menu FO_MENU_VOTE = { } } }; -void fo_menu_start(vector position, vector size, string title, float flags) = { - InProgressMenu.position = position; - InProgressMenu.size = size; - InProgressMenu.title = title; - InProgressMenu.flags = flags; - InProgressMenu.active = 0; - //InProgressMenu.alpha = 0.6; - fo_menu_option fmo; - for(float i = 0; i < InProgressMenu.options.length; i++) { - InProgressMenu.options[i] = fmo; - } - InProgressMenu.num_opts = 0; -} - -void fo_menu_add_option(fo_menu_option option) { - if(InProgressMenu.num_opts < InProgressMenu.options.length) { - InProgressMenu.options[InProgressMenu.num_opts] = option; - InProgressMenu.num_opts++; - } else { - print("Ran out of room to add option #", ftos(InProgressMenu.num_opts), " to menu\n"); - } -} - -void fo_menu_add_option2(string shortcut, string name, string value, string description, float state, void() action) { - fo_menu_option option = {shortcut, name, value, description, state, action }; - if(InProgressMenu.num_opts < InProgressMenu.options.length) { - InProgressMenu.options[InProgressMenu.num_opts] = option; - InProgressMenu.num_opts++; - } else { - print("Ran out of room to add option #", ftos(InProgressMenu.num_opts), " to menu\n"); - } -} vector fo_menu_draw(fo_menu * menu) = { vector position; @@ -1240,7 +1208,7 @@ void FO_Menu_Special(float force) = { if(fo_hud_menu_active && force != 1) return; - fo_menu* NewMenu; + fo_menu* NewMenu = __NULL__; //void(float) nm; switch (SBAR.PlayerClass) { case PC_SCOUT: diff --git a/csqc/status.qc b/csqc/status.qc index 7f2f07e1..6a73a885 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -252,7 +252,7 @@ void(string panelid, float display, string text, string icon) drawGameModePanel local float padding = 4 * panel.Scale; local float transparency = 0.3; local float lines; - local string message; + local string message = ""; if (fo_hud_editor) { message = "Game Mode"; if (hud_panel(panelid, position, size, 0.3, panel.Display)) { @@ -317,7 +317,7 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { local float padding = 4 * panel.Scale; local float lines; local float pos_aligned; - local string message; + local string message = ""; if (fo_hud_editor) { message = "Ready Status"; if (hud_panel(panelid, position, size, 0.3, panel.Display)) { diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 1f9a2796..b19e8471 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -173,7 +173,7 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { if (hitsound == "1" || hitsound == "2") { - local float crit; + local float crit = 0; if((inflictor.weapon == DMSG_ROCKETL) && (damage >= 80)) { crit = 1; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index eb225b92..cbed266a 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -279,7 +279,7 @@ void (entity cap, float pick) CaptainPick = { } float (string arg1, string arg2, string arg3) ParseCmds = { - local float arg_num, processedCmd, inp; + local float arg_num = 0, processedCmd, inp; local string tmp; local float farg3; local entity ent, pl; diff --git a/ssqc/status.qc b/ssqc/status.qc index e6adafbb..b6265d02 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -998,16 +998,16 @@ void UpdateClientStatusBar(entity pl) void (entity pl) RefreshStatusBar = { local string pad; - local string s1; // will be used for grenade timers - local string s2; // class line - local string s3; // score & clip - local string ct; // class tip + local string s1 = ""; // will be used for grenade timers + local string s2 = ""; // class line + local string s3 = ""; // score & clip + local string ct = ""; // class tip local string st1, st2, st3, st4; // status bar columns 1-4 - local string ident; + local string ident = ""; local float height; local float i; local entity tfdet; //info_tfdetect entity - local entity te, tg; + local entity te = world, tg; local string bi; //button info local float csqcactive; //By default, show after tips; 0/off = off; 2 = always @@ -1311,7 +1311,7 @@ string(float num) GreenScoreToString = string(entity pl, float csqcactive) ClipSizeToString = { local string st = ""; - local float num, max; + local float num = 0, max; max = GetClipSize(pl); if (pl.current_weapon == WEAP_SHOTGUN) { From 141d0ba7de97468097675b296b204a8ce96f2e94 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 13 Aug 2020 20:22:49 +1200 Subject: [PATCH 1064/2474] fix fte menus not appearing when using 'disguise' or 'build' aliases --- csqc/main.qc | 12 ++++++++++++ csqc/menu.qc | 6 ++++-- ssqc/tforthlp.qc | 24 ++++++++++++++++++++---- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 64742708..b5f56fd2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -41,6 +41,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_admin"); registercommand("fo_menu_vote"); registercommand("fo_menu_special"); + registercommand("fo_menu_disguise"); + registercommand("fo_menu_build"); + registercommand("fo_menu_dropammo"); registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("primeone"); @@ -171,6 +174,15 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_special": FO_Menu_Special(TRUE); break; + case "fo_menu_disguise": + FO_Menu_Spy_Skin(TRUE); + break; + case "fo_menu_build": + FO_Menu_Build(TRUE); + break; + case "fo_menu_dropammo": + FO_Menu_DropAmmo(TRUE, 1, (player_class == PC_ENGINEER)); + break; case "primeone": if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { if(!grentimer_waiting) { diff --git a/csqc/menu.qc b/csqc/menu.qc index e7baaa0c..a5efdadc 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -1070,10 +1070,12 @@ void FO_Menu_Spy_Skin(float force) = { Menu_Cancel(); return; } - if(fo_hud_menu_active && force != 1) + if(fo_hud_menu_active && force != 1) { return; - if(!fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY_SKIN && force == 2) + } + if(!fo_hud_menu_active && CurrentMenu == &FO_MENU_SPY_SKIN && force == 2) { return; + } CurrentMenu = &FO_MENU_SPY_SKIN; fo_hud_menu_active = TRUE; } diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 29f911ac..e28d473f 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -68,7 +68,11 @@ void () TeamFortress_MOTD = { } //TeamFortress_Alias("menu", TF_CLASSMENU, 0); - TeamFortress_AliasString("menu", "cmd menu"); + if(csqcactive) { + TeamFortress_AliasString("menu", "fo_menu_special"); + } else { + TeamFortress_AliasString("menu", "cmd menu"); + } TeamFortress_Alias("slot1", TF_SLOT1, 0); TeamFortress_Alias("slot2", TF_SLOT2, 0); TeamFortress_Alias("slot3", TF_SLOT3, 0); @@ -140,7 +144,11 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); TeamFortress_Alias("togglevote", TF_TOGGLEVOTE, 0); TeamFortress_Alias("dropkey", TF_DROPKEY, 0); - TeamFortress_Alias("dropammo", TF_DROP_AMMO, 0); + if(csqcactive) { + TeamFortress_AliasString("dropammo", "fo_menu_dropammo"); + } else { + TeamFortress_Alias("dropammo", TF_DROP_AMMO, 0); + } TeamFortress_Alias("dropflag", TF_DROPFLAG, 0); TeamFortress_Alias("dropitems", TF_DROPFLAG, 0); TeamFortress_Alias("showloc", TF_DISPLAYLOCATION, 0); @@ -203,7 +211,11 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("unlock", TF_LOCKOFF, 0); TeamFortress_Alias("+lock", TF_LOCKON, 0); TeamFortress_Alias("-lock", TF_LOCKOFF, 0); - TeamFortress_Alias("disguise", TF_SPY_SPY, 0); + if(csqcactive) { + TeamFortress_AliasString("disguise", "fo_menu_disguise"); + } else { + TeamFortress_Alias("disguise", TF_SPY_SPY, 0); + } TeamFortress_Alias("feign", TF_SPY_DIE, 0); TeamFortress_Alias("sfeign", TF_SPY_SILENT_DIE, 0); } else if (self.motd == 110) { @@ -223,7 +235,11 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dgreen", TF_DISGUISE_GREEN, 0); TeamFortress_Alias("denemy", TF_DISGUISE_ENEMY, 0); TeamFortress_Alias("dlast", TF_DISGUISE_LAST, 0); - TeamFortress_Alias("build", TF_ENGINEER_BUILD, 0); + if(csqcactive) { + TeamFortress_AliasString("build", "fo_menu_build"); + } else { + TeamFortress_Alias("build", TF_ENGINEER_BUILD, 0); + } TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); } else if (self.motd == 130) { From 2219a3ba18ae3b499ca2a15f297a2c4403431e06 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 13 Aug 2020 23:06:42 +1000 Subject: [PATCH 1065/2474] Don't send qc stuff to non csqc clients --- csqc/csextradefs.qc | 10 ++++++- csqc/events.qc | 14 +++++++--- csqc/status.qc | 20 +++++++++++--- share/commondefs.qc | 3 +++ ssqc/tfort.qc | 6 ----- ssqc/tforttm.qc | 65 ++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 98 insertions(+), 20 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 4946901c..0870a2c0 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -80,7 +80,6 @@ float round_over; float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown -float team1score; float jump_counter; float frames_since_onground; @@ -270,6 +269,15 @@ typedef struct { FlagInfoLine FlagInfoLines[10]; +typedef struct { + float team1score; + float team2score; + float team3score; + float team4score; +} FO_TeamScores; + +FO_TeamScores TS; + // hud stuff typedef struct { string id; diff --git a/csqc/events.qc b/csqc/events.qc index 423fbc15..ee8c2a8d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -260,11 +260,17 @@ void() CSQC_Parse_Event = { case MSG_GRENTHROWN: grentimer_waiting = FALSE; break; - case MSG_GRENTHROWN: - grentimer_waiting = FALSE; - break; case MSG_TEAM_ONE_SCORE: - team1score = readfloat(); + TS.team1score = readfloat(); + break; + case MSG_TEAM_TWO_SCORE: + TS.team2score = readfloat(); + break; + case MSG_TEAM_THREE_SCORE: + TS.team3score = readfloat(); + break; + case MSG_TEAM_FOUR_SCORE: + TS.team4score = readfloat(); break; } } diff --git a/csqc/status.qc b/csqc/status.qc index 04738081..05328b02 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -766,9 +766,23 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel vector size = getFillSize(id); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; - - local string message = ftos(getplayerkeyfloat(0, INFOKEY_P_FRAGS)); - + local string message = strcat(ftos(TS.team1score), " - ", ftos(TS.team2score)); + + /* drawfill( */ + /* position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y*2], */ + /* mediumtext, */ + /* '0 0 255', */ + /* 1, */ + /* 0 */ + /* ); */ + + /* drawfill( */ + /* position + [size.x / 2,padding*2 + mediumtext.y*2], */ + /* mediumtext, */ + /* '255 0 0', */ + /* 1, */ + /* 0 */ + /* ); */ drawstring( position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y*2], diff --git a/share/commondefs.qc b/share/commondefs.qc index d439d0bc..b34b8eb1 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -27,6 +27,9 @@ #define MSG_GRENTHROWN 15 #define MSG_ID 16 #define MSG_TEAM_ONE_SCORE 17 +#define MSG_TEAM_TWO_SCORE 18 +#define MSG_TEAM_THREE_SCORE 19 +#define MSG_TEAM_FOUR_SCORE 20 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 5802de50..46fd4498 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -3109,12 +3109,6 @@ void (entity pl, float fr) TF_AddFrags = { if (toggleflags & TFLAG_FULLTEAMSCORE) { e = find(world, classname, "player"); while (e) { - msg_entity = e; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_ONE_SCORE); - WriteFloat(MSG_MULTICAST, team1score); - multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); - if (e.team_no == pl.team_no) e.frags = TeamFortress_TeamGetScore(e.team_no); e = find(e, classname, "player"); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index fe17191b..69a2bc14 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -358,23 +358,76 @@ void () TeamFortress_CheckTeamCheats = { void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore = { local entity e; + local entity pl; - if ((tno == 0) || (scoretoadd == 0)) + if ((tno == 0) || (scoretoadd == 0)) { return; + } - if (tno == 1) + if (tno == 1) { team1score = team1score + scoretoadd; - if (tno == 2) + pl = find(world, classname, "player"); + while (pl) { + if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_ONE_SCORE); + WriteFloat(MSG_MULTICAST, team1score); + multicast('0 0 0', MULTICAST_ONE_R); + } + pl = find(pl, classname, "player"); + } + } + if (tno == 2) { team2score = team2score + scoretoadd; - if (tno == 3) + pl = find(world, classname, "player"); + while (pl) { + if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_TWO_SCORE); + WriteFloat(MSG_MULTICAST, team2score); + multicast('0 0 0', MULTICAST_ONE_R); + } + pl = find(pl, classname, "player"); + } + } + + if (tno == 3) { team3score = team3score + scoretoadd; - if (tno == 4) + pl = find(world, classname, "player"); + while (pl) { + if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_THREE_SCORE); + WriteFloat(MSG_MULTICAST, team3score); + multicast('0 0 0', MULTICAST_ONE_R); + } + pl = find(pl, classname, "player"); + } + } + + if (tno == 4) { team4score = team4score + scoretoadd; - if ((toggleflags & TFLAG_TEAMFRAGS) || (toggleflags & 2048)) { + pl = find(world, classname, "player"); + while (pl) { + if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_FOUR_SCORE); + WriteFloat(MSG_MULTICAST, team4score); + multicast('0 0 0', MULTICAST_ONE_R); + } + pl = find(pl, classname, "player"); + } + } + + if ((toggleflags & TFLAG_TEAMFRAGS) || (toggleflags & TFLAG_FULLTEAMSCORE)) { e = find(world, classname, "player"); while (e) { if (e.team_no == tno) From c2616fa65320f8566e9629364e8c1fff9f62ff8d Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 13 Aug 2020 23:17:32 +1000 Subject: [PATCH 1066/2474] broadcast_high only once... --- ssqc/tfortmap.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 61e827cd..df95356b 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1983,14 +1983,15 @@ void (entity Goal, entity AP, float addb) DoResults = { } } gotone = 0; + if ((strtrim(Goal.broadcast_high) != "") && (CTF_Map == 0)) { + bprint(PRINT_HIGH, Goal.broadcast_high); + } te = find(world, classname, "player"); while (te != world) { if ((Goal.broadcast != string_null) && (CTF_Map == 0)) { CenterPrint2(te, "\n\n\n", Goal.broadcast); } - if ((strtrim(Goal.broadcast_high) != "") && (CTF_Map == 0)) { - bprint(PRINT_HIGH, Goal.broadcast_high); - } + if ((strtrim(Goal.netname_broadcast) != "") && (CTF_Map == 0)) { sprint(te, PRINT_HIGH, AP.netname, Goal.netname_broadcast); } From d3bc0b5b5d4466992720843f071c3e6224700d41 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 14 Aug 2020 00:27:38 +1000 Subject: [PATCH 1067/2474] Write scores on join --- ssqc/client.qc | 1 + ssqc/csmenu.qc | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index b73bdc11..d06b86ce 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2694,6 +2694,7 @@ void (optional float csqcactive) ClientConnect = { if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { InitAllStatuses(self); UpdateClientMOTD(self); + UpdateClientTeamScores(self); //if(quadmode) UpdateClientPrematch(self, !cb_prematch); } diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index c66f8812..7977094b 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -254,7 +254,33 @@ void UpdateClientMOTD(entity pl) = { )); WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); WriteFloat(MSG_MULTICAST, number_of_teams); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientTeamScores(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_ONE_SCORE); + WriteFloat(MSG_MULTICAST, team1score); + multicast('0 0 0', MULTICAST_ONE_R); + + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_TWO_SCORE); + WriteFloat(MSG_MULTICAST, team2score); + multicast('0 0 0', MULTICAST_ONE_R); + + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_THREE_SCORE); + WriteFloat(MSG_MULTICAST, team3score); + multicast('0 0 0', MULTICAST_ONE_R); + + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TEAM_FOUR_SCORE); + WriteFloat(MSG_MULTICAST, team4score); + multicast('0 0 0', MULTICAST_ONE_R); } void UpdateClientPrematch(entity pl, float countdownstarted) = { From b27480636f58ae40a0a8d828882d78a07c27adf1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 14 Aug 2020 00:43:28 +1000 Subject: [PATCH 1068/2474] Refactor --- ssqc/tforttm.qc | 61 ++++++++----------------------------------------- 1 file changed, 9 insertions(+), 52 deletions(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 69a2bc14..3c97cac5 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -360,71 +360,28 @@ void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore = { local entity e; local entity pl; - if ((tno == 0) || (scoretoadd == 0)) { + if ((tno == 0) || (scoretoadd == 0)) return; - } - if (tno == 1) { + if (tno == 1) team1score = team1score + scoretoadd; - - pl = find(world, classname, "player"); - while (pl) { - if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_ONE_SCORE); - WriteFloat(MSG_MULTICAST, team1score); - multicast('0 0 0', MULTICAST_ONE_R); - } - pl = find(pl, classname, "player"); - } - } - if (tno == 2) { + + if (tno == 2) team2score = team2score + scoretoadd; - pl = find(world, classname, "player"); - while (pl) { - if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_TWO_SCORE); - WriteFloat(MSG_MULTICAST, team2score); - multicast('0 0 0', MULTICAST_ONE_R); - } - pl = find(pl, classname, "player"); - } - } - - if (tno == 3) { + if (tno == 3) team3score = team3score + scoretoadd; - pl = find(world, classname, "player"); - while (pl) { - if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_THREE_SCORE); - WriteFloat(MSG_MULTICAST, team3score); - multicast('0 0 0', MULTICAST_ONE_R); - } - pl = find(pl, classname, "player"); - } - } - - if (tno == 4) { + if (tno == 4) team4score = team4score + scoretoadd; + if ((tno == 1) || (tno == 2) || (tno == 3) || (tno == 4)) { pl = find(world, classname, "player"); while (pl) { - if (infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_FOUR_SCORE); - WriteFloat(MSG_MULTICAST, team4score); - multicast('0 0 0', MULTICAST_ONE_R); - } + UpdateClientTeamScores(pl); pl = find(pl, classname, "player"); } + } if ((toggleflags & TFLAG_TEAMFRAGS) || (toggleflags & TFLAG_FULLTEAMSCORE)) { From a1cbb3893cbb2d0590fd03398c295263badf546c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 14 Aug 2020 00:52:06 +1000 Subject: [PATCH 1069/2474] Refactor --- csqc/events.qc | 8 +------- share/commondefs.qc | 5 +---- ssqc/csmenu.qc | 14 +------------- 3 files changed, 3 insertions(+), 24 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index ee8c2a8d..727fdb65 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -260,16 +260,10 @@ void() CSQC_Parse_Event = { case MSG_GRENTHROWN: grentimer_waiting = FALSE; break; - case MSG_TEAM_ONE_SCORE: + case MSG_TEAM_SCORES: TS.team1score = readfloat(); - break; - case MSG_TEAM_TWO_SCORE: TS.team2score = readfloat(); - break; - case MSG_TEAM_THREE_SCORE: TS.team3score = readfloat(); - break; - case MSG_TEAM_FOUR_SCORE: TS.team4score = readfloat(); break; } diff --git a/share/commondefs.qc b/share/commondefs.qc index b34b8eb1..dce9116d 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -26,10 +26,7 @@ #define MSG_PREMATCH 14 #define MSG_GRENTHROWN 15 #define MSG_ID 16 -#define MSG_TEAM_ONE_SCORE 17 -#define MSG_TEAM_TWO_SCORE 18 -#define MSG_TEAM_THREE_SCORE 19 -#define MSG_TEAM_FOUR_SCORE 20 +#define MSG_TEAM_SCORES 17 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 7977094b..f9ff688b 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -263,22 +263,10 @@ void UpdateClientTeamScores(entity pl) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_ONE_SCORE); + WriteByte(MSG_MULTICAST, MSG_TEAM_SCORES); WriteFloat(MSG_MULTICAST, team1score); - multicast('0 0 0', MULTICAST_ONE_R); - - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_TWO_SCORE); WriteFloat(MSG_MULTICAST, team2score); - multicast('0 0 0', MULTICAST_ONE_R); - - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_THREE_SCORE); WriteFloat(MSG_MULTICAST, team3score); - multicast('0 0 0', MULTICAST_ONE_R); - - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TEAM_FOUR_SCORE); WriteFloat(MSG_MULTICAST, team4score); multicast('0 0 0', MULTICAST_ONE_R); } From 647643255b88f72041b7b68664cf5e3e7958b259 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 14 Aug 2020 00:58:50 +1000 Subject: [PATCH 1070/2474] Remove whitespace --- ssqc/tforttm.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 3c97cac5..81864e5d 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -381,7 +381,6 @@ void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore = { UpdateClientTeamScores(pl); pl = find(pl, classname, "player"); } - } if ((toggleflags & TFLAG_TEAMFRAGS) || (toggleflags & TFLAG_FULLTEAMSCORE)) { From 8d450504bcd65af7a0229b902641c4f9e6377b77 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 14 Aug 2020 02:13:00 +1000 Subject: [PATCH 1071/2474] Track if anyone has joined a team (and scored) --- csqc/csextradefs.qc | 4 ++++ csqc/events.qc | 4 ++++ csqc/status.qc | 12 +++++++++++- ssqc/client.qc | 7 +++++++ ssqc/commands.qc | 14 ++++++++++++++ ssqc/csmenu.qc | 4 ++++ ssqc/tforttm.qc | 11 ++++++++++- 7 files changed, 54 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 0870a2c0..f77f27b5 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -270,6 +270,10 @@ typedef struct { FlagInfoLine FlagInfoLines[10]; typedef struct { + float team1nump; + float team2nump; + float team3nump; + float team4nump; float team1score; float team2score; float team3score; diff --git a/csqc/events.qc b/csqc/events.qc index 727fdb65..4ab7e3ed 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -261,6 +261,10 @@ void() CSQC_Parse_Event = { grentimer_waiting = FALSE; break; case MSG_TEAM_SCORES: + TS.team1nump = readfloat(); + TS.team2nump = readfloat(); + TS.team3nump = readfloat(); + TS.team4nump = readfloat(); TS.team1score = readfloat(); TS.team2score = readfloat(); TS.team3score = readfloat(); diff --git a/csqc/status.qc b/csqc/status.qc index 05328b02..c0b61150 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -766,7 +766,17 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel vector size = getFillSize(id); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; - local string message = strcat(ftos(TS.team1score), " - ", ftos(TS.team2score)); + + local string message = ""; + + if (TS.team1nump || TS.team1score) + message = strcat(message, ftos(TS.team1score), " "); + if (TS.team2nump || TS.team2score) + message = strcat(message, ftos(TS.team2score), " "); + if (TS.team3nump || TS.team3score) + message = strcat(message, ftos(TS.team3score), " "); + if (TS.team4nump || TS.team4score) + message = strcat(message, ftos(TS.team4score)); /* drawfill( */ /* position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y*2], */ diff --git a/ssqc/client.qc b/ssqc/client.qc index d06b86ce..d36a5d14 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2659,6 +2659,13 @@ void (optional float csqcactive) ClientConnect = { if (te.tf_id == self.tf_id) { got_one = 1; TeamFortress_TeamSet_Options(self, te.team_no, TRUE); + + local entity pl = find(world, classname, "player"); + while (pl) { + UpdateClientTeamScores(pl); + pl = find(pl, classname, "player"); + } + self.frags = te.frags; self.real_frags = te.real_frags; if (!(toggleflags & TFLAG_TEAMFRAGS) && diff --git a/ssqc/commands.qc b/ssqc/commands.qc index eb225b92..26c6a0ed 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -151,6 +151,13 @@ void (float cap1, float cap2) CaptainMode = { te.team_no = 1; SetTeamName(te); TeamFortress_TeamSet_Options(te, 1, TRUE); + + local entity pl = find(world, classname, "player"); + while (pl) { + UpdateClientTeamScores(pl); + pl = find(pl, classname, "player"); + } + //stuffcmd(self, "color "); //st = ftos(TeamFortress_TeamGetColor (1) - 1); //stuffcmd(self, st); @@ -162,6 +169,13 @@ void (float cap1, float cap2) CaptainMode = { te.team_no = 2; SetTeamName(te); TeamFortress_TeamSet_Options(te, 2, TRUE); + + local entity pl2 = find(world, classname, "player"); + while (pl2) { + UpdateClientTeamScores(pl2); + pl2 = find(pl, classname, "player"); + } + //stuffcmd(self, "color "); //st = ftos(TeamFortress_TeamGetColor (2) - 1); //stuffcmd(self, st); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index f9ff688b..fbf281c9 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -264,6 +264,10 @@ void UpdateClientTeamScores(entity pl) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_TEAM_SCORES); + WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(1)); + WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(2)); + WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(3)); + WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(4)); WriteFloat(MSG_MULTICAST, team1score); WriteFloat(MSG_MULTICAST, team2score); WriteFloat(MSG_MULTICAST, team3score); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 81864e5d..fa048202 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -240,6 +240,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options st = ftos(tc); stuffcmd(pe, st); stuffcmd(pe, "\n"); + if(!skipclasscheck) { if(pe.playerclass == PC_CIVILIAN) { if (TeamFortress_TeamIsCivilian(tno)) { @@ -291,7 +292,15 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options }; float (float tno) TeamFortress_TeamSet = { - return TeamFortress_TeamSet_Options(self, tno, FALSE); + local float tftso = TeamFortress_TeamSet_Options(self, tno, FALSE); + + local entity pl = find(world, classname, "player"); + while (pl) { + UpdateClientTeamScores(pl); + pl = find(pl, classname, "player"); + } + + return (tftso); } void () TeamFortress_CheckTeamCheats = { From 3c889752d8126071936def87f98eca2580e484f2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 14 Aug 2020 02:15:43 +1000 Subject: [PATCH 1072/2474] Whitespace --- ssqc/tforttm.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index fa048202..b3442003 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -374,7 +374,7 @@ void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore = { if (tno == 1) team1score = team1score + scoretoadd; - + if (tno == 2) team2score = team2score + scoretoadd; From 5dc7afb89945a72d3835743075491a2fef739df2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 14 Aug 2020 02:25:02 +1000 Subject: [PATCH 1073/2474] Refactor --- ssqc/client.qc | 15 +++++++++------ ssqc/commands.qc | 14 ++------------ ssqc/tforttm.qc | 15 ++------------- 3 files changed, 13 insertions(+), 31 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index d36a5d14..4031ea74 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2606,6 +2606,14 @@ void () PlayerPostThink = { } }; +void () UpdateAllClientsTeamScores = { + local entity pl = find(world, classname, "player"); + while (pl) { + UpdateClientTeamScores(pl); + pl = find(pl, classname, "player"); + } +} + //do not rely on csqcactive - it may misbehave when using `join` from spectator void (optional float csqcactive) ClientConnect = { local entity te; @@ -2659,12 +2667,7 @@ void (optional float csqcactive) ClientConnect = { if (te.tf_id == self.tf_id) { got_one = 1; TeamFortress_TeamSet_Options(self, te.team_no, TRUE); - - local entity pl = find(world, classname, "player"); - while (pl) { - UpdateClientTeamScores(pl); - pl = find(pl, classname, "player"); - } + UpdateAllClientsTeamScores(); self.frags = te.frags; self.real_frags = te.real_frags; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 26c6a0ed..fd4539e8 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -151,12 +151,7 @@ void (float cap1, float cap2) CaptainMode = { te.team_no = 1; SetTeamName(te); TeamFortress_TeamSet_Options(te, 1, TRUE); - - local entity pl = find(world, classname, "player"); - while (pl) { - UpdateClientTeamScores(pl); - pl = find(pl, classname, "player"); - } + UpdateAllClientsTeamScores(); //stuffcmd(self, "color "); //st = ftos(TeamFortress_TeamGetColor (1) - 1); @@ -169,12 +164,7 @@ void (float cap1, float cap2) CaptainMode = { te.team_no = 2; SetTeamName(te); TeamFortress_TeamSet_Options(te, 2, TRUE); - - local entity pl2 = find(world, classname, "player"); - while (pl2) { - UpdateClientTeamScores(pl2); - pl2 = find(pl, classname, "player"); - } + UpdateAllClientsTeamScores(); //stuffcmd(self, "color "); //st = ftos(TeamFortress_TeamGetColor (2) - 1); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index b3442003..300a75b1 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -293,13 +293,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options float (float tno) TeamFortress_TeamSet = { local float tftso = TeamFortress_TeamSet_Options(self, tno, FALSE); - - local entity pl = find(world, classname, "player"); - while (pl) { - UpdateClientTeamScores(pl); - pl = find(pl, classname, "player"); - } - + UpdateAllClientsTeamScores(); return (tftso); } @@ -367,7 +361,6 @@ void () TeamFortress_CheckTeamCheats = { void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore = { local entity e; - local entity pl; if ((tno == 0) || (scoretoadd == 0)) return; @@ -385,11 +378,7 @@ void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore = { team4score = team4score + scoretoadd; if ((tno == 1) || (tno == 2) || (tno == 3) || (tno == 4)) { - pl = find(world, classname, "player"); - while (pl) { - UpdateClientTeamScores(pl); - pl = find(pl, classname, "player"); - } + UpdateAllClientsTeamScores(); } if ((toggleflags & TFLAG_TEAMFRAGS) || (toggleflags & TFLAG_FULLTEAMSCORE)) { From 82e91e97c68c7ff5efd9072b3130e1a453cd121d Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 14 Aug 2020 22:23:35 +1000 Subject: [PATCH 1074/2474] fix csqc msg breaking ezquake --- ssqc/csmenu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index fbf281c9..a265734f 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -272,7 +272,7 @@ void UpdateClientTeamScores(entity pl) = { WriteFloat(MSG_MULTICAST, team2score); WriteFloat(MSG_MULTICAST, team3score); WriteFloat(MSG_MULTICAST, team4score); - multicast('0 0 0', MULTICAST_ONE_R); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } void UpdateClientPrematch(entity pl, float countdownstarted) = { From 67266d3ddb5f3bc44e9fcb7b65be69eeb322e993 Mon Sep 17 00:00:00 2001 From: danni Date: Fri, 14 Aug 2020 22:23:35 +1000 Subject: [PATCH 1075/2474] fix csqc msg breaking ezquake --- ssqc/csmenu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index fbf281c9..a265734f 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -272,7 +272,7 @@ void UpdateClientTeamScores(entity pl) = { WriteFloat(MSG_MULTICAST, team2score); WriteFloat(MSG_MULTICAST, team3score); WriteFloat(MSG_MULTICAST, team4score); - multicast('0 0 0', MULTICAST_ONE_R); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } void UpdateClientPrematch(entity pl, float countdownstarted) = { From 506faadbb0b3eacefa323c887dca23300b3048b6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 15 Aug 2020 01:32:34 +1000 Subject: [PATCH 1076/2474] Use number_of_teams instead --- csqc/csextradefs.qc | 4 ---- csqc/events.qc | 4 ---- csqc/status.qc | 19 +++++++++++-------- ssqc/csmenu.qc | 4 ---- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f77f27b5..0870a2c0 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -270,10 +270,6 @@ typedef struct { FlagInfoLine FlagInfoLines[10]; typedef struct { - float team1nump; - float team2nump; - float team3nump; - float team4nump; float team1score; float team2score; float team3score; diff --git a/csqc/events.qc b/csqc/events.qc index 4ab7e3ed..727fdb65 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -261,10 +261,6 @@ void() CSQC_Parse_Event = { grentimer_waiting = FALSE; break; case MSG_TEAM_SCORES: - TS.team1nump = readfloat(); - TS.team2nump = readfloat(); - TS.team3nump = readfloat(); - TS.team4nump = readfloat(); TS.team1score = readfloat(); TS.team2score = readfloat(); TS.team3score = readfloat(); diff --git a/csqc/status.qc b/csqc/status.qc index c0b61150..3a90d461 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -769,14 +769,17 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel local string message = ""; - if (TS.team1nump || TS.team1score) - message = strcat(message, ftos(TS.team1score), " "); - if (TS.team2nump || TS.team2score) - message = strcat(message, ftos(TS.team2score), " "); - if (TS.team3nump || TS.team3score) - message = strcat(message, ftos(TS.team3score), " "); - if (TS.team4nump || TS.team4score) - message = strcat(message, ftos(TS.team4score)); + if (number_of_teams >= 1) + message = strcat(message, ftos(TS.team1score), " "); + + if (number_of_teams >= 2) + message = strcat(message, ftos(TS.team2score), " "); + + if (number_of_teams >= 3) + message = strcat(message, ftos(TS.team3score), " "); + + if (number_of_teams >= 4) + message = strcat(message, ftos(TS.team4score)); /* drawfill( */ /* position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y*2], */ diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index a265734f..fa4b474c 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -264,10 +264,6 @@ void UpdateClientTeamScores(entity pl) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_TEAM_SCORES); - WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(1)); - WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(2)); - WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(3)); - WriteFloat(MSG_MULTICAST, TeamFortress_TeamGetNoPlayers(4)); WriteFloat(MSG_MULTICAST, team1score); WriteFloat(MSG_MULTICAST, team2score); WriteFloat(MSG_MULTICAST, team3score); From 5144a0de3aacb74739aa0b5073efb35667b8eb1d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Aug 2020 00:08:56 +1000 Subject: [PATCH 1077/2474] Basic scoreboard colours --- csqc/status.qc | 51 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 3a90d461..40862ec9 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -767,27 +767,44 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; - local string message = ""; + local vector fillsize = mediumtext; + fillsize_x = fillsize_x * 3; - if (number_of_teams >= 1) - message = strcat(message, ftos(TS.team1score), " "); + local float offset; + local vector score_position; + local string message = ""; - if (number_of_teams >= 2) - message = strcat(message, ftos(TS.team2score), " "); + if (number_of_teams >= 1) { + score_position = position; + offset = fillsize_x * 0; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team1score))); + drawfill(score_position, fillsize, '0 0 255', 0.5, 0); + } - if (number_of_teams >= 3) - message = strcat(message, ftos(TS.team3score), " "); + if (number_of_teams >= 2) { + score_position = position; + offset = fillsize_x * 1; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team2score))); + drawfill(score_position, fillsize, '255 0 0', 0.5, 0); + } - if (number_of_teams >= 4) - message = strcat(message, ftos(TS.team4score)); + if (number_of_teams >= 3) { + score_position = position; + offset = fillsize_x * 2; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team3score))); + drawfill(score_position, fillsize, '255 255 0', 0.5, 0); + } - /* drawfill( */ - /* position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y*2], */ - /* mediumtext, */ - /* '0 0 255', */ - /* 1, */ - /* 0 */ - /* ); */ + if (number_of_teams >= 4) { + score_position = position; + offset = fillsize_x * 3; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team4score))); + drawfill(score_position, fillsize, '0 255 0', 0.5, 0); + } /* drawfill( */ /* position + [size.x / 2,padding*2 + mediumtext.y*2], */ @@ -798,7 +815,7 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel /* ); */ drawstring( - position + [size.x / 2 - stringwidth(message,1,mediumtext)/2,padding*2 + mediumtext.y*2], + position, message, mediumtext, MENU_TEXT_1, From 7502cc1c9cd195f8945434d729edc8427a76478a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Aug 2020 00:56:27 +1000 Subject: [PATCH 1078/2474] Consistent colour --- csqc/status.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 40862ec9..fad91c84 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -779,7 +779,7 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel offset = fillsize_x * 0; score_position_x = score_position_x + offset; message = strcat(message, strpad(-3, ftos(TS.team1score))); - drawfill(score_position, fillsize, '0 0 255', 0.5, 0); + drawfill(score_position, fillsize, '0.3 0.4 0.7', 0.5, 0); } if (number_of_teams >= 2) { @@ -787,7 +787,7 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel offset = fillsize_x * 1; score_position_x = score_position_x + offset; message = strcat(message, strpad(-3, ftos(TS.team2score))); - drawfill(score_position, fillsize, '255 0 0', 0.5, 0); + drawfill(score_position, fillsize, '0.7 0.4 0.3', 0.5, 0); } if (number_of_teams >= 3) { @@ -795,7 +795,7 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel offset = fillsize_x * 2; score_position_x = score_position_x + offset; message = strcat(message, strpad(-3, ftos(TS.team3score))); - drawfill(score_position, fillsize, '255 255 0', 0.5, 0); + drawfill(score_position, fillsize, '0.7 0.7 0.3', 0.5, 0); } if (number_of_teams >= 4) { @@ -803,7 +803,7 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel offset = fillsize_x * 3; score_position_x = score_position_x + offset; message = strcat(message, strpad(-3, ftos(TS.team4score))); - drawfill(score_position, fillsize, '0 255 0', 0.5, 0); + drawfill(score_position, fillsize, '0.4 0.7 0.3', 0.5, 0); } /* drawfill( */ From 6bfa3cca688678075b9b3de6beaaa32be581d446 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 16 Aug 2020 10:53:32 +1200 Subject: [PATCH 1079/2474] Add a list to manually select hud editor panels in case of them being covered up --- csqc/csextradefs.qc | 11 ++++-- csqc/hud.qc | 94 ++++++++++++++++++++++++++++++++++++--------- csqc/hud_helpers.qc | 12 +++--- csqc/status.qc | 15 +++++--- 4 files changed, 98 insertions(+), 34 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index fd24cb1d..e96976d4 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -122,7 +122,7 @@ typedef struct string icon; } FO_Hud_Icons; FO_Hud_Icons HudIcons[29] = { - {""}, +// {""}, {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, @@ -278,9 +278,12 @@ typedef struct { float Scale; float TextScale; float Display; - float NodeInsertLoc; + float Orientation; void(string panelid, float display, string text, string icon) drawPanel; string() getValue; + FO_Hud_Icons * Icon; + float Snap; + float Status; } FO_Hud_Panel; FO_Hud_Panel DrawPanel; @@ -341,7 +344,6 @@ string FO_ScoreBoardColumns[] = { }; enum { - HUD_PANEL_HUDOPTIONS, HUD_PANEL_CLIPSIZE, HUD_PANEL_FRAGSTREAK, HUD_PANEL_CAPS, @@ -356,7 +358,8 @@ enum { HUD_PANEL_MENU_HINT, HUD_PANEL_GAME_MODE, HUD_PANEL_READY, - HUD_PANEL_SHOWSCORES + HUD_PANEL_SHOWSCORES, + HUD_PANEL_HUDOPTIONS, }; #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" diff --git a/csqc/hud.qc b/csqc/hud.qc index d6c62734..684a7461 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -56,11 +56,11 @@ void FO_Hud_Editor_LoadDefaultSettings() // TODO - maybe implement these to allow for pivoting of items /* vector pos, fill; - float scale, display, nodeInsertLoc; + float scale, display, Orientation; pos = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; scale = 1; display = 1; - nodeInsertLoc = FO_HUD_INSERT_BEFORE; + Orientation = FO_HUD_INSERT_BEFORE; fill = [FO_HUD_CLIPSIZE_PANEL_X, FO_HUD_CLIPSIZE_PANEL_Y]; for(float i = 0; i < Hud_Panels.length; i++) { @@ -69,18 +69,18 @@ void FO_Hud_Editor_LoadDefaultSettings() //Hud_Panels[i].FillSize = fillSize; Hud_Panels[i].Scale = scale; Hud_Panels[i].Display = display; - Hud_Panels[i].NodeInsertLoc = nodeInsertLoc; + Hud_Panels[i].Orientation = Orientation; //pnl.Name = name; } */ //Default menus, id, ready and MOTD to centre of the screen Hud_Panels[HUD_PANEL_GAME_MODE].Position = [width - Hud_Panels[HUD_PANEL_GAME_MODE].FillSize.x, 30]; - Hud_Panels[HUD_PANEL_GAME_MODE].NodeInsertLoc = FO_HUD_INSERT_AFTER; + Hud_Panels[HUD_PANEL_GAME_MODE].Orientation = FO_HUD_INSERT_AFTER; Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 30]; Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 30]; Hud_Panels[HUD_PANEL_MENU_HINT].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), 80]; - Hud_Panels[HUD_PANEL_MENU_HINT].NodeInsertLoc = FO_HUD_INSERT_MIDDLE; + Hud_Panels[HUD_PANEL_MENU_HINT].Orientation = FO_HUD_INSERT_MIDDLE; Hud_Panels[HUD_PANEL_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), 120]; Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height - 100]; Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) + 16, height - 50]; @@ -91,7 +91,7 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_GREN2].Scale = 0.75; Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, (height / 2) + 32]; Hud_Panels[HUD_PANEL_GRENTIMER].Scale = 0.75; - Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc = FO_HUD_INSERT_AFTER; + Hud_Panels[HUD_PANEL_FLAGINFO].Orientation = FO_HUD_INSERT_AFTER; Hud_Panels[HUD_PANEL_FLAGINFO].Position = [width - 24, (height / 2) - 8]; Hud_Panels[HUD_PANEL_FRAGSTREAK].Display = 0; Hud_Panels[HUD_PANEL_CAPS].Display = 0; @@ -131,7 +131,7 @@ string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { case "show": return ftos(panel.Display); case "orientation": - return ftos(panel.NodeInsertLoc); + return ftos(panel.Orientation); default: print("^1Setting^7 '", setting, "' does not exist!\n"); break; @@ -154,7 +154,7 @@ void FO_Hud_Editor_Show_Panel(string panelid) = { print("\tscale: ", ftos(panel.Scale), "\n"); print("\ttextscale: ", ftos(panel.TextScale), "\n"); print("\tshow: ", ftos(panel.Display), "\n"); - print("\torientation: ", ftos(panel.NodeInsertLoc), "\n"); + print("\torientation: ", ftos(panel.Orientation), "\n"); } void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting) = { @@ -196,7 +196,7 @@ void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string valu panel.Display = stof(value); break; case "orientation": - panel.NodeInsertLoc = stof(value); + panel.Orientation = stof(value); break; default: print("^1Setting^7 '", setting, "' does not exist!\n"); @@ -263,12 +263,12 @@ void Hud_DrawFlagStatusBar(string panelid) if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].NodeInsertLoc), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); } drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); @@ -283,6 +283,55 @@ void Hud_DrawFlagStatusBar(string panelid) } } +void Hud_ScrollPanelSelector(float num, float numlines) { + float newpos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Status + num; + if(newpos < 1) { + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = 1; + } else if(newpos > (Hud_Panels.length - numlines)) { + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = Hud_Panels.length - (numlines - 1); + } else { + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = newpos; + } +} + +//Draw the list of all panels +void Hud_DrawHudOptionsPanelSelector() { + if(!fo_hud_editor || !Editor_SelectedPanel_Index) + return; + vector pos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; //Start with option panel's pos + vector size = Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale; //for simplicity, use the same size as options panel + float textsize = 8 * (Hud_Panels[HUD_PANEL_HUDOPTIONS].TextScale ? Hud_Panels[HUD_PANEL_HUDOPTIONS].TextScale : Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale); + if((pos.x + (size.x * 2)) < ScreenSize.x) { + //If there's room on the screen, draw to the right of options panel + pos.x = pos.x + size.x; + } else { + pos.x = pos.x - size.x; + } + + if (hud_panel("hud_option_panel_list", pos, size, 0, 1)) + { + // click event + } + + float numlines = rint(size.y / (textsize + 2)); + //Need to draw scrollbar? + if((Hud_Panels.length * (textsize + 2)) > size.y) { + //Scrollbar buttons + if(hud_button("hud_option_panel_list_scrollup", pos + [size.x - textsize - 2,2], [textsize, textsize], "^")) { + Hud_ScrollPanelSelector(-1, numlines); + } + if(hud_button("hud_option_panel_list_scrolldown", pos + [size.x - textsize - 2, size.y - textsize - 2], [textsize, textsize], "v")) { + Hud_ScrollPanelSelector(1, numlines); + } + } + for(float i = 0,j = 0; i < min(numlines, Hud_Panels.length); i++) { + j = i + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status - 1; + if(hud_button(strcat("hud_option_panel_list_item", ftos(i)), pos + [2, (textsize + 2) * i], [size.x - textsize - 4, textsize + 2], Hud_Panels[j].Name)) { + Editor_SelectedPanel_Index = j; + } + } +} + void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string icon) { if(!fo_hud_editor || !Editor_SelectedPanel_Index) @@ -293,11 +342,15 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, size, 0, Hud_Panels[HUD_PANEL_HUDOPTIONS].Display)) { // click event + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = 0; } FO_Hud_Panel* selectedPanel = &Hud_Panels[Editor_SelectedPanel_Index]; - drawstring(pos + [4,4], selectedPanel.Name, [8,8], MENU_SELECTED, 1, 0); + //drawstring(pos + [4,4], selectedPanel.Name, [8,8], MENU_SELECTED, 1, 0); + if(hud_button("hud_option_panel_list_button", pos + [4,2], [140, 10], strcat(selectedPanel.Name, " >"))) { + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = !Hud_Panels[HUD_PANEL_HUDOPTIONS].Status; + } float fscale = selectedPanel.Scale; drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); @@ -311,15 +364,15 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string if(ftscale != selectedPanel.TextScale) { Hud_Panels[Editor_SelectedPanel_Index].TextScale = ftscale; } - float ftextalign = selectedPanel.NodeInsertLoc; - //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.NodeInsertLoc ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); + float ftextalign = selectedPanel.Orientation; + //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.Orientation ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); - if(hud_button("hud_option_textalign_toggle", pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.NodeInsertLoc])) { - Hud_Panels[Editor_SelectedPanel_Index].NodeInsertLoc = (selectedPanel.NodeInsertLoc + 1) % 3; + if(hud_button("hud_option_textalign_toggle", pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.Orientation])) { + Hud_Panels[Editor_SelectedPanel_Index].Orientation = (selectedPanel.Orientation + 1) % 3; } //hud_slider("hud_option_textalign_scroll", pos + [8,64], [32,8], [0,1,1], ftextalign); - //if(ftextalign != selectedPanel.NodeInsertLoc) { - // Hud_Panels[Editor_SelectedPanel_Index].NodeInsertLoc = ftextalign; + //if(ftextalign != selectedPanel.Orientation) { + // Hud_Panels[Editor_SelectedPanel_Index].Orientation = ftextalign; //} if(hud_button("hud_option_show_hide_toggle", pos + [4,74], [140, 20], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { Hud_Panels[Editor_SelectedPanel_Index].Display = !selectedPanel.Display; @@ -327,7 +380,10 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [10,116], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); - + + if(Hud_Panels[HUD_PANEL_HUDOPTIONS].Status) { + Hud_DrawHudOptionsPanelSelector(); + } } void Hud_DrawClassInfoPanel(string id, float playerclass) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 876ad37b..e76aa02d 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -188,7 +188,7 @@ string GetPanelString(string line, string name) line = FormatCfgString(line, strcat(name, ".scale"), ftos(DrawPanel.Scale)); line = FormatCfgString(line, strcat(name, ".textscale"), ftos(DrawPanel.TextScale)); line = FormatCfgString(line, strcat(name, ".display"), ftos(DrawPanel.Display)); - line = FormatCfgString(line, strcat(name, ".nodeinsertloc"), ftos(DrawPanel.NodeInsertLoc)); + line = FormatCfgString(line, strcat(name, ".nodeinsertloc"), ftos(DrawPanel.Orientation)); return line; } @@ -254,7 +254,7 @@ void FO_Hud_Editor_LoadSettings() DrawPanel.Display = stof(val); break; case "nodeinsertloc": - DrawPanel.NodeInsertLoc = stof(val); + DrawPanel.Orientation = stof(val); break; } @@ -279,7 +279,7 @@ void FO_Hud_Editor_LoadSettings() } -void GetNewPanel(vector pos, vector fillSize, float scale, float display, float nodeInsertLoc, string name) +void GetNewPanel(vector pos, vector fillSize, float scale, float display, float orientation, string name) { FO_Hud_Panel pnl; @@ -287,7 +287,7 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float pnl.FillSize = fillSize; pnl.Scale = scale; pnl.Display = display; - pnl.NodeInsertLoc = nodeInsertLoc; + pnl.Orientation = orientation; pnl.Name = name; NewPanel = pnl; @@ -317,7 +317,7 @@ void Hud_DrawPanelLMP(string id, string val, string icon) float len; len = strlen(val); - float offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + float offset = (DrawPanel.Orientation == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; pos = [pos_x + offset, pos_y, 0]; float textScale = DrawPanel.TextScale ? DrawPanel.TextScale : DrawPanel.Scale; @@ -329,7 +329,7 @@ vector GetStringOffsetPos(string msg, vector size, vector fontSize, vector pos, { float len, offset; len = strlen(msg); - offset = (DrawPanel.NodeInsertLoc == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + size_x + (fontSize_x * len)) * -1; + offset = (DrawPanel.Orientation == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + size_x + (fontSize_x * len)) * -1; pos = [basepos_x + offset, newline ? pos_y + 2 + ((size_y - fontSize_y) * .5) : pos_y + ((size_y - fontSize_y) * .5), 0]; return pos; diff --git a/csqc/status.qc b/csqc/status.qc index 7f2f07e1..c4b13d2d 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -106,7 +106,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { local float lines; if (fo_hud_editor) { drawstring( - [GetTextAlignOffset(position.x,size.x,padding,panelid,mediumtext.x,panel.NodeInsertLoc), padding*2 + position.y], + [GetTextAlignOffset(position.x,size.x,padding,panelid,mediumtext.x,panel.Orientation), padding*2 + position.y], panelid, mediumtext, MENU_TEXT_1, @@ -138,7 +138,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { line = strtrim(line); if (strlen(line) > 0) { drawstring( - [GetTextAlignOffset(position.x,size.x,padding,line,mediumtext.x,panel.NodeInsertLoc), position.y + padding + mediumtext.y*i], + [GetTextAlignOffset(position.x,size.x,padding,line,mediumtext.x,panel.Orientation), position.y + padding + mediumtext.y*i], line, mediumtext, MENU_TEXT_1, @@ -292,7 +292,7 @@ void(string panelid, float display, string text, string icon) drawGameModePanel } if(message) { drawstring( - [GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.NodeInsertLoc), position.y], + [GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.Orientation), position.y], message, mediumtext, MENU_TEXT_1, @@ -344,7 +344,7 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { } } if(message) { - pos_aligned = GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.NodeInsertLoc); + pos_aligned = GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.Orientation); drawstring( [pos_aligned, position.y], message, @@ -754,7 +754,11 @@ void (float show) FO_Show_Scores = { }; var FO_Hud_Panel Hud_Panels[] = { - {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, +// id, Name, Position, FillSize, Scale, TextScale, Display, Orientation, +// void drawPanel(string panelid, float display, string text, string icon), +// string getValue(), +// Icon, Snap, Status + {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, {"capspanel",FO_HUD_CAPS_NAME,'10 80','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, @@ -770,6 +774,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, + {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; float(string panelid) getHudPanel = { From 9e26f99fa12226b21db10706f356550547e6690c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Aug 2020 14:14:53 +1000 Subject: [PATCH 1080/2474] WIP Allow team scores panel to be moved in fo_hud_editor --- csqc/csextradefs.qc | 1 + csqc/hud.qc | 88 +++++++++++++++++++++++++++++++++++++++++++++ csqc/status.qc | 79 +++++----------------------------------- 3 files changed, 97 insertions(+), 71 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 0870a2c0..c79120ca 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -98,6 +98,7 @@ void(string id, string identify) Hud_DrawIdentifyPanel; void (string panelid, float display, string text, string icon) Hud_DrawHudOptionsPanel; void (string id, float playerclass) Hud_DrawClassInfoPanel; void (string panelid) Hud_DrawFlagStatusBar; +void (string panelid) Hud_DrawTeamScorePanel; float(string id, vector pos, vector size, float alpha, float enabled) hud_panel; vector(float panelid) getPosition; vector(float panelid) getFillSize; diff --git a/csqc/hud.qc b/csqc/hud.qc index d6c62734..21d0c453 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -221,6 +221,94 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, fl return pos + iconsize; } +void(string panelid) Hud_DrawTeamScorePanel = { + float id = getHudPanel(panelid); + if(id < 0) { + return; + } + + vector pos; + pos = Hud_Panels[HUD_PANEL_TEAM_SCORE].Position; + + + float alpha = 0; + FO_Hud_Panel* panel = getHudPanelPointer(id); + + vector position = getPosition(id); + vector size = getFillSize(id); + float sizex, sizey; + sizex = size_x; + sizey = size_y; + vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + local float padding = 4 * panel.Scale; + + local vector fillsize = mediumtext; + fillsize_x = fillsize_x * 3; + + if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_TEAM_SCORE].Display)) + { + // click event + if (fo_hud_editor) + { + + } + } + + + local float offset; + local vector score_position; + local string message = ""; + + if (number_of_teams >= 1) { + score_position = position; + offset = fillsize_x * 0; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team1score))); + drawfill(score_position, fillsize, '0.3 0.4 0.7', 0.5, 0); + } + + if (number_of_teams >= 2) { + score_position = position; + offset = fillsize_x * 1; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team2score))); + drawfill(score_position, fillsize, '0.7 0.4 0.3', 0.5, 0); + } + + if (number_of_teams >= 3) { + score_position = position; + offset = fillsize_x * 2; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team3score))); + drawfill(score_position, fillsize, '0.7 0.7 0.3', 0.5, 0); + } + + if (number_of_teams >= 4) { + score_position = position; + offset = fillsize_x * 3; + score_position_x = score_position_x + offset; + message = strcat(message, strpad(-3, ftos(TS.team4score))); + drawfill(score_position, fillsize, '0.4 0.7 0.3', 0.5, 0); + } + + /* drawfill( */ + /* position + [size.x / 2,padding*2 + mediumtext.y*2], */ + /* mediumtext, */ + /* '255 0 0', */ + /* 1, */ + /* 0 */ + /* ); */ + + drawstring( + position, + message, + mediumtext, + MENU_TEXT_1, + 1, + 0 + ); +}; + void Hud_DrawFlagStatusBar(string panelid) { vector pos; diff --git a/csqc/status.qc b/csqc/status.qc index fad91c84..b18f75d3 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -16,6 +16,14 @@ void(string panelid, float display, string text, string icon) drawIdentify = { } }; +void(string panelid, float display, string text, string icon) drawTeamScorePanel = { + if (display || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawTeamScorePanel(panelid); + } +}; + void(string panelid, float display, string text, string icon) drawFlagInfo = { if (display || fo_hud_editor) { @@ -754,77 +762,6 @@ void (float show) FO_Show_Scores = { panel.Display = show; }; -void(string panelid, float display, string text, string icon) drawTeamScorePanel = { - float id = getHudPanel(panelid); - if(id < 0) { - return; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); - - vector position = getPosition(id); - vector size = getFillSize(id); - vector mediumtext = MENU_TEXT_SMALL * panel.Scale; - local float padding = 4 * panel.Scale; - - local vector fillsize = mediumtext; - fillsize_x = fillsize_x * 3; - - local float offset; - local vector score_position; - local string message = ""; - - if (number_of_teams >= 1) { - score_position = position; - offset = fillsize_x * 0; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team1score))); - drawfill(score_position, fillsize, '0.3 0.4 0.7', 0.5, 0); - } - - if (number_of_teams >= 2) { - score_position = position; - offset = fillsize_x * 1; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team2score))); - drawfill(score_position, fillsize, '0.7 0.4 0.3', 0.5, 0); - } - - if (number_of_teams >= 3) { - score_position = position; - offset = fillsize_x * 2; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team3score))); - drawfill(score_position, fillsize, '0.7 0.7 0.3', 0.5, 0); - } - - if (number_of_teams >= 4) { - score_position = position; - offset = fillsize_x * 3; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team4score))); - drawfill(score_position, fillsize, '0.4 0.7 0.3', 0.5, 0); - } - - /* drawfill( */ - /* position + [size.x / 2,padding*2 + mediumtext.y*2], */ - /* mediumtext, */ - /* '255 0 0', */ - /* 1, */ - /* 0 */ - /* ); */ - - drawstring( - position, - message, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); -}; - - var FO_Hud_Panel Hud_Panels[] = { {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, From 5909770fb34e4f5b48e31f26f9ee94c91bba87eb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 18 Aug 2020 20:12:21 +1000 Subject: [PATCH 1081/2474] Update score of spectators --- csqc/hud.qc | 2 +- ssqc/client.qc | 16 ++++++++++++---- ssqc/csmenu.qc | 6 +++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 21d0c453..0754b0dc 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -223,6 +223,7 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, fl void(string panelid) Hud_DrawTeamScorePanel = { float id = getHudPanel(panelid); + if(id < 0) { return; } @@ -230,7 +231,6 @@ void(string panelid) Hud_DrawTeamScorePanel = { vector pos; pos = Hud_Panels[HUD_PANEL_TEAM_SCORE].Position; - float alpha = 0; FO_Hud_Panel* panel = getHudPanelPointer(id); diff --git a/ssqc/client.qc b/ssqc/client.qc index 4031ea74..8ae418d9 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2607,10 +2607,18 @@ void () PlayerPostThink = { }; void () UpdateAllClientsTeamScores = { - local entity pl = find(world, classname, "player"); - while (pl) { - UpdateClientTeamScores(pl); - pl = find(pl, classname, "player"); + local entity e; + + e = find(world, classname, "player"); + while (e) { + UpdateClientTeamScores(e); + e = find(e, classname, "player"); + } + + e = find(world, classname, "player"); + while (e) { + UpdateClientTeamScores(e); + e = find(e, classname, "observer"); } } diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index fa4b474c..a3783f8f 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -257,11 +257,11 @@ void UpdateClientMOTD(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -void UpdateClientTeamScores(entity pl) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) +void UpdateClientTeamScores(entity e) = { + if(!infokeyf(e, INFOKEY_P_CSQCACTIVE)) return; - msg_entity = pl; + msg_entity = e; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_TEAM_SCORES); WriteFloat(MSG_MULTICAST, team1score); From 0ee2cb5742d5ffe0eaf2b2b3ea38a018d868f61f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 18 Aug 2020 20:15:06 +1000 Subject: [PATCH 1082/2474] Start with observer --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 8ae418d9..0d8e121a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2615,7 +2615,7 @@ void () UpdateAllClientsTeamScores = { e = find(e, classname, "player"); } - e = find(world, classname, "player"); + e = find(world, classname, "observer"); while (e) { UpdateClientTeamScores(e); e = find(e, classname, "observer"); From 120d749b2516d3f4a606401516c8bbdcbb7deb9e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 22 Aug 2020 17:04:36 +1000 Subject: [PATCH 1083/2474] Remove draconian spectalk rules --- ssqc/clan.qc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index c90810d0..04d1f961 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -155,15 +155,7 @@ void () StartMatch = te.nextthink = (time + 1); } } - st = infokey(world, "spectalk"); - f2 = stof(st); - if (!f2) - { - st = "0"; - } - localcmd("sv_spectalk "); - localcmd(st); - localcmd("\n"); + f1 = stof(infokey(world, "fpd")); f1 = (f1 - (f1 & 64)) + (f2 * 64); localcmd("serverinfo fpd "); From fa9164c918c8f5d30a326148a6f1f5dde2cfb796 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 22 Aug 2020 17:46:17 +1000 Subject: [PATCH 1084/2474] Remove fpd manipulation on startmatch --- ssqc/clan.qc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 04d1f961..2440f561 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -59,8 +59,6 @@ void () MatchThink = void () StartMatch = { local string st; - local float f1; - local float f2; local entity te; local entity oldself; local entity gren; @@ -156,13 +154,6 @@ void () StartMatch = } } - f1 = stof(infokey(world, "fpd")); - f1 = (f1 - (f1 & 64)) + (f2 * 64); - localcmd("serverinfo fpd "); - st = ftos(f1); - localcmd(st); - localcmd("\n"); - if (quadmode) { if (rounds) { StartQuadRound(); From f3048556831d9c269920b8bfc3eadd8de227d121 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 23 Aug 2020 14:22:43 +1000 Subject: [PATCH 1085/2474] experimental pyro rework, probably needs to be nerfed --- README.md | 2 +- share/defs.h | 19 +- ssqc/client.qc | 14 +- ssqc/combat.qc | 53 ++--- ssqc/engineer.qc | 6 + ssqc/player.qc | 2 +- ssqc/pyro.qc | 558 +++++++++++++++++++++++++++++------------------ ssqc/qw.qc | 7 +- ssqc/tfort.qc | 87 ++++---- ssqc/tfortmap.qc | 6 +- ssqc/weapons.qc | 16 +- ssqc/world.qc | 2 + 12 files changed, 477 insertions(+), 295 deletions(-) diff --git a/README.md b/README.md index ed6dd03f..cd0de886 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,8 @@ New features * Dropping flag now possible on all maps using /dropflag. * Allow team changing. * Any non-valid impulse now closes the active menu. -* Option for pyro to rocket jump with incendiary cannnon rockets like soldier `localinfo pyro_soldiercannon on`. * Option to allow a demoman to place a detpack while reloading his weapon `localinfo detreload on` +* Pyro types - `localinfo pyro_type val` - 0 = original tf2.9, 1 = oztf pyro style, 2 = FO pyro style == Removed === diff --git a/share/defs.h b/share/defs.h index 2d3df87d..e8f2e33a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -249,8 +249,9 @@ #define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised #define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack // FIXME - concussion and flash states aren't set or tested... -#define TFSTATE_CONCUSSED 131072 +#define TFSTATE_FLAMES_MAX 131072 #define TFSTATE_FLASHED 262144 +#define TFSTATE_CONCUSSED 524288 // Defines used by TF_T_Damage (see combat.qc) #define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target @@ -264,6 +265,7 @@ #define TF_TD_ELECTRICITY 8 // Electric damage #define TF_TD_FIRE 16 // Fire damage #define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc +#define TF_TD_NOMOMENTUM 512 // Special damage, don't change momentum // Classic Fortress stuff #define CF_MAPVOTE_FORCESHOW 10 // Seconds to force the mapvote menu to be open @@ -1045,6 +1047,18 @@ #define PC_PYRO_GRENADE_MAX_1 4 #define PC_PYRO_GRENADE_MAX_2 4 #define PC_PYRO_TF_ITEMS 0 +#define PC_PYRO_AIRBLAST_RANGE 400 +#define PC_PYRO_AIRBLAST_COOLDOWN 3 +#define PC_PYRO_LAVA_LIFETIME 3 +#define PC_PYRO_LAVA_RETICK 1.2 +#define PC_PYRO_FLAMETHROWER_DAM_FO 15 +#define PC_PYRO_FLAMETHROWER_DAM_ORIG 10 + + +// pyro types +#define PYRO_ORIGINAL 0 +#define PYRO_OZTF 1 +#define PYRO_FO 2 // Class Details for SPY #define PC_SPY_SKIN 22 @@ -1406,4 +1420,5 @@ #define PUSH_ONCE 1 #define PUSH_INCLUDETFITEM 2 #define PUSH_EXCLUDEOTHER 4 // bad names, bad bits, bad coder -#define PUSH_NONOISE 8 \ No newline at end of file +#define PUSH_NONOISE 8 + diff --git a/ssqc/client.qc b/ssqc/client.qc index 0d8e121a..68c6644a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -592,10 +592,6 @@ void () DecodeLevelParms = { // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass pyro_type = CF_GetSetting("pyrotype", "pyro_type", "1"); - // pyro setting to rocketjump like soldier - pyro_soldiercannon = CF_GetSetting("pyrosold", "pyro_soldiercannon", "off"); - - // ceasefire type - 0: default; 1: pause ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); @@ -749,7 +745,7 @@ void () DecodeLevelParms = { old_hp_armor = FALSE; ng_velocity = 1500; old_ng_rof = FALSE; - pyro_type = 1; + pyro_type = PYRO_OZTF; Role_None.gren1_limits[1] = PC_SCOUT_GRENADE_MAX_1; Role_None.gren1_limits[2] = PC_SNIPER_GRENADE_MAX_1; Role_None.gren1_limits[3] = PC_SOLDIER_GRENADE_MAX_1; @@ -820,7 +816,7 @@ void () DecodeLevelParms = { old_hp_armor = TRUE; ng_velocity = 1000; old_ng_rof = TRUE; - pyro_type = 0; + pyro_type = PYRO_ORIGINAL; Role_None.gren1_limits[1] = 4; Role_None.gren1_limits[2] = 4; Role_None.gren1_limits[3] = 4; @@ -2218,7 +2214,7 @@ void () WaterMove = { } return; } - if (self.watertype == -5) { + if (self.watertype == CONTENT_LAVA) { if (self.dmgtime < time) { if(votemode && !vote_anarchy_mode) { respawn(); @@ -2241,7 +2237,7 @@ void () WaterMove = { } } if (!(self.flags & 16)) { - if (self.watertype == -5) { + if (self.watertype == CONTENT_LAVA) { FO_Sound(self, CHAN_BODY, "player/inlava.wav", 1, 1); } if (self.watertype == -3) { @@ -3209,7 +3205,7 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage s_deathstring = " gulped a load of slime\n"; else s_deathstring = " can't exist on slime alone\n"; - } else if (rnum == -5) { + } else if (rnum == CONTENT_LAVA) { if (pe_target.health < -15) s_deathstring = " burst into flames\n"; else if (random() < 0.5) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index b19e8471..03e1f6ae 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -406,7 +406,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, if (targ.takedamage == 0) return; - if (T_AttackType & 256) { + if (T_AttackType & TF_TD_NOSOUND) { targ.health = damage; return; } @@ -517,41 +517,44 @@ void (entity targ, entity inflictor, entity attacker, float damage, targ.dmg_inflictor = inflictor; } - if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && + if (!(T_AttackType & TF_TD_NOMOMENTUM)) + { + if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && !(targ.tfstate & TFSTATE_CANT_MOVE)) { + if (deathmsg != DMSG_GREN_NAIL) { - if (deathmsg != DMSG_GREN_NAIL) { - - targ.immune_to_check = time + damage / 20; - dir = - targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; - dir = normalize(dir); + targ.immune_to_check = time + damage / 20; + dir = + targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; + dir = normalize(dir); - if (targ.playerclass == PC_HVYWEAP) { - moment = damage / 4; - if (damage <= 50) - moment = 0; - } else - moment = damage; + if (targ.playerclass == PC_HVYWEAP) { + moment = damage / 4; + if (damage <= 50) + moment = 0; + } else + moment = damage; - if ((moment < 60) - && (attacker.classname == "player") - && (targ.classname == "player") - && (attacker.netname != targ.netname)) { + if ((moment < 60) + && (attacker.classname == "player") + && (targ.classname == "player") + && (attacker.netname != targ.netname)) { - targ.velocity = targ.velocity + dir * moment * 11; + targ.velocity = targ.velocity + dir * moment * 11; - } else - targ.velocity = targ.velocity + dir * moment * 8; + } else + targ.velocity = targ.velocity + dir * moment * 8; - if ((rj > 1) && (attacker.classname == "player") - && (targ.classname == "player") - && (attacker.netname == targ.netname)) { + if ((rj > 1) && (attacker.classname == "player") + && (targ.classname == "player") + && (attacker.netname == targ.netname)) { - targ.velocity = targ.velocity + dir * moment * rj; + targ.velocity = targ.velocity + dir * moment * rj; + } } } } + if (targ.flags & FL_GODMODE) return; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 98da57b9..2e50b7a6 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -778,6 +778,8 @@ void () DispenserThink = { if (!old_dispenser) Dispenser_FindPlayers(self); + CheckPyroLava(); + self.nextthink = time + 0.3; }; @@ -879,6 +881,8 @@ void () TeamFortress_FinishedBuilding = { oldself.takedamage = DAMAGE_NO; oldself.th_die = Sentry_Die; oldself.team_no = self.team_no; + oldself.think = CheckPyroLava; + oldself.nextthink = time + .1; self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; setsize(oldself, '-16 -16 0', '16 16 4'); newmis = spawn(); @@ -1395,3 +1399,5 @@ void () info_empblock = { self.weapon = 512; self.netname = "EMP Block"; }; +// fixme +// combat.qc tf_t_damage everything doing true damage \ No newline at end of file diff --git a/ssqc/player.qc b/ssqc/player.qc index c2415600..22d1afa4 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -617,7 +617,7 @@ void () PainSound = { } return; } - if (self.watertype == -5) { + if (self.watertype == CONTENT_LAVA) { if (random() > 0.5) { FO_Sound(self, CHAN_VOICE, "player/lburn1.wav", 1, 1); } else { diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 527d9eb3..d268925d 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -96,6 +96,8 @@ float (string id_flame) RemoveFlameFromQueue = { return (1); }; + + void () Remove = { FlameDestroy(self); }; @@ -258,13 +260,13 @@ void () FlameFollow = { FlameDestroy(self); return; } - if ((self.enemy.armorclass & 16) && (self.enemy.armorvalue > 0)) { + if ((self.enemy.armorclass & AT_SAVEFIRE) && (self.enemy.armorvalue > 0)) { self.health = 0; } - if (self.enemy.tfstate & 131072) { + if (self.enemy.tfstate & TFSTATE_FLAMES_MAX) { self.health = 45; self.enemy.tfstate = - self.enemy.tfstate - (self.enemy.tfstate & 131072); + self.enemy.tfstate - (self.enemy.tfstate & TFSTATE_FLAMES_MAX); } if (self.health < 1) { if ((self.effects != 8) || (self.enemy.numflames <= 1)) { @@ -314,46 +316,65 @@ void () FlameFollow = { } }; -void () OnPlayerFlame_touch = { - local entity flame; - local vector vtemp; +void (entity player, entity fireowner, vector org + , float flamehealth) SetOnFire = { + entity flame; - if (((other != world) && (other.health > 0)) && (other != self.enemy)) { - if (cb_prematch) { + if (cb_prematch) + { + return; + } + + if (player.numflames >= 4) + { + player.tfstate = player.tfstate | TFSTATE_FLAMES_MAX; + return; + } + + if ((player.armorclass & AT_SAVEFIRE) && (player.armorvalue > 0)) + { + return; + } + + if (player.classname == "player") + { + if (((teamplay & 16) && (player.team_no > 0)) && + (player.team_no == fireowner.team_no)) { return; } - if (other.numflames >= 4) { - other.tfstate = other.tfstate | 131072; + CenterPrint(player, "You are on fire!\n"); + stuffcmd(player, "bf\n"); + } + + if (player.numflames < 1) + { + flame = FlameSpawn("1", player); + //FO_Sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, 1); // original tf code, but super annoying and it doesn't stop + } + else + { + flame = FlameSpawn("3", player); + if (flame == world) { return; } - if (other.classname == "player") { - if (((teamplay & 16) && (other.team_no > 0)) && - (other.team_no == self.owner.team_no)) { - return; - } - CenterPrint(other, "You are on fire!\n"); - stuffcmd(other, "bf\n"); - } - if (other.numflames < 1) { - flame = FlameSpawn("1", other); - FO_Sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, 1); - } else { - flame = FlameSpawn("3", other); - if (flame == world) { - return; - } - } - flame.classname = "fire"; - flame.health = 45; - other.numflames = other.numflames + 1; - flame.velocity = other.velocity; - flame.enemy = other; - flame.touch = OnPlayerFlame_touch; - flame.owner = self.owner; - vtemp = self.origin; - setorigin(flame, vtemp); - flame.nextthink = time + 0.1; - flame.think = FlameFollow; + } + + flame.classname = "fire"; + flame.health = flamehealth; + player.numflames = player.numflames + 1; + flame.velocity = player.velocity; + flame.enemy = player; + flame.touch = OnPlayerFlame_touch; + flame.owner = fireowner; + setorigin(flame, org); + flame.nextthink = time + 0.1; + flame.think = FlameFollow; +}; + +void () OnPlayerFlame_touch = { + if (((other != world) && (other.health > 0)) && (other != self.enemy)) { + float flamehealth = 45; + SetOnFire(other, self.owner, self.origin, flamehealth); } }; @@ -366,9 +387,6 @@ void () QW_Flame_ResetTouch = { }; void () WorldFlame_touch = { - local entity flame; - local vector vtemp; - deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.enemy, 10, TF_TD_NOTTEAM, TF_TD_FIRE); self.touch = SUB_Null; @@ -377,48 +395,13 @@ void () WorldFlame_touch = { self.nextthink = time + 1; } if (((other != world) && (other.solid != 1)) && (other.health > 0)) { - if (cb_prematch) { - return; - } - if (other.numflames >= 4) { - other.tfstate = other.tfstate | 131072; - return; - } - if (other.classname == "player") { - if (((teamplay & 16) && (other.team_no > 0)) && - (other.team_no == self.owner.team_no)) { - return; - } - CenterPrint(other, "You are on fire!\n"); - stuffcmd(other, "bf\n"); - } - if (other.numflames < 1) { - flame = FlameSpawn("1", other); - FO_Sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, 1); - } else { - flame = FlameSpawn("3", other); - if (flame == world) { - return; - } - } - flame.classname = "fire"; - flame.health = 0; - other.numflames = other.numflames + 1; - flame.velocity = other.velocity; - flame.enemy = other; - flame.touch = OnPlayerFlame_touch; - flame.owner = self.owner; - vtemp = self.origin + '0 0 10'; - setorigin(flame, vtemp); - flame.nextthink = time + 0.15; - flame.think = FlameFollow; + vector org = self.origin + '0 0 10'; + float flamehealth = 0; + SetOnFire(other, self.owner, org, flamehealth); } }; void () Flamer_stream_touch = { - local entity flame; - local vector vtemp; - if (other.classname == "fire") { return; } @@ -433,47 +416,17 @@ void () Flamer_stream_touch = { } } - TF_T_Damage(other, self, self.owner, 10, TF_TD_NOTTEAM, - TF_TD_FIRE); - if (cb_prematch) { - return; + if (pyro_type == PYRO_FO) + { + TF_T_Damage(other, self, self.owner, PC_PYRO_FLAMETHROWER_DAM_FO, TF_TD_NOTTEAM, TF_TD_FIRE); } - if (other.numflames >= 4) { - other.tfstate = other.tfstate | 131072; - return; + else + { + TF_T_Damage(other, self, self.owner, PC_PYRO_FLAMETHROWER_DAM_ORIG, TF_TD_NOTTEAM, TF_TD_FIRE); } - if ((other.armorclass & 16) && (other.armorvalue > 0)) { - return; - } - if (other.classname == "player") { - if (((teamplay & 16) && (other.team_no > 0)) && - (other.team_no == self.owner.team_no)) { - return; - } - CenterPrint(other, "You are on fire!\n"); - stuffcmd(other, "bf\n"); - } - if (other.numflames < 1) { - flame = FlameSpawn("1", other); - FO_Sound(flame, CHAN_VOICE, "ambience/fire1.wav", 1, - ATTN_NORM); - } else { - flame = FlameSpawn("3", other); - if (flame == world) { - return; - } - } - flame.classname = "fire"; - flame.health = 45; - other.numflames = other.numflames + 1; - flame.velocity = other.velocity; - flame.enemy = other; - flame.touch = OnPlayerFlame_touch; - flame.owner = self.owner; - vtemp = self.origin; - setorigin(flame, vtemp); - flame.nextthink = time + 0.1; - flame.think = FlameFollow; + + float flamehealth = 45; + SetOnFire(other, self.owner, self.origin, flamehealth); } } else { if ((random() < 0.3) || @@ -481,11 +434,12 @@ void () Flamer_stream_touch = { remove(self); return; } + entity flame; flame = FlameSpawn("4", other); if (flame != world) { flame.touch = WorldFlame_touch; flame.classname = "fire"; - vtemp = self.origin + '0 0 10'; + vector vtemp = self.origin + '0 0 10'; setorigin(flame, vtemp); flame.nextthink = time + 8; flame.heat = flame.nextthink; @@ -497,9 +451,6 @@ void () Flamer_stream_touch = { }; void () Napalm_touch = { - local entity flame; - local vector vtemp; - if (other.classname == "fire") { return; } @@ -508,55 +459,21 @@ void () Napalm_touch = { deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, 6, TF_TD_NOTTEAM, TF_TD_FIRE); - if (cb_prematch) { - return; - } - if (other.numflames >= 4) { - other.tfstate = other.tfstate | 131072; - return; - } - if ((other.armorclass & 16) && (other.armorvalue > 0)) { - return; - } - if (other.classname == "player") { - if (((teamplay & 16) && (other.team_no > 0)) && - (other.team_no == self.owner.team_no)) { - return; - } - FO_Sound(other, CHAN_VOICE, "ambience/fire1.wav", 1, ATTN_NORM); - CenterPrint(other, "You are on fire!\n"); - stuffcmd(other, "bf\n"); - } - if (other.numflames < 1) { - flame = FlameSpawn("1", other); - } else { - flame = FlameSpawn("3", other); - if (flame == world) { - return; - } - } - flame.classname = "fire"; - flame.health = 45; - other.numflames = other.numflames + 1; - flame.velocity = other.velocity; - flame.enemy = other; - flame.touch = OnPlayerFlame_touch; - flame.owner = self.owner; - vtemp = self.origin; - setorigin(flame, vtemp); - flame.nextthink = time + 0.1; - flame.think = FlameFollow; + + float flamehealth = 45; + SetOnFire(other, self.owner, self.origin, flamehealth); } } else { if (pointcontents((self.origin + '0 0 1')) != -1) { FlameDestroy(self); return; } + entity flame; flame = FlameSpawn("4", other); if (flame != world) { flame.touch = WorldFlame_touch; flame.classname = "fire"; - vtemp = self.origin + '0 0 10'; + vector vtemp = self.origin + '0 0 10'; setorigin(flame, vtemp); flame.nextthink = time + 20; flame.heat = flame.nextthink; @@ -610,24 +527,59 @@ void () W_FireFlame = { flame.classname = "flamerflame"; makevectors(self.v_angle); flame.velocity = aim(self, 10000); - flame.velocity = flame.velocity * 600; + if (pyro_type == PYRO_FO) + { + flame.velocity = flame.velocity * 600; + flame.nextthink = time + 0.15; + } + else + { + flame.velocity = flame.velocity * 600; + flame.nextthink = time + 0.15; + } + flame.touch = Flamer_stream_touch; flame.think = s_explode1; - flame.nextthink = time + 0.15; + FO_SetModel(flame, "progs/s_explod.spr"); setsize(flame, '0 0 0', '0 0 0'); setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); }; -void () IncendiaryRadius = -{ - local float damg; +void () IncendiaryRadius = { + entity head; + head = findradius(self.origin, 180); + while (head) { + if (head.takedamage) { + traceline(self.origin, head.origin, 1, self); + if ((trace_fraction == 1) + || ((trace_fraction != 1) + && (vlen(self.origin - head.origin) <= 64))) { + deathmsg = DMSG_FLAME; + TF_T_Damage(head, self, self.owner, 10, TF_TD_NOTTEAM, + TF_TD_FIRE); + other = head; + Napalm_touch(); + if (other.classname == "player") { + stuffcmd(other, "bf\nbf\n"); + } + } + } + head = head.chain; + } + self.origin = self.origin - 8 * normalize(self.velocity); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PHS); + dremove(self); +}; - if(pyro_soldiercannon) - damg = 92; - else - damg = 72; - +void () IncendiaryRadius_OZTF = { + local float damg; + damg = 92; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -640,9 +592,121 @@ void () IncendiaryRadius = dremove(self); }; +void (entity targ, entity lava) ForceIncendiaryLavaTouch = { + if (targ.classname == "building_sentrygun_base") + { + targ = targ.oldenemy; // set other to sentrygun turret + } + if (targ.takedamage) + { + if (targ.icdmgtime < time) + { + targ.icdmgtime = time + PC_PYRO_LAVA_RETICK; + deathmsg = DMSG_FLAME; + TF_T_Damage(targ, lava, lava.owner, 40, TF_TD_NOTTEAM, TF_TD_NOMOMENTUM | TF_TD_FIRE); + + if (random() > 0.5) { + FO_Sound(targ, CHAN_VOICE, "player/lburn1.wav", 1, 1); + } else { + FO_Sound(targ, CHAN_VOICE, "player/lburn2.wav", 1, 1); + } + } + SetOnFire(targ, lava.owner, lava.origin, 15); + } +}; + +// used by sentrygun and dispenser to see if they are standing on "lava", touch events not being set off +void () CheckPyroLava = { + vector org = self.origin; + org_z = org_z - self.mins_z; + if (self.classname == "building_sentrygun_base") + { + self.nextthink = time + .3; + } + else if (self.classname == "building_dispenser") + { + // nothing for now + } + else + { + // spam everyone, get this bug fixed + bprint(PRINT_HIGH, "CheckPyroLava returning for ", self.classname, "\n"); + return; + } + + // FIXME - do dodgy radius, means disp and sentry can catch on fire when not "touching" edge of pool + // fix later if we keep these changes + entity lava; + lava = findradius(org, 5); + while (lava) + { + if (lava.classname == "pyrolava") + { + ForceIncendiaryLavaTouch(self, lava); + return; + } + lava = lava.chain; + } +}; + +void () IncendiaryLavaThink = { + dremove(self); +}; + +void () IncendiaryLavaTouch = { + ForceIncendiaryLavaTouch(other, self); +}; + +entity (vector org) SpawnLavaSprite = { + entity lava; + lava = spawn(); + lava.mdl = "progs/s_explod.spr"; + lava.owner = self.owner; + lava.movetype = MOVETYPE_TOSS; + lava.solid = SOLID_TRIGGER; + lava.touch = IncendiaryLavaTouch; + lava.classname = "pyrolava"; + + FO_SetModel(lava, lava.mdl); + setorigin(lava, org); + setsize(lava, VEC_ORIGIN, VEC_ORIGIN); + + lava.think = IncendiaryLavaThink; + lava.nextthink = time + PC_PYRO_LAVA_LIFETIME; + + return lava; +}; + +void () IncendiaryRadius_FO = { + + vector org; + org = self.origin; + entity lava = SpawnLavaSprite(org); + + for (float i = -5; i < 5; i++) + { + org = self.origin; + org_x = org_x + 10 * i; + + float yval = org_y; + for (float i2 = -5; i2 < 5; i2++) + { + if (i2 == 0 && i == 0) + continue; + + org_y = yval + 10 * i2; + SpawnLavaSprite(org); + } + + } + + FO_Sound(self, CHAN_AUTO, "player/inlava.wav", 1, ATTN_NORM); + + dremove(self); +}; + void () T_IncendiaryTouch = { local float damg; - local entity head; if (other == self.owner) { return; @@ -652,45 +716,32 @@ void () T_IncendiaryTouch = { return; } self.effects = self.effects | 4; - if (pyro_type == 1) - damg = 42 + random() * 20; - else + if (pyro_type == PYRO_ORIGINAL) + { damg = 30 + random() * 20; + } + else + { + damg = 42 + random() * 20; + } + if (other.health) { deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_FIRE); } - if (pyro_type == 1) - IncendiaryRadius(); - else { - head = findradius(self.origin, 180); - while (head) { - if (head.takedamage) { - traceline(self.origin, head.origin, 1, self); - if ((trace_fraction == 1) - || ((trace_fraction != 1) - && (vlen(self.origin - head.origin) <= 64))) { - deathmsg = DMSG_FLAME; - TF_T_Damage(head, self, self.owner, 10, TF_TD_NOTTEAM, - TF_TD_FIRE); - other = head; - Napalm_touch(); - if (other.classname == "player") { - stuffcmd(other, "bf\nbf\n"); - } - } - } - head = head.chain; - } - self.origin = self.origin - 8 * normalize(self.velocity); - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); - dremove(self); + + switch (pyro_type) + { + case PYRO_ORIGINAL: + IncendiaryRadius(); + break; + case PYRO_OZTF: + IncendiaryRadius_OZTF(); + break; + case PYRO_FO: + IncendiaryRadius_FO(); + break; } }; @@ -708,20 +759,29 @@ void () W_FireIncendiaryCannon = { newmis.solid = SOLID_BBOX; makevectors(self.v_angle); newmis.velocity = aim(self, 1000); - if (pyro_type == 1) { - newmis.velocity = newmis.velocity * 800; - newmis.think = IncendiaryRadius; - } - else { + string rktmdl = "progs/missile.mdl"; + if (pyro_type == PYRO_ORIGINAL) + { newmis.velocity = newmis.velocity * 600; newmis.think = SUB_Remove; } + else + { + newmis.velocity = newmis.velocity * 800; + newmis.think = IncendiaryRadius_OZTF; + + if (pyro_type == PYRO_FO) + { + rktmdl = "progs/lavaball.mdl"; + } + } + newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_IncendiaryTouch; newmis.nextthink = time + 5; newmis.weapon = DMSG_INCENDIARY; newmis.classname = "pyro_rocket"; - FO_SetModel(newmis, "progs/missile.mdl"); + FO_SetModel(newmis, rktmdl); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); }; @@ -749,3 +809,79 @@ void () TeamFortress_FlameThrower = { self.current_weapon = WEAP_FLAMETHROWER; W_SetCurrentAmmo(self); }; + +void () UseAirBlast = { + if (self.special_cooldown < time) + { + self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; + + FO_Sound(self, CHAN_WEAPON, "weapons/airblast.wav", 1, ATTN_NORM); + makevectors(self.v_angle); + entity ent; + + ent = findradius(self.origin, PC_PYRO_AIRBLAST_RANGE); + while (ent) + { + if (visible(ent)) + { + switch (ent.classname) + { + case "player": + case "pyro_rocket": + case "flamerflame": + case "proj_tranq": + case "proj_bullet": + case "proj_rocket": + case "grenade": + case "spike": + case "pipebomb": + vector targorg; + targorg = ent.origin; + float pushval = 1000; + if (ent == self) + { + pushval = 500; + traceline(self.origin, self.origin + v_forward * 200, MOVE_NOMONSTERS, self); + if (trace_fraction < 1) + { + targorg = self.origin - (v_forward * 200 * trace_fraction); + } + } + + vector delta = targorg - self.origin; + float dist = vlen(delta); + float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; + + if (ent.flags & FL_ONGROUND) + { + if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted + { + setorigin(ent, ent.origin + '0 0 1'); + } + } + + delta = normalize(delta); + delta = delta * percent * pushval; + + if (ent.movetype == MOVETYPE_FLYMISSILE) + { + float speed = vlen(ent.velocity); + ent.velocity = normalize(delta) * speed; + } + else + { + ent.velocity = ent.velocity + delta; + } + + break; + } + } + + ent = ent.chain; + } + } + else + { + sprint(self, PRINT_HIGH, "Airblast is on cooldown\n"); + } +}; \ No newline at end of file diff --git a/ssqc/qw.qc b/ssqc/qw.qc index cca1c976..9d6b1686 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -382,9 +382,11 @@ float item_list_bit; // Global, used to determine what the bit of //============================================================================ +// pyro float num_world_flames; .float numflames; // number of flames on entity .string flame_id; // has to be string so that the C function find() can be used +.float icdmgtime; // Spy variables .float undercover_team; @@ -569,7 +571,6 @@ float old_ng_rof; float impulse_queue; float detpack_when_reloading; float pyro_type; -float pyro_soldiercannon; float flag_follow; float ceasefire_type; float is_paused; @@ -705,4 +706,6 @@ float FO_FlashDimension; // allow for default goal state .float default_group_no; -.string broadcast_high; \ No newline at end of file +.string broadcast_high; + +.float special_cooldown; \ No newline at end of file diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 46fd4498..09dfa16a 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -43,44 +43,57 @@ void () UseSpecialSkill = { local vector src; self.impulse = 0; - if (self.playerclass == PC_SCOUT) - self.impulse = TF_DASH; - else if (self.playerclass == PC_SNIPER) - self.impulse = TF_ZOOMTOGGLE; - else if (self.playerclass == PC_DEMOMAN) - self.impulse = TF_PB_DETONATE; - else if (self.playerclass == PC_MEDIC) - self.impulse = TF_MEDIC_AURA_TOGGLE; - else if (self.playerclass == PC_HVYWEAP) { - if (self.tfstate & TFSTATE_LOCK) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); - else - self.tfstate = self.tfstate | TFSTATE_LOCK; - Status_Refresh(self); - self.impulse = 0; - return; - } else if (self.playerclass == PC_SPY) - self.impulse = TF_SPY_DIE; - else if (self.playerclass == PC_ENGINEER) - self.impulse = TF_ENGINEER_DETDISP; - else if (self.playerclass == PC_UNDEFINED) { - if (self.enemy == world) { - src = self.origin + v_forward * 10; - src_z = self.absmin_z + self.size_z * 0.7; - traceline(src, src + v_forward * 2048, 0, self); - if ((trace_ent != world) && (trace_ent.origin != world.origin)) { - sprint3(self, PRINT_HIGH, "Locked onto ", - trace_ent.classname, "\n"); - self.enemy = trace_ent; - self.camdist = vlen(self.enemy.origin - self.origin); - self.camangle = self.origin - self.enemy.origin; - self.camangle_z = 0 - self.camangle_z; - self.camangle = vectoangles(self.camangle); + switch (self.playerclass) + { + case PC_SCOUT: + self.impulse = TF_DASH; + break; + case PC_SNIPER: + self.impulse = TF_ZOOMTOGGLE; + break; + case PC_DEMOMAN: + self.impulse = TF_PB_DETONATE; + break; + case PC_MEDIC: + self.impulse = TF_MEDIC_AURA_TOGGLE; + break; + case PC_HVYWEAP: + if (self.tfstate & TFSTATE_LOCK) + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); + else + self.tfstate = self.tfstate | TFSTATE_LOCK; + Status_Refresh(self); + self.impulse = 0; + return; + case PC_PYRO: + if (pyro_type == PYRO_FO) + UseAirBlast(); + break; + case PC_SPY: + self.impulse = TF_SPY_DIE; + break; + case PC_ENGINEER: + self.impulse = TF_ENGINEER_DETDISP; + break; + case PC_UNDEFINED: + if (self.enemy == world) { + src = self.origin + v_forward * 10; + src_z = self.absmin_z + self.size_z * 0.7; + traceline(src, src + v_forward * 2048, 0, self); + if ((trace_ent != world) && (trace_ent.origin != world.origin)) { + sprint3(self, PRINT_HIGH, "Locked onto ", + trace_ent.classname, "\n"); + self.enemy = trace_ent; + self.camdist = vlen(self.enemy.origin - self.origin); + self.camangle = self.origin - self.enemy.origin; + self.camangle_z = 0 - self.camangle_z; + self.camangle = vectoangles(self.camangle); + } + } else { + sprint(self, PRINT_HIGH, "Removed lock\n"); + self.enemy = world; } - } else { - sprint(self, PRINT_HIGH, "Removed lock\n"); - self.enemy = world; - } + break; } }; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index df95356b..7910228b 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2520,15 +2520,15 @@ void () tfgoalitem_dropthink = { self.movetype = 6; if (self.pausetime != 0) { pos = pointcontents(self.origin); - if (pos == -4) { //CONTENT_SLIME + if (pos == CONTENT_SLIME) { self.nextthink = time + (self.pausetime / 4); } else { - if (pos == -5) { //CONTENT_LAVA + if (pos == CONTENT_LAVA) { self.nextthink = time + 5; self.think = tfgoalitem_remove; return; } else { - if ((pos == -2) || (pos == -6)) { //CONTENT_SOLID || CONTENT_SKY + if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { if (self.camdist < 3) { self.origin = self.camangle; setorigin(self, self.origin); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index aa8f2fe2..6e9895cf 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2070,10 +2070,18 @@ void () W_Attack = { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); - if (pyro_type == 1) - Attack_Finished(0.9); - else - Attack_Finished(1.2); + switch (pyro_type) + { + case PYRO_ORIGINAL: + Attack_Finished(1.2); + break; + case PYRO_OZTF: + Attack_Finished(0.9); + break; + case PYRO_FO: + Attack_Finished(PC_PYRO_LAVA_RETICK); + break; + } } else if (time >= self.antispam_incendiary_cannon) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; diff --git a/ssqc/world.qc b/ssqc/world.qc index 18be3689..83ee5124 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -316,6 +316,8 @@ void () worldspawn = { precache_sound("shalrath/attack2.wav"); precache_sound("blob/sight1.wav"); precache_sound("misc/secret.wav"); + precache_model("maps/b_nail0.bsp"); + precache_sound("weapons/airblast.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); From 55af22e0ccc50e7d75b44dcf70c1522f89b70714 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 23 Aug 2020 14:35:29 +1000 Subject: [PATCH 1086/2474] remove health precache --- ssqc/world.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/world.qc b/ssqc/world.qc index 83ee5124..44765581 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -316,7 +316,6 @@ void () worldspawn = { precache_sound("shalrath/attack2.wav"); precache_sound("blob/sight1.wav"); precache_sound("misc/secret.wav"); - precache_model("maps/b_nail0.bsp"); precache_sound("weapons/airblast.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); From 8bdaff835cfc9e08d800ce66edc0297803bb5991 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 23 Aug 2020 14:36:49 +1000 Subject: [PATCH 1087/2474] remove old comment --- ssqc/engineer.qc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 2e50b7a6..ec2f1bf7 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1398,6 +1398,4 @@ void (entity eng) Engineer_RemoveBuildings = { void () info_empblock = { self.weapon = 512; self.netname = "EMP Block"; -}; -// fixme -// combat.qc tf_t_damage everything doing true damage \ No newline at end of file +}; \ No newline at end of file From b80599b9de74fc57cb10b262385378393c31feba Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 23 Aug 2020 21:01:53 +1000 Subject: [PATCH 1088/2474] don't apply airblast if movetype is none --- ssqc/pyro.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index d268925d..91533902 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -822,6 +822,9 @@ void () UseAirBlast = { ent = findradius(self.origin, PC_PYRO_AIRBLAST_RANGE); while (ent) { + if (ent.movetype == MOVETYPE_NONE) + continue; + if (visible(ent)) { switch (ent.classname) From f934288b36f2140f22d7df20b25225feebf809d5 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 24 Aug 2020 23:16:48 +1200 Subject: [PATCH 1089/2474] Allow teamscores to be right-edge aligned; fix teamscores for indi frags --- csqc/csextradefs.qc | 2 ++ csqc/hud.qc | 26 ++++++++++++++++++++++++-- csqc/status.qc | 9 +++++++++ share/defs.h | 1 + ssqc/tfort.qc | 1 + 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9d606ea3..59934e59 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -99,6 +99,7 @@ void (string panelid, float display, string text, string icon) Hud_DrawHudOption void (string id, float playerclass) Hud_DrawClassInfoPanel; void (string panelid) Hud_DrawFlagStatusBar; void (string panelid) Hud_DrawTeamScorePanel; +void (string panelid) Hud_DrawMapMenuPanel; float(string id, vector pos, vector size, float alpha, float enabled) hud_panel; vector(float panelid) getPosition; vector(float panelid) getFillSize; @@ -370,6 +371,7 @@ enum { HUD_PANEL_READY, HUD_PANEL_SHOWSCORES, HUD_PANEL_TEAM_SCORE, + HUD_PANEL_MAP_MENU, HUD_PANEL_HUDOPTIONS, }; diff --git a/csqc/hud.qc b/csqc/hud.qc index a2d022bc..f003e5dc 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -221,6 +221,14 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, fl return pos + iconsize; } +void(string panelid) Hud_DrawMapMenuPanel = { + float id = getHudPanel(panelid); + + if(id < 0) { + return; + } +} + void(string panelid) Hud_DrawTeamScorePanel = { float id = getHudPanel(panelid); @@ -258,6 +266,9 @@ void(string panelid) Hud_DrawTeamScorePanel = { local float offset; local vector score_position; local string message = ""; + if(panel.Orientation == FO_HUD_INSERT_AFTER) { + position_x = position_x - ((number_of_teams - 1) * fillsize_x); + } if (number_of_teams >= 1) { score_position = position; @@ -762,7 +773,7 @@ void Hud_DrawIdentifyPanel(string id, string identify) void Hud_Draw(float width, float height) { - + float offset = 0; for(float i = 0; i < Hud_Panels.length; i++) { Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); if(sui_is_last_clicked(Hud_Panels[i].id)) { @@ -770,7 +781,18 @@ void Hud_Draw(float width, float height) } //Draw panel names when editing if(fo_hud_editor && Hud_Panels[i].id != "hudoptionspanel") { - drawstring(Hud_Panels[i].Position + [2,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); + switch (Hud_Panels[i].Orientation) { + case FO_HUD_INSERT_BEFORE: + offset = 2; + break; + case FO_HUD_INSERT_AFTER: + offset = Hud_Panels[i].FillSize.x - (strlen(Hud_Panels[i].Name) * 6) - 2; + break; + case FO_HUD_INSERT_MIDDLE: + offset = (Hud_Panels[i].FillSize.x / 2) - (strlen(Hud_Panels[i].Name) * 3); //because 3 = 6/2 + break; + } + drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); } } diff --git a/csqc/status.qc b/csqc/status.qc index 5ef53b68..6bd514c2 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -24,6 +24,14 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel } }; +void(string panelid, float display, string text, string icon) drawMapMenuPanel = { + if (display || fo_hud_editor) + { + GetDrawPanel(panelid); + Hud_DrawMapMenuPanel(panelid); + } +}; + void(string panelid, float display, string text, string icon) drawFlagInfo = { if (display || fo_hud_editor) { @@ -784,6 +792,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, + {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; diff --git a/share/defs.h b/share/defs.h index 2d3df87d..a486b2ee 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1362,6 +1362,7 @@ #define FO_HUD_GAME_MODE_NAME "Game Mode" #define FO_HUD_READY_NAME "Ready Status" #define FO_HUD_SHOWSCORES_NAME "Show Scores" +#define FO_HUD_MAP_MENU_NAME "Map Menu" #define FO_HUD_TEAM_SCORE_NAME "Team Score" diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 46fd4498..70011e5c 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -3095,6 +3095,7 @@ void (entity pl, float fr) TF_AddFrags = { team3score = team3score + fr; else if (pl.team_no == 4) team4score = team4score + fr; + UpdateAllClientsTeamScores(); //Update scoreboard for indi frags } if (pl.team_no == 1) From ebdf8f885487557bd22fe44d4b96742809b65fa4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 24 Aug 2020 23:37:49 +1200 Subject: [PATCH 1090/2474] fix icons --- csqc/csextradefs.qc | 2 +- csqc/hud.qc | 32 +++++++++++++++++++++----------- csqc/status.qc | 2 +- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 59934e59..5d3623d0 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -371,7 +371,7 @@ enum { HUD_PANEL_READY, HUD_PANEL_SHOWSCORES, HUD_PANEL_TEAM_SCORE, - HUD_PANEL_MAP_MENU, +// HUD_PANEL_MAP_MENU, HUD_PANEL_HUDOPTIONS, }; diff --git a/csqc/hud.qc b/csqc/hud.qc index f003e5dc..9fca80c6 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -227,6 +227,16 @@ void(string panelid) Hud_DrawMapMenuPanel = { if(id < 0) { return; } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + local vector fillsize = panel.FillSize * panel.Scale; + local float alpha = 0.2; + if (hud_panel(panelid, panel.Position, fillsize, alpha, panel.Display)) { + // click event + if (fo_hud_editor) { + + } + } } void(string panelid) Hud_DrawTeamScorePanel = { @@ -535,7 +545,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) switch (playerclass) { case PC_SCOUT: - icon = HudIcons[playerclass+6].icon; + icon = ICON_SCOUT; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = SBAR.ScannerOn ? "Scanning" : "Offline"; @@ -555,7 +565,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_SNIPER: if (SBAR.SniperDam) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_SNIPER; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("Dam: ", ftos(SBAR.SniperDam)); @@ -572,7 +582,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_DEMOMAN: if (SBAR.IsDetpacking) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Setting"; @@ -583,7 +593,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } else if (SBAR.DetpackLeft) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat(ftos(SBAR.DetpackLeft), " secs left"); @@ -591,7 +601,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } break; case PC_MEDIC: - icon = HudIcons[playerclass+6].icon; + icon = ICON_MEDIC; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = SBAR.AuraActive ? "On" : "Off"; @@ -624,7 +634,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_HVYWEAP: if (SBAR.LockedCannon) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_HWGUY; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Assault Cannon Locked"; @@ -634,7 +644,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_SPY: if (SBAR.IsUndercover == 1) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_SPY; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.InvisOnly) @@ -652,7 +662,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } else if (SBAR.IsUndercover == 2) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_SPY; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.InvisOnly) @@ -699,7 +709,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) case PC_ENGINEER: if (SBAR.HasSentry) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(rint(SBAR.SentryHealth)), " S: ", ftos(rint(SBAR.SentryAmmoShells)), " R: ", ftos(rint(SBAR.SentryAmmoRockets))); @@ -707,7 +717,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } else if (SBAR.IsBuilding) { - icon = HudIcons[playerclass+6].icon; + icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat(ftos(SBAR.BuildingPercentage), "%"); @@ -719,7 +729,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) basepos = pos; if (SBAR.HasDispenser) { - icon = HudIcons[playerclass + 7].icon; + icon = ICON_ENGINEER_DISP; //HudIcons[playerclass + 7].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("H: ", ftos(rint(SBAR.DispenserHealth))); diff --git a/csqc/status.qc b/csqc/status.qc index 6bd514c2..faaae3b6 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -792,7 +792,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, - {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + //{"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; From eb5074154222efb63b780f61cff8fe932a8089f4 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 25 Aug 2020 00:11:01 +1200 Subject: [PATCH 1091/2474] fix civilian axe --- ssqc/weapons.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index aa8f2fe2..a1eb119e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2705,6 +2705,9 @@ float (entity pl) W_WeaponState_Check = { } void (float inp) W_ChangeWeapon = { + if(self.playerclass == PC_CIVILIAN) { + inp = 4; + } if (inp < 1 || inp > GetLastWeaponImpulse()) return; @@ -2720,6 +2723,9 @@ void (float inp) W_ChangeWeapon = { return; if (IsUsingOldImpulses()) { + if(self.playerclass == PC_CIVILIAN) { + inp = 1; + } // check for ammo if (! W_OldAmmoSlot(inp)) { W_AmmoError(); From c36e4a0da422aec265d98c6032fbdf9b68d336a7 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 25 Aug 2020 00:12:14 +1200 Subject: [PATCH 1092/2474] fix civilian axe --- ssqc/csmenu.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index a3783f8f..b7ac7775 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -38,6 +38,7 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { + sprint(pl, PRINT_HIGH, "ssendidng class menu\n"); //MEHT if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; if(!pl.playerclass) { From 32eab5c3a3ee9ea97b1ee65895faed3660d9b9e5 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 25 Aug 2020 00:25:49 +1200 Subject: [PATCH 1093/2474] hide civilian class menu --- csqc/events.qc | 3 +++ ssqc/csmenu.qc | 1 - ssqc/menu.qc | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index 727fdb65..fabb6434 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -199,6 +199,9 @@ void() CSQC_Parse_Event = { for(float i = 0; i < 10; i++) { if(civonly) { FO_MENU_CLASS.options[i].value = "-"; + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_CLASS) { + Menu_Cancel(); + } } else { float class_max = readfloat(); if(class_max < 0) { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index b7ac7775..a3783f8f 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -38,7 +38,6 @@ void UpdateClientClasses(entity pl, float team) = { } void UpdateClientMenu_Class(entity pl) = { - sprint(pl, PRINT_HIGH, "ssendidng class menu\n"); //MEHT if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; if(!pl.playerclass) { diff --git a/ssqc/menu.qc b/ssqc/menu.qc index bf452e66..330b0859 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -356,6 +356,7 @@ void (float update) Menu_Class = { local entity timer; if (TeamFortress_TeamIsCivilian(self.team_no)) { sprint(self, PRINT_HIGH, "Your team can only be civilians\n"); + UpdateClientClasses(self, self.team_no); Menu_Close(self); return; } From 034e93695c6be693432b268096b95f7e098e8b06 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 25 Aug 2020 23:44:32 +1200 Subject: [PATCH 1094/2474] allow hud_editor to hide off components --- csqc/csextradefs.qc | 3 ++- csqc/hud.qc | 36 +++++++++++++++++++++--------------- csqc/status.qc | 2 +- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 5d3623d0..106201c0 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -292,6 +292,7 @@ typedef struct { float Orientation; void(string panelid, float display, string text, string icon) drawPanel; string() getValue; + float Style; FO_Hud_Icons * Icon; float Snap; float Status; @@ -371,7 +372,7 @@ enum { HUD_PANEL_READY, HUD_PANEL_SHOWSCORES, HUD_PANEL_TEAM_SCORE, -// HUD_PANEL_MAP_MENU, + HUD_PANEL_MAP_MENU, HUD_PANEL_HUDOPTIONS, }; diff --git a/csqc/hud.qc b/csqc/hud.qc index 9fca80c6..32c4a3ac 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -483,12 +483,16 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string //if(ftextalign != selectedPanel.Orientation) { // Hud_Panels[Editor_SelectedPanel_Index].Orientation = ftextalign; //} - if(hud_button("hud_option_show_hide_toggle", pos + [4,74], [140, 20], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { + if(hud_button("hud_option_show_hide_toggle", pos + [4,74], [140, 16], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { Hud_Panels[Editor_SelectedPanel_Index].Display = !selectedPanel.Display; } drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [10,116], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); + + if(hud_button("hud_option_show_all_toggle", pos + [4,126], [140, 16], Hud_Panels[HUD_PANEL_HUDOPTIONS].Style ? "Show All" : "Hide Disabled")) { + Hud_Panels[HUD_PANEL_HUDOPTIONS].Style = !Hud_Panels[HUD_PANEL_HUDOPTIONS].Style; + } if(Hud_Panels[HUD_PANEL_HUDOPTIONS].Status) { Hud_DrawHudOptionsPanelSelector(); @@ -785,24 +789,26 @@ void Hud_Draw(float width, float height) { float offset = 0; for(float i = 0; i < Hud_Panels.length; i++) { - Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); if(sui_is_last_clicked(Hud_Panels[i].id)) { Editor_SelectedPanel_Index = i; } - //Draw panel names when editing - if(fo_hud_editor && Hud_Panels[i].id != "hudoptionspanel") { - switch (Hud_Panels[i].Orientation) { - case FO_HUD_INSERT_BEFORE: - offset = 2; - break; - case FO_HUD_INSERT_AFTER: - offset = Hud_Panels[i].FillSize.x - (strlen(Hud_Panels[i].Name) * 6) - 2; - break; - case FO_HUD_INSERT_MIDDLE: - offset = (Hud_Panels[i].FillSize.x / 2) - (strlen(Hud_Panels[i].Name) * 3); //because 3 = 6/2 - break; + if(!Hud_Panels[HUD_PANEL_HUDOPTIONS].Style || Hud_Panels[i].Display) { + Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); + //Draw panel names when editing + if(fo_hud_editor && Hud_Panels[i].id != "hudoptionspanel") { + switch (Hud_Panels[i].Orientation) { + case FO_HUD_INSERT_BEFORE: + offset = 2; + break; + case FO_HUD_INSERT_AFTER: + offset = Hud_Panels[i].FillSize.x - (strlen(Hud_Panels[i].Name) * 6) - 2; + break; + case FO_HUD_INSERT_MIDDLE: + offset = (Hud_Panels[i].FillSize.x / 2) - (strlen(Hud_Panels[i].Name) * 3); //because 3 = 6/2 + break; + } + drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); } - drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); } } diff --git a/csqc/status.qc b/csqc/status.qc index faaae3b6..6bd514c2 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -792,7 +792,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, - //{"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; From 6cb273753d1f8a70267bd8c45232165e0aac8c59 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 26 Aug 2020 08:21:39 +1200 Subject: [PATCH 1095/2474] grentimer icons, detpack command toggle --- csqc/csextradefs.qc | 6 ++++++ csqc/hud_helpers.qc | 4 ++-- csqc/status.qc | 4 ++-- ssqc/commands.qc | 9 +++++++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 106201c0..4c5a2608 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -155,6 +155,12 @@ FO_Hud_Icons HudIcons[29] = { {"textures/wad/anum_percent.png"} }; +FO_Hud_Icons GrenadeIcons[3] = { + {ICON_GREN1}, + {ICON_GREN1}, + {ICON_GREN2}, +}; + typedef struct { string ClipSize; float FragStreak; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index e76aa02d..5b3eb3a6 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -349,9 +349,9 @@ void AddGrenTimer(float grentype) { FO_Hud_Grentimers[i].grentype = grentype; FO_Hud_Grentimers[i].expires = time + 3.8; if(grentype == GR_TYPE_NORMAL) { - FO_Hud_Grentimers[i].icon_index = 4; + FO_Hud_Grentimers[i].icon_index = 1; } else { - FO_Hud_Grentimers[i].icon_index = 5; + FO_Hud_Grentimers[i].icon_index = 2; } break; } diff --git a/csqc/status.qc b/csqc/status.qc index 6bd514c2..640192cd 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -82,7 +82,7 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel DrawPanel.Scale = Scale * 0.8; DrawPanel.TextScale = TextScale * 0.8; } - Hud_DrawPanelLMP(panelid, ftos(timeleft), HudIcons[FO_Hud_Grentimers[i].icon_index].icon); + Hud_DrawPanelLMP(panelid, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon); DrawPanel.Position = DrawPanel.Position + [0, 24 * DrawPanel.Scale]; timercount++; } @@ -792,7 +792,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, - {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,0,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 4cd828fc..8e58e49b 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -586,13 +586,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Can't set detpacks while dead.\n"); break; } - if (arg2) { + if (arg2) { if(arg2 == "cancel") { TeamFortress_DetpackStop(); break; } if(self.is_detpacking) { - Menu_Demoman_Cancel(); + TeamFortress_DetpackStop(); +// Menu_Demoman_Cancel(); break; } local float farg2 = stof(arg2); @@ -602,6 +603,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } sprint(self, PRINT_HIGH, "Invalid choice. Please use integer values 5+.\n"); } else { + if(self.is_detpacking) { + Menu_Demoman_Cancel(); + break; + } Menu_Demoman(); } break; From c83935cf0009476352944c4794d425cf55ba5afb Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 27 Aug 2020 12:51:47 +1000 Subject: [PATCH 1096/2474] add trigger_jumppad so new features don't result in a floaty trigger_push in other mods --- ssqc/triggers.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index a239e258..2bad83b2 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -582,6 +582,11 @@ void trigger_push_setup() self.movedir = origin2; } +void () trigger_jumppad = { + self.classname = "trigger_push"; + trigger_push(); +}; + void () trigger_push = { if (CheckExistence() == FALSE) { dremove(self); From 215c6670f2b5c77d3fc73888dc56f5dbb3261eef Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 27 Aug 2020 12:54:16 +1000 Subject: [PATCH 1097/2474] make sure it compiles... --- ssqc/triggers.qc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 2bad83b2..b94e18dd 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -582,11 +582,6 @@ void trigger_push_setup() self.movedir = origin2; } -void () trigger_jumppad = { - self.classname = "trigger_push"; - trigger_push(); -}; - void () trigger_push = { if (CheckExistence() == FALSE) { dremove(self); @@ -623,6 +618,11 @@ void () trigger_push = { self.touch = trigger_push_touch; }; +void () trigger_jumppad = { + self.classname = "trigger_push"; + trigger_push(); +}; + void () trigger_monsterjump_touch = { if ((other.flags & (FL_MONSTER | FL_FLY | FL_SWIM)) != FL_MONSTER) return; From 4c24b803140822a933bb82a356e90218f06b68c0 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 30 Aug 2020 12:51:14 +1000 Subject: [PATCH 1098/2474] take out new fo IC, make airblast length longer --- share/defs.h | 2 +- ssqc/pyro.qc | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/share/defs.h b/share/defs.h index 4663b9cc..cff4470f 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1048,7 +1048,7 @@ #define PC_PYRO_GRENADE_MAX_2 4 #define PC_PYRO_TF_ITEMS 0 #define PC_PYRO_AIRBLAST_RANGE 400 -#define PC_PYRO_AIRBLAST_COOLDOWN 3 +#define PC_PYRO_AIRBLAST_COOLDOWN 5 #define PC_PYRO_LAVA_LIFETIME 3 #define PC_PYRO_LAVA_RETICK 1.2 #define PC_PYRO_FLAMETHROWER_DAM_FO 15 diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 91533902..e15d79d8 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -740,7 +740,8 @@ void () T_IncendiaryTouch = { IncendiaryRadius_OZTF(); break; case PYRO_FO: - IncendiaryRadius_FO(); + //IncendiaryRadius_FO(); + IncendiaryRadius_OZTF(); break; } }; @@ -824,6 +825,9 @@ void () UseAirBlast = { { if (ent.movetype == MOVETYPE_NONE) continue; + + if (ent == self) + continue; if (visible(ent)) { From d2a271fab072b715959f5a80c65d1b3c60cc6fea Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 30 Aug 2020 12:52:30 +1000 Subject: [PATCH 1099/2474] default fo pyro to on --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 68c6644a..ed26553a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -590,7 +590,7 @@ void () DecodeLevelParms = { detpack_when_reloading = CF_GetSetting("detreload", "detpack_while_reloading", "off"); // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass - pyro_type = CF_GetSetting("pyrotype", "pyro_type", "1"); + pyro_type = CF_GetSetting("pyrotype", "pyro_type", "2"); // ceasefire type - 0: default; 1: pause ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); From 7e2285a2cf6bf3affd31f8dc242148d691f9a822 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 30 Aug 2020 12:56:11 +1000 Subject: [PATCH 1100/2474] reduce hwguy mirvs to 1 --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index cff4470f..a49a07e2 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1013,7 +1013,7 @@ #define PC_HVYWEAP_GRENADE_INIT_1 4 #define PC_HVYWEAP_GRENADE_INIT_2 1 #define PC_HVYWEAP_GRENADE_MAX_1 4 -#define PC_HVYWEAP_GRENADE_MAX_2 2 +#define PC_HVYWEAP_GRENADE_MAX_2 1 #define PC_HVYWEAP_TF_ITEMS 0 #define PC_HVYWEAP_PROJSPEED 3000 #define PC_HVYWEAP_ASSCAN_CLIPSIZE 100 From bea531d80f6c95927d1b3e1a3c3047b450f6bada Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 30 Aug 2020 13:29:26 +1000 Subject: [PATCH 1101/2474] fix loop never ending --- ssqc/pyro.qc | 104 +++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index e15d79d8..9a5f022a 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -826,63 +826,63 @@ void () UseAirBlast = { if (ent.movetype == MOVETYPE_NONE) continue; - if (ent == self) - continue; - - if (visible(ent)) - { - switch (ent.classname) + if (ent != self) + { + if (visible(ent)) { - case "player": - case "pyro_rocket": - case "flamerflame": - case "proj_tranq": - case "proj_bullet": - case "proj_rocket": - case "grenade": - case "spike": - case "pipebomb": - vector targorg; - targorg = ent.origin; - float pushval = 1000; - if (ent == self) - { - pushval = 500; - traceline(self.origin, self.origin + v_forward * 200, MOVE_NOMONSTERS, self); - if (trace_fraction < 1) + switch (ent.classname) + { + case "player": + case "pyro_rocket": + case "flamerflame": + case "proj_tranq": + case "proj_bullet": + case "proj_rocket": + case "grenade": + case "spike": + case "pipebomb": + vector targorg; + targorg = ent.origin; + float pushval = 1000; + if (ent == self) { - targorg = self.origin - (v_forward * 200 * trace_fraction); + pushval = 500; + traceline(self.origin, self.origin + v_forward * 200, MOVE_NOMONSTERS, self); + if (trace_fraction < 1) + { + targorg = self.origin - (v_forward * 200 * trace_fraction); + } } - } - - vector delta = targorg - self.origin; - float dist = vlen(delta); - float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; - - if (ent.flags & FL_ONGROUND) - { - if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted + + vector delta = targorg - self.origin; + float dist = vlen(delta); + float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; + + if (ent.flags & FL_ONGROUND) { - setorigin(ent, ent.origin + '0 0 1'); + if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted + { + setorigin(ent, ent.origin + '0 0 1'); + } } - } - - delta = normalize(delta); - delta = delta * percent * pushval; - - if (ent.movetype == MOVETYPE_FLYMISSILE) - { - float speed = vlen(ent.velocity); - ent.velocity = normalize(delta) * speed; - } - else - { - ent.velocity = ent.velocity + delta; - } - - break; - } - } + + delta = normalize(delta); + delta = delta * percent * pushval; + + if (ent.movetype == MOVETYPE_FLYMISSILE) + { + float speed = vlen(ent.velocity); + ent.velocity = normalize(delta) * speed; + } + else + { + ent.velocity = ent.velocity + delta; + } + + break; + } + } + } ent = ent.chain; } From 0990c3956dd9d1ab1e5293c2ab6fb7dc5c2205e7 Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 30 Aug 2020 13:32:10 +1000 Subject: [PATCH 1102/2474] fix another game crashing loop! --- ssqc/pyro.qc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 9a5f022a..33558c93 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -823,10 +823,7 @@ void () UseAirBlast = { ent = findradius(self.origin, PC_PYRO_AIRBLAST_RANGE); while (ent) { - if (ent.movetype == MOVETYPE_NONE) - continue; - - if (ent != self) + if (ent.movetype != MOVETYPE_NONE && ent != self) { if (visible(ent)) { From b8c61c3df3d65e4c93a2afa5db3b650173ae62ca Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 30 Aug 2020 18:35:07 +1000 Subject: [PATCH 1103/2474] Don't include filenames in mvd and stats --- ssqc/clan.qc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 2440f561..4f4946d7 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -241,12 +241,6 @@ string () GetGameFileName = { str = strcat(str, "_["); str = strcat(str, mapname); str = strcat(str, "]_"); - - if (GetPlayerCount() < 9) { - str = strcat(str, GetPlayersName()); - str = clearString(str); - return str; - } while ((i < number_of_teams)) { From 0a1d5f40c2b8f7361e5c7a1396fbebe8032a603c Mon Sep 17 00:00:00 2001 From: danni Date: Sun, 30 Aug 2020 21:42:17 +1000 Subject: [PATCH 1104/2474] revert attack speed nerf on pyro --- ssqc/weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 614def48..fe5b1eda 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2079,7 +2079,8 @@ void () W_Attack = { Attack_Finished(0.9); break; case PYRO_FO: - Attack_Finished(PC_PYRO_LAVA_RETICK); + //Attack_Finished(PC_PYRO_LAVA_RETICK); + Attack_Finished(0.9); break; } } else if (time >= self.antispam_incendiary_cannon) { From efb6a8fe914d832c7da913242b9b0986ee4f1e90 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Mon, 31 Aug 2020 23:56:50 +1200 Subject: [PATCH 1105/2474] no decimals on disp health --- ssqc/actions.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 3fad7de8..03d9b96b 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -209,14 +209,14 @@ void (entity pe_player) FO_Spectator_Identify = { } else if(trace_ent.classname == "building_sentrygun") { s_id_string = strcat(trace_ent.real_owner.netname, "'s Sentry Gun (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); s_id_string = strcat(s_id_string, "\sLevel:\s ", ftos(trace_ent.weapon), "\n"); - s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(rint(trace_ent.health)), "\n"); } else if(trace_ent.classname == "building_sentrygun_base") { s_id_string = strcat(trace_ent.real_owner.netname, "'s Sentry Gun (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); s_id_string = strcat(s_id_string, "\sLevel:\s ", ftos(trace_ent.oldenemy.weapon), "\n"); - s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.oldenemy.health), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(rint(trace_ent.oldenemy.health)), "\n"); } else if(trace_ent.classname == "building_dispenser") { s_id_string = strcat(trace_ent.real_owner.netname, "'s Dispenser (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); - s_id_string = strcat(s_id_string, "\sH:\s ", ftos(trace_ent.health), "\n"); + s_id_string = strcat(s_id_string, "\sH:\s ", ftos(rint(trace_ent.health)), "\n"); } else if(trace_ent.classname == "detpack") { s_id_string = strcat(trace_ent.owner.netname, "'s Detpack (", TeamFortress_TeamGetColorString(trace_ent.team_no), ")\n"); s_id_string = strcat(s_id_string, "\sTime Left:\s ", ftos(trace_ent.detpack_left), " seconds\n"); From 2d124d6d73457fd86a7afb1da6fba8b6a775f9bc Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 1 Sep 2020 22:29:00 +1200 Subject: [PATCH 1106/2474] fizzle flamethrower on first hit --- ssqc/pyro.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 33558c93..ded907e0 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -427,6 +427,7 @@ void () Flamer_stream_touch = { float flamehealth = 45; SetOnFire(other, self.owner, self.origin, flamehealth); + dremove(self); } } else { if ((random() < 0.3) || From 5ad2798524558ea8ec0bedd17f6b6b4d6bf94a37 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 6 Sep 2020 15:21:17 -0300 Subject: [PATCH 1107/2474] added toggle server_sbflaginfo to disable sbar flaginfo server-side (default: enabled) --- README.md | 2 +- ssqc/client.qc | 3 +++ ssqc/qw.qc | 1 + ssqc/status.qc | 58 ++++++++++++++++++++++++++++---------------------- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index dc22523f..00ee1a01 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ New features * Any non-valid impulse now closes the active menu. * Option to allow a demoman to place a detpack while reloading his weapon `localinfo detreload on` * Pyro types - `localinfo pyro_type val` - 0 = original tf2.9, 1 = oztf pyro style, 2 = FO pyro style - +* localinfo server_sbflaginfo : 0 - disables sbar flaginfo, 1 enables it [default: 1] == Removed === * Removed weapon messages for weapons without weapon modes. diff --git a/ssqc/client.qc b/ssqc/client.qc index ed26553a..cf800ac4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -697,6 +697,9 @@ void () DecodeLevelParms = { // disable hit sounds [off] nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); + // enable server-side flaginfo on statusbar [on] + server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 27b410bf..736772d8 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -588,6 +588,7 @@ float fo_flashtime; float solid_nailgren; float noreturn; float nohitsounds; +float server_sbflaginfo; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/status.qc b/ssqc/status.qc index b6265d02..81e3c2e4 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1099,42 +1099,45 @@ void (entity pl) RefreshStatusBar = { UpdateClientIDString(pl); // flag info - if (tfdet) + if (server_sbflaginfo) { - for (float t = 1; t <= number_of_teams; t++) + if (tfdet) { - switch (t) + for (float t = 1; t <= number_of_teams; t++) { - case 1: - te = Finditem(tfdet.display_item_status1); - break; - case 2: - te = Finditem(tfdet.display_item_status2); - break; - case 3: - te = Finditem(tfdet.display_item_status3); - break; - case 4: - te = Finditem(tfdet.display_item_status4); - break; - } + switch (t) + { + case 1: + te = Finditem(tfdet.display_item_status1); + break; + case 2: + te = Finditem(tfdet.display_item_status2); + break; + case 3: + te = Finditem(tfdet.display_item_status3); + break; + case 4: + te = Finditem(tfdet.display_item_status4); + break; + } - if (te) - { - UpdateClientFlagStatus(pl, te); + if (te) + { + UpdateClientFlagStatus(pl, te); + } } } - } - tg = find(world, classname, "info_tfgoal"); - while (tg) { - if (tg.track_goal) { - UpdateClientButtonStatus(pl, tg); + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.track_goal) { + UpdateClientButtonStatus(pl, tg); + } + tg = find(tg, classname, "info_tfgoal"); } - tg = find(tg, classname, "info_tfgoal"); } } - else // no csqc but has sbflaginfo on + else if (server_sbflaginfo) // no csqc but has sbflaginfo on and server_sbflaginfo is enabled { ct = ""; i = number_of_teams; // Extra newlines @@ -1198,6 +1201,9 @@ void (entity pl) RefreshStatusBar = { ct = strzone(ct); } + else { + ct = strzone("\n\n\n\n\n\n"); + } } if (!csqcactive) From a5671967573cabc80eea6d4a26f1351116debd1f Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 6 Sep 2020 16:44:58 -0300 Subject: [PATCH 1108/2474] preventing flag/button icons appearing when server_sbflaginfo is disabled --- ssqc/status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 81e3c2e4..f815cb0e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -583,7 +583,7 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5, string s string getLocationName(vector location); void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { - if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE) || !server_sbflaginfo) return; //float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); //if(csqcactive) { From a33a984bcc16989ae84befce20a6c60c2f9b1357 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Mon, 7 Sep 2020 15:17:28 -0300 Subject: [PATCH 1109/2474] adding possibility to exchange cap point and flag spawn locations --- ssqc/client.qc | 46 +++++++++++++++++++++++++++++++++++++++++++++- ssqc/qw.qc | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index cf800ac4..9b8959a3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -220,7 +220,8 @@ void () DecodeLevelParms = { local string st; local entity ent; - local entity te; + local entity te, tg; + local vector teoriginbkp; if (serverflags) if (world.model == "maps/start.bsp") @@ -700,6 +701,49 @@ void () DecodeLevelParms = { // enable server-side flaginfo on statusbar [on] server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); + reverse_cap = CF_GetSetting("rcap","reverse_cap", "0"); + + if (reverse_cap) { + te = world; + ent = find(world, classname, "info_tfdetect"); + for (float t = 1; t <= number_of_teams; t++) { + switch (t) + { + case 1: + te = Finditem(ent.display_item_status1); + break; + case 2: + te = Finditem(ent.display_item_status2); + break; + case 3: + te = Finditem(ent.display_item_status3); + break; + case 4: + te = Finditem(ent.display_item_status4); + break; + } + + if (te) { + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.items_allowed == te.goal_no) { + teoriginbkp = te.origin; + + te.oldorigin = tg.origin; + te.origin = tg.origin; + setsize(te, te.goal_min, te.goal_max); + + tg.oldorigin = teoriginbkp; + tg.origin = teoriginbkp; + setsize(tg, tg.mins, tg.maxs); + } + tg = find(tg, classname, "info_tfgoal"); + } + } + } + } + + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 736772d8..7c18bc5b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -589,6 +589,7 @@ float solid_nailgren; float noreturn; float nohitsounds; float server_sbflaginfo; +float reverse_cap; float numlocs; typedef struct {vector pos; string desc;} loc_t; From 5d22c9b3fcdbd31481ef54c90197a767a5c5f54a Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Mon, 7 Sep 2020 15:21:14 -0300 Subject: [PATCH 1110/2474] updating readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 00ee1a01..3927ec32 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ New features * Option to allow a demoman to place a detpack while reloading his weapon `localinfo detreload on` * Pyro types - `localinfo pyro_type val` - 0 = original tf2.9, 1 = oztf pyro style, 2 = FO pyro style * localinfo server_sbflaginfo : 0 - disables sbar flaginfo, 1 enables it [default: 1] +* localinfo reverse_cap : 0 - normal gameplay, 1: you have to take your flag and capture in the enemy base [default: 0] == Removed === * Removed weapon messages for weapons without weapon modes. From 801c3e6475a2482ae0add12da804ff8fd04c5c5c Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Mon, 7 Sep 2020 15:31:40 -0300 Subject: [PATCH 1111/2474] extracting function for better readability --- ssqc/client.qc | 89 +++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 9b8959a3..0a84f417 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -64,6 +64,7 @@ string(float)TeamFortress_TeamGetColorString; void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options; float (float tno) TeamFortress_TeamGetLives; +void () InitReverseCap; string nextmap; @@ -220,8 +221,7 @@ void () DecodeLevelParms = { local string st; local entity ent; - local entity te, tg; - local vector teoriginbkp; + local entity te; if (serverflags) if (world.model == "maps/start.bsp") @@ -703,44 +703,9 @@ void () DecodeLevelParms = { reverse_cap = CF_GetSetting("rcap","reverse_cap", "0"); - if (reverse_cap) { - te = world; - ent = find(world, classname, "info_tfdetect"); - for (float t = 1; t <= number_of_teams; t++) { - switch (t) - { - case 1: - te = Finditem(ent.display_item_status1); - break; - case 2: - te = Finditem(ent.display_item_status2); - break; - case 3: - te = Finditem(ent.display_item_status3); - break; - case 4: - te = Finditem(ent.display_item_status4); - break; - } - - if (te) { - tg = find(world, classname, "info_tfgoal"); - while (tg) { - if (tg.items_allowed == te.goal_no) { - teoriginbkp = te.origin; - - te.oldorigin = tg.origin; - te.origin = tg.origin; - setsize(te, te.goal_min, te.goal_max); - - tg.oldorigin = teoriginbkp; - tg.origin = teoriginbkp; - setsize(tg, tg.mins, tg.maxs); - } - tg = find(tg, classname, "info_tfgoal"); - } - } - } + if (reverse_cap) + { + InitReverseCap(); } @@ -3411,6 +3376,50 @@ float () GetLastWeaponImpulse = { return 4; } +void () InitReverseCap = { + local entity te = world, tg, tfdet; + local vector originbkp; + + te = world; + tfdet = find(world, classname, "info_tfdetect"); + for (float t = 1; t <= number_of_teams; t++) { + switch (t) + { + case 1: + te = Finditem(tfdet.display_item_status1); + break; + case 2: + te = Finditem(tfdet.display_item_status2); + break; + case 3: + te = Finditem(tfdet.display_item_status3); + break; + case 4: + te = Finditem(tfdet.display_item_status4); + break; + } + + if (te) { + tg = find(world, classname, "info_tfgoal"); + while (tg) { + if (tg.items_allowed == te.goal_no) { + originbkp = te.origin; + + te.oldorigin = tg.origin; + te.origin = tg.origin; + setsize(te, te.goal_min, te.goal_max); + + tg.oldorigin = originbkp; + tg.origin = originbkp; + setsize(tg, tg.mins, tg.maxs); + } + tg = find(tg, classname, "info_tfgoal"); + } + } + } + +} + // this is to fix hack used to avoid fall damage, it currently breaks pm_airstep /* void() SV_RunClientCommand = { From 12ac81bc7d00bc965455fc2aaac78fe6df4c624d Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 10 Sep 2020 09:54:15 +1000 Subject: [PATCH 1112/2474] add some info around extra entity fields/types --- docs/tfentref.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/tfentref.txt b/docs/tfentref.txt index 4b3fbb66..5324aec0 100644 --- a/docs/tfentref.txt +++ b/docs/tfentref.txt @@ -1216,6 +1216,16 @@ func_button / func_door This works the same as info_tfgoal except for obvious variables such as "model". Additional Bitfields: goal_activation 8 : only activated when hit by an engineer's spanner + forcecloseonblock 1 : when blocked by a player or item, keep attempting to close + +trigger_push + This can now be paired with a targetname of a point entity called target_position - this will create Q3 style jumppads + spawnflags: 2 : include TFItems (So flags can be affected) + 4 : exclude "other" (So only TFItems are affected) + 8 : "no noise" make sure no default noise is added + +trigger_jumppad + Rename of trigger_push, can be used to allow for "Fortress One" only trigger_push entities that won't be misinterpreted by other fortress mods OTHER ENTITIES Most Quake entities work the same as info_tfgoal except From f8ab02c9005239323c56944c3817e6e3a9194a71 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Thu, 10 Sep 2020 00:14:33 -0300 Subject: [PATCH 1113/2474] creating huetf preset, moving round_delay_time from quadmode to default --- ssqc/client.qc | 44 ++++++++++++++++++++++++++++++++++++++++++++ ssqc/commands.qc | 2 +- ssqc/qw.qc | 1 + ssqc/tfort.qc | 3 +++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 0a84f417..9667c109 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -662,6 +662,9 @@ void () DecodeLevelParms = { vote_threshold = 0.5; } + //default round interval for quadmode (seconds) + localcmd ("localinfo round_delay_time 30\n"); + // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); @@ -852,6 +855,47 @@ void () DecodeLevelParms = { solid_nailgren = TRUE; } + st = infokey(world, "huetf"); + if (st == "on") { + server_huetf = TRUE; + impulse_queue = TRUE; + chweap_wait_attfinished = FALSE; + flag_follow = FALSE; + ng_velocity = 1000; + ng_damage = 18; + sng_damage = 26; + old_ng_rof = TRUE; + scoutdash = FALSE; + fo_flash = FALSE; + nailgren_type = NGR_TYPE_DEFAULT; + Role_None.detpipe_limit = 7; + detpipe_limit_world = 7; + medicaura = FALSE; + medicnocuss = FALSE; + pyro_type = 1; + drop_grenades = FALSE; + drop_grenpack = FALSE; + drop_gren1 = 0; + drop_gren2 = 0; + cussgrentime = 19; + spawnfull = FALSE; + stockfull = FALSE; + stock_on_cap = FALSE; + stock_reload = FALSE; + classtips = FALSE; + nohitsounds = TRUE; + detpack_when_reloading = TRUE; + old_hp_armor = TRUE; + server_sbflaginfo = FALSE; + solid_detpack = TRUE; + walls_block_emp = FALSE; + grentimers = FALSE; + Role_None.gren2_limits[1] = 3; + Role_None.gren2_limits[3] = 2; + Role_None.gren2_limits[4] = 4; + Role_None.gren2_limits[5] = 3; + Role_None.gren2_limits[8] = 3; + } } if (parm11) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 8e58e49b..653ad657 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -53,7 +53,6 @@ void () QuadMode = localcmd ("localinfo rounds 2\n"); localcmd ("timelimit 0\n"); localcmd ("localinfo round_time 10\n"); - localcmd ("localinfo round_delay_time 30\n"); localcmd ("localinfo teamfrags on\n"); localcmd ("localinfo fullteamscore off\n"); localcmd ("fraglimit 0\n"); @@ -71,6 +70,7 @@ void () ClanMode = localcmd ("localinfo rd 0\n"); localcmd ("localinfo votemode 0\n"); localcmd ("localinfo vote_style 2\n"); + localcmd ("localinfo rounds 0\n"); localcmd ("exec fo_clanmode.cfg\n"); bprint(PRINT_HIGH, "Clan Mode set to on\n"); bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 7c18bc5b..060c887c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -559,6 +559,7 @@ float sniperreloadpercent; float buildstatus; float server_default; float server_faithful; +float server_huetf; float old_spanner; float old_dispenser; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3adc9f31..15095e7a 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -724,6 +724,9 @@ void () TeamFortress_ShowTF = { } else if (server_default) { sprint(self, PRINT_HIGH, "\nThis server is running default FortressOne Server settings.\n"); } + else if (server_huetf) { + sprint(self, PRINT_HIGH, "\nThis server is running HueTF FortressOne Server settings.\n"); + } }; void () TeamFortress_GrenadePrimed; From 9f8e4f7cb9ea1ea557970d2c1bfefd255cd6291b Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 12 Sep 2020 19:43:00 +1200 Subject: [PATCH 1114/2474] fix csqc flagstatusinit on map change --- ssqc/client.qc | 7 ++++--- ssqc/qw.qc | 2 +- ssqc/status.qc | 30 ++++++++++++++---------------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 9667c109..c2d87da8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -702,8 +702,8 @@ void () DecodeLevelParms = { nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); // enable server-side flaginfo on statusbar [on] - server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); - +// server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); + reverse_cap = CF_GetSetting("rcap","reverse_cap", "0"); if (reverse_cap) @@ -886,7 +886,8 @@ void () DecodeLevelParms = { nohitsounds = TRUE; detpack_when_reloading = TRUE; old_hp_armor = TRUE; - server_sbflaginfo = FALSE; + //server_sbflaginfo = FALSE; + localcmd("localinfo server_sbflaginfo 0\n"); solid_detpack = TRUE; walls_block_emp = FALSE; grentimers = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 060c887c..50ba81a4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -589,7 +589,7 @@ float fo_flashtime; float solid_nailgren; float noreturn; float nohitsounds; -float server_sbflaginfo; +//float server_sbflaginfo; float reverse_cap; float numlocs; diff --git a/ssqc/status.qc b/ssqc/status.qc index f815cb0e..ebff41a6 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -583,21 +583,19 @@ void (entity pl, string s1, string s2, string s3, string s4, string s5, string s string getLocationName(vector location); void (entity Player, float index, entity Item, float icon) InitClientFlagStatus = { - if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE) || !server_sbflaginfo) + if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE) || !CF_GetSetting("ssbfi", "server_sbflaginfo", "1")) { return; - //float csqcactive = infokeyf(Player, INFOKEY_P_CSQCACTIVE); - //if(csqcactive) { - msg_entity = Player; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_FLAGINFOINIT); - WriteFloat(MSG_MULTICAST, index); - WriteFloat(MSG_MULTICAST, Item.goal_no); - WriteString(MSG_MULTICAST, Item.mdl); - WriteFloat(MSG_MULTICAST, Item.skin); - WriteFloat(MSG_MULTICAST, Item.owned_by); - WriteFloat(MSG_MULTICAST, icon); - multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); - //} + } + msg_entity = Player; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAGINFOINIT); + WriteFloat(MSG_MULTICAST, index); + WriteFloat(MSG_MULTICAST, Item.goal_no); + WriteString(MSG_MULTICAST, Item.mdl); + WriteFloat(MSG_MULTICAST, Item.skin); + WriteFloat(MSG_MULTICAST, Item.owned_by); + WriteFloat(MSG_MULTICAST, icon); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } void (entity Player) InitAllStatuses = { @@ -1099,7 +1097,7 @@ void (entity pl) RefreshStatusBar = { UpdateClientIDString(pl); // flag info - if (server_sbflaginfo) + if (CF_GetSetting("ssbfi", "server_sbflaginfo", "1")) { if (tfdet) { @@ -1137,7 +1135,7 @@ void (entity pl) RefreshStatusBar = { } } } - else if (server_sbflaginfo) // no csqc but has sbflaginfo on and server_sbflaginfo is enabled + else if (CF_GetSetting("ssbfi", "server_sbflaginfo", "1")) // no csqc but has sbflaginfo on and server_sbflaginfo is enabled { ct = ""; i = number_of_teams; // Extra newlines From b76456bada3d57e3edd40254c6401643f107619f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 13 Sep 2020 21:51:37 +1200 Subject: [PATCH 1115/2474] stop saying ready up when game over --- csqc/status.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/csqc/status.qc b/csqc/status.qc index 640192cd..7a80d9df 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -348,6 +348,8 @@ void(string panelid, float display, string text, string icon) drawReadyPanel = { if(SBAR.Ready) { message = "Ready"; textcolour = MENU_TEXT_GREEN; + } else if(round_over) { + message = "Change map to continue playing"; } else { tokenize(findkeysforcommand("ready")); string keynum = argv(0); @@ -792,7 +794,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, - {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,0,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; From f17b4cdd3b97cd74acac7b6cebcd7f8957218b55 Mon Sep 17 00:00:00 2001 From: John Hwee Date: Wed, 23 Sep 2020 20:57:43 -0400 Subject: [PATCH 1116/2474] allow "on" value for setinfo ec --- ssqc/tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 46fd4498..05a537fd 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -3124,7 +3124,7 @@ void (entity p) TeamFortress_ExecClassScript = { if (st == string_null) st = infokey(p, "exec_class"); - if (st == "1") { + if (st == "1" || st == "on") { if (p.playerclass == PC_SCOUT) stuffcmd(p, "exec scout.cfg\n"); else if (p.playerclass == PC_SNIPER) From adb944ce5c73a7696227702dd2db019ba40e2d03 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 24 Sep 2020 20:07:12 +1200 Subject: [PATCH 1117/2474] cmd votemap works for all maps now --- ssqc/vote.qc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 63680d66..8c5a7668 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1420,6 +1420,14 @@ void () StartVoting = { void (entity p, string vote) VoteForMap = { + float filehandle; + filehandle = fopen(strcat("maps/",vote,".bsp"), FILE_READ); + if (filehandle >= 0) { + AddVoteMap(vote,"Custom vote","Custom Vote",0,0,0); + fclose(filehandle); + } else { + sprint(p, PRINT_HIGH, "\bUnfortunately, \b", vote, "\b doesn't appear to be a valid map.\nUse \bcmd listmaps\b to for a list of valid maps.\b\n"); + } local entity mc = find(world, classname, "map_candidate"); while(mc) { if(mc.netname == vote) { @@ -1444,7 +1452,6 @@ void (entity p, string vote) VoteForMap = { } mc = find(mc, classname, "map_candidate"); } - sprint(p, PRINT_HIGH, "\bUnfortunately, \b", vote, "\b doesn't appear to be a valid map.\nUse \bcmd listmaps\b to for a list of valid maps.\b\n"); }; void (entity p) UnvoteForMap = { From 0ce931e3c6504f851c658c6a1edc7727f3f0d189 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 24 Sep 2020 20:35:02 +1200 Subject: [PATCH 1118/2474] replace \[ with \x10 and 11 --- ssqc/commands.qc | 8 ++++---- ssqc/functions.qc | 2 +- ssqc/menu.qc | 20 ++++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 8e58e49b..c33cc8d5 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -134,7 +134,7 @@ void (entity pe) SetEquipmentForPlayer = { void (float cap1, float cap2) CaptainMode = { captainmode = 1; - bprint(PRINT_HIGH, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); + bprint(PRINT_HIGH, "\x10\sCaptain Mode\s\x11\s:\s All available players are now Observers\n"); local string st = 0; local float userid = 0, csqcactive = 0; local entity oldself;// = self; @@ -172,7 +172,7 @@ void (float cap1, float cap2) CaptainMode = { //stuffcmd(self, "\n"); //SetTeamName(self); } - bprint(PRINT_HIGH, "\[\sCaptain Mode\s\]\s:\s "); + bprint(PRINT_HIGH, "\x10\sCaptain Mode\s\x11\s:\s "); bprint(PRINT_HIGH, te.netname); bprint(PRINT_HIGH, " \bis the captain for team\b "); bprint(PRINT_HIGH, TeamToString(te.team_no)); @@ -262,7 +262,7 @@ void (entity cap, float pick) CaptainPick = { sprint(self, PRINT_HIGH, picked.netname ," has already been picked!\n"); return; } - bprint(PRINT_HIGH, "\[\bCaptain Mode\b\]\b:\b "); + bprint(PRINT_HIGH, "\x10\bCaptain Mode\b\x11\b:\b "); bprint(PRINT_HIGH, picked.netname); bprint(PRINT_HIGH, " \bcalled\b "); bprint(PRINT_HIGH, cap.netname); @@ -277,7 +277,7 @@ void (entity cap, float pick) CaptainPick = { sprint(self, PRINT_HIGH, "Sorry, couldn't pick ", picked.netname ,"\n"); } if(!countleft) { - bprint(PRINT_HIGH, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s\n"); + bprint(PRINT_HIGH, "\x10\sCaptain Mode\s\x11\s:\s \sTeams are set, let's start the game!\s\n"); StopCaptainMode(cap, othercap); } } diff --git a/ssqc/functions.qc b/ssqc/functions.qc index 8879831b..f9aaa892 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -58,7 +58,7 @@ void () nextCaptain = { void () disableCaptain = { captainmode = 0; - bprint(2, "\[\sCaptain Mode\s\]\s:\s Captain Mode Disabled!\n"); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s Captain Mode Disabled!\n"); }; void () randomizeCaptains = { diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 330b0859..104216e3 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1365,7 +1365,7 @@ void () Menu_Admin = s_menu1 = "Captain Team 2 Select Menu: \n\n"; break; case ADMIN_MENU_TYPE_CAPTAINSELECT: - s_menu1 = strcat(Q"\[\sCaptain\s\] Team ", ftos(self.team_no)); + s_menu1 = strcat(Q"\x10\sCaptain\s\x11 Team ", ftos(self.team_no)); s_menu1 = strcat(s_menu1, " : \n\n"); break; case ADMIN_MENU_TYPE_CLASSES: @@ -1464,7 +1464,7 @@ void () Menu_Admin = } if (f_tmp == 0 && ( self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO ) ) { - bprint(2, "\[\sCaptain Mode\s\]\s:\s \sTeams are set, let's start the game!\s\n"); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s \sTeams are set, let's start the game!\s\n"); temp = self; te = find (world, classname, "player"); while (te != world) { @@ -1555,10 +1555,10 @@ void (float inp) Menu_Admin_Input = self.current_menu_type = ADMIN_MENU_TYPE_CAPTAINTEAMONE; self.current_menu_page = 1; - bprint(2, "\[\sCaptain Mode\s\]\s:\s is now \sON\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); - bprint(2, "\[\sCaptain Mode\s\]\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s is now \sON\s.\n"); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s ONLY CAPTAINS CAN TALK! YOU ARE ALL \sMUTED\s.\n"); temp = find (world, classname, "player"); while (temp != world) { @@ -1738,7 +1738,7 @@ void (float inp) Menu_Admin_Input = //TeamFortress_TeamSet(self.team_no); self.playerclass = 0; playerSetTeam(self.team_no); - bprint(2, "\[\sCaptain Mode\s\]\s:\s "); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s "); bprint(2, self.netname); bprint(2, " \bIs the captain for team\b "); bprint(2, TeamToString(self.team_no)); @@ -1747,7 +1747,7 @@ void (float inp) Menu_Admin_Input = te = find (te, classname, "player"); } self = temp; - bprint(2, "\[\sCaptain Mode\s\]\s:\s All available players are now Observers\n"); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s All available players are now Observers\n"); Menu_Close(self); self.current_menu_type = ADMIN_MENU_TYPE_MAIN; self.current_menu_page = 1; @@ -1763,7 +1763,7 @@ void (float inp) Menu_Admin_Input = playerSetTeam (temp.team_no); - bprint(2, "\[\bCaptain Mode\b\]\b:\b "); + bprint(2, "\x10\bCaptain Mode\b\x11\b:\b "); bprint(2, temp.netname); bprint(2, " \bcalled\b "); bprint(2, self.netname); @@ -1864,7 +1864,7 @@ void (float inp) Menu_Admin_Input = if (inp == 10) { if (self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE) { captainmode = 0; - bprint(2, "\[\sCaptain Mode\s\]\s:\s \scanceled by request of\s "); + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s \scanceled by request of\s "); bprint(2, self.netname); bprint(2, ".\n"); te = self; From 5d32e22430d53eee738b1fbdb1f28c445d32549a Mon Sep 17 00:00:00 2001 From: John Hwee Date: Thu, 24 Sep 2020 06:14:13 -0400 Subject: [PATCH 1119/2474] Use helper function to get user info --- ssqc/tfort.qc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 05a537fd..21f43b23 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -3118,13 +3118,9 @@ void (entity pl, float fr) TF_AddFrags = { }; void (entity p) TeamFortress_ExecClassScript = { - local string st; - - st = infokey(p, "ec"); - if (st == string_null) - st = infokey(p, "exec_class"); + local float st = FO_GetUserSetting(p, "ec", "exec_class", "off"); - if (st == "1" || st == "on") { + if (st) { if (p.playerclass == PC_SCOUT) stuffcmd(p, "exec scout.cfg\n"); else if (p.playerclass == PC_SNIPER) @@ -3147,13 +3143,9 @@ void (entity p) TeamFortress_ExecClassScript = { }; void (entity p) TeamFortress_ExecMapScript = { - local string st; - - st = infokey(p, "em"); - if (st == string_null) - st = infokey(p, "exec_map"); + local float st = FO_GetUserSetting(p, "em", "exec_map", "off"); - if (st == "1") { + if (st) { stuffcmd(p, "exec maps/default.cfg\n"); stuffcmd(p, "exec maps/"); stuffcmd(p, mapname); From 31aff74029eb639bdeb6205997c70f81f95f4f05 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 27 Sep 2020 22:36:37 +1300 Subject: [PATCH 1120/2474] some things --- csqc/csextradefs.qc | 1 + csqc/csprogs.src | 2 +- csqc/hud.qc | 2 +- csqc/main.qc | 21 ++++++++++++++++----- csqc/status.qc | 6 +++--- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 4c5a2608..407cca79 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -82,6 +82,7 @@ float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown float jump_counter; float frames_since_onground; +//float hud_idle_alpha; .string name; .string description; diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 06ab8a94..709a516c 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -6,6 +6,7 @@ csextradefs.qc ../share/common_helpers.qc ../share/common_vote.qc sui_sys.qc +vote.qc status.qc menu.qc main.qc @@ -14,4 +15,3 @@ hud_helpers.qc hud.qc settings.qc input.qc -vote.qc diff --git a/csqc/hud.qc b/csqc/hud.qc index 32c4a3ac..d1e26072 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -364,7 +364,7 @@ void Hud_DrawFlagStatusBar(string panelid) { if (FlagInfoLines[i].id) { - alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? 0.3 : 1; + alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? cvar("fo_hud_idle_alpha") : 1; string icon = FlagInfoLines[i].icon.filename; vector iconcolour = FlagInfoLines[i].icon.colour; float bigfont = 8 * (Hud_Panels[HUD_PANEL_FLAGINFO].TextScale ? Hud_Panels[HUD_PANEL_FLAGINFO].TextScale : Hud_Panels[HUD_PANEL_FLAGINFO].Scale); diff --git a/csqc/main.qc b/csqc/main.qc index b5f56fd2..f05d0318 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -56,6 +56,10 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("+fo_showscores"); registercommand("-fo_showscores"); + registercommand("vote_addmap"); + registercommand("vote_removemap"); + registercvar("fo_hud_idle_alpha", "0.3"); + FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -64,6 +68,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { is_admin = FALSE; grentimer_waiting = FALSE; jump_counter = 0; +// hud_idle_alpha = 0.3; }; noref void() CSQC_WorldLoaded = { @@ -122,7 +127,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } noref float(string cmd) CSQC_ConsoleCommand = { - tokenize(cmd); + tokenize_console(cmd); float val; string key1, key2; switch(argv(0)) { @@ -184,7 +189,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_DropAmmo(TRUE, 1, (player_class == PC_ENGINEER)); break; case "primeone": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); @@ -196,7 +201,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "primetwo": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); @@ -208,7 +213,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren1": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); @@ -220,7 +225,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren2": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || round_active)) { + if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); @@ -301,6 +306,12 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("-jump"); } break; + case "vote_addmap": + AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6))); + break; + case "vote_removemap": + RemoveVoteMap(argv(1)); + break; } return FALSE; }; diff --git a/csqc/status.qc b/csqc/status.qc index 7a80d9df..4da0d64b 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -130,7 +130,7 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { 1, 0 ); - if (hud_panel(panelid, position, size, 0.3, panel.Display)) { + if (hud_panel(panelid, position, size, transparency, panel.Display)) { // click event } } else { @@ -193,7 +193,7 @@ void(string panelid, float display, string text, string icon) drawMOTDPanel = { 0 ); - if (hud_panel(panelid, position, size, 0.3, panel.Display)) { + if (hud_panel(panelid, position, size, transparency, panel.Display)) { // click event } } else { @@ -272,7 +272,7 @@ void(string panelid, float display, string text, string icon) drawGameModePanel local string message = ""; if (fo_hud_editor) { message = "Game Mode"; - if (hud_panel(panelid, position, size, 0.3, panel.Display)) { + if (hud_panel(panelid, position, size, transparency, panel.Display)) { // click event } } else { From d025948b102e85b9c636214723a6d99386e30099 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 27 Sep 2020 22:40:38 +1300 Subject: [PATCH 1121/2474] readme update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3927ec32..a4bb5cdf 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* new cvar for zut ``fo_hud_idle_alpha`` - sets the minimum transparency for flaginfo inactive items * optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * localinfo nohitsounds 1 - disables hitsounds server-wide * localinfo noreturn 1 - prevents goalitems from returning (will still return from lava) From 2930c265d6785e716018bc5226d5606f5cd8a646 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Wed, 7 Oct 2020 16:12:18 -0300 Subject: [PATCH 1122/2474] a number of login related fixes --- ssqc/client.qc | 103 +++++++++++++++++++++++++++++----------------- ssqc/commands.qc | 36 ++++++++++------ ssqc/functions.qc | 2 +- ssqc/login.qc | 24 ++++++++--- ssqc/quadmode.qc | 12 +----- 5 files changed, 109 insertions(+), 68 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c2d87da8..fd047b4a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -65,6 +65,8 @@ void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options; float (float tno) TeamFortress_TeamGetLives; void () InitReverseCap; +float () RejoinWithTfId; +void () CreateTfIdAndJoin; string nextmap; @@ -2677,7 +2679,6 @@ void () UpdateAllClientsTeamScores = { //do not rely on csqcactive - it may misbehave when using `join` from spectator void (optional float csqcactive) ClientConnect = { - local entity te; local string st; local float got_one; @@ -2721,44 +2722,13 @@ void (optional float csqcactive) ClientConnect = { got_one = 0; st = infokey(self, "tf_id"); self.tf_id = stof(st); - if ((st != string_null) && (self.tf_id != 0)) { - sprint(self, PRINT_HIGH, "Welcome back!\n"); - te = find(world, classname, "ghost"); - while (te) { - if (te.tf_id == self.tf_id) { - got_one = 1; - TeamFortress_TeamSet_Options(self, te.team_no, TRUE); - UpdateAllClientsTeamScores(); - - self.frags = te.frags; - self.real_frags = te.real_frags; - if (!(toggleflags & TFLAG_TEAMFRAGS) && - !(toggleflags & TFLAG_FULLTEAMSCORE)) { - self.frags = self.real_frags; - } - self.playerclass = te.playerclass; - self.nextpc = te.playerclass; - self.tfstate = te.tfstate; - dremove(te); - te = world; - } else - te = find(te, classname, "ghost"); + if (!loginRequired) { + if ((st != string_null) && (self.tf_id != 0)) { + got_one = RejoinWithTfId(); } - } - if (!got_one) { - if (game_locked && (!cb_prematch)) { - sprint(self, PRINT_HIGH, - "Closed server. Clan battle in progress.\n"); - KickCheater(self); - return; + if (!got_one) { + CreateTfIdAndJoin(); } - last_id = last_id + 20 + random() * 10; - self.tf_id = rint(random() * 10 + last_id); - st = ftos(self.tf_id); - stuffcmd(self, "setinfo tf_id "); - stuffcmd(self, st); - stuffcmd(self, "\n"); - sprint(self, PRINT_HIGH, "Your battle ID is ", st, "\n"); } } @@ -2773,6 +2743,65 @@ void (optional float csqcactive) ClientConnect = { sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); }; +float () RejoinWithTfId = { + local entity te; + sprint(self, PRINT_HIGH, "Welcome back!\n"); + te = find(world, classname, "ghost"); + while (te) { + if (te.tf_id == self.tf_id) { + TeamFortress_TeamSet_Options(self, te.team_no, TRUE); + UpdateAllClientsTeamScores(); + + self.frags = te.frags; + self.real_frags = te.real_frags; + if (!(toggleflags & TFLAG_TEAMFRAGS) && + !(toggleflags & TFLAG_FULLTEAMSCORE)) { + self.frags = self.real_frags; + } + self.playerclass = te.playerclass; + self.nextpc = te.playerclass; + self.tfstate = te.tfstate; + dremove(te); + te = world; + return 1; + } else + te = find(te, classname, "ghost"); + } + return 0; +} + +void () CreateTfIdAndJoin = { + local string st; + if (game_locked && (!cb_prematch)) { + sprint(self, PRINT_HIGH, + "Closed server. Clan battle in progress.\n"); + KickCheater(self); + return; + } + last_id = last_id + 20 + random() * 10; + self.tf_id = rint(random() * 10 + last_id); + st = ftos(self.tf_id); + stuffcmd(self, "setinfo tf_id "); + stuffcmd(self, st); + stuffcmd(self, "\n"); + sprint(self, PRINT_HIGH, "Your battle ID is ", st, "\n"); +} + +void (entity pl) ResetAndRespawnPlayer = { + if(pl.team_no && pl.playerclass) { + pl.classname = "player"; + pl.takedamage = DAMAGE_AIM; + pl.solid = SOLID_SLIDEBOX; + pl.movetype = MOVETYPE_WALK; + TeamFortress_RemoveTimers(); + setspawnparms(pl); + PutClientInServer(); + } + if(infokeyf(pl, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(pl, FALSE); + } +} + void () CountMatchPlayersAndReset = { local float playersleft = 0; local entity te = find (world, classname, "player"); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index c75e2eab..df5835ed 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -282,6 +282,23 @@ void (entity cap, float pick) CaptainPick = { } } +void (entity pl) PrintWho = { + local string msg; + msg = strzone(string_null); + msg = strcat(msg, infokey(pl,"name")); + msg = strcat(msg, " - "); + if (pl.login != string_null) + msg = strcat(msg, pl.login); + else + msg = strcat(msg, "NOT LOGGED IN"); + if (pl.is_admin) { + msg = strcat(msg, " (admin)"); + } + msg = strcat(msg, "\n"); + sprint(self, PRINT_HIGH, msg); + strunzone(msg); +} + float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; @@ -879,22 +896,15 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "who": processedCmd = TRUE; pl = find (world, classname, "player"); - string msg; while (pl) { - msg = string_null; - msg = strcat(msg, infokey(pl,"name")); - msg = strcat(msg, " - "); - if (pl.login != string_null) - msg = strcat(msg, pl.login); - else - msg = strcat(msg, "NOT LOGGED IN"); - if (pl.is_admin) { - msg = strcat(msg, " (admin)"); - } - msg = strcat(msg, "\n"); - sprint(self, PRINT_HIGH, msg); + PrintWho(pl); pl = find (pl, classname, "player"); } + pl = find (world, classname, "observer"); + while (pl) { + PrintWho(pl); + pl = find (pl, classname, "observer"); + } break; } diff --git a/ssqc/functions.qc b/ssqc/functions.qc index f9aaa892..f753467f 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -136,7 +136,7 @@ void () MapEndSequence = { player = find (world, classname, "player"); while (player) { - if (player.playerclass != 0) { + if (player.playerclass != 0 && self.has_disconnected != 1) { local float timeplayed = gametime - player.classtime; LogEventChangeClass(player, player.playerclass, 0, timeplayed); player.classtime = gametime; diff --git a/ssqc/login.qc b/ssqc/login.qc index 66981303..1fe4a44d 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -14,6 +14,7 @@ void (entity player, string login, string secret) performLogin = { } void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { + local float got_one = 0; self.login_in_progress = 0; local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); if (!responsecode) { @@ -38,12 +39,23 @@ void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { sprint (self, 2, "Type \scommands\s for admin commands.\n"); } } - if(self.team_no == 0 && !intermission_running ) { - if (csqcactive) - Menu_Team(0); - else - Menu_Team(1); - } + if(self.team_no == 0 && !intermission_running) { + if (clanbattle && (self.has_disconnected != 1)) { + if (self.tf_id != 0) { + got_one = RejoinWithTfId(); + ResetAndRespawnPlayer(self); + } + if (!got_one) { + CreateTfIdAndJoin(); + } + } + if (!got_one) { + if (csqcactive) + Menu_Team(0); + else + Menu_Team(1); + } + } } else { dprint(infokey(self,"name")); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 207f5703..fa49c17d 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -173,17 +173,7 @@ void () QuadRoundBegin = { while (te != world) { oldself = self; self = te; - if(self.team_no && self.playerclass) { - self.takedamage = DAMAGE_AIM; - self.solid = SOLID_SLIDEBOX; - self.movetype = MOVETYPE_WALK; - TeamFortress_RemoveTimers(); - setspawnparms(self); - PutClientInServer(); - } - if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - UpdateClientPrematch(self, FALSE); - } + ResetAndRespawnPlayer(self); self = oldself; te = find (te, classname, "player"); } From 129ff08b8b5c0dc1187560fedb7abe47324d47d5 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 8 Oct 2020 21:03:00 +1100 Subject: [PATCH 1123/2474] reset special cd on spawn --- ssqc/client.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index c2d87da8..d93f538f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1791,6 +1791,7 @@ void () PutClientInServer = { self.fire_held_down = 0; self.dimension_see = DMN_NOFLASH; self.dimension_seen = DMN_NOFLASH - (DMN_NOFLASH & DMN_FLASH); + self.special_cooldown = 0; setmodel(self, string_null); modelindex_null = self.modelindex; From 774c125f209573067ce5472a0dad02469f328ca0 Mon Sep 17 00:00:00 2001 From: danni Date: Thu, 8 Oct 2020 22:48:04 +1100 Subject: [PATCH 1124/2474] halve napalm explosions, double initial damage, up burn damage, give damage amplification if target is burning --- share/defs.h | 9 +++ ssqc/combat.qc | 3 + ssqc/engineer.qc | 4 -- ssqc/pyro.qc | 182 +++++++++++++++-------------------------------- ssqc/tfortmap.qc | 2 +- ssqc/weapons.qc | 4 +- 6 files changed, 75 insertions(+), 129 deletions(-) diff --git a/share/defs.h b/share/defs.h index a49a07e2..1f4ead36 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1053,6 +1053,15 @@ #define PC_PYRO_LAVA_RETICK 1.2 #define PC_PYRO_FLAMETHROWER_DAM_FO 15 #define PC_PYRO_FLAMETHROWER_DAM_ORIG 10 +#define PC_PYRO_NAPALM_INIT_DAM_ORIG 20 +#define PC_PYRO_NAPALM_INIT_DAM_FO 40 +#define PC_PYRO_NAPALM_MAX_EXPLOSIONS_ORIG 8 +#define PC_PYRO_NAPALM_MAX_EXPLOSIONS_FO 4 +#define PC_PYRO_INIT_BURN_DAM_ORIG 6 +#define PC_PYRO_INIT_BURN_DAM_FO 12 +#define PC_PYRO_BURN_MULTIPLIER_ORIG .3 +#define PC_PYRO_BURN_MULTIPLIER_FO 1 +#define PC_PYRO_BURN_DAMAGE_AMP 1.2 // pyro types diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 03e1f6ae..84863050 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -415,6 +415,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, no_damage = 0; + if (pyro_type == PYRO_FO && (targ.tfstate & TFSTATE_BURNING)) + damage = damage * PC_PYRO_BURN_DAMAGE_AMP; + if (attacker.classname == "player") { damage = damage * 0.9; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index ec2f1bf7..42b71137 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -778,8 +778,6 @@ void () DispenserThink = { if (!old_dispenser) Dispenser_FindPlayers(self); - CheckPyroLava(); - self.nextthink = time + 0.3; }; @@ -881,8 +879,6 @@ void () TeamFortress_FinishedBuilding = { oldself.takedamage = DAMAGE_NO; oldself.th_die = Sentry_Die; oldself.team_no = self.team_no; - oldself.think = CheckPyroLava; - oldself.nextthink = time + .1; self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; setsize(oldself, '-16 -16 0', '16 16 4'); newmis = spawn(); diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index ded907e0..32ab46ce 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -8,6 +8,20 @@ void (vector org, entity shooter) NapalmGrenadeLaunch; void () Napalm_touch; float (string id_flame) RemoveFlameFromQueue; +void (entity ent, float num) SetFlameCount = { + ent.numflames = num; + + if (num == 0) + { + ent.tfstate = ent.tfstate - (ent.tfstate & TFSTATE_BURNING); + } + else + { + ent.tfstate = ent.tfstate | TFSTATE_BURNING; + } + +}; + entity(string type, entity p_owner) FlameSpawn = { if (cb_prematch) { @@ -124,6 +138,21 @@ void () NapalmGrenadeNetThink = { local entity head; local entity te; + // TODO - make a settings struct and put these in on world spawn + float explodeDam = 0; + float maxExplosions = 0; + switch (pyro_type) + { + case PYRO_FO: + explodeDam = PC_PYRO_NAPALM_INIT_DAM_FO; + maxExplosions = PC_PYRO_NAPALM_MAX_EXPLOSIONS_FO; + break; + default: + explodeDam = PC_PYRO_NAPALM_INIT_DAM_ORIG; + maxExplosions = PC_PYRO_NAPALM_MAX_EXPLOSIONS_ORIG; + break; + } + if (self.heat == 0) { self.owner.no_active_napalm_grens = self.owner.no_active_napalm_grens + 1; @@ -154,7 +183,8 @@ void () NapalmGrenadeNetThink = { while (head) { if (head.takedamage) { deathmsg = DMSG_FLAME; - TF_T_Damage(head, self, self.owner, 20, TF_TD_NOTTEAM, + + TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, TF_TD_FIRE); other = head; Napalm_touch(); @@ -172,7 +202,8 @@ void () NapalmGrenadeNetThink = { multicast(self.origin, MULTICAST_PHS); self.heat = self.heat + 1; - if (self.heat > 7) + + if (self.heat >= maxExplosions) RemoveGrenade(); }; @@ -256,7 +287,7 @@ void () FlameFollow = { if (self.enemy.health < 1) { deathmsg = 15; T_RadiusDamage(self, self, 10, self); - self.enemy.numflames = 0; + SetFlameCount(self.enemy, 0); FlameDestroy(self); return; } @@ -270,8 +301,7 @@ void () FlameFollow = { } if (self.health < 1) { if ((self.effects != 8) || (self.enemy.numflames <= 1)) { - self.enemy.numflames = self.enemy.numflames - 1; - self.enemy.numflames = 0; + SetFlameCount(self.enemy, (self.enemy.numflames - 1)); FlameDestroy(self); return; } @@ -295,13 +325,23 @@ void () FlameFollow = { } if ((self.enemy.waterlevel > 1) || (self.enemy.classname != "player" && self.enemy.waterlevel > 0)) { FO_Sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, 1); - self.enemy.numflames = self.enemy.numflames - 1; + SetFlameCount(self.enemy, self.enemy.numflames - 1); FlameDestroy(self); return; } self.nextthink = time + 0.1; if ((self.effects == 8) && (self.heat >= 3)) { - damage = self.enemy.numflames * 0.3 * 3; + damage = 0; + switch (pyro_type) + { + case PYRO_FO: + damage = self.enemy.numflames * PC_PYRO_BURN_MULTIPLIER_FO * 3; + break; + default: + damage = self.enemy.numflames * PC_PYRO_BURN_MULTIPLIER_ORIG * 3; + break; + } + if (damage < 1) { damage = 1; } @@ -361,7 +401,7 @@ void (entity player, entity fireowner, vector org flame.classname = "fire"; flame.health = flamehealth; - player.numflames = player.numflames + 1; + SetFlameCount(player, (player.numflames + 1)); flame.velocity = player.velocity; flame.enemy = player; flame.touch = OnPlayerFlame_touch; @@ -457,8 +497,18 @@ void () Napalm_touch = { } if (other != world) { if ((other.takedamage == 2) && (other.health > 0)) { + float dam = 0; + switch (pyro_type) + { + case PYRO_FO: + dam = PC_PYRO_INIT_BURN_DAM_FO; + break; + default: + dam = PC_PYRO_INIT_BURN_DAM_ORIG; + break; + } deathmsg = DMSG_FLAME; - TF_T_Damage(other, self, self.owner, 6, TF_TD_NOTTEAM, + TF_T_Damage(other, self, self.owner, dam, TF_TD_NOTTEAM, TF_TD_FIRE); float flamehealth = 45; @@ -593,119 +643,6 @@ void () IncendiaryRadius_OZTF = { dremove(self); }; -void (entity targ, entity lava) ForceIncendiaryLavaTouch = { - if (targ.classname == "building_sentrygun_base") - { - targ = targ.oldenemy; // set other to sentrygun turret - } - if (targ.takedamage) - { - if (targ.icdmgtime < time) - { - targ.icdmgtime = time + PC_PYRO_LAVA_RETICK; - deathmsg = DMSG_FLAME; - TF_T_Damage(targ, lava, lava.owner, 40, TF_TD_NOTTEAM, TF_TD_NOMOMENTUM | TF_TD_FIRE); - - if (random() > 0.5) { - FO_Sound(targ, CHAN_VOICE, "player/lburn1.wav", 1, 1); - } else { - FO_Sound(targ, CHAN_VOICE, "player/lburn2.wav", 1, 1); - } - } - SetOnFire(targ, lava.owner, lava.origin, 15); - } -}; - -// used by sentrygun and dispenser to see if they are standing on "lava", touch events not being set off -void () CheckPyroLava = { - vector org = self.origin; - org_z = org_z - self.mins_z; - if (self.classname == "building_sentrygun_base") - { - self.nextthink = time + .3; - } - else if (self.classname == "building_dispenser") - { - // nothing for now - } - else - { - // spam everyone, get this bug fixed - bprint(PRINT_HIGH, "CheckPyroLava returning for ", self.classname, "\n"); - return; - } - - // FIXME - do dodgy radius, means disp and sentry can catch on fire when not "touching" edge of pool - // fix later if we keep these changes - entity lava; - lava = findradius(org, 5); - while (lava) - { - if (lava.classname == "pyrolava") - { - ForceIncendiaryLavaTouch(self, lava); - return; - } - lava = lava.chain; - } -}; - -void () IncendiaryLavaThink = { - dremove(self); -}; - -void () IncendiaryLavaTouch = { - ForceIncendiaryLavaTouch(other, self); -}; - -entity (vector org) SpawnLavaSprite = { - entity lava; - lava = spawn(); - lava.mdl = "progs/s_explod.spr"; - lava.owner = self.owner; - lava.movetype = MOVETYPE_TOSS; - lava.solid = SOLID_TRIGGER; - lava.touch = IncendiaryLavaTouch; - lava.classname = "pyrolava"; - - FO_SetModel(lava, lava.mdl); - setorigin(lava, org); - setsize(lava, VEC_ORIGIN, VEC_ORIGIN); - - lava.think = IncendiaryLavaThink; - lava.nextthink = time + PC_PYRO_LAVA_LIFETIME; - - return lava; -}; - -void () IncendiaryRadius_FO = { - - vector org; - org = self.origin; - entity lava = SpawnLavaSprite(org); - - for (float i = -5; i < 5; i++) - { - org = self.origin; - org_x = org_x + 10 * i; - - float yval = org_y; - for (float i2 = -5; i2 < 5; i2++) - { - if (i2 == 0 && i == 0) - continue; - - org_y = yval + 10 * i2; - SpawnLavaSprite(org); - } - - } - - FO_Sound(self, CHAN_AUTO, "player/inlava.wav", 1, ATTN_NORM); - - dremove(self); -}; - void () T_IncendiaryTouch = { local float damg; @@ -741,7 +678,6 @@ void () T_IncendiaryTouch = { IncendiaryRadius_OZTF(); break; case PYRO_FO: - //IncendiaryRadius_FO(); IncendiaryRadius_OZTF(); break; } diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 7910228b..ee8d881f 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1032,7 +1032,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player.numflames > 0) { FO_Sound(Player, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); - Player.numflames = 0; + SetFlameCount(Player, 0); } if (Player.FlashTime > 0) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fe5b1eda..0d5e9e58 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -120,6 +120,8 @@ float () IsUsingOldImpulses; void (float inp) W_OldWeaponSlot; +void (entity ent, float num) SetFlameCount; + void () W_Precache = { precache_sound("weapons/r_exp3.wav"); precache_sound("weapons/rocket1i.wav"); @@ -504,7 +506,7 @@ void () W_FireMedikit = { FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); - trace_ent.numflames = 0; + SetFlameCount(trace_ent, 0); if (self.classname == "player") { bprint(PRINT_MEDIUM, self.netname, " put out ", From 07c40c722820095562866ed3269700ba6cde3335 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sat, 10 Oct 2020 00:28:35 -0300 Subject: [PATCH 1125/2474] allowing engy to move while building --- share/defs.h | 3 ++ ssqc/client.qc | 1 + ssqc/engineer.qc | 127 +++++++++++++++++++++++++++++++++-------------- ssqc/qw.qc | 1 + ssqc/sentry.qc | 2 +- ssqc/status.qc | 22 ++++++-- 6 files changed, 114 insertions(+), 42 deletions(-) diff --git a/share/defs.h b/share/defs.h index a49a07e2..45f29073 100644 --- a/share/defs.h +++ b/share/defs.h @@ -670,6 +670,9 @@ #define BUILD_DISPENSER_MAX_CELLS 400 #define BUILD_DISPENSER_MAX_ARMOR 500 +#define BUILD_SENTRYGUN_MAX_DISTANCE 128 +#define BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE 1024 + /*======================================================*/ /* Ammo quantities for dropping */ /*======================================================*/ diff --git a/ssqc/client.qc b/ssqc/client.qc index c2d87da8..670f53a4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -711,6 +711,7 @@ void () DecodeLevelParms = { InitReverseCap(); } + engineer_move = CF_GetSetting("em","engineer_move", "0"); st = infokey(world, "default"); if (st == "on") { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index ec2f1bf7..9fb2ee77 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -337,12 +337,9 @@ void () TeamFortress_EngineerBuildStop = { local entity te; local vector dist; - self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; - self.movetype = MOVETYPE_WALK; - TeamFortress_SetSpeed(self); te = find(world, netname, "build_timer"); while (te) { - if (te.owner == self) { + if (te.owner == self || (engineer_move && te.real_owner == self)) { dist = self.origin - te.origin; if (vlen(dist) > 128) { sprint(self, PRINT_HIGH, "Your building disappeared\n"); @@ -355,6 +352,9 @@ void () TeamFortress_EngineerBuildStop = { } else { sprint(self, PRINT_HIGH, "You stop building\n"); } + if (engineer_move) { + self.has_sentry = 0; + } dremove(te); te = world; } else { @@ -364,8 +364,13 @@ void () TeamFortress_EngineerBuildStop = { Menu_Close(self); self.is_building = 0; self.building_percentage = 0; - self.current_weapon = self.weapon; - W_SetCurrentAmmo(self); + if (!engineer_move) { + self.current_weapon = self.weapon; + self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; + self.movetype = MOVETYPE_WALK; + TeamFortress_SetSpeed(self); + W_SetCurrentAmmo(self); + } } float (entity obj, entity builder) CheckArea = { @@ -505,16 +510,18 @@ void (float objtobuild) TeamFortress_Build = { } } self.is_building = 1; - self.immune_to_check = time + 5; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - self.movetype = MOVETYPE_NONE; - self.weapon = self.current_weapon; - self.current_weapon = 0; - self.weaponmodel = ""; - self.weaponframe = 0; - TeamFortress_SetSpeed(self); + if (!engineer_move) { + self.immune_to_check = time + 5; + self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + self.movetype = MOVETYPE_NONE; + self.weapon = self.current_weapon; + self.current_weapon = 0; + self.weaponmodel = ""; + self.weaponframe = 0; + TeamFortress_SetSpeed(self); + Menu_Engineer_Cancel(); + } Status_Refresh(self); - Menu_Engineer_Cancel(); newmis.owner = self; newmis.classname = "timer"; @@ -532,6 +539,22 @@ void (float objtobuild) TeamFortress_Build = { setorigin(newmis, newmis.origin); newmis.flags = newmis.flags - (newmis.flags & 512); + if (engineer_move) { + newmis.owner = world; + newmis.real_owner = self; + self.sentry_ent = newmis; + self.has_sentry = TRUE; + newmis.health = 50; + newmis.max_health = newmis.health; + newmis.th_die = Sentry_Die; + newmis.th_pain = Sentry_Pain; + newmis.takedamage = DAMAGE_AIM; + self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; + newmis.classname = "building_sentrygun"; + newmis.team_no = self.team_no; + newmis.weapon = 0; + } + oldmis = newmis; newmis = spawn(); newmis.owner = self; @@ -543,6 +566,7 @@ void (float objtobuild) TeamFortress_Build = { }; void () CF_CheckBuilding = { + local float max_dist = BUILD_SENTRYGUN_MAX_DISTANCE; local vector dist; local entity timer = self; local entity building = self.enemy; @@ -553,8 +577,10 @@ void () CF_CheckBuilding = { return; } + if (engineer_move) + max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; dist = self.origin - building.origin; - if (vlen(dist) > 128) { + if (vlen(dist) > max_dist) { TeamFortress_EngineerBuildStop(); dremove(timer); return; @@ -811,9 +837,17 @@ void UpdateClient_Dispenser(entity pl, entity disp) = { void () TeamFortress_FinishedBuilding = { local entity oldself; - if (self.owner.is_building != 1) { - return; + if (engineer_move) { + if (self.real_owner.is_building != 1) { + return; + } } + else { + if (self.owner.is_building != 1) { + return; + } + } + self.owner = self.real_owner; local float csqcactive = infokeyf(self.owner, INFOKEY_P_CSQCACTIVE); @@ -823,11 +857,14 @@ void () TeamFortress_FinishedBuilding = { oldself.real_owner = self; self.is_building = FALSE; self.building_percentage = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - self.movetype = MOVETYPE_WALK; - self.current_weapon = self.weapon; + if (!engineer_move) { + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.movetype = MOVETYPE_WALK; + self.current_weapon = self.weapon; + TeamFortress_SetSpeed(self); + } Status_Refresh(self); - TeamFortress_SetSpeed(self); + Menu_Close(self); if (oldself.weapon == 1) { self.has_dispenser = TRUE; @@ -871,7 +908,7 @@ void () TeamFortress_FinishedBuilding = { if(csqcactive) { UpdateClient_Dispenser(self, oldself); } - } else if (oldself.weapon == 2) { + } else if (oldself.weapon == 2 || (engineer_move && oldself.weapon == 0)) { self.has_sentry = TRUE; sprint(self, PRINT_HIGH, "You finish building the sentry gun\n"); teamsprint(self.team_no, self, self.netname); @@ -883,7 +920,8 @@ void () TeamFortress_FinishedBuilding = { oldself.team_no = self.team_no; oldself.think = CheckPyroLava; oldself.nextthink = time + .1; - self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; + if (!engineer_move) + self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; setsize(oldself, '-16 -16 0', '16 16 4'); newmis = spawn(); newmis.classname = "building_sentrygun"; @@ -1162,18 +1200,29 @@ void (entity gun) Engineer_UseSentryGun = { // automate tasks if old_spanner setting is disabled if (!old_spanner) { if(gun.team_no > 0 && gun.team_no == self.team_no) { - //Menu_EngineerFix_SentryGun_Rotate(); - Engineer_SentryGun_ShowMenu(self.building); - if (gun.weapon < 3 && self.ammo_cells >= ENG_SENTRY_COST) { - Engineer_SentryGun_Upgrade(gun); - return; - } else if (gun.health < gun.max_health && self.ammo_cells > 0) { - Engineer_SentryGun_Repair(gun); - return; - } else if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) - || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets - && self.ammo_rockets > 0)) { - Engineer_SentryGun_InsertAmmo(gun); + if (gun.weapon > 0) { + //Menu_EngineerFix_SentryGun_Rotate(); + Engineer_SentryGun_ShowMenu(self.building); + if (gun.weapon < 3 && self.ammo_cells >= ENG_SENTRY_COST) { + Engineer_SentryGun_Upgrade(gun); + return; + } else if (gun.health < gun.max_health && self.ammo_cells > 0) { + Engineer_SentryGun_Repair(gun); + return; + } else if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) + || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets + && self.ammo_rockets > 0)) { + Engineer_SentryGun_InsertAmmo(gun); + return; + } + } else { + sprint (self, PRINT_HIGH, strcat("You stopped building sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); + self.ammo_cells = self.ammo_cells + ENG_SENTRY_COST; + if (gun.trigger_field != world) + dremove (gun.trigger_field); + dremove (gun); + self.has_sentry = 0; + W_SetCurrentAmmo(self); return; } } else { // hit enemy sentry @@ -1182,7 +1231,8 @@ void (entity gun) Engineer_UseSentryGun = { bprint(PRINT_HIGH, self.netname, " dismantled ", gun.real_owner.netname, "'s sentry gun\n"); TF_AddFrags(self, 1); sprint(gun.real_owner, PRINT_HIGH, "Your sentry gun was dismantled by ",self.netname,"\n"); - dremove (gun.trigger_field); + if (gun.trigger_field != world) + dremove (gun.trigger_field); dremove (gun); ThrowGib("progs/tgib1.mdl", -30); ThrowGib("progs/tgib2.mdl", -50); @@ -1371,7 +1421,8 @@ void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { te.real_owner.has_dispenser = 0; if(bld == "building_sentrygun") { te.real_owner.has_sentry = 0; - dremove (te.trigger_field); + if (te.trigger_field != world) + dremove (te.trigger_field); } spawn_tfog(te.origin); dremove (te); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 50ba81a4..9cc09803 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -591,6 +591,7 @@ float noreturn; float nohitsounds; //float server_sbflaginfo; float reverse_cap; +float engineer_move; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 204b30bf..a96afd89 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -245,7 +245,7 @@ void () Sentry_Explode = { if (self.classname == "building_sentrygun_base") { if (self.oldenemy) dremove(self.oldenemy); - } else + } else if (self.trigger_field != world) dremove(self.trigger_field); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); diff --git a/ssqc/status.qc b/ssqc/status.qc index ebff41a6..85bc93fa 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1641,16 +1641,32 @@ string(entity pl) SentryDetailsToString = return st; }; -string(entity pl) BuildingToString = -{ +string(entity pl) BuildingToString ={ local string st = ""; + local int dist_percentage; + local string dist_string; + local string hp; + + if (engineer_move) { + hp = strcat(strpadl(ftos(floor(self.sentry_ent.health)), 2), " hp"); + st = strcat(st,strcat(Q"\sSentry\s: ", hp)); + st = strpadr(st, 14); + } if (!buildstatus) return "Building..."; - st = Q"\sBuilding\s: "; + st = strcat(st, Q"\sReady\s: "); st = strcat(st, ftos(pl.building_percentage)); st = strcat(st, "%"); + if (engineer_move) { + dist_percentage = (vlen(self.origin - self.sentry_ent.origin)/BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE)*100; + st = strpadr(st, 26); + st = strcat(st, Q"\sDistance\s:"); + dist_string = strcat(itos(dist_percentage),"%"); + dist_string = strcat(Q"\x10", dist_string ,Q"\x11"); + st = strcat(st, dist_string); + } return st; }; From c14d79a97774127b69dd8fc5326ea6a82707e608 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 11 Oct 2020 14:11:37 -0300 Subject: [PATCH 1126/2474] dispenser and removing max_distance as a test --- ssqc/commands.qc | 2 +- ssqc/engineer.qc | 80 +++++++++++++++++++++++++++++++++++------------- ssqc/menu.qc | 18 ++++++++--- ssqc/status.qc | 18 ++++++----- ssqc/weapons.qc | 3 +- 5 files changed, 83 insertions(+), 38 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index c75e2eab..d9251568 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -626,7 +626,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } if(arg2 == "sentry") { - if(self.is_building) { + if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); break; } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 9fb2ee77..ebe3542f 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -353,7 +353,10 @@ void () TeamFortress_EngineerBuildStop = { sprint(self, PRINT_HIGH, "You stop building\n"); } if (engineer_move) { - self.has_sentry = 0; + if (self.has_sentry == 1) + self.has_sentry = 0; + else if (self.has_dispenser == 1) + self.has_dispenser = 0; } dremove(te); te = world; @@ -542,17 +545,29 @@ void (float objtobuild) TeamFortress_Build = { if (engineer_move) { newmis.owner = world; newmis.real_owner = self; - self.sentry_ent = newmis; - self.has_sentry = TRUE; newmis.health = 50; newmis.max_health = newmis.health; - newmis.th_die = Sentry_Die; - newmis.th_pain = Sentry_Pain; - newmis.takedamage = DAMAGE_AIM; - self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; - newmis.classname = "building_sentrygun"; - newmis.team_no = self.team_no; - newmis.weapon = 0; + if (objtobuild == 1) { + self.has_dispenser = TRUE; + newmis.th_die = Dispenser_Die; + newmis.team_no = self.team_no; + newmis.real_owner = self; + newmis.team_no = self.team_no; + newmis.takedamage = DAMAGE_AIM; + self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; + newmis.classname = "building_dispenser"; + } + if (objtobuild == 2) { + self.sentry_ent = newmis; + self.has_sentry = TRUE; + newmis.th_die = Sentry_Die; + newmis.th_pain = Sentry_Pain; + newmis.takedamage = DAMAGE_AIM; + self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; + newmis.classname = "building_sentrygun"; + newmis.team_no = self.team_no; + newmis.weapon = 0; + } } oldmis = newmis; @@ -577,13 +592,15 @@ void () CF_CheckBuilding = { return; } - if (engineer_move) - max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; - dist = self.origin - building.origin; - if (vlen(dist) > max_dist) { - TeamFortress_EngineerBuildStop(); - dremove(timer); - return; + if (!engineer_move) { //disabling max_distance for moving engineer + if (engineer_move) + max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; + dist = self.origin - building.origin; + if (vlen(dist) > max_dist) { + TeamFortress_EngineerBuildStop(); + dremove(timer); + return; + } } if (building.weapon == 2) { @@ -835,8 +852,7 @@ void UpdateClient_Dispenser(entity pl, entity disp) = { void () TeamFortress_FinishedBuilding = { - local entity oldself; - + local entity oldself; if (engineer_move) { if (self.real_owner.is_building != 1) { return; @@ -1038,7 +1054,6 @@ void () Dispenser_Die = { void (entity disp) Engineer_UseDispenser = { local entity dist_checker; - // engineer hits enemy dispenser - dismantle if(!(disp.team_no > 0 && disp.team_no == self.team_no)) { self.ammo_cells = self.ammo_cells + 50; @@ -1054,6 +1069,21 @@ void (entity disp) Engineer_UseDispenser = { return; } + if (self.team_no == disp.team_no) { + if (disp.real_owner.is_building) { + sprint (self, PRINT_HIGH, strcat("You stopped building a dispenser and got ", ftos(ENG_DISPENSER_COST), " cells back\n")); + self.ammo_cells = self.ammo_cells + ENG_DISPENSER_COST; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; + dremove (disp); + W_SetCurrentAmmo(self); + self = disp.real_owner; + self.has_dispenser = 0; + TeamFortress_EngineerBuildStop(); + return; + } + } + if (disp.health < disp.max_health && !old_spanner) { Engineer_Dispenser_Repair(disp); return; @@ -1216,17 +1246,23 @@ void (entity gun) Engineer_UseSentryGun = { return; } } else { - sprint (self, PRINT_HIGH, strcat("You stopped building sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); + sprint (self, PRINT_HIGH, strcat("You stopped building a sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); self.ammo_cells = self.ammo_cells + ENG_SENTRY_COST; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; if (gun.trigger_field != world) dremove (gun.trigger_field); dremove (gun); - self.has_sentry = 0; W_SetCurrentAmmo(self); + self = gun.real_owner; + self.has_sentry = 0; + TeamFortress_EngineerBuildStop(); return; } } else { // hit enemy sentry self.ammo_cells = self.ammo_cells + 65; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; gun.real_owner.has_sentry = 0; bprint(PRINT_HIGH, self.netname, " dismantled ", gun.real_owner.netname, "'s sentry gun\n"); TF_AddFrags(self, 1); diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 104216e3..0ebe9b5a 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -844,11 +844,19 @@ void (float inp) Menu_Engineer_Input = { dismantle_sentrygun = 0; dismantle_dispenser = 0; - if (inp == 1 && !self.has_sentry && self.ammo_cells >= ENG_SENTRY_COST) - TeamFortress_Build(2); - - if (inp == 2 && !self.has_dispenser && self.ammo_cells >= ENG_DISPENSER_COST) - TeamFortress_Build(1); + if (inp == 1 && !self.has_sentry) { + if (self.ammo_cells >= ENG_SENTRY_COST) + TeamFortress_Build(2); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST), " cells to build a sentry gun")); + } + + if (inp == 2 && !self.has_dispenser) { + if (self.ammo_cells >= ENG_DISPENSER_COST) + TeamFortress_Build(1); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); + } if (inp == 3 && self.has_sentry) { te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); diff --git a/ssqc/status.qc b/ssqc/status.qc index 85bc93fa..545a2d4e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1647,7 +1647,7 @@ string(entity pl) BuildingToString ={ local string dist_string; local string hp; - if (engineer_move) { + if (engineer_move && self.sentry_ent) { hp = strcat(strpadl(ftos(floor(self.sentry_ent.health)), 2), " hp"); st = strcat(st,strcat(Q"\sSentry\s: ", hp)); st = strpadr(st, 14); @@ -1659,13 +1659,15 @@ string(entity pl) BuildingToString ={ st = strcat(st, Q"\sReady\s: "); st = strcat(st, ftos(pl.building_percentage)); st = strcat(st, "%"); - if (engineer_move) { - dist_percentage = (vlen(self.origin - self.sentry_ent.origin)/BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE)*100; - st = strpadr(st, 26); - st = strcat(st, Q"\sDistance\s:"); - dist_string = strcat(itos(dist_percentage),"%"); - dist_string = strcat(Q"\x10", dist_string ,Q"\x11"); - st = strcat(st, dist_string); + if (!engineer_move) { //disabling max_distance for moving engineer + if (engineer_move) { + dist_percentage = (vlen(self.origin - self.sentry_ent.origin)/BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE)*100; + st = strpadr(st, 26); + st = strcat(st, Q"\sDistance\s:"); + dist_string = strcat(itos(dist_percentage),"%"); + dist_string = strcat(Q"\x10", dist_string ,Q"\x11"); + st = strcat(st, dist_string); + } } return st; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fe5b1eda..be3327f5 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -279,7 +279,6 @@ void () W_FireSpanner = { if (trace_ent.takedamage) { if (trace_ent.classname == "building_dispenser") { - Engineer_UseDispenser(trace_ent); return; @@ -3330,7 +3329,7 @@ void () W_WeaponFrame = { // slot 1-4 (or 1-7) binds if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && (WeaponReady(self) || !chweap_wait_attfinished) - && !self.is_building && !self.is_detpacking) { + && !(self.is_building && !engineer_move) && !self.is_detpacking) { if (!(self.tfstate & TFSTATE_RELOADING)) { // load weapon state if current state doesn't match stored state From c29448f55bb15aa2888b561d40a7cce286a2995f Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 11 Oct 2020 22:29:29 -0300 Subject: [PATCH 1127/2474] fixing bugs --- ssqc/engineer.qc | 4 ++++ ssqc/sentry.qc | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index ebe3542f..35a5730d 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1050,6 +1050,10 @@ void () Dispenser_Die = { self.real_owner.has_dispenser = 0; self.think = Dispenser_Explode; self.nextthink = time + 0.1; + if (self.real_owner.is_building) { + self = self.real_owner; + TeamFortress_EngineerBuildStop(); + } }; void (entity disp) Engineer_UseDispenser = { diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index a96afd89..8c4b0e0c 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -264,6 +264,11 @@ void () Sentry_Die = { self.real_owner.has_sentry = 0; self.think = Sentry_Explode; self.nextthink = time + 0.1; + if (self.real_owner.is_building) { + self = self.real_owner; + TeamFortress_EngineerBuildStop(); + } + }; float () Sentry_Fire = { From 8b6981c48dd58a6612fd91d8f2a5f227715a53a0 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Mon, 12 Oct 2020 01:56:05 -0300 Subject: [PATCH 1128/2474] destroying sentry base when one dies while building --- ssqc/engineer.qc | 6 +++--- ssqc/tfort.qc | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 35a5730d..e518d301 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -353,9 +353,9 @@ void () TeamFortress_EngineerBuildStop = { sprint(self, PRINT_HIGH, "You stop building\n"); } if (engineer_move) { - if (self.has_sentry == 1) + if (te.classname == "building_sentrygun") self.has_sentry = 0; - else if (self.has_dispenser == 1) + else if (te.classname == "building_dispenser") self.has_dispenser = 0; } dremove(te); @@ -603,7 +603,7 @@ void () CF_CheckBuilding = { } } - if (building.weapon == 2) { + if (building.weapon == 2 || building.weapon == 0) { self.sentry_ticks = self.sentry_ticks + 0.3; self.building_percentage = ceil((self.sentry_ticks / 5) * 100); } else if (building.weapon == 1) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 957513f5..61b7fc58 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2301,6 +2301,12 @@ void () TeamFortress_RemoveTimers = { self.leg_damage = 0; self.is_concussed = 0; self.is_undercover = 0; + + if (self.is_building && engineer_move) { + bprint(2,"TEST 1\n"); + TeamFortress_EngineerBuildStop(); + } + self.is_building = 0; self.building = world; if (self.tfstate & TFSTATE_AIMING) { From 3dbc7a251382f8eea99600f64e5ee738c7871e17 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Tue, 13 Oct 2020 00:49:19 -0300 Subject: [PATCH 1129/2474] fixing concurrent build bugs --- ssqc/commands.qc | 4 +-- ssqc/engineer.qc | 76 +++++++++++++++++++++++++----------------------- ssqc/menu.qc | 4 +++ ssqc/status.qc | 2 +- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index d9251568..2f8c1994 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -624,7 +624,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if(arg2 == "cancel") { TeamFortress_EngineerBuildStop(); break; - } + } if(arg2 == "sentry") { if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); @@ -634,7 +634,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } if(arg2 == "dispenser") { - if(self.is_building) { + if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); break; } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index e518d301..021d4759 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -320,6 +320,19 @@ void () EMPGrenadeExplode = { dremove(self); }; +entity () FO_FindCurrentBuildingObject = { + local entity te; + te = find(world, netname, "build_timer"); + while (te) { + if (te.owner == self || (engineer_move && te.real_owner == self)) { + return te; + } else { + te = find(te, netname, "build_timer"); + } + } + return world; +} + void () TeamFortress_EngineerBuild = { if (self.is_building == 0) { if (((self.ammo_cells < 100) && !self.has_dispenser) && @@ -337,33 +350,31 @@ void () TeamFortress_EngineerBuildStop = { local entity te; local vector dist; - te = find(world, netname, "build_timer"); - while (te) { - if (te.owner == self || (engineer_move && te.real_owner == self)) { - dist = self.origin - te.origin; - if (vlen(dist) > 128) { - sprint(self, PRINT_HIGH, "Your building disappeared\n"); - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, te.origin_x); - WriteCoord(MSG_MULTICAST, te.origin_y); - WriteCoord(MSG_MULTICAST, te.origin_z); - multicast(te.origin, MULTICAST_PHS); - } else { - sprint(self, PRINT_HIGH, "You stop building\n"); - } - if (engineer_move) { - if (te.classname == "building_sentrygun") - self.has_sentry = 0; - else if (te.classname == "building_dispenser") - self.has_dispenser = 0; - } - dremove(te); - te = world; + te = FO_FindCurrentBuildingObject(); + if (te != world) { + dist = self.origin - te.origin; + if (vlen(dist) > 128) { + sprint(self, PRINT_HIGH, "Your building disappeared\n"); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, te.origin_x); + WriteCoord(MSG_MULTICAST, te.origin_y); + WriteCoord(MSG_MULTICAST, te.origin_z); + multicast(te.origin, MULTICAST_PHS); } else { - te = find(te, netname, "build_timer"); + sprint(self, PRINT_HIGH, "You stop building\n"); } + if (engineer_move) { + if (te.classname == "building_sentrygun") + self.has_sentry = 0; + else if (te.classname == "building_dispenser") + self.has_dispenser = 0; + } + dremove(te); + te = world; + } + Menu_Close(self); self.is_building = 0; self.building_percentage = 0; @@ -524,7 +535,6 @@ void (float objtobuild) TeamFortress_Build = { TeamFortress_SetSpeed(self); Menu_Engineer_Cancel(); } - Status_Refresh(self); newmis.owner = self; newmis.classname = "timer"; @@ -546,14 +556,12 @@ void (float objtobuild) TeamFortress_Build = { newmis.owner = world; newmis.real_owner = self; newmis.health = 50; + newmis.team_no = self.team_no; newmis.max_health = newmis.health; + newmis.takedamage = DAMAGE_AIM; if (objtobuild == 1) { self.has_dispenser = TRUE; newmis.th_die = Dispenser_Die; - newmis.team_no = self.team_no; - newmis.real_owner = self; - newmis.team_no = self.team_no; - newmis.takedamage = DAMAGE_AIM; self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; newmis.classname = "building_dispenser"; } @@ -565,7 +573,6 @@ void (float objtobuild) TeamFortress_Build = { newmis.takedamage = DAMAGE_AIM; self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; newmis.classname = "building_sentrygun"; - newmis.team_no = self.team_no; newmis.weapon = 0; } } @@ -578,6 +585,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.netname = "buildcheck_timer"; newmis.nextthink = time + 0.3; newmis.think = CF_CheckBuilding; + Status_Refresh(self); }; void () CF_CheckBuilding = { @@ -592,9 +600,7 @@ void () CF_CheckBuilding = { return; } - if (!engineer_move) { //disabling max_distance for moving engineer - if (engineer_move) - max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; + if (!engineer_move) { dist = self.origin - building.origin; if (vlen(dist) > max_dist) { TeamFortress_EngineerBuildStop(); @@ -1079,10 +1085,8 @@ void (entity disp) Engineer_UseDispenser = { self.ammo_cells = self.ammo_cells + ENG_DISPENSER_COST; if (self.ammo_cells > self.maxammo_cells) self.ammo_cells = self.maxammo_cells; - dremove (disp); W_SetCurrentAmmo(self); self = disp.real_owner; - self.has_dispenser = 0; TeamFortress_EngineerBuildStop(); return; } @@ -1256,10 +1260,8 @@ void (entity gun) Engineer_UseSentryGun = { self.ammo_cells = self.maxammo_cells; if (gun.trigger_field != world) dremove (gun.trigger_field); - dremove (gun); W_SetCurrentAmmo(self); self = gun.real_owner; - self.has_sentry = 0; TeamFortress_EngineerBuildStop(); return; } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 0ebe9b5a..660ae32c 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -837,6 +837,10 @@ void (float inp) Menu_Engineer_Input = { return; if (self.is_building) { + if (engineer_move) { + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You are already building something")); + return; + } Menu_Engineer(self); return; } diff --git a/ssqc/status.qc b/ssqc/status.qc index 545a2d4e..b0a3d947 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1650,7 +1650,7 @@ string(entity pl) BuildingToString ={ if (engineer_move && self.sentry_ent) { hp = strcat(strpadl(ftos(floor(self.sentry_ent.health)), 2), " hp"); st = strcat(st,strcat(Q"\sSentry\s: ", hp)); - st = strpadr(st, 14); + st = strpadr(st, 15); } if (!buildstatus) From 19d9f6fc1d167fc30f6a8ca7f59677493d6489d8 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sat, 10 Oct 2020 00:28:35 -0300 Subject: [PATCH 1130/2474] allowing engy to move while building --- share/defs.h | 3 ++ ssqc/client.qc | 1 + ssqc/engineer.qc | 127 +++++++++++++++++++++++++++++++++-------------- ssqc/qw.qc | 1 + ssqc/sentry.qc | 2 +- ssqc/status.qc | 22 ++++++-- 6 files changed, 114 insertions(+), 42 deletions(-) diff --git a/share/defs.h b/share/defs.h index a49a07e2..45f29073 100644 --- a/share/defs.h +++ b/share/defs.h @@ -670,6 +670,9 @@ #define BUILD_DISPENSER_MAX_CELLS 400 #define BUILD_DISPENSER_MAX_ARMOR 500 +#define BUILD_SENTRYGUN_MAX_DISTANCE 128 +#define BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE 1024 + /*======================================================*/ /* Ammo quantities for dropping */ /*======================================================*/ diff --git a/ssqc/client.qc b/ssqc/client.qc index fd047b4a..e9632df7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -713,6 +713,7 @@ void () DecodeLevelParms = { InitReverseCap(); } + engineer_move = CF_GetSetting("em","engineer_move", "0"); st = infokey(world, "default"); if (st == "on") { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index ec2f1bf7..9fb2ee77 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -337,12 +337,9 @@ void () TeamFortress_EngineerBuildStop = { local entity te; local vector dist; - self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; - self.movetype = MOVETYPE_WALK; - TeamFortress_SetSpeed(self); te = find(world, netname, "build_timer"); while (te) { - if (te.owner == self) { + if (te.owner == self || (engineer_move && te.real_owner == self)) { dist = self.origin - te.origin; if (vlen(dist) > 128) { sprint(self, PRINT_HIGH, "Your building disappeared\n"); @@ -355,6 +352,9 @@ void () TeamFortress_EngineerBuildStop = { } else { sprint(self, PRINT_HIGH, "You stop building\n"); } + if (engineer_move) { + self.has_sentry = 0; + } dremove(te); te = world; } else { @@ -364,8 +364,13 @@ void () TeamFortress_EngineerBuildStop = { Menu_Close(self); self.is_building = 0; self.building_percentage = 0; - self.current_weapon = self.weapon; - W_SetCurrentAmmo(self); + if (!engineer_move) { + self.current_weapon = self.weapon; + self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; + self.movetype = MOVETYPE_WALK; + TeamFortress_SetSpeed(self); + W_SetCurrentAmmo(self); + } } float (entity obj, entity builder) CheckArea = { @@ -505,16 +510,18 @@ void (float objtobuild) TeamFortress_Build = { } } self.is_building = 1; - self.immune_to_check = time + 5; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - self.movetype = MOVETYPE_NONE; - self.weapon = self.current_weapon; - self.current_weapon = 0; - self.weaponmodel = ""; - self.weaponframe = 0; - TeamFortress_SetSpeed(self); + if (!engineer_move) { + self.immune_to_check = time + 5; + self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + self.movetype = MOVETYPE_NONE; + self.weapon = self.current_weapon; + self.current_weapon = 0; + self.weaponmodel = ""; + self.weaponframe = 0; + TeamFortress_SetSpeed(self); + Menu_Engineer_Cancel(); + } Status_Refresh(self); - Menu_Engineer_Cancel(); newmis.owner = self; newmis.classname = "timer"; @@ -532,6 +539,22 @@ void (float objtobuild) TeamFortress_Build = { setorigin(newmis, newmis.origin); newmis.flags = newmis.flags - (newmis.flags & 512); + if (engineer_move) { + newmis.owner = world; + newmis.real_owner = self; + self.sentry_ent = newmis; + self.has_sentry = TRUE; + newmis.health = 50; + newmis.max_health = newmis.health; + newmis.th_die = Sentry_Die; + newmis.th_pain = Sentry_Pain; + newmis.takedamage = DAMAGE_AIM; + self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; + newmis.classname = "building_sentrygun"; + newmis.team_no = self.team_no; + newmis.weapon = 0; + } + oldmis = newmis; newmis = spawn(); newmis.owner = self; @@ -543,6 +566,7 @@ void (float objtobuild) TeamFortress_Build = { }; void () CF_CheckBuilding = { + local float max_dist = BUILD_SENTRYGUN_MAX_DISTANCE; local vector dist; local entity timer = self; local entity building = self.enemy; @@ -553,8 +577,10 @@ void () CF_CheckBuilding = { return; } + if (engineer_move) + max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; dist = self.origin - building.origin; - if (vlen(dist) > 128) { + if (vlen(dist) > max_dist) { TeamFortress_EngineerBuildStop(); dremove(timer); return; @@ -811,9 +837,17 @@ void UpdateClient_Dispenser(entity pl, entity disp) = { void () TeamFortress_FinishedBuilding = { local entity oldself; - if (self.owner.is_building != 1) { - return; + if (engineer_move) { + if (self.real_owner.is_building != 1) { + return; + } } + else { + if (self.owner.is_building != 1) { + return; + } + } + self.owner = self.real_owner; local float csqcactive = infokeyf(self.owner, INFOKEY_P_CSQCACTIVE); @@ -823,11 +857,14 @@ void () TeamFortress_FinishedBuilding = { oldself.real_owner = self; self.is_building = FALSE; self.building_percentage = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - self.movetype = MOVETYPE_WALK; - self.current_weapon = self.weapon; + if (!engineer_move) { + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.movetype = MOVETYPE_WALK; + self.current_weapon = self.weapon; + TeamFortress_SetSpeed(self); + } Status_Refresh(self); - TeamFortress_SetSpeed(self); + Menu_Close(self); if (oldself.weapon == 1) { self.has_dispenser = TRUE; @@ -871,7 +908,7 @@ void () TeamFortress_FinishedBuilding = { if(csqcactive) { UpdateClient_Dispenser(self, oldself); } - } else if (oldself.weapon == 2) { + } else if (oldself.weapon == 2 || (engineer_move && oldself.weapon == 0)) { self.has_sentry = TRUE; sprint(self, PRINT_HIGH, "You finish building the sentry gun\n"); teamsprint(self.team_no, self, self.netname); @@ -883,7 +920,8 @@ void () TeamFortress_FinishedBuilding = { oldself.team_no = self.team_no; oldself.think = CheckPyroLava; oldself.nextthink = time + .1; - self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; + if (!engineer_move) + self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; setsize(oldself, '-16 -16 0', '16 16 4'); newmis = spawn(); newmis.classname = "building_sentrygun"; @@ -1162,18 +1200,29 @@ void (entity gun) Engineer_UseSentryGun = { // automate tasks if old_spanner setting is disabled if (!old_spanner) { if(gun.team_no > 0 && gun.team_no == self.team_no) { - //Menu_EngineerFix_SentryGun_Rotate(); - Engineer_SentryGun_ShowMenu(self.building); - if (gun.weapon < 3 && self.ammo_cells >= ENG_SENTRY_COST) { - Engineer_SentryGun_Upgrade(gun); - return; - } else if (gun.health < gun.max_health && self.ammo_cells > 0) { - Engineer_SentryGun_Repair(gun); - return; - } else if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) - || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets - && self.ammo_rockets > 0)) { - Engineer_SentryGun_InsertAmmo(gun); + if (gun.weapon > 0) { + //Menu_EngineerFix_SentryGun_Rotate(); + Engineer_SentryGun_ShowMenu(self.building); + if (gun.weapon < 3 && self.ammo_cells >= ENG_SENTRY_COST) { + Engineer_SentryGun_Upgrade(gun); + return; + } else if (gun.health < gun.max_health && self.ammo_cells > 0) { + Engineer_SentryGun_Repair(gun); + return; + } else if ((gun.ammo_shells < gun.maxammo_shells && self.ammo_shells > 0) + || (gun.weapon == 3 && gun.ammo_rockets < gun.maxammo_rockets + && self.ammo_rockets > 0)) { + Engineer_SentryGun_InsertAmmo(gun); + return; + } + } else { + sprint (self, PRINT_HIGH, strcat("You stopped building sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); + self.ammo_cells = self.ammo_cells + ENG_SENTRY_COST; + if (gun.trigger_field != world) + dremove (gun.trigger_field); + dremove (gun); + self.has_sentry = 0; + W_SetCurrentAmmo(self); return; } } else { // hit enemy sentry @@ -1182,7 +1231,8 @@ void (entity gun) Engineer_UseSentryGun = { bprint(PRINT_HIGH, self.netname, " dismantled ", gun.real_owner.netname, "'s sentry gun\n"); TF_AddFrags(self, 1); sprint(gun.real_owner, PRINT_HIGH, "Your sentry gun was dismantled by ",self.netname,"\n"); - dremove (gun.trigger_field); + if (gun.trigger_field != world) + dremove (gun.trigger_field); dremove (gun); ThrowGib("progs/tgib1.mdl", -30); ThrowGib("progs/tgib2.mdl", -50); @@ -1371,7 +1421,8 @@ void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { te.real_owner.has_dispenser = 0; if(bld == "building_sentrygun") { te.real_owner.has_sentry = 0; - dremove (te.trigger_field); + if (te.trigger_field != world) + dremove (te.trigger_field); } spawn_tfog(te.origin); dremove (te); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 50ba81a4..9cc09803 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -591,6 +591,7 @@ float noreturn; float nohitsounds; //float server_sbflaginfo; float reverse_cap; +float engineer_move; float numlocs; typedef struct {vector pos; string desc;} loc_t; diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 204b30bf..a96afd89 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -245,7 +245,7 @@ void () Sentry_Explode = { if (self.classname == "building_sentrygun_base") { if (self.oldenemy) dremove(self.oldenemy); - } else + } else if (self.trigger_field != world) dremove(self.trigger_field); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); diff --git a/ssqc/status.qc b/ssqc/status.qc index ebff41a6..85bc93fa 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1641,16 +1641,32 @@ string(entity pl) SentryDetailsToString = return st; }; -string(entity pl) BuildingToString = -{ +string(entity pl) BuildingToString ={ local string st = ""; + local int dist_percentage; + local string dist_string; + local string hp; + + if (engineer_move) { + hp = strcat(strpadl(ftos(floor(self.sentry_ent.health)), 2), " hp"); + st = strcat(st,strcat(Q"\sSentry\s: ", hp)); + st = strpadr(st, 14); + } if (!buildstatus) return "Building..."; - st = Q"\sBuilding\s: "; + st = strcat(st, Q"\sReady\s: "); st = strcat(st, ftos(pl.building_percentage)); st = strcat(st, "%"); + if (engineer_move) { + dist_percentage = (vlen(self.origin - self.sentry_ent.origin)/BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE)*100; + st = strpadr(st, 26); + st = strcat(st, Q"\sDistance\s:"); + dist_string = strcat(itos(dist_percentage),"%"); + dist_string = strcat(Q"\x10", dist_string ,Q"\x11"); + st = strcat(st, dist_string); + } return st; }; From 220d52c73c496c4fdc5ca89fbc955cf9edc371e5 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 11 Oct 2020 14:11:37 -0300 Subject: [PATCH 1131/2474] dispenser and removing max_distance as a test --- ssqc/commands.qc | 2 +- ssqc/engineer.qc | 80 +++++++++++++++++++++++++++++++++++------------- ssqc/menu.qc | 18 ++++++++--- ssqc/status.qc | 18 ++++++----- ssqc/weapons.qc | 3 +- 5 files changed, 83 insertions(+), 38 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index df5835ed..369357ea 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -643,7 +643,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } if(arg2 == "sentry") { - if(self.is_building) { + if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); break; } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 9fb2ee77..ebe3542f 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -353,7 +353,10 @@ void () TeamFortress_EngineerBuildStop = { sprint(self, PRINT_HIGH, "You stop building\n"); } if (engineer_move) { - self.has_sentry = 0; + if (self.has_sentry == 1) + self.has_sentry = 0; + else if (self.has_dispenser == 1) + self.has_dispenser = 0; } dremove(te); te = world; @@ -542,17 +545,29 @@ void (float objtobuild) TeamFortress_Build = { if (engineer_move) { newmis.owner = world; newmis.real_owner = self; - self.sentry_ent = newmis; - self.has_sentry = TRUE; newmis.health = 50; newmis.max_health = newmis.health; - newmis.th_die = Sentry_Die; - newmis.th_pain = Sentry_Pain; - newmis.takedamage = DAMAGE_AIM; - self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; - newmis.classname = "building_sentrygun"; - newmis.team_no = self.team_no; - newmis.weapon = 0; + if (objtobuild == 1) { + self.has_dispenser = TRUE; + newmis.th_die = Dispenser_Die; + newmis.team_no = self.team_no; + newmis.real_owner = self; + newmis.team_no = self.team_no; + newmis.takedamage = DAMAGE_AIM; + self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; + newmis.classname = "building_dispenser"; + } + if (objtobuild == 2) { + self.sentry_ent = newmis; + self.has_sentry = TRUE; + newmis.th_die = Sentry_Die; + newmis.th_pain = Sentry_Pain; + newmis.takedamage = DAMAGE_AIM; + self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; + newmis.classname = "building_sentrygun"; + newmis.team_no = self.team_no; + newmis.weapon = 0; + } } oldmis = newmis; @@ -577,13 +592,15 @@ void () CF_CheckBuilding = { return; } - if (engineer_move) - max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; - dist = self.origin - building.origin; - if (vlen(dist) > max_dist) { - TeamFortress_EngineerBuildStop(); - dremove(timer); - return; + if (!engineer_move) { //disabling max_distance for moving engineer + if (engineer_move) + max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; + dist = self.origin - building.origin; + if (vlen(dist) > max_dist) { + TeamFortress_EngineerBuildStop(); + dremove(timer); + return; + } } if (building.weapon == 2) { @@ -835,8 +852,7 @@ void UpdateClient_Dispenser(entity pl, entity disp) = { void () TeamFortress_FinishedBuilding = { - local entity oldself; - + local entity oldself; if (engineer_move) { if (self.real_owner.is_building != 1) { return; @@ -1038,7 +1054,6 @@ void () Dispenser_Die = { void (entity disp) Engineer_UseDispenser = { local entity dist_checker; - // engineer hits enemy dispenser - dismantle if(!(disp.team_no > 0 && disp.team_no == self.team_no)) { self.ammo_cells = self.ammo_cells + 50; @@ -1054,6 +1069,21 @@ void (entity disp) Engineer_UseDispenser = { return; } + if (self.team_no == disp.team_no) { + if (disp.real_owner.is_building) { + sprint (self, PRINT_HIGH, strcat("You stopped building a dispenser and got ", ftos(ENG_DISPENSER_COST), " cells back\n")); + self.ammo_cells = self.ammo_cells + ENG_DISPENSER_COST; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; + dremove (disp); + W_SetCurrentAmmo(self); + self = disp.real_owner; + self.has_dispenser = 0; + TeamFortress_EngineerBuildStop(); + return; + } + } + if (disp.health < disp.max_health && !old_spanner) { Engineer_Dispenser_Repair(disp); return; @@ -1216,17 +1246,23 @@ void (entity gun) Engineer_UseSentryGun = { return; } } else { - sprint (self, PRINT_HIGH, strcat("You stopped building sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); + sprint (self, PRINT_HIGH, strcat("You stopped building a sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); self.ammo_cells = self.ammo_cells + ENG_SENTRY_COST; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; if (gun.trigger_field != world) dremove (gun.trigger_field); dremove (gun); - self.has_sentry = 0; W_SetCurrentAmmo(self); + self = gun.real_owner; + self.has_sentry = 0; + TeamFortress_EngineerBuildStop(); return; } } else { // hit enemy sentry self.ammo_cells = self.ammo_cells + 65; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; gun.real_owner.has_sentry = 0; bprint(PRINT_HIGH, self.netname, " dismantled ", gun.real_owner.netname, "'s sentry gun\n"); TF_AddFrags(self, 1); diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 104216e3..0ebe9b5a 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -844,11 +844,19 @@ void (float inp) Menu_Engineer_Input = { dismantle_sentrygun = 0; dismantle_dispenser = 0; - if (inp == 1 && !self.has_sentry && self.ammo_cells >= ENG_SENTRY_COST) - TeamFortress_Build(2); - - if (inp == 2 && !self.has_dispenser && self.ammo_cells >= ENG_DISPENSER_COST) - TeamFortress_Build(1); + if (inp == 1 && !self.has_sentry) { + if (self.ammo_cells >= ENG_SENTRY_COST) + TeamFortress_Build(2); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST), " cells to build a sentry gun")); + } + + if (inp == 2 && !self.has_dispenser) { + if (self.ammo_cells >= ENG_DISPENSER_COST) + TeamFortress_Build(1); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); + } if (inp == 3 && self.has_sentry) { te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); diff --git a/ssqc/status.qc b/ssqc/status.qc index 85bc93fa..545a2d4e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1647,7 +1647,7 @@ string(entity pl) BuildingToString ={ local string dist_string; local string hp; - if (engineer_move) { + if (engineer_move && self.sentry_ent) { hp = strcat(strpadl(ftos(floor(self.sentry_ent.health)), 2), " hp"); st = strcat(st,strcat(Q"\sSentry\s: ", hp)); st = strpadr(st, 14); @@ -1659,13 +1659,15 @@ string(entity pl) BuildingToString ={ st = strcat(st, Q"\sReady\s: "); st = strcat(st, ftos(pl.building_percentage)); st = strcat(st, "%"); - if (engineer_move) { - dist_percentage = (vlen(self.origin - self.sentry_ent.origin)/BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE)*100; - st = strpadr(st, 26); - st = strcat(st, Q"\sDistance\s:"); - dist_string = strcat(itos(dist_percentage),"%"); - dist_string = strcat(Q"\x10", dist_string ,Q"\x11"); - st = strcat(st, dist_string); + if (!engineer_move) { //disabling max_distance for moving engineer + if (engineer_move) { + dist_percentage = (vlen(self.origin - self.sentry_ent.origin)/BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE)*100; + st = strpadr(st, 26); + st = strcat(st, Q"\sDistance\s:"); + dist_string = strcat(itos(dist_percentage),"%"); + dist_string = strcat(Q"\x10", dist_string ,Q"\x11"); + st = strcat(st, dist_string); + } } return st; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fe5b1eda..be3327f5 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -279,7 +279,6 @@ void () W_FireSpanner = { if (trace_ent.takedamage) { if (trace_ent.classname == "building_dispenser") { - Engineer_UseDispenser(trace_ent); return; @@ -3330,7 +3329,7 @@ void () W_WeaponFrame = { // slot 1-4 (or 1-7) binds if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && (WeaponReady(self) || !chweap_wait_attfinished) - && !self.is_building && !self.is_detpacking) { + && !(self.is_building && !engineer_move) && !self.is_detpacking) { if (!(self.tfstate & TFSTATE_RELOADING)) { // load weapon state if current state doesn't match stored state From a39efcbfd1a055457954824565605d378f1d7b55 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 11 Oct 2020 22:29:29 -0300 Subject: [PATCH 1132/2474] fixing bugs --- ssqc/engineer.qc | 4 ++++ ssqc/sentry.qc | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index ebe3542f..35a5730d 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1050,6 +1050,10 @@ void () Dispenser_Die = { self.real_owner.has_dispenser = 0; self.think = Dispenser_Explode; self.nextthink = time + 0.1; + if (self.real_owner.is_building) { + self = self.real_owner; + TeamFortress_EngineerBuildStop(); + } }; void (entity disp) Engineer_UseDispenser = { diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index a96afd89..8c4b0e0c 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -264,6 +264,11 @@ void () Sentry_Die = { self.real_owner.has_sentry = 0; self.think = Sentry_Explode; self.nextthink = time + 0.1; + if (self.real_owner.is_building) { + self = self.real_owner; + TeamFortress_EngineerBuildStop(); + } + }; float () Sentry_Fire = { From adad9f6d87b984f00cb58861e344beb90741abcc Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Mon, 12 Oct 2020 01:56:05 -0300 Subject: [PATCH 1133/2474] destroying sentry base when one dies while building --- ssqc/engineer.qc | 6 +++--- ssqc/tfort.qc | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 35a5730d..e518d301 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -353,9 +353,9 @@ void () TeamFortress_EngineerBuildStop = { sprint(self, PRINT_HIGH, "You stop building\n"); } if (engineer_move) { - if (self.has_sentry == 1) + if (te.classname == "building_sentrygun") self.has_sentry = 0; - else if (self.has_dispenser == 1) + else if (te.classname == "building_dispenser") self.has_dispenser = 0; } dremove(te); @@ -603,7 +603,7 @@ void () CF_CheckBuilding = { } } - if (building.weapon == 2) { + if (building.weapon == 2 || building.weapon == 0) { self.sentry_ticks = self.sentry_ticks + 0.3; self.building_percentage = ceil((self.sentry_ticks / 5) * 100); } else if (building.weapon == 1) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 957513f5..61b7fc58 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2301,6 +2301,12 @@ void () TeamFortress_RemoveTimers = { self.leg_damage = 0; self.is_concussed = 0; self.is_undercover = 0; + + if (self.is_building && engineer_move) { + bprint(2,"TEST 1\n"); + TeamFortress_EngineerBuildStop(); + } + self.is_building = 0; self.building = world; if (self.tfstate & TFSTATE_AIMING) { From 885fa44a1e8268daa4751306dbe10cb1d144f798 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Tue, 13 Oct 2020 00:49:19 -0300 Subject: [PATCH 1134/2474] fixing concurrent build bugs --- ssqc/commands.qc | 4 +-- ssqc/engineer.qc | 76 +++++++++++++++++++++++++----------------------- ssqc/menu.qc | 4 +++ ssqc/status.qc | 2 +- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 369357ea..45ae0d45 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -641,7 +641,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if(arg2 == "cancel") { TeamFortress_EngineerBuildStop(); break; - } + } if(arg2 == "sentry") { if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); @@ -651,7 +651,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } if(arg2 == "dispenser") { - if(self.is_building) { + if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); break; } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index e518d301..021d4759 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -320,6 +320,19 @@ void () EMPGrenadeExplode = { dremove(self); }; +entity () FO_FindCurrentBuildingObject = { + local entity te; + te = find(world, netname, "build_timer"); + while (te) { + if (te.owner == self || (engineer_move && te.real_owner == self)) { + return te; + } else { + te = find(te, netname, "build_timer"); + } + } + return world; +} + void () TeamFortress_EngineerBuild = { if (self.is_building == 0) { if (((self.ammo_cells < 100) && !self.has_dispenser) && @@ -337,33 +350,31 @@ void () TeamFortress_EngineerBuildStop = { local entity te; local vector dist; - te = find(world, netname, "build_timer"); - while (te) { - if (te.owner == self || (engineer_move && te.real_owner == self)) { - dist = self.origin - te.origin; - if (vlen(dist) > 128) { - sprint(self, PRINT_HIGH, "Your building disappeared\n"); - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, te.origin_x); - WriteCoord(MSG_MULTICAST, te.origin_y); - WriteCoord(MSG_MULTICAST, te.origin_z); - multicast(te.origin, MULTICAST_PHS); - } else { - sprint(self, PRINT_HIGH, "You stop building\n"); - } - if (engineer_move) { - if (te.classname == "building_sentrygun") - self.has_sentry = 0; - else if (te.classname == "building_dispenser") - self.has_dispenser = 0; - } - dremove(te); - te = world; + te = FO_FindCurrentBuildingObject(); + if (te != world) { + dist = self.origin - te.origin; + if (vlen(dist) > 128) { + sprint(self, PRINT_HIGH, "Your building disappeared\n"); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, te.origin_x); + WriteCoord(MSG_MULTICAST, te.origin_y); + WriteCoord(MSG_MULTICAST, te.origin_z); + multicast(te.origin, MULTICAST_PHS); } else { - te = find(te, netname, "build_timer"); + sprint(self, PRINT_HIGH, "You stop building\n"); } + if (engineer_move) { + if (te.classname == "building_sentrygun") + self.has_sentry = 0; + else if (te.classname == "building_dispenser") + self.has_dispenser = 0; + } + dremove(te); + te = world; + } + Menu_Close(self); self.is_building = 0; self.building_percentage = 0; @@ -524,7 +535,6 @@ void (float objtobuild) TeamFortress_Build = { TeamFortress_SetSpeed(self); Menu_Engineer_Cancel(); } - Status_Refresh(self); newmis.owner = self; newmis.classname = "timer"; @@ -546,14 +556,12 @@ void (float objtobuild) TeamFortress_Build = { newmis.owner = world; newmis.real_owner = self; newmis.health = 50; + newmis.team_no = self.team_no; newmis.max_health = newmis.health; + newmis.takedamage = DAMAGE_AIM; if (objtobuild == 1) { self.has_dispenser = TRUE; newmis.th_die = Dispenser_Die; - newmis.team_no = self.team_no; - newmis.real_owner = self; - newmis.team_no = self.team_no; - newmis.takedamage = DAMAGE_AIM; self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; newmis.classname = "building_dispenser"; } @@ -565,7 +573,6 @@ void (float objtobuild) TeamFortress_Build = { newmis.takedamage = DAMAGE_AIM; self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; newmis.classname = "building_sentrygun"; - newmis.team_no = self.team_no; newmis.weapon = 0; } } @@ -578,6 +585,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.netname = "buildcheck_timer"; newmis.nextthink = time + 0.3; newmis.think = CF_CheckBuilding; + Status_Refresh(self); }; void () CF_CheckBuilding = { @@ -592,9 +600,7 @@ void () CF_CheckBuilding = { return; } - if (!engineer_move) { //disabling max_distance for moving engineer - if (engineer_move) - max_dist = BUILD_SENTRYGUN_MAX_DISTANCE_ENGMOVE; + if (!engineer_move) { dist = self.origin - building.origin; if (vlen(dist) > max_dist) { TeamFortress_EngineerBuildStop(); @@ -1079,10 +1085,8 @@ void (entity disp) Engineer_UseDispenser = { self.ammo_cells = self.ammo_cells + ENG_DISPENSER_COST; if (self.ammo_cells > self.maxammo_cells) self.ammo_cells = self.maxammo_cells; - dremove (disp); W_SetCurrentAmmo(self); self = disp.real_owner; - self.has_dispenser = 0; TeamFortress_EngineerBuildStop(); return; } @@ -1256,10 +1260,8 @@ void (entity gun) Engineer_UseSentryGun = { self.ammo_cells = self.maxammo_cells; if (gun.trigger_field != world) dremove (gun.trigger_field); - dremove (gun); W_SetCurrentAmmo(self); self = gun.real_owner; - self.has_sentry = 0; TeamFortress_EngineerBuildStop(); return; } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 0ebe9b5a..660ae32c 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -837,6 +837,10 @@ void (float inp) Menu_Engineer_Input = { return; if (self.is_building) { + if (engineer_move) { + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You are already building something")); + return; + } Menu_Engineer(self); return; } diff --git a/ssqc/status.qc b/ssqc/status.qc index 545a2d4e..b0a3d947 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -1650,7 +1650,7 @@ string(entity pl) BuildingToString ={ if (engineer_move && self.sentry_ent) { hp = strcat(strpadl(ftos(floor(self.sentry_ent.health)), 2), " hp"); st = strcat(st,strcat(Q"\sSentry\s: ", hp)); - st = strpadr(st, 14); + st = strpadr(st, 15); } if (!buildstatus) From 888a6f7ed63b3669196d01ce608b716a8603fcca Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Tue, 13 Oct 2020 00:53:09 -0300 Subject: [PATCH 1135/2474] removing debug messages! --- ssqc/tfort.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 61b7fc58..62554d05 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2303,7 +2303,6 @@ void () TeamFortress_RemoveTimers = { self.is_undercover = 0; if (self.is_building && engineer_move) { - bprint(2,"TEST 1\n"); TeamFortress_EngineerBuildStop(); } From 04e60c7a626f9a02524d4ad9d5c26ae3e4bf8449 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Tue, 13 Oct 2020 00:57:03 -0300 Subject: [PATCH 1136/2474] readme update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a4bb5cdf..e68901d2 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ New features * Pyro types - `localinfo pyro_type val` - 0 = original tf2.9, 1 = oztf pyro style, 2 = FO pyro style * localinfo server_sbflaginfo : 0 - disables sbar flaginfo, 1 enables it [default: 1] * localinfo reverse_cap : 0 - normal gameplay, 1: you have to take your flag and capture in the enemy base [default: 0] +* localinfo engineer_move / em : 0 - normal gameplay, 1: engineers can move while building [default: 0] == Removed === * Removed weapon messages for weapons without weapon modes. From 446faca60d5684e48c0e79bb36c53ea6f78c35e3 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Tue, 13 Oct 2020 01:15:57 -0300 Subject: [PATCH 1137/2474] fixing bug when engineer_move is not activated --- ssqc/engineer.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 021d4759..1b9df028 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -869,7 +869,8 @@ void () TeamFortress_FinishedBuilding = { return; } } - self.owner = self.real_owner; + if (engineer_move) + self.owner = self.real_owner; local float csqcactive = infokeyf(self.owner, INFOKEY_P_CSQCACTIVE); From f4878f1dc50e7b2e4c8791450d1d71959dbea8ac Mon Sep 17 00:00:00 2001 From: danni Date: Tue, 13 Oct 2020 21:56:17 +1100 Subject: [PATCH 1138/2474] airblast reload sound/msg, fix visible -> infront function --- ssqc/pyro.qc | 15 +++++++++++++-- ssqc/world.qc | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 32ab46ce..d223e259 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -748,12 +748,23 @@ void () TeamFortress_FlameThrower = { W_SetCurrentAmmo(self); }; +void () AirBlastReloadFinished = { + sprint(self.owner, PRINT_HIGH, "Airblast ready\n"); + stuffcmd(self.owner, "play weapons/airblast.wav\n"); + dremove(self); +}; + void () UseAirBlast = { if (self.special_cooldown < time) { self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; + entity timer = spawn(); + timer.owner = self; + timer.classname = "timer"; + timer.nextthink = time + PC_PYRO_AIRBLAST_COOLDOWN; + timer.think = AirBlastReloadFinished; - FO_Sound(self, CHAN_WEAPON, "weapons/airblast.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); makevectors(self.v_angle); entity ent; @@ -762,7 +773,7 @@ void () UseAirBlast = { { if (ent.movetype != MOVETYPE_NONE && ent != self) { - if (visible(ent)) + if (infront(ent)) { switch (ent.classname) { diff --git a/ssqc/world.qc b/ssqc/world.qc index 44765581..38b52623 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -317,6 +317,7 @@ void () worldspawn = { precache_sound("blob/sight1.wav"); precache_sound("misc/secret.wav"); precache_sound("weapons/airblast.wav"); + precache_sound("weapons/airblastshoot.wav"); lightstyle(0, "m"); lightstyle(1, "mmnmmommommnonmmonqnmmo"); lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); From d7bdfd047c4bdf891e3a3465477ff0abcfc7b533 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Tue, 13 Oct 2020 14:15:27 -0300 Subject: [PATCH 1139/2474] adjusting pyro to deal more damage on direct hits and less on splash, compensating rjump momentum --- ssqc/combat.qc | 3 +++ ssqc/engineer.qc | 1 - ssqc/pyro.qc | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 84863050..6e6d461a 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -537,6 +537,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, moment = 0; } else moment = damage; + if (inflictor.classname == "pyro_rocket") { + moment = damage * 1.4; + } if ((moment < 60) && (attacker.classname == "player") diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 484abf1c..aecb909d 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -939,7 +939,6 @@ void () TeamFortress_FinishedBuilding = { oldself.takedamage = DAMAGE_NO; oldself.th_die = Sentry_Die; oldself.team_no = self.team_no; - oldself.think = CheckPyroLava; oldself.nextthink = time + .1; if (!engineer_move) self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index d223e259..3331c1a0 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -630,7 +630,7 @@ void () IncendiaryRadius = { void () IncendiaryRadius_OZTF = { local float damg; - damg = 92; + damg = 76; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -660,7 +660,7 @@ void () T_IncendiaryTouch = { } else { - damg = 42 + random() * 20; + damg = 76 + random() * 20; } if (other.health) { From f770f895825cf9d25eaf0bc297d333ceebfdf69f Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Tue, 13 Oct 2020 14:37:39 -0300 Subject: [PATCH 1140/2474] adjusting damage balance --- ssqc/combat.qc | 2 +- ssqc/pyro.qc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 6e6d461a..02e30fea 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -538,7 +538,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, } else moment = damage; if (inflictor.classname == "pyro_rocket") { - moment = damage * 1.4; + moment = damage * 1.5; } if ((moment < 60) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 3331c1a0..95ab13c3 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -630,7 +630,7 @@ void () IncendiaryRadius = { void () IncendiaryRadius_OZTF = { local float damg; - damg = 76; + damg = 68; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -660,7 +660,7 @@ void () T_IncendiaryTouch = { } else { - damg = 76 + random() * 20; + damg = 68 + random() * 20; } if (other.health) { From 6518010c6ff8e6b6bf1f5b851ea84211a44508a2 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 15 Oct 2020 00:09:05 +1300 Subject: [PATCH 1141/2474] enough for today --- csqc/csextradefs.qc | 5 +- csqc/hud.qc | 159 +++++++++++++++++++++++++++++++++++++++++++- csqc/input.qc | 46 +++++++++++++ csqc/main.qc | 14 +++- csqc/menu.qc | 17 ++++- csqc/status.qc | 2 +- csqc/sui_sys.qc | 17 +++-- csqc/vote.qc | 4 +- 8 files changed, 249 insertions(+), 15 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 407cca79..58f628b9 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -82,7 +82,10 @@ float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown float jump_counter; float frames_since_onground; -//float hud_idle_alpha; +float num_mapvotes; +entity vote_selected_item; +float vote_selected_index; +float vote_list_offset; .string name; .string description; diff --git a/csqc/hud.qc b/csqc/hud.qc index d1e26072..2fc75e85 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -220,7 +220,19 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, fl } return pos + iconsize; } - +//MEHT this is a sui example thing +void(string id, vector pos, vector size, string name, string command) bind_button = +{ + sui_push_frame(pos, size); + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + string key = "A"; //sui_binder(id, [0, 0], size, name, command); + if (sui_is_hovered(id)) sui_fill([0, 0], size, MENU_HIGHLIGHT, 0.1, 0); + sui_text([6, 0], MENU_TEXT_SMALL, name, MENU_TEXT_1, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([-6, 0], MENU_TEXT_SMALL, key, MENU_TEXT_1, 1, 0); + + sui_pop_frame(); +}; void(string panelid) Hud_DrawMapMenuPanel = { float id = getHudPanel(panelid); @@ -230,13 +242,156 @@ void(string panelid) Hud_DrawMapMenuPanel = { FO_Hud_Panel* panel = getHudPanelPointer(id); local vector fillsize = panel.FillSize * panel.Scale; - local float alpha = 0.2; + local float alpha = fo_hud_editor?0.2:0.9; + if(panel.Display) { + setcursormode(TRUE); + } if (hud_panel(panelid, panel.Position, fillsize, alpha, panel.Display)) { // click event if (fo_hud_editor) { } } + + if(fo_hud_editor) { + return; + } + + local vector bgcolour = MENU_BG_DARK, textcolour = MENU_TEXT_1; + local float textscale = 1, padding = 4, cnt = 0; + local float titlesize = 12; + local float listitemhover = FALSE; + local vector listitemsize = [100, 10], listitempos = [0,0]; + if(panel.TextScale) { + textscale = panel.TextScale; + } else { + textscale = panel.Scale; + } + listitemsize.y = listitemsize.y * textscale; + titlesize = titlesize * textscale; + padding = padding * panel.Scale; + listitemsize.x = listitemsize.y * 14; //14 chars of mapname + + local vector listviewsize = [listitemsize.x, fillsize.y - padding * 3 - listitemsize.y]; + local float visiblelistitems = floor(listviewsize.y / listitemsize.y); + + //Window title + sui_push_frame(panel.Position + [padding,padding], [fillsize.x - padding * 2, titlesize]); + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_text([padding, 0], [titlesize,titlesize], "Map Selection", MENU_TEXT_4, 1, 0); + sui_pop_frame(); + + + vector listoffset; +/* + sui_list_view_begin(strcat("a", "scrl"), panel.Position + [200,4], [100, 150], [94, 10], num_mapvotes, listoffset, [0, 6]); + vector listitem_pos = '0 0 0'; + for (float index = sui_list_item(listitem_pos); index > -1; index = sui_list_item(listitem_pos)) + { + sui_push_frame(listitem_pos, [94, 10]); + //bind_button(strcat("b", ftos(index)), [0, 0], [94, 24], "index is ", ftos(index)); + hud_button(strcat("b", ftos(index)), listitem_pos, [94, 24], "index is ", ftos(index)); + //drawstring(listitem_pos, strcat("a", ftos(index)), [8,8], MENU_TEXT_2, 1, 0); + + sui_pop_frame(); + } + sui_list_view_end(); +*/ + //sui_scroll_view_begin("scrolltest", panel.Position + [200,4], [100,100], [100,200], listoffset, [2,6]); + //sui_scroll_view_end(); + if(vote_list_offset > num_mapvotes - visiblelistitems) { + vote_list_offset = num_mapvotes - visiblelistitems; + } + if(vote_list_offset < 0) { + vote_list_offset = 0; + } + sui_border_box(panel.Position + [padding, padding * 2 + titlesize], listviewsize, 1, MENU_BORDER, 0.6, 0); + entity mc = find(world, classname, "map_candidate"); + while(mc) { + if(cnt >= vote_list_offset) { + listitempos = panel.Position + [padding, padding * 2 + titlesize + listitemsize.y * (cnt - vote_list_offset)]; + if((listitempos.y + listitemsize.y + padding) > (panel.Position.y + fillsize.y)) { + //too many to fit + break; + } + listitemhover = (Mouse.x > listitempos.x && Mouse.y > listitempos.y && Mouse.x < (listitempos.x + listitemsize.x) && Mouse.y < (listitempos.y + listitemsize.y)); + if(listitemhover) { + bgcolour = MENU_BORDER; //MENU_UNSELECTED; + } else { + bgcolour = MENU_BG_DARK; + } + if(vote_selected_index < 0) { + vote_selected_index = 0; + } + if(vote_selected_index >= num_mapvotes) { + vote_selected_index = num_mapvotes - 1; + } + if(vote_selected_index == cnt) { + vote_selected_item = mc; + } + if(!vote_selected_item) { + vote_selected_item = mc; + vote_selected_index = cnt; + } + if(mc == vote_selected_item) { + alpha = 1; + bgcolour = MENU_BG_WARNING; + } else { + alpha = 0.4; + } + //sui_border_box(listitempos, listitemsize, 1, bgcolour, 0.4, 0); + //sui_fill(listitempos, listitemsize, bgcolour, alpha, 0); + //sui_text(listitempos, [listitemsize.y, listitemsize.y], mc.name, textcolour, alpha, 0); + if(hud_colour_button(strcat("listitem",ftos(cnt)),listitempos, listitemsize, mc.name, bgcolour, [listitemsize.y, listitemsize.y], textcolour, SUI_ALIGN_START, 2, alpha, alpha, 1)) { + vote_selected_item = mc; + vote_selected_index = cnt; + print("Selected is now ", mc.name, "\n"); //MEHT + } + } + cnt++; + mc = find(mc, classname, "map_candidate"); + } + if(cnt < num_mapvotes) { + //draw scrollbar here + //sui_scrollbar("maplist_scrollbar", [listitemsize.x, fillsize.y - padding * 3 - listitemsize.y], [listitemsize.x,listitemsize.y * num_mapvotes], listoffset, [0,6]); + } + + sui_border_box(panel.Position, fillsize, 1, MENU_BORDER, 0.6, 0); + + //Map heading + vector mapheadingpos = [panel.Position.x + padding * 2 + listviewsize.x, panel.Position.y + padding * 2 + titlesize]; + float mapinfowidth = fillsize.x - (mapheadingpos.x - panel.Position.x); + sui_push_frame(mapheadingpos, [mapinfowidth, titlesize]); + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_text([padding, 0], [titlesize,titlesize], vote_selected_item.name, MENU_TEXT_2, 1, 0); + sui_pop_frame(); + + //Map image + float filehandle; + string levelshot = strcat("textures/levelshots/",vote_selected_item.name,".jpg"); //need to fix extensions somehow + filehandle = fopen(levelshot, FILE_READ); + if (filehandle >= 0) { + fclose(filehandle); + //Make it half the width of the map info area and aspect of 1.25:1 + vector levelshotsize = [mapinfowidth / 2, mapinfowidth * 2 / 5]; + sui_push_frame([mapheadingpos.x + mapinfowidth - levelshotsize.x - padding,mapheadingpos.y + titlesize + padding * 2], levelshotsize); + sui_pic([0,0], levelshotsize, levelshot, [1,1,1], 1, 0); + sui_border_box([0,0], levelshotsize, 1, MENU_TEXT_GREEN, 0.6, 0); + sui_pop_frame(); + //drawstring([200,200],strcat("We found ", levelshot),[8,8],MENU_TEXT_GREEN,1,0); //MEHT + } else { + //drawstring([200,200],strcat("We did not found ", levelshot),[8,8],MENU_TEXT_GREEN,1,0); //MEHT + } + + //Map description + vector descriptionpos = [mapheadingpos.x,panel.Position.y + fillsize.y - padding * 4 - titlesize - listitemsize.y * 3] + sui_push_frame(descriptionpos, [mapinfowidth - padding * 2, listitemsize.y * 3]); + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); + sui_text([padding / 2, padding / 2], [listitemsize.y,listitemsize.y], vote_selected_item.description, MENU_TEXT_1, 1, 0); + //sui_border_box([0,0], [fillsize.x - (mapheadingpos.x - panel.Position.x), listitemsize.y * 3], 1, MENU_BORDER, 0.6, 0); + sui_border_box([0,0], [mapinfowidth - padding, listitemsize.y * 3], 1, MENU_BORDER, 0.6, 0); + sui_pop_frame(); + } void(string panelid) Hud_DrawTeamScorePanel = { diff --git a/csqc/input.qc b/csqc/input.qc index ee2bf319..8a88acae 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -60,6 +60,52 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return (fo_hud_editor || menu_mouse); default: } + } else if(Hud_Panels[HUD_PANEL_MAP_MENU].Display) { + switch (evtype) { + case IE_MOUSEDELTA: + return TRUE; + case IE_MOUSEABS: + Mouse.x = scanx; + Mouse.y = chary; + return TRUE; + case IE_KEYDOWN: + switch (scanx) { + case K_ESCAPE: + return TRUE; + break; + case K_MOUSE1: + return TRUE; + break; + case K_UPARROW: + vote_selected_index--; + vote_list_offset--; + return TRUE; + break; + case K_DOWNARROW: + vote_selected_index++; + vote_list_offset++; + return TRUE; + break; + case K_MWHEELUP: + vote_list_offset--; + return TRUE; + break; + case K_MWHEELDOWN: + vote_list_offset++; + return TRUE; + break; + } + case IE_KEYUP: + switch (scanx) { + case K_ESCAPE: + showVoteMenu(FALSE); + return TRUE; + break; + case K_MOUSE1: + return TRUE; + break; + } + } } else { switch (evtype) { diff --git a/csqc/main.qc b/csqc/main.qc index f05d0318..76bca894 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -68,7 +68,16 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { is_admin = FALSE; grentimer_waiting = FALSE; jump_counter = 0; -// hud_idle_alpha = 0.3; + num_mapvotes = 0; + vote_selected_item = world; + vote_selected_index = -1; + vote_list_offset = 0; + AddVoteMap("1on1", "1 on 1, the old one","Duel",2,2,2); //MEHT + AddVoteMap("border1", "Cross the border","Civilian Hunt",3,4,20); //MEHT + AddVoteMap("2fort5r","2 Freaking Forts 5 R\nR stands for revised","CTF",2,6,16); //MEHT + for(float i = 0; i < 50; i++) { + AddVoteMap(strcat("2fort", ftos(i)),strcat("Test Map #",ftos(i)),"TEST",4*rint(random() * i),6*rint(random() * i),8*rint(random() * i)); //MEHT + } }; noref void() CSQC_WorldLoaded = { @@ -174,7 +183,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Admin_Main(TRUE); break; case "fo_menu_vote": - FO_Menu_Vote(TRUE); + //FO_Menu_Vote(TRUE); + showVoteMenu(!Hud_Panels[HUD_PANEL_MAP_MENU].Display); break; case "fo_menu_special": FO_Menu_Special(TRUE); diff --git a/csqc/menu.qc b/csqc/menu.qc index 10f41a69..8d7b87a9 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -630,7 +630,7 @@ var fo_menu FO_MENU_ADMIN_FRAGLIMIT = { }, 11, TRUE }; var fo_menu FO_MENU_VOTE = { - [0,0], [300,200], "Map Vote", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { + [0,0], [300,200], "Map Vote", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { {"1","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[0].name,"\n");Menu_Cancel();},MENU_BUTTON}, {"2","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[1].name,"\n");Menu_Cancel();},MENU_BUTTON}, {"3","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[2].name,"\n");Menu_Cancel();},MENU_BUTTON}, @@ -661,6 +661,8 @@ vector fo_menu_draw(fo_menu * menu) = { return position; } + Hud_Panels[HUD_PANEL_MAP_MENU].Display = FALSE; + setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); if(menu.update) { @@ -734,7 +736,7 @@ vector fo_menu_draw(fo_menu * menu) = { if(menu.options[i].state == FO_MENU_STATE_NORMAL) { //if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, padding * 3 + smalltext.x)) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), buttonpos, buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, alignment, shortcutoffset.x)) { + if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), buttonpos, buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, MENU_TEXT_1, alignment, shortcutoffset.x, 0.6, 1, 0)) { menu.options[i].action(); } } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { @@ -1259,3 +1261,14 @@ void FO_Menu_Special(float force) = { localcmd("cmd menu\n"); //fo_hud_menu_active = TRUE; }; + +void (float show) showVoteMenu = { + if(fo_hud_menu_active) { + Menu_Cancel(); + } + setcursormode(show); + Hud_Panels[HUD_PANEL_MAP_MENU].Display = show; + if(show) { + CurrentMenu = &FO_MENU_VOTE; + } +}; \ No newline at end of file diff --git a/csqc/status.qc b/csqc/status.qc index 4da0d64b..6606c361 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -794,7 +794,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, - {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','400 200',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index a0f674f0..68243c1a 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -935,20 +935,25 @@ void() sui_draw_bind_overlay = } }; -float(string id, vector pos, vector size, string text, vector colour, vector textsize, float alignment, float padding) hud_colour_button = +/* + * Flags: 1 = No Border + * + */ +float(string id, vector pos, vector size, string text, vector colour, vector textsize, vector textcolour, float alignment, float padding, float alpha, float textalpha, float flags) hud_colour_button = { sui_push_frame(pos, size); vector basecolor = sui_is_hovered(id) ? colour + MENU_HIGHLIGHT * 0.1 : colour; vector bordercolour = colour + '0.05 0.05 0.05'; basecolor = sui_is_held(id) ? colour - MENU_DARKEN * 0.1 : basecolor; - sui_fill([0, 0], size, basecolor, 0.6, 0); - sui_border_box([0, 0], size, 1, bordercolour, 0.4, 0); - + sui_fill([0, 0], size, basecolor, alpha, 0); + if(!(flags & 1)) { + sui_border_box([0, 0], size, 1, bordercolour, 0.4, 0); + } sui_set_align([alignment, SUI_ALIGN_CENTER]); if(!padding && alignment == SUI_ALIGN_START) { padding = 4; } - sui_text([padding, 0], textsize, text, MENU_TEXT_1, 1, 0); + sui_text([padding, 0], textsize, text, textcolour, textalpha, 0); sui_action_element([0, 0], size, id, sui_noop); sui_pop_frame(); @@ -956,7 +961,7 @@ float(string id, vector pos, vector size, string text, vector colour, vector tex }; float(string id, vector pos, vector size, string text) hud_button = { - return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL, SUI_ALIGN_CENTER, 0); + return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL, MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 0.6, 1, 0); } diff --git a/csqc/vote.qc b/csqc/vote.qc index 8dc08f4c..9e1c3ab3 100644 --- a/csqc/vote.qc +++ b/csqc/vote.qc @@ -3,7 +3,6 @@ "name" "amth1" //map name "description" "Duel arena, ctf and Sniper War" //description "groupname" "Duel/Arena" //group -"group" "min_val" "2" //min players "max_val" "8" //max players "team_num" "4" //supported teams @@ -50,6 +49,8 @@ entity (string n, string desc, string mapgroup, float num_teams, float min_playe mc.team_num = num_teams?num_teams:2; mc.min_val = min_players?min_players:6; mc.max_val = max_players?max_players:16; + + num_mapvotes++; return mc; }; @@ -61,6 +62,7 @@ float (string n) RemoveVoteMap = { while(mc) { if(mc.name == n) { remove(mc); + num_mapvotes--; return TRUE; } mc = find(mc, classname, "map_candidate"); From 2909e1f69c2df14248e0965fea37110b1d1d23a3 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 18 Oct 2020 00:27:48 -0300 Subject: [PATCH 1142/2474] correcting bug with round_delay_time setting (was always 30s no matter what) and adding option to configure max active nailgrens/shockgrens --- README.md | 2 ++ ssqc/client.qc | 4 +++- ssqc/engineer.qc | 3 +-- ssqc/quadmode.qc | 8 ++++---- ssqc/qw.qc | 2 ++ ssqc/tsoldier.qc | 6 ++++-- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e68901d2..242441c9 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,8 @@ New features * localinfo server_sbflaginfo : 0 - disables sbar flaginfo, 1 enables it [default: 1] * localinfo reverse_cap : 0 - normal gameplay, 1: you have to take your flag and capture in the enemy base [default: 0] * localinfo engineer_move / em : 0 - normal gameplay, 1: engineers can move while building [default: 0] +* localinfo round_delay_time : interval time between rounds in quadmode - seconds [default: 30] +* localinfo max_gren2_soldier : maximum number of active nail/shock grenades (TF 2.8 = 3, OzTF = 1) [default: 3] == Removed === * Removed weapon messages for weapons without weapon modes. diff --git a/ssqc/client.qc b/ssqc/client.qc index cb62a06f..48e67dd6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -665,7 +665,7 @@ void () DecodeLevelParms = { } //default round interval for quadmode (seconds) - localcmd ("localinfo round_delay_time 30\n"); + round_delay_time = CF_GetSetting("round_delay_time", "rdt", "30"); // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); @@ -715,6 +715,8 @@ void () DecodeLevelParms = { engineer_move = CF_GetSetting("em","engineer_move", "0"); + max_active_gren2_soldier = CF_GetSetting("mg2s","max_active_gren2_soldier", "3"); + st = infokey(world, "default"); if (st == "on") { impulse_queue = FALSE; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 484abf1c..ac8f3cf8 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -938,8 +938,7 @@ void () TeamFortress_FinishedBuilding = { oldself.netname = "sentry gun"; oldself.takedamage = DAMAGE_NO; oldself.th_die = Sentry_Die; - oldself.team_no = self.team_no; - oldself.think = CheckPyroLava; + oldself.team_no = self.team_no; oldself.nextthink = time + .1; if (!engineer_move) self.ammo_cells = self.ammo_cells - ENG_SENTRY_COST; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index fa49c17d..93a5954b 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -93,7 +93,7 @@ void () QuadRoundThink = { if (rounds > 1) { local string st; - st = infokey(world, "round_delay_time"); + st = ftos(round_delay_time); bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); } @@ -430,8 +430,8 @@ void () StartQuadRound = } local float rdt; - st = infokey(world, "round_delay_time"); - rdt = stof(st); + st = ftos(round_delay_time); + rdt = round_delay_time; te.cnt2 = rdt; st = infokey (world, "round_time"); te.cnt = stof (st); @@ -452,7 +452,7 @@ void () EndQuadRound = { if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { if (rounds > 1) { local string st; - st = infokey(world, "round_delay_time"); + st = ftos(round_delay_time); bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); lightstyle (0, "e"); self.think = QuadRoundOver; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9cc09803..866371f1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -448,6 +448,7 @@ float quad_winner; float rounds; float round_active; float round_over; +float round_delay_time; float gametime; float is_countdown; float duelmode; @@ -520,6 +521,7 @@ float max_gren2_pyro; float max_gren2_spy; float max_gren2_engineer; */ +float max_active_gren2_soldier; float grentimers; float id_extended; float remember_weapon; diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 6bbb56e7..55fca4d1 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -22,11 +22,13 @@ void () NailGrenadeExplode = { local entity te; self.owner.no_active_nail_grens = self.owner.no_active_nail_grens + 1; - if (self.owner.no_active_nail_grens > 2) { + if (self.owner.no_active_nail_grens > max_active_gren2_soldier) { te = find(world, classname, "grenade"); while (te) { - if ((te.owner == self.owner) && (te.no_active_nail_grens == 1)) { + if ((te.owner == self.owner || te.real_owner == self.owner) && (te.no_active_nail_grens == 1)) { + if (!te.owner) + te.owner = te.real_owner; te.weapon = 9; te.think = GrenadeExplode; te.nextthink = time + 0.1; From 2ecd46ef316326e122cf2289a9470d5d1f5b506e Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 18 Oct 2020 00:32:30 -0300 Subject: [PATCH 1143/2474] > to >= --- ssqc/tsoldier.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 55fca4d1..7a326bc8 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -22,7 +22,7 @@ void () NailGrenadeExplode = { local entity te; self.owner.no_active_nail_grens = self.owner.no_active_nail_grens + 1; - if (self.owner.no_active_nail_grens > max_active_gren2_soldier) { + if (self.owner.no_active_nail_grens >= max_active_gren2_soldier) { te = find(world, classname, "grenade"); while (te) { From 635298c031d12a61550381d45ac09b26e37a9002 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 18 Oct 2020 00:52:59 -0300 Subject: [PATCH 1144/2474] setting admin permissions as a star key to make sure it remains after map changes - akin to login --- ssqc/admin.qc | 1 + ssqc/client.qc | 2 ++ ssqc/login.qc | 1 + ssqc/spect.qc | 5 +++++ 4 files changed, 9 insertions(+) diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 25ec1fa0..5f2c4fb3 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -269,6 +269,7 @@ void (string cl_pwd) Admin_Check = stuffcmd(self, "\"\n"); if (st2 != string_null && cl_pwd == st2) { self.is_admin = TRUE; + forceinfokey(self,"*admin", ftos(self.is_admin)); bprint2(2, self.netname, "\s gains full admin status!\s\n"); sprint(self, 2, "Type \scmd list\s for admin commands.\n"); sprint(self, 2, "You can also use the \sadminmenu\s command for adjusting some settings.\n"); diff --git a/ssqc/client.qc b/ssqc/client.qc index fd047b4a..5ac6c40c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2694,6 +2694,8 @@ void (optional float csqcactive) ClientConnect = { if (infokey(self,"*login")) self.login = infokey(self,"*login"); + if (infokey(self,"*admin")) + self.is_admin = stof(infokey(self, "*admin")); if (self.login == string_null) sprint(self,2, "Login required, please use \"cmd login \" \nbefore joining the game\n"); diff --git a/ssqc/login.qc b/ssqc/login.qc index 1fe4a44d..887dfb1b 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -33,6 +33,7 @@ void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { if (num_args > 1) { if (argv(1) == "true") { self.is_admin = TRUE; + forceinfokey(self,"*admin", ftos(self.is_admin)); Admin_Aliases (); bprint2 (2, self.netname, " \sgains full admin status!\s\n"); // bprint (3, "\n"); diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 94b68aee..c5949b80 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -25,6 +25,11 @@ void () SpectatorConnect = { self.classname = "observer"; self.flags = 8; + if (infokey(self,"*login")) + self.login = infokey(self,"*login"); + if (infokey(self,"*admin")) + self.is_admin = stof(infokey(self, "*admin")); + st = infokey(self, "apw"); if (st == string_null) st = infokey(self, "adminpwd"); From 18445e764b9468b6f972fc635f560fbcaf565e3f Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Sun, 18 Oct 2020 01:16:00 -0300 Subject: [PATCH 1145/2474] adding max_active_gren2_soldier and round_delay_time values as part of huetf's preset --- ssqc/client.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 48e67dd6..e5dff7cb 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -901,6 +901,8 @@ void () DecodeLevelParms = { Role_None.gren2_limits[4] = 4; Role_None.gren2_limits[5] = 3; Role_None.gren2_limits[8] = 3; + max_active_gren2_soldier = 1; + round_delay_time = 10; } } From 34e74206a1efedcde8f7dfe69ab3c5c998c3ffe9 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Mon, 19 Oct 2020 22:39:21 -0300 Subject: [PATCH 1146/2474] applying damage balance only when oztf pyro is used --- ssqc/combat.qc | 2 +- ssqc/pyro.qc | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 02e30fea..3547136f 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -537,7 +537,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, moment = 0; } else moment = damage; - if (inflictor.classname == "pyro_rocket") { + if (inflictor.classname == "pyro_rocket" && pyro_type == 1) { moment = damage * 1.5; } diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 95ab13c3..c2ac3cad 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -630,7 +630,10 @@ void () IncendiaryRadius = { void () IncendiaryRadius_OZTF = { local float damg; - damg = 68; + if (pyro_type == 1) + damg = 68; + else + damg = 92; deathmsg = 15; T_RadiusDamage(self, self.owner, damg, other); self.origin = (self.origin - (8 * normalize (self.velocity))); @@ -660,7 +663,10 @@ void () T_IncendiaryTouch = { } else { - damg = 68 + random() * 20; + if (pyro_type == 1) + damg = 68 + random() * 20; + else + damg = 42 + random() * 20; } if (other.health) { From 97602280871e64c980847f24cd6b52dad1b0eb6d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 20 Oct 2020 22:32:15 +1100 Subject: [PATCH 1147/2474] Version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7dea76ed..6d7de6e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.1 +1.0.2 From cb0f4193bb5ecbdc52819085afc3d7cb12b5020f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 3 Nov 2020 23:28:45 +1300 Subject: [PATCH 1148/2474] voting etc --- csqc/csextradefs.qc | 4 +- csqc/events.qc | 25 +++++++++++- csqc/hud.qc | 98 ++++++++++++++++++++++++++++++++++++++++++--- csqc/input.qc | 10 +++++ csqc/main.qc | 11 ++--- csqc/vote.qc | 18 ++++++--- share/commondefs.qc | 5 +++ ssqc/client.qc | 1 + ssqc/csmenu.qc | 92 ++++++++++++++++++++++++++++++++++++++++++ ssqc/spect.qc | 1 + ssqc/vote.qc | 8 ++++ 11 files changed, 251 insertions(+), 22 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 58f628b9..1d04a7fc 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -86,6 +86,7 @@ float num_mapvotes; entity vote_selected_item; float vote_selected_index; float vote_list_offset; +entity current_vote; .string name; .string description; @@ -94,7 +95,8 @@ float vote_list_offset; .float team_num; .float min_val; .float max_val; -.float cnt; +.float votecount; +.float localmap; float(string) GetDrawPanel; void(string, string, string) Hud_DrawPanelLMP; diff --git a/csqc/events.qc b/csqc/events.qc index fabb6434..54c4781d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -3,7 +3,8 @@ void AddGrenTimer(float grentype); void() CSQC_Parse_Event = { float msgtype = readbyte(); - local float goalno; + local float goalno; + entity te; switch (msgtype) { case MSG_FLAGINFOINIT: float index = readfloat(); @@ -27,7 +28,7 @@ void() CSQC_Parse_Event = { FlagInfoLines[index].message = ""; if(mdl) precache_model(mdl); - entity te = spawn(); + te = spawn(); te.renderflags = RF_VIEWMODEL | RF_DEPTHHACK | RF_NOSHADOW; te.origin = [5, 0, 0]; te.angles = '-60 0 0'; @@ -192,6 +193,9 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_CAPTAIN_PICK: FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0); break; + case CLIENT_MENU_MAPS: + showVoteMenu(!Hud_Panels[HUD_PANEL_MAP_MENU].Display); + break; } break; case MSG_CLASSES_UPDATE: @@ -269,6 +273,23 @@ void() CSQC_Parse_Event = { TS.team3score = readfloat(); TS.team4score = readfloat(); break; + case MSG_VOTE_UPDATE: + te = AddVoteMap(readstring(), "","",0,0,0,FALSE); + te.votecount = readfloat(); + if(readbyte()) { + current_vote = te; + } + break; + case MSG_VOTE_MAP_ADD: + te = AddVoteMap(readstring(), readstring(), readstring(), readfloat(), readfloat(), readfloat(), FALSE); + te.votecount = readfloat(); + if(readbyte()) { + current_vote = te; + } + break; + case MSG_VOTE_MAP_DELETE: + RemoveVoteMap(readstring(), FALSE); + break; } } diff --git a/csqc/hud.qc b/csqc/hud.qc index 2fc75e85..1f3324c2 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -299,13 +299,13 @@ void(string panelid) Hud_DrawMapMenuPanel = { */ //sui_scroll_view_begin("scrolltest", panel.Position + [200,4], [100,100], [100,200], listoffset, [2,6]); //sui_scroll_view_end(); + sui_border_box(panel.Position + [padding, padding * 2 + titlesize], listviewsize, 1, MENU_TEXT_SPEC_FO, 0.6, 0); if(vote_list_offset > num_mapvotes - visiblelistitems) { vote_list_offset = num_mapvotes - visiblelistitems; } if(vote_list_offset < 0) { vote_list_offset = 0; } - sui_border_box(panel.Position + [padding, padding * 2 + titlesize], listviewsize, 1, MENU_BORDER, 0.6, 0); entity mc = find(world, classname, "map_candidate"); while(mc) { if(cnt >= vote_list_offset) { @@ -342,11 +342,23 @@ void(string panelid) Hud_DrawMapMenuPanel = { //sui_border_box(listitempos, listitemsize, 1, bgcolour, 0.4, 0); //sui_fill(listitempos, listitemsize, bgcolour, alpha, 0); //sui_text(listitempos, [listitemsize.y, listitemsize.y], mc.name, textcolour, alpha, 0); - if(hud_colour_button(strcat("listitem",ftos(cnt)),listitempos, listitemsize, mc.name, bgcolour, [listitemsize.y, listitemsize.y], textcolour, SUI_ALIGN_START, 2, alpha, alpha, 1)) { + sui_push_frame(listitempos, listitemsize); + if(mc == current_vote) { + textcolour = MENU_TEXT_GREEN; + } else if(mc.votecount > 0) { + textcolour = MENU_TEXT_WARNING; + } else { + textcolour = MENU_TEXT_1; + } + if(hud_colour_button(strcat("listitem",ftos(cnt)),[0,0], listitemsize, mc.name, bgcolour, [listitemsize.y, listitemsize.y], textcolour, SUI_ALIGN_START, 2, alpha, alpha, 1)) { vote_selected_item = mc; vote_selected_index = cnt; - print("Selected is now ", mc.name, "\n"); //MEHT } + if(mc.votecount > 0) { + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([padding * -1, 0], [listitemsize.y, listitemsize.y], ftos(mc.votecount), MENU_TEXT_4, alpha, 0); + } + sui_pop_frame(); } cnt++; mc = find(mc, classname, "map_candidate"); @@ -363,8 +375,12 @@ void(string panelid) Hud_DrawMapMenuPanel = { float mapinfowidth = fillsize.x - (mapheadingpos.x - panel.Position.x); sui_push_frame(mapheadingpos, [mapinfowidth, titlesize]); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_text([padding, 0], [titlesize,titlesize], vote_selected_item.name, MENU_TEXT_2, 1, 0); + sui_text([padding, 0], [titlesize,titlesize], (vote_selected_item?vote_selected_item.name:"No map selected"), MENU_TEXT_3, 1, 0); sui_pop_frame(); + + if(!vote_selected_item) { + return; + } //Map image float filehandle; @@ -378,11 +394,66 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_pic([0,0], levelshotsize, levelshot, [1,1,1], 1, 0); sui_border_box([0,0], levelshotsize, 1, MENU_TEXT_GREEN, 0.6, 0); sui_pop_frame(); - //drawstring([200,200],strcat("We found ", levelshot),[8,8],MENU_TEXT_GREEN,1,0); //MEHT } else { - //drawstring([200,200],strcat("We did not found ", levelshot),[8,8],MENU_TEXT_GREEN,1,0); //MEHT + //placeholder maybe? } + //Map details + float mapdetailgridindex = 0; + sui_push_frame(mapheadingpos + [0,titlesize + padding * 2], [mapinfowidth / 2, titlesize]); + if(vote_selected_item.group) { + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Type:", MENU_TEXT_2, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], vote_selected_item.groupname, MENU_TEXT_2, 1, 0); + mapdetailgridindex++; + } + if(vote_selected_item.team_num) { + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Teams:", MENU_TEXT_2, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], ftos(vote_selected_item.team_num), MENU_TEXT_2, 1, 0); + mapdetailgridindex++; + } + if(vote_selected_item.min_val || vote_selected_item.max_val) { + string playernumstring = ""; + if(vote_selected_item.min_val && vote_selected_item.max_val) { + if(vote_selected_item.min_val == vote_selected_item.max_val) { + playernumstring = strcat(ftos(vote_selected_item.min_val)); + } else { + playernumstring = strcat(ftos(vote_selected_item.min_val),"-",ftos(vote_selected_item.max_val)); + } + } else if(vote_selected_item.min_val) { + playernumstring = strcat(ftos(vote_selected_item.min_val),"+"); + } else { + playernumstring = strcat(ftos(vote_selected_item.max_val),"-"); + } + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Players:", MENU_TEXT_2, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], playernumstring, MENU_TEXT_2, 1, 0); + mapdetailgridindex++; + } + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Client-side:", MENU_TEXT_2, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], vote_selected_item.localmap?"\x10\x8f\x11":"\x10 \x11", MENU_TEXT_2, 1, 0); + mapdetailgridindex++; + if(vote_selected_item.votecount) { + if(mc == current_vote) { + textcolour = MENU_TEXT_WARNING; + } else { + textcolour = MENU_TEXT_GREEN; + } + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Votes:", textcolour, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], strcat(ftos(vote_selected_item.votecount),(mc == current_vote?" (your vote)":"")), textcolour, 1, 0); + mapdetailgridindex++; + } + sui_pop_frame(); + + //Map description vector descriptionpos = [mapheadingpos.x,panel.Position.y + fillsize.y - padding * 4 - titlesize - listitemsize.y * 3] sui_push_frame(descriptionpos, [mapinfowidth - padding * 2, listitemsize.y * 3]); @@ -392,6 +463,21 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_border_box([0,0], [mapinfowidth - padding, listitemsize.y * 3], 1, MENU_BORDER, 0.6, 0); sui_pop_frame(); + sui_push_frame(descriptionpos + [0, listitemsize.y * 3 + padding], [mapinfowidth - padding * 2, listitemsize.y * 3]); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]); + if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Vote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { + localcmd("cmd votemap ", vote_selected_item.name, "\n"); + } + if(hud_colour_button("change_button", [0 - listitemsize.x - padding,0], listitemsize + [0,padding], "Change Now", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_WARNING, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { + if(is_admin) { + localcmd("cmd map ", vote_selected_item.name, "\n"); + } else { + localcmd("rcon map ", vote_selected_item.name, "\n"); + } + } + + sui_pop_frame(); + } void(string panelid) Hud_DrawTeamScorePanel = { diff --git a/csqc/input.qc b/csqc/input.qc index 8a88acae..2631f6f2 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -86,6 +86,16 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { vote_list_offset++; return TRUE; break; + case K_PGUP: + vote_selected_index -= 10; + vote_list_offset -= 10; + return TRUE; + break; + case K_PGDN: + vote_selected_index +=10; + vote_list_offset +=10; + return TRUE; + break; case K_MWHEELUP: vote_list_offset--; return TRUE; diff --git a/csqc/main.qc b/csqc/main.qc index 76bca894..4db1175d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -72,12 +72,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_selected_item = world; vote_selected_index = -1; vote_list_offset = 0; - AddVoteMap("1on1", "1 on 1, the old one","Duel",2,2,2); //MEHT - AddVoteMap("border1", "Cross the border","Civilian Hunt",3,4,20); //MEHT - AddVoteMap("2fort5r","2 Freaking Forts 5 R\nR stands for revised","CTF",2,6,16); //MEHT - for(float i = 0; i < 50; i++) { - AddVoteMap(strcat("2fort", ftos(i)),strcat("Test Map #",ftos(i)),"TEST",4*rint(random() * i),6*rint(random() * i),8*rint(random() * i)); //MEHT - } + current_vote = world; }; noref void() CSQC_WorldLoaded = { @@ -317,10 +312,10 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "vote_addmap": - AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6))); + AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); break; case "vote_removemap": - RemoveVoteMap(argv(1)); + RemoveVoteMap(argv(1), TRUE); break; } return FALSE; diff --git a/csqc/vote.qc b/csqc/vote.qc index 9e1c3ab3..02c85891 100644 --- a/csqc/vote.qc +++ b/csqc/vote.qc @@ -28,7 +28,7 @@ entity (string n) AddVoteMapGroup = { return mg; }; -entity (string n, string desc, string mapgroup, float num_teams, float min_players, float max_players) AddVoteMap = { +entity (string n, string desc, string mapgroup, float num_teams, float min_players, float max_players, float islocal) AddVoteMap = { if(!n) { return world; } @@ -49,21 +49,29 @@ entity (string n, string desc, string mapgroup, float num_teams, float min_playe mc.team_num = num_teams?num_teams:2; mc.min_val = min_players?min_players:6; mc.max_val = max_players?max_players:16; + mc.localmap = islocal; num_mapvotes++; return mc; }; -float (string n) RemoveVoteMap = { +float (string n, float isLocal) RemoveVoteMap = { if(!n) { return FALSE; } local entity mc = find(world, classname, "map_candidate"); while(mc) { if(mc.name == n) { - remove(mc); - num_mapvotes--; - return TRUE; + if(isLocal || isLocal == mc.localmap) { + if(current_vote == mc) { + current_vote = world; + } + remove(mc); + num_mapvotes--; + return TRUE; + } else { + return FALSE; + } } mc = find(mc, classname, "map_candidate"); } diff --git a/share/commondefs.qc b/share/commondefs.qc index dce9116d..347d42b2 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -27,6 +27,10 @@ #define MSG_GRENTHROWN 15 #define MSG_ID 16 #define MSG_TEAM_SCORES 17 +#define MSG_VOTE_MAPS 18 +#define MSG_VOTE_UPDATE 19 +#define MSG_VOTE_MAP_ADD 20 +#define MSG_VOTE_MAP_DELETE 21 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 @@ -65,3 +69,4 @@ #define CLIENT_MENU_CAPTAIN_1 21 #define CLIENT_MENU_CAPTAIN_2 22 #define CLIENT_MENU_CAPTAIN_PICK 23 +#define CLIENT_MENU_MAPS 24 diff --git a/ssqc/client.qc b/ssqc/client.qc index c2d87da8..19cafc0c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2768,6 +2768,7 @@ void (optional float csqcactive) ClientConnect = { UpdateClientTeamScores(self); //if(quadmode) UpdateClientPrematch(self, !cb_prematch); + UpdateClient_VoteMap_AddAll(self); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index a3783f8f..9527c77d 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -285,3 +285,95 @@ void UpdateClientPrematch(entity pl, float countdownstarted) = { //WriteByte(MSG_MULTICAST, countdownstarted); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } + +void UpdateClientMapVote(entity pl, entity candidate) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE) || !candidate) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_VOTE_UPDATE); + WriteString(MSG_MULTICAST, candidate.netname); + WriteFloat(MSG_MULTICAST, candidate.cnt); + WriteByte(MSG_MULTICAST, (pl.vote_map == candidate)); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateAllClientMapVotes(entity candidate) { + if(!candidate) { + return; + } + entity pl = find(world, classname, "player"); + while(pl) { + if(!pl.has_disconnected) { + UpdateClientMapVote(pl, candidate); + } + pl = find(pl, classname, "player"); + } +} + +void UpdateClientMenu_Maps(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); + WriteFloat(MSG_MULTICAST, CLIENT_MENU_MAPS); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClient_VoteMap_Add(entity pl, entity map_candidate) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_VOTE_MAP_ADD); + WriteString(MSG_MULTICAST, map_candidate.netname); + WriteString(MSG_MULTICAST, map_candidate.broadcast); + WriteString(MSG_MULTICAST, map_candidate.team_broadcast); + WriteFloat(MSG_MULTICAST, map_candidate.team_no); + WriteFloat(MSG_MULTICAST, map_candidate.ex_skill_min); + WriteFloat(MSG_MULTICAST, map_candidate.ex_skill_max); + WriteFloat(MSG_MULTICAST, map_candidate.cnt); + WriteByte(MSG_MULTICAST, (pl.vote_map == map_candidate)); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClient_VoteMap_AddAll(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + local entity mc = find(world, classname, "map_candidate"); + while(mc) { + UpdateClient_VoteMap_Add(pl, mc); + mc = find(mc, classname, "map_candidate"); + } +} + +void UpdateClient_VoteMap_Add_Broadcast(entity map_candidate) = { + local entity pl = find(world, classname, "map_candidate"); + while(pl) { + if(infokeyf(pl, INFOKEY_P_CSQCACTIVE) && !pl.has_disconnected) { + UpdateClient_VoteMap_Add(pl, map_candidate); + } + pl = find(pl, classname, "player"); + } +} + +void UpdateClient_VoteMap_Delete(entity pl, string map) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_VOTE_MAP_DELETE); + WriteString(MSG_MULTICAST, map); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClient_VoteMap_Delete_Broadcast(entity map_candidate) = { + local entity pl = find(world, classname, "map_candidate"); + while(pl) { + if(infokeyf(pl, INFOKEY_P_CSQCACTIVE) && !pl.has_disconnected) { + UpdateClient_VoteMap_Delete(pl, map_candidate.netname); + } + pl = find(pl, classname, "player"); + } +} diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 94b68aee..d9febda5 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -52,6 +52,7 @@ void () SpectatorConnect = { InitAllStatuses(self); UpdateClientMOTD(self); UpdateClientPrematch(self, !cb_prematch); + UpdateClient_VoteMap_AddAll(self); } TeamFortress_StartTimers(); diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 8c5a7668..c781fb9f 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1142,6 +1142,7 @@ entity (string name, string desc, string mapgroup, float num_teams, float min_pl mc.team_no = num_teams?num_teams:2; mc.ex_skill_min = min_players?min_players:6; mc.ex_skill_max = max_players?max_players:16; + UpdateClient_VoteMap_Add_Broadcast(mc); return mc; }; @@ -1152,6 +1153,7 @@ float (string name) RemoveVoteMap = { local entity mc = find(world, classname, "map_candidate"); while(mc) { if(mc.netname == name) { + UpdateClient_VoteMap_Delete_Broadcast(mc); dremove(mc); return TRUE; } @@ -1447,6 +1449,7 @@ void (entity p, string vote) VoteForMap = { } p.vote_map = mc; mc.cnt++; + UpdateAllClientMapVotes(mc); CheckVoting(); return; } @@ -1598,6 +1601,11 @@ void (float update) Vote_Menu_Map = { return; } + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)){ + UpdateClientMenu_Maps(self); + return; + } + // prepare menu strings local string s_title = strcat("\sEquations\s\nPage ",ftos(self.current_menu_page),"\n\n"); local string s_8 = Q"\s[8]\s Previous \n"; From b350f6b407f15c7f18d57ffa4b91f63f31b7e4a9 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 4 Nov 2020 08:43:43 +1300 Subject: [PATCH 1149/2474] some fixes --- README.md | 2 ++ csqc/hud.qc | 26 +++++++++++++++++++------- csqc/menu.qc | 7 +++++-- ssqc/vote.qc | 3 +++ 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a4bb5cdf..9094cea6 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ FortressOne Server New features ------ +* new csqc command ``fo_menu_vote`` shows the list of maps available to vote. +* ``vote_addmap``\``vote_removemap`` now work client-side * new cvar for zut ``fo_hud_idle_alpha`` - sets the minimum transparency for flaginfo inactive items * optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * localinfo nohitsounds 1 - disables hitsounds server-wide diff --git a/csqc/hud.qc b/csqc/hud.qc index 1f3324c2..277dd510 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -343,7 +343,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { //sui_fill(listitempos, listitemsize, bgcolour, alpha, 0); //sui_text(listitempos, [listitemsize.y, listitemsize.y], mc.name, textcolour, alpha, 0); sui_push_frame(listitempos, listitemsize); - if(mc == current_vote) { + if(current_vote && mc == current_vote) { textcolour = MENU_TEXT_GREEN; } else if(mc.votecount > 0) { textcolour = MENU_TEXT_WARNING; @@ -381,6 +381,11 @@ void(string panelid) Hud_DrawMapMenuPanel = { if(!vote_selected_item) { return; } + + float current_vote_selected = FALSE; + if(current_vote && current_vote == vote_selected_item) { + current_vote_selected = TRUE; + } //Map image float filehandle; @@ -440,15 +445,15 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], vote_selected_item.localmap?"\x10\x8f\x11":"\x10 \x11", MENU_TEXT_2, 1, 0); mapdetailgridindex++; if(vote_selected_item.votecount) { - if(mc == current_vote) { - textcolour = MENU_TEXT_WARNING; - } else { + if(current_vote_selected) { textcolour = MENU_TEXT_GREEN; + } else { + textcolour = MENU_TEXT_WARNING; } sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Votes:", textcolour, 1, 0); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); - sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], strcat(ftos(vote_selected_item.votecount),(mc == current_vote?" (your vote)":"")), textcolour, 1, 0); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], strcat(ftos(vote_selected_item.votecount),(current_vote_selected?" (your vote)":"")), textcolour, 1, 0); mapdetailgridindex++; } sui_pop_frame(); @@ -465,8 +470,15 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_push_frame(descriptionpos + [0, listitemsize.y * 3 + padding], [mapinfowidth - padding * 2, listitemsize.y * 3]); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]); - if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Vote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { - localcmd("cmd votemap ", vote_selected_item.name, "\n"); + if(current_vote_selected) { + if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Unvote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { + localcmd("cmd break\n"); + current_vote = world; + } + } else { + if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Vote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { + localcmd("cmd votemap ", vote_selected_item.name, "\n"); + } } if(hud_colour_button("change_button", [0 - listitemsize.x - padding,0], listitemsize + [0,padding], "Change Now", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_WARNING, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { if(is_admin) { diff --git a/csqc/menu.qc b/csqc/menu.qc index 8d7b87a9..cf3b0608 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -10,6 +10,7 @@ void (float force) FO_Menu_Spy; void (float force) FO_Menu_Spy_Skin; void (float force) FO_Menu_Spy_Team; void (float force) FO_Menu_Class; +void (float force) showVoteMenu; void FO_Menu_Admin_Players(float force, float type, float page); typedef struct { @@ -74,18 +75,20 @@ var fo_menu FO_MENU_GAME = { {"4","Spectate", "","Do not participate in the game, but observe as a ghost",FO_MENU_STATE_NORMAL,{localcmd("observe\n"); Menu_Cancel();},MENU_BUTTON}, {"5","Server Admin", "","Admin options for the server",FO_MENU_STATE_DISABLED,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, {"6","Captain's Menu", "","",FO_MENU_STATE_DISABLED,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0);},MENU_BUTTON}, + {"7","Map Menu", "","",FO_MENU_STATE_NORMAL,{showVoteMenu(TRUE);},MENU_BUTTON}, MenuSpacer, {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, - }, 9, TRUE + }, 10, TRUE }; var fo_menu FO_MENU_GAME_SPECTATOR = { [0,0], [300,200], "Fortress One", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Join Game", "","",FO_MENU_STATE_NORMAL,{localcmd("join\n"); Menu_Cancel(); },MENU_BUTTON}, MenuSpacer, {"3","Server Admin", "","",FO_MENU_STATE_DISABLED,{FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, + {"4","Map Menu", "","",FO_MENU_STATE_NORMAL,{showVoteMenu(TRUE);},MENU_BUTTON}, MenuSpacer, {"0","Main Menu","","",FO_MENU_STATE_NORMAL,{localcmd("fo_main_menu\n"); Menu_Cancel();},MENU_BUTTON}, - }, 5, TRUE + }, 6, TRUE }; var fo_menu FO_MENU_SPECTATOR_TRACK = { [0,0], [300,200], "Track", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { diff --git a/ssqc/vote.qc b/ssqc/vote.qc index c781fb9f..069dbc21 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1268,6 +1268,7 @@ void () EndVoting = { e = find(world, classname, "map_candidate"); while(e) { e.cnt = 0; + UpdateAllClientMapVotes(e); e = find(e, classname, "map_candidate"); } }; @@ -1441,6 +1442,7 @@ void (entity p, string vote) VoteForMap = { if(p.vote_map) { bprint(PRINT_HIGH, p.netname, " changes vote to \b", vote, "\b\n"); p.vote_map.cnt--; + UpdateAllClientMapVotes(p.vote_map); } else { FO_Sound(self, CHAN_AUTO, "items/protect.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, p.netname, " has voted for \b", vote, "\b\n"); @@ -1464,6 +1466,7 @@ void (entity p) UnvoteForMap = { } else { bprint(PRINT_HIGH, p.netname, " \babandons vote for\b ", p.vote_map.netname, "\n"); } + UpdateAllClientMapVotes(p.vote_map); p.vote_map.cnt--; p.vote_map = world; vote_total_votes--; From c4f7d1f5c2c775e78b960b6ad1d4eb9260446c44 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 4 Nov 2020 21:37:22 +1300 Subject: [PATCH 1150/2474] typo --- ssqc/csmenu.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 9527c77d..37288ac8 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -349,7 +349,7 @@ void UpdateClient_VoteMap_AddAll(entity pl) = { } void UpdateClient_VoteMap_Add_Broadcast(entity map_candidate) = { - local entity pl = find(world, classname, "map_candidate"); + local entity pl = find(world, classname, "player"); while(pl) { if(infokeyf(pl, INFOKEY_P_CSQCACTIVE) && !pl.has_disconnected) { UpdateClient_VoteMap_Add(pl, map_candidate); @@ -369,7 +369,7 @@ void UpdateClient_VoteMap_Delete(entity pl, string map) = { } void UpdateClient_VoteMap_Delete_Broadcast(entity map_candidate) = { - local entity pl = find(world, classname, "map_candidate"); + local entity pl = find(world, classname, "player"); while(pl) { if(infokeyf(pl, INFOKEY_P_CSQCACTIVE) && !pl.has_disconnected) { UpdateClient_VoteMap_Delete(pl, map_candidate.netname); From 7155596701e37fd5f39df60eba2616278ac5f194 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 12 Nov 2020 22:05:28 +1300 Subject: [PATCH 1151/2474] fix vote menu --- csqc/hud.qc | 10 ++++++---- ssqc/client.qc | 6 ++++++ ssqc/csmenu.qc | 14 +++++--------- ssqc/qw.qc | 2 ++ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 277dd510..d094b03f 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -270,7 +270,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { listitemsize.y = listitemsize.y * textscale; titlesize = titlesize * textscale; padding = padding * panel.Scale; - listitemsize.x = listitemsize.y * 14; //14 chars of mapname + listitemsize.x = listitemsize.y * 20; //20 chars of mapname local vector listviewsize = [listitemsize.x, fillsize.y - padding * 3 - listitemsize.y]; local float visiblelistitems = floor(listviewsize.y / listitemsize.y); @@ -393,8 +393,10 @@ void(string panelid) Hud_DrawMapMenuPanel = { filehandle = fopen(levelshot, FILE_READ); if (filehandle >= 0) { fclose(filehandle); - //Make it half the width of the map info area and aspect of 1.25:1 - vector levelshotsize = [mapinfowidth / 2, mapinfowidth * 2 / 5]; + ////Make it half the width of the map info area and aspect of 1.25:1 + //vector levelshotsize = [mapinfowidth / 2, mapinfowidth * 2 / 5]; + //No, make it 16:9 and 2/3 of the width + vector levelshotsize = [mapinfowidth * 2 / 3, mapinfowidth * 2 * 9 / (3 * 16)]; sui_push_frame([mapheadingpos.x + mapinfowidth - levelshotsize.x - padding,mapheadingpos.y + titlesize + padding * 2], levelshotsize); sui_pic([0,0], levelshotsize, levelshot, [1,1,1], 1, 0); sui_border_box([0,0], levelshotsize, 1, MENU_TEXT_GREEN, 0.6, 0); @@ -405,7 +407,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { //Map details float mapdetailgridindex = 0; - sui_push_frame(mapheadingpos + [0,titlesize + padding * 2], [mapinfowidth / 2, titlesize]); + sui_push_frame(mapheadingpos + [0,titlesize + padding * 2], [mapinfowidth - levelshotsize.x, titlesize]); if(vote_selected_item.group) { sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Type:", MENU_TEXT_2, 1, 0); diff --git a/ssqc/client.qc b/ssqc/client.qc index 19cafc0c..be83099b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2356,6 +2356,12 @@ void () PlayerPreThink = { if (self.cheat_level > 0) { self.cheat_level = self.cheat_level - 1; } + + if (self.vote_map_send) { + UpdateClient_VoteMap_Add(self, self.vote_map_send); + self.vote_map_send = find(self.vote_map_send, classname, "map_candidate"); + } + if (intermission_running) { IntermissionThink(); return; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 37288ac8..81b83bed 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -327,25 +327,21 @@ void UpdateClient_VoteMap_Add(entity pl, entity map_candidate) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_VOTE_MAP_ADD); - WriteString(MSG_MULTICAST, map_candidate.netname); + WriteString(MSG_MULTICAST, substring(map_candidate.netname,0,20)); WriteString(MSG_MULTICAST, map_candidate.broadcast); - WriteString(MSG_MULTICAST, map_candidate.team_broadcast); + WriteString(MSG_MULTICAST, substring(map_candidate.team_broadcast,0,10)); WriteFloat(MSG_MULTICAST, map_candidate.team_no); WriteFloat(MSG_MULTICAST, map_candidate.ex_skill_min); WriteFloat(MSG_MULTICAST, map_candidate.ex_skill_max); WriteFloat(MSG_MULTICAST, map_candidate.cnt); WriteByte(MSG_MULTICAST, (pl.vote_map == map_candidate)); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); } - void UpdateClient_VoteMap_AddAll(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; - local entity mc = find(world, classname, "map_candidate"); - while(mc) { - UpdateClient_VoteMap_Add(pl, mc); - mc = find(mc, classname, "map_candidate"); - } + pl.vote_map_send = find(world, classname, "map_candidate"); + //Now just let PlayerPreThink handle the rest } void UpdateClient_VoteMap_Add_Broadcast(entity map_candidate) = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 50ba81a4..8ab467b4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -632,6 +632,8 @@ float intermission_exittime; .entity chain2; // allows for nesting of findradius (use in EMPGrenadeExplode) +.entity vote_map_send; + // global variables for voting float vote1_cnt, vote2_cnt, vote3_cnt, vote4_cnt, vote5_cnt; string vote1_map, vote2_map, vote3_map, vote4_map, vote5_map, vote_result; From d33e85331ef2c5e0e9c1425d70ec7346cfdc11b9 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Fri, 13 Nov 2020 01:36:33 -0300 Subject: [PATCH 1152/2474] fixing player entities remanining stuck in server after they leave, inserting a timeout for forced map changes after rounds are over in quad mode --- ssqc/admin.qc | 2 +- ssqc/client.qc | 2 ++ ssqc/events.qc | 19 ++++++++++++++++++- ssqc/functions.qc | 16 +++++++++++++++- ssqc/quadmode.qc | 2 ++ ssqc/qw.qc | 1 + 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 5f2c4fb3..2f106f82 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -190,7 +190,7 @@ void () Admin_Pause = { setpause(1); is_paused = 1; pause_actor = self.netname; - if (cb_prematch && infokey(world, "status") == "Countdown") { + if (cb_prematch && is_countdown) { StopTimer(); bprint2(2, pause_actor, " stops the countdown\n"); return; diff --git a/ssqc/client.qc b/ssqc/client.qc index f5f81104..a104d55f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -667,6 +667,8 @@ void () DecodeLevelParms = { //default round interval for quadmode (seconds) round_delay_time = CF_GetSetting("round_delay_time", "rdt", "30"); + map_restart_time = CF_GetSetting("map_restart_Time", "mrt", "120"); + // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); diff --git a/ssqc/events.qc b/ssqc/events.qc index 0e0c6434..0c0f619c 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -1,6 +1,17 @@ string (string text) clearString; string (float tno) GetTeamName; +float (entity player) isPlayerValid = { + if (player.has_disconnected == 1 + || !infokey(player, INFOKEY_P_USERID) + || infokey(player, INFOKEY_P_USERID) == "" + || !infokey(player, INFOKEY_P_NAME) + || infokey(player, INFOKEY_P_NAME) == "") { + return 0; + } + return 1; +} + string () ISOTimemillis = { local string padding = string_null; local string timeuse = strftime(0,"%Y-%m-%dT%H:%M:%S."); @@ -33,6 +44,8 @@ void (string evt) logevent = { void (entity player) LogEventPlayerStart = { if (canlog == 0) return; + if (isPlayerValid(player) == FALSE) + return; local string event; event = sprintf(",\n{\"type\": \"playerStart\", \"player\": \"%s\", \"classtime\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(player), ftos(player.classtime), ftos(gametime), gametimestamp); @@ -50,7 +63,8 @@ void () LogEventGameStart = { while (player) { - numplayers++; + if (isPlayerValid(player) == TRUE) + numplayers++; player = find (player, classname, "player"); } @@ -61,9 +75,12 @@ void () LogEventGameStart = { void (entity player, float previous, float next, float timeplayed) LogEventChangeClass = { if (canlog == 0) return; + if (isPlayerValid(player) == FALSE) + return; if (previous == 0) { return; } + local string event; event = sprintf(",\n{\"type\": \"changeClass\", \"player\": \"%s\", \"playerClass\": %s, \"nextClass\": %s, \"team\": %s, \"timePlayed\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(player), diff --git a/ssqc/functions.qc b/ssqc/functions.qc index f753467f..9c1822da 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -131,8 +131,16 @@ void () PrintLoginMessage = { return; } +void () EndGameThink = { + localcmd("changelevel "); + localcmd(mapname); + localcmd("\n"); + dremove(self); +} + void () MapEndSequence = { - local entity player; + local entity player; + local entity maprestarttimer; player = find (world, classname, "player"); while (player) { @@ -148,4 +156,10 @@ void () MapEndSequence = { if (logfilehandle > 0) fclose(logfilehandle); canlog = 0; + + maprestarttimer = spawn(); + maprestarttimer.classname = "timer"; + maprestarttimer.netname = "maprestarttimer"; + maprestarttimer.think = EndGameThink; + maprestarttimer.nextthink = time + map_restart_time; } \ No newline at end of file diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 93a5954b..b41f3c6d 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -331,6 +331,8 @@ void () StartQuadRound = te = find(te, classname, "observer"); } bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); + bprint2(2, "map will auto-restart in ", ftos(map_restart_time)); + bprint2(2, " seconds\n"); if (!clan_scores_dumped) { DumpClanScores(); MapEndSequence(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 866371f1..6bc3ebe8 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -449,6 +449,7 @@ float rounds; float round_active; float round_over; float round_delay_time; +float map_restart_time; float gametime; float is_countdown; float duelmode; From 0b67a17cff87f179085b1352e35ec385103ddd38 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Fri, 13 Nov 2020 01:41:22 -0300 Subject: [PATCH 1153/2474] preventing double-demo recording --- ssqc/clan.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 4f4946d7..c2570e17 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -317,7 +317,8 @@ void () PreMatch_Think = { if (self.cnt2 == 10) { is_countdown = 1; lightstyle(0, "e"); - + //preventing double demo recording + localcmd("cancel\n"); if (stof(infokey(world, "demo_auto_left")) > 0) { if (infokey(world, "serverdemo") == "on") { calltimeofday(); From ac98428a19e91b603729cccb5cd013530d96c4d6 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 14 Nov 2020 21:14:25 +1300 Subject: [PATCH 1154/2474] big teamscores --- csqc/csextradefs.qc | 11 +++++++++++ csqc/events.qc | 12 ++++++++---- csqc/hud.qc | 30 ++++++++++++++++++++++++------ csqc/menu.qc | 8 ++++---- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 407cca79..43c2721b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -29,6 +29,13 @@ vector MENU_TEXT_YELLOW_FO = '0.7 0.7 0.3'; vector MENU_TEXT_GREEN_FO = '0.4 0.7 0.3'; vector MENU_TEXT_SPEC_FO = '0.1 0.1 0.1'; +vector TEXT_TEAM_COLOUR[] = { + MENU_TEXT_BLUE_FO, + MENU_TEXT_RED_FO, + MENU_TEXT_YELLOW_FO, + MENU_TEXT_GREEN_FO +}; + #define FO_MENU_FLAG_USE_MOUSE 1 #define FO_MENU_FLAG_CENTER 2 #define FO_MENU_FLAG_SHOW_SHORTCUTS 4 @@ -278,6 +285,7 @@ typedef struct { FlagInfoLine FlagInfoLines[10]; +/* typedef struct { float team1score; float team2score; @@ -286,6 +294,9 @@ typedef struct { } FO_TeamScores; FO_TeamScores TS; +*/ + +float TeamScore[4]; // hud stuff typedef struct { diff --git a/csqc/events.qc b/csqc/events.qc index fabb6434..e8caf092 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -264,10 +264,14 @@ void() CSQC_Parse_Event = { grentimer_waiting = FALSE; break; case MSG_TEAM_SCORES: - TS.team1score = readfloat(); - TS.team2score = readfloat(); - TS.team3score = readfloat(); - TS.team4score = readfloat(); + //TS.team1score = readfloat(); + //TS.team2score = readfloat(); + //TS.team3score = readfloat(); + //TS.team4score = readfloat(); + TeamScore[0] = readfloat(); + TeamScore[1] = readfloat(); + TeamScore[2] = readfloat(); + TeamScore[3] = readfloat(); break; } } diff --git a/csqc/hud.qc b/csqc/hud.qc index d1e26072..512c331f 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -254,14 +254,16 @@ void(string panelid) Hud_DrawTeamScorePanel = { vector position = getPosition(id); vector size = getFillSize(id); + float textScale = panel.TextScale?panel.TextScale:panel.Scale; float sizex, sizey; sizex = size_x; sizey = size_y; - vector mediumtext = MENU_TEXT_SMALL * panel.Scale; - local float padding = 4 * panel.Scale; + vector mediumtext = MENU_TEXT_SMALL * textScale; + local float padding = 0.5 * textScale; - local vector fillsize = mediumtext; + local vector fillsize = [12,12] * textScale; //mediumtext; fillsize_x = fillsize_x * 3; + fillsize_y = fillsize_y + padding * 2; if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_TEAM_SCORE].Display)) { @@ -274,12 +276,27 @@ void(string panelid) Hud_DrawTeamScorePanel = { local float offset; - local vector score_position; + local vector score_position = position; local string message = ""; if(panel.Orientation == FO_HUD_INSERT_AFTER) { position_x = position_x - ((number_of_teams - 1) * fillsize_x); } + float len; + float textOffset; + string val; + for(float i = 0; i < number_of_teams; i++) { + score_position = position; + offset = (fillsize_x) * i; + score_position_x = score_position_x + offset; + //message = strcat(message, strpad(-3, ftos(TS.team1score))); + drawfill(score_position, fillsize, TEXT_TEAM_COLOUR[i], 0.5, 0); + val = ftos(TeamScore[i]); + len = strlen(val); + textOffset = (12 * textScale * (3 - len)); + Hud_DrawStringLMP(score_position + [textOffset,padding], val, 12 * textScale); + } +/* if (number_of_teams >= 1) { score_position = position; offset = fillsize_x * 0; @@ -311,7 +328,7 @@ void(string panelid) Hud_DrawTeamScorePanel = { message = strcat(message, strpad(-3, ftos(TS.team4score))); drawfill(score_position, fillsize, '0.4 0.7 0.3', 0.5, 0); } - +*/ /* drawfill( */ /* position + [size.x / 2,padding*2 + mediumtext.y*2], */ /* mediumtext, */ @@ -319,7 +336,7 @@ void(string panelid) Hud_DrawTeamScorePanel = { /* 1, */ /* 0 */ /* ); */ - +/* drawstring( position, message, @@ -328,6 +345,7 @@ void(string panelid) Hud_DrawTeamScorePanel = { 1, 0 ); +*/ }; void Hud_DrawFlagStatusBar(string panelid) diff --git a/csqc/menu.qc b/csqc/menu.qc index 10f41a69..d3d6b150 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -104,10 +104,10 @@ void teamChosen(string team) = { var fo_menu FO_MENU_TEAM = { [0,0], [300,200], "Select Team", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Blue team","","Known for cunning and strategy, Blues like to attack first",FO_MENU_STATE_NORMAL,{teamChosen("1");},'0.3 0.4 0.7'}, - {"2","Red team","","Excellent at standing their ground, Reds won't stand for being attacked",FO_MENU_STATE_NORMAL,{teamChosen("2");},'0.7 0.4 0.3'}, - {"3","Yellow team","","The best team",FO_MENU_STATE_NORMAL,{teamChosen("3");},'0.7 0.7 0.3'}, - {"4","Green team","","Also okay",FO_MENU_STATE_NORMAL,{teamChosen("4");},'0.4 0.7 0.3'}, + {"1","Blue team","","Known for cunning and strategy, Blues like to attack first",FO_MENU_STATE_NORMAL,{teamChosen("1");},MENU_TEXT_BLUE_FO}, + {"2","Red team","","Excellent at standing their ground, Reds won't stand for being attacked",FO_MENU_STATE_NORMAL,{teamChosen("2");},MENU_TEXT_RED_FO}, + {"3","Yellow team","","The best team",FO_MENU_STATE_NORMAL,{teamChosen("3");},MENU_TEXT_YELLOW_FO}, + {"4","Green team","","Also okay",FO_MENU_STATE_NORMAL,{teamChosen("4");},MENU_TEXT_GREEN_FO}, MenuSpacer, {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{teamChosen("auto");},MENU_BUTTON}, MenuSpacer, From aeadf0a28be6ddae4c34495553750e80b921bc78 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 14 Nov 2020 21:15:10 +1300 Subject: [PATCH 1155/2474] clean up old code --- csqc/events.qc | 4 ---- csqc/hud.qc | 50 -------------------------------------------------- 2 files changed, 54 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index e8caf092..b7b25407 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -264,10 +264,6 @@ void() CSQC_Parse_Event = { grentimer_waiting = FALSE; break; case MSG_TEAM_SCORES: - //TS.team1score = readfloat(); - //TS.team2score = readfloat(); - //TS.team3score = readfloat(); - //TS.team4score = readfloat(); TeamScore[0] = readfloat(); TeamScore[1] = readfloat(); TeamScore[2] = readfloat(); diff --git a/csqc/hud.qc b/csqc/hud.qc index 512c331f..4f2d045b 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -296,56 +296,6 @@ void(string panelid) Hud_DrawTeamScorePanel = { textOffset = (12 * textScale * (3 - len)); Hud_DrawStringLMP(score_position + [textOffset,padding], val, 12 * textScale); } -/* - if (number_of_teams >= 1) { - score_position = position; - offset = fillsize_x * 0; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team1score))); - drawfill(score_position, fillsize, '0.3 0.4 0.7', 0.5, 0); - } - - if (number_of_teams >= 2) { - score_position = position; - offset = fillsize_x * 1; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team2score))); - drawfill(score_position, fillsize, '0.7 0.4 0.3', 0.5, 0); - } - - if (number_of_teams >= 3) { - score_position = position; - offset = fillsize_x * 2; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team3score))); - drawfill(score_position, fillsize, '0.7 0.7 0.3', 0.5, 0); - } - - if (number_of_teams >= 4) { - score_position = position; - offset = fillsize_x * 3; - score_position_x = score_position_x + offset; - message = strcat(message, strpad(-3, ftos(TS.team4score))); - drawfill(score_position, fillsize, '0.4 0.7 0.3', 0.5, 0); - } -*/ - /* drawfill( */ - /* position + [size.x / 2,padding*2 + mediumtext.y*2], */ - /* mediumtext, */ - /* '255 0 0', */ - /* 1, */ - /* 0 */ - /* ); */ -/* - drawstring( - position, - message, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); -*/ }; void Hud_DrawFlagStatusBar(string panelid) From a34cbb104ff753ad9193acfa5c71323fe3434acd Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 14 Nov 2020 23:32:25 +1300 Subject: [PATCH 1156/2474] showscores - added ready+chat icons; self+spec colour (gold+purple) --- csqc/csextradefs.qc | 1 + csqc/status.qc | 67 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 43c2721b..89c98fff 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -351,6 +351,7 @@ typedef struct { float damagegiven; float damagetaken; float ready; + float chat; } FO_ScoreBoardLine; // fte maxclients is 255, right? diff --git a/csqc/status.qc b/csqc/status.qc index 4da0d64b..2815df29 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -499,17 +499,24 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id sui_fill(position, size, columnColour, trans, 0); - if (prematch && lines[i].team_no && !SBAR.CountdownStarted - && lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) - { - float ready = lines[i].ready; - if (ready) - { - textcolour = MENU_TEXT_GREEN_FO; - } - else + textcolour = MENU_TEXT_1; + if(lines[i].name == getplayerkeyvalue(player_localnum, "name")) { + textcolour = MENU_TEXT_4; + } else if(lines[i].name == getplayerkeyvalue(player_localentnum - 1, "name")) { + textcolour = '0.8 0 0.8'; + } else { + if (prematch && lines[i].team_no && !SBAR.CountdownStarted + && lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { - textcolour = MENU_TEXT_RED_FO; + float ready = lines[i].ready; + if (ready) + { + textcolour = MENU_TEXT_GREEN_FO; + } + else + { + textcolour = MENU_TEXT_RED_FO; + } } } @@ -558,6 +565,45 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id sui_text(position, smalltext, n, textcolour, 1, 0); position_x += namespace; + vector iconpos = [size_x, position_y]; + //check for icon files existing, otherwise use fallbacks + float filehandle; + if(lines[i].ready) { + filehandle = fopen(strcat("textures/wad/icon_ready.png"), FILE_READ); + if (filehandle >= 0) { + fclose(filehandle); + sui_pic(iconpos, smalltext, "textures/wad/icon_ready.png", '1 1 1', alpha, flags); + } else { + sui_text(iconpos, smalltext, "R", MENU_TEXT_GREEN_FO, 1, 0); + } + iconpos_x += smalltext.x; + } + if(lines[i].chat & 1) { + filehandle = fopen(strcat("textures/wad/icon_chat.png"), FILE_READ); + if (filehandle >= 0) { + fclose(filehandle); + sui_pic(iconpos, smalltext, "textures/wad/icon_chat.png", '1 1 1', alpha, flags); + } else { + //use ezquake chaticons image. Couldn't get drawsubpic to work, so now we get this instead + drawsetcliparea(iconpos_x + panel.Position.x, iconpos_y + panel.Position.y + 20, smalltext.x, smalltext.y); + sui_pic(iconpos, [smalltext_x * 4,smalltext_y * 256 / 56 ], "textures/chaticons.png", '1 1 1', alpha, flags); + drawresetcliparea(); + } + iconpos_x += smalltext.x; + } + if(lines[i].chat & 2) { + filehandle = fopen(strcat("textures/wad/icon_afk.png"), FILE_READ); + if (filehandle >= 0) { + fclose(filehandle); + sui_pic(iconpos, smalltext, "textures/wad/icon_afk.png", '1 1 1', alpha, flags); + } else { + drawsetcliparea(iconpos_x + panel.Position.x, iconpos_y + panel.Position.y + 20, smalltext.x, smalltext.y); + sui_pic(iconpos - [smalltext_x,0], [smalltext_x * 4,smalltext_y * 256 / 56 ], "textures/chaticons.png", '1 1 1', alpha, flags); + drawresetcliparea(); + } + iconpos_x += smalltext.x; + } + if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) { position_y += smalltext_y; @@ -669,6 +715,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane sbl.damagetaken = getplayerkeyfloat(i, "damagetaken"); sbl.team_no = getplayerkeyfloat(i, "team_no"); sbl.ready = getplayerkeyfloat(i, "ready"); + sbl.chat = getplayerkeyfloat(i, "chat"); switch (sbl.team_no) { From c373c0706dcfe06b798c21bb2ca75f78e227014c Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 15 Nov 2020 13:01:47 +1300 Subject: [PATCH 1157/2474] fix non-csqc map vote menu for specs --- ssqc/spect.qc | 4 ++++ ssqc/vote.qc | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ssqc/spect.qc b/ssqc/spect.qc index d9febda5..19ae0b68 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -90,6 +90,10 @@ void () SpectatorImpulseCommand = { TeamFortress_TeamShowScores(0); + if(self.menu_input == Vote_Menu_Map_Input && self.impulse >= 1 && self.impulse <= 10) { + Menu_Input(self.impulse); + } + if (!self.is_admin) { self.impulse = 0; return; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 069dbc21..b424e23e 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1594,7 +1594,11 @@ void (float inp) Vote_Menu_Map_Input = { local entity mc = Vote_Menu_Map_GetMapCandidate((self.current_menu_page - 1) * 7 + inp); if(mc) { self.admin_use = mc; - Vote_Menu_Map_Action(0); + if(self.classname == "observer") { + Vote_Menu_Map_Action_Input(2); + } else { + Vote_Menu_Map_Action(0); + } } }; void (float update) Vote_Menu_Map = { From 44cf63efb1a8761dd5af509e2d0cab290d144716 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Wed, 18 Nov 2020 23:54:31 -0300 Subject: [PATCH 1158/2474] fixing pyro throwing hwguy's around --- ssqc/combat.qc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 3547136f..b49d079b 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -531,15 +531,21 @@ void (entity targ, entity inflictor, entity attacker, float damage, targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; dir = normalize(dir); + moment = damage; + if (inflictor.classname == "pyro_rocket" && pyro_type == 1) { + moment = damage * 1.25; + if (attacker == targ) { + moment = damage * 1.5; + } + else { + moment = damage * 1.25; + } + } if (targ.playerclass == PC_HVYWEAP) { - moment = damage / 4; + moment = moment / 4; if (damage <= 50) moment = 0; - } else - moment = damage; - if (inflictor.classname == "pyro_rocket" && pyro_type == 1) { - moment = damage * 1.5; - } + } if ((moment < 60) && (attacker.classname == "player") From 0ab24cb6403f53322e05bc7866aec15b92fd2e72 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 19 Nov 2020 21:43:08 +1300 Subject: [PATCH 1159/2474] vote menu filtering + unvote fix --- csqc/csextradefs.qc | 4 +++ csqc/events.qc | 4 +++ csqc/hud.qc | 83 +++++++++++++++++++++++++-------------------- csqc/input.qc | 36 ++++++++++++++++++-- csqc/main.qc | 1 + csqc/vote.qc | 30 ++++++++++++++++ ssqc/csmenu.qc | 2 +- ssqc/vote.qc | 2 +- 8 files changed, 121 insertions(+), 41 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1d04a7fc..e8cbbce1 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -50,6 +50,8 @@ vector MENU_TEXT_SPEC_FO = '0.1 0.1 0.1'; #define TEAM_SPECTATOR 9 #define TEAM_OBSERVER 99 +#define MAP_MAX_CHARS 20 + .float owned_by; .string netname; .float playerid; @@ -83,10 +85,12 @@ float grentimer_waiting; //grenade primed, but not thrown float jump_counter; float frames_since_onground; float num_mapvotes; +float num_mapvotes_filtered; entity vote_selected_item; float vote_selected_index; float vote_list_offset; entity current_vote; +string vote_list_filter; .string name; .string description; diff --git a/csqc/events.qc b/csqc/events.qc index 54c4781d..2c33ae5b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -278,6 +278,10 @@ void() CSQC_Parse_Event = { te.votecount = readfloat(); if(readbyte()) { current_vote = te; + } else { + if(current_vote == te) { + current_vote = world; + } } break; case MSG_VOTE_MAP_ADD: diff --git a/csqc/hud.qc b/csqc/hud.qc index d094b03f..b14de4b7 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -270,7 +270,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { listitemsize.y = listitemsize.y * textscale; titlesize = titlesize * textscale; padding = padding * panel.Scale; - listitemsize.x = listitemsize.y * 20; //20 chars of mapname + listitemsize.x = listitemsize.y * MAP_MAX_CHARS; //20 chars of mapname local vector listviewsize = [listitemsize.x, fillsize.y - padding * 3 - listitemsize.y]; local float visiblelistitems = floor(listviewsize.y / listitemsize.y); @@ -281,7 +281,16 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_text([padding, 0], [titlesize,titlesize], "Map Selection", MENU_TEXT_4, 1, 0); sui_pop_frame(); - + //Filter textbox + if(vote_list_filter != "") { + sui_push_frame(panel.Position + [padding,padding], listitemsize + [0,padding]); + //sui_border_box([0,0], listitemsize, 1, MENU_BG_DARK, 0.6, 0); + sui_fill([0,0], listitemsize + [0,padding], MENU_BG_DARK, 0.6, 0); + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + sui_text([0, 0], [listitemsize.y, listitemsize.y], vote_list_filter, MENU_TEXT_2, 1, 0); + sui_pop_frame(); + } + vector listoffset; /* sui_list_view_begin(strcat("a", "scrl"), panel.Position + [200,4], [100, 150], [94, 10], num_mapvotes, listoffset, [0, 6]); @@ -300,13 +309,13 @@ void(string panelid) Hud_DrawMapMenuPanel = { //sui_scroll_view_begin("scrolltest", panel.Position + [200,4], [100,100], [100,200], listoffset, [2,6]); //sui_scroll_view_end(); sui_border_box(panel.Position + [padding, padding * 2 + titlesize], listviewsize, 1, MENU_TEXT_SPEC_FO, 0.6, 0); - if(vote_list_offset > num_mapvotes - visiblelistitems) { - vote_list_offset = num_mapvotes - visiblelistitems; + if(vote_list_offset > num_mapvotes_filtered - visiblelistitems) { + vote_list_offset = num_mapvotes_filtered - visiblelistitems; } if(vote_list_offset < 0) { vote_list_offset = 0; } - entity mc = find(world, classname, "map_candidate"); + entity mc = find(world, classname, "map_candidate_filtered"); while(mc) { if(cnt >= vote_list_offset) { listitempos = panel.Position + [padding, padding * 2 + titlesize + listitemsize.y * (cnt - vote_list_offset)]; @@ -323,8 +332,8 @@ void(string panelid) Hud_DrawMapMenuPanel = { if(vote_selected_index < 0) { vote_selected_index = 0; } - if(vote_selected_index >= num_mapvotes) { - vote_selected_index = num_mapvotes - 1; + if(vote_selected_index >= num_mapvotes_filtered) { + vote_selected_index = num_mapvotes_filtered - 1; } if(vote_selected_index == cnt) { vote_selected_item = mc; @@ -343,27 +352,27 @@ void(string panelid) Hud_DrawMapMenuPanel = { //sui_fill(listitempos, listitemsize, bgcolour, alpha, 0); //sui_text(listitempos, [listitemsize.y, listitemsize.y], mc.name, textcolour, alpha, 0); sui_push_frame(listitempos, listitemsize); - if(current_vote && mc == current_vote) { + if(current_vote && mc.owner == current_vote) { textcolour = MENU_TEXT_GREEN; - } else if(mc.votecount > 0) { + } else if(mc.owner.votecount > 0) { textcolour = MENU_TEXT_WARNING; } else { textcolour = MENU_TEXT_1; } - if(hud_colour_button(strcat("listitem",ftos(cnt)),[0,0], listitemsize, mc.name, bgcolour, [listitemsize.y, listitemsize.y], textcolour, SUI_ALIGN_START, 2, alpha, alpha, 1)) { + if(hud_colour_button(strcat("listitem",ftos(cnt)),[0,0], listitemsize, mc.owner.name, bgcolour, [listitemsize.y, listitemsize.y], textcolour, SUI_ALIGN_START, 2, alpha, alpha, 1)) { vote_selected_item = mc; vote_selected_index = cnt; } - if(mc.votecount > 0) { + if(mc.owner.votecount > 0) { sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); - sui_text([padding * -1, 0], [listitemsize.y, listitemsize.y], ftos(mc.votecount), MENU_TEXT_4, alpha, 0); + sui_text([padding * -1, 0], [listitemsize.y, listitemsize.y], ftos(mc.owner.votecount), MENU_TEXT_4, alpha, 0); } sui_pop_frame(); } cnt++; - mc = find(mc, classname, "map_candidate"); + mc = find(mc, classname, "map_candidate_filtered"); } - if(cnt < num_mapvotes) { + if(cnt < num_mapvotes_filtered) { //draw scrollbar here //sui_scrollbar("maplist_scrollbar", [listitemsize.x, fillsize.y - padding * 3 - listitemsize.y], [listitemsize.x,listitemsize.y * num_mapvotes], listoffset, [0,6]); } @@ -375,7 +384,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { float mapinfowidth = fillsize.x - (mapheadingpos.x - panel.Position.x); sui_push_frame(mapheadingpos, [mapinfowidth, titlesize]); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_text([padding, 0], [titlesize,titlesize], (vote_selected_item?vote_selected_item.name:"No map selected"), MENU_TEXT_3, 1, 0); + sui_text([padding, 0], [titlesize,titlesize], (vote_selected_item?vote_selected_item.owner.name:"No map selected"), MENU_TEXT_3, 1, 0); sui_pop_frame(); if(!vote_selected_item) { @@ -383,13 +392,13 @@ void(string panelid) Hud_DrawMapMenuPanel = { } float current_vote_selected = FALSE; - if(current_vote && current_vote == vote_selected_item) { + if(current_vote && current_vote == vote_selected_item.owner) { current_vote_selected = TRUE; } //Map image float filehandle; - string levelshot = strcat("textures/levelshots/",vote_selected_item.name,".jpg"); //need to fix extensions somehow + string levelshot = strcat("textures/levelshots/",vote_selected_item.owner.name,".jpg"); //need to fix extensions somehow filehandle = fopen(levelshot, FILE_READ); if (filehandle >= 0) { fclose(filehandle); @@ -408,32 +417,32 @@ void(string panelid) Hud_DrawMapMenuPanel = { //Map details float mapdetailgridindex = 0; sui_push_frame(mapheadingpos + [0,titlesize + padding * 2], [mapinfowidth - levelshotsize.x, titlesize]); - if(vote_selected_item.group) { + if(vote_selected_item.owner.group) { sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Type:", MENU_TEXT_2, 1, 0); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); - sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], vote_selected_item.groupname, MENU_TEXT_2, 1, 0); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], vote_selected_item.owner.groupname, MENU_TEXT_2, 1, 0); mapdetailgridindex++; } - if(vote_selected_item.team_num) { + if(vote_selected_item.owner.team_num) { sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Teams:", MENU_TEXT_2, 1, 0); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); - sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], ftos(vote_selected_item.team_num), MENU_TEXT_2, 1, 0); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], ftos(vote_selected_item.owner.team_num), MENU_TEXT_2, 1, 0); mapdetailgridindex++; } - if(vote_selected_item.min_val || vote_selected_item.max_val) { + if(vote_selected_item.owner.min_val || vote_selected_item.owner.max_val) { string playernumstring = ""; - if(vote_selected_item.min_val && vote_selected_item.max_val) { - if(vote_selected_item.min_val == vote_selected_item.max_val) { - playernumstring = strcat(ftos(vote_selected_item.min_val)); + if(vote_selected_item.owner.min_val && vote_selected_item.owner.max_val) { + if(vote_selected_item.owner.min_val == vote_selected_item.owner.max_val) { + playernumstring = strcat(ftos(vote_selected_item.owner.min_val)); } else { - playernumstring = strcat(ftos(vote_selected_item.min_val),"-",ftos(vote_selected_item.max_val)); + playernumstring = strcat(ftos(vote_selected_item.owner.min_val),"-",ftos(vote_selected_item.owner.max_val)); } - } else if(vote_selected_item.min_val) { - playernumstring = strcat(ftos(vote_selected_item.min_val),"+"); + } else if(vote_selected_item.owner.min_val) { + playernumstring = strcat(ftos(vote_selected_item.owner.min_val),"+"); } else { - playernumstring = strcat(ftos(vote_selected_item.max_val),"-"); + playernumstring = strcat(ftos(vote_selected_item.owner.max_val),"-"); } sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Players:", MENU_TEXT_2, 1, 0); @@ -444,9 +453,9 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Client-side:", MENU_TEXT_2, 1, 0); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); - sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], vote_selected_item.localmap?"\x10\x8f\x11":"\x10 \x11", MENU_TEXT_2, 1, 0); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], vote_selected_item.owner.localmap?"\x10\x8f\x11":"\x10 \x11", MENU_TEXT_2, 1, 0); mapdetailgridindex++; - if(vote_selected_item.votecount) { + if(vote_selected_item.owner.votecount) { if(current_vote_selected) { textcolour = MENU_TEXT_GREEN; } else { @@ -455,7 +464,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Votes:", textcolour, 1, 0); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); - sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], strcat(ftos(vote_selected_item.votecount),(current_vote_selected?" (your vote)":"")), textcolour, 1, 0); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], strcat(ftos(vote_selected_item.owner.votecount),(current_vote_selected?" (your vote)":"")), textcolour, 1, 0); mapdetailgridindex++; } sui_pop_frame(); @@ -465,7 +474,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { vector descriptionpos = [mapheadingpos.x,panel.Position.y + fillsize.y - padding * 4 - titlesize - listitemsize.y * 3] sui_push_frame(descriptionpos, [mapinfowidth - padding * 2, listitemsize.y * 3]); sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); - sui_text([padding / 2, padding / 2], [listitemsize.y,listitemsize.y], vote_selected_item.description, MENU_TEXT_1, 1, 0); + sui_text([padding / 2, padding / 2], [listitemsize.y,listitemsize.y], vote_selected_item.owner.description, MENU_TEXT_1, 1, 0); //sui_border_box([0,0], [fillsize.x - (mapheadingpos.x - panel.Position.x), listitemsize.y * 3], 1, MENU_BORDER, 0.6, 0); sui_border_box([0,0], [mapinfowidth - padding, listitemsize.y * 3], 1, MENU_BORDER, 0.6, 0); sui_pop_frame(); @@ -475,18 +484,18 @@ void(string panelid) Hud_DrawMapMenuPanel = { if(current_vote_selected) { if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Unvote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { localcmd("cmd break\n"); - current_vote = world; + //current_vote = world; } } else { if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Vote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { - localcmd("cmd votemap ", vote_selected_item.name, "\n"); + localcmd("cmd votemap ", vote_selected_item.owner.name, "\n"); } } if(hud_colour_button("change_button", [0 - listitemsize.x - padding,0], listitemsize + [0,padding], "Change Now", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_WARNING, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { if(is_admin) { - localcmd("cmd map ", vote_selected_item.name, "\n"); + localcmd("cmd map ", vote_selected_item.owner.name, "\n"); } else { - localcmd("rcon map ", vote_selected_item.name, "\n"); + localcmd("rcon map ", vote_selected_item.owner.name, "\n"); } } diff --git a/csqc/input.qc b/csqc/input.qc index 2631f6f2..d921c4a6 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -3,7 +3,7 @@ void FO_Menu_Game(float); float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { float used = sui_input_event(evtype, scanx, chary, devid); - //if(evtype == IE_KEYUP) print("Key up: ", ftos(scanx), ", char: ", ftos(chary), "\n"); + //if(evtype == IE_KEYDOWN) print("Key down: ", ftos(scanx), ", char: ", ftos(chary), "\n"); float menu_mouse = (fo_hud_menu_active && (CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)); if (fo_hud_editor || fo_hud_menu_active) { @@ -104,7 +104,39 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { vote_list_offset++; return TRUE; break; - } + case K_ENTER: + if(vote_selected_item && current_vote == vote_selected_item.owner) { + localcmd("cmd break\n"); + } else { + localcmd("cmd votemap ", vote_selected_item.owner.name, "\n"); + } + return TRUE; + break; + case K_BACKSPACE: + if(strlen(vote_list_filter) > 0) { + vote_list_filter = substring(vote_list_filter, 0, strlen(vote_list_filter) - 1); + ApplyMapFilter(); + } + return TRUE; + break; + case K_DEL: //blank it out + if(strlen(vote_list_filter) > 0) { + vote_list_filter = ""; + ApplyMapFilter(); + } + return TRUE; + default: + //48 = '0' .. 57 = '9' + //97 = 'a' .. 122 = 'z' + //45 = '-' + if((scanx >= 48 && scanx <= 57) || (scanx >= 97 && scanx <= 122) || scanx == 45) { + if(strlen(vote_list_filter) < MAP_MAX_CHARS) { + vote_list_filter = strcat(vote_list_filter, chr2str(chary)); + ApplyMapFilter(); + } + return TRUE; + } + } case IE_KEYUP: switch (scanx) { case K_ESCAPE: diff --git a/csqc/main.qc b/csqc/main.qc index 4db1175d..be30eded 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -73,6 +73,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_selected_index = -1; vote_list_offset = 0; current_vote = world; + vote_list_filter = ""; }; noref void() CSQC_WorldLoaded = { diff --git a/csqc/vote.qc b/csqc/vote.qc index 02c85891..2018e4b9 100644 --- a/csqc/vote.qc +++ b/csqc/vote.qc @@ -1,4 +1,32 @@ +void () ApplyMapFilter = { + entity mc = find(world, classname, "map_candidate_filtered"); + entity temp = world; + while(mc) { + remove(mc); + mc = find(mc, classname, "map_candidate_filtered"); + } + num_mapvotes_filtered = 0; + mc = find(world, classname, "map_candidate"); + while(mc) { + if(strstrofs(mc.name, vote_list_filter) > -1) { + temp = spawn(); + temp.classname = "map_candidate_filtered"; + temp.owner = mc; + //temp.name = mc.name; + //temp.description = mc.description; + //temp.groupname = mc.groupname; + //temp.group = mc.group; + //temp.team_num = mc.team_num; + //temp.min_val = mc.min_val; + //temp.max_val = mc.max_val; + //temp.localmap = mc.localmap; + num_mapvotes_filtered++; + } + mc = find(mc, classname, "map_candidate"); + } +} + /* "name" "amth1" //map name "description" "Duel arena, ctf and Sniper War" //description @@ -52,6 +80,7 @@ entity (string n, string desc, string mapgroup, float num_teams, float min_playe mc.localmap = islocal; num_mapvotes++; + ApplyMapFilter(); return mc; }; @@ -68,6 +97,7 @@ float (string n, float isLocal) RemoveVoteMap = { } remove(mc); num_mapvotes--; + ApplyMapFilter(); return TRUE; } else { return FALSE; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 81b83bed..8bb30d4d 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -294,7 +294,7 @@ void UpdateClientMapVote(entity pl, entity candidate) = { WriteByte(MSG_MULTICAST, MSG_VOTE_UPDATE); WriteString(MSG_MULTICAST, candidate.netname); WriteFloat(MSG_MULTICAST, candidate.cnt); - WriteByte(MSG_MULTICAST, (pl.vote_map == candidate)); + WriteByte(MSG_MULTICAST, (candidate.cnt > 0 && pl.vote_map == candidate)); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/vote.qc b/ssqc/vote.qc index b424e23e..aba22fbf 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1466,8 +1466,8 @@ void (entity p) UnvoteForMap = { } else { bprint(PRINT_HIGH, p.netname, " \babandons vote for\b ", p.vote_map.netname, "\n"); } - UpdateAllClientMapVotes(p.vote_map); p.vote_map.cnt--; + UpdateAllClientMapVotes(p.vote_map); p.vote_map = world; vote_total_votes--; } From a0920d351721d4ae7da147beef9a1e1b53ec3269 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 22 Nov 2020 22:57:12 +1300 Subject: [PATCH 1160/2474] make default size more sensible; fix sending throughput --- csqc/events.qc | 4 ++++ csqc/hud.qc | 2 +- csqc/status.qc | 2 +- ssqc/client.qc | 5 ----- ssqc/csmenu.qc | 20 +++++++++++++++++++- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 2c33ae5b..26350a59 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -289,6 +289,10 @@ void() CSQC_Parse_Event = { te.votecount = readfloat(); if(readbyte()) { current_vote = te; + } else { + if(current_vote == te) { + current_vote = world; + } } break; case MSG_VOTE_MAP_DELETE: diff --git a/csqc/hud.qc b/csqc/hud.qc index b14de4b7..922b8899 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -464,7 +464,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); sui_text([padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], "Votes:", textcolour, 1, 0); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); - sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], strcat(ftos(vote_selected_item.owner.votecount),(current_vote_selected?" (your vote)":"")), textcolour, 1, 0); + sui_text([-2 * padding, (titlesize + padding) * mapdetailgridindex], [titlesize,titlesize], strcat(ftos(vote_selected_item.owner.votecount),(current_vote_selected?" (yours)":"")), textcolour, 1, 0); mapdetailgridindex++; } sui_pop_frame(); diff --git a/csqc/status.qc b/csqc/status.qc index 6606c361..0cc8bc21 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -794,7 +794,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, - {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','400 200',2,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; diff --git a/ssqc/client.qc b/ssqc/client.qc index be83099b..a8c98c73 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2357,11 +2357,6 @@ void () PlayerPreThink = { self.cheat_level = self.cheat_level - 1; } - if (self.vote_map_send) { - UpdateClient_VoteMap_Add(self, self.vote_map_send); - self.vote_map_send = find(self.vote_map_send, classname, "map_candidate"); - } - if (intermission_running) { IntermissionThink(); return; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 8bb30d4d..8893f53e 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -337,11 +337,29 @@ void UpdateClient_VoteMap_Add(entity pl, entity map_candidate) = { WriteByte(MSG_MULTICAST, (pl.vote_map == map_candidate)); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } + +void() votemap_sender_think = { + if (self.owner.vote_map_send) { + UpdateClient_VoteMap_Add(self.owner, self.owner.vote_map_send); + self.owner.vote_map_send = find(self.owner.vote_map_send, classname, "map_candidate"); + self.nextthink = time + 0.1; + } else { + dremove(self); + } +} + void UpdateClient_VoteMap_AddAll(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; + + //PlayerPreThink was too fast. Use a timer to slow down the send rate + //Soas to not overflow the message buffers pl.vote_map_send = find(world, classname, "map_candidate"); - //Now just let PlayerPreThink handle the rest + local entity sender_timer = spawn(); + sender_timer.owner = pl; + sender_timer.classname = "votemap_sender_timer"; + sender_timer.nextthink = time + 0.1; + sender_timer.think = votemap_sender_think; } void UpdateClient_VoteMap_Add_Broadcast(entity map_candidate) = { From 5456840fb4ac556a07cf5cd1f4064918fef2b062 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 3 Dec 2020 22:26:52 +1300 Subject: [PATCH 1161/2474] better defaults; dragging --- csqc/csextradefs.qc | 2 ++ csqc/hud.qc | 16 ++++++++++++++++ csqc/input.qc | 5 +++++ csqc/main.qc | 1 + csqc/status.qc | 2 +- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e8cbbce1..665d609c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -266,6 +266,8 @@ typedef struct } MouseStruct; MouseStruct Mouse; +MouseStruct PrevMouse; +float MouseDown; typedef struct { string filename; diff --git a/csqc/hud.qc b/csqc/hud.qc index 922b8899..cc648f52 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -98,6 +98,8 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; Hud_Panels[HUD_PANEL_SHOWSCORES].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_SHOWSCORES].FillSize.x / 2), 30]; Hud_Panels[HUD_PANEL_SHOWSCORES].Scale = 1.00; + Hud_Panels[HUD_PANEL_MAP_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MAP_MENU].FillSize.x / 2), 30]; + Hud_Panels[HUD_PANEL_MAP_MENU].Scale = 1.00; } void FO_Hud_Editor_List_Panels() = { @@ -233,6 +235,20 @@ void(string id, vector pos, vector size, string name, string command) bind_butto sui_pop_frame(); }; + +void (float dx, float dy) Hud_MapMenuPanel_Move = { + FO_Hud_Panel* panel = &Hud_Panels[HUD_PANEL_MAP_MENU]; + if( + Mouse.x > panel.Position.x && + Mouse.y > panel.Position.y && + Mouse.x < (panel.Position.x + panel.FillSize.x * panel.Scale) && + Mouse.y < (panel.Position.y + panel.FillSize.y * panel.Scale) + ) { + panel.Position.x += dx; + panel.Position.y += dy; + } +}; + void(string panelid) Hud_DrawMapMenuPanel = { float id = getHudPanel(panelid); diff --git a/csqc/input.qc b/csqc/input.qc index d921c4a6..a7310932 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -65,8 +65,11 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case IE_MOUSEDELTA: return TRUE; case IE_MOUSEABS: + PrevMouse.x = Mouse.x; + PrevMouse.y = Mouse.y; Mouse.x = scanx; Mouse.y = chary; + if(MouseDown) Hud_MapMenuPanel_Move(Mouse.x - PrevMouse.x, Mouse.y - PrevMouse.y); return TRUE; case IE_KEYDOWN: switch (scanx) { @@ -74,6 +77,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; break; case K_MOUSE1: + MouseDown = TRUE; return TRUE; break; case K_UPARROW: @@ -144,6 +148,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; break; case K_MOUSE1: + MouseDown = FALSE; return TRUE; break; } diff --git a/csqc/main.qc b/csqc/main.qc index be30eded..9ac33fd6 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -74,6 +74,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_list_offset = 0; current_vote = world; vote_list_filter = ""; + MouseDown = 0; }; noref void() CSQC_WorldLoaded = { diff --git a/csqc/status.qc b/csqc/status.qc index 0cc8bc21..6d536c52 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -794,7 +794,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, - {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 100','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 30','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; From 62e412eb52ccdbfae414d2b438acc316f0789920 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 9 Dec 2020 19:13:56 +1300 Subject: [PATCH 1162/2474] trigger_jumper --- ssqc/triggers.qc | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index eeadf6f0..a4cd3d8a 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -675,3 +675,48 @@ void () trigger_monsterjump = { InitTrigger(); self.touch = trigger_monsterjump_touch; }; + +void () trigger_jumper_touch = { + local entity te; + + if(!Activated(self, other)) { + if((self.else_goal != 0)) { + te = Findgoal(self.else_goal); + if(te) { + DoResults(te, other, (self.goal_result & TFGR_ADD_BONUSES)); + } + } + return; + } + if(((other.classname == "grenade") || (other.classname != "player"))) { + return; + } else { + if(((other.health > 0) && !self.armorclass)) { + other.velocity_z = (self.speed * 7); + if((other.classname == "player")) { + if((other.fly_sound < time)) { + other.fly_sound = (time + 1.5); + if(!(self.spawnflags & 2.000000)) { + sound(other, 0.000000, "misc/boing.wav", 1.000000, 1.000000); + } + } + } + } + } + if((self.spawnflags & 1)) { + dremove (self); + } +}; + +void () trigger_jumper = { + if((CheckExistence() == 0.000000)) { + dremove (self); + return; + } + InitTrigger(); + precache_sound("misc/boing.wav"); + self.touch = trigger_jumper_touch; + if(!self.speed) { + self.speed = 1000; + } +}; \ No newline at end of file From d24a2805937a012b9e4e389b8e75aadf85aa4852 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Wed, 9 Dec 2020 21:15:50 +1300 Subject: [PATCH 1163/2474] trigger_push.spawnflags & 16 now works like trigger_jumper --- README.md | 1 + share/defs.h | 1 + ssqc/triggers.qc | 87 ++++++++++++++++++++++++------------------------ 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 242441c9..82187bf8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new cvar for zut ``fo_hud_idle_alpha`` - sets the minimum transparency for flaginfo inactive items * optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * localinfo nohitsounds 1 - disables hitsounds server-wide diff --git a/share/defs.h b/share/defs.h index f7f91142..5466b047 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1434,4 +1434,5 @@ #define PUSH_INCLUDETFITEM 2 #define PUSH_EXCLUDEOTHER 4 // bad names, bad bits, bad coder #define PUSH_NONOISE 8 +#define PUSH_MEGAJUMPER 16 diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index a4cd3d8a..929dbeeb 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -502,6 +502,38 @@ void () trigger_hurt = { self.dmg = 5; }; +void () trigger_jumper_touch = { + local entity te; + + if(!Activated(self, other)) { + if((self.else_goal != 0)) { + te = Findgoal(self.else_goal); + if(te) { + DoResults(te, other, (self.goal_result & TFGR_ADD_BONUSES)); + } + } + return; + } + if(((other.classname == "grenade") || (other.classname != "player"))) { + return; + } else { + if(((other.health > 0) && !self.armorclass)) { + other.velocity_z = (self.speed * 7); + if((other.classname == "player")) { + if((other.fly_sound < time)) { + other.fly_sound = (time + 1.5); + if(!(self.spawnflags & 2)) { + FO_Sound(other, CHAN_AUTO, self.noise, 1, ATTN_NORM); + } + } + } + } + } + if((self.spawnflags & 1)) { + dremove (self); + } +}; + void () trigger_push_touch = { local entity te; @@ -605,6 +637,7 @@ void () trigger_push = { } InitTrigger(); + self.touch = trigger_push_touch; if (self.target) { // the target ent might not be processed yet, so we do setup after map starts @@ -613,8 +646,12 @@ void () trigger_push = { } else { - if (!self.speed) + if (!self.speed) { self.speed = 1000; + } + if(self.spawnflags & PUSH_MEGAJUMPER) { + self.touch = trigger_jumper_touch; + } } if (!(self.spawnflags & PUSH_NONOISE)) @@ -635,7 +672,6 @@ void () trigger_push = { precache_sound(self.noise); } - self.touch = trigger_push_touch; }; void () trigger_jumppad = { @@ -676,47 +712,10 @@ void () trigger_monsterjump = { self.touch = trigger_monsterjump_touch; }; -void () trigger_jumper_touch = { - local entity te; - - if(!Activated(self, other)) { - if((self.else_goal != 0)) { - te = Findgoal(self.else_goal); - if(te) { - DoResults(te, other, (self.goal_result & TFGR_ADD_BONUSES)); - } - } - return; - } - if(((other.classname == "grenade") || (other.classname != "player"))) { - return; - } else { - if(((other.health > 0) && !self.armorclass)) { - other.velocity_z = (self.speed * 7); - if((other.classname == "player")) { - if((other.fly_sound < time)) { - other.fly_sound = (time + 1.5); - if(!(self.spawnflags & 2.000000)) { - sound(other, 0.000000, "misc/boing.wav", 1.000000, 1.000000); - } - } - } - } - } - if((self.spawnflags & 1)) { - dremove (self); - } -}; - void () trigger_jumper = { - if((CheckExistence() == 0.000000)) { - dremove (self); - return; + if(!self.noise) { + self.noise = "misc/boing.wav"; //"world/bouncepad.wav"; } - InitTrigger(); - precache_sound("misc/boing.wav"); - self.touch = trigger_jumper_touch; - if(!self.speed) { - self.speed = 1000; - } -}; \ No newline at end of file + self.spawnflags = self.spawnflags | PUSH_MEGAJUMPER; + trigger_push(); +} From 65ae6067da64f0c81a4c211002bf66f7f01792bb Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 10 Dec 2020 20:04:43 +1300 Subject: [PATCH 1164/2474] change default trigger_jumper sound as there is a file conflict --- ssqc/triggers.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 929dbeeb..9cd6b2b6 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -714,7 +714,7 @@ void () trigger_monsterjump = { void () trigger_jumper = { if(!self.noise) { - self.noise = "misc/boing.wav"; //"world/bouncepad.wav"; + self.noise = "world/bounce.wav"; //"misc/boing.wav"; //"world/bouncepad.wav"; } self.spawnflags = self.spawnflags | PUSH_MEGAJUMPER; trigger_push(); From f50ae4f52d4c6f95b2372e2f14d36170da264ebf Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 13 Dec 2020 14:42:48 +1100 Subject: [PATCH 1165/2474] Add localinfo em to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 734c8617..49b86dae 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. * ``vote_addmap``\``vote_removemap`` now work client-side From 733bf79a2065c8ed4d487a1eacad73e488c5c1eb Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 19 Dec 2020 20:41:24 +1300 Subject: [PATCH 1166/2474] customizable menu options --- csqc/csextradefs.qc | 4 ++++ csqc/main.qc | 7 +++++++ csqc/menu.qc | 9 +++++++++ menu/options_keys.qc | 3 ++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d1afc378..3b44672a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -136,6 +136,10 @@ string HUD_ALIGN[] = { "Center" }; +string MENU_OPTION[] = { + "1","2","3","4","5","6","7","8","9","0","-","+" +}; + typedef struct { string icon; diff --git a/csqc/main.qc b/csqc/main.qc index 9ac33fd6..9fba49fd 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -44,6 +44,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_disguise"); registercommand("fo_menu_build"); registercommand("fo_menu_dropammo"); + registercommand("fo_menu_cancel"); registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("primeone"); @@ -59,6 +60,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("vote_addmap"); registercommand("vote_removemap"); registercvar("fo_hud_idle_alpha", "0.3"); + for(float i = 0; i < MENU_OPTION.length; i++) { + registercvar(strcat("fo_menu_option_",MENU_OPTION[i]), MENU_OPTION[i]); + } FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); @@ -195,6 +199,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_dropammo": FO_Menu_DropAmmo(TRUE, 1, (player_class == PC_ENGINEER)); break; + case "fo_menu_cancel": + Menu_Cancel(); + break; case "primeone": if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { if(!grentimer_waiting) { diff --git a/csqc/menu.qc b/csqc/menu.qc index 74957870..3cff9d0f 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -794,6 +794,7 @@ vector fo_menu_draw(fo_menu * menu) = { float fo_menu_process_input(fo_menu * menu, float scan) = { local string button = ""; local float found = FALSE; + /* if(scan > 47 && scan < 58) { button = ftos(scan - 48); } else { @@ -806,6 +807,14 @@ float fo_menu_process_input(fo_menu * menu, float scan) = { break; } } + */ + string prefix = "fo_menu_option_"; + for(float i = 0; i < MENU_OPTION.length; i++) { + if(str2chr(cvar_string(strcat("fo_menu_option_",MENU_OPTION[i])),0) == scan) { + button = MENU_OPTION[i]; + break; + } + } if(button != "") { for(float i = 0; i < menu.num_opts; i++) { if(menu.options[i].shortcut == button) { diff --git a/menu/options_keys.qc b/menu/options_keys.qc index 9107c268..360e4cb7 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -67,11 +67,12 @@ const static struct {0, 0}, {_(""), "Misc"}, {0, 0}, - {_("Scores"), "+showscores"}, + {_("Scores"), "+fo_showscores"}, {_("Ready Up"), "ready"}, {_("Server Chat"), "messagemode"}, {_("Team Chat"), "messagemode2"}, {_("Map Help"), "maphelp"}, + {_("Main Menu"), "togglemenu"}, /* {_("Break Match"), "break"}, */ /* {_("Voice Chat"), "+voip"}, */ // {_("Mouse Look"), "+mlook"}, From 408a96faf5283dc0555c78c85c6eb145b3aa500f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 27 Dec 2020 21:46:17 +1300 Subject: [PATCH 1167/2474] menu + fix --- csqc/main.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 9fba49fd..5964f081 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -60,9 +60,10 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("vote_addmap"); registercommand("vote_removemap"); registercvar("fo_hud_idle_alpha", "0.3"); - for(float i = 0; i < MENU_OPTION.length; i++) { + for(float i = 0; i < MENU_OPTION.length - 1; i++) { registercvar(strcat("fo_menu_option_",MENU_OPTION[i]), MENU_OPTION[i]); } + registercvar("fo_menu_option_+", "="); FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); From 405798be1eed116ab82b8486dc40ecb1f946d3e8 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 4 Jan 2021 13:10:15 +1100 Subject: [PATCH 1168/2474] fix sg target randomness --- ssqc/client.qc | 2 + ssqc/qw.qc | 1 + ssqc/sentry.qc | 181 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 151 insertions(+), 33 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 47d0b573..a97e713c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -648,6 +648,8 @@ void () DecodeLevelParms = { // new emp range and set damage values (so no dropammo to reduce) new_emp = CF_GetSetting("nemp", "new_emp", "1"); + fo_sentry_targeting = CF_GetSetting("fosgt", "fo_sentry_targ", "1"); + // For duelmode, how soon to reset the winning player (allows for double KOs) duel_reset_delay = CF_GetSetting("drd", "duel_reset_delay", "3.9"); // remove packs in duelmode [1] diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9dba5a57..ec1223e4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -587,6 +587,7 @@ float override_mapclasses; float solid_detpack; float walls_block_emp; float new_emp; +float fo_sentry_targeting; // new improved targeting for sentry guns float cb_keepteams; float fo_flashtime; float solid_nailgren; diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 8c4b0e0c..a6b75ee6 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -6,7 +6,6 @@ void (entity bld) CheckBelowBuilding; void (entity gunhead) CheckSentry; void () Sentry_Rotate; -float () Sentry_FindTarget; void () Sentry_FoundTarget; void () Sentry_HuntTarget; void (entity e, float f) Sentry_Pain; @@ -112,38 +111,6 @@ void () lvl3_sentry_atk3 =[6, lvl3_sentry_atk1] { }; //=========================== -void () Sentry_Rotate = { - local float ay; - - self.effects = self.effects - (self.effects & EF_DIMLIGHT); - CheckSentry(self); - if (Sentry_FindTarget()) - return; - - if (self.heat == 0) { - self.ideal_yaw = self.waitmin; - ChangeYaw(); - ay = anglemod(self.angles_y); - ay = rint(ay); - if (ay == rint(self.waitmin)) { - CheckBelowBuilding(self.trigger_field); - self.heat = 1; - if (random() < 0.1) - FO_Sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, - ATTN_NORM); - } - } else { - self.ideal_yaw = self.waitmax; - ChangeYaw(); - ay = anglemod(self.angles_y); - ay = rint(ay); - if (ay == rint(self.waitmax)) { - CheckBelowBuilding(self.trigger_field); - self.heat = 0; - } - } -}; - float () Sentry_FindTarget = { local entity client; local float r; @@ -202,6 +169,154 @@ float () Sentry_FindTarget = { return (1); }; +float (entity p) FO_Sentry_ValidTarget = { + float valid = TRUE; + + if ((p == self.real_owner) || !p.takedamage) + valid = FALSE; + if (p.has_disconnected == 1) + valid = FALSE; + + if (teamplay) { + if ((p.team_no == self.team_no) && (self.team_no != 0)) + valid = FALSE; + if ((p.undercover_team == self.team_no) && + (self.team_no != 0)) + valid = FALSE; + } + if (p.is_feigning) + valid = FALSE; + if ((p.flags & FL_NOTARGET) || + (p.items & IT_INVISIBILITY)) + valid = FALSE; + if (!visible(p)) + valid = FALSE; + + float r = range(p); + if (r == RANGE_FAR) + valid = FALSE; + else if ((r == RANGE_MID) && !infront(p)) + valid = FALSE; + + return valid; +}; + +void () FO_Sentry_Timer_Think = { + entity oself = self; + oself.nextthink = time + 0.01; + oself.cnt2 = oself.cnt2 + 0.01; // rotate speed + self = self.owner; + + if (FO_Sentry_ValidTarget(self.enemy)) + { + if (oself.cnt2 >= 0.1) + { + ai_face(); + oself.cnt2 = 0; + } + + if (oself.cnt <= time) + { + Sentry_FoundTarget(); + dremove(oself); + } + } + +}; + +float () FO_Sentry_FindTarget = { + entity p = find(world, classname, "player"); + float foundTarg = FALSE; + float dist = -1; + entity targ = world; + + while (p) + { + // do checks + if (FO_Sentry_ValidTarget(p)) + { + // do vlen check + if (dist == -1) + { + dist = vlen(self.origin - p.origin); + targ = p; + } + else if (dist > vlen(self.origin - p.origin)) + { + dist = vlen(self.origin - p.origin); + targ = p; + } + } + + p = find(p, classname, "player"); + } + + if (!targ) + { + self.enemy = world; + return FALSE; + } + + self.enemy = targ; + if (self.enemy.classname != "player") { + self.enemy = self.enemy.enemy; + if (self.enemy.classname != "player") { + self.enemy = world; + return FALSE; + } + } + + // attack delay + entity timer = spawn(); + timer.owner = self; + timer.think = FO_Sentry_Timer_Think; + timer.cnt = time + 0.15; // delay + timer.nextthink = time + 0.01; + + return TRUE; +}; + +void () Sentry_Rotate = { + local float ay; + + self.effects = self.effects - (self.effects & EF_DIMLIGHT); + CheckSentry(self); + + if (fo_sentry_targeting) + { + if (FO_Sentry_FindTarget()) + return; + } + else + { + if (Sentry_FindTarget()) + return; + } + + if (self.heat == 0) { + self.ideal_yaw = self.waitmin; + ChangeYaw(); + ay = anglemod(self.angles_y); + ay = rint(ay); + if (ay == rint(self.waitmin)) { + CheckBelowBuilding(self.trigger_field); + self.heat = 1; + if (random() < 0.1) + FO_Sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, + ATTN_NORM); + } + } else { + self.ideal_yaw = self.waitmax; + ChangeYaw(); + ay = anglemod(self.angles_y); + ay = rint(ay); + if (ay == rint(self.waitmax)) { + CheckBelowBuilding(self.trigger_field); + self.heat = 0; + } + } +}; + void () Sentry_FoundTarget = { if ((self.ammo_shells > 0) || ((self.ammo_rockets > 0) && (self.weapon == 3))) From 5dde8233f98bfd2b0bbdb74268903d1657bd787a Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 4 Jan 2021 15:35:26 +1100 Subject: [PATCH 1169/2474] new ratio option for repairing --- ssqc/client.qc | 3 +++ ssqc/engineer.qc | 2 +- ssqc/qw.qc | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 47d0b573..dcc69d19 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -685,6 +685,9 @@ void () DecodeLevelParms = { // fortress one flash time in seconds fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "2"); + // health repair + fo_repair_ratio = CF_GetSetting("forep", "fo_repair_ratio", "2"); + // keep teams on map change [off] cb_keepteams = CF_GetSetting("kt", "keep_teams", "0"); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index ac8f3cf8..d09cf1da 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1387,7 +1387,7 @@ void (entity gun) Engineer_SentryGun_Upgrade = { void (entity gun) Engineer_SentryGun_Repair = { local float metalcost, healamount; - metalcost = ceil((gun.max_health - gun.health) / 5); + metalcost = ceil((gun.max_health - gun.health) / (fo_repair_ratio == 0 ? 5 : fo_repair_ratio)); if (metalcost > self.ammo_cells) metalcost = self.ammo_cells; self.ammo_cells = self.ammo_cells - metalcost; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9dba5a57..dea2e271 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -589,6 +589,7 @@ float walls_block_emp; float new_emp; float cb_keepteams; float fo_flashtime; +float fo_repair_ratio; float solid_nailgren; float noreturn; float nohitsounds; From 44cfa45ac0330595a8691364bcf550bbc14ada99 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 4 Jan 2021 22:14:53 +1100 Subject: [PATCH 1170/2474] fix for sentry not exploding sometimes due to think getting overwritten --- ssqc/sentry.qc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index a6b75ee6..585a5354 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -377,13 +377,15 @@ void () Sentry_Die = { sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); self.real_owner.has_sentry = 0; - self.think = Sentry_Explode; - self.nextthink = time + 0.1; + entity oself = self; + //self.think = Sentry_Explode; + //self.nextthink = time + 0.1; if (self.real_owner.is_building) { self = self.real_owner; TeamFortress_EngineerBuildStop(); } - + self = oself; + Sentry_Explode(); }; float () Sentry_Fire = { From 0f6db0351959d67970e7f96a22817e77765649c0 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 4 Jan 2021 23:31:46 +1100 Subject: [PATCH 1171/2474] increase lock on delay --- ssqc/sentry.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 585a5354..977ece09 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -270,7 +270,7 @@ float () FO_Sentry_FindTarget = { entity timer = spawn(); timer.owner = self; timer.think = FO_Sentry_Timer_Think; - timer.cnt = time + 0.15; // delay + timer.cnt = time + 0.25; // delay timer.nextthink = time + 0.01; return TRUE; From 327584f281dbc9b3921de239e9418e38a131931e Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 5 Jan 2021 23:18:09 +1100 Subject: [PATCH 1172/2474] make sure sentry explodes when it dies --- share/defs.h | 2 +- ssqc/sentry.qc | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/share/defs.h b/share/defs.h index 5466b047..e5016848 100644 --- a/share/defs.h +++ b/share/defs.h @@ -244,7 +244,7 @@ #define TFSTATE_GRENTHROWING 1024 // is throwing a grenade #define TFSTATE_AIMING 2048 // is using the laser sight #define TFSTATE_LOCK 4096 // this state will stop hwguy from shooting assault cannon -#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire +#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire, as sentry gun, indicate it needs to die #define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating #define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised #define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 977ece09..f5e4b9cd 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -329,6 +329,9 @@ void () Sentry_FoundTarget = { }; void () Sentry_HuntTarget = { + if (self.tfstate & TFSTATE_RESPAWN_READY) + return; + self.goalentity = self.enemy; if (self.weapon == 1) @@ -377,15 +380,14 @@ void () Sentry_Die = { sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); self.real_owner.has_sentry = 0; - entity oself = self; - //self.think = Sentry_Explode; - //self.nextthink = time + 0.1; + + self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; + self.think = Sentry_Explode; + self.nextthink = time + 0.1; if (self.real_owner.is_building) { self = self.real_owner; TeamFortress_EngineerBuildStop(); } - self = oself; - Sentry_Explode(); }; float () Sentry_Fire = { From 255d6362e7d4ad4a226b42f3041b84471688300a Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 5 Jan 2021 23:20:54 +1100 Subject: [PATCH 1173/2474] add a random progs version command so we can make sure server is updated --- ssqc/commands.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 45ae0d45..fa876313 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -313,6 +313,9 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { + case "progsversion" + sprint(self, PRINT_HIGH, "sv progs version: 0.1\n"); + break; case "adminpwd": processedCmd = TRUE; if (arg_num == 2) { From 83e334c9678ac44fecc991e13f3035a6bb8159f1 Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 5 Jan 2021 23:22:51 +1100 Subject: [PATCH 1174/2474] missing punctuation --- ssqc/commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index fa876313..3975a8b0 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -313,7 +313,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { - case "progsversion" + case "progsversion": sprint(self, PRINT_HIGH, "sv progs version: 0.1\n"); break; case "adminpwd": From dc6cdab184a8e83b63a0727cc2fb9be1cd446da8 Mon Sep 17 00:00:00 2001 From: lordee Date: Wed, 6 Jan 2021 15:44:56 +1100 Subject: [PATCH 1175/2474] lose target properly --- ssqc/sentry.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index f5e4b9cd..7e334316 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -221,7 +221,10 @@ void () FO_Sentry_Timer_Think = { dremove(oself); } } - + else + { + dremove(oself); // lose tracking when people duck behind walls + } }; float () FO_Sentry_FindTarget = { From fcd332bd097b335b7221bfc0de71fe259507a20a Mon Sep 17 00:00:00 2001 From: lordee Date: Fri, 8 Jan 2021 22:48:58 +1100 Subject: [PATCH 1176/2474] range based delay --- ssqc/sentry.qc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 7e334316..4f788e49 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -269,11 +269,20 @@ float () FO_Sentry_FindTarget = { } } + vector spot1 = self.origin + self.view_ofs; + vector spot2 = targ.origin + targ.view_ofs; + + float r = vlen(spot1 - spot2); + float delay = 0.25; + if (r >= 500) // RANGE_MID, 500 is halfway of sentry targeting distance + { + delay = 0.35; + } // attack delay entity timer = spawn(); timer.owner = self; timer.think = FO_Sentry_Timer_Think; - timer.cnt = time + 0.25; // delay + timer.cnt = time + delay; // delay timer.nextthink = time + 0.01; return TRUE; From 71ef30e78b20c4e8b9c8cb047d17102533110cd9 Mon Sep 17 00:00:00 2001 From: lordee Date: Fri, 8 Jan 2021 22:49:24 +1100 Subject: [PATCH 1177/2474] increase delay for bad players --- ssqc/sentry.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 4f788e49..726abebc 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -276,7 +276,7 @@ float () FO_Sentry_FindTarget = { float delay = 0.25; if (r >= 500) // RANGE_MID, 500 is halfway of sentry targeting distance { - delay = 0.35; + delay = 0.45; } // attack delay entity timer = spawn(); From 3fbcb9547e7e84ceac187f31b91a53283389cb6f Mon Sep 17 00:00:00 2001 From: lordee Date: Fri, 8 Jan 2021 22:51:15 +1100 Subject: [PATCH 1178/2474] ensure we haven't reassigned targ --- ssqc/sentry.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 726abebc..c2649db8 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -270,7 +270,7 @@ float () FO_Sentry_FindTarget = { } vector spot1 = self.origin + self.view_ofs; - vector spot2 = targ.origin + targ.view_ofs; + vector spot2 = self.enemy.origin + self.enemy.view_ofs; float r = vlen(spot1 - spot2); float delay = 0.25; From ddc0edf66bdd4ef58590935d078435fe7986fb5e Mon Sep 17 00:00:00 2001 From: lordee Date: Fri, 8 Jan 2021 22:52:24 +1100 Subject: [PATCH 1179/2474] increment version --- ssqc/commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 3975a8b0..d80a6d02 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -314,7 +314,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { case "progsversion": - sprint(self, PRINT_HIGH, "sv progs version: 0.1\n"); + sprint(self, PRINT_HIGH, "sv progs version: 0.2\n"); break; case "adminpwd": processedCmd = TRUE; From e7da8a8ebde3d5f341932287fbde149e3e1b6895 Mon Sep 17 00:00:00 2001 From: Fabio Ferreira Date: Fri, 8 Jan 2021 22:34:28 -0300 Subject: [PATCH 1180/2474] fixing being stuck while building sentry and doing something else --- ssqc/tfort.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 62554d05..7ba4be76 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1179,7 +1179,7 @@ void (entity p) TeamFortress_SetSpeed = { local entity te; stuffcmd(p, "cl_movespeedkey 1\n"); - if (p.tfstate & TFSTATE_CANT_MOVE || p.is_building == 1 || p.is_detpacking > 0) { + if (p.tfstate & TFSTATE_CANT_MOVE || (p.is_building == 1 && !engineer_move) || p.is_detpacking > 0) { #ifdef STOP_MOUSE_MOVEMENT stuffcmd(p, "m_forward 0\n"); stuffcmd(p, "m_side 0\n"); From e500a5126756ce7a79dadb8a3252f741b3906caa Mon Sep 17 00:00:00 2001 From: me Date: Wed, 13 Jan 2021 21:10:56 +1300 Subject: [PATCH 1181/2474] fix eng cell updates on build --- ssqc/engineer.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index ac8f3cf8..3671e47e 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -575,6 +575,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.classname = "building_sentrygun"; newmis.weapon = 0; } + W_SetCurrentAmmo(self); } oldmis = newmis; @@ -1489,4 +1490,4 @@ void (entity eng) Engineer_RemoveBuildings = { void () info_empblock = { self.weapon = 512; self.netname = "EMP Block"; -}; \ No newline at end of file +}; From 0a76ce8b4bae5804a56314329afbe1f5abb8aeba Mon Sep 17 00:00:00 2001 From: lordee Date: Wed, 13 Jan 2021 22:25:38 +1100 Subject: [PATCH 1182/2474] embarassing fix for sentry lock on --- ssqc/commands.qc | 2 +- ssqc/sentry.qc | 37 +++++++++++-------------------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index d80a6d02..e2acdda9 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -314,7 +314,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { case "progsversion": - sprint(self, PRINT_HIGH, "sv progs version: 0.2\n"); + sprint(self, PRINT_HIGH, "sv progs version: 0.3\n"); break; case "adminpwd": processedCmd = TRUE; diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index c2649db8..3571bc1b 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -172,6 +172,9 @@ float () Sentry_FindTarget = { float (entity p) FO_Sentry_ValidTarget = { float valid = TRUE; + if (!p) + return FALSE; + if ((p == self.real_owner) || !p.takedamage) valid = FALSE; if (p.has_disconnected == 1) @@ -201,33 +204,19 @@ float (entity p) FO_Sentry_ValidTarget = { return valid; }; -void () FO_Sentry_Timer_Think = { - entity oself = self; - oself.nextthink = time + 0.01; - oself.cnt2 = oself.cnt2 + 0.01; // rotate speed - self = self.owner; - +float () FO_Sentry_FindTarget = { + + // check for current valid target if (FO_Sentry_ValidTarget(self.enemy)) { - if (oself.cnt2 >= 0.1) - { - ai_face(); - oself.cnt2 = 0; - } - - if (oself.cnt <= time) + if (self.cnt <= time) { Sentry_FoundTarget(); - dremove(oself); + return TRUE; } + return FALSE; } - else - { - dremove(oself); // lose tracking when people duck behind walls - } -}; -float () FO_Sentry_FindTarget = { entity p = find(world, classname, "player"); float foundTarg = FALSE; float dist = -1; @@ -278,12 +267,8 @@ float () FO_Sentry_FindTarget = { { delay = 0.45; } - // attack delay - entity timer = spawn(); - timer.owner = self; - timer.think = FO_Sentry_Timer_Think; - timer.cnt = time + delay; // delay - timer.nextthink = time + 0.01; + + self.cnt = time + delay; // delay return TRUE; }; From d1f5e2661b6f58a0c13504668d7910beaf7b80e5 Mon Sep 17 00:00:00 2001 From: lordee Date: Wed, 13 Jan 2021 22:32:40 +1100 Subject: [PATCH 1183/2474] whoops, we buffed healing instead of nerfing --- ssqc/engineer.qc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index d09cf1da..a30c1008 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1211,17 +1211,19 @@ void (entity disp) Engineer_Dispenser_InsertArmor = { }; void (entity disp) Engineer_Dispenser_Repair = { - local float metalcost, healamount; + local float metalcost, healamount, ratio; if (disp.health == disp.max_health) return; - metalcost = ceil((disp.max_health - disp.health) / 5); + ratio = (fo_repair_ratio == 0 ? 5 : fo_repair_ratio); + + metalcost = ceil((disp.max_health - disp.health) / ratio); if (metalcost > self.ammo_cells) metalcost = self.ammo_cells; self.ammo_cells = self.ammo_cells - metalcost; - healamount = floor(metalcost * 5); + healamount = floor(metalcost * ratio); disp.health = disp.health + healamount; if (metalcost > 0) { @@ -1385,14 +1387,16 @@ void (entity gun) Engineer_SentryGun_Upgrade = { }; void (entity gun) Engineer_SentryGun_Repair = { - local float metalcost, healamount; + local float metalcost, healamount, ratio; + + ratio = (fo_repair_ratio == 0 ? 5 : fo_repair_ratio); - metalcost = ceil((gun.max_health - gun.health) / (fo_repair_ratio == 0 ? 5 : fo_repair_ratio)); + metalcost = ceil((gun.max_health - gun.health) / ratio); if (metalcost > self.ammo_cells) metalcost = self.ammo_cells; self.ammo_cells = self.ammo_cells - metalcost; - healamount = floor(metalcost * 5); + healamount = floor(metalcost * ratio); gun.health = gun.health + healamount; if (gun.health > gun.max_health) From 4a66da653865107d35c8f92fe18c2114316e6a67 Mon Sep 17 00:00:00 2001 From: me Date: Thu, 14 Jan 2021 11:31:05 +1300 Subject: [PATCH 1184/2474] fix #537 - dropammo menu --- csqc/events.qc | 5 +--- csqc/menu.qc | 75 ++++++++++++++++++++++++++++++++++---------------- ssqc/client.qc | 3 +- ssqc/csmenu.qc | 4 +-- ssqc/menu.qc | 27 ++---------------- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 36c722f2..339012dc 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -131,10 +131,7 @@ void() CSQC_Parse_Event = { FO_Menu_Class(2); break; case CLIENT_MENU_DROPAMMO: - float ammotypes = readfloat(); - float ammomakes = readfloat(); - - FO_Menu_DropAmmo(FALSE, ammotypes, ammomakes); + FO_Menu_DropAmmo(FALSE); break; case CLIENT_MENU_SCOUT: float scanner_on = readbyte(); diff --git a/csqc/menu.qc b/csqc/menu.qc index 3cff9d0f..deaaf784 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -942,39 +942,68 @@ void FO_Menu_Class(float force) = { fo_hud_menu_active = TRUE; } -void FO_Menu_DropAmmo(float force, float ammotypes, float ammomakes) { +void FO_Menu_DropAmmo(float force) { if(fo_hud_menu_active && CurrentMenu == &FO_MENU_DROPAMMO) { Menu_Cancel(); return; } if(fo_hud_menu_active && !force) return; - if(!ammotypes) { - Menu_Cancel(); + + float available = 0; + FO_MENU_DROPAMMO.options[0].value = ""; + if(getstatf(STAT_SHELLS) < DROP_SHELLS) { + FO_MENU_DROPAMMO.options[0].state = FO_MENU_STATE_DISABLED; + } else { + FO_MENU_DROPAMMO.options[0].state = FO_MENU_STATE_NORMAL; + available++; + } + FO_MENU_DROPAMMO.options[1].value = ""; + if(getstatf(STAT_NAILS) < DROP_NAILS) { + FO_MENU_DROPAMMO.options[1].state = FO_MENU_STATE_DISABLED; + } else { + FO_MENU_DROPAMMO.options[1].state = FO_MENU_STATE_NORMAL; + available++; + } + FO_MENU_DROPAMMO.options[2].value = ""; + if(getstatf(STAT_ROCKETS) < DROP_ROCKETS) { + FO_MENU_DROPAMMO.options[2].state = FO_MENU_STATE_DISABLED; + } else { + FO_MENU_DROPAMMO.options[2].state = FO_MENU_STATE_NORMAL; + available++; + } + FO_MENU_DROPAMMO.options[3].value = ""; + if(getstatf(STAT_CELLS) < DROP_CELLS) { + FO_MENU_DROPAMMO.options[3].state = FO_MENU_STATE_DISABLED; + } else { + FO_MENU_DROPAMMO.options[3].state = FO_MENU_STATE_NORMAL; + available++; + } + if(!available) { + if(fo_hud_menu_active && CurrentMenu == &FO_MENU_DROPAMMO) { + Menu_Cancel(); + } else { + print("Not enough ammo\n"); + } + return; } - if(ammomakes) { + if (player_class == PC_ENGINEER) { FO_MENU_DROPAMMO.title = "Drop or Make Ammo"; + if ((getstatf(STAT_SHELLS) < DROP_SHELLS) && ((getstatf(STAT_CELLS) / AMMO_COST_SHELLS) > (DROP_SHELLS - getstatf(STAT_SHELLS)))) { + FO_MENU_DROPAMMO.options[0].value = "(make)"; + FO_MENU_DROPAMMO.options[0].state = FO_MENU_STATE_NORMAL; + } + if ((getstatf(STAT_NAILS) < DROP_NAILS) && ((getstatf(STAT_CELLS) / AMMO_COST_NAILS) > (DROP_NAILS - getstatf(STAT_NAILS)))) { + FO_MENU_DROPAMMO.options[1].value = "(make)"; + FO_MENU_DROPAMMO.options[1].state = FO_MENU_STATE_NORMAL; + } + if ((getstatf(STAT_ROCKETS) < DROP_ROCKETS) && ((getstatf(STAT_CELLS) / AMMO_COST_ROCKETS) > (DROP_ROCKETS - getstatf(STAT_ROCKETS)))) { + FO_MENU_DROPAMMO.options[2].value = "(make)"; + FO_MENU_DROPAMMO.options[2].state = FO_MENU_STATE_NORMAL; + } } else { FO_MENU_DROPAMMO.title = "Drop Ammo"; } - for(float i = 0; i < 4; i++) { - if(ammotypes & pow(2,i)) { - FO_MENU_DROPAMMO.options[i].state = FO_MENU_STATE_NORMAL; - } else { - if(ammomakes & pow(2,i)) { - FO_MENU_DROPAMMO.options[i].value = "(make)"; - FO_MENU_DROPAMMO.options[i].state = FO_MENU_STATE_NORMAL; - } else { - FO_MENU_DROPAMMO.options[i].value = ""; - FO_MENU_DROPAMMO.options[i].state = FO_MENU_STATE_DISABLED; - } - } - if(ammomakes & pow(2,i)) { - FO_MENU_DROPAMMO.options[i].value = "(make)"; - } else { - FO_MENU_DROPAMMO.options[i].value = ""; - } - } CurrentMenu = &FO_MENU_DROPAMMO; fo_hud_menu_active = TRUE; @@ -1283,4 +1312,4 @@ void (float show) showVoteMenu = { if(show) { CurrentMenu = &FO_MENU_VOTE; } -}; \ No newline at end of file +}; diff --git a/ssqc/client.qc b/ssqc/client.qc index 47d0b573..4cb59354 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1985,6 +1985,7 @@ void () PutClientInServer = { if (self.playerclass == 0 && self.team_no > 0) { Menu_Class(0); } + }; //void () info_player_start = { @@ -2366,7 +2367,6 @@ void () PlayerPreThink = { if (self.cheat_level > 0) { self.cheat_level = self.cheat_level - 1; } - if (intermission_running) { IntermissionThink(); return; @@ -2749,7 +2749,6 @@ void (optional float csqcactive) ClientConnect = { UpdateClientTeamScores(self); //if(quadmode) UpdateClientPrematch(self, !cb_prematch); - UpdateClient_VoteMap_AddAll(self); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 8893f53e..933178b5 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -50,15 +50,13 @@ void UpdateClientMenu_Class(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -void UpdateClientMenu_DropAmmo(entity pl, float ammotypes, float ammomakes) = { +void UpdateClientMenu_DropAmmo(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); WriteFloat(MSG_MULTICAST, CLIENT_MENU_DROPAMMO); - WriteFloat(MSG_MULTICAST, ammotypes); - WriteFloat(MSG_MULTICAST, ammomakes); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 660ae32c..6011ca5b 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -107,7 +107,7 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; void (entity pl) UpdateClientMenu_Team; void (entity pl, float team) UpdateClientClasses; void (entity pl) UpdateClientMenu_Class; -void (entity pl, float ammotypes, float ammomakes) UpdateClientMenu_DropAmmo; +void (entity pl) UpdateClientMenu_DropAmmo; void (entity pl) UpdateClientMenu_Scout; void (entity pl) UpdateClientMenu_Spy; void (entity pl) UpdateClientMenu_Spy_Skin; @@ -470,32 +470,9 @@ void () Menu_Drop = { if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { //fte+csqc has its own team menu //ask the client to activate it - float ammotypes = (1 | 2 | 4 | 8), ammomakes = 0; - if (self.ammo_shells < DROP_SHELLS) - ammotypes -= 1; - if (self.ammo_nails < DROP_NAILS) - ammotypes -= 2; - if (self.ammo_rockets < DROP_ROCKETS) - ammotypes -= 4; - if (self.ammo_cells < DROP_CELLS) - ammotypes -= 8; - - if (self.playerclass == PC_ENGINEER) { - ammomakes = 0; - if ((self.ammo_shells < DROP_SHELLS) && ((self.ammo_cells / AMMO_COST_SHELLS) >= (DROP_SHELLS - self.ammo_shells))) - ammomakes += 1; - if ((self.ammo_nails < DROP_NAILS) && ((self.ammo_cells / AMMO_COST_NAILS) >= (DROP_NAILS - self.ammo_nails))) - ammomakes += 2; - if ((self.ammo_rockets < DROP_ROCKETS) && ((self.ammo_cells / AMMO_COST_ROCKETS) >= (DROP_ROCKETS - self.ammo_rockets))) - ammomakes += 4; - } Menu_Close(self); - if(ammotypes) { - UpdateClientMenu_DropAmmo(self, ammotypes, ammomakes); - } else { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - } + UpdateClientMenu_DropAmmo(self); return; } From ae6561cc8d2be33eb431c4dbe292c4a6a285d80d Mon Sep 17 00:00:00 2001 From: me Date: Tue, 19 Jan 2021 17:29:41 +1300 Subject: [PATCH 1185/2474] prevent server crash on timer_goal scoring --- ssqc/events.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ssqc/events.qc b/ssqc/events.qc index 0c0f619c..d2e7c761 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -398,6 +398,8 @@ void (entity attacker, entity target, float tfstate) LogEventAffliction = { }; void (entity player) LogEventGoal = { + if(player == world) + return; player.caps = player.caps + 1; if (canlog == 0) return; @@ -511,4 +513,4 @@ void () LogEventTeamScores = { local string event; event = sprintf(",\n{\"type\": \"teamScores\", %s, %s, \"winningTeam\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", teamscores, teamnames, ftos(winning_team), ftos(gametime), gametimestamp); logevent(event); -} \ No newline at end of file +} From 2b76549a9b04c8bc0ae6e85089791a634cd08da6 Mon Sep 17 00:00:00 2001 From: me Date: Wed, 20 Jan 2021 10:45:46 +1300 Subject: [PATCH 1186/2474] fix returns for undroppable flags (blcit, steal4d etc) --- share/defs.h | 3 +++ ssqc/tfortmap.qc | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/share/defs.h b/share/defs.h index 5466b047..2bf48b72 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1207,6 +1207,9 @@ #define TFGI_KEEP 256 // Players keep this item even when they die #define TFGI_ITEMGLOWS 512 // Item glows when on the ground #define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed +#define TFGI_DROPTOFLOOR 2048 // If this bit is set, the GoalItem drops to the ground when it first spawns. +#define TFGI_ALLOWTHROW 4096 // Item can be thrown with 'dropitems' command +#define TFGI_SOLID 8192 // Item is solid // Defines for TeamSpawnpoints : goal_activation (in team spawns) #define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index ee8d881f..d9e1daf7 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2614,6 +2614,9 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { Item.think = tfgoalitem_dropthink; Item.bubble_count = time + Item.pausetime + 5; //used by the return timer } + if (Item.goal_activation & TFGI_RETURN_DROP) { + Item.think = tfgoalitem_remove; + } Item.owner = world; }; @@ -2623,7 +2626,7 @@ void () tfgoalitem_remove = { if (self.goal_state == 1) { return; } - if (self.goal_activation & 32) { + if (self.goal_activation & 32 || self.goal_activation & TFGI_RETURN_DROP) { te = spawn(); te.enemy = self; te.weapon = 3; @@ -2961,12 +2964,15 @@ void () DropGoalItems = { while (te) { if (te.owner == self) { if (old_dropflag) { - if (te.goal_activation & 4096) { + if (te.goal_activation & TFGI_ALLOWTHROW) { tfgoalitem_RemoveFromPlayer(te, self, 2); } } + else if(te.goal_activation & TFGI_RETURN_DROP) { + tfgoalitem_RemoveFromPlayer(te, self, 0); + } //Always allow dropping 4096 - else if (self.effects & EF_DIMLIGHT || te.goal_activation & 4096) { + else if (self.effects & EF_DIMLIGHT || te.goal_activation & TFGI_ALLOWTHROW) { timecarried = gametime - self.goalrunningtime; RemoveFlagFollow(self); LogEventFumble(self, timecarried); From c57acd5b74e277f09d647db8f5be3a0546b59d2a Mon Sep 17 00:00:00 2001 From: lordee Date: Sun, 24 Jan 2021 13:20:50 +1100 Subject: [PATCH 1187/2474] better explanation --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 5466b047..c76d0b05 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1432,7 +1432,7 @@ // trigger_push #define PUSH_ONCE 1 #define PUSH_INCLUDETFITEM 2 -#define PUSH_EXCLUDEOTHER 4 // bad names, bad bits, bad coder +#define PUSH_EXCLUDEOTHER 4 // bad names, bad bits, bad coder - use in conjunction with includetfitem to exclude all but tfitem #define PUSH_NONOISE 8 #define PUSH_MEGAJUMPER 16 From 96f556149d8f71932b732f6bdb6ea7643e54b287 Mon Sep 17 00:00:00 2001 From: lordee Date: Sun, 24 Jan 2021 22:53:26 +1100 Subject: [PATCH 1188/2474] on quad round change, active all entities with targetname of "fo_roundchange" --- ssqc/quadmode.qc | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index b41f3c6d..83e2c21a 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -35,7 +35,24 @@ float () CheckWinningTeam = { return winning_team; }; +void () FO_RoundChange = { + entity e = find(world, targetname, "fo_roundchange"); + + while (e) + { + // activate + self = e; + self.use(); + SUB_UseTargets(); + e = find(e, targetname, "fo_roundchange"); + } +}; + void () QuadRoundOver = { + if (rounds != 1) + { + FO_RoundChange(); + } round_over = 2; self.think = StartQuadRound; self.nextthink = (time + 0.5); @@ -452,7 +469,7 @@ void () StartQuadRound = void () EndQuadRound = { if (infokey(world, "quadmode") == "on") { if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { - if (rounds > 1) { + if (rounds > 1) { local string st; st = ftos(round_delay_time); bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); @@ -466,3 +483,4 @@ void () EndQuadRound = { } } }; + From a44d9cee66bb6219036144511e0b37ac394d3c07 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 25 Jan 2021 21:40:09 +1100 Subject: [PATCH 1189/2474] trigger_push spawnflag to ignore grenades --- share/defs.h | 14 ++++++++++++++ ssqc/triggers.qc | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/share/defs.h b/share/defs.h index c2165673..ccfe87ac 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1430,7 +1430,12 @@ // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this +// all bits between 1 and 255 are reserved for flash #define DMN_NOFLASH 256 // see all the things +#define DMN_TEAMBLUE 512 +#define DMN_TEAMRED 1024 +#define DMN_TEAMYELL 2048 +#define DMN_TEAMGREN 4096 // trigger_push #define PUSH_ONCE 1 @@ -1438,4 +1443,13 @@ #define PUSH_EXCLUDEOTHER 4 // bad names, bad bits, bad coder - use in conjunction with includetfitem to exclude all but tfitem #define PUSH_NONOISE 8 #define PUSH_MEGAJUMPER 16 +#define PUSH_EXCLUDEGRENADE 32 +// func_wall +#define WALL_SOLID_NOT 1 + +// teams +#define TEAM_BLUE 1 +#define TEAM_RED 2 +#define TEAM_YELL 3 +#define TEAM_GREN 4 \ No newline at end of file diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 9cd6b2b6..4e2ed989 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -558,6 +558,10 @@ void () trigger_push_touch = { { return; } + else if ((self.spawnflags & PUSH_EXCLUDEGRENADE) && other.classname == "grenade") + { + return; + } else { if (other.classname == "grenade" || other.health > 0) From 34245de65aca78c42e8ae26beeef4ed49fd11ad3 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 25 Jan 2021 21:42:34 +1100 Subject: [PATCH 1190/2474] dimensions for team_no on func_wall, to make walls only be seen by team_no set, spawnflags to allow non solid func_wall --- ssqc/client.qc | 29 +++++++++++++++++++++++++++-- ssqc/misc.qc | 29 +++++++++++++++++++++++++++-- ssqc/scout.qc | 6 ++---- ssqc/spect.qc | 4 +--- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index b3178b56..7f8641a8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1762,6 +1762,32 @@ void (entity player) UpdateScoreboardInfo = { CheckSetInfoKey(player, "ready", player.is_ready); }; +void (float all_dimensions) SetDimensions = { + if (all_dimensions) + { + self.dimension_seen = DMN_NOFLASH; + + switch (self.team_no) + { + case TEAM_BLUE: + self.dimension_see = DMN_NOFLASH | DMN_TEAMBLUE; + break; + case TEAM_RED: + self.dimension_see = DMN_NOFLASH | DMN_TEAMRED; + break; + case TEAM_YELL: + self.dimension_see = DMN_NOFLASH | DMN_TEAMYELL; + break; + case TEAM_GREN: + self.dimension_see = DMN_NOFLASH | DMN_TEAMGREN; + break; + default: + self.dimension_see = DMN_NOFLASH; + break; + } + } +}; + void () PutClientInServer = { local float oldclass; local entity spot; @@ -1803,8 +1829,7 @@ void () PutClientInServer = { self.immune_to_check = time + 10; self.fire_held_down = 0; - self.dimension_see = DMN_NOFLASH; - self.dimension_seen = DMN_NOFLASH - (DMN_NOFLASH & DMN_FLASH); + SetDimensions(TRUE); self.special_cooldown = 0; setmodel(self, string_null); diff --git a/ssqc/misc.qc b/ssqc/misc.qc index f8c7c557..726b3150 100644 --- a/ssqc/misc.qc +++ b/ssqc/misc.qc @@ -467,8 +467,33 @@ void () func_wall = { } self.angles = '0 0 0'; self.movetype = MOVETYPE_PUSH; - self.solid = SOLID_BSP; - self.use = func_wall_use; + self.use = func_wall_use; + + if (self.spawnflags & WALL_SOLID_NOT) + { + self.solid = SOLID_NOT; + } + else + { + self.solid = SOLID_BSP; + } + switch (self.team_no) + { + case TEAM_BLUE: + self.dimension_seen = DMN_TEAMBLUE; + break; + case TEAM_RED: + self.dimension_seen = DMN_TEAMRED; + break; + case TEAM_YELL: + self.dimension_seen = DMN_TEAMYELL; + break; + case TEAM_GREN: + self.dimension_seen = DMN_TEAMGREN; + break; + default: + break; + } setmodel(self, self.model); }; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index f386cc11..80cb0dbb 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -151,8 +151,7 @@ void () FlashTimer = { te.FlashTime = 1; stuffcmd(te, "v_cshift; wait; bf\n"); remove(self); - te.dimension_see = DMN_NOFLASH; - te.dimension_seen = DMN_NOFLASH; + SetDimensions(TRUE); return; } @@ -191,8 +190,7 @@ void FO_FlashTimer() sprint(te, PRINT_HIGH, "Flash has worn off\n"); stuffcmd(te, "v_cshift; wait; bf\n"); remove(self); - te.dimension_see = DMN_NOFLASH; - te.dimension_seen = DMN_NOFLASH; + SetDimensions(TRUE); return; } diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 4ceef067..e229cc36 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -15,9 +15,7 @@ void () SpectatorThink; void () Admin_Aliases; void () SpectatorConnect = { - - self.dimension_see = DMN_NOFLASH; - self.dimension_seen = DMN_NOFLASH; + SetDimensions(TRUE); local string st; From a259761874e37f6abd3e87c28e8e154b505fe5dd Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Tue, 26 Jan 2021 22:40:50 +1300 Subject: [PATCH 1191/2474] buttons don't crash server if don't have target --- ssqc/buttons.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/buttons.qc b/ssqc/buttons.qc index 93435c9d..bacf0813 100644 --- a/ssqc/buttons.qc +++ b/ssqc/buttons.qc @@ -25,7 +25,7 @@ void () button_return = { targ = world; targname = self.target; targ = find(targ, targetname, targname); - targ.active = TFGS_INACTIVE; + if(targ) targ.active = TFGS_INACTIVE; self.goal_state = TFGS_INACTIVE; self.state = STATE_DOWN; @@ -49,7 +49,7 @@ void () button_fire = { targ = world; targname = self.target; targ = find(targ, targetname, targname); - targ.active = TFGS_ACTIVE; + if(targ) targ.active = TFGS_ACTIVE; FO_Sound(self, CHAN_VOICE, self.noise, 1, ATTN_NORM); From 771f1cdc3a8f4b33039e3000a5b11b528e96fdc7 Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 26 Jan 2021 21:07:21 +1100 Subject: [PATCH 1192/2474] remove centerprint from hidden touch --- ssqc/roles.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/roles.qc b/ssqc/roles.qc index 431a8dbf..565316e6 100644 --- a/ssqc/roles.qc +++ b/ssqc/roles.qc @@ -135,11 +135,11 @@ void () item_tfgoal_hidden_touch = { if (trace_fraction < 1) return; - if(self.owned_by == other.team_no) { + /*if(self.owned_by == other.team_no) { CenterPrint(other, "Unfortunately, your flag is in another castle\n\nYou are Attacking the other base\n"); } else { CenterPrint(other, "You are defending the wrong flag!\n\nGet back to your base quickly\n"); - } + }*/ } void Quad_HideFlag(entity flag) = { From ef3f98f0815e3b5bec27e861731d14cbe7832d79 Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 26 Jan 2021 21:07:34 +1100 Subject: [PATCH 1193/2474] add switch team_no group_no field --- ssqc/qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 0cd027cf..2e171db9 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -271,6 +271,7 @@ float coop; .float inactivate_group_no; .float remove_group_no; .float restore_group_no; +.float switch_team_group_no; .vector goal_min; .vector goal_max; From ccdd27c7693151cfd1fe9915a30fa32d3a458950 Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 26 Jan 2021 21:07:53 +1100 Subject: [PATCH 1194/2474] increment version response --- ssqc/commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index e2acdda9..e654c248 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -314,7 +314,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { case "progsversion": - sprint(self, PRINT_HIGH, "sv progs version: 0.3\n"); + sprint(self, PRINT_HIGH, "sv progs version: 0.4\n"); break; case "adminpwd": processedCmd = TRUE; From f93e202f3325c002657d9570e6d6b6f34465b5aa Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 26 Jan 2021 21:33:40 +1100 Subject: [PATCH 1195/2474] allow door triggers to have fields modified based on group_no --- ssqc/doors.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/doors.qc b/ssqc/doors.qc index 98f5e986..4703b71b 100644 --- a/ssqc/doors.qc +++ b/ssqc/doors.qc @@ -242,6 +242,7 @@ entity(vector fmins, vector fmaxs) spawn_field = trigger.all_active = self.all_active; trigger.last_impulse = self.last_impulse; trigger.else_goal = self.else_goal; + trigger.group_no = self.group_no; t1 = fmins; t2 = fmaxs; setsize(trigger, t1 - '60 60 8', t2 + '60 60 8'); From ddf1c66d2bd504bd295c911163286735d16d4eca Mon Sep 17 00:00:00 2001 From: lordee Date: Wed, 27 Jan 2021 13:31:21 +1100 Subject: [PATCH 1196/2474] fix team not being set on player for first spawn of the game, messing up dimensions in putclientinserver. Add dimensions to team set function instead. --- ssqc/tforttm.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 300a75b1..e7b2d409 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -293,6 +293,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options float (float tno) TeamFortress_TeamSet = { local float tftso = TeamFortress_TeamSet_Options(self, tno, FALSE); + SetDimensions(TRUE); UpdateAllClientsTeamScores(); return (tftso); } From 39667415145851cb5db079c15d0095be09c4fd02 Mon Sep 17 00:00:00 2001 From: lordee Date: Thu, 28 Jan 2021 00:45:06 +1100 Subject: [PATCH 1197/2474] support for entity execution on round change --- docs/tfentref.txt | 7 ++- share/defs.h | 3 + ssqc/misc.qc | 19 +++++- ssqc/quadmode.qc | 145 ++++++++++++++++++++++++++++++++++++++-------- ssqc/tfortmap.qc | 11 +++- 5 files changed, 157 insertions(+), 28 deletions(-) diff --git a/docs/tfentref.txt b/docs/tfentref.txt index 5324aec0..c36e10e3 100644 --- a/docs/tfentref.txt +++ b/docs/tfentref.txt @@ -346,8 +346,8 @@ playerclass AP must be this playerclass to meet this Goal's criteria 9 : Only allow an Engineer to activate spawnflags 1 : By default, when a GoalItem has a .mdl set, it will glow based on team_no. - This spawnflag will stop that glow. - + This spawnflag will stop that glow. (TFGI_NOGLOW) + 2 : Allow this goal to work even in clan battle/quadmode prematch (TFGI_CB_IGNORE) if_goal_is_active This Goal must be in ACTIVE state. if_goal_is_inactive This Goal must be in INACTIVE state. if_goal_is_removed This Goal must be in REMOVED state. @@ -1224,6 +1224,9 @@ trigger_push 4 : exclude "other" (So only TFItems are affected) 8 : "no noise" make sure no default noise is added +func_wall + spawnflags: 1 : make wall non solid + 2 : WALL_HIDE_ON_USE trigger_jumppad Rename of trigger_push, can be used to allow for "Fortress One" only trigger_push entities that won't be misinterpreted by other fortress mods diff --git a/share/defs.h b/share/defs.h index ccfe87ac..1828ffdc 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1239,6 +1239,7 @@ // spawnflags #define TFGI_NOGLOW 1 // stop the automatic glow applied in fortressone to goals with a .mdl set based on team +#define TFGI_CB_IGNORE 2 // Allow this goal to work even in clan battle/quadmode prematch /*======================================================================*/ /* Flamethrower */ @@ -1436,6 +1437,7 @@ #define DMN_TEAMRED 1024 #define DMN_TEAMYELL 2048 #define DMN_TEAMGREN 4096 +#define DMN_INVISIBLE 8192 // special dimension to hide stuff in // trigger_push #define PUSH_ONCE 1 @@ -1447,6 +1449,7 @@ // func_wall #define WALL_SOLID_NOT 1 +#define WALL_HIDE_ON_USE 2 // teams #define TEAM_BLUE 1 diff --git a/ssqc/misc.qc b/ssqc/misc.qc index 726b3150..10f1b5b7 100644 --- a/ssqc/misc.qc +++ b/ssqc/misc.qc @@ -457,7 +457,21 @@ void () viewthing = { }; void () func_wall_use = { - self.frame = (1 - self.frame); + if (self.spawnflags & WALL_HIDE_ON_USE) + { + if (self.cnt == self.dimension_seen) + { + self.dimension_seen = DMN_INVISIBLE; + } + else + { + self.dimension_seen = self.cnt; + } + } + else + { + self.frame = (1 - self.frame); + } }; void () func_wall = { @@ -494,7 +508,10 @@ void () func_wall = { default: break; } + self.cnt = self.dimension_seen; + setmodel(self, self.model); + self.mdl = self.model; }; void () func_illusionary = { diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 83e2c21a..a020c51a 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -1,4 +1,4 @@ -//=-=-=-=-= +void () info_player_teamspawn; float () CheckWinningTeam = { local float win_score = 0; @@ -35,25 +35,135 @@ float () CheckWinningTeam = { return winning_team; }; +void (entity te) Quad_HideFlags = { + if(rounds % 2) { + if(te.team_no == 2 && te.owned_by == 1) { + Quad_UnHideFlag(te); + } else if(te.team_no == 1 && te.owned_by == 2) { + Quad_HideFlag(te); + } + } else { + if(te.team_no == 2 && te.owned_by == 1) { + Quad_HideFlag(te); + } else if(te.team_no == 1 && te.owned_by == 2) { + Quad_UnHideFlag(te); + } + } +}; + void () FO_RoundChange = { entity e = find(world, targetname, "fo_roundchange"); - + entity oldself = self; while (e) { // activate self = e; - self.use(); - SUB_UseTargets(); + entity c; + // initial round, hide the restore items + if (rounds == CF_GetSetting("rounds","rounds","on")) + { + if (e.restore_group_no) + { + c = findfloat(world, group_no, e.restore_group_no); + while (c) + { + switch (c.classname) + { + case "item_tfgoal": + Quad_HideFlag(c); + break; + } + c = findfloat(c, group_no, e.restore_group_no); + } + } + } + else + { + self.use(); + //SUB_UseTargets(); + + // TF state of removed seems to be broken and ignored all + // throughout the codebase, so we will do the same + if (e.remove_group_no) + { + c = findfloat(world, group_no, e.remove_group_no); + while (c) + { + switch (c.classname) + { + case "item_tfgoal": + Quad_HideFlag(c); + break; + } + c = findfloat(c, group_no, e.remove_group_no); + } + } + + if (e.restore_group_no) + { + c = findfloat(world, group_no, e.restore_group_no); + while (c) + { + switch (c.classname) + { + case "item_tfgoal": + Quad_UnHideFlag(c); + break; + } + c = findfloat(c, group_no, e.restore_group_no); + } + } + + if (e.switch_team_group_no) + { + c = findfloat(world, group_no, e.switch_team_group_no); + while (c) + { + // this could be abused..? + if (c.group_no == e.switch_team_group_no) + { + switch (c.team_no) + { + // need another field to denote swaps + case TEAM_BLUE: + c.team_no = TEAM_RED; + break; + case TEAM_RED: + c.team_no = TEAM_BLUE; + break; + case TEAM_YELL: + c.team_no = TEAM_GREN; + break; + case TEAM_GREN: + c.team_no = TEAM_YELL; + break; + } + + switch (c.classname) + { + case "func_wall": + self = c; + func_wall(); + break; + case "info_player_teamspawn": + self = c; + info_player_teamspawn(); + break; + } + } + c = findfloat(c, group_no, e.switch_team_group_no); + } + } + } + e = find(e, targetname, "fo_roundchange"); } + self = oldself; }; void () QuadRoundOver = { - if (rounds != 1) - { - FO_RoundChange(); - } round_over = 2; + self.think = StartQuadRound; self.nextthink = (time + 0.5); }; @@ -114,9 +224,6 @@ void () QuadRoundThink = { bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); } - -// lightstyle (0, "e"); - self.think = QuadRoundOver; self.nextthink = (time + 0.1); return; @@ -169,23 +276,13 @@ void () QuadRoundBegin = { } te = find(world, classname, "item_tfgoal"); while (te) { - if(rounds % 2) { - if(te.team_no == 2 && te.owned_by == 1) { - Quad_UnHideFlag(te); - } else if(te.team_no == 1 && te.owned_by == 2) { - Quad_HideFlag(te); - } - } else { - if(te.team_no == 2 && te.owned_by == 1) { - Quad_HideFlag(te); - } else if(te.team_no == 1 && te.owned_by == 2) { - Quad_UnHideFlag(te); - } - } + Quad_HideFlags(te); te = find(te, classname, "item_tfgoal"); } } + FO_RoundChange(); + te = find(world, classname, "player"); while (te != world) { oldself = self; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index d9e1daf7..1e6b2ad2 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1774,7 +1774,7 @@ void (entity Goal, entity AP, float addb) DoResults = { local float winners; local float gotone; - if (cb_prematch) { + if (cb_prematch && !(Goal.spawnflags & TFGI_CB_IGNORE)) { return; } if (Goal.goal_state == 1) { @@ -2116,8 +2116,17 @@ void () info_tfgoal_use = { void () tfgoal_timer_tick = { if (self.goal_state != 3) { if (APMeetsCriteria(self, world)) + { + //bprint(PRINT_HIGH, "meets criteria, doing results\n"); DoResults(self, world, 1); + + // redo think here too, as quadmode breaks proper timers + // in DoResults due to return after cb_prematch test + self.think = tfgoal_timer_tick; + self.nextthink = time + self.search_time; + } else { + bprint(PRINT_HIGH, "inactivating timer\n"); InactivateGoal(self); self.think = tfgoal_timer_tick; self.nextthink = time + self.search_time; From 93a59f5e9d8f49ebf172f20f021506949966f819 Mon Sep 17 00:00:00 2001 From: lordee Date: Thu, 28 Jan 2021 14:44:39 +1100 Subject: [PATCH 1198/2474] fix flash effect not wearing off --- ssqc/scout.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 80cb0dbb..8308515f 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -190,6 +190,7 @@ void FO_FlashTimer() sprint(te, PRINT_HIGH, "Flash has worn off\n"); stuffcmd(te, "v_cshift; wait; bf\n"); remove(self); + self = te; SetDimensions(TRUE); return; } From e3bd18e2f10eb484e3d82f24e5e25ed0db177219 Mon Sep 17 00:00:00 2001 From: lordee Date: Thu, 28 Jan 2021 14:45:54 +1100 Subject: [PATCH 1199/2474] increment version --- ssqc/commands.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index e654c248..5e887ddf 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -314,7 +314,8 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { case "progsversion": - sprint(self, PRINT_HIGH, "sv progs version: 0.4\n"); + // yy.mm.dd.incremented vers + sprint(self, PRINT_HIGH, "sv progs version: 20.01.28.1\n"); break; case "adminpwd": processedCmd = TRUE; From 06fd6b257846fec67b0ed7e60c6988f6a5525681 Mon Sep 17 00:00:00 2001 From: lordee Date: Thu, 28 Jan 2021 14:51:10 +1100 Subject: [PATCH 1200/2474] wrong year in version --- ssqc/commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5e887ddf..4a09b7c2 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -315,7 +315,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { { case "progsversion": // yy.mm.dd.incremented vers - sprint(self, PRINT_HIGH, "sv progs version: 20.01.28.1\n"); + sprint(self, PRINT_HIGH, "sv progs version: 21.01.28.1\n"); break; case "adminpwd": processedCmd = TRUE; From c487ca72e186706cd96c6a6725f5af5757feb17e Mon Sep 17 00:00:00 2001 From: me Date: Fri, 29 Jan 2021 11:36:27 +1300 Subject: [PATCH 1201/2474] fix changelevel triggers; add triggers for voting --- ssqc/client.qc | 47 ++++++++++++++++++++++++++--------------------- ssqc/functions.qc | 10 ++++++++-- ssqc/qw.qc | 2 ++ ssqc/vote.qc | 10 +++++++++- 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 47d0b573..222783e6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -68,8 +68,6 @@ void () InitReverseCap; float () RejoinWithTfId; void () CreateTfIdAndJoin; -string nextmap; - void () info_intermission = { if (CheckExistence() == 0) { @@ -1020,7 +1018,7 @@ void () TF_MovePlayer = { }; void () GotoNextMap = { - if (vote_result != string_null) + if (vote_result != string_null && (nextmap == string_null || nextmap == "")) nextmap = strzone(vote_result); if (nextmap != mapname || vote_result != string_null) { @@ -1108,29 +1106,36 @@ void () execute_changelevel = { WriteAngle(MSG_ALL, pos.mangle_y); WriteAngle(MSG_ALL, pos.mangle_z); - local string nextmapstring = vote_result; - local string vm = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); - vote_style = CF_GetSetting("vs", "vote_style", "2"); - if (vote_style || votemode == 2){ - if(votemode == 1 && vote_result && vote_result != vm) { - localcmd ("localinfo votemode off\n"); - //changelevel(vote_result); - } else if((vote_style == 1 && (vote_result == vm || vote_result == "")) || votemode == 2) { - vote_result = vm; - localcmd ("localinfo votemode on\n"); - //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); - } else if(vote_style == 2 && (vote_result == vm || vote_result == "")) { - vote_result = mapname; + local string nextmapstring = nextmap; + if((vote_result == string_null || vote_result == "") && (nextmap == string_null || nextmap == "")) { + local string vm = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); + vote_style = CF_GetSetting("vs", "vote_style", "2"); + if (vote_style || votemode == 2){ + if(votemode == 1 && vote_result && vote_result != vm) { + localcmd ("localinfo votemode off\n"); + //changelevel(vote_result); + } else if((vote_style == 1 && (vote_result == vm || vote_result == "")) || votemode == 2) { + vote_result = vm; + localcmd ("localinfo votemode on\n"); + //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); + } else if(vote_style == 2 && (vote_result == vm || vote_result == "")) { + vote_result = mapname; + } } + //if(!votemode) { + // vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); + // nextmapstring = strcat(vote_result, " \b(voting)\b"); + //} + } + if(vote_result != string_null && vote_result != "") { + nextmapstring = vote_result; + nextmap = vote_result; } - //if(!votemode) { - // vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); - // nextmapstring = strcat(vote_result, " \b(voting)\b"); - //} +// other = find(world, classname, "player"); while (other != world) { - if (vote_result != string_null) + if (nextmapstring != string_null && nextmapstring != "") sprint(other, PRINT_HIGH, "Next up: ", nextmapstring, "\n"); other.takedamage = DAMAGE_NO; other.solid = SOLID_NOT; diff --git a/ssqc/functions.qc b/ssqc/functions.qc index 9c1822da..536d9f53 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -132,7 +132,13 @@ void () PrintLoginMessage = { } void () EndGameThink = { - localcmd("changelevel "); + local string m = mapname; + if(vote_result != string_null && vote_result != "") { + m = vote_result; + } else if(nextmap != string_null && nextmap != "") { + m = nextmap; + } + localcmd("changelevel "); localcmd(mapname); localcmd("\n"); dremove(self); @@ -162,4 +168,4 @@ void () MapEndSequence = { maprestarttimer.netname = "maprestarttimer"; maprestarttimer.think = EndGameThink; maprestarttimer.nextthink = time + map_restart_time; -} \ No newline at end of file +} diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9dba5a57..4e20c21d 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -121,6 +121,8 @@ typedef void (float n) f_void_float; float toggleflags; // toggleable flags +string nextmap; + //float respawn_delay_time; // diff --git a/ssqc/vote.qc b/ssqc/vote.qc index aba22fbf..617e6f09 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -39,7 +39,7 @@ string (string ps_list, float pf_idx) List_Index; string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; void (entity ent) TeamFortress_SetSpeed; void FO_Sound(entity e, float chan, string samp, float vol, float atten); - +void (entity p, string vote) VoteForMap; // opens the map voting early // called from weapons.qc:ImpulseCommands() @@ -1162,10 +1162,17 @@ float (string name) RemoveVoteMap = { return FALSE; } +void() map_candidate_use = { + if(activator && activator.classname == "player") { + VoteForMap(activator, self.netname); + } +} + void() map_candidate = { if(self.team_broadcast && self.team_broadcast != "") { self.owner = AddVoteMapGroup(self.team_broadcast); } + self.use = map_candidate_use; }; void () InitVoteMaps = { @@ -1275,6 +1282,7 @@ void () EndVoting = { void (string map_name) ChangeToVotedMap = { vote_result = map_name; + nextmap = map_name; // if(!votemode) { // votemode = 2; // } From a9b107ca96ce6cb9d2fd32d1eb5760eca514080a Mon Sep 17 00:00:00 2001 From: lordee Date: Wed, 3 Feb 2021 15:01:08 +1100 Subject: [PATCH 1202/2474] if flags are hidden, don't unhide them on flag return --- ssqc/roles.qc | 4 ++-- ssqc/tfortmap.qc | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/roles.qc b/ssqc/roles.qc index 565316e6..2416b706 100644 --- a/ssqc/roles.qc +++ b/ssqc/roles.qc @@ -142,13 +142,13 @@ void () item_tfgoal_hidden_touch = { }*/ } -void Quad_HideFlag(entity flag) = { +void (entity flag) Quad_HideFlag = { flag.touch = item_tfgoal_hidden_touch; setmodel(flag, ""); setsize(flag, flag.goal_min, flag.goal_max); }; -void Quad_UnHideFlag(entity flag) = { +void (entity flag) Quad_UnHideFlag = { flag.touch = item_tfgoal_touch; setmodel(flag, flag.mdl); setsize(flag, flag.goal_min, flag.goal_max); diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 1e6b2ad2..4e4a03e1 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2329,6 +2329,9 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { void () ReturnItem = { local entity te; + if (self.enemy.touch == item_tfgoal_hidden_touch) + return; + self.enemy.goal_state = 2; if ((self.enemy.goal_activation & 8192) && (self.enemy.classname == "item_tfgoal")) From 63d9feca730a4c4c2803f082055c32ade0a77c88 Mon Sep 17 00:00:00 2001 From: me Date: Tue, 23 Feb 2021 11:18:47 +1300 Subject: [PATCH 1203/2474] fix se2 --- ssqc/commands.qc | 1 + ssqc/functions.qc | 2 +- ssqc/world.qc | 11 ++++++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 45ae0d45..5f875e9e 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1117,6 +1117,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { bprint(PRINT_HIGH, " has changed the map to "); bprint(PRINT_HIGH, arg2); bprint(PRINT_HIGH, "\n"); + nextmap = arg2; if (!clan_scores_dumped) { if (quadmode) { rounds = 1; diff --git a/ssqc/functions.qc b/ssqc/functions.qc index 536d9f53..dceb8079 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -139,7 +139,7 @@ void () EndGameThink = { m = nextmap; } localcmd("changelevel "); - localcmd(mapname); + localcmd(m); localcmd("\n"); dremove(self); } diff --git a/ssqc/world.qc b/ssqc/world.qc index 38b52623..4bdb8f43 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -343,13 +343,13 @@ void () worldspawn = { votemode = CF_GetSetting("vm", "votemode", "off"); vote_total_votes = 0; vote_style = CF_GetSetting("vs", "vote_style", "1"); + string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); //No map candidates in map! Add some defaults... if(!find(world, classname, "map_candidate")) { InitVoteMaps(); } if(votemode) { - string votemap = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); if(world.model != strcat("maps/",votemap,".bsp")) { bprint(PRINT_HIGH, "\bDisabling vote mode as map is not\b ",votemap,"\n"); //changelevel(votemap); @@ -357,6 +357,15 @@ void () worldspawn = { votemode = FALSE; } else { } + } else { + if(world.model == strcat("maps/",votemap,".bsp")) { + bprint(PRINT_HIGH, "\bEnabling vote mode as map is not\b ",votemap,"\n"); + localcmd ("localinfo votemode on\n"); + votemode = TRUE; + //changelevel(votemap); + } else { + } + } dimension_send = DMN_NOFLASH; From 41f917312e38aaca6f70571fe136df56be5049ae Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 12 Mar 2021 20:35:56 +1100 Subject: [PATCH 1204/2474] readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 49b86dae..889451e5 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* ``setinfo keepcells x`` allows scout/med/pyro/eng/hwguy to discard cells, x is how many they wish to keep. eg. an eng with 200 cells that has setinfo keepcells 50 will discard 150 cells and keep 50 (suggest users put in class configs) * option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. From ea2c695e6dc6dfe73626e9e2d179270ccbd5a697 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 12 Mar 2021 20:40:13 +1100 Subject: [PATCH 1205/2474] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 889451e5..4c5b482c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server New features ------ -* ``setinfo keepcells x`` allows scout/med/pyro/eng/hwguy to discard cells, x is how many they wish to keep. eg. an eng with 200 cells that has setinfo keepcells 50 will discard 150 cells and keep 50 (suggest users put in class configs) +* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to discard cells, x is how many they wish to keep. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50 (suggest users put in class configs) * option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. From c1f5c1442aa6e585c3afafc54b24758f389839b9 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 12 Mar 2021 20:44:25 +1100 Subject: [PATCH 1206/2474] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c5b482c..f54fd3e2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server New features ------ -* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to discard cells, x is how many they wish to keep. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50 (suggest users put in class configs) +* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50 (suggest users put in class configs) * option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. From 5551a07b49683665d8297a29ca7214d231cc0a5b Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 12 Mar 2021 20:49:39 +1100 Subject: [PATCH 1207/2474] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f54fd3e2..6c452dea 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server New features ------ -* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50 (suggest users put in class configs) +* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set limits for each class. * option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. From ef8600e1296c5f07b9d03ad62395e78bb6b7e965 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 12 Mar 2021 20:53:59 +1100 Subject: [PATCH 1208/2474] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c452dea..95124808 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server New features ------ -* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set limits for each class. +* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above ```` into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of ```` (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set values for each class. * option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. From 01a048d395ddbeedb519ffbee6721be757e2b5bf Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 12 Mar 2021 20:57:04 +1100 Subject: [PATCH 1209/2474] keepcells --- ssqc/actions.qc | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 03d9b96b..00fe4f85 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -5,24 +5,56 @@ void () TeamFortress_ClipTick; void () TeamFortress_Discard = { + local string s = infokey(self,"keepcells"); + local float c = stof(s); + if (c == 0 && s != "0") + c = -1; //using this to track if player doesnt want to use keepcells setinfo + else if (c < 0) + c = -1; + else + { + if(self.ammo_cells > c) //changing c to track how many cells to include in discard + c = self.ammo_cells - c; + else + c = 0; + } + + newmis = spawn(); switch (self.playerclass) { case PC_SCOUT: + newmis.ammo_rockets = self.ammo_rockets; + if(c > 0) + newmis.ammo_cells = c; + break; case PC_ENGINEER: - newmis.ammo_rockets = self.ammo_rockets; + newmis.ammo_rockets = self.ammo_rockets; + if(c > 0) + newmis.ammo_cells = c; break; case PC_MEDIC: newmis.ammo_rockets = self.ammo_rockets; if (!medicaura && old_medikit) { newmis.ammo_cells = self.ammo_cells; } + else + { + if(c > 0) + newmis.ammo_cells = c; + } break; case PC_SNIPER: + newmis.ammo_rockets = self.ammo_rockets; + newmis.ammo_cells = self.ammo_cells; + break; case PC_SPY: newmis.ammo_rockets = self.ammo_rockets; newmis.ammo_cells = self.ammo_cells; break; case PC_SOLDIER: + newmis.ammo_nails = self.ammo_nails; + newmis.ammo_cells = self.ammo_cells; + break; case PC_DEMOMAN: newmis.ammo_cells = self.ammo_cells; newmis.ammo_nails = self.ammo_nails; @@ -30,9 +62,13 @@ void () TeamFortress_Discard = { case PC_HVYWEAP: newmis.ammo_rockets = self.ammo_rockets; newmis.ammo_nails = self.ammo_nails; + if(c > 0) + newmis.ammo_cells = c; break; case PC_PYRO: newmis.ammo_nails = self.ammo_nails; + if(c > 0) + newmis.ammo_cells = c; break; default: } @@ -50,7 +86,10 @@ void () TeamFortress_Discard = { self.ammo_rockets = 0; } if (newmis.ammo_cells) { - self.ammo_cells = 0; + if(self.playerclass == PC_SCOUT || self.playerclass == PC_MEDIC || self.playerclass == PC_PYRO || self.playerclass == PC_HVYWEAP || self.playerclass == PC_ENGINEER && c > 0) + self.ammo_cells = self.ammo_cells - c; + else + self.ammo_cells = 0; } W_SetCurrentAmmo(self); FO_Sound(self, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); From 84ae6d74f63c166aea420b92772fbd06063c7a23 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sun, 14 Mar 2021 18:13:36 +1100 Subject: [PATCH 1210/2474] serverside nokeepcells localinfo nkc 1 to disable keepcells serverwide --- ssqc/actions.qc | 4 +++- ssqc/client.qc | 3 +++ ssqc/qw.qc | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 00fe4f85..c2b5dd44 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -7,7 +7,9 @@ void () TeamFortress_ClipTick; void () TeamFortress_Discard = { local string s = infokey(self,"keepcells"); local float c = stof(s); - if (c == 0 && s != "0") + if(nokeepcells) //check if disabled serverside + c = -1; + else if (c == 0 && s != "0") c = -1; //using this to track if player doesnt want to use keepcells setinfo else if (c < 0) c = -1; diff --git a/ssqc/client.qc b/ssqc/client.qc index 47d0b573..f4c19527 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -704,6 +704,9 @@ void () DecodeLevelParms = { // disable hit sounds [off] nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); + + // disable setinfo keepcells [off] + nokeepcells = CF_GetSetting("nkc", "nokeepcells", "0"); // enable server-side flaginfo on statusbar [on] // server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9dba5a57..7a0739f3 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -592,6 +592,7 @@ float fo_flashtime; float solid_nailgren; float noreturn; float nohitsounds; +float nokeepcells; //float server_sbflaginfo; float reverse_cap; float engineer_move; From 192302c0bc96b760e6d240202f7c9132651f9a2d Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sun, 14 Mar 2021 18:14:02 +1100 Subject: [PATCH 1211/2474] Add files via upload --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 95124808..c11204ff 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ FortressOne Server New features ------ -* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above ```` into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of ```` (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set values for each class. +* ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above ```` into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of ```` (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set values for each class. ``localinfo nokeepcells 1`` - disables keepcells server-wide * option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. From c496d9affbd6681c7375297fb96daa38d087cecd Mon Sep 17 00:00:00 2001 From: John Hwee Date: Wed, 24 Mar 2021 20:13:50 -0400 Subject: [PATCH 1212/2474] update build and make ammo comparison operators for engy --- csqc/menu.qc | 4 ++-- ssqc/tfort.qc | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index 3cff9d0f..5586ecc1 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -284,7 +284,7 @@ var fo_menu FO_MENU_BUILD = { FO_MENU_BUILD.options[3].state = FO_MENU_STATE_HIDDEN; //Dismantle } } else { - if(getstatf(STAT_CELLS) > ENG_SENTRY_COST) { + if(getstatf(STAT_CELLS) >= ENG_SENTRY_COST) { FO_MENU_BUILD.options[0].state = FO_MENU_STATE_NORMAL; } else { FO_MENU_BUILD.options[0].state = FO_MENU_STATE_DISABLED; @@ -302,7 +302,7 @@ var fo_menu FO_MENU_BUILD = { FO_MENU_BUILD.options[5].state = FO_MENU_STATE_HIDDEN; } } else { - if(getstatf(STAT_CELLS) > ENG_DISPENSER_COST) { + if(getstatf(STAT_CELLS) >= ENG_DISPENSER_COST) { FO_MENU_BUILD.options[1].state = FO_MENU_STATE_NORMAL; } else { FO_MENU_BUILD.options[1].state = FO_MENU_STATE_DISABLED; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 7ba4be76..adf1bf2b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2517,7 +2517,7 @@ void (float type) TeamFortress_DropAmmo = { ammo = DROP_SHELLS; if (self.ammo_shells < ammo) { if (self.playerclass == PC_ENGINEER) { - if ((self.ammo_cells / AMMO_COST_SHELLS) > + if ((self.ammo_cells / AMMO_COST_SHELLS) >= (ammo - self.ammo_shells)) { sprint(self, PRINT_HIGH, "You make some shells\n"); self.ammo_cells = @@ -2535,7 +2535,7 @@ void (float type) TeamFortress_DropAmmo = { ammo = DROP_NAILS; if (self.ammo_nails < ammo) { if (self.playerclass == PC_ENGINEER) { - if ((self.ammo_cells / AMMO_COST_NAILS) > + if ((self.ammo_cells / AMMO_COST_NAILS) >= (ammo - self.ammo_nails)) { sprint(self, PRINT_HIGH, "You make some nails\n"); self.ammo_cells = @@ -2553,7 +2553,7 @@ void (float type) TeamFortress_DropAmmo = { ammo = DROP_ROCKETS; if (self.ammo_rockets < ammo) { if (self.playerclass == PC_ENGINEER) { - if ((self.ammo_cells / AMMO_COST_ROCKETS) > + if ((self.ammo_cells / AMMO_COST_ROCKETS) >= (ammo - self.ammo_rockets)) { sprint(self, PRINT_HIGH, "You make some rockets\n"); self.ammo_cells = @@ -2571,7 +2571,7 @@ void (float type) TeamFortress_DropAmmo = { ammo = DROP_CELLS; if (self.ammo_cells < ammo) { if (self.playerclass == PC_ENGINEER) { - if ((self.ammo_cells / AMMO_COST_CELLS) > + if ((self.ammo_cells / AMMO_COST_CELLS) >= (ammo - self.ammo_cells)) { sprint(self, PRINT_HIGH, "You make some cells\n"); self.ammo_cells = From df383f450eddceb8b756f83916b2a633f289f8a5 Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 02:31:30 +1100 Subject: [PATCH 1213/2474] Replace medic's cuss with blast gren --- share/defs.h | 3 ++- ssqc/help.qc | 2 +- ssqc/items.qc | 4 +++- ssqc/scout.qc | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ ssqc/tfort.qc | 19 +++++++++++++++++- 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/share/defs.h b/share/defs.h index e5016848..5dc2c6fd 100644 --- a/share/defs.h +++ b/share/defs.h @@ -765,6 +765,7 @@ #define GR_TYPE_EMP 8 #define GR_TYPE_FLASH 9 #define GR_TYPE_CALTROP 10 +#define GR_TYPE_BLAST 11 // Defines for NailGren Types #define NGR_TYPE_DEFAULT 0 @@ -972,7 +973,7 @@ #define PC_MEDIC_INITAMMO_ROCKET 0 #define PC_MEDIC_INITAMMO_MEDIKIT 50 #define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION +#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_BLAST #define PC_MEDIC_GRENADE_INIT_1 3 #define PC_MEDIC_GRENADE_INIT_2 2 #define PC_MEDIC_GRENADE_MAX_1 4 diff --git a/ssqc/help.qc b/ssqc/help.qc index 43b535a6..feaa1e81 100644 --- a/ssqc/help.qc +++ b/ssqc/help.qc @@ -110,7 +110,7 @@ void () Help_ShowMedic = { sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); sprint(self, PRINT_HIGH, Q"\s4\s - Equip Medikit\n"); - sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Concussion Grenade\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Blast Grenade\n"); sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); }; diff --git a/ssqc/items.qc b/ssqc/items.qc index c4329ddf..86dc7917 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -763,6 +763,8 @@ void (entity pl, float typ) PrintGrenadeType = { st = "caltrop"; } else if (typ == 9) { st = "flash"; + } else if (typ == 11) { + st = "blast"; } sprint(pl, PRINT_HIGH, st); }; @@ -1430,4 +1432,4 @@ void () DropBackpack = { newmis.nextthink = time + 120; newmis.think = SUB_Remove; -}; \ No newline at end of file +}; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index f386cc11..75e5886b 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -14,6 +14,8 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce; +void (entity inflictor, entity attacker, float bounce, + entity ignore) T_RadiusBounceNoCuss; entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; @@ -369,6 +371,23 @@ void () ConcussionGrenadeExplode = { dremove(self); }; +void () BlastGrenadeTouch = { + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; +}; + +void () BlastGrenadeExplode = { + T_RadiusBounceNoCuss(self, self.owner, 240, world); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PHS); + dremove(self); +}; + void () OldConcussionGrenadeTimer = { local string st; @@ -707,6 +726,40 @@ void CussSpeedBump() } } +void (entity inflictor, entity attacker, float bounce, + entity ignore) T_RadiusBounceNoCuss = { + local float points; + local entity head; + local entity te; + local vector org; + + head = findradius(inflictor.origin, bounce + 40); + while (head) { + if (head != ignore) { + if (head.takedamage) { + org = head.origin + (head.mins + head.maxs) * 0.5; + points = 0.5 * vlen(org - inflictor.origin); + if (points < 0) + points = 0; + points = bounce - points; + + if ((head.classname != "building_dispenser") + && (head.classname != "building_sentrygun") + && (head.classname != "building_sentrygun_base") + && (points > 0)) { + head.velocity = org - inflictor.origin; + head.velocity = head.velocity * (points / 20); + if (head.classname != "player") { + if (head.flags & FL_ONGROUND) + head.flags = head.flags - FL_ONGROUND; + } + } + } + } + head = head.chain; + } +}; + void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce = { local float points; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 7ba4be76..c7edf8ad 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -444,6 +444,9 @@ string GetGrenName(float type) case GR_TYPE_CONCUSSION: s = "concussion grenade"; break; + case GR_TYPE_BLAST: + s = "blast grenade"; + break; case GR_TYPE_NONE: s = "no grenade"; break; @@ -643,7 +646,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Sniper max grenades type 2 (flare)", Role_None.gren2_limits[2], "", PC_SNIPER_GRENADE_MAX_2); CF_PrintSetting("Soldier max grenades type 2 (nail/shock)", Role_None.gren2_limits[3], "", PC_SOLDIER_GRENADE_MAX_2); CF_PrintSetting("Demoman max grenades type 2 (mirv)", Role_None.gren2_limits[4], "", PC_DEMOMAN_GRENADE_MAX_2); - CF_PrintSetting("Medic max grenades type 2 (concussion)", Role_None.gren2_limits[5], "", PC_MEDIC_GRENADE_MAX_2); + CF_PrintSetting("Medic max grenades type 2 (concussion/blast)", Role_None.gren2_limits[5], "", PC_MEDIC_GRENADE_MAX_2); CF_PrintSetting("Heavy Weapons max grenades type 2 (mirv)", Role_None.gren2_limits[6], "", PC_HVYWEAP_GRENADE_MAX_2); CF_PrintSetting("Pyro max grenades type 2 (napalm)", Role_None.gren2_limits[7], "", PC_PYRO_GRENADE_MAX_2); CF_PrintSetting("Spy max grenades type 2 (gas)", Role_None.gren2_limits[8], "", PC_SPY_GRENADE_MAX_2); @@ -796,6 +799,8 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "Flash grenade"; else if (self.tp_grenades_1 == 10) gs = "Caltrop canister"; + else if (self.tp_grenades_1 == 11) + gs = "Blast grenade"; else gs = "Grenade"; @@ -1006,6 +1011,13 @@ void () TeamFortress_GrenadePrimed = { newmis.skin = 1; newmis.avelocity = '300 300 300'; FO_SetModel(newmis, "progs/hgren2.mdl"); + } else if (self.weapon == GR_TYPE_BLAST) { + newmis.touch = BlastGrenadeTouch; + newmis.think = BlastGrenadeExplode; + newmis.grenadename = "blastgrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; @@ -1102,6 +1114,8 @@ void () TeamFortress_GrenadeSwitch = { gs = "Gas grenade"; else if (self.tp_grenades_1 == 8) gs = "EMP grenade"; + else if (self.tp_grenades_1 == 11) + gs = "Blast grenade"; else gs = "Grenade"; } else { @@ -2881,6 +2895,9 @@ void () TeamFortress_ExplodePerson = { if (self.weapon == GR_TYPE_CONCUSSION) bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, ", eating a concussion grenade is bad!\n"); + else if (self.weapon == GR_TYPE_BLAST) + bprint3(PRINT_MEDIUM, "Nice one ", self.owner.netname, + ", you forgot to throw your blast grenade!\n"); else bprint3(PRINT_MEDIUM, "No ", self.owner.netname, "! Assist your own suicide some other time!\n"); From a04e2ab933d9571c82325e77c2acf48613226c30 Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 03:39:17 +1100 Subject: [PATCH 1214/2474] Make blast gren togglable --- README.md | 1 + share/defs.h | 4 ++++ ssqc/client.qc | 6 +++++- ssqc/help.qc | 2 +- ssqc/items.qc | 6 +++++- ssqc/qw.qc | 2 ++ ssqc/scout.qc | 1 - ssqc/tfort.qc | 51 +++++++++++++++++++++++++++++++++++++++++--------- 8 files changed, 60 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 49b86dae..6a1337d9 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ New features * Admin system created to allow for easy setup of pub/clan/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` * Loc support added to server, show locations for dropped flag. * Nailgrenades changed to "Shock/Laser Grenades" to lower spam/not stop bunnyhopping on hit (0 original, 1 laser, 2 burst). `localinfo nailgren_type 1` and `nginfo` in game for all configurable settings. +* Medic cuss grenades changed to "Blast grenades" (no cuss effect) (0 original, 1 blast). `localinfo mediccussgren_type 1` and `nginfo` in game for all configurable settings. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. diff --git a/share/defs.h b/share/defs.h index 5dc2c6fd..b31c2a60 100644 --- a/share/defs.h +++ b/share/defs.h @@ -772,6 +772,10 @@ #define NGR_TYPE_LASER 1 #define NGR_TYPE_BURST 2 +// Defines for CussGren Types +#define MCGR_TYPE_DEFAULT 0 +#define MCGR_TYPE_BLAST 1 + // NailGren Default Settings #define NGR_LASER_DEFAULT_ROTATIONCOUNT 2 #define NGR_LASER_DEFAULT_ROTATIONTIME 1 diff --git a/ssqc/client.qc b/ssqc/client.qc index 7044ae5b..d31d0634 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -386,9 +386,12 @@ void () DecodeLevelParms = { spurs_flag = CF_GetSetting("spf", "spurs_flag" , "0"); // can climb with flag - // nailgren types 0 = NGR_TYPE_DEFAULT, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST + // nail gren types 0 = NGR_TYPE_DEFAULT, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_LASER)); + // medic cuss types 0 = MCGR_TYPE_DEFAULT, 1 = MCGR_TYPE_BLAST + mediccussgren_type = CF_GetSetting("mcgt", "mediccussgren_type", ftos(MCGR_TYPE_BLAST)); + // how many rotations the nailgren does [2] lasergren_rotationcount = CF_GetSetting("lgrc", "lasergren_rotationcount", ftos(NGR_LASER_DEFAULT_ROTATIONCOUNT)); @@ -880,6 +883,7 @@ void () DecodeLevelParms = { scoutdash = FALSE; fo_flash = FALSE; nailgren_type = NGR_TYPE_DEFAULT; + mediccussgren_type = MCGR_TYPE_BLAST; Role_None.detpipe_limit = 7; detpipe_limit_world = 7; medicaura = FALSE; diff --git a/ssqc/help.qc b/ssqc/help.qc index feaa1e81..e8a7b0fe 100644 --- a/ssqc/help.qc +++ b/ssqc/help.qc @@ -110,7 +110,7 @@ void () Help_ShowMedic = { sprint(self, PRINT_HIGH, Q"\s2\s - Equip Super Shotgun\n"); sprint(self, PRINT_HIGH, Q"\s2\s - Equip Shotgun\n"); sprint(self, PRINT_HIGH, Q"\s4\s - Equip Medikit\n"); - sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Blast Grenade\n"); + sprint(self, PRINT_HIGH, Q"\sf\s - Prime/throw Concussion/Blast Grenade\n"); sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); }; diff --git a/ssqc/items.qc b/ssqc/items.qc index 86dc7917..f909f9ce 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -764,7 +764,11 @@ void (entity pl, float typ) PrintGrenadeType = { } else if (typ == 9) { st = "flash"; } else if (typ == 11) { - st = "blast"; + if (mediccussgren_type == MCGR_TYPE_BLAST) { + st = "blast"; + } else { + st = "concussion"; + } } sprint(pl, PRINT_HIGH, st); }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 0cd027cf..f853d2c4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -493,6 +493,8 @@ float burstgren_count; float burstgren_interval; float burstgren_range; +float mediccussgren_type; + float old_grens; float fo_flash; float invis_only; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 75e5886b..3257b548 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -730,7 +730,6 @@ void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounceNoCuss = { local float points; local entity head; - local entity te; local vector org; head = findradius(inflictor.origin, bounce + 40); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c7edf8ad..ed3f6621 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -445,7 +445,7 @@ string GetGrenName(float type) s = "concussion grenade"; break; case GR_TYPE_BLAST: - s = "blast grenade"; + s = (mediccussgren_type == MCGR_TYPE_BLAST) ? "blast grenade" : "concussion grenade"; break; case GR_TYPE_NONE: s = "no grenade"; @@ -800,7 +800,11 @@ void (float inp) TeamFortress_PrimeGrenade = { else if (self.tp_grenades_1 == 10) gs = "Caltrop canister"; else if (self.tp_grenades_1 == 11) - gs = "Blast grenade"; + if (mediccussgren_type == MCGR_TYPE_BLAST) { + gs = "Blast grenade"; + } else { + gs = "Concussion grenade"; + } else gs = "Grenade"; @@ -1012,12 +1016,21 @@ void () TeamFortress_GrenadePrimed = { newmis.avelocity = '300 300 300'; FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_BLAST) { - newmis.touch = BlastGrenadeTouch; - newmis.think = BlastGrenadeExplode; - newmis.grenadename = "blastgrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); + if (mediccussgren_type == MCGR_TYPE_BLAST){ + newmis.touch = BlastGrenadeTouch; + newmis.think = BlastGrenadeExplode; + newmis.grenadename = "blastgrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/hgren2.mdl"); + } else { + newmis.touch = ConcussionGrenadeTouch; + newmis.think = ConcussionGrenadeExplode; + newmis.grenadename = "concussiongrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/hgren2.mdl"); + } } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; @@ -1115,7 +1128,11 @@ void () TeamFortress_GrenadeSwitch = { else if (self.tp_grenades_1 == 8) gs = "EMP grenade"; else if (self.tp_grenades_1 == 11) - gs = "Blast grenade"; + if (mediccussgren_type == MCGR_TYPE_BLAST) { + gs = "Blast grenade"; + } else { + gs = "Cuss grenade"; + } else gs = "Grenade"; } else { @@ -2814,6 +2831,22 @@ void () TeamFortress_ExplodePerson = { newmis.skin = 1; newmis.avelocity = '300 300 300'; FO_SetModel(newmis, "progs/hgren2.mdl"); + } else if (self.weapon == GR_TYPE_BLAST) { + if (mediccussgren_type == MCGR_TYPE_BLAST) { + newmis.touch = BlastGrenadeTouch; + newmis.think = BlastGrenadeExplode; + newmis.grenadename = "blastgrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/hgren2.mdl"); + } else { + newmis.touch = ConcussionGrenadeTouch; + newmis.think = ConcussionGrenadeExplode; + newmis.grenadename = "concussiongrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/hgren2.mdl"); + } } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; From b2650a02fccfb03c348b26550c1af94cd4621b2d Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 04:00:28 +1100 Subject: [PATCH 1215/2474] Make blast gren 12.5% weaker than ordinary cuss (but no speedbump on medic) --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 3257b548..6b98d3b7 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -737,7 +737,7 @@ void (entity inflictor, entity attacker, float bounce, if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs) * 0.5; - points = 0.5 * vlen(org - inflictor.origin); + points = 0.625 * vlen(org - inflictor.origin); if (points < 0) points = 0; points = bounce - points; From 2beb84c9af7bf66f3a9bc134cbdb1e74caa1cf82 Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 04:01:51 +1100 Subject: [PATCH 1216/2474] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a1337d9..04a1a0b8 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ New features * Admin system created to allow for easy setup of pub/clan/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` * Loc support added to server, show locations for dropped flag. * Nailgrenades changed to "Shock/Laser Grenades" to lower spam/not stop bunnyhopping on hit (0 original, 1 laser, 2 burst). `localinfo nailgren_type 1` and `nginfo` in game for all configurable settings. -* Medic cuss grenades changed to "Blast grenades" (no cuss effect) (0 original, 1 blast). `localinfo mediccussgren_type 1` and `nginfo` in game for all configurable settings. +* Medic cuss grenades changed to "Blast grenades" (no cuss effect, 12.5% weaker, no medic speedhump) (0 original, 1 blast). `localinfo mediccussgren_type 1` and `nginfo` in game for all configurable settings. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. From a171e3507d5d924852d058827a09a97707bd9b9d Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 04:14:20 +1100 Subject: [PATCH 1217/2474] More sensible name --- ssqc/scout.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 6b98d3b7..0a0b4b07 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -15,7 +15,7 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce; void (entity inflictor, entity attacker, float bounce, - entity ignore) T_RadiusBounceNoCuss; + entity ignore) T_RadiusBounceBlast; entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; @@ -378,7 +378,7 @@ void () BlastGrenadeTouch = { }; void () BlastGrenadeExplode = { - T_RadiusBounceNoCuss(self, self.owner, 240, world); + T_RadiusBounceBlast(self, self.owner, 240, world); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_EXPLOSION); WriteCoord(MSG_MULTICAST, self.origin_x); @@ -727,7 +727,7 @@ void CussSpeedBump() } void (entity inflictor, entity attacker, float bounce, - entity ignore) T_RadiusBounceNoCuss = { + entity ignore) T_RadiusBounceBlast = { local float points; local entity head; local vector org; From d85324fedc4b6e3c111087ff10abcea89f36497e Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 04:28:51 +1100 Subject: [PATCH 1218/2474] Fix hand held cuss message --- ssqc/tfort.qc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index ed3f6621..72880eb4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2925,15 +2925,18 @@ void () TeamFortress_ExplodePerson = { bprint3(PRINT_MEDIUM, "Ack! ", self.owner.netname, "! The grenade is your friend for another reason!\n"); else if (self.owner.playerclass == PC_MEDIC) { - if (self.weapon == GR_TYPE_CONCUSSION) - bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, - ", eating a concussion grenade is bad!\n"); - else if (self.weapon == GR_TYPE_BLAST) - bprint3(PRINT_MEDIUM, "Nice one ", self.owner.netname, - ", you forgot to throw your blast grenade!\n"); - else + if (self.weapon == GR_TYPE_BLAST) { + if (mediccussgren_type == MCGR_TYPE_BLAST) { + bprint3(PRINT_MEDIUM, "Nice one ", self.owner.netname, + ", you forgot to throw your blast grenade!\n"); + } else { + bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, + ", eating a concussion grenade is bad!\n"); + } + } else { bprint3(PRINT_MEDIUM, "No ", self.owner.netname, "! Assist your own suicide some other time!\n"); + } } else if (self.owner.playerclass == PC_HVYWEAP) bprint3(PRINT_MEDIUM, "Hey ", self.owner.netname, From 18eac381dcb75362fc0a620ab4f21e6fb92b23f4 Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 04:40:39 +1100 Subject: [PATCH 1219/2474] Fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04a1a0b8..cdb76eee 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ New features * Admin system created to allow for easy setup of pub/clan/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` * Loc support added to server, show locations for dropped flag. * Nailgrenades changed to "Shock/Laser Grenades" to lower spam/not stop bunnyhopping on hit (0 original, 1 laser, 2 burst). `localinfo nailgren_type 1` and `nginfo` in game for all configurable settings. -* Medic cuss grenades changed to "Blast grenades" (no cuss effect, 12.5% weaker, no medic speedhump) (0 original, 1 blast). `localinfo mediccussgren_type 1` and `nginfo` in game for all configurable settings. +* Option for medic secondary grenade changed to "Blast grenade" (blast like cuss grenade but no cuss effect, 12.5% weaker, no medic speedhump) (0 original, 1 blast). `localinfo mediccussgren_type 1`. * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. From ebe7789b4a4d13b894e4cee1c33f55a6b93bceef Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 17:59:35 +1100 Subject: [PATCH 1220/2474] Decrease blast power slightly --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 0a0b4b07..68fee694 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -737,7 +737,7 @@ void (entity inflictor, entity attacker, float bounce, if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs) * 0.5; - points = 0.625 * vlen(org - inflictor.origin); + points = 0.65 * vlen(org - inflictor.origin); if (points < 0) points = 0; points = bounce - points; From fd33a4012617e14dad963877a8d39e64965092dc Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 18:35:09 +1100 Subject: [PATCH 1221/2474] Actually print Blast grenade when priming --- ssqc/tfort.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 72880eb4..ee8d89f3 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -869,6 +869,12 @@ void (float inp) TeamFortress_PrimeGrenade = { gs = "EMP grenade"; else if (self.tp_grenades_2 == 9) gs = "Flash grenade"; + else if (self.tp_grenades_2 == 11) + if (mediccussgren_type == MCGR_TYPE_BLAST) { + gs = "Blast grenade"; + } else { + gs = "Concussion grenade"; + } else gs = "Grenade"; From 1526866df69ed21fdb5650956b8f35c95dcb085b Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 18:47:39 +1100 Subject: [PATCH 1222/2474] Allow medic to be cussed again (when using blast grens) --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 68fee694..7dd71c58 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -788,7 +788,7 @@ void (entity inflictor, entity attacker, float bounce, } else { if (head.playerclass == PC_MEDIC) { - if (medicnocuss) + if (medicnocuss && (mediccussgren_type != MCGR_TYPE_BLAST)) { entity speedbump; speedbump = spawn(); From 4b743b8e720f7cec8297425145f5aa08e9c7788f Mon Sep 17 00:00:00 2001 From: drzel Date: Sat, 27 Mar 2021 22:27:50 +1100 Subject: [PATCH 1223/2474] Make blast stronger --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 7dd71c58..55cdd5ee 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -737,7 +737,7 @@ void (entity inflictor, entity attacker, float bounce, if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs) * 0.5; - points = 0.65 * vlen(org - inflictor.origin); + points = 0.6 * vlen(org - inflictor.origin); if (points < 0) points = 0; points = bounce - points; From d2c8ff5683dc409a8e7da8d1c652ecd70d35a146 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 28 Mar 2021 01:23:33 +1100 Subject: [PATCH 1224/2474] Make blast more powerful still --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 55cdd5ee..4d8e286b 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -737,7 +737,7 @@ void (entity inflictor, entity attacker, float bounce, if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs) * 0.5; - points = 0.6 * vlen(org - inflictor.origin); + points = 0.55 * vlen(org - inflictor.origin); if (points < 0) points = 0; points = bounce - points; From 074edddc028c0e76ceb57a4643aaa050308d1b2d Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 28 Mar 2021 02:22:44 +1100 Subject: [PATCH 1225/2474] Use blastgren.mdl --- ssqc/tfort.qc | 4 ++-- ssqc/world.qc | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index ee8d89f3..16071d16 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1028,7 +1028,7 @@ void () TeamFortress_GrenadePrimed = { newmis.grenadename = "blastgrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/blastgren.mdl"); } else { newmis.touch = ConcussionGrenadeTouch; newmis.think = ConcussionGrenadeExplode; @@ -2844,7 +2844,7 @@ void () TeamFortress_ExplodePerson = { newmis.grenadename = "blastgrenade"; newmis.skin = 1; newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); + FO_SetModel(newmis, "progs/blastgren.mdl"); } else { newmis.touch = ConcussionGrenadeTouch; newmis.think = ConcussionGrenadeExplode; diff --git a/ssqc/world.qc b/ssqc/world.qc index 38b52623..36c098fc 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -276,6 +276,7 @@ void () worldspawn = { precache_model2("progs/tf_stan.mdl"); precache_model2("progs/v_medi.mdl"); precache_model2("progs/hgren2.mdl"); + precache_model2("progs/blastgren.mdl"); precache_model2("progs/flashgren.mdl"); precache_model2("progs/biggren.mdl"); precache_model2("progs/flare.mdl"); From 531aaeacb8cc4f9118c4803b9ba719e58d92ac6f Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 28 Mar 2021 14:55:18 +1100 Subject: [PATCH 1226/2474] Try reduce medic speed a little --- share/defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/defs.h b/share/defs.h index b31c2a60..e8fb04d4 100644 --- a/share/defs.h +++ b/share/defs.h @@ -957,8 +957,8 @@ // Class Details for COMBAT MEDIC #define PC_MEDIC_SKIN 3 #define PC_MEDIC_MAXHEALTH 100 -#define PC_MEDIC_MAXSPEED 320 -#define PC_MEDIC_MAXSTRAFESPEED 320 +#define PC_MEDIC_MAXSPEED 280 +#define PC_MEDIC_MAXSTRAFESPEED 280 #define PC_MEDIC_MAXARMOR 90 #define PC_MEDIC_INITARMOR 40 #define PC_MEDIC_MAXARMORTYPE 0.6 From 41b931a4813746abf95527e11129171503674ae5 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 28 Mar 2021 15:12:56 +1100 Subject: [PATCH 1227/2474] Reduce blast medic's speed 320 -> 280 --- share/defs.h | 6 ++++-- ssqc/tfort.qc | 13 +++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/share/defs.h b/share/defs.h index e8fb04d4..1ac747cf 100644 --- a/share/defs.h +++ b/share/defs.h @@ -957,8 +957,10 @@ // Class Details for COMBAT MEDIC #define PC_MEDIC_SKIN 3 #define PC_MEDIC_MAXHEALTH 100 -#define PC_MEDIC_MAXSPEED 280 -#define PC_MEDIC_MAXSTRAFESPEED 280 +#define PC_MEDIC_MAXSPEED 320 +#define PC_MEDIC_MAXSTRAFESPEED 320 +#define PC_BLASTMEDIC_MAXSPEED 280 +#define PC_BLASTMEDIC_MAXSTRAFESPEED 280 #define PC_MEDIC_MAXARMOR 90 #define PC_MEDIC_INITARMOR 40 #define PC_MEDIC_MAXARMORTYPE 0.6 diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 16071d16..2652c328 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1247,8 +1247,13 @@ void (entity p) TeamFortress_SetSpeed = { p.maxfbspeed = PC_DEMOMAN_MAXSPEED; p.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED; } else if (p.playerclass == PC_MEDIC) { - p.maxfbspeed = PC_MEDIC_MAXSPEED; - p.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED; + if (mediccussgren_type == MCGR_TYPE_BLAST) { + p.maxfbspeed = PC_BLASTMEDIC_MAXSPEED; + p.maxstrafespeed = PC_BLASTMEDIC_MAXSTRAFESPEED; + } else { + p.maxfbspeed = PC_MEDIC_MAXSPEED; + p.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED; + } } else if (p.playerclass == PC_HVYWEAP) { p.maxfbspeed = PC_HVYWEAP_MAXSPEED; p.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED; @@ -1265,8 +1270,8 @@ void (entity p) TeamFortress_SetSpeed = { p.maxfbspeed = PC_ENGINEER_MAXSPEED; p.maxstrafespeed = PC_ENGINEER_MAXSTRAFESPEED; } else if (p.playerclass == PC_UNDEFINED) { -// p.maxfbspeed = 320; -// p.maxstrafespeed = 320; + // p.maxfbspeed = 320; + // p.maxstrafespeed = 320; p.maxfbspeed = 0; p.maxstrafespeed = 0; p.maxspeed = 0; From 65a3b7c9f4355300c6cd5db17bafc3a30cfdbc8c Mon Sep 17 00:00:00 2001 From: driztf Date: Sun, 28 Mar 2021 15:04:45 -0700 Subject: [PATCH 1228/2474] Add MOVE_LAGGED to weapon traces --- ssqc/actions.qc | 2 +- ssqc/weapons.qc | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index c2b5dd44..3a3f5ee9 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -288,7 +288,7 @@ void (entity pe_player, float f_type) CF_Identify = { v_source = pe_player.origin + v_forward * 10; v_source_z = pe_player.absmin_z + pe_player.size_z * 0.7; - traceline(v_source, v_source + v_forward * 2048, 0, pe_player); + traceline(v_source, v_source + v_forward * 2048, MOVE_LAGGED, pe_player); if (trace_ent != world) { local string s_id_string = "", s_class = "", s_name = ""; local float f_health = 0, f_maxhealth = 0, f_armor = 0, f_maxarmor = 0, f_friendly = 0, f_fakefriendly = 0, f_sentryhealth = 0, f_maxsentryhealth = 0; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 4d59c39b..99921b68 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -751,7 +751,7 @@ void (float shotcount, vector dir, vector spread) FireBullets = { ClearMultiDamage(); - traceline(src, src + dir * 2048, FALSE, self); + traceline(src, src + dir * 2048, MOVE_LAGGED, self); puff_org = trace_endpos - dir * 4; while (shotcount > 0) { @@ -760,7 +760,7 @@ void (float shotcount, vector dir, vector spread) FireBullets = { dir + crandom() * spread_x * v_right + crandom() * spread_y * v_up; - traceline(src, (src + (direction * 2048)), 0, self); + traceline(src, (src + (direction * 2048)), MOVE_LAGGED, self); if (trace_fraction != 1) { if (self.current_weapon != WEAP_ASSAULT_CANNON) TraceAttack(4, direction); @@ -819,7 +819,7 @@ void (vector direction, float damage) FireSniperBullet = { KickPlayer(-3, self); - traceline(src, src + direction * 4096, FALSE, self); + traceline(src, src + direction * 4096, MOVE_LAGGED, self); if (trace_fraction != 1) TraceAttack(damage, direction); @@ -852,9 +852,9 @@ void () W_FireSniperRifle = { use_this = FALSE; if (old_sniperrange) - traceline(src, src + dir * 8092, FALSE, self); + traceline(src, src + dir * 8092, MOVE_LAGGED, self); else - traceline(src, src + dir * 9192, FALSE, self); + traceline(src, src + dir * 9192, MOVE_LAGGED, self); if (trace_fraction != 1) if (trace_ent != world) if (trace_ent.classname == "player") @@ -865,9 +865,9 @@ void () W_FireSniperRifle = { if (!use_this) { dir = aim(self, 10000); if (old_sniperrange) - traceline(src, src + dir * 3072, 0, self); + traceline(src, src + dir * 3072, MOVE_LAGGED, self); else - traceline(src, src + dir * 9192, 0, self); + traceline(src, src + dir * 9192, MOVE_LAGGED, self); } deathmsg = DMSG_SNIPERRIFLE; dam_mult = 1; From 6d9d1e9888a056046d2b772fd5814ac03f52a677 Mon Sep 17 00:00:00 2001 From: drzel Date: Tue, 30 Mar 2021 23:46:36 +1100 Subject: [PATCH 1229/2474] Restore to original cuss velocity --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 4d8e286b..5792e524 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -737,7 +737,7 @@ void (entity inflictor, entity attacker, float bounce, if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs) * 0.5; - points = 0.55 * vlen(org - inflictor.origin); + points = 0.5 * vlen(org - inflictor.origin); if (points < 0) points = 0; points = bounce - points; From 1c9ec31bbeca04ecf826de1a97aeb60fee94eebb Mon Sep 17 00:00:00 2001 From: drzel Date: Wed, 31 Mar 2021 00:00:01 +1100 Subject: [PATCH 1230/2474] Improve readability --- README.md | 2 +- share/defs.h | 6 +++--- ssqc/client.qc | 6 +++--- ssqc/items.qc | 2 +- ssqc/qw.qc | 2 +- ssqc/scout.qc | 2 +- ssqc/tfort.qc | 16 ++++++++-------- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index cdb76eee..48c512b8 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ New features * Admin system created to allow for easy setup of pub/clan/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` * Loc support added to server, show locations for dropped flag. * Nailgrenades changed to "Shock/Laser Grenades" to lower spam/not stop bunnyhopping on hit (0 original, 1 laser, 2 burst). `localinfo nailgren_type 1` and `nginfo` in game for all configurable settings. -* Option for medic secondary grenade changed to "Blast grenade" (blast like cuss grenade but no cuss effect, 12.5% weaker, no medic speedhump) (0 original, 1 blast). `localinfo mediccussgren_type 1`. +* Option for "blast medic". Secondary grenade is repaced with blast gren. It behaves like a concussion grenade, but doesn't apply a concussion effect. The blast medic moves at 280 units (instead of 320), but is not speed capped. `localinfo medic_type 1` (0 for normal, 1 for blast). * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. diff --git a/share/defs.h b/share/defs.h index 1ac747cf..b36e0e9b 100644 --- a/share/defs.h +++ b/share/defs.h @@ -772,9 +772,9 @@ #define NGR_TYPE_LASER 1 #define NGR_TYPE_BURST 2 -// Defines for CussGren Types -#define MCGR_TYPE_DEFAULT 0 -#define MCGR_TYPE_BLAST 1 +// Defines for Medic type +#define MEDIC_TYPE_DEFAULT 0 +#define MEDIC_TYPE_BLAST 1 // NailGren Default Settings #define NGR_LASER_DEFAULT_ROTATIONCOUNT 2 diff --git a/ssqc/client.qc b/ssqc/client.qc index d31d0634..c991bcdd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -389,8 +389,8 @@ void () DecodeLevelParms = { // nail gren types 0 = NGR_TYPE_DEFAULT, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_LASER)); - // medic cuss types 0 = MCGR_TYPE_DEFAULT, 1 = MCGR_TYPE_BLAST - mediccussgren_type = CF_GetSetting("mcgt", "mediccussgren_type", ftos(MCGR_TYPE_BLAST)); + // medic types 0 = MEDIC_TYPE_DEFAULT, 1 = MEDIC_TYPE_BLAST + medic_type = CF_GetSetting("mcgt", "medic_type", ftos(MEDIC_TYPE_BLAST)); // how many rotations the nailgren does [2] lasergren_rotationcount = CF_GetSetting("lgrc", "lasergren_rotationcount", ftos(NGR_LASER_DEFAULT_ROTATIONCOUNT)); @@ -883,7 +883,7 @@ void () DecodeLevelParms = { scoutdash = FALSE; fo_flash = FALSE; nailgren_type = NGR_TYPE_DEFAULT; - mediccussgren_type = MCGR_TYPE_BLAST; + medic_type = MEDIC_TYPE_BLAST; Role_None.detpipe_limit = 7; detpipe_limit_world = 7; medicaura = FALSE; diff --git a/ssqc/items.qc b/ssqc/items.qc index f909f9ce..5541688f 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -764,7 +764,7 @@ void (entity pl, float typ) PrintGrenadeType = { } else if (typ == 9) { st = "flash"; } else if (typ == 11) { - if (mediccussgren_type == MCGR_TYPE_BLAST) { + if (medic_type == MEDIC_TYPE_BLAST) { st = "blast"; } else { st = "concussion"; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index f853d2c4..74224613 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -493,7 +493,7 @@ float burstgren_count; float burstgren_interval; float burstgren_range; -float mediccussgren_type; +float medic_type; float old_grens; float fo_flash; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 5792e524..2d62f4f1 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -788,7 +788,7 @@ void (entity inflictor, entity attacker, float bounce, } else { if (head.playerclass == PC_MEDIC) { - if (medicnocuss && (mediccussgren_type != MCGR_TYPE_BLAST)) + if (medicnocuss && (medic_type != MEDIC_TYPE_BLAST)) { entity speedbump; speedbump = spawn(); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2652c328..9f7191ef 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -445,7 +445,7 @@ string GetGrenName(float type) s = "concussion grenade"; break; case GR_TYPE_BLAST: - s = (mediccussgren_type == MCGR_TYPE_BLAST) ? "blast grenade" : "concussion grenade"; + s = (medic_type == MEDIC_TYPE_BLAST) ? "blast grenade" : "concussion grenade"; break; case GR_TYPE_NONE: s = "no grenade"; @@ -800,7 +800,7 @@ void (float inp) TeamFortress_PrimeGrenade = { else if (self.tp_grenades_1 == 10) gs = "Caltrop canister"; else if (self.tp_grenades_1 == 11) - if (mediccussgren_type == MCGR_TYPE_BLAST) { + if (medic_type == MEDIC_TYPE_BLAST) { gs = "Blast grenade"; } else { gs = "Concussion grenade"; @@ -870,7 +870,7 @@ void (float inp) TeamFortress_PrimeGrenade = { else if (self.tp_grenades_2 == 9) gs = "Flash grenade"; else if (self.tp_grenades_2 == 11) - if (mediccussgren_type == MCGR_TYPE_BLAST) { + if (medic_type == MEDIC_TYPE_BLAST) { gs = "Blast grenade"; } else { gs = "Concussion grenade"; @@ -1022,7 +1022,7 @@ void () TeamFortress_GrenadePrimed = { newmis.avelocity = '300 300 300'; FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_BLAST) { - if (mediccussgren_type == MCGR_TYPE_BLAST){ + if (medic_type == MEDIC_TYPE_BLAST){ newmis.touch = BlastGrenadeTouch; newmis.think = BlastGrenadeExplode; newmis.grenadename = "blastgrenade"; @@ -1134,7 +1134,7 @@ void () TeamFortress_GrenadeSwitch = { else if (self.tp_grenades_1 == 8) gs = "EMP grenade"; else if (self.tp_grenades_1 == 11) - if (mediccussgren_type == MCGR_TYPE_BLAST) { + if (medic_type == MEDIC_TYPE_BLAST) { gs = "Blast grenade"; } else { gs = "Cuss grenade"; @@ -1247,7 +1247,7 @@ void (entity p) TeamFortress_SetSpeed = { p.maxfbspeed = PC_DEMOMAN_MAXSPEED; p.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED; } else if (p.playerclass == PC_MEDIC) { - if (mediccussgren_type == MCGR_TYPE_BLAST) { + if (medic_type == MEDIC_TYPE_BLAST) { p.maxfbspeed = PC_BLASTMEDIC_MAXSPEED; p.maxstrafespeed = PC_BLASTMEDIC_MAXSTRAFESPEED; } else { @@ -2843,7 +2843,7 @@ void () TeamFortress_ExplodePerson = { newmis.avelocity = '300 300 300'; FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_BLAST) { - if (mediccussgren_type == MCGR_TYPE_BLAST) { + if (medic_type == MEDIC_TYPE_BLAST) { newmis.touch = BlastGrenadeTouch; newmis.think = BlastGrenadeExplode; newmis.grenadename = "blastgrenade"; @@ -2937,7 +2937,7 @@ void () TeamFortress_ExplodePerson = { "! The grenade is your friend for another reason!\n"); else if (self.owner.playerclass == PC_MEDIC) { if (self.weapon == GR_TYPE_BLAST) { - if (mediccussgren_type == MCGR_TYPE_BLAST) { + if (medic_type == MEDIC_TYPE_BLAST) { bprint3(PRINT_MEDIUM, "Nice one ", self.owner.netname, ", you forgot to throw your blast grenade!\n"); } else { From 3cfe567b611e97dd7084f1c6e0346df31cbb64b6 Mon Sep 17 00:00:00 2001 From: drzel Date: Wed, 31 Mar 2021 00:39:48 +1100 Subject: [PATCH 1231/2474] Add blast gren multiplier option --- README.md | 1 + share/defs.h | 11 +++++++---- ssqc/client.qc | 3 +++ ssqc/qw.qc | 1 + ssqc/scout.qc | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 48c512b8..e7deeec2 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ New features * Loc support added to server, show locations for dropped flag. * Nailgrenades changed to "Shock/Laser Grenades" to lower spam/not stop bunnyhopping on hit (0 original, 1 laser, 2 burst). `localinfo nailgren_type 1` and `nginfo` in game for all configurable settings. * Option for "blast medic". Secondary grenade is repaced with blast gren. It behaves like a concussion grenade, but doesn't apply a concussion effect. The blast medic moves at 280 units (instead of 320), but is not speed capped. `localinfo medic_type 1` (0 for normal, 1 for blast). +* Blast grenade velocity multiplier `localinfo blastgren_velocity_multiplier`. (default 1 is same as concussion grenade). * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. diff --git a/share/defs.h b/share/defs.h index b36e0e9b..af3352e5 100644 --- a/share/defs.h +++ b/share/defs.h @@ -772,10 +772,6 @@ #define NGR_TYPE_LASER 1 #define NGR_TYPE_BURST 2 -// Defines for Medic type -#define MEDIC_TYPE_DEFAULT 0 -#define MEDIC_TYPE_BLAST 1 - // NailGren Default Settings #define NGR_LASER_DEFAULT_ROTATIONCOUNT 2 #define NGR_LASER_DEFAULT_ROTATIONTIME 1 @@ -786,6 +782,13 @@ #define NGR_BURST_DEFAULT_INTERVAL 0.7 #define NGR_BURST_DEFAULT_RANGE 0.3 +// Defines for Medic type +#define MEDIC_TYPE_DEFAULT 0 +#define MEDIC_TYPE_BLAST 1 + +// Defines for BlastGren Settings +#define BLASTGREN_DEFAULT_VELOCITY_MULTIPLIER 1 + // Defines for WeaponMode #define GL_NORMAL 0 #define GL_PIPEBOMB 1 diff --git a/ssqc/client.qc b/ssqc/client.qc index c991bcdd..8569e2b8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -416,6 +416,9 @@ void () DecodeLevelParms = { // time before nail projectile destroys itself [0.3] burstgren_range = CF_GetSetting("bgr", "burstgren_range", ftos(NGR_BURST_DEFAULT_RANGE)); + // multiplier to blast gren velocity + blastgren_velocity_multiplier = CF_GetSetting("bvm", "blastgren_velocity_multiplier", ftos(BLASTGREN_DEFAULT_VELOCITY_MULTIPLIER)); + // use old concussion, gas and flash grenades [off] old_grens = CF_GetSetting("og", "old_grens", "off"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 74224613..e61d9d67 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -494,6 +494,7 @@ float burstgren_interval; float burstgren_range; float medic_type; +float blastgren_velocity_multiplier; float old_grens; float fo_flash; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 2d62f4f1..e216a557 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -747,7 +747,7 @@ void (entity inflictor, entity attacker, float bounce, && (head.classname != "building_sentrygun_base") && (points > 0)) { head.velocity = org - inflictor.origin; - head.velocity = head.velocity * (points / 20); + head.velocity = head.velocity * (points / 20) * blastgren_velocity_multiplier; if (head.classname != "player") { if (head.flags & FL_ONGROUND) head.flags = head.flags - FL_ONGROUND; From 7ec73a0c5415b9b20133ec2d167e5837516c7015 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 4 Apr 2021 21:38:33 +1000 Subject: [PATCH 1232/2474] Reduce hwguy armor to 250 (and make configurable) --- share/defs.h | 2 +- ssqc/client.qc | 3 +++ ssqc/commands.qc | 6 +++--- ssqc/qw.qc | 1 + ssqc/tfort.qc | 17 +++++++++++++---- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/share/defs.h b/share/defs.h index af3352e5..39213797 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1006,7 +1006,7 @@ #define PC_HVYWEAP_MAXHEALTH 100 #define PC_HVYWEAP_MAXSPEED 230 #define PC_HVYWEAP_MAXSTRAFESPEED 230 -#define PC_HVYWEAP_MAXARMOR 300 +#define PC_HVYWEAP_MAXARMOR 250 #define PC_HVYWEAP_INITARMOR 150 #define PC_HVYWEAP_MAXARMORTYPE 0.8 #define PC_HVYWEAP_INITARMORTYPE 0.8 diff --git a/ssqc/client.qc b/ssqc/client.qc index 8569e2b8..0815d92f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -566,6 +566,9 @@ void () DecodeLevelParms = { // use old init/max hp/armor [off] old_hp_armor = CF_GetSetting("oh", "old_hp_armor", "off"); + // configure max armor of heavy weapons guy [250] + max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); + // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index d80a6d02..9e3a1a8f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -737,7 +737,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_EngineerFix_Dispenser_Input(1); break; } - if(arg2 == "armour" || arg2 == "armor") { + if(arg2 == "armor" || arg2 == "armor") { Menu_EngineerFix_Dispenser_Input(2); break; } @@ -750,7 +750,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Dispenser_Input(1); break; } - if(arg3 == "armour" || arg3 == "armor") { + if(arg3 == "armor" || arg3 == "armor") { Menu_Dispenser_Input(2); break; } @@ -869,7 +869,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "cmd detpack [#|cancel]\n"); sprint(self, PRINT_HIGH, "cmd build [cancel|sentry|dispenser|destroy {sentry|dispenser}]\n"); sprint(self, PRINT_HIGH, "cmd sentry [rotate #]\n"); - sprint(self, PRINT_HIGH, "cmd dispenser [ammo|armour|repair|withdraw {ammo|armour}]\n"); + sprint(self, PRINT_HIGH, "cmd dispenser [ammo|armor|repair|withdraw {ammo|armor}]\n"); sprint(self, PRINT_HIGH, "cmd captainpick #\n"); sprint(self, PRINT_HIGH, "cmd break\b: end current map\b\n"); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index e61d9d67..a73359eb 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -570,6 +570,7 @@ float server_huetf; float old_spanner; float old_dispenser; float old_hp_armor; +float max_armor_hwguy; float ng_velocity; float ng_damage; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 9f7191ef..be5433cd 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1890,10 +1890,14 @@ void () TeamFortress_SetEquipment = { self.no_grenades_1 = role.gren1_limits[6]; self.no_grenades_2 = role.gren2_limits[6]; - if (old_hp_armor) + if (old_hp_armor) { self.armorvalue = 300; - else + } else if (max_armor_hwguy) { + self.armorvalue = max_armor_hwguy; + } else { self.armorvalue = PC_HVYWEAP_MAXARMOR; + } + } else { self.ammo_rockets = PC_HVYWEAP_INITAMMO_ROCKET; self.ammo_nails = PC_HVYWEAP_INITAMMO_NAIL; @@ -1928,10 +1932,15 @@ void () TeamFortress_SetEquipment = { self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS; self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE; - if (old_hp_armor) + + if (old_hp_armor) { self.maxarmor = 300; - else + } else if (max_armor_hwguy) { + self.maxarmor = max_armor_hwguy; + } else { self.maxarmor = PC_HVYWEAP_MAXARMOR; + } + if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SUPER_SHOTGUN; From 05830dbcc40ceab5c3683aa9cdb68b53d39a9f8d Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 4 Apr 2021 21:40:33 +1000 Subject: [PATCH 1233/2474] Update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e7deeec2..7ed16668 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* Option to configure hwguy armor `localinfo max_armor_hwguy 250`. * option to let engineer move while building `localinfo em on`. * new brush ent ``trigger_jumper`` - an alias for ``trigger_push`` with spawnflags 16 - retains your x/y velocity, only boosting your z by the .speed value. * new csqc command ``fo_menu_vote`` shows the list of maps available to vote. @@ -65,7 +66,7 @@ New features * Keys and flags glow their colour. * Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime`. * Option to fully restock player on cap. `localinfo stock_on_cap on`. -* Option for packs to fully restock health and armour of player. `localinfo stockfull on`. +* Option for packs to fully restock health and armor of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. * Map vote (4 random maps + current map) during last few minutes of game (shown for newly spawned or toggled with /togglevote). * Force early map vote using /votenext, /votetrick (trick maps) and /voterace (race maps). From 938ffc769a36d9de45a2298d15bcc4c12f0af701 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 4 Apr 2021 21:46:37 +1000 Subject: [PATCH 1234/2474] Remove uneeded if statement --- ssqc/tfort.qc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 72c82760..36d0091b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1892,10 +1892,8 @@ void () TeamFortress_SetEquipment = { if (old_hp_armor) { self.armorvalue = 300; - } else if (max_armor_hwguy) { - self.armorvalue = max_armor_hwguy; } else { - self.armorvalue = PC_HVYWEAP_MAXARMOR; + self.armorvalue = max_armor_hwguy; } } else { @@ -1935,10 +1933,8 @@ void () TeamFortress_SetEquipment = { if (old_hp_armor) { self.maxarmor = 300; - } else if (max_armor_hwguy) { - self.maxarmor = max_armor_hwguy; } else { - self.maxarmor = PC_HVYWEAP_MAXARMOR; + self.maxarmor = max_armor_hwguy; } if (self.last_playerclass != self.playerclass) From c54efcd8e7835751e2384adf54995e5e14ba6743 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 4 Apr 2021 21:49:47 +1000 Subject: [PATCH 1235/2474] Fix inconsistent armor spelling --- csqc/menu.qc | 4 ++-- share/defs.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index b1aa839f..8d084579 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -346,7 +346,7 @@ var fo_menu FO_MENU_SENTRY_ROTATE = { var fo_menu FO_MENU_DISPENSER_MAINTAIN = { [0,0], [300,200], "Dispenser", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Insert Ammo","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser ammo\n");Menu_Cancel();},MENU_BUTTON}, - {"2","Insert Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser armour\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Insert Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser armor\n");Menu_Cancel();},MENU_BUTTON}, {"3","Repair","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser repair\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, @@ -361,7 +361,7 @@ var fo_menu FO_MENU_DISPENSER_MAINTAIN = { var fo_menu FO_MENU_DISPENSER_USE = { [0,0], [300,200], "Use Dispenser", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Withdraw Ammo","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw ammo\n");Menu_Cancel();},MENU_BUTTON}, - {"2","Withdraw Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armour\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Withdraw Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armor\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 4, TRUE, { diff --git a/share/defs.h b/share/defs.h index ab58288d..8542491a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -254,7 +254,7 @@ #define TFSTATE_CONCUSSED 524288 // Defines used by TF_T_Damage (see combat.qc) -#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target +#define TF_TD_IGNOREARMOUR 1 // Bypasses the armor of the target #define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) #define TF_TD_NOTSELF 4 // Doesn't damage self @@ -1465,4 +1465,4 @@ #define TEAM_BLUE 1 #define TEAM_RED 2 #define TEAM_YELL 3 -#define TEAM_GREN 4 \ No newline at end of file +#define TEAM_GREN 4 From b4fd5db198a2b7697e3a2bda57ad930f1833e367 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 4 Apr 2021 22:06:12 +1000 Subject: [PATCH 1236/2474] Fix broken disp and use american spelling for all instances of armor --- csqc/csdefs.qc | 2 +- csqc/menu.qc | 4 ++-- share/defs.h | 2 +- ssqc/client.qc | 2 +- ssqc/combat.qc | 2 +- ssqc/medic.qc | 2 +- ssqc/triggers.qc | 2 +- ssqc/weapons.qc | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 12f20ca7..265abdb7 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -317,7 +317,7 @@ const float HASH_REPLACE = 256; /* Used with hash_add. Attempts to remove the ol const float STAT_HEALTH = 0; const float STAT_WEAPON = 2; const float STAT_AMMO = 3; -const float STAT_ARMOUR = 4; +const float STAT_ARMOR = 4; const float STAT_WEAPONFRAME = 5; const float STAT_SHELLS = 6; const float STAT_NAILS = 7; diff --git a/csqc/menu.qc b/csqc/menu.qc index 8d084579..44b2c386 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -346,7 +346,7 @@ var fo_menu FO_MENU_SENTRY_ROTATE = { var fo_menu FO_MENU_DISPENSER_MAINTAIN = { [0,0], [300,200], "Dispenser", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Insert Ammo","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser ammo\n");Menu_Cancel();},MENU_BUTTON}, - {"2","Insert Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser armor\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Insert Armor","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser armor\n");Menu_Cancel();},MENU_BUTTON}, {"3","Repair","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser repair\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, @@ -361,7 +361,7 @@ var fo_menu FO_MENU_DISPENSER_MAINTAIN = { var fo_menu FO_MENU_DISPENSER_USE = { [0,0], [300,200], "Use Dispenser", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { {"1","Withdraw Ammo","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw ammo\n");Menu_Cancel();},MENU_BUTTON}, - {"2","Withdraw Armour","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armor\n");Menu_Cancel();},MENU_BUTTON}, + {"2","Withdraw Armor","","",FO_MENU_STATE_NORMAL,{localcmd("cmd dispenser withdraw armor\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 4, TRUE, { diff --git a/share/defs.h b/share/defs.h index 8542491a..33d786a2 100644 --- a/share/defs.h +++ b/share/defs.h @@ -254,7 +254,7 @@ #define TFSTATE_CONCUSSED 524288 // Defines used by TF_T_Damage (see combat.qc) -#define TF_TD_IGNOREARMOUR 1 // Bypasses the armor of the target +#define TF_TD_IGNOREARMOR 1 // Bypasses the armor of the target #define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) #define TF_TD_NOTSELF 4 // Doesn't damage self diff --git a/ssqc/client.qc b/ssqc/client.qc index 659c1da6..05ca8b25 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1375,7 +1375,7 @@ void () ResetPlayers = { if(te.health > 0) { stuffcmd(te, "f_respawn\n"); if(round_winner_print_health) { - bprint(PRINT_HIGH, te.netname, ": \sHealth:\s ", ftos(te.health), " \sArmour:\s " , ftos(te.armorvalue), "\n"); + bprint(PRINT_HIGH, te.netname, ": \sHealth:\s ", ftos(te.health), " \sArmor:\s " , ftos(te.armorvalue), "\n"); } } oldself = self; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index b49d079b..7ceb4c71 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -471,7 +471,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, } } - if (T_flags & TF_TD_IGNOREARMOUR) { + if (T_flags & TF_TD_IGNOREARMOR) { take = damage; save = 0; diff --git a/ssqc/medic.qc b/ssqc/medic.qc index 10a8d27c..17dd697b 100644 --- a/ssqc/medic.qc +++ b/ssqc/medic.qc @@ -198,7 +198,7 @@ void () BioInfection_Decay = { else self.nextthink = time + 1; deathmsg = DMSG_BIOWEAPON; - TF_T_Damage(self.owner, self, self.enemy, 8, TF_TD_IGNOREARMOUR, TF_TD_OTHER); + TF_T_Damage(self.owner, self, self.enemy, 8, TF_TD_IGNOREARMOR, TF_TD_OTHER); SpawnBlood(self.owner.origin, 30); }; diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 4e2ed989..91b5a0b3 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -484,7 +484,7 @@ void () hurt_touch = { } self.solid = SOLID_NOT; deathmsg = DMSG_TRIGGER; - TF_T_Damage(other, self, self, self.dmg, TF_TD_IGNOREARMOUR, + TF_T_Damage(other, self, self, self.dmg, TF_TD_IGNOREARMOR, TF_TD_OTHER); self.think = hurt_on; self.nextthink = time + 1; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 99921b68..0a10c8d1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -211,7 +211,7 @@ void () W_FireAxe = { if (crossproducttf(def, v_forward) > 0) { deathmsg = DMSG_BACKSTAB; TF_T_Damage(trace_ent, self, self, 120, - TF_TD_NOTTEAM | TF_TD_IGNOREARMOUR, + TF_TD_NOTTEAM | TF_TD_IGNOREARMOR, TF_TD_OTHER); } else { deathmsg = DMSG_AXE; From d05cb3bc7a36886af0695c76bf59048bb2ff86c9 Mon Sep 17 00:00:00 2001 From: drzel Date: Sun, 4 Apr 2021 22:07:35 +1000 Subject: [PATCH 1237/2474] Remove pointless or statement --- ssqc/commands.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a563f90c..085dad48 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -738,7 +738,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_EngineerFix_Dispenser_Input(1); break; } - if(arg2 == "armor" || arg2 == "armor") { + if(arg2 == "armor") { Menu_EngineerFix_Dispenser_Input(2); break; } @@ -751,7 +751,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Menu_Dispenser_Input(1); break; } - if(arg3 == "armor" || arg3 == "armor") { + if(arg3 == "armor") { Menu_Dispenser_Input(2); break; } From 9e87ef1ee8d340610d9bc3eca67b80c737fbc8cb Mon Sep 17 00:00:00 2001 From: me Date: Wed, 7 Apr 2021 22:41:49 +1200 Subject: [PATCH 1238/2474] #630 - team scores init on spec join --- ssqc/spect.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 4ceef067..4db597f0 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -56,6 +56,7 @@ void () SpectatorConnect = { if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { InitAllStatuses(self); UpdateClientMOTD(self); + UpdateClientTeamScores(self); UpdateClientPrematch(self, !cb_prematch); UpdateClient_VoteMap_AddAll(self); } From 6a70b629ef647786e8e1269ee3515db1f4f17387 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 12:44:16 +1000 Subject: [PATCH 1239/2474] Allow quickshot while building --- ssqc/weapons.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 4d59c39b..cc616b7e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3358,8 +3358,7 @@ void () W_WeaponFrame = { } // +slot1-4 quick fire - } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 - && !self.is_building && !self.is_detpacking) { + } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && !self.is_detpacking) { self.is_quickfiring = 1; self.has_quickfired = 0; From 1b31eb0e93a4293ea31a50967d045a08a2781975 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 13:01:46 +1000 Subject: [PATCH 1240/2474] Add quick aliases --- README.md | 2 +- menu/options_keys.qc | 10 +++++----- ssqc/tforthlp.qc | 8 ++++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 49b86dae..5f7879be 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ New features * Grenade slot switching (/grenswitch). * Prime/throw grenades with one button (/gren1 and /gren2). * Weapon slots (1-4) where 1 is always primary and 4 is always melee. -* Quick attack aliases (+slot1-4). +* Quick attack aliases (+quick1-4 will switch weapon and fire. +slot1-4 will do the same and switch back). * Next/previous weapon (/weapprev and /weapnext). * Last weapon (/weaplast). * Remember current weapon and last weapon after dying. diff --git a/menu/options_keys.qc b/menu/options_keys.qc index 360e4cb7..3f8bf92c 100644 --- a/menu/options_keys.qc +++ b/menu/options_keys.qc @@ -50,14 +50,14 @@ const static struct {0, 0}, {_(""), "Advanced Weaponry"}, {0, 0}, - {_("Fire Primary"), "+fire1"}, - {_("Fire Secondary"), "+fire2"}, - {_("Fire Tertiary"), "+fire3"}, - {_("Fire Melee"), "+fire4"}, + {_("Fire Primary"), "+quick1"}, + {_("Fire Secondary"), "+quick2"}, + {_("Fire Tertiary"), "+quick3"}, + {_("Fire Melee"), "+quick4"}, {_("Quick Primary"), "+slot1"}, {_("Quick Secondary"), "+slot2"}, {_("Quick Tertiary"), "+slot3"}, - {_("Quick Melee"), "+slot4"}, + {_("Quick Melee"), "+slot4"}, {_("Prime Grenade 1"), "primeone"}, {_("Prime Grenade 2"), "primetwo"}, {_("Throw Grenade"), "throwgren"}, diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index e28d473f..044bfa58 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -248,6 +248,14 @@ void () TeamFortress_MOTD = { TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo TeamFortress_AliasString("break", "cmd break"); + TeamFortress_AliasString("+quick1", "impulse 1;+attack"); + TeamFortress_AliasString("-quick1", "-attack"); + TeamFortress_AliasString("+quick2", "impulse 2;+attack"); + TeamFortress_AliasString("-quick2", "-attack"); + TeamFortress_AliasString("+quick3", "impulse 3;+attack"); + TeamFortress_AliasString("-quick3", "-attack"); + TeamFortress_AliasString("+quick4", "impulse 4;+attack"); + TeamFortress_AliasString("-quick4", "-attack"); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) Menu_Login(); From 52de462ebddf600340bdc9831a5463508c16630d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 14:06:09 +1000 Subject: [PATCH 1241/2474] Make engineer_move default on --- README.md | 2 +- ssqc/client.qc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 49b86dae..a012eb64 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ New features * Pyro types - `localinfo pyro_type val` - 0 = original tf2.9, 1 = oztf pyro style, 2 = FO pyro style * localinfo server_sbflaginfo : 0 - disables sbar flaginfo, 1 enables it [default: 1] * localinfo reverse_cap : 0 - normal gameplay, 1: you have to take your flag and capture in the enemy base [default: 0] -* localinfo engineer_move / em : 0 - normal gameplay, 1: engineers can move while building [default: 0] +* localinfo engineer_move / em : 0 - normal gameplay, 1: engineers can move while building [default: 1] * localinfo round_delay_time : interval time between rounds in quadmode - seconds [default: 30] * localinfo max_gren2_soldier : maximum number of active nail/shock grenades (TF 2.8 = 3, OzTF = 1) [default: 3] diff --git a/ssqc/client.qc b/ssqc/client.qc index 7044ae5b..90f335ff 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -711,8 +711,8 @@ void () DecodeLevelParms = { nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); // enable server-side flaginfo on statusbar [on] -// server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); - + // server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); + reverse_cap = CF_GetSetting("rcap","reverse_cap", "0"); if (reverse_cap) @@ -720,7 +720,7 @@ void () DecodeLevelParms = { InitReverseCap(); } - engineer_move = CF_GetSetting("em","engineer_move", "0"); + engineer_move = CF_GetSetting("em","engineer_move", "1"); max_active_gren2_soldier = CF_GetSetting("mg2s","max_active_gren2_soldier", "3"); From 217d2b3c0fbe24400876bc32ca66c8ab7359fcd0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 17:05:47 +1000 Subject: [PATCH 1242/2474] Move default teamscore location --- csqc/hud.qc | 5 +++-- csqc/status.qc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index b5a8cd26..ab344bb7 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -98,6 +98,7 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; Hud_Panels[HUD_PANEL_SHOWSCORES].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_SHOWSCORES].FillSize.x / 2), 30]; Hud_Panels[HUD_PANEL_SHOWSCORES].Scale = 1.00; + Hud_Panels[HUD_PANEL_TEAM_SCORE].Position = [(width - Hud_Panels[HUD_PANEL_TEAM_SCORE].FillSize.x), 0]; Hud_Panels[HUD_PANEL_MAP_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MAP_MENU].FillSize.x / 2), 30]; Hud_Panels[HUD_PANEL_MAP_MENU].Scale = 1.00; } @@ -533,8 +534,9 @@ void(string panelid) Hud_DrawTeamScorePanel = { FO_Hud_Panel* panel = getHudPanelPointer(id); vector position = getPosition(id); + vector size = getFillSize(id); - float textScale = panel.TextScale?panel.TextScale:panel.Scale; + float textScale = panel.TextScale ? panel.TextScale : panel.Scale; float sizex, sizey; sizex = size_x; sizey = size_y; @@ -550,7 +552,6 @@ void(string panelid) Hud_DrawTeamScorePanel = { // click event if (fo_hud_editor) { - } } diff --git a/csqc/status.qc b/csqc/status.qc index 867c13de..e7cab030 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -840,7 +840,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, - {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, + {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'0 0','72 12',2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 30','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; From 2bb1c3bf8255e3d15206029faefd318302543375 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 17:09:34 +1000 Subject: [PATCH 1243/2474] Make normal medic default --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 1e5ad4a0..8721f780 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -388,7 +388,7 @@ void () DecodeLevelParms = { nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_LASER)); // medic types 0 = MEDIC_TYPE_DEFAULT, 1 = MEDIC_TYPE_BLAST - medic_type = CF_GetSetting("mcgt", "medic_type", ftos(MEDIC_TYPE_BLAST)); + medic_type = CF_GetSetting("mcgt", "medic_type", ftos(MEDIC_TYPE_DEFAULT)); // how many rotations the nailgren does [2] lasergren_rotationcount = CF_GetSetting("lgrc", "lasergren_rotationcount", ftos(NGR_LASER_DEFAULT_ROTATIONCOUNT)); From 22422a37f41037fd6dc56b0f3613a631319f130f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 17:12:26 +1000 Subject: [PATCH 1244/2474] Make default heavy armor 300 --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 33d786a2..31006475 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1006,7 +1006,7 @@ #define PC_HVYWEAP_MAXHEALTH 100 #define PC_HVYWEAP_MAXSPEED 230 #define PC_HVYWEAP_MAXSTRAFESPEED 230 -#define PC_HVYWEAP_MAXARMOR 250 +#define PC_HVYWEAP_MAXARMOR 300 #define PC_HVYWEAP_INITARMOR 150 #define PC_HVYWEAP_MAXARMORTYPE 0.8 #define PC_HVYWEAP_INITARMORTYPE 0.8 From bfc00e071bbd399ba5c0bc44f3b30fc31b2c7430 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 20:00:02 +1000 Subject: [PATCH 1245/2474] Don't make blast medic default in huetf --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 8721f780..ca7b7e0b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -890,7 +890,7 @@ void () DecodeLevelParms = { scoutdash = FALSE; fo_flash = FALSE; nailgren_type = NGR_TYPE_DEFAULT; - medic_type = MEDIC_TYPE_BLAST; + medic_type = MEDIC_TYPE_DEFAULT; Role_None.detpipe_limit = 7; detpipe_limit_world = 7; medicaura = FALSE; From 1ca7a40140670c9558631d1d533746560eac23b2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Apr 2021 20:02:15 +1000 Subject: [PATCH 1246/2474] Fix bad comment --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ca7b7e0b..c9ed05a8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -564,7 +564,7 @@ void () DecodeLevelParms = { // use old init/max hp/armor [off] old_hp_armor = CF_GetSetting("oh", "old_hp_armor", "off"); - // configure max armor of heavy weapons guy [250] + // configure max armor of heavy weapons guy [300] max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); // delay respawning by this many seconds [0] From 4af90a762182d3db00ee1719a2c57cbea2629ccc Mon Sep 17 00:00:00 2001 From: LD Date: Sun, 11 Apr 2021 10:17:58 -0400 Subject: [PATCH 1247/2474] Adding pyro airblast to HUD --- csqc/csextradefs.qc | 2 ++ csqc/events.qc | 3 +++ csqc/hud.qc | 19 ++++++++++++++++++- ssqc/pyro.qc | 2 ++ ssqc/qw.qc | 2 +- ssqc/status.qc | 10 ++++++++++ ssqc/tfort.qc | 2 ++ 7 files changed, 38 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3b44672a..9e543e23 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -215,6 +215,8 @@ typedef struct { float AuraStatus; // hwguy float LockedCannon; + // pyro + float AirBlast; // spy float IsUndercover; float InvisOnly; diff --git a/csqc/events.qc b/csqc/events.qc index 339012dc..61d190e0 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -351,6 +351,9 @@ void ParseSBAR() case PC_HVYWEAP: SBAR.LockedCannon = readfloat(); break; + case PC_PYRO: + SBAR.AirBlast = readfloat(); + break; case PC_SPY: SBAR.IsUndercover = readfloat(); diff --git a/csqc/hud.qc b/csqc/hud.qc index ab344bb7..d425df87 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -762,7 +762,6 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) switch (SBAR.PlayerClass) { case PC_SOLDIER: - case PC_PYRO: return; } @@ -894,6 +893,24 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); } break; + case PC_PYRO: + if (SBAR.AirBlast) + { + icon = ICON_PYRO; //HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + + msg = "Airblast Cooling Down"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } + else if (!SBAR.AirBlast) + { + icon = ICON_PYRO; //HudIcons[playerclass+6].icon; + drawpic(pos, icon, size, '1 1 1', 1, 0); + + msg = "Airblast Ready"; + DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + } + break; case PC_SPY: if (SBAR.IsUndercover == 1) { diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index c2ac3cad..9422ab71 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -755,6 +755,7 @@ void () TeamFortress_FlameThrower = { }; void () AirBlastReloadFinished = { + self.owner.airblast_cooldown = 0; sprint(self.owner, PRINT_HIGH, "Airblast ready\n"); stuffcmd(self.owner, "play weapons/airblast.wav\n"); dremove(self); @@ -763,6 +764,7 @@ void () AirBlastReloadFinished = { void () UseAirBlast = { if (self.special_cooldown < time) { + self.airblast_cooldown = 1; self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; entity timer = spawn(); timer.owner = self; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 146a956c..d9319f68 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -728,4 +728,4 @@ float FO_FlashDimension; .string broadcast_high; .float special_cooldown; - +.float airblast_cooldown; diff --git a/ssqc/status.qc b/ssqc/status.qc index b0a3d947..01387ec3 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -935,6 +935,16 @@ void UpdateClientStatusBar(entity pl) WriteFloat(MSG_MULTICAST, l); break; + case PC_PYRO: + if(pl.airblast_cooldown == 1) + { + WriteFloat(MSG_MULTICAST, TRUE); + } + else if (pl.airblast_cooldown == 0) + { + WriteFloat(MSG_MULTICAST, FALSE); + } + break; case PC_SPY: WriteFloat(MSG_MULTICAST, pl.is_undercover); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 36d0091b..a47ff3ec 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -68,6 +68,7 @@ void () UseSpecialSkill = { case PC_PYRO: if (pyro_type == PYRO_FO) UseAirBlast(); + Status_Refresh(self); break; case PC_SPY: self.impulse = TF_SPY_DIE; @@ -1528,6 +1529,7 @@ void () TeamFortress_SetEquipment = { } self.is_building = 0; self.is_detpacking = 0; + self.airblast_cooldown = 0; self.is_undercover = 0; self.is_feigning = 0; self.is_unabletospy = 0; From d887ef691a4787f1d6f3c42859cdf5abc957fc4d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Apr 2021 16:25:40 +1000 Subject: [PATCH 1248/2474] Fix purple flag --- ssqc/tfortmap.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 4e4a03e1..87ea4724 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -222,9 +222,6 @@ void () TF_PlaceItem = { self.movetype = 0; self.oldorigin = self.origin; - if (self.goal_activation & TFGI_ITEMGLOWS) - self.effects = self.effects | EF_DIMLIGHT; - if (item_list_bit == 0) item_list_bit = 1; From dca37f05bc77e79913aa12d9f30c9765d34ce36c Mon Sep 17 00:00:00 2001 From: me Date: Fri, 21 May 2021 22:06:53 +1200 Subject: [PATCH 1249/2474] explicit dropammo doesn't show menu; optional amount --- ssqc/commands.qc | 10 +++++++--- ssqc/menu.qc | 4 ++-- ssqc/tfort.qc | 14 +++++++------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 085dad48..e32a95d1 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -448,8 +448,12 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if (arg2) { if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { inp = stof(arg2); - TeamFortress_DropAmmo(inp); - Menu_Drop(); + farg3 = stof(arg3); + if(farg3 < 0) { + farg3 = 0; + } + TeamFortress_DropAmmo(inp, farg3); + //Menu_Drop(); break; } sprint(self, PRINT_HIGH, "Invalid choice. Please use values 1-4.\n"); @@ -860,7 +864,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } else { sprint(self, PRINT_HIGH, "cmd changeteam [#|auto]\n"); sprint(self, PRINT_HIGH, "cmd changeclass [#]\n"); - sprint(self, PRINT_HIGH, "cmd dropammo [1-4]\n"); + sprint(self, PRINT_HIGH, "cmd dropammo [1-4] [amount]\n"); sprint(self, PRINT_HIGH, "cmd disguise [last|none|skin #|team #]\n"); sprint(self, PRINT_HIGH, "cmd menu\n"); sprint(self, PRINT_HIGH, "cmd autoscan\n"); diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 6011ca5b..978fdef5 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -36,7 +36,7 @@ void (entity p) TeamFortress_SetSkin; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; -void (float type) TeamFortress_DropAmmo; +void (float type, float amount) TeamFortress_DropAmmo; void (entity disp) Engineer_Dispenser_InsertAmmo; void (entity disp) Engineer_Dispenser_InsertArmor; void (entity disp) Engineer_Dispenser_Repair; @@ -449,7 +449,7 @@ void (float update) Menu_Class = { void (float inp) Menu_Drop_Input = { if ((inp > 0) && (inp < 5)) { - TeamFortress_DropAmmo(inp); + TeamFortress_DropAmmo(inp, 0); Menu_Drop(); } }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index a47ff3ec..3247d0d3 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2558,12 +2558,12 @@ void () TeamFortress_CheckClassStats = { self.items = self.items | IT_ARMOR1; }; -void (float type) TeamFortress_DropAmmo = { - local float ammo; - ammo = 0; +void (float type, float ammo) TeamFortress_DropAmmo = { + //local float ammo; + //ammo = 0; if (type == 1) { - ammo = DROP_SHELLS; + if(!ammo) ammo = DROP_SHELLS; if (self.ammo_shells < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_SHELLS) >= @@ -2581,7 +2581,7 @@ void (float type) TeamFortress_DropAmmo = { } self.ammo_shells = self.ammo_shells - ammo; } else if (type == 2) { - ammo = DROP_NAILS; + if(!ammo) ammo = DROP_NAILS; if (self.ammo_nails < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_NAILS) >= @@ -2599,7 +2599,7 @@ void (float type) TeamFortress_DropAmmo = { } self.ammo_nails = self.ammo_nails - ammo; } else if (type == 3) { - ammo = DROP_ROCKETS; + if(!ammo) ammo = DROP_ROCKETS; if (self.ammo_rockets < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_ROCKETS) >= @@ -2617,7 +2617,7 @@ void (float type) TeamFortress_DropAmmo = { } self.ammo_rockets = self.ammo_rockets - ammo; } else if (type == 4) { - ammo = DROP_CELLS; + if(!ammo) ammo = DROP_CELLS; if (self.ammo_cells < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_CELLS) >= From 6b84da05fcc59e8fba7afed50a7dc05b2074e99c Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 22 May 2021 22:10:10 +1200 Subject: [PATCH 1250/2474] disp build took cells twice with eng_move enabled --- ssqc/engineer.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index b7b2eff5..e323b013 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -893,7 +893,8 @@ void () TeamFortress_FinishedBuilding = { sprint(self, PRINT_HIGH, "You finish building the dispenser\n"); teamsprint(self.team_no, self, self.netname); teamsprint(self.team_no, self, " has built a dispenser\n"); - self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; + if (!engineer_move) + self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; oldself.classname = "building_dispenser"; oldself.netname = "dispenser"; oldself.blocked = T_Dispenser; From c22f24dd817a6a7e9f5fe4ab17feddd9ced2b71f Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sat, 5 Jun 2021 10:40:48 +1200 Subject: [PATCH 1251/2474] Support snapping hud elements to edges, and then using relative coords --- csqc/csextradefs.qc | 36 +++++++++++ csqc/hud.qc | 135 +++++++++++++++++++++++++++++------------ csqc/hud_helpers.qc | 33 +++++++++- csqc/status.qc | 142 ++++++++++++++++++++++++-------------------- 4 files changed, 240 insertions(+), 106 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3b44672a..5e41e689 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -136,10 +136,45 @@ string HUD_ALIGN[] = { "Center" }; +string HUD_HORIZONTAL_ALIGN[] = { + "Left", + "Center", + "Right" +}; + +string HUD_VERTICAL_ALIGN[] = { + "Top", + "Middle", + "Bottom" +}; + string MENU_OPTION[] = { "1","2","3","4","5","6","7","8","9","0","-","+" }; +const float HUD_SNAP_NONE = 0; +const float HUD_SNAP_LEFT = 1; +const float HUD_SNAP_CENTER = 2; +const float HUD_SNAP_RIGHT = 4; +const float HUD_SNAP_TOP = 8; +const float HUD_SNAP_VCENTER = 16; +const float HUD_SNAP_BOTTOM = 32; + +const float HUD_SNAP_TOP_LEFT = 9; +const float HUD_SNAP_TOP_CENTER = 10; +const float HUD_SNAP_TOP_RIGHT = 12; +const float HUD_SNAP_VCENTER_LEFT = 17; +const float HUD_SNAP_VCENTER_CENTER = 18; +const float HUD_SNAP_VCENTER_RIGHT = 20; +const float HUD_SNAP_BOTTOM_LEFT = 33; +const float HUD_SNAP_BOTTOM_CENTER = 34; +const float HUD_SNAP_BOTTOM_RIGHT = 36; + +const float HUD_SNAP_NORTH = 64; +const float HUD_SNAP_EAST = 128; +const float HUD_SNAP_SOUTH = 256; +const float HUD_SNAP_WEST = 512; + typedef struct { string icon; @@ -329,6 +364,7 @@ typedef struct { FO_Hud_Icons * Icon; float Snap; float Status; + float SnapID; } FO_Hud_Panel; FO_Hud_Panel DrawPanel; diff --git a/csqc/hud.qc b/csqc/hud.qc index b5a8cd26..f7b88857 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -134,6 +134,8 @@ string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { return ftos(panel.Display); case "orientation": return ftos(panel.Orientation); + case "snap": + return ftos(panel.Snap); default: print("^1Setting^7 '", setting, "' does not exist!\n"); break; @@ -157,9 +159,15 @@ void FO_Hud_Editor_Show_Panel(string panelid) = { print("\ttextscale: ", ftos(panel.TextScale), "\n"); print("\tshow: ", ftos(panel.Display), "\n"); print("\torientation: ", ftos(panel.Orientation), "\n"); + print("\tsnap: ", ftos(panel.Snap), "\n"); } void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting) = { + if(panelid == "help" || panelid == "?") { + print("^1orientation^7: Extends from base to the... 0 = Left, 1 = Right, 2 = Middle (where applicable)\n"); + print("^1snap^7: 0 = None, Horzontal: 1/2/4 = Left/Centre/Right, Vertical: 8/16/32 = Top/Middle/Bottom)\n"); + return ""; + } if(setting == "") { FO_Hud_Editor_Show_Panel(panelid); } else { @@ -174,6 +182,8 @@ void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string valu return; } + float val = 0; + FO_Hud_Panel* panel = getHudPanelPointer(id); switch (setting) { case "id": @@ -200,6 +210,20 @@ void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string valu case "orientation": panel.Orientation = stof(value); break; + case "snap": + val = stof(value); + if(val) { + if(val & 1 || val & 2 || val & 4) { + panel.Position.x = 0; + } + if(val & 8 || val & 16 || val & 32) { + panel.Position.y = 0; + } + } else { + panel.Position = getPosition(id); + } + panel.Snap = val; + break; default: print("^1Setting^7 '", setting, "' does not exist!\n"); break; @@ -259,10 +283,11 @@ void(string panelid) Hud_DrawMapMenuPanel = { FO_Hud_Panel* panel = getHudPanelPointer(id); local vector fillsize = panel.FillSize * panel.Scale; local float alpha = fo_hud_editor?0.2:0.9; + local vector position = getPosition(id); if(panel.Display) { setcursormode(TRUE); } - if (hud_panel(panelid, panel.Position, fillsize, alpha, panel.Display)) { + if (hud_panel(panelid, position, fillsize, alpha, panel.Display)) { // click event if (fo_hud_editor) { @@ -292,14 +317,14 @@ void(string panelid) Hud_DrawMapMenuPanel = { local float visiblelistitems = floor(listviewsize.y / listitemsize.y); //Window title - sui_push_frame(panel.Position + [padding,padding], [fillsize.x - padding * 2, titlesize]); + sui_push_frame(position + [padding,padding], [fillsize.x - padding * 2, titlesize]); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); sui_text([padding, 0], [titlesize,titlesize], "Map Selection", MENU_TEXT_4, 1, 0); sui_pop_frame(); //Filter textbox if(vote_list_filter != "") { - sui_push_frame(panel.Position + [padding,padding], listitemsize + [0,padding]); + sui_push_frame(position + [padding,padding], listitemsize + [0,padding]); //sui_border_box([0,0], listitemsize, 1, MENU_BG_DARK, 0.6, 0); sui_fill([0,0], listitemsize + [0,padding], MENU_BG_DARK, 0.6, 0); sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); @@ -324,7 +349,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { */ //sui_scroll_view_begin("scrolltest", panel.Position + [200,4], [100,100], [100,200], listoffset, [2,6]); //sui_scroll_view_end(); - sui_border_box(panel.Position + [padding, padding * 2 + titlesize], listviewsize, 1, MENU_TEXT_SPEC_FO, 0.6, 0); + sui_border_box(position + [padding, padding * 2 + titlesize], listviewsize, 1, MENU_TEXT_SPEC_FO, 0.6, 0); if(vote_list_offset > num_mapvotes_filtered - visiblelistitems) { vote_list_offset = num_mapvotes_filtered - visiblelistitems; } @@ -334,8 +359,8 @@ void(string panelid) Hud_DrawMapMenuPanel = { entity mc = find(world, classname, "map_candidate_filtered"); while(mc) { if(cnt >= vote_list_offset) { - listitempos = panel.Position + [padding, padding * 2 + titlesize + listitemsize.y * (cnt - vote_list_offset)]; - if((listitempos.y + listitemsize.y + padding) > (panel.Position.y + fillsize.y)) { + listitempos = position + [padding, padding * 2 + titlesize + listitemsize.y * (cnt - vote_list_offset)]; + if((listitempos.y + listitemsize.y + padding) > (position.y + fillsize.y)) { //too many to fit break; } @@ -393,11 +418,11 @@ void(string panelid) Hud_DrawMapMenuPanel = { //sui_scrollbar("maplist_scrollbar", [listitemsize.x, fillsize.y - padding * 3 - listitemsize.y], [listitemsize.x,listitemsize.y * num_mapvotes], listoffset, [0,6]); } - sui_border_box(panel.Position, fillsize, 1, MENU_BORDER, 0.6, 0); + sui_border_box(position, fillsize, 1, MENU_BORDER, 0.6, 0); //Map heading - vector mapheadingpos = [panel.Position.x + padding * 2 + listviewsize.x, panel.Position.y + padding * 2 + titlesize]; - float mapinfowidth = fillsize.x - (mapheadingpos.x - panel.Position.x); + vector mapheadingpos = [position.x + padding * 2 + listviewsize.x, position.y + padding * 2 + titlesize]; + float mapinfowidth = fillsize.x - (mapheadingpos.x - position.x); sui_push_frame(mapheadingpos, [mapinfowidth, titlesize]); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); sui_text([padding, 0], [titlesize,titlesize], (vote_selected_item?vote_selected_item.owner.name:"No map selected"), MENU_TEXT_3, 1, 0); @@ -487,7 +512,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { //Map description - vector descriptionpos = [mapheadingpos.x,panel.Position.y + fillsize.y - padding * 4 - titlesize - listitemsize.y * 3] + vector descriptionpos = [mapheadingpos.x,position.y + fillsize.y - padding * 4 - titlesize - listitemsize.y * 3] sui_push_frame(descriptionpos, [mapinfowidth - padding * 2, listitemsize.y * 3]); sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); sui_text([padding / 2, padding / 2], [listitemsize.y,listitemsize.y], vote_selected_item.owner.description, MENU_TEXT_1, 1, 0); @@ -526,26 +551,25 @@ void(string panelid) Hud_DrawTeamScorePanel = { return; } - vector pos; - pos = Hud_Panels[HUD_PANEL_TEAM_SCORE].Position; - float alpha = 0; FO_Hud_Panel* panel = getHudPanelPointer(id); - vector position = getPosition(id); - vector size = getFillSize(id); - float textScale = panel.TextScale?panel.TextScale:panel.Scale; - float sizex, sizey; - sizex = size_x; - sizey = size_y; - vector mediumtext = MENU_TEXT_SMALL * textScale; - local float padding = 0.5 * textScale; + //vector size = getFillSize(id); + float textScale = panel.Scale; //panel.TextScale; //panel.TextScale?panel.TextScale:panel.Scale; + //float sizex, sizey; + //sizex = size_x; + //sizey = size_y; + //vector mediumtext = MENU_TEXT_SMALL * textScale; + local float padding = 0.5; // * textScale; - local vector fillsize = [12,12] * textScale; //mediumtext; + local vector fillsize = [12,12]; // * textScale; //mediumtext; fillsize_x = fillsize_x * 3; fillsize_y = fillsize_y + padding * 2; + panel.FillSize = fillsize; + fillsize = fillsize * textScale; + vector position = getPanelPosition(panel); - if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_TEAM_SCORE].Display)) + if (hud_panel(panelid, position, fillsize, alpha, Hud_Panels[HUD_PANEL_TEAM_SCORE].Display)) { // click event if (fo_hud_editor) @@ -554,12 +578,13 @@ void(string panelid) Hud_DrawTeamScorePanel = { } } - local float offset; local vector score_position = position; local string message = ""; if(panel.Orientation == FO_HUD_INSERT_AFTER) { position_x = position_x - ((number_of_teams - 1) * fillsize_x); + } else if(panel.Orientation == FO_HUD_INSERT_MIDDLE) { + position_x = position_x - (((number_of_teams - 1) * fillsize_x) / 2); } float len; float textOffset; @@ -581,7 +606,6 @@ void(string panelid) Hud_DrawTeamScorePanel = { void Hud_DrawFlagStatusBar(string panelid) { vector pos; - pos = Hud_Panels[HUD_PANEL_FLAGINFO].Position; float sizey, sizex; sizey = FO_Hud_Icon_Size_y * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; sizex = FO_Hud_Icon_Size_x * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; @@ -594,10 +618,14 @@ void Hud_DrawFlagStatusBar(string panelid) flagInfoCount++; } } + //Show one for reference even on maps without if(fo_hud_editor && !flagInfoCount) { flagInfoCount = 1; } vector fillsize = [sizex * 4, sizey * flagInfoCount]; + Hud_Panels[HUD_PANEL_FLAGINFO].FillSize = fillsize; + //pos = getPosition(HUD_PANEL_FLAGINFO); //Hud_Panels[HUD_PANEL_FLAGINFO].Position; + pos = getScaledPanelPosition(getHudPanelPointer(HUD_PANEL_FLAGINFO), 1); float alpha = 0; if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_FLAGINFO].Display)) { @@ -653,9 +681,9 @@ void Hud_ScrollPanelSelector(float num, float numlines) { //Draw the list of all panels void Hud_DrawHudOptionsPanelSelector() { - if(!fo_hud_editor || !Editor_SelectedPanel_Index) + if(!fo_hud_editor) return; - vector pos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; //Start with option panel's pos + vector pos = getPosition(HUD_PANEL_HUDOPTIONS); //Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; //Start with option panel's pos vector size = Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale; //for simplicity, use the same size as options panel float textsize = 8 * (Hud_Panels[HUD_PANEL_HUDOPTIONS].TextScale ? Hud_Panels[HUD_PANEL_HUDOPTIONS].TextScale : Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale); if((pos.x + (size.x * 2)) < ScreenSize.x) { @@ -691,10 +719,10 @@ void Hud_DrawHudOptionsPanelSelector() { void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string icon) { - if(!fo_hud_editor || !Editor_SelectedPanel_Index) + if(!fo_hud_editor) return; - vector pos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; + vector pos = getPosition(HUD_PANEL_HUDOPTIONS); //Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; vector size = Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale; if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, size, 0, Hud_Panels[HUD_PANEL_HUDOPTIONS].Display)) { @@ -738,10 +766,41 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [10,116], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); - if(hud_button("hud_option_show_all_toggle", pos + [4,126], [140, 16], Hud_Panels[HUD_PANEL_HUDOPTIONS].Style ? "Show All" : "Hide Disabled")) { - Hud_Panels[HUD_PANEL_HUDOPTIONS].Style = !Hud_Panels[HUD_PANEL_HUDOPTIONS].Style; + local float snap = 0; + local string ssnap; + if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 2) { + snap = 1; + } else if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 4) { + snap = 2; + } else { + snap = 0; + } + drawstring(pos + [4,130], "Hor. Snap: ", [8,8], MENU_SELECTED, 1, 0); + if(hud_button("hud_option_hsnap_toggle", pos + [size.x - 6 - 56,126], [56, 16], HUD_HORIZONTAL_ALIGN[snap])) { + snap = (snap + 1) % 3; + Hud_Panels[Editor_SelectedPanel_Index].Position.x = 0; + Hud_Panels[Editor_SelectedPanel_Index].Snap -= (Hud_Panels[Editor_SelectedPanel_Index].Snap & 7); + Hud_Panels[Editor_SelectedPanel_Index].Snap += pow(2,snap); + } + if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 16) { + snap = 1; + } else if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 32) { + snap = 2; + } else { + snap = 0; + } + drawstring(pos + [4,148], "Ver. Snap: ", [8,8], MENU_SELECTED, 1, 0); + if(hud_button("hud_option_vsnap_toggle", pos + [size.x - 6 - 56,144], [56, 16], HUD_VERTICAL_ALIGN[snap])) { + snap = (snap + 1) % 3; + Hud_Panels[Editor_SelectedPanel_Index].Position.y = 0; + Hud_Panels[Editor_SelectedPanel_Index].Snap -= (Hud_Panels[Editor_SelectedPanel_Index].Snap & 56); + Hud_Panels[Editor_SelectedPanel_Index].Snap += pow(2,(snap + 3)); } + if(hud_button("hud_option_show_all_toggle", pos + [4,162], [140, 16], Hud_Panels[HUD_PANEL_HUDOPTIONS].Style ? "Show All" : "Hide Disabled")) { + Hud_Panels[HUD_PANEL_HUDOPTIONS].Style = !Hud_Panels[HUD_PANEL_HUDOPTIONS].Style; + } + if(Hud_Panels[HUD_PANEL_HUDOPTIONS].Status) { Hud_DrawHudOptionsPanelSelector(); } @@ -749,9 +808,12 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string void Hud_DrawClassInfoPanel(string id, float playerclass) { + vector pos; + pos = getPosition(HUD_PANEL_PLAYERCLASS); //DrawPanel.Position; + if(fo_hud_editor) { - hud_panel(id, DrawPanel.Position, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display); - drawpic(DrawPanel.Position, "textures/wad/face1.png", FO_Hud_Icon_Size * DrawPanel.Scale, '1 1 1', 1, 0); + hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display); + drawpic(pos, "textures/wad/face1.png", FO_Hud_Icon_Size * DrawPanel.Scale, '1 1 1', 1, 0); return; } @@ -767,8 +829,6 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) if (SBAR.PlayerClass) { - vector pos; - pos = DrawPanel.Position; if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) { @@ -1040,7 +1100,7 @@ void Hud_Draw(float width, float height) if(sui_is_last_clicked(Hud_Panels[i].id)) { Editor_SelectedPanel_Index = i; } - if(!Hud_Panels[HUD_PANEL_HUDOPTIONS].Style || Hud_Panels[i].Display) { + if(!Hud_Panels[HUD_PANEL_HUDOPTIONS].Style || Hud_Panels[i].Display || (fo_hud_editor && i == Editor_SelectedPanel_Index)) { Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); //Draw panel names when editing if(fo_hud_editor && Hud_Panels[i].id != "hudoptionspanel") { @@ -1055,7 +1115,8 @@ void Hud_Draw(float width, float height) offset = (Hud_Panels[i].FillSize.x / 2) - (strlen(Hud_Panels[i].Name) * 3); //because 3 = 6/2 break; } - drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); + //drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); + drawstring(getScaledPanelPosition(getHudPanelPointer(i),1) + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); } } } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 5b3eb3a6..5c4a523e 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -19,6 +19,18 @@ void FO_Hud_Editor() } } +float(float fo_align) fo_to_sui_aligntment = { + switch(fo_align) { + case HUD_ALIGN_RIGHT: + return SUI_ALIGN_END; + case HUD_ALIGN_LEFT: + return SUI_ALIGN_START; + case HUD_ALIGN_CENTER: + return SUI_ALIGN_CENTER; + } + return HUD_ALIGN_CENTER; +}; + void(string id, vector pos, vector size, vector minmaxsteps, __inout float value) hud_slider = { sui_push_frame(pos, size); @@ -75,8 +87,9 @@ float(string id, vector pos, vector size, float alpha, float enabled) hud_panel if (sui_is_held(id)) { - pos = [Mouse.x, Mouse.y]; - pos = UpdatePos(id, pos); + //pos = [Mouse.x, Mouse.y]; + //pos = UpdatePos(id, pos); + UpdatePos(id, [Mouse.x, Mouse.y]); sui_border_box(pos, size, 1, MENU_SELECTED, 0.4, 0); } @@ -189,6 +202,8 @@ string GetPanelString(string line, string name) line = FormatCfgString(line, strcat(name, ".textscale"), ftos(DrawPanel.TextScale)); line = FormatCfgString(line, strcat(name, ".display"), ftos(DrawPanel.Display)); line = FormatCfgString(line, strcat(name, ".nodeinsertloc"), ftos(DrawPanel.Orientation)); + line = FormatCfgString(line, strcat(name, ".snap"), ftos(DrawPanel.Snap)); + line = FormatCfgString(line, strcat(name, ".style"), ftos(DrawPanel.Style)); return line; } @@ -256,6 +271,12 @@ void FO_Hud_Editor_LoadSettings() case "nodeinsertloc": DrawPanel.Orientation = stof(val); break; + case "snap": + DrawPanel.Snap = stof(val); + break; + case "style": + DrawPanel.Style = stof(val); + break; } SetDrawPanel(pnl); @@ -298,9 +319,15 @@ void Hud_DrawPanelLMP(string id, string val, string icon) { if (!DrawPanel.Display && !fo_hud_editor) return; + + float fid = getHudPanel(id); + + if(fid < 0) { + return; + } vector pos; - pos = DrawPanel.Position; + pos = getPosition(fid); //DrawPanel.Position; if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) { diff --git a/csqc/status.qc b/csqc/status.qc index 867c13de..71a4073b 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1,4 +1,6 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, float textsize, float align); +float fo_to_sui_aligntment(float fo_align); +vector (FO_Hud_Panel* panel) getPanelPosition; void(string panelid, float display, string text, string icon) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) @@ -176,83 +178,72 @@ void(string panelid, float display, string text, string icon) drawMOTDPanel = { FO_Hud_Panel* panel = getHudPanelPointer(id); - vector position = getPosition(id); - vector size = getFillSize(id); + //vector position = getPosition(id); + //vector size = getFillSize(id); + vector position = getPanelPosition(panel); //panel.Position; + vector size = panel.FillSize * panel.Scale; + + float textscale = panel.TextScale; + if(!textscale) { + textscale = panel.Scale; + } vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; local float transparency = 0.3; local float lines; - local string gamemode; + local string tempstr; if (fo_hud_editor) { - drawstring( - position + [size.x / 2 - (22 * mediumtext.x)/2,padding*2 + mediumtext.y*2], - "Welcome to FortressOne", - mediumtext, - MENU_TEXT_4, - 1, - 0 - ); - if (hud_panel(panelid, position, size, transparency, panel.Display)) { // click event } - } else { - if(showingscores || !panel.Display) { - return; - } - if(text && text != "") { - if(!intermission && time < motd_expiry && !team_no) { - local string motd = serverkey("hostname"); - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2], - motd, - mediumtext*1.5, - MENU_TEXT_4, - 1, - 0 - ); - if(strlen(SBAR.MOTD) <= 1) { - motd = "Welcome to FortressOne"; - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*2], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - motd = "www.fortressone.org"; + } + if((showingscores || !panel.Display) && !fo_hud_editor) { + return; + } + //if(text && text != "") { + if((!intermission && time < motd_expiry && !team_no) || fo_hud_editor) { + sui_push_frame(position, size); + sui_set_align([fo_to_sui_aligntment(panel.Orientation), SUI_ALIGN_CENTER]); + local string motd = serverkey("hostname"); + sui_text([0,0], mediumtext*textscale*1.5, motd, MENU_TEXT_4, 1, 0); + /* + drawstring( + position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2], + motd, + mediumtext*1.5, + MENU_TEXT_4, + 1, tokenizebyseparator + 0 + ); + */ + if(strlen(SBAR.MOTD) <= 1) { + motd = "Welcome to FortressOne\nwww.fortressone.org"; + } else { + motd = SBAR.MOTD; + } + lines = tokenizebyseparator(motd, "\n"); + for (float i = 0; i <= lines; i++) { + tempstr = argv(i); + // tokenize doesn't handle newlines very well + tempstr = strreplace("\n", "", tempstr); + tempstr = strtrim(tempstr); + if (strlen(tempstr) > 0) { + sui_text([0,mediumtext.y*textscale * (i+2)], mediumtext*textscale, tempstr, MENU_TEXT_1, 1, 0); + /* drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*3], + position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(i+2)], motd, mediumtext, MENU_TEXT_1, 1, 0 ); - lines = 2; - } else { - lines = tokenizebyseparator(SBAR.MOTD, "\n"); - for (float i = 0; i <= lines; i++) { - motd = argv(i); - // tokenize doesn't handle newlines very well - motd = strreplace("\n", "", motd); - motd = strtrim(motd); - if (strlen(motd) > 0) { - drawstring( - position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(i+2)], - motd, - mediumtext, - MENU_TEXT_1, - 1, - 0 - ); - } - } + */ } } + sui_pop_frame(); } - } + //} } void(string panelid, float display, string text, string icon) drawGameModePanel = { @@ -826,14 +817,14 @@ var FO_Hud_Panel Hud_Panels[] = { // Icon, Snap, Status {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, - {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, - {"capspanel",FO_HUD_CAPS_NAME,'10 80','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'10 110','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'10 140','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, + {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, + {"capspanel",FO_HUD_CAPS_NAME,'10 80','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'10 110','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'10 140','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 230','150 260',1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'100 110','50 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, + {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'100 110','26 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, {"menupanel","Menu",'10 110','300 200',1,0,1,0, drawSimplePanel, {return "";}}, {"motdpanel",FO_HUD_MOTD_NAME,'150 100','100 24',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'100 300','300 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, @@ -842,7 +833,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawTeamScorePanel, {return "";}}, {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 30','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, - {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 150',1,0,1,0, doNothing, {return DrawPanel.id;}}, + {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 182',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; float(string panelid) getHudPanel = { @@ -858,8 +849,27 @@ FO_Hud_Panel* (float panelid) getHudPanelPointer = { return &(Hud_Panels[panelid]); }; +vector (FO_Hud_Panel* panel, float scale) getScaledPanelPosition = { + if(panel.Snap == HUD_SNAP_NONE) { + return panel.Position; //Hud_Panels[panelid].Position; + } + vector v = panel.Position; + if(panel.Snap & HUD_SNAP_LEFT) v.x; + if(panel.Snap & HUD_SNAP_CENTER) v.x += (ScreenSize.x / 2) - ((panel.FillSize.x * scale) / 2); + if(panel.Snap & HUD_SNAP_RIGHT) v.x += ScreenSize.x - (panel.FillSize.x * scale); + if(panel.Snap & HUD_SNAP_TOP) v.y; + if(panel.Snap & HUD_SNAP_VCENTER) v.y += (ScreenSize.y / 2) - ((panel.FillSize.y * scale) / 2); + if(panel.Snap & HUD_SNAP_BOTTOM) v.y += ScreenSize.y - (panel.FillSize.y * scale); + return v; +} + +vector (FO_Hud_Panel* panel) getPanelPosition = { + return getScaledPanelPosition(panel, panel.Scale); +} + vector(float panelid) getPosition = { - return Hud_Panels[panelid].Position; + FO_Hud_Panel* panel = getHudPanelPointer(panelid); + return getPanelPosition(panel); } vector(float panelid) getFillSize = { return Hud_Panels[panelid].FillSize; From 9e5ad4d7eaf22f73624772d32c3ede8072428876 Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Thu, 10 Jun 2021 19:33:38 +1200 Subject: [PATCH 1252/2474] vote_style & 4 = no votemode on votemap --- ssqc/client.qc | 16 +++++++++++----- ssqc/world.qc | 4 ++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c9ed05a8..77814a2f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1132,11 +1132,15 @@ void () execute_changelevel = { if(votemode == 1 && vote_result && vote_result != vm) { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); - } else if((vote_style == 1 && (vote_result == vm || vote_result == "")) || votemode == 2) { + } + if((vote_style & 1 && (vote_result == vm || vote_result == "")) || votemode == 2) { vote_result = vm; - localcmd ("localinfo votemode on\n"); + if(!(vote_style & 4)) { + localcmd ("localinfo votemode on\n"); + } //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); - } else if(vote_style == 2 && (vote_result == vm || vote_result == "")) { + } + if(vote_style & 2 && (vote_result == vm || vote_result == "")) { vote_result = mapname; } } @@ -2138,9 +2142,11 @@ void () NextLevel = { if(votemode == 1 && nextmap && nextmap != vm) { localcmd ("localinfo votemode off\n"); //changelevel(vote_result); - } else if(vote_style == 1 || votemode == 2) { + } else if(vote_style & 1 || votemode == 2) { nextmap = vm; - localcmd ("localinfo votemode on\n"); + if(!(vote_style & 4)) { + localcmd ("localinfo votemode on\n"); + } //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); } else { nextmap = mapname; diff --git a/ssqc/world.qc b/ssqc/world.qc index 7dece17c..066c42c2 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -358,9 +358,9 @@ void () worldspawn = { votemode = FALSE; } else { } - } else { + } else if(!(vote_style & 4)) { if(world.model == strcat("maps/",votemap,".bsp")) { - bprint(PRINT_HIGH, "\bEnabling vote mode as map is not\b ",votemap,"\n"); + bprint(PRINT_HIGH, "\bEnabling vote mode as map is\b ",votemap,"\n"); localcmd ("localinfo votemode on\n"); votemode = TRUE; //changelevel(votemap); From 85c97bf73c3e88ade447b68e3e8137a164abe71c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 29 Jun 2021 23:59:30 +1000 Subject: [PATCH 1253/2474] Add EMP gren to start with --- csqc/csextradefs.qc | 6 ++++-- csqc/status.qc | 19 ++++++++++++++++++- share/defs.h | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3b44672a..9a93173b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -144,13 +144,14 @@ typedef struct { string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[29] = { +FO_Hud_Icons HudIcons[30] = { // {""}, {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, {ICON_GREN1}, {ICON_GREN2}, + {ICON_GREN_EMP}, {ICON_IDENTIFY}, {ICON_SCOUT}, {ICON_SNIPER}, @@ -176,10 +177,11 @@ FO_Hud_Icons HudIcons[29] = { {"textures/wad/anum_percent.png"} }; -FO_Hud_Icons GrenadeIcons[3] = { +FO_Hud_Icons GrenadeIcons[4] = { {ICON_GREN1}, {ICON_GREN1}, {ICON_GREN2}, + {ICON_GREN_EMP}, }; typedef struct { diff --git a/csqc/status.qc b/csqc/status.qc index e7cab030..f4ddfcf1 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -47,6 +47,23 @@ void(string panelid, float display, string text, string icon) drawIconPanel = { Hud_DrawPanelLMP(panelid, text, icon); } }; + +void(string panelid, float display, string text, string icon) drawGren2Panel = { + if (display || fo_hud_editor) + { + switch (SBAR.PlayerClass) { + case PC_ENGINEER: + icon = ICON_GREN_EMP; + break; + default: + icon = ICON_GREN2; + } + + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, text, icon); + } +}; + void(string panelid, float display, string text, string icon) drawSpecial = { if (SBAR.PlayerClass || fo_hud_editor) { @@ -829,7 +846,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, {"capspanel",FO_HUD_CAPS_NAME,'10 80','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, {"gren1panel",FO_HUD_GREN1_NAME,'10 110','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'10 140','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren2);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'10 140','50 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 230','150 260',1,0,1,0, drawFlagInfo, {return "";}}, diff --git a/share/defs.h b/share/defs.h index 31006475..3883d99b 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1412,6 +1412,7 @@ #define ICON_IDENTIFY "textures/wad/identify.png" #define ICON_GREN1 "textures/wad/gren1.png" #define ICON_GREN2 "textures/wad/gren2.png" +#define ICON_GREN_EMP "textures/wad/emp.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" #define ICON_SOLDIER "textures/wad/soldier.png" From c354f53b87ff44c22e26d08e99b46fc7b6b89c5a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 30 Jun 2021 01:56:57 +1000 Subject: [PATCH 1254/2474] Rename ICON_GREN1 and ICON_GREN2 --- csqc/csextradefs.qc | 10 +++++----- csqc/status.qc | 4 ++-- share/defs.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9a93173b..b86d42fa 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -149,8 +149,8 @@ FO_Hud_Icons HudIcons[30] = { {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, - {ICON_GREN1}, - {ICON_GREN2}, + {ICON_GREN_FRAG}, + {ICON_GREN_NAIL}, {ICON_GREN_EMP}, {ICON_IDENTIFY}, {ICON_SCOUT}, @@ -178,9 +178,9 @@ FO_Hud_Icons HudIcons[30] = { }; FO_Hud_Icons GrenadeIcons[4] = { - {ICON_GREN1}, - {ICON_GREN1}, - {ICON_GREN2}, + {ICON_GREN_FRAG}, + {ICON_GREN_FRAG}, + {ICON_GREN_NAIL}, {ICON_GREN_EMP}, }; diff --git a/csqc/status.qc b/csqc/status.qc index f4ddfcf1..04a0cf9b 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -56,7 +56,7 @@ void(string panelid, float display, string text, string icon) drawGren2Panel = { icon = ICON_GREN_EMP; break; default: - icon = ICON_GREN2; + icon = ICON_GREN_NAIL; } GetDrawPanel(panelid); @@ -107,7 +107,7 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel } if(fo_hud_editor && (!display || !timercount)) { GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, "0", ICON_GREN1); + Hud_DrawPanelLMP(panelid, "0", ICON_GREN_FRAG); } }; diff --git a/share/defs.h b/share/defs.h index 3883d99b..b40df7b7 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1410,8 +1410,8 @@ #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" #define ICON_CAPS "textures/wad/caps.png" #define ICON_IDENTIFY "textures/wad/identify.png" -#define ICON_GREN1 "textures/wad/gren1.png" -#define ICON_GREN2 "textures/wad/gren2.png" +#define ICON_GREN_FRAG "textures/wad/gren1.png" +#define ICON_GREN_NAIL "textures/wad/gren2.png" #define ICON_GREN_EMP "textures/wad/emp.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" From 2411e65708c2be2d6093c0df57b7f0d92200ce5f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 30 Jun 2021 02:14:39 +1000 Subject: [PATCH 1255/2474] Add HUD icons for scout --- csqc/csextradefs.qc | 4 +++- csqc/status.qc | 21 ++++++++++++++++++++- share/defs.h | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index b86d42fa..9fe88ef1 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -144,7 +144,7 @@ typedef struct { string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[30] = { +FO_Hud_Icons HudIcons[32] = { // {""}, {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, @@ -152,6 +152,8 @@ FO_Hud_Icons HudIcons[30] = { {ICON_GREN_FRAG}, {ICON_GREN_NAIL}, {ICON_GREN_EMP}, + {ICON_GREN_CUSS}, + {ICON_GREN_FLASH}, {ICON_IDENTIFY}, {ICON_SCOUT}, {ICON_SNIPER}, diff --git a/csqc/status.qc b/csqc/status.qc index 04a0cf9b..82881999 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -48,10 +48,29 @@ void(string panelid, float display, string text, string icon) drawIconPanel = { } }; +void(string panelid, float display, string text, string icon) drawGren1Panel = { + if (display || fo_hud_editor) + { + switch (SBAR.PlayerClass) { + case PC_SCOUT: + icon = ICON_GREN_FLASH; + break; + default: + icon = ICON_GREN_FRAG; + } + + GetDrawPanel(panelid); + Hud_DrawPanelLMP(panelid, text, icon); + } +}; + void(string panelid, float display, string text, string icon) drawGren2Panel = { if (display || fo_hud_editor) { switch (SBAR.PlayerClass) { + case PC_SCOUT: + icon = ICON_GREN_CUSS; + break; case PC_ENGINEER: icon = ICON_GREN_EMP; break; @@ -845,7 +864,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, {"capspanel",FO_HUD_CAPS_NAME,'10 80','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'10 110','50 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Gren1);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'10 110','50 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, {"gren2panel",FO_HUD_GREN2_NAME,'10 140','50 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, diff --git a/share/defs.h b/share/defs.h index b40df7b7..a315a161 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1412,6 +1412,8 @@ #define ICON_IDENTIFY "textures/wad/identify.png" #define ICON_GREN_FRAG "textures/wad/gren1.png" #define ICON_GREN_NAIL "textures/wad/gren2.png" +#define ICON_GREN_CUSS "textures/wad/gren_cuss.png" +#define ICON_GREN_FLASH "textures/wad/gren_flash.png" #define ICON_GREN_EMP "textures/wad/emp.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" From cd4823000779c62db5b8a7e6491c7199f58315fb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 1 Jul 2021 00:17:51 +1000 Subject: [PATCH 1256/2474] Add other classes --- csqc/csextradefs.qc | 6 ++++-- csqc/status.qc | 45 +++++++++++++++++++++++++++++++++++++++++++++ share/defs.h | 10 +++++++--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9fe88ef1..f42f9038 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -144,7 +144,7 @@ typedef struct { string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[32] = { +FO_Hud_Icons HudIcons[33] = { // {""}, {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, @@ -154,6 +154,7 @@ FO_Hud_Icons HudIcons[32] = { {ICON_GREN_EMP}, {ICON_GREN_CUSS}, {ICON_GREN_FLASH}, + {ICON_GREN_FLARE}, {ICON_IDENTIFY}, {ICON_SCOUT}, {ICON_SNIPER}, @@ -179,11 +180,12 @@ FO_Hud_Icons HudIcons[32] = { {"textures/wad/anum_percent.png"} }; -FO_Hud_Icons GrenadeIcons[4] = { +FO_Hud_Icons GrenadeIcons[5] = { {ICON_GREN_FRAG}, {ICON_GREN_FRAG}, {ICON_GREN_NAIL}, {ICON_GREN_EMP}, + {ICON_GREN_FLARE}, }; typedef struct { diff --git a/csqc/status.qc b/csqc/status.qc index 82881999..3f9d2dc5 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -55,6 +55,30 @@ void(string panelid, float display, string text, string icon) drawGren1Panel = { case PC_SCOUT: icon = ICON_GREN_FLASH; break; + case PC_SNIPER: + icon = ICON_GREN_FRAG; + break; + case PC_SOLDIER: + icon = ICON_GREN_FRAG; + break; + case PC_DEMOMAN: + icon = ICON_GREN_FRAG; + break; + case PC_MEDIC: + icon = ICON_GREN_FRAG; + break; + case PC_HVYWEAP: + icon = ICON_GREN_FRAG; + break; + case PC_PYRO: + icon = ICON_GREN_FRAG; + break; + case PC_SPY: + icon = ICON_GREN_FRAG; + break; + case PC_ENGINEER: + icon = ICON_GREN_FRAG; + break; default: icon = ICON_GREN_FRAG; } @@ -71,6 +95,27 @@ void(string panelid, float display, string text, string icon) drawGren2Panel = { case PC_SCOUT: icon = ICON_GREN_CUSS; break; + case PC_SNIPER: + icon = ICON_GREN_FLARE; + break; + case PC_SOLDIER: + icon = ICON_GREN_NAIL; + break; + case PC_DEMOMAN: + icon = ICON_GREN_MIRV; + break; + case PC_MEDIC: + icon = ICON_GREN_CUSS; + break; + case PC_HVYWEAP: + icon = ICON_GREN_MIRV; + break; + case PC_PYRO: + icon = ICON_GREN_NAPALM; + break; + case PC_SPY: + icon = ICON_GREN_GAS; + break; case PC_ENGINEER: icon = ICON_GREN_EMP; break; diff --git a/share/defs.h b/share/defs.h index a315a161..829d9fa0 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1410,11 +1410,15 @@ #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" #define ICON_CAPS "textures/wad/caps.png" #define ICON_IDENTIFY "textures/wad/identify.png" -#define ICON_GREN_FRAG "textures/wad/gren1.png" -#define ICON_GREN_NAIL "textures/wad/gren2.png" +#define ICON_GREN_FRAG "textures/wad/gren_frag.png" +#define ICON_GREN_NAIL "textures/wad/gren_nail.png" #define ICON_GREN_CUSS "textures/wad/gren_cuss.png" #define ICON_GREN_FLASH "textures/wad/gren_flash.png" -#define ICON_GREN_EMP "textures/wad/emp.png" +#define ICON_GREN_EMP "textures/wad/gren_emp.png" +#define ICON_GREN_MIRV "textures/wad/gren_mirv.png" +#define ICON_GREN_NAPALM "textures/wad/gren_napalm.png" +#define ICON_GREN_GAS "textures/wad/gren_gas.png" +#define ICON_GREN_FLARE "textures/wad/gren_flare.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" #define ICON_SOLDIER "textures/wad/soldier.png" From 1abb72e24c8a1acbfb73b6eeaec0ebce1a81356e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 4 Jul 2021 03:04:35 +1000 Subject: [PATCH 1257/2474] Fix grenade timer icons --- csqc/csextradefs.qc | 24 ++++++++-- csqc/events.qc | 5 ++ csqc/hud_helpers.qc | 6 +-- csqc/main.qc | 111 ++++++++++++++++++++++++++++++++++++++++++-- share/commondefs.qc | 1 + share/defs.h | 2 + ssqc/client.qc | 3 +- ssqc/csmenu.qc | 12 +++++ 8 files changed, 149 insertions(+), 15 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f42f9038..e4813efa 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -82,6 +82,9 @@ float is_admin; float motd_expiry; float quad_round; float quad_rounds_total; +float fo_flash; +float medic_type; +float nailgren_type; //float game_started; float prematch; float round_active; @@ -144,17 +147,21 @@ typedef struct { string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[33] = { -// {""}, + +FO_Hud_Icons HudIcons[36] = { {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, {ICON_GREN_FRAG}, {ICON_GREN_NAIL}, {ICON_GREN_EMP}, + {ICON_GREN_GAS}, {ICON_GREN_CUSS}, {ICON_GREN_FLASH}, {ICON_GREN_FLARE}, + {ICON_GREN_NAPALM}, + {ICON_GREN_CALTROP}, + {ICON_GREN_BLAST}, {ICON_IDENTIFY}, {ICON_SCOUT}, {ICON_SNIPER}, @@ -180,12 +187,19 @@ FO_Hud_Icons HudIcons[33] = { {"textures/wad/anum_percent.png"} }; -FO_Hud_Icons GrenadeIcons[5] = { - {ICON_GREN_FRAG}, +FO_Hud_Icons GrenadeIcons[12] = { + {}, {ICON_GREN_FRAG}, + {ICON_GREN_CUSS}, {ICON_GREN_NAIL}, - {ICON_GREN_EMP}, + {ICON_GREN_MIRV}, + {ICON_GREN_NAPALM}, {ICON_GREN_FLARE}, + {ICON_GREN_GAS}, + {ICON_GREN_EMP}, + {ICON_GREN_FLASH}, + {ICON_GREN_CALTROP}, + {ICON_GREN_BLAST}, }; typedef struct { diff --git a/csqc/events.qc b/csqc/events.qc index 339012dc..08f1849b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -261,6 +261,11 @@ void() CSQC_Parse_Event = { quad_round = readfloat(); //game_started = readbyte(); break; + case MSG_GRENADESETTINGS: + fo_flash = readfloat(); + medic_type = readfloat(); + nailgren_type = readfloat(); + break; case MSG_GRENTHROWN: grentimer_waiting = FALSE; break; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 5b3eb3a6..fbdf0b3a 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -347,12 +347,8 @@ void AddGrenTimer(float grentype) { for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype == 0) { FO_Hud_Grentimers[i].grentype = grentype; + FO_Hud_Grentimers[i].icon_index = grentype; FO_Hud_Grentimers[i].expires = time + 3.8; - if(grentype == GR_TYPE_NORMAL) { - FO_Hud_Grentimers[i].icon_index = 1; - } else { - FO_Hud_Grentimers[i].icon_index = 2; - } break; } } diff --git a/csqc/main.qc b/csqc/main.qc index 5964f081..110a410c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -208,8 +208,21 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); - AddGrenTimer(1); + float grentype; + + if(SBAR.PlayerClass == PC_SCOUT) { + if(fo_flash) { + grentype = GR_TYPE_FLASH; + } else { + grentype = GR_TYPE_CALTROP; + } + } else { + grentype = GR_TYPE_NORMAL; + } + + AddGrenTimer(grentype); } + grentimer_waiting = TRUE; } localcmd("primeone_server"); @@ -220,7 +233,46 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); - AddGrenTimer(2); + float grentype; + + switch(SBAR.PlayerClass) { + case PC_SCOUT: + grentype = GR_TYPE_CONCUSSION; + break; + case PC_SNIPER: + grentype = GR_TYPE_FLARE; + break; + case PC_SOLDIER: + grentype = GR_TYPE_NAIL; + break; + case PC_DEMOMAN: + grentype = GR_TYPE_MIRV; + break; + case PC_MEDIC: + if(medic_type == MEDIC_TYPE_BLAST) { + grentype = GR_TYPE_BLAST; + } else { + grentype = GR_TYPE_CONCUSSION; + } + break; + case PC_HVYWEAP: + grentype = GR_TYPE_MIRV; + break; + case PC_PYRO: + grentype = GR_TYPE_NAPALM; + break; + case PC_SPY: + grentype = GR_TYPE_GAS; + break; + case PC_ENGINEER: + grentype = GR_TYPE_EMP; + break; + default: + grentype = GR_TYPE_NONE; + break; + } + + AddGrenTimer(grentype); } grentimer_waiting = TRUE; } @@ -232,7 +284,19 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); - AddGrenTimer(1); + float grentype; + + if(SBAR.PlayerClass == PC_SCOUT) { + if(fo_flash) { + grentype = GR_TYPE_FLASH; + } else { + grentype = GR_TYPE_CALTROP; + } + } else { + grentype = GR_TYPE_NORMAL; + } + + AddGrenTimer(grentype); } grentimer_waiting = TRUE; } @@ -244,7 +308,46 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); - AddGrenTimer(2); + float grentype; + + switch(SBAR.PlayerClass) { + case PC_SCOUT: + grentype = GR_TYPE_CONCUSSION; + break; + case PC_SNIPER: + grentype = GR_TYPE_FLARE; + break; + case PC_SOLDIER: + grentype = GR_TYPE_NAIL; + break; + case PC_DEMOMAN: + grentype = GR_TYPE_MIRV; + break; + case PC_MEDIC: + if(medic_type == MEDIC_TYPE_BLAST) { + grentype = GR_TYPE_BLAST; + } else { + grentype = GR_TYPE_CONCUSSION; + } + break; + case PC_HVYWEAP: + grentype = GR_TYPE_MIRV; + break; + case PC_PYRO: + grentype = GR_TYPE_NAPALM; + break; + case PC_SPY: + grentype = GR_TYPE_GAS; + break; + case PC_ENGINEER: + grentype = GR_TYPE_EMP; + break; + default: + grentype = GR_TYPE_NONE; + break; + } + + AddGrenTimer(grentype); } grentimer_waiting = TRUE; } diff --git a/share/commondefs.qc b/share/commondefs.qc index 347d42b2..b128ba24 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -31,6 +31,7 @@ #define MSG_VOTE_UPDATE 19 #define MSG_VOTE_MAP_ADD 20 #define MSG_VOTE_MAP_DELETE 21 +#define MSG_GRENADESETTINGS 22 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/share/defs.h b/share/defs.h index 829d9fa0..1690ecf0 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1419,6 +1419,8 @@ #define ICON_GREN_NAPALM "textures/wad/gren_napalm.png" #define ICON_GREN_GAS "textures/wad/gren_gas.png" #define ICON_GREN_FLARE "textures/wad/gren_flare.png" +#define ICON_GREN_CALTROP "textures/wad/gren_caltrop.png" +#define ICON_GREN_BLAST "textures/wad/gren_blast.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" #define ICON_SOLDIER "textures/wad/soldier.png" diff --git a/ssqc/client.qc b/ssqc/client.qc index c9ed05a8..e463dae3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2029,11 +2029,12 @@ void () PutClientInServer = { self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); } - + if (self.playerclass == 0 && self.team_no > 0) { Menu_Class(0); } + UpdateClientGrenadeSettings(self); }; //void () info_player_start = { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 933178b5..ebeccbe9 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -284,6 +284,18 @@ void UpdateClientPrematch(entity pl, float countdownstarted) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientGrenadeSettings(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_GRENADESETTINGS); + WriteFloat(MSG_MULTICAST, fo_flash); + WriteFloat(MSG_MULTICAST, medic_type); + WriteFloat(MSG_MULTICAST, nailgren_type); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientMapVote(entity pl, entity candidate) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE) || !candidate) return; From 415a35a3786b0b7ff44a7a11f34c216676625a2e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 4 Jul 2021 15:39:22 +1000 Subject: [PATCH 1258/2474] Fix grenade hud indicators for alternate grens --- csqc/csextradefs.qc | 13 +++---- csqc/main.qc | 86 +++++++++++++++++++++++++++++++++++---------- csqc/status.qc | 54 ++++++++++++++++------------ share/defs.h | 5 +-- 4 files changed, 110 insertions(+), 48 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 276afe54..3b87e899 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -148,15 +148,16 @@ typedef struct string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[36] = { +FO_Hud_Icons HudIcons[37] = { {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, - {ICON_GREN_FRAG}, + {ICON_GREN_NONE}, + {ICON_GREN_NORMAL}, {ICON_GREN_NAIL}, {ICON_GREN_EMP}, {ICON_GREN_GAS}, - {ICON_GREN_CUSS}, + {ICON_GREN_CONCUSSION}, {ICON_GREN_FLASH}, {ICON_GREN_FLARE}, {ICON_GREN_NAPALM}, @@ -188,9 +189,9 @@ FO_Hud_Icons HudIcons[36] = { }; FO_Hud_Icons GrenadeIcons[12] = { - {}, - {ICON_GREN_FRAG}, - {ICON_GREN_CUSS}, + {ICON_GREN_NONE}, + {ICON_GREN_NORMAL}, + {ICON_GREN_CONCUSSION}, {ICON_GREN_NAIL}, {ICON_GREN_MIRV}, {ICON_GREN_NAPALM}, diff --git a/csqc/main.qc b/csqc/main.qc index 110a410c..947ab7c8 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -210,14 +210,40 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("play grentimer.wav\n"); float grentype; - if(SBAR.PlayerClass == PC_SCOUT) { - if(fo_flash) { - grentype = GR_TYPE_FLASH; - } else { - grentype = GR_TYPE_CALTROP; - } - } else { - grentype = GR_TYPE_NORMAL; + switch(SBAR.PlayerClass) { + case PC_SCOUT: + if(fo_flash) { + grentype = GR_TYPE_FLASH; + } else { + grentype = GR_TYPE_CALTROP; + } + break; + case PC_SNIPER: + grentype = GR_TYPE_NORMAL; + break; + case PC_SOLDIER: + grentype = GR_TYPE_NORMAL; + break; + case PC_DEMOMAN: + grentype = GR_TYPE_NORMAL; + break; + case PC_MEDIC: + grentype = GR_TYPE_NORMAL; + break; + case PC_HVYWEAP: + grentype = GR_TYPE_NORMAL; + break; + case PC_PYRO: + grentype = GR_TYPE_NORMAL; + break; + case PC_SPY: + grentype = GR_TYPE_NORMAL; + break; + case PC_ENGINEER: + grentype = GR_TYPE_NORMAL; + break; + default: + grentype = GR_TYPE_NONE; } AddGrenTimer(grentype); @@ -269,7 +295,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; default: grentype = GR_TYPE_NONE; - break; } AddGrenTimer(grentype); @@ -286,14 +311,40 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("play grentimer.wav\n"); float grentype; - if(SBAR.PlayerClass == PC_SCOUT) { - if(fo_flash) { - grentype = GR_TYPE_FLASH; - } else { - grentype = GR_TYPE_CALTROP; - } - } else { - grentype = GR_TYPE_NORMAL; + switch(SBAR.PlayerClass) { + case PC_SCOUT: + if(fo_flash) { + grentype = GR_TYPE_FLASH; + } else { + grentype = GR_TYPE_CALTROP; + } + break; + case PC_SNIPER: + grentype = GR_TYPE_NORMAL; + break; + case PC_SOLDIER: + grentype = GR_TYPE_NORMAL; + break; + case PC_DEMOMAN: + grentype = GR_TYPE_NORMAL; + break; + case PC_MEDIC: + grentype = GR_TYPE_NORMAL; + break; + case PC_HVYWEAP: + grentype = GR_TYPE_NORMAL; + break; + case PC_PYRO: + grentype = GR_TYPE_NORMAL; + break; + case PC_SPY: + grentype = GR_TYPE_NORMAL; + break; + case PC_ENGINEER: + grentype = GR_TYPE_NORMAL; + break; + default: + grentype = GR_TYPE_NONE; } AddGrenTimer(grentype); @@ -344,7 +395,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; default: grentype = GR_TYPE_NONE; - break; } AddGrenTimer(grentype); diff --git a/csqc/status.qc b/csqc/status.qc index 3f9d2dc5..69fc416e 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -48,39 +48,44 @@ void(string panelid, float display, string text, string icon) drawIconPanel = { } }; -void(string panelid, float display, string text, string icon) drawGren1Panel = { - if (display || fo_hud_editor) - { - switch (SBAR.PlayerClass) { +void(string panelid, float display, string text) drawGren1Panel = { + local string icon; + + if (display || fo_hud_editor) { + switch(SBAR.PlayerClass) { case PC_SCOUT: - icon = ICON_GREN_FLASH; + if(fo_flash) { + icon = ICON_GREN_FLASH; + } else { + icon = ICON_GREN_CALTROP; + } break; case PC_SNIPER: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; case PC_SOLDIER: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; case PC_DEMOMAN: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; case PC_MEDIC: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; case PC_HVYWEAP: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; case PC_PYRO: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; case PC_SPY: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; case PC_ENGINEER: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NORMAL; break; default: - icon = ICON_GREN_FRAG; + icon = ICON_GREN_NONE; } GetDrawPanel(panelid); @@ -88,12 +93,13 @@ void(string panelid, float display, string text, string icon) drawGren1Panel = { } }; -void(string panelid, float display, string text, string icon) drawGren2Panel = { - if (display || fo_hud_editor) - { - switch (SBAR.PlayerClass) { +void(string panelid, float display, string text) drawGren2Panel = { + local string icon; + + if (display || fo_hud_editor) { + switch(SBAR.PlayerClass) { case PC_SCOUT: - icon = ICON_GREN_CUSS; + icon = ICON_GREN_CONCUSSION; break; case PC_SNIPER: icon = ICON_GREN_FLARE; @@ -105,7 +111,11 @@ void(string panelid, float display, string text, string icon) drawGren2Panel = { icon = ICON_GREN_MIRV; break; case PC_MEDIC: - icon = ICON_GREN_CUSS; + if(medic_type == MEDIC_TYPE_BLAST) { + icon = ICON_GREN_BLAST; + } else { + icon = ICON_GREN_CONCUSSION; + } break; case PC_HVYWEAP: icon = ICON_GREN_MIRV; @@ -120,7 +130,7 @@ void(string panelid, float display, string text, string icon) drawGren2Panel = { icon = ICON_GREN_EMP; break; default: - icon = ICON_GREN_NAIL; + icon = ICON_GREN_NONE; } GetDrawPanel(panelid); @@ -171,7 +181,7 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel } if(fo_hud_editor && (!display || !timercount)) { GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, "0", ICON_GREN_FRAG); + Hud_DrawPanelLMP(panelid, "0", ICON_GREN_NORMAL); } }; diff --git a/share/defs.h b/share/defs.h index 1690ecf0..e295cdb5 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1410,9 +1410,9 @@ #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" #define ICON_CAPS "textures/wad/caps.png" #define ICON_IDENTIFY "textures/wad/identify.png" -#define ICON_GREN_FRAG "textures/wad/gren_frag.png" +#define ICON_GREN_NORMAL "textures/wad/gren_normal.png" #define ICON_GREN_NAIL "textures/wad/gren_nail.png" -#define ICON_GREN_CUSS "textures/wad/gren_cuss.png" +#define ICON_GREN_CONCUSSION "textures/wad/gren_concussion.png" #define ICON_GREN_FLASH "textures/wad/gren_flash.png" #define ICON_GREN_EMP "textures/wad/gren_emp.png" #define ICON_GREN_MIRV "textures/wad/gren_mirv.png" @@ -1421,6 +1421,7 @@ #define ICON_GREN_FLARE "textures/wad/gren_flare.png" #define ICON_GREN_CALTROP "textures/wad/gren_caltrop.png" #define ICON_GREN_BLAST "textures/wad/gren_blast.png" +#define ICON_GREN_NONE "textures/wad/gren_none.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" #define ICON_SOLDIER "textures/wad/soldier.png" From bada7475bced5635c0a8016504915dceb5b8d9da Mon Sep 17 00:00:00 2001 From: "Me (revenant)" Date: Sun, 4 Jul 2021 20:32:47 +1200 Subject: [PATCH 1259/2474] grentimer icon layering fix --- csqc/csextradefs.qc | 1 - csqc/hud_helpers.qc | 21 ++++++---------- csqc/status.qc | 61 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 5604de7b..0a3a8d31 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -110,7 +110,6 @@ string vote_list_filter; .float localmap; float(string) GetDrawPanel; -void(string, string, string) Hud_DrawPanelLMP; void(string id, string identify) Hud_DrawIdentifyPanel; void (string panelid, float display, string text, string icon) Hud_DrawHudOptionsPanel; void (string id, float playerclass) Hud_DrawClassInfoPanel; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 5c4a523e..78b15801 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -315,21 +315,15 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float } // draws value string using lmps -void Hud_DrawPanelLMP(string id, string val, string icon) +void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon) { - if (!DrawPanel.Display && !fo_hud_editor) + if (!panel || (!panel.Display && !fo_hud_editor)) return; - float fid = getHudPanel(id); - - if(fid < 0) { - return; - } - vector pos; - pos = getPosition(fid); //DrawPanel.Position; + pos = getPanelPosition(panel); //getPosition(fid); //DrawPanel.Position; - if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) + if (hud_panel(panel.id, pos, panel.FillSize * panel.Scale, 0, panel.Display)) { // click event if (fo_hud_editor) @@ -338,20 +332,19 @@ void Hud_DrawPanelLMP(string id, string val, string icon) } } - vector size = FO_Hud_Icon_Size * DrawPanel.Scale; + vector size = FO_Hud_Icon_Size * panel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; drawpic(pos, icon, size, '1 1 1', 1, 0); float len; len = strlen(val); - float offset = (DrawPanel.Orientation == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + float offset = (panel.Orientation == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; pos = [pos_x + offset, pos_y, 0]; - float textScale = DrawPanel.TextScale ? DrawPanel.TextScale : DrawPanel.Scale; + float textScale = panel.TextScale ? panel.TextScale : panel.Scale; Hud_DrawStringLMP(pos, val, 24 * textScale); } - vector GetStringOffsetPos(string msg, vector size, vector fontSize, vector pos, vector basepos, float newline) { float len, offset; diff --git a/csqc/status.qc b/csqc/status.qc index c588dd7e..8a6b0444 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1,12 +1,21 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, float textsize, float align); float fo_to_sui_aligntment(float fo_align); vector (FO_Hud_Panel* panel) getPanelPosition; +float getHudPanel(string); +void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string); +FO_Hud_Panel* getHudPanelPointer(float); void(string panelid, float display, string text, string icon) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) { - GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, text, icon); + //GetDrawPanel(panelid); + //Hud_DrawPanelLMP(panelid, text, icon); + float id = getHudPanel(panelid); + + if(id < 0) { + return; + } + Hud_DrawPanelLMP(getHudPanelPointer(id), text, icon); } }; @@ -45,8 +54,15 @@ void(string panelid, float display, string text, string icon) drawFlagInfo = { void(string panelid, float display, string text, string icon) drawIconPanel = { if (display || fo_hud_editor) { - GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, text, icon); + //GetDrawPanel(panelid); + //Hud_DrawPanelLMP(panelid, text, icon); + float id = getHudPanel(panelid); + + if(id < 0) { + return; + } + Hud_DrawPanelLMP(getHudPanelPointer(id), text, icon); + } }; void(string panelid, float display, string text, string icon) drawSpecial = { @@ -61,9 +77,22 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel local float timeleft; local float timercount = 0; if (display) { - GetDrawPanel(panelid); - float Scale = DrawPanel.Scale; - float TextScale = DrawPanel.TextScale; + //GetDrawPanel(panelid); + float id = getHudPanel(panelid); + + if(id < 0) { + return; + } + + FO_Hud_Panel* panel = getHudPanelPointer(id); + + float Scale = panel.Scale; + float TextScale = panel.TextScale; + FO_Hud_Panel panel2; + panel2.Position = panel.Position; + panel2.Scale = panel.Scale; + panel2.TextScale = panel.TextScale; + panel2.Display = panel.Display; for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype > 0) { timeleft = floor(FO_Hud_Grentimers[i].expires - time) + 1; @@ -81,18 +110,24 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel continue; } if(i) { - DrawPanel.Scale = Scale * 0.8; - DrawPanel.TextScale = TextScale * 0.8; + panel2.Scale = Scale * 0.8; + panel2.TextScale = TextScale * 0.8; } - Hud_DrawPanelLMP(panelid, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon); - DrawPanel.Position = DrawPanel.Position + [0, 24 * DrawPanel.Scale]; + Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon); + panel2.Position = panel2.Position + [0, 24 * panel2.Scale]; timercount++; } } } if(fo_hud_editor && (!display || !timercount)) { - GetDrawPanel(panelid); - Hud_DrawPanelLMP(panelid, "0", ICON_GREN1); + //GetDrawPanel(panelid); + //Hud_DrawPanelLMP(panelid, "0", ICON_GREN1); + float id = getHudPanel(panelid); + + if(id < 0) { + return; + } + Hud_DrawPanelLMP(getHudPanelPointer(id), text, icon); } }; From 24030bc382776d22973be359ff2fd0592467c322 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 4 Jul 2021 22:57:49 +1000 Subject: [PATCH 1260/2474] Refactor --- csqc/status.qc | 138 ++++++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 76 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 011b163b..db10867c 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -4,6 +4,8 @@ vector (FO_Hud_Panel* panel) getPanelPosition; float getHudPanel(string); void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string); FO_Hud_Panel* getHudPanelPointer(float); +string GetGrenOneIconForClass(float playerclass); +string GetGrenTwoIconForClass(float playerclass); void(string panelid, float display, string text, string icon) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) @@ -67,86 +69,12 @@ void(string panelid, float display, string text, string icon) drawIconPanel = { }; void(string panelid, float display, string text) drawGren1Panel = { - local string icon; - - switch(SBAR.PlayerClass) { - case PC_SCOUT: - if(fo_flash) { - icon = ICON_GREN_FLASH; - } else { - icon = ICON_GREN_CALTROP; - } - break; - case PC_SNIPER: - icon = ICON_GREN_NORMAL; - break; - case PC_SOLDIER: - icon = ICON_GREN_NORMAL; - break; - case PC_DEMOMAN: - icon = ICON_GREN_NORMAL; - break; - case PC_MEDIC: - icon = ICON_GREN_NORMAL; - break; - case PC_HVYWEAP: - icon = ICON_GREN_NORMAL; - break; - case PC_PYRO: - icon = ICON_GREN_NORMAL; - break; - case PC_SPY: - icon = ICON_GREN_NORMAL; - break; - case PC_ENGINEER: - icon = ICON_GREN_NORMAL; - break; - default: - icon = ICON_GREN_NONE; - } - + local string icon = GetGrenOneIconForClass(SBAR.PlayerClass); drawIconPanel(panelid, display, text, icon); }; void(string panelid, float display, string text) drawGren2Panel = { - local string icon; - - switch(SBAR.PlayerClass) { - case PC_SCOUT: - icon = ICON_GREN_CONCUSSION; - break; - case PC_SNIPER: - icon = ICON_GREN_FLARE; - break; - case PC_SOLDIER: - icon = ICON_GREN_NAIL; - break; - case PC_DEMOMAN: - icon = ICON_GREN_MIRV; - break; - case PC_MEDIC: - if(medic_type == MEDIC_TYPE_BLAST) { - icon = ICON_GREN_BLAST; - } else { - icon = ICON_GREN_CONCUSSION; - } - break; - case PC_HVYWEAP: - icon = ICON_GREN_MIRV; - break; - case PC_PYRO: - icon = ICON_GREN_NAPALM; - break; - case PC_SPY: - icon = ICON_GREN_GAS; - break; - case PC_ENGINEER: - icon = ICON_GREN_EMP; - break; - default: - icon = ICON_GREN_NONE; - } - + local string icon = GetGrenTwoIconForClass(SBAR.PlayerClass); drawIconPanel(panelid, display, text, icon); }; @@ -994,3 +922,61 @@ vector(float panelid) getPosition = { vector(float panelid) getFillSize = { return Hud_Panels[panelid].FillSize; } + +string GetGrenOneIconForClass(float playerclass) { + switch(playerclass) { + case PC_SCOUT: + if(fo_flash) { + return ICON_GREN_FLASH; + } else { + return ICON_GREN_CALTROP; + } + case PC_SNIPER: + return ICON_GREN_NORMAL; + case PC_SOLDIER: + return ICON_GREN_NORMAL; + case PC_DEMOMAN: + return ICON_GREN_NORMAL; + case PC_MEDIC: + return ICON_GREN_NORMAL; + case PC_HVYWEAP: + return ICON_GREN_NORMAL; + case PC_PYRO: + return ICON_GREN_NORMAL; + case PC_SPY: + return ICON_GREN_NORMAL; + case PC_ENGINEER: + return ICON_GREN_NORMAL; + default: + return ICON_GREN_NONE; + } +} + +string GetGrenTwoIconForClass(float playerclass) { + switch(playerclass) { + case PC_SCOUT: + return ICON_GREN_CONCUSSION; + case PC_SNIPER: + return ICON_GREN_FLARE; + case PC_SOLDIER: + return ICON_GREN_NAIL; + case PC_DEMOMAN: + return ICON_GREN_MIRV; + case PC_MEDIC: + if(medic_type == MEDIC_TYPE_BLAST) { + return ICON_GREN_BLAST; + } else { + return ICON_GREN_CONCUSSION; + } + case PC_HVYWEAP: + return ICON_GREN_MIRV; + case PC_PYRO: + return ICON_GREN_NAPALM; + case PC_SPY: + return ICON_GREN_GAS; + case PC_ENGINEER: + return ICON_GREN_EMP; + default: + return ICON_GREN_NONE; + } +} From 447e3840e40f774b8597e994935589d2dd7b050c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 4 Jul 2021 23:15:34 +1000 Subject: [PATCH 1261/2474] Refactor --- csqc/main.qc | 216 +++++++++++++++------------------------------------ 1 file changed, 64 insertions(+), 152 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 947ab7c8..b013601a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,6 +10,8 @@ void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); +float GetGrenOneTypeForClass(float playerclass); +float GetGrenTwoTypeForClass(float playerclass); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -208,44 +210,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); - float grentype; - - switch(SBAR.PlayerClass) { - case PC_SCOUT: - if(fo_flash) { - grentype = GR_TYPE_FLASH; - } else { - grentype = GR_TYPE_CALTROP; - } - break; - case PC_SNIPER: - grentype = GR_TYPE_NORMAL; - break; - case PC_SOLDIER: - grentype = GR_TYPE_NORMAL; - break; - case PC_DEMOMAN: - grentype = GR_TYPE_NORMAL; - break; - case PC_MEDIC: - grentype = GR_TYPE_NORMAL; - break; - case PC_HVYWEAP: - grentype = GR_TYPE_NORMAL; - break; - case PC_PYRO: - grentype = GR_TYPE_NORMAL; - break; - case PC_SPY: - grentype = GR_TYPE_NORMAL; - break; - case PC_ENGINEER: - grentype = GR_TYPE_NORMAL; - break; - default: - grentype = GR_TYPE_NONE; - } - + local float grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } @@ -259,44 +224,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); - float grentype; - - switch(SBAR.PlayerClass) { - case PC_SCOUT: - grentype = GR_TYPE_CONCUSSION; - break; - case PC_SNIPER: - grentype = GR_TYPE_FLARE; - break; - case PC_SOLDIER: - grentype = GR_TYPE_NAIL; - break; - case PC_DEMOMAN: - grentype = GR_TYPE_MIRV; - break; - case PC_MEDIC: - if(medic_type == MEDIC_TYPE_BLAST) { - grentype = GR_TYPE_BLAST; - } else { - grentype = GR_TYPE_CONCUSSION; - } - break; - case PC_HVYWEAP: - grentype = GR_TYPE_MIRV; - break; - case PC_PYRO: - grentype = GR_TYPE_NAPALM; - break; - case PC_SPY: - grentype = GR_TYPE_GAS; - break; - case PC_ENGINEER: - grentype = GR_TYPE_EMP; - break; - default: - grentype = GR_TYPE_NONE; - } - + local float grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; @@ -309,44 +237,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); - float grentype; - - switch(SBAR.PlayerClass) { - case PC_SCOUT: - if(fo_flash) { - grentype = GR_TYPE_FLASH; - } else { - grentype = GR_TYPE_CALTROP; - } - break; - case PC_SNIPER: - grentype = GR_TYPE_NORMAL; - break; - case PC_SOLDIER: - grentype = GR_TYPE_NORMAL; - break; - case PC_DEMOMAN: - grentype = GR_TYPE_NORMAL; - break; - case PC_MEDIC: - grentype = GR_TYPE_NORMAL; - break; - case PC_HVYWEAP: - grentype = GR_TYPE_NORMAL; - break; - case PC_PYRO: - grentype = GR_TYPE_NORMAL; - break; - case PC_SPY: - grentype = GR_TYPE_NORMAL; - break; - case PC_ENGINEER: - grentype = GR_TYPE_NORMAL; - break; - default: - grentype = GR_TYPE_NONE; - } - + local float grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; @@ -359,44 +250,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); - float grentype; - - switch(SBAR.PlayerClass) { - case PC_SCOUT: - grentype = GR_TYPE_CONCUSSION; - break; - case PC_SNIPER: - grentype = GR_TYPE_FLARE; - break; - case PC_SOLDIER: - grentype = GR_TYPE_NAIL; - break; - case PC_DEMOMAN: - grentype = GR_TYPE_MIRV; - break; - case PC_MEDIC: - if(medic_type == MEDIC_TYPE_BLAST) { - grentype = GR_TYPE_BLAST; - } else { - grentype = GR_TYPE_CONCUSSION; - } - break; - case PC_HVYWEAP: - grentype = GR_TYPE_MIRV; - break; - case PC_PYRO: - grentype = GR_TYPE_NAPALM; - break; - case PC_SPY: - grentype = GR_TYPE_GAS; - break; - case PC_ENGINEER: - grentype = GR_TYPE_EMP; - break; - default: - grentype = GR_TYPE_NONE; - } - + local float grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; @@ -525,3 +379,61 @@ noref void CSQC_Input_Frame() { void CSQC_Shutdown() = { FO_WriteSettings(); } + +float GetGrenOneTypeForClass(float playerclass) { + switch(playerclass) { + case PC_SCOUT: + if(fo_flash) { + return GR_TYPE_FLASH; + } else { + return GR_TYPE_CALTROP; + } + case PC_SNIPER: + return GR_TYPE_NORMAL; + case PC_SOLDIER: + return GR_TYPE_NORMAL; + case PC_DEMOMAN: + return GR_TYPE_NORMAL; + case PC_MEDIC: + return GR_TYPE_NORMAL; + case PC_HVYWEAP: + return GR_TYPE_NORMAL; + case PC_PYRO: + return GR_TYPE_NORMAL; + case PC_SPY: + return GR_TYPE_NORMAL; + case PC_ENGINEER: + return GR_TYPE_NORMAL; + default: + return GR_TYPE_NONE; + } +} + +float GetGrenTwoTypeForClass(float playerclass) { + switch(playerclass) { + case PC_SCOUT: + return GR_TYPE_CONCUSSION; + case PC_SNIPER: + return GR_TYPE_FLARE; + case PC_SOLDIER: + return GR_TYPE_NAIL; + case PC_DEMOMAN: + return GR_TYPE_MIRV; + case PC_MEDIC: + if(medic_type == MEDIC_TYPE_BLAST) { + return GR_TYPE_BLAST; + } else { + return GR_TYPE_CONCUSSION; + } + case PC_HVYWEAP: + return GR_TYPE_MIRV; + case PC_PYRO: + return GR_TYPE_NAPALM; + case PC_SPY: + return GR_TYPE_GAS; + case PC_ENGINEER: + return GR_TYPE_EMP; + default: + return GR_TYPE_NONE; + } +} From c058dff38e47fa1d697a2fdee2e6cb0242f8a578 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 4 Jul 2021 23:25:23 +1000 Subject: [PATCH 1262/2474] Refactor --- csqc/hud.qc | 2 +- csqc/main.qc | 8 ++++---- csqc/status.qc | 14 +++++++++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 8d6f1569..cb1c1ea3 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -852,7 +852,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) /* drawpic(pos, icon, size, '1 1 1', 1, 0); */ float len = 0, offset = 0; - + switch (playerclass) { case PC_SCOUT: diff --git a/csqc/main.qc b/csqc/main.qc index b013601a..87181e70 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -35,7 +35,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); registercvar(FOCMD_OLDSCOREBOARD, "0"); - + registercommand("fo_menu_game"); registercommand("fo_main_menu"); registercommand("fo_menu_team"); @@ -69,7 +69,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Hud_Editor_LoadSettings(); FO_LoadSettings(); - + CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; is_admin = FALSE; @@ -277,8 +277,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { if (key2 != "") { localcmd(sprintf("unbind %s\n", key2)); - localcmd(sprintf("bind %s +showscores\n", key2)); - } + localcmd(sprintf("bind %s +showscores\n", key2)); + } } FO_Show_Scores(TRUE); break; diff --git a/csqc/status.qc b/csqc/status.qc index db10867c..88604cad 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -69,11 +69,23 @@ void(string panelid, float display, string text, string icon) drawIconPanel = { }; void(string panelid, float display, string text) drawGren1Panel = { - local string icon = GetGrenOneIconForClass(SBAR.PlayerClass); + local float playerclass = SBAR.PlayerClass + + if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) { + return; + } + + local string icon = GetGrenOneIconForClass(playerclass); drawIconPanel(panelid, display, text, icon); }; void(string panelid, float display, string text) drawGren2Panel = { + local float playerclass = SBAR.PlayerClass + + if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) { + return; + } + local string icon = GetGrenTwoIconForClass(SBAR.PlayerClass); drawIconPanel(panelid, display, text, icon); }; From de055bbc7cfbe03b76ab11c2bc8f88a1151e00fd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 4 Jul 2021 23:31:37 +1000 Subject: [PATCH 1263/2474] Reliably send grenade settings --- ssqc/csmenu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index ebeccbe9..82970934 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -293,7 +293,7 @@ void UpdateClientGrenadeSettings(entity pl) = { WriteFloat(MSG_MULTICAST, fo_flash); WriteFloat(MSG_MULTICAST, medic_type); WriteFloat(MSG_MULTICAST, nailgren_type); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } void UpdateClientMapVote(entity pl, entity candidate) = { From d458b5a38133b90d2e21d17668fc078877f1dd41 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 4 Jul 2021 23:37:18 +1000 Subject: [PATCH 1264/2474] Increase default width of hud grenade panels (to prevent overlap) --- csqc/status.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 88604cad..d729881f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -879,8 +879,8 @@ var FO_Hud_Panel Hud_Panels[] = { {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, {"capspanel",FO_HUD_CAPS_NAME,'10 80','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'10 110','26 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'10 140','26 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'10 110','50 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'10 140','50 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 230','150 260',1,0,1,0, drawFlagInfo, {return "";}}, From 84ddeea4736fd449ac403d3953671801dd1ddf3f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 6 Jul 2021 02:14:04 +1000 Subject: [PATCH 1265/2474] Refactor --- csqc/main.qc | 70 +++++--------------------------------------------- csqc/status.qc | 65 ++++++++++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 94 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 87181e70..07acfb28 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,8 +10,6 @@ void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); -float GetGrenOneTypeForClass(float playerclass); -float GetGrenTwoTypeForClass(float playerclass); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -143,6 +141,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { tokenize_console(cmd); float val; string key1, key2; + local float grentype; + switch(argv(0)) { case "fo_hud_editor": FO_Hud_Editor(); @@ -210,7 +210,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); - local float grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); + grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } @@ -224,7 +224,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); - local float grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); + grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; @@ -237,7 +237,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); - local float grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); + grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; @@ -250,7 +250,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); - local float grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); + grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; @@ -379,61 +379,3 @@ noref void CSQC_Input_Frame() { void CSQC_Shutdown() = { FO_WriteSettings(); } - -float GetGrenOneTypeForClass(float playerclass) { - switch(playerclass) { - case PC_SCOUT: - if(fo_flash) { - return GR_TYPE_FLASH; - } else { - return GR_TYPE_CALTROP; - } - case PC_SNIPER: - return GR_TYPE_NORMAL; - case PC_SOLDIER: - return GR_TYPE_NORMAL; - case PC_DEMOMAN: - return GR_TYPE_NORMAL; - case PC_MEDIC: - return GR_TYPE_NORMAL; - case PC_HVYWEAP: - return GR_TYPE_NORMAL; - case PC_PYRO: - return GR_TYPE_NORMAL; - case PC_SPY: - return GR_TYPE_NORMAL; - case PC_ENGINEER: - return GR_TYPE_NORMAL; - default: - return GR_TYPE_NONE; - } -} - -float GetGrenTwoTypeForClass(float playerclass) { - switch(playerclass) { - case PC_SCOUT: - return GR_TYPE_CONCUSSION; - case PC_SNIPER: - return GR_TYPE_FLARE; - case PC_SOLDIER: - return GR_TYPE_NAIL; - case PC_DEMOMAN: - return GR_TYPE_MIRV; - case PC_MEDIC: - if(medic_type == MEDIC_TYPE_BLAST) { - return GR_TYPE_BLAST; - } else { - return GR_TYPE_CONCUSSION; - } - case PC_HVYWEAP: - return GR_TYPE_MIRV; - case PC_PYRO: - return GR_TYPE_NAPALM; - case PC_SPY: - return GR_TYPE_GAS; - case PC_ENGINEER: - return GR_TYPE_EMP; - default: - return GR_TYPE_NONE; - } -} diff --git a/csqc/status.qc b/csqc/status.qc index d729881f..0b559eb0 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -4,8 +4,8 @@ vector (FO_Hud_Panel* panel) getPanelPosition; float getHudPanel(string); void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string); FO_Hud_Panel* getHudPanelPointer(float); -string GetGrenOneIconForClass(float playerclass); -string GetGrenTwoIconForClass(float playerclass); +float GetGrenOneTypeForClass(float playerclass); +float GetGrenTwoTypeForClass(float playerclass); void(string panelid, float display, string text, string icon) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) @@ -69,24 +69,28 @@ void(string panelid, float display, string text, string icon) drawIconPanel = { }; void(string panelid, float display, string text) drawGren1Panel = { - local float playerclass = SBAR.PlayerClass + local float playerclass = SBAR.PlayerClass; if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) { return; } - local string icon = GetGrenOneIconForClass(playerclass); + local float gren_type = GetGrenOneTypeForClass(playerclass); + local string icon = GrenadeIcons[gren_type].icon; + drawIconPanel(panelid, display, text, icon); }; void(string panelid, float display, string text) drawGren2Panel = { - local float playerclass = SBAR.PlayerClass + local float playerclass = SBAR.PlayerClass; if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) { return; } - local string icon = GetGrenTwoIconForClass(SBAR.PlayerClass); + local float gren_type = GetGrenTwoTypeForClass(playerclass); + local string icon = GrenadeIcons[gren_type].icon; + drawIconPanel(panelid, display, text, icon); }; @@ -101,6 +105,7 @@ void(string panelid, float display, string text, string icon) drawSpecial = { void(string panelid, float display, string text, string icon) drawGrenTimerPanel = { local float timeleft; local float timercount = 0; + if (display) { //GetDrawPanel(panelid); float id = getHudPanel(panelid); @@ -935,60 +940,60 @@ vector(float panelid) getFillSize = { return Hud_Panels[panelid].FillSize; } -string GetGrenOneIconForClass(float playerclass) { +float GetGrenOneTypeForClass(float playerclass) { switch(playerclass) { case PC_SCOUT: if(fo_flash) { - return ICON_GREN_FLASH; + return GR_TYPE_FLASH; } else { - return ICON_GREN_CALTROP; + return GR_TYPE_CALTROP; } case PC_SNIPER: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; case PC_SOLDIER: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; case PC_DEMOMAN: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; case PC_MEDIC: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; case PC_HVYWEAP: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; case PC_PYRO: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; case PC_SPY: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; case PC_ENGINEER: - return ICON_GREN_NORMAL; + return GR_TYPE_NORMAL; default: - return ICON_GREN_NONE; + return GR_TYPE_NONE; } } -string GetGrenTwoIconForClass(float playerclass) { +float GetGrenTwoTypeForClass(float playerclass) { switch(playerclass) { case PC_SCOUT: - return ICON_GREN_CONCUSSION; + return GR_TYPE_CONCUSSION; case PC_SNIPER: - return ICON_GREN_FLARE; + return GR_TYPE_FLARE; case PC_SOLDIER: - return ICON_GREN_NAIL; + return GR_TYPE_NAIL; case PC_DEMOMAN: - return ICON_GREN_MIRV; + return GR_TYPE_MIRV; case PC_MEDIC: if(medic_type == MEDIC_TYPE_BLAST) { - return ICON_GREN_BLAST; + return GR_TYPE_BLAST; } else { - return ICON_GREN_CONCUSSION; + return GR_TYPE_CONCUSSION; } case PC_HVYWEAP: - return ICON_GREN_MIRV; + return GR_TYPE_MIRV; case PC_PYRO: - return ICON_GREN_NAPALM; + return GR_TYPE_NAPALM; case PC_SPY: - return ICON_GREN_GAS; + return GR_TYPE_GAS; case PC_ENGINEER: - return ICON_GREN_EMP; + return GR_TYPE_EMP; default: - return ICON_GREN_NONE; + return GR_TYPE_NONE; } } From 5a1e2a339dcd263aa63b4f132a9ce0921dd5fb7e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 17 Jul 2021 17:05:29 +1000 Subject: [PATCH 1266/2474] Move a definition --- share/defs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index e295cdb5..e200ebce 100644 --- a/share/defs.h +++ b/share/defs.h @@ -754,6 +754,7 @@ // Grenades #define GR_PRIMETIME 3 + #define GR_TYPE_NONE 0 #define GR_TYPE_NORMAL 1 #define GR_TYPE_CONCUSSION 2 @@ -1410,6 +1411,7 @@ #define ICON_FRAGSTREAK "textures/wad/fragstreak.png" #define ICON_CAPS "textures/wad/caps.png" #define ICON_IDENTIFY "textures/wad/identify.png" +#define ICON_GREN_NONE "textures/wad/gren_none.png" #define ICON_GREN_NORMAL "textures/wad/gren_normal.png" #define ICON_GREN_NAIL "textures/wad/gren_nail.png" #define ICON_GREN_CONCUSSION "textures/wad/gren_concussion.png" @@ -1421,7 +1423,6 @@ #define ICON_GREN_FLARE "textures/wad/gren_flare.png" #define ICON_GREN_CALTROP "textures/wad/gren_caltrop.png" #define ICON_GREN_BLAST "textures/wad/gren_blast.png" -#define ICON_GREN_NONE "textures/wad/gren_none.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" #define ICON_SOLDIER "textures/wad/soldier.png" From e87d4af804aba982758fcc1cfbb9e080598b0b5b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 17 Jul 2021 18:20:05 +1000 Subject: [PATCH 1267/2474] Remove hud config menu (for now) --- menu/menu.src | 1 - menu/options.qc | 2 -- menu/options_hud.qc | 68 --------------------------------------------- 3 files changed, 71 deletions(-) diff --git a/menu/menu.src b/menu/menu.src index fcc72df9..296f5f4c 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -42,7 +42,6 @@ void(mitem_desktop desktop) M_Pop = cmd("m_effects", M_Options_Effects, options_effects.qc) \ cmd("m_audio", M_Options_Audio, options_audio.qc) \ cmd("m_particles", M_Options_Particles, options_particles.qc) \ - cmd("m_hud", M_Options_Hud, options_hud.qc) \ cmd("m_load", M_Load, loadsave.qc) \ cmd("m_save", M_Save, ) \ cmd("m_quit", M_Quit, quit.qc) \ diff --git a/menu/options.qc b/menu/options.qc index 56265e73..be70c6d5 100644 --- a/menu/options.qc +++ b/menu/options.qc @@ -43,8 +43,6 @@ nonstatic void(mitem_desktop desktop) M_Options = fr.add(spawn(mitem_text, item_text:"Effects", item_command:"m_pop;m_effects", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; if (assumefalsecheckcommand("r_particledesc")) {fr.add(spawn(mitem_text, item_text:"Particles", item_command:"m_pop;m_particles", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} - if (assumefalsecheckcommand("ezhud_nquake")) - {fr.add(spawn(mitem_text, item_text:"Hud", item_command:"m_pop;m_hud", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} fr.add(spawn(mitem_text, item_text:"Controls", item_command:"m_pop;m_keys", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; if (assumefalsecheckcommand("cfg_save")) {fr.add(spawn(mitem_text, item_text:"Save Settings", item_command:"cfg_save", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} diff --git a/menu/options_hud.qc b/menu/options_hud.qc index 6e3381ca..e69de29b 100644 --- a/menu/options_hud.qc +++ b/menu/options_hud.qc @@ -1,68 +0,0 @@ -nonstatic void(mitem_desktop desktop) M_Options_Hud = -{ - local float i; - local float h; - mitem_exmenu m; - m = spawn(mitem_exmenu, item_text:_("Hud Configurations"), item_flags:IF_SELECTABLE, item_command:"m_options"); - desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); - desktop.item_focuschange(m, IF_KFOCUSED); - m.totop(); - - h = 200; - h *= 0.5; //and halve it - - //draw title art above the options - mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [banner.item_size_x*-0.5, -h-32], [banner.item_size_x*0.5, -h-8]); - - //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. - mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); - m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); - - float fs = search_begin("huds/*.cfg", TRUE, TRUE); - float fc = search_getsize(fs); - - float y = 0; - string fname = "huds/hud_default.cfg"; - string iname = "Default"; - string dname = iname; - if ((int)whichpack(fname)) - { - dname = GetFirstLineComment(fname, iname); - fr.add(spawn(mitem_text, item_text:dname, item_command:sprintf("set plug_sbar 3; cvarreset hud_*; exec \"%s\"; hud_recalculate", fname), item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], [0, 16]); - } - else - fr.add(spawn(mitem_text, item_text:dname, item_command:"cvarreset hud_*; set plug_sbar 0", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], [0, 16]); - y += 16; - - //add the options - for (i = 0; i < fc; i++) - { - fname = search_getfilename(fs, i); - iname = substring(fname, 5, -5); - if (iname == "hud_default") - continue; - if (substring(fname, 0, 4) == "hud_") - iname = substring(fname, 4, -1); - dname = GetFirstLineComment(fname, iname); -// print(sprintf("\"%s\" \"%s\" - \"%s\"\n", fname, iname, dname)); - if (dname) - { - fr.add(spawn(mitem_text, item_text:dname, item_command:sprintf("set plug_sbar 3; cvarreset hud_*; exec \"%s\"; hud_recalculate", fname), item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], [0, 16]); - y += 16; - } - } - search_end(fs); - - - //random art for style -#if 1//def CSQC - m.addm(spawn (mitem_spinnymodel, item_text: "progs/g_nail2.mdl", zbias:-16), [-160-60, 12*-16/2], [-60, 12*16/2]); -#else - //menuqc doesn't support entities. shove some random crappy static image there instead. - local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); - m.addm(plaque, [(-160-plaque.item_size_x)*0.5, 12*-16/2], [(-160+plaque.item_size_x)*0.5, 12*16/2]); -#endif - - addmenuback(m); -}; From 4364dd1ab5649c47a58bc5b5cc1c145ab3280842 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 18 Jul 2021 01:49:05 +1000 Subject: [PATCH 1268/2474] Remove a bunch of unpolished menus for now --- menu/menu.src | 5 +- menu/options.qc | 3 - menu/options_configs.qc | 57 ---------------- menu/options_particles.qc | 136 -------------------------------------- menu/presets.qc | 102 ---------------------------- 5 files changed, 1 insertion(+), 302 deletions(-) delete mode 100644 menu/options_configs.qc delete mode 100644 menu/options_particles.qc diff --git a/menu/menu.src b/menu/menu.src index 296f5f4c..8c5f369a 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -41,15 +41,12 @@ void(mitem_desktop desktop) M_Pop = cmd("m_video", M_Options_Video, options_video.qc) \ cmd("m_effects", M_Options_Effects, options_effects.qc) \ cmd("m_audio", M_Options_Audio, options_audio.qc) \ - cmd("m_particles", M_Options_Particles, options_particles.qc) \ cmd("m_load", M_Load, loadsave.qc) \ cmd("m_save", M_Save, ) \ cmd("m_quit", M_Quit, quit.qc) \ cmd("m_newgame", M_NewGame, newgame.qc) \ cmd("m_servers", M_Servers, servers.qc) \ - cmd("m_configs", M_Configs, options_configs.qc) \ - cmd("m_reset", M_Reset, ) \ - cmd("m_preset", M_Preset, presets.qc) + cmd("m_reset", M_Reset, ) #if 0 diff --git a/menu/options.qc b/menu/options.qc index be70c6d5..132fb175 100644 --- a/menu/options.qc +++ b/menu/options.qc @@ -36,13 +36,10 @@ nonstatic void(mitem_desktop desktop) M_Options = //and show the options. /* if (assumefalsecheckcommand("fps_preset")) */ /* {fr.add(spawn(mitem_text, item_text:"Graphical Presets", item_command:"m_pop;m_preset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} */ - fr.add(spawn(mitem_text, item_text:"Game Configs", item_command:"m_pop;m_configs", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; fr.add(spawn(mitem_text, item_text:"Basic Setup", item_command:"m_pop;m_basicopts", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; fr.add(spawn(mitem_text, item_text:"Audio", item_command:"m_pop;m_audio", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; fr.add(spawn(mitem_text, item_text:"Video", item_command:"m_pop;m_video", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; fr.add(spawn(mitem_text, item_text:"Effects", item_command:"m_pop;m_effects", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; - if (assumefalsecheckcommand("r_particledesc")) - {fr.add(spawn(mitem_text, item_text:"Particles", item_command:"m_pop;m_particles", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} fr.add(spawn(mitem_text, item_text:"Controls", item_command:"m_pop;m_keys", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16; if (assumefalsecheckcommand("cfg_save")) {fr.add(spawn(mitem_text, item_text:"Save Settings", item_command:"cfg_save", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;} diff --git a/menu/options_configs.qc b/menu/options_configs.qc deleted file mode 100644 index fa9556f5..00000000 --- a/menu/options_configs.qc +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** -Uses the engine command to apply the preset, and tries an exec instead if a config file exists. -Doesn't track the current one or anything. -Really simple and stupid menu. -no background tint, so the game is still visible so you can preview it. -*/ - -nonstatic void(mitem_desktop desktop) M_Configs = -{ - local float i; - mitem_exmenu m; - m = spawn(mitem_exmenu, item_text:_("Game Presets / Configs"), item_flags:IF_SELECTABLE, item_command:"m_options"); - desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); - desktop.item_focuschange(m, IF_KFOCUSED); - m.totop(); - - - float h = 200*0.5; - //draw title art above the options - mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-60-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); - - //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. - mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); - m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); - - - - - float fs, y=0; - fs = search_begin("configs/game_*.cfg", TRUE, TRUE); - float c = search_getsize(fs); - for (i = 0; i < c; i++) - { - string fname = search_getfilename(fs, i); - string iname = strzone(substring(fname, 13, -5)); - string dname = GetFirstLineComment(fname, iname); - iname = sprintf("exec \"%s\"", fname); - if (dname && !fr.findchildcmd(iname)) - fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=16], '100 16'); - } - search_end(fs); - if (c <= 0) - fr.add(spawn(mitem_text, item_text:"No configs found", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], '100 16'); - - //random art for style -#if 1//def CSQC - m.addm(spawn (mitem_spinnymodel, item_text: "progs/g_rock2.mdl", zbias:-16), [-160-60, 12*-16/2], [-60, 12*16/2]); -#else - //menuqc doesn't support entities. shove some random crappy static image there instead. - local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); - m.addm(plaque, [(-160-plaque.item_size_x)*0.5, 12*-16/2], [(-160+plaque.item_size_x)*0.5, 12*16/2]); -#endif - - addmenuback(m); -}; - diff --git a/menu/options_particles.qc b/menu/options_particles.qc deleted file mode 100644 index fa52998a..00000000 --- a/menu/options_particles.qc +++ /dev/null @@ -1,136 +0,0 @@ -//menu that configues r_particledesc according to the files available in the particles/ subdir, including the (known) internal effects. - -class particlesmenu : mitem_frame -{ - string thelist; - void() particlesmenu = - { - thelist = cvar_string("r_particledesc"); - }; - virtual void() item_remove = - { - cvar_set("r_particledesc", thelist); - }; - - //to reconfigure colours for when something changees. - nonvirtual void() UpdateSelections = - { - float sc = tokenize(thelist); - for (mitem ch = item_children; ch; ch = ch.item_next) - { - ch.item_rgb = '1 0.5 0.5'; - for (float i = 0; i < sc; i++) - { - if (!strcasecmp(argv(i), ch.item_command)) - { - ch.item_rgb = '1 1 1'; - break; - } - } - } - }; - virtual void(mitem fromitem, string cmd) item_execcommand = - { - float sc = tokenize(thelist); - for (float i = 0; i < sc; i++) - { - if (!strcasecmp(argv(i), cmd)) - { - thelist = strtrim(strcat(strtrim(substring(thelist, 0, argv_start_index(i))), " ", strtrim(substring(thelist, argv_end_index(i), -1)))); - UpdateSelections(); - return; - } - } - - if (strstrofs(cmd, "\t") >= 0 || strstrofs(cmd, " ") >= 0 || strstrofs(cmd, "\"") >= 0 || strstrofs(cmd, ";") >= 0 || strstrofs(cmd, "\n") >= 0) - thelist = strtrim(strcat(thelist, " \"", cmd, "\"")); - else - thelist = strtrim(strcat(thelist, " ", cmd)); - UpdateSelections(); - }; -}; - -string(string fname, string dflt) GetFirstLineComment = -{ - float f = fopen(fname, FILE_READ); - if (f < 0) - return 0; - string l = strtrim(fgets(f)); - fclose(f); - if (!strcasecmp(substring(l, 0, 9), "//private")) - return 0; - if (!strcasecmp(substring(l, 0, 8), "//hidden")) - return 0; - if (!strcasecmp(substring(l, 0, 7), "//desc:")) - return strtrim(substring(l, 7, -1)); -// if (substring(l, 0, 1) == "#") -// return strtrim(substring(l, 1, -1)); - return dflt; -}; - -nonstatic void(mitem_desktop desktop) M_Options_Particles = -{ - float y = -8; - float h; - - //create the menu, give it focus, and make sure its displayed over everything else. - mitem_exmenu m = spawn(mitem_exmenu, item_text:_("Particles Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); - desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); - desktop.item_focuschange(m, IF_KFOCUSED); - m.totop(); - - //figure out the size of the stuff -// h = sizeof(binds) / sizeof(binds[0]); -// h *= 8; - h = 200; - h *= 0.5; //and halve it - - //draw title art above the options - mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [banner.item_size_x*-0.5, -h-32], [banner.item_size_x*0.5, -h-8]); - - //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. - particlesmenu fr = spawn(particlesmenu, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); - m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); - - //FIXME: this stuff should be listed in order of selection, to reflect the priorities given to the various effects. - - //FIXME: these should not be listed if its a no-compat/no-legacy build. this'll do for now, but its a bit wrong - if (checkextension("FTE_PART_NAMESPACE_EFFECTINFO")) - { - fr.add(spawn(mitem_text, item_text:"Classic Particles", item_command:"classic", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); - fr.add(spawn(mitem_text, item_text:"High Quality", item_command:"high", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); - fr.add(spawn(mitem_text, item_text:"TimeServ's Shaft", item_command:"tsshaft", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); - - string efi = GetFirstLineComment("effectinfo.txt", "Effectinfo"); - if (efi) - fr.add(spawn(mitem_text, item_text:efi, item_command:"effectinfo", item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); - } - - float fs; - fs = search_begin("particles/*.cfg", TRUE, TRUE); - for (float c = search_getsize(fs), float i = 0; i < c; i++) - { - string fname = search_getfilename(fs, i); - string iname = substring(fname, 10, -5); - string dname = GetFirstLineComment(fname, iname); - if (dname && !fr.findchildcmd(iname)) - fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); - } - search_end(fs); - fs = search_begin("particles/*/*.cfg", TRUE, TRUE); - for (float c = search_getsize(fs), float i = 0; i < c; i++) - { - string fname = search_getfilename(fs, i); - string iname = substring(fname, 10, -5); - string dname = GetFirstLineComment(fname, iname); - if (dname && !fr.findchildcmd(iname)) - fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8'); - } - search_end(fs); - - fr.UpdateSelections(); - - //and give us a suitable menu tint too, just because. - addmenuback(m); -}; diff --git a/menu/presets.qc b/menu/presets.qc index 601bd97d..e69de29b 100644 --- a/menu/presets.qc +++ b/menu/presets.qc @@ -1,102 +0,0 @@ -/*************************************************************************** -Uses the engine command to apply the preset, and tries an exec instead if a config file exists. -Doesn't track the current one or anything. -Really simple and stupid menu. -no background tint, so the game is still visible so you can preview it. - -you should probably remove the fps_preset part. I left it in so that I don't have to bother with providing cfg files. note that this isn't a valid solution for dp, but whatever. -the great thing about providing source is that you can change it. -you can instead just shove your preset settings directly into the quotes instead of exec. -*/ - -struct -{ - string name; - string preset; - string config; -} presets[] = -{ - {"Simple", "286", "configs/preset_simple.cfg"}, - {"Fast", "fast", "configs/preset_fast.cfg"}, - {"Regression", "vanilla", "configs/preset_vanilla.cfg"}, - {"Faithful", "normal", "configs/preset_faithful.cfg"}, - {"Nice", "nice", "configs/preset_nice.cfg"}, - {"Realtime", "realtime", "configs/preset_realtime.cfg"} -}; -nonstatic float(string fname) checkfileexists = -{ - if (dp_workarounds) - { - float sh = search_begin(fname, FALSE, TRUE); - float result = FALSE; - if (sh >= 0) - { - result = !!search_getsize(sh); - search_end(sh); - } - return result; - } - else - { - //FTE's whichpack returns empty if its not in a pack, and null if its not found anywhere. - if (whichpack(fname)) - return TRUE; - return FALSE; - } -}; -nonstatic void(mitem_desktop desktop) M_Preset = -{ - local float i; - mitem_exmenu m; - m = spawn(mitem_exmenu, item_text:_("Graphical Presets"), item_flags:IF_SELECTABLE, item_command:"m_options"); - desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); - desktop.item_focuschange(m, IF_KFOCUSED); - m.totop(); - - - float h = 200 * 0.5; - //draw title art above the options - mitem_pic banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-60-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); - //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. - mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); - m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]); - float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; - - float fs, y=0; - fs = search_begin("configs/preset_*.cfg", TRUE, TRUE); - float c = search_getsize(fs); - for (i = 0; i < c; i++) - { - string fname = search_getfilename(fs, i); - string iname = substring(fname, 15, -5); - string dname = GetFirstLineComment(fname, iname); - iname = sprintf("exec \"configs/preset_%s.cfg\";vid_reload", iname); - if (dname && !fr.findchildcmd(iname)) - { - fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, y], '100 16'); - y+=16; - } - } - search_end(fs); - if (c <= 0) - { - //add the default options - for (i = 0, float pos = 0; i < presets.length; i++) - { - fr.add(spawn(mitem_text, item_text:presets[i].name, item_command:sprintf("fps_preset %s", presets[i].preset), item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [100, 16]); - pos += 16; - } - } - - //random art for style -#if 1//def CSQC - m.addm(spawn (mitem_spinnymodel, item_text: "progs/suit.mdl"), [-160, 12*-16/2], [0, 12*16/2]); -#else - //menuqc doesn't support entities. shove some random crappy static image there instead. - local mitem_pic plaque = spawn (mitem_pic, item_text:"gfx/qplaque.lmp", item_alpha:1); - m.addm(plaque, [(-160-plaque.item_size_x)*0.5, 12*-16/2], [(-160+plaque.item_size_x)*0.5, 12*16/2]); -#endif - - addmenuback(m); -}; From 30ba7cf23d494c3c8379677069f859551006b793 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 18 Jul 2021 03:21:16 +1000 Subject: [PATCH 1269/2474] Add team crosshair color option --- menu/options_basic.qc | 30 +++++++++++++++++++++++------- menu/options_hud.qc | 0 2 files changed, 23 insertions(+), 7 deletions(-) delete mode 100644 menu/options_hud.qc diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 31c120cd..8fed2a08 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -124,16 +124,32 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.4 1.3 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.8 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'0.0 0.5 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Crosshair"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcheck_spawn (_("Show Speed"), "show_speed", '280 8'), fl, [0, pos], [0, 8]); pos += 8; pos += 8; + fr.add( + spawn( + mitem_text, + item_text:strcat("^{e080} ^a","Crosshair","^d ^{e082}"), + item_command:"", + item_scale:8, + item_flags:IF_CENTERALIGN + ), + RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, + [0, pos], + [0, 8] + ); + pos += 8; + pos += 8; + fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( - "0 \"None\" " - "1 \"Server\" " - "2 \"Immediate\" " - )), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + /* fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( */ + /* "0 \"None\" " */ + /* "1 \"Server\" " */ + /* "2 \"Immediate\" " */ + /* )), fl, [0, pos], [0, 8]); pos += 8; */ + /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; diff --git a/menu/options_hud.qc b/menu/options_hud.qc deleted file mode 100644 index e69de29b..00000000 From d460a70439f1f1c91e73b37df9385d9e95f96c59 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 18 Jul 2021 03:37:02 +1000 Subject: [PATCH 1270/2474] Add texturemode --- menu/options_effects.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/menu/options_effects.qc b/menu/options_effects.qc index 22e115e5..c081587f 100644 --- a/menu/options_effects.qc +++ b/menu/options_effects.qc @@ -26,6 +26,10 @@ nonstatic void(mitem_desktop desktop) M_Options_Effects = fr.add(menuitemcheck_spawn(_("Relief Mapping"), "r_glsl_offsetmapping", '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcheck_spawn(_("Realtime Dynamic Lights"), "r_shadow_realtime_dlight", '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcheck_spawn(_("Realtime World Lighting"), "r_shadow_realtime_world", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Texture Mode"), "gl_texturemode", '280 8', _( + "nll \"Blocky\" " + "lll \"Blurry\" " + )), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Particle Density"), "r_part_density", '0.25 4 0.25', '280 8'), fl, [0, pos], [0, 8]); pos += 8; From 1638fb35e283f67627eb3e6611027955b5c0ea5e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 5 Aug 2021 15:43:33 +1000 Subject: [PATCH 1271/2474] Add ctag generation script --- README.md | 13 +++++++++++-- generate_ctags.sh | 8 ++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100755 generate_ctags.sh diff --git a/README.md b/README.md index e1eea242..a9458461 100644 --- a/README.md +++ b/README.md @@ -196,12 +196,21 @@ Engineer * Engineers can now only dismantle own buildings and rotate own Sentry Gun. -Compilation +Development +------ + +Compile ------ Compile with [FTEQCC](http://fte.triptohell.info/downloads) Ensure that `fteqcc64` is available in `$PATH` and: ``` -$ make +make +``` + +Generate ctags +------ +``` +./generate_ctags.sh ``` diff --git a/generate_ctags.sh b/generate_ctags.sh new file mode 100755 index 00000000..c4424ab0 --- /dev/null +++ b/generate_ctags.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +rm *tags +fteqcc64 -ftags ./ssqc/progs.src +fteqcc64 -ftags ./csqc/csprogs.src +fteqcc64 -ftags ./menu/menu.src +cat *.tags|LC_COLLATE=C sort>tags +rm *.tags From e3e6110d28de0c6cd55bfd389943773015fbf1b8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 5 Aug 2021 15:50:37 +1000 Subject: [PATCH 1272/2474] Update readme --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index a9458461..10de8330 100644 --- a/README.md +++ b/README.md @@ -214,3 +214,10 @@ Generate ctags ``` ./generate_ctags.sh ``` + +Note: I got an error in vim: +``` +E431: Format error in tags file "tags" +Before byte 364464 +``` +I just removed the one line at that byte address and it works fine now. From 8fa504b891a44e78ef0f74832acb11f4aeedad4b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 5 Aug 2021 19:31:13 +1000 Subject: [PATCH 1273/2474] Update readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 10de8330..900c910e 100644 --- a/README.md +++ b/README.md @@ -221,3 +221,13 @@ E431: Format error in tags file "tags" Before byte 364464 ``` I just removed the one line at that byte address and it works fine now. + + +List assets +----- + +Only works in ssqc + +``` +fteqcc64 ./ssqc/progs.src -fdumpfilenames +``` From b0eec6e6e266364a8ffb0079a9a33a3b9243a320 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 7 Aug 2021 12:33:55 +1000 Subject: [PATCH 1274/2474] Update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 900c910e..a306e08c 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,8 @@ Before byte 364464 ``` I just removed the one line at that byte address and it works fine now. +Note: Fixed in fteqcc 6010 + List assets ----- From a2b616df485ee4f58cfbe1695421c77a6ad1d2f4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 7 Aug 2021 12:34:11 +1000 Subject: [PATCH 1275/2474] Remove new game hud menu option for now --- menu/main.qc | 1 - menu/menu.src | 1 - menu/newgame.qc | 238 ------------------------------------------------ 3 files changed, 240 deletions(-) delete mode 100644 menu/newgame.qc diff --git a/menu/main.qc b/menu/main.qc index f333453c..0a0dc554 100644 --- a/menu/main.qc +++ b/menu/main.qc @@ -81,7 +81,6 @@ nonstatic void(mitem_desktop desktop) M_Main = if (checkextension("FTE_CSQC_SERVERBROWSER")) #endif {menuitemtext_cladd16(m, _("Join Server"), "m_pop;m_servers", y); y += 16;} - //if (assumetruecheckcommand("map")) {menuitemtext_cladd16(m, _("New Game"), "m_pop;m_newgame", y); y += 16;} if (assumefalsecheckcommand("menu_demo")) {menuitemtext_cladd16(m, _("Demos"), "m_pop;menu_demo", y); y += 16;} //if (assumetruecheckcommand("save") && (isserver()||dp_workarounds)) {menuitemtext_cladd16(m, _("Save"), "m_pop;m_save", y); y += 16;} //if (assumetruecheckcommand("load")) {menuitemtext_cladd16(m, _("Load"), "m_pop;m_load", y); y += 16;} diff --git a/menu/menu.src b/menu/menu.src index 8c5f369a..bf25607b 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -44,7 +44,6 @@ void(mitem_desktop desktop) M_Pop = cmd("m_load", M_Load, loadsave.qc) \ cmd("m_save", M_Save, ) \ cmd("m_quit", M_Quit, quit.qc) \ - cmd("m_newgame", M_NewGame, newgame.qc) \ cmd("m_servers", M_Servers, servers.qc) \ cmd("m_reset", M_Reset, ) diff --git a/menu/newgame.qc b/menu/newgame.qc deleted file mode 100644 index 639ce7da..00000000 --- a/menu/newgame.qc +++ /dev/null @@ -1,238 +0,0 @@ -static string newgameinfo; -class mitem_newgame : mitem_exmenu -{ - virtual string(string key) get = - { - return infoget(newgameinfo, key); - }; - virtual void(string key, string newval) set = - { - string old = newgameinfo; - newgameinfo = strzone(infoadd(newgameinfo, key, newval)); - if (old) - strunzone(old); - }; -}; - -nonstatic void(mitem_desktop desktop) M_NewGame = -{ - mitem_pic banner; - string gametype = argv(1); - local float pos; - mitem_exmenu m; - if (gametype == "sp") - { - //single player has no options. the start map itself gives skill+episode options. - localcmd("\ndeathmatch 0; coop 0; maxplayers 0; timelimit 0; fraglimit 0; teamplay 0; samelevel 0; startmap_sp\n"); - return; - } - if (gametype == "begin") - { - cvar_set("hostname", infoget(newgameinfo, "hostname")); - cvar_set("deathmatch", infoget(newgameinfo, "deathmatch")); - cvar_set("coop", infoget(newgameinfo, "coop")); - cvar_set("teamplay", infoget(newgameinfo, "teamplay")); - cvar_set("sv_public", infoget(newgameinfo, "sv_public")); - cvar_set("maxclients", infoget(newgameinfo, "maxclients")); - cvar_set("timelimit", infoget(newgameinfo, "timelimit")); - cvar_set("fraglimit", infoget(newgameinfo, "fraglimit")); - string map = infoget(newgameinfo, "map"); - if (map == "") - map = sprintf("dm%g", floor(random(1, 6))); - localcmd(sprintf("\nmap \"%s\"\n", map)); - return; - } - - if (newgameinfo) - strunzone(newgameinfo); - newgameinfo = ""; - newgameinfo = infoadd(newgameinfo, "hostname", cvar_string("hostname")); - newgameinfo = infoadd(newgameinfo, "deathmatch", cvar_string("deathmatch")); - newgameinfo = infoadd(newgameinfo, "teamplay", cvar_string("teamplay")); - newgameinfo = infoadd(newgameinfo, "sv_public", cvar_string("sv_public")); - newgameinfo = infoadd(newgameinfo, "maxclients", cvar_string("maxclients")); - newgameinfo = infoadd(newgameinfo, "timelimit", cvar_string("timelimit")); - newgameinfo = infoadd(newgameinfo, "fraglimit", cvar_string("fraglimit")); - newgameinfo = strzone(newgameinfo); - - m = spawn(mitem_newgame, item_text:_("New Game"), item_flags:IF_SELECTABLE, item_command:"m_main"); - desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); - desktop.item_focuschange(m, IF_KFOCUSED); - m.totop(); - - switch(gametype) - { - case "tdm": - case "dm": - case "coop": - case "sp": - break; - default: - //show game type selection - pos = (16/-2)*(4); - banner = spawn(mitem_pic, item_text:"gfx/p_option.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.addm(banner, [(160-banner.item_size_x)*0.5, pos-32], [(160+banner.item_size_x)*0.5, pos-8]); - m.addm(spawn(mitem_text, item_text:"Single Player", item_command:"m_pop;m_newgame sp", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; - m.addm(spawn(mitem_text, item_text:"Cooperative", item_command:"m_pop;m_newgame coop", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; - m.addm(spawn(mitem_text, item_text:"Deathmatch", item_command:"m_pop;m_newgame dm", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; - m.addm(spawn(mitem_text, item_text:"Team Deathmatch", item_command:"m_pop;m_newgame tdm", item_scale:16, item_flags:IF_CENTERALIGN), [0, pos], [160, pos+16]); pos += 16; - -#if 1//def CSQC - m.add(spawn (mitem_spinnymodel, item_text: "progs/soldier.mdl",firstframe:73, framecount:8, shootframe:81, shootframes:9), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); -#else - //need some art for menuqc -#endif - return; - } - - pos = (16/-2)*(4); - - banner = spawn(mitem_pic, item_text:"gfx/p_multi.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.addm(banner, [(160-banner.item_size_x)*0.5, pos-32], [(160+banner.item_size_x)*0.5, pos-8]); - - m.addm(menuitemeditt_spawn(_("Hostname"), "hostname", '280 8'), [-160, pos], [160, pos+8]); pos += 8; - m.addm(menuitemcheck_spawn(_("Public"), "sv_public", '280 8'), [-160, pos], [160, pos+8]); pos += 8; - m.addm(menuitemcombo_spawn(_("Max Clients"), "maxclients", '280 8', _( - "2 \"Two\" " - "3 \"Three\" " - "4 \"Four\" " - "8 \"Eight\" " - "16 \"Sixteen\" " - "32 \"Thirty Two\" " - )), [-160, pos], [160, pos+8]); pos += 8; - - if (gametype == "dm" || gametype == "tdm") - { - if (m.get("deathmatch") == "0") - { - m.set("deathmatch", "1"); - m.set("coop", "0"); - } - m.addm(menuitemcombo_spawn(_("Deathmatch Mode"), "deathmatch", '280 8', _( - "1 \"Weapons Respawn\" " - "2 \"Weapons Stay\" " - "3 \"Powerups Respawn\" " - "4 \"Start With Weapons\" " - )), [-160, pos], [160, pos+8]); pos += 8; - } - else - { - if (m.get("coop") == "0") - { - m.set("deathmatch", "0"); - m.set("coop", "1"); - } - } - if (gametype == "tdm") - { - if (m.get("teamplay") == "0") - m.set("teamplay", "1"); - } - if (gametype == "dm") - { - if (m.get("teamplay") != "0") - m.set("teamplay", "0"); - } - if (gametype == "coop") - m.addm(menuitemcheck_spawn(_("No Friendly Fire"), "teamplay", '280 8'), [-160, pos], [160, pos+8]); pos += 8; -// if (gametype == "dm" || gametype == "tdm") - - if (gametype == "coop") - m.set("map", "start"); - else - { - m.addm(menuitemcombo_spawn(_("Time Limit"), "timelimit", '280 8', _( - "0 \"No Limit\" " - "5 \"5 minutes\" " - "10 \"10 minutes\" " - "15 \"15 minutes\" " - "20 \"20 minutes\" " - "25 \"25 minutes\" " - "30 \"30 minutes\" " - "35 \"35 minutes\" " - "40 \"40 minutes\" " - "45 \"45 minutes\" " - "50 \"50 minutes\" " - "55 \"55 minutes\" " - "60 \"1 hour\" " - )), [-160, pos], [160, pos+8]); pos += 8; - m.addm(menuitemcombo_spawn(_("Frag Limit"), "fraglimit", '280 8', _( - "0 \"No Limit\" " - "10 \"10 frags\" " - "20 \"20 frags\" " - "30 \"30 frags\" " - "40 \"40 frags\" " - "50 \"50 frags\" " - "60 \"60 frags\" " - "70 \"70 frags\" " - "80 \"80 frags\" " - "90 \"90 frags\" " - "100 \"100 frags\" " - )), [-160, pos], [160, pos+8]); pos += 8; - - m.set("map", ""); - m.addm(menuitemcombo_spawn(_("Initial Map"), "map", '280 8', _( - "dm1 \"DM1 (dm1)\" " - "dm2 \"DM2 (dm2)\" " - "dm3 \"DM3 (dm3)\" " - "dm4 \"DM4 (dm4)\" " - "dm5 \"DM5 (dm5)\" " - "dm6 \"DM6 (dm6)\" " - "start \"Start (Introduction)\" " - "e1m1 \"E1M1 (The Slipgate Complex)\" " - "e1m2 \"E1M2 (Castle Of The Damned)\" " - "e1m3 \"E1M3 (The Necropolis)\" " - "e1m4 \"E1M4 (The Grisly Grotto)\" " - "e1m5 \"E1M5 (Gloom Keep)\" " - "e1m6 \"E1M6 (The Door To Chthon)\" " - "e1m7 \"E1M7 (The House Of Chthon)\" " - "e1m8 \"E1M8 (Ziggarat Vertigo)\" " - "e2m1 \"E2M1 (The Installation)\" " - "e2m2 \"E2M2 (The Ogre Citadel)\" " - "e2m3 \"E2M3 (The Crypt Of Decay)\" " - "e2m4 \"E2M4 (The Ebon Fortress)\" " - "e2m5 \"E2M5 (The Wizard's Manse)\" " - "e2m6 \"E2M6 (The Dismal Oubliette\" " - "e2m7 \"E2M7 (The Underearth)\" " - "e3m1 \"E3M1 (Termination Central)\" " - "e3m2 \"E3M2 (The Vaults Of Zin)\" " - "e3m3 \"E3M3 (The Tomb Of Terror)\" " - "e3m4 \"E3M4 (Satan's Dark Delight)\" " - "e3m5 \"E3M5 (The Wind Tunnels)\" " - "e3m6 \"E3M6 (Chambers Of Torment)\" " - "e3m7 \"E3M7 (Tha Haunted Halls)\" " - "e4m1 \"E4M1 (The Sewage System)\" " - "e4m2 \"E4M2 (The Tower Of Despair)\" " - "e4m3 \"E4M3 (The Elder God Shrine)\" " - "e4m4 \"E4M4 (The Palace Of Hate)\" " - "e4m5 \"E4M5 (Hell's Atrium)\" " - "e4m6 \"E4M6 (The Pain Maze)\" " - "e4m7 \"E4M7 (Azure Agony)\" " - "e4m8 \"E4M8 (The Nameless City)\" " - "end \"End (Shub-Niggurath's Pit)\" " - )), [-160, pos], [160, pos+8]); pos += 8; - } - - m.addm(spawn(mitem_text, item_text:"BEGIN!", item_command:"m_pop;m_newgame begin", item_scale:16, item_flags:IF_CENTERALIGN), [-160, pos], [160, pos+16]); - - if (gametype == "coop") - { - //random art for style -#if 1//def CSQC - m.add(spawn (mitem_spinnymodel, item_text: "progs/soldier.mdl", firstframe:73, framecount:8, shootframe:81, shootframes:9), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, -240/2], [0, 240/2]); -#else - //need some art for menuqc -#endif - } - else - { - //random art for style -#if 1//def CSQC - m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); -#else - //need some art for menuqc -#endif - } - - addmenuback(m); -}; From e1d2ae1263b906ba9190993f68bd8e319a9b053b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Aug 2021 00:14:30 +1000 Subject: [PATCH 1276/2474] Remove id1 assets --- ssqc/items.qc | 31 ------------------------------ ssqc/tfortmap.qc | 8 ++++---- ssqc/vote.qc | 6 +++--- ssqc/weapons.qc | 1 - ssqc/world.qc | 49 ++---------------------------------------------- 5 files changed, 9 insertions(+), 86 deletions(-) diff --git a/ssqc/items.qc b/ssqc/items.qc index 5541688f..c7e823e6 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -1151,37 +1151,6 @@ void () sigil_touch = { SUB_UseTargets(); }; -void () item_sigil = { - if (CheckExistence() == 0) { - dremove(self); - return; - } - if (!self.spawnflags) { - objerror("no spawnflags"); - } - precache_sound("misc/runekey.wav"); - self.noise = "misc/runekey.wav"; - if (self.spawnflags & 1) { - precache_model("progs/end1.mdl"); - FO_SetModel(self, "progs/end1.mdl"); - } - if (self.spawnflags & 2) { - precache_model2("progs/end2.mdl"); - FO_SetModel(self, "progs/end2.mdl"); - } - if (self.spawnflags & 4) { - precache_model2("progs/end3.mdl"); - FO_SetModel(self, "progs/end3.mdl"); - } - if (self.spawnflags & 8) { - precache_model2("progs/end4.mdl"); - FO_SetModel(self, "progs/end4.mdl"); - } - self.touch = sigil_touch; - setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); - StartItem(); -}; - void () powerup_touch = { if (other.classname != "player") return; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 87ea4724..dec907e2 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2724,7 +2724,7 @@ void () item_flag_team2 = { CTF_Map = 1; UpdateAbbreviations(self); precache_sound("ogre/ogwake.wav"); - precache_sound("boss2/pop2.wav"); + precache_sound("boss1/out1.wav"); self.classname = "item_tfgoal"; self.netname = "Blue Flag"; self.broadcast = Q" \sgot\s the enemy team's flag!\n"; @@ -2766,7 +2766,7 @@ void () item_flag_team2 = { dp.goal_effects = 3; dp.broadcast = Q" \scaptured\s the enemy flag!\n"; dp.message = Q"You \scaptured\s the enemy flag!\n"; - dp.noise = "boss2/pop2.wav"; + dp.noise = "boss1/out1.wav"; dp.goal_result = 2; dp.activate_goal_no = 5; dp.axhitme = 2; @@ -2801,7 +2801,7 @@ void () item_flag_team1 = { CTF_Map = 1; UpdateAbbreviations(self); precache_sound("ogre/ogwake.wav"); - precache_sound("boss2/pop2.wav"); + precache_sound("boss1/out1.wav"); self.classname = "item_tfgoal"; self.netname = "Red Flag"; self.broadcast = Q" \sgot\s the enemy team's flag!\n"; @@ -2841,7 +2841,7 @@ void () item_flag_team1 = { dp.goal_effects = 3; dp.broadcast = Q" \scaptured\s the enemy flag!\n"; dp.message = Q"You \scaptured\s the enemy flag!\n"; - dp.noise = "boss2/pop2.wav"; + dp.noise = "boss1/out1.wav"; dp.goal_result = 2; dp.activate_goal_no = 6; dp.axhitme = 1; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 617e6f09..b35ec7c7 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1240,7 +1240,7 @@ void () AnarchyMode = { e = find(e, classname, "player"); } bprint(PRINT_HIGH, "\bDemocracy has failed!\b Let the result be decided in \bBATTLE\b\n"); - FO_Sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "boss1/out1.wav", 1, ATTN_NONE); //e = spawn(); //e.classname = "anarchy_timer"; //e.think = anarchy_timer_think; @@ -1346,7 +1346,7 @@ float () CheckVoting = { // do we want this to trigger during anarchy too when hitting majority? if(e.cnt > (numplayers * vote_threshold)) { bprint(PRINT_HIGH, "\bTime's up!\b Majority choice: ", e.netname, "\n"); - FO_Sound(self, CHAN_AUTO, "blob/sight1.wav", 1, ATTN_NONE); + FO_Sound(self, CHAN_AUTO, "boss1/sight1.wav", 1, ATTN_NONE); ChangeToVotedMap(e.netname); return FALSE; } else if(votemode) { @@ -1502,7 +1502,7 @@ void (entity p) VoteToEndMap = { te = find (te, classname, "player"); } if(numvoted > (numplayers * vote_threshold)) { - sound(self, CHAN_AUTO, "boss2/pop2.wav", 1, ATTN_NONE); + sound(self, CHAN_AUTO, "boss1/out1.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, "\bMap ended by majority vote.\b.\n"); vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); votemode = 2; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 610f4ea1..aec270a6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -140,7 +140,6 @@ void () W_Precache = { precache_sound("items/r_item2.wav"); precache_model("progs/flame2.mdl"); precache_sound("ambience/fire1.wav"); - precache_sound2("blob/land1.wav"); precache_model2("progs/v_spike.mdl"); precache_sound("hknight/hit.wav"); precache_sound("weapons/detpack.wav"); diff --git a/ssqc/world.qc b/ssqc/world.qc index 066c42c2..dfb5eedb 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -7,11 +7,6 @@ void () main = { precache_file("gfx.wad"); precache_file("quake.rc"); precache_file("default.cfg"); - precache_file("end1.bin"); - precache_file2("end2.bin"); - precache_file("demo1.dem"); - precache_file("demo2.dem"); - precache_file("demo3.dem"); precache_file("gfx/palette.lmp"); precache_file("gfx/colormap.lmp"); precache_file2("gfx/pop.lmp"); @@ -74,45 +69,6 @@ void () main = { precache_sound("misc/menu3.wav"); precache_sound("ambience/water1.wav"); precache_sound("ambience/wind2.wav"); - precache_file("maps/start.bsp"); - precache_file("maps/e1m1.bsp"); - precache_file("maps/e1m2.bsp"); - precache_file("maps/e1m3.bsp"); - precache_file("maps/e1m4.bsp"); - precache_file("maps/e1m5.bsp"); - precache_file("maps/e1m6.bsp"); - precache_file("maps/e1m7.bsp"); - precache_file("maps/e1m8.bsp"); - precache_file2("gfx/pop.lmp"); - precache_file2("maps/e2m1.bsp"); - precache_file2("maps/e2m2.bsp"); - precache_file2("maps/e2m3.bsp"); - precache_file2("maps/e2m4.bsp"); - precache_file2("maps/e2m5.bsp"); - precache_file2("maps/e2m6.bsp"); - precache_file2("maps/e2m7.bsp"); - precache_file2("maps/e3m1.bsp"); - precache_file2("maps/e3m2.bsp"); - precache_file2("maps/e3m3.bsp"); - precache_file2("maps/e3m4.bsp"); - precache_file2("maps/e3m5.bsp"); - precache_file2("maps/e3m6.bsp"); - precache_file2("maps/e3m7.bsp"); - precache_file2("maps/e4m1.bsp"); - precache_file2("maps/e4m2.bsp"); - precache_file2("maps/e4m3.bsp"); - precache_file2("maps/e4m4.bsp"); - precache_file2("maps/e4m5.bsp"); - precache_file2("maps/e4m6.bsp"); - precache_file2("maps/e4m7.bsp"); - precache_file2("maps/e4m8.bsp"); - precache_file2("maps/end.bsp"); - precache_file2("maps/dm1.bsp"); - precache_file2("maps/dm2.bsp"); - precache_file2("maps/dm3.bsp"); - precache_file2("maps/dm4.bsp"); - precache_file2("maps/dm5.bsp"); - precache_file2("maps/dm6.bsp"); }; entity lastspawn; @@ -268,7 +224,6 @@ void () worldspawn = { precache_model2("progs/laser.mdl"); precache_sound2("enforcer/enfire.wav"); precache_sound2("enforcer/enfstop.wav"); - precache_sound2("hknight/attack1.wav"); precache_model2("progs/sight.spr"); precache_model2("progs/caltrop.mdl"); precache_model2("progs/cross1.mdl"); @@ -311,11 +266,11 @@ void () worldspawn = { precache_model2(MODEL_PROJ_DIAM2); precache_sound("grentimer.wav"); precache_sound("buttons/switch04.wav"); - precache_sound("boss2/pop2.wav"); + precache_sound("boss1/out1.wav"); precache_sound("items/qpi2.wav"); precache_sound("shalrath/death.wav"); precache_sound("shalrath/attack2.wav"); - precache_sound("blob/sight1.wav"); + precache_sound("boss1/sight1.wav"); precache_sound("misc/secret.wav"); precache_sound("weapons/airblast.wav"); precache_sound("weapons/airblastshoot.wav"); From 10a2da4019143342a62c97522e8b8e7fbc6cc6ae Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Aug 2021 00:36:36 +1000 Subject: [PATCH 1277/2474] Remove show speed, make brightness gamma contrast sliders more sensible --- menu/options_basic.qc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 8fed2a08..286dfc53 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -121,10 +121,9 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = fr.add(menuitemslider_spawn(_("Sensitivity"), "sensitivity", '3 20 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Fov"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Viewmodel Fov"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.4 1.3 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.8 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'0.0 0.5 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Show Speed"), "show_speed", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'-0.2 0.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; pos += 8; fr.add( spawn( From ee0d184b822c77bf3bee1208804534ce2877b01c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Aug 2021 00:53:50 +1000 Subject: [PATCH 1278/2474] Refactor --- csqc/main.qc | 45 ++++++++++++++++++++++++++++++++++----------- share/commondefs.qc | 2 +- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 07acfb28..168137cd 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,6 +10,7 @@ void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); +void GrenOne(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -233,17 +234,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren1": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { - localcmd("play grentimer.wav\n"); - grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); - AddGrenTimer(grentype); - } - grentimer_waiting = TRUE; - } - localcmd("gren1_server"); - } + GrenOne(); break; case "gren2": if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { @@ -379,3 +370,35 @@ noref void CSQC_Input_Frame() { void CSQC_Shutdown() = { FO_WriteSettings(); } + +void GrenOne() = { + if (cvar(FOCMD_GRENTIMER) != 2) + return; + + if (prematch) + return; + + if (round_over) + return; + + if (SBAR.GameMode && (SBAR.GameMode & GAMEMODE_VOTE)) + return; + + if ((SBAR.GameMode & GAMEMODE_QUAD) && !round_active) + return; + + if (getstatf(STAT_HEALTH <= 0)) + return; + + if (!grentimer_waiting) { + if (SBAR.Gren1) { + localcmd("play grentimer.wav\n"); + local float grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); + AddGrenTimer(grentype); + } + + grentimer_waiting = TRUE; + } + + localcmd("gren1_server"); +} diff --git a/share/commondefs.qc b/share/commondefs.qc index b128ba24..e5a6c50f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -23,7 +23,7 @@ #define MSG_SERVER_ADMIN_INFO 11 #define MSG_CAPTAINS 12 #define MSG_MOTD 13 -#define MSG_PREMATCH 14 +#define MSG_PREMATCH 14 #define MSG_GRENTHROWN 15 #define MSG_ID 16 #define MSG_TEAM_SCORES 17 From e02ba26da41cf5f7acd244f236d34b9431c48c02 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Aug 2021 01:07:16 +1000 Subject: [PATCH 1279/2474] Refactor --- csqc/main.qc | 70 ++++++++++++++++++------------ csqc/status.qc | 114 ++++++++++++++++++++++++------------------------- 2 files changed, 100 insertions(+), 84 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 168137cd..5b47cf2f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -11,6 +11,8 @@ void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); void GrenOne(); +void GrenTwo(); +void IsValidToPrimeGrenade(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -211,7 +213,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { localcmd("play grentimer.wav\n"); - grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); + grentype = GetGrenTypeForClass(1, SBAR.PlayerClass); AddGrenTimer(grentype); } @@ -225,7 +227,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { if(!grentimer_waiting) { if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { localcmd("play grentimer.wav\n"); - grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); + grentype = GetGrenTypeForClass(2, SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; @@ -237,17 +239,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { GrenOne(); break; case "gren2": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { - localcmd("play grentimer.wav\n"); - grentype = GetGrenTwoTypeForClass(SBAR.PlayerClass); - AddGrenTimer(grentype); - } - grentimer_waiting = TRUE; - } - localcmd("gren2_server"); - } + GrenOne(); break; case "+fo_showscores": if (cvar(FOCMD_OLDSCOREBOARD) == 1) @@ -372,33 +364,57 @@ void CSQC_Shutdown() = { } void GrenOne() = { - if (cvar(FOCMD_GRENTIMER) != 2) + if !(IsValidToPrimeGrenade()) return; - if (prematch) - return; - - if (round_over) - return; + if (!grentimer_waiting) { + if (SBAR.Gren1) { + localcmd("play grentimer.wav\n"); + local float grentype = GetGrenTypeForClass(1, SBAR.PlayerClass); + AddGrenTimer(grentype); + } - if (SBAR.GameMode && (SBAR.GameMode & GAMEMODE_VOTE)) - return; + grentimer_waiting = TRUE; + } - if ((SBAR.GameMode & GAMEMODE_QUAD) && !round_active) - return; + localcmd("gren1_server"); +} - if (getstatf(STAT_HEALTH <= 0)) +void GrenTwo() = { + if !(IsValidToPrimeGrenade()) return; if (!grentimer_waiting) { - if (SBAR.Gren1) { + if (SBAR.Gren2) { localcmd("play grentimer.wav\n"); - local float grentype = GetGrenOneTypeForClass(SBAR.PlayerClass); + local float grentype = GetGrenTypeForClass(2, SBAR.PlayerClass); AddGrenTimer(grentype); } grentimer_waiting = TRUE; } - localcmd("gren1_server"); + localcmd("gren2_server"); +} + +void IsValidToPrimeGrenade() { + if (cvar(FOCMD_GRENTIMER) != 2) + return FALSE; + + if (prematch) + return FALSE; + + if (round_over) + return FALSE; + + if (SBAR.GameMode && (SBAR.GameMode & GAMEMODE_VOTE)) + return FALSE; + + if ((SBAR.GameMode & GAMEMODE_QUAD) && !round_active) + return FALSE; + + if (getstatf(STAT_HEALTH <= 0)) + return FALSE; + + return TRUE; } diff --git a/csqc/status.qc b/csqc/status.qc index 0b559eb0..e9733f69 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -4,8 +4,7 @@ vector (FO_Hud_Panel* panel) getPanelPosition; float getHudPanel(string); void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string); FO_Hud_Panel* getHudPanelPointer(float); -float GetGrenOneTypeForClass(float playerclass); -float GetGrenTwoTypeForClass(float playerclass); +float GetGrenTypeForClass(float gren_number, float playerclass); void(string panelid, float display, string text, string icon) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) @@ -75,7 +74,7 @@ void(string panelid, float display, string text) drawGren1Panel = { return; } - local float gren_type = GetGrenOneTypeForClass(playerclass); + local float gren_type = GetGrenTypeForClass(1, playerclass); local string icon = GrenadeIcons[gren_type].icon; drawIconPanel(panelid, display, text, icon); @@ -88,7 +87,7 @@ void(string panelid, float display, string text) drawGren2Panel = { return; } - local float gren_type = GetGrenTwoTypeForClass(playerclass); + local float gren_type = GetGrenTypeForClass(2, playerclass); local string icon = GrenadeIcons[gren_type].icon; drawIconPanel(panelid, display, text, icon); @@ -940,60 +939,61 @@ vector(float panelid) getFillSize = { return Hud_Panels[panelid].FillSize; } -float GetGrenOneTypeForClass(float playerclass) { - switch(playerclass) { - case PC_SCOUT: - if(fo_flash) { - return GR_TYPE_FLASH; - } else { - return GR_TYPE_CALTROP; +float GetGrenTypeForClass(float gren_number, float playerclass) { + switch(gren_number) { + case 1: + switch(playerclass) { + case PC_SCOUT: + if(fo_flash) { + return GR_TYPE_FLASH; + } else { + return GR_TYPE_CALTROP; + } + case PC_SNIPER: + return GR_TYPE_NORMAL; + case PC_SOLDIER: + return GR_TYPE_NORMAL; + case PC_DEMOMAN: + return GR_TYPE_NORMAL; + case PC_MEDIC: + return GR_TYPE_NORMAL; + case PC_HVYWEAP: + return GR_TYPE_NORMAL; + case PC_PYRO: + return GR_TYPE_NORMAL; + case PC_SPY: + return GR_TYPE_NORMAL; + case PC_ENGINEER: + return GR_TYPE_NORMAL; + default: + return GR_TYPE_NONE; } - case PC_SNIPER: - return GR_TYPE_NORMAL; - case PC_SOLDIER: - return GR_TYPE_NORMAL; - case PC_DEMOMAN: - return GR_TYPE_NORMAL; - case PC_MEDIC: - return GR_TYPE_NORMAL; - case PC_HVYWEAP: - return GR_TYPE_NORMAL; - case PC_PYRO: - return GR_TYPE_NORMAL; - case PC_SPY: - return GR_TYPE_NORMAL; - case PC_ENGINEER: - return GR_TYPE_NORMAL; - default: - return GR_TYPE_NONE; - } -} - -float GetGrenTwoTypeForClass(float playerclass) { - switch(playerclass) { - case PC_SCOUT: - return GR_TYPE_CONCUSSION; - case PC_SNIPER: - return GR_TYPE_FLARE; - case PC_SOLDIER: - return GR_TYPE_NAIL; - case PC_DEMOMAN: - return GR_TYPE_MIRV; - case PC_MEDIC: - if(medic_type == MEDIC_TYPE_BLAST) { - return GR_TYPE_BLAST; - } else { - return GR_TYPE_CONCUSSION; + case 2: + switch(playerclass) { + case PC_SCOUT: + return GR_TYPE_CONCUSSION; + case PC_SNIPER: + return GR_TYPE_FLARE; + case PC_SOLDIER: + return GR_TYPE_NAIL; + case PC_DEMOMAN: + return GR_TYPE_MIRV; + case PC_MEDIC: + if(medic_type == MEDIC_TYPE_BLAST) { + return GR_TYPE_BLAST; + } else { + return GR_TYPE_CONCUSSION; + } + case PC_HVYWEAP: + return GR_TYPE_MIRV; + case PC_PYRO: + return GR_TYPE_NAPALM; + case PC_SPY: + return GR_TYPE_GAS; + case PC_ENGINEER: + return GR_TYPE_EMP; + default: + return GR_TYPE_NONE; } - case PC_HVYWEAP: - return GR_TYPE_MIRV; - case PC_PYRO: - return GR_TYPE_NAPALM; - case PC_SPY: - return GR_TYPE_GAS; - case PC_ENGINEER: - return GR_TYPE_EMP; - default: - return GR_TYPE_NONE; } } From 1ccd631eb9e5ce2d48e68c4829f8ef648b66dff7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Aug 2021 01:26:08 +1000 Subject: [PATCH 1280/2474] Refactor --- csqc/main.qc | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 5b47cf2f..ca692961 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -12,6 +12,7 @@ void FO_WriteSettings(); void AddGrenTimer(float grentype); void GrenOne(); void GrenTwo(); +void PrimeOrThrowGren(float gren_number, float remaining_grenades, string server_command); void IsValidToPrimeGrenade(); void GetSelf() = { @@ -239,7 +240,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { GrenOne(); break; case "gren2": - GrenOne(); + GrenTwo(); break; case "+fo_showscores": if (cvar(FOCMD_OLDSCOREBOARD) == 1) @@ -364,37 +365,25 @@ void CSQC_Shutdown() = { } void GrenOne() = { - if !(IsValidToPrimeGrenade()) - return; - - if (!grentimer_waiting) { - if (SBAR.Gren1) { - localcmd("play grentimer.wav\n"); - local float grentype = GetGrenTypeForClass(1, SBAR.PlayerClass); - AddGrenTimer(grentype); - } - - grentimer_waiting = TRUE; - } - - localcmd("gren1_server"); + PrimeOrThrowGren(1, SBAR.Gren1, "gren1_server"); } void GrenTwo() = { + PrimeOrThrowGren(2, SBAR.Gren2, "gren2_server"); +} + +void PrimeOrThrowGren(float gren_number, float remaining_grenades, string server_command) { if !(IsValidToPrimeGrenade()) return; - if (!grentimer_waiting) { - if (SBAR.Gren2) { - localcmd("play grentimer.wav\n"); - local float grentype = GetGrenTypeForClass(2, SBAR.PlayerClass); - AddGrenTimer(grentype); - } - + if (!grentimer_waiting && remaining_grenades) { grentimer_waiting = TRUE; + localcmd("play grentimer.wav\n"); + local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); + AddGrenTimer(grentype); } - localcmd("gren2_server"); + localcmd(server_command); } void IsValidToPrimeGrenade() { From 0d2d20dc554718db95854cf8b8881e1f2ba408fe Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Aug 2021 01:50:22 +1000 Subject: [PATCH 1281/2474] Refactor --- csqc/main.qc | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index ca692961..ab18224c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,10 +10,9 @@ void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); -void GrenOne(); -void GrenTwo(); -void PrimeOrThrowGren(float gren_number, float remaining_grenades, string server_command); -void IsValidToPrimeGrenade(); +void PrimeOrThrowGren(float gren_number); +float RemainingGrenades(float gren_number); +float IsValidToUseGrenades(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -237,10 +236,10 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "gren1": - GrenOne(); + PrimeOrThrowGren(1, SBAR.Gren1); break; case "gren2": - GrenTwo(); + PrimeOrThrowGren(2, SBAR.Gren2); break; case "+fo_showscores": if (cvar(FOCMD_OLDSCOREBOARD) == 1) @@ -364,29 +363,31 @@ void CSQC_Shutdown() = { FO_WriteSettings(); } -void GrenOne() = { - PrimeOrThrowGren(1, SBAR.Gren1, "gren1_server"); -} - -void GrenTwo() = { - PrimeOrThrowGren(2, SBAR.Gren2, "gren2_server"); -} - -void PrimeOrThrowGren(float gren_number, float remaining_grenades, string server_command) { - if !(IsValidToPrimeGrenade()) +void PrimeOrThrowGren(float gren_number) { + if !(IsValidToUseGrenades()) return; - if (!grentimer_waiting && remaining_grenades) { + if (!grentimer_waiting && RemainingGrenades(gren_number)) { grentimer_waiting = TRUE; localcmd("play grentimer.wav\n"); local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); AddGrenTimer(grentype); } - localcmd(server_command); + local string command = strcat("gren", ftos(gren_number), "_server"); + localcmd(command); +} + +float RemainingGrenades(float gren_number) { + switch (gren_number) { + case 1: + return SBAR.Gren1; + case 2: + return SBAR.Gren2; + } } -void IsValidToPrimeGrenade() { +float IsValidToUseGrenades() { if (cvar(FOCMD_GRENTIMER) != 2) return FALSE; @@ -402,7 +403,7 @@ void IsValidToPrimeGrenade() { if ((SBAR.GameMode & GAMEMODE_QUAD) && !round_active) return FALSE; - if (getstatf(STAT_HEALTH <= 0)) + if (getstatf(STAT_HEALTH) <= 0) return FALSE; return TRUE; From fbc729496150391985a1ee437af4f1b808716b09 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Aug 2021 02:12:02 +1000 Subject: [PATCH 1282/2474] Refactor --- csqc/main.qc | 44 ++++++++++++++++---------------------------- ssqc/tforthlp.qc | 4 ++-- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index ab18224c..16ed8221 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -11,6 +11,8 @@ void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); void PrimeOrThrowGren(float gren_number); +void PrimeGren(float gren_number); +void ShowGrenadeTimer(float gren_number); float RemainingGrenades(float gren_number); float IsValidToUseGrenades(); @@ -209,37 +211,16 @@ noref float(string cmd) CSQC_ConsoleCommand = { Menu_Cancel(); break; case "primeone": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren1) { - localcmd("play grentimer.wav\n"); - grentype = GetGrenTypeForClass(1, SBAR.PlayerClass); - AddGrenTimer(grentype); - } - - grentimer_waiting = TRUE; - } - localcmd("primeone_server"); - } + PrimeGren(1); break; case "primetwo": - if(getstatf(STAT_HEALTH) > 0 && (!SBAR.GameMode || ((SBAR.GameMode & GAMEMODE_QUAD) && round_active) || (((SBAR.GameMode & GAMEMODE_DUEL) || (SBAR.GameMode & GAMEMODE_CLAN)) && !prematch && !round_over))) { - if(!grentimer_waiting) { - if(cvar(FOCMD_GRENTIMER) == 2 && SBAR.Gren2) { - localcmd("play grentimer.wav\n"); - grentype = GetGrenTypeForClass(2, SBAR.PlayerClass); - AddGrenTimer(grentype); - } - grentimer_waiting = TRUE; - } - localcmd("primetwo_server"); - } + PrimeGren(2); break; case "gren1": - PrimeOrThrowGren(1, SBAR.Gren1); + PrimeOrThrowGren(1); break; case "gren2": - PrimeOrThrowGren(2, SBAR.Gren2); + PrimeOrThrowGren(2); break; case "+fo_showscores": if (cvar(FOCMD_OLDSCOREBOARD) == 1) @@ -363,7 +344,17 @@ void CSQC_Shutdown() = { FO_WriteSettings(); } +void PrimeGren(float gren_number) { + ShowGrenadeTimer(gren_number); + localcmd(strcat("prime", ftos(gren_number), "_server")); +} + void PrimeOrThrowGren(float gren_number) { + ShowGrenadeTimer(gren_number); + localcmd(strcat("gren", ftos(gren_number), "_server")); +} + +void ShowGrenadeTimer(float gren_number) { if !(IsValidToUseGrenades()) return; @@ -373,9 +364,6 @@ void PrimeOrThrowGren(float gren_number) { local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); AddGrenTimer(grentype); } - - local string command = strcat("gren", ftos(gren_number), "_server"); - localcmd(command); } float RemainingGrenades(float gren_number) { diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 044bfa58..54f03c3d 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -179,8 +179,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); } else { - TeamFortress_Alias("primeone_server", TF_GRENADE_1, 0); - TeamFortress_Alias("primetwo_server", TF_GRENADE_2, 0); + TeamFortress_Alias("prime1_server", TF_GRENADE_1, 0); + TeamFortress_Alias("prime2_server", TF_GRENADE_2, 0); TeamFortress_Alias("gren1_server", TF_GRENADE_PT_1, 0); TeamFortress_Alias("gren2_server", TF_GRENADE_PT_2, 0); TeamFortress_AliasString("+gren1", "primeone"); From 3ed6d2a51728621408bd0493004f0a645967234b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 19 Aug 2021 00:10:31 +1000 Subject: [PATCH 1283/2474] Add 26 grenade timers (none as good as mine) --- README.md | 1 + csqc/csextradefs.qc | 1 + csqc/events.qc | 4 +-- csqc/main.qc | 3 ++- csqc/settings.qc | 5 ++++ menu/options_basic.qc | 62 ++++++++++++++++++++++++++++++++++++------- ssqc/world.qc | 26 ++++++++++++++++++ 7 files changed, 89 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a306e08c..5b7aed01 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ New features * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press +* CSQC - fo_grentimersound grentimer.wav * CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+aux_jump` to use with rj scripts) * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e93669a1..cb8512be 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -471,6 +471,7 @@ enum { #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" +#define FOCMD_GRENTIMERSOUND "fo_grentimersound" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" float team_no; diff --git a/csqc/events.qc b/csqc/events.qc index 851100bd..6f411e55 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -105,8 +105,8 @@ void() CSQC_Parse_Event = { AddGrenTimer(grentype); } if(timertype == 1) { - localcmd("play grentimer.wav\n"); - } + localcmd(sprintf("play %s\n", cvar_string(FOCMD_GRENTIMERSOUND))); + } break; case MSG_CLIENT_MENU: float menutype = readfloat(); diff --git a/csqc/main.qc b/csqc/main.qc index 16ed8221..05f80a41 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -37,6 +37,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); + registercvar(FOCMD_GRENTIMERSOUND, "grentimer.wav"); registercvar(FOCMD_OLDSCOREBOARD, "0"); registercommand("fo_menu_game"); @@ -360,7 +361,7 @@ void ShowGrenadeTimer(float gren_number) { if (!grentimer_waiting && RemainingGrenades(gren_number)) { grentimer_waiting = TRUE; - localcmd("play grentimer.wav\n"); + localcmd(sprintf("play %s\n", cvar_string(FOCMD_GRENTIMERSOUND))); local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); AddGrenTimer(grentype); } diff --git a/csqc/settings.qc b/csqc/settings.qc index 049cd25b..bca130cd 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -5,6 +5,7 @@ void FO_WriteSettings() filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); string line = FormatCfgString("", FOCMD_AUTOHOP, ftos(cvar(FOCMD_AUTOHOP))); line = FormatCfgString(line, FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); + line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, cvar_string(FOCMD_GRENTIMERSOUND)); line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(cvar(FOCMD_OLDSCOREBOARD))); fputs(filehandle, line); fclose(filehandle); @@ -14,6 +15,7 @@ void FO_LoadDefaultSettings() { cvar_set(FOCMD_AUTOHOP, "0"); cvar_set(FOCMD_GRENTIMER, "1"); + cvar_set(FOCMD_GRENTIMERSOUND, "grentimer.wav"); cvar_set(FOCMD_OLDSCOREBOARD, "0"); } @@ -49,6 +51,9 @@ void FO_LoadSettings() case FOCMD_GRENTIMER: cvar_set(FOCMD_GRENTIMER, val); break; + case FOCMD_GRENTIMERSOUND: + cvar_set(FOCMD_GRENTIMERSOUND, val); + break; case FOCMD_OLDSCOREBOARD: cvar_set(FOCMD_OLDSCOREBOARD, val); break; diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 286dfc53..7fa9eded 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -136,18 +136,60 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [0, pos], [0, 8] - ); + ); pos += 8; pos += 8; + fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; pos += 8; - fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - /* fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( */ - /* "0 \"None\" " */ - /* "1 \"Server\" " */ - /* "2 \"Immediate\" " */ - /* )), fl, [0, pos], [0, 8]); pos += 8; */ + fr.add( + spawn( + mitem_text, + item_text:strcat("^{e080} ^a","Grenades","^d ^{e082}"), + item_command:"", + item_scale:8, + item_flags:IF_CENTERALIGN + ), + RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, + [0, pos], + [0, 8] + ); pos += 8; + pos += 8; + fr.add(menuitemcombo_spawn (_("Timer"), "fo_grentimer", '280 8', _( + "2 \"On\" " + "0 \"Silent\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn (_("Sound"), "fo_grentimersound", '280 8', _( + "grentimer.wav \"Default\" " + "mcp_grentimer1.wav \"1\" " + "mcp_grentimer2.wav \"2\" " + "mcp_grentimer3.wav \"3\" " + "mcp_grentimer4.wav \"4\" " + "mcp_grentimer5.wav \"5\" " + "mcp_grentimer6.wav \"6\" " + "mcp_grentimer7.wav \"7\" " + "mcp_grentimer8.wav \"8\" " + "mcp_grentimer9.wav \"9\" " + "mcp_grentimer10.wav \"10\" " + "mcp_grentimer11.wav \"11\" " + "mcp_grentimer12.wav \"12\" " + "mcp_grentimer13.wav \"13\" " + "mcp_grentimer14.wav \"14\" " + "mcp_grentimer15.wav \"15\" " + "mcp_grentimer16.wav \"16\" " + "mcp_grentimer17.wav \"17\" " + "mcp_grentimer18.wav \"18\" " + "mcp_grentimer19.wav \"19\" " + "mcp_grentimer20.wav \"20\" " + "mcp_grentimer21.wav \"21\" " + "mcp_grentimer22.wav \"22\" " + "mcp_grentimer23.wav \"23\" " + "mcp_grentimer24.wav \"24\" " + "mcp_grentimer25.wav \"25\" " + "mcp_grentimer26.wav \"26\" " + )), fl, [0, pos], [0, 8]); pos += 8; + + /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; diff --git a/ssqc/world.qc b/ssqc/world.qc index dfb5eedb..62b329a5 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -265,6 +265,32 @@ void () worldspawn = { precache_model2("progs/grenade3.mdl"); precache_model2(MODEL_PROJ_DIAM2); precache_sound("grentimer.wav"); + precache_sound("mcp_grentimer1.wav"); + precache_sound("mcp_grentimer2.wav"); + precache_sound("mcp_grentimer3.wav"); + precache_sound("mcp_grentimer4.wav"); + precache_sound("mcp_grentimer5.wav"); + precache_sound("mcp_grentimer6.wav"); + precache_sound("mcp_grentimer7.wav"); + precache_sound("mcp_grentimer8.wav"); + precache_sound("mcp_grentimer9.wav"); + precache_sound("mcp_grentimer10.wav"); + precache_sound("mcp_grentimer11.wav"); + precache_sound("mcp_grentimer12.wav"); + precache_sound("mcp_grentimer13.wav"); + precache_sound("mcp_grentimer14.wav"); + precache_sound("mcp_grentimer15.wav"); + precache_sound("mcp_grentimer16.wav"); + precache_sound("mcp_grentimer17.wav"); + precache_sound("mcp_grentimer18.wav"); + precache_sound("mcp_grentimer19.wav"); + precache_sound("mcp_grentimer20.wav"); + precache_sound("mcp_grentimer21.wav"); + precache_sound("mcp_grentimer22.wav"); + precache_sound("mcp_grentimer23.wav"); + precache_sound("mcp_grentimer24.wav"); + precache_sound("mcp_grentimer25.wav"); + precache_sound("mcp_grentimer26.wav"); precache_sound("buttons/switch04.wav"); precache_sound("boss1/out1.wav"); precache_sound("items/qpi2.wav"); From 46943969c8c80e82344afa1aa56837349842ec89 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 22 Aug 2021 19:00:15 +1000 Subject: [PATCH 1284/2474] Set quick attack aliases for spectators --- ssqc/client.qc | 3 +-- ssqc/spect.qc | 3 +++ ssqc/tforthlp.qc | 21 +++++++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 27d4d032..39659fd5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -57,6 +57,7 @@ void () StopTimer; void () StartQuadRound; void (string cl_pwd) Admin_Check; void () Admin_Aliases; +void () Quick_Aliases; void () PreMatch_Message; float () GetLastWeaponImpulse; float () CheckAllPlayersReady; @@ -2747,8 +2748,6 @@ void (optional float csqcactive) ClientConnect = { local string st; local float got_one; - stuffcmd(self, "set fortressone 1\n"); - bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 16a095a2..97cf7f7e 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -12,6 +12,7 @@ void () SpectatorDisconnect; void () SpectatorImpulseCommand; void () SpectatorThink; +void () Quick_Aliases; void () Admin_Aliases; void () SpectatorConnect = { @@ -28,6 +29,8 @@ void () SpectatorConnect = { if (infokey(self,"*admin")) self.is_admin = stof(infokey(self, "*admin")); + Quick_Aliases(); + st = infokey(self, "apw"); if (st == string_null) st = infokey(self, "adminpwd"); diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 044bfa58..59e3a32b 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -8,6 +8,18 @@ void (float inp) MOTD_Input = { Menu_Team_Input(inp); }; +void () Quick_Aliases = +{ + TeamFortress_AliasString("+quick1", "impulse 1;+attack"); + TeamFortress_AliasString("-quick1", "-attack"); + TeamFortress_AliasString("+quick2", "impulse 2;+attack"); + TeamFortress_AliasString("-quick2", "-attack"); + TeamFortress_AliasString("+quick3", "impulse 3;+attack"); + TeamFortress_AliasString("-quick3", "-attack"); + TeamFortress_AliasString("+quick4", "impulse 4;+attack"); + TeamFortress_AliasString("-quick4", "-attack"); +}; + void () TeamFortress_MOTD = { if (votemode) { return; @@ -248,14 +260,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo TeamFortress_AliasString("break", "cmd break"); - TeamFortress_AliasString("+quick1", "impulse 1;+attack"); - TeamFortress_AliasString("-quick1", "-attack"); - TeamFortress_AliasString("+quick2", "impulse 2;+attack"); - TeamFortress_AliasString("-quick2", "-attack"); - TeamFortress_AliasString("+quick3", "impulse 3;+attack"); - TeamFortress_AliasString("-quick3", "-attack"); - TeamFortress_AliasString("+quick4", "impulse 4;+attack"); - TeamFortress_AliasString("-quick4", "-attack"); + Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) Menu_Login(); From 52ecbae857b28bae69af2d504bcacd9ffd0eb590 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 22 Aug 2021 19:02:23 +1000 Subject: [PATCH 1285/2474] Remove unneeded declaration --- ssqc/client.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 39659fd5..238d89d4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -57,7 +57,6 @@ void () StopTimer; void () StartQuadRound; void (string cl_pwd) Admin_Check; void () Admin_Aliases; -void () Quick_Aliases; void () PreMatch_Message; float () GetLastWeaponImpulse; float () CheckAllPlayersReady; From 589675ec214473c4eb94b058deece2647be97928 Mon Sep 17 00:00:00 2001 From: lordee Date: Thu, 26 Aug 2021 20:30:45 +1000 Subject: [PATCH 1286/2474] remove debug message --- ssqc/tfortmap.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 87ea4724..6e2d7761 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2123,7 +2123,7 @@ void () tfgoal_timer_tick = { self.nextthink = time + self.search_time; } else { - bprint(PRINT_HIGH, "inactivating timer\n"); + //bprint(PRINT_HIGH, "inactivating timer\n"); InactivateGoal(self); self.think = tfgoal_timer_tick; self.nextthink = time + self.search_time; From f520307ab41ec1ec91c30ff497ddfa5320d40c18 Mon Sep 17 00:00:00 2001 From: me Date: Wed, 1 Sep 2021 17:22:00 +1200 Subject: [PATCH 1287/2474] health hud works, ran out of array --- csqc/csextradefs.qc | 49 +++++++++++++++-- csqc/hud.qc | 6 +++ csqc/hud_helpers.qc | 114 +++++++++++++++++++++++++++++++++++++-- csqc/main.qc | 16 +++++- csqc/status.qc | 126 ++++++++++++++++++++++++++++++++++++++++++-- share/defs.h | 10 ++++ 6 files changed, 310 insertions(+), 11 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e93669a1..6c37c66d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -218,8 +218,8 @@ FO_Hud_Icons HudIcons[37] = { {ICON_FLAG_RED}, {ICON_FLAG_YELLOW}, {ICON_FLAG_GREEN}, - {"textures/wad/num_percent.png"}, - {"textures/wad/anum_percent.png"} + {"textures/wad/num_percent"}, + {"textures/wad/anum_percent"} }; FO_Hud_Icons GrenadeIcons[12] = { @@ -237,6 +237,40 @@ FO_Hud_Icons GrenadeIcons[12] = { {ICON_GREN_BLAST}, }; +FO_Hud_Icons FaceIcons[] = { + //normal + {"textures/wad/face1"}, + {"textures/wad/face2"}, + {"textures/wad/face3"}, + {"textures/wad/face4"}, + {"textures/wad/face5"}, + //pain + {"textures/wad/face_p1"}, + {"textures/wad/face_p2"}, + {"textures/wad/face_p3"}, + {"textures/wad/face_p4"}, + {"textures/wad/face_p5"}, +}; + +FO_Hud_Icons FaceInvisibleIcon = {"textures/wad/face_invis"}; +FO_Hud_Icons FaceInvisibleInvulnerableIcon = {"textures/wad/face_inv2"}; +FO_Hud_Icons FaceInvulnerableIcon = {"textures/wad/face_invul2"}; +FO_Hud_Icons FaceQuadIcon = {"textures/wad/face_quad"}; + +FO_Hud_Icons ArmourIcons[] = { + {"textures/wad/disc"}, + {"textures/wad/sb_armor1"}, + {"textures/wad/sb_armor2"}, + {"textures/wad/sb_armor3"}, +}; +FO_Hud_Icons AmmoIcons[] = { + {"textures/wad/sb_shells"}, + {"textures/wad/sb_nails"}, + {"textures/wad/sb_rocket"}, + {"textures/wad/sb_cells"}, +}; + + typedef struct { string ClipSize; float FragStreak; @@ -383,7 +417,6 @@ typedef struct { void(string panelid, float display, string text, string icon) drawPanel; string() getValue; float Style; - FO_Hud_Icons * Icon; float Snap; float Status; float SnapID; @@ -465,6 +498,12 @@ enum { HUD_PANEL_SHOWSCORES, HUD_PANEL_TEAM_SCORE, HUD_PANEL_MAP_MENU, + HUD_PANEL_HEALTH, + HUD_PANEL_FACE, + HUD_PANEL_AMMO, + HUD_PANEL_AMMO_ICON, + HUD_PANEL_ARMOUR, + HUD_PANEL_ARMOUR_ICON, HUD_PANEL_HUDOPTIONS, }; @@ -472,11 +511,15 @@ enum { #define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" +#define FOCMD_FTE_HUD "fo_fte_hud" float team_no; float is_spectator; float player_class; float is_observer; +//float health; +float oldhealth; +float painfinished; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/hud.qc b/csqc/hud.qc index cb1c1ea3..d9c6e171 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -137,6 +137,8 @@ string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { return ftos(panel.Orientation); case "snap": return ftos(panel.Snap); + case "style": + return ftos(panel.Style); default: print("^1Setting^7 '", setting, "' does not exist!\n"); break; @@ -161,6 +163,7 @@ void FO_Hud_Editor_Show_Panel(string panelid) = { print("\tshow: ", ftos(panel.Display), "\n"); print("\torientation: ", ftos(panel.Orientation), "\n"); print("\tsnap: ", ftos(panel.Snap), "\n"); + print("\tstyle: ", ftos(panel.Style), "\n"); } void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting) = { @@ -225,6 +228,9 @@ void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string valu } panel.Snap = val; break; + case "style": + panel.Style = stof(value); + break; default: print("^1Setting^7 '", setting, "' does not exist!\n"); break; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 3e3eefa6..f1174b94 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -181,6 +181,56 @@ void Hud_DrawStringLMP(vector pos, string value, float size) } } +void Hud_DrawStringLMPThreshold(vector pos, string value, float size, float threshold) +{ + float c; + float len, i, intval; + string s, lmpname; + if (!size) size = 24; + vector vsize = [size, size, 0]; + s = value; + intval = stof(value); + len = strlen(s); + i = 0; + + while(i health) { + painfinished = time + 0.2; + } +} + void CSQC_Shutdown() = { FO_WriteSettings(); } diff --git a/csqc/status.qc b/csqc/status.qc index 0b559eb0..929c5da4 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -3,6 +3,7 @@ float fo_to_sui_aligntment(float fo_align); vector (FO_Hud_Panel* panel) getPanelPosition; float getHudPanel(string); void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string); +void Hud_DrawLMPThreshold(FO_Hud_Panel*, string, float); FO_Hud_Panel* getHudPanelPointer(float); float GetGrenOneTypeForClass(float playerclass); float GetGrenTwoTypeForClass(float playerclass); @@ -161,6 +162,115 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel } }; +void(string panelid, float display, string text) drawFacePanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + local float playerclass = SBAR.PlayerClass; //we could add different faces per class? + + local string icon = FaceInvisibleInvulnerableIcon.icon; + + if(playerclass) { + local float health = getstatf(STAT_HEALTH); + if(health > 0) { + local float items = getstatf(STAT_ITEMS); + //we should add all the combos :) + if(items & IT_INVULNERABILITY && items & IT_INVISIBILITY) icon = FaceInvisibleInvulnerableIcon.icon; + else if(items & IT_INVULNERABILITY) icon = FaceInvulnerableIcon.icon; + else if(items & IT_INVISIBILITY) icon = FaceInvisibleIcon.icon; + else if(items & IT_QUAD) icon = FaceQuadIcon.icon; + else { + local float index = 0; + if(health >= 80) index = 0; + else if(health >= 60) index = 1; + else if(health >= 40) index = 2; + else if(health >= 20) index = 3; + else index = 4; + + if(time < painfinished) { + index += 5; + } + + icon = FaceIcons[index].icon; + } + } else { + icon = FaceIcons[4].icon; + } + } + + drawIconPanel(panelid, display, text, icon); +}; + +void(string panelid, float display, string text) drawArmourPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + local float playerclass = SBAR.PlayerClass; + + local string icon = fo_hud_editor?ArmourIcons[1].icon:""; + + if(playerclass) { + local float items = getstatf(STAT_ITEMS); + if(items & IT_INVULNERABILITY) icon = ArmourIcons[0].icon; + else if(items & IT_ARMOR1) icon = ArmourIcons[1].icon; + else if(items & IT_ARMOR2) icon = ArmourIcons[2].icon; + else if(items & IT_ARMOR3) icon = ArmourIcons[3].icon; + } + + if(icon != "") drawIconPanel(panelid, display, text, icon); +}; + +void(string panelid, float display, string text) drawAmmoPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + local string icon = fo_hud_editor?AmmoIcons[0].icon:""; + + local float items = getstatf(STAT_ITEMS); + if(items & IT_SHELLS) icon = AmmoIcons[0].icon; + else if(items & IT_NAILS) icon = AmmoIcons[1].icon; + else if(items & IT_ROCKETS) icon = AmmoIcons[2].icon; + else if(items & IT_CELLS) icon = AmmoIcons[3].icon; + + if(icon != "") drawIconPanel(panelid, display, text, icon); +}; + +void(string panelid, float display, string text) drawInvShellsPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + drawIconPanel(panelid, display, text, AmmoIcons[0].icon); +}; +void(string panelid, float display, string text) drawInvNailsPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + drawIconPanel(panelid, display, text, AmmoIcons[1].icon); +}; +void(string panelid, float display, string text) drawInvRocketsPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + drawIconPanel(panelid, display, text, AmmoIcons[2].icon); +}; +void(string panelid, float display, string text) drawInvCellsPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + drawIconPanel(panelid, display, text, AmmoIcons[3].icon); +}; + + +void(string panelid, float display, string text, float threshold) drawBigNumberPanel = { + if (display || fo_hud_editor) + { + float id = getHudPanel(panelid); + + if(id < 0) { + return; + } + + Hud_DrawLMPThreshold(getHudPanelPointer(id), text, threshold); + } +}; + +void(string panelid, float display, string text) drawHealthTextPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + drawBigNumberPanel(panelid, display, text, 26); +}; + +void(string panelid, float display, string text) drawAmmoTextPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + drawBigNumberPanel(panelid, display, text, 11); +}; + + void(string panelid, float display, string text, string icon) doNothing = {}; void(string panelid, float display, string text, string icon) drawSimplePanel = { @@ -879,13 +989,13 @@ var FO_Hud_Panel Hud_Panels[] = { // id, Name, Position, FillSize, Scale, TextScale, Display, Orientation, // void drawPanel(string panelid, float display, string text, string icon), // string getValue(), -// Icon, Snap, Status +// Snap, Status {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, {"capspanel",FO_HUD_CAPS_NAME,'10 80','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'10 110','50 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'10 140','50 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, + {"gren1panel",FO_HUD_GREN1_NAME,'10 110','26 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, + {"gren2panel",FO_HUD_GREN2_NAME,'10 140','26 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 230','150 260',1,0,1,0, drawFlagInfo, {return "";}}, @@ -898,6 +1008,16 @@ var FO_Hud_Panel Hud_Panels[] = { {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'0 0','72 12',2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 30','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"healthpanel",FO_HUD_HEALTH_NAME,'-64 0','72 26',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, + {"facepanel",FO_HUD_FACE_NAME,'-64 0','26 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawFacePanel, {return "";}, 0, 34}, + {"ammopanel",FO_HUD_AMMO_NAME,'10 30','72 26',1,0,1,FO_HUD_INSERT_AFTER, drawAmmoTextPanel, {return ftos(getstatf(STAT_AMMO));}}, + {"ammoiconpanel",FO_HUD_AMMO_ICON_NAME,'10 30','26 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawAmmoPanel, {return "";}}, + {"armourpanel",FO_HUD_ARMOUR_NAME,'10 30','72 26',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}}, + {"armouriconpanel",FO_HUD_ARMOUR_ICON_NAME,'10 30','26 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawArmourPanel, {return "";}}, +// {"invshellspanel",FO_HUD_INV_SHELLS_NAME,'10 140','26 26',1,1.4,1,0, drawInvShellsPanel, {return ftos(getstatf(STAT_SHELLS));}, 1, 33}, +// {"invnailspanel",FO_HUD_INV_NAILS_NAME,'10 140','26 26',1,1.4,1,0, drawInvNailsPanel, {return ftos(getstatf(STAT_NAILS));}, 1, 33}, +// {"invrocketspanel",FO_HUD_INV_ROCKETS_NAME,'10 140','26 26',1,1.4,1,0, drawInvRocketsPanel, {return ftos(getstatf(STAT_ROCKETS));}, 1, 33}, +// {"invcellspanel",FO_HUD_INV_CELLS_NAME,'10 140','26 26',1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 182',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; diff --git a/share/defs.h b/share/defs.h index e200ebce..72359061 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1404,6 +1404,16 @@ #define FO_HUD_READY_NAME "Ready Status" #define FO_HUD_SHOWSCORES_NAME "Show Scores" #define FO_HUD_MAP_MENU_NAME "Map Menu" +#define FO_HUD_HEALTH_NAME "Health" +#define FO_HUD_FACE_NAME "Face" +#define FO_HUD_AMMO_NAME "Ammo" +#define FO_HUD_AMMO_ICON_NAME "Ammo Icon" +#define FO_HUD_ARMOUR_NAME "Armour" +#define FO_HUD_ARMOUR_ICON_NAME "Armour Icon" +#define FO_HUD_INV_SHELLS_NAME "Shells" +#define FO_HUD_INV_NAILS_NAME "Nails" +#define FO_HUD_INV_ROCKETS_NAME "Rockets" +#define FO_HUD_INV_CELLS_NAME "Cells" #define FO_HUD_TEAM_SCORE_NAME "Team Score" From b5094ebb03c0d6a172865384bfbb0a3fdb37f6bb Mon Sep 17 00:00:00 2001 From: me Date: Wed, 1 Sep 2021 19:36:04 +1200 Subject: [PATCH 1288/2474] health hud works, ran out of array --- csqc/csextradefs.qc | 1 + csqc/status.qc | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6c37c66d..c98661fd 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -422,6 +422,7 @@ typedef struct { float SnapID; } FO_Hud_Panel; +FO_Hud_Panel NullPanel; FO_Hud_Panel DrawPanel; FO_Hud_Panel NewPanel; float Editor_SelectedPanel_Index; diff --git a/csqc/status.qc b/csqc/status.qc index 929c5da4..3f902c39 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1020,7 +1020,7 @@ var FO_Hud_Panel Hud_Panels[] = { // {"invcellspanel",FO_HUD_INV_CELLS_NAME,'10 140','26 26',1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 182',1,0,1,0, doNothing, {return DrawPanel.id;}}, }; - +/* float(string panelid) getHudPanel = { for(float i = 0; i < Hud_Panels.length; i++) { if(Hud_Panels[i].id == panelid) { @@ -1029,11 +1029,21 @@ float(string panelid) getHudPanel = { } return -1; }; +*/ FO_Hud_Panel* (float panelid) getHudPanelPointer = { return &(Hud_Panels[panelid]); }; +FO_Hud_Panel* (string panelid) getAnyHudPanelByNamePointer = { + for(float i = 0; i < Hud_Panels.length; i++) { + if(Hud_Panels[i].id == panelid) { + return &(Hud_Panels[i]); + } + } + return NullPanel; +}; + vector (FO_Hud_Panel* panel, float scale) getScaledPanelPosition = { if(panel.Snap == HUD_SNAP_NONE) { return panel.Position; //Hud_Panels[panelid].Position; From 244d3ec66b8e4ba959fabb15f4b579410035a604 Mon Sep 17 00:00:00 2001 From: lordee Date: Thu, 2 Sep 2021 22:26:00 +1000 Subject: [PATCH 1289/2474] channel fix for backpacks stopping grentimer sound --- ssqc/actions.qc | 2 +- ssqc/items.qc | 2 +- ssqc/tfort.qc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 3a3f5ee9..c9104adb 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -94,7 +94,7 @@ void () TeamFortress_Discard = { self.ammo_cells = 0; } W_SetCurrentAmmo(self); - FO_Sound(self, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_AUTO, "weapons/lock4.wav", 1, ATTN_NORM); newmis.enemy = self; newmis.health = time; newmis.weapon = 0; diff --git a/ssqc/items.qc b/ssqc/items.qc index 5541688f..f736c34c 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -1378,7 +1378,7 @@ void () BackpackTouch = { } } sprint(other, PRINT_LOW, "\n"); - FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); + FO_Sound(other, CHAN_AUTO, "weapons/lock4.wav", 1, ATTN_NORM); stuffcmd(other, "bf\n"); dremove(self); self = other; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index a47ff3ec..83e2cd91 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2696,7 +2696,7 @@ void () TeamFortress_AmmoboxTouch = { other.ammo_cells = other.ammo_cells + self.ammo_cells; dremove(self); bound_other_ammo(other); - FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, 1); + FO_Sound(other, CHAN_AUTO, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); self = other; W_SetCurrentAmmo(self); From 81836237020528434232b475d644269908e2735e Mon Sep 17 00:00:00 2001 From: me Date: Thu, 23 Sep 2021 14:39:26 +1200 Subject: [PATCH 1290/2474] fo-hud in some sort of glory --- csqc/csextradefs.qc | 17 ++- csqc/events.qc | 4 + csqc/hud.qc | 152 +++++++++++-------- csqc/hud_helpers.qc | 58 +++---- csqc/main.qc | 41 ++++- csqc/menu.qc | 17 +-- csqc/status.qc | 363 +++++++++++++++++++++++++------------------- share/defs.h | 3 + ssqc/csmenu.qc | 18 +++ ssqc/world.qc | 1 + 10 files changed, 406 insertions(+), 268 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c98661fd..e493b37d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -89,6 +89,7 @@ float nailgren_type; float prematch; float round_active; float round_over; +float round_time_remaining; float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown @@ -114,7 +115,7 @@ string vote_list_filter; float(string) GetDrawPanel; void(string id, string identify) Hud_DrawIdentifyPanel; -void (string panelid, float display, string text, string icon) Hud_DrawHudOptionsPanel; +void (string panelid, float display, string text) Hud_DrawHudOptionsPanel; void (string id, float playerclass) Hud_DrawClassInfoPanel; void (string panelid) Hud_DrawFlagStatusBar; void (string panelid) Hud_DrawTeamScorePanel; @@ -182,7 +183,7 @@ typedef struct string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons[37] = { +FO_Hud_Icons HudIcons2[37] = { {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, @@ -414,7 +415,7 @@ typedef struct { float TextScale; float Display; float Orientation; - void(string panelid, float display, string text, string icon) drawPanel; + void(string panelid, float display, string text) drawPanel; string() getValue; float Style; float Snap; @@ -482,6 +483,7 @@ string FO_ScoreBoardColumns[] = { }; enum { + HUD_PANEL_HUDOPTIONS, HUD_PANEL_CLIPSIZE, HUD_PANEL_FRAGSTREAK, HUD_PANEL_CAPS, @@ -505,7 +507,10 @@ enum { HUD_PANEL_AMMO_ICON, HUD_PANEL_ARMOUR, HUD_PANEL_ARMOUR_ICON, - HUD_PANEL_HUDOPTIONS, + HUD_PANEL_INV_SHELLS, + HUD_PANEL_INV_NAILS, + HUD_PANEL_INV_ROCKETS, + HUD_PANEL_INV_CELLS, }; #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" @@ -521,6 +526,10 @@ float is_observer; //float health; float oldhealth; float painfinished; +vector thisorigin; +vector lastorigin; +float nextoriginupdate; +float speed; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/events.qc b/csqc/events.qc index 851100bd..f1ed11df 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -260,6 +260,10 @@ void() CSQC_Parse_Event = { //motd_expiry = time + MOTD_TIME; quad_round = readfloat(); //game_started = readbyte(); + local float rtr = readfloat(); + if(rtr) { + round_time_remaining = time + rtr; + } break; case MSG_GRENADESETTINGS: fo_flash = readfloat(); diff --git a/csqc/hud.qc b/csqc/hud.qc index d9c6e171..ed27ebca 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -6,25 +6,27 @@ float GetDrawPanel(string id) return i; } } +// for(float i = 0; i < Hud_ExtraPanels.length; i++) { +// if(Hud_ExtraPanels[i].id == id) { +// DrawPanel = Hud_ExtraPanels[i]; +// return i; +// } +// } return -1; } void SetDrawPanel(string id) { - for(float i = 0; i < Hud_Panels.length; i++) { - if(Hud_Panels[i].id == id) { - Hud_Panels[i] = DrawPanel; - } - } -} - -float GetPanelById(string id) = { for(float i = 0; i < Hud_Panels.length; i++) { if(Hud_Panels[i].id == id) { - return i; + Hud_Panels[i] = DrawPanel; } } - return 0; +// for(float i = 0; i < Hud_ExtraPanels.length; i++) { +// if(Hud_ExtraPanels[i].id == id) { +// Hud_ExtraPanels[i] = DrawPanel; +// } +// } } void Hud_WriteCfg(string path) @@ -38,6 +40,10 @@ void Hud_WriteCfg(string path) DrawPanel = Hud_Panels[i]; line = GetPanelString(line, Hud_Panels[i].id); } +// for(float i = 0; i < Hud_ExtraPanels.length; i++) { +// DrawPanel = Hud_ExtraPanels[i]; +// line = GetPanelString(line, Hud_ExtraPanels[i].id); +// } fputs(filehandle, line); fclose(filehandle); @@ -108,16 +114,25 @@ void FO_Hud_Editor_List_Panels() = { for(float i = 0; i < Hud_Panels.length; i++) { print(Hud_Panels[i].id, ": ", Hud_Panels[i].Name, "\n"); } +// for(float i = 0; i < Hud_ExtraPanels.length; i++) { +// print(Hud_ExtraPanels[i].id, ": ", Hud_ExtraPanels[i].Name, "\n"); +// } } string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { +/* float id = getHudPanel(panelid); if(id < 0) { print("^1HUD Element^7 '", panelid, "' does not exist!\n"); return ""; } +*/ + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + if(!panel || &panel == &NullPanel) { + print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + return ""; + } - FO_Hud_Panel* panel = getHudPanelPointer(id); switch (setting) { case "id": return panel.id; @@ -147,13 +162,18 @@ string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { } void FO_Hud_Editor_Show_Panel(string panelid) = { + /* float id = getHudPanel(panelid); if(id < 0) { print("^1HUD Element^7 '", panelid, "' does not exist!\n"); return; } - - FO_Hud_Panel* panel = getHudPanelPointer(id); + */ + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + if(!panel || &panel == &NullPanel) { + print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + return; + } print("^1id^7: ", panel.id, "\n"); print("\tname: ", panel.Name, "\n"); print("\tposition: ", vtos(panel.Position), "\n"); @@ -170,7 +190,7 @@ void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting) = { if(panelid == "help" || panelid == "?") { print("^1orientation^7: Extends from base to the... 0 = Left, 1 = Right, 2 = Middle (where applicable)\n"); print("^1snap^7: 0 = None, Horzontal: 1/2/4 = Left/Centre/Right, Vertical: 8/16/32 = Top/Middle/Bottom)\n"); - return ""; + return; } if(setting == "") { FO_Hud_Editor_Show_Panel(panelid); @@ -180,15 +200,20 @@ void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting) = { } void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string value) = { +/* float id = getHudPanel(panelid); if(id < 0) { print("^1HUD Element^7 '", panelid, "' does not exist!\n"); return; } - +*/ float val = 0; - FO_Hud_Panel* panel = getHudPanelPointer(id); + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + if(!panel || &panel == &NullPanel) { + print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + return; + } switch (setting) { case "id": print("^5id ^1can't be changed^7!\n"); @@ -224,7 +249,7 @@ void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string valu panel.Position.y = 0; } } else { - panel.Position = getPosition(id); + panel.Position = getPanelPosition(panel); } panel.Snap = val; break; @@ -281,16 +306,10 @@ void (float dx, float dy) Hud_MapMenuPanel_Move = { }; void(string panelid) Hud_DrawMapMenuPanel = { - float id = getHudPanel(panelid); - - if(id < 0) { - return; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); local vector fillsize = panel.FillSize * panel.Scale; local float alpha = fo_hud_editor?0.2:0.9; - local vector position = getPosition(id); + local vector position = getPanelPosition(panel); if(panel.Display) { setcursormode(TRUE); } @@ -444,16 +463,17 @@ void(string panelid) Hud_DrawMapMenuPanel = { current_vote_selected = TRUE; } + ////Make it half the width of the map info area and aspect of 1.25:1 + //vector levelshotsize = [mapinfowidth / 2, mapinfowidth * 2 / 5]; + //No, make it 16:9 and 2/3 of the width + vector levelshotsize = [mapinfowidth * 2 / 3, mapinfowidth * 2 * 9 / (3 * 16)]; + //Map image float filehandle; string levelshot = strcat("textures/levelshots/",vote_selected_item.owner.name,".jpg"); //need to fix extensions somehow filehandle = fopen(levelshot, FILE_READ); if (filehandle >= 0) { fclose(filehandle); - ////Make it half the width of the map info area and aspect of 1.25:1 - //vector levelshotsize = [mapinfowidth / 2, mapinfowidth * 2 / 5]; - //No, make it 16:9 and 2/3 of the width - vector levelshotsize = [mapinfowidth * 2 / 3, mapinfowidth * 2 * 9 / (3 * 16)]; sui_push_frame([mapheadingpos.x + mapinfowidth - levelshotsize.x - padding,mapheadingpos.y + titlesize + padding * 2], levelshotsize); sui_pic([0,0], levelshotsize, levelshot, [1,1,1], 1, 0); sui_border_box([0,0], levelshotsize, 1, MENU_TEXT_GREEN, 0.6, 0); @@ -519,7 +539,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { //Map description - vector descriptionpos = [mapheadingpos.x,position.y + fillsize.y - padding * 4 - titlesize - listitemsize.y * 3] + vector descriptionpos = [mapheadingpos.x,position.y + fillsize.y - padding * 4 - titlesize - listitemsize.y * 3]; sui_push_frame(descriptionpos, [mapinfowidth - padding * 2, listitemsize.y * 3]); sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); sui_text([padding / 2, padding / 2], [listitemsize.y,listitemsize.y], vote_selected_item.owner.description, MENU_TEXT_1, 1, 0); @@ -552,14 +572,8 @@ void(string panelid) Hud_DrawMapMenuPanel = { } void(string panelid) Hud_DrawTeamScorePanel = { - float id = getHudPanel(panelid); - - if(id < 0) { - return; - } - float alpha = 0; - FO_Hud_Panel* panel = getHudPanelPointer(id); + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); //vector size = getFillSize(id); float textScale = panel.Scale; //panel.TextScale; //panel.TextScale?panel.TextScale:panel.Scale; @@ -721,9 +735,15 @@ void Hud_DrawHudOptionsPanelSelector() { Editor_SelectedPanel_Index = j; } } +// for(float i = 0,j = 0; i < min(numlines, Hud_ExtraPanels.length); i++) { +// j = i + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status - 1; +// if(hud_button(strcat("hud_option_panel_list_item", ftos(i)), pos + [2, (textsize + 2) * i], [size.x - textsize - 4, textsize + 2], Hud_ExtraPanels[j].Name)) { +// Editor_SelectedPanel_Index = j; +// } +// } } -void Hud_DrawHudOptionsPanel(string panelid, float display, string text, string icon) +void Hud_DrawHudOptionsPanel(string panelid, float display, string text) { if(!fo_hud_editor) return; @@ -819,7 +839,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) if(fo_hud_editor) { hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display); - drawpic(pos, "textures/wad/face1.png", FO_Hud_Icon_Size * DrawPanel.Scale, '1 1 1', 1, 0); + drawpic(pos, "textures/wad/face1", FO_Hud_Icon_Size * DrawPanel.Scale, '1 1 1', 1, 0); return; } @@ -1116,33 +1136,39 @@ void Hud_DrawIdentifyPanel(string id, string identify) } } -void Hud_Draw(float width, float height) -{ +void Hud_DrawPanel(FO_Hud_Panel* panel, float index) { float offset = 0; - for(float i = 0; i < Hud_Panels.length; i++) { - if(sui_is_last_clicked(Hud_Panels[i].id)) { - Editor_SelectedPanel_Index = i; - } - if(!Hud_Panels[HUD_PANEL_HUDOPTIONS].Style || Hud_Panels[i].Display || (fo_hud_editor && i == Editor_SelectedPanel_Index)) { - Hud_Panels[i].drawPanel( Hud_Panels[i].id, Hud_Panels[i].Display, Hud_Panels[i].getValue(), HudIcons[i].icon); - //Draw panel names when editing - if(fo_hud_editor && Hud_Panels[i].id != "hudoptionspanel") { - switch (Hud_Panels[i].Orientation) { - case FO_HUD_INSERT_BEFORE: - offset = 2; - break; - case FO_HUD_INSERT_AFTER: - offset = Hud_Panels[i].FillSize.x - (strlen(Hud_Panels[i].Name) * 6) - 2; - break; - case FO_HUD_INSERT_MIDDLE: - offset = (Hud_Panels[i].FillSize.x / 2) - (strlen(Hud_Panels[i].Name) * 3); //because 3 = 6/2 - break; - } - //drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); - drawstring(getScaledPanelPosition(getHudPanelPointer(i),1) + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); + if(sui_is_last_clicked(panel.id)) { + Editor_SelectedPanel_Index = index; + } + if(!Hud_Panels[HUD_PANEL_HUDOPTIONS].Style || panel.Display || (fo_hud_editor && index == Editor_SelectedPanel_Index)) { + panel.drawPanel( panel.id, panel.Display, panel.getValue()); + //Draw panel names when editing + if(fo_hud_editor && panel.id != "hudoptionspanel") { + switch (panel.Orientation) { + case FO_HUD_INSERT_BEFORE: + offset = 2; + break; + case FO_HUD_INSERT_AFTER: + offset = panel.FillSize.x - (strlen(panel.Name) * 6) - 2; + break; + case FO_HUD_INSERT_MIDDLE: + offset = (panel.FillSize.x / 2) - (strlen(panel.Name) * 3); //because 3 = 6/2 + break; } + //drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); + drawstring(getScaledPanelPosition(panel,1) + [offset,2], panel.Name, '6 6', '0 1 0', 1, 0); } - } + } +} +void Hud_Draw(float width, float height) +{ + for(float i = 0; i < Hud_Panels.length; i++) { + Hud_DrawPanel(&(Hud_Panels[i]), i); + } +// for(float i = 0; i < Hud_ExtraPanels.length; i++) { +// Hud_DrawPanel(&(Hud_ExtraPanels[i]), i); +// } HudSettings.MousePos = [Mouse.x, Mouse.y]; } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index f1174b94..7f837146 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -1,7 +1,6 @@ void Hud_WriteCfg(string path); float GetDrawPanel(string id); void SetDrawPanel(string id); -float GetPanelById(string id); void FO_Hud_Editor() { @@ -259,12 +258,15 @@ string GetPanelString(string line, string name) } float firstrun; -void FO_Hud_Editor_LoadSettings() +void FO_Hud_Editor_LoadSettings(string filename) { + if(!filename || filename == "") return; + vector vsize = (vector)getproperty(VF_SCREENVSIZE); float width = vsize_x; float height = vsize_y; fo_hud_editor = FALSE; + FO_Hud_Panel* panel = &NullPanel; FO_Hud_Editor_LoadDefaultSettings(); @@ -273,7 +275,7 @@ void FO_Hud_Editor_LoadSettings() // fte does weird stuff and writes/reads this to/from a "gamedir/data/file" float filehandle; - filehandle = fopen(FO_HUD_CONFIG_PATH, FILE_READ); + filehandle = fopen(filename, FILE_READ); if (filehandle >= 0) { // get number of lines string ln; @@ -292,14 +294,18 @@ void FO_Hud_Editor_LoadSettings() val = argv(1); val = strtrim(val); - switch(field) - { + //switch(field) + //{ - default: + //default: count = tokenizebyseparator(field, "."); string pnl; pnl = argv(0); - GetDrawPanel(pnl); + panel = getAnyHudPanelByNamePointer(pnl); + if(!panel || &panel == &NullPanel) { + ln = fgets(filehandle); + continue; + } switch (argv(1)) { @@ -307,31 +313,31 @@ void FO_Hud_Editor_LoadSettings() count = tokenizebyseparator(val, ","); x = stof(argv(0)); y = stof(argv(1)); - DrawPanel.Position = [x, y]; + panel.Position = [x, y]; break; case "scale": - DrawPanel.Scale = stof(val); + panel.Scale = stof(val); break; case "textscale": - DrawPanel.TextScale = stof(val); + panel.TextScale = stof(val); break; case "display": - DrawPanel.Display = stof(val); + panel.Display = stof(val); break; case "nodeinsertloc": - DrawPanel.Orientation = stof(val); + panel.Orientation = stof(val); break; case "snap": - DrawPanel.Snap = stof(val); + panel.Snap = stof(val); break; case "style": - DrawPanel.Style = stof(val); + panel.Style = stof(val); break; } - SetDrawPanel(pnl); - break; - } + //SetDrawPanel(pnl); + //break; + //} } ln = fgets(filehandle); } @@ -340,7 +346,7 @@ void FO_Hud_Editor_LoadSettings() else { // write a new file - Hud_WriteCfg(FO_HUD_CONFIG_PATH); + Hud_WriteCfg(filename); } if(Hud_Panels[HUD_PANEL_MENU].Position.x < 0) Hud_Panels[HUD_PANEL_MENU].Position.x = 10; if(Hud_Panels[HUD_PANEL_MENU].Position.y < 0) Hud_Panels[HUD_PANEL_MENU].Position.y = 10; @@ -367,12 +373,13 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float // draws value string using lmps void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon) { - if (!panel || (!panel.Display && !fo_hud_editor)) + if (!panel || &panel == &NullPanel || (!panel.Display && !fo_hud_editor)) return; vector pos; pos = getPanelPosition(panel); //getPosition(fid); //DrawPanel.Position; vector scaledFillSize = panel.FillSize * panel.Scale; + //if(scaledFill if (hud_panel(panel.id, pos, scaledFillSize, 0, panel.Display)) { @@ -383,25 +390,24 @@ void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon) } } - vector size = FO_Hud_Icon_Size * panel.Scale; + //vector size = FO_Hud_Icon_Size * panel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; - drawpic(pos, icon, size, '1 1 1', 1, 0); + //drawpic(pos, icon, size, '1 1 1', 1, 0); + drawpic(pos, icon, scaledFillSize, '1 1 1', 1, 0); - float len; - len = strlen(val); + float len = strlen(val); float textScale = panel.TextScale ? panel.TextScale : panel.Scale; + float offset = 0; if(!panel.Style) { - float offset = (panel.Orientation == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + (size_x * len)) * -1; + offset = (panel.Orientation == FO_HUD_INSERT_BEFORE) ? 2 + scaledFillSize.x : (2 + (scaledFillSize.z * len)) * -1; pos = [pos_x + offset, pos_y, 0]; Hud_DrawStringLMP(pos, val, 24 * textScale); } else { float smallfont = 6 * textScale; - float len = strlen(val); - float offset = 0; if(panel.Orientation == FO_HUD_INSERT_BEFORE) { offset = scaledFillSize.x - len * smallfont - 2; } else if(panel.Orientation == FO_HUD_INSERT_MIDDLE) { diff --git a/csqc/main.qc b/csqc/main.qc index 19154ce8..5e3540f7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -1,6 +1,6 @@ void FO_Hud_Editor(); void Hud_Draw(float width, float height); -void FO_Hud_Editor_LoadSettings(); +void FO_Hud_Editor_LoadSettings(string); void FO_Hud_Editor_LoadDefaultSettings(); void FO_Hud_Editor_List_Panels(); void FO_Hud_Editor_Show_Panel(string panelid); @@ -20,15 +20,16 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_model("progs/weapons/v_rock.mdl"); - for (float i = 0; i < HudIcons.length; i++) { - precache_pic(HudIcons[i].icon); - } +// for (float i = 0; i < HudIcons.length; i++) { +// precache_pic(HudIcons[i].icon); +// } registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); registercommand("fo_hud"); registercommand("fo_hud_save"); + registercommand("fo_hud_load"); registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); @@ -66,7 +67,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { } registercvar("fo_menu_option_+", "="); - FO_Hud_Editor_LoadSettings(); + FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); FO_LoadSettings(); print("There are ", ftos(Hud_Panels.length), " panels\n"); //MEHT @@ -103,8 +104,16 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (is_spectator) is_observer = FALSE; SBAR.Hint = ""; - //stop grentimer on death + thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); + //if(nextoriginupdate < time) { + // speed = vlen([thisorigin.x, thisorigin.y] - [lastorigin.x, lastorigin.y]) * 10; + // lastorigin = thisorigin; + // nextoriginupdate = time + 0.1; + //} + vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; + speed = sqrt(vel.x * vel.x + vel.y * vel.y); + //stop grentimer on death if(getstatf(STAT_HEALTH) <= 0) { //localcmd("stopsound\n"); for(float i = 0; i < FO_Hud_Grentimers.length; i++) { @@ -163,14 +172,23 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "fo_hud_save": - Hud_WriteCfg(FO_HUD_CONFIG_PATH); + if(argv(1) != "") { + Hud_WriteCfg(argv(1)); + } else { + Hud_WriteCfg(FO_HUD_CONFIG_PATH); + } break; case "fo_hud_reload": - FO_Hud_Editor_LoadSettings(); + FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); break; case "fo_hud_reset": FO_Hud_Editor_LoadDefaultSettings(); break; + case "fo_hud_load": + if(argv(1) != "") { + FO_Hud_Editor_LoadSettings(argv(1)); + } + break; case "fo_menu_game": FO_Menu_Game(TRUE); break; @@ -315,10 +333,16 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd(sprintf("bind %s +fo_showscores\n", key2)); } } + if(cvar(FOCMD_FTE_HUD)) { + FO_Show_Scores(TRUE); + } break; case "-showscores": case "-showteamscores": showingscores = FALSE; + if(cvar(FOCMD_FTE_HUD)) { + FO_Show_Scores(FALSE); + } break; case "tracktarget": localcmd("cmd tracktarget\n"); @@ -388,6 +412,7 @@ float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { if(oldhealth > health) { painfinished = time + 0.2; } + return 0; } void CSQC_Shutdown() = { diff --git a/csqc/menu.qc b/csqc/menu.qc index 44b2c386..c9c539bd 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -273,10 +273,9 @@ var fo_menu FO_MENU_BUILD = { FO_Menu_Build(FALSE); return; } - vector org = (vector)getentity(player_localentnum, GE_ORIGIN); if(SBAR.HasSentry) { FO_MENU_BUILD.options[0].state = FO_MENU_STATE_HIDDEN; //Build - if(vlen(org - sentry_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { + if(vlen(thisorigin - sentry_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { FO_MENU_BUILD.options[2].state = FO_MENU_STATE_HIDDEN; //Destroy FO_MENU_BUILD.options[3].state = FO_MENU_STATE_NORMAL; //Dismantle } else { @@ -294,7 +293,7 @@ var fo_menu FO_MENU_BUILD = { } if(SBAR.HasDispenser) { FO_MENU_BUILD.options[1].state = FO_MENU_STATE_HIDDEN; - if(vlen(org - dispenser_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { + if(vlen(thisorigin - dispenser_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { FO_MENU_BUILD.options[4].state = FO_MENU_STATE_HIDDEN; FO_MENU_BUILD.options[5].state = FO_MENU_STATE_NORMAL; } else { @@ -320,8 +319,7 @@ var fo_menu FO_MENU_SENTRY_MAINTAIN = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { - vector org = (vector)getentity(player_localentnum, GE_ORIGIN); - if(vlen(org - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(thisorigin - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } @@ -336,8 +334,7 @@ var fo_menu FO_MENU_SENTRY_ROTATE = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { - vector org = (vector)getentity(player_localentnum, GE_ORIGIN); - if(vlen(org - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(thisorigin - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } @@ -351,8 +348,7 @@ var fo_menu FO_MENU_DISPENSER_MAINTAIN = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { - vector org = (vector)getentity(player_localentnum, GE_ORIGIN); - if(vlen(org - dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(thisorigin - dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } @@ -365,8 +361,7 @@ var fo_menu FO_MENU_DISPENSER_USE = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 4, TRUE, { - vector org = (vector)getentity(player_localentnum, GE_ORIGIN); - if(vlen(org - touched_dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(thisorigin - touched_dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } diff --git a/csqc/status.qc b/csqc/status.qc index 3f902c39..bc8e3447 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1,28 +1,22 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, float textsize, float align); float fo_to_sui_aligntment(float fo_align); vector (FO_Hud_Panel* panel) getPanelPosition; -float getHudPanel(string); +vector (FO_Hud_Panel* panel) getPanelFillSize; void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string); void Hud_DrawLMPThreshold(FO_Hud_Panel*, string, float); FO_Hud_Panel* getHudPanelPointer(float); +FO_Hud_Panel* getAnyHudPanelByNamePointer(string); float GetGrenOneTypeForClass(float playerclass); float GetGrenTwoTypeForClass(float playerclass); -void(string panelid, float display, string text, string icon) drawClipSize = { +void(string panelid, float display, string text) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) { - //GetDrawPanel(panelid); - //Hud_DrawPanelLMP(panelid, text, icon); - float id = getHudPanel(panelid); - - if(id < 0) { - return; - } - Hud_DrawPanelLMP(getHudPanelPointer(id), text, icon); + Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_CLIPSIZE); } }; -void(string panelid, float display, string text, string icon) drawIdentify = { +void(string panelid, float display, string text) drawIdentify = { if (strlen(SBAR.Identify) > 0 || fo_hud_editor) { GetDrawPanel(panelid); @@ -30,7 +24,7 @@ void(string panelid, float display, string text, string icon) drawIdentify = { } }; -void(string panelid, float display, string text, string icon) drawTeamScorePanel = { +void(string panelid, float display, string text) drawTeamScorePanel = { if (display || fo_hud_editor) { GetDrawPanel(panelid); @@ -38,7 +32,7 @@ void(string panelid, float display, string text, string icon) drawTeamScorePanel } }; -void(string panelid, float display, string text, string icon) drawMapMenuPanel = { +void(string panelid, float display, string text) drawMapMenuPanel = { if (display || fo_hud_editor) { GetDrawPanel(panelid); @@ -46,7 +40,7 @@ void(string panelid, float display, string text, string icon) drawMapMenuPanel = } }; -void(string panelid, float display, string text, string icon) drawFlagInfo = { +void(string panelid, float display, string text) drawFlagInfo = { if (display || fo_hud_editor) { GetDrawPanel(panelid); @@ -57,16 +51,16 @@ void(string panelid, float display, string text, string icon) drawFlagInfo = { void(string panelid, float display, string text, string icon) drawIconPanel = { if (display || fo_hud_editor) { - //GetDrawPanel(panelid); - //Hud_DrawPanelLMP(panelid, text, icon); - float id = getHudPanel(panelid); + Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, icon); + } +}; - if(id < 0) { - return; - } - Hud_DrawPanelLMP(getHudPanelPointer(id), text, icon); +void(string panelid, float display, string text) drawFragStreakPanel = { + drawIconPanel(panelid, display, text, ICON_FRAGSTREAK); +}; - } +void(string panelid, float display, string text) drawCapsPanel = { + drawIconPanel(panelid, display, text, ICON_CAPS); }; void(string panelid, float display, string text) drawGren1Panel = { @@ -95,7 +89,7 @@ void(string panelid, float display, string text) drawGren2Panel = { drawIconPanel(panelid, display, text, icon); }; -void(string panelid, float display, string text, string icon) drawSpecial = { +void(string panelid, float display, string text) drawSpecial = { if (SBAR.PlayerClass || fo_hud_editor) { GetDrawPanel(panelid); @@ -103,19 +97,12 @@ void(string panelid, float display, string text, string icon) drawSpecial = { } }; -void(string panelid, float display, string text, string icon) drawGrenTimerPanel = { +void(string panelid, float display, string text) drawGrenTimerPanel = { local float timeleft; local float timercount = 0; if (display) { - //GetDrawPanel(panelid); - float id = getHudPanel(panelid); - - if(id < 0) { - return; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); float Scale = panel.Scale; float TextScale = panel.TextScale; @@ -124,6 +111,7 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel panel2.Scale = panel.Scale; panel2.TextScale = panel.TextScale; panel2.Display = panel.Display; + panel2.FillSize = panel.FillSize; for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype > 0) { timeleft = floor(FO_Hud_Grentimers[i].expires - time) + 1; @@ -145,20 +133,12 @@ void(string panelid, float display, string text, string icon) drawGrenTimerPanel panel2.TextScale = TextScale * 0.8; } Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon); - panel2.Position = panel2.Position + [0, 24 * panel2.Scale]; + panel2.Position = panel2.Position + [0, panel2.FillSize.y * panel2.Scale]; timercount++; } } - } - if(fo_hud_editor && (!display || !timercount)) { - //GetDrawPanel(panelid); - //Hud_DrawPanelLMP(panelid, "0", ICON_GREN1); - float id = getHudPanel(panelid); - - if(id < 0) { - return; - } - Hud_DrawPanelLMP(getHudPanelPointer(id), text, icon); + } else if(fo_hud_editor && (!display || !timercount)) { + Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_GREN_NORMAL); } }; @@ -229,6 +209,14 @@ void(string panelid, float display, string text) drawAmmoPanel = { if(icon != "") drawIconPanel(panelid, display, text, icon); }; +void(string panelid, float display, string text) drawInvIconPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + if(text && text != "") { + drawIconPanel(panelid, display, "", text); + } else if(fo_hud_editor) { + drawIconPanel(panelid, display, "", FaceIcons[0].icon); + } +}; void(string panelid, float display, string text) drawInvShellsPanel = { if(!cvar(FOCMD_FTE_HUD)) return; drawIconPanel(panelid, display, text, AmmoIcons[0].icon); @@ -246,17 +234,43 @@ void(string panelid, float display, string text) drawInvCellsPanel = { drawIconPanel(panelid, display, text, AmmoIcons[3].icon); }; +string(float gunnum) getGunIcon = { + string retval = ""; + if(getstatf(STAT_ITEMS) & gunnum) { + switch(gunnum) { + case IT_SHOTGUN: + retval = "shotgun"; + break; + case IT_SUPER_SHOTGUN: + retval = "sshotgun"; + break; + case IT_NAILGUN: + retval = "nailgun"; + break; + case IT_SUPER_NAILGUN: + retval = "snailgun"; + break; + case IT_GRENADE_LAUNCHER: + retval = "rlaunch"; + break; + case IT_ROCKET_LAUNCHER: + retval = "srlaunch"; + break; + case IT_LIGHTNING: + retval = "lightng"; + break; + } + if(retval != "") { + retval = strcat((getstatf(STAT_ACTIVEWEAPON) == gunnum)?"inv2_":"inv_", retval); + } + } + return retval; +}; void(string panelid, float display, string text, float threshold) drawBigNumberPanel = { if (display || fo_hud_editor) { - float id = getHudPanel(panelid); - - if(id < 0) { - return; - } - - Hud_DrawLMPThreshold(getHudPanelPointer(id), text, threshold); + Hud_DrawLMPThreshold(getAnyHudPanelByNamePointer(panelid), text, threshold); } }; @@ -270,30 +284,68 @@ void(string panelid, float display, string text) drawAmmoTextPanel = { drawBigNumberPanel(panelid, display, text, 11); }; +void(string panelid, float display, string text) drawClockPanel = { + if(!cvar(FOCMD_FTE_HUD)) return; + drawBigNumberPanel(panelid, display, text, 0); +}; -void(string panelid, float display, string text, string icon) doNothing = {}; +string clockString() { + float minutes = time/60; + float seconds = (float)time - (minutes*60); -void(string panelid, float display, string text, string icon) drawSimplePanel = { + //return strcat(ftos(minutes),":", ftos(seconds)); + //return "00:00"; + return ftos(rint(time)); +}; + +string gameClockString() { + float minutes = 0; + float seconds = 0; + float timelimit = stof(serverkey("timelimit")); + + if(round_time_remaining) { + float t = round_time_remaining - time; + if(t < 0) t = t * -1; + minutes = floor(t/60); + seconds = floor(t - (minutes*60)); + } else if(timelimit) { + minutes = floor(time/60); + seconds = 60 - floor(time - (minutes*60)); + minutes = timelimit - ceil(time/60); + if(minutes < 0) minutes = minutes * -1; + if(seconds < 0) seconds = seconds * -1; + } else { + minutes = floor(time/60); + seconds = floor(time - (minutes*60)); + } + + string sm = strcat((minutes<10?"0":""),ftos(minutes)); + string ss = strcat((seconds<10?"0":""),ftos(seconds)); + + string tmp = strcat(sm,":",ss); + //if(round_time_remaining) tmp = ftos(floor(round_time_remaining - time)); + + return tmp; +}; + +void(string panelid, float display, string text) doNothing = {}; + +void(string panelid, float display, string text) drawSimplePanel = { if (fo_hud_editor) { - if (hud_panel(panelid, getPosition(HUD_PANEL_MENU), getFillSize(HUD_PANEL_MENU), 0.3, 1)) { - // click event + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + if(panel && &panel != &NullPanel) { + if (hud_panel(panelid, getPanelPosition(panel), getPanelFillSize(panel), 0.3, 1)) { + // click event + } } } } -float(string panelid) getHudPanel; -FO_Hud_Panel* (float panelid) getHudPanelPointer; - -void(string panelid, float display, string text, string icon) drawTextPanel = { - float id = getHudPanel(panelid); - if(id < 0) { - return; - } +void(string panelid, float display, string text) drawTextPanel = { + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); - FO_Hud_Panel* panel = getHudPanelPointer(id); - - vector position = getPosition(id); - vector size = getFillSize(id); + vector position = getPanelPosition(panel); + vector size = getPanelFillSize(panel); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; local float transparency = 0.3; @@ -345,13 +397,8 @@ void(string panelid, float display, string text, string icon) drawTextPanel = { } } -void(string panelid, float display, string text, string icon) drawMOTDPanel = { - float id = getHudPanel(panelid); - if(id < 0) { - return; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); +void(string panelid, float display, string text) drawMOTDPanel = { + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); //vector position = getPosition(id); //vector size = getFillSize(id); @@ -421,16 +468,11 @@ void(string panelid, float display, string text, string icon) drawMOTDPanel = { //} } -void(string panelid, float display, string text, string icon) drawGameModePanel = { - float id = getHudPanel(panelid); - if(id < 0) { - return; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); +void(string panelid, float display, string text) drawGameModePanel = { + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); - vector position = getPosition(id); - vector size = getFillSize(id); + vector position = getPanelPosition(panel); + vector size = getPanelFillSize(panel); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; local float padding = 4 * panel.Scale; local float transparency = 0.3; @@ -485,16 +527,11 @@ void(string panelid, float display, string text, string icon) drawGameModePanel } } -void(string panelid, float display, string text, string icon) drawReadyPanel = { - float id = getHudPanel(panelid); - if(id < 0) { - return; - } +void(string panelid, float display, string text) drawReadyPanel = { + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); - FO_Hud_Panel* panel = getHudPanelPointer(id); - - vector position = getPosition(id); - vector size = getFillSize(id); + vector position = getPanelPosition(panel); + vector size = getPanelFillSize(panel); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; vector textcolour = MENU_TEXT_4; local float padding = 4 * panel.Scale; @@ -591,14 +628,13 @@ void (vector position, vector size, string val, vector textcolour, float alpha sui_text(position, size, val, textcolour, 1, 0); }; -vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id +vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel , float padding, vector columnColour) drawShowScoresTeamPanel = { - vector textcolour = MENU_TEXT_1; vector smalltext = MENU_TEXT_SMALL * panel.Scale; vector yspacer = [0, 20]; vector position = [0, 0]; - vector size = getFillSize(id); + vector size = getPanelFillSize(panel); position = [0,0]; sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); @@ -822,16 +858,11 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel, float id return position; }; -void(string panelid, float display, string text, string icon) drawShowScoresPanel = { - float id = getHudPanel(panelid); - if(id < 0) { - return; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); +void(string panelid, float display, string text) drawShowScoresPanel = { + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); - vector position = getPosition(id); - vector size = getFillSize(id); + vector position = getPanelPosition(panel); + vector size = getPanelFillSize(panel); vector mediumtext = MENU_TEXT_SMALL * panel.Scale * 2; vector textcolour = MENU_TEXT_1; float padding = 4 * panel.Scale; @@ -916,7 +947,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane { position += yspacer; sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Blue, panel, id, padding, MENU_TEXT_BLUE_FO); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Blue, panel, padding, MENU_TEXT_BLUE_FO); sbCount++; } @@ -924,7 +955,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane { position += yspacer; sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Red, panel, id, padding, MENU_TEXT_RED_FO); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Red, panel, padding, MENU_TEXT_RED_FO); sbCount++; } @@ -932,7 +963,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane { position += yspacer; sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Yellow, panel, id, padding, MENU_TEXT_YELLOW_FO); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Yellow, panel, padding, MENU_TEXT_YELLOW_FO); sbCount++; } @@ -940,7 +971,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane { position += yspacer; sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Green, panel, id, padding, MENU_TEXT_GREEN_FO); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Green, panel, padding, MENU_TEXT_GREEN_FO); sbCount++; } @@ -948,7 +979,7 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane { position += yspacer; sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Specs, panel, id, padding, MENU_TEXT_SPEC_FO); + position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Specs, panel, padding, MENU_TEXT_SPEC_FO); sbCount++; } @@ -976,13 +1007,8 @@ void(string panelid, float display, string text, string icon) drawShowScoresPane void (float show) FO_Show_Scores = { showingscores = show; - float id = getHudPanel("showscorespanel"); - if(id < 0) { - return FALSE; - } - - FO_Hud_Panel* panel = getHudPanelPointer(id); - panel.Display = show; + FO_Hud_Panel* panel = getAnyHudPanelByNamePointer("showscores"); + if(panel && &panel != &NullPanel) panel.Display = show; }; var FO_Hud_Panel Hud_Panels[] = { @@ -991,45 +1017,57 @@ var FO_Hud_Panel Hud_Panels[] = { // string getValue(), // Snap, Status - {"clipsizepanel",FO_HUD_CLIPSIZE_NAME,'10 20','50 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, - {"fragstreakpanel",FO_HUD_FRAGSTREAK_NAME,'10 50','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.FragStreak);}}, - {"capspanel",FO_HUD_CAPS_NAME,'10 80','26 26',1,0,1,0, drawIconPanel, {return ftos(SBAR.Caps);}}, - {"gren1panel",FO_HUD_GREN1_NAME,'10 110','26 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, - {"gren2panel",FO_HUD_GREN2_NAME,'10 140','26 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, - {"playerclasspanel",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identifypanel",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, - {"flaginfopanel",FO_HUD_FLAGINFO_NAME,'10 230','150 260',1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimerpanel",FO_HUD_GRENTIMER_NAME,'100 110','26 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, - {"menupanel","Menu",'10 110','300 200',1,0,1,0, drawSimplePanel, {return "";}}, - {"motdpanel",FO_HUD_MOTD_NAME,'150 100','100 24',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, - {"menuhintpanel",FO_HUD_MENU_HINT_NAME,'100 300','300 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, - {"gamemodepanel",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, - {"readypanel",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, - {"showscorespanel",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, - {"teamscorepanel",FO_HUD_TEAM_SCORE_NAME,'0 0','72 12',2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, - {"mapmenupanel",FO_HUD_MAP_MENU_NAME,'10 30','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, - {"healthpanel",FO_HUD_HEALTH_NAME,'-64 0','72 26',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, - {"facepanel",FO_HUD_FACE_NAME,'-64 0','26 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawFacePanel, {return "";}, 0, 34}, - {"ammopanel",FO_HUD_AMMO_NAME,'10 30','72 26',1,0,1,FO_HUD_INSERT_AFTER, drawAmmoTextPanel, {return ftos(getstatf(STAT_AMMO));}}, - {"ammoiconpanel",FO_HUD_AMMO_ICON_NAME,'10 30','26 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawAmmoPanel, {return "";}}, - {"armourpanel",FO_HUD_ARMOUR_NAME,'10 30','72 26',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}}, - {"armouriconpanel",FO_HUD_ARMOUR_ICON_NAME,'10 30','26 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawArmourPanel, {return "";}}, -// {"invshellspanel",FO_HUD_INV_SHELLS_NAME,'10 140','26 26',1,1.4,1,0, drawInvShellsPanel, {return ftos(getstatf(STAT_SHELLS));}, 1, 33}, -// {"invnailspanel",FO_HUD_INV_NAILS_NAME,'10 140','26 26',1,1.4,1,0, drawInvNailsPanel, {return ftos(getstatf(STAT_NAILS));}, 1, 33}, -// {"invrocketspanel",FO_HUD_INV_ROCKETS_NAME,'10 140','26 26',1,1.4,1,0, drawInvRocketsPanel, {return ftos(getstatf(STAT_ROCKETS));}, 1, 33}, -// {"invcellspanel",FO_HUD_INV_CELLS_NAME,'10 140','26 26',1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, - {"hudoptionspanel",FO_HUD_OPTIONS_NAME,'10 10','150 182',1,0,1,0, doNothing, {return DrawPanel.id;}}, + {"hudoptions",FO_HUD_OPTIONS_NAME,'10 10','150 182',1,0,1,0, doNothing, {return DrawPanel.id;}}, + {"clipsize",FO_HUD_CLIPSIZE_NAME,'10 20','26 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"fragstreak",FO_HUD_FRAGSTREAK_NAME,'10 50','26 26',1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, + {"caps",FO_HUD_CAPS_NAME,'10 80','26 26',1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, + {"gren1",FO_HUD_GREN1_NAME,'10 110','26 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, + {"gren2",FO_HUD_GREN2_NAME,'10 140','26 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, + {"playerclass",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {"identify",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, + {"flaginfo",FO_HUD_FLAGINFO_NAME,'10 230','26 260',1,0,1,0, drawFlagInfo, {return "";}}, + {"grentimer",FO_HUD_GRENTIMER_NAME,'100 110','26 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, + {"menu","Menu",'10 110','300 200',1,0,1,0, drawSimplePanel, {return "";}}, + {"motd",FO_HUD_MOTD_NAME,'150 100','100 24',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, + {"menuhint",FO_HUD_MENU_HINT_NAME,'100 300','300 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, + {"gamemode",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, + {"ready",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, + {"showscores",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, + {"teamscore",FO_HUD_TEAM_SCORE_NAME,'0 0','72 12',2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, + {"mapmenu",FO_HUD_MAP_MENU_NAME,'10 30','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"health",FO_HUD_HEALTH_NAME,'-64 0','72 24',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, + {"face",FO_HUD_FACE_NAME,'-64 0','24 24',1,0,1,FO_HUD_INSERT_MIDDLE, drawFacePanel, {return "";}, 0, 34}, + {"ammo",FO_HUD_AMMO_NAME,'10 30','72 24',1,0,1,FO_HUD_INSERT_AFTER, drawAmmoTextPanel, {return ftos(getstatf(STAT_AMMO));}}, + {"ammoicon",FO_HUD_AMMO_ICON_NAME,'10 30','24 24',1,0,1,FO_HUD_INSERT_MIDDLE, drawAmmoPanel, {return "";}}, + {"armour",FO_HUD_ARMOUR_NAME,'10 30','72 24',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}}, + {"armouricon",FO_HUD_ARMOUR_ICON_NAME,'10 30','24 24',1,0,1,FO_HUD_INSERT_MIDDLE, drawArmourPanel, {return "";}}, + {"invshells",FO_HUD_INV_SHELLS_NAME,'10 140','24 24',1,1.4,1,0, drawInvShellsPanel, {return ftos(getstatf(STAT_SHELLS));}, 1, 33}, + {"invnails",FO_HUD_INV_NAILS_NAME,'10 140','24 24',1,1.4,1,0, drawInvNailsPanel, {return ftos(getstatf(STAT_NAILS));}, 1, 33}, + {"invrockets",FO_HUD_INV_ROCKETS_NAME,'10 140','24 24',1,1.4,1,0, drawInvRocketsPanel, {return ftos(getstatf(STAT_ROCKETS));}, 1, 33}, + {"invcells",FO_HUD_INV_CELLS_NAME,'10 140','24 24',1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, + {"gameclock","Game Clock",'10 140','108 24',1,1.4,1,0, drawClockPanel, {return gameClockString();}}, + {"quad","Quad Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}}, + {"pent","Pentagram Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}}, + {"ring","Ring Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVISIBILITY)?"textures/wad/sb_invis":"";}}, + {"suit","Biosuit Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_SUIT)?"textures/wad/sb_suit":"";}}, + {"key1","Silver Key",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY1)?"textures/wad/sb_key1":"";}}, + {"key2","Gold Key",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY2)?"textures/wad/sb_key2":"";}}, + {"rune1","Earth Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 1)?"textures/wad/sb_sigi1":"";}}, + {"rune2","Black Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 2)?"textures/wad/sb_sigil2":"";}}, + {"rune3","Hell Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 4)?"textures/wad/sb_sigil3":"";}}, + {"rune4","Elder Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 8)?"textures/wad/sb_sigil4":"";}}, + {"gun2","Shotgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SHOTGUN);}}, + {"gun3","Super Shotgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_SHOTGUN);}}, + {"gun4","Nailgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_NAILGUN);}}, + {"gun5","Super Nailgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_NAILGUN);}}, + {"gun6","Grenade Launcher",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}}, + {"gun7","Rocket Launcher",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}}, + {"gun8","Lighning Gun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}}, + {"speed","Speed",'10 140','26 26',1,1.4,1,0, drawTextPanel, {return sprintf("%3.1f UPS", speed);}}, }; -/* -float(string panelid) getHudPanel = { - for(float i = 0; i < Hud_Panels.length; i++) { - if(Hud_Panels[i].id == panelid) { - return i; - } - } - return -1; -}; -*/ + +//var FO_Hud_Panel Hud_ExtraPanels[] = { +//}; FO_Hud_Panel* (float panelid) getHudPanelPointer = { return &(Hud_Panels[panelid]); @@ -1041,7 +1079,12 @@ FO_Hud_Panel* (string panelid) getAnyHudPanelByNamePointer = { return &(Hud_Panels[i]); } } - return NullPanel; +// for(float i = 0; i < Hud_ExtraPanels.length; i++) { +// if(Hud_ExtraPanels[i].id == panelid) { +// return &(Hud_ExtraPanels[i]); +// } +// } + return &NullPanel; }; vector (FO_Hud_Panel* panel, float scale) getScaledPanelPosition = { @@ -1049,10 +1092,10 @@ vector (FO_Hud_Panel* panel, float scale) getScaledPanelPosition = { return panel.Position; //Hud_Panels[panelid].Position; } vector v = panel.Position; - if(panel.Snap & HUD_SNAP_LEFT) v.x; + //if(panel.Snap & HUD_SNAP_LEFT) v.x; if(panel.Snap & HUD_SNAP_CENTER) v.x += (ScreenSize.x / 2) - ((panel.FillSize.x * scale) / 2); if(panel.Snap & HUD_SNAP_RIGHT) v.x += ScreenSize.x - (panel.FillSize.x * scale); - if(panel.Snap & HUD_SNAP_TOP) v.y; + //if(panel.Snap & HUD_SNAP_TOP) v.y; if(panel.Snap & HUD_SNAP_VCENTER) v.y += (ScreenSize.y / 2) - ((panel.FillSize.y * scale) / 2); if(panel.Snap & HUD_SNAP_BOTTOM) v.y += ScreenSize.y - (panel.FillSize.y * scale); return v; @@ -1070,6 +1113,14 @@ vector(float panelid) getFillSize = { return Hud_Panels[panelid].FillSize; } +vector (FO_Hud_Panel* panel) getPanelFillSize = { + return panel.FillSize; +} + +vector (FO_Hud_Panel* panel) getScaledPanelFillSize = { + return panel.FillSize * panel.Scale; +} + float GetGrenOneTypeForClass(float playerclass) { switch(playerclass) { case PC_SCOUT: diff --git a/share/defs.h b/share/defs.h index 72359061..6db2050f 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1459,6 +1459,9 @@ #define STAT_TEAMNO 33 #define STAT_READY 34 #define STAT_CLASS 35 +#define STAT_VELOCITY_X 36 +#define STAT_VELOCITY_Y 37 +#define STAT_VELOCITY_Z 38 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 82970934..7d9d073b 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -280,6 +280,24 @@ void UpdateClientPrematch(entity pl, float countdownstarted) = { WriteByte(MSG_MULTICAST, round_over); WriteByte(MSG_MULTICAST, countdownstarted); WriteFloat(MSG_MULTICAST, rounds); + float timeleft = 0; +// if(!cb_prematch && round_active && !round_over) { + local entity t = find(world, classname, "match"); + if (t != world) { + timeleft = t.cnt2; + + } + t = find(world, classname, "prematch"); + if (t != world) { + timeleft = t.cnt2; + + } + t = find(world, classname, "round"); + if (t != world) { + timeleft = t.cnt * 60 + t.cnt2; + } +// } + WriteFloat(MSG_MULTICAST, timeleft); //WriteByte(MSG_MULTICAST, countdownstarted); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/world.qc b/ssqc/world.qc index dfb5eedb..8b7eb00c 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -291,6 +291,7 @@ void () worldspawn = { clientstat(STAT_TEAMNO, EV_FLOAT, team_no); clientstat(STAT_READY, EV_FLOAT, is_ready); clientstat(STAT_CLASS, EV_FLOAT, playerclass); + clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector entity worldspawnent; worldspawnent = spawn(); From e7a32e6f0d3929f3a607440e97206df5827b1753 Mon Sep 17 00:00:00 2001 From: me Date: Thu, 23 Sep 2021 22:43:16 +1200 Subject: [PATCH 1291/2474] default values for new hud elements --- csqc/status.qc | 94 +++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index fe7e3a4f..3b160897 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1016,53 +1016,53 @@ var FO_Hud_Panel Hud_Panels[] = { // string getValue(), // Snap, Status - {"hudoptions",FO_HUD_OPTIONS_NAME,'10 10','150 182',1,0,1,0, doNothing, {return DrawPanel.id;}}, - {"clipsize",FO_HUD_CLIPSIZE_NAME,'10 20','26 26',1,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, - {"fragstreak",FO_HUD_FRAGSTREAK_NAME,'10 50','26 26',1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, - {"caps",FO_HUD_CAPS_NAME,'10 80','26 26',1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, - {"gren1",FO_HUD_GREN1_NAME,'10 110','26 26',1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, - {"gren2",FO_HUD_GREN2_NAME,'10 140','26 26',1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, - {"playerclass",FO_HUD_SPECIAL_NAME,'10 170','50 26',1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identify",FO_HUD_IDENTIFY_NAME,'10 200','50 26',1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, - {"flaginfo",FO_HUD_FLAGINFO_NAME,'10 230','26 260',1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimer",FO_HUD_GRENTIMER_NAME,'100 110','26 26',1,0,1,0, drawGrenTimerPanel, {return "";}}, - {"menu","Menu",'10 110','300 200',1,0,1,0, drawSimplePanel, {return "";}}, - {"motd",FO_HUD_MOTD_NAME,'150 100','100 24',1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, - {"menuhint",FO_HUD_MENU_HINT_NAME,'100 300','300 24',1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, - {"gamemode",FO_HUD_GAME_MODE_NAME,'100 140','100 10',1,0,1,0, drawGameModePanel, {return "";}}, - {"ready",FO_HUD_READY_NAME,'10 100','100 10',2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, - {"showscores",FO_HUD_SHOWSCORES_NAME,'10 100','600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, - {"teamscore",FO_HUD_TEAM_SCORE_NAME,'0 0','72 12',2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, - {"mapmenu",FO_HUD_MAP_MENU_NAME,'10 30','800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, - {"health",FO_HUD_HEALTH_NAME,'-64 0','72 24',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, - {"face",FO_HUD_FACE_NAME,'-64 0','24 24',1,0,1,FO_HUD_INSERT_MIDDLE, drawFacePanel, {return "";}, 0, 34}, - {"ammo",FO_HUD_AMMO_NAME,'10 30','72 24',1,0,1,FO_HUD_INSERT_AFTER, drawAmmoTextPanel, {return ftos(getstatf(STAT_AMMO));}}, - {"ammoicon",FO_HUD_AMMO_ICON_NAME,'10 30','24 24',1,0,1,FO_HUD_INSERT_MIDDLE, drawAmmoPanel, {return "";}}, - {"armour",FO_HUD_ARMOUR_NAME,'10 30','72 24',1,0,1,FO_HUD_INSERT_AFTER, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}}, - {"armouricon",FO_HUD_ARMOUR_ICON_NAME,'10 30','24 24',1,0,1,FO_HUD_INSERT_MIDDLE, drawArmourPanel, {return "";}}, - {"invshells",FO_HUD_INV_SHELLS_NAME,'10 140','24 24',1,1.4,1,0, drawInvShellsPanel, {return ftos(getstatf(STAT_SHELLS));}, 1, 33}, - {"invnails",FO_HUD_INV_NAILS_NAME,'10 140','24 24',1,1.4,1,0, drawInvNailsPanel, {return ftos(getstatf(STAT_NAILS));}, 1, 33}, - {"invrockets",FO_HUD_INV_ROCKETS_NAME,'10 140','24 24',1,1.4,1,0, drawInvRocketsPanel, {return ftos(getstatf(STAT_ROCKETS));}, 1, 33}, - {"invcells",FO_HUD_INV_CELLS_NAME,'10 140','24 24',1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, - {"gameclock","Game Clock",'10 140','108 24',1,1.4,1,0, drawClockPanel, {return gameClockString();}}, - {"quad","Quad Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}}, - {"pent","Pentagram Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}}, - {"ring","Ring Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVISIBILITY)?"textures/wad/sb_invis":"";}}, - {"suit","Biosuit Icon",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_SUIT)?"textures/wad/sb_suit":"";}}, - {"key1","Silver Key",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY1)?"textures/wad/sb_key1":"";}}, - {"key2","Gold Key",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY2)?"textures/wad/sb_key2":"";}}, - {"rune1","Earth Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 1)?"textures/wad/sb_sigi1":"";}}, - {"rune2","Black Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 2)?"textures/wad/sb_sigil2":"";}}, - {"rune3","Hell Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 4)?"textures/wad/sb_sigil3":"";}}, - {"rune4","Elder Rune",'10 140','26 26',1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 8)?"textures/wad/sb_sigil4":"";}}, - {"gun2","Shotgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SHOTGUN);}}, - {"gun3","Super Shotgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_SHOTGUN);}}, - {"gun4","Nailgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_NAILGUN);}}, - {"gun5","Super Nailgun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_NAILGUN);}}, - {"gun6","Grenade Launcher",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}}, - {"gun7","Rocket Launcher",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}}, - {"gun8","Lighning Gun",'10 140','36 24',1,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}}, - {"speed","Speed",'10 140','26 26',1,1.4,1,0, drawTextPanel, {return sprintf("%3.1f UPS", speed);}}, + {"hudoptions",FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return DrawPanel.id;}}, + {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"fragstreak",FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, + {"caps",FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, + {"gren1",FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, + {"gren2",FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, + {"playerclass",FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {"identify",FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, + {"flaginfo",FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0, drawFlagInfo, {return "";}}, + {"grentimer",FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0, drawGrenTimerPanel, {return "";}}, + {"menu","Menu", '10 110', '300 200',1,0,1,0, drawSimplePanel, {return "";}}, + {"motd",FO_HUD_MOTD_NAME, '150 100', '100 24', 1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, + {"menuhint",FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, + {"gamemode",FO_HUD_GAME_MODE_NAME, '100 140', '100 10', 1,0,1,0, drawGameModePanel, {return "";}}, + {"ready",FO_HUD_READY_NAME, '10 100', '100 10', 2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, + {"showscores",FO_HUD_SHOWSCORES_NAME, '10 100', '600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, + {"teamscore",FO_HUD_TEAM_SCORE_NAME, '0 0', '72 12', 2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, + {"mapmenu",FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {"health",FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, + {"face",FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0, drawFacePanel, {return "";}, 0, 34}, + {"ammo",FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(getstatf(STAT_AMMO));}, 0, 34}, + {"ammoicon",FO_HUD_AMMO_ICON_NAME , '42 -2', '24 24', 1,0,1,0, drawAmmoPanel, {return "";}, 0, 34}, + {"armour",FO_HUD_ARMOUR_NAME, '-134 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}, 0, 34}, + {"armouricon",FO_HUD_ARMOUR_ICON_NAME,'-182 -2', '24 24', 1,0,1,0, drawArmourPanel, {return "";}, 0, 34}, + {"invshells",FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(getstatf(STAT_SHELLS));}, 1, 33}, + {"invnails",FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(getstatf(STAT_NAILS));}, 1, 33}, + {"invrockets",FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(getstatf(STAT_ROCKETS));}, 1, 33}, + {"invcells",FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, + {"gameclock","Game Clock", '0 0' , '108 24', 1,0.8,1,0, drawClockPanel, {return gameClockString();}, 0, 10}, + {"quad","Quad Icon", '-200 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}, 0, 36}, + {"pent","Pentagram Icon", '-170 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}, 0, 36}, + {"ring","Ring Icon", '-140 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVISIBILITY)?"textures/wad/sb_invis":"";}, 0, 36}, + {"suit","Biosuit Icon", '-110 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_SUIT)?"textures/wad/sb_suit":"";}, 0, 36}, + {"key1","Silver Key", '140 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY1)?"textures/wad/sb_key1":"";}, 0, 34}, + {"key2","Gold Key", '160 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY2)?"textures/wad/sb_key2":"";}, 0, 34}, + {"rune1","Earth Rune", '-200 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 1)?"textures/wad/sb_sigi1":"";}, 0, 34}, + {"rune2","Black Rune", '-170 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 2)?"textures/wad/sb_sigil2":"";}, 0, 34}, + {"rune3","Hell Rune", '-140 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 4)?"textures/wad/sb_sigil3":"";}, 0, 34}, + {"rune4","Elder Rune", '-110 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 8)?"textures/wad/sb_sigil4":"";}, 0, 34}, + {"gun2","Shotgun", '-4 -170', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SHOTGUN);}, 0, 36}, + {"gun3","Super Shotgun", '-4 -150', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_SHOTGUN);}, 0, 36}, + {"gun4","Nailgun", '-4 -130', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_NAILGUN);}, 0, 36}, + {"gun5","Super Nailgun", '-4 -110', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_NAILGUN);}, 0, 36}, + {"gun6","Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, + {"gun7","Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, + {"gun8","Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, + {"speed","Speed", '4 15', '26 26', 1,1.4,1,0, drawTextPanel, {return sprintf("%3.1f UPS", speed);}, 0, 4}, }; //var FO_Hud_Panel Hud_ExtraPanels[] = { From 1571ff10e07172118537e8109618fdab0501a6b7 Mon Sep 17 00:00:00 2001 From: me Date: Fri, 24 Sep 2021 10:12:14 +1200 Subject: [PATCH 1292/2474] disable speed by default and default new fte hud to 0 --- csqc/main.qc | 2 +- csqc/status.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 582e9451..3a819034 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -39,7 +39,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); registercvar(FOCMD_OLDSCOREBOARD, "0"); - registercvar(FOCMD_FTE_HUD, "1"); + registercvar(FOCMD_FTE_HUD, "0"); registercommand("fo_menu_game"); registercommand("fo_main_menu"); diff --git a/csqc/status.qc b/csqc/status.qc index 3b160897..52411483 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1062,7 +1062,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gun6","Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, {"gun7","Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {"gun8","Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {"speed","Speed", '4 15', '26 26', 1,1.4,1,0, drawTextPanel, {return sprintf("%3.1f UPS", speed);}, 0, 4}, + {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return cvar(FOCMD_FTE_HUD)?sprintf("%3.1f UPS", speed):"";}, 0, 4}, }; //var FO_Hud_Panel Hud_ExtraPanels[] = { From c25b62a353fa60851c64448e2fda69c87a2f556d Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 27 Sep 2021 23:59:36 +1000 Subject: [PATCH 1293/2474] swap out some numbers for constants --- ssqc/doors.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssqc/doors.qc b/ssqc/doors.qc index 4703b71b..dda88cd7 100644 --- a/ssqc/doors.qc +++ b/ssqc/doors.qc @@ -28,7 +28,7 @@ void () door_blocked = { void () door_hit_top = { FO_Sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); - self.state = 0; + self.state = STATE_TOP; if (self.spawnflags & 32) return; @@ -39,7 +39,7 @@ void () door_hit_top = { void () door_hit_bottom = { self.goal_state = 2; FO_Sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); - self.state = 1; + self.state = STATE_BOTTOM; }; void () door_go_down_silent = { @@ -427,7 +427,7 @@ void () func_door = { self.pos2 = self.pos1; self.pos1 = self.origin; } - self.state = 1; + self.state = STATE_BOTTOM; if (self.health) { self.takedamage = 1; self.th_die = door_killed; From 0b3db6d4e61545a7a8366e59036cbb42e51d7d07 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 27 Sep 2021 23:59:53 +1000 Subject: [PATCH 1294/2474] some new constants --- share/defs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/defs.h b/share/defs.h index 31006475..3182544a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1251,6 +1251,11 @@ #define TFGI_NOGLOW 1 // stop the automatic glow applied in fortressone to goals with a .mdl set based on team #define TFGI_CB_IGNORE 2 // Allow this goal to work even in clan battle/quadmode prematch +// spawnflags - fo_misc_info +#define TFGI_NOGLOW 1 // we reuse some tfgi functions, so keep this spawnflag +#define TFGI_CB_IGNORE 2 // Allow this goal to work even in clan battle/quadmode prematch +#define FO_MISC_INFO_NO_Z_TEST 4 // Draw this "through" walls - fake it in ez, csqc do it locally + /*======================================================================*/ /* Flamethrower */ /*======================================================================*/ @@ -1460,6 +1465,7 @@ // func_wall #define WALL_SOLID_NOT 1 #define WALL_HIDE_ON_USE 2 +#define WALL_SOLID_NOT_ON_USE 4 // teams #define TEAM_BLUE 1 From 7ed410f32ca393d6679f04b5453982041b442817 Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 28 Sep 2021 00:00:18 +1000 Subject: [PATCH 1295/2474] fix up goal_results mistake -> goal_result is actual field --- docs/tfentref.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tfentref.txt b/docs/tfentref.txt index c36e10e3..a0c1c39a 100644 --- a/docs/tfentref.txt +++ b/docs/tfentref.txt @@ -463,7 +463,7 @@ t_length Everyone within this radius is affected. To specify whe in "goal_effects" -goal_results Determines what results are applied to APA. Bitfields: +goal_result Determines what results are applied to APA. Bitfields: 1 : Goal is removed after activation. 2 : Goals activated by this one apply their results to the AP. @@ -743,7 +743,7 @@ maxammo_shells All members of this team are affected. maxammo_nails All members not of this team are affected. -goal_results Determines what results are applied to APA. Bitfields: +goal_result Determines what results are applied to APA. Bitfields: 1 : Goal is removed after activation. 2 : Goals activated by this one apply their results to the AP. @@ -1070,7 +1070,7 @@ ex_skill_max This entity is removed when the map starts if the game's variable is <= to this value. To specify a skill of 0, use -1 instead. -goal_results Determines what results are applied to APA. Bitfields: +goal_result Determines what results are applied to APA. Bitfields: 1 : Goal is removed after activation. 2 : Goals activated by this one apply their results to APA. From 1452ea79e6ce2e956b7c59bb5047001ee8dd3286 Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 28 Sep 2021 00:06:13 +1000 Subject: [PATCH 1296/2474] support for fo_rock map: new logic, math, info entities, allow multiple class names for findgoal --- ssqc/fo_logic.qc | 282 +++++++++++++++++++++++++++++++++++++++++++ ssqc/fo_math.qc | 66 ++++++++++ ssqc/fo_misc_info.qc | 29 +++++ ssqc/misc.qc | 31 +++-- ssqc/progs.src | 5 +- ssqc/qw.qc | 11 ++ ssqc/tfortmap.qc | 125 ++++++++++--------- ssqc/world.qc | 3 +- 8 files changed, 479 insertions(+), 73 deletions(-) create mode 100644 ssqc/fo_logic.qc create mode 100644 ssqc/fo_math.qc create mode 100644 ssqc/fo_misc_info.qc diff --git a/ssqc/fo_logic.qc b/ssqc/fo_logic.qc new file mode 100644 index 00000000..12baa4a4 --- /dev/null +++ b/ssqc/fo_logic.qc @@ -0,0 +1,282 @@ +class fo_logic : entity +{ + float if_goal_no; + float if_group_no; + string if_fieldname; + float compare_goal_no; + float compare_group_no; + string compare_fieldname; + + float activate_goal_no_if_equal; + float activate_goal_no_if_not_equal; + float activate_goal_no_if_less_than; + float activate_goal_no_if_greater_than; + float activate_group_no_if_equal; + float activate_group_no_if_not_equal; + float activate_group_no_if_less_than; + float activate_group_no_if_greater_than; + float set_value_on_goal_no_if_equal; + float set_value_on_goal_no_if_not_equal; + float set_value_on_goal_no_if_less_than; + float set_value_on_goal_no_if_greater_than; + string set_from_fieldname; + float set_from_goal_no; + string set_to_fieldname; + float set_to_goal_no; + + float fieldtype; + float compare_fieldtype; + float set_fieldnum; + float fieldnum_used; + .__variant fieldref; + .__variant compare_fieldref; + .__variant test; + + void () fo_logic = + { + float argc = tokenize(__fullspawndata)-1; + for (float i = 1; i < argc;) + { + string field = argv(i++); + string val = argv(i++); + float i2 = findentityfield(strcat(this.classname, "::__m", field)); + + if (i2) + { + putentityfieldstring(i2, this, val); + } + } + + if (!if_goal_no && !if_group_no) + { + bprint(PRINT_HIGH, "fo_logic entity with netname: '", this.netname, "' does not have if_goal_no or if_group_no set!\n"); + remove(this); + return; + } + + if (!compare_goal_no && !compare_group_no) + { + bprint(PRINT_HIGH, "fo_logic entity with netname: '", this.netname, "' does not have compare_goal_no or compare_group_no set!\n"); + remove(this); + return; + } + + if (this.if_fieldname == __NULL__) + this.if_fieldname = ""; + + if (this.if_fieldname == "") + { + bprint(PRINT_HIGH, "fo_logic entity with netname: '", this.netname, "' does not have fieldname set!\n"); + remove(this); + return; + } + + if (this.compare_fieldname == __NULL__) + this.compare_fieldname = ""; + + if (this.compare_fieldname == "") + { + bprint(PRINT_HIGH, "fo_logic entity with netname: '", this.netname, "' does not have compare_fieldname set!\n"); + remove(this); + return; + } + + if (!activate_goal_no_if_equal && !activate_goal_no_if_not_equal + && !activate_goal_no_if_less_than && !activate_goal_no_if_greater_than + && !activate_group_no_if_equal && !activate_group_no_if_not_equal + && !activate_group_no_if_less_than && !activate_group_no_if_greater_than + && (!set_to_goal_no && !set_from_goal_no)) + { + bprint(PRINT_HIGH, "fo_logic entity with netname: '", this.netname, "' does not have any values in activate_goal_no_if_equal, activate_goal_no_if_not_equal, activate_goal_no_if_less_than, activate_goal_no_if_greater_than, activate_group_no_if_equal, activate_group_no_if_not_equal, activate_group_no_if_less_than, activate_group_no_if_greater_than,, set_to_goal_no, set_from_goal_no!\n"); + remove(this); + return; + } + + float fieldnum = findentityfield(this.if_fieldname); + fieldtype = entityfieldtype(fieldnum); + + float compare_fieldnum = findentityfield(this.compare_fieldname); + compare_fieldtype = entityfieldtype(compare_fieldnum); + + if (fieldtype != compare_fieldtype) + { + bprint(PRINT_HIGH, "fo_logic entity with netname: '", this.netname, "' cannot compare if_fieldname and compare_fieldname due to mismatched types!\n"); + remove(this); + return; + } + fieldref = entityfieldref(fieldnum); + compare_fieldref = entityfieldref(compare_fieldnum); + + if (this.set_to_fieldname == __NULL__) + this.set_to_fieldname = ""; + + if (this.set_to_fieldname != "") + { + set_fieldnum = findentityfield(this.set_to_fieldname); + fieldnum_used = TRUE; + } + }; + + nonvirtual void () SetValue = + { + if (!fieldnum_used) + return; + if (!set_from_goal_no) + return; + + float fieldnum = findentityfield(this.set_from_fieldname); + float set_fieldtype = entityfieldtype(fieldnum); + entity from = findfloat(world, ::goal_no, set_from_goal_no); + .__variant set_fieldref = entityfieldref(fieldnum); + string set_value = __NULL__; + switch (set_fieldtype) + { + case EV_STRING: + set_value = from.((.string)set_fieldref); + break; + case EV_FLOAT: + set_value = ftos(from.((.float)set_fieldref)); + break; + } + + entity to = findfloat(world, ::goal_no, set_to_goal_no); + float set_to_fieldnum = findentityfield(this.set_to_fieldname); + if (!putentityfieldstring(set_to_fieldnum, to, set_value)) + { + bprint(PRINT_HIGH, "fo_logic entity with netname: '", this.netname, "' set_value failed!\n"); + } + }; + + nonvirtual void (float gno) ActivateGoal = + { + if (!gno) + return; + + entity act = findfloat(world, ::goal_no, gno); + if (act) + { + AttemptToActivate(act, other, this); + } + + }; + + nonvirtual void (float gno) ActivateGroup = + { + if (!gno) + return; + + entity act = findfloat(world, ::group_no, gno); + while (act) + { + AttemptToActivate(act, other, this); + act = findfloat(act, ::group_no, gno); + } + }; + + nonvirtual void (entity goal, entity compare_goal) CompareGoals = + { + entity act = world; + switch (fieldtype) + { + case EV_STRING: + string sval = goal.((.string)fieldref); + string compare_sval = compare_goal.((.string)compare_fieldref); + if (sval == compare_sval) + { + this.SetValue(); + this.ActivateGoal(activate_goal_no_if_equal); + this.ActivateGroup(activate_group_no_if_equal); + } + else + { + this.ActivateGoal(activate_goal_no_if_not_equal); + this.ActivateGroup(activate_group_no_if_not_equal); + } + break; + case EV_FLOAT: + float fval = goal.((.float)fieldref); + float compare_fval = compare_goal.((.float)compare_fieldref); + + if (fval == compare_fval) + { + this.SetValue(); + this.ActivateGoal(activate_goal_no_if_equal); + this.ActivateGroup(activate_group_no_if_equal); + } + else + { + this.ActivateGoal(activate_goal_no_if_not_equal); + this.ActivateGroup(activate_group_no_if_not_equal); + } + + if (fval > compare_fval) + { + this.ActivateGoal(activate_goal_no_if_greater_than); + this.ActivateGroup(activate_group_no_if_greater_than); + } + else if (fval < compare_fval) + { + this.ActivateGoal(activate_goal_no_if_less_than); + this.ActivateGroup(activate_group_no_if_less_than); + } + break; + default: + // TODO - lazy, don't want to do this right now + bprint(PRINT_HIGH, "fo_logic entity can only compare fields that are string or float\n"); + break; + } + }; + + nonvirtual void (entity goal) ExecuteLogic = + { + entity compare_goal = world; + if (this.compare_goal_no) + { + compare_goal = findfloat(world, ::goal_no, compare_goal_no); + if (compare_goal) + { + this.CompareGoals(goal, compare_goal); + } + } + + if (this.compare_group_no) + { + compare_goal = world; + compare_goal = findfloat(world, ::group_no, compare_group_no); + + while (compare_goal) + { + this.CompareGoals(goal, compare_goal); + compare_goal = findfloat(compare_goal, ::group_no, compare_group_no); + } + } + }; + + virtual void () use = + { + float gnum = this.if_goal_no; + entity goal = world; + + if (gnum) + { + goal = findfloat(world, ::goal_no, gnum); + if (goal) + { + this.ExecuteLogic(goal); + } + } + + gnum = this.if_group_no; + if (gnum) + { + goal = world; + goal = findfloat(world, ::group_no, gnum); + + while (goal) + { + this.ExecuteLogic(goal); + goal = findfloat(goal, ::group_no, gnum); + } + } + }; +}; \ No newline at end of file diff --git a/ssqc/fo_math.qc b/ssqc/fo_math.qc new file mode 100644 index 00000000..736ae331 --- /dev/null +++ b/ssqc/fo_math.qc @@ -0,0 +1,66 @@ +class fo_math : entity +{ + float value; + float min_value; + float max_value; + + float add; + float subtract; + float multiply; + float divide; + + float activate_goal_no_on_max_value; + float activate_goal_no_on_min_value; + + float perform_reset_on_max_value; + float perform_reset_on_min_value; + float reset_value_on_max_value; + float reset_value_on_min_value; + + // state + float hit_max_value; + float hit_min_value; + + nonvirtual void (float hit_value, float activate_goal_no) ValidateValue = + { + entity act = world; + + // only execute once after it is past the max/min value + if (!hit_value) + { + if (activate_goal_no) + { + act = findfloat(world, ::goal_no, activate_goal_no); + if (act) + AttemptToActivate(act, other, this); + } + } + }; + + nonvirtual void () Process = + { + entity act = world; + value = value + add; + if (value > max_value) + { + ValidateValue(hit_max_value, activate_goal_no_on_max_value); + hit_max_value = TRUE; + + if (perform_reset_on_max_value) + { + value = reset_value_on_max_value; + } + } + + act = world; + value = value - subtract; + if (value < min_value) + { + ValidateValue(hit_min_value, activate_goal_no_on_min_value); + hit_min_value = TRUE; + + if (perform_reset_on_min_value) + value = reset_value_on_min_value; + } + }; +}; \ No newline at end of file diff --git a/ssqc/fo_misc_info.qc b/ssqc/fo_misc_info.qc new file mode 100644 index 00000000..b82d3789 --- /dev/null +++ b/ssqc/fo_misc_info.qc @@ -0,0 +1,29 @@ +class fo_misc_info : entity +{ + void () fo_misc_info = + { + if (this.mdl) + { + precache_model(this.mdl); + precache_model2(this.mdl); + this.model = this.mdl; + + if (this.spawnflags & FO_MISC_INFO_NO_Z_TEST) + { + this.nextthink = time + .01; + } + else + { + FO_SetModel(this, this.mdl); + } + + if (this.goal_state == TFGS_REMOVED) + RemoveGoal(this); + } + }; + + virtual void () think = + { + this.nextthink = time + .01; + }; +}; \ No newline at end of file diff --git a/ssqc/misc.qc b/ssqc/misc.qc index 10f1b5b7..48b27019 100644 --- a/ssqc/misc.qc +++ b/ssqc/misc.qc @@ -457,15 +457,23 @@ void () viewthing = { }; void () func_wall_use = { + if (self.spawnflags & WALL_SOLID_NOT_ON_USE) + { + self.solid = self.solid ? SOLID_NOT : SOLID_BSP; + } + if (self.spawnflags & WALL_HIDE_ON_USE) { - if (self.cnt == self.dimension_seen) + if (self.dimension_seen != DMN_INVISIBLE) { + self.old_dimension_seen = self.dimension_seen; self.dimension_seen = DMN_INVISIBLE; } else { - self.dimension_seen = self.cnt; + float val = self.dimension_seen; + self.dimension_seen = self.old_dimension_seen; + self.old_dimension_seen = val; } } else @@ -491,27 +499,34 @@ void () func_wall = { { self.solid = SOLID_BSP; } + float team_bit = 0; switch (self.team_no) { case TEAM_BLUE: - self.dimension_seen = DMN_TEAMBLUE; + team_bit = DMN_TEAMBLUE; break; case TEAM_RED: - self.dimension_seen = DMN_TEAMRED; + team_bit = DMN_TEAMRED; break; case TEAM_YELL: - self.dimension_seen = DMN_TEAMYELL; + team_bit = DMN_TEAMYELL; break; case TEAM_GREN: - self.dimension_seen = DMN_TEAMGREN; + team_bit = DMN_TEAMGREN; break; default: break; } - self.cnt = self.dimension_seen; + self.dimension_seen = self.dimension_seen | team_bit; + + if (self.dimension_seen & DMN_INVISIBLE) + self.old_dimension_seen = DMN_NOFLASH | DMN_FLASH | team_bit; + else + self.old_dimension_seen = self.dimension_seen | DMN_NOFLASH | DMN_FLASH; + setmodel(self, self.model); - self.mdl = self.model; + //self.mdl = self.model; }; void () func_illusionary = { diff --git a/ssqc/progs.src b/ssqc/progs.src index a8cf2a8c..a9fbbcc0 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -60,4 +60,7 @@ actions.qc spect.qc q3.qc mvdsv.qc -rotate.qc \ No newline at end of file +rotate.qc +fo_logic.qc +fo_math.qc +fo_misc_info.qc \ No newline at end of file diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d9319f68..6a452f69 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -721,9 +721,20 @@ float canlog; // flash stuff float FO_FlashDimension; +.float old_dimension_seen; // allow for default goal state .float default_group_no; +// classes to search for in goal remove, restore etc +string goal_class_names[7] = { + "info_tfgoal", + "trigger_teleport", + "door", + "func_wall", + "fo_misc_info", + "fo_logic", + "fo_math", +}; .string broadcast_high; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 6e2d7761..2344d888 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -612,17 +612,22 @@ entity(float ino) Finditem = entity(float gno) Findgoal = { - local entity tg; - local string st; - - tg = find(world, classname, "info_tfgoal"); - while (tg) { - if (tg.goal_no == gno) - return (tg); - tg = find(tg, classname, "info_tfgoal"); + for (float i = 0; i < goal_class_names.length; i++) + { + string goal_type = goal_class_names[i]; + entity tg = find(world, classname, goal_type); + while (tg) + { + if (tg.goal_no == gno) + { + return tg; + } + tg = find(tg, classname, goal_type); + } } + dprint("Could not find a goal with a goal_no of "); - st = ftos(gno); + string st = ftos(gno); dprint(st); dprint(".\n"); return world; @@ -674,19 +679,27 @@ void DefaultGoalState (entity Goal) } void (entity Goal) RestoreGoal = { + if (Goal.goal_state == TFGS_REMOVED) { + Goal.dimension_seen = DMN_NOFLASH; + if (Goal.search_time == 0) { - if ((Goal.goal_activation & 8192) && - (Goal.classname == "item_tfgoal")) { + if ( + ((Goal.goal_activation & 8192) && (Goal.classname == "item_tfgoal")) + || Goal.classname == "door" + ) + { Goal.solid = SOLID_BBOX; - } else { + } + else + { Goal.solid = SOLID_TRIGGER; } } else { Goal.nextthink = time + Goal.search_time; } Goal.goal_state = TFGS_INACTIVE; - if (Goal.model) { + if (Goal.mdl) { FO_SetModel(Goal, Goal.mdl); setsize(Goal, Goal.goal_min, Goal.goal_max); entity oldself; @@ -699,6 +712,9 @@ void (entity Goal) RestoreGoal = { }; void (entity Goal) RemoveGoal = { + Goal.old_dimension_seen = Goal.dimension_seen; + Goal.dimension_seen = DMN_INVISIBLE; + Goal.solid = 0; Goal.goal_state = TFGS_REMOVED; if (Goal.mdl != string_null) @@ -1519,7 +1535,7 @@ void (entity Goal, entity AP) DoGoalWork = { } }; -void (entity Goal, entity AP) DoGroupWork = { +void (entity Goal, entity AP, string cname) DoGroupWorkByClass = { local string st; local entity tg; local float allset; @@ -1532,14 +1548,14 @@ void (entity Goal, entity AP) DoGroupWork = { dprint(" has a .all_active specified, but no .last_impulse\n"); } else { allset = 1; - tg = find(world, classname, "info_tfgoal"); + tg = find(world, classname, cname); while (tg) { if (tg.group_no == Goal.all_active) { if (tg.goal_state != 1) { allset = 0; } } - tg = find(tg, classname, "info_tfgoal"); + tg = find(tg, classname, cname); } if (allset) { tg = Findgoal(Goal.last_impulse); @@ -1548,81 +1564,52 @@ void (entity Goal, entity AP) DoGroupWork = { } } } - } + } + if (Goal.activate_group_no != 0) { - tg = find(world, classname, "info_tfgoal"); + tg = find(world, classname, cname); while (tg) { if (tg.group_no == Goal.activate_group_no) { DoResults(tg, AP, 0); } - tg = find(tg, classname, "info_tfgoal"); + tg = find(tg, classname, cname); } } if (Goal.inactivate_group_no != 0) { - tg = find(world, classname, "info_tfgoal"); - while (tg) { - if (tg.group_no == Goal.inactivate_group_no) { - InactivateGoal(tg); - } - tg = find(tg, classname, "info_tfgoal"); - } - - tg = find(world, classname, "trigger_teleport"); + tg = find(world, classname, cname); while (tg) { if (tg.group_no == Goal.inactivate_group_no) { InactivateGoal(tg); } - tg = find(tg, classname, "trigger_teleport"); + tg = find(tg, classname, cname); } } if (Goal.remove_group_no != 0) { - tg = find(world, classname, "info_tfgoal"); - while (tg) { - if (tg.group_no == Goal.remove_group_no) { - RemoveGoal(tg); - } - tg = find(tg, classname, "info_tfgoal"); - } - - tg = find(world, classname, "trigger_teleport"); + tg = find(world, classname, cname); while (tg) { if (tg.group_no == Goal.remove_group_no) { RemoveGoal(tg); } - tg = find(tg, classname, "trigger_teleport"); + tg = find(tg, classname, cname); } } if (Goal.restore_group_no != 0) { - tg = find(world, classname, "info_tfgoal"); + tg = find(world, classname, cname); while (tg) { if (tg.group_no == Goal.restore_group_no) { RestoreGoal(tg); } - tg = find(tg, classname, "info_tfgoal"); - } - tg = find(world, classname, "trigger_teleport"); - while (tg) { - if (tg.group_no == Goal.restore_group_no) { - RestoreGoal(tg); - } - tg = find(tg, classname, "trigger_teleport"); + tg = find(tg, classname, cname); } } if (Goal.default_group_no != 0) { - tg = find(world, classname, "info_tfgoal"); + tg = find(world, classname, cname); while (tg) { if (tg.group_no == Goal.default_group_no) { DefaultGoalState(tg); } - tg = find(tg, classname, "info_tfgoal"); - } - tg = find(world, classname, "trigger_teleport"); - while (tg) { - if (tg.group_no == Goal.default_group_no) { - DefaultGoalState(tg); - } - tg = find(tg, classname, "trigger_teleport"); + tg = find(tg, classname, cname); } } @@ -1727,6 +1714,16 @@ void (entity Item, entity AP) DoItemGroupWork = { } }; + + +void (entity Goal, entity AP) DoGroupWork = +{ + for (float i = 0; i < goal_class_names.length; i++) + { + DoGroupWorkByClass(Goal, AP, goal_class_names[i]); + } +}; + void (entity Goal, entity AP) DoTriggerWork = { local entity t; @@ -1761,9 +1758,11 @@ void (entity Goal, entity AP) DoTriggerWork = { }; void () DelayedResult = { + entity oself = self; if (self.enemy.goal_state == TFGS_DELAYED) DoResults(self.enemy, self.owner, self.weapon); - dremove(self); + + dremove(oself); }; void (entity Goal, entity AP, float addb) DoResults = { @@ -1774,11 +1773,11 @@ void (entity Goal, entity AP, float addb) DoResults = { if (cb_prematch && !(Goal.spawnflags & TFGI_CB_IGNORE)) { return; } - if (Goal.goal_state == 1) { + if (Goal.goal_state == TFGS_ACTIVE) { return; } - if ((Goal.delay_time > 0) && (Goal.goal_state != 4)) { - Goal.goal_state = 4; + if ((Goal.delay_time > 0) && (Goal.goal_state != TFGS_DELAYED)) { + Goal.goal_state = TFGS_DELAYED; te = spawn(); te.think = DelayedResult; te.nextthink = time + Goal.delay_time; @@ -1790,7 +1789,7 @@ void (entity Goal, entity AP, float addb) DoResults = { } UpdateAbbreviations(Goal); - Goal.goal_state = 2; + Goal.goal_state = TFGS_INACTIVE; if ((Goal.classname == "info_tfgoal") && (Goal.mdl != string_null)) { setmodel(Goal, string_null); } @@ -2052,7 +2051,7 @@ void (entity Goal, entity AP, float addb) DoResults = { te = find(te, classname, "player"); } if (Goal.classname != "item_tfgoal") { - Goal.goal_state = 1; + Goal.goal_state = TFGS_ACTIVE; } if (Goal.goal_result & 4) { TeamFortress_TeamShowScores(1); diff --git a/ssqc/world.qc b/ssqc/world.qc index 7dece17c..fc4c4bd1 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -425,7 +425,8 @@ void (entity ent) CopyToBodyQue = { void(void() fnc)CheckSpawn = { if(fnc) { - self.dimension_seen = DMN_NOFLASH | DMN_FLASH; + if (self.dimension_seen != DMN_INVISIBLE) + self.dimension_seen = self.dimension_seen | DMN_NOFLASH | DMN_FLASH; //bprint(PRINT_HIGH, strcat("spawning: ", self.classname, "\n")); fnc(); } From e00c615e8f44ca68015559be918ef1d7825781cc Mon Sep 17 00:00:00 2001 From: lordee Date: Tue, 28 Sep 2021 22:36:12 +1000 Subject: [PATCH 1297/2474] fix plats for fo_roundchange --- ssqc/plats.qc | 1 + ssqc/quadmode.qc | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/ssqc/plats.qc b/ssqc/plats.qc index d42cb627..2b3ab748 100644 --- a/ssqc/plats.qc +++ b/ssqc/plats.qc @@ -16,6 +16,7 @@ void () plat_spawn_inside_trigger = { trigger.movetype = MOVETYPE_NONE; trigger.solid = SOLID_TRIGGER; trigger.enemy = self; + self.enemy = trigger; trigger.team_no = self.team_no; trigger.playerclass = self.playerclass; trigger.items_allowed = self.items_allowed; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index a020c51a..50a470ff 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -149,6 +149,11 @@ void () FO_RoundChange = { self = c; info_player_teamspawn(); break; + case "plat": + if (c.enemy) + c.enemy.team_no = c.team_no; + break; + } } c = findfloat(c, group_no, e.switch_team_group_no); From 3168564c7c1263788af69d26533d04caa7b0caf0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 29 Sep 2021 01:03:35 +1000 Subject: [PATCH 1298/2474] Use stats for remaining grens --- csqc/csextradefs.qc | 2 -- csqc/events.qc | 6 ------ csqc/main.qc | 4 ++-- csqc/status.qc | 6 +++--- share/defs.h | 2 ++ ssqc/status.qc | 5 ----- ssqc/world.qc | 2 ++ 7 files changed, 9 insertions(+), 18 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e493b37d..157f4805 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -278,8 +278,6 @@ typedef struct { float Caps; string Identify; float PlayerClass; - float Gren1; - float Gren2; string MOTD; string Hint; //1 = Clanmode, 2 = Quadmode, 4 = Duelmode, 8 = Prematch diff --git a/csqc/events.qc b/csqc/events.qc index f1ed11df..f873d01d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -314,12 +314,6 @@ void ParseSBAR() SBAR.Caps = readfloat(); SBAR.PlayerClass = readfloat(); - if (SBAR.PlayerClass) - { - SBAR.Gren1 = readfloat(); - SBAR.Gren2 = readfloat(); - } - switch (SBAR.PlayerClass) { case PC_SCOUT: diff --git a/csqc/main.qc b/csqc/main.qc index 3a819034..941b2bef 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -408,9 +408,9 @@ void ShowGrenadeTimer(float gren_number) { float RemainingGrenades(float gren_number) { switch (gren_number) { case 1: - return SBAR.Gren1; + return getstatf(STAT_NO_GREN1); case 2: - return SBAR.Gren2; + return getstatf(STAT_NO_GREN2); } } diff --git a/csqc/status.qc b/csqc/status.qc index 52411483..68f60ef7 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1014,14 +1014,14 @@ var FO_Hud_Panel Hud_Panels[] = { // id, Name, Position, FillSize, Scale, TextScale, Display, Orientation, // void drawPanel(string panelid, float display, string text, string icon), // string getValue(), -// Snap, Status +// Snap, Status {"hudoptions",FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return DrawPanel.id;}}, {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, {"fragstreak",FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {"caps",FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, - {"gren1",FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(SBAR.Gren1);}}, - {"gren2",FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0, drawGren2Panel, {return ftos(SBAR.Gren2);}}, + {"gren1",FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, + {"gren2",FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0, drawGren2Panel, {return ftos(getstatf(STAT_NO_GREN2));}}, {"playerclass",FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {"identify",FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, {"flaginfo",FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0, drawFlagInfo, {return "";}}, diff --git a/share/defs.h b/share/defs.h index a1ca7bd7..1d448aec 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1467,6 +1467,8 @@ #define STAT_VELOCITY_X 36 #define STAT_VELOCITY_Y 37 #define STAT_VELOCITY_Z 38 +#define STAT_NO_GREN1 39 +#define STAT_NO_GREN2 40 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/status.qc b/ssqc/status.qc index 01387ec3..19e5691f 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -851,11 +851,6 @@ void UpdateClientStatusBar(entity pl) WriteFloat(MSG_MULTICAST, pl.caps); WriteFloat(MSG_MULTICAST, pl.playerclass); // just in case we get a packet from "last life" after changing playerclass - if (pl.playerclass) - { - WriteFloat(MSG_MULTICAST, pl.no_grenades_1); - WriteFloat(MSG_MULTICAST, pl.no_grenades_2); - } // class info switch (pl.playerclass) diff --git a/ssqc/world.qc b/ssqc/world.qc index db35aacf..65bc4afd 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -292,6 +292,8 @@ void () worldspawn = { clientstat(STAT_READY, EV_FLOAT, is_ready); clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector + clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); + clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); entity worldspawnent; worldspawnent = spawn(); From 22d6f8cab51d08fe626ee1d7666c57a8555e45fd Mon Sep 17 00:00:00 2001 From: me Date: Wed, 29 Sep 2021 21:31:38 +1300 Subject: [PATCH 1299/2474] fix menu and grentimer in hud editor --- csqc/csextradefs.qc | 1 + csqc/hud_helpers.qc | 12 ++++++++++-- csqc/main.qc | 4 ++-- csqc/menu.qc | 7 ++++--- csqc/status.qc | 7 ++++--- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e493b37d..336444db 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -426,6 +426,7 @@ typedef struct { FO_Hud_Panel NullPanel; FO_Hud_Panel DrawPanel; FO_Hud_Panel NewPanel; +FO_Hud_Panel* MenuPanel; float Editor_SelectedPanel_Index; typedef struct { diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 7f837146..8e27e3b1 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -303,8 +303,16 @@ void FO_Hud_Editor_LoadSettings(string filename) pnl = argv(0); panel = getAnyHudPanelByNamePointer(pnl); if(!panel || &panel == &NullPanel) { - ln = fgets(filehandle); - continue; + if(strlen(pnl) < 6) { + ln = fgets(filehandle); + continue; + } + pnl = substring(pnl, 0, strlen(pnl) - 5); + panel = getAnyHudPanelByNamePointer(pnl); + if(!panel || &panel == &NullPanel) { + ln = fgets(filehandle); + continue; + } } switch (argv(1)) diff --git a/csqc/main.qc b/csqc/main.qc index 3a819034..95f7396f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -75,8 +75,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); FO_LoadSettings(); - print("There are ", ftos(Hud_Panels.length), " panels\n"); //MEHT - + MenuPanel = getAnyHudPanelByNamePointer("menu"); + CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; is_admin = FALSE; diff --git a/csqc/menu.qc b/csqc/menu.qc index c9c539bd..be904379 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -648,7 +648,7 @@ var fo_menu FO_MENU_VOTE = { vector fo_menu_draw(fo_menu * menu) = { vector position; if(menu.flags & FO_MENU_FLAG_CENTER) { - position = Hud_Panels[HUD_PANEL_MENU].Position; + position = getPanelPosition(MenuPanel); } else { position = menu.position; } @@ -667,7 +667,7 @@ vector fo_menu_draw(fo_menu * menu) = { menu.update(); } - local float scale = Hud_Panels[HUD_PANEL_MENU].Scale, textscale = Hud_Panels[HUD_PANEL_MENU].TextScale; + local float scale = MenuPanel.Scale, textscale = MenuPanel.TextScale; if(!textscale) { textscale = scale; } @@ -688,6 +688,7 @@ vector fo_menu_draw(fo_menu * menu) = { if (sui_is_held(id)) { position = position + [Mouse.x, Mouse.y] - HudSettings.MousePos; + MenuPanel.Position = MenuPanel.Position + [Mouse.x, Mouse.y] - HudSettings.MousePos; } sui_border_box(position, menusize, 1, bordercolour, FO_MENU_TRANSPARENCY, 0); @@ -837,7 +838,7 @@ void Menu_Cancel() = { void Menu_Draw(float width, float height, float menushown) = { if(fo_hud_menu_active) { CurrentMenu.position = fo_menu_draw(CurrentMenu); - Hud_Panels[HUD_PANEL_MENU].Position = CurrentMenu.position; + //MenuPanel.Position = CurrentMenu.position; } else { Menu_Cancel(); } diff --git a/csqc/status.qc b/csqc/status.qc index 52411483..44f64add 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -136,7 +136,8 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { timercount++; } } - } else if(fo_hud_editor && (!display || !timercount)) { + } + if(fo_hud_editor && (!display || !timercount)) { Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_GREN_NORMAL); } }; @@ -1014,9 +1015,9 @@ var FO_Hud_Panel Hud_Panels[] = { // id, Name, Position, FillSize, Scale, TextScale, Display, Orientation, // void drawPanel(string panelid, float display, string text, string icon), // string getValue(), -// Snap, Status +// Style, Snap, Status - {"hudoptions",FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return DrawPanel.id;}}, + {"hudoptions",FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return DrawPanel.id;}, 1}, {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, {"fragstreak",FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {"caps",FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, From 3056fac6c3baa883ff9be84aee45ac7d9b09ac54 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 29 Sep 2021 23:51:31 +1000 Subject: [PATCH 1300/2474] Update scout.qc --- ssqc/scout.qc | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 203283a2..7b4ec286 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -2,6 +2,8 @@ // Functions for the SCOUT class and associated weaponry //======================================================== +void () ScanBolt_Touch; +void () ScanBolt_Think; void () CaltropTouch; void () CaltropScatterThink; void () ScatterCaltrops; @@ -19,6 +21,43 @@ void (entity inflictor, entity attacker, float bounce, entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; +void () ScanBolt_Think = { + self.solid = SOLID_TRIGGER; + self.movetype = MOVETYPE_FLYMISSILE; + self.velocity = self.oldorigin; + self.touch = ScanBolt_Touch; + FO_SetModel(self, "progs/spike_scan.mdl"); + self.nextthink = time + 1; + self.think = SUB_Remove; +}; + +// Scanbolt touch function. +void () ScanBolt_Touch = { + local vector org; + + if (other == self.owner) { + return; + } + if ((other == self.enemy) && (self.enemy != world)) { + return; + } + if (pointcontents(self.origin) == CONTENT_SKY) { + dremove(self); + return; + } + org = self.origin - 8 * normalize(self.velocity); + + msg_entity = self.owner; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_SPIKE); + WriteCoord(MSG_ONE, self.origin_x); + WriteCoord(MSG_ONE, self.origin_y); + WriteCoord(MSG_ONE, self.origin_z + 8); + + dremove(self); +}; + + void () CF_Scout_Dash = { if (self.playerclass != PC_SCOUT) return; @@ -634,6 +673,46 @@ void () TeamFortress_Scan = { WriteCoord(MSG_ONE, lightningvec_x); WriteCoord(MSG_ONE, lightningvec_y); WriteCoord(MSG_ONE, lightningvec_z + 8); + + // code injected by hz - scanner projectile + scanvec = normalize(list.origin - self.owner.origin); + newmis = spawn(); + newmis.owner = self.owner; + newmis.enemy = self.owner; + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.solid = SOLID_TRIGGER; + + FO_SetModel(newmis, "progs/spike_scan.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); + setorigin(newmis, self.owner.origin + v_forward * 8); + + switch (self.owner.team_no) + { + case TEAM_BLUE: + newmis.dimension_seen = DMN_TEAMBLUE; + break; + case TEAM_RED: + newmis.dimension_seen = DMN_TEAMRED; + break; + case TEAM_YELL: + newmis.dimension_seen = DMN_TEAMYELL; + break; + case TEAM_GREN: + newmis.dimension_seen = DMN_TEAMGREN; + break; + default: + newmis.dimension_seen = DMN_NOFLASH; + break; + } + + newmis.velocity = scanvec * 1000; + newmis.angles = vectoangles(newmis.velocity); + newmis.oldorigin = newmis.velocity; + newmis.nextthink = time + 5; + newmis.think = SUB_Remove; + newmis.touch = ScanBolt_Touch; + newmis.classname = "scanspike"; + //END hz replaced code if (self.owner.tf_items_flags & 4) { stuffcmd(self.owner, "play misc/basekey.wav\n"); From bb7476faf7aca20cb2c7f5c3f48de3b3c9137e99 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 09:18:57 +1000 Subject: [PATCH 1301/2474] Update scout.qc --- ssqc/scout.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 7b4ec286..fbb59f3d 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -585,6 +585,7 @@ void () TeamFortress_Scan = { local float scen; local float scfr; local float num; + local vector scanvec; local vector lightningvec; local float enemy_detected; local float any_detected; From 1f2cd33afe30fda350786cbca831f916c4a347df Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 12:29:07 +1000 Subject: [PATCH 1302/2474] Update defs.h --- share/defs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/share/defs.h b/share/defs.h index e200ebce..b3e8fb9c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1032,6 +1032,7 @@ #define PC_HVYWEAP_PROJSPEED 3000 #define PC_HVYWEAP_ASSCAN_CLIPSIZE 100 #define MODEL_PROJ_DIAM2 "progs/proj_diam2.mdl" +#define MODEL_SPIKE_SCAN "progs/spike_scan.mdl" // Class Details for PYRO From 05e6a27dbd0613505ca054a22ce9b5c24b02c92b Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 12:30:56 +1000 Subject: [PATCH 1303/2474] Adding def.h 'MODEL_SPIKE_SCAN' variable This fixes ezquake error > server disconnection. --- ssqc/scout.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index fbb59f3d..97f4b96f 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -26,7 +26,7 @@ void () ScanBolt_Think = { self.movetype = MOVETYPE_FLYMISSILE; self.velocity = self.oldorigin; self.touch = ScanBolt_Touch; - FO_SetModel(self, "progs/spike_scan.mdl"); + FO_SetModel(self, MODEL_SPIKE_SCAN); self.nextthink = time + 1; self.think = SUB_Remove; }; @@ -683,7 +683,7 @@ void () TeamFortress_Scan = { newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_TRIGGER; - FO_SetModel(newmis, "progs/spike_scan.mdl"); + FO_SetModel(newmis, MODEL_SPIKE_SCAN); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.owner.origin + v_forward * 8); From 401af2bf6dfb77cb675d92a29c7e431690dc9c39 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 12:46:27 +1000 Subject: [PATCH 1304/2474] Update world.qc --- ssqc/world.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/world.qc b/ssqc/world.qc index dfb5eedb..c0d9fc89 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -264,6 +264,7 @@ void () worldspawn = { precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); precache_model2(MODEL_PROJ_DIAM2); + precache_model2(MODEL_SPIKE_SCAN); precache_sound("grentimer.wav"); precache_sound("buttons/switch04.wav"); precache_sound("boss1/out1.wav"); From e98b73665d494bac55ed54f686c0683bf4eb412e Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 20:23:17 +1000 Subject: [PATCH 1305/2474] Update qw.qc --- ssqc/qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d9319f68..b91b9108 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -569,6 +569,7 @@ float buildstatus; float server_default; float server_faithful; float server_huetf; +float scoutscanspike; float old_spanner; float old_dispenser; From a792ff5b88007e5660a10cc763617b30c37e5517 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 20:30:24 +1000 Subject: [PATCH 1306/2474] Update client.qc --- ssqc/client.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 238d89d4..5bfcbae4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -566,6 +566,9 @@ void () DecodeLevelParms = { // configure max armor of heavy weapons guy [300] max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); + + // Scout Scanner spike on / off + scoutscanspike = CF_GetSetting("scp", "scoutscanspike", "on"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); @@ -804,6 +807,7 @@ void () DecodeLevelParms = { solid_detpack = FALSE; walls_block_emp = FALSE; solid_nailgren = FALSE; + scoutscanspike = TRUE; } st = infokey(world, "faithful"); @@ -875,6 +879,7 @@ void () DecodeLevelParms = { solid_detpack = TRUE; walls_block_emp = FALSE; solid_nailgren = TRUE; + scoutscanspike = FALSE; } st = infokey(world, "huetf"); @@ -921,6 +926,7 @@ void () DecodeLevelParms = { Role_None.gren2_limits[8] = 3; max_active_gren2_soldier = 1; round_delay_time = 10; + scoutscanspike = FALSE; } } From 59d2a8ad702fe0e984fa075f6c5f689331a2977d Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 20:33:21 +1000 Subject: [PATCH 1307/2474] Update scout.qc --- ssqc/scout.qc | 76 +++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 97f4b96f..0e6daee3 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -675,45 +675,45 @@ void () TeamFortress_Scan = { WriteCoord(MSG_ONE, lightningvec_y); WriteCoord(MSG_ONE, lightningvec_z + 8); - // code injected by hz - scanner projectile - scanvec = normalize(list.origin - self.owner.origin); - newmis = spawn(); - newmis.owner = self.owner; - newmis.enemy = self.owner; - newmis.movetype = MOVETYPE_FLYMISSILE; - newmis.solid = SOLID_TRIGGER; - - FO_SetModel(newmis, MODEL_SPIKE_SCAN); - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, self.owner.origin + v_forward * 8); - - switch (self.owner.team_no) - { - case TEAM_BLUE: - newmis.dimension_seen = DMN_TEAMBLUE; - break; - case TEAM_RED: - newmis.dimension_seen = DMN_TEAMRED; - break; - case TEAM_YELL: - newmis.dimension_seen = DMN_TEAMYELL; - break; - case TEAM_GREN: - newmis.dimension_seen = DMN_TEAMGREN; - break; - default: - newmis.dimension_seen = DMN_NOFLASH; - break; - } + if (scoutspikescan) { + scanvec = normalize(list.origin - self.owner.origin); + newmis = spawn(); + newmis.owner = self.owner; + newmis.enemy = self.owner; + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.solid = SOLID_TRIGGER; + + FO_SetModel(newmis, MODEL_SPIKE_SCAN); + setsize(newmis, '0 0 0', '0 0 0'); + setorigin(newmis, self.owner.origin + v_forward * 8); + + switch (self.owner.team_no) + { + case TEAM_BLUE: + newmis.dimension_seen = DMN_TEAMBLUE; + break; + case TEAM_RED: + newmis.dimension_seen = DMN_TEAMRED; + break; + case TEAM_YELL: + newmis.dimension_seen = DMN_TEAMYELL; + break; + case TEAM_GREN: + newmis.dimension_seen = DMN_TEAMGREN; + break; + default: + newmis.dimension_seen = DMN_NOFLASH; + break; + } - newmis.velocity = scanvec * 1000; - newmis.angles = vectoangles(newmis.velocity); - newmis.oldorigin = newmis.velocity; - newmis.nextthink = time + 5; - newmis.think = SUB_Remove; - newmis.touch = ScanBolt_Touch; - newmis.classname = "scanspike"; - //END hz replaced code + newmis.velocity = scanvec * 1000; + newmis.angles = vectoangles(newmis.velocity); + newmis.oldorigin = newmis.velocity; + newmis.nextthink = time + 5; + newmis.think = SUB_Remove; + newmis.touch = ScanBolt_Touch; + newmis.classname = "scanspike"; + } if (self.owner.tf_items_flags & 4) { stuffcmd(self.owner, "play misc/basekey.wav\n"); From 1e8f81ba40ba6cfa4d2d311bfeef75477940277f Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 20:35:42 +1000 Subject: [PATCH 1308/2474] Update scout.qc --- ssqc/scout.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 0e6daee3..d08a1bd8 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -675,7 +675,7 @@ void () TeamFortress_Scan = { WriteCoord(MSG_ONE, lightningvec_y); WriteCoord(MSG_ONE, lightningvec_z + 8); - if (scoutspikescan) { + if (scoutscanspike) { scanvec = normalize(list.origin - self.owner.origin); newmis = spawn(); newmis.owner = self.owner; From 0a3c3b1754db625c6145424c164513c010629f45 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 20:46:05 +1000 Subject: [PATCH 1309/2474] Update client.qc --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5bfcbae4..681b88f9 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -568,7 +568,7 @@ void () DecodeLevelParms = { max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); // Scout Scanner spike on / off - scoutscanspike = CF_GetSetting("scp", "scoutscanspike", "on"); + scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From fff127d4e0f7860173d1dfe58750871a17271d8d Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 30 Sep 2021 21:05:45 +1000 Subject: [PATCH 1310/2474] Update client.qc --- ssqc/client.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 681b88f9..bfb2c3b0 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -926,7 +926,6 @@ void () DecodeLevelParms = { Role_None.gren2_limits[8] = 3; max_active_gren2_soldier = 1; round_delay_time = 10; - scoutscanspike = FALSE; } } From 6333537b36911de7b449c4f6a9d36611be3b4655 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 13:07:20 +1000 Subject: [PATCH 1311/2474] Update scout.qc --- ssqc/scout.qc | 50 +++++++++----------------------------------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index d08a1bd8..49fbad67 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -21,43 +21,6 @@ void (entity inflictor, entity attacker, float bounce, entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; -void () ScanBolt_Think = { - self.solid = SOLID_TRIGGER; - self.movetype = MOVETYPE_FLYMISSILE; - self.velocity = self.oldorigin; - self.touch = ScanBolt_Touch; - FO_SetModel(self, MODEL_SPIKE_SCAN); - self.nextthink = time + 1; - self.think = SUB_Remove; -}; - -// Scanbolt touch function. -void () ScanBolt_Touch = { - local vector org; - - if (other == self.owner) { - return; - } - if ((other == self.enemy) && (self.enemy != world)) { - return; - } - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove(self); - return; - } - org = self.origin - 8 * normalize(self.velocity); - - msg_entity = self.owner; - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_SPIKE); - WriteCoord(MSG_ONE, self.origin_x); - WriteCoord(MSG_ONE, self.origin_y); - WriteCoord(MSG_ONE, self.origin_z + 8); - - dremove(self); -}; - - void () CF_Scout_Dash = { if (self.playerclass != PC_SCOUT) return; @@ -680,8 +643,8 @@ void () TeamFortress_Scan = { newmis = spawn(); newmis.owner = self.owner; newmis.enemy = self.owner; - newmis.movetype = MOVETYPE_FLYMISSILE; - newmis.solid = SOLID_TRIGGER; + newmis.movetype = MOVETYPE_NOCLIP; + newmis.solid = SOLID_NOT; FO_SetModel(newmis, MODEL_SPIKE_SCAN); setsize(newmis, '0 0 0', '0 0 0'); @@ -709,9 +672,14 @@ void () TeamFortress_Scan = { newmis.velocity = scanvec * 1000; newmis.angles = vectoangles(newmis.velocity); newmis.oldorigin = newmis.velocity; - newmis.nextthink = time + 5; + + //Remove the scan spike when it reaches list.origin newmis.think = SUB_Remove; - newmis.touch = ScanBolt_Touch; + num = vlen(list.origin - self.owner.origin); + num = num / 1000; + newmis.nextthink = time + num; + + newmis.touch = SUB_Null; newmis.classname = "scanspike"; } From d12271b113a5f143ba808d17056cbad510fe85e3 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 13:15:10 +1000 Subject: [PATCH 1312/2474] Update scout.qc --- ssqc/scout.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 49fbad67..26edef28 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -2,8 +2,6 @@ // Functions for the SCOUT class and associated weaponry //======================================================== -void () ScanBolt_Touch; -void () ScanBolt_Think; void () CaltropTouch; void () CaltropScatterThink; void () ScatterCaltrops; From 2f523101499d983bee8d1d0f89e4fe2e52099fc0 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 14:41:34 +1000 Subject: [PATCH 1313/2474] Added AssCanThink for use with asscanrange --- ssqc/hwguy.qc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index b6186821..1d1f2fa0 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -1,3 +1,11 @@ +void AssCanBulletThink () +{ + self.movetype = MOVETYPE_TOSS; + self.think = SUB_Remove; + self.nextthink = time + 3; +} + + void AssCanBulletTouch() { if (self.voided) @@ -70,8 +78,15 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) newmis.solid = SOLID_BBOX; newmis.touch = AssCanBulletTouch; - newmis.think = SUB_Remove; - newmis.nextthink = time + 5; // Stop projectile going forever + + if (asscanrange > 0) { + num = (1 / proj_speed) * asscanrange; + newmis.think = AssCanBulletThink; + newmis.nextthink = time + num; // Projectile range / gravity + } else { + newmis.think = SUB_Remove; + newmis.nextthink = time + 5; // Stop projectile going forever + } newmis.mdl = MODEL_PROJ_DIAM2; FO_SetModel(newmis, newmis.mdl); // Diamond model From 28fef4e03c9543512bfe595cda9291364627e159 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 14:43:20 +1000 Subject: [PATCH 1314/2474] Includes scoutscanspike and asscanrange --- ssqc/qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index b91b9108..480557e7 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -570,6 +570,7 @@ float server_default; float server_faithful; float server_huetf; float scoutscanspike; +float asscanrange; float old_spanner; float old_dispenser; From aff888589824295f6072c52a4788d20d4aab4bc7 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 14:45:14 +1000 Subject: [PATCH 1315/2474] Includes scoutscanspike and asscanrange --- ssqc/client.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index bfb2c3b0..d166a1b6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -569,6 +569,9 @@ void () DecodeLevelParms = { // Scout Scanner spike on / off scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); + + // HwGuy Assault Cannon Range default - 500 + asscanrange = CF_GetSetting("asr", "asscanrange", "500"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From 748800211f43c9556424456d2250a95392c6fb5b Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 14:48:03 +1000 Subject: [PATCH 1316/2474] Update hwguy.qc --- ssqc/hwguy.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 1d1f2fa0..54c604c9 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -69,6 +69,8 @@ vector(float base, float rndmix, float plusminus) vecrand = void LaunchAssCan(vector org, vector dir, float proj_speed) { + local float num; + newmis = spawn(); newmis.owner = self; newmis.classname = "proj_bullet"; From 4b6fd79308c63e372701a03f00c36a2ec1204838 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 15:19:08 +1000 Subject: [PATCH 1317/2474] ASR changed to ASR for assaultcannonrange --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index d166a1b6..fbb4cb87 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -571,7 +571,7 @@ void () DecodeLevelParms = { scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); // HwGuy Assault Cannon Range default - 500 - asscanrange = CF_GetSetting("asr", "asscanrange", "500"); + asscanrange = CF_GetSetting("acr", "asscanrange", "500"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From 3840a2e1a3e698c01366ff9082cab4206e887a8f Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 15:30:40 +1000 Subject: [PATCH 1318/2474] Changing the asscanrange to default to disabled asscanrange defaults to zero / disabled. --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index fbb4cb87..5f3e36a3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -570,8 +570,8 @@ void () DecodeLevelParms = { // Scout Scanner spike on / off scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); - // HwGuy Assault Cannon Range default - 500 - asscanrange = CF_GetSetting("acr", "asscanrange", "500"); + // HwGuy Assault Cannon Range default as 0 to disable + asscanrange = CF_GetSetting("acr", "asscanrange", "0"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From cf02d8aed8d04c09ebd4342972f6799d5071b9ab Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 21:37:13 +1000 Subject: [PATCH 1319/2474] Adding die time on hwguy range/gravity --- ssqc/hwguy.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 54c604c9..8bacfef9 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -2,7 +2,12 @@ void AssCanBulletThink () { self.movetype = MOVETYPE_TOSS; self.think = SUB_Remove; - self.nextthink = time + 3; + + if (asscanrangedie > 0) { + self.nextthink = time + asscanrangedie; + } else { + self.nextthink = time + 3; + } } From bcc024982abd7add194a722167ae10a0b2f8dc96 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 21:38:32 +1000 Subject: [PATCH 1320/2474] Added assaultcannonrangedie --- ssqc/client.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5f3e36a3..8bd63cd3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -572,6 +572,8 @@ void () DecodeLevelParms = { // HwGuy Assault Cannon Range default as 0 to disable asscanrange = CF_GetSetting("acr", "asscanrange", "0"); + // and adding a die time toggle + asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From c02cdf05d2b34b51ee400842084cdd04c2824d4e Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 21:39:08 +1000 Subject: [PATCH 1321/2474] Added asscanrangedie --- ssqc/qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 480557e7..6e1094de 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -571,6 +571,7 @@ float server_faithful; float server_huetf; float scoutscanspike; float asscanrange; +float asscanrangedie; float old_spanner; float old_dispenser; From 50b356245065189b05f9a7706ad597529bce5b32 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 22:00:58 +1000 Subject: [PATCH 1322/2474] removed asscanrangedie --- ssqc/hwguy.qc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 8bacfef9..60bd5d30 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -1,13 +1,8 @@ void AssCanBulletThink () { self.movetype = MOVETYPE_TOSS; - self.think = SUB_Remove; - - if (asscanrangedie > 0) { - self.nextthink = time + asscanrangedie; - } else { - self.nextthink = time + 3; - } + self.think = SUB_Remove; + self.nextthink = time + 3; } From e078b7c585d22e029b8b9342481c7e5272a389c5 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 22:01:48 +1000 Subject: [PATCH 1323/2474] Update qw.qc --- ssqc/qw.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 6e1094de..480557e7 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -571,7 +571,6 @@ float server_faithful; float server_huetf; float scoutscanspike; float asscanrange; -float asscanrangedie; float old_spanner; float old_dispenser; From 94364bfa5dec17fb8f13f7b850ba75d5ea529b56 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 22:02:35 +1000 Subject: [PATCH 1324/2474] Update client.qc --- ssqc/client.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 8bd63cd3..5f3e36a3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -572,8 +572,6 @@ void () DecodeLevelParms = { // HwGuy Assault Cannon Range default as 0 to disable asscanrange = CF_GetSetting("acr", "asscanrange", "0"); - // and adding a die time toggle - asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From 9cede73ec2d547ff7a64725aefb469235389b132 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 22:22:20 +1000 Subject: [PATCH 1325/2474] Restoring asscanrangedie --- ssqc/hwguy.qc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 60bd5d30..f5c0cbc7 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -1,11 +1,17 @@ void AssCanBulletThink () { self.movetype = MOVETYPE_TOSS; - self.think = SUB_Remove; - self.nextthink = time + 3; + self.think = SUB_Remove; + + if (asscanrangedie > 0) { + self.nextthink = time + asscanrangedie; + } else { + self.nextthink = time + 3; + } } + void AssCanBulletTouch() { if (self.voided) From 8786ec69286f869ff9941a1557f47d31e322361e Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 22:23:32 +1000 Subject: [PATCH 1326/2474] Restored asscanrangedie --- ssqc/qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 480557e7..6e1094de 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -571,6 +571,7 @@ float server_faithful; float server_huetf; float scoutscanspike; float asscanrange; +float asscanrangedie; float old_spanner; float old_dispenser; From ea4574f5b31705133c4c3e66817164f4231d1b3c Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sat, 2 Oct 2021 22:24:42 +1000 Subject: [PATCH 1327/2474] Restored asscanrangedie --- ssqc/client.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5f3e36a3..a7003f8f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -570,8 +570,9 @@ void () DecodeLevelParms = { // Scout Scanner spike on / off scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); - // HwGuy Assault Cannon Range default as 0 to disable + // HwGuy Assault Cannon Range default as 0 to disable, and die time once range hit. asscanrange = CF_GetSetting("acr", "asscanrange", "0"); + asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From 7fdb0f6b1e753a9f5810a3340f0d321b74ec8c2f Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:01:15 +1100 Subject: [PATCH 1328/2474] Fixes/Updates to UseAirblast 1. Changed the center of the findradius based on aim vector. The findradius is now applied ahead where player aims and not on the player origin. Half the radius range should be applied (originally 400 but adjust to 200). 2. Removed if (ent == self) in switch - as per the while loop ent != self. 3. Pushval starts at 1000 for percentage calculation (% tends to range from 0.2 to 0.8). Added a min pushval of 500 and max of 800 for more consistency. 4. Added some height (setorigin) for an entity on floor and applying of 500. --- ssqc/pyro.qc | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 9422ab71..35445a65 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -761,7 +761,6 @@ void () AirBlastReloadFinished = { dremove(self); }; -void () UseAirBlast = { if (self.special_cooldown < time) { self.airblast_cooldown = 1; @@ -775,8 +774,12 @@ void () UseAirBlast = { FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); makevectors(self.v_angle); entity ent; + vector ab_start = self.origin + v_forward * 8; + vector ab_origin = ab_start + aim(self,1000) * (PC_PYRO_AIRBLAST_RANGE / 2); + vector ab_end = ab_start + aim(self,1000) * PC_PYRO_AIRBLAST_RANGE; + ent = findradius(ab_origin, PC_PYRO_AIRBLAST_RANGE); - ent = findradius(self.origin, PC_PYRO_AIRBLAST_RANGE); + ent = findradius(ab_origin, PC_PYRO_AIRBLAST_RANGE); while (ent) { if (ent.movetype != MOVETYPE_NONE && ent != self) @@ -797,37 +800,43 @@ void () UseAirBlast = { vector targorg; targorg = ent.origin; float pushval = 1000; - if (ent == self) - { - pushval = 500; - traceline(self.origin, self.origin + v_forward * 200, MOVE_NOMONSTERS, self); - if (trace_fraction < 1) - { - targorg = self.origin - (v_forward * 200 * trace_fraction); - } - } - vector delta = targorg - self.origin; + vector delta = targorg - ab_start; float dist = vlen(delta); float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; + pushval = pushval * percent; + + if (pushval < 500) + { + pushval = 500; + } + else if (pushval > 800) + { + pushval = 800; + } + if (ent.flags & FL_ONGROUND) { if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted { - setorigin(ent, ent.origin + '0 0 1'); + setorigin(ent, ent.origin + '0 0 5'); } } delta = normalize(delta); - delta = delta * percent * pushval; + delta = delta * pushval; if (ent.movetype == MOVETYPE_FLYMISSILE) { float speed = vlen(ent.velocity); ent.velocity = normalize(delta) * speed; } - else + else if (ent.velocity == '0 0 0') + { + ent.velocity = v_forward * 500; + } + else { ent.velocity = ent.velocity + delta; } @@ -844,4 +853,4 @@ void () UseAirBlast = { { sprint(self, PRINT_HIGH, "Airblast is on cooldown\n"); } -}; \ No newline at end of file +}; From 705d1f2177285028d8315ab3f5c114cf070f45b4 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:03:40 +1100 Subject: [PATCH 1329/2474] Added missing/removed UseAirBlast declaration Below code restored. void () UseAirBlast = { --- ssqc/pyro.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 35445a65..010ad2ef 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -761,6 +761,7 @@ void () AirBlastReloadFinished = { dremove(self); }; +void () UseAirBlast = { if (self.special_cooldown < time) { self.airblast_cooldown = 1; From b67584d0590d6a56dd0587139bd10f33426cae99 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:06:14 +1100 Subject: [PATCH 1330/2474] Updated Pyro AirBlast range Updated PC_PYRO_AIRBLAST_RANGE as code updated to based on aim not on the player mode. --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index b3e8fb9c..b7c87a72 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1062,7 +1062,7 @@ #define PC_PYRO_GRENADE_MAX_1 4 #define PC_PYRO_GRENADE_MAX_2 4 #define PC_PYRO_TF_ITEMS 0 -#define PC_PYRO_AIRBLAST_RANGE 400 +#define PC_PYRO_AIRBLAST_RANGE 200 #define PC_PYRO_AIRBLAST_COOLDOWN 5 #define PC_PYRO_LAVA_LIFETIME 3 #define PC_PYRO_LAVA_RETICK 1.2 From b2df970e2bebf5acf29d5f2d00d096e19ec55c1e Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 4 Oct 2021 14:25:06 +1100 Subject: [PATCH 1331/2474] Including airblast pushval min and max. --- ssqc/qw.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 6e1094de..1f218be5 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -572,6 +572,8 @@ float server_huetf; float scoutscanspike; float asscanrange; float asscanrangedie; +float airblastpushmin; +float airblastpushmax; float old_spanner; float old_dispenser; From e3215f6f5ff69c68f4542057f2caea8fd31c056c Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 4 Oct 2021 14:27:42 +1100 Subject: [PATCH 1332/2474] Including airblast pushval min and max --- ssqc/client.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index a7003f8f..e50f8ed1 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -573,6 +573,10 @@ void () DecodeLevelParms = { // HwGuy Assault Cannon Range default as 0 to disable, and die time once range hit. asscanrange = CF_GetSetting("acr", "asscanrange", "0"); asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); + + // Pyro Airblast pushval min and max + airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); + airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); @@ -812,6 +816,8 @@ void () DecodeLevelParms = { walls_block_emp = FALSE; solid_nailgren = FALSE; scoutscanspike = TRUE; + airblastpushmin = 500; + airblastpushmax = 800; } st = infokey(world, "faithful"); From a0d02f74c2f209e84109c5301e8b19f3cc86b2ae Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 4 Oct 2021 14:29:33 +1100 Subject: [PATCH 1333/2474] Including server options pushval min and max --- ssqc/pyro.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 010ad2ef..3841fce1 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -807,13 +807,13 @@ void () UseAirBlast = { float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; pushval = pushval * percent; - if (pushval < 500) + if (pushval < airblastpushmin) { - pushval = 500; + pushval = airblastpushmin; } - else if (pushval > 800) + else if (pushval > airblastpushmax) { - pushval = 800; + pushval = airblastpushmax; } From 2ba62c6d66b726bfb5f24cfd06b7be61369d327f Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 4 Oct 2021 15:16:51 +1100 Subject: [PATCH 1334/2474] Update pyro.qc --- ssqc/pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 3841fce1..6203c8d0 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -800,7 +800,7 @@ void () UseAirBlast = { case "pipebomb": vector targorg; targorg = ent.origin; - float pushval = 1000; + float pushval = airblastpushmax / 0.8; vector delta = targorg - ab_start; float dist = vlen(delta); From 0d49efe9d155caa7ddb6dd0916dce19e0200bdff Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:35:15 +1100 Subject: [PATCH 1335/2474] Original airblast and now airblastv2 --- ssqc/pyro.qc | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 6203c8d0..b1ebcc84 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -762,6 +762,91 @@ void () AirBlastReloadFinished = { }; void () UseAirBlast = { + if (self.special_cooldown < time) + { + self.airblast_cooldown = 1; + self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; + entity timer = spawn(); + timer.owner = self; + timer.classname = "timer"; + timer.nextthink = time + PC_PYRO_AIRBLAST_COOLDOWN; + timer.think = AirBlastReloadFinished; + + FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); + makevectors(self.v_angle); + entity ent; + + ent = findradius(self.origin, PC_PYRO_AIRBLAST_RANGE); + while (ent) + { + if (ent.movetype != MOVETYPE_NONE && ent != self) + { + if (infront(ent)) + { + switch (ent.classname) + { + case "player": + case "pyro_rocket": + case "flamerflame": + case "proj_tranq": + case "proj_bullet": + case "proj_rocket": + case "grenade": + case "spike": + case "pipebomb": + vector targorg; + targorg = ent.origin; + float pushval = 1000; + if (ent == self) + { + pushval = 500; + traceline(self.origin, self.origin + v_forward * 200, MOVE_NOMONSTERS, self); + if (trace_fraction < 1) + { + targorg = self.origin - (v_forward * 200 * trace_fraction); + } + } + + vector delta = targorg - self.origin; + float dist = vlen(delta); + float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; + + if (ent.flags & FL_ONGROUND) + { + if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted + { + setorigin(ent, ent.origin + '0 0 1'); + } + } + + delta = normalize(delta); + delta = delta * percent * pushval; + + if (ent.movetype == MOVETYPE_FLYMISSILE) + { + float speed = vlen(ent.velocity); + ent.velocity = normalize(delta) * speed; + } + else + { + ent.velocity = ent.velocity + delta; + } + + break; + } + } + } + + ent = ent.chain; + } + } + else + { + sprint(self, PRINT_HIGH, "Airblast is on cooldown\n"); + } +}; + +void () UseAirBlastV2 = { if (self.special_cooldown < time) { self.airblast_cooldown = 1; From 5544130909b9b6dea326bc3ac99f0631749ed6bf Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:36:45 +1100 Subject: [PATCH 1336/2474] Server config now for airblastv2 --- ssqc/tfort.qc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3247d0d3..14500c84 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -67,7 +67,13 @@ void () UseSpecialSkill = { return; case PC_PYRO: if (pyro_type == PYRO_FO) - UseAirBlast(); + if (airblastv2) { + UseAirBlastV2(); + } + else + { + UseAirBlast(); + } Status_Refresh(self); break; case PC_SPY: From 5b446d897b7817ae7ce703046e670abe6b3f84f1 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:37:25 +1100 Subject: [PATCH 1337/2474] Server config for airblastv2 --- ssqc/qw.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 1f218be5..d0e73af1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -572,6 +572,7 @@ float server_huetf; float scoutscanspike; float asscanrange; float asscanrangedie; +float airblastv2; float airblastpushmin; float airblastpushmax; From 8d223bd7c62aadcc042a1960283efaa96031a455 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:38:46 +1100 Subject: [PATCH 1338/2474] Serverconfig for airblastv2 --- ssqc/client.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index e50f8ed1..637f78e3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -575,6 +575,7 @@ void () DecodeLevelParms = { asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); // Pyro Airblast pushval min and max + airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); From 7089f6c5b39f204d32d6fda104abcb7a81854dfe Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:50:33 +1100 Subject: [PATCH 1339/2474] Update defs.h --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index b7c87a72..5e2655af 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1062,7 +1062,7 @@ #define PC_PYRO_GRENADE_MAX_1 4 #define PC_PYRO_GRENADE_MAX_2 4 #define PC_PYRO_TF_ITEMS 0 -#define PC_PYRO_AIRBLAST_RANGE 200 +#define PC_PYRO_AIRBLAST_RANGE 400 #define PC_PYRO_AIRBLAST_COOLDOWN 5 #define PC_PYRO_LAVA_LIFETIME 3 #define PC_PYRO_LAVA_RETICK 1.2 From 649a2b1e4c8ede915f57a41b530a839fb0572cc5 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:54:15 +1100 Subject: [PATCH 1340/2474] Range tweaks for airblastv2 For backward compatibility halving the airblast range for the v2 function. --- ssqc/pyro.qc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index b1ebcc84..2db42ebb 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -860,12 +860,13 @@ void () UseAirBlastV2 = { FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); makevectors(self.v_angle); entity ent; + float abrange = PC_PYRO_AIRBLAST_RANGE / 2; vector ab_start = self.origin + v_forward * 8; - vector ab_origin = ab_start + aim(self,1000) * (PC_PYRO_AIRBLAST_RANGE / 2); - vector ab_end = ab_start + aim(self,1000) * PC_PYRO_AIRBLAST_RANGE; - ent = findradius(ab_origin, PC_PYRO_AIRBLAST_RANGE); + vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); + vector ab_end = ab_start + aim(self,1000) * abrange; + ent = findradius(ab_origin, abrange); - ent = findradius(ab_origin, PC_PYRO_AIRBLAST_RANGE); + ent = findradius(ab_origin, abrange); while (ent) { if (ent.movetype != MOVETYPE_NONE && ent != self) @@ -886,10 +887,10 @@ void () UseAirBlastV2 = { vector targorg; targorg = ent.origin; float pushval = airblastpushmax / 0.8; - + vector delta = targorg - ab_start; float dist = vlen(delta); - float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; + float percent = (abrange - dist) / abrange; pushval = pushval * percent; if (pushval < airblastpushmin) From b7c4b5cd86b5a83e795c1a4545fcd627abd8fc38 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 11:17:22 +1100 Subject: [PATCH 1341/2474] Removed infront since Airblast is now based on aim --- ssqc/pyro.qc | 102 +++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 2db42ebb..ac748931 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -871,65 +871,61 @@ void () UseAirBlastV2 = { { if (ent.movetype != MOVETYPE_NONE && ent != self) { - if (infront(ent)) + switch (ent.classname) { - switch (ent.classname) - { - case "player": - case "pyro_rocket": - case "flamerflame": - case "proj_tranq": - case "proj_bullet": - case "proj_rocket": - case "grenade": - case "spike": - case "pipebomb": - vector targorg; - targorg = ent.origin; - float pushval = airblastpushmax / 0.8; + case "player": + case "pyro_rocket": + case "flamerflame": + case "proj_tranq": + case "proj_bullet": + case "proj_rocket": + case "grenade": + case "spike": + case "pipebomb": + vector targorg; + targorg = ent.origin; + float pushval = airblastpushmax / 0.8; - vector delta = targorg - ab_start; - float dist = vlen(delta); - float percent = (abrange - dist) / abrange; - pushval = pushval * percent; - - if (pushval < airblastpushmin) - { - pushval = airblastpushmin; - } - else if (pushval > airblastpushmax) + vector delta = targorg - ab_start; + float dist = vlen(delta); + float percent = (abrange - dist) / abrange; + pushval = pushval * percent; + + if (pushval < airblastpushmin) + { + pushval = airblastpushmin; + } + else if (pushval > airblastpushmax) + { + pushval = airblastpushmax; + } + + if (ent.flags & FL_ONGROUND) + { + if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted { - pushval = airblastpushmax; - } - - - if (ent.flags & FL_ONGROUND) - { - if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted - { - setorigin(ent, ent.origin + '0 0 5'); - } + setorigin(ent, ent.origin + '0 0 5'); } + } - delta = normalize(delta); - delta = delta * pushval; - - if (ent.movetype == MOVETYPE_FLYMISSILE) - { - float speed = vlen(ent.velocity); - ent.velocity = normalize(delta) * speed; - } - else if (ent.velocity == '0 0 0') - { - ent.velocity = v_forward * 500; - } - else - { - ent.velocity = ent.velocity + delta; - } + delta = normalize(delta); + delta = delta * pushval; + + if (ent.movetype == MOVETYPE_FLYMISSILE) + { + float speed = vlen(ent.velocity); + ent.velocity = normalize(delta) * speed; + } + else if (ent.velocity == '0 0 0') + { + ent.velocity = v_forward * 500; + } + else + { + ent.velocity = ent.velocity + delta; + } - break; - } + break; } } From 30860d5ae088e457edee3df380e6b7f791fc5b50 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 13:12:53 +1100 Subject: [PATCH 1342/2474] Update pyro.qc --- ssqc/pyro.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index ac748931..719dd516 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -864,7 +864,6 @@ void () UseAirBlastV2 = { vector ab_start = self.origin + v_forward * 8; vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); vector ab_end = ab_start + aim(self,1000) * abrange; - ent = findradius(ab_origin, abrange); ent = findradius(ab_origin, abrange); while (ent) From bad6282668ce57d4a3a6763ee5e20703d3cb2ccc Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 13:52:03 +1100 Subject: [PATCH 1343/2474] Update client.qc --- ssqc/client.qc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 637f78e3..761b3a31 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -566,17 +566,17 @@ void () DecodeLevelParms = { // configure max armor of heavy weapons guy [300] max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); - - // Scout Scanner spike on / off + + // Scout Scanner spike on / off scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); - - // HwGuy Assault Cannon Range default as 0 to disable, and die time once range hit. - asscanrange = CF_GetSetting("acr", "asscanrange", "0"); + + // HwGuy Assault Cannon Range default as 0 to disable, and die time once range hit. + asscanrange = CF_GetSetting("acr", "asscanrange", "0"); asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); - - // Pyro Airblast pushval min and max - airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); - airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); + + // Pyro Airblast pushval min and max + airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); + airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); // delay respawning by this many seconds [0] @@ -816,9 +816,9 @@ void () DecodeLevelParms = { solid_detpack = FALSE; walls_block_emp = FALSE; solid_nailgren = FALSE; - scoutscanspike = TRUE; - airblastpushmin = 500; - airblastpushmax = 800; + scoutscanspike = TRUE; + airblastpushmin = 500; + airblastpushmax = 800; } st = infokey(world, "faithful"); From 11645cbcd258c3f5c732b8830c4d1db380120530 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 13:54:01 +1100 Subject: [PATCH 1344/2474] Update defs.h --- share/defs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 5e2655af..b2336f27 100644 --- a/share/defs.h +++ b/share/defs.h @@ -872,6 +872,8 @@ #define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range #define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector +#define MODEL_SPIKE_SCAN "progs/spike_scan.mdl" + // Class Details for SNIPER #define PC_SNIPER_SKIN 5 #define PC_SNIPER_MAXHEALTH 100 @@ -1032,7 +1034,6 @@ #define PC_HVYWEAP_PROJSPEED 3000 #define PC_HVYWEAP_ASSCAN_CLIPSIZE 100 #define MODEL_PROJ_DIAM2 "progs/proj_diam2.mdl" -#define MODEL_SPIKE_SCAN "progs/spike_scan.mdl" // Class Details for PYRO From 8f3cc27efb60adc236a82046b8848930d4aaaf06 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 20:54:25 +1100 Subject: [PATCH 1345/2474] Update defs.h --- share/defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/share/defs.h b/share/defs.h index 1d448aec..c3bf0fd6 100644 --- a/share/defs.h +++ b/share/defs.h @@ -872,6 +872,8 @@ #define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range #define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector +#define MODEL_SPIKE_SCAN "progs/spike_scan.mdl" + // Class Details for SNIPER #define PC_SNIPER_SKIN 5 #define PC_SNIPER_MAXHEALTH 100 From 98b3bb31e4d1e3a3248b72c46ff3b2181a1f97f5 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 20:57:05 +1100 Subject: [PATCH 1346/2474] Update client.qc --- ssqc/client.qc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 238d89d4..d14aaa3a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -521,6 +521,18 @@ void () DecodeLevelParms = { // turn off spy [off] spy_off = CF_GetSetting("spy", "spy", "off"); + + // Scout Scanner spike on / off + scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); + + // HwGuy Assault Cannon Range default as 0 to disable, and die time once range hit. + asscanrange = CF_GetSetting("acr", "asscanrange", "0"); + asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); + + // Pyro Airblast pushval min and max + airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); + airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); + airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); // enable spy invisibility [off] invis_only = CF_GetSetting("s", "spyinvis", "off"); @@ -804,6 +816,9 @@ void () DecodeLevelParms = { solid_detpack = FALSE; walls_block_emp = FALSE; solid_nailgren = FALSE; + scoutscanspike = TRUE; + airblastpushmin = 500; + airblastpushmax = 800; } st = infokey(world, "faithful"); @@ -875,6 +890,7 @@ void () DecodeLevelParms = { solid_detpack = TRUE; walls_block_emp = FALSE; solid_nailgren = TRUE; + scoutscanspike = FALSE; } st = infokey(world, "huetf"); From de8af93b41142a5449e512bb908fc4f6acdea73d Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 20:58:29 +1100 Subject: [PATCH 1347/2474] Update hwguy.qc --- ssqc/hwguy.qc | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index b6186821..c6bb1c0c 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -1,3 +1,15 @@ +void AssCanBulletThink () +{ + self.movetype = MOVETYPE_TOSS; + self.think = SUB_Remove; + + if (asscanrangedie > 0) { + self.nextthink = time + asscanrangedie; + } else { + self.nextthink = time + 3; + } +} + void AssCanBulletTouch() { if (self.voided) @@ -61,6 +73,8 @@ vector(float base, float rndmix, float plusminus) vecrand = void LaunchAssCan(vector org, vector dir, float proj_speed) { + local float num; + newmis = spawn(); newmis.owner = self; newmis.classname = "proj_bullet"; @@ -69,9 +83,16 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) newmis.solid = SOLID_BBOX; newmis.touch = AssCanBulletTouch; - - newmis.think = SUB_Remove; - newmis.nextthink = time + 5; // Stop projectile going forever + + + if (asscanrange > 0) { + num = (1 / proj_speed) * asscanrange; + newmis.think = AssCanBulletThink; + newmis.nextthink = time + num; // Projectile range / gravity + } else { + newmis.think = SUB_Remove; + newmis.nextthink = time + 5; // Stop projectile going forever + } newmis.mdl = MODEL_PROJ_DIAM2; FO_SetModel(newmis, newmis.mdl); // Diamond model From 91ec62f99a991b3e35e387364a000c545351699b Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 20:59:12 +1100 Subject: [PATCH 1348/2474] Update pyro.qc --- ssqc/pyro.qc | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 9422ab71..8bd29191 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -844,4 +844,95 @@ void () UseAirBlast = { { sprint(self, PRINT_HIGH, "Airblast is on cooldown\n"); } -}; \ No newline at end of file +}; + +void () UseAirBlastV2 = { + if (self.special_cooldown < time) + { + self.airblast_cooldown = 1; + self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; + entity timer = spawn(); + timer.owner = self; + timer.classname = "timer"; + timer.nextthink = time + PC_PYRO_AIRBLAST_COOLDOWN; + timer.think = AirBlastReloadFinished; + + FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); + makevectors(self.v_angle); + entity ent; + float abrange = PC_PYRO_AIRBLAST_RANGE / 2; + vector ab_start = self.origin + v_forward * 8; + vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); + vector ab_end = ab_start + aim(self,1000) * abrange; + + ent = findradius(ab_origin, abrange); + while (ent) + { + if (ent.movetype != MOVETYPE_NONE && ent != self) + { + switch (ent.classname) + { + case "player": + case "pyro_rocket": + case "flamerflame": + case "proj_tranq": + case "proj_bullet": + case "proj_rocket": + case "grenade": + case "spike": + case "pipebomb": + vector targorg; + targorg = ent.origin; + float pushval = airblastpushmax / 0.8; + + vector delta = targorg - ab_start; + float dist = vlen(delta); + float percent = (abrange - dist) / abrange; + pushval = pushval * percent; + + if (pushval < airblastpushmin) + { + pushval = airblastpushmin; + } + else if (pushval > airblastpushmax) + { + pushval = airblastpushmax; + } + + if (ent.flags & FL_ONGROUND) + { + if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted + { + setorigin(ent, ent.origin + '0 0 5'); + } + } + + delta = normalize(delta); + delta = delta * pushval; + + if (ent.movetype == MOVETYPE_FLYMISSILE) + { + float speed = vlen(ent.velocity); + ent.velocity = normalize(delta) * speed; + } + else if (ent.velocity == '0 0 0') + { + ent.velocity = v_forward * 500; + } + else + { + ent.velocity = ent.velocity + delta; + } + + break; + } + } + + ent = ent.chain; + } + } + else + { + sprint(self, PRINT_HIGH, "Airblast is on cooldown\n"); + } +}; From 017f8deb29c626377f51871f6fd997944bbdb96a Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 21:00:20 +1100 Subject: [PATCH 1349/2474] Update qw.qc --- ssqc/qw.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 6a452f69..b55423c7 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -569,6 +569,12 @@ float buildstatus; float server_default; float server_faithful; float server_huetf; +float scoutscanspike; +float asscanrange; +float asscanrangedie; +float airblastv2; +float airblastpushmin; +float airblastpushmax; float old_spanner; float old_dispenser; From 87ee49eb0ba84c4071ae256e82a140bcf47602aa Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 21:02:05 +1100 Subject: [PATCH 1350/2474] Update scout.qc --- ssqc/scout.qc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 203283a2..7f245e1c 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -546,6 +546,7 @@ void () TeamFortress_Scan = { local float scen; local float scfr; local float num; + local vector scanvec; local vector lightningvec; local float enemy_detected; local float any_detected; @@ -634,6 +635,51 @@ void () TeamFortress_Scan = { WriteCoord(MSG_ONE, lightningvec_x); WriteCoord(MSG_ONE, lightningvec_y); WriteCoord(MSG_ONE, lightningvec_z + 8); + + if (scoutscanspike) { + scanvec = normalize(list.origin - self.owner.origin); + newmis = spawn(); + newmis.owner = self.owner; + newmis.enemy = self.owner; + newmis.movetype = MOVETYPE_NOCLIP; + newmis.solid = SOLID_NOT; + + FO_SetModel(newmis, MODEL_SPIKE_SCAN); + setsize(newmis, '0 0 0', '0 0 0'); + setorigin(newmis, self.owner.origin + v_forward * 8); + + switch (self.owner.team_no) + { + case TEAM_BLUE: + newmis.dimension_seen = DMN_TEAMBLUE; + break; + case TEAM_RED: + newmis.dimension_seen = DMN_TEAMRED; + break; + case TEAM_YELL: + newmis.dimension_seen = DMN_TEAMYELL; + break; + case TEAM_GREN: + newmis.dimension_seen = DMN_TEAMGREN; + break; + default: + newmis.dimension_seen = DMN_NOFLASH; + break; + } + + newmis.velocity = scanvec * 1000; + newmis.angles = vectoangles(newmis.velocity); + newmis.oldorigin = newmis.velocity; + + //Remove the scan spike when it reaches list.origin + newmis.think = SUB_Remove; + num = vlen(list.origin - self.owner.origin); + num = num / 1000; + newmis.nextthink = time + num; + + newmis.touch = SUB_Null; + newmis.classname = "scanspike"; + } if (self.owner.tf_items_flags & 4) { stuffcmd(self.owner, "play misc/basekey.wav\n"); From 653ea3a84338ee0f2e29c7c2e730157f7e824d31 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 21:02:53 +1100 Subject: [PATCH 1351/2474] Update tfort.qc --- ssqc/tfort.qc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e5925e90..ae0654a0 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -67,7 +67,14 @@ void () UseSpecialSkill = { return; case PC_PYRO: if (pyro_type == PYRO_FO) - UseAirBlast(); + if (airblastv2) { + UseAirBlastV2(); + } + else + { + UseAirBlast(); + } + Status_Refresh(self); break; case PC_SPY: From 5c873a7607ed6d5e4bb0058b9bd35e8f65eb93d9 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 6 Oct 2021 21:04:09 +1100 Subject: [PATCH 1352/2474] Update world.qc --- ssqc/world.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/world.qc b/ssqc/world.qc index 65bc4afd..0a445719 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -264,6 +264,7 @@ void () worldspawn = { precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); precache_model2(MODEL_PROJ_DIAM2); + precache_model2(MODEL_SPIKE_SCAN); precache_sound("grentimer.wav"); precache_sound("buttons/switch04.wav"); precache_sound("boss1/out1.wav"); From 3ad9d5fc1d3d9670592e1604dbae4ccb451f4217 Mon Sep 17 00:00:00 2001 From: driztf Date: Wed, 6 Oct 2021 23:18:17 +0000 Subject: [PATCH 1353/2474] Experimental rocket projection --- ssqc/client.qc | 4 ++++ ssqc/qw.qc | 2 ++ ssqc/weapons.qc | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 238d89d4..88607e32 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -567,6 +567,9 @@ void () DecodeLevelParms = { // configure max armor of heavy weapons guy [300] max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); + // project rockets by player ping + project_rockets = CF_GetSetting("pr", "project_rockets", "on"); + // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { @@ -895,6 +898,7 @@ void () DecodeLevelParms = { detpipe_limit_world = 7; medicaura = FALSE; medicnocuss = FALSE; + project_rockets = FALSE; pyro_type = 1; drop_grenades = FALSE; drop_grenpack = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d9319f68..1908bc20 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -575,6 +575,8 @@ float old_dispenser; float old_hp_armor; float max_armor_hwguy; +float project_rockets; + float ng_velocity; float ng_damage; float sng_damage; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index aec270a6..0eb95611 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1106,6 +1106,30 @@ void () W_FireRocket = { FO_SetModel(newmis, "progs/missile.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + + if (project_rockets) { + // Project rockets player ping forward in time based on ping up to a maximum of 100ms + local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; + if (player_ping_s > 0.1) { + player_ping_s = 0.1; + } + local float rocket_offset = player_ping_s * 450; + local vector projected_origin = self.origin + v_forward * (8 + rocket_offset) + '0 0 16'; + + local string st; + + st = ftos(rocket_offset); + bprint4(PRINT_HIGH, "Offset : ", st, "\n"); + + // Trace projectile? + traceline(newmis.origin, projected_origin, MOVE_LAGGED, self); + + if (trace_fraction < 1) { + projected_origin = trace_endpos; + } + + setorigin(newmis, projected_origin); + } }; void (entity from, float damage) LightningHit = { From 4fda776e12809efb1cee21d6471eb0a1e870e60f Mon Sep 17 00:00:00 2001 From: driztf Date: Thu, 7 Oct 2021 06:12:28 +0000 Subject: [PATCH 1354/2474] - introduce const for rocket speed - allow comp up to 150ms (~70 units projected) --- share/defs.h | 2 +- ssqc/weapons.qc | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/share/defs.h b/share/defs.h index e200ebce..418add37 100644 --- a/share/defs.h +++ b/share/defs.h @@ -926,6 +926,7 @@ #define PC_SOLDIER_GRENADE_INIT_2 1 #define PC_SOLDIER_GRENADE_MAX_1 4 #define PC_SOLDIER_GRENADE_MAX_2 1 +#define PC_SOLDIER_ROCKET_SPEED 900 #define PC_SOLDIER_TF_ITEMS 0 // Class Details for DEMOLITION MAN @@ -1077,7 +1078,6 @@ #define PC_PYRO_BURN_MULTIPLIER_FO 1 #define PC_PYRO_BURN_DAMAGE_AMP 1.2 - // pyro types #define PYRO_ORIGINAL 0 #define PYRO_OZTF 1 diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 0eb95611..23962fe1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1092,7 +1092,7 @@ void () W_FireRocket = { makevectors(self.v_angle); newmis.velocity = v_forward; - newmis.velocity = newmis.velocity * 900; + newmis.velocity = newmis.velocity * PC_SOLDIER_ROCKET_SPEED; newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_MissileTouch; @@ -1110,10 +1110,13 @@ void () W_FireRocket = { if (project_rockets) { // Project rockets player ping forward in time based on ping up to a maximum of 100ms local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; - if (player_ping_s > 0.1) { - player_ping_s = 0.1; + if (player_ping_s > 0.15) { + player_ping_s = 0.15; + } else if (player_ping_s < 0.0015) { + player_ping_s = 0; } - local float rocket_offset = player_ping_s * 450; + + local float rocket_offset = (player_ping_s / 2) * PC_SOLDIER_ROCKET_SPEED; local vector projected_origin = self.origin + v_forward * (8 + rocket_offset) + '0 0 16'; local string st; @@ -1121,7 +1124,7 @@ void () W_FireRocket = { st = ftos(rocket_offset); bprint4(PRINT_HIGH, "Offset : ", st, "\n"); - // Trace projectile? + // Trace projectile? traceline(newmis.origin, projected_origin, MOVE_LAGGED, self); if (trace_fraction < 1) { From e0ab7bbe6270d325352939fc165eb4721885d484 Mon Sep 17 00:00:00 2001 From: driztf Date: Thu, 7 Oct 2021 17:37:47 +0000 Subject: [PATCH 1355/2474] - introduce projection function - also project assault cannon bullets --- ssqc/antilag.qc | 34 ++++++++++++++++++++++++++++++++++ ssqc/client.qc | 4 ++++ ssqc/hwguy.qc | 4 ++++ ssqc/progs.src | 1 + ssqc/qw.qc | 1 + ssqc/weapons.qc | 25 +------------------------ 6 files changed, 45 insertions(+), 24 deletions(-) create mode 100644 ssqc/antilag.qc diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc new file mode 100644 index 00000000..a4ba84dd --- /dev/null +++ b/ssqc/antilag.qc @@ -0,0 +1,34 @@ +void AL_ProjectProjectile (entity projectile, float velocity) { + // Project projectiles player ping forward in time based on ping up to a maximum of 150ms + // Effective projection time is 75ms, because we assume RTT is evenly distributed in both + // directions - and we want the server to spawn the entity in the position it would have + // have been if it had received the message (player_ping / 2) ago. + local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; + // Remove 13ms / 1 frame to keep behaviour consistent on low ping + player_ping_s = player_ping_s - (0.01298701298); // 1/77 + if (player_ping_s > 0.15) { + player_ping_s = 0.15; + } else if (player_ping_s < 0.0013) { + player_ping_s = 0; + } + + local float rocket_offset = (player_ping_s / 2) * velocity; + local vector projected_origin = newmis.origin + v_forward * (rocket_offset); + + local string st; + st = ftos(rocket_offset); + bprint4(PRINT_HIGH, "Offset : ", st, "\n"); + + // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin + // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED + // because by tracing between old origin and projected origin we effectively have a single (last) frame + // rewind at the projected origin. The effect is high ping players are disadvantaged in close combat. + // This is preferable to unhappy low ping players. + traceline(newmis.origin, projected_origin, 0, self); + + if (trace_fraction < 1) { + projected_origin = trace_endpos; + } + + setorigin(newmis, projected_origin); +} \ No newline at end of file diff --git a/ssqc/client.qc b/ssqc/client.qc index 88607e32..37c7c848 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -570,6 +570,9 @@ void () DecodeLevelParms = { // project rockets by player ping project_rockets = CF_GetSetting("pr", "project_rockets", "on"); + // project assault cannon by player ping + project_assault_cannon = CF_GetSetting("pac", "project_assault_cannon", "on"); + // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { @@ -899,6 +902,7 @@ void () DecodeLevelParms = { medicaura = FALSE; medicnocuss = FALSE; project_rockets = FALSE; + project_assault_cannon = FALSE; pyro_type = 1; drop_grenades = FALSE; drop_grenpack = FALSE; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index b6186821..0176fb94 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -85,6 +85,10 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) setorigin (newmis, org); // Move to starting position newmis.avelocity = vecrand(100, 200, FALSE); + + if (project_assault_cannon) { + AL_ProjectProjectile(newmis, proj_speed); + } } void FireAssCan (float shotcount, vector dir, vector spread) diff --git a/ssqc/progs.src b/ssqc/progs.src index a8cf2a8c..06557f4c 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -22,6 +22,7 @@ subs.qc combat.qc items.qc locfiles.qc +antilag.qc weapons.qc world.qc client.qc diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 1908bc20..9c7309bc 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -576,6 +576,7 @@ float old_hp_armor; float max_armor_hwguy; float project_rockets; +float project_assault_cannon; float ng_velocity; float ng_damage; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 23962fe1..f0f49110 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1108,30 +1108,7 @@ void () W_FireRocket = { setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); if (project_rockets) { - // Project rockets player ping forward in time based on ping up to a maximum of 100ms - local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; - if (player_ping_s > 0.15) { - player_ping_s = 0.15; - } else if (player_ping_s < 0.0015) { - player_ping_s = 0; - } - - local float rocket_offset = (player_ping_s / 2) * PC_SOLDIER_ROCKET_SPEED; - local vector projected_origin = self.origin + v_forward * (8 + rocket_offset) + '0 0 16'; - - local string st; - - st = ftos(rocket_offset); - bprint4(PRINT_HIGH, "Offset : ", st, "\n"); - - // Trace projectile? - traceline(newmis.origin, projected_origin, MOVE_LAGGED, self); - - if (trace_fraction < 1) { - projected_origin = trace_endpos; - } - - setorigin(newmis, projected_origin); + AL_ProjectProjectile(newmis, PC_SOLDIER_ROCKET_SPEED); } }; From fff75926efcd9edcfa517bfc503f0f22b5011f39 Mon Sep 17 00:00:00 2001 From: driztf Date: Fri, 8 Oct 2021 00:14:10 +0000 Subject: [PATCH 1356/2474] - apply to pyro, spy, engineer, nailguns - remove debug code - use single toggle --- share/defs.h | 4 ++++ ssqc/antilag.qc | 4 ---- ssqc/client.qc | 10 +++------- ssqc/engineer.qc | 6 +++++- ssqc/hwguy.qc | 2 +- ssqc/pyro.qc | 4 ++++ ssqc/qw.qc | 3 +-- ssqc/spy.qc | 5 ++++- ssqc/weapons.qc | 6 +++++- 9 files changed, 27 insertions(+), 17 deletions(-) diff --git a/share/defs.h b/share/defs.h index 418add37..248fb9f5 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1077,6 +1077,8 @@ #define PC_PYRO_BURN_MULTIPLIER_ORIG .3 #define PC_PYRO_BURN_MULTIPLIER_FO 1 #define PC_PYRO_BURN_DAMAGE_AMP 1.2 +#define PC_PYRO_OLD_PROJSPEED 600 +#define PC_PYRO_NEW_PROJSPEED 800 // pyro types #define PYRO_ORIGINAL 0 @@ -1114,6 +1116,7 @@ #define PC_SPY_CELL_REGEN_AMOUNT 1 #define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible #define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover +#define PC_SPY_TRANQSPEED 1500 // Class Details for ENGINEER #define PC_ENGINEER_SKIN 22 // Not used anymore @@ -1143,6 +1146,7 @@ #define PC_ENGINEER_GRENADE_MAX_2 4 #define PC_ENGINEER_TF_ITEMS 0 #define PC_ENGINEER_GRENADE_TYPE_2_RANGE 240 +#define PC_ENGINEER_RAILSPEED 1500 // Class Details for CIVILIAN #define PC_CIVILIAN_SKIN 22 diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index a4ba84dd..cfbf6e41 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -14,10 +14,6 @@ void AL_ProjectProjectile (entity projectile, float velocity) { local float rocket_offset = (player_ping_s / 2) * velocity; local vector projected_origin = newmis.origin + v_forward * (rocket_offset); - - local string st; - st = ftos(rocket_offset); - bprint4(PRINT_HIGH, "Offset : ", st, "\n"); // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED diff --git a/ssqc/client.qc b/ssqc/client.qc index 37c7c848..298f40b6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -567,11 +567,8 @@ void () DecodeLevelParms = { // configure max armor of heavy weapons guy [300] max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); - // project rockets by player ping - project_rockets = CF_GetSetting("pr", "project_rockets", "on"); - - // project assault cannon by player ping - project_assault_cannon = CF_GetSetting("pac", "project_assault_cannon", "on"); + // project projectile weapons by player ping + project_weapons = CF_GetSetting("pw", "project_weapons", "on"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); @@ -901,8 +898,7 @@ void () DecodeLevelParms = { detpipe_limit_world = 7; medicaura = FALSE; medicnocuss = FALSE; - project_rockets = FALSE; - project_assault_cannon = FALSE; + project_weapons = FALSE; pyro_type = 1; drop_grenades = FALSE; drop_grenpack = FALSE; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index e323b013..7d109c49 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -100,7 +100,7 @@ void () W_FireLaser = { setorigin(newmis, org + '0 0 16'); - newmis.velocity = vec * 1500; + newmis.velocity = vec * PC_ENGINEER_RAILSPEED; newmis.angles = vectoangles(newmis.velocity); newmis.oldorigin = newmis.velocity; @@ -108,6 +108,10 @@ void () W_FireLaser = { newmis.think = SUB_Remove; newmis.touch = LaserBolt_Touch; newmis.classname = "railslug"; + + if (project_weapons) { + AL_ProjectProjectile(newmis, PC_ENGINEER_RAILSPEED); + } }; void () EMPExplode = { diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 0176fb94..e8eaa27c 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -86,7 +86,7 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) newmis.avelocity = vecrand(100, 200, FALSE); - if (project_assault_cannon) { + if (project_weapons) { AL_ProjectProjectile(newmis, proj_speed); } } diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 9422ab71..ce8064f4 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -728,6 +728,10 @@ void () W_FireIncendiaryCannon = { FO_SetModel(newmis, rktmdl); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + + if (project_weapons) { + AL_ProjectProjectile(newmis, pyro_type == PYRO_FO ? PC_PYRO_NEW_PROJSPEED : PC_PYRO_OLD_PROJSPEED); + } }; void () TeamFortress_IncendiaryCannon = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9c7309bc..dca32058 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -575,8 +575,7 @@ float old_dispenser; float old_hp_armor; float max_armor_hwguy; -float project_rockets; -float project_assault_cannon; +float project_weapons; float ng_velocity; float ng_damage; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 3dd6ec00..468da369 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1317,7 +1317,7 @@ void () W_FireTranq = { newmis.solid = 2; makevectors(self.v_angle); newmis.velocity = v_forward; - newmis.velocity = newmis.velocity * 1500; + newmis.velocity = newmis.velocity * PC_SPY_TRANQSPEED; newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_TranqDartTouch; newmis.think = SUB_Remove; @@ -1326,6 +1326,9 @@ void () W_FireTranq = { FO_SetModel(newmis, "progs/spike.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + if (project_weapons) { + AL_ProjectProjectile(newmis, PC_SPY_TRANQSPEED); + } }; void () T_TranqDartTouch = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f0f49110..66916f1d 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1107,7 +1107,7 @@ void () W_FireRocket = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); - if (project_rockets) { + if (project_weapons) { AL_ProjectProjectile(newmis, PC_SOLDIER_ROCKET_SPEED); } }; @@ -1346,6 +1346,10 @@ void (vector org, vector dir) launch_spike = { setorigin(newmis, org); newmis.velocity = dir * ng_velocity; + + if (project_weapons) { + AL_ProjectProjectile(newmis, ng_velocity); + } }; void () W_FireSuperSpikes = { From 82cf2ba2d09e3262726ec679d0c3bb11c075c5ab Mon Sep 17 00:00:00 2001 From: driztf Date: Fri, 8 Oct 2021 00:32:10 +0000 Subject: [PATCH 1357/2474] - reduce default max latency to 100ms - add configuration setting for max latency --- ssqc/antilag.qc | 4 ++-- ssqc/client.qc | 2 ++ ssqc/qw.qc | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index cfbf6e41..f34794c2 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -6,8 +6,8 @@ void AL_ProjectProjectile (entity projectile, float velocity) { local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; // Remove 13ms / 1 frame to keep behaviour consistent on low ping player_ping_s = player_ping_s - (0.01298701298); // 1/77 - if (player_ping_s > 0.15) { - player_ping_s = 0.15; + if (player_ping_s > project_weapons_max_latency) { + player_ping_s = project_weapons_max_latency; } else if (player_ping_s < 0.0013) { player_ping_s = 0; } diff --git a/ssqc/client.qc b/ssqc/client.qc index 298f40b6..260c4957 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -570,6 +570,8 @@ void () DecodeLevelParms = { // project projectile weapons by player ping project_weapons = CF_GetSetting("pw", "project_weapons", "on"); + project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); + // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index dca32058..ac6bec82 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -576,6 +576,7 @@ float old_hp_armor; float max_armor_hwguy; float project_weapons; +float project_weapons_max_latency; float ng_velocity; float ng_damage; From 928fb33275059ea86b44d55f39f66b33ee3f2905 Mon Sep 17 00:00:00 2001 From: driztf Date: Fri, 8 Oct 2021 00:54:48 +0000 Subject: [PATCH 1358/2474] - include grenades/pipes --- ssqc/weapons.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 66916f1d..1f853e4a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1323,6 +1323,10 @@ void () W_FireGrenade = { FO_SetModel(newmis, "progs/grenade2.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin); + + if (project_weapons) { + AL_ProjectProjectile(newmis, 600); + } }; void () spike_touch; From 5cff042d28a46fabeeece3fcbfb005d010db1e8a Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sun, 10 Oct 2021 22:36:08 +1100 Subject: [PATCH 1359/2474] Removed need for spike_scan.mdl --- share/defs.h | 2 -- ssqc/client.qc | 12 +++++++ ssqc/pyro.qc | 85 +++++++++++++++++++++++++++----------------------- ssqc/scout.qc | 60 ++++++++++++++++++----------------- 4 files changed, 89 insertions(+), 70 deletions(-) diff --git a/share/defs.h b/share/defs.h index c3bf0fd6..1d448aec 100644 --- a/share/defs.h +++ b/share/defs.h @@ -872,8 +872,6 @@ #define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range #define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector -#define MODEL_SPIKE_SCAN "progs/spike_scan.mdl" - // Class Details for SNIPER #define PC_SNIPER_SKIN 5 #define PC_SNIPER_MAXHEALTH 100 diff --git a/ssqc/client.qc b/ssqc/client.qc index d14aaa3a..b87a55bc 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -578,6 +578,18 @@ void () DecodeLevelParms = { // configure max armor of heavy weapons guy [300] max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); + + // Scout Scanner spike on / off + scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); + + // HwGuy Assault Cannon Range default as 0 to disable, and die time once range hit. + asscanrange = CF_GetSetting("acr", "asscanrange", "0"); + asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); + + // Pyro Airblast pushval min and max + airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); + airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "470"); + airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "600"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 8bd29191..1a04f41a 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -860,14 +860,37 @@ void () UseAirBlastV2 = { FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); makevectors(self.v_angle); entity ent; - float abrange = PC_PYRO_AIRBLAST_RANGE / 2; - vector ab_start = self.origin + v_forward * 8; + float abrange = PC_PYRO_AIRBLAST_RANGE / 3; + vector ab_start = self.origin + v_up * 20 + v_forward * 8; vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); vector ab_end = ab_start + aim(self,1000) * abrange; + + pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); + + /* Work in progress - CSQC for FTE players only? + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, ab_origin_x); + WriteCoord(MSG_MULTICAST, ab_origin_y); + WriteCoord(MSG_MULTICAST, ab_origin_z); + multicast(ab_origin, MULTICAST_PHS);*/ + + + vector direction = self.v_angle; + if (direction_x > 60) + { + if (self.flags & FL_ONGROUND) + self.velocity_z = 460; + else + { + self.velocity_z = self.velocity_z + 260; + } + } ent = findradius(ab_origin, abrange); while (ent) { + if (ent.movetype != MOVETYPE_NONE && ent != self) { switch (ent.classname) @@ -881,50 +904,34 @@ void () UseAirBlastV2 = { case "grenade": case "spike": case "pipebomb": - vector targorg; - targorg = ent.origin; - float pushval = airblastpushmax / 0.8; - - vector delta = targorg - ab_start; - float dist = vlen(delta); + vector targorg = ent.origin; + float pushval = airblastpushmax; + + vector delta = targorg - ab_start; + float dist = vlen(delta); + float scale = airblastpushmax - airblastpushmin; float percent = (abrange - dist) / abrange; - pushval = pushval * percent; - - if (pushval < airblastpushmin) - { - pushval = airblastpushmin; - } - else if (pushval > airblastpushmax) - { - pushval = airblastpushmax; - } - - if (ent.flags & FL_ONGROUND) - { - if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted - { - setorigin(ent, ent.origin + '0 0 5'); - } - } - - delta = normalize(delta); - delta = delta * pushval; - - if (ent.movetype == MOVETYPE_FLYMISSILE) + + if (ent.classname != "pipebomb" && ent.velocity == '0 0 0') // Airblast non-moving ents, except for pipebombs { - float speed = vlen(ent.velocity); - ent.velocity = normalize(delta) * speed; + setorigin(ent, ent.origin + '0 0 1'); + ent.velocity = '0 0 150' + normalize(ent.origin - (self.origin - v_up * 28 )) * 400; } - else if (ent.velocity == '0 0 0') + else if (ent.owner == self && ent.movetype != MOVETYPE_FLYMISSILE) // Fine tuning airblast of own items - assuming they are going forward here { - ent.velocity = v_forward * 500; + if (percent <= 0.05) { pushval = airblastpushmin; } + else if (percent >= 0.50) { pushval = airblastpushmax; } + else { pushval = airblastpushmin + scale * percent; } + + ent.velocity = ent.velocity + pushval * aim(self,1000); //* pushval; } - else + else // otherwise push in the direction of the aim { - ent.velocity = ent.velocity + delta; + ent.velocity = vlen(ent.velocity) * aim(self,1000); } - - break; + + break; + } } diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 7f245e1c..d37768c0 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -637,37 +637,39 @@ void () TeamFortress_Scan = { WriteCoord(MSG_ONE, lightningvec_z + 8); if (scoutscanspike) { - scanvec = normalize(list.origin - self.owner.origin); - newmis = spawn(); - newmis.owner = self.owner; - newmis.enemy = self.owner; - newmis.movetype = MOVETYPE_NOCLIP; - newmis.solid = SOLID_NOT; - - FO_SetModel(newmis, MODEL_SPIKE_SCAN); - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, self.owner.origin + v_forward * 8); - - switch (self.owner.team_no) - { - case TEAM_BLUE: - newmis.dimension_seen = DMN_TEAMBLUE; - break; - case TEAM_RED: - newmis.dimension_seen = DMN_TEAMRED; - break; - case TEAM_YELL: - newmis.dimension_seen = DMN_TEAMYELL; - break; - case TEAM_GREN: - newmis.dimension_seen = DMN_TEAMGREN; - break; - default: - newmis.dimension_seen = DMN_NOFLASH; - break; + scanvec = normalize(list.origin - self.owner.origin); + newmis = spawn(); + newmis.owner = self.owner; + newmis.enemy = self.owner; + newmis.movetype = MOVETYPE_NOCLIP; + newmis.solid = SOLID_NOT; + + FO_SetModel(newmis, "progs/spike.mdl"); + newmis.traileffectnum = particleeffectnum("spike_scan"); + + setsize(newmis, '0 0 0', '0 0 0'); + setorigin(newmis, self.owner.origin + v_forward * 8); + + switch (self.owner.team_no) + { + case TEAM_BLUE: + newmis.dimension_seen = DMN_TEAMBLUE; + break; + case TEAM_RED: + newmis.dimension_seen = DMN_TEAMRED; + break; + case TEAM_YELL: + newmis.dimension_seen = DMN_TEAMYELL; + break; + case TEAM_GREN: + newmis.dimension_seen = DMN_TEAMGREN; + break; + default: + newmis.dimension_seen = DMN_NOFLASH; + break; } - newmis.velocity = scanvec * 1000; + newmis.velocity = scanvec * 2000; newmis.angles = vectoangles(newmis.velocity); newmis.oldorigin = newmis.velocity; From 758cfa4efe42aaa6d2104243dcf31c1bcb01c7f5 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sun, 10 Oct 2021 22:44:57 +1100 Subject: [PATCH 1360/2474] Update client.qc --- ssqc/client.qc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index b87a55bc..cbd987de 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -531,8 +531,8 @@ void () DecodeLevelParms = { // Pyro Airblast pushval min and max airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); - airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); - airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); + airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "470"); + airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "600"); // enable spy invisibility [off] invis_only = CF_GetSetting("s", "spyinvis", "off"); @@ -828,9 +828,9 @@ void () DecodeLevelParms = { solid_detpack = FALSE; walls_block_emp = FALSE; solid_nailgren = FALSE; - scoutscanspike = TRUE; - airblastpushmin = 500; - airblastpushmax = 800; + scoutscanspike = TRUE; + airblastpushmin = 470; + airblastpushmax = 600; } st = infokey(world, "faithful"); From c17b97904f09ceea6f476f9864e1d3dd29441206 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sun, 10 Oct 2021 22:50:33 +1100 Subject: [PATCH 1361/2474] Cleanup --- ssqc/client.qc | 12 ------------ ssqc/world.qc | 1 - 2 files changed, 13 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index cbd987de..59283a57 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -578,18 +578,6 @@ void () DecodeLevelParms = { // configure max armor of heavy weapons guy [300] max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); - - // Scout Scanner spike on / off - scoutscanspike = CF_GetSetting("sss", "scoutscanspike", "on"); - - // HwGuy Assault Cannon Range default as 0 to disable, and die time once range hit. - asscanrange = CF_GetSetting("acr", "asscanrange", "0"); - asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); - - // Pyro Airblast pushval min and max - airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); - airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "470"); - airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "600"); // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); diff --git a/ssqc/world.qc b/ssqc/world.qc index 0a445719..65bc4afd 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -264,7 +264,6 @@ void () worldspawn = { precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); precache_model2(MODEL_PROJ_DIAM2); - precache_model2(MODEL_SPIKE_SCAN); precache_sound("grentimer.wav"); precache_sound("buttons/switch04.wav"); precache_sound("boss1/out1.wav"); From 9e045171d972f2ba041a2e5ab3b9a56da3beaa26 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sun, 10 Oct 2021 22:51:34 +1100 Subject: [PATCH 1362/2474] Update client.qc --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 59283a57..72be5145 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -816,7 +816,7 @@ void () DecodeLevelParms = { solid_detpack = FALSE; walls_block_emp = FALSE; solid_nailgren = FALSE; - scoutscanspike = TRUE; + scoutscanspike = TRUE; airblastpushmin = 470; airblastpushmax = 600; } From 2d3f8fbf96a8a290eb37fee8317620e0c2e00a1e Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sun, 10 Oct 2021 23:11:16 +1100 Subject: [PATCH 1363/2474] Update pyro.qc --- ssqc/pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 1a04f41a..5581f91a 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -883,7 +883,7 @@ void () UseAirBlastV2 = { self.velocity_z = 460; else { - self.velocity_z = self.velocity_z + 260; + self.velocity_z = self.velocity_z + 300; } } From 9245149b9f2e61744a8ebdeefef96cb2bf42c164 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Sun, 10 Oct 2021 23:55:01 +1100 Subject: [PATCH 1364/2474] Update pyro.qc --- ssqc/pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 5581f91a..db570eab 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -860,7 +860,7 @@ void () UseAirBlastV2 = { FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); makevectors(self.v_angle); entity ent; - float abrange = PC_PYRO_AIRBLAST_RANGE / 3; + float abrange = PC_PYRO_AIRBLAST_RANGE / 2; vector ab_start = self.origin + v_up * 20 + v_forward * 8; vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); vector ab_end = ab_start + aim(self,1000) * abrange; From 84da94b9a4a8b12767b144205170c9235d43e1f4 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 11 Oct 2021 10:54:01 +1100 Subject: [PATCH 1365/2474] Airblast jump feature flag serverinfo abj on // Off by default --- ssqc/client.qc | 1 + ssqc/pyro.qc | 2 +- ssqc/qw.qc | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 72be5145..d33de6f1 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -533,6 +533,7 @@ void () DecodeLevelParms = { airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "470"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "600"); + airblastjump = CF_GetSetting("abj", "airblastjump", "off"); // enable spy invisibility [off] invis_only = CF_GetSetting("s", "spyinvis", "off"); diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index db570eab..02b6f385 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -877,7 +877,7 @@ void () UseAirBlastV2 = { vector direction = self.v_angle; - if (direction_x > 60) + if (airblastjump && direction_x > 60) { if (self.flags & FL_ONGROUND) self.velocity_z = 460; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index b55423c7..febeccab 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -575,6 +575,7 @@ float asscanrangedie; float airblastv2; float airblastpushmin; float airblastpushmax; +float airblastjump; float old_spanner; float old_dispenser; From 1cecb70a0f116807af7d42b60a0cb052685dc9d0 Mon Sep 17 00:00:00 2001 From: driztf Date: Mon, 11 Oct 2021 02:10:16 +0000 Subject: [PATCH 1366/2474] default projection to off --- ssqc/client.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 260c4957..21ed413a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -568,8 +568,9 @@ void () DecodeLevelParms = { max_armor_hwguy = CF_GetSetting("mah", "max_armor_hwguy", ftos(PC_HVYWEAP_MAXARMOR)); // project projectile weapons by player ping - project_weapons = CF_GetSetting("pw", "project_weapons", "on"); + project_weapons = CF_GetSetting("pw", "project_weapons", "off"); + // max projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); // delay respawning by this many seconds [0] From 7c9996625dd972cf49d90a44c0cda40bc0f4d027 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 11 Oct 2021 17:55:37 +1100 Subject: [PATCH 1367/2474] Update pyro.qc --- ssqc/pyro.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 02b6f385..c30347a6 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -879,9 +879,9 @@ void () UseAirBlastV2 = { vector direction = self.v_angle; if (airblastjump && direction_x > 60) { - if (self.flags & FL_ONGROUND) + if ((airblastjump == 1 || airblastjump == 3) && self.flags & FL_ONGROUND) self.velocity_z = 460; - else + else if (airblastjump == 1 || airblastjump == 2) { self.velocity_z = self.velocity_z + 300; } From 5c126df580399d40209c14f5b1e4e35a5c0ac2a5 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 11 Oct 2021 22:48:26 +1100 Subject: [PATCH 1368/2474] More pyro airblast tweaks Now requiring ents to be within 75 units of the airblast trajectory - can be changed via serverinfo abs 150 // default. Also tweaked algorithm - missiles return via aim trajectory, everything else via the ab to ent trajectory --- ssqc/client.qc | 4 +++- ssqc/qw.qc | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index d33de6f1..b1fa01fd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -534,6 +534,7 @@ void () DecodeLevelParms = { airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "470"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "600"); airblastjump = CF_GetSetting("abj", "airblastjump", "off"); + airblastsize = CF_GetSetting("abs", "airblastsize", "150"); // enable spy invisibility [off] invis_only = CF_GetSetting("s", "spyinvis", "off"); @@ -820,6 +821,7 @@ void () DecodeLevelParms = { scoutscanspike = TRUE; airblastpushmin = 470; airblastpushmax = 600; + airblastsize = 150; } st = infokey(world, "faithful"); @@ -891,7 +893,7 @@ void () DecodeLevelParms = { solid_detpack = TRUE; walls_block_emp = FALSE; solid_nailgren = TRUE; - scoutscanspike = FALSE; + scoutscanspike = FALSE; } st = infokey(world, "huetf"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index febeccab..721a8f53 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -576,6 +576,7 @@ float airblastv2; float airblastpushmin; float airblastpushmax; float airblastjump; +float airblastsize; float old_spanner; float old_dispenser; From 8cc48bbf8ad7e7acbb66885fff2206b25aa7b89c Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 11 Oct 2021 22:53:52 +1100 Subject: [PATCH 1369/2474] Pyro tweaks Now requiring ents to be within 75 units of the airblast trajectory - can be changed via serverinfo abs 150 // default. Also tweaked algorithm - missiles return via aim trajectory, everything else via the ab to ent trajectory --- ssqc/pyro.qc | 92 +++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index c30347a6..6a5a82cf 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -863,7 +863,7 @@ void () UseAirBlastV2 = { float abrange = PC_PYRO_AIRBLAST_RANGE / 2; vector ab_start = self.origin + v_up * 20 + v_forward * 8; vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); - vector ab_end = ab_start + aim(self,1000) * abrange; + vector ab_diameter = ab_start + aim(self,1000) * abrange; pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); @@ -874,7 +874,6 @@ void () UseAirBlastV2 = { WriteCoord(MSG_MULTICAST, ab_origin_y); WriteCoord(MSG_MULTICAST, ab_origin_z); multicast(ab_origin, MULTICAST_PHS);*/ - vector direction = self.v_angle; if (airblastjump && direction_x > 60) @@ -890,49 +889,54 @@ void () UseAirBlastV2 = { ent = findradius(ab_origin, abrange); while (ent) { - if (ent.movetype != MOVETYPE_NONE && ent != self) - { - switch (ent.classname) - { - case "player": - case "pyro_rocket": - case "flamerflame": - case "proj_tranq": - case "proj_bullet": - case "proj_rocket": - case "grenade": - case "spike": - case "pipebomb": - vector targorg = ent.origin; - float pushval = airblastpushmax; - - vector delta = targorg - ab_start; - float dist = vlen(delta); - float scale = airblastpushmax - airblastpushmin; - float percent = (abrange - dist) / abrange; - - if (ent.classname != "pipebomb" && ent.velocity == '0 0 0') // Airblast non-moving ents, except for pipebombs - { - setorigin(ent, ent.origin + '0 0 1'); - ent.velocity = '0 0 150' + normalize(ent.origin - (self.origin - v_up * 28 )) * 400; - } - else if (ent.owner == self && ent.movetype != MOVETYPE_FLYMISSILE) // Fine tuning airblast of own items - assuming they are going forward here - { - if (percent <= 0.05) { pushval = airblastpushmin; } - else if (percent >= 0.50) { pushval = airblastpushmax; } - else { pushval = airblastpushmin + scale * percent; } - - ent.velocity = ent.velocity + pushval * aim(self,1000); //* pushval; - } - else // otherwise push in the direction of the aim - { - ent.velocity = vlen(ent.velocity) * aim(self,1000); - } - - break; - - } + { + vector diameter_pos = ab_start + aim(self,500) * vlen(ent.origin - ab_start); + float distfromdiameter = vlen(ent.origin - diameter_pos); + + if (distfromdiameter <= airblastsize / 2 && ent != self) + { + switch (ent.classname) + { + case "player": + case "pyro_rocket": + case "flamerflame": + case "proj_tranq": + case "proj_bullet": + case "proj_rocket": + case "grenade": + case "spike": + case "pipebomb": + vector targorg = ent.origin; + float pushval = airblastpushmax; + + vector delta = targorg - ab_start; + float dist = vlen(delta); + float scale = airblastpushmax - airblastpushmin; + float percent = (abrange - dist) / abrange; + + if (ent.classname != "pipebomb" && ent.velocity == '0 0 0') // Airblast non-moving ents, except for pipebombs + { + setorigin(ent, ent.origin + '0 0 1'); + ent.velocity = '0 0 150' + normalize(ent.origin - (self.origin - v_up * 28 )) * 400; + } + else if (ent.movetype == MOVETYPE_FLYMISSILE) // return missle at same speed in where aiming + { + ent.velocity = vlen(ent.velocity) * aim(self,1000); + } + else // All other trajectory is based on ab -> ent and velocity via pushval + { + if (percent <= 0.05) { pushval = airblastpushmin; } + else if (percent >= 0.50) { pushval = airblastpushmax; } + else { pushval = airblastpushmin + scale * percent; } + + ent.velocity = ent.velocity + pushval * normalize(ent.origin - ab_start); + } + + break; + + } + } } ent = ent.chain; From 4df6df20cfed880bb1890e41b7bc192be56af19a Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Mon, 11 Oct 2021 23:33:47 +1100 Subject: [PATCH 1370/2474] Update pyro.qc --- ssqc/pyro.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 6a5a82cf..6a730f8c 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -930,6 +930,10 @@ void () UseAirBlastV2 = { else if (percent >= 0.50) { pushval = airblastpushmax; } else { pushval = airblastpushmin + scale * percent; } + if (ent.owner != self) + { + ent.velocity = '0 0 0'; + } ent.velocity = ent.velocity + pushval * normalize(ent.origin - ab_start); } From fe2ac76814eb3c29d2dc7cece14eb46bc3206a7a Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 12 Oct 2021 12:51:45 +1100 Subject: [PATCH 1371/2474] Update pyro.qc --- ssqc/pyro.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 6a730f8c..545a516e 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -908,14 +908,13 @@ void () UseAirBlastV2 = { case "spike": case "pipebomb": vector targorg = ent.origin; - float pushval = airblastpushmax; - + float pushval = airblastpushmax; vector delta = targorg - ab_start; float dist = vlen(delta); float scale = airblastpushmax - airblastpushmin; float percent = (abrange - dist) / abrange; - if (ent.classname != "pipebomb" && ent.velocity == '0 0 0') // Airblast non-moving ents, except for pipebombs + if (ent.movetype != MOVETYPE_FLY && ent.classname != "pipebomb" && ent.velocity == '0 0 0') // Airblast non-moving ents, except for pipebombs { setorigin(ent, ent.origin + '0 0 1'); ent.velocity = '0 0 150' + normalize(ent.origin - (self.origin - v_up * 28 )) * 400; From 7a98465e561cee2d3bea557a0fb62db6331c3d44 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Tue, 12 Oct 2021 18:11:31 +1100 Subject: [PATCH 1372/2474] Update pyro.qc --- ssqc/pyro.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 545a516e..eeced0a1 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -879,10 +879,10 @@ void () UseAirBlastV2 = { if (airblastjump && direction_x > 60) { if ((airblastjump == 1 || airblastjump == 3) && self.flags & FL_ONGROUND) - self.velocity_z = 460; + self.velocity_z = 490; else if (airblastjump == 1 || airblastjump == 2) { - self.velocity_z = self.velocity_z + 300; + self.velocity_z = self.velocity_z + 260; } } From 87541f966b95537b2d00bbf3fbd237ecab03f255 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 13 Oct 2021 00:23:55 +1100 Subject: [PATCH 1373/2474] Finalised AB cell cost and particle on all fte clients --- share/defs.h | 4 ++++ ssqc/client.qc | 2 ++ ssqc/pyro.qc | 45 +++++++++++++++++++++++++++++++-------------- ssqc/qw.qc | 2 ++ 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/share/defs.h b/share/defs.h index 1d448aec..1213f0ea 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1063,6 +1063,8 @@ #define PC_PYRO_TF_ITEMS 0 #define PC_PYRO_AIRBLAST_RANGE 400 #define PC_PYRO_AIRBLAST_COOLDOWN 5 +#define PC_PYRO_AIRBLAST_CELLS 55 +#define PC_PYRO_AIRBLASTJUMP_CELLS 75 #define PC_PYRO_LAVA_LIFETIME 3 #define PC_PYRO_LAVA_RETICK 1.2 #define PC_PYRO_FLAMETHROWER_DAM_FO 15 @@ -1076,6 +1078,8 @@ #define PC_PYRO_BURN_MULTIPLIER_ORIG .3 #define PC_PYRO_BURN_MULTIPLIER_FO 1 #define PC_PYRO_BURN_DAMAGE_AMP 1.2 +#define PC_PYRO_BURN_DAMAGE_AMP 1.2 + // pyro types diff --git a/ssqc/client.qc b/ssqc/client.qc index b1fa01fd..81bd9600 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -535,6 +535,8 @@ void () DecodeLevelParms = { airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "600"); airblastjump = CF_GetSetting("abj", "airblastjump", "off"); airblastsize = CF_GetSetting("abs", "airblastsize", "150"); + airblastcells = CF_GetSetting("abc", "airblastcells", ftos(PC_PYRO_AIRBLAST_CELLS)); + airblastjumpcells = CF_GetSetting("abjc", "airblastjumpcells", ftos(PC_PYRO_AIRBLASTJUMP_CELLS)); // enable spy invisibility [off] invis_only = CF_GetSetting("s", "spyinvis", "off"); diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index eeced0a1..43225f5e 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -847,8 +847,20 @@ void () UseAirBlast = { }; void () UseAirBlastV2 = { - if (self.special_cooldown < time) + float isabjump = airblastjump && self.v_angle_x > 60; + + if (self.ammo_cells < airblastcells) + { + sprint(self, PRINT_HIGH, "Not enough cells to Airblast\n"); + } + else if (isabjump && airblastcells > 0 && self.ammo_cells < airblastjumpcells) { + sprint(self, PRINT_HIGH, "Not enough cells to Airblast jump\n"); + } + else if (self.special_cooldown < time) + { + float cellcost = airblastcells; + self.airblast_cooldown = 1; self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; entity timer = spawn(); @@ -864,20 +876,14 @@ void () UseAirBlastV2 = { vector ab_start = self.origin + v_up * 20 + v_forward * 8; vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); vector ab_diameter = ab_start + aim(self,1000) * abrange; - - pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); - - /* Work in progress - CSQC for FTE players only? - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, ab_origin_x); - WriteCoord(MSG_MULTICAST, ab_origin_y); - WriteCoord(MSG_MULTICAST, ab_origin_z); - multicast(ab_origin, MULTICAST_PHS);*/ - - vector direction = self.v_angle; - if (airblastjump && direction_x > 60) + + if (isabjump) { + if (airblastcells > 0 && airblastjumpcells > airblastcells) + { + cellcost = cellcost + airblastjumpcells - airblastcells; + } + if ((airblastjump == 1 || airblastjump == 3) && self.flags & FL_ONGROUND) self.velocity_z = 490; else if (airblastjump == 1 || airblastjump == 2) @@ -886,6 +892,9 @@ void () UseAirBlastV2 = { } } + self.ammo_cells = self.ammo_cells - cellcost; + W_SetCurrentAmmo(self); + ent = findradius(ab_origin, abrange); while (ent) { @@ -944,6 +953,14 @@ void () UseAirBlastV2 = { ent = ent.chain; } + + entity te = find(world, classname, "player") + while (te) + { + msg_entity = te; + pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); + te = find(te, classname, "player"); + } } else { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 721a8f53..135e4fe0 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -577,6 +577,8 @@ float airblastpushmin; float airblastpushmax; float airblastjump; float airblastsize; +float airblastcells; +float airblastjumpcells; float old_spanner; float old_dispenser; From 408ae29a84f07c468d831352d0636f8e022e2a54 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 13 Oct 2021 11:55:03 +1100 Subject: [PATCH 1374/2474] Update pyro.qc --- ssqc/pyro.qc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 43225f5e..889e9184 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -877,6 +877,8 @@ void () UseAirBlastV2 = { vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); vector ab_diameter = ab_start + aim(self,1000) * abrange; + pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); + if (isabjump) { if (airblastcells > 0 && airblastjumpcells > airblastcells) @@ -954,13 +956,6 @@ void () UseAirBlastV2 = { ent = ent.chain; } - entity te = find(world, classname, "player") - while (te) - { - msg_entity = te; - pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); - te = find(te, classname, "player"); - } } else { From 68ad6529d0f4cde3ea58c793c39835456a3bb7b5 Mon Sep 17 00:00:00 2001 From: driztf Date: Mon, 18 Oct 2021 18:55:45 +0000 Subject: [PATCH 1375/2474] Project ents using their velocity --- ssqc/antilag.qc | 15 +++++++-------- ssqc/engineer.qc | 2 +- ssqc/hwguy.qc | 2 +- ssqc/pyro.qc | 2 +- ssqc/spy.qc | 2 +- ssqc/weapons.qc | 6 +++--- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index f34794c2..636ebd8b 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,20 +1,19 @@ -void AL_ProjectProjectile (entity projectile, float velocity) { - // Project projectiles player ping forward in time based on ping up to a maximum of 150ms +void AL_ProjectProjectile (entity projectile) { + // Project projectiles forward in time based on ping up to configurable maximum (default 100ms). // Effective projection time is 75ms, because we assume RTT is evenly distributed in both // directions - and we want the server to spawn the entity in the position it would have // have been if it had received the message (player_ping / 2) ago. local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; - // Remove 13ms / 1 frame to keep behaviour consistent on low ping - player_ping_s = player_ping_s - (0.01298701298); // 1/77 + if (player_ping_s > project_weapons_max_latency) { player_ping_s = project_weapons_max_latency; - } else if (player_ping_s < 0.0013) { + } else if (player_ping_s <= 0.0013) { // Ping 13ms or lower? Don't do anything player_ping_s = 0; } - local float rocket_offset = (player_ping_s / 2) * velocity; - local vector projected_origin = newmis.origin + v_forward * (rocket_offset); - + local float time_offset = (player_ping_s / 2); + local vector projected_origin = newmis.origin + (newmis.velocity * time_offset); + // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED // because by tracing between old origin and projected origin we effectively have a single (last) frame diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 7d109c49..4630e718 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -110,7 +110,7 @@ void () W_FireLaser = { newmis.classname = "railslug"; if (project_weapons) { - AL_ProjectProjectile(newmis, PC_ENGINEER_RAILSPEED); + AL_ProjectProjectile(newmis); } }; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 1197253e..bb5efbf8 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -110,7 +110,7 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) newmis.avelocity = vecrand(100, 200, FALSE); if (project_weapons) { - AL_ProjectProjectile(newmis, proj_speed); + AL_ProjectProjectile(newmis); } } diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index e33c8d96..8f1f57ef 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -730,7 +730,7 @@ void () W_FireIncendiaryCannon = { setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); if (project_weapons) { - AL_ProjectProjectile(newmis, pyro_type == PYRO_FO ? PC_PYRO_NEW_PROJSPEED : PC_PYRO_OLD_PROJSPEED); + AL_ProjectProjectile(newmis); } }; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 468da369..6c0d1084 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1327,7 +1327,7 @@ void () W_FireTranq = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); if (project_weapons) { - AL_ProjectProjectile(newmis, PC_SPY_TRANQSPEED); + AL_ProjectProjectile(newmis); } }; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1f853e4a..32ab9e4f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1108,7 +1108,7 @@ void () W_FireRocket = { setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); if (project_weapons) { - AL_ProjectProjectile(newmis, PC_SOLDIER_ROCKET_SPEED); + AL_ProjectProjectile(newmis); } }; @@ -1325,7 +1325,7 @@ void () W_FireGrenade = { setorigin(newmis, self.origin); if (project_weapons) { - AL_ProjectProjectile(newmis, 600); + AL_ProjectProjectile(newmis); } }; @@ -1352,7 +1352,7 @@ void (vector org, vector dir) launch_spike = { newmis.velocity = dir * ng_velocity; if (project_weapons) { - AL_ProjectProjectile(newmis, ng_velocity); + AL_ProjectProjectile(newmis); } }; From 97c9f372247118688a2be671da7254e9ccfdf19a Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Wed, 20 Oct 2021 18:22:20 +1100 Subject: [PATCH 1376/2474] Remove precache for spike_scan.mdl --- share/defs.h | 2 -- ssqc/world.qc | 1 - 2 files changed, 3 deletions(-) diff --git a/share/defs.h b/share/defs.h index fc875727..49b0e80d 100644 --- a/share/defs.h +++ b/share/defs.h @@ -872,8 +872,6 @@ #define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range #define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector -#define MODEL_SPIKE_SCAN "progs/spike_scan.mdl" - // Class Details for SNIPER #define PC_SNIPER_SKIN 5 #define PC_SNIPER_MAXHEALTH 100 diff --git a/ssqc/world.qc b/ssqc/world.qc index 0a445719..65bc4afd 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -264,7 +264,6 @@ void () worldspawn = { precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); precache_model2(MODEL_PROJ_DIAM2); - precache_model2(MODEL_SPIKE_SCAN); precache_sound("grentimer.wav"); precache_sound("buttons/switch04.wav"); precache_sound("boss1/out1.wav"); From 8f8aad90188e282e696c79537015264717405b1b Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 21 Oct 2021 22:57:58 +1100 Subject: [PATCH 1377/2474] Update pyro.qc --- ssqc/pyro.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 5bb59a33..b5d610ab 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -949,7 +949,8 @@ void () UseAirBlastV2 = { { ent.velocity = '0 0 0'; } - ent.velocity = ent.velocity + pushval * normalize(ent.origin - ab_start); + //self.origin used to avoid downward trajectory + ent.velocity = ent.velocity + pushval * normalize(ent.origin - self.origin); } break; From 43b12532ea84c6c1a0cdc4093c12754d8131a2c3 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 21 Oct 2021 23:00:11 +1100 Subject: [PATCH 1378/2474] Update pyro.qc --- ssqc/pyro.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index b5d610ab..ab42a076 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -905,7 +905,7 @@ void () UseAirBlastV2 = { ent = findradius(ab_origin, abrange); while (ent) { - if (ent.movetype != MOVETYPE_NONE && ent != self) + if (ent.movetype != MOVETYPE_NONE && ent != self && CanDamage(ent,self)) { vector diameter_pos = ab_start + aim(self,500) * vlen(ent.origin - ab_start); float distfromdiameter = vlen(ent.origin - diameter_pos); From 1a80c09c5ad2b40dc29e93344a09a272ffef9bb4 Mon Sep 17 00:00:00 2001 From: driztf Date: Wed, 6 Oct 2021 22:26:27 +0000 Subject: [PATCH 1379/2474] Add distance based cuss duration option --- ssqc/client.qc | 4 ++++ ssqc/qw.qc | 1 + ssqc/scout.qc | 28 ++++++++++++++++++++++++++-- ssqc/tfort.qc | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 95026b72..b34f0faa 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -565,6 +565,9 @@ void () DecodeLevelParms = { // concussion grenade effect time [19] cussgrentime = CF_GetSetting("cgt", "cussgrentime", "19"); + // concussion grenade effect time proportional to distance from explosion + distance_based_cuss_duration = CF_GetSetting("dbcd", "distance_based_cuss_duration", "off"); + // medic immune to concussion grenade effects [on] medicnocuss = CF_GetSetting("mnc", "medicnocuss", "on"); @@ -935,6 +938,7 @@ void () DecodeLevelParms = { medicaura = FALSE; medicnocuss = FALSE; project_weapons = FALSE; + distance_based_cuss_duration = FALSE; pyro_type = 1; drop_grenades = FALSE; drop_grenpack = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 481c68f1..ff14aedc 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -563,6 +563,7 @@ float stock_reload; float classtips; float cussgrentime; float medicnocuss; +float distance_based_cuss_duration; float sniperpower; float sniperreloadpercent; float buildstatus; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index d37768c0..1ef2a762 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -808,6 +808,8 @@ void (entity inflictor, entity attacker, float bounce, void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce = { + local float actual_cuss_time = cussgrentime; + local float distance; local float points; local entity head; local entity te; @@ -818,11 +820,24 @@ void (entity inflictor, entity attacker, float bounce, if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs) * 0.5; - points = 0.5 * vlen(org - inflictor.origin); + distance = vlen(org - inflictor.origin); + points = 0.5 * distance; if (points < 0) points = 0; points = bounce - points; + if (distance_based_cuss_duration) { + // Actual cuss time based on distance from max explosion radius + local float fractional_distance = (1 - (distance / (bounce + 40))); + if (fractional_distance <= 1 && fractional_distance > 0.80) { + actual_cuss_time = cussgrentime; + } else if (fractional_distance <= 0.8 && fractional_distance > 0.2) { + actual_cuss_time = rint((1 - fractional_distance) * cussgrentime); + } else { + actual_cuss_time = rint(actual_cuss_time * 0.05); + } + } + if ((head.classname != "building_dispenser") && (head.classname != "building_sentrygun") && (head.classname != "building_sentrygun_base") @@ -848,6 +863,15 @@ void (entity inflictor, entity attacker, float bounce, } } + if (distance_based_cuss_duration + && ((head.playerclass == PC_MEDIC) || (head.playerclass == PC_SCOUT))) { + entity speedbump; + speedbump = spawn(); + speedbump.think = CussSpeedBump; + speedbump.nextthink = time + 1; + speedbump.owner = head; + } + te = find(world, classname, "timer"); if (old_grens == TRUE) while (((te.owner != head) || @@ -891,7 +915,7 @@ void (entity inflictor, entity attacker, float bounce, te.team_no = attacker.team_no; te.classname = "timer"; te.owner = head; - te.health = 40 * cussgrentime; + te.health = 40 * actual_cuss_time; self.owner.is_concussed = 1; } } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3a105811..df65071e 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -658,7 +658,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Pyro max grenades type 2 (napalm)", Role_None.gren2_limits[7], "", PC_PYRO_GRENADE_MAX_2); CF_PrintSetting("Spy max grenades type 2 (gas)", Role_None.gren2_limits[8], "", PC_SPY_GRENADE_MAX_2); CF_PrintSetting("Engineer max grenades type 2 (emp)", Role_None.gren2_limits[9], "", PC_ENGINEER_GRENADE_MAX_2); - + CF_PrintSetting("Distance based cuss", distance_based_cuss_duration, "", 1); sprint(self, PRINT_HIGH, "Concussion effect lasts "); sprint(self, PRINT_HIGH, ftos(cussgrentime)); sprint(self, PRINT_HIGH, " seconds"); From 34e7cdd0569eed461b29ed3eb789dfc8869df09d Mon Sep 17 00:00:00 2001 From: driztf Date: Tue, 2 Nov 2021 03:17:30 +0000 Subject: [PATCH 1380/2474] git pu --- README.md | 2 ++ antilag.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 antilag.md diff --git a/README.md b/README.md index a306e08c..2ecbb837 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,8 @@ New features * localinfo engineer_move / em : 0 - normal gameplay, 1: engineers can move while building [default: 1] * localinfo round_delay_time : interval time between rounds in quadmode - seconds [default: 30] * localinfo max_gren2_soldier : maximum number of active nail/shock grenades (TF 2.8 = 3, OzTF = 1) [default: 3] +* localinfo distance_based_cuss_duration : on/off - enables cuss duration to be proportional to the distance from the explosion [default: off] +* lag compensation: see antilag.md for more information == Removed === * Removed weapon messages for weapons without weapon modes. diff --git a/antilag.md b/antilag.md new file mode 100644 index 00000000..63301110 --- /dev/null +++ b/antilag.md @@ -0,0 +1,44 @@ +FortressOne Lag Compenstation +========= +FortressOne supports lag compensation to improve player experience when playing across continents or across oceans. + +tl;dr +-- +``` +rcon sv_antilag 1 +rcon localinfo project_weapons on +``` + +There are two types of lag compensation available, and these are configured at the server level. + +Hitscan weapons +--------------- +Enabled with: ```sv_antilag 1``` (default: 0) + +Hitscan weapons are weapons where an instant trace is emitted from the attacker in the direction they are shooting. In FortressOne, this means the shotgun and super-shotgun only. + +Hitscan weapons use a rollback mechanism based on antilag support in FTE. This means that players can aim using their crosshair without compensating for latency, as it would be if they were playing on a local server. + +To enable, set sv_antilag to 1. + +Projectile weapons + +------------------ + +- Enabled with: ```localinfo project_weapons on``` (default: off) +- Configurable: ```localinfo project_weapons_max_latency``` (default: 0.1) + +Projectile weapons are everything else. These are weapons which emit a projectile with a velocity that travel through space, eventually impacting on a player or the environment. +In FortressOne, projectiles can be fast-forwarded, or 'projected' forward based on the ping of the player shooting the rocket. This means that a player on a ping with 100ms will have their projectiles origin fast-forwarded to the point that they would have spawned if the player had zero latency. + +For example: +Rockets travel at 900units / second. + +A player with 0ms ping has the rocket launcher out and clicks the shoot. The server immediately receives the message and spawns the rocket. 500ms after clicking the shoot button, the rocket will be 450units away from the player. + +A player with a 100ms ping has the rocket launcher out and clicks to shoot. The server receives the message 50ms later. Without projectile fast-forwarding, after 500ms since clicking the shoot button, the projectile will be only 405units away from the player after the button was clicked - it has only had 450ms of existence and therefore 450ms of travel time. + +With project_weapons turned on, FortressOne will calculate where the rocket would be if it was spawned 50ms ago (in this case 45 units from player), and then regular handling of projectile motion takes over. + +This means that 500ms from the player clicking the shoot button, the rocket is 45 units (spawn position) + 405 (450ms * 900) units from the player position - 450 - ie, the same position had the player had 0 ping. + From 8fa23ce48b859d950787fff9572b43db4370834b Mon Sep 17 00:00:00 2001 From: me Date: Mon, 15 Nov 2021 21:54:56 +1300 Subject: [PATCH 1381/2474] nextmap command --- ssqc/client.qc | 10 ++++++---- ssqc/commands.qc | 4 ++++ ssqc/mvdsv.qc | 4 ++++ ssqc/tforthlp.qc | 2 ++ ssqc/vote.qc | 35 +++++++++++++++++++++++++++++++++-- ssqc/world.qc | 9 +++++---- 6 files changed, 54 insertions(+), 10 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 238d89d4..234f8b46 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -245,8 +245,10 @@ void () DecodeLevelParms = { if (coop || !deathmatch) toggleflags = toggleflags | TFLAG_CLASS_PERSIST; - nextmap = strzone(mapname); - + if(nextmap == "") { + nextmap = strzone(mapname); + } + ent = find(world, classname, "info_tfdetect"); if (ent != world) { @@ -1149,7 +1151,7 @@ void () execute_changelevel = { // nextmapstring = strcat(vote_result, " \b(voting)\b"); //} } - if(vote_result != string_null && vote_result != "") { + if(vote_result != string_null && vote_result != "" && vote_result != mapname) { nextmapstring = vote_result; nextmap = vote_result; } @@ -2149,7 +2151,7 @@ void () NextLevel = { localcmd ("localinfo votemode on\n"); } //changelevel(FO_GetUserSettingString(world, "vote_map", "votemap", "se2")); - } else { + } else if (nextmap == "" || nextmap == string_null) { nextmap = mapname; } } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index e32a95d1..1e7b3a2a 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -813,6 +813,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } } break; + case "voteyes": + processedCmd = TRUE; + VoteYes(self); + break; case "captainpick": processedCmd = TRUE; if(arg2) { diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index 21a36421..7bd510ad 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -28,6 +28,10 @@ float (string cmd) ConsoleCmd { case "vote_removemap": RemoveVoteMap(argv(1)); return TRUE; + case "nextmap": + nextmap = argv(1); + bprint(PRINT_HIGH, "Next map set to ", nextmap, "\n"); + return TRUE; } } else { //MVDSV implementation diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 59e3a32b..8950af75 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -260,6 +260,8 @@ void () TeamFortress_MOTD = { TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo TeamFortress_AliasString("break", "cmd break"); + TeamFortress_AliasString("voteyes", "cmd voteyes"); + TeamFortress_AliasString("yes", "cmd voteyes"); Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) diff --git a/ssqc/vote.qc b/ssqc/vote.qc index b35ec7c7..0edd71fd 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1504,8 +1504,10 @@ void (entity p) VoteToEndMap = { if(numvoted > (numplayers * vote_threshold)) { sound(self, CHAN_AUTO, "boss1/out1.wav", 1, ATTN_NONE); bprint(PRINT_HIGH, "\bMap ended by majority vote.\b.\n"); - vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); - votemode = 2; + if(nextmap == "") { + vote_result = FO_GetUserSettingString(world, "vote_map", "votemap", "se2"); + votemode = 2; + } execute_changelevel(); } else { sound(self, CHAN_AUTO, "misc/secret.wav", 1, ATTN_NONE); @@ -1515,6 +1517,35 @@ void (entity p) VoteToEndMap = { } }; +void (entity p) VoteYes = { + if(!voting_started) { + sprint(p, PRINT_HIGH, "No suggestions so far.\n"); + return; + } + if(p.vote_map) { + sprint(p, PRINT_HIGH, "You've already voted for (", p.vote_map.netname, ")!\n"); + return; + } + + local entity mc = find(world, classname, "map_candidate"); + local entity mc2 = world; + local float count = 0; + while(mc) { + if(mc.cnt > 0) { + count++; + mc2 = mc; + } + mc = find(mc, classname, "map_candidate"); + } + if(count > 1) { + sprint(p, PRINT_HIGH, "There are multiple suggestions. Use 'cmd votemap' to vote!\n"); + return; + } + if(count == 1) { + VoteForMap(p, mc2.netname); + } +} + entity (float index) Vote_Menu_Map_GetMapCandidate = { local float count = 1; local entity mc = find(world, classname, "map_candidate"); diff --git a/ssqc/world.qc b/ssqc/world.qc index dfb5eedb..d47d1fbd 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -88,6 +88,7 @@ void () worldspawn = { WriteByte(MSG_INIT, 9/*svc_stufftext*/); WriteString(MSG_INIT, "set fo_serverscripts 1\n"); + vote_started = -1; local string st; lastspawn = world; @@ -333,10 +334,10 @@ void () StartFrame = { fraglimit = cvar("fraglimit"); deathmatch = cvar("deathmatch"); framecount = framecount + 1; - if(!votemode) { - //TODO: make this optional - Vote_Check(); - } +// if(!votemode) { +// //TODO: make this optional +// Vote_Check(); +// } }; entity bodyque_head; From 2db8851c4049d7a6a31017382612de0e4aa0d135 Mon Sep 17 00:00:00 2001 From: lordee Date: Sat, 20 Nov 2021 14:59:13 +1100 Subject: [PATCH 1382/2474] remove autohop, keep aux jump so we don't break anything --- README.md | 1 - csqc/csextradefs.qc | 2 -- csqc/main.qc | 26 ++------------------------ csqc/settings.qc | 7 +------ menu/options_basic.qc | 1 - 5 files changed, 3 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 2ecbb837..a01b8b6e 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ New features * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press -* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+aux_jump` to use with rj scripts) * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index aa54553b..28c60942 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -93,7 +93,6 @@ float round_time_remaining; float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown -float jump_counter; float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; @@ -513,7 +512,6 @@ enum { }; #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" -#define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" #define FOCMD_FTE_HUD "fo_fte_hud" diff --git a/csqc/main.qc b/csqc/main.qc index 8dd92e77..f7a9986e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -36,7 +36,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_hud_save"); registercommand("fo_hud_load"); - registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); registercvar(FOCMD_OLDSCOREBOARD, "0"); registercvar(FOCMD_FTE_HUD, "0"); @@ -81,7 +80,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { player_menu_type = 0; is_admin = FALSE; grentimer_waiting = FALSE; - jump_counter = 0; num_mapvotes = 0; vote_selected_item = world; vote_selected_index = -1; @@ -312,15 +310,10 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd tracktarget\n"); break; case "+aux_jump": - jump_counter = jump_counter + 1; localcmd("+jump"); break; case "-aux_jump": - jump_counter = jump_counter - 1; - if (jump_counter <= 0) { - jump_counter = 0; - localcmd("-jump"); - } + localcmd("-jump"); break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -352,22 +345,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { - if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2 && getstatf(STAT_HEALTH) > 0) { - if (pmove_onground) { - frames_since_onground = 0; - } else { - - // next two frames after leaving ground - if (frames_since_onground <= 2) { - frames_since_onground = frames_since_onground + 1; - - // third frame after leaving ground - } else if (frames_since_onground == 3) { - input_buttons &= ~2; - frames_since_onground = frames_since_onground + 1; - } - } - } + } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { diff --git a/csqc/settings.qc b/csqc/settings.qc index 049cd25b..d70147f8 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,8 +3,7 @@ void FO_WriteSettings() // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", FOCMD_AUTOHOP, ftos(cvar(FOCMD_AUTOHOP))); - line = FormatCfgString(line, FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); + string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(cvar(FOCMD_OLDSCOREBOARD))); fputs(filehandle, line); fclose(filehandle); @@ -12,7 +11,6 @@ void FO_WriteSettings() void FO_LoadDefaultSettings() { - cvar_set(FOCMD_AUTOHOP, "0"); cvar_set(FOCMD_GRENTIMER, "1"); cvar_set(FOCMD_OLDSCOREBOARD, "0"); } @@ -43,9 +41,6 @@ void FO_LoadSettings() switch(field) { - case FOCMD_AUTOHOP: - cvar_set(FOCMD_AUTOHOP, val); - break; case FOCMD_GRENTIMER: cvar_set(FOCMD_GRENTIMER, val); break; diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 286dfc53..c2dc1793 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -148,7 +148,6 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = /* "1 \"Server\" " */ /* "2 \"Immediate\" " */ /* )), fl, [0, pos], [0, 8]); pos += 8; */ - /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; From 3b84ae449a9529df5b88ca6f871c3109f8889e4d Mon Sep 17 00:00:00 2001 From: lordee Date: Sat, 20 Nov 2021 15:04:34 +1100 Subject: [PATCH 1383/2474] remove autohop, keep aux jump so we don't break anything --- README.md | 1 - csqc/csextradefs.qc | 2 -- csqc/main.qc | 24 +----------------------- csqc/settings.qc | 7 +------ menu/options_basic.qc | 1 - 5 files changed, 2 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index a306e08c..84a878e0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ New features * CSQC - fo_main_menu main menu - either from menu.dat or engine * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press -* CSQC - fo_autohop 0/1 enable bunnyhop assist (use `+aux_jump` to use with rj scripts) * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e93669a1..7b83bd44 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -92,7 +92,6 @@ float round_over; float showingscores; float mapvote_expiry; float grentimer_waiting; //grenade primed, but not thrown -float jump_counter; float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; @@ -469,7 +468,6 @@ enum { }; #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" -#define FOCMD_AUTOHOP "fo_autohop" #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" diff --git a/csqc/main.qc b/csqc/main.qc index 07acfb28..956807f0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -30,7 +30,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_hud"); registercommand("fo_hud_save"); - registercvar(FOCMD_AUTOHOP, "0"); registercvar(FOCMD_GRENTIMER, "1"); registercvar(FOCMD_OLDSCOREBOARD, "0"); @@ -72,7 +71,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { player_menu_type = 0; is_admin = FALSE; grentimer_waiting = FALSE; - jump_counter = 0; num_mapvotes = 0; vote_selected_item = world; vote_selected_index = -1; @@ -318,15 +316,10 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd tracktarget\n"); break; case "+aux_jump": - jump_counter = jump_counter + 1; localcmd("+jump"); break; case "-aux_jump": - jump_counter = jump_counter - 1; - if (jump_counter <= 0) { - jump_counter = 0; - localcmd("-jump"); - } + localcmd("-jump"); break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -358,22 +351,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { - if (cvar(FOCMD_AUTOHOP) == 1 && input_buttons&2 && getstatf(STAT_HEALTH) > 0) { - if (pmove_onground) { - frames_since_onground = 0; - } else { - - // next two frames after leaving ground - if (frames_since_onground <= 2) { - frames_since_onground = frames_since_onground + 1; - // third frame after leaving ground - } else if (frames_since_onground == 3) { - input_buttons &= ~2; - frames_since_onground = frames_since_onground + 1; - } - } - } } void CSQC_Shutdown() = { diff --git a/csqc/settings.qc b/csqc/settings.qc index 049cd25b..d70147f8 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,8 +3,7 @@ void FO_WriteSettings() // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", FOCMD_AUTOHOP, ftos(cvar(FOCMD_AUTOHOP))); - line = FormatCfgString(line, FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); + string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(cvar(FOCMD_OLDSCOREBOARD))); fputs(filehandle, line); fclose(filehandle); @@ -12,7 +11,6 @@ void FO_WriteSettings() void FO_LoadDefaultSettings() { - cvar_set(FOCMD_AUTOHOP, "0"); cvar_set(FOCMD_GRENTIMER, "1"); cvar_set(FOCMD_OLDSCOREBOARD, "0"); } @@ -43,9 +41,6 @@ void FO_LoadSettings() switch(field) { - case FOCMD_AUTOHOP: - cvar_set(FOCMD_AUTOHOP, val); - break; case FOCMD_GRENTIMER: cvar_set(FOCMD_GRENTIMER, val); break; diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 286dfc53..c2dc1793 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -148,7 +148,6 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = /* "1 \"Server\" " */ /* "2 \"Immediate\" " */ /* )), fl, [0, pos], [0, 8]); pos += 8; */ - /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; From 3274c0573871bba54fb4a80358a0568c72151897 Mon Sep 17 00:00:00 2001 From: driztf Date: Sat, 15 Jan 2022 23:38:13 +0000 Subject: [PATCH 1384/2474] fix use of newmis and old comment --- ssqc/antilag.qc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 636ebd8b..80831003 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,6 +1,6 @@ void AL_ProjectProjectile (entity projectile) { // Project projectiles forward in time based on ping up to configurable maximum (default 100ms). - // Effective projection time is 75ms, because we assume RTT is evenly distributed in both + // Effective projection time is maximum / 2 (eg 50ms), because we assume RTT is evenly distributed in both // directions - and we want the server to spawn the entity in the position it would have // have been if it had received the message (player_ping / 2) ago. local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; @@ -8,22 +8,22 @@ void AL_ProjectProjectile (entity projectile) { if (player_ping_s > project_weapons_max_latency) { player_ping_s = project_weapons_max_latency; } else if (player_ping_s <= 0.0013) { // Ping 13ms or lower? Don't do anything - player_ping_s = 0; + return; } - local float time_offset = (player_ping_s / 2); - local vector projected_origin = newmis.origin + (newmis.velocity * time_offset); + local float time_offset = (player_ping_s / 2); + local vector projected_origin = projectile.origin + (projectile.velocity * time_offset); // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED // because by tracing between old origin and projected origin we effectively have a single (last) frame // rewind at the projected origin. The effect is high ping players are disadvantaged in close combat. // This is preferable to unhappy low ping players. - traceline(newmis.origin, projected_origin, 0, self); + traceline(projectile.origin, projected_origin, 0, self); if (trace_fraction < 1) { projected_origin = trace_endpos; } - setorigin(newmis, projected_origin); + setorigin(projectile, projected_origin); } \ No newline at end of file From 190064eeb5c4f27847ca6bfba32215996fec54e6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 20 Jan 2022 01:15:25 +1100 Subject: [PATCH 1385/2474] Fix overlapping hud grens --- csqc/hud.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index ed27ebca..6245acc8 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -91,7 +91,7 @@ void FO_Hud_Editor_LoadDefaultSettings() Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height - 100]; Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) + 16, height - 50]; Hud_Panels[HUD_PANEL_CLIPSIZE].Scale = 0.75; - Hud_Panels[HUD_PANEL_GREN1].Position = [(width / 2) - 16 - (Hud_Panels[HUD_PANEL_GREN1].FillSize.x * 2), height - 50]; + Hud_Panels[HUD_PANEL_GREN1].Position = [(width / 2) - 16 - (Hud_Panels[HUD_PANEL_GREN1].FillSize.x * 3), height - 50]; Hud_Panels[HUD_PANEL_GREN1].Scale = 0.75; Hud_Panels[HUD_PANEL_GREN2].Position = [(width / 2) - 16 - Hud_Panels[HUD_PANEL_GREN2].FillSize.x * 0.75, height - 50]; Hud_Panels[HUD_PANEL_GREN2].Scale = 0.75; From 2f7dfe7c753366fa54d6e67a19d85fe54d5b16b2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 29 Jan 2022 19:43:50 +1100 Subject: [PATCH 1386/2474] Don't send server gren commands if no grens --- csqc/main.qc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 21e24448..dd24da97 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -368,14 +368,19 @@ void PrimeGren(float gren_number) { } void PrimeOrThrowGren(float gren_number) { + if !(IsValidToUseGrenades()) + return; + + if (RemainingGrenades(gren_number) <= 0 && !grentimer_waiting) { + print("No grenades left\n"); + return; + } + ShowGrenadeTimer(gren_number); localcmd(strcat("gren", ftos(gren_number), "_server")); } void ShowGrenadeTimer(float gren_number) { - if !(IsValidToUseGrenades()) - return; - if (!grentimer_waiting && RemainingGrenades(gren_number)) { grentimer_waiting = TRUE; localcmd(sprintf("play %s\n", cvar_string(FOCMD_GRENTIMERSOUND))); From 416fcfd1c43b453e958d663a6d6d4c9065d81b9f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 29 Jan 2022 20:13:29 +1100 Subject: [PATCH 1387/2474] Don't send server request for priming gren if none in hand --- csqc/main.qc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index dd24da97..453cdaaa 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -363,6 +363,14 @@ void CSQC_Shutdown() = { } void PrimeGren(float gren_number) { + if !(IsValidToUseGrenades()) + return; + + if (RemainingGrenades(gren_number) <= 0) { + print("No grenades left\n"); + return; + } + ShowGrenadeTimer(gren_number); localcmd(strcat("prime", ftos(gren_number), "_server")); } From 6a9bf614208d39566a53e63be36314184d29ebc6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 30 Jan 2022 02:17:53 +1100 Subject: [PATCH 1388/2474] Stop gren timer sound on death --- csqc/csdefs.qc | 6 ++++++ csqc/main.qc | 23 +++++++++++++++++++++-- share/defs.h | 2 ++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 265abdb7..ee8ee14c 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -477,6 +477,12 @@ void(entity e, float chan, string samp, float vol, float atten, optional float s if specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed. flags&1 means the sound should be sent reliably. */ +void(string soundname, optional float channel, optional float volume) localsound = #177; /* + Plays a sound... locally... probably best not to call this from ssqc. Also disables reverb. */ + +float(entity e, float channel, string newsample, float volume, float attenuation, float pitchpct, float flags, float timeoffset) soundupdate = #0:soundupdate; /* + Changes the properties of the current sound being played on the given entity channel. newsample may be empty, and will be ignored in this case. timeoffset is relative to the current position (subtract the result of getsoundtime for absolute positions). Negative volume can be used to stop the sound. Return value is a fractional value based upon the number of audio devices that could be updated - test against TRUE rather than non-zero. */ + vector(vector v) normalize = #9; /* Shorten or lengthen a direction vector such that it is only one quake unit long. */ diff --git a/csqc/main.qc b/csqc/main.qc index 453cdaaa..bcf5c759 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -119,12 +119,15 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { //stop grentimer on death if(getstatf(STAT_HEALTH) <= 0) { - //localcmd("stopsound\n"); + soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); + soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { FO_Hud_Grentimers[i].grentype = 0; FO_Hud_Grentimers[i].expires = 0; FO_Hud_Grentimers[i].icon_index = 0; } + } clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! @@ -391,7 +394,23 @@ void PrimeOrThrowGren(float gren_number) { void ShowGrenadeTimer(float gren_number) { if (!grentimer_waiting && RemainingGrenades(gren_number)) { grentimer_waiting = TRUE; - localcmd(sprintf("play %s\n", cvar_string(FOCMD_GRENTIMERSOUND))); + + local float grentimer_channel; + local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); + local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); + + if (chan_gren1_soundtime == -1 ) { + grentimer_channel = CHAN_GREN1; + } else if (chan_gren2_soundtime == -1 ) { + grentimer_channel = CHAN_GREN2; + } else if (chan_gren1_soundtime > chan_gren2_soundtime) { + grentimer_channel = CHAN_GREN1; + } else { + grentimer_channel = CHAN_GREN2; + } + + localsound(cvar_string(FOCMD_GRENTIMERSOUND), grentimer_channel, 1); + local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); AddGrenTimer(grentype); } diff --git a/share/defs.h b/share/defs.h index 49b0e80d..fd00139f 100644 --- a/share/defs.h +++ b/share/defs.h @@ -173,6 +173,8 @@ #define CHAN_VOICE 2 #define CHAN_ITEM 3 #define CHAN_BODY 4 +#define CHAN_GREN1 5 +#define CHAN_GREN2 6 #define CHAN_NO_PHS_ADD 8 #define ATTN_NONE 0 From fb29ea4b1265d31026ff6522e3fc9e86b235d6fd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 30 Jan 2022 10:01:21 +1100 Subject: [PATCH 1389/2474] Add a few defs for consistency --- csqc/csdefs.qc | 2 ++ share/fteextensions.qc | 3 +++ 2 files changed, 5 insertions(+) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index ee8ee14c..87c3be3d 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -239,6 +239,8 @@ const float CHAN_WEAPON = 1; const float CHAN_VOICE = 2; const float CHAN_ITEM = 3; const float CHAN_BODY = 4; +const float CHAN_GREN1 = 5; +const float CHAN_GREN2 = 6; const float ATTN_NONE = 0; /* Sounds with this attenuation can be heard throughout the map */ const float ATTN_NORM = 1; /* Standard attenuation */ const float ATTN_IDLE = 2; /* Extra attenuation so that sounds don't travel too far. */ diff --git a/share/fteextensions.qc b/share/fteextensions.qc index ba76135f..1fc9bcec 100644 --- a/share/fteextensions.qc +++ b/share/fteextensions.qc @@ -841,6 +841,9 @@ const float CHAN_WEAPON = 1; const float CHAN_VOICE = 2; const float CHAN_ITEM = 3; const float CHAN_BODY = 4; +const float CHAN_GREN1 = 5; +const float CHAN_GREN2 = 6; + #endif #if defined(QWSSQC) const float CHANF_RELIABLE = 8; /* Only valid if the flags argument is not specified. The sound will be sent reliably, which is important if it is intended to replace looping sounds on doors etc. */ From 13acc9a453d9c9df022e7d3b91dca361fecdecc2 Mon Sep 17 00:00:00 2001 From: me Date: Sun, 30 Jan 2022 14:51:23 +1300 Subject: [PATCH 1390/2474] Lessen the confusion --- README.md | 1 + ssqc/mvdsv.qc | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 641cac1c..c7a5afe2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* Added ``localinfo nomapcycle 1`` to stop all the confusion. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. * ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above ```` into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of ```` (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set values for each class. ``localinfo nokeepcells 1`` - disables keepcells server-wide * option to let engineer move while building `localinfo em on`. diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index 7bd510ad..677f6fe7 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -29,8 +29,12 @@ float (string cmd) ConsoleCmd { RemoveVoteMap(argv(1)); return TRUE; case "nextmap": - nextmap = argv(1); - bprint(PRINT_HIGH, "Next map set to ", nextmap, "\n"); + if(infokey (world, "nomapcycle")) { + bprint(PRINT_HIGH, "Tried setting next map to ", nextmap, ", but nomapcycle is set.\n"); + } else { + nextmap = argv(1); + bprint(PRINT_HIGH, "Next map set to ", nextmap, ". Enable nomapcycle to skip.\n"); + } return TRUE; } } else { From 1803bfbffad6f25405d48a1a9fe8ee611cf8f4f4 Mon Sep 17 00:00:00 2001 From: me Date: Sun, 30 Jan 2022 15:05:23 +1300 Subject: [PATCH 1391/2474] fix variable types --- ssqc/mvdsv.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index 677f6fe7..de692b13 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -29,8 +29,9 @@ float (string cmd) ConsoleCmd { RemoveVoteMap(argv(1)); return TRUE; case "nextmap": - if(infokey (world, "nomapcycle")) { - bprint(PRINT_HIGH, "Tried setting next map to ", nextmap, ", but nomapcycle is set.\n"); + bprint(PRINT_HIGH, "Hmm: ", ftos(FO_GetUserSetting (world, "nomapcycle", "nmc", "0")), "\n"); //MEHT + if(FO_GetUserSetting (world, "nomapcycle", "nmc", "0")) { + bprint(PRINT_HIGH, "Tried setting next map to ", argv(1), ", but nomapcycle is set.\n"); } else { nextmap = argv(1); bprint(PRINT_HIGH, "Next map set to ", nextmap, ". Enable nomapcycle to skip.\n"); From b4541efef415f90a662c0926ed3d8858de3d3035 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 30 Jan 2022 14:01:06 +1100 Subject: [PATCH 1392/2474] Add sound when no grens left --- csqc/main.qc | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index bcf5c759..71e3890e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -370,6 +370,7 @@ void PrimeGren(float gren_number) { return; if (RemainingGrenades(gren_number) <= 0) { + localsound("error.wav", CHAN_AUTO, 1); print("No grenades left\n"); return; } @@ -383,6 +384,7 @@ void PrimeOrThrowGren(float gren_number) { return; if (RemainingGrenades(gren_number) <= 0 && !grentimer_waiting) { + localsound("error.wav", CHAN_AUTO, 1); print("No grenades left\n"); return; } @@ -392,28 +394,29 @@ void PrimeOrThrowGren(float gren_number) { } void ShowGrenadeTimer(float gren_number) { - if (!grentimer_waiting && RemainingGrenades(gren_number)) { - grentimer_waiting = TRUE; - - local float grentimer_channel; - local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); - local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); - - if (chan_gren1_soundtime == -1 ) { - grentimer_channel = CHAN_GREN1; - } else if (chan_gren2_soundtime == -1 ) { - grentimer_channel = CHAN_GREN2; - } else if (chan_gren1_soundtime > chan_gren2_soundtime) { - grentimer_channel = CHAN_GREN1; - } else { - grentimer_channel = CHAN_GREN2; - } + if (grentimer_waiting || !RemainingGrenades(gren_number)) + return; + + grentimer_waiting = TRUE; - localsound(cvar_string(FOCMD_GRENTIMERSOUND), grentimer_channel, 1); + local float grentimer_channel; + local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); + local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); - local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); - AddGrenTimer(grentype); + if (chan_gren1_soundtime == -1 ) { + grentimer_channel = CHAN_GREN1; + } else if (chan_gren2_soundtime == -1 ) { + grentimer_channel = CHAN_GREN2; + } else if (chan_gren1_soundtime > chan_gren2_soundtime) { + grentimer_channel = CHAN_GREN1; + } else { + grentimer_channel = CHAN_GREN2; } + + localsound(cvar_string(FOCMD_GRENTIMERSOUND), grentimer_channel, 1); + + local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); + AddGrenTimer(grentype); } float RemainingGrenades(float gren_number) { From 170fa1a43c0f01f69d4a411c3e452957bfcfcce2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 30 Jan 2022 20:09:36 +1100 Subject: [PATCH 1393/2474] Fix broken primeone / gren1 commands for people using fo_grentimer 1 --- csqc/main.qc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 71e3890e..f5357f5d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -366,6 +366,11 @@ void CSQC_Shutdown() = { } void PrimeGren(float gren_number) { + if (cvar(FOCMD_GRENTIMER) != 2) { + localcmd(strcat("gren", ftos(gren_number), "_server")); + return; + } + if !(IsValidToUseGrenades()) return; @@ -380,6 +385,11 @@ void PrimeGren(float gren_number) { } void PrimeOrThrowGren(float gren_number) { + if (cvar(FOCMD_GRENTIMER) != 2) { + localcmd(strcat("gren", ftos(gren_number), "_server")); + return; + } + if !(IsValidToUseGrenades()) return; @@ -394,9 +404,6 @@ void PrimeOrThrowGren(float gren_number) { } void ShowGrenadeTimer(float gren_number) { - if (grentimer_waiting || !RemainingGrenades(gren_number)) - return; - grentimer_waiting = TRUE; local float grentimer_channel; @@ -429,9 +436,6 @@ float RemainingGrenades(float gren_number) { } float IsValidToUseGrenades() { - if (cvar(FOCMD_GRENTIMER) != 2) - return FALSE; - if (prematch) return FALSE; From 982830dab628e12b3d049703e54682843109a950 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 31 Jan 2022 00:01:09 +1100 Subject: [PATCH 1394/2474] Fix some bad logic --- csqc/main.qc | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index f5357f5d..1fa1dfd2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -366,40 +366,38 @@ void CSQC_Shutdown() = { } void PrimeGren(float gren_number) { - if (cvar(FOCMD_GRENTIMER) != 2) { - localcmd(strcat("gren", ftos(gren_number), "_server")); - return; - } + if (cvar(FOCMD_GRENTIMER) == 2) { + if !(IsValidToUseGrenades()) + return; - if !(IsValidToUseGrenades()) - return; + if (RemainingGrenades(gren_number) <= 0) { + localsound("error.wav", CHAN_AUTO, 1); + print("No grenades left\n"); + return; + } - if (RemainingGrenades(gren_number) <= 0) { - localsound("error.wav", CHAN_AUTO, 1); - print("No grenades left\n"); - return; + if (!grentimer_waiting) + ShowGrenadeTimer(gren_number); } - ShowGrenadeTimer(gren_number); localcmd(strcat("prime", ftos(gren_number), "_server")); } void PrimeOrThrowGren(float gren_number) { - if (cvar(FOCMD_GRENTIMER) != 2) { - localcmd(strcat("gren", ftos(gren_number), "_server")); - return; - } + if (cvar(FOCMD_GRENTIMER) == 2) { + if (!IsValidToUseGrenades()) + return; - if !(IsValidToUseGrenades()) - return; + if (RemainingGrenades(gren_number) <= 0 && !grentimer_waiting) { + localsound("error.wav", CHAN_AUTO, 1); + print("No grenades left\n"); + return; + } - if (RemainingGrenades(gren_number) <= 0 && !grentimer_waiting) { - localsound("error.wav", CHAN_AUTO, 1); - print("No grenades left\n"); - return; + if (!grentimer_waiting) + ShowGrenadeTimer(gren_number); } - ShowGrenadeTimer(gren_number); localcmd(strcat("gren", ftos(gren_number), "_server")); } From 65e41fe3fb7bf3bba5774882704f56f15747ac3d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 3 Feb 2022 23:44:37 +1100 Subject: [PATCH 1395/2474] Try to fix very occasional sticky grens --- csqc/main.qc | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1fa1dfd2..2783be78 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -384,21 +384,39 @@ void PrimeGren(float gren_number) { } void PrimeOrThrowGren(float gren_number) { - if (cvar(FOCMD_GRENTIMER) == 2) { - if (!IsValidToUseGrenades()) - return; + if (cvar(FOCMD_GRENTIMER) != 2) { + localcmd(strcat("gren", ftos(gren_number), "_server")); + return; + } - if (RemainingGrenades(gren_number) <= 0 && !grentimer_waiting) { - localsound("error.wav", CHAN_AUTO, 1); - print("No grenades left\n"); - return; - } + if (!IsValidToUseGrenades()) + return; - if (!grentimer_waiting) - ShowGrenadeTimer(gren_number); + if (grentimer_waiting) { + localcmd(strcat("throwgren")); + return; + } + + if (RemainingGrenades(gren_number) <= 0) { + localsound("error.wav", CHAN_AUTO, 1); + print("No grenades left\n"); + return; + } + + ShowGrenadeTimer(gren_number); + + local string cmd; + + switch(gren_number) { + case 1: + cmd = "primeone"; + break; + case 2: + cmd = "primetwo"; + break; } - localcmd(strcat("gren", ftos(gren_number), "_server")); + localcmd(strcat(cmd)); } void ShowGrenadeTimer(float gren_number) { From f9c7139561ec4fd397ba3a1d0c09bd4d7a56d4dd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 4 Feb 2022 01:02:11 +1100 Subject: [PATCH 1396/2474] Add transparency to thrown grenades --- csqc/csextradefs.qc | 1 + csqc/hud_helpers.qc | 6 ++++-- csqc/main.qc | 8 ++++++++ csqc/status.qc | 14 +++++++++----- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index fae68d09..953f8570 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -435,6 +435,7 @@ typedef struct { float grentype; float expires; float icon_index; + float alpha; } FO_Hud_Grentimer; FO_Hud_Grentimer FO_Hud_Grentimers[5]; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 8e27e3b1..4f54f3f5 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -379,7 +379,7 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float } // draws value string using lmps -void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon) +void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon, float icon_alpha) { if (!panel || &panel == &NullPanel || (!panel.Display && !fo_hud_editor)) return; @@ -401,7 +401,8 @@ void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon) //vector size = FO_Hud_Icon_Size * panel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; //drawpic(pos, icon, size, '1 1 1', 1, 0); - drawpic(pos, icon, scaledFillSize, '1 1 1', 1, 0); + + drawpic(pos, icon, scaledFillSize, '1 1 1', icon_alpha, 0); float len = strlen(val); @@ -488,6 +489,7 @@ void AddGrenTimer(float grentype) { if(FO_Hud_Grentimers[i].grentype == 0) { FO_Hud_Grentimers[i].grentype = grentype; FO_Hud_Grentimers[i].icon_index = grentype; + FO_Hud_Grentimers[i].alpha = 1; FO_Hud_Grentimers[i].expires = time + 3.8; break; } diff --git a/csqc/main.qc b/csqc/main.qc index 2783be78..a5842d6c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,6 +10,7 @@ void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); +void ApplyTransparencyToGrenTimer(); void PrimeOrThrowGren(float gren_number); void PrimeGren(float gren_number); void ShowGrenadeTimer(float gren_number); @@ -383,6 +384,12 @@ void PrimeGren(float gren_number) { localcmd(strcat("prime", ftos(gren_number), "_server")); } +void ApplyTransparencyToGrenTimer() { + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + FO_Hud_Grentimers[i].alpha = 0.3; + } +} + void PrimeOrThrowGren(float gren_number) { if (cvar(FOCMD_GRENTIMER) != 2) { localcmd(strcat("gren", ftos(gren_number), "_server")); @@ -393,6 +400,7 @@ void PrimeOrThrowGren(float gren_number) { return; if (grentimer_waiting) { + ApplyTransparencyToGrenTimer(); localcmd(strcat("throwgren")); return; } diff --git a/csqc/status.qc b/csqc/status.qc index 22009a3b..77412928 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -2,7 +2,7 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, fl float fo_to_sui_aligntment(float fo_align); vector (FO_Hud_Panel* panel) getPanelPosition; vector (FO_Hud_Panel* panel) getPanelFillSize; -void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string); +void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string, float); void Hud_DrawLMPThreshold(FO_Hud_Panel*, string, float); FO_Hud_Panel* getHudPanelPointer(float); FO_Hud_Panel* getAnyHudPanelByNamePointer(string); @@ -11,7 +11,7 @@ float GetGrenTypeForClass(float gren_number, float playerclass); void(string panelid, float display, string text) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) { - Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_CLIPSIZE); + Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_CLIPSIZE, 1); } }; @@ -50,7 +50,7 @@ void(string panelid, float display, string text) drawFlagInfo = { void(string panelid, float display, string text, string icon) drawIconPanel = { if (display || fo_hud_editor) { - Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, icon); + Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, icon, 1); } }; @@ -121,24 +121,28 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { FO_Hud_Grentimers[j - 1].grentype = FO_Hud_Grentimers[j].grentype; FO_Hud_Grentimers[j - 1].expires = FO_Hud_Grentimers[j].expires; FO_Hud_Grentimers[j - 1].icon_index = FO_Hud_Grentimers[j].icon_index; + FO_Hud_Grentimers[j - 1].alpha = FO_Hud_Grentimers[j].alpha; } FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].grentype = 0; FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].expires = 0; FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].icon_index = 0; + FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].alpha = 0; continue; } + if(i) { panel2.Scale = Scale * 0.8; panel2.TextScale = TextScale * 0.8; } - Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon); + + Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon, FO_Hud_Grentimers[i].alpha); panel2.Position = panel2.Position + [0, panel2.FillSize.y * panel2.Scale]; timercount++; } } } if(fo_hud_editor && (!display || !timercount)) { - Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_GREN_NORMAL); + Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_GREN_NORMAL, 1); } }; From b6ae617cb9676b6da6410dcb3a9d3f7f30cca22b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 4 Feb 2022 17:44:23 +1100 Subject: [PATCH 1397/2474] localcmds get concatenated and sent as one, so require a newline --- csqc/main.qc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index a5842d6c..2df1d20f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -315,10 +315,10 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd tracktarget\n"); break; case "+aux_jump": - localcmd("+jump"); + localcmd("+jump\n"); break; case "-aux_jump": - localcmd("-jump"); + localcmd("-jump\n"); break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -381,7 +381,7 @@ void PrimeGren(float gren_number) { ShowGrenadeTimer(gren_number); } - localcmd(strcat("prime", ftos(gren_number), "_server")); + localcmd(strcat("prime", ftos(gren_number), "_server\n")); } void ApplyTransparencyToGrenTimer() { @@ -392,7 +392,7 @@ void ApplyTransparencyToGrenTimer() { void PrimeOrThrowGren(float gren_number) { if (cvar(FOCMD_GRENTIMER) != 2) { - localcmd(strcat("gren", ftos(gren_number), "_server")); + localcmd(strcat("gren", ftos(gren_number), "_server\n")); return; } @@ -401,7 +401,7 @@ void PrimeOrThrowGren(float gren_number) { if (grentimer_waiting) { ApplyTransparencyToGrenTimer(); - localcmd(strcat("throwgren")); + localcmd(strcat("throwgren\n")); return; } @@ -417,10 +417,10 @@ void PrimeOrThrowGren(float gren_number) { switch(gren_number) { case 1: - cmd = "primeone"; + cmd = "primeone\n"; break; case 2: - cmd = "primetwo"; + cmd = "primetwo\n"; break; } From ee43d16fe3931338512a3a3990a5336255d7526c Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 4 Feb 2022 19:30:23 +1100 Subject: [PATCH 1398/2474] practice spawns --- ssqc/actions.qc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ ssqc/client.qc | 21 +++++++++++++++++- ssqc/qw.qc | 1 + ssqc/tfort.qc | 4 +++- ssqc/tforthlp.qc | 2 ++ ssqc/weapons.qc | 7 +++++- ssqc/world.qc | 1 + 7 files changed, 91 insertions(+), 3 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index c9104adb..d5fffbb8 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -865,3 +865,61 @@ void () TeamFortress_ClipTick = { dremove(self); } }; + +entity TeamFortress_GetPracticeSpawn(entity e) = +{ + local entity spt = find(world, classname, "practicespawn"); + while (spt != world) + { + if (spt.owner == e) + { + return spt; + } + spt = find(spt, classname, "practicespawn"); + } + + return world; +}; + +void TeamFortress_RemovePracticeSpawn(entity e) = +{ + if(e == world) + return; + if(!allowpracspawns) + return; + + local entity spt = TeamFortress_GetPracticeSpawn(e); + + if(spt != world) + { + spawn_tfog(spt.origin); + dremove(spt); + + } +}; + + +void TeamFortress_PlacePracticeSpawn(entity e) = +{ + if(e == world) + return; + if(!allowpracspawns) + return; + + TeamFortress_RemovePracticeSpawn(e); + + local entity ps = spawn(); + ps.owner = e; + ps.movetype = MOVETYPE_NONE; + ps.solid = SOLID_NOT; + ps.classname = "practicespawn"; + setsize(ps, '0 0 0', '0 0 0'); + setorigin(ps, e.origin + '0 0 8'); + FO_SetModel(ps, "progs/s_light.spr"); + sprint(e, PRINT_HIGH, "your practice spawn has been placed @ ", vtos(e.origin),".\n"); + spawn_tfog(ps.origin); + + +}; + + diff --git a/ssqc/client.qc b/ssqc/client.qc index 032a8c9d..9ab15b57 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -67,6 +67,8 @@ float (float tno) TeamFortress_TeamGetLives; void () InitReverseCap; float () RejoinWithTfId; void () CreateTfIdAndJoin; +entity (entity e)TeamFortress_GetPracticeSpawn; + void () info_intermission = { @@ -758,6 +760,9 @@ void () DecodeLevelParms = { // disable setinfo keepcells [off] nokeepcells = CF_GetSetting("nkc", "nokeepcells", "0"); + + // allow clients to place a personal practice spawn [off] + allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); // enable server-side flaginfo on statusbar [on] // server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); @@ -1328,6 +1333,7 @@ void () RemovePlayerOwnedEnts = { TeamFortress_RemoveTimers(); RemoveGasTimers(); Engineer_QuietlyRemoveBuildings(self); + TeamFortress_RemovePracticeSpawn(self); te = find(world, classname, "detpack"); while (te) { if (te.owner == self) { @@ -1518,7 +1524,10 @@ void () ClientKill = { TeamFortress_RemoveTimers(); // players can't suicide again for 10 seconds - self.suicide_time = time + 5 + random() * 5; + if(!allowpracspawns) + self.suicide_time = time + 5 + random() * 5; + else + self.suicide_time = time; if (self.clientkillfree == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { TeamFortress_SetupRespawn(FALSE); @@ -1671,6 +1680,15 @@ void (entity e) ValidateUser = { entity () SelectSpawnPoint = { + if(allowpracspawns && self != world) + { + local entity spot2; + spot2 = TeamFortress_GetPracticeSpawn(self); + + if(spot2 != world) + return spot2; + } + local entity spot; local float attempts; @@ -2973,6 +2991,7 @@ void () ClientDisconnect = { if(votemode) { UnvoteForMap(self); } + }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ff14aedc..efb5d24f 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -616,6 +616,7 @@ float solid_nailgren; float noreturn; float nohitsounds; float nokeepcells; +float allowpracspawns; //float server_sbflaginfo; float reverse_cap; float engineer_move; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index df65071e..474b3316 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2462,7 +2462,9 @@ void (float Suicided) TeamFortress_SetupRespawn = { if (Suicided) { if (self.lives > 0) self.lives = self.lives - 1; - restime = restime + 7; + + if(!allowpracspawns) + restime = restime + 7; } } if (cb_prematch) { diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 1f47fb97..f3245636 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -262,6 +262,8 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("break", "cmd break"); TeamFortress_AliasString("voteyes", "cmd voteyes"); TeamFortress_AliasString("yes", "cmd voteyes"); + TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); + TeamFortress_Alias("removepracpawn", TF_PRACSPAWN_REMOVE, 0); Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 32ab9e4f..61911909 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -63,7 +63,8 @@ void () TeamFortress_Discard_DropAmmo; float (float force) TeamFortress_DetonatePipebombs; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; - +void (entity e) TeamFortress_PlacePracticeSpawn; +void (entity e) TeamFortress_RemovePracticeSpawn; void () DropKey; void () UseSpecialSkill; void () RemoveFlare; @@ -2979,6 +2980,10 @@ void () ImpulseCommands = { else if (self.impulse == TF_DROP_AMMO) { Menu_Drop(); } + else if (self.impulse == TF_PRACSPAWN_PLACE) + TeamFortress_PlacePracticeSpawn(self); + else if (self.impulse == TF_PRACSPAWN_REMOVE) + TeamFortress_RemovePracticeSpawn(self); } if (self.impulse == TF_INVENTORY) diff --git a/ssqc/world.qc b/ssqc/world.qc index d6501c9f..4c0f50be 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -200,6 +200,7 @@ void () worldspawn = { precache_model("progs/gib3.mdl"); precache_model("progs/s_bubble.spr"); precache_model("progs/s_explod.spr"); + precache_model("progs/s_light.spr"); precache_model("progs/v_axe.mdl"); precache_model("progs/v_tranq.mdl"); precache_model("progs/v_shot.mdl"); From 427bcaa2ab35a2c9343974e17ee97eedbe3e1f6c Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 4 Feb 2022 19:31:08 +1100 Subject: [PATCH 1399/2474] practice spawns --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 641cac1c..bd7bfc72 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ FortressOne Server New features ------ +* `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. * ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above ```` into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of ```` (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set values for each class. ``localinfo nokeepcells 1`` - disables keepcells server-wide * option to let engineer move while building `localinfo em on`. From 50118886a4e33b0be0401504008e97b2fc852d96 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 4 Feb 2022 19:33:06 +1100 Subject: [PATCH 1400/2474] practice spawns --- ssqc/spect.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 97cf7f7e..2b045ce2 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -63,6 +63,7 @@ void () SpectatorConnect = { } TeamFortress_StartTimers(); + TeamFortress_RemovePracticeSpawn(self); }; void () SpectatorDisconnect = { From 54b4d103f0572032fabd85a7b4294a0232ea0872 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 4 Feb 2022 21:25:24 +1100 Subject: [PATCH 1401/2474] practice spawns --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bd7bfc72..bbe04984 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ FortressOne Server New features ------ -* `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. +* `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. +* Added ``localinfo nomapcycle 1`` to stop all the confusion. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. * ``setinfo keepcells `` allows scout/med/pyro/eng/hwguy to include cells above ```` into discards. eg. an eng with 200 cells that has ``setinfo keepcells 50`` will discard 150 cells and keep 50. sold/spy/sniper/demo will throw all cells regardless of ```` (current behaviour). suggest players using this setinfo use scout/med/pyro/eng/hwguy class configs to set values for each class. ``localinfo nokeepcells 1`` - disables keepcells server-wide * option to let engineer move while building `localinfo em on`. From be6ec8831f1cdd8aa34eaab090a2e1df0cabf66a Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 4 Feb 2022 22:10:21 +1100 Subject: [PATCH 1402/2474] practice spawns --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 9ab15b57..4e37916f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1526,7 +1526,7 @@ void () ClientKill = { // players can't suicide again for 10 seconds if(!allowpracspawns) self.suicide_time = time + 5 + random() * 5; - else + else self.suicide_time = time; if (self.clientkillfree == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { From 790eca4968849595f613bd6e8a35599990dabcc0 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 4 Feb 2022 23:59:51 +1100 Subject: [PATCH 1403/2474] practice spawns --- ssqc/client.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 4e37916f..ada454cf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1525,9 +1525,9 @@ void () ClientKill = { // players can't suicide again for 10 seconds if(!allowpracspawns) - self.suicide_time = time + 5 + random() * 5; - else - self.suicide_time = time; + self.suicide_time = time + 5 + random() * 5; + else + self.suicide_time = time; if (self.clientkillfree == 1 && !self.has_throwngren && (self.has_changedteam || self.has_changedclass)) { TeamFortress_SetupRespawn(FALSE); From 79a4c7920fb0118379a3784520e04fcaed973452 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Feb 2022 20:12:31 +1100 Subject: [PATCH 1404/2474] Give some care to the ones who use primeone, primetwo, and throwgren --- csqc/main.qc | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 2df1d20f..81d39b18 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -237,6 +237,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_cancel": Menu_Cancel(); break; + case "throwgren": + ThrowGren(); + break; case "primeone": PrimeGren(1); break; @@ -366,27 +369,46 @@ void CSQC_Shutdown() = { FO_WriteSettings(); } +void ThrowGren() { + ApplyTransparencyToGrenTimer(); + localcmd(strcat("throwgren\n")); +} + void PrimeGren(float gren_number) { - if (cvar(FOCMD_GRENTIMER) == 2) { - if !(IsValidToUseGrenades()) - return; + local string cmd; - if (RemainingGrenades(gren_number) <= 0) { - localsound("error.wav", CHAN_AUTO, 1); - print("No grenades left\n"); - return; - } + switch(gren_number) { + case 1: + cmd = "primeone\n"; + break; + case 2: + cmd = "primetwo\n"; + break; + } - if (!grentimer_waiting) - ShowGrenadeTimer(gren_number); + if (cvar(FOCMD_GRENTIMER) != 2) { + localcmd(strcat(cmd)); + return; + } + + if (!IsValidToUseGrenades()) + return; + + if (RemainingGrenades(gren_number) <= 0) { + localsound("error.wav", CHAN_AUTO, 1); + print("No grenades left\n"); + return; } - localcmd(strcat("prime", ftos(gren_number), "_server\n")); + ShowGrenadeTimer(gren_number); + localcmd(strcat(cmd)); } void ApplyTransparencyToGrenTimer() { - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - FO_Hud_Grentimers[i].alpha = 0.3; + for(float i = FO_Hud_Grentimers.length; i >= 0; i--) { + if FO_Hud_Grentimers[i].grentype != 0 + FO_Hud_Grentimers[i].alpha = 0.3; + break; } } From 32fb0f6358cdeacabfdf1815d4ac3e231e50c28d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Feb 2022 22:57:27 +1100 Subject: [PATCH 1405/2474] Add csqc throwgren command --- csqc/main.qc | 21 ++++++++++++--------- ssqc/tforthlp.qc | 3 ++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 81d39b18..6edef05d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -11,6 +11,7 @@ void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); void ApplyTransparencyToGrenTimer(); +void ThrowGren(); void PrimeOrThrowGren(float gren_number); void PrimeGren(float gren_number); void ShowGrenadeTimer(float gren_number); @@ -57,6 +58,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("primeone"); registercommand("primetwo"); + registercommand("throwgren"); registercommand("gren1"); registercommand("gren2"); registercommand("+aux_jump"); @@ -371,7 +373,7 @@ void CSQC_Shutdown() = { void ThrowGren() { ApplyTransparencyToGrenTimer(); - localcmd(strcat("throwgren\n")); + localcmd("throwgren_server\n"); } void PrimeGren(float gren_number) { @@ -387,7 +389,7 @@ void PrimeGren(float gren_number) { } if (cvar(FOCMD_GRENTIMER) != 2) { - localcmd(strcat(cmd)); + localcmd(cmd); return; } @@ -401,14 +403,15 @@ void PrimeGren(float gren_number) { } ShowGrenadeTimer(gren_number); - localcmd(strcat(cmd)); + localcmd(cmd); } void ApplyTransparencyToGrenTimer() { - for(float i = FO_Hud_Grentimers.length; i >= 0; i--) { - if FO_Hud_Grentimers[i].grentype != 0 + for(float i = FO_Hud_Grentimers.length - 1; i >= 0; i--) { + if (FO_Hud_Grentimers[i].grentype != 0) { FO_Hud_Grentimers[i].alpha = 0.3; break; + } } } @@ -423,7 +426,7 @@ void PrimeOrThrowGren(float gren_number) { if (grentimer_waiting) { ApplyTransparencyToGrenTimer(); - localcmd(strcat("throwgren\n")); + localcmd("throwgren_server\n"); return; } @@ -439,14 +442,14 @@ void PrimeOrThrowGren(float gren_number) { switch(gren_number) { case 1: - cmd = "primeone\n"; + cmd = "prime1_server\n"; break; case 2: - cmd = "primetwo\n"; + cmd = "prime2_server\n"; break; } - localcmd(strcat(cmd)); + localcmd(cmd); } void ShowGrenadeTimer(float gren_number) { diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 1f47fb97..8e2404b3 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -179,13 +179,13 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("reloadnext", TF_RELOAD_NEXT, 0); } else if (self.motd == 70) { TeamFortress_Alias("grenswitch", TF_GRENADE_SWITCH, 0); - TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); TeamFortress_Alias("-gren1", TF_GRENADE_T, 0); TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); //Don't send to fte - these are handled client-side if(!csqcactive) { TeamFortress_Alias("primeone", TF_GRENADE_1, 0); TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); + TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); TeamFortress_Alias("+gren1", TF_GRENADE_1, 0); TeamFortress_Alias("+gren2", TF_GRENADE_2, 0); TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); @@ -193,6 +193,7 @@ void () TeamFortress_MOTD = { } else { TeamFortress_Alias("prime1_server", TF_GRENADE_1, 0); TeamFortress_Alias("prime2_server", TF_GRENADE_2, 0); + TeamFortress_Alias("throwgren_server", TF_GRENADE_T, 0); TeamFortress_Alias("gren1_server", TF_GRENADE_PT_1, 0); TeamFortress_Alias("gren2_server", TF_GRENADE_PT_2, 0); TeamFortress_AliasString("+gren1", "primeone"); From 432d3095c74db3ade03f549df5444e7312dd8723 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Feb 2022 23:02:45 +1100 Subject: [PATCH 1406/2474] Support primeone primetwo and throwgren --- csqc/main.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 6edef05d..16ce9d87 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -381,10 +381,10 @@ void PrimeGren(float gren_number) { switch(gren_number) { case 1: - cmd = "primeone\n"; + cmd = "prime1_server\n"; break; case 2: - cmd = "primetwo\n"; + cmd = "prime2_server\n"; break; } From eb954cee53d36477e27068ad494534fbe428146b Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sun, 6 Feb 2022 14:57:28 +1100 Subject: [PATCH 1407/2474] Update client.qc --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ada454cf..176ab837 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1682,7 +1682,7 @@ entity () SelectSpawnPoint = { if(allowpracspawns && self != world) { - local entity spot2; + local entity spot2; spot2 = TeamFortress_GetPracticeSpawn(self); if(spot2 != world) From 640b977343095a94ae33d2c0587f332a0e019090 Mon Sep 17 00:00:00 2001 From: lordee Date: Sun, 6 Feb 2022 21:21:46 +1100 Subject: [PATCH 1408/2474] Update actions.qc --- ssqc/actions.qc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index d5fffbb8..b9222022 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -876,7 +876,7 @@ entity TeamFortress_GetPracticeSpawn(entity e) = return spt; } spt = find(spt, classname, "practicespawn"); - } + } return world; }; @@ -894,7 +894,6 @@ void TeamFortress_RemovePracticeSpawn(entity e) = { spawn_tfog(spt.origin); dremove(spt); - } }; @@ -918,8 +917,6 @@ void TeamFortress_PlacePracticeSpawn(entity e) = FO_SetModel(ps, "progs/s_light.spr"); sprint(e, PRINT_HIGH, "your practice spawn has been placed @ ", vtos(e.origin),".\n"); spawn_tfog(ps.origin); - - }; From d90aa702fee99cceaae8b1a0905de4fe97214a9e Mon Sep 17 00:00:00 2001 From: lordee Date: Sun, 6 Feb 2022 21:26:36 +1100 Subject: [PATCH 1409/2474] Update client.qc --- ssqc/client.qc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 176ab837..680adbf7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1680,14 +1680,14 @@ void (entity e) ValidateUser = { entity () SelectSpawnPoint = { - if(allowpracspawns && self != world) - { - local entity spot2; - spot2 = TeamFortress_GetPracticeSpawn(self); - - if(spot2 != world) - return spot2; - } + if(allowpracspawns && self != world) + { + local entity spot2; + spot2 = TeamFortress_GetPracticeSpawn(self); + + if(spot2 != world) + return spot2; + } local entity spot; local float attempts; From 44ea0de0652d96f0cfa04d5a1cbc6cb2cbd534e8 Mon Sep 17 00:00:00 2001 From: lordee Date: Sun, 6 Feb 2022 21:29:09 +1100 Subject: [PATCH 1410/2474] Update tfort.qc --- ssqc/tfort.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 474b3316..b3123645 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2463,8 +2463,8 @@ void (float Suicided) TeamFortress_SetupRespawn = { if (self.lives > 0) self.lives = self.lives - 1; - if(!allowpracspawns) - restime = restime + 7; + if(!allowpracspawns) + restime = restime + 7; } } if (cb_prematch) { From 9ea314766c464928bbd5e2106e7c5da87367ac1c Mon Sep 17 00:00:00 2001 From: lordee Date: Sun, 6 Feb 2022 21:30:05 +1100 Subject: [PATCH 1411/2474] Update weapons.qc --- ssqc/weapons.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 61911909..f7848988 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2980,10 +2980,10 @@ void () ImpulseCommands = { else if (self.impulse == TF_DROP_AMMO) { Menu_Drop(); } - else if (self.impulse == TF_PRACSPAWN_PLACE) - TeamFortress_PlacePracticeSpawn(self); - else if (self.impulse == TF_PRACSPAWN_REMOVE) - TeamFortress_RemovePracticeSpawn(self); + else if (self.impulse == TF_PRACSPAWN_PLACE) + TeamFortress_PlacePracticeSpawn(self); + else if (self.impulse == TF_PRACSPAWN_REMOVE) + TeamFortress_RemovePracticeSpawn(self); } if (self.impulse == TF_INVENTORY) From 5d7fbff059d7ab25812f36513db94ab2b7ca3ac5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Feb 2022 00:06:52 +1100 Subject: [PATCH 1412/2474] Create tfstate stat and use it for gren timers --- csqc/csextradefs.qc | 1 - csqc/events.qc | 6 ------ csqc/main.qc | 38 +++++++++++++++++++++++++------------- share/defs.h | 5 +++-- ssqc/status.qc | 2 +- ssqc/world.qc | 1 + 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 953f8570..f8703ed8 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -92,7 +92,6 @@ float round_over; float round_time_remaining; float showingscores; float mapvote_expiry; -float grentimer_waiting; //grenade primed, but not thrown float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; diff --git a/csqc/events.qc b/csqc/events.qc index 82a17623..633b987b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -270,9 +270,6 @@ void() CSQC_Parse_Event = { medic_type = readfloat(); nailgren_type = readfloat(); break; - case MSG_GRENTHROWN: - grentimer_waiting = FALSE; - break; case MSG_TEAM_SCORES: TeamScore[0] = readfloat(); TeamScore[1] = readfloat(); @@ -401,7 +398,4 @@ void ParseSBAR() } break; } - if(!readfloat()) { - grentimer_waiting = FALSE; - } } diff --git a/csqc/main.qc b/csqc/main.qc index 16ce9d87..e07c9684 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -83,7 +83,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; is_admin = FALSE; - grentimer_waiting = FALSE; num_mapvotes = 0; vote_selected_item = world; vote_selected_index = -1; @@ -153,13 +152,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); - - //reset grentimer status if all there are no more active grentimers - if(grentimer_waiting) { - if(FO_Hud_Grentimers[0].grentype == 0) { - grentimer_waiting = FALSE; - } - } } noref float(string cmd) CSQC_ConsoleCommand = { @@ -372,8 +364,22 @@ void CSQC_Shutdown() = { } void ThrowGren() { - ApplyTransparencyToGrenTimer(); - localcmd("throwgren_server\n"); + local string cmd = "throwgren_server\n"; + + if (cvar(FOCMD_GRENTIMER) != 2) { + localcmd(cmd); + return; + } + + if (!IsValidToUseGrenades()) + return; + + local float tfstate = getstatf(STAT_TFSTATE); + + if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { + ApplyTransparencyToGrenTimer(); + localcmd(cmd); + } } void PrimeGren(float gren_number) { @@ -396,6 +402,12 @@ void PrimeGren(float gren_number) { if (!IsValidToUseGrenades()) return; + local float tfstate = getstatf(STAT_TFSTATE); + + if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { + return; + } + if (RemainingGrenades(gren_number) <= 0) { localsound("error.wav", CHAN_AUTO, 1); print("No grenades left\n"); @@ -424,7 +436,9 @@ void PrimeOrThrowGren(float gren_number) { if (!IsValidToUseGrenades()) return; - if (grentimer_waiting) { + local float tfstate = getstatf(STAT_TFSTATE); + + if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { ApplyTransparencyToGrenTimer(); localcmd("throwgren_server\n"); return; @@ -453,8 +467,6 @@ void PrimeOrThrowGren(float gren_number) { } void ShowGrenadeTimer(float gren_number) { - grentimer_waiting = TRUE; - local float grentimer_channel; local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); diff --git a/share/defs.h b/share/defs.h index fd00139f..b1a30d4a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1475,8 +1475,9 @@ #define STAT_VELOCITY_X 36 #define STAT_VELOCITY_Y 37 #define STAT_VELOCITY_Z 38 -#define STAT_NO_GREN1 39 -#define STAT_NO_GREN2 40 +#define STAT_NO_GREN1 39 +#define STAT_NO_GREN2 40 +#define STAT_TFSTATE 41 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/status.qc b/ssqc/status.qc index 19e5691f..c68b7f24 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -995,7 +995,7 @@ void UpdateClientStatusBar(entity pl) } break; } - WriteFloat(MSG_MULTICAST, ((pl.tfstate & TFSTATE_GRENPRIMED) == TFSTATE_GRENPRIMED)); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/world.qc b/ssqc/world.qc index d6501c9f..7e013226 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -321,6 +321,7 @@ void () worldspawn = { clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); + clientstat(STAT_TFSTATE, EV_FLOAT, tfstate); entity worldspawnent; worldspawnent = spawn(); From d9a421a645b818914ba20e42132fd310d210ce85 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Feb 2022 00:24:46 +1100 Subject: [PATCH 1413/2474] Add missing pracspawn declarations, fix typo --- share/defs.h | 2 ++ ssqc/tforthlp.qc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index b1a30d4a..35fce05c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -444,6 +444,8 @@ #define TF_ENGINEER_DETDISP 78 // Engineer: Detonate dispenser for Engineer #define TF_ENGINEER_DETSENTRY 79 // Engineer: Detonate sentry gun for Engineer #define TF_DISCARD_DROP_AMMO 80 +#define TF_PRACSPAWN_PLACE 81 +#define TF_PRACSPAWN_REMOVE 80 // unused 81 // unused 82 // unused 83 diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index fcfaf80f..91252248 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -264,7 +264,7 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("voteyes", "cmd voteyes"); TeamFortress_AliasString("yes", "cmd voteyes"); TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); - TeamFortress_Alias("removepracpawn", TF_PRACSPAWN_REMOVE, 0); + TeamFortress_Alias("removepracspawn", TF_PRACSPAWN_REMOVE, 0); Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) From e3a985f8ef262da9c7e12a0d48e0650ff2a27cc2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Feb 2022 00:47:56 +1100 Subject: [PATCH 1414/2474] Keep client side record of gren prime until server catches up --- csqc/csextradefs.qc | 1 + csqc/main.qc | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f8703ed8..0baac8c2 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -92,6 +92,7 @@ float round_over; float round_time_remaining; float showingscores; float mapvote_expiry; +float cs_grenprimed; float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; diff --git a/csqc/main.qc b/csqc/main.qc index e07c9684..95fb04f5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -146,6 +146,12 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view + local float tfstate = getstatf(STAT_TFSTATE); + + if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { + cs_grenprimed = FALSE; + } + renderscene(); sui_begin(width, height); @@ -444,6 +450,9 @@ void PrimeOrThrowGren(float gren_number) { return; } + if (cs_grenprimed) + return; + if (RemainingGrenades(gren_number) <= 0) { localsound("error.wav", CHAN_AUTO, 1); print("No grenades left\n"); @@ -467,6 +476,8 @@ void PrimeOrThrowGren(float gren_number) { } void ShowGrenadeTimer(float gren_number) { + cs_grenprimed = TRUE; + local float grentimer_channel; local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); From 44757c66691d75731adf59ea00224c9093e98a33 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Feb 2022 01:37:03 +1100 Subject: [PATCH 1415/2474] Rely on stats for thrown indicator --- csqc/main.qc | 36 ++++++------------------------------ ssqc/tforthlp.qc | 3 +-- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 95fb04f5..cb6195f2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -11,7 +11,6 @@ void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype); void ApplyTransparencyToGrenTimer(); -void ThrowGren(); void PrimeOrThrowGren(float gren_number); void PrimeGren(float gren_number); void ShowGrenadeTimer(float gren_number); @@ -58,7 +57,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("primeone"); registercommand("primetwo"); - registercommand("throwgren"); registercommand("gren1"); registercommand("gren2"); registercommand("+aux_jump"); @@ -150,6 +148,10 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { cs_grenprimed = FALSE; + } else { + if (!cs_grenprimed) { + ApplyTransparencyToGrenTimer(); + } } renderscene(); @@ -237,9 +239,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_cancel": Menu_Cancel(); break; - case "throwgren": - ThrowGren(); - break; case "primeone": PrimeGren(1); break; @@ -369,25 +368,6 @@ void CSQC_Shutdown() = { FO_WriteSettings(); } -void ThrowGren() { - local string cmd = "throwgren_server\n"; - - if (cvar(FOCMD_GRENTIMER) != 2) { - localcmd(cmd); - return; - } - - if (!IsValidToUseGrenades()) - return; - - local float tfstate = getstatf(STAT_TFSTATE); - - if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { - ApplyTransparencyToGrenTimer(); - localcmd(cmd); - } -} - void PrimeGren(float gren_number) { local string cmd; @@ -444,15 +424,11 @@ void PrimeOrThrowGren(float gren_number) { local float tfstate = getstatf(STAT_TFSTATE); - if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { - ApplyTransparencyToGrenTimer(); - localcmd("throwgren_server\n"); + if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING) || cs_grenprimed) { + localcmd("throwgren\n"); return; } - if (cs_grenprimed) - return; - if (RemainingGrenades(gren_number) <= 0) { localsound("error.wav", CHAN_AUTO, 1); print("No grenades left\n"); diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 91252248..37ebad37 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -181,11 +181,11 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("grenswitch", TF_GRENADE_SWITCH, 0); TeamFortress_Alias("-gren1", TF_GRENADE_T, 0); TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); + TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); //Don't send to fte - these are handled client-side if(!csqcactive) { TeamFortress_Alias("primeone", TF_GRENADE_1, 0); TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); - TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); TeamFortress_Alias("+gren1", TF_GRENADE_1, 0); TeamFortress_Alias("+gren2", TF_GRENADE_2, 0); TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); @@ -193,7 +193,6 @@ void () TeamFortress_MOTD = { } else { TeamFortress_Alias("prime1_server", TF_GRENADE_1, 0); TeamFortress_Alias("prime2_server", TF_GRENADE_2, 0); - TeamFortress_Alias("throwgren_server", TF_GRENADE_T, 0); TeamFortress_Alias("gren1_server", TF_GRENADE_PT_1, 0); TeamFortress_Alias("gren2_server", TF_GRENADE_PT_2, 0); TeamFortress_AliasString("+gren1", "primeone"); From f5d9895a8a87b7e403032fee2dbc103ac1a0fa17 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Feb 2022 23:34:06 +1100 Subject: [PATCH 1416/2474] Keep client side gren flags until server side stats update --- csqc/csextradefs.qc | 1 + csqc/main.qc | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 0baac8c2..34051b26 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -93,6 +93,7 @@ float round_time_remaining; float showingscores; float mapvote_expiry; float cs_grenprimed; +float cs_grenthrown; float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; diff --git a/csqc/main.qc b/csqc/main.qc index cb6195f2..4c4c0040 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -149,6 +149,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { cs_grenprimed = FALSE; } else { + cs_grenthrown = FALSE; + if (!cs_grenprimed) { ApplyTransparencyToGrenTimer(); } @@ -424,7 +426,8 @@ void PrimeOrThrowGren(float gren_number) { local float tfstate = getstatf(STAT_TFSTATE); - if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING) || cs_grenprimed) { + if (!cs_grenthrown && ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING) || cs_grenprimed)) { + cs_grenthrown = TRUE; localcmd("throwgren\n"); return; } From cacbc88ee172fe3620f6e78bdb281c933ea1c242 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 8 Feb 2022 00:52:44 +1100 Subject: [PATCH 1417/2474] Fix multiple timers appearing when tapping quickly issue --- csqc/main.qc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 4c4c0040..d3a07329 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -146,14 +146,12 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { local float tfstate = getstatf(STAT_TFSTATE); - if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { + if (tfstate & TFSTATE_GRENPRIMED) cs_grenprimed = FALSE; - } else { - cs_grenthrown = FALSE; - if (!cs_grenprimed) { - ApplyTransparencyToGrenTimer(); - } + if (tfstate & TFSTATE_GRENTHROWING) { + ApplyTransparencyToGrenTimer(); + cs_grenthrown = FALSE; } renderscene(); @@ -407,8 +405,8 @@ void PrimeGren(float gren_number) { } void ApplyTransparencyToGrenTimer() { - for(float i = FO_Hud_Grentimers.length - 1; i >= 0; i--) { - if (FO_Hud_Grentimers[i].grentype != 0) { + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + if (FO_Hud_Grentimers[i].grentype != 0 && FO_Hud_Grentimers[i].alpha != 0.3) { FO_Hud_Grentimers[i].alpha = 0.3; break; } @@ -424,9 +422,12 @@ void PrimeOrThrowGren(float gren_number) { if (!IsValidToUseGrenades()) return; + if (cs_grenprimed && cs_grenthrown) + return; + local float tfstate = getstatf(STAT_TFSTATE); - if (!cs_grenthrown && ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING) || cs_grenprimed)) { + if (!cs_grenthrown && (cs_grenprimed || (tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING))) { cs_grenthrown = TRUE; localcmd("throwgren\n"); return; From 52278e7166cc9d1ba15164fb890cc3d687134091 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 8 Feb 2022 23:20:17 +1100 Subject: [PATCH 1418/2474] Clean up a bit --- csqc/csextradefs.qc | 2 +- csqc/main.qc | 45 +++++++++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 34051b26..eabdd47b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -93,7 +93,7 @@ float round_time_remaining; float showingscores; float mapvote_expiry; float cs_grenprimed; -float cs_grenthrown; +float pending_prime_or_throw_command; float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; diff --git a/csqc/main.qc b/csqc/main.qc index d3a07329..43b9ceeb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -129,6 +129,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } } + clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -146,12 +147,11 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { local float tfstate = getstatf(STAT_TFSTATE); - if (tfstate & TFSTATE_GRENPRIMED) + if (tfstate & TFSTATE_GRENPRIMED || tfstate & TFSTATE_GRENTHROWING) cs_grenprimed = FALSE; if (tfstate & TFSTATE_GRENTHROWING) { ApplyTransparencyToGrenTimer(); - cs_grenthrown = FALSE; } renderscene(); @@ -368,6 +368,15 @@ void CSQC_Shutdown() = { FO_WriteSettings(); } +void ApplyTransparencyToGrenTimer() { + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + if (FO_Hud_Grentimers[i].grentype != 0 && FO_Hud_Grentimers[i].alpha != 0.3) { + FO_Hud_Grentimers[i].alpha = 0.3; + break; + } + } +} + void PrimeGren(float gren_number) { local string cmd; @@ -390,7 +399,7 @@ void PrimeGren(float gren_number) { local float tfstate = getstatf(STAT_TFSTATE); - if ((tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING)) { + if (cs_grenprimed || (tfstate & TFSTATE_GRENPRIMED)) { return; } @@ -404,31 +413,29 @@ void PrimeGren(float gren_number) { localcmd(cmd); } -void ApplyTransparencyToGrenTimer() { - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - if (FO_Hud_Grentimers[i].grentype != 0 && FO_Hud_Grentimers[i].alpha != 0.3) { - FO_Hud_Grentimers[i].alpha = 0.3; - break; - } - } -} - void PrimeOrThrowGren(float gren_number) { + local string cmd; + if (cvar(FOCMD_GRENTIMER) != 2) { - localcmd(strcat("gren", ftos(gren_number), "_server\n")); + switch(gren_number) { + case 1: + cmd = "gren1_server\n"; + break; + case 2: + cmd = "gren2_server\n"; + break; + } + + localcmd(cmd); return; } if (!IsValidToUseGrenades()) return; - if (cs_grenprimed && cs_grenthrown) - return; - local float tfstate = getstatf(STAT_TFSTATE); - if (!cs_grenthrown && (cs_grenprimed || (tfstate & TFSTATE_GRENPRIMED) || (tfstate & TFSTATE_GRENTHROWING))) { - cs_grenthrown = TRUE; + if (cs_grenprimed || (tfstate & TFSTATE_GRENPRIMED)) { localcmd("throwgren\n"); return; } @@ -441,8 +448,6 @@ void PrimeOrThrowGren(float gren_number) { ShowGrenadeTimer(gren_number); - local string cmd; - switch(gren_number) { case 1: cmd = "prime1_server\n"; From 84c2c544aefefc1f2ff3afa42ee54bb6944d057f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 8 Feb 2022 23:46:48 +1100 Subject: [PATCH 1419/2474] reset cs_primed on death --- csqc/main.qc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 43b9ceeb..e24fe8d4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -117,8 +117,11 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; speed = sqrt(vel.x * vel.x + vel.y * vel.y); + //stop grentimer on death - if(getstatf(STAT_HEALTH) <= 0) { + if(oldhealth <= 0) { + cs_primed = FALSE; + soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); @@ -130,6 +133,16 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } + local float tfstate = getstatf(STAT_TFSTATE); + + if (tfstate & TFSTATE_GRENPRIMED || tfstate & TFSTATE_GRENTHROWING) + cs_grenprimed = FALSE; + + if (tfstate & TFSTATE_GRENTHROWING) { + ApplyTransparencyToGrenTimer(); + } + + clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -145,15 +158,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view - local float tfstate = getstatf(STAT_TFSTATE); - - if (tfstate & TFSTATE_GRENPRIMED || tfstate & TFSTATE_GRENTHROWING) - cs_grenprimed = FALSE; - - if (tfstate & TFSTATE_GRENTHROWING) { - ApplyTransparencyToGrenTimer(); - } - renderscene(); sui_begin(width, height); From 6ca42cbf11f4e53c6fbf7445573d3910234abefc Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 8 Feb 2022 23:48:38 +1100 Subject: [PATCH 1420/2474] Fix variable name --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index e24fe8d4..46f5e114 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -120,7 +120,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { //stop grentimer on death if(oldhealth <= 0) { - cs_primed = FALSE; + cs_grenprimed = FALSE; soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); From 2bc82e2e325aa554437b0a15910ab2872a1a2f86 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 11 Feb 2022 00:01:41 +1100 Subject: [PATCH 1421/2474] Add debug statement --- csqc/main.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index 46f5e114..7a22433f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -119,6 +119,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { //stop grentimer on death + /* printf("oldhealth: %f", oldhealth); */ + if(oldhealth <= 0) { cs_grenprimed = FALSE; @@ -441,6 +443,7 @@ void PrimeOrThrowGren(float gren_number) { if (cs_grenprimed || (tfstate & TFSTATE_GRENPRIMED)) { localcmd("throwgren\n"); + printf("cs_grenprimed: %f\n", cs_grenprimed); return; } From 55579bb07495976d31b9132a080c4232a31b144c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 11 Feb 2022 02:51:34 +1100 Subject: [PATCH 1422/2474] Forget client side, just offset timer by ping --- csqc/events.qc | 50 +++++++++++-- csqc/hud_helpers.qc | 4 +- csqc/main.qc | 166 +------------------------------------------- ssqc/tforthlp.qc | 22 ++---- 4 files changed, 52 insertions(+), 190 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 633b987b..1eddb959 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,5 +1,7 @@ void ParseSBAR(); -void AddGrenTimer(float grentype); +void ParseGrenPrimed(float grentype, float timertype); +void AddGrenTimer(float grentype, float offset); +void PlayGrenTimer(float antilag); void() CSQC_Parse_Event = { float msgtype = readbyte(); @@ -101,12 +103,7 @@ void() CSQC_Parse_Event = { case MSG_GRENPRIMED: float grentype = readfloat(); float timertype = cvar(FOCMD_GRENTIMER); - if(timertype != 2) { - AddGrenTimer(grentype); - } - if(timertype == 1) { - localcmd(sprintf("play %s\n", cvar_string(FOCMD_GRENTIMERSOUND))); - } + ParseGrenPrimed(grentype, timertype); break; case MSG_CLIENT_MENU: float menutype = readfloat(); @@ -304,6 +301,45 @@ void() CSQC_Parse_Event = { } } +void PlayGrenTimer(float offset) { + local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); + local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); + local float grentimer_channel; + + if (chan_gren1_soundtime == -1 ) { + grentimer_channel = CHAN_GREN1; + } else if (chan_gren2_soundtime == -1 ) { + grentimer_channel = CHAN_GREN2; + } else if (chan_gren1_soundtime > chan_gren2_soundtime) { + grentimer_channel = CHAN_GREN1; + } else { + grentimer_channel = CHAN_GREN2; + } + + local string grentimer_sound = cvar_string(FOCMD_GRENTIMERSOUND); + soundupdate(self, grentimer_channel, grentimer_sound, 1, 0, 0, 0, offset); +} + +void ParseGrenPrimed(float grentype, float timertype) { + if(timertype == 0) { + AddGrenTimer(grentype, 0); + return; + } + + if(timertype == 1) { + PlayGrenTimer(0); + AddGrenTimer(grentype, 0); + return; + } + + if(timertype == 2) { + local float offset = getplayerkeyfloat(player_localnum, INFOKEY_P_PING)/1000; + PlayGrenTimer(offset); + AddGrenTimer(grentype, offset); + return; + } +} + void ParseSBAR() { SBAR.ClipSize = readstring(); diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 4f54f3f5..a33c9c86 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -484,13 +484,13 @@ vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, ve return pos; } -void AddGrenTimer(float grentype) { +void AddGrenTimer(float grentype, float offset) { for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype == 0) { FO_Hud_Grentimers[i].grentype = grentype; FO_Hud_Grentimers[i].icon_index = grentype; FO_Hud_Grentimers[i].alpha = 1; - FO_Hud_Grentimers[i].expires = time + 3.8; + FO_Hud_Grentimers[i].expires = time + 3.8 - offset; break; } } diff --git a/csqc/main.qc b/csqc/main.qc index 7a22433f..afe0a2da 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -9,11 +9,8 @@ void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string valu void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); -void AddGrenTimer(float grentype); +void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); -void PrimeOrThrowGren(float gren_number); -void PrimeGren(float gren_number); -void ShowGrenadeTimer(float gren_number); float RemainingGrenades(float gren_number); float IsValidToUseGrenades(); @@ -55,10 +52,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_cancel"); registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); - registercommand("primeone"); - registercommand("primetwo"); - registercommand("gren1"); - registercommand("gren2"); registercommand("+aux_jump"); registercommand("-aux_jump"); registercommand("tracktarget"); @@ -117,13 +110,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; speed = sqrt(vel.x * vel.x + vel.y * vel.y); - //stop grentimer on death - /* printf("oldhealth: %f", oldhealth); */ - if(oldhealth <= 0) { - cs_grenprimed = FALSE; - soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); @@ -132,19 +120,14 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { FO_Hud_Grentimers[i].expires = 0; FO_Hud_Grentimers[i].icon_index = 0; } - } local float tfstate = getstatf(STAT_TFSTATE); - if (tfstate & TFSTATE_GRENPRIMED || tfstate & TFSTATE_GRENTHROWING) - cs_grenprimed = FALSE; - if (tfstate & TFSTATE_GRENTHROWING) { ApplyTransparencyToGrenTimer(); } - clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -245,18 +228,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_cancel": Menu_Cancel(); break; - case "primeone": - PrimeGren(1); - break; - case "primetwo": - PrimeGren(2); - break; - case "gren1": - PrimeOrThrowGren(1); - break; - case "gren2": - PrimeOrThrowGren(2); - break; case "+fo_showscores": if (cvar(FOCMD_OLDSCOREBOARD) == 1) { @@ -382,138 +353,3 @@ void ApplyTransparencyToGrenTimer() { } } } - -void PrimeGren(float gren_number) { - local string cmd; - - switch(gren_number) { - case 1: - cmd = "prime1_server\n"; - break; - case 2: - cmd = "prime2_server\n"; - break; - } - - if (cvar(FOCMD_GRENTIMER) != 2) { - localcmd(cmd); - return; - } - - if (!IsValidToUseGrenades()) - return; - - local float tfstate = getstatf(STAT_TFSTATE); - - if (cs_grenprimed || (tfstate & TFSTATE_GRENPRIMED)) { - return; - } - - if (RemainingGrenades(gren_number) <= 0) { - localsound("error.wav", CHAN_AUTO, 1); - print("No grenades left\n"); - return; - } - - ShowGrenadeTimer(gren_number); - localcmd(cmd); -} - -void PrimeOrThrowGren(float gren_number) { - local string cmd; - - if (cvar(FOCMD_GRENTIMER) != 2) { - switch(gren_number) { - case 1: - cmd = "gren1_server\n"; - break; - case 2: - cmd = "gren2_server\n"; - break; - } - - localcmd(cmd); - return; - } - - if (!IsValidToUseGrenades()) - return; - - local float tfstate = getstatf(STAT_TFSTATE); - - if (cs_grenprimed || (tfstate & TFSTATE_GRENPRIMED)) { - localcmd("throwgren\n"); - printf("cs_grenprimed: %f\n", cs_grenprimed); - return; - } - - if (RemainingGrenades(gren_number) <= 0) { - localsound("error.wav", CHAN_AUTO, 1); - print("No grenades left\n"); - return; - } - - ShowGrenadeTimer(gren_number); - - switch(gren_number) { - case 1: - cmd = "prime1_server\n"; - break; - case 2: - cmd = "prime2_server\n"; - break; - } - - localcmd(cmd); -} - -void ShowGrenadeTimer(float gren_number) { - cs_grenprimed = TRUE; - - local float grentimer_channel; - local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); - local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); - - if (chan_gren1_soundtime == -1 ) { - grentimer_channel = CHAN_GREN1; - } else if (chan_gren2_soundtime == -1 ) { - grentimer_channel = CHAN_GREN2; - } else if (chan_gren1_soundtime > chan_gren2_soundtime) { - grentimer_channel = CHAN_GREN1; - } else { - grentimer_channel = CHAN_GREN2; - } - - localsound(cvar_string(FOCMD_GRENTIMERSOUND), grentimer_channel, 1); - - local float grentype = GetGrenTypeForClass(gren_number, SBAR.PlayerClass); - AddGrenTimer(grentype); -} - -float RemainingGrenades(float gren_number) { - switch (gren_number) { - case 1: - return getstatf(STAT_NO_GREN1); - case 2: - return getstatf(STAT_NO_GREN2); - } -} - -float IsValidToUseGrenades() { - if (prematch) - return FALSE; - - if (round_over) - return FALSE; - - if (SBAR.GameMode && (SBAR.GameMode & GAMEMODE_VOTE)) - return FALSE; - - if ((SBAR.GameMode & GAMEMODE_QUAD) && !round_active) - return FALSE; - - if (getstatf(STAT_HEALTH) <= 0) - return FALSE; - - return TRUE; -} diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 37ebad37..524364ae 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -182,22 +182,12 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-gren1", TF_GRENADE_T, 0); TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); - //Don't send to fte - these are handled client-side - if(!csqcactive) { - TeamFortress_Alias("primeone", TF_GRENADE_1, 0); - TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); - TeamFortress_Alias("+gren1", TF_GRENADE_1, 0); - TeamFortress_Alias("+gren2", TF_GRENADE_2, 0); - TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); - TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); - } else { - TeamFortress_Alias("prime1_server", TF_GRENADE_1, 0); - TeamFortress_Alias("prime2_server", TF_GRENADE_2, 0); - TeamFortress_Alias("gren1_server", TF_GRENADE_PT_1, 0); - TeamFortress_Alias("gren2_server", TF_GRENADE_PT_2, 0); - TeamFortress_AliasString("+gren1", "primeone"); - TeamFortress_AliasString("+gren2", "primetwo"); - } + TeamFortress_Alias("primeone", TF_GRENADE_1, 0); + TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); + TeamFortress_Alias("+gren1", TF_GRENADE_1, 0); + TeamFortress_Alias("+gren2", TF_GRENADE_2, 0); + TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); + TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); } else if (self.motd == 80) { TeamFortress_Alias("dash", TF_DASH, 0); TeamFortress_Alias("autoscan", TF_SCAN, 0); From 369bf5aeeb4fcd69cecb731f47ae5980a3c47b3e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 11 Feb 2022 03:25:29 +1100 Subject: [PATCH 1423/2474] No need to check every frame for gren thrown --- csqc/events.qc | 3 +++ csqc/main.qc | 6 ------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 1eddb959..93dd31a6 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -105,6 +105,9 @@ void() CSQC_Parse_Event = { float timertype = cvar(FOCMD_GRENTIMER); ParseGrenPrimed(grentype, timertype); break; + case MSG_GRENTHROWN: + ApplyTransparencyToGrenTimer(); + break; case MSG_CLIENT_MENU: float menutype = readfloat(); switch (menutype) { diff --git a/csqc/main.qc b/csqc/main.qc index afe0a2da..892abe0c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -122,12 +122,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } } - local float tfstate = getstatf(STAT_TFSTATE); - - if (tfstate & TFSTATE_GRENTHROWING) { - ApplyTransparencyToGrenTimer(); - } - clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! From 3255a139dd7ba7003f9b94afb56abbfb357b7773 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 11 Feb 2022 11:20:43 +1100 Subject: [PATCH 1424/2474] Don't check for death every frame, push a message to stop gren timers on death instead --- csqc/events.qc | 3 +++ csqc/main.qc | 24 ++++++++++++------------ share/commondefs.qc | 1 + ssqc/player.qc | 3 +++ ssqc/status.qc | 9 +++++++++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 93dd31a6..0027c6e4 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -108,6 +108,9 @@ void() CSQC_Parse_Event = { case MSG_GRENTHROWN: ApplyTransparencyToGrenTimer(); break; + case MSG_PLAYERDIE: + StopGrenTimers(); + break; case MSG_CLIENT_MENU: float menutype = readfloat(); switch (menutype) { diff --git a/csqc/main.qc b/csqc/main.qc index 892abe0c..cd4f4d87 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -11,6 +11,7 @@ void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); +void StopGrenTimers(); float RemainingGrenades(float gren_number); float IsValidToUseGrenades(); @@ -110,18 +111,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; speed = sqrt(vel.x * vel.x + vel.y * vel.y); - //stop grentimer on death - if(oldhealth <= 0) { - soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); - soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); - - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - FO_Hud_Grentimers[i].grentype = 0; - FO_Hud_Grentimers[i].expires = 0; - FO_Hud_Grentimers[i].icon_index = 0; - } - } - clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -347,3 +336,14 @@ void ApplyTransparencyToGrenTimer() { } } } + +void StopGrenTimers() { + soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); + soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); + + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + FO_Hud_Grentimers[i].grentype = 0; + FO_Hud_Grentimers[i].expires = 0; + FO_Hud_Grentimers[i].icon_index = 0; + } +} diff --git a/share/commondefs.qc b/share/commondefs.qc index e5a6c50f..787f52e6 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -32,6 +32,7 @@ #define MSG_VOTE_MAP_ADD 20 #define MSG_VOTE_MAP_DELETE 21 #define MSG_GRENADESETTINGS 22 +#define MSG_PLAYERDIE 23 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/player.qc b/ssqc/player.qc index 22d1afa4..dd8c2eb3 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -913,6 +913,8 @@ void () GibPlayer = { }; void () PlayerDie = { + UpdateClientPlayerDie(self); + local float i; local entity te; @@ -952,6 +954,7 @@ void () PlayerDie = { GibPlayer(); return; } + DeathSound(); self.angles_x = 0; self.angles_z = 0; diff --git a/ssqc/status.qc b/ssqc/status.qc index c68b7f24..6a27f7ba 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -815,6 +815,15 @@ void UpdateClientGrenadeThrown(entity pl) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientPlayerDie(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_PLAYERDIE); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientIDString(entity pl) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From 57df9585ddd4881ea2545b4bbc0c705e3cc38f89 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 12 Feb 2022 01:08:04 +1100 Subject: [PATCH 1425/2474] Fix overlapping constants --- share/defs.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/share/defs.h b/share/defs.h index 35fce05c..57b15ffd 100644 --- a/share/defs.h +++ b/share/defs.h @@ -445,9 +445,7 @@ #define TF_ENGINEER_DETSENTRY 79 // Engineer: Detonate sentry gun for Engineer #define TF_DISCARD_DROP_AMMO 80 #define TF_PRACSPAWN_PLACE 81 -#define TF_PRACSPAWN_REMOVE 80 -// unused 81 -// unused 82 +#define TF_PRACSPAWN_REMOVE 82 // unused 83 // unused 84 // unused 85 From 44c36ae45bb55ce8e472581ff6e94043ed35bbe2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 12 Feb 2022 01:08:26 +1100 Subject: [PATCH 1426/2474] Keep orientation when placing pracice spaw --- ssqc/actions.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index b9222022..eea725b7 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -912,6 +912,7 @@ void TeamFortress_PlacePracticeSpawn(entity e) = ps.movetype = MOVETYPE_NONE; ps.solid = SOLID_NOT; ps.classname = "practicespawn"; + ps.angles = e.angles; setsize(ps, '0 0 0', '0 0 0'); setorigin(ps, e.origin + '0 0 8'); FO_SetModel(ps, "progs/s_light.spr"); From de741c973eb93969bc31b60efe6d36202ac31879 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Sun, 13 Feb 2022 23:14:06 +1100 Subject: [PATCH 1427/2474] track specified settings, allow users to request list of current settings being tracked and value --- ssqc/admin.qc | 4 ++-- ssqc/commands.qc | 14 +++++++++++++- ssqc/qw.qc | 15 +++++++++++++++ ssqc/tforthlp.qc | 1 + ssqc/world.qc | 30 ++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 3 deletions(-) diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 2f106f82..bb80ed1a 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -277,8 +277,7 @@ void (string cl_pwd) Admin_Check = } }; -void () Admin_Aliases = -{ +void () Admin_Aliases = { TeamFortress_Alias("countplayers", TF_ADMIN_COUNTPLAYERS, 0); TeamFortress_Alias("deal", TF_ADMIN_CYCLEDEAL, 0); TeamFortress_Alias("kick", TF_ADMIN_KICK, 0); @@ -294,3 +293,4 @@ void () Admin_Aliases = TeamFortress_Alias("readystatus", TF_ADMIN_READYSTATUS, 0); stuffcmd(self,"alias ceasefire \"cmd ceasefire\"\n"); }; + diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1e7b3a2a..fb123932 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -299,6 +299,15 @@ void (entity pl) PrintWho = { strunzone(msg); } +void () OutputTrackedSettings = { + bprint(PRINT_HIGH, self.netname, " called for a settings check (fo_settings_status)\n"); + for (float i = 0; i < settings_to_track_list.length; i++) + { + setting_t* s = &settings_to_track[i]; + bprint(PRINT_HIGH, "Setting ", s.setting_name, " is currently ", s.value, "\n"); + } +} + float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; @@ -313,9 +322,12 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { + case "fo_settings_status": + OutputTrackedSettings(); + break; case "progsversion": // yy.mm.dd.incremented vers - sprint(self, PRINT_HIGH, "sv progs version: 21.03.25.1\n"); + sprint(self, PRINT_HIGH, "sv progs version: 22.02.13.1\n"); break; case "adminpwd": processedCmd = TRUE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ff14aedc..5b6b9c7e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -754,3 +754,18 @@ string goal_class_names[7] = { .float special_cooldown; .float airblast_cooldown; + + +// people complain about settings, let's track them + +string settings_to_track_list[2] = { + "sv_antilag", + "project_weapons" +}; + +typedef struct setting_t { + string setting_name; + string value; +}; + +setting_t *settings_to_track; \ No newline at end of file diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 1f47fb97..981959da 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -262,6 +262,7 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("break", "cmd break"); TeamFortress_AliasString("voteyes", "cmd voteyes"); TeamFortress_AliasString("yes", "cmd voteyes"); + TeamFortress_AliasString("fo_settings_status", "cmd fo_settings_status"); Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) diff --git a/ssqc/world.qc b/ssqc/world.qc index d6501c9f..74066b52 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -1,4 +1,5 @@ void () InitBodyQue; +void () CheckTrackedSettings string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; void () main = { @@ -355,6 +356,15 @@ void () worldspawn = { } dimension_send = DMN_NOFLASH; + + settings_to_track = memalloc(sizeof(*settings_to_track)*settings_to_track_list.length); + for (float i = 0; i < settings_to_track_list.length; i++) + { + settings_to_track[i].setting_name = settings_to_track_list[i]; + string val = infokey(world, settings_to_track_list[i]); + val = (val != "") ? val : "unset"; + settings_to_track[i].value = val; + } }; void () StartFrame = { @@ -363,6 +373,13 @@ void () StartFrame = { fraglimit = cvar("fraglimit"); deathmatch = cvar("deathmatch"); framecount = framecount + 1; + + if (framecount % 77 == 0) + { + CheckTrackedSettings(); + } + + // if(!votemode) { // //TODO: make this optional // Vote_Check(); @@ -420,3 +437,16 @@ void(void() fnc)CheckSpawn = { remove(self); } }; + +void () CheckTrackedSettings = { + for (float i = 0; i < settings_to_track_list.length; i++) + { + setting_t* s = &settings_to_track[i]; + string new_val = infokey(world, s.setting_name); + if (new_val != s.value) + { + bprint(PRINT_HIGH, "Setting ", s.setting_name, " has been changed from ", s.value, " to ", new_val, "\n"); + s.value = new_val; + } + } +} \ No newline at end of file From d2eb7e5b78bcd05701a0a2fffa7b57a44d7338a0 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 14 Feb 2022 23:13:19 +1100 Subject: [PATCH 1428/2474] fix auto bunny breaking when a jump bind is used. Fix it for normal +jump binds, not just aux_jump (now redundant command, kept for compat) --- csqc/csextradefs.qc | 1 + csqc/main.qc | 30 +++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index fae68d09..45c1b40c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -528,6 +528,7 @@ vector thisorigin; vector lastorigin; float nextoriginupdate; float speed; +float jump_counter; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index 21e24448..68fa6bc1 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -81,6 +81,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { player_menu_type = 0; is_admin = FALSE; grentimer_waiting = FALSE; + jump_counter = 0; num_mapvotes = 0; vote_selected_item = world; vote_selected_index = -1; @@ -311,10 +312,18 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd tracktarget\n"); break; case "+aux_jump": - localcmd("+jump"); + case "+jump": + input_buttons = input_buttons&2; + jump_counter = jump_counter + 1; break; case "-aux_jump": - localcmd("-jump"); + case "-jump": + jump_counter = jump_counter - 1; + if (jump_counter <= 0) { + jump_counter = 0; + input_buttons &= ~2; + } + break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -346,7 +355,22 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { - + if (input_buttons&2 && getstatf(STAT_HEALTH) > 0) { + if (pmove_onground) { + frames_since_onground = 0; + } else { + + // next two frames after leaving ground + if (frames_since_onground <= 2) { + frames_since_onground = frames_since_onground + 1; + + // third frame after leaving ground + } else if (frames_since_onground == 3) { + input_buttons &= ~2; + frames_since_onground = frames_since_onground + 1; + } + } + } } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { From fdf2249e003c840119fabfcd5a9ebe3141b4a2a4 Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Mon, 14 Feb 2022 23:18:30 +1100 Subject: [PATCH 1429/2474] fix missing global def --- csqc/csextradefs.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index a3b37b1b..020c16f9 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -531,6 +531,7 @@ vector lastorigin; float nextoriginupdate; float speed; float jump_counter; +float grentimer_waiting; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; From a873ee9a938403ab8162f456e5a339c52fddcc24 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 16 Feb 2022 20:17:03 +1100 Subject: [PATCH 1430/2474] Small fixes --- csqc/csextradefs.qc | 1 - csqc/events.qc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index eabdd47b..0baac8c2 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -93,7 +93,6 @@ float round_time_remaining; float showingscores; float mapvote_expiry; float cs_grenprimed; -float pending_prime_or_throw_command; float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; diff --git a/csqc/events.qc b/csqc/events.qc index 0027c6e4..72223296 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,7 +1,7 @@ void ParseSBAR(); void ParseGrenPrimed(float grentype, float timertype); void AddGrenTimer(float grentype, float offset); -void PlayGrenTimer(float antilag); +void PlayGrenTimer(float offset); void() CSQC_Parse_Event = { float msgtype = readbyte(); From 764f84d50784b11c188e7ff34ae9f68593931d51 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 18 Feb 2022 00:37:27 +1100 Subject: [PATCH 1431/2474] Allow up to five grentimers to play at once --- csqc/events.qc | 29 ++++++++--------------------- csqc/hud_helpers.qc | 23 +++++++++++++++++++---- csqc/main.qc | 3 +++ csqc/status.qc | 1 + share/defs.h | 7 +++++-- share/fteextensions.qc | 2 -- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 72223296..9a017a52 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,7 +1,10 @@ void ParseSBAR(); void ParseGrenPrimed(float grentype, float timertype); void AddGrenTimer(float grentype, float offset); -void PlayGrenTimer(float offset); +void AddSilentGrenTimer(float grentype, float offset); +void StartGrenTimer(float slot, float grentype, float offset); +void AddGrenTimer(float grentype, float offset); +void PlayGrenTimer(float channel, float offset); void() CSQC_Parse_Event = { float msgtype = readbyte(); @@ -307,40 +310,24 @@ void() CSQC_Parse_Event = { } } -void PlayGrenTimer(float offset) { - local float chan_gren1_soundtime = getsoundtime(self, CHAN_GREN1); - local float chan_gren2_soundtime = getsoundtime(self, CHAN_GREN2); - local float grentimer_channel; - - if (chan_gren1_soundtime == -1 ) { - grentimer_channel = CHAN_GREN1; - } else if (chan_gren2_soundtime == -1 ) { - grentimer_channel = CHAN_GREN2; - } else if (chan_gren1_soundtime > chan_gren2_soundtime) { - grentimer_channel = CHAN_GREN1; - } else { - grentimer_channel = CHAN_GREN2; - } - - local string grentimer_sound = cvar_string(FOCMD_GRENTIMERSOUND); - soundupdate(self, grentimer_channel, grentimer_sound, 1, 0, 0, 0, offset); +void PlayGrenTimer(float channel, float offset) { + local string sound = cvar_string(FOCMD_GRENTIMERSOUND); + soundupdate(self, channel, sound, 1, 0, 0, 0, offset); } void ParseGrenPrimed(float grentype, float timertype) { if(timertype == 0) { - AddGrenTimer(grentype, 0); + AddSilentGrenTimer(grentype, 0); return; } if(timertype == 1) { - PlayGrenTimer(0); AddGrenTimer(grentype, 0); return; } if(timertype == 2) { local float offset = getplayerkeyfloat(player_localnum, INFOKEY_P_PING)/1000; - PlayGrenTimer(offset); AddGrenTimer(grentype, offset); return; } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index a33c9c86..fd4d9836 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -487,11 +487,26 @@ vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, ve void AddGrenTimer(float grentype, float offset) { for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype == 0) { - FO_Hud_Grentimers[i].grentype = grentype; - FO_Hud_Grentimers[i].icon_index = grentype; - FO_Hud_Grentimers[i].alpha = 1; - FO_Hud_Grentimers[i].expires = time + 3.8 - offset; + StartGrenTimer(i, grentype, offset); + local float channel = CHAN_GREN1 + i; + PlayGrenTimer(channel, offset); break; } } } + +void AddSilentGrenTimer(float grentype, float offset) { + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { + if(FO_Hud_Grentimers[i].grentype == 0) { + StartGrenTimer(i, grentype, offset); + break; + } + } +} + +void StartGrenTimer(float slot, float grentype, float offset) { + FO_Hud_Grentimers[slot].grentype = grentype; + FO_Hud_Grentimers[slot].icon_index = grentype; + FO_Hud_Grentimers[slot].alpha = 1; + FO_Hud_Grentimers[slot].expires = time + 3.8 - offset; +} diff --git a/csqc/main.qc b/csqc/main.qc index cd4f4d87..c985c75e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -340,6 +340,9 @@ void ApplyTransparencyToGrenTimer() { void StopGrenTimers() { soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); + soundupdate(self, CHAN_GREN3, "", 0, 0, 0, 0, 0); + soundupdate(self, CHAN_GREN4, "", 0, 0, 0, 0, 0); + soundupdate(self, CHAN_GREN5, "", 0, 0, 0, 0, 0); for(float i = 0; i < FO_Hud_Grentimers.length; i++) { FO_Hud_Grentimers[i].grentype = 0; diff --git a/csqc/status.qc b/csqc/status.qc index 77412928..3a29e8f8 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -111,6 +111,7 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { panel2.TextScale = panel.TextScale; panel2.Display = panel.Display; panel2.FillSize = panel.FillSize; + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype > 0) { timeleft = floor(FO_Hud_Grentimers[i].expires - time) + 1; diff --git a/share/defs.h b/share/defs.h index 57b15ffd..d5f96b53 100644 --- a/share/defs.h +++ b/share/defs.h @@ -173,9 +173,12 @@ #define CHAN_VOICE 2 #define CHAN_ITEM 3 #define CHAN_BODY 4 -#define CHAN_GREN1 5 -#define CHAN_GREN2 6 #define CHAN_NO_PHS_ADD 8 +#define CHAN_GREN1 9 +#define CHAN_GREN2 10 +#define CHAN_GREN3 11 +#define CHAN_GREN4 12 +#define CHAN_GREN5 13 #define ATTN_NONE 0 #define ATTN_NORM 1 diff --git a/share/fteextensions.qc b/share/fteextensions.qc index 1fc9bcec..7fc00a9e 100644 --- a/share/fteextensions.qc +++ b/share/fteextensions.qc @@ -841,8 +841,6 @@ const float CHAN_WEAPON = 1; const float CHAN_VOICE = 2; const float CHAN_ITEM = 3; const float CHAN_BODY = 4; -const float CHAN_GREN1 = 5; -const float CHAN_GREN2 = 6; #endif #if defined(QWSSQC) From f3f1dd935cfc9894a2887c90f80a175b5de03490 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 18 Feb 2022 10:46:30 +1100 Subject: [PATCH 1432/2474] Don't show blast hud icon when cuss gren selected, refactor --- csqc/csextradefs.qc | 8 +- csqc/events.qc | 5 - csqc/status.qc | 2 + share/commondefs.qc | 3 +- share/defs.h | 14 ++- ssqc/client.qc | 27 +++--- ssqc/combat.qc | 20 ++-- ssqc/csmenu.qc | 12 --- ssqc/items.qc | 38 ++++---- ssqc/tfort.qc | 222 ++++++++++++++++++++++++-------------------- ssqc/tsoldier.qc | 104 ++++++++++++++++++--- ssqc/weapons.qc | 4 +- 12 files changed, 269 insertions(+), 190 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 0baac8c2..733c8172 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -182,7 +182,7 @@ typedef struct string icon; } FO_Hud_Icons; -FO_Hud_Icons HudIcons2[37] = { +FO_Hud_Icons HudIcons2[39] = { {ICON_CLIPSIZE}, {ICON_FRAGSTREAK}, {ICON_CAPS}, @@ -197,6 +197,8 @@ FO_Hud_Icons HudIcons2[37] = { {ICON_GREN_NAPALM}, {ICON_GREN_CALTROP}, {ICON_GREN_BLAST}, + {ICON_GREN_SHOCK}, + {ICON_GREN_BURST}, {ICON_IDENTIFY}, {ICON_SCOUT}, {ICON_SNIPER}, @@ -222,7 +224,7 @@ FO_Hud_Icons HudIcons2[37] = { {"textures/wad/anum_percent"} }; -FO_Hud_Icons GrenadeIcons[12] = { +FO_Hud_Icons GrenadeIcons[14] = { {ICON_GREN_NONE}, {ICON_GREN_NORMAL}, {ICON_GREN_CONCUSSION}, @@ -235,6 +237,8 @@ FO_Hud_Icons GrenadeIcons[12] = { {ICON_GREN_FLASH}, {ICON_GREN_CALTROP}, {ICON_GREN_BLAST}, + {ICON_GREN_SHOCK}, + {ICON_GREN_BURST}, }; FO_Hud_Icons FaceIcons[] = { diff --git a/csqc/events.qc b/csqc/events.qc index 9a017a52..11279cb1 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -271,11 +271,6 @@ void() CSQC_Parse_Event = { round_time_remaining = time + rtr; } break; - case MSG_GRENADESETTINGS: - fo_flash = readfloat(); - medic_type = readfloat(); - nailgren_type = readfloat(); - break; case MSG_TEAM_SCORES: TeamScore[0] = readfloat(); TeamScore[1] = readfloat(); diff --git a/csqc/status.qc b/csqc/status.qc index 3a29e8f8..f0af6e32 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -137,6 +137,7 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { } Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon, FO_Hud_Grentimers[i].alpha); + panel2.Position = panel2.Position + [0, panel2.FillSize.y * panel2.Scale]; timercount++; } @@ -1184,3 +1185,4 @@ float GetGrenTypeForClass(float gren_number, float playerclass) { } } } + diff --git a/share/commondefs.qc b/share/commondefs.qc index 787f52e6..b8a1a29c 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -31,8 +31,7 @@ #define MSG_VOTE_UPDATE 19 #define MSG_VOTE_MAP_ADD 20 #define MSG_VOTE_MAP_DELETE 21 -#define MSG_GRENADESETTINGS 22 -#define MSG_PLAYERDIE 23 +#define MSG_PLAYERDIE 22 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/share/defs.h b/share/defs.h index d5f96b53..7fa1f6fe 100644 --- a/share/defs.h +++ b/share/defs.h @@ -772,9 +772,11 @@ #define GR_TYPE_FLASH 9 #define GR_TYPE_CALTROP 10 #define GR_TYPE_BLAST 11 +#define GR_TYPE_SHOCK 12 +#define GR_TYPE_BURST 13 // Defines for NailGren Types -#define NGR_TYPE_DEFAULT 0 +#define NGR_TYPE_NAIL 0 #define NGR_TYPE_LASER 1 #define NGR_TYPE_BURST 2 @@ -866,7 +868,7 @@ #define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned #define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned #define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned -#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_FLASH // <- 1st Type of Grenade this class has +/* #define PC_SCOUT_GRENADE_TYPE_1 // Configured in TeamFortress_SetEquipment() */ #define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has #define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned #define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned @@ -926,7 +928,7 @@ #define PC_SOLDIER_INITAMMO_CELL 0 #define PC_SOLDIER_INITAMMO_ROCKET 10 #define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL +/* #define PC_SOLDIER_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_SOLDIER_GRENADE_INIT_1 4 #define PC_SOLDIER_GRENADE_INIT_2 1 #define PC_SOLDIER_GRENADE_MAX_1 4 @@ -989,7 +991,7 @@ #define PC_MEDIC_INITAMMO_ROCKET 0 #define PC_MEDIC_INITAMMO_MEDIKIT 50 #define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_BLAST +/* #define PC_MEDIC_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_MEDIC_GRENADE_INIT_1 3 #define PC_MEDIC_GRENADE_INIT_2 2 #define PC_MEDIC_GRENADE_MAX_1 4 @@ -1335,6 +1337,8 @@ #define DMSG_DISPENSER_EXPLODE 39 #define DMSG_GREN_PIPE_AIR 40 #define DMSG_GREN_CALTROP 41 +#define DMSG_GREN_SHOCK 42 +#define DMSG_GREN_BURST 43 /*======================================================*/ /* Menus */ @@ -1449,6 +1453,8 @@ #define ICON_GREN_FLARE "textures/wad/gren_flare.png" #define ICON_GREN_CALTROP "textures/wad/gren_caltrop.png" #define ICON_GREN_BLAST "textures/wad/gren_blast.png" +#define ICON_GREN_SHOCK "textures/wad/gren_nail.png" +#define ICON_GREN_BURST "textures/wad/gren_nail.png" #define ICON_SCOUT "textures/wad/scout.png" #define ICON_SNIPER "textures/wad/sniper.png" #define ICON_SOLDIER "textures/wad/soldier.png" diff --git a/ssqc/client.qc b/ssqc/client.qc index 680adbf7..0b2123df 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -388,7 +388,7 @@ void () DecodeLevelParms = { spurs_flag = CF_GetSetting("spf", "spurs_flag" , "0"); // can climb with flag - // nail gren types 0 = NGR_TYPE_DEFAULT, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST + // nail gren types 0 = NGR_TYPE_NAIL, 1 = NGR_TYPE_LASER, 2 = NGR_TYPE_BURST nailgren_type = CF_GetSetting("ngt", "nailgren_type", ftos(NGR_TYPE_LASER)); // medic types 0 = MEDIC_TYPE_DEFAULT, 1 = MEDIC_TYPE_BLAST @@ -938,7 +938,7 @@ void () DecodeLevelParms = { old_ng_rof = TRUE; scoutdash = FALSE; fo_flash = FALSE; - nailgren_type = NGR_TYPE_DEFAULT; + nailgren_type = NGR_TYPE_NAIL; medic_type = MEDIC_TYPE_DEFAULT; Role_None.detpipe_limit = 7; detpipe_limit_world = 7; @@ -2101,8 +2101,6 @@ void () PutClientInServer = { if (self.playerclass == 0 && self.team_no > 0) { Menu_Class(0); } - - UpdateClientGrenadeSettings(self); }; //void () info_player_start = { @@ -3038,11 +3036,11 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage s_deathstring = " grenades himself\n"; return strcat(pe_target.netname, s_deathstring); } else if (pf_deathmsg == DMSG_GREN_NAIL) { - if (nailgren_type == NGR_TYPE_LASER) { - return strcat(pe_target.netname, " electrocutes himself\n"); - } else { - return strcat(pe_target.netname, " hammers himself\n"); - } + return strcat(pe_target.netname, " hammers himself\n"); + } else if (pf_deathmsg == DMSG_GREN_SHOCK) { + return strcat(pe_target.netname, " electrocutes himself\n"); + } else if (pf_deathmsg == DMSG_GREN_BURST) { + return strcat(pe_target.netname, " peppers himself\n"); } else if (pf_deathmsg == DMSG_GREN_MIRV) { if (pe_target.playerclass == PC_DEMOMAN) s_deathstring = " practiced his own Mirv dance\n"; @@ -3144,13 +3142,14 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage } } else if (pf_deathmsg == DMSG_GREN_NAIL) { - if (nailgren_type == NGR_TYPE_LASER) { - s_deathstring = " gets melted by "; - s_deathstring2 = "'s shock grenade\n"; - } else { s_deathstring = " gets flayed by "; s_deathstring2 = "'s nail grenade\n"; - } + } else if (pf_deathmsg == DMSG_GREN_SHOCK) { + s_deathstring = " gets melted by "; + s_deathstring2 = "'s shock grenade\n"; + } else if (pf_deathmsg == DMSG_GREN_BURST) { + s_deathstring = " gets peppered by "; + s_deathstring2 = "'s burst grenade\n"; } else if (pf_deathmsg == DMSG_GREN_MIRV) { if (pe_attacker.playerclass == PC_DEMOMAN) { s_deathstring = " does a dance on "; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 7ceb4c71..970510a0 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -520,29 +520,27 @@ void (entity targ, entity inflictor, entity attacker, float damage, targ.dmg_inflictor = inflictor; } - if (!(T_AttackType & TF_TD_NOMOMENTUM)) - { - if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && - !(targ.tfstate & TFSTATE_CANT_MOVE)) { - if (deathmsg != DMSG_GREN_NAIL) { - + if (!(T_AttackType & TF_TD_NOMOMENTUM)) { + if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && !(targ.tfstate & TFSTATE_CANT_MOVE)) { + if (deathmsg != DMSG_GREN_NAIL && deathmsg != DMSG_GREN_SHOCK && deathmsg != DMSG_GREN_BURST) { targ.immune_to_check = time + damage / 20; - dir = - targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; + dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; dir = normalize(dir); - moment = damage; + if (inflictor.classname == "pyro_rocket" && pyro_type == 1) { moment = damage * 1.25; + if (attacker == targ) { moment = damage * 1.5; - } - else { + } else { moment = damage * 1.25; } } + if (targ.playerclass == PC_HVYWEAP) { moment = moment / 4; + if (damage <= 50) moment = 0; } diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 7d9d073b..66c0e986 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -302,18 +302,6 @@ void UpdateClientPrematch(entity pl, float countdownstarted) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -void UpdateClientGrenadeSettings(entity pl) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_GRENADESETTINGS); - WriteFloat(MSG_MULTICAST, fo_flash); - WriteFloat(MSG_MULTICAST, medic_type); - WriteFloat(MSG_MULTICAST, nailgren_type); - multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); -} - void UpdateClientMapVote(entity pl, entity candidate) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE) || !candidate) return; diff --git a/ssqc/items.qc b/ssqc/items.qc index eb3f1f0c..78067b43 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -739,36 +739,32 @@ void (entity pl, float typ) PrintGrenadeType = { local string st; st = ""; - if (typ == 1) { + if (typ == GR_TYPE_NORMAL) { st = "normal"; - } else if (typ == 2) { + } else if (typ == GR_TYPE_CONCUSSION) { st = "concussion"; - } else if (typ == 3) { - if (nailgren_type == NGR_TYPE_LASER) { - st = "shock"; - } else { - st = "nail"; - } - } else if (typ == 4) { + } else if (typ == GR_TYPE_NAIL) { + st = "nail"; + } else if (typ == GR_TYPE_MIRV) { st = "mirv"; - } else if (typ == 5) { + } else if (typ == GR_TYPE_NAPALM) { st = "napalm"; - } else if (typ == 6) { + } else if (typ == GR_TYPE_FLARE) { st = "flare"; - } else if (typ == 7) { + } else if (typ == GR_TYPE_GAS) { st = "gas"; - } else if (typ == 8) { + } else if (typ == GR_TYPE_EMP) { st = "EMP"; - } else if (typ == 10) { + } else if (typ == GR_TYPE_CALTROP) { st = "caltrop"; - } else if (typ == 9) { + } else if (typ == GR_TYPE_FLASH) { st = "flash"; - } else if (typ == 11) { - if (medic_type == MEDIC_TYPE_BLAST) { - st = "blast"; - } else { - st = "concussion"; - } + } else if (typ == GR_TYPE_BLAST) { + st = "blast"; + } else if (typ == GR_TYPE_SHOCK) { + st = "shock"; + } else if (typ == GR_TYPE_BURST) { + st = "burst"; } sprint(pl, PRINT_HIGH, st); }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b3123645..82e2636e 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -425,7 +425,7 @@ string GetGrenName(float type) s = "normal grenade"; break; case GR_TYPE_NAIL: - s = (nailgren_type == NGR_TYPE_LASER) ? "shock grenade" : "nail grenade"; + s = "nail grenade"; break; case GR_TYPE_MIRV: s = "mirv grenade"; @@ -452,7 +452,13 @@ string GetGrenName(float type) s = "concussion grenade"; break; case GR_TYPE_BLAST: - s = (medic_type == MEDIC_TYPE_BLAST) ? "blast grenade" : "concussion grenade"; + s = "blast grenade"; + break; + case GR_TYPE_SHOCK: + s = "shock grenade"; + break; + case GR_TYPE_BURST: + s = "burst grenade"; break; case GR_TYPE_NONE: s = "no grenade"; @@ -773,45 +779,40 @@ void (float inp) TeamFortress_PrimeGrenade = { local entity timer; gtype = 0; - if ((self.tfstate & TFSTATE_GRENPRIMED) || - (self.tfstate & TFSTATE_GRENTHROWING)) + if ((self.tfstate & TFSTATE_GRENPRIMED) || (self.tfstate & TFSTATE_GRENTHROWING)) return; if (no_fire_mode) return; - if ( (inp == 1 && self.tp_grenade_switch != 1) - || (inp == 2 && self.tp_grenade_switch == 1)) { + if ((inp == 1 && self.tp_grenade_switch != 1) || (inp == 2 && self.tp_grenade_switch == 1)) { + gtype = self.tp_grenades_1; - if (self.tp_grenades_1 == 2) + if (gtype == GR_TYPE_CONCUSSION) gs = "Concussion grenade"; - else if (self.tp_grenades_1 == 3) { - if (nailgren_type == NGR_TYPE_LASER) { - gs = "Shock grenade"; - } else { - gs = "Nail grenade"; - } - } else if (self.tp_grenades_1 == 4) + else if (gtype == GR_TYPE_NAIL) { + gs = "Nail grenade"; + } else if (gtype == GR_TYPE_MIRV) gs = "Mirv grenade"; - else if (self.tp_grenades_1 == 5) + else if (gtype == GR_TYPE_NAPALM) gs = "Napalm grenade"; - else if (self.tp_grenades_1 == 6) + else if (gtype == GR_TYPE_FLARE) gs = "Flare"; - else if (self.tp_grenades_1 == 7) + else if (gtype == GR_TYPE_GAS) gs = "Gas grenade"; - else if (self.tp_grenades_1 == 8) + else if (gtype == GR_TYPE_EMP) gs = "EMP grenade"; - else if (self.tp_grenades_1 == 9) + else if (gtype == GR_TYPE_FLASH) gs = "Flash grenade"; - else if (self.tp_grenades_1 == 10) + else if (gtype == GR_TYPE_CALTROP) gs = "Caltrop canister"; - else if (self.tp_grenades_1 == 11) - if (medic_type == MEDIC_TYPE_BLAST) { - gs = "Blast grenade"; - } else { - gs = "Concussion grenade"; - } + else if (gtype == GR_TYPE_BLAST) + gs = "Blast grenade"; + else if (gtype == GR_TYPE_SHOCK) + gs = "Shock grenade"; + else if (gtype == GR_TYPE_BURST) + gs = "Burst grenade"; else gs = "Grenade"; @@ -852,36 +853,33 @@ void (float inp) TeamFortress_PrimeGrenade = { return; } } - if ( (inp == 2 && self.tp_grenade_switch != 1) - || (inp == 1 && self.tp_grenade_switch == 1)) { + + if ( (inp == 2 && self.tp_grenade_switch != 1) || (inp == 1 && self.tp_grenade_switch == 1)) { + gtype = self.tp_grenades_2; - if (self.tp_grenades_2 == 2) + if (gtype == GR_TYPE_CONCUSSION) gs = "Concussion grenade"; - else if (self.tp_grenades_2 == 3) { - if (nailgren_type == NGR_TYPE_LASER) { - gs = "Shock grenade"; - } else { - gs = "Nail grenade"; - } - } else if (self.tp_grenades_2 == 4) + else if (gtype == GR_TYPE_NAIL) + gs = "Nail grenade"; + else if (gtype == GR_TYPE_MIRV) gs = "Mirv grenade"; - else if (self.tp_grenades_2 == 5) + else if (gtype == GR_TYPE_NAPALM) gs = "Napalm grenade"; - else if (self.tp_grenades_2 == 6) + else if (gtype == GR_TYPE_FLARE) gs = "Flare"; - else if (self.tp_grenades_2 == 7) + else if (gtype == GR_TYPE_GAS) gs = "Gas grenade"; - else if (self.tp_grenades_2 == 8) + else if (gtype == GR_TYPE_EMP) gs = "EMP grenade"; - else if (self.tp_grenades_2 == 9) + else if (gtype == GR_TYPE_FLASH) gs = "Flash grenade"; - else if (self.tp_grenades_2 == 11) - if (medic_type == MEDIC_TYPE_BLAST) { - gs = "Blast grenade"; - } else { - gs = "Concussion grenade"; - } + else if (gtype == GR_TYPE_BLAST) + gs = "Blast grenade"; + else if (gtype == GR_TYPE_SHOCK) + gs = "Shock grenade"; + else if (gtype == GR_TYPE_BURST) + gs = "Burst grenade"; else gs = "Grenade"; @@ -1014,6 +1012,7 @@ void () TeamFortress_GrenadePrimed = { newmis.angles = vectoangles(newmis.velocity); newmis.think = SUB_Null; newmis.nextthink = self.heat; + if (self.weapon == GR_TYPE_NORMAL) { newmis.touch = NormalGrenadeTouch; newmis.think = NormalGrenadeExplode; @@ -1029,28 +1028,30 @@ void () TeamFortress_GrenadePrimed = { newmis.avelocity = '300 300 300'; FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_BLAST) { - if (medic_type == MEDIC_TYPE_BLAST){ - newmis.touch = BlastGrenadeTouch; - newmis.think = BlastGrenadeExplode; - newmis.grenadename = "blastgrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/blastgren.mdl"); - } else { - newmis.touch = ConcussionGrenadeTouch; - newmis.think = ConcussionGrenadeExplode; - newmis.grenadename = "concussiongrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } + newmis.touch = BlastGrenadeTouch; + newmis.think = BlastGrenadeExplode; + newmis.grenadename = "blastgrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/blastgren.mdl"); } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; - if (nailgren_type == NGR_TYPE_LASER) - newmis.grenadename = "shockgrenade"; - else - newmis.grenadename = "nailgrenade"; + newmis.grenadename = "nailgrenade"; + newmis.skin = 1; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (self.weapon == GR_TYPE_SHOCK) { + newmis.touch = ShockGrenadeTouch; + newmis.think = ShockGrenadeExplode; + newmis.grenadename = "shockgrenade"; + newmis.skin = 1; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (self.weapon == GR_TYPE_BURST) { + newmis.touch = BurstGrenadeTouch; + newmis.think = BurstGrenadeExplode; + newmis.grenadename = "burstgrenade"; newmis.skin = 1; newmis.avelocity = '0 300 0'; FO_SetModel(newmis, "progs/biggren.mdl"); @@ -1125,11 +1126,7 @@ void () TeamFortress_GrenadeSwitch = { if (self.tp_grenades_1 == 2) gs = "Concussion grenade"; else if (self.tp_grenades_1 == 3) { - if (nailgren_type == NGR_TYPE_LASER) { - gs = "Shock grenade"; - } else { - gs = "Nail grenade"; - } + gs = "Nail grenade"; } else if (self.tp_grenades_1 == 4) gs = "Mirv grenade"; else if (self.tp_grenades_1 == 5) @@ -1141,11 +1138,11 @@ void () TeamFortress_GrenadeSwitch = { else if (self.tp_grenades_1 == 8) gs = "EMP grenade"; else if (self.tp_grenades_1 == 11) - if (medic_type == MEDIC_TYPE_BLAST) { - gs = "Blast grenade"; - } else { - gs = "Cuss grenade"; - } + gs = "Blast grenade"; + else if (self.tp_grenades_1 == 12) + gs = "Shock grenade"; + else if (self.tp_grenades_1 == 13) + gs = "Burst grenade"; else gs = "Grenade"; } else { @@ -1153,11 +1150,7 @@ void () TeamFortress_GrenadeSwitch = { if (self.tp_grenades_2 == 2) gs = "Concussion grenade"; else if (self.tp_grenades_2 == 3) { - if (nailgren_type == NGR_TYPE_LASER) { - gs = "Shock grenade"; - } else { - gs = "Nail grenade"; - } + gs = "Nail grenade"; } else if (self.tp_grenades_2 == 4) gs = "Mirv grenade"; else if (self.tp_grenades_2 == 5) @@ -1172,6 +1165,12 @@ void () TeamFortress_GrenadeSwitch = { gs = "Flash grenade"; else if (self.tp_grenades_2 == 10) gs = "Caltrop canister"; + else if (self.tp_grenades_2 == 11) + gs = "Blast grenade"; + else if (self.tp_grenades_2 == 12) + gs = "Shock grenade"; + else if (self.tp_grenades_2 == 13) + gs = "Burst grenade"; else gs = "Grenade"; } @@ -1731,7 +1730,19 @@ void () TeamFortress_SetEquipment = { self.max_grenades_2 = role.gren2_limits[3]; self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2; + + switch (nailgren_type) { + case NGR_TYPE_NAIL: + self.tp_grenades_2 = GR_TYPE_NAIL; + break; + case NGR_TYPE_LASER: + self.tp_grenades_2 = GR_TYPE_SHOCK; + break; + case NGR_TYPE_BURST: + self.tp_grenades_2 = GR_TYPE_BURST; + break; + } + self.tf_items = PC_SOLDIER_TF_ITEMS; self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS; @@ -1850,7 +1861,12 @@ void () TeamFortress_SetEquipment = { self.max_grenades_2 = role.gren2_limits[5]; self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2; + if(medic_type == MEDIC_TYPE_BLAST) { + self.tp_grenades_2 = GR_TYPE_BLAST; + } else { + self.tp_grenades_2 = GR_TYPE_CONCUSSION; + } + self.tf_items = PC_MEDIC_TF_ITEMS; self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS; @@ -2858,28 +2874,30 @@ void () TeamFortress_ExplodePerson = { newmis.avelocity = '300 300 300'; FO_SetModel(newmis, "progs/hgren2.mdl"); } else if (self.weapon == GR_TYPE_BLAST) { - if (medic_type == MEDIC_TYPE_BLAST) { - newmis.touch = BlastGrenadeTouch; - newmis.think = BlastGrenadeExplode; - newmis.grenadename = "blastgrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/blastgren.mdl"); - } else { - newmis.touch = ConcussionGrenadeTouch; - newmis.think = ConcussionGrenadeExplode; - newmis.grenadename = "concussiongrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } + newmis.touch = BlastGrenadeTouch; + newmis.think = BlastGrenadeExplode; + newmis.grenadename = "blastgrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/blastgren.mdl"); } else if (self.weapon == GR_TYPE_NAIL) { newmis.touch = NailGrenadeTouch; newmis.think = NailGrenadeExplode; - if (nailgren_type == NGR_TYPE_LASER) - newmis.grenadename = "shockgrenade"; - else - newmis.grenadename = "nailgrenade"; + newmis.grenadename = "nailgrenade"; + newmis.skin = 1; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (self.weapon == GR_TYPE_SHOCK) { + newmis.touch = ShockGrenadeTouch; + newmis.think = ShockGrenadeExplode; + newmis.grenadename = "shockgrenade"; + newmis.skin = 1; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (self.weapon == GR_TYPE_BURST) { + newmis.touch = BurstGrenadeTouch; + newmis.think = BurstGrenadeExplode; + newmis.grenadename = "burstgrenade"; newmis.skin = 1; newmis.avelocity = '0 300 0'; FO_SetModel(newmis, "progs/biggren.mdl"); diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 7a326bc8..07395540 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -3,6 +3,8 @@ //======================================================== void () NailGrenadeExplode; +void () ShockGrenadeExplode; +void () BurstGrenadeExplode; void () NailGrenadeNailEm; void () NailGrenadeLaunchNail; void () NailGrenLaser; @@ -18,9 +20,63 @@ void () NailGrenadeTouch = { self.avelocity = '0 0 0'; }; +void () ShockGrenadeTouch = { + if (other == self.owner) + return; + + // If the Shock Grenade hits a player, it just bounces off + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; +}; + +void () BurstGrenadeTouch = { + if (other == self.owner) + return; + + // If the Burst Grenade hits a player, it just bounces off + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; +}; + void () NailGrenadeExplode = { local entity te; + self.owner.no_active_nail_grens = self.owner.no_active_nail_grens + 1; + + if (self.owner.no_active_nail_grens >= max_active_gren2_soldier) { + te = find(world, classname, "grenade"); + + while (te) { + if ((te.owner == self.owner || te.real_owner == self.owner) && (te.no_active_nail_grens == 1)) { + if (!te.owner) + te.owner = te.real_owner; + + te.weapon = 9; + te.think = GrenadeExplode; + te.nextthink = time + 0.1; + } + + te = find(te, classname, "grenade"); + } + } + + self.no_active_nail_grens = self.owner.no_active_nail_grens; + self.movetype = MOVETYPE_FLY; + setorigin(self, self.origin + '0 0 32'); + + if(solid_nailgren) + setsize(self, '-1 -1 -1', '1 1 1'); + + self.avelocity = '0 500 0'; + self.nextthink = time + 0.7; + self.think = NailGrenadeNailEm; +}; + +void () ShockGrenadeExplode = { + local entity te; + self.owner.no_active_nail_grens = self.owner.no_active_nail_grens + 1; if (self.owner.no_active_nail_grens >= max_active_gren2_soldier) { @@ -44,20 +100,38 @@ void () NailGrenadeExplode = { } self.avelocity = '0 500 0'; self.nextthink = time + 0.7; - if (nailgren_type == NGR_TYPE_LASER) - { self.playerclass = 0; self.think = NailGrenLaser; +}; + +void () BurstGrenadeExplode = { + local entity te; + + self.owner.no_active_nail_grens = self.owner.no_active_nail_grens + 1; + if (self.owner.no_active_nail_grens >= max_active_gren2_soldier) { + + te = find(world, classname, "grenade"); + while (te) { + if ((te.owner == self.owner || te.real_owner == self.owner) && (te.no_active_nail_grens == 1)) { + if (!te.owner) + te.owner = te.real_owner; + te.weapon = 9; + te.think = GrenadeExplode; + te.nextthink = time + 0.1; + } + te = find(te, classname, "grenade"); + } } - else if (nailgren_type == NGR_TYPE_BURST) - { + self.no_active_nail_grens = self.owner.no_active_nail_grens; + self.movetype = MOVETYPE_FLY; + setorigin(self, self.origin + '0 0 32'); + if(solid_nailgren) { + setsize(self, '-1 -1 -1', '1 1 1'); + } + self.avelocity = '0 500 0'; + self.nextthink = time + 0.7; self.playerclass = 0; self.think = NailGrenBurst; - } - else - { - self.think = NailGrenadeNailEm; - } }; void () NailGrenadeNailEm = { @@ -142,7 +216,7 @@ void () NailGrenLaser = { //using self.playerclass to count thinks WriteCoord(MSG_MULTICAST, trace_endpos_z); multicast(trace_endpos, MULTICAST_PVS); - deathmsg = DMSG_GREN_NAIL; + deathmsg = DMSG_GREN_SHOCK; TF_T_Damage(trace_ent, self, self.real_owner, lasergren_damage, TF_TD_NOTTEAM, TF_TD_ELECTRICITY); } if (self.t_width < time) { @@ -157,7 +231,7 @@ void () NailGrenLaser = { //using self.playerclass to count thinks if (self.playerclass > lasergren_reqthinks) { //not >= to give an extra think so it hits start again self.owner = self.real_owner; - self.weapon = DMSG_GREN_NAIL; + self.weapon = DMSG_GREN_SHOCK; self.think = GrenadeExplode; } }; @@ -177,11 +251,11 @@ void () NailGrenBurst = { sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); - deathmsg = DMSG_GREN_NAIL; + deathmsg = DMSG_GREN_BURST; launch_spike(self.origin, v_forward); newmis.velocity = v_forward * 1000; newmis.touch = superspike_touch; - newmis.weapon = DMSG_GREN_NAIL; + newmis.weapon = DMSG_GREN_BURST; newmis.nextthink = time + burstgren_range; i++; current_yaw = anglemod(self.angles_y + 22.5); @@ -191,7 +265,7 @@ void () NailGrenBurst = { if (self.playerclass >= burstgren_count){ self.nextthink = time + 0.1; - self.weapon = DMSG_GREN_NAIL; + self.weapon = DMSG_GREN_BURST; self.think = GrenadeExplode; } }; @@ -199,7 +273,7 @@ void () NailGrenBurst = { void () TeamFortress_NailGrenInfo = { sprint(self,2,Q"\n\snailgren info - num in brackets are default - num shown are to one dec place - updated on map change\s\n"); sprint(self,2,Q"\n\s----------------------------------------------------------------------------------------------\s\n"); - sprint(self,2,Q"ngt nailgren_type ",ftos(nailgren_type)," (",ftos(NGR_TYPE_DEFAULT),") \s// 0 default, 1 laser, 2 burst \n\n"); + sprint(self,2,Q"ngt nailgren_type ",ftos(nailgren_type)," (",ftos(NGR_TYPE_NAIL),") \s// 0 default, 1 laser, 2 burst \n\n"); sprint(self,2,Q"lgrc lasergren_rotationcount ",ftos(lasergren_rotationcount)," (",ftos(NGR_LASER_DEFAULT_ROTATIONCOUNT),") \s// how many rotations to perform\n"); sprint(self,2,Q"lgrt lasergren_rotationtime ",ftos(lasergren_rotationtime)," (",ftos(NGR_LASER_DEFAULT_ROTATIONTIME),") \s// time to complete one rotation\n"); sprint(self,2,Q"lgr lasergren_range ",ftos(lasergren_range)," (",ftos(NGR_LASER_DEFAULT_RANGE),") \s// range\n"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f7848988..9af82fce 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1521,12 +1521,12 @@ void () superspike_touch = { if (other.takedamage) { spawn_touchblood(18); deathmsg = self.weapon; - if (deathmsg == DMSG_GREN_NAIL) { + if (deathmsg == DMSG_GREN_NAIL || deathmsg == DMSG_GREN_BURST) { ndmg = 40; } else { ndmg = sng_damage; - } + } if (self.owner.classname == "grenade") TF_T_Damage(other, self, self.owner.owner, ndmg, TF_TD_NOTTEAM, From 51c36c5ff5b5206e24b8c9599e5b40c50150dabe Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 18 Feb 2022 14:13:29 +1100 Subject: [PATCH 1433/2474] Use stats instead of logic to determine gren type --- csqc/main.qc | 1 - csqc/status.qc | 65 ++------------------------------------------------ share/defs.h | 3 ++- ssqc/world.qc | 3 ++- 4 files changed, 6 insertions(+), 66 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index c985c75e..4902ddf0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -12,7 +12,6 @@ void FO_WriteSettings(); void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); -float RemainingGrenades(float gren_number); float IsValidToUseGrenades(); void GetSelf() = { diff --git a/csqc/status.qc b/csqc/status.qc index f0af6e32..c4fd4c0f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -6,7 +6,6 @@ void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string, float); void Hud_DrawLMPThreshold(FO_Hud_Panel*, string, float); FO_Hud_Panel* getHudPanelPointer(float); FO_Hud_Panel* getAnyHudPanelByNamePointer(string); -float GetGrenTypeForClass(float gren_number, float playerclass); void(string panelid, float display, string text) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) @@ -69,7 +68,7 @@ void(string panelid, float display, string text) drawGren1Panel = { return; } - local float gren_type = GetGrenTypeForClass(1, playerclass); + local float gren_type = getstatf(STAT_TP_GREN1); local string icon = GrenadeIcons[gren_type].icon; drawIconPanel(panelid, display, text, icon); @@ -82,7 +81,7 @@ void(string panelid, float display, string text) drawGren2Panel = { return; } - local float gren_type = GetGrenTypeForClass(2, playerclass); + local float gren_type = getstatf(STAT_TP_GREN2); local string icon = GrenadeIcons[gren_type].icon; drawIconPanel(panelid, display, text, icon); @@ -1126,63 +1125,3 @@ vector (FO_Hud_Panel* panel) getPanelFillSize = { vector (FO_Hud_Panel* panel) getScaledPanelFillSize = { return panel.FillSize * panel.Scale; } - -float GetGrenTypeForClass(float gren_number, float playerclass) { - switch(gren_number) { - case 1: - switch(playerclass) { - case PC_SCOUT: - if(fo_flash) { - return GR_TYPE_FLASH; - } else { - return GR_TYPE_CALTROP; - } - case PC_SNIPER: - return GR_TYPE_NORMAL; - case PC_SOLDIER: - return GR_TYPE_NORMAL; - case PC_DEMOMAN: - return GR_TYPE_NORMAL; - case PC_MEDIC: - return GR_TYPE_NORMAL; - case PC_HVYWEAP: - return GR_TYPE_NORMAL; - case PC_PYRO: - return GR_TYPE_NORMAL; - case PC_SPY: - return GR_TYPE_NORMAL; - case PC_ENGINEER: - return GR_TYPE_NORMAL; - default: - return GR_TYPE_NONE; - } - case 2: - switch(playerclass) { - case PC_SCOUT: - return GR_TYPE_CONCUSSION; - case PC_SNIPER: - return GR_TYPE_FLARE; - case PC_SOLDIER: - return GR_TYPE_NAIL; - case PC_DEMOMAN: - return GR_TYPE_MIRV; - case PC_MEDIC: - if(medic_type == MEDIC_TYPE_BLAST) { - return GR_TYPE_BLAST; - } else { - return GR_TYPE_CONCUSSION; - } - case PC_HVYWEAP: - return GR_TYPE_MIRV; - case PC_PYRO: - return GR_TYPE_NAPALM; - case PC_SPY: - return GR_TYPE_GAS; - case PC_ENGINEER: - return GR_TYPE_EMP; - default: - return GR_TYPE_NONE; - } - } -} - diff --git a/share/defs.h b/share/defs.h index 7fa1f6fe..354149f1 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1486,7 +1486,8 @@ #define STAT_VELOCITY_Z 38 #define STAT_NO_GREN1 39 #define STAT_NO_GREN2 40 -#define STAT_TFSTATE 41 +#define STAT_TP_GREN1 41 +#define STAT_TP_GREN2 42 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/world.qc b/ssqc/world.qc index 48765fc6..9d162877 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -322,7 +322,8 @@ void () worldspawn = { clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); - clientstat(STAT_TFSTATE, EV_FLOAT, tfstate); + clientstat(STAT_TP_GREN1, EV_FLOAT, tp_grenades_1); + clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); entity worldspawnent; worldspawnent = spawn(); From 4e16f0baab56218981dab9fc0a39fd96e1c13a0b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 18 Feb 2022 18:47:37 +1100 Subject: [PATCH 1434/2474] Move channel selection logic to inside PlayGrenTimer --- csqc/events.qc | 23 +++++++++++++++++++++-- csqc/hud_helpers.qc | 3 +-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 11279cb1..13ca1424 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -4,7 +4,7 @@ void AddGrenTimer(float grentype, float offset); void AddSilentGrenTimer(float grentype, float offset); void StartGrenTimer(float slot, float grentype, float offset); void AddGrenTimer(float grentype, float offset); -void PlayGrenTimer(float channel, float offset); +void PlayGrenTimer(float offset); void() CSQC_Parse_Event = { float msgtype = readbyte(); @@ -305,8 +305,27 @@ void() CSQC_Parse_Event = { } } -void PlayGrenTimer(float channel, float offset) { +void PlayGrenTimer(float offset) { + local float channel; + local float soundtime; + local float highest_soundtime; + + for(float i = CHAN_GREN1; i <= CHAN_GREN5; i++) { + soundtime = getsoundtime(self, i); + + if (soundtime < 0) { + channel = i; + break; + } + + if (soundtime > highest_soundtime) { + highest_soundtime = soundtime; + channel = i; + } + } + local string sound = cvar_string(FOCMD_GRENTIMERSOUND); + localsound(sound, channel, 1); // required because soundupdate doesn't reset getsoundtime soundupdate(self, channel, sound, 1, 0, 0, 0, offset); } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index fd4d9836..2c1e3f59 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -488,8 +488,7 @@ void AddGrenTimer(float grentype, float offset) { for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype == 0) { StartGrenTimer(i, grentype, offset); - local float channel = CHAN_GREN1 + i; - PlayGrenTimer(channel, offset); + PlayGrenTimer(offset); break; } } From fc60fa063011a18e84c33c4fd4fad23ae68cd492 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 18 Feb 2022 21:36:02 +1100 Subject: [PATCH 1435/2474] Add grentimer volume --- README.md | 1 + csqc/csextradefs.qc | 1 + csqc/events.qc | 4 ++-- csqc/main.qc | 1 + csqc/settings.qc | 7 ++++++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b424e8c6..7b60cf7d 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ New features * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press * CSQC - fo_grentimersound grentimer.wav +* CSQC - fo_grentimervolume * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 733c8172..09064e09 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -519,6 +519,7 @@ enum { #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_GRENTIMERSOUND "fo_grentimersound" +#define FOCMD_GRENTIMERVOLUME "fo_grentimervolume" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" #define FOCMD_FTE_HUD "fo_fte_hud" diff --git a/csqc/events.qc b/csqc/events.qc index 13ca1424..52504a03 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -325,8 +325,8 @@ void PlayGrenTimer(float offset) { } local string sound = cvar_string(FOCMD_GRENTIMERSOUND); - localsound(sound, channel, 1); // required because soundupdate doesn't reset getsoundtime - soundupdate(self, channel, sound, 1, 0, 0, 0, offset); + localsound(sound, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime + soundupdate(self, channel, sound, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); } void ParseGrenPrimed(float grentype, float timertype) { diff --git a/csqc/main.qc b/csqc/main.qc index 4902ddf0..70620de5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -36,6 +36,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_GRENTIMER, "1"); registercvar(FOCMD_GRENTIMERSOUND, "grentimer.wav"); + registercvar(FOCMD_GRENTIMERVOLUME, "1"); registercvar(FOCMD_OLDSCOREBOARD, "0"); registercvar(FOCMD_FTE_HUD, "0"); diff --git a/csqc/settings.qc b/csqc/settings.qc index 80d3b894..3a52b82b 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -5,6 +5,7 @@ void FO_WriteSettings() filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, cvar_string(FOCMD_GRENTIMERSOUND)); + line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, cvar_string(FOCMD_GRENTIMERVOLUME)); line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(cvar(FOCMD_OLDSCOREBOARD))); fputs(filehandle, line); fclose(filehandle); @@ -14,6 +15,7 @@ void FO_LoadDefaultSettings() { cvar_set(FOCMD_GRENTIMER, "1"); cvar_set(FOCMD_GRENTIMERSOUND, "grentimer.wav"); + cvar_set(FOCMD_GRENTIMERVOLUME, "1"); cvar_set(FOCMD_OLDSCOREBOARD, "0"); } @@ -24,7 +26,7 @@ void FO_LoadSettings() float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_READ); if (filehandle >= 0) { - // get number of lines + // get number of lines string ln; ln = fgets(filehandle); while (ln) @@ -49,6 +51,9 @@ void FO_LoadSettings() case FOCMD_GRENTIMERSOUND: cvar_set(FOCMD_GRENTIMERSOUND, val); break; + case FOCMD_GRENTIMERVOLUME: + cvar_set(FOCMD_GRENTIMERVOLUME, val); + break; case FOCMD_OLDSCOREBOARD: cvar_set(FOCMD_OLDSCOREBOARD, val); break; From 851b7eae67d707ae2b522e1e2475bdd93d056b52 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Feb 2022 02:18:27 +1100 Subject: [PATCH 1436/2474] Remove unneeded declarations --- csqc/csextradefs.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 09064e09..e31c52d0 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -82,9 +82,6 @@ float is_admin; float motd_expiry; float quad_round; float quad_rounds_total; -float fo_flash; -float medic_type; -float nailgren_type; //float game_started; float prematch; float round_active; From 664311b0d08006674aeff37034c933505377fa50 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Feb 2022 02:19:20 +1100 Subject: [PATCH 1437/2474] Play sound on sentry death, closes #720 --- ssqc/sentry.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 0f9cf411..4e27cf24 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -374,8 +374,8 @@ void () Sentry_Explode = { }; void () Sentry_Die = { - sprint(self.real_owner, PRINT_HIGH, - "Your sentry gun was destroyed\n"); + sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); + FO_Sound(self.real_owner, CHAN_AUTO, "misc/chink.wav", 1, ATTN_NORM); self.real_owner.has_sentry = 0; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; From 8c95f27f13967c07a6722720fbfeea908031e80f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Feb 2022 02:39:49 +1100 Subject: [PATCH 1438/2474] Fix assault cannon not responding to reloadnext --- ssqc/weapons.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 32ab9e4f..28e16479 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1920,9 +1920,8 @@ float (float weap) CheckForAmmo = { if (self.reload_rocket_launcher >= 1 && self.ammo_rockets > self.reload_rocket_launcher) return 1; } else if (weap == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > self.reload_assault_cannon) + if (fo_hwguy) { + if (self.reload_assault_cannon >= 1 && self.ammo_shells > self.reload_assault_cannon) return 1; } } From ef060232a54e34ffb33d0a0c6a71befb785ca677 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Feb 2022 02:58:48 +1100 Subject: [PATCH 1439/2474] Don't show timer for caltrop or flare. Resolves #681 --- csqc/hud_helpers.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 2c1e3f59..93724fc0 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -485,6 +485,9 @@ vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, ve } void AddGrenTimer(float grentype, float offset) { + if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) + return; + for(float i = 0; i < FO_Hud_Grentimers.length; i++) { if(FO_Hud_Grentimers[i].grentype == 0) { StartGrenTimer(i, grentype, offset); From e88563582fac2d6074547ada394590b6e0624501 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Feb 2022 21:19:35 +1100 Subject: [PATCH 1440/2474] Don't let the world hear the sentry down sound --- ssqc/sentry.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 4e27cf24..1624c715 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -375,7 +375,7 @@ void () Sentry_Explode = { void () Sentry_Die = { sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); - FO_Sound(self.real_owner, CHAN_AUTO, "misc/chink.wav", 1, ATTN_NORM); + stuffcmd(self.owner, "play misc/chink\n"); self.real_owner.has_sentry = 0; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; From b66db4199506f37c7d7f322c0166e438b13a76cc Mon Sep 17 00:00:00 2001 From: Danni Uptlen Date: Sat, 19 Feb 2022 22:20:30 +1100 Subject: [PATCH 1441/2474] fix it --- csqc/csextradefs.qc | 1 + csqc/main.qc | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 0baac8c2..a829d6d5 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -529,6 +529,7 @@ vector thisorigin; vector lastorigin; float nextoriginupdate; float speed; +float jump_counter; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index cd4f4d87..aab4605d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -82,6 +82,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { current_vote = world; vote_list_filter = ""; MouseDown = 0; + jump_counter = 0; }; noref void() CSQC_WorldLoaded = { @@ -277,10 +278,15 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd tracktarget\n"); break; case "+aux_jump": + jump_counter = jump_counter + 1; localcmd("+jump\n"); break; case "-aux_jump": - localcmd("-jump\n"); + jump_counter = jump_counter - 1; + if (jump_counter <= 0) { + jump_counter = 0; + localcmd("-jump\n"); + } break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); From ed64aa0abe32b07eadb796d88cac4ade603a4738 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Feb 2022 22:30:07 +1100 Subject: [PATCH 1442/2474] Include file extension duh --- ssqc/sentry.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 1624c715..05f8d07f 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -375,7 +375,7 @@ void () Sentry_Explode = { void () Sentry_Die = { sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); - stuffcmd(self.owner, "play misc/chink\n"); + stuffcmd(self.owner, "play misc/chink.wav\n"); self.real_owner.has_sentry = 0; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; From 4bd22685adf4ca789b74492812b510773c436ef1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Feb 2022 22:32:56 +1100 Subject: [PATCH 1443/2474] And send it to the right person --- ssqc/sentry.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 05f8d07f..201151ec 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -375,7 +375,7 @@ void () Sentry_Explode = { void () Sentry_Die = { sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); - stuffcmd(self.owner, "play misc/chink.wav\n"); + stuffcmd(self.real_owner, "play misc/chink.wav\n"); self.real_owner.has_sentry = 0; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; From 3a70d3c0a97ef68b90ef8231f5cf9df453ecf2cc Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Tue, 22 Feb 2022 03:09:35 +1100 Subject: [PATCH 1444/2474] backpack changes --- ssqc/actions.qc | 7 ++++++- ssqc/client.qc | 12 ++++++++++++ ssqc/items.qc | 28 ++++++++++++++++++++++------ ssqc/qw.qc | 6 ++++++ ssqc/spy.qc | 7 ++++++- ssqc/world.qc | 2 ++ 6 files changed, 54 insertions(+), 8 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index eea725b7..17c066c4 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -116,7 +116,12 @@ void () TeamFortress_Discard = { newmis.nextthink = time + 30; newmis.think = SUB_Remove; newmis.touch = TeamFortress_AmmoboxTouch; - FO_SetModel(newmis, "progs/backpack.mdl"); + + if(seperatebackpackmodels) + FO_SetModel(newmis, "progs/discard.mdl"); + else + FO_SetModel(newmis, "progs/backpack.mdl"); + }; void () TeamFortress_Discard_DropAmmo = { diff --git a/ssqc/client.qc b/ssqc/client.qc index 680adbf7..5f21426d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -763,6 +763,18 @@ void () DecodeLevelParms = { // allow clients to place a personal practice spawn [off] allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); + + // seperate backpack.mdl into deathbag.mdl and discard.mdl [off] (visual change only) + seperatebackpackmodels = CF_GetSetting("sbm", "seperatebackpackmodels", "0"); + + // standardize contents of backpack dropped on a players death [off] + standardizedeathammo = CF_GetSetting("sda", "standardizedeathammo", "0"); + + // if standardizedeathbags set to 1 use these settings instead of players ammo to fill bag on death + deathammo_shells = CF_GetSetting("das", "deathammo_shells", "25"); + deathammo_nails = CF_GetSetting("dan", "deathammo_nails", "25"); + deathammo_cells = CF_GetSetting("dac", "deathammo_cells", "50"); + deathammo_rockets = CF_GetSetting("dar", "deathammo_rockets", "10"); // enable server-side flaginfo on statusbar [on] // server_sbflaginfo = CF_GetSetting("ssbfi", "server_sbflaginfo", "1"); diff --git a/ssqc/items.qc b/ssqc/items.qc index eb3f1f0c..3fc106bd 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -1338,7 +1338,7 @@ void () BackpackTouch = { sprint(other, PRINT_LOW, s, " cells "); } if ((self.armorvalue && (other.playerclass == 9)) && - (other.ammo_cells < other.maxammo_cells)) { + (other.ammo_cells < other.maxammo_cells) && !standardizedeathammo) { s = ftos(self.armorvalue); sprint(other, PRINT_LOW, s, " metal "); other.ammo_cells = other.ammo_cells + self.armorvalue; @@ -1366,10 +1366,21 @@ void () DropBackpack = { newmis = spawn(); newmis.origin = self.origin - '0 0 24'; - newmis.ammo_shells = self.ammo_shells; - newmis.ammo_nails = self.ammo_nails; - newmis.ammo_rockets = self.ammo_rockets; - newmis.ammo_cells = self.ammo_cells; + if(standardizedeathammo) + { + newmis.ammo_shells = deathammo_shells; + newmis.ammo_nails = deathammo_nails; + newmis.ammo_rockets = deathammo_rockets; + newmis.ammo_cells = deathammo_cells; + } + else + { + newmis.ammo_shells = self.ammo_shells; + newmis.ammo_nails = self.ammo_nails; + newmis.ammo_rockets = self.ammo_rockets; + newmis.ammo_cells = self.ammo_cells; + } + if (drop_grenpack) { if (drop_gren1 == -1) newmis.no_grenades_1 = self.no_grenades_1; @@ -1398,7 +1409,12 @@ void () DropBackpack = { newmis.flags = FL_ITEM; newmis.solid = SOLID_TRIGGER; newmis.movetype = MOVETYPE_TOSS; - FO_SetModel(newmis, "progs/backpack.mdl"); + + if(seperatebackpackmodels) + FO_SetModel(newmis, "progs/deathbag.mdl"); + else + FO_SetModel(newmis, "progs/backpack.mdl"); + setsize(newmis, '-16 -16 0', '16 16 56'); newmis.touch = BackpackTouch; newmis.classname = "backpack"; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index efb5d24f..42feaea0 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -617,6 +617,12 @@ float noreturn; float nohitsounds; float nokeepcells; float allowpracspawns; +float seperatebackpackmodels; +float standardizedeathammo; +float deathammo_shells; +float deathammo_nails; +float deathammo_rockets; +float deathammo_cells; //float server_sbflaginfo; float reverse_cap; float engineer_move; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 6c0d1084..c018804c 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1458,7 +1458,12 @@ void () Spy_DropBackpack = { newmis.flags = FL_ITEM; newmis.solid = SOLID_TRIGGER; newmis.movetype = MOVETYPE_TOSS; - FO_SetModel(newmis, "progs/backpack.mdl"); + + if(seperatebackpackmodels) + FO_SetModel(newmis, "progs/deathbag.mdl"); + else + FO_SetModel(newmis, "progs/backpack.mdl"); + setsize(newmis, '-16 -16 0', '16 16 56'); newmis.touch = BackpackTouch; newmis.classname = "backpack"; diff --git a/ssqc/world.qc b/ssqc/world.qc index 48765fc6..6604a708 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -259,6 +259,8 @@ void () worldspawn = { precache_model2("progs/grenade2.mdl"); precache_model2("progs/v_grap.mdl"); precache_model2("progs/caltrop.mdl"); + precache_model2("progs/deathbag.mdl"); + precache_model2("progs/discard.mdl"); precache_sound("doors/baseuse.wav"); precache_sound("doors/medtry.wav"); precache_sound2("speech/saveme1.wav"); From 5a505c59b51c2442f772ea2f60f2e34ef5ba24d9 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Tue, 22 Feb 2022 03:17:12 +1100 Subject: [PATCH 1445/2474] backpack changes --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b424e8c6..97de171e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ +* `localinfo seperatebackpackmodels 1` server setting to have different visual models for bags dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. * Added ``localinfo nomapcycle 1`` to stop all the confusion. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. From 0055c76eb3e6cb2380afadeccfa22737597f040a Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Tue, 22 Feb 2022 03:24:59 +1100 Subject: [PATCH 1446/2474] backpack changes --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 97de171e..5be399a5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ FortressOne Server New features ------ -* `localinfo seperatebackpackmodels 1` server setting to have different visual models for bags dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` +* `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values +* `localinfo seperatebackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. * Added ``localinfo nomapcycle 1`` to stop all the confusion. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. From 3e51a93273f318b4fd95af410bf51e19a9909f0e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Mar 2022 02:44:13 +1100 Subject: [PATCH 1447/2474] Make knife it's own weapon --- share/defs.h | 4 +- ssqc/player.qc | 8 ++++ ssqc/spy.qc | 2 +- ssqc/weapons.qc | 113 +++++++++++++++++++++++++++++++++--------------- 4 files changed, 90 insertions(+), 37 deletions(-) diff --git a/share/defs.h b/share/defs.h index 354149f1..3953cc3f 100644 --- a/share/defs.h +++ b/share/defs.h @@ -700,7 +700,7 @@ /*======================================================*/ #define WEAP_HOOK 1 -// unused 2 +#define WEAP_KNIFE 2 #define WEAP_MEDIKIT 4 #define WEAP_SPANNER 8 #define WEAP_AXE 16 @@ -1105,7 +1105,7 @@ #define PC_SPY_INITARMORTYPE 0.6 #define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION #define PC_SPY_INITARMORCLASS 0 -#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN +#define PC_SPY_WEAPONS WEAP_KNIFE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN #define PC_SPY_MAXAMMO_SHOT 40 #define PC_SPY_MAXAMMO_NAIL 100 #define PC_SPY_MAXAMMO_CELL 30 diff --git a/ssqc/player.qc b/ssqc/player.qc index dd8c2eb3..54156205 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -175,6 +175,8 @@ void () player_axe3 =[121, player_axe4] { self.weaponframe = 3; if (self.current_weapon == WEAP_AXE) W_FireAxe(); + else if (self.current_weapon == WEAP_KNIFE) + W_FireKnife(); else W_FireSpanner(); }; @@ -195,6 +197,8 @@ void () player_axeb3 =[127, player_axeb4] { self.weaponframe = 7; if (self.current_weapon == WEAP_AXE) W_FireAxe(); + else if (self.current_weapon == WEAP_KNIFE) + W_FireKnife(); else W_FireSpanner(); }; @@ -215,6 +219,8 @@ void () player_axec3 =[133, player_axec4] { self.weaponframe = 3; if (self.current_weapon == WEAP_AXE) W_FireAxe(); + else if (self.current_weapon == WEAP_KNIFE) + W_FireKnife(); else W_FireSpanner(); }; @@ -235,6 +241,8 @@ void () player_axed3 =[139, player_axed4] { self.weaponframe = 7; if (self.current_weapon == WEAP_AXE) W_FireAxe(); + else if (self.current_weapon == WEAP_KNIFE) + W_FireKnife(); else W_FireSpanner(); }; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 6c0d1084..3adc8193 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -580,7 +580,7 @@ void (float issilent) CF_Spy_FeignDeath = { te = find(te, classname, "item_tfgoal"); } - // die with axe equipped if carrying axe, medikit or spanner + // die with axe equipped if carrying axe, medikit, knife or spanner if (self.weapon <= WEAP_AXE) { spy_die_ax1(); return; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e5555816..00408efe 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -181,6 +181,36 @@ void () W_FireAxe = { local vector org; local vector def; + makevectors(self.v_angle); + source = self.origin + '0 0 16'; + traceline(source, source + v_forward * 64, FALSE, self); + if (trace_fraction == 1) + return; + + org = trace_endpos - v_forward * 4; + if (trace_ent.takedamage) { + trace_ent.axhitme = 1; + SpawnBlood(org, 20); + + deathmsg = DMSG_AXE; + TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); + } else { // hit wall + FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_GUNSHOT); + WriteByte(MSG_MULTICAST, 3); + WriteCoord(MSG_MULTICAST, org_x); + WriteCoord(MSG_MULTICAST, org_y); + WriteCoord(MSG_MULTICAST, org_z); + multicast(org, MULTICAST_PVS); + } +}; + +void () W_FireKnife = { + local vector source; + local vector org; + local vector def; + makevectors(self.v_angle); source = self.origin + '0 0 16'; traceline(source, source + v_forward * 64, FALSE, self); @@ -193,31 +223,24 @@ void () W_FireAxe = { trace_ent.axhitme = 1; SpawnBlood(org, 20); - if ((self.playerclass != PC_SPY) || - (trace_ent.classname != "player")) { - deathmsg = DMSG_AXE; - TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, - TF_TD_OTHER); + self.weaponmode = 1; + self.weaponmodel = "progs/v_knife2.mdl"; + + // Check direction of Attack + makevectors(trace_ent.v_angle); + def = v_right; + makevectors(self.v_angle); + + // Backstab + if (crossproducttf(def, v_forward) > 0) { + deathmsg = DMSG_BACKSTAB; + TF_T_Damage(trace_ent, self, self, 120, + TF_TD_NOTTEAM | TF_TD_IGNOREARMOR, + TF_TD_OTHER); } else { - self.weaponmode = 1; - self.weaponmodel = "progs/v_knife2.mdl"; - - // Check direction of Attack - makevectors(trace_ent.v_angle); - def = v_right; - makevectors(self.v_angle); - - // Backstab - if (crossproducttf(def, v_forward) > 0) { - deathmsg = DMSG_BACKSTAB; - TF_T_Damage(trace_ent, self, self, 120, - TF_TD_NOTTEAM | TF_TD_IGNOREARMOR, - TF_TD_OTHER); - } else { - deathmsg = DMSG_AXE; - TF_T_Damage(trace_ent, self, self, 40, TF_TD_NOTTEAM, - TF_TD_OTHER); - } + deathmsg = DMSG_AXE; + TF_T_Damage(trace_ent, self, self, 40, TF_TD_NOTTEAM, + TF_TD_OTHER); } } else { // hit wall FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); @@ -1559,13 +1582,14 @@ void (entity pl) W_SetCurrentAmmo = { if (pl.current_weapon == WEAP_AXE) { pl.currentammo = 0; - if (pl.playerclass == 8) { - if (pl.weaponmode == 0) - pl.weaponmodel = "progs/v_knife.mdl"; - else - pl.weaponmodel = "progs/v_knife2.mdl"; - } else - pl.weaponmodel = "progs/v_axe.mdl"; + pl.weaponmodel = "progs/v_axe.mdl"; + pl.weaponframe = 0; + } else if (pl.current_weapon == WEAP_KNIFE) { + pl.currentammo = 0; + if (pl.weaponmode == 0) + pl.weaponmodel = "progs/v_knife.mdl"; + else + pl.weaponmodel = "progs/v_knife2.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_SPANNER) { pl.currentammo = pl.ammo_cells; @@ -1740,6 +1764,8 @@ float () W_BestWeapon = { return WEAP_SHOTGUN; else if (it & WEAP_MEDIKIT) return WEAP_MEDIKIT; + else if (it & WEAP_KNIFE) + return WEAP_KNIFE; else if (it & WEAP_SPANNER) return WEAP_SPANNER; else if (it & WEAP_AXE) @@ -1779,8 +1805,10 @@ void () W_ChangeToBestWeapon = { } float () W_CheckNoAmmo = { - if (self.current_weapon == WEAP_AXE || self.current_weapon == WEAP_SPANNER - || self.current_weapon == WEAP_MEDIKIT) + if (self.current_weapon == WEAP_AXE + || self.current_weapon == WEAP_SPANNER + || self.current_weapon == WEAP_KNIFE + || self.current_weapon == WEAP_MEDIKIT) return 1; else if (self.current_weapon == WEAP_SUPER_NAILGUN && self.currentammo >= 4) return 1; @@ -1983,6 +2011,18 @@ void () W_Attack = { player_axec1(); else player_axed1(); + } else if (self.current_weapon == WEAP_KNIFE) { + Attack_Finished(0.5); + FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + r = random(); + if (r < 0.25) + player_axe1(); + else if (r < 0.5) + player_axeb1(); + else if (r < 0.75) + player_axec1(); + else + player_axed1(); } else if (self.current_weapon == WEAP_SPANNER) { Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); @@ -2193,6 +2233,7 @@ float (float weap) W_GetSlot = { float (float weap) W_OldGetSlot = { if (weap == WEAP_AXE + || weap == WEAP_KNIFE || weap == WEAP_MEDIKIT || weap == WEAP_SPANNER) return 1; @@ -2364,6 +2405,8 @@ float (float inp) W_OldAmmoSlot = { float () W_OldWeaponSlot1 = { if (self.weapons_carried & WEAP_MEDIKIT) return WEAP_MEDIKIT; + else if (self.weapons_carried & WEAP_KNIFE) + return WEAP_KNIFE; else if (self.weapons_carried & WEAP_SPANNER) return WEAP_SPANNER; else @@ -2499,6 +2542,8 @@ float () W_WeaponSlot3 = { float () W_WeaponSlot4 = { if (self.weapons_carried & WEAP_MEDIKIT) return WEAP_MEDIKIT; + else if (self.weapons_carried & WEAP_KNIFE) + return WEAP_KNIFE; else if (self.weapons_carried & WEAP_SPANNER) return WEAP_SPANNER; else @@ -2662,7 +2707,7 @@ float (float newSlot) W_OldImpulseFromNewSlot = { return W_OldGetSlot(WEAP_AXE); } else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_AXE); + return W_OldGetSlot(WEAP_KNIFE); } else if (self.playerclass == PC_ENGINEER) { return W_OldGetSlot(WEAP_SPANNER); From e77490d438d0c65ccf07902bca3572c83817fd33 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Mar 2022 03:43:24 +1100 Subject: [PATCH 1448/2474] Make knife attack on all four frames --- ssqc/player.qc | 88 ++++++++++++++++++++++++++++++++++++++++++++----- ssqc/weapons.qc | 13 +++++--- 2 files changed, 89 insertions(+), 12 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 54156205..3f35cd2d 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -175,8 +175,6 @@ void () player_axe3 =[121, player_axe4] { self.weaponframe = 3; if (self.current_weapon == WEAP_AXE) W_FireAxe(); - else if (self.current_weapon == WEAP_KNIFE) - W_FireKnife(); else W_FireSpanner(); }; @@ -197,8 +195,6 @@ void () player_axeb3 =[127, player_axeb4] { self.weaponframe = 7; if (self.current_weapon == WEAP_AXE) W_FireAxe(); - else if (self.current_weapon == WEAP_KNIFE) - W_FireKnife(); else W_FireSpanner(); }; @@ -219,8 +215,6 @@ void () player_axec3 =[133, player_axec4] { self.weaponframe = 3; if (self.current_weapon == WEAP_AXE) W_FireAxe(); - else if (self.current_weapon == WEAP_KNIFE) - W_FireKnife(); else W_FireSpanner(); }; @@ -241,8 +235,6 @@ void () player_axed3 =[139, player_axed4] { self.weaponframe = 7; if (self.current_weapon == WEAP_AXE) W_FireAxe(); - else if (self.current_weapon == WEAP_KNIFE) - W_FireKnife(); else W_FireSpanner(); }; @@ -251,6 +243,86 @@ void () player_axed4 =[140, player_run] { self.weaponframe = 8; }; +void () player_knife1 =[119, player_knife2] { + self.weaponframe = 1; + W_FireKnife(); +}; + +void () player_knife2 =[120, player_knife3] { + self.weaponframe = 2; + W_FireKnife(); +}; + +void () player_knife3 =[121, player_knife4] { + self.weaponframe = 3; + W_FireKnife(); +}; + +void () player_knife4 =[122, player_run] { + self.weaponframe = 4; + W_FireKnife(); +}; + +void () player_knifeb1 =[125, player_knifeb2] { + self.weaponframe = 5; + W_FireKnife(); +}; + +void () player_knifeb2 =[126, player_knifeb3] { + self.weaponframe = 6; + W_FireKnife(); +}; + +void () player_knifeb3 =[127, player_knifeb4] { + self.weaponframe = 7; + W_FireKnife(); +}; + +void () player_knifeb4 =[128, player_run] { + self.weaponframe = 8; + W_FireKnife(); +}; + +void () player_knifec1 =[131, player_knifec2] { + self.weaponframe = 1; + W_FireKnife(); +}; + +void () player_knifec2 =[132, player_knifec3] { + self.weaponframe = 2; + W_FireKnife(); +}; + +void () player_knifec3 =[133, player_knifec4] { + self.weaponframe = 3; + W_FireKnife(); +}; + +void () player_knifec4 =[134, player_run] { + self.weaponframe = 4; + W_FireKnife(); +}; + +void () player_knifed1 =[137, player_knifed2] { + self.weaponframe = 5; + W_FireKnife(); +}; + +void () player_knifed2 =[138, player_knifed3] { + self.weaponframe = 6; + W_FireKnife(); +}; + +void () player_knifed3 =[139, player_knifed4] { + self.weaponframe = 7; + W_FireKnife(); +}; + +void () player_knifed4 =[140, player_run] { + self.weaponframe = 8; + W_FireKnife(); +}; + void () player_medikit1 =[119, player_medikit2] { self.weaponframe = 1; }; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 00408efe..2ef1e88c 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1962,6 +1962,11 @@ void () player_axeb1; void () player_axec1; void () player_axed1; +void () player_knife1; +void () player_knifeb1; +void () player_knifec1; +void () player_knifed1; + void () player_shot1; void () player_nail1; void () player_light1; @@ -2016,13 +2021,13 @@ void () W_Attack = { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.25) - player_axe1(); + player_knife1(); else if (r < 0.5) - player_axeb1(); + player_knifeb1(); else if (r < 0.75) - player_axec1(); + player_knifec1(); else - player_axed1(); + player_knifed1(); } else if (self.current_weapon == WEAP_SPANNER) { Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); From 23d0022ca9f2f178fd242adade46d38b5d8df928 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Mar 2022 15:05:26 +1100 Subject: [PATCH 1449/2474] Put superknife on toggle --- ssqc/client.qc | 6 ++++++ ssqc/player.qc | 36 ++++++++++++++++++++++++------------ ssqc/qw.qc | 1 + 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 0b2123df..ddf52b25 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -633,6 +633,9 @@ void () DecodeLevelParms = { // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); + // make knife hit on every frame of animation + superknife = CF_GetSetting("sk", "superknife", "on"); + // impulse command queueing // ensures detpipe impulse isn't cleared at end of function impulse_queue = CF_GetSetting("impulsequeue", "impulse_queue", "off"); @@ -826,6 +829,7 @@ void () DecodeLevelParms = { old_hp_armor = FALSE; ng_velocity = 1500; old_ng_rof = FALSE; + superknife = TRUE; pyro_type = PYRO_OZTF; Role_None.gren1_limits[1] = PC_SCOUT_GRENADE_MAX_1; Role_None.gren1_limits[2] = PC_SNIPER_GRENADE_MAX_1; @@ -900,6 +904,7 @@ void () DecodeLevelParms = { buildstatus = FALSE; old_hp_armor = TRUE; ng_velocity = 1000; + superknife = FALSE; old_ng_rof = TRUE; pyro_type = PYRO_ORIGINAL; Role_None.gren1_limits[1] = 4; @@ -935,6 +940,7 @@ void () DecodeLevelParms = { ng_velocity = 1000; ng_damage = 18; sng_damage = 26; + superknife = FALSE; old_ng_rof = TRUE; scoutdash = FALSE; fo_flash = FALSE; diff --git a/ssqc/player.qc b/ssqc/player.qc index 3f35cd2d..a14d77f3 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -245,12 +245,14 @@ void () player_axed4 =[140, player_run] { void () player_knife1 =[119, player_knife2] { self.weaponframe = 1; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knife2 =[120, player_knife3] { self.weaponframe = 2; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knife3 =[121, player_knife4] { @@ -260,17 +262,20 @@ void () player_knife3 =[121, player_knife4] { void () player_knife4 =[122, player_run] { self.weaponframe = 4; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifeb1 =[125, player_knifeb2] { self.weaponframe = 5; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifeb2 =[126, player_knifeb3] { self.weaponframe = 6; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifeb3 =[127, player_knifeb4] { @@ -280,17 +285,20 @@ void () player_knifeb3 =[127, player_knifeb4] { void () player_knifeb4 =[128, player_run] { self.weaponframe = 8; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifec1 =[131, player_knifec2] { self.weaponframe = 1; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifec2 =[132, player_knifec3] { self.weaponframe = 2; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifec3 =[133, player_knifec4] { @@ -300,17 +308,20 @@ void () player_knifec3 =[133, player_knifec4] { void () player_knifec4 =[134, player_run] { self.weaponframe = 4; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifed1 =[137, player_knifed2] { self.weaponframe = 5; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifed2 =[138, player_knifed3] { self.weaponframe = 6; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_knifed3 =[139, player_knifed4] { @@ -320,7 +331,8 @@ void () player_knifed3 =[139, player_knifed4] { void () player_knifed4 =[140, player_run] { self.weaponframe = 8; - W_FireKnife(); + if (superknife) + W_FireKnife(); }; void () player_medikit1 =[119, player_medikit2] { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index efb5d24f..4258ff28 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -592,6 +592,7 @@ float project_weapons_max_latency; float ng_velocity; float ng_damage; float sng_damage; +float superknife; float old_ng_rof; float impulse_queue; float detpack_when_reloading; From 1c9e3253e071b4f77dea579a57256175de4d5f83 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Mar 2022 15:10:58 +1100 Subject: [PATCH 1450/2474] Must have pressed undo one too many times --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2ef1e88c..2bc288f6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1950,7 +1950,7 @@ float (float weap) CheckForAmmo = { return 1; } else if (weap == WEAP_ASSAULT_CANNON) { if (fo_hwguy) { - if (self.reload_assault_cannon >= 1 && self.ammo_shells > self.reload_assault_cannon) + if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > self.reload_assault_cannon) return 1; } } From 951442ffde67c5f7ddcfd815e0c26a21c0ffbac7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Mar 2022 15:17:36 +1100 Subject: [PATCH 1451/2474] Refactor --- share/defs.h | 1 + ssqc/client.qc | 13 +++++++------ ssqc/weapons.qc | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/share/defs.h b/share/defs.h index 3953cc3f..1f4a9a08 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1339,6 +1339,7 @@ #define DMSG_GREN_CALTROP 41 #define DMSG_GREN_SHOCK 42 #define DMSG_GREN_BURST 43 +#define DMSG_KNIFE 44 /*======================================================*/ /* Menus */ diff --git a/ssqc/client.qc b/ssqc/client.qc index ddf52b25..787ba9cd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3230,9 +3230,7 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage } } else if (pf_deathmsg == DMSG_AXE) { s_deathstring2 = "\n"; - if (pe_attacker.playerclass == PC_SPY) - s_deathstring = " was knife-murdered by "; - else if (pe_attacker.playerclass == PC_SCOUT) + if (pe_attacker.playerclass == PC_SCOUT) s_deathstring = "'s mellon was split by "; else if (pe_attacker.playerclass == PC_SNIPER) s_deathstring = " was put on the chop block by "; @@ -3249,6 +3247,12 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage s_deathstring2 = "'s axe\n"; } else s_deathstring = " was ax-murdered by "; + } else if (pf_deathmsg == DMSG_KNIFE) { + s_deathstring = " was knife-murdered by "; + s_deathstring2 = "\n"; + } else if (pf_deathmsg == DMSG_BACKSTAB) { + s_deathstring = " gets knifed from behind by "; + s_deathstring2 = "\n"; } else if (pf_deathmsg == DMSG_SPANNER) { s_deathstring = " was spanner-murdered by "; s_deathstring2 = "\n"; @@ -3348,9 +3352,6 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage } else if (pf_deathmsg == DMSG_ASSAULTCANNON) { s_deathstring = " gets sawn in half by "; s_deathstring2 = "\n"; - } else if (pf_deathmsg == DMSG_BACKSTAB) { - s_deathstring = " gets knifed from behind by "; - s_deathstring2 = "\n"; } else if (pf_deathmsg == DMSG_TRANQ) { s_deathstring = " is put to sleep by "; s_deathstring2 = "\n"; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2bc288f6..f4006f89 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -238,7 +238,7 @@ void () W_FireKnife = { TF_TD_NOTTEAM | TF_TD_IGNOREARMOR, TF_TD_OTHER); } else { - deathmsg = DMSG_AXE; + deathmsg = DMSG_KNIFE; TF_T_Damage(trace_ent, self, self, 40, TF_TD_NOTTEAM, TF_TD_OTHER); } From 44fecea82c384691c6fee1f72e92683dc12ea850 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Mar 2022 15:22:16 +1100 Subject: [PATCH 1452/2474] Reapply heavy reloadnext fix --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f4006f89..c9539f3a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1950,7 +1950,7 @@ float (float weap) CheckForAmmo = { return 1; } else if (weap == WEAP_ASSAULT_CANNON) { if (fo_hwguy) { - if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > self.reload_assault_cannon) + if (self.reload_assault_cannon >= 1 && self.ammo_shells > self.reload_assault_cannon) return 1; } } From f51694e41ccd5d515cc1067bb50ea48baec7d369 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 6 Mar 2022 15:07:20 +1100 Subject: [PATCH 1453/2474] Add superknife_multihit option --- README.md | 2 ++ ssqc/client.qc | 4 ++++ ssqc/player.qc | 63 +++++++++++++++++++++++++++++++++++++++---------- ssqc/qw.qc | 1 + ssqc/weapons.qc | 1 - 5 files changed, 58 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7b60cf7d..7c125d2e 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ New features * optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * localinfo nohitsounds 1 - disables hitsounds server-wide * localinfo noreturn 1 - prevents goalitems from returning (will still return from lava) +* localinfo superknife on/off - causes the knife to hit on all four attack frames (instead of only on 3rd frame) +* localinfo superkinfe_multihit on/off - controls whether multiple hits are allowed in a single attack * scout has "new" flash grenades - localinfo fo_flash on (default on) * ability to set client side min and max flash amounts - localinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) * `cmd votemap`/`cmd showvotes`/`cmd listmaps` can now be used at any time and are part of the same system diff --git a/ssqc/client.qc b/ssqc/client.qc index 787ba9cd..1f68ee38 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -635,6 +635,7 @@ void () DecodeLevelParms = { // make knife hit on every frame of animation superknife = CF_GetSetting("sk", "superknife", "on"); + superknife_multihit = CF_GetSetting("skmh", "superknife_multihit", "on"); // impulse command queueing // ensures detpipe impulse isn't cleared at end of function @@ -830,6 +831,7 @@ void () DecodeLevelParms = { ng_velocity = 1500; old_ng_rof = FALSE; superknife = TRUE; + superknife_multihit = TRUE; pyro_type = PYRO_OZTF; Role_None.gren1_limits[1] = PC_SCOUT_GRENADE_MAX_1; Role_None.gren1_limits[2] = PC_SNIPER_GRENADE_MAX_1; @@ -905,6 +907,7 @@ void () DecodeLevelParms = { old_hp_armor = TRUE; ng_velocity = 1000; superknife = FALSE; + superknife_multihit = FALSE; old_ng_rof = TRUE; pyro_type = PYRO_ORIGINAL; Role_None.gren1_limits[1] = 4; @@ -941,6 +944,7 @@ void () DecodeLevelParms = { ng_damage = 18; sng_damage = 26; superknife = FALSE; + superknife_multihit = FALSE; old_ng_rof = TRUE; scoutdash = FALSE; fo_flash = FALSE; diff --git a/ssqc/player.qc b/ssqc/player.qc index a14d77f3..ca773744 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -12,6 +12,8 @@ void () bubble_bob; void () T_Dispenser; void () Headless_Think; +float hit_in_current_animation; // Set on knife attack if a hit is recorded to prevent combo hits + void () player_touch = { local entity Bio; local entity te; @@ -244,95 +246,132 @@ void () player_axed4 =[140, player_run] { }; void () player_knife1 =[119, player_knife2] { + hit_in_current_animation = FALSE; self.weaponframe = 1; if (superknife) + hit_in_current_animation = TRUE; W_FireKnife(); }; void () player_knife2 =[120, player_knife3] { self.weaponframe = 2; - if (superknife) + + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knife3 =[121, player_knife4] { self.weaponframe = 3; - W_FireKnife(); + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { + hit_in_current_animation = TRUE; + W_FireKnife(); + } }; void () player_knife4 =[122, player_run] { self.weaponframe = 4; - if (superknife) + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifeb1 =[125, player_knifeb2] { + hit_in_current_animation = FALSE; self.weaponframe = 5; if (superknife) + hit_in_current_animation = TRUE; W_FireKnife(); }; void () player_knifeb2 =[126, player_knifeb3] { self.weaponframe = 6; - if (superknife) + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifeb3 =[127, player_knifeb4] { self.weaponframe = 7; - W_FireKnife(); + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { + hit_in_current_animation = TRUE; + W_FireKnife(); + } }; void () player_knifeb4 =[128, player_run] { self.weaponframe = 8; - if (superknife) + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifec1 =[131, player_knifec2] { + hit_in_current_animation = FALSE; self.weaponframe = 1; if (superknife) + hit_in_current_animation = TRUE; W_FireKnife(); }; void () player_knifec2 =[132, player_knifec3] { self.weaponframe = 2; - if (superknife) + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifec3 =[133, player_knifec4] { self.weaponframe = 3; - W_FireKnife(); + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { + hit_in_current_animation = TRUE; + W_FireKnife(); + } }; void () player_knifec4 =[134, player_run] { self.weaponframe = 4; - if (superknife) + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifed1 =[137, player_knifed2] { + hit_in_current_animation = FALSE; self.weaponframe = 5; if (superknife) + hit_in_current_animation = TRUE; W_FireKnife(); }; void () player_knifed2 =[138, player_knifed3] { self.weaponframe = 6; - if (superknife) + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifed3 =[139, player_knifed4] { self.weaponframe = 7; - W_FireKnife(); + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { + hit_in_current_animation = TRUE; + W_FireKnife(); + } }; void () player_knifed4 =[140, player_run] { self.weaponframe = 8; - if (superknife) + if (superknife && (superknife_multihit || !hit_in_current_animation)) { + hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_medikit1 =[119, player_medikit2] { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4258ff28..14619848 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -593,6 +593,7 @@ float ng_velocity; float ng_damage; float sng_damage; float superknife; +float superknife_multihit; float old_ng_rof; float impulse_queue; float detpack_when_reloading; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index c9539f3a..47478d7f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -219,7 +219,6 @@ void () W_FireKnife = { org = trace_endpos - v_forward * 4; if (trace_ent.takedamage) { - trace_ent.axhitme = 1; SpawnBlood(org, 20); From 5348f92f9dac0def97865cc1e6048768b5222eee Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 6 Mar 2022 15:30:28 +1100 Subject: [PATCH 1454/2474] Woops, missing brackets --- ssqc/player.qc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index ca773744..adc1e170 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -248,9 +248,10 @@ void () player_axed4 =[140, player_run] { void () player_knife1 =[119, player_knife2] { hit_in_current_animation = FALSE; self.weaponframe = 1; - if (superknife) + if (superknife) { hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knife2 =[120, player_knife3] { @@ -281,9 +282,10 @@ void () player_knife4 =[122, player_run] { void () player_knifeb1 =[125, player_knifeb2] { hit_in_current_animation = FALSE; self.weaponframe = 5; - if (superknife) + if (superknife) { hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifeb2 =[126, player_knifeb3] { @@ -313,9 +315,10 @@ void () player_knifeb4 =[128, player_run] { void () player_knifec1 =[131, player_knifec2] { hit_in_current_animation = FALSE; self.weaponframe = 1; - if (superknife) + if (superknife) { hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifec2 =[132, player_knifec3] { @@ -345,9 +348,10 @@ void () player_knifec4 =[134, player_run] { void () player_knifed1 =[137, player_knifed2] { hit_in_current_animation = FALSE; self.weaponframe = 5; - if (superknife) + if (superknife) { hit_in_current_animation = TRUE; W_FireKnife(); + } }; void () player_knifed2 =[138, player_knifed3] { From 36c2402bd44dce35176564275ce2d90f898d1dae Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 6 Mar 2022 15:51:35 +1100 Subject: [PATCH 1455/2474] Use brackets on multi-string if statements --- ssqc/player.qc | 64 ++++++++++++++++++++++++------------------------- ssqc/weapons.qc | 6 ++++- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index adc1e170..690b72db 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -249,8 +249,8 @@ void () player_knife1 =[119, player_knife2] { hit_in_current_animation = FALSE; self.weaponframe = 1; if (superknife) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; @@ -258,24 +258,24 @@ void () player_knife2 =[120, player_knife3] { self.weaponframe = 2; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knife3 =[121, player_knife4] { self.weaponframe = 3; if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knife4 =[122, player_run] { self.weaponframe = 4; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; @@ -283,32 +283,32 @@ void () player_knifeb1 =[125, player_knifeb2] { hit_in_current_animation = FALSE; self.weaponframe = 5; if (superknife) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifeb2 =[126, player_knifeb3] { self.weaponframe = 6; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifeb3 =[127, player_knifeb4] { self.weaponframe = 7; if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifeb4 =[128, player_run] { self.weaponframe = 8; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; @@ -316,32 +316,32 @@ void () player_knifec1 =[131, player_knifec2] { hit_in_current_animation = FALSE; self.weaponframe = 1; if (superknife) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifec2 =[132, player_knifec3] { self.weaponframe = 2; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifec3 =[133, player_knifec4] { self.weaponframe = 3; if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifec4 =[134, player_run] { self.weaponframe = 4; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; @@ -349,32 +349,32 @@ void () player_knifed1 =[137, player_knifed2] { hit_in_current_animation = FALSE; self.weaponframe = 5; if (superknife) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifed2 =[138, player_knifed3] { self.weaponframe = 6; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifed3 =[139, player_knifed4] { self.weaponframe = 7; if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; void () player_knifed4 =[140, player_run] { self.weaponframe = 8; if (superknife && (superknife_multihit || !hit_in_current_animation)) { - hit_in_current_animation = TRUE; - W_FireKnife(); + if (W_FireKnife()) + hit_in_current_animation = TRUE; } }; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 47478d7f..4ce1f063 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -206,7 +206,7 @@ void () W_FireAxe = { } }; -void () W_FireKnife = { +int () W_FireKnife = { local vector source; local vector org; local vector def; @@ -241,6 +241,8 @@ void () W_FireKnife = { TF_T_Damage(trace_ent, self, self, 40, TF_TD_NOTTEAM, TF_TD_OTHER); } + + return TRUE; } else { // hit wall FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); @@ -250,6 +252,8 @@ void () W_FireKnife = { WriteCoord(MSG_MULTICAST, org_y); WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); + + return FALSE; } }; From 19a862fbce06eb0d14387879a50adb25028e4e22 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Mar 2022 00:31:16 +1100 Subject: [PATCH 1456/2474] Refactor --- ssqc/player.qc | 111 +++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 64 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 690b72db..2466c4f2 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -248,134 +248,117 @@ void () player_axed4 =[140, player_run] { void () player_knife1 =[119, player_knife2] { hit_in_current_animation = FALSE; self.weaponframe = 1; - if (superknife) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife) + hit_in_current_animation = W_FireKnife(); }; void () player_knife2 =[120, player_knife3] { self.weaponframe = 2; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_knife3 =[121, player_knife4] { self.weaponframe = 3; - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) + hit_in_current_animation = W_FireKnife(); }; void () player_knife4 =[122, player_run] { self.weaponframe = 4; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_knifeb1 =[125, player_knifeb2] { hit_in_current_animation = FALSE; self.weaponframe = 5; - if (superknife) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife) + hit_in_current_animation = W_FireKnife(); }; void () player_knifeb2 =[126, player_knifeb3] { self.weaponframe = 6; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_knifeb3 =[127, player_knifeb4] { self.weaponframe = 7; - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) + hit_in_current_animation = W_FireKnife(); }; void () player_knifeb4 =[128, player_run] { self.weaponframe = 8; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_knifec1 =[131, player_knifec2] { hit_in_current_animation = FALSE; self.weaponframe = 1; - if (superknife) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife) + hit_in_current_animation = W_FireKnife(); }; void () player_knifec2 =[132, player_knifec3] { self.weaponframe = 2; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_knifec3 =[133, player_knifec4] { self.weaponframe = 3; - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) + hit_in_current_animation = W_FireKnife(); }; void () player_knifec4 =[134, player_run] { self.weaponframe = 4; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_knifed1 =[137, player_knifed2] { hit_in_current_animation = FALSE; self.weaponframe = 5; - if (superknife) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife) + hit_in_current_animation = W_FireKnife(); }; void () player_knifed2 =[138, player_knifed3] { self.weaponframe = 6; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_knifed3 =[139, player_knifed4] { self.weaponframe = 7; - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) + hit_in_current_animation = W_FireKnife(); }; void () player_knifed4 =[140, player_run] { self.weaponframe = 8; - if (superknife && (superknife_multihit || !hit_in_current_animation)) { - if (W_FireKnife()) - hit_in_current_animation = TRUE; - } + + if (superknife && (superknife_multihit || !hit_in_current_animation)) + hit_in_current_animation = W_FireKnife(); }; void () player_medikit1 =[119, player_medikit2] { From 1c52d8efdbff531882f2a3caf889c7af1f2e4fd9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Mar 2022 02:36:09 +1100 Subject: [PATCH 1457/2474] Add superspanner --- README.md | 1 + ssqc/client.qc | 10 ++++++++- ssqc/player.qc | 49 +++++++++++++++++++++++++++------------- ssqc/qw.qc | 1 + ssqc/weapons.qc | 60 ++++++++++++++++++++++++------------------------- 5 files changed, 73 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 7c125d2e..f83ae873 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ New features * optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * localinfo nohitsounds 1 - disables hitsounds server-wide * localinfo noreturn 1 - prevents goalitems from returning (will still return from lava) +* localinfo superspanner on/off - causes the spanner to hit on all four attack frames (instead of only on 3rd frame) * localinfo superknife on/off - causes the knife to hit on all four attack frames (instead of only on 3rd frame) * localinfo superkinfe_multihit on/off - controls whether multiple hits are allowed in a single attack * scout has "new" flash grenades - localinfo fo_flash on (default on) diff --git a/ssqc/client.qc b/ssqc/client.qc index 1f68ee38..bf4b61f7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -633,8 +633,13 @@ void () DecodeLevelParms = { // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); - // make knife hit on every frame of animation + // allow spanner to hit on any frame of animation + superspanner = CF_GetSetting("ss", "superspanner", "on"); + + // allow knife to hit on any frame of animation superknife = CF_GetSetting("sk", "superknife", "on"); + + // allow knife to hit on every frame of animation superknife_multihit = CF_GetSetting("skmh", "superknife_multihit", "on"); // impulse command queueing @@ -830,6 +835,7 @@ void () DecodeLevelParms = { old_hp_armor = FALSE; ng_velocity = 1500; old_ng_rof = FALSE; + superspanner = TRUE; superknife = TRUE; superknife_multihit = TRUE; pyro_type = PYRO_OZTF; @@ -906,6 +912,7 @@ void () DecodeLevelParms = { buildstatus = FALSE; old_hp_armor = TRUE; ng_velocity = 1000; + superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; old_ng_rof = TRUE; @@ -943,6 +950,7 @@ void () DecodeLevelParms = { ng_velocity = 1000; ng_damage = 18; sng_damage = 26; + superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; old_ng_rof = TRUE; diff --git a/ssqc/player.qc b/ssqc/player.qc index 2466c4f2..82b22e49 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -175,16 +175,42 @@ void () player_axe2 =[120, player_axe3] { void () player_axe3 =[121, player_axe4] { self.weaponframe = 3; - if (self.current_weapon == WEAP_AXE) - W_FireAxe(); - else - W_FireSpanner(); + W_FireAxe(); }; void () player_axe4 =[122, player_run] { self.weaponframe = 4; }; +void () player_spanner1 =[119, player_spanner2] { + hit_in_current_animation = FALSE; + self.weaponframe = 1; + + if (superspanner) + hit_in_current_animation = W_FireSpanner(); +}; + +void () player_spanner2 =[120, player_spanner3] { + self.weaponframe = 2; + + if (superspanner && !hit_in_current_animation) + hit_in_current_animation = W_FireSpanner(); +}; + +void () player_spanner3 =[121, player_spanner4] { + self.weaponframe = 3; + + if (!superspanner || (superspanner && !hit_in_current_animation)) + hit_in_current_animation = W_FireSpanner(); +}; + +void () player_spanner4 =[122, player_run] { + self.weaponframe = 4; + + if (superspanner && !hit_in_current_animation) + hit_in_current_animation = W_FireSpanner(); +}; + void () player_axeb1 =[125, player_axeb2] { self.weaponframe = 5; }; @@ -195,10 +221,7 @@ void () player_axeb2 =[126, player_axeb3] { void () player_axeb3 =[127, player_axeb4] { self.weaponframe = 7; - if (self.current_weapon == WEAP_AXE) - W_FireAxe(); - else - W_FireSpanner(); + W_FireAxe(); }; void () player_axeb4 =[128, player_run] { @@ -215,10 +238,7 @@ void () player_axec2 =[132, player_axec3] { void () player_axec3 =[133, player_axec4] { self.weaponframe = 3; - if (self.current_weapon == WEAP_AXE) - W_FireAxe(); - else - W_FireSpanner(); + W_FireAxe(); }; void () player_axec4 =[134, player_run] { @@ -235,10 +255,7 @@ void () player_axed2 =[138, player_axed3] { void () player_axed3 =[139, player_axed4] { self.weaponframe = 7; - if (self.current_weapon == WEAP_AXE) - W_FireAxe(); - else - W_FireSpanner(); + W_FireAxe(); }; void () player_axed4 =[140, player_run] { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 14619848..bd85ade8 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -592,6 +592,7 @@ float project_weapons_max_latency; float ng_velocity; float ng_damage; float sng_damage; +float superspanner; float superknife; float superknife_multihit; float old_ng_rof; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 4ce1f063..45f862f2 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -214,8 +214,9 @@ int () W_FireKnife = { makevectors(self.v_angle); source = self.origin + '0 0 16'; traceline(source, source + v_forward * 64, FALSE, self); + if (trace_fraction == 1) - return; + return FALSE; org = trace_endpos - v_forward * 4; if (trace_ent.takedamage) { @@ -257,7 +258,7 @@ int () W_FireKnife = { } }; -void () W_FireSpanner = { +int () W_FireSpanner = { local vector source; local vector org; local float healam; @@ -266,16 +267,15 @@ void () W_FireSpanner = { makevectors(self.v_angle); source = self.origin + '0 0 16'; traceline(source, source + v_forward * 64, FALSE, self); + if (trace_fraction == 1) - return; + return FALSE; org = trace_endpos - v_forward * 4; // It may be a trigger that can be activated by the engineer's spanner if (trace_ent.goal_activation & TFGA_SPANNER) { - if (Activated(trace_ent, self)) { - DoResults(trace_ent, self, TRUE); if (trace_ent.classname == "func_button") { @@ -287,11 +287,9 @@ void () W_FireSpanner = { self = other; } } else if (trace_ent.else_goal != 0) { - te = Findgoal(trace_ent.else_goal); if (te) AttemptToActivate(te, self, trace_ent); - } else { FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); @@ -302,53 +300,46 @@ void () W_FireSpanner = { WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); } - return; + return TRUE; } - if (trace_ent.takedamage) { + if (trace_ent.takedamage) { if (trace_ent.classname == "building_dispenser") { Engineer_UseDispenser(trace_ent); - return; + return TRUE; } else if (trace_ent.classname == "building_sentrygun") { - Engineer_UseSentryGun(trace_ent); - return; + return TRUE; } else if (trace_ent.classname == "building_sentrygun_base") { - if (trace_ent.oldenemy) Engineer_UseSentryGun(trace_ent.oldenemy); - return; + return TRUE; } else if (trace_ent.classname == "player") { - - if ((((trace_ent.team_no == self.team_no) && - (self.team_no != 0)) && teamplay) || coop) { + if ((((trace_ent.team_no == self.team_no) && (self.team_no != 0)) && teamplay) || coop) { healam = WEAP_SPANNER_REPAIR; + if (self.ammo_cells < healam) healam = self.ammo_cells; + if (trace_ent.armortype == 0) - return; + return TRUE; - if ((trace_ent.maxarmor - trace_ent.armorvalue) < - (healam * 4)) - healam = - ceil((trace_ent.maxarmor - - trace_ent.armorvalue) / 4); + if ((trace_ent.maxarmor - trace_ent.armorvalue) < (healam * 4)) + healam = ceil((trace_ent.maxarmor - trace_ent.armorvalue) / 4); if (healam > 0) { + trace_ent.armorvalue = trace_ent.armorvalue + healam * 4; - trace_ent.armorvalue = - trace_ent.armorvalue + healam * 4; if (trace_ent.armorvalue > trace_ent.maxarmor) trace_ent.armorvalue = trace_ent.maxarmor; self.ammo_cells = self.ammo_cells - healam; - FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, - ATTN_NORM); + FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_GUNSHOT); @@ -357,11 +348,11 @@ void () W_FireSpanner = { WriteCoord(MSG_MULTICAST, org_y); WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); - - W_SetCurrentAmmo(self); } - return; + + return TRUE; } + trace_ent.axhitme = 1; SpawnBlood(org, 20); deathmsg = DMSG_SPANNER; @@ -369,6 +360,7 @@ void () W_FireSpanner = { } else { TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); } + return TRUE; } else { FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); @@ -378,6 +370,7 @@ void () W_FireSpanner = { WriteCoord(MSG_MULTICAST, org_y); WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); + return TRUE; } }; @@ -1965,6 +1958,11 @@ void () player_axeb1; void () player_axec1; void () player_axed1; +void () player_spanner1; +void () player_spanner2; +void () player_spanner3; +void () player_spanner4; + void () player_knife1; void () player_knifeb1; void () player_knifec1; @@ -2034,7 +2032,7 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_SPANNER) { Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); - player_axe1(); + player_spanner1(); } else if (self.current_weapon == WEAP_SHOTGUN) { if (CheckForReload() == TRUE) return; From 4cb592a3edf0ad57b24361865b830ed0dd8a2506 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 7 Mar 2022 05:13:11 +1100 Subject: [PATCH 1458/2474] seperate to split spelling mistake --- ssqc/qw.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 42feaea0..8d997db8 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -617,7 +617,7 @@ float noreturn; float nohitsounds; float nokeepcells; float allowpracspawns; -float seperatebackpackmodels; +float splitbackpackmodels; float standardizedeathammo; float deathammo_shells; float deathammo_nails; From f262832a923746060a3de9d28a37af1421728205 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 7 Mar 2022 05:14:32 +1100 Subject: [PATCH 1459/2474] spelling mistake --- ssqc/items.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/items.qc b/ssqc/items.qc index 5e7409f2..068981c9 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -1406,7 +1406,7 @@ void () DropBackpack = { newmis.solid = SOLID_TRIGGER; newmis.movetype = MOVETYPE_TOSS; - if(seperatebackpackmodels) + if(splitbackpackmodels) FO_SetModel(newmis, "progs/deathbag.mdl"); else FO_SetModel(newmis, "progs/backpack.mdl"); From 15dd09783e7837f32dabe407228d8e5bdcb18c86 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 7 Mar 2022 05:15:46 +1100 Subject: [PATCH 1460/2474] spelling mistake --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c3e59527..264ba406 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -764,8 +764,8 @@ void () DecodeLevelParms = { // allow clients to place a personal practice spawn [off] allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); - // seperate backpack.mdl into deathbag.mdl and discard.mdl [off] (visual change only) - seperatebackpackmodels = CF_GetSetting("sbm", "seperatebackpackmodels", "0"); + // split backpack.mdl into deathbag.mdl and discard.mdl [off] (visual change only) + splitbackpackmodels = CF_GetSetting("sbm", "splitbackpackmodels", "0"); // standardize contents of backpack dropped on a players death [off] standardizedeathammo = CF_GetSetting("sda", "standardizedeathammo", "0"); From f5878b70d20db0129a3e71eb3c938cbf3af9ad15 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 7 Mar 2022 05:16:36 +1100 Subject: [PATCH 1461/2474] Update spy.qc --- ssqc/spy.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index c018804c..10d670f7 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1459,7 +1459,7 @@ void () Spy_DropBackpack = { newmis.solid = SOLID_TRIGGER; newmis.movetype = MOVETYPE_TOSS; - if(seperatebackpackmodels) + if(splitbackpackmodels) FO_SetModel(newmis, "progs/deathbag.mdl"); else FO_SetModel(newmis, "progs/backpack.mdl"); From baa916bfebdf5b60d28d0106ce698ba5443a857c Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 7 Mar 2022 05:17:43 +1100 Subject: [PATCH 1462/2474] Update actions.qc --- ssqc/actions.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 17c066c4..b80388d2 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -117,7 +117,7 @@ void () TeamFortress_Discard = { newmis.think = SUB_Remove; newmis.touch = TeamFortress_AmmoboxTouch; - if(seperatebackpackmodels) + if(splitbackpackmodels) FO_SetModel(newmis, "progs/discard.mdl"); else FO_SetModel(newmis, "progs/backpack.mdl"); From 340ff83f5f975f9a4bdd21022a9d87d582bc7d7c Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 7 Mar 2022 05:18:25 +1100 Subject: [PATCH 1463/2474] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c463ae98..88e81fdc 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ New features ------ * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values -* `localinfo seperatebackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` +* `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. * Added ``localinfo nomapcycle 1`` to stop all the confusion. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. From 448e6fb3b55fda5c77ac3806ff7730fcce701c87 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Mar 2022 15:16:02 +1100 Subject: [PATCH 1464/2474] Refactor --- ssqc/player.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 82b22e49..4d77d4ab 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -183,7 +183,6 @@ void () player_axe4 =[122, player_run] { }; void () player_spanner1 =[119, player_spanner2] { - hit_in_current_animation = FALSE; self.weaponframe = 1; if (superspanner) @@ -200,7 +199,9 @@ void () player_spanner2 =[120, player_spanner3] { void () player_spanner3 =[121, player_spanner4] { self.weaponframe = 3; - if (!superspanner || (superspanner && !hit_in_current_animation)) + if (!superspanner) + W_FireSpanner(); + else if (!hit_in_current_animation) hit_in_current_animation = W_FireSpanner(); }; From cf25bd87468a5f5edfcb2c4089393a86dbc77eac Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 13 Mar 2022 14:19:42 +1100 Subject: [PATCH 1465/2474] Refactor --- ssqc/player.qc | 64 ++----------------------------------------------- ssqc/weapons.qc | 10 ++------ 2 files changed, 4 insertions(+), 70 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 4d77d4ab..d80cf151 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -264,7 +264,6 @@ void () player_axed4 =[140, player_run] { }; void () player_knife1 =[119, player_knife2] { - hit_in_current_animation = FALSE; self.weaponframe = 1; if (superknife) @@ -281,7 +280,7 @@ void () player_knife2 =[120, player_knife3] { void () player_knife3 =[121, player_knife4] { self.weaponframe = 3; - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) + if (!superknife || (superknife_multihit && !hit_in_current_animation)) hit_in_current_animation = W_FireKnife(); }; @@ -293,7 +292,6 @@ void () player_knife4 =[122, player_run] { }; void () player_knifeb1 =[125, player_knifeb2] { - hit_in_current_animation = FALSE; self.weaponframe = 5; if (superknife) @@ -310,7 +308,7 @@ void () player_knifeb2 =[126, player_knifeb3] { void () player_knifeb3 =[127, player_knifeb4] { self.weaponframe = 7; - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) + if (!superknife || (superknife_multihit && !hit_in_current_animation)) hit_in_current_animation = W_FireKnife(); }; @@ -321,64 +319,6 @@ void () player_knifeb4 =[128, player_run] { hit_in_current_animation = W_FireKnife(); }; -void () player_knifec1 =[131, player_knifec2] { - hit_in_current_animation = FALSE; - self.weaponframe = 1; - - if (superknife) - hit_in_current_animation = W_FireKnife(); -}; - -void () player_knifec2 =[132, player_knifec3] { - self.weaponframe = 2; - - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); -}; - -void () player_knifec3 =[133, player_knifec4] { - self.weaponframe = 3; - - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) - hit_in_current_animation = W_FireKnife(); -}; - -void () player_knifec4 =[134, player_run] { - self.weaponframe = 4; - - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); -}; - -void () player_knifed1 =[137, player_knifed2] { - hit_in_current_animation = FALSE; - self.weaponframe = 5; - - if (superknife) - hit_in_current_animation = W_FireKnife(); -}; - -void () player_knifed2 =[138, player_knifed3] { - self.weaponframe = 6; - - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); -}; - -void () player_knifed3 =[139, player_knifed4] { - self.weaponframe = 7; - - if (!superknife || (superknife && (superknife_multihit || !hit_in_current_animation))) - hit_in_current_animation = W_FireKnife(); -}; - -void () player_knifed4 =[140, player_run] { - self.weaponframe = 8; - - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); -}; - void () player_medikit1 =[119, player_medikit2] { self.weaponframe = 1; }; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 45f862f2..c2f75886 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1965,8 +1965,6 @@ void () player_spanner4; void () player_knife1; void () player_knifeb1; -void () player_knifec1; -void () player_knifed1; void () player_shot1; void () player_nail1; @@ -2021,14 +2019,10 @@ void () W_Attack = { Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); - if (r < 0.25) + if (r < 0.5) player_knife1(); - else if (r < 0.5) - player_knifeb1(); - else if (r < 0.75) - player_knifec1(); else - player_knifed1(); + player_knifeb1(); } else if (self.current_weapon == WEAP_SPANNER) { Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); From 21edad9a50c653de36bd0bfcdb32fcbbeb731545 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 13 Mar 2022 15:32:34 +1100 Subject: [PATCH 1466/2474] Refactor --- ssqc/player.qc | 34 ---------------------------------- ssqc/weapons.qc | 10 ++-------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index d80cf151..e0729aa1 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -229,40 +229,6 @@ void () player_axeb4 =[128, player_run] { self.weaponframe = 8; }; -void () player_axec1 =[131, player_axec2] { - self.weaponframe = 1; -}; - -void () player_axec2 =[132, player_axec3] { - self.weaponframe = 2; -}; - -void () player_axec3 =[133, player_axec4] { - self.weaponframe = 3; - W_FireAxe(); -}; - -void () player_axec4 =[134, player_run] { - self.weaponframe = 4; -}; - -void () player_axed1 =[137, player_axed2] { - self.weaponframe = 5; -}; - -void () player_axed2 =[138, player_axed3] { - self.weaponframe = 6; -}; - -void () player_axed3 =[139, player_axed4] { - self.weaponframe = 7; - W_FireAxe(); -}; - -void () player_axed4 =[140, player_run] { - self.weaponframe = 8; -}; - void () player_knife1 =[119, player_knife2] { self.weaponframe = 1; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index c2f75886..c2aff4c8 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1955,8 +1955,6 @@ float (float weap) CheckForAmmo = { void () player_axe1; void () player_axeb1; -void () player_axec1; -void () player_axed1; void () player_spanner1; void () player_spanner2; @@ -2007,14 +2005,10 @@ void () W_Attack = { Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); - if (r < 0.25) + if (r < 0.5) player_axe1(); - else if (r < 0.5) - player_axeb1(); - else if (r < 0.75) - player_axec1(); else - player_axed1(); + player_axeb1(); } else if (self.current_weapon == WEAP_KNIFE) { Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); From 4a7f0e792614e29b51ba1fd6d074c2db7aa167c1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 13 Mar 2022 15:48:11 +1100 Subject: [PATCH 1467/2474] Add superaxe --- ssqc/client.qc | 6 +++++ ssqc/player.qc | 62 +++++++++++++++++++++++++++++++++++-------------- ssqc/qw.qc | 1 + ssqc/weapons.qc | 6 +++-- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index bf4b61f7..76e7639f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -633,6 +633,9 @@ void () DecodeLevelParms = { // use old ROF for nailguns old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); + // allow axe to hit on any frame of animation + superaxe = CF_GetSetting("ss", "superaxe", "on"); + // allow spanner to hit on any frame of animation superspanner = CF_GetSetting("ss", "superspanner", "on"); @@ -835,6 +838,7 @@ void () DecodeLevelParms = { old_hp_armor = FALSE; ng_velocity = 1500; old_ng_rof = FALSE; + superaxe = TRUE; superspanner = TRUE; superknife = TRUE; superknife_multihit = TRUE; @@ -912,6 +916,7 @@ void () DecodeLevelParms = { buildstatus = FALSE; old_hp_armor = TRUE; ng_velocity = 1000; + superaxe = FALSE; superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; @@ -950,6 +955,7 @@ void () DecodeLevelParms = { ng_velocity = 1000; ng_damage = 18; sng_damage = 26; + superaxe = FALSE; superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; diff --git a/ssqc/player.qc b/ssqc/player.qc index e0729aa1..3249dca0 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -167,19 +167,62 @@ void () player_autorifle3 =[118, player_run] { void () player_axe1 =[119, player_axe2] { self.weaponframe = 1; + + if (superaxe) + hit_in_current_animation = W_FireAxe(); }; void () player_axe2 =[120, player_axe3] { self.weaponframe = 2; + + if (superaxe && !hit_in_current_animation) + hit_in_current_animation = W_FireAxe(); }; void () player_axe3 =[121, player_axe4] { self.weaponframe = 3; - W_FireAxe(); + + if (!superaxe) + W_FireAxe(); + else if (!hit_in_current_animation) + hit_in_current_animation = W_FireAxe(); }; void () player_axe4 =[122, player_run] { self.weaponframe = 4; + + if (superaxe && !hit_in_current_animation) + hit_in_current_animation = W_FireAxe(); +}; + +void () player_axeb1 =[124, player_axeb2] { + self.weaponframe = 5; + + if (superaxe) + hit_in_current_animation = W_FireAxe(); +}; + +void () player_axeb2 =[125, player_axeb3] { + self.weaponframe = 6; + + if (superaxe && !hit_in_current_animation) + hit_in_current_animation = W_FireAxe(); +}; + +void () player_axeb3 =[126, player_axeb4] { + self.weaponframe = 7; + + if (!superaxe) + W_FireAxe(); + else if (!hit_in_current_animation) + hit_in_current_animation = W_FireAxe(); +}; + +void () player_axeb4 =[127, player_run] { + self.weaponframe = 8; + + if (superaxe && !hit_in_current_animation) + hit_in_current_animation = W_FireAxe(); }; void () player_spanner1 =[119, player_spanner2] { @@ -212,23 +255,6 @@ void () player_spanner4 =[122, player_run] { hit_in_current_animation = W_FireSpanner(); }; -void () player_axeb1 =[125, player_axeb2] { - self.weaponframe = 5; -}; - -void () player_axeb2 =[126, player_axeb3] { - self.weaponframe = 6; -}; - -void () player_axeb3 =[127, player_axeb4] { - self.weaponframe = 7; - W_FireAxe(); -}; - -void () player_axeb4 =[128, player_run] { - self.weaponframe = 8; -}; - void () player_knife1 =[119, player_knife2] { self.weaponframe = 1; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bd85ade8..653e9fc1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -592,6 +592,7 @@ float project_weapons_max_latency; float ng_velocity; float ng_damage; float sng_damage; +float superaxe; float superspanner; float superknife; float superknife_multihit; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index c2aff4c8..993b4211 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -176,7 +176,7 @@ void (float att_delay) Attack_Finished = { self.attack_finished = time + att_delay; }; -void () W_FireAxe = { +float () W_FireAxe = { local vector source; local vector org; local vector def; @@ -185,7 +185,7 @@ void () W_FireAxe = { source = self.origin + '0 0 16'; traceline(source, source + v_forward * 64, FALSE, self); if (trace_fraction == 1) - return; + return FALSE; org = trace_endpos - v_forward * 4; if (trace_ent.takedamage) { @@ -194,6 +194,7 @@ void () W_FireAxe = { deathmsg = DMSG_AXE; TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); + return TRUE; } else { // hit wall FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); @@ -203,6 +204,7 @@ void () W_FireAxe = { WriteCoord(MSG_MULTICAST, org_y); WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); + return TRUE; } }; From 695f2a4ddd01f5ed2654694ccbb7575e32c3e268 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 22 Mar 2022 22:39:23 +1100 Subject: [PATCH 1468/2474] Reliably update client of grenade primed --- ssqc/status.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 6a27f7ba..c46a5b69 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -800,10 +800,10 @@ void UpdateClientGrenadePrimed(entity pl, float grentype) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); WriteFloat(MSG_MULTICAST, grentype); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } void UpdateClientGrenadeThrown(entity pl) = { From f22a9e9e6489e347792c8bdbe8045ef5fc81cec0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 22 Mar 2022 23:28:30 +1100 Subject: [PATCH 1469/2474] Use short commit hash for fo_rev --- VERSION | 1 - version.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 VERSION diff --git a/VERSION b/VERSION deleted file mode 100644 index 6d7de6e6..00000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.0.2 diff --git a/version.sh b/version.sh index f92ac3e9..4e67ff79 100755 --- a/version.sh +++ b/version.sh @@ -4,7 +4,7 @@ if [ -f VERSION ]; then ver=$(cat VERSION) rev=$(sed -e 's/^r\([0-9]\+\).*$/\1/' VERSION) elif [ -x "$(command -v git)" -a -d ".git" ]; then - rev=$(git rev-list HEAD | wc -l | tr -d -c 0-9) + rev=$(git rev-parse --short HEAD) ver="r$rev~$(git rev-parse --short HEAD)" else echo "WARNING: Couldn't detect ezQuake version." >&2 From 09ffac65623ac701484e6a570ff62547069028c1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 26 Mar 2022 01:31:09 +1100 Subject: [PATCH 1470/2474] Add supermedikit --- ssqc/client.qc | 6 +++++ ssqc/player.qc | 62 +++++++++++++++++++++---------------------------- ssqc/qw.qc | 1 + ssqc/weapons.qc | 32 +++++++++++-------------- 4 files changed, 48 insertions(+), 53 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 76e7639f..a13dda53 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -636,6 +636,9 @@ void () DecodeLevelParms = { // allow axe to hit on any frame of animation superaxe = CF_GetSetting("ss", "superaxe", "on"); + // allow medikit to hit on any frame of animation + supermedikit = CF_GetSetting("sm", "supermedikit", "on"); + // allow spanner to hit on any frame of animation superspanner = CF_GetSetting("ss", "superspanner", "on"); @@ -839,6 +842,7 @@ void () DecodeLevelParms = { ng_velocity = 1500; old_ng_rof = FALSE; superaxe = TRUE; + supermedikit = TRUE; superspanner = TRUE; superknife = TRUE; superknife_multihit = TRUE; @@ -917,6 +921,7 @@ void () DecodeLevelParms = { old_hp_armor = TRUE; ng_velocity = 1000; superaxe = FALSE; + supermedikit = FALSE; superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; @@ -956,6 +961,7 @@ void () DecodeLevelParms = { ng_damage = 18; sng_damage = 26; superaxe = FALSE; + supermedikit = FALSE; superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; diff --git a/ssqc/player.qc b/ssqc/player.qc index 3249dca0..a9ed2a48 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -313,70 +313,62 @@ void () player_knifeb4 =[128, player_run] { void () player_medikit1 =[119, player_medikit2] { self.weaponframe = 1; + + if (supermedikit) + hit_in_current_animation = W_FireMedikit(); }; void () player_medikit2 =[120, player_medikit3] { self.weaponframe = 2; + + if (supermedikit && !hit_in_current_animation) + hit_in_current_animation = W_FireMedikit(); }; void () player_medikit3 =[121, player_medikit4] { self.weaponframe = 3; - W_FireMedikit(); + + if (!supermedikit) + W_FireMedikit(); + else if (!hit_in_current_animation) + hit_in_current_animation = W_FireMedikit(); }; void () player_medikit4 =[122, player_run] { self.weaponframe = 4; + + if (supermedikit && !hit_in_current_animation) + hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb1 =[125, player_medikitb2] { self.weaponframe = 5; + + if (supermedikit) + hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb2 =[126, player_medikitb3] { self.weaponframe = 6; + + if (supermedikit && !hit_in_current_animation) + hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb3 =[127, player_medikitb4] { self.weaponframe = 7; - W_FireMedikit(); + + if (!supermedikit) + W_FireMedikit(); + else if (!hit_in_current_animation) + hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb4 =[128, player_run] { self.weaponframe = 8; -}; - -void () player_medikitc1 =[131, player_medikitc2] { - self.weaponframe = 1; -}; - -void () player_medikitc2 =[132, player_medikitc3] { - self.weaponframe = 2; -}; -void () player_medikitc3 =[133, player_medikitc4] { - self.weaponframe = 3; - W_FireMedikit(); -}; - -void () player_medikitc4 =[134, player_run] { - self.weaponframe = 4; -}; - -void () player_medikitd1 =[137, player_medikitd2] { - self.weaponframe = 5; -}; - -void () player_medikitd2 =[138, player_medikitd3] { - self.weaponframe = 6; -}; - -void () player_medikitd3 =[139, player_medikitd4] { - self.weaponframe = 7; - W_FireMedikit(); -}; - -void () player_medikitd4 =[140, player_run] { - self.weaponframe = 8; + if (supermedikit && !hit_in_current_animation) + hit_in_current_animation = W_FireMedikit(); }; void () player_nail1 =[103, player_nail2] { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 653e9fc1..7bb4a687 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -593,6 +593,7 @@ float ng_velocity; float ng_damage; float sng_damage; float superaxe; +float supermedikit; float superspanner; float superknife; float superknife_multihit; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 993b4211..4f544084 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -376,7 +376,7 @@ int () W_FireSpanner = { } }; -void () W_FireMedikit = { +float () W_FireMedikit = { local vector source; local vector org; local float healam; @@ -385,14 +385,13 @@ void () W_FireMedikit = { source = self.origin + '0 0 16'; traceline(source, (source + (v_forward * 64)), 0, self); - if ((trace_fraction == 1)) { - return; + if (trace_fraction == 1) + return FALSE; - } org = trace_endpos - v_forward * 4; - if (trace_ent.takedamage) { + if (trace_ent.takedamage) { if (trace_ent.classname == "player") { if (((trace_ent.team_no == self.team_no) && @@ -520,7 +519,7 @@ void () W_FireMedikit = { if (trace_ent.infection_team_no != self.team_no) TF_AddFrags(self, 1); } - return; + return TRUE; } if (trace_ent.numflames > 0) { @@ -532,7 +531,7 @@ void () W_FireMedikit = { bprint(PRINT_MEDIUM, self.netname, " put out ", trace_ent.netname, "'s fire.\n"); } - return; + return TRUE; } if (old_medikit) { @@ -603,11 +602,11 @@ void () W_FireMedikit = { T_Damage(trace_ent, self, self, 10); if (trace_ent.playerclass == PC_MEDIC) - return; + return TRUE; if (cb_prematch) - return; + return TRUE; if (trace_ent.tfstate & TFSTATE_INFECTED) - return; + return TRUE; trace_ent.tfstate = trace_ent.tfstate | TFSTATE_INFECTED; BioInfection = spawn(); @@ -622,6 +621,8 @@ void () W_FireMedikit = { } else { TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_OTHER); } + return TRUE; + } else { // hit wall FO_Sound(self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); @@ -632,6 +633,7 @@ void () W_FireMedikit = { WriteCoord(MSG_MULTICAST, org_y); WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); + return TRUE; } }; @@ -1978,8 +1980,6 @@ void () player_assaultcannondown1; void () player_medikit1; void () player_medikitb1; -void () player_medikitc1; -void () player_medikitd1; void () W_Attack = { local float r; @@ -2138,14 +2138,10 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_MEDIKIT) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); - if (r < 0.25) + if (r < 0.5) player_medikit1(); - else if (r < 0.5) - player_medikitb1(); - else if (r < 0.75) - player_medikitc1(); else - player_medikitd1(); + player_medikitb1(); Attack_Finished(0.5); } else if (self.current_weapon == WEAP_TRANQ) { FO_Sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); From 4687a029107a7f188e951d676f38a2d84fb732d5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 26 Mar 2022 01:55:23 +1100 Subject: [PATCH 1471/2474] Default multihit to off --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index a13dda53..1eaf55a6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -646,7 +646,7 @@ void () DecodeLevelParms = { superknife = CF_GetSetting("sk", "superknife", "on"); // allow knife to hit on every frame of animation - superknife_multihit = CF_GetSetting("skmh", "superknife_multihit", "on"); + superknife_multihit = CF_GetSetting("skmh", "superknife_multihit", "off"); // impulse command queueing // ensures detpipe impulse isn't cleared at end of function @@ -845,7 +845,7 @@ void () DecodeLevelParms = { supermedikit = TRUE; superspanner = TRUE; superknife = TRUE; - superknife_multihit = TRUE; + superknife_multihit = FALSE; pyro_type = PYRO_OZTF; Role_None.gren1_limits[1] = PC_SCOUT_GRENADE_MAX_1; Role_None.gren1_limits[2] = PC_SNIPER_GRENADE_MAX_1; From c597d18a8d9b971c7b7aa80d66b72d23aca7cdb5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 26 Mar 2022 01:57:51 +1100 Subject: [PATCH 1472/2474] Update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f83ae873..5ec41b87 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ New features * optional solid nail/shock grenades - localinfo solid_nailgren on (default on) * localinfo nohitsounds 1 - disables hitsounds server-wide * localinfo noreturn 1 - prevents goalitems from returning (will still return from lava) +* localinfo superaxe on/off - causes the axe to hit on all four attack frames (instead of only on 3rd frame) +* localinfo supermedikit on/off - causes the medikit to hit on all four attack frames (instead of only on 3rd frame) * localinfo superspanner on/off - causes the spanner to hit on all four attack frames (instead of only on 3rd frame) * localinfo superknife on/off - causes the knife to hit on all four attack frames (instead of only on 3rd frame) * localinfo superkinfe_multihit on/off - controls whether multiple hits are allowed in a single attack From d5cbcc3f2ce3c1d7cb68ba43321559335dad465b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 27 Mar 2022 22:48:58 +1100 Subject: [PATCH 1473/2474] Fix readmE --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ec41b87..43885373 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ New features * localinfo supermedikit on/off - causes the medikit to hit on all four attack frames (instead of only on 3rd frame) * localinfo superspanner on/off - causes the spanner to hit on all four attack frames (instead of only on 3rd frame) * localinfo superknife on/off - causes the knife to hit on all four attack frames (instead of only on 3rd frame) -* localinfo superkinfe_multihit on/off - controls whether multiple hits are allowed in a single attack +* localinfo superknife_multihit on/off - controls whether multiple hits are allowed in a single attack * scout has "new" flash grenades - localinfo fo_flash on (default on) * ability to set client side min and max flash amounts - localinfo minflash x/localinfo maxflash x (number as a percentage - 1.5 = 150%) * `cmd votemap`/`cmd showvotes`/`cmd listmaps` can now be used at any time and are part of the same system From 83ae9d172651eb743ff212f674aa3796b2052492 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 27 Mar 2022 22:52:27 +1100 Subject: [PATCH 1474/2474] Count hitting wall as hit on knife --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 4f544084..dfac1396 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -256,7 +256,7 @@ int () W_FireKnife = { WriteCoord(MSG_MULTICAST, org_z); multicast(org, MULTICAST_PVS); - return FALSE; + return TRUE; } }; From 19f6fb2979dcfd6466e4f69c971c49d96d88dc35 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 29 Mar 2022 23:43:15 +1100 Subject: [PATCH 1475/2474] Disable superspanner for now it's a bit broken when healing sentry --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 1eaf55a6..03892ba8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -640,7 +640,7 @@ void () DecodeLevelParms = { supermedikit = CF_GetSetting("sm", "supermedikit", "on"); // allow spanner to hit on any frame of animation - superspanner = CF_GetSetting("ss", "superspanner", "on"); + superspanner = CF_GetSetting("ss", "superspanner", "off"); // allow knife to hit on any frame of animation superknife = CF_GetSetting("sk", "superknife", "on"); @@ -843,7 +843,7 @@ void () DecodeLevelParms = { old_ng_rof = FALSE; superaxe = TRUE; supermedikit = TRUE; - superspanner = TRUE; + superspanner = FALSE; superknife = TRUE; superknife_multihit = FALSE; pyro_type = PYRO_OZTF; From b45de96bc7bc7867a6df246c1163fd3cfccb4c83 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 30 Mar 2022 01:03:30 +1100 Subject: [PATCH 1476/2474] Default splitbag to on --- ssqc/client.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 1553b8de..c8302b02 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -779,11 +779,11 @@ void () DecodeLevelParms = { // allow clients to place a personal practice spawn [off] allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); - // split backpack.mdl into deathbag.mdl and discard.mdl [off] (visual change only) - splitbackpackmodels = CF_GetSetting("sbm", "splitbackpackmodels", "0"); + // split backpack.mdl into deathbag.mdl and discard.mdl [on] (visual change only) + splitbackpackmodels = CF_GetSetting("sbm", "splitbackpackmodels", "on"); - // standardize contents of backpack dropped on a players death [off] - standardizedeathammo = CF_GetSetting("sda", "standardizedeathammo", "0"); + // standardize contents of backpack dropped on a players death [on] + standardizedeathammo = CF_GetSetting("sda", "standardizedeathammo", "on"); // if standardizedeathbags set to 1 use these settings instead of players ammo to fill bag on death deathammo_shells = CF_GetSetting("das", "deathammo_shells", "25"); From 39c293e9110dd1fad55cd9b8753b43f1c709e0e1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 8 Apr 2022 01:00:42 +1000 Subject: [PATCH 1477/2474] Recklessly remove player_run without really understanding why it's there --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index dfac1396..75fa0d2d 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1575,7 +1575,7 @@ void (entity pl) W_SetCurrentAmmo = { return; if (!(self.tfstate & TFSTATE_AIMING) && !(self.tfstate & TFSTATE_CANT_MOVE)) - player_run(); + /* player_run(); */ pl.items = pl.items - (pl.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS)); pl.weapon = 0; From 678fb759566b0f8411b2ffef92bc209156273826 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 17 Apr 2022 17:29:50 +1000 Subject: [PATCH 1478/2474] Add start time to serverinfo --- ssqc/world.qc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ssqc/world.qc b/ssqc/world.qc index 9d162877..b0077ba1 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -104,6 +104,13 @@ void () worldspawn = { cvar_set("sv_waterfriction", "1"); if (teamplay == 0) cvar_set("teamplay", "1"); + + if (infokey(world, "starttime") == string_null) { + calltimeofday(); + string timestamp = strcat(tod_year, tod_mon, tod_day, tod_hour, tod_min, tod_sec); + localcmd(strcat("serverinfo starttime \"", timestamp, "\"\n")); + } + localcmd("serverinfo fo_rev \""); localcmd(REV); localcmd("\"\n"); From 5163c16b0bf586fdbf094372ae11e8935b33fa8c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 7 Jun 2022 22:06:00 +1000 Subject: [PATCH 1479/2474] This clearly should be a field --- ssqc/player.qc | 100 ++++++++++++++++++++++++------------------------- ssqc/qw.qc | 3 +- 2 files changed, 51 insertions(+), 52 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index a9ed2a48..36d99fe6 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -12,8 +12,6 @@ void () bubble_bob; void () T_Dispenser; void () Headless_Think; -float hit_in_current_animation; // Set on knife attack if a hit is recorded to prevent combo hits - void () player_touch = { local entity Bio; local entity te; @@ -169,14 +167,14 @@ void () player_axe1 =[119, player_axe2] { self.weaponframe = 1; if (superaxe) - hit_in_current_animation = W_FireAxe(); + self.hit_in_current_animation = W_FireAxe(); }; void () player_axe2 =[120, player_axe3] { self.weaponframe = 2; - if (superaxe && !hit_in_current_animation) - hit_in_current_animation = W_FireAxe(); + if (superaxe && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireAxe(); }; void () player_axe3 =[121, player_axe4] { @@ -184,29 +182,29 @@ void () player_axe3 =[121, player_axe4] { if (!superaxe) W_FireAxe(); - else if (!hit_in_current_animation) - hit_in_current_animation = W_FireAxe(); + else if (!self.hit_in_current_animation) + self.hit_in_current_animation = W_FireAxe(); }; void () player_axe4 =[122, player_run] { self.weaponframe = 4; - if (superaxe && !hit_in_current_animation) - hit_in_current_animation = W_FireAxe(); + if (superaxe && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireAxe(); }; void () player_axeb1 =[124, player_axeb2] { self.weaponframe = 5; if (superaxe) - hit_in_current_animation = W_FireAxe(); + self.hit_in_current_animation = W_FireAxe(); }; void () player_axeb2 =[125, player_axeb3] { self.weaponframe = 6; - if (superaxe && !hit_in_current_animation) - hit_in_current_animation = W_FireAxe(); + if (superaxe && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireAxe(); }; void () player_axeb3 =[126, player_axeb4] { @@ -214,29 +212,29 @@ void () player_axeb3 =[126, player_axeb4] { if (!superaxe) W_FireAxe(); - else if (!hit_in_current_animation) - hit_in_current_animation = W_FireAxe(); + else if (!self.hit_in_current_animation) + self.hit_in_current_animation = W_FireAxe(); }; void () player_axeb4 =[127, player_run] { self.weaponframe = 8; - if (superaxe && !hit_in_current_animation) - hit_in_current_animation = W_FireAxe(); + if (superaxe && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireAxe(); }; void () player_spanner1 =[119, player_spanner2] { self.weaponframe = 1; if (superspanner) - hit_in_current_animation = W_FireSpanner(); + self.hit_in_current_animation = W_FireSpanner(); }; void () player_spanner2 =[120, player_spanner3] { self.weaponframe = 2; - if (superspanner && !hit_in_current_animation) - hit_in_current_animation = W_FireSpanner(); + if (superspanner && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireSpanner(); }; void () player_spanner3 =[121, player_spanner4] { @@ -244,85 +242,85 @@ void () player_spanner3 =[121, player_spanner4] { if (!superspanner) W_FireSpanner(); - else if (!hit_in_current_animation) - hit_in_current_animation = W_FireSpanner(); + else if (!self.hit_in_current_animation) + self.hit_in_current_animation = W_FireSpanner(); }; void () player_spanner4 =[122, player_run] { self.weaponframe = 4; - if (superspanner && !hit_in_current_animation) - hit_in_current_animation = W_FireSpanner(); + if (superspanner && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireSpanner(); }; void () player_knife1 =[119, player_knife2] { self.weaponframe = 1; if (superknife) - hit_in_current_animation = W_FireKnife(); + self.hit_in_current_animation = W_FireKnife(); }; void () player_knife2 =[120, player_knife3] { self.weaponframe = 2; - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); + if (superknife && (superknife_multihit || !self.hit_in_current_animation)) + self.hit_in_current_animation = W_FireKnife(); }; void () player_knife3 =[121, player_knife4] { self.weaponframe = 3; - if (!superknife || (superknife_multihit && !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); + if (!superknife || (superknife_multihit && !self.hit_in_current_animation)) + self.hit_in_current_animation = W_FireKnife(); }; void () player_knife4 =[122, player_run] { self.weaponframe = 4; - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); + if (superknife && (superknife_multihit || !self.hit_in_current_animation)) + self.hit_in_current_animation = W_FireKnife(); }; void () player_knifeb1 =[125, player_knifeb2] { self.weaponframe = 5; if (superknife) - hit_in_current_animation = W_FireKnife(); + self.hit_in_current_animation = W_FireKnife(); }; void () player_knifeb2 =[126, player_knifeb3] { self.weaponframe = 6; - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); + if (superknife && (superknife_multihit || !self.hit_in_current_animation)) + self.hit_in_current_animation = W_FireKnife(); }; void () player_knifeb3 =[127, player_knifeb4] { self.weaponframe = 7; - if (!superknife || (superknife_multihit && !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); + if (!superknife || (superknife_multihit && !self.hit_in_current_animation)) + self.hit_in_current_animation = W_FireKnife(); }; void () player_knifeb4 =[128, player_run] { self.weaponframe = 8; - if (superknife && (superknife_multihit || !hit_in_current_animation)) - hit_in_current_animation = W_FireKnife(); + if (superknife && (superknife_multihit || !self.hit_in_current_animation)) + self.hit_in_current_animation = W_FireKnife(); }; void () player_medikit1 =[119, player_medikit2] { self.weaponframe = 1; if (supermedikit) - hit_in_current_animation = W_FireMedikit(); + self.hit_in_current_animation = W_FireMedikit(); }; void () player_medikit2 =[120, player_medikit3] { self.weaponframe = 2; - if (supermedikit && !hit_in_current_animation) - hit_in_current_animation = W_FireMedikit(); + if (supermedikit && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireMedikit(); }; void () player_medikit3 =[121, player_medikit4] { @@ -330,29 +328,29 @@ void () player_medikit3 =[121, player_medikit4] { if (!supermedikit) W_FireMedikit(); - else if (!hit_in_current_animation) - hit_in_current_animation = W_FireMedikit(); + else if (!self.hit_in_current_animation) + self.hit_in_current_animation = W_FireMedikit(); }; void () player_medikit4 =[122, player_run] { self.weaponframe = 4; - if (supermedikit && !hit_in_current_animation) - hit_in_current_animation = W_FireMedikit(); + if (supermedikit && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb1 =[125, player_medikitb2] { self.weaponframe = 5; if (supermedikit) - hit_in_current_animation = W_FireMedikit(); + self.hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb2 =[126, player_medikitb3] { self.weaponframe = 6; - if (supermedikit && !hit_in_current_animation) - hit_in_current_animation = W_FireMedikit(); + if (supermedikit && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb3 =[127, player_medikitb4] { @@ -360,15 +358,15 @@ void () player_medikitb3 =[127, player_medikitb4] { if (!supermedikit) W_FireMedikit(); - else if (!hit_in_current_animation) - hit_in_current_animation = W_FireMedikit(); + else if (!self.hit_in_current_animation) + self.hit_in_current_animation = W_FireMedikit(); }; void () player_medikitb4 =[128, player_run] { self.weaponframe = 8; - if (supermedikit && !hit_in_current_animation) - hit_in_current_animation = W_FireMedikit(); + if (supermedikit && !self.hit_in_current_animation) + self.hit_in_current_animation = W_FireMedikit(); }; void () player_nail1 =[103, player_nail2] { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 89103b56..ed2e6818 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -407,6 +407,7 @@ float already_chosen_map; .float disptimer; .float fire_held_down; +.float hit_in_current_animation; // Set on knife attack if a hit is recorded to prevent combo hits // sniper location damage stuff .vector head_shot_vector; @@ -780,4 +781,4 @@ typedef struct setting_t { string value; }; -setting_t *settings_to_track; \ No newline at end of file +setting_t *settings_to_track; From 70a8bfc4a59076778145d462fa2600c8dfaf27ac Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 11 Jun 2022 03:47:39 +1000 Subject: [PATCH 1480/2474] Create autodisguise setinfo --- ssqc/client.qc | 67 +++++++++++++++++++++++++++++++++++++++++------- ssqc/commands.qc | 1 + ssqc/qw.qc | 3 ++- ssqc/spy.qc | 4 +++ ssqc/tfort.qc | 6 ++++- ssqc/tforttm.qc | 2 ++ 6 files changed, 72 insertions(+), 11 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c8302b02..987c67a5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -68,7 +68,7 @@ void () InitReverseCap; float () RejoinWithTfId; void () CreateTfIdAndJoin; entity (entity e)TeamFortress_GetPracticeSpawn; - +void () TeamFortress_SpyAutoDisguise; void () info_intermission = { @@ -1990,6 +1990,7 @@ void () PutClientInServer = { if (self.playerclass != PC_CIVILIAN && TeamFortress_TeamIsCivilian(self.team_no)) { TeamFortress_ChangeClass(11); } + if (deathmatch == 3) { if(self.nextpc != self.playerclass) { if (self.playerclass != 0) { @@ -2007,13 +2008,14 @@ void () PutClientInServer = { TeamFortress_ExecClassScript(self); } } - -/* - if ((!IsLegalClass(self.playerclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, self.playerclass)) { - TeamFortress_ChangeClass(0); - Menu_Class(0); - } -*/ + + /* + if ((!IsLegalClass(self.playerclass) && !override_mapclasses) || CF_ClassIsRestricted(self.team_no, self.playerclass)) { + TeamFortress_ChangeClass(0); + Menu_Class(0); + } + */ + if (self.tfstate & TFSTATE_RANDOMPC) { oldclass = self.playerclass; self.playerclass = 1 + floor(random() * (10 - 1)); @@ -2036,12 +2038,13 @@ void () PutClientInServer = { TeamFortress_PrintClassName(self, self.playerclass, self.tfstate & TFSTATE_RANDOMPC); + TeamFortress_SetEquipment(); TeamFortress_SetHealth(); TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_StartTimers(); - + if(quadmode && quad_roles) { sprint(self, PRINT_HIGH, "\sRole:\s ", GetTeamRole(self.team_no).name, "\n"); } @@ -2143,6 +2146,11 @@ void () PutClientInServer = { if (self.playerclass == 0 && self.team_no > 0) { Menu_Class(0); } + + local float autodisguise = stof(infokey(self, "autodisguise")); + if (self.playerclass == PC_SPY && autodisguise) { + TeamFortress_SpyAutoDisguise(); + } }; //void () info_player_start = { @@ -3667,6 +3675,47 @@ void () InitReverseCap = { } +void () TeamFortress_SpyAutoDisguise = { + local float no_teams_with_at_least_one_player = ( + TeamFortress_TeamGetNoPlayers(1) > 0 + + TeamFortress_TeamGetNoPlayers(2) > 0 + + TeamFortress_TeamGetNoPlayers(3) > 0 + + TeamFortress_TeamGetNoPlayers(4) > 0 + ) + + // only show this option if there's only two teams + switch(no_teams_with_at_least_one_player) { + case 0: + break; + case 1: + break; + case 2: + // Do everything + break; + default: + break; + } + + local entity te = find(world, classname, "player"); + local float latest_spawn_time; + local entity enemy_to_disguise_as; + + while (te != world) { + if (te.team_no != self.team_no) { + if (te.spawn_time > latest_spawn_time) { + latest_spawn_time = te.spawn_time; + enemy_to_disguise_as = te; + } + } + + te = find(te, classname, "player"); + } + + CF_Spy_ChangeSkin(self, enemy_to_disguise_as.skin); + CF_Spy_ChangeColor(self, enemy_to_disguise_as.team_no); +}; + + // this is to fix hack used to avoid fall damage, it currently breaks pm_airstep /* void() SV_RunClientCommand = { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index fb123932..a3c20ed9 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -151,6 +151,7 @@ void (float cap1, float cap2) CaptainMode = { te.team_no = 1; SetTeamName(te); TeamFortress_TeamSet_Options(te, 1, TRUE); + UpdateAllClientsTeamScores(); //stuffcmd(self, "color "); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 89103b56..59534e4e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -554,6 +554,7 @@ float fo_hwguy; float feign_air; float feign_pack; float feign_msg; +float autodisguise; float scoutdash; float sniperreload; float spawnfull; @@ -780,4 +781,4 @@ typedef struct setting_t { string value; }; -setting_t *settings_to_track; \ No newline at end of file +setting_t *settings_to_track; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 68c4bb16..192c7d0f 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1435,6 +1435,10 @@ void (entity spy) Spy_RemoveDisguise = { } if (coverblown) Status_Print(self, "\n\n\n\n\n\n\n", "You blew your cover!"); + + local float autodisguise = stof(infokey(self, "autodisguise")); + if (autodisguise) + TeamFortress_SpyAutoDisguise(); }; void () Spy_DropBackpack = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 82e2636e..e7fc5ab9 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -174,7 +174,6 @@ void (float inp) TeamFortress_ChangeClass = { return; } - if(inp > 0) { if (TeamFortress_TeamIsCivilian(self.team_no) && self.playerclass == PC_CIVILIAN) { sprint(self, PRINT_HIGH, "You cannot change class\n"); @@ -329,6 +328,11 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); } self.spawn_time = time; + + local float autodisguise = stof(infokey(self, "autodisguise")); + if (self.playerclass == PC_SPY && autodisguise) { + TeamFortress_SpyAutoDisguise(); + }; }; void () TeamFortress_DisplayLegalClasses = { diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index e7b2d409..bb1edc28 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -272,6 +272,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options } TeamFortress_TeamShowMemberClasses(pe); SetTeamName(pe); + if(!skipclasscheck) { if (pe.playerclass == 0) { if (TeamFortress_TeamIsCivilian(tno)) { @@ -288,6 +289,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options } forceinfokey(pe, "team_no", ftos(tno)); + return (1); }; From 8006ada0c9073d885d7c968f65120bb7586762d6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 11 Jun 2022 10:40:46 +1000 Subject: [PATCH 1481/2474] Add dlastdead command --- README.md | 3 ++- share/defs.h | 1 + ssqc/client.qc | 45 ++------------------------------------------- ssqc/menu.qc | 1 + ssqc/qw.qc | 1 - ssqc/spy.qc | 33 ++++++++++++++++++++++++++++++++- ssqc/tfort.qc | 2 +- ssqc/tforthlp.qc | 1 + ssqc/weapons.qc | 2 ++ 9 files changed, 42 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index cf8c2ad6..3336738b 100644 --- a/README.md +++ b/README.md @@ -183,10 +183,11 @@ Pyro Spy ------ * Improved disguise menu. +* Auto-disguse (setinfo autodisguise 1). * Change color and skin in one sequence. * Last disguise (reachable through disguise menu or using /dlast alias). * Stop disguising by pressing last weapon bind. -* New aliases for changing team color (/denemy (if 2 teams), /dblue, /dred, /dyellow, /dgreen). +* New aliases for changing team color (/denemy (if 2 teams), /dblue, /dred, /dyellow, /dgreen, /dlastdead). * New aliases for changing skin (/dscout, /dsniper, /dsoldier, etc). * Build your own disguise aliases (e.g. alias bsniper "dblue; wait; dsniper" for blue sniper). * Spy can now feign death in air. diff --git a/share/defs.h b/share/defs.h index 1f4a9a08..49f842ab 100644 --- a/share/defs.h +++ b/share/defs.h @@ -449,6 +449,7 @@ #define TF_DISCARD_DROP_AMMO 80 #define TF_PRACSPAWN_PLACE 81 #define TF_PRACSPAWN_REMOVE 82 +#define TF_DISGUISE_LAST_DEAD 83 // Spy: Disguise as last enemy to die // unused 83 // unused 84 // unused 85 diff --git a/ssqc/client.qc b/ssqc/client.qc index 987c67a5..9bc72251 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -68,7 +68,6 @@ void () InitReverseCap; float () RejoinWithTfId; void () CreateTfIdAndJoin; entity (entity e)TeamFortress_GetPracticeSpawn; -void () TeamFortress_SpyAutoDisguise; void () info_intermission = { @@ -2149,7 +2148,7 @@ void () PutClientInServer = { local float autodisguise = stof(infokey(self, "autodisguise")); if (self.playerclass == PC_SPY && autodisguise) { - TeamFortress_SpyAutoDisguise(); + FO_Spy_DisguiseLastDead(); } }; @@ -3675,46 +3674,6 @@ void () InitReverseCap = { } -void () TeamFortress_SpyAutoDisguise = { - local float no_teams_with_at_least_one_player = ( - TeamFortress_TeamGetNoPlayers(1) > 0 + - TeamFortress_TeamGetNoPlayers(2) > 0 + - TeamFortress_TeamGetNoPlayers(3) > 0 + - TeamFortress_TeamGetNoPlayers(4) > 0 - ) - - // only show this option if there's only two teams - switch(no_teams_with_at_least_one_player) { - case 0: - break; - case 1: - break; - case 2: - // Do everything - break; - default: - break; - } - - local entity te = find(world, classname, "player"); - local float latest_spawn_time; - local entity enemy_to_disguise_as; - - while (te != world) { - if (te.team_no != self.team_no) { - if (te.spawn_time > latest_spawn_time) { - latest_spawn_time = te.spawn_time; - enemy_to_disguise_as = te; - } - } - - te = find(te, classname, "player"); - } - - CF_Spy_ChangeSkin(self, enemy_to_disguise_as.skin); - CF_Spy_ChangeColor(self, enemy_to_disguise_as.team_no); -}; - // this is to fix hack used to avoid fall damage, it currently breaks pm_airstep /* @@ -3741,7 +3700,7 @@ void() SV_RunClientCommand = { } fdmg = rint(fdmg); TF_T_Damage(self, world, world, fdmg, 1, 0); - FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTf_NORM); self.deathtype = "falling"; } else { FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 978fdef5..3c2eccb4 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -71,6 +71,7 @@ void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; void (float inp) Menu_Spy_Color_Input; void () CF_Spy_DisguiseLast; +void () FO_Spy_DisguiseLastDead; void () Menu_Demoman; void () Menu_Demoman_Cancel; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 59534e4e..34c63f12 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -554,7 +554,6 @@ float fo_hwguy; float feign_air; float feign_pack; float feign_msg; -float autodisguise; float scoutdash; float sniperreload; float spawnfull; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 192c7d0f..06a3a7fe 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -706,6 +706,37 @@ void () CF_Spy_DisguiseLast = { } }; +void () FO_Spy_DisguiseLastDead = { + local float no_teams_with_at_least_one_player = ( + TeamFortress_TeamGetNoPlayers(1) > 0 + + TeamFortress_TeamGetNoPlayers(2) > 0 + + TeamFortress_TeamGetNoPlayers(3) > 0 + + TeamFortress_TeamGetNoPlayers(4) > 0 + ) + + if (no_teams_with_at_least_one_player < 2) + return; + + local entity te = find(world, classname, "player"); + local float latest_spawn_time; + local entity enemy_to_disguise_as; + + while (te != world) { + if (te.team_no != self.team_no) { + if (te.spawn_time > latest_spawn_time) { + latest_spawn_time = te.spawn_time; + enemy_to_disguise_as = te; + } + } + + te = find(te, classname, "player"); + } + + CF_Spy_ChangeSkin(self, enemy_to_disguise_as.skin); + CF_Spy_ChangeColor(self, enemy_to_disguise_as.team_no); +}; + + void (entity own) Spy_SetClientSkins = { entity te; string color, dcolor, skin, dskin, sendcolor, sendskin, pteam, dsteam, sendteam; @@ -1438,7 +1469,7 @@ void (entity spy) Spy_RemoveDisguise = { local float autodisguise = stof(infokey(self, "autodisguise")); if (autodisguise) - TeamFortress_SpyAutoDisguise(); + FO_Spy_DisguiseLastDead(); }; void () Spy_DropBackpack = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e7fc5ab9..d40c738b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -331,7 +331,7 @@ void (float inp) TeamFortress_ChangeClass = { local float autodisguise = stof(infokey(self, "autodisguise")); if (self.playerclass == PC_SPY && autodisguise) { - TeamFortress_SpyAutoDisguise(); + FO_Spy_DisguiseLastDead(); }; }; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 7bd50250..99f4e179 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -237,6 +237,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dgreen", TF_DISGUISE_GREEN, 0); TeamFortress_Alias("denemy", TF_DISGUISE_ENEMY, 0); TeamFortress_Alias("dlast", TF_DISGUISE_LAST, 0); + TeamFortress_Alias("dlastdead", TF_DISGUISE_LAST_DEAD, 0); if(csqcactive) { TeamFortress_AliasString("build", "fo_menu_build"); } else { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 75fa0d2d..56f22677 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3108,6 +3108,8 @@ void () ImpulseCommands = { CF_Spy_ChangeColor(self, 1); } else if (self.impulse == TF_DISGUISE_LAST && self.playerclass == PC_SPY) CF_Spy_DisguiseLast(); + else if (self.impulse == TF_DISGUISE_LAST_DEAD && self.playerclass == PC_SPY) + FO_Spy_DisguiseLastDead(); else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); From 5d9d4bf1bc6a2ee0a948397f517ae867ae82f126 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 11 Jun 2022 11:23:26 +1000 Subject: [PATCH 1482/2474] Rename command to dlastspawn, handle no enemies --- README.md | 2 +- share/defs.h | 3 +-- ssqc/client.qc | 2 +- ssqc/menu.qc | 2 +- ssqc/spy.qc | 30 ++++++++++++++++-------------- ssqc/tfort.qc | 2 +- ssqc/tforthlp.qc | 2 +- ssqc/weapons.qc | 4 ++-- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 3336738b..1a7069bd 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ Spy * Change color and skin in one sequence. * Last disguise (reachable through disguise menu or using /dlast alias). * Stop disguising by pressing last weapon bind. -* New aliases for changing team color (/denemy (if 2 teams), /dblue, /dred, /dyellow, /dgreen, /dlastdead). +* New aliases for changing team color (/denemy (if 2 teams), /dblue, /dred, /dyellow, /dgreen, /dlastspawn). * New aliases for changing skin (/dscout, /dsniper, /dsoldier, etc). * Build your own disguise aliases (e.g. alias bsniper "dblue; wait; dsniper" for blue sniper). * Spy can now feign death in air. diff --git a/share/defs.h b/share/defs.h index 49f842ab..487031a2 100644 --- a/share/defs.h +++ b/share/defs.h @@ -449,8 +449,7 @@ #define TF_DISCARD_DROP_AMMO 80 #define TF_PRACSPAWN_PLACE 81 #define TF_PRACSPAWN_REMOVE 82 -#define TF_DISGUISE_LAST_DEAD 83 // Spy: Disguise as last enemy to die -// unused 83 +#define TF_DISGUISE_LAST_SPAWNED 83 // Spy: Disguise as last enemy to spawn // unused 84 // unused 85 // unused 86 diff --git a/ssqc/client.qc b/ssqc/client.qc index 9bc72251..c01d4814 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2148,7 +2148,7 @@ void () PutClientInServer = { local float autodisguise = stof(infokey(self, "autodisguise")); if (self.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastDead(); + FO_Spy_DisguiseLastSpawned(); } }; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 3c2eccb4..fe5e7938 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -71,7 +71,7 @@ void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; void (float inp) Menu_Spy_Color_Input; void () CF_Spy_DisguiseLast; -void () FO_Spy_DisguiseLastDead; +void () FO_Spy_DisguiseLastSpawned; void () Menu_Demoman; void () Menu_Demoman_Cancel; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 06a3a7fe..d1d956f3 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -706,17 +706,7 @@ void () CF_Spy_DisguiseLast = { } }; -void () FO_Spy_DisguiseLastDead = { - local float no_teams_with_at_least_one_player = ( - TeamFortress_TeamGetNoPlayers(1) > 0 + - TeamFortress_TeamGetNoPlayers(2) > 0 + - TeamFortress_TeamGetNoPlayers(3) > 0 + - TeamFortress_TeamGetNoPlayers(4) > 0 - ) - - if (no_teams_with_at_least_one_player < 2) - return; - +void () FO_Spy_DisguiseLastSpawned = { local entity te = find(world, classname, "player"); local float latest_spawn_time; local entity enemy_to_disguise_as; @@ -732,8 +722,20 @@ void () FO_Spy_DisguiseLastDead = { te = find(te, classname, "player"); } - CF_Spy_ChangeSkin(self, enemy_to_disguise_as.skin); - CF_Spy_ChangeColor(self, enemy_to_disguise_as.team_no); + if (enemy_to_disguise_as.team_no) { + CF_Spy_ChangeSkin(self, enemy_to_disguise_as.skin); + CF_Spy_ChangeColor(self, enemy_to_disguise_as.team_no); + } else { + local float lowest_enemy_team_no; + + if (self.team_no == 1) { + lowest_enemy_team_no = 2; + } else { + lowest_enemy_team_no = 1; + } + + CF_Spy_ChangeColor(self, lowest_enemy_team_no); + } }; @@ -1469,7 +1471,7 @@ void (entity spy) Spy_RemoveDisguise = { local float autodisguise = stof(infokey(self, "autodisguise")); if (autodisguise) - FO_Spy_DisguiseLastDead(); + FO_Spy_DisguiseLastSpawned(); }; void () Spy_DropBackpack = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index d40c738b..3eea12fd 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -331,7 +331,7 @@ void (float inp) TeamFortress_ChangeClass = { local float autodisguise = stof(infokey(self, "autodisguise")); if (self.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastDead(); + FO_Spy_DisguiseLastSpawned(); }; }; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 99f4e179..ad4c4e23 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -237,7 +237,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dgreen", TF_DISGUISE_GREEN, 0); TeamFortress_Alias("denemy", TF_DISGUISE_ENEMY, 0); TeamFortress_Alias("dlast", TF_DISGUISE_LAST, 0); - TeamFortress_Alias("dlastdead", TF_DISGUISE_LAST_DEAD, 0); + TeamFortress_Alias("dlastspawn", TF_DISGUISE_LAST_SPAWNED, 0); if(csqcactive) { TeamFortress_AliasString("build", "fo_menu_build"); } else { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 56f22677..0a00c03a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3108,8 +3108,8 @@ void () ImpulseCommands = { CF_Spy_ChangeColor(self, 1); } else if (self.impulse == TF_DISGUISE_LAST && self.playerclass == PC_SPY) CF_Spy_DisguiseLast(); - else if (self.impulse == TF_DISGUISE_LAST_DEAD && self.playerclass == PC_SPY) - FO_Spy_DisguiseLastDead(); + else if (self.impulse == TF_DISGUISE_LAST_SPAWNED && self.playerclass == PC_SPY) + FO_Spy_DisguiseLastSpawned(); else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); From 6c1428a80a24023f330c4eb887f27192d5088195 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 11 Jun 2022 12:03:59 +1000 Subject: [PATCH 1483/2474] Add special skill 2 --- README.md | 3 +++ share/defs.h | 2 +- ssqc/tfort.qc | 31 +++++++++++++++++++++++++++++++ ssqc/tforthlp.qc | 1 + ssqc/weapons.qc | 11 ++++++++++- 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a7069bd..7aebc05d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ FortressOne Server New features ------ +* `dlastspawn` Tells spy to disguise as enemy who last spawned. +* `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. +* `special2` Demoman: `+det5`, Spy: `dlastspawn`, Engineer: `detsentry` * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. diff --git a/share/defs.h b/share/defs.h index 487031a2..933d2197 100644 --- a/share/defs.h +++ b/share/defs.h @@ -450,7 +450,7 @@ #define TF_PRACSPAWN_PLACE 81 #define TF_PRACSPAWN_REMOVE 82 #define TF_DISGUISE_LAST_SPAWNED 83 // Spy: Disguise as last enemy to spawn -// unused 84 +#define TF_SPECIAL_SKILL_2 84 // Class special 2 // unused 85 // unused 86 // unused 87 diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3eea12fd..7bef5c3a 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -104,6 +104,37 @@ void () UseSpecialSkill = { } }; +void () UseSpecialSkill2 = { + local vector src; + + self.impulse = 0; + switch (self.playerclass) + { + case PC_SCOUT: + // Radar something? + break; + case PC_SNIPER: + break; + case PC_DEMOMAN: + self.impulse = TF_DETPACK_5; + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + break; + case PC_SPY: + self.impulse = TF_DISGUISE_LAST_SPAWNED; + break; + case PC_ENGINEER: + self.impulse = TF_ENGINEER_DETSENTRY; + break; + case PC_UNDEFINED: + break; + } +}; + void () RemoveAutoIdTimer = { local entity te = find(world, classname, "aitimer"); while (te != world) { diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index ad4c4e23..cb14da00 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -165,6 +165,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("dropitems", TF_DROPFLAG, 0); TeamFortress_Alias("showloc", TF_DISPLAYLOCATION, 0); TeamFortress_Alias("special", TF_SPECIAL_SKILL, 0); + TeamFortress_Alias("special2", TF_SPECIAL_SKILL_2, 0); TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); TeamFortress_Alias("discard", TF_DISCARD, 0); TeamFortress_Alias("discard_drop_ammo", TF_DISCARD_DROP_AMMO, 0); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 0a00c03a..a590641b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -67,6 +67,7 @@ void (entity e) TeamFortress_PlacePracticeSpawn; void (entity e) TeamFortress_RemovePracticeSpawn; void () DropKey; void () UseSpecialSkill; +void () UseSpecialSkill2; void () RemoveFlare; void () ScannerSwitch; @@ -2961,6 +2962,9 @@ void () ImpulseCommands = { if (self.impulse == TF_SPECIAL_SKILL) UseSpecialSkill(); + if (self.impulse == TF_SPECIAL_SKILL_2) + UseSpecialSkill2(); + if (self.impulse == TF_NEXTTIP) { self.display_tip = 0; self.tip_type = 0; @@ -3168,6 +3172,10 @@ void () PreMatchImpulses = { self.invincible_finished = time + 666; } } + + if (self.impulse == TF_SPECIAL_SKILL_2) { + // Something + } }; void () DeadImpulses = { @@ -3351,7 +3359,7 @@ void () W_WeaponFrame = { return; } - if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL && self.impulse != TF_MEDIC_HELPME && self.impulse != TF_SPY_DIE && self.impulse != TF_SPY_SILENT_DIE) + if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL && self.impulse != TF_SPECIAL_SKILL_2 && self.impulse != TF_MEDIC_HELPME && self.impulse != TF_SPY_DIE && self.impulse != TF_SPY_SILENT_DIE) return; if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { @@ -3498,6 +3506,7 @@ void () W_WeaponFrame = { switch (self.impulse) { case TF_SPECIAL_SKILL: + case TF_SPECIAL_SKILL_2: case TF_PB_DETONATE: case TF_MEDIC_HELPME: case TF_DASH: From 0c2fcf940e011e0d99d2bfdefcc01dc76114c5b3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 11 Jun 2022 12:07:03 +1000 Subject: [PATCH 1484/2474] Revert typo in comment --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c01d4814..f2ef0c68 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3700,7 +3700,7 @@ void() SV_RunClientCommand = { } fdmg = rint(fdmg); TF_T_Damage(self, world, world, fdmg, 1, 0); - FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTf_NORM); + FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); self.deathtype = "falling"; } else { FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); From aca07e0a0c43e219c166f226a92697b011267775 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 11 Jun 2022 22:26:53 +1000 Subject: [PATCH 1485/2474] Autodisguise after throw and cap --- ssqc/client.qc | 2 +- ssqc/menu.qc | 2 +- ssqc/spy.qc | 16 ++++++++-------- ssqc/tfort.qc | 2 +- ssqc/tfortmap.qc | 11 +++++++++++ ssqc/weapons.qc | 2 +- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index f2ef0c68..4cd9d2db 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2148,7 +2148,7 @@ void () PutClientInServer = { local float autodisguise = stof(infokey(self, "autodisguise")); if (self.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastSpawned(); + FO_Spy_DisguiseLastSpawned(self); } }; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index fe5e7938..699bcdc6 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -71,7 +71,7 @@ void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; void (float inp) Menu_Spy_Color_Input; void () CF_Spy_DisguiseLast; -void () FO_Spy_DisguiseLastSpawned; +void (entity player) FO_Spy_DisguiseLastSpawned; void () Menu_Demoman; void () Menu_Demoman_Cancel; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index d1d956f3..5ceea7a7 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -706,13 +706,13 @@ void () CF_Spy_DisguiseLast = { } }; -void () FO_Spy_DisguiseLastSpawned = { +void (entity player) FO_Spy_DisguiseLastSpawned = { local entity te = find(world, classname, "player"); - local float latest_spawn_time; + local float latest_spawn_time = 0; local entity enemy_to_disguise_as; while (te != world) { - if (te.team_no != self.team_no) { + if (te.team_no != player.team_no) { if (te.spawn_time > latest_spawn_time) { latest_spawn_time = te.spawn_time; enemy_to_disguise_as = te; @@ -723,18 +723,18 @@ void () FO_Spy_DisguiseLastSpawned = { } if (enemy_to_disguise_as.team_no) { - CF_Spy_ChangeSkin(self, enemy_to_disguise_as.skin); - CF_Spy_ChangeColor(self, enemy_to_disguise_as.team_no); + CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); + CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); } else { local float lowest_enemy_team_no; - if (self.team_no == 1) { + if (player.team_no == 1) { lowest_enemy_team_no = 2; } else { lowest_enemy_team_no = 1; } - CF_Spy_ChangeColor(self, lowest_enemy_team_no); + CF_Spy_ChangeColor(player, lowest_enemy_team_no); } }; @@ -1471,7 +1471,7 @@ void (entity spy) Spy_RemoveDisguise = { local float autodisguise = stof(infokey(self, "autodisguise")); if (autodisguise) - FO_Spy_DisguiseLastSpawned(); + FO_Spy_DisguiseLastSpawned(self); }; void () Spy_DropBackpack = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 7bef5c3a..565ea4b2 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -362,7 +362,7 @@ void (float inp) TeamFortress_ChangeClass = { local float autodisguise = stof(infokey(self, "autodisguise")); if (self.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastSpawned(); + FO_Spy_DisguiseLastSpawned(self); }; }; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index ff11ad0a..841b18a7 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1080,6 +1080,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { self.immune_to_check = time + 10; Spy_RemoveDisguise(Player); } + if ((Goal.items != 0) && (Goal.classname != "item_tfgoal")) { te = Finditem(Goal.items); if ((te != world) && (te != Goal)) @@ -1132,6 +1133,11 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } if (Goal.goal_result & TFGR_FORCE_RESPAWN) ForceRespawn(Player); + + local float autodisguise = stof(infokey(Player, "autodisguise")); + if (Player.playerclass == PC_SPY && autodisguise) { + FO_Spy_DisguiseLastSpawned(Player); + } }; void (entity Goal, entity Player) RemoveResults = { @@ -3034,4 +3040,9 @@ void () DropGoalItems = { } dremove(newmis); TeamFortress_SetSpeed(self); + + local float autodisguise = stof(infokey(self, "autodisguise")); + if (self.playerclass == PC_SPY && autodisguise) { + FO_Spy_DisguiseLastSpawned(self); + } }; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index a590641b..4276f2f5 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3113,7 +3113,7 @@ void () ImpulseCommands = { } else if (self.impulse == TF_DISGUISE_LAST && self.playerclass == PC_SPY) CF_Spy_DisguiseLast(); else if (self.impulse == TF_DISGUISE_LAST_SPAWNED && self.playerclass == PC_SPY) - FO_Spy_DisguiseLastSpawned(); + FO_Spy_DisguiseLastSpawned(self); else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); From 3d9794d7b047bb1065550aeed477377431fc8e48 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 11 Jun 2022 23:00:02 +1000 Subject: [PATCH 1486/2474] Refactor --- ssqc/client.qc | 2 +- ssqc/spy.qc | 2 +- ssqc/tfort.qc | 2 +- ssqc/tfortmap.qc | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 4cd9d2db..599616be 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2146,7 +2146,7 @@ void () PutClientInServer = { Menu_Class(0); } - local float autodisguise = stof(infokey(self, "autodisguise")); + local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); if (self.playerclass == PC_SPY && autodisguise) { FO_Spy_DisguiseLastSpawned(self); } diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 5ceea7a7..82d73742 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1469,7 +1469,7 @@ void (entity spy) Spy_RemoveDisguise = { if (coverblown) Status_Print(self, "\n\n\n\n\n\n\n", "You blew your cover!"); - local float autodisguise = stof(infokey(self, "autodisguise")); + local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); if (autodisguise) FO_Spy_DisguiseLastSpawned(self); }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 565ea4b2..28bd02e7 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -360,7 +360,7 @@ void (float inp) TeamFortress_ChangeClass = { } self.spawn_time = time; - local float autodisguise = stof(infokey(self, "autodisguise")); + local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); if (self.playerclass == PC_SPY && autodisguise) { FO_Spy_DisguiseLastSpawned(self); }; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 841b18a7..f0c8d17c 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1134,7 +1134,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Goal.goal_result & TFGR_FORCE_RESPAWN) ForceRespawn(Player); - local float autodisguise = stof(infokey(Player, "autodisguise")); + local float autodisguise = FO_GetUserSetting(Player, "autodisguise", "ad", "off"); if (Player.playerclass == PC_SPY && autodisguise) { FO_Spy_DisguiseLastSpawned(Player); } @@ -3041,7 +3041,7 @@ void () DropGoalItems = { dremove(newmis); TeamFortress_SetSpeed(self); - local float autodisguise = stof(infokey(self, "autodisguise")); + local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); if (self.playerclass == PC_SPY && autodisguise) { FO_Spy_DisguiseLastSpawned(self); } From 74212a51240c36fc54e0f114425812b304ec1b9f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jun 2022 00:27:53 +1000 Subject: [PATCH 1487/2474] Keep scanner settings after respawn --- ssqc/client.qc | 16 +++++++++++++++- ssqc/commands.qc | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 599616be..190794bd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -959,7 +959,7 @@ void () DecodeLevelParms = { solid_detpack = TRUE; walls_block_emp = FALSE; solid_nailgren = TRUE; - scoutscanspike = FALSE; + scoutscanspike = FALSE; } st = infokey(world, "huetf"); @@ -2150,6 +2150,20 @@ void () PutClientInServer = { if (self.playerclass == PC_SPY && autodisguise) { FO_Spy_DisguiseLastSpawned(self); } + + if(self.playerclass == PC_SCOUT && self.ScannerOn == 1) { + te = spawn(); + te.nextthink = time + 2; + te.think = TeamFortress_Scan; + te.owner = self; + te.classname = "timer"; + te.netname = "scanner"; + sprint(self, PRINT_HIGH, "Scanner on\n"); + self.ScannerOn = 1; + + if (!(self.tf_items_flags & NIT_SCANNER_ENEMY)) + self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY; + } }; //void () info_player_start = { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a3c20ed9..c618e522 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -451,7 +451,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; -//These only work when alive + //These only work when alive case "dropammo": processedCmd = TRUE; if(self.health <= 0) { From 7181f14d3759b46ecc4f2849fe502c34f69bee6a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jun 2022 00:33:20 +1000 Subject: [PATCH 1488/2474] Add special2 for scout (autoscan) --- README.md | 2 +- ssqc/tfort.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7aebc05d..7b1faf6c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ New features * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. -* `special2` Demoman: `+det5`, Spy: `dlastspawn`, Engineer: `detsentry` +* `special2` Scout: `autoscan`, Demoman: `+det5`, Spy: `dlastspawn`, Engineer: `detsentry` * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 28bd02e7..9874cdcd 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -111,7 +111,7 @@ void () UseSpecialSkill2 = { switch (self.playerclass) { case PC_SCOUT: - // Radar something? + self.impulse = TF_SCAN; break; case PC_SNIPER: break; From c872187fb70efa3a277391f28d554400bcc28769 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jun 2022 10:53:31 +1000 Subject: [PATCH 1489/2474] Engineer specials toggle build / det buildings --- share/defs.h | 4 ++-- ssqc/tfort.qc | 4 ++-- ssqc/weapons.qc | 30 ++++++++++++++++++++++++------ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/share/defs.h b/share/defs.h index 933d2197..ff33ed19 100644 --- a/share/defs.h +++ b/share/defs.h @@ -451,8 +451,8 @@ #define TF_PRACSPAWN_REMOVE 82 #define TF_DISGUISE_LAST_SPAWNED 83 // Spy: Disguise as last enemy to spawn #define TF_SPECIAL_SKILL_2 84 // Class special 2 -// unused 85 -// unused 86 +#define TF_ENGINEER_TOGGLESENTRY 85 // Engineer: Build or detonate sentry +#define TF_ENGINEER_TOGGLEDISP 86 // Engineer: Build or detonate dispenser // unused 87 // unused 88 // unused 89 diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 9874cdcd..c2ec75c7 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -80,7 +80,7 @@ void () UseSpecialSkill = { self.impulse = TF_SPY_DIE; break; case PC_ENGINEER: - self.impulse = TF_ENGINEER_DETDISP; + self.impulse = TF_ENGINEER_TOGGLEDISP; break; case PC_UNDEFINED: if (self.enemy == world) { @@ -128,7 +128,7 @@ void () UseSpecialSkill2 = { self.impulse = TF_DISGUISE_LAST_SPAWNED; break; case PC_ENGINEER: - self.impulse = TF_ENGINEER_DETSENTRY; + self.impulse = TF_ENGINEER_TOGGLESENTRY; break; case PC_UNDEFINED: break; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 4276f2f5..ae8f8a2b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3057,11 +3057,33 @@ void () ImpulseCommands = { else if (self.impulse == TF_MEDIC_AURA_TOGGLE) CF_Medic_AuraToggle(); else if ((self.impulse == TF_ENGINEER_DETSENTRY) && - (self.playerclass == PC_ENGINEER)) + (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_sentrygun"); else if ((self.impulse == TF_ENGINEER_DETDISP) && - (self.playerclass == PC_ENGINEER)) + (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_dispenser"); + else if ((self.impulse == TF_ENGINEER_TOGGLESENTRY) && (self.playerclass == PC_ENGINEER)) { + if (self.has_sentry) { + DestroyBuilding(self, "building_sentrygun"); + } else { + sprint(self, PRINT_HIGH, "test\n"); + if (self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't build while dead.\n"); + } else { + Menu_Engineer_Input(1); + } + } + } else if ((self.impulse == TF_ENGINEER_TOGGLEDISP) && (self.playerclass == PC_ENGINEER)) { + if (self.has_dispenser) { + DestroyBuilding(self, "building_dispenser"); + } else { + if (self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't build while dead.\n"); + } else { + Menu_Engineer_Input(2); + } + } + } else if ((self.impulse == 196) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_teleporter_exit"); else if ((self.impulse == 197) && (self.playerclass == PC_ENGINEER)) @@ -3172,10 +3194,6 @@ void () PreMatchImpulses = { self.invincible_finished = time + 666; } } - - if (self.impulse == TF_SPECIAL_SKILL_2) { - // Something - } }; void () DeadImpulses = { From a8954813a05616ed80802361c8d4296790252fd2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jun 2022 11:02:05 +1000 Subject: [PATCH 1490/2474] Update readme --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b1faf6c..199c43aa 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ New features * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. -* `special2` Scout: `autoscan`, Demoman: `+det5`, Spy: `dlastspawn`, Engineer: `detsentry` +* `special2` Scout: `autoscan`, Demoman: `+det5`, Spy: `dlastspawn`, Engineer: Toggle build / det sentry * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. @@ -181,7 +181,8 @@ Heavy Weapons Guy Pyro ------ -* Add knockback to Flamethrower. +* Add air-blast special. +* Rebalance weapons. Spy ------ @@ -209,7 +210,8 @@ Engineer * Stop building by pressing last weapon key. * Added message when Dispenser is destroyed. * Added dismantle message to show how many cells were returned to Engineer. -* Changed class special to detonate dispenser. +* Changed class special to toggle build or detonate dispenser. +* New class special2 to toggle build or detonate sentry. * Engineers can now only dismantle own buildings and rotate own Sentry Gun. From f620fac81cc3d5975610b3f2046cb68d6cff31e2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 Jun 2022 11:11:29 +1000 Subject: [PATCH 1491/2474] Remove debug statement --- ssqc/weapons.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ae8f8a2b..848b21b2 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3066,7 +3066,6 @@ void () ImpulseCommands = { if (self.has_sentry) { DestroyBuilding(self, "building_sentrygun"); } else { - sprint(self, PRINT_HIGH, "test\n"); if (self.health <= 0) { sprint(self, PRINT_HIGH, "Can't build while dead.\n"); } else { From 1660c788c2aef8fb11578c51fa1ebed253df4dd5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 13 Jun 2022 01:17:04 +1000 Subject: [PATCH 1492/2474] Spy change colour before changing skin --- ssqc/menu.qc | 5 ++--- ssqc/spy.qc | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 699bcdc6..f39f3424 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -652,9 +652,6 @@ void (float inp) Menu_Spy_Skin_Input = { return; } - if (self.skin != inp) - CF_Spy_ChangeSkin(self, inp); - if(infokeyf(self, "smt")) { Menu_Spy_Color(); } else { @@ -668,6 +665,8 @@ void (float inp) Menu_Spy_Skin_Input = { CF_Spy_ChangeColor(self, 1); } + if (self.skin != inp) + CF_Spy_ChangeSkin(self, inp); }; void () Menu_Spy_Skin = { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 82d73742..d74b9505 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -723,8 +723,8 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { } if (enemy_to_disguise_as.team_no) { - CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); + CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); } else { local float lowest_enemy_team_no; From 52633d5f047df2ec32aa6264dfd786bd11b1eca6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 13 Jun 2022 01:34:35 +1000 Subject: [PATCH 1493/2474] Don't try to disguise as someone without a skin --- ssqc/spy.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index d74b9505..aadd4f32 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -724,7 +724,10 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { if (enemy_to_disguise_as.team_no) { CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); - CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); + + if (enemy_to_disguise_as.skin) { + CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); + } } else { local float lowest_enemy_team_no; From ca55ed55d10f1c0741b0e9ec98450e288fd9d482 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 13 Jun 2022 01:37:48 +1000 Subject: [PATCH 1494/2474] Remove debug statement --- ssqc/mvdsv.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index de692b13..5681e3ad 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -29,7 +29,6 @@ float (string cmd) ConsoleCmd { RemoveVoteMap(argv(1)); return TRUE; case "nextmap": - bprint(PRINT_HIGH, "Hmm: ", ftos(FO_GetUserSetting (world, "nomapcycle", "nmc", "0")), "\n"); //MEHT if(FO_GetUserSetting (world, "nomapcycle", "nmc", "0")) { bprint(PRINT_HIGH, "Tried setting next map to ", argv(1), ", but nomapcycle is set.\n"); } else { From 123f6271c2ece3d5da11e52b88910aa7db0684d2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 14 Jun 2022 23:04:41 +1000 Subject: [PATCH 1495/2474] Add last skin option to autodisguise, also, use last selected skin instead of actual --- README.md | 3 ++- csqc/csextradefs.qc | 2 +- csqc/events.qc | 2 +- csqc/menu.qc | 8 ++++---- ssqc/client.qc | 12 ++++++++++-- ssqc/csmenu.qc | 2 +- ssqc/menu.qc | 6 +++--- ssqc/qw.qc | 2 +- ssqc/spy.qc | 39 ++++++++++++++++++++++++++++----------- ssqc/tfort.qc | 13 ++++++++++--- ssqc/tfortmap.qc | 22 ++++++++++++++++++---- ssqc/weapons.qc | 2 +- 12 files changed, 80 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 199c43aa..82599798 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ New features * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. +* `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. * `special2` Scout: `autoscan`, Demoman: `+det5`, Spy: `dlastspawn`, Engineer: Toggle build / det sentry * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` @@ -187,7 +188,7 @@ Pyro Spy ------ * Improved disguise menu. -* Auto-disguse (setinfo autodisguise 1). +* Auto-disguise (setinfo autodisguise 0/1/2). * Change color and skin in one sequence. * Last disguise (reachable through disguise menu or using /dlast alias). * Stop disguising by pressing last weapon bind. diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 31bf19c2..ffbbb093 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -66,7 +66,7 @@ float fo_hud_editor; float fo_hud_menu_active; vector ScreenSize; float number_of_teams; -float last_skin; +float last_selected_skin; float last_team; vector sentry_pos; vector dispenser_pos; diff --git a/csqc/events.qc b/csqc/events.qc index 52504a03..1e61a701 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -147,7 +147,7 @@ void() CSQC_Parse_Event = { break; case CLIENT_MENU_SPY: SBAR.InvisOnly = readfloat(); - last_skin = readfloat(); + last_selected_skin = readfloat(); last_team = readfloat(); FO_Menu_Spy(2); break; diff --git a/csqc/menu.qc b/csqc/menu.qc index be904379..1b044cdb 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -181,9 +181,9 @@ var fo_menu FO_MENU_SPY = { } else { FO_MENU_SPY.options[0].name = "Disguise"; FO_MENU_SPY.options[0].value = (SBAR.IsUndercover?"on":"off"); - if(last_skin || last_team) { + if(last_selected_skin || last_team) { FO_MENU_SPY.options[1].state = FO_MENU_STATE_NORMAL; - FO_MENU_SPY.options[1].value = strcat(TeamToString(last_team)," ",ClassToString(last_skin)); + FO_MENU_SPY.options[1].value = strcat(TeamToString(last_team)," ",ClassToString(last_selected_skin)); } else { FO_MENU_SPY.options[1].state = FO_MENU_STATE_DISABLED; } @@ -1037,9 +1037,9 @@ void FO_Menu_Spy(float force) = { //FO_MENU_SPY.options[1].state = FO_MENU_STATE_HIDDEN; FO_MENU_SPY.options[0].name = "Disguise"; FO_MENU_SPY.options[0].value = (SBAR.IsUndercover?"on":"off"); - if(last_skin || last_team) { + if(last_selected_skin || last_team) { FO_MENU_SPY.options[1].state = FO_MENU_STATE_NORMAL; - FO_MENU_SPY.options[1].value = strcat(TeamToString(last_team)," ",ClassToString(last_skin)); + FO_MENU_SPY.options[1].value = strcat(TeamToString(last_team)," ",ClassToString(last_selected_skin)); } else { FO_MENU_SPY.options[1].state = FO_MENU_STATE_DISABLED; } diff --git a/ssqc/client.qc b/ssqc/client.qc index 190794bd..819e3cf2 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2146,9 +2146,17 @@ void () PutClientInServer = { Menu_Class(0); } + local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); - if (self.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastSpawned(self); + if (self.playerclass == PC_SPY) { + switch(autodisguise) { + case 1: + FO_Spy_DisguiseLastSpawned(self); + break; + case 2: + FO_Spy_DisguiseLast(self); + break; + } } if(self.playerclass == PC_SCOUT && self.ScannerOn == 1) { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 66c0e986..5cf036cf 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -80,7 +80,7 @@ void UpdateClientMenu_Spy(entity pl) = { WriteByte(MSG_MULTICAST, MSG_CLIENT_MENU); WriteFloat(MSG_MULTICAST, CLIENT_MENU_SPY); WriteFloat(MSG_MULTICAST, invis_only); - WriteFloat(MSG_MULTICAST, pl.last_skin); + WriteFloat(MSG_MULTICAST, pl.last_selected_skin); WriteFloat(MSG_MULTICAST, pl.last_team); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index f39f3424..ebae3204 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -70,7 +70,7 @@ void (float inp) Menu_Scout_Input; void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; void (float inp) Menu_Spy_Color_Input; -void () CF_Spy_DisguiseLast; +void (entity player) FO_Spy_DisguiseLast; void (entity player) FO_Spy_DisguiseLastSpawned; void () Menu_Demoman; @@ -579,7 +579,7 @@ void (float inp) Menu_Spy_Input = { else Menu_Spy_Skin(); } else if (inp == 2 && !invis_only) { - CF_Spy_DisguiseLast(); + FO_Spy_DisguiseLast(self); } else if (inp == 3) { CF_Spy_FeignDeath(1); if (self.is_feigning) { @@ -618,7 +618,7 @@ void (entity pe_player) Menu_Spy = { } else if (pe_player.is_undercover == 2) s_skin = Q"\s[1]\s Stop disguising \n"; - if ((!pe_player.last_skin && !pe_player.last_team) || invis_only) + if ((!pe_player.last_selected_skin && !pe_player.last_team) || invis_only) s_last = "\n"; if (pe_player.is_feigning) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 34c63f12..83a29407 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -58,7 +58,7 @@ typedef void (float n) f_void_float; .float pipecooldown; // Time when detpipe command can be issued .float disguise_skin; // The skin the spy is changing to .float queue_skin; // The skin the spy will change to after team disguise is finished -.float last_skin; // The last skin the spy disguised as +.float last_selected_skin; // The last skin the spy selected to disguise as .float disguise_team; // The team the spy is changing to .float queue_team; // The team the spy will change to after skin disguise is finished .float last_team; // The last team the spy disguised as diff --git a/ssqc/spy.qc b/ssqc/spy.qc index aadd4f32..f1cb336c 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -670,7 +670,6 @@ void () CF_Spy_DisguiseStop = { if (self.undercover_skin || self.undercover_team) { sprint(self, PRINT_HIGH, "Disguised as ", s_team, " ", s_class, "\n"); self.is_undercover = 1; - self.last_skin = self.undercover_skin; self.last_team = self.undercover_team; } else { sprint(self, PRINT_HIGH, "You stop going undercover\n"); @@ -697,12 +696,22 @@ void () CF_Spy_DisguiseStop = { }; -void () CF_Spy_DisguiseLast = { - if (self.last_skin) { - CF_Spy_ChangeSkin(self, self.last_skin); +void (entity player) FO_Spy_DisguiseLast = { + if (player.last_team) { + CF_Spy_ChangeColor(player, player.last_team); + } else { + local float lowest_enemy_team_no; + + if (player.team_no == 1) { + lowest_enemy_team_no = 2; + } else { + lowest_enemy_team_no = 1; + } + + CF_Spy_ChangeColor(player, lowest_enemy_team_no); } - if (self.last_team) { - CF_Spy_ChangeColor(self, self.last_team); + if (player.last_selected_skin) { + CF_Spy_ChangeSkin(player, player.last_selected_skin); } }; @@ -840,7 +849,6 @@ void () CF_Spy_UndercoverThink = { if (self.skin) { self.owner.undercover_skin = self.skin; - self.owner.last_skin = self.skin; self.owner.disguise_skin = 0; self.owner.queue_skin = 0; self.owner.is_undercover = 1; @@ -891,7 +899,7 @@ void () CF_Spy_UndercoverThink = { }; void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { - local entity e_timer; + pe_player.last_selected_skin = pf_class; // stop if you're already disguised as the requested skin if (pe_player.undercover_skin == pf_class) @@ -928,12 +936,13 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { sprint(pe_player, PRINT_HIGH, "Going undercover...\n"); else if(pe_player.undercover_skin != pf_class) sprint(pe_player, PRINT_HIGH, "Changing costumes...\n"); - + pe_player.is_undercover = 2; pe_player.disguise_skin = pf_class; pe_player.disguise_team = 0; // disguise timer, finishes in 4 seconds + local entity e_timer; e_timer = spawn(); e_timer.classname = "spytimer"; e_timer.owner = pe_player; @@ -1473,8 +1482,16 @@ void (entity spy) Spy_RemoveDisguise = { Status_Print(self, "\n\n\n\n\n\n\n", "You blew your cover!"); local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); - if (autodisguise) - FO_Spy_DisguiseLastSpawned(self); + if (self.playerclass == PC_SPY) { + switch(autodisguise) { + case 1: + FO_Spy_DisguiseLastSpawned(self); + break; + case 2: + FO_Spy_DisguiseLast(self); + break; + } + } }; void () Spy_DropBackpack = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c2ec75c7..e87a1fb8 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -361,9 +361,16 @@ void (float inp) TeamFortress_ChangeClass = { self.spawn_time = time; local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); - if (self.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastSpawned(self); - }; + if (self.playerclass == PC_SPY) { + switch(autodisguise) { + case 1: + FO_Spy_DisguiseLastSpawned(self); + break; + case 2: + FO_Spy_DisguiseLast(self); + break; + } + } }; void () TeamFortress_DisplayLegalClasses = { diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index f0c8d17c..b539fd56 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1135,8 +1135,15 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { ForceRespawn(Player); local float autodisguise = FO_GetUserSetting(Player, "autodisguise", "ad", "off"); - if (Player.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastSpawned(Player); + if (Player.playerclass == PC_SPY) { + switch(autodisguise) { + case 1: + FO_Spy_DisguiseLastSpawned(Player); + break; + case 2: + FO_Spy_DisguiseLast(Player); + break; + } } }; @@ -3042,7 +3049,14 @@ void () DropGoalItems = { TeamFortress_SetSpeed(self); local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); - if (self.playerclass == PC_SPY && autodisguise) { - FO_Spy_DisguiseLastSpawned(self); + if (self.playerclass == PC_SPY) { + switch(autodisguise) { + case 1: + FO_Spy_DisguiseLastSpawned(self); + break; + case 2: + FO_Spy_DisguiseLast(self); + break; + } } }; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 848b21b2..51ab89e1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3132,7 +3132,7 @@ void () ImpulseCommands = { else CF_Spy_ChangeColor(self, 1); } else if (self.impulse == TF_DISGUISE_LAST && self.playerclass == PC_SPY) - CF_Spy_DisguiseLast(); + FO_Spy_DisguiseLast(self); else if (self.impulse == TF_DISGUISE_LAST_SPAWNED && self.playerclass == PC_SPY) FO_Spy_DisguiseLastSpawned(self); else if ((self.impulse == TF_DEMOMAN_DETPACK) && From a99dfc92e84ddcd122818349d8b5e88fd8b16a66 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 Jun 2022 23:55:47 +1000 Subject: [PATCH 1496/2474] Revert disguise order due to timing bug --- ssqc/menu.qc | 6 +++--- ssqc/spy.qc | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index ebae3204..177c53fb 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -652,6 +652,9 @@ void (float inp) Menu_Spy_Skin_Input = { return; } + if (self.skin != inp) + CF_Spy_ChangeSkin(self, inp); + if(infokeyf(self, "smt")) { Menu_Spy_Color(); } else { @@ -664,9 +667,6 @@ void (float inp) Menu_Spy_Skin_Input = { else CF_Spy_ChangeColor(self, 1); } - - if (self.skin != inp) - CF_Spy_ChangeSkin(self, inp); }; void () Menu_Spy_Skin = { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index f1cb336c..5eb30263 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -697,6 +697,10 @@ void () CF_Spy_DisguiseStop = { }; void (entity player) FO_Spy_DisguiseLast = { + if (player.last_selected_skin) { + CF_Spy_ChangeSkin(player, player.last_selected_skin); + } + if (player.last_team) { CF_Spy_ChangeColor(player, player.last_team); } else { @@ -710,9 +714,6 @@ void (entity player) FO_Spy_DisguiseLast = { CF_Spy_ChangeColor(player, lowest_enemy_team_no); } - if (player.last_selected_skin) { - CF_Spy_ChangeSkin(player, player.last_selected_skin); - } }; void (entity player) FO_Spy_DisguiseLastSpawned = { @@ -732,11 +733,11 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { } if (enemy_to_disguise_as.team_no) { - CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); - if (enemy_to_disguise_as.skin) { CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); } + + CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); } else { local float lowest_enemy_team_no; From e44c929ca7090fd84151d9f25fb95971aee43fca Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Jun 2022 00:57:51 +1000 Subject: [PATCH 1497/2474] Disguise team before skin, remove timers --- README.md | 4 ++-- ssqc/menu.qc | 6 +++--- ssqc/spy.qc | 30 ++++++++++++++++++++---------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 82599798..a5d99956 100644 --- a/README.md +++ b/README.md @@ -211,8 +211,8 @@ Engineer * Stop building by pressing last weapon key. * Added message when Dispenser is destroyed. * Added dismantle message to show how many cells were returned to Engineer. -* Changed class special to toggle build or detonate dispenser. -* New class special2 to toggle build or detonate sentry. +* Changed class special to build or detonate dispenser. +* New class special2 to build or detonate sentry. * Engineers can now only dismantle own buildings and rotate own Sentry Gun. diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 177c53fb..ebae3204 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -652,9 +652,6 @@ void (float inp) Menu_Spy_Skin_Input = { return; } - if (self.skin != inp) - CF_Spy_ChangeSkin(self, inp); - if(infokeyf(self, "smt")) { Menu_Spy_Color(); } else { @@ -667,6 +664,9 @@ void (float inp) Menu_Spy_Skin_Input = { else CF_Spy_ChangeColor(self, 1); } + + if (self.skin != inp) + CF_Spy_ChangeSkin(self, inp); }; void () Menu_Spy_Skin = { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 5eb30263..4aba5f9a 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -633,6 +633,7 @@ void () CF_Spy_Invisible = { sprint(self, PRINT_HIGH, "Going invisible...\n"); self.is_undercover = 2; + self.undercover_timer = PC_SPY_GO_UNDERCOVER_TIME; // create a timer for 4 seconds e_timer = spawn(); @@ -640,7 +641,6 @@ void () CF_Spy_Invisible = { e_timer.owner = self; e_timer.think = CF_Spy_UndercoverThink; e_timer.nextthink = time + 1; - self.undercover_timer = 4; } Status_Refresh(self); @@ -693,14 +693,9 @@ void () CF_Spy_DisguiseStop = { } Status_Refresh(self); - }; void (entity player) FO_Spy_DisguiseLast = { - if (player.last_selected_skin) { - CF_Spy_ChangeSkin(player, player.last_selected_skin); - } - if (player.last_team) { CF_Spy_ChangeColor(player, player.last_team); } else { @@ -714,6 +709,10 @@ void (entity player) FO_Spy_DisguiseLast = { CF_Spy_ChangeColor(player, lowest_enemy_team_no); } + + if (player.last_selected_skin) { + CF_Spy_ChangeSkin(player, player.last_selected_skin); + } }; void (entity player) FO_Spy_DisguiseLastSpawned = { @@ -733,11 +732,11 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { } if (enemy_to_disguise_as.team_no) { + CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); + if (enemy_to_disguise_as.skin) { CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); } - - CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); } else { local float lowest_enemy_team_no; @@ -943,6 +942,7 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { pe_player.disguise_team = 0; // disguise timer, finishes in 4 seconds + pe_player.undercover_timer = PC_SPY_GO_UNDERCOVER_TIME; local entity e_timer; e_timer = spawn(); e_timer.classname = "spytimer"; @@ -950,7 +950,6 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { e_timer.think = CF_Spy_UndercoverThink; e_timer.nextthink = time + 1; e_timer.skin = pf_class; - pe_player.undercover_timer = 4; Status_Refresh(pe_player); }; @@ -998,11 +997,12 @@ void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { pe_player.disguise_team = pf_team_no; // disguise timer, finishes in 4 seconds + pe_player.undercover_timer = PC_SPY_GO_UNDERCOVER_TIME; e_timer = spawn(); e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 4; + e_timer.nextthink = time + 1; e_timer.team = pf_team_no; Status_Refresh(pe_player); @@ -1479,6 +1479,16 @@ void (entity spy) Spy_RemoveDisguise = { } Status_Refresh(self); } + + local entity timer = find(world, classname, "spytimer"); + while (timer) { + if (timer.owner == self) { + dremove(timer); + } + + timer = find(timer, classname, "spytimer"); + } + if (coverblown) Status_Print(self, "\n\n\n\n\n\n\n", "You blew your cover!"); From e59e34e3bdbd91d28ffab767d4d73464373fdb03 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Jun 2022 01:07:00 +1000 Subject: [PATCH 1498/2474] Disguise as last spawned enemy if no last disguise --- ssqc/spy.qc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 4aba5f9a..94dfd47f 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -696,23 +696,24 @@ void () CF_Spy_DisguiseStop = { }; void (entity player) FO_Spy_DisguiseLast = { + if (!player.last_selected_skin) { + FO_Spy_DisguiseLastSpawned(player); + return; + } + + local float undercover_team; if (player.last_team) { - CF_Spy_ChangeColor(player, player.last_team); + undercover_team = player.last_team; } else { - local float lowest_enemy_team_no; - if (player.team_no == 1) { - lowest_enemy_team_no = 2; + undercover_team = 2; } else { - lowest_enemy_team_no = 1; + undercover_team = 1; } - - CF_Spy_ChangeColor(player, lowest_enemy_team_no); } - if (player.last_selected_skin) { - CF_Spy_ChangeSkin(player, player.last_selected_skin); - } + CF_Spy_ChangeColor(player, undercover_team); + CF_Spy_ChangeSkin(player, player.last_selected_skin); }; void (entity player) FO_Spy_DisguiseLastSpawned = { From 7fa5b9fd2f1cca555dc9f90dcc6af8b296e71ba5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 19 Jun 2022 01:34:49 +1000 Subject: [PATCH 1499/2474] Stop disguising if you're trying to disguise as a different class --- ssqc/spy.qc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 94dfd47f..63bbdc5e 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -701,6 +701,10 @@ void (entity player) FO_Spy_DisguiseLast = { return; } + if (self.is_undercover == 2 && player.last_selected_skin != player.disguise_skin) { + CF_Spy_DisguiseStop(); + } + local float undercover_team; if (player.last_team) { undercover_team = player.last_team; @@ -732,6 +736,10 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { te = find(te, classname, "player"); } + if (self.is_undercover == 2 && enemy_to_disguise_as.skin != player.disguise_skin) { + CF_Spy_DisguiseStop(); + } + if (enemy_to_disguise_as.team_no) { CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); @@ -739,15 +747,14 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); } } else { - local float lowest_enemy_team_no; - + local float undercover_team; if (player.team_no == 1) { - lowest_enemy_team_no = 2; + undercover_team = 2; } else { - lowest_enemy_team_no = 1; + undercover_team = 1; } - CF_Spy_ChangeColor(player, lowest_enemy_team_no); + CF_Spy_ChangeColor(player, undercover_team); } }; From bf5d8db70c44aeb459c763ee1ff940566efa393f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 20 Jun 2022 00:16:20 +1000 Subject: [PATCH 1500/2474] Add +special2, +rj, togglesentry, toggledisp --- README.md | 11 ++++-- csqc/main.qc | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ share/defs.h | 2 +- ssqc/tfort.qc | 4 ++ ssqc/tforthlp.qc | 4 ++ ssqc/tsoldier.qc | 24 ++++++++++++ ssqc/weapons.qc | 6 ++- 7 files changed, 141 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a5d99956..4ea3d9be 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ New features * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. -* `special2` Scout: `autoscan`, Demoman: `+det5`, Spy: `dlastspawn`, Engineer: Toggle build / det sentry +* `+special2` Scout: `autoscan`, Soldier: `+rj`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: Toggle build / det sentry * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. @@ -158,6 +158,10 @@ Sniper * Sniper Rifle range increased. * Automatic sensitivity scaling while zoomed in. Use the special button as a zoom button. Use mouse wheel to adjust zoom while zoomed in. Sniper Rifle now needs to be reloaded between shots. +Soldier +------ +* New command +rj (or +special2) to rocket jump. + Demolitions Man ------ * New detpack menu containing 5, 20, 50 and 255 second detpacks. @@ -184,6 +188,7 @@ Pyro ------ * Add air-blast special. * Rebalance weapons. +* New command +rj (or +special2) to rocket jump. Spy ------ @@ -211,8 +216,8 @@ Engineer * Stop building by pressing last weapon key. * Added message when Dispenser is destroyed. * Added dismantle message to show how many cells were returned to Engineer. -* Changed class special to build or detonate dispenser. -* New class special2 to build or detonate sentry. +* New command toggledisp (or special) to build or detonate dispenser. +* New command togglesentry (or +special2) to build or detonate sentry. * Engineers can now only dismantle own buildings and rotate own Sentry Gun. diff --git a/csqc/main.qc b/csqc/main.qc index 1feebf15..11ddf918 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -55,6 +55,10 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("+aux_jump"); registercommand("-aux_jump"); + registercommand("+special2"); + registercommand("-special2"); + registercommand("+rj"); + registercommand("-rj"); registercommand("tracktarget"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); @@ -290,6 +294,96 @@ noref float(string cmd) CSQC_ConsoleCommand = { jump_counter = 0; localcmd("-jump\n"); } + break; + case "+special2": + switch (player_class) { + case PC_SCOUT: + localcmd("autoscan\n"); + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + localcmd("+rj\n"); + break; + case PC_DEMOMAN: + localcmd("+det5\n"); + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + localcmd("+rj\n"); + break; + case PC_SPY: + localcmd("dlastspawn\n"); + break; + case PC_ENGINEER: + localcmd("togglesentry\n"); + break; + case PC_UNDEFINED: + break; + } + break; + case "-special2": + switch (player_class) { + case PC_SCOUT: + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + localcmd("-rj\n"); + break; + case PC_DEMOMAN: + localcmd("-det5\n"); + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + localcmd("-rj\n"); + break; + case PC_SPY: + break; + case PC_ENGINEER: + break; + case PC_UNDEFINED: + break; + } + break; + case "+rj": + if (player_class != PC_SOLDIER && player_class != PC_PYRO) { + break; + } + + switch (player_class) { + case PC_SOLDIER: + localcmd("impulse 1\n"); + break; + case PC_PYRO: + localcmd("impulse 2\n"); + break; + } + + localcmd("+attack\n"); + + if (input_buttons&2) { + jump_counter = jump_counter + 1; + } else { + localcmd("+jump\n"); + } + + break; + case "-rj": + localcmd("-attack\n"); + + if (jump_counter) { + jump_counter = jump_counter - 1; + } else { + localcmd("-jump\n"); + } + break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -298,6 +392,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { RemoveVoteMap(argv(1), TRUE); break; } + return FALSE; }; diff --git a/share/defs.h b/share/defs.h index ff33ed19..4b93830e 100644 --- a/share/defs.h +++ b/share/defs.h @@ -453,7 +453,7 @@ #define TF_SPECIAL_SKILL_2 84 // Class special 2 #define TF_ENGINEER_TOGGLESENTRY 85 // Engineer: Build or detonate sentry #define TF_ENGINEER_TOGGLEDISP 86 // Engineer: Build or detonate dispenser -// unused 87 +#define TF_ROCKET_JUMP 87 // Soldier and Pyro: Rocket Jump // unused 88 // unused 89 // unused 90 diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e87a1fb8..e62f77e3 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -115,6 +115,9 @@ void () UseSpecialSkill2 = { break; case PC_SNIPER: break; + case PC_SOLDIER: + self.impulse = TF_ROCKET_JUMP; + break; case PC_DEMOMAN: self.impulse = TF_DETPACK_5; break; @@ -123,6 +126,7 @@ void () UseSpecialSkill2 = { case PC_HVYWEAP: break; case PC_PYRO: + self.impulse = TF_ROCKET_JUMP; break; case PC_SPY: self.impulse = TF_DISGUISE_LAST_SPAWNED; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index cb14da00..7b2fa680 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -246,6 +246,8 @@ void () TeamFortress_MOTD = { } TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); + TeamFortress_Alias("togglesentry", TF_ENGINEER_TOGGLESENTRY, 0); + TeamFortress_Alias("toggledispenser", TF_ENGINEER_TOGGLEDISP, 0); } else if (self.motd == 130) { stuffcmd(self, "is_aliased\n"); TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); @@ -257,6 +259,8 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("fo_settings_status", "cmd fo_settings_status"); TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); TeamFortress_Alias("removepracspawn", TF_PRACSPAWN_REMOVE, 0); + } else if (self.motd == 140) { + TeamFortress_Alias("+rj", TF_ROCKET_JUMP, 0); Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 07395540..f4215bce 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -285,3 +285,27 @@ void () TeamFortress_NailGrenInfo = { sprint(self,2,Q"\s----------------------------------------------------------------------------------------------\s\n"); self.impulse = 0; }; + +void () TeamFortress_RocketJump = { + if (self.playerclass != PC_SOLDIER && self.playerclass != PC_PYRO) { + return; + } + + if (!WeaponReady(self)) { + return; + } + + sprint(self, PRINT_HIGH, "TeamFortress_RocketJump()\n"); + + local float cweap = self.current_weapon; + + if (self.playerclass == PC_SOLDIER) { + self.current_weapon = WEAP_ROCKET_LAUNCHER; + } else if (self.playerclass == PC_PYRO) { + self.current_weapon = WEAP_INCENDIARY; + } + W_Attack(); + // input_buttons |= 2; + // runstandardplayerphysics(self); + self.current_weapon = cweap; +}; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 51ab89e1..628f0f67 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -57,6 +57,7 @@ void () TeamFortress_DetpackMenu; void () CF_Medic_AuraToggle; void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; +void () TeamFortress_RocketJump; void () TeamFortress_Scan; void () TeamFortress_Discard; void () TeamFortress_Discard_DropAmmo; @@ -3141,6 +3142,9 @@ void () ImpulseCommands = { else if ((self.impulse == TF_ENGINEER_BUILD) && (self.playerclass == PC_ENGINEER)) TeamFortress_EngineerBuild(); + else if ((self.impulse == TF_ROCKET_JUMP) && + (self.playerclass == PC_SOLDIER || self.playerclass == PC_PYRO)) + TeamFortress_RocketJump(); else if (self.impulse == FLAG_INFO) { if (CTF_Map == 1) TeamFortress_CTF_FlagInfo(); @@ -3543,7 +3547,7 @@ void () W_WeaponFrame = { case FLAG_INFO: ImpulseCommands(); return; - // allows setting detpack while reloading on toggle, defaults to off + // allows setting detpack while reloading on toggle, defaults to off case TF_DEMOMAN_DETPACK: case TF_DETPACK: case TF_DETPACK_STOP: From add159b1c755da6ac914b1c17848ac7d9aa5a3bc Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 20 Jun 2022 00:19:13 +1000 Subject: [PATCH 1501/2474] Remove serverside TeamFortress_RocketJump --- share/defs.h | 2 +- ssqc/tfort.qc | 2 -- ssqc/tforthlp.qc | 1 - ssqc/tsoldier.qc | 24 ------------------------ ssqc/weapons.qc | 4 ---- 5 files changed, 1 insertion(+), 32 deletions(-) diff --git a/share/defs.h b/share/defs.h index 4b93830e..ff33ed19 100644 --- a/share/defs.h +++ b/share/defs.h @@ -453,7 +453,7 @@ #define TF_SPECIAL_SKILL_2 84 // Class special 2 #define TF_ENGINEER_TOGGLESENTRY 85 // Engineer: Build or detonate sentry #define TF_ENGINEER_TOGGLEDISP 86 // Engineer: Build or detonate dispenser -#define TF_ROCKET_JUMP 87 // Soldier and Pyro: Rocket Jump +// unused 87 // unused 88 // unused 89 // unused 90 diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e62f77e3..9d2102d6 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -116,7 +116,6 @@ void () UseSpecialSkill2 = { case PC_SNIPER: break; case PC_SOLDIER: - self.impulse = TF_ROCKET_JUMP; break; case PC_DEMOMAN: self.impulse = TF_DETPACK_5; @@ -126,7 +125,6 @@ void () UseSpecialSkill2 = { case PC_HVYWEAP: break; case PC_PYRO: - self.impulse = TF_ROCKET_JUMP; break; case PC_SPY: self.impulse = TF_DISGUISE_LAST_SPAWNED; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 7b2fa680..850f0c10 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -260,7 +260,6 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); TeamFortress_Alias("removepracspawn", TF_PRACSPAWN_REMOVE, 0); } else if (self.motd == 140) { - TeamFortress_Alias("+rj", TF_ROCKET_JUMP, 0); Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index f4215bce..07395540 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -285,27 +285,3 @@ void () TeamFortress_NailGrenInfo = { sprint(self,2,Q"\s----------------------------------------------------------------------------------------------\s\n"); self.impulse = 0; }; - -void () TeamFortress_RocketJump = { - if (self.playerclass != PC_SOLDIER && self.playerclass != PC_PYRO) { - return; - } - - if (!WeaponReady(self)) { - return; - } - - sprint(self, PRINT_HIGH, "TeamFortress_RocketJump()\n"); - - local float cweap = self.current_weapon; - - if (self.playerclass == PC_SOLDIER) { - self.current_weapon = WEAP_ROCKET_LAUNCHER; - } else if (self.playerclass == PC_PYRO) { - self.current_weapon = WEAP_INCENDIARY; - } - W_Attack(); - // input_buttons |= 2; - // runstandardplayerphysics(self); - self.current_weapon = cweap; -}; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 628f0f67..5a43c6cf 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -57,7 +57,6 @@ void () TeamFortress_DetpackMenu; void () CF_Medic_AuraToggle; void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; -void () TeamFortress_RocketJump; void () TeamFortress_Scan; void () TeamFortress_Discard; void () TeamFortress_Discard_DropAmmo; @@ -3142,9 +3141,6 @@ void () ImpulseCommands = { else if ((self.impulse == TF_ENGINEER_BUILD) && (self.playerclass == PC_ENGINEER)) TeamFortress_EngineerBuild(); - else if ((self.impulse == TF_ROCKET_JUMP) && - (self.playerclass == PC_SOLDIER || self.playerclass == PC_PYRO)) - TeamFortress_RocketJump(); else if (self.impulse == FLAG_INFO) { if (CTF_Map == 1) TeamFortress_CTF_FlagInfo(); From ee509e3413c48f0251c59f1cd80a496596ddcd4f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 20 Jun 2022 01:39:30 +1000 Subject: [PATCH 1502/2474] Use aux_jump in rj script, delete unusued code --- csqc/main.qc | 60 +++++++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 41 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 11ddf918..244783f0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -285,15 +285,20 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd tracktarget\n"); break; case "+aux_jump": - jump_counter = jump_counter + 1; + jump_counter++; localcmd("+jump\n"); break; case "-aux_jump": - jump_counter = jump_counter - 1; - if (jump_counter <= 0) { + jump_counter--; + + if (jump_counter < 0) { jump_counter = 0; + } + + if (!jump_counter) { localcmd("-jump\n"); } + break; case "+special2": switch (player_class) { @@ -353,37 +358,26 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "+rj": - if (player_class != PC_SOLDIER && player_class != PC_PYRO) { + if (player_class == PC_SOLDIER) { + localcmd("impulse 1\n"); + } else if (player_class == PC_PYRO) { + localcmd("impulse 2\n"); + } else { break; } - switch (player_class) { - case PC_SOLDIER: - localcmd("impulse 1\n"); - break; - case PC_PYRO: - localcmd("impulse 2\n"); - break; - } - localcmd("+attack\n"); - - if (input_buttons&2) { - jump_counter = jump_counter + 1; - } else { - localcmd("+jump\n"); - } + localcmd("+aux_jump\n"); break; case "-rj": - localcmd("-attack\n"); - - if (jump_counter) { - jump_counter = jump_counter - 1; - } else { - localcmd("-jump\n"); + if (player_class != PC_SOLDIER && player_class != PC_PYRO) { + break; } + localcmd("-attack\n"); + localcmd("-aux_jump\n"); + break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -416,22 +410,6 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { - if (input_buttons&2 && getstatf(STAT_HEALTH) > 0) { - if (pmove_onground) { - frames_since_onground = 0; - } else { - - // next two frames after leaving ground - if (frames_since_onground <= 2) { - frames_since_onground = frames_since_onground + 1; - - // third frame after leaving ground - } else if (frames_since_onground == 3) { - input_buttons &= ~2; - frames_since_onground = frames_since_onground + 1; - } - } - } } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { From 6d7eeaf92f0ba83a52bbe9fdb2c0a300a0829df3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 20 Jun 2022 01:43:53 +1000 Subject: [PATCH 1503/2474] Remove unneeded alias splitting --- ssqc/tforthlp.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 850f0c10..e9c9fc99 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -259,7 +259,6 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("fo_settings_status", "cmd fo_settings_status"); TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); TeamFortress_Alias("removepracspawn", TF_PRACSPAWN_REMOVE, 0); - } else if (self.motd == 140) { Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) From ab926c67f43b722cdbae51965eb1c6190c1e054f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 21 Jun 2022 01:16:22 +1000 Subject: [PATCH 1504/2474] Add +feign alias --- share/defs.h | 172 +++++++++++++++++++++++------------------------ ssqc/client.qc | 9 +++ ssqc/combat.qc | 9 ++- ssqc/help.qc | 1 + ssqc/qw.qc | 1 + ssqc/tforthlp.qc | 2 + ssqc/weapons.qc | 20 ++++-- 7 files changed, 120 insertions(+), 94 deletions(-) diff --git a/share/defs.h b/share/defs.h index ff33ed19..6634d776 100644 --- a/share/defs.h +++ b/share/defs.h @@ -426,35 +426,35 @@ #define TF_LOCKON 57 // HWGuy: Turn Assault Cannon fire on #define TF_LOCKOFF 58 // HWGuy: Turn Assault Cannon fire off #define TF_SPY_DIE 59 // Spy: Feign death -#define TF_SPY_SILENT_DIE 60 // Spy: Silent feign death -#define TF_SPY_SPY 61 // Spy: Bring up disguise menu -#define TF_DISGUISE_ENEMY 62 // Spy: Disguise as enemy team -#define TF_DISGUISE_LAST 63 // Spy: Use last disguise -#define TF_DISGUISE_RESET 64 // Spy: Reset disguise -#define TF_DISGUISE_SCOUT 65 // Spy: Disguise as Scout -#define TF_DISGUISE_SNIPER 66 // Spy: Disguise as Sniper -#define TF_DISGUISE_SOLDIER 67 // Spy: Disguise as Soldier -#define TF_DISGUISE_DEMOMAN 68 // Spy: Disguise as Demoman -#define TF_DISGUISE_MEDIC 69 // Spy: Disguise as Medic -#define TF_DISGUISE_HWGUY 70 // Spy: Disguise as HWGuy -#define TF_DISGUISE_PYRO 71 // Spy: Disguise as Pyro -#define TF_DISGUISE_ENGINEER 72 // Spy: Disguise as Engineer -#define TF_DISGUISE_BLUE 73 // Spy: Disguise as blue team -#define TF_DISGUISE_RED 74 // Spy: Disguise as red team -#define TF_DISGUISE_YELLOW 75 // Spy: Disguise as yellow team -#define TF_DISGUISE_GREEN 76 // Spy: Disguise as green team -#define TF_ENGINEER_BUILD 77 // Engineer: Bring up build menu for Engineer -#define TF_ENGINEER_DETDISP 78 // Engineer: Detonate dispenser for Engineer -#define TF_ENGINEER_DETSENTRY 79 // Engineer: Detonate sentry gun for Engineer -#define TF_DISCARD_DROP_AMMO 80 -#define TF_PRACSPAWN_PLACE 81 -#define TF_PRACSPAWN_REMOVE 82 -#define TF_DISGUISE_LAST_SPAWNED 83 // Spy: Disguise as last enemy to spawn -#define TF_SPECIAL_SKILL_2 84 // Class special 2 -#define TF_ENGINEER_TOGGLESENTRY 85 // Engineer: Build or detonate sentry -#define TF_ENGINEER_TOGGLEDISP 86 // Engineer: Build or detonate dispenser -// unused 87 -// unused 88 +#define TF_SPY_DIE_ON 60 // Spy: Feign death next damage +#define TF_SPY_DIE_OFF 61 // Spy: Unfeign +#define TF_SPY_SILENT_DIE 62 // Spy: Silent feign death +#define TF_SPY_SPY 63 // Spy: Bring up disguise menu +#define TF_DISGUISE_ENEMY 64 // Spy: Disguise as enemy team +#define TF_DISGUISE_LAST 65 // Spy: Use last disguise +#define TF_DISGUISE_RESET 66 // Spy: Reset disguise +#define TF_DISGUISE_SCOUT 67 // Spy: Disguise as Scout +#define TF_DISGUISE_SNIPER 68 // Spy: Disguise as Sniper +#define TF_DISGUISE_SOLDIER 69 // Spy: Disguise as Soldier +#define TF_DISGUISE_DEMOMAN 70 // Spy: Disguise as Demoman +#define TF_DISGUISE_MEDIC 71 // Spy: Disguise as Medic +#define TF_DISGUISE_HWGUY 72 // Spy: Disguise as HWGuy +#define TF_DISGUISE_PYRO 73 // Spy: Disguise as Pyro +#define TF_DISGUISE_ENGINEER 74 // Spy: Disguise as Engineer +#define TF_DISGUISE_BLUE 75 // Spy: Disguise as blue team +#define TF_DISGUISE_RED 76 // Spy: Disguise as red team +#define TF_DISGUISE_YELLOW 77 // Spy: Disguise as yellow team +#define TF_DISGUISE_GREEN 78 // Spy: Disguise as green team +#define TF_ENGINEER_BUILD 79 // Engineer: Bring up build menu for Engineer +#define TF_ENGINEER_DETDISP 80 // Engineer: Detonate dispenser for Engineer +#define TF_ENGINEER_DETSENTRY 81 // Engineer: Detonate sentry gun for Engineer +#define TF_DISCARD_DROP_AMMO 82 +#define TF_PRACSPAWN_PLACE 83 +#define TF_PRACSPAWN_REMOVE 84 +#define TF_DISGUISE_LAST_SPAWNED 85 // Spy: Disguise as last enemy to spawn +#define TF_SPECIAL_SKILL_2 86 // Class special 2 +#define TF_ENGINEER_TOGGLESENTRY 87 // Engineer: Build or detonate sentry +#define TF_ENGINEER_TOGGLEDISP 88 // Engineer: Build or detonate dispenser // unused 89 // unused 90 // unused 91 @@ -466,48 +466,48 @@ // unused 97 // unused 98 // unused 99 -#define TF_CHANGETEAM 100 // Bring up team selection menu -#define TF_TEAM_1 101 // Join team 1 -#define TF_TEAM_2 102 // Join team 2 -#define TF_TEAM_3 103 // Join team 3 -#define TF_TEAM_4 104 // Join team 4 -#define TF_DISPLAYLOCATION 105 // Displays current location and angles (for developers) -#define TF_SHOWTF 106 // Displays server settings and mod version -#define TF_SHOWLEGALCLASSES 107 // Show what classes are allowed by current map -#define TF_SHOW_IDS 108 // Show ids of connected players -#define TF_ALIAS_CHECK 109 // Check if client has gotten all the aliases -#define TF_CHANGECLASS 110 // Bring up class selection menu -#define TF_CHANGEPC_SCOUT 111 // Change class to Scout -#define TF_CHANGEPC_SNIPER 112 // Change class to Sniper -#define TF_CHANGEPC_SOLDIER 113 // Change class to Soldier -#define TF_CHANGEPC_DEMOMAN 114 // Change class to Demoman -#define TF_CHANGEPC_MEDIC 115 // Change class to Medic -#define TF_CHANGEPC_HVYWEAP 116 // Change class to HWGuy -#define TF_CHANGEPC_PYRO 117 // Change class to Pyro -#define TF_CHANGEPC_SPY 118 // Change class to Spy -#define TF_CHANGEPC_ENGINEER 119 // Change class to Engineer -#define TF_CHANGEPC_RANDOM 120 // Change class to RandomPC -#define TF_HELP_MAP 121 // Displays current map objectives -#define TF_CLASSHELP 122 // Class help alias -#define TF_TEAM_CLASSES 123 // Display team classes -#define TF_TEAM_LIST 124 // Display the players in each team -#define TF_TEAM_SCORES 125 // Display team scores -#define TF_STATUS_QUERY 126 // Displays current team balance and equilization ratios -#define TF_NEXTTIP 127 // Shows the next general/class tip -// unused 128 +// unused 100 +#define TF_CHANGETEAM 101 // Bring up team selection menu +#define TF_TEAM_1 102 // Join team 1 +#define TF_TEAM_2 103 // Join team 2 +#define TF_TEAM_3 104 // Join team 3 +#define TF_TEAM_4 105 // Join team 4 +#define TF_DISPLAYLOCATION 106 // Displays current location and angles (for developers) +#define TF_SHOWTF 107 // Displays server settings and mod version +#define TF_SHOWLEGALCLASSES 108 // Show what classes are allowed by current map +#define TF_SHOW_IDS 109 // Show ids of connected players +#define TF_ALIAS_CHECK 110 // Check if client has gotten all the aliases +#define TF_CHANGECLASS 111 // Bring up class selection menu +#define TF_CHANGEPC_SCOUT 112 // Change class to Scout +#define TF_CHANGEPC_SNIPER 113 // Change class to Sniper +#define TF_CHANGEPC_SOLDIER 114 // Change class to Soldier +#define TF_CHANGEPC_DEMOMAN 115 // Change class to Demoman +#define TF_CHANGEPC_MEDIC 116 // Change class to Medic +#define TF_CHANGEPC_HVYWEAP 117 // Change class to HWGuy +#define TF_CHANGEPC_PYRO 118 // Change class to Pyro +#define TF_CHANGEPC_SPY 119 // Change class to Spy +#define TF_CHANGEPC_ENGINEER 120 // Change class to Engineer +#define TF_CHANGEPC_RANDOM 121 // Change class to RandomPC +#define TF_HELP_MAP 122 // Displays current map objectives +#define TF_CLASSHELP 123 // Class help alias +#define TF_TEAM_CLASSES 124 // Display team classes +#define TF_TEAM_LIST 125 // Display the players in each team +#define TF_TEAM_SCORES 126 // Display team scores +#define TF_STATUS_QUERY 127 // Displays current team balance and equilization ratios +#define TF_NEXTTIP 128 // Shows the next general/class tip // unused 129 -#define TF_TOGGLEVOTE 130 // Toggle vote menu on/off -#define TF_VOTENEXT 131 // Vote to start voting for next map -#define TF_VOTETRICK 132 // Vote to start voting for a trick map -#define TF_VOTERACE 133 // Vote to start voting for a race map -#define TF_FORCENEXT 134 // Vote to force a change to voted map -#define TF_PLAYER_READY 135 -#define TF_PLAYER_NOT_READY 136 -#define TF_ADMIN_FORCESTARTMATCH 137 -#define TF_ADMIN_READYSTATUS 138 -// unused 139 -#define TF_NAILGREN_INFO 140 -// unused 141 +// unused 130 +#define TF_TOGGLEVOTE 131 // Toggle vote menu on/off +#define TF_VOTENEXT 132 // Vote to start voting for next map +#define TF_VOTETRICK 133 // Vote to start voting for a trick map +#define TF_VOTERACE 134 // Vote to start voting for a race map +#define TF_FORCENEXT 135 // Vote to force a change to voted map +#define TF_PLAYER_READY 136 +#define TF_PLAYER_NOT_READY 137 +#define TF_ADMIN_FORCESTARTMATCH 138 +#define TF_ADMIN_READYSTATUS 139 +// unused 140 +#define TF_NAILGREN_INFO 141 // unused 142 // unused 143 // unused 144 @@ -555,17 +555,17 @@ // unused 186 // unused 187 // unused 188 -#define TF_ADMIN_CYCLEDEAL 189 -#define TF_ADMIN_KICK 190 -#define TF_ADMIN_BAN 191 -#define TF_ADMIN_COUNTPLAYERS 192 -#define TF_ADMIN_CEASEFIRE 193 -// unused 194 -#define TF_ADMIN_NEXT 195 -// unused 196 +// unused 189 +#define TF_ADMIN_CYCLEDEAL 190 +#define TF_ADMIN_KICK 191 +#define TF_ADMIN_BAN 192 +#define TF_ADMIN_COUNTPLAYERS 193 +#define TF_ADMIN_CEASEFIRE 194 +// unused 195 +#define TF_ADMIN_NEXT 196 // unused 197 -#define TF_ADMIN_LISTIPS 198 -// unused 199 +// unused 198 +#define TF_ADMIN_LISTIPS 199 // unused 200 // unused 201 // unused 202 @@ -573,10 +573,10 @@ // unused 204 // unused 205 // unused 206 -#define TF_ADMIN_CLANMODE 207 -#define TF_ADMIN_QUADMODE 208 -#define TF_ADMIN_DUELMODE 209 -// unused 210 +// unused 207 +#define TF_ADMIN_CLANMODE 208 +#define TF_ADMIN_QUADMODE 209 +#define TF_ADMIN_DUELMODE 210 // unused 211 // unused 212 // unused 213 @@ -605,8 +605,8 @@ // unused 236 // unused 237 // unused 238 -#define TF_ADMIN_ADMINMENU 239 -// unused 240 +// unused 239 +#define TF_ADMIN_ADMINMENU 240 // unused 241 // unused 242 // unused 243 diff --git a/ssqc/client.qc b/ssqc/client.qc index 819e3cf2..2dcaf18c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2619,6 +2619,14 @@ void () PlayerPreThink = { self.flags = self.flags | FL_JUMPRELEASED; } } + + if ((self.impulse == TF_SPY_DIE_OFF) && (self.playerclass == PC_SPY)) { + self.feign_next_damage = 0; + if (self.is_feigning) { + CF_Spy_FeignDeath(0); + } + } + if ((time < self.pausetime) || (cease_fire == 1)) { self.velocity = '0 0 0'; } @@ -2798,6 +2806,7 @@ void () PlayerPostThink = { if (self.view_ofs == '0 0 0') { return; } + if (self.deadflag) { DeadImpulses(); self.impulse = 0; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 970510a0..0bc03532 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -442,9 +442,9 @@ void (entity targ, entity inflictor, entity attacker, float damage, } } } - + HitSound(targ, inflictor, attacker, damage); - + damage_attacker = attacker; if (teamplay & (TEAMPLAY_LESSSCOREHELP | TEAMPLAY_LESSPLAYERSHELP)) @@ -680,6 +680,11 @@ void (entity targ, entity inflictor, entity attacker, float damage, self.pain_finished = time + 5; } } + + if (self.feign_next_damage && !self.is_feigning){ + CF_Spy_FeignDeath(0); + } + self = oldself; }; diff --git a/ssqc/help.qc b/ssqc/help.qc index e8a7b0fe..9b59e9ec 100644 --- a/ssqc/help.qc +++ b/ssqc/help.qc @@ -146,6 +146,7 @@ void () Help_ShowSpy = { sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Spy:\n"); sprint(self, PRINT_HIGH, Q"\sfeign\s - Feign death\n"); + sprint(self, PRINT_HIGH, Q"\s+feign\s - Hold to feign death\n"); sprint(self, PRINT_HIGH, Q"\ssfeign\s - Silently feign death\n"); }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 26515761..a9e89e93 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -27,6 +27,7 @@ typedef void (float n) f_void_float; .float is_building; // TRUE for an ENGINEER if they're building something .float is_detpacking; // TRUE for a DEMOMAN if they're setting a detpack .float is_feigning; // TRUE for a SPY if they're feigning death +.float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float is_quickfiring; // TRUE for a player if they're using the quick slots diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index e9c9fc99..0db5c96e 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -219,6 +219,8 @@ void () TeamFortress_MOTD = { } else { TeamFortress_Alias("disguise", TF_SPY_SPY, 0); } + TeamFortress_Alias("+feign", TF_SPY_DIE_ON, 0); + TeamFortress_Alias("-feign", TF_SPY_DIE_OFF, 0); TeamFortress_Alias("feign", TF_SPY_DIE, 0); TeamFortress_Alias("sfeign", TF_SPY_SILENT_DIE, 0); } else if (self.motd == 110) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5a43c6cf..7dcc52e9 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3052,9 +3052,10 @@ void () ImpulseCommands = { CF_Scout_Dash(); else if (self.impulse == TF_PB_DETONATE) clearImpulse = TeamFortress_DetonatePipebombs(0); - else if (self.impulse == TF_DETPACK_STOP) + else if (self.impulse == TF_DETPACK_STOP) { + sprint(self, PRINT_HIGH, "detpack_stop\n"); TeamFortress_DetpackStop(); - else if (self.impulse == TF_MEDIC_AURA_TOGGLE) + } else if (self.impulse == TF_MEDIC_AURA_TOGGLE) CF_Medic_AuraToggle(); else if ((self.impulse == TF_ENGINEER_DETSENTRY) && (self.playerclass == PC_ENGINEER)) @@ -3094,8 +3095,9 @@ void () ImpulseCommands = { Menu_Spy_Skin(); } else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) CF_Spy_FeignDeath(0); - else if ((self.impulse == TF_SPY_SILENT_DIE) && - (self.playerclass == PC_SPY)) + else if ((self.impulse == TF_SPY_DIE_ON) && (self.playerclass == PC_SPY)) { + self.feign_next_damage = 1; + } else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) CF_Spy_FeignDeath(1); else if (self.impulse == TF_DISGUISE_RESET && self.playerclass == PC_SPY) { CF_Spy_ChangeSkin(self, 8); @@ -3148,8 +3150,9 @@ void () ImpulseCommands = { TeamFortress_DisplayDetectionItems(); } else if (self.impulse == TF_DISPLAYLOCATION) display_location(); - else + else { DeadImpulses(); + } if (self.impulse == TF_DETPACK) self.last_impulse = self.impulse; @@ -3376,7 +3379,12 @@ void () W_WeaponFrame = { return; } - if (self.is_feigning && self.impulse != TF_SPECIAL_SKILL && self.impulse != TF_SPECIAL_SKILL_2 && self.impulse != TF_MEDIC_HELPME && self.impulse != TF_SPY_DIE && self.impulse != TF_SPY_SILENT_DIE) + if ((self.is_feigning) && + (self.impulse != TF_SPECIAL_SKILL) && + (self.impulse != TF_SPECIAL_SKILL_2) && + (self.impulse != TF_MEDIC_HELPME) && + (self.impulse != TF_SPY_DIE) && + (self.impulse != TF_SPY_SILENT_DIE)) return; if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { From 1cd8537fd7ed5fb5e4b62d1e4b9b1405a15be86f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 22 Jun 2022 00:58:41 +1000 Subject: [PATCH 1505/2474] WIP +special --- README.md | 4 +- csqc/main.qc | 59 +++++++++++ share/defs.h | 268 +++++++++++++++++++++++------------------------ ssqc/hwguy.qc | 21 +++- ssqc/pyro.qc | 10 ++ ssqc/tfort.qc | 19 +--- ssqc/tforthlp.qc | 2 + ssqc/weapons.qc | 11 +- 8 files changed, 237 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index 4ea3d9be..cf067ab5 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,12 @@ FortressOne Server New features ------ +* `+rj` Switches to rocket/incendiary weapon, jumps and shoots. Bind jump key to `+aux_jump` to prevent `-jump` from interupting auto-hop. * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. -* `+special2` Scout: `autoscan`, Soldier: `+rj`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: Toggle build / det sentry +* `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledisp` +* `+special2` Scout: `autoscan`, Soldier: `+rj`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: `togglesentry` * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. diff --git a/csqc/main.qc b/csqc/main.qc index 244783f0..3492ed8a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -55,6 +55,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("+aux_jump"); registercommand("-aux_jump"); + registercommand("+special"); + registercommand("-special"); registercommand("+special2"); registercommand("-special2"); registercommand("+rj"); @@ -299,6 +301,63 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("-jump\n"); } + break; + case "+special": + switch (player_class) { + case PC_SCOUT: + localcmd("dash\n"); + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + localcmd("detpipe\n"); + break; + case PC_MEDIC: + localcmd("aura\n"); + break; + case PC_HVYWEAP: + localcmd("locktoggle\n"); + break; + case PC_PYRO: + localcmd("airblast\n"); + break; + case PC_SPY: + localcmd("+feign\n"); + break; + case PC_ENGINEER: + localcmd("toggledisp\n"); + break; + case PC_UNDEFINED: + break; + } + break; + case "-special": + switch (player_class) { + case PC_SCOUT: + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + localcmd("-det5\n"); + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + break; + case PC_SPY: + localcmd("-feign\n"); + break; + case PC_ENGINEER: + break; + case PC_UNDEFINED: + break; + } break; case "+special2": switch (player_class) { diff --git a/share/defs.h b/share/defs.h index 6634d776..fab50ee8 100644 --- a/share/defs.h +++ b/share/defs.h @@ -367,96 +367,96 @@ /*======================================================*/ /* Impulse Defines */ /*======================================================*/ -#define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) -#define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) -#define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) -#define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) -#define TF_CLASSMENU 5 // Brings up class menu +#define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) +#define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) +#define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) +#define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_CLASSMENU 5 // Brings up class menu // unused 6 // unused 7 // unused 8 // unused 9 // unused 10 -#define TF_WEAPNEXT 11 // Selects the next weapon slot -#define TF_WEAPPREV 12 // Selects the previous weapon slot -#define TF_WEAPLAST 13 // Selects the last used weapon slot -#define TF_GRENADE_1 14 // Prime grenade type 1 -#define TF_GRENADE_2 15 // Prime grenade type 2 -#define TF_GRENADE_T 16 // Throw primed grenade -#define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) -#define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) -#define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 -#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon -#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon -#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon -#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon -#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped -#define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 -#define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 -#define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 -#define TF_RELOAD 28 // Reload current weapon -#define TF_RELOAD_NEXT 29 // Reload next weapon with a non-full clip -#define TF_SPECIAL_SKILL 30 // Class special -#define TF_DROPFLAG 31 // Drop flag -#define TF_DROPKEY 32 // Drop key -#define TF_DISCARD 33 // Discard useless ammo -#define TF_DROP_AMMO 34 // Drop an ammo box on the ground -#define TF_MEDIC_HELPME 35 // Alert players around you that you are in need of medical attention -#define TF_INVENTORY 36 // Displays current inventory -#define FLAG_INFO 37 // Displays current flag location -#define TF_ID 38 // Identify player/object in front of player -#define TF_ID_TEAM 39 // Identify team player/object in front of player -#define TF_ID_ENEMY 40 // Identify enemy player/object in front of player -#define TF_DASH 41 // Scout: Initialize a forward bunnyhop -#define TF_SCAN 42 // Scout: Toggle Scanner on/off -#define TF_SCAN_ENEMY 43 // Scout: Toggle scanning of enemies -#define TF_SCAN_FRIENDLY 44 // Scout: Toggle scanning of friendlies -#define TF_SCAN_SOUND 45 // Scout: Toggle scanner sound -#define TF_ZOOMTOGGLE 46 // Sniper: Toggle zoom mode on/off -#define TF_ZOOMIN 47 // Sniper: Zoom in (while zoom mode is on) -#define TF_ZOOMOUT 48 // Sniper: Zoom out (while zoom mode is on) -#define TF_DEMOMAN_DETPACK 49 // Demoman: Bring up detpack menu -#define TF_DETPACK 50 // Demoman: Detpack Pre-Impulse -#define TF_DETPACK_STOP 51 // Demoman: Impulse to stop setting detpack -#define TF_DETPACK_5 52 // Demoman: Detpack set to 5 seconds -#define TF_DETPACK_20 53 // Demoman: Detpack set to 20 seconds -#define TF_DETPACK_50 54 // Demoman: Detpack set to 50 seconds -#define TF_PB_DETONATE 55 // Demoman: Detonate Pipebombs -#define TF_MEDIC_AURA_TOGGLE 56 // Medic: Toggle Healing Aura on/off -#define TF_LOCKON 57 // HWGuy: Turn Assault Cannon fire on -#define TF_LOCKOFF 58 // HWGuy: Turn Assault Cannon fire off -#define TF_SPY_DIE 59 // Spy: Feign death -#define TF_SPY_DIE_ON 60 // Spy: Feign death next damage -#define TF_SPY_DIE_OFF 61 // Spy: Unfeign -#define TF_SPY_SILENT_DIE 62 // Spy: Silent feign death -#define TF_SPY_SPY 63 // Spy: Bring up disguise menu -#define TF_DISGUISE_ENEMY 64 // Spy: Disguise as enemy team -#define TF_DISGUISE_LAST 65 // Spy: Use last disguise -#define TF_DISGUISE_RESET 66 // Spy: Reset disguise -#define TF_DISGUISE_SCOUT 67 // Spy: Disguise as Scout -#define TF_DISGUISE_SNIPER 68 // Spy: Disguise as Sniper -#define TF_DISGUISE_SOLDIER 69 // Spy: Disguise as Soldier -#define TF_DISGUISE_DEMOMAN 70 // Spy: Disguise as Demoman -#define TF_DISGUISE_MEDIC 71 // Spy: Disguise as Medic -#define TF_DISGUISE_HWGUY 72 // Spy: Disguise as HWGuy -#define TF_DISGUISE_PYRO 73 // Spy: Disguise as Pyro -#define TF_DISGUISE_ENGINEER 74 // Spy: Disguise as Engineer -#define TF_DISGUISE_BLUE 75 // Spy: Disguise as blue team -#define TF_DISGUISE_RED 76 // Spy: Disguise as red team -#define TF_DISGUISE_YELLOW 77 // Spy: Disguise as yellow team -#define TF_DISGUISE_GREEN 78 // Spy: Disguise as green team -#define TF_ENGINEER_BUILD 79 // Engineer: Bring up build menu for Engineer -#define TF_ENGINEER_DETDISP 80 // Engineer: Detonate dispenser for Engineer -#define TF_ENGINEER_DETSENTRY 81 // Engineer: Detonate sentry gun for Engineer -#define TF_DISCARD_DROP_AMMO 82 -#define TF_PRACSPAWN_PLACE 83 -#define TF_PRACSPAWN_REMOVE 84 -#define TF_DISGUISE_LAST_SPAWNED 85 // Spy: Disguise as last enemy to spawn -#define TF_SPECIAL_SKILL_2 86 // Class special 2 -#define TF_ENGINEER_TOGGLESENTRY 87 // Engineer: Build or detonate sentry -#define TF_ENGINEER_TOGGLEDISP 88 // Engineer: Build or detonate dispenser -// unused 89 -// unused 90 +#define TF_WEAPNEXT 11 // Selects the next weapon slot +#define TF_WEAPPREV 12 // Selects the previous weapon slot +#define TF_WEAPLAST 13 // Selects the last used weapon slot +#define TF_GRENADE_1 14 // Prime grenade type 1 +#define TF_GRENADE_2 15 // Prime grenade type 2 +#define TF_GRENADE_T 16 // Throw primed grenade +#define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) +#define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) +#define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 +#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon +#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon +#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon +#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon +#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped +#define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 +#define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 +#define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 +#define TF_RELOAD 28 // Reload current weapon +#define TF_RELOAD_NEXT 29 // Reload next weapon with a non-full clip +#define TF_SPECIAL_SKILL 30 // Class special +#define TF_DROPFLAG 31 // Drop flag +#define TF_DROPKEY 32 // Drop key +#define TF_DISCARD 33 // Discard useless ammo +#define TF_DROP_AMMO 34 // Drop an ammo box on the ground +#define TF_MEDIC_HELPME 35 // Alert players around you that you are in need of medical attention +#define TF_INVENTORY 36 // Displays current inventory +#define FLAG_INFO 37 // Displays current flag location +#define TF_ID 38 // Identify player/object in front of player +#define TF_ID_TEAM 39 // Identify team player/object in front of player +#define TF_ID_ENEMY 40 // Identify enemy player/object in front of player +#define TF_DASH 41 // Scout: Initialize a forward bunnyhop +#define TF_SCAN 42 // Scout: Toggle Scanner on/off +#define TF_SCAN_ENEMY 43 // Scout: Toggle scanning of enemies +#define TF_SCAN_FRIENDLY 44 // Scout: Toggle scanning of friendlies +#define TF_SCAN_SOUND 45 // Scout: Toggle scanner sound +#define TF_ZOOMTOGGLE 46 // Sniper: Toggle zoom mode on/off +#define TF_ZOOMIN 47 // Sniper: Zoom in (while zoom mode is on) +#define TF_ZOOMOUT 48 // Sniper: Zoom out (while zoom mode is on) +#define TF_DEMOMAN_DETPACK 49 // Demoman: Bring up detpack menu +#define TF_DETPACK 50 // Demoman: Detpack Pre-Impulse +#define TF_DETPACK_STOP 51 // Demoman: Impulse to stop setting detpack +#define TF_DETPACK_5 52 // Demoman: Detpack set to 5 seconds +#define TF_DETPACK_20 53 // Demoman: Detpack set to 20 seconds +#define TF_DETPACK_50 54 // Demoman: Detpack set to 50 seconds +#define TF_PB_DETONATE 55 // Demoman: Detonate Pipebombs +#define TF_MEDIC_AURA_TOGGLE 56 // Medic: Toggle Healing Aura on/off +#define TF_HVYWEAP_LOCK_TOGGLE 57 // Medic: Toggle Healing Aura on/off +#define TF_LOCKON 58 // HWGuy: Turn Assault Cannon fire on +#define TF_LOCKOFF 59 // HWGuy: Turn Assault Cannon fire off +#define TF_AIRBLAST 60 // Pyro: Air blast +#define TF_SPY_DIE 61 // Spy: Feign death +#define TF_SPY_DIE_ON 62 // Spy: Feign death next damage +#define TF_SPY_DIE_OFF 63 // Spy: Unfeign +#define TF_SPY_SILENT_DIE 64 // Spy: Silent feign death +#define TF_SPY_SPY 65 // Spy: Bring up disguise menu +#define TF_DISGUISE_ENEMY 66 // Spy: Disguise as enemy team +#define TF_DISGUISE_LAST 67 // Spy: Use last disguise +#define TF_DISGUISE_RESET 68 // Spy: Reset disguise +#define TF_DISGUISE_SCOUT 69 // Spy: Disguise as Scout +#define TF_DISGUISE_SNIPER 70 // Spy: Disguise as Sniper +#define TF_DISGUISE_SOLDIER 71 // Spy: Disguise as Soldier +#define TF_DISGUISE_DEMOMAN 72 // Spy: Disguise as Demoman +#define TF_DISGUISE_MEDIC 73 // Spy: Disguise as Medic +#define TF_DISGUISE_HWGUY 74 // Spy: Disguise as HWGuy +#define TF_DISGUISE_PYRO 75 // Spy: Disguise as Pyro +#define TF_DISGUISE_ENGINEER 76 // Spy: Disguise as Engineer +#define TF_DISGUISE_BLUE 77 // Spy: Disguise as blue team +#define TF_DISGUISE_RED 78 // Spy: Disguise as red team +#define TF_DISGUISE_YELLOW 79 // Spy: Disguise as yellow team +#define TF_DISGUISE_GREEN 80 // Spy: Disguise as green team +#define TF_ENGINEER_BUILD 81 // Engineer: Bring up build menu for Engineer +#define TF_ENGINEER_DETDISP 82 // Engineer: Detonate dispenser for Engineer +#define TF_ENGINEER_DETSENTRY 83 // Engineer: Detonate sentry gun for Engineer +#define TF_DISCARD_DROP_AMMO 84 +#define TF_PRACSPAWN_PLACE 85 +#define TF_PRACSPAWN_REMOVE 86 +#define TF_DISGUISE_LAST_SPAWNED 87 // Spy: Disguise as last enemy to spawn +#define TF_SPECIAL_SKILL_2 88 // Class special 2 +#define TF_ENGINEER_TOGGLESENTRY 89 // Engineer: Build or detonate sentry +#define TF_ENGINEER_TOGGLEDISP 90 // Engineer: Build or detonate dispenser // unused 91 // unused 92 // unused 93 @@ -467,47 +467,47 @@ // unused 98 // unused 99 // unused 100 -#define TF_CHANGETEAM 101 // Bring up team selection menu -#define TF_TEAM_1 102 // Join team 1 -#define TF_TEAM_2 103 // Join team 2 -#define TF_TEAM_3 104 // Join team 3 -#define TF_TEAM_4 105 // Join team 4 -#define TF_DISPLAYLOCATION 106 // Displays current location and angles (for developers) -#define TF_SHOWTF 107 // Displays server settings and mod version -#define TF_SHOWLEGALCLASSES 108 // Show what classes are allowed by current map -#define TF_SHOW_IDS 109 // Show ids of connected players -#define TF_ALIAS_CHECK 110 // Check if client has gotten all the aliases -#define TF_CHANGECLASS 111 // Bring up class selection menu -#define TF_CHANGEPC_SCOUT 112 // Change class to Scout -#define TF_CHANGEPC_SNIPER 113 // Change class to Sniper -#define TF_CHANGEPC_SOLDIER 114 // Change class to Soldier -#define TF_CHANGEPC_DEMOMAN 115 // Change class to Demoman -#define TF_CHANGEPC_MEDIC 116 // Change class to Medic -#define TF_CHANGEPC_HVYWEAP 117 // Change class to HWGuy -#define TF_CHANGEPC_PYRO 118 // Change class to Pyro -#define TF_CHANGEPC_SPY 119 // Change class to Spy -#define TF_CHANGEPC_ENGINEER 120 // Change class to Engineer -#define TF_CHANGEPC_RANDOM 121 // Change class to RandomPC -#define TF_HELP_MAP 122 // Displays current map objectives -#define TF_CLASSHELP 123 // Class help alias -#define TF_TEAM_CLASSES 124 // Display team classes -#define TF_TEAM_LIST 125 // Display the players in each team -#define TF_TEAM_SCORES 126 // Display team scores -#define TF_STATUS_QUERY 127 // Displays current team balance and equilization ratios -#define TF_NEXTTIP 128 // Shows the next general/class tip +#define TF_CHANGETEAM 101 // Bring up team selection menu +#define TF_TEAM_1 102 // Join team 1 +#define TF_TEAM_2 103 // Join team 2 +#define TF_TEAM_3 104 // Join team 3 +#define TF_TEAM_4 105 // Join team 4 +#define TF_DISPLAYLOCATION 106 // Displays current location and angles (for developers) +#define TF_SHOWTF 107 // Displays server settings and mod version +#define TF_SHOWLEGALCLASSES 108 // Show what classes are allowed by current map +#define TF_SHOW_IDS 109 // Show ids of connected players +#define TF_ALIAS_CHECK 110 // Check if client has gotten all the aliases +#define TF_CHANGECLASS 111 // Bring up class selection menu +#define TF_CHANGEPC_SCOUT 112 // Change class to Scout +#define TF_CHANGEPC_SNIPER 113 // Change class to Sniper +#define TF_CHANGEPC_SOLDIER 114 // Change class to Soldier +#define TF_CHANGEPC_DEMOMAN 115 // Change class to Demoman +#define TF_CHANGEPC_MEDIC 116 // Change class to Medic +#define TF_CHANGEPC_HVYWEAP 117 // Change class to HWGuy +#define TF_CHANGEPC_PYRO 118 // Change class to Pyro +#define TF_CHANGEPC_SPY 119 // Change class to Spy +#define TF_CHANGEPC_ENGINEER 120 // Change class to Engineer +#define TF_CHANGEPC_RANDOM 121 // Change class to RandomPC +#define TF_HELP_MAP 122 // Displays current map objectives +#define TF_CLASSHELP 123 // Class help alias +#define TF_TEAM_CLASSES 124 // Display team classes +#define TF_TEAM_LIST 125 // Display the players in each team +#define TF_TEAM_SCORES 126 // Display team scores +#define TF_STATUS_QUERY 127 // Displays current team balance and equilization ratios +#define TF_NEXTTIP 128 // Shows the next general/class tip // unused 129 // unused 130 -#define TF_TOGGLEVOTE 131 // Toggle vote menu on/off -#define TF_VOTENEXT 132 // Vote to start voting for next map -#define TF_VOTETRICK 133 // Vote to start voting for a trick map -#define TF_VOTERACE 134 // Vote to start voting for a race map -#define TF_FORCENEXT 135 // Vote to force a change to voted map -#define TF_PLAYER_READY 136 -#define TF_PLAYER_NOT_READY 137 -#define TF_ADMIN_FORCESTARTMATCH 138 -#define TF_ADMIN_READYSTATUS 139 +#define TF_TOGGLEVOTE 131 // Toggle vote menu on/off +#define TF_VOTENEXT 132 // Vote to start voting for next map +#define TF_VOTETRICK 133 // Vote to start voting for a trick map +#define TF_VOTERACE 134 // Vote to start voting for a race map +#define TF_FORCENEXT 135 // Vote to force a change to voted map +#define TF_PLAYER_READY 136 +#define TF_PLAYER_NOT_READY 137 +#define TF_ADMIN_FORCESTARTMATCH 138 +#define TF_ADMIN_READYSTATUS 139 // unused 140 -#define TF_NAILGREN_INFO 141 +#define TF_NAILGREN_INFO 141 // unused 142 // unused 143 // unused 144 @@ -556,16 +556,16 @@ // unused 187 // unused 188 // unused 189 -#define TF_ADMIN_CYCLEDEAL 190 -#define TF_ADMIN_KICK 191 -#define TF_ADMIN_BAN 192 -#define TF_ADMIN_COUNTPLAYERS 193 -#define TF_ADMIN_CEASEFIRE 194 +#define TF_ADMIN_CYCLEDEAL 190 +#define TF_ADMIN_KICK 191 +#define TF_ADMIN_BAN 192 +#define TF_ADMIN_COUNTPLAYERS 193 +#define TF_ADMIN_CEASEFIRE 194 // unused 195 -#define TF_ADMIN_NEXT 196 +#define TF_ADMIN_NEXT 196 // unused 197 // unused 198 -#define TF_ADMIN_LISTIPS 199 +#define TF_ADMIN_LISTIPS 199 // unused 200 // unused 201 // unused 202 @@ -574,9 +574,9 @@ // unused 205 // unused 206 // unused 207 -#define TF_ADMIN_CLANMODE 208 -#define TF_ADMIN_QUADMODE 209 -#define TF_ADMIN_DUELMODE 210 +#define TF_ADMIN_CLANMODE 208 +#define TF_ADMIN_QUADMODE 209 +#define TF_ADMIN_DUELMODE 210 // unused 211 // unused 212 // unused 213 @@ -606,7 +606,7 @@ // unused 237 // unused 238 // unused 239 -#define TF_ADMIN_ADMINMENU 240 +#define TF_ADMIN_ADMINMENU 240 // unused 241 // unused 242 // unused 243 diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 772edd4a..a1a8a5a1 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -116,17 +116,17 @@ void FireAssCan (float shotcount, vector dir, vector spread) self.reload_assault_cannon = self.reload_assault_cannon + 1; Status_Refresh(self); CheckForReload(); - + vector bullet_dir, spread_dir, rand_dir, org; - float bullet_speed, var_speed; + float bullet_speed, var_speed; makevectors(self.v_angle); // Infront of player model and down towards gun bullet_speed = PC_HVYWEAP_PROJSPEED; bullet_dir = normalize(v_forward * bullet_speed); - - while (shotcount > 0) { + + while (shotcount > 0) { var_speed = crandom()*10 + bullet_speed; // Slight speed variance rand_dir = (crandom()*spread_x) * v_right + (crandom()*spread_y) * v_up; spread_dir = bullet_dir + rand_dir; @@ -137,3 +137,16 @@ void FireAssCan (float shotcount, vector dir, vector spread) shotcount = shotcount - 1; } } + +void FO_LockToggle () { + if (self.tfstate & TFSTATE_LOCK) { + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); + } else { + self.tfstate = self.tfstate | TFSTATE_LOCK; + } + + Status_Refresh(self); + /* self.impulse = 0; */ + /* this shouldn't be here, I think we just need to allow this impulse while shooting */ + /* worth checking detpipes for this too */ +} diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 01cf64d0..5f9d0477 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -765,6 +765,16 @@ void () AirBlastReloadFinished = { dremove(self); }; +void FO_Airblast() = { + if (pyro_type == PYRO_FO) + if (airblastv2) { + UseAirBlastV2(); + } else { + UseAirBlast(); + } + Status_Refresh(self); +} + void () UseAirBlast = { if (self.special_cooldown < time) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 9d2102d6..f1841d7b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -58,23 +58,10 @@ void () UseSpecialSkill = { self.impulse = TF_MEDIC_AURA_TOGGLE; break; case PC_HVYWEAP: - if (self.tfstate & TFSTATE_LOCK) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); - else - self.tfstate = self.tfstate | TFSTATE_LOCK; - Status_Refresh(self); - self.impulse = 0; - return; + self.impulse = TF_HVYWEAP_LOCK_TOGGLE; + break; case PC_PYRO: - if (pyro_type == PYRO_FO) - if (airblastv2) { - UseAirBlastV2(); - } - else - { - UseAirBlast(); - } - Status_Refresh(self); + self.impulse = TF_AIRBLAST; break; case PC_SPY: self.impulse = TF_SPY_DIE; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 0db5c96e..18ac2199 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -210,10 +210,12 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); } else if (self.motd == 100) { TeamFortress_Alias("aura", TF_MEDIC_AURA_TOGGLE, 0); + TeamFortress_Alias("locktoggle", TF_HVYWEAP_LOCK_TOGGLE, 0); TeamFortress_Alias("lock", TF_LOCKON, 0); TeamFortress_Alias("unlock", TF_LOCKOFF, 0); TeamFortress_Alias("+lock", TF_LOCKON, 0); TeamFortress_Alias("-lock", TF_LOCKOFF, 0); + TeamFortress_Alias("airblast", TF_AIRBLAST, 0); if(csqcactive) { TeamFortress_AliasString("disguise", "fo_menu_disguise"); } else { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 7dcc52e9..154ea07b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -55,6 +55,10 @@ void () CF_Scout_Dash; void () CF_Spy_DisguiseStop; void () TeamFortress_DetpackMenu; void () CF_Medic_AuraToggle; +void () FO_LockToggle; +void () FO_Airblast; +void () UseAirBlast; +void () UseAirBlastV2; void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; @@ -3053,10 +3057,13 @@ void () ImpulseCommands = { else if (self.impulse == TF_PB_DETONATE) clearImpulse = TeamFortress_DetonatePipebombs(0); else if (self.impulse == TF_DETPACK_STOP) { - sprint(self, PRINT_HIGH, "detpack_stop\n"); TeamFortress_DetpackStop(); } else if (self.impulse == TF_MEDIC_AURA_TOGGLE) CF_Medic_AuraToggle(); + else if (self.impulse == TF_HVYWEAP_LOCK_TOGGLE && self.playerclass == PC_HVYWEAP) + FO_LockToggle(); + else if (self.impulse == TF_AIRBLAST && self.playerclass == PC_PYRO) + FO_Airblast(); else if ((self.impulse == TF_ENGINEER_DETSENTRY) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_sentrygun"); @@ -3494,7 +3501,7 @@ void () W_WeaponFrame = { Menu_Class(0); self.impulse = 0; return; - } + } if (intermission_running) return; From 8cf27bf8a0ff29bae66dcbeb0137dd13dac161f2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 22 Jun 2022 01:21:56 +1000 Subject: [PATCH 1506/2474] Fix heavy lock --- ssqc/weapons.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 154ea07b..da602185 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3507,11 +3507,16 @@ void () W_WeaponFrame = { // hwguy assault cannon special if (self.playerclass == PC_HVYWEAP) { - if (cannon_lock && (self.impulse == TF_LOCKON || self.impulse == TF_LOCKOFF)) { + if (cannon_lock && + ((self.impulse == TF_LOCKON) || + (self.impulse == TF_LOCKOFF) || + (self.impulse == TF_HVYWEAP_LOCK_TOGGLE))) { if (self.impulse == TF_LOCKON) self.tfstate = self.tfstate | TFSTATE_LOCK; else if (self.impulse == TF_LOCKOFF) self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); + else if (self.impulse == TF_HVYWEAP_LOCK_TOGGLE) + FO_LockToggle(); Status_Refresh(self); self.impulse = 0; return; From 9b8070f57a204991228a1e71bff4bee651861fd6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 25 Jun 2022 13:49:04 +1000 Subject: [PATCH 1507/2474] WIP +special and +special2 buttons --- csqc/csextradefs.qc | 9 +- csqc/main.qc | 167 +++++++---------------- csqc/vote.qc | 1 - ssqc/client.qc | 8 +- ssqc/engineer.qc | 12 ++ ssqc/menu.qc | 3 + ssqc/pyro.qc | 8 -- ssqc/qw.qc | 3 +- ssqc/spy.qc | 321 ++++++++++++++++++++++---------------------- ssqc/tforthlp.qc | 2 +- ssqc/weapons.qc | 167 +++++++++++++++++++++-- ssqc/world.qc | 2 +- 12 files changed, 400 insertions(+), 303 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index ffbbb093..86da6efb 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -49,7 +49,6 @@ vector TEXT_TEAM_COLOUR[] = { #define FO_MENU_STATE_SPACER 3 #define FO_MENU_MAX_OPTIONS 20 - #define FO_MENU_TRANSPARENCY 0.2 #define MOTD_TIME 30 @@ -57,6 +56,14 @@ vector TEXT_TEAM_COLOUR[] = { #define TEAM_SPECTATOR 9 #define TEAM_OBSERVER 99 +#define BUTTON0 1 +/* #define BUTTON1 ? */ +#define BUTTON2 2 +#define BUTTON3 4 +#define BUTTON4 8 +#define BUTTON5 16 +#define BUTTON6 32 + #define MAP_MAX_CHARS 20 .float owned_by; diff --git a/csqc/main.qc b/csqc/main.qc index 3492ed8a..71160199 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -12,6 +12,7 @@ void FO_WriteSettings(); void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); +void InterceptRocketJump(); float IsValidToUseGrenades(); void GetSelf() = { @@ -303,140 +304,26 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; case "+special": - switch (player_class) { - case PC_SCOUT: - localcmd("dash\n"); - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; - case PC_DEMOMAN: - localcmd("detpipe\n"); - break; - case PC_MEDIC: - localcmd("aura\n"); - break; - case PC_HVYWEAP: - localcmd("locktoggle\n"); - break; - case PC_PYRO: - localcmd("airblast\n"); - break; - case PC_SPY: - localcmd("+feign\n"); - break; - case PC_ENGINEER: - localcmd("toggledisp\n"); - break; - case PC_UNDEFINED: - break; - } + localcmd("+button3"); break; case "-special": - switch (player_class) { - case PC_SCOUT: - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; - case PC_DEMOMAN: - localcmd("-det5\n"); - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - break; - case PC_SPY: - localcmd("-feign\n"); - break; - case PC_ENGINEER: - break; - case PC_UNDEFINED: - break; - } + localcmd("-button3"); break; case "+special2": - switch (player_class) { - case PC_SCOUT: - localcmd("autoscan\n"); - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - localcmd("+rj\n"); - break; - case PC_DEMOMAN: - localcmd("+det5\n"); - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - localcmd("+rj\n"); - break; - case PC_SPY: - localcmd("dlastspawn\n"); - break; - case PC_ENGINEER: - localcmd("togglesentry\n"); - break; - case PC_UNDEFINED: - break; - } + localcmd("+button4"); break; case "-special2": - switch (player_class) { - case PC_SCOUT: - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - localcmd("-rj\n"); - break; - case PC_DEMOMAN: - localcmd("-det5\n"); - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - localcmd("-rj\n"); - break; - case PC_SPY: - break; - case PC_ENGINEER: - break; - case PC_UNDEFINED: - break; - } + localcmd("-button4"); break; case "+rj": - if (player_class == PC_SOLDIER) { - localcmd("impulse 1\n"); - } else if (player_class == PC_PYRO) { - localcmd("impulse 2\n"); - } else { - break; + if (player_class == PC_SOLDIER || player_class == PC_PYRO) { + localcmd("+button4"); } - - localcmd("+attack\n"); - localcmd("+aux_jump\n"); - break; case "-rj": - if (player_class != PC_SOLDIER && player_class != PC_PYRO) { - break; + if (player_class == PC_SOLDIER || player_class == PC_PYRO) { + localcmd("-button4"); } - - localcmd("-attack\n"); - localcmd("-aux_jump\n"); - break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -469,6 +356,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { + InterceptRocketJump(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -506,3 +394,38 @@ void StopGrenTimers() { FO_Hud_Grentimers[i].icon_index = 0; } } + +void InterceptRocketJump() { + if (!(input_buttons & BUTTON4)) { + return; + } + + if (player_class != PC_SOLDIER && player_class != PC_PYRO) { + return; + } + + // unpress +special2 + input_buttons = input_buttons & ~BUTTON4; + + local float active_weapon = getstatf(STAT_ACTIVEWEAPON); + local float rj_weapon = 32; + + if (active_weapon != rj_weapon) { + local string rj_weapon_impulse; + + if (player_class == PC_SOLDIER) { + // need to consider old impulses + rj_weapon_impulse = "impulse 1\n"; + } + + if (player_class == PC_PYRO) { + // need to consider old impulses + rj_weapon_impulse = "impulse 2\n"; + } + + localcmd(rj_weapon_impulse); + } else { + // press +jump and +attack + input_buttons |= BUTTON0 + BUTTON2; + } +} diff --git a/csqc/vote.qc b/csqc/vote.qc index 2018e4b9..e115c0af 100644 --- a/csqc/vote.qc +++ b/csqc/vote.qc @@ -1,4 +1,3 @@ - void () ApplyMapFilter = { entity mc = find(world, classname, "map_candidate_filtered"); entity temp = world; diff --git a/ssqc/client.qc b/ssqc/client.qc index 2dcaf18c..888fcfd0 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2389,8 +2389,10 @@ void () PlayerJump = { } return; } + if (!(self.flags & FL_ONGROUND)) return; + if (!(self.flags & FL_JUMPRELEASED)) return; @@ -2418,6 +2420,7 @@ void () PlayerJump = { TeamFortress_SetSpeed(self); } } + if (old_grens != 1) { te = find(world, classname, "timer"); while (((te.owner != self) || (te.think != ConcussionGrenadeTimer)) @@ -2586,6 +2589,7 @@ void () PlayerPreThink = { if (self.deadflag == 1) { return; } + if (self.is_feigning) { if (self.flags & FL_ONGROUND) { // check area for entities - if found, bounce player forward @@ -2815,7 +2819,7 @@ void () PlayerPostThink = { local float fdmg; - if (((self.jump_flag < -300) && (self.flags & 512)) && + if (((self.jump_flag < -300) && (self.flags & FL_ONGROUND)) && (self.health > 0)) { if (self.watertype == -3) { FO_Sound(self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM); @@ -2851,6 +2855,7 @@ void () PlayerPostThink = { //TeamFortress_SetSpeed(self); } else { CheckPowerups(); + ButtonFrame(); W_WeaponFrame(); if (self.motd <= 400) { TeamFortress_MOTD(); @@ -3705,7 +3710,6 @@ void () InitReverseCap = { } - // this is to fix hack used to avoid fall damage, it currently breaks pm_airstep /* void() SV_RunClientCommand = { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 4630e718..f81e94c8 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -337,6 +337,18 @@ entity () FO_FindCurrentBuildingObject = { return world; } +void () FO_Engineer_ToggleDisp = { + if (self.has_dispenser) { + DestroyBuilding(self, "building_dispenser"); + } else { + if (self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't build while dead.\n"); + } else { + Menu_Engineer_Input(2); + } + } +} + void () TeamFortress_EngineerBuild = { if (self.is_building == 0) { if (((self.ammo_cells < 100) && !self.has_dispenser) && diff --git a/ssqc/menu.qc b/ssqc/menu.qc index ebae3204..b098ccef 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -5,6 +5,9 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin; void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor; void (float issilent) CF_Spy_FeignDeath; +void (float issilent) FO_Spy_Feign; +void () FO_Spy_Unfeign; +void (float issilent) CF_Spy_FeignDeath; void () CF_Spy_Invisible; void () CF_Spy_DisguiseStop; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 5f9d0477..c38cbb35 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -854,10 +854,6 @@ void () UseAirBlast = { ent = ent.chain; } } - else - { - sprint(self, PRINT_HIGH, "Airblast is on cooldown\n"); - } }; void () UseAirBlastV2 = { @@ -973,8 +969,4 @@ void () UseAirBlastV2 = { } } - else - { - sprint(self, PRINT_HIGH, "Airblast is on cooldown\n"); - } }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a9e89e93..4144e0de 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -18,6 +18,8 @@ typedef void (float n) f_void_float; .float tp_grenades_1; // 1st type of grenades being carried .float tp_grenades_2; // 2nd type of grenades being carried .float tp_grenade_switch; // Set to 1 if +gren1 and +gren2 switch places +.float button3; // special +.float button4; // special2 .float hook_out; // Dummy field for hook to silence error messages .float got_aliases; // TRUE if the player has TeamFortress aliases @@ -422,7 +424,6 @@ float already_chosen_map; // anti spam .float antispam_detpack; // don't spam detpack messages -.float antispam_feign; // don't spam feign deaths .float antispam_assault_cannon; // don't spam assault cannon messages .float antispam_cannon_air; // don't spam assault cannon air messages .float antispam_incendiary_cannon; // don't spam incendiary cannon messages diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 63bbdc5e..1ff7eb61 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -434,170 +434,177 @@ void () CF_Spy_AirThink = { self.nextthink = time + 0.1; }; -void (float issilent) CF_Spy_FeignDeath = { - local string deathstring; - local float area_check; - local float i; - local entity te, spy; +void (float issilent) FO_Spy_Feign = { + if (self.is_feigning == 1) { + return; + } - if (self.is_feigning) { + // don't allow feign if spy is in air and air feigning is disallowed + if (!feign_air && !(self.flags & FL_ONGROUND)) { + sprint(self, PRINT_HIGH, "You cannot feign while you are airborne\n"); + return; + } - // check area for obstructing entities - area_check = Spy_CheckArea(self); + // check area for feigned spy on the ground + local float area_check; + area_check = Spy_CheckArea(self); + if (area_check == 3) { + sprint(self, PRINT_HIGH, "You cannot feign on top of another spy\n"); + return; + } - // nothing on top => unfeign - if (!area_check) { + // don't check for team color cheat for 5 seconds + self.immune_to_check = time + 5; - // set size of player model - setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); + // set movetype to toss + self.movetype = MOVETYPE_TOSS; - // set view height - self.view_ofs = '0 0 22'; + // this timer will make sure the spy falls + // to the ground when possible + local entity spy; + spy = spawn(); + spy.classname = "airtimer"; + spy.owner = self; + spy.think = CF_Spy_AirThink; + spy.nextthink = time + 0.1; - // unset feign variables - self.is_feigning = 0; - self.feign_areachecked = 0; + // set spy feign variables + self.is_feigning = 1; - // load saved weapon state and set current ammo - W_WeaponState_Load(self, 0); - W_SetCurrentAmmo(self); + Attack_Finished(0.8); + self.invisible_finished = 0; - // allow spy to move again - self.movetype = MOVETYPE_WALK; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); + // set precached model index + self.modelindex = modelindex_player; - // set revive animation - i = 1 + floor(random() * 5); - if (i == 1) { - spy_upb1(); - } else if (i == 2) { - spy_upc1(); - } else if (i == 3) { - spy_upd1(); - } else { - spy_upe1(); - } + // set size of player model + setsize(self, '-16 -16 -24', '16 16 -16'); - // something is on top of spy - } else if (area_check == 1) { - sprint(self, PRINT_HIGH, "You cannot get up with something on top of you\n"); - } else if (area_check == 2) { - sprint(self, PRINT_HIGH, "You cannot get up while someone is standing on you\n"); - } - } else { + // set weapon state and remove weapon viewmodel + W_WeaponState_Save(self); + self.weaponmodel = ""; + self.weaponframe = 0; - // don't feign spam timer is active - if (time < self.antispam_feign) { - sprint(self, PRINT_HIGH, "You cannot feign right now\n"); - return; - } + // set view height to ground + self.view_ofs = '0 0 4'; - // don't allow feign if spy is in air and air feigning is disallowed - if (!feign_air && !(self.flags & FL_ONGROUND)) { - sprint(self, PRINT_HIGH, "You cannot feign while you are airborne\n"); - return; - } + // do extra stuff if feign is not silent feign + if (issilent == 0) { + // make a death sound + DeathSound(); + + // drop an empty backpack (if this is not disabled in settings) + if (feign_pack) + Spy_DropBackpack(); - // check area for feigned spy on the ground - area_check = Spy_CheckArea(self); - if (area_check == 3) { - sprint(self, PRINT_HIGH, "You cannot feign on top of another spy\n"); - return; + // print feign message (if this is not disabled in settings) + if (feign_msg) { + local string deathstring; + deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); + bprint(PRINT_MEDIUM, deathstring); + KillSound(self, self.attacked_by); } - // stop spy from attempting feign for 3 seconds - self.antispam_feign = time + 3; + // set movement speed to 0 if currently in the air to disable manipulation of trajectory + if (!(self.flags & FL_ONGROUND)) + self.maxspeed = 0; + } - // don't check for team color cheat for 5 seconds - self.immune_to_check = time + 5; + // drop flag if spy is carrying it + local entity te; + te = find(world, classname, "item_tfgoal"); + while (te) { + if (te.owner == self) { + if (!(te.goal_activation & TFGI_KEEP) || self.has_disconnected == 1) + tfgoalitem_RemoveFromPlayer(te, self, 0); + if (CTF_Map == 1) { + if (te.goal_no == 1) + bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sblue\s flag!\n"); + else if (te.goal_no == 2) + bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sred\s flag!\n"); + } + } + te = find(te, classname, "item_tfgoal"); + } - // set movetype to toss - self.movetype = MOVETYPE_TOSS; + // die with axe equipped if carrying axe, medikit, knife or spanner + if (self.weapon <= WEAP_AXE) { + spy_die_ax1(); + return; + } - // this timer will make sure the spy falls - // to the ground when possible - spy = spawn(); - spy.classname = "airtimer"; - spy.owner = self; - spy.think = CF_Spy_AirThink; - spy.nextthink = time + 0.1; + // randomize death animation + local float i; + i = 1 + floor((random() * 6)); + if (i == 1) + spy_diea1(); + else if (i == 2) + spy_dieb1(); + else if (i == 3) + spy_diec1(); + else if (i == 4) + spy_died1(); + else + spy_diee1(); +} - // set spy feign variables - self.is_feigning = 1; +void () FO_Spy_Unfeign = { + if (self.is_feigning == 0) { + return; + } - Attack_Finished(0.8); - self.invisible_finished = 0; + // check area for obstructing entities + local float area_check; + area_check = Spy_CheckArea(self); - // set precached model index - self.modelindex = modelindex_player; + // nothing on top => unfeign + if (!area_check) { // set size of player model - setsize(self, '-16 -16 -24', '16 16 -16'); - - // set weapon state and remove weapon viewmodel - W_WeaponState_Save(self); - self.weaponmodel = ""; - self.weaponframe = 0; - - // set view height to ground - self.view_ofs = '0 0 4'; - - // do extra stuff if feign is not silent feign - if (issilent == 0) { - // make a death sound - DeathSound(); - - // drop an empty backpack (if this is not disabled in settings) - if (feign_pack) - Spy_DropBackpack(); - - // print feign message (if this is not disabled in settings) - if (feign_msg) { - deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); - bprint(PRINT_MEDIUM, deathstring); - KillSound(self, self.attacked_by); - } - - // set movement speed to 0 if currently in the air to disable manipulation of trajectory - if (!(self.flags & FL_ONGROUND)) - self.maxspeed = 0; - } - - // drop flag if spy is carrying it - te = find(world, classname, "item_tfgoal"); - while (te) { - if (te.owner == self) { - if (!(te.goal_activation & TFGI_KEEP) || self.has_disconnected == 1) - tfgoalitem_RemoveFromPlayer(te, self, 0); - if (CTF_Map == 1) { - if (te.goal_no == 1) - bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sblue\s flag!\n"); - else if (te.goal_no == 2) - bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sred\s flag!\n"); - } - } - te = find(te, classname, "item_tfgoal"); + setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); + + // set view height + self.view_ofs = '0 0 22'; + + // unset feign variables + self.is_feigning = 0; + self.feign_areachecked = 0; + + // load saved weapon state and set current ammo + W_WeaponState_Load(self, 0); + W_SetCurrentAmmo(self); + + // allow spy to move again + self.movetype = MOVETYPE_WALK; + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + TeamFortress_SetSpeed(self); + + // set revive animation + local float i; + i = 1 + floor(random() * 5); + if (i == 1) { + spy_upb1(); + } else if (i == 2) { + spy_upc1(); + } else if (i == 3) { + spy_upd1(); + } else { + spy_upe1(); } - // die with axe equipped if carrying axe, medikit, knife or spanner - if (self.weapon <= WEAP_AXE) { - spy_die_ax1(); - return; - } + // something is on top of spy + } else if (area_check == 1) { + sprint(self, PRINT_HIGH, "You cannot get up with something on top of you\n"); + } else if (area_check == 2) { + sprint(self, PRINT_HIGH, "You cannot get up while someone is standing on you\n"); + } +} - // randomize death animation - i = 1 + floor((random() * 6)); - if (i == 1) - spy_diea1(); - else if (i == 2) - spy_dieb1(); - else if (i == 3) - spy_diec1(); - else if (i == 4) - spy_died1(); - else - spy_diee1(); +void (float issilent) CF_Spy_FeignDeath = { + if (self.is_feigning) { + FO_Spy_Unfeign(); + } else { + FO_Spy_Feign(issilent); } }; @@ -943,7 +950,7 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { if (!pe_player.undercover_team) sprint(pe_player, PRINT_HIGH, "Going undercover...\n"); else if(pe_player.undercover_skin != pf_class) - sprint(pe_player, PRINT_HIGH, "Changing costumes...\n"); + sprint(pe_player, PRINT_HIGH, "Changing costumes...\n"); pe_player.is_undercover = 2; pe_player.disguise_skin = pf_class; @@ -1024,7 +1031,7 @@ void (entity spy) TeamFortress_SpyCalcName = { te = find(world, classname, "player"); while (te) { if ((te.team_no == spy.undercover_team) && - (te.skin == spy.undercover_skin)) { + (te.skin == spy.undercover_skin)) { spy.undercover_name = te.netname; te = world; } else { @@ -1100,7 +1107,7 @@ void () GasGrenadeMakeGas = { te = find(world, classname, "gastimer"); while (te) { if ((te.owner == self.owner) && - (te.no_active_gas_grens == 1)) { + (te.no_active_gas_grens == 1)) { te.weapon = 24; te.think = RemoveGrenade; te.nextthink = time + 0.1; @@ -1115,14 +1122,14 @@ void () GasGrenadeMakeGas = { while (te != world) { if (CanDamage(te, self)) { if (((te.classname == "player") && (te.deadflag == 0)) && - (te.has_disconnected != 1)) { + (te.has_disconnected != 1)) { deathmsg = 24; TF_T_Damage(te, world, self.owner, 10, (1 | 2), 0); if (te.tfstate & TFSTATE_HALLUCINATING) { timer = find(world, classname, "timer"); while (((timer.owner != te) || - (timer.think != HallucinationTimer)) && - (timer != world)) { + (timer.think != HallucinationTimer)) && + (timer != world)) { timer = find(timer, classname, "timer"); } if (timer != world) { @@ -1146,7 +1153,7 @@ void () GasGrenadeMakeGas = { sprint(te, PRINT_HIGH, "Far out man!\n"); } else { sprint(te, PRINT_HIGH, - "Run for cover! They are everywhere!\n"); + "Run for cover! They are everywhere!\n"); } te.tfstate = te.tfstate | TFSTATE_HALLUCINATING; timer = spawn(); @@ -1206,7 +1213,7 @@ void () HallucinationTimer = { self.health = self.health - 2.5; } if (((self.health <= 0) || (self.owner.deadflag != 0)) || - (self.owner.has_disconnected == 1)) { + (self.owner.has_disconnected == 1)) { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_HALLUCINATING); } @@ -1293,7 +1300,7 @@ void () HallucinationTimer = { stuffcmd(self.owner, "play weapons/tink1.wav\n"); } else if (halltype2 < 0.55) { CenterPrint2(self.owner, "\n\n\n", - Q"Your team \scaptured\s the flag!!"); + Q"Your team \scaptured\s the flag!!"); stuffcmd(self.owner, "play weapons/grenade.wav\n"); } else if (halltype2 < 0.6) { stuffcmd(self.owner, "play weapons/bounce.wav\n"); @@ -1345,7 +1352,7 @@ void () HallucinationTimer = { stuffcmd(self.owner, "play weapons/sniper.wav\n"); } else if (halltype2 < 0.6) { CenterPrint2(self.owner, "\n\n\n", - Q"Your flag has been \staken\s!!"); + Q"Your flag has been \staken\s!!"); stuffcmd(self.owner, "play weapons/flmfire2.wav\n"); } else if (halltype2 < 0.7) { stuffcmd(self.owner, "play weapons/flmgrexp.wav\n"); @@ -1397,16 +1404,16 @@ void () T_TranqDartTouch = { } if (other.takedamage) { if ((other.classname == "player") && - !((other.team_no == self.owner.team_no) && - (teamplay & (2 | 4)))) { + !((other.team_no == self.owner.team_no) && + (teamplay & (2 | 4)))) { LogEventAffliction(self.owner, other, TFSTATE_TRANQUILISED); if (other.tfstate & TFSTATE_TRANQUILISED) { timer = find(world, classname, "timer"); while (((timer.owner != other) || - (timer.think != TranquiliserTimer)) && - (timer != world)) { + (timer.think != TranquiliserTimer)) && + (timer != world)) { timer = find(timer, classname, "timer"); } if (timer != world) { @@ -1534,11 +1541,11 @@ void () Spy_DropBackpack = { newmis.flags = FL_ITEM; newmis.solid = SOLID_TRIGGER; newmis.movetype = MOVETYPE_TOSS; - - if(splitbackpackmodels) - FO_SetModel(newmis, "progs/deathbag.mdl"); - else - FO_SetModel(newmis, "progs/backpack.mdl"); + + if(splitbackpackmodels) + FO_SetModel(newmis, "progs/deathbag.mdl"); + else + FO_SetModel(newmis, "progs/backpack.mdl"); setsize(newmis, '-16 -16 0', '16 16 56'); newmis.touch = BackpackTouch; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 18ac2199..5c971935 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -251,7 +251,7 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); TeamFortress_Alias("togglesentry", TF_ENGINEER_TOGGLESENTRY, 0); - TeamFortress_Alias("toggledispenser", TF_ENGINEER_TOGGLEDISP, 0); + TeamFortress_Alias("toggledisp", TF_ENGINEER_TOGGLEDISP, 0); } else if (self.motd == 130) { stuffcmd(self, "is_aliased\n"); TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index da602185..fcd447bb 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -64,6 +64,7 @@ void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; void () TeamFortress_Discard_DropAmmo; +void () FO_Engineer_ToggleDisp; float (float force) TeamFortress_DetonatePipebombs; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; @@ -128,6 +129,13 @@ void (float inp) W_OldWeaponSlot; void (entity ent, float num) SetFlameCount; +float button3_keydown; +float button3_keydown_frame; +float button3_keyup_frame; +float button4_keydown; +float button4_keydown_frame; +float button4_keyup_frame; + void () W_Precache = { precache_sound("weapons/r_exp3.wav"); precache_sound("weapons/rocket1i.wav"); @@ -3081,15 +3089,7 @@ void () ImpulseCommands = { } } } else if ((self.impulse == TF_ENGINEER_TOGGLEDISP) && (self.playerclass == PC_ENGINEER)) { - if (self.has_dispenser) { - DestroyBuilding(self, "building_dispenser"); - } else { - if (self.health <= 0) { - sprint(self, PRINT_HIGH, "Can't build while dead.\n"); - } else { - Menu_Engineer_Input(2); - } - } + FO_Engineer_ToggleDisp(); } else if ((self.impulse == 196) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_teleporter_exit"); @@ -3352,6 +3352,155 @@ void () DeadImpulses = { } }; +void () ButtonFrame = { + if (self.button3) { // +special + if (!button3_keydown) { + button3_keydown = 1; + button3_keydown_frame = 1; + } + + switch (self.playerclass) { + case PC_SCOUT: + CF_Scout_Dash(); + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + TeamFortress_DetonatePipebombs(1); + break; + case PC_MEDIC: + if (button3_keydown_frame) { + CF_Medic_AuraToggle(); + } + break; + case PC_HVYWEAP: + if (button3_keydown_frame) { + FO_LockToggle(); + } + break; + case PC_PYRO: + FO_Airblast(); + break; + case PC_SPY: + FO_Spy_Feign(0); + break; + case PC_ENGINEER: + if (button3_keydown_frame) { + FO_Engineer_ToggleDisp(); + } + break; + case PC_UNDEFINED: + break; + } + + button3_keydown_frame = 0; + } else { // -special + if (button3_keydown) { + button3_keydown = 0; + button3_keyup_frame = 1; + } + + switch (self.playerclass) { + case PC_SCOUT: + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + break; + case PC_SPY: + FO_Spy_Unfeign(); + break; + case PC_ENGINEER: + break; + case PC_UNDEFINED: + break; + } + + button3_keyup_frame = 0; + } + + if (self.button4) { // +special2 + if (!button4_keydown) { + button4_keydown = 1; + button4_keydown_frame = 1; + } + + switch (self.playerclass) { + case PC_SCOUT: + if (button3_keydown_frame) { + ScannerSwitch(); + } + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + /* self.current_weapon = WEAP_ROCKET_LAUNCHER; */ + /* self.button0 = 1; */ + /* self.button2 = 1; */ + break; + case PC_DEMOMAN: + localcmd("+det5\n"); + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + localcmd("+rj\n"); + break; + case PC_SPY: + localcmd("dlastspawn\n"); + break; + case PC_ENGINEER: + localcmd("togglesentry\n"); + break; + case PC_UNDEFINED: + break; + } + + button4_keydown_frame = 0; + } else { // -special2 + if (button4_keydown) { + button4_keydown = 0; + button4_keyup_frame = 1; + } + + switch (self.playerclass) { + case PC_SCOUT: + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + break; + case PC_SPY: + break; + case PC_ENGINEER: + break; + case PC_UNDEFINED: + break; + } + + button4_keyup_frame = 0; + } +} void () W_WeaponFrame = { diff --git a/ssqc/world.qc b/ssqc/world.qc index e07013a6..8753ef6a 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -461,4 +461,4 @@ void () CheckTrackedSettings = { s.value = new_val; } } -} \ No newline at end of file +} From b9e951082fdd0c037cd659bb08e66d7f0ffc5143 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 25 Jun 2022 14:06:35 +1000 Subject: [PATCH 1508/2474] Fix demoman special buttons --- ssqc/weapons.qc | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fcd447bb..520d10b5 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3353,7 +3353,8 @@ void () DeadImpulses = { }; void () ButtonFrame = { - if (self.button3) { // +special + // +special + if (self.button3) { if (!button3_keydown) { button3_keydown = 1; button3_keydown_frame = 1; @@ -3368,7 +3369,7 @@ void () ButtonFrame = { case PC_SOLDIER: break; case PC_DEMOMAN: - TeamFortress_DetonatePipebombs(1); + TeamFortress_DetonatePipebombs(0); break; case PC_MEDIC: if (button3_keydown_frame) { @@ -3396,7 +3397,7 @@ void () ButtonFrame = { } button3_keydown_frame = 0; - } else { // -special + } else { if (button3_keydown) { button3_keydown = 0; button3_keyup_frame = 1; @@ -3429,7 +3430,8 @@ void () ButtonFrame = { button3_keyup_frame = 0; } - if (self.button4) { // +special2 + // +special2 + if (self.button4) { if (!button4_keydown) { button4_keydown = 1; button4_keydown_frame = 1; @@ -3437,26 +3439,26 @@ void () ButtonFrame = { switch (self.playerclass) { case PC_SCOUT: - if (button3_keydown_frame) { + if (button4_keydown_frame) { ScannerSwitch(); } break; case PC_SNIPER: break; case PC_SOLDIER: - /* self.current_weapon = WEAP_ROCKET_LAUNCHER; */ - /* self.button0 = 1; */ - /* self.button2 = 1; */ + // Intercepted by InterceptRocketJump() break; case PC_DEMOMAN: - localcmd("+det5\n"); + if (button4_keydown_frame) { + TeamFortress_SetDetpack(5); + } break; case PC_MEDIC: break; case PC_HVYWEAP: break; case PC_PYRO: - localcmd("+rj\n"); + // Intercepted by InterceptRocketJump() break; case PC_SPY: localcmd("dlastspawn\n"); @@ -3483,6 +3485,9 @@ void () ButtonFrame = { case PC_SOLDIER: break; case PC_DEMOMAN: + if (button4_keyup_frame) { + TeamFortress_DetpackStop(); + } break; case PC_MEDIC: break; From eb9078da6056e856dc2426ef82dc125ce915d7db Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 25 Jun 2022 22:09:51 +1000 Subject: [PATCH 1509/2474] Add toggle dispenser / toggle sentry to +special(2) --- README.md | 4 +- share/defs.h | 510 +++++++++++++++++++++++------------------------ ssqc/engineer.qc | 14 +- ssqc/tfort.qc | 2 +- ssqc/tforthlp.qc | 2 +- ssqc/weapons.qc | 86 ++++---- 6 files changed, 313 insertions(+), 305 deletions(-) diff --git a/README.md b/README.md index cf067ab5..848935e3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ New features * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. -* `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledisp` +* `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledispenser` * `+special2` Scout: `autoscan`, Soldier: `+rj`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: `togglesentry` * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` @@ -218,7 +218,7 @@ Engineer * Stop building by pressing last weapon key. * Added message when Dispenser is destroyed. * Added dismantle message to show how many cells were returned to Engineer. -* New command toggledisp (or special) to build or detonate dispenser. +* New command toggledispenser (or special) to build or detonate dispenser. * New command togglesentry (or +special2) to build or detonate sentry. * Engineers can now only dismantle own buildings and rotate own Sentry Gun. diff --git a/share/defs.h b/share/defs.h index fab50ee8..bfa02835 100644 --- a/share/defs.h +++ b/share/defs.h @@ -367,261 +367,261 @@ /*======================================================*/ /* Impulse Defines */ /*======================================================*/ -#define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) -#define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) -#define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) -#define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) -#define TF_CLASSMENU 5 // Brings up class menu -// unused 6 -// unused 7 -// unused 8 -// unused 9 -// unused 10 -#define TF_WEAPNEXT 11 // Selects the next weapon slot -#define TF_WEAPPREV 12 // Selects the previous weapon slot -#define TF_WEAPLAST 13 // Selects the last used weapon slot -#define TF_GRENADE_1 14 // Prime grenade type 1 -#define TF_GRENADE_2 15 // Prime grenade type 2 -#define TF_GRENADE_T 16 // Throw primed grenade -#define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) -#define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) -#define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 -#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon -#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon -#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon -#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon -#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped -#define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 -#define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 -#define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 -#define TF_RELOAD 28 // Reload current weapon -#define TF_RELOAD_NEXT 29 // Reload next weapon with a non-full clip -#define TF_SPECIAL_SKILL 30 // Class special -#define TF_DROPFLAG 31 // Drop flag -#define TF_DROPKEY 32 // Drop key -#define TF_DISCARD 33 // Discard useless ammo -#define TF_DROP_AMMO 34 // Drop an ammo box on the ground -#define TF_MEDIC_HELPME 35 // Alert players around you that you are in need of medical attention -#define TF_INVENTORY 36 // Displays current inventory -#define FLAG_INFO 37 // Displays current flag location -#define TF_ID 38 // Identify player/object in front of player -#define TF_ID_TEAM 39 // Identify team player/object in front of player -#define TF_ID_ENEMY 40 // Identify enemy player/object in front of player -#define TF_DASH 41 // Scout: Initialize a forward bunnyhop -#define TF_SCAN 42 // Scout: Toggle Scanner on/off -#define TF_SCAN_ENEMY 43 // Scout: Toggle scanning of enemies -#define TF_SCAN_FRIENDLY 44 // Scout: Toggle scanning of friendlies -#define TF_SCAN_SOUND 45 // Scout: Toggle scanner sound -#define TF_ZOOMTOGGLE 46 // Sniper: Toggle zoom mode on/off -#define TF_ZOOMIN 47 // Sniper: Zoom in (while zoom mode is on) -#define TF_ZOOMOUT 48 // Sniper: Zoom out (while zoom mode is on) -#define TF_DEMOMAN_DETPACK 49 // Demoman: Bring up detpack menu -#define TF_DETPACK 50 // Demoman: Detpack Pre-Impulse -#define TF_DETPACK_STOP 51 // Demoman: Impulse to stop setting detpack -#define TF_DETPACK_5 52 // Demoman: Detpack set to 5 seconds -#define TF_DETPACK_20 53 // Demoman: Detpack set to 20 seconds -#define TF_DETPACK_50 54 // Demoman: Detpack set to 50 seconds -#define TF_PB_DETONATE 55 // Demoman: Detonate Pipebombs -#define TF_MEDIC_AURA_TOGGLE 56 // Medic: Toggle Healing Aura on/off -#define TF_HVYWEAP_LOCK_TOGGLE 57 // Medic: Toggle Healing Aura on/off -#define TF_LOCKON 58 // HWGuy: Turn Assault Cannon fire on -#define TF_LOCKOFF 59 // HWGuy: Turn Assault Cannon fire off -#define TF_AIRBLAST 60 // Pyro: Air blast -#define TF_SPY_DIE 61 // Spy: Feign death -#define TF_SPY_DIE_ON 62 // Spy: Feign death next damage -#define TF_SPY_DIE_OFF 63 // Spy: Unfeign -#define TF_SPY_SILENT_DIE 64 // Spy: Silent feign death -#define TF_SPY_SPY 65 // Spy: Bring up disguise menu -#define TF_DISGUISE_ENEMY 66 // Spy: Disguise as enemy team -#define TF_DISGUISE_LAST 67 // Spy: Use last disguise -#define TF_DISGUISE_RESET 68 // Spy: Reset disguise -#define TF_DISGUISE_SCOUT 69 // Spy: Disguise as Scout -#define TF_DISGUISE_SNIPER 70 // Spy: Disguise as Sniper -#define TF_DISGUISE_SOLDIER 71 // Spy: Disguise as Soldier -#define TF_DISGUISE_DEMOMAN 72 // Spy: Disguise as Demoman -#define TF_DISGUISE_MEDIC 73 // Spy: Disguise as Medic -#define TF_DISGUISE_HWGUY 74 // Spy: Disguise as HWGuy -#define TF_DISGUISE_PYRO 75 // Spy: Disguise as Pyro -#define TF_DISGUISE_ENGINEER 76 // Spy: Disguise as Engineer -#define TF_DISGUISE_BLUE 77 // Spy: Disguise as blue team -#define TF_DISGUISE_RED 78 // Spy: Disguise as red team -#define TF_DISGUISE_YELLOW 79 // Spy: Disguise as yellow team -#define TF_DISGUISE_GREEN 80 // Spy: Disguise as green team -#define TF_ENGINEER_BUILD 81 // Engineer: Bring up build menu for Engineer -#define TF_ENGINEER_DETDISP 82 // Engineer: Detonate dispenser for Engineer -#define TF_ENGINEER_DETSENTRY 83 // Engineer: Detonate sentry gun for Engineer -#define TF_DISCARD_DROP_AMMO 84 -#define TF_PRACSPAWN_PLACE 85 -#define TF_PRACSPAWN_REMOVE 86 -#define TF_DISGUISE_LAST_SPAWNED 87 // Spy: Disguise as last enemy to spawn -#define TF_SPECIAL_SKILL_2 88 // Class special 2 -#define TF_ENGINEER_TOGGLESENTRY 89 // Engineer: Build or detonate sentry -#define TF_ENGINEER_TOGGLEDISP 90 // Engineer: Build or detonate dispenser -// unused 91 -// unused 92 -// unused 93 -// unused 94 -// unused 95 -// unused 96 -// unused 97 -// unused 98 -// unused 99 -// unused 100 -#define TF_CHANGETEAM 101 // Bring up team selection menu -#define TF_TEAM_1 102 // Join team 1 -#define TF_TEAM_2 103 // Join team 2 -#define TF_TEAM_3 104 // Join team 3 -#define TF_TEAM_4 105 // Join team 4 -#define TF_DISPLAYLOCATION 106 // Displays current location and angles (for developers) -#define TF_SHOWTF 107 // Displays server settings and mod version -#define TF_SHOWLEGALCLASSES 108 // Show what classes are allowed by current map -#define TF_SHOW_IDS 109 // Show ids of connected players -#define TF_ALIAS_CHECK 110 // Check if client has gotten all the aliases -#define TF_CHANGECLASS 111 // Bring up class selection menu -#define TF_CHANGEPC_SCOUT 112 // Change class to Scout -#define TF_CHANGEPC_SNIPER 113 // Change class to Sniper -#define TF_CHANGEPC_SOLDIER 114 // Change class to Soldier -#define TF_CHANGEPC_DEMOMAN 115 // Change class to Demoman -#define TF_CHANGEPC_MEDIC 116 // Change class to Medic -#define TF_CHANGEPC_HVYWEAP 117 // Change class to HWGuy -#define TF_CHANGEPC_PYRO 118 // Change class to Pyro -#define TF_CHANGEPC_SPY 119 // Change class to Spy -#define TF_CHANGEPC_ENGINEER 120 // Change class to Engineer -#define TF_CHANGEPC_RANDOM 121 // Change class to RandomPC -#define TF_HELP_MAP 122 // Displays current map objectives -#define TF_CLASSHELP 123 // Class help alias -#define TF_TEAM_CLASSES 124 // Display team classes -#define TF_TEAM_LIST 125 // Display the players in each team -#define TF_TEAM_SCORES 126 // Display team scores -#define TF_STATUS_QUERY 127 // Displays current team balance and equilization ratios -#define TF_NEXTTIP 128 // Shows the next general/class tip -// unused 129 -// unused 130 -#define TF_TOGGLEVOTE 131 // Toggle vote menu on/off -#define TF_VOTENEXT 132 // Vote to start voting for next map -#define TF_VOTETRICK 133 // Vote to start voting for a trick map -#define TF_VOTERACE 134 // Vote to start voting for a race map -#define TF_FORCENEXT 135 // Vote to force a change to voted map -#define TF_PLAYER_READY 136 -#define TF_PLAYER_NOT_READY 137 -#define TF_ADMIN_FORCESTARTMATCH 138 -#define TF_ADMIN_READYSTATUS 139 -// unused 140 -#define TF_NAILGREN_INFO 141 -// unused 142 -// unused 143 -// unused 144 -// unused 145 -// unused 146 -// unused 147 -// unused 148 -// unused 149 -// unused 150 -// unused 151 -// unused 152 -// unused 153 -// unused 154 -// unused 155 -// unused 156 -// unused 157 -// unused 158 -// unused 159 -// unused 160 -// unused 161 -// unused 162 -// unused 163 -// unused 164 -// unused 165 -// unused 166 -// unused 167 -// unused 168 -// unused 169 -// unused 170 -// unused 171 -// unused 172 -// unused 173 -// unused 174 -// unused 175 -// unused 176 -// unused 177 -// unused 178 -// unused 179 -// unused 180 -// unused 181 -// unused 182 -// unused 183 -// unused 184 -// unused 185 -// unused 186 -// unused 187 -// unused 188 -// unused 189 -#define TF_ADMIN_CYCLEDEAL 190 -#define TF_ADMIN_KICK 191 -#define TF_ADMIN_BAN 192 -#define TF_ADMIN_COUNTPLAYERS 193 -#define TF_ADMIN_CEASEFIRE 194 -// unused 195 -#define TF_ADMIN_NEXT 196 -// unused 197 -// unused 198 -#define TF_ADMIN_LISTIPS 199 -// unused 200 -// unused 201 -// unused 202 -// unused 203 -// unused 204 -// unused 205 -// unused 206 -// unused 207 -#define TF_ADMIN_CLANMODE 208 -#define TF_ADMIN_QUADMODE 209 -#define TF_ADMIN_DUELMODE 210 -// unused 211 -// unused 212 -// unused 213 -// unused 214 -// unused 215 -// unused 216 -// unused 217 -// unused 218 -// unused 219 -// unused 220 -// unused 221 -// unused 222 -// unused 223 -// unused 224 -// unused 225 -// unused 226 -// unused 227 -// unused 228 -// unused 229 -// unused 230 -// unused 231 -// unused 232 -// unused 233 -// unused 234 -// unused 235 -// unused 236 -// unused 237 -// unused 238 -// unused 239 -#define TF_ADMIN_ADMINMENU 240 -// unused 241 -// unused 242 -// unused 243 -// unused 244 -// unused 245 -// unused 246 -// unused 247 -// unused 248 -// unused 249 -// unused 250 -// unused 251 -// unused 252 -// unused 253 -// unused 254 -// unused 255 +#define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) +#define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) +#define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) +#define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_CLASSMENU 5 // Brings up class menu +// unused 6 +// unused 7 +// unused 8 +// unused 9 +// unused 10 +#define TF_WEAPNEXT 11 // Selects the next weapon slot +#define TF_WEAPPREV 12 // Selects the previous weapon slot +#define TF_WEAPLAST 13 // Selects the last used weapon slot +#define TF_GRENADE_1 14 // Prime grenade type 1 +#define TF_GRENADE_2 15 // Prime grenade type 2 +#define TF_GRENADE_T 16 // Throw primed grenade +#define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) +#define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) +#define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 +#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon +#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon +#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon +#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon +#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped +#define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 +#define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 +#define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 +#define TF_RELOAD 28 // Reload current weapon +#define TF_RELOAD_NEXT 29 // Reload next weapon with a non-full clip +#define TF_SPECIAL_SKILL 30 // Class special +#define TF_DROPFLAG 31 // Drop flag +#define TF_DROPKEY 32 // Drop key +#define TF_DISCARD 33 // Discard useless ammo +#define TF_DROP_AMMO 34 // Drop an ammo box on the ground +#define TF_MEDIC_HELPME 35 // Alert players around you that you are in need of medical attention +#define TF_INVENTORY 36 // Displays current inventory +#define FLAG_INFO 37 // Displays current flag location +#define TF_ID 38 // Identify player/object in front of player +#define TF_ID_TEAM 39 // Identify team player/object in front of player +#define TF_ID_ENEMY 40 // Identify enemy player/object in front of player +#define TF_DASH 41 // Scout: Initialize a forward bunnyhop +#define TF_SCAN 42 // Scout: Toggle Scanner on/off +#define TF_SCAN_ENEMY 43 // Scout: Toggle scanning of enemies +#define TF_SCAN_FRIENDLY 44 // Scout: Toggle scanning of friendlies +#define TF_SCAN_SOUND 45 // Scout: Toggle scanner sound +#define TF_ZOOMTOGGLE 46 // Sniper: Toggle zoom mode on/off +#define TF_ZOOMIN 47 // Sniper: Zoom in (while zoom mode is on) +#define TF_ZOOMOUT 48 // Sniper: Zoom out (while zoom mode is on) +#define TF_DEMOMAN_DETPACK 49 // Demoman: Bring up detpack menu +#define TF_DETPACK 50 // Demoman: Detpack Pre-Impulse +#define TF_DETPACK_STOP 51 // Demoman: Impulse to stop setting detpack +#define TF_DETPACK_5 52 // Demoman: Detpack set to 5 seconds +#define TF_DETPACK_20 53 // Demoman: Detpack set to 20 seconds +#define TF_DETPACK_50 54 // Demoman: Detpack set to 50 seconds +#define TF_PB_DETONATE 55 // Demoman: Detonate Pipebombs +#define TF_MEDIC_AURA_TOGGLE 56 // Medic: Toggle Healing Aura on/off +#define TF_HVYWEAP_LOCK_TOGGLE 57 // Medic: Toggle Healing Aura on/off +#define TF_LOCKON 58 // HWGuy: Turn Assault Cannon fire on +#define TF_LOCKOFF 59 // HWGuy: Turn Assault Cannon fire off +#define TF_AIRBLAST 60 // Pyro: Air blast +#define TF_SPY_DIE 61 // Spy: Feign death +#define TF_SPY_DIE_ON 62 // Spy: Feign death next damage +#define TF_SPY_DIE_OFF 63 // Spy: Unfeign +#define TF_SPY_SILENT_DIE 64 // Spy: Silent feign death +#define TF_SPY_SPY 65 // Spy: Bring up disguise menu +#define TF_DISGUISE_ENEMY 66 // Spy: Disguise as enemy team +#define TF_DISGUISE_LAST 67 // Spy: Use last disguise +#define TF_DISGUISE_RESET 68 // Spy: Reset disguise +#define TF_DISGUISE_SCOUT 69 // Spy: Disguise as Scout +#define TF_DISGUISE_SNIPER 70 // Spy: Disguise as Sniper +#define TF_DISGUISE_SOLDIER 71 // Spy: Disguise as Soldier +#define TF_DISGUISE_DEMOMAN 72 // Spy: Disguise as Demoman +#define TF_DISGUISE_MEDIC 73 // Spy: Disguise as Medic +#define TF_DISGUISE_HWGUY 74 // Spy: Disguise as HWGuy +#define TF_DISGUISE_PYRO 75 // Spy: Disguise as Pyro +#define TF_DISGUISE_ENGINEER 76 // Spy: Disguise as Engineer +#define TF_DISGUISE_BLUE 77 // Spy: Disguise as blue team +#define TF_DISGUISE_RED 78 // Spy: Disguise as red team +#define TF_DISGUISE_YELLOW 79 // Spy: Disguise as yellow team +#define TF_DISGUISE_GREEN 80 // Spy: Disguise as green team +#define TF_ENGINEER_BUILD 81 // Engineer: Bring up build menu for Engineer +#define TF_ENGINEER_DETDISP 82 // Engineer: Detonate dispenser for Engineer +#define TF_ENGINEER_DETSENTRY 83 // Engineer: Detonate sentry gun for Engineer +#define TF_DISCARD_DROP_AMMO 84 +#define TF_PRACSPAWN_PLACE 85 +#define TF_PRACSPAWN_REMOVE 86 +#define TF_DISGUISE_LAST_SPAWNED 87 // Spy: Disguise as last enemy to spawn +#define TF_SPECIAL_SKILL_2 88 // Class special 2 +#define TF_ENGINEER_TOGGLESENTRY 89 // Engineer: Build or detonate sentry +#define TF_ENGINEER_TOGGLEDISPENSER 90 // Engineer: Build or detonate dispenser +// unused 91 +// unused 92 +// unused 93 +// unused 94 +// unused 95 +// unused 96 +// unused 97 +// unused 98 +// unused 99 +// unused 100 +#define TF_CHANGETEAM 101 // Bring up team selection menu +#define TF_TEAM_1 102 // Join team 1 +#define TF_TEAM_2 103 // Join team 2 +#define TF_TEAM_3 104 // Join team 3 +#define TF_TEAM_4 105 // Join team 4 +#define TF_DISPLAYLOCATION 106 // Displays current location and angles (for developers) +#define TF_SHOWTF 107 // Displays server settings and mod version +#define TF_SHOWLEGALCLASSES 108 // Show what classes are allowed by current map +#define TF_SHOW_IDS 109 // Show ids of connected players +#define TF_ALIAS_CHECK 110 // Check if client has gotten all the aliases +#define TF_CHANGECLASS 111 // Bring up class selection menu +#define TF_CHANGEPC_SCOUT 112 // Change class to Scout +#define TF_CHANGEPC_SNIPER 113 // Change class to Sniper +#define TF_CHANGEPC_SOLDIER 114 // Change class to Soldier +#define TF_CHANGEPC_DEMOMAN 115 // Change class to Demoman +#define TF_CHANGEPC_MEDIC 116 // Change class to Medic +#define TF_CHANGEPC_HVYWEAP 117 // Change class to HWGuy +#define TF_CHANGEPC_PYRO 118 // Change class to Pyro +#define TF_CHANGEPC_SPY 119 // Change class to Spy +#define TF_CHANGEPC_ENGINEER 120 // Change class to Engineer +#define TF_CHANGEPC_RANDOM 121 // Change class to RandomPC +#define TF_HELP_MAP 122 // Displays current map objectives +#define TF_CLASSHELP 123 // Class help alias +#define TF_TEAM_CLASSES 124 // Display team classes +#define TF_TEAM_LIST 125 // Display the players in each team +#define TF_TEAM_SCORES 126 // Display team scores +#define TF_STATUS_QUERY 127 // Displays current team balance and equilization ratios +#define TF_NEXTTIP 128 // Shows the next general/class tip +// unused 129 +// unused 130 +#define TF_TOGGLEVOTE 131 // Toggle vote menu on/off +#define TF_VOTENEXT 132 // Vote to start voting for next map +#define TF_VOTETRICK 133 // Vote to start voting for a trick map +#define TF_VOTERACE 134 // Vote to start voting for a race map +#define TF_FORCENEXT 135 // Vote to force a change to voted map +#define TF_PLAYER_READY 136 +#define TF_PLAYER_NOT_READY 137 +#define TF_ADMIN_FORCESTARTMATCH 138 +#define TF_ADMIN_READYSTATUS 139 +// unused 140 +#define TF_NAILGREN_INFO 141 +// unused 142 +// unused 143 +// unused 144 +// unused 145 +// unused 146 +// unused 147 +// unused 148 +// unused 149 +// unused 150 +// unused 151 +// unused 152 +// unused 153 +// unused 154 +// unused 155 +// unused 156 +// unused 157 +// unused 158 +// unused 159 +// unused 160 +// unused 161 +// unused 162 +// unused 163 +// unused 164 +// unused 165 +// unused 166 +// unused 167 +// unused 168 +// unused 169 +// unused 170 +// unused 171 +// unused 172 +// unused 173 +// unused 174 +// unused 175 +// unused 176 +// unused 177 +// unused 178 +// unused 179 +// unused 180 +// unused 181 +// unused 182 +// unused 183 +// unused 184 +// unused 185 +// unused 186 +// unused 187 +// unused 188 +// unused 189 +#define TF_ADMIN_CYCLEDEAL 190 +#define TF_ADMIN_KICK 191 +#define TF_ADMIN_BAN 192 +#define TF_ADMIN_COUNTPLAYERS 193 +#define TF_ADMIN_CEASEFIRE 194 +// unused 195 +#define TF_ADMIN_NEXT 196 +// unused 197 +// unused 198 +#define TF_ADMIN_LISTIPS 199 +// unused 200 +// unused 201 +// unused 202 +// unused 203 +// unused 204 +// unused 205 +// unused 206 +// unused 207 +#define TF_ADMIN_CLANMODE 208 +#define TF_ADMIN_QUADMODE 209 +#define TF_ADMIN_DUELMODE 210 +// unused 211 +// unused 212 +// unused 213 +// unused 214 +// unused 215 +// unused 216 +// unused 217 +// unused 218 +// unused 219 +// unused 220 +// unused 221 +// unused 222 +// unused 223 +// unused 224 +// unused 225 +// unused 226 +// unused 227 +// unused 228 +// unused 229 +// unused 230 +// unused 231 +// unused 232 +// unused 233 +// unused 234 +// unused 235 +// unused 236 +// unused 237 +// unused 238 +// unused 239 +#define TF_ADMIN_ADMINMENU 240 +// unused 241 +// unused 242 +// unused 243 +// unused 244 +// unused 245 +// unused 246 +// unused 247 +// unused 248 +// unused 249 +// unused 250 +// unused 251 +// unused 252 +// unused 253 +// unused 254 +// unused 255 /*======================================================*/ /* Colors */ diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f81e94c8..88e4f4f9 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -337,7 +337,7 @@ entity () FO_FindCurrentBuildingObject = { return world; } -void () FO_Engineer_ToggleDisp = { +void () FO_Engineer_ToggleDispenser = { if (self.has_dispenser) { DestroyBuilding(self, "building_dispenser"); } else { @@ -349,6 +349,18 @@ void () FO_Engineer_ToggleDisp = { } } +void () FO_Engineer_ToggleSentry = { + if (self.has_sentry) { + DestroyBuilding(self, "building_sentrygun"); + } else { + if (self.health <= 0) { + sprint(self, PRINT_HIGH, "Can't build while dead.\n"); + } else { + Menu_Engineer_Input(1); + } + } +} + void () TeamFortress_EngineerBuild = { if (self.is_building == 0) { if (((self.ammo_cells < 100) && !self.has_dispenser) && diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f1841d7b..2839f45c 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -67,7 +67,7 @@ void () UseSpecialSkill = { self.impulse = TF_SPY_DIE; break; case PC_ENGINEER: - self.impulse = TF_ENGINEER_TOGGLEDISP; + self.impulse = TF_ENGINEER_TOGGLEDISPENSER; break; case PC_UNDEFINED: if (self.enemy == world) { diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 5c971935..55459db6 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -250,8 +250,8 @@ void () TeamFortress_MOTD = { } TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); + TeamFortress_Alias("toggledispenser", TF_ENGINEER_TOGGLEDISPENSER, 0); TeamFortress_Alias("togglesentry", TF_ENGINEER_TOGGLESENTRY, 0); - TeamFortress_Alias("toggledisp", TF_ENGINEER_TOGGLEDISP, 0); } else if (self.motd == 130) { stuffcmd(self, "is_aliased\n"); TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 520d10b5..a20be56a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -64,7 +64,8 @@ void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; void () TeamFortress_Discard_DropAmmo; -void () FO_Engineer_ToggleDisp; +void () FO_Engineer_ToggleDispenser; +void () FO_Engineer_ToggleSentry; float (float force) TeamFortress_DetonatePipebombs; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; @@ -129,12 +130,12 @@ void (float inp) W_OldWeaponSlot; void (entity ent, float num) SetFlameCount; -float button3_keydown; -float button3_keydown_frame; -float button3_keyup_frame; -float button4_keydown; -float button4_keydown_frame; -float button4_keyup_frame; +.float button3_keydown; +.float button3_keydown_frame; +.float button3_keyup_frame; +.float button4_keydown; +.float button4_keydown_frame; +.float button4_keyup_frame; void () W_Precache = { precache_sound("weapons/r_exp3.wav"); @@ -3078,19 +3079,10 @@ void () ImpulseCommands = { else if ((self.impulse == TF_ENGINEER_DETDISP) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_dispenser"); - else if ((self.impulse == TF_ENGINEER_TOGGLESENTRY) && (self.playerclass == PC_ENGINEER)) { - if (self.has_sentry) { - DestroyBuilding(self, "building_sentrygun"); - } else { - if (self.health <= 0) { - sprint(self, PRINT_HIGH, "Can't build while dead.\n"); - } else { - Menu_Engineer_Input(1); - } - } - } else if ((self.impulse == TF_ENGINEER_TOGGLEDISP) && (self.playerclass == PC_ENGINEER)) { - FO_Engineer_ToggleDisp(); - } + else if ((self.impulse == TF_ENGINEER_TOGGLEDISPENSER) && (self.playerclass == PC_ENGINEER)) + FO_Engineer_ToggleDispenser(); + else if ((self.impulse == TF_ENGINEER_TOGGLESENTRY) && (self.playerclass == PC_ENGINEER)) + FO_Engineer_ToggleSentry(); else if ((self.impulse == 196) && (self.playerclass == PC_ENGINEER)) DestroyBuilding(self, "building_teleporter_exit"); else if ((self.impulse == 197) && (self.playerclass == PC_ENGINEER)) @@ -3355,9 +3347,9 @@ void () DeadImpulses = { void () ButtonFrame = { // +special if (self.button3) { - if (!button3_keydown) { - button3_keydown = 1; - button3_keydown_frame = 1; + if (!self.button3_keydown) { + self.button3_keydown = 1; + self.button3_keydown_frame = 1; } switch (self.playerclass) { @@ -3372,12 +3364,12 @@ void () ButtonFrame = { TeamFortress_DetonatePipebombs(0); break; case PC_MEDIC: - if (button3_keydown_frame) { + if (self.button3_keydown_frame) { CF_Medic_AuraToggle(); } break; case PC_HVYWEAP: - if (button3_keydown_frame) { + if (self.button3_keydown_frame) { FO_LockToggle(); } break; @@ -3388,19 +3380,19 @@ void () ButtonFrame = { FO_Spy_Feign(0); break; case PC_ENGINEER: - if (button3_keydown_frame) { - FO_Engineer_ToggleDisp(); + if (self.button3_keydown_frame) { + FO_Engineer_ToggleDispenser(); } break; case PC_UNDEFINED: break; } - button3_keydown_frame = 0; + self.button3_keydown_frame = 0; } else { - if (button3_keydown) { - button3_keydown = 0; - button3_keyup_frame = 1; + if (self.button3_keydown) { + self.button3_keydown = 0; + self.button3_keyup_frame = 1; } switch (self.playerclass) { @@ -3427,19 +3419,19 @@ void () ButtonFrame = { break; } - button3_keyup_frame = 0; + self.button3_keyup_frame = 0; } // +special2 if (self.button4) { - if (!button4_keydown) { - button4_keydown = 1; - button4_keydown_frame = 1; + if (!self.button4_keydown) { + self.button4_keydown = 1; + self.button4_keydown_frame = 1; } switch (self.playerclass) { case PC_SCOUT: - if (button4_keydown_frame) { + if (self.button4_keydown_frame) { ScannerSwitch(); } break; @@ -3449,7 +3441,7 @@ void () ButtonFrame = { // Intercepted by InterceptRocketJump() break; case PC_DEMOMAN: - if (button4_keydown_frame) { + if (self.button4_keydown_frame) { TeamFortress_SetDetpack(5); } break; @@ -3461,20 +3453,24 @@ void () ButtonFrame = { // Intercepted by InterceptRocketJump() break; case PC_SPY: - localcmd("dlastspawn\n"); + if (self.button4_keydown_frame) { + FO_Spy_DisguiseLastSpawned(self); + } break; case PC_ENGINEER: - localcmd("togglesentry\n"); + if (self.button4_keydown_frame) { + FO_Engineer_ToggleSentry(); + } break; case PC_UNDEFINED: break; } - button4_keydown_frame = 0; + self.button4_keydown_frame = 0; } else { // -special2 - if (button4_keydown) { - button4_keydown = 0; - button4_keyup_frame = 1; + if (self.button4_keydown) { + self.button4_keydown = 0; + self.button4_keyup_frame = 1; } switch (self.playerclass) { @@ -3485,7 +3481,7 @@ void () ButtonFrame = { case PC_SOLDIER: break; case PC_DEMOMAN: - if (button4_keyup_frame) { + if (self.button4_keyup_frame) { TeamFortress_DetpackStop(); } break; @@ -3503,7 +3499,7 @@ void () ButtonFrame = { break; } - button4_keyup_frame = 0; + self.button4_keyup_frame = 0; } } From 3102a49417e91d7a2cb1ee9000672fac044adb91 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 25 Jun 2022 22:15:49 +1000 Subject: [PATCH 1510/2474] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 848935e3..6cfc9765 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server New features ------ -* `+rj` Switches to rocket/incendiary weapon, jumps and shoots. Bind jump key to `+aux_jump` to prevent `-jump` from interupting auto-hop. +* `+rj` Switches to rocket/incendiary weapon, jumps and shoots. `+aux_jump` is no longer required. * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. From d3043c5a3abefe0ce37864c0969bfd0cb2e98a75 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 00:10:06 +1000 Subject: [PATCH 1511/2474] is still valid --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6cfc9765..dea6c508 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ New features * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. -* `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledispenser` -* `+special2` Scout: `autoscan`, Soldier: `+rj`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: `togglesentry` +* `special2` Scout: `autoscan`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: `togglesentry` +* New buttons (not impulses): + * `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledispenser`. + * `+special2` Same as `special2`, but also has `+rj` for Soldier and Pyro. * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. From e799c5f37fd20de03c258f65e034c887b79eacbd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 00:17:39 +1000 Subject: [PATCH 1512/2474] Add class specific update docs --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dea6c508..4df2dbad 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ New features * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. * `special2` Scout: `autoscan`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: `togglesentry` * New buttons (not impulses): - * `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledispenser`. - * `+special2` Same as `special2`, but also has `+rj` for Soldier and Pyro. +* `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledispenser`. +* `+special2` Same as `special2`, but also has `+rj` for Soldier and Pyro. * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. @@ -156,6 +156,7 @@ Scout * New Scanner menu where Scanner settings can be changed. * Caltrop Canisters no longer "explode" in your hands. * Remember Scanner status across deaths. +* `+special2` to toggle scanner. Sniper ------ @@ -164,7 +165,7 @@ Sniper Soldier ------ -* New command +rj (or +special2) to rocket jump. +* New command `+rj` (or `+special2`) to rocket jump. Demolitions Man ------ @@ -172,6 +173,7 @@ Demolitions Man * Changed maximum detpipes allowed per team to 6 per demoman instead of 7 total. * Decrease /detpipe cooldown to 0.5 seconds instead of 0.8. * Stop detpacking by pressing last weapon bind. +* `+special2` to set 5 second detpack. Combat Medic ------ @@ -207,6 +209,7 @@ Spy * Spy can now feign death in air. * Spy now drops an empty backpack when feigning death. * A fake death message (but relevant to current situation) is now shown when feigning death. +* `+special2` to disguise as last spawned enemy. Engineer ------ @@ -223,6 +226,8 @@ Engineer * New command toggledispenser (or special) to build or detonate dispenser. * New command togglesentry (or +special2) to build or detonate sentry. * Engineers can now only dismantle own buildings and rotate own Sentry Gun. +* `+special` to build or destroy dispenser. +* `+special2` to build or destroy sentry. Development From 86004db67ef8d75ee87f9e4d6938bf61ecde783b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 00:25:30 +1000 Subject: [PATCH 1513/2474] BUTTON1 not supported --- csqc/csextradefs.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 86da6efb..04d0181c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -57,7 +57,7 @@ vector TEXT_TEAM_COLOUR[] = { #define TEAM_OBSERVER 99 #define BUTTON0 1 -/* #define BUTTON1 ? */ +/* BUTTON1 not supported */ #define BUTTON2 2 #define BUTTON3 4 #define BUTTON4 8 From 247f04a0d0cae9813ca352d69fd01aa1e4c6a13c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 00:28:48 +1000 Subject: [PATCH 1514/2474] Readme fixes --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4df2dbad..e99deb16 100644 --- a/README.md +++ b/README.md @@ -203,9 +203,9 @@ Spy * Change color and skin in one sequence. * Last disguise (reachable through disguise menu or using /dlast alias). * Stop disguising by pressing last weapon bind. -* New aliases for changing team color (/denemy (if 2 teams), /dblue, /dred, /dyellow, /dgreen, /dlastspawn). -* New aliases for changing skin (/dscout, /dsniper, /dsoldier, etc). -* Build your own disguise aliases (e.g. alias bsniper "dblue; wait; dsniper" for blue sniper). +* New aliases for changing team color (`denemy` (if 2 teams), `dblue,` `dred,` `dyellow,` `dgreen,` `dlastspawn`). +* New aliases for changing skin (`dscout`, `dsniper`, `dsoldier`, etc). +* Build your own disguise aliases (e.g. `alias bsniper "dblue; wait; dsniper"` for blue sniper). * Spy can now feign death in air. * Spy now drops an empty backpack when feigning death. * A fake death message (but relevant to current situation) is now shown when feigning death. @@ -223,8 +223,8 @@ Engineer * Stop building by pressing last weapon key. * Added message when Dispenser is destroyed. * Added dismantle message to show how many cells were returned to Engineer. -* New command toggledispenser (or special) to build or detonate dispenser. -* New command togglesentry (or +special2) to build or detonate sentry. +* New command toggledispenser (or `+special`) to build or detonate dispenser. +* New command togglesentry (or `+special2`) to build or detonate sentry. * Engineers can now only dismantle own buildings and rotate own Sentry Gun. * `+special` to build or destroy dispenser. * `+special2` to build or destroy sentry. From e886a4f8759e77f064c99537aa5a79839a70cc1b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 02:33:33 +1000 Subject: [PATCH 1515/2474] Make incendiary cannon the pyro's primary weapon --- csqc/main.qc | 16 ++++------------ ssqc/client.qc | 17 ++++++++--------- ssqc/weapons.qc | 45 +++++++++++++++++++++++---------------------- 3 files changed, 35 insertions(+), 43 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 71160199..eabaca94 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -411,19 +411,11 @@ void InterceptRocketJump() { local float rj_weapon = 32; if (active_weapon != rj_weapon) { - local string rj_weapon_impulse; - - if (player_class == PC_SOLDIER) { - // need to consider old impulses - rj_weapon_impulse = "impulse 1\n"; - } - - if (player_class == PC_PYRO) { - // need to consider old impulses - rj_weapon_impulse = "impulse 2\n"; + if (getplayerkeyfloat(player_localnum, "old_weapon_impulses") || getplayerkeyfloat(player_localnum, "owi")) { + localcmd("impulse 7\n"); + } else { + localcmd("impulse 1\n"); } - - localcmd(rj_weapon_impulse); } else { // press +jump and +attack input_buttons |= BUTTON0 + BUTTON2; diff --git a/ssqc/client.qc b/ssqc/client.qc index 888fcfd0..f8f153af 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1719,16 +1719,15 @@ entity(float team_num) FindTeamSpawnPoint = void (entity e) ValidateUser = { }; -entity () SelectSpawnPoint = -{ - if(allowpracspawns && self != world) - { - local entity spot2; - spot2 = TeamFortress_GetPracticeSpawn(self); +entity () SelectSpawnPoint = { + if (allowpracspawns && self != world) + { + local entity spot2; + spot2 = TeamFortress_GetPracticeSpawn(self); - if(spot2 != world) - return spot2; - } + if(spot2 != world) + return spot2; + } local entity spot; local float attempts; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index a20be56a..1885dc4a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2209,14 +2209,14 @@ float (float weap) W_GetSlot = { if (weap == WEAP_ROCKET_LAUNCHER || weap == WEAP_SUPER_NAILGUN || weap == WEAP_SNIPER_RIFLE - || weap == WEAP_FLAMETHROWER + || weap == WEAP_INCENDIARY || weap == WEAP_TRANQ || weap == WEAP_LASER || weap == WEAP_ASSAULT_CANNON) { return 1; } else if (weap == WEAP_SUPER_SHOTGUN || weap == WEAP_AUTO_RIFLE - || weap == WEAP_INCENDIARY) { + || weap == WEAP_FLAMETHROWER) { return 2; } else if (weap == WEAP_SHOTGUN) { if (self.playerclass == PC_SCOUT) @@ -2274,7 +2274,7 @@ float (float weap) W_OldGetSlot = { float (float inp) W_AmmoSlot = { self.noammo = 0; - if (inp == 1) { + if (inp == TF_SLOT1) { if (self.playerclass == PC_SCOUT && self.ammo_nails < 2) self.noammo = 1; else if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) @@ -2290,13 +2290,13 @@ float (float inp) W_AmmoSlot = { self.noammo = 1; else if (self.ammo_cells < 7) self.noammo = 2; - } else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) + } else if (self.playerclass == PC_PYRO && self.ammo_rockets < 3) self.noammo = 1; - else if (self.playerclass == PC_SPY && self.ammo_shells < 1) + else if (self.playerclass == PC_SPY && self.ammo_shells < 1) self.noammo = 1; else if (self.playerclass == PC_ENGINEER && self.ammo_nails < 1) self.noammo = 1; - } else if (inp == 2) { + } else if (inp == TF_SLOT2) { if (self.playerclass == PC_SCOUT && self.ammo_shells < 1) self.noammo = 1; else if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) @@ -2310,9 +2310,9 @@ float (float inp) W_AmmoSlot = { self.noammo = 1; else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) self.noammo = 1; - else if (self.playerclass == PC_PYRO && self.ammo_rockets < 3) + else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) self.noammo = 1; - } else if (inp == 3) { + } else if (inp == TF_SLOT3) { if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) return 0; @@ -2327,7 +2327,7 @@ float (float inp) W_AmmoSlot = { || self.playerclass == PC_PYRO) && self.ammo_shells < 1) self.noammo = 1; - } else if (inp == 4) + } else if (inp == TF_SLOT4) return 1; if (self.noammo > 0) @@ -2338,10 +2338,10 @@ float (float inp) W_AmmoSlot = { float (float inp) W_OldAmmoSlot = { self.noammo = 0; - if (inp == 1) { + if (inp == TF_SLOT1) { return 1; } - else if (inp == 2) { + else if (inp == TF_SLOT2) { if ((self.playerclass == PC_SCOUT || self.playerclass == PC_SNIPER || self.playerclass == PC_SOLDIER @@ -2356,7 +2356,7 @@ float (float inp) W_OldAmmoSlot = { self.noammo = 1; } - else if (inp == 3) { + else if (inp == TF_SLOT3) { if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) self.noammo = 1; else if ((self.playerclass == PC_SOLDIER @@ -2367,7 +2367,7 @@ float (float inp) W_OldAmmoSlot = { && self.ammo_shells < 2) self.noammo = 1; } - else if (inp == 4) { + else if (inp == TF_SLOT4) { if ((self.playerclass == PC_SCOUT || self.playerclass == PC_SNIPER || self.playerclass == PC_SPY) @@ -2500,7 +2500,7 @@ float () W_WeaponSlot1 = { else if (self.playerclass == PC_HVYWEAP) return WEAP_ASSAULT_CANNON; else if (self.playerclass == PC_PYRO) - return WEAP_FLAMETHROWER; + return WEAP_INCENDIARY; else if (self.playerclass == PC_SPY) return WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) @@ -2522,7 +2522,7 @@ float () W_WeaponSlot2 = { else if (self.playerclass == PC_DEMOMAN) { return WEAP_GRENADE_LAUNCHER; // weaponmode = 1 (pipebomb launcher) } else if (self.playerclass == PC_PYRO) - return WEAP_INCENDIARY; + return WEAP_FLAMETHROWER; return 0; }; @@ -2573,16 +2573,16 @@ void (float slot) W_WeaponSlot = { void (float inp) W_OldWeaponSlot = { self.next_weaponmode = 0; - if (inp == 1) { + if (inp == TF_SLOT1) { self.next_weapon = W_OldWeaponSlot1(); } - else if (inp == 2) { + else if (inp == TF_SLOT2) { self.next_weapon = W_OldWeaponSlot2(); } - else if (inp == 3) { + else if (inp == TF_SLOT3) { self.next_weapon = W_OldWeaponSlot3(); } - else if (inp == 4) { + else if (inp == TF_SLOT4) { self.next_weapon = W_OldWeaponSlot4(); } else if (inp == 5) { @@ -2778,9 +2778,10 @@ float (entity pl) W_WeaponState_Check = { void (float inp) W_ChangeWeapon = { if(self.playerclass == PC_CIVILIAN) { - inp = 4; + inp = TF_SLOT4; } - if (inp < 1 || inp > GetLastWeaponImpulse()) + + if (inp < TF_SLOT1 || inp > GetLastWeaponImpulse()) return; if (self.playerclass == 0) @@ -2796,7 +2797,7 @@ void (float inp) W_ChangeWeapon = { if (IsUsingOldImpulses()) { if(self.playerclass == PC_CIVILIAN) { - inp = 1; + inp = TF_SLOT1; } // check for ammo if (! W_OldAmmoSlot(inp)) { From 289122a429dfecf0bcc48e117a0d1808e196fdf0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 10:45:25 +1000 Subject: [PATCH 1516/2474] Separate feign and +feign logic --- ssqc/qw.qc | 1 + ssqc/spy.qc | 158 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 151 insertions(+), 8 deletions(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4144e0de..3da232cb 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -29,6 +29,7 @@ typedef void (float n) f_void_float; .float is_building; // TRUE for an ENGINEER if they're building something .float is_detpacking; // TRUE for a DEMOMAN if they're setting a detpack .float is_feigning; // TRUE for a SPY if they're feigning death +.float is_button_feigning; // TRUE for a SPY if they're feigning death with +feign or +special .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 1ff7eb61..11a6a1e9 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -391,13 +391,14 @@ void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch = { void () CF_Spy_AirThink = { local float area_check = 0; - if(self.owner.deadflag >= 2) { - // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) - self.owner.movetype = MOVETYPE_NONE; - self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; + if(self.owner.deadflag >= 2) { + // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) + self.owner.movetype = MOVETYPE_NONE; + self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; dremove(self); return; } + if ((self.owner.playerclass != PC_SPY) || (!self.owner.is_feigning)) { dremove(self); return; @@ -435,7 +436,7 @@ void () CF_Spy_AirThink = { }; void (float issilent) FO_Spy_Feign = { - if (self.is_feigning == 1) { + if (self.is_feigning) { return; } @@ -470,6 +471,7 @@ void (float issilent) FO_Spy_Feign = { // set spy feign variables self.is_feigning = 1; + self.is_button_feigning = 1; Attack_Finished(0.8); self.invisible_finished = 0; @@ -549,7 +551,7 @@ void (float issilent) FO_Spy_Feign = { } void () FO_Spy_Unfeign = { - if (self.is_feigning == 0) { + if (!self.is_button_feigning) { return; } @@ -568,6 +570,7 @@ void () FO_Spy_Unfeign = { // unset feign variables self.is_feigning = 0; + self.is_button_feigning = 0; self.feign_areachecked = 0; // load saved weapon state and set current ammo @@ -601,10 +604,149 @@ void () FO_Spy_Unfeign = { } void (float issilent) CF_Spy_FeignDeath = { + local string deathstring; + local float area_check; + local float i; + local entity te, spy; + if (self.is_feigning) { - FO_Spy_Unfeign(); + // check area for obstructing entities + area_check = Spy_CheckArea(self); + + // nothing on top => unfeign + if (!area_check) { + + // set size of player model + setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); + + // set view height + self.view_ofs = '0 0 22'; + + // unset feign variables + self.is_feigning = 0; + self.feign_areachecked = 0; + + // load saved weapon state and set current ammo + W_WeaponState_Load(self, 0); + W_SetCurrentAmmo(self); + + // allow spy to move again + self.movetype = MOVETYPE_WALK; + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + TeamFortress_SetSpeed(self); + + // set revive animation + i = 1 + floor(random() * 5); + if (i == 1) { + spy_upb1(); + } else if (i == 2) { + spy_upc1(); + } else if (i == 3) { + spy_upd1(); + } else { + spy_upe1(); + } + + // something is on top of spy + } else if (area_check == 1) { + sprint(self, PRINT_HIGH, "You cannot get up with something on top of you\n"); + } else if (area_check == 2) { + sprint(self, PRINT_HIGH, "You cannot get up while someone is standing on you\n"); + } } else { - FO_Spy_Feign(issilent); + + // don't allow feign if spy is in air and air feigning is disallowed + if (!feign_air && !(self.flags & FL_ONGROUND)) { + sprint(self, PRINT_HIGH, "You cannot feign while you are airborne\n"); + return; + } + + // check area for feigned spy on the ground + area_check = Spy_CheckArea(self); + if (area_check == 3) { + sprint(self, PRINT_HIGH, "You cannot feign on top of another spy\n"); + return; + } + + // don't check for team color cheat for 5 seconds + self.immune_to_check = time + 5; + + // set movetype to toss + self.movetype = MOVETYPE_TOSS; + + // this timer will make sure the spy falls + // to the ground when possible + spy = spawn(); + spy.classname = "airtimer"; + spy.owner = self; + spy.think = CF_Spy_AirThink; + spy.nextthink = time + 0.1; + // set spy feign variables + self.is_feigning = 1; + Attack_Finished(0.8); + self.invisible_finished = 0; + // set precached model index + self.modelindex = modelindex_player; + // set size of player model + setsize(self, '-16 -16 -24', '16 16 -16'); + // set weapon state and remove weapon viewmodel + W_WeaponState_Save(self); + self.weaponmodel = ""; + self.weaponframe = 0; + // set view height to ground + self.view_ofs = '0 0 4'; + // do extra stuff if feign is not silent feign + if (issilent == 0) { + // make a death sound + DeathSound(); + // drop an empty backpack (if this is not disabled in settings) + if (feign_pack) + Spy_DropBackpack(); + + // print feign message (if this is not disabled in settings) + if (feign_msg) { + deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); + bprint(PRINT_MEDIUM, deathstring); + KillSound(self, self.attacked_by); + } + // set movement speed to 0 if currently in the air to disable manipulation of trajectory + if (!(self.flags & FL_ONGROUND)) + self.maxspeed = 0; + } + + // drop flag if spy is carrying it + te = find(world, classname, "item_tfgoal"); + while (te) { + if (te.owner == self) { + if (!(te.goal_activation & TFGI_KEEP) || self.has_disconnected == 1) + tfgoalitem_RemoveFromPlayer(te, self, 0); + if (CTF_Map == 1) { + if (te.goal_no == 1) + bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sblue\s flag!\n"); + else if (te.goal_no == 2) + bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sred\s flag!\n"); + } + } + te = find(te, classname, "item_tfgoal"); + } + // die with axe equipped if carrying axe, medikit, knife or spanner + if (self.weapon <= WEAP_AXE) { + spy_die_ax1(); + return; + } + + // randomize death animation + i = 1 + floor((random() * 6)); + if (i == 1) + spy_diea1(); + else if (i == 2) + spy_dieb1(); + else if (i == 3) + spy_diec1(); + else if (i == 4) + spy_died1(); + else + spy_diee1(); } }; From 7175bdaa663ea8b0ba13087fe8a524ae780a973f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 11:18:35 +1000 Subject: [PATCH 1517/2474] Don't spam when you can't (un)feign --- ssqc/spy.qc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 11a6a1e9..df4215d7 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -442,7 +442,6 @@ void (float issilent) FO_Spy_Feign = { // don't allow feign if spy is in air and air feigning is disallowed if (!feign_air && !(self.flags & FL_ONGROUND)) { - sprint(self, PRINT_HIGH, "You cannot feign while you are airborne\n"); return; } @@ -450,7 +449,6 @@ void (float issilent) FO_Spy_Feign = { local float area_check; area_check = Spy_CheckArea(self); if (area_check == 3) { - sprint(self, PRINT_HIGH, "You cannot feign on top of another spy\n"); return; } @@ -594,12 +592,6 @@ void () FO_Spy_Unfeign = { } else { spy_upe1(); } - - // something is on top of spy - } else if (area_check == 1) { - sprint(self, PRINT_HIGH, "You cannot get up with something on top of you\n"); - } else if (area_check == 2) { - sprint(self, PRINT_HIGH, "You cannot get up while someone is standing on you\n"); } } From 94642ba4b36ad1f4bdac5813f1030583173a0b7a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 11:55:33 +1000 Subject: [PATCH 1518/2474] Put dropflag on a button --- README.md | 1 + csqc/main.qc | 8 ++++++++ ssqc/qw.qc | 5 +++-- ssqc/weapons.qc | 5 +++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e99deb16..22d06b4d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ +* `+dropflag` Allows player to hold button and flag will be thrown on contact. * `+rj` Switches to rocket/incendiary weapon, jumps and shoots. `+aux_jump` is no longer required. * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. diff --git a/csqc/main.qc b/csqc/main.qc index eabaca94..307f194a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -60,6 +60,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-special"); registercommand("+special2"); registercommand("-special2"); + registercommand("+dropflag"); + registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); registercommand("tracktarget"); @@ -315,6 +317,12 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-special2": localcmd("-button4"); break; + case "+dropflag": + localcmd("+button7"); + break; + case "-dropflag": + localcmd("-button7"); + break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { localcmd("+button4"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 3da232cb..acd78f7c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -18,8 +18,9 @@ typedef void (float n) f_void_float; .float tp_grenades_1; // 1st type of grenades being carried .float tp_grenades_2; // 2nd type of grenades being carried .float tp_grenade_switch; // Set to 1 if +gren1 and +gren2 switch places -.float button3; // special -.float button4; // special2 +.float button3; // +special +.float button4; // +special2 +.float button7; // +dropflag .float hook_out; // Dummy field for hook to silence error messages .float got_aliases; // TRUE if the player has TeamFortress aliases diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1885dc4a..323ac959 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3502,6 +3502,11 @@ void () ButtonFrame = { self.button4_keyup_frame = 0; } + + // +dropflag + if (self.button7) { + DropGoalItems(); + } } void () W_WeaponFrame = { From 903592bacea6cea2d09bc4a4ead94768cb69ed25 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 12:17:35 +1000 Subject: [PATCH 1519/2474] Hold feign, but wait until taking damage to feign --- ssqc/client.qc | 7 ------- ssqc/combat.qc | 2 +- ssqc/weapons.qc | 7 ++++++- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index f8f153af..6f06e868 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2623,13 +2623,6 @@ void () PlayerPreThink = { } } - if ((self.impulse == TF_SPY_DIE_OFF) && (self.playerclass == PC_SPY)) { - self.feign_next_damage = 0; - if (self.is_feigning) { - CF_Spy_FeignDeath(0); - } - } - if ((time < self.pausetime) || (cease_fire == 1)) { self.velocity = '0 0 0'; } diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 0bc03532..1278d2f6 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -682,7 +682,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, } if (self.feign_next_damage && !self.is_feigning){ - CF_Spy_FeignDeath(0); + FO_Spy_Feign(0); } self = oldself; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 323ac959..8788c46b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3378,7 +3378,9 @@ void () ButtonFrame = { FO_Airblast(); break; case PC_SPY: - FO_Spy_Feign(0); + if (self.button3_keydown_frame) { + self.feign_next_damage = 1; + } break; case PC_ENGINEER: if (self.button3_keydown_frame) { @@ -3412,6 +3414,9 @@ void () ButtonFrame = { case PC_PYRO: break; case PC_SPY: + if (self.button3_keyup_frame) { + self.feign_next_damage = 0; + } FO_Spy_Unfeign(); break; case PC_ENGINEER: From 740244975cb4b4bab805528a3ed7f3f21ee31bf3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 12:29:23 +1000 Subject: [PATCH 1520/2474] Add grenade buttons --- csqc/main.qc | 16 ++++++++++++++++ ssqc/qw.qc | 2 ++ ssqc/weapons.qc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index 307f194a..ec3af33d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -60,6 +60,10 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-special"); registercommand("+special2"); registercommand("-special2"); + registercommand("+grenade1"); + registercommand("-grenade1"); + registercommand("+grenade2"); + registercommand("-grenade2"); registercommand("+dropflag"); registercommand("-dropflag"); registercommand("+rj"); @@ -317,6 +321,18 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-special2": localcmd("-button4"); break; + case "+grenade1": + localcmd("+button5"); + break; + case "-grenade1": + localcmd("-button5"); + break; + case "+grenade2": + localcmd("+button6"); + break; + case "-grenade2": + localcmd("-button6"); + break; case "+dropflag": localcmd("+button7"); break; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index acd78f7c..29e8623f 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -20,6 +20,8 @@ typedef void (float n) f_void_float; .float tp_grenade_switch; // Set to 1 if +gren1 and +gren2 switch places .float button3; // +special .float button4; // +special2 +.float button5; // +grenade1 +.float button6; // +grenade2 .float button7; // +dropflag .float hook_out; // Dummy field for hook to silence error messages diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 8788c46b..05369ae2 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -136,6 +136,12 @@ void (entity ent, float num) SetFlameCount; .float button4_keydown; .float button4_keydown_frame; .float button4_keyup_frame; +.float button5_keydown; +.float button5_keydown_frame; +.float button5_keyup_frame; +.float button6_keydown; +.float button6_keydown_frame; +.float button6_keyup_frame; void () W_Precache = { precache_sound("weapons/r_exp3.wav"); @@ -3508,6 +3514,46 @@ void () ButtonFrame = { self.button4_keyup_frame = 0; } + if (self.button5) { + if (!self.button5_keydown) { + self.button5_keydown = 1; + self.button5_keydown_frame = 1; + } + + if (self.button5_keydown_frame) { + TeamFortress_PrimeThrowGrenade(1); + } + + self.button5_keydown_frame = 0; + } else { + if (self.button5_keydown) { + self.button5_keydown = 0; + self.button5_keyup_frame = 1; + } + + self.button5_keyup_frame = 0; + } + + if (self.button6) { + if (!self.button6_keydown) { + self.button6_keydown = 1; + self.button6_keydown_frame = 1; + } + + if (self.button5_keydown_frame) { + TeamFortress_PrimeThrowGrenade(2); + } + + self.button6_keydown_frame = 0; + } else { + if (self.button6_keydown) { + self.button6_keydown = 0; + self.button6_keyup_frame = 1; + } + + self.button6_keyup_frame = 0; + } + // +dropflag if (self.button7) { DropGoalItems(); From 2abb534bbd1e9d3831375b1af9d7ab4a0d3c044e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 12:30:56 +1000 Subject: [PATCH 1521/2474] Create grenade buttons --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 22d06b4d..85891047 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ +* `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. * `+dropflag` Allows player to hold button and flag will be thrown on contact. * `+rj` Switches to rocket/incendiary weapon, jumps and shoots. `+aux_jump` is no longer required. * `dlastspawn` Tells spy to disguise as enemy who last spawned. From 2a3924c364da7fef42a7b39cb940101e1e75e015 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 14:44:30 +1000 Subject: [PATCH 1522/2474] Make swapping of incendiary and flame optional --- csqc/main.qc | 2 ++ ssqc/weapons.qc | 30 ++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index ec3af33d..44c5258c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -437,6 +437,8 @@ void InterceptRocketJump() { if (active_weapon != rj_weapon) { if (getplayerkeyfloat(player_localnum, "old_weapon_impulses") || getplayerkeyfloat(player_localnum, "owi")) { localcmd("impulse 7\n"); + } else if (player_class = PC_PYRO && getplayerkeyfloat(player_localnum, "cf_pyro_impulses")) { + localcmd("impulse 2\n"); } else { localcmd("impulse 1\n"); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 05369ae2..d3c5230e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2212,17 +2212,20 @@ void () W_PrintWeaponMessage = { }; float (float weap) W_GetSlot = { + local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); if (weap == WEAP_ROCKET_LAUNCHER || weap == WEAP_SUPER_NAILGUN || weap == WEAP_SNIPER_RIFLE - || weap == WEAP_INCENDIARY + || (!cf_pyro_impulses && weap == WEAP_INCENDIARY) + || (cf_pyro_impulses && weap == WEAP_FLAMETHROWER) || weap == WEAP_TRANQ || weap == WEAP_LASER || weap == WEAP_ASSAULT_CANNON) { return 1; } else if (weap == WEAP_SUPER_SHOTGUN || weap == WEAP_AUTO_RIFLE - || weap == WEAP_FLAMETHROWER) { + || (!cf_pyro_impulses && weap == WEAP_FLAMETHROWER) + || (cf_pyro_impulses && weap == WEAP_INCENDIARY)) { return 2; } else if (weap == WEAP_SHOTGUN) { if (self.playerclass == PC_SCOUT) @@ -2278,6 +2281,7 @@ float (float weap) W_OldGetSlot = { }; float (float inp) W_AmmoSlot = { + local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); self.noammo = 0; if (inp == TF_SLOT1) { @@ -2296,7 +2300,9 @@ float (float inp) W_AmmoSlot = { self.noammo = 1; else if (self.ammo_cells < 7) self.noammo = 2; - } else if (self.playerclass == PC_PYRO && self.ammo_rockets < 3) + } else if (self.playerclass == PC_PYRO && !cf_pyro_impulses && self.ammo_rockets < 3) + self.noammo = 1; + else if (self.playerclass == PC_PYRO && cf_pyro_impulses && self.ammo_cells < 3) self.noammo = 1; else if (self.playerclass == PC_SPY && self.ammo_shells < 1) self.noammo = 1; @@ -2316,7 +2322,9 @@ float (float inp) W_AmmoSlot = { self.noammo = 1; else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) self.noammo = 1; - else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) + else if (self.playerclass == PC_PYRO && !cf_pyro_impulses && self.ammo_cells < 1) + self.noammo = 1; + else if (self.playerclass == PC_PYRO && cf_pyro_impulses && self.ammo_rockets < 1) self.noammo = 1; } else if (inp == TF_SLOT3) { if (self.playerclass == PC_SCOUT @@ -2493,6 +2501,7 @@ float () W_OldWeaponSlot7 = { }; float () W_WeaponSlot1 = { + local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); if (self.playerclass == PC_SCOUT) return WEAP_NAILGUN; else if (self.playerclass == PC_SNIPER) @@ -2506,7 +2515,11 @@ float () W_WeaponSlot1 = { else if (self.playerclass == PC_HVYWEAP) return WEAP_ASSAULT_CANNON; else if (self.playerclass == PC_PYRO) - return WEAP_INCENDIARY; + if (cf_pyro_impulses) { + return WEAP_FLAMETHROWER; + } else { + return WEAP_INCENDIARY; + } else if (self.playerclass == PC_SPY) return WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) @@ -2515,6 +2528,7 @@ float () W_WeaponSlot1 = { }; float () W_WeaponSlot2 = { + local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); if (self.playerclass == PC_SCOUT) return WEAP_SHOTGUN; else if (self.playerclass == PC_SNIPER) @@ -2528,7 +2542,11 @@ float () W_WeaponSlot2 = { else if (self.playerclass == PC_DEMOMAN) { return WEAP_GRENADE_LAUNCHER; // weaponmode = 1 (pipebomb launcher) } else if (self.playerclass == PC_PYRO) - return WEAP_FLAMETHROWER; + if (cf_pyro_impulses) { + return WEAP_INCENDIARY; + } else { + return WEAP_FLAMETHROWER; + } return 0; }; From 97154d335cecba820f8c14dad13e193a95d83064 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 14:47:39 +1000 Subject: [PATCH 1523/2474] Add option to swtich pyro's primary and secondary weapons --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 85891047..bf8eb9da 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ New features * `+dropflag` Allows player to hold button and flag will be thrown on contact. * `+rj` Switches to rocket/incendiary weapon, jumps and shoots. `+aux_jump` is no longer required. * `dlastspawn` Tells spy to disguise as enemy who last spawned. +* `setinfo cf_pyro_impulses 1` to swap Pyro's primary and secondary weapons. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. * `special2` Scout: `autoscan`, Demoman: `+det5`, Pyro: `+rj`, Spy: `dlastspawn`, Engineer: `togglesentry` From d096ffef596765aa3c40593ba00a6291af348c89 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Jun 2022 18:56:37 +1000 Subject: [PATCH 1524/2474] Fix silly bugs --- csqc/csextradefs.qc | 1 + csqc/main.qc | 24 ++++++++++++------------ ssqc/weapons.qc | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 04d0181c..9d8795e9 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -63,6 +63,7 @@ vector TEXT_TEAM_COLOUR[] = { #define BUTTON4 8 #define BUTTON5 16 #define BUTTON6 32 +#define BUTTON7 64 #define MAP_MAX_CHARS 20 diff --git a/csqc/main.qc b/csqc/main.qc index 44c5258c..af8ede87 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -310,43 +310,43 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; case "+special": - localcmd("+button3"); + localcmd("+button3\n"); break; case "-special": - localcmd("-button3"); + localcmd("-button3\n"); break; case "+special2": - localcmd("+button4"); + localcmd("+button4\n"); break; case "-special2": - localcmd("-button4"); + localcmd("-button4\n"); break; case "+grenade1": - localcmd("+button5"); + localcmd("+button5\n"); break; case "-grenade1": - localcmd("-button5"); + localcmd("-button5\n"); break; case "+grenade2": - localcmd("+button6"); + localcmd("+button6\n"); break; case "-grenade2": - localcmd("-button6"); + localcmd("-button6\n"); break; case "+dropflag": - localcmd("+button7"); + localcmd("+button7\n"); break; case "-dropflag": - localcmd("-button7"); + localcmd("-button7\n"); break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { - localcmd("+button4"); + localcmd("+button4\n"); } break; case "-rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { - localcmd("-button4"); + localcmd("-button4\n"); } break; case "vote_addmap": diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d3c5230e..e26cdad8 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3558,7 +3558,7 @@ void () ButtonFrame = { self.button6_keydown_frame = 1; } - if (self.button5_keydown_frame) { + if (self.button6_keydown_frame) { TeamFortress_PrimeThrowGrenade(2); } From bd5abf060a44fa93de7c246b8e851d2950367e2a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 01:10:17 +1000 Subject: [PATCH 1525/2474] Let people know when they're last to ready up --- csqc/csextradefs.qc | 1 + csqc/main.qc | 1 + csqc/status.qc | 34 +++++++++++++++++++++++++++++++++- share/defs.h | 21 +++++++++++---------- ssqc/clan.qc | 44 ++++++++++++++++++++++++++++++++++++++++---- ssqc/client.qc | 13 +++++++++++-- ssqc/qw.qc | 1 + ssqc/world.qc | 3 ++- 8 files changed, 100 insertions(+), 18 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index ffbbb093..3997e7cc 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -283,6 +283,7 @@ typedef struct { //1 = Clanmode, 2 = Quadmode, 4 = Duelmode, 8 = Prematch float GameMode; float Ready; + float LastNotReady; float CountdownStarted; // scout float ScannerOn; diff --git a/csqc/main.qc b/csqc/main.qc index 1feebf15..32007a35 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -101,6 +101,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { is_observer = TRUE; player_class = getstatf(STAT_CLASS); SBAR.Ready = getstatf(STAT_READY); + SBAR.LastNotReady = getstatf(STAT_ONLY_ONE_NOT_READY); oldhealth = getstatf(STAT_HEALTH); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) diff --git a/csqc/status.qc b/csqc/status.qc index c4fd4c0f..3e3c06cf 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -559,14 +559,46 @@ void(string panelid, float display, string text) drawReadyPanel = { } else if(round_over) { message = "Change map to continue playing"; } else { + textcolour = MENU_TEXT_WARNING; tokenize(findkeysforcommand("ready")); string keynum = argv(0); + + if(SBAR.LastNotReady) { + local vector alert_text_largetext = mediumtext * 2; + local vector alert_text_position = position; + alert_text_position.y *= 6; + local string alert_text_message; + + if(keynum != "-1") { + alert_text_message = "Everyone else is ready!"; + } + + pos_aligned = GetTextAlignOffset( + alert_text_position.x, + size.x, + padding, + alert_text_message, + alert_text_largetext.x, + panel.Orientation + ); + + drawstring( + [pos_aligned, alert_text_position.y], + alert_text_message, + alert_text_largetext, + textcolour, + 1, + 0 + ); + + position.y = alert_text_position.y + 48; + } + if(keynum != "-1") { message = strcat("Press ", keynumtostring(stof(keynum)), " to ready up"); } else { message = "Type 'ready' in the console to ready up"; } - textcolour = MENU_TEXT_WARNING; } } } diff --git a/share/defs.h b/share/defs.h index ff33ed19..03dc548d 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1479,16 +1479,17 @@ // stats // first 32 are reserved -#define STAT_TEAMNO 33 -#define STAT_READY 34 -#define STAT_CLASS 35 -#define STAT_VELOCITY_X 36 -#define STAT_VELOCITY_Y 37 -#define STAT_VELOCITY_Z 38 -#define STAT_NO_GREN1 39 -#define STAT_NO_GREN2 40 -#define STAT_TP_GREN1 41 -#define STAT_TP_GREN2 42 +#define STAT_TEAMNO 33 +#define STAT_READY 34 +#define STAT_CLASS 35 +#define STAT_VELOCITY_X 36 +#define STAT_VELOCITY_Y 37 +#define STAT_VELOCITY_Z 38 +#define STAT_NO_GREN1 39 +#define STAT_NO_GREN2 40 +#define STAT_TP_GREN1 41 +#define STAT_TP_GREN2 42 +#define STAT_ONLY_ONE_NOT_READY 43 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/clan.qc b/ssqc/clan.qc index c2570e17..e2b9c01f 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -371,8 +371,10 @@ void () ResetBreakAndReady = { while (te != world) { te.bvote = 0; te.is_ready = 0; + te.is_only_one_not_ready = 0; v_break = 0; v_ready = 0; + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { UpdateClientPrematch(te, TRUE); } @@ -945,6 +947,15 @@ void () PlayerNotReady = { self.is_ready = 0; v_ready = (v_ready - 1); Broadcast_Players_NotReady(); + + local float f1 = TeamFortress_GetNoPlayers (); + if (v_ready < f1 -1) { + local entity p = find (world, classname, "player"); + while (p != world) { + p.is_only_one_not_ready = 0; + p = find(p, classname, "player"); + } + } } } @@ -973,8 +984,7 @@ float () CheckAllPlayersReady = { return 0; } -void () PlayerReady = -{ +void () PlayerReady = { if (is_countdown) { sprint(self, 2, "You cannot do this after countdown has started.\n"); return; @@ -991,16 +1001,33 @@ void () PlayerReady = sprint(self, 2, "You must choose a class first.\n"); return; } - if (intermission_running) + if (intermission_running) { return; - if (self.classname != "player") + } + + if (self.classname != "player") { return; + } + if (self.is_ready) { PlayerNotReady(); return; } + self.is_ready = 1; v_ready = v_ready + 1; + + local float f1 = TeamFortress_GetNoPlayers (); + if (v_ready == f1 -1) { + local entity p = find (world, classname, "player"); + while (p != world) { + if (p.is_ready == 0) { + p.is_only_one_not_ready = 1; + } + p = find(p, classname, "player"); + } + } + bprint2 (3, self.netname, " is ready to start the match\n"); if(!CheckAllPlayersReady()) Broadcast_Players_NotReady(); @@ -1016,6 +1043,15 @@ void () RemoveVotes = { bprint2(2, self.netname, " is NOT ready anymore\n "); self.is_ready = 0; v_ready = (v_ready - 1); + + local float f1 = TeamFortress_GetNoPlayers (); + if (v_ready < f1 -1) { + local entity p = find (world, classname, "player"); + while (p != world) { + p.is_only_one_not_ready = 0; + p = find(p, classname, "player"); + } + } } }; diff --git a/ssqc/client.qc b/ssqc/client.qc index 819e3cf2..10d9eba1 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3055,12 +3055,21 @@ void () ClientDisconnect = { } else { CheckAllPlayersReady(); } + + local float f1 = TeamFortress_GetNoPlayers (); + if (v_ready < f1 -1) { + local entity p = find (world, classname, "player"); + while (p != world) { + p.is_only_one_not_ready = 0; + p = find(p, classname, "player"); + } + } } - + if(votemode) { UnvoteForMap(self); } - + }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 26515761..59d1512b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -645,6 +645,7 @@ float autokick_kills; .float vote; .float bvote; .float is_ready; +.float is_only_one_not_ready; .float is_admin; .float admin_mode; diff --git a/ssqc/world.qc b/ssqc/world.qc index e07013a6..746ba84c 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -328,6 +328,7 @@ void () worldspawn = { clientstat(STAT_TEAMNO, EV_FLOAT, team_no); clientstat(STAT_READY, EV_FLOAT, is_ready); + clientstat(STAT_ONLY_ONE_NOT_READY, EV_FLOAT, is_only_one_not_ready); clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); @@ -461,4 +462,4 @@ void () CheckTrackedSettings = { s.value = new_val; } } -} \ No newline at end of file +} From 5a77a25615d2f96392d7d54221d51d1fb004191d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 01:21:01 +1000 Subject: [PATCH 1526/2474] Ready to start --- csqc/status.qc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 3e3c06cf..6eb09556 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -592,12 +592,18 @@ void(string panelid, float display, string text) drawReadyPanel = { ); position.y = alert_text_position.y + 48; - } - if(keynum != "-1") { - message = strcat("Press ", keynumtostring(stof(keynum)), " to ready up"); + if(keynum != "-1") { + message = strcat("Press ", keynumtostring(stof(keynum)), " to start"); + } else { + message = "Type 'ready' in the console to start"; + } } else { - message = "Type 'ready' in the console to ready up"; + if(keynum != "-1") { + message = strcat("Press ", keynumtostring(stof(keynum)), " to ready up"); + } else { + message = "Type 'ready' in the console to ready up"; + } } } } From 45abae99776adfcbaac5b2f02c558c56033be80d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 01:38:34 +1000 Subject: [PATCH 1527/2474] Allow grens in prematch --- ssqc/weapons.qc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 51ab89e1..b0405b05 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2953,6 +2953,17 @@ void () ImpulseCommands = { if ((self.last_impulse == TF_DETPACK) && self.impulse) TeamFortress_SetDetpack(self.impulse); + if (!self.is_feigning) { + if (self.impulse == TF_GRENADE_1) + TeamFortress_PrimeGrenade(1); + else if (self.impulse == TF_GRENADE_2) + TeamFortress_PrimeGrenade(2); + else if (self.impulse == TF_GRENADE_PT_1) + TeamFortress_PrimeThrowGrenade(1); + else if (self.impulse == TF_GRENADE_PT_2) + TeamFortress_PrimeThrowGrenade(2); + } + if (cb_prematch || cease_fire) { PreMatchImpulses(); DeadImpulses(); @@ -2985,17 +2996,6 @@ void () ImpulseCommands = { } else if (self.impulse == TF_TOGGLEVOTE) Vote_ToggleMenu(self); - if (!self.is_feigning) { - if (self.impulse == TF_GRENADE_1) - TeamFortress_PrimeGrenade(1); - else if (self.impulse == TF_GRENADE_2) - TeamFortress_PrimeGrenade(2); - else if (self.impulse == TF_GRENADE_PT_1) - TeamFortress_PrimeThrowGrenade(1); - else if (self.impulse == TF_GRENADE_PT_2) - TeamFortress_PrimeThrowGrenade(2); - } - if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { if (self.impulse == TF_WEAPNEXT) CycleWeaponNext(); From a0ec9ec225e203039e05dc74b31cbd6e23e3a5ad Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 02:18:14 +1000 Subject: [PATCH 1528/2474] Special toggles invincibility in prematch --- ssqc/weapons.qc | 304 +++++++++++++++++++++++++----------------------- 1 file changed, 161 insertions(+), 143 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e26cdad8..81d9923a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -123,6 +123,8 @@ void () PlayerNotReady; void () Broadcast_Players_NotReady; void () StartTimer; +void () ToggleInvincibility; + float () GetLastWeaponImpulse; float () IsUsingOldImpulses; @@ -3207,18 +3209,7 @@ void () PreMatchImpulses = { display_location(); if (self.impulse == TF_SPECIAL_SKILL) { - if(self.tfstate & TFSTATE_INVINCIBLE) { - self.items = self.items - (self.items & IT_INVULNERABILITY); - self.invincible_time = 0; - self.invincible_finished = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_INVINCIBLE); - self.effects = self.effects - (self.effects & (EF_RED + EF_DIMLIGHT + EF_BRIGHTLIGHT)); - } else { - self.items = self.items | IT_INVULNERABILITY; - self.invincible_time = 1; - self.tfstate = self.tfstate | TFSTATE_INVINCIBLE; - self.invincible_finished = time + 666; - } + ToggleInvincibility(); } }; @@ -3377,42 +3368,48 @@ void () ButtonFrame = { self.button3_keydown_frame = 1; } - switch (self.playerclass) { - case PC_SCOUT: - CF_Scout_Dash(); - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; - case PC_DEMOMAN: - TeamFortress_DetonatePipebombs(0); - break; - case PC_MEDIC: - if (self.button3_keydown_frame) { - CF_Medic_AuraToggle(); - } - break; - case PC_HVYWEAP: - if (self.button3_keydown_frame) { - FO_LockToggle(); - } - break; - case PC_PYRO: - FO_Airblast(); - break; - case PC_SPY: - if (self.button3_keydown_frame) { - self.feign_next_damage = 1; - } - break; - case PC_ENGINEER: - if (self.button3_keydown_frame) { - FO_Engineer_ToggleDispenser(); - } - break; - case PC_UNDEFINED: - break; + if (!cb_prematch && !cease_fire) { + switch (self.playerclass) { + case PC_SCOUT: + CF_Scout_Dash(); + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + TeamFortress_DetonatePipebombs(0); + break; + case PC_MEDIC: + if (self.button3_keydown_frame) { + CF_Medic_AuraToggle(); + } + break; + case PC_HVYWEAP: + if (self.button3_keydown_frame) { + FO_LockToggle(); + } + break; + case PC_PYRO: + FO_Airblast(); + break; + case PC_SPY: + if (self.button3_keydown_frame) { + self.feign_next_damage = 1; + } + break; + case PC_ENGINEER: + if (self.button3_keydown_frame) { + FO_Engineer_ToggleDispenser(); + } + break; + case PC_UNDEFINED: + break; + } + } else { + if (self.button3_keydown_frame) { + ToggleInvincibility(); + } } self.button3_keydown_frame = 0; @@ -3422,31 +3419,33 @@ void () ButtonFrame = { self.button3_keyup_frame = 1; } - switch (self.playerclass) { - case PC_SCOUT: - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; - case PC_DEMOMAN: - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - break; - case PC_SPY: - if (self.button3_keyup_frame) { - self.feign_next_damage = 0; - } - FO_Spy_Unfeign(); - break; - case PC_ENGINEER: - break; - case PC_UNDEFINED: - break; + if (!cb_prematch && !cease_fire) { + switch (self.playerclass) { + case PC_SCOUT: + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + break; + case PC_SPY: + if (self.button3_keyup_frame) { + self.feign_next_damage = 0; + } + FO_Spy_Unfeign(); + break; + case PC_ENGINEER: + break; + case PC_UNDEFINED: + break; + } } self.button3_keyup_frame = 0; @@ -3459,41 +3458,43 @@ void () ButtonFrame = { self.button4_keydown_frame = 1; } - switch (self.playerclass) { - case PC_SCOUT: - if (self.button4_keydown_frame) { - ScannerSwitch(); - } - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - // Intercepted by InterceptRocketJump() - break; - case PC_DEMOMAN: - if (self.button4_keydown_frame) { - TeamFortress_SetDetpack(5); - } - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - // Intercepted by InterceptRocketJump() - break; - case PC_SPY: - if (self.button4_keydown_frame) { - FO_Spy_DisguiseLastSpawned(self); - } - break; - case PC_ENGINEER: - if (self.button4_keydown_frame) { - FO_Engineer_ToggleSentry(); - } - break; - case PC_UNDEFINED: - break; + if (!cb_prematch && !cease_fire) { + switch (self.playerclass) { + case PC_SCOUT: + if (self.button4_keydown_frame) { + ScannerSwitch(); + } + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + // Intercepted by InterceptRocketJump() + break; + case PC_DEMOMAN: + if (self.button4_keydown_frame) { + TeamFortress_SetDetpack(5); + } + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + // Intercepted by InterceptRocketJump() + break; + case PC_SPY: + if (self.button4_keydown_frame) { + FO_Spy_DisguiseLastSpawned(self); + } + break; + case PC_ENGINEER: + if (self.button4_keydown_frame) { + FO_Engineer_ToggleSentry(); + } + break; + case PC_UNDEFINED: + break; + } } self.button4_keydown_frame = 0; @@ -3503,30 +3504,32 @@ void () ButtonFrame = { self.button4_keyup_frame = 1; } - switch (self.playerclass) { - case PC_SCOUT: - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; - case PC_DEMOMAN: - if (self.button4_keyup_frame) { - TeamFortress_DetpackStop(); - } - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - break; - case PC_SPY: - break; - case PC_ENGINEER: - break; - case PC_UNDEFINED: - break; + if (!cb_prematch && !cease_fire) { + switch (self.playerclass) { + case PC_SCOUT: + break; + case PC_SNIPER: + break; + case PC_SOLDIER: + break; + case PC_DEMOMAN: + if (self.button4_keyup_frame) { + TeamFortress_DetpackStop(); + } + break; + case PC_MEDIC: + break; + case PC_HVYWEAP: + break; + case PC_PYRO: + break; + case PC_SPY: + break; + case PC_ENGINEER: + break; + case PC_UNDEFINED: + break; + } } self.button4_keyup_frame = 0; @@ -3583,7 +3586,7 @@ void () W_WeaponFrame = { if (self.login_in_progress) { CenterPrint(self, "Trying to log in..."); } - + if (loginRequired && !self.login) { PrintLoginMessage(); self.impulse = 0; @@ -3650,7 +3653,7 @@ void () W_WeaponFrame = { // slot 1-4 (or 1-7) binds if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && (WeaponReady(self) || !chweap_wait_attfinished) - && !(self.is_building && !engineer_move) && !self.is_detpacking) { + && !(self.is_building && !engineer_move) && !self.is_detpacking) { if (!(self.tfstate & TFSTATE_RELOADING)) { // load weapon state if current state doesn't match stored state @@ -3667,7 +3670,7 @@ void () W_WeaponFrame = { self.impulse = 0; } - // regular attack (both +attack and -attack) + // regular attack (both +attack and -attack) } else if (!self.impulse && !self.is_quickfiring) { // load weapon state if current state doesn't match @@ -3676,7 +3679,7 @@ void () W_WeaponFrame = { W_WeaponState_Load(self, 0); } - // +slot1-4 quick fire + // +slot1-4 quick fire } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && !self.is_detpacking) { self.is_quickfiring = 1; @@ -3705,10 +3708,10 @@ void () W_WeaponFrame = { } } - // change weapon if queue_weaponslot has been set + // change weapon if queue_weaponslot has been set } else if (self.queue_weaponslot > 0) { W_ChangeWeapon(self.queue_weaponslot); - // load weapon state + // load weapon state } else if (self.queue_weaponstate && WeaponReady(self)) { // load weaponstate saved from before quick fire started if (self.queue_weaponstate == 1) @@ -3788,7 +3791,7 @@ void () W_WeaponFrame = { case FLAG_INFO: ImpulseCommands(); return; - // allows setting detpack while reloading on toggle, defaults to off + // allows setting detpack while reloading on toggle, defaults to off case TF_DEMOMAN_DETPACK: case TF_DETPACK: case TF_DETPACK_STOP: @@ -3816,9 +3819,9 @@ void () W_WeaponFrame = { return; if (self.button0 - && (!self.fire_held_down - || - (self.fire_held_down && self.heat == 0 && self.playerclass == PC_HVYWEAP))) { + && (!self.fire_held_down + || + (self.fire_held_down && self.heat == 0 && self.playerclass == PC_HVYWEAP))) { if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) { @@ -3892,7 +3895,7 @@ void () RemoveGrenade = { te = find(world, classname, "grentimer"); while (te) { if ((te.owner == self.owner) && - (te.no_active_napalm_grens > 0)) + (te.no_active_napalm_grens > 0)) te.no_active_napalm_grens = te.no_active_napalm_grens - 1; te = find(te, classname, "grentimer"); } @@ -3916,3 +3919,18 @@ void () RemoveGrenade = { dremove(self); } }; + +void () ToggleInvincibility = { + if(self.tfstate & TFSTATE_INVINCIBLE) { + self.items = self.items - (self.items & IT_INVULNERABILITY); + self.invincible_time = 0; + self.invincible_finished = 0; + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_INVINCIBLE); + self.effects = self.effects - (self.effects & (EF_RED + EF_DIMLIGHT + EF_BRIGHTLIGHT)); + } else { + self.items = self.items | IT_INVULNERABILITY; + self.invincible_time = 1; + self.tfstate = self.tfstate | TFSTATE_INVINCIBLE; + self.invincible_finished = time + 666; + } +}; From 73e68e591aa741e4628e55ac15eff7476f37af3f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 02:37:00 +1000 Subject: [PATCH 1529/2474] Ignore panel position for nag message --- csqc/status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/status.qc b/csqc/status.qc index 6eb09556..f580a06f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -566,7 +566,7 @@ void(string panelid, float display, string text) drawReadyPanel = { if(SBAR.LastNotReady) { local vector alert_text_largetext = mediumtext * 2; local vector alert_text_position = position; - alert_text_position.y *= 6; + alert_text_position.y = ScreenSize.y / 3; local string alert_text_message; if(keynum != "-1") { From 190ebf4c96bf1880c347101bb3860a7de7edef18 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 02:45:36 +1000 Subject: [PATCH 1530/2474] Force nagging message to centre screen --- csqc/status.qc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index f580a06f..cdafcde2 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -565,13 +565,10 @@ void(string panelid, float display, string text) drawReadyPanel = { if(SBAR.LastNotReady) { local vector alert_text_largetext = mediumtext * 2; - local vector alert_text_position = position; + local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; - local string alert_text_message; - - if(keynum != "-1") { - alert_text_message = "Everyone else is ready!"; - } + alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); + local string alert_text_message = "Everyone else is ready!"; pos_aligned = GetTextAlignOffset( alert_text_position.x, From b3ffee51cb740ad93c081bb20b4d85c9922c86b4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 02:45:36 +1000 Subject: [PATCH 1531/2474] Force nagging message to centre screen --- csqc/status.qc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index f580a06f..cdafcde2 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -565,13 +565,10 @@ void(string panelid, float display, string text) drawReadyPanel = { if(SBAR.LastNotReady) { local vector alert_text_largetext = mediumtext * 2; - local vector alert_text_position = position; + local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; - local string alert_text_message; - - if(keynum != "-1") { - alert_text_message = "Everyone else is ready!"; - } + alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); + local string alert_text_message = "Everyone else is ready!"; pos_aligned = GetTextAlignOffset( alert_text_position.x, From 397d1625ca9aa0e055052f36a936eefa732dfa2e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 02:50:16 +1000 Subject: [PATCH 1532/2474] Centre both nag messages --- csqc/status.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/status.qc b/csqc/status.qc index cdafcde2..1cd61928 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -589,6 +589,7 @@ void(string panelid, float display, string text) drawReadyPanel = { ); position.y = alert_text_position.y + 48; + position.x = (ScreenSize.x / 2) - (size.x / 2); if(keynum != "-1") { message = strcat("Press ", keynumtostring(stof(keynum)), " to start"); From f2657e6742f35fc77b43ce864a3e776d7ce22c90 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 28 Jun 2022 23:07:19 +1000 Subject: [PATCH 1533/2474] Refactor before improving ready state --- csqc/csextradefs.qc | 2 +- csqc/main.qc | 2 +- csqc/status.qc | 35 ++++++++++++++++++++++++++++++++++- share/defs.h | 9 ++++++--- ssqc/clan.qc | 8 ++++---- ssqc/client.qc | 2 +- ssqc/qw.qc | 2 +- ssqc/world.qc | 2 +- 8 files changed, 49 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 086959bd..4b2cbc8d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -291,7 +291,7 @@ typedef struct { //1 = Clanmode, 2 = Quadmode, 4 = Duelmode, 8 = Prematch float GameMode; float Ready; - float LastNotReady; + float ReadyStatus; float CountdownStarted; // scout float ScannerOn; diff --git a/csqc/main.qc b/csqc/main.qc index 12a37fc2..39e41d53 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -114,7 +114,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { is_observer = TRUE; player_class = getstatf(STAT_CLASS); SBAR.Ready = getstatf(STAT_READY); - SBAR.LastNotReady = getstatf(STAT_ONLY_ONE_NOT_READY); + SBAR.ReadyStatus = getstatf(STAT_READY_STATUS); oldhealth = getstatf(STAT_HEALTH); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) diff --git a/csqc/status.qc b/csqc/status.qc index 1cd61928..732ede6c 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -563,7 +563,7 @@ void(string panelid, float display, string text) drawReadyPanel = { tokenize(findkeysforcommand("ready")); string keynum = argv(0); - if(SBAR.LastNotReady) { + if(SBAR.ReadyStatus == LAST_NOT_READY) { local vector alert_text_largetext = mediumtext * 2; local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; @@ -596,6 +596,39 @@ void(string panelid, float display, string text) drawReadyPanel = { } else { message = "Type 'ready' in the console to start"; } + } else if (SBAR.ReadyStatus == ENEMY_TEAM_READY) { + local vector alert_text_largetext = mediumtext * 2; + local vector alert_text_position; + alert_text_position.y = ScreenSize.y / 3; + alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); + local string alert_text_message = "Enemy team is ready!"; + + pos_aligned = GetTextAlignOffset( + alert_text_position.x, + size.x, + padding, + alert_text_message, + alert_text_largetext.x, + panel.Orientation + ); + + drawstring( + [pos_aligned, alert_text_position.y], + alert_text_message, + alert_text_largetext, + textcolour, + 1, + 0 + ); + + position.y = alert_text_position.y + 48; + position.x = (ScreenSize.x / 2) - (size.x / 2); + + if(keynum != "-1") { + message = strcat("Press ", keynumtostring(stof(keynum)), " to ready up"); + } else { + message = "Type 'ready' in the console to ready up"; + } } else { if(keynum != "-1") { message = strcat("Press ", keynumtostring(stof(keynum)), " to ready up"); diff --git a/share/defs.h b/share/defs.h index 990e2ef0..de8f06a5 100644 --- a/share/defs.h +++ b/share/defs.h @@ -101,7 +101,6 @@ #define IT_HOOK 8388608 // point content values - #define CONTENT_EMPTY -1 #define CONTENT_SOLID -2 #define CONTENT_WATER -3 @@ -193,7 +192,6 @@ #define UPDATE_TEMP 3 // entity effects - #define EF_BRIGHTFIELD 1 #define EF_MUZZLEFLASH 2 #define EF_BRIGHTLIGHT 4 @@ -231,6 +229,11 @@ #define AS_MELEE 3 #define AS_MISSILE 4 +// ready_status +#define NEITHER_TEAM_READY 1 +#define ENEMY_TEAM_READY 2 +#define LAST_NOT_READY 3 + //=========================================================================== // TEAMFORTRESS Defs //=========================================================================== @@ -1489,7 +1492,7 @@ #define STAT_NO_GREN2 40 #define STAT_TP_GREN1 41 #define STAT_TP_GREN2 42 -#define STAT_ONLY_ONE_NOT_READY 43 +#define STAT_READY_STATUS 43 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/clan.qc b/ssqc/clan.qc index e2b9c01f..02ac02d3 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -371,7 +371,7 @@ void () ResetBreakAndReady = { while (te != world) { te.bvote = 0; te.is_ready = 0; - te.is_only_one_not_ready = 0; + te.ready_status = NEITHER_TEAM_READY; v_break = 0; v_ready = 0; @@ -952,7 +952,7 @@ void () PlayerNotReady = { if (v_ready < f1 -1) { local entity p = find (world, classname, "player"); while (p != world) { - p.is_only_one_not_ready = 0; + p.ready_status = NEITHER_TEAM_READY; p = find(p, classname, "player"); } } @@ -1022,7 +1022,7 @@ void () PlayerReady = { local entity p = find (world, classname, "player"); while (p != world) { if (p.is_ready == 0) { - p.is_only_one_not_ready = 1; + p.ready_status = LAST_NOT_READY; } p = find(p, classname, "player"); } @@ -1048,7 +1048,7 @@ void () RemoveVotes = { if (v_ready < f1 -1) { local entity p = find (world, classname, "player"); while (p != world) { - p.is_only_one_not_ready = 0; + p.ready_status = NEITHER_TEAM_READY; p = find(p, classname, "player"); } } diff --git a/ssqc/client.qc b/ssqc/client.qc index 80e02df7..03e2e5a5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3066,7 +3066,7 @@ void () ClientDisconnect = { if (v_ready < f1 -1) { local entity p = find (world, classname, "player"); while (p != world) { - p.is_only_one_not_ready = 0; + p.ready_status = 0; p = find(p, classname, "player"); } } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4abeba20..ecb71300 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -651,7 +651,7 @@ float autokick_kills; .float vote; .float bvote; .float is_ready; -.float is_only_one_not_ready; +.float ready_status; .float is_admin; .float admin_mode; diff --git a/ssqc/world.qc b/ssqc/world.qc index 746ba84c..1d232310 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -328,7 +328,7 @@ void () worldspawn = { clientstat(STAT_TEAMNO, EV_FLOAT, team_no); clientstat(STAT_READY, EV_FLOAT, is_ready); - clientstat(STAT_ONLY_ONE_NOT_READY, EV_FLOAT, is_only_one_not_ready); + clientstat(STAT_READY_STATUS, EV_FLOAT, ready_status); clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); From a678c3e235e6546ba98c711c05cc9eb82254df47 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 30 Jun 2022 00:04:06 +1000 Subject: [PATCH 1534/2474] Show obnoxious message when enemy team is ready --- csqc/status.qc | 4 +- share/defs.h | 5 +- ssqc/clan.qc | 138 ++++++++++++++++++++++++++++++++++++++----------- ssqc/client.qc | 16 ++---- 4 files changed, 116 insertions(+), 47 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 732ede6c..b4bf13be 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -563,7 +563,7 @@ void(string panelid, float display, string text) drawReadyPanel = { tokenize(findkeysforcommand("ready")); string keynum = argv(0); - if(SBAR.ReadyStatus == LAST_NOT_READY) { + if(SBAR.ReadyStatus & LAST_NOT_READY) { local vector alert_text_largetext = mediumtext * 2; local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; @@ -596,7 +596,7 @@ void(string panelid, float display, string text) drawReadyPanel = { } else { message = "Type 'ready' in the console to start"; } - } else if (SBAR.ReadyStatus == ENEMY_TEAM_READY) { + } else if (SBAR.ReadyStatus & ENEMY_TEAM_READY) { local vector alert_text_largetext = mediumtext * 2; local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; diff --git a/share/defs.h b/share/defs.h index de8f06a5..805d84c3 100644 --- a/share/defs.h +++ b/share/defs.h @@ -230,9 +230,8 @@ #define AS_MISSILE 4 // ready_status -#define NEITHER_TEAM_READY 1 -#define ENEMY_TEAM_READY 2 -#define LAST_NOT_READY 3 +#define ENEMY_TEAM_READY 1 +#define LAST_NOT_READY 2 //=========================================================================== // TEAMFORTRESS Defs diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 02ac02d3..df09b980 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -371,7 +371,7 @@ void () ResetBreakAndReady = { while (te != world) { te.bvote = 0; te.is_ready = 0; - te.ready_status = NEITHER_TEAM_READY; + UpdateReadyStatus(); v_break = 0; v_ready = 0; @@ -943,19 +943,114 @@ void () Broadcast_Players_NotReady = { void () PlayerNotReady = { if (self.is_ready) { - bprint2 (2, self.netname, " is NOT ready anymore\n "); self.is_ready = 0; + UpdateReadyStatus(); + bprint2 (2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); Broadcast_Players_NotReady(); + } +} - local float f1 = TeamFortress_GetNoPlayers (); - if (v_ready < f1 -1) { - local entity p = find (world, classname, "player"); - while (p != world) { - p.ready_status = NEITHER_TEAM_READY; - p = find(p, classname, "player"); - } +void () UpdateReadyStatus = { + local float players_size; + local float players_ready_size; + local float team_1_size; + local float team_1_ready_size; + local float team_2_size; + local float team_2_ready_size; + local float team_3_size; + local float team_3_ready_size; + local float team_4_size; + local float team_4_ready_size; + + local entity p = find(world, classname, "player"); + while (p != world) { + if (p.team_no) { + players_size++; + } + + if (p.is_ready) { + players_ready_size++; + } + + switch(p.team_no) { + case 1: + team_1_size++; + if (p.is_ready) { + team_1_ready_size++; + } + break; + case 2: + team_2_size++; + if (p.is_ready) { + team_2_ready_size++; + } + case 3: + team_3_size++; + if (p.is_ready) { + team_3_ready_size++; + } + break; + case 4: + team_4_size++; + if (p.is_ready) { + team_4_ready_size++; + } + break; + } + + p = find(p, classname, "player"); + } + + local float team_1_ready = (team_1_size && (team_1_size - team_1_ready_size) == 0); + local float team_2_ready = (team_2_size && (team_2_size - team_2_ready_size) == 0); + local float team_3_ready = (team_3_size && (team_3_size - team_3_ready_size) == 0); + local float team_4_ready = (team_4_size && (team_4_size - team_4_ready_size) == 0); + local float teams_ready_size = team_1_ready + team_2_ready + team_3_ready + team_4_ready; + local float one_player_not_ready = (players_size > 1 && players_size - players_ready_size == 1); + + local entity p = find(world, classname, "player"); + local float team_ready; + + while (p != world) { + // ENEMY_TEAM_READY + switch(p.team_no) { + case 1: + if (team_1_ready) { + team_ready = 1; + } + break; + case 2: + if (team_2_ready) { + team_ready = 1; + } + case 3: + if (team_3_ready) { + team_ready = 1; + } + break; + case 4: + if (team_4_ready) { + team_ready = 1; + } + break; + } + + if ((teams_ready_size - team_ready) > 0) { + p.ready_status |= ENEMY_TEAM_READY; + } else { + p.ready_status &= ~ENEMY_TEAM_READY; + } + + // LAST_NOT_READY + if (!p.is_ready && one_player_not_ready) { + p.ready_status |= LAST_NOT_READY; + } else { + p.ready_status &= ~LAST_NOT_READY; } + + + p = find(p, classname, "player"); } } @@ -1015,19 +1110,8 @@ void () PlayerReady = { } self.is_ready = 1; + UpdateReadyStatus(); v_ready = v_ready + 1; - - local float f1 = TeamFortress_GetNoPlayers (); - if (v_ready == f1 -1) { - local entity p = find (world, classname, "player"); - while (p != world) { - if (p.is_ready == 0) { - p.ready_status = LAST_NOT_READY; - } - p = find(p, classname, "player"); - } - } - bprint2 (3, self.netname, " is ready to start the match\n"); if(!CheckAllPlayersReady()) Broadcast_Players_NotReady(); @@ -1040,18 +1124,10 @@ void () RemoveVotes = { v_break = (v_break - 1); } if (self.is_ready) { - bprint2(2, self.netname, " is NOT ready anymore\n "); self.is_ready = 0; + UpdateReadyStatus(); + bprint2(2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); - - local float f1 = TeamFortress_GetNoPlayers (); - if (v_ready < f1 -1) { - local entity p = find (world, classname, "player"); - while (p != world) { - p.ready_status = NEITHER_TEAM_READY; - p = find(p, classname, "player"); - } - } } }; diff --git a/ssqc/client.qc b/ssqc/client.qc index 03e2e5a5..881d2b25 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -59,6 +59,7 @@ void (string cl_pwd) Admin_Check; void () Admin_Aliases; void () PreMatch_Message; float () GetLastWeaponImpulse; +void () UpdateReadyStatus; float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; void (float tno, float scoretoadd) TeamFortress_TeamIncreaseScore; @@ -3054,21 +3055,14 @@ void () ClientDisconnect = { strunzone(self.StatusString); self.StatusString = string_null; + + if(cb_prematch) { //Check in case the player leaving is the last not-readied player if(self.is_ready) { v_ready = (v_ready - 1); - } else { - CheckAllPlayersReady(); - } - - local float f1 = TeamFortress_GetNoPlayers (); - if (v_ready < f1 -1) { - local entity p = find (world, classname, "player"); - while (p != world) { - p.ready_status = 0; - p = find(p, classname, "player"); - } + } else if (!CheckAllPlayersReady()) { + UpdateReadyStatus(); } } From 77d15604ff71b582520cc86a4d29725be61a10c9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 30 Jun 2022 00:41:08 +1000 Subject: [PATCH 1535/2474] remove is_ready field, buggy --- csqc/csextradefs.qc | 1 - csqc/main.qc | 1 - csqc/status.qc | 2 +- share/defs.h | 8 ++++---- ssqc/clan.qc | 37 ++++++++++++++++++------------------- ssqc/client.qc | 4 ++-- ssqc/qw.qc | 1 - ssqc/tforttm.qc | 5 +++-- ssqc/weapons.qc | 2 +- ssqc/world.qc | 1 - 10 files changed, 29 insertions(+), 33 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 4b2cbc8d..834b09ff 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -290,7 +290,6 @@ typedef struct { string Hint; //1 = Clanmode, 2 = Quadmode, 4 = Duelmode, 8 = Prematch float GameMode; - float Ready; float ReadyStatus; float CountdownStarted; // scout diff --git a/csqc/main.qc b/csqc/main.qc index 39e41d53..dc451164 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -113,7 +113,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (team_no == 0) is_observer = TRUE; player_class = getstatf(STAT_CLASS); - SBAR.Ready = getstatf(STAT_READY); SBAR.ReadyStatus = getstatf(STAT_READY_STATUS); oldhealth = getstatf(STAT_HEALTH); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); diff --git a/csqc/status.qc b/csqc/status.qc index b4bf13be..1643bd2e 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -553,7 +553,7 @@ void(string panelid, float display, string text) drawReadyPanel = { return; } if(prematch && team_no && player_class && !SBAR.CountdownStarted && !is_spectator) { - if(SBAR.Ready) { + if(SBAR.ReadyStatus & PLAYER_READY) { message = "Ready"; textcolour = MENU_TEXT_GREEN; } else if(round_over) { diff --git a/share/defs.h b/share/defs.h index 805d84c3..04b175a3 100644 --- a/share/defs.h +++ b/share/defs.h @@ -230,8 +230,9 @@ #define AS_MISSILE 4 // ready_status -#define ENEMY_TEAM_READY 1 -#define LAST_NOT_READY 2 +#define PLAYER_READY 1 +#define ENEMY_TEAM_READY 2 +#define LAST_NOT_READY 4 //=========================================================================== // TEAMFORTRESS Defs @@ -1482,7 +1483,7 @@ // stats // first 32 are reserved #define STAT_TEAMNO 33 -#define STAT_READY 34 +#define STAT_READY_STATUS 34 #define STAT_CLASS 35 #define STAT_VELOCITY_X 36 #define STAT_VELOCITY_Y 37 @@ -1491,7 +1492,6 @@ #define STAT_NO_GREN2 40 #define STAT_TP_GREN1 41 #define STAT_TP_GREN2 42 -#define STAT_READY_STATUS 43 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/clan.qc b/ssqc/clan.qc index df09b980..c9ac5467 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -370,7 +370,7 @@ void () ResetBreakAndReady = { te = find (world, classname, "player"); while (te != world) { te.bvote = 0; - te.is_ready = 0; + te.ready_status &= ~PLAYER_READY; UpdateReadyStatus(); v_break = 0; v_ready = 0; @@ -877,7 +877,7 @@ void () CenterPrint_Players_NotReady = { local float first = 0; te = find (world, classname, "player"); while (te) { - if (te.is_ready == 0 && !te.has_disconnected) + if (!(te.ready_status & PLAYER_READY) && !te.has_disconnected) { first = first + 1; if (first == 1) @@ -916,7 +916,7 @@ void () Broadcast_Players_NotReady = { local float first = 1; te = find (world, classname, "player"); while (te != world) { - if (te.is_ready == 0 && !te.has_disconnected) { + if (!(te.ready_status & PLAYER_READY) && !te.has_disconnected) { if (!first) players_not_ready = strcat(players_not_ready, ", "); else @@ -929,7 +929,7 @@ void () Broadcast_Players_NotReady = { bprint(1, players_not_ready); te = find (world, classname, "player"); while (te != world) { - if (te.is_ready == 0 && !te.has_disconnected) + if (!(te.ready_status & PLAYER_READY) && !te.has_disconnected) sprint(te, 2, "If you are ready, type \s/ready\s in the console\n"); te = find(te, classname, "player"); } @@ -942,8 +942,8 @@ void () Broadcast_Players_NotReady = { } void () PlayerNotReady = { - if (self.is_ready) { - self.is_ready = 0; + if (self.ready_status & PLAYER_READY) { + self.ready_status &= ~PLAYER_READY; UpdateReadyStatus(); bprint2 (2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); @@ -969,31 +969,31 @@ void () UpdateReadyStatus = { players_size++; } - if (p.is_ready) { + if (p.ready_status & PLAYER_READY) { players_ready_size++; } switch(p.team_no) { case 1: team_1_size++; - if (p.is_ready) { + if (p.ready_status & PLAYER_READY) { team_1_ready_size++; } break; case 2: team_2_size++; - if (p.is_ready) { + if (p.ready_status & PLAYER_READY) { team_2_ready_size++; } case 3: team_3_size++; - if (p.is_ready) { + if (p.ready_status & PLAYER_READY) { team_3_ready_size++; } break; case 4: team_4_size++; - if (p.is_ready) { + if (p.ready_status & PLAYER_READY) { team_4_ready_size++; } break; @@ -1043,13 +1043,12 @@ void () UpdateReadyStatus = { } // LAST_NOT_READY - if (!p.is_ready && one_player_not_ready) { + if (!(p.ready_status & PLAYER_READY) && one_player_not_ready) { p.ready_status |= LAST_NOT_READY; } else { p.ready_status &= ~LAST_NOT_READY; } - p = find(p, classname, "player"); } } @@ -1064,7 +1063,7 @@ float () CheckAllPlayersReady = { } if (intermission_running) return 0; - + f1 = TeamFortress_GetNoPlayers (); bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); if (v_ready == f1 && v_ready > 0) { @@ -1104,12 +1103,12 @@ void () PlayerReady = { return; } - if (self.is_ready) { + if (self.ready_status & PLAYER_READY) { PlayerNotReady(); return; } - self.is_ready = 1; + self.ready_status |= PLAYER_READY; UpdateReadyStatus(); v_ready = v_ready + 1; bprint2 (3, self.netname, " is ready to start the match\n"); @@ -1123,8 +1122,8 @@ void () RemoveVotes = { self.bvote = 0; v_break = (v_break - 1); } - if (self.is_ready) { - self.is_ready = 0; + if (self.ready_status & PLAYER_READY) { + self.ready_status &= ~PLAYER_READY; UpdateReadyStatus(); bprint2(2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); @@ -1139,7 +1138,7 @@ void () PreMatch_Message = { while (p != world) { if (p.netname != "") { sprint(p, PRINT_HIGH, "Currently in \sprematch\s time\n"); - if (p.is_ready) + if (p.ready_status & PLAYER_READY) sprint(p, PRINT_HIGH, "You are \sready\s to start the match.\n Type \s/notready\s in the console if you are not ready\n"); else sprint(p, PRINT_HIGH, "Type \s/ready\s in the console if you are ready to start the match\n"); diff --git a/ssqc/client.qc b/ssqc/client.qc index 881d2b25..c901a45e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1886,7 +1886,7 @@ void (entity player) UpdateScoreboardInfo = { CheckSetInfoKey(player, "touches", player.touches); CheckSetInfoKey(player, "team_no", player.team_no); CheckSetInfoKey(player, "playerclass", player.playerclass); - CheckSetInfoKey(player, "ready", player.is_ready); + CheckSetInfoKey(player, "ready", player.ready_status & PLAYER_READY); }; void (float all_dimensions) SetDimensions = { @@ -3059,7 +3059,7 @@ void () ClientDisconnect = { if(cb_prematch) { //Check in case the player leaving is the last not-readied player - if(self.is_ready) { + if(self.ready_status & PLAYER_READY) { v_ready = (v_ready - 1); } else if (!CheckAllPlayersReady()) { UpdateReadyStatus(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ecb71300..5187e472 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -650,7 +650,6 @@ float autokick_kills; .float vote; .float bvote; -.float is_ready; .float ready_status; .float is_admin; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index bb1edc28..93594462 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -165,7 +165,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options if (!CF_TeamIsValid) { return 0; } - + if (tno == 1) team = "blue team"; else if (tno == 2) @@ -179,7 +179,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options sprint(pe, PRINT_HIGH, "You are already on the ", team, "!\n"); return 0; } - + if (TeamFortress_TeamGetColor(tno) == 0 && !teamplay) { TeamFortress_TeamSetColor(tno); if (TeamFortress_TeamGetColor(tno) == 0) { @@ -297,6 +297,7 @@ float (float tno) TeamFortress_TeamSet = { local float tftso = TeamFortress_TeamSet_Options(self, tno, FALSE); SetDimensions(TRUE); UpdateAllClientsTeamScores(); + UpdateReadyStatus(); return (tftso); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index dd162be3..325db593 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2188,7 +2188,7 @@ float (entity pl) WeaponReady = { if (time >= pl.attack_finished && !(pl.tfstate & TFSTATE_RELOADING)) { return 1; } - + return 0; } diff --git a/ssqc/world.qc b/ssqc/world.qc index 1d232310..50ca1eb1 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -327,7 +327,6 @@ void () worldspawn = { lightstyle(63, "a"); clientstat(STAT_TEAMNO, EV_FLOAT, team_no); - clientstat(STAT_READY, EV_FLOAT, is_ready); clientstat(STAT_READY_STATUS, EV_FLOAT, ready_status); clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector From 37257a6ff6b3023d57df142f58579adece0a2f1d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 30 Jun 2022 23:58:45 +1000 Subject: [PATCH 1536/2474] Support press and hold or toggle for some buttons --- README.md | 3 +++ ssqc/client.qc | 1 + ssqc/demoman.qc | 8 +++++++ ssqc/menu.qc | 2 ++ ssqc/spy.qc | 22 +++++++++++++++++++ ssqc/weapons.qc | 57 ++++++++++++++++++++++++++++++++++++------------- 6 files changed, 78 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index bf8eb9da..df4dc986 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ New features * New buttons (not impulses): * `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledispenser`. * `+special2` Same as `special2`, but also has `+rj` for Soldier and Pyro. +* `setinfo hold_grens` for press and hold `+grenade1` and `+grenade2` +* `setinfo hold_fiegn` for press and hold feigning +* `setinfo hold_detpack` for press and hold detpack * `localinfo standardizedeathammo 1` server setting to make all backpack's dropped on death contain same ammo, regardless of victims ammo. If enabled defaults to 25 shells, 25 nails, 10 rockets, 50 cells. `localinfo deathammo_shells ` , `localinfo deathammo_nails ` , `localinfo deathammo_rockets `, `localinfo deathammo_cells ` to modify these values * `localinfo splitbackpackmodels 1` server setting to have different visual models for backpack dropped on death ``progs/deathbag.mdl`` and discards ``progs/discard.mdl`` * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. diff --git a/ssqc/client.qc b/ssqc/client.qc index 80e02df7..59f18280 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -668,6 +668,7 @@ void () DecodeLevelParms = { // override map-set class restrictions [off] override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); + // Maximum number of primary grenades per class /* max_gren1_scout = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index e72f65a0..0a1f24e3 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -128,6 +128,14 @@ void () TeamFortress_DetpackMenu = { Menu_Demoman(); }; +void (float timer) TeamFortress_ToggleDetpack = { + if (self.is_detpacking) { + TeamFortress_DetpackStop(); + } else { + TeamFortress_SetDetpack(timer); + } +}; + void (float timer) TeamFortress_SetDetpack = { local string stimer; local entity te; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index b098ccef..294e6400 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -6,6 +6,7 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin; void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor; void (float issilent) CF_Spy_FeignDeath; void (float issilent) FO_Spy_Feign; +void () FO_Spy_FeignOnNextDamage; void () FO_Spy_Unfeign; void (float issilent) CF_Spy_FeignDeath; void () CF_Spy_Invisible; @@ -37,6 +38,7 @@ void (float inp) TeamFortress_ChangeClass; void (entity p) TeamFortress_SetSkin; void (float timer) TeamFortress_SetDetpack; +void (float timer) TeamFortress_ToggleDetpack; void () TeamFortress_DetpackStop; void (float type, float amount) TeamFortress_DropAmmo; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index df4215d7..0ba3bee0 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -435,6 +435,14 @@ void () CF_Spy_AirThink = { self.nextthink = time + 0.1; }; +void (float issilent) FO_Spy_ToggleFeign = { + if (self.is_feigning || self.feign_next_damage) { + FO_Spy_Unfeign(); + } else { + FO_Spy_FeignOnNextDamage(); + } +} + void (float issilent) FO_Spy_Feign = { if (self.is_feigning) { return; @@ -548,7 +556,21 @@ void (float issilent) FO_Spy_Feign = { spy_diee1(); } +void () FO_Spy_FeignOnNextDamage = { + self.feign_next_damage = 1; + sprint(self, PRINT_HIGH, "Feigning on next damage...\n"); +} + void () FO_Spy_Unfeign = { + if (self.feign_next_damage) { + self.feign_next_damage = 0; + sprint(self, PRINT_HIGH, "Feign cancelled\n"); + } + + if (!self.is_feigning) { + return; + } + if (!self.is_button_feigning) { return; } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index dd162be3..d9313251 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -64,9 +64,11 @@ void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; void () TeamFortress_Discard_DropAmmo; +void (float issilent) FO_Spy_ToggleFeign; void () FO_Engineer_ToggleDispenser; void () FO_Engineer_ToggleSentry; float (float force) TeamFortress_DetonatePipebombs; +void (float timer) TeamFortress_ToggleDetpack; void (float timer) TeamFortress_SetDetpack; void () TeamFortress_DetpackStop; void (entity e) TeamFortress_PlacePracticeSpawn; @@ -3122,7 +3124,7 @@ void () ImpulseCommands = { } else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) CF_Spy_FeignDeath(0); else if ((self.impulse == TF_SPY_DIE_ON) && (self.playerclass == PC_SPY)) { - self.feign_next_damage = 1; + FO_Spy_FeignOnNextDamage(); } else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) CF_Spy_FeignDeath(1); else if (self.impulse == TF_DISGUISE_RESET && self.playerclass == PC_SPY) { @@ -3395,7 +3397,7 @@ void () ButtonFrame = { break; case PC_SPY: if (self.button3_keydown_frame) { - self.feign_next_damage = 1; + FO_Spy_ToggleFeign(0); } break; case PC_ENGINEER: @@ -3436,10 +3438,9 @@ void () ButtonFrame = { case PC_PYRO: break; case PC_SPY: - if (self.button3_keyup_frame) { - self.feign_next_damage = 0; + if (FO_GetUserSetting(self, "hold_feign", "hf", "off")) { + FO_Spy_Unfeign(); } - FO_Spy_Unfeign(); break; case PC_ENGINEER: break; @@ -3472,7 +3473,7 @@ void () ButtonFrame = { break; case PC_DEMOMAN: if (self.button4_keydown_frame) { - TeamFortress_SetDetpack(5); + TeamFortress_ToggleDetpack(5); } break; case PC_MEDIC: @@ -3514,7 +3515,9 @@ void () ButtonFrame = { break; case PC_DEMOMAN: if (self.button4_keyup_frame) { - TeamFortress_DetpackStop(); + if(FO_GetUserSetting(self, "hold_detpack", "hd", "off")) { + TeamFortress_DetpackStop(); + } } break; case PC_MEDIC: @@ -3535,6 +3538,7 @@ void () ButtonFrame = { self.button4_keyup_frame = 0; } + // +grenade1 if (self.button5) { if (!self.button5_keydown) { self.button5_keydown = 1; @@ -3542,19 +3546,31 @@ void () ButtonFrame = { } if (self.button5_keydown_frame) { - TeamFortress_PrimeThrowGrenade(1); - } + self.button5_keydown_frame = 0; - self.button5_keydown_frame = 0; + if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { + TeamFortress_PrimeGrenade(1); + } else { + TeamFortress_PrimeThrowGrenade(1); + } + } + // -grenade1 } else { if (self.button5_keydown) { self.button5_keydown = 0; self.button5_keyup_frame = 1; } - self.button5_keyup_frame = 0; + if (self.button5_keyup_frame) { + self.button5_keyup_frame = 0; + + if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { + TeamFortress_ThrowGrenade(1); + } + } } + // +grenade2 if (self.button6) { if (!self.button6_keydown) { self.button6_keydown = 1; @@ -3562,17 +3578,28 @@ void () ButtonFrame = { } if (self.button6_keydown_frame) { - TeamFortress_PrimeThrowGrenade(2); - } + self.button6_keydown_frame = 0; - self.button6_keydown_frame = 0; + if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { + TeamFortress_PrimeGrenade(2); + } else { + TeamFortress_PrimeThrowGrenade(2); + } + } } else { if (self.button6_keydown) { self.button6_keydown = 0; self.button6_keyup_frame = 1; } - self.button6_keyup_frame = 0; + if (self.button6_keyup_frame) { + self.button6_keyup_frame = 0; + + if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { + TeamFortress_ThrowGrenade(2); + } + } + } // +dropflag From 877480565122c2fe82f2134317b86322da25f6f5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Jul 2022 14:35:19 +1000 Subject: [PATCH 1537/2474] Convert ready stat into general flags stat, and fix broken logic --- csqc/main.qc | 2 +- share/defs.h | 4 +- ssqc/clan.qc | 105 +++++++++++++++++++++++++++--------------------- ssqc/client.qc | 6 ++- ssqc/qw.qc | 2 +- ssqc/tforttm.qc | 1 + ssqc/world.qc | 2 +- 7 files changed, 69 insertions(+), 53 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index dc451164..10508d10 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -113,7 +113,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (team_no == 0) is_observer = TRUE; player_class = getstatf(STAT_CLASS); - SBAR.ReadyStatus = getstatf(STAT_READY_STATUS); + SBAR.ReadyStatus = getstatf(STAT_FLAGS); oldhealth = getstatf(STAT_HEALTH); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) diff --git a/share/defs.h b/share/defs.h index 04b175a3..aa78906c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -229,7 +229,7 @@ #define AS_MELEE 3 #define AS_MISSILE 4 -// ready_status +// stat_flags #define PLAYER_READY 1 #define ENEMY_TEAM_READY 2 #define LAST_NOT_READY 4 @@ -1483,7 +1483,7 @@ // stats // first 32 are reserved #define STAT_TEAMNO 33 -#define STAT_READY_STATUS 34 +#define STAT_FLAGS 34 #define STAT_CLASS 35 #define STAT_VELOCITY_X 36 #define STAT_VELOCITY_Y 37 diff --git a/ssqc/clan.qc b/ssqc/clan.qc index c9ac5467..b7747bbf 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -370,7 +370,7 @@ void () ResetBreakAndReady = { te = find (world, classname, "player"); while (te != world) { te.bvote = 0; - te.ready_status &= ~PLAYER_READY; + te.stat_flags &= ~PLAYER_READY; UpdateReadyStatus(); v_break = 0; v_ready = 0; @@ -877,7 +877,7 @@ void () CenterPrint_Players_NotReady = { local float first = 0; te = find (world, classname, "player"); while (te) { - if (!(te.ready_status & PLAYER_READY) && !te.has_disconnected) + if (!(te.stat_flags & PLAYER_READY) && !te.has_disconnected) { first = first + 1; if (first == 1) @@ -916,7 +916,7 @@ void () Broadcast_Players_NotReady = { local float first = 1; te = find (world, classname, "player"); while (te != world) { - if (!(te.ready_status & PLAYER_READY) && !te.has_disconnected) { + if (!(te.stat_flags & PLAYER_READY) && !te.has_disconnected) { if (!first) players_not_ready = strcat(players_not_ready, ", "); else @@ -929,7 +929,7 @@ void () Broadcast_Players_NotReady = { bprint(1, players_not_ready); te = find (world, classname, "player"); while (te != world) { - if (!(te.ready_status & PLAYER_READY) && !te.has_disconnected) + if (!(te.stat_flags & PLAYER_READY) && !te.has_disconnected) sprint(te, 2, "If you are ready, type \s/ready\s in the console\n"); te = find(te, classname, "player"); } @@ -942,8 +942,8 @@ void () Broadcast_Players_NotReady = { } void () PlayerNotReady = { - if (self.ready_status & PLAYER_READY) { - self.ready_status &= ~PLAYER_READY; + if (self.stat_flags & PLAYER_READY) { + self.stat_flags &= ~PLAYER_READY; UpdateReadyStatus(); bprint2 (2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); @@ -952,68 +952,79 @@ void () PlayerNotReady = { } void () UpdateReadyStatus = { - local float players_size; - local float players_ready_size; - local float team_1_size; - local float team_1_ready_size; - local float team_2_size; - local float team_2_ready_size; - local float team_3_size; - local float team_3_ready_size; - local float team_4_size; - local float team_4_ready_size; + local float players_size = 0; + local float players_ready_size = 0; + local float team_1_size = 0; + local float team_1_ready_size = 0; + local float team_2_size = 0; + local float team_2_ready_size = 0; + local float team_3_size = 0; + local float team_3_ready_size = 0; + local float team_4_size = 0; + local float team_4_ready_size = 0; local entity p = find(world, classname, "player"); while (p != world) { - if (p.team_no) { - players_size++; - } - - if (p.ready_status & PLAYER_READY) { - players_ready_size++; - } - switch(p.team_no) { case 1: team_1_size++; - if (p.ready_status & PLAYER_READY) { + players_size++; + + if (p.stat_flags & PLAYER_READY) { team_1_ready_size++; + players_ready_size++; } + break; case 2: team_2_size++; - if (p.ready_status & PLAYER_READY) { + players_size++; + + if (p.stat_flags & PLAYER_READY) { team_2_ready_size++; + players_ready_size++; } + + break; case 3: team_3_size++; - if (p.ready_status & PLAYER_READY) { + players_size++; + + if (p.stat_flags & PLAYER_READY) { team_3_ready_size++; + players_ready_size++; } + break; case 4: team_4_size++; - if (p.ready_status & PLAYER_READY) { + players_size++; + + if (p.stat_flags & PLAYER_READY) { team_4_ready_size++; + players_ready_size++; } + break; } p = find(p, classname, "player"); } - local float team_1_ready = (team_1_size && (team_1_size - team_1_ready_size) == 0); - local float team_2_ready = (team_2_size && (team_2_size - team_2_ready_size) == 0); - local float team_3_ready = (team_3_size && (team_3_size - team_3_ready_size) == 0); - local float team_4_ready = (team_4_size && (team_4_size - team_4_ready_size) == 0); - local float teams_ready_size = team_1_ready + team_2_ready + team_3_ready + team_4_ready; - local float one_player_not_ready = (players_size > 1 && players_size - players_ready_size == 1); + local float team_1_ready = (team_1_size && (team_1_size == team_1_ready_size)); + local float team_2_ready = (team_2_size && (team_2_size == team_2_ready_size)); + local float team_3_ready = (team_3_size && (team_3_size == team_3_ready_size)); + local float team_4_ready = (team_4_size && (team_4_size == team_4_ready_size)); + local float teams_ready_size = (team_1_ready + team_2_ready + team_3_ready + team_4_ready); + local float one_player_not_ready = ((players_size > 1) && ((players_size - players_ready_size) == 1)); local entity p = find(world, classname, "player"); local float team_ready; while (p != world) { - // ENEMY_TEAM_READY + team_ready = 0; + + // Check if own team is ready switch(p.team_no) { case 1: if (team_1_ready) { @@ -1024,6 +1035,7 @@ void () UpdateReadyStatus = { if (team_2_ready) { team_ready = 1; } + break; case 3: if (team_3_ready) { team_ready = 1; @@ -1036,17 +1048,18 @@ void () UpdateReadyStatus = { break; } + // if at least one other team is ready if ((teams_ready_size - team_ready) > 0) { - p.ready_status |= ENEMY_TEAM_READY; + p.stat_flags |= ENEMY_TEAM_READY; } else { - p.ready_status &= ~ENEMY_TEAM_READY; + p.stat_flags &= ~ENEMY_TEAM_READY; } - // LAST_NOT_READY - if (!(p.ready_status & PLAYER_READY) && one_player_not_ready) { - p.ready_status |= LAST_NOT_READY; + // if you are the last to ready up + if (!(p.stat_flags & PLAYER_READY) && one_player_not_ready) { + p.stat_flags |= LAST_NOT_READY; } else { - p.ready_status &= ~LAST_NOT_READY; + p.stat_flags &= ~LAST_NOT_READY; } p = find(p, classname, "player"); @@ -1103,12 +1116,12 @@ void () PlayerReady = { return; } - if (self.ready_status & PLAYER_READY) { + if (self.stat_flags & PLAYER_READY) { PlayerNotReady(); return; } - self.ready_status |= PLAYER_READY; + self.stat_flags |= PLAYER_READY; UpdateReadyStatus(); v_ready = v_ready + 1; bprint2 (3, self.netname, " is ready to start the match\n"); @@ -1122,8 +1135,8 @@ void () RemoveVotes = { self.bvote = 0; v_break = (v_break - 1); } - if (self.ready_status & PLAYER_READY) { - self.ready_status &= ~PLAYER_READY; + if (self.stat_flags & PLAYER_READY) { + self.stat_flags &= ~PLAYER_READY; UpdateReadyStatus(); bprint2(2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); @@ -1138,7 +1151,7 @@ void () PreMatch_Message = { while (p != world) { if (p.netname != "") { sprint(p, PRINT_HIGH, "Currently in \sprematch\s time\n"); - if (p.ready_status & PLAYER_READY) + if (p.stat_flags & PLAYER_READY) sprint(p, PRINT_HIGH, "You are \sready\s to start the match.\n Type \s/notready\s in the console if you are not ready\n"); else sprint(p, PRINT_HIGH, "Type \s/ready\s in the console if you are ready to start the match\n"); diff --git a/ssqc/client.qc b/ssqc/client.qc index c901a45e..f66bb0f7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1886,7 +1886,7 @@ void (entity player) UpdateScoreboardInfo = { CheckSetInfoKey(player, "touches", player.touches); CheckSetInfoKey(player, "team_no", player.team_no); CheckSetInfoKey(player, "playerclass", player.playerclass); - CheckSetInfoKey(player, "ready", player.ready_status & PLAYER_READY); + CheckSetInfoKey(player, "ready", player.stat_flags & PLAYER_READY); }; void (float all_dimensions) SetDimensions = { @@ -2172,6 +2172,8 @@ void () PutClientInServer = { if (!(self.tf_items_flags & NIT_SCANNER_ENEMY)) self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY; } + + UpdateReadyStatus(); }; //void () info_player_start = { @@ -3059,7 +3061,7 @@ void () ClientDisconnect = { if(cb_prematch) { //Check in case the player leaving is the last not-readied player - if(self.ready_status & PLAYER_READY) { + if(self.stat_flags & PLAYER_READY) { v_ready = (v_ready - 1); } else if (!CheckAllPlayersReady()) { UpdateReadyStatus(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 5187e472..e5b55566 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -650,7 +650,7 @@ float autokick_kills; .float vote; .float bvote; -.float ready_status; +.float stat_flags; .float is_admin; .float admin_mode; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 93594462..6858f49a 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -289,6 +289,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options } forceinfokey(pe, "team_no", ftos(tno)); + UpdateReadyStatus(); return (1); }; diff --git a/ssqc/world.qc b/ssqc/world.qc index 50ca1eb1..1a27983a 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -327,7 +327,7 @@ void () worldspawn = { lightstyle(63, "a"); clientstat(STAT_TEAMNO, EV_FLOAT, team_no); - clientstat(STAT_READY_STATUS, EV_FLOAT, ready_status); + clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); From 03873f1d867df9942eab2b6a7c4a0b1285130794 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Jul 2022 15:13:57 +1000 Subject: [PATCH 1538/2474] Format ready status messages --- csqc/status.qc | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 1643bd2e..1342d2f0 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -534,10 +534,10 @@ void(string panelid, float display, string text) drawGameModePanel = { void(string panelid, float display, string text) drawReadyPanel = { FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); - + vector position = getPanelPosition(panel); vector size = getPanelFillSize(panel); - vector mediumtext = MENU_TEXT_SMALL * panel.Scale; + vector textsize = MENU_TEXT_SMALL * panel.Scale; vector textcolour = MENU_TEXT_4; local float padding = 4 * panel.Scale; local float lines; @@ -564,31 +564,31 @@ void(string panelid, float display, string text) drawReadyPanel = { string keynum = argv(0); if(SBAR.ReadyStatus & LAST_NOT_READY) { - local vector alert_text_largetext = mediumtext * 2; + local vector alert_text_size = MENU_TEXT_LARGE * panel.Scale; local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); - local string alert_text_message = "Everyone else is ready!"; + local string alert_text_message = "You're last"; pos_aligned = GetTextAlignOffset( alert_text_position.x, size.x, padding, alert_text_message, - alert_text_largetext.x, + alert_text_size.x, panel.Orientation ); drawstring( [pos_aligned, alert_text_position.y], - alert_text_message, - alert_text_largetext, - textcolour, - 1, + alert_text_message, + alert_text_size, + textcolour, + 1, 0 ); - position.y = alert_text_position.y + 48; + position.y = alert_text_position.y + alert_text_size.y + textsize.y; position.x = (ScreenSize.x / 2) - (size.x / 2); if(keynum != "-1") { @@ -597,7 +597,7 @@ void(string panelid, float display, string text) drawReadyPanel = { message = "Type 'ready' in the console to start"; } } else if (SBAR.ReadyStatus & ENEMY_TEAM_READY) { - local vector alert_text_largetext = mediumtext * 2; + local vector alert_text_size = MENU_TEXT_MEDIUM * panel.Scale; local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); @@ -608,20 +608,20 @@ void(string panelid, float display, string text) drawReadyPanel = { size.x, padding, alert_text_message, - alert_text_largetext.x, + alert_text_size.x, panel.Orientation ); drawstring( [pos_aligned, alert_text_position.y], - alert_text_message, - alert_text_largetext, - textcolour, - 1, + alert_text_message, + alert_text_size, + textcolour, + 1, 0 ); - position.y = alert_text_position.y + 48; + position.y = alert_text_position.y + alert_text_size.y + textsize.y; position.x = (ScreenSize.x / 2) - (size.x / 2); if(keynum != "-1") { @@ -640,13 +640,13 @@ void(string panelid, float display, string text) drawReadyPanel = { } } if(message) { - pos_aligned = GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.Orientation); + pos_aligned = GetTextAlignOffset(position.x,size.x,padding,message,textsize.x,panel.Orientation); drawstring( [pos_aligned, position.y], - message, - mediumtext, - textcolour, - 1, + message, + textsize, + textcolour, + 1, 0 ); } From 7a8dc7fd477d5d7d3669a84d51c80c24ed633022 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Jul 2022 23:41:12 +1000 Subject: [PATCH 1539/2474] No forced reloads option --- ssqc/client.qc | 3 +++ ssqc/hwguy.qc | 4 ++-- ssqc/player.qc | 4 ++-- ssqc/qw.qc | 1 + ssqc/weapons.qc | 36 ++++++++++++++++++++++++++++-------- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 819e3cf2..418e634b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -541,6 +541,9 @@ void () DecodeLevelParms = { airblastcells = CF_GetSetting("abc", "airblastcells", ftos(PC_PYRO_AIRBLAST_CELLS)); airblastjumpcells = CF_GetSetting("abjc", "airblastjumpcells", ftos(PC_PYRO_AIRBLASTJUMP_CELLS)); + // force reload [on] + force_reload = CF_GetSetting("fr", "forcereload", "on"); + // enable spy invisibility [off] invis_only = CF_GetSetting("s", "spyinvis", "off"); diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 772edd4a..bfa07b11 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -116,7 +116,7 @@ void FireAssCan (float shotcount, vector dir, vector spread) self.reload_assault_cannon = self.reload_assault_cannon + 1; Status_Refresh(self); CheckForReload(); - + vector bullet_dir, spread_dir, rand_dir, org; float bullet_speed, var_speed; @@ -125,7 +125,7 @@ void FireAssCan (float shotcount, vector dir, vector spread) // Infront of player model and down towards gun bullet_speed = PC_HVYWEAP_PROJSPEED; bullet_dir = normalize(v_forward * bullet_speed); - + while (shotcount > 0) { var_speed = crandom()*10 + bullet_speed; // Slight speed variance rand_dir = (crandom()*spread_x) * v_right + (crandom()*spread_y) * v_up; diff --git a/ssqc/player.qc b/ssqc/player.qc index 36d99fe6..2adf5b49 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -473,7 +473,7 @@ void () player_assaultcannonup2 =[103, player_assaultcannonup1] { void () player_assaultcannon1 =[103, player_assaultcannon2] { if (fo_hwguy) { - if (self.tfstate & TFSTATE_RELOADING) + if (self.tfstate & TFSTATE_RELOADING || self.reload_assault_cannon == PC_HVYWEAP_ASSCAN_CLIPSIZE) { self.count = 1; player_assaultcannondown1(); @@ -523,7 +523,7 @@ void () player_assaultcannon1 =[103, player_assaultcannon2] { void () player_assaultcannon2 =[104, player_assaultcannon1] { if (fo_hwguy) { - if (self.tfstate & TFSTATE_RELOADING) + if (self.tfstate & TFSTATE_RELOADING || self.reload_assault_cannon == PC_HVYWEAP_ASSCAN_CLIPSIZE) { self.count = 1; player_assaultcannondown1(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 26515761..81eee5eb 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -581,6 +581,7 @@ float airblastjump; float airblastsize; float airblastcells; float airblastjumpcells; +float force_reload; float old_spanner; float old_dispenser; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 51ab89e1..4383613f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -70,6 +70,7 @@ void () UseSpecialSkill; void () UseSpecialSkill2; void () RemoveFlare; void () ScannerSwitch; +float () CheckForReload; void (float all) TeamFortress_TeamShowScores; void (entity Player) TeamFortress_TeamShowMemberClasses; @@ -122,6 +123,7 @@ float () IsUsingOldImpulses; void (float inp) W_OldWeaponSlot; + void (entity ent, float num) SetFlameCount; void () W_Precache = { @@ -1788,7 +1790,7 @@ float () W_BestWeaponSlot = { void () W_ChangeToBestWeapon = { local float slot = W_BestWeaponSlot(); - + if (!IsUsingOldImpulses()) W_WeaponSlot(slot); else @@ -1898,34 +1900,52 @@ void () W_Reload_assault_cannon = { float () CheckForReload = { if (self.current_weapon == WEAP_SHOTGUN) { if (self.reload_shotgun >= 8 && self.ammo_shells > 0) { - TeamFortress_ReloadCurrentWeapon(); + if (force_reload) { + TeamFortress_ReloadCurrentWeapon(); + } + return 1; } } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) { - TeamFortress_ReloadCurrentWeapon(); + if (force_reload) { + TeamFortress_ReloadCurrentWeapon(); + } + return 1; } } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) { - TeamFortress_ReloadCurrentWeapon(); + if (force_reload) { + TeamFortress_ReloadCurrentWeapon(); + } + return 1; } } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) { - TeamFortress_ReloadCurrentWeapon(); + if (force_reload) { + TeamFortress_ReloadCurrentWeapon(); + } + return 1; } } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) { - TeamFortress_ReloadCurrentWeapon(); + if (force_reload) { + TeamFortress_ReloadCurrentWeapon(); + } + return 1; } } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { if (fo_hwguy) { if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > 0) { - TeamFortress_ReloadCurrentWeapon(); + if (force_reload) { + TeamFortress_ReloadCurrentWeapon(); + } + return 1; } } @@ -1993,7 +2013,7 @@ void () W_Attack = { if (self.tfstate & TFSTATE_RELOADING || self.is_detpacking) return; - + if(no_fire_mode) return; From 4bf2a47d1284355fb5728bdf5c3566347448182b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Jul 2022 23:42:30 +1000 Subject: [PATCH 1540/2474] Update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a5d99956..e55d0019 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ +* `localinfo forcereload 0/1` Option to prevent forced reloads. * `dlastspawn` Tells spy to disguise as enemy who last spawned. * `setinfo autodisguise 1` Causes spy to `dlastspawn` after spawning or cover blown. * `setinfo autodisguise 2` Causes spy to `dlast` after spawning or cover blown. From 37b4876d97915196be4d1e771cd6e3a14cfac764 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 2 Jul 2022 23:27:53 +1000 Subject: [PATCH 1541/2474] WIP button +slotx and +quickx, probably premature optimisation, simplify needed --- csqc/csextradefs.qc | 5 ++ csqc/main.qc | 117 ++++++++++++++++++++++++++++++++++++++++++++ share/defs.h | 1 + ssqc/qw.qc | 1 + ssqc/world.qc | 1 + 5 files changed, 125 insertions(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 086959bd..2c1cc843 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -64,6 +64,7 @@ vector TEXT_TEAM_COLOUR[] = { #define BUTTON5 16 #define BUTTON6 32 #define BUTTON7 64 +#define BUTTON8 128 #define MAP_MAX_CHARS 20 @@ -542,6 +543,10 @@ float nextoriginupdate; float speed; float jump_counter; float grentimer_waiting; +float current_weaponslot; +float last_weaponslot; +float quick_firing; +float slot; vector FO_Hud_Icon_Size = [24, 24, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index 12a37fc2..ad86be5b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,6 +14,8 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); void InterceptRocketJump(); float IsValidToUseGrenades(); +void InterceptSlotAttacks(); +void InterceptQuickAttack(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -68,6 +70,22 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); + registercommand("+slot1"); + registercommand("-slot1"); + registercommand("+slot2"); + registercommand("-slot2"); + registercommand("+slot3"); + registercommand("-slot3"); + registercommand("+slot4"); + registercommand("-slot4"); + registercommand("+quick1"); + registercommand("-quick1"); + registercommand("+quick2"); + registercommand("-quick2"); + registercommand("+quick3"); + registercommand("-quick3"); + registercommand("+quick4"); + registercommand("-quick4"); registercommand("tracktarget"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); @@ -99,6 +117,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_list_filter = ""; MouseDown = 0; jump_counter = 0; + quick_firing = 0; + slot = 0; }; noref void() CSQC_WorldLoaded = { @@ -115,6 +135,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { player_class = getstatf(STAT_CLASS); SBAR.Ready = getstatf(STAT_READY); SBAR.LastNotReady = getstatf(STAT_ONLY_ONE_NOT_READY); + current_weaponslot = getstatf(STAT_CURRENT_WEAPONSLOT); oldhealth = getstatf(STAT_HEALTH); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) @@ -350,6 +371,66 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("-button4\n"); } break; + case "+slot1": + slot = TF_SLOT1; + localcmd("+button0\n"); + break; + case "-slot1": + localcmd("-button0\n"); + break; + case "+slot2": + slot = TF_SLOT2; + localcmd("+button0\n"); + break; + case "-slot2": + localcmd("-button0\n"); + break; + case "+slot3": + slot = TF_SLOT3; + localcmd("+button0\n"); + break; + case "-slot3": + localcmd("-button0\n"); + break; + case "+slot4": + slot = TF_SLOT4; + localcmd("+button0\n"); + break; + case "-slot4": + localcmd("-button0\n"); + break; + case "+quick1": + quick_firing = 1; + slot = TF_SLOT1; + localcmd("+button0\n"); + break; + case "-quick1": + localcmd("-button0\n"); + break; + case "+quick2": + quick_firing = 1; + slot = TF_SLOT2; + localcmd("+button0\n"); + break; + case "-quick2": + localcmd("-button0\n"); + break; + case "+quick3": + quick_firing = 1; + slot = TF_SLOT3; + localcmd("+button0\n"); + break; + case "-quick3": + localcmd("-button0\n"); + break; + case "+quick4": + quick_firing = 1; + slot = TF_SLOT4; + localcmd("+button0\n"); + break; + case "-quick4": + localcmd("-button0\n"); + break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); break; @@ -382,6 +463,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { InterceptRocketJump(); + InterceptSlotAttacks(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -448,3 +530,38 @@ void InterceptRocketJump() { input_buttons |= BUTTON0 + BUTTON2; } } + +void InterceptSlotAttacks() { + if (slot && (input_buttons & BUTTON0)) { + if (current_weaponslot != slot) { + input_buttons &= ~BUTTON0; + localcmd("impulse ", ftos(slot), "\n"); + } else { + slot = 0; + } + } +} + +void InterceptQuickAttack() { + if (!quick_firing) { + return; + } + + if (input_buttons & BUTTON0) { + if (current_weaponslot != slot) { + last_weaponslot = current_weaponslot; + localcmd("impulse ", ftos(slot), "\n"); + print("unpressing button0\n"); + input_buttons &= ~BUTTON0; + return; + } + } else { + slot = 0; + + if (current_weaponslot != last_weaponslot) { + localcmd("impulse ", ftos(last_weaponslot), "\n"); + } else { + quick_firing = 0; + } + } +} diff --git a/share/defs.h b/share/defs.h index 990e2ef0..e2b33a42 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1490,6 +1490,7 @@ #define STAT_TP_GREN1 41 #define STAT_TP_GREN2 42 #define STAT_ONLY_ONE_NOT_READY 43 +#define STAT_CURRENT_WEAPONSLOT 44 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4abeba20..4ad97656 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -23,6 +23,7 @@ typedef void (float n) f_void_float; .float button5; // +grenade1 .float button6; // +grenade2 .float button7; // +dropflag +.float button8; .float hook_out; // Dummy field for hook to silence error messages .float got_aliases; // TRUE if the player has TeamFortress aliases diff --git a/ssqc/world.qc b/ssqc/world.qc index 746ba84c..adf5500e 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -335,6 +335,7 @@ void () worldspawn = { clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); clientstat(STAT_TP_GREN1, EV_FLOAT, tp_grenades_1); clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); + clientstat(STAT_CURRENT_WEAPONSLOT, EV_FLOAT, current_weaponslot); entity worldspawnent; worldspawnent = spawn(); From 6ed1e7d50e5c9284f65bf64ad3a214f3b2f56ed9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 3 Jul 2022 00:35:50 +1000 Subject: [PATCH 1542/2474] Add missing button constants, simplify slot attack --- csqc/csextradefs.qc | 8 ++++ csqc/main.qc | 96 +++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 56 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 2c1cc843..edd8ece7 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -65,6 +65,14 @@ vector TEXT_TEAM_COLOUR[] = { #define BUTTON6 32 #define BUTTON7 64 #define BUTTON8 128 +#define BUTTON9 2048 +#define BUTTON10 4096 +#define BUTTON11 8192 +#define BUTTON12 16384 +#define BUTTON13 32768 +#define BUTTON14 65536 +#define BUTTON15 131072 +#define BUTTON16 262144 #define MAP_MAX_CHARS 20 diff --git a/csqc/main.qc b/csqc/main.qc index ad86be5b..90044dfe 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,7 +14,7 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); void InterceptRocketJump(); float IsValidToUseGrenades(); -void InterceptSlotAttacks(); +void InterceptSlotAttack(float slot); void InterceptQuickAttack(); void GetSelf() = { @@ -135,7 +135,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { player_class = getstatf(STAT_CLASS); SBAR.Ready = getstatf(STAT_READY); SBAR.LastNotReady = getstatf(STAT_ONLY_ONE_NOT_READY); - current_weaponslot = getstatf(STAT_CURRENT_WEAPONSLOT); oldhealth = getstatf(STAT_HEALTH); is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) @@ -372,64 +371,28 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; case "+slot1": - slot = TF_SLOT1; - localcmd("+button0\n"); + localcmd("+button8\n"); break; case "-slot1": - localcmd("-button0\n"); + localcmd("-button8\n"); break; case "+slot2": - slot = TF_SLOT2; - localcmd("+button0\n"); + localcmd("+button9\n"); break; case "-slot2": - localcmd("-button0\n"); + localcmd("-button9\n"); break; case "+slot3": - slot = TF_SLOT3; - localcmd("+button0\n"); + localcmd("+button10\n"); break; case "-slot3": - localcmd("-button0\n"); + localcmd("-button10\n"); break; case "+slot4": - slot = TF_SLOT4; - localcmd("+button0\n"); + localcmd("+button11\n"); break; case "-slot4": - localcmd("-button0\n"); - break; - case "+quick1": - quick_firing = 1; - slot = TF_SLOT1; - localcmd("+button0\n"); - break; - case "-quick1": - localcmd("-button0\n"); - break; - case "+quick2": - quick_firing = 1; - slot = TF_SLOT2; - localcmd("+button0\n"); - break; - case "-quick2": - localcmd("-button0\n"); - break; - case "+quick3": - quick_firing = 1; - slot = TF_SLOT3; - localcmd("+button0\n"); - break; - case "-quick3": - localcmd("-button0\n"); - break; - case "+quick4": - quick_firing = 1; - slot = TF_SLOT4; - localcmd("+button0\n"); - break; - case "-quick4": - localcmd("-button0\n"); + localcmd("-button11\n"); break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); @@ -463,7 +426,19 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { InterceptRocketJump(); - InterceptSlotAttacks(); + + if (input_buttons & BUTTON8) { + InterceptSlotAttack(TF_SLOT1); + } + if (input_buttons & BUTTON9) { + InterceptSlotAttack(TF_SLOT2); + } + if (input_buttons & BUTTON10) { + InterceptSlotAttack(TF_SLOT3); + } + if (input_buttons & BUTTON11) { + InterceptSlotAttack(TF_SLOT4); + } } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -512,7 +487,7 @@ void InterceptRocketJump() { } // unpress +special2 - input_buttons = input_buttons & ~BUTTON4; + input_buttons &= ~BUTTON4; local float active_weapon = getstatf(STAT_ACTIVEWEAPON); local float rj_weapon = 32; @@ -531,17 +506,26 @@ void InterceptRocketJump() { } } -void InterceptSlotAttacks() { - if (slot && (input_buttons & BUTTON0)) { - if (current_weaponslot != slot) { - input_buttons &= ~BUTTON0; - localcmd("impulse ", ftos(slot), "\n"); - } else { - slot = 0; - } +void InterceptSlotAttack(float slot) { + if (getstatf(STAT_CURRENT_WEAPONSLOT) != slot) { + localcmd("impulse ", ftos(slot), "\n"); + input_buttons &= ~BUTTON0; + } else { + input_buttons |= BUTTON0; } } +/* void InterceptSlotAttacks() { */ +/* if (slot && (input_buttons & BUTTON0)) { */ +/* if (current_weaponslot != slot) { */ +/* input_buttons &= ~BUTTON0; */ +/* localcmd("impulse ", ftos(slot), "\n"); */ +/* } else { */ +/* slot = 0; */ +/* } */ +/* } */ +/* } */ + void InterceptQuickAttack() { if (!quick_firing) { return; From b918827631315dcf6b2a3dce84befd26a2373b3c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 8 Jul 2022 23:10:23 +1000 Subject: [PATCH 1543/2474] Allow throwgren in prematch without button --- ssqc/weapons.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fcbadda6..736f3eb1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3020,6 +3020,8 @@ void () ImpulseCommands = { TeamFortress_PrimeGrenade(1); else if (self.impulse == TF_GRENADE_2) TeamFortress_PrimeGrenade(2); + else if (self.impulse == TF_GRENADE_T) + TeamFortress_ThrowGrenade(); else if (self.impulse == TF_GRENADE_PT_1) TeamFortress_PrimeThrowGrenade(1); else if (self.impulse == TF_GRENADE_PT_2) From b093b44eefee6828bd4000eb5fadc3f83461d890 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 9 Jul 2022 13:06:21 +1000 Subject: [PATCH 1544/2474] WIP --- csqc/csextradefs.qc | 22 ---------- csqc/main.qc | 102 ++++++++++++++++++++++---------------------- share/commondefs.qc | 19 +++++++++ ssqc/client.qc | 7 +++ ssqc/commands.qc | 7 ++- ssqc/qw.qc | 10 ++++- ssqc/weapons.qc | 45 +++++++++++++++++++ 7 files changed, 137 insertions(+), 75 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index edd8ece7..3494c1de 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -56,24 +56,6 @@ vector TEXT_TEAM_COLOUR[] = { #define TEAM_SPECTATOR 9 #define TEAM_OBSERVER 99 -#define BUTTON0 1 -/* BUTTON1 not supported */ -#define BUTTON2 2 -#define BUTTON3 4 -#define BUTTON4 8 -#define BUTTON5 16 -#define BUTTON6 32 -#define BUTTON7 64 -#define BUTTON8 128 -#define BUTTON9 2048 -#define BUTTON10 4096 -#define BUTTON11 8192 -#define BUTTON12 16384 -#define BUTTON13 32768 -#define BUTTON14 65536 -#define BUTTON15 131072 -#define BUTTON16 262144 - #define MAP_MAX_CHARS 20 .float owned_by; @@ -552,10 +534,6 @@ float speed; float jump_counter; float grentimer_waiting; float current_weaponslot; -float last_weaponslot; -float quick_firing; -float slot; - vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index 90044dfe..1b98fc10 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,8 +14,7 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); void InterceptRocketJump(); float IsValidToUseGrenades(); -void InterceptSlotAttack(float slot); -void InterceptQuickAttack(); +void InterceptSlotAttacks(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -78,14 +77,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-slot3"); registercommand("+slot4"); registercommand("-slot4"); - registercommand("+quick1"); - registercommand("-quick1"); - registercommand("+quick2"); - registercommand("-quick2"); - registercommand("+quick3"); - registercommand("-quick3"); - registercommand("+quick4"); - registercommand("-quick4"); registercommand("tracktarget"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); @@ -117,8 +108,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_list_filter = ""; MouseDown = 0; jump_counter = 0; - quick_firing = 0; - slot = 0; }; noref void() CSQC_WorldLoaded = { @@ -426,19 +415,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { InterceptRocketJump(); - - if (input_buttons & BUTTON8) { - InterceptSlotAttack(TF_SLOT1); - } - if (input_buttons & BUTTON9) { - InterceptSlotAttack(TF_SLOT2); - } - if (input_buttons & BUTTON10) { - InterceptSlotAttack(TF_SLOT3); - } - if (input_buttons & BUTTON11) { - InterceptSlotAttack(TF_SLOT4); - } + InterceptSlotAttacks(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -506,15 +483,38 @@ void InterceptRocketJump() { } } -void InterceptSlotAttack(float slot) { - if (getstatf(STAT_CURRENT_WEAPONSLOT) != slot) { - localcmd("impulse ", ftos(slot), "\n"); - input_buttons &= ~BUTTON0; - } else { +void InterceptSlotAttacks() { + if (input_buttons & (BUTTON8 | BUTTON9 | BUTTON10 | BUTTON11)) { input_buttons |= BUTTON0; } } +/* void InterceptQuickAttack(float button, float slot) { */ +/* if (!(input_buttons & button) && !last_weaponslot) { */ +/* return; */ +/* } */ + +/* local float current_weaponslot = getstatf(STAT_CURRENT_WEAPONSLOT); */ + +/* if (input_buttons & button) { */ +/* if (current_weaponslot != slot) { */ +/* last_weaponslot = current_weaponslot; */ +/* localcmd("impulse ", ftos(slot), "\n"); */ +/* input_buttons &= ~BUTTON0; */ +/* } else { */ +/* input_buttons |= BUTTON0; */ +/* } */ +/* } else { */ +/* if (last_weaponslot) { */ +/* if (current_weaponslot == last_weaponslot) { */ +/* last_weaponslot = 0; */ +/* } else { */ +/* localcmd("impulse ", ftos(last_weaponslot), "\n"); */ +/* } */ +/* } */ +/* } */ +/* } */ + /* void InterceptSlotAttacks() { */ /* if (slot && (input_buttons & BUTTON0)) { */ /* if (current_weaponslot != slot) { */ @@ -526,26 +526,26 @@ void InterceptSlotAttack(float slot) { /* } */ /* } */ -void InterceptQuickAttack() { - if (!quick_firing) { - return; - } +/* void InterceptQuickAttack() { */ +/* if (!quick_firing) { */ +/* return; */ +/* } */ - if (input_buttons & BUTTON0) { - if (current_weaponslot != slot) { - last_weaponslot = current_weaponslot; - localcmd("impulse ", ftos(slot), "\n"); - print("unpressing button0\n"); - input_buttons &= ~BUTTON0; - return; - } - } else { - slot = 0; +/* if (input_buttons & BUTTON0) { */ +/* if (current_weaponslot != slot) { */ +/* last_weaponslot = current_weaponslot; */ +/* localcmd("impulse ", ftos(slot), "\n"); */ +/* print("unpressing button0\n"); */ +/* input_buttons &= ~BUTTON0; */ +/* return; */ +/* } */ +/* } else { */ +/* slot = 0; */ - if (current_weaponslot != last_weaponslot) { - localcmd("impulse ", ftos(last_weaponslot), "\n"); - } else { - quick_firing = 0; - } - } -} +/* if (current_weaponslot != last_weaponslot) { */ +/* localcmd("impulse ", ftos(last_weaponslot), "\n"); */ +/* } else { */ +/* quick_firing = 0; */ +/* } */ +/* } */ +/* } */ diff --git a/share/commondefs.qc b/share/commondefs.qc index b8a1a29c..8a9eb0a0 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -71,3 +71,22 @@ #define CLIENT_MENU_CAPTAIN_2 22 #define CLIENT_MENU_CAPTAIN_PICK 23 #define CLIENT_MENU_MAPS 24 + +#define BUTTON0 1 +/* BUTTON1 not supported */ +#define BUTTON2 2 +#define BUTTON3 4 +#define BUTTON4 8 +#define BUTTON5 16 +#define BUTTON6 32 +#define BUTTON7 64 +#define BUTTON8 128 +#define BUTTON9 2048 +#define BUTTON10 4096 +#define BUTTON11 8192 +#define BUTTON12 16384 +#define BUTTON13 32768 +#define BUTTON14 65536 +#define BUTTON15 131072 +#define BUTTON16 262144 + diff --git a/ssqc/client.qc b/ssqc/client.qc index 59f18280..933ad73e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -68,6 +68,13 @@ void () InitReverseCap; float () RejoinWithTfId; void () CreateTfIdAndJoin; entity (entity e)TeamFortress_GetPracticeSpawn; +void CSEv_SetPlayerImpulse_f(float n); + +void (float n) CSEv_SetPlayerImpulse_f = { + bprint(PRINT_HIGH, self.netname, "\n"); + bprint(PRINT_HIGH, "setting impulse ", ftos(n), "\n"); + self.impulse = n; +}; void () info_intermission = { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index c618e522..fae4b327 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -315,7 +315,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { local float farg3; local entity ent, pl; processedCmd = FALSE; - + if (arg1) arg_num = 1; if (arg2) @@ -323,6 +323,11 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { + case "impulse": + if (arg_num == 2) { + self.impulse = stof(arg2); + } + break; case "fo_settings_status": OutputTrackedSettings(); break; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4ad97656..58e9505a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -23,7 +23,15 @@ typedef void (float n) f_void_float; .float button5; // +grenade1 .float button6; // +grenade2 .float button7; // +dropflag -.float button8; +.float button8; // +slot1 +.float button9; // +slot2 +.float button10; // +slot3 +.float button11; // +slot4 +.float button12; // +quick1 +.float button13; // +quick2 +.float button14; // +quick3 +.float button15; // +quick4 +.float button16; // unused .float hook_out; // Dummy field for hook to silence error messages .float got_aliases; // TRUE if the player has TeamFortress aliases diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d9313251..f771b303 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -146,6 +146,7 @@ void (entity ent, float num) SetFlameCount; .float button6_keydown; .float button6_keydown_frame; .float button6_keyup_frame; +.float oldbuttons; void () W_Precache = { precache_sound("weapons/r_exp3.wav"); @@ -3363,6 +3364,28 @@ void () DeadImpulses = { }; void () ButtonFrame = { + local float changed_buttons = input_buttons ^ self.oldbuttons; + self.oldbuttons = input_buttons; + local float buttons_down = changed_buttons & input_buttons; + local float buttons_up = changed_buttons & ~input_buttons; + + if (buttons_down & BUTTON8) { + sprint(self, PRINT_MEDIUM, "Button 8 pressed\n"); + self.impulse = TF_SLOT1; + } + if (buttons_down & BUTTON9) { + sprint(self, PRINT_MEDIUM, "Button 9 pressed\n"); + self.impulse = TF_SLOT2; + } + if (buttons_down & BUTTON10) { + sprint(self, PRINT_MEDIUM, "Button 10 pressed\n"); + self.impulse = TF_SLOT3; + } + if (buttons_down & BUTTON11) { + sprint(self, PRINT_MEDIUM, "Button 11 pressed\n"); + self.impulse = TF_SLOT4; + } + // +special if (self.button3) { if (!self.button3_keydown) { @@ -3606,6 +3629,28 @@ void () ButtonFrame = { if (self.button7) { DropGoalItems(); } + +/* if (input_buttons & BUTTON8) { */ +/* if (changed_buttons & BUTTON8) { */ +/* self.last_weaponslot = self.current_weaponslot; */ +/* self.impulse = TF_SLOT1; */ +/* input_buttons |= BUTTON0; */ +/* } */ +/* } else { */ +/* if (changed_buttons & BUTTON8) { */ +/* sprint(self, PRINT_MEDIUM, "Button 8 unpressed\n"); */ +/* self.impulse = self.last_weaponslot; */ +/* } */ +/* } */ + +/* if (input_buttons & BUTTON9) {} */ +/* if (input_buttons & BUTTON10) {} */ +/* if (input_buttons & BUTTON11) {} */ +/* if (input_buttons & BUTTON12) {} */ +/* if (input_buttons & BUTTON13) {} */ +/* if (input_buttons & BUTTON14) {} */ +/* if (input_buttons & BUTTON15) {} */ +/* if (input_buttons & BUTTON16) {} */ } void () W_WeaponFrame = { From 71f9de3bd31cf2b3c5a1552e2d82312a76de221f Mon Sep 17 00:00:00 2001 From: fdittz Date: Tue, 12 Jul 2022 17:11:33 -0300 Subject: [PATCH 1545/2474] making medicts start with 3 concussion grenades, when not limited by localinfo max_gren2_medic --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index aa78906c..f0703542 100644 --- a/share/defs.h +++ b/share/defs.h @@ -996,7 +996,7 @@ #define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL /* #define PC_MEDIC_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_MEDIC_GRENADE_INIT_1 3 -#define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_GRENADE_INIT_2 3 #define PC_MEDIC_GRENADE_MAX_1 4 #define PC_MEDIC_GRENADE_MAX_2 3 #define PC_MEDIC_TF_ITEMS 0 From 1b1888964ba542b026d4548cd8ea23127a80e9d3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 15 Jul 2022 22:59:54 +1000 Subject: [PATCH 1546/2474] Simplify and fix slot attacks --- csqc/main.qc | 61 ------------------------------------------------- ssqc/weapons.qc | 4 ---- 2 files changed, 65 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1b98fc10..966dfa26 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -488,64 +488,3 @@ void InterceptSlotAttacks() { input_buttons |= BUTTON0; } } - -/* void InterceptQuickAttack(float button, float slot) { */ -/* if (!(input_buttons & button) && !last_weaponslot) { */ -/* return; */ -/* } */ - -/* local float current_weaponslot = getstatf(STAT_CURRENT_WEAPONSLOT); */ - -/* if (input_buttons & button) { */ -/* if (current_weaponslot != slot) { */ -/* last_weaponslot = current_weaponslot; */ -/* localcmd("impulse ", ftos(slot), "\n"); */ -/* input_buttons &= ~BUTTON0; */ -/* } else { */ -/* input_buttons |= BUTTON0; */ -/* } */ -/* } else { */ -/* if (last_weaponslot) { */ -/* if (current_weaponslot == last_weaponslot) { */ -/* last_weaponslot = 0; */ -/* } else { */ -/* localcmd("impulse ", ftos(last_weaponslot), "\n"); */ -/* } */ -/* } */ -/* } */ -/* } */ - -/* void InterceptSlotAttacks() { */ -/* if (slot && (input_buttons & BUTTON0)) { */ -/* if (current_weaponslot != slot) { */ -/* input_buttons &= ~BUTTON0; */ -/* localcmd("impulse ", ftos(slot), "\n"); */ -/* } else { */ -/* slot = 0; */ -/* } */ -/* } */ -/* } */ - -/* void InterceptQuickAttack() { */ -/* if (!quick_firing) { */ -/* return; */ -/* } */ - -/* if (input_buttons & BUTTON0) { */ -/* if (current_weaponslot != slot) { */ -/* last_weaponslot = current_weaponslot; */ -/* localcmd("impulse ", ftos(slot), "\n"); */ -/* print("unpressing button0\n"); */ -/* input_buttons &= ~BUTTON0; */ -/* return; */ -/* } */ -/* } else { */ -/* slot = 0; */ - -/* if (current_weaponslot != last_weaponslot) { */ -/* localcmd("impulse ", ftos(last_weaponslot), "\n"); */ -/* } else { */ -/* quick_firing = 0; */ -/* } */ -/* } */ -/* } */ diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f771b303..c1be76e5 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3370,19 +3370,15 @@ void () ButtonFrame = { local float buttons_up = changed_buttons & ~input_buttons; if (buttons_down & BUTTON8) { - sprint(self, PRINT_MEDIUM, "Button 8 pressed\n"); self.impulse = TF_SLOT1; } if (buttons_down & BUTTON9) { - sprint(self, PRINT_MEDIUM, "Button 9 pressed\n"); self.impulse = TF_SLOT2; } if (buttons_down & BUTTON10) { - sprint(self, PRINT_MEDIUM, "Button 10 pressed\n"); self.impulse = TF_SLOT3; } if (buttons_down & BUTTON11) { - sprint(self, PRINT_MEDIUM, "Button 11 pressed\n"); self.impulse = TF_SLOT4; } From 226ca0e721c43d6d54f1e56cbf57062cca52e3e9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 15 Jul 2022 23:55:52 +1000 Subject: [PATCH 1547/2474] Refactor --- csqc/main.qc | 41 +++++++++++------------------------------ ssqc/client.qc | 6 +++++- ssqc/weapons.qc | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 966dfa26..54576f7b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -349,16 +349,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-dropflag": localcmd("-button7\n"); break; - case "+rj": - if (player_class == PC_SOLDIER || player_class == PC_PYRO) { - localcmd("+button4\n"); - } - break; - case "-rj": - if (player_class == PC_SOLDIER || player_class == PC_PYRO) { - localcmd("-button4\n"); - } - break; case "+slot1": localcmd("+button8\n"); break; @@ -383,6 +373,16 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-slot4": localcmd("-button11\n"); break; + case "+rj": + if (player_class == PC_SOLDIER || player_class == PC_PYRO) { + localcmd("+button4\n"); + } + break; + case "-rj": + if (player_class == PC_SOLDIER || player_class == PC_PYRO) { + localcmd("-button4\n"); + } + break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); break; @@ -455,30 +455,11 @@ void StopGrenTimers() { } void InterceptRocketJump() { - if (!(input_buttons & BUTTON4)) { - return; - } - if (player_class != PC_SOLDIER && player_class != PC_PYRO) { return; } - // unpress +special2 - input_buttons &= ~BUTTON4; - - local float active_weapon = getstatf(STAT_ACTIVEWEAPON); - local float rj_weapon = 32; - - if (active_weapon != rj_weapon) { - if (getplayerkeyfloat(player_localnum, "old_weapon_impulses") || getplayerkeyfloat(player_localnum, "owi")) { - localcmd("impulse 7\n"); - } else if (player_class = PC_PYRO && getplayerkeyfloat(player_localnum, "cf_pyro_impulses")) { - localcmd("impulse 2\n"); - } else { - localcmd("impulse 1\n"); - } - } else { - // press +jump and +attack + if (input_buttons & BUTTON4) { input_buttons |= BUTTON0 + BUTTON2; } } diff --git a/ssqc/client.qc b/ssqc/client.qc index 933ad73e..71d1c045 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -189,7 +189,7 @@ float (entity ent, string ps_short, string ps_setting, string ps_default) FO_Get return TRUE; case "off": return FALSE; - default: + default: return stof(st); } }; @@ -3668,6 +3668,10 @@ float () IsUsingOldImpulses = { return ((infokey(self, "old_weapon_impulses") == "1") || (infokey(self, "owi") == "1")); } +float () IsUsingCFImpulses = { + return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); +} + float () GetLastWeaponImpulse = { if (IsUsingOldImpulses()) return 7; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index c1be76e5..b88429ca 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -129,6 +129,7 @@ void () ToggleInvincibility; float () GetLastWeaponImpulse; float () IsUsingOldImpulses; +float () IsUsingCFImpulses; void (float inp) W_OldWeaponSlot; @@ -3372,12 +3373,15 @@ void () ButtonFrame = { if (buttons_down & BUTTON8) { self.impulse = TF_SLOT1; } + if (buttons_down & BUTTON9) { self.impulse = TF_SLOT2; } + if (buttons_down & BUTTON10) { self.impulse = TF_SLOT3; } + if (buttons_down & BUTTON11) { self.impulse = TF_SLOT4; } @@ -3488,6 +3492,11 @@ void () ButtonFrame = { case PC_SNIPER: break; case PC_SOLDIER: + if (IsUsingOldImpulses()) { + self.impulse = 7; + } else { + self.impulse = TF_SLOT1; + } // Intercepted by InterceptRocketJump() break; case PC_DEMOMAN: @@ -3500,6 +3509,13 @@ void () ButtonFrame = { case PC_HVYWEAP: break; case PC_PYRO: + if (IsUsingOldImpulses()) { + self.impulse = 7; + } else if (IsUsingCFImpulses()) { + self.impulse = TF_SLOT2; + } else { + self.impulse = TF_SLOT1; + } // Intercepted by InterceptRocketJump() break; case PC_SPY: From 2841f432622cb641cbfc1f14a11307abeb1fc268 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 16 Jul 2022 01:53:42 +1000 Subject: [PATCH 1548/2474] Refactor --- ssqc/weapons.qc | 272 +++++++++++++++++------------------------------- 1 file changed, 94 insertions(+), 178 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index b88429ca..f0f849bc 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3367,212 +3367,133 @@ void () DeadImpulses = { void () ButtonFrame = { local float changed_buttons = input_buttons ^ self.oldbuttons; self.oldbuttons = input_buttons; - local float buttons_down = changed_buttons & input_buttons; - local float buttons_up = changed_buttons & ~input_buttons; - if (buttons_down & BUTTON8) { - self.impulse = TF_SLOT1; - } - - if (buttons_down & BUTTON9) { - self.impulse = TF_SLOT2; - } - - if (buttons_down & BUTTON10) { - self.impulse = TF_SLOT3; - } - - if (buttons_down & BUTTON11) { - self.impulse = TF_SLOT4; - } - - // +special - if (self.button3) { - if (!self.button3_keydown) { - self.button3_keydown = 1; - self.button3_keydown_frame = 1; - } + local float keydowns = changed_buttons & input_buttons; + local float keyups = changed_buttons & ~input_buttons; + // +special every frame + if (input_buttons & BUTTON3) { if (!cb_prematch && !cease_fire) { switch (self.playerclass) { case PC_SCOUT: CF_Scout_Dash(); break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; case PC_DEMOMAN: TeamFortress_DetonatePipebombs(0); break; - case PC_MEDIC: - if (self.button3_keydown_frame) { - CF_Medic_AuraToggle(); - } - break; - case PC_HVYWEAP: - if (self.button3_keydown_frame) { - FO_LockToggle(); - } - break; case PC_PYRO: FO_Airblast(); break; - case PC_SPY: - if (self.button3_keydown_frame) { - FO_Spy_ToggleFeign(0); - } - break; - case PC_ENGINEER: - if (self.button3_keydown_frame) { - FO_Engineer_ToggleDispenser(); - } - break; - case PC_UNDEFINED: - break; - } - } else { - if (self.button3_keydown_frame) { - ToggleInvincibility(); } } + } - self.button3_keydown_frame = 0; - } else { - if (self.button3_keydown) { - self.button3_keydown = 0; - self.button3_keyup_frame = 1; + // -special every frame + if (!(input_buttons & BUTTON3)) { + if (FO_GetUserSetting(self, "hold_feign", "hf", "off")) { + FO_Spy_Unfeign(); } + } - if (!cb_prematch && !cease_fire) { + // +special keydown frame + if (keydowns & BUTTON3) { + if (cb_prematch || cease_fire) { + ToggleInvincibility(); + } else { switch (self.playerclass) { - case PC_SCOUT: - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; - case PC_DEMOMAN: - break; case PC_MEDIC: + CF_Medic_AuraToggle(); break; case PC_HVYWEAP: - break; - case PC_PYRO: + FO_LockToggle(); break; case PC_SPY: - if (FO_GetUserSetting(self, "hold_feign", "hf", "off")) { - FO_Spy_Unfeign(); - } + FO_Spy_ToggleFeign(0); break; case PC_ENGINEER: - break; - case PC_UNDEFINED: + FO_Engineer_ToggleDispenser(); break; } } - - self.button3_keyup_frame = 0; } - // +special2 - if (self.button4) { - if (!self.button4_keydown) { - self.button4_keydown = 1; - self.button4_keydown_frame = 1; + // +special2 every frame + if (input_buttons & BUTTON4) { + switch (self.playerclass) { + case PC_SOLDIER: + if (IsUsingOldImpulses()) { + self.impulse = 7; + } else { + self.impulse = TF_SLOT1; + } + // Intercepted by InterceptRocketJump() + break; + case PC_PYRO: + if (IsUsingOldImpulses()) { + self.impulse = 7; + } else if (IsUsingCFImpulses()) { + self.impulse = TF_SLOT2; + } else { + self.impulse = TF_SLOT1; + } + // Intercepted by InterceptRocketJump() + break; } + } + + // -special2 every frame + // if (!(input_buttons & BUTTON4)) { } + // +special2 keydown frame + if (keydowns & BUTTON4) { if (!cb_prematch && !cease_fire) { switch (self.playerclass) { case PC_SCOUT: - if (self.button4_keydown_frame) { - ScannerSwitch(); - } - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - if (IsUsingOldImpulses()) { - self.impulse = 7; - } else { - self.impulse = TF_SLOT1; - } - // Intercepted by InterceptRocketJump() + ScannerSwitch(); break; case PC_DEMOMAN: - if (self.button4_keydown_frame) { - TeamFortress_ToggleDetpack(5); - } - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - if (IsUsingOldImpulses()) { - self.impulse = 7; - } else if (IsUsingCFImpulses()) { - self.impulse = TF_SLOT2; - } else { - self.impulse = TF_SLOT1; - } - // Intercepted by InterceptRocketJump() + TeamFortress_ToggleDetpack(5); break; case PC_SPY: - if (self.button4_keydown_frame) { - FO_Spy_DisguiseLastSpawned(self); - } + FO_Spy_DisguiseLastSpawned(self); break; case PC_ENGINEER: - if (self.button4_keydown_frame) { - FO_Engineer_ToggleSentry(); - } - break; - case PC_UNDEFINED: + FO_Engineer_ToggleSentry(); break; } } + } - self.button4_keydown_frame = 0; - } else { // -special2 - if (self.button4_keydown) { - self.button4_keydown = 0; - self.button4_keyup_frame = 1; + // +special2 keyup frame + if (keyups & BUTTON4) { + switch (self.playerclass) { + case PC_DEMOMAN: + if(FO_GetUserSetting(self, "hold_detpack", "hd", "off")) { + TeamFortress_DetpackStop(); + } + break; } + } - if (!cb_prematch && !cease_fire) { - switch (self.playerclass) { - case PC_SCOUT: - break; - case PC_SNIPER: - break; - case PC_SOLDIER: - break; - case PC_DEMOMAN: - if (self.button4_keyup_frame) { - if(FO_GetUserSetting(self, "hold_detpack", "hd", "off")) { - TeamFortress_DetpackStop(); - } - } - break; - case PC_MEDIC: - break; - case PC_HVYWEAP: - break; - case PC_PYRO: - break; - case PC_SPY: - break; - case PC_ENGINEER: - break; - case PC_UNDEFINED: - break; - } - } - self.button4_keyup_frame = 0; + /* + // +special2 every frame + if (input_buttons & BUTTON4) { + } + + // -special2 every frame + if (!(input_buttons & BUTTON4)) { + } + + // +special2 keydown frame + if (keydowns & BUTTON4) { } + // +special2 keyup frame + if (keyups & BUTTON4) { + } + */ + // +grenade1 if (self.button5) { if (!self.button5_keydown) { @@ -3589,7 +3510,7 @@ void () ButtonFrame = { TeamFortress_PrimeThrowGrenade(1); } } - // -grenade1 + // -grenade1 } else { if (self.button5_keydown) { self.button5_keydown = 0; @@ -3638,31 +3559,26 @@ void () ButtonFrame = { } // +dropflag - if (self.button7) { + if (input_buttons & BUTTON7) { DropGoalItems(); } -/* if (input_buttons & BUTTON8) { */ -/* if (changed_buttons & BUTTON8) { */ -/* self.last_weaponslot = self.current_weaponslot; */ -/* self.impulse = TF_SLOT1; */ -/* input_buttons |= BUTTON0; */ -/* } */ -/* } else { */ -/* if (changed_buttons & BUTTON8) { */ -/* sprint(self, PRINT_MEDIUM, "Button 8 unpressed\n"); */ -/* self.impulse = self.last_weaponslot; */ -/* } */ -/* } */ - -/* if (input_buttons & BUTTON9) {} */ -/* if (input_buttons & BUTTON10) {} */ -/* if (input_buttons & BUTTON11) {} */ -/* if (input_buttons & BUTTON12) {} */ -/* if (input_buttons & BUTTON13) {} */ -/* if (input_buttons & BUTTON14) {} */ -/* if (input_buttons & BUTTON15) {} */ -/* if (input_buttons & BUTTON16) {} */ + if (keydowns & BUTTON8) { + self.impulse = TF_SLOT1; + } + + if (keydowns & BUTTON9) { + self.impulse = TF_SLOT2; + } + + if (keydowns & BUTTON10) { + self.impulse = TF_SLOT3; + } + + if (keydowns & BUTTON11) { + self.impulse = TF_SLOT4; + } + } void () W_WeaponFrame = { From 259bbd28d332fbfdf7bffb3e0f1cc48ca0ee09a9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 16 Jul 2022 21:20:58 +1000 Subject: [PATCH 1549/2474] Refactor --- ssqc/weapons.qc | 105 +++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 77 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f0f849bc..785a7a27 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3441,9 +3441,6 @@ void () ButtonFrame = { } } - // -special2 every frame - // if (!(input_buttons & BUTTON4)) { } - // +special2 keydown frame if (keydowns & BUTTON4) { if (!cb_prematch && !cease_fire) { @@ -3475,110 +3472,64 @@ void () ButtonFrame = { } } + local float hold_grens = FO_GetUserSetting(self, "hold_grens", "hg", "off"); - /* - // +special2 every frame - if (input_buttons & BUTTON4) { - } - - // -special2 every frame - if (!(input_buttons & BUTTON4)) { - } - - // +special2 keydown frame - if (keydowns & BUTTON4) { - } - - // +special2 keyup frame - if (keyups & BUTTON4) { - } - */ - - // +grenade1 - if (self.button5) { - if (!self.button5_keydown) { - self.button5_keydown = 1; - self.button5_keydown_frame = 1; - } - - if (self.button5_keydown_frame) { - self.button5_keydown_frame = 0; - - if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { - TeamFortress_PrimeGrenade(1); - } else { - TeamFortress_PrimeThrowGrenade(1); - } - } - // -grenade1 - } else { - if (self.button5_keydown) { - self.button5_keydown = 0; - self.button5_keyup_frame = 1; - } - - if (self.button5_keyup_frame) { - self.button5_keyup_frame = 0; - - if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { - TeamFortress_ThrowGrenade(1); - } + // +grenade1 keydown frame + if (keydowns & BUTTON5) { + if (hold_grens) { + TeamFortress_PrimeGrenade(1); + } else { + TeamFortress_PrimeThrowGrenade(1); } } - // +grenade2 - if (self.button6) { - if (!self.button6_keydown) { - self.button6_keydown = 1; - self.button6_keydown_frame = 1; + // +grenade1 keyup frame + if (keyups & BUTTON5) { + if (hold_grens) { + TeamFortress_ThrowGrenade(1); } + } - if (self.button6_keydown_frame) { - self.button6_keydown_frame = 0; - - if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { - TeamFortress_PrimeGrenade(2); - } else { - TeamFortress_PrimeThrowGrenade(2); - } - } - } else { - if (self.button6_keydown) { - self.button6_keydown = 0; - self.button6_keyup_frame = 1; + // +grenade2 keydown frame + if (keydowns & BUTTON6) { + if (hold_grens) { + TeamFortress_PrimeGrenade(2); + } else { + TeamFortress_PrimeThrowGrenade(2); } + } - if (self.button6_keyup_frame) { - self.button6_keyup_frame = 0; - - if (FO_GetUserSetting(self, "hold_grens", "hg", "off")) { - TeamFortress_ThrowGrenade(2); - } + // +grenade2 keyup frame + if (keyups & BUTTON6) { + if (hold_grens) { + TeamFortress_ThrowGrenade(2); } - } - // +dropflag + // +dropflag every frame if (input_buttons & BUTTON7) { DropGoalItems(); } + // +slot1 keydown frame if (keydowns & BUTTON8) { self.impulse = TF_SLOT1; } + // +slot2 keydown frame if (keydowns & BUTTON9) { self.impulse = TF_SLOT2; } + // +slot3 keydown frame if (keydowns & BUTTON10) { self.impulse = TF_SLOT3; } + // +slot4 keydown frame if (keydowns & BUTTON11) { self.impulse = TF_SLOT4; } - } void () W_WeaponFrame = { From 4bf4969fc8535f9f591826ab52462dc4176ed761 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 16 Jul 2022 22:22:17 +1000 Subject: [PATCH 1550/2474] Fix slot and quick attacks, don't force when csqc is active --- csqc/main.qc | 56 +++++++++++++++++++++++++++++++++++++++++------- ssqc/qw.qc | 15 ------------- ssqc/tforthlp.qc | 22 +++++++++++-------- ssqc/weapons.qc | 49 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 105 insertions(+), 37 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 54576f7b..bcf1e103 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,6 +14,7 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); void InterceptRocketJump(); float IsValidToUseGrenades(); +void InterceptQuickAttacks(); void InterceptSlotAttacks(); void GetSelf() = { @@ -69,6 +70,14 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); + registercommand("+quick1"); + registercommand("-quick1"); + registercommand("+quick2"); + registercommand("-quick2"); + registercommand("+quick3"); + registercommand("-quick3"); + registercommand("+quick4"); + registercommand("-quick4"); registercommand("+slot1"); registercommand("-slot1"); registercommand("+slot2"); @@ -352,27 +361,51 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "+slot1": localcmd("+button8\n"); break; - case "-slot1": + case "-quick1": localcmd("-button8\n"); break; - case "+slot2": + case "+quick2": localcmd("+button9\n"); break; - case "-slot2": + case "-quick2": localcmd("-button9\n"); break; - case "+slot3": + case "+quick3": localcmd("+button10\n"); break; - case "-slot3": + case "-quick3": localcmd("-button10\n"); break; - case "+slot4": + case "+quick4": localcmd("+button11\n"); break; - case "-slot4": + case "-quick4": localcmd("-button11\n"); break; + case "+slot1": + localcmd("+button12\n"); + break; + case "-slot1": + localcmd("-button12\n"); + break; + case "+slot2": + localcmd("+button13\n"); + break; + case "-slot2": + localcmd("-button13\n"); + break; + case "+slot3": + localcmd("+button14\n"); + break; + case "-slot3": + localcmd("-button14\n"); + break; + case "+slot4": + localcmd("+button15\n"); + break; + case "-slot4": + localcmd("-button15\n"); + break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { localcmd("+button4\n"); @@ -416,6 +449,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { InterceptRocketJump(); InterceptSlotAttacks(); + InterceptQuickAttacks(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -464,8 +498,14 @@ void InterceptRocketJump() { } } -void InterceptSlotAttacks() { +void InterceptQuickAttacks() { if (input_buttons & (BUTTON8 | BUTTON9 | BUTTON10 | BUTTON11)) { input_buttons |= BUTTON0; } } + +void InterceptSlotAttacks() { + if (input_buttons & (BUTTON12 | BUTTON13 | BUTTON14 | BUTTON15)) { + input_buttons |= BUTTON0; + } +} diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 58e9505a..94678c08 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -18,21 +18,6 @@ typedef void (float n) f_void_float; .float tp_grenades_1; // 1st type of grenades being carried .float tp_grenades_2; // 2nd type of grenades being carried .float tp_grenade_switch; // Set to 1 if +gren1 and +gren2 switch places -.float button3; // +special -.float button4; // +special2 -.float button5; // +grenade1 -.float button6; // +grenade2 -.float button7; // +dropflag -.float button8; // +slot1 -.float button9; // +slot2 -.float button10; // +slot3 -.float button11; // +slot4 -.float button12; // +quick1 -.float button13; // +quick2 -.float button14; // +quick3 -.float button15; // +quick4 -.float button16; // unused - .float hook_out; // Dummy field for hook to silence error messages .float got_aliases; // TRUE if the player has TeamFortress aliases .float cheat_check; // Time when we'll next check for team cheats diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 55459db6..f3b662b0 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -89,14 +89,16 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("slot2", TF_SLOT2, 0); TeamFortress_Alias("slot3", TF_SLOT3, 0); TeamFortress_Alias("slot4", TF_SLOT4, 0); - TeamFortress_AliasString("+slot1", "impulse 20;+attack"); - TeamFortress_AliasString("-slot1", "-attack;impulse 24"); - TeamFortress_AliasString("+slot2", "impulse 21;+attack"); - TeamFortress_AliasString("-slot2", "-attack;impulse 24"); - TeamFortress_AliasString("+slot3", "impulse 22;+attack"); - TeamFortress_AliasString("-slot3", "-attack;impulse 24"); - TeamFortress_AliasString("+slot4", "impulse 23;+attack"); - TeamFortress_AliasString("-slot4", "-attack;impulse 24"); + if (!csqcactive) { + TeamFortress_AliasString("+slot1", "impulse 20;+attack"); + TeamFortress_AliasString("-slot1", "-attack;impulse 24"); + TeamFortress_AliasString("+slot2", "impulse 21;+attack"); + TeamFortress_AliasString("-slot2", "-attack;impulse 24"); + TeamFortress_AliasString("+slot3", "impulse 22;+attack"); + TeamFortress_AliasString("-slot3", "-attack;impulse 24"); + TeamFortress_AliasString("+slot4", "impulse 23;+attack"); + TeamFortress_AliasString("-slot4", "-attack;impulse 24"); + } } else if (self.motd == 30) { if(csqcactive) { TeamFortress_AliasString("changeteam", "fo_menu_team"); @@ -263,7 +265,9 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("fo_settings_status", "cmd fo_settings_status"); TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); TeamFortress_Alias("removepracspawn", TF_PRACSPAWN_REMOVE, 0); - Quick_Aliases(); + if (!csqcactive) { + Quick_Aliases(); + } } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) Menu_Login(); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 785a7a27..082d7e1c 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3511,29 +3511,68 @@ void () ButtonFrame = { DropGoalItems(); } - // +slot1 keydown frame + // +quick1 keydown frame if (keydowns & BUTTON8) { self.impulse = TF_SLOT1; } - // +slot2 keydown frame + // +quick2 keydown frame if (keydowns & BUTTON9) { self.impulse = TF_SLOT2; } - // +slot3 keydown frame + // +quick3 keydown frame if (keydowns & BUTTON10) { self.impulse = TF_SLOT3; } - // +slot4 keydown frame + // +quick4 keydown frame if (keydowns & BUTTON11) { self.impulse = TF_SLOT4; } + + // +slot1 keydown frame + if (keydowns & BUTTON12) { + self.impulse = TF_SLOT1; + } + + // +slot1 keyup frame + if (keyups & BUTTON12) { + self.impulse = TF_WEAPLAST; + } + + // +slot2 keydown frame + if (keydowns & BUTTON13) { + self.impulse = TF_SLOT2; + } + + // +slot2 keyup frame + if (keyups & BUTTON13) { + self.impulse = TF_WEAPLAST; + } + + // +slot3 keydown frame + if (keydowns & BUTTON14) { + self.impulse = TF_SLOT3; + } + + // +slot3 keyup frame + if (keyups & BUTTON14) { + self.impulse = TF_WEAPLAST; + } + + // +slot4 keydown frame + if (keydowns & BUTTON15) { + self.impulse = TF_SLOT4; + } + + // +slot4 keyup frame + if (keyups & BUTTON15) { + self.impulse = TF_WEAPLAST; + } } void () W_WeaponFrame = { - if (self.login_in_progress) { CenterPrint(self, "Trying to log in..."); } From 436b00b914e7458a12ebcd1074f38ea640af3b0e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 17 Jul 2022 23:11:22 +1000 Subject: [PATCH 1551/2474] Improved by still slightly broken quickfire --- README.md | 2 +- csqc/main.qc | 48 ++++++++++++++++++++-------------------- ssqc/qw.qc | 1 + ssqc/weapons.qc | 59 ++++++++++++++++++++++++++++++++++--------------- 4 files changed, 67 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index df4dc986..92ff5534 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ New features * Grenade slot switching (/grenswitch). * Prime/throw grenades with one button (/gren1 and /gren2). * Weapon slots (1-4) where 1 is always primary and 4 is always melee. -* Quick attack aliases (+quick1-4 will switch weapon and fire. +slot1-4 will do the same and switch back). +* Quick attack aliases (+slot1-4 will switch weapon and fire. +quick1-4 will do the same and switch back). * Next/previous weapon (/weapprev and /weapnext). * Last weapon (/weaplast). * Remember current weapon and last weapon after dying. diff --git a/csqc/main.qc b/csqc/main.qc index bcf1e103..91a0ba5b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,8 +14,8 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); void InterceptRocketJump(); float IsValidToUseGrenades(); -void InterceptQuickAttacks(); void InterceptSlotAttacks(); +void InterceptQuickAttacks(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -70,14 +70,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); - registercommand("+quick1"); - registercommand("-quick1"); - registercommand("+quick2"); - registercommand("-quick2"); - registercommand("+quick3"); - registercommand("-quick3"); - registercommand("+quick4"); - registercommand("-quick4"); registercommand("+slot1"); registercommand("-slot1"); registercommand("+slot2"); @@ -86,6 +78,14 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-slot3"); registercommand("+slot4"); registercommand("-slot4"); + registercommand("+quick1"); + registercommand("-quick1"); + registercommand("+quick2"); + registercommand("-quick2"); + registercommand("+quick3"); + registercommand("-quick3"); + registercommand("+quick4"); + registercommand("-quick4"); registercommand("tracktarget"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); @@ -361,49 +361,49 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "+slot1": localcmd("+button8\n"); break; - case "-quick1": + case "-slot1": localcmd("-button8\n"); break; - case "+quick2": + case "+slot2": localcmd("+button9\n"); break; - case "-quick2": + case "-slot2": localcmd("-button9\n"); break; - case "+quick3": + case "+slot3": localcmd("+button10\n"); break; - case "-quick3": + case "-slot3": localcmd("-button10\n"); break; - case "+quick4": + case "+slot4": localcmd("+button11\n"); break; - case "-quick4": + case "-slot4": localcmd("-button11\n"); break; - case "+slot1": + case "+quick1": localcmd("+button12\n"); break; - case "-slot1": + case "-quick1": localcmd("-button12\n"); break; - case "+slot2": + case "+quick2": localcmd("+button13\n"); break; - case "-slot2": + case "-quick2": localcmd("-button13\n"); break; - case "+slot3": + case "+quick3": localcmd("+button14\n"); break; - case "-slot3": + case "-quick3": localcmd("-button14\n"); break; - case "+slot4": + case "+quick4": localcmd("+button15\n"); break; - case "-slot4": + case "-quick4": localcmd("-button15\n"); break; case "+rj": diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 94678c08..d9df366a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -80,6 +80,7 @@ typedef void (float n) f_void_float; .float building_percentage; // The building percentage shown in status bar .float fragstreak; // Frag streak .float caps; // Caps during this game +.float quickfireprevweap; // Weapon to select at completion on +quick* attack .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types .float tfstate; // State flags for TeamFortress diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 082d7e1c..2d349850 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3511,64 +3511,87 @@ void () ButtonFrame = { DropGoalItems(); } - // +quick1 keydown frame + // +slot1 keydown frame if (keydowns & BUTTON8) { self.impulse = TF_SLOT1; } - // +quick2 keydown frame + // +slot2 keydown frame if (keydowns & BUTTON9) { self.impulse = TF_SLOT2; } - // +quick3 keydown frame + // +slot3 keydown frame if (keydowns & BUTTON10) { self.impulse = TF_SLOT3; } - // +quick4 keydown frame + // +slot4 keydown frame if (keydowns & BUTTON11) { self.impulse = TF_SLOT4; } - // +slot1 keydown frame + // +quick1 keydown frame if (keydowns & BUTTON12) { + if (!self.quickfireprevweap) { + self.quickfireprevweap = self.current_weaponslot; + } self.impulse = TF_SLOT1; } - // +slot1 keyup frame + // +quick1 keyup frame if (keyups & BUTTON12) { - self.impulse = TF_WEAPLAST; + if (!(input_buttons & BUTTON0)) { + self.impulse = self.quickfireprevweap; + self.quickfireprevweap = 0; + } } - // +slot2 keydown frame + // +quick2 keydown frame if (keydowns & BUTTON13) { + if (!self.quickfireprevweap) { + self.quickfireprevweap = self.current_weaponslot; + } self.impulse = TF_SLOT2; } - // +slot2 keyup frame + // +quick2 keyup frame if (keyups & BUTTON13) { - self.impulse = TF_WEAPLAST; + if (!(input_buttons & BUTTON0)) { + self.impulse = self.quickfireprevweap; + self.quickfireprevweap = 0; + } } - // +slot3 keydown frame + // +quick3 keydown frame if (keydowns & BUTTON14) { + if (!self.quickfireprevweap) { + self.quickfireprevweap = self.current_weaponslot; + } self.impulse = TF_SLOT3; } - // +slot3 keyup frame + // +quick3 keyup frame if (keyups & BUTTON14) { - self.impulse = TF_WEAPLAST; + if (!(input_buttons & BUTTON0)) { + self.impulse = self.quickfireprevweap; + self.quickfireprevweap = 0; + } } - // +slot4 keydown frame + // +quick4 keydown frame if (keydowns & BUTTON15) { + if (!self.quickfireprevweap) { + self.quickfireprevweap = self.current_weaponslot; + } self.impulse = TF_SLOT4; } - // +slot4 keyup frame + // +quick4 keyup frame if (keyups & BUTTON15) { - self.impulse = TF_WEAPLAST; + if (!self.quickfireprevweap) { + self.quickfireprevweap = self.current_weaponslot; + } } } @@ -3671,6 +3694,7 @@ void () W_WeaponFrame = { // +slot1-4 quick fire } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && !self.is_detpacking) { + sprint(self, PRINT_MEDIUM, "Line 3655 in weapons.qc\n"); self.is_quickfiring = 1; self.has_quickfired = 0; @@ -3685,8 +3709,7 @@ void () W_WeaponFrame = { W_ChangeWeapon(3); else if (self.impulse == TF_QUICKSLOT4) W_ChangeWeapon(4); - } - else { + } else { if (self.impulse == TF_QUICKSLOT1) W_ChangeWeapon(W_OldImpulseFromNewSlot(1)); else if (self.impulse == TF_QUICKSLOT2) From 8c48ae0fd8a367a00b1ac855314c59238255554e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 20 Jul 2022 00:55:08 +1000 Subject: [PATCH 1552/2474] Support default weapon --- csqc/main.qc | 2 +- share/defs.h | 8 ++++---- ssqc/client.qc | 23 +++++++++++++++++++++++ ssqc/qw.qc | 3 +++ ssqc/weapons.qc | 48 +++++++++++++++++++----------------------------- 5 files changed, 50 insertions(+), 34 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 91a0ba5b..7fb11845 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -116,7 +116,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { current_vote = world; vote_list_filter = ""; MouseDown = 0; - jump_counter = 0; }; noref void() CSQC_WorldLoaded = { @@ -504,6 +503,7 @@ void InterceptQuickAttacks() { } } + void InterceptSlotAttacks() { if (input_buttons & (BUTTON12 | BUTTON13 | BUTTON14 | BUTTON15)) { input_buttons |= BUTTON0; diff --git a/share/defs.h b/share/defs.h index e2b33a42..e99cdb99 100644 --- a/share/defs.h +++ b/share/defs.h @@ -372,10 +372,10 @@ #define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) #define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) #define TF_CLASSMENU 5 // Brings up class menu -// unused 6 -// unused 7 -// unused 8 -// unused 9 +#define TF_BUTTONSLOT1 6 +#define TF_BUTTONSLOT2 7 +#define TF_BUTTONSLOT3 8 +#define TF_BUTTONSLOT4 9 // unused 10 #define TF_WEAPNEXT 11 // Selects the next weapon slot #define TF_WEAPPREV 12 // Selects the previous weapon slot diff --git a/ssqc/client.qc b/ssqc/client.qc index 71d1c045..2f9add30 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2856,6 +2856,29 @@ void () PlayerPostThink = { } else { CheckPowerups(); ButtonFrame(); + + if ((self.impulse >= TF_SLOT1 && self.impulse <= TF_SLOT4) + || self.impulse == TF_WEAPNEXT + || self.impulse == TF_WEAPPREV + || self.impulse == TF_WEAPLAST ) { + self.select_default_weapon = 0; + } else { + switch (self.impulse) { + case TF_BUTTONSLOT1: + self.impulse = TF_SLOT1; + break; + case TF_BUTTONSLOT2: + self.impulse = TF_SLOT2; + break; + case TF_BUTTONSLOT3: + self.impulse = TF_SLOT3; + break; + case TF_BUTTONSLOT4: + self.impulse = TF_SLOT4; + break; + } + } + W_WeaponFrame(); if (self.motd <= 400) { TeamFortress_MOTD(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d9df366a..0cd5266d 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -81,6 +81,9 @@ typedef void (float n) f_void_float; .float fragstreak; // Frag streak .float caps; // Caps during this game .float quickfireprevweap; // Weapon to select at completion on +quick* attack +.float select_default_weapon; // Set after weapon changing commands to prevent default weapon being selected +.float default_weapon; // Weapon to select when not firing + .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types .float tfstate; // State flags for TeamFortress diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2d349850..0065f0cf 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2018,10 +2018,12 @@ void () W_Attack = { if (self.tfstate & TFSTATE_RELOADING || self.is_detpacking) return; - + if(no_fire_mode) return; + self.select_default_weapon = 1; + if ((self.is_undercover || (self.undercover_team != 0)) || (self.undercover_skin != 0)) Spy_RemoveDisguise(self); @@ -3014,6 +3016,7 @@ void () ImpulseCommands = { self.impulse = 0; return; } + if (self.impulse == TF_SPECIAL_SKILL) UseSpecialSkill(); @@ -3513,84 +3516,71 @@ void () ButtonFrame = { // +slot1 keydown frame if (keydowns & BUTTON8) { - self.impulse = TF_SLOT1; + self.impulse = TF_BUTTONSLOT1; } // +slot2 keydown frame if (keydowns & BUTTON9) { - self.impulse = TF_SLOT2; + self.impulse = TF_BUTTONSLOT2; } // +slot3 keydown frame if (keydowns & BUTTON10) { - self.impulse = TF_SLOT3; + self.impulse = TF_BUTTONSLOT3; } // +slot4 keydown frame if (keydowns & BUTTON11) { - self.impulse = TF_SLOT4; + self.impulse = TF_BUTTONSLOT4; } // +quick1 keydown frame if (keydowns & BUTTON12) { - if (!self.quickfireprevweap) { - self.quickfireprevweap = self.current_weaponslot; - } - self.impulse = TF_SLOT1; + self.impulse = TF_BUTTONSLOT1; } + local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "1"); + // +quick1 keyup frame if (keyups & BUTTON12) { if (!(input_buttons & BUTTON0)) { - self.impulse = self.quickfireprevweap; - self.quickfireprevweap = 0; + self.impulse = default_weapon; } } // +quick2 keydown frame if (keydowns & BUTTON13) { - if (!self.quickfireprevweap) { - self.quickfireprevweap = self.current_weaponslot; - } - self.impulse = TF_SLOT2; + self.impulse = TF_BUTTONSLOT2; } // +quick2 keyup frame if (keyups & BUTTON13) { if (!(input_buttons & BUTTON0)) { - self.impulse = self.quickfireprevweap; - self.quickfireprevweap = 0; + self.impulse = default_weapon; } } // +quick3 keydown frame if (keydowns & BUTTON14) { - if (!self.quickfireprevweap) { - self.quickfireprevweap = self.current_weaponslot; - } - self.impulse = TF_SLOT3; + self.impulse = TF_BUTTONSLOT3; } // +quick3 keyup frame if (keyups & BUTTON14) { if (!(input_buttons & BUTTON0)) { - self.impulse = self.quickfireprevweap; - self.quickfireprevweap = 0; + self.impulse = default_weapon; } } // +quick4 keydown frame if (keydowns & BUTTON15) { - if (!self.quickfireprevweap) { - self.quickfireprevweap = self.current_weaponslot; - } - self.impulse = TF_SLOT4; + self.impulse = TF_BUTTONSLOT4; } // +quick4 keyup frame if (keyups & BUTTON15) { - if (!self.quickfireprevweap) { - self.quickfireprevweap = self.current_weaponslot; + if (!(input_buttons & BUTTON0)) { + self.impulse = default_weapon; } } } From 39f5b03fa838584b572bb0d4495045cd853d6916 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 20 Jul 2022 02:00:27 +1000 Subject: [PATCH 1553/2474] Add default_weapon setinfo --- README.md | 3 +- csqc/csextradefs.qc | 1 - csqc/main.qc | 57 +++++---------------------------- share/defs.h | 9 +++--- ssqc/client.qc | 23 -------------- ssqc/qw.qc | 2 -- ssqc/tforthlp.qc | 21 +++++++------ ssqc/weapons.qc | 77 ++++++++++----------------------------------- ssqc/world.qc | 1 - 9 files changed, 42 insertions(+), 152 deletions(-) diff --git a/README.md b/README.md index 92ff5534..d4e9e873 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,8 @@ New features * Grenade slot switching (/grenswitch). * Prime/throw grenades with one button (/gren1 and /gren2). * Weapon slots (1-4) where 1 is always primary and 4 is always melee. -* Quick attack aliases (+slot1-4 will switch weapon and fire. +quick1-4 will do the same and switch back). +* Quick attack aliases (+quick1-4 will switch weapon and fire). +* Set default weapon to select after firing (e.g. `setinfo default_weapon 1`). * Next/previous weapon (/weapprev and /weapnext). * Last weapon (/weaplast). * Remember current weapon and last weapon after dying. diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3494c1de..4e450665 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -533,7 +533,6 @@ float nextoriginupdate; float speed; float jump_counter; float grentimer_waiting; -float current_weaponslot; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index 7fb11845..2e5ffc41 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,7 +14,6 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); void InterceptRocketJump(); float IsValidToUseGrenades(); -void InterceptSlotAttacks(); void InterceptQuickAttacks(); void GetSelf() = { @@ -70,14 +69,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); - registercommand("+slot1"); - registercommand("-slot1"); - registercommand("+slot2"); - registercommand("-slot2"); - registercommand("+slot3"); - registercommand("-slot3"); - registercommand("+slot4"); - registercommand("-slot4"); registercommand("+quick1"); registercommand("-quick1"); registercommand("+quick2"); @@ -357,53 +348,29 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-dropflag": localcmd("-button7\n"); break; - case "+slot1": - localcmd("+button8\n"); - break; - case "-slot1": - localcmd("-button8\n"); - break; - case "+slot2": - localcmd("+button9\n"); - break; - case "-slot2": - localcmd("-button9\n"); - break; - case "+slot3": - localcmd("+button10\n"); - break; - case "-slot3": - localcmd("-button10\n"); - break; - case "+slot4": - localcmd("+button11\n"); - break; - case "-slot4": - localcmd("-button11\n"); - break; case "+quick1": - localcmd("+button12\n"); + localcmd("+button8\n"); break; case "-quick1": - localcmd("-button12\n"); + localcmd("-button8\n"); break; case "+quick2": - localcmd("+button13\n"); + localcmd("+button9\n"); break; case "-quick2": - localcmd("-button13\n"); + localcmd("-button9\n"); break; case "+quick3": - localcmd("+button14\n"); + localcmd("+button10\n"); break; case "-quick3": - localcmd("-button14\n"); + localcmd("-button10\n"); break; case "+quick4": - localcmd("+button15\n"); + localcmd("+button11\n"); break; case "-quick4": - localcmd("-button15\n"); + localcmd("-button11\n"); break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { @@ -447,7 +414,6 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { InterceptRocketJump(); - InterceptSlotAttacks(); InterceptQuickAttacks(); } @@ -502,10 +468,3 @@ void InterceptQuickAttacks() { input_buttons |= BUTTON0; } } - - -void InterceptSlotAttacks() { - if (input_buttons & (BUTTON12 | BUTTON13 | BUTTON14 | BUTTON15)) { - input_buttons |= BUTTON0; - } -} diff --git a/share/defs.h b/share/defs.h index e99cdb99..990e2ef0 100644 --- a/share/defs.h +++ b/share/defs.h @@ -372,10 +372,10 @@ #define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) #define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) #define TF_CLASSMENU 5 // Brings up class menu -#define TF_BUTTONSLOT1 6 -#define TF_BUTTONSLOT2 7 -#define TF_BUTTONSLOT3 8 -#define TF_BUTTONSLOT4 9 +// unused 6 +// unused 7 +// unused 8 +// unused 9 // unused 10 #define TF_WEAPNEXT 11 // Selects the next weapon slot #define TF_WEAPPREV 12 // Selects the previous weapon slot @@ -1490,7 +1490,6 @@ #define STAT_TP_GREN1 41 #define STAT_TP_GREN2 42 #define STAT_ONLY_ONE_NOT_READY 43 -#define STAT_CURRENT_WEAPONSLOT 44 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/client.qc b/ssqc/client.qc index 2f9add30..71d1c045 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2856,29 +2856,6 @@ void () PlayerPostThink = { } else { CheckPowerups(); ButtonFrame(); - - if ((self.impulse >= TF_SLOT1 && self.impulse <= TF_SLOT4) - || self.impulse == TF_WEAPNEXT - || self.impulse == TF_WEAPPREV - || self.impulse == TF_WEAPLAST ) { - self.select_default_weapon = 0; - } else { - switch (self.impulse) { - case TF_BUTTONSLOT1: - self.impulse = TF_SLOT1; - break; - case TF_BUTTONSLOT2: - self.impulse = TF_SLOT2; - break; - case TF_BUTTONSLOT3: - self.impulse = TF_SLOT3; - break; - case TF_BUTTONSLOT4: - self.impulse = TF_SLOT4; - break; - } - } - W_WeaponFrame(); if (self.motd <= 400) { TeamFortress_MOTD(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 0cd5266d..b9e6c547 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -80,8 +80,6 @@ typedef void (float n) f_void_float; .float building_percentage; // The building percentage shown in status bar .float fragstreak; // Frag streak .float caps; // Caps during this game -.float quickfireprevweap; // Weapon to select at completion on +quick* attack -.float select_default_weapon; // Set after weapon changing commands to prevent default weapon being selected .float default_weapon; // Weapon to select when not firing .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index f3b662b0..b82d645d 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -89,16 +89,17 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("slot2", TF_SLOT2, 0); TeamFortress_Alias("slot3", TF_SLOT3, 0); TeamFortress_Alias("slot4", TF_SLOT4, 0); - if (!csqcactive) { - TeamFortress_AliasString("+slot1", "impulse 20;+attack"); - TeamFortress_AliasString("-slot1", "-attack;impulse 24"); - TeamFortress_AliasString("+slot2", "impulse 21;+attack"); - TeamFortress_AliasString("-slot2", "-attack;impulse 24"); - TeamFortress_AliasString("+slot3", "impulse 22;+attack"); - TeamFortress_AliasString("-slot3", "-attack;impulse 24"); - TeamFortress_AliasString("+slot4", "impulse 23;+attack"); - TeamFortress_AliasString("-slot4", "-attack;impulse 24"); - } + + // you shouldn't use these in fte, use setinfo default_weapon and +quick instead + // leaving in to prevent breaking change + TeamFortress_AliasString("+slot1", "impulse 20;+attack"); + TeamFortress_AliasString("-slot1", "-attack;impulse 24"); + TeamFortress_AliasString("+slot2", "impulse 21;+attack"); + TeamFortress_AliasString("-slot2", "-attack;impulse 24"); + TeamFortress_AliasString("+slot3", "impulse 22;+attack"); + TeamFortress_AliasString("-slot3", "-attack;impulse 24"); + TeamFortress_AliasString("+slot4", "impulse 23;+attack"); + TeamFortress_AliasString("-slot4", "-attack;impulse 24"); } else if (self.motd == 30) { if(csqcactive) { TeamFortress_AliasString("changeteam", "fo_menu_team"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 0065f0cf..1e67fcce 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2022,8 +2022,6 @@ void () W_Attack = { if(no_fire_mode) return; - self.select_default_weapon = 1; - if ((self.is_undercover || (self.undercover_team != 0)) || (self.undercover_skin != 0)) Spy_RemoveDisguise(self); @@ -3374,6 +3372,15 @@ void () ButtonFrame = { local float keydowns = changed_buttons & input_buttons; local float keyups = changed_buttons & ~input_buttons; + // +attack keyup + if (keyups & BUTTON0) { + local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); + + if (default_weapon >= 1 && default_weapon <= 4) { + self.impulse = default_weapon; + } + } + // +special every frame if (input_buttons & BUTTON3) { if (!cb_prematch && !cease_fire) { @@ -3514,74 +3521,24 @@ void () ButtonFrame = { DropGoalItems(); } - // +slot1 keydown frame - if (keydowns & BUTTON8) { - self.impulse = TF_BUTTONSLOT1; - } - - // +slot2 keydown frame - if (keydowns & BUTTON9) { - self.impulse = TF_BUTTONSLOT2; - } - - // +slot3 keydown frame - if (keydowns & BUTTON10) { - self.impulse = TF_BUTTONSLOT3; - } - - // +slot4 keydown frame - if (keydowns & BUTTON11) { - self.impulse = TF_BUTTONSLOT4; - } - // +quick1 keydown frame - if (keydowns & BUTTON12) { - self.impulse = TF_BUTTONSLOT1; - } - - local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "1"); - - // +quick1 keyup frame - if (keyups & BUTTON12) { - if (!(input_buttons & BUTTON0)) { - self.impulse = default_weapon; - } + if (keydowns & BUTTON8) { + self.impulse = TF_SLOT1; } // +quick2 keydown frame - if (keydowns & BUTTON13) { - self.impulse = TF_BUTTONSLOT2; - } - - // +quick2 keyup frame - if (keyups & BUTTON13) { - if (!(input_buttons & BUTTON0)) { - self.impulse = default_weapon; - } + if (keydowns & BUTTON9) { + self.impulse = TF_SLOT2; } // +quick3 keydown frame - if (keydowns & BUTTON14) { - self.impulse = TF_BUTTONSLOT3; - } - - // +quick3 keyup frame - if (keyups & BUTTON14) { - if (!(input_buttons & BUTTON0)) { - self.impulse = default_weapon; - } + if (keydowns & BUTTON10) { + self.impulse = TF_SLOT3; } // +quick4 keydown frame - if (keydowns & BUTTON15) { - self.impulse = TF_BUTTONSLOT4; - } - - // +quick4 keyup frame - if (keyups & BUTTON15) { - if (!(input_buttons & BUTTON0)) { - self.impulse = default_weapon; - } + if (keydowns & BUTTON11) { + self.impulse = TF_SLOT4; } } diff --git a/ssqc/world.qc b/ssqc/world.qc index adf5500e..746ba84c 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -335,7 +335,6 @@ void () worldspawn = { clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); clientstat(STAT_TP_GREN1, EV_FLOAT, tp_grenades_1); clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); - clientstat(STAT_CURRENT_WEAPONSLOT, EV_FLOAT, current_weaponslot); entity worldspawnent; worldspawnent = spawn(); From fce833e8186a7320b29d60fe1860779bfc47bf64 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 21 Jul 2022 22:02:43 +1000 Subject: [PATCH 1554/2474] Remove debug statement --- ssqc/weapons.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5560a47e..ae0828b1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3661,8 +3661,6 @@ void () W_WeaponFrame = { // +slot1-4 quick fire } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && !self.is_detpacking) { - sprint(self, PRINT_MEDIUM, "Line 3655 in weapons.qc\n"); - self.is_quickfiring = 1; self.has_quickfired = 0; From 8581a1a371ffdba6c1628a1db57b4abea820781e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 21 Jul 2022 22:20:47 +1000 Subject: [PATCH 1555/2474] Comment out the buttonification of +quick commands until Spike fixes _pext_vrinputs 1 --- csqc/main.qc | 76 ++++++++++++++++++++++----------------------- share/commondefs.qc | 16 +++++----- ssqc/tforthlp.qc | 5 ++- ssqc/weapons.qc | 38 +++++++++++------------ 4 files changed, 67 insertions(+), 68 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 2e5ffc41..b7626ac7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -69,14 +69,14 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); - registercommand("+quick1"); - registercommand("-quick1"); - registercommand("+quick2"); - registercommand("-quick2"); - registercommand("+quick3"); - registercommand("-quick3"); - registercommand("+quick4"); - registercommand("-quick4"); + // registercommand("+quick1"); + // registercommand("-quick1"); + // registercommand("+quick2"); + // registercommand("-quick2"); + // registercommand("+quick3"); + // registercommand("-quick3"); + // registercommand("+quick4"); + // registercommand("-quick4"); registercommand("tracktarget"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); @@ -348,30 +348,30 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-dropflag": localcmd("-button7\n"); break; - case "+quick1": - localcmd("+button8\n"); - break; - case "-quick1": - localcmd("-button8\n"); - break; - case "+quick2": - localcmd("+button9\n"); - break; - case "-quick2": - localcmd("-button9\n"); - break; - case "+quick3": - localcmd("+button10\n"); - break; - case "-quick3": - localcmd("-button10\n"); - break; - case "+quick4": - localcmd("+button11\n"); - break; - case "-quick4": - localcmd("-button11\n"); - break; + // case "+quick1": + // localcmd("+button8\n"); + // break; + // case "-quick1": + // localcmd("-button8\n"); + // break; + // case "+quick2": + // localcmd("+button9\n"); + // break; + // case "-quick2": + // localcmd("-button9\n"); + // break; + // case "+quick3": + // localcmd("+button10\n"); + // break; + // case "-quick3": + // localcmd("-button10\n"); + // break; + // case "+quick4": + // localcmd("+button11\n"); + // break; + // case "-quick4": + // localcmd("-button11\n"); + // break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { localcmd("+button4\n"); @@ -414,7 +414,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and noref void CSQC_Input_Frame() { InterceptRocketJump(); - InterceptQuickAttacks(); + // InterceptQuickAttacks(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -463,8 +463,8 @@ void InterceptRocketJump() { } } -void InterceptQuickAttacks() { - if (input_buttons & (BUTTON8 | BUTTON9 | BUTTON10 | BUTTON11)) { - input_buttons |= BUTTON0; - } -} +// void InterceptQuickAttacks() { +// if (input_buttons & (BUTTON8 | BUTTON9 | BUTTON10 | BUTTON11)) { +// input_buttons |= BUTTON0; +// } +// } diff --git a/share/commondefs.qc b/share/commondefs.qc index 8a9eb0a0..71bd23ff 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -81,12 +81,12 @@ #define BUTTON6 32 #define BUTTON7 64 #define BUTTON8 128 -#define BUTTON9 2048 -#define BUTTON10 4096 -#define BUTTON11 8192 -#define BUTTON12 16384 -#define BUTTON13 32768 -#define BUTTON14 65536 -#define BUTTON15 131072 -#define BUTTON16 262144 +// #define BUTTON9 2048 +// #define BUTTON10 4096 +// #define BUTTON11 8192 +// #define BUTTON12 16384 +// #define BUTTON13 32768 +// #define BUTTON14 65536 +// #define BUTTON15 131072 +// #define BUTTON16 262144 diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index b82d645d..3be9685e 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -266,9 +266,8 @@ void () TeamFortress_MOTD = { TeamFortress_AliasString("fo_settings_status", "cmd fo_settings_status"); TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); TeamFortress_Alias("removepracspawn", TF_PRACSPAWN_REMOVE, 0); - if (!csqcactive) { - Quick_Aliases(); - } + } else if (self.motd == 140) { + Quick_Aliases(); } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { if (loginRequired && !self.login) Menu_Login(); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ae0828b1..b5dc4d82 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3541,25 +3541,25 @@ void () ButtonFrame = { DropGoalItems(); } - // +quick1 keydown frame - if (keydowns & BUTTON8) { - self.impulse = TF_SLOT1; - } - - // +quick2 keydown frame - if (keydowns & BUTTON9) { - self.impulse = TF_SLOT2; - } - - // +quick3 keydown frame - if (keydowns & BUTTON10) { - self.impulse = TF_SLOT3; - } - - // +quick4 keydown frame - if (keydowns & BUTTON11) { - self.impulse = TF_SLOT4; - } + // // +quick1 keydown frame + // if (keydowns & BUTTON8) { + // self.impulse = TF_SLOT1; + // } + + // // +quick2 keydown frame + // if (keydowns & BUTTON9) { + // self.impulse = TF_SLOT2; + // } + + // // +quick3 keydown frame + // if (keydowns & BUTTON10) { + // self.impulse = TF_SLOT3; + // } + + // // +quick4 keydown frame + // if (keydowns & BUTTON11) { + // self.impulse = TF_SLOT4; + // } } void () W_WeaponFrame = { From 938c8ff35ca443adcd5e5210689eb59df35680fe Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 21 Jul 2022 23:56:51 +1000 Subject: [PATCH 1556/2474] Restore default weapon after reloading --- ssqc/actions.qc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index b80388d2..024e3bde 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -477,8 +477,17 @@ void (entity pe_player, float f_type) CF_Identify = { } }; +void () RestoreDefaultWeapon = { + local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); + if (default_weapon >= 1 && default_weapon <= 4) { + W_ChangeWeapon(default_weapon); + } +}; + void TeamFortress_ReloadWeapon(float weap) { + RestoreDefaultWeapon(); + local float reloadtime = 0; local float reloadamount = 0; local entity tWeapon, tClip; @@ -858,6 +867,7 @@ void () TeamFortress_ReloadNext = { } if (!reload) + RestoreDefaultWeapon(); sprint(self, PRINT_HIGH, "All clips full\n"); }; From 7cc6bd8c0bbb0eece72f28513468aa4015868c1b Mon Sep 17 00:00:00 2001 From: fdittz Date: Mon, 1 Aug 2022 10:37:43 -0300 Subject: [PATCH 1557/2474] making medicts start with 3 concussion grenades, when not limited by localinfo max_gren2_medic --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 03dc548d..351f83f8 100644 --- a/share/defs.h +++ b/share/defs.h @@ -993,7 +993,7 @@ #define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL /* #define PC_MEDIC_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_MEDIC_GRENADE_INIT_1 3 -#define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_GRENADE_INIT_2 3 #define PC_MEDIC_GRENADE_MAX_1 4 #define PC_MEDIC_GRENADE_MAX_2 3 #define PC_MEDIC_TF_ITEMS 0 From be583905a343cad7cb5e647988e88656006acc67 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 3 Aug 2022 15:11:30 +1000 Subject: [PATCH 1558/2474] Client side jump and land sounds --- csqc/csdefs.qc | 1 + csqc/csextradefs.qc | 3 ++- csqc/main.qc | 18 +++++++++++++++++- ssqc/client.qc | 14 +++++++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 87c3be3d..b86c4fa4 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -54,6 +54,7 @@ float input_buttons; float input_impulse; void end_sys_globals; float pmove_onground; +vector pmove_vel; .float modelindex; .vector absmin; .vector absmax; diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 4e450665..cf4ebe6b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -89,7 +89,6 @@ float round_time_remaining; float showingscores; float mapvote_expiry; float cs_grenprimed; -float frames_since_onground; float num_mapvotes; float num_mapvotes_filtered; entity vote_selected_item; @@ -519,6 +518,7 @@ enum { #define FOCMD_GRENTIMERVOLUME "fo_grentimervolume" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" #define FOCMD_FTE_HUD "fo_fte_hud" +#define FOCMD_JUMPSOUND "player/plyrjmp8" float team_no; float is_spectator; @@ -533,6 +533,7 @@ float nextoriginupdate; float speed; float jump_counter; float grentimer_waiting; +float last_vel_z; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index b7626ac7..165cb3dd 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -158,6 +158,22 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); + + local float health = getstatf(STAT_HEALTH); + // The pmove_vel_z < 180 check makes sure you're not sliding + if (pmove_onground && health > 0 && pmove_vel_z < 180) { + if (last_vel_z < -650) { + localsound("player/land2.wav"); + } else if (last_vel_z < -300) { + localsound("player/land.wav"); + } + + if (input_buttons & BUTTON2) { + localsound("player/plyrjmp8.wav", CHAN_BODY, 1); + } + } + + last_vel_z = pmove_vel_z; } noref float(string cmd) CSQC_ConsoleCommand = { @@ -413,8 +429,8 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { - InterceptRocketJump(); // InterceptQuickAttacks(); + InterceptRocketJump(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { diff --git a/ssqc/client.qc b/ssqc/client.qc index 0d06f2f7..7185ed02 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2409,7 +2409,10 @@ void () PlayerJump = { self.flags = self.flags - (self.flags & FL_JUMPRELEASED); self.button2 = 0; - FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (!csqcactive) { + FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + } if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { if (!cannon_air) { @@ -2821,6 +2824,7 @@ void () PlayerPostThink = { } local float fdmg; + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); if (((self.jump_flag < -300) && (self.flags & FL_ONGROUND)) && (self.health > 0)) { @@ -2839,10 +2843,14 @@ void () PlayerPostThink = { } fdmg = rint(fdmg); TF_T_Damage(self, world, world, fdmg, 1, 0); - FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); + if (!csqcactive) { + FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); + } self.deathtype = "falling"; } else { - FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); + if (!csqcactive) { + FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); + } } } } From 62f302869874b2df5bc20ea85b28876bd8df4fb0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 3 Aug 2022 15:14:36 +1000 Subject: [PATCH 1559/2474] Remove unused define --- csqc/csextradefs.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index cf4ebe6b..61f712e9 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -518,7 +518,6 @@ enum { #define FOCMD_GRENTIMERVOLUME "fo_grentimervolume" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" #define FOCMD_FTE_HUD "fo_fte_hud" -#define FOCMD_JUMPSOUND "player/plyrjmp8" float team_no; float is_spectator; From a40897f00f915cf8ccb2c67fe830fefb6611b6e9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 4 Aug 2022 12:11:36 +1000 Subject: [PATCH 1560/2474] Terminate idle server with more than 24 hours uptime --- ssqc/client.qc | 3 ++- ssqc/world.qc | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 0d06f2f7..9a2d07e5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1257,7 +1257,7 @@ void () execute_changelevel = { nextmap = vote_result; } -// + other = find(world, classname, "player"); while (other != world) { if (nextmapstring != string_null && nextmapstring != "") @@ -3050,6 +3050,7 @@ void () ClientDisconnect = { " frags\n"); FO_Sound(self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE); self.has_disconnected = 1; + self.classname = "disconnected"; RemovePlayerOwnedEnts(); if (duelmode && clanbattle && !cb_prematch) { diff --git a/ssqc/world.qc b/ssqc/world.qc index 746ba84c..7fc6c566 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -387,12 +387,19 @@ void () StartFrame = { deathmatch = cvar("deathmatch"); framecount = framecount + 1; + local float one_day = 86400; + if (gettime() > one_day) { + local entity te = find (world, classname, "player"); + if (te == world) { + error("Terminated empty server with more than 24 hours uptime\n"); + } + } + if (framecount % 77 == 0) { CheckTrackedSettings(); } - // if(!votemode) { // //TODO: make this optional // Vote_Check(); From 331cf1cbeba393cfd540e967cd28932e22f926df Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 4 Aug 2022 14:56:04 +1000 Subject: [PATCH 1561/2474] Don't change class of disconnected players, refactor --- ssqc/client.qc | 1 - ssqc/world.qc | 34 ++++++++++++++++++---------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 9a2d07e5..b2eb5d83 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3050,7 +3050,6 @@ void () ClientDisconnect = { " frags\n"); FO_Sound(self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE); self.has_disconnected = 1; - self.classname = "disconnected"; RemovePlayerOwnedEnts(); if (duelmode && clanbattle && !cb_prematch) { diff --git a/ssqc/world.qc b/ssqc/world.qc index 7fc6c566..da74edfb 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -1,5 +1,7 @@ void () InitBodyQue; -void () CheckTrackedSettings +void () CheckTrackedSettings; +void () TerminateStaleServer; + string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; void () main = { @@ -387,23 +389,10 @@ void () StartFrame = { deathmatch = cvar("deathmatch"); framecount = framecount + 1; - local float one_day = 86400; - if (gettime() > one_day) { - local entity te = find (world, classname, "player"); - if (te == world) { - error("Terminated empty server with more than 24 hours uptime\n"); - } - } - - if (framecount % 77 == 0) - { + if (framecount % 77 == 0) { CheckTrackedSettings(); + TerminateStaleServer(); } - -// if(!votemode) { -// //TODO: make this optional -// Vote_Check(); -// } }; entity bodyque_head; @@ -470,3 +459,16 @@ void () CheckTrackedSettings = { } } } + +void () TerminateStaleServer = { + if (gettime() < 86400) + return; + + for (entity e = world; (e = find(e, classname, "player")); ) { + if (!e.has_disconnected) + return; //someone is around + } + + dprint("Terminating empty server with more than 24 hours uptime\n"); + localcmd("quit\n"); +} From f1e6cb409660f23d330ddf34ea74328a8821dd9c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 6 Aug 2022 23:34:26 +1000 Subject: [PATCH 1562/2474] Only take the z-axis velocity from the first onground frame to determine landing sound --- csqc/csextradefs.qc | 1 + csqc/main.qc | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 61f712e9..e31d1597 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -532,6 +532,7 @@ float nextoriginupdate; float speed; float jump_counter; float grentimer_waiting; +float last_pmove_onground; float last_vel_z; vector FO_Hud_Icon_Size = [24, 24, 0]; diff --git a/csqc/main.qc b/csqc/main.qc index 165cb3dd..ab008dfd 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -160,8 +160,9 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { sui_end(); local float health = getstatf(STAT_HEALTH); + // The pmove_vel_z < 180 check makes sure you're not sliding - if (pmove_onground && health > 0 && pmove_vel_z < 180) { + if (pmove_onground && !last_pmove_onground && health > 0 && pmove_vel_z < 180) { if (last_vel_z < -650) { localsound("player/land2.wav"); } else if (last_vel_z < -300) { @@ -174,6 +175,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } last_vel_z = pmove_vel_z; + last_pmove_onground = pmove_onground; } noref float(string cmd) CSQC_ConsoleCommand = { From 61deafdf3b0ba7523249b0b1b39a4e0d086e184c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 6 Aug 2022 23:57:46 +1000 Subject: [PATCH 1563/2474] Fix first jump sound not playing bug --- csqc/main.qc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index ab008dfd..692b9ce5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -161,16 +161,18 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { local float health = getstatf(STAT_HEALTH); - // The pmove_vel_z < 180 check makes sure you're not sliding - if (pmove_onground && !last_pmove_onground && health > 0 && pmove_vel_z < 180) { - if (last_vel_z < -650) { - localsound("player/land2.wav"); - } else if (last_vel_z < -300) { - localsound("player/land.wav"); + if (pmove_onground && health > 0) { + // The pmove_vel_z < 180 check makes sure you're not sliding + if (input_buttons & BUTTON2 && pmove_vel_z < 180) { + localsound("player/plyrjmp8.wav", CHAN_BODY, 1); } - if (input_buttons & BUTTON2) { - localsound("player/plyrjmp8.wav", CHAN_BODY, 1); + if (!last_pmove_onground) { + if (last_vel_z < -650) { + localsound("player/land2.wav"); + } else if (last_vel_z < -300) { + localsound("player/land.wav"); + } } } From 0eb30dd22833494252cb407fa4b09f90d87c48d3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 7 Aug 2022 13:13:33 +1000 Subject: [PATCH 1564/2474] Explicitly provide channel and volume to localsound call or it is flakey on hpb --- csqc/main.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 692b9ce5..78740190 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -169,9 +169,11 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!last_pmove_onground) { if (last_vel_z < -650) { - localsound("player/land2.wav"); + print("650 hit!\n"); + localsound("player/land2.wav", CHAN_AUTO, 1); } else if (last_vel_z < -300) { - localsound("player/land.wav"); + print("300 hit!\n"); + localsound("player/land.wav", CHAN_AUTO, 1); } } } From ac6c4f0bcc5cb361b32cd179f461a32ab148810d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 7 Aug 2022 13:26:44 +1000 Subject: [PATCH 1565/2474] Remove debug statements --- csqc/main.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 78740190..91c93bac 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -169,10 +169,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!last_pmove_onground) { if (last_vel_z < -650) { - print("650 hit!\n"); localsound("player/land2.wav", CHAN_AUTO, 1); } else if (last_vel_z < -300) { - print("300 hit!\n"); localsound("player/land.wav", CHAN_AUTO, 1); } } From b59c3a730e24fa7e15763733825bbce2ceb018fb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 7 Aug 2022 15:10:20 +1000 Subject: [PATCH 1566/2474] Add fo_jumpvolume command --- README.md | 1 + csqc/csextradefs.qc | 1 + csqc/main.qc | 3 ++- csqc/settings.qc | 5 +++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 638ff810..8b075403 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ New features * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press * CSQC - fo_grentimersound grentimer.wav * CSQC - fo_grentimervolume +* CSQC - fo_jumpvolume * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e31d1597..0ae2d7ac 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -516,6 +516,7 @@ enum { #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_GRENTIMERSOUND "fo_grentimersound" #define FOCMD_GRENTIMERVOLUME "fo_grentimervolume" +#define FOCMD_JUMPVOLUME "fo_jumpvolume" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" #define FOCMD_FTE_HUD "fo_fte_hud" diff --git a/csqc/main.qc b/csqc/main.qc index 91c93bac..0018fdc3 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -39,6 +39,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_GRENTIMER, "1"); registercvar(FOCMD_GRENTIMERSOUND, "grentimer.wav"); registercvar(FOCMD_GRENTIMERVOLUME, "1"); + registercvar(FOCMD_JUMPVOLUME, "1"); registercvar(FOCMD_OLDSCOREBOARD, "0"); registercvar(FOCMD_FTE_HUD, "0"); @@ -164,7 +165,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (pmove_onground && health > 0) { // The pmove_vel_z < 180 check makes sure you're not sliding if (input_buttons & BUTTON2 && pmove_vel_z < 180) { - localsound("player/plyrjmp8.wav", CHAN_BODY, 1); + localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); } if (!last_pmove_onground) { diff --git a/csqc/settings.qc b/csqc/settings.qc index 3a52b82b..cdf3d3fd 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -6,6 +6,7 @@ void FO_WriteSettings() string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, cvar_string(FOCMD_GRENTIMERSOUND)); line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, cvar_string(FOCMD_GRENTIMERVOLUME)); + line = FormatCfgString(line, FOCMD_JUMPVOLUME, cvar_string(FOCMD_JUMPVOLUME)); line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(cvar(FOCMD_OLDSCOREBOARD))); fputs(filehandle, line); fclose(filehandle); @@ -16,6 +17,7 @@ void FO_LoadDefaultSettings() cvar_set(FOCMD_GRENTIMER, "1"); cvar_set(FOCMD_GRENTIMERSOUND, "grentimer.wav"); cvar_set(FOCMD_GRENTIMERVOLUME, "1"); + cvar_set(FOCMD_JUMPVOLUME, "1"); cvar_set(FOCMD_OLDSCOREBOARD, "0"); } @@ -54,6 +56,9 @@ void FO_LoadSettings() case FOCMD_GRENTIMERVOLUME: cvar_set(FOCMD_GRENTIMERVOLUME, val); break; + case FOCMD_JUMPVOLUME: + cvar_set(FOCMD_JUMPVOLUME, val); + break; case FOCMD_OLDSCOREBOARD: cvar_set(FOCMD_OLDSCOREBOARD, val); break; From ddbb76f59ba326997808352923f0c9c7bade32f0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 11 Aug 2022 22:18:38 +1000 Subject: [PATCH 1567/2474] Don't spam jump sound in ceasefire --- csqc/main.qc | 3 ++- share/defs.h | 8 +++++--- ssqc/admin.qc | 4 ++++ ssqc/clan.qc | 2 ++ ssqc/client.qc | 3 +++ ssqc/mvdsv.qc | 1 + ssqc/quadmode.qc | 2 ++ ssqc/qw.qc | 1 + ssqc/world.qc | 2 ++ 9 files changed, 22 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 71f71335..f4ebb360 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -160,8 +160,9 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { sui_end(); local float health = getstatf(STAT_HEALTH); + local float paused = getstatf(STAT_PAUSED); - if (pmove_onground && health > 0) { + if (pmove_onground && health > 0 && !paused) { // The pmove_vel_z < 180 check makes sure you're not sliding if (input_buttons & BUTTON2 && pmove_vel_z < 180) { localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); diff --git a/share/defs.h b/share/defs.h index f0703542..89e3a0c3 100644 --- a/share/defs.h +++ b/share/defs.h @@ -230,9 +230,10 @@ #define AS_MISSILE 4 // stat_flags -#define PLAYER_READY 1 -#define ENEMY_TEAM_READY 2 -#define LAST_NOT_READY 4 +#define PLAYER_READY 1 +#define ENEMY_TEAM_READY 2 +#define LAST_NOT_READY 4 +#define CEASEFIRE 8 //=========================================================================== // TEAMFORTRESS Defs @@ -1492,6 +1493,7 @@ #define STAT_NO_GREN2 40 #define STAT_TP_GREN1 41 #define STAT_TP_GREN2 42 +#define STAT_PAUSED 43 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/admin.qc b/ssqc/admin.qc index bb80ed1a..c1c7c9b7 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -146,6 +146,7 @@ void () Admin_CeaseFire = { StopTimer(); } cease_fire = 1; + cs_paused = 1; bprint(2, "CEASE FIRE\n"); te = find(world, classname, "player"); while (te) { @@ -167,6 +168,7 @@ void () Admin_CeaseFire = { dremove(te); } cease_fire = 0; + cs_paused = 0; bprint(2, "RESUME FIRE\n"); if (cb_prematch) { //Make sure you don't just start the countdown on resume when not everyone's readied up @@ -189,6 +191,7 @@ void () Admin_Pause = { if (!is_paused) { setpause(1); is_paused = 1; + cs_paused = 1; pause_actor = self.netname; if (cb_prematch && is_countdown) { StopTimer(); @@ -205,6 +208,7 @@ void () Admin_Pause = { } setpause(0); is_paused = 0; + cs_paused = 0; return; } pause_actor = self.netname; diff --git a/ssqc/clan.qc b/ssqc/clan.qc index b7747bbf..f63ee306 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -104,6 +104,7 @@ void () StartMatch = } cb_prematch = 0; cease_fire = 0; + cs_paused = 0; te = find(world, classname, "player"); while (te) { @@ -348,6 +349,7 @@ void () PreMatch_Think = { CenterPrint3 (p, "Countdown ", tmp, "\n"); if (self.cnt2 < 6) { cease_fire = 0; + cs_paused = 0; stuffcmd (p, "play buttons/switch04.wav\n"); } } diff --git a/ssqc/client.qc b/ssqc/client.qc index 83d65d8a..200ee1b4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -321,6 +321,7 @@ void () DecodeLevelParms = { autokick_time = 0; cease_fire = 0; + cs_paused = 0; toggleflags = toggleflags - (toggleflags & TFLAG_TEAMFRAGS); toggleflags = toggleflags - (toggleflags & TFLAG_CHEATCHECK); @@ -2413,7 +2414,9 @@ void () PlayerJump = { self.button2 = 0; local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (!csqcactive) { + sprint(self, PRINT_MEDIUM, "csqcactive: ", ftos(csqcactive), "\n"); FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); } diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index 5681e3ad..2930774e 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -111,6 +111,7 @@ void (float duration) GE_PausedTic = { if (unpause_requested) { if ((duration >= unpause_countdown)) { is_paused = 0; + cs_paused = 0; unpause_countdown = 0; unpause_requested = 0; unpause_lastcountnumber = 0; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 50a470ff..6d536130 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -370,6 +370,7 @@ void () QuadRoundInit = { if (self.cnt2 <= 5) { cease_fire = 0; + cs_paused = 0; stuffcmd(p, "play buttons/switch04.wav\n"); } } @@ -390,6 +391,7 @@ void () StartQuadRound = lightstyle(0, "m"); cease_fire = 0; + cs_paused = 0; p = find(world, classname, "player"); while (p != world) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ac71744a..a33dd4d4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -607,6 +607,7 @@ float detpack_when_reloading; float pyro_type; float flag_follow; float ceasefire_type; +float cs_paused; float is_paused; string pause_actor; float unpause_requested; diff --git a/ssqc/world.qc b/ssqc/world.qc index 74a06d70..6d7fa2cc 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -337,6 +337,8 @@ void () worldspawn = { clientstat(STAT_TP_GREN1, EV_FLOAT, tp_grenades_1); clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); + globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused"); + entity worldspawnent; worldspawnent = spawn(); worldspawnent.think = WorldSpawnPost; From 4db08f1feb9f68f8fc10a8e49db7c74b25393671 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 13 Aug 2022 20:03:15 +1000 Subject: [PATCH 1568/2474] Remove debug statement --- ssqc/client.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 200ee1b4..fecdd7fb 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2416,7 +2416,6 @@ void () PlayerJump = { local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); if (!csqcactive) { - sprint(self, PRINT_MEDIUM, "csqcactive: ", ftos(csqcactive), "\n"); FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); } From a2547afcaef9b71447fe4966c7ec231e6b98c138 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 15 Aug 2022 21:36:17 +1000 Subject: [PATCH 1569/2474] Set max number of clients at beginning of quad --- ssqc/quadmode.qc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 50a470ff..dca59e41 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -254,7 +254,20 @@ void () QuadRoundBegin = { local entity oldself; //local entity tfdet; local float counter; + localcmd(strcat(strcat("timelimit ", ftos(stof(infokey(world, "round_time")))), "\n")); + + // set sv_maxclients to number of players at start of match + local float numplayers = 0; + local entity player; + player = find (world, classname, "player"); + while (player) { + if (isPlayerValid(player) == TRUE) + numplayers++; + player = find (player, classname, "player"); + } + localcmd(sprintf("sv_maxclients %g\n", numplayers)); + te = find(world, classname, "func_breakable"); while (te) { setmodel(te, te.mdl); From 08925e19990fd648ff592113a437607cf53f7734 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 15 Aug 2022 21:45:43 +1000 Subject: [PATCH 1570/2474] Set sv_maxclients at beginning of countdown --- ssqc/clan.qc | 1 + ssqc/quadmode.qc | 11 ----------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index b7747bbf..5636858a 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1085,6 +1085,7 @@ float () CheckAllPlayersReady = { } else { bprint (2, "All players ready, starting match\n"); StartTimer (); + localcmd(sprintf("sv_maxclients %g\n", f1)); } return 1; } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index dca59e41..3d7f11a6 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -257,17 +257,6 @@ void () QuadRoundBegin = { localcmd(strcat(strcat("timelimit ", ftos(stof(infokey(world, "round_time")))), "\n")); - // set sv_maxclients to number of players at start of match - local float numplayers = 0; - local entity player; - player = find (world, classname, "player"); - while (player) { - if (isPlayerValid(player) == TRUE) - numplayers++; - player = find (player, classname, "player"); - } - localcmd(sprintf("sv_maxclients %g\n", numplayers)); - te = find(world, classname, "func_breakable"); while (te) { setmodel(te, te.mdl); From 2009b84cf8aa1813674e54d4dd7dc2d3272e9f74 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 15 Aug 2022 22:31:35 +1000 Subject: [PATCH 1571/2474] Restore maxclients and end of quad --- ssqc/clan.qc | 1 + ssqc/quadmode.qc | 3 +++ ssqc/qw.qc | 1 + 3 files changed, 5 insertions(+) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 5636858a..b4d9cbc2 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1085,6 +1085,7 @@ float () CheckAllPlayersReady = { } else { bprint (2, "All players ready, starting match\n"); StartTimer (); + init_maxclients = cvar("sv_maxclients"); localcmd(sprintf("sv_maxclients %g\n", f1)); } return 1; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 3d7f11a6..8b5907ac 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -451,6 +451,9 @@ void () StartQuadRound = } te = find(te, classname, "observer"); } + + localcmd(sprintf("sv_maxclients %g\n", init_maxclients)); + bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); bprint2(2, "map will auto-restart in ", ftos(map_restart_time)); bprint2(2, " seconds\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ac71744a..46433767 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -131,6 +131,7 @@ string nextmap; // // FortressMap stuff // +float init_maxclients; float number_of_teams; float illegalclasses; float illegalclasses1; From befe682c521b2ba1314a271e1764e97464f92c8d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 16 Aug 2022 00:30:02 +1000 Subject: [PATCH 1572/2474] Disable auto limiting sv_maxlients to number of active players at quad start with localinfo limit_quad_players off --- README.md | 1 + ssqc/clan.qc | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 638ff810..b00907a0 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ +* Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. * `+dropflag` Allows player to hold button and flag will be thrown on contact. * `+rj` Switches to rocket/incendiary weapon, jumps and shoots. `+aux_jump` is no longer required. diff --git a/ssqc/clan.qc b/ssqc/clan.qc index b4d9cbc2..0841de59 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1085,8 +1085,12 @@ float () CheckAllPlayersReady = { } else { bprint (2, "All players ready, starting match\n"); StartTimer (); - init_maxclients = cvar("sv_maxclients"); - localcmd(sprintf("sv_maxclients %g\n", f1)); + + local float limit_quad_players = CF_GetSetting("lqp", "limit_quad_players", "on"); + if (limit_quad_players) { + init_maxclients = cvar("sv_maxclients"); + localcmd(sprintf("sv_maxclients %g\n", f1)); + } } return 1; } From 9b722e1513ddf87ca15b84f42cb0917600b977ea Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 19 Aug 2022 01:18:26 +1000 Subject: [PATCH 1573/2474] Just do it in quakec, and don't bother messing with sv_maxclients --- ssqc/clan.qc | 6 ++---- ssqc/client.qc | 6 ++++++ ssqc/quadmode.qc | 2 -- ssqc/qw.qc | 2 +- ssqc/tforttm.qc | 9 ++++++--- ssqc/world.qc | 2 ++ 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 0841de59..55cec517 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1067,7 +1067,6 @@ void () UpdateReadyStatus = { } float () CheckAllPlayersReady = { - local float f1; if (is_countdown) { return 0; } @@ -1077,7 +1076,7 @@ float () CheckAllPlayersReady = { if (intermission_running) return 0; - f1 = TeamFortress_GetNoPlayers (); + local float f1 = TeamFortress_GetNoActivePlayers(); bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); if (v_ready == f1 && v_ready > 0) { if(cease_fire) { @@ -1088,8 +1087,7 @@ float () CheckAllPlayersReady = { local float limit_quad_players = CF_GetSetting("lqp", "limit_quad_players", "on"); if (limit_quad_players) { - init_maxclients = cvar("sv_maxclients"); - localcmd(sprintf("sv_maxclients %g\n", f1)); + quad_maxplayers = f1; } } return 1; diff --git a/ssqc/client.qc b/ssqc/client.qc index 4ee553bd..0bcc2849 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2960,6 +2960,12 @@ void (optional float csqcactive) ClientConnect = { } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); + + local float numplayers = TeamFortress_GetNoActivePlayers (); + if (quadmode && quad_maxplayers && (numplayers >= quad_maxplayers)) { + sprint(self, PRINT_HIGH, "Match in progress, forcing to observer\n"); + forceinfokey(self, "*spectator", "1"); + } }; float () RejoinWithTfId = { diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 8b5907ac..f5bc71c6 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -452,8 +452,6 @@ void () StartQuadRound = te = find(te, classname, "observer"); } - localcmd(sprintf("sv_maxclients %g\n", init_maxclients)); - bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); bprint2(2, "map will auto-restart in ", ftos(map_restart_time)); bprint2(2, " seconds\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 46433767..dfe9cd87 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -131,7 +131,7 @@ string nextmap; // // FortressMap stuff // -float init_maxclients; +float quad_maxplayers; float number_of_teams; float illegalclasses; float illegalclasses1; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 6858f49a..d7b1ea41 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -520,10 +520,13 @@ float () TeamFortress_GetNoActivePlayers = { search = find(world, classname, "player"); while (search != world) { - if (search.netname != string_null) { - if (search.team_no && search.playerclass) - nump = nump + 1; + if (search.netname != string_null + && search.team_no + && search.playerclass + && !search.has_disconnected) { + nump = nump + 1; } + search = find(search, classname, "player"); } return (nump); diff --git a/ssqc/world.qc b/ssqc/world.qc index 74a06d70..a73ff258 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -96,6 +96,8 @@ void () worldspawn = { lastspawn = world; number_of_teams = 0; + quad_maxplayers = 0; + InitBodyQue(); if (self.model == "maps/e1m8.bsp") cvar_set("sv_gravity", "100"); From 8f5abb0bee84e20175f313bdd640fb3fdf10bc4a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 23 Aug 2022 23:24:58 +1000 Subject: [PATCH 1574/2474] Fix bug causing jump sound not to play in world for csqc active players hehe --- csqc/events.qc | 14 ++++++++++++++ ssqc/client.qc | 14 +++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 1e61a701..5955326c 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -442,3 +442,17 @@ void ParseSBAR() break; } } + +float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound = { + if !(entnum == player_localentnum) + return 0; + + switch(soundname) { + case "player/plyrjmp8.wav": + case "player/land.wav": + case "player/land2.wav": + return 1; + } + + return 0; +} diff --git a/ssqc/client.qc b/ssqc/client.qc index fecdd7fb..d3be9c8e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2413,11 +2413,7 @@ void () PlayerJump = { self.flags = self.flags - (self.flags & FL_JUMPRELEASED); self.button2 = 0; - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - - if (!csqcactive) { - FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); - } + FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { if (!cannon_air) { @@ -2848,14 +2844,10 @@ void () PlayerPostThink = { } fdmg = rint(fdmg); TF_T_Damage(self, world, world, fdmg, 1, 0); - if (!csqcactive) { - FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); - } + FO_Sound(self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM); self.deathtype = "falling"; } else { - if (!csqcactive) { - FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); - } + FO_Sound(self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); } } } From 4db6a7386a9ee741504687e2e685f18b0b787a3b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 27 Aug 2022 17:08:46 +1000 Subject: [PATCH 1575/2474] Fix sniper\'s zoom --- csqc/csextradefs.qc | 2 ++ csqc/main.qc | 53 ++++++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 339ea43e..74b6739f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -96,6 +96,8 @@ float vote_selected_index; float vote_list_offset; entity current_vote; string vote_list_filter; +float oldbuttons; +float zoomed_in; .string name; .string description; diff --git a/csqc/main.qc b/csqc/main.qc index f4ebb360..55e24255 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -12,9 +12,7 @@ void FO_WriteSettings(); void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); -void InterceptRocketJump(); float IsValidToUseGrenades(); -void InterceptQuickAttacks(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -148,8 +146,23 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { //setviewprop(VF_DRAWWORLD, 1); //whether the world entity should be drawn. set to 0 if you want a completely empty scene. //setviewprop(VF_MIN, '0 0 0'); //top-left coord (x,y) of the scene viewport in virtual pixels (or annoying physical pixels in dp). //setviewprop(VF_SIZE, [width, height, 0]); //virtual size (width,height) of the scene viewport in virtual pixels (or annoying physical pixels in dp). - //setviewprop(VF_AFOV, cvar("fov”)); //note: fov_x and fov_y control individual axis. afov is general + //setviewprop(VF_AFOV, cvar("fov")); //note: fov_x and fov_y control individual axis. afov is general //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. + + local float health = getstatf(STAT_HEALTH); + + if (health <= 0 || player_class != PC_SNIPER) { + zoomed_in = 0; + } + + if (zoomed_in) { + setviewprop(VF_AFOV, cvar("fov")/3); + setsensitivityscaler(1/3); + } else { + setviewprop(VF_AFOV, cvar("fov")); + setsensitivityscaler(1); + } + addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view renderscene(); @@ -159,7 +172,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Hud_Draw(width, height); sui_end(); - local float health = getstatf(STAT_HEALTH); local float paused = getstatf(STAT_PAUSED); if (pmove_onground && health > 0 && !paused) { @@ -434,8 +446,21 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { - // InterceptQuickAttacks(); - InterceptRocketJump(); + local float changed_buttons = input_buttons ^ oldbuttons; + oldbuttons = input_buttons; + + local float keydowns = changed_buttons & input_buttons; + local float keyups = changed_buttons & ~input_buttons; + + // Intercept rocket jump; + if ((player_class == PC_SOLDIER || player_class == PC_PYRO) && input_buttons & BUTTON4) { + input_buttons |= BUTTON0 + BUTTON2; + } + + // Intercept zoom + if (player_class == PC_SNIPER && keydowns & BUTTON3) { + zoomed_in = !zoomed_in; + } } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -473,19 +498,3 @@ void StopGrenTimers() { FO_Hud_Grentimers[i].icon_index = 0; } } - -void InterceptRocketJump() { - if (player_class != PC_SOLDIER && player_class != PC_PYRO) { - return; - } - - if (input_buttons & BUTTON4) { - input_buttons |= BUTTON0 + BUTTON2; - } -} - -// void InterceptQuickAttacks() { -// if (input_buttons & (BUTTON8 | BUTTON9 | BUTTON10 | BUTTON11)) { -// input_buttons |= BUTTON0; -// } -// } From 6d54482f4653347f1658563c67db2afeca569c99 Mon Sep 17 00:00:00 2001 From: me Date: Tue, 30 Aug 2022 21:29:00 +1200 Subject: [PATCH 1576/2474] duel_no_packs now doesn't make sound either --- ssqc/tfortmap.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index ff11ad0a..f7ad1f5c 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -297,7 +297,9 @@ void () TF_PlaceGoal = { if (self.classname != "info_tfgoal_timer") { if (self.goal_activation & TFGA_TOUCH) { - self.touch = tfgoal_touch; + if(!duelmode || !duel_no_packs) { + self.touch = tfgoal_touch; + } } } else { self.think = tfgoal_timer_tick; @@ -2089,6 +2091,8 @@ void () tfgoal_touch = { return; if (self.goal_state == TFGS_ACTIVE) return; + if(duelmode && duel_no_packs) + return; if (CTF_Map == 1) { if ((self.goal_no == 3) && (other.team_no == 1)) { From fcbbd76dfcc27505c80a1fe2f395883468252721 Mon Sep 17 00:00:00 2001 From: me Date: Tue, 30 Aug 2022 23:49:31 +1200 Subject: [PATCH 1577/2474] duel_no_packs now doesn't make sound either --- README.md | 1 + ssqc/client.qc | 19 +++++++++++++++++++ ssqc/qw.qc | 2 ++ 3 files changed, 22 insertions(+) diff --git a/README.md b/README.md index 7b60cf7d..7bb3a224 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ New features * CSQC - fo_hud_editor to move panels and save to config * `info_empblock` has a new field `goal_effects`. Setting it to 16 will prevent it from blocking emps if there is a wall between it and the explosion. * New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. +* Server option for duelmode to print winner's health `localinfo duel_print_health 1`/`localinfo dph 1` * Server option for duelmode to respawn with all grens `localinfo duel_all_grens 1`/`localinfo dag 1` * Server option to remove packs in duel mode `localinfo duel_no_packs 1`/`localinfo dnp 1` * Server setting for duelmode reset delay `localinfo drd 0.5` (`localinfo duel_reset_delay 0.5`) diff --git a/ssqc/client.qc b/ssqc/client.qc index 0b2123df..bbd7e1ad 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -706,6 +706,10 @@ void () DecodeLevelParms = { duel_all_grens = CF_GetSetting("dag", "duel_all_grens", "0"); // After a duel round, print the winners' health stats round_winner_print_health = CF_GetSetting("dph", "duel_print_health", "0"); + // After respawning in duel mode, nobody shoots until + // 0 - immediately + // 1 - all players have moved away from spawn + duel_spawn_guard = CF_GetSetting("dsg", "duel_spawn_guard", "1"); //Proportion required to trigger a map change vote_threshold = CF_GetSetting("vt", "vote_threshold", "0.5"); @@ -1384,6 +1388,11 @@ void (string cn) RemoveAllEntsByClassname = { } } +void () spawn_guard_think = { + self.nextthink = time + 0.1; + bprint(PRINT_HIGH, "spawn_guard_think\n"); +}; + void () ResetPlayers = { local entity te, oldself, reset_timer; local float teamsleft; @@ -1425,6 +1434,13 @@ void () ResetPlayers = { RemoveAllEntsByClassname("pyro_rocket"); RemoveAllEntsByClassname("proj_tranq"); + if(duel_spawn_guard) { + no_fire_mode = 1; + reset_timer = spawn(); + reset_timer.classname = "spawn_guard_check"; + reset_timer.think = spawn_guard_think; + reset_timer.nextthink = time + 0.1; + } te = find(world, classname, "player"); while (te != world) { if(!te.has_disconnected) { @@ -1440,6 +1456,9 @@ void () ResetPlayers = { setspawnparms(self); PutClientInServer(); self.respawn_time = 0; + if(duel_spawn_guard) { + self.duel_guarded = 1; + } self = oldself; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index efb5d24f..8aaad7ab 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -461,6 +461,8 @@ float duel_reset_timer; float no_fire_mode; float duel_all_grens; float duel_no_packs; +float duel_spawn_guard; +float .duel_guarded; float votemode; float voting_started; float voting_expires; From 553ab1917190cc54b570e56a391c58ae4cc942ed Mon Sep 17 00:00:00 2001 From: me Date: Wed, 31 Aug 2022 13:01:01 +1200 Subject: [PATCH 1578/2474] Wolv's wild duel ideas --- ssqc/clan.qc | 5 ++++- ssqc/client.qc | 52 +++++++++++++++++++++++++++++++++++++++--------- ssqc/demoman.qc | 5 +++++ ssqc/engineer.qc | 5 +++++ ssqc/pyro.qc | 10 ++++++++++ ssqc/qw.qc | 2 +- 6 files changed, 68 insertions(+), 11 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index c2570e17..27435f1d 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -89,7 +89,7 @@ void () StartMatch = dremove(te.observer_list); } dremove(te.linked_list); - dremove(te); + dremove(te); //remove before finding next? te = find (te, classname, "detpack"); } if(duelmode && duel_no_packs) { @@ -160,6 +160,9 @@ void () StartMatch = } } if (duelmode) { + if(duel_spawn_guard) { + StartSpawnGuard(); + } //ResetPlayers(); CountMatchPlayersAndReset(); } diff --git a/ssqc/client.qc b/ssqc/client.qc index bbd7e1ad..9880eebd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1389,8 +1389,42 @@ void (string cn) RemoveAllEntsByClassname = { } void () spawn_guard_think = { + local entity te; + local float no_fire = 0; + te = find(world, classname, "player"); + while (te != world) { + if(!te.has_disconnected) { + if(te.duel_guarded != world) { + if(vlen(te.duel_guarded.origin - te.origin) > 200) { + te.duel_guarded = world; + te.invincible_finished = 0; + te.invincible_time = 0; + te.effects = 0; + bprint(PRINT_HIGH, te.netname, " \bhas left the spawn!\b\n"); + } else { + no_fire++; + } + } + } + te = find (te, classname, "player"); + } self.nextthink = time + 0.1; - bprint(PRINT_HIGH, "spawn_guard_think\n"); + if(!no_fire) { + no_fire_mode = 0; + bprint(PRINT_HIGH, "\bFIGHT!\b\n"); + FO_Sound(world, CHAN_ITEM, "fight.wav", 1, ATTN_NONE); + self.think = SUB_Remove; + } +}; + +void () StartSpawnGuard = { + no_fire_mode = 1; + entity reset_timer = spawn(); + reset_timer.classname = "spawn_guard_check"; + reset_timer.think = spawn_guard_think; + reset_timer.nextthink = time + 0.1; + bprint(PRINT_HIGH, "\bLeave the spawn to begin!\b\n"); + FO_Sound(world, CHAN_ITEM, "come_get.wav", 1, ATTN_NONE); }; void () ResetPlayers = { @@ -1435,11 +1469,9 @@ void () ResetPlayers = { RemoveAllEntsByClassname("proj_tranq"); if(duel_spawn_guard) { - no_fire_mode = 1; - reset_timer = spawn(); - reset_timer.classname = "spawn_guard_check"; - reset_timer.think = spawn_guard_think; - reset_timer.nextthink = time + 0.1; + StartSpawnGuard(); + precache_sound("get_some.wav"); + precache_sound("fight.wav"); } te = find(world, classname, "player"); while (te != world) { @@ -1456,9 +1488,6 @@ void () ResetPlayers = { setspawnparms(self); PutClientInServer(); self.respawn_time = 0; - if(duel_spawn_guard) { - self.duel_guarded = 1; - } self = oldself; } @@ -2080,6 +2109,11 @@ void () PutClientInServer = { spot.think = SUB_Remove; } } + + if(duel_spawn_guard) { + self.duel_guarded = spot; + self.invincible_finished = time + 666; + } setmodel(self, string_null); modelindex_null = self.modelindex; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index e72f65a0..63e42ad5 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -145,6 +145,11 @@ void (float timer) TeamFortress_SetDetpack = { return; } + if (no_fire_mode) { + sprint(self, PRINT_HIGH, "You can't set a detpack right now\n"); + return; + } + at_spot = findradius(self.origin, 65); while (at_spot != world) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 4630e718..f0cdeb12 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -453,6 +453,11 @@ void (float objtobuild) TeamFortress_Build = { sprint(self, PRINT_MEDIUM, "You cannot build during prematch\n"); return; } + + if(no_fire_mode) { + sprint(self, PRINT_MEDIUM, "You cannot build right now\n"); + return; + } local float btime; local vector tmp1; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 01cf64d0..ae24adc1 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -766,6 +766,11 @@ void () AirBlastReloadFinished = { }; void () UseAirBlast = { + if(no_fire_mode) { + sprint(self, PRINT_MEDIUM, "You cannot blast air right now\n"); + return; + } + if (self.special_cooldown < time) { self.airblast_cooldown = 1; @@ -851,6 +856,11 @@ void () UseAirBlast = { }; void () UseAirBlastV2 = { + if(no_fire_mode) { + sprint(self, PRINT_MEDIUM, "You cannot blast air right now\n"); + return; + } + float isabjump = airblastjump && self.v_angle_x > 60; if (self.ammo_cells < airblastcells) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 8aaad7ab..9cfe43bf 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -462,7 +462,7 @@ float no_fire_mode; float duel_all_grens; float duel_no_packs; float duel_spawn_guard; -float .duel_guarded; +.entity duel_guarded; float votemode; float voting_started; float voting_expires; From 94d1612e3357589f88f70af0557bac2c1506324f Mon Sep 17 00:00:00 2001 From: me Date: Wed, 31 Aug 2022 13:09:26 +1200 Subject: [PATCH 1579/2474] Make non-duel players vulnerable again --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 9880eebd..d8085cb6 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1468,7 +1468,7 @@ void () ResetPlayers = { RemoveAllEntsByClassname("pyro_rocket"); RemoveAllEntsByClassname("proj_tranq"); - if(duel_spawn_guard) { + if(duelmode && duel_spawn_guard) { StartSpawnGuard(); precache_sound("get_some.wav"); precache_sound("fight.wav"); @@ -2110,7 +2110,7 @@ void () PutClientInServer = { } } - if(duel_spawn_guard) { + if(duelmode && duel_spawn_guard) { self.duel_guarded = spot; self.invincible_finished = time + 666; } From 139777e80c9b8f2a3b72e47fc3ceac9d9739070d Mon Sep 17 00:00:00 2001 From: me Date: Wed, 31 Aug 2022 13:56:41 +1200 Subject: [PATCH 1580/2474] Update duel-spawn-guard readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7bb3a224..e1fa23a0 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ +* Server option for duelmode to allow spawn protection `localinfo duel_spawn_guard 1`/`localinfo dsg 1` - it will not allow any fighting until both players have left the spawn. * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. * Added ``localinfo nomapcycle 1`` to stop all the confusion. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. From f6cd0a57313abc8718357bd1e6555bdd80fd46ab Mon Sep 17 00:00:00 2001 From: me Date: Wed, 31 Aug 2022 13:58:40 +1200 Subject: [PATCH 1581/2474] Update duel-spawn-guard readme v2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e1fa23a0..19806b54 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ FortressOne Server New features ------ -* Server option for duelmode to allow spawn protection `localinfo duel_spawn_guard 1`/`localinfo dsg 1` - it will not allow any fighting until both players have left the spawn. * `localinfo allowpracspawns 1` option for players to set a personal spawnpoint for practice. Players can then use commands `placepracspawn` and `removepracspawn`. Suicide time penalties are removed while allowpracspawns is enabled. * Added ``localinfo nomapcycle 1`` to stop all the confusion. * Option to configure hwguy armor `localinfo max_armor_hwguy 250`. @@ -49,6 +48,7 @@ New features * CSQC - fo_hud_editor to move panels and save to config * `info_empblock` has a new field `goal_effects`. Setting it to 16 will prevent it from blocking emps if there is a wall between it and the explosion. * New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. +* Server option for duelmode to allow spawn protection `localinfo duel_spawn_guard 1`/`localinfo dsg 1` - it will not allow any fighting until both players have left the spawn. * Server option for duelmode to print winner's health `localinfo duel_print_health 1`/`localinfo dph 1` * Server option for duelmode to respawn with all grens `localinfo duel_all_grens 1`/`localinfo dag 1` * Server option to remove packs in duel mode `localinfo duel_no_packs 1`/`localinfo dnp 1` From eff4cf86944c6f21e93c0f584d9d483fdb0f5d84 Mon Sep 17 00:00:00 2001 From: me Date: Thu, 1 Sep 2022 09:41:13 +1200 Subject: [PATCH 1582/2474] No EZ floaters --- ssqc/client.qc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index d8085cb6..c4ccabd5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2110,11 +2110,6 @@ void () PutClientInServer = { } } - if(duelmode && duel_spawn_guard) { - self.duel_guarded = spot; - self.invincible_finished = time + 666; - } - setmodel(self, string_null); modelindex_null = self.modelindex; @@ -2154,6 +2149,12 @@ void () PutClientInServer = { if (self.playerclass == 0 && self.team_no > 0) { Menu_Class(0); } + + if(duelmode && duel_spawn_guard && self.team_no && self.playerclass) { + self.duel_guarded = spot; + self.invincible_finished = time + 666; + } + }; //void () info_player_start = { From 6f585b5b414bd3d2b591cf470ded226f1b90fb01 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 8 Sep 2022 21:04:47 -0700 Subject: [PATCH 1583/2474] Fix missing jump sounds Matching on player_localentnum is too broad since we assume the identity of other ents when spectating obseriving. Filter these cases out. It's possible we need isdemo() also; but at least the demos I tried worked. --- csqc/events.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index 5955326c..59533070 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -444,7 +444,9 @@ void ParseSBAR() } float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound = { - if !(entnum == player_localentnum) + // Filter out sounds we may have generated locally, unless we're just + // pretending to be that entity. + if (entnum != player_localentnum || is_spectator || is_observer) return 0; switch(soundname) { From 6ddd8953cd3cb0dd696f447e2540b41d00a220e3 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Sep 2022 00:31:09 -0700 Subject: [PATCH 1584/2474] Reduce per-frame overhead A large amount of game logic is currently overloaded with per-frame rendering. Move this into independent synchronization that tries to follow server updates more directly. wayland won't let me escape vsync, but limited profiling suggests this is good for at least 1-2% cpu reduction from infobuf string conversion alone at higher framerates. --- csqc/main.qc | 139 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 55e24255..3a4e0ebb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -13,6 +13,7 @@ void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); float IsValidToUseGrenades(); +void Sync_GameState(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -115,25 +116,8 @@ noref void() CSQC_WorldLoaded = { noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; - team_no = getstatf(STAT_TEAMNO); - is_observer = FALSE; - if (team_no == 0) - is_observer = TRUE; - player_class = getstatf(STAT_CLASS); - SBAR.ReadyStatus = getstatf(STAT_FLAGS); - oldhealth = getstatf(STAT_HEALTH); - is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); - if (is_spectator) - is_observer = FALSE; SBAR.Hint = ""; thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); - //if(nextoriginupdate < time) { - // speed = vlen([thisorigin.x, thisorigin.y] - [lastorigin.x, lastorigin.y]) * 10; - // lastorigin = thisorigin; - // nextoriginupdate = time + 0.1; - //} - vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; - speed = sqrt(vel.x * vel.x + vel.y * vel.y); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! @@ -141,27 +125,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if(cvar(FOCMD_FTE_HUD) != 1) { setproperty(VF_DRAWENGINESBAR, 1); /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ } - //setviewprop(VF_ORIGIN, '0 0 0'); //view position of the scene (after view_ofs effects). - //setviewprop(VF_ANGLES, '0 0 0'); //override the view angles. input will work as normal. other players will see your player as normal. your screen will just be pointing a different direction. - //setviewprop(VF_DRAWWORLD, 1); //whether the world entity should be drawn. set to 0 if you want a completely empty scene. - //setviewprop(VF_MIN, '0 0 0'); //top-left coord (x,y) of the scene viewport in virtual pixels (or annoying physical pixels in dp). - //setviewprop(VF_SIZE, [width, height, 0]); //virtual size (width,height) of the scene viewport in virtual pixels (or annoying physical pixels in dp). - //setviewprop(VF_AFOV, cvar("fov")); //note: fov_x and fov_y control individual axis. afov is general - //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. - - local float health = getstatf(STAT_HEALTH); - - if (health <= 0 || player_class != PC_SNIPER) { - zoomed_in = 0; - } - - if (zoomed_in) { - setviewprop(VF_AFOV, cvar("fov")/3); - setsensitivityscaler(1/3); - } else { - setviewprop(VF_AFOV, cvar("fov")); - setsensitivityscaler(1); - } addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view @@ -171,26 +134,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); - - local float paused = getstatf(STAT_PAUSED); - - if (pmove_onground && health > 0 && !paused) { - // The pmove_vel_z < 180 check makes sure you're not sliding - if (input_buttons & BUTTON2 && pmove_vel_z < 180) { - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); - } - - if (!last_pmove_onground) { - if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_AUTO, 1); - } else if (last_vel_z < -300) { - localsound("player/land.wav", CHAN_AUTO, 1); - } - } - } - - last_vel_z = pmove_vel_z; - last_pmove_onground = pmove_onground; } noref float(string cmd) CSQC_ConsoleCommand = { @@ -461,6 +404,8 @@ noref void CSQC_Input_Frame() { if (player_class == PC_SNIPER && keydowns & BUTTON3) { zoomed_in = !zoomed_in; } + + Sync_GameState(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -498,3 +443,81 @@ void StopGrenTimers() { FO_Hud_Grentimers[i].icon_index = 0; } } + +float last_servercommandframe; +void _Sync_ServerCommandFrame() { + // Server command frames are monotonically unique, we can skip processing + // unless there is new state. + if (last_servercommandframe == servercommandframe) + return; + last_servercommandframe = servercommandframe; + + team_no = getstatf(STAT_TEAMNO); + is_observer = FALSE; + if (team_no == 0) + is_observer = TRUE; + player_class = getstatf(STAT_CLASS); + SBAR.ReadyStatus = getstatf(STAT_FLAGS); + oldhealth = getstatf(STAT_HEALTH); + is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); + if (is_spectator) + is_observer = FALSE; + + vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), + getstatf(STAT_VELOCITY_Z)]; + speed = sqrt(vel.x * vel.x + vel.y * vel.y); + + local float health = getstatf(STAT_HEALTH); + if (health <= 0 || player_class != PC_SNIPER) { + zoomed_in = 0; + } + + if (zoomed_in) { + setviewprop(VF_AFOV, cvar("fov")/3); + setsensitivityscaler(1/3); + } else { + setviewprop(VF_AFOV, cvar("fov")); + setsensitivityscaler(1); + } +} + +float last_pmove_onground; +float last_vel_z; +float last_clientcommandframe; +// REQUIRES: Must be called after _Sync_ServerCommandFrame. +void _Sync_ClientCommandFrame() { + // Client command frames are regenerated beyond the server frame, so we + // cannot check that we have not seen this client command frame alone. + if (last_servercommandframe == servercommandframe && + last_clientcommandframe == clientcommandframe) + return; + last_clientcommandframe = clientcommandframe; + + local float paused = getstatf(STAT_PAUSED); + local float health = getstatf(STAT_HEALTH); + + if (pmove_onground && health > 0 && !paused) { + // The pmove_vel_z < 180 check makes sure you're not sliding + if (input_buttons & BUTTON2 && pmove_vel_z < 180) { + localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + } + + if (!last_pmove_onground) { + if (last_vel_z < -650) { + localsound("player/land2.wav", CHAN_AUTO, 1); + } else if (last_vel_z < -300) { + localsound("player/land.wav", CHAN_AUTO, 1); + } + } + } + + last_vel_z = pmove_vel_z; + last_pmove_onground = pmove_onground; +} + +// Called for each {client, server} command frame, ensures globals are +// synchronized with server and predicted state. +void Sync_GameState() { + _Sync_ServerCommandFrame(); + _Sync_ClientCommandFrame(); +} From 049d4de3033111fa78155a26ae5cfbccf7ece56d Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Sep 2022 01:53:48 -0700 Subject: [PATCH 1585/2474] Rate-limit feign and remove dead code Introduces a rate limit, set by localinfo feign_rate_limit [default=5s] which bounds how frequently you can manually feign. Feigning in reaction to damage ignores this limit (e.g. you can manually feign, unfeign, take damage, and refeign), but it will still count towards your next manual feign. Also, delete duplicate CF implementation of Feign. Both implementations were previously being used. If this breaks anything we'll have to figure out how they're different. --- ssqc/client.qc | 3 + ssqc/combat.qc | 2 +- ssqc/menu.qc | 6 +- ssqc/qw.qc | 2 + ssqc/spy.qc | 164 +++++------------------------------------------- ssqc/tfort.qc | 1 + ssqc/weapons.qc | 5 +- 7 files changed, 29 insertions(+), 154 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index e1d2d59d..9daa6a5a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -531,6 +531,9 @@ void () DecodeLevelParms = { // print fake death message when feigning death [on] feign_msg = CF_GetSetting("fm", "feign_msg", "on"); + // rate limit on feign + feign_rate_limit = CF_GetSetting("frl", "feign_rate_limit", "5"); + // turn off spy [off] spy_off = CF_GetSetting("spy", "spy", "off"); diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 1278d2f6..866b985d 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -682,7 +682,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, } if (self.feign_next_damage && !self.is_feigning){ - FO_Spy_Feign(0); + FO_Spy_Feign(0, /* ignore rate-limit */ 1); } self = oldself; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 294e6400..33541b7b 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -4,11 +4,9 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin; void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor; -void (float issilent) CF_Spy_FeignDeath; -void (float issilent) FO_Spy_Feign; +void (float issilent, float force) FO_Spy_Feign; void () FO_Spy_FeignOnNextDamage; void () FO_Spy_Unfeign; -void (float issilent) CF_Spy_FeignDeath; void () CF_Spy_Invisible; void () CF_Spy_DisguiseStop; @@ -586,7 +584,7 @@ void (float inp) Menu_Spy_Input = { } else if (inp == 2 && !invis_only) { FO_Spy_DisguiseLast(self); } else if (inp == 3) { - CF_Spy_FeignDeath(1); + FO_Spy_Feign(1, 0); if (self.is_feigning) { Menu_Spy(self); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bbc6ca2d..65d6ed0e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -401,6 +401,7 @@ float num_world_flames; .string undercover_name; .entity attacked_by; // Used by spy feign death to produce a fake death message .float feignmsg; // Stores the death message to be used when feigning +.float next_feign_time; // timestamp for when feign is next allowed float live_camera; .float camdist; @@ -560,6 +561,7 @@ float fo_hwguy; float feign_air; float feign_pack; float feign_msg; +float feign_rate_limit; float scoutdash; float sniperreload; float spawnfull; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 0ba3bee0..19339d12 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -443,11 +443,18 @@ void (float issilent) FO_Spy_ToggleFeign = { } } -void (float issilent) FO_Spy_Feign = { +void (float issilent, float force) FO_Spy_Feign = { if (self.is_feigning) { return; } + if (!force && time <= self.next_feign_time) { + sprint(self, PRINT_HIGH, sprintf( + "%0.1f seconds until you have enough fake-blood to feign again!\n", + self.next_feign_time - time)); + return; + } + // don't allow feign if spy is in air and air feigning is disallowed if (!feign_air && !(self.flags & FL_ONGROUND)) { return; @@ -460,6 +467,9 @@ void (float issilent) FO_Spy_Feign = { return; } + // Success. We will feign. + self.next_feign_time = time + feign_rate_limit; + // don't check for team color cheat for 5 seconds self.immune_to_check = time + 5; @@ -617,152 +627,12 @@ void () FO_Spy_Unfeign = { } } -void (float issilent) CF_Spy_FeignDeath = { - local string deathstring; - local float area_check; - local float i; - local entity te, spy; - - if (self.is_feigning) { - // check area for obstructing entities - area_check = Spy_CheckArea(self); - - // nothing on top => unfeign - if (!area_check) { - - // set size of player model - setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); - - // set view height - self.view_ofs = '0 0 22'; - - // unset feign variables - self.is_feigning = 0; - self.feign_areachecked = 0; - - // load saved weapon state and set current ammo - W_WeaponState_Load(self, 0); - W_SetCurrentAmmo(self); - - // allow spy to move again - self.movetype = MOVETYPE_WALK; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - - // set revive animation - i = 1 + floor(random() * 5); - if (i == 1) { - spy_upb1(); - } else if (i == 2) { - spy_upc1(); - } else if (i == 3) { - spy_upd1(); - } else { - spy_upe1(); - } - - // something is on top of spy - } else if (area_check == 1) { - sprint(self, PRINT_HIGH, "You cannot get up with something on top of you\n"); - } else if (area_check == 2) { - sprint(self, PRINT_HIGH, "You cannot get up while someone is standing on you\n"); - } - } else { - - // don't allow feign if spy is in air and air feigning is disallowed - if (!feign_air && !(self.flags & FL_ONGROUND)) { - sprint(self, PRINT_HIGH, "You cannot feign while you are airborne\n"); - return; - } - - // check area for feigned spy on the ground - area_check = Spy_CheckArea(self); - if (area_check == 3) { - sprint(self, PRINT_HIGH, "You cannot feign on top of another spy\n"); - return; - } - - // don't check for team color cheat for 5 seconds - self.immune_to_check = time + 5; - - // set movetype to toss - self.movetype = MOVETYPE_TOSS; - - // this timer will make sure the spy falls - // to the ground when possible - spy = spawn(); - spy.classname = "airtimer"; - spy.owner = self; - spy.think = CF_Spy_AirThink; - spy.nextthink = time + 0.1; - // set spy feign variables - self.is_feigning = 1; - Attack_Finished(0.8); - self.invisible_finished = 0; - // set precached model index - self.modelindex = modelindex_player; - // set size of player model - setsize(self, '-16 -16 -24', '16 16 -16'); - // set weapon state and remove weapon viewmodel - W_WeaponState_Save(self); - self.weaponmodel = ""; - self.weaponframe = 0; - // set view height to ground - self.view_ofs = '0 0 4'; - // do extra stuff if feign is not silent feign - if (issilent == 0) { - // make a death sound - DeathSound(); - // drop an empty backpack (if this is not disabled in settings) - if (feign_pack) - Spy_DropBackpack(); - - // print feign message (if this is not disabled in settings) - if (feign_msg) { - deathstring = GetDeathMessage(self, self.attacked_by, self.feignmsg); - bprint(PRINT_MEDIUM, deathstring); - KillSound(self, self.attacked_by); - } - // set movement speed to 0 if currently in the air to disable manipulation of trajectory - if (!(self.flags & FL_ONGROUND)) - self.maxspeed = 0; - } - - // drop flag if spy is carrying it - te = find(world, classname, "item_tfgoal"); - while (te) { - if (te.owner == self) { - if (!(te.goal_activation & TFGI_KEEP) || self.has_disconnected == 1) - tfgoalitem_RemoveFromPlayer(te, self, 0); - if (CTF_Map == 1) { - if (te.goal_no == 1) - bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sblue\s flag!\n"); - else if (te.goal_no == 2) - bprint(PRINT_HIGH, self.netname, Q" \slost\s the \sred\s flag!\n"); - } - } - te = find(te, classname, "item_tfgoal"); - } - // die with axe equipped if carrying axe, medikit, knife or spanner - if (self.weapon <= WEAP_AXE) { - spy_die_ax1(); - return; - } - - // randomize death animation - i = 1 + floor((random() * 6)); - if (i == 1) - spy_diea1(); - else if (i == 2) - spy_dieb1(); - else if (i == 3) - spy_diec1(); - else if (i == 4) - spy_died1(); - else - spy_diee1(); - } -}; +void (float issilent) FO_Spy_FeignCmd = { + if (self.is_feigning) + FO_Spy_Unfeign(); + else + FO_Spy_Feign(issilent, 0); +} void () CF_Spy_Invisible = { local entity e_timer; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2839f45c..c8e2b157 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1568,6 +1568,7 @@ void () TeamFortress_SetEquipment = { self.airblast_cooldown = 0; self.is_undercover = 0; self.is_feigning = 0; + self.next_feign_time = 0; self.is_unabletospy = 0; self.is_concussed = 0; self.disguise_skin = 0; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 847c1db2..fb686118 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -64,6 +64,7 @@ void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; void () TeamFortress_Discard; void () TeamFortress_Discard_DropAmmo; +void (float issilent) FO_Spy_FeignCmd; void (float issilent) FO_Spy_ToggleFeign; void () FO_Engineer_ToggleDispenser; void () FO_Engineer_ToggleSentry; @@ -3147,11 +3148,11 @@ void () ImpulseCommands = { else Menu_Spy_Skin(); } else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) - CF_Spy_FeignDeath(0); + FO_Spy_FeignCmd(0); else if ((self.impulse == TF_SPY_DIE_ON) && (self.playerclass == PC_SPY)) { FO_Spy_FeignOnNextDamage(); } else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) - CF_Spy_FeignDeath(1); + FO_Spy_FeignCmd(1); else if (self.impulse == TF_DISGUISE_RESET && self.playerclass == PC_SPY) { CF_Spy_ChangeSkin(self, 8); CF_Spy_ChangeColor(self, self.team_no); From a66d6066927cb45b298d10e7cdc8b973dc6b7d46 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Sep 2022 12:37:24 -0700 Subject: [PATCH 1586/2474] Fix discard DOS Discard turns out to have a user triggerable DOS where we always create the entity, even if there is nothing to discard. Spamming this you can fairly quickly crash a server by exhausting progs VM memory (32mb). --- ssqc/actions.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 024e3bde..99d2b3e8 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -75,6 +75,7 @@ void () TeamFortress_Discard = { default: } if ((newmis.ammo_rockets + newmis.ammo_cells + newmis.ammo_nails + newmis.ammo_shells) == 0) { + remove(newmis); return; } From 180195b85ffc23dc02045448cc2a2f31756c1804 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Sep 2022 15:36:10 -0700 Subject: [PATCH 1587/2474] Add precise priming synchronization For CSQC enabled clients we synchronize the grenade timer with the server's notion of when the grenade was actually primed to eliminate ping dependency. Augment this by transmitting the actual time the grenade was primed. This both improves accuracy and allows future client-side physics for grenade jump emulation. We introduce a temporary fo_grentimer == 3 mode which uses the new prediction for the offset to prime, while maintaining RTT/2 for throwgren. --- csqc/events.qc | 36 ++++++++++++++++++++++-------------- ssqc/status.qc | 1 + 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 5955326c..ee4a3c2b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,5 +1,5 @@ void ParseSBAR(); -void ParseGrenPrimed(float grentype, float timertype); +void ParseGrenPrimed(float grentype, float primetime); void AddGrenTimer(float grentype, float offset); void AddSilentGrenTimer(float grentype, float offset); void StartGrenTimer(float slot, float grentype, float offset); @@ -105,8 +105,8 @@ void() CSQC_Parse_Event = { break; case MSG_GRENPRIMED: float grentype = readfloat(); - float timertype = cvar(FOCMD_GRENTIMER); - ParseGrenPrimed(grentype, timertype); + float primetime = readfloat(); + ParseGrenPrimed(grentype, primetime); break; case MSG_GRENTHROWN: ApplyTransparencyToGrenTimer(); @@ -329,21 +329,29 @@ void PlayGrenTimer(float offset) { soundupdate(self, channel, sound, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); } -void ParseGrenPrimed(float grentype, float timertype) { - if(timertype == 0) { - AddSilentGrenTimer(grentype, 0); - return; - } +void ParseGrenPrimed(float grentype, float primetime) { + local float timertype = cvar(FOCMD_GRENTIMER); - if(timertype == 1) { + if (timertype == 0) { + AddSilentGrenTimer(grentype, 0); + } else if(timertype == 1) { AddGrenTimer(grentype, 0); - return; - } + } else if (timertype == 2) { + // We need to offset our sound by 2 RTT/2s: + // The first is the already occurred delay to receive notification. + // The second is the will-occur delay in sending throwgren back. + local float offset = getplayerkeyfloat(player_localnum, + INFOKEY_P_PING)/1000; - if(timertype == 2) { - local float offset = getplayerkeyfloat(player_localnum, INFOKEY_P_PING)/1000; AddGrenTimer(grentype, offset); - return; + } else if (timertype == 3) { + // As above, but uses precise accounting for the already occurred delay. + // Will eventually replace type==2. + local float offset_prime = time - primetime; + local float offset_throw = getplayerkeyfloat(player_localnum, + INFOKEY_P_PING)/1000 / 2; + + AddGrenTimer(grentype, offset_prime + offset_throw); } } diff --git a/ssqc/status.qc b/ssqc/status.qc index c46a5b69..07275e42 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -803,6 +803,7 @@ void UpdateClientGrenadePrimed(entity pl, float grentype) = { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); WriteFloat(MSG_MULTICAST, grentype); + WriteFloat(MSG_MULTICAST, time); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } From 6f48a7118b71dbe6f04903f19a800d96a16e2910 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Sep 2022 17:30:10 -0700 Subject: [PATCH 1588/2474] Make csqc death messages reliable and maintain more state Use a reliable transmit for death messages as well as logging the time of last death. This allows grenade timers to be more reliably stopped and allows for stronger ordering of events which might be out of order (e.g. prime as dying). --- csqc/csextradefs.qc | 1 + csqc/events.qc | 4 ++++ ssqc/status.qc | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 74b6739f..37b4db82 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -536,6 +536,7 @@ float jump_counter; float grentimer_waiting; float last_pmove_onground; float last_vel_z; +float last_death_time; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/events.qc b/csqc/events.qc index ee4a3c2b..da2cec7b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -112,6 +112,7 @@ void() CSQC_Parse_Event = { ApplyTransparencyToGrenTimer(); break; case MSG_PLAYERDIE: + last_death_time = readfloat(); StopGrenTimers(); break; case MSG_CLIENT_MENU: @@ -332,6 +333,9 @@ void PlayGrenTimer(float offset) { void ParseGrenPrimed(float grentype, float primetime) { local float timertype = cvar(FOCMD_GRENTIMER); + if (primetime < last_death_time) + return; + if (timertype == 0) { AddSilentGrenTimer(grentype, 0); } else if(timertype == 1) { diff --git a/ssqc/status.qc b/ssqc/status.qc index 07275e42..b17b7821 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -822,7 +822,8 @@ void UpdateClientPlayerDie(entity pl) = { msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_PLAYERDIE); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + WriteFloat(MSG_MULTICAST, time); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } void UpdateClientIDString(entity pl) { From 91a5d09bc50bede94d8927b1a65a41f06f954634 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 11 Sep 2022 01:46:51 -0700 Subject: [PATCH 1589/2474] Implement precise grenade throwing Up to this point, all version of Team Fortress (including FortressOne) have implemented grenade throwing using a test which executes every 100ms. This introduces a random input-delay (of up to 100ms) dependent on when you press throw relative to the next timer evaluation. This introduces a new, 'precise' timing mode that throws grenades immediately when instructed. We reserve the final 100ms before the grenade explodes. Previously, it was random whether or not you would be able to throw in this time. Now it is deterministic, if you hold a grenade to this point, you are along for the ride. This is to allow future client-side prediction on knockback to function reliably (as this allows us to predict the grenade explosion position from player position when held more reliably). Note that this also explains other behaviors, such as inconsistency in airblast hitting thrown grenades when tightly timed. In this case, the input lag on throw was allowing the grenade throw to actually be re-ordered with the airblast, so that it was thrown after -- even when pressed before. To enable: setinfo precise_grenades on or setinfo pg on --- README.md | 1 + ssqc/qw.qc | 3 + ssqc/tfort.qc | 326 ++++++++++++++++++++++++++++++-------------------- 3 files changed, 199 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index 1defa82e..f5fbbb7c 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New features ------ +* `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. * Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bbc6ca2d..39b11b63 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -757,6 +757,9 @@ float canlog; float FO_FlashDimension; .float old_dimension_seen; +// precise grenades +.entity grenade_timer; + // allow for default goal state .float default_group_no; // classes to search for in goal remove, restore etc diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2839f45c..501ab886 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -776,8 +776,6 @@ void () TeamFortress_ShowTF = { } }; -void () TeamFortress_GrenadePrimed; - void () GrenadeTimer = { self.heat = self.heat - 1; self.nextthink = time + 1; @@ -789,6 +787,137 @@ void () GrenadeTimer = { } }; +void (entity timer) FO_SpawnThrownGrenade = { + local entity user = timer.owner; + user.tfstate &= ~(TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING); + + if (grentimers && infokeyf(user, INFOKEY_P_CSQCACTIVE)) { + UpdateClientGrenadeThrown(user); + } + + FO_Sound(user, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + KickPlayer(-1, user); + newmis = spawn(); + newmis.owner = user; + newmis.movetype = 10; + newmis.solid = 2; + newmis.classname = "grenade"; + makevectors(user.v_angle); + if (user.deadflag) { + if (timer.weapon == GR_TYPE_NORMAL) + newmis.velocity = '0 0 200'; + else + return; + } else if (user.v_angle_x) { + newmis.velocity = + v_forward * 600 + v_up * 200 + crandom() * v_right * 10 + + crandom() * v_up * 10; + } else { + newmis.velocity = aim(user, 10000); + newmis.velocity = newmis.velocity * 600; + newmis.velocity_z = 200; + } + newmis.angles = vectoangles(newmis.velocity); + newmis.think = SUB_Null; + newmis.nextthink = timer.heat; + + if (timer.weapon == GR_TYPE_NORMAL) { + newmis.touch = NormalGrenadeTouch; + newmis.think = NormalGrenadeExplode; + newmis.grenadename = "normalgrenade"; + newmis.skin = 0; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/hgren2.mdl"); + } else if (timer.weapon == GR_TYPE_CONCUSSION) { + newmis.touch = ConcussionGrenadeTouch; + newmis.think = ConcussionGrenadeExplode; + newmis.grenadename = "concussiongrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/hgren2.mdl"); + } else if (timer.weapon == GR_TYPE_BLAST) { + newmis.touch = BlastGrenadeTouch; + newmis.think = BlastGrenadeExplode; + newmis.grenadename = "blastgrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/blastgren.mdl"); + } else if (timer.weapon == GR_TYPE_NAIL) { + newmis.touch = NailGrenadeTouch; + newmis.think = NailGrenadeExplode; + newmis.grenadename = "nailgrenade"; + newmis.skin = 1; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (timer.weapon == GR_TYPE_SHOCK) { + newmis.touch = ShockGrenadeTouch; + newmis.think = ShockGrenadeExplode; + newmis.grenadename = "shockgrenade"; + newmis.skin = 1; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (timer.weapon == GR_TYPE_BURST) { + newmis.touch = BurstGrenadeTouch; + newmis.think = BurstGrenadeExplode; + newmis.grenadename = "burstgrenade"; + newmis.skin = 1; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (timer.weapon == GR_TYPE_MIRV) { + newmis.touch = MirvGrenadeTouch; + newmis.think = MirvGrenadeExplode; + newmis.grenadename = "mirvgrenade"; + newmis.skin = 0; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (timer.weapon == GR_TYPE_NAPALM) { + newmis.touch = NapalmGrenadeTouch; + newmis.think = NapalmGrenadeExplode; + newmis.grenadename = "napalmgrenade"; + newmis.skin = 2; + newmis.avelocity = '0 300 0'; + FO_SetModel(newmis, "progs/biggren.mdl"); + } else if (timer.weapon == GR_TYPE_FLARE) { + newmis.touch = FlareGrenadeTouch; + newmis.weapon = timer.team_no; + newmis.think = FlareGrenadeExplode; + newmis.grenadename = "flaregrenade"; + newmis.skin = 1; + newmis.avelocity = '300 300 300'; + newmis.mdl = "flare"; + FO_SetModel(newmis, "progs/flare.mdl"); + } else if (timer.weapon == GR_TYPE_GAS) { + newmis.touch = GasGrenadeTouch; + newmis.think = GasGrenadeExplode; + newmis.grenadename = "gasgrenade"; + newmis.skin = 3; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/grenade2.mdl"); + } else if (timer.weapon == GR_TYPE_EMP) { + newmis.touch = EMPGrenadeTouch; + newmis.think = EMPGrenadeExplode; + newmis.grenadename = "empgrenade"; + newmis.skin = 4; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/grenade2.mdl"); + } else if (timer.weapon == GR_TYPE_CALTROP) { + newmis.touch = CanisterTouch; + newmis.think = ScatterCaltrops; + newmis.grenadename = "caltropgrenade"; + newmis.skin = 0; + newmis.avelocity = '0 0 0'; + } else if (timer.weapon == GR_TYPE_FLASH) { + newmis.touch = FlashGrenadeTouch; + newmis.think = FlashGrenadeExplode; + newmis.grenadename = "flashgrenade"; + newmis.skin = 0; + newmis.avelocity = '300 300 300'; + FO_SetModel(newmis, "progs/flashgren.mdl"); + } + setsize(newmis, '0 0 0', '0 0 0'); + setorigin(newmis, user.origin); +} + void (float inp) TeamFortress_PrimeThrowGrenade = { if ((self.tfstate & TFSTATE_GRENPRIMED) || (self.tfstate & TFSTATE_GRENTHROWING)) @@ -802,6 +931,10 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { } }; +void () TeamFortress_GrenadePrimedThink; +void () FO_PreciseGrenadeThink; +float () FO_UsePreciseGrenades; + void (float inp) TeamFortress_PrimeGrenade = { local float gtype; local string gs; @@ -956,7 +1089,7 @@ void (float inp) TeamFortress_PrimeGrenade = { return; } } - self.tfstate = self.tfstate | 1; + self.tfstate = self.tfstate | TFSTATE_GRENPRIMED; tGrenade = spawn(); tGrenade.owner = self; tGrenade.weapon = gtype; @@ -992,10 +1125,14 @@ void (float inp) TeamFortress_PrimeGrenade = { } } - tGrenade.think = TeamFortress_GrenadePrimed; + if (FO_UsePreciseGrenades()) + tGrenade.think = FO_PreciseGrenadeThink; + else + tGrenade.think = TeamFortress_GrenadePrimedThink; + self.grenade_timer = tGrenade; }; -void () TeamFortress_GrenadePrimed = { +void () TeamFortress_GrenadePrimedThink = { local entity user; user = self.owner; @@ -1012,141 +1149,68 @@ void () TeamFortress_GrenadePrimed = { if (!(user.tfstate & TFSTATE_GRENPRIMED)) dprint("GrenadePrimed logic error\n"); - user.tfstate = user.tfstate - (user.tfstate & TFSTATE_GRENPRIMED); - user.tfstate = user.tfstate - (user.tfstate & TFSTATE_GRENTHROWING); - if (grentimers && infokeyf(user, INFOKEY_P_CSQCACTIVE)) { - UpdateClientGrenadeThrown(user); + FO_SpawnThrownGrenade(self); + dremove(self); +}; + +float () FO_UsePreciseGrenades = { + return FO_GetUserSetting(self, "precise_grenades", "pg", "off"); +} + +void () FO_PreciseGrenadeThink = { + local entity user = self.owner; + + // Claim: These cases do not exist for FO; to be removed once proven true. + if (user.deadflag || user.has_disconnected) { + dprint("BUG: saw deadflag / disconnected in PreciseGrenadePrimed\n"); + dremove(self); + return; } - FO_Sound(user, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); - KickPlayer(-1, user); - newmis = spawn(); - newmis.owner = user; - newmis.movetype = 10; - newmis.solid = 2; - newmis.classname = "grenade"; - makevectors(user.v_angle); - if (user.deadflag) { - if (self.weapon == GR_TYPE_NORMAL) - newmis.velocity = '0 0 200'; - else - return; - } else if (user.v_angle_x) { - newmis.velocity = - v_forward * 600 + v_up * 200 + crandom() * v_right * 10 + - crandom() * v_up * 10; + // This timer fires at most 2 times: + // - Once at 0.8s, this is the first time you are allowed to throw. We catch + // GRENTHROWING which latches this state for throws before this point. + // - A second time at the grenade's expiration for the case it was not thrown. + // We remove the timer if the client throws before expiration. + if (time < self.heat) { + if (user.tfstate & TFSTATE_GRENTHROWING) { // Latched throw case. + FO_SpawnThrownGrenade(self); + dremove(self); + } else { + // If this fires, we never threw. + self.nextthink = self.heat; + } } else { - newmis.velocity = aim(user, 10000); - newmis.velocity = newmis.velocity * 600; - newmis.velocity_z = 200; + TeamFortress_ExplodePerson(); + dremove(self); } - newmis.angles = vectoangles(newmis.velocity); - newmis.think = SUB_Null; - newmis.nextthink = self.heat; +} - if (self.weapon == GR_TYPE_NORMAL) { - newmis.touch = NormalGrenadeTouch; - newmis.think = NormalGrenadeExplode; - newmis.grenadename = "normalgrenade"; - newmis.skin = 0; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } else if (self.weapon == GR_TYPE_CONCUSSION) { - newmis.touch = ConcussionGrenadeTouch; - newmis.think = ConcussionGrenadeExplode; - newmis.grenadename = "concussiongrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } else if (self.weapon == GR_TYPE_BLAST) { - newmis.touch = BlastGrenadeTouch; - newmis.think = BlastGrenadeExplode; - newmis.grenadename = "blastgrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/blastgren.mdl"); - } else if (self.weapon == GR_TYPE_NAIL) { - newmis.touch = NailGrenadeTouch; - newmis.think = NailGrenadeExplode; - newmis.grenadename = "nailgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_SHOCK) { - newmis.touch = ShockGrenadeTouch; - newmis.think = ShockGrenadeExplode; - newmis.grenadename = "shockgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_BURST) { - newmis.touch = BurstGrenadeTouch; - newmis.think = BurstGrenadeExplode; - newmis.grenadename = "burstgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_MIRV) { - newmis.touch = MirvGrenadeTouch; - newmis.think = MirvGrenadeExplode; - newmis.grenadename = "mirvgrenade"; - newmis.skin = 0; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_NAPALM) { - newmis.touch = NapalmGrenadeTouch; - newmis.think = NapalmGrenadeExplode; - newmis.grenadename = "napalmgrenade"; - newmis.skin = 2; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_FLARE) { - newmis.touch = FlareGrenadeTouch; - newmis.weapon = self.team_no; - newmis.think = FlareGrenadeExplode; - newmis.grenadename = "flaregrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - newmis.mdl = "flare"; - FO_SetModel(newmis, "progs/flare.mdl"); - } else if (self.weapon == GR_TYPE_GAS) { - newmis.touch = GasGrenadeTouch; - newmis.think = GasGrenadeExplode; - newmis.grenadename = "gasgrenade"; - newmis.skin = 3; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/grenade2.mdl"); - } else if (self.weapon == GR_TYPE_EMP) { - newmis.touch = EMPGrenadeTouch; - newmis.think = EMPGrenadeExplode; - newmis.grenadename = "empgrenade"; - newmis.skin = 4; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/grenade2.mdl"); - } else if (self.weapon == GR_TYPE_CALTROP) { - newmis.touch = CanisterTouch; - newmis.think = ScatterCaltrops; - newmis.grenadename = "caltropgrenade"; - newmis.skin = 0; - newmis.avelocity = '0 0 0'; - } else if (self.weapon == GR_TYPE_FLASH) { - newmis.touch = FlashGrenadeTouch; - newmis.think = FlashGrenadeExplode; - newmis.grenadename = "flashgrenade"; - newmis.skin = 0; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/flashgren.mdl"); +void () FO_ThrowPreciseGrenade = { + local entity timer = self.grenade_timer; + if (timer.nextthink != timer.heat || timer.heat - time < 0.1) { + // We do not allow throwing within the first second, or the last 0.1. + // The former is a priming time, the latter is so that client side + // knockback will be able to reliably predict whether a grenade was held + // (e.g. gren jump) or thrown up to ~200ms ping. + // + // In the first case, we've set THROWING so think will handle. + // In the second, buckle up. + } else { + FO_SpawnThrownGrenade(timer); + dremove(timer); } - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, user.origin); - dremove(self); -}; +} void () TeamFortress_ThrowGrenade = { - if (!(self.tfstate & TFSTATE_GRENPRIMED)) + if (!(self.tfstate & (TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING))) return; - self.tfstate = self.tfstate | TFSTATE_GRENTHROWING; + self.tfstate |= TFSTATE_GRENTHROWING; + // While this is controlled by localinfo, it's a per-grenade value. + if (FO_UsePreciseGrenades() && + self.grenade_timer.think == FO_PreciseGrenadeThink) + FO_ThrowPreciseGrenade(); }; void () TeamFortress_GrenadeSwitch = { @@ -2876,7 +2940,7 @@ void () TeamFortress_AssaultWeapon = { void () TeamFortress_ExplodePerson = { local entity te; - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & 1); + self.owner.tfstate &= ~(TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING); KickPlayer(-2, self.owner); newmis = spawn(); From 3e8336b5530ce47ce320d2b63b43957f78ee0934 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Sep 2022 00:31:09 -0700 Subject: [PATCH 1590/2474] Reduce per-frame overhead A large amount of game logic is currently overloaded with per-frame rendering. Move this into independent synchronization that tries to follow server updates more directly. wayland won't let me escape vsync, but limited profiling suggests this is good for at least 1-2% cpu reduction from infobuf string conversion alone at higher framerates. --- csqc/main.qc | 139 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 55e24255..3a4e0ebb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -13,6 +13,7 @@ void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); float IsValidToUseGrenades(); +void Sync_GameState(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -115,25 +116,8 @@ noref void() CSQC_WorldLoaded = { noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; - team_no = getstatf(STAT_TEAMNO); - is_observer = FALSE; - if (team_no == 0) - is_observer = TRUE; - player_class = getstatf(STAT_CLASS); - SBAR.ReadyStatus = getstatf(STAT_FLAGS); - oldhealth = getstatf(STAT_HEALTH); - is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); - if (is_spectator) - is_observer = FALSE; SBAR.Hint = ""; thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); - //if(nextoriginupdate < time) { - // speed = vlen([thisorigin.x, thisorigin.y] - [lastorigin.x, lastorigin.y]) * 10; - // lastorigin = thisorigin; - // nextoriginupdate = time + 0.1; - //} - vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; - speed = sqrt(vel.x * vel.x + vel.y * vel.y); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! @@ -141,27 +125,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if(cvar(FOCMD_FTE_HUD) != 1) { setproperty(VF_DRAWENGINESBAR, 1); /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ } - //setviewprop(VF_ORIGIN, '0 0 0'); //view position of the scene (after view_ofs effects). - //setviewprop(VF_ANGLES, '0 0 0'); //override the view angles. input will work as normal. other players will see your player as normal. your screen will just be pointing a different direction. - //setviewprop(VF_DRAWWORLD, 1); //whether the world entity should be drawn. set to 0 if you want a completely empty scene. - //setviewprop(VF_MIN, '0 0 0'); //top-left coord (x,y) of the scene viewport in virtual pixels (or annoying physical pixels in dp). - //setviewprop(VF_SIZE, [width, height, 0]); //virtual size (width,height) of the scene viewport in virtual pixels (or annoying physical pixels in dp). - //setviewprop(VF_AFOV, cvar("fov")); //note: fov_x and fov_y control individual axis. afov is general - //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. - - local float health = getstatf(STAT_HEALTH); - - if (health <= 0 || player_class != PC_SNIPER) { - zoomed_in = 0; - } - - if (zoomed_in) { - setviewprop(VF_AFOV, cvar("fov")/3); - setsensitivityscaler(1/3); - } else { - setviewprop(VF_AFOV, cvar("fov")); - setsensitivityscaler(1); - } addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view @@ -171,26 +134,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); - - local float paused = getstatf(STAT_PAUSED); - - if (pmove_onground && health > 0 && !paused) { - // The pmove_vel_z < 180 check makes sure you're not sliding - if (input_buttons & BUTTON2 && pmove_vel_z < 180) { - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); - } - - if (!last_pmove_onground) { - if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_AUTO, 1); - } else if (last_vel_z < -300) { - localsound("player/land.wav", CHAN_AUTO, 1); - } - } - } - - last_vel_z = pmove_vel_z; - last_pmove_onground = pmove_onground; } noref float(string cmd) CSQC_ConsoleCommand = { @@ -461,6 +404,8 @@ noref void CSQC_Input_Frame() { if (player_class == PC_SNIPER && keydowns & BUTTON3) { zoomed_in = !zoomed_in; } + + Sync_GameState(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -498,3 +443,81 @@ void StopGrenTimers() { FO_Hud_Grentimers[i].icon_index = 0; } } + +float last_servercommandframe; +void _Sync_ServerCommandFrame() { + // Server command frames are monotonically unique, we can skip processing + // unless there is new state. + if (last_servercommandframe == servercommandframe) + return; + last_servercommandframe = servercommandframe; + + team_no = getstatf(STAT_TEAMNO); + is_observer = FALSE; + if (team_no == 0) + is_observer = TRUE; + player_class = getstatf(STAT_CLASS); + SBAR.ReadyStatus = getstatf(STAT_FLAGS); + oldhealth = getstatf(STAT_HEALTH); + is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); + if (is_spectator) + is_observer = FALSE; + + vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), + getstatf(STAT_VELOCITY_Z)]; + speed = sqrt(vel.x * vel.x + vel.y * vel.y); + + local float health = getstatf(STAT_HEALTH); + if (health <= 0 || player_class != PC_SNIPER) { + zoomed_in = 0; + } + + if (zoomed_in) { + setviewprop(VF_AFOV, cvar("fov")/3); + setsensitivityscaler(1/3); + } else { + setviewprop(VF_AFOV, cvar("fov")); + setsensitivityscaler(1); + } +} + +float last_pmove_onground; +float last_vel_z; +float last_clientcommandframe; +// REQUIRES: Must be called after _Sync_ServerCommandFrame. +void _Sync_ClientCommandFrame() { + // Client command frames are regenerated beyond the server frame, so we + // cannot check that we have not seen this client command frame alone. + if (last_servercommandframe == servercommandframe && + last_clientcommandframe == clientcommandframe) + return; + last_clientcommandframe = clientcommandframe; + + local float paused = getstatf(STAT_PAUSED); + local float health = getstatf(STAT_HEALTH); + + if (pmove_onground && health > 0 && !paused) { + // The pmove_vel_z < 180 check makes sure you're not sliding + if (input_buttons & BUTTON2 && pmove_vel_z < 180) { + localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + } + + if (!last_pmove_onground) { + if (last_vel_z < -650) { + localsound("player/land2.wav", CHAN_AUTO, 1); + } else if (last_vel_z < -300) { + localsound("player/land.wav", CHAN_AUTO, 1); + } + } + } + + last_vel_z = pmove_vel_z; + last_pmove_onground = pmove_onground; +} + +// Called for each {client, server} command frame, ensures globals are +// synchronized with server and predicted state. +void Sync_GameState() { + _Sync_ServerCommandFrame(); + _Sync_ClientCommandFrame(); +} From 69ad90aba2d51fcf9d6b515aa4e9baac93ccb63d Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 12 Sep 2022 00:31:19 -0700 Subject: [PATCH 1591/2474] Fix not-exploding napalm grenades (and eliminate grentimer effects) A long standing bug is that napalm grenades occasionally do not explode properly, leaving glowing, stuck entities. This turns out to be a race between several pieces of the code. 1. When the grenade initially explodes render a flare and start a timer program for the subsequent napalm explosions ("grentimer"). 2. When the program in (1) begins 100ms later, it tries to track the number of napalm (or gas) grenades active for the player in question. 3. When the player dies, conditional on there being no active napalm grenades we try to reclaim these timers. It turns out that when (3) occurs between the 100ms between (1) and (2) that the accounting can be incorrect and we'll remove the timer, but this incorrectly eliminated the subsequent explosion and left the grenade pinned until the ent was reclaimed (since the timer also owned its removal). There is no need for either: (1) The extra timer entity (2) The existing spam tracking For (1) we can extend the think state machine on the existing entity for both napalm and gas, this also allows us to completely eliminate all the clean-up complexity that (3) adds [now we can just remove grenades, rather than worrying about grenades also parenting area of effect timers that we also have to remove]. We throw (2) out for now. There are cleaner ways to write it if it's needed and it wasn't even working for gas grenades (because someone changed the timer name at some point). --- ssqc/pyro.qc | 107 +++++++++++++++++++---------------------------- ssqc/quadmode.qc | 6 --- ssqc/qw.qc | 2 - ssqc/spy.qc | 46 ++++++-------------- ssqc/tfort.qc | 19 +++------ ssqc/weapons.qc | 39 ----------------- 6 files changed, 61 insertions(+), 158 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 7289f068..b802aaca 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -134,7 +134,23 @@ void () NapalmGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () NapalmGrenadeNetThink = { +void () NapalmGrenadeExplode2; + +// Explode1 is the initial "flare" before we start emitting dmg. +// Explode2 handles the subsequent explosions. +void () NapalmGrenadeExplode1 = { + local entity head; + + FO_Sound(self, CHAN_AUTO, "weapons/flmgrexp.wav", 1, ATTN_NORM); + traceline(self.origin, self.origin, 1, self); + if (trace_inwater != 1) + self.effects = self.effects | EF_DIMLIGHT; + self.think = NapalmGrenadeExplode2; + self.nextthink = time + 0.1; + self.heat = 0; +}; + +void () NapalmGrenadeExplode2 = { local entity head; local entity te; @@ -153,82 +169,45 @@ void () NapalmGrenadeNetThink = { break; } - if (self.heat == 0) { - self.owner.no_active_napalm_grens = - self.owner.no_active_napalm_grens + 1; - if (self.owner.no_active_napalm_grens > 2) { - te = find(world, classname, "grentimer"); - while (te) { - if ((te.owner == self.owner) && - (te.no_active_napalm_grens == 1)) { - te.weapon = DMSG_FLAME; - te.think = RemoveGrenade; - te.nextthink = time + 0.1; - } - te = find(te, classname, "grentimer"); - } - } - self.no_active_napalm_grens = self.owner.no_active_napalm_grens; - } self.nextthink = time + 1; - self.origin = self.enemy.origin; makevectors(self.v_angle); traceline(self.origin, self.origin, 1, self); - if (trace_inwater == 1) { + + local float ignited = self.effects & EF_DIMLIGHT; + if (trace_inwater == 1 && ignited) { + self.effects &= ~EF_DIMLIGHT; // Extinguish. FO_Sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, ATTN_NORM); - RemoveGrenade(); - return; - } - head = findradius(self.origin, 180); - while (head) { - if (head.takedamage) { - deathmsg = DMSG_FLAME; - - TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, - TF_TD_FIRE); - other = head; - Napalm_touch(); - if (other.classname == "player") { - stuffcmd(other, "bf\nbf\n"); + } else if (ignited) { + head = findradius(self.origin, 180); + while (head) { + if (head.takedamage) { + deathmsg = DMSG_FLAME; + + TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, + TF_TD_FIRE); + other = head; + Napalm_touch(); + if (other.classname == "player") { + stuffcmd(other, "bf\nbf\n"); + } } + head = head.chain; } - head = head.chain; + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PHS); } - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); self.heat = self.heat + 1; - - if (self.heat >= maxExplosions) - RemoveGrenade(); -}; -void () NapalmGrenadeExplode = { - local entity head; - - FO_Sound(self, CHAN_AUTO, "weapons/flmgrexp.wav", 1, ATTN_NORM); - traceline(self.origin, self.origin, 1, self); - if (trace_inwater == 1) { + if (self.heat >= maxExplosions) dremove(self); - return; - } - self.effects = self.effects | EF_DIMLIGHT; - head = spawn(); - head.think = NapalmGrenadeNetThink; - head.classname = "grentimer"; - head.grenadename = "napalmfire"; - head.nextthink = time + 0.1; - head.heat = 0; - head.origin = self.origin; - head.owner = self.owner; - head.team_no = self.owner.team_no; - head.enemy = self; }; + void (vector org, entity shooter) NapalmGrenadeLaunch = { local float xdir; local float ydir; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 63a3c75a..163dab99 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -518,12 +518,6 @@ void () StartQuadRound = gren.nextthink = (time + 0.1); gren = find(gren, classname, "grenade"); } - gren = find(world, classname, "grentimer"); - while (gren) { - gren.think = SUB_Remove; - gren.nextthink = (time + 0.1); - gren = find(gren, classname, "grentimer"); - } te = find(world, classname, "detpack"); while (te){ if (te.weaponmode == 1) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bbc6ca2d..e93acf78 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -241,8 +241,6 @@ float coop; .float last_saveme_sound; .float no_active_nail_grens; -.float no_active_napalm_grens; -.float no_active_gas_grens; /*======================================================================*/ /* TEAMFORTRESS GOALS */ diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 0ba3bee0..8a32b90f 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1,7 +1,6 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer; void (entity spy) TeamFortress_SpyCalcName; void () CF_Spy_UndercoverThink; -void () GasGrenadeMakeGas; void () T_TranqDartTouch; void () Spy_DropBackpack; void (entity targ, entity attacker) KillSound; @@ -1214,22 +1213,20 @@ void () GasGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () GasGrenadeExplode = { - local entity te; +void () GasGrenadeExplode2; + +// GasGrenadeExplode1 handles the initial "pre-explosion". +// GasGrenadeExplode2 handles aoe emission. +void () GasGrenadeExplode1 = { local float pos; pos = pointcontents(self.origin); if (pos == -1) { - te = spawn(); - te.think = GasGrenadeMakeGas; - te.nextthink = time + 0.1; - te.classname = "gastimer"; - te.heat = 0; - te.origin = self.origin; - te.owner = self.owner; - te.team_no = self.owner.team_no; - te.weapon = 0; - te.enemy = self; + self.think = GasGrenadeExplode2; + self.nextthink = time + 0.1; + self.heat = 0; + self.dimension_seen = DMN_INVISIBLE; + self.movetype = MOVETYPE_NONE; } else { pos = 0; while (pos < 10) { @@ -1248,31 +1245,14 @@ void () GasGrenadeExplode = { setsize(newmis, '-8 -8 -8', '8 8 8'); pos = pos + 1; } + dremove(self); } - dremove(self); }; -void () GasGrenadeMakeGas = { +void () GasGrenadeExplode2 = { local entity te; local entity timer; - if (self.heat == 0) { - self.owner.no_active_gas_grens = - self.owner.no_active_gas_grens + 1; - if (self.owner.no_active_gas_grens > 2) { - te = find(world, classname, "gastimer"); - while (te) { - if ((te.owner == self.owner) && - (te.no_active_gas_grens == 1)) { - te.weapon = 24; - te.think = RemoveGrenade; - te.nextthink = time + 0.1; - } - te = find(te, classname, "gastimer"); - } - } - self.no_active_gas_grens = self.owner.no_active_gas_grens; - } self.nextthink = time + 0.75; te = findradius(self.origin, 200); while (te != world) { @@ -1353,7 +1333,7 @@ void () GasGrenadeMakeGas = { self.weapon = 0; return; } - RemoveGrenade(); + dremove(self); }; void () HallucinationTimer = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2839f45c..5b503560 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1095,7 +1095,7 @@ void () TeamFortress_GrenadePrimed = { FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; - newmis.think = NapalmGrenadeExplode; + newmis.think = NapalmGrenadeExplode1; newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; @@ -1111,7 +1111,7 @@ void () TeamFortress_GrenadePrimed = { FO_SetModel(newmis, "progs/flare.mdl"); } else if (self.weapon == GR_TYPE_GAS) { newmis.touch = GasGrenadeTouch; - newmis.think = GasGrenadeExplode; + newmis.think = GasGrenadeExplode1; newmis.grenadename = "gasgrenade"; newmis.skin = 3; newmis.avelocity = '300 300 300'; @@ -2423,7 +2423,7 @@ void () TeamFortress_RemoveTimers = { te = find(world, classname, "timer"); while (te != world) { - if ((te.owner == self) && (te.no_active_gas_grens <= 0)) { + if (te.owner == self) { dremove(te); te = find(world, classname, "timer"); } else @@ -2436,15 +2436,6 @@ void () TeamFortress_RemoveTimers = { self.StatusGrenTime = 0; Status_Refresh(self); - te = find(world, classname, "grentimer"); - while (te != world) { - if ((te.owner == self) && (te.no_active_napalm_grens <= 0)) { - dremove(te); - te = find(world, classname, "grentimer"); - } else - te = find(te, classname, "grentimer"); - } - te = find(world, classname, "item_tfgoal"); while (te) { if (te.owner == self) { @@ -2941,7 +2932,7 @@ void () TeamFortress_ExplodePerson = { FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; - newmis.think = NapalmGrenadeExplode; + newmis.think = NapalmGrenadeExplode1; newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; @@ -2961,7 +2952,7 @@ void () TeamFortress_ExplodePerson = { return; } else if (self.weapon == GR_TYPE_GAS) { newmis.touch = GasGrenadeTouch; - newmis.think = GasGrenadeExplode; + newmis.think = GasGrenadeExplode1; newmis.grenadename = "gasgrenade"; newmis.skin = 2; newmis.avelocity = '300 300 300'; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 847c1db2..c562b406 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3861,45 +3861,6 @@ void () SuperDamageSound = { return; }; -void () RemoveGrenade = { - local entity te; - - if (self.no_active_napalm_grens > 0) { - - self.no_active_napalm_grens = 0; - self.owner.no_active_napalm_grens = - self.owner.no_active_napalm_grens - 1; - if (self.owner.no_active_napalm_grens < 0) - self.owner.no_active_napalm_grens = 0; - - te = find(world, classname, "grentimer"); - while (te) { - if ((te.owner == self.owner) && - (te.no_active_napalm_grens > 0)) - te.no_active_napalm_grens = te.no_active_napalm_grens - 1; - te = find(te, classname, "grentimer"); - } - dremove(self.enemy); - dremove(self); - } - if (self.no_active_gas_grens > 0) { - - self.no_active_gas_grens = 0; - self.owner.no_active_gas_grens = - self.owner.no_active_gas_grens - 1; - if (self.owner.no_active_gas_grens < 0) - self.owner.no_active_gas_grens = 0; - - te = find(world, classname, "grentimer"); - while (te) { - if ((te.owner == self.owner) && (te.no_active_gas_grens > 0)) - te.no_active_gas_grens = te.no_active_gas_grens - 1; - te = find(te, classname, "grentimer"); - } - dremove(self); - } -}; - void () ToggleInvincibility = { if(self.tfstate & TFSTATE_INVINCIBLE) { self.items = self.items - (self.items & IT_INVULNERABILITY); From f3d182053028adf9216d296dca350c01d915ff22 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 11 Sep 2022 14:14:35 -0700 Subject: [PATCH 1592/2474] Further improve FTE performance I realized there were many more per-frame cvar queries hidden in the status bar rendering code. (These are more expensive than you might think due to vm entry/exit, string wrapping, and look-up-by-string.) Replace these with autocvars which we can interact with natively. The performance improvement is quite nice when the FO hud is enabled. There were many of these calls as they were per-panel. Even at only 60fps (wayland forced vsync) I'm getting ~50% improvements in time spent within CSQC frame rendering. While we're in here, add fo_legacy_sbar for Novate. Which allows use of the original sbar (you'll still need to edit the FTE sbar to hide any panels you don't want.) --- csqc/csextradefs.qc | 9 ++++++++- csqc/main.qc | 19 ++++++++----------- csqc/status.qc | 46 +++++++++++++++++++++++++++++++++------------ 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 74b6739f..8784ebfd 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -1,5 +1,10 @@ #include "../share/defs.h" +#define DEFCVAR_FLOAT(n,d) var float autocvar_##n = d; +#define DEFCVAR_STRING(n,d) var string autocvar_##n = d; +#define CVARF(n) autocvar_##n +#define CVARS(n) autocvar_##n + vector MENU_BG = '0.2 0.3 0.4'; vector MENU_BG_DARK = '0.1 0.15 0.2'; vector MENU_BORDER = '0.3 0.4 0.5'; @@ -519,7 +524,9 @@ enum { #define FOCMD_GRENTIMERVOLUME "fo_grentimervolume" #define FOCMD_JUMPVOLUME "fo_jumpvolume" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" -#define FOCMD_FTE_HUD "fo_fte_hud" + +DEFCVAR_FLOAT(fo_fte_hud, 0); +DEFCVAR_FLOAT(fo_legacy_sbar, 0); float team_no; float is_spectator; diff --git a/csqc/main.qc b/csqc/main.qc index 3a4e0ebb..33c0ab5c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -39,8 +39,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_GRENTIMERSOUND, "grentimer.wav"); registercvar(FOCMD_GRENTIMERVOLUME, "1"); registercvar(FOCMD_JUMPVOLUME, "1"); - registercvar(FOCMD_OLDSCOREBOARD, "0"); - registercvar(FOCMD_FTE_HUD, "0"); registercommand("fo_menu_game"); registercommand("fo_main_menu"); @@ -115,21 +113,20 @@ noref void() CSQC_WorldLoaded = { } noref void(float width, float height, float menushown) CSQC_UpdateView = { - ScreenSize = [width, height, menushown]; - SBAR.Hint = ""; - thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); - clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! - if(cvar(FOCMD_FTE_HUD) != 1) { - setproperty(VF_DRAWENGINESBAR, 1); /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ - } + + // Draw original sbar, viewsize honoured automatically. + if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) + setproperty(VF_DRAWENGINESBAR, 1); addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view renderscene(); + ScreenSize = [width, height, menushown]; + SBAR.Hint = ""; sui_begin(width, height); Menu_Draw(width, height, menushown); Hud_Draw(width, height); @@ -264,14 +261,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd(sprintf("bind %s +fo_showscores\n", key2)); } } - if(cvar(FOCMD_FTE_HUD)) { + if(CVARF(fo_fte_hud)) { FO_Show_Scores(TRUE); } break; case "-showscores": case "-showteamscores": showingscores = FALSE; - if(cvar(FOCMD_FTE_HUD)) { + if(CVARF(fo_fte_hud)) { FO_Show_Scores(FALSE); } break; diff --git a/csqc/status.qc b/csqc/status.qc index 1342d2f0..a9312c47 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -148,7 +148,9 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { }; void(string panelid, float display, string text) drawFacePanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if (!CVARF(fo_fte_hud)) + return; + local float playerclass = SBAR.PlayerClass; //we could add different faces per class? local string icon = FaceInvisibleInvulnerableIcon.icon; @@ -185,7 +187,9 @@ void(string panelid, float display, string text) drawFacePanel = { }; void(string panelid, float display, string text) drawArmourPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + local float playerclass = SBAR.PlayerClass; local string icon = fo_hud_editor?ArmourIcons[1].icon:""; @@ -202,7 +206,9 @@ void(string panelid, float display, string text) drawArmourPanel = { }; void(string panelid, float display, string text) drawAmmoPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + local string icon = fo_hud_editor?AmmoIcons[0].icon:""; local float items = getstatf(STAT_ITEMS); @@ -215,7 +221,9 @@ void(string panelid, float display, string text) drawAmmoPanel = { }; void(string panelid, float display, string text) drawInvIconPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + if(text && text != "") { drawIconPanel(panelid, display, "", text); } else if(fo_hud_editor) { @@ -223,19 +231,27 @@ void(string panelid, float display, string text) drawInvIconPanel = { } }; void(string panelid, float display, string text) drawInvShellsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[0].icon); }; void(string panelid, float display, string text) drawInvNailsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[1].icon); }; void(string panelid, float display, string text) drawInvRocketsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[2].icon); }; void(string panelid, float display, string text) drawInvCellsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[3].icon); }; @@ -280,17 +296,23 @@ void(string panelid, float display, string text, float threshold) drawBigNumberP }; void(string panelid, float display, string text) drawHealthTextPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawBigNumberPanel(panelid, display, text, 26); }; void(string panelid, float display, string text) drawAmmoTextPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawBigNumberPanel(panelid, display, text, 11); }; void(string panelid, float display, string text) drawClockPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawBigNumberPanel(panelid, display, text, 0); }; @@ -1137,7 +1159,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gun6","Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, {"gun7","Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {"gun8","Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return cvar(FOCMD_FTE_HUD)?sprintf("%3.1f UPS", speed):"";}, 0, 4}, + {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, }; //var FO_Hud_Panel Hud_ExtraPanels[] = { From 74683cbb51fd1a2abeffe44694502f761d169f68 Mon Sep 17 00:00:00 2001 From: me Date: Mon, 12 Sep 2022 21:38:59 +1200 Subject: [PATCH 1593/2474] duels: allow draws, tie breaks, draw countdowns, autoprimes --- README.md | 4 ++ ssqc/clan.qc | 7 ++-- ssqc/client.qc | 105 ++++++++++++++++++++++++++++++++++++++++++------- ssqc/combat.qc | 5 ++- ssqc/mvdsv.qc | 2 +- ssqc/qw.qc | 4 ++ 6 files changed, 108 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 19806b54..b3f75d67 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,10 @@ New features * CSQC - fo_hud_editor to move panels and save to config * `info_empblock` has a new field `goal_effects`. Setting it to 16 will prevent it from blocking emps if there is a wall between it and the explosion. * New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. +* Server option for duelmode to allow draws on a double-ko `localinfo duel_allow_draw 1`/`localinfo dad 1` (default 1) +* Server option for duelmode to force a tie-break based on difference `localinfo duel_tie_break X`/`localinfo dtb X` (default 2) +* Server option for duelmode to force a countdown even if there is a double-kill `localinfo duel_draw_countdown 1`/`localinfo ddc 1` (default 1). If 0, both will respawn immediately upon the second player's death. +* Server option for duelmode to allow players to autoprime as soon as they are able `localinfo duel_autoprime 1`/`localinfo dap `. (default 0). Will only autoprime for players who have set `setinfo dap 1` * Server option for duelmode to allow spawn protection `localinfo duel_spawn_guard 1`/`localinfo dsg 1` - it will not allow any fighting until both players have left the spawn. * Server option for duelmode to print winner's health `localinfo duel_print_health 1`/`localinfo dph 1` * Server option for duelmode to respawn with all grens `localinfo duel_all_grens 1`/`localinfo dag 1` diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 27435f1d..362fb9d4 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -77,8 +77,9 @@ void () StartMatch = gren = find(world, classname, "grenade"); while (gren) { - gren.think = GrenadeExplode; - gren.nextthink = (time + 0.1); + //gren.think = GrenadeExplode; + //gren.nextthink = (time + 0.1); + dremove(gren); gren = find(gren, classname, "grenade"); } te = find(world, classname, "detpack"); @@ -89,7 +90,7 @@ void () StartMatch = dremove(te.observer_list); } dremove(te.linked_list); - dremove(te); //remove before finding next? + dremove(te); te = find (te, classname, "detpack"); } if(duelmode && duel_no_packs) { diff --git a/ssqc/client.qc b/ssqc/client.qc index c4ccabd5..31652515 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -68,7 +68,7 @@ void () InitReverseCap; float () RejoinWithTfId; void () CreateTfIdAndJoin; entity (entity e)TeamFortress_GetPracticeSpawn; - +void () NextLevel; void () info_intermission = { @@ -710,6 +710,16 @@ void () DecodeLevelParms = { // 0 - immediately // 1 - all players have moved away from spawn duel_spawn_guard = CF_GetSetting("dsg", "duel_spawn_guard", "1"); + // If 0, first to reach fraglimit wins + // If 1, a double-ko (with delay) will end the match in a draw + duel_allow_draw = CF_GetSetting("dad", "duel_allow_draw", "1"); + // Sets the number of frags difference required to break a tie after a double-ko upon fraglimit + duel_tie_break = CF_GetSetting("dtb", "duel_tie_break", "2"); + // If 0, in case of a double-ko, reset immediately + // If 1, round countdown always happens, even with a double-ko + duel_draw_countdown = CF_GetSetting("ddc", "duel_draw_countdown", "1"); + // If 1, clients that have 'setinfo dap 1' will prime a gren as soon as they leave spawn + duel_autoprime = CF_GetSetting("dap", "duel_autoprime", "0"); //Proportion required to trigger a map change vote_threshold = CF_GetSetting("vt", "vote_threshold", "0.5"); @@ -1389,7 +1399,7 @@ void (string cn) RemoveAllEntsByClassname = { } void () spawn_guard_think = { - local entity te; + local entity te, oldself; local float no_fire = 0; te = find(world, classname, "player"); while (te != world) { @@ -1401,6 +1411,7 @@ void () spawn_guard_think = { te.invincible_time = 0; te.effects = 0; bprint(PRINT_HIGH, te.netname, " \bhas left the spawn!\b\n"); + FO_Sound(world, CHAN_AUTO, "misc/basekey.wav", 1, ATTN_NONE); } else { no_fire++; } @@ -1412,8 +1423,20 @@ void () spawn_guard_think = { if(!no_fire) { no_fire_mode = 0; bprint(PRINT_HIGH, "\bFIGHT!\b\n"); - FO_Sound(world, CHAN_ITEM, "fight.wav", 1, ATTN_NONE); + FO_Sound(world, CHAN_AUTO, "fight.wav", 1, ATTN_NONE); self.think = SUB_Remove; + if(duel_autoprime) { + te = find(world, classname, "player"); + while (te != world) { + if(!te.has_disconnected && infokey(te, "dap") == "1") { + oldself = self; + self = te; + TeamFortress_PrimeGrenade(1); + self = oldself; + } + te = find (te, classname, "player"); + } + } } }; @@ -1424,13 +1447,29 @@ void () StartSpawnGuard = { reset_timer.think = spawn_guard_think; reset_timer.nextthink = time + 0.1; bprint(PRINT_HIGH, "\bLeave the spawn to begin!\b\n"); - FO_Sound(world, CHAN_ITEM, "come_get.wav", 1, ATTN_NONE); + FO_Sound(world, CHAN_AUTO, "come_get.wav", 1, ATTN_NONE); +}; + +void () DuelFinish = { + FO_Sound(world, CHAN_AUTO, "boss1/sight1.wav", 1, ATTN_NONE); + NextLevel(); + RemoveGrenadeTimers(); + RemovePrimeTimers(); + RemoveGrenades(); +}; + +void (entity winner) DuelWin = { + bprint(PRINT_HIGH, "\sDuel over!\s ", winner.netname, " \sis victorious!\s\n"); + DuelFinish(); }; + void () ResetPlayers = { - local entity te, oldself, reset_timer; + local entity te, oldself, reset_timer, winner = world; local float teamsleft; + local float maxscore = 0, nextscore = 0; no_fire_mode = 0; + reset_timer = find(world, classname, "duel_reset_timer"); while (reset_timer != world) { oldself = reset_timer; @@ -1440,6 +1479,8 @@ void () ResetPlayers = { if(cb_prematch) return; + TeamFortress_TeamShowScores(2); + teamsleft = CountRemainingTeams(); if(teamsleft == 1) { if(round_winner) { @@ -1454,7 +1495,6 @@ void () ResetPlayers = { } else if(teamsleft == 0) { bprint(PRINT_HIGH, "Everybody died! It's a draw.\n"); } - TeamFortress_TeamShowScores(2); RemoveAllEntsByClassname("proj_bullet"); RemoveAllEntsByClassname("proj_rocket"); @@ -1468,31 +1508,68 @@ void () ResetPlayers = { RemoveAllEntsByClassname("pyro_rocket"); RemoveAllEntsByClassname("proj_tranq"); - if(duelmode && duel_spawn_guard) { - StartSpawnGuard(); - precache_sound("get_some.wav"); - precache_sound("fight.wav"); - } te = find(world, classname, "player"); while (te != world) { if(!te.has_disconnected) { if(te.health > 0) { stuffcmd(te, "f_respawn\n"); if(round_winner_print_health) { - bprint(PRINT_HIGH, te.netname, ": \sHealth:\s ", ftos(te.health), " \sArmor:\s " , ftos(te.armorvalue), "\n"); + bprint(PRINT_HIGH, te.netname, ": \sHealth:\s ", ftos(te.health), " \sArmour:\s " , ftos(te.armorvalue), "\n"); } } oldself = self; self = te; + if(duelmode && duel_allow_draw && fraglimit) { + //if(duel_tie_break > 0) { + if(maxscore <= te.frags) { + nextscore = maxscore; + maxscore = te.frags; + winner = te; + } + //} else if (te.frags >= fraglimit) { + // DuelWin(te); + // return; + //} + } RemovePlayerOwnedEnts(); setspawnparms(self); PutClientInServer(); self.respawn_time = 0; - self = oldself; } te = find (te, classname, "player"); } + if(duelmode && duel_allow_draw) { + if(fraglimit) { + if(duel_tie_break > 0) { + if(maxscore == fraglimit && maxscore == nextscore) { + bprint(PRINT_HIGH, "\sFraglimit reached, but the fight's not over!\s\n\sYou must reach\s ", ftos(duel_tie_break), " \sfrag difference to win!\s\n"); + FO_Sound(world, CHAN_AUTO, "items/suit.wav", 1, ATTN_NONE); + } + if((maxscore >= fraglimit && nextscore < fraglimit) || (maxscore > fraglimit && maxscore >= (nextscore + duel_tie_break) )) { + DuelWin(winner); + return; + } + } else { + if(maxscore >= fraglimit) { + if(maxscore == nextscore) { + bprint(PRINT_HIGH, "\sDuel over! It is a\s DRAW\s!\s\n"); + DuelFinish(); + } else { + DuelWin(winner); + } + return; + } + } + } + } + + if(duelmode && duel_spawn_guard) { + StartSpawnGuard(); + precache_sound("get_some.wav"); + precache_sound("fight.wav"); + } + } float () CountRemainingTeams = { @@ -2549,7 +2626,7 @@ void () PlayerPreThink = { } // Check if timelimit/fraglimit has been met - if(!votemode) CheckRules(); + if(!votemode && !(duelmode && duel_allow_draw)) CheckRules(); if (self.playerclass != 0 || votemode) { WaterMove(); diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 970510a0..59cab546 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -7,6 +7,7 @@ void (entity Goal, entity AP, float addb) DoResults; float (entity Goal, entity AP) Activated; float (entity targ, entity attacker, float damage) TeamEqualiseDamage; float () CountRemainingTeams; +void () CheckRules; void () monster_death_use = { if (self.flags & FL_FLY) @@ -128,7 +129,9 @@ void (entity targ, entity attacker) Killed = { //Already in no fire mode - implies you're not the first to die if(no_fire_mode) { if(CountRemainingTeams() == 0) { - ResetPlayers(); + if(!duel_draw_countdown) { + ResetPlayers(); + } } } else { if(CountRemainingTeams() < 2) { diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index de692b13..f6905040 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -29,7 +29,7 @@ float (string cmd) ConsoleCmd { RemoveVoteMap(argv(1)); return TRUE; case "nextmap": - bprint(PRINT_HIGH, "Hmm: ", ftos(FO_GetUserSetting (world, "nomapcycle", "nmc", "0")), "\n"); //MEHT + //bprint(PRINT_HIGH, "Hmm: ", ftos(FO_GetUserSetting (world, "nomapcycle", "nmc", "0")), "\n"); //MEHT if(FO_GetUserSetting (world, "nomapcycle", "nmc", "0")) { bprint(PRINT_HIGH, "Tried setting next map to ", argv(1), ", but nomapcycle is set.\n"); } else { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9cfe43bf..4bd410e2 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -463,6 +463,10 @@ float duel_all_grens; float duel_no_packs; float duel_spawn_guard; .entity duel_guarded; +float duel_allow_draw; +float duel_tie_break; +float duel_draw_countdown; +float duel_autoprime; float votemode; float voting_started; float voting_expires; From cfff7bdb441ae8f1d2f82747658fe2755ace74de Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 12 Sep 2022 22:32:10 +1000 Subject: [PATCH 1594/2474] Add toggle for csqcjumpsounds --- csqc/events.qc | 3 +++ csqc/main.qc | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 5955326c..f6816f3a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -444,6 +444,9 @@ void ParseSBAR() } float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound = { + if !(cvar("csqcjumpsounds")) + return 0; + if !(entnum == player_localentnum) return 0; diff --git a/csqc/main.qc b/csqc/main.qc index 55e24255..7275aa0e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -88,6 +88,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { } registercvar("fo_menu_option_+", "="); + autocvar(csqcjumpsounds, 0, "client-side predicted jump sounds"); + FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); FO_LoadSettings(); @@ -174,17 +176,19 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { local float paused = getstatf(STAT_PAUSED); - if (pmove_onground && health > 0 && !paused) { - // The pmove_vel_z < 180 check makes sure you're not sliding - if (input_buttons & BUTTON2 && pmove_vel_z < 180) { - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); - } + if (cvar("csqcjumpsounds")) { + if (pmove_onground && health > 0 && !paused) { + // The pmove_vel_z < 180 check makes sure you're not sliding + if (input_buttons & BUTTON2 && pmove_vel_z < 180) { + localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + } - if (!last_pmove_onground) { - if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_AUTO, 1); - } else if (last_vel_z < -300) { - localsound("player/land.wav", CHAN_AUTO, 1); + if (!last_pmove_onground) { + if (last_vel_z < -650) { + localsound("player/land2.wav", CHAN_AUTO, 1); + } else if (last_vel_z < -300) { + localsound("player/land.wav", CHAN_AUTO, 1); + } } } } From 030185690f1b8e35cf063387a82ea9800965c773 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 12 Sep 2022 22:34:30 +1000 Subject: [PATCH 1595/2474] Add toggle --- README.md | 1 + csqc/events.qc | 2 +- csqc/main.qc | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f2b3e2a7..35be689c 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ New features * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config +* CSQC - fo_csjumpsounds * `info_empblock` has a new field `goal_effects`. Setting it to 16 will prevent it from blocking emps if there is a wall between it and the explosion. * New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. * Server option for duelmode to allow draws on a double-ko `localinfo duel_allow_draw 1`/`localinfo dad 1` (default 1) diff --git a/csqc/events.qc b/csqc/events.qc index f6816f3a..2d8612dc 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -444,7 +444,7 @@ void ParseSBAR() } float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound = { - if !(cvar("csqcjumpsounds")) + if !(cvar("fo_csjumpsounds")) return 0; if !(entnum == player_localentnum) diff --git a/csqc/main.qc b/csqc/main.qc index 7275aa0e..43f70137 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -88,7 +88,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { } registercvar("fo_menu_option_+", "="); - autocvar(csqcjumpsounds, 0, "client-side predicted jump sounds"); + autocvar(fo_csjumpsounds, 1, "client-side predicted jump sounds"); FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); FO_LoadSettings(); @@ -176,7 +176,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { local float paused = getstatf(STAT_PAUSED); - if (cvar("csqcjumpsounds")) { + if (cvar("fo_csjumpsounds")) { if (pmove_onground && health > 0 && !paused) { // The pmove_vel_z < 180 check makes sure you're not sliding if (input_buttons & BUTTON2 && pmove_vel_z < 180) { From 1712de6f844abc38ec29e2d35140c41eb6ffb5be Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 12 Sep 2022 21:56:39 -0700 Subject: [PATCH 1596/2474] Fix context menus Menus were still using thisorigin, ensure it's set when active. --- csqc/menu.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/menu.qc b/csqc/menu.qc index 1b044cdb..46adcd35 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -661,6 +661,7 @@ vector fo_menu_draw(fo_menu * menu) = { Hud_Panels[HUD_PANEL_MAP_MENU].Display = FALSE; + thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); if(menu.update) { From c5cfedfddf716f7bb888abe720bbe57685359b88 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 13 Sep 2022 02:09:11 -0700 Subject: [PATCH 1597/2474] Default on for precise_grenades. --- README.md | 2 +- ssqc/tfort.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f5fbbb7c..428dd01e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server New features ------ -* `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. +* `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 501ab886..ee673b50 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1154,7 +1154,7 @@ void () TeamFortress_GrenadePrimedThink = { }; float () FO_UsePreciseGrenades = { - return FO_GetUserSetting(self, "precise_grenades", "pg", "off"); + return FO_GetUserSetting(self, "precise_grenades", "pg", "on"); } void () FO_PreciseGrenadeThink = { From e3141c522be33fcec4d38d4ccd7f7d1df7ae05fe Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Sep 2022 00:31:09 -0700 Subject: [PATCH 1598/2474] Reduce per-frame overhead A large amount of game logic is currently overloaded with per-frame rendering. Move this into independent synchronization that tries to follow server updates more directly. wayland won't let me escape vsync, but limited profiling suggests this is good for at least 1-2% cpu reduction from infobuf string conversion alone at higher framerates. --- csqc/main.qc | 139 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 55e24255..3a4e0ebb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -13,6 +13,7 @@ void AddGrenTimer(float grentype, float offset); void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); float IsValidToUseGrenades(); +void Sync_GameState(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -115,25 +116,8 @@ noref void() CSQC_WorldLoaded = { noref void(float width, float height, float menushown) CSQC_UpdateView = { ScreenSize = [width, height, menushown]; - team_no = getstatf(STAT_TEAMNO); - is_observer = FALSE; - if (team_no == 0) - is_observer = TRUE; - player_class = getstatf(STAT_CLASS); - SBAR.ReadyStatus = getstatf(STAT_FLAGS); - oldhealth = getstatf(STAT_HEALTH); - is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); - if (is_spectator) - is_observer = FALSE; SBAR.Hint = ""; thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); - //if(nextoriginupdate < time) { - // speed = vlen([thisorigin.x, thisorigin.y] - [lastorigin.x, lastorigin.y]) * 10; - // lastorigin = thisorigin; - // nextoriginupdate = time + 0.1; - //} - vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; - speed = sqrt(vel.x * vel.x + vel.y * vel.y); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! @@ -141,27 +125,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if(cvar(FOCMD_FTE_HUD) != 1) { setproperty(VF_DRAWENGINESBAR, 1); /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ } - //setviewprop(VF_ORIGIN, '0 0 0'); //view position of the scene (after view_ofs effects). - //setviewprop(VF_ANGLES, '0 0 0'); //override the view angles. input will work as normal. other players will see your player as normal. your screen will just be pointing a different direction. - //setviewprop(VF_DRAWWORLD, 1); //whether the world entity should be drawn. set to 0 if you want a completely empty scene. - //setviewprop(VF_MIN, '0 0 0'); //top-left coord (x,y) of the scene viewport in virtual pixels (or annoying physical pixels in dp). - //setviewprop(VF_SIZE, [width, height, 0]); //virtual size (width,height) of the scene viewport in virtual pixels (or annoying physical pixels in dp). - //setviewprop(VF_AFOV, cvar("fov")); //note: fov_x and fov_y control individual axis. afov is general - //setviewprop(VF_PERSPECTIVE, 1); //1 means like quake and other 3d games. 0 means isometric. - - local float health = getstatf(STAT_HEALTH); - - if (health <= 0 || player_class != PC_SNIPER) { - zoomed_in = 0; - } - - if (zoomed_in) { - setviewprop(VF_AFOV, cvar("fov")/3); - setsensitivityscaler(1/3); - } else { - setviewprop(VF_AFOV, cvar("fov")); - setsensitivityscaler(1); - } addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view @@ -171,26 +134,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); - - local float paused = getstatf(STAT_PAUSED); - - if (pmove_onground && health > 0 && !paused) { - // The pmove_vel_z < 180 check makes sure you're not sliding - if (input_buttons & BUTTON2 && pmove_vel_z < 180) { - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); - } - - if (!last_pmove_onground) { - if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_AUTO, 1); - } else if (last_vel_z < -300) { - localsound("player/land.wav", CHAN_AUTO, 1); - } - } - } - - last_vel_z = pmove_vel_z; - last_pmove_onground = pmove_onground; } noref float(string cmd) CSQC_ConsoleCommand = { @@ -461,6 +404,8 @@ noref void CSQC_Input_Frame() { if (player_class == PC_SNIPER && keydowns & BUTTON3) { zoomed_in = !zoomed_in; } + + Sync_GameState(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -498,3 +443,81 @@ void StopGrenTimers() { FO_Hud_Grentimers[i].icon_index = 0; } } + +float last_servercommandframe; +void _Sync_ServerCommandFrame() { + // Server command frames are monotonically unique, we can skip processing + // unless there is new state. + if (last_servercommandframe == servercommandframe) + return; + last_servercommandframe = servercommandframe; + + team_no = getstatf(STAT_TEAMNO); + is_observer = FALSE; + if (team_no == 0) + is_observer = TRUE; + player_class = getstatf(STAT_CLASS); + SBAR.ReadyStatus = getstatf(STAT_FLAGS); + oldhealth = getstatf(STAT_HEALTH); + is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); + if (is_spectator) + is_observer = FALSE; + + vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), + getstatf(STAT_VELOCITY_Z)]; + speed = sqrt(vel.x * vel.x + vel.y * vel.y); + + local float health = getstatf(STAT_HEALTH); + if (health <= 0 || player_class != PC_SNIPER) { + zoomed_in = 0; + } + + if (zoomed_in) { + setviewprop(VF_AFOV, cvar("fov")/3); + setsensitivityscaler(1/3); + } else { + setviewprop(VF_AFOV, cvar("fov")); + setsensitivityscaler(1); + } +} + +float last_pmove_onground; +float last_vel_z; +float last_clientcommandframe; +// REQUIRES: Must be called after _Sync_ServerCommandFrame. +void _Sync_ClientCommandFrame() { + // Client command frames are regenerated beyond the server frame, so we + // cannot check that we have not seen this client command frame alone. + if (last_servercommandframe == servercommandframe && + last_clientcommandframe == clientcommandframe) + return; + last_clientcommandframe = clientcommandframe; + + local float paused = getstatf(STAT_PAUSED); + local float health = getstatf(STAT_HEALTH); + + if (pmove_onground && health > 0 && !paused) { + // The pmove_vel_z < 180 check makes sure you're not sliding + if (input_buttons & BUTTON2 && pmove_vel_z < 180) { + localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + } + + if (!last_pmove_onground) { + if (last_vel_z < -650) { + localsound("player/land2.wav", CHAN_AUTO, 1); + } else if (last_vel_z < -300) { + localsound("player/land.wav", CHAN_AUTO, 1); + } + } + } + + last_vel_z = pmove_vel_z; + last_pmove_onground = pmove_onground; +} + +// Called for each {client, server} command frame, ensures globals are +// synchronized with server and predicted state. +void Sync_GameState() { + _Sync_ServerCommandFrame(); + _Sync_ClientCommandFrame(); +} From 787593e0ba0e1938982e2f0d2e3187ebdc5045fa Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 11 Sep 2022 14:14:35 -0700 Subject: [PATCH 1599/2474] Further improve FTE performance I realized there were many more per-frame cvar queries hidden in the status bar rendering code. (These are more expensive than you might think due to vm entry/exit, string wrapping, and look-up-by-string.) Replace these with autocvars which we can interact with natively. The performance improvement is quite nice when the FO hud is enabled. There were many of these calls as they were per-panel. Even at only 60fps (wayland forced vsync) I'm getting ~50% improvements in time spent within CSQC frame rendering. While we're in here, add fo_legacy_sbar for Novate. Which allows use of the original sbar (you'll still need to edit the FTE sbar to hide any panels you don't want.) --- csqc/csextradefs.qc | 9 ++++++++- csqc/main.qc | 19 ++++++++----------- csqc/status.qc | 46 +++++++++++++++++++++++++++++++++------------ 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 74b6739f..8784ebfd 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -1,5 +1,10 @@ #include "../share/defs.h" +#define DEFCVAR_FLOAT(n,d) var float autocvar_##n = d; +#define DEFCVAR_STRING(n,d) var string autocvar_##n = d; +#define CVARF(n) autocvar_##n +#define CVARS(n) autocvar_##n + vector MENU_BG = '0.2 0.3 0.4'; vector MENU_BG_DARK = '0.1 0.15 0.2'; vector MENU_BORDER = '0.3 0.4 0.5'; @@ -519,7 +524,9 @@ enum { #define FOCMD_GRENTIMERVOLUME "fo_grentimervolume" #define FOCMD_JUMPVOLUME "fo_jumpvolume" #define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" -#define FOCMD_FTE_HUD "fo_fte_hud" + +DEFCVAR_FLOAT(fo_fte_hud, 0); +DEFCVAR_FLOAT(fo_legacy_sbar, 0); float team_no; float is_spectator; diff --git a/csqc/main.qc b/csqc/main.qc index 3a4e0ebb..33c0ab5c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -39,8 +39,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar(FOCMD_GRENTIMERSOUND, "grentimer.wav"); registercvar(FOCMD_GRENTIMERVOLUME, "1"); registercvar(FOCMD_JUMPVOLUME, "1"); - registercvar(FOCMD_OLDSCOREBOARD, "0"); - registercvar(FOCMD_FTE_HUD, "0"); registercommand("fo_menu_game"); registercommand("fo_main_menu"); @@ -115,21 +113,20 @@ noref void() CSQC_WorldLoaded = { } noref void(float width, float height, float menushown) CSQC_UpdateView = { - ScreenSize = [width, height, menushown]; - SBAR.Hint = ""; - thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); - clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! - if(cvar(FOCMD_FTE_HUD) != 1) { - setproperty(VF_DRAWENGINESBAR, 1); /* boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically. */ - } + + // Draw original sbar, viewsize honoured automatically. + if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) + setproperty(VF_DRAWENGINESBAR, 1); addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view renderscene(); + ScreenSize = [width, height, menushown]; + SBAR.Hint = ""; sui_begin(width, height); Menu_Draw(width, height, menushown); Hud_Draw(width, height); @@ -264,14 +261,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd(sprintf("bind %s +fo_showscores\n", key2)); } } - if(cvar(FOCMD_FTE_HUD)) { + if(CVARF(fo_fte_hud)) { FO_Show_Scores(TRUE); } break; case "-showscores": case "-showteamscores": showingscores = FALSE; - if(cvar(FOCMD_FTE_HUD)) { + if(CVARF(fo_fte_hud)) { FO_Show_Scores(FALSE); } break; diff --git a/csqc/status.qc b/csqc/status.qc index 1342d2f0..a9312c47 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -148,7 +148,9 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { }; void(string panelid, float display, string text) drawFacePanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if (!CVARF(fo_fte_hud)) + return; + local float playerclass = SBAR.PlayerClass; //we could add different faces per class? local string icon = FaceInvisibleInvulnerableIcon.icon; @@ -185,7 +187,9 @@ void(string panelid, float display, string text) drawFacePanel = { }; void(string panelid, float display, string text) drawArmourPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + local float playerclass = SBAR.PlayerClass; local string icon = fo_hud_editor?ArmourIcons[1].icon:""; @@ -202,7 +206,9 @@ void(string panelid, float display, string text) drawArmourPanel = { }; void(string panelid, float display, string text) drawAmmoPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + local string icon = fo_hud_editor?AmmoIcons[0].icon:""; local float items = getstatf(STAT_ITEMS); @@ -215,7 +221,9 @@ void(string panelid, float display, string text) drawAmmoPanel = { }; void(string panelid, float display, string text) drawInvIconPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + if(text && text != "") { drawIconPanel(panelid, display, "", text); } else if(fo_hud_editor) { @@ -223,19 +231,27 @@ void(string panelid, float display, string text) drawInvIconPanel = { } }; void(string panelid, float display, string text) drawInvShellsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[0].icon); }; void(string panelid, float display, string text) drawInvNailsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[1].icon); }; void(string panelid, float display, string text) drawInvRocketsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[2].icon); }; void(string panelid, float display, string text) drawInvCellsPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawIconPanel(panelid, display, text, AmmoIcons[3].icon); }; @@ -280,17 +296,23 @@ void(string panelid, float display, string text, float threshold) drawBigNumberP }; void(string panelid, float display, string text) drawHealthTextPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawBigNumberPanel(panelid, display, text, 26); }; void(string panelid, float display, string text) drawAmmoTextPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawBigNumberPanel(panelid, display, text, 11); }; void(string panelid, float display, string text) drawClockPanel = { - if(!cvar(FOCMD_FTE_HUD)) return; + if(!CVARF(fo_fte_hud)) + return; + drawBigNumberPanel(panelid, display, text, 0); }; @@ -1137,7 +1159,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gun6","Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, {"gun7","Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {"gun8","Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return cvar(FOCMD_FTE_HUD)?sprintf("%3.1f UPS", speed):"";}, 0, 4}, + {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, }; //var FO_Hud_Panel Hud_ExtraPanels[] = { From 6366e663e7724d01169ce1913ad4db3ebcd99f2a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 12 Sep 2022 21:56:39 -0700 Subject: [PATCH 1600/2474] Fix context menus Menus were still using thisorigin, ensure it's set when active. --- csqc/menu.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/menu.qc b/csqc/menu.qc index 1b044cdb..46adcd35 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -661,6 +661,7 @@ vector fo_menu_draw(fo_menu * menu) = { Hud_Panels[HUD_PANEL_MAP_MENU].Display = FALSE; + thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); if(menu.update) { From ece81e8161b38d20acf950da733b6d45eed86cdc Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Sep 2022 00:21:14 +1000 Subject: [PATCH 1601/2474] Play proper water landing sound --- csqc/events.qc | 7 +++---- csqc/main.qc | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 2d8612dc..76458bc6 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -444,9 +444,6 @@ void ParseSBAR() } float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound = { - if !(cvar("fo_csjumpsounds")) - return 0; - if !(entnum == player_localentnum) return 0; @@ -454,7 +451,9 @@ float(float entnum, float channel, string soundname, float vol, float attenuatio case "player/plyrjmp8.wav": case "player/land.wav": case "player/land2.wav": - return 1; + case "player/h2ojump.wav": + if (autocvar(fo_csjumpsounds, 1)) + return 1; } return 0; diff --git a/csqc/main.qc b/csqc/main.qc index 4f1adfec..6b4d5958 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -139,17 +139,20 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { local float paused = getstatf(STAT_PAUSED); if (pmove_onground && health > 0 && !paused) { - // The pmove_vel_z < 180 check makes sure you're not sliding - if ((input_buttons & BUTTON2) && (pmove_vel_z < 180)) { - print("pmove_vel_z: ", ftos(pmove_vel_z), "\n"); + // jumping + if ((input_buttons & BUTTON2) && (pmove_vel_z < 180 /* not sliding */)) { localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); } - if (!last_pmove_onground) { - if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_AUTO, 1); - } else if (last_vel_z < -300) { - localsound("player/land.wav", CHAN_AUTO, 1); + // landing + if (!last_pmove_onground && last_vel_z < -300) { + thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); + if (pointcontents(thisorigin) == CONTENT_WATER) { + localsound("player/h2ojump.wav", CHAN_BODY, 1); + } else if (last_vel_z < -650) { + localsound("player/land2.wav", CHAN_BODY, 1); + } else { + localsound("player/land.wav", CHAN_BODY, 1); } } } From 1ba3a63262808a62ff442fd266a7604a2ea4cac4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Sep 2022 00:25:27 +1000 Subject: [PATCH 1602/2474] Use proper channels --- csqc/main.qc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 6b4d5958..1889779f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -148,18 +148,18 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!last_pmove_onground && last_vel_z < -300) { thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); if (pointcontents(thisorigin) == CONTENT_WATER) { - localsound("player/h2ojump.wav", CHAN_BODY, 1); + localsound("player/h2ojump.wav", CHAN_VOICE, 1); } else if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_BODY, 1); + localsound("player/land2.wav", CHAN_VOICE, 1); } else { - localsound("player/land.wav", CHAN_BODY, 1); + localsound("player/land.wav", CHAN_VOICE, 1); } } } - } - last_vel_z = pmove_vel_z; - last_pmove_onground = pmove_onground; + last_vel_z = pmove_vel_z; + last_pmove_onground = pmove_onground; + } } noref float(string cmd) CSQC_ConsoleCommand = { From 3b0cdedb756d37d4334816ce4e3c04f97e58b043 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Sep 2022 00:38:54 +1000 Subject: [PATCH 1603/2474] Add cooldown to client side jump sound --- csqc/csextradefs.qc | 1 + csqc/main.qc | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 8784ebfd..cca55bf6 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -541,6 +541,7 @@ float nextoriginupdate; float speed; float jump_counter; float grentimer_waiting; +float jumpsound_cooldown; float last_pmove_onground; float last_vel_z; diff --git a/csqc/main.qc b/csqc/main.qc index 1889779f..586cb860 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -141,7 +141,10 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (pmove_onground && health > 0 && !paused) { // jumping if ((input_buttons & BUTTON2) && (pmove_vel_z < 180 /* not sliding */)) { - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + if (jumpsound_cooldown < time) { + jumpsound_cooldown = time + 0.01; + localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + } } // landing From 5aa978859abe7a95eecf69e45d0c975b3e0fd249 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Sep 2022 00:42:38 +1000 Subject: [PATCH 1604/2474] Refactor --- csqc/events.qc | 2 +- csqc/main.qc | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 76458bc6..31e561fd 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -452,7 +452,7 @@ float(float entnum, float channel, string soundname, float vol, float attenuatio case "player/land.wav": case "player/land2.wav": case "player/h2ojump.wav": - if (autocvar(fo_csjumpsounds, 1)) + if (autocvar(fo_csjumpsounds, 1, "client-side predicted jump sounds")) return 1; } diff --git a/csqc/main.qc b/csqc/main.qc index 586cb860..d005b107 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -87,8 +87,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { } registercvar("fo_menu_option_+", "="); - autocvar(fo_csjumpsounds, 1, "client-side predicted jump sounds"); - FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); FO_LoadSettings(); From fee109e36366dea988b8c32b0156648970d6eeaa Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Sep 2022 00:44:31 +1000 Subject: [PATCH 1605/2474] Refactor --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index d005b107..da749c4d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -132,7 +132,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Hud_Draw(width, height); sui_end(); - if (cvar("fo_csjumpsounds")) { + if (autocvar(fo_csjumpsounds, 1, "client-side predicted jump sounds")) { local float health = getstatf(STAT_HEALTH); local float paused = getstatf(STAT_PAUSED); From 39385a62ec46abec66d9e38282cba2d34d12e7a1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Sep 2022 01:56:55 +1000 Subject: [PATCH 1606/2474] Predicted origin is already available --- csqc/csdefs.qc | 1 + csqc/main.qc | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index b86c4fa4..37b5e5aa 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -55,6 +55,7 @@ float input_impulse; void end_sys_globals; float pmove_onground; vector pmove_vel; +vector pmove_org; .float modelindex; .vector absmin; .vector absmax; diff --git a/csqc/main.qc b/csqc/main.qc index da749c4d..a1c62e9e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -147,8 +147,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { // landing if (!last_pmove_onground && last_vel_z < -300) { - thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); - if (pointcontents(thisorigin) == CONTENT_WATER) { + if (pointcontents(pmove_org) == CONTENT_WATER) { localsound("player/h2ojump.wav", CHAN_VOICE, 1); } else if (last_vel_z < -650) { localsound("player/land2.wav", CHAN_VOICE, 1); @@ -508,8 +507,6 @@ void _Sync_ServerCommandFrame() { } } -float last_pmove_onground; -float last_vel_z; float last_clientcommandframe; // REQUIRES: Must be called after _Sync_ServerCommandFrame. void _Sync_ClientCommandFrame() { From 70878f76603bf8b37a66a4b4dd226d74a2a5ea41 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Sep 2022 02:00:27 +1000 Subject: [PATCH 1607/2474] pmove_org is already available --- csqc/csdefs.qc | 1 + csqc/main.qc | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index b86c4fa4..37b5e5aa 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -55,6 +55,7 @@ float input_impulse; void end_sys_globals; float pmove_onground; vector pmove_vel; +vector pmove_org; .float modelindex; .vector absmin; .vector absmax; diff --git a/csqc/main.qc b/csqc/main.qc index da749c4d..9aa19f1f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -147,8 +147,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { // landing if (!last_pmove_onground && last_vel_z < -300) { - thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); - if (pointcontents(thisorigin) == CONTENT_WATER) { + if (pointcontents(pmove_org) == CONTENT_WATER) { localsound("player/h2ojump.wav", CHAN_VOICE, 1); } else if (last_vel_z < -650) { localsound("player/land2.wav", CHAN_VOICE, 1); From 19f35ce715c52beb53bf916673bede1690efc48b Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 14 Sep 2022 03:43:41 -0700 Subject: [PATCH 1608/2474] Enable compiler optimization and tuning Basic tests seemed to work on O3, so let's start there and ratchet it down if we have any issues. Also enabled: TARGET fte_5768 [specialize for FTE outputs, allows extended opcodes] subscope [restrict locals to their actual scope] --- csqc/csprogs.src | 9 +- menu/menu.src | 272 ++++++++++++++++++++++++----------------------- ssqc/commands.qc | 2 +- ssqc/progs.src | 13 ++- 4 files changed, 156 insertions(+), 140 deletions(-) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 709a516c..2aa77962 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,4 +1,10 @@ -../csprogs.dat +#pragma target fte_5768 +#pragma optimise 3 +#pragma flag enable subscope + +#pragma progs_dat "../csprogs.dat" + +#includelist csdefs.qc csextradefs.qc @@ -15,3 +21,4 @@ hud_helpers.qc hud.qc settings.qc input.qc +#endlist diff --git a/menu/menu.src b/menu/menu.src index bf25607b..ce60d2ea 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -1,135 +1,137 @@ -#pragma progs_dat "../menu.dat" - -//#pragma target fte - -#define MENU //select the module - -#includelist -../share/fteextensions.qc //also sets up system defs - -../menusys/mitems.qc //root item type -../menusys/mitems_common.qc //basic types -../menusys/mitem_desktop.qc //other sort of root item -../menusys/mitem_exmenu.qc //fullscreen/exclusive menus -../menusys/mitem_edittext.qc //simple text editor -../menusys/mitem_tabs.qc //tabs -../menusys/mitem_colours.qc //colour picker -../menusys/mitem_checkbox.qc //checkbox (boolean thingies) -../menusys/mitem_slider.qc //scrollbars -../menusys/mitem_combo.qc //multiple-choice thingies -../menusys/mitem_bind.qc //key binding thingie -../menusys/mitem_spinnymodel.qc //menu art -#endlist - -//might as well put this here. - -void(mitem_desktop desktop) M_Pop = -{ - mitem it = desktop.item_kactivechild; - if (it) - it.item_remove(); -}; - -//define the commands. -//cmd argments are: Name, Function, Sourcefile(may be empty) -#define concommandslist \ - cmd("m_main", M_Main, main.qc) \ - cmd("m_pop", M_Pop, ) \ - cmd("m_options", M_Options, options.qc) \ - cmd("m_keys", M_Options_Keys, options_keys.qc) \ - cmd("m_basicopts", M_Options_Basic, options_basic.qc) \ - cmd("m_video", M_Options_Video, options_video.qc) \ - cmd("m_effects", M_Options_Effects, options_effects.qc) \ - cmd("m_audio", M_Options_Audio, options_audio.qc) \ - cmd("m_load", M_Load, loadsave.qc) \ - cmd("m_save", M_Save, ) \ - cmd("m_quit", M_Quit, quit.qc) \ - cmd("m_servers", M_Servers, servers.qc) \ - cmd("m_reset", M_Reset, ) - - -#if 0 -#append concommandslist cmd("m_servers", M_Servers, servers.qc) -#define serverbrowser "m_servers" -#else -#define serverbrowser "menu_servers" -#endif - -//make sure all the right files are included -#define cmd(n,fnc,inc) inc -#includelist - concommandslist -#endlist -#undef cmd - -mitem_desktop desktop; -void() m_shutdown = {}; -void(vector screensize) m_draw = {items_draw(desktop);}; -void(float scan, float chr) m_keydown = {items_keypress(desktop, scan, chr, TRUE);}; -void(float scan, float chr) m_keyup = {items_keypress(desktop, scan, chr, FALSE);}; -void(float mode) m_toggle -{ //mode is stupid. 1=enable,0=disable,-1=actually toggle. - if (mode < 0) - mode = !desktop.item_kactivechild; - if (mode) - M_Main(desktop); - else while(desktop.item_kactivechild) - { - mitem it = desktop.item_kactivechild; - if (it.item_flags & IF_NOKILL) - break; - it.item_remove(); - } - - items_updategrabs(TRUE); -}; - -var float autocvar_dp_workarounds_allow = TRUE; -var float autocvar_dp_workarounds_force = FALSE; -void() m_init = -{ - desktop = spawn(mitem_desktop); - - //register the console commands via the alias command. -#define cmd(n,f) localcmd("alias " n " \"menu_cmd " n " $*\"\n"); - concommandslist -#undef cmd - - //work around some dp differences/bugs. - //this check identifies one significant bug in DP. - //if anyone actually cares to fix DP, then there is no reason they cannot do so by just removing DP_QC_RENDERSCENE and then fixing anything else that arises. - if (checkextension("DP_QC_RENDER_SCENE") && !checkextension("DP_CON_SET")) - dp_workarounds = autocvar(dp_workarounds_allow, TRUE); - if (autocvar(dp_workarounds_force, FALSE)) - dp_workarounds = TRUE; - - if (dp_workarounds) - print("^1WORKING AROUND DP BUGS\n"); - - //for compat with DP, 'none' is the default cursor in menuqc. - //naturally this is not ideal. - if (checkextension("FTE_QC_HARDWARECURSORS")) - setcursormode(TRUE, ""); - else - print("No hardware cursors\n"); - - if (clientstate() == 1) //disconnected==1, supposedly - m_toggle(1); -}; -void(string cstr) GameCommand = -{ - tokenize(cstr); - string cmd = argv(0); - - switch(cmd) - { -//switch on the known commands. -#define cmd(n,f) case n: f(desktop); break; - concommandslist -#undef cmd - default: - print("unknown command ", cmd, "\n"); - break; - } - items_updategrabs(TRUE); -}; +#pragma target fte_5768 +#pragma optimise 3 +#pragma flag enable subscope + +#pragma progs_dat "../menu.dat" + +#define MENU //select the module + +#includelist +../share/fteextensions.qc //also sets up system defs + +../menusys/mitems.qc //root item type +../menusys/mitems_common.qc //basic types +../menusys/mitem_desktop.qc //other sort of root item +../menusys/mitem_exmenu.qc //fullscreen/exclusive menus +../menusys/mitem_edittext.qc //simple text editor +../menusys/mitem_tabs.qc //tabs +../menusys/mitem_colours.qc //colour picker +../menusys/mitem_checkbox.qc //checkbox (boolean thingies) +../menusys/mitem_slider.qc //scrollbars +../menusys/mitem_combo.qc //multiple-choice thingies +../menusys/mitem_bind.qc //key binding thingie +../menusys/mitem_spinnymodel.qc //menu art +#endlist + +//might as well put this here. + +void(mitem_desktop desktop) M_Pop = +{ + mitem it = desktop.item_kactivechild; + if (it) + it.item_remove(); +}; + +//define the commands. +//cmd argments are: Name, Function, Sourcefile(may be empty) +#define concommandslist \ + cmd("m_main", M_Main, main.qc) \ + cmd("m_pop", M_Pop, ) \ + cmd("m_options", M_Options, options.qc) \ + cmd("m_keys", M_Options_Keys, options_keys.qc) \ + cmd("m_basicopts", M_Options_Basic, options_basic.qc) \ + cmd("m_video", M_Options_Video, options_video.qc) \ + cmd("m_effects", M_Options_Effects, options_effects.qc) \ + cmd("m_audio", M_Options_Audio, options_audio.qc) \ + cmd("m_load", M_Load, loadsave.qc) \ + cmd("m_save", M_Save, ) \ + cmd("m_quit", M_Quit, quit.qc) \ + cmd("m_servers", M_Servers, servers.qc) \ + cmd("m_reset", M_Reset, ) + + +#if 0 +#append concommandslist cmd("m_servers", M_Servers, servers.qc) +#define serverbrowser "m_servers" +#else +#define serverbrowser "menu_servers" +#endif + +//make sure all the right files are included +#define cmd(n,fnc,inc) inc +#includelist + concommandslist +#endlist +#undef cmd + +mitem_desktop desktop; +void() m_shutdown = {}; +void(vector screensize) m_draw = {items_draw(desktop);}; +void(float scan, float chr) m_keydown = {items_keypress(desktop, scan, chr, TRUE);}; +void(float scan, float chr) m_keyup = {items_keypress(desktop, scan, chr, FALSE);}; +void(float mode) m_toggle +{ //mode is stupid. 1=enable,0=disable,-1=actually toggle. + if (mode < 0) + mode = !desktop.item_kactivechild; + if (mode) + M_Main(desktop); + else while(desktop.item_kactivechild) + { + mitem it = desktop.item_kactivechild; + if (it.item_flags & IF_NOKILL) + break; + it.item_remove(); + } + + items_updategrabs(TRUE); +}; + +var float autocvar_dp_workarounds_allow = TRUE; +var float autocvar_dp_workarounds_force = FALSE; +void() m_init = +{ + desktop = spawn(mitem_desktop); + + //register the console commands via the alias command. +#define cmd(n,f) localcmd("alias " n " \"menu_cmd " n " $*\"\n"); + concommandslist +#undef cmd + + //work around some dp differences/bugs. + //this check identifies one significant bug in DP. + //if anyone actually cares to fix DP, then there is no reason they cannot do so by just removing DP_QC_RENDERSCENE and then fixing anything else that arises. + if (checkextension("DP_QC_RENDER_SCENE") && !checkextension("DP_CON_SET")) + dp_workarounds = autocvar(dp_workarounds_allow, TRUE); + if (autocvar(dp_workarounds_force, FALSE)) + dp_workarounds = TRUE; + + if (dp_workarounds) + print("^1WORKING AROUND DP BUGS\n"); + + //for compat with DP, 'none' is the default cursor in menuqc. + //naturally this is not ideal. + if (checkextension("FTE_QC_HARDWARECURSORS")) + setcursormode(TRUE, ""); + else + print("No hardware cursors\n"); + + if (clientstate() == 1) //disconnected==1, supposedly + m_toggle(1); +}; +void(string cstr) GameCommand = +{ + tokenize(cstr); + string cmd = argv(0); + + switch(cmd) + { +//switch on the known commands. +#define cmd(n,f) case n: f(desktop); break; + concommandslist +#undef cmd + default: + print("unknown command ", cmd, "\n"); + break; + } + items_updategrabs(TRUE); +}; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index fae4b327..afb000eb 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -312,7 +312,7 @@ void () OutputTrackedSettings = { float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; - local float farg3; + local float farg2, farg3; local entity ent, pl; processedCmd = FALSE; diff --git a/ssqc/progs.src b/ssqc/progs.src index 897a99c0..b4c38f88 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -1,6 +1,12 @@ -../qwprogs.dat +#pragma target fte_5768 +#pragma optimise 3 +#pragma flag enable subscope -#define QWSSQC +#pragma progs_dat "../qwprogs.dat" + +#define QWSSQC + +#includelist ../share/fteextensions.qc defs.qc ../share/commondefs.qc @@ -64,4 +70,5 @@ mvdsv.qc rotate.qc fo_logic.qc fo_math.qc -fo_misc_info.qc \ No newline at end of file +fo_misc_info.qc +#endlist From 7dd011eba5769d55991c6a3eea663a949df1cec6 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 15 Sep 2022 00:53:58 -0700 Subject: [PATCH 1609/2474] Fix all compiler warnings There were a lot of existing warnings, and optimization added new ones (since it does things like dead code elimination). Clean them all up. This did include some legitimate bugs such as potential bad references in the menu code and disguise-last-spawn when there is no one on the enemy team. --- csqc/csextradefs.qc | 3 --- csqc/events.qc | 4 ++-- csqc/input.qc | 14 -------------- csqc/main.qc | 2 +- csqc/sui_sys.qc | 3 --- menu/servers.qc | 4 ++-- menusys/mitem_frame.qc | 2 +- menusys/mitem_spinnymodel.qc | 2 ++ menusys/mitems.qc | 2 ++ ssqc/pyro.qc | 2 +- ssqc/spy.qc | 7 ++++++- ssqc/weapons.qc | 4 ++-- 12 files changed, 19 insertions(+), 30 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 74b6739f..df1f8dd5 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -88,7 +88,6 @@ float round_over; float round_time_remaining; float showingscores; float mapvote_expiry; -float cs_grenprimed; float num_mapvotes; float num_mapvotes_filtered; entity vote_selected_item; @@ -529,8 +528,6 @@ float is_observer; float oldhealth; float painfinished; vector thisorigin; -vector lastorigin; -float nextoriginupdate; float speed; float jump_counter; float grentimer_waiting; diff --git a/csqc/events.qc b/csqc/events.qc index 5955326c..d7c363a9 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -306,9 +306,9 @@ void() CSQC_Parse_Event = { } void PlayGrenTimer(float offset) { - local float channel; + local float channel = CHAN_GREN1; local float soundtime; - local float highest_soundtime; + local float highest_soundtime = -1; for(float i = CHAN_GREN1; i <= CHAN_GREN5; i++) { soundtime = getsoundtime(self, i); diff --git a/csqc/input.qc b/csqc/input.qc index a7310932..9d449e84 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -75,39 +75,31 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { switch (scanx) { case K_ESCAPE: return TRUE; - break; case K_MOUSE1: MouseDown = TRUE; return TRUE; - break; case K_UPARROW: vote_selected_index--; vote_list_offset--; return TRUE; - break; case K_DOWNARROW: vote_selected_index++; vote_list_offset++; return TRUE; - break; case K_PGUP: vote_selected_index -= 10; vote_list_offset -= 10; return TRUE; - break; case K_PGDN: vote_selected_index +=10; vote_list_offset +=10; return TRUE; - break; case K_MWHEELUP: vote_list_offset--; return TRUE; - break; case K_MWHEELDOWN: vote_list_offset++; return TRUE; - break; case K_ENTER: if(vote_selected_item && current_vote == vote_selected_item.owner) { localcmd("cmd break\n"); @@ -115,14 +107,12 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { localcmd("cmd votemap ", vote_selected_item.owner.name, "\n"); } return TRUE; - break; case K_BACKSPACE: if(strlen(vote_list_filter) > 0) { vote_list_filter = substring(vote_list_filter, 0, strlen(vote_list_filter) - 1); ApplyMapFilter(); } return TRUE; - break; case K_DEL: //blank it out if(strlen(vote_list_filter) > 0) { vote_list_filter = ""; @@ -146,11 +136,9 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case K_ESCAPE: showVoteMenu(FALSE); return TRUE; - break; case K_MOUSE1: MouseDown = FALSE; return TRUE; - break; } } } else { @@ -162,7 +150,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case K_ESCAPE: FO_Menu_Game(TRUE); return TRUE; - break; } break; case IE_KEYDOWN: @@ -170,7 +157,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { { case K_ESCAPE: return TRUE; - break; } break; default: diff --git a/csqc/main.qc b/csqc/main.qc index 55e24255..8c754856 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -265,7 +265,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Build(TRUE); break; case "fo_menu_dropammo": - FO_Menu_DropAmmo(TRUE, 1, (player_class == PC_ENGINEER)); + FO_Menu_DropAmmo(TRUE); break; case "fo_menu_cancel": Menu_Cancel(); diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 68243c1a..4e11eaa3 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -640,7 +640,6 @@ float(float evtype, float scanx, float chary, float devid) sui_input_event = case IE_MOUSEABS: _sui_mouse_move([scanx, chary]); return TRUE; - break; case IE_MOUSEDELTA: // Big question mark... // maybe make our own delta based sui_cursor here.. @@ -648,7 +647,6 @@ float(float evtype, float scanx, float chary, float devid) sui_input_event = // delta cursor by passing different params to this func...? // for MVP let's just use mouseabs only return FALSE; - break; case IE_KEYDOWN: if (_sui_binding_command != "") { @@ -668,7 +666,6 @@ float(float evtype, float scanx, float chary, float devid) sui_input_event = return FALSE; return _sui_add_input(chary, scanx); } - break; case IE_KEYUP: if (_sui_binding_command != "") { diff --git a/menu/servers.qc b/menu/servers.qc index c2560c78..8cbb1ccf 100644 --- a/menu/servers.qc +++ b/menu/servers.qc @@ -111,7 +111,7 @@ class mitem_servers : mitem maxsv = slider.val + maxy; float sort = gethostcachevalue(SLIST_SORTFIELD); - string colkey; + string colkey = ""; #define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {if (ui.mousepos[0] > pos_x && ui.mousepos[1] < pos_y+8) colkey = #sortname; pos_x += width+8;} COLUMNS #undef COLUMN @@ -408,4 +408,4 @@ nonstatic void(mitem_desktop desktop) M_Servers = m.add(menuitemcheck_spawn(_("Fraglimit"), "sb_showfraglimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*2], [8*20, -8*1]); m.add(menuitemcheck_spawn(_("Timelimit"), "sb_showtimelimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*1], [8*20, -8*0]); } -}; \ No newline at end of file +}; diff --git a/menusys/mitem_frame.qc b/menusys/mitem_frame.qc index 9a119766..cf93a310 100644 --- a/menusys/mitem_frame.qc +++ b/menusys/mitem_frame.qc @@ -650,7 +650,7 @@ void(vector pos) mitem_frame::item_draw = { ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]); if (item_exclusive) - item_exclusive.item_draw(clientpos + ch.item_position); + item_exclusive.item_draw(clientpos + item_exclusive.item_position); else { for(ch = item_children; ch; ch = ch.item_next) diff --git a/menusys/mitem_spinnymodel.qc b/menusys/mitem_spinnymodel.qc index b52c10af..c59ed59b 100644 --- a/menusys/mitem_spinnymodel.qc +++ b/menusys/mitem_spinnymodel.qc @@ -32,6 +32,7 @@ probably others. it really wouldn't surprise me. //helper function to work around a DP bug. static vector(vector v) vtodpp = { +#pragma warning disable F333 #ifndef CSQC_SIMPLE //so fucking disgustingly ugly. if (dp_workarounds) @@ -41,6 +42,7 @@ static vector(vector v) vtodpp = } #endif return v; +#pragma warning enable F333 }; //make sure the fields are all defined if we're in menuqc or something noref .vector origin; diff --git a/menusys/mitems.qc b/menusys/mitems.qc index 782b580f..ee62af9d 100644 --- a/menusys/mitems.qc +++ b/menusys/mitems.qc @@ -150,6 +150,7 @@ var uiinfo_t ui = void() queryscreensize = { +#pragma warning disable F333 #ifdef MENU //there is no proper way to do this. //fte thus has special checks for these cvars, and they should not be autocvars if you want them to work properly. @@ -172,6 +173,7 @@ void() queryscreensize = } #endif #endif +#pragma warning enable F333 }; //helper function diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 7289f068..6a6a83c7 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -898,7 +898,7 @@ void () UseAirBlastV2 = { vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); vector ab_diameter = ab_start + aim(self,1000) * abrange; - pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); + pointparticles(particleeffectnum("fo_airblast"), ab_origin, v_forward); if (isabjump) { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 0ba3bee0..f317c318 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -886,7 +886,7 @@ void (entity player) FO_Spy_DisguiseLast = { void (entity player) FO_Spy_DisguiseLastSpawned = { local entity te = find(world, classname, "player"); local float latest_spawn_time = 0; - local entity enemy_to_disguise_as; + local entity enemy_to_disguise_as = world; while (te != world) { if (te.team_no != player.team_no) { @@ -899,6 +899,11 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { te = find(te, classname, "player"); } + if (enemy_to_disguise_as == world) { + sprint(self.owner, PRINT_HIGH, "No enemies to disguise as!\n"); + return; + } + if (self.is_undercover == 2 && enemy_to_disguise_as.skin != player.disguise_skin) { CF_Spy_DisguiseStop(); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 847c1db2..b741782c 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3518,7 +3518,7 @@ void () ButtonFrame = { // +grenade1 keyup frame if (keyups & BUTTON5) { if (hold_grens) { - TeamFortress_ThrowGrenade(1); + TeamFortress_ThrowGrenade(); } } @@ -3534,7 +3534,7 @@ void () ButtonFrame = { // +grenade2 keyup frame if (keyups & BUTTON6) { if (hold_grens) { - TeamFortress_ThrowGrenade(2); + TeamFortress_ThrowGrenade(); } } From ca82a7fbedf20cb5e21dbc5015440d019e2f51c9 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 15 Sep 2022 01:06:04 -0700 Subject: [PATCH 1610/2474] Add a visual effect to airblast --- ssqc/pyro.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 7289f068..9512a7f8 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -791,6 +791,8 @@ void () UseAirBlast = { timer.nextthink = time + PC_PYRO_AIRBLAST_COOLDOWN; timer.think = AirBlastReloadFinished; + pointparticles(particleeffectnum("te_teleportsplash"), + self.origin + v_forward * PC_PYRO_AIRBLAST_RANGE / 4, v_forward); FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); makevectors(self.v_angle); entity ent; From 75a3b86635ba303e7b1dd55272459fe17010575c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 15 Sep 2022 18:55:31 +1000 Subject: [PATCH 1611/2474] Add missing break to case statement and use CVARF accessors --- csqc/csextradefs.qc | 1 + csqc/events.qc | 5 ++++- csqc/main.qc | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index cca55bf6..c1ec3157 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -527,6 +527,7 @@ enum { DEFCVAR_FLOAT(fo_fte_hud, 0); DEFCVAR_FLOAT(fo_legacy_sbar, 0); +DEFCVAR_FLOAT(fo_csjumpsounds, 1); float team_no; float is_spectator; diff --git a/csqc/events.qc b/csqc/events.qc index 71b57bb7..bc628b59 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -454,8 +454,11 @@ float(float entnum, float channel, string soundname, float vol, float attenuatio case "player/land.wav": case "player/land2.wav": case "player/h2ojump.wav": - if (autocvar(fo_csjumpsounds, 1, "client-side predicted jump sounds")) + if (CVARF(fo_csjumpsounds)) { return 1; + } else { + break; + } } return 0; diff --git a/csqc/main.qc b/csqc/main.qc index 9aa19f1f..3ca71a4b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -132,7 +132,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Hud_Draw(width, height); sui_end(); - if (autocvar(fo_csjumpsounds, 1, "client-side predicted jump sounds")) { + if (CVARF(fo_csjumpsounds)) { local float health = getstatf(STAT_HEALTH); local float paused = getstatf(STAT_PAUSED); From c6a457ae752e027f1f034bf2a0fad32cc14f5dca Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 16 Sep 2022 00:56:47 +1000 Subject: [PATCH 1612/2474] Get input state before running jumpsound logic --- csqc/main.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/main.qc b/csqc/main.qc index 3ca71a4b..389a0aae 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -138,6 +138,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (pmove_onground && health > 0 && !paused) { // jumping + getinputstate(clientcommandframe); // without this the input buttons are innacurate if ((input_buttons & BUTTON2) && (pmove_vel_z < 180 /* not sliding */)) { if (jumpsound_cooldown < time) { jumpsound_cooldown = time + 0.01; From 48208fab6de1abbed8e353d720d619a0e40bc573 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 12 Sep 2022 20:31:49 -0700 Subject: [PATCH 1613/2474] Grenade ping correction Due to their nature, grenades have all sorts of inconsistencies introduced by delay between client and server around each event. Two players that see each other at the same time, and prime at the same time, will actually not be able to throw at the same time as the player with the lower ping is able to get the server to register their prime first. This is particularly material since grenades don't allow you to throw for the first 800ms, so even 50-100ms ping differences are a large relative advantage. This introduces ping correction, so that the point at which we consider the client to have primed is corrected for their latency when enabled. We ensure that this does not let players prime any faster, or more frequently, than they would have been able to before, only more consistently. One very nice property is that unlike projectile projection, which causes visible projectiles to skip, there are no strange artifacts for other clients as the adjustment occurs before it's possible to throw the grenade. Also rewrite the grenade timer rendering client code to be more compact and to handle the fact that the expiry offset has been adjusted to correct for latency. Clients that do not support CSQC can simply playsound at the point which they prime; this will now be correctly aligned (as the point they primed is properly reflected to the server). Controlled by: localinfo precise_grenades on/off While we'd normally default a server setting on, this is a big enough change that we'll give it a pug or two of testing before pushing it as a default to soak. [For this reason we also temporarily allow mid-round changing of the tunable.] --- README.md | 3 ++ csqc/csextradefs.qc | 51 +++++++++++++++++++---- csqc/events.qc | 98 ++++++++++++++++++++++----------------------- csqc/hud_helpers.qc | 29 -------------- csqc/main.qc | 26 +----------- csqc/status.qc | 43 ++++++++------------ share/defs.h | 8 ++-- ssqc/antilag.qc | 19 ++++++++- ssqc/client.qc | 2 +- ssqc/qw.qc | 6 ++- ssqc/status.qc | 5 ++- ssqc/tfort.qc | 19 +++++---- ssqc/weapons.qc | 10 ++--- 13 files changed, 160 insertions(+), 159 deletions(-) diff --git a/README.md b/README.md index a17cb59b..380a85c7 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ FortressOne Server New features ------ +* `localinfo project_grenades 0/1` [default: 0] Adjust the point at which + grenades are primed to correct for client latency. Does not allow players to +throw grenades any faster, or more frequently; only more consistently. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `localinfo forcereload 0/1` Option to prevent forced reloads. diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index b74c65d7..d353e302 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -436,14 +436,51 @@ typedef struct { } FO_Hud_Settings; FO_Hud_Settings HudSettings; -typedef struct { - float grentype; - float expires; - float icon_index; - float alpha; -} FO_Hud_Grentimer; +enumflags { + FL_GT_SOUND, + FL_GT_THROWN, + FL_GT_ADJPING +}; + +class CsGrenTimer; +CsGrenTimer grentimers[NUM_GREN_TIMERS]; + +class CsGrenTimer { + float primed_at_; + float expires_at_; + float flags_; + float channel_; + float grentype_; + + nonvirtual float() active { return expires_at_ > time; }; + nonvirtual float() expiry { return expires_at_; }; + nonvirtual float() grentype { return grentype_; }; + nonvirtual void() set_thrown { flags_ |= FL_GT_THROWN; }; + nonvirtual float() is_thrown { return flags_ & FL_GT_THROWN; }; + + nonvirtual void(float primed_at, float expires_at, + float grentype, float timer_flags) Set; + nonvirtual void() Stop; -FO_Hud_Grentimer FO_Hud_Grentimers[5]; + static float next_index_; + static CsGrenTimer last_; + + static void() Init { + for (float i = 0; i < grentimers.length; i++) + grentimers[i] = spawn(CsGrenTimer, channel_: CHAN_GREN_START + i); + }; + + static void() StopAll { + for (float i = 0; i < grentimers.length; i++) + grentimers[i].Stop(); + }; + + static CsGrenTimer() GetNext { + return last_ = grentimers[next_index_++ % grentimers.length]; + }; + + static CsGrenTimer() GetLast { return last_; }; +}; // scoreboard stuff typedef struct { diff --git a/csqc/events.qc b/csqc/events.qc index dec39e9b..f84a3161 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,10 +1,6 @@ void ParseSBAR(); -void ParseGrenPrimed(float grentype, float primetime); -void AddGrenTimer(float grentype, float offset); -void AddSilentGrenTimer(float grentype, float offset); -void StartGrenTimer(float slot, float grentype, float offset); -void AddGrenTimer(float grentype, float offset); -void PlayGrenTimer(float offset); +void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); +float StartGrenTimer(float primed_at, float expires_at, float grentype, float play_sound); void() CSQC_Parse_Event = { float msgtype = readbyte(); @@ -104,12 +100,15 @@ void() CSQC_Parse_Event = { SBAR.Identify = readstring(); break; case MSG_GRENPRIMED: - float grentype = readfloat(); - float primetime = readfloat(); - ParseGrenPrimed(grentype, primetime); + float grentype = readbyte(); + float primed_at = readfloat(); + float explodes_at = readfloat(); + ParseGrenPrimed(grentype, primed_at, explodes_at); break; case MSG_GRENTHROWN: - ApplyTransparencyToGrenTimer(); + CsGrenTimer last = CsGrenTimer::GetLast(); + last.set_thrown(); + //CsGrenTimer::GetLast().set_thrown(); break; case MSG_PLAYERDIE: last_death_time = readfloat(); @@ -306,57 +305,56 @@ void() CSQC_Parse_Event = { } } -void PlayGrenTimer(float offset) { - local float channel = CHAN_GREN1; - local float soundtime; - local float highest_soundtime = -1; +void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, + float timer_flags) { + grentype_ = _grentype; + primed_at_ = primed_at; + expires_at_ = expires_at; + flags_ = timer_flags; - for(float i = CHAN_GREN1; i <= CHAN_GREN5; i++) { - soundtime = getsoundtime(self, i); + if (this.flags_ & FL_GT_ADJPING) { + local float rtt = + getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; + expires_at_ -= rtt/2; + } - if (soundtime < 0) { - channel = i; - break; - } + if !(this.flags_ & FL_GT_SOUND) + return; - if (soundtime > highest_soundtime) { - highest_soundtime = soundtime; - channel = i; - } - } + local float adj = 3.8 - (expires_at_ - time); + string sound = cvar_string(FOCMD_GRENTIMERSOUND); + soundupdate(self, channel_, cvar_string(FOCMD_GRENTIMERSOUND), + cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, adj); +} - local string sound = cvar_string(FOCMD_GRENTIMERSOUND); - localsound(sound, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime - soundupdate(self, channel, sound, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); +void CsGrenTimer::Stop() { + expires_at_ = -1; + if (flags_ & FL_GT_SOUND) + soundupdate(self, channel_, "", -1, 0, 0, 0, 0); // -ve volume => stop. + flags_ = 0; } -void ParseGrenPrimed(float grentype, float primetime) { - local float timertype = cvar(FOCMD_GRENTIMER); +void StopGrenTimers() { + for (float i = 0; i < NUM_GREN_TIMERS; i++) + grentimers[i].Stop(); +} - if (primetime < last_death_time) +void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { + if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) return; - if (timertype == 0) { - AddSilentGrenTimer(grentype, 0); - } else if(timertype == 1) { - AddGrenTimer(grentype, 0); - } else if (timertype == 2) { - // We need to offset our sound by 2 RTT/2s: - // The first is the already occurred delay to receive notification. - // The second is the will-occur delay in sending throwgren back. - local float offset = getplayerkeyfloat(player_localnum, - INFOKEY_P_PING)/1000; - - AddGrenTimer(grentype, offset); - } else if (timertype == 3) { - // As above, but uses precise accounting for the already occurred delay. - // Will eventually replace type==2. - local float offset_prime = time - primetime; - local float offset_throw = getplayerkeyfloat(player_localnum, - INFOKEY_P_PING)/1000 / 2; + if (primed_at < last_death_time) + return; - AddGrenTimer(grentype, offset_prime + offset_throw); + local float timer_flags = 0; + switch (cvar(FOCMD_GRENTIMER)) { + case 0: break; + case 1: timer_flags = FL_GT_SOUND; break; + // 2 [and something sane for anything we don't recognize.] + default: timer_flags = FL_GT_SOUND | FL_GT_ADJPING; break; } + CsGrenTimer timer = CsGrenTimer::GetNext(); + timer.Set(primed_at, explodes_at, grentype, timer_flags); } void ParseSBAR() diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 93724fc0..218a2c76 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -483,32 +483,3 @@ vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, ve return pos; } - -void AddGrenTimer(float grentype, float offset) { - if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) - return; - - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - if(FO_Hud_Grentimers[i].grentype == 0) { - StartGrenTimer(i, grentype, offset); - PlayGrenTimer(offset); - break; - } - } -} - -void AddSilentGrenTimer(float grentype, float offset) { - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - if(FO_Hud_Grentimers[i].grentype == 0) { - StartGrenTimer(i, grentype, offset); - break; - } - } -} - -void StartGrenTimer(float slot, float grentype, float offset) { - FO_Hud_Grentimers[slot].grentype = grentype; - FO_Hud_Grentimers[slot].icon_index = grentype; - FO_Hud_Grentimers[slot].alpha = 1; - FO_Hud_Grentimers[slot].expires = time + 3.8 - offset; -} diff --git a/csqc/main.qc b/csqc/main.qc index 59fa23c3..7f5bd666 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,7 +10,6 @@ void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); void AddGrenTimer(float grentype, float offset); -void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); @@ -28,6 +27,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_pic(HudIcons[i].icon); // } + CsGrenTimer::Init(); + registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); @@ -448,29 +449,6 @@ void CSQC_Shutdown() = { FO_WriteSettings(); } -void ApplyTransparencyToGrenTimer() { - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - if (FO_Hud_Grentimers[i].grentype != 0 && FO_Hud_Grentimers[i].alpha != 0.3) { - FO_Hud_Grentimers[i].alpha = 0.3; - break; - } - } -} - -void StopGrenTimers() { - soundupdate(self, CHAN_GREN1, "", 0, 0, 0, 0, 0); - soundupdate(self, CHAN_GREN2, "", 0, 0, 0, 0, 0); - soundupdate(self, CHAN_GREN3, "", 0, 0, 0, 0, 0); - soundupdate(self, CHAN_GREN4, "", 0, 0, 0, 0, 0); - soundupdate(self, CHAN_GREN5, "", 0, 0, 0, 0, 0); - - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - FO_Hud_Grentimers[i].grentype = 0; - FO_Hud_Grentimers[i].expires = 0; - FO_Hud_Grentimers[i].icon_index = 0; - } -} - float last_servercommandframe; void _Sync_ServerCommandFrame() { // Server command frames are monotonically unique, we can skip processing diff --git a/csqc/status.qc b/csqc/status.qc index a9312c47..28cca665 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -101,7 +101,6 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { if (display) { FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); - float Scale = panel.Scale; float TextScale = panel.TextScale; FO_Hud_Panel panel2; @@ -111,35 +110,27 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { panel2.Display = panel.Display; panel2.FillSize = panel.FillSize; - for(float i = 0; i < FO_Hud_Grentimers.length; i++) { - if(FO_Hud_Grentimers[i].grentype > 0) { - timeleft = floor(FO_Hud_Grentimers[i].expires - time) + 1; - if(timeleft < 1) { - //Expire and fill the gap if there are any active grentimers afterwards - FO_Hud_Grentimers[i].grentype = 0; - for(float j = i + 1; j < FO_Hud_Grentimers.length; j++) { - FO_Hud_Grentimers[j - 1].grentype = FO_Hud_Grentimers[j].grentype; - FO_Hud_Grentimers[j - 1].expires = FO_Hud_Grentimers[j].expires; - FO_Hud_Grentimers[j - 1].icon_index = FO_Hud_Grentimers[j].icon_index; - FO_Hud_Grentimers[j - 1].alpha = FO_Hud_Grentimers[j].alpha; - } - FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].grentype = 0; - FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].expires = 0; - FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].icon_index = 0; - FO_Hud_Grentimers[FO_Hud_Grentimers.length - 1].alpha = 0; - continue; - } + for (float i = 0; i < grentimers.length; i++) { + local CsGrenTimer gt = grentimers[i]; - if(i) { - panel2.Scale = Scale * 0.8; - panel2.TextScale = TextScale * 0.8; - } + if (!gt.active()) + continue; - Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[FO_Hud_Grentimers[i].icon_index].icon, FO_Hud_Grentimers[i].alpha); + timeleft = floor(gt.expiry() - time) + 1; + if (timeleft < 1) + continue; - panel2.Position = panel2.Position + [0, panel2.FillSize.y * panel2.Scale]; - timercount++; + if (timercount) { + panel2.Scale = Scale * 0.8; + panel2.TextScale = TextScale * 0.8; } + + local float alpha = (gt.is_thrown()) ? 0.3 : 1.0; + Hud_DrawPanelLMP(&panel2, ftos(timeleft), + GrenadeIcons[gt.grentype()].icon, alpha); + panel2.Position = panel2.Position + + [0, panel2.FillSize.y * panel2.Scale]; + timercount++; } } if(fo_hud_editor && (!display || !timercount)) { diff --git a/share/defs.h b/share/defs.h index 89e3a0c3..2cfb7575 100644 --- a/share/defs.h +++ b/share/defs.h @@ -173,11 +173,9 @@ #define CHAN_ITEM 3 #define CHAN_BODY 4 #define CHAN_NO_PHS_ADD 8 -#define CHAN_GREN1 9 -#define CHAN_GREN2 10 -#define CHAN_GREN3 11 -#define CHAN_GREN4 12 -#define CHAN_GREN5 13 +#define NUM_GREN_TIMERS 5 +#define CHAN_GREN_START 9 +#define CHAN_GREN_END (CHAN_GREN_START + NUM_GREN_TIMERS - 1) #define ATTN_NONE 0 #define ATTN_NORM 1 diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 80831003..da2c9b5f 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -26,4 +26,21 @@ void AL_ProjectProjectile (entity projectile) { } setorigin(projectile, projected_origin); -} \ No newline at end of file +} + +float AL_GrenadeOffset() { + if (!CF_GetSetting("pg", "project_grenades", "off")) + return 0; + + local float offset = infokeyf(self, INFOKEY_P_PING) / 1000; + local float smallest_grenade_think = 0.5; + + offset /= 2; + // Make sure we'll always order before first think. + offset = min(offset, smallest_grenade_think - 0.1); + + // Don't allow prime to move before throw (or to the same frame). + offset = min(offset, time - (self.last_throw + 0.013)); + + return offset; +} diff --git a/ssqc/client.qc b/ssqc/client.qc index 90194714..0dc2457e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1489,7 +1489,7 @@ void () spawn_guard_think = { if(!te.has_disconnected && infokey(te, "dap") == "1") { oldself = self; self = te; - TeamFortress_PrimeGrenade(1); + TeamFortress_PrimeGrenade(1, FALSE); self = oldself; } te = find (te, classname, "player"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index fe1ab59b..99c4c71a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -763,6 +763,7 @@ float FO_FlashDimension; // precise grenades .entity grenade_timer; +.float last_throw; // allow for default goal state .float default_group_no; @@ -785,9 +786,10 @@ string goal_class_names[7] = { // people complain about settings, let's track them -string settings_to_track_list[2] = { +string settings_to_track_list[3] = { "sv_antilag", - "project_weapons" + "project_weapons", + "project_grenades", }; typedef struct setting_t { diff --git a/ssqc/status.qc b/ssqc/status.qc index b17b7821..520545b7 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -796,14 +796,15 @@ string GetSBClassInfo(entity pl, float csqcactive) return st1; } -void UpdateClientGrenadePrimed(entity pl, float grentype) = { +void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); - WriteFloat(MSG_MULTICAST, grentype); + WriteByte(MSG_MULTICAST, grentype); WriteFloat(MSG_MULTICAST, time); + WriteFloat(MSG_MULTICAST, explodes_at); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 1d5965be..cb538802 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -790,6 +790,7 @@ void () GrenadeTimer = { void (entity timer) FO_SpawnThrownGrenade = { local entity user = timer.owner; user.tfstate &= ~(TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING); + user.last_throw = time; if (grentimers && infokeyf(user, INFOKEY_P_CSQCACTIVE)) { UpdateClientGrenadeThrown(user); @@ -923,7 +924,7 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { (self.tfstate & TFSTATE_GRENTHROWING)) TeamFortress_ThrowGrenade(); else { - TeamFortress_PrimeGrenade(inp); + TeamFortress_PrimeGrenade(inp, TRUE); if ( ((inp == 1 && self.tp_grenade_switch != 1) || (inp == 2 && self.tp_grenade_switch == 1)) && self.tp_grenades_1 == GR_TYPE_CALTROP) @@ -935,7 +936,9 @@ void () TeamFortress_GrenadePrimedThink; void () FO_PreciseGrenadeThink; float () FO_UsePreciseGrenades; -void (float inp) TeamFortress_PrimeGrenade = { +// is_player defines whether this originated from the player or server. Player +// generated primes are corrected for latency when project_grenades is on. +void (float inp, float is_player) TeamFortress_PrimeGrenade = { local float gtype; local string gs; local string ptime; @@ -1098,12 +1101,14 @@ void (float inp) TeamFortress_PrimeGrenade = { tGrenade.impulse = TF_GRENADE_1; else if (inp == 2) tGrenade.impulse = TF_GRENADE_2; - tGrenade.nextthink = time + 0.8; + local float lag_adjust = is_player ? AL_GrenadeOffset() : 0; + + tGrenade.nextthink = time + 0.8 - lag_adjust; if (gtype == GR_TYPE_CALTROP) - tGrenade.heat = time + 0.5 + 0.5; + tGrenade.heat = time + 0.5 + 0.5 - lag_adjust; else { - tGrenade.heat = time + 3 + 0.8; + tGrenade.heat = time + 3 + 0.8 - lag_adjust; RemoveGrenadeTimers(); @@ -1111,7 +1116,7 @@ void (float inp) TeamFortress_PrimeGrenade = { local float notimers = stof(infokey(self, "nt")); if (grentimers && notimers != 1) { timer = spawn(); - timer.nextthink = time + 0.8; + timer.nextthink = time + 0.8 - lag_adjust; timer.think = GrenadeTimer; timer.heat = 4; timer.owner = self; @@ -1121,7 +1126,7 @@ void (float inp) TeamFortress_PrimeGrenade = { } } if (grentimers && csqcactive) { - UpdateClientGrenadePrimed(self, gtype); + UpdateClientGrenadePrimed(self, gtype, tGrenade.heat); } } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1df68a95..2809efee 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -30,7 +30,7 @@ void () TeamFortress_ShowTF; void () TeamFortress_AssaultWeapon; void () TeamFortress_IncendiaryCannon; void () TeamFortress_FlameThrower; -void (float inp) TeamFortress_PrimeGrenade; +void (float inp, float is_player) TeamFortress_PrimeGrenade; void () TeamFortress_ThrowGrenade; void (float inp) TeamFortress_PrimeThrowGrenade; void () TeamFortress_GrenadeSwitch; @@ -3020,9 +3020,9 @@ void () ImpulseCommands = { if (!self.is_feigning) { if (self.impulse == TF_GRENADE_1) - TeamFortress_PrimeGrenade(1); + TeamFortress_PrimeGrenade(1, TRUE); else if (self.impulse == TF_GRENADE_2) - TeamFortress_PrimeGrenade(2); + TeamFortress_PrimeGrenade(2, TRUE); else if (self.impulse == TF_GRENADE_T) TeamFortress_ThrowGrenade(); else if (self.impulse == TF_GRENADE_PT_1) @@ -3510,7 +3510,7 @@ void () ButtonFrame = { // +grenade1 keydown frame if (keydowns & BUTTON5) { if (hold_grens) { - TeamFortress_PrimeGrenade(1); + TeamFortress_PrimeGrenade(1, TRUE); } else { TeamFortress_PrimeThrowGrenade(1); } @@ -3526,7 +3526,7 @@ void () ButtonFrame = { // +grenade2 keydown frame if (keydowns & BUTTON6) { if (hold_grens) { - TeamFortress_PrimeGrenade(2); + TeamFortress_PrimeGrenade(2, TRUE); } else { TeamFortress_PrimeThrowGrenade(2); } From 7600cb1ecf792b396d757a8e55d90c0e4bd4d883 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 16 Sep 2022 23:25:31 -0700 Subject: [PATCH 1614/2474] Debug patch which adds fo_grentimer_debug which dumps additional timer info --- csqc/events.qc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/csqc/events.qc b/csqc/events.qc index f84a3161..ae133e83 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -339,6 +339,8 @@ void StopGrenTimers() { grentimers[i].Stop(); } +DEFCVAR_FLOAT(fo_grentimer_debug, 0); + void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) return; @@ -355,6 +357,19 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { } CsGrenTimer timer = CsGrenTimer::GetNext(); timer.Set(primed_at, explodes_at, grentype, timer_flags); + + if (CVARF(fo_grentimer_debug) == 1) { + float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; + + float expires_old = time + 3.8 - ping; + float expires_new = timer.expiry(); + float expires_ideal = explodes_at - ping/2; + + print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f\n", + primed_at, explodes_at, explodes_at - primed_at)); + print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", + expires_ideal, expires_new, expires_old)); + } } void ParseSBAR() From ec21372e44239aa765a03addcf06c64d7df833d1 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 17 Sep 2022 14:26:51 -0700 Subject: [PATCH 1615/2474] Add additional debugging and retry around playing Trying to debug some inconsistencies with soundupdate. --- csqc/csdefs.qc | 2 -- csqc/csextradefs.qc | 3 ++- csqc/events.qc | 59 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 37b5e5aa..ff7db300 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -241,8 +241,6 @@ const float CHAN_WEAPON = 1; const float CHAN_VOICE = 2; const float CHAN_ITEM = 3; const float CHAN_BODY = 4; -const float CHAN_GREN1 = 5; -const float CHAN_GREN2 = 6; const float ATTN_NONE = 0; /* Sounds with this attenuation can be heard throughout the map */ const float ATTN_NORM = 1; /* Standard attenuation */ const float ATTN_IDLE = 2; /* Extra attenuation so that sounds don't travel too far. */ diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d353e302..a919905a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -457,6 +457,7 @@ class CsGrenTimer { nonvirtual float() grentype { return grentype_; }; nonvirtual void() set_thrown { flags_ |= FL_GT_THROWN; }; nonvirtual float() is_thrown { return flags_ & FL_GT_THROWN; }; + nonvirtual float() channel { return channel_; }; nonvirtual void(float primed_at, float expires_at, float grentype, float timer_flags) Set; @@ -466,7 +467,7 @@ class CsGrenTimer { static CsGrenTimer last_; static void() Init { - for (float i = 0; i < grentimers.length; i++) + for (float i = 0; i < NUM_GREN_TIMERS; i++) grentimers[i] = spawn(CsGrenTimer, channel_: CHAN_GREN_START + i); }; diff --git a/csqc/events.qc b/csqc/events.qc index ae133e83..a2a507af 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -305,6 +305,43 @@ void() CSQC_Parse_Event = { } } +DEFCVAR_FLOAT(fo_grentimer_debug, 0); + +void play_retry(string sound, float channel, float volume, float adj) { + for (float i = 0; i < 3; i++) { + float update = soundupdate(self, channel, sound, volume, 0, 0, 0, adj); + if (CVARF(fo_grentimer_debug) & 1) + print(sprintf("%d soundupdate(%d) = %0.2f!\n", i, channel, update)); + if (update == TRUE) { + return; + } + } +} + +void OldPlayGren(float offset) { + local float channel = CHAN_GREN_START; + local float soundtime; + local float highest_soundtime = -1; + + for(float i = CHAN_GREN_START; i <= CHAN_GREN_END; i++) { + soundtime = getsoundtime(self, i); + + if (soundtime < 0) { + channel = i; + break; + } + + if (soundtime > highest_soundtime) { + highest_soundtime = soundtime; + channel = i; + } + } + + local string sound = cvar_string(FOCMD_GRENTIMERSOUND); + localsound(sound, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime + soundupdate(self, channel, sound, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); +} + void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, float timer_flags) { grentype_ = _grentype; @@ -323,14 +360,21 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, local float adj = 3.8 - (expires_at_ - time); string sound = cvar_string(FOCMD_GRENTIMERSOUND); - soundupdate(self, channel_, cvar_string(FOCMD_GRENTIMERSOUND), - cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, adj); + float volume = cvar(FOCMD_GRENTIMERVOLUME); + + if (CVARF(fo_grentimer_debug) & 4) { + localsound(sound, channel_, 0); + play_retry(sound, channel_, volume, adj); + } else { + OldPlayGren(adj); + } } + void CsGrenTimer::Stop() { expires_at_ = -1; if (flags_ & FL_GT_SOUND) - soundupdate(self, channel_, "", -1, 0, 0, 0, 0); // -ve volume => stop. + soundupdate(self, channel_, "", 0, 0, 0, 0, 0); // -ve volume => stop. flags_ = 0; } @@ -339,8 +383,6 @@ void StopGrenTimers() { grentimers[i].Stop(); } -DEFCVAR_FLOAT(fo_grentimer_debug, 0); - void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) return; @@ -358,15 +400,16 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { CsGrenTimer timer = CsGrenTimer::GetNext(); timer.Set(primed_at, explodes_at, grentype, timer_flags); - if (CVARF(fo_grentimer_debug) == 1) { + if (CVARF(fo_grentimer_debug) & 1) { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; float expires_old = time + 3.8 - ping; float expires_new = timer.expiry(); float expires_ideal = explodes_at - ping/2; - print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f\n", - primed_at, explodes_at, explodes_at - primed_at)); + print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f chan=%d\n", + primed_at, explodes_at, explodes_at - primed_at, + timer.channel())); print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", expires_ideal, expires_new, expires_old)); } From 09ec28f53e89abf99dba56e7c2db2b67e2f1fd89 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 17 Sep 2022 17:29:10 -0700 Subject: [PATCH 1616/2474] Following some more leads. --- csqc/csextradefs.qc | 4 +++- csqc/events.qc | 4 ++-- share/defs.h | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index a919905a..3b528779 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -467,8 +467,10 @@ class CsGrenTimer { static CsGrenTimer last_; static void() Init { + float num_gren_sound = CHAN_GREN_END - CHAN_GREN_START + 1; for (float i = 0; i < NUM_GREN_TIMERS; i++) - grentimers[i] = spawn(CsGrenTimer, channel_: CHAN_GREN_START + i); + grentimers[i] = spawn(CsGrenTimer, + channel_: CHAN_GREN_START + (i % num_gren_sound)); }; static void() StopAll { diff --git a/csqc/events.qc b/csqc/events.qc index a2a507af..56024c3d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -309,7 +309,7 @@ DEFCVAR_FLOAT(fo_grentimer_debug, 0); void play_retry(string sound, float channel, float volume, float adj) { for (float i = 0; i < 3; i++) { - float update = soundupdate(self, channel, sound, volume, 0, 0, 0, adj); + float update = soundupdate(world, channel, sound, volume, 0, 0, 0, adj); if (CVARF(fo_grentimer_debug) & 1) print(sprintf("%d soundupdate(%d) = %0.2f!\n", i, channel, update)); if (update == TRUE) { @@ -339,7 +339,7 @@ void OldPlayGren(float offset) { local string sound = cvar_string(FOCMD_GRENTIMERSOUND); localsound(sound, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime - soundupdate(self, channel, sound, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); + soundupdate(world, channel, sound, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); } void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, diff --git a/share/defs.h b/share/defs.h index 2cfb7575..aed2a1ff 100644 --- a/share/defs.h +++ b/share/defs.h @@ -172,10 +172,10 @@ #define CHAN_VOICE 2 #define CHAN_ITEM 3 #define CHAN_BODY 4 +#define CHAN_GREN_START 5 +#define CHAN_GREN_END 7 #define CHAN_NO_PHS_ADD 8 -#define NUM_GREN_TIMERS 5 -#define CHAN_GREN_START 9 -#define CHAN_GREN_END (CHAN_GREN_START + NUM_GREN_TIMERS - 1) +#define NUM_GREN_TIMERS 5 // We overlap channels when >3 active. #define ATTN_NONE 0 #define ATTN_NORM 1 From bcd5121ce73d98fff3cfa977817c725c6046e904 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 17 Sep 2022 23:54:22 -0700 Subject: [PATCH 1617/2474] The hunt continues. So a major part of the issue seems to be that the reference "self" was changing due to migration of timers into a class. However, it turns out we were getting fortunate before and that self was actually the world entity and not the player. This turns out to be the entire reason that soundupdate even worked with localsound, as the latter implies a default entity of zero. This explains why we got double sounds even with the identical calls under the new code (as implicit entities from the grentimer entities were substituted. This seems to work, I get very occasional misses, but I suspect those were the ones you were also seeing before. I'm not sure about the PHS stuff, I've gone through the FTE code and it doesn't look like it's strongly interpreted for Q1 despite the docs and other mod's usage. I've restored the extra channels for now. I've left the old sound code as the default while I test the new one in a few pugs before flipping them. Also made sure the timer sound was cached to avoid potential hitching (and anything to generally increase reliability). --- csqc/events.qc | 31 +++++++++++++++---------------- share/defs.h | 7 +++++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 56024c3d..d838e018 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -307,15 +307,13 @@ void() CSQC_Parse_Event = { DEFCVAR_FLOAT(fo_grentimer_debug, 0); -void play_retry(string sound, float channel, float volume, float adj) { - for (float i = 0; i < 3; i++) { - float update = soundupdate(world, channel, sound, volume, 0, 0, 0, adj); - if (CVARF(fo_grentimer_debug) & 1) - print(sprintf("%d soundupdate(%d) = %0.2f!\n", i, channel, update)); - if (update == TRUE) { - return; - } +string cached_timer; +string GetGrenTimerSound() { + string wav = cvar_string(FOCMD_GRENTIMERSOUND); + if (cached_timer != wav) { + cached_timer = wav; } + return wav; } void OldPlayGren(float offset) { @@ -324,7 +322,7 @@ void OldPlayGren(float offset) { local float highest_soundtime = -1; for(float i = CHAN_GREN_START; i <= CHAN_GREN_END; i++) { - soundtime = getsoundtime(self, i); + soundtime = getsoundtime(world, i); if (soundtime < 0) { channel = i; @@ -337,9 +335,9 @@ void OldPlayGren(float offset) { } } - local string sound = cvar_string(FOCMD_GRENTIMERSOUND); - localsound(sound, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime - soundupdate(world, channel, sound, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); + local string wav = GetGrenTimerSound(); + localsound(wav, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime + soundupdate(world, channel, wav, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); } void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, @@ -359,13 +357,14 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, return; local float adj = 3.8 - (expires_at_ - time); - string sound = cvar_string(FOCMD_GRENTIMERSOUND); + string wav = GetGrenTimerSound(); float volume = cvar(FOCMD_GRENTIMERVOLUME); - if (CVARF(fo_grentimer_debug) & 4) { - localsound(sound, channel_, 0); - play_retry(sound, channel_, volume, adj); + if (CVARF(fo_grentimer_debug) & 2) { + localsound(wav, channel_, volume); + soundupdate(world, channel_, wav, volume, 0, 0, 0, adj); } else { + // Default to old until new gets more testing. OldPlayGren(adj); } } diff --git a/share/defs.h b/share/defs.h index aed2a1ff..df2c16e7 100644 --- a/share/defs.h +++ b/share/defs.h @@ -172,10 +172,13 @@ #define CHAN_VOICE 2 #define CHAN_ITEM 3 #define CHAN_BODY 4 -#define CHAN_GREN_START 5 -#define CHAN_GREN_END 7 #define CHAN_NO_PHS_ADD 8 + +// We can overlap these with regular channels since they play on the world ent. #define NUM_GREN_TIMERS 5 // We overlap channels when >3 active. +#define CHAN_GREN_START 5 +#define CHAN_GREN_END 9 +// #define CHAN_GREN_END (CHAN_GREN_START + NUM_GREN_TIMERS - 1) #define ATTN_NONE 0 #define ATTN_NORM 1 From 94302176dd8aa17a6f4ffe63012f44bbfddcda97 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 18 Sep 2022 01:46:59 -0700 Subject: [PATCH 1618/2474] - Update to use fte extensions ver 6306 - Removed reprecated API use such as calltimeofday - We preserve dimension_see{,n} since these are used by flash grenades and the unsupported parts (MVD, Splitscreen) we can live with. - Fix minor bug in printing name of banned player. --- csqc/status.qc | 2 +- share/fteextensions.qc | 1513 ++++++++++++++++++++++++++++------------ ssqc/admin.qc | 28 +- ssqc/camera.qc | 6 +- ssqc/clan.qc | 80 +-- ssqc/client.qc | 5 +- ssqc/commands.qc | 4 +- ssqc/debug.qc | 4 +- ssqc/defs.qc | 121 ---- ssqc/events.qc | 2 +- ssqc/login.qc | 54 -- ssqc/menu.qc | 4 +- ssqc/quadmode.qc | 8 +- ssqc/status.qc | 4 +- ssqc/tfort.qc | 28 +- ssqc/tforttm.qc | 4 +- ssqc/vote.qc | 8 +- ssqc/world.qc | 3 +- 18 files changed, 1162 insertions(+), 716 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index a9312c47..b099dc3e 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1159,7 +1159,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gun6","Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, {"gun7","Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {"gun8","Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, + {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, }; //var FO_Hud_Panel Hud_ExtraPanels[] = { diff --git a/share/fteextensions.qc b/share/fteextensions.qc index 7fc00a9e..a47a9767 100644 --- a/share/fteextensions.qc +++ b/share/fteextensions.qc @@ -1,16 +1,8 @@ /* -This file was automatically generated by FTE Quake v1.06 +This file was generated by FTE Quake 6306, dated 2022-08-19T13:30:16.464410Z. This file can be regenerated by issuing the following command: pr_dumpplatform -o fteextensions -Available options: --Ffte - target only FTE (optimations and additional extensions) --Tnq - dump specifically NQ fields --Tqw - dump specifically QW fields --Tcs - dump specifically CSQC fields --Tmenu - dump specifically menuqc fields --Fdefines - generate #defines instead of constants --Faccessors - use accessors instead of basic types via defines --O - write to a different qc file +(Use the -help arg for a list of available args) */ #pragma noref 1 //#pragma flag enable logicops @@ -18,53 +10,35 @@ Available options: #pragma warning error Q105 /*too few parms. The vanilla qcc didn't validate properly, hence why fteqcc normally treats it as a warning.*/ #pragma warning error Q106 /*assignment to constant/lvalue. Define them as var if you want to initialise something.*/ #pragma warning error Q208 /*system crc unknown. Compatibility goes out of the window if you disable this.*/ -#pragma warning disable F211 /*system crc outdated (eg: dp's csqc). Note that this may trigger emulation.*/ #pragma warning enable F301 /*non-utf-8 strings. Think of the foreigners! Also think of text editors that insist on screwing up your char encodings.*/ #pragma warning enable F302 /*uninitialised locals. They usually default to 0 in qc (except in recursive functions), but its still probably a bug*/ #if !defined(CSQC) && !defined(NQSSQC) && !defined(QWSSQC)&& !defined(MENU) -#ifdef QUAKEWORLD -#define QWSSQC + #ifdef QUAKEWORLD + #define QWSSQC + #else + #define NQSSQC + #endif +#endif +#if !defined(SSQC) && (defined(QWSSQC) || defined(NQSSQC)) + #define SSQC +#endif +#if defined(CSQC) || defined(MENU) + #define DEP_CSQC DEP #else -#define NQSSQC + #define DEP_CSQC __deprecated("Use CSQC for this") #endif +#ifndef DEP + #define DEP __deprecated //predefine this if you want to avoid our deprecation warnings. #endif -#if !defined(SSQC) && (defined(QWSSQC) || defined(NQSSQC)) -#define SSQC +#ifndef FTEDEP + #define FTEDEP(reason) //for symbols deprecated in FTE that may still be useful/required for other engines #endif -#define FTE_PEXT_SETVIEW /* NQ's svc_setview works correctly even in quakeworld */ -#define DP_ENT_SCALE -#define FTE_PEXT_LIGHTSTYLECOL -#define DP_ENT_ALPHA -#define FTE_PEXT_VIEW2 -#define FTE_PEXT_ACURATETIMINGS -#define FTE_PEXT_SOUNDDBL -#define FTE_PEXT_FATNESS -#define DP_HALFLIFE_MAP -#define FTE_PEXT_TE_BULLET -#define FTE_PEXT_HULLSIZE -#define FTE_PEXT_MODELDBL -#define FTE_PEXT_ENTITYDBL -#define FTE_PEXT_ENTITYDBL2 -#define FTE_PEXT_FLOATCOORDS -#define FTE_PEXT_VWEAP -#define FTE_PEXT_Q2BSP -#define FTE_PEXT_Q3BSP -#define DP_ENT_COLORMOD -#define FTE_HEXEN2 -#define FTE_PEXT_SPAWNSTATIC -#define FTE_PEXT_CUSTOMTENTS -#define FTE_PEXT_256PACKETENTITIES -#define TEI_SHOWLMP2 -#define DP_GFX_QUAKE3MODELTAGS -#define FTE_PK3DOWNLOADS -#define PEXT_CHUNKEDDOWNLOADS -#define EXT_CSQC_SHARED -#define PEXT_DPFLAGS -#define EXT_CSQC #define BX_COLOREDTEXT #define DP_CON_SET /* The 'set' console command exists, and can be used to create/set cvars. */ #define DP_CON_SETA /* The 'seta' console command exists, like the 'set' command, but also marks the cvar for archiving, allowing it to be written into the user's config. Use this command in your default.cfg file. */ +#define DP_CSQC_ROTATEMOVES #define DP_EF_ADDITIVE +#define DP_ENT_ALPHA #define DP_EF_BLUE #define DP_EF_FULLBRIGHT #define DP_EF_NODEPTHTEST @@ -72,14 +46,18 @@ Available options: #define DP_EF_NOGUNBOB #define DP_EF_NOSHADOW #define DP_EF_RED +#define DP_ENT_COLORMOD #define DP_ENT_CUSTOMCOLORMAP #define DP_ENT_EXTERIORMODELTOCLIENT +#define DP_ENT_SCALE #define DP_ENT_TRAILEFFECTNUM /* self.traileffectnum=particleeffectnum("myeffectname"); can be used to attach a particle trail to the given server entity. This is equivelent to calling trailparticles each frame. */ #define DP_ENT_VIEWMODEL #define DP_GECKO_SUPPORT #define DP_GFX_FONTS +#define DP_GFX_QUAKE3MODELTAGS #define DP_GFX_SKINFILES #define DP_GFX_SKYBOX +#define DP_HALFLIFE_MAP #define DP_HALFLIFE_MAP_CVAR #define DP_INPUTBUTTONS #define DP_LIGHTSTYLE_STATICVALUE @@ -94,6 +72,7 @@ Available options: #define DP_QC_CVAR_DEFSTRING #define DP_QC_CVAR_STRING #define DP_QC_CVAR_TYPE +#define DP_QC_DIGEST_SHA256 #define DP_QC_EDICT_NUM #define DP_QC_ENTITYDATA #define DP_QC_ETOS @@ -103,9 +82,12 @@ Available options: #define DP_QC_FINDCHAINFLAGS #define DP_QC_FINDFLOAT #define DP_QC_FS_SEARCH +#define DP_QC_FS_SEARCH_PACKFILE +#define DP_QC_GETLIGHT #define DP_QC_GETSURFACE #define DP_QC_GETSURFACEPOINTATTRIBUTE #define DP_QC_GETTAGINFO +#define DP_QC_I18N /* Specifies that the engine uses $MODULE.dat.$LANG.po files that translates the dotranslate_* globals on load - these are usually created via the _("foo") qcc intrinsic. */ #define DP_QC_MINMAXBOUND #define DP_QC_MULTIPLETEMPSTRINGS /* Superseded by DP_QC_UNLIMITEDTEMPSTRINGS. Functions that return a temporary string will not overwrite/destroy previous temporary strings until at least 16 strings are returned (or control returns to the engine). */ #define DP_QC_RANDOMVEC @@ -132,6 +114,7 @@ Available options: #define DP_QC_WHICHPACK #define DP_QUAKE2_MODEL #define DP_QUAKE2_SPRITE +#define DP_QUAKE3_MAP #define DP_QUAKE3_MODEL #define DP_REGISTERCVAR #define DP_SND_SOUND7_WIP2 @@ -140,8 +123,10 @@ Available options: #define DP_SOLIDCORPSE #define DP_SPRITE32 #define DP_SV_BOTCLIENT +#define DP_SV_CLIENTCAMERA /* Works like svc_setview except also handles pvs. */ #define DP_SV_CLIENTCOLORS /* Provided only for compatibility with DP. */ #define DP_SV_CLIENTNAME /* Provided only for compatibility with DP. */ +#define DP_SV_CUSTOMIZEENTITYFORCLIENT /* Deprecated feature for compat with DP. Can be slow, incompatible with splitscreen, usually malfunctions with mvds. */ #define DP_SV_DRAWONLYTOCLIENT #define DP_SV_DROPCLIENT /* Equivelent to quakeworld's stuffcmd(self,"disconnect\n"); hack */ #define DP_SV_EFFECT @@ -151,7 +136,9 @@ Available options: #define DP_SV_POINTSOUND #define DP_SV_PRECACHEANYTIME /* Specifies that the various precache builtins can be called at any time. WARNING: precaches are sent reliably while sound events, modelindexes, and particle events are not. This can mean sounds and particles might not work the first time around, or models may take a while to appear (after the reliables are received and the model is loaded from disk). Always attempt to precache a little in advance in order to reduce these issues (preferably at the start of the map...) */ #define DP_SV_PRINT /* Says that the print builtin can be used from nqssqc (as well as just csqc), bypassing the developer cvar issues. */ +#define DP_SV_ROTATINGBMODEL /* Engines that support this support avelocity on MOVETYPE_PUSH entities, pushing entities out of the way as needed. */ #define DP_SV_SETCOLOR +#define DP_SV_SHUTDOWN #define DP_SV_SPAWNFUNC_PREFIX #define DP_SV_WRITEPICTURE #define DP_SV_WRITEUNTERMINATEDSTRING @@ -166,6 +153,8 @@ Available options: #define DP_TE_STANDARDEFFECTBUILTINS #define DP_VIEWZOOM #define EXT_BITSHIFT +#define EXT_CSQC +#define EXT_CSQC_SHARED #define EXT_DIMENSION_VISIBILITY #define EXT_DIMENSION_PHYSICS #define EXT_DIMENSION_GHOST @@ -187,6 +176,7 @@ Available options: #define FTE_FORCEINFOKEY /* Provides an easy way to change a user's userinfo from the server. */ #define FTE_GFX_QUAKE3SHADERS /* specifies that the engine has full support for vanilla quake3 shaders */ #define FTE_GFX_REMAPSHADER /* With the raw power of stuffcmds, the r_remapshader console command is exposed! This mystical command can be used to remap any shader to another. Remapped shaders that specify $diffuse etc in some form will inherit the textures implied by the surface. */ +#define FTE_GFX_IQM_HITMESH /* Supports hitmesh iqm extensions. Also supports geomsets and embedded events. */ #define FTE_GFX_MODELEVENTS /* Provides a query for per-animation events in model files, including from progs/foo.mdl.events files. */ #define FTE_ISBACKBUFFERED /* Allows you to check if a client has too many reliable messages pending. */ #define FTE_MEMALLOC /* Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games. */ @@ -195,9 +185,21 @@ Available options: #define FTE_MULTIPROGS /* Multiple progs.dat files can be loaded inside the same qcvm. Insert new ones with addprogs inside the 'init' function, and use externvalue+externset to rewrite globals (and hook functions) to link them together. Note that the result is generally not very clean unless you carefully design for it beforehand. */ #define FTE_MULTITHREADED /* Faux multithreading, allowing multiple contexts to run in sequence. */ #define FTE_MVD_PLAYERSTATS /* In csqc, getplayerstat can be used to query any player's stats when playing back MVDs. isdemo will return 2 in this case. */ -#define FTE_PART_SCRIPT /* Specifies that the r_particledesc cvar can be used to select a list of particle effects to load from particles/*.cfg, the format of which is documented elsewhere. */ +#define FTE_PART_SCRIPT /* Specifies that the r_particledesc cvar can be used to select a list of particle effects to load from particles/foo.cfg, the format of which is documented elsewhere. */ #define FTE_PART_NAMESPACES /* Specifies that the engine can use foo.bar to load effect foo from particle description bar. When used via ssqc, this should cause the client to download whatever effects as needed. */ #define FTE_PART_NAMESPACE_EFFECTINFO /* Specifies that effectinfo.bar can load effects from effectinfo.txt for DP compatibility. */ +#define FTE_PEXT_SETVIEW /* NQ's svc_setview works correctly even in quakeworld */ +#define FTE_PEXT_LIGHTSTYLECOL +#define FTE_PEXT_VIEW2 +#define FTE_PEXT_FATNESS +#define FTE_PEXT_TE_BULLET +#define FTE_PEXT_FLOATCOORDS +#define FTE_PEXT_Q2BSP /* Specifies that the client supports q2bsps. */ +#define FTE_PEXT_Q3BSP /* Specifies that the client supports q3bsps. */ +#define FTE_HEXEN2 +#define FTE_PEXT_SPAWNSTATIC +#define FTE_PEXT_CUSTOMTENTS +#define FTE_PEXT_256PACKETENTITIES /* Specifies that the client is not limited to vanilla's limit of only 64 ents visible at once. */ #define FTE_QC_BASEFRAME /* Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc. */ #define FTE_QC_FILE_BINARY /* Extends FRIK_FILE with binary read+write, as well as allowing seeking. Requires pointers. */ #define FTE_QC_CHANGELEVEL_HUB /* Adds an extra argument to changelevel which is carried over to the next map in the 'spawnspot' global. Maps will be saved+reloaded until the extra argument is omitted again, purging all saved maps. Saved games will contain a copy of each preserved map. parm1-parm64 globals can be used, giving more space to transfer more player data. */ @@ -205,6 +207,10 @@ Available options: #define FTE_QC_CHECKPVS #define FTE_QC_CROSSPRODUCT #define FTE_QC_CUSTOMSKINS /* The engine supports the use of q3 skins, as well as the use of such skin 'files' to specify rich top+bottom colours, qw skins, geomsets, or texture composition even on non-players.. */ +#define FTE_QC_DIGEST_SHA1 /* The digest_hex builtin supports 160-bit sha1 hashes. */ +#define FTE_QC_DIGEST_SHA224 /* The digest_hex builtin supports 224-bit sha2 hashes. */ +#define FTE_QC_DIGEST_SHA384 /* The digest_hex builtin supports 384-bit sha2 hashes. */ +#define FTE_QC_DIGEST_SHA512 /* The digest_hex builtin supports 512-bit sha2 hashes. */ #define FTE_QC_FS_SEARCH_SIZEMTIME #define FTE_QC_HARDWARECURSORS /* setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits (or hardware cursors are unsupported), it will be emulated using regular draws - this at least still avoids conflicting cursors as only one will ever be used, even if console+menu+csqc are all overlayed. */ #define FTE_QC_HASHTABLES /* Provides efficient string-based lookups. */ @@ -222,6 +228,7 @@ Available options: #define FTE_QUAKE2_SERVER /* This engine is able to act as a quake2 server */ #define FTE_QUAKE3_CLIENT /* This engine is able to act as a quake3 client */ #define FTE_QUAKE3_SERVER /* This engine is able to act as a quake3 server */ +#define FTE_SOLID_BSPTRIGGER /* Allows for mappers to use shaped triggers instead of being limited to axially aligned triggers. */ #define FTE_SOLID_LADDER /* Allows a simple trigger to remove effects of gravity (solid 20). obsolete. will prolly be removed at some point as it is not networked properly. Use FTE_ENT_SKIN_CONTENTS */ #define FTE_SPLITSCREEN /* Client supports splitscreen, controlled via cl_splitscreen. Servers require allow_splitscreen 1 if splitscreen is to be used over the internet. Mods that use csqc will need to be aware for this to work properly. per-client networking may be problematic. */ #define FTE_SQL /* Provides sql* builtins which can be used for sql database access */ @@ -232,6 +239,8 @@ Available options: #define FTE_TE_STANDARDEFFECTBUILTINS /* Provides builtins to replace writebytes, with a QW compatible twist. */ #define FTE_TERRAIN_MAP /* This engine supports .hmp files, as well as terrain embedded within bsp files. */ #define FTE_RAW_MAP /* This engine supports directly loading .map files, as well as realtime editing of the various brushes. */ +#define FTE_INFOBLOBS /* Removes the length limits on user/server/local info strings, and allows embedded nulls and other otherwise-reserved characters. This can be used to network avatar images and the like, or other binary data. */ +#define FTE_VRINPUTS /* input_weapon, input_left_*, input_right_*, input_head_* work, both in csqc (as inputs with suitable plugin/hardware support) and ssqc (available in PlayerPreThink). */ #define KRIMZON_SV_PARSECLIENTCOMMAND /* SSQC's SV_ParseClientCommand function is able to handle client 'cmd' commands. The tokenizing parts also work in csqc. */ #define NEH_CMD_PLAY2 #define NEH_RESTOREGAME @@ -239,6 +248,7 @@ Available options: #define QW_ENGINE #define QWE_MVD_RECORD /* You can use the easyrecord command to record MVD demos serverside. */ #define TEI_MD3_MODEL +#define TEI_SHOWLMP2 #define TENEBRAE_GFX_DLIGHTS /* Allows ssqc to attach rtlights to entities with various special properties. */ #define ZQ_MOVETYPE_FLY /* MOVETYPE_FLY works on players. */ #define ZQ_MOVETYPE_NOCLIP /* MOVETYPE_NOCLIP works on players. */ @@ -300,20 +310,40 @@ float total_secrets; float total_monsters; float found_secrets; float killed_monsters; -float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16; +float parm1; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm2; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm3; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm4; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm5; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm6; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm7; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm8; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm9; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm10; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm11; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm12; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm13; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm14; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm15; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm16; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ #endif #ifdef CSQC float intermission; #endif #if defined(CSQC) || defined(SSQC) -vector v_forward, v_up, v_right; +vector v_forward; +vector v_up; +vector v_right; #endif #ifdef CSQC vector view_angles; /* +x=DOWN */ #endif #if defined(CSQC) || defined(SSQC) -float trace_allsolid, trace_startsolid, trace_fraction; -vector trace_endpos, trace_plane_normal; +float trace_allsolid; +float trace_startsolid; +float trace_fraction; +vector trace_endpos; +vector trace_plane_normal; float trace_plane_dist; entity trace_ent; float trace_inopen; @@ -334,7 +364,7 @@ void() PlayerPreThink; /* With Prediction(QW compat/FTE default): Called before No Prediction(NQ compat): Called AFTER the player's movement intents have already been processed (ie: velocity will have already changed according to input_*, but before the actual position change. */ void() PlayerPostThink; /* Called after the player's input commands are processed. */ void() ClientKill; /* Called in response to 'cmd kill' (or just 'kill'). */ -void(optional float csqcactive) ClientConnect; /* Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. */ +void() ClientConnect; /* Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. To determine if the client has csqc active (and kick anyone that doesn't), you can use if(infokeyf(self,INFOKEY_P_CSQCACTIVE)) {sprint(self, "CSQC is required for this server\n");dropclient(self);} */ void() PutClientInServer; /* Enginewise, this is only ever called immediately after ClientConnect and is thus a little redundant. Modwise, this is also called for respawning a player etc. */ void() ClientDisconnect; /* Called once a client disconnects or times out. Not guarenteed to be called on map changes. */ void() SetNewParms; /* Called without context when a new client initially connects (before ClientConnect is even called). This function is expected to only set the parm* globals so that they can be decoded properly later. You should not rely on 'self' being set. */ @@ -478,6 +508,10 @@ void end_sys_fields; #ifdef MENU float time; /* The current local time. Increases while paused. */ #endif +#if defined(CSQC) || defined(SSQC) +float input_sequence; /* This is the client-generated input sequence number. 0 for unsequenced movements. */ +float input_servertime; /* Server's timestamp of the client's interpolation state. */ +#endif #ifdef SSQC float input_timelength; vector input_angles; /* +x=DOWN */ @@ -485,12 +519,6 @@ vector input_movevalues; float input_buttons; float input_impulse; #endif -#ifdef CSQC -vector input_cursor_screen; -vector input_cursor_trace_start; -vector input_cursor_trace_endpos; -float input_cursor_trace_entnum; -#endif #if defined(CSQC) || defined(SSQC) int trace_endcontents; int trace_surfaceflags; @@ -501,28 +529,57 @@ int trace_bone_id; /* 1-based. 0 if not known. typically needs MOVE_HITMODEL. */ int trace_triangle_id; /* 1-based. 0 if not known. */ #endif #ifdef CSQC -int trace_networkentity; /* Repots which ssqc entnum was hit when a csqc traceline impacts an ssqc-based brush entity. */ +float trace_networkentity; /* Repots which ssqc entnum was hit when a csqc traceline impacts an ssqc-based brush entity. */ +vector pmove_org; /* Reports the origin of the engineside player (after prediction). Does not work when the player is a csqc-owned entity. */ +vector pmove_vel; /* Reports the velocity of the engineside player (after prediction). Does not work when the player is a csqc-owned entity. */ +float pmove_onground; /* Reports the onground state of the engineside player (after prediction). Does not work when the player is a csqc-owned entity. */ #endif #if defined(CSQC) || defined(SSQC) vector global_gravitydir = '0 0 -1'; /* The direction gravity should act in if not otherwise specified per entity. */ int serverid; /* The unique id of this server within the server cluster. */ #endif +#ifdef CSQC +.string message; /* Allows the csqc to read the map description from the server. */ +#endif +#ifdef SSQC +.float button3; +.float button4; +.float button5; +.float button6; +.float button7; +.float button8; +#endif #if defined(NQSSQC) +.float buttonuse; /* For DP compat only. */ +.float buttonchat; /* For DP compat only. */ +.float cursor_active; /* For DP compat only. */ +.float button9; /* For DP compat only. */ +.float button10; /* For DP compat only. */ +.float button11; /* For DP compat only. */ +.float button12; /* For DP compat only. */ +.float button13; /* For DP compat only. */ +.float button14; /* For DP compat only. */ +.float button15; /* For DP compat only. */ +.float button16; /* For DP compat only. */ +.vector cursor_screen; /* For DP compat only. */ +.vector cursor_start; /* For DP compat only. */ +.vector cursor_impact; /* For DP compat only. */ +.entity cursor_entitynumber; /* For DP compat only. */ .float lastruntime; /* This field used to be used to avoid running an entity multiple times in a single frame due to quakeworld's out-of-order thinks. It is no longer used by FTE due to precision issues, but may still be updated for compatibility reasons. */ #endif #if defined(CSQC) || defined(QWSSQC) .vector punchangle; #endif #if defined(CSQC) || defined(SSQC) -.float gravity; +.float gravity; /* Multiplier applied in addition to sv_gravity (not absolute units), to control the gravity affecting this entity specifically. */ .float hull; /* Overrides the hull used by the entity for walkmove/movetogoal and not traceline/tracebox. */ .entity movechain; /* This is a linked list of entities which will be moved whenever this entity moves, logically they are attached to this entity. */ .void() chainmoved; /* Called when the entity is moved as a result of being part of another entity's .movechain */ .void(float old, float new) contentstransition; /* This function is called when the entity moves between water and air. If specified, default splash sounds will be disabled allowing you to provide your own. */ -.float dimension_solid; /* This is the bitmask of dimensions which the entity is solid within. */ +.float dimension_solid; /* This is the bitmask of dimensions which the entity is solid within. This is not networked, instead csqc traces impacting ssqc entities assumes the ssqc entity to have a dimension_solid of 1. */ .float dimension_hit; /* This is the bitmask of dimensions which the entity will be blocked by. If other.dimension_solid & self.dimension_hit, our traces will impact and not proceed. If its false, the traces will NOT impact, allowing self to pass straight through. */ -.int hitcontentsmaski; /* Traces performed for this entity will impact against surfaces that match this contents mask. */ -.float dphitcontentsmask; /* Some crappy field that inefficiently requires translating to the native contents flags. Ditch the 'dp', do it properly. */ +.int hitcontentsmaski; /* Traces performed for this entity will impact against surfaces that match this contents mask (CONTENTBITS_* constants). */ +__deprecated("Does not support mod-specific contents.") .float dphitcontentsmask; /* Some crappy field that inefficiently requires translating to the native contents flags. Ditch the 'dp', do it properly. */ .float scale; /* Multiplier that resizes the entity. 1 is normal sized, 2 is double sized. scale 0 is remapped to 1. In SSQC, this is limited to 1/16th precision, with a maximum just shy of 16. */ .float fatness; /* How many QuakeUnits to push the entity's verticies along their normals by. */ .float alpha; /* The transparency of the entity. 1 means opaque, 0.0001 means virtually invisible. 0 is remapped to 1, for compatibility. */ @@ -535,13 +592,13 @@ int serverid; /* The unique id of this server within the server cluster. */ .float basebone; /* The base* frame animations are equivelent to their non-base versions, except that they only affect bone numbers below the 'basebone' value. This means that the base* animation can affect the legs of a skeletal model independantly of the normal animation fields affecting the torso area. For more complex animation than this, use skeletal objects. */ .float baseframe; /* See basebone */ .void() customphysics; /* Called once each physics frame, overriding the entity's .movetype field and associated logic. You'll probably want to use tracebox to move it through the world. Be sure to call .think as appropriate. */ -.entity tag_entity; -.float tag_index; +.entity tag_entity; /* Specifies which entity this entity's origin+angles is 'attached' to. */ +.float tag_index; /* Specifies the tag or bone on the parent entity that we're attached to. If this is -1 then the entity is instead a q3-like camera portal, with the tag_entity saying the entity to display for. If tag_entity is world then this is a q3-like portal surface marker with a separate camera (with a tag_entity referring to the portal surface). */ .float skeletonindex; /* This object serves as a container for the skeletal bone states used to override the animation data. */ -.vector colormod; /* Provides a colour tint for the entity. */ -.vector glowmod; +.vector colormod; /* Provides a colour tint for the entity (does not affect fullbrights). */ +.vector glowmod; /* Scaler for an entity's fullbright textures. */ .vector gravitydir; /* Specifies the direction in which gravity acts. Must be normalised. '0 0 0' also means down. Use '0 0 1' if you want the player to be able to run on ceilings. */ -.vector(vector org, vector ang) camera_transform; /* Provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc. */ +.vector(vector org, vector ang) camera_transform; /* A callback that provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc. */ #endif #ifdef SSQC .float pmove_flags; @@ -572,31 +629,33 @@ int serverid; /* The unique id of this server within the server cluster. */ .entity view2; /* defines a second viewpoint, typically displayed in a corner of the screen (also punches open pvs). */ .vector movement; /* These are the directions that the player is currently trying to move in (ie: which +forward/+moveright/+moveup etc buttons they have held), expressed relative to that player's angles. Order is forward, right, up. */ .float vw_index; /* This acts as a second modelindex, using the same frames etc. */ -.entity nodrawtoclient; /* This entity will not be sent to the player named by this field. They will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ -.entity drawonlytoclient; /* This entity will be sent *only* to the player named by this field. To other players they will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ -.entity viewmodelforclient; /* This entity will be sent only to the player named by this field, and this entity will be attached to the player's view as an additional weapon model. */ -.entity exteriormodeltoclient; /* This entity will be invisible to the player named by this field, except in mirrors or mirror-like surfaces, where it will be visible as normal. It may still cast shadows as normal, and generate lights+particles, depending on client settings. Does not affect how other players see the entity. */ -.float glow_size; -.float glow_color; -.float glow_trail; +__deprecated("Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity nodrawtoclient; /* This entity will not be sent to the player named by this field. They will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ +__deprecated("Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity drawonlytoclient; /* This entity will be sent *only* to the player named by this field. To other players they will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ +__deprecated("Redundant. Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity viewmodelforclient; /* This entity will be sent only to the player named by this field, and this entity will be attached to the player's view as an additional weapon model. */ +__deprecated("Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity exteriormodeltoclient; /* This entity will be invisible to the player named by this field, except in mirrors or mirror-like surfaces, where it will be visible as normal. It may still cast shadows as normal, and generate lights+particles, depending on client settings. Does not affect how other players see the entity. */ +.entity clientcamera; /* Controls which entity to use for this client's camera. */ +.float glow_size; /* Some outdated particle trail thing. */ +.float glow_color; /* Some outdated particle trail thing. */ +.float glow_trail; /* Some outdated particle trail thing. */ .float traileffectnum; /* This should be set to the result of particleeffectnum, in order to attach a custom trail effect to an entity as it moves. */ .float emiteffectnum; /* This should be set to the result of particleeffectnum, in order to continually spawn particles in the direction that this entity faces. */ -.float dimension_see; /* This is the dimension mask (bitfield) that the client is allowed to see. Entities and events not in this dimension mask will be invisible. */ -.float dimension_seen; /* This is the dimension mask (bitfield) that the client is visible within. Clients that cannot see this dimension mask will not see this entity. */ -.float dimension_ghost; /* If this entity is visible only within these dimensions, it will become transparent, as if a ghost. */ -.float dimension_ghost_alpha; /* If this entity is subject to dimension_ghost, this is the scaler for its alpha value. If 0, 0.5 will be used instead. */ + +/* We use these for flash grenades and are OK with MVD/splitscreen issues. */ +/*__deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_see; /* This is the dimension mask (bitfield) that the client is allowed to see. Entities and events not in this dimension mask will be invisible. */ +/* __deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_seen; /* This is the dimension mask (bitfield) that the client is visible within. Clients that cannot see this dimension mask will not see this entity. */ +/* __deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_ghost; /* If this entity is visible only within these dimensions, it will become transparent, as if a ghost. */ +/* __deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_ghost_alpha; /* If this entity is subject to dimension_ghost, this is the scaler for its alpha value. If 0, 0.5 will be used instead. */ .float(entity playerent, float changedflags) SendEntity; /* Called by the engine whenever an entity needs to be (re)sent to a client's csprogs, either because SendFlags was set or because data was lost. Must write its data to the MSG_ENTITY buffer. Will be called at the engine's leasure. */ .float SendFlags; /* Indicates that something in the entity has been changed, and that it needs to be updated to all players that can see it. The engine will clear it at some point, with the cleared bits appearing in the 'changedflags' argument of the SendEntity method. */ -.float Version; /* Obsolete, set a SendFlags bit instead. */ -.float clientcolors; +__deprecated("Use SendFlags instead.") .float Version; /* Obsolete */ +__deprecated("Doesn't support RGB player colours.") .float clientcolors; .float viewzoom; -.float items2; .float playerclass; .float hasted; .float light_level; /* Used by hexen2 to indicate the light level where the player is standing. */ .float pvsflags; /* Reconfigures when the entity is visible to clients */ .float uniquespawnid; /* Incremented by 1 whenever the entity is respawned. Persists across remove calls, for when the two-second grace period is insufficient. */ -.float() customizeentityforclient; /* Called just before an entity is sent to a client (non-csqc protocol). This gives you a chance to tailor 'self' according to what 'other' should see. */ +DEP_CSQC .float() customizeentityforclient; /* Called just before an entity is sent to a client (non-csqc protocol). This gives you a chance to tailor 'self' according to what 'other' should see. */ #endif #ifdef CSQC .float frame3; /* Some people just don't understand how to use framegroups... */ @@ -620,7 +679,7 @@ int serverid; /* The unique id of this server within the server cluster. */ .float basesubblendfrac; /* See basebone */ .float basesubblend2frac; /* See basebone */ #endif -void(float reqid, float responsecode, string resourcebody) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */ +void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */ #ifdef SSQC void() SpectatorConnect; /* Called when a spectator joins the game. */ void() SpectatorDisconnect; /* Called when a spectator disconnects from the game. */ @@ -632,8 +691,12 @@ void(float pauseduration) SV_PausedTic; /* For each frame that the server is pau float(float newstatus) SV_ShouldPause; /* Called to give the qc a change to block pause/unpause requests. Return false for the pause request to be ignored. newstatus is 1 if the user is trying to pause the game. For the duration of the call, self will be set to the player who tried to pause, or to world if it was triggered by a server-side event. */ void() SV_RunClientCommand; /* Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysics' after modifying the inputs. */ void() SV_AddDebugPolygons; /* Called each video frame. This is the only place where ssqc is allowed to call the R_BeginPolygon/R_PolygonVertex/R_EndPolygon builtins. This is exclusively for debugging, and will break in anything but single player as it will not be called if the engine is not running both a client and a server. */ -void() SV_PlayerPhysics; /* Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful. */ +DEP_CSQC void() SV_PlayerPhysics; /* Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful. */ +void(float fd, float entcount, float playerslots) SV_PerformSave; /* Called by the engine as part of saved games. The QC is responsible for writing any data that will be required to restore the game. Save files are not limited to just text, you can use fwrite (and later fread) for binary data. Remember to close the passed file. */ +void(float fd, float entcount, float playerslots) SV_PerformLoad; /* Called by the engine to restore a saved game that was saved via SV_PerformSave, the server will have already started the game to its inital state (for precaches+makestatic calls), so entities+globals will have their post-spawn values (you will likely want to remove most of them, you can use the two extra args as helpers for that). You can use respawn_edict to un-remove specific entities, with parseentitydata or putentityfieldstring(findentityfield(NAME), ent, value) to assign to fields by name strings. Don't expect bprints/etc to work - players are likely in a pending state. Remember to close the passed file. */ +void() RestoreGame; /* Called for each reconnecting player as part of loading a saved game. Part of NEH_RESTOREGAME. */ void() EndFrame; /* Called after non-player entities have been run at the end of the physics frame. Player physics is performed out of order and can/will still occur between EndFrame and BeginFrame. */ +void() SetTransferParms; /* Called as an alternative to SetChangeParms when a player is transferring to another server. Part of FTE_SV_CLUSTER. */ string(string addr, string uinfo, string features) SV_CheckRejectConnection; /* Called to give the mod a chance to ignore connection requests based upon client protocol support or other properties. Use infoget to read the uinfo and features arguments. */ #endif #ifdef CSQC @@ -671,7 +734,7 @@ void(string cmdtext) GameCommand; string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) Cef_GeneratePage; /* Provides an entrypoint to generate pages for the CEF plugin from within QC. Headers are -separated key/value pairs (use tokenizebyseparator). */ #ifdef SSQC -string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) HTTP_GeneratePage; /* Provides an entrypoint to generate pages for pages requested over http (sv_port_tcp+net_enable_http). Headers are +string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) HTTP_GeneratePage; /* Provides an entrypoint to generate pages for pages requested over http (sv_port_tcp+net_enable_http). Headers are -separated key/value pairs (use tokenizebyseparator). Return __NULL__ to let the engine handle it, an empty string for a 404, and any other text for a regular 200 response. */ #endif #if defined(CSQC) || defined(SSQC) @@ -683,20 +746,25 @@ void() m_init; void() m_shutdown; void(vector screensize) m_draw; /* Provides the menuqc with a chance to draw. Will be called even if the menu does not have focus, so be sure to avoid that. COMPAT: screensize is not provided in DP. */ void(vector screensize, float opaque) m_drawloading; /* Additional drawing function to draw loading screens. If opaque is set, then this function must ensure that the entire screen is overdrawn (even if just by a black drawfill). */ +void(string rendererdescription) Menu_RendererRestarted; /* Called by the engine after the video was restarted. This serves to notify the MenuQC that any render targets that it may have cached were purged, and will need to be regenerated. */ float(float evtype, float scanx, float chary, float devid) Menu_InputEvent; /* If present, this is called instead of m_keydown and m_keyup Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */ -void(float scan, float chr) m_keydown; -void(float scan, float chr) m_keyup; +__deprecated("Use Menu_InputEvent") void(float scan, float chr) m_keydown; +__deprecated("Use Menu_InputEvent") void(float scan, float chr) m_keyup; void(float wantmode) m_toggle; float(string cmd) m_consolecommand; +float(float idx) m_gethostcachecategory; #endif #ifdef SSQC -float parm17, parm18, parm19, parm20, parm21, parm22, parm23, parm24, parm25, parm26, parm27, parm28, parm29, parm30, parm31, parm32; +float parm17, parm18, parm19, parm20, parm21, parm22, parm23, parm24, parm25, parm26, parm27, parm28, parm29, parm30, parm31, parm32; /* Additional spawn parms, following the same parmN theme. */ float parm33, parm34, parm35, parm36, parm37, parm38, parm39, parm40, parm41, parm42, parm43, parm44, parm45, parm46, parm47, parm48; float parm49, parm50, parm51, parm52, parm53, parm54, parm55, parm56, parm57, parm58, parm59, parm60, parm61, parm62, parm63, parm64; +string parm_string; /* Like the regular parmN globals, but preserves string contents. */ +string startspot; /* Receives the value of the second argument to changelevel from the previous map. */ var float dimension_send; /* Used by multicast functionality. Multicasts (and related builtins that multicast internally) will only be sent to players where (player.dimension_see & dimension_send) is non-zero. */ //var float dimension_default = 255; /* Default dimension bitmask */ +__unused var string __fullspawndata; /* Set by the engine before calls to spawn functions, and is most easily parsed with the tokenize builtin. This allows you to handle halflife's multiple-fields-with-the-same-name (or target-specific fields). */ #endif #if defined(CSQC) || defined(SSQC) __used var float physics_mode = 2; /* 0: original csqc - physics are not run @@ -712,9 +780,90 @@ var vector drawfontscale = '1 1 0'; /* Specifies a scaler for all text rendering float drawfont; /* Allows you to choose exactly which font is to be used to draw text. Fonts can be registered/allocated with the loadfont builtin. */ const float FONT_DEFAULT = 0; #endif +#if defined(NQSSQC) +entity newmis; /* ssqc global */ +#endif +#if defined(CSQC) || defined(QWSSQC) +float deathmatch; /* ssqc global */ +float coop; /* ssqc global */ +#endif +#if defined(QWSSQC) +float teamplay; /* ssqc global */ +#endif +#if defined(CSQC) || defined(SSQC) +int trace_endcontentsi; /* ssqc global */ +int trace_surfaceflagsi; /* ssqc global */ +string trace_surfacename; /* ssqc global */ +float cycle_wrapped; /* ssqc global */ +#endif +#ifdef CSQC +float dimension_default; /* ssqc global */ +#endif +#if defined(CSQC) || defined(SSQC) +unsigned int input_weapon; /* ssqc global */ +float input_lightlevel; /* ssqc global */ +vector input_cursor_screen; /* ssqc global */ +vector input_cursor_trace_start; /* ssqc global */ +vector input_cursor_trace_endpos; /* ssqc global */ +float input_cursor_entitynumber; /* ssqc global */ +unsigned int input_head_status; /* ssqc global */ +vector input_head_origin; /* ssqc global */ +vector input_head_angles; /* ssqc global */ +vector input_head_velocity; /* ssqc global */ +vector input_head_avelocity; /* ssqc global */ +unsigned int input_head_weapon; /* ssqc global */ +unsigned int input_left_status; /* ssqc global */ +vector input_left_origin; /* ssqc global */ +vector input_left_angles; /* ssqc global */ +vector input_left_velocity; /* ssqc global */ +vector input_left_avelocity; /* ssqc global */ +unsigned int input_left_weapon; /* ssqc global */ +unsigned int input_right_status; /* ssqc global */ +vector input_right_origin; /* ssqc global */ +vector input_right_angles; /* ssqc global */ +vector input_right_velocity; /* ssqc global */ +vector input_right_avelocity; /* ssqc global */ +unsigned int input_right_weapon; /* ssqc global */ +#endif +#ifdef SSQC +float trace_endcontentsf; /* ssqc global */ +float trace_surfaceflagsf; /* ssqc global */ +#endif +#if defined(CSQC) || defined(SSQC) +string trace_dphittexturename; /* ssqc global */ +#endif +#ifdef SSQC +float trace_dpstartcontents; /* ssqc global */ +float trace_dphitcontents; /* ssqc global */ +float trace_dphitq3surfaceflags; /* ssqc global */ +#endif +#ifdef CSQC +float(vector angles, float isdelta) CSQC_Parse_SetAngles; +void(float playernum) CSQC_PlayerInfoChanged; +void() CSQC_ServerInfoChanged; +DEP("use CSQC_Event_Sound") float(float channel, string soundname, vector pos, float vol, float attenuation, float flags) CSQC_ServerSound; +void(int entidx, string newentdata) CSQC_MapEntityEdited; +float clframetime; +float servertime; +float serverprevtime; +float serverdeltatime; +DEP("Does not support mod-specific contents.") float trace_dpstartcontents; +DEP("Does not support mod-specific contents.") float trace_dphitcontents; +DEP("Does not support mod-specific surface flags") float trace_dphitq3surfaceflags; +DEP("Does not support all mod-specific surface flags.") float trace_surfaceflagsf; +DEP("Does not support all mod-specific contents.") float trace_endcontentsf; +float intermission_time; +vector pmove_mins; +vector pmove_maxs; +float pmove_jump_held; +float pmove_waterjumptime; +float input_clienttime; +float autocvar_vid_conwidth; +float autocvar_vid_conheight; +#endif const float TRUE = 1; const float FALSE = 0; /* File not found... */ -const float M_PI = 3.14159; +const float M_PI = 3.14159; /* Mathematica Pi constant. */ #if defined(CSQC) || defined(SSQC) const float MOVETYPE_NONE = 0; const float MOVETYPE_WALK = 3; @@ -735,9 +884,10 @@ const float SOLID_TRIGGER = 1; const float SOLID_BBOX = 2; const float SOLID_SLIDEBOX = 3; const float SOLID_BSP = 4; /* Does not collide against other SOLID_BSP entities. Normally paired with MOVETYPE_PUSH. */ -const float SOLID_CORPSE = 5; /* Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .solid value to SOLID_BBOX or so, perform the traceline, then revert the player's .solid value. */ -const float SOLID_LADDER = 20; /* Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead. */ +const float SOLID_CORPSE = 5; /* Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .hitcontentsmaski value to include CONTENTBIT_CORPSE, perform the traceline, then revert the player's .solid value. */ +__deprecated("Obsoleted by .skin=CONTENTS_LADDER") const float SOLID_LADDER = 20; /* Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead. */ const float SOLID_PORTAL = 21; /* CSG subtraction volume combined with entity transformations on impact. */ +const float SOLID_BSPTRIGGER = 22; /* For complex-shaped trigger volumes, instead of being a pure aabb. */ const float SOLID_PHYSICS_BOX = 32; const float SOLID_PHYSICS_SPHERE = 33; const float SOLID_PHYSICS_CAPSULE = 34; @@ -819,29 +969,28 @@ const int CONTENTBIT_SOLID = 0x00000001i; const int CONTENTBIT_LAVA = 0x00000008i; const int CONTENTBIT_SLIME = 0x00000010i; const int CONTENTBIT_WATER = 0x00000020i; -const int CONTENTBIT_FTELADDER = 0x00004000i; +const int CONTENTBIT_FTELADDER = 0x00004000i; /* Content bit used for .skin=CONTENT_LADDER entities. */ const int CONTENTBIT_PLAYERCLIP = 0x00010000i; const int CONTENTBIT_MONSTERCLIP = 0x00020000i; -const int CONTENTBIT_BODY = 0x02000000i; -const int CONTENTBIT_CORPSE = 0x04000000i; -const int CONTENTBIT_Q2LADDER = 0x20000000i; /* Content bit specific to q2bsp */ -const int CONTENTBIT_SKY = 0x80000000i; +const int CONTENTBIT_BODY = 0x02000000i; /* Content bit that indicates collisions against SOLID_BBOX/SOLID_SLIDEBOX entities. */ +const int CONTENTBIT_CORPSE = 0x04000000i; /* Content bit that indicates collisions against SOLID_CORPSE entities. */ +const int CONTENTBIT_Q2LADDER = 0x20000000i; /* Content bit specific to q2bsp (conflicts with q3bsp contents so use with caution). */ +const int CONTENTBIT_SKY = 0x80000000i; /* Content bit somewhat specific to q1bsp (aliases to NODROP in q3bsp), but you should probably check surfaceflags&SURF_SKY as well for q2+q3bsp too. */ const int CONTENTBITS_POINTSOLID = CONTENTBIT_SOLID|0x00000002i|CONTENTBIT_BODY; /* Bits that traceline would normally consider solid */ const int CONTENTBITS_BOXSOLID = CONTENTBIT_SOLID|0x00000002i|CONTENTBIT_BODY|CONTENTBIT_PLAYERCLIP; /* Bits that tracebox would normally consider solid */ const int CONTENTBITS_FLUID = CONTENTBIT_WATER|CONTENTBIT_SLIME|CONTENTBIT_LAVA|CONTENTBIT_SKY; -const int SPA_POSITION; /* These SPA_* constants are to specify which attribute is returned by the getsurfacepointattribute builtin */ -const int SPA_S_AXIS = 1; -const int SPA_T_AXIS = 2; -const int SPA_R_AXIS = 3; /* aka: SPA_NORMAL */ -const int SPA_TEXCOORDS0 = 4; -const int SPA_LIGHTMAP0_TEXCOORDS = 5; -const int SPA_LIGHTMAP0_COLOR = 6; +const float SPA_POSITION = 0; /* These SPA_* constants are to specify which attribute is returned by the getsurfacepointattribute builtin */ +const float SPA_S_AXIS = 1; +const float SPA_T_AXIS = 2; +const float SPA_R_AXIS = 3; /* aka: SPA_NORMAL */ +const float SPA_TEXCOORDS0 = 4; +const float SPA_LIGHTMAP0_TEXCOORDS = 5; +const float SPA_LIGHTMAP0_COLOR = 6; const float CHAN_AUTO = 0; /* The automatic channel, play as many sounds on this channel as you want, and they'll all play, however the other channels will replace each other. */ const float CHAN_WEAPON = 1; const float CHAN_VOICE = 2; const float CHAN_ITEM = 3; const float CHAN_BODY = 4; - #endif #if defined(QWSSQC) const float CHANF_RELIABLE = 8; /* Only valid if the flags argument is not specified. The sound will be sent reliably, which is important if it is intended to replace looping sounds on doors etc. */ @@ -854,13 +1003,10 @@ const float SOUNDFLAG_ABSVOLUME = 16; /* The sample's volume is not scaled by th #endif #if defined(CSQC) || defined(SSQC) const float SOUNDFLAG_FORCELOOP = 2; /* The sound will restart once it reaches the end of the sample. */ -#endif -#ifdef CSQC const float SOUNDFLAG_NOSPACIALISE = 4; /* The different audio channels are played at the same volume regardless of which way the player is facing, without needing to use 0 attenuation. */ -#endif -#if defined(CSQC) || defined(SSQC) const float SOUNDFLAG_NOREVERB = 32; /* Disables the use of underwater/reverb effects on this sound effect. */ const float SOUNDFLAG_FOLLOW = 64; /* The sound's origin will updated to follow the emitting entity. */ +const float SOUNDFLAG_NOREPLACE = 128; /* Sounds started with this flag will be ignored when there's already a sound playing on that same ent-channel. */ #endif #ifdef SSQC const float SOUNDFLAG_UNICAST = 256; /* The sound will be sent only by the player specified by msg_entity. Spectators and related splitscreen players will also hear the sound. */ @@ -874,9 +1020,42 @@ const float ATTN_STATIC = 3; /* Even more attenuation to avoid torches drowing o #endif #ifdef SSQC const float SVC_CGAMEPACKET = 83; /* Direct ssqc->csqc message. Must only be multicast. The data triggers a CSQC_Parse_Event call in the csqc for the csqc to read the contents. The server *may* insert length information for clients connected via proxies which are not able to cope with custom csqc payloads. This should only ever be used in conjunction with the MSG_MULTICAST destination. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float TE_SPIKE = 0; +const float TE_SUPERSPIKE = 1; +const float TE_GUNSHOT = 2; +const float TE_EXPLOSION = 3; +const float TE_TAREXPLOSION = 4; +const float TE_LIGHTNING1 = 5; +const float TE_LIGHTNING2 = 6; +const float TE_WIZSPIKE = 7; +const float TE_KNIGHTSPIKE = 8; +const float TE_LIGHTNING3 = 9; +const float TE_LAVASPLASH = 10; +const float TE_TELEPORT = 11; +#endif +#if defined(CSQC) || defined(QWSSQC) +const float TE_BLOOD = 12; +#endif +#if defined(NQSSQC) +const float TE_EXPLOSION2 = 12; +#endif +#if defined(CSQC) || defined(QWSSQC) +const float TE_LIGHTNINGBLOOD = 13; +#endif +#if defined(NQSSQC) +const float TE_BEAM = 13; const float MSG_BROADCAST = 0; /* The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family. */ const float MSG_ONE = 1; /* The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client. */ const float MSG_ALL = 2; /* The byte(s) will be reliably sent to all players. */ +#endif +#if defined(QWSSQC) +__deprecated("Use MSG_MULTICAST+multicast(MULTICAST_*)") const float MSG_BROADCAST; /* The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family. */ +__deprecated("Use MSG_MULTICAST+multicast(MULTICAST_ONE_R)") const float MSG_ONE = 1; /* The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client. */ +__deprecated("Use MSG_MULTICAST+multicast(MULTICAST_ALL)") const float MSG_ALL = 2; /* The byte(s) will be reliably sent to all players. */ +#endif +#ifdef SSQC const float MSG_INIT = 3; /* The byte(s) will be written into the signon buffer. Clients will see these messages when they connect later. This buffer is only flushed on map changes, so spamming it _WILL_ result in overflows. */ const float MSG_MULTICAST = 4; /* The byte(s) will be written into the multicast buffer for more selective sending. Messages sent this way will never be split across packets, and using this for csqc-only messages will not break protocol translation. */ const float MSG_ENTITY = 5; /* The byte(s) will be written into the entity buffer. This is a special value used only inside 'SendEntity' functions. */ @@ -901,8 +1080,8 @@ const float PRINT_CHAT = 3; const float PVSF_NORMALPVS = 0; /* Filter first by PVS, then filter this entity using tracelines if sv_cullentities is enabled. */ const float PVSF_NOTRACECHECK = 1; /* Filter strictly by PVS. */ const float PVSF_USEPHS = 2; /* Send if we're close enough to be able to hear this entity. */ -const float PVSF_IGNOREPVS = 3; /* Ignores pvs. This entity is visible whereever you are on the map. */ -const float PVSF_NOREMOVE = 128; /* Once visible to a client, this entity will remain visible. This can be useful for csqc and corpses. */ +const float PVSF_IGNOREPVS = 3; /* Ignores pvs. This entity is visible whereever you are on the map. Updates will be sent regardless of pvs or phs */ +const float PVSF_NOREMOVE = 128; /* Once visible to a client, this entity will remain visible. This can be useful for csqc and corpses. While this flag is set, no CSQC_Remove events will be sent for the entity, but this does NOT mean that it will still receive further updates while outside of the pvs. */ const string INFOKEY_P_IP = "ip"; /* The apparent ip address of the client. This may be a proxy's ip address. */ const string INFOKEY_P_REALIP = "realip"; /* If sv_getrealip is set, this gives the ip as determine using that algorithm. */ const string INFOKEY_P_CSQCACTIVE = "csqcactive"; /* Client has csqc enabled. CSQC ents etc will be sent to this player. */ @@ -974,7 +1153,7 @@ const float FL_ONGROUND = 512; const float FL_PARTIALGROUND = 1024; const float FL_WATERJUMP = 2048; #endif -#if defined(CSQC) || defined(NQSSQC) +#if defined(NQSSQC) const float FL_JUMPRELEASED = 4096; #endif #if defined(CSQC) || defined(SSQC) @@ -987,6 +1166,7 @@ const float FL_LAGGEDMOVE = 65536; /* Enables anti-lag on rockets etc. */ const float MOVE_NORMAL = 0; const float MOVE_NOMONSTERS = 1; /* The trace will ignore all non-solid_bsp entities. */ const float MOVE_MISSILE = 2; /* The trace will use a bbox size of +/- 15 against entities with FL_MONSTER set. */ +const float MOVE_WORLDONLY = 3; /* The trace will ignore everything but the worldmodel. This is useful for to prevent the q3bsp pvs+culling issues that come with spectator modes leaving the world . */ const float MOVE_HITMODEL = 4; /* Traces will impact the actual mesh of the model instead of merely their bounding box. Should generally only be used for tracelines. Note that this flag is unreliable as an object can animate through projectiles. The bounding box MUST be set to completely encompass the entity or those extra areas will be non-solid (leaving a hole for things to go through). */ const float MOVE_TRIGGERS = 16; /* This trace type will impact only triggers. It will ignore non-solid entities. */ const float MOVE_EVERYTHING = 32; /* This type of trace will hit solids and triggers alike. Even non-solid entities. */ @@ -998,6 +1178,12 @@ const float MOVE_LAGGED = 64; /* Will use antilag based upon the player's latenc const float MOVE_ENTCHAIN = 128; /* Returns a list of entities impacted via the trace_ent.chain field */ const float MOVE_OTHERONLY = 256; /* Traces that use this trace type will collide against *only* the entity specified via the 'other' global, and will ignore all owner/solid_not/dimension etc rules, they will still adhere to contents and bsp/bbox rules though. */ #endif +const float CVAR_TYPEFLAG_EXISTS = 1; /* Cvar name actually exists. */ +const float CVAR_TYPEFLAG_SAVED = 2; /* Cvar is flaged for archival (might need cfg_save to actually save). */ +const float CVAR_TYPEFLAG_PRIVATE = 4; /* QC is not allowed to read. */ +const float CVAR_TYPEFLAG_ENGINE = 8; /* Cvar was created by the engine itself (not user/mod created). */ +const float CVAR_TYPEFLAG_HASDESCRIPTION = 16; /* cvar_description will return something (hopefully) useful. */ +const float CVAR_TYPEFLAG_READONLY = 32; /* cvar may not be changed by qc. */ const float RESTYPE_MODEL = 0; /* RESTYPE_* constants are used as arguments with the resourcestatus builtin. */ const float RESTYPE_SOUND = 1; /* precache_sound */ const float RESTYPE_PARTICLE = 2; /* particleeffectnum */ @@ -1026,7 +1212,7 @@ const float EF_FLAG1 = 16; const float EF_FLAG2 = 32; #endif #if defined(CSQC) || defined(NQSSQC) -const float EF_NODRAW = 16; +const float EF_NODRAW = 16; /* Disables drawing of the model. Does NOT work on QW players. */ #endif #if defined(CSQC) || defined(SSQC) const float EF_ADDITIVE = 32; /* The entity will be drawn with an additive blend. This is NOT supported on players in any quakeworld engine. */ @@ -1051,15 +1237,15 @@ const float MF_TRACER2 = 64; /* AKA: hellknight projectile trail */ const float MF_TRACER3 = 128; /* AKA: purple vore trail */ #endif #ifdef SSQC -const float SL_ORG_TL = 20; /* Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen */ -const float SL_ORG_TR = 21; -const float SL_ORG_BL = 22; -const float SL_ORG_BR = 23; -const float SL_ORG_MM = 24; -const float SL_ORG_TM = 25; -const float SL_ORG_BM = 26; -const float SL_ORG_ML = 27; -const float SL_ORG_MR = 28; +DEP_CSQC const float SL_ORG_TL = 20; /* Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen */ +DEP_CSQC const float SL_ORG_TR = 21; +DEP_CSQC const float SL_ORG_BL = 22; +DEP_CSQC const float SL_ORG_BR = 23; +DEP_CSQC const float SL_ORG_MM = 24; +DEP_CSQC const float SL_ORG_TM = 25; +DEP_CSQC const float SL_ORG_BM = 26; +DEP_CSQC const float SL_ORG_ML = 27; +DEP_CSQC const float SL_ORG_MR = 28; #endif #if defined(CSQC) || defined(SSQC) const float PFLAGS_NOSHADOW = 1; /* Associated RT lights attached will not cast shadows, making them significantly faster to draw. */ @@ -1068,7 +1254,6 @@ const float PFLAGS_CORONA = 2; /* Enables support of coronas on the associated r #ifdef SSQC const float PFLAGS_FULLDYNAMIC = 128; /* When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used. */ #endif -#if defined(CSQC) || defined(SSQC) const float EV_STRING = 1; const float EV_FLOAT = 2; const float EV_VECTOR = 3; @@ -1077,8 +1262,10 @@ const float EV_FIELD = 5; const float EV_FUNCTION = 6; const float EV_POINTER = 7; const float EV_INTEGER = 8; -const float EV_VARIANT = 9; -#endif +const float EV_UINT = 9; +const float EV_INT64 = 10; +const float EV_UINT64 = 11; +const float EV_DOUBLE = 12; hashtable gamestate; /* Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted). */ const float HASH_REPLACE = 256; /* Used with hash_add. Attempts to remove the old value instead of adding two values for a single key. */ const float HASH_ADD = 512; /* Used with hash_add. The new entry will be inserted in addition to the existing entry. */ @@ -1106,6 +1293,10 @@ const float STAT_VIEWZOOM = 21; /* Scales fov and sensitiity. Part of DP_VIEWZOO const float STAT_USER = 32; /* Custom user stats start here (lower values are reserved for engine use). */ #endif #if defined(CSQC) || defined(MENU) +const float PRECACHE_PIC_FROMWAD = 1; /* Attempt to load it from the legacy gfx.wad file (usually its better to just use a gfx/ prefix instead). */ +const float PRECACHE_PIC_NOCLAMP = 4; /* Texture coords for the pic will not be clamped nor padded nor atlased. */ +const float PRECACHE_PIC_DOWNLOAD = 256; /* If no image could be loaded then attempt to download one from the server. This flag can cause the function to block until completion. (Slow!) */ +const float PRECACHE_PIC_TEST = 512; /* The precache will block until the image is fully loaded, returning a null string on failure. (Slow!) */ const float VF_MIN = 1; /* The top-left of the 3d viewport in screenspace. The VF_ values are used via the setviewprop/getviewprop builtins. */ const float VF_MIN_X = 2; const float VF_MIN_Y = 3; @@ -1114,8 +1305,8 @@ const float VF_SIZE_X = 5; const float VF_SIZE_Y = 6; const float VF_VIEWPORT = 7; /* vector+vector. Two argument shortcut for VF_MIN and VF_SIZE */ const float VF_FOV = 8; /* sets both fovx and fovy. consider using afov instead. */ -const float VF_FOVX = 9; /* horizontal field of view. does not consider aspect at all. */ -const float VF_FOVY = 10; /* vertical field of view. does not consider aspect at all. */ +const float VF_FOV_X = 9; /* horizontal field of view. does not consider aspect at all. */ +const float VF_FOV_Y = 10; /* vertical field of view. does not consider aspect at all. */ const float VF_ORIGIN = 11; /* The origin of the view. Not of the player. */ const float VF_ORIGIN_X = 12; const float VF_ORIGIN_Y = 13; @@ -1157,16 +1348,45 @@ const float VF_VIEWENTITY = 206; /* Changes the RF_EXTERNALMODEL flag on entitie #endif #if defined(CSQC) || defined(MENU) const float VF_RT_DESTCOLOUR = 212; /* The texture name to write colour info into, this includes both 3d and 2d drawing. -Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. +Additional arguments are: format (IMGFMT_*), sizexy. Written to by both 3d and 2d rendering. Note that any rendertarget textures may be destroyed on video mode changes or so. Shaders can name render targets by prefixing texture names with '$rt:', or $sourcecolour. */ +const float VF_RT_DESTCOLOUR1 = 213; /* Like VF_RT_DESTCOLOUR, for multiple render targets. */ +const float VF_RT_DESTCOLOUR2 = 214; /* Like VF_RT_DESTCOLOUR, for multiple render targets. */ +const float VF_RT_DESTCOLOUR3 = 215; /* Like VF_RT_DESTCOLOUR, for multiple render targets. */ const float VF_RT_SOURCECOLOUR = 209; /* The texture name to use with shaders that specify a $sourcecolour map. */ -const float VF_RT_DEPTH = 210; /* The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16bit=4,24bit=5,32bit=6), sizexy. */ +const float VF_RT_DEPTH = 210; /* The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (IMGFMT_D*), sizexy. */ const float VF_RT_RIPPLE = 211; /* The texture name to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy. */ const float VF_ENVMAP = 220; /* The cubemap name to use as a fallback for $reflectcube, if a shader was unable to load one. Note that this doesn't automatically change shader permutations or anything. */ const float VF_USERDATA = 221; /* Pointer (and byte size) to an array of vec4s. This data is then globally visible to all glsl via the w_user uniform. */ #endif #ifdef CSQC +const float VF_SKYROOM_CAMERA = 222; /* Controls the camera position of the skyroom (which will be drawn underneath transparent sky surfaces). This should move slightly with the real camera, but not so much that the skycamera enters walls. Requires a skyshader with a blend mode on the first pass (or no passes). */ +#endif +#if defined(CSQC) || defined(MENU) +const float VF_PROJECTIONOFFSET = 224; /* vec2 horizontal+vertical offset for the projection matrix, for weird off-centre rendering. */ +const float DRAWFLAG_NORMAL = 0; /* Args for drawpic/drawfill/beginpolygon. Not to be confused with the hexen2-compatibility feature. */ +const float DRAWFLAG_ADD = 1; /* Forces additive blending, overriding any shader settings. */ +const float DRAWFLAG_MODULATE = 2; /* Forces alpha blending, overriding any shader settings. */ +const float DRAWFLAG_2D = 4; /* For use with beginpolygon. The polygon will be drawn to the 2d screen, instead of being added to the 3d scene. */ +const float DRAWFLAG_TWOSIDED = 1024; /* For use with beginpolygon. The polygon will be two-sided without any backface culling. */ +const float DRAWFLAG_LINES = 2048; /* For use with beginpolygon. The surface verticies should be interpreted as a line loop, instead of a triangle fan. */ +const float IMGFMT_R8G8B8A8 = 1; /* Typical 32bit rgba pixel format. */ +const float IMGFMT_R16G16B16A16F = 2; /* Half-Float pixel format. Requires gl3 support. */ +const float IMGFMT_R32G32B32A32F = 3; /* Regular Float pixel format. Requires gl3 support. */ +const float IMGFMT_D16 = 4; /* 16-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*. */ +const float IMGFMT_D24 = 5; /* 24-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*. */ +const float IMGFMT_D32 = 6; /* 32-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*. */ +const float IMGFMT_R8 = 7; /* Single channel red-only 8bit pixel format. */ +const float IMGFMT_R16F = 8; /* Single channel red-only Half-Float pixel format. Requires gl3 support. */ +const float IMGFMT_R32F = 9; /* Single channel red-only Float pixel format. Requires gl3 support. */ +const float IMGFMT_A2B10G10R10 = 10; /* Packed 32-bit packed 10-bit colour pixel format. Requires gl3 support. */ +const float IMGFMT_R5G6B5 = 11; /* Packed 16-bit colour pixel format. */ +const float IMGFMT_R4G4B4A4 = 12; /* Packed 16-bit colour pixel format, with alpha */ +const float IMGFMT_R8G8 = 13; /* 16-bit two-channel pixel format. */ +const float IMGFMT_R32G32B32F = 14; /* A pixel format that matches QC's vector type. */ +#endif +#ifdef CSQC const float RF_VIEWMODEL = 1; /* Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob. */ const float RF_EXTERNALMODEL = 2; /* Specifies that this entity should be displayed in mirrors (and may still cast shadows), but will not otherwise be visible. */ #endif @@ -1178,14 +1398,23 @@ const float RF_ADDITIVE = 8; /* Shaders from this entity will temporarily be hac const float RF_USEAXIS = 16; /* The entity will be oriented according to the current v_forward+v_right+v_up vector values instead of the entity's .angles field. */ const float RF_NOSHADOW = 32; /* This entity will not cast shadows. Often useful on view models. */ const float RF_FRAMETIMESARESTARTTIMES = 64; /* Specifies that the frame1time, frame2time field are timestamps (denoting the start of the animation) rather than time into the animation. */ +const float RF_FIRSTPERSON = 1024; /* This is basically the opposite of RF_EXTERNALMODEL. Don't draw in third-person or mirrors. */ +#endif +#if defined(CSQC) || defined(MENU) const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ const float IE_KEYUP = 1; /* Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired. */ -const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use in_windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ const float IE_MOUSEABS = 3; /* Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event. */ const float IE_ACCELEROMETER = 4; const float IE_FOCUS = 5; /* Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged. */ const float IE_JOYAXIS = 6; /* Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller. */ const float IE_GYROSCOPE = 7; +const float GGDI_GAMEDIR = 0; /* Used with getgamedirinfo to query the mod's public gamedir. There is often other info that cannot be expressed with just a gamedir name, resulting in dupes or other weirdness. */ +const float GGDI_DESCRIPTION = 1; /* The human-readable title of the mod. Empty when no data is known (ie: the gamedir just contains some maps). */ +const float GGDI_OVERRIDES = 2; /* A list of settings overrides. */ +const float GGDI_LOADCOMMAND = 3; /* The console command needed to actually load the mod. */ +const float GGDI_ICON = 4; /* The mod's Icon path, ready for drawpic. */ +const float GGDI_GAMEDIRLIST = 5; /* A semi-colon delimited list of gamedirs that the mod's content can be loaded through. */ #endif #ifdef SSQC const float CLIENTTYPE_DISCONNECTED = 0; /* Return value from clienttype() builtin. This entity is a player slot that is currently empty. */ @@ -1196,11 +1425,9 @@ const float CLIENTTYPE_NOTACLIENT = 3; /* This entity is not even a player slot. const float FILE_READ = 0; /* The file may be read via fgets to read a single line at a time. */ const float FILE_APPEND = 1; /* Like FILE_WRITE, but writing starts at the end of the file. */ const float FILE_WRITE = 2; /* fputs will be used to write to the file. */ -#if defined(CSQC) || defined(SSQC) const float FILE_READNL = 4; /* Like FILE_READ, except newlines are not special. fgets reads the entire file into a tempstring. */ const float FILE_MMAP_READ = 5; /* The file will be loaded into memory. fgets returns a pointer to the first byte (and will always return the same value for this file). Cast this to your datatype. */ const float FILE_MMAP_RW = 6; /* Like FILE_MMAP_READ, except any changes to the data will be written back to disk once the file is closed. */ -#endif #ifdef CSQC const float MASK_ENGINE = 1; /* Valid as an argument for addentities. If specified, all non-csqc entities will be added to the scene. */ const float MASK_VIEWMODEL = 2; /* Valid as an argument for addentities. If specified, the regular engine viewmodel will be added to the scene. */ @@ -1224,6 +1451,8 @@ const float LFIELD_DIETIME = 14; const float LFIELD_RGBDECAY = 15; const float LFIELD_RADIUSDECAY = 16; const float LFIELD_STYLESTRING = 17; +const float LFIELD_NEARCLIP = 18; +const float LFIELD_OWNER = 19; const float LFLAG_NORMALMODE = 1; const float LFLAG_REALTIMEMODE = 2; const float LFLAG_LIGHTMAP = 4; @@ -1284,12 +1513,20 @@ const float SLIST_TEST_NOTSTARTSWITH = 9; float(string ext) checkextension = #1; /* Checks if the named extension is supported by the running engine. */ -void(string err,...) error = #2; -void(string err,...) objerror = #3; -void(string text,...) print = #4; /* Part of DP_SV_PRINT*/ -void(string text,...) bprint = #5; -void(float clientnum, string text,...) msprint = #6; -void(string text,...) cprint = #7; +void(string err,...) error = #2; /* + Fatal error that will trigger a crash-to-console that users will actually notice. */ + +void(string err,...) objerror = #3; /* + For some reason this has been redefined as non-fatal, and as it won't force the user to look at the console it'll generally be ignored completely so really what's the point? Other than as a convoluted way to remove(self) that is. */ + +void(string text,...) print = #4; /* Part of DP_SV_PRINT + Hello, world. Shoves junk on the console. Hopefully people will bother to read it, maybe. */ + +DEP void(string text,...) bprint = #5; +DEP void(float clientnum, string text,...) msprint = #6; +void(string text,...) cprint = #7; /* + Tries to show the given message in the centre of the screen, assuming that its not obscured by menus. Oh hey look, you're calling it in menuqc! */ + vector(vector) normalize = #8; float(vector) vlen = #9; float(vector) vectoyaw = #10; @@ -1298,7 +1535,7 @@ float() random = #12; void(string,...) localcmd = #13; float(string name) cvar = #14; void(string name, string value) cvar_set = #15; -void(string text) dprint = #16; +void(string text, ...) dprint = #16; string(float) ftos = #17; float(float) fabs = #18; string(vector) vtos = #19; @@ -1310,11 +1547,19 @@ entity(entity start, .string field, string match) find = #24; entity(entity start, .__variant field, __variant match) findfloat = #25; /* Part of DP_QC_FINDFLOAT*/ entity(.string field, string match) findchain = #26; /* Part of DP_QC_FINDCHAIN*/ entity(.__variant field, __variant match) findchainfloat = #27; /* Part of DP_QC_FINDCHAINFLOAT*/ -string(string file) precache_file = #28; +string(string file) precache_file = #28; /* + Attempts to download the named file from the current server, if it isn't found locally. Not very useful as menuqc is normally meant to work before joining servers too. */ + string(string sample) precache_sound = #29; -void() coredump = #30; -void() traceon = #31; -void() traceoff = #32; +void() coredump = #30; /* + Takes a dump, writing the qcvm's state to disk. There are normally easier ways to debug, but I suppose this one still beats print spam. */ + +void() traceon = #31; /* + Enables single-stepping. Its generally easier to just set a breakpoint. */ + +void() traceoff = #32; /* + Disables single-stepping. Which sucks if you started said singlestepping outside of qc. */ + void(entity) eprint = #33; float(float) rint = #34; float(float) floor = #35; @@ -1324,12 +1569,16 @@ float(float) sin = #38; /* Part of DP_QC_SINCOSSQRTPOW*/ float(float) cos = #39; /* Part of DP_QC_SINCOSSQRTPOW*/ float(float) sqrt = #40; /* Part of DP_QC_SINCOSSQRTPOW*/ vector() randomvector = #41; -float(string name, string value, float flags) registercvar = #42; /* Part of DP_REGISTERCVAR*/ +float(string name, string value, float flags) registercvar = #42; /* Part of DP_REGISTERCVAR + Creates the cvar if it didn't already exist. This presents issues for setting those cvars via startup configs of course, and autocvars are easier but I suppose they don't get any flags (which are ignored anyway, of course). */ + float(float,...) min = #43; /* Part of DP_QC_MINMAXBOUND*/ float(float,...) max = #44; /* Part of DP_QC_MINMAXBOUND*/ float(float min,float value,float max) bound = #45; /* Part of DP_QC_MINMAXBOUND*/ float(float,float) pow = #46; /* Part of DP_QC_SINCOSSQRTPOW*/ -void(entity src, entity dst) copyentity = #47; /* Part of DP_QC_COPYENTITY*/ +void(entity src, entity dst) copyentity = #47; /* Part of DP_QC_COPYENTITY + Copies all entity fields from one entity into another (forgetting any that were previously set on the destination). */ + filestream(string filename, float mode) fopen = #48; /* Part of FRIK_FILE*/ void(filestream fhandle) fclose = #49; /* Part of FRIK_FILE*/ string(filestream fhandle) fgets = #50; /* Part of FRIK_FILE*/ @@ -1338,36 +1587,77 @@ float(string) strlen = #52; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string, optional string, optional string, optional string, optional string, optional string, optional string, optional string) strcat = #53; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, float start, float length) substring = #54; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ vector(string) stov = #55; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -string(string) strzone = #56; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -void(string) strunzone = #57; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -float(string) tokenize = #58; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ -string(float) argv = #59; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ -float() isserver = #60; -float() clientcount = #61; -float() clientstate = #62; -void(string map) changelevel = #64; -void(string sample, optional float channel, optional float volume) localsound = #65; -vector() getmousepos = #66; +FTEDEP("Redundant") string(string) strzone = #56; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS + Exists in FTE for compat only, no different from strcat. */ + +FTEDEP("Redundant") void(string) strunzone = #57; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS + Exists in FTE for compat only, does nothing. */ + +float(string) tokenize = #58; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND + Splits up the given string into its different components (what constitutes a token separator is not well defined and has been hacked about with over the years so have fun with that), returning the number of tokens that were found. Call argv(0 through ret-1) to retrieve each individual token. Take care to not use this recursively. */ + +string(float) argv = #59; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND + Returns one of the tokens found via tokenize (and equivelent builtins). */ + +float() isserver = #60; /* + Returns true if the local engine is running a server, and thus cvars and localcmds are shared with said server. */ + +float() clientcount = #61; /* + Returns the maximum number of players on the server. Useless if its a remote server, so its a kinda useless builtin really. */ + +float() clientstate = #62; /* + Tells you whether the client is actually connected to anything. 0 for a dedicated server (but dedicated servers don't normally run menuqc anyway), 2 if connecting or connected to a server (but not necessarily spawned+active), 1 for sitting around idle without trying to connect to anything yet. */ + +void(string map) changelevel = #64; /* + Not really any different from a localcmd, but with proper string escapes. */ + +void(string sample, optional float channel, optional float volume) localsound = #65; /* + Plays a sound, locally. precaching is optional, but recommended. */ + +vector() getmousepos = #66; /* + Obsolete. Return values depend upon the current cursor mode. Implement Menu_InputEvent instead, so you can handle deltas as-is or absolutes if that's all the OS can provide. */ + float(optional float timetype) gettime = #67; -void(string data) loadfromdata = #68; -void(string data) loadfromfile = #69; +void(string s) loadfromdata = #68; /* + Reads a set of entities from the given string. This string should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + +void(string s) loadfromfile = #69; /* + Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + float(float val, float m) mod = #70; -string(string name) cvar_string = #71; /* Part of DP_QC_CVAR_STRING*/ -void() crash = #72; -void() stackdump = #73; -searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #74; /* Part of DP_QC_FS_SEARCH*/ -void(searchhandle handle) search_end = #75; /* Part of DP_QC_FS_SEARCH*/ -float(searchhandle handle) search_getsize = #76; /* Part of DP_QC_FS_SEARCH*/ -string(searchhandle handle, float num) search_getfilename = #77; /* Part of DP_QC_FS_SEARCH*/ +string(string name) cvar_string = #71; /* Part of DP_QC_CVAR_STRING + Returns the value of a cvar, as a string. */ + +FTEDEP("Call 'error' instead") void() crash = #72; /* + Demonstrates that no program is bug free. */ + +void() stackdump = #73; /* + Prints out the QC's stack, for console-based error reports. */ + +searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3,SB_MULTISEARCH=1<<4,SB_NAMESORT=1<<5} flags, float quiet, optional string package) search_begin = #74; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +void(searchhandle handle) search_end = #75; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +float(searchhandle handle) search_getsize = #76; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +string(searchhandle handle, float num) search_getfilename = #77; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ float(entity) etof = #79; entity(float) ftoe = #80; -float(string) validstring = #81; -float(string str) altstr_count = #82; -string(string str) altstr_prepare = #83; -string(string str, float num) altstr_get = #84; -string(string str, float num, string set) altstr_set = #85; +float(string) validstring = #81; /* + Returns true if str isn't null. In case 'if [not](str)' was configured to test for empty instead of null. */ + +DEP float(string str) altstr_count = #82; /* + Reports how many single-quotes there were in the string, divided by 2. */ + +DEP string(string str) altstr_prepare = #83; /* + Adds markup to escape only single-quotes. Does not add any. */ + +DEP string(string str, float num) altstr_get = #84; /* + Gets the Nth single-quoted token in the input. */ + +DEP string(string str, float num, string setval) altstr_set = #85; /* + Changes the Nth single-quoted token. The setval argument must not contain any single-quotes (use altstr_prepare to ensure this). */ + entity(entity start, .float field, float match) findflags = #87; /* Part of DP_QC_FINDFLAGS*/ entity(.float field, float match) findchainflags = #88; /* Part of DP_QC_FINDCHAINFLAGS*/ +string(string name) cvar_defstring = #89; /* Part of DP_QC_CVAR_DEFSTRING*/ void(entity ent, string mname) setmodel = #90; /* Menuqc-specific version. */ @@ -1391,13 +1681,9 @@ void(entity e, string m) setmodel = #3; /* void(entity e, vector min, vector max) setsize = #4; /* Sets the e's mins and maxs fields. Also relinks collision state, which sets absmin and absmax too. */ -#endif -#ifdef SSQC void() breakpoint = #6; /* Trigger a debugging event. FTE will break into the qc debugger. Other engines may crash with a debug execption. */ -#endif -#if defined(CSQC) || defined(SSQC) float() random = #7; /* Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays. */ @@ -1428,8 +1714,13 @@ entity() spawn = #14; /* Adds a brand new entity into the world! Hurrah, you're now a parent! */ void(entity e) remove = #15; /* - Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After two seconds, the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid. */ + Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After half a second the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid. */ + +#endif +void(entity e) removeinstant = #0:removeinstant; /* + Same thing as the regular remove builtin, but bypasses the half-second rule. The entity slot may be reused instantly. Be CERTAIN that you have no lingering references, because if they're followed they will end up poking an entirely different type of entity! So only use this where you're sure its safe. */ +#if defined(CSQC) || defined(SSQC) void(vector v1, vector v2, float flags, entity ent) traceline = #16; /* Traces a thin line through the world from v1 towards v2. Will not collide with ent, ent.owner, or any entity who's owner field refers to ent. @@ -1453,6 +1744,12 @@ entity(entity start, .string fld, string match) find = #18; /* Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more. If you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep). */ +#endif +entity*(.__variant fld, __variant match, int type=EV_STRING, __out int count) find_list = #0:find_list; /* + Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more. + If you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep). */ + +#if defined(CSQC) || defined(SSQC) string(string s) precache_sound = #19; /* Precaches a sound, making it known to clients and loading it from disk. This builtin (strongly) should be called during spawn functions. This builtin must be called for the sound before the sound builtin is called, or it might not even be heard. */ @@ -1462,22 +1759,25 @@ string(string s) precache_model = #20; /* #endif #ifdef SSQC -void(entity client, string s) stuffcmd = #21; /* +void(entity client, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) stuffcmd = #21; /* Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \n. This builtin is generally considered evil. */ -void(entity client, float flags, string s) stuffcmdflags = #0:stuffcmdflags; /* Part of FTE_QC_STUFFCMDFLAGS +void(entity client, float flags, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) stuffcmdflags = #0:stuffcmdflags; /* Part of FTE_QC_STUFFCMDFLAGS Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \n. This (just as evil) variant allows specifying some flags too. See the STUFFCMD_* constants. */ #endif #if defined(CSQC) || defined(SSQC) entity(vector org, float rad, optional .entity chainfield) findradius = #22; /* - Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. */ + Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. Use findradius_list for an updated alternative without reenterancy issues. */ + +entity*(vector org, float rad, __out int foundcount, int sort=0) findradius_list = #0:findradius_list; /* + Finds all entities linked with a bbox within a distance of the 'org' specified, returning the list as a temp-array (world signifies the end). Unlike findradius, sv_gameplayfix_blowupfallenzombies is ignored (use FL_FINDABLE_NONSOLID instead), while sv_gameplayfix_findradiusdistancetobox and dpcompat_findradiusarealinks are force-enabled. The resulting buffer will automatically be cleaned up by the engine and does not need to be freed. */ #endif #if defined(NQSSQC) -void(string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) bprint = #23; /* +void(string s, optional string/__ s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) bprint = #23; /* NQ: Concatenates all arguments, and prints the messsage on the console of all connected clients. */ #endif @@ -1551,7 +1851,10 @@ float(entity ent) checkbottom = #40; /* Expensive checks to ensure that the entity is actually sitting on something solid, returns true if it is. */ float(vector pos) pointcontents = #41; /* - Checks the given point to see what is there. Returns one of the SOLID_* constants. Just because a spot is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ + Checks the given point to see what is there. Returns one of the CONTENTS_* constants. Just because a point is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ + +__uint(vector pos, optional float worldonly=1) pointcontentsmask = #0:pointcontentsmask; /* + Checks the given point to see what is there. Returns a mask of the CONTENTBIT_* constants. Just because a point is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ float(float) fabs = #43; /* Removes the sign of the float, making it positive if it is negative. */ @@ -1559,7 +1862,7 @@ float(float) fabs = #43; /* #endif #ifdef SSQC vector(entity player, float missilespeed) aim = #44; /* - Returns a direction vector (specifically v_forward on error). This builtin attempts to guess what pitch angle to fire projectiles at for people that don't know about mouselook. Does not affect yaw angles. */ + Returns a tweaked copy of the v_forward vector (must be set! ie: makevectors(player.v_angle) ). This is important for keyboard users (that don't want to have to look up/down the whole time), as well as joystick users (who's aim is otherwise annoyingly imprecise). Only the upwards component of the result will differ from the value of v_forward. The builtin will select the enemy closest to the crosshair within the angle of acos(sv_aim). */ #endif #if defined(CSQC) || defined(SSQC) @@ -1587,13 +1890,27 @@ vector(vector fwd, optional vector up) vectoangles = #51; /* void(float to, float val) WriteByte = #52; /* Writes a single byte into a network message buffer. Typically you will find a more correct alternative to writing arbitary data. 'to' should be one of the MSG_* constants. MSG_ONE must have msg_entity set first. */ -void(float to, float val) WriteChar = #53; -void(float to, float val) WriteShort = #54; -void(float to, float val) WriteLong = #55; -void(float to, float val) WriteCoord = #56; -void(float to, float val) WriteAngle = #57; -void(float to, string val) WriteString = #58; -void(float to, entity val) WriteEntity = #59; +void(float to, float val) WriteChar = #53; /* + Writes a signed value between -128 and 127. */ + +void(float to, float val) WriteShort = #54; /* + Writes a signed value between -32768 and 32767. As an exception, values up to 65535 will not trigger warnings (but readshort will read the result as negative!) */ + +void(float to, float val) WriteLong = #55; /* + Writes a signed 32bit integer. Note that the input argument being of float type limits the resulting integer to a mere 24 consecutive bits of validity. Use WriteInt if you want to write an entire 32bit int without data loss. */ + +void(float to, float val) WriteCoord = #56; /* + Writes a single value suitable for a map coordinate axis. The precision is not strictly specified but is assumed to be of at least 13.3 fixed-point precision (ie: +/-4k with 1/8th precision). */ + +void(float to, float val) WriteAngle = #57; /* + Writes a single value suitable for an angle axis. The precision is not strictly specified but is assumed to be 8bit, giving 256 notches instead of the assumed 360 range passed in. */ + +void(float to, string val) WriteString = #58; /* + Writes a variable-length null terminated string. There are length limits. The codepage is not translated, so be sure that client+server agree on whether utf-8 is being used or not (or just stick to ascii+markup). */ + +void(float to, entity val) WriteEntity = #59; /* + Writes the index of the specified entity (the network data size is not specified). This can be read clientside using the readentitynum builtin, with caveats. */ + #endif #if defined(CSQC) || defined(SSQC) float(float angle) sin = #60; /* Part of DP_QC_SINCOSSQRTPOW @@ -1626,7 +1943,7 @@ void(string mapname, optional string newmapstartspot) changelevel = #70; /* #endif #if defined(CSQC) || defined(SSQC) void(string cvarname, string valuetoset) cvar_set = #72; /* - Instantly sets a cvar to the given string value. */ + Instantly sets a cvar to the given string value. Warning: the resulting string includes apostrophies surrounding the result. You may wish to use sprintf instead. */ #endif #ifdef SSQC @@ -1640,6 +1957,27 @@ string(string str) precache_file2 = #77; #endif #ifdef SSQC void(entity player) setspawnparms = #78; +float() ex_finaleFinished = #0:ex_finaleFinished; /* + Behaviour is undocumented. */ + +void(entity client, string sample) ex_localsound = #0:ex_localsound; /* + Behaviour is undocumented. */ + +void(entity ent, string text, optional string s0, optional string s1, optional string s2, optional string s3, optional string s4, optional string s5) ex_centerprint = #0:ex_centerprint; /* + Remaster: Sends the strings to the client, which will order according to {#}. Also substitutes localised strings for $NAME strings. */ + +void(string s, optional string s0, optional string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) ex_bprint = #0:ex_bprint; /* + Remaster: Sends the strings to all clients, which will order them according to {#}. Also substitutes localised strings for $NAME strings. */ + +void(entity client, string s, optional string s0, optional string s1, optional string s2, optional string s3, optional string s4, optional string s5) ex_sprint = #0:ex_sprint; /* + Remaster: Sends the strings to the client, which will order according to {#}. Also substitutes localised strings for $NAME strings. */ + +float(entity playerEnt) ex_CheckPlayerEXFlags = #0:ex_CheckPlayerEXFlags; /* + Behaviour is undocumented. */ + +float(float movedist, vector goal) ex_walkpathtogoal = #0:ex_walkpathtogoal; /* + Behaviour is undocumented. */ + void(entity killer, entity killee) logfrag = #79; /* Part of QW_ENGINE*/ #endif #if defined(CSQC) || defined(SSQC) @@ -1651,16 +1989,19 @@ string(entity e, string key) infokey = #80; /* Part of FTE_QC_INFOKEY, QW_ENGINE float(entity e, string key) infokeyf = #0:infokeyf; /* Identical to regular infokey, except returns a float. */ +int(entity e, string key, optional void *outbuf, int outbufsize) infokey_blob = #0:infokey_blob; /* + Retrieves a user's blob size, and optionally writes it to the specified buffer. */ + #endif #if defined(CSQC) || defined(SSQC) float(string) stof = #81; /* Part of FRIK_FILE, FTE_QC_INFOKEY, FTE_STRINGS, QW_ENGINE, ZQ_QC_STRINGS*/ #endif #ifdef SSQC #define unicast(pl,reli) do{msg_entity = pl; multicast('0 0 0', reli?MULITCAST_ONE_R:MULTICAST_ONE);}while(0) -void(vector where, float set) multicast = #82; /* Part of FTE_QC_MULTICAST +void(vector where, float set) multicast = #82; /* Part of EXT_CSQC, FTE_QC_MULTICAST Once the MSG_MULTICAST network message buffer has been filled with data, this builtin is used to dispatch it to the given target, filtering by pvs for reduced network bandwidth. */ -void(entity to, string str) redirectcmd = #101; /* Part of ??MVDSV_BUILTINS +DEP void(entity to, string str) redirectcmd = #101; /* Part of ??MVDSV_BUILTINS Executes a single console command, and sends the text generated by it to the specified player. The command will be executed at the end of the frame once QC is no longer running - you may wish to pre/postfix it with 'echo'. */ #endif @@ -1684,7 +2025,7 @@ void(vector start, vector mins, vector maxs, vector end, float nomonsters, entit vector() randomvec = #91; /* Part of DP_QC_RANDOMVEC Returns a vector with random values. Each axis is independantly a value between -1 and 1 inclusive. */ -vector(vector org) getlight = #92; +vector(vector org) getlight = #92; /* Part of DP_QC_GETLIGHT*/ float(string cvarname, string defaultvalue) registercvar = #93; /* Part of DP_REGISTERCVAR Creates a new cvar on the fly. If it does not already exist, it will be given the specified value. If it does exist, this is a no-op. This builtin has the limitation that it does not apply to configs or commandlines. Such configs will need to use the set or seta command causing this builtin to be a noop. @@ -1725,12 +2066,15 @@ float(string builtinname) builtin_find = #100; /* #endif #if defined(CSQC) || defined(SSQC) float(float value) anglemod = #102; +float(float newangle, float oldangle) anglesub = #0:anglesub; /* + Returns newangle-oldangle, except returning the shortest route around a circle so yields a result between -180 and +180. */ + #endif #ifdef SSQC -void(string slot, string picname, float x, float y, float zone, optional entity player) showpic = #104; /* Part of TEI_SHOWLMP2*/ -void(string slot, optional entity player) hidepic = #105; /* Part of TEI_SHOWLMP2*/ -void(string slot, float x, float y, float zone, optional entity player) movepic = #106; /* Part of TEI_SHOWLMP2*/ -void(string slot, string picname, optional entity player) changepic = #107; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, string picname, float x, float y, float zone, optional entity player) showpic = #104; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, optional entity player) hidepic = #105; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, float x, float y, float zone, optional entity player) movepic = #106; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, string picname, optional entity player) changepic = #107; /* Part of TEI_SHOWLMP2*/ #endif #if defined(CSQC) || defined(SSQC) filestream(string filename, float mode, optional float mmapminsize) fopen = #110; /* Part of FRIK_FILE @@ -1762,13 +2106,16 @@ float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS* string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, float start, float length) substring = #116; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ vector(string s) stov = #117; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS +FTEDEP("Redundant") string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods. */ -void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS +FTEDEP("Redundant") void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing. */ #endif +void*(int bytes) createbuffer = #0:createbuffer; /* + Returns a temporary buffer that can be written to / read from. The buffer will be garbage collected and thus cannot be explicitly freed. Tempstrings and buffer references must not be stored into the buffer as the garbage collector will not scan these. */ + #ifdef SSQC void(string cvar, float val) cvar_setf = #176; #endif @@ -1780,6 +2127,9 @@ float(string modelname, optional float queryonly) getmodelindex = #200; /* Acts as an alternative to precache_model(foo);setmodel(bar, foo); return bar.modelindex; If queryonly is set and the model was not previously precached, the builtin will return 0 without needlessly precaching the model. */ +float(string soundname, optional float queryonly) getsoundindex = #0:getsoundindex; /* + Provides a way to query if a sound is already precached or not. The return value can also be checked for <=255 to see if it'll work over any network protocol. The sound index can also be used for writebyte hacks, but this is discouraged - use SOUNDFLAG_UNICAST instead. */ + __variant(float prnum, string funcname, ...) externcall = #201; /* Part of FTE_MULTIPROGS Directly call a function in a different/same progs by its name. prnum=0 is the 'default' or 'main' progs. @@ -1827,7 +2177,7 @@ void(float sleeptime) sleep = #212; /* Part of FTE_MULTITHREADED void(entity player, string key, string value) forceinfokey = #213; /* Part of FTE_FORCEINFOKEY Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers. */ -void(entity player, string key, void *data, int size) forceinfokeyblob = #0:forceinfokeyblob; /* +void(entity player, string key, void *data, int size) forceinfokeyblob = #0:forceinfokeyblob; /* Part of FTE_INFOBLOBS Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers. */ #endif @@ -1866,7 +2216,7 @@ string(float ccase, float redalpha, float redchars, string str, ...) strconv = # string(float pad, string str1, ...) strpad = #225; /* Part of FTE_STRINGS Pads the string with spaces, to ensure its a specific length (so long as a fixed-width font is used, anyway). If pad is negative, the spaces are added on the left. If positive the padding is on the right. */ -string(infostring old, string key, string value) infoadd = #226; /* Part of FTE_STRINGS +infostring(infostring old, string key, string value) infoadd = #226; /* Part of FTE_STRINGS Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \ character. */ string(infostring info, string key) infoget = #227; /* Part of FTE_STRINGS @@ -1889,14 +2239,14 @@ string(string s) strtrim = #0:strtrim; /* Trims the whitespace from the start+end of the string. */ #if defined(CSQC) || defined(SSQC) -void() calltimeofday = #231; /* Part of FTE_CALLTIMEOFDAY +__deprecated("Use strftime.") void() calltimeofday = #231; /* Part of FTE_CALLTIMEOFDAY Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv. timeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue) The strftime builtin is more versatile and less weird. */ #endif #ifdef SSQC -void(float num, float type, .__variant fld) clientstat = #232; /* +void(float num, float type, .__variant fld) clientstat = #232; /* Part of EXT_CSQC Specifies what data to use in order to send various stats, in a client-specific way. 'num' should be a value between 32 and 127, other values are reserved. 'type' must be set to one of the EV_* constants, one of EV_FLOAT, EV_STRING, EV_INTEGER, EV_ENTITY. @@ -1908,6 +2258,9 @@ void(float num, float type, string name) globalstat = #233; /* void(float num, float type, __variant *address) pointerstat = #0:pointerstat; /* Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, address however, is the address of the variable you would like to use (pass &foo). */ +void(entity ent, vector sendflags, entity unicastplayer) setsendneeded = #0:setsendneeded; /* + Flags the entity as needing to be resent. This builtin allows for more bits than supported by the SendEntity field, as well as allows flagging sends to specific players. */ + float(entity player) isbackbuffered = #234; /* Part of FTE_ISBACKBUFFERED Returns if the given player's network buffer will take multiple network frames in order to clear. If this builtin returns non-zero, you should delay or reduce the amount of reliable (and also unreliable) data that you are sending to that client. */ @@ -1925,6 +2278,11 @@ float(string shadername, optional string defaultshader, ...) shaderforname = #23 If the shader could not be loaded from disk (missing file or ruleset_allow_shaders 0), it will be created from the 'defaultshader' string if specified, or a 'skin shader' default will be used. defaultshader if not empty should include the outer {} that you would ordinarily find in a shader. */ +#endif +#ifdef CSQC +void(string shadername, string replacement, float timeoffset) remapshader = #0:remapshader; /* + All surfaces drawn with the specified shader will instead be drawn using the specified replacement shader. Shaders can be remapped to something else later by using the same source shadername. This is mostly useful for worldmodel surfaces (eg showing which team is currently winning). Entities should generally use setcustomskin or forceshader instead. Remaps will be forgotten on vid_reload, but can be reapplied via CSQC_RendererRestarted. */ + #endif #if defined(CSQC) || defined(SSQC) void(vector org, optional float count) te_bloodqw = #239; /* Part of FTE_TE_STANDARDEFFECTBUILTINS*/ @@ -1938,7 +2296,7 @@ float(vector viewpos, entity entity) checkpvs = #240; /* Part of FTE_QC_CHECKPVS #ifdef SSQC entity(string match, optional float matchnum) matchclientname = #241; /* Part of FTE_QC_MATCHCLIENTNAME*/ #endif -void(string destaddress, string content) sendpacket = #242; /* Part of FTE_QC_SENDPACKET +float(string destaddress, string content) sendpacket = #242; /* Part of FTE_QC_SENDPACKET Sends a UDP packet to the specified destination. Note that the payload will be prefixed with four 255 bytes as a sort of security feature. */ #ifdef CSQC @@ -1960,6 +2318,51 @@ float(float serveridx, float queryidx, float row, float column) sqlreadfloat = # int(float serveridx, float queryidx, float row, float column, __variant *ptr, int maxsize) sqlreadblob = #0:sqlreadblob; string(float serveridx, __variant *ptr, int maxsize) sqlescapeblob = #0:sqlescapeblob; #endif +typedef struct json_s *json_t; +accessor jsonnode : json_t; +jsonnode(string) json_parse = #0:json_parse; /* + Parses the given JSON string. */ + +void(jsonnode) json_free = #0:json_free; /* + Frees a json tree and all of its children. Must only be called on the root node. */ + +enum json_type_e : int +{ + JSON_TYPE_STRING, + JSON_TYPE_NUMBER, + JSON_TYPE_OBJECT, + JSON_TYPE_ARRAY, + JSON_TYPE_TRUE, + JSON_TYPE_FALSE, + JSON_TYPE_NULL +}; +json_type_e(jsonnode node) json_get_value_type = #0:json_get_value_type; /* + Get type of a JSON value. */ + +int(jsonnode node) json_get_integer = #0:json_get_integer; /* + Get an integer from a json node. */ + +float(jsonnode node) json_get_float = #0:json_get_float; /* + Get a float from a json node. */ + +string(jsonnode node) json_get_string = #0:json_get_string; /* + Get a string from a value. Returns a null string if its not a string type. */ + +jsonnode(jsonnode node, string) json_find_object_child = #0:json_find_object_child; /* + Find a child of a json object by name. Returns NULL if the handle couldn't be found. */ + +int(jsonnode node) json_get_length = #0:json_get_length; /* + Get the length of a json array or object. Returns 0 if its not an array. */ + +jsonnode(jsonnode node, int childindex) json_get_child_at_index = #0:json_get_child_at_index; /* + Get the nth child of a json array or object. Returns NULL if the index is out of range. */ + +string(jsonnode node) json_get_name = #0:json_get_name; /* + Gets the object's name (useful if you're using json_get_child_at_index to walk an object's children for whatever reason). */ + +string(string javascript) js_run_script = #0:js_run_script; /* + Runs the provided javascript snippet. This builtin functions only in emscripten builds, returning a null string on other systems (or if the script evaluates to null). */ + #if defined(CSQC) || defined(SSQC) int(string) stoi = #259; /* Part of FTE_QC_INTCONV Converts the given string into a true integer. Base 8, 10, or 16 is determined based upon the format of the string. */ @@ -1977,14 +2380,18 @@ string(int) htos = #262; /* Part of FTE_QC_INTCONV int(float) ftoi = #0:ftoi; /* Part of FTE_QC_INTCONV Converts the given float into a true integer without depending on extended qcvm instructions. */ -float(int) itof = #0:itof; /* Part of FTE_QC_INTCONV - Converts the given true integer into a float without depending on extended qcvm instructions. */ +float(int, optional float shift, float mask=24) itof = #0:itof; /* Part of FTE_QC_INTCONV + Converts the given true integer into a float without depending on extended qcvm instructions. If shift and mask are specified then only specific parts of the integer will be cast to float. */ #if defined(CSQC) || defined(SSQC) float(float modlindex, optional float useabstransforms) skel_create = #263; /* Part of FTE_CSQC_SKELETONOBJECTS Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model. eg: self.skeletonobject = skel_create(self.modelindex); */ +float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS + Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object. + If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */ + typedef struct { int sourcemodelindex; /*frame data will be imported from this model, bones must be compatible*/ @@ -1999,10 +2406,6 @@ typedef struct float subblend[2]; float controllers[5]; } skelblend_t; -float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS - Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object. - If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */ - float(float skel, int numblends, skelblend_t *weights, int structsize) skel_build_ptr = #0:skel_build_ptr; /* Like skel_build, but slightly simpler. */ @@ -2049,14 +2452,17 @@ float(float modidx, string framename) frameforname = #276; /* Part of FTE_CSQC_S float(float modidx, float framenum) frameduration = #277; /* Part of FTE_CSQC_SKELETONOBJECTS Retrieves the duration (in seconds) of the specified framegroup. */ +float(float modidx, int actionid) frameforaction = #0:frameforaction; /* + Returns a random frame/animation for the specified mod-defined action, or -1 if no animations have the specified action. */ + void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback) processmodelevents = #0:processmodelevents; /* Part of FTE_GFX_MODELEVENTS Calls a callback for each event that has been reached. Basetime is set to targettime. */ -float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data) getnextmodelevent = #0:getnextmodelevent; /* +float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data) getnextmodelevent = #0:getnextmodelevent; /* Part of FTE_GFX_MODELEVENTS Reports the next event within a model's animation. Returns a boolean if an event was found between basetime and targettime. Writes to basetime,code,data arguments (if an event was found, basetime is set to the event's time, otherwise to targettime). WARNING: this builtin cannot deal with multiple events with the same timestamp (only the first will be reported). */ -float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data) getmodeleventidx = #0:getmodeleventidx; /* +float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data) getmodeleventidx = #0:getmodeleventidx; /* Part of FTE_GFX_MODELEVENTS Reports an indexed event within a model's animation. Writes to timestamp,code,data arguments on success. Returns false if the animation/event/model was out of range/invalid. Does not consider looping animations (retry from index 0 if it fails and you know that its a looping animation). This builtin is more annoying to use than getnextmodelevent, but can be made to deal with multiple events with the exact same timestamp. */ #endif @@ -2066,7 +2472,7 @@ vector(vector v1, vector v2) crossproduct = #0:crossproduct; /* Part of FTE_QC_C #if defined(CSQC) || defined(SSQC) float(entity pusher, vector move, vector amove) pushmove = #0:pushmove; -void(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /* Part of FTE_TERRAIN_MAP +__variant(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /* Part of FTE_TERRAIN_MAP Realtime terrain editing. Actions are the TEREDIT_ constants. */ typedef struct @@ -2100,15 +2506,64 @@ int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoin int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults) brush_findinvolume = #0:brush_findinvolume; /* Part of FTE_RAW_MAP Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice. */ +typedef struct +{ + string shadername; + int contents; + int cpwidth; + int cpheight; + int tesswidth; + int tessheight; + vector texinfo;/*scalex,y,rot*/ +} patchinfo_t; +typedef struct +{ + vector xyz; + vector rgb; float a; + float s, t; +} patchvert_t; +#define patch_delete(modelidx,patchidx) brush_delete(modelidx,patchidx) +int(float modelidx, int patchid, patchvert_t *out_controlverts, int maxcp, patchinfo_t *out_info) patch_getcp = #0:patch_getcp; /* + Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error. */ + +int(float modelidx, int patchid, patchvert_t *out_verts, int maxverts, __out patchinfo_t out_info) patch_getmesh = #0:patch_getmesh; /* + Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error. */ + +int(float modelidx, int oldpatchid, patchvert_t *in_controlverts, patchinfo_t in_info) patch_create = #0:patch_create; /* + Inserts a new patch into the model. Return value is the new patch's id. */ + +typedef struct +{ + vector dest; + int linkflags; + float radius; +} nodeslist_t; +void(entity ent, vector dest, int denylinkflags, void(entity ent, vector dest, int numnodes, nodeslist_t *nodelist) callback) route_calculate = #0:route_calculate; /* + Begin calculating a route. The callback function will be called once the route has finished being calculated. The route must be memfreed once it is no longer needed. The route must be followed in reverse order (ie: the first node that must be reached is at index numnodes-1). If no route is available then the callback will be called with no nodes. */ + void(optional entity ent, optional vector neworigin) touchtriggers = #279; /* Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity. */ #endif #ifdef SSQC -void(float buf, float fl) WriteFloat = #280; +void(float buf, float fl) WriteFloat = #280; /* + Writes a full 32bit float without any data conversions at all, for full precision. */ + +void(float buf, __double dbl) WriteDouble = #0:WriteDouble; /* + Writes a full 64bit double-precision float without any data conversions at all, for excessive precision. */ + +void(float buf, int fl) WriteInt = #0:WriteInt; /* + Writes all 4 bytes of a 32bit integer without truncating to a float first before converting back to an int (unlike WriteLong does, but otherwise equivelent). */ + +void(float buf, __int64 fl) WriteInt64 = #0:WriteInt64; /* + Writes all 8 bytes of a 64bit integer. This uses variable-length coding and will send only a single byte for any value between -64 and 63. */ + +void(float buf, __uint64 fl) WriteUInt64 = #0:WriteUInt64; /* + Writes all 8 bytes of a 64bit unsigned integer. Values between 0-127 will be sent in a single byte. */ + #endif #if defined(CSQC) || defined(SSQC) -float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* +float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* Part of FTE_QC_RAGDOLL_WIP Updates the skeletal object attached to the entity according to its origin and other properties. if animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results. If dollcmd is not set, the ragdoll will update (this should be done each frame). @@ -2121,10 +2576,10 @@ float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body). enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter. */ -float*(float skel) skel_mmap = #282; /* +float*(float skel) skel_mmap = #282; /* Part of FTE_QC_RAGDOLL_WIP Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly). */ -void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up) skel_set_bone_world = #283; /* +void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up) skel_set_bone_world = #283; /* Part of FTE_QC_RAGDOLL_WIP Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use. */ string(float modidx, float framenum) frametoname = #284; @@ -2134,18 +2589,24 @@ float(float resourcetype, float tryload, string resourcename) resourcestatus = # #endif hashtable(float tabsize, optional float defaulttype) hash_createtab = #287; /* Part of FTE_QC_HASHTABLES - Creates a hash table object with at least 'tabsize' slots. hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return). */ + Creates a hash table object. + The tabsize argument is a performance hint and should generally be set to something similar to the number of entries expected, typically a power of two assumption. Too high simply wastes memory, too low results in extra string compares but no actual bugs. + defaulttype must be one of the EV_* values, if specified. + The hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return). */ void(hashtable table) hash_destroytab = #288; /* Part of FTE_QC_HASHTABLES Destroys a hash table object. */ void(hashtable table, string name, __variant value, optional float typeandflags) hash_add = #289; /* Part of FTE_QC_HASHTABLES Adds the given key with the given value to the table. - If flags&HASH_REPLACE, the old value will be removed, if not set then multiple values may be added for a single key, they won't overwrite. - The type argument describes how the value should be stored and saved to files. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games. */ + If flags&HASH_REPLACE, the old value will be removed, otherwise if flags&HASH_ADD then a duplicate entry will be added with a second value (can be obtained via hash_get's index argument). + The type argument describes how the value should be stored in saved games, as well as providing constraints with the hash_get function. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games - be sure to be explicit with EV_STRING where appropriate because tempstrings may be reclaimed before the get (especially with saved games or table 0). */ __variant(hashtable table, string name, optional __variant deflt, optional float requiretype, optional float index) hash_get = #290; /* Part of FTE_QC_HASHTABLES - looks up the specified key name in the hash table. returns deflt if key was not found. If stringsonly=1, the return value will be in the form of a tempstring, otherwise it'll be the original value argument exactly as it was. If requiretype is specified, then values not of the specified type will be ignored. Hurrah for multiple types with the same name. */ + Looks up the specified key name in the hash table. Returns deflt if the key was not found. + If requiretype is specified then the function will only consider entries of the matching type (allowing you to store both flags+strings under a single name without getting confused). + If index is specified then the function will ignore the first N entries with the same key (applicable only with entries added using HASH_ADD, not HASH_REPLACE), allowing you to store multiple entries. Keep querying higher indexes starting from 0 until it returns the deflt value. + You will usually need to cast the result of this function to a real datatype. */ __variant(hashtable table, string name) hash_delete = #291; /* Part of FTE_QC_HASHTABLES removes the named key. returns the value of the object that was destroyed, or 0 on error. */ @@ -2189,6 +2650,9 @@ void(float mask) addentities = #301; /* void(entity ent) addentity = #302; /* Copies the entity fields into a new rentity for later rendering via addscene. */ +void(entity ent, vector lightdir, vector lightavg, vector lightrange, int reserved1=0,void*reserved2=0) addentity_lighting = #0:addentity_lighting; /* + Copies the entity fields into a new rentity for later rendering via addscene, but with explicit lighting info. */ + #endif #ifdef CSQC void(entity ent) removeentity = #0:removeentity; /* @@ -2226,8 +2690,13 @@ void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #3 Specifies a polygon vertex with its various properties. */ void() R_EndPolygon = #308; /* - Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader. */ + Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon again if you wish to draw another polygon with the same shader. */ + +#ifdef CSQC +void(float radius, vector texcoordbias) R_EndPolygonRibbon = #0:R_EndPolygonRibbon; /* + Ends the current primitive and duplicates each vertex sideways into a ribbon. The texcoordbias will be added to each duplicated vertex allowing for regular 2d textures. At least 2 verticies must have been specified. You do not need to call beginpolygon again if you wish to draw another polygon with the same shader. */ +#endif #if defined(CSQC) || defined(MENU) #define getviewprop getproperty __variant(float property) getproperty = #309; /* @@ -2243,8 +2712,8 @@ vector (vector v) project = #311; /* #endif #if defined(CSQC) || defined(MENU) -void(vector pos, vector size, float alignflags, string text) drawtextfield = #0:drawtextfield; /* - Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3. */ +float(vector pos, vector size, float alignflags, string text) drawtextfield = #0:drawtextfield; /* + Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3. Returns the total number of lines. */ #endif #ifdef CSQC @@ -2254,27 +2723,30 @@ void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional fl float(string name) iscachedpic = #316; /* Checks to see if the image is currently loaded. Engines might lie, or cache between maps. */ -string(string name, optional float trywad) precache_pic = #317; /* - Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension. */ +string(string name, optional float flags) precache_pic = #317; /* + Forces the engine to load the named image. Flags are a bitmask of the PRECACHE_PIC_* flags. */ #endif #if defined(CSQC) || defined(MENU) void(string imagename, int width, int height, void *pixeldata, optional int datasize, optional int format) r_uploadimage = #0:r_uploadimage; /* Part of FTE_CSQC_RAWIMAGES - Updates a texture with the specified rgba data. Will be created if needed. If blobsize is specified then the image is decoded (eg .ktx or .dds data) instead of being raw R8G8B8A data. You'll typically want shaderforname to also generate a shader to use the texture. */ + Updates a texture with the specified rgba data (uploading it to the gpu). Will be created if needed. If datasize is specified then the image is decoded (eg .ktx or .dds data) instead of being raw R8G8B8A data. You'll typically want shaderforname to also generate a shader to use the texture. */ -int*(string filename, __out int width, __out int height) r_readimage = #0:r_readimage; /* Part of FTE_CSQC_RAWIMAGES - Reads and decodes an image from disk, providing raw R8G8B8A pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it. */ +int*(string filename, __out int width, __out int height, __out int format) r_readimage = #0:r_readimage; /* Part of FTE_CSQC_RAWIMAGES + Reads and decodes an image from disk, providing raw R8G8B8A8 pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it. */ #endif #ifdef CSQC #define draw_getimagesize drawgetimagesize vector(string picname) drawgetimagesize = #318; /* - Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution. */ + Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution. WARNING: this function may be slow if used without or directly after its initial precache_pic. */ void(string name) freepic = #319; /* Tells the engine that the image is no longer needed. The image will appear to be new the next time its needed. */ -float(vector position, float character, vector size, vector rgb, float alpha, optional float drawflag) drawcharacter = #320; /* +string(string modelname, int frame, float frametime) spriteframe = #0:spriteframe; /* + Obtains a suitable shader name to draw a sprite's shader via drawpic/R_BeginPolygon/etc, instead of needing to create a scene. */ + +float(vector position, float character, vector size='8 8', vector rgb='1 1 1', float alpha=1, optional float drawflag=0) drawcharacter = #320; /* Draw the given quake character at the given position. If flag&4, the function will consider the char to be a unicode char instead (or display as a ? if outside the 32-127 range). size should normally be something like '8 8 0'. @@ -2288,7 +2760,7 @@ float(vector position, string text, vector size, vector rgb, float alpha, option If UTF-8 is globally enabled in the engine, then that encoding is used (without additional markup), otherwise it is raw quake chars. Software engines may assume a size of '8 8 0', rgb='1 1 1', alpha=1, flag&3=0, but it is not an error to draw out of the screen. */ -float(vector position, string pic, vector size, vector rgb, float alpha, optional float drawflag) drawpic = #322; /* +float(vector position, string pic, vector size, vector rgb='1 1 1', float alpha=1, optional float drawflag=0) drawpic = #322; /* Draws an shader within the given 2d screen box. Software engines may omit support for rgb+alpha, but must support rescaling, and must clip to the screen without crashing. */ float(vector position, vector size, vector rgb, float alpha, optional float drawflag) drawfill = #323; /* @@ -2302,10 +2774,10 @@ void(float x, float y, float width, float height) drawsetcliparea = #324; /* void(void) drawresetcliparea = #325; /* Reverts the scissor/clip area to the whole screen. */ -float(vector position, string text, vector size, vector rgb, float alpha, float drawflag) drawstring = #326; /* +float(vector position, string text, vector size='8 8', vector rgb='1 1 1', float alpha=1, float drawflag=0) drawstring = #326; /* Draws a string, interpreting markup and recolouring as appropriate. */ -float(string text, float usecolours, optional vector fontsize) stringwidth = #327; /* +float(string text, float usecolours, vector fontsize='8 8') stringwidth = #327; /* Calculates the width of the screen in virtual pixels. If usecolours is 1, markup that does not affect the string width will be ignored. Will always be decoded as UTF-8 if UTF-8 is globally enabled. If the char size is not specified, '8 8 0' will be assumed. */ @@ -2324,27 +2796,30 @@ void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector tx #ifdef CSQC #define getstati_punf(stnum) (float)(__variant)getstati(stnum) int(float stnum) getstati = #330; /* - Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat. Use getstati_punf if you wish to type-pun a float stat as an int to avoid truncation issues in DP. */ + Retrieves the full precision of a stat registered as EV_INTEGER. */ #define getstatbits getstatf float(float stnum, optional float firstbit, optional float bitcount) getstatf = #331; /* - Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat (converted into a float, so there are no VM dependancies). */ + Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, then this builtin acts as getstati combined with itof, and which should be used for STAT_ITEMS (but not other stats). */ string(float stnum) getstats = #332; /* Retrieves the value of the given EV_STRING stat, as a tempstring. Older engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but FTE Quake uses a separate namespace for string stats and has a much higher length limit. */ __variant(float playernum, float statnum, float stattype) getplayerstat = #0:getplayerstat; /* - Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits. */ + Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. Return value matches the specified EV_ stattype. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits. */ void(entity e, float mdlindex) setmodelindex = #333; /* Sets a model by precache index instead of by name. Otherwise identical to setmodel. */ -string(float mdlindex) modelnameforindex = #334; /* - Retrieves the name of the model based upon a precache index. This can be used to reduce csqc network traffic by enabling model matching. */ - #endif #if defined(CSQC) || defined(SSQC) +string(float mdlindex) modelnameforindex = #334; /* + Retrieves the name of the model based upon a precache index. This can be used to reduce csqc network traffic by enabling model matching (with getmodelindex). */ + +string(float sndindex) soundnameforindex = #0:soundnameforindex; /* + Retrieves the name of the sound based upon a precache index. This can be used to reduce csqc network traffic by enabling sound matching (with getsoundindex). */ + float(string effectname) particleeffectnum = #335; /* Part of DP_ENT_TRAILEFFECTNUM, FTE_SV_POINTPARTICLES Precaches the named particle effect. If your effect name is of the form 'foo.bar' then particles/foo.cfg will be loaded by the client if foo.bar was not already defined. Different engines will have different particle systems, this specifies the QC API only. */ @@ -2373,7 +2848,7 @@ string(float keynum) keynumtostring = #340; /* #endif #ifdef MENU -string(float keynum) keynumtostring_csqc = #340; /* +DEP string(float keynum) keynumtostring_csqc = #340; /* Returns a hunam-readable name for the given keycode, as a tempstring. */ #endif @@ -2383,7 +2858,7 @@ float(string keyname) stringtokeynum = #341; /* #endif #ifdef MENU -float(string keyname) stringtokeynum_csqc = #341; /* +DEP float(string keyname) stringtokeynum_csqc = #341; /* Looks up the key name in the same way that the bind command would, returning the keycode for that key. */ #endif @@ -2400,8 +2875,15 @@ float(float effective) getcursormode = #0:getcursormode; /* #endif #ifdef CSQC vector() getmousepos = #344; /* - Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods. */ + Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent instead for such things in csqc mods. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(vector newpos) setmousepos = #0:setmousepos; /* + Warps the mouse cursor to the given location. Should normally only be done following setcursormode(TRUE,...). The warp MAY be visible through *_InputEvent, but normally be seen as an IE_ABSMOUSE event anyway. Not all systems support cursor warping (or even cursors), so this is a hint only and you should not depend upon it. */ +#endif +#ifdef CSQC float(float inputsequencenum) getinputstate = #345; /* Looks up an input frame from the log, setting the input_* globals accordingly. The sequence number range used for prediction should normally be servercommandframe < sequence <= clientcommandframe. @@ -2424,16 +2906,30 @@ string(float playernum, string keyname) getplayerkeyvalue = #348; /* float(float playernum, string keyname, optional float assumevalue) getplayerkeyfloat = #0:getplayerkeyfloat; /* Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ -int(float playernum, string keyname, optional void *outptr, int size) getplayerkeyblob = #0:getplayerkeyblob; /* - Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ +int(float playernum, string keyname, optional void *outptr, int size) getplayerkeyblob = #0:getplayerkeyblob; /* Part of FTE_INFOBLOBS + Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; /* + Change a userinfo key for the specified local player seat, equivelent to the setinfo console command. The server will normally forward the setting to other clients. */ + +string(float seat, string keyname) getlocaluserinfo = #0:getlocaluserinfo; /* + Reads a local userinfo key for the specified local player seat. This is not quite the same as getplayerkeyvalue, due to latency and possible serverside filtering. */ + +void(float seat, string keyname, void *outptr, int size) setlocaluserinfoblob = #0:setlocaluserinfoblob; /* Part of FTE_INFOBLOBS + Sets the userinfo key to a blob that may contain nulls etc. Keys with a leading underscore will be visible to only the server (for user-specific binary settings). */ + +int(float seat, string keyname, void *outptr, int maxsize) getlocaluserinfoblob = #0:getlocaluserinfoblob; /* Part of FTE_INFOBLOBS + Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ #endif #ifdef SSQC int(string keyname, optional void *outptr, int size) getlocalinfo = #0:getlocalinfo; /* - Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ + Obtains a copy of a data blob (with spaces) from the server's private localinfo. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ void(string keyname, optional void *outptr, int size) setlocalinfo = #0:setlocalinfo; /* - Changes the server's localinfo. This data will be available for the following map, and will *usually* reload with saved games. */ + Changes the server's private localinfo. This data will be available for the following map, and will *usually* reload with saved games. */ #endif #if defined(CSQC) || defined(MENU) @@ -2477,28 +2973,26 @@ void(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t) setup_re Reconfigures a reverb slot for weird effects. Slot 0 is reserved for no effects. Slot 1 is reserved for underwater effects. Reserved slots will be reinitialised on snd_restart, but can otherwise be changed. These reverb slots can be activated with SetListener. Note that reverb will currently only work when using OpenAL. */ #endif -#if defined(CSQC) || defined(MENU) void(string cmdname) registercommand = #352; /* Register the given console command, for easy console use. - Console commands that are later used will invoke CSQC_ConsoleCommand. */ + Console commands that are later used will invoke CSQC_ConsoleCommand/m_consolecommand/ConsoleCmd according to module. */ -#endif -#if defined(CSQC) || defined(SSQC) float(entity ent) wasfreed = #353; /* - Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust. */ + Quickly check to see if the entity is currently free. This function is only valid during the half-second non-reuse window, after that it may give bad results. Try one second to make it more robust. */ +#if defined(CSQC) || defined(SSQC) string(string key) serverkey = #354; /* - Look up a key in the server's public serverinfo string */ + Look up a key in the server's public serverinfo string. If the key contains binary data then it will be truncated at the first null. */ float(string key, optional float assumevalue) serverkeyfloat = #0:serverkeyfloat; /* Version of serverkey that returns the value as a float (which avoids tempstrings). */ -int(int buf, string key, optional void *ptr, int size) serverkeyblob = #0:serverkeyblob; /* - Version of serverkey that can obtain entire serverinfo, localinfo, or (local)userinfo blobs. Returns blob size */ +int(string key, optional void *ptr, int maxsize) serverkeyblob = #0:serverkeyblob; /* Part of FTE_INFOBLOBS + Version of serverkey that returns data as a blob (ie: binary data that may contain nulls). Returns the full blob size, even if truncated (pass maxsize=0 to query required storage). */ #endif #ifdef SSQC -void(int buf, string key, void *ptr, optional int size) setserverkey = #0:setserverkey; /* +void(string key, void *ptr, optional int size) setserverkey = #0:setserverkey; /* Changes the server's serverinfo. */ #endif @@ -2516,22 +3010,52 @@ float(string s) findfont = #356; /* Part of DP_GFX_FONTS Looks up a named font slot. Matches the actual font name as a last resort. */ float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357; /* Part of DP_GFX_FONTS - too convoluted for me to even try to explain correct usage. Try drawfont = loadfont("", "cour", "16", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows.. */ + too convoluted for me to even try to explain correct usage. Try drawfont = loadfont("", "cour", "16", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high) ('cour' requires mscorefonts installed in linux). Additionally you can add "outline=1" as an extra token in the sizes string, to have more readable outlined fonts. */ #endif #ifdef CSQC void(string evname, string evargs, ...) sendevent = #359; /* Invoke CSEv_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors. */ -float() readbyte = #360; -float() readchar = #361; -float() readshort = #362; -float() readlong = #363; -float() readcoord = #364; -float() readangle = #365; -string() readstring = #366; -float() readfloat = #367; -float() readentitynum = #368; +float() readbyte = #360; /* + Reads an unsigned 8-bit value, pair with WriteByte. */ + +float() readchar = #361; /* + Reads a signed 8-bit value. Paired with WriteChar. */ + +float() readshort = #362; /* + Reads a signed 16-bit value. Paired with WriteShort. */ + +float() readlong = #363; /* + Reads a signed 32-bit value. Paired with WriteLong or WriteInt. */ + +float() readcoord = #364; /* + Reads a value matching the unspecified precision written ONLY by WriteCoord. */ + +float() readangle = #365; /* + Reads a value matching the unspecified precision written ONLY by WriteAngle. */ + +string() readstring = #366; /* + Reads a null-terminated string. */ + +float() readfloat = #367; /* + Reads a float without any truncation nor conversions. Data MUST have originally been written with WriteFloat. */ + +__double() readdouble = #0:readdouble; /* + Reads a double-precision float without any truncation nor conversions. Data MUST have originally been written with WriteDouble. */ + +int() readint = #0:readint; /* + Reads a 32bit int without any conversions to float, otherwise interchangable with readlong. */ + +__int64() readint64 = #0:readint64; /* + Reads a 64bit signed int. Paired with WriteInt64. */ + +__uint64() readuint64 = #0:readuint64; /* + Reads a 64bit unsigned int. Paired with WriteUInt64. */ + +float() readentitynum = #368; /* + Reads the serverside index of an entity, paired with WriteEntity. There may be nothing else known about the entity yet, so the result typically needs to be saved as-is and re-looked up each frame. This can be done via getentity(NUM, GE_*) for non-csqc ents, or findentity(world,entnum,NUM) - both of which can fail due to latency. */ + float(string modelname, float(float isnew) updatecallback, float flags) deltalisten = #371; /* Specifies a per-modelindex callback to listen for engine-networking entity updates. Such entities are automatically interpolated by the engine (unless flags specifies not to). The various standard entity fields will be overwritten each frame before the updatecallback function is called. */ @@ -2558,10 +3082,10 @@ void(entity e, string skinfilename, optional string skindata) setcustomskin = #3 #endif #ifdef CSQC -float(string skinfilename, optional string skindata) loadcustomskin = #377; /* +float(string skinfilename, optional string skindata) loadcustomskin = #377; /* Part of FTE_QC_CUSTOMSKINS Creates a new skin object and returns it. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format: - surfacename,shadername - makes the named surface use the named shader - replace "surfacename" "shadername" - same. + surfacename,shadername - makes the named surface use the named shader (legacy format for compat with q3) + replace "surfacename" "shadername" - non-legacy equivalent. qwskin "foo" - use an unmodified quakeworld player skin (including crop+repalette rules) q1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red q1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue @@ -2569,12 +3093,24 @@ float(string skinfilename, optional string skindata) loadcustomskin = #377; /* The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line. Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). Must be matched with a releasecustomskin call later, and is pointless without applycustomskin. */ -void(entity e, float skinobj) applycustomskin = #378; /* +void(entity e, float skinobj) applycustomskin = #378; /* Part of FTE_QC_CUSTOMSKINS Updates the entity's custom skin (refcounted). */ -void(float skinobj) releasecustomskin = #379; /* +void(float skinobj) releasecustomskin = #379; /* Part of FTE_QC_CUSTOMSKINS Lets the engine know that the skin will no longer be needed. Thanks to refcounting any ents with the skin already applied will retain their skin until later changed. It is valid to destroy a skin just after applying it to an ent in the same function that it was created in, as the skin will only be destroyed once its refcount rops to 0. */ +void(float devid, float amp_low, float amp_high, float duration) gp_rumble = #0:gp_rumble; /* + Sends a single rumble event to the game-pad specified in devid. Every time you call this, the previous effect is cancelled out. */ + +void(float devid, float left, float right, float duration) gp_rumbletriggers = #0:gp_rumbletriggers; /* + Makes the analog triggers rumble of the specified game-pad, like gp_rumble() one call cancels out the previous one on the device. */ + +void(float devid, vector color) gp_setledcolor = #0:gp_setledcolor; /* + Updates the game-pad LED color. */ + +void(float devid, /*const*/ void *data, int size) gp_settriggerfx = #0:gp_settriggerfx; /* + Sends a specific effect packet to the controller. On the PlayStation 5's DualSense that can adjust the tension on the analog triggers. */ + #endif __variant*(int size) memalloc = #384; /* Part of FTE_MEMALLOC Allocate an arbitary block of memory */ @@ -2613,13 +3149,9 @@ void(string conname, vector pos, vector size, float fontsize) con_draw = #393; / float(string conname, float inevtype, float parama, float paramb, float paramc) con_input = #394; /* Part of FTE_CSQC_ALTCONSOLES Forwards input events to the named console. Mouse updates should be absolute only. */ -#endif -#ifdef CSQC void(string newcaption) setwindowcaption = #0:setwindowcaption; /* Part of FTE_CSQC_WINDOWCAPTION Replaces the title of the game window, as seen when task switching or just running in windowed mode. */ -#endif -#if defined(CSQC) || defined(MENU) float() cvars_haveunsaved = #0:cvars_haveunsaved; /* Returns true if any archived cvar has an unsaved value. */ @@ -2627,13 +3159,33 @@ float() cvars_haveunsaved = #0:cvars_haveunsaved; /* float(entity e, float nowreadonly) entityprotection = #0:entityprotection; /* Changes the protection on the specified entity to protect it from further edits from QC. The return value is the previous setting. Note that this can be used to unprotect the world, but doing so long term is not advised as you will no longer be able to detect invalid entity references. Also, world is not networked, so results might not be seen by clients (or in other words, world.avelocity_y=64 is a bad idea). */ +#ifdef CSQC +string(vector pos) getlocationname = #0:getlocationname; /* + Looks up the specified position in the current map's .loc file and reports the nearest marked name. */ + +#endif +#ifdef MENU +void(int cliptype) clipboard_get = #0:clipboard_get; /* + Attempts to query the system clipboard. Any pasted text will be returned via Menu_InputEvent */ + +#endif +#if defined(CSQC) || defined(MENU) +void(int cliptype, string text) clipboard_set = #0:clipboard_set; /* + Changes the system clipboard to the specified text. */ + +#endif +#ifdef SSQC +entity(float entnum, optional __out float wasspawned) respawnedict = #0:respawnedict; /* + Acts like edict_num returning a specific entity number, but also marks it as spawned. If it was previously spawned then all of its prior field data will be LOST (you may wish to use wasfreed(edict_num(idx)) to check. */ + +#endif #if defined(CSQC) || defined(SSQC) entity(entity from, optional entity to) copyentity = #400; /* Part of DP_QC_COPYENTITY Copies all fields from one entity to another. */ #endif #ifdef SSQC -void(entity ent, float colours) setcolors = #401; /* +__deprecated("No RGB support.") void(entity ent, float colours) setcolor = #401; /* Part of DP_SV_SETCOLOR Changes a player's colours. The bits 0-3 are the lower/trouser colour, bits 4-7 are the upper/shirt colours. */ #endif @@ -2691,7 +3243,7 @@ void(strbuf bufhandle, float string_index, string str) bufstr_set = #447; /* Par float(strbuf bufhandle, string str, float ordered) bufstr_add = #448; /* Part of DP_QC_STRINGBUFFERS*/ void(strbuf bufhandle, float string_index) bufstr_free = #449; /* Part of DP_QC_STRINGBUFFERS*/ float(string name) iscachedpic = #451; -string(string name, optional float trywad) precache_pic = #452; +string(string name, optional float flags) precache_pic = #452; float(vector position, float character, vector scale, vector rgb, float alpha, optional float flag) drawcharacter = #454; float(vector position, string text, vector scale, vector rgb, float alpha, optional float flag) drawrawstring = #455; float(vector position, string pic, vector size, vector rgb, float alpha, optional float flag) drawpic = #456; @@ -2699,25 +3251,26 @@ float(vector position, vector size, vector rgb, float alpha, optional float flag void(float x, float y, float width, float height) drawsetcliparea = #458; void(void) drawresetcliparea = #459; vector(string picname) drawgetimagesize = #460; +void(float width, vector pos1, vector pos2) drawline = #466; float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #467; -float(string text, float usecolours, optional vector fontsize) stringwidth = #468; +float(string text, float usecolours, vector fontsize='8 8') stringwidth = #468; void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, float flag) drawsubpic = #469; #endif #ifdef SSQC void(entity e, string s) clientcommand = #440; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ #endif #if defined(CSQC) || defined(SSQC) -float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ /* return value is the number of parts created, ie argc */ +float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ string(float n) argv = #442; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ void(entity e, entity tagentity, string tagname) setattachment = #443; /* Part of DP_GFX_QUAKE3MODELTAGS*/ -searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #444; /* Part of DP_QC_FS_SEARCH - initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. */ +searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3} flags, float quiet, optional string filterpackage) search_begin = #444; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE + initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. SB_FULLPACKAGEPATH interprets the filterpackage arg as a full package path to avoid gamedir ambiguity, equivelent to whichpack's WP_FULLPACKAGEPATH flag. SB_ALLOWDUPES allows returning multiple entries with the same name (but different package, useful with search_fopen). SB_FORCESEARCH requires use of the filterpackage and SB_FULLPACKAGEPATH flag, initiating searches from gamedirs/packages which are not currently active. */ -void(searchhandle handle) search_end = #445; /* Part of DP_QC_FS_SEARCH*/ -float(searchhandle handle) search_getsize = #446; /* Part of DP_QC_FS_SEARCH +void(searchhandle handle) search_end = #445; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +float(searchhandle handle) search_getsize = #446; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE Retrieves the number of files that were found. */ -string(searchhandle handle, float num) search_getfilename = #447; /* Part of DP_QC_FS_SEARCH +string(searchhandle handle, float num) search_getfilename = #447; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE Retrieves name of one of the files that was found by the initial search. */ #endif @@ -2727,6 +3280,12 @@ float(searchhandle handle, float num) search_getfilesize = #0:search_getfilesize string(searchhandle handle, float num) search_getfilemtime = #0:search_getfilemtime; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME Retrieves modification time of one of the files. */ +string(searchhandle handle, float num) search_getpackagename = #0:search_getpackagename; /* + Retrieves the name of the package containing the file. Search with SB_FULLPACKAGEPATH to see gamedir/package info */ + +filestream(searchhandle handle, float num) search_fopen = #0:search_fopen; /* + Opens the file directly, without getting confused about entries from other packages. Read access only. */ + #if defined(CSQC) || defined(SSQC) string(string cvarname) cvar_string = #448; /* Part of DP_QC_CVAR_STRING*/ entity(entity start, .float fld, float match) findflags = #449; /* Part of DP_QC_FINDFLAGS*/ @@ -2770,11 +3329,15 @@ string(string s) strdecolorize = #477; /* Part of DP_QC_STRINGCOLORFUNCTIONS Flattens any markup/colours, removing them from the string. */ string(float uselocaltime, string format, ...) strftime = #478; /* Part of DP_QC_STRFTIME*/ -float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR*/ +float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR + Splits up the string using only the specified delimiters/separators. Multiple delimiters can be given, they are each considered equivelent (though should start with the longest if you want to do weird subseparator stuff). + The resulting tokens can be queried via argv (and argv_start|end_index builtins, if you want to determine which of the separators was present between two tokens). + Note that while an input string containing JUST a separator will return 2, a string with no delimiter will return 1, while (in FTE) an empty string will ALWAYS return 0. */ + string(string s) strtolower = #480; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ string(string s) strtoupper = #481; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ -string(string s) cvar_defstring = #482; /* Part of DP_QC_CVAR_DEFSTRING*/ #if defined(CSQC) || defined(SSQC) +string(string s) cvar_defstring = #482; /* Part of DP_QC_CVAR_DEFSTRING*/ void(vector origin, string sample, float volume, float attenuation) pointsound = #483; /* Part of DP_SV_POINTSOUND*/ #endif string(string search, string replace, string subject) strreplace = #484; /* Part of DP_QC_STRREPLACE*/ @@ -2815,7 +3378,7 @@ void(string id, float newstate) cin_setstate = #0:cin_setstate; float(string id) cin_getstate = #0:cin_getstate; void(string file) cin_restart = #0:cin_restart; #endif -float(float caseinsensitive, string s, ...) crc16 = #494; /* Part of DP_QC_CRC16*/ +__deprecated("Use digest_hex") float(float caseinsensitive, string s, ...) crc16 = #494; /* Part of DP_QC_CRC16*/ float(string name) cvar_type = #495; /* Part of DP_QC_CVAR_TYPE*/ float() numentityfields = #496; /* Part of DP_QC_ENTITYDATA Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3). */ @@ -2846,16 +3409,20 @@ string() ReadPicture = #501; /* void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, optional float flags) boxparticles = #502; #endif -string(string filename, optional float makereferenced) whichpack = #503; /* Part of DP_QC_WHICHPACK - Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If makereferenced is true, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ +string(string filename, optional enumflags:float{WP_REFERENCEPACKAGE,WP_FULLPACKAGEPATH} flags) whichpack = #503; /* Part of DP_QC_WHICHPACK + Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If WP_REFERENCE, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ #ifdef CSQC __variant(float entnum, float fieldnum) getentity = #504; /* Looks up fields from non-csqc-visible entities. The entity will need to be within the player's pvs. fieldnum should be one of the GE_ constants. */ #endif -string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE*/ -string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE*/ +string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE + Uses percent-encoding to encode any bytes in the input string which are not ascii alphanumeric, period, hyphen, or underscore. All other bytes will expand to eg '%20' for a single space char. This encoding scheme is compatible with http and other uris. */ + +string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE + Undo any percent-encoding in the input string, hopefully resulting in the same original sequence of bytes (and thus chars too). */ + float(entity ent) num_for_edict = #512; #define uri_post uri_get float(string uril, float id, optional string postmimetype, optional string postdata) uri_get = #513; /* Part of DP_QC_URI_GET, DP_QC_URI_POST @@ -2882,10 +3449,12 @@ string(string cvarname) cvar_description = #518; /* float(optional float timetype) gettime = #519; #endif #ifdef CSQC -string(float keynum) keynumtostring_omgwtf = #520; -string(string command, optional float bindmap) findkeysforcommand = #521; /* +DEP string(float keynum) keynumtostring_omgwtf = #520; +__deprecated("Does not support modifiers") string(string command, optional float bindmap) findkeysforcommand = #521; /* Returns a list of keycodes that perform the given console command in a format that can only be parsed via tokenize (NOT tokenize_console). This only and always returns two values - if only one key is actually bound, -1 will be returned. The bindmap argument is listed for compatibility with dp-specific defs, but is ignored in FTE. */ +#endif +#if defined(CSQC) || defined(MENU) string(string command, optional float bindmap) findkeysforcommandex = #0:findkeysforcommandex; /* Returns a list of key bindings in keyname format instead of keynums. Use tokenize to parse. This list may contain modifiers. May return large numbers of keys. */ @@ -2897,14 +3466,14 @@ void(string s) loadfromdata = #529; /* void(string s) loadfromfile = #530; /* Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ -#endif -#ifdef SSQC void(float pause) setpause = #531; /* Sets whether the server should or should not be paused. This does not affect auto-paused things like when the console is down. */ +#endif +#ifdef SSQC float(string mname) precache_vwep_model = #532; /* Part of ZQ_VWEP*/ #endif -float(float v, optional float base) log = #532; /* Part of ??MVDSV_BUILTINS +float(float v, optional float base) log = #532; /* Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */ #ifdef CSQC @@ -2914,6 +3483,9 @@ float(entity e, float channel, string newsample, float volume, float attenuation float(entity e, float channel) getsoundtime = #533; /* Returns the current playback time of the sample on the given entity's channel. Beware CHAN_AUTO (in csqc, channels are not limited by network protocol). */ +float(entity e, float channel) getchannellevel = #0:getchannellevel; /* + Reports how load the sound's sample is at its current offset. */ + #endif #if defined(CSQC) || defined(MENU) float(string sample) soundlength = #534; /* @@ -2926,9 +3498,12 @@ float(string filename, strbuf bufhandle) buf_loadfile = #535; /* float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536; /* Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer. */ +float(float bufhandle, string match, float matchrule, float startpos, float step) bufstr_find = #537; /* + Looks for the first occurence of the specified string in the buffer, returning its index or -1 on failure. */ + #ifdef SSQC -float(optional float force) physics_supported = #0:physics_supported; /* - Queries whether rigid body physics is enabled or not. CSQC and SSQC may report different values. If the force argument is used then the engine will try to activate or release physics (returning the new state, which may fail if plugins or dlls are missing). Note that restarting the physics engine is likely to result in hitches when collision trees get generated. The state may change if a plugin is disabled mid-map. */ +float(optional float forcestate) physics_supported = #0:physics_supported; /* + Queries whether rigid body physics is enabled or not. CSQC and SSQC may report different values. If the force argument is specified then the engine will try to activate or release physics (returning the new state, which may fail if plugins or dlls are missing). Note that restarting the physics engine is likely to result in hitches when collision trees get generated. The state may change if a plugin is disabled mid-map. */ #endif #if defined(CSQC) || defined(SSQC) @@ -2965,7 +3540,7 @@ vector(float vidmode, optional float forfullscreen) getresolution = #608; /* #endif #ifdef CSQC -string(float keynum) keynumtostring_menu = #609; +DEP string(float keynum) keynumtostring_menu = #609; #endif #ifdef MENU string(float keynum) keynumtostring = #609; /* @@ -3004,6 +3579,14 @@ void(string key) addwantedhostcachekey = #623; /* Part of FTE_CSQC_SERVERBROWSER string() getextresponse = #624; /* Part of FTE_CSQC_SERVERBROWSER*/ #endif string(string dnsname, optional float defport) netaddress_resolve = #625; +#if defined(CSQC) || defined(MENU) +string(float n, float prop) getgamedirinfo = #626; /* + Queries properties about an indexed gamedir (or -1 for the current gamedir). Returns null strings when out of bounds. Use the GDDI_* constants for the prop arg. */ + +string(int n, int prop) getpackagemanagerinfo = #0:getpackagemanagerinfo; /* + Queries information about a package from the engine's package manager subsystem. Actions can be taken via the pkg console command. */ + +#endif string(string fmt, ...) sprintf = #627; /* Part of DP_QC_SPRINTF 'prints' to a formatted temp-string. Mostly acts as in C, however %d assumes floats (fteqcc has arg checking. Use it.). type conversions: l=arg is an int, h=arg is a float, and will work as a prefix for any float or int representation. @@ -3017,6 +3600,7 @@ float(entity e, float s) getsurfacenumtriangles = #628; vector(entity e, float s, float n) getsurfacetriangle = #629; #endif #if defined(CSQC) || defined(MENU) +float(float key, string bind, optional float bindmap, optional float modifier) setkeybind = #630; vector() getbindmaps = #631; float(vector bm) setbindmaps = #632; #endif @@ -3024,149 +3608,184 @@ string(string digest, string data, ...) digest_hex = #639; string(string digest, void *data, int length) digest_ptr = #0:digest_ptr; /* Calculates the digest of a single contiguous block of memory (including nulls) using the specified hash function. */ +float(string src, string dst) fcopy = #650; /* + Equivelent to fopen+fread+fwrite+fclose from QC (ie: reads from $gamedir/data/ or $gamedir, but always writes to $gamedir/data/ ) */ + +float(string src, string dst) frename = #651; /* + Renames the file, returning 0 on success. Both paths are relative to the data/ subdir. */ + +float(string fname) fremove = #652; /* + Deletes the named file - path is relative to data/ subdir, like fopen's FILE_WRITE. Returns 0 on success. */ + +float(string fname) fexists = #653; /* + Returns true if it exists inside the default writable path. Use whichpack for greater portability. */ + +float(string path) rmtree = #654; /* + Dangerous, but sandboxed to data/ */ + #if defined(CSQC) || defined(MENU) -#define K_TAB 9 -#define K_ENTER 13 -#define K_ESCAPE 27 -#define K_SPACE 32 -#define K_BACKSPACE 127 -#define K_UPARROW 128 -#define K_DOWNARROW 129 -#define K_LEFTARROW 130 -#define K_RIGHTARROW 131 -#define K_LALT 132 -#define K_RALT -245 -#define K_LCTRL 133 -#define K_RCTRL -246 -#define K_LSHIFT 134 -#define K_RSHIFT -247 -#define K_F1 135 -#define K_F2 136 -#define K_F3 137 -#define K_F4 138 -#define K_F5 139 -#define K_F6 140 -#define K_F7 141 -#define K_F8 142 -#define K_F9 143 -#define K_F10 144 -#define K_F11 145 -#define K_F12 146 -#define K_INS 147 -#define K_DEL 148 -#define K_PGDN 149 -#define K_PGUP 150 -#define K_HOME 151 -#define K_END 152 -#define K_KP_HOME 164 -#define K_KP_UPARROW 165 -#define K_KP_PGUP 166 -#define K_KP_LEFTARROW 161 -#define K_KP_5 162 -#define K_KP_RIGHTARROW 163 -#define K_KP_END 158 -#define K_KP_DOWNARROW 159 -#define K_KP_PGDN 160 -#define K_KP_ENTER 172 -#define K_KP_INS 157 -#define K_KP_DEL 167 -#define K_KP_SLASH 168 -#define K_KP_MINUS 170 -#define K_KP_PLUS 171 -#define K_KP_NUMLOCK 154 -#define K_KP_STAR 169 -#define K_KP_EQUALS 173 -#define K_MOUSE1 512 -#define K_MOUSE2 513 -#define K_MOUSE3 514 -#define K_MOUSE4 517 -#define K_MOUSE5 518 -#define K_MOUSE6 519 -#define K_MOUSE7 520 -#define K_MOUSE8 521 -#define K_MOUSE9 522 -#define K_MOUSE10 523 -#define K_MWHEELUP 515 -#define K_MWHEELDOWN 516 -#define K_LWIN -239 -#define K_RWIN -240 -#define K_APP -241 -#define K_SEARCH -242 -#define K_POWER -130 -#define K_VOLUP -243 -#define K_VOLDOWN -244 -#define K_JOY1 768 -#define K_JOY2 769 -#define K_JOY3 770 -#define K_JOY4 771 -#define K_AUX1 784 -#define K_AUX2 785 -#define K_AUX3 786 -#define K_AUX4 787 -#define K_AUX5 788 -#define K_AUX6 789 -#define K_AUX7 790 -#define K_AUX8 791 -#define K_AUX9 792 -#define K_AUX10 793 -#define K_AUX11 794 -#define K_AUX12 795 -#define K_AUX13 796 -#define K_AUX14 797 -#define K_AUX15 798 -#define K_AUX16 799 -#define K_AUX17 800 -#define K_AUX18 801 -#define K_AUX19 802 -#define K_AUX20 803 -#define K_AUX21 804 -#define K_AUX22 805 -#define K_AUX23 806 -#define K_AUX24 807 -#define K_AUX25 808 -#define K_AUX26 809 -#define K_AUX27 810 -#define K_AUX28 811 -#define K_AUX29 812 -#define K_AUX30 813 -#define K_AUX31 814 -#define K_AUX32 815 -#define K_PAUSE 153 -#define K_PRINTSCREEN 174 -#define K_CAPSLOCK 155 -#define K_SCROLLLOCK 156 -#define K_SEMICOLON 59 -#define K_PLUS 43 -#define K_MINUS 45 -#define K_TILDE 126 -#define K_BACKQUOTE 96 -#define K_BACKSLASH 92 -#define K_GP_A 826 -#define K_GP_B 827 -#define K_GP_X 828 -#define K_GP_Y 829 -#define K_GP_LSHOULDER 824 -#define K_GP_RSHOULDER 825 -#define K_GP_LTRIGGER 830 -#define K_GP_RTRIGGER 831 -#define K_GP_BACK 821 -#define K_GP_START 820 -#define K_GP_LTHUMB 822 -#define K_GP_RTHUMB 823 -#define K_GP_DPAD_UP 816 -#define K_GP_DPAD_DOWN 817 -#define K_GP_DPAD_LEFT 818 -#define K_GP_DPAD_RIGHT 819 -#define K_GP_GUIDE -202 -#define K_GP_UNKNOWN -255 -#define K_GP_LTHUMB_UP 832 -#define K_GP_LTHUMB_DOWN 833 -#define K_GP_LTHUMB_LEFT 834 -#define K_GP_LTHUMB_RIGHT 835 -#define K_GP_RTHUMB_UP 836 -#define K_GP_RTHUMB_DOWN 837 -#define K_GP_RTHUMB_LEFT 838 -#define K_GP_RTHUMB_RIGHT 839 +const float K_TAB = 9; +const float K_ENTER = 13; +const float K_ESCAPE = 27; +const float K_SPACE = 32; +const float K_BACKSPACE = 127; +const float K_UPARROW = 128; +const float K_DOWNARROW = 129; +const float K_LEFTARROW = 130; +const float K_RIGHTARROW = 131; +const float K_LALT = 132; +const float K_RALT = -280; +const float K_LCTRL = 133; +const float K_RCTRL = -281; +const float K_LSHIFT = 134; +const float K_RSHIFT = -282; +const float K_F1 = 135; +const float K_F2 = 136; +const float K_F3 = 137; +const float K_F4 = 138; +const float K_F5 = 139; +const float K_F6 = 140; +const float K_F7 = 141; +const float K_F8 = 142; +const float K_F9 = 143; +const float K_F10 = 144; +const float K_F11 = 145; +const float K_F12 = 146; +const float K_INS = 147; +const float K_DEL = 148; +const float K_PGDN = 149; +const float K_PGUP = 150; +const float K_HOME = 151; +const float K_END = 152; +const float K_KP_HOME = 164; +const float K_KP_UPARROW = 165; +const float K_KP_PGUP = 166; +const float K_KP_LEFTARROW = 161; +const float K_KP_5 = 162; +const float K_KP_RIGHTARROW = 163; +const float K_KP_END = 158; +const float K_KP_DOWNARROW = 159; +const float K_KP_PGDN = 160; +const float K_KP_ENTER = 172; +const float K_KP_INS = 157; +const float K_KP_DEL = 167; +const float K_KP_SLASH = 168; +const float K_KP_MINUS = 170; +const float K_KP_PLUS = 171; +const float K_KP_NUMLOCK = 154; +const float K_KP_STAR = 169; +const float K_KP_EQUALS = 173; +const float K_MOUSE1 = 512; +const float K_MOUSE2 = 513; +const float K_MOUSE3 = 514; +const float K_MOUSE4 = 517; +const float K_MOUSE5 = 518; +const float K_MOUSE6 = 519; +const float K_MOUSE7 = 520; +const float K_MOUSE8 = 521; +const float K_MOUSE9 = 522; +const float K_MOUSE10 = 523; +const float K_MWHEELUP = 515; +const float K_MWHEELDOWN = 516; +const float K_LWIN = -274; +const float K_RWIN = -275; +const float K_APP = -276; +const float K_SEARCH = -277; +const float K_POWER = -130; +const float K_VOLUP = -278; +const float K_VOLDOWN = -279; +const float K_JOY1 = 768; +const float K_JOY2 = 769; +const float K_JOY3 = 770; +const float K_JOY4 = 771; +const float K_JOY5 = 772; +const float K_JOY6 = 773; +const float K_JOY7 = 774; +const float K_JOY8 = 775; +const float K_JOY9 = 776; +const float K_JOY10 = 777; +const float K_JOY11 = 778; +const float K_JOY12 = 779; +const float K_JOY13 = 780; +const float K_JOY14 = 781; +const float K_JOY15 = 782; +const float K_JOY16 = 783; +const float K_JOY17 = 784; +const float K_JOY18 = 785; +const float K_JOY19 = 786; +const float K_JOY20 = 787; +const float K_JOY21 = 788; +const float K_JOY22 = 789; +const float K_JOY23 = 790; +const float K_JOY24 = 791; +const float K_JOY25 = 792; +const float K_JOY26 = 793; +const float K_JOY27 = 794; +const float K_JOY28 = 795; +const float K_JOY29 = 796; +const float K_JOY30 = 797; +const float K_JOY31 = 798; +const float K_JOY32 = 799; +const float K_AUX1 = 800; +const float K_AUX2 = 801; +const float K_AUX3 = 802; +const float K_AUX4 = 803; +const float K_AUX5 = 804; +const float K_AUX6 = 805; +const float K_AUX7 = 806; +const float K_AUX8 = 807; +const float K_AUX9 = 808; +const float K_AUX10 = 809; +const float K_AUX11 = 810; +const float K_AUX12 = 811; +const float K_AUX13 = 812; +const float K_AUX14 = 813; +const float K_AUX15 = 814; +const float K_AUX16 = 815; +const float K_PAUSE = 153; +const float K_PRINTSCREEN = 174; +const float K_CAPSLOCK = 155; +const float K_SCROLLLOCK = 156; +const float K_SEMICOLON = 59; +const float K_PLUS = 43; +const float K_MINUS = 45; +const float K_APOSTROPHE = 39; +const float K_QUOTES = 34; +const float K_TILDE = 126; +const float K_BACKQUOTE = 96; +const float K_BACKSLASH = 92; +const float K_GP_A = 826; +const float K_GP_B = 827; +const float K_GP_X = 828; +const float K_GP_Y = 829; +const float K_GP_LSHOULDER = 824; +const float K_GP_RSHOULDER = 825; +const float K_GP_LTRIGGER = 830; +const float K_GP_RTRIGGER = 831; +const float K_GP_BACK = 821; +const float K_GP_START = 820; +const float K_GP_LTHUMB = 822; +const float K_GP_RTHUMB = 823; +const float K_GP_DPAD_UP = 816; +const float K_GP_DPAD_DOWN = 817; +const float K_GP_DPAD_LEFT = 818; +const float K_GP_DPAD_RIGHT = 819; +const float K_GP_GUIDE = -238; +const float K_GP_SHARE = -248; +const float K_GP_PADDLE1 = -249; +const float K_GP_PADDLE2 = -250; +const float K_GP_PADDLE3 = -251; +const float K_GP_PADDLE4 = -252; +const float K_GP_TOUCHPAD = -253; +const float K_GP_UNKNOWN = -264; +const float K_GP_LTHUMB_UP = 832; +const float K_GP_LTHUMB_DOWN = 833; +const float K_GP_LTHUMB_LEFT = 834; +const float K_GP_LTHUMB_RIGHT = 835; +const float K_GP_RTHUMB_UP = 836; +const float K_GP_RTHUMB_DOWN = 837; +const float K_GP_RTHUMB_LEFT = 838; +const float K_GP_RTHUMB_RIGHT = 839; #endif #ifdef _ACCESSORS accessor strbuf : float @@ -3196,7 +3815,7 @@ accessor hashtable : float accessor infostring : string { get string[string] = infoget; - inline seti& string[string fld] = {this = infoadd(this, fld, value);}; + inline set& string[string fld] = {this = infoadd(this, fld, value);}; }; accessor filestream : float { @@ -3204,4 +3823,18 @@ accessor filestream : float inline set string = {fputs(this,value);}; }; #endif +accessor jsonnode : json_t +{ + inline get json_type_e type = json_get_value_type; + inline get string s = json_get_string; + inline get float f = json_get_float; + inline get __int i = json_get_integer; + inline get __int length = json_get_length; + inline get jsonnode a[__int key] = json_get_child_at_index; + inline get jsonnode[string key] = json_find_object_child; + inline get string name = json_get_name; +}; +#undef DEP_CSQC +#undef FTEDEP +#undef DEP #pragma noref 0 diff --git a/ssqc/admin.qc b/ssqc/admin.qc index c1c7c9b7..bd56df78 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -8,26 +8,26 @@ void () Admin_CountPlayers = { nump = TeamFortress_GetNoPlayers(); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in game: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in game: ", st, "\n"); if (number_of_teams > 0) { nump = TeamFortress_TeamGetNoPlayers(1); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in blue team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in blue team: ", st, "\n"); } if (number_of_teams > 1) { nump = TeamFortress_TeamGetNoPlayers(2); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in red team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in red team: ", st, "\n"); } if (number_of_teams > 2) { nump = TeamFortress_TeamGetNoPlayers(3); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in yellow team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in yellow team: ", st, "\n"); } if (number_of_teams > 3) { nump = TeamFortress_TeamGetNoPlayers(4); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in green team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in green team: ", st, "\n"); } }; @@ -103,21 +103,21 @@ void () Admin_CycleDeal = { }; void () Admin_DoKick = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was kicked by ", self.netname, "\n"); + bprint(PRINT_HIGH, self.admin_use.netname, " was kicked by ", self.netname, "\n"); KickCheater(self.admin_use); self.admin_mode = 0; self.admin_use = world; }; void () Admin_DoBan = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was banned by ", self.netname, "\n"); + bprint(PRINT_HIGH, self.admin_use.netname, " was banned by ", self.netname, "\n"); BanCheater(self.admin_use); self.admin_mode = 0; self.admin_use = world; }; void () Admin_ForceSpectator = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); + bprint(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); clientcommand(self.admin_use, "observe"); self.admin_mode = 0; self.admin_use = world; @@ -195,10 +195,10 @@ void () Admin_Pause = { pause_actor = self.netname; if (cb_prematch && is_countdown) { StopTimer(); - bprint2(2, pause_actor, " stops the countdown\n"); + bprint(2, pause_actor, " stops the countdown\n"); return; } - bprint2(2, pause_actor, " paused the game\n"); + bprint(2, pause_actor, " paused the game\n"); } else { if (cb_prematch) { @@ -213,11 +213,11 @@ void () Admin_Pause = { } pause_actor = self.netname; if (!unpause_requested) { - bprint2(2, pause_actor, " has requested to unpause the game in 5 seconds\n"); + bprint(2, pause_actor, " has requested to unpause the game in 5 seconds\n"); unpause_requested = 1; } else { - bprint2(2, pause_actor, " cancels unpause request\n"); + bprint(2, pause_actor, " cancels unpause request\n"); unpause_requested = 0; unpause_countdown = 0; unpause_lastcountnumber = 0; @@ -230,7 +230,7 @@ void (entity p) CheckAutoKick = { local entity te; if ((p.teamkills >= autokick_kills) && (autokick_kills != 0)) { - bprint2(PRINT_HIGH, p.netname, + bprint(PRINT_HIGH, p.netname, " was kicked for killing teammates\n"); sprint(p, PRINT_HIGH, "You were kicked for killing teammates\n"); KickCheater(p); @@ -274,7 +274,7 @@ void (string cl_pwd) Admin_Check = if (st2 != string_null && cl_pwd == st2) { self.is_admin = TRUE; forceinfokey(self,"*admin", ftos(self.is_admin)); - bprint2(2, self.netname, "\s gains full admin status!\s\n"); + bprint(2, self.netname, "\s gains full admin status!\s\n"); sprint(self, 2, "Type \scmd list\s for admin commands.\n"); sprint(self, 2, "You can also use the \sadminmenu\s command for adjusting some settings.\n"); } diff --git a/ssqc/camera.qc b/ssqc/camera.qc index 5540fd6e..06f9b07e 100644 --- a/ssqc/camera.qc +++ b/ssqc/camera.qc @@ -6,7 +6,7 @@ void () CamLock = { te = find(world, netname, self.netname); while (te) { if (te != self) { - sprint3(self, PRINT_HIGH, "Locked onto ", te.netname, + sprint(self, PRINT_HIGH, "Locked onto ", te.netname, "\n"); self.enemy = te; self.heat = vlen((self.enemy.origin - self.origin)); @@ -14,7 +14,7 @@ void () CamLock = { te = find(te, netname, self.netname); } if (self.enemy == world) - sprint2(self, PRINT_HIGH, te.netname, " not found\n"); + sprint(self, PRINT_HIGH, te.netname, " not found\n"); } else { sprint(self, PRINT_HIGH, "Removed lock\n"); self.enemy = world; @@ -242,7 +242,7 @@ void () CamDrop = { } prevte.camera_list = cam; st = ftos(tf); - sprint3(self, PRINT_HIGH, "Camera ", st, " dropped\n"); + sprint(self, PRINT_HIGH, "Camera ", st, " dropped\n"); }; void () fadetoblack = { diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 1662ef1a..05a784eb 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -31,7 +31,7 @@ void () MatchThink = if (!self.cnt2) { if (self.cnt == 1 || self.cnt == 5) { tmp = ftos (self.cnt); - bprint3(2, Q"\s[\s", tmp, "\s]\s minute"); + bprint(2, Q"\s[\s", tmp, "\s]\s minute"); if (self.cnt != 1) { bprint(2, "s"); } @@ -46,7 +46,7 @@ void () MatchThink = } if (!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= 10))) { tmp = ftos(self.cnt2); - bprint3(2, Q"\s[\s", tmp, "\s]\s second"); + bprint(2, Q"\s[\s", tmp, "\s]\s second"); if (self.cnt2 != 1) { bprint(2, "s"); } @@ -207,7 +207,7 @@ string () GetPlayersName if (strlen(plname) <= 13) { st = strcat( st, plname ); } else { - st = strcat( st, substr(plname,0,12)); + st = strcat( st, substring(plname,0,12)); } } te = find (te, classname, "player"); @@ -229,19 +229,8 @@ string () GetGameFileName = { i = 0; t = find (world, classname, "prematch"); if (t != world) - { - calltimeofday (); - str = strcat(str, tod_year); // year - str = strcat(str, "-"); - str = strcat(str, tod_mon); // month - str = strcat(str, "-"); - str = strcat(str, tod_day); // day - str = strcat(str, "_"); - str = strcat(str, tod_hour); // hour - str = strcat(str, "-"); - str = strcat(str, tod_min); // minute - str = strcat(str, "-"); - str = strcat(str, tod_sec); // second + { + str = strftime(TRUE, "%Y-%m-%d-%H-%M-%S"); } str = strcat(str, "_["); str = strcat(str, mapname); @@ -312,7 +301,7 @@ void () PreMatch_Think = { fl = (self.cnt2 / 60); if (fl == 1 || fl == 2 || fl == 3 || fl == 4 || fl == 5 || fl == 6 || fl == 7 || fl == 8 || fl == 9 || fl == 10) { num = ftos(fl); - bprint3(2, "Match will begin in ", num, " minute(s).\n"); + bprint(2, "Match will begin in ", num, " minute(s).\n"); } if (self.cnt2 == 30) { num = ftos(self.cnt2 / 60); @@ -326,7 +315,6 @@ void () PreMatch_Think = { localcmd("cancel\n"); if (stof(infokey(world, "demo_auto_left")) > 0) { if (infokey(world, "serverdemo") == "on") { - calltimeofday(); localcmd("record \""); str = strzone(GetGameFileName()); @@ -360,7 +348,7 @@ void () PreMatch_Think = { p = find(p, classname, "player"); } if (self.cnt2 > 1) { - bprint2(2, num, " seconds \n"); + bprint(2, num, " seconds \n"); } else { bprint(2, "1 second \n"); @@ -584,9 +572,9 @@ void () DumpClanScores = { if ((winners != 2) && (t2_pl != 0)) { st = GetTeamName(2); if (printed == no_teams) { - bprint2(PRINT_HIGH, " and ", st); + bprint(PRINT_HIGH, " and ", st); } else if (printed) { - bprint2(PRINT_HIGH, ", ", st); + bprint(PRINT_HIGH, ", ", st); } else { bprint(PRINT_HIGH, st); } @@ -595,9 +583,9 @@ void () DumpClanScores = { if ((winners != 3) && (t3_pl != 0)) { st = GetTeamName(3); if (printed == no_teams) { - bprint2(PRINT_HIGH, " and ", st); + bprint(PRINT_HIGH, " and ", st); } else if (printed) { - bprint2(PRINT_HIGH, ", ", st); + bprint(PRINT_HIGH, ", ", st); } else { bprint(PRINT_HIGH, st); } @@ -606,9 +594,9 @@ void () DumpClanScores = { if ((winners != 4) && (t4_pl != 0)) { st = GetTeamName(4); if (printed == no_teams) { - bprint2(PRINT_HIGH, " and ", st); + bprint(PRINT_HIGH, " and ", st); } else if (printed) { - bprint2(PRINT_HIGH, ", ", st); + bprint(PRINT_HIGH, ", ", st); } else { bprint(PRINT_HIGH, st); } @@ -773,49 +761,49 @@ void () DumpClanScores = { bprint(PRINT_HIGH, "\n=------= Blue team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(1); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team1frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t1_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team1score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } if (t2_pl > 0) { bprint(PRINT_HIGH, "\n=------= Red team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(2); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team2frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t2_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team2score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } if (t3_pl > 0) { bprint(PRINT_HIGH, "\n=------= Yellow team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(3); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team3frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t3_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team3score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } if (t4_pl > 0) { bprint(PRINT_HIGH, "\n=------= Green team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(4); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team4frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t4_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team4score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } te = find(world, classname, "player"); while (te) { @@ -866,7 +854,7 @@ void () TeamFortress_ShowIDs = { if (te.team_no == self.team_no) { got_one = 1; st = ftos(te.tf_id); - sprint2(self, 2, st, "\n"); + sprint(self, 2, st, "\n"); } te = find(te, classname, "ghost"); } @@ -951,7 +939,7 @@ void () PlayerNotReady = { if (self.stat_flags & PLAYER_READY) { self.stat_flags &= ~PLAYER_READY; UpdateReadyStatus(); - bprint2 (2, self.netname, " is NOT ready anymore\n "); + bprint (2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); Broadcast_Players_NotReady(); } @@ -1134,21 +1122,21 @@ void () PlayerReady = { self.stat_flags |= PLAYER_READY; UpdateReadyStatus(); v_ready = v_ready + 1; - bprint2 (3, self.netname, " is ready to start the match\n"); + bprint (3, self.netname, " is ready to start the match\n"); if(!CheckAllPlayersReady()) Broadcast_Players_NotReady(); }; void () RemoveVotes = { if (self.bvote) { - bprint2(2, self.netname, " \swithdraws\s his/her vote\n"); + bprint(2, self.netname, " \swithdraws\s his/her vote\n"); self.bvote = 0; v_break = (v_break - 1); } if (self.stat_flags & PLAYER_READY) { self.stat_flags &= ~PLAYER_READY; UpdateReadyStatus(); - bprint2(2, self.netname, " is NOT ready anymore\n "); + bprint(2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); } }; diff --git a/ssqc/client.qc b/ssqc/client.qc index 90194714..a4a3c1be 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3031,7 +3031,8 @@ void () UpdateAllClientsTeamScores = { } //do not rely on csqcactive - it may misbehave when using `join` from spectator -void (optional float csqcactive) ClientConnect = { +void () ClientConnect = { + local float csqc_active = infokeyf(self, INFOKEY_P_CSQCACTIVE); local string st; local float got_one; @@ -3190,7 +3191,7 @@ void () ClientDisconnect = { LogEventChangeClass(self, self.playerclass, 0, timeplayed); self.classtime = gametime; - bprint4(PRINT_HIGH, self.netname, " left the game with ", st, + bprint(PRINT_HIGH, self.netname, " left the game with ", st, " frags\n"); FO_Sound(self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE); self.has_disconnected = 1; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index afb000eb..a40dec71 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1099,7 +1099,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { ent = find(world, classname, "player"); while(ent) { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { - bprint4(PRINT_HIGH, ent, " was banned by ", self.netname, ".\n"); + bprint(PRINT_HIGH, ent.netname, " was banned by ", self.netname, ".\n"); localcmd("addip "); localcmd(infokey(ent, INFOKEY_P_IP)); localcmd("\n"); @@ -1122,7 +1122,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { ent = find(world, classname, "player"); while(ent) { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { - bprint4(PRINT_HIGH, ent.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); + bprint(PRINT_HIGH, ent.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); clientcommand(ent, "observe"); break; } diff --git a/ssqc/debug.qc b/ssqc/debug.qc index 4f08d052..2c6ff206 100644 --- a/ssqc/debug.qc +++ b/ssqc/debug.qc @@ -20,8 +20,8 @@ void () display_location = { local string st; st = vtos(self.origin); - sprint3(self, PRINT_HIGH, "Location : ", st, "\n"); + sprint(self, PRINT_HIGH, "Location : ", st, "\n"); st = vtos(self.angles); - sprint3(self, PRINT_HIGH, "Angles : ", st, "\n"); + sprint(self, PRINT_HIGH, "Angles : ", st, "\n"); }; diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 74a1c518..50c45bca 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -311,131 +311,10 @@ float rj; //=========================================================================== // builtin functions // -void (vector ang) makevectors = #1; // sets v_forward, etc globals -void (entity e, vector o) setorigin = #2; -void (entity e, string m) setmodel = #3; // set movetype and solid first -void (entity e, vector min, vector max) setsize = #4; -// #5 was removed -// #6 was removed (was: break) -float () random = #7; // returns 0 - 1 -//void (entity e, float chan, string samp, float vol, float atten) sound = #8; -vector(vector v) normalize = #9; -void (string e) error = #10; -void (string e) objerror = #11; -float (vector v) vlen = #12; -//float (vector v) vectoyaw = #13; -entity()spawn = #14; -void (entity e) remove = #15; - -// sets trace_* globals -// nomonsters can be: -// An entity will also be ignored for testing if forent == test, -// forent->owner == test, or test->owner == forent -// a forent of world is ignored -void (vector v1, vector v2, float nomonsters, entity forent) traceline = #16; - -entity()checkclient = #17; // returns a client to look for -entity(entity start,.string fld, string match) find = #18; -string(string s) precache_sound = #19; -string(string s) precache_model = #20; -void (entity client, string s) stuffcmd = #21; -//entity(vector org, float rad) findradius = #22; -//void (...) bprint = #23; -void (...) bprint2 = #23; -void (...) bprint3 = #23; -void (...) bprint4 = #23; -//void (...) sprint = #24; -void (...) sprint2 = #24; -void (...) sprint3 = #24; -//void (...) dprint = #25; -string(float f) ftos = #26; -string(vector v) vtos = #27; -void () coredump = #28; // prints all edicts -void () traceon = #29; // turns statment trace on -void () traceoff = #30; -void (entity e) eprint = #31; // prints an entire edict -//float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE -// #33 was removed -float () droptofloor = #34; // TRUE if landed on floor -//void (float style, string value) lightstyle = #35; -float (float v) rint = #36; // round to nearest int -float (float v) floor = #37; // largest integer <= v -float (float v) ceil = #38; // smallest integer >= v -// #39 was removed -float (entity e) checkbottom = #40; // true if self is on ground -float (vector v) pointcontents = #41; // returns a CONTENT_* -// #42 was removed -float (float f) fabs = #43; -vector(entity e, float speed) aim = #44; // returns the shooting vector -float (string s) cvar = #45; // return cvar.value -void (string s) localcmd = #46; // put string into local que -entity(entity e) nextent = #47; // for looping through all ents -void (vector o, vector d, float color, float count) particle = #48; -void () ChangeYaw = #49; // turn towards self.ideal_yaw - // at self.yaw_speed -// #50 was removed -//vector(vector v) vectoangles = #51; -// -// direct client message generation -// -void (float to, float f) WriteByte = #52; -void (float to, float f) WriteChar = #53; -void (float to, float f) WriteShort = #54; -void (float to, float f) WriteLong = #55; -void (float to, float f) WriteCoord = #56; -void (float to, float f) WriteAngle = #57; -void (float to, string s) WriteString = #58; -void (float to, entity s) WriteEntity = #59; - -// several removed - -void (float step) movetogoal = #67; - -string(string s) precache_file = #68; // no effect except for -copy -void (entity e) makestatic = #69; -//void (string s) changelevel = #70; - -//#71 was removed - -void (string var, string val) cvar_set = #72; // sets cvar.value - -//void (...) centerprint = #73; // sprint, but in middle - -void (vector pos, string samp, float vol, float atten) ambientsound = #74; - -string(string s) precache_model2 = #75; // registered version only -string(string s) precache_sound2 = #76; // registered version only -string(string s) precache_file2 = #77; // registered version only - -void (entity e) setspawnparms = #78; // set parm1... to the - // values at level start - // for coop respawn -void (entity killer, entity killee) logfrag = #79; // add to stats - -string(entity e, string key) infokey = #80; // get a key value (world = serverinfo) -float (string s) stof = #81; // convert string to float -void (vector where, float set) multicast = #82; // sends the temp message to a set - // of clients, possibly in PVS or PHS - -//void(string str) tokenize = #84; // tokenize text float() argc = #85; // returns number of tokens string(float num) argv_mvdsv = #86; // returns token for the given number -float (float a, float b, ...) min = #94; -float (float a, float b, ...) max = #95; -float (float min, float value, float max) bound = #96; -float (float x, float y) pow = #97; - -float (string s) strlen = #114; -//string (string s1, string s2) strcat = #115; -string (string s, float start, float count) substr = #116; -string (string s, ...) strzone = #118; -//void (string s, ...) strunzone = #119; - -void() calltimeofday = #231; // force server to call mod function timeofday - - //In order to make it more useful, this header includes a timeofday function which just grabs the values for you to use in your qc code straight after calling calltimeofday. string tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; diff --git a/ssqc/events.qc b/ssqc/events.qc index d2e7c761..88cc143a 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -36,7 +36,7 @@ string (entity pl) getEntityNameOrLogin = { void (string evt) logevent = { local string st = infokey (world, "event_debug"); if (stof(st) > 0) { - bprint2(PRINT_HIGH, evt, "\n"); + bprint(PRINT_HIGH, evt, "\n"); } fputs(logfilehandle, evt); } diff --git a/ssqc/login.qc b/ssqc/login.qc index 887dfb1b..36faf1f3 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -12,57 +12,3 @@ void (entity player, string login, string secret) performLogin = { dprint(login); dprint("\n"); } - -void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { - local float got_one = 0; - self.login_in_progress = 0; - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if (!responsecode) { - float num_args = tokenizebyseparator(resourcebody,";"); - self.login = argv(0); - forceinfokey(self,"*login", self.login); - bprint(2, infokey(self,"name")); - bprint(2, " has logged in as \s"); - bprint(2, self.login); - bprint(2, "\s\n"); - dprint(infokey(self,"name")); - dprint(" logged in as "); - dprint(self.login); - dprint("\n"); - CenterPrint3(self, "You have logged in as ", self.login, "\n"); - if (num_args > 1) { - if (argv(1) == "true") { - self.is_admin = TRUE; - forceinfokey(self,"*admin", ftos(self.is_admin)); - Admin_Aliases (); - bprint2 (2, self.netname, " \sgains full admin status!\s\n"); -// bprint (3, "\n"); - sprint (self, 2, "Type \scommands\s for admin commands.\n"); - } - } - if(self.team_no == 0 && !intermission_running) { - if (clanbattle && (self.has_disconnected != 1)) { - if (self.tf_id != 0) { - got_one = RejoinWithTfId(); - ResetAndRespawnPlayer(self); - } - if (!got_one) { - CreateTfIdAndJoin(); - } - } - if (!got_one) { - if (csqcactive) - Menu_Team(0); - else - Menu_Team(1); - } - } - } - else { - dprint(infokey(self,"name")); - dprint(" login failed: "); - dprint(self.login); - dprint("\n"); - CenterPrint3(self, ftos(responsecode), " - Login FAILED, invalid Login/Secret", "\n"); - } -} diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 33541b7b..d999ecfa 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1421,7 +1421,7 @@ void () Menu_Admin = s_menu2 = strcat( s_menu2, te.netname ); } else { - s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + s_menu2 = strcat( s_menu2, substring(te.netname,0,25)); } s_menu2 = Menu_Indent_line(s_menu2, 30); } @@ -1446,7 +1446,7 @@ void () Menu_Admin = s_menu2 = strcat( s_menu2, te.netname ); } else { - s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + s_menu2 = strcat( s_menu2, substring(te.netname,0,25)); } s_menu2 = Menu_Indent_line(s_menu2, 30); } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 63a3c75a..072f5474 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -216,7 +216,7 @@ void () QuadRoundThink = { if (!self.cnt2) { if ((self.cnt == 1) || (self.cnt == 5)) { tmp = ftos (self.cnt); - bprint3(2, "\s[\s", tmp, "\s]\s minute"); + bprint(2, "\s[\s", tmp, "\s]\s minute"); if (self.cnt != 1) bprint(2, "s"); bprint(2, " remaining\n"); @@ -238,7 +238,7 @@ void () QuadRoundThink = { fl = ceil (self.cnt2); if (!(fl - self.cnt2)) { tmp = ftos(self.cnt2); - bprint3(2, "\s[\s", tmp, "\s]\s second"); + bprint(2, "\s[\s", tmp, "\s]\s second"); if ((self.cnt2 != 1)) bprint(2, "s"); bprint(2, " remaining\n"); @@ -455,8 +455,8 @@ void () StartQuadRound = } bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); - bprint2(2, "map will auto-restart in ", ftos(map_restart_time)); - bprint2(2, " seconds\n"); + bprint(2, "map will auto-restart in ", ftos(map_restart_time)); + bprint(2, " seconds\n"); if (!clan_scores_dumped) { DumpClanScores(); MapEndSequence(); diff --git a/ssqc/status.qc b/ssqc/status.qc index c46a5b69..d5a47aff 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -513,7 +513,7 @@ void (entity pl, string...count) Status_Print = lines = 0; for (i = 0; i < len; i++) - if (substr(pl.StatusString, i, 1) == "\n") + if (substring(pl.StatusString, i, 1) == "\n") lines++; pl.StatusStringLines = lines; @@ -539,7 +539,7 @@ void (entity pl, f_void_float func, string...count) Status_Menu = lines = 0; for (i = 0; i < len; i++) - if (substr(pl.StatusString, i, 1) == "\n") + if (substring(pl.StatusString, i, 1) == "\n") lines++; pl.StatusStringLines = lines; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 67a03042..f20bc048 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -75,7 +75,7 @@ void () UseSpecialSkill = { src_z = self.absmin_z + self.size_z * 0.7; traceline(src, src + v_forward * 2048, 0, self); if ((trace_ent != world) && (trace_ent.origin != world.origin)) { - sprint3(self, PRINT_HIGH, "Locked onto ", + sprint(self, PRINT_HIGH, "Locked onto ", trace_ent.classname, "\n"); self.enemy = trace_ent; self.camdist = vlen(self.enemy.origin - self.origin); @@ -3053,45 +3053,45 @@ void () TeamFortress_ExplodePerson = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.owner.origin); if ((self.owner.playerclass == PC_SCOUT) && (self.weapon != 10)) - bprint3(PRINT_MEDIUM, "No ", self.owner.netname, + bprint(PRINT_MEDIUM, "No ", self.owner.netname, ", swallowing the grenade isn't very effective!\n"); else if (self.owner.playerclass == PC_SNIPER) - bprint3(PRINT_MEDIUM, "Well ", self.owner.netname, + bprint(PRINT_MEDIUM, "Well ", self.owner.netname, ", don't quit your day job!\n"); else if (self.owner.playerclass == PC_SOLDIER) - bprint3(PRINT_MEDIUM, "Ummm, ", self.owner.netname, + bprint(PRINT_MEDIUM, "Ummm, ", self.owner.netname, ", you're supposed to THROW the grenade!\n"); else if (self.owner.playerclass == PC_DEMOMAN) - bprint3(PRINT_MEDIUM, "Ack! ", self.owner.netname, + bprint(PRINT_MEDIUM, "Ack! ", self.owner.netname, "! The grenade is your friend for another reason!\n"); else if (self.owner.playerclass == PC_MEDIC) { if (self.weapon == GR_TYPE_BLAST) { if (medic_type == MEDIC_TYPE_BLAST) { - bprint3(PRINT_MEDIUM, "Nice one ", self.owner.netname, + bprint(PRINT_MEDIUM, "Nice one ", self.owner.netname, ", you forgot to throw your blast grenade!\n"); } else { - bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, + bprint(PRINT_MEDIUM, "Yes ", self.owner.netname, ", eating a concussion grenade is bad!\n"); } } else { - bprint3(PRINT_MEDIUM, "No ", self.owner.netname, + bprint(PRINT_MEDIUM, "No ", self.owner.netname, "! Assist your own suicide some other time!\n"); } } else if (self.owner.playerclass == PC_HVYWEAP) - bprint3(PRINT_MEDIUM, "Hey ", self.owner.netname, + bprint(PRINT_MEDIUM, "Hey ", self.owner.netname, ", you're not THAT heavy!\n"); else if (self.owner.playerclass == PC_PYRO) - bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, + bprint(PRINT_MEDIUM, "Yes ", self.owner.netname, ", the grenade does explode on '3'!\n"); else if (self.owner.playerclass == PC_SPY) - bprint3(PRINT_MEDIUM, "You do realize ", self.owner.netname, + bprint(PRINT_MEDIUM, "You do realize ", self.owner.netname, ", you can blow your cover in easier ways!\n"); else if (self.owner.playerclass == PC_ENGINEER) - bprint3(PRINT_MEDIUM, "Hey ", self.owner.netname, + bprint(PRINT_MEDIUM, "Hey ", self.owner.netname, ", study grenade dynamics on your own time!\n"); else - bprint3(PRINT_MEDIUM, "No ", self.owner.netname, + bprint(PRINT_MEDIUM, "No ", self.owner.netname, ", throw the grenade, not the pin!\n"); dremove(self); @@ -3252,7 +3252,7 @@ void () TeamFortress_CheckforCheats = { } if (self.owner.cheat_level > 1200) { self.owner.cheat_level = 0; - bprint2(PRINT_MEDIUM, self.owner.netname, + bprint(PRINT_MEDIUM, self.owner.netname, " has been kicked for cheating\n"); sprint(self.owner, PRINT_HIGH, "You have been kicked for cheating, because of your speed\n"); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index d7b1ea41..cbc7d017 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -342,7 +342,7 @@ void () TeamFortress_CheckTeamCheats = { sk = TeamFortress_GetSkin(self.team_no, self.playerclass); if (st != sk) { TeamFortress_SetSkin(self); - bprint2(PRINT_MEDIUM, self.netname, + bprint(PRINT_MEDIUM, self.netname, " has been kicked for changing skin\n"); sprint(self, PRINT_HIGH, "You have been kicked for changing your skin\n"); @@ -354,7 +354,7 @@ void () TeamFortress_CheckTeamCheats = { st = GetTeamName(self.team_no); if (st != infokey(self, "team")) { SetTeamName(self); - bprint2(PRINT_MEDIUM, self.netname, + bprint(PRINT_MEDIUM, self.netname, " has been kicked for changing team\n"); sprint(self, PRINT_HIGH, "You have been kicked for changing your team\n"); diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 0edd71fd..4ce9edbd 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1043,7 +1043,7 @@ float (string ps_list) List_Count = { for (i = 0; i < f_length; i++) { // set current character - local string s_current = substr(ps_list, i, 1); + local string s_current = substring(ps_list, i, 1); // non-empty space => word if (s_current != " " && s_previous == " ") @@ -1066,7 +1066,7 @@ string (string ps_list, float pf_idx) List_Index = { for (i = 0; i < f_length; i++) { // set current character - local string s_current = substr(ps_list, i, 1); + local string s_current = substring(ps_list, i, 1); // non-empty space => start of word if (s_current != " " && s_previous == " ") { @@ -1077,14 +1077,14 @@ string (string ps_list, float pf_idx) List_Index = { // empty space => end of word if (s_current == " " && f_start > -1) - return strzone(substr(ps_list, f_start, i - f_start)); + return strzone(substring(ps_list, f_start, i - f_start)); s_previous = s_current; } // if f_start is set it means a list item was found if (f_start > -1) - return strzone(substr(ps_list, f_start, i - f_start)); + return strzone(substring(ps_list, f_start, i - f_start)); return strzone(string_null); }; diff --git a/ssqc/world.qc b/ssqc/world.qc index b6c3c8eb..0347b1f5 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -111,8 +111,7 @@ void () worldspawn = { cvar_set("teamplay", "1"); if (infokey(world, "starttime") == string_null) { - calltimeofday(); - string timestamp = strcat(tod_year, tod_mon, tod_day, tod_hour, tod_min, tod_sec); + string timestamp = strftime(FALSE, "%Y%m%d%H%M%S"); localcmd(strcat("serverinfo starttime \"", timestamp, "\"\n")); } From 2a9acbfa78971bc7295c5442a59427bc3c79c87c Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 14 Sep 2022 03:43:41 -0700 Subject: [PATCH 1619/2474] Enable compiler optimization and tuning Basic tests seemed to work on O3, so let's start there and ratchet it down if we have any issues. Also enabled: TARGET fte_5768 [specialize for FTE outputs, allows extended opcodes] subscope [restrict locals to their actual scope] --- csqc/csprogs.src | 9 +- menu/menu.src | 272 ++++++++++++++++++++++++----------------------- ssqc/commands.qc | 2 +- ssqc/progs.src | 13 ++- 4 files changed, 156 insertions(+), 140 deletions(-) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 709a516c..2aa77962 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,4 +1,10 @@ -../csprogs.dat +#pragma target fte_5768 +#pragma optimise 3 +#pragma flag enable subscope + +#pragma progs_dat "../csprogs.dat" + +#includelist csdefs.qc csextradefs.qc @@ -15,3 +21,4 @@ hud_helpers.qc hud.qc settings.qc input.qc +#endlist diff --git a/menu/menu.src b/menu/menu.src index bf25607b..ce60d2ea 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -1,135 +1,137 @@ -#pragma progs_dat "../menu.dat" - -//#pragma target fte - -#define MENU //select the module - -#includelist -../share/fteextensions.qc //also sets up system defs - -../menusys/mitems.qc //root item type -../menusys/mitems_common.qc //basic types -../menusys/mitem_desktop.qc //other sort of root item -../menusys/mitem_exmenu.qc //fullscreen/exclusive menus -../menusys/mitem_edittext.qc //simple text editor -../menusys/mitem_tabs.qc //tabs -../menusys/mitem_colours.qc //colour picker -../menusys/mitem_checkbox.qc //checkbox (boolean thingies) -../menusys/mitem_slider.qc //scrollbars -../menusys/mitem_combo.qc //multiple-choice thingies -../menusys/mitem_bind.qc //key binding thingie -../menusys/mitem_spinnymodel.qc //menu art -#endlist - -//might as well put this here. - -void(mitem_desktop desktop) M_Pop = -{ - mitem it = desktop.item_kactivechild; - if (it) - it.item_remove(); -}; - -//define the commands. -//cmd argments are: Name, Function, Sourcefile(may be empty) -#define concommandslist \ - cmd("m_main", M_Main, main.qc) \ - cmd("m_pop", M_Pop, ) \ - cmd("m_options", M_Options, options.qc) \ - cmd("m_keys", M_Options_Keys, options_keys.qc) \ - cmd("m_basicopts", M_Options_Basic, options_basic.qc) \ - cmd("m_video", M_Options_Video, options_video.qc) \ - cmd("m_effects", M_Options_Effects, options_effects.qc) \ - cmd("m_audio", M_Options_Audio, options_audio.qc) \ - cmd("m_load", M_Load, loadsave.qc) \ - cmd("m_save", M_Save, ) \ - cmd("m_quit", M_Quit, quit.qc) \ - cmd("m_servers", M_Servers, servers.qc) \ - cmd("m_reset", M_Reset, ) - - -#if 0 -#append concommandslist cmd("m_servers", M_Servers, servers.qc) -#define serverbrowser "m_servers" -#else -#define serverbrowser "menu_servers" -#endif - -//make sure all the right files are included -#define cmd(n,fnc,inc) inc -#includelist - concommandslist -#endlist -#undef cmd - -mitem_desktop desktop; -void() m_shutdown = {}; -void(vector screensize) m_draw = {items_draw(desktop);}; -void(float scan, float chr) m_keydown = {items_keypress(desktop, scan, chr, TRUE);}; -void(float scan, float chr) m_keyup = {items_keypress(desktop, scan, chr, FALSE);}; -void(float mode) m_toggle -{ //mode is stupid. 1=enable,0=disable,-1=actually toggle. - if (mode < 0) - mode = !desktop.item_kactivechild; - if (mode) - M_Main(desktop); - else while(desktop.item_kactivechild) - { - mitem it = desktop.item_kactivechild; - if (it.item_flags & IF_NOKILL) - break; - it.item_remove(); - } - - items_updategrabs(TRUE); -}; - -var float autocvar_dp_workarounds_allow = TRUE; -var float autocvar_dp_workarounds_force = FALSE; -void() m_init = -{ - desktop = spawn(mitem_desktop); - - //register the console commands via the alias command. -#define cmd(n,f) localcmd("alias " n " \"menu_cmd " n " $*\"\n"); - concommandslist -#undef cmd - - //work around some dp differences/bugs. - //this check identifies one significant bug in DP. - //if anyone actually cares to fix DP, then there is no reason they cannot do so by just removing DP_QC_RENDERSCENE and then fixing anything else that arises. - if (checkextension("DP_QC_RENDER_SCENE") && !checkextension("DP_CON_SET")) - dp_workarounds = autocvar(dp_workarounds_allow, TRUE); - if (autocvar(dp_workarounds_force, FALSE)) - dp_workarounds = TRUE; - - if (dp_workarounds) - print("^1WORKING AROUND DP BUGS\n"); - - //for compat with DP, 'none' is the default cursor in menuqc. - //naturally this is not ideal. - if (checkextension("FTE_QC_HARDWARECURSORS")) - setcursormode(TRUE, ""); - else - print("No hardware cursors\n"); - - if (clientstate() == 1) //disconnected==1, supposedly - m_toggle(1); -}; -void(string cstr) GameCommand = -{ - tokenize(cstr); - string cmd = argv(0); - - switch(cmd) - { -//switch on the known commands. -#define cmd(n,f) case n: f(desktop); break; - concommandslist -#undef cmd - default: - print("unknown command ", cmd, "\n"); - break; - } - items_updategrabs(TRUE); -}; +#pragma target fte_5768 +#pragma optimise 3 +#pragma flag enable subscope + +#pragma progs_dat "../menu.dat" + +#define MENU //select the module + +#includelist +../share/fteextensions.qc //also sets up system defs + +../menusys/mitems.qc //root item type +../menusys/mitems_common.qc //basic types +../menusys/mitem_desktop.qc //other sort of root item +../menusys/mitem_exmenu.qc //fullscreen/exclusive menus +../menusys/mitem_edittext.qc //simple text editor +../menusys/mitem_tabs.qc //tabs +../menusys/mitem_colours.qc //colour picker +../menusys/mitem_checkbox.qc //checkbox (boolean thingies) +../menusys/mitem_slider.qc //scrollbars +../menusys/mitem_combo.qc //multiple-choice thingies +../menusys/mitem_bind.qc //key binding thingie +../menusys/mitem_spinnymodel.qc //menu art +#endlist + +//might as well put this here. + +void(mitem_desktop desktop) M_Pop = +{ + mitem it = desktop.item_kactivechild; + if (it) + it.item_remove(); +}; + +//define the commands. +//cmd argments are: Name, Function, Sourcefile(may be empty) +#define concommandslist \ + cmd("m_main", M_Main, main.qc) \ + cmd("m_pop", M_Pop, ) \ + cmd("m_options", M_Options, options.qc) \ + cmd("m_keys", M_Options_Keys, options_keys.qc) \ + cmd("m_basicopts", M_Options_Basic, options_basic.qc) \ + cmd("m_video", M_Options_Video, options_video.qc) \ + cmd("m_effects", M_Options_Effects, options_effects.qc) \ + cmd("m_audio", M_Options_Audio, options_audio.qc) \ + cmd("m_load", M_Load, loadsave.qc) \ + cmd("m_save", M_Save, ) \ + cmd("m_quit", M_Quit, quit.qc) \ + cmd("m_servers", M_Servers, servers.qc) \ + cmd("m_reset", M_Reset, ) + + +#if 0 +#append concommandslist cmd("m_servers", M_Servers, servers.qc) +#define serverbrowser "m_servers" +#else +#define serverbrowser "menu_servers" +#endif + +//make sure all the right files are included +#define cmd(n,fnc,inc) inc +#includelist + concommandslist +#endlist +#undef cmd + +mitem_desktop desktop; +void() m_shutdown = {}; +void(vector screensize) m_draw = {items_draw(desktop);}; +void(float scan, float chr) m_keydown = {items_keypress(desktop, scan, chr, TRUE);}; +void(float scan, float chr) m_keyup = {items_keypress(desktop, scan, chr, FALSE);}; +void(float mode) m_toggle +{ //mode is stupid. 1=enable,0=disable,-1=actually toggle. + if (mode < 0) + mode = !desktop.item_kactivechild; + if (mode) + M_Main(desktop); + else while(desktop.item_kactivechild) + { + mitem it = desktop.item_kactivechild; + if (it.item_flags & IF_NOKILL) + break; + it.item_remove(); + } + + items_updategrabs(TRUE); +}; + +var float autocvar_dp_workarounds_allow = TRUE; +var float autocvar_dp_workarounds_force = FALSE; +void() m_init = +{ + desktop = spawn(mitem_desktop); + + //register the console commands via the alias command. +#define cmd(n,f) localcmd("alias " n " \"menu_cmd " n " $*\"\n"); + concommandslist +#undef cmd + + //work around some dp differences/bugs. + //this check identifies one significant bug in DP. + //if anyone actually cares to fix DP, then there is no reason they cannot do so by just removing DP_QC_RENDERSCENE and then fixing anything else that arises. + if (checkextension("DP_QC_RENDER_SCENE") && !checkextension("DP_CON_SET")) + dp_workarounds = autocvar(dp_workarounds_allow, TRUE); + if (autocvar(dp_workarounds_force, FALSE)) + dp_workarounds = TRUE; + + if (dp_workarounds) + print("^1WORKING AROUND DP BUGS\n"); + + //for compat with DP, 'none' is the default cursor in menuqc. + //naturally this is not ideal. + if (checkextension("FTE_QC_HARDWARECURSORS")) + setcursormode(TRUE, ""); + else + print("No hardware cursors\n"); + + if (clientstate() == 1) //disconnected==1, supposedly + m_toggle(1); +}; +void(string cstr) GameCommand = +{ + tokenize(cstr); + string cmd = argv(0); + + switch(cmd) + { +//switch on the known commands. +#define cmd(n,f) case n: f(desktop); break; + concommandslist +#undef cmd + default: + print("unknown command ", cmd, "\n"); + break; + } + items_updategrabs(TRUE); +}; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index fae4b327..afb000eb 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -312,7 +312,7 @@ void () OutputTrackedSettings = { float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; - local float farg3; + local float farg2, farg3; local entity ent, pl; processedCmd = FALSE; diff --git a/ssqc/progs.src b/ssqc/progs.src index 897a99c0..b4c38f88 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -1,6 +1,12 @@ -../qwprogs.dat +#pragma target fte_5768 +#pragma optimise 3 +#pragma flag enable subscope -#define QWSSQC +#pragma progs_dat "../qwprogs.dat" + +#define QWSSQC + +#includelist ../share/fteextensions.qc defs.qc ../share/commondefs.qc @@ -64,4 +70,5 @@ mvdsv.qc rotate.qc fo_logic.qc fo_math.qc -fo_misc_info.qc \ No newline at end of file +fo_misc_info.qc +#endlist From bcfd0b14db8f95fb3c9f9eb26965dd638b34f401 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 15 Sep 2022 00:53:58 -0700 Subject: [PATCH 1620/2474] Fix all compiler warnings There were a lot of existing warnings, and optimization added new ones (since it does things like dead code elimination). Clean them all up. This did include some legitimate bugs such as potential bad references in the menu code and disguise-last-spawn when there is no one on the enemy team. --- csqc/csextradefs.qc | 3 --- csqc/events.qc | 4 ++-- csqc/input.qc | 14 -------------- csqc/main.qc | 2 +- csqc/sui_sys.qc | 3 --- menu/servers.qc | 4 ++-- menusys/mitem_frame.qc | 2 +- menusys/mitem_spinnymodel.qc | 2 ++ menusys/mitems.qc | 2 ++ ssqc/pyro.qc | 2 +- ssqc/spy.qc | 7 ++++++- ssqc/weapons.qc | 4 ++-- 12 files changed, 19 insertions(+), 30 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c1ec3157..1c5e9550 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -93,7 +93,6 @@ float round_over; float round_time_remaining; float showingscores; float mapvote_expiry; -float cs_grenprimed; float num_mapvotes; float num_mapvotes_filtered; entity vote_selected_item; @@ -537,8 +536,6 @@ float is_observer; float oldhealth; float painfinished; vector thisorigin; -vector lastorigin; -float nextoriginupdate; float speed; float jump_counter; float grentimer_waiting; diff --git a/csqc/events.qc b/csqc/events.qc index bc628b59..b68a0390 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -306,9 +306,9 @@ void() CSQC_Parse_Event = { } void PlayGrenTimer(float offset) { - local float channel; + local float channel = CHAN_GREN1; local float soundtime; - local float highest_soundtime; + local float highest_soundtime = -1; for(float i = CHAN_GREN1; i <= CHAN_GREN5; i++) { soundtime = getsoundtime(self, i); diff --git a/csqc/input.qc b/csqc/input.qc index a7310932..9d449e84 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -75,39 +75,31 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { switch (scanx) { case K_ESCAPE: return TRUE; - break; case K_MOUSE1: MouseDown = TRUE; return TRUE; - break; case K_UPARROW: vote_selected_index--; vote_list_offset--; return TRUE; - break; case K_DOWNARROW: vote_selected_index++; vote_list_offset++; return TRUE; - break; case K_PGUP: vote_selected_index -= 10; vote_list_offset -= 10; return TRUE; - break; case K_PGDN: vote_selected_index +=10; vote_list_offset +=10; return TRUE; - break; case K_MWHEELUP: vote_list_offset--; return TRUE; - break; case K_MWHEELDOWN: vote_list_offset++; return TRUE; - break; case K_ENTER: if(vote_selected_item && current_vote == vote_selected_item.owner) { localcmd("cmd break\n"); @@ -115,14 +107,12 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { localcmd("cmd votemap ", vote_selected_item.owner.name, "\n"); } return TRUE; - break; case K_BACKSPACE: if(strlen(vote_list_filter) > 0) { vote_list_filter = substring(vote_list_filter, 0, strlen(vote_list_filter) - 1); ApplyMapFilter(); } return TRUE; - break; case K_DEL: //blank it out if(strlen(vote_list_filter) > 0) { vote_list_filter = ""; @@ -146,11 +136,9 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case K_ESCAPE: showVoteMenu(FALSE); return TRUE; - break; case K_MOUSE1: MouseDown = FALSE; return TRUE; - break; } } } else { @@ -162,7 +150,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case K_ESCAPE: FO_Menu_Game(TRUE); return TRUE; - break; } break; case IE_KEYDOWN: @@ -170,7 +157,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { { case K_ESCAPE: return TRUE; - break; } break; default: diff --git a/csqc/main.qc b/csqc/main.qc index 3ca71a4b..3add1668 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -234,7 +234,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Build(TRUE); break; case "fo_menu_dropammo": - FO_Menu_DropAmmo(TRUE, 1, (player_class == PC_ENGINEER)); + FO_Menu_DropAmmo(TRUE); break; case "fo_menu_cancel": Menu_Cancel(); diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 68243c1a..4e11eaa3 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -640,7 +640,6 @@ float(float evtype, float scanx, float chary, float devid) sui_input_event = case IE_MOUSEABS: _sui_mouse_move([scanx, chary]); return TRUE; - break; case IE_MOUSEDELTA: // Big question mark... // maybe make our own delta based sui_cursor here.. @@ -648,7 +647,6 @@ float(float evtype, float scanx, float chary, float devid) sui_input_event = // delta cursor by passing different params to this func...? // for MVP let's just use mouseabs only return FALSE; - break; case IE_KEYDOWN: if (_sui_binding_command != "") { @@ -668,7 +666,6 @@ float(float evtype, float scanx, float chary, float devid) sui_input_event = return FALSE; return _sui_add_input(chary, scanx); } - break; case IE_KEYUP: if (_sui_binding_command != "") { diff --git a/menu/servers.qc b/menu/servers.qc index c2560c78..8cbb1ccf 100644 --- a/menu/servers.qc +++ b/menu/servers.qc @@ -111,7 +111,7 @@ class mitem_servers : mitem maxsv = slider.val + maxy; float sort = gethostcachevalue(SLIST_SORTFIELD); - string colkey; + string colkey = ""; #define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {if (ui.mousepos[0] > pos_x && ui.mousepos[1] < pos_y+8) colkey = #sortname; pos_x += width+8;} COLUMNS #undef COLUMN @@ -408,4 +408,4 @@ nonstatic void(mitem_desktop desktop) M_Servers = m.add(menuitemcheck_spawn(_("Fraglimit"), "sb_showfraglimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*2], [8*20, -8*1]); m.add(menuitemcheck_spawn(_("Timelimit"), "sb_showtimelimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*1], [8*20, -8*0]); } -}; \ No newline at end of file +}; diff --git a/menusys/mitem_frame.qc b/menusys/mitem_frame.qc index 9a119766..cf93a310 100644 --- a/menusys/mitem_frame.qc +++ b/menusys/mitem_frame.qc @@ -650,7 +650,7 @@ void(vector pos) mitem_frame::item_draw = { ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]); if (item_exclusive) - item_exclusive.item_draw(clientpos + ch.item_position); + item_exclusive.item_draw(clientpos + item_exclusive.item_position); else { for(ch = item_children; ch; ch = ch.item_next) diff --git a/menusys/mitem_spinnymodel.qc b/menusys/mitem_spinnymodel.qc index b52c10af..c59ed59b 100644 --- a/menusys/mitem_spinnymodel.qc +++ b/menusys/mitem_spinnymodel.qc @@ -32,6 +32,7 @@ probably others. it really wouldn't surprise me. //helper function to work around a DP bug. static vector(vector v) vtodpp = { +#pragma warning disable F333 #ifndef CSQC_SIMPLE //so fucking disgustingly ugly. if (dp_workarounds) @@ -41,6 +42,7 @@ static vector(vector v) vtodpp = } #endif return v; +#pragma warning enable F333 }; //make sure the fields are all defined if we're in menuqc or something noref .vector origin; diff --git a/menusys/mitems.qc b/menusys/mitems.qc index 782b580f..ee62af9d 100644 --- a/menusys/mitems.qc +++ b/menusys/mitems.qc @@ -150,6 +150,7 @@ var uiinfo_t ui = void() queryscreensize = { +#pragma warning disable F333 #ifdef MENU //there is no proper way to do this. //fte thus has special checks for these cvars, and they should not be autocvars if you want them to work properly. @@ -172,6 +173,7 @@ void() queryscreensize = } #endif #endif +#pragma warning enable F333 }; //helper function diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 7289f068..6a6a83c7 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -898,7 +898,7 @@ void () UseAirBlastV2 = { vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); vector ab_diameter = ab_start + aim(self,1000) * abrange; - pointparticles(particleeffectnum("fo_airblast"), ab_origin, 1); + pointparticles(particleeffectnum("fo_airblast"), ab_origin, v_forward); if (isabjump) { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 19339d12..4b1a19ad 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -756,7 +756,7 @@ void (entity player) FO_Spy_DisguiseLast = { void (entity player) FO_Spy_DisguiseLastSpawned = { local entity te = find(world, classname, "player"); local float latest_spawn_time = 0; - local entity enemy_to_disguise_as; + local entity enemy_to_disguise_as = world; while (te != world) { if (te.team_no != player.team_no) { @@ -769,6 +769,11 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { te = find(te, classname, "player"); } + if (enemy_to_disguise_as == world) { + sprint(self.owner, PRINT_HIGH, "No enemies to disguise as!\n"); + return; + } + if (self.is_undercover == 2 && enemy_to_disguise_as.skin != player.disguise_skin) { CF_Spy_DisguiseStop(); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fb686118..252fcd4e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3519,7 +3519,7 @@ void () ButtonFrame = { // +grenade1 keyup frame if (keyups & BUTTON5) { if (hold_grens) { - TeamFortress_ThrowGrenade(1); + TeamFortress_ThrowGrenade(); } } @@ -3535,7 +3535,7 @@ void () ButtonFrame = { // +grenade2 keyup frame if (keyups & BUTTON6) { if (hold_grens) { - TeamFortress_ThrowGrenade(2); + TeamFortress_ThrowGrenade(); } } From 0b0ee5065af2cf4c23d353fe39ea90f3cda1a7a8 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 18 Sep 2022 01:46:59 -0700 Subject: [PATCH 1621/2474] - Update to use fte extensions ver 6306 - Removed reprecated API use such as calltimeofday - We preserve dimension_see{,n} since these are used by flash grenades and the unsupported parts (MVD, Splitscreen) we can live with. - Fix minor bug in printing name of banned player. --- csqc/status.qc | 2 +- share/fteextensions.qc | 1513 ++++++++++++++++++++++++++++------------ ssqc/admin.qc | 28 +- ssqc/camera.qc | 6 +- ssqc/clan.qc | 80 +-- ssqc/client.qc | 5 +- ssqc/commands.qc | 4 +- ssqc/debug.qc | 4 +- ssqc/defs.qc | 121 ---- ssqc/events.qc | 2 +- ssqc/login.qc | 54 -- ssqc/menu.qc | 4 +- ssqc/quadmode.qc | 8 +- ssqc/status.qc | 4 +- ssqc/tfort.qc | 28 +- ssqc/tforttm.qc | 4 +- ssqc/vote.qc | 8 +- ssqc/world.qc | 3 +- 18 files changed, 1162 insertions(+), 716 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index a9312c47..b099dc3e 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1159,7 +1159,7 @@ var FO_Hud_Panel Hud_Panels[] = { {"gun6","Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, {"gun7","Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {"gun8","Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, + {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, }; //var FO_Hud_Panel Hud_ExtraPanels[] = { diff --git a/share/fteextensions.qc b/share/fteextensions.qc index 7fc00a9e..a47a9767 100644 --- a/share/fteextensions.qc +++ b/share/fteextensions.qc @@ -1,16 +1,8 @@ /* -This file was automatically generated by FTE Quake v1.06 +This file was generated by FTE Quake 6306, dated 2022-08-19T13:30:16.464410Z. This file can be regenerated by issuing the following command: pr_dumpplatform -o fteextensions -Available options: --Ffte - target only FTE (optimations and additional extensions) --Tnq - dump specifically NQ fields --Tqw - dump specifically QW fields --Tcs - dump specifically CSQC fields --Tmenu - dump specifically menuqc fields --Fdefines - generate #defines instead of constants --Faccessors - use accessors instead of basic types via defines --O - write to a different qc file +(Use the -help arg for a list of available args) */ #pragma noref 1 //#pragma flag enable logicops @@ -18,53 +10,35 @@ Available options: #pragma warning error Q105 /*too few parms. The vanilla qcc didn't validate properly, hence why fteqcc normally treats it as a warning.*/ #pragma warning error Q106 /*assignment to constant/lvalue. Define them as var if you want to initialise something.*/ #pragma warning error Q208 /*system crc unknown. Compatibility goes out of the window if you disable this.*/ -#pragma warning disable F211 /*system crc outdated (eg: dp's csqc). Note that this may trigger emulation.*/ #pragma warning enable F301 /*non-utf-8 strings. Think of the foreigners! Also think of text editors that insist on screwing up your char encodings.*/ #pragma warning enable F302 /*uninitialised locals. They usually default to 0 in qc (except in recursive functions), but its still probably a bug*/ #if !defined(CSQC) && !defined(NQSSQC) && !defined(QWSSQC)&& !defined(MENU) -#ifdef QUAKEWORLD -#define QWSSQC + #ifdef QUAKEWORLD + #define QWSSQC + #else + #define NQSSQC + #endif +#endif +#if !defined(SSQC) && (defined(QWSSQC) || defined(NQSSQC)) + #define SSQC +#endif +#if defined(CSQC) || defined(MENU) + #define DEP_CSQC DEP #else -#define NQSSQC + #define DEP_CSQC __deprecated("Use CSQC for this") #endif +#ifndef DEP + #define DEP __deprecated //predefine this if you want to avoid our deprecation warnings. #endif -#if !defined(SSQC) && (defined(QWSSQC) || defined(NQSSQC)) -#define SSQC +#ifndef FTEDEP + #define FTEDEP(reason) //for symbols deprecated in FTE that may still be useful/required for other engines #endif -#define FTE_PEXT_SETVIEW /* NQ's svc_setview works correctly even in quakeworld */ -#define DP_ENT_SCALE -#define FTE_PEXT_LIGHTSTYLECOL -#define DP_ENT_ALPHA -#define FTE_PEXT_VIEW2 -#define FTE_PEXT_ACURATETIMINGS -#define FTE_PEXT_SOUNDDBL -#define FTE_PEXT_FATNESS -#define DP_HALFLIFE_MAP -#define FTE_PEXT_TE_BULLET -#define FTE_PEXT_HULLSIZE -#define FTE_PEXT_MODELDBL -#define FTE_PEXT_ENTITYDBL -#define FTE_PEXT_ENTITYDBL2 -#define FTE_PEXT_FLOATCOORDS -#define FTE_PEXT_VWEAP -#define FTE_PEXT_Q2BSP -#define FTE_PEXT_Q3BSP -#define DP_ENT_COLORMOD -#define FTE_HEXEN2 -#define FTE_PEXT_SPAWNSTATIC -#define FTE_PEXT_CUSTOMTENTS -#define FTE_PEXT_256PACKETENTITIES -#define TEI_SHOWLMP2 -#define DP_GFX_QUAKE3MODELTAGS -#define FTE_PK3DOWNLOADS -#define PEXT_CHUNKEDDOWNLOADS -#define EXT_CSQC_SHARED -#define PEXT_DPFLAGS -#define EXT_CSQC #define BX_COLOREDTEXT #define DP_CON_SET /* The 'set' console command exists, and can be used to create/set cvars. */ #define DP_CON_SETA /* The 'seta' console command exists, like the 'set' command, but also marks the cvar for archiving, allowing it to be written into the user's config. Use this command in your default.cfg file. */ +#define DP_CSQC_ROTATEMOVES #define DP_EF_ADDITIVE +#define DP_ENT_ALPHA #define DP_EF_BLUE #define DP_EF_FULLBRIGHT #define DP_EF_NODEPTHTEST @@ -72,14 +46,18 @@ Available options: #define DP_EF_NOGUNBOB #define DP_EF_NOSHADOW #define DP_EF_RED +#define DP_ENT_COLORMOD #define DP_ENT_CUSTOMCOLORMAP #define DP_ENT_EXTERIORMODELTOCLIENT +#define DP_ENT_SCALE #define DP_ENT_TRAILEFFECTNUM /* self.traileffectnum=particleeffectnum("myeffectname"); can be used to attach a particle trail to the given server entity. This is equivelent to calling trailparticles each frame. */ #define DP_ENT_VIEWMODEL #define DP_GECKO_SUPPORT #define DP_GFX_FONTS +#define DP_GFX_QUAKE3MODELTAGS #define DP_GFX_SKINFILES #define DP_GFX_SKYBOX +#define DP_HALFLIFE_MAP #define DP_HALFLIFE_MAP_CVAR #define DP_INPUTBUTTONS #define DP_LIGHTSTYLE_STATICVALUE @@ -94,6 +72,7 @@ Available options: #define DP_QC_CVAR_DEFSTRING #define DP_QC_CVAR_STRING #define DP_QC_CVAR_TYPE +#define DP_QC_DIGEST_SHA256 #define DP_QC_EDICT_NUM #define DP_QC_ENTITYDATA #define DP_QC_ETOS @@ -103,9 +82,12 @@ Available options: #define DP_QC_FINDCHAINFLAGS #define DP_QC_FINDFLOAT #define DP_QC_FS_SEARCH +#define DP_QC_FS_SEARCH_PACKFILE +#define DP_QC_GETLIGHT #define DP_QC_GETSURFACE #define DP_QC_GETSURFACEPOINTATTRIBUTE #define DP_QC_GETTAGINFO +#define DP_QC_I18N /* Specifies that the engine uses $MODULE.dat.$LANG.po files that translates the dotranslate_* globals on load - these are usually created via the _("foo") qcc intrinsic. */ #define DP_QC_MINMAXBOUND #define DP_QC_MULTIPLETEMPSTRINGS /* Superseded by DP_QC_UNLIMITEDTEMPSTRINGS. Functions that return a temporary string will not overwrite/destroy previous temporary strings until at least 16 strings are returned (or control returns to the engine). */ #define DP_QC_RANDOMVEC @@ -132,6 +114,7 @@ Available options: #define DP_QC_WHICHPACK #define DP_QUAKE2_MODEL #define DP_QUAKE2_SPRITE +#define DP_QUAKE3_MAP #define DP_QUAKE3_MODEL #define DP_REGISTERCVAR #define DP_SND_SOUND7_WIP2 @@ -140,8 +123,10 @@ Available options: #define DP_SOLIDCORPSE #define DP_SPRITE32 #define DP_SV_BOTCLIENT +#define DP_SV_CLIENTCAMERA /* Works like svc_setview except also handles pvs. */ #define DP_SV_CLIENTCOLORS /* Provided only for compatibility with DP. */ #define DP_SV_CLIENTNAME /* Provided only for compatibility with DP. */ +#define DP_SV_CUSTOMIZEENTITYFORCLIENT /* Deprecated feature for compat with DP. Can be slow, incompatible with splitscreen, usually malfunctions with mvds. */ #define DP_SV_DRAWONLYTOCLIENT #define DP_SV_DROPCLIENT /* Equivelent to quakeworld's stuffcmd(self,"disconnect\n"); hack */ #define DP_SV_EFFECT @@ -151,7 +136,9 @@ Available options: #define DP_SV_POINTSOUND #define DP_SV_PRECACHEANYTIME /* Specifies that the various precache builtins can be called at any time. WARNING: precaches are sent reliably while sound events, modelindexes, and particle events are not. This can mean sounds and particles might not work the first time around, or models may take a while to appear (after the reliables are received and the model is loaded from disk). Always attempt to precache a little in advance in order to reduce these issues (preferably at the start of the map...) */ #define DP_SV_PRINT /* Says that the print builtin can be used from nqssqc (as well as just csqc), bypassing the developer cvar issues. */ +#define DP_SV_ROTATINGBMODEL /* Engines that support this support avelocity on MOVETYPE_PUSH entities, pushing entities out of the way as needed. */ #define DP_SV_SETCOLOR +#define DP_SV_SHUTDOWN #define DP_SV_SPAWNFUNC_PREFIX #define DP_SV_WRITEPICTURE #define DP_SV_WRITEUNTERMINATEDSTRING @@ -166,6 +153,8 @@ Available options: #define DP_TE_STANDARDEFFECTBUILTINS #define DP_VIEWZOOM #define EXT_BITSHIFT +#define EXT_CSQC +#define EXT_CSQC_SHARED #define EXT_DIMENSION_VISIBILITY #define EXT_DIMENSION_PHYSICS #define EXT_DIMENSION_GHOST @@ -187,6 +176,7 @@ Available options: #define FTE_FORCEINFOKEY /* Provides an easy way to change a user's userinfo from the server. */ #define FTE_GFX_QUAKE3SHADERS /* specifies that the engine has full support for vanilla quake3 shaders */ #define FTE_GFX_REMAPSHADER /* With the raw power of stuffcmds, the r_remapshader console command is exposed! This mystical command can be used to remap any shader to another. Remapped shaders that specify $diffuse etc in some form will inherit the textures implied by the surface. */ +#define FTE_GFX_IQM_HITMESH /* Supports hitmesh iqm extensions. Also supports geomsets and embedded events. */ #define FTE_GFX_MODELEVENTS /* Provides a query for per-animation events in model files, including from progs/foo.mdl.events files. */ #define FTE_ISBACKBUFFERED /* Allows you to check if a client has too many reliable messages pending. */ #define FTE_MEMALLOC /* Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games. */ @@ -195,9 +185,21 @@ Available options: #define FTE_MULTIPROGS /* Multiple progs.dat files can be loaded inside the same qcvm. Insert new ones with addprogs inside the 'init' function, and use externvalue+externset to rewrite globals (and hook functions) to link them together. Note that the result is generally not very clean unless you carefully design for it beforehand. */ #define FTE_MULTITHREADED /* Faux multithreading, allowing multiple contexts to run in sequence. */ #define FTE_MVD_PLAYERSTATS /* In csqc, getplayerstat can be used to query any player's stats when playing back MVDs. isdemo will return 2 in this case. */ -#define FTE_PART_SCRIPT /* Specifies that the r_particledesc cvar can be used to select a list of particle effects to load from particles/*.cfg, the format of which is documented elsewhere. */ +#define FTE_PART_SCRIPT /* Specifies that the r_particledesc cvar can be used to select a list of particle effects to load from particles/foo.cfg, the format of which is documented elsewhere. */ #define FTE_PART_NAMESPACES /* Specifies that the engine can use foo.bar to load effect foo from particle description bar. When used via ssqc, this should cause the client to download whatever effects as needed. */ #define FTE_PART_NAMESPACE_EFFECTINFO /* Specifies that effectinfo.bar can load effects from effectinfo.txt for DP compatibility. */ +#define FTE_PEXT_SETVIEW /* NQ's svc_setview works correctly even in quakeworld */ +#define FTE_PEXT_LIGHTSTYLECOL +#define FTE_PEXT_VIEW2 +#define FTE_PEXT_FATNESS +#define FTE_PEXT_TE_BULLET +#define FTE_PEXT_FLOATCOORDS +#define FTE_PEXT_Q2BSP /* Specifies that the client supports q2bsps. */ +#define FTE_PEXT_Q3BSP /* Specifies that the client supports q3bsps. */ +#define FTE_HEXEN2 +#define FTE_PEXT_SPAWNSTATIC +#define FTE_PEXT_CUSTOMTENTS +#define FTE_PEXT_256PACKETENTITIES /* Specifies that the client is not limited to vanilla's limit of only 64 ents visible at once. */ #define FTE_QC_BASEFRAME /* Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc. */ #define FTE_QC_FILE_BINARY /* Extends FRIK_FILE with binary read+write, as well as allowing seeking. Requires pointers. */ #define FTE_QC_CHANGELEVEL_HUB /* Adds an extra argument to changelevel which is carried over to the next map in the 'spawnspot' global. Maps will be saved+reloaded until the extra argument is omitted again, purging all saved maps. Saved games will contain a copy of each preserved map. parm1-parm64 globals can be used, giving more space to transfer more player data. */ @@ -205,6 +207,10 @@ Available options: #define FTE_QC_CHECKPVS #define FTE_QC_CROSSPRODUCT #define FTE_QC_CUSTOMSKINS /* The engine supports the use of q3 skins, as well as the use of such skin 'files' to specify rich top+bottom colours, qw skins, geomsets, or texture composition even on non-players.. */ +#define FTE_QC_DIGEST_SHA1 /* The digest_hex builtin supports 160-bit sha1 hashes. */ +#define FTE_QC_DIGEST_SHA224 /* The digest_hex builtin supports 224-bit sha2 hashes. */ +#define FTE_QC_DIGEST_SHA384 /* The digest_hex builtin supports 384-bit sha2 hashes. */ +#define FTE_QC_DIGEST_SHA512 /* The digest_hex builtin supports 512-bit sha2 hashes. */ #define FTE_QC_FS_SEARCH_SIZEMTIME #define FTE_QC_HARDWARECURSORS /* setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits (or hardware cursors are unsupported), it will be emulated using regular draws - this at least still avoids conflicting cursors as only one will ever be used, even if console+menu+csqc are all overlayed. */ #define FTE_QC_HASHTABLES /* Provides efficient string-based lookups. */ @@ -222,6 +228,7 @@ Available options: #define FTE_QUAKE2_SERVER /* This engine is able to act as a quake2 server */ #define FTE_QUAKE3_CLIENT /* This engine is able to act as a quake3 client */ #define FTE_QUAKE3_SERVER /* This engine is able to act as a quake3 server */ +#define FTE_SOLID_BSPTRIGGER /* Allows for mappers to use shaped triggers instead of being limited to axially aligned triggers. */ #define FTE_SOLID_LADDER /* Allows a simple trigger to remove effects of gravity (solid 20). obsolete. will prolly be removed at some point as it is not networked properly. Use FTE_ENT_SKIN_CONTENTS */ #define FTE_SPLITSCREEN /* Client supports splitscreen, controlled via cl_splitscreen. Servers require allow_splitscreen 1 if splitscreen is to be used over the internet. Mods that use csqc will need to be aware for this to work properly. per-client networking may be problematic. */ #define FTE_SQL /* Provides sql* builtins which can be used for sql database access */ @@ -232,6 +239,8 @@ Available options: #define FTE_TE_STANDARDEFFECTBUILTINS /* Provides builtins to replace writebytes, with a QW compatible twist. */ #define FTE_TERRAIN_MAP /* This engine supports .hmp files, as well as terrain embedded within bsp files. */ #define FTE_RAW_MAP /* This engine supports directly loading .map files, as well as realtime editing of the various brushes. */ +#define FTE_INFOBLOBS /* Removes the length limits on user/server/local info strings, and allows embedded nulls and other otherwise-reserved characters. This can be used to network avatar images and the like, or other binary data. */ +#define FTE_VRINPUTS /* input_weapon, input_left_*, input_right_*, input_head_* work, both in csqc (as inputs with suitable plugin/hardware support) and ssqc (available in PlayerPreThink). */ #define KRIMZON_SV_PARSECLIENTCOMMAND /* SSQC's SV_ParseClientCommand function is able to handle client 'cmd' commands. The tokenizing parts also work in csqc. */ #define NEH_CMD_PLAY2 #define NEH_RESTOREGAME @@ -239,6 +248,7 @@ Available options: #define QW_ENGINE #define QWE_MVD_RECORD /* You can use the easyrecord command to record MVD demos serverside. */ #define TEI_MD3_MODEL +#define TEI_SHOWLMP2 #define TENEBRAE_GFX_DLIGHTS /* Allows ssqc to attach rtlights to entities with various special properties. */ #define ZQ_MOVETYPE_FLY /* MOVETYPE_FLY works on players. */ #define ZQ_MOVETYPE_NOCLIP /* MOVETYPE_NOCLIP works on players. */ @@ -300,20 +310,40 @@ float total_secrets; float total_monsters; float found_secrets; float killed_monsters; -float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16; +float parm1; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm2; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm3; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm4; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm5; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm6; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm7; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm8; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm9; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm10; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm11; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm12; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm13; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm14; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm15; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ +float parm16; /* Player specific mod-defined values that are transferred from one map to the next. These are set by the qc inside calls to SetNewParms and SetChangeParms, and can then be read on a per-player basis after a call to the setspawnparms builtin. They are not otherwise valid. */ #endif #ifdef CSQC float intermission; #endif #if defined(CSQC) || defined(SSQC) -vector v_forward, v_up, v_right; +vector v_forward; +vector v_up; +vector v_right; #endif #ifdef CSQC vector view_angles; /* +x=DOWN */ #endif #if defined(CSQC) || defined(SSQC) -float trace_allsolid, trace_startsolid, trace_fraction; -vector trace_endpos, trace_plane_normal; +float trace_allsolid; +float trace_startsolid; +float trace_fraction; +vector trace_endpos; +vector trace_plane_normal; float trace_plane_dist; entity trace_ent; float trace_inopen; @@ -334,7 +364,7 @@ void() PlayerPreThink; /* With Prediction(QW compat/FTE default): Called before No Prediction(NQ compat): Called AFTER the player's movement intents have already been processed (ie: velocity will have already changed according to input_*, but before the actual position change. */ void() PlayerPostThink; /* Called after the player's input commands are processed. */ void() ClientKill; /* Called in response to 'cmd kill' (or just 'kill'). */ -void(optional float csqcactive) ClientConnect; /* Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. */ +void() ClientConnect; /* Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. To determine if the client has csqc active (and kick anyone that doesn't), you can use if(infokeyf(self,INFOKEY_P_CSQCACTIVE)) {sprint(self, "CSQC is required for this server\n");dropclient(self);} */ void() PutClientInServer; /* Enginewise, this is only ever called immediately after ClientConnect and is thus a little redundant. Modwise, this is also called for respawning a player etc. */ void() ClientDisconnect; /* Called once a client disconnects or times out. Not guarenteed to be called on map changes. */ void() SetNewParms; /* Called without context when a new client initially connects (before ClientConnect is even called). This function is expected to only set the parm* globals so that they can be decoded properly later. You should not rely on 'self' being set. */ @@ -478,6 +508,10 @@ void end_sys_fields; #ifdef MENU float time; /* The current local time. Increases while paused. */ #endif +#if defined(CSQC) || defined(SSQC) +float input_sequence; /* This is the client-generated input sequence number. 0 for unsequenced movements. */ +float input_servertime; /* Server's timestamp of the client's interpolation state. */ +#endif #ifdef SSQC float input_timelength; vector input_angles; /* +x=DOWN */ @@ -485,12 +519,6 @@ vector input_movevalues; float input_buttons; float input_impulse; #endif -#ifdef CSQC -vector input_cursor_screen; -vector input_cursor_trace_start; -vector input_cursor_trace_endpos; -float input_cursor_trace_entnum; -#endif #if defined(CSQC) || defined(SSQC) int trace_endcontents; int trace_surfaceflags; @@ -501,28 +529,57 @@ int trace_bone_id; /* 1-based. 0 if not known. typically needs MOVE_HITMODEL. */ int trace_triangle_id; /* 1-based. 0 if not known. */ #endif #ifdef CSQC -int trace_networkentity; /* Repots which ssqc entnum was hit when a csqc traceline impacts an ssqc-based brush entity. */ +float trace_networkentity; /* Repots which ssqc entnum was hit when a csqc traceline impacts an ssqc-based brush entity. */ +vector pmove_org; /* Reports the origin of the engineside player (after prediction). Does not work when the player is a csqc-owned entity. */ +vector pmove_vel; /* Reports the velocity of the engineside player (after prediction). Does not work when the player is a csqc-owned entity. */ +float pmove_onground; /* Reports the onground state of the engineside player (after prediction). Does not work when the player is a csqc-owned entity. */ #endif #if defined(CSQC) || defined(SSQC) vector global_gravitydir = '0 0 -1'; /* The direction gravity should act in if not otherwise specified per entity. */ int serverid; /* The unique id of this server within the server cluster. */ #endif +#ifdef CSQC +.string message; /* Allows the csqc to read the map description from the server. */ +#endif +#ifdef SSQC +.float button3; +.float button4; +.float button5; +.float button6; +.float button7; +.float button8; +#endif #if defined(NQSSQC) +.float buttonuse; /* For DP compat only. */ +.float buttonchat; /* For DP compat only. */ +.float cursor_active; /* For DP compat only. */ +.float button9; /* For DP compat only. */ +.float button10; /* For DP compat only. */ +.float button11; /* For DP compat only. */ +.float button12; /* For DP compat only. */ +.float button13; /* For DP compat only. */ +.float button14; /* For DP compat only. */ +.float button15; /* For DP compat only. */ +.float button16; /* For DP compat only. */ +.vector cursor_screen; /* For DP compat only. */ +.vector cursor_start; /* For DP compat only. */ +.vector cursor_impact; /* For DP compat only. */ +.entity cursor_entitynumber; /* For DP compat only. */ .float lastruntime; /* This field used to be used to avoid running an entity multiple times in a single frame due to quakeworld's out-of-order thinks. It is no longer used by FTE due to precision issues, but may still be updated for compatibility reasons. */ #endif #if defined(CSQC) || defined(QWSSQC) .vector punchangle; #endif #if defined(CSQC) || defined(SSQC) -.float gravity; +.float gravity; /* Multiplier applied in addition to sv_gravity (not absolute units), to control the gravity affecting this entity specifically. */ .float hull; /* Overrides the hull used by the entity for walkmove/movetogoal and not traceline/tracebox. */ .entity movechain; /* This is a linked list of entities which will be moved whenever this entity moves, logically they are attached to this entity. */ .void() chainmoved; /* Called when the entity is moved as a result of being part of another entity's .movechain */ .void(float old, float new) contentstransition; /* This function is called when the entity moves between water and air. If specified, default splash sounds will be disabled allowing you to provide your own. */ -.float dimension_solid; /* This is the bitmask of dimensions which the entity is solid within. */ +.float dimension_solid; /* This is the bitmask of dimensions which the entity is solid within. This is not networked, instead csqc traces impacting ssqc entities assumes the ssqc entity to have a dimension_solid of 1. */ .float dimension_hit; /* This is the bitmask of dimensions which the entity will be blocked by. If other.dimension_solid & self.dimension_hit, our traces will impact and not proceed. If its false, the traces will NOT impact, allowing self to pass straight through. */ -.int hitcontentsmaski; /* Traces performed for this entity will impact against surfaces that match this contents mask. */ -.float dphitcontentsmask; /* Some crappy field that inefficiently requires translating to the native contents flags. Ditch the 'dp', do it properly. */ +.int hitcontentsmaski; /* Traces performed for this entity will impact against surfaces that match this contents mask (CONTENTBITS_* constants). */ +__deprecated("Does not support mod-specific contents.") .float dphitcontentsmask; /* Some crappy field that inefficiently requires translating to the native contents flags. Ditch the 'dp', do it properly. */ .float scale; /* Multiplier that resizes the entity. 1 is normal sized, 2 is double sized. scale 0 is remapped to 1. In SSQC, this is limited to 1/16th precision, with a maximum just shy of 16. */ .float fatness; /* How many QuakeUnits to push the entity's verticies along their normals by. */ .float alpha; /* The transparency of the entity. 1 means opaque, 0.0001 means virtually invisible. 0 is remapped to 1, for compatibility. */ @@ -535,13 +592,13 @@ int serverid; /* The unique id of this server within the server cluster. */ .float basebone; /* The base* frame animations are equivelent to their non-base versions, except that they only affect bone numbers below the 'basebone' value. This means that the base* animation can affect the legs of a skeletal model independantly of the normal animation fields affecting the torso area. For more complex animation than this, use skeletal objects. */ .float baseframe; /* See basebone */ .void() customphysics; /* Called once each physics frame, overriding the entity's .movetype field and associated logic. You'll probably want to use tracebox to move it through the world. Be sure to call .think as appropriate. */ -.entity tag_entity; -.float tag_index; +.entity tag_entity; /* Specifies which entity this entity's origin+angles is 'attached' to. */ +.float tag_index; /* Specifies the tag or bone on the parent entity that we're attached to. If this is -1 then the entity is instead a q3-like camera portal, with the tag_entity saying the entity to display for. If tag_entity is world then this is a q3-like portal surface marker with a separate camera (with a tag_entity referring to the portal surface). */ .float skeletonindex; /* This object serves as a container for the skeletal bone states used to override the animation data. */ -.vector colormod; /* Provides a colour tint for the entity. */ -.vector glowmod; +.vector colormod; /* Provides a colour tint for the entity (does not affect fullbrights). */ +.vector glowmod; /* Scaler for an entity's fullbright textures. */ .vector gravitydir; /* Specifies the direction in which gravity acts. Must be normalised. '0 0 0' also means down. Use '0 0 1' if you want the player to be able to run on ceilings. */ -.vector(vector org, vector ang) camera_transform; /* Provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc. */ +.vector(vector org, vector ang) camera_transform; /* A callback that provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc. */ #endif #ifdef SSQC .float pmove_flags; @@ -572,31 +629,33 @@ int serverid; /* The unique id of this server within the server cluster. */ .entity view2; /* defines a second viewpoint, typically displayed in a corner of the screen (also punches open pvs). */ .vector movement; /* These are the directions that the player is currently trying to move in (ie: which +forward/+moveright/+moveup etc buttons they have held), expressed relative to that player's angles. Order is forward, right, up. */ .float vw_index; /* This acts as a second modelindex, using the same frames etc. */ -.entity nodrawtoclient; /* This entity will not be sent to the player named by this field. They will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ -.entity drawonlytoclient; /* This entity will be sent *only* to the player named by this field. To other players they will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ -.entity viewmodelforclient; /* This entity will be sent only to the player named by this field, and this entity will be attached to the player's view as an additional weapon model. */ -.entity exteriormodeltoclient; /* This entity will be invisible to the player named by this field, except in mirrors or mirror-like surfaces, where it will be visible as normal. It may still cast shadows as normal, and generate lights+particles, depending on client settings. Does not affect how other players see the entity. */ -.float glow_size; -.float glow_color; -.float glow_trail; +__deprecated("Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity nodrawtoclient; /* This entity will not be sent to the player named by this field. They will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ +__deprecated("Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity drawonlytoclient; /* This entity will be sent *only* to the player named by this field. To other players they will be invisible and not emit dlights/particles. Does not work in MVD-recorded game. */ +__deprecated("Redundant. Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity viewmodelforclient; /* This entity will be sent only to the player named by this field, and this entity will be attached to the player's view as an additional weapon model. */ +__deprecated("Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.") .entity exteriormodeltoclient; /* This entity will be invisible to the player named by this field, except in mirrors or mirror-like surfaces, where it will be visible as normal. It may still cast shadows as normal, and generate lights+particles, depending on client settings. Does not affect how other players see the entity. */ +.entity clientcamera; /* Controls which entity to use for this client's camera. */ +.float glow_size; /* Some outdated particle trail thing. */ +.float glow_color; /* Some outdated particle trail thing. */ +.float glow_trail; /* Some outdated particle trail thing. */ .float traileffectnum; /* This should be set to the result of particleeffectnum, in order to attach a custom trail effect to an entity as it moves. */ .float emiteffectnum; /* This should be set to the result of particleeffectnum, in order to continually spawn particles in the direction that this entity faces. */ -.float dimension_see; /* This is the dimension mask (bitfield) that the client is allowed to see. Entities and events not in this dimension mask will be invisible. */ -.float dimension_seen; /* This is the dimension mask (bitfield) that the client is visible within. Clients that cannot see this dimension mask will not see this entity. */ -.float dimension_ghost; /* If this entity is visible only within these dimensions, it will become transparent, as if a ghost. */ -.float dimension_ghost_alpha; /* If this entity is subject to dimension_ghost, this is the scaler for its alpha value. If 0, 0.5 will be used instead. */ + +/* We use these for flash grenades and are OK with MVD/splitscreen issues. */ +/*__deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_see; /* This is the dimension mask (bitfield) that the client is allowed to see. Entities and events not in this dimension mask will be invisible. */ +/* __deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_seen; /* This is the dimension mask (bitfield) that the client is visible within. Clients that cannot see this dimension mask will not see this entity. */ +/* __deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_ghost; /* If this entity is visible only within these dimensions, it will become transparent, as if a ghost. */ +/* __deprecated("Does not work with MVDs nor splitscreen.") */ .float dimension_ghost_alpha; /* If this entity is subject to dimension_ghost, this is the scaler for its alpha value. If 0, 0.5 will be used instead. */ .float(entity playerent, float changedflags) SendEntity; /* Called by the engine whenever an entity needs to be (re)sent to a client's csprogs, either because SendFlags was set or because data was lost. Must write its data to the MSG_ENTITY buffer. Will be called at the engine's leasure. */ .float SendFlags; /* Indicates that something in the entity has been changed, and that it needs to be updated to all players that can see it. The engine will clear it at some point, with the cleared bits appearing in the 'changedflags' argument of the SendEntity method. */ -.float Version; /* Obsolete, set a SendFlags bit instead. */ -.float clientcolors; +__deprecated("Use SendFlags instead.") .float Version; /* Obsolete */ +__deprecated("Doesn't support RGB player colours.") .float clientcolors; .float viewzoom; -.float items2; .float playerclass; .float hasted; .float light_level; /* Used by hexen2 to indicate the light level where the player is standing. */ .float pvsflags; /* Reconfigures when the entity is visible to clients */ .float uniquespawnid; /* Incremented by 1 whenever the entity is respawned. Persists across remove calls, for when the two-second grace period is insufficient. */ -.float() customizeentityforclient; /* Called just before an entity is sent to a client (non-csqc protocol). This gives you a chance to tailor 'self' according to what 'other' should see. */ +DEP_CSQC .float() customizeentityforclient; /* Called just before an entity is sent to a client (non-csqc protocol). This gives you a chance to tailor 'self' according to what 'other' should see. */ #endif #ifdef CSQC .float frame3; /* Some people just don't understand how to use framegroups... */ @@ -620,7 +679,7 @@ int serverid; /* The unique id of this server within the server cluster. */ .float basesubblendfrac; /* See basebone */ .float basesubblend2frac; /* See basebone */ #endif -void(float reqid, float responsecode, string resourcebody) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */ +void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */ #ifdef SSQC void() SpectatorConnect; /* Called when a spectator joins the game. */ void() SpectatorDisconnect; /* Called when a spectator disconnects from the game. */ @@ -632,8 +691,12 @@ void(float pauseduration) SV_PausedTic; /* For each frame that the server is pau float(float newstatus) SV_ShouldPause; /* Called to give the qc a change to block pause/unpause requests. Return false for the pause request to be ignored. newstatus is 1 if the user is trying to pause the game. For the duration of the call, self will be set to the player who tried to pause, or to world if it was triggered by a server-side event. */ void() SV_RunClientCommand; /* Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysics' after modifying the inputs. */ void() SV_AddDebugPolygons; /* Called each video frame. This is the only place where ssqc is allowed to call the R_BeginPolygon/R_PolygonVertex/R_EndPolygon builtins. This is exclusively for debugging, and will break in anything but single player as it will not be called if the engine is not running both a client and a server. */ -void() SV_PlayerPhysics; /* Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful. */ +DEP_CSQC void() SV_PlayerPhysics; /* Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful. */ +void(float fd, float entcount, float playerslots) SV_PerformSave; /* Called by the engine as part of saved games. The QC is responsible for writing any data that will be required to restore the game. Save files are not limited to just text, you can use fwrite (and later fread) for binary data. Remember to close the passed file. */ +void(float fd, float entcount, float playerslots) SV_PerformLoad; /* Called by the engine to restore a saved game that was saved via SV_PerformSave, the server will have already started the game to its inital state (for precaches+makestatic calls), so entities+globals will have their post-spawn values (you will likely want to remove most of them, you can use the two extra args as helpers for that). You can use respawn_edict to un-remove specific entities, with parseentitydata or putentityfieldstring(findentityfield(NAME), ent, value) to assign to fields by name strings. Don't expect bprints/etc to work - players are likely in a pending state. Remember to close the passed file. */ +void() RestoreGame; /* Called for each reconnecting player as part of loading a saved game. Part of NEH_RESTOREGAME. */ void() EndFrame; /* Called after non-player entities have been run at the end of the physics frame. Player physics is performed out of order and can/will still occur between EndFrame and BeginFrame. */ +void() SetTransferParms; /* Called as an alternative to SetChangeParms when a player is transferring to another server. Part of FTE_SV_CLUSTER. */ string(string addr, string uinfo, string features) SV_CheckRejectConnection; /* Called to give the mod a chance to ignore connection requests based upon client protocol support or other properties. Use infoget to read the uinfo and features arguments. */ #endif #ifdef CSQC @@ -671,7 +734,7 @@ void(string cmdtext) GameCommand; string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) Cef_GeneratePage; /* Provides an entrypoint to generate pages for the CEF plugin from within QC. Headers are -separated key/value pairs (use tokenizebyseparator). */ #ifdef SSQC -string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) HTTP_GeneratePage; /* Provides an entrypoint to generate pages for pages requested over http (sv_port_tcp+net_enable_http). Headers are +string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) HTTP_GeneratePage; /* Provides an entrypoint to generate pages for pages requested over http (sv_port_tcp+net_enable_http). Headers are -separated key/value pairs (use tokenizebyseparator). Return __NULL__ to let the engine handle it, an empty string for a 404, and any other text for a regular 200 response. */ #endif #if defined(CSQC) || defined(SSQC) @@ -683,20 +746,25 @@ void() m_init; void() m_shutdown; void(vector screensize) m_draw; /* Provides the menuqc with a chance to draw. Will be called even if the menu does not have focus, so be sure to avoid that. COMPAT: screensize is not provided in DP. */ void(vector screensize, float opaque) m_drawloading; /* Additional drawing function to draw loading screens. If opaque is set, then this function must ensure that the entire screen is overdrawn (even if just by a black drawfill). */ +void(string rendererdescription) Menu_RendererRestarted; /* Called by the engine after the video was restarted. This serves to notify the MenuQC that any render targets that it may have cached were purged, and will need to be regenerated. */ float(float evtype, float scanx, float chary, float devid) Menu_InputEvent; /* If present, this is called instead of m_keydown and m_keyup Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */ -void(float scan, float chr) m_keydown; -void(float scan, float chr) m_keyup; +__deprecated("Use Menu_InputEvent") void(float scan, float chr) m_keydown; +__deprecated("Use Menu_InputEvent") void(float scan, float chr) m_keyup; void(float wantmode) m_toggle; float(string cmd) m_consolecommand; +float(float idx) m_gethostcachecategory; #endif #ifdef SSQC -float parm17, parm18, parm19, parm20, parm21, parm22, parm23, parm24, parm25, parm26, parm27, parm28, parm29, parm30, parm31, parm32; +float parm17, parm18, parm19, parm20, parm21, parm22, parm23, parm24, parm25, parm26, parm27, parm28, parm29, parm30, parm31, parm32; /* Additional spawn parms, following the same parmN theme. */ float parm33, parm34, parm35, parm36, parm37, parm38, parm39, parm40, parm41, parm42, parm43, parm44, parm45, parm46, parm47, parm48; float parm49, parm50, parm51, parm52, parm53, parm54, parm55, parm56, parm57, parm58, parm59, parm60, parm61, parm62, parm63, parm64; +string parm_string; /* Like the regular parmN globals, but preserves string contents. */ +string startspot; /* Receives the value of the second argument to changelevel from the previous map. */ var float dimension_send; /* Used by multicast functionality. Multicasts (and related builtins that multicast internally) will only be sent to players where (player.dimension_see & dimension_send) is non-zero. */ //var float dimension_default = 255; /* Default dimension bitmask */ +__unused var string __fullspawndata; /* Set by the engine before calls to spawn functions, and is most easily parsed with the tokenize builtin. This allows you to handle halflife's multiple-fields-with-the-same-name (or target-specific fields). */ #endif #if defined(CSQC) || defined(SSQC) __used var float physics_mode = 2; /* 0: original csqc - physics are not run @@ -712,9 +780,90 @@ var vector drawfontscale = '1 1 0'; /* Specifies a scaler for all text rendering float drawfont; /* Allows you to choose exactly which font is to be used to draw text. Fonts can be registered/allocated with the loadfont builtin. */ const float FONT_DEFAULT = 0; #endif +#if defined(NQSSQC) +entity newmis; /* ssqc global */ +#endif +#if defined(CSQC) || defined(QWSSQC) +float deathmatch; /* ssqc global */ +float coop; /* ssqc global */ +#endif +#if defined(QWSSQC) +float teamplay; /* ssqc global */ +#endif +#if defined(CSQC) || defined(SSQC) +int trace_endcontentsi; /* ssqc global */ +int trace_surfaceflagsi; /* ssqc global */ +string trace_surfacename; /* ssqc global */ +float cycle_wrapped; /* ssqc global */ +#endif +#ifdef CSQC +float dimension_default; /* ssqc global */ +#endif +#if defined(CSQC) || defined(SSQC) +unsigned int input_weapon; /* ssqc global */ +float input_lightlevel; /* ssqc global */ +vector input_cursor_screen; /* ssqc global */ +vector input_cursor_trace_start; /* ssqc global */ +vector input_cursor_trace_endpos; /* ssqc global */ +float input_cursor_entitynumber; /* ssqc global */ +unsigned int input_head_status; /* ssqc global */ +vector input_head_origin; /* ssqc global */ +vector input_head_angles; /* ssqc global */ +vector input_head_velocity; /* ssqc global */ +vector input_head_avelocity; /* ssqc global */ +unsigned int input_head_weapon; /* ssqc global */ +unsigned int input_left_status; /* ssqc global */ +vector input_left_origin; /* ssqc global */ +vector input_left_angles; /* ssqc global */ +vector input_left_velocity; /* ssqc global */ +vector input_left_avelocity; /* ssqc global */ +unsigned int input_left_weapon; /* ssqc global */ +unsigned int input_right_status; /* ssqc global */ +vector input_right_origin; /* ssqc global */ +vector input_right_angles; /* ssqc global */ +vector input_right_velocity; /* ssqc global */ +vector input_right_avelocity; /* ssqc global */ +unsigned int input_right_weapon; /* ssqc global */ +#endif +#ifdef SSQC +float trace_endcontentsf; /* ssqc global */ +float trace_surfaceflagsf; /* ssqc global */ +#endif +#if defined(CSQC) || defined(SSQC) +string trace_dphittexturename; /* ssqc global */ +#endif +#ifdef SSQC +float trace_dpstartcontents; /* ssqc global */ +float trace_dphitcontents; /* ssqc global */ +float trace_dphitq3surfaceflags; /* ssqc global */ +#endif +#ifdef CSQC +float(vector angles, float isdelta) CSQC_Parse_SetAngles; +void(float playernum) CSQC_PlayerInfoChanged; +void() CSQC_ServerInfoChanged; +DEP("use CSQC_Event_Sound") float(float channel, string soundname, vector pos, float vol, float attenuation, float flags) CSQC_ServerSound; +void(int entidx, string newentdata) CSQC_MapEntityEdited; +float clframetime; +float servertime; +float serverprevtime; +float serverdeltatime; +DEP("Does not support mod-specific contents.") float trace_dpstartcontents; +DEP("Does not support mod-specific contents.") float trace_dphitcontents; +DEP("Does not support mod-specific surface flags") float trace_dphitq3surfaceflags; +DEP("Does not support all mod-specific surface flags.") float trace_surfaceflagsf; +DEP("Does not support all mod-specific contents.") float trace_endcontentsf; +float intermission_time; +vector pmove_mins; +vector pmove_maxs; +float pmove_jump_held; +float pmove_waterjumptime; +float input_clienttime; +float autocvar_vid_conwidth; +float autocvar_vid_conheight; +#endif const float TRUE = 1; const float FALSE = 0; /* File not found... */ -const float M_PI = 3.14159; +const float M_PI = 3.14159; /* Mathematica Pi constant. */ #if defined(CSQC) || defined(SSQC) const float MOVETYPE_NONE = 0; const float MOVETYPE_WALK = 3; @@ -735,9 +884,10 @@ const float SOLID_TRIGGER = 1; const float SOLID_BBOX = 2; const float SOLID_SLIDEBOX = 3; const float SOLID_BSP = 4; /* Does not collide against other SOLID_BSP entities. Normally paired with MOVETYPE_PUSH. */ -const float SOLID_CORPSE = 5; /* Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .solid value to SOLID_BBOX or so, perform the traceline, then revert the player's .solid value. */ -const float SOLID_LADDER = 20; /* Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead. */ +const float SOLID_CORPSE = 5; /* Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .hitcontentsmaski value to include CONTENTBIT_CORPSE, perform the traceline, then revert the player's .solid value. */ +__deprecated("Obsoleted by .skin=CONTENTS_LADDER") const float SOLID_LADDER = 20; /* Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead. */ const float SOLID_PORTAL = 21; /* CSG subtraction volume combined with entity transformations on impact. */ +const float SOLID_BSPTRIGGER = 22; /* For complex-shaped trigger volumes, instead of being a pure aabb. */ const float SOLID_PHYSICS_BOX = 32; const float SOLID_PHYSICS_SPHERE = 33; const float SOLID_PHYSICS_CAPSULE = 34; @@ -819,29 +969,28 @@ const int CONTENTBIT_SOLID = 0x00000001i; const int CONTENTBIT_LAVA = 0x00000008i; const int CONTENTBIT_SLIME = 0x00000010i; const int CONTENTBIT_WATER = 0x00000020i; -const int CONTENTBIT_FTELADDER = 0x00004000i; +const int CONTENTBIT_FTELADDER = 0x00004000i; /* Content bit used for .skin=CONTENT_LADDER entities. */ const int CONTENTBIT_PLAYERCLIP = 0x00010000i; const int CONTENTBIT_MONSTERCLIP = 0x00020000i; -const int CONTENTBIT_BODY = 0x02000000i; -const int CONTENTBIT_CORPSE = 0x04000000i; -const int CONTENTBIT_Q2LADDER = 0x20000000i; /* Content bit specific to q2bsp */ -const int CONTENTBIT_SKY = 0x80000000i; +const int CONTENTBIT_BODY = 0x02000000i; /* Content bit that indicates collisions against SOLID_BBOX/SOLID_SLIDEBOX entities. */ +const int CONTENTBIT_CORPSE = 0x04000000i; /* Content bit that indicates collisions against SOLID_CORPSE entities. */ +const int CONTENTBIT_Q2LADDER = 0x20000000i; /* Content bit specific to q2bsp (conflicts with q3bsp contents so use with caution). */ +const int CONTENTBIT_SKY = 0x80000000i; /* Content bit somewhat specific to q1bsp (aliases to NODROP in q3bsp), but you should probably check surfaceflags&SURF_SKY as well for q2+q3bsp too. */ const int CONTENTBITS_POINTSOLID = CONTENTBIT_SOLID|0x00000002i|CONTENTBIT_BODY; /* Bits that traceline would normally consider solid */ const int CONTENTBITS_BOXSOLID = CONTENTBIT_SOLID|0x00000002i|CONTENTBIT_BODY|CONTENTBIT_PLAYERCLIP; /* Bits that tracebox would normally consider solid */ const int CONTENTBITS_FLUID = CONTENTBIT_WATER|CONTENTBIT_SLIME|CONTENTBIT_LAVA|CONTENTBIT_SKY; -const int SPA_POSITION; /* These SPA_* constants are to specify which attribute is returned by the getsurfacepointattribute builtin */ -const int SPA_S_AXIS = 1; -const int SPA_T_AXIS = 2; -const int SPA_R_AXIS = 3; /* aka: SPA_NORMAL */ -const int SPA_TEXCOORDS0 = 4; -const int SPA_LIGHTMAP0_TEXCOORDS = 5; -const int SPA_LIGHTMAP0_COLOR = 6; +const float SPA_POSITION = 0; /* These SPA_* constants are to specify which attribute is returned by the getsurfacepointattribute builtin */ +const float SPA_S_AXIS = 1; +const float SPA_T_AXIS = 2; +const float SPA_R_AXIS = 3; /* aka: SPA_NORMAL */ +const float SPA_TEXCOORDS0 = 4; +const float SPA_LIGHTMAP0_TEXCOORDS = 5; +const float SPA_LIGHTMAP0_COLOR = 6; const float CHAN_AUTO = 0; /* The automatic channel, play as many sounds on this channel as you want, and they'll all play, however the other channels will replace each other. */ const float CHAN_WEAPON = 1; const float CHAN_VOICE = 2; const float CHAN_ITEM = 3; const float CHAN_BODY = 4; - #endif #if defined(QWSSQC) const float CHANF_RELIABLE = 8; /* Only valid if the flags argument is not specified. The sound will be sent reliably, which is important if it is intended to replace looping sounds on doors etc. */ @@ -854,13 +1003,10 @@ const float SOUNDFLAG_ABSVOLUME = 16; /* The sample's volume is not scaled by th #endif #if defined(CSQC) || defined(SSQC) const float SOUNDFLAG_FORCELOOP = 2; /* The sound will restart once it reaches the end of the sample. */ -#endif -#ifdef CSQC const float SOUNDFLAG_NOSPACIALISE = 4; /* The different audio channels are played at the same volume regardless of which way the player is facing, without needing to use 0 attenuation. */ -#endif -#if defined(CSQC) || defined(SSQC) const float SOUNDFLAG_NOREVERB = 32; /* Disables the use of underwater/reverb effects on this sound effect. */ const float SOUNDFLAG_FOLLOW = 64; /* The sound's origin will updated to follow the emitting entity. */ +const float SOUNDFLAG_NOREPLACE = 128; /* Sounds started with this flag will be ignored when there's already a sound playing on that same ent-channel. */ #endif #ifdef SSQC const float SOUNDFLAG_UNICAST = 256; /* The sound will be sent only by the player specified by msg_entity. Spectators and related splitscreen players will also hear the sound. */ @@ -874,9 +1020,42 @@ const float ATTN_STATIC = 3; /* Even more attenuation to avoid torches drowing o #endif #ifdef SSQC const float SVC_CGAMEPACKET = 83; /* Direct ssqc->csqc message. Must only be multicast. The data triggers a CSQC_Parse_Event call in the csqc for the csqc to read the contents. The server *may* insert length information for clients connected via proxies which are not able to cope with custom csqc payloads. This should only ever be used in conjunction with the MSG_MULTICAST destination. */ +#endif +#if defined(CSQC) || defined(SSQC) +const float TE_SPIKE = 0; +const float TE_SUPERSPIKE = 1; +const float TE_GUNSHOT = 2; +const float TE_EXPLOSION = 3; +const float TE_TAREXPLOSION = 4; +const float TE_LIGHTNING1 = 5; +const float TE_LIGHTNING2 = 6; +const float TE_WIZSPIKE = 7; +const float TE_KNIGHTSPIKE = 8; +const float TE_LIGHTNING3 = 9; +const float TE_LAVASPLASH = 10; +const float TE_TELEPORT = 11; +#endif +#if defined(CSQC) || defined(QWSSQC) +const float TE_BLOOD = 12; +#endif +#if defined(NQSSQC) +const float TE_EXPLOSION2 = 12; +#endif +#if defined(CSQC) || defined(QWSSQC) +const float TE_LIGHTNINGBLOOD = 13; +#endif +#if defined(NQSSQC) +const float TE_BEAM = 13; const float MSG_BROADCAST = 0; /* The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family. */ const float MSG_ONE = 1; /* The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client. */ const float MSG_ALL = 2; /* The byte(s) will be reliably sent to all players. */ +#endif +#if defined(QWSSQC) +__deprecated("Use MSG_MULTICAST+multicast(MULTICAST_*)") const float MSG_BROADCAST; /* The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family. */ +__deprecated("Use MSG_MULTICAST+multicast(MULTICAST_ONE_R)") const float MSG_ONE = 1; /* The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client. */ +__deprecated("Use MSG_MULTICAST+multicast(MULTICAST_ALL)") const float MSG_ALL = 2; /* The byte(s) will be reliably sent to all players. */ +#endif +#ifdef SSQC const float MSG_INIT = 3; /* The byte(s) will be written into the signon buffer. Clients will see these messages when they connect later. This buffer is only flushed on map changes, so spamming it _WILL_ result in overflows. */ const float MSG_MULTICAST = 4; /* The byte(s) will be written into the multicast buffer for more selective sending. Messages sent this way will never be split across packets, and using this for csqc-only messages will not break protocol translation. */ const float MSG_ENTITY = 5; /* The byte(s) will be written into the entity buffer. This is a special value used only inside 'SendEntity' functions. */ @@ -901,8 +1080,8 @@ const float PRINT_CHAT = 3; const float PVSF_NORMALPVS = 0; /* Filter first by PVS, then filter this entity using tracelines if sv_cullentities is enabled. */ const float PVSF_NOTRACECHECK = 1; /* Filter strictly by PVS. */ const float PVSF_USEPHS = 2; /* Send if we're close enough to be able to hear this entity. */ -const float PVSF_IGNOREPVS = 3; /* Ignores pvs. This entity is visible whereever you are on the map. */ -const float PVSF_NOREMOVE = 128; /* Once visible to a client, this entity will remain visible. This can be useful for csqc and corpses. */ +const float PVSF_IGNOREPVS = 3; /* Ignores pvs. This entity is visible whereever you are on the map. Updates will be sent regardless of pvs or phs */ +const float PVSF_NOREMOVE = 128; /* Once visible to a client, this entity will remain visible. This can be useful for csqc and corpses. While this flag is set, no CSQC_Remove events will be sent for the entity, but this does NOT mean that it will still receive further updates while outside of the pvs. */ const string INFOKEY_P_IP = "ip"; /* The apparent ip address of the client. This may be a proxy's ip address. */ const string INFOKEY_P_REALIP = "realip"; /* If sv_getrealip is set, this gives the ip as determine using that algorithm. */ const string INFOKEY_P_CSQCACTIVE = "csqcactive"; /* Client has csqc enabled. CSQC ents etc will be sent to this player. */ @@ -974,7 +1153,7 @@ const float FL_ONGROUND = 512; const float FL_PARTIALGROUND = 1024; const float FL_WATERJUMP = 2048; #endif -#if defined(CSQC) || defined(NQSSQC) +#if defined(NQSSQC) const float FL_JUMPRELEASED = 4096; #endif #if defined(CSQC) || defined(SSQC) @@ -987,6 +1166,7 @@ const float FL_LAGGEDMOVE = 65536; /* Enables anti-lag on rockets etc. */ const float MOVE_NORMAL = 0; const float MOVE_NOMONSTERS = 1; /* The trace will ignore all non-solid_bsp entities. */ const float MOVE_MISSILE = 2; /* The trace will use a bbox size of +/- 15 against entities with FL_MONSTER set. */ +const float MOVE_WORLDONLY = 3; /* The trace will ignore everything but the worldmodel. This is useful for to prevent the q3bsp pvs+culling issues that come with spectator modes leaving the world . */ const float MOVE_HITMODEL = 4; /* Traces will impact the actual mesh of the model instead of merely their bounding box. Should generally only be used for tracelines. Note that this flag is unreliable as an object can animate through projectiles. The bounding box MUST be set to completely encompass the entity or those extra areas will be non-solid (leaving a hole for things to go through). */ const float MOVE_TRIGGERS = 16; /* This trace type will impact only triggers. It will ignore non-solid entities. */ const float MOVE_EVERYTHING = 32; /* This type of trace will hit solids and triggers alike. Even non-solid entities. */ @@ -998,6 +1178,12 @@ const float MOVE_LAGGED = 64; /* Will use antilag based upon the player's latenc const float MOVE_ENTCHAIN = 128; /* Returns a list of entities impacted via the trace_ent.chain field */ const float MOVE_OTHERONLY = 256; /* Traces that use this trace type will collide against *only* the entity specified via the 'other' global, and will ignore all owner/solid_not/dimension etc rules, they will still adhere to contents and bsp/bbox rules though. */ #endif +const float CVAR_TYPEFLAG_EXISTS = 1; /* Cvar name actually exists. */ +const float CVAR_TYPEFLAG_SAVED = 2; /* Cvar is flaged for archival (might need cfg_save to actually save). */ +const float CVAR_TYPEFLAG_PRIVATE = 4; /* QC is not allowed to read. */ +const float CVAR_TYPEFLAG_ENGINE = 8; /* Cvar was created by the engine itself (not user/mod created). */ +const float CVAR_TYPEFLAG_HASDESCRIPTION = 16; /* cvar_description will return something (hopefully) useful. */ +const float CVAR_TYPEFLAG_READONLY = 32; /* cvar may not be changed by qc. */ const float RESTYPE_MODEL = 0; /* RESTYPE_* constants are used as arguments with the resourcestatus builtin. */ const float RESTYPE_SOUND = 1; /* precache_sound */ const float RESTYPE_PARTICLE = 2; /* particleeffectnum */ @@ -1026,7 +1212,7 @@ const float EF_FLAG1 = 16; const float EF_FLAG2 = 32; #endif #if defined(CSQC) || defined(NQSSQC) -const float EF_NODRAW = 16; +const float EF_NODRAW = 16; /* Disables drawing of the model. Does NOT work on QW players. */ #endif #if defined(CSQC) || defined(SSQC) const float EF_ADDITIVE = 32; /* The entity will be drawn with an additive blend. This is NOT supported on players in any quakeworld engine. */ @@ -1051,15 +1237,15 @@ const float MF_TRACER2 = 64; /* AKA: hellknight projectile trail */ const float MF_TRACER3 = 128; /* AKA: purple vore trail */ #endif #ifdef SSQC -const float SL_ORG_TL = 20; /* Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen */ -const float SL_ORG_TR = 21; -const float SL_ORG_BL = 22; -const float SL_ORG_BR = 23; -const float SL_ORG_MM = 24; -const float SL_ORG_TM = 25; -const float SL_ORG_BM = 26; -const float SL_ORG_ML = 27; -const float SL_ORG_MR = 28; +DEP_CSQC const float SL_ORG_TL = 20; /* Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen */ +DEP_CSQC const float SL_ORG_TR = 21; +DEP_CSQC const float SL_ORG_BL = 22; +DEP_CSQC const float SL_ORG_BR = 23; +DEP_CSQC const float SL_ORG_MM = 24; +DEP_CSQC const float SL_ORG_TM = 25; +DEP_CSQC const float SL_ORG_BM = 26; +DEP_CSQC const float SL_ORG_ML = 27; +DEP_CSQC const float SL_ORG_MR = 28; #endif #if defined(CSQC) || defined(SSQC) const float PFLAGS_NOSHADOW = 1; /* Associated RT lights attached will not cast shadows, making them significantly faster to draw. */ @@ -1068,7 +1254,6 @@ const float PFLAGS_CORONA = 2; /* Enables support of coronas on the associated r #ifdef SSQC const float PFLAGS_FULLDYNAMIC = 128; /* When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used. */ #endif -#if defined(CSQC) || defined(SSQC) const float EV_STRING = 1; const float EV_FLOAT = 2; const float EV_VECTOR = 3; @@ -1077,8 +1262,10 @@ const float EV_FIELD = 5; const float EV_FUNCTION = 6; const float EV_POINTER = 7; const float EV_INTEGER = 8; -const float EV_VARIANT = 9; -#endif +const float EV_UINT = 9; +const float EV_INT64 = 10; +const float EV_UINT64 = 11; +const float EV_DOUBLE = 12; hashtable gamestate; /* Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted). */ const float HASH_REPLACE = 256; /* Used with hash_add. Attempts to remove the old value instead of adding two values for a single key. */ const float HASH_ADD = 512; /* Used with hash_add. The new entry will be inserted in addition to the existing entry. */ @@ -1106,6 +1293,10 @@ const float STAT_VIEWZOOM = 21; /* Scales fov and sensitiity. Part of DP_VIEWZOO const float STAT_USER = 32; /* Custom user stats start here (lower values are reserved for engine use). */ #endif #if defined(CSQC) || defined(MENU) +const float PRECACHE_PIC_FROMWAD = 1; /* Attempt to load it from the legacy gfx.wad file (usually its better to just use a gfx/ prefix instead). */ +const float PRECACHE_PIC_NOCLAMP = 4; /* Texture coords for the pic will not be clamped nor padded nor atlased. */ +const float PRECACHE_PIC_DOWNLOAD = 256; /* If no image could be loaded then attempt to download one from the server. This flag can cause the function to block until completion. (Slow!) */ +const float PRECACHE_PIC_TEST = 512; /* The precache will block until the image is fully loaded, returning a null string on failure. (Slow!) */ const float VF_MIN = 1; /* The top-left of the 3d viewport in screenspace. The VF_ values are used via the setviewprop/getviewprop builtins. */ const float VF_MIN_X = 2; const float VF_MIN_Y = 3; @@ -1114,8 +1305,8 @@ const float VF_SIZE_X = 5; const float VF_SIZE_Y = 6; const float VF_VIEWPORT = 7; /* vector+vector. Two argument shortcut for VF_MIN and VF_SIZE */ const float VF_FOV = 8; /* sets both fovx and fovy. consider using afov instead. */ -const float VF_FOVX = 9; /* horizontal field of view. does not consider aspect at all. */ -const float VF_FOVY = 10; /* vertical field of view. does not consider aspect at all. */ +const float VF_FOV_X = 9; /* horizontal field of view. does not consider aspect at all. */ +const float VF_FOV_Y = 10; /* vertical field of view. does not consider aspect at all. */ const float VF_ORIGIN = 11; /* The origin of the view. Not of the player. */ const float VF_ORIGIN_X = 12; const float VF_ORIGIN_Y = 13; @@ -1157,16 +1348,45 @@ const float VF_VIEWENTITY = 206; /* Changes the RF_EXTERNALMODEL flag on entitie #endif #if defined(CSQC) || defined(MENU) const float VF_RT_DESTCOLOUR = 212; /* The texture name to write colour info into, this includes both 3d and 2d drawing. -Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. +Additional arguments are: format (IMGFMT_*), sizexy. Written to by both 3d and 2d rendering. Note that any rendertarget textures may be destroyed on video mode changes or so. Shaders can name render targets by prefixing texture names with '$rt:', or $sourcecolour. */ +const float VF_RT_DESTCOLOUR1 = 213; /* Like VF_RT_DESTCOLOUR, for multiple render targets. */ +const float VF_RT_DESTCOLOUR2 = 214; /* Like VF_RT_DESTCOLOUR, for multiple render targets. */ +const float VF_RT_DESTCOLOUR3 = 215; /* Like VF_RT_DESTCOLOUR, for multiple render targets. */ const float VF_RT_SOURCECOLOUR = 209; /* The texture name to use with shaders that specify a $sourcecolour map. */ -const float VF_RT_DEPTH = 210; /* The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16bit=4,24bit=5,32bit=6), sizexy. */ +const float VF_RT_DEPTH = 210; /* The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (IMGFMT_D*), sizexy. */ const float VF_RT_RIPPLE = 211; /* The texture name to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy. */ const float VF_ENVMAP = 220; /* The cubemap name to use as a fallback for $reflectcube, if a shader was unable to load one. Note that this doesn't automatically change shader permutations or anything. */ const float VF_USERDATA = 221; /* Pointer (and byte size) to an array of vec4s. This data is then globally visible to all glsl via the w_user uniform. */ #endif #ifdef CSQC +const float VF_SKYROOM_CAMERA = 222; /* Controls the camera position of the skyroom (which will be drawn underneath transparent sky surfaces). This should move slightly with the real camera, but not so much that the skycamera enters walls. Requires a skyshader with a blend mode on the first pass (or no passes). */ +#endif +#if defined(CSQC) || defined(MENU) +const float VF_PROJECTIONOFFSET = 224; /* vec2 horizontal+vertical offset for the projection matrix, for weird off-centre rendering. */ +const float DRAWFLAG_NORMAL = 0; /* Args for drawpic/drawfill/beginpolygon. Not to be confused with the hexen2-compatibility feature. */ +const float DRAWFLAG_ADD = 1; /* Forces additive blending, overriding any shader settings. */ +const float DRAWFLAG_MODULATE = 2; /* Forces alpha blending, overriding any shader settings. */ +const float DRAWFLAG_2D = 4; /* For use with beginpolygon. The polygon will be drawn to the 2d screen, instead of being added to the 3d scene. */ +const float DRAWFLAG_TWOSIDED = 1024; /* For use with beginpolygon. The polygon will be two-sided without any backface culling. */ +const float DRAWFLAG_LINES = 2048; /* For use with beginpolygon. The surface verticies should be interpreted as a line loop, instead of a triangle fan. */ +const float IMGFMT_R8G8B8A8 = 1; /* Typical 32bit rgba pixel format. */ +const float IMGFMT_R16G16B16A16F = 2; /* Half-Float pixel format. Requires gl3 support. */ +const float IMGFMT_R32G32B32A32F = 3; /* Regular Float pixel format. Requires gl3 support. */ +const float IMGFMT_D16 = 4; /* 16-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*. */ +const float IMGFMT_D24 = 5; /* 24-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*. */ +const float IMGFMT_D32 = 6; /* 32-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*. */ +const float IMGFMT_R8 = 7; /* Single channel red-only 8bit pixel format. */ +const float IMGFMT_R16F = 8; /* Single channel red-only Half-Float pixel format. Requires gl3 support. */ +const float IMGFMT_R32F = 9; /* Single channel red-only Float pixel format. Requires gl3 support. */ +const float IMGFMT_A2B10G10R10 = 10; /* Packed 32-bit packed 10-bit colour pixel format. Requires gl3 support. */ +const float IMGFMT_R5G6B5 = 11; /* Packed 16-bit colour pixel format. */ +const float IMGFMT_R4G4B4A4 = 12; /* Packed 16-bit colour pixel format, with alpha */ +const float IMGFMT_R8G8 = 13; /* 16-bit two-channel pixel format. */ +const float IMGFMT_R32G32B32F = 14; /* A pixel format that matches QC's vector type. */ +#endif +#ifdef CSQC const float RF_VIEWMODEL = 1; /* Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob. */ const float RF_EXTERNALMODEL = 2; /* Specifies that this entity should be displayed in mirrors (and may still cast shadows), but will not otherwise be visible. */ #endif @@ -1178,14 +1398,23 @@ const float RF_ADDITIVE = 8; /* Shaders from this entity will temporarily be hac const float RF_USEAXIS = 16; /* The entity will be oriented according to the current v_forward+v_right+v_up vector values instead of the entity's .angles field. */ const float RF_NOSHADOW = 32; /* This entity will not cast shadows. Often useful on view models. */ const float RF_FRAMETIMESARESTARTTIMES = 64; /* Specifies that the frame1time, frame2time field are timestamps (denoting the start of the animation) rather than time into the animation. */ +const float RF_FIRSTPERSON = 1024; /* This is basically the opposite of RF_EXTERNALMODEL. Don't draw in third-person or mirrors. */ +#endif +#if defined(CSQC) || defined(MENU) const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ const float IE_KEYUP = 1; /* Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired. */ -const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use in_windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ const float IE_MOUSEABS = 3; /* Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event. */ const float IE_ACCELEROMETER = 4; const float IE_FOCUS = 5; /* Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged. */ const float IE_JOYAXIS = 6; /* Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller. */ const float IE_GYROSCOPE = 7; +const float GGDI_GAMEDIR = 0; /* Used with getgamedirinfo to query the mod's public gamedir. There is often other info that cannot be expressed with just a gamedir name, resulting in dupes or other weirdness. */ +const float GGDI_DESCRIPTION = 1; /* The human-readable title of the mod. Empty when no data is known (ie: the gamedir just contains some maps). */ +const float GGDI_OVERRIDES = 2; /* A list of settings overrides. */ +const float GGDI_LOADCOMMAND = 3; /* The console command needed to actually load the mod. */ +const float GGDI_ICON = 4; /* The mod's Icon path, ready for drawpic. */ +const float GGDI_GAMEDIRLIST = 5; /* A semi-colon delimited list of gamedirs that the mod's content can be loaded through. */ #endif #ifdef SSQC const float CLIENTTYPE_DISCONNECTED = 0; /* Return value from clienttype() builtin. This entity is a player slot that is currently empty. */ @@ -1196,11 +1425,9 @@ const float CLIENTTYPE_NOTACLIENT = 3; /* This entity is not even a player slot. const float FILE_READ = 0; /* The file may be read via fgets to read a single line at a time. */ const float FILE_APPEND = 1; /* Like FILE_WRITE, but writing starts at the end of the file. */ const float FILE_WRITE = 2; /* fputs will be used to write to the file. */ -#if defined(CSQC) || defined(SSQC) const float FILE_READNL = 4; /* Like FILE_READ, except newlines are not special. fgets reads the entire file into a tempstring. */ const float FILE_MMAP_READ = 5; /* The file will be loaded into memory. fgets returns a pointer to the first byte (and will always return the same value for this file). Cast this to your datatype. */ const float FILE_MMAP_RW = 6; /* Like FILE_MMAP_READ, except any changes to the data will be written back to disk once the file is closed. */ -#endif #ifdef CSQC const float MASK_ENGINE = 1; /* Valid as an argument for addentities. If specified, all non-csqc entities will be added to the scene. */ const float MASK_VIEWMODEL = 2; /* Valid as an argument for addentities. If specified, the regular engine viewmodel will be added to the scene. */ @@ -1224,6 +1451,8 @@ const float LFIELD_DIETIME = 14; const float LFIELD_RGBDECAY = 15; const float LFIELD_RADIUSDECAY = 16; const float LFIELD_STYLESTRING = 17; +const float LFIELD_NEARCLIP = 18; +const float LFIELD_OWNER = 19; const float LFLAG_NORMALMODE = 1; const float LFLAG_REALTIMEMODE = 2; const float LFLAG_LIGHTMAP = 4; @@ -1284,12 +1513,20 @@ const float SLIST_TEST_NOTSTARTSWITH = 9; float(string ext) checkextension = #1; /* Checks if the named extension is supported by the running engine. */ -void(string err,...) error = #2; -void(string err,...) objerror = #3; -void(string text,...) print = #4; /* Part of DP_SV_PRINT*/ -void(string text,...) bprint = #5; -void(float clientnum, string text,...) msprint = #6; -void(string text,...) cprint = #7; +void(string err,...) error = #2; /* + Fatal error that will trigger a crash-to-console that users will actually notice. */ + +void(string err,...) objerror = #3; /* + For some reason this has been redefined as non-fatal, and as it won't force the user to look at the console it'll generally be ignored completely so really what's the point? Other than as a convoluted way to remove(self) that is. */ + +void(string text,...) print = #4; /* Part of DP_SV_PRINT + Hello, world. Shoves junk on the console. Hopefully people will bother to read it, maybe. */ + +DEP void(string text,...) bprint = #5; +DEP void(float clientnum, string text,...) msprint = #6; +void(string text,...) cprint = #7; /* + Tries to show the given message in the centre of the screen, assuming that its not obscured by menus. Oh hey look, you're calling it in menuqc! */ + vector(vector) normalize = #8; float(vector) vlen = #9; float(vector) vectoyaw = #10; @@ -1298,7 +1535,7 @@ float() random = #12; void(string,...) localcmd = #13; float(string name) cvar = #14; void(string name, string value) cvar_set = #15; -void(string text) dprint = #16; +void(string text, ...) dprint = #16; string(float) ftos = #17; float(float) fabs = #18; string(vector) vtos = #19; @@ -1310,11 +1547,19 @@ entity(entity start, .string field, string match) find = #24; entity(entity start, .__variant field, __variant match) findfloat = #25; /* Part of DP_QC_FINDFLOAT*/ entity(.string field, string match) findchain = #26; /* Part of DP_QC_FINDCHAIN*/ entity(.__variant field, __variant match) findchainfloat = #27; /* Part of DP_QC_FINDCHAINFLOAT*/ -string(string file) precache_file = #28; +string(string file) precache_file = #28; /* + Attempts to download the named file from the current server, if it isn't found locally. Not very useful as menuqc is normally meant to work before joining servers too. */ + string(string sample) precache_sound = #29; -void() coredump = #30; -void() traceon = #31; -void() traceoff = #32; +void() coredump = #30; /* + Takes a dump, writing the qcvm's state to disk. There are normally easier ways to debug, but I suppose this one still beats print spam. */ + +void() traceon = #31; /* + Enables single-stepping. Its generally easier to just set a breakpoint. */ + +void() traceoff = #32; /* + Disables single-stepping. Which sucks if you started said singlestepping outside of qc. */ + void(entity) eprint = #33; float(float) rint = #34; float(float) floor = #35; @@ -1324,12 +1569,16 @@ float(float) sin = #38; /* Part of DP_QC_SINCOSSQRTPOW*/ float(float) cos = #39; /* Part of DP_QC_SINCOSSQRTPOW*/ float(float) sqrt = #40; /* Part of DP_QC_SINCOSSQRTPOW*/ vector() randomvector = #41; -float(string name, string value, float flags) registercvar = #42; /* Part of DP_REGISTERCVAR*/ +float(string name, string value, float flags) registercvar = #42; /* Part of DP_REGISTERCVAR + Creates the cvar if it didn't already exist. This presents issues for setting those cvars via startup configs of course, and autocvars are easier but I suppose they don't get any flags (which are ignored anyway, of course). */ + float(float,...) min = #43; /* Part of DP_QC_MINMAXBOUND*/ float(float,...) max = #44; /* Part of DP_QC_MINMAXBOUND*/ float(float min,float value,float max) bound = #45; /* Part of DP_QC_MINMAXBOUND*/ float(float,float) pow = #46; /* Part of DP_QC_SINCOSSQRTPOW*/ -void(entity src, entity dst) copyentity = #47; /* Part of DP_QC_COPYENTITY*/ +void(entity src, entity dst) copyentity = #47; /* Part of DP_QC_COPYENTITY + Copies all entity fields from one entity into another (forgetting any that were previously set on the destination). */ + filestream(string filename, float mode) fopen = #48; /* Part of FRIK_FILE*/ void(filestream fhandle) fclose = #49; /* Part of FRIK_FILE*/ string(filestream fhandle) fgets = #50; /* Part of FRIK_FILE*/ @@ -1338,36 +1587,77 @@ float(string) strlen = #52; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string, optional string, optional string, optional string, optional string, optional string, optional string, optional string) strcat = #53; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, float start, float length) substring = #54; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ vector(string) stov = #55; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -string(string) strzone = #56; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -void(string) strunzone = #57; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -float(string) tokenize = #58; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ -string(float) argv = #59; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ -float() isserver = #60; -float() clientcount = #61; -float() clientstate = #62; -void(string map) changelevel = #64; -void(string sample, optional float channel, optional float volume) localsound = #65; -vector() getmousepos = #66; +FTEDEP("Redundant") string(string) strzone = #56; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS + Exists in FTE for compat only, no different from strcat. */ + +FTEDEP("Redundant") void(string) strunzone = #57; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS + Exists in FTE for compat only, does nothing. */ + +float(string) tokenize = #58; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND + Splits up the given string into its different components (what constitutes a token separator is not well defined and has been hacked about with over the years so have fun with that), returning the number of tokens that were found. Call argv(0 through ret-1) to retrieve each individual token. Take care to not use this recursively. */ + +string(float) argv = #59; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND + Returns one of the tokens found via tokenize (and equivelent builtins). */ + +float() isserver = #60; /* + Returns true if the local engine is running a server, and thus cvars and localcmds are shared with said server. */ + +float() clientcount = #61; /* + Returns the maximum number of players on the server. Useless if its a remote server, so its a kinda useless builtin really. */ + +float() clientstate = #62; /* + Tells you whether the client is actually connected to anything. 0 for a dedicated server (but dedicated servers don't normally run menuqc anyway), 2 if connecting or connected to a server (but not necessarily spawned+active), 1 for sitting around idle without trying to connect to anything yet. */ + +void(string map) changelevel = #64; /* + Not really any different from a localcmd, but with proper string escapes. */ + +void(string sample, optional float channel, optional float volume) localsound = #65; /* + Plays a sound, locally. precaching is optional, but recommended. */ + +vector() getmousepos = #66; /* + Obsolete. Return values depend upon the current cursor mode. Implement Menu_InputEvent instead, so you can handle deltas as-is or absolutes if that's all the OS can provide. */ + float(optional float timetype) gettime = #67; -void(string data) loadfromdata = #68; -void(string data) loadfromfile = #69; +void(string s) loadfromdata = #68; /* + Reads a set of entities from the given string. This string should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + +void(string s) loadfromfile = #69; /* + Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ + float(float val, float m) mod = #70; -string(string name) cvar_string = #71; /* Part of DP_QC_CVAR_STRING*/ -void() crash = #72; -void() stackdump = #73; -searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #74; /* Part of DP_QC_FS_SEARCH*/ -void(searchhandle handle) search_end = #75; /* Part of DP_QC_FS_SEARCH*/ -float(searchhandle handle) search_getsize = #76; /* Part of DP_QC_FS_SEARCH*/ -string(searchhandle handle, float num) search_getfilename = #77; /* Part of DP_QC_FS_SEARCH*/ +string(string name) cvar_string = #71; /* Part of DP_QC_CVAR_STRING + Returns the value of a cvar, as a string. */ + +FTEDEP("Call 'error' instead") void() crash = #72; /* + Demonstrates that no program is bug free. */ + +void() stackdump = #73; /* + Prints out the QC's stack, for console-based error reports. */ + +searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3,SB_MULTISEARCH=1<<4,SB_NAMESORT=1<<5} flags, float quiet, optional string package) search_begin = #74; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +void(searchhandle handle) search_end = #75; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +float(searchhandle handle) search_getsize = #76; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +string(searchhandle handle, float num) search_getfilename = #77; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ float(entity) etof = #79; entity(float) ftoe = #80; -float(string) validstring = #81; -float(string str) altstr_count = #82; -string(string str) altstr_prepare = #83; -string(string str, float num) altstr_get = #84; -string(string str, float num, string set) altstr_set = #85; +float(string) validstring = #81; /* + Returns true if str isn't null. In case 'if [not](str)' was configured to test for empty instead of null. */ + +DEP float(string str) altstr_count = #82; /* + Reports how many single-quotes there were in the string, divided by 2. */ + +DEP string(string str) altstr_prepare = #83; /* + Adds markup to escape only single-quotes. Does not add any. */ + +DEP string(string str, float num) altstr_get = #84; /* + Gets the Nth single-quoted token in the input. */ + +DEP string(string str, float num, string setval) altstr_set = #85; /* + Changes the Nth single-quoted token. The setval argument must not contain any single-quotes (use altstr_prepare to ensure this). */ + entity(entity start, .float field, float match) findflags = #87; /* Part of DP_QC_FINDFLAGS*/ entity(.float field, float match) findchainflags = #88; /* Part of DP_QC_FINDCHAINFLAGS*/ +string(string name) cvar_defstring = #89; /* Part of DP_QC_CVAR_DEFSTRING*/ void(entity ent, string mname) setmodel = #90; /* Menuqc-specific version. */ @@ -1391,13 +1681,9 @@ void(entity e, string m) setmodel = #3; /* void(entity e, vector min, vector max) setsize = #4; /* Sets the e's mins and maxs fields. Also relinks collision state, which sets absmin and absmax too. */ -#endif -#ifdef SSQC void() breakpoint = #6; /* Trigger a debugging event. FTE will break into the qc debugger. Other engines may crash with a debug execption. */ -#endif -#if defined(CSQC) || defined(SSQC) float() random = #7; /* Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays. */ @@ -1428,8 +1714,13 @@ entity() spawn = #14; /* Adds a brand new entity into the world! Hurrah, you're now a parent! */ void(entity e) remove = #15; /* - Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After two seconds, the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid. */ + Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After half a second the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid. */ + +#endif +void(entity e) removeinstant = #0:removeinstant; /* + Same thing as the regular remove builtin, but bypasses the half-second rule. The entity slot may be reused instantly. Be CERTAIN that you have no lingering references, because if they're followed they will end up poking an entirely different type of entity! So only use this where you're sure its safe. */ +#if defined(CSQC) || defined(SSQC) void(vector v1, vector v2, float flags, entity ent) traceline = #16; /* Traces a thin line through the world from v1 towards v2. Will not collide with ent, ent.owner, or any entity who's owner field refers to ent. @@ -1453,6 +1744,12 @@ entity(entity start, .string fld, string match) find = #18; /* Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more. If you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep). */ +#endif +entity*(.__variant fld, __variant match, int type=EV_STRING, __out int count) find_list = #0:find_list; /* + Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more. + If you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep). */ + +#if defined(CSQC) || defined(SSQC) string(string s) precache_sound = #19; /* Precaches a sound, making it known to clients and loading it from disk. This builtin (strongly) should be called during spawn functions. This builtin must be called for the sound before the sound builtin is called, or it might not even be heard. */ @@ -1462,22 +1759,25 @@ string(string s) precache_model = #20; /* #endif #ifdef SSQC -void(entity client, string s) stuffcmd = #21; /* +void(entity client, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) stuffcmd = #21; /* Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \n. This builtin is generally considered evil. */ -void(entity client, float flags, string s) stuffcmdflags = #0:stuffcmdflags; /* Part of FTE_QC_STUFFCMDFLAGS +void(entity client, float flags, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) stuffcmdflags = #0:stuffcmdflags; /* Part of FTE_QC_STUFFCMDFLAGS Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \n. This (just as evil) variant allows specifying some flags too. See the STUFFCMD_* constants. */ #endif #if defined(CSQC) || defined(SSQC) entity(vector org, float rad, optional .entity chainfield) findradius = #22; /* - Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. */ + Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. Use findradius_list for an updated alternative without reenterancy issues. */ + +entity*(vector org, float rad, __out int foundcount, int sort=0) findradius_list = #0:findradius_list; /* + Finds all entities linked with a bbox within a distance of the 'org' specified, returning the list as a temp-array (world signifies the end). Unlike findradius, sv_gameplayfix_blowupfallenzombies is ignored (use FL_FINDABLE_NONSOLID instead), while sv_gameplayfix_findradiusdistancetobox and dpcompat_findradiusarealinks are force-enabled. The resulting buffer will automatically be cleaned up by the engine and does not need to be freed. */ #endif #if defined(NQSSQC) -void(string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) bprint = #23; /* +void(string s, optional string/__ s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) bprint = #23; /* NQ: Concatenates all arguments, and prints the messsage on the console of all connected clients. */ #endif @@ -1551,7 +1851,10 @@ float(entity ent) checkbottom = #40; /* Expensive checks to ensure that the entity is actually sitting on something solid, returns true if it is. */ float(vector pos) pointcontents = #41; /* - Checks the given point to see what is there. Returns one of the SOLID_* constants. Just because a spot is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ + Checks the given point to see what is there. Returns one of the CONTENTS_* constants. Just because a point is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ + +__uint(vector pos, optional float worldonly=1) pointcontentsmask = #0:pointcontentsmask; /* + Checks the given point to see what is there. Returns a mask of the CONTENTBIT_* constants. Just because a point is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests. */ float(float) fabs = #43; /* Removes the sign of the float, making it positive if it is negative. */ @@ -1559,7 +1862,7 @@ float(float) fabs = #43; /* #endif #ifdef SSQC vector(entity player, float missilespeed) aim = #44; /* - Returns a direction vector (specifically v_forward on error). This builtin attempts to guess what pitch angle to fire projectiles at for people that don't know about mouselook. Does not affect yaw angles. */ + Returns a tweaked copy of the v_forward vector (must be set! ie: makevectors(player.v_angle) ). This is important for keyboard users (that don't want to have to look up/down the whole time), as well as joystick users (who's aim is otherwise annoyingly imprecise). Only the upwards component of the result will differ from the value of v_forward. The builtin will select the enemy closest to the crosshair within the angle of acos(sv_aim). */ #endif #if defined(CSQC) || defined(SSQC) @@ -1587,13 +1890,27 @@ vector(vector fwd, optional vector up) vectoangles = #51; /* void(float to, float val) WriteByte = #52; /* Writes a single byte into a network message buffer. Typically you will find a more correct alternative to writing arbitary data. 'to' should be one of the MSG_* constants. MSG_ONE must have msg_entity set first. */ -void(float to, float val) WriteChar = #53; -void(float to, float val) WriteShort = #54; -void(float to, float val) WriteLong = #55; -void(float to, float val) WriteCoord = #56; -void(float to, float val) WriteAngle = #57; -void(float to, string val) WriteString = #58; -void(float to, entity val) WriteEntity = #59; +void(float to, float val) WriteChar = #53; /* + Writes a signed value between -128 and 127. */ + +void(float to, float val) WriteShort = #54; /* + Writes a signed value between -32768 and 32767. As an exception, values up to 65535 will not trigger warnings (but readshort will read the result as negative!) */ + +void(float to, float val) WriteLong = #55; /* + Writes a signed 32bit integer. Note that the input argument being of float type limits the resulting integer to a mere 24 consecutive bits of validity. Use WriteInt if you want to write an entire 32bit int without data loss. */ + +void(float to, float val) WriteCoord = #56; /* + Writes a single value suitable for a map coordinate axis. The precision is not strictly specified but is assumed to be of at least 13.3 fixed-point precision (ie: +/-4k with 1/8th precision). */ + +void(float to, float val) WriteAngle = #57; /* + Writes a single value suitable for an angle axis. The precision is not strictly specified but is assumed to be 8bit, giving 256 notches instead of the assumed 360 range passed in. */ + +void(float to, string val) WriteString = #58; /* + Writes a variable-length null terminated string. There are length limits. The codepage is not translated, so be sure that client+server agree on whether utf-8 is being used or not (or just stick to ascii+markup). */ + +void(float to, entity val) WriteEntity = #59; /* + Writes the index of the specified entity (the network data size is not specified). This can be read clientside using the readentitynum builtin, with caveats. */ + #endif #if defined(CSQC) || defined(SSQC) float(float angle) sin = #60; /* Part of DP_QC_SINCOSSQRTPOW @@ -1626,7 +1943,7 @@ void(string mapname, optional string newmapstartspot) changelevel = #70; /* #endif #if defined(CSQC) || defined(SSQC) void(string cvarname, string valuetoset) cvar_set = #72; /* - Instantly sets a cvar to the given string value. */ + Instantly sets a cvar to the given string value. Warning: the resulting string includes apostrophies surrounding the result. You may wish to use sprintf instead. */ #endif #ifdef SSQC @@ -1640,6 +1957,27 @@ string(string str) precache_file2 = #77; #endif #ifdef SSQC void(entity player) setspawnparms = #78; +float() ex_finaleFinished = #0:ex_finaleFinished; /* + Behaviour is undocumented. */ + +void(entity client, string sample) ex_localsound = #0:ex_localsound; /* + Behaviour is undocumented. */ + +void(entity ent, string text, optional string s0, optional string s1, optional string s2, optional string s3, optional string s4, optional string s5) ex_centerprint = #0:ex_centerprint; /* + Remaster: Sends the strings to the client, which will order according to {#}. Also substitutes localised strings for $NAME strings. */ + +void(string s, optional string s0, optional string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6) ex_bprint = #0:ex_bprint; /* + Remaster: Sends the strings to all clients, which will order them according to {#}. Also substitutes localised strings for $NAME strings. */ + +void(entity client, string s, optional string s0, optional string s1, optional string s2, optional string s3, optional string s4, optional string s5) ex_sprint = #0:ex_sprint; /* + Remaster: Sends the strings to the client, which will order according to {#}. Also substitutes localised strings for $NAME strings. */ + +float(entity playerEnt) ex_CheckPlayerEXFlags = #0:ex_CheckPlayerEXFlags; /* + Behaviour is undocumented. */ + +float(float movedist, vector goal) ex_walkpathtogoal = #0:ex_walkpathtogoal; /* + Behaviour is undocumented. */ + void(entity killer, entity killee) logfrag = #79; /* Part of QW_ENGINE*/ #endif #if defined(CSQC) || defined(SSQC) @@ -1651,16 +1989,19 @@ string(entity e, string key) infokey = #80; /* Part of FTE_QC_INFOKEY, QW_ENGINE float(entity e, string key) infokeyf = #0:infokeyf; /* Identical to regular infokey, except returns a float. */ +int(entity e, string key, optional void *outbuf, int outbufsize) infokey_blob = #0:infokey_blob; /* + Retrieves a user's blob size, and optionally writes it to the specified buffer. */ + #endif #if defined(CSQC) || defined(SSQC) float(string) stof = #81; /* Part of FRIK_FILE, FTE_QC_INFOKEY, FTE_STRINGS, QW_ENGINE, ZQ_QC_STRINGS*/ #endif #ifdef SSQC #define unicast(pl,reli) do{msg_entity = pl; multicast('0 0 0', reli?MULITCAST_ONE_R:MULTICAST_ONE);}while(0) -void(vector where, float set) multicast = #82; /* Part of FTE_QC_MULTICAST +void(vector where, float set) multicast = #82; /* Part of EXT_CSQC, FTE_QC_MULTICAST Once the MSG_MULTICAST network message buffer has been filled with data, this builtin is used to dispatch it to the given target, filtering by pvs for reduced network bandwidth. */ -void(entity to, string str) redirectcmd = #101; /* Part of ??MVDSV_BUILTINS +DEP void(entity to, string str) redirectcmd = #101; /* Part of ??MVDSV_BUILTINS Executes a single console command, and sends the text generated by it to the specified player. The command will be executed at the end of the frame once QC is no longer running - you may wish to pre/postfix it with 'echo'. */ #endif @@ -1684,7 +2025,7 @@ void(vector start, vector mins, vector maxs, vector end, float nomonsters, entit vector() randomvec = #91; /* Part of DP_QC_RANDOMVEC Returns a vector with random values. Each axis is independantly a value between -1 and 1 inclusive. */ -vector(vector org) getlight = #92; +vector(vector org) getlight = #92; /* Part of DP_QC_GETLIGHT*/ float(string cvarname, string defaultvalue) registercvar = #93; /* Part of DP_REGISTERCVAR Creates a new cvar on the fly. If it does not already exist, it will be given the specified value. If it does exist, this is a no-op. This builtin has the limitation that it does not apply to configs or commandlines. Such configs will need to use the set or seta command causing this builtin to be a noop. @@ -1725,12 +2066,15 @@ float(string builtinname) builtin_find = #100; /* #endif #if defined(CSQC) || defined(SSQC) float(float value) anglemod = #102; +float(float newangle, float oldangle) anglesub = #0:anglesub; /* + Returns newangle-oldangle, except returning the shortest route around a circle so yields a result between -180 and +180. */ + #endif #ifdef SSQC -void(string slot, string picname, float x, float y, float zone, optional entity player) showpic = #104; /* Part of TEI_SHOWLMP2*/ -void(string slot, optional entity player) hidepic = #105; /* Part of TEI_SHOWLMP2*/ -void(string slot, float x, float y, float zone, optional entity player) movepic = #106; /* Part of TEI_SHOWLMP2*/ -void(string slot, string picname, optional entity player) changepic = #107; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, string picname, float x, float y, float zone, optional entity player) showpic = #104; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, optional entity player) hidepic = #105; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, float x, float y, float zone, optional entity player) movepic = #106; /* Part of TEI_SHOWLMP2*/ +DEP_CSQC void(string slot, string picname, optional entity player) changepic = #107; /* Part of TEI_SHOWLMP2*/ #endif #if defined(CSQC) || defined(SSQC) filestream(string filename, float mode, optional float mmapminsize) fopen = #110; /* Part of FRIK_FILE @@ -1762,13 +2106,16 @@ float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS* string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ string(string s, float start, float length) substring = #116; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ vector(string s) stov = #117; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ -string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS +FTEDEP("Redundant") string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods. */ -void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS +FTEDEP("Redundant") void(string s) strunzone = #119; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing. */ #endif +void*(int bytes) createbuffer = #0:createbuffer; /* + Returns a temporary buffer that can be written to / read from. The buffer will be garbage collected and thus cannot be explicitly freed. Tempstrings and buffer references must not be stored into the buffer as the garbage collector will not scan these. */ + #ifdef SSQC void(string cvar, float val) cvar_setf = #176; #endif @@ -1780,6 +2127,9 @@ float(string modelname, optional float queryonly) getmodelindex = #200; /* Acts as an alternative to precache_model(foo);setmodel(bar, foo); return bar.modelindex; If queryonly is set and the model was not previously precached, the builtin will return 0 without needlessly precaching the model. */ +float(string soundname, optional float queryonly) getsoundindex = #0:getsoundindex; /* + Provides a way to query if a sound is already precached or not. The return value can also be checked for <=255 to see if it'll work over any network protocol. The sound index can also be used for writebyte hacks, but this is discouraged - use SOUNDFLAG_UNICAST instead. */ + __variant(float prnum, string funcname, ...) externcall = #201; /* Part of FTE_MULTIPROGS Directly call a function in a different/same progs by its name. prnum=0 is the 'default' or 'main' progs. @@ -1827,7 +2177,7 @@ void(float sleeptime) sleep = #212; /* Part of FTE_MULTITHREADED void(entity player, string key, string value) forceinfokey = #213; /* Part of FTE_FORCEINFOKEY Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers. */ -void(entity player, string key, void *data, int size) forceinfokeyblob = #0:forceinfokeyblob; /* +void(entity player, string key, void *data, int size) forceinfokeyblob = #0:forceinfokeyblob; /* Part of FTE_INFOBLOBS Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers. */ #endif @@ -1866,7 +2216,7 @@ string(float ccase, float redalpha, float redchars, string str, ...) strconv = # string(float pad, string str1, ...) strpad = #225; /* Part of FTE_STRINGS Pads the string with spaces, to ensure its a specific length (so long as a fixed-width font is used, anyway). If pad is negative, the spaces are added on the left. If positive the padding is on the right. */ -string(infostring old, string key, string value) infoadd = #226; /* Part of FTE_STRINGS +infostring(infostring old, string key, string value) infoadd = #226; /* Part of FTE_STRINGS Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \ character. */ string(infostring info, string key) infoget = #227; /* Part of FTE_STRINGS @@ -1889,14 +2239,14 @@ string(string s) strtrim = #0:strtrim; /* Trims the whitespace from the start+end of the string. */ #if defined(CSQC) || defined(SSQC) -void() calltimeofday = #231; /* Part of FTE_CALLTIMEOFDAY +__deprecated("Use strftime.") void() calltimeofday = #231; /* Part of FTE_CALLTIMEOFDAY Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv. timeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue) The strftime builtin is more versatile and less weird. */ #endif #ifdef SSQC -void(float num, float type, .__variant fld) clientstat = #232; /* +void(float num, float type, .__variant fld) clientstat = #232; /* Part of EXT_CSQC Specifies what data to use in order to send various stats, in a client-specific way. 'num' should be a value between 32 and 127, other values are reserved. 'type' must be set to one of the EV_* constants, one of EV_FLOAT, EV_STRING, EV_INTEGER, EV_ENTITY. @@ -1908,6 +2258,9 @@ void(float num, float type, string name) globalstat = #233; /* void(float num, float type, __variant *address) pointerstat = #0:pointerstat; /* Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, address however, is the address of the variable you would like to use (pass &foo). */ +void(entity ent, vector sendflags, entity unicastplayer) setsendneeded = #0:setsendneeded; /* + Flags the entity as needing to be resent. This builtin allows for more bits than supported by the SendEntity field, as well as allows flagging sends to specific players. */ + float(entity player) isbackbuffered = #234; /* Part of FTE_ISBACKBUFFERED Returns if the given player's network buffer will take multiple network frames in order to clear. If this builtin returns non-zero, you should delay or reduce the amount of reliable (and also unreliable) data that you are sending to that client. */ @@ -1925,6 +2278,11 @@ float(string shadername, optional string defaultshader, ...) shaderforname = #23 If the shader could not be loaded from disk (missing file or ruleset_allow_shaders 0), it will be created from the 'defaultshader' string if specified, or a 'skin shader' default will be used. defaultshader if not empty should include the outer {} that you would ordinarily find in a shader. */ +#endif +#ifdef CSQC +void(string shadername, string replacement, float timeoffset) remapshader = #0:remapshader; /* + All surfaces drawn with the specified shader will instead be drawn using the specified replacement shader. Shaders can be remapped to something else later by using the same source shadername. This is mostly useful for worldmodel surfaces (eg showing which team is currently winning). Entities should generally use setcustomskin or forceshader instead. Remaps will be forgotten on vid_reload, but can be reapplied via CSQC_RendererRestarted. */ + #endif #if defined(CSQC) || defined(SSQC) void(vector org, optional float count) te_bloodqw = #239; /* Part of FTE_TE_STANDARDEFFECTBUILTINS*/ @@ -1938,7 +2296,7 @@ float(vector viewpos, entity entity) checkpvs = #240; /* Part of FTE_QC_CHECKPVS #ifdef SSQC entity(string match, optional float matchnum) matchclientname = #241; /* Part of FTE_QC_MATCHCLIENTNAME*/ #endif -void(string destaddress, string content) sendpacket = #242; /* Part of FTE_QC_SENDPACKET +float(string destaddress, string content) sendpacket = #242; /* Part of FTE_QC_SENDPACKET Sends a UDP packet to the specified destination. Note that the payload will be prefixed with four 255 bytes as a sort of security feature. */ #ifdef CSQC @@ -1960,6 +2318,51 @@ float(float serveridx, float queryidx, float row, float column) sqlreadfloat = # int(float serveridx, float queryidx, float row, float column, __variant *ptr, int maxsize) sqlreadblob = #0:sqlreadblob; string(float serveridx, __variant *ptr, int maxsize) sqlescapeblob = #0:sqlescapeblob; #endif +typedef struct json_s *json_t; +accessor jsonnode : json_t; +jsonnode(string) json_parse = #0:json_parse; /* + Parses the given JSON string. */ + +void(jsonnode) json_free = #0:json_free; /* + Frees a json tree and all of its children. Must only be called on the root node. */ + +enum json_type_e : int +{ + JSON_TYPE_STRING, + JSON_TYPE_NUMBER, + JSON_TYPE_OBJECT, + JSON_TYPE_ARRAY, + JSON_TYPE_TRUE, + JSON_TYPE_FALSE, + JSON_TYPE_NULL +}; +json_type_e(jsonnode node) json_get_value_type = #0:json_get_value_type; /* + Get type of a JSON value. */ + +int(jsonnode node) json_get_integer = #0:json_get_integer; /* + Get an integer from a json node. */ + +float(jsonnode node) json_get_float = #0:json_get_float; /* + Get a float from a json node. */ + +string(jsonnode node) json_get_string = #0:json_get_string; /* + Get a string from a value. Returns a null string if its not a string type. */ + +jsonnode(jsonnode node, string) json_find_object_child = #0:json_find_object_child; /* + Find a child of a json object by name. Returns NULL if the handle couldn't be found. */ + +int(jsonnode node) json_get_length = #0:json_get_length; /* + Get the length of a json array or object. Returns 0 if its not an array. */ + +jsonnode(jsonnode node, int childindex) json_get_child_at_index = #0:json_get_child_at_index; /* + Get the nth child of a json array or object. Returns NULL if the index is out of range. */ + +string(jsonnode node) json_get_name = #0:json_get_name; /* + Gets the object's name (useful if you're using json_get_child_at_index to walk an object's children for whatever reason). */ + +string(string javascript) js_run_script = #0:js_run_script; /* + Runs the provided javascript snippet. This builtin functions only in emscripten builds, returning a null string on other systems (or if the script evaluates to null). */ + #if defined(CSQC) || defined(SSQC) int(string) stoi = #259; /* Part of FTE_QC_INTCONV Converts the given string into a true integer. Base 8, 10, or 16 is determined based upon the format of the string. */ @@ -1977,14 +2380,18 @@ string(int) htos = #262; /* Part of FTE_QC_INTCONV int(float) ftoi = #0:ftoi; /* Part of FTE_QC_INTCONV Converts the given float into a true integer without depending on extended qcvm instructions. */ -float(int) itof = #0:itof; /* Part of FTE_QC_INTCONV - Converts the given true integer into a float without depending on extended qcvm instructions. */ +float(int, optional float shift, float mask=24) itof = #0:itof; /* Part of FTE_QC_INTCONV + Converts the given true integer into a float without depending on extended qcvm instructions. If shift and mask are specified then only specific parts of the integer will be cast to float. */ #if defined(CSQC) || defined(SSQC) float(float modlindex, optional float useabstransforms) skel_create = #263; /* Part of FTE_CSQC_SKELETONOBJECTS Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model. eg: self.skeletonobject = skel_create(self.modelindex); */ +float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS + Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object. + If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */ + typedef struct { int sourcemodelindex; /*frame data will be imported from this model, bones must be compatible*/ @@ -1999,10 +2406,6 @@ typedef struct float subblend[2]; float controllers[5]; } skelblend_t; -float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS - Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object. - If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */ - float(float skel, int numblends, skelblend_t *weights, int structsize) skel_build_ptr = #0:skel_build_ptr; /* Like skel_build, but slightly simpler. */ @@ -2049,14 +2452,17 @@ float(float modidx, string framename) frameforname = #276; /* Part of FTE_CSQC_S float(float modidx, float framenum) frameduration = #277; /* Part of FTE_CSQC_SKELETONOBJECTS Retrieves the duration (in seconds) of the specified framegroup. */ +float(float modidx, int actionid) frameforaction = #0:frameforaction; /* + Returns a random frame/animation for the specified mod-defined action, or -1 if no animations have the specified action. */ + void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback) processmodelevents = #0:processmodelevents; /* Part of FTE_GFX_MODELEVENTS Calls a callback for each event that has been reached. Basetime is set to targettime. */ -float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data) getnextmodelevent = #0:getnextmodelevent; /* +float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data) getnextmodelevent = #0:getnextmodelevent; /* Part of FTE_GFX_MODELEVENTS Reports the next event within a model's animation. Returns a boolean if an event was found between basetime and targettime. Writes to basetime,code,data arguments (if an event was found, basetime is set to the event's time, otherwise to targettime). WARNING: this builtin cannot deal with multiple events with the same timestamp (only the first will be reported). */ -float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data) getmodeleventidx = #0:getmodeleventidx; /* +float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data) getmodeleventidx = #0:getmodeleventidx; /* Part of FTE_GFX_MODELEVENTS Reports an indexed event within a model's animation. Writes to timestamp,code,data arguments on success. Returns false if the animation/event/model was out of range/invalid. Does not consider looping animations (retry from index 0 if it fails and you know that its a looping animation). This builtin is more annoying to use than getnextmodelevent, but can be made to deal with multiple events with the exact same timestamp. */ #endif @@ -2066,7 +2472,7 @@ vector(vector v1, vector v2) crossproduct = #0:crossproduct; /* Part of FTE_QC_C #if defined(CSQC) || defined(SSQC) float(entity pusher, vector move, vector amove) pushmove = #0:pushmove; -void(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /* Part of FTE_TERRAIN_MAP +__variant(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /* Part of FTE_TERRAIN_MAP Realtime terrain editing. Actions are the TEREDIT_ constants. */ typedef struct @@ -2100,15 +2506,64 @@ int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoin int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults) brush_findinvolume = #0:brush_findinvolume; /* Part of FTE_RAW_MAP Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice. */ +typedef struct +{ + string shadername; + int contents; + int cpwidth; + int cpheight; + int tesswidth; + int tessheight; + vector texinfo;/*scalex,y,rot*/ +} patchinfo_t; +typedef struct +{ + vector xyz; + vector rgb; float a; + float s, t; +} patchvert_t; +#define patch_delete(modelidx,patchidx) brush_delete(modelidx,patchidx) +int(float modelidx, int patchid, patchvert_t *out_controlverts, int maxcp, patchinfo_t *out_info) patch_getcp = #0:patch_getcp; /* + Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error. */ + +int(float modelidx, int patchid, patchvert_t *out_verts, int maxverts, __out patchinfo_t out_info) patch_getmesh = #0:patch_getmesh; /* + Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error. */ + +int(float modelidx, int oldpatchid, patchvert_t *in_controlverts, patchinfo_t in_info) patch_create = #0:patch_create; /* + Inserts a new patch into the model. Return value is the new patch's id. */ + +typedef struct +{ + vector dest; + int linkflags; + float radius; +} nodeslist_t; +void(entity ent, vector dest, int denylinkflags, void(entity ent, vector dest, int numnodes, nodeslist_t *nodelist) callback) route_calculate = #0:route_calculate; /* + Begin calculating a route. The callback function will be called once the route has finished being calculated. The route must be memfreed once it is no longer needed. The route must be followed in reverse order (ie: the first node that must be reached is at index numnodes-1). If no route is available then the callback will be called with no nodes. */ + void(optional entity ent, optional vector neworigin) touchtriggers = #279; /* Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity. */ #endif #ifdef SSQC -void(float buf, float fl) WriteFloat = #280; +void(float buf, float fl) WriteFloat = #280; /* + Writes a full 32bit float without any data conversions at all, for full precision. */ + +void(float buf, __double dbl) WriteDouble = #0:WriteDouble; /* + Writes a full 64bit double-precision float without any data conversions at all, for excessive precision. */ + +void(float buf, int fl) WriteInt = #0:WriteInt; /* + Writes all 4 bytes of a 32bit integer without truncating to a float first before converting back to an int (unlike WriteLong does, but otherwise equivelent). */ + +void(float buf, __int64 fl) WriteInt64 = #0:WriteInt64; /* + Writes all 8 bytes of a 64bit integer. This uses variable-length coding and will send only a single byte for any value between -64 and 63. */ + +void(float buf, __uint64 fl) WriteUInt64 = #0:WriteUInt64; /* + Writes all 8 bytes of a 64bit unsigned integer. Values between 0-127 will be sent in a single byte. */ + #endif #if defined(CSQC) || defined(SSQC) -float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* +float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* Part of FTE_QC_RAGDOLL_WIP Updates the skeletal object attached to the entity according to its origin and other properties. if animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results. If dollcmd is not set, the ragdoll will update (this should be done each frame). @@ -2121,10 +2576,10 @@ float(entity skelent, string dollcmd, float animskel) skel_ragupdate = #281; /* animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body). enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter. */ -float*(float skel) skel_mmap = #282; /* +float*(float skel) skel_mmap = #282; /* Part of FTE_QC_RAGDOLL_WIP Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly). */ -void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up) skel_set_bone_world = #283; /* +void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up) skel_set_bone_world = #283; /* Part of FTE_QC_RAGDOLL_WIP Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use. */ string(float modidx, float framenum) frametoname = #284; @@ -2134,18 +2589,24 @@ float(float resourcetype, float tryload, string resourcename) resourcestatus = # #endif hashtable(float tabsize, optional float defaulttype) hash_createtab = #287; /* Part of FTE_QC_HASHTABLES - Creates a hash table object with at least 'tabsize' slots. hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return). */ + Creates a hash table object. + The tabsize argument is a performance hint and should generally be set to something similar to the number of entries expected, typically a power of two assumption. Too high simply wastes memory, too low results in extra string compares but no actual bugs. + defaulttype must be one of the EV_* values, if specified. + The hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return). */ void(hashtable table) hash_destroytab = #288; /* Part of FTE_QC_HASHTABLES Destroys a hash table object. */ void(hashtable table, string name, __variant value, optional float typeandflags) hash_add = #289; /* Part of FTE_QC_HASHTABLES Adds the given key with the given value to the table. - If flags&HASH_REPLACE, the old value will be removed, if not set then multiple values may be added for a single key, they won't overwrite. - The type argument describes how the value should be stored and saved to files. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games. */ + If flags&HASH_REPLACE, the old value will be removed, otherwise if flags&HASH_ADD then a duplicate entry will be added with a second value (can be obtained via hash_get's index argument). + The type argument describes how the value should be stored in saved games, as well as providing constraints with the hash_get function. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games - be sure to be explicit with EV_STRING where appropriate because tempstrings may be reclaimed before the get (especially with saved games or table 0). */ __variant(hashtable table, string name, optional __variant deflt, optional float requiretype, optional float index) hash_get = #290; /* Part of FTE_QC_HASHTABLES - looks up the specified key name in the hash table. returns deflt if key was not found. If stringsonly=1, the return value will be in the form of a tempstring, otherwise it'll be the original value argument exactly as it was. If requiretype is specified, then values not of the specified type will be ignored. Hurrah for multiple types with the same name. */ + Looks up the specified key name in the hash table. Returns deflt if the key was not found. + If requiretype is specified then the function will only consider entries of the matching type (allowing you to store both flags+strings under a single name without getting confused). + If index is specified then the function will ignore the first N entries with the same key (applicable only with entries added using HASH_ADD, not HASH_REPLACE), allowing you to store multiple entries. Keep querying higher indexes starting from 0 until it returns the deflt value. + You will usually need to cast the result of this function to a real datatype. */ __variant(hashtable table, string name) hash_delete = #291; /* Part of FTE_QC_HASHTABLES removes the named key. returns the value of the object that was destroyed, or 0 on error. */ @@ -2189,6 +2650,9 @@ void(float mask) addentities = #301; /* void(entity ent) addentity = #302; /* Copies the entity fields into a new rentity for later rendering via addscene. */ +void(entity ent, vector lightdir, vector lightavg, vector lightrange, int reserved1=0,void*reserved2=0) addentity_lighting = #0:addentity_lighting; /* + Copies the entity fields into a new rentity for later rendering via addscene, but with explicit lighting info. */ + #endif #ifdef CSQC void(entity ent) removeentity = #0:removeentity; /* @@ -2226,8 +2690,13 @@ void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #3 Specifies a polygon vertex with its various properties. */ void() R_EndPolygon = #308; /* - Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader. */ + Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon again if you wish to draw another polygon with the same shader. */ + +#ifdef CSQC +void(float radius, vector texcoordbias) R_EndPolygonRibbon = #0:R_EndPolygonRibbon; /* + Ends the current primitive and duplicates each vertex sideways into a ribbon. The texcoordbias will be added to each duplicated vertex allowing for regular 2d textures. At least 2 verticies must have been specified. You do not need to call beginpolygon again if you wish to draw another polygon with the same shader. */ +#endif #if defined(CSQC) || defined(MENU) #define getviewprop getproperty __variant(float property) getproperty = #309; /* @@ -2243,8 +2712,8 @@ vector (vector v) project = #311; /* #endif #if defined(CSQC) || defined(MENU) -void(vector pos, vector size, float alignflags, string text) drawtextfield = #0:drawtextfield; /* - Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3. */ +float(vector pos, vector size, float alignflags, string text) drawtextfield = #0:drawtextfield; /* + Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3. Returns the total number of lines. */ #endif #ifdef CSQC @@ -2254,27 +2723,30 @@ void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional fl float(string name) iscachedpic = #316; /* Checks to see if the image is currently loaded. Engines might lie, or cache between maps. */ -string(string name, optional float trywad) precache_pic = #317; /* - Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension. */ +string(string name, optional float flags) precache_pic = #317; /* + Forces the engine to load the named image. Flags are a bitmask of the PRECACHE_PIC_* flags. */ #endif #if defined(CSQC) || defined(MENU) void(string imagename, int width, int height, void *pixeldata, optional int datasize, optional int format) r_uploadimage = #0:r_uploadimage; /* Part of FTE_CSQC_RAWIMAGES - Updates a texture with the specified rgba data. Will be created if needed. If blobsize is specified then the image is decoded (eg .ktx or .dds data) instead of being raw R8G8B8A data. You'll typically want shaderforname to also generate a shader to use the texture. */ + Updates a texture with the specified rgba data (uploading it to the gpu). Will be created if needed. If datasize is specified then the image is decoded (eg .ktx or .dds data) instead of being raw R8G8B8A data. You'll typically want shaderforname to also generate a shader to use the texture. */ -int*(string filename, __out int width, __out int height) r_readimage = #0:r_readimage; /* Part of FTE_CSQC_RAWIMAGES - Reads and decodes an image from disk, providing raw R8G8B8A pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it. */ +int*(string filename, __out int width, __out int height, __out int format) r_readimage = #0:r_readimage; /* Part of FTE_CSQC_RAWIMAGES + Reads and decodes an image from disk, providing raw R8G8B8A8 pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it. */ #endif #ifdef CSQC #define draw_getimagesize drawgetimagesize vector(string picname) drawgetimagesize = #318; /* - Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution. */ + Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution. WARNING: this function may be slow if used without or directly after its initial precache_pic. */ void(string name) freepic = #319; /* Tells the engine that the image is no longer needed. The image will appear to be new the next time its needed. */ -float(vector position, float character, vector size, vector rgb, float alpha, optional float drawflag) drawcharacter = #320; /* +string(string modelname, int frame, float frametime) spriteframe = #0:spriteframe; /* + Obtains a suitable shader name to draw a sprite's shader via drawpic/R_BeginPolygon/etc, instead of needing to create a scene. */ + +float(vector position, float character, vector size='8 8', vector rgb='1 1 1', float alpha=1, optional float drawflag=0) drawcharacter = #320; /* Draw the given quake character at the given position. If flag&4, the function will consider the char to be a unicode char instead (or display as a ? if outside the 32-127 range). size should normally be something like '8 8 0'. @@ -2288,7 +2760,7 @@ float(vector position, string text, vector size, vector rgb, float alpha, option If UTF-8 is globally enabled in the engine, then that encoding is used (without additional markup), otherwise it is raw quake chars. Software engines may assume a size of '8 8 0', rgb='1 1 1', alpha=1, flag&3=0, but it is not an error to draw out of the screen. */ -float(vector position, string pic, vector size, vector rgb, float alpha, optional float drawflag) drawpic = #322; /* +float(vector position, string pic, vector size, vector rgb='1 1 1', float alpha=1, optional float drawflag=0) drawpic = #322; /* Draws an shader within the given 2d screen box. Software engines may omit support for rgb+alpha, but must support rescaling, and must clip to the screen without crashing. */ float(vector position, vector size, vector rgb, float alpha, optional float drawflag) drawfill = #323; /* @@ -2302,10 +2774,10 @@ void(float x, float y, float width, float height) drawsetcliparea = #324; /* void(void) drawresetcliparea = #325; /* Reverts the scissor/clip area to the whole screen. */ -float(vector position, string text, vector size, vector rgb, float alpha, float drawflag) drawstring = #326; /* +float(vector position, string text, vector size='8 8', vector rgb='1 1 1', float alpha=1, float drawflag=0) drawstring = #326; /* Draws a string, interpreting markup and recolouring as appropriate. */ -float(string text, float usecolours, optional vector fontsize) stringwidth = #327; /* +float(string text, float usecolours, vector fontsize='8 8') stringwidth = #327; /* Calculates the width of the screen in virtual pixels. If usecolours is 1, markup that does not affect the string width will be ignored. Will always be decoded as UTF-8 if UTF-8 is globally enabled. If the char size is not specified, '8 8 0' will be assumed. */ @@ -2324,27 +2796,30 @@ void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector tx #ifdef CSQC #define getstati_punf(stnum) (float)(__variant)getstati(stnum) int(float stnum) getstati = #330; /* - Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat. Use getstati_punf if you wish to type-pun a float stat as an int to avoid truncation issues in DP. */ + Retrieves the full precision of a stat registered as EV_INTEGER. */ #define getstatbits getstatf float(float stnum, optional float firstbit, optional float bitcount) getstatf = #331; /* - Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat (converted into a float, so there are no VM dependancies). */ + Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, then this builtin acts as getstati combined with itof, and which should be used for STAT_ITEMS (but not other stats). */ string(float stnum) getstats = #332; /* Retrieves the value of the given EV_STRING stat, as a tempstring. Older engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but FTE Quake uses a separate namespace for string stats and has a much higher length limit. */ __variant(float playernum, float statnum, float stattype) getplayerstat = #0:getplayerstat; /* - Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits. */ + Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. Return value matches the specified EV_ stattype. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits. */ void(entity e, float mdlindex) setmodelindex = #333; /* Sets a model by precache index instead of by name. Otherwise identical to setmodel. */ -string(float mdlindex) modelnameforindex = #334; /* - Retrieves the name of the model based upon a precache index. This can be used to reduce csqc network traffic by enabling model matching. */ - #endif #if defined(CSQC) || defined(SSQC) +string(float mdlindex) modelnameforindex = #334; /* + Retrieves the name of the model based upon a precache index. This can be used to reduce csqc network traffic by enabling model matching (with getmodelindex). */ + +string(float sndindex) soundnameforindex = #0:soundnameforindex; /* + Retrieves the name of the sound based upon a precache index. This can be used to reduce csqc network traffic by enabling sound matching (with getsoundindex). */ + float(string effectname) particleeffectnum = #335; /* Part of DP_ENT_TRAILEFFECTNUM, FTE_SV_POINTPARTICLES Precaches the named particle effect. If your effect name is of the form 'foo.bar' then particles/foo.cfg will be loaded by the client if foo.bar was not already defined. Different engines will have different particle systems, this specifies the QC API only. */ @@ -2373,7 +2848,7 @@ string(float keynum) keynumtostring = #340; /* #endif #ifdef MENU -string(float keynum) keynumtostring_csqc = #340; /* +DEP string(float keynum) keynumtostring_csqc = #340; /* Returns a hunam-readable name for the given keycode, as a tempstring. */ #endif @@ -2383,7 +2858,7 @@ float(string keyname) stringtokeynum = #341; /* #endif #ifdef MENU -float(string keyname) stringtokeynum_csqc = #341; /* +DEP float(string keyname) stringtokeynum_csqc = #341; /* Looks up the key name in the same way that the bind command would, returning the keycode for that key. */ #endif @@ -2400,8 +2875,15 @@ float(float effective) getcursormode = #0:getcursormode; /* #endif #ifdef CSQC vector() getmousepos = #344; /* - Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods. */ + Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent instead for such things in csqc mods. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(vector newpos) setmousepos = #0:setmousepos; /* + Warps the mouse cursor to the given location. Should normally only be done following setcursormode(TRUE,...). The warp MAY be visible through *_InputEvent, but normally be seen as an IE_ABSMOUSE event anyway. Not all systems support cursor warping (or even cursors), so this is a hint only and you should not depend upon it. */ +#endif +#ifdef CSQC float(float inputsequencenum) getinputstate = #345; /* Looks up an input frame from the log, setting the input_* globals accordingly. The sequence number range used for prediction should normally be servercommandframe < sequence <= clientcommandframe. @@ -2424,16 +2906,30 @@ string(float playernum, string keyname) getplayerkeyvalue = #348; /* float(float playernum, string keyname, optional float assumevalue) getplayerkeyfloat = #0:getplayerkeyfloat; /* Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ -int(float playernum, string keyname, optional void *outptr, int size) getplayerkeyblob = #0:getplayerkeyblob; /* - Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ +int(float playernum, string keyname, optional void *outptr, int size) getplayerkeyblob = #0:getplayerkeyblob; /* Part of FTE_INFOBLOBS + Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ + +#endif +#if defined(CSQC) || defined(MENU) +void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; /* + Change a userinfo key for the specified local player seat, equivelent to the setinfo console command. The server will normally forward the setting to other clients. */ + +string(float seat, string keyname) getlocaluserinfo = #0:getlocaluserinfo; /* + Reads a local userinfo key for the specified local player seat. This is not quite the same as getplayerkeyvalue, due to latency and possible serverside filtering. */ + +void(float seat, string keyname, void *outptr, int size) setlocaluserinfoblob = #0:setlocaluserinfoblob; /* Part of FTE_INFOBLOBS + Sets the userinfo key to a blob that may contain nulls etc. Keys with a leading underscore will be visible to only the server (for user-specific binary settings). */ + +int(float seat, string keyname, void *outptr, int maxsize) getlocaluserinfoblob = #0:getlocaluserinfoblob; /* Part of FTE_INFOBLOBS + Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ #endif #ifdef SSQC int(string keyname, optional void *outptr, int size) getlocalinfo = #0:getlocalinfo; /* - Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ + Obtains a copy of a data blob (with spaces) from the server's private localinfo. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there. */ void(string keyname, optional void *outptr, int size) setlocalinfo = #0:setlocalinfo; /* - Changes the server's localinfo. This data will be available for the following map, and will *usually* reload with saved games. */ + Changes the server's private localinfo. This data will be available for the following map, and will *usually* reload with saved games. */ #endif #if defined(CSQC) || defined(MENU) @@ -2477,28 +2973,26 @@ void(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t) setup_re Reconfigures a reverb slot for weird effects. Slot 0 is reserved for no effects. Slot 1 is reserved for underwater effects. Reserved slots will be reinitialised on snd_restart, but can otherwise be changed. These reverb slots can be activated with SetListener. Note that reverb will currently only work when using OpenAL. */ #endif -#if defined(CSQC) || defined(MENU) void(string cmdname) registercommand = #352; /* Register the given console command, for easy console use. - Console commands that are later used will invoke CSQC_ConsoleCommand. */ + Console commands that are later used will invoke CSQC_ConsoleCommand/m_consolecommand/ConsoleCmd according to module. */ -#endif -#if defined(CSQC) || defined(SSQC) float(entity ent) wasfreed = #353; /* - Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust. */ + Quickly check to see if the entity is currently free. This function is only valid during the half-second non-reuse window, after that it may give bad results. Try one second to make it more robust. */ +#if defined(CSQC) || defined(SSQC) string(string key) serverkey = #354; /* - Look up a key in the server's public serverinfo string */ + Look up a key in the server's public serverinfo string. If the key contains binary data then it will be truncated at the first null. */ float(string key, optional float assumevalue) serverkeyfloat = #0:serverkeyfloat; /* Version of serverkey that returns the value as a float (which avoids tempstrings). */ -int(int buf, string key, optional void *ptr, int size) serverkeyblob = #0:serverkeyblob; /* - Version of serverkey that can obtain entire serverinfo, localinfo, or (local)userinfo blobs. Returns blob size */ +int(string key, optional void *ptr, int maxsize) serverkeyblob = #0:serverkeyblob; /* Part of FTE_INFOBLOBS + Version of serverkey that returns data as a blob (ie: binary data that may contain nulls). Returns the full blob size, even if truncated (pass maxsize=0 to query required storage). */ #endif #ifdef SSQC -void(int buf, string key, void *ptr, optional int size) setserverkey = #0:setserverkey; /* +void(string key, void *ptr, optional int size) setserverkey = #0:setserverkey; /* Changes the server's serverinfo. */ #endif @@ -2516,22 +3010,52 @@ float(string s) findfont = #356; /* Part of DP_GFX_FONTS Looks up a named font slot. Matches the actual font name as a last resort. */ float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357; /* Part of DP_GFX_FONTS - too convoluted for me to even try to explain correct usage. Try drawfont = loadfont("", "cour", "16", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows.. */ + too convoluted for me to even try to explain correct usage. Try drawfont = loadfont("", "cour", "16", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high) ('cour' requires mscorefonts installed in linux). Additionally you can add "outline=1" as an extra token in the sizes string, to have more readable outlined fonts. */ #endif #ifdef CSQC void(string evname, string evargs, ...) sendevent = #359; /* Invoke CSEv_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors. */ -float() readbyte = #360; -float() readchar = #361; -float() readshort = #362; -float() readlong = #363; -float() readcoord = #364; -float() readangle = #365; -string() readstring = #366; -float() readfloat = #367; -float() readentitynum = #368; +float() readbyte = #360; /* + Reads an unsigned 8-bit value, pair with WriteByte. */ + +float() readchar = #361; /* + Reads a signed 8-bit value. Paired with WriteChar. */ + +float() readshort = #362; /* + Reads a signed 16-bit value. Paired with WriteShort. */ + +float() readlong = #363; /* + Reads a signed 32-bit value. Paired with WriteLong or WriteInt. */ + +float() readcoord = #364; /* + Reads a value matching the unspecified precision written ONLY by WriteCoord. */ + +float() readangle = #365; /* + Reads a value matching the unspecified precision written ONLY by WriteAngle. */ + +string() readstring = #366; /* + Reads a null-terminated string. */ + +float() readfloat = #367; /* + Reads a float without any truncation nor conversions. Data MUST have originally been written with WriteFloat. */ + +__double() readdouble = #0:readdouble; /* + Reads a double-precision float without any truncation nor conversions. Data MUST have originally been written with WriteDouble. */ + +int() readint = #0:readint; /* + Reads a 32bit int without any conversions to float, otherwise interchangable with readlong. */ + +__int64() readint64 = #0:readint64; /* + Reads a 64bit signed int. Paired with WriteInt64. */ + +__uint64() readuint64 = #0:readuint64; /* + Reads a 64bit unsigned int. Paired with WriteUInt64. */ + +float() readentitynum = #368; /* + Reads the serverside index of an entity, paired with WriteEntity. There may be nothing else known about the entity yet, so the result typically needs to be saved as-is and re-looked up each frame. This can be done via getentity(NUM, GE_*) for non-csqc ents, or findentity(world,entnum,NUM) - both of which can fail due to latency. */ + float(string modelname, float(float isnew) updatecallback, float flags) deltalisten = #371; /* Specifies a per-modelindex callback to listen for engine-networking entity updates. Such entities are automatically interpolated by the engine (unless flags specifies not to). The various standard entity fields will be overwritten each frame before the updatecallback function is called. */ @@ -2558,10 +3082,10 @@ void(entity e, string skinfilename, optional string skindata) setcustomskin = #3 #endif #ifdef CSQC -float(string skinfilename, optional string skindata) loadcustomskin = #377; /* +float(string skinfilename, optional string skindata) loadcustomskin = #377; /* Part of FTE_QC_CUSTOMSKINS Creates a new skin object and returns it. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format: - surfacename,shadername - makes the named surface use the named shader - replace "surfacename" "shadername" - same. + surfacename,shadername - makes the named surface use the named shader (legacy format for compat with q3) + replace "surfacename" "shadername" - non-legacy equivalent. qwskin "foo" - use an unmodified quakeworld player skin (including crop+repalette rules) q1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red q1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue @@ -2569,12 +3093,24 @@ float(string skinfilename, optional string skindata) loadcustomskin = #377; /* The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line. Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). Must be matched with a releasecustomskin call later, and is pointless without applycustomskin. */ -void(entity e, float skinobj) applycustomskin = #378; /* +void(entity e, float skinobj) applycustomskin = #378; /* Part of FTE_QC_CUSTOMSKINS Updates the entity's custom skin (refcounted). */ -void(float skinobj) releasecustomskin = #379; /* +void(float skinobj) releasecustomskin = #379; /* Part of FTE_QC_CUSTOMSKINS Lets the engine know that the skin will no longer be needed. Thanks to refcounting any ents with the skin already applied will retain their skin until later changed. It is valid to destroy a skin just after applying it to an ent in the same function that it was created in, as the skin will only be destroyed once its refcount rops to 0. */ +void(float devid, float amp_low, float amp_high, float duration) gp_rumble = #0:gp_rumble; /* + Sends a single rumble event to the game-pad specified in devid. Every time you call this, the previous effect is cancelled out. */ + +void(float devid, float left, float right, float duration) gp_rumbletriggers = #0:gp_rumbletriggers; /* + Makes the analog triggers rumble of the specified game-pad, like gp_rumble() one call cancels out the previous one on the device. */ + +void(float devid, vector color) gp_setledcolor = #0:gp_setledcolor; /* + Updates the game-pad LED color. */ + +void(float devid, /*const*/ void *data, int size) gp_settriggerfx = #0:gp_settriggerfx; /* + Sends a specific effect packet to the controller. On the PlayStation 5's DualSense that can adjust the tension on the analog triggers. */ + #endif __variant*(int size) memalloc = #384; /* Part of FTE_MEMALLOC Allocate an arbitary block of memory */ @@ -2613,13 +3149,9 @@ void(string conname, vector pos, vector size, float fontsize) con_draw = #393; / float(string conname, float inevtype, float parama, float paramb, float paramc) con_input = #394; /* Part of FTE_CSQC_ALTCONSOLES Forwards input events to the named console. Mouse updates should be absolute only. */ -#endif -#ifdef CSQC void(string newcaption) setwindowcaption = #0:setwindowcaption; /* Part of FTE_CSQC_WINDOWCAPTION Replaces the title of the game window, as seen when task switching or just running in windowed mode. */ -#endif -#if defined(CSQC) || defined(MENU) float() cvars_haveunsaved = #0:cvars_haveunsaved; /* Returns true if any archived cvar has an unsaved value. */ @@ -2627,13 +3159,33 @@ float() cvars_haveunsaved = #0:cvars_haveunsaved; /* float(entity e, float nowreadonly) entityprotection = #0:entityprotection; /* Changes the protection on the specified entity to protect it from further edits from QC. The return value is the previous setting. Note that this can be used to unprotect the world, but doing so long term is not advised as you will no longer be able to detect invalid entity references. Also, world is not networked, so results might not be seen by clients (or in other words, world.avelocity_y=64 is a bad idea). */ +#ifdef CSQC +string(vector pos) getlocationname = #0:getlocationname; /* + Looks up the specified position in the current map's .loc file and reports the nearest marked name. */ + +#endif +#ifdef MENU +void(int cliptype) clipboard_get = #0:clipboard_get; /* + Attempts to query the system clipboard. Any pasted text will be returned via Menu_InputEvent */ + +#endif +#if defined(CSQC) || defined(MENU) +void(int cliptype, string text) clipboard_set = #0:clipboard_set; /* + Changes the system clipboard to the specified text. */ + +#endif +#ifdef SSQC +entity(float entnum, optional __out float wasspawned) respawnedict = #0:respawnedict; /* + Acts like edict_num returning a specific entity number, but also marks it as spawned. If it was previously spawned then all of its prior field data will be LOST (you may wish to use wasfreed(edict_num(idx)) to check. */ + +#endif #if defined(CSQC) || defined(SSQC) entity(entity from, optional entity to) copyentity = #400; /* Part of DP_QC_COPYENTITY Copies all fields from one entity to another. */ #endif #ifdef SSQC -void(entity ent, float colours) setcolors = #401; /* +__deprecated("No RGB support.") void(entity ent, float colours) setcolor = #401; /* Part of DP_SV_SETCOLOR Changes a player's colours. The bits 0-3 are the lower/trouser colour, bits 4-7 are the upper/shirt colours. */ #endif @@ -2691,7 +3243,7 @@ void(strbuf bufhandle, float string_index, string str) bufstr_set = #447; /* Par float(strbuf bufhandle, string str, float ordered) bufstr_add = #448; /* Part of DP_QC_STRINGBUFFERS*/ void(strbuf bufhandle, float string_index) bufstr_free = #449; /* Part of DP_QC_STRINGBUFFERS*/ float(string name) iscachedpic = #451; -string(string name, optional float trywad) precache_pic = #452; +string(string name, optional float flags) precache_pic = #452; float(vector position, float character, vector scale, vector rgb, float alpha, optional float flag) drawcharacter = #454; float(vector position, string text, vector scale, vector rgb, float alpha, optional float flag) drawrawstring = #455; float(vector position, string pic, vector size, vector rgb, float alpha, optional float flag) drawpic = #456; @@ -2699,25 +3251,26 @@ float(vector position, vector size, vector rgb, float alpha, optional float flag void(float x, float y, float width, float height) drawsetcliparea = #458; void(void) drawresetcliparea = #459; vector(string picname) drawgetimagesize = #460; +void(float width, vector pos1, vector pos2) drawline = #466; float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #467; -float(string text, float usecolours, optional vector fontsize) stringwidth = #468; +float(string text, float usecolours, vector fontsize='8 8') stringwidth = #468; void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, float flag) drawsubpic = #469; #endif #ifdef SSQC void(entity e, string s) clientcommand = #440; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ #endif #if defined(CSQC) || defined(SSQC) -float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ /* return value is the number of parts created, ie argc */ +float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ string(float n) argv = #442; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ void(entity e, entity tagentity, string tagname) setattachment = #443; /* Part of DP_GFX_QUAKE3MODELTAGS*/ -searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #444; /* Part of DP_QC_FS_SEARCH - initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. */ +searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3} flags, float quiet, optional string filterpackage) search_begin = #444; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE + initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. SB_FULLPACKAGEPATH interprets the filterpackage arg as a full package path to avoid gamedir ambiguity, equivelent to whichpack's WP_FULLPACKAGEPATH flag. SB_ALLOWDUPES allows returning multiple entries with the same name (but different package, useful with search_fopen). SB_FORCESEARCH requires use of the filterpackage and SB_FULLPACKAGEPATH flag, initiating searches from gamedirs/packages which are not currently active. */ -void(searchhandle handle) search_end = #445; /* Part of DP_QC_FS_SEARCH*/ -float(searchhandle handle) search_getsize = #446; /* Part of DP_QC_FS_SEARCH +void(searchhandle handle) search_end = #445; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ +float(searchhandle handle) search_getsize = #446; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE Retrieves the number of files that were found. */ -string(searchhandle handle, float num) search_getfilename = #447; /* Part of DP_QC_FS_SEARCH +string(searchhandle handle, float num) search_getfilename = #447; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE Retrieves name of one of the files that was found by the initial search. */ #endif @@ -2727,6 +3280,12 @@ float(searchhandle handle, float num) search_getfilesize = #0:search_getfilesize string(searchhandle handle, float num) search_getfilemtime = #0:search_getfilemtime; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME Retrieves modification time of one of the files. */ +string(searchhandle handle, float num) search_getpackagename = #0:search_getpackagename; /* + Retrieves the name of the package containing the file. Search with SB_FULLPACKAGEPATH to see gamedir/package info */ + +filestream(searchhandle handle, float num) search_fopen = #0:search_fopen; /* + Opens the file directly, without getting confused about entries from other packages. Read access only. */ + #if defined(CSQC) || defined(SSQC) string(string cvarname) cvar_string = #448; /* Part of DP_QC_CVAR_STRING*/ entity(entity start, .float fld, float match) findflags = #449; /* Part of DP_QC_FINDFLAGS*/ @@ -2770,11 +3329,15 @@ string(string s) strdecolorize = #477; /* Part of DP_QC_STRINGCOLORFUNCTIONS Flattens any markup/colours, removing them from the string. */ string(float uselocaltime, string format, ...) strftime = #478; /* Part of DP_QC_STRFTIME*/ -float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR*/ +float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR + Splits up the string using only the specified delimiters/separators. Multiple delimiters can be given, they are each considered equivelent (though should start with the longest if you want to do weird subseparator stuff). + The resulting tokens can be queried via argv (and argv_start|end_index builtins, if you want to determine which of the separators was present between two tokens). + Note that while an input string containing JUST a separator will return 2, a string with no delimiter will return 1, while (in FTE) an empty string will ALWAYS return 0. */ + string(string s) strtolower = #480; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ string(string s) strtoupper = #481; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ -string(string s) cvar_defstring = #482; /* Part of DP_QC_CVAR_DEFSTRING*/ #if defined(CSQC) || defined(SSQC) +string(string s) cvar_defstring = #482; /* Part of DP_QC_CVAR_DEFSTRING*/ void(vector origin, string sample, float volume, float attenuation) pointsound = #483; /* Part of DP_SV_POINTSOUND*/ #endif string(string search, string replace, string subject) strreplace = #484; /* Part of DP_QC_STRREPLACE*/ @@ -2815,7 +3378,7 @@ void(string id, float newstate) cin_setstate = #0:cin_setstate; float(string id) cin_getstate = #0:cin_getstate; void(string file) cin_restart = #0:cin_restart; #endif -float(float caseinsensitive, string s, ...) crc16 = #494; /* Part of DP_QC_CRC16*/ +__deprecated("Use digest_hex") float(float caseinsensitive, string s, ...) crc16 = #494; /* Part of DP_QC_CRC16*/ float(string name) cvar_type = #495; /* Part of DP_QC_CVAR_TYPE*/ float() numentityfields = #496; /* Part of DP_QC_ENTITYDATA Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3). */ @@ -2846,16 +3409,20 @@ string() ReadPicture = #501; /* void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, optional float flags) boxparticles = #502; #endif -string(string filename, optional float makereferenced) whichpack = #503; /* Part of DP_QC_WHICHPACK - Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If makereferenced is true, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ +string(string filename, optional enumflags:float{WP_REFERENCEPACKAGE,WP_FULLPACKAGEPATH} flags) whichpack = #503; /* Part of DP_QC_WHICHPACK + Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If WP_REFERENCE, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ #ifdef CSQC __variant(float entnum, float fieldnum) getentity = #504; /* Looks up fields from non-csqc-visible entities. The entity will need to be within the player's pvs. fieldnum should be one of the GE_ constants. */ #endif -string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE*/ -string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE*/ +string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE + Uses percent-encoding to encode any bytes in the input string which are not ascii alphanumeric, period, hyphen, or underscore. All other bytes will expand to eg '%20' for a single space char. This encoding scheme is compatible with http and other uris. */ + +string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE + Undo any percent-encoding in the input string, hopefully resulting in the same original sequence of bytes (and thus chars too). */ + float(entity ent) num_for_edict = #512; #define uri_post uri_get float(string uril, float id, optional string postmimetype, optional string postdata) uri_get = #513; /* Part of DP_QC_URI_GET, DP_QC_URI_POST @@ -2882,10 +3449,12 @@ string(string cvarname) cvar_description = #518; /* float(optional float timetype) gettime = #519; #endif #ifdef CSQC -string(float keynum) keynumtostring_omgwtf = #520; -string(string command, optional float bindmap) findkeysforcommand = #521; /* +DEP string(float keynum) keynumtostring_omgwtf = #520; +__deprecated("Does not support modifiers") string(string command, optional float bindmap) findkeysforcommand = #521; /* Returns a list of keycodes that perform the given console command in a format that can only be parsed via tokenize (NOT tokenize_console). This only and always returns two values - if only one key is actually bound, -1 will be returned. The bindmap argument is listed for compatibility with dp-specific defs, but is ignored in FTE. */ +#endif +#if defined(CSQC) || defined(MENU) string(string command, optional float bindmap) findkeysforcommandex = #0:findkeysforcommandex; /* Returns a list of key bindings in keyname format instead of keynums. Use tokenize to parse. This list may contain modifiers. May return large numbers of keys. */ @@ -2897,14 +3466,14 @@ void(string s) loadfromdata = #529; /* void(string s) loadfromfile = #530; /* Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */ -#endif -#ifdef SSQC void(float pause) setpause = #531; /* Sets whether the server should or should not be paused. This does not affect auto-paused things like when the console is down. */ +#endif +#ifdef SSQC float(string mname) precache_vwep_model = #532; /* Part of ZQ_VWEP*/ #endif -float(float v, optional float base) log = #532; /* Part of ??MVDSV_BUILTINS +float(float v, optional float base) log = #532; /* Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */ #ifdef CSQC @@ -2914,6 +3483,9 @@ float(entity e, float channel, string newsample, float volume, float attenuation float(entity e, float channel) getsoundtime = #533; /* Returns the current playback time of the sample on the given entity's channel. Beware CHAN_AUTO (in csqc, channels are not limited by network protocol). */ +float(entity e, float channel) getchannellevel = #0:getchannellevel; /* + Reports how load the sound's sample is at its current offset. */ + #endif #if defined(CSQC) || defined(MENU) float(string sample) soundlength = #534; /* @@ -2926,9 +3498,12 @@ float(string filename, strbuf bufhandle) buf_loadfile = #535; /* float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536; /* Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer. */ +float(float bufhandle, string match, float matchrule, float startpos, float step) bufstr_find = #537; /* + Looks for the first occurence of the specified string in the buffer, returning its index or -1 on failure. */ + #ifdef SSQC -float(optional float force) physics_supported = #0:physics_supported; /* - Queries whether rigid body physics is enabled or not. CSQC and SSQC may report different values. If the force argument is used then the engine will try to activate or release physics (returning the new state, which may fail if plugins or dlls are missing). Note that restarting the physics engine is likely to result in hitches when collision trees get generated. The state may change if a plugin is disabled mid-map. */ +float(optional float forcestate) physics_supported = #0:physics_supported; /* + Queries whether rigid body physics is enabled or not. CSQC and SSQC may report different values. If the force argument is specified then the engine will try to activate or release physics (returning the new state, which may fail if plugins or dlls are missing). Note that restarting the physics engine is likely to result in hitches when collision trees get generated. The state may change if a plugin is disabled mid-map. */ #endif #if defined(CSQC) || defined(SSQC) @@ -2965,7 +3540,7 @@ vector(float vidmode, optional float forfullscreen) getresolution = #608; /* #endif #ifdef CSQC -string(float keynum) keynumtostring_menu = #609; +DEP string(float keynum) keynumtostring_menu = #609; #endif #ifdef MENU string(float keynum) keynumtostring = #609; /* @@ -3004,6 +3579,14 @@ void(string key) addwantedhostcachekey = #623; /* Part of FTE_CSQC_SERVERBROWSER string() getextresponse = #624; /* Part of FTE_CSQC_SERVERBROWSER*/ #endif string(string dnsname, optional float defport) netaddress_resolve = #625; +#if defined(CSQC) || defined(MENU) +string(float n, float prop) getgamedirinfo = #626; /* + Queries properties about an indexed gamedir (or -1 for the current gamedir). Returns null strings when out of bounds. Use the GDDI_* constants for the prop arg. */ + +string(int n, int prop) getpackagemanagerinfo = #0:getpackagemanagerinfo; /* + Queries information about a package from the engine's package manager subsystem. Actions can be taken via the pkg console command. */ + +#endif string(string fmt, ...) sprintf = #627; /* Part of DP_QC_SPRINTF 'prints' to a formatted temp-string. Mostly acts as in C, however %d assumes floats (fteqcc has arg checking. Use it.). type conversions: l=arg is an int, h=arg is a float, and will work as a prefix for any float or int representation. @@ -3017,6 +3600,7 @@ float(entity e, float s) getsurfacenumtriangles = #628; vector(entity e, float s, float n) getsurfacetriangle = #629; #endif #if defined(CSQC) || defined(MENU) +float(float key, string bind, optional float bindmap, optional float modifier) setkeybind = #630; vector() getbindmaps = #631; float(vector bm) setbindmaps = #632; #endif @@ -3024,149 +3608,184 @@ string(string digest, string data, ...) digest_hex = #639; string(string digest, void *data, int length) digest_ptr = #0:digest_ptr; /* Calculates the digest of a single contiguous block of memory (including nulls) using the specified hash function. */ +float(string src, string dst) fcopy = #650; /* + Equivelent to fopen+fread+fwrite+fclose from QC (ie: reads from $gamedir/data/ or $gamedir, but always writes to $gamedir/data/ ) */ + +float(string src, string dst) frename = #651; /* + Renames the file, returning 0 on success. Both paths are relative to the data/ subdir. */ + +float(string fname) fremove = #652; /* + Deletes the named file - path is relative to data/ subdir, like fopen's FILE_WRITE. Returns 0 on success. */ + +float(string fname) fexists = #653; /* + Returns true if it exists inside the default writable path. Use whichpack for greater portability. */ + +float(string path) rmtree = #654; /* + Dangerous, but sandboxed to data/ */ + #if defined(CSQC) || defined(MENU) -#define K_TAB 9 -#define K_ENTER 13 -#define K_ESCAPE 27 -#define K_SPACE 32 -#define K_BACKSPACE 127 -#define K_UPARROW 128 -#define K_DOWNARROW 129 -#define K_LEFTARROW 130 -#define K_RIGHTARROW 131 -#define K_LALT 132 -#define K_RALT -245 -#define K_LCTRL 133 -#define K_RCTRL -246 -#define K_LSHIFT 134 -#define K_RSHIFT -247 -#define K_F1 135 -#define K_F2 136 -#define K_F3 137 -#define K_F4 138 -#define K_F5 139 -#define K_F6 140 -#define K_F7 141 -#define K_F8 142 -#define K_F9 143 -#define K_F10 144 -#define K_F11 145 -#define K_F12 146 -#define K_INS 147 -#define K_DEL 148 -#define K_PGDN 149 -#define K_PGUP 150 -#define K_HOME 151 -#define K_END 152 -#define K_KP_HOME 164 -#define K_KP_UPARROW 165 -#define K_KP_PGUP 166 -#define K_KP_LEFTARROW 161 -#define K_KP_5 162 -#define K_KP_RIGHTARROW 163 -#define K_KP_END 158 -#define K_KP_DOWNARROW 159 -#define K_KP_PGDN 160 -#define K_KP_ENTER 172 -#define K_KP_INS 157 -#define K_KP_DEL 167 -#define K_KP_SLASH 168 -#define K_KP_MINUS 170 -#define K_KP_PLUS 171 -#define K_KP_NUMLOCK 154 -#define K_KP_STAR 169 -#define K_KP_EQUALS 173 -#define K_MOUSE1 512 -#define K_MOUSE2 513 -#define K_MOUSE3 514 -#define K_MOUSE4 517 -#define K_MOUSE5 518 -#define K_MOUSE6 519 -#define K_MOUSE7 520 -#define K_MOUSE8 521 -#define K_MOUSE9 522 -#define K_MOUSE10 523 -#define K_MWHEELUP 515 -#define K_MWHEELDOWN 516 -#define K_LWIN -239 -#define K_RWIN -240 -#define K_APP -241 -#define K_SEARCH -242 -#define K_POWER -130 -#define K_VOLUP -243 -#define K_VOLDOWN -244 -#define K_JOY1 768 -#define K_JOY2 769 -#define K_JOY3 770 -#define K_JOY4 771 -#define K_AUX1 784 -#define K_AUX2 785 -#define K_AUX3 786 -#define K_AUX4 787 -#define K_AUX5 788 -#define K_AUX6 789 -#define K_AUX7 790 -#define K_AUX8 791 -#define K_AUX9 792 -#define K_AUX10 793 -#define K_AUX11 794 -#define K_AUX12 795 -#define K_AUX13 796 -#define K_AUX14 797 -#define K_AUX15 798 -#define K_AUX16 799 -#define K_AUX17 800 -#define K_AUX18 801 -#define K_AUX19 802 -#define K_AUX20 803 -#define K_AUX21 804 -#define K_AUX22 805 -#define K_AUX23 806 -#define K_AUX24 807 -#define K_AUX25 808 -#define K_AUX26 809 -#define K_AUX27 810 -#define K_AUX28 811 -#define K_AUX29 812 -#define K_AUX30 813 -#define K_AUX31 814 -#define K_AUX32 815 -#define K_PAUSE 153 -#define K_PRINTSCREEN 174 -#define K_CAPSLOCK 155 -#define K_SCROLLLOCK 156 -#define K_SEMICOLON 59 -#define K_PLUS 43 -#define K_MINUS 45 -#define K_TILDE 126 -#define K_BACKQUOTE 96 -#define K_BACKSLASH 92 -#define K_GP_A 826 -#define K_GP_B 827 -#define K_GP_X 828 -#define K_GP_Y 829 -#define K_GP_LSHOULDER 824 -#define K_GP_RSHOULDER 825 -#define K_GP_LTRIGGER 830 -#define K_GP_RTRIGGER 831 -#define K_GP_BACK 821 -#define K_GP_START 820 -#define K_GP_LTHUMB 822 -#define K_GP_RTHUMB 823 -#define K_GP_DPAD_UP 816 -#define K_GP_DPAD_DOWN 817 -#define K_GP_DPAD_LEFT 818 -#define K_GP_DPAD_RIGHT 819 -#define K_GP_GUIDE -202 -#define K_GP_UNKNOWN -255 -#define K_GP_LTHUMB_UP 832 -#define K_GP_LTHUMB_DOWN 833 -#define K_GP_LTHUMB_LEFT 834 -#define K_GP_LTHUMB_RIGHT 835 -#define K_GP_RTHUMB_UP 836 -#define K_GP_RTHUMB_DOWN 837 -#define K_GP_RTHUMB_LEFT 838 -#define K_GP_RTHUMB_RIGHT 839 +const float K_TAB = 9; +const float K_ENTER = 13; +const float K_ESCAPE = 27; +const float K_SPACE = 32; +const float K_BACKSPACE = 127; +const float K_UPARROW = 128; +const float K_DOWNARROW = 129; +const float K_LEFTARROW = 130; +const float K_RIGHTARROW = 131; +const float K_LALT = 132; +const float K_RALT = -280; +const float K_LCTRL = 133; +const float K_RCTRL = -281; +const float K_LSHIFT = 134; +const float K_RSHIFT = -282; +const float K_F1 = 135; +const float K_F2 = 136; +const float K_F3 = 137; +const float K_F4 = 138; +const float K_F5 = 139; +const float K_F6 = 140; +const float K_F7 = 141; +const float K_F8 = 142; +const float K_F9 = 143; +const float K_F10 = 144; +const float K_F11 = 145; +const float K_F12 = 146; +const float K_INS = 147; +const float K_DEL = 148; +const float K_PGDN = 149; +const float K_PGUP = 150; +const float K_HOME = 151; +const float K_END = 152; +const float K_KP_HOME = 164; +const float K_KP_UPARROW = 165; +const float K_KP_PGUP = 166; +const float K_KP_LEFTARROW = 161; +const float K_KP_5 = 162; +const float K_KP_RIGHTARROW = 163; +const float K_KP_END = 158; +const float K_KP_DOWNARROW = 159; +const float K_KP_PGDN = 160; +const float K_KP_ENTER = 172; +const float K_KP_INS = 157; +const float K_KP_DEL = 167; +const float K_KP_SLASH = 168; +const float K_KP_MINUS = 170; +const float K_KP_PLUS = 171; +const float K_KP_NUMLOCK = 154; +const float K_KP_STAR = 169; +const float K_KP_EQUALS = 173; +const float K_MOUSE1 = 512; +const float K_MOUSE2 = 513; +const float K_MOUSE3 = 514; +const float K_MOUSE4 = 517; +const float K_MOUSE5 = 518; +const float K_MOUSE6 = 519; +const float K_MOUSE7 = 520; +const float K_MOUSE8 = 521; +const float K_MOUSE9 = 522; +const float K_MOUSE10 = 523; +const float K_MWHEELUP = 515; +const float K_MWHEELDOWN = 516; +const float K_LWIN = -274; +const float K_RWIN = -275; +const float K_APP = -276; +const float K_SEARCH = -277; +const float K_POWER = -130; +const float K_VOLUP = -278; +const float K_VOLDOWN = -279; +const float K_JOY1 = 768; +const float K_JOY2 = 769; +const float K_JOY3 = 770; +const float K_JOY4 = 771; +const float K_JOY5 = 772; +const float K_JOY6 = 773; +const float K_JOY7 = 774; +const float K_JOY8 = 775; +const float K_JOY9 = 776; +const float K_JOY10 = 777; +const float K_JOY11 = 778; +const float K_JOY12 = 779; +const float K_JOY13 = 780; +const float K_JOY14 = 781; +const float K_JOY15 = 782; +const float K_JOY16 = 783; +const float K_JOY17 = 784; +const float K_JOY18 = 785; +const float K_JOY19 = 786; +const float K_JOY20 = 787; +const float K_JOY21 = 788; +const float K_JOY22 = 789; +const float K_JOY23 = 790; +const float K_JOY24 = 791; +const float K_JOY25 = 792; +const float K_JOY26 = 793; +const float K_JOY27 = 794; +const float K_JOY28 = 795; +const float K_JOY29 = 796; +const float K_JOY30 = 797; +const float K_JOY31 = 798; +const float K_JOY32 = 799; +const float K_AUX1 = 800; +const float K_AUX2 = 801; +const float K_AUX3 = 802; +const float K_AUX4 = 803; +const float K_AUX5 = 804; +const float K_AUX6 = 805; +const float K_AUX7 = 806; +const float K_AUX8 = 807; +const float K_AUX9 = 808; +const float K_AUX10 = 809; +const float K_AUX11 = 810; +const float K_AUX12 = 811; +const float K_AUX13 = 812; +const float K_AUX14 = 813; +const float K_AUX15 = 814; +const float K_AUX16 = 815; +const float K_PAUSE = 153; +const float K_PRINTSCREEN = 174; +const float K_CAPSLOCK = 155; +const float K_SCROLLLOCK = 156; +const float K_SEMICOLON = 59; +const float K_PLUS = 43; +const float K_MINUS = 45; +const float K_APOSTROPHE = 39; +const float K_QUOTES = 34; +const float K_TILDE = 126; +const float K_BACKQUOTE = 96; +const float K_BACKSLASH = 92; +const float K_GP_A = 826; +const float K_GP_B = 827; +const float K_GP_X = 828; +const float K_GP_Y = 829; +const float K_GP_LSHOULDER = 824; +const float K_GP_RSHOULDER = 825; +const float K_GP_LTRIGGER = 830; +const float K_GP_RTRIGGER = 831; +const float K_GP_BACK = 821; +const float K_GP_START = 820; +const float K_GP_LTHUMB = 822; +const float K_GP_RTHUMB = 823; +const float K_GP_DPAD_UP = 816; +const float K_GP_DPAD_DOWN = 817; +const float K_GP_DPAD_LEFT = 818; +const float K_GP_DPAD_RIGHT = 819; +const float K_GP_GUIDE = -238; +const float K_GP_SHARE = -248; +const float K_GP_PADDLE1 = -249; +const float K_GP_PADDLE2 = -250; +const float K_GP_PADDLE3 = -251; +const float K_GP_PADDLE4 = -252; +const float K_GP_TOUCHPAD = -253; +const float K_GP_UNKNOWN = -264; +const float K_GP_LTHUMB_UP = 832; +const float K_GP_LTHUMB_DOWN = 833; +const float K_GP_LTHUMB_LEFT = 834; +const float K_GP_LTHUMB_RIGHT = 835; +const float K_GP_RTHUMB_UP = 836; +const float K_GP_RTHUMB_DOWN = 837; +const float K_GP_RTHUMB_LEFT = 838; +const float K_GP_RTHUMB_RIGHT = 839; #endif #ifdef _ACCESSORS accessor strbuf : float @@ -3196,7 +3815,7 @@ accessor hashtable : float accessor infostring : string { get string[string] = infoget; - inline seti& string[string fld] = {this = infoadd(this, fld, value);}; + inline set& string[string fld] = {this = infoadd(this, fld, value);}; }; accessor filestream : float { @@ -3204,4 +3823,18 @@ accessor filestream : float inline set string = {fputs(this,value);}; }; #endif +accessor jsonnode : json_t +{ + inline get json_type_e type = json_get_value_type; + inline get string s = json_get_string; + inline get float f = json_get_float; + inline get __int i = json_get_integer; + inline get __int length = json_get_length; + inline get jsonnode a[__int key] = json_get_child_at_index; + inline get jsonnode[string key] = json_find_object_child; + inline get string name = json_get_name; +}; +#undef DEP_CSQC +#undef FTEDEP +#undef DEP #pragma noref 0 diff --git a/ssqc/admin.qc b/ssqc/admin.qc index c1c7c9b7..bd56df78 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -8,26 +8,26 @@ void () Admin_CountPlayers = { nump = TeamFortress_GetNoPlayers(); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in game: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in game: ", st, "\n"); if (number_of_teams > 0) { nump = TeamFortress_TeamGetNoPlayers(1); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in blue team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in blue team: ", st, "\n"); } if (number_of_teams > 1) { nump = TeamFortress_TeamGetNoPlayers(2); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in red team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in red team: ", st, "\n"); } if (number_of_teams > 2) { nump = TeamFortress_TeamGetNoPlayers(3); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in yellow team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in yellow team: ", st, "\n"); } if (number_of_teams > 3) { nump = TeamFortress_TeamGetNoPlayers(4); st = ftos(nump); - sprint3(self, PRINT_HIGH, "Players in green team: ", st, "\n"); + sprint(self, PRINT_HIGH, "Players in green team: ", st, "\n"); } }; @@ -103,21 +103,21 @@ void () Admin_CycleDeal = { }; void () Admin_DoKick = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was kicked by ", self.netname, "\n"); + bprint(PRINT_HIGH, self.admin_use.netname, " was kicked by ", self.netname, "\n"); KickCheater(self.admin_use); self.admin_mode = 0; self.admin_use = world; }; void () Admin_DoBan = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was banned by ", self.netname, "\n"); + bprint(PRINT_HIGH, self.admin_use.netname, " was banned by ", self.netname, "\n"); BanCheater(self.admin_use); self.admin_mode = 0; self.admin_use = world; }; void () Admin_ForceSpectator = { - bprint4(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); + bprint(PRINT_HIGH, self.admin_use.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); clientcommand(self.admin_use, "observe"); self.admin_mode = 0; self.admin_use = world; @@ -195,10 +195,10 @@ void () Admin_Pause = { pause_actor = self.netname; if (cb_prematch && is_countdown) { StopTimer(); - bprint2(2, pause_actor, " stops the countdown\n"); + bprint(2, pause_actor, " stops the countdown\n"); return; } - bprint2(2, pause_actor, " paused the game\n"); + bprint(2, pause_actor, " paused the game\n"); } else { if (cb_prematch) { @@ -213,11 +213,11 @@ void () Admin_Pause = { } pause_actor = self.netname; if (!unpause_requested) { - bprint2(2, pause_actor, " has requested to unpause the game in 5 seconds\n"); + bprint(2, pause_actor, " has requested to unpause the game in 5 seconds\n"); unpause_requested = 1; } else { - bprint2(2, pause_actor, " cancels unpause request\n"); + bprint(2, pause_actor, " cancels unpause request\n"); unpause_requested = 0; unpause_countdown = 0; unpause_lastcountnumber = 0; @@ -230,7 +230,7 @@ void (entity p) CheckAutoKick = { local entity te; if ((p.teamkills >= autokick_kills) && (autokick_kills != 0)) { - bprint2(PRINT_HIGH, p.netname, + bprint(PRINT_HIGH, p.netname, " was kicked for killing teammates\n"); sprint(p, PRINT_HIGH, "You were kicked for killing teammates\n"); KickCheater(p); @@ -274,7 +274,7 @@ void (string cl_pwd) Admin_Check = if (st2 != string_null && cl_pwd == st2) { self.is_admin = TRUE; forceinfokey(self,"*admin", ftos(self.is_admin)); - bprint2(2, self.netname, "\s gains full admin status!\s\n"); + bprint(2, self.netname, "\s gains full admin status!\s\n"); sprint(self, 2, "Type \scmd list\s for admin commands.\n"); sprint(self, 2, "You can also use the \sadminmenu\s command for adjusting some settings.\n"); } diff --git a/ssqc/camera.qc b/ssqc/camera.qc index 5540fd6e..06f9b07e 100644 --- a/ssqc/camera.qc +++ b/ssqc/camera.qc @@ -6,7 +6,7 @@ void () CamLock = { te = find(world, netname, self.netname); while (te) { if (te != self) { - sprint3(self, PRINT_HIGH, "Locked onto ", te.netname, + sprint(self, PRINT_HIGH, "Locked onto ", te.netname, "\n"); self.enemy = te; self.heat = vlen((self.enemy.origin - self.origin)); @@ -14,7 +14,7 @@ void () CamLock = { te = find(te, netname, self.netname); } if (self.enemy == world) - sprint2(self, PRINT_HIGH, te.netname, " not found\n"); + sprint(self, PRINT_HIGH, te.netname, " not found\n"); } else { sprint(self, PRINT_HIGH, "Removed lock\n"); self.enemy = world; @@ -242,7 +242,7 @@ void () CamDrop = { } prevte.camera_list = cam; st = ftos(tf); - sprint3(self, PRINT_HIGH, "Camera ", st, " dropped\n"); + sprint(self, PRINT_HIGH, "Camera ", st, " dropped\n"); }; void () fadetoblack = { diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 1662ef1a..05a784eb 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -31,7 +31,7 @@ void () MatchThink = if (!self.cnt2) { if (self.cnt == 1 || self.cnt == 5) { tmp = ftos (self.cnt); - bprint3(2, Q"\s[\s", tmp, "\s]\s minute"); + bprint(2, Q"\s[\s", tmp, "\s]\s minute"); if (self.cnt != 1) { bprint(2, "s"); } @@ -46,7 +46,7 @@ void () MatchThink = } if (!self.cnt && (((self.cnt2 == 30) || (self.cnt2 == 15)) || (self.cnt2 <= 10))) { tmp = ftos(self.cnt2); - bprint3(2, Q"\s[\s", tmp, "\s]\s second"); + bprint(2, Q"\s[\s", tmp, "\s]\s second"); if (self.cnt2 != 1) { bprint(2, "s"); } @@ -207,7 +207,7 @@ string () GetPlayersName if (strlen(plname) <= 13) { st = strcat( st, plname ); } else { - st = strcat( st, substr(plname,0,12)); + st = strcat( st, substring(plname,0,12)); } } te = find (te, classname, "player"); @@ -229,19 +229,8 @@ string () GetGameFileName = { i = 0; t = find (world, classname, "prematch"); if (t != world) - { - calltimeofday (); - str = strcat(str, tod_year); // year - str = strcat(str, "-"); - str = strcat(str, tod_mon); // month - str = strcat(str, "-"); - str = strcat(str, tod_day); // day - str = strcat(str, "_"); - str = strcat(str, tod_hour); // hour - str = strcat(str, "-"); - str = strcat(str, tod_min); // minute - str = strcat(str, "-"); - str = strcat(str, tod_sec); // second + { + str = strftime(TRUE, "%Y-%m-%d-%H-%M-%S"); } str = strcat(str, "_["); str = strcat(str, mapname); @@ -312,7 +301,7 @@ void () PreMatch_Think = { fl = (self.cnt2 / 60); if (fl == 1 || fl == 2 || fl == 3 || fl == 4 || fl == 5 || fl == 6 || fl == 7 || fl == 8 || fl == 9 || fl == 10) { num = ftos(fl); - bprint3(2, "Match will begin in ", num, " minute(s).\n"); + bprint(2, "Match will begin in ", num, " minute(s).\n"); } if (self.cnt2 == 30) { num = ftos(self.cnt2 / 60); @@ -326,7 +315,6 @@ void () PreMatch_Think = { localcmd("cancel\n"); if (stof(infokey(world, "demo_auto_left")) > 0) { if (infokey(world, "serverdemo") == "on") { - calltimeofday(); localcmd("record \""); str = strzone(GetGameFileName()); @@ -360,7 +348,7 @@ void () PreMatch_Think = { p = find(p, classname, "player"); } if (self.cnt2 > 1) { - bprint2(2, num, " seconds \n"); + bprint(2, num, " seconds \n"); } else { bprint(2, "1 second \n"); @@ -584,9 +572,9 @@ void () DumpClanScores = { if ((winners != 2) && (t2_pl != 0)) { st = GetTeamName(2); if (printed == no_teams) { - bprint2(PRINT_HIGH, " and ", st); + bprint(PRINT_HIGH, " and ", st); } else if (printed) { - bprint2(PRINT_HIGH, ", ", st); + bprint(PRINT_HIGH, ", ", st); } else { bprint(PRINT_HIGH, st); } @@ -595,9 +583,9 @@ void () DumpClanScores = { if ((winners != 3) && (t3_pl != 0)) { st = GetTeamName(3); if (printed == no_teams) { - bprint2(PRINT_HIGH, " and ", st); + bprint(PRINT_HIGH, " and ", st); } else if (printed) { - bprint2(PRINT_HIGH, ", ", st); + bprint(PRINT_HIGH, ", ", st); } else { bprint(PRINT_HIGH, st); } @@ -606,9 +594,9 @@ void () DumpClanScores = { if ((winners != 4) && (t4_pl != 0)) { st = GetTeamName(4); if (printed == no_teams) { - bprint2(PRINT_HIGH, " and ", st); + bprint(PRINT_HIGH, " and ", st); } else if (printed) { - bprint2(PRINT_HIGH, ", ", st); + bprint(PRINT_HIGH, ", ", st); } else { bprint(PRINT_HIGH, st); } @@ -773,49 +761,49 @@ void () DumpClanScores = { bprint(PRINT_HIGH, "\n=------= Blue team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(1); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team1frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t1_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team1score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } if (t2_pl > 0) { bprint(PRINT_HIGH, "\n=------= Red team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(2); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team2frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t2_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team2score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } if (t3_pl > 0) { bprint(PRINT_HIGH, "\n=------= Yellow team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(3); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team3frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t3_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team3score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } if (t4_pl > 0) { bprint(PRINT_HIGH, "\n=------= Green team results =------=\n"); tno = TeamFortress_TeamGetNoPlayers(4); st = ftos(tno); - bprint2(PRINT_HIGH, st, " players\n"); + bprint(PRINT_HIGH, st, " players\n"); st = ftos(team4frags); - bprint2(PRINT_HIGH, st, " frags, "); + bprint(PRINT_HIGH, st, " frags, "); st = ftos(t4_unacc); - bprint2(PRINT_HIGH, st, " unaccounted for\n"); + bprint(PRINT_HIGH, st, " unaccounted for\n"); st = ftos(team4score); - bprint2(PRINT_HIGH, st, " team score\n"); + bprint(PRINT_HIGH, st, " team score\n"); } te = find(world, classname, "player"); while (te) { @@ -866,7 +854,7 @@ void () TeamFortress_ShowIDs = { if (te.team_no == self.team_no) { got_one = 1; st = ftos(te.tf_id); - sprint2(self, 2, st, "\n"); + sprint(self, 2, st, "\n"); } te = find(te, classname, "ghost"); } @@ -951,7 +939,7 @@ void () PlayerNotReady = { if (self.stat_flags & PLAYER_READY) { self.stat_flags &= ~PLAYER_READY; UpdateReadyStatus(); - bprint2 (2, self.netname, " is NOT ready anymore\n "); + bprint (2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); Broadcast_Players_NotReady(); } @@ -1134,21 +1122,21 @@ void () PlayerReady = { self.stat_flags |= PLAYER_READY; UpdateReadyStatus(); v_ready = v_ready + 1; - bprint2 (3, self.netname, " is ready to start the match\n"); + bprint (3, self.netname, " is ready to start the match\n"); if(!CheckAllPlayersReady()) Broadcast_Players_NotReady(); }; void () RemoveVotes = { if (self.bvote) { - bprint2(2, self.netname, " \swithdraws\s his/her vote\n"); + bprint(2, self.netname, " \swithdraws\s his/her vote\n"); self.bvote = 0; v_break = (v_break - 1); } if (self.stat_flags & PLAYER_READY) { self.stat_flags &= ~PLAYER_READY; UpdateReadyStatus(); - bprint2(2, self.netname, " is NOT ready anymore\n "); + bprint(2, self.netname, " is NOT ready anymore\n "); v_ready = (v_ready - 1); } }; diff --git a/ssqc/client.qc b/ssqc/client.qc index 90194714..a4a3c1be 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3031,7 +3031,8 @@ void () UpdateAllClientsTeamScores = { } //do not rely on csqcactive - it may misbehave when using `join` from spectator -void (optional float csqcactive) ClientConnect = { +void () ClientConnect = { + local float csqc_active = infokeyf(self, INFOKEY_P_CSQCACTIVE); local string st; local float got_one; @@ -3190,7 +3191,7 @@ void () ClientDisconnect = { LogEventChangeClass(self, self.playerclass, 0, timeplayed); self.classtime = gametime; - bprint4(PRINT_HIGH, self.netname, " left the game with ", st, + bprint(PRINT_HIGH, self.netname, " left the game with ", st, " frags\n"); FO_Sound(self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE); self.has_disconnected = 1; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index afb000eb..a40dec71 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1099,7 +1099,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { ent = find(world, classname, "player"); while(ent) { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { - bprint4(PRINT_HIGH, ent, " was banned by ", self.netname, ".\n"); + bprint(PRINT_HIGH, ent.netname, " was banned by ", self.netname, ".\n"); localcmd("addip "); localcmd(infokey(ent, INFOKEY_P_IP)); localcmd("\n"); @@ -1122,7 +1122,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { ent = find(world, classname, "player"); while(ent) { if(infokeyf(ent, INFOKEY_P_USERID) == farg2) { - bprint4(PRINT_HIGH, ent.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); + bprint(PRINT_HIGH, ent.netname, " was made spectator by ", self.netname, ". There's probably a good reason for this.\n"); clientcommand(ent, "observe"); break; } diff --git a/ssqc/debug.qc b/ssqc/debug.qc index 4f08d052..2c6ff206 100644 --- a/ssqc/debug.qc +++ b/ssqc/debug.qc @@ -20,8 +20,8 @@ void () display_location = { local string st; st = vtos(self.origin); - sprint3(self, PRINT_HIGH, "Location : ", st, "\n"); + sprint(self, PRINT_HIGH, "Location : ", st, "\n"); st = vtos(self.angles); - sprint3(self, PRINT_HIGH, "Angles : ", st, "\n"); + sprint(self, PRINT_HIGH, "Angles : ", st, "\n"); }; diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 74a1c518..50c45bca 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -311,131 +311,10 @@ float rj; //=========================================================================== // builtin functions // -void (vector ang) makevectors = #1; // sets v_forward, etc globals -void (entity e, vector o) setorigin = #2; -void (entity e, string m) setmodel = #3; // set movetype and solid first -void (entity e, vector min, vector max) setsize = #4; -// #5 was removed -// #6 was removed (was: break) -float () random = #7; // returns 0 - 1 -//void (entity e, float chan, string samp, float vol, float atten) sound = #8; -vector(vector v) normalize = #9; -void (string e) error = #10; -void (string e) objerror = #11; -float (vector v) vlen = #12; -//float (vector v) vectoyaw = #13; -entity()spawn = #14; -void (entity e) remove = #15; - -// sets trace_* globals -// nomonsters can be: -// An entity will also be ignored for testing if forent == test, -// forent->owner == test, or test->owner == forent -// a forent of world is ignored -void (vector v1, vector v2, float nomonsters, entity forent) traceline = #16; - -entity()checkclient = #17; // returns a client to look for -entity(entity start,.string fld, string match) find = #18; -string(string s) precache_sound = #19; -string(string s) precache_model = #20; -void (entity client, string s) stuffcmd = #21; -//entity(vector org, float rad) findradius = #22; -//void (...) bprint = #23; -void (...) bprint2 = #23; -void (...) bprint3 = #23; -void (...) bprint4 = #23; -//void (...) sprint = #24; -void (...) sprint2 = #24; -void (...) sprint3 = #24; -//void (...) dprint = #25; -string(float f) ftos = #26; -string(vector v) vtos = #27; -void () coredump = #28; // prints all edicts -void () traceon = #29; // turns statment trace on -void () traceoff = #30; -void (entity e) eprint = #31; // prints an entire edict -//float (float yaw, float dist) walkmove = #32; // returns TRUE or FALSE -// #33 was removed -float () droptofloor = #34; // TRUE if landed on floor -//void (float style, string value) lightstyle = #35; -float (float v) rint = #36; // round to nearest int -float (float v) floor = #37; // largest integer <= v -float (float v) ceil = #38; // smallest integer >= v -// #39 was removed -float (entity e) checkbottom = #40; // true if self is on ground -float (vector v) pointcontents = #41; // returns a CONTENT_* -// #42 was removed -float (float f) fabs = #43; -vector(entity e, float speed) aim = #44; // returns the shooting vector -float (string s) cvar = #45; // return cvar.value -void (string s) localcmd = #46; // put string into local que -entity(entity e) nextent = #47; // for looping through all ents -void (vector o, vector d, float color, float count) particle = #48; -void () ChangeYaw = #49; // turn towards self.ideal_yaw - // at self.yaw_speed -// #50 was removed -//vector(vector v) vectoangles = #51; -// -// direct client message generation -// -void (float to, float f) WriteByte = #52; -void (float to, float f) WriteChar = #53; -void (float to, float f) WriteShort = #54; -void (float to, float f) WriteLong = #55; -void (float to, float f) WriteCoord = #56; -void (float to, float f) WriteAngle = #57; -void (float to, string s) WriteString = #58; -void (float to, entity s) WriteEntity = #59; - -// several removed - -void (float step) movetogoal = #67; - -string(string s) precache_file = #68; // no effect except for -copy -void (entity e) makestatic = #69; -//void (string s) changelevel = #70; - -//#71 was removed - -void (string var, string val) cvar_set = #72; // sets cvar.value - -//void (...) centerprint = #73; // sprint, but in middle - -void (vector pos, string samp, float vol, float atten) ambientsound = #74; - -string(string s) precache_model2 = #75; // registered version only -string(string s) precache_sound2 = #76; // registered version only -string(string s) precache_file2 = #77; // registered version only - -void (entity e) setspawnparms = #78; // set parm1... to the - // values at level start - // for coop respawn -void (entity killer, entity killee) logfrag = #79; // add to stats - -string(entity e, string key) infokey = #80; // get a key value (world = serverinfo) -float (string s) stof = #81; // convert string to float -void (vector where, float set) multicast = #82; // sends the temp message to a set - // of clients, possibly in PVS or PHS - -//void(string str) tokenize = #84; // tokenize text float() argc = #85; // returns number of tokens string(float num) argv_mvdsv = #86; // returns token for the given number -float (float a, float b, ...) min = #94; -float (float a, float b, ...) max = #95; -float (float min, float value, float max) bound = #96; -float (float x, float y) pow = #97; - -float (string s) strlen = #114; -//string (string s1, string s2) strcat = #115; -string (string s, float start, float count) substr = #116; -string (string s, ...) strzone = #118; -//void (string s, ...) strunzone = #119; - -void() calltimeofday = #231; // force server to call mod function timeofday - - //In order to make it more useful, this header includes a timeofday function which just grabs the values for you to use in your qc code straight after calling calltimeofday. string tod_sec, tod_min, tod_hour, tod_day, tod_mon, tod_year; diff --git a/ssqc/events.qc b/ssqc/events.qc index d2e7c761..88cc143a 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -36,7 +36,7 @@ string (entity pl) getEntityNameOrLogin = { void (string evt) logevent = { local string st = infokey (world, "event_debug"); if (stof(st) > 0) { - bprint2(PRINT_HIGH, evt, "\n"); + bprint(PRINT_HIGH, evt, "\n"); } fputs(logfilehandle, evt); } diff --git a/ssqc/login.qc b/ssqc/login.qc index 887dfb1b..36faf1f3 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -12,57 +12,3 @@ void (entity player, string login, string secret) performLogin = { dprint(login); dprint("\n"); } - -void(float reqid, float responsecode, string resourcebody) URI_Get_Callback = { - local float got_one = 0; - self.login_in_progress = 0; - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if (!responsecode) { - float num_args = tokenizebyseparator(resourcebody,";"); - self.login = argv(0); - forceinfokey(self,"*login", self.login); - bprint(2, infokey(self,"name")); - bprint(2, " has logged in as \s"); - bprint(2, self.login); - bprint(2, "\s\n"); - dprint(infokey(self,"name")); - dprint(" logged in as "); - dprint(self.login); - dprint("\n"); - CenterPrint3(self, "You have logged in as ", self.login, "\n"); - if (num_args > 1) { - if (argv(1) == "true") { - self.is_admin = TRUE; - forceinfokey(self,"*admin", ftos(self.is_admin)); - Admin_Aliases (); - bprint2 (2, self.netname, " \sgains full admin status!\s\n"); -// bprint (3, "\n"); - sprint (self, 2, "Type \scommands\s for admin commands.\n"); - } - } - if(self.team_no == 0 && !intermission_running) { - if (clanbattle && (self.has_disconnected != 1)) { - if (self.tf_id != 0) { - got_one = RejoinWithTfId(); - ResetAndRespawnPlayer(self); - } - if (!got_one) { - CreateTfIdAndJoin(); - } - } - if (!got_one) { - if (csqcactive) - Menu_Team(0); - else - Menu_Team(1); - } - } - } - else { - dprint(infokey(self,"name")); - dprint(" login failed: "); - dprint(self.login); - dprint("\n"); - CenterPrint3(self, ftos(responsecode), " - Login FAILED, invalid Login/Secret", "\n"); - } -} diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 33541b7b..d999ecfa 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1421,7 +1421,7 @@ void () Menu_Admin = s_menu2 = strcat( s_menu2, te.netname ); } else { - s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + s_menu2 = strcat( s_menu2, substring(te.netname,0,25)); } s_menu2 = Menu_Indent_line(s_menu2, 30); } @@ -1446,7 +1446,7 @@ void () Menu_Admin = s_menu2 = strcat( s_menu2, te.netname ); } else { - s_menu2 = strcat( s_menu2, substr(te.netname,0,25)); + s_menu2 = strcat( s_menu2, substring(te.netname,0,25)); } s_menu2 = Menu_Indent_line(s_menu2, 30); } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 63a3c75a..072f5474 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -216,7 +216,7 @@ void () QuadRoundThink = { if (!self.cnt2) { if ((self.cnt == 1) || (self.cnt == 5)) { tmp = ftos (self.cnt); - bprint3(2, "\s[\s", tmp, "\s]\s minute"); + bprint(2, "\s[\s", tmp, "\s]\s minute"); if (self.cnt != 1) bprint(2, "s"); bprint(2, " remaining\n"); @@ -238,7 +238,7 @@ void () QuadRoundThink = { fl = ceil (self.cnt2); if (!(fl - self.cnt2)) { tmp = ftos(self.cnt2); - bprint3(2, "\s[\s", tmp, "\s]\s second"); + bprint(2, "\s[\s", tmp, "\s]\s second"); if ((self.cnt2 != 1)) bprint(2, "s"); bprint(2, " remaining\n"); @@ -455,8 +455,8 @@ void () StartQuadRound = } bprint(2, "Rounds Over! Use \"cmd map \" to go to the nextmap\n"); - bprint2(2, "map will auto-restart in ", ftos(map_restart_time)); - bprint2(2, " seconds\n"); + bprint(2, "map will auto-restart in ", ftos(map_restart_time)); + bprint(2, " seconds\n"); if (!clan_scores_dumped) { DumpClanScores(); MapEndSequence(); diff --git a/ssqc/status.qc b/ssqc/status.qc index c46a5b69..d5a47aff 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -513,7 +513,7 @@ void (entity pl, string...count) Status_Print = lines = 0; for (i = 0; i < len; i++) - if (substr(pl.StatusString, i, 1) == "\n") + if (substring(pl.StatusString, i, 1) == "\n") lines++; pl.StatusStringLines = lines; @@ -539,7 +539,7 @@ void (entity pl, f_void_float func, string...count) Status_Menu = lines = 0; for (i = 0; i < len; i++) - if (substr(pl.StatusString, i, 1) == "\n") + if (substring(pl.StatusString, i, 1) == "\n") lines++; pl.StatusStringLines = lines; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 67a03042..f20bc048 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -75,7 +75,7 @@ void () UseSpecialSkill = { src_z = self.absmin_z + self.size_z * 0.7; traceline(src, src + v_forward * 2048, 0, self); if ((trace_ent != world) && (trace_ent.origin != world.origin)) { - sprint3(self, PRINT_HIGH, "Locked onto ", + sprint(self, PRINT_HIGH, "Locked onto ", trace_ent.classname, "\n"); self.enemy = trace_ent; self.camdist = vlen(self.enemy.origin - self.origin); @@ -3053,45 +3053,45 @@ void () TeamFortress_ExplodePerson = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.owner.origin); if ((self.owner.playerclass == PC_SCOUT) && (self.weapon != 10)) - bprint3(PRINT_MEDIUM, "No ", self.owner.netname, + bprint(PRINT_MEDIUM, "No ", self.owner.netname, ", swallowing the grenade isn't very effective!\n"); else if (self.owner.playerclass == PC_SNIPER) - bprint3(PRINT_MEDIUM, "Well ", self.owner.netname, + bprint(PRINT_MEDIUM, "Well ", self.owner.netname, ", don't quit your day job!\n"); else if (self.owner.playerclass == PC_SOLDIER) - bprint3(PRINT_MEDIUM, "Ummm, ", self.owner.netname, + bprint(PRINT_MEDIUM, "Ummm, ", self.owner.netname, ", you're supposed to THROW the grenade!\n"); else if (self.owner.playerclass == PC_DEMOMAN) - bprint3(PRINT_MEDIUM, "Ack! ", self.owner.netname, + bprint(PRINT_MEDIUM, "Ack! ", self.owner.netname, "! The grenade is your friend for another reason!\n"); else if (self.owner.playerclass == PC_MEDIC) { if (self.weapon == GR_TYPE_BLAST) { if (medic_type == MEDIC_TYPE_BLAST) { - bprint3(PRINT_MEDIUM, "Nice one ", self.owner.netname, + bprint(PRINT_MEDIUM, "Nice one ", self.owner.netname, ", you forgot to throw your blast grenade!\n"); } else { - bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, + bprint(PRINT_MEDIUM, "Yes ", self.owner.netname, ", eating a concussion grenade is bad!\n"); } } else { - bprint3(PRINT_MEDIUM, "No ", self.owner.netname, + bprint(PRINT_MEDIUM, "No ", self.owner.netname, "! Assist your own suicide some other time!\n"); } } else if (self.owner.playerclass == PC_HVYWEAP) - bprint3(PRINT_MEDIUM, "Hey ", self.owner.netname, + bprint(PRINT_MEDIUM, "Hey ", self.owner.netname, ", you're not THAT heavy!\n"); else if (self.owner.playerclass == PC_PYRO) - bprint3(PRINT_MEDIUM, "Yes ", self.owner.netname, + bprint(PRINT_MEDIUM, "Yes ", self.owner.netname, ", the grenade does explode on '3'!\n"); else if (self.owner.playerclass == PC_SPY) - bprint3(PRINT_MEDIUM, "You do realize ", self.owner.netname, + bprint(PRINT_MEDIUM, "You do realize ", self.owner.netname, ", you can blow your cover in easier ways!\n"); else if (self.owner.playerclass == PC_ENGINEER) - bprint3(PRINT_MEDIUM, "Hey ", self.owner.netname, + bprint(PRINT_MEDIUM, "Hey ", self.owner.netname, ", study grenade dynamics on your own time!\n"); else - bprint3(PRINT_MEDIUM, "No ", self.owner.netname, + bprint(PRINT_MEDIUM, "No ", self.owner.netname, ", throw the grenade, not the pin!\n"); dremove(self); @@ -3252,7 +3252,7 @@ void () TeamFortress_CheckforCheats = { } if (self.owner.cheat_level > 1200) { self.owner.cheat_level = 0; - bprint2(PRINT_MEDIUM, self.owner.netname, + bprint(PRINT_MEDIUM, self.owner.netname, " has been kicked for cheating\n"); sprint(self.owner, PRINT_HIGH, "You have been kicked for cheating, because of your speed\n"); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index d7b1ea41..cbc7d017 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -342,7 +342,7 @@ void () TeamFortress_CheckTeamCheats = { sk = TeamFortress_GetSkin(self.team_no, self.playerclass); if (st != sk) { TeamFortress_SetSkin(self); - bprint2(PRINT_MEDIUM, self.netname, + bprint(PRINT_MEDIUM, self.netname, " has been kicked for changing skin\n"); sprint(self, PRINT_HIGH, "You have been kicked for changing your skin\n"); @@ -354,7 +354,7 @@ void () TeamFortress_CheckTeamCheats = { st = GetTeamName(self.team_no); if (st != infokey(self, "team")) { SetTeamName(self); - bprint2(PRINT_MEDIUM, self.netname, + bprint(PRINT_MEDIUM, self.netname, " has been kicked for changing team\n"); sprint(self, PRINT_HIGH, "You have been kicked for changing your team\n"); diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 0edd71fd..4ce9edbd 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1043,7 +1043,7 @@ float (string ps_list) List_Count = { for (i = 0; i < f_length; i++) { // set current character - local string s_current = substr(ps_list, i, 1); + local string s_current = substring(ps_list, i, 1); // non-empty space => word if (s_current != " " && s_previous == " ") @@ -1066,7 +1066,7 @@ string (string ps_list, float pf_idx) List_Index = { for (i = 0; i < f_length; i++) { // set current character - local string s_current = substr(ps_list, i, 1); + local string s_current = substring(ps_list, i, 1); // non-empty space => start of word if (s_current != " " && s_previous == " ") { @@ -1077,14 +1077,14 @@ string (string ps_list, float pf_idx) List_Index = { // empty space => end of word if (s_current == " " && f_start > -1) - return strzone(substr(ps_list, f_start, i - f_start)); + return strzone(substring(ps_list, f_start, i - f_start)); s_previous = s_current; } // if f_start is set it means a list item was found if (f_start > -1) - return strzone(substr(ps_list, f_start, i - f_start)); + return strzone(substring(ps_list, f_start, i - f_start)); return strzone(string_null); }; diff --git a/ssqc/world.qc b/ssqc/world.qc index b6c3c8eb..0347b1f5 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -111,8 +111,7 @@ void () worldspawn = { cvar_set("teamplay", "1"); if (infokey(world, "starttime") == string_null) { - calltimeofday(); - string timestamp = strcat(tod_year, tod_mon, tod_day, tod_hour, tod_min, tod_sec); + string timestamp = strftime(FALSE, "%Y%m%d%H%M%S"); localcmd(strcat("serverinfo starttime \"", timestamp, "\"\n")); } From e9a60f2cf6808836276e7dac80980b71bd782bef Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 15 Sep 2022 21:44:02 -0700 Subject: [PATCH 1622/2474] Implement rewind buffer First pass on a rewind buffer that tracks client position and allows seeking to an arbitrary time for recalculating movement, damage, corrected for latency. --- ssqc/antilag.qc | 310 +++++++++++++++++++++++++++++++++++++++++++++++- ssqc/client.qc | 3 + ssqc/progs.src | 2 +- 3 files changed, 313 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 80831003..40ffe4b1 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -26,4 +26,312 @@ void AL_ProjectProjectile (entity projectile) { } setorigin(projectile, projected_origin); -} \ No newline at end of file +} + +#define DEBUG_ANTILAG 0 + +#if DEBUG_ANTILAG +#define printf(...) sprint(self, PRINT_HIGH, sprintf(__VA_ARGS__)) +#define printd(...) dprint(sprintf(__VA_ARGS__)) +#else +#define printf(...) +#define printd(...) +#endif + +#define AL_MAX_REWINDS 25 +#define AL_FRAME_LIMIT (1/77.0) + +struct RewindSnapshot { + float time; + vector origin; + vector velocity; +}; + +struct RewindState { + entity owner; + RewindSnapshot snapshot[AL_MAX_REWINDS]; + + float rewound; + vector tmp_origin; + vector tmp_velocity; + RewindSnapshot* rewound_from; + + float cursor; + float cursor_limit; + + float allocated; + RewindState* next; + RewindState* prev; +}; + +RewindState* rewind_players; + +RewindState* AllocRewind(entity ent) { + RewindState* state = memalloc(sizeof(RewindState)); + state.cursor = 0; + state.cursor_limit = time + AL_FRAME_LIMIT; + state.owner = ent; + return state; +} + +void FreeRewind(RewindState* h) { + memfree(h); +} + + +void RL_Insert(RewindState** head, RewindState* node) { + if (!*head) { + node->next = node->prev = node; + *head = node; + } else { + node->next = *head; + node->prev = (*head)->prev; + + (node->next)->prev = (node->prev)->next = node; + } +} + +void RL_Remove(RewindState** head, RewindState* node) { + if (*head == node) { + *head = __NULL__; + } else { + (node->next)->prev = node->prev; + (node->prev)->next = node->next; + } +} + +#define RL_FOR_EACH(_head, _var) \ + for (RewindState* _var = _head; _var;\ + _var = _var->next != head ? _var->next : __NULL__) + +RewindSnapshot* RewindLog(RewindState* target) { + if (target->owner != self) + error("Log mismatch\n"); + + if (time > target->cursor_limit) { + target->cursor = (target->cursor + 1) % AL_MAX_REWINDS; + target->cursor_limit = time + AL_FRAME_LIMIT; + } + + RewindSnapshot* snapshot = &target->snapshot[target->cursor]; + snapshot->time = time; + snapshot->origin = target->owner.origin; + snapshot->velocity = target->owner.velocity; + + return snapshot; +} + +struct SeekResult { + RewindSnapshot *before; + RewindSnapshot *after; + RewindSnapshot *nearest; +}; + +inline float NextIndex(float pos) { return (pos + 1) % AL_MAX_REWINDS; } +inline float Index(float pos) { return (pos + AL_MAX_REWINDS) % AL_MAX_REWINDS; } +inline float PrevIndex(float pos) { return Index(pos - 1); } + +void DumpPos(RewindState* target, float pos) { + printd(" dump %d %0.2f\n", Index(pos), target->snapshot[Index(pos)].time); +} + +void SeekCheck(RewindState* target, float when, SeekResult* r) { + float before = 0, after = time, nearest = when + 1; + + for (int i = 0; i < AL_MAX_REWINDS; i++) { + RewindSnapshot* s = &target->snapshot[i]; + + if (s->time && s->time > when && s->time < after) + after = s->time; + if (s->time && s->time < when && s->time > before) + before = s->time; + } + + if (fabs(when - before) < fabs(when - after)) + nearest = before; + else + nearest = after; + + if (before != (r.before)->time) + error(sprintf("before mismatch w=%f seek=%f check=%f\n", + when, (r.before)->time, before)); + if (after != (r.after)->time) + error(sprintf("after mismatch w=%f seek=%f check=%f\n", + when, (r.after)->time, after)); + if (nearest != (r.nearest)->time) + error(sprintf("nearest mismatch w=%f seek=%f check=%f\n", + when, (r.nearest)->time, nearest)); +} + +SeekResult Seek(RewindState* target, float when) { + SeekResult r; + r.before = r.after = r.nearest = __NULL__; + + float probe = floor((time - when) / AL_FRAME_LIMIT); + probe = max(probe - 3, 0); + printd(" probe = %d -> %d, %d\n", + probe, target->cursor, Index(target->cursor - probe)); + + if (probe > AL_MAX_REWINDS || probe < 0) + return r; + + probe = 0; // Conservative/safe for now. + float tmp = Index(target->cursor - probe); + printd(" t = %d c = %f\n", tmp, target->cursor); + while (target->snapshot[tmp].time > when) { + RewindSnapshot* snap = &target->snapshot[tmp]; + + r.after = &target->snapshot[tmp]; + printd(" %d >when %0.2f\n", tmp, (r.after)->time); + tmp = PrevIndex(tmp); + } + printd(" %d middle %0.2f\n", tmp, target->snapshot[tmp].time); + + if (target->snapshot[tmp].time > 0) { + r.before = &target->snapshot[tmp]; + printd(" %d time); + } + + DumpPos(target, tmp - 1); + DumpPos(target, tmp); + DumpPos(target, tmp + 1); + + r.nearest = r.after; + if (r.before && fabs((r.before)->time - when) < fabs((r.after)->time - when)) + r.nearest = r.before; + tmp = NextIndex(tmp); + + SeekCheck(target, when, &r); + return r; +} + +// TODO: Filter out observers, but no harm immediately. +void RL_Rewind(RewindState* head, entity exclude, float when) { + printd("REWIND START %p\n", head); + RL_FOR_EACH(head, rs) { + if (rs->owner == exclude || + when < rs->owner->spawn_time) { // Don't rewind to past life. + rs->rewound = 2; + printd("rewind skipped %s\n", exclude.netname); + continue; + } + + printd("start %s, %f -> %f %d\n", rs->owner.netname, time, when, + (time - when) / AL_FRAME_LIMIT); + SeekResult seek = Seek(rs, when); + RewindSnapshot* near = seek.nearest; + if (near) { + printd("trying to rewind %s to %f, found %f\n", rs->owner.netname, + when, near->time); + if (rs->rewound == 1) + error("ALREADY REWOUND"); + + rs->rewound = TRUE; + rs->tmp_origin = rs->owner.origin; + rs->tmp_velocity = rs->owner.velocity; + rs->owner.origin = near->origin; + rs->owner.velocity = near->velocity; + rs->rewound_from = near; + + pointparticles(particleeffectnum("fo_airblast"), near->origin); + } + } + printd("REWIND END\n"); +} + +void RL_RestorePresent(RewindState* head) { + RL_FOR_EACH(head, rs) { + if (rs->rewound == 1) { + printd("restoring %s\n", rs->owner.netname); + + rs->owner.origin = rs->tmp_origin; + rs->owner.velocity = rs->tmp_velocity; + } else { + printd("restore skipped %s\n", rs->owner.netname); + } + + rs->rewound = FALSE; + rs->rewound_from = __NULL__; + } +} + + +class FOPlayer { + RewindState* rewind_; + void() FOPlayer = { + rewind_ = AllocRewind(this); + RL_Insert(&rewind_players, rewind_); + }; + + virtual void() Destroy = { + RL_Remove(&rewind_players, rewind_); + + }; + + nonvirtual void() Respawn = { + + }; + + nonvirtual void() RewindUpdate = { + RewindLog(rewind_); + }; + + void(float when) RewindExcept = { + RL_Rewind(rewind_players, this, when); + }; + + static void (float when) RewindAll = { + RL_Rewind(rewind_players, world, when); + }; + + static void() RestoreAll { + RL_RestorePresent(rewind_players); + }; + + void() RestoreNow = { + if (rewind_->rewound == 1) { + this.origin = rewind_->tmp_origin; + this.velocity = rewind_->tmp_velocity; + rewind_->rewound = 2; + } + }; + + vector() TrueOrigin = { + if (rewind_->rewound == 1) { + return rewind_->tmp_origin; + } else { + return this->origin; + } + }; +}; + +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +float RewindForPlayer(entity p) { + // Live changeagble for now. + float project_detpipe = CF_GetSetting("pd", "project_detpipe", "off"); + // Want to lower this in time, but good for testing. + float project_detpipe_max_lat = + CF_GetSetting("pdml", "project_max_latency", "500") / 1000; + + project_detpipe_max_lat = min(project_detpipe_max_lat, + ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT) * 2); + + if (!project_detpipe) + return FALSE; + + local float rtt = infokeyf(p, INFOKEY_P_PING) / 1000; + rtt = max(rtt, project_detpipe_max_lat); + + if (rtt < 0.013) + return FALSE; + rtt = min(rtt, project_detpipe_max_lat); + + FOPlayer fop = (FOPlayer)p; + fop.RewindExcept(time - rtt/2); + return TRUE; +} + +void UnrewindPlayer(entity p) { + FOPlayer fop = (FOPlayer)p; + fop.RestoreNow(); +} diff --git a/ssqc/client.qc b/ssqc/client.qc index a4a3c1be..f23b7b37 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2946,6 +2946,8 @@ void () CheckPowerups = { void () PlayerPostThink = { UpdateScoreboardInfo(self); + FOPlayer fop = (FOPlayer)self; + fop.RewindUpdate(); if (self.view_ofs == '0 0 0') { return; @@ -3036,6 +3038,7 @@ void () ClientConnect = { local string st; local float got_one; + spawnfunc_FOPlayer(); bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; diff --git a/ssqc/progs.src b/ssqc/progs.src index b4c38f88..e535fdef 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -12,6 +12,7 @@ defs.qc ../share/commondefs.qc ../share/common_helpers.qc qw.qc +antilag.qc events.qc roles.qc q3defs.qc @@ -28,7 +29,6 @@ subs.qc combat.qc items.qc locfiles.qc -antilag.qc weapons.qc world.qc client.qc From dcf8b01a852b725044f8c0692df1f91bb69d3d0a Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 18 Sep 2022 10:40:51 -0700 Subject: [PATCH 1623/2474] Connect detpipe to rewind We use the rewound position to calculate damage, but the current position to calculate knockback. This will bear some tinkering as movement replay gets more sophisticated (as well as rewinding some flag events), but this is OK as a testing starting point. We have to be careful of a few things, e.g. not applying to rewind to non-pipebombs as they share think programs as well as not rewinding server triggered events (such as death detonating pipebombs) since they're independent of user latnecy. --- ssqc/combat.qc | 90 ++++++++++++++++++++++++++++++++++++++++--------- ssqc/demoman.qc | 1 + ssqc/weapons.qc | 10 +++++- 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index f9d580f0..65c09536 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -269,7 +269,7 @@ void (entity targ, entity attacker) KillSound = { }; void (entity targ, entity inflictor, entity attacker, - float damage) T_Damage = { + float damage, float knock_damage) T_DamageKnock = { local vector dir; local entity oldself, te; local float save; @@ -324,22 +324,22 @@ void (entity targ, entity inflictor, entity attacker, } if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK)) { - targ.immune_to_check = time + (damage / 20); + targ.immune_to_check = time + (knock_damage / 20); dir = targ.origin - ((inflictor.absmin + inflictor.absmax) * 0.5); dir = normalize(dir); - if (((damage < 60) && + if (((knock_damage < 60) && ((attacker.classname == "player") && (targ.classname == "player"))) && (attacker.netname != targ.netname)) - targ.velocity = targ.velocity + dir * damage * 11; + targ.velocity = targ.velocity + dir * knock_damage * 11; else - targ.velocity = targ.velocity + dir * damage * 8; + targ.velocity = targ.velocity + dir * knock_damage * 8; if (((rj > 1) && ((attacker.classname == "player") && (targ.classname == "player"))) && (attacker.netname == targ.netname)) - targ.velocity = (targ.velocity + ((dir * damage) * rj)); + targ.velocity = (targ.velocity + ((dir * knock_damage) * rj)); } if (targ.flags & FL_GODMODE) return; @@ -395,8 +395,13 @@ void (entity targ, entity inflictor, entity attacker, self = oldself; }; -void (entity targ, entity inflictor, entity attacker, float damage, - float T_flags, float T_AttackType) TF_T_Damage = { +void (entity targ, entity inflictor, entity attacker, + float damage) T_Damage = { + T_DamageKnock(targ, inflictor, attacker, damage, damage); +} + +void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, + float damage, float knock_damage, float T_flags, float T_AttackType) { local vector dir; local entity oldself; local entity te; @@ -405,6 +410,7 @@ void (entity targ, entity inflictor, entity attacker, float damage, local float olddmsg; local float no_damage; local float moment; + local float original_damage = damage; if (targ.takedamage == 0) return; @@ -523,21 +529,20 @@ void (entity targ, entity inflictor, entity attacker, float damage, targ.dmg_inflictor = inflictor; } - if (!(T_AttackType & TF_TD_NOMOMENTUM)) { + knock_damage = floor(damage / original_damage * knock_damage); + if (!(T_AttackType & TF_TD_NOMOMENTUM) && knock_damage) { if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && !(targ.tfstate & TFSTATE_CANT_MOVE)) { if (deathmsg != DMSG_GREN_NAIL && deathmsg != DMSG_GREN_SHOCK && deathmsg != DMSG_GREN_BURST) { targ.immune_to_check = time + damage / 20; dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; dir = normalize(dir); - moment = damage; + moment = knock_damage; if (inflictor.classname == "pyro_rocket" && pyro_type == 1) { - moment = damage * 1.25; - if (attacker == targ) { - moment = damage * 1.5; + moment *= 1.5; } else { - moment = damage * 1.25; + moment *= 1.25; } } @@ -691,6 +696,12 @@ void (entity targ, entity inflictor, entity attacker, float damage, self = oldself; }; +void TF_T_Damage(entity targ, entity inflictor, entity attacker, + float damage, float T_flags, float T_AttackType) { + TF_T_DamageKnock(targ, inflictor, attacker, damage, damage, + T_flags, T_AttackType); +} + void (entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage = { local float points; @@ -717,7 +728,8 @@ void (entity inflictor, entity attacker, float damage, T_Damage(head, inflictor, attacker, points * 0.5); else - TF_T_Damage(head, inflictor, attacker, points, + TF_T_DamageKnock(head, inflictor, attacker, points, + points, TF_TD_NOTTEAM, TF_TD_EXPLOSION); } } @@ -727,6 +739,54 @@ void (entity inflictor, entity attacker, float damage, } }; +float RewindForPlayer(entity p); + +.float last_det_forced; // state would be nicer, but cleared at respawn. +// Will merge with RadiusDamage in time. +void T_RadiusDamage_Antilag (entity inflictor, entity attacker, float damage, + entity ignore) { + float dmg[2]; + vector org[2]; + + // No short circuiting, consider enabling. + if (attacker.last_det_forced) + return T_RadiusDamage(inflictor, attacker, damage, ignore); + if (!RewindForPlayer(attacker)) + return T_RadiusDamage(inflictor, attacker, damage, ignore); + + int count; + entity* list = findradius_list(inflictor.origin, damage + 40, count); + for (int i = 0; i < count; i++) { + entity c = list[i]; + if (c == ignore || !c.takedamage || !CanDamage(c, inflictor)) + continue; + + FOPlayer fc = (FOPlayer)c; + + org[0] = c.origin + (c.mins + c.maxs) * 0.5; + org[1] = fc.TrueOrigin() + (c.mins + c.maxs) * 0.5; + + for (int j = 0; j < 2; j++) { + float points = 0.5 * vlen(inflictor.origin - org[j]); + if (points < 0) + points = 0; + points = damage - points; + if (c == attacker) + points = points * 0.75; + dmg[j] = points; + } + + fc.RestoreNow(); // Use current location for knockback, etc. + dmg[1] = min(dmg[0], dmg[1]); // Limit Kerbal. + + if (dmg[0] > 0) + TF_T_DamageKnock(c, inflictor, attacker, dmg[0], dmg[1], + TF_TD_NOTTEAM, TF_TD_EXPLOSION); + } + FOPlayer::RestoreAll(); + +} + void (entity attacker, float damage) T_BeamDamage = { local float points; local entity head; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 110e4370..1a622975 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -26,6 +26,7 @@ float (float force) TeamFortress_DetonatePipebombs = { return impulse_queue ? FALSE : TRUE; } + self.last_det_forced = force; e = find(world, classname, "pipebomb"); while (e != world) { if (e.owner == self) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 252fcd4e..62a2abb2 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1252,8 +1252,12 @@ void () W_FireLightning = { LightningDamage(self.origin, trace_endpos + v_forward * 4, self, 30); }; +void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, + entity ignore); + void () GrenadeExplode = { local entity te; + float use_antilag = FALSE; if (self.voided) return; @@ -1262,10 +1266,14 @@ void () GrenadeExplode = { if (self.classname == "pipebomb") { if (!(self.flags & 512)) self.weapon = 40; + use_antilag = TRUE; } if (self.owner.has_disconnected != 1) { deathmsg = self.weapon; - T_RadiusDamage(self, self.owner, 120, world); + if (!use_antilag) + T_RadiusDamage(self, self.owner, 120, world); + else + T_RadiusDamage_Antilag(self, self.owner, 120, world); } if (self.no_active_nail_grens != 0) { From 8203a62e7208410bd239fd6172a23c1520584097 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 19 Sep 2022 12:50:19 -0700 Subject: [PATCH 1624/2474] Assign ent numbers to grenade timer objects so that we can play on their own channels and get out of the channel game entirely. Seems to work reliably under testing. Also try to "perfectly" emulate the old grenade timer sounds in case there are still problems. This means pulling them out of the object and back to the CSQC-call chain so that self can be world and not the object. This can be enabled with fo_grentimer_debug 2. (I tried it the other way but under testing the new timers seemed more reliable now that they're on their own ent (from sound system pov) so..... we'll see.) --- csqc/csextradefs.qc | 4 ++++ csqc/events.qc | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3b528779..859633a0 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -458,6 +458,9 @@ class CsGrenTimer { nonvirtual void() set_thrown { flags_ |= FL_GT_THROWN; }; nonvirtual float() is_thrown { return flags_ & FL_GT_THROWN; }; nonvirtual float() channel { return channel_; }; + nonvirtual float() sound_offset { + return 3.8 - (expires_at_ - time); + }; nonvirtual void(float primed_at, float expires_at, float grentype, float timer_flags) Set; @@ -470,6 +473,7 @@ class CsGrenTimer { float num_gren_sound = CHAN_GREN_END - CHAN_GREN_START + 1; for (float i = 0; i < NUM_GREN_TIMERS; i++) grentimers[i] = spawn(CsGrenTimer, + entnum: 10000 + i, channel_: CHAN_GREN_START + (i % num_gren_sound)); }; diff --git a/csqc/events.qc b/csqc/events.qc index d838e018..647a1ddc 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -337,7 +337,7 @@ void OldPlayGren(float offset) { local string wav = GetGrenTimerSound(); localsound(wav, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime - soundupdate(world, channel, wav, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); + soundupdate(self, channel, wav, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); } void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, @@ -356,30 +356,33 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, if !(this.flags_ & FL_GT_SOUND) return; - local float adj = 3.8 - (expires_at_ - time); string wav = GetGrenTimerSound(); float volume = cvar(FOCMD_GRENTIMERVOLUME); - if (CVARF(fo_grentimer_debug) & 2) { - localsound(wav, channel_, volume); - soundupdate(world, channel_, wav, volume, 0, 0, 0, adj); - } else { - // Default to old until new gets more testing. - OldPlayGren(adj); - } + // Can't localsound since that goes to world. There's also a bug where + // starting sound with soundupdate returns false, even though it started, + // so "retry" for that as well as resiliency for now. + soundupdate(this, CHAN_WEAPON, wav, volume, 0, 0, 0, sound_offset()); + soundupdate(this, CHAN_WEAPON, wav, volume, 0, 0, 0, sound_offset()); } void CsGrenTimer::Stop() { expires_at_ = -1; if (flags_ & FL_GT_SOUND) - soundupdate(self, channel_, "", 0, 0, 0, 0, 0); // -ve volume => stop. + soundupdate(this, CHAN_WEAPON, "", -1, 0, 0, 0, 0); // -volume => stop. flags_ = 0; } void StopGrenTimers() { + // New style. for (float i = 0; i < NUM_GREN_TIMERS; i++) grentimers[i].Stop(); + + // Old style. + for (float i = CHAN_GREN_START; i <= CHAN_GREN_END; i++) { + soundupdate(self, i, "", 0, 0, 0, 0, 0); + } } void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { @@ -396,19 +399,32 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { // 2 [and something sane for anything we don't recognize.] default: timer_flags = FL_GT_SOUND | FL_GT_ADJPING; break; } + + float debug_print_state = CVARF(fo_grentimer_debug) & 1; + float debug_use_old_sound = CVARF(fo_grentimer_debug) & 2; + + float play_old_sound = FALSE; + if (debug_use_old_sound) { + play_old_sound = timer_flags & FL_GT_SOUND; + timer_flags &= ~FL_GT_SOUND; + } + CsGrenTimer timer = CsGrenTimer::GetNext(); timer.Set(primed_at, explodes_at, grentype, timer_flags); - if (CVARF(fo_grentimer_debug) & 1) { + if (play_old_sound) + OldPlayGren(timer.sound_offset()); + + if (debug_print_state) { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; float expires_old = time + 3.8 - ping; float expires_new = timer.expiry(); float expires_ideal = explodes_at - ping/2; - print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f chan=%d\n", + print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f new_s=%d\n", primed_at, explodes_at, explodes_at - primed_at, - timer.channel())); + debug_use_new_sound)); print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", expires_ideal, expires_new, expires_old)); } From e7ac5a25cdcf80825a10442548c09b8125ba2284 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 19 Sep 2022 19:08:50 -0700 Subject: [PATCH 1625/2474] Fix merge conflicts on staging --- csqc/events.qc | 4 ++-- ssqc/progs.src | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 647a1ddc..4fbafb00 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -422,9 +422,9 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { float expires_new = timer.expiry(); float expires_ideal = explodes_at - ping/2; - print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f new_s=%d\n", + print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f old_s=%d\n", primed_at, explodes_at, explodes_at - primed_at, - debug_use_new_sound)); + debug_use_old_sound)); print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", expires_ideal, expires_new, expires_old)); } diff --git a/ssqc/progs.src b/ssqc/progs.src index e535fdef..f7346ea1 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -12,7 +12,6 @@ defs.qc ../share/commondefs.qc ../share/common_helpers.qc qw.qc -antilag.qc events.qc roles.qc q3defs.qc @@ -26,9 +25,10 @@ vote.qc extraents.qc help.qc subs.qc -combat.qc items.qc locfiles.qc +antilag.qc +combat.qc weapons.qc world.qc client.qc From 8282291a85fb9495a648d0b90779f98707c896d3 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 20 Sep 2022 00:36:22 -0700 Subject: [PATCH 1626/2474] Flip default to old timers so we don't pick up grentimer_debug into clients for testing. In effort to mirror original magically working state (which is the default), restore original channels. Fix caching which got dropped in merge. Small cleanups. --- csqc/csextradefs.qc | 6 ++++-- csqc/events.qc | 16 +++++++--------- share/defs.h | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 859633a0..39721f0b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -471,7 +471,7 @@ class CsGrenTimer { static void() Init { float num_gren_sound = CHAN_GREN_END - CHAN_GREN_START + 1; - for (float i = 0; i < NUM_GREN_TIMERS; i++) + for (float i = 0; i < grentimers.length; i++) grentimers[i] = spawn(CsGrenTimer, entnum: 10000 + i, channel_: CHAN_GREN_START + (i % num_gren_sound)); @@ -483,7 +483,9 @@ class CsGrenTimer { }; static CsGrenTimer() GetNext { - return last_ = grentimers[next_index_++ % grentimers.length]; + next_index_ = (next_index_ + 1) % grentimers.length; + last_ = grentimers[next_index_]; + return last_; }; static CsGrenTimer() GetLast { return last_; }; diff --git a/csqc/events.qc b/csqc/events.qc index 647a1ddc..21644e6a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -108,7 +108,6 @@ void() CSQC_Parse_Event = { case MSG_GRENTHROWN: CsGrenTimer last = CsGrenTimer::GetLast(); last.set_thrown(); - //CsGrenTimer::GetLast().set_thrown(); break; case MSG_PLAYERDIE: last_death_time = readfloat(); @@ -311,6 +310,7 @@ string cached_timer; string GetGrenTimerSound() { string wav = cvar_string(FOCMD_GRENTIMERSOUND); if (cached_timer != wav) { + precache_sound(wav); cached_timer = wav; } return wav; @@ -359,18 +359,16 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, string wav = GetGrenTimerSound(); float volume = cvar(FOCMD_GRENTIMERVOLUME); - // Can't localsound since that goes to world. There's also a bug where - // starting sound with soundupdate returns false, even though it started, - // so "retry" for that as well as resiliency for now. - soundupdate(this, CHAN_WEAPON, wav, volume, 0, 0, 0, sound_offset()); - soundupdate(this, CHAN_WEAPON, wav, volume, 0, 0, 0, sound_offset()); + // Note there's a bug where soundupdate returns false for a new sample, even + // though it's started. + soundupdate(this, CHAN_VOICE, wav, volume, 0, 0, 0, sound_offset()); } void CsGrenTimer::Stop() { expires_at_ = -1; if (flags_ & FL_GT_SOUND) - soundupdate(this, CHAN_WEAPON, "", -1, 0, 0, 0, 0); // -volume => stop. + soundupdate(this, CHAN_VOICE, "", -1, 0, 0, 0, 0); // -volume => stop. flags_ = 0; } @@ -401,10 +399,10 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { } float debug_print_state = CVARF(fo_grentimer_debug) & 1; - float debug_use_old_sound = CVARF(fo_grentimer_debug) & 2; + float debug_use_new_sound = CVARF(fo_grentimer_debug) & 2; float play_old_sound = FALSE; - if (debug_use_old_sound) { + if (!debug_use_new_sound) { play_old_sound = timer_flags & FL_GT_SOUND; timer_flags &= ~FL_GT_SOUND; } diff --git a/share/defs.h b/share/defs.h index df2c16e7..c7f48f09 100644 --- a/share/defs.h +++ b/share/defs.h @@ -176,8 +176,8 @@ // We can overlap these with regular channels since they play on the world ent. #define NUM_GREN_TIMERS 5 // We overlap channels when >3 active. -#define CHAN_GREN_START 5 -#define CHAN_GREN_END 9 +#define CHAN_GREN_START 9 +#define CHAN_GREN_END 13 // #define CHAN_GREN_END (CHAN_GREN_START + NUM_GREN_TIMERS - 1) #define ATTN_NONE 0 From fca6634d294e6d7e5dfd5953166de7088cc4e60b Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 20 Sep 2022 00:43:48 -0700 Subject: [PATCH 1627/2474] Resolve poor automatic merge --- csqc/events.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index cc641869..21644e6a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -420,9 +420,9 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { float expires_new = timer.expiry(); float expires_ideal = explodes_at - ping/2; - print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f old_s=%d\n", + print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f new_s=%d\n", primed_at, explodes_at, explodes_at - primed_at, - debug_use_old_sound)); + debug_use_new_sound)); print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", expires_ideal, expires_new, expires_old)); } From 251b014b5acb51beab0bbaefe73b7ea0fd06f94e Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 21 Sep 2022 18:13:57 -0700 Subject: [PATCH 1628/2474] Ensure negative offsets can't be emitted. Small inconsistencies between client time and server time can result in minute negative offsets that can stop the sound from playing. --- csqc/csextradefs.qc | 10 +++------- csqc/events.qc | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 39721f0b..679cf31d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -449,7 +449,6 @@ class CsGrenTimer { float primed_at_; float expires_at_; float flags_; - float channel_; float grentype_; nonvirtual float() active { return expires_at_ > time; }; @@ -457,9 +456,9 @@ class CsGrenTimer { nonvirtual float() grentype { return grentype_; }; nonvirtual void() set_thrown { flags_ |= FL_GT_THROWN; }; nonvirtual float() is_thrown { return flags_ & FL_GT_THROWN; }; - nonvirtual float() channel { return channel_; }; nonvirtual float() sound_offset { - return 3.8 - (expires_at_ - time); + float offset = max(3.8 - (expires_at_ - time), 0); + return offset; }; nonvirtual void(float primed_at, float expires_at, @@ -470,11 +469,8 @@ class CsGrenTimer { static CsGrenTimer last_; static void() Init { - float num_gren_sound = CHAN_GREN_END - CHAN_GREN_START + 1; for (float i = 0; i < grentimers.length; i++) - grentimers[i] = spawn(CsGrenTimer, - entnum: 10000 + i, - channel_: CHAN_GREN_START + (i % num_gren_sound)); + grentimers[i] = spawn(CsGrenTimer); }; static void() StopAll { diff --git a/csqc/events.qc b/csqc/events.qc index 21644e6a..a6f5a9a3 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -420,7 +420,7 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { float expires_new = timer.expiry(); float expires_ideal = explodes_at - ping/2; - print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f new_s=%d\n", + print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f new=%d\n", primed_at, explodes_at, explodes_at - primed_at, debug_use_new_sound)); print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", From ee555a735eac21057267248108e99b383e931408 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 21 Sep 2022 20:30:48 -0700 Subject: [PATCH 1629/2474] Restore URI_GetCallback Misread prior error message, this is just a proto change and still being used by some communities. --- ssqc/login.qc | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/ssqc/login.qc b/ssqc/login.qc index 36faf1f3..a83f979d 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -12,3 +12,57 @@ void (entity player, string login, string secret) performLogin = { dprint(login); dprint("\n"); } + +void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback = { + local float got_one = 0; + self.login_in_progress = 0; + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (!responsecode) { + float num_args = tokenizebyseparator(resourcebody,";"); + self.login = argv(0); + forceinfokey(self,"*login", self.login); + bprint(2, infokey(self,"name")); + bprint(2, " has logged in as \s"); + bprint(2, self.login); + bprint(2, "\s\n"); + dprint(infokey(self,"name")); + dprint(" logged in as "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, "You have logged in as ", self.login, "\n"); + if (num_args > 1) { + if (argv(1) == "true") { + self.is_admin = TRUE; + forceinfokey(self,"*admin", ftos(self.is_admin)); + Admin_Aliases (); + bprint(2, self.netname, " \sgains full admin status!\s\n"); +// bprint (3, "\n"); + sprint(self, 2, "Type \scommands\s for admin commands.\n"); + } + } + if(self.team_no == 0 && !intermission_running) { + if (clanbattle && (self.has_disconnected != 1)) { + if (self.tf_id != 0) { + got_one = RejoinWithTfId(); + ResetAndRespawnPlayer(self); + } + if (!got_one) { + CreateTfIdAndJoin(); + } + } + if (!got_one) { + if (csqcactive) + Menu_Team(0); + else + Menu_Team(1); + } + } + } + else { + dprint(infokey(self,"name")); + dprint(" login failed: "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, ftos(responsecode), " - Login FAILED, invalid Login/Secret", "\n"); + } +} From bfd1f19b1fa5550fc5ad9637be1c4929141f2885 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 21 Sep 2022 23:30:54 -0700 Subject: [PATCH 1630/2474] Saw a mismatch between the optimized and basic seek i testing. Temporarily revert to the basic seek and fix a misclamp on rtt. --- ssqc/antilag.qc | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 40ffe4b1..952741b3 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -135,23 +135,34 @@ void DumpPos(RewindState* target, float pos) { printd(" dump %d %0.2f\n", Index(pos), target->snapshot[Index(pos)].time); } -void SeekCheck(RewindState* target, float when, SeekResult* r) { +SeekResult SeekBasic(RewindState* target, float when) { + SeekResult r; float before = 0, after = time, nearest = when + 1; + r.before = r.after = r.nearest = __NULL__; for (int i = 0; i < AL_MAX_REWINDS; i++) { RewindSnapshot* s = &target->snapshot[i]; - if (s->time && s->time > when && s->time < after) + if (s->time && s->time > when && s->time < after) { after = s->time; - if (s->time && s->time < when && s->time > before) + r.after = s; + } + if (s->time && s->time < when && s->time > before) { before = s->time; + r.before = s; + } } if (fabs(when - before) < fabs(when - after)) - nearest = before; + r.nearest = r.before; else - nearest = after; + r.nearest = r.after; + return r; +} + +#if 0 +void CompareSeek(SeekResult s1, SeekResult, s2) { if (before != (r.before)->time) error(sprintf("before mismatch w=%f seek=%f check=%f\n", when, (r.before)->time, before)); @@ -163,7 +174,8 @@ void SeekCheck(RewindState* target, float when, SeekResult* r) { when, (r.nearest)->time, nearest)); } -SeekResult Seek(RewindState* target, float when) { + +SeekResult SeekOpt(RewindState* target, float when) { SeekResult r; r.before = r.after = r.nearest = __NULL__; @@ -204,6 +216,14 @@ SeekResult Seek(RewindState* target, float when) { SeekCheck(target, when, &r); return r; } +#endif + +SeekResult Seek(RewindState* target, float when) { + SeekResult r; + r.before = r.after = r.nearest = __NULL__; + + return SeekBasic(target, when); +} // TODO: Filter out observers, but no harm immediately. void RL_Rewind(RewindState* head, entity exclude, float when) { @@ -320,7 +340,6 @@ float RewindForPlayer(entity p) { return FALSE; local float rtt = infokeyf(p, INFOKEY_P_PING) / 1000; - rtt = max(rtt, project_detpipe_max_lat); if (rtt < 0.013) return FALSE; From deabfa439ec5f7d5efa1f2a85b31e00b3112b0ec Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 22 Sep 2022 01:24:14 -0700 Subject: [PATCH 1631/2474] Enable correction of grenade prime time by player latency by default. --- ssqc/antilag.qc | 2 +- ssqc/client.qc | 6 +++++- ssqc/qw.qc | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index da2c9b5f..cbd7e89a 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -29,7 +29,7 @@ void AL_ProjectProjectile (entity projectile) { } float AL_GrenadeOffset() { - if (!CF_GetSetting("pg", "project_grenades", "off")) + if (!project_grenades) return 0; local float offset = infokeyf(self, INFOKEY_P_PING) / 1000; diff --git a/ssqc/client.qc b/ssqc/client.qc index 493b52e6..c5aa7f35 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -620,9 +620,12 @@ void () DecodeLevelParms = { // project projectile weapons by player ping project_weapons = CF_GetSetting("pw", "project_weapons", "off"); - // max projection latency (default 100ms) + // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); + // Correct grenade prime timing by player ping. + project_grenades = CF_GetSetting("pg", "project_grenades", "on"); + // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { @@ -1017,6 +1020,7 @@ void () DecodeLevelParms = { medicaura = FALSE; medicnocuss = FALSE; project_weapons = FALSE; + project_grenades = TRUE; distance_based_cuss_duration = FALSE; pyro_type = 1; drop_grenades = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 99c4c71a..d92cc4fa 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -599,6 +599,7 @@ float max_armor_hwguy; float project_weapons; float project_weapons_max_latency; +float project_grenades; float ng_velocity; float ng_damage; From a65caca7d177ec8c4bb56a9fc14d6450026b2fef Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 12 Sep 2022 00:31:19 -0700 Subject: [PATCH 1632/2474] Fix not-exploding napalm grenades (and eliminate grentimer effects) A long standing bug is that napalm grenades occasionally do not explode properly, leaving glowing, stuck entities. This turns out to be a race between several pieces of the code. 1. When the grenade initially explodes render a flare and start a timer program for the subsequent napalm explosions ("grentimer"). 2. When the program in (1) begins 100ms later, it tries to track the number of napalm (or gas) grenades active for the player in question. 3. When the player dies, conditional on there being no active napalm grenades we try to reclaim these timers. It turns out that when (3) occurs between the 100ms between (1) and (2) that the accounting can be incorrect and we'll remove the timer, but this incorrectly eliminated the subsequent explosion and left the grenade pinned until the ent was reclaimed (since the timer also owned its removal). There is no need for either: (1) The extra timer entity (2) The existing spam tracking For (1) we can extend the think state machine on the existing entity for both napalm and gas, this also allows us to completely eliminate all the clean-up complexity that (3) adds [now we can just remove grenades, rather than worrying about grenades also parenting area of effect timers that we also have to remove]. We throw (2) out for now. There are cleaner ways to write it if it's needed and it wasn't even working for gas grenades (because someone changed the timer name at some point). --- ssqc/pyro.qc | 107 +++++++++++++++++++---------------------------- ssqc/quadmode.qc | 6 --- ssqc/qw.qc | 2 - ssqc/spy.qc | 46 ++++++-------------- ssqc/tfort.qc | 15 ++----- ssqc/weapons.qc | 39 ----------------- 6 files changed, 59 insertions(+), 156 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 6a6a83c7..78640160 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -134,7 +134,23 @@ void () NapalmGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () NapalmGrenadeNetThink = { +void () NapalmGrenadeExplode2; + +// Explode1 is the initial "flare" before we start emitting dmg. +// Explode2 handles the subsequent explosions. +void () NapalmGrenadeExplode1 = { + local entity head; + + FO_Sound(self, CHAN_AUTO, "weapons/flmgrexp.wav", 1, ATTN_NORM); + traceline(self.origin, self.origin, 1, self); + if (trace_inwater != 1) + self.effects = self.effects | EF_DIMLIGHT; + self.think = NapalmGrenadeExplode2; + self.nextthink = time + 0.1; + self.heat = 0; +}; + +void () NapalmGrenadeExplode2 = { local entity head; local entity te; @@ -153,82 +169,45 @@ void () NapalmGrenadeNetThink = { break; } - if (self.heat == 0) { - self.owner.no_active_napalm_grens = - self.owner.no_active_napalm_grens + 1; - if (self.owner.no_active_napalm_grens > 2) { - te = find(world, classname, "grentimer"); - while (te) { - if ((te.owner == self.owner) && - (te.no_active_napalm_grens == 1)) { - te.weapon = DMSG_FLAME; - te.think = RemoveGrenade; - te.nextthink = time + 0.1; - } - te = find(te, classname, "grentimer"); - } - } - self.no_active_napalm_grens = self.owner.no_active_napalm_grens; - } self.nextthink = time + 1; - self.origin = self.enemy.origin; makevectors(self.v_angle); traceline(self.origin, self.origin, 1, self); - if (trace_inwater == 1) { + + local float ignited = self.effects & EF_DIMLIGHT; + if (trace_inwater == 1 && ignited) { + self.effects &= ~EF_DIMLIGHT; // Extinguish. FO_Sound(self, CHAN_VOICE, "misc/vapeur2.wav", 1, ATTN_NORM); - RemoveGrenade(); - return; - } - head = findradius(self.origin, 180); - while (head) { - if (head.takedamage) { - deathmsg = DMSG_FLAME; - - TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, - TF_TD_FIRE); - other = head; - Napalm_touch(); - if (other.classname == "player") { - stuffcmd(other, "bf\nbf\n"); + } else if (ignited) { + head = findradius(self.origin, 180); + while (head) { + if (head.takedamage) { + deathmsg = DMSG_FLAME; + + TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, + TF_TD_FIRE); + other = head; + Napalm_touch(); + if (other.classname == "player") { + stuffcmd(other, "bf\nbf\n"); + } } + head = head.chain; } - head = head.chain; + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + multicast(self.origin, MULTICAST_PHS); } - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); self.heat = self.heat + 1; - - if (self.heat >= maxExplosions) - RemoveGrenade(); -}; -void () NapalmGrenadeExplode = { - local entity head; - - FO_Sound(self, CHAN_AUTO, "weapons/flmgrexp.wav", 1, ATTN_NORM); - traceline(self.origin, self.origin, 1, self); - if (trace_inwater == 1) { + if (self.heat >= maxExplosions) dremove(self); - return; - } - self.effects = self.effects | EF_DIMLIGHT; - head = spawn(); - head.think = NapalmGrenadeNetThink; - head.classname = "grentimer"; - head.grenadename = "napalmfire"; - head.nextthink = time + 0.1; - head.heat = 0; - head.origin = self.origin; - head.owner = self.owner; - head.team_no = self.owner.team_no; - head.enemy = self; }; + void (vector org, entity shooter) NapalmGrenadeLaunch = { local float xdir; local float ydir; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 63a3c75a..163dab99 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -518,12 +518,6 @@ void () StartQuadRound = gren.nextthink = (time + 0.1); gren = find(gren, classname, "grenade"); } - gren = find(world, classname, "grentimer"); - while (gren) { - gren.think = SUB_Remove; - gren.nextthink = (time + 0.1); - gren = find(gren, classname, "grentimer"); - } te = find(world, classname, "detpack"); while (te){ if (te.weaponmode == 1) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 062c1d62..fe1ab59b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -241,8 +241,6 @@ float coop; .float last_saveme_sound; .float no_active_nail_grens; -.float no_active_napalm_grens; -.float no_active_gas_grens; /*======================================================================*/ /* TEAMFORTRESS GOALS */ diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 4b1a19ad..6aab6be0 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1,7 +1,6 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer; void (entity spy) TeamFortress_SpyCalcName; void () CF_Spy_UndercoverThink; -void () GasGrenadeMakeGas; void () T_TranqDartTouch; void () Spy_DropBackpack; void (entity targ, entity attacker) KillSound; @@ -1089,22 +1088,20 @@ void () GasGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () GasGrenadeExplode = { - local entity te; +void () GasGrenadeExplode2; + +// GasGrenadeExplode1 handles the initial "pre-explosion". +// GasGrenadeExplode2 handles aoe emission. +void () GasGrenadeExplode1 = { local float pos; pos = pointcontents(self.origin); if (pos == -1) { - te = spawn(); - te.think = GasGrenadeMakeGas; - te.nextthink = time + 0.1; - te.classname = "gastimer"; - te.heat = 0; - te.origin = self.origin; - te.owner = self.owner; - te.team_no = self.owner.team_no; - te.weapon = 0; - te.enemy = self; + self.think = GasGrenadeExplode2; + self.nextthink = time + 0.1; + self.heat = 0; + self.dimension_seen = DMN_INVISIBLE; + self.movetype = MOVETYPE_NONE; } else { pos = 0; while (pos < 10) { @@ -1123,31 +1120,14 @@ void () GasGrenadeExplode = { setsize(newmis, '-8 -8 -8', '8 8 8'); pos = pos + 1; } + dremove(self); } - dremove(self); }; -void () GasGrenadeMakeGas = { +void () GasGrenadeExplode2 = { local entity te; local entity timer; - if (self.heat == 0) { - self.owner.no_active_gas_grens = - self.owner.no_active_gas_grens + 1; - if (self.owner.no_active_gas_grens > 2) { - te = find(world, classname, "gastimer"); - while (te) { - if ((te.owner == self.owner) && - (te.no_active_gas_grens == 1)) { - te.weapon = 24; - te.think = RemoveGrenade; - te.nextthink = time + 0.1; - } - te = find(te, classname, "gastimer"); - } - } - self.no_active_gas_grens = self.owner.no_active_gas_grens; - } self.nextthink = time + 0.75; te = findradius(self.origin, 200); while (te != world) { @@ -1228,7 +1208,7 @@ void () GasGrenadeMakeGas = { self.weapon = 0; return; } - RemoveGrenade(); + dremove(self); }; void () HallucinationTimer = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 67a03042..4adfcae4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2488,7 +2488,7 @@ void () TeamFortress_RemoveTimers = { te = find(world, classname, "timer"); while (te != world) { - if ((te.owner == self) && (te.no_active_gas_grens <= 0)) { + if (te.owner == self) { dremove(te); te = find(world, classname, "timer"); } else @@ -2501,15 +2501,6 @@ void () TeamFortress_RemoveTimers = { self.StatusGrenTime = 0; Status_Refresh(self); - te = find(world, classname, "grentimer"); - while (te != world) { - if ((te.owner == self) && (te.no_active_napalm_grens <= 0)) { - dremove(te); - te = find(world, classname, "grentimer"); - } else - te = find(te, classname, "grentimer"); - } - te = find(world, classname, "item_tfgoal"); while (te) { if (te.owner == self) { @@ -3006,7 +2997,7 @@ void () TeamFortress_ExplodePerson = { FO_SetModel(newmis, "progs/biggren.mdl"); } else if (self.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; - newmis.think = NapalmGrenadeExplode; + newmis.think = NapalmGrenadeExplode1; newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; @@ -3026,7 +3017,7 @@ void () TeamFortress_ExplodePerson = { return; } else if (self.weapon == GR_TYPE_GAS) { newmis.touch = GasGrenadeTouch; - newmis.think = GasGrenadeExplode; + newmis.think = GasGrenadeExplode1; newmis.grenadename = "gasgrenade"; newmis.skin = 2; newmis.avelocity = '300 300 300'; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 252fcd4e..1df68a95 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3862,45 +3862,6 @@ void () SuperDamageSound = { return; }; -void () RemoveGrenade = { - local entity te; - - if (self.no_active_napalm_grens > 0) { - - self.no_active_napalm_grens = 0; - self.owner.no_active_napalm_grens = - self.owner.no_active_napalm_grens - 1; - if (self.owner.no_active_napalm_grens < 0) - self.owner.no_active_napalm_grens = 0; - - te = find(world, classname, "grentimer"); - while (te) { - if ((te.owner == self.owner) && - (te.no_active_napalm_grens > 0)) - te.no_active_napalm_grens = te.no_active_napalm_grens - 1; - te = find(te, classname, "grentimer"); - } - dremove(self.enemy); - dremove(self); - } - if (self.no_active_gas_grens > 0) { - - self.no_active_gas_grens = 0; - self.owner.no_active_gas_grens = - self.owner.no_active_gas_grens - 1; - if (self.owner.no_active_gas_grens < 0) - self.owner.no_active_gas_grens = 0; - - te = find(world, classname, "grentimer"); - while (te) { - if ((te.owner == self.owner) && (te.no_active_gas_grens > 0)) - te.no_active_gas_grens = te.no_active_gas_grens - 1; - te = find(te, classname, "grentimer"); - } - dremove(self); - } -}; - void () ToggleInvincibility = { if(self.tfstate & TFSTATE_INVINCIBLE) { self.items = self.items - (self.items & IT_INVULNERABILITY); From b99f11269b66affe3863dc9fe105fd494433dd87 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 22 Sep 2022 09:54:51 -0700 Subject: [PATCH 1633/2474] Remove "non-precise" grenades Now that we're happy with the new behavior and there's no differences from the old beyond precision, eliminate the old code and precise grenade option, there are now only "FO Grenades". --- README.md | 1 - ssqc/tfort.qc | 45 +++++++-------------------------------------- 2 files changed, 7 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 380a85c7..10e33d02 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ New features * `localinfo project_grenades 0/1` [default: 0] Adjust the point at which grenades are primed to correct for client latency. Does not allow players to throw grenades any faster, or more frequently; only more consistently. -* `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 551549a9..d5e69479 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -932,9 +932,7 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { } }; -void () TeamFortress_GrenadePrimedThink; -void () FO_PreciseGrenadeThink; -float () FO_UsePreciseGrenades; +void () FO_GrenadeThink; // is_player defines whether this originated from the player or server. Player // generated primes are corrected for latency when project_grenades is on. @@ -1130,39 +1128,12 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { } } - if (FO_UsePreciseGrenades()) - tGrenade.think = FO_PreciseGrenadeThink; - else - tGrenade.think = TeamFortress_GrenadePrimedThink; + tGrenade.think = FO_GrenadeThink; self.grenade_timer = tGrenade; }; -void () TeamFortress_GrenadePrimedThink = { - local entity user; - - user = self.owner; - if (!(user.tfstate & TFSTATE_GRENTHROWING) && !user.deadflag && !user.has_disconnected) { - self.nextthink = time + 0.1; - if (!self.think) - dremove(self); - - if (time > self.heat && self.weapon != GR_TYPE_CALTROP) - TeamFortress_ExplodePerson(); - - return; - } - if (!(user.tfstate & TFSTATE_GRENPRIMED)) - dprint("GrenadePrimed logic error\n"); - - FO_SpawnThrownGrenade(self); - dremove(self); -}; - -float () FO_UsePreciseGrenades = { - return FO_GetUserSetting(self, "precise_grenades", "pg", "on"); -} -void () FO_PreciseGrenadeThink = { +void () FO_GrenadeThink = { local entity user = self.owner; // Claim: These cases do not exist for FO; to be removed once proven true. @@ -1186,12 +1157,13 @@ void () FO_PreciseGrenadeThink = { self.nextthink = self.heat; } } else { - TeamFortress_ExplodePerson(); + if (self.weapon != GR_TYPE_CALTROP) + TeamFortress_ExplodePerson(); dremove(self); } } -void () FO_ThrowPreciseGrenade = { +void () FO_ThrowGrenade = { local entity timer = self.grenade_timer; if (timer.nextthink != timer.heat || timer.heat - time < 0.1) { // We do not allow throwing within the first second, or the last 0.1. @@ -1212,10 +1184,7 @@ void () TeamFortress_ThrowGrenade = { return; self.tfstate |= TFSTATE_GRENTHROWING; - // While this is controlled by localinfo, it's a per-grenade value. - if (FO_UsePreciseGrenades() && - self.grenade_timer.think == FO_PreciseGrenadeThink) - FO_ThrowPreciseGrenade(); + FO_ThrowGrenade(); }; void () TeamFortress_GrenadeSwitch = { From 654677f55a6bd127aa7ec943eb2fbb0ca93348cb Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 22 Sep 2022 12:16:38 -0700 Subject: [PATCH 1634/2474] Grenade timer visual tweaks zel pointed out it's nicer to stack timers by expiry time when some is spamm^Whas several active simultaneously. Also, he thought he might have seen 2 opaque timers. This could happen momentarily if prime and throw messages are reordered, but we can actually hide this easily by always rendering stacked timers as transparent. --- csqc/csextradefs.qc | 4 +++- csqc/status.qc | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 679cf31d..9047c3e4 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -446,11 +446,13 @@ class CsGrenTimer; CsGrenTimer grentimers[NUM_GREN_TIMERS]; class CsGrenTimer { + float index_; float primed_at_; float expires_at_; float flags_; float grentype_; + nonvirtual float() index { return index_; }; nonvirtual float() active { return expires_at_ > time; }; nonvirtual float() expiry { return expires_at_; }; nonvirtual float() grentype { return grentype_; }; @@ -470,7 +472,7 @@ class CsGrenTimer { static void() Init { for (float i = 0; i < grentimers.length; i++) - grentimers[i] = spawn(CsGrenTimer); + grentimers[i] = spawn(CsGrenTimer, index_: i); }; static void() StopAll { diff --git a/csqc/status.qc b/csqc/status.qc index b01b4817..7e9128af 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -96,8 +96,8 @@ void(string panelid, float display, string text) drawSpecial = { }; void(string panelid, float display, string text) drawGrenTimerPanel = { - local float timeleft; - local float timercount = 0; + float timeleft; + float timercount = 0; if (display) { FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); @@ -110,8 +110,11 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { panel2.Display = panel.Display; panel2.FillSize = panel.FillSize; - for (float i = 0; i < grentimers.length; i++) { - local CsGrenTimer gt = grentimers[i]; + CsGrenTimer lt = CsGrenTimer::GetLast(); + // We want to render in reverse mod order from the last primed grenade + // here, that way we'll properly stack timers relative to expiry. + for (float i = grentimers.length; i > 0; i--) { + CsGrenTimer gt = grentimers[(lt.index() + i) % grentimers.length]; if (!gt.active()) continue; @@ -125,7 +128,11 @@ void(string panelid, float display, string text) drawGrenTimerPanel = { panel2.TextScale = TextScale * 0.8; } - local float alpha = (gt.is_thrown()) ? 0.3 : 1.0; + // It's technically possible to get a primed message before thrown + // if things get reordered, but since we can only ever have one + // grenade primed, we can obscure this by always considering + // grenades after the first as primed. + float alpha = (gt.is_thrown() || timercount) ? 0.3 : 1.0; Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[gt.grentype()].icon, alpha); panel2.Position = panel2.Position + From 699c37429e6461e4ee4c32516261115f79294eed Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 22 Sep 2022 14:34:21 -0700 Subject: [PATCH 1635/2474] Disable voting in quadmode The voting code is fairly spaghettified; but this adapts the existing (partial) clanbattle disable and makes sure we also hit the entry points that I found in commands.qc --- ssqc/client.qc | 2 ++ ssqc/qw.qc | 1 + ssqc/vote.qc | 31 ++++++++++++++++++++----------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 90194714..2d5f258d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -337,6 +337,8 @@ void () DecodeLevelParms = { quadmode = CF_GetSetting("quadmode", "quadmode", "off"); duelmode = CF_GetSetting("duelmode", "duelmode", "off"); + disable_voting = clanbattle || quadmode; + rounds = CF_GetSetting("rounds","rounds","on"); if (!rounds) rounds = -1; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 062c1d62..886bd972 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -442,6 +442,7 @@ float already_chosen_map; float clanbattle; float clan_scores_dumped; float cb_prematch; +float disable_voting; float v_break; float v_ready; .float allowvote; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 0edd71fd..fa1c9a1c 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -46,7 +46,7 @@ void (entity p, string vote) VoteForMap; void (entity pe_player) Vote_NextMap = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle || vote_style) + if (disable_voting || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_next) @@ -87,7 +87,7 @@ void (entity pe_player) Vote_NextMap = { void (entity pe_player) Vote_TrickMap = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle || vote_style) + if (disable_voting || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_trick) @@ -128,7 +128,7 @@ void (entity pe_player) Vote_TrickMap = { void (entity pe_player) Vote_RaceMap = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle || vote_style) + if (disable_voting || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass || pe_player.vote_race) @@ -168,7 +168,7 @@ void (entity pe_player) Vote_RaceMap = { // called from weapons.qc:ImpulseCommands() void (entity pe_player) Vote_ToggleMenu = { - if (clanbattle || vote_style) + if (disable_voting || vote_style) return; if (vote_started > 0 && !vote_abort) { @@ -240,7 +240,7 @@ float () Vote_GetRaceVotes = { void (entity pe_player) Vote_ForceNext = { local float f_votes, f_votes_needed, f_votes_left; - if (clanbattle || vote_style) + if (disable_voting || vote_style) return; if (!pe_player.team_no || !pe_player.playerclass) @@ -291,7 +291,7 @@ float () Vote_GetForceNextVotes = { // called from world.qc:StartFrame() void () Vote_Check = { - if (clanbattle || vote_style) + if (disable_voting || vote_style) return; local float closetime = timelimit - CF_MAPVOTE_FINISH; @@ -513,6 +513,9 @@ void () Vote_MenuClose = { // shows the map vote menu // called from Vote_Input(), Menu_Open() void (entity pe_player) Vote_Menu = { + if (disable_voting) + return; + local string s_choose, s_vote1, s_vote2, s_vote3, s_vote4, s_vote5; local string s_tmp1, s_tmp2, s_tmp3, s_tmp4, s_tmp5; local float f_width = 0, f_timeleft = 0; @@ -1043,7 +1046,7 @@ float (string ps_list) List_Count = { for (i = 0; i < f_length; i++) { // set current character - local string s_current = substr(ps_list, i, 1); + local string s_current = substring(ps_list, i, 1); // non-empty space => word if (s_current != " " && s_previous == " ") @@ -1066,7 +1069,7 @@ string (string ps_list, float pf_idx) List_Index = { for (i = 0; i < f_length; i++) { // set current character - local string s_current = substr(ps_list, i, 1); + local string s_current = substring(ps_list, i, 1); // non-empty space => start of word if (s_current != " " && s_previous == " ") { @@ -1077,14 +1080,14 @@ string (string ps_list, float pf_idx) List_Index = { // empty space => end of word if (s_current == " " && f_start > -1) - return strzone(substr(ps_list, f_start, i - f_start)); + return strzone(substring(ps_list, f_start, i - f_start)); s_previous = s_current; } // if f_start is set it means a list item was found if (f_start > -1) - return strzone(substr(ps_list, f_start, i - f_start)); + return strzone(substring(ps_list, f_start, i - f_start)); return strzone(string_null); }; @@ -1405,7 +1408,7 @@ void() vote_think = { }; void () StartVoting = { - if(voting_started) + if(voting_started || disable_voting) return; local float expires = CF_GetSetting("votetime", "vote_time", "60"); local entity te; @@ -1431,6 +1434,9 @@ void () StartVoting = { void (entity p, string vote) VoteForMap = { + if (disable_voting) + return; + float filehandle; filehandle = fopen(strcat("maps/",vote,".bsp"), FILE_READ); if (filehandle >= 0) { @@ -1468,6 +1474,9 @@ void (entity p, string vote) VoteForMap = { }; void (entity p) UnvoteForMap = { + if (disable_voting) + return; + if(p.vote_map) { if(vote_anarchy_mode) { bprint(PRINT_HIGH, p.netname, " \brecinds vote for\b ", p.vote_map.netname, " \bin battle\b\n"); From c14fb38c01a8fe55dae6ba8a06dcdba721eaa909 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 22 Sep 2022 01:28:47 -0700 Subject: [PATCH 1636/2474] Rewrite Detpipe The original detpipe implementation was written by finding each active pipebomb then chaining callbacks by setting their expiries to the present. This makes operations such as time manipulation more difficult as there isn't a parenting calling context. This reworks detpipe to work in-situ, allowing the detpipe call itself to own these manipulations, as well as more cleanly aligning with things like not rewinding prior to the pipe coooldown. --- ssqc/antilag.qc | 20 ++++++++++++-------- ssqc/combat.qc | 18 ++++++------------ ssqc/defs.qc | 1 + ssqc/demoman.qc | 39 ++++++++++++++++++++++++++++----------- ssqc/subs.qc | 6 ++++++ ssqc/weapons.qc | 29 +++++++++++++---------------- 6 files changed, 66 insertions(+), 47 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 952741b3..e2fbbe14 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -326,27 +326,30 @@ class FOPlayer { }; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; -float RewindForPlayer(entity p) { + +float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { // Live changeagble for now. float project_detpipe = CF_GetSetting("pd", "project_detpipe", "off"); // Want to lower this in time, but good for testing. float project_detpipe_max_lat = CF_GetSetting("pdml", "project_max_latency", "500") / 1000; - project_detpipe_max_lat = min(project_detpipe_max_lat, - ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT) * 2); - if (!project_detpipe) return FALSE; - local float rtt = infokeyf(p, INFOKEY_P_PING) / 1000; + project_detpipe_max_lat = min(project_detpipe_max_lat, + ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT) * 2); + + local float rtt = infokeyf(self, INFOKEY_P_PING) / 1000; + rtt = min(rtt, project_detpipe_max_lat); if (rtt < 0.013) return FALSE; - rtt = min(rtt, project_detpipe_max_lat); - FOPlayer fop = (FOPlayer)p; - fop.RewindExcept(time - rtt/2); + float rewind_to = max(farthest_rewind_point, time - rtt / 2); + + FOPlayer fop = (FOPlayer)self; + fop.RewindExcept(rewind_to); return TRUE; } @@ -354,3 +357,4 @@ void UnrewindPlayer(entity p) { FOPlayer fop = (FOPlayer)p; fop.RestoreNow(); } + diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 65c09536..959f732c 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -739,21 +739,17 @@ void (entity inflictor, entity attacker, float damage, } }; -float RewindForPlayer(entity p); -.float last_det_forced; // state would be nicer, but cleared at respawn. +// Implements T_RadiusDamage but with awareness that the rewound player position +// for damage and the current player position for knockback may not be the +// same. +// // Will merge with RadiusDamage in time. -void T_RadiusDamage_Antilag (entity inflictor, entity attacker, float damage, - entity ignore) { +void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, + entity ignore) { float dmg[2]; vector org[2]; - // No short circuiting, consider enabling. - if (attacker.last_det_forced) - return T_RadiusDamage(inflictor, attacker, damage, ignore); - if (!RewindForPlayer(attacker)) - return T_RadiusDamage(inflictor, attacker, damage, ignore); - int count; entity* list = findradius_list(inflictor.origin, damage + 40, count); for (int i = 0; i < count; i++) { @@ -783,8 +779,6 @@ void T_RadiusDamage_Antilag (entity inflictor, entity attacker, float damage, TF_T_DamageKnock(c, inflictor, attacker, dmg[0], dmg[1], TF_TD_NOTTEAM, TF_TD_EXPLOSION); } - FOPlayer::RestoreAll(); - } void (entity attacker, float damage) T_BeamDamage = { diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 50c45bca..86a566c2 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -341,6 +341,7 @@ void () SUB_Null; void (entity et, float f) SUB_Null_pain; void () SUB_UseTargets; void () SUB_Remove; +void (entity ent) RemoveDeferred; // // combat.qc diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 1a622975..ccd6689b 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -19,20 +19,37 @@ void () TeamFortress_DetpackCountDown; void CheckStateQ3Goal(entity trig); float (float force) TeamFortress_DetonatePipebombs = { - local entity e; - if (time < self.pipecooldown && !force) - { - return impulse_queue ? FALSE : TRUE; - } + return impulse_queue ? FALSE : TRUE; + + int count; + entity* pipes = find_list(classname, "pipebomb", EV_STRING, count); + + float rewound = FALSE; + if (!force && count > 0) + rewound = AL_RewindPlayersExceptSelf(self.pipecooldown); + + for (float i = 0; i < count; i++) { + deathmsg = pipes[i].weapon; + + if (pipes[i].owner == self) { + if !(pipes[i].flags & FL_ONGROUND) + deathmsg = pipes[i].flags & FL_ONGROUND ? pipes[i].weapon : + DMSG_GREN_PIPE_AIR; - self.last_det_forced = force; - e = find(world, classname, "pipebomb"); - while (e != world) { - if (e.owner == self) - e.nextthink = time; - e = find(e, classname, "pipebomb"); + T_RadiusDamage_Antilag(pipes[i], pipes[i].owner, 120, world); + + // This maintains some sort of awful hack that we'll remove. + pipes[i].voided = 1; + + RenderExplosion(pipes[i].origin); + RemoveDeferred(pipes[i]); + } } + + if (rewound) + FOPlayer::RestoreAll(); + return TRUE; }; diff --git a/ssqc/subs.qc b/ssqc/subs.qc index d0bae51a..1d64b39e 100644 --- a/ssqc/subs.qc +++ b/ssqc/subs.qc @@ -27,6 +27,12 @@ void () SUB_Remove = { dremove(self); }; + +void RemoveDeferred(entity e) { + e.nextthink = time; + e.think = SUB_Remove; +} + void () SetMovedir = { if (self.angles == '0 -1 0') self.movedir = '0 0 1'; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 62a2abb2..7391c270 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1252,6 +1252,15 @@ void () W_FireLightning = { LightningDamage(self.origin, trace_endpos + v_forward * 4, self, 30); }; +void RenderExplosion(vector origin) { + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, origin_x); + WriteCoord(MSG_MULTICAST, origin_y); + WriteCoord(MSG_MULTICAST, origin_z); + multicast(origin, MULTICAST_PHS); +} + void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, entity ignore); @@ -1263,18 +1272,11 @@ void () GrenadeExplode = { return; self.voided = 1; - if (self.classname == "pipebomb") { - if (!(self.flags & 512)) - self.weapon = 40; - use_antilag = TRUE; - } if (self.owner.has_disconnected != 1) { deathmsg = self.weapon; - if (!use_antilag) - T_RadiusDamage(self, self.owner, 120, world); - else - T_RadiusDamage_Antilag(self, self.owner, 120, world); + T_RadiusDamage(self, self.owner, 120, world); } + if (self.no_active_nail_grens != 0) { self.no_active_nail_grens = 0; @@ -1288,14 +1290,9 @@ void () GrenadeExplode = { te = find(te, classname, "grenade"); } } - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); - BecomeExplosion(); + RenderExplosion(self.origin); + dremove(self); }; void () GrenadeTouch = { From 2c1fa18644cdf9bbc972f96cb1d8f7335bf0c2d0 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 22 Sep 2022 16:59:22 -0700 Subject: [PATCH 1637/2474] Fix up conditional on death message --- ssqc/demoman.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index ccd6689b..87782c59 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -30,10 +30,7 @@ float (float force) TeamFortress_DetonatePipebombs = { rewound = AL_RewindPlayersExceptSelf(self.pipecooldown); for (float i = 0; i < count; i++) { - deathmsg = pipes[i].weapon; - if (pipes[i].owner == self) { - if !(pipes[i].flags & FL_ONGROUND) deathmsg = pipes[i].flags & FL_ONGROUND ? pipes[i].weapon : DMSG_GREN_PIPE_AIR; From f48ca3b9e855b6f62e64deaa424ff88580368d8e Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 23 Sep 2022 09:55:30 -0700 Subject: [PATCH 1638/2474] Enable antilag detpipe by default and move rendering rewind points behind `rewind_debug_show`. --- ssqc/antilag.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index e2fbbe14..195d41f1 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -227,6 +227,8 @@ SeekResult Seek(RewindState* target, float when) { // TODO: Filter out observers, but no harm immediately. void RL_Rewind(RewindState* head, entity exclude, float when) { + float show_rewind_points = CF_GetSetting("rds", "rewind_debug_show", "off"); + printd("REWIND START %p\n", head); RL_FOR_EACH(head, rs) { if (rs->owner == exclude || @@ -253,7 +255,8 @@ void RL_Rewind(RewindState* head, entity exclude, float when) { rs->owner.velocity = near->velocity; rs->rewound_from = near; - pointparticles(particleeffectnum("fo_airblast"), near->origin); + if (show_rewind_points) + pointparticles(particleeffectnum("fo_airblast"), near->origin); } } printd("REWIND END\n"); @@ -329,7 +332,7 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { // Live changeagble for now. - float project_detpipe = CF_GetSetting("pd", "project_detpipe", "off"); + float project_detpipe = CF_GetSetting("pd", "project_detpipe", "on"); // Want to lower this in time, but good for testing. float project_detpipe_max_lat = CF_GetSetting("pdml", "project_max_latency", "500") / 1000; From 4aa54864f1d9ac0f4a1db8cc2cb8991a186a1140 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 23 Sep 2022 14:25:06 -0700 Subject: [PATCH 1639/2474] Default the player quad limit to off for now This doesn't update fast enough when clients crash and is causing problems where people can't rejoin running games quickly enough. (More than the disruption random players were causing, which we can at least password away.) --- ssqc/clan.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 1662ef1a..351302de 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1091,7 +1091,7 @@ float () CheckAllPlayersReady = { bprint (2, "All players ready, starting match\n"); StartTimer (); - local float limit_quad_players = CF_GetSetting("lqp", "limit_quad_players", "on"); + local float limit_quad_players = CF_GetSetting("lqp", "limit_quad_players", "off"); if (limit_quad_players) { quad_maxplayers = f1; } From 475010356e0a2b488b1784859e1eae9f49ba469e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Sep 2022 01:24:53 +1000 Subject: [PATCH 1640/2474] Error go away --- ssqc/client.qc | 4 ++++ ssqc/tfort.qc | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 90194714..8a68e0aa 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2109,6 +2109,10 @@ void () PutClientInServer = { setmodel(self, "progs/player.mdl"); modelindex_player = self.modelindex; + if(no_fire_mode) { + return; + } + if(votemode) { SetVoteParams(self); return; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 4adfcae4..1d5965be 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -872,7 +872,7 @@ void (entity timer) FO_SpawnThrownGrenade = { FO_SetModel(newmis, "progs/biggren.mdl"); } else if (timer.weapon == GR_TYPE_NAPALM) { newmis.touch = NapalmGrenadeTouch; - newmis.think = NapalmGrenadeExplode; + newmis.think = NapalmGrenadeExplode1; newmis.grenadename = "napalmgrenade"; newmis.skin = 2; newmis.avelocity = '0 300 0'; @@ -888,7 +888,7 @@ void (entity timer) FO_SpawnThrownGrenade = { FO_SetModel(newmis, "progs/flare.mdl"); } else if (timer.weapon == GR_TYPE_GAS) { newmis.touch = GasGrenadeTouch; - newmis.think = GasGrenadeExplode; + newmis.think = GasGrenadeExplode1; newmis.grenadename = "gasgrenade"; newmis.skin = 3; newmis.avelocity = '300 300 300'; From 8834e0e1a6c04ddaccdfe5c13982543ea8f7f1a7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Sep 2022 01:27:38 +1000 Subject: [PATCH 1641/2474] Wrong branch --- ssqc/client.qc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 8a68e0aa..90194714 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2109,10 +2109,6 @@ void () PutClientInServer = { setmodel(self, "progs/player.mdl"); modelindex_player = self.modelindex; - if(no_fire_mode) { - return; - } - if(votemode) { SetVoteParams(self); return; From fd79ae63ecc665b2c8eadbd6879dca6c8dd34108 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Sep 2022 01:33:36 +1000 Subject: [PATCH 1642/2474] Don't let player spawn during no fire mode --- ssqc/client.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index 90194714..c011967f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2114,6 +2114,10 @@ void () PutClientInServer = { return; } + if(no_fire_mode) { + return; + } + if (self.last_playerclass == 0) self.last_playerclass = self.playerclass; From 58bfe5b01af1a00481e24d31a8df29be8df8cca9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Sep 2022 14:18:23 +1000 Subject: [PATCH 1643/2474] Auto set and unset password if none set in quad --- ssqc/clan.qc | 14 ++++++++++++++ ssqc/quadmode.qc | 6 ++++++ ssqc/qw.qc | 2 ++ 3 files changed, 22 insertions(+) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 1662ef1a..cedf0d32 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1082,6 +1082,20 @@ float () CheckAllPlayersReady = { if (intermission_running) return 0; + if (infokey(world, "needpass") != "1") { + local string default_password = "pineapple"; + cvar_set("password", default_password); + default_password_set = 1; + + local entity te = find(world, classname, "player"); + while (te != world) { + if (te.team_no) { + sprint(te, PRINT_HIGH, "Setting password to \"", default_password, "\"\n"); + } + te = find(te, classname, "player"); + } + } + local float f1 = TeamFortress_GetNoActivePlayers(); bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); if (v_ready == f1 && v_ready > 0) { diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 163dab99..12afdc1d 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -462,6 +462,12 @@ void () StartQuadRound = MapEndSequence(); clan_scores_dumped = 1; } + + if (default_password_set) { + cvar_set("password", "none"); + default_password_set = 0; + } + localcmd("stop\n"); return; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4f95c30c..013e026c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -669,6 +669,8 @@ float deathmsg; // Global, which is set before every T_Damage, t float intermission_running; float intermission_exittime; +float default_password_set; + // add clientkill ent defs .float clientkillforce; .float clientkillfree; From 8e001f14a00cb66921d5b4fa4c700f79c3a48d1a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Sep 2022 14:51:43 +1000 Subject: [PATCH 1644/2474] Ensure default_password is removed if match doesn't end --- ssqc/clan.qc | 2 +- ssqc/quadmode.qc | 4 ++-- ssqc/qw.qc | 2 -- ssqc/world.qc | 5 +++++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index cedf0d32..88412ce9 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1085,7 +1085,7 @@ float () CheckAllPlayersReady = { if (infokey(world, "needpass") != "1") { local string default_password = "pineapple"; cvar_set("password", default_password); - default_password_set = 1; + localcmd("localinfo default_password on\n"); local entity te = find(world, classname, "player"); while (te != world) { diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 12afdc1d..cdf1f5ca 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -463,9 +463,9 @@ void () StartQuadRound = clan_scores_dumped = 1; } - if (default_password_set) { + if (infokey(world, "default_password") == "on") { cvar_set("password", "none"); - default_password_set = 0; + localcmd("localinfo default_password off\n"); } localcmd("stop\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 013e026c..4f95c30c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -669,8 +669,6 @@ float deathmsg; // Global, which is set before every T_Damage, t float intermission_running; float intermission_exittime; -float default_password_set; - // add clientkill ent defs .float clientkillforce; .float clientkillfree; diff --git a/ssqc/world.qc b/ssqc/world.qc index b6c3c8eb..4baa2567 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -98,6 +98,11 @@ void () worldspawn = { number_of_teams = 0; quad_maxplayers = 0; + if (infokey(world, "default_password") == "on") { + cvar_set("password", "none"); + localcmd("localinfo default_password off\n"); + } + InitBodyQue(); if (self.model == "maps/e1m8.bsp") cvar_set("sv_gravity", "100"); From b775fd65aee02c2c3de3ed02c89e1051c471ecfd Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 18:58:39 -0700 Subject: [PATCH 1645/2474] Rewrite reloading Synchronizing client and server state for prediction and latency corection benefits from some clean touch points to work with and the current reload code is a spaghetti nightmare. Rework it while also coalescing the state we'll need for weapon prediction. Can be temporarily toggled with `rcon localinfo dunr off` --- share/defs.h | 1 + ssqc/actions.qc | 31 +++++++++++++++----- ssqc/progs.src | 1 + ssqc/weapons.qc | 77 ++++++++++++++++++++----------------------------- 4 files changed, 57 insertions(+), 53 deletions(-) diff --git a/share/defs.h b/share/defs.h index c7f48f09..a335c43c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -724,6 +724,7 @@ #define WEAP_DETPACK 131072 #define WEAP_TRANQ 262144 #define WEAP_LASER 524288 +#define WEAP_RAILGUN 524288 // still room for 12 more weapons // but we can remove some by giving the weapons // a weapon mode (like the rifle) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 99d2b3e8..d77f6780 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -485,7 +485,17 @@ void () RestoreDefaultWeapon = { } }; -void TeamFortress_ReloadWeapon(float weap) +void TeamFortress_OldReloadWeapon(float weap); +void FO_ReloadWeapon(float weap, float force); + +void TeamFortress_ReloadWeapon(float weap, float force) { + if (FO_UseNewReload()) + FO_ReloadWeapon(weap, force); + else + TeamFortress_OldReloadWeapon(weap); +} + +void TeamFortress_OldReloadWeapon(float weap) { RestoreDefaultWeapon(); @@ -496,6 +506,7 @@ void TeamFortress_ReloadWeapon(float weap) if (self.tfstate & TFSTATE_RELOADING) { return; } + if (weap == WEAP_SHOTGUN) { if (self.ammo_shells == 0) { sprint(self, PRINT_HIGH, "Out of shells\n"); @@ -759,7 +770,11 @@ void TeamFortress_ReloadWeapon(float weap) } void () TeamFortress_ReloadCurrentWeapon = { - TeamFortress_ReloadWeapon(self.current_weapon); + TeamFortress_ReloadWeapon(self.current_weapon, FALSE); +}; + +void () TeamFortress_ForceReloadCurrentWeapon = { + TeamFortress_ReloadWeapon(self.current_weapon, TRUE); }; void (float slot) TeamFortress_ReloadSlot = { @@ -778,7 +793,7 @@ void (float slot) TeamFortress_ReloadSlot = { return; weap = W_WeaponSlot3(); } - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); } else { if (slot < 1 || slot > 7) @@ -798,7 +813,7 @@ void (float slot) TeamFortress_ReloadSlot = { else if (slot == 7) weap = W_OldWeaponSlot7(); if (weap != 0) - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); } }; @@ -809,7 +824,7 @@ void () TeamFortress_ReloadNext = { // reload current slot first slot = W_GetSlot(self.current_weapon); if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon); + TeamFortress_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -828,7 +843,7 @@ void () TeamFortress_ReloadNext = { if (CheckForAmmo(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); reload = 1; break; } @@ -837,7 +852,7 @@ void () TeamFortress_ReloadNext = { else { slot = W_OldGetSlot(self.current_weapon); if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon); + TeamFortress_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -860,7 +875,7 @@ void () TeamFortress_ReloadNext = { if (CheckForAmmo(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); reload = 1; break; } diff --git a/ssqc/progs.src b/ssqc/progs.src index f7346ea1..2bd3c685 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -29,6 +29,7 @@ items.qc locfiles.qc antilag.qc combat.qc +../share/fo_weapons.qc weapons.qc world.qc client.qc diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 6939a302..d3a06182 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -46,6 +46,7 @@ void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void (entity pe_player, float f_type) CF_Identify; void () TeamFortress_ReloadCurrentWeapon; +void () TeamFortress_ForceReloadCurrentWeapon; void (float slot) TeamFortress_ReloadSlot; void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; @@ -1928,63 +1929,49 @@ void () W_Reload_assault_cannon = { Status_Refresh(self.owner); }; +float FO_CheckForReload(); + float () CheckForReload = { - if (self.current_weapon == WEAP_SHOTGUN) { - if (self.reload_shotgun >= 8 && self.ammo_shells > 0) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } + if (FO_UseNewReload()) + return FO_CheckForReload(); - return 1; - } - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } + float need_reload = FALSE; - return 1; - } + if (self.current_weapon == WEAP_SHOTGUN) { + if (self.reload_shotgun >= 8 && self.ammo_shells > 0) + need_reload = TRUE; + } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { + if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) + need_reload = TRUE; } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } - - return 1; - } + if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) + need_reload = TRUE; } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } - - return 1; - } + if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) + need_reload = TRUE; } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { - if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } - - return 1; - } + if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) + need_reload = TRUE; } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > 0) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } + if (fo_hwguy && self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE + && self.ammo_shells > 0) + need_reload = TRUE; + } - return 1; - } - } + if (need_reload) { + if (force_reload) + TeamFortress_ForceReloadCurrentWeapon(); + return 1; + } else { + return 0; } - return 0; }; +float FO_CheckForAmmo(float weapon); float (float weap) CheckForAmmo = { + if (FO_UseNewReload()) + return FO_CheckForAmmo(weap); + if (weap == WEAP_SHOTGUN) { if (self.reload_shotgun >= 1 && self.ammo_shells > self.reload_shotgun) return 1; From aa799aa87b1dadc01a614391843150d0725c4902 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 18:19:06 -0700 Subject: [PATCH 1646/2474] Add client_time Rather than implementing a-la-carte ping correction, introduce a centrally updated notion of client_time, that we can use in place of time when calculating next think times. We can also simplify all of the places we are careful not to go backwards in time by ensuring it's monotonically increasing. Update weapon projection to be based on client_time. Also document some errors in the current math that we'll forrect in the future. --- ssqc/antilag.qc | 32 +++++++++++++++++++++++++++++++- ssqc/client.qc | 9 +++++++++ ssqc/qw.qc | 18 +++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 4f37f058..ee556c27 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -298,6 +298,7 @@ void RL_RestorePresent(RewindState* head) { class FOPlayer { RewindState* rewind_; + void() FOPlayer = { rewind_ = AllocRewind(this); RL_Insert(&rewind_players, rewind_); @@ -376,4 +377,33 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { void UnrewindPlayer(entity p) { FOPlayer fop = (FOPlayer)p; fop.RestoreNow(); -} \ No newline at end of file +} + +.float client_time_internal; +float client_time(optional float ct_type = CT_NOEXTERNALEFFECT) { + return self.client_time_internal; +} + +void AL_UpdateClientTime(entity player) { + float offset; + + // Naively, we might want to offset by rtt/2, because that's how old the + // client's input is. However, the client's input is also relative to a + // world view that is itself rtt/2 behind. [Client is a full rtt behind, + // and it interpolates ahead to rtt/2 behind.] + // This means that if we want, say, "run to a position and perform an action" + // to have equivalent time, we need to correct by a full rtt. + offset = infokeyf(player, INFOKEY_P_PING) / 1000; + + offset = min(offset, antilag_settings.max_client_time_offset); + + float old_client_time = player.client_time_internal + if (time - offset > player.client_time_internal) + player.client_time_internal = time - offset; + + // Monotonically increasing and not dragging beyond 75% of time as/if RTT + // changes. + player.client_time_internal = max(player.client_time_internal, + old_client_time + (1/77.0 * 0.75)); +} + diff --git a/ssqc/client.qc b/ssqc/client.qc index 7ed1ed93..7b382a25 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -619,6 +619,10 @@ void () DecodeLevelParms = { airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); + // client_time max delta + antilag_settings.max_client_time_offset = + CF_GetSetting("almcto", "al_max_client_time_offset", "200"); + // project projectile weapons by player ping project_weapons = CF_GetSetting("pw", "project_weapons", "off"); @@ -2691,7 +2695,12 @@ void () CheckWaterJump = { } }; +void AL_UpdateClientTime(entity player); + void () PlayerPreThink = { + // We'll use this time for calculating ping adjusted expiration / projection / etc. + AL_UpdateClientTime(self); + if (self.impulse) { if (self.impulse == TF_VOTENEXT) { Vote_NextMap(self); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 38ff9d8a..4e3e46da 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -3,6 +3,21 @@ void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate; typedef void (float n) f_void_float; +enum { + CT_NOEXTERNALEFFECT, // No external effects (e.g. reload, build, prime, etc) +}; + +struct antilag_settings_t { + float max_client_time_offset; +} antilag_settings; + +// A monotonically increasing, latency corrected notion of client-time. +// Monotonicity guarantees that for some offset `o`: +// at t1: client_time() + o < at t2: client_time() + o FOR t2 > t1 +// E.g. That you never have to worry about the correction reordering events +// that `time + o` would not. +float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); + //=========================================================================== // TEAMFORTRESS Defs //=========================================================================== @@ -788,10 +803,11 @@ string goal_class_names[7] = { // people complain about settings, let's track them -string settings_to_track_list[3] = { +string settings_to_track_list[4] = { "sv_antilag", "project_weapons", "project_grenades", + "al_max_client_time_offset", }; typedef struct setting_t { From 6f965c4de0bbbd6d9fa8d5bf79ba5e9903d96468 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 20:17:27 -0700 Subject: [PATCH 1647/2474] Move weapon projection to use client_time The original code followed the reasoning: `Project projectiles forward in time based on ping up to configurable maximum (default 100ms). Effective projection time is maximum / 2 (eg 50ms), because we assume RTT is evenly distributed in both directions - and we want the server to spawn the entity in the position it would have have been if it had received the message (player_ping / 2) ago.` This was is not quite correct. It's true the client fired rtt/2 ago, however, this is not the whole story. The point that client fired from an was also an interpolated point at time-rtt/2. --- ssqc/antilag.qc | 63 ++++++++++++++++++++++++++----------------------- ssqc/client.qc | 1 + ssqc/qw.qc | 2 ++ 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index ee556c27..27c76a29 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,31 +1,24 @@ void AL_ProjectProjectile (entity projectile) { - // Project projectiles forward in time based on ping up to configurable maximum (default 100ms). - // Effective projection time is maximum / 2 (eg 50ms), because we assume RTT is evenly distributed in both - // directions - and we want the server to spawn the entity in the position it would have - // have been if it had received the message (player_ping / 2) ago. - local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; - - if (player_ping_s > project_weapons_max_latency) { - player_ping_s = project_weapons_max_latency; - } else if (player_ping_s <= 0.0013) { // Ping 13ms or lower? Don't do anything - return; - } - - local float time_offset = (player_ping_s / 2); - local vector projected_origin = projectile.origin + (projectile.velocity * time_offset); - - // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin - // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED - // because by tracing between old origin and projected origin we effectively have a single (last) frame - // rewind at the projected origin. The effect is high ping players are disadvantaged in close combat. - // This is preferable to unhappy low ping players. - traceline(projectile.origin, projected_origin, 0, self); - - if (trace_fraction < 1) { - projected_origin = trace_endpos; - } - - setorigin(projectile, projected_origin); + float time_offset = time - client_time(CT_SLOW_PROJECTILE); + + if (time_offset <= 0.013) // ping 13ms or lower? Don't do anything + return; + + vector projected_origin = projectile.origin + (projectile.velocity * time_offset); + // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin + // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED + // because by tracing between old origin and projected origin we effectively have a single (last) frame + // rewind at the projected origin. The effect is high ping players are disadvantaged in close combat. + // This is preferable to unhappy low ping players. + // + // XXX This will updated to use rewind. + traceline(projectile.origin, projected_origin, 0, self); + + if (trace_fraction < 1) { + projected_origin = trace_endpos; + } + + setorigin(projectile, projected_origin); } float AL_GrenadeOffset() { @@ -380,8 +373,20 @@ void UnrewindPlayer(entity p) { } .float client_time_internal; + float client_time(optional float ct_type = CT_NOEXTERNALEFFECT) { - return self.client_time_internal; + if (ct_type == CT_NOEXTERNALEFFECT) + return self.client_time_internal; + + float offset = time - self.client_time_internal; + float max_offset = 0; + switch (ct_type) { + case CT_SLOW_PROJECTILE: + max_offset = antilag_settings.max_projectile_slow_offset; + break; + } + + return max(self.client_time_internal, time - max_offset); } void AL_UpdateClientTime(entity player) { @@ -397,7 +402,7 @@ void AL_UpdateClientTime(entity player) { offset = min(offset, antilag_settings.max_client_time_offset); - float old_client_time = player.client_time_internal + float old_client_time = player.client_time_internal; if (time - offset > player.client_time_internal) player.client_time_internal = time - offset; diff --git a/ssqc/client.qc b/ssqc/client.qc index 7b382a25..46745aa7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -628,6 +628,7 @@ void () DecodeLevelParms = { // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); + antilag_settings.max_projectile_slow_offset = project_weapons_max_latency / 2; // Correct grenade prime timing by player ping. project_grenades = CF_GetSetting("pg", "project_grenades", "on"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4e3e46da..06445423 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -5,10 +5,12 @@ typedef void (float n) f_void_float; enum { CT_NOEXTERNALEFFECT, // No external effects (e.g. reload, build, prime, etc) + CT_SLOW_PROJECTILE, // Projectile for which judder is noticable (e.g. rocket) }; struct antilag_settings_t { float max_client_time_offset; + float max_projectile_slow_offset; } antilag_settings; // A monotonically increasing, latency corrected notion of client-time. From 3abcb5d8fb996c4e05bc1f1283b5807f816bc09d Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 18:53:56 -0700 Subject: [PATCH 1648/2474] Move grenade offsets to use client-time, eliminate AL_GrenadeOffset --- README.md | 3 --- ssqc/antilag.qc | 17 ----------------- ssqc/client.qc | 4 ---- ssqc/qw.qc | 4 +--- ssqc/tfort.qc | 15 ++++++--------- 5 files changed, 7 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 10e33d02..35be689c 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,6 @@ FortressOne Server New features ------ -* `localinfo project_grenades 0/1` [default: 0] Adjust the point at which - grenades are primed to correct for client latency. Does not allow players to -throw grenades any faster, or more frequently; only more consistently. * Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 27c76a29..07157db6 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -21,23 +21,6 @@ void AL_ProjectProjectile (entity projectile) { setorigin(projectile, projected_origin); } -float AL_GrenadeOffset() { - if (!project_grenades) - return 0; - - local float offset = infokeyf(self, INFOKEY_P_PING) / 1000; - local float smallest_grenade_think = 0.5; - - offset /= 2; - // Make sure we'll always order before first think. - offset = min(offset, smallest_grenade_think - 0.1); - - // Don't allow prime to move before throw (or to the same frame). - offset = min(offset, time - (self.last_throw + 0.013)); - - return offset; -} - #define DEBUG_ANTILAG 0 #if DEBUG_ANTILAG diff --git a/ssqc/client.qc b/ssqc/client.qc index 46745aa7..3428f491 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -630,9 +630,6 @@ void () DecodeLevelParms = { project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); antilag_settings.max_projectile_slow_offset = project_weapons_max_latency / 2; - // Correct grenade prime timing by player ping. - project_grenades = CF_GetSetting("pg", "project_grenades", "on"); - // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { @@ -1027,7 +1024,6 @@ void () DecodeLevelParms = { medicaura = FALSE; medicnocuss = FALSE; project_weapons = FALSE; - project_grenades = TRUE; distance_based_cuss_duration = FALSE; pyro_type = 1; drop_grenades = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 06445423..e8a919a9 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -617,7 +617,6 @@ float max_armor_hwguy; float project_weapons; float project_weapons_max_latency; -float project_grenades; float ng_velocity; float ng_damage; @@ -805,10 +804,9 @@ string goal_class_names[7] = { // people complain about settings, let's track them -string settings_to_track_list[4] = { +string settings_to_track_list[3] = { "sv_antilag", "project_weapons", - "project_grenades", "al_max_client_time_offset", }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index d5e69479..b4e418fa 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -934,8 +934,7 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { void () FO_GrenadeThink; -// is_player defines whether this originated from the player or server. Player -// generated primes are corrected for latency when project_grenades is on. +// is_player defines whether this originated from the player or server. void (float inp, float is_player) TeamFortress_PrimeGrenade = { local float gtype; local string gs; @@ -1100,13 +1099,11 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { else if (inp == 2) tGrenade.impulse = TF_GRENADE_2; - local float lag_adjust = is_player ? AL_GrenadeOffset() : 0; - - tGrenade.nextthink = time + 0.8 - lag_adjust; + tGrenade.nextthink = client_time() + 0.8; if (gtype == GR_TYPE_CALTROP) - tGrenade.heat = time + 0.5 + 0.5 - lag_adjust; + tGrenade.heat = client_time() + 0.5 + 0.5; else { - tGrenade.heat = time + 3 + 0.8 - lag_adjust; + tGrenade.heat = client_time() + 3 + 0.8; RemoveGrenadeTimers(); @@ -1114,7 +1111,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { local float notimers = stof(infokey(self, "nt")); if (grentimers && notimers != 1) { timer = spawn(); - timer.nextthink = time + 0.8 - lag_adjust; + timer.nextthink = client_time() + 0.8; timer.think = GrenadeTimer; timer.heat = 4; timer.owner = self; @@ -2918,7 +2915,7 @@ void () TeamFortress_ExplodePerson = { newmis.velocity = '0 0 0'; newmis.angles = vectoangles(newmis.velocity); newmis.think = SUB_Null; - newmis.nextthink = time + 0.1; + newmis.nextthink = time + 0.1; // Server generated, no client time here. if (self.weapon == GR_TYPE_NORMAL) { newmis.touch = NormalGrenadeTouch; From a8380640d7400ed73420468ab0f7a3670ad5be6d Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:12:24 -0700 Subject: [PATCH 1649/2474] Use clienttime for reload and attack_finished Correct for voluntary reloads/attacks --- ssqc/weapons.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d3a06182..92bde134 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -201,9 +201,9 @@ float () crandom = { void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) - self.attack_finished = time + att_delay * 2; + self.attack_finished = client_time() + att_delay * 2; else - self.attack_finished = time + att_delay; + self.attack_finished = client_time() + att_delay; }; float () W_FireAxe = { From 422c058cbc86679f7078e06b36a6af14d4df4860 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:21:48 -0700 Subject: [PATCH 1650/2474] Correct engineer build times for ping This is technically a small buff for a higher ping engineer in that the gun will be visibly under construction for a very small amount of reduced time. This seems fine. --- ssqc/engineer.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 5b9ca751..f63b7bdc 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -525,7 +525,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/disp.mdl"; newmis.netname = "dispenser"; - btime = time + 2; + btime = client_time() + 2; self.dispenser_ticks = 0; } else if (objtobuild == 2) { if (self.has_sentry) { @@ -537,7 +537,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/turrbase.mdl"; newmis.netname = "sentrygun"; - btime = time + 5; + btime = client_time() + 5; self.sentry_ticks = 0; } if (CheckArea(newmis, self) == 0) { From 094f97201fbe8fbcf9c8719fbf8d66acb550098e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Sep 2022 19:36:24 +1000 Subject: [PATCH 1651/2474] Set password to empty string --- ssqc/quadmode.qc | 2 +- ssqc/world.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index cdf1f5ca..1a51068f 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -464,7 +464,7 @@ void () StartQuadRound = } if (infokey(world, "default_password") == "on") { - cvar_set("password", "none"); + cvar_set("password", ""); localcmd("localinfo default_password off\n"); } diff --git a/ssqc/world.qc b/ssqc/world.qc index 4baa2567..fb55d0cb 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -99,7 +99,7 @@ void () worldspawn = { quad_maxplayers = 0; if (infokey(world, "default_password") == "on") { - cvar_set("password", "none"); + cvar_set("password", ""); localcmd("localinfo default_password off\n"); } From 4c1e24fbd5abdddd7119fa33cad22f6ef187967c Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:31:02 -0700 Subject: [PATCH 1652/2474] Correct spy actions for latency --- ssqc/client.qc | 4 ++-- ssqc/commands.qc | 2 +- ssqc/menu.qc | 18 +++++++++--------- ssqc/spy.qc | 34 +++++++++++++++++----------------- ssqc/tfort.qc | 4 ++-- ssqc/tfortmap.qc | 8 ++++---- ssqc/weapons.qc | 38 +++++++++++++++++++------------------- 7 files changed, 54 insertions(+), 54 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 3428f491..e435b706 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2303,10 +2303,10 @@ void () PutClientInServer = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a40dec71..510d136d 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -511,7 +511,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { //Menu_Spy_Color_Input(stof(arg3)); farg3 = stof(arg3); if (farg3 > 0 && farg3 <= number_of_teams) - CF_Spy_ChangeColor(self, farg3); + CF_Spy_ChangeColor(self, farg3, TRUE); else Menu_Spy_Input(1); break; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index d999ecfa..7df35e38 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -2,8 +2,8 @@ // This file handles all menu functions and displays. //====================================================== -void (entity pe_player, float pf_class) CF_Spy_ChangeSkin; -void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor; +void (entity pe_player, float pf_class, float is_user) CF_Spy_ChangeSkin; +void (entity pe_player, float pf_team_no, float is_user) CF_Spy_ChangeColor; void (float issilent, float force) FO_Spy_Feign; void () FO_Spy_FeignOnNextDamage; void () FO_Spy_Unfeign; @@ -73,8 +73,8 @@ void (float inp) Menu_Scout_Input; void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; void (float inp) Menu_Spy_Color_Input; -void (entity player) FO_Spy_DisguiseLast; -void (entity player) FO_Spy_DisguiseLastSpawned; +void (entity player, float is_user) FO_Spy_DisguiseLast; +void (entity player, float is_user) FO_Spy_DisguiseLastSpawned; void () Menu_Demoman; void () Menu_Demoman_Cancel; @@ -582,7 +582,7 @@ void (float inp) Menu_Spy_Input = { else Menu_Spy_Skin(); } else if (inp == 2 && !invis_only) { - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, TRUE); } else if (inp == 3) { FO_Spy_Feign(1, 0); if (self.is_feigning) { @@ -663,13 +663,13 @@ void (float inp) Menu_Spy_Skin_Input = { else if (number_of_teams > 2) Menu_Spy_Color(); else if (self.team_no == 1) - CF_Spy_ChangeColor(self, 2); + CF_Spy_ChangeColor(self, 2, TRUE); else - CF_Spy_ChangeColor(self, 1); + CF_Spy_ChangeColor(self, 1, TRUE); } if (self.skin != inp) - CF_Spy_ChangeSkin(self, inp); + CF_Spy_ChangeSkin(self, inp, TRUE); }; void () Menu_Spy_Skin = { @@ -711,7 +711,7 @@ void (float inp) Menu_Spy_Color_Input = { else if (inp == 4 && color == 11) Menu_Spy_Color(); else if (inp > 0 && inp <= number_of_teams) - CF_Spy_ChangeColor(self, inp); + CF_Spy_ChangeColor(self, inp, TRUE); }; void () Menu_Spy_Color = { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 6aab6be0..f4d0197a 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -672,7 +672,7 @@ void () CF_Spy_Invisible = { e_timer.classname = "spytimer"; e_timer.owner = self; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 1; + e_timer.nextthink = client_time() + 1; } Status_Refresh(self); @@ -727,9 +727,9 @@ void () CF_Spy_DisguiseStop = { Status_Refresh(self); }; -void (entity player) FO_Spy_DisguiseLast = { +void (entity player, float is_user) FO_Spy_DisguiseLast = { if (!player.last_selected_skin) { - FO_Spy_DisguiseLastSpawned(player); + FO_Spy_DisguiseLastSpawned(player, is_user); return; } @@ -748,11 +748,11 @@ void (entity player) FO_Spy_DisguiseLast = { } } - CF_Spy_ChangeColor(player, undercover_team); - CF_Spy_ChangeSkin(player, player.last_selected_skin); + CF_Spy_ChangeColor(player, undercover_team, is_user); + CF_Spy_ChangeSkin(player, player.last_selected_skin, is_user); }; -void (entity player) FO_Spy_DisguiseLastSpawned = { +void (entity player, float is_user) FO_Spy_DisguiseLastSpawned = { local entity te = find(world, classname, "player"); local float latest_spawn_time = 0; local entity enemy_to_disguise_as = world; @@ -778,10 +778,10 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { } if (enemy_to_disguise_as.team_no) { - CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); + CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no, is_user); if (enemy_to_disguise_as.skin) { - CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); + CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin, is_user); } } else { local float undercover_team; @@ -791,7 +791,7 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { undercover_team = 1; } - CF_Spy_ChangeColor(player, undercover_team); + CF_Spy_ChangeColor(player, undercover_team, is_user); } }; @@ -900,7 +900,7 @@ void () CF_Spy_UndercoverThink = { TeamFortress_SetSkin(self.owner); if (self.owner.queue_team) { - CF_Spy_ChangeColor(self.owner, self.owner.queue_team); + CF_Spy_ChangeColor(self.owner, self.owner.queue_team, FALSE); } else { if (self.owner.undercover_team) s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); @@ -921,7 +921,7 @@ void () CF_Spy_UndercoverThink = { TeamFortress_SetSkin(self.owner); if (self.owner.queue_skin) { - CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin); + CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin, FALSE); } else { s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); if (self.owner.undercover_skin) @@ -943,7 +943,7 @@ void () CF_Spy_UndercoverThink = { dremove(self); }; -void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { +void (entity pe_player, float pf_class, float is_user) CF_Spy_ChangeSkin = { pe_player.last_selected_skin = pf_class; // stop if you're already disguised as the requested skin @@ -993,13 +993,13 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 1; + e_timer.nextthink = (is_user ? client_time() : time) + 1; e_timer.skin = pf_class; Status_Refresh(pe_player); }; -void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { +void (entity pe_player, float pf_team_no, float is_user) CF_Spy_ChangeColor = { local entity e_timer; local float f_team_color = TeamFortress_TeamGetColor(pf_team_no) - 1; @@ -1047,7 +1047,7 @@ void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 1; + e_timer.nextthink = (is_user ? client_time() : time) + 1; e_timer.team = pf_team_no; Status_Refresh(pe_player); @@ -1522,10 +1522,10 @@ void (entity spy) Spy_RemoveDisguise = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b4e418fa..f7ed591d 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -353,10 +353,10 @@ void (float inp) TeamFortress_ChangeClass = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 01090a83..47c37a3f 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1140,10 +1140,10 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(Player); + FO_Spy_DisguiseLastSpawned(Player, FALSE); break; case 2: - FO_Spy_DisguiseLast(Player); + FO_Spy_DisguiseLast(Player, FALSE); break; } } @@ -3056,10 +3056,10 @@ void () DropGoalItems = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 92bde134..56e932a5 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3146,43 +3146,43 @@ void () ImpulseCommands = { } else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) FO_Spy_FeignCmd(1); else if (self.impulse == TF_DISGUISE_RESET && self.playerclass == PC_SPY) { - CF_Spy_ChangeSkin(self, 8); - CF_Spy_ChangeColor(self, self.team_no); + CF_Spy_ChangeSkin(self, 8, TRUE); + CF_Spy_ChangeColor(self, self.team_no, TRUE); } else if (self.impulse == TF_DISGUISE_SCOUT && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 1); + CF_Spy_ChangeSkin(self, 1, TRUE); else if (self.impulse == TF_DISGUISE_SNIPER && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 2); + CF_Spy_ChangeSkin(self, 2, TRUE); else if (self.impulse == TF_DISGUISE_SOLDIER && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 3); + CF_Spy_ChangeSkin(self, 3, TRUE); else if (self.impulse == TF_DISGUISE_DEMOMAN && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 4); + CF_Spy_ChangeSkin(self, 4, TRUE); else if (self.impulse == TF_DISGUISE_MEDIC && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 5); + CF_Spy_ChangeSkin(self, 5, TRUE); else if (self.impulse == TF_DISGUISE_HWGUY && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 6); + CF_Spy_ChangeSkin(self, 6, TRUE); else if (self.impulse == TF_DISGUISE_PYRO && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 7); + CF_Spy_ChangeSkin(self, 7, TRUE); else if (self.impulse == TF_DISGUISE_ENGINEER && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 9); + CF_Spy_ChangeSkin(self, 9, TRUE); else if (self.impulse == TF_DISGUISE_BLUE && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 1); + CF_Spy_ChangeColor(self, 1, TRUE); else if (self.impulse == TF_DISGUISE_RED && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 2); + CF_Spy_ChangeColor(self, 2, TRUE); else if (self.impulse == TF_DISGUISE_YELLOW && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 3); + CF_Spy_ChangeColor(self, 3, TRUE); else if (self.impulse == TF_DISGUISE_GREEN && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 4); + CF_Spy_ChangeColor(self, 4, TRUE); else if (self.impulse == TF_DISGUISE_ENEMY && self.playerclass == PC_SPY) { if (number_of_teams > 2) Menu_Spy_Color(); else if (self.team_no == 1) - CF_Spy_ChangeColor(self, 2); + CF_Spy_ChangeColor(self, 2, TRUE); else - CF_Spy_ChangeColor(self, 1); + CF_Spy_ChangeColor(self, 1, TRUE); } else if (self.impulse == TF_DISGUISE_LAST && self.playerclass == PC_SPY) - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, TRUE); else if (self.impulse == TF_DISGUISE_LAST_SPAWNED && self.playerclass == PC_SPY) - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, TRUE); else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); @@ -3477,7 +3477,7 @@ void () ButtonFrame = { TeamFortress_ToggleDetpack(5); break; case PC_SPY: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, TRUE); break; case PC_ENGINEER: FO_Engineer_ToggleSentry(); From 2596766fd7296d072f1100ca1a07b16e5fbe0d4f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Sep 2022 19:42:29 +1000 Subject: [PATCH 1653/2474] Don't auto-password unless the match actually starts --- ssqc/clan.qc | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 88412ce9..f2fdc2f4 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1082,20 +1082,6 @@ float () CheckAllPlayersReady = { if (intermission_running) return 0; - if (infokey(world, "needpass") != "1") { - local string default_password = "pineapple"; - cvar_set("password", default_password); - localcmd("localinfo default_password on\n"); - - local entity te = find(world, classname, "player"); - while (te != world) { - if (te.team_no) { - sprint(te, PRINT_HIGH, "Setting password to \"", default_password, "\"\n"); - } - te = find(te, classname, "player"); - } - } - local float f1 = TeamFortress_GetNoActivePlayers(); bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); if (v_ready == f1 && v_ready > 0) { @@ -1103,8 +1089,24 @@ float () CheckAllPlayersReady = { bprint (2, "All players ready, match will start after ceasefire ends.\n"); } else { bprint (2, "All players ready, starting match\n"); + StartTimer (); + // set default password if no password set + if (infokey(world, "needpass") != "1") { + local string default_password = "pineapple"; // maybe this should be configurable + cvar_set("password", default_password); + localcmd("localinfo default_password on\n"); + + local entity te = find(world, classname, "player"); + while (te != world) { + if (te.team_no) { + sprint(te, PRINT_HIGH, "Setting password to \"", default_password, "\"\n"); + } + te = find(te, classname, "player"); + } + } + local float limit_quad_players = CF_GetSetting("lqp", "limit_quad_players", "on"); if (limit_quad_players) { quad_maxplayers = f1; From 2d119310c166b970ed63bb45dbf8865321fe2325 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:53:26 -0700 Subject: [PATCH 1654/2474] Add new files Helps if you git add new files. --- share/fo_weapons.qc | 337 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 share/fo_weapons.qc diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc new file mode 100644 index 00000000..5a9d80d7 --- /dev/null +++ b/share/fo_weapons.qc @@ -0,0 +1,337 @@ +enum AmmoType { + AMMO_NONE, + AMMO_SHELLS, + AMMO_NAILS, + AMMO_CELLS, + AMMO_ROCKETS, + AMMO_GRENADES, // Rockets really +}; + +// REQUIRES: Order must match above. +static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; + +static float* AMMO_to_p(entity player, AmmoType ammo_type) { + switch (ammo_type) { + case AMMO_NONE: return __NULL__; + case AMMO_SHELLS: return &player.ammo_shells; + case AMMO_CELLS: return &player.ammo_cells; + case AMMO_NAILS: return &player.ammo_nails; + case AMMO_ROCKETS: return &player.ammo_rockets; + case AMMO_GRENADES: return &player.ammo_rockets; + } + error(sprintf("UNK AMMO_TYPE=%d\n", ammo_type)); + return __NULL__; +} + +struct FO_WeapInfo { + float weapon; + + /* These are always constant and relative to weapon. */ + string name; + string model[2]; // indexed by weaponmode + AmmoType ammo_type; + float ammo_per_shot; + float needs_reload; + float full_reload_time; + float clip_size; + float attack_time; + + /* These are relative to the player passed. */ + float* ammo_remaining; + float* clip_fired; +}; + +void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { + wi->weapon = weapon; + wi->ammo_per_shot = 1; + wi->needs_reload = TRUE; + switch (weapon) { + /* NONE */ + case WEAP_HOOK: + wi->name = "Hook"; + wi->model[0] = "progs/v_grap.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_KNIFE: + wi->name = "Knife"; + wi->model[0] = "progs/v_knife.mdl"; + wi->model[1] = "progs/v_knife2.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_MEDIKIT: + wi->name = "BioAxe"; + wi->model[0] = "progs/v_medi.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_SPANNER: + wi->name = "Spanner"; + wi->model[0] = "progs/v_spanner.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_AXE: + wi->name = "Axe"; + wi->model[0] = "progs/v_axe.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + break; + /* SHELLS */ + case WEAP_SHOTGUN: + wi->name = "Shotgun"; + wi->model[0] = "progs/v_shot.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->clip_size = 8; + wi->attack_time = 0.5; + wi->full_reload_time = 2; + wi->clip_fired = &player.reload_shotgun; + break; + case WEAP_SUPER_SHOTGUN: + wi->name = "Super Shotgun"; + wi->model[0] = "progs/v_shot2.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->clip_size = 16; + wi->ammo_per_shot = 2; + wi->attack_time = 0.7; + wi->full_reload_time = 3; + wi->clip_fired = &player.reload_super_shotgun; + break; + case WEAP_SNIPER_RIFLE: + wi->name = "Sniper Rifle"; + wi->model[0] = "progs/v_srifle.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->attack_time = 1.5; + if (sniperreload) { + wi->clip_size = 1; + wi->full_reload_time = 4; + wi->clip_fired = &self.reload_sniper_rifle; + } else { + wi->needs_reload = FALSE; + } + break; + case WEAP_AUTO_RIFLE: + wi->name = "Sniper Rifle"; + wi->model[0] = "progs/v_srifle.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->needs_reload = FALSE; + wi->attack_time = 0.1; + break; + case WEAP_TRANQ: + wi->name = "Tranq Gun"; + wi->model[0] = "progs/v_tranq.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->needs_reload = FALSE; + wi->attack_time = 1.5; + break; + case WEAP_ASSAULT_CANNON: + wi->name = "Assault Cannon"; + wi->model[0] = "progs/v_asscan.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->clip_size = 100; + wi->full_reload_time = 4; + wi->clip_fired = &player.reload_assault_cannon; + break; + /* NAILS */ + case WEAP_NAILGUN: + wi->name = "Nailgun"; + wi->model[0] = "progs/v_nail.mdl"; + wi->ammo_type = AMMO_NAILS; + wi->ammo_per_shot = 2; + wi->attack_time = 0.2; + wi->needs_reload = FALSE; + break; + case WEAP_SUPER_NAILGUN: + wi->name = "Super Nailgun"; + wi->model[0] = "progs/v_nail2.mdl"; + wi->ammo_type = AMMO_NAILS; + wi->ammo_per_shot = 4; + wi->attack_time = 0.2; + wi->needs_reload = FALSE; + break; + case WEAP_RAILGUN: + wi->name = "Railgun"; + wi->model[0] = "progs/v_rail.mdl"; + wi->ammo_type = AMMO_NAILS; + wi->ammo_type = AMMO_NAILS; + wi->needs_reload = FALSE; + wi->attack_time = 0.4; + break; + /* ROCKETS */ + case WEAP_GRENADE_LAUNCHER: + wi->name = "Grenade Launcher"; + wi->model[0] = "progs/v_rock.mdl"; + wi->model[1] = "progs/v_pipe.mdl"; + wi->ammo_type = AMMO_ROCKETS; + wi->clip_size = 6; + wi->attack_time = 0.6; + wi->full_reload_time = 4; + wi->clip_fired = &player->reload_grenade_launcher; + case WEAP_ROCKET_LAUNCHER: + wi->name = "Rocket Launcher"; + wi->model[0] = "progs/v_rock2.mdl"; + wi->ammo_type = AMMO_ROCKETS; + wi->clip_size = 4; + wi->clip_fired = &player->reload_rocket_launcher; + wi->full_reload_time = 5; + wi->attack_time = 0.8; + break; + case WEAP_INCENDIARY: + wi->name = "Incendiary Launcher"; + wi->model[0] = "progs/v_irock.mdl"; + wi->ammo_type = AMMO_ROCKETS; + wi->ammo_per_shot = 3; + wi->attack_time = 0.9; + switch (pyro_type) { + case PYRO_ORIGINAL: wi->attack_time = 1.2; break; + case PYRO_OZTF: wi->attack_time = 0.9; break; + case PYRO_FO: wi->attack_time = 0.9; break; + } + wi->needs_reload = FALSE; + break; + /* CELLS */ + case WEAP_LIGHTNING: + error("Should never be invoked\n"); + case WEAP_FLAMETHROWER: + wi->name = "Flamethrower"; + wi->model[0] = "progs/v_flame.mdl"; + wi->ammo_type = AMMO_CELLS; + wi->needs_reload = FALSE; + wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; + break; + case WEAP_DETPACK: + error("Should never be invoked\n"); + } + + wi->ammo_remaining = AMMO_to_p(player, wi->ammo_type); + if (!wi->needs_reload) { + wi->clip_fired = __NULL__; + } +} + +#ifdef SSQC +void TeamFortress_OldReloadWeapon(float weap); +void () RestoreDefaultWeapon; +void (entity pl) Status_Refresh; +void (entity pl, float swap) W_WeaponState_Load; +void (float att_delay) Attack_Finished; + +static void FOT_ReloadTimer() { + FO_WeapInfo wi; + FO_FillWeapInfo(self.owner, self.current_weapon, &wi); + + if (time == self.heat) { + // Reload finished + self.owner.tfstate &= ~TFSTATE_RELOADING; + self.owner.weaponmodel = wi->model[self.owner.weaponmode]; + sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); + dremove(self); + W_WeaponState_Load(self.owner, 0); + } else { + // Refresh clip + if (wi.weapon != WEAP_SNIPER_RIFLE) + self.owner.reload_clipsize += 1; + else + self.owner.reload_sniper_ticks += 1; + + self.nextthink = min(time + self.owner.reload_tick, self.heat); + } + Status_Refresh(self.owner); +} + +float FO_UseNewReload() { + return CF_GetSetting("dunr", "debug_use_new_reload", "on"); +} + +float FO_CheckForAmmo(float weapon) { + FO_WeapInfo wi; + FO_FillWeapInfo(self, weapon, &wi); + + if (wi->needs_reload && *wi->clip_fired > 0 + && *wi->ammo_remaining > wi->ammo_per_shot) + return 1; + + return 0; +} + +void () TeamFortress_ForceReloadCurrentWeapon; +float FO_CheckForReload() { + FO_WeapInfo wi; + FO_FillWeapInfo(self, self.current_weapon, &wi); + + if (*wi->clip_fired >= wi->clip_size && *wi->ammo_remaining > 0) { + if (force_reload) + TeamFortress_ForceReloadCurrentWeapon(); + return 1; + } else { + return 0; + } +} + +void FO_ReloadWeapon(float weapon, float force) { + RestoreDefaultWeapon(); + if (self.tfstate & TFSTATE_RELOADING) + return; + + FO_WeapInfo wi; + FO_FillWeapInfo(self, weapon, &wi); + + if (!wi->needs_reload) + return; + + string msg = string_null; + if (*wi->clip_fired == 0) + msg = "Clip full\n"; + else if (*wi->ammo_remaining == 0) + msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); + else if (wi->clip_size - *wi->clip_fired == *wi->ammo_remaining) + msg = strcat("All ", AMMO_to_s[wi->ammo_type], "are in the clip\n"); + + if (msg != string_null) { + sprint(self, PRINT_HIGH, msg); + return; + } else { + sprint(self, PRINT_HIGH, strcat("Reloading ", wi->name, "...\n")); + } + + Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. + + self.weaponmodel = ""; + self.weaponframe = 0; + self.tfstate |= TFSTATE_RELOADING; + Status_Refresh(self); + + float reload_count = min(*wi->clip_fired, *wi->ammo_remaining); + float reload_duration = + (reload_count / wi->clip_size) * wi->full_reload_time; + + *wi->clip_fired -= reload_count; + + // Sets up for status bar. + self.reload_time = time + reload_duration; + self.reload_tick = reload_duration / reload_count; + self.reload_clipsize = wi->clip_size - reload_count; + + // Actual entity that will update status bar / clear reload. + entity reload_timer = spawn(); + reload_timer.owner = self; + reload_timer.current_weapon = weapon; + reload_timer.classname = "timer"; + reload_timer.think = FOT_ReloadTimer; + + // TODO: Remove this hack. + if (weapon == WEAP_SNIPER_RIFLE) { + self.reload_tick = 1; + self.reload_sniper_ticks = 0; + } + + // It turns out, even on forced reloads we should use the client_time() not + // the server time as the action that forced the reload (firing the last + // shot), was client relative. + reload_timer.heat = client_time() + reload_duration; + reload_timer.nextthink = client_time() + self.reload_tick; + +} +#endif From fd9c6cc505eddc9d8fec3915e6d828fb4573934b Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 03:09:56 -0700 Subject: [PATCH 1655/2474] Ensure overflows terminate --- share/fo_weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 5a9d80d7..21709026 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -222,7 +222,7 @@ static void FOT_ReloadTimer() { FO_WeapInfo wi; FO_FillWeapInfo(self.owner, self.current_weapon, &wi); - if (time == self.heat) { + if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; self.owner.weaponmodel = wi->model[self.owner.weaponmode]; From ce04953fefe97902f5853de7576e167083641fc6 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 04:07:32 -0700 Subject: [PATCH 1656/2474] Shot in the dark on a crash, remove primed_at from message temporarily. --- csqc/events.qc | 5 +++-- ssqc/status.qc | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index a6f5a9a3..e4713715 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -101,9 +101,8 @@ void() CSQC_Parse_Event = { break; case MSG_GRENPRIMED: float grentype = readbyte(); - float primed_at = readfloat(); float explodes_at = readfloat(); - ParseGrenPrimed(grentype, primed_at, explodes_at); + ParseGrenPrimed(grentype, 0, explodes_at); break; case MSG_GRENTHROWN: CsGrenTimer last = CsGrenTimer::GetLast(); @@ -387,8 +386,10 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) return; +#if 0 if (primed_at < last_death_time) return; +#endif local float timer_flags = 0; switch (cvar(FOCMD_GRENTIMER)) { diff --git a/ssqc/status.qc b/ssqc/status.qc index f23d22cc..5945e463 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -803,7 +803,6 @@ void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); WriteByte(MSG_MULTICAST, grentype); - WriteFloat(MSG_MULTICAST, time); WriteFloat(MSG_MULTICAST, explodes_at); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } From 7164f1d0381aea13ec73d1c8f05b1c1faeec4706 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 13:07:22 -0700 Subject: [PATCH 1657/2474] Add missing breaks (fix no reload on grenade launcher) When filling in the switch table for all the weapons a few breaks were missed at the end. This was resulting in (for example) grenade launcher not needing reload. --- share/fo_weapons.qc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 21709026..ce2656ea 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -53,6 +53,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_KNIFE: wi->name = "Knife"; wi->model[0] = "progs/v_knife.mdl"; @@ -60,18 +61,21 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_MEDIKIT: wi->name = "BioAxe"; wi->model[0] = "progs/v_medi.mdl"; wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_SPANNER: wi->name = "Spanner"; wi->model[0] = "progs/v_spanner.mdl"; wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_AXE: wi->name = "Axe"; wi->model[0] = "progs/v_axe.mdl"; @@ -169,6 +173,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->attack_time = 0.6; wi->full_reload_time = 4; wi->clip_fired = &player->reload_grenade_launcher; + break; case WEAP_ROCKET_LAUNCHER: wi->name = "Rocket Launcher"; wi->model[0] = "progs/v_rock2.mdl"; @@ -192,7 +197,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->needs_reload = FALSE; break; /* CELLS */ - case WEAP_LIGHTNING: error("Should never be invoked\n"); case WEAP_FLAMETHROWER: wi->name = "Flamethrower"; @@ -201,7 +205,10 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->needs_reload = FALSE; wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; break; + /* NOT USED */ + case WEAP_LIGHTNING: case WEAP_DETPACK: + default: error("Should never be invoked\n"); } From 25535c5d0bb1d1d85c39e8129d7c03cdd4b8d267 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 03:07:31 -0700 Subject: [PATCH 1658/2474] Update antilag detpipe to use client_time Removed `project_max_latency`, it's now implicit from client_time (and tunables). --- ssqc/antilag.qc | 22 ++++++++-------------- ssqc/client.qc | 3 +++ ssqc/qw.qc | 4 +++- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 07157db6..7d7bbad2 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -325,26 +325,20 @@ class FOPlayer { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { - // Live changeagble for now. - float project_detpipe = CF_GetSetting("pd", "project_detpipe", "on"); - // Want to lower this in time, but good for testing. - float project_detpipe_max_lat = - CF_GetSetting("pdml", "project_max_latency", "500") / 1000; - - if (!project_detpipe) + if (antilag_settings.rewind_detpipe) return FALSE; - project_detpipe_max_lat = min(project_detpipe_max_lat, - ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT) * 2); + float rewind_max_offset = ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT); + farthest_rewind_point = max(farthest_rewind_point, + time - rewind_max_offset); - local float rtt = infokeyf(self, INFOKEY_P_PING) / 1000; - rtt = min(rtt, project_detpipe_max_lat); + // Det was pushed at client_time(), let's see if we can get there. + float rewind_to = max(farthest_rewind_point, client_time()); - if (rtt < 0.013) + // Ignore for LAN pings. + if (time - rewind_to < 0.013) return FALSE; - float rewind_to = max(farthest_rewind_point, time - rtt / 2); - FOPlayer fop = (FOPlayer)self; fop.RewindExcept(rewind_to); return TRUE; diff --git a/ssqc/client.qc b/ssqc/client.qc index e435b706..2b43cc50 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -619,6 +619,9 @@ void () DecodeLevelParms = { airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); + // client_time max delta + antilag_settings.rewind_detpipe = + CF_GetSetting("alrd", "al_rewind_detpipe", "on"); // client_time max delta antilag_settings.max_client_time_offset = CF_GetSetting("almcto", "al_max_client_time_offset", "200"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index e8a919a9..b81e88da 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -11,6 +11,7 @@ enum { struct antilag_settings_t { float max_client_time_offset; float max_projectile_slow_offset; + float rewind_detpipe; } antilag_settings; // A monotonically increasing, latency corrected notion of client-time. @@ -804,9 +805,10 @@ string goal_class_names[7] = { // people complain about settings, let's track them -string settings_to_track_list[3] = { +string settings_to_track_list[4] = { "sv_antilag", "project_weapons", + "al_rewind_detpipe", "al_max_client_time_offset", }; From 0618ce09bc2b6d6cf088edd1de68e731463f9cae Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:05:19 -0700 Subject: [PATCH 1659/2474] Rename Laser to Railgun For legacy reasons the railgun is a laser in the code. Fix this. --- share/defs.h | 3 +-- share/fo_weapons.qc | 1 - ssqc/tfort.qc | 2 +- ssqc/weapons.qc | 20 ++++++++++---------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/share/defs.h b/share/defs.h index a335c43c..3d0a8e5b 100644 --- a/share/defs.h +++ b/share/defs.h @@ -723,7 +723,6 @@ #define WEAP_LIGHTNING 65536 #define WEAP_DETPACK 131072 #define WEAP_TRANQ 262144 -#define WEAP_LASER 524288 #define WEAP_RAILGUN 524288 // still room for 12 more weapons // but we can remove some by giving the weapons @@ -1144,7 +1143,7 @@ #define PC_ENGINEER_INITARMORTYPE 0.3 #define PC_ENGINEER_ARMORCLASSES 31 // ALL #define PC_ENGINEER_INITARMORCLASS 0 -#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN +#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_RAILGUN | WEAP_SUPER_SHOTGUN #define PC_ENGINEER_MAXAMMO_SHOT 50 #define PC_ENGINEER_MAXAMMO_NAIL 50 #define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index ce2656ea..2f7e43af 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -197,7 +197,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->needs_reload = FALSE; break; /* CELLS */ - error("Should never be invoked\n"); case WEAP_FLAMETHROWER: wi->name = "Flamethrower"; wi->model[0] = "progs/v_flame.mdl"; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f7ed591d..57fcbf05 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2273,7 +2273,7 @@ void () TeamFortress_SetEquipment = { else self.maxarmor = PC_ENGINEER_MAXARMOR; if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_LASER; + self.current_weapon = WEAP_RAILGUN; self.items_allowed = PC_ENGINEER_WEAPONS; self.items = self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 56e932a5..9a2e2ca8 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1737,7 +1737,7 @@ void (entity pl) W_SetCurrentAmmo = { } pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_LASER) { + } else if (pl.current_weapon == WEAP_RAILGUN) { pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_rail.mdl"; @@ -1785,8 +1785,8 @@ float () W_BestWeapon = { return WEAP_FLAMETHROWER; else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) return WEAP_SUPER_NAILGUN; - else if (self.ammo_nails >= 1 && it & WEAP_LASER) - return WEAP_LASER; + else if (self.ammo_nails >= 1 && it & WEAP_RAILGUN) + return WEAP_RAILGUN; else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) return WEAP_TRANQ; else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) @@ -2187,7 +2187,7 @@ void () W_Attack = { player_shot1(); W_FireTranq(); Attack_Finished(1.5); - } else if (self.current_weapon == WEAP_LASER) { + } else if (self.current_weapon == WEAP_RAILGUN) { FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireLaser(); @@ -2238,7 +2238,7 @@ float (float weap) W_GetSlot = { || (!cf_pyro_impulses && weap == WEAP_INCENDIARY) || (cf_pyro_impulses && weap == WEAP_FLAMETHROWER) || weap == WEAP_TRANQ - || weap == WEAP_LASER + || weap == WEAP_RAILGUN || weap == WEAP_ASSAULT_CANNON) { return 1; } else if (weap == WEAP_SUPER_SHOTGUN @@ -2274,7 +2274,7 @@ float (float weap) W_OldGetSlot = { else if (weap == WEAP_SHOTGUN || weap == WEAP_SNIPER_RIFLE || weap == WEAP_TRANQ - || weap == WEAP_LASER) + || weap == WEAP_RAILGUN) return 2; else if (weap == WEAP_SUPER_SHOTGUN || weap == WEAP_AUTO_RIFLE) @@ -2465,7 +2465,7 @@ float () W_OldWeaponSlot2 = { else if (self.playerclass == PC_SPY) return WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) - return WEAP_LASER; + return WEAP_RAILGUN; return 0; }; @@ -2542,7 +2542,7 @@ float () W_WeaponSlot1 = { else if (self.playerclass == PC_SPY) return WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) - return WEAP_LASER; + return WEAP_RAILGUN; return 0; }; @@ -2672,7 +2672,7 @@ float (float newSlot) W_OldImpulseFromNewSlot = { return W_OldGetSlot(WEAP_TRANQ); } else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_LASER); + return W_OldGetSlot(WEAP_RAILGUN); } } else if (newSlot == 2) { @@ -2730,7 +2730,7 @@ float (float newSlot) W_OldImpulseFromNewSlot = { return W_OldGetSlot(WEAP_NAILGUN); } else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_LASER); + return W_OldGetSlot(WEAP_RAILGUN); } } else if (newSlot == 4) { From 651d93caa4ff6c76fe698eb4e512a9c50f06810f Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:04:37 -0700 Subject: [PATCH 1660/2474] Remove old reload code, migrate fully to new implementation. Large simplification to attack code since reload and clip interaction is generic rather than per-weap. Fixed a frustrating edge case: If you fire as spy when you need to reload, you'd previously drop your disguise before reload is forced, even though you never actually fired to reveal it. Leaving you undisguised and helpless. --- share/fo_weapons.qc | 40 ++---- ssqc/actions.qc | 320 ++------------------------------------------ ssqc/hwguy.qc | 2 +- ssqc/progs.src | 2 +- ssqc/status.qc | 90 ++----------- ssqc/weapons.qc | 231 +++----------------------------- 6 files changed, 63 insertions(+), 622 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 2f7e43af..9b2c753e 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -44,14 +44,13 @@ struct FO_WeapInfo { void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->weapon = weapon; wi->ammo_per_shot = 1; - wi->needs_reload = TRUE; + wi->clip_size = 0; switch (weapon) { /* NONE */ case WEAP_HOOK: wi->name = "Hook"; wi->model[0] = "progs/v_grap.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_KNIFE: @@ -59,28 +58,24 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->model[0] = "progs/v_knife.mdl"; wi->model[1] = "progs/v_knife2.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_MEDIKIT: wi->name = "BioAxe"; wi->model[0] = "progs/v_medi.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_SPANNER: wi->name = "Spanner"; wi->model[0] = "progs/v_spanner.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_AXE: wi->name = "Axe"; wi->model[0] = "progs/v_axe.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; /* SHELLS */ @@ -112,22 +107,18 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->clip_size = 1; wi->full_reload_time = 4; wi->clip_fired = &self.reload_sniper_rifle; - } else { - wi->needs_reload = FALSE; } break; case WEAP_AUTO_RIFLE: wi->name = "Sniper Rifle"; wi->model[0] = "progs/v_srifle.mdl"; wi->ammo_type = AMMO_SHELLS; - wi->needs_reload = FALSE; wi->attack_time = 0.1; break; case WEAP_TRANQ: wi->name = "Tranq Gun"; wi->model[0] = "progs/v_tranq.mdl"; wi->ammo_type = AMMO_SHELLS; - wi->needs_reload = FALSE; wi->attack_time = 1.5; break; case WEAP_ASSAULT_CANNON: @@ -137,6 +128,8 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->clip_size = 100; wi->full_reload_time = 4; wi->clip_fired = &player.reload_assault_cannon; + if (fo_hwguy) + wi->clip_size = PC_HVYWEAP_ASSCAN_CLIPSIZE; break; /* NAILS */ case WEAP_NAILGUN: @@ -145,7 +138,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NAILS; wi->ammo_per_shot = 2; wi->attack_time = 0.2; - wi->needs_reload = FALSE; break; case WEAP_SUPER_NAILGUN: wi->name = "Super Nailgun"; @@ -153,14 +145,12 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NAILS; wi->ammo_per_shot = 4; wi->attack_time = 0.2; - wi->needs_reload = FALSE; break; case WEAP_RAILGUN: wi->name = "Railgun"; wi->model[0] = "progs/v_rail.mdl"; wi->ammo_type = AMMO_NAILS; wi->ammo_type = AMMO_NAILS; - wi->needs_reload = FALSE; wi->attack_time = 0.4; break; /* ROCKETS */ @@ -194,14 +184,12 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { case PYRO_OZTF: wi->attack_time = 0.9; break; case PYRO_FO: wi->attack_time = 0.9; break; } - wi->needs_reload = FALSE; break; /* CELLS */ case WEAP_FLAMETHROWER: wi->name = "Flamethrower"; wi->model[0] = "progs/v_flame.mdl"; wi->ammo_type = AMMO_CELLS; - wi->needs_reload = FALSE; wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; break; /* NOT USED */ @@ -211,6 +199,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { error("Should never be invoked\n"); } + wi->needs_reload = wi->clip_size > 0; wi->ammo_remaining = AMMO_to_p(player, wi->ammo_type); if (!wi->needs_reload) { wi->clip_fired = __NULL__; @@ -218,7 +207,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { } #ifdef SSQC -void TeamFortress_OldReloadWeapon(float weap); void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; void (entity pl, float swap) W_WeaponState_Load; @@ -247,19 +235,18 @@ static void FOT_ReloadTimer() { Status_Refresh(self.owner); } -float FO_UseNewReload() { - return CF_GetSetting("dunr", "debug_use_new_reload", "on"); -} - -float FO_CheckForAmmo(float weapon) { +float FO_CanReload(float weapon) { FO_WeapInfo wi; FO_FillWeapInfo(self, weapon, &wi); + if (wi->ammo_type == AMMO_NONE) + return FALSE; + if (wi->needs_reload && *wi->clip_fired > 0 && *wi->ammo_remaining > wi->ammo_per_shot) - return 1; + return TRUE; - return 0; + return FALSE; } void () TeamFortress_ForceReloadCurrentWeapon; @@ -267,12 +254,13 @@ float FO_CheckForReload() { FO_WeapInfo wi; FO_FillWeapInfo(self, self.current_weapon, &wi); - if (*wi->clip_fired >= wi->clip_size && *wi->ammo_remaining > 0) { + if (wi->needs_reload && *wi->clip_fired >= wi->clip_size && + *wi->ammo_remaining > 0) { if (force_reload) TeamFortress_ForceReloadCurrentWeapon(); - return 1; + return TRUE; } else { - return 0; + return FALSE; } } diff --git a/ssqc/actions.qc b/ssqc/actions.qc index d77f6780..21e773ba 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -2,8 +2,6 @@ // Non Class-Specific Impulse Commands //======================================================== -void () TeamFortress_ClipTick; - void () TeamFortress_Discard = { local string s = infokey(self,"keepcells"); local float c = stof(s); @@ -485,296 +483,12 @@ void () RestoreDefaultWeapon = { } }; -void TeamFortress_OldReloadWeapon(float weap); -void FO_ReloadWeapon(float weap, float force); - -void TeamFortress_ReloadWeapon(float weap, float force) { - if (FO_UseNewReload()) - FO_ReloadWeapon(weap, force); - else - TeamFortress_OldReloadWeapon(weap); -} - -void TeamFortress_OldReloadWeapon(float weap) -{ - RestoreDefaultWeapon(); - - local float reloadtime = 0; - local float reloadamount = 0; - local entity tWeapon, tClip; - - if (self.tfstate & TFSTATE_RELOADING) { - return; - } - - if (weap == WEAP_SHOTGUN) { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - if (self.reload_shotgun == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((8 - self.reload_shotgun) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - if (self.ammo_shells >= 1) { - self.current_weapon = weap; - if (self.reload_shotgun >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_shotgun; - Attack_Finished(0.4); - self.reload_clipsize = (8 - reloadamount); - reloadtime = (8 - reloadamount) / 8; - reloadtime = 2 - 2 * reloadtime; - self.reload_shotgun = 0; - if (self.ammo_shells < 8) { - self.reload_shotgun = 8 - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Shotgun...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_shotgun; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_SUPER_SHOTGUN) { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - if (self.reload_super_shotgun == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((16 - self.reload_super_shotgun) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - if (self.ammo_shells >= 2) { - self.current_weapon = weap; - if (self.reload_super_shotgun >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_super_shotgun; - Attack_Finished(0.7); - self.reload_clipsize = (16 - reloadamount); - reloadtime = (16 - reloadamount) / 16; - reloadtime = 3 - (3 * reloadtime); - self.reload_super_shotgun = 0; - if (self.ammo_shells < 16) { - self.reload_super_shotgun = 16 - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Super Shotgun...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_super_shotgun; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_SNIPER_RIFLE) { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - if (self.reload_sniper_rifle == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((16 - self.reload_sniper_rifle) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - if (self.ammo_shells >= 1) { - self.current_weapon = weap; - if (self.reload_super_shotgun >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_sniper_rifle; - Attack_Finished(1.5); - self.reload_clipsize = (1 - reloadamount); - self.reload_sniper_rifle = 0; - self.reload_sniper_ticks = 0; - if (self.ammo_shells < 1) { - self.reload_sniper_rifle = 1 - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Sniper Rifle...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + 1; // this will tick four times before finishing reload - tWeapon.think = W_Reload_sniper_rifle_tick; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.ammo_rockets == 0) { - sprint(self, PRINT_HIGH, "Out of grenades\n"); - return; - } - if (self.reload_grenade_launcher == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((6 - self.reload_grenade_launcher) == - self.ammo_rockets) { - sprint(self, PRINT_HIGH, "All grenades are in the clip\n"); - return; - } - if (self.ammo_rockets >= 1) { - self.current_weapon = weap; - if (self.reload_grenade_launcher >= self.ammo_rockets) - reloadamount = self.ammo_rockets; - else - reloadamount = self.reload_grenade_launcher; - Attack_Finished(0.6); - self.reload_clipsize = (6 - reloadamount); - reloadtime = (6 - reloadamount) / 6; - reloadtime = 4 - 4 * reloadtime; - self.reload_grenade_launcher = 0; - if (self.ammo_rockets < 6) { - self.reload_grenade_launcher = - 6 - self.ammo_rockets; - } - sprint(self, PRINT_HIGH, "Reloading Grenade Launcher...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_grenade_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_ROCKET_LAUNCHER) { - if (self.ammo_rockets == 0) { - sprint(self, PRINT_HIGH, "Out of rockets\n"); - return; - } - if (self.reload_rocket_launcher == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((4 - self.reload_rocket_launcher) == - self.ammo_rockets) { - sprint(self, PRINT_HIGH, "All rockets are in the clip\n"); - return; - } - if (self.ammo_rockets >= 1) { - self.current_weapon = weap; - if (self.reload_rocket_launcher >= self.ammo_rockets) - reloadamount = self.ammo_rockets; - else - reloadamount = self.reload_rocket_launcher; - Attack_Finished(0.8); - self.reload_clipsize = (4 - reloadamount); - reloadtime = (4 - reloadamount) / 4; - reloadtime = 5 - (5 * reloadtime); - self.reload_rocket_launcher = 0; - if (self.ammo_rockets < 4) { - self.reload_rocket_launcher = - 4 - self.ammo_rockets; - } - sprint(self, PRINT_HIGH, "Reloading Rocket Launcher...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_rocket_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - - if (self.reload_assault_cannon == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - - if ((PC_HVYWEAP_ASSCAN_CLIPSIZE - self.reload_assault_cannon) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - - if (self.ammo_shells >= 1) { - self.current_weapon = weap; - if (self.reload_assault_cannon >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_assault_cannon; - Attack_Finished(0.8); - self.reload_clipsize = (PC_HVYWEAP_ASSCAN_CLIPSIZE - reloadamount); - reloadtime = (PC_HVYWEAP_ASSCAN_CLIPSIZE - reloadamount) / PC_HVYWEAP_ASSCAN_CLIPSIZE; - reloadtime = 4 - (4 * reloadtime); - self.reload_assault_cannon = 0; - if (self.ammo_shells < PC_HVYWEAP_ASSCAN_CLIPSIZE) { - self.reload_assault_cannon = PC_HVYWEAP_ASSCAN_CLIPSIZE - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Assault Cannon...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_assault_cannon; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } - } - - if (reloadamount && reloadtime) { - self.reload_time = time + reloadtime; - self.reload_tick = reloadtime / reloadamount; - tClip = spawn(); - tClip.owner = self; - tClip.classname = "timer"; - tClip.nextthink = time + self.reload_tick; - tClip.think = TeamFortress_ClipTick; - } -} - void () TeamFortress_ReloadCurrentWeapon = { - TeamFortress_ReloadWeapon(self.current_weapon, FALSE); + FO_ReloadWeapon(self.current_weapon, FALSE); }; void () TeamFortress_ForceReloadCurrentWeapon = { - TeamFortress_ReloadWeapon(self.current_weapon, TRUE); + FO_ReloadWeapon(self.current_weapon, TRUE); }; void (float slot) TeamFortress_ReloadSlot = { @@ -793,7 +507,7 @@ void (float slot) TeamFortress_ReloadSlot = { return; weap = W_WeaponSlot3(); } - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); } else { if (slot < 1 || slot > 7) @@ -813,7 +527,7 @@ void (float slot) TeamFortress_ReloadSlot = { else if (slot == 7) weap = W_OldWeaponSlot7(); if (weap != 0) - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); } }; @@ -823,8 +537,8 @@ void () TeamFortress_ReloadNext = { if (!IsUsingOldImpulses()) { // reload current slot first slot = W_GetSlot(self.current_weapon); - if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon, FALSE); + if (FO_CanReload(self.current_weapon)) { + FO_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -841,9 +555,9 @@ void () TeamFortress_ReloadNext = { weap = W_WeaponSlot3(); } - if (CheckForAmmo(weap)) { + if (FO_CanReload(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); reload = 1; break; } @@ -851,8 +565,8 @@ void () TeamFortress_ReloadNext = { } else { slot = W_OldGetSlot(self.current_weapon); - if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon, FALSE); + if (FO_CanReload(self.current_weapon)) { + FO_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -873,9 +587,9 @@ void () TeamFortress_ReloadNext = { else if (slot == 7) weap = W_OldWeaponSlot7(); - if (CheckForAmmo(weap)) { + if (FO_CanReload(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); reload = 1; break; } @@ -887,16 +601,6 @@ void () TeamFortress_ReloadNext = { sprint(self, PRINT_HIGH, "All clips full\n"); }; -void () TeamFortress_ClipTick = { - if (time < self.owner.reload_time) { - self.owner.reload_clipsize = self.owner.reload_clipsize + 1; - Status_Refresh(self.owner); - self.nextthink = time + self.owner.reload_tick; - } else { - dremove(self); - } -}; - entity TeamFortress_GetPracticeSpawn(entity e) = { local entity spt = find(world, classname, "practicespawn"); diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 73739a18..e6e0550b 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -115,7 +115,7 @@ void FireAssCan (float shotcount, vector dir, vector spread) { self.reload_assault_cannon = self.reload_assault_cannon + 1; Status_Refresh(self); - CheckForReload(); + FO_CheckForReload(); vector bullet_dir, spread_dir, rand_dir, org; float bullet_speed, var_speed; diff --git a/ssqc/progs.src b/ssqc/progs.src index 2bd3c685..5cd0b0b3 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -16,6 +16,7 @@ events.qc roles.qc q3defs.qc debug.qc +../share/fo_weapons.qc status.qc functions.qc menu.qc @@ -29,7 +30,6 @@ items.qc locfiles.qc antilag.qc combat.qc -../share/fo_weapons.qc weapons.qc world.qc client.qc diff --git a/ssqc/status.qc b/ssqc/status.qc index f23d22cc..1e2f383a 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -6,7 +6,6 @@ string(float num) RedScoreToString; string(float num) YellowScoreToString; string(float num) GreenScoreToString; string(entity pl, float csqcactive) ClipSizeToString; -float(entity pl) GetClipSize; string(entity pl) SniperPowerToString; string(entity pl) DetpackToString; string(entity pl) AuraToString; @@ -753,6 +752,9 @@ string GetSBClipString(entity pl, float csqcactive) string msg = ""; if (pl.tfstate & TFSTATE_RELOADING) { + FO_WeapInfo wi; + FO_FillWeapInfo(pl, pl.current_weapon, &wi); + if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); } else { @@ -762,7 +764,7 @@ string GetSBClipString(entity pl, float csqcactive) msg = csqcactive ? "0" : " 0"; msg = strcat(msg, "/"); - msg = strcat(msg, (csqcactive ? ftos(GetClipSize(pl)) : strpadr(ftos(GetClipSize(pl)), 3))); + msg = strcat(msg, (csqcactive ? ftos(wi->clip_size) : strpadr(ftos(wi->clip_size), 3))); } } else @@ -1331,89 +1333,25 @@ string(float num) GreenScoreToString = string(entity pl, float csqcactive) ClipSizeToString = { - local string st = ""; - local float num = 0, max; - - max = GetClipSize(pl); - if (pl.current_weapon == WEAP_SHOTGUN) { - if ((max - pl.reload_shotgun) > pl.ammo_shells) - pl.reload_shotgun = max - pl.ammo_shells; - num = max - pl.reload_shotgun; - } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { - if ((max - pl.reload_super_shotgun) > pl.ammo_shells) - pl.reload_super_shotgun = max - pl.ammo_shells; - num = (max - pl.reload_super_shotgun); - } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { - if (!sniperreload) - return ""; - if ((max - pl.reload_sniper_rifle) > pl.ammo_shells) - pl.reload_sniper_rifle = max - pl.ammo_shells; - num = (max - pl.reload_sniper_rifle); - } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { - if ((max - pl.reload_grenade_launcher) > pl.ammo_rockets) - pl.reload_grenade_launcher = (max - pl.ammo_rockets); - num = (max - pl.reload_grenade_launcher); - } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { - if ((max - pl.reload_rocket_launcher) > pl.ammo_rockets) - pl.reload_rocket_launcher = (max - pl.ammo_rockets); - num = (max - pl.reload_rocket_launcher); - } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if ((max - pl.reload_assault_cannon) > pl.ammo_shells) - pl.reload_assault_cannon = (max - pl.ammo_shells); - num = (max - pl.reload_assault_cannon); - } - } else + FO_WeapInfo wi; + FO_FillWeapInfo(pl, pl.current_weapon, &wi); + + if (!wi->needs_reload) return ""; - if (num > 999) - num = 999; + if (wi->clip_size - *wi->clip_fired > *wi->ammo_remaining) + *wi->clip_fired = wi->clip_size - *wi->ammo_remaining; + float rem = min(wi->clip_size - *wi->clip_fired, 999); + string st = ""; if (csqcactive) - { - st = strcat(ftos(floor(num)), "/", ftos(max)); - } + st = strcat(ftos(floor(rem)), "/", ftos(wi->clip_size)); else - { - st = strpadl(ftos(floor(num)), 2); - st = strcat(st, "/"); - st = strcat(st, strpadr(ftos(max), 3)); - } - - + st = strcat(strpadl(ftos(rem), 2), "/", strpadr(ftos(wi->clip_size), 3)); return st; }; -float GetClipSize(entity pl) -{ - switch (pl.current_weapon) - { - case WEAP_SHOTGUN: - return 8; - case WEAP_SUPER_SHOTGUN: - return 16; - case WEAP_SNIPER_RIFLE: - return 1; - case WEAP_GRENADE_LAUNCHER: - return 6; - case WEAP_ROCKET_LAUNCHER: - return 4; - case WEAP_ASSAULT_CANNON: - if (fo_hwguy) - { - return PC_HVYWEAP_ASSCAN_CLIPSIZE; - } - else - { - return 0; - } - default: - return 0; - } -} - string(entity pl) DisguiseToString = { local string st = ""; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 9a2e2ca8..70492d4d 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -80,7 +80,7 @@ void () UseSpecialSkill; void () UseSpecialSkill2; void () RemoveFlare; void () ScannerSwitch; -float () CheckForReload; +float () FO_CheckForReload; void (float all) TeamFortress_TeamShowScores; void (entity Player) TeamFortress_TeamShowMemberClasses; @@ -1839,163 +1839,6 @@ void () W_ChangeToBestWeapon = { W_PrintWeaponMessage(); } -float () W_CheckNoAmmo = { - if (self.current_weapon == WEAP_AXE - || self.current_weapon == WEAP_SPANNER - || self.current_weapon == WEAP_KNIFE - || self.current_weapon == WEAP_MEDIKIT) - return 1; - else if (self.current_weapon == WEAP_SUPER_NAILGUN && self.currentammo >= 4) - return 1; - else if (self.current_weapon == WEAP_INCENDIARY && self.currentammo >= 3) - return 1; - else if ((self.current_weapon == WEAP_SUPER_SHOTGUN || self.current_weapon == WEAP_NAILGUN) - && self.currentammo >= 2) - return 1; - else if (self.currentammo > 0) - return 1; - - W_ChangeToBestWeapon(); - return 0; -}; - -void () W_Reload_shotgun = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_shot.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void () W_Reload_super_shotgun = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_shot2.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void (entity pl) W_Reload_sniper_rifle = { - pl.reload_sniper_ticks = 0; - pl.tfstate = pl.tfstate - (pl.tfstate & TFSTATE_RELOADING); - pl.weaponmodel = "progs/v_srifle.mdl"; - sprint(pl, PRINT_HIGH, "Finished reloading\n"); - W_WeaponState_Load(pl, 0); - Status_Refresh(pl); -}; - -void () W_Reload_sniper_rifle_tick = { - self.owner.reload_sniper_ticks = self.owner.reload_sniper_ticks + 1; - - if (self.owner.reload_sniper_ticks >= 4) { - W_Reload_sniper_rifle(self.owner); - dremove(self); - return; - } - - Status_Refresh(self.owner); - self.nextthink = time + 1; -} - -void () W_Reload_grenade_launcher = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - if (self.owner.weaponmode == 0) - self.owner.weaponmodel = "progs/v_rock.mdl"; - else - self.owner.weaponmodel = "progs/v_pipe.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void () W_Reload_rocket_launcher = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_rock2.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void () W_Reload_assault_cannon = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_asscan.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -float FO_CheckForReload(); - -float () CheckForReload = { - if (FO_UseNewReload()) - return FO_CheckForReload(); - - float need_reload = FALSE; - - if (self.current_weapon == WEAP_SHOTGUN) { - if (self.reload_shotgun >= 8 && self.ammo_shells > 0) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { - if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy && self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE - && self.ammo_shells > 0) - need_reload = TRUE; - } - - if (need_reload) { - if (force_reload) - TeamFortress_ForceReloadCurrentWeapon(); - return 1; - } else { - return 0; - } -}; - -float FO_CheckForAmmo(float weapon); -float (float weap) CheckForAmmo = { - if (FO_UseNewReload()) - return FO_CheckForAmmo(weap); - - if (weap == WEAP_SHOTGUN) { - if (self.reload_shotgun >= 1 && self.ammo_shells > self.reload_shotgun) - return 1; - } else if (weap == WEAP_SUPER_SHOTGUN) { - if (self.reload_super_shotgun >= 2 && self.ammo_shells > self.reload_super_shotgun) - return 1; - } else if (weap == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > self.reload_sniper_rifle && sniperreload) - return 1; - } else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.reload_grenade_launcher >= 1 && self.ammo_rockets > self.reload_grenade_launcher) - return 1; - } else if (weap == WEAP_ROCKET_LAUNCHER) { - if (self.reload_rocket_launcher >= 1 && self.ammo_rockets > self.reload_rocket_launcher) - return 1; - } else if (weap == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) { - if (self.reload_assault_cannon >= 1 && self.ammo_shells > self.reload_assault_cannon) - return 1; - } - } - return 0; -}; - void () player_axe1; void () player_axeb1; @@ -2021,10 +1864,9 @@ void () player_medikit1; void () player_medikitb1; void () W_Attack = { - local float r; - - if (!W_CheckNoAmmo()) - return; + FO_WeapInfo wi; + FO_FillWeapInfo(self, self.current_weapon, &wi); + float r; if (self.has_disconnected == TRUE) return; @@ -2032,7 +1874,17 @@ void () W_Attack = { if (self.tfstate & TFSTATE_RELOADING || self.is_detpacking) return; - if(no_fire_mode) + if (no_fire_mode) + return; + + // Out of ammo? + if (wi->ammo_type != AMMO_NONE && + *wi->ammo_remaining < wi->ammo_per_shot) { + W_ChangeToBestWeapon(); + return; + } + // Fired into forced reload? + if (FO_CheckForReload()) return; if ((self.is_undercover || (self.undercover_team != 0)) || @@ -2043,7 +1895,6 @@ void () W_Attack = { self.show_hostile = time + 1; if (self.current_weapon == WEAP_AXE) { - Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) @@ -2051,7 +1902,6 @@ void () W_Attack = { else player_axeb1(); } else if (self.current_weapon == WEAP_KNIFE) { - Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) @@ -2059,77 +1909,48 @@ void () W_Attack = { else player_knifeb1(); } else if (self.current_weapon == WEAP_SPANNER) { - Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); player_spanner1(); } else if (self.current_weapon == WEAP_SHOTGUN) { - if (CheckForReload() == TRUE) - return; player_shot1(); W_FireShotgun(); self.reload_shotgun = self.reload_shotgun + 1; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.5); } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - if (CheckForReload() == TRUE) - return; player_shot1(); W_FireSuperShotgun(); self.reload_super_shotgun = self.reload_super_shotgun + 2; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.7); } else if (self.current_weapon == WEAP_NAILGUN) { player_nail1(); } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { player_nail1(); } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - if (CheckForReload() == TRUE) - return; player_rocket1(); W_FireGrenade(); self.reload_grenade_launcher = self.reload_grenade_launcher + 1; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.6); } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { - if (CheckForReload() == TRUE) - return; player_rocket1(); W_FireRocket(); self.reload_rocket_launcher = self.reload_rocket_launcher + 1; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.8); } else if (self.current_weapon == WEAP_LIGHTNING) { player_light1(); - Attack_Finished(0.1); FO_Sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.flags & FL_ONGROUND) { - if (CheckForReload() == TRUE) - return; player_shot1(); W_FireSniperRifle(); if (sniperreload) { self.reload_sniper_rifle = self.reload_sniper_rifle + 1; Status_Refresh(self); - CheckForReload(); } - Attack_Finished(1.5); } } else if (self.current_weapon == WEAP_AUTO_RIFLE) { player_autorifle1(); W_FireAutoRifle(); - Attack_Finished(0.1); } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if (CheckForReload() == TRUE) - return; - } - if (self.ammo_cells < 7) { if (time >= self.antispam_assault_cannon) { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); @@ -2157,19 +1978,6 @@ void () W_Attack = { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); - switch (pyro_type) - { - case PYRO_ORIGINAL: - Attack_Finished(1.2); - break; - case PYRO_OZTF: - Attack_Finished(0.9); - break; - case PYRO_FO: - //Attack_Finished(PC_PYRO_LAVA_RETICK); - Attack_Finished(0.9); - break; - } } else if (time >= self.antispam_incendiary_cannon) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; @@ -2181,19 +1989,22 @@ void () W_Attack = { player_medikit1(); else player_medikitb1(); - Attack_Finished(0.5); } else if (self.current_weapon == WEAP_TRANQ) { FO_Sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); player_shot1(); W_FireTranq(); - Attack_Finished(1.5); } else if (self.current_weapon == WEAP_RAILGUN) { FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireLaser(); - Attack_Finished(0.4); } + if (self.current_weapon != WEAP_FLAMETHROWER) + Attack_Finished(wi->attack_time); + + if (wi->needs_reload) + FO_CheckForReload(); + //These weapons have to log each projectile launched/bullet fired if (self.current_weapon != WEAP_ASSAULT_CANNON || self.current_weapon != WEAP_NAILGUN || From b6288178bc3f6a806779d678f7fe853052668a8d Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:19:55 -0700 Subject: [PATCH 1661/2474] Add WEAP->Index conversion Useful so that we can have lookup tables indexed by weapon, which is otherwise a flag bit value. --- csqc/csprogs.src | 1 + csqc/main.qc | 1 + share/defs.h | 44 ++++++++++++++++++++++++-------------------- share/fo_weapons.qc | 42 +++++++++++++++++++++++++++++++++++++++++- ssqc/client.qc | 5 +++-- 5 files changed, 70 insertions(+), 23 deletions(-) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 2aa77962..37747e32 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -11,6 +11,7 @@ csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc +../share/fo_weapons.qc sui_sys.qc vote.qc status.qc diff --git a/csqc/main.qc b/csqc/main.qc index 7f5bd666..3e7f7994 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -27,6 +27,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_pic(HudIcons[i].icon); // } + FO_Weapons_Init(); CsGrenTimer::Init(); registercommand("fo_hud_editor"); diff --git a/share/defs.h b/share/defs.h index 3d0a8e5b..fef62997 100644 --- a/share/defs.h +++ b/share/defs.h @@ -704,26 +704,30 @@ /* New Weapon Defines */ /*======================================================*/ -#define WEAP_HOOK 1 -#define WEAP_KNIFE 2 -#define WEAP_MEDIKIT 4 -#define WEAP_SPANNER 8 -#define WEAP_AXE 16 -#define WEAP_SNIPER_RIFLE 32 -#define WEAP_AUTO_RIFLE 64 -#define WEAP_SHOTGUN 128 -#define WEAP_SUPER_SHOTGUN 256 -#define WEAP_NAILGUN 512 -#define WEAP_SUPER_NAILGUN 1024 -#define WEAP_GRENADE_LAUNCHER 2048 -#define WEAP_FLAMETHROWER 4096 -#define WEAP_ROCKET_LAUNCHER 8192 -#define WEAP_INCENDIARY 16384 -#define WEAP_ASSAULT_CANNON 32768 -#define WEAP_LIGHTNING 65536 -#define WEAP_DETPACK 131072 -#define WEAP_TRANQ 262144 -#define WEAP_RAILGUN 524288 +enumflags { + WEAP_HOOK, + WEAP_KNIFE, + WEAP_MEDIKIT, + WEAP_SPANNER, + WEAP_AXE, + WEAP_SNIPER_RIFLE, + WEAP_AUTO_RIFLE, + WEAP_SHOTGUN, + WEAP_SUPER_SHOTGUN, + WEAP_NAILGUN, + WEAP_SUPER_NAILGUN, + WEAP_GRENADE_LAUNCHER, + WEAP_FLAMETHROWER, + WEAP_ROCKET_LAUNCHER, + WEAP_INCENDIARY, + WEAP_ASSAULT_CANNON, + WEAP_LIGHTNING, + WEAP_DETPACK, + WEAP_TRANQ, + WEAP_RAILGUN, + WEAP_LAST = WEAP_RAILGUN, +}; + // still room for 12 more weapons // but we can remove some by giving the weapons // a weapon mode (like the rifle) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 9b2c753e..adda5d1c 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -1,3 +1,40 @@ +#ifdef CSQC +/* + * This is a hack so that we can have our client entity be closer to server for + * shared code. We'll refactor this on both sides to be cleaner incrementally, + * but it gets us started. + */ +.float reload_rocket_launcher; +.float reload_grenade_launcher; +.float reload_shotgun; +.float reload_super_shotgun; +.float reload_super_shotgun; +.float reload_assault_cannon; +.float reload_sniper_rifle; +.float waterlevel; + +.float ammo_shells; +.float ammo_nails; +.float ammo_rockets; +.float ammo_cells; + +float fo_hwguy = TRUE; +float sniperreload = FALSE; +float pyro_type = PYRO_FO; +#endif + +// Convert a weapon-bit to a linear index. +static float WEAP_to_index(float weapon) { + float index = 0; + for (; weapon > 0; weapon >>= 1, index++) { + if (weapon >= 64) { + weapon >>= 6; + index += 6; + } + } + return index - 1; // Want zero-offset. +} + enum AmmoType { AMMO_NONE, AMMO_SHELLS, @@ -196,7 +233,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { case WEAP_LIGHTNING: case WEAP_DETPACK: default: - error("Should never be invoked\n"); + error(sprintf("ID=%d should never be invoked\n", weapon)); } wi->needs_reload = wi->clip_size > 0; @@ -329,3 +366,6 @@ void FO_ReloadWeapon(float weapon, float force) { } #endif + +void FO_Weapons_Init() { +} diff --git a/ssqc/client.qc b/ssqc/client.qc index 2b43cc50..2a46e9cf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1076,8 +1076,9 @@ void () DecodeLevelParms = { } if (parm15) self.is_admin = parm15; - - + + // Must be after we've set up conditional options (e.g. hwguy reload). + FO_Weapons_Init(); /* local entity p = find(world, classname, "player"); while (p != world) { From 698018150598ddc0e40b5562d62cdc957f02e87e Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 21:02:29 -0700 Subject: [PATCH 1662/2474] refactor on weapindex --- share/fo_weapons.qc | 350 +++++++++++++++++++++++++------------------- ssqc/status.qc | 14 +- ssqc/weapons.qc | 7 +- 3 files changed, 209 insertions(+), 162 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index adda5d1c..bf761eb4 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -41,9 +41,98 @@ enum AmmoType { AMMO_NAILS, AMMO_CELLS, AMMO_ROCKETS, - AMMO_GRENADES, // Rockets really + AMMO_NUM_TYPES = AMMO_ROCKETS + 1, }; +struct FO_WeapInfo { + int weapon; // Verification + AmmoType ammo_type; + int clip_size; + int ammo_per_shot; + float attack_time; + float full_reload_time; + + // Fields below this are automatically initialized by Init. Do not include + // in table. + float needs_reload; +}; + +// REQUIRES: weapon at index i == WEAP_to_index(weap) +// -ve values are placeholders signifying conditional init based on game modes. +FO_WeapInfo weapon_info[] = { + { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_MEDIKIT, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_SPANNER, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_AXE, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_SNIPER_RIFLE, AMMO_SHELLS, -9, 1, 1.5, 4 }, + { WEAP_AUTO_RIFLE, AMMO_SHELLS, 0, 1, 0.1, 0 }, + { WEAP_SHOTGUN, AMMO_SHELLS, 8, 1, 0.5, 2 }, + { WEAP_SUPER_SHOTGUN, AMMO_SHELLS, 16, 2, 0.7, 3 }, + { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, + { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 4, 0.2, 0 }, + { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, + { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, + { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, + { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, + { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0, 4 }, + { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, + { WEAP_DETPACK, AMMO_NONE, 0, 0, -1, 0 }, + { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, + { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, +}; + +struct FO_ClassWeapons { + float id; + float slots[4]; + FO_WeapInfo *info[4]; +}; + +// Indexed by class ID, e.g. PC_SOLDIER +FO_ClassWeapons class_weapons[] = { + { PC_UNDEFINED, { 0, 0, 0, 0 } }, + { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, + { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, + { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_GRENADE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_MEDIC, { WEAP_SUPER_NAILGUN, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_MEDIKIT } }, + { PC_HVYWEAP, { WEAP_ASSAULT_CANNON, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, + { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, +}; + +inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { + return &weapon_info[WEAP_to_index(weapon)]; +} + +// Indexed by WEAP_to_index(). We keep them out of the main table just to keep +// things a little more wieldly/readable. +static string weapon_names[] = { + "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", "Sniper Rifle", + "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", "Grenade Launcher", + "Flamethrower", "Rocket Launcher", "Incendiary Launcher", "Assault Cannon", + "Lightning Gun", "Detpack", "Tranquilizer", "Railgun" +}; + +inline string FO_GetWeapName(float weapon) { + return weapon_names[WEAP_to_index(weapon)]; +} + +struct FO_WeapState { + float weapon; + + // Constant and relative to weapon. TODO, migrate similar to WeapInfo. + FO_WeapInfo* wi; + string model[2]; // indexed by weaponmode + + /* These are relative to the player passed. */ + float* ammo_remaining; + float* clip_fired; +}; + +struct FO_WeapInfo weap_info_by_index[32]; + // REQUIRES: Order must match above. static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; @@ -54,180 +143,90 @@ static float* AMMO_to_p(entity player, AmmoType ammo_type) { case AMMO_CELLS: return &player.ammo_cells; case AMMO_NAILS: return &player.ammo_nails; case AMMO_ROCKETS: return &player.ammo_rockets; - case AMMO_GRENADES: return &player.ammo_rockets; } error(sprintf("UNK AMMO_TYPE=%d\n", ammo_type)); return __NULL__; } -struct FO_WeapInfo { - float weapon; - - /* These are always constant and relative to weapon. */ - string name; - string model[2]; // indexed by weaponmode - AmmoType ammo_type; - float ammo_per_shot; - float needs_reload; - float full_reload_time; - float clip_size; - float attack_time; +float WEAP_to_slot(float class, float weapon) { + for (float i = 0; i < 4; i++) + if (class_weapons[class].slots[i] == weapon) + return i; + return -1; +} - /* These are relative to the player passed. */ - float* ammo_remaining; - float* clip_fired; -}; +void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { + ws->weapon = weapon; + ws->wi = FO_GetWeapInfo(weapon); -void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { - wi->weapon = weapon; - wi->ammo_per_shot = 1; - wi->clip_size = 0; switch (weapon) { /* NONE */ case WEAP_HOOK: - wi->name = "Hook"; - wi->model[0] = "progs/v_grap.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_grap.mdl"; break; case WEAP_KNIFE: - wi->name = "Knife"; - wi->model[0] = "progs/v_knife.mdl"; - wi->model[1] = "progs/v_knife2.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_knife.mdl"; + ws->model[1] = "progs/v_knife2.mdl"; break; case WEAP_MEDIKIT: - wi->name = "BioAxe"; - wi->model[0] = "progs/v_medi.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_medi.mdl"; break; case WEAP_SPANNER: - wi->name = "Spanner"; - wi->model[0] = "progs/v_spanner.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_spanner.mdl"; break; case WEAP_AXE: - wi->name = "Axe"; - wi->model[0] = "progs/v_axe.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_axe.mdl"; break; /* SHELLS */ case WEAP_SHOTGUN: - wi->name = "Shotgun"; - wi->model[0] = "progs/v_shot.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->clip_size = 8; - wi->attack_time = 0.5; - wi->full_reload_time = 2; - wi->clip_fired = &player.reload_shotgun; + ws->model[0] = "progs/v_shot.mdl"; + ws->clip_fired = &player.reload_shotgun; break; case WEAP_SUPER_SHOTGUN: - wi->name = "Super Shotgun"; - wi->model[0] = "progs/v_shot2.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->clip_size = 16; - wi->ammo_per_shot = 2; - wi->attack_time = 0.7; - wi->full_reload_time = 3; - wi->clip_fired = &player.reload_super_shotgun; + ws->model[0] = "progs/v_shot2.mdl"; + ws->clip_fired = &player.reload_super_shotgun; break; case WEAP_SNIPER_RIFLE: - wi->name = "Sniper Rifle"; - wi->model[0] = "progs/v_srifle.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->attack_time = 1.5; - if (sniperreload) { - wi->clip_size = 1; - wi->full_reload_time = 4; - wi->clip_fired = &self.reload_sniper_rifle; - } + ws->model[0] = "progs/v_srifle.mdl"; + if (sniperreload) + ws->clip_fired = &player.reload_sniper_rifle; break; case WEAP_AUTO_RIFLE: - wi->name = "Sniper Rifle"; - wi->model[0] = "progs/v_srifle.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->attack_time = 0.1; + ws->model[0] = "progs/v_srifle.mdl"; break; case WEAP_TRANQ: - wi->name = "Tranq Gun"; - wi->model[0] = "progs/v_tranq.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->attack_time = 1.5; + ws->model[0] = "progs/v_tranq.mdl"; break; case WEAP_ASSAULT_CANNON: - wi->name = "Assault Cannon"; - wi->model[0] = "progs/v_asscan.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->clip_size = 100; - wi->full_reload_time = 4; - wi->clip_fired = &player.reload_assault_cannon; - if (fo_hwguy) - wi->clip_size = PC_HVYWEAP_ASSCAN_CLIPSIZE; + ws->model[0] = "progs/v_asscan.mdl"; + ws->clip_fired = &player.reload_assault_cannon; break; /* NAILS */ case WEAP_NAILGUN: - wi->name = "Nailgun"; - wi->model[0] = "progs/v_nail.mdl"; - wi->ammo_type = AMMO_NAILS; - wi->ammo_per_shot = 2; - wi->attack_time = 0.2; + ws->model[0] = "progs/v_nail.mdl"; break; case WEAP_SUPER_NAILGUN: - wi->name = "Super Nailgun"; - wi->model[0] = "progs/v_nail2.mdl"; - wi->ammo_type = AMMO_NAILS; - wi->ammo_per_shot = 4; - wi->attack_time = 0.2; + ws->model[0] = "progs/v_nail2.mdl"; break; case WEAP_RAILGUN: - wi->name = "Railgun"; - wi->model[0] = "progs/v_rail.mdl"; - wi->ammo_type = AMMO_NAILS; - wi->ammo_type = AMMO_NAILS; - wi->attack_time = 0.4; + ws->model[0] = "progs/v_rail.mdl"; break; /* ROCKETS */ case WEAP_GRENADE_LAUNCHER: - wi->name = "Grenade Launcher"; - wi->model[0] = "progs/v_rock.mdl"; - wi->model[1] = "progs/v_pipe.mdl"; - wi->ammo_type = AMMO_ROCKETS; - wi->clip_size = 6; - wi->attack_time = 0.6; - wi->full_reload_time = 4; - wi->clip_fired = &player->reload_grenade_launcher; + ws->model[0] = "progs/v_rock.mdl"; + ws->model[1] = "progs/v_pipe.mdl"; + ws->clip_fired = &player.reload_grenade_launcher; break; case WEAP_ROCKET_LAUNCHER: - wi->name = "Rocket Launcher"; - wi->model[0] = "progs/v_rock2.mdl"; - wi->ammo_type = AMMO_ROCKETS; - wi->clip_size = 4; - wi->clip_fired = &player->reload_rocket_launcher; - wi->full_reload_time = 5; - wi->attack_time = 0.8; + ws->model[0] = "progs/v_rock2.mdl"; + ws->clip_fired = &player.reload_rocket_launcher; break; case WEAP_INCENDIARY: - wi->name = "Incendiary Launcher"; - wi->model[0] = "progs/v_irock.mdl"; - wi->ammo_type = AMMO_ROCKETS; - wi->ammo_per_shot = 3; - wi->attack_time = 0.9; - switch (pyro_type) { - case PYRO_ORIGINAL: wi->attack_time = 1.2; break; - case PYRO_OZTF: wi->attack_time = 0.9; break; - case PYRO_FO: wi->attack_time = 0.9; break; - } + ws->model[0] = "progs/v_irock.mdl"; break; /* CELLS */ case WEAP_FLAMETHROWER: - wi->name = "Flamethrower"; - wi->model[0] = "progs/v_flame.mdl"; - wi->ammo_type = AMMO_CELLS; - wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; + ws->model[0] = "progs/v_flame.mdl"; break; /* NOT USED */ case WEAP_LIGHTNING: @@ -236,11 +235,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { error(sprintf("ID=%d should never be invoked\n", weapon)); } - wi->needs_reload = wi->clip_size > 0; - wi->ammo_remaining = AMMO_to_p(player, wi->ammo_type); - if (!wi->needs_reload) { - wi->clip_fired = __NULL__; - } + ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); } #ifdef SSQC @@ -250,19 +245,19 @@ void (entity pl, float swap) W_WeaponState_Load; void (float att_delay) Attack_Finished; static void FOT_ReloadTimer() { - FO_WeapInfo wi; - FO_FillWeapInfo(self.owner, self.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self.owner, self.current_weapon, &ws); if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = wi->model[self.owner.weaponmode]; + self.owner.weaponmodel = ws->model[self.owner.weaponmode]; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); } else { // Refresh clip - if (wi.weapon != WEAP_SNIPER_RIFLE) + if (ws->weapon != WEAP_SNIPER_RIFLE) self.owner.reload_clipsize += 1; else self.owner.reload_sniper_ticks += 1; @@ -273,14 +268,15 @@ static void FOT_ReloadTimer() { } float FO_CanReload(float weapon) { - FO_WeapInfo wi; - FO_FillWeapInfo(self, weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, weapon, &ws); + FO_WeapInfo* wi = ws->wi; if (wi->ammo_type == AMMO_NONE) return FALSE; - if (wi->needs_reload && *wi->clip_fired > 0 - && *wi->ammo_remaining > wi->ammo_per_shot) + if (wi->needs_reload && *ws->clip_fired > 0 + && *ws->ammo_remaining > wi->ammo_per_shot) return TRUE; return FALSE; @@ -288,11 +284,12 @@ float FO_CanReload(float weapon) { void () TeamFortress_ForceReloadCurrentWeapon; float FO_CheckForReload() { - FO_WeapInfo wi; - FO_FillWeapInfo(self, self.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, self.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; - if (wi->needs_reload && *wi->clip_fired >= wi->clip_size && - *wi->ammo_remaining > 0) { + if (wi->needs_reload && *ws->clip_fired >= wi->clip_size && + *ws->ammo_remaining > 0) { if (force_reload) TeamFortress_ForceReloadCurrentWeapon(); return TRUE; @@ -306,25 +303,27 @@ void FO_ReloadWeapon(float weapon, float force) { if (self.tfstate & TFSTATE_RELOADING) return; - FO_WeapInfo wi; - FO_FillWeapInfo(self, weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, weapon, &ws); + FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) return; string msg = string_null; - if (*wi->clip_fired == 0) + if (*ws->clip_fired == 0) msg = "Clip full\n"; - else if (*wi->ammo_remaining == 0) + else if (*ws->ammo_remaining == 0) msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); - else if (wi->clip_size - *wi->clip_fired == *wi->ammo_remaining) + else if (wi->clip_size - *ws->clip_fired == *ws->ammo_remaining) msg = strcat("All ", AMMO_to_s[wi->ammo_type], "are in the clip\n"); if (msg != string_null) { sprint(self, PRINT_HIGH, msg); return; } else { - sprint(self, PRINT_HIGH, strcat("Reloading ", wi->name, "...\n")); + sprint(self, PRINT_HIGH, strcat("Reloading ", + FO_GetWeapName(ws->weapon), "...\n")); } Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. @@ -334,11 +333,11 @@ void FO_ReloadWeapon(float weapon, float force) { self.tfstate |= TFSTATE_RELOADING; Status_Refresh(self); - float reload_count = min(*wi->clip_fired, *wi->ammo_remaining); + float reload_count = min(*ws->clip_fired, *ws->ammo_remaining); float reload_duration = (reload_count / wi->clip_size) * wi->full_reload_time; - *wi->clip_fired -= reload_count; + *ws->clip_fired -= reload_count; // Sets up for status bar. self.reload_time = time + reload_duration; @@ -365,7 +364,54 @@ void FO_ReloadWeapon(float weapon, float force) { reload_timer.nextthink = client_time() + self.reload_tick; } + +void FO_InstantReloadAllWeapons(entity player) { + player.tfstate &= ~TFSTATE_RELOADING; + player.reload_shotgun = 0; + player.reload_super_shotgun = 0; + player.reload_grenade_launcher = 0; + player.reload_rocket_launcher = 0; + player.reload_sniper_rifle = 0; + player.reload_assault_cannon = 0; +} #endif void FO_Weapons_Init() { + float i, j; + + if (weapon_names.length != weapon_info.length) + error("Weapon Names/Weapon Info inconsistency\n"); + + FO_WeapInfo* WI_ac = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + WI_ac->clip_size = fo_hwguy ? PC_HVYWEAP_ASSCAN_CLIPSIZE : 0; + FO_WeapInfo* WI_sr = FO_GetWeapInfo(WEAP_SNIPER_RIFLE); + WI_sr->clip_size = sniperreload ? 1 : 0; + + FO_WeapInfo* WI_ir = FO_GetWeapInfo(WEAP_INCENDIARY); + switch (pyro_type) { + case PYRO_ORIGINAL: WI_ir->attack_time = 1.2; break; + case PYRO_OZTF: + case PYRO_FO: + default: + WI_ir->attack_time = 0.9; break; + } + + for (i = 0; i < weapon_info.length; i++) { + FO_WeapInfo* wi = &weapon_info[i]; + if (WEAP_to_index(wi->weapon) != i) + error(sprintf("Mismatch at index %d\n", i)); + + wi->needs_reload = wi->clip_size > 0; + } + + for (i = 0; i < class_weapons.length; i++) { + for (j = 0; j < 4; j++) { + FO_ClassWeapons* cw = &class_weapons[i]; + + if (cw->slots[j]) + cw->info[j] = &weap_info_by_index[WEAP_to_index(cw->slots[j])]; + else + cw->info[j] = __NULL__; + } + } } diff --git a/ssqc/status.qc b/ssqc/status.qc index 1e2f383a..8729cf1e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -752,8 +752,7 @@ string GetSBClipString(entity pl, float csqcactive) string msg = ""; if (pl.tfstate & TFSTATE_RELOADING) { - FO_WeapInfo wi; - FO_FillWeapInfo(pl, pl.current_weapon, &wi); + FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); @@ -1333,15 +1332,16 @@ string(float num) GreenScoreToString = string(entity pl, float csqcactive) ClipSizeToString = { - FO_WeapInfo wi; - FO_FillWeapInfo(pl, pl.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(pl, pl.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) return ""; - if (wi->clip_size - *wi->clip_fired > *wi->ammo_remaining) - *wi->clip_fired = wi->clip_size - *wi->ammo_remaining; - float rem = min(wi->clip_size - *wi->clip_fired, 999); + if (wi->clip_size - *ws->clip_fired > *ws->ammo_remaining) + *ws->clip_fired = wi->clip_size - *ws->ammo_remaining; + float rem = min(wi->clip_size - *ws->clip_fired, 999); string st = ""; if (csqcactive) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 70492d4d..11b59ff9 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1864,8 +1864,9 @@ void () player_medikit1; void () player_medikitb1; void () W_Attack = { - FO_WeapInfo wi; - FO_FillWeapInfo(self, self.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, self.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; float r; if (self.has_disconnected == TRUE) @@ -1879,7 +1880,7 @@ void () W_Attack = { // Out of ammo? if (wi->ammo_type != AMMO_NONE && - *wi->ammo_remaining < wi->ammo_per_shot) { + *ws->ammo_remaining < wi->ammo_per_shot) { W_ChangeToBestWeapon(); return; } From 32fee125ad0979701c8a559306e7c67623c07acf Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 16:46:35 -0700 Subject: [PATCH 1663/2474] Eliminate reload_ spaghetti step 1. Migrates all references to reload_ types to be internal to our new implementation and with FO_WeapState to indirect. --- ssqc/client.qc | 8 +--- ssqc/hwguy.qc | 7 +++- ssqc/tfortmap.qc | 107 ++++++++++++++++------------------------------- ssqc/weapons.qc | 17 ++++---- 4 files changed, 52 insertions(+), 87 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 2a46e9cf..07d2579b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2098,13 +2098,7 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; - self.reload_shotgun = 0; - self.reload_super_shotgun = 0; - self.reload_grenade_launcher = 0; - self.reload_rocket_launcher = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RELOADING); - self.reload_sniper_rifle = 0; - self.reload_assault_cannon = 0; + FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; self.fire_held_down = 0; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index e6e0550b..174debaa 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -113,10 +113,15 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) void FireAssCan (float shotcount, vector dir, vector spread) { - self.reload_assault_cannon = self.reload_assault_cannon + 1; + FO_WeapState ws; + FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + + Status_Refresh(self); FO_CheckForReload(); + *ws->clip_fired += 1; + vector bullet_dir, spread_dir, rand_dir, org; float bullet_speed, var_speed; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 47c37a3f..158f8d2d 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -834,74 +834,44 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack; //refill the clip if stock_reload is 2 if (stock_reload == 2) { - if(Goal.ammo_shells) { - if(Player.current_weapon == WEAP_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); - if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); - if(Player.current_weapon == WEAP_SNIPER_RIFLE) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); - - if(Player.current_weapon == WEAP_ASSAULT_CANNON) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_assault_cannon = max(Player.reload_assault_cannon - Goal.ammo_shells, 0); - } - if(Goal.ammo_rockets) { - if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); - if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); + FO_WeapState ws; + FO_FillWeapState(Player, Player.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; + + + float* ammo_ptr = __NULL__; + if (Goal.ammo_shells && wi->ammo_type == AMMO_SHELLS) + ammo_ptr = &Goal.ammo_shells; + else if (Goal.ammo_rockets && wi->ammo_type == AMMO_ROCKETS) + ammo_ptr = &Goal.ammo_rockets; + else if (Goal.ammo_cells && wi->ammo_type == AMMO_CELLS) + ammo_ptr = &Goal.ammo_cells; + else if (Goal.ammo_cells && wi->ammo_type == AMMO_NAILS) + ammo_ptr = &Goal.ammo_nails; + + if (wi->needs_reload && ammo_ptr != __NULL__) { + Player.tfstate &= ~TFSTATE_RELOADING; + *ws->clip_fired = max(*ws->clip_fired - *ammo_ptr, 0); } } else { //for use in map entities without specifically enabling the general override - if(Goal.reload_shotgun) { - if(Player.current_weapon == WEAP_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); - } - if(Goal.reload_super_shotgun) { - if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); - } - if(Goal.reload_sniper_rifle) { - if(Player.current_weapon == WEAP_SNIPER_RIFLE) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); - } - if(Goal.reload_grenade_launcher) { - if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); + FO_WeapState ws; + FO_FillWeapState(Player, Player.current_weapon, &ws); + + if ((Goal.reload_shotgun && ws.weapon == WEAP_SHOTGUN) || + (Goal.reload_super_shotgun && ws.weapon == WEAP_SUPER_SHOTGUN) || + (Goal.reload_sniper_rifle && ws.weapon == WEAP_SNIPER_RIFLE) || + (Goal.reload_assault_cannon && ws.weapon == WEAP_ASSAULT_CANNON)) { + Player.tfstate &= ~TFSTATE_RELOADING; + *ws->clip_fired = max(*ws->clip_fired - Goal.ammo_shells, 0); } - if(Goal.reload_rocket_launcher) { - if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); + + if ((Goal.reload_grenade_launcher && ws.weapon == WEAP_GRENADE_LAUNCHER) || + (Goal.reload_rocket_launcher && ws.weapon == WEAP_ROCKET_LAUNCHER)) { + Player.tfstate &= ~TFSTATE_RELOADING; + *ws->clip_fired = max(*ws->clip_fired - Goal.ammo_rockets, 0); } - if (Goal.reload_assault_cannon) - { - if(Player.current_weapon == WEAP_ASSAULT_CANNON) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_assault_cannon = max(Player.reload_assault_cannon - Goal.ammo_shells, 0); - } + } Player.no_grenades_1 = Player.no_grenades_1 + Goal.no_grenades_1; @@ -1057,15 +1027,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { dremove(te); } //Refill the clip while restocking - if (stock_reload) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - Player.reload_shotgun = 0; - Player.reload_super_shotgun = 0; - Player.reload_grenade_launcher = 0; - Player.reload_rocket_launcher = 0; - Player.reload_sniper_rifle = 0; - Player.reload_assault_cannon = 0; - } + if (stock_reload) + FO_InstantReloadAllWeapons(Player); } } } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 11b59ff9..362b9030 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1864,10 +1864,10 @@ void () player_medikit1; void () player_medikitb1; void () W_Attack = { + float r; FO_WeapState ws; FO_FillWeapState(self, self.current_weapon, &ws); FO_WeapInfo* wi = ws->wi; - float r; if (self.has_disconnected == TRUE) return; @@ -1888,6 +1888,12 @@ void () W_Attack = { if (FO_CheckForReload()) return; + if (wi->needs_reload) { + if (FO_CheckForReload()) + return; + *ws->clip_fired += wi->ammo_per_shot; + } + if ((self.is_undercover || (self.undercover_team != 0)) || (self.undercover_skin != 0)) Spy_RemoveDisguise(self); @@ -1915,12 +1921,10 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_SHOTGUN) { player_shot1(); W_FireShotgun(); - self.reload_shotgun = self.reload_shotgun + 1; Status_Refresh(self); } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { player_shot1(); W_FireSuperShotgun(); - self.reload_super_shotgun = self.reload_super_shotgun + 2; Status_Refresh(self); } else if (self.current_weapon == WEAP_NAILGUN) { player_nail1(); @@ -1929,12 +1933,10 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { player_rocket1(); W_FireGrenade(); - self.reload_grenade_launcher = self.reload_grenade_launcher + 1; Status_Refresh(self); } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { player_rocket1(); W_FireRocket(); - self.reload_rocket_launcher = self.reload_rocket_launcher + 1; Status_Refresh(self); } else if (self.current_weapon == WEAP_LIGHTNING) { player_light1(); @@ -1944,7 +1946,6 @@ void () W_Attack = { player_shot1(); W_FireSniperRifle(); if (sniperreload) { - self.reload_sniper_rifle = self.reload_sniper_rifle + 1; Status_Refresh(self); } } @@ -2003,8 +2004,10 @@ void () W_Attack = { if (self.current_weapon != WEAP_FLAMETHROWER) Attack_Finished(wi->attack_time); - if (wi->needs_reload) + if (wi->needs_reload) { + *ws->clip_fired += wi->ammo_per_shot; FO_CheckForReload(); + } //These weapons have to log each projectile launched/bullet fired if (self.current_weapon != WEAP_ASSAULT_CANNON || From 7699db75e746dfe0894f39699cb1b6999d3b5a88 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 13:57:20 -0700 Subject: [PATCH 1664/2474] Migrate clip state to be allocated and referenced rather than having bespoke per-weapon clip allocations. Weapons with clips have storage/tracking automatically allocated and performed. --- share/fo_weapons.qc | 76 +++++++++++++++++++++++++-------------------- ssqc/weapons.qc | 7 +---- 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index bf761eb4..22c98c09 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -55,6 +55,7 @@ struct FO_WeapInfo { // Fields below this are automatically initialized by Init. Do not include // in table. float needs_reload; + int storage_index; // Allocated by init }; // REQUIRES: weapon at index i == WEAP_to_index(weap) @@ -119,20 +120,6 @@ inline string FO_GetWeapName(float weapon) { return weapon_names[WEAP_to_index(weapon)]; } -struct FO_WeapState { - float weapon; - - // Constant and relative to weapon. TODO, migrate similar to WeapInfo. - FO_WeapInfo* wi; - string model[2]; // indexed by weaponmode - - /* These are relative to the player passed. */ - float* ammo_remaining; - float* clip_fired; -}; - -struct FO_WeapInfo weap_info_by_index[32]; - // REQUIRES: Order must match above. static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; @@ -155,9 +142,32 @@ float WEAP_to_slot(float class, float weapon) { return -1; } +// Internal clip storage for both SSQC/CSQC. +#define CLIP_STORAGE_SIZE 8 +.float clip_fired[CLIP_STORAGE_SIZE]; + +#ifdef SSQC +struct FO_WeapState { + float weapon; + + // Constant and relative to weapon. TODO, migrate similar to WeapInfo. + FO_WeapInfo* wi; + string model[2]; // indexed by weaponmode + + /* These are relative to the player passed. */ + float* ammo_remaining; + float* clip_fired; +}; + + void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { ws->weapon = weapon; - ws->wi = FO_GetWeapInfo(weapon); + FO_WeapInfo* wi = FO_GetWeapInfo(weapon); + ws->wi = wi; + + if (wi->needs_reload) + ws->clip_fired = &player.clip_fired[wi->storage_index]; + ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); switch (weapon) { /* NONE */ @@ -180,16 +190,12 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { /* SHELLS */ case WEAP_SHOTGUN: ws->model[0] = "progs/v_shot.mdl"; - ws->clip_fired = &player.reload_shotgun; break; case WEAP_SUPER_SHOTGUN: ws->model[0] = "progs/v_shot2.mdl"; - ws->clip_fired = &player.reload_super_shotgun; break; case WEAP_SNIPER_RIFLE: ws->model[0] = "progs/v_srifle.mdl"; - if (sniperreload) - ws->clip_fired = &player.reload_sniper_rifle; break; case WEAP_AUTO_RIFLE: ws->model[0] = "progs/v_srifle.mdl"; @@ -199,7 +205,6 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { break; case WEAP_ASSAULT_CANNON: ws->model[0] = "progs/v_asscan.mdl"; - ws->clip_fired = &player.reload_assault_cannon; break; /* NAILS */ case WEAP_NAILGUN: @@ -215,11 +220,9 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { case WEAP_GRENADE_LAUNCHER: ws->model[0] = "progs/v_rock.mdl"; ws->model[1] = "progs/v_pipe.mdl"; - ws->clip_fired = &player.reload_grenade_launcher; break; case WEAP_ROCKET_LAUNCHER: ws->model[0] = "progs/v_rock2.mdl"; - ws->clip_fired = &player.reload_rocket_launcher; break; case WEAP_INCENDIARY: ws->model[0] = "progs/v_irock.mdl"; @@ -234,11 +237,8 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { default: error(sprintf("ID=%d should never be invoked\n", weapon)); } - - ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); } -#ifdef SSQC void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; void (entity pl, float swap) W_WeaponState_Load; @@ -367,12 +367,8 @@ void FO_ReloadWeapon(float weapon, float force) { void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; - player.reload_shotgun = 0; - player.reload_super_shotgun = 0; - player.reload_grenade_launcher = 0; - player.reload_rocket_launcher = 0; - player.reload_sniper_rifle = 0; - player.reload_assault_cannon = 0; + for (int i = 0; i < CLIP_STORAGE_SIZE; i++) + player.clip_fired[i] = 0; } #endif @@ -396,20 +392,34 @@ void FO_Weapons_Init() { WI_ir->attack_time = 0.9; break; } + float clips_allocated = 0; for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; if (WEAP_to_index(wi->weapon) != i) error(sprintf("Mismatch at index %d\n", i)); - wi->needs_reload = wi->clip_size > 0; + + if (wi->clip_size > 0) { + if (wi->clip_size > 0) + wi->needs_reload = TRUE; + // We always allocate a storage index for something that can have + // reload to save negotiating between client and server around + // localinfo tunables. + wi->storage_index = clips_allocated++; + } else { + wi->needs_reload = FALSE; + wi->storage_index = -1; // Make sure we'll OOB. + } } + if (clips_allocated > CLIP_STORAGE_SIZE) + error("Insufficient clip storage"); for (i = 0; i < class_weapons.length; i++) { for (j = 0; j < 4; j++) { FO_ClassWeapons* cw = &class_weapons[i]; if (cw->slots[j]) - cw->info[j] = &weap_info_by_index[WEAP_to_index(cw->slots[j])]; + cw->info[j] = &weapon_info[WEAP_to_index(cw->slots[j])]; else cw->info[j] = __NULL__; } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 362b9030..e5da4b83 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1884,16 +1884,11 @@ void () W_Attack = { W_ChangeToBestWeapon(); return; } + // Fired into forced reload? if (FO_CheckForReload()) return; - if (wi->needs_reload) { - if (FO_CheckForReload()) - return; - *ws->clip_fired += wi->ammo_per_shot; - } - if ((self.is_undercover || (self.undercover_team != 0)) || (self.undercover_skin != 0)) Spy_RemoveDisguise(self); From 895c1935ab2b068c7c31d0e29eeca44a8fd26274 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 03:28:06 -0700 Subject: [PATCH 1665/2474] Move models out of WeapState We'll put them somewhere better in another patch, but now that we've gotten everything to tables they're the last wart standing. --- share/fo_weapons.qc | 109 +++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 71 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 22c98c09..bd5ca92e 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -44,6 +44,8 @@ enum AmmoType { AMMO_NUM_TYPES = AMMO_ROCKETS + 1, }; +struct FO_WeapModels; + struct FO_WeapInfo { int weapon; // Verification AmmoType ammo_type; @@ -56,6 +58,7 @@ struct FO_WeapInfo { // in table. float needs_reload; int storage_index; // Allocated by init + FO_WeapModels* models; }; // REQUIRES: weapon at index i == WEAP_to_index(weap) @@ -120,6 +123,34 @@ inline string FO_GetWeapName(float weapon) { return weapon_names[WEAP_to_index(weapon)]; } +struct FO_WeapModels { + string mode[2]; +}; + +// Indexed by WEAP_to_index() and player.weaponmode +static FO_WeapModels weapon_models[] = { +/* WEAP_HOOK, */ {{"progs/v_grap.mdl" }}, +/* WEAP_KNIFE, */ {{"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, +/* WEAP_MEDIKIT, */ {{"progs/v_medi.mdl"}}, +/* WEAP_SPANNER, */ {{"progs/v_span.mdl"}}, +/* WEAP_AXE, */ {{"progs/v_axe.mdl"}}, +/* WEAP_SNIPER_RIFLE, */ {{"progs/v_srifle.mdl"}}, +/* WEAP_AUTO_RIFLE, */ {{"progs/v_srifle.mdl"}}, +/* WEAP_SHOTGUN, */ {{"progs/v_shot.mdl"}}, +/* WEAP_SUPER_SHOTGUN, */ {{"progs/v_shot2.mdl"}}, +/* WEAP_NAILGUN, */ {{"progs/v_nail.mdl"}}, +/* WEAP_SUPER_NAILGUN, */ {{"progs/v_nail2.mdl"}}, +/* WEAP_GRENADE_LAUNCHER, */ {{"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, +/* WEAP_FLAMETHROWER, */ {{"progs/v_flame.mdl"}}, +/* WEAP_ROCKET_LAUNCHER, */ {{"progs/v_rock2.mdl"}}, +/* WEAP_INCENDIARY, */ {{"progs/v_irock.mdl"}}, +/* WEAP_ASSAULT_CANNON, */ {{"progs/v_asscan.mdl"}}, +/* WEAP_LIGHTNING, */ {{}}, +/* WEAP_DETPACK, */ {{}}, +/* WEAP_TRANQ, */ {{"progs/v_tranq.mdl"}}, +/* WEAP_RAILGUN, */ {{"progs/v_rail.mdl"}}, +}; + // REQUIRES: Order must match above. static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; @@ -152,7 +183,6 @@ struct FO_WeapState { // Constant and relative to weapon. TODO, migrate similar to WeapInfo. FO_WeapInfo* wi; - string model[2]; // indexed by weaponmode /* These are relative to the player passed. */ float* ammo_remaining; @@ -168,75 +198,6 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { if (wi->needs_reload) ws->clip_fired = &player.clip_fired[wi->storage_index]; ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); - - switch (weapon) { - /* NONE */ - case WEAP_HOOK: - ws->model[0] = "progs/v_grap.mdl"; - break; - case WEAP_KNIFE: - ws->model[0] = "progs/v_knife.mdl"; - ws->model[1] = "progs/v_knife2.mdl"; - break; - case WEAP_MEDIKIT: - ws->model[0] = "progs/v_medi.mdl"; - break; - case WEAP_SPANNER: - ws->model[0] = "progs/v_spanner.mdl"; - break; - case WEAP_AXE: - ws->model[0] = "progs/v_axe.mdl"; - break; - /* SHELLS */ - case WEAP_SHOTGUN: - ws->model[0] = "progs/v_shot.mdl"; - break; - case WEAP_SUPER_SHOTGUN: - ws->model[0] = "progs/v_shot2.mdl"; - break; - case WEAP_SNIPER_RIFLE: - ws->model[0] = "progs/v_srifle.mdl"; - break; - case WEAP_AUTO_RIFLE: - ws->model[0] = "progs/v_srifle.mdl"; - break; - case WEAP_TRANQ: - ws->model[0] = "progs/v_tranq.mdl"; - break; - case WEAP_ASSAULT_CANNON: - ws->model[0] = "progs/v_asscan.mdl"; - break; - /* NAILS */ - case WEAP_NAILGUN: - ws->model[0] = "progs/v_nail.mdl"; - break; - case WEAP_SUPER_NAILGUN: - ws->model[0] = "progs/v_nail2.mdl"; - break; - case WEAP_RAILGUN: - ws->model[0] = "progs/v_rail.mdl"; - break; - /* ROCKETS */ - case WEAP_GRENADE_LAUNCHER: - ws->model[0] = "progs/v_rock.mdl"; - ws->model[1] = "progs/v_pipe.mdl"; - break; - case WEAP_ROCKET_LAUNCHER: - ws->model[0] = "progs/v_rock2.mdl"; - break; - case WEAP_INCENDIARY: - ws->model[0] = "progs/v_irock.mdl"; - break; - /* CELLS */ - case WEAP_FLAMETHROWER: - ws->model[0] = "progs/v_flame.mdl"; - break; - /* NOT USED */ - case WEAP_LIGHTNING: - case WEAP_DETPACK: - default: - error(sprintf("ID=%d should never be invoked\n", weapon)); - } } void () RestoreDefaultWeapon; @@ -251,7 +212,7 @@ static void FOT_ReloadTimer() { if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = ws->model[self.owner.weaponmode]; + self.owner.weaponmodel = ((ws->wi)->models)->mode[self.owner.weaponmode]; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); @@ -410,6 +371,12 @@ void FO_Weapons_Init() { wi->needs_reload = FALSE; wi->storage_index = -1; // Make sure we'll OOB. } + + FO_WeapModels* wm = &weapon_models[i]; + for (j = 0; j < 2; j++) + if (wm->mode[j] != "") + precache_model(wm->mode[j]); + wi->models = wm; } if (clips_allocated > CLIP_STORAGE_SIZE) error("Insufficient clip storage"); From e5823587b8c1d2af105b32b44f35e9dd280e92ad Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 14:49:07 -0700 Subject: [PATCH 1666/2474] Disable auto-assword quad code. This is locking players out with password set, while there are known interactions with 'reconnect', this also seems to include 'disconnect;password;connect'. Only way to rejoin has been to clear the password. Remove for now. --- ssqc/clan.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 82004ed9..5b8ed7d9 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1081,7 +1081,7 @@ float () CheckAllPlayersReady = { StartTimer (); // set default password if no password set - if (infokey(world, "needpass") != "1") { + if (FALSE && infokey(world, "needpass") != "1") { local string default_password = "pineapple"; // maybe this should be configurable cvar_set("password", default_password); localcmd("localinfo default_password on\n"); From e9893384de589d2cdda370ed28fe89d35aa775a8 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 15:11:18 -0700 Subject: [PATCH 1667/2474] Add WEAP_NONE There are a few cases where there's no weapon (e.g. setting detpack) add WEAP_NONE to handle this properly. --- share/defs.h | 1 + share/fo_weapons.qc | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/share/defs.h b/share/defs.h index fef62997..b78b7ea4 100644 --- a/share/defs.h +++ b/share/defs.h @@ -704,6 +704,7 @@ /* New Weapon Defines */ /*======================================================*/ +#define WEAP_NONE 0 enumflags { WEAP_HOOK, WEAP_KNIFE, diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index bd5ca92e..f29409f3 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -32,7 +32,7 @@ static float WEAP_to_index(float weapon) { index += 6; } } - return index - 1; // Want zero-offset. + return index; } enum AmmoType { @@ -64,6 +64,7 @@ struct FO_WeapInfo { // REQUIRES: weapon at index i == WEAP_to_index(weap) // -ve values are placeholders signifying conditional init based on game modes. FO_WeapInfo weapon_info[] = { + { WEAP_NONE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_MEDIKIT, AMMO_NONE, 0, 0, 0.5, 0 }, @@ -81,7 +82,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0, 4 }, { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, - { WEAP_DETPACK, AMMO_NONE, 0, 0, -1, 0 }, + { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, }; @@ -113,10 +114,11 @@ inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { - "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", "Sniper Rifle", - "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", "Grenade Launcher", - "Flamethrower", "Rocket Launcher", "Incendiary Launcher", "Assault Cannon", - "Lightning Gun", "Detpack", "Tranquilizer", "Railgun" + "None", "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", + "Sniper Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", + "Grenade Launcher", "Flamethrower", "Rocket Launcher", + "Incendiary Launcher", "Assault Cannon", "Lightning Gun", "Detpack", + "Tranquilizer", "Railgun" }; inline string FO_GetWeapName(float weapon) { @@ -156,13 +158,14 @@ static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; static float* AMMO_to_p(entity player, AmmoType ammo_type) { switch (ammo_type) { - case AMMO_NONE: return __NULL__; case AMMO_SHELLS: return &player.ammo_shells; case AMMO_CELLS: return &player.ammo_cells; case AMMO_NAILS: return &player.ammo_nails; case AMMO_ROCKETS: return &player.ammo_rockets; + default: + case AMMO_NONE: + return __NULL__; } - error(sprintf("UNK AMMO_TYPE=%d\n", ammo_type)); return __NULL__; } @@ -361,8 +364,7 @@ void FO_Weapons_Init() { if (wi->clip_size > 0) { - if (wi->clip_size > 0) - wi->needs_reload = TRUE; + wi->needs_reload = TRUE; // We always allocate a storage index for something that can have // reload to save negotiating between client and server around // localinfo tunables. From e4077b239e3a679d77caf23840865ef0e84cf545 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 16:15:06 -0700 Subject: [PATCH 1668/2474] Add WEAP_NONE placeholders to other tables --- share/fo_weapons.qc | 47 ++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index f29409f3..140f1d01 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -126,31 +126,33 @@ inline string FO_GetWeapName(float weapon) { } struct FO_WeapModels { + int weapon; string mode[2]; }; // Indexed by WEAP_to_index() and player.weaponmode static FO_WeapModels weapon_models[] = { -/* WEAP_HOOK, */ {{"progs/v_grap.mdl" }}, -/* WEAP_KNIFE, */ {{"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, -/* WEAP_MEDIKIT, */ {{"progs/v_medi.mdl"}}, -/* WEAP_SPANNER, */ {{"progs/v_span.mdl"}}, -/* WEAP_AXE, */ {{"progs/v_axe.mdl"}}, -/* WEAP_SNIPER_RIFLE, */ {{"progs/v_srifle.mdl"}}, -/* WEAP_AUTO_RIFLE, */ {{"progs/v_srifle.mdl"}}, -/* WEAP_SHOTGUN, */ {{"progs/v_shot.mdl"}}, -/* WEAP_SUPER_SHOTGUN, */ {{"progs/v_shot2.mdl"}}, -/* WEAP_NAILGUN, */ {{"progs/v_nail.mdl"}}, -/* WEAP_SUPER_NAILGUN, */ {{"progs/v_nail2.mdl"}}, -/* WEAP_GRENADE_LAUNCHER, */ {{"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, -/* WEAP_FLAMETHROWER, */ {{"progs/v_flame.mdl"}}, -/* WEAP_ROCKET_LAUNCHER, */ {{"progs/v_rock2.mdl"}}, -/* WEAP_INCENDIARY, */ {{"progs/v_irock.mdl"}}, -/* WEAP_ASSAULT_CANNON, */ {{"progs/v_asscan.mdl"}}, -/* WEAP_LIGHTNING, */ {{}}, -/* WEAP_DETPACK, */ {{}}, -/* WEAP_TRANQ, */ {{"progs/v_tranq.mdl"}}, -/* WEAP_RAILGUN, */ {{"progs/v_rail.mdl"}}, + { WEAP_NONE, {""}}, + { WEAP_HOOK, {"progs/v_grap.mdl" }}, + { WEAP_KNIFE, {"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, + { WEAP_MEDIKIT, {"progs/v_medi.mdl"}}, + { WEAP_SPANNER, {"progs/v_span.mdl"}}, + { WEAP_AXE, {"progs/v_axe.mdl"}}, + { WEAP_SNIPER_RIFLE, {"progs/v_srifle.mdl"}}, + { WEAP_AUTO_RIFLE, {"progs/v_srifle.mdl"}}, + { WEAP_SHOTGUN, {"progs/v_shot.mdl"}}, + { WEAP_SUPER_SHOTGUN, {"progs/v_shot2.mdl"}}, + { WEAP_NAILGUN, {"progs/v_nail.mdl"}}, + { WEAP_SUPER_NAILGUN, {"progs/v_nail2.mdl"}}, + { WEAP_GRENADE_LAUNCHER, {"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, + { WEAP_FLAMETHROWER, {"progs/v_flame.mdl"}}, + { WEAP_ROCKET_LAUNCHER, {"progs/v_rock2.mdl"}}, + { WEAP_INCENDIARY, {"progs/v_irock.mdl"}}, + { WEAP_ASSAULT_CANNON, {"progs/v_asscan.mdl"}}, + { WEAP_LIGHTNING, {""}}, + { WEAP_DETPACK, {""}}, + { WEAP_TRANQ, {"progs/v_tranq.mdl"}}, + { WEAP_RAILGUN, {"progs/v_rail.mdl"}}, }; // REQUIRES: Order must match above. @@ -360,8 +362,7 @@ void FO_Weapons_Init() { for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; if (WEAP_to_index(wi->weapon) != i) - error(sprintf("Mismatch at index %d\n", i)); - + error(sprintf("WI mismatch at index %d\n", i)); if (wi->clip_size > 0) { wi->needs_reload = TRUE; @@ -375,6 +376,8 @@ void FO_Weapons_Init() { } FO_WeapModels* wm = &weapon_models[i]; + if (WEAP_to_index(wm->weapon) != i) + error(sprintf("WM mismatch at index %d\n", i)); for (j = 0; j < 2; j++) if (wm->mode[j] != "") precache_model(wm->mode[j]); From 7ebc5bed27a541008066cdb933315dcc5c3da611 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 13:39:50 -0700 Subject: [PATCH 1669/2474] Remove old medikit Adds complexity no longer worth maintaining. --- ssqc/actions.qc | 13 ++----------- ssqc/client.qc | 5 ----- ssqc/engineer.qc | 3 --- ssqc/medic.qc | 14 +++----------- ssqc/qw.qc | 1 - ssqc/tfort.qc | 1 - ssqc/weapons.qc | 39 +++------------------------------------ 7 files changed, 8 insertions(+), 68 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 21e773ba..ce0a410e 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -34,14 +34,8 @@ void () TeamFortress_Discard = { break; case PC_MEDIC: newmis.ammo_rockets = self.ammo_rockets; - if (!medicaura && old_medikit) { - newmis.ammo_cells = self.ammo_cells; - } - else - { - if(c > 0) - newmis.ammo_cells = c; - } + if(c > 0) + newmis.ammo_cells = c; break; case PC_SNIPER: newmis.ammo_rockets = self.ammo_rockets; @@ -135,9 +129,6 @@ void () TeamFortress_Discard_DropAmmo = { break; case PC_MEDIC: disc = self.ammo_rockets; - if (!medicaura && old_medikit) { - disc += self.ammo_cells; - } break; case PC_SNIPER: case PC_SPY: diff --git a/ssqc/client.qc b/ssqc/client.qc index 07d2579b..3e613e0c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -483,9 +483,6 @@ void () DecodeLevelParms = { // allow medic aura [on] medicaura = CF_GetSetting("ma", "medicaura", "on"); - // use old tf style medikit (don't insta-heal max+50) [off] - old_medikit = CF_GetSetting("om", "old_medikit", "off"); - // use old tf style bioweapon (less damage) [off] old_biodamage = CF_GetSetting("ob", "old_biodamage", "off"); @@ -867,7 +864,6 @@ void () DecodeLevelParms = { detpipe_limit_world = -1; old_pipecooldown = FALSE; medicaura = TRUE; - old_medikit = FALSE; old_biodamage = FALSE; cannon_lock = TRUE; cannon_air = TRUE; @@ -947,7 +943,6 @@ void () DecodeLevelParms = { detpipe_limit_world = 7; old_pipecooldown = TRUE; medicaura = FALSE; - old_medikit = TRUE; old_biodamage = TRUE; cannon_lock = FALSE; cannon_air = TRUE; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f63b7bdc..a254b3f0 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -261,9 +261,6 @@ void () EMPGrenadeExplode = { break; case PC_MEDIC: expsize = expsize - te.maxammo_rockets * .75 * 2; - if (!medicaura && old_medikit) { - expsize = expsize - te.maxammo_cells * .75; - } break; case PC_SNIPER: case PC_SPY: diff --git a/ssqc/medic.qc b/ssqc/medic.qc index 17dd697b..4e9d5344 100644 --- a/ssqc/medic.qc +++ b/ssqc/medic.qc @@ -73,7 +73,7 @@ void () CF_Medic_AuraFindPlayers = { } self.owner.ammo_cells = self.owner.ammo_cells - ceil(PC_MEDIC_MAXAMMO_CELL / 20); - if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) + if (self.owner.current_weapon == WEAP_MEDIKIT) self.owner.currentammo = self.owner.ammo_cells; }; @@ -83,10 +83,6 @@ void () CF_Medic_RegenerateCells = { local entity oldself; local float f_newcells = self.owner.ammo_cells + min(ceil(PC_MEDIC_MAXAMMO_CELL * (PC_MEDIC_CELL_REGEN_PERCENT / 100)), ceil(PC_MEDIC_MAXAMMO_CELL - self.owner.ammo_cells)); - // don't regenerate cells if not using aura or new medikit - if (!medicaura && old_medikit) - return; - // skip this regen tick if on cooldown if (time <= self.owner.regen_cooldown) { self.nextthink = time + 1; @@ -104,7 +100,7 @@ void () CF_Medic_RegenerateCells = { else if (f_newcells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2) && f_newcells < ceil(PC_MEDIC_MAXAMMO_CELL / 2 + PC_MEDIC_MAXAMMO_CELL / 10)) Status_Refresh(self.owner); - if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) + if (self.owner.current_weapon == WEAP_MEDIKIT) self.owner.currentammo = self.owner.ammo_cells; } @@ -128,11 +124,7 @@ void () CF_Medic_Regenerate = { } // only regen if half of max or more cells with new medikit - if (!old_medikit) { - if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { - return; - } - } else if (self.owner.health >= self.owner.max_health || self.owner.ammo_medikit) { + if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { return; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index b81e88da..f5c4354e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -568,7 +568,6 @@ float old_sniperrange; float detpipe_limit_world; float old_pipecooldown; float medicaura; -float old_medikit; float old_biodamage; float flame_knockback; float build_water; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 57fcbf05..f8354d90 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -731,7 +731,6 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "\n== Combat Medic ==\n"); CF_PrintSetting("Medic aura ability", medicaura, "", 1); - CF_PrintSetting("Old medikit behaviour", old_medikit, "", 1); CF_PrintSetting("Old bioweapon damage", old_sniperrange, "", 1); sprint(self, PRINT_HIGH, "\n== Heavy Weapons Guy ==\n"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e5da4b83..914586df 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -563,37 +563,7 @@ float () W_FireMedikit = { } return TRUE; } - if (old_medikit) { - - if (healam > 0 && trace_ent.health < trace_ent.max_health) { - - FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); - trace_ent.axhitme = 1; - SpawnBlood(org, 20); - T_Heal(trace_ent, healam, 0); - - } else if (trace_ent.health >= trace_ent.max_health && trace_ent.health < (trace_ent.max_health + 50)) { - - healam = 5; - if (healam > (self.ammo_medikit * 5)) - healam = self.ammo_medikit * 5; - - if (healam > 0) { - FO_Sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); - T_Heal(trace_ent, healam, 1); - self.ammo_medikit = self.ammo_medikit - rint(healam / 5); - - if (!(trace_ent.items & IT_SUPERHEALTH)) { - trace_ent.items = trace_ent.items | IT_SUPERHEALTH; - newmis = spawn(); - newmis.nextthink = time + 5; - newmis.think = item_megahealth_rot; - newmis.owner = trace_ent; - } - } - } - - } else if (trace_ent.health < (trace_ent.max_health + 50)) { + if (trace_ent.health < (trace_ent.max_health + 50)) { if (self.ammo_cells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { healam = trace_ent.max_health - trace_ent.health + 50; @@ -1722,11 +1692,8 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_MEDIKIT) { - if (!old_medikit) { - pl.currentammo = pl.ammo_cells; - pl.items = pl.items | IT_CELLS; - } else - pl.currentammo = 0; + pl.currentammo = pl.ammo_cells; + pl.items = pl.items | IT_CELLS; pl.weaponmodel = "progs/v_medi.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_TRANQ) { From 0d36e05e9885fc1aa5a07b32625febffb5b58f62 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 13:37:25 -0700 Subject: [PATCH 1670/2474] Eliminate currentammo Current ammo is a bit of a kludge that tries to copy the current ammo into a singly named accessor. We have WeapState for this now so we can get rid of it. This also fixes cells not showing up for bioaxe/spanner. --- share/fo_weapons.qc | 4 ++-- ssqc/actions.qc | 1 - ssqc/client.qc | 14 ++++++++++++-- ssqc/defs.qc | 1 - ssqc/demoman.qc | 2 -- ssqc/engineer.qc | 12 ------------ ssqc/items.qc | 5 ----- ssqc/medic.qc | 5 ----- ssqc/menu.qc | 5 ----- ssqc/player.qc | 1 - ssqc/pyro.qc | 5 ----- ssqc/scout.qc | 4 ---- ssqc/spy.qc | 2 -- ssqc/tfort.qc | 5 ----- ssqc/tfortmap.qc | 2 -- ssqc/vote.qc | 2 -- ssqc/weapons.qc | 47 ++++++++------------------------------------- 17 files changed, 22 insertions(+), 95 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 140f1d01..16fe3928 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -67,8 +67,8 @@ FO_WeapInfo weapon_info[] = { { WEAP_NONE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_MEDIKIT, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_SPANNER, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_MEDIKIT, AMMO_CELLS, 0, 0, 0.5, 0 }, + { WEAP_SPANNER, AMMO_CELLS, 0, 0, 0.5, 0 }, { WEAP_AXE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_SNIPER_RIFLE, AMMO_SHELLS, -9, 1, 1.5, 4 }, { WEAP_AUTO_RIFLE, AMMO_SHELLS, 0, 1, 0.1, 0 }, diff --git a/ssqc/actions.qc b/ssqc/actions.qc index ce0a410e..c973f451 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -86,7 +86,6 @@ void () TeamFortress_Discard = { else self.ammo_cells = 0; } - W_SetCurrentAmmo(self); FO_Sound(self, CHAN_AUTO, "weapons/lock4.wav", 1, ATTN_NORM); newmis.enemy = self; newmis.health = time; diff --git a/ssqc/client.qc b/ssqc/client.qc index 3e613e0c..f813f337 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2192,7 +2192,6 @@ void () PutClientInServer = { stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - W_SetCurrentAmmo(self); if (self.current_weaponslot && self.last_playerclass == self.playerclass) W_ChangeWeapon(self.current_weaponslot); else { @@ -2779,11 +2778,15 @@ void () PlayerPreThink = { if ((time < self.pausetime) || (cease_fire == 1)) { self.velocity = '0 0 0'; } + +#if 0 + FO_WeapState ws; + FO_FillWeapState(self, self.weapon, &ws); if (time > self.attack_finished && !self.currentammo && self.weapon > WEAP_AXE) { W_ChangeWeapon(W_BestWeaponSlot()); - W_SetCurrentAmmo(self); W_WeaponState_Save(self); } +#endif }; void () CheckPowerups = { @@ -2949,11 +2952,18 @@ void () CheckPowerups = { } }; +void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws); + void () PlayerPostThink = { UpdateScoreboardInfo(self); FOPlayer fop = (FOPlayer)self; fop.RewindUpdate(); + FO_WeapState ws; + FO_FillWeapState(self, self.current_weapon, &ws); + self.currentammo = + (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; + if (self.view_ofs == '0 0 0') { return; } diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 86a566c2..66a6410a 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -119,7 +119,6 @@ void end_sys_globals; .float weapon; .string weaponmodel; .float weaponframe; -.float currentammo; .float ammo_shells, ammo_nails, ammo_rockets, ammo_cells; .float items; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 87782c59..954dd26b 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -270,7 +270,6 @@ void () TeamFortress_DetpackStop = { self.current_weapon = self.next_weapon; Status_Refresh(self); - W_SetCurrentAmmo(self); TeamFortress_SetSpeed(self); self.pausetime = time; }; @@ -296,7 +295,6 @@ void () TeamFortress_DetpackSet = { self.is_detpacking = 0; self.current_weapon = self.next_weapon; Status_Refresh(self); - W_SetCurrentAmmo(self); self = oldself; newmis = spawn(); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index a254b3f0..7ea37512 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -82,7 +82,6 @@ void () W_FireLaser = { local vector vec, org; self.ammo_nails = self.ammo_nails - 1; - self.currentammo = self.ammo_nails; makevectors(self.v_angle); org = self.origin + v_forward * 8; @@ -300,7 +299,6 @@ void () EMPGrenadeExplode = { } oldself = self; self = te; - W_SetCurrentAmmo(self); self = oldself; } else { te.think = SUB_Remove; @@ -408,7 +406,6 @@ void () TeamFortress_EngineerBuildStop = { self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_WALK; TeamFortress_SetSpeed(self); - W_SetCurrentAmmo(self); } } @@ -605,7 +602,6 @@ void (float objtobuild) TeamFortress_Build = { newmis.classname = "building_sentrygun"; newmis.weapon = 0; } - W_SetCurrentAmmo(self); } oldmis = newmis; @@ -1023,7 +1019,6 @@ void () TeamFortress_FinishedBuilding = { UpdateClient_Sentry(self, oldself); } } - W_SetCurrentAmmo(self); self = oldself; }; @@ -1105,7 +1100,6 @@ void (entity disp) Engineer_UseDispenser = { ThrowGib("progs/dgib1.mdl", -30); ThrowGib("progs/dgib2.mdl", -50); ThrowGib("progs/dgib3.mdl", -50); - W_SetCurrentAmmo(self); return; } @@ -1115,7 +1109,6 @@ void (entity disp) Engineer_UseDispenser = { self.ammo_cells = self.ammo_cells + ENG_DISPENSER_COST; if (self.ammo_cells > self.maxammo_cells) self.ammo_cells = self.maxammo_cells; - W_SetCurrentAmmo(self); self = disp.real_owner; TeamFortress_EngineerBuildStop(); return; @@ -1190,7 +1183,6 @@ void (entity disp) Engineer_Dispenser_InsertAmmo = { disp.ammo_cells = (disp.ammo_cells + cells); if ((shells + nails + rockets + cells) > 0) { - W_SetCurrentAmmo(self); sprint(self, PRINT_HIGH, "You insert "); if (shells > 0) sprint(self, PRINT_HIGH, ftos(shells), " shells"); @@ -1292,7 +1284,6 @@ void (entity gun) Engineer_UseSentryGun = { self.ammo_cells = self.maxammo_cells; if (gun.trigger_field != world) dremove (gun.trigger_field); - W_SetCurrentAmmo(self); self = gun.real_owner; TeamFortress_EngineerBuildStop(); return; @@ -1311,7 +1302,6 @@ void (entity gun) Engineer_UseSentryGun = { ThrowGib("progs/tgib1.mdl", -30); ThrowGib("progs/tgib2.mdl", -50); ThrowGib("progs/tgib3.mdl", -50); - W_SetCurrentAmmo(self); return; } } @@ -1382,7 +1372,6 @@ void (entity gun) Engineer_SentryGun_InsertAmmo = { } if ((shells + rockets) > 0) { - W_SetCurrentAmmo(self); ammo = "You insert "; if (shells > 0) ammo = strcat(ammo, strcat(ftos(floor(shells)), " shells")); @@ -1483,7 +1472,6 @@ void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { self = eng; self.ammo_cells = self.ammo_cells + 100; bound_other_ammo(self); - W_SetCurrentAmmo(self); self = oldself; } if (te.real_owner.building == te) { diff --git a/ssqc/items.qc b/ssqc/items.qc index 068981c9..a9cfc7d7 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -262,7 +262,6 @@ void () health_touch = { self.think = SUB_regen; } activator = other; - W_SetCurrentAmmo(self); SUB_UseTargets(); } } @@ -398,7 +397,6 @@ void () armor_touch = { } oldself = self; self = other; - W_SetCurrentAmmo(self); self = oldself; } value = other.maxarmor; @@ -644,7 +642,6 @@ void () weapon_touch = { stemp = self; self = other; Deathmatch_Weapon(old, new); - W_SetCurrentAmmo(self); self = stemp; if (leave) return; @@ -879,7 +876,6 @@ void () ammo_touch = { sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); stemp = self; self = other; - W_SetCurrentAmmo(self); self = stemp; } Respawn_Item(self, other); @@ -1347,7 +1343,6 @@ void () BackpackTouch = { stuffcmd(other, "bf\n"); dremove(self); self = other; - W_SetCurrentAmmo(self); }; void () DropBackpack = { diff --git a/ssqc/medic.qc b/ssqc/medic.qc index 4e9d5344..af64b495 100644 --- a/ssqc/medic.qc +++ b/ssqc/medic.qc @@ -73,8 +73,6 @@ void () CF_Medic_AuraFindPlayers = { } self.owner.ammo_cells = self.owner.ammo_cells - ceil(PC_MEDIC_MAXAMMO_CELL / 20); - if (self.owner.current_weapon == WEAP_MEDIKIT) - self.owner.currentammo = self.owner.ammo_cells; }; // increases the medic's cells two times per second @@ -99,9 +97,6 @@ void () CF_Medic_RegenerateCells = { Status_Refresh(self.owner); else if (f_newcells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2) && f_newcells < ceil(PC_MEDIC_MAXAMMO_CELL / 2 + PC_MEDIC_MAXAMMO_CELL / 10)) Status_Refresh(self.owner); - - if (self.owner.current_weapon == WEAP_MEDIKIT) - self.owner.currentammo = self.owner.ammo_cells; } // Update drop ammo menu if cells are diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 7df35e38..c7748ba4 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -52,8 +52,6 @@ void () TeamFortress_EngineerBuildStop; void (entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage; -void (entity pl) W_SetCurrentAmmo; - void (entity p) bound_other_ammo; float (float v) anglemod; @@ -853,7 +851,6 @@ void (float inp) Menu_Engineer_Input = { dremove (te); self.has_sentry = 0; dismantle_sentrygun = 1; - W_SetCurrentAmmo(self); } } te = te.chain; @@ -872,7 +869,6 @@ void (float inp) Menu_Engineer_Input = { dremove (te); self.has_dispenser = 0; dismantle_dispenser = 1; - W_SetCurrentAmmo(self); } } te = te.chain; @@ -1159,7 +1155,6 @@ void (float inp) Menu_Dispenser_Input = { self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)); } - W_SetCurrentAmmo(self); } }; diff --git a/ssqc/player.qc b/ssqc/player.qc index 2adf5b49..ab5940ae 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -573,7 +573,6 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(self); W_PrintWeaponMessage(); return; } diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index b3a55eca..c09a4c2d 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -548,7 +548,6 @@ void () W_FireFlame = { return; } self.ammo_cells = self.ammo_cells - 1; - self.currentammo = self.ammo_cells; FO_Sound(self, CHAN_AUTO, "weapons/flmfire2.wav", 1, ATTN_NORM); flame = spawn(); flame.owner = self; @@ -673,7 +672,6 @@ void () W_FireIncendiaryCannon = { return; } self.ammo_rockets = self.ammo_rockets - 3; - self.currentammo = self.ammo_rockets; FO_Sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); KickPlayer(-3, self); newmis = spawn(); @@ -722,7 +720,6 @@ void () TeamFortress_IncendiaryCannon = { return; } self.current_weapon = WEAP_INCENDIARY; - W_SetCurrentAmmo(self); }; void () TeamFortress_FlameThrower = { @@ -734,7 +731,6 @@ void () TeamFortress_FlameThrower = { return; } self.current_weapon = WEAP_FLAMETHROWER; - W_SetCurrentAmmo(self); }; void () AirBlastReloadFinished = { @@ -897,7 +893,6 @@ void () UseAirBlastV2 = { } self.ammo_cells = self.ammo_cells - cellcost; - W_SetCurrentAmmo(self); ent = findradius(ab_origin, abrange); while (ent) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 1ef2a762..0d5ce0de 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -564,7 +564,6 @@ void () TeamFortress_Scan = { sprint(self.owner, PRINT_HIGH, "Not enough cells to run scanner\n"); self.owner.ammo_cells = 0; - W_SetCurrentAmmo(self); self.owner.ScannerOn = 0; dremove(self); return; @@ -572,7 +571,6 @@ void () TeamFortress_Scan = { if (scancost > self.owner.ammo_cells) { scanrange = self.owner.ammo_cells * 20; scancost = self.owner.ammo_cells; - W_SetCurrentAmmo(self); } scen = 0; scfr = 0; @@ -592,7 +590,6 @@ void () TeamFortress_Scan = { if (self.owner.ammo_cells < 0) { self.owner.ammo_cells = 0; } - W_SetCurrentAmmo(self); scanrange = scanrange * 25; list = T_RadiusScan(self.owner, scanrange, scen, scfr); } @@ -728,7 +725,6 @@ void () TeamFortress_Scan = { self.nextthink = time + 2; return; } - W_SetCurrentAmmo(self); self.nextthink = time + 2; return; }; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index f4d0197a..a144ca1b 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -604,7 +604,6 @@ void () FO_Spy_Unfeign = { // load saved weapon state and set current ammo W_WeaponState_Load(self, 0); - W_SetCurrentAmmo(self); // allow spy to move again self.movetype = MOVETYPE_WALK; @@ -1381,7 +1380,6 @@ void () HallucinationTimer = { void () W_FireTranq = { self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; KickPlayer(-2, self); newmis = spawn(); newmis.owner = self; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f8354d90..775d6deb 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2326,7 +2326,6 @@ void () TeamFortress_SetEquipment = { else if (self.armortype >= 0.3) self.items = self.items | IT_ARMOR1; - W_SetCurrentAmmo(self); if (self.last_playerclass != self.playerclass) self.current_weaponslot = W_BestWeaponSlot(); }; @@ -2716,7 +2715,6 @@ void (float type, float ammo) TeamFortress_DropAmmo = { } self.ammo_cells = self.ammo_cells - ammo; } - W_SetCurrentAmmo(self); newmis = spawn(); newmis.aflag = ammo; newmis.weapon = type; @@ -2780,7 +2778,6 @@ void () TeamFortress_AmmoboxTouch = { FO_Sound(other, CHAN_AUTO, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); self = other; - W_SetCurrentAmmo(self); return; } else if ((other.playerclass == PC_SCOUT) || (other.playerclass == PC_ENGINEER)) { @@ -2869,7 +2866,6 @@ void () TeamFortress_AmmoboxTouch = { FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); self = other; - W_SetCurrentAmmo(self); }; void () TeamFortress_AssaultWeapon = { @@ -2896,7 +2892,6 @@ void () TeamFortress_AssaultWeapon = { return; } self.current_weapon = WEAP_ASSAULT_CANNON; - W_SetCurrentAmmo(self); }; void () TeamFortress_ExplodePerson = { diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 158f8d2d..d2a52987 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1037,7 +1037,6 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { oldself = self; self = Player; TeamFortress_CheckClassStats(); - W_SetCurrentAmmo(self); self = oldself; } if ((Player.playerclass == PC_SPY) && @@ -1239,7 +1238,6 @@ void (entity Goal, entity Player) RemoveResults = { oldself = self; self = Player; TeamFortress_CheckClassStats(); - W_SetCurrentAmmo(self); self = oldself; }; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index fa1c9a1c..235acaa2 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1238,7 +1238,6 @@ void () AnarchyMode = { e.super_damage_finished = time + 666; //e.effects = e.effects | EF_BLUE; } - W_SetCurrentAmmo(e); TeamFortress_SetSpeed(e); e = find(e, classname, "player"); } @@ -1270,7 +1269,6 @@ void () EndVoting = { e.current_weapon = 0; e.super_damage_finished = 0; //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; - W_SetCurrentAmmo(e); TeamFortress_SetSpeed(e); e.health = 100; e = find(e, classname, "player"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 914586df..def0b222 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -135,6 +135,7 @@ float () IsUsingOldImpulses; float () IsUsingCFImpulses; void (float inp) W_OldWeaponSlot; +void (entity pl) W_UpdateCurrentWeapon; void (entity ent, float num) SetFlameCount; @@ -578,9 +579,6 @@ float () W_FireMedikit = { FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); } - if (self.current_weapon == WEAP_MEDIKIT) - self.currentammo = self.ammo_cells; - Status_Refresh(self); T_Heal(trace_ent, healam, 1); @@ -809,7 +807,6 @@ void () W_FireShotgun = { KickPlayer(-2, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_SHOTGUN; FireBullets(6, dir, '0.04 0.04 0'); @@ -818,7 +815,7 @@ void () W_FireShotgun = { void () W_FireSuperShotgun = { local vector dir; - if (self.currentammo == 1) { + if (self.ammo_shells == 1) { W_FireShotgun(); return; } @@ -826,7 +823,6 @@ void () W_FireSuperShotgun = { KickPlayer(-4, self); self.ammo_shells = self.ammo_shells - 2; - self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_SSHOTGUN; FireBullets(14, dir, '0.14 0.08 0'); @@ -866,7 +862,6 @@ void () W_FireSniperRifle = { FO_Sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); KickPlayer(-2, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; makevectors(self.v_angle); src = self.origin + v_forward * 10; @@ -968,7 +963,6 @@ void () W_FireAutoRifle = { KickPlayer(-1, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; makevectors(self.v_angle); dir = v_forward; deathmsg = DMSG_AUTORIFLE; @@ -981,7 +975,6 @@ void () W_FireAssaultCannon = { KickPlayer(-4, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_ASSAULTCANNON; @@ -1105,7 +1098,6 @@ void () T_MissileTouch = { void () W_FireRocket = { self.ammo_rockets = self.ammo_rockets - 1; - self.currentammo = self.ammo_rockets; FO_Sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); KickPlayer(-2, self); @@ -1192,7 +1184,7 @@ void () W_FireLightning = { if (self.waterlevel > 1) { cells = self.ammo_cells; self.ammo_cells = 0; - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); deathmsg = DMSG_LIGHTNING; T_RadiusDamage(self, self, 35 * cells, world); return; @@ -1204,7 +1196,6 @@ void () W_FireLightning = { KickPlayer(-2, self); self.ammo_cells = self.ammo_cells - 1; - self.currentammo = self.ammo_cells; org = self.origin + '0 0 16'; traceline(org, org + v_forward * 600, 1, self); @@ -1309,7 +1300,6 @@ void () ExplodeOldestPipebomb = { void () W_FireGrenade = { self.ammo_rockets = self.ammo_rockets - 1; - self.currentammo = self.ammo_rockets; FO_Sound(self, CHAN_WEAPON, "weapons/grenade.wav", 1, 1); KickPlayer(-2, self); newmis = spawn(); @@ -1394,7 +1384,6 @@ void () W_FireSuperSpikes = { self.ammo_nails = self.ammo_nails - 4; else self.ammo_nails = self.ammo_nails - 2; - self.currentammo = self.ammo_nails; dir = aim(self, 1000); launch_spike(self.origin + '0 0 16', dir); LogEventAttack(self); @@ -1421,10 +1410,8 @@ void (float ox) W_FireSpikes = { FO_Sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); if ((self.ammo_nails == 1) || !old_ng_rof) { self.ammo_nails = self.ammo_nails - 1; - self.currentammo = self.ammo_nails; } else { self.ammo_nails = self.ammo_nails - 2; - self.currentammo = self.ammo_nails; } dir = aim(self, 1000); launch_spike(self.origin + '0 0 16' + v_right * ox, dir); @@ -1573,7 +1560,7 @@ void () superspike_touch = { dremove(self); }; -void (entity pl) W_SetCurrentAmmo = { +void (entity pl) W_UpdateCurrentWeapon = { entity oldself; if ((pl.health <= 0) || (pl.current_weapon == 0)) @@ -1586,22 +1573,18 @@ void (entity pl) W_SetCurrentAmmo = { pl.weapon = 0; if (pl.current_weapon == WEAP_AXE) { - pl.currentammo = 0; pl.weaponmodel = "progs/v_axe.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_KNIFE) { - pl.currentammo = 0; if (pl.weaponmode == 0) pl.weaponmodel = "progs/v_knife.mdl"; else pl.weaponmodel = "progs/v_knife2.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_SPANNER) { - pl.currentammo = pl.ammo_cells; pl.weaponmodel = "progs/v_span.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_SHOTGUN) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_shot.mdl"; pl.weaponframe = 0; @@ -1609,7 +1592,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_shot2.mdl"; pl.weaponframe = 0; @@ -1617,7 +1599,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SUPER_SHOTGUN; } else if (pl.current_weapon == WEAP_NAILGUN) { - pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_nail.mdl"; pl.weaponframe = 0; @@ -1625,7 +1606,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_NAILS; pl.weapon = IT_NAILGUN; } else if (pl.current_weapon == WEAP_SUPER_NAILGUN) { - pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_nail2.mdl"; pl.weaponframe = 0; @@ -1633,7 +1613,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_NAILS; pl.weapon = IT_SUPER_NAILGUN; } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { - pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { if (pl.weaponmode == 0) pl.weaponmodel = "progs/v_rock.mdl"; @@ -1644,7 +1623,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.weapon = IT_GRENADE_LAUNCHER; pl.items = pl.items | IT_ROCKETS; } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { - pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_rock2.mdl"; pl.weaponframe = 0; @@ -1652,7 +1630,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_srifle.mdl"; pl.weaponframe = 0; @@ -1660,7 +1637,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; } else if (pl.current_weapon == WEAP_AUTO_RIFLE) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_srifle.mdl"; pl.weaponframe = 0; @@ -1668,7 +1644,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SUPER_SHOTGUN; } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_asscan.mdl"; pl.weaponframe = 0; @@ -1676,7 +1651,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_FLAMETHROWER) { - pl.currentammo = pl.ammo_cells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_flame.mdl"; pl.weaponframe = 0; @@ -1684,7 +1658,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_CELLS; pl.weapon = IT_GRENADE_LAUNCHER; } else if (pl.current_weapon == WEAP_INCENDIARY) { - pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_irock.mdl"; pl.weaponframe = 0; @@ -1692,12 +1665,10 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_MEDIKIT) { - pl.currentammo = pl.ammo_cells; pl.items = pl.items | IT_CELLS; pl.weaponmodel = "progs/v_medi.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_TRANQ) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_tranq.mdl"; pl.weaponframe = 0; @@ -1705,7 +1676,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; } else if (pl.current_weapon == WEAP_RAILGUN) { - pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_rail.mdl"; pl.weaponframe = 0; @@ -1713,7 +1683,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_NAILS; pl.weapon = IT_SHOTGUN; } else { - pl.currentammo = 0; pl.weaponmodel = ""; pl.weaponframe = 0; } @@ -1801,7 +1770,7 @@ void () W_ChangeToBestWeapon = { self.current_weaponslot = slot; self.current_weapon = self.next_weapon; self.weaponmode = self.next_weaponmode; - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); W_WeaponState_Save(self); W_PrintWeaponMessage(); } @@ -1921,7 +1890,7 @@ void () W_Attack = { self.antispam_assault_cannon = time + 3; } W_ChangeWeapon(W_BestWeaponSlot()); - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); W_WeaponState_Save(self); } else { self.ammo_cells = self.ammo_cells - 7; @@ -2582,7 +2551,7 @@ void (entity pl, float swap) W_WeaponState_Load = { pl.queue_weaponstate = 0; W_WeaponState_Save(pl); - W_SetCurrentAmmo(pl); + W_UpdateCurrentWeapon(pl); Status_Refresh(pl); } @@ -2654,7 +2623,7 @@ void (float inp) W_ChangeWeapon = { if (!self.is_quickfiring && !self.has_quickfired) W_WeaponState_Save(self); - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); Status_Refresh(self); self.queue_weaponslot = 0; }; From 0f2df3c75f00a3eae69da92c987bffabd310784c Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 13:03:57 -0700 Subject: [PATCH 1671/2474] Simplify item interaction --- share/fo_weapons.qc | 60 +++++++++++++++++++- ssqc/client.qc | 15 ++--- ssqc/engineer.qc | 2 +- ssqc/menu.qc | 4 +- ssqc/tfort.qc | 53 +----------------- ssqc/vote.qc | 1 - ssqc/weapons.qc | 131 +++----------------------------------------- 7 files changed, 78 insertions(+), 188 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 16fe3928..1fcf91fd 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -45,6 +45,7 @@ enum AmmoType { }; struct FO_WeapModels; +struct FO_WeapToItem; struct FO_WeapInfo { int weapon; // Verification @@ -59,6 +60,7 @@ struct FO_WeapInfo { float needs_reload; int storage_index; // Allocated by init FO_WeapModels* models; + FO_WeapToItem* items; }; // REQUIRES: weapon at index i == WEAP_to_index(weap) @@ -95,7 +97,7 @@ struct FO_ClassWeapons { // Indexed by class ID, e.g. PC_SOLDIER FO_ClassWeapons class_weapons[] = { - { PC_UNDEFINED, { 0, 0, 0, 0 } }, + { PC_UNDEFINED, { 0, 0, 0, WEAP_AXE } }, { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, @@ -105,6 +107,7 @@ FO_ClassWeapons class_weapons[] = { { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, + { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { @@ -182,6 +185,47 @@ float WEAP_to_slot(float class, float weapon) { #define CLIP_STORAGE_SIZE 8 .float clip_fired[CLIP_STORAGE_SIZE]; +struct FO_WeapToItem { + int weapon; + float it_weapon; + + // Fields below this line automatically populated. + float ammo_mask; +}; + +FO_WeapToItem weapon_to_items[] = { + { WEAP_NONE, 0}, + { WEAP_HOOK, IT_HOOK}, + { WEAP_KNIFE, 0}, + { WEAP_MEDIKIT, 0}, + { WEAP_SPANNER, 0}, + { WEAP_AXE, 0}, + { WEAP_SNIPER_RIFLE, IT_SHOTGUN}, + { WEAP_AUTO_RIFLE, IT_SUPER_SHOTGUN}, + { WEAP_SHOTGUN, IT_SHOTGUN}, + { WEAP_SUPER_SHOTGUN, IT_SUPER_SHOTGUN}, + { WEAP_NAILGUN, IT_NAILGUN}, + { WEAP_SUPER_NAILGUN, IT_SUPER_NAILGUN}, + { WEAP_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER}, + { WEAP_FLAMETHROWER, IT_GRENADE_LAUNCHER}, + { WEAP_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER}, + { WEAP_INCENDIARY, IT_ROCKET_LAUNCHER}, + { WEAP_ASSAULT_CANNON, IT_ROCKET_LAUNCHER}, + { WEAP_LIGHTNING, IT_LIGHTNING}, + { WEAP_DETPACK, 0}, + { WEAP_TRANQ, IT_SHOTGUN}, + { WEAP_RAILGUN, IT_SHOTGUN}, +}; + +float FO_ClassWeaponItemMask(float class) { + float mask = 0; + for (float i = 0; i < 4; i++) { + FO_WeapInfo* wi = class_weapons[class].info[i]; + mask |= wi ? (wi->items)->it_weapon : 0; + } + return mask; +} + #ifdef SSQC struct FO_WeapState { float weapon; @@ -378,11 +422,23 @@ void FO_Weapons_Init() { FO_WeapModels* wm = &weapon_models[i]; if (WEAP_to_index(wm->weapon) != i) error(sprintf("WM mismatch at index %d\n", i)); + for (j = 0; j < 2; j++) if (wm->mode[j] != "") precache_model(wm->mode[j]); wi->models = wm; - } + + FO_WeapToItem* wti = &weapon_to_items[i]; + if (WEAP_to_index(wti->weapon) != i) + error(sprintf("WTI mismatch at index %d\n", i)); + wi->items = wti; + switch (wi->ammo_type) { + case AMMO_SHELLS: wti->ammo_mask = IT_SHELLS; break; + case AMMO_CELLS: wti->ammo_mask = IT_CELLS; break; + case AMMO_NAILS: wti->ammo_mask = IT_NAILS; break; + case AMMO_ROCKETS: wti->ammo_mask = IT_ROCKETS; break; + } +} if (clips_allocated > CLIP_STORAGE_SIZE) error("Insufficient clip storage"); diff --git a/ssqc/client.qc b/ssqc/client.qc index f813f337..dd909ac1 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -100,11 +100,8 @@ void () SetChangeParms = { SetNewParms(); return; } - self.items = - self.items - - (self. - items & (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY - | IT_SUIT | IT_QUAD)); + self.items &= ~(IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | + IT_SUIT | IT_QUAD); if (self.health > 100) self.health = 100; if (self.health < 50) @@ -2827,7 +2824,7 @@ void () CheckPowerups = { } } if (self.invisible_finished < time) { - self.items = self.items - IT_INVISIBILITY; + self.items &= ~IT_INVISIBILITY; self.invisible_finished = 0; self.invisible_time = 0; } @@ -2858,7 +2855,7 @@ void () CheckPowerups = { } } if (self.invincible_finished < time) { - self.items = self.items - 1048576; + self.items &= ~IT_INVULNERABILITY; self.invincible_time = 0; self.invincible_finished = 0; } @@ -2901,7 +2898,7 @@ void () CheckPowerups = { } } if (self.super_damage_finished < time) { - self.items = self.items - IT_QUAD; + self.items &= ~IT_QUAD; self.super_damage_finished = 0; self.super_time = 0; } @@ -2945,7 +2942,7 @@ void () CheckPowerups = { } } if (self.radsuit_finished < time) { - self.items = self.items - 2097152; + self.items &= ~IT_SUIT; self.rad_time = 0; self.radsuit_finished = 0; } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 7ea37512..8080473a 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1225,7 +1225,7 @@ void (entity disp) Engineer_Dispenser_InsertArmor = { if (self.armorvalue == 0) { self.armortype = 0; self.armorclass = 0; - self.items = (self.items - (self.items & ((IT_ARMOR1 | IT_ARMOR2) | IT_ARMOR3))); + self.items &= ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3); } if (armor > 0) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index c7748ba4..a865ef1f 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1151,9 +1151,7 @@ void (float inp) Menu_Dispenser_Input = { if (self.armorvalue == 0) { self.armortype = 0; self.armorclass = 0; - self.items = - self.items - - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)); + self.items &= ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3); } } }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 775d6deb..8dc90bb4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1566,8 +1566,8 @@ void () TeamFortress_SetEquipment = { Team_Role * role = GetTeamRole(self.team_no); kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); + self.items = FO_ClassWeaponItemMask(self.playerclass) | kept_items; - self.items = 0; self.weapons_carried = 0; if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; @@ -1616,7 +1616,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_medikit = 0; self.ammo_detpack = 0; self.maxammo_detpack = 0; - self.items_allowed = 0; self.armor_allowed = 0; self.maxarmor = 0; self.respawn_time = 0; @@ -1626,8 +1625,6 @@ void () TeamFortress_SetEquipment = { if (self.team_no == 0) self.lives = -1; - self.items = self.items | kept_items; - if (self.playerclass == PC_SCOUT) { self.weapons_carried = self.weapons_carried | PC_SCOUT_WEAPONS; @@ -1691,10 +1688,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_SCOUT_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_NAILGUN; - - self.items_allowed = PC_SCOUT_WEAPONS; - - self.items = self.items | IT_SHOTGUN | IT_NAILGUN; } else if (self.playerclass == PC_SNIPER) { self.weapons_carried = self.weapons_carried | PC_SNIPER_WEAPONS; @@ -1749,10 +1742,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_SNIPER_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SNIPER_RIFLE; - - self.items_allowed = PC_SNIPER_WEAPONS; - self.items = - self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN; } else if (self.playerclass == PC_SOLDIER) { self.weapons_carried = self.weapons_carried | PC_SOLDIER_WEAPONS; @@ -1819,11 +1808,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_SOLDIER_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_ROCKET_LAUNCHER; - - self.items_allowed = PC_SOLDIER_WEAPONS; - self.items = - self. - items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_DEMOMAN) { self.weapons_carried = self.weapons_carried | PC_DEMOMAN_WEAPONS; @@ -1881,9 +1865,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_DEMOMAN_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_GRENADE_LAUNCHER; - - self.items_allowed = PC_DEMOMAN_WEAPONS; - self.items = self.items | IT_SHOTGUN | IT_GRENADE_LAUNCHER; } else if (self.playerclass == PC_MEDIC) { self.weapons_carried = self.weapons_carried | PC_MEDIC_WEAPONS; @@ -1964,10 +1945,6 @@ void () TeamFortress_SetEquipment = { te.think = CF_Medic_AuraFindPlayers; te.owner = self; te.classname = "timer"; - - self.items_allowed = PC_MEDIC_WEAPONS; - self.items = - self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_SUPER_NAILGUN; } else if (self.playerclass == PC_HVYWEAP) { self.weapons_carried = self.weapons_carried | PC_HVYWEAP_WEAPONS; @@ -2016,7 +1993,6 @@ void () TeamFortress_SetEquipment = { self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1; self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2; - self.tf_items = PC_HVYWEAP_TF_ITEMS; self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS; self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE; @@ -2029,11 +2005,6 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SUPER_SHOTGUN; - - self.items_allowed = PC_HVYWEAP_WEAPONS; - self.items = - self. - items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_PYRO) { self.weapons_carried = self.weapons_carried | PC_PYRO_WEAPONS; @@ -2078,7 +2049,6 @@ void () TeamFortress_SetEquipment = { self.tp_grenades_1 = PC_PYRO_GRENADE_TYPE_1; self.tp_grenades_2 = PC_PYRO_GRENADE_TYPE_2; - self.tf_items = PC_PYRO_TF_ITEMS; self.armorclass = self.armorclass | PC_PYRO_INITARMORCLASS; self.armor_allowed = PC_PYRO_MAXARMORTYPE; @@ -2088,11 +2058,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_PYRO_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_FLAMETHROWER; - - self.items_allowed = PC_PYRO_WEAPONS; - self.items = - self. - items | IT_SHOTGUN | IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_CIVILIAN) { self.weapons_carried = self.weapons_carried | PC_CIVILIAN_WEAPONS; @@ -2147,9 +2112,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_CIVILIAN_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_AXE; - - self.items_allowed = PC_CIVILIAN_WEAPONS; - self.items = 0; } else if (self.playerclass == PC_SPY) { self.weapons_carried = self.weapons_carried | PC_SPY_WEAPONS; @@ -2207,10 +2169,6 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_TRANQ; - self.items_allowed = PC_SPY_WEAPONS; - self.items = - self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN; - if (invis_only == 1) { te = spawn(); te.nextthink = time + PC_SPY_CELL_REGEN_TIME; @@ -2274,10 +2232,7 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_RAILGUN; - self.items_allowed = PC_ENGINEER_WEAPONS; - self.items = self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN; } else if (self.playerclass == PC_UNDEFINED) { - self.items = 0; self.ammo_rockets = 0; self.ammo_nails = 0; self.ammo_shells = 0; @@ -2350,7 +2305,7 @@ float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { }; float (entity Retriever, float WeaponType) TeamFortress_CanGetWeapon = { - if (Retriever.items_allowed & WeaponType) + if (Retriever.items & WeaponType) return TRUE; return FALSE; @@ -3146,9 +3101,7 @@ void () TeamFortress_RegenerateCells = { if (self.owner.ammo_cells == 0) { self.owner.is_undercover = 0; self.owner.modelindex = modelindex_player; - self.owner.items = - self.owner.items - - (self.owner.items & IT_INVISIBILITY); + self.owner.items &= ~IT_INVISIBILITY; } else { self.owner.ammo_cells = self.owner.ammo_cells - PC_SPY_CELL_USAGE; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 235acaa2..22a652a0 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1228,7 +1228,6 @@ void () AnarchyMode = { vote_anarchy_mode = TRUE; local entity e = find(world, classname, "player"); while(e) { - e.items_allowed = IT_AXE | IT_QUAD; e.items = IT_AXE; e.weapons_carried = IT_AXE; e.current_weapon = WEAP_AXE; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index def0b222..a7a88775 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1566,131 +1566,18 @@ void (entity pl) W_UpdateCurrentWeapon = { if ((pl.health <= 0) || (pl.current_weapon == 0)) return; - if (!(self.tfstate & TFSTATE_AIMING) && !(self.tfstate & TFSTATE_CANT_MOVE)) - /* player_run(); */ - - pl.items = pl.items - (pl.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS)); - pl.weapon = 0; - - if (pl.current_weapon == WEAP_AXE) { - pl.weaponmodel = "progs/v_axe.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_KNIFE) { - if (pl.weaponmode == 0) - pl.weaponmodel = "progs/v_knife.mdl"; - else - pl.weaponmodel = "progs/v_knife2.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_SPANNER) { - pl.weaponmodel = "progs/v_span.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_SHOTGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_shot.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_shot2.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SUPER_SHOTGUN; - } else if (pl.current_weapon == WEAP_NAILGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_nail.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_NAILS; - pl.weapon = IT_NAILGUN; - } else if (pl.current_weapon == WEAP_SUPER_NAILGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_nail2.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_NAILS; - pl.weapon = IT_SUPER_NAILGUN; - } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - if (pl.weaponmode == 0) - pl.weaponmodel = "progs/v_rock.mdl"; - else - pl.weaponmodel = "progs/v_pipe.mdl"; - pl.weaponframe = 0; - } - pl.weapon = IT_GRENADE_LAUNCHER; - pl.items = pl.items | IT_ROCKETS; - } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_rock2.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_ROCKETS; - pl.weapon = IT_ROCKET_LAUNCHER; - } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_srifle.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_AUTO_RIFLE) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_srifle.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SUPER_SHOTGUN; - } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_asscan.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_ROCKET_LAUNCHER; - } else if (pl.current_weapon == WEAP_FLAMETHROWER) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_flame.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_CELLS; - pl.weapon = IT_GRENADE_LAUNCHER; - } else if (pl.current_weapon == WEAP_INCENDIARY) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_irock.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_ROCKETS; - pl.weapon = IT_ROCKET_LAUNCHER; - } else if (pl.current_weapon == WEAP_MEDIKIT) { - pl.items = pl.items | IT_CELLS; - pl.weaponmodel = "progs/v_medi.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_TRANQ) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_tranq.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_RAILGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_rail.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_NAILS; - pl.weapon = IT_SHOTGUN; + FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); + pl.items &= ~(IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS); + // TODO: Shouldn't this always be union? Carrying prior behavior for now. + pl.items |= (wi->items)->ammo_mask; + pl.weapon = (wi->items)->it_weapon; + + if (pl.tfstate & TFSTATE_RELOADING == 0 || pl.is_feigning) { + pl.weaponmodel = (wi->models)->mode[pl.weaponmode]; } else { pl.weaponmodel = ""; - pl.weaponframe = 0; - } - - if (pl.is_feigning) { - pl.weaponmodel = ""; - pl.weaponframe = 0; } + pl.weaponframe = 0; // refresh engineer build menu when ammo updated if (pl.menu_input == Menu_Engineer_Input) From d414e505fe67147bafab5cad8af892bda7f2aaf9 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 17:18:31 -0700 Subject: [PATCH 1672/2474] Move init to FIRST_ENTRY only --- ssqc/client.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index dd909ac1..18359e3f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1047,6 +1047,9 @@ void () DecodeLevelParms = { max_active_gren2_soldier = 1; round_delay_time = 10; } + + // Must be after we've set up conditional options (e.g. hwguy reload). + FO_Weapons_Init(); } if (parm11) @@ -1069,8 +1072,6 @@ void () DecodeLevelParms = { if (parm15) self.is_admin = parm15; - // Must be after we've set up conditional options (e.g. hwguy reload). - FO_Weapons_Init(); /* local entity p = find(world, classname, "player"); while (p != world) { From 80d0392c175b183236f57f7d3ae8cc04926ce45a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 12:18:37 -0700 Subject: [PATCH 1673/2474] Eliminate all the weaponmode edgecases. Add a separate weapon entry for pipebombs. --- share/defs.h | 3 +- share/fo_weapons.qc | 74 ++++++++++++++++++++++------------------ ssqc/clan.qc | 2 +- ssqc/client.qc | 4 +-- ssqc/combat.qc | 2 +- ssqc/demoman.qc | 8 ++--- ssqc/doors.qc | 2 +- ssqc/events.qc | 82 ++++++--------------------------------------- ssqc/plats.qc | 2 +- ssqc/progs.src | 4 +-- ssqc/quadmode.qc | 2 +- ssqc/qw.qc | 6 +--- ssqc/tfort.qc | 8 ++--- ssqc/weapons.qc | 67 ++++++++++++------------------------ 14 files changed, 94 insertions(+), 172 deletions(-) diff --git a/share/defs.h b/share/defs.h index b78b7ea4..53b2dbd1 100644 --- a/share/defs.h +++ b/share/defs.h @@ -718,6 +718,7 @@ enumflags { WEAP_NAILGUN, WEAP_SUPER_NAILGUN, WEAP_GRENADE_LAUNCHER, + WEAP_PIPE_LAUNCHER, WEAP_FLAMETHROWER, WEAP_ROCKET_LAUNCHER, WEAP_INCENDIARY, @@ -957,7 +958,7 @@ enumflags { #define PC_DEMOMAN_INITARMORTYPE 0.6 #define PC_DEMOMAN_ARMORCLASSES 31 // ALL #define PC_DEMOMAN_INITARMORCLASS 0 //4 // AT_SAVEEXPLOSION -#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK +#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_PIPE_LAUNCHER | WEAP_DETPACK #define PC_DEMOMAN_MAXAMMO_SHOT 75 #define PC_DEMOMAN_MAXAMMO_NAIL 50 #define PC_DEMOMAN_MAXAMMO_CELL 50 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 1fcf91fd..eee6ac8d 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -79,6 +79,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 4, 0.2, 0 }, { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, + { WEAP_PIPE_LAUNCHER, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, @@ -101,7 +102,7 @@ FO_ClassWeapons class_weapons[] = { { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, - { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_GRENADE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_MEDIC, { WEAP_SUPER_NAILGUN, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_MEDIKIT } }, { PC_HVYWEAP, { WEAP_ASSAULT_CANNON, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, @@ -117,45 +118,46 @@ inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { - "None", "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", - "Sniper Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", - "Grenade Launcher", "Flamethrower", "Rocket Launcher", + "None", "Hook", "Knife", "Medikit", "Spanner", "Axe", "Sniper Rifle", + "Auto Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", + "Grenade Launcher", "Pipebomb Launcher", "Flamethrower", "Rocket Launcher", "Incendiary Launcher", "Assault Cannon", "Lightning Gun", "Detpack", "Tranquilizer", "Railgun" }; -inline string FO_GetWeapName(float weapon) { +string FO_GetWeapName(float weapon) { return weapon_names[WEAP_to_index(weapon)]; } struct FO_WeapModels { int weapon; - string mode[2]; + string model; }; -// Indexed by WEAP_to_index() and player.weaponmode +// Indexed by WEAP_to_index() static FO_WeapModels weapon_models[] = { - { WEAP_NONE, {""}}, - { WEAP_HOOK, {"progs/v_grap.mdl" }}, - { WEAP_KNIFE, {"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, - { WEAP_MEDIKIT, {"progs/v_medi.mdl"}}, - { WEAP_SPANNER, {"progs/v_span.mdl"}}, - { WEAP_AXE, {"progs/v_axe.mdl"}}, - { WEAP_SNIPER_RIFLE, {"progs/v_srifle.mdl"}}, - { WEAP_AUTO_RIFLE, {"progs/v_srifle.mdl"}}, - { WEAP_SHOTGUN, {"progs/v_shot.mdl"}}, - { WEAP_SUPER_SHOTGUN, {"progs/v_shot2.mdl"}}, - { WEAP_NAILGUN, {"progs/v_nail.mdl"}}, - { WEAP_SUPER_NAILGUN, {"progs/v_nail2.mdl"}}, - { WEAP_GRENADE_LAUNCHER, {"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, - { WEAP_FLAMETHROWER, {"progs/v_flame.mdl"}}, - { WEAP_ROCKET_LAUNCHER, {"progs/v_rock2.mdl"}}, - { WEAP_INCENDIARY, {"progs/v_irock.mdl"}}, - { WEAP_ASSAULT_CANNON, {"progs/v_asscan.mdl"}}, - { WEAP_LIGHTNING, {""}}, - { WEAP_DETPACK, {""}}, - { WEAP_TRANQ, {"progs/v_tranq.mdl"}}, - { WEAP_RAILGUN, {"progs/v_rail.mdl"}}, + { WEAP_NONE, ""}, + { WEAP_HOOK, "progs/v_grap.mdl" }, + { WEAP_KNIFE, "progs/v_knife.mdl" }, + { WEAP_MEDIKIT, "progs/v_medi.mdl" }, + { WEAP_SPANNER, "progs/v_span.mdl" }, + { WEAP_AXE, "progs/v_axe.mdl" }, + { WEAP_SNIPER_RIFLE, "progs/v_srifle.mdl" }, + { WEAP_AUTO_RIFLE, "progs/v_srifle.mdl" }, + { WEAP_SHOTGUN, "progs/v_shot.mdl" }, + { WEAP_SUPER_SHOTGUN, "progs/v_shot2.mdl" }, + { WEAP_NAILGUN, "progs/v_nail.mdl" }, + { WEAP_SUPER_NAILGUN, "progs/v_nail2.mdl" }, + { WEAP_GRENADE_LAUNCHER, "progs/v_rock.mdl" }, + { WEAP_PIPE_LAUNCHER, "progs/v_pipe.mdl" }, + { WEAP_FLAMETHROWER, "progs/v_flame.mdl" }, + { WEAP_ROCKET_LAUNCHER, "progs/v_rock2.mdl" }, + { WEAP_INCENDIARY, "progs/v_irock.mdl" }, + { WEAP_ASSAULT_CANNON, "progs/v_asscan.mdl" }, + { WEAP_LIGHTNING, "" }, + { WEAP_DETPACK, "" }, + { WEAP_TRANQ, "progs/v_tranq.mdl" }, + { WEAP_RAILGUN, "progs/v_rail.mdl" }, }; // REQUIRES: Order must match above. @@ -207,6 +209,7 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_NAILGUN, IT_NAILGUN}, { WEAP_SUPER_NAILGUN, IT_SUPER_NAILGUN}, { WEAP_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER}, + { WEAP_PIPE_LAUNCHER, IT_GRENADE_LAUNCHER}, { WEAP_FLAMETHROWER, IT_GRENADE_LAUNCHER}, { WEAP_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER}, { WEAP_INCENDIARY, IT_ROCKET_LAUNCHER}, @@ -261,7 +264,7 @@ static void FOT_ReloadTimer() { if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = ((ws->wi)->models)->mode[self.owner.weaponmode]; + self.owner.weaponmodel = ((ws->wi)->models)->model; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); @@ -408,7 +411,14 @@ void FO_Weapons_Init() { if (WEAP_to_index(wi->weapon) != i) error(sprintf("WI mismatch at index %d\n", i)); - if (wi->clip_size > 0) { + if (wi->weapon == WEAP_PIPE_LAUNCHER) { + FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); + wi->ammo_type = parent->ammo_type; + wi->clip_size = parent->clip_size; + wi->storage_index = parent->storage_index; + wi->full_reload_time = parent->full_reload_time; + wi->needs_reload = parent->needs_reload; + } else if (wi->clip_size > 0) { wi->needs_reload = TRUE; // We always allocate a storage index for something that can have // reload to save negotiating between client and server around @@ -423,9 +433,7 @@ void FO_Weapons_Init() { if (WEAP_to_index(wm->weapon) != i) error(sprintf("WM mismatch at index %d\n", i)); - for (j = 0; j < 2; j++) - if (wm->mode[j] != "") - precache_model(wm->mode[j]); + precache_model(wm->model); wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; diff --git a/ssqc/clan.qc b/ssqc/clan.qc index f70ed66e..980a8cc7 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -84,7 +84,7 @@ void () StartMatch = } te = find(world, classname, "detpack"); while (te){ - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed (te.enemy); dremove(te.oldenemy); dremove(te.observer_list); diff --git a/ssqc/client.qc b/ssqc/client.qc index 18359e3f..2dc4148b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1413,7 +1413,7 @@ void () RemovePlayerOwnedEnts = { te = find(world, classname, "detpack"); while (te) { if (te.owner == self) { - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed(te.enemy); dremove(te.oldenemy); dremove(te.observer_list); @@ -1426,7 +1426,7 @@ void () RemovePlayerOwnedEnts = { te = find(world, classname, "countdown_timer"); while (te) { if (te.owner == self) { - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed(te.enemy); dremove(te.oldenemy); dremove(te.observer_list); diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 959f732c..8969a187 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -672,7 +672,7 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, if (targ.health <= 0) { if ((inflictor.classname == "detpack") - && (inflictor.weaponmode == 1) && (inflictor.enemy == targ)) + && (inflictor.is_disarming) && (inflictor.enemy == targ)) deathmsg = DMSG_DETPACK_DIS; LogEventKill(attacker, targ, inflictor); Killed(targ, attacker); diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 954dd26b..2ac726cc 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -312,7 +312,7 @@ void () TeamFortress_DetpackSet = { newmis.angles_y = self.owner.angles_y; newmis.velocity = '0 0 0'; newmis.avelocity = '0 0 0'; - newmis.weaponmode = 0; + newmis.is_disarming = FALSE; newmis.touch = TeamFortress_DetpackTouch; FO_SetModel(newmis, "progs/detpack.mdl"); @@ -410,7 +410,7 @@ void () TeamFortress_DetpackExplode = { } else sprint(self.owner, PRINT_HIGH, "Your detpack fizzled out\n"); - if (self.weaponmode == 1) { + if (self.is_disarming) { TeamFortress_SetSpeed(self.enemy); dremove(self.oldenemy); dremove(self.observer_list); @@ -430,7 +430,7 @@ void () TeamFortress_DetpackTouch = { return; if (other.deadflag) return; - if (self.weaponmode == 1) + if (self.is_disarming) return; if ((other.team_no == self.owner.team_no) && (self.owner.team_no != 0)) @@ -462,7 +462,7 @@ void () TeamFortress_DetpackTouch = { disarm.nextthink = time + 3; disarm.think = TeamFortress_DetpackDisarm; - self.weaponmode = 1; + self.is_disarming = TRUE; self.enemy = other; self.observer_list = disarm; }; diff --git a/ssqc/doors.qc b/ssqc/doors.qc index dda88cd7..9ed830a9 100644 --- a/ssqc/doors.qc +++ b/ssqc/doors.qc @@ -7,7 +7,7 @@ void () door_blocked = { if (other.classname == "detpack") { sprint(other.owner, PRINT_HIGH, "Your detpack was squashed\n"); - if (other.weaponmode == 1) { + if (other.is_disarming) { TeamFortress_SetSpeed(other.enemy); dremove(other.observer_list); diff --git a/ssqc/events.qc b/ssqc/events.qc index 88cc143a..77be41b7 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -94,75 +94,15 @@ void (entity player, float previous, float next, float timeplayed) LogEventChang logevent(event); } -string (float code, float mode) GetWeaponName = { - if (code == 1) { - return "hook"; +string (float weapon) GetWeaponName = { + if (weapon >= 1 && weapon <= WEAP_LAST) { + string name = FO_GetWeapName(weapon); + name = strtolower(name); + name = strreplace(name, " ", ""); + return name; } - else if (code == 4) { - return "medikit"; - } - else if (code == 8) { - return "spanner"; - } - else if (code == 16) { - return "axe"; - } - else if (code == 32) { - return "sniperrifle"; - } - else if (code == 64) { - return "autorifle"; - } - else if (code == 128) { - return "shotgun"; - } - else if (code == 256) { - return "supershotgun"; - } - else if (code == 512) { - return "nailgun"; - } - else if (code == 1024) { - return "supernailgun"; - } - else if (code == 2048) { - if (mode == 0) - return "grenadelauncher"; - else if (mode == 1) - return "pipebomblauncher"; - } - else if (code == 4096) { - return "flamethrower"; - } - else if (code == 8192) { - return "rocketlauncher"; - } - else if (code == 16384) { - return "incendiary"; - } - else if (code == 32768) { - return "assaultcannon"; - } - else if (code == 65536) { - return "lightning"; - } - else if (code == 131072) { - return "plasmagun"; - } - else if (code == 262144) { - return "tranquilizer"; - } - else if (code == 524288) { - return "railgun"; - } - else if (code == 1048576) { - return "tribolt"; - } - else if (code == 2097152) { - return "sniperrail"; - } - else - return "undefined"; + + return "undefined"; } void (entity attacker, entity target, string afflictionType) LogAffliction = { @@ -230,7 +170,7 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon, attacker.weaponmode); + inflictorId = GetWeaponName(attacker.current_weapon); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -332,7 +272,7 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { killKind = "enemy"; if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon, attacker.weaponmode); + inflictorId = GetWeaponName(attacker.current_weapon); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -446,7 +386,7 @@ void (entity attacker) LogEventAttack = { if (canlog == 0) return; local string event; - event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(attacker.current_weapon, attacker.weaponmode), ftos(gametime), gametimestamp); + event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(attacker.current_weapon), ftos(gametime), gametimestamp); logevent(event); } diff --git a/ssqc/plats.qc b/ssqc/plats.qc index 2b3ab748..d681cb57 100644 --- a/ssqc/plats.qc +++ b/ssqc/plats.qc @@ -147,7 +147,7 @@ void () plat_trigger_use = { void () plat_crush = { if (other.classname == "detpack") { sprint(other.owner, PRINT_HIGH, "Your detpack was squashed\n"); - if (other.weaponmode == 1) { + if (other.is_disarming) { TeamFortress_SetSpeed(other.enemy); dremove(other.observer_list); } diff --git a/ssqc/progs.src b/ssqc/progs.src index 5cd0b0b3..e69fee0a 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -12,11 +12,11 @@ defs.qc ../share/commondefs.qc ../share/common_helpers.qc qw.qc +debug.qc +../share/fo_weapons.qc events.qc roles.qc q3defs.qc -debug.qc -../share/fo_weapons.qc status.qc functions.qc menu.qc diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 0e59bb2c..10bb0b2e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -520,7 +520,7 @@ void () StartQuadRound = } te = find(world, classname, "detpack"); while (te){ - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed (te.enemy); dremove(te.oldenemy); dremove(te.observer_list); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index f5c4354e..709ff91a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -130,8 +130,7 @@ float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); .float maxfbspeed; // Maximum forward/back speed .float maxstrafespeed; // Maximum side speed -.float weaponmode; // Used for multiple mode weapons -.float last_weaponmode; // Last weapon's weapon mode +.float is_disarming; .float motd; // Used to display MOTD .float current_menu; .float current_menu_type; @@ -216,15 +215,12 @@ float coop; .float queue_weaponslot; // the weaponslot to switch to when possible .float queue_weaponstate; // the weaponstate to load when possible .float next_weapon; // used by weapon slots to communicate which weapon to select -.float next_weaponmode; // used by weapon slots to communicate which weapon mode to select // weapon states .float weaponstate_current_weaponslot; .float weaponstate_last_weaponslot; .float weaponstate_current_weapon; .float weaponstate_last_weapon; -.float weaponstate_weaponmode; -.float weaponstate_last_weaponmode; .float ammo_medikit; // Ammo used for the medikit .float maxammo_medikit; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 8dc90bb4..2df04c55 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1572,8 +1572,6 @@ void () TeamFortress_SetEquipment = { if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; self.last_weapon = 0; - self.weaponmode = 0; - self.last_weaponmode = 0; self.current_weaponslot = W_BestWeaponSlot(); self.last_weaponslot = 2; W_WeaponState_Save(self); @@ -2283,6 +2281,8 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weaponslot = W_BestWeaponSlot(); + + W_UpdateCurrentWeapon(self); }; float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { @@ -2447,8 +2447,8 @@ void () TeamFortress_RemoveTimers = { te = find(world, classname, "detpack"); while (te) { - if ((te.weaponmode == 1) && (te.enemy == self)) - te.weaponmode = 0; + if ((te.is_disarming) && (te.enemy == self)) + te.is_disarming = FALSE; te = find(te, classname, "detpack"); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index a7a88775..749cdaf7 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -256,8 +256,7 @@ int () W_FireKnife = { trace_ent.axhitme = 1; SpawnBlood(org, 20); - self.weaponmode = 1; - self.weaponmodel = "progs/v_knife2.mdl"; + // TODO: Rework knife bloodying // Check direction of Attack makevectors(trace_ent.v_angle); @@ -1307,7 +1306,7 @@ void () W_FireGrenade = { newmis.owner = self; newmis.movetype = 10; newmis.solid = 2; - if ((self.weaponmode == 0) || (cb_prematch)) { + if (self.current_weapon == WEAP_GRENADE_LAUNCHER || cb_prematch) { newmis.weapon = 5; newmis.classname = "grenade"; newmis.skin = 1; @@ -1573,7 +1572,7 @@ void (entity pl) W_UpdateCurrentWeapon = { pl.weapon = (wi->items)->it_weapon; if (pl.tfstate & TFSTATE_RELOADING == 0 || pl.is_feigning) { - pl.weaponmodel = (wi->models)->mode[pl.weaponmode]; + pl.weaponmodel = (wi->models)->model; } else { pl.weaponmodel = ""; } @@ -1653,10 +1652,8 @@ void () W_ChangeToBestWeapon = { //self.last_weaponslot = self.current_weaponslot; //self.last_weapon = self.current_weapon; - //self.last_weaponmode = self.weaponmode; self.current_weaponslot = slot; self.current_weapon = self.next_weapon; - self.weaponmode = self.next_weaponmode; W_UpdateCurrentWeapon(self); W_WeaponState_Save(self); W_PrintWeaponMessage(); @@ -1752,6 +1749,10 @@ void () W_Attack = { player_rocket1(); W_FireGrenade(); Status_Refresh(self); + } else if (self.current_weapon == WEAP_PIPE_LAUNCHER) { + player_rocket1(); + W_FireGrenade(); + Status_Refresh(self); } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { player_rocket1(); W_FireRocket(); @@ -1846,12 +1847,12 @@ void () W_PrintWeaponMessage = { switch (self.current_weapon) { case WEAP_GRENADE_LAUNCHER: - if (self.weaponmode == GL_NORMAL) - sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); - else if (cb_prematch) - sprint(self, PRINT_MEDIUM, - "Pipebomb mode not available in prematch\n"); - else if (self.weaponmode == GL_PIPEBOMB) + sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); + break; + case WEAP_PIPE_LAUNCHER: + if (cb_prematch) + sprint(self, PRINT_MEDIUM, "Pipebomb mode not available in prematch\n"); + else sprint(self, PRINT_MEDIUM, "Pipebomb mode\n"); break; case WEAP_SNIPER_RIFLE: @@ -1889,11 +1890,6 @@ float (float weap) W_GetSlot = { return 1; else return 3; - } else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.weaponmode == 0) - return 1; - else - return 2; } return 0; }; @@ -1923,12 +1919,11 @@ float (float weap) W_OldGetSlot = { || weap == WEAP_ASSAULT_CANNON || weap == WEAP_INCENDIARY) return 7; - else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.weaponmode == 0) - return 6; - else - return 7; - } + else if (weap == WEAP_GRENADE_LAUNCHER) + return 6; + else if (weap == WEAP_PIPE_LAUNCHER) + return 7; + return 0; }; @@ -2131,10 +2126,8 @@ float () W_OldWeaponSlot5 = { }; float () W_OldWeaponSlot6 = { - if (self.playerclass == PC_DEMOMAN) { - self.next_weaponmode = 0; + if (self.playerclass == PC_DEMOMAN) return WEAP_GRENADE_LAUNCHER; - } else if (self.playerclass == PC_PYRO) return WEAP_FLAMETHROWER; return 0; @@ -2144,7 +2137,7 @@ float () W_OldWeaponSlot7 = { if (self.playerclass == PC_SOLDIER) return WEAP_ROCKET_LAUNCHER; if (self.playerclass == PC_DEMOMAN) - return WEAP_GRENADE_LAUNCHER; + return WEAP_PIPE_LAUNCHER; else if (self.playerclass == PC_HVYWEAP) return WEAP_ASSAULT_CANNON; else if (self.playerclass == PC_PYRO) @@ -2192,7 +2185,7 @@ float () W_WeaponSlot2 = { || self.playerclass == PC_ENGINEER) return WEAP_SUPER_SHOTGUN; else if (self.playerclass == PC_DEMOMAN) { - return WEAP_GRENADE_LAUNCHER; // weaponmode = 1 (pipebomb launcher) + return WEAP_PIPE_LAUNCHER; } else if (self.playerclass == PC_PYRO) if (cf_pyro_impulses) { return WEAP_INCENDIARY; @@ -2233,13 +2226,10 @@ float () W_WeaponSlot4 = { }; void (float slot) W_WeaponSlot = { - self.next_weaponmode = 0; if (slot == 1) self.next_weapon = W_WeaponSlot1(); else if (slot == 2) { self.next_weapon = W_WeaponSlot2(); - if (self.next_weapon == WEAP_GRENADE_LAUNCHER) - self.next_weaponmode = 1; } else if (slot == 3) self.next_weapon = W_WeaponSlot3(); @@ -2248,7 +2238,6 @@ void (float slot) W_WeaponSlot = { }; void (float inp) W_OldWeaponSlot = { - self.next_weaponmode = 0; if (inp == TF_SLOT1) { self.next_weapon = W_OldWeaponSlot1(); } @@ -2269,8 +2258,6 @@ void (float inp) W_OldWeaponSlot = { } else if (inp == 7) { self.next_weapon = W_OldWeaponSlot7(); - if (self.next_weapon == WEAP_GRENADE_LAUNCHER) - self.next_weaponmode = 1; } if (self.next_weapon == 0) { self.next_weapon = self.current_weapon; @@ -2415,8 +2402,6 @@ void (entity pl) W_WeaponState_Save = { pl.weaponstate_last_weaponslot = pl.last_weaponslot; pl.weaponstate_current_weapon = pl.current_weapon; pl.weaponstate_last_weapon = pl.last_weapon; - pl.weaponstate_weaponmode = pl.weaponmode; - pl.weaponstate_last_weaponmode = pl.last_weaponmode; } void (entity pl, float swap) W_WeaponState_Load = { @@ -2425,15 +2410,11 @@ void (entity pl, float swap) W_WeaponState_Load = { pl.last_weaponslot = pl.weaponstate_last_weaponslot; pl.current_weapon = pl.weaponstate_current_weapon; pl.last_weapon = pl.weaponstate_last_weapon; - pl.weaponmode = pl.weaponstate_weaponmode; - pl.last_weaponmode = pl.weaponstate_last_weaponmode; } else { pl.current_weaponslot = pl.weaponstate_last_weaponslot; pl.last_weaponslot = pl.weaponstate_current_weaponslot; pl.current_weapon = pl.weaponstate_last_weapon; pl.last_weapon = pl.weaponstate_current_weapon; - pl.weaponmode = pl.weaponstate_last_weaponmode; - pl.last_weaponmode = pl.weaponstate_weaponmode; } pl.queue_weaponstate = 0; @@ -2495,13 +2476,11 @@ void (float inp) W_ChangeWeapon = { } // don't update current/last weapon information if next weapon is the same as current - if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { + if (self.current_weapon != self.next_weapon) { self.last_weaponslot = self.current_weaponslot; self.current_weaponslot = self.queue_weaponslot; self.last_weapon = self.current_weapon; self.current_weapon = self.next_weapon; - self.last_weaponmode = self.weaponmode; - self.weaponmode = self.next_weaponmode; if (!self.is_quickfiring) W_PrintWeaponMessage(); @@ -3463,8 +3442,6 @@ void () W_WeaponFrame = { SuperDamageSound(); W_Attack(); } - } else if (self.playerclass == 0) { - self.weaponmode = 0; } else if (self.tfstate & TFSTATE_AIMING) { W_Attack(); self.tfstate = self.tfstate - TFSTATE_AIMING; From b26634044b74c5e99ab37815156b272365215778 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 12:18:59 -0700 Subject: [PATCH 1674/2474] Refactor everything to use the new weapon code This indavertently became a huge diff. It was too awkward to separate this stuff as the touch points were super entwined. - Class loadouts are now all generated from our class tables. - Eliminate everything around , we now work purely in weapons. When we need something else, we convert it to a weapon. - Remove `chweap_wait_atk`. We have queueing, it's not used for any of our game modes, and it adds complexity. --- share/defs.h | 10 - share/fo_weapons.qc | 42 ++- ssqc/actions.qc | 115 +------ ssqc/client.qc | 22 +- ssqc/demoman.qc | 11 +- ssqc/player.qc | 3 +- ssqc/qw.qc | 5 +- ssqc/spy.qc | 6 +- ssqc/tfort.qc | 63 +--- ssqc/weapons.qc | 748 +++++++++----------------------------------- 10 files changed, 218 insertions(+), 807 deletions(-) diff --git a/share/defs.h b/share/defs.h index 53b2dbd1..49670e60 100644 --- a/share/defs.h +++ b/share/defs.h @@ -870,7 +870,6 @@ enumflags { #define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned #define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class #define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned -#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN #define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry #define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry #define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry @@ -901,7 +900,6 @@ enumflags { #define PC_SNIPER_INITARMORTYPE 0.3 #define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL #define PC_SNIPER_INITARMORCLASS 0 -#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN #define PC_SNIPER_MAXAMMO_SHOT 75 #define PC_SNIPER_MAXAMMO_NAIL 100 #define PC_SNIPER_MAXAMMO_CELL 50 @@ -929,7 +927,6 @@ enumflags { #define PC_SOLDIER_INITARMORTYPE 0.8 #define PC_SOLDIER_ARMORCLASSES 31 // ALL #define PC_SOLDIER_INITARMORCLASS 0 -#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER #define PC_SOLDIER_MAXAMMO_SHOT 100 #define PC_SOLDIER_MAXAMMO_NAIL 100 #define PC_SOLDIER_MAXAMMO_CELL 50 @@ -958,7 +955,6 @@ enumflags { #define PC_DEMOMAN_INITARMORTYPE 0.6 #define PC_DEMOMAN_ARMORCLASSES 31 // ALL #define PC_DEMOMAN_INITARMORCLASS 0 //4 // AT_SAVEEXPLOSION -#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_PIPE_LAUNCHER | WEAP_DETPACK #define PC_DEMOMAN_MAXAMMO_SHOT 75 #define PC_DEMOMAN_MAXAMMO_NAIL 50 #define PC_DEMOMAN_MAXAMMO_CELL 50 @@ -990,7 +986,6 @@ enumflags { #define PC_MEDIC_INITARMORTYPE 0.3 #define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION #define PC_MEDIC_INITARMORCLASS 0 -#define PC_MEDIC_WEAPONS WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN #define PC_MEDIC_MAXAMMO_SHOT 75 #define PC_MEDIC_MAXAMMO_NAIL 150 #define PC_MEDIC_MAXAMMO_CELL 50 @@ -1032,7 +1027,6 @@ enumflags { #define PC_HVYWEAP_INITARMORTYPE 0.8 #define PC_HVYWEAP_ARMORCLASSES 31 // ALL #define PC_HVYWEAP_INITARMORCLASS 0 -#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN #define PC_HVYWEAP_MAXAMMO_SHOT 200 #define PC_HVYWEAP_MAXAMMO_NAIL 200 #define PC_HVYWEAP_MAXAMMO_CELL 50 @@ -1064,7 +1058,6 @@ enumflags { #define PC_PYRO_INITARMORTYPE 0.6 #define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION #define PC_PYRO_INITARMORCLASS 16 // AT_SAVEFIRE -#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN #define PC_PYRO_MAXAMMO_SHOT 40 #define PC_PYRO_MAXAMMO_NAIL 50 #define PC_PYRO_MAXAMMO_CELL 200 @@ -1116,7 +1109,6 @@ enumflags { #define PC_SPY_INITARMORTYPE 0.6 #define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION #define PC_SPY_INITARMORCLASS 0 -#define PC_SPY_WEAPONS WEAP_KNIFE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN #define PC_SPY_MAXAMMO_SHOT 40 #define PC_SPY_MAXAMMO_NAIL 100 #define PC_SPY_MAXAMMO_CELL 30 @@ -1149,7 +1141,6 @@ enumflags { #define PC_ENGINEER_INITARMORTYPE 0.3 #define PC_ENGINEER_ARMORCLASSES 31 // ALL #define PC_ENGINEER_INITARMORCLASS 0 -#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_RAILGUN | WEAP_SUPER_SHOTGUN #define PC_ENGINEER_MAXAMMO_SHOT 50 #define PC_ENGINEER_MAXAMMO_NAIL 50 #define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal @@ -1179,7 +1170,6 @@ enumflags { #define PC_CIVILIAN_INITARMORTYPE 0 #define PC_CIVILIAN_ARMORCLASSES 0 #define PC_CIVILIAN_INITARMORCLASS 0 -#define PC_CIVILIAN_WEAPONS WEAP_AXE #define PC_CIVILIAN_MAXAMMO_SHOT 0 #define PC_CIVILIAN_MAXAMMO_NAIL 0 #define PC_CIVILIAN_MAXAMMO_CELL 0 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index eee6ac8d..86565b33 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -12,6 +12,7 @@ .float reload_assault_cannon; .float reload_sniper_rifle; .float waterlevel; +.float playerclass; .float ammo_shells; .float ammo_nails; @@ -90,6 +91,9 @@ FO_WeapInfo weapon_info[] = { { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, }; +inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { + return &weapon_info[WEAP_to_index(weapon)]; +} struct FO_ClassWeapons { float id; float slots[4]; @@ -111,10 +115,6 @@ FO_ClassWeapons class_weapons[] = { { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; -inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { - return &weapon_info[WEAP_to_index(weapon)]; -} - // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { @@ -220,11 +220,37 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_RAILGUN, IT_SHOTGUN}, }; +FO_WeapInfo* FO_ClassWeaponSlot(float class, float slot) { + FO_ClassWeapons* cw = &class_weapons[class]; + return cw->info[slot - 1] ? cw->info[slot - 1] : __NULL__; +} + +float FO_ClassWeapMask(float class) { + float result = 0; + for (int i = 1; i <= 4; i++) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); + if (wi) + result |= (wi->items)->it_weapon; + } + return result; +} + float FO_ClassWeaponItemMask(float class) { float mask = 0; - for (float i = 0; i < 4; i++) { - FO_WeapInfo* wi = class_weapons[class].info[i]; - mask |= wi ? (wi->items)->it_weapon : 0; + for (float i = 1; i <= 4; i++) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); + if (wi) + mask |= (wi->items)->it_weapon; + } + return mask; +} + +float FO_CurrentWeaponsMask() { + float mask = 0; + for (float i = 1; i <= 4; i++) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, i); + if (wi) + mask |= wi->weapon; } return mask; } @@ -254,7 +280,6 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; -void (entity pl, float swap) W_WeaponState_Load; void (float att_delay) Attack_Finished; static void FOT_ReloadTimer() { @@ -267,7 +292,6 @@ static void FOT_ReloadTimer() { self.owner.weaponmodel = ((ws->wi)->models)->model; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); - W_WeaponState_Load(self.owner, 0); } else { // Refresh clip if (ws->weapon != WEAP_SNIPER_RIFLE) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index c973f451..452585f0 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -467,9 +467,9 @@ void (entity pe_player, float f_type) CF_Identify = { }; void () RestoreDefaultWeapon = { - local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); + float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); if (default_weapon >= 1 && default_weapon <= 4) { - W_ChangeWeapon(default_weapon); + W_ChangeWeapon(W_WeaponBySlot(default_weapon)); } }; @@ -482,114 +482,31 @@ void () TeamFortress_ForceReloadCurrentWeapon = { }; void (float slot) TeamFortress_ReloadSlot = { - local float weap = 0; + float weap = W_WeaponBySlot(slot); - if (!IsUsingOldImpulses()) { - if (slot < 1 || slot > 3) - return; + FO_ReloadWeapon(weap, FALSE); +} - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) - return; - weap = W_WeaponSlot3(); - } - FO_ReloadWeapon(weap, FALSE); - } - else { - if (slot < 1 || slot > 7) - return; - if (slot == 1) - weap = W_OldWeaponSlot1(); - else if (slot == 2) - weap = W_OldWeaponSlot2(); - else if (slot == 3) - weap = W_OldWeaponSlot3(); - else if (slot == 4) - weap = W_OldWeaponSlot4(); - else if (slot == 5) - weap = W_OldWeaponSlot5(); - else if (slot == 6) - weap = W_OldWeaponSlot6(); - else if (slot == 7) - weap = W_OldWeaponSlot7(); - if (weap != 0) - FO_ReloadWeapon(weap, FALSE); - } -}; +float W_FindPrevNextWeapon(float weapon, float is_prev); void () TeamFortress_ReloadNext = { - local float slot, reload = 0, weap = 0; - - if (!IsUsingOldImpulses()) { - // reload current slot first - slot = W_GetSlot(self.current_weapon); - if (FO_CanReload(self.current_weapon)) { - FO_ReloadWeapon(self.current_weapon, FALSE); - reload = 1; - return; - } - - // then go through each slot - for (slot = 1; slot < 4; slot++) { - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) - break; - weap = W_WeaponSlot3(); - } + float weapon = self.current_weapon; - if (FO_CanReload(weap)) { - self.current_weapon = weap; - FO_ReloadWeapon(weap, FALSE); - reload = 1; + if (!FO_CanReload(weapon)) { + for (int i = 0; i < 3; i++) { + weapon = W_FindPrevNextWeapon(weapon, FALSE); + if (FO_CanReload(weapon)) break; - } - } - } - else { - slot = W_OldGetSlot(self.current_weapon); - if (FO_CanReload(self.current_weapon)) { - FO_ReloadWeapon(self.current_weapon, FALSE); - reload = 1; - return; - } - // then go through each slot - for (slot = 1; slot < GetLastWeaponImpulse(); slot++) { - if (slot == 1) - weap = W_OldWeaponSlot1(); - else if (slot == 2) - weap = W_OldWeaponSlot2(); - else if (slot == 3) - weap = W_OldWeaponSlot3(); - else if (slot == 4) - weap = W_OldWeaponSlot4(); - else if (slot == 5) - weap = W_OldWeaponSlot5(); - else if (slot == 6) - weap = W_OldWeaponSlot6(); - else if (slot == 7) - weap = W_OldWeaponSlot7(); - - if (FO_CanReload(weap)) { - self.current_weapon = weap; - FO_ReloadWeapon(weap, FALSE); - reload = 1; - break; - } } } - if (!reload) + if (FO_CanReload(weapon)) { + FO_ReloadWeapon(weapon, FALSE); RestoreDefaultWeapon(); + } else { sprint(self, PRINT_HIGH, "All clips full\n"); -}; + } +} entity TeamFortress_GetPracticeSpawn(entity e) = { diff --git a/ssqc/client.qc b/ssqc/client.qc index 2dc4148b..5cee5312 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -58,7 +58,6 @@ void () StartQuadRound; void (string cl_pwd) Admin_Check; void () Admin_Aliases; void () PreMatch_Message; -float () GetLastWeaponImpulse; void () UpdateReadyStatus; float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; @@ -680,9 +679,6 @@ void () DecodeLevelParms = { // ceasefire type - 0: default; 1: pause ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); - // wait until attack_finished is over before changing weapons - chweap_wait_attfinished = CF_GetSetting("cwaf", "chweap_wait_atk", "on"); - // enable flag model following the player who has it flag_follow = CF_GetSetting("flagfollow", "flag_follow", "on"); @@ -999,7 +995,6 @@ void () DecodeLevelParms = { if (st == "on") { server_huetf = TRUE; impulse_queue = TRUE; - chweap_wait_attfinished = FALSE; flag_follow = FALSE; ng_velocity = 1000; ng_damage = 18; @@ -2112,9 +2107,6 @@ void () PutClientInServer = { return; } - if (self.last_playerclass == 0) - self.last_playerclass = self.playerclass; - // remove prime timers to avoid getting an old grenade in your face te = find(world, classname, "primetimer"); while (te != world) { @@ -2177,6 +2169,7 @@ void () PutClientInServer = { TeamFortress_PrintClassName(self, self.playerclass, self.tfstate & TFSTATE_RANDOMPC); + self.attack_finished = 0; // Allow below to change weapon freely. TeamFortress_SetEquipment(); TeamFortress_SetHealth(); TeamFortress_SetSpeed(self); @@ -2190,12 +2183,6 @@ void () PutClientInServer = { stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - if (self.current_weaponslot && self.last_playerclass == self.playerclass) - W_ChangeWeapon(self.current_weaponslot); - else { - W_ChangeWeapon(W_BestWeaponSlot()); - } - self.last_playerclass = self.playerclass; self.attack_finished = time + 0.3; self.th_pain = player_pain; @@ -3829,11 +3816,8 @@ float () IsUsingCFImpulses = { return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); } -float () GetLastWeaponImpulse = { - if (IsUsingOldImpulses()) - return 7; - else - return 4; +float GetMaxWeaponInput() { + return IsUsingOldImpulses() ? 7 : 4; } void () InitReverseCap = { diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 2ac726cc..181b6b07 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -224,8 +224,9 @@ void (float timer) TeamFortress_SetDetpack = { self.ammo_detpack = self.ammo_detpack - 1; self.immune_to_check = time + 10; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - self.weapon = self.current_weapon; - self.next_weapon = self.current_weapon; + self.weapon = IT_AXE; + self.queue_weapon = self.current_weapon; + self.current_weapon = 0; self.weaponmodel = ""; self.weaponframe = 0; @@ -267,7 +268,8 @@ void () TeamFortress_DetpackStop = { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); self.is_detpacking = 0; self.detpack_left = 0; - self.current_weapon = self.next_weapon; + self.current_weapon = self.queue_weapon; + self.queue_weapon = 0; Status_Refresh(self); TeamFortress_SetSpeed(self); @@ -293,7 +295,8 @@ void () TeamFortress_DetpackSet = { oldself = self; self = self.owner; self.is_detpacking = 0; - self.current_weapon = self.next_weapon; + self.current_weapon = self.queue_weapon; + self.queue_weapon = 0; Status_Refresh(self); self = oldself; diff --git a/ssqc/player.qc b/ssqc/player.qc index ab5940ae..895675ac 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -571,9 +571,8 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { - self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_BestWeaponSlot(); W_PrintWeaponMessage(); + W_ChangeToBestWeapon(); return; } player_run(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 709ff91a..5e7a6d23 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -212,9 +212,7 @@ float coop; .float last_weapon; // the last weapon the player was using .float current_weaponslot; // the currently equipped weaponslot .float last_weaponslot; // the last equipped weaponslot -.float queue_weaponslot; // the weaponslot to switch to when possible -.float queue_weaponstate; // the weaponstate to load when possible -.float next_weapon; // used by weapon slots to communicate which weapon to select +.float queue_weapon; // the weapon to switch to when possible // weapon states .float weaponstate_current_weaponslot; @@ -634,7 +632,6 @@ string pause_actor; float unpause_requested; float unpause_countdown; float unpause_lastcountnumber; -float chweap_wait_attfinished; float override_mapclasses; float solid_detpack; float walls_block_emp; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index a144ca1b..9bb3b179 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -498,9 +498,7 @@ void (float issilent, float force) FO_Spy_Feign = { setsize(self, '-16 -16 -24', '16 16 -16'); // set weapon state and remove weapon viewmodel - W_WeaponState_Save(self); - self.weaponmodel = ""; - self.weaponframe = 0; + W_QueueAndDisableWeapon(); // set view height to ground self.view_ofs = '0 0 4'; @@ -603,7 +601,7 @@ void () FO_Spy_Unfeign = { self.feign_areachecked = 0; // load saved weapon state and set current ammo - W_WeaponState_Load(self, 0); + W_UpdateCurrentWeapon(self); // allow spy to move again self.movetype = MOVETYPE_WALK; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2df04c55..7a7e4832 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -340,7 +340,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(W_BestWeaponSlot()); + W_ChangeWeapon(W_BestWeapon()); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; @@ -544,10 +544,11 @@ void () TeamFortress_Inventory = { if (self.tf_items & NIT_SCANNER) sprint(self, PRINT_HIGH, "Scanner\n"); - if (self.weapons_carried & WEAP_MEDIKIT) + float current_weapons = FO_CurrentWeaponsMask(); + if (current_weapons & WEAP_MEDIKIT) sprint(self, PRINT_HIGH, "Medikit\n"); - if (self.weapons_carried & WEAP_DETPACK) { + if (current_weapons & WEAP_DETPACK) { if (self.ammo_detpack > 0) { st = ftos(self.ammo_detpack); sprint(self, PRINT_HIGH, st, " detpack"); @@ -1568,13 +1569,9 @@ void () TeamFortress_SetEquipment = { kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); self.items = FO_ClassWeaponItemMask(self.playerclass) | kept_items; - self.weapons_carried = 0; if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; self.last_weapon = 0; - self.current_weaponslot = W_BestWeaponSlot(); - self.last_weaponslot = 2; - W_WeaponState_Save(self); } self.tf_items = 0; @@ -1624,8 +1621,6 @@ void () TeamFortress_SetEquipment = { self.lives = -1; if (self.playerclass == PC_SCOUT) { - self.weapons_carried = self.weapons_carried | PC_SCOUT_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SCOUT_MAXAMMO_ROCKET; self.ammo_nails = PC_SCOUT_MAXAMMO_NAIL; @@ -1684,11 +1679,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_SCOUT_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_NAILGUN; } else if (self.playerclass == PC_SNIPER) { - self.weapons_carried = self.weapons_carried | PC_SNIPER_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SNIPER_MAXAMMO_ROCKET; self.ammo_nails = PC_SNIPER_MAXAMMO_NAIL; @@ -1738,11 +1729,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_SNIPER_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_SNIPER_RIFLE; } else if (self.playerclass == PC_SOLDIER) { - self.weapons_carried = self.weapons_carried | PC_SOLDIER_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET; self.ammo_nails = PC_SOLDIER_MAXAMMO_NAIL; @@ -1804,11 +1791,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 200; else self.maxarmor = PC_SOLDIER_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_ROCKET_LAUNCHER; } else if (self.playerclass == PC_DEMOMAN) { - self.weapons_carried = self.weapons_carried | PC_DEMOMAN_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET; self.ammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; @@ -1861,11 +1844,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 120; else self.maxarmor = PC_DEMOMAN_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_GRENADE_LAUNCHER; } else if (self.playerclass == PC_MEDIC) { - self.weapons_carried = self.weapons_carried | PC_MEDIC_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_MEDIC_MAXAMMO_ROCKET; self.ammo_nails = PC_MEDIC_MAXAMMO_NAIL; @@ -1920,8 +1899,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 100; else self.maxarmor = PC_MEDIC_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_SUPER_NAILGUN; self.ammo_medikit = PC_MEDIC_INITAMMO_MEDIKIT; self.maxammo_medikit = PC_MEDIC_MAXAMMO_MEDIKIT; @@ -1944,8 +1921,6 @@ void () TeamFortress_SetEquipment = { te.owner = self; te.classname = "timer"; } else if (self.playerclass == PC_HVYWEAP) { - self.weapons_carried = self.weapons_carried | PC_HVYWEAP_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET; self.ammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; @@ -2001,11 +1976,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = max_armor_hwguy; } - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_SUPER_SHOTGUN; } else if (self.playerclass == PC_PYRO) { - self.weapons_carried = self.weapons_carried | PC_PYRO_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_PYRO_MAXAMMO_ROCKET; self.ammo_nails = PC_PYRO_MAXAMMO_NAIL; @@ -2054,11 +2025,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 150; else self.maxarmor = PC_PYRO_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_FLAMETHROWER; } else if (self.playerclass == PC_CIVILIAN) { - self.weapons_carried = self.weapons_carried | PC_CIVILIAN_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_CIVILIAN_MAXAMMO_ROCKET; self.ammo_nails = PC_CIVILIAN_MAXAMMO_NAIL; @@ -2108,11 +2075,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 0; else self.maxarmor = PC_CIVILIAN_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_AXE; } else if (self.playerclass == PC_SPY) { - self.weapons_carried = self.weapons_carried | PC_SPY_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SPY_MAXAMMO_ROCKET; self.ammo_nails = PC_SPY_MAXAMMO_NAIL; @@ -2164,8 +2127,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 100; else self.maxarmor = PC_SPY_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_TRANQ; if (invis_only == 1) { te = spawn(); @@ -2175,8 +2136,6 @@ void () TeamFortress_SetEquipment = { te.classname = "timer"; } } else if (self.playerclass == PC_ENGINEER) { - self.weapons_carried = self.weapons_carried | PC_ENGINEER_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_ENGINEER_MAXAMMO_ROCKET; self.ammo_nails = PC_ENGINEER_MAXAMMO_NAIL; @@ -2227,8 +2186,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_ENGINEER_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_RAILGUN; } else if (self.playerclass == PC_UNDEFINED) { self.ammo_rockets = 0; @@ -2248,7 +2205,6 @@ void () TeamFortress_SetEquipment = { self.armorvalue = 0; self.weapon = 0; self.current_weapon = 0; - self.weapons_carried = 0; self.flags = FL_CLIENT | FL_NOTARGET; self.waterlevel = 3; @@ -2280,9 +2236,10 @@ void () TeamFortress_SetEquipment = { self.items = self.items | IT_ARMOR1; if (self.last_playerclass != self.playerclass) - self.current_weaponslot = W_BestWeaponSlot(); - - W_UpdateCurrentWeapon(self); + W_ChangeToBestWeapon(); + else + W_UpdateCurrentWeapon(self); + self.last_playerclass = self.playerclass; }; float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { @@ -2828,7 +2785,7 @@ void () TeamFortress_AssaultWeapon = { if (self.tfstate & TFSTATE_RELOADING) return; - if (!(self.weapons_carried & WEAP_ASSAULT_CANNON)) + if (FO_CurrentWeaponsMask() & WEAP_ASSAULT_CANNON == 0) return; if (self.heat > 0) { @@ -2846,7 +2803,7 @@ void () TeamFortress_AssaultWeapon = { self.antispam_assault_cannon = time + 3; return; } - self.current_weapon = WEAP_ASSAULT_CANNON; + W_ChangeWeapon(WEAP_ASSAULT_CANNON); }; void () TeamFortress_ExplodePerson = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 749cdaf7..ef9cfee6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -12,8 +12,8 @@ void () OldConcussionGrenadeTimer; void (float inp) W_ChangeWeapon; void () W_ChangeToBestWeapon; -void (float slot) W_WeaponSlot; -void (entity pl) W_WeaponState_Save; +float (float slot) W_WeaponBySlot; +float (float impulse) W_WeaponByImpulse; void () W_PrintWeaponMessage; void () button_fire; @@ -107,10 +107,8 @@ void () TeamFortress_NailGrenInfo; void () BioInfection_Decay; void () BioInfection_MonsterDecay; -void (entity pl, float swap) W_WeaponState_Load; float (float weap) W_GetSlot; float (float weap) W_OldGetSlot; -float () W_BestWeaponSlot; void () W_FireFlame; void () W_FireIncendiaryCannon; void () W_FireTranq; @@ -130,11 +128,11 @@ void () StartTimer; void () ToggleInvincibility; -float () GetLastWeaponImpulse; +float () GetMaxWeaponInput; float () IsUsingOldImpulses; float () IsUsingCFImpulses; -void (float inp) W_OldWeaponSlot; +float (float impulse) W_WeaponByImpulse; void (entity pl) W_UpdateCurrentWeapon; @@ -1571,11 +1569,10 @@ void (entity pl) W_UpdateCurrentWeapon = { pl.items |= (wi->items)->ammo_mask; pl.weapon = (wi->items)->it_weapon; - if (pl.tfstate & TFSTATE_RELOADING == 0 || pl.is_feigning) { + if ((pl.tfstate & TFSTATE_RELOADING == 0) && !pl.is_feigning) pl.weaponmodel = (wi->models)->model; - } else { + else pl.weaponmodel = ""; - } pl.weaponframe = 0; // refresh engineer build menu when ammo updated @@ -1590,9 +1587,9 @@ void (entity pl) W_UpdateCurrentWeapon = { }; float () W_BestWeapon = { - local float it; + float it = FO_CurrentWeaponsMask(); - it = self.weapons_carried; + // TODO: Clean-up this at some point. It at least works with WEAPs. if ((self.ammo_cells >= 1 && it & WEAP_LIGHTNING) && self.waterlevel <= 1) return WEAP_LIGHTNING; else if ((self.ammo_cells >= 7 && self.ammo_shells >= 1) && it & WEAP_ASSAULT_CANNON) @@ -1631,32 +1628,8 @@ float () W_BestWeapon = { return 0; }; -float () W_BestWeaponSlot = { - local float weap; - - weap = W_BestWeapon(); - - if (!IsUsingOldImpulses()) - return W_GetSlot(weap); - else - return W_OldGetSlot(weap); -}; - void () W_ChangeToBestWeapon = { - local float slot = W_BestWeaponSlot(); - - if (!IsUsingOldImpulses()) - W_WeaponSlot(slot); - else - W_OldWeaponSlot(slot); - - //self.last_weaponslot = self.current_weaponslot; - //self.last_weapon = self.current_weapon; - self.current_weaponslot = slot; - self.current_weapon = self.next_weapon; - W_UpdateCurrentWeapon(self); - W_WeaponState_Save(self); - W_PrintWeaponMessage(); + W_ChangeWeapon(W_BestWeapon()); } void () player_axe1; @@ -1777,9 +1750,7 @@ void () W_Attack = { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); self.antispam_assault_cannon = time + 3; } - W_ChangeWeapon(W_BestWeaponSlot()); - W_UpdateCurrentWeapon(self); - W_WeaponState_Save(self); + W_ChangeToBestWeapon(); } else { self.ammo_cells = self.ammo_cells - 7; self.heat = 1; @@ -2069,548 +2040,168 @@ float (float inp) W_OldAmmoSlot = { return 1; }; -float () W_OldWeaponSlot1 = { - if (self.weapons_carried & WEAP_MEDIKIT) - return WEAP_MEDIKIT; - else if (self.weapons_carried & WEAP_KNIFE) - return WEAP_KNIFE; - else if (self.weapons_carried & WEAP_SPANNER) - return WEAP_SPANNER; - else - return WEAP_AXE; -}; - -float () W_OldWeaponSlot2 = { - if (self.playerclass == PC_SCOUT - ||self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO) - return WEAP_SHOTGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_SNIPER_RIFLE; - else if (self.playerclass == PC_SPY) - return WEAP_TRANQ; - else if (self.playerclass == PC_ENGINEER) - return WEAP_RAILGUN; - return 0; -}; - -float () W_OldWeaponSlot3 = { - if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - return WEAP_SUPER_SHOTGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_AUTO_RIFLE; - return 0; -}; - -float () W_OldWeaponSlot4 = { - if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - return WEAP_NAILGUN; - return 0; -}; - -float () W_OldWeaponSlot5 = { - if (self.playerclass == PC_MEDIC) - return WEAP_SUPER_NAILGUN; - else if (self.playerclass == PC_PYRO) - return WEAP_FLAMETHROWER; - return 0; -}; - -float () W_OldWeaponSlot6 = { - if (self.playerclass == PC_DEMOMAN) - return WEAP_GRENADE_LAUNCHER; - else if (self.playerclass == PC_PYRO) - return WEAP_FLAMETHROWER; - return 0; -}; - -float () W_OldWeaponSlot7 = { - if (self.playerclass == PC_SOLDIER) - return WEAP_ROCKET_LAUNCHER; - if (self.playerclass == PC_DEMOMAN) - return WEAP_PIPE_LAUNCHER; - else if (self.playerclass == PC_HVYWEAP) - return WEAP_ASSAULT_CANNON; - else if (self.playerclass == PC_PYRO) - return WEAP_INCENDIARY; - return 0; -}; - -float () W_WeaponSlot1 = { - local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - if (self.playerclass == PC_SCOUT) - return WEAP_NAILGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_SNIPER_RIFLE; - else if (self.playerclass == PC_SOLDIER) - return WEAP_ROCKET_LAUNCHER; - else if (self.playerclass == PC_DEMOMAN) - return WEAP_GRENADE_LAUNCHER; - else if (self.playerclass == PC_MEDIC) - return WEAP_SUPER_NAILGUN; - else if (self.playerclass == PC_HVYWEAP) - return WEAP_ASSAULT_CANNON; - else if (self.playerclass == PC_PYRO) - if (cf_pyro_impulses) { - return WEAP_FLAMETHROWER; - } else { - return WEAP_INCENDIARY; - } - else if (self.playerclass == PC_SPY) - return WEAP_TRANQ; - else if (self.playerclass == PC_ENGINEER) - return WEAP_RAILGUN; - return 0; -}; +struct ImpulseWeapons { + int class; + float weapons[7]; +}; + +static ImpulseWeapons impulse_weapons[] = { + { PC_UNDEFINED, { WEAP_AXE } }, + { PC_SCOUT, + { WEAP_AXE, WEAP_SHOTGUN, 0, WEAP_NAILGUN } }, + { PC_SNIPER, + { WEAP_AXE, WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN } }, + { PC_SOLDIER, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, + { PC_DEMOMAN, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, + { PC_MEDIC, + { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, + { PC_HVYWEAP, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, + { PC_PYRO, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, + { PC_SPY, + { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, + { PC_ENGINEER, + { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, + { PC_CIVILIAN, { WEAP_AXE } }, +}; + +float W_WeaponByImpulse(float impulse) { + if (impulse <= 1 || impulse >= 7) return 0; + return impulse_weapons[self.playerclass].weapons[impulse - 1]; +} -float () W_WeaponSlot2 = { - local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - if (self.playerclass == PC_SCOUT) - return WEAP_SHOTGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_AUTO_RIFLE; - else if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - return WEAP_SUPER_SHOTGUN; - else if (self.playerclass == PC_DEMOMAN) { - return WEAP_PIPE_LAUNCHER; - } else if (self.playerclass == PC_PYRO) - if (cf_pyro_impulses) { - return WEAP_INCENDIARY; - } else { - return WEAP_FLAMETHROWER; - } - return 0; -}; +static float HandlePyroSlotSwap(float slot) { + float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); + if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) + slot = 3 - slot; + return slot; +} -float () W_WeaponSlot3 = { - if (self.playerclass == PC_SCOUT - || self.playerclass == PC_ENGINEER) { +float W_WeaponBySlot(float slot) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, + HandlePyroSlotSwap(slot)); + if (!wi) { sprint(self, PRINT_HIGH, "No weapon\n"); return 0; } - if (self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - return WEAP_NAILGUN; - else if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO) - return WEAP_SHOTGUN; - return 0; -}; - -float () W_WeaponSlot4 = { - if (self.weapons_carried & WEAP_MEDIKIT) - return WEAP_MEDIKIT; - else if (self.weapons_carried & WEAP_KNIFE) - return WEAP_KNIFE; - else if (self.weapons_carried & WEAP_SPANNER) - return WEAP_SPANNER; - else - return WEAP_AXE; -}; - -void (float slot) W_WeaponSlot = { - if (slot == 1) - self.next_weapon = W_WeaponSlot1(); - else if (slot == 2) { - self.next_weapon = W_WeaponSlot2(); - } - else if (slot == 3) - self.next_weapon = W_WeaponSlot3(); - else if (slot == 4) - self.next_weapon = W_WeaponSlot4(); -}; - -void (float inp) W_OldWeaponSlot = { - if (inp == TF_SLOT1) { - self.next_weapon = W_OldWeaponSlot1(); - } - else if (inp == TF_SLOT2) { - self.next_weapon = W_OldWeaponSlot2(); - } - else if (inp == TF_SLOT3) { - self.next_weapon = W_OldWeaponSlot3(); - } - else if (inp == TF_SLOT4) { - self.next_weapon = W_OldWeaponSlot4(); - } - else if (inp == 5) { - self.next_weapon = W_OldWeaponSlot5(); - } - else if (inp == 6) { - self.next_weapon = W_OldWeaponSlot6(); - } - else if (inp == 7) { - self.next_weapon = W_OldWeaponSlot7(); - } - if (self.next_weapon == 0) { - self.next_weapon = self.current_weapon; - sprint(self, PRINT_HIGH, "No weapon\n"); - } + return wi->weapon; } -float (float newSlot) W_OldImpulseFromNewSlot = { - if (newSlot == 1) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_SNIPER_RIFLE); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_ROCKET_LAUNCHER); - } - else if (self.playerclass == PC_DEMOMAN) { - return 6; - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_SUPER_NAILGUN); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_ASSAULT_CANNON); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_INCENDIARY); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_TRANQ); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_RAILGUN); - } - } - else if (newSlot == 2) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_AUTO_RIFLE); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_DEMOMAN) { - return 7; - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_FLAMETHROWER); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - } - else if (newSlot == 3) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_DEMOMAN) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_RAILGUN); - } - } - else if (newSlot == 4) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_DEMOMAN) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_MEDIKIT); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_KNIFE); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_SPANNER); - } - } - return 0; +float W_GetWeaponByInput(float input) { + if (IsUsingOldImpulses()) + return W_WeaponByImpulse(input); + else + return W_WeaponBySlot(input); } -void () W_AmmoError = { +static void W_AmmoError() { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); else if (self.noammo == 2 && time >= self.antispam_assault_cannon) { sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); self.antispam_assault_cannon = time + 3; } -}; +} -void (entity pl) W_WeaponState_Save = { - if (!WeaponReady(pl)) +void W_ChangeWeaponByInput(float input) { + if (input < 1 || input > GetMaxWeaponInput()) return; - pl.weaponstate_current_weaponslot = pl.current_weaponslot; - pl.weaponstate_last_weaponslot = pl.last_weaponslot; - pl.weaponstate_current_weapon = pl.current_weapon; - pl.weaponstate_last_weapon = pl.last_weapon; -} - -void (entity pl, float swap) W_WeaponState_Load = { - if (!swap) { - pl.current_weaponslot = pl.weaponstate_current_weaponslot; - pl.last_weaponslot = pl.weaponstate_last_weaponslot; - pl.current_weapon = pl.weaponstate_current_weapon; - pl.last_weapon = pl.weaponstate_last_weapon; - } else { - pl.current_weaponslot = pl.weaponstate_last_weaponslot; - pl.last_weaponslot = pl.weaponstate_current_weaponslot; - pl.current_weapon = pl.weaponstate_last_weapon; - pl.last_weapon = pl.weaponstate_current_weapon; - } - pl.queue_weaponstate = 0; + float weapon = W_GetWeaponByInput(input); + if (weapon == 0) + return; - W_WeaponState_Save(pl); - W_UpdateCurrentWeapon(pl); - Status_Refresh(pl); + W_ChangeWeapon(weapon); } -float (entity pl) W_WeaponState_Check = { - // bprint(2,ftos(pl.current_weaponslot == pl.weaponstate_current_weaponslot)); - //bprint(2,"\n"); - if (pl.current_weaponslot == pl.weaponstate_current_weaponslot - && pl.last_weaponslot == pl.weaponstate_last_weaponslot) - return 1; - else - return 0; +void W_QueueAndDisableWeapon() { + self.queue_weapon = self.current_weapon; + // We don't want to actually call Update/Change since that could affect what + // other players see. Caller should be setting some state that holds back + // the queue (e.g. feigned). + self.current_weapon = WEAP_NONE; + self.weaponmodel = ""; + self.weaponframe = 0; } -void (float inp) W_ChangeWeapon = { - if(self.playerclass == PC_CIVILIAN) { - inp = TF_SLOT4; - } - - if (inp < TF_SLOT1 || inp > GetLastWeaponImpulse()) - return; - +void W_ChangeWeapon(float weapon) { if (self.playerclass == 0) return; // queue next weapon if queue is not empty or has changed - if (!self.queue_weaponslot || inp != self.queue_weaponslot) - self.queue_weaponslot = inp; + if (!self.queue_weapon || weapon != self.queue_weapon) + self.queue_weapon = weapon; // halt if weapon is not ready to be fired - if (!WeaponReady(self) && chweap_wait_attfinished) + if (!WeaponReady(self)) return; - - if (IsUsingOldImpulses()) { - if(self.playerclass == PC_CIVILIAN) { - inp = TF_SLOT1; - } - // check for ammo - if (! W_OldAmmoSlot(inp)) { - W_AmmoError(); - self.queue_weaponslot = 0; - return; - } - W_OldWeaponSlot(inp); - } - else { - // check for ammo - if (! W_AmmoSlot(inp)) { - W_AmmoError(); - self.queue_weaponslot = 0; - return; - } - W_WeaponSlot(inp); - } + self.queue_weapon = 0; - // don't update current/last weapon information if next weapon is the same as current - if (self.current_weapon != self.next_weapon) { - self.last_weaponslot = self.current_weaponslot; - self.current_weaponslot = self.queue_weaponslot; - self.last_weapon = self.current_weapon; - self.current_weapon = self.next_weapon; + FO_WeapState ws; + FO_FillWeapState(self, weapon, &ws); - if (!self.is_quickfiring) - W_PrintWeaponMessage(); + if (*ws->ammo_remaining == 0) { + W_AmmoError(); + return; } - if (!self.is_quickfiring && !self.has_quickfired) - W_WeaponState_Save(self); + if (self.current_weapon == weapon) + return; + + self.last_weapon = self.current_weapon; + + if (!self.is_quickfiring) + W_PrintWeaponMessage(); + self.current_weapon = weapon; W_UpdateCurrentWeapon(self); Status_Refresh(self); - self.queue_weaponslot = 0; }; -void () CycleWeaponLast = { - if (!self.last_weaponslot) +void W_ChangeWeaponLast() { + if (self.last_weapon == 0) return; - if (!self.is_quickfiring) - W_ChangeWeapon(self.last_weaponslot); - else - W_WeaponState_Load(self, 1); + W_ChangeWeapon(self.last_weapon); }; -void () CycleWeaponNext = { - local float slot, next; +float W_FindPrevNextWeapon(float weapon, float is_prev) { + int i; + float *table = IsUsingOldImpulses() ? + impulse_weapons[self.playerclass].weapons : + class_weapons[self.playerclass].slots; - if (self.weaponmodel == string_null || self.current_weapon == 0) - return; + float len = GetMaxWeaponInput(); + for (i = 0; i < len; i++) + if (table[i] == weapon) + break; - next = 0; - if (!IsUsingOldImpulses()) { - for (slot = 1; slot <= 4; slot++) { - next = (slot == 4) ? 1 : (slot + 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 4) ? 1 : (next + 1); - break; - } - } - } - else if (IsUsingOldImpulses()) { - for (slot = self.current_weaponslot; slot <= GetLastWeaponImpulse(); slot++) { - next = (slot == GetLastWeaponImpulse()) ? 1 : (slot + 1); - if (next == 1) { - if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) - break; - } - else if (next == 2) { - if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) - break; - } - else if (next == 3) { - if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) - break; - } - else if (next == 4) { - if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) - break; - } - else if (next == 5) { - if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) - break; - } - else if (next == 6) { - if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) - break; - } - else if (next == 7) { - if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) - break; - } - } - } - W_ChangeWeapon(next); -}; + float direction = is_prev ? -1 : 1; + do { + i = (i + direction + len) % len; + } while (table[i] == 0); -void () CycleWeaponPrev = { - local float slot, next; + return table[i]; +} +void W_ChangeWeaponNext() { if (self.weaponmodel == string_null || self.current_weapon == 0) return; - next = 0; - if (!IsUsingOldImpulses()) { - for (slot = 1; slot <= 4; slot++) { - next = (slot == 1) ? 4 : (slot - 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 1) ? 4 : (next - 1); - break; - } - } - } - else { - for (slot = self.current_weaponslot; slot >= 1; slot--) { - next = (slot == 1) ? GetLastWeaponImpulse() : (slot - 1); - if (next == 1) { - if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) - break; - } - else if (next == 2) { - if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) - break; - } - else if (next == 3) { - if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) - break; - } - else if (next == 4) { - if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) - break; - } - else if (next == 5) { - if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) - break; - } - else if (next == 6) { - if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) - break; - } - else if (next == 7) { - if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) - break; - } - } - } - + W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, FALSE)); +} - W_ChangeWeapon(next); -}; +void W_ChangeWeaponPrev() { + if (self.weaponmodel == string_null || self.current_weapon == 0) + return; + + W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, TRUE)); +} void () PreMatchImpulses; void () DeadImpulses; @@ -2660,19 +2251,19 @@ void () ImpulseCommands = { CF_Spy_DisguiseStop(); else if (self.playerclass == PC_ENGINEER && self.is_building) { TeamFortress_EngineerBuildStop(); - CycleWeaponLast(); + W_ChangeWeaponLast(); } else if (self.playerclass == PC_DEMOMAN && self.is_detpacking) { TeamFortress_DetpackStop(); - CycleWeaponLast(); + W_ChangeWeaponLast(); } } else if (self.impulse == TF_TOGGLEVOTE) Vote_ToggleMenu(self); if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { if (self.impulse == TF_WEAPNEXT) - CycleWeaponNext(); + W_ChangeWeaponNext(); else if (self.impulse == TF_WEAPPREV) - CycleWeaponPrev(); + W_ChangeWeaponPrev(); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); else if (self.impulse == TF_RELOAD_SLOT1) @@ -2824,9 +2415,9 @@ void () ImpulseCommands = { void () PreMatchImpulses = { if (self.impulse == TF_WEAPNEXT) - CycleWeaponNext(); + W_ChangeWeaponNext(); else if (self.impulse == TF_WEAPPREV) - CycleWeaponPrev(); + W_ChangeWeaponPrev(); if (self.impulse == TF_INVENTORY) TeamFortress_Inventory(); @@ -3210,16 +2801,9 @@ void () W_WeaponFrame = { return; if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { - - // change to last weapon now - if (WeaponReady(self)) - CycleWeaponLast(); - // change to weaponstate (prior to quick fire) when weapon is ready - else if (self.is_quickfiring) - self.queue_weaponstate = 2; - // change to last weapon when weapon is ready - else - self.queue_weaponslot = self.last_weaponslot; + W_ChangeWeaponLast(); + self.impulse = 0; + return; } // when +slotX bind is released, this gets issued @@ -3237,73 +2821,31 @@ void () W_WeaponFrame = { self.has_quickfired = 0; } + float can_change_weapon = WeaponReady(self) && + !self.is_detpacking && !(self.is_building && !engineer_move); - // slot 1-4 (or 1-7) binds - if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && (WeaponReady(self) || !chweap_wait_attfinished) - && !(self.is_building && !engineer_move) && !self.is_detpacking) { - - if (!(self.tfstate & TFSTATE_RELOADING)) { - // load weapon state if current state doesn't match stored state - if (!W_WeaponState_Check(self)) - W_WeaponState_Load(self, 0); - - // obviously not quickfiring if we're changing weapon - self.is_quickfiring = 0; - self.has_quickfired = 0; - W_ChangeWeapon(self.impulse); - } - else if (!chweap_wait_attfinished) { - //clears impulse so it doesn't switch weapons just after reloading - self.impulse = 0; - } - - // regular attack (both +attack and -attack) - } else if (!self.impulse && !self.is_quickfiring) { + if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() && + can_change_weapon) { + // slot 1-4 (or 1-7) binds - // load weapon state if current state doesn't match - // stored state, if weapon is ready - if (!W_WeaponState_Check(self) && WeaponReady(self) && !(self.tfstate & TFSTATE_AIMING)) { - W_WeaponState_Load(self, 0); - } + // obviously not quickfiring if we're changing weapon + self.is_quickfiring = 0; + self.has_quickfired = 0; + W_ChangeWeaponByInput(self.impulse); + self.impulse = 0; + } else if (self.impulse >= TF_QUICKSLOT1 && + self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { // +slot1-4 quick fire - } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && !self.is_detpacking) { self.is_quickfiring = 1; self.has_quickfired = 0; - if (WeaponReady(self)) { - if (!IsUsingOldImpulses()) { - if (self.impulse == TF_QUICKSLOT1) - W_ChangeWeapon(1); - else if (self.impulse == TF_QUICKSLOT2) - W_ChangeWeapon(2); - else if (self.impulse == TF_QUICKSLOT3) - W_ChangeWeapon(3); - else if (self.impulse == TF_QUICKSLOT4) - W_ChangeWeapon(4); - } else { - if (self.impulse == TF_QUICKSLOT1) - W_ChangeWeapon(W_OldImpulseFromNewSlot(1)); - else if (self.impulse == TF_QUICKSLOT2) - W_ChangeWeapon(W_OldImpulseFromNewSlot(2)); - else if (self.impulse == TF_QUICKSLOT3) - W_ChangeWeapon(W_OldImpulseFromNewSlot(3)); - else if (self.impulse == TF_QUICKSLOT4) - W_ChangeWeapon(W_OldImpulseFromNewSlot(4)); - } - } - + // Manually check so that we don't queue otherwise. + if (self.tfstate & TFSTATE_RELOADING) + W_ChangeWeapon(W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1)); + } else if (self.queue_weapon > 0 && can_change_weapon) { // change weapon if queue_weaponslot has been set - } else if (self.queue_weaponslot > 0) { - W_ChangeWeapon(self.queue_weaponslot); - // load weapon state - } else if (self.queue_weaponstate && WeaponReady(self)) { - // load weaponstate saved from before quick fire started - if (self.queue_weaponstate == 1) - W_WeaponState_Load(self, 0); - // load swapped weaponstate - else - W_WeaponState_Load(self, 1); + W_ChangeWeapon(self.queue_weapon); } if (self.impulse == TF_CHANGETEAM) { From 9027e1551ffd03fd738186c06c5ec7ba026a0e13 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 02:00:58 -0700 Subject: [PATCH 1675/2474] All of the quickfire stuff had gotten pretty messy, it's not needed now that weapon queuing just works. Rip it out. --- ssqc/qw.qc | 3 +-- ssqc/weapons.qc | 40 +++++++++++----------------------------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 5e7a6d23..3759b39e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -48,9 +48,8 @@ float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in -.float is_quickfiring; // TRUE for a player if they're using the quick slots .float is_concussed; // TRUE for a player who is affected by concussion grenade -.float has_quickfired; // TRUE for a player that has stopped quick firing (until weapon is ready) +.float qf_swap_last_weapon; // TRUE if +slotX was initated from another slot .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team .float has_changedclass; // TRUE for a player that has changed class diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ef9cfee6..b2aa72ff 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2155,9 +2155,6 @@ void W_ChangeWeapon(float weapon) { self.last_weapon = self.current_weapon; - if (!self.is_quickfiring) - W_PrintWeaponMessage(); - self.current_weapon = weapon; W_UpdateCurrentWeapon(self); Status_Refresh(self); @@ -2806,43 +2803,28 @@ void () W_WeaponFrame = { return; } - // when +slotX bind is released, this gets issued - if (self.impulse == TF_QUICKSTOP && self.is_quickfiring) { - - self.has_quickfired = 1; - self.impulse = 0; - - } - - // unset quick firing variables when quick weapon has finished firing - if (self.is_quickfiring && self.has_quickfired && WeaponReady(self)) { + // +slot/-slot handle attack; we only need to swap back to last weapon. + // Let's see if we can get away with just treating this as last weapon; + // there were already so many edge cases in the old code such as swapping on + // an empty weapon. + if (self.impulse == TF_QUICKSTOP) + self.impulse = self.qf_swap_last_weapon ? TF_WEAPLAST : 0; - self.is_quickfiring = 0; - self.has_quickfired = 0; - - } float can_change_weapon = WeaponReady(self) && !self.is_detpacking && !(self.is_building && !engineer_move); + // TODO: Open up queueing by moving queue can_change to ChangeWeapon? if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() && can_change_weapon) { // slot 1-4 (or 1-7) binds - - // obviously not quickfiring if we're changing weapon - self.is_quickfiring = 0; - self.has_quickfired = 0; - W_ChangeWeaponByInput(self.impulse); self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - // +slot1-4 quick fire - self.is_quickfiring = 1; - self.has_quickfired = 0; - - // Manually check so that we don't queue otherwise. - if (self.tfstate & TFSTATE_RELOADING) - W_ChangeWeapon(W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1)); + float weapon = W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1); + self.qf_swap_last_weapon = weapon != self.current_weapon; + W_ChangeWeapon(weapon); + self.impulse = 0; } else if (self.queue_weapon > 0 && can_change_weapon) { // change weapon if queue_weaponslot has been set W_ChangeWeapon(self.queue_weapon); From 59779cb19ae245e9eff8c0edcaa3caffdb71149d Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 02:22:41 -0700 Subject: [PATCH 1676/2474] Make detpacks work again. Just use ammo check rather than carried_items. --- ssqc/demoman.qc | 20 ++++---------------- ssqc/tfort.qc | 14 ++++++-------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 181b6b07..0dee0066 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -158,11 +158,6 @@ void (float timer) TeamFortress_SetDetpack = { self.impulse = 0; self.last_impulse = 0; - if (!(self.weapons_carried & WEAP_DETPACK)) { - sprint(self, PRINT_HIGH, "You don't have a detpack\n"); - return; - } - if (self.ammo_detpack <= 0) { sprint(self, PRINT_HIGH, "You don't have any detpacks left\n"); return; @@ -224,12 +219,9 @@ void (float timer) TeamFortress_SetDetpack = { self.ammo_detpack = self.ammo_detpack - 1; self.immune_to_check = time + 10; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - self.weapon = IT_AXE; - self.queue_weapon = self.current_weapon; - self.current_weapon = 0; - self.weaponmodel = ""; - self.weaponframe = 0; + self.weapon = IT_AXE; + W_QueueAndDisableWeapon(); Status_Refresh(self); TeamFortress_SetSpeed(self); @@ -266,10 +258,8 @@ void () TeamFortress_DetpackStop = { dremove(detpack_timer); self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - self.is_detpacking = 0; + self.is_detpacking = 0; // Weapon is queued. self.detpack_left = 0; - self.current_weapon = self.queue_weapon; - self.queue_weapon = 0; Status_Refresh(self); TeamFortress_SetSpeed(self); @@ -294,9 +284,7 @@ void () TeamFortress_DetpackSet = { FO_Sound(self.owner, CHAN_VOICE, "doors/medtry.wav", 1, ATTN_NORM); oldself = self; self = self.owner; - self.is_detpacking = 0; - self.current_weapon = self.queue_weapon; - self.queue_weapon = 0; + self.is_detpacking = 0; // Weapon is queued. Status_Refresh(self); self = oldself; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 7a7e4832..d6fac766 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -548,14 +548,12 @@ void () TeamFortress_Inventory = { if (current_weapons & WEAP_MEDIKIT) sprint(self, PRINT_HIGH, "Medikit\n"); - if (current_weapons & WEAP_DETPACK) { - if (self.ammo_detpack > 0) { - st = ftos(self.ammo_detpack); - sprint(self, PRINT_HIGH, st, " detpack"); - if (self.ammo_detpack > 1) - sprint(self, PRINT_HIGH, "s"); - sprint(self, PRINT_HIGH, "\n"); - } + if (self.ammo_detpack > 0) { + st = ftos(self.ammo_detpack); + sprint(self, PRINT_HIGH, st, " detpack"); + if (self.ammo_detpack > 1) + sprint(self, PRINT_HIGH, "s"); + sprint(self, PRINT_HIGH, "\n"); } if (self.playerclass == PC_SPY && invis_only) { From 70ac91786c22e65b9b69b5fba1ef3c44f577c9dc Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 27 Sep 2022 22:46:47 +1000 Subject: [PATCH 1677/2474] Remove the quad maxplayers stuff --- README.md | 1 - ssqc/clan.qc | 6 +----- ssqc/client.qc | 6 ------ ssqc/qw.qc | 1 - ssqc/world.qc | 1 - 5 files changed, 1 insertion(+), 14 deletions(-) diff --git a/README.md b/README.md index a17cb59b..8ad78ce9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ New features ------ * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) -* Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. * `+dropflag` Allows player to hold button and flag will be thrown on contact. diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 1662ef1a..ca1fadfb 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1084,17 +1084,13 @@ float () CheckAllPlayersReady = { local float f1 = TeamFortress_GetNoActivePlayers(); bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); + if (v_ready == f1 && v_ready > 0) { if(cease_fire) { bprint (2, "All players ready, match will start after ceasefire ends.\n"); } else { bprint (2, "All players ready, starting match\n"); StartTimer (); - - local float limit_quad_players = CF_GetSetting("lqp", "limit_quad_players", "on"); - if (limit_quad_players) { - quad_maxplayers = f1; - } } return 1; } diff --git a/ssqc/client.qc b/ssqc/client.qc index fce5138a..b297fa4c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3101,12 +3101,6 @@ void (optional float csqcactive) ClientConnect = { } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); - - local float numplayers = TeamFortress_GetNoActivePlayers (); - if (quadmode && quad_maxplayers && (numplayers >= quad_maxplayers)) { - sprint(self, PRINT_HIGH, "Match in progress, forcing to observer\n"); - forceinfokey(self, "*spectator", "1"); - } }; float () RejoinWithTfId = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4f95c30c..269b0b3b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -131,7 +131,6 @@ string nextmap; // // FortressMap stuff // -float quad_maxplayers; float number_of_teams; float illegalclasses; float illegalclasses1; diff --git a/ssqc/world.qc b/ssqc/world.qc index b6c3c8eb..4721c9d2 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -96,7 +96,6 @@ void () worldspawn = { lastspawn = world; number_of_teams = 0; - quad_maxplayers = 0; InitBodyQue(); if (self.model == "maps/e1m8.bsp") From b7084b1085ffe9940565b7fdcd0791bb043e33c8 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 21:36:17 -0700 Subject: [PATCH 1678/2474] Revert "Shot in the dark on a crash, remove primed_at from message temporarily." This reverts commit ce04953fefe97902f5853de7576e167083641fc6. --- csqc/events.qc | 5 ++--- ssqc/status.qc | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index e4713715..a6f5a9a3 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -101,8 +101,9 @@ void() CSQC_Parse_Event = { break; case MSG_GRENPRIMED: float grentype = readbyte(); + float primed_at = readfloat(); float explodes_at = readfloat(); - ParseGrenPrimed(grentype, 0, explodes_at); + ParseGrenPrimed(grentype, primed_at, explodes_at); break; case MSG_GRENTHROWN: CsGrenTimer last = CsGrenTimer::GetLast(); @@ -386,10 +387,8 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) return; -#if 0 if (primed_at < last_death_time) return; -#endif local float timer_flags = 0; switch (cvar(FOCMD_GRENTIMER)) { diff --git a/ssqc/status.qc b/ssqc/status.qc index 5945e463..f23d22cc 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -803,6 +803,7 @@ void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); WriteByte(MSG_MULTICAST, grentype); + WriteFloat(MSG_MULTICAST, time); WriteFloat(MSG_MULTICAST, explodes_at); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } From cd48be3847af849012418cfc29f8fae09807ce49 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 22:08:46 -0700 Subject: [PATCH 1679/2474] Migrate to autocvar and update default fo_grentimer Both because cvar string interaction is suspect in a crash and because autocvars are just better, migrate all* of our cvars to use autocvar. Also update fo_grentimer default to 2, it had not been updated to reflect the work on ping correction (either new or old). *: Some of the menu code uses dynamically constructed names which are incompatible with autocvar so we exclude those. --- csqc/csprogs.src | 2 +- csqc/events.qc | 11 +++++---- csqc/hud.qc | 2 +- csqc/hud_helpers.qc | 14 ------------ csqc/main.qc | 13 +++-------- csqc/menu.qc | 2 +- csqc/settings.qc | 56 +++++++++++++++++++++++++++++++++------------ 7 files changed, 53 insertions(+), 47 deletions(-) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 2aa77962..f61b3f0a 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -11,6 +11,7 @@ csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc +settings.qc sui_sys.qc vote.qc status.qc @@ -19,6 +20,5 @@ main.qc events.qc hud_helpers.qc hud.qc -settings.qc input.qc #endlist diff --git a/csqc/events.qc b/csqc/events.qc index a6f5a9a3..4c52eed2 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -308,7 +308,8 @@ DEFCVAR_FLOAT(fo_grentimer_debug, 0); string cached_timer; string GetGrenTimerSound() { - string wav = cvar_string(FOCMD_GRENTIMERSOUND); + string wav = CVARS(FOCMD_GRENTIMERSOUND); + if (cached_timer != wav) { precache_sound(wav); cached_timer = wav; @@ -336,8 +337,8 @@ void OldPlayGren(float offset) { } local string wav = GetGrenTimerSound(); - localsound(wav, channel, cvar(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime - soundupdate(self, channel, wav, cvar(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); + localsound(wav, channel, CVARF(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime + soundupdate(self, channel, wav, CVARF(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); } void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, @@ -357,7 +358,7 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, return; string wav = GetGrenTimerSound(); - float volume = cvar(FOCMD_GRENTIMERVOLUME); + float volume = CVARF(FOCMD_GRENTIMERVOLUME); // Note there's a bug where soundupdate returns false for a new sample, even // though it's started. @@ -391,7 +392,7 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { return; local float timer_flags = 0; - switch (cvar(FOCMD_GRENTIMER)) { + switch (CVARF(FOCMD_GRENTIMER)) { case 0: break; case 1: timer_flags = FL_GT_SOUND; break; // 2 [and something sane for anything we don't recognize.] diff --git a/csqc/hud.qc b/csqc/hud.qc index 6245acc8..4dea948e 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -660,7 +660,7 @@ void Hud_DrawFlagStatusBar(string panelid) { if (FlagInfoLines[i].id) { - alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? cvar("fo_hud_idle_alpha") : 1; + alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? CVARF(fo_hud_idle_alpha) : 1; string icon = FlagInfoLines[i].icon.filename; vector iconcolour = FlagInfoLines[i].icon.colour; float bigfont = 8 * (Hud_Panels[HUD_PANEL_FLAGINFO].TextScale ? Hud_Panels[HUD_PANEL_FLAGINFO].TextScale : Hud_Panels[HUD_PANEL_FLAGINFO].Scale); diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 218a2c76..385af80d 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -230,20 +230,6 @@ void Hud_DrawStringLMPThreshold(vector pos, string value, float size, float thre } } -string FormatCfgString(string line, string field, string value) -{ - line = strcat(line, "\n", field, ":", value); - - return line; -} - -string FormatCfgVector(string line, string field, vector value) -{ - line = strcat(line, "\n", field, ":", strcat(ftos(value_x), ",", ftos(value_y))); - - return line; -} - string GetPanelString(string line, string name) { line = FormatCfgVector(line, strcat(name, ".position"), DrawPanel.Position); diff --git a/csqc/main.qc b/csqc/main.qc index 7f5bd666..768a7851 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -36,11 +36,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_hud_save"); registercommand("fo_hud_load"); - registercvar(FOCMD_GRENTIMER, "1"); - registercvar(FOCMD_GRENTIMERSOUND, "grentimer.wav"); - registercvar(FOCMD_GRENTIMERVOLUME, "1"); - registercvar(FOCMD_JUMPVOLUME, "1"); - registercommand("fo_menu_game"); registercommand("fo_main_menu"); registercommand("fo_menu_team"); @@ -52,7 +47,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_build"); registercommand("fo_menu_dropammo"); registercommand("fo_menu_cancel"); - registercvar(FOCMD_ADMIN_MENU_UPDATE_TIME, "2"); registercommand("+aux_jump"); registercommand("-aux_jump"); @@ -82,7 +76,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("vote_addmap"); registercommand("vote_removemap"); - registercvar("fo_hud_idle_alpha", "0.3"); for(float i = 0; i < MENU_OPTION.length - 1; i++) { registercvar(strcat("fo_menu_option_",MENU_OPTION[i]), MENU_OPTION[i]); } @@ -143,7 +136,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if ((input_buttons & BUTTON2) && (pmove_vel_z < 180 /* not sliding */)) { if (jumpsound_cooldown < time) { jumpsound_cooldown = time + 0.01; - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + localsound("player/plyrjmp8.wav", CHAN_BODY, CVARF(FOCMD_JUMPVOLUME)); } } @@ -242,7 +235,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { Menu_Cancel(); break; case "+fo_showscores": - if (cvar(FOCMD_OLDSCOREBOARD) == 1) + if (CVARF(FOCMD_OLDSCOREBOARD) == 1) { tokenize(findkeysforcommand(argv(0))); @@ -271,7 +264,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "+showscores": case "+showteamscores": showingscores = TRUE; - if (cvar(FOCMD_OLDSCOREBOARD) != 1) + if (CVARF(FOCMD_OLDSCOREBOARD) != 1) { tokenize(findkeysforcommand(argv(0))); diff --git a/csqc/menu.qc b/csqc/menu.qc index 46adcd35..0ca07f8f 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -371,7 +371,7 @@ var fo_menu FO_MENU_DISPENSER_USE = { void updateAdminMenuInfo() = { if(admin_menu_next_update < time) { localcmd("cmd adminrefresh\n"); - admin_menu_next_update = time + cvar(FOCMD_ADMIN_MENU_UPDATE_TIME); + admin_menu_next_update = time + CVARF(FOCMD_ADMIN_MENU_UPDATE_TIME); } } diff --git a/csqc/settings.qc b/csqc/settings.qc index cdf3d3fd..88034d11 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -1,24 +1,50 @@ +// Saved/Loaded/Restored by Settings funcs +DEFCVAR_FLOAT(FOCMD_GRENTIMER, 2); // Sound + Ping adjust +DEFCVAR_STRING(FOCMD_GRENTIMERSOUND, "grentimer.wav"); +DEFCVAR_FLOAT(FOCMD_GRENTIMERVOLUME, 1); +DEFCVAR_FLOAT(FOCMD_JUMPVOLUME, 1); +DEFCVAR_FLOAT(FOCMD_OLDSCOREBOARD, 0); + +// CVARS that just pass via regular config state. +DEFCVAR_FLOAT(fo_hud_idle_alpha, 0.3); +DEFCVAR_FLOAT(FOCMD_ADMIN_MENU_UPDATE_TIME, 2); + +string FormatCfgString(string line, string field, string value) +{ + line = strcat(line, "\n", field, ":", value); + + return line; +} + +string FormatCfgVector(string line, string field, vector value) +{ + line = strcat(line, "\n", field, ":", strcat(ftos(value_x), ",", ftos(value_y))); + + return line; +} + + void FO_WriteSettings() { // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(cvar(FOCMD_GRENTIMER))); - line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, cvar_string(FOCMD_GRENTIMERSOUND)); - line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, cvar_string(FOCMD_GRENTIMERVOLUME)); - line = FormatCfgString(line, FOCMD_JUMPVOLUME, cvar_string(FOCMD_JUMPVOLUME)); - line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(cvar(FOCMD_OLDSCOREBOARD))); + string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(CVARF(FOCMD_GRENTIMER))); + line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, CVARS(FOCMD_GRENTIMERSOUND)); + line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, ftos(CVARF(FOCMD_GRENTIMERVOLUME))); + line = FormatCfgString(line, FOCMD_JUMPVOLUME, ftos(CVARF(FOCMD_JUMPVOLUME))); + line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(CVARF(FOCMD_OLDSCOREBOARD))); fputs(filehandle, line); fclose(filehandle); } void FO_LoadDefaultSettings() { - cvar_set(FOCMD_GRENTIMER, "1"); - cvar_set(FOCMD_GRENTIMERSOUND, "grentimer.wav"); - cvar_set(FOCMD_GRENTIMERVOLUME, "1"); - cvar_set(FOCMD_JUMPVOLUME, "1"); - cvar_set(FOCMD_OLDSCOREBOARD, "0"); + CVARF(FOCMD_GRENTIMER) = 2; + CVARS(FOCMD_GRENTIMERSOUND) = "grentimer.wav"; + CVARF(FOCMD_GRENTIMERVOLUME) = 1; + CVARF(FOCMD_JUMPVOLUME) = 1; + CVARF(FOCMD_OLDSCOREBOARD) = 0; } void FO_LoadSettings() @@ -48,19 +74,19 @@ void FO_LoadSettings() switch(field) { case FOCMD_GRENTIMER: - cvar_set(FOCMD_GRENTIMER, val); + CVARF(FOCMD_GRENTIMER) = stof(val); break; case FOCMD_GRENTIMERSOUND: - cvar_set(FOCMD_GRENTIMERSOUND, val); + CVARS(FOCMD_GRENTIMERSOUND) = val; break; case FOCMD_GRENTIMERVOLUME: - cvar_set(FOCMD_GRENTIMERVOLUME, val); + CVARF(FOCMD_GRENTIMERVOLUME) = stof(val); break; case FOCMD_JUMPVOLUME: - cvar_set(FOCMD_JUMPVOLUME, val); + CVARF(FOCMD_JUMPVOLUME) = stof(val); break; case FOCMD_OLDSCOREBOARD: - cvar_set(FOCMD_OLDSCOREBOARD, val); + CVARF(FOCMD_OLDSCOREBOARD) = stof(val); break; } } From e4b27882e339ef13673feb62b10e6e41cb43e02c Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 22:12:33 -0700 Subject: [PATCH 1680/2474] Move suspect string uop behind debug control --- csqc/events.qc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 4c52eed2..91f9e39e 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -310,9 +310,15 @@ string cached_timer; string GetGrenTimerSound() { string wav = CVARS(FOCMD_GRENTIMERSOUND); - if (cached_timer != wav) { - precache_sound(wav); - cached_timer = wav; + // The string NE-uop below is suspect in crashes. Possible interaction + // with cvar_string implementation. Hopefully the migration to autocvar + // resolves this, but also put it behind a debug control temporarily so we + // can test with/without. + if (CVARF("fo_grentimer_debug") & 8 == 1) { + if (cached_timer != wav) { + precache_sound(wav); + cached_timer = wav; + } } return wav; } From 432aaa729a20cd1147b00844801462ed0e1461b6 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 22:24:23 -0700 Subject: [PATCH 1681/2474] Messed up conflict resolution prior to push --- csqc/events.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index 91f9e39e..2f3c88ae 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -314,7 +314,7 @@ string GetGrenTimerSound() { // with cvar_string implementation. Hopefully the migration to autocvar // resolves this, but also put it behind a debug control temporarily so we // can test with/without. - if (CVARF("fo_grentimer_debug") & 8 == 1) { + if (CVARF(fo_grentimer_debug) & 8 == 1) { if (cached_timer != wav) { precache_sound(wav); cached_timer = wav; From 10748598238b9950c149d493dbe09545500cb5e2 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 22:52:41 -0700 Subject: [PATCH 1682/2474] Fix attack_finished nits A few weapons implement attacks via the animation code, namely the assault cannon, and both nailguns. While this had no interaction with the nailguns, as their own animation code was setting the same attack_finished values, this was causing problems with the assault cannon that uses out of band synchronization around spin-up/spin-down. For completeness, exclude all 3 from setting attack-finished. At some point nailguns can probably have it pulled out of the animation code but that's a question for another day (might matter for NG more than SNG). --- ssqc/hwguy.qc | 1 - ssqc/weapons.qc | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 174debaa..23336746 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -116,7 +116,6 @@ void FireAssCan (float shotcount, vector dir, vector spread) FO_WeapState ws; FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); - Status_Refresh(self); FO_CheckForReload(); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index b2aa72ff..8cb4b995 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1791,7 +1791,10 @@ void () W_Attack = { W_FireLaser(); } - if (self.current_weapon != WEAP_FLAMETHROWER) + if (self.current_weapon != WEAP_FLAMETHROWER && // Variable + self.current_weapon != WEAP_ASSAULT_CANNON && // In animation + self.current_weapon != WEAP_NAILGUN && // In animation + self.current_weapon != WEAP_SUPER_NAILGUN) // In animation Attack_Finished(wi->attack_time); if (wi->needs_reload) { From 1ce9c0de48ce46f7e2e6f61888a937290866ae2a Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 23:32:47 -0700 Subject: [PATCH 1683/2474] Fix weapon nits - Autorifle wasn't on the right slot for sniper - NG/SNG had bugs in both new and old code with attack finished interactions on running out of ammo (in the old code the animation would keep generating muzzle flashes, in the new code it would stop firing but not switch). Now properly works. - There was a ton of spaghetti in the old hwguy cannon implementation, missing weapon switches on certain ammo cases, duplication across multiple animation functions. Not all of this seemed to be working right so just rip it all out and rewrite it. Seems good now. --- share/fo_weapons.qc | 18 +++- ssqc/client.qc | 4 +- ssqc/player.qc | 206 ++++++++++++-------------------------------- ssqc/tfort.qc | 5 -- ssqc/weapons.qc | 45 +++++----- 5 files changed, 96 insertions(+), 182 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 86565b33..e2c002d9 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -22,6 +22,7 @@ float fo_hwguy = TRUE; float sniperreload = FALSE; float pyro_type = PYRO_FO; +float old_ng_rof = FALSE; #endif // Convert a weapon-bit to a linear index. @@ -78,13 +79,13 @@ FO_WeapInfo weapon_info[] = { { WEAP_SHOTGUN, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, AMMO_SHELLS, 16, 2, 0.7, 3 }, { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, - { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 4, 0.2, 0 }, + { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 2, 0.2, 0 }, { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, { WEAP_PIPE_LAUNCHER, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0, 4 }, + { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, @@ -94,6 +95,7 @@ FO_WeapInfo weapon_info[] = { inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { return &weapon_info[WEAP_to_index(weapon)]; } + struct FO_ClassWeapons { float id; float slots[4]; @@ -104,7 +106,7 @@ struct FO_ClassWeapons { FO_ClassWeapons class_weapons[] = { { PC_UNDEFINED, { 0, 0, 0, WEAP_AXE } }, { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, - { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, + { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_MEDIC, { WEAP_SUPER_NAILGUN, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_MEDIKIT } }, @@ -429,6 +431,14 @@ void FO_Weapons_Init() { WI_ir->attack_time = 0.9; break; } + // Consider just removing this? + if (old_ng_rof) { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_NAILGUN); + wi->ammo_per_shot = 2; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); + wi->ammo_per_shot = 4; + } + float clips_allocated = 0; for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; @@ -470,7 +480,7 @@ void FO_Weapons_Init() { case AMMO_NAILS: wti->ammo_mask = IT_NAILS; break; case AMMO_ROCKETS: wti->ammo_mask = IT_ROCKETS; break; } -} + } if (clips_allocated > CLIP_STORAGE_SIZE) error("Insufficient clip storage"); diff --git a/ssqc/client.qc b/ssqc/client.qc index 5cee5312..c74ade9f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2516,7 +2516,7 @@ void () PlayerJump = { self.weaponframe = 0; self.heat = 0; self.count = 1; - player_assaultcannondown1(); + player_assaultcannondown(); } return; } @@ -2545,7 +2545,7 @@ void () PlayerJump = { self.weaponframe = 0; self.count = 1; self.heat = 0; - player_assaultcannondown1(); + player_assaultcannondown(); } else { self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); diff --git a/ssqc/player.qc b/ssqc/player.qc index 895675ac..8b8277ff 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -387,7 +387,6 @@ void () player_nail1 =[103, player_nail2] { W_FireSpikes(-4); self.nailpos = 0; } - Attack_Finished(0.2); }; void () player_nail2 =[104, player_nail1] { @@ -409,185 +408,94 @@ void () player_nail2 =[104, player_nail1] { self.nailpos = 0; } } - Attack_Finished(0.2); }; -void () player_assaultcannonup1 =[103, player_assaultcannonup2] { - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; +static float CheckNeedAssaultCannonDown() { + FO_WeapState ws; + FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + + if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || + ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { + self.tfstate |= TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.count = 1; - self.heat = 0; - player_assaultcannondown1(); - return; + player_assaultcannondown(); + return TRUE; } + return FALSE; +} +void () player_assaultcannon; + +void () player_assaultcannonup =[103, player_assaultcannonup] { + if (CheckNeedAssaultCannonDown()) + return; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + self.fire_held_down = 1; - if (self.heat == 1) { + if (self.count == 0) FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - } + SuperDamageSound(); - Attack_Finished(0.2); - if ((self.heat != 2) && (self.heat != 4)) { - if (self.weaponframe >= 3) { - self.weaponframe = 0; - } else { - self.weaponframe = self.weaponframe + 1; - } - } - self.heat = self.heat + 1; - if (self.heat >= 7) { - self.heat = 0; - player_assaultcannon1(); - } + if ((self.heat != 2) && (self.heat != 4)) + self.weaponframe = (self.weaponframe + 1) % 4; + + if (self.count++ >= 5) // 600ms spin up + player_assaultcannon(); + else + Attack_Finished(wi->attack_time); }; -void () player_assaultcannonup2 =[103, player_assaultcannonup1] { - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.count = 1; - self.heat = 0; - player_assaultcannondown1(); +void () player_assaultcannon =[103, player_assaultcannon] { + if (CheckNeedAssaultCannonDown()) return; - } - SuperDamageSound(); - Attack_Finished(0.2); - if (((self.heat != 2) && (self.heat != 4)) && (self.heat != 7)) { - if ((self.weaponframe == 2) && (self.heat >= 9)) { - self.weaponframe = 0; - } else { - if (self.weaponframe >= 3) { - self.weaponframe = 0; - } else { - self.weaponframe = self.weaponframe + 1; - } - } - } - self.heat = self.heat + 1; - if (self.heat >= 13) { - self.heat = 0; - player_assaultcannon1(); - } -}; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); -void () player_assaultcannon1 =[103, player_assaultcannon2] { - if (fo_hwguy) - { - if (self.tfstate & TFSTATE_RELOADING || self.reload_assault_cannon == PC_HVYWEAP_ASSCAN_CLIPSIZE) - { - self.count = 1; - player_assaultcannondown1(); - return; + if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) + && !(self.tfstate & TFSTATE_LOCK)) { + if (self.count % 2 == 0) { + muzzleflash(); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); } - } - - if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) <= 30) - && !(self.tfstate & TFSTATE_LOCK)) { - muzzleflash(); - FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - - if (self.weaponframe == 2) - self.weaponframe = 4; - else - self.weaponframe = 2; SuperDamageSound(); + self.weaponframe = self.weaponframe == 2 ? 4 : 2; - self.tfstate = self.tfstate | TFSTATE_AIMING; + self.tfstate |= TFSTATE_AIMING; if (!cannon_move) - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + self.tfstate |= TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); - W_FireAssaultCannon(); + // Halve firing speed when moving too fast. + if (vlen(self.velocity) < 30 || self.count % 2 == 0) + W_FireAssaultCannon(); } else { FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); - - if (self.weaponframe == 2) - self.weaponframe = 0; - else - self.weaponframe = 2; + self.weaponframe = self.weaponframe == 2 ? 0 : 2; } - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - if (!cannon_move) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.count = 1; - player_assaultcannondown1(); - return; - } - Attack_Finished(0.2); -}; - -void () player_assaultcannon2 =[104, player_assaultcannon1] { - if (fo_hwguy) - { - if (self.tfstate & TFSTATE_RELOADING || self.reload_assault_cannon == PC_HVYWEAP_ASSCAN_CLIPSIZE) - { - self.count = 1; - player_assaultcannondown1(); - return; - } - } - if (vlen(self.velocity) < 30 && !(self.tfstate & TFSTATE_LOCK)) { - if (self.weaponframe == 2) { - self.weaponframe = 4; - } else { - self.weaponframe = 2; - } - SuperDamageSound(); - W_FireAssaultCannon(); - self.heat = self.heat + 0.1; - } else { - if (self.weaponframe == 2) { - self.weaponframe = 0; - } else { - self.weaponframe = 2; - } - } - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - if (!cannon_move) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.count = 1; - player_assaultcannondown1(); - return; - } - Attack_Finished(0.2); + self.count++; + Attack_Finished(wi->attack_time); }; -void () player_assaultcannondown1 =[103, player_assaultcannondown1] { - if (self.count == 1) { +void () player_assaultcannondown =[103, player_assaultcannondown] { + if (self.count == 0) FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); - self.heat = 0; - } - if (self.count >= 15) { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if (self.count >= 14) { self.fire_held_down = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); + self.tfstate &= ~TFSTATE_AIMING; if (!cannon_move) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.tfstate &= ~TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); - if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { + + player_run(); + if (self.ammo_cells < 7 || !FO_CheckForReload()) { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); - return; - } - player_run(); - return; - } - if ((((self.count != 8) && (self.count != 10)) && (self.count != 12)) - && (self.count != 14)) { - if (self.weaponframe == 3) { - self.weaponframe = 0; - } else { - self.weaponframe = self.weaponframe + 1; } - } - self.count = self.count + 1; - Attack_Finished(0.2); + } else if (++self.count % 2 == 0) + self.weaponframe = (self.weaponframe + 1) % 4; + Attack_Finished(wi->attack_time); }; void () player_light1 =[105, player_light2] { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index d6fac766..e08fb981 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2786,11 +2786,6 @@ void () TeamFortress_AssaultWeapon = { if (FO_CurrentWeaponsMask() & WEAP_ASSAULT_CANNON == 0) return; - if (self.heat > 0) { - sprint(self, PRINT_HIGH, "The Assault Cannon is still overheated\n"); - return; - } - if (self.ammo_shells < 1) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); return; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 8cb4b995..be6b8c27 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1374,13 +1374,12 @@ void (vector org, vector dir) launch_spike = { void () W_FireSuperSpikes = { local vector dir; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); FO_Sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); - if (old_ng_rof) - self.ammo_nails = self.ammo_nails - 4; - else - self.ammo_nails = self.ammo_nails - 2; + self.ammo_nails -= wi->ammo_per_shot; + dir = aim(self, 1000); launch_spike(self.origin + '0 0 16', dir); LogEventAttack(self); @@ -1389,31 +1388,33 @@ void () W_FireSuperSpikes = { FO_SetModel(newmis, "progs/s_spike.mdl"); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); KickPlayer(-3, self); + + Attack_Finished(wi->attack_time); }; void (float ox) W_FireSpikes = { local vector dir; + FO_WeapInfo* wi = FO_GetWeapInfo(self.current_weapon); makevectors(self.v_angle); - if (((self.ammo_nails >= 4) || ((self.ammo_nails >= 2) && !old_ng_rof)) && - (self.current_weapon == WEAP_SUPER_NAILGUN)) { - W_FireSuperSpikes(); - return; - } - if (self.ammo_nails < 1) { + + if (self.ammo_nails < wi->ammo_per_shot) { W_ChangeToBestWeapon(); return; + } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { + W_FireSuperSpikes(); + return; } + FO_Sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); - if ((self.ammo_nails == 1) || !old_ng_rof) { - self.ammo_nails = self.ammo_nails - 1; - } else { - self.ammo_nails = self.ammo_nails - 2; - } + self.ammo_nails -= wi->ammo_per_shot; + dir = aim(self, 1000); launch_spike(self.origin + '0 0 16' + v_right * ox, dir); LogEventAttack(self); KickPlayer(-3, self); + + Attack_Finished(wi->attack_time); }; void () t_climb = { @@ -1649,9 +1650,8 @@ void () player_light1; void () player_rocket1; void () player_autorifle1; -void () player_assaultcannon1; -void () player_assaultcannonup1; -void () player_assaultcannondown1; +void () player_assaultcannonup; +void () player_assaultcannondown; void () player_medikit1; void () player_medikitb1; @@ -1752,12 +1752,12 @@ void () W_Attack = { } W_ChangeToBestWeapon(); } else { - self.ammo_cells = self.ammo_cells - 7; - self.heat = 1; + self.ammo_cells -= - 7; + self.count = 0; self.immune_to_check = time + 5; self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); - player_assaultcannonup1(); + player_assaultcannonup(); } } else if (self.current_weapon == WEAP_FLAMETHROWER) { player_shot1(); @@ -1798,7 +1798,8 @@ void () W_Attack = { Attack_Finished(wi->attack_time); if (wi->needs_reload) { - *ws->clip_fired += wi->ammo_per_shot; + if (self.current_weapon != WEAP_ASSAULT_CANNON) // In animation + *ws->clip_fired += wi->ammo_per_shot; FO_CheckForReload(); } From d8006cc838eab5fb216154d0cee26f5782d767d5 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 17:36:31 -0700 Subject: [PATCH 1684/2474] Fix spin-down sound Moved an offset in prior commit, was skipping spindown sound on first frame --- ssqc/player.qc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 8b8277ff..04257777 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -418,7 +418,7 @@ static float CheckNeedAssaultCannonDown() { ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { self.tfstate |= TFSTATE_AIMING; TeamFortress_SetSpeed(self); - self.count = 1; + self.count = 0; player_assaultcannondown(); return TRUE; } @@ -481,7 +481,7 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (self.count >= 14) { + if (self.count >= 14) { // 1.5s down self.fire_held_down = 0; self.tfstate &= ~TFSTATE_AIMING; if (!cannon_move) @@ -493,8 +493,10 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); } - } else if (++self.count % 2 == 0) + } else if (self.count % 2 == 0) self.weaponframe = (self.weaponframe + 1) % 4; + + self.count++; Attack_Finished(wi->attack_time); }; From 0f3fac1cf01c9f90e5d8d646684f81a2af4e04f4 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 17:41:34 -0700 Subject: [PATCH 1685/2474] Roll everyone over to the new timer implementation by default Last step before deleting the old code and merging to master, everything seems to be working well for people now. Also confirmed that there was an FTE use-after-free bug in reading the grenade timer sound from cvar that was occasionally resulting in crashes. That bug is being fixed FTE side and our migration to auto-cvar in the meanwhile is sufficient to fix on ourside. This fixes client hitches so let's make sure everyone gets it again. --- csqc/events.qc | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 2f3c88ae..e6f072fc 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -310,15 +310,9 @@ string cached_timer; string GetGrenTimerSound() { string wav = CVARS(FOCMD_GRENTIMERSOUND); - // The string NE-uop below is suspect in crashes. Possible interaction - // with cvar_string implementation. Hopefully the migration to autocvar - // resolves this, but also put it behind a debug control temporarily so we - // can test with/without. - if (CVARF(fo_grentimer_debug) & 8 == 1) { - if (cached_timer != wav) { - precache_sound(wav); - cached_timer = wav; - } + if (cached_timer != wav) { + precache_sound(wav); + cached_timer = wav; } return wav; } @@ -406,10 +400,10 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { } float debug_print_state = CVARF(fo_grentimer_debug) & 1; - float debug_use_new_sound = CVARF(fo_grentimer_debug) & 2; + float debug_use_old_sound = CVARF(fo_grentimer_debug) & 4; float play_old_sound = FALSE; - if (!debug_use_new_sound) { + if (debug_use_old_sound) { play_old_sound = timer_flags & FL_GT_SOUND; timer_flags &= ~FL_GT_SOUND; } @@ -429,7 +423,7 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f new=%d\n", primed_at, explodes_at, explodes_at - primed_at, - debug_use_new_sound)); + !debug_use_old_sound)); print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", expires_ideal, expires_new, expires_old)); } From bf3960ae0c160421c88b6f0077e6bed7e5e22bc0 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 19:13:27 -0700 Subject: [PATCH 1686/2474] OOB slot check We've seen a single crash on an OOB array of size 4, this is the obvious candidate. --- share/fo_weapons.qc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index e2c002d9..9e7b32ff 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -222,8 +222,20 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_RAILGUN, IT_SHOTGUN}, }; +float BoundSlotInput(float slot) { + if (slot < 1 || slot > 4) { +#ifdef SSQC + sprint(self, PRINT_HIGH, sprintf("Error: slot %d OOB\n", slot)); +#endif + return 1; + } else { + return slot; + } +} + FO_WeapInfo* FO_ClassWeaponSlot(float class, float slot) { FO_ClassWeapons* cw = &class_weapons[class]; + slot = BoundSlotInput(slot); return cw->info[slot - 1] ? cw->info[slot - 1] : __NULL__; } From 4909e2c124ea4c50a647a206eae4d6cbedfbdb9a Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 21:18:45 -0700 Subject: [PATCH 1687/2474] Re-enable antilag It turns out the undefined optional behavior dominates default parameter, so: foo(optional int param = 1) Will be invoked with param = and not 1. This was disabling antilag by selecting an undefined mode with a max of 0. --- ssqc/antilag.qc | 12 ++++-------- ssqc/qw.qc | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 7d7bbad2..7c82b62c 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -351,12 +351,12 @@ void UnrewindPlayer(entity p) { .float client_time_internal; -float client_time(optional float ct_type = CT_NOEXTERNALEFFECT) { +float client_time(float ct_type = CT_NOEXTERNALEFFECT) { if (ct_type == CT_NOEXTERNALEFFECT) return self.client_time_internal; float offset = time - self.client_time_internal; - float max_offset = 0; + float max_offset = antilag_settings.max_client_time_offset; switch (ct_type) { case CT_SLOW_PROJECTILE: max_offset = antilag_settings.max_projectile_slow_offset; @@ -379,13 +379,9 @@ void AL_UpdateClientTime(entity player) { offset = min(offset, antilag_settings.max_client_time_offset); - float old_client_time = player.client_time_internal; - if (time - offset > player.client_time_internal) - player.client_time_internal = time - offset; - // Monotonically increasing and not dragging beyond 75% of time as/if RTT // changes. - player.client_time_internal = max(player.client_time_internal, - old_client_time + (1/77.0 * 0.75)); + player.client_time_internal = + max(time - offset, player.client_time_internal + (1/77.0 * 0.75)); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 3759b39e..bb776224 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -19,7 +19,7 @@ struct antilag_settings_t { // at t1: client_time() + o < at t2: client_time() + o FOR t2 > t1 // E.g. That you never have to worry about the correction reordering events // that `time + o` would not. -float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); +float client_time(float ct_type = CT_NOEXTERNALEFFECT); //=========================================================================== // TEAMFORTRESS Defs From 2d5c35fa019e3f2d80aa77e1304645455626b61d Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 29 Sep 2022 20:30:52 -0700 Subject: [PATCH 1688/2474] Fix impulse 1/7 We still support the old impulses when `old_weapon_impulses` is set, but the filtering was too aggressive (<=1 vs <1, same for 7). --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index be6b8c27..d02feb8a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2073,7 +2073,7 @@ static ImpulseWeapons impulse_weapons[] = { }; float W_WeaponByImpulse(float impulse) { - if (impulse <= 1 || impulse >= 7) return 0; + if (impulse < 1 || impulse > 7) return 0; return impulse_weapons[self.playerclass].weapons[impulse - 1]; } From 332c33e7ea226d3264c3643d22beec30d7dcc679 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 30 Sep 2022 16:32:24 +1000 Subject: [PATCH 1689/2474] Remove default_password remnants --- ssqc/quadmode.qc | 5 ----- ssqc/world.qc | 5 ----- 2 files changed, 10 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index c9554a11..9bae1afc 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -463,11 +463,6 @@ void () StartQuadRound = clan_scores_dumped = 1; } - if (infokey(world, "default_password") == "on") { - cvar_set("password", ""); - localcmd("localinfo default_password off\n"); - } - localcmd("stop\n"); return; } diff --git a/ssqc/world.qc b/ssqc/world.qc index 690d1bd6..b4a0cbe9 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -97,11 +97,6 @@ void () worldspawn = { lastspawn = world; number_of_teams = 0; - if (infokey(world, "default_password") == "on") { - cvar_set("password", ""); - localcmd("localinfo default_password off\n"); - } - InitBodyQue(); if (self.model == "maps/e1m8.bsp") cvar_set("sv_gravity", "100"); From 06882db5da35f1647aa14a740e9d7475dbbaa9db Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 30 Sep 2022 00:53:01 -0700 Subject: [PATCH 1690/2474] Ensure ping correction can't affect firing rate In adjusting attack_finished for ping we need to make this on both sides, e.g. when the client fires and when we subsequently check. In missing the second we'd allow firing rate to increase with latency. Also re-add catch-all that was previosuly present for no ammo and minor cleanup. --- ssqc/client.qc | 15 ++++++++------- ssqc/weapons.qc | 24 +++++++++++++----------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c74ade9f..a793df85 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2184,7 +2184,7 @@ void () PutClientInServer = { stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - self.attack_finished = time + 0.3; + self.attack_finished = client_time() + 0.3; self.th_pain = player_pain; self.th_die = PlayerDie; self.height = 0; @@ -2764,14 +2764,15 @@ void () PlayerPreThink = { self.velocity = '0 0 0'; } -#if 0 + // Catch all. FO_WeapState ws; - FO_FillWeapState(self, self.weapon, &ws); - if (time > self.attack_finished && !self.currentammo && self.weapon > WEAP_AXE) { - W_ChangeWeapon(W_BestWeaponSlot()); - W_WeaponState_Save(self); + FO_FillWeapState(self, self.current_weapon, &ws); + if ((client_time() > self.attack_finished) && + (self.current_weapon > WEAP_AXE) && + ((ws->wi)->ammo_type != AMMO_NONE)) { + if (*ws->ammo_remaining == 0) + W_ChangeToBestWeapon(); } -#endif }; void () CheckPowerups = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d02feb8a..2bee5f3b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -200,9 +200,11 @@ float () crandom = { void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) - self.attack_finished = client_time() + att_delay * 2; - else - self.attack_finished = client_time() + att_delay; + att_delay *= 2; + + // Ensure we hold firing rate constant with jitter. + self.attack_finished = max(client_time() + att_delay, + self.attack_finished + att_delay); }; float () W_FireAxe = { @@ -1810,12 +1812,12 @@ void () W_Attack = { LogEventAttack(self); }; -float (entity pl) WeaponReady = { - if (time >= pl.attack_finished && !(pl.tfstate & TFSTATE_RELOADING)) { - return 1; - } +float WeaponReady() { + if (client_time() >= self.attack_finished && + !(self.tfstate & TFSTATE_RELOADING)) + return TRUE; - return 0; + return FALSE; } void () W_PrintWeaponMessage = { @@ -2141,7 +2143,7 @@ void W_ChangeWeapon(float weapon) { self.queue_weapon = weapon; // halt if weapon is not ready to be fired - if (!WeaponReady(self)) + if (!WeaponReady()) return; self.queue_weapon = 0; @@ -2814,7 +2816,7 @@ void () W_WeaponFrame = { if (self.impulse == TF_QUICKSTOP) self.impulse = self.qf_swap_last_weapon ? TF_WEAPLAST : 0; - float can_change_weapon = WeaponReady(self) && + float can_change_weapon = WeaponReady() && !self.is_detpacking && !(self.is_building && !engineer_move); // TODO: Open up queueing by moving queue can_change to ChangeWeapon? @@ -2923,7 +2925,7 @@ void () W_WeaponFrame = { return; } - if (!WeaponReady(self)) + if (!WeaponReady()) return; if (self.impulse != 0 && self.has_disconnected == 0) From 4a9ee940647601f489da8b9d1d9b65e4ec996a69 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 30 Sep 2022 11:57:53 -0700 Subject: [PATCH 1691/2474] Move up prototype for CF_GetSetting Other changes in staging (proto from another file we pick up) were providing this for higher functions in the file. --- ssqc/antilag.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 195d41f1..c55baec6 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,3 +1,5 @@ +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; + void AL_ProjectProjectile (entity projectile) { // Project projectiles forward in time based on ping up to configurable maximum (default 100ms). // Effective projection time is maximum / 2 (eg 50ms), because we assume RTT is evenly distributed in both @@ -328,8 +330,6 @@ class FOPlayer { }; }; -float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; - float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { // Live changeagble for now. float project_detpipe = CF_GetSetting("pd", "project_detpipe", "on"); From fd020fc470c0431f4b52aac8ca7a932ed1fab262 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 30 Sep 2022 13:34:55 -0700 Subject: [PATCH 1692/2474] Tie attack_finished to client_time() for now The prior approach failed to account for the fact that some of weapon animations have attack_finished embedded in them, resulting in overlapping calls. This was pushing the finished time out unreasonably. Just remove the max for now, we're going to make some other changes that will smooth out client_time in the face of jitter anyway. --- share/fo_weapons.qc | 2 +- ssqc/player.qc | 5 +++-- ssqc/weapons.qc | 4 +--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 9e7b32ff..ced3c2cc 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -85,7 +85,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, + { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, diff --git a/ssqc/player.qc b/ssqc/player.qc index 04257777..b5cf4e1c 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -436,7 +436,7 @@ void () player_assaultcannonup =[103, player_assaultcannonup] { FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); SuperDamageSound(); - if ((self.heat != 2) && (self.heat != 4)) + if ((self.count != 2) && (self.count != 4)) self.weaponframe = (self.weaponframe + 1) % 4; if (self.count++ >= 5) // 600ms spin up @@ -493,8 +493,9 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); } - } else if (self.count % 2 == 0) + } else if (self.count % 2 == 0) { self.weaponframe = (self.weaponframe + 1) % 4; + } self.count++; Attack_Finished(wi->attack_time); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2bee5f3b..3ed4b966 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -202,9 +202,7 @@ void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) att_delay *= 2; - // Ensure we hold firing rate constant with jitter. - self.attack_finished = max(client_time() + att_delay, - self.attack_finished + att_delay); + self.attack_finished = client_time() + att_delay; }; float () W_FireAxe = { From f5c6a36d3a453bf3748f994ae06fe6ef5dee55de Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 29 Sep 2022 01:01:49 -0700 Subject: [PATCH 1693/2474] Delete unused FLAGINFO code --- csqc/main.qc | 9 ++------- ssqc/client.qc | 11 ----------- ssqc/status.qc | 7 ------- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3e7f7994..60b27f43 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -399,19 +399,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { }; void(float isnew) CSQC_Ent_Update = { - print("CSQC_Ent_Update, new: ", ftos(isnew), "\n"); float etype = readbyte(); - string s; switch (etype) { - case MSG_FLAGINFO: - s = readstring(); - print("CSQC_Ent_Update, Flag info: ", s, "\n"); - break; default: - error("Unhandled CSQC entity\n"); //you can change it to a print, but if you're not using sv_csqcdebug 1 doing so would just confuse people over the real cause. + error("Unhandled CSQC entity\n"); return; } }; + void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and will no longer be tracked... print("CSQC_Ent_Remove\n"); remove(self); diff --git a/ssqc/client.qc b/ssqc/client.qc index a793df85..cb1aab0a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -216,12 +216,6 @@ void InitPrematch() } } -void (entity goalitem) SetFlagSendMethod = { - if(goalitem) { - goalitem.SendEntity = SendClientFlagStatus; - } -} - void () DecodeLevelParms = { local float fl; local string st; @@ -263,11 +257,6 @@ void () DecodeLevelParms = { if ((number_of_teams <= 0) || (number_of_teams >= 5)) number_of_teams = 4; - //SetFlagSendMethod(Finditem(ent.display_item_status1)); - //SetFlagSendMethod(Finditem(ent.display_item_status2)); - //SetFlagSendMethod(Finditem(ent.display_item_status3)); - //SetFlagSendMethod(Finditem(ent.display_item_status4)); - } else { ent = find(world, classname, "info_player_team1"); diff --git a/ssqc/status.qc b/ssqc/status.qc index 8729cf1e..ce510d90 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -694,13 +694,6 @@ void (entity Player, entity Item) UpdateClientFlagStatus = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -float(entity playerent, float changedflags) SendClientFlagStatus = { - bprint(PRINT_HIGH, "SendClientFlagStatus, for: ",playerent.netname,"\n"); - WriteByte (MSG_ENTITY, MSG_FLAGINFO); - WriteString (MSG_ENTITY, self.mdl); - return TRUE; -} - string (entity Player, entity Item, float teamno) GetItemStatus = { local string st = ""; switch (teamno) From 04b56e4850571d7dbc71f1654ad787168fc3495e Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 30 Sep 2022 11:05:48 -0700 Subject: [PATCH 1694/2474] Make WeapState operate on current weapon and clip-storage be slot-based --- share/defs.h | 5 + share/fo_weapons.qc | 234 ++++++++++++++++++++++----------- ssqc/actions.qc | 37 ++---- ssqc/client.qc | 13 +- ssqc/engineer.qc | 14 +- ssqc/events.qc | 6 +- ssqc/items.qc | 45 ++----- ssqc/player.qc | 10 +- ssqc/pyro.qc | 22 ---- ssqc/qw.qc | 19 +-- ssqc/scout.qc | 4 +- ssqc/sniper.qc | 2 +- ssqc/status.qc | 6 +- ssqc/tfort.qc | 33 +---- ssqc/tfortmap.qc | 4 +- ssqc/vote.qc | 8 +- ssqc/weapons.qc | 313 ++++++++++++++++---------------------------- 17 files changed, 336 insertions(+), 439 deletions(-) diff --git a/share/defs.h b/share/defs.h index 49670e60..9b748b06 100644 --- a/share/defs.h +++ b/share/defs.h @@ -372,10 +372,15 @@ /*======================================================*/ /* Impulse Defines */ /*======================================================*/ +#define TF_SLOT_NONE 0 #define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) #define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) #define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) #define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_SLOT_LAST TF_SLOT4 +#define TF_SLOT_MELEE TF_SLOT4 +#define TF_NUM_SLOTS (TF_SLOT_LAST - TF_SLOT1 + 1) + #define TF_CLASSMENU 5 // Brings up class menu // unused 6 // unused 7 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index ced3c2cc..3826e537 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -4,13 +4,6 @@ * shared code. We'll refactor this on both sides to be cleaner incrementally, * but it gets us started. */ -.float reload_rocket_launcher; -.float reload_grenade_launcher; -.float reload_shotgun; -.float reload_super_shotgun; -.float reload_super_shotgun; -.float reload_assault_cannon; -.float reload_sniper_rifle; .float waterlevel; .float playerclass; @@ -57,10 +50,9 @@ struct FO_WeapInfo { float attack_time; float full_reload_time; - // Fields below this are automatically initialized by Init. Do not include - // in table. + // Fields below this are automatically initialized by Init. + // ** Do not include in table. ** float needs_reload; - int storage_index; // Allocated by init FO_WeapModels* models; FO_WeapToItem* items; }; @@ -114,6 +106,7 @@ FO_ClassWeapons class_weapons[] = { { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, + { PC_RANDOM, { 0, 0, 0, WEAP_AXE } }, // TODO: Probably needs attention { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; @@ -181,13 +174,12 @@ static float* AMMO_to_p(entity player, AmmoType ammo_type) { float WEAP_to_slot(float class, float weapon) { for (float i = 0; i < 4; i++) if (class_weapons[class].slots[i] == weapon) - return i; + return i + TF_SLOT1; return -1; } // Internal clip storage for both SSQC/CSQC. -#define CLIP_STORAGE_SIZE 8 -.float clip_fired[CLIP_STORAGE_SIZE]; +.float clip_fired[TF_SLOT_LAST - TF_SLOT1 + 1]; struct FO_WeapToItem { int weapon; @@ -223,46 +215,50 @@ FO_WeapToItem weapon_to_items[] = { }; float BoundSlotInput(float slot) { - if (slot < 1 || slot > 4) { -#ifdef SSQC - sprint(self, PRINT_HIGH, sprintf("Error: slot %d OOB\n", slot)); -#endif - return 1; + if (slot < TF_SLOT1 || slot > TF_SLOT4) { + return TF_SLOT4; } else { return slot; } } -FO_WeapInfo* FO_ClassWeaponSlot(float class, float slot) { +FO_WeapInfo* FO_SlotWeapInfo(float class, float slot) { + if (slot == TF_SLOT_NONE) + return FO_GetWeapInfo(WEAP_NONE); + FO_ClassWeapons* cw = &class_weapons[class]; slot = BoundSlotInput(slot); - return cw->info[slot - 1] ? cw->info[slot - 1] : __NULL__; + return cw->info[slot - TF_SLOT1] ? cw->info[slot - TF_SLOT1] : + FO_GetWeapInfo(WEAP_NONE); +} + +float FO_ClassWeaponBySlot(float class, float slot) { + FO_WeapInfo* wi = FO_SlotWeapInfo(class, slot); + if (!wi) + return WEAP_NONE; + + return wi->weapon; +} + +float FO_WeaponSlot(float slot) { + return FO_ClassWeaponBySlot(self.playerclass, slot); } -float FO_ClassWeapMask(float class) { + +float FO_ClassWeapItemMask(float class) { float result = 0; - for (int i = 1; i <= 4; i++) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); + for (int i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(class, i); if (wi) result |= (wi->items)->it_weapon; } return result; } -float FO_ClassWeaponItemMask(float class) { +float FO_WeaponsMask(entity player) { float mask = 0; - for (float i = 1; i <= 4; i++) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); - if (wi) - mask |= (wi->items)->it_weapon; - } - return mask; -} - -float FO_CurrentWeaponsMask() { - float mask = 0; - for (float i = 1; i <= 4; i++) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, i); + for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, i); if (wi) mask |= wi->weapon; } @@ -272,6 +268,7 @@ float FO_CurrentWeaponsMask() { #ifdef SSQC struct FO_WeapState { float weapon; + float slot; // Constant and relative to weapon. TODO, migrate similar to WeapInfo. FO_WeapInfo* wi; @@ -282,28 +279,49 @@ struct FO_WeapState { }; -void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { - ws->weapon = weapon; - FO_WeapInfo* wi = FO_GetWeapInfo(weapon); - ws->wi = wi; +void FO_FillWeapState(entity player, float slot, FO_WeapState* result) { + if (slot < 0 || slot > 4) error(sprintf("SLOT %d OOB\n", slot)); - if (wi->needs_reload) - ws->clip_fired = &player.clip_fired[wi->storage_index]; - ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, slot); + + result->weapon = wi->weapon; + result->slot = slot; + result->wi = wi; + + result->ammo_remaining = AMMO_to_p(player, wi->ammo_type); + + if (slot != TF_SLOT_NONE) + result->clip_fired = &player.clip_fired[slot - TF_SLOT1]; + else + result->clip_fired = __NULL__; +} + +float FO_ClassWeaponBySlot(float class, float slot); + +inline float FO_CurrentWeapon() { + return FO_ClassWeaponBySlot(self.playerclass, self.current_slot); +} + +inline float FO_PlayerCurrentWeapon(entity player) { + return FO_ClassWeaponBySlot(player.playerclass, player.current_slot); +} + +inline void FO_FillCurrentWeapState(FO_WeapState* result) { + FO_FillWeapState(self, self.current_slot, result); } -void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; void (float att_delay) Attack_Finished; static void FOT_ReloadTimer() { FO_WeapState ws; - FO_FillWeapState(self.owner, self.current_weapon, &ws); + FO_FillWeapState(self.owner, self.owner.current_slot, &ws); if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; self.owner.weaponmodel = ((ws->wi)->models)->model; + self.owner.weaponframe = 0; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); } else { @@ -318,9 +336,9 @@ static void FOT_ReloadTimer() { Status_Refresh(self.owner); } -float FO_CanReload(float weapon) { +float FO_CanReload(float slot) { FO_WeapState ws; - FO_FillWeapState(self, weapon, &ws); + FO_FillWeapState(self, slot, &ws); FO_WeapInfo* wi = ws->wi; if (wi->ammo_type == AMMO_NONE) @@ -333,29 +351,14 @@ float FO_CanReload(float weapon) { return FALSE; } -void () TeamFortress_ForceReloadCurrentWeapon; -float FO_CheckForReload() { - FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); - FO_WeapInfo* wi = ws->wi; - - if (wi->needs_reload && *ws->clip_fired >= wi->clip_size && - *ws->ammo_remaining > 0) { - if (force_reload) - TeamFortress_ForceReloadCurrentWeapon(); - return TRUE; - } else { - return FALSE; - } -} - -void FO_ReloadWeapon(float weapon, float force) { +void () RestoreDefaultWeapon; +void FO_ReloadSlot(float slot, float force) { RestoreDefaultWeapon(); if (self.tfstate & TFSTATE_RELOADING) return; FO_WeapState ws; - FO_FillWeapState(self, weapon, &ws); + FO_FillWeapState(self, slot, &ws); FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) @@ -398,12 +401,11 @@ void FO_ReloadWeapon(float weapon, float force) { // Actual entity that will update status bar / clear reload. entity reload_timer = spawn(); reload_timer.owner = self; - reload_timer.current_weapon = weapon; reload_timer.classname = "timer"; reload_timer.think = FOT_ReloadTimer; // TODO: Remove this hack. - if (weapon == WEAP_SNIPER_RIFLE) { + if (ws.weapon == WEAP_SNIPER_RIFLE) { self.reload_tick = 1; self.reload_sniper_ticks = 0; } @@ -416,13 +418,88 @@ void FO_ReloadWeapon(float weapon, float force) { } +float FO_CheckForReload() { + FO_WeapState ws; + FO_FillCurrentWeapState(&ws); + FO_WeapInfo* wi = ws->wi; + + if (wi->needs_reload && *ws->clip_fired >= wi->clip_size && + *ws->ammo_remaining > 0) { + if (force_reload) + FO_ReloadSlot(self.current_slot, TRUE); + return TRUE; + } else { + return FALSE; + } +} + void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; - for (int i = 0; i < CLIP_STORAGE_SIZE; i++) + for (int i = 0; i < 4; i++) player.clip_fired[i] = 0; } #endif +struct ImpulseWeapon { + int class; + float weapons[7]; + + // Autogenerated + float slots[7]; +}; + +ImpulseWeapon impulse_weapons[] = { + { PC_UNDEFINED, { WEAP_AXE } }, + { PC_SCOUT, + { WEAP_AXE, WEAP_SHOTGUN, 0, WEAP_NAILGUN } }, + { PC_SNIPER, + { WEAP_AXE, WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN } }, + { PC_SOLDIER, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, + { PC_DEMOMAN, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, + { PC_MEDIC, + { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, + { PC_HVYWEAP, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, + { PC_PYRO, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, + { PC_SPY, + { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, + { PC_ENGINEER, + { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, + { PC_CIVILIAN, { WEAP_AXE } }, +}; + +float FO_ImpulseToSlot(float impulse) { + if (impulse < 1 || impulse > 7) return 0; + return impulse_weapons[self.playerclass].slots[impulse - 1]; +} + +#ifdef SSQC +float IsUsingOldImpulses(); + +float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; +static float IsPyroSlotSwapped() { + return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); +} +#else +float IsUsingOldImpulses() { return FALSE; } + +static float IsPyroSlotSwapped() { return FALSE; } +#endif + +static float HandlePyroSlotSwap(float slot) { + float cf_pyro_impulses = IsPyroSlotSwapped(); + if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) + slot = 3 - slot; + return slot; +} + +float FO_SlotByInput(float input) { + return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : input; +} + void FO_Weapons_Init() { float i, j; @@ -451,7 +528,6 @@ void FO_Weapons_Init() { wi->ammo_per_shot = 4; } - float clips_allocated = 0; for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; if (WEAP_to_index(wi->weapon) != i) @@ -461,24 +537,17 @@ void FO_Weapons_Init() { FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); wi->ammo_type = parent->ammo_type; wi->clip_size = parent->clip_size; - wi->storage_index = parent->storage_index; wi->full_reload_time = parent->full_reload_time; wi->needs_reload = parent->needs_reload; } else if (wi->clip_size > 0) { wi->needs_reload = TRUE; - // We always allocate a storage index for something that can have - // reload to save negotiating between client and server around - // localinfo tunables. - wi->storage_index = clips_allocated++; } else { wi->needs_reload = FALSE; - wi->storage_index = -1; // Make sure we'll OOB. } FO_WeapModels* wm = &weapon_models[i]; if (WEAP_to_index(wm->weapon) != i) error(sprintf("WM mismatch at index %d\n", i)); - precache_model(wm->model); wi->models = wm; @@ -493,8 +562,6 @@ void FO_Weapons_Init() { case AMMO_ROCKETS: wti->ammo_mask = IT_ROCKETS; break; } } - if (clips_allocated > CLIP_STORAGE_SIZE) - error("Insufficient clip storage"); for (i = 0; i < class_weapons.length; i++) { for (j = 0; j < 4; j++) { @@ -503,7 +570,16 @@ void FO_Weapons_Init() { if (cw->slots[j]) cw->info[j] = &weapon_info[WEAP_to_index(cw->slots[j])]; else - cw->info[j] = __NULL__; + cw->info[j] = &weapon_info[0]; // WEAP_NONE } } + + for (i = 0; i < impulse_weapons.length; i++) { + ImpulseWeapon* iw = &impulse_weapons[i]; + + for (j = 0; j < 7; j++) + if (iw->weapons[j]) + iw->slots[j] = WEAP_to_slot(iw->class, iw->weapons[j]); + } } + diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 452585f0..0367bffd 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -469,39 +469,28 @@ void (entity pe_player, float f_type) CF_Identify = { void () RestoreDefaultWeapon = { float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); if (default_weapon >= 1 && default_weapon <= 4) { - W_ChangeWeapon(W_WeaponBySlot(default_weapon)); + W_ChangeWeaponSlot(default_weapon); } }; -void () TeamFortress_ReloadCurrentWeapon = { - FO_ReloadWeapon(self.current_weapon, FALSE); -}; - -void () TeamFortress_ForceReloadCurrentWeapon = { - FO_ReloadWeapon(self.current_weapon, TRUE); -}; - -void (float slot) TeamFortress_ReloadSlot = { - float weap = W_WeaponBySlot(slot); - - FO_ReloadWeapon(weap, FALSE); -} - -float W_FindPrevNextWeapon(float weapon, float is_prev); - void () TeamFortress_ReloadNext = { - float weapon = self.current_weapon; + float slot = self.current_slot; + + if (!FO_CanReload(slot)) { + for (int i = 1; i < TF_NUM_SLOTS; i++) { + slot = slot + 1; // Easier to read than mod version because 1-base. + if (slot > TF_SLOT_LAST) + slot -= TF_NUM_SLOTS; + sprint(self, PRINT_HIGH, sprintf("checking %d\n", slot)); - if (!FO_CanReload(weapon)) { - for (int i = 0; i < 3; i++) { - weapon = W_FindPrevNextWeapon(weapon, FALSE); - if (FO_CanReload(weapon)) + if (FO_CanReload(slot)) break; } } - if (FO_CanReload(weapon)) { - FO_ReloadWeapon(weapon, FALSE); + if (FO_CanReload(slot)) { + sprint(self, PRINT_HIGH, sprintf("reloading %d\n", slot)); + FO_ReloadSlot(slot, FALSE); RestoreDefaultWeapon(); } else { sprint(self, PRINT_HIGH, "All clips full\n"); diff --git a/ssqc/client.qc b/ssqc/client.qc index cb1aab0a..68d3da8e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -118,7 +118,7 @@ void () SetChangeParms = { parm5 = self.ammo_nails; parm6 = self.ammo_rockets; parm7 = self.ammo_cells; - parm8 = self.current_weapon; + parm8 = self.current_slot; parm9 = self.armortype * 100; parm10 = 0; parm11 = 0; @@ -2497,7 +2497,7 @@ void () PlayerJump = { else FO_Sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } - if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); @@ -2521,7 +2521,7 @@ void () PlayerJump = { FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); - if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { if (!cannon_air) { if (self.antispam_cannon_air < time) { sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); @@ -2755,10 +2755,9 @@ void () PlayerPreThink = { // Catch all. FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); if ((client_time() > self.attack_finished) && - (self.current_weapon > WEAP_AXE) && - ((ws->wi)->ammo_type != AMMO_NONE)) { + (ws.weapon > WEAP_AXE) && ((ws->wi)->ammo_type != AMMO_NONE)) { if (*ws->ammo_remaining == 0) W_ChangeToBestWeapon(); } @@ -2935,7 +2934,7 @@ void () PlayerPostThink = { fop.RewindUpdate(); FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 8080473a..9b3beb0c 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -402,10 +402,10 @@ void () TeamFortress_EngineerBuildStop = { self.is_building = 0; self.building_percentage = 0; if (!engineer_move) { - self.current_weapon = self.weapon; - self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; + self.tfstate &= ~TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_WALK; TeamFortress_SetSpeed(self); + // Old weapon already queued. } } @@ -555,10 +555,8 @@ void (float objtobuild) TeamFortress_Build = { self.immune_to_check = time + 5; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_NONE; - self.weapon = self.current_weapon; - self.current_weapon = 0; - self.weaponmodel = ""; - self.weaponframe = 0; + + W_QueueAndDisableWeapon(); TeamFortress_SetSpeed(self); Menu_Engineer_Cancel(); } @@ -906,10 +904,10 @@ void () TeamFortress_FinishedBuilding = { self.is_building = FALSE; self.building_percentage = 0; if (!engineer_move) { - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.tfstate &= ~TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_WALK; - self.current_weapon = self.weapon; TeamFortress_SetSpeed(self); + // Weapon should be queued. } Status_Refresh(self); diff --git a/ssqc/events.qc b/ssqc/events.qc index 77be41b7..fbeda3f9 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -170,7 +170,7 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon); + inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -272,7 +272,7 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { killKind = "enemy"; if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon); + inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -386,7 +386,7 @@ void (entity attacker) LogEventAttack = { if (canlog == 0) return; local string event; - event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(attacker.current_weapon), ftos(gametime), gametimestamp); + event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(FO_PlayerCurrentWeapon(attacker)), ftos(gametime), gametimestamp); logevent(event); } diff --git a/ssqc/items.qc b/ssqc/items.qc index a9cfc7d7..8cea4a1a 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -241,7 +241,7 @@ void () health_touch = { } } else { if (!T_Heal(other, self.healamount, 0)) { - if (other.weapons_carried & 4) { + if (FO_WeaponsMask(other) & WEAP_MEDIKIT) { if (other.ammo_medikit < other.maxammo_medikit) { other.ammo_medikit = other.ammo_medikit + self.healamount; @@ -317,7 +317,6 @@ void () armor_touch = { local float value; local float bit; local string s; - local entity oldself; if (other.health <= 0) { return; @@ -395,9 +394,6 @@ void () armor_touch = { if (other.ammo_cells > other.maxammo_cells) { other.ammo_cells = other.maxammo_cells; } - oldself = self; - self = other; - self = oldself; } value = other.maxarmor; } @@ -507,9 +503,6 @@ float (float w) RankForWeapon = { return 7; }; -void (float old, float new) Deathmatch_Weapon = { -}; - void () ammo_touch; void (entity ritem, entity act) Respawn_Item = { @@ -531,15 +524,12 @@ void (entity ritem, entity act) Respawn_Item = { self = oldself; }; -float () W_BestWeapon; - void () weapon_touch = { local float hadammo; - local float best; local float new; local float old; - local entity stemp; local float leave; + float other_weapons_carried = FO_WeaponsMask(other); new = 0; if (!(other.flags & 8)) @@ -551,17 +541,13 @@ void () weapon_touch = { if (cb_prematch == 1) return; - stemp = self; - self = other; - best = W_BestWeapon(); - self = stemp; if ((deathmatch == 2) || coop) { leave = 1; } else { leave = 0; } if (self.classname == "weapon_nailgun") { - if (leave && (other.weapons_carried & WEAP_NAILGUN)) { + if (leave && (other_weapons_carried & WEAP_NAILGUN)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_NAILGUN)) { @@ -572,7 +558,7 @@ void () weapon_touch = { other.ammo_nails = other.ammo_nails + 30; } else { if (self.classname == "weapon_supernailgun") { - if (leave && (other.weapons_carried & WEAP_SUPER_NAILGUN)) { + if (leave && (other_weapons_carried & WEAP_SUPER_NAILGUN)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_SUPER_NAILGUN)) { @@ -583,7 +569,7 @@ void () weapon_touch = { other.ammo_nails = other.ammo_nails + 30; } else { if (self.classname == "weapon_supershotgun") { - if (leave && (other.weapons_carried & WEAP_SUPER_SHOTGUN)) { + if (leave && (other_weapons_carried & WEAP_SUPER_SHOTGUN)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_SUPER_SHOTGUN)) { @@ -594,7 +580,7 @@ void () weapon_touch = { other.ammo_shells = other.ammo_shells + 5; } else { if (self.classname == "weapon_rocketlauncher") { - if (leave && (other.weapons_carried & WEAP_ROCKET_LAUNCHER)) { + if (leave && (other_weapons_carried & WEAP_ROCKET_LAUNCHER)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_ROCKET_LAUNCHER)) { @@ -605,7 +591,7 @@ void () weapon_touch = { other.ammo_rockets = other.ammo_rockets + 5; } else { if (self.classname == "weapon_grenadelauncher") { - if (leave && (other.weapons_carried & WEAP_GRENADE_LAUNCHER)) { + if (leave && (other_weapons_carried & WEAP_GRENADE_LAUNCHER)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_GRENADE_LAUNCHER)) { @@ -616,7 +602,7 @@ void () weapon_touch = { other.ammo_rockets = other.ammo_rockets + 5; } else { if (self.classname == "weapon_lightning") { - if (leave && (other.weapons_carried & WEAP_LIGHTNING)) { + if (leave && (other_weapons_carried & WEAP_LIGHTNING)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_LIGHTNING)) { @@ -637,12 +623,6 @@ void () weapon_touch = { FO_Sound(other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM); stuffcmd(other, "bf\n"); bound_other_ammo(other); - old = other.weapons_carried; - other.weapons_carried = other.weapons_carried | new; - stemp = self; - self = other; - Deathmatch_Weapon(old, new); - self = stemp; if (leave) return; Respawn_Item(self, other); @@ -810,8 +790,6 @@ float () GetGrenadePossibility = { }; void () ammo_touch = { - local entity stemp; - local float best; local float gotgren; local float gotbox; @@ -829,10 +807,6 @@ void () ammo_touch = { } gotgren = 0; gotbox = 0; - stemp = self; - self = other; - best = W_BestWeapon(); - self = stemp; if (self.weapon == 1) { if (other.ammo_shells >= TeamFortress_GetMaxAmmo(other, 256)) { return; @@ -874,9 +848,6 @@ void () ammo_touch = { if (gotbox) { bound_other_ammo(other); sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); - stemp = self; - self = other; - self = stemp; } Respawn_Item(self, other); }; diff --git a/ssqc/player.qc b/ssqc/player.qc index b5cf4e1c..a81a28f2 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -90,7 +90,7 @@ void () player_stand1 =[17, player_stand1] { player_run(); return; } - if (self.current_weapon <= 16) { + if (self.current_slot == TF_SLOT_MELEE) { if (self.walkframe >= 12) { self.walkframe = 0; } @@ -111,7 +111,7 @@ void () player_run =[6, player_run] { player_stand1(); return; } - if (self.current_weapon <= 16) { + if (FO_CurrentWeapon() <= WEAP_AXE) { if (self.walkframe >= 6) { self.walkframe = 0; } @@ -682,10 +682,10 @@ void (entity et, float f) player_pain = { PainSound(); return; } - if (self.button0 && (self.current_weapon == 32768)) + if (self.button0 && (FO_CurrentWeapon() == WEAP_INCENDIARY)) return; - if (self.current_weapon <= 16) + if (FO_CurrentWeapon() <= WEAP_AXE) player_axpain1(); else player_pain1(); @@ -925,7 +925,7 @@ void () PlayerDie = { DeathSound(); self.angles_x = 0; self.angles_z = 0; - if (self.current_weapon <= 16) { + if (FO_CurrentWeapon() <= WEAP_AXE) { player_die_ax1(); TeamFortress_SetupRespawn(0); return; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index c09a4c2d..6468290b 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -711,28 +711,6 @@ void () W_FireIncendiaryCannon = { } }; -void () TeamFortress_IncendiaryCannon = { - if (!(self.weapons_carried & WEAP_INCENDIARY)) { - return; - } - if (self.ammo_rockets < 3) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } - self.current_weapon = WEAP_INCENDIARY; -}; - -void () TeamFortress_FlameThrower = { - if (!(self.weapons_carried & WEAP_FLAMETHROWER)) { - return; - } - if (self.ammo_cells < 1) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } - self.current_weapon = WEAP_FLAMETHROWER; -}; - void () AirBlastReloadFinished = { self.owner.airblast_cooldown = 0; sprint(self.owner, PRINT_HIGH, "Airblast ready\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bb776224..7f46aef5 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -49,7 +49,7 @@ float client_time(float ct_type = CT_NOEXTERNALEFFECT); .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float is_concussed; // TRUE for a player who is affected by concussion grenade -.float qf_swap_last_weapon; // TRUE if +slotX was initated from another slot +.float qf_swap_last_slot; // TRUE if +slotX was initiated from another slot .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team .float has_changedclass; // TRUE for a player that has changed class @@ -206,18 +206,9 @@ float coop; /*==============================================*/ /* New Weapon variables */ /*==============================================*/ -.float weapons_carried; // the weapons the player is carrying -.float current_weapon; // the weapon the player is using -.float last_weapon; // the last weapon the player was using -.float current_weaponslot; // the currently equipped weaponslot -.float last_weaponslot; // the last equipped weaponslot -.float queue_weapon; // the weapon to switch to when possible - -// weapon states -.float weaponstate_current_weaponslot; -.float weaponstate_last_weaponslot; -.float weaponstate_current_weapon; -.float weaponstate_last_weapon; +.float current_slot; // the currently equipped (weapon) slot +.float last_slot; // the last slot the player was using +.float queue_slot; // the slot to switch to when possible .float ammo_medikit; // Ammo used for the medikit .float maxammo_medikit; @@ -226,7 +217,7 @@ float coop; .float noammo; // used for no ammo error messages // variables used for reloading -.float reload_shotgun; +.float reload_shotgun; // Only use for map compatibility. .float reload_super_shotgun; .float reload_sniper_rifle; .float reload_grenade_launcher; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 0d5ce0de..927f7a57 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -484,7 +484,9 @@ void () ConcussionGrenadeTimer = { pos = pointcontents(src); if ((self.owner.flags & 512) || (self.owner.flags & 16)) { - if (!self.owner.is_feigning && !(self.owner.current_weapon == WEAP_ASSAULT_CANNON && !cannon_conc && self.owner.button0)) { + if (!self.owner.is_feigning && + !(FO_PlayerCurrentWeapon(self.owner) == WEAP_ASSAULT_CANNON && + !cannon_conc && self.owner.button0)) { makevectors(self.owner.v_angle); stumble = crandom() * self.health; if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { diff --git a/ssqc/sniper.qc b/ssqc/sniper.qc index a5d7bb61..49ab796e 100644 --- a/ssqc/sniper.qc +++ b/ssqc/sniper.qc @@ -119,7 +119,7 @@ void () SniperSight_Update = { local vector org; if (!(self.owner.tfstate & TFSTATE_AIMING) || - (self.owner.current_weapon != WEAP_SNIPER_RIFLE)) { + (FO_PlayerCurrentWeapon(self.owner) != WEAP_SNIPER_RIFLE)) { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_AIMING); diff --git a/ssqc/status.qc b/ssqc/status.qc index ce510d90..156ba7ee 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -745,7 +745,7 @@ string GetSBClipString(entity pl, float csqcactive) string msg = ""; if (pl.tfstate & TFSTATE_RELOADING) { - FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); + FO_WeapInfo* wi = FO_GetWeapInfo(FO_PlayerCurrentWeapon(pl)); if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); @@ -1326,7 +1326,7 @@ string(float num) GreenScoreToString = string(entity pl, float csqcactive) ClipSizeToString = { FO_WeapState ws; - FO_FillWeapState(pl, pl.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) @@ -1474,7 +1474,7 @@ string(entity pl) AuraToString = string(entity pl) AssaultCannonToString = { - if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_LOCK)) + if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_LOCK)) return Q"\sAssault Cannon Locked\s"; else return ""; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e08fb981..f5ea8890 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -340,7 +340,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(W_BestWeapon()); + W_ChangeToBestWeapon(); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; @@ -544,7 +544,7 @@ void () TeamFortress_Inventory = { if (self.tf_items & NIT_SCANNER) sprint(self, PRINT_HIGH, "Scanner\n"); - float current_weapons = FO_CurrentWeaponsMask(); + float current_weapons = FO_WeaponsMask(self); if (current_weapons & WEAP_MEDIKIT) sprint(self, PRINT_HIGH, "Medikit\n"); @@ -1565,11 +1565,11 @@ void () TeamFortress_SetEquipment = { Team_Role * role = GetTeamRole(self.team_no); kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); - self.items = FO_ClassWeaponItemMask(self.playerclass) | kept_items; + self.items = FO_ClassWeapItemMask(self.playerclass) | kept_items; if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { - self.current_weapon = 0; - self.last_weapon = 0; + self.current_slot = 0; + self.last_slot = 0; } self.tf_items = 0; @@ -2202,7 +2202,7 @@ void () TeamFortress_SetEquipment = { self.armortype = 0; self.armorvalue = 0; self.weapon = 0; - self.current_weapon = 0; + self.current_slot = 0; self.flags = FL_CLIENT | FL_NOTARGET; self.waterlevel = 3; @@ -2778,27 +2778,6 @@ void () TeamFortress_AmmoboxTouch = { self = other; }; -void () TeamFortress_AssaultWeapon = { - self.impulse = 0; - if (self.tfstate & TFSTATE_RELOADING) - return; - - if (FO_CurrentWeaponsMask() & WEAP_ASSAULT_CANNON == 0) - return; - - if (self.ammo_shells < 1) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } - - if (self.ammo_cells < 7 && time >= self.antispam_assault_cannon) { - sprint(self, PRINT_HIGH, "Not enough cells to power the Assault Cannon\n"); - self.antispam_assault_cannon = time + 3; - return; - } - W_ChangeWeapon(WEAP_ASSAULT_CANNON); -}; - void () TeamFortress_ExplodePerson = { local entity te; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index d2a52987..97292d68 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -835,7 +835,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { //refill the clip if stock_reload is 2 if (stock_reload == 2) { FO_WeapState ws; - FO_FillWeapState(Player, Player.current_weapon, &ws); + FO_FillWeapState(Player, Player.current_slot, &ws); FO_WeapInfo* wi = ws->wi; @@ -856,7 +856,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } else { //for use in map entities without specifically enabling the general override FO_WeapState ws; - FO_FillWeapState(Player, Player.current_weapon, &ws); + FO_FillWeapState(Player, Player.current_slot, &ws); if ((Goal.reload_shotgun && ws.weapon == WEAP_SHOTGUN) || (Goal.reload_super_shotgun && ws.weapon == WEAP_SUPER_SHOTGUN) || diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 22a652a0..7d277cf3 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1228,9 +1228,8 @@ void () AnarchyMode = { vote_anarchy_mode = TRUE; local entity e = find(world, classname, "player"); while(e) { - e.items = IT_AXE; - e.weapons_carried = IT_AXE; - e.current_weapon = WEAP_AXE; + // TODO: Add a no weap switch to handle this like it used to. + e.current_slot = TF_SLOT4; if(e.vote_map) { e.items |= IT_QUAD; e.tfstate &= 128; @@ -1264,8 +1263,7 @@ void () EndVoting = { while(e) { e.vote_map = world; e.items = 0; - e.weapons_carried = 0; - e.current_weapon = 0; + e.current_slot = TF_SLOT4; e.super_damage_finished = 0; //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; TeamFortress_SetSpeed(e); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 3ed4b966..5880f678 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -10,10 +10,8 @@ void () SuperDamageSound; void () ConcussionGrenadeTimer; void () OldConcussionGrenadeTimer; -void (float inp) W_ChangeWeapon; +void (float slot) W_ChangeWeaponSlot; void () W_ChangeToBestWeapon; -float (float slot) W_WeaponBySlot; -float (float impulse) W_WeaponByImpulse; void () W_PrintWeaponMessage; void () button_fire; @@ -27,9 +25,6 @@ void () TeamFortress_DisplayLegalClasses; void () TeamFortress_ShowIDs; void () TeamFortress_ShowTF; -void () TeamFortress_AssaultWeapon; -void () TeamFortress_IncendiaryCannon; -void () TeamFortress_FlameThrower; void (float inp, float is_player) TeamFortress_PrimeGrenade; void () TeamFortress_ThrowGrenade; void (float inp) TeamFortress_PrimeThrowGrenade; @@ -45,9 +40,6 @@ void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void (entity pe_player, float f_type) CF_Identify; -void () TeamFortress_ReloadCurrentWeapon; -void () TeamFortress_ForceReloadCurrentWeapon; -void (float slot) TeamFortress_ReloadSlot; void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; void (float zoom_in) Sniper_ZoomAdjust; @@ -132,10 +124,8 @@ float () GetMaxWeaponInput; float () IsUsingOldImpulses; float () IsUsingCFImpulses; -float (float impulse) W_WeaponByImpulse; void (entity pl) W_UpdateCurrentWeapon; - void (entity ent, float num) SetFlameCount; .float button3_keydown; @@ -780,20 +770,20 @@ void (float shotcount, vector dir, vector spread) FireBullets = { traceline(src, (src + (direction * 2048)), MOVE_LAGGED, self); if (trace_fraction != 1) { - if (self.current_weapon != WEAP_ASSAULT_CANNON) + if (FO_CurrentWeapon() != WEAP_ASSAULT_CANNON) TraceAttack(4, direction); else TraceAttack(8, direction); } shotcount = shotcount - 1; - if (self.current_weapon == WEAP_ASSAULT_CANNON) { + if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON) { puff_org = trace_endpos + direction; Multi_Finish(); } } ApplyMultiDamage(); - if (self.current_weapon != WEAP_ASSAULT_CANNON) + if (FO_CurrentWeapon() != WEAP_ASSAULT_CANNON) Multi_Finish(); }; @@ -1304,7 +1294,7 @@ void () W_FireGrenade = { newmis.owner = self; newmis.movetype = 10; newmis.solid = 2; - if (self.current_weapon == WEAP_GRENADE_LAUNCHER || cb_prematch) { + if (FO_CurrentWeapon() == WEAP_GRENADE_LAUNCHER || cb_prematch) { newmis.weapon = 5; newmis.classname = "grenade"; newmis.skin = 1; @@ -1394,14 +1384,16 @@ void () W_FireSuperSpikes = { void (float ox) W_FireSpikes = { local vector dir; - FO_WeapInfo* wi = FO_GetWeapInfo(self.current_weapon); + FO_WeapState ws; + FO_FillCurrentWeapState(&ws); + FO_WeapInfo* wi = ws->wi; makevectors(self.v_angle); if (self.ammo_nails < wi->ammo_per_shot) { W_ChangeToBestWeapon(); return; - } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { + } else if (ws.weapon == WEAP_SUPER_NAILGUN) { W_FireSuperSpikes(); return; } @@ -1561,10 +1553,13 @@ void () superspike_touch = { void (entity pl) W_UpdateCurrentWeapon = { entity oldself; - if ((pl.health <= 0) || (pl.current_weapon == 0)) + if ((pl.health <= 0) || (pl.current_slot == 0)) return; - FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); + FO_WeapState ws; + FO_FillWeapState(pl, pl.current_slot, &ws); + FO_WeapInfo* wi = ws.wi; + pl.items &= ~(IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS); // TODO: Shouldn't this always be union? Carrying prior behavior for now. pl.items |= (wi->items)->ammo_mask; @@ -1587,50 +1582,24 @@ void (entity pl) W_UpdateCurrentWeapon = { } }; -float () W_BestWeapon = { - float it = FO_CurrentWeaponsMask(); - - // TODO: Clean-up this at some point. It at least works with WEAPs. - if ((self.ammo_cells >= 1 && it & WEAP_LIGHTNING) && self.waterlevel <= 1) - return WEAP_LIGHTNING; - else if ((self.ammo_cells >= 7 && self.ammo_shells >= 1) && it & WEAP_ASSAULT_CANNON) - return WEAP_ASSAULT_CANNON; - else if (self.ammo_rockets >= 1 && it & WEAP_GRENADE_LAUNCHER) - return WEAP_GRENADE_LAUNCHER; - else if (self.ammo_rockets >= 1 && it & WEAP_ROCKET_LAUNCHER) - return WEAP_ROCKET_LAUNCHER; - else if (self.ammo_rockets >= 3 && it & WEAP_INCENDIARY) - return WEAP_INCENDIARY; - else if (self.ammo_cells >= 1 && it & WEAP_FLAMETHROWER) - return WEAP_FLAMETHROWER; - else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) - return WEAP_SUPER_NAILGUN; - else if (self.ammo_nails >= 1 && it & WEAP_RAILGUN) - return WEAP_RAILGUN; - else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) - return WEAP_TRANQ; - else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) - return WEAP_SUPER_SHOTGUN; - else if (self.ammo_shells >= 1 && it & WEAP_SNIPER_RIFLE) - return WEAP_SNIPER_RIFLE; - else if (self.ammo_nails >= 1 && it & WEAP_NAILGUN) - return WEAP_NAILGUN; - else if (self.ammo_shells >= 1 && it & WEAP_SHOTGUN) - return WEAP_SHOTGUN; - else if (it & WEAP_MEDIKIT) - return WEAP_MEDIKIT; - else if (it & WEAP_KNIFE) - return WEAP_KNIFE; - else if (it & WEAP_SPANNER) - return WEAP_SPANNER; - else if (it & WEAP_AXE) - return WEAP_AXE; +float W_BestWeaponSlot() { + FO_WeapState ws; + for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { + FO_FillWeapState(self, i, &ws); - return 0; + // AC also takes cells to fire. + if (ws->weapon == WEAP_ASSAULT_CANNON && self.ammo_cells < 7) + continue; + + if (ws.weapon != WEAP_NONE && + ((ws.wi)->ammo_type == AMMO_NONE || *ws.ammo_remaining)) + return i; + } + return TF_SLOT4; }; void () W_ChangeToBestWeapon = { - W_ChangeWeapon(W_BestWeapon()); + W_ChangeWeaponSlot(W_BestWeaponSlot()); } void () player_axe1; @@ -1659,7 +1628,7 @@ void () player_medikitb1; void () W_Attack = { float r; FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); FO_WeapInfo* wi = ws->wi; if (self.has_disconnected == TRUE) @@ -1689,51 +1658,51 @@ void () W_Attack = { makevectors(self.v_angle); self.show_hostile = time + 1; - if (self.current_weapon == WEAP_AXE) { + if (ws.weapon == WEAP_AXE) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) player_axe1(); else player_axeb1(); - } else if (self.current_weapon == WEAP_KNIFE) { + } else if (ws.weapon == WEAP_KNIFE) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) player_knife1(); else player_knifeb1(); - } else if (self.current_weapon == WEAP_SPANNER) { + } else if (ws.weapon == WEAP_SPANNER) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); player_spanner1(); - } else if (self.current_weapon == WEAP_SHOTGUN) { + } else if (ws.weapon == WEAP_SHOTGUN) { player_shot1(); W_FireShotgun(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { + } else if (ws.weapon == WEAP_SUPER_SHOTGUN) { player_shot1(); W_FireSuperShotgun(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_NAILGUN) { + } else if (ws.weapon == WEAP_NAILGUN) { player_nail1(); - } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { + } else if (ws.weapon == WEAP_SUPER_NAILGUN) { player_nail1(); - } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { + } else if (ws.weapon == WEAP_GRENADE_LAUNCHER) { player_rocket1(); W_FireGrenade(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_PIPE_LAUNCHER) { + } else if (ws.weapon == WEAP_PIPE_LAUNCHER) { player_rocket1(); W_FireGrenade(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { + } else if (ws.weapon == WEAP_ROCKET_LAUNCHER) { player_rocket1(); W_FireRocket(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_LIGHTNING) { + } else if (ws.weapon == WEAP_LIGHTNING) { player_light1(); FO_Sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); - } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { + } else if (ws.weapon == WEAP_SNIPER_RIFLE) { if (self.flags & FL_ONGROUND) { player_shot1(); W_FireSniperRifle(); @@ -1741,10 +1710,10 @@ void () W_Attack = { Status_Refresh(self); } } - } else if (self.current_weapon == WEAP_AUTO_RIFLE) { + } else if (ws.weapon == WEAP_AUTO_RIFLE) { player_autorifle1(); W_FireAutoRifle(); - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { + } else if (ws.weapon == WEAP_ASSAULT_CANNON) { if (self.ammo_cells < 7) { if (time >= self.antispam_assault_cannon) { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); @@ -1759,14 +1728,14 @@ void () W_Attack = { TeamFortress_SetSpeed(self); player_assaultcannonup(); } - } else if (self.current_weapon == WEAP_FLAMETHROWER) { + } else if (ws.weapon == WEAP_FLAMETHROWER) { player_shot1(); W_FireFlame(); if (self.waterlevel > 2) Attack_Finished(1); else Attack_Finished(0.15); - } else if (self.current_weapon == WEAP_INCENDIARY) { + } else if (ws.weapon == WEAP_INCENDIARY) { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); @@ -1774,39 +1743,38 @@ void () W_Attack = { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; } - } else if (self.current_weapon == WEAP_MEDIKIT) { + } else if (ws.weapon == WEAP_MEDIKIT) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) player_medikit1(); else player_medikitb1(); - } else if (self.current_weapon == WEAP_TRANQ) { + } else if (ws.weapon == WEAP_TRANQ) { FO_Sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); player_shot1(); W_FireTranq(); - } else if (self.current_weapon == WEAP_RAILGUN) { + } else if (ws.weapon == WEAP_RAILGUN) { FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireLaser(); } - if (self.current_weapon != WEAP_FLAMETHROWER && // Variable - self.current_weapon != WEAP_ASSAULT_CANNON && // In animation - self.current_weapon != WEAP_NAILGUN && // In animation - self.current_weapon != WEAP_SUPER_NAILGUN) // In animation + if (ws.weapon != WEAP_FLAMETHROWER && // Variable + ws.weapon != WEAP_ASSAULT_CANNON && // In animation + ws.weapon != WEAP_NAILGUN && // In animation + ws.weapon != WEAP_SUPER_NAILGUN) // In animation Attack_Finished(wi->attack_time); if (wi->needs_reload) { - if (self.current_weapon != WEAP_ASSAULT_CANNON) // In animation + if (ws.weapon != WEAP_ASSAULT_CANNON) // In animation *ws->clip_fired += wi->ammo_per_shot; FO_CheckForReload(); } //These weapons have to log each projectile launched/bullet fired - if (self.current_weapon != WEAP_ASSAULT_CANNON || - self.current_weapon != WEAP_NAILGUN || - self.current_weapon != WEAP_SUPER_NAILGUN) + if (ws.weapon != WEAP_ASSAULT_CANNON || ws.weapon != WEAP_NAILGUN || + ws.weapon != WEAP_SUPER_NAILGUN) LogEventAttack(self); }; @@ -1819,7 +1787,7 @@ float WeaponReady() { } void () W_PrintWeaponMessage = { - switch (self.current_weapon) + switch (FO_CurrentWeapon()) { case WEAP_GRENADE_LAUNCHER: sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); @@ -2044,64 +2012,6 @@ float (float inp) W_OldAmmoSlot = { return 1; }; -struct ImpulseWeapons { - int class; - float weapons[7]; -}; - -static ImpulseWeapons impulse_weapons[] = { - { PC_UNDEFINED, { WEAP_AXE } }, - { PC_SCOUT, - { WEAP_AXE, WEAP_SHOTGUN, 0, WEAP_NAILGUN } }, - { PC_SNIPER, - { WEAP_AXE, WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN } }, - { PC_SOLDIER, - { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, - { PC_DEMOMAN, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, - { PC_MEDIC, - { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, - { PC_HVYWEAP, - { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, - { PC_PYRO, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, - { PC_SPY, - { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, - { PC_ENGINEER, - { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, - { PC_CIVILIAN, { WEAP_AXE } }, -}; - -float W_WeaponByImpulse(float impulse) { - if (impulse < 1 || impulse > 7) return 0; - return impulse_weapons[self.playerclass].weapons[impulse - 1]; -} - -static float HandlePyroSlotSwap(float slot) { - float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) - slot = 3 - slot; - return slot; -} - -float W_WeaponBySlot(float slot) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, - HandlePyroSlotSwap(slot)); - if (!wi) { - sprint(self, PRINT_HIGH, "No weapon\n"); - return 0; - } - - return wi->weapon; -} - -float W_GetWeaponByInput(float input) { - if (IsUsingOldImpulses()) - return W_WeaponByImpulse(input); - else - return W_WeaponBySlot(input); -} - static void W_AmmoError() { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -2115,93 +2025,100 @@ void W_ChangeWeaponByInput(float input) { if (input < 1 || input > GetMaxWeaponInput()) return; - float weapon = W_GetWeaponByInput(input); - if (weapon == 0) + float slot = FO_SlotByInput(input); + if (slot == TF_SLOT_NONE) return; - W_ChangeWeapon(weapon); + W_ChangeWeaponSlot(slot); } void W_QueueAndDisableWeapon() { - self.queue_weapon = self.current_weapon; + self.queue_slot = self.current_slot; // We don't want to actually call Update/Change since that could affect what // other players see. Caller should be setting some state that holds back // the queue (e.g. feigned). - self.current_weapon = WEAP_NONE; + self.current_slot = TF_SLOT_NONE; self.weaponmodel = ""; self.weaponframe = 0; } -void W_ChangeWeapon(float weapon) { +void W_ChangeWeaponSlot(float slot) { if (self.playerclass == 0) return; + FO_WeapState ws; + FO_FillWeapState(self, slot, &ws); + if (ws.weapon == WEAP_NONE) + return; + // queue next weapon if queue is not empty or has changed - if (!self.queue_weapon || weapon != self.queue_weapon) - self.queue_weapon = weapon; + if (!self.queue_slot || slot != self.queue_slot) + self.queue_slot = slot; // halt if weapon is not ready to be fired if (!WeaponReady()) return; - self.queue_weapon = 0; - - FO_WeapState ws; - FO_FillWeapState(self, weapon, &ws); + self.queue_slot = 0; if (*ws->ammo_remaining == 0) { W_AmmoError(); return; } - if (self.current_weapon == weapon) + if (self.current_slot == slot) return; - self.last_weapon = self.current_weapon; + self.last_slot = self.current_slot; + self.current_slot = slot; - self.current_weapon = weapon; W_UpdateCurrentWeapon(self); Status_Refresh(self); }; void W_ChangeWeaponLast() { - if (self.last_weapon == 0) - return; - - W_ChangeWeapon(self.last_weapon); + if (self.last_slot) + W_ChangeWeaponSlot(self.last_slot); }; -float W_FindPrevNextWeapon(float weapon, float is_prev) { - int i; - float *table = IsUsingOldImpulses() ? - impulse_weapons[self.playerclass].weapons : - class_weapons[self.playerclass].slots; +float W_FindPrevNextWeaponSlot(float slot, float is_prev) { + float i, len; - float len = GetMaxWeaponInput(); - for (i = 0; i < len; i++) - if (table[i] == weapon) - break; + float *table; + + if (IsUsingOldImpulses()) { + table = impulse_weapons[self.playerclass].slots; + len = impulse_weapons[self.playerclass].slots.length; + for (i = 0; i < 7; i++) + if (table[i] == slot) + break; + } else { + table = class_weapons[self.playerclass].slots; + len = class_weapons[self.playerclass].slots.length; + i = slot - TF_SLOT1; // Table is 0-index. + } float direction = is_prev ? -1 : 1; do { i = (i + direction + len) % len; } while (table[i] == 0); - return table[i]; + dprint(sprintf("FPN s=%d ip=%d i=%d\n", slot, is_prev, i)); + return IsUsingOldImpulses() ? table[i] : i + TF_SLOT1; } void W_ChangeWeaponNext() { - if (self.weaponmodel == string_null || self.current_weapon == 0) + if (self.weaponmodel == string_null || self.current_slot == 0) return; - W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, FALSE)); + W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, FALSE)); } void W_ChangeWeaponPrev() { - if (self.weaponmodel == string_null || self.current_weapon == 0) + if (self.weaponmodel == string_null || self.current_slot == 0) return; - W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, TRUE)); + W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, TRUE)); } void () PreMatchImpulses; @@ -2266,13 +2183,13 @@ void () ImpulseCommands = { else if (self.impulse == TF_WEAPPREV) W_ChangeWeaponPrev(); else if (self.impulse == TF_RELOAD) - TeamFortress_ReloadCurrentWeapon(); + FO_ReloadSlot(self.current_slot, FALSE); else if (self.impulse == TF_RELOAD_SLOT1) - TeamFortress_ReloadSlot(1); + FO_ReloadSlot(TF_SLOT1, FALSE); else if (self.impulse == TF_RELOAD_SLOT2) - TeamFortress_ReloadSlot(2); + FO_ReloadSlot(TF_SLOT2, FALSE); else if (self.impulse == TF_RELOAD_SLOT3) - TeamFortress_ReloadSlot(3); + FO_ReloadSlot(TF_SLOT3, FALSE); else if (self.impulse == TF_RELOAD_NEXT) TeamFortress_ReloadNext(); else if (self.impulse == TF_DETPACK_5) @@ -2650,17 +2567,11 @@ void () ButtonFrame = { if (input_buttons & BUTTON4) { switch (self.playerclass) { case PC_SOLDIER: - if (IsUsingOldImpulses()) { - self.impulse = 7; - } else { - self.impulse = TF_SLOT1; - } + self.impulse = TF_SLOT1; // Intercepted by InterceptRocketJump() break; case PC_PYRO: - if (IsUsingOldImpulses()) { - self.impulse = 7; - } else if (IsUsingCFImpulses()) { + if (IsUsingCFImpulses()) { self.impulse = TF_SLOT2; } else { self.impulse = TF_SLOT1; @@ -2793,7 +2704,7 @@ void () W_WeaponFrame = { return; } - if ((self.is_feigning) && + if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && (self.impulse != TF_MEDIC_HELPME) && @@ -2812,7 +2723,7 @@ void () W_WeaponFrame = { // there were already so many edge cases in the old code such as swapping on // an empty weapon. if (self.impulse == TF_QUICKSTOP) - self.impulse = self.qf_swap_last_weapon ? TF_WEAPLAST : 0; + self.impulse = self.qf_swap_last_slot ? TF_WEAPLAST : 0; float can_change_weapon = WeaponReady() && !self.is_detpacking && !(self.is_building && !engineer_move); @@ -2825,13 +2736,13 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - float weapon = W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1); - self.qf_swap_last_weapon = weapon != self.current_weapon; - W_ChangeWeapon(weapon); + float slot = self.impulse - TF_QUICKSLOT1 + TF_SLOT1; + self.qf_swap_last_slot = slot != self.current_slot; + W_ChangeWeaponSlot(slot); self.impulse = 0; - } else if (self.queue_weapon > 0 && can_change_weapon) { - // change weapon if queue_weaponslot has been set - W_ChangeWeapon(self.queue_weapon); + } else if (self.queue_slot > 0 && can_change_weapon) { + // change slot if queue_slot has been set + W_ChangeWeaponSlot(self.queue_slot); } if (self.impulse == TF_CHANGETEAM) { @@ -2935,7 +2846,7 @@ void () W_WeaponFrame = { && (!self.fire_held_down || (self.fire_held_down && self.heat == 0 && self.playerclass == PC_HVYWEAP))) { - if (self.current_weapon == WEAP_SNIPER_RIFLE) { + if (FO_CurrentWeapon() == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) { self.heat = self.heat + 3; @@ -2958,7 +2869,7 @@ void () W_WeaponFrame = { TeamFortress_SetSpeed(self); } } - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { + } else if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON) { if (self.flags & FL_ONGROUND || cannon_air) { SuperDamageSound(); W_Attack(); From 58340fafe4fee818201bb35e32d7dbe7c4298154 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 2 Oct 2022 17:14:52 -0700 Subject: [PATCH 1695/2474] Harden interfaces with opaque Slot tokens We've seen one or two crashes with out of bound slots, the code is also confusing in terms of trying to determine when you need to do input checking and when you can just trust that a slot is valid. Try to better formalize this by introducing an opaque slot token type that references valid slots. --- share/defs.h | 16 +-- share/fo_weapons.qc | 86 ++++++++------- ssqc/actions.qc | 15 ++- ssqc/client.qc | 4 +- ssqc/hwguy.qc | 2 +- ssqc/player.qc | 4 +- ssqc/qw.qc | 6 +- ssqc/tfort.qc | 9 +- ssqc/tforthlp.qc | 8 +- ssqc/vote.qc | 4 +- ssqc/weapons.qc | 250 +++++++++++--------------------------------- 11 files changed, 144 insertions(+), 260 deletions(-) diff --git a/share/defs.h b/share/defs.h index 9b748b06..ad1d2145 100644 --- a/share/defs.h +++ b/share/defs.h @@ -297,6 +297,9 @@ /* Toggleable Game Settings */ /*======================================================*/ +// Opaque token that encapsulates slots for correctness. +struct Slot { int id; }; + // Some of the toggleflags aren't used anymore, but the bits are still // there to provide compatability with old maps #define TFLAG_CLASS_PERSIST 1 // Persistent Classes Bit @@ -372,14 +375,11 @@ /*======================================================*/ /* Impulse Defines */ /*======================================================*/ -#define TF_SLOT_NONE 0 -#define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) -#define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) -#define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) -#define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) -#define TF_SLOT_LAST TF_SLOT4 -#define TF_SLOT_MELEE TF_SLOT4 -#define TF_NUM_SLOTS (TF_SLOT_LAST - TF_SLOT1 + 1) +#define TF_IMPULSE_SLOT1 1 // Changes weapon to slot 1 (primary weapon) +#define TF_IMPULSE_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) +#define TF_IMPULSE_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) +#define TF_IMPULSE_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_NUM_SLOTS 4 #define TF_CLASSMENU 5 // Brings up class menu // unused 6 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 3826e537..ebaf66a3 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -18,6 +18,26 @@ float pyro_type = PYRO_FO; float old_ng_rof = FALSE; #endif +// Careful: Slots are not 0-indexed they start from 1. +// Use SlotIndex() to convert a slot if you're indexing an array. +Slot MakeSlot(float slot_num) { + if (slot_num < 1 || slot_num > TF_NUM_SLOTS) + error(sprintf("invalid slot %d\n", slot_num)); + + Slot result; + result.id = slot_num; + return result; +} + +const Slot SlotMelee = { 4 }; +const Slot SlotNull = { 0 }; +inline float IsSlotNull(Slot slot) { return slot.id == 0; } +inline float IsSlotMelee(Slot slot) { return slot.id == 3; } +inline float IsSameSlot(Slot slot1, Slot slot2) { return slot1.id == slot2.id; } + +// Returns dense [0..TF_NUM_SLOTS-1] +float SlotIndex(Slot slot) { return slot.id - 1; } + // Convert a weapon-bit to a linear index. static float WEAP_to_index(float weapon) { float index = 0; @@ -171,15 +191,16 @@ static float* AMMO_to_p(entity player, AmmoType ammo_type) { return __NULL__; } -float WEAP_to_slot(float class, float weapon) { - for (float i = 0; i < 4; i++) - if (class_weapons[class].slots[i] == weapon) - return i + TF_SLOT1; - return -1; +Slot WEAP_to_slot(float playerclass, float weapon) { + for (float i = 0; i < TF_NUM_SLOTS; i++) { + if (class_weapons[playerclass].slots[i] == weapon) + return MakeSlot(i + 1); + } + return SlotNull; } // Internal clip storage for both SSQC/CSQC. -.float clip_fired[TF_SLOT_LAST - TF_SLOT1 + 1]; +.float clip_fired[TF_NUM_SLOTS]; struct FO_WeapToItem { int weapon; @@ -214,25 +235,16 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_RAILGUN, IT_SHOTGUN}, }; -float BoundSlotInput(float slot) { - if (slot < TF_SLOT1 || slot > TF_SLOT4) { - return TF_SLOT4; - } else { - return slot; - } -} - -FO_WeapInfo* FO_SlotWeapInfo(float class, float slot) { - if (slot == TF_SLOT_NONE) +FO_WeapInfo* FO_SlotWeapInfo(float class, Slot slot) { + if (IsSlotNull(slot)) return FO_GetWeapInfo(WEAP_NONE); FO_ClassWeapons* cw = &class_weapons[class]; - slot = BoundSlotInput(slot); - return cw->info[slot - TF_SLOT1] ? cw->info[slot - TF_SLOT1] : + return cw->info[SlotIndex(slot)] ? cw->info[SlotIndex(slot)] : FO_GetWeapInfo(WEAP_NONE); } -float FO_ClassWeaponBySlot(float class, float slot) { +float FO_ClassWeaponBySlot(float class, Slot slot) { FO_WeapInfo* wi = FO_SlotWeapInfo(class, slot); if (!wi) return WEAP_NONE; @@ -240,15 +252,15 @@ float FO_ClassWeaponBySlot(float class, float slot) { return wi->weapon; } -float FO_WeaponSlot(float slot) { +float FO_WeaponSlot(Slot slot) { return FO_ClassWeaponBySlot(self.playerclass, slot); } float FO_ClassWeapItemMask(float class) { float result = 0; - for (int i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { - FO_WeapInfo* wi = FO_SlotWeapInfo(class, i); + for (int i = 1; i <= TF_NUM_SLOTS; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(class, MakeSlot(i)); if (wi) result |= (wi->items)->it_weapon; } @@ -257,8 +269,8 @@ float FO_ClassWeapItemMask(float class) { float FO_WeaponsMask(entity player) { float mask = 0; - for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { - FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, i); + for (float i = 1; i <= TF_NUM_SLOTS; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, MakeSlot(i)); if (wi) mask |= wi->weapon; } @@ -268,7 +280,7 @@ float FO_WeaponsMask(entity player) { #ifdef SSQC struct FO_WeapState { float weapon; - float slot; + Slot slot; // Constant and relative to weapon. TODO, migrate similar to WeapInfo. FO_WeapInfo* wi; @@ -279,9 +291,7 @@ struct FO_WeapState { }; -void FO_FillWeapState(entity player, float slot, FO_WeapState* result) { - if (slot < 0 || slot > 4) error(sprintf("SLOT %d OOB\n", slot)); - +void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, slot); result->weapon = wi->weapon; @@ -290,13 +300,13 @@ void FO_FillWeapState(entity player, float slot, FO_WeapState* result) { result->ammo_remaining = AMMO_to_p(player, wi->ammo_type); - if (slot != TF_SLOT_NONE) - result->clip_fired = &player.clip_fired[slot - TF_SLOT1]; + if (!IsSlotNull(slot)) + result->clip_fired = &player.clip_fired[SlotIndex(slot)]; else result->clip_fired = __NULL__; } -float FO_ClassWeaponBySlot(float class, float slot); +float FO_ClassWeaponBySlot(float class, Slot slot); inline float FO_CurrentWeapon() { return FO_ClassWeaponBySlot(self.playerclass, self.current_slot); @@ -336,7 +346,7 @@ static void FOT_ReloadTimer() { Status_Refresh(self.owner); } -float FO_CanReload(float slot) { +float FO_CanReload(Slot slot) { FO_WeapState ws; FO_FillWeapState(self, slot, &ws); FO_WeapInfo* wi = ws->wi; @@ -352,7 +362,7 @@ float FO_CanReload(float slot) { } void () RestoreDefaultWeapon; -void FO_ReloadSlot(float slot, float force) { +void FO_ReloadSlot(Slot slot, float force) { RestoreDefaultWeapon(); if (self.tfstate & TFSTATE_RELOADING) return; @@ -445,7 +455,7 @@ struct ImpulseWeapon { float weapons[7]; // Autogenerated - float slots[7]; + Slot slots[7]; }; ImpulseWeapon impulse_weapons[] = { @@ -471,7 +481,7 @@ ImpulseWeapon impulse_weapons[] = { { PC_CIVILIAN, { WEAP_AXE } }, }; -float FO_ImpulseToSlot(float impulse) { +Slot FO_ImpulseToSlot(float impulse) { if (impulse < 1 || impulse > 7) return 0; return impulse_weapons[self.playerclass].slots[impulse - 1]; } @@ -496,10 +506,12 @@ static float HandlePyroSlotSwap(float slot) { return slot; } -float FO_SlotByInput(float input) { - return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : input; +Slot FO_SlotByInput(float input) { + return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : MakeSlot(input); } +float getv(float v) { return v; } + void FO_Weapons_Init() { float i, j; diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 0367bffd..259389e4 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -468,28 +468,25 @@ void (entity pe_player, float f_type) CF_Identify = { void () RestoreDefaultWeapon = { float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); - if (default_weapon >= 1 && default_weapon <= 4) { - W_ChangeWeaponSlot(default_weapon); + if (default_weapon >= 1 && default_weapon <= TF_NUM_SLOTS) { + W_ChangeWeaponSlot(MakeSlot(default_weapon)); } }; void () TeamFortress_ReloadNext = { - float slot = self.current_slot; + Slot slot = self.current_slot; if (!FO_CanReload(slot)) { - for (int i = 1; i < TF_NUM_SLOTS; i++) { - slot = slot + 1; // Easier to read than mod version because 1-base. - if (slot > TF_SLOT_LAST) - slot -= TF_NUM_SLOTS; - sprint(self, PRINT_HIGH, sprintf("checking %d\n", slot)); + int base = SlotIndex(slot); + for (int i = 1; i < TF_NUM_SLOTS; i++) { + slot = MakeSlot(1 + ((base + 1) % TF_NUM_SLOTS)); if (FO_CanReload(slot)) break; } } if (FO_CanReload(slot)) { - sprint(self, PRINT_HIGH, sprintf("reloading %d\n", slot)); FO_ReloadSlot(slot, FALSE); RestoreDefaultWeapon(); } else { diff --git a/ssqc/client.qc b/ssqc/client.qc index 68d3da8e..80212fd3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -118,7 +118,7 @@ void () SetChangeParms = { parm5 = self.ammo_nails; parm6 = self.ammo_rockets; parm7 = self.ammo_cells; - parm8 = self.current_slot; + parm8 = SlotIndex(self.current_slot) + 1; parm9 = self.armortype * 100; parm10 = 0; parm11 = 0; @@ -2926,8 +2926,6 @@ void () CheckPowerups = { } }; -void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws); - void () PlayerPostThink = { UpdateScoreboardInfo(self); FOPlayer fop = (FOPlayer)self; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 23336746..dd7ec290 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -114,7 +114,7 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) void FireAssCan (float shotcount, vector dir, vector spread) { FO_WeapState ws; - FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + FO_FillWeapState(self, MakeSlot(1), &ws); Status_Refresh(self); FO_CheckForReload(); diff --git a/ssqc/player.qc b/ssqc/player.qc index a81a28f2..12a962e2 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -90,7 +90,7 @@ void () player_stand1 =[17, player_stand1] { player_run(); return; } - if (self.current_slot == TF_SLOT_MELEE) { + if (IsSlotMelee(self.current_slot)) { if (self.walkframe >= 12) { self.walkframe = 0; } @@ -412,7 +412,7 @@ void () player_nail2 =[104, player_nail1] { static float CheckNeedAssaultCannonDown() { FO_WeapState ws; - FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + FO_FillWeapState(self, MakeSlot(1), &ws); if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 7f46aef5..6457e80b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -206,9 +206,9 @@ float coop; /*==============================================*/ /* New Weapon variables */ /*==============================================*/ -.float current_slot; // the currently equipped (weapon) slot -.float last_slot; // the last slot the player was using -.float queue_slot; // the slot to switch to when possible +.Slot current_slot; // the currently equipped (weapon) slot +.Slot last_slot; // the last slot the player was using +.Slot queue_slot; // the slot to switch to when possible .float ammo_medikit; // Ammo used for the medikit .float maxammo_medikit; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f5ea8890..4658c89d 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1567,9 +1567,10 @@ void () TeamFortress_SetEquipment = { kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); self.items = FO_ClassWeapItemMask(self.playerclass) | kept_items; - if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { - self.current_slot = 0; - self.last_slot = 0; + if (!remember_weapon || self.last_playerclass != self.playerclass || + (self.tfstate & TFSTATE_RANDOMPC)) { + self.current_slot = SlotMelee; + self.last_slot = SlotNull; } self.tf_items = 0; @@ -2202,7 +2203,7 @@ void () TeamFortress_SetEquipment = { self.armortype = 0; self.armorvalue = 0; self.weapon = 0; - self.current_slot = 0; + self.current_slot = SlotNull; self.flags = FL_CLIENT | FL_NOTARGET; self.waterlevel = 3; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 3be9685e..44368883 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -85,10 +85,10 @@ void () TeamFortress_MOTD = { } else { TeamFortress_AliasString("menu", "cmd menu"); } - TeamFortress_Alias("slot1", TF_SLOT1, 0); - TeamFortress_Alias("slot2", TF_SLOT2, 0); - TeamFortress_Alias("slot3", TF_SLOT3, 0); - TeamFortress_Alias("slot4", TF_SLOT4, 0); + TeamFortress_Alias("slot1", TF_IMPULSE_SLOT1, 0); + TeamFortress_Alias("slot2", TF_IMPULSE_SLOT2, 0); + TeamFortress_Alias("slot3", TF_IMPULSE_SLOT3, 0); + TeamFortress_Alias("slot4", TF_IMPULSE_SLOT4, 0); // you shouldn't use these in fte, use setinfo default_weapon and +quick instead // leaving in to prevent breaking change diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 7d277cf3..56f50ca8 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1229,7 +1229,7 @@ void () AnarchyMode = { local entity e = find(world, classname, "player"); while(e) { // TODO: Add a no weap switch to handle this like it used to. - e.current_slot = TF_SLOT4; + e.current_slot = SlotMelee; if(e.vote_map) { e.items |= IT_QUAD; e.tfstate &= 128; @@ -1263,7 +1263,7 @@ void () EndVoting = { while(e) { e.vote_map = world; e.items = 0; - e.current_slot = TF_SLOT4; + e.current_slot = SlotMelee; e.super_damage_finished = 0; //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; TeamFortress_SetSpeed(e); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5880f678..fdb15faf 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -10,7 +10,7 @@ void () SuperDamageSound; void () ConcussionGrenadeTimer; void () OldConcussionGrenadeTimer; -void (float slot) W_ChangeWeaponSlot; +void (Slot slot) W_ChangeWeaponSlot; void () W_ChangeToBestWeapon; void () W_PrintWeaponMessage; @@ -1553,7 +1553,7 @@ void () superspike_touch = { void (entity pl) W_UpdateCurrentWeapon = { entity oldself; - if ((pl.health <= 0) || (pl.current_slot == 0)) + if ((pl.health <= 0) || IsSlotNull(pl.current_slot)) return; FO_WeapState ws; @@ -1582,20 +1582,23 @@ void (entity pl) W_UpdateCurrentWeapon = { } }; -float W_BestWeaponSlot() { +Slot W_BestWeaponSlot() { FO_WeapState ws; - for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { - FO_FillWeapState(self, i, &ws); + for (float i = 1; i <= TF_NUM_SLOTS; i++) { + Slot slot = MakeSlot(i); + FO_FillWeapState(self, slot, &ws); // AC also takes cells to fire. if (ws->weapon == WEAP_ASSAULT_CANNON && self.ammo_cells < 7) continue; + // We don't need to handle out of ammo medi/spanner here because of + // fallback below. if (ws.weapon != WEAP_NONE && ((ws.wi)->ammo_type == AMMO_NONE || *ws.ammo_remaining)) - return i; + return slot; } - return TF_SLOT4; + return SlotMelee; }; void () W_ChangeToBestWeapon = { @@ -1870,148 +1873,6 @@ float (float weap) W_OldGetSlot = { return 0; }; -float (float inp) W_AmmoSlot = { - local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - self.noammo = 0; - - if (inp == TF_SLOT1) { - if (self.playerclass == PC_SCOUT && self.ammo_nails < 2) - self.noammo = 1; - else if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_SOLDIER && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_MEDIC && self.ammo_nails < 4) - self.noammo = 1; - else if (self.playerclass == PC_HVYWEAP) { - if (self.ammo_shells < 1) - self.noammo = 1; - else if (self.ammo_cells < 7) - self.noammo = 2; - } else if (self.playerclass == PC_PYRO && !cf_pyro_impulses && self.ammo_rockets < 3) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && cf_pyro_impulses && self.ammo_cells < 3) - self.noammo = 1; - else if (self.playerclass == PC_SPY && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_ENGINEER && self.ammo_nails < 1) - self.noammo = 1; - } else if (inp == TF_SLOT2) { - if (self.playerclass == PC_SCOUT && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) - self.noammo = 1; - else if ((self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - && self.ammo_shells < 2) - self.noammo = 1; - else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && !cf_pyro_impulses && self.ammo_cells < 1) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && cf_pyro_impulses && self.ammo_rockets < 1) - self.noammo = 1; - } else if (inp == TF_SLOT3) { - if (self.playerclass == PC_SCOUT - || self.playerclass == PC_ENGINEER) - return 0; - if ((self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - && self.ammo_nails < 2) - self.noammo = 1; - else if ((self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO) - && self.ammo_shells < 1) - self.noammo = 1; - } else if (inp == TF_SLOT4) - return 1; - - if (self.noammo > 0) - return 0; - else - return 1; -}; - -float (float inp) W_OldAmmoSlot = { - self.noammo = 0; - if (inp == TF_SLOT1) { - return 1; - } - else if (inp == TF_SLOT2) { - if ((self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO - || self.playerclass == PC_SPY) - && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_ENGINEER && self.ammo_nails < 1) - self.noammo = 1; - - } - else if (inp == TF_SLOT3) { - if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) - self.noammo = 1; - else if ((self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - && self.ammo_shells < 2) - self.noammo = 1; - } - else if (inp == TF_SLOT4) { - if ((self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - && self.ammo_nails < 2) - self.noammo = 1; - } - else if (inp == 5) { - if (self.playerclass == PC_MEDIC && self.ammo_nails < 4) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) - self.noammo = 1; - } - else if (inp == 6) { - if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) - self.noammo = 1; - - } - else if (inp == 7) { - if (self.playerclass == PC_SOLDIER && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_HVYWEAP) { - if (self.ammo_shells < 1) - self.noammo = 1; - else if (self.ammo_cells < 7) - self.noammo = 2; - } - else if (self.playerclass == PC_PYRO && self.ammo_rockets < 3) - self.noammo = 1; - - } - if (self.noammo > 0) - return 0; - else - return 1; -}; - static void W_AmmoError() { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -2025,8 +1886,8 @@ void W_ChangeWeaponByInput(float input) { if (input < 1 || input > GetMaxWeaponInput()) return; - float slot = FO_SlotByInput(input); - if (slot == TF_SLOT_NONE) + Slot slot = FO_SlotByInput(input); + if (IsSlotNull(slot)) return; W_ChangeWeaponSlot(slot); @@ -2037,12 +1898,12 @@ void W_QueueAndDisableWeapon() { // We don't want to actually call Update/Change since that could affect what // other players see. Caller should be setting some state that holds back // the queue (e.g. feigned). - self.current_slot = TF_SLOT_NONE; + self.current_slot = SlotNull; self.weaponmodel = ""; self.weaponframe = 0; } -void W_ChangeWeaponSlot(float slot) { +void W_ChangeWeaponSlot(Slot slot) { if (self.playerclass == 0) return; @@ -2052,21 +1913,22 @@ void W_ChangeWeaponSlot(float slot) { return; // queue next weapon if queue is not empty or has changed - if (!self.queue_slot || slot != self.queue_slot) + if (IsSlotNull(self.queue_slot) || !IsSameSlot(slot, self.queue_slot)) self.queue_slot = slot; // halt if weapon is not ready to be fired if (!WeaponReady()) return; - self.queue_slot = 0; + self.queue_slot = SlotNull; - if (*ws->ammo_remaining == 0) { + // We still allow swapping to medikit/spanner with no ammo. + if (*ws->ammo_remaining == 0 && !IsSlotMelee(slot)) { W_AmmoError(); return; } - if (self.current_slot == slot) + if (IsSameSlot(slot, self.current_slot)) return; self.last_slot = self.current_slot; @@ -2077,45 +1939,54 @@ void W_ChangeWeaponSlot(float slot) { }; void W_ChangeWeaponLast() { - if (self.last_slot) + if (!IsSlotNull(self.last_slot)) W_ChangeWeaponSlot(self.last_slot); }; -float W_FindPrevNextWeaponSlot(float slot, float is_prev) { +Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { float i, len; - - float *table; + float direction = is_prev ? -1 : 1; if (IsUsingOldImpulses()) { - table = impulse_weapons[self.playerclass].slots; - len = impulse_weapons[self.playerclass].slots.length; - for (i = 0; i < 7; i++) - if (table[i] == slot) + Slot* impulse_table = impulse_weapons[self.playerclass].slots; + // For reasons that seem to rhyme with -ompilerbug, reads from + // impulse_table[offset] return junk so we use a pointer cursor. + Slot* cur; + len = 7; + + for (i = 0; i < len; i++) { + cur = &impulse_table[i]; + if (IsSameSlot(*cur, slot)) break; + } + do { + i = (i + direction + len) % len; + cur = &impulse_table[i]; + } while (IsSlotNull(*cur)); + + return *cur; } else { - table = class_weapons[self.playerclass].slots; - len = class_weapons[self.playerclass].slots.length; - i = slot - TF_SLOT1; // Table is 0-index. - } + float* slot_weaps = class_weapons[self.playerclass].slots; + len = 4; + i = SlotIndex(slot); - float direction = is_prev ? -1 : 1; - do { - i = (i + direction + len) % len; - } while (table[i] == 0); + do { + i = (i + direction + len) % len; + } while (slot_weaps[i] == 0); - dprint(sprintf("FPN s=%d ip=%d i=%d\n", slot, is_prev, i)); - return IsUsingOldImpulses() ? table[i] : i + TF_SLOT1; + return MakeSlot(i + 1); + } } void W_ChangeWeaponNext() { - if (self.weaponmodel == string_null || self.current_slot == 0) + if (self.weaponmodel == string_null || IsSlotNull(self.current_slot)) return; W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, FALSE)); } void W_ChangeWeaponPrev() { - if (self.weaponmodel == string_null || self.current_slot == 0) + if (self.weaponmodel == string_null || IsSlotNull(self.current_slot)) return; W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, TRUE)); @@ -2185,11 +2056,11 @@ void () ImpulseCommands = { else if (self.impulse == TF_RELOAD) FO_ReloadSlot(self.current_slot, FALSE); else if (self.impulse == TF_RELOAD_SLOT1) - FO_ReloadSlot(TF_SLOT1, FALSE); + FO_ReloadSlot(MakeSlot(1), FALSE); else if (self.impulse == TF_RELOAD_SLOT2) - FO_ReloadSlot(TF_SLOT2, FALSE); + FO_ReloadSlot(MakeSlot(2), FALSE); else if (self.impulse == TF_RELOAD_SLOT3) - FO_ReloadSlot(TF_SLOT3, FALSE); + FO_ReloadSlot(MakeSlot(3), FALSE); else if (self.impulse == TF_RELOAD_NEXT) TeamFortress_ReloadNext(); else if (self.impulse == TF_DETPACK_5) @@ -2567,14 +2438,14 @@ void () ButtonFrame = { if (input_buttons & BUTTON4) { switch (self.playerclass) { case PC_SOLDIER: - self.impulse = TF_SLOT1; + self.impulse = TF_IMPULSE_SLOT1; // Intercepted by InterceptRocketJump() break; case PC_PYRO: if (IsUsingCFImpulses()) { - self.impulse = TF_SLOT2; + self.impulse = TF_IMPULSE_SLOT2; } else { - self.impulse = TF_SLOT1; + self.impulse = TF_IMPULSE_SLOT1; } // Intercepted by InterceptRocketJump() break; @@ -2736,11 +2607,16 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - float slot = self.impulse - TF_QUICKSLOT1 + TF_SLOT1; - self.qf_swap_last_slot = slot != self.current_slot; - W_ChangeWeaponSlot(slot); + Slot slot = MakeSlot(self.impulse - TF_QUICKSLOT1 + 1); + + if (IsSameSlot(slot, self.current_slot)) { + self.qf_swap_last_slot = FALSE; + } else { + self.qf_swap_last_slot = TRUE; + W_ChangeWeaponSlot(slot); + } self.impulse = 0; - } else if (self.queue_slot > 0 && can_change_weapon) { + } else if (!IsSlotNull(self.queue_slot) && can_change_weapon) { // change slot if queue_slot has been set W_ChangeWeaponSlot(self.queue_slot); } From 4bdecb59f5f7003f4f03487a0682e74341ea84ff Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 21 Sep 2022 20:30:48 -0700 Subject: [PATCH 1696/2474] Restore URI_GetCallback Misread prior error message, this is just a proto change and still being used by some communities. --- ssqc/login.qc | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/ssqc/login.qc b/ssqc/login.qc index 36faf1f3..a83f979d 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -12,3 +12,57 @@ void (entity player, string login, string secret) performLogin = { dprint(login); dprint("\n"); } + +void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback = { + local float got_one = 0; + self.login_in_progress = 0; + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (!responsecode) { + float num_args = tokenizebyseparator(resourcebody,";"); + self.login = argv(0); + forceinfokey(self,"*login", self.login); + bprint(2, infokey(self,"name")); + bprint(2, " has logged in as \s"); + bprint(2, self.login); + bprint(2, "\s\n"); + dprint(infokey(self,"name")); + dprint(" logged in as "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, "You have logged in as ", self.login, "\n"); + if (num_args > 1) { + if (argv(1) == "true") { + self.is_admin = TRUE; + forceinfokey(self,"*admin", ftos(self.is_admin)); + Admin_Aliases (); + bprint(2, self.netname, " \sgains full admin status!\s\n"); +// bprint (3, "\n"); + sprint(self, 2, "Type \scommands\s for admin commands.\n"); + } + } + if(self.team_no == 0 && !intermission_running) { + if (clanbattle && (self.has_disconnected != 1)) { + if (self.tf_id != 0) { + got_one = RejoinWithTfId(); + ResetAndRespawnPlayer(self); + } + if (!got_one) { + CreateTfIdAndJoin(); + } + } + if (!got_one) { + if (csqcactive) + Menu_Team(0); + else + Menu_Team(1); + } + } + } + else { + dprint(infokey(self,"name")); + dprint(" login failed: "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, ftos(responsecode), " - Login FAILED, invalid Login/Secret", "\n"); + } +} From b94366bca8ae06ec9873a0f4989cb40a3382ff84 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 20:41:54 -0700 Subject: [PATCH 1697/2474] Remove legacy timer implementation --- csqc/events.qc | 46 ++-------------------------------------------- 1 file changed, 2 insertions(+), 44 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index e6f072fc..6b251aec 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -317,30 +317,6 @@ string GetGrenTimerSound() { return wav; } -void OldPlayGren(float offset) { - local float channel = CHAN_GREN_START; - local float soundtime; - local float highest_soundtime = -1; - - for(float i = CHAN_GREN_START; i <= CHAN_GREN_END; i++) { - soundtime = getsoundtime(world, i); - - if (soundtime < 0) { - channel = i; - break; - } - - if (soundtime > highest_soundtime) { - highest_soundtime = soundtime; - channel = i; - } - } - - local string wav = GetGrenTimerSound(); - localsound(wav, channel, CVARF(FOCMD_GRENTIMERVOLUME)); // required because soundupdate doesn't reset getsoundtime - soundupdate(self, channel, wav, CVARF(FOCMD_GRENTIMERVOLUME), 0, 0, 0, offset); -} - void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, float timer_flags) { grentype_ = _grentype; @@ -377,11 +353,6 @@ void StopGrenTimers() { // New style. for (float i = 0; i < NUM_GREN_TIMERS; i++) grentimers[i].Stop(); - - // Old style. - for (float i = CHAN_GREN_START; i <= CHAN_GREN_END; i++) { - soundupdate(self, i, "", 0, 0, 0, 0, 0); - } } void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { @@ -400,20 +371,10 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { } float debug_print_state = CVARF(fo_grentimer_debug) & 1; - float debug_use_old_sound = CVARF(fo_grentimer_debug) & 4; - - float play_old_sound = FALSE; - if (debug_use_old_sound) { - play_old_sound = timer_flags & FL_GT_SOUND; - timer_flags &= ~FL_GT_SOUND; - } CsGrenTimer timer = CsGrenTimer::GetNext(); timer.Set(primed_at, explodes_at, grentype, timer_flags); - if (play_old_sound) - OldPlayGren(timer.sound_offset()); - if (debug_print_state) { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; @@ -421,11 +382,8 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { float expires_new = timer.expiry(); float expires_ideal = explodes_at - ping/2; - print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f new=%d\n", - primed_at, explodes_at, explodes_at - primed_at, - !debug_use_old_sound)); - print(sprintf("ideal=%0.2f new=%0.2f old=%0.2f\n", - expires_ideal, expires_new, expires_old)); + print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f\n", + primed_at, explodes_at, explodes_at - primed_at)); } } From 26e78b968364f1db8d1b268c9f3fa715dfa47fa5 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 2 Oct 2022 22:53:40 -0700 Subject: [PATCH 1698/2474] Sync grenade timers with cease fire It's rather frustrating that ceasefire causes all the active grenade timers to lose sync (the visual timer pauses, but the sound just keeps playing). Implement actual pause/unpause of the timer sound around ceasefire start/end. --- csqc/csextradefs.qc | 19 +++++++++++++++ csqc/events.qc | 32 +++++++++++++++--------- share/commondefs.qc | 2 ++ ssqc/admin.qc | 16 ++++++++++++ ssqc/mvdsv.qc | 59 +++++++++------------------------------------ 5 files changed, 69 insertions(+), 59 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9047c3e4..5a2b0b1a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -467,6 +467,12 @@ class CsGrenTimer { float grentype, float timer_flags) Set; nonvirtual void() Stop; + nonvirtual void() PauseSound { + if (flags_ & FL_GT_SOUND) // -volume => stop. + soundupdate(this, CHAN_VOICE, "", -1, 0, 0, 0, 0); + }; + nonvirtual void() StartSound; + static float next_index_; static CsGrenTimer last_; @@ -485,6 +491,19 @@ class CsGrenTimer { last_ = grentimers[next_index_]; return last_; }; + static void() SyncPause { + // Time froze, but sound kept running, realign. + for (float i = 0; i < grentimers.length; i++) + if (grentimers[i].active) + grentimers[i].PauseSound(); + }; + + static void() SyncUnpause { + // Time froze, but sound kept running, realign. + for (float i = 0; i < grentimers.length; i++) + if (grentimers[i].active) + grentimers[i].StartSound(); + }; static CsGrenTimer() GetLast { return last_; }; }; diff --git a/csqc/events.qc b/csqc/events.qc index 6b251aec..dbc614a5 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -301,6 +301,12 @@ void() CSQC_Parse_Event = { case MSG_VOTE_MAP_DELETE: RemoveVoteMap(readstring(), FALSE); break; + case MSG_PAUSE: + CsGrenTimer::SyncPause(); + break; + case MSG_UNPAUSE: + CsGrenTimer::SyncUnpause(); + break; } } @@ -317,6 +323,18 @@ string GetGrenTimerSound() { return wav; } +void CsGrenTimer::StartSound() { + if !(this.flags_ & FL_GT_SOUND) + return; + + string wav = GetGrenTimerSound(); + float volume = CVARF(FOCMD_GRENTIMERVOLUME); + + // Note there's a bug where soundupdate returns false for a new sample, even + // though it's started. + soundupdate(this, CHAN_VOICE, wav, volume, 0, 0, 0, sound_offset()); +} + void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, float timer_flags) { grentype_ = _grentype; @@ -330,22 +348,12 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, expires_at_ -= rtt/2; } - if !(this.flags_ & FL_GT_SOUND) - return; - - string wav = GetGrenTimerSound(); - float volume = CVARF(FOCMD_GRENTIMERVOLUME); - - // Note there's a bug where soundupdate returns false for a new sample, even - // though it's started. - soundupdate(this, CHAN_VOICE, wav, volume, 0, 0, 0, sound_offset()); + StartSound(); } - void CsGrenTimer::Stop() { expires_at_ = -1; - if (flags_ & FL_GT_SOUND) - soundupdate(this, CHAN_VOICE, "", -1, 0, 0, 0, 0); // -volume => stop. + PauseSound(); // Pause is really stop. flags_ = 0; } diff --git a/share/commondefs.qc b/share/commondefs.qc index 71bd23ff..aa8eb494 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -32,6 +32,8 @@ #define MSG_VOTE_MAP_ADD 20 #define MSG_VOTE_MAP_DELETE 21 #define MSG_PLAYERDIE 22 +#define MSG_PAUSE 23 +#define MSG_UNPAUSE 24 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/admin.qc b/ssqc/admin.qc index bd56df78..8f3ab367 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -187,9 +187,25 @@ void () Admin_CeaseFire = { } }; +void NotifyPauseUnpause(float is_pause) { + entity p = find (world, classname, "player"); + while (p) { + if (p.netname == "" || !infokeyf(p, INFOKEY_P_CSQCACTIVE)) + continue; + + msg_entity = p; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, is_pause ? MSG_PAUSE : MSG_UNPAUSE); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); + + p = find(p, classname, "player"); + } +} + void () Admin_Pause = { if (!is_paused) { setpause(1); + NotifyPauseUnpause(TRUE); is_paused = 1; cs_paused = 1; pause_actor = self.netname; diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index 2930774e..d77e8df5 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -107,6 +107,7 @@ void (float duration) GE_PausedTic = { local entity p; if (unpause_requested && (unpause_countdown == 0)) { unpause_countdown = duration + 5; + unpause_lastcountnumber = 5; } if (unpause_requested) { if ((duration >= unpause_countdown)) { @@ -116,56 +117,20 @@ void (float duration) GE_PausedTic = { unpause_requested = 0; unpause_lastcountnumber = 0; setpause(0); - } - else { - if (duration >= (unpause_countdown - 4) && (unpause_lastcountnumber == 0)) { - unpause_lastcountnumber = 4; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); - } - bprint(PRINT_HIGH, "Unpausing in 4 seconds\n" ); - - } - else if (duration >= (unpause_countdown - 3) && (unpause_lastcountnumber == 4)) { - unpause_lastcountnumber = 3; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); - } - bprint(PRINT_HIGH, "Unpausing in 3 seconds\n" ); - } - else if (duration >= (unpause_countdown - 2) && (unpause_lastcountnumber == 3)) { - unpause_lastcountnumber = 2; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); - } - bprint(PRINT_HIGH, "Unpausing in 2 seconds\n" ); - } - else if (duration >= (unpause_countdown - 1) && (unpause_lastcountnumber == 2)) { - unpause_lastcountnumber = 1; - p = find (world, classname, "player"); - while (p) { - if (p.netname != "") { - stuffcmd(p, "play buttons/switch04.wav\n"); - } - p = find(p, classname, "player"); - } - bprint(PRINT_HIGH, "Unpausing in 1 second\n" ); + NotifyPauseUnpause(FALSE); + } else if (duration >= unpause_countdown - (unpause_lastcountnumber)) { + unpause_lastcountnumber--; + p = find (world, classname, "player"); + while (p) { + if (p.netname != "") + stuffcmd(p, "play buttons/switch04.wav\n"); + p = find(p, classname, "player"); } + bprint(PRINT_HIGH, + sprintf("Unpausing in %d seconds\n", unpause_lastcountnumber)); } } -} +} void(float pauseduration) SV_PausedTic = { GE_PausedTic(pauseduration); From dbeffbd8936173253e4f1a0263d15a8aae4df723 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 12:27:24 -0700 Subject: [PATCH 1699/2474] Make sure we swap pyro 1/2 slots with cf_pyro_impulses Also extend handling to default_weapon which I'm not sure was covered before (although not commonly used). --- share/fo_weapons.qc | 17 ++++++++++------- ssqc/weapons.qc | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index ebaf66a3..aae000c2 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -499,19 +499,22 @@ float IsUsingOldImpulses() { return FALSE; } static float IsPyroSlotSwapped() { return FALSE; } #endif -static float HandlePyroSlotSwap(float slot) { +float InputHandlePyroSlotSwap(float input) { float cf_pyro_impulses = IsPyroSlotSwapped(); - if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) - slot = 3 - slot; - return slot; + if (self.playerclass == PC_PYRO && cf_pyro_impulses && (input == 1 || input == 2)) + input = 3 - input; + return input; } Slot FO_SlotByInput(float input) { - return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : MakeSlot(input); + if (IsUsingOldImpulses()) { + return FO_ImpulseToSlot(input); + } else { + input = InputHandlePyroSlotSwap(input); + return MakeSlot(input); + } } -float getv(float v) { return v; } - void FO_Weapons_Init() { float i, j; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fdb15faf..be927a1f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2384,7 +2384,7 @@ void () ButtonFrame = { local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); if (default_weapon >= 1 && default_weapon <= 4) { - self.impulse = default_weapon; + self.impulse = InputHandlePyroSlotSwap(default_weapon); } } From 153771db5069273d036af03618343cf528f2e973 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 13:57:17 -0700 Subject: [PATCH 1700/2474] Also handle CFPI with weapnext/weapprev This is a little annoying since we're trying to walk [1234/4321] but with CFPI we must also consider [2134]/[4312]. --- ssqc/weapons.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index be927a1f..6c612030 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1968,13 +1968,16 @@ Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { } else { float* slot_weaps = class_weapons[self.playerclass].slots; len = 4; - i = SlotIndex(slot); + // This is a little subtle, we need to transform the index both before + // and after the walk so that we don't walk back into ourselves. + i = InputHandlePyroSlotSwap(SlotIndex(slot) + 1) - 1; do { i = (i + direction + len) % len; } while (slot_weaps[i] == 0); - return MakeSlot(i + 1); + i = InputHandlePyroSlotSwap(i + 1); + return MakeSlot(i); } } From 84c9dc74273a30f9912ba07a6cc05cc68468195c Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 16:28:41 -0700 Subject: [PATCH 1701/2474] Make sure ReloadSlot checks for not a nullslot Generically called from impulse commands, could be no weapon. --- share/fo_weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index aae000c2..f1c9d9a0 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -364,7 +364,7 @@ float FO_CanReload(Slot slot) { void () RestoreDefaultWeapon; void FO_ReloadSlot(Slot slot, float force) { RestoreDefaultWeapon(); - if (self.tfstate & TFSTATE_RELOADING) + if (self.tfstate & TFSTATE_RELOADING || IsSlotNull(slot)) return; FO_WeapState ws; From d76a70e1a0051734346b0c2b1c51e74b3ba410fd Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 20:49:15 -0700 Subject: [PATCH 1702/2474] Fix impulse 6/7 to grenade/pipe under old_weapon_impulses Also restore flavour text for bvr. --- share/fo_weapons.qc | 2 +- ssqc/weapons.qc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index f1c9d9a0..3d6e0225 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -467,7 +467,7 @@ ImpulseWeapon impulse_weapons[] = { { PC_SOLDIER, { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, { PC_DEMOMAN, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, { PC_MEDIC, { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, { PC_HVYWEAP, diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 6c612030..e16994f9 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1935,6 +1935,7 @@ void W_ChangeWeaponSlot(Slot slot) { self.current_slot = slot; W_UpdateCurrentWeapon(self); + W_PrintWeaponMessage(); Status_Refresh(self); }; From b0a05360e792f848e49324582b9ce85d203d4707 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 02:21:15 -0700 Subject: [PATCH 1703/2474] Fix runaway loop in ceasefire grentimer restart Deceptively works with a list length of 1 for testing before. --- ssqc/admin.qc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 8f3ab367..939f2ff4 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -188,17 +188,17 @@ void () Admin_CeaseFire = { }; void NotifyPauseUnpause(float is_pause) { - entity p = find (world, classname, "player"); - while (p) { - if (p.netname == "" || !infokeyf(p, INFOKEY_P_CSQCACTIVE)) + int count; + entity* p = find_list(classname, "player", EV_STRING, count); + + for (float i = 0; i < count; i++) { + if (p[i].netname == "" || !infokeyf(p[i], INFOKEY_P_CSQCACTIVE)) continue; - msg_entity = p; + msg_entity = p[i]; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, is_pause ? MSG_PAUSE : MSG_UNPAUSE); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); - - p = find(p, classname, "player"); } } From 04d5eab1bd7e3231ed3b921a85b7a34ce69ff410 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 4 Oct 2022 00:40:05 -0700 Subject: [PATCH 1704/2474] Add debug helpers Better error messages, active comments. --- csqc/csprogs.src | 1 + csqc/sui_sys.qc | 1 - menu/menu.src | 1 + share/debug.qc | 65 +++++++++++++++++++++++++++++++++++++++++++++ share/fo_weapons.qc | 47 +++++++++++++++----------------- ssqc/antilag.qc | 24 ++++++++--------- ssqc/progs.src | 1 + 7 files changed, 102 insertions(+), 38 deletions(-) create mode 100644 share/debug.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 37747e32..81b6c037 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -8,6 +8,7 @@ csdefs.qc csextradefs.qc +../share/debug.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 4e11eaa3..16896adc 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -5,7 +5,6 @@ // The API is made simple and easy to build upon, but cuts have been made // to keep complexity low. // -#define printf(x, ...) print(sprintf(x, __VA_ARGS__)) #ifdef MENU const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ diff --git a/menu/menu.src b/menu/menu.src index ce60d2ea..c5b8dc78 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -8,6 +8,7 @@ #includelist ../share/fteextensions.qc //also sets up system defs +../share/debug.qc ../menusys/mitems.qc //root item type ../menusys/mitems_common.qc //basic types diff --git a/share/debug.qc b/share/debug.qc new file mode 100644 index 00000000..c94c4b1c --- /dev/null +++ b/share/debug.qc @@ -0,0 +1,65 @@ +#ifdef SSQC + +// printf that works in any context +#define printf(...) bprint(PRINT_HIGH, sprintf(__VA_ARGS__)) +#define printd(...) dprint(sprintf(__VA_ARGS__)) + +#else + +#define printf(...) print(sprintf(__VA_ARGS__)) + +#endif + +#define MSEC 0.001 +#define SEC 1 + +#define errors(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__)) +#define errorf(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__, __VA_ARGS__)) + +#define _ASSERT_OP(_op, _invop, _fmt, _v1, _v2) \ + if (!((_v1) _op (_v2))) \ + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ + #_v1, #_v2, _v1, _v2) + +#define __ASSERT_OP(_op, _invop, _fmt, _v1, _v2, __v1, __v2) \ + if (!((__v1) _op (__v2))) \ + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ + #_v1, #_v2, __v1, __v2) + +#define ASSERTF_EQ(_v1, _v2) _ASSERT_OP(==, !=, %0.2f, _v1, _v2) +#define ASSERTF_NE(_v1, _v2) _ASSERT_OP(!=, ==, %0.2f, _v1, _v2) +#define ASSERTF_GT(_v1, _v2) _ASSERT_OP( >, <=, %0.2f, _v1, _v2) +#define ASSERTF_GE(_v1, _v2) _ASSERT_OP(>=, <, %0.2f, _v1, _v2) +#define ASSERTF_LT(_v1, _v2) _ASSERT_OP( <, >=, %0.2f, _v1, _v2) +#define ASSERTF_LE(_v1, _v2) _ASSERT_OP(<=, <, %0.2f, _v1, _v2) + + +// Work around general weird behaviors with __int +float __as_float(float v) { return v; } + +#define ASSERTD_EQ(_v1, _v2) __ASSERT_OP(==, !=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_NE(_v1, _v2) __ASSERT_OP(!=, ==, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_GT(_v1, _v2) __ASSERT_OP( >, <=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_GE(_v1, _v2) __ASSERT_OP(>=, <, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_LT(_v1, _v2) __ASSERT_OP( <, >=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_LE(_v1, _v2) __ASSERT_OP(<=, <, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) + +#define ASSERTS_EQ(_v1, _v2) _ASSERT_OP(==, !=, %s, _v1, _v2) +#define ASSERTS_NE(_v1, _v2) _ASSERT_OP(!=, ==, %s, _v1, _v2) + +#define ASSERTF_TRUE(_v1) ASSERTF_EQ(_v1, TRUE) +#define ASSERTF_FALSE(_v1) ASSERTF_EQ(_v1, FALSE) + + +#define __CONCAT(_a, _b) _a ## _b +#define _PRINT_ONCE(_n, ...) \ + do { static float _n; if (!_n) { _n = TRUE; printf(__VA_ARGS__); } } while (0) +#define _PRINT_EVERY(_n, _p, ...) \ + do { static float _n; if (time > _n + _p) { _n = time + _p; printf(__VA_ARGS__); } } while (0) + +#define PRINT_ONCE(...) _PRINT_ONCE(__CONCAT(__once, __LINE__), __VA_ARGS__) +#define PRINT_EVERY(_p, ...) _PRINT_EVERY(__CONCAT(__every, __LINE_), _p, __VA_ARGS__) + +#define EPS 0.001 +#define FEQ(_v1, _v2) (fabs(_v1 - _v2) < EPS) +#define FNEQ(_v1, _v2) (fabs(_v1 - _v2) >= EPS) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 3d6e0225..84b41a60 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -22,7 +22,7 @@ float old_ng_rof = FALSE; // Use SlotIndex() to convert a slot if you're indexing an array. Slot MakeSlot(float slot_num) { if (slot_num < 1 || slot_num > TF_NUM_SLOTS) - error(sprintf("invalid slot %d\n", slot_num)); + errorf("invalid slot %d\n", slot_num); Slot result; result.id = slot_num; @@ -518,8 +518,7 @@ Slot FO_SlotByInput(float input) { void FO_Weapons_Init() { float i, j; - if (weapon_names.length != weapon_info.length) - error("Weapon Names/Weapon Info inconsistency\n"); + ASSERTD_EQ(weapon_names.length, weapon_info.length); FO_WeapInfo* WI_ac = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); WI_ac->clip_size = fo_hwguy ? PC_HVYWEAP_ASSCAN_CLIPSIZE : 0; @@ -545,30 +544,28 @@ void FO_Weapons_Init() { for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; - if (WEAP_to_index(wi->weapon) != i) - error(sprintf("WI mismatch at index %d\n", i)); - - if (wi->weapon == WEAP_PIPE_LAUNCHER) { - FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); - wi->ammo_type = parent->ammo_type; - wi->clip_size = parent->clip_size; - wi->full_reload_time = parent->full_reload_time; - wi->needs_reload = parent->needs_reload; - } else if (wi->clip_size > 0) { - wi->needs_reload = TRUE; - } else { - wi->needs_reload = FALSE; - } - - FO_WeapModels* wm = &weapon_models[i]; - if (WEAP_to_index(wm->weapon) != i) - error(sprintf("WM mismatch at index %d\n", i)); - precache_model(wm->model); - wi->models = wm; + ASSERTD_EQ(WEAP_to_index(wi->weapon), i); + + if (wi->weapon == WEAP_PIPE_LAUNCHER) { + FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); + wi->ammo_type = parent->ammo_type; + wi->clip_size = parent->clip_size; + wi->full_reload_time = parent->full_reload_time; + wi->needs_reload = parent->needs_reload; + } else if (wi->clip_size > 0) { + wi->needs_reload = TRUE; + } else { + wi->needs_reload = FALSE; + } + + FO_WeapModels* wm = &weapon_models[i]; + ASSERTD_EQ(WEAP_to_index(wm->weapon), i); + precache_model(wm->model); + wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; - if (WEAP_to_index(wti->weapon) != i) - error(sprintf("WTI mismatch at index %d\n", i)); + ASSERTD_EQ(WEAP_to_index(wti->weapon), i); + wi->items = wti; switch (wi->ammo_type) { case AMMO_SHELLS: wti->ammo_mask = IT_SHELLS; break; diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 7c82b62c..ec5afd67 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -23,12 +23,12 @@ void AL_ProjectProjectile (entity projectile) { #define DEBUG_ANTILAG 0 -#if DEBUG_ANTILAG -#define printf(...) sprint(self, PRINT_HIGH, sprintf(__VA_ARGS__)) -#define printd(...) dprint(sprintf(__VA_ARGS__)) +#ifndef DEBUG_ANTILAG +#define al_printf(...) printf(__VA_ARGS__) +#define al_printd(...) dprint(__VA_ARGS__) #else -#define printf(...) -#define printd(...) +#define al_printf(...) +#define al_printd(...) #endif #define AL_MAX_REWINDS 25 @@ -157,14 +157,14 @@ SeekResult SeekBasic(RewindState* target, float when) { #if 0 void CompareSeek(SeekResult s1, SeekResult, s2) { if (before != (r.before)->time) - error(sprintf("before mismatch w=%f seek=%f check=%f\n", - when, (r.before)->time, before)); + errorf("before mismatch w=%f seek=%f check=%f\n", + when, (r.before)->time, before); if (after != (r.after)->time) - error(sprintf("after mismatch w=%f seek=%f check=%f\n", - when, (r.after)->time, after)); + errorf("after mismatch w=%f seek=%f check=%f\n", + when, (r.after)->time, after); if (nearest != (r.nearest)->time) - error(sprintf("nearest mismatch w=%f seek=%f check=%f\n", - when, (r.nearest)->time, nearest)); + errorf("nearest mismatch w=%f seek=%f check=%f\n", + when, (r.nearest)->time, nearest); } @@ -175,7 +175,7 @@ SeekResult SeekOpt(RewindState* target, float when) { float probe = floor((time - when) / AL_FRAME_LIMIT); probe = max(probe - 3, 0); printd(" probe = %d -> %d, %d\n", - probe, target->cursor, Index(target->cursor - probe)); + probe, target->cursor, Index(target->cursor - probe); if (probe > AL_MAX_REWINDS || probe < 0) return r; diff --git a/ssqc/progs.src b/ssqc/progs.src index e69fee0a..b8d67bdf 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -8,6 +8,7 @@ #includelist ../share/fteextensions.qc +../share/debug.qc defs.qc ../share/commondefs.qc ../share/common_helpers.qc From 6df359fa03c5dae5d17c38cb4d1180419133ef3d Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 01:52:57 -0700 Subject: [PATCH 1705/2474] Fix inversion on detpipe enable --- ssqc/antilag.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index ec5afd67..cba089a2 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -325,7 +325,7 @@ class FOPlayer { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { - if (antilag_settings.rewind_detpipe) + if (!antilag_settings.rewind_detpipe) return FALSE; float rewind_max_offset = ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT); From 90398ab46d1d9e8d399ca73a7015a6b5b12c616a Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 4 Oct 2022 00:40:05 -0700 Subject: [PATCH 1706/2474] Add debug helpers Better error messages, active comments. --- csqc/csprogs.src | 1 + csqc/sui_sys.qc | 1 - menu/menu.src | 1 + share/debug.qc | 65 +++++++++++++++++++++++++++++++++++++++++++++ share/fo_weapons.qc | 47 +++++++++++++++----------------- ssqc/antilag.qc | 22 +++++++-------- ssqc/progs.src | 1 + 7 files changed, 101 insertions(+), 37 deletions(-) create mode 100644 share/debug.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 37747e32..81b6c037 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -8,6 +8,7 @@ csdefs.qc csextradefs.qc +../share/debug.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 4e11eaa3..16896adc 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -5,7 +5,6 @@ // The API is made simple and easy to build upon, but cuts have been made // to keep complexity low. // -#define printf(x, ...) print(sprintf(x, __VA_ARGS__)) #ifdef MENU const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ diff --git a/menu/menu.src b/menu/menu.src index ce60d2ea..c5b8dc78 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -8,6 +8,7 @@ #includelist ../share/fteextensions.qc //also sets up system defs +../share/debug.qc ../menusys/mitems.qc //root item type ../menusys/mitems_common.qc //basic types diff --git a/share/debug.qc b/share/debug.qc new file mode 100644 index 00000000..c94c4b1c --- /dev/null +++ b/share/debug.qc @@ -0,0 +1,65 @@ +#ifdef SSQC + +// printf that works in any context +#define printf(...) bprint(PRINT_HIGH, sprintf(__VA_ARGS__)) +#define printd(...) dprint(sprintf(__VA_ARGS__)) + +#else + +#define printf(...) print(sprintf(__VA_ARGS__)) + +#endif + +#define MSEC 0.001 +#define SEC 1 + +#define errors(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__)) +#define errorf(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__, __VA_ARGS__)) + +#define _ASSERT_OP(_op, _invop, _fmt, _v1, _v2) \ + if (!((_v1) _op (_v2))) \ + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ + #_v1, #_v2, _v1, _v2) + +#define __ASSERT_OP(_op, _invop, _fmt, _v1, _v2, __v1, __v2) \ + if (!((__v1) _op (__v2))) \ + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ + #_v1, #_v2, __v1, __v2) + +#define ASSERTF_EQ(_v1, _v2) _ASSERT_OP(==, !=, %0.2f, _v1, _v2) +#define ASSERTF_NE(_v1, _v2) _ASSERT_OP(!=, ==, %0.2f, _v1, _v2) +#define ASSERTF_GT(_v1, _v2) _ASSERT_OP( >, <=, %0.2f, _v1, _v2) +#define ASSERTF_GE(_v1, _v2) _ASSERT_OP(>=, <, %0.2f, _v1, _v2) +#define ASSERTF_LT(_v1, _v2) _ASSERT_OP( <, >=, %0.2f, _v1, _v2) +#define ASSERTF_LE(_v1, _v2) _ASSERT_OP(<=, <, %0.2f, _v1, _v2) + + +// Work around general weird behaviors with __int +float __as_float(float v) { return v; } + +#define ASSERTD_EQ(_v1, _v2) __ASSERT_OP(==, !=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_NE(_v1, _v2) __ASSERT_OP(!=, ==, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_GT(_v1, _v2) __ASSERT_OP( >, <=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_GE(_v1, _v2) __ASSERT_OP(>=, <, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_LT(_v1, _v2) __ASSERT_OP( <, >=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_LE(_v1, _v2) __ASSERT_OP(<=, <, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) + +#define ASSERTS_EQ(_v1, _v2) _ASSERT_OP(==, !=, %s, _v1, _v2) +#define ASSERTS_NE(_v1, _v2) _ASSERT_OP(!=, ==, %s, _v1, _v2) + +#define ASSERTF_TRUE(_v1) ASSERTF_EQ(_v1, TRUE) +#define ASSERTF_FALSE(_v1) ASSERTF_EQ(_v1, FALSE) + + +#define __CONCAT(_a, _b) _a ## _b +#define _PRINT_ONCE(_n, ...) \ + do { static float _n; if (!_n) { _n = TRUE; printf(__VA_ARGS__); } } while (0) +#define _PRINT_EVERY(_n, _p, ...) \ + do { static float _n; if (time > _n + _p) { _n = time + _p; printf(__VA_ARGS__); } } while (0) + +#define PRINT_ONCE(...) _PRINT_ONCE(__CONCAT(__once, __LINE__), __VA_ARGS__) +#define PRINT_EVERY(_p, ...) _PRINT_EVERY(__CONCAT(__every, __LINE_), _p, __VA_ARGS__) + +#define EPS 0.001 +#define FEQ(_v1, _v2) (fabs(_v1 - _v2) < EPS) +#define FNEQ(_v1, _v2) (fabs(_v1 - _v2) >= EPS) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 3d6e0225..84b41a60 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -22,7 +22,7 @@ float old_ng_rof = FALSE; // Use SlotIndex() to convert a slot if you're indexing an array. Slot MakeSlot(float slot_num) { if (slot_num < 1 || slot_num > TF_NUM_SLOTS) - error(sprintf("invalid slot %d\n", slot_num)); + errorf("invalid slot %d\n", slot_num); Slot result; result.id = slot_num; @@ -518,8 +518,7 @@ Slot FO_SlotByInput(float input) { void FO_Weapons_Init() { float i, j; - if (weapon_names.length != weapon_info.length) - error("Weapon Names/Weapon Info inconsistency\n"); + ASSERTD_EQ(weapon_names.length, weapon_info.length); FO_WeapInfo* WI_ac = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); WI_ac->clip_size = fo_hwguy ? PC_HVYWEAP_ASSCAN_CLIPSIZE : 0; @@ -545,30 +544,28 @@ void FO_Weapons_Init() { for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; - if (WEAP_to_index(wi->weapon) != i) - error(sprintf("WI mismatch at index %d\n", i)); - - if (wi->weapon == WEAP_PIPE_LAUNCHER) { - FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); - wi->ammo_type = parent->ammo_type; - wi->clip_size = parent->clip_size; - wi->full_reload_time = parent->full_reload_time; - wi->needs_reload = parent->needs_reload; - } else if (wi->clip_size > 0) { - wi->needs_reload = TRUE; - } else { - wi->needs_reload = FALSE; - } - - FO_WeapModels* wm = &weapon_models[i]; - if (WEAP_to_index(wm->weapon) != i) - error(sprintf("WM mismatch at index %d\n", i)); - precache_model(wm->model); - wi->models = wm; + ASSERTD_EQ(WEAP_to_index(wi->weapon), i); + + if (wi->weapon == WEAP_PIPE_LAUNCHER) { + FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); + wi->ammo_type = parent->ammo_type; + wi->clip_size = parent->clip_size; + wi->full_reload_time = parent->full_reload_time; + wi->needs_reload = parent->needs_reload; + } else if (wi->clip_size > 0) { + wi->needs_reload = TRUE; + } else { + wi->needs_reload = FALSE; + } + + FO_WeapModels* wm = &weapon_models[i]; + ASSERTD_EQ(WEAP_to_index(wm->weapon), i); + precache_model(wm->model); + wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; - if (WEAP_to_index(wti->weapon) != i) - error(sprintf("WTI mismatch at index %d\n", i)); + ASSERTD_EQ(WEAP_to_index(wti->weapon), i); + wi->items = wti; switch (wi->ammo_type) { case AMMO_SHELLS: wti->ammo_mask = IT_SHELLS; break; diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 7c82b62c..609f4d49 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -23,12 +23,12 @@ void AL_ProjectProjectile (entity projectile) { #define DEBUG_ANTILAG 0 -#if DEBUG_ANTILAG -#define printf(...) sprint(self, PRINT_HIGH, sprintf(__VA_ARGS__)) -#define printd(...) dprint(sprintf(__VA_ARGS__)) +#ifndef DEBUG_ANTILAG +#define al_printf(...) printf(__VA_ARGS__) +#define al_printd(...) dprint(__VA_ARGS__) #else -#define printf(...) -#define printd(...) +#define al_printf(...) +#define al_printd(...) #endif #define AL_MAX_REWINDS 25 @@ -157,14 +157,14 @@ SeekResult SeekBasic(RewindState* target, float when) { #if 0 void CompareSeek(SeekResult s1, SeekResult, s2) { if (before != (r.before)->time) - error(sprintf("before mismatch w=%f seek=%f check=%f\n", - when, (r.before)->time, before)); + errorf("before mismatch w=%f seek=%f check=%f\n", + when, (r.before)->time, before); if (after != (r.after)->time) - error(sprintf("after mismatch w=%f seek=%f check=%f\n", - when, (r.after)->time, after)); + errorf("after mismatch w=%f seek=%f check=%f\n", + when, (r.after)->time, after); if (nearest != (r.nearest)->time) - error(sprintf("nearest mismatch w=%f seek=%f check=%f\n", - when, (r.nearest)->time, nearest)); + errorf("nearest mismatch w=%f seek=%f check=%f\n", + when, (r.nearest)->time, nearest); } diff --git a/ssqc/progs.src b/ssqc/progs.src index e69fee0a..b8d67bdf 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -8,6 +8,7 @@ #includelist ../share/fteextensions.qc +../share/debug.qc defs.qc ../share/commondefs.qc ../share/common_helpers.qc From b040b395f5787c915b292943f7936d35f7d81189 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 02:03:34 -0700 Subject: [PATCH 1707/2474] Make CFPI work with quickslots hydro pointed out that the quick slot inputs are are another place we need to carry the pyro slot swap option. --- ssqc/weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e16994f9..9971b8f6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2611,7 +2611,8 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - Slot slot = MakeSlot(self.impulse - TF_QUICKSLOT1 + 1); + float input = InputHandlePyroSlotSwap(self.impulse - TF_QUICKSLOT1 + 1); + Slot slot = MakeSlot(input); if (IsSameSlot(slot, self.current_slot)) { self.qf_swap_last_slot = FALSE; From a881ae05cce8b6d3ba20f40aa3f1454c8b858828 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 01:52:57 -0700 Subject: [PATCH 1708/2474] Fix inversion on detpipe enable --- ssqc/antilag.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 609f4d49..e1eabc77 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -325,7 +325,7 @@ class FOPlayer { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { - if (antilag_settings.rewind_detpipe) + if (!antilag_settings.rewind_detpipe) return FALSE; float rewind_max_offset = ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT); From 63cf4569eeed1cab72e4db6403b3cec955bb75a7 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 02:03:34 -0700 Subject: [PATCH 1709/2474] Make CFPI work with quickslots hydro pointed out that the quick slot inputs are are another place we need to carry the pyro slot swap option. --- ssqc/weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e16994f9..9971b8f6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2611,7 +2611,8 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - Slot slot = MakeSlot(self.impulse - TF_QUICKSLOT1 + 1); + float input = InputHandlePyroSlotSwap(self.impulse - TF_QUICKSLOT1 + 1); + Slot slot = MakeSlot(input); if (IsSameSlot(slot, self.current_slot)) { self.qf_swap_last_slot = FALSE; From 5b3c20635a5dfe7d090b70012374c1db15bd706c Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 02:57:17 -0700 Subject: [PATCH 1710/2474] In the midst of giving this another pass, but I think this is actually closer to correct after all. --- ssqc/antilag.qc | 2 +- ssqc/client.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index e1eabc77..d1e82c0c 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,5 +1,5 @@ void AL_ProjectProjectile (entity projectile) { - float time_offset = time - client_time(CT_SLOW_PROJECTILE); + float time_offset = (time - client_time(CT_SLOW_PROJECTILE)) / 2; if (time_offset <= 0.013) // ping 13ms or lower? Don't do anything return; diff --git a/ssqc/client.qc b/ssqc/client.qc index 80212fd3..bf668a0a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -613,7 +613,7 @@ void () DecodeLevelParms = { // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); - antilag_settings.max_projectile_slow_offset = project_weapons_max_latency / 2; + antilag_settings.max_projectile_slow_offset = project_weapons_max_latency; // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From e41b88cb4beb64e1ea46fb06aea44fe04ea05269 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 6 Oct 2022 17:52:01 -0700 Subject: [PATCH 1711/2474] Fix off-by-one on Melee slot and add some logging for high indexes We're seeing a rare crash with an index of 4 (e.g. an effective slot 5), add some logging / hardening against this. --- share/fo_weapons.qc | 26 ++++++++++++++++++++++---- ssqc/client.qc | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 84b41a60..90f89cf8 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -18,9 +18,22 @@ float pyro_type = PYRO_FO; float old_ng_rof = FALSE; #endif +// Some preprocessor bug is making __LINE__ not substitute right here most of +// the time. Oh well, even if we just get file it's good enough to narrow. +#define CheckSlot(slot_num) _CheckSlot(__FILE__, __LINE__, slot_num) +float _CheckSlot(string file, float line, float slot_num) { + if (slot_num < 1 || slot_num > TF_NUM_SLOTS) { + printf("%s:%d: Invalid slot (%d). Continuing.\n", + file, line, slot_num); + return 4; + } + return slot_num; +} + +#define MakeSlot(slot_num) _MakeSlot(CheckSlot(slot_num)) // Careful: Slots are not 0-indexed they start from 1. // Use SlotIndex() to convert a slot if you're indexing an array. -Slot MakeSlot(float slot_num) { +Slot _MakeSlot(float slot_num) { if (slot_num < 1 || slot_num > TF_NUM_SLOTS) errorf("invalid slot %d\n", slot_num); @@ -32,11 +45,16 @@ Slot MakeSlot(float slot_num) { const Slot SlotMelee = { 4 }; const Slot SlotNull = { 0 }; inline float IsSlotNull(Slot slot) { return slot.id == 0; } -inline float IsSlotMelee(Slot slot) { return slot.id == 3; } +inline float IsSlotMelee(Slot slot) { return slot.id == 4; } inline float IsSameSlot(Slot slot1, Slot slot2) { return slot1.id == slot2.id; } // Returns dense [0..TF_NUM_SLOTS-1] -float SlotIndex(Slot slot) { return slot.id - 1; } +float SlotIndex(Slot slot) { + if (slot.id > 4) { + printf("ERROR: OOB slot id (%d) found. Continuing.\n", (float)slot.id); + return TF_NUM_SLOTS - 1; + } + return slot.id - 1; } // Convert a weapon-bit to a linear index. static float WEAP_to_index(float weapon) { @@ -445,7 +463,7 @@ float FO_CheckForReload() { void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; - for (int i = 0; i < 4; i++) + for (int i = 0; i < TF_NUM_SLOTS; i++) player.clip_fired[i] = 0; } #endif diff --git a/ssqc/client.qc b/ssqc/client.qc index bf668a0a..5c2d0482 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2075,6 +2075,7 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; + self.current_slot = SlotMelee; FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; From ac8ee5fda89dbda2a8efd70afa0d095c9f5fa0a4 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 6 Oct 2022 21:37:27 -0700 Subject: [PATCH 1712/2474] Spawn with SlotNull not Melee This was intended as a conservative state reset but it triggers other last selected weapon logic later and results in always spawning with axe, Null's a more correct choice anyway. --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5c2d0482..4c019e62 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2075,7 +2075,7 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; - self.current_slot = SlotMelee; + self.current_slot = SlotNull; FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; From 03e1e96989c9d1e0f76bf447cc29494bbc0f8155 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 7 Oct 2022 16:48:37 -0700 Subject: [PATCH 1713/2474] Fix Ammo table A missing comma was resulting in silent string concatenation and a table size of 4. This was leading to OOB references that looked like they were on slots but were really on ammo. Originally I was going to restore grenades as an ammo type here (with flavour text) as well but other stuff is yielding a message first so will look at that later. --- share/fo_weapons.qc | 2 +- ssqc/client.qc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 90f89cf8..668302ee 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -194,7 +194,7 @@ static FO_WeapModels weapon_models[] = { }; // REQUIRES: Order must match above. -static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; +static string AMMO_to_s[] = {"none", "shells", "nails", "cells", "rockets"}; static float* AMMO_to_p(entity player, AmmoType ammo_type) { switch (ammo_type) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 4c019e62..bf668a0a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2075,7 +2075,6 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; - self.current_slot = SlotNull; FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; From 4183fc5c8e657538c949d65359de96ebebab02ce Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 09:45:06 -0700 Subject: [PATCH 1714/2474] Make sure pipe/grenade launcher share clip Inadvertently removed in the collapse to slot/clip based storage. --- share/fo_weapons.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 668302ee..d20dcb36 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -322,6 +322,10 @@ void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { result->clip_fired = &player.clip_fired[SlotIndex(slot)]; else result->clip_fired = __NULL__; + + // Special case: Overlap with grenade launcher. + if (wi->weapon == WEAP_PIPE_LAUNCHER) + result->clip_fired = &player.clip_fired[0]; } float FO_ClassWeaponBySlot(float class, Slot slot); From 6c596dfd491357b7b1bb66a4cba17408a5c66f9f Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 10:07:02 -0700 Subject: [PATCH 1715/2474] Introduce stable clock `time` turns out to not be particularly well-aligned with frames, with it being often +/- half a frame by timing. Improve this by introducing a stable client_time clock (which subsumes some of the prior notion). Infrastructure for aligning think events (such as animation) with this clock (which can then be more strongly aligned with the client) is added. While we're here, migrate a bunch of other things that we're going to need to synchronize with this clock (too much really, but hard to split now). At least we simplified the reload timing and tracking in the transition. We pull a bunch of things back to time (e.g. pipecooldown) are not migrated yet since we need to also unify client_time with rewind or just generally test and tune. --- share/fo_weapons.qc | 89 ++++++++++++++++++++++----------------------- ssqc/actions.qc | 8 ++-- ssqc/antilag.qc | 45 +++-------------------- ssqc/client.qc | 28 +++++--------- ssqc/engineer.qc | 4 +- ssqc/progs.src | 1 + ssqc/qw.qc | 35 +++++++++++------- ssqc/spy.qc | 6 +-- ssqc/status.qc | 43 ++++------------------ ssqc/tfort.qc | 12 +++--- ssqc/time.qc | 50 +++++++++++++++++++++++++ ssqc/weapons.qc | 7 +++- 12 files changed, 158 insertions(+), 170 deletions(-) create mode 100644 ssqc/time.qc diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index d20dcb36..fa0d3768 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -83,8 +83,8 @@ struct FO_WeapToItem; struct FO_WeapInfo { int weapon; // Verification AmmoType ammo_type; - int clip_size; - int ammo_per_shot; + float clip_size; + float ammo_per_shot; float attack_time; float full_reload_time; @@ -295,6 +295,11 @@ float FO_WeaponsMask(entity player) { return mask; } +float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) { + float tick = (wi->ammo_per_shot / wi->clip_size) * wi->full_reload_time; + return ceil((reload_finished - now) / tick) * wi->ammo_per_shot; +} + #ifdef SSQC struct FO_WeapState { float weapon; @@ -345,27 +350,39 @@ inline void FO_FillCurrentWeapState(FO_WeapState* result) { void (entity pl) Status_Refresh; void (float att_delay) Attack_Finished; -static void FOT_ReloadTimer() { +// Hack until we fix Status_Refresh() to not be awful. +.float last_still_loading; + +float FO_ReloadFrame() { + if (self.tfstate & TFSTATE_RELOADING == 0) + return FALSE; + FO_WeapState ws; - FO_FillWeapState(self.owner, self.owner.current_slot, &ws); - - if (time >= self.heat) { - // Reload finished - self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = ((ws->wi)->models)->model; - self.owner.weaponframe = 0; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - } else { - // Refresh clip - if (ws->weapon != WEAP_SNIPER_RIFLE) - self.owner.reload_clipsize += 1; - else - self.owner.reload_sniper_ticks += 1; + FO_FillWeapState(self, self.current_slot, &ws); + FO_WeapInfo* wi = ws.wi; + + if (wi->weapon == WEAP_NONE) + return FALSE; - self.nextthink = min(time + self.owner.reload_tick, self.heat); + if (self.client_time >= self.reload_finished) { + self.tfstate &= ~TFSTATE_RELOADING; + self.weaponmodel = ((ws->wi)->models)->model; + self.weaponframe = 0; + self.last_still_loading = 0; + Status_Refresh(self); + sprint(self, PRINT_HIGH, "Finished reloading\n"); + + return FALSE; } - Status_Refresh(self.owner); + + float still_loading = FO_NumClipStillLoading(wi, self.client_time, + self.reload_finished); + if (self.last_still_loading != still_loading) { + self.last_still_loading = still_loading; + Status_Refresh(self); + } + + return TRUE; } float FO_CanReload(Slot slot) { @@ -423,31 +440,11 @@ void FO_ReloadSlot(Slot slot, float force) { float reload_duration = (reload_count / wi->clip_size) * wi->full_reload_time; - *ws->clip_fired -= reload_count; - - // Sets up for status bar. - self.reload_time = time + reload_duration; - self.reload_tick = reload_duration / reload_count; - self.reload_clipsize = wi->clip_size - reload_count; - - // Actual entity that will update status bar / clear reload. - entity reload_timer = spawn(); - reload_timer.owner = self; - reload_timer.classname = "timer"; - reload_timer.think = FOT_ReloadTimer; - - // TODO: Remove this hack. - if (ws.weapon == WEAP_SNIPER_RIFLE) { - self.reload_tick = 1; - self.reload_sniper_ticks = 0; - } - - // It turns out, even on forced reloads we should use the client_time() not - // the server time as the action that forced the reload (firing the last - // shot), was client relative. - reload_timer.heat = client_time() + reload_duration; - reload_timer.nextthink = client_time() + self.reload_tick; - + // TODO: Make ammo in clip independent from ammo_remaining (so you can't + // have shots in clip that are discarded and other weirdness.) + (*ws->clip_fired) -= reload_count; + self.last_still_loading = reload_count; + self.reload_finished = self.client_time + reload_duration; } float FO_CheckForReload() { @@ -467,6 +464,8 @@ float FO_CheckForReload() { void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; + player.reload_finished = 0; + player.last_still_loading = 0; for (int i = 0; i < TF_NUM_SLOTS; i++) player.clip_fired[i] = 0; } diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 259389e4..ca3537ec 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -160,13 +160,13 @@ void () TeamFortress_Discard_DropAmmo = { void () TeamFortress_SaveMe = { local entity te, tl; - if (self.last_saveme_sound < time) { + if (self.client_time > self.next_saveme_sound) { if (random() < 0.8) FO_Sound(self, CHAN_WEAPON, "speech/saveme1.wav", 1, ATTN_NORM); else FO_Sound(self, CHAN_WEAPON, "speech/saveme2.wav", 1, ATTN_NORM); - self.last_saveme_sound = time + 4; + self.next_saveme_sound = self.client_time + 4; } te = find(world, classname, "player"); while (te) { @@ -258,7 +258,7 @@ void (entity pe_player) FO_Spectator_Identify = { } // refresh status bar - pe_player.ident_time = time + 0.5; + pe_player.ident_time = self.client_time + 0.5; if(pe_player.ident_string != s_id_string) { pe_player.ident_string = s_id_string; //if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { @@ -452,7 +452,7 @@ void (entity pe_player, float f_type) CF_Identify = { s_id_string = strcat(s_id_string, s_class); } - pe_player.ident_time = time + 0.5; + pe_player.ident_time = self.client_time + 0.5; // don't update memory when the id string is the same if (pe_player.ident_string == s_id_string) { diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index d1e82c0c..eabe93db 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,7 +1,7 @@ void AL_ProjectProjectile (entity projectile) { - float time_offset = (time - client_time(CT_SLOW_PROJECTILE)) / 2; + float time_offset = self.client_time - remote_client_time(CT_SLOW_PROJECTILE); - if (time_offset <= 0.013) // ping 13ms or lower? Don't do anything + if (time_offset <= 13 * MSEC) // ping 13ms or lower? Don't do anything return; vector projected_origin = projectile.origin + (projectile.velocity * time_offset); @@ -332,8 +332,9 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { farthest_rewind_point = max(farthest_rewind_point, time - rewind_max_offset); - // Det was pushed at client_time(), let's see if we can get there. - float rewind_to = max(farthest_rewind_point, client_time()); + // Det was pushed at remote_client_time(), let's see if we can get there. + float rewind_to = max(farthest_rewind_point, + client_to_global_time(remote_client_time())); // Ignore for LAN pings. if (time - rewind_to < 0.013) @@ -349,39 +350,3 @@ void UnrewindPlayer(entity p) { fop.RestoreNow(); } -.float client_time_internal; - -float client_time(float ct_type = CT_NOEXTERNALEFFECT) { - if (ct_type == CT_NOEXTERNALEFFECT) - return self.client_time_internal; - - float offset = time - self.client_time_internal; - float max_offset = antilag_settings.max_client_time_offset; - switch (ct_type) { - case CT_SLOW_PROJECTILE: - max_offset = antilag_settings.max_projectile_slow_offset; - break; - } - - return max(self.client_time_internal, time - max_offset); -} - -void AL_UpdateClientTime(entity player) { - float offset; - - // Naively, we might want to offset by rtt/2, because that's how old the - // client's input is. However, the client's input is also relative to a - // world view that is itself rtt/2 behind. [Client is a full rtt behind, - // and it interpolates ahead to rtt/2 behind.] - // This means that if we want, say, "run to a position and perform an action" - // to have equivalent time, we need to correct by a full rtt. - offset = infokeyf(player, INFOKEY_P_PING) / 1000; - - offset = min(offset, antilag_settings.max_client_time_offset); - - // Monotonically increasing and not dragging beyond 75% of time as/if RTT - // changes. - player.client_time_internal = - max(time - offset, player.client_time_internal + (1/77.0 * 0.75)); -} - diff --git a/ssqc/client.qc b/ssqc/client.qc index bf668a0a..47d0f2dd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -450,9 +450,6 @@ void () DecodeLevelParms = { // use old tf style dropflag (map decides on/off) [off] old_dropflag = CF_GetSetting("odf", "old_dropflag", "off"); - // show ticking clip ammo in sbar when reloading [on] - reload_cliptick = CF_GetSetting("rc", "reload_cliptick", "on"); - // use old tf sniper range (shorter) [off] old_sniperrange = CF_GetSetting("os", "old_sniperrange", "off"); @@ -601,19 +598,18 @@ void () DecodeLevelParms = { airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); - // client_time max delta + // remote_client_time max delta antilag_settings.rewind_detpipe = CF_GetSetting("alrd", "al_rewind_detpipe", "on"); - // client_time max delta - antilag_settings.max_client_time_offset = - CF_GetSetting("almcto", "al_max_client_time_offset", "200"); + // maximum ping we'll have effect at + antilag_settings.max_ping = CF_GetSetting("almp", "al_max_ping", "200"); // project projectile weapons by player ping project_weapons = CF_GetSetting("pw", "project_weapons", "off"); // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); - antilag_settings.max_projectile_slow_offset = project_weapons_max_latency; + antilag_settings.max_projectile_slow_ping = project_weapons_max_latency; // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); @@ -838,7 +834,6 @@ void () DecodeLevelParms = { remember_weapon = TRUE; discammo_pickup = FALSE; old_dropflag = FALSE; - reload_cliptick = TRUE; scoutdash = TRUE; sniperreload = TRUE; old_sniperrange = FALSE; @@ -917,7 +912,6 @@ void () DecodeLevelParms = { remember_weapon = FALSE; discammo_pickup = TRUE; old_dropflag = TRUE; - reload_cliptick = FALSE; scoutdash = FALSE; sniperreload = FALSE; old_sniperrange = TRUE; @@ -1962,7 +1956,7 @@ void (entity p) SetVoteParams = { stuffcmd(p, strcat("color ", ftos(rint(random() * 12)), " ", ftos(rint(random() * 12)), "\n")); p.takedamage = DAMAGE_AIM; //DAMAGE_YES; - p.attack_finished = time + 0.3; + p.attack_finished = self.client_time + 0.3; p.th_pain = player_pain; p.th_die = PlayerDie; p.height = 0; @@ -2068,7 +2062,7 @@ void () PutClientInServer = { self.invincible_finished = 0; self.effects = 0; self.invincible_time = 0; - self.spawn_time = time; + self.spawn_time = self.client_time; self.vote_close = 0; self.has_throwngren = FALSE; self.saveme_time = 0; @@ -2173,7 +2167,7 @@ void () PutClientInServer = { stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - self.attack_finished = client_time() + 0.3; + self.attack_finished = self.client_time + 0.3; self.th_pain = player_pain; self.th_die = PlayerDie; self.height = 0; @@ -2658,11 +2652,8 @@ void () CheckWaterJump = { } }; -void AL_UpdateClientTime(entity player); - void () PlayerPreThink = { - // We'll use this time for calculating ping adjusted expiration / projection / etc. - AL_UpdateClientTime(self); + FO_UpdateClientTime(); if (self.impulse) { if (self.impulse == TF_VOTENEXT) { @@ -2756,7 +2747,7 @@ void () PlayerPreThink = { // Catch all. FO_WeapState ws; FO_FillCurrentWeapState(&ws); - if ((client_time() > self.attack_finished) && + if ((self.client_time > self.attack_finished) && (ws.weapon > WEAP_AXE) && ((ws->wi)->ammo_type != AMMO_NONE)) { if (*ws->ammo_remaining == 0) W_ChangeToBestWeapon(); @@ -2927,6 +2918,7 @@ void () CheckPowerups = { }; void () PlayerPostThink = { + FO_CheckClientThink(); UpdateScoreboardInfo(self); FOPlayer fop = (FOPlayer)self; fop.RewindUpdate(); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 9b3beb0c..a5a9fe27 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -519,7 +519,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/disp.mdl"; newmis.netname = "dispenser"; - btime = client_time() + 2; + btime = time + 2; self.dispenser_ticks = 0; } else if (objtobuild == 2) { if (self.has_sentry) { @@ -531,7 +531,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/turrbase.mdl"; newmis.netname = "sentrygun"; - btime = client_time() + 5; + btime = time + 5; self.sentry_ticks = 0; } if (CheckArea(newmis, self) == 0) { diff --git a/ssqc/progs.src b/ssqc/progs.src index b8d67bdf..a838a65b 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -14,6 +14,7 @@ defs.qc ../share/common_helpers.qc qw.qc debug.qc +time.qc ../share/fo_weapons.qc events.qc roles.qc diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 6457e80b..d61093c1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -9,17 +9,25 @@ enum { }; struct antilag_settings_t { - float max_client_time_offset; - float max_projectile_slow_offset; + float max_ping; + float max_projectile_slow_ping; float rewind_detpipe; } antilag_settings; -// A monotonically increasing, latency corrected notion of client-time. -// Monotonicity guarantees that for some offset `o`: -// at t1: client_time() + o < at t2: client_time() + o FOR t2 > t1 +.float client_time; // A stable/predictable client clock +.float client_ping; // ping used for prediction [capped] +.float last_remote_client_time; // For monoticity + +.void() client_think; // client-time relative think +.float client_thinkindex; +.float client_nextthink; + +// A monotonically non-decreasing, latency corrected notion of remote +// client-time. Monotonicity guarantees that for some offset `o`: +// at t1: remote_client_time() + o < at t2: lag_time() + o FOR t2 > t1 // E.g. That you never have to worry about the correction reordering events // that `time + o` would not. -float client_time(float ct_type = CT_NOEXTERNALEFFECT); +float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT); //=========================================================================== // TEAMFORTRESS Defs @@ -217,16 +225,16 @@ float coop; .float noammo; // used for no ammo error messages // variables used for reloading -.float reload_shotgun; // Only use for map compatibility. +.float reload_finished; // when the reload will finish + +// Only use below for map ent compatibility. +.float reload_shotgun; .float reload_super_shotgun; .float reload_sniper_rifle; .float reload_grenade_launcher; .float reload_rocket_launcher; .float reload_assault_cannon; -.float reload_tick; // how often the status bar should be refreshed during reload -.float reload_time; // when the reload will finish -.float reload_clipsize; // how much ammo is currently in the reloading clip -.float reload_sniper_ticks; // used to indicate when sniper rifle (with only 1 clip) will be reloaded +// Only use above for map ent compatibility. // Assault Cannon .float heat; @@ -240,7 +248,7 @@ float coop; .float immune_to_check; // Make sure people don't do too many saveme sounds -.float last_saveme_sound; +.float next_saveme_sound; .float no_active_nail_grens; @@ -546,7 +554,6 @@ float id_extended; float remember_weapon; float discammo_pickup; float old_dropflag; -float reload_cliptick; float old_sniperrange; //float detpipe_limit; float detpipe_limit_world; @@ -791,7 +798,7 @@ string settings_to_track_list[4] = { "sv_antilag", "project_weapons", "al_rewind_detpipe", - "al_max_client_time_offset", + "al_max_remote_client_time_offset", }; typedef struct setting_t { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 9bb3b179..a23d4165 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -669,7 +669,7 @@ void () CF_Spy_Invisible = { e_timer.classname = "spytimer"; e_timer.owner = self; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = client_time() + 1; + e_timer.nextthink = time + 1; } Status_Refresh(self); @@ -990,7 +990,7 @@ void (entity pe_player, float pf_class, float is_user) CF_Spy_ChangeSkin = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = (is_user ? client_time() : time) + 1; + e_timer.nextthink = (is_user ? time : time) + 1; e_timer.skin = pf_class; Status_Refresh(pe_player); @@ -1044,7 +1044,7 @@ void (entity pe_player, float pf_team_no, float is_user) CF_Spy_ChangeColor = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = (is_user ? client_time() : time) + 1; + e_timer.nextthink = (is_user ? time : time) + 1; e_timer.team = pf_team_no; Status_Refresh(pe_player); diff --git a/ssqc/status.qc b/ssqc/status.qc index 156ba7ee..5c186ddf 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -740,33 +740,6 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { return st; } -string GetSBClipString(entity pl, float csqcactive) -{ - string msg = ""; - if (pl.tfstate & TFSTATE_RELOADING) - { - FO_WeapInfo* wi = FO_GetWeapInfo(FO_PlayerCurrentWeapon(pl)); - - if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { - msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); - } else { - if (reload_cliptick) - msg = csqcactive ? ftos(pl.reload_clipsize) : strpadl(ftos(pl.reload_clipsize), 2); - else - msg = csqcactive ? "0" : " 0"; - - msg = strcat(msg, "/"); - msg = strcat(msg, (csqcactive ? ftos(wi->clip_size) : strpadr(ftos(wi->clip_size), 3))); - } - } - else - { - msg = ClipSizeToString(pl, csqcactive); - } - - return msg; -} - string GetSBClassInfo(entity pl, float csqcactive) { string st1 = ""; @@ -831,7 +804,7 @@ void UpdateClientIDString(entity pl) { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_ID); // identify - if (pl.ident_string && time < pl.ident_time) { + if (pl.ident_string && self.client_time < pl.ident_time) { WriteString(MSG_MULTICAST, pl.ident_string); } else { WriteString(MSG_MULTICAST, ""); @@ -848,7 +821,7 @@ void UpdateClientStatusBar(entity pl) string msg = ""; msg_entity = pl; - string clipMsg = GetSBClipString(pl, TRUE); + string clipMsg = ClipSizeToString(pl, TRUE); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SBAR); @@ -1264,7 +1237,7 @@ void (entity pl) RefreshStatusBar = { st2 = ""; // status line 3 column 2 - clip size - st2 = strcat(Q"\sClip\s: ", GetSBClipString(pl, csqcactive)); + st2 = strcat(Q"\sClip\s: ", ClipSizeToString(pl, csqcactive)); // status line 3 column 3 - grenade 1 count st3 = strcat(Q"\sGren1\s: ", ftos(pl.no_grenades_1)); @@ -1280,7 +1253,7 @@ void (entity pl) RefreshStatusBar = { s3 = strzone(s3); // identify - if (pl.ident_string != string_null && time < pl.ident_time) { + if (pl.ident_string != string_null && self.client_time < pl.ident_time) { ident = strcat(pl.ident_string, "\n\n"); } else { ident = "\n\n\n\n"; @@ -1332,15 +1305,13 @@ string(entity pl, float csqcactive) ClipSizeToString = if (!wi->needs_reload) return ""; - if (wi->clip_size - *ws->clip_fired > *ws->ammo_remaining) - *ws->clip_fired = wi->clip_size - *ws->ammo_remaining; - float rem = min(wi->clip_size - *ws->clip_fired, 999); + float clip_rem = min(wi->clip_size - *ws->clip_fired - pl.last_still_loading, 999); string st = ""; if (csqcactive) - st = strcat(ftos(floor(rem)), "/", ftos(wi->clip_size)); + st = strcat(ftos(floor(clip_rem)), "/", ftos(wi->clip_size)); else - st = strcat(strpadl(ftos(rem), 2), "/", strpadr(ftos(wi->clip_size), 3)); + st = strcat(strpadl(ftos(clip_rem), 2), "/", strpadr(ftos(wi->clip_size), 3)); return st; }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 4658c89d..500243cc 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -25,7 +25,7 @@ void () AutoId = { return; } - if (time > self.ident_time || !self.ident_time) { + if (self.client_time > self.ident_time || !self.ident_time) { // remove ident string from memory if (self.ident_string != string_null) { @@ -663,7 +663,6 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Old dropflag behaviour", old_dropflag, "", 1); CF_PrintSetting("Remember weapon", remember_weapon, "", 1); CF_PrintSetting("Pick up discarded ammo", discammo_pickup, "", 1); - CF_PrintSetting("Reload clip tick", reload_cliptick, "", 1); CF_PrintSetting("ID extras", id_extended, "", 1); CF_PrintSetting("Display class tips", classtips, "", 1); CF_PrintSetting("Old grenades", old_grens, "", 1); @@ -1097,11 +1096,12 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { else if (inp == 2) tGrenade.impulse = TF_GRENADE_2; - tGrenade.nextthink = client_time() + 0.8; + float time_base = client_to_global_time(remote_client_time()); + tGrenade.nextthink = time_base + 0.8; if (gtype == GR_TYPE_CALTROP) - tGrenade.heat = client_time() + 0.5 + 0.5; + tGrenade.heat = time_base + 0.5 + 0.5; else { - tGrenade.heat = client_time() + 3 + 0.8; + tGrenade.heat = time_base + 3 + 0.8; RemoveGrenadeTimers(); @@ -1109,7 +1109,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { local float notimers = stof(infokey(self, "nt")); if (grentimers && notimers != 1) { timer = spawn(); - timer.nextthink = client_time() + 0.8; + timer.nextthink = time_base + 0.8; timer.think = GrenadeTimer; timer.heat = 4; timer.owner = self; diff --git a/ssqc/time.qc b/ssqc/time.qc new file mode 100644 index 00000000..f827530b --- /dev/null +++ b/ssqc/time.qc @@ -0,0 +1,50 @@ +float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT) { + float offset = self.client_ping; // Already bounded by max_ping + + switch (ct_type) { + case CT_SLOW_PROJECTILE: + offset = min(offset, antilag_settings.max_projectile_slow_ping); + break; + } + + float target = self.client_time - offset; + if (self.last_remote_client_time > target) + return self.last_remote_client_time; + + self.last_remote_client_time = target; + return target; +} + +// Note: Delta has jitter of up to ~frame +inline float client_to_global_time(float ctime) { + return time + (ctime - self.client_time); +} + + +static void think_nop() {} +void FO_SetClientThink(void() func, float offset, float override = TRUE) { + self.think = think_nop; + self.nextthink = 0; + + self.client_think = func; + self.client_nextthink = self.client_time + offset; +} + +void FO_CheckClientThink() { + if (self.client_nextthink && self.client_time >= self.client_nextthink) { + float held_client_time = self.client_time; + + self.client_time = self.client_nextthink; + self.client_nextthink = 0; + self.client_think(); + + self.client_time = held_client_time; + } +} + +void FO_UpdateClientTime() { + self.client_time += frametime; + + float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; + self.client_ping = min(antilag_settings.max_ping, ping); +} diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 9971b8f6..dae34f8c 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -192,7 +192,7 @@ void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) att_delay *= 2; - self.attack_finished = client_time() + att_delay; + self.attack_finished = self.client_time + att_delay; }; float () W_FireAxe = { @@ -1782,7 +1782,7 @@ void () W_Attack = { }; float WeaponReady() { - if (client_time() >= self.attack_finished && + if (self.client_time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) return TRUE; @@ -2579,6 +2579,9 @@ void () W_WeaponFrame = { return; } + if (FO_ReloadFrame()) + return; + if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && From 9f151f50e08a92e34490cad4cabe26d8a1c3cc7d Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 6 Oct 2022 01:45:09 -0700 Subject: [PATCH 1716/2474] Move animations to client_time Index animations off client_time so that they can be more tightly synchronized, also repackage them so that we can share animation definition between CSQC and SSQC. --- ssqc/client.qc | 27 +-- ssqc/hwguy.qc | 11 ++ ssqc/player.qc | 457 ++++++++++++++---------------------------------- ssqc/weapons.qc | 15 +- 4 files changed, 160 insertions(+), 350 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 47d0f2dd..3aeaf5a4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -71,6 +71,8 @@ entity (entity e)TeamFortress_GetPracticeSpawn; void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); +void StopAssCan(); + void (float n) CSEv_SetPlayerImpulse_f = { bprint(PRINT_HIGH, self.netname, "\n"); bprint(PRINT_HIGH, "setting impulse ", ftos(n), "\n"); @@ -2467,6 +2469,8 @@ void () PlayerDeathThink = { } }; +void player_asscan_down1(); + void () PlayerJump = { local entity te; local float stumble; @@ -2491,16 +2495,10 @@ void () PlayerJump = { else FO_Sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } - if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.heat = 0; - self.count = 1; - player_assaultcannondown(); - } + + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) + StopAssCan(); + return; } @@ -2521,14 +2519,7 @@ void () PlayerJump = { sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); self.antispam_cannon_air = time + 3; } - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.count = 1; - self.heat = 0; - player_assaultcannondown(); + StopAssCan(); } else { self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index dd7ec290..a8b42038 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -142,6 +142,17 @@ void FireAssCan (float shotcount, vector dir, vector spread) } } +void StopAssCan() { + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { + self.tfstate = self.tfstate | TFSTATE_AIMING; + TeamFortress_SetSpeed(self); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + TeamFortress_SetSpeed(self); + //self.weaponframe = 0; + player_asscan_down1(); + } +} + void FO_LockToggle () { if (self.tfstate & TFSTATE_LOCK) { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); diff --git a/ssqc/player.qc b/ssqc/player.qc index 12a962e2..bf06a2fe 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -83,332 +83,170 @@ void () player_touch = { } }; -void () player_stand1 =[17, player_stand1] { +void player_stand1() { + FO_SetClientThink(player_stand1, 0.1); + + self.frame = 17; self.weaponframe = 0; + if (self.velocity_x || self.velocity_y) { self.walkframe = 0; player_run(); return; } + if (IsSlotMelee(self.current_slot)) { - if (self.walkframe >= 12) { + if (self.walkframe >= 12) self.walkframe = 0; - } self.frame = 17 + self.walkframe; } else { - if (self.walkframe >= 5) { + if (self.walkframe >= 5) self.walkframe = 0; - } self.frame = 12 + self.walkframe; } - self.walkframe = self.walkframe + 1; + self.walkframe++; }; -void () player_run =[6, player_run] { +void player_run() { + FO_SetClientThink(player_run, 0.1); + + self.frame = 6; self.weaponframe = 0; + if (!self.velocity_x && !self.velocity_y) { self.walkframe = 0; player_stand1(); return; } - if (FO_CurrentWeapon() <= WEAP_AXE) { - if (self.walkframe >= 6) { - self.walkframe = 0; - } - self.frame = 0 + self.walkframe; - } else { - if (self.walkframe >= 6) { - self.walkframe = 0; - } - self.frame = self.frame + self.walkframe; - } - self.walkframe = self.walkframe + 1; -}; - -void () player_shot1 =[113, player_shot2] { - self.weaponframe = 1; - muzzleflash(); -}; - -void () player_shot2 =[114, player_shot3] { - self.weaponframe = 2; -}; - -void () player_shot3 =[115, player_shot4] { - self.weaponframe = 3; -}; - -void () player_shot4 =[116, player_shot5] { - self.weaponframe = 4; -}; - -void () player_shot5 =[117, player_shot6] { - self.weaponframe = 5; -}; - -void () player_shot6 =[118, player_run] { - self.weaponframe = 6; -}; - -void () player_autorifle1 =[113, player_autorifle2] { - self.weaponframe = 1; - muzzleflash(); -}; - -void () player_autorifle2 =[114, player_autorifle3] { - self.weaponframe = 2; -}; - -void () player_autorifle3 =[118, player_run] { - self.weaponframe = 6; -}; - -void () player_axe1 =[119, player_axe2] { - self.weaponframe = 1; - - if (superaxe) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axe2 =[120, player_axe3] { - self.weaponframe = 2; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axe3 =[121, player_axe4] { - self.weaponframe = 3; - - if (!superaxe) - W_FireAxe(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axe4 =[122, player_run] { - self.weaponframe = 4; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb1 =[124, player_axeb2] { - self.weaponframe = 5; - - if (superaxe) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb2 =[125, player_axeb3] { - self.weaponframe = 6; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb3 =[126, player_axeb4] { - self.weaponframe = 7; - - if (!superaxe) - W_FireAxe(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb4 =[127, player_run] { - self.weaponframe = 8; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_spanner1 =[119, player_spanner2] { - self.weaponframe = 1; - - if (superspanner) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_spanner2 =[120, player_spanner3] { - self.weaponframe = 2; - - if (superspanner && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_spanner3 =[121, player_spanner4] { - self.weaponframe = 3; - - if (!superspanner) - W_FireSpanner(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_spanner4 =[122, player_run] { - self.weaponframe = 4; - - if (superspanner && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_knife1 =[119, player_knife2] { - self.weaponframe = 1; - - if (superknife) - self.hit_in_current_animation = W_FireKnife(); -}; - -void () player_knife2 =[120, player_knife3] { - self.weaponframe = 2; - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); + // Note: Reverses animation when walking backwards + self.walkframe = (self.walkframe + (self.movement_x < 0 ? -1 : 1) + 6) % 6; + self.frame = (IsSlotMelee(self.current_slot) ? 0 : 6) + self.walkframe; }; -void () player_knife3 =[121, player_knife4] { - self.weaponframe = 3; +static void think_nop() {} - if (!superknife || (superknife_multihit && !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); +struct anim_t { + int num_frames, num_wf; + int frames[9]; + int weaponframes[9]; + int muzzle_flash; // muzzle flash on weaponframe index 0 + int loop; }; -void () player_knife4 =[122, player_run] { - self.weaponframe = 4; +void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { + int tidx = self.client_thinkindex++; - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; + int wfi = tidx % anim->num_wf; + self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; + if (wfi == 0 && anim->muzzle_flash) + muzzleflash(); -void () player_knifeb1 =[125, player_knifeb2] { - self.weaponframe = 5; + int fi = tidx % anim->num_frames; + self.frame = anim->frames[fi] ?: anim->frames[0] + fi; - if (superknife) - self.hit_in_current_animation = W_FireKnife(); -}; + if (wfi == anim->num_wf - 1 && !anim->loop) + FO_SetClientThink(player_run, 0.1); + else + FO_SetClientThink(parent_thunk, 0.1); -void () player_knifeb2 =[126, player_knifeb3] { - self.weaponframe = 6; + if (extra != think_nop) + extra(); +} - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; +anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; +void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } +void player_rocket1() { self.client_thinkindex = 0; player_rocketN(); } -void () player_knifeb3 =[127, player_knifeb4] { - self.weaponframe = 7; +anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; +void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } +void player_shot1() { self.client_thinkindex = 0; player_shotN(); } - if (!superknife || (superknife_multihit && !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; -void () player_knifeb4 =[128, player_run] { - self.weaponframe = 8; +anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; +void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } +void player_autorifle1() { self.client_thinkindex = 0; player_autorifleN(); } - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; -void () player_medikit1 =[119, player_medikit2] { - self.weaponframe = 1; +static void axe_extra() { + float weapon = FO_CurrentWeapon(); + float* flag; + int() w_attack; - if (supermedikit) - self.hit_in_current_animation = W_FireMedikit(); -}; + // We'd use default below but compiler can't recognize that init is + // guaranteed then. + flag = &superaxe; + w_attack = W_FireAxe; -void () player_medikit2 =[120, player_medikit3] { - self.weaponframe = 2; + switch (weapon) { + case WEAP_MEDIKIT: + flag = &supermedikit; + w_attack = W_FireMedikit; + break; + case WEAP_SPANNER: + flag = &superspanner; + w_attack = W_FireSpanner; + break; + case WEAP_KNIFE: + flag = &superknife; + w_attack = W_FireKnife; + break; + } - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; + if ((*flag && !self.hit_in_current_animation) || + (!*flag && self.weaponframe == 3)) + self.hit_in_current_animation = w_attack(); -void () player_medikit3 =[121, player_medikit4] { - self.weaponframe = 3; + if (weapon == WEAP_KNIFE && superknife && superknife_multihit) + self.hit_in_current_animation = FALSE; +} - if (!supermedikit) - W_FireMedikit(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; +anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; +void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } +void player_axe1() { self.client_thinkindex = 0; player_axeN(); } -void () player_medikit4 =[122, player_run] { - self.weaponframe = 4; +anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; +void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } +void player_axeb1() { self.client_thinkindex = 0; player_axebN(); } - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; +void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } +void player_spanner1() { self.client_thinkindex = 0; player_spannerN(); } -void () player_medikitb1 =[125, player_medikitb2] { - self.weaponframe = 5; +void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } +void player_knife1() { self.client_thinkindex = 0; player_knifeN(); } - if (supermedikit) - self.hit_in_current_animation = W_FireMedikit(); -}; - -void () player_medikitb2 =[126, player_medikitb3] { - self.weaponframe = 6; +// TODO: zel had this on 125, but I think it should be on 124. Double check. +void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } +void player_knifeb1() { self.client_thinkindex = 0; player_knifebN(); } - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; +void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } +void player_medikit1() { self.client_thinkindex = 0; player_medikitN(); } -void () player_medikitb3 =[127, player_medikitb4] { - self.weaponframe = 7; +// TODO: zel had this on 125, but I think it should be on 124. Double check. +void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } +void player_medikitb1() { self.client_thinkindex = 0; player_medikitbN(); } - if (!supermedikit) - W_FireMedikit(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; -void () player_medikitb4 =[128, player_run] { - self.weaponframe = 8; - - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; - -void () player_nail1 =[103, player_nail2] { - muzzleflash(); +void nail_extra() { if (!self.button0 || intermission_running) { player_run(); return; } - self.weaponframe = self.weaponframe + 1; - if (self.weaponframe == 9) { - self.weaponframe = 1; - } - SuperDamageSound(); - if (self.nailpos == 0) { - W_FireSpikes(4); - self.nailpos = 1; - } else { - W_FireSpikes(-4); - self.nailpos = 0; - } -}; -void () player_nail2 =[104, player_nail1] { - if (!self.button0 || intermission_running) { - player_run(); - return; - } - self.weaponframe = self.weaponframe + 1; - if (self.weaponframe == 9) { - self.weaponframe = 1; - } - if (!old_ng_rof) { + float idx = (self.client_thinkindex - 1) % 2; + if (idx == 0 || !old_ng_rof) { SuperDamageSound(); - if (self.nailpos == 0) { - W_FireSpikes(4); - self.nailpos = 1; - } else { - W_FireSpikes(-4); - self.nailpos = 0; - } - } -}; + W_FireSpikes(self.nailpos ? 4 : -4); + self.nailpos = 1 - self.nailpos; + } +} + +anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; +void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } +void player_nail1() { self.client_thinkindex = 0; player_nailN(); } + +void player_asscan_fire(); +void player_asscan_down1(); static float CheckNeedAssaultCannonDown() { FO_WeapState ws; @@ -418,47 +256,42 @@ static float CheckNeedAssaultCannonDown() { ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { self.tfstate |= TFSTATE_AIMING; TeamFortress_SetSpeed(self); - self.count = 0; - player_assaultcannondown(); + player_asscan_down1(); return TRUE; } return FALSE; } -void () player_assaultcannon; -void () player_assaultcannonup =[103, player_assaultcannonup] { +void asscan_up_extra() { if (CheckNeedAssaultCannonDown()) return; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); self.fire_held_down = 1; - if (self.count == 0) + if (self.client_thinkindex == 1) // Already incremented FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - SuperDamageSound(); - if ((self.count != 2) && (self.count != 4)) - self.weaponframe = (self.weaponframe + 1) % 4; - if (self.count++ >= 5) // 600ms spin up - player_assaultcannon(); + if (self.client_thinkindex == 6) // 600ms spin up + player_asscan_fire(); else Attack_Finished(wi->attack_time); -}; +} -void () player_assaultcannon =[103, player_assaultcannon] { +void asscan_fire_extra() { if (CheckNeedAssaultCannonDown()) return; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) && !(self.tfstate & TFSTATE_LOCK)) { - if (self.count % 2 == 0) { - muzzleflash(); + + if (self.client_thinkindex % 2 == 0) FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - } SuperDamageSound(); - self.weaponframe = self.weaponframe == 2 ? 4 : 2; self.tfstate |= TFSTATE_AIMING; if (!cannon_move) @@ -472,16 +305,16 @@ void () player_assaultcannon =[103, player_assaultcannon] { FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); self.weaponframe = self.weaponframe == 2 ? 0 : 2; } - self.count++; Attack_Finished(wi->attack_time); -}; +} -void () player_assaultcannondown =[103, player_assaultcannondown] { - if (self.count == 0) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); +void asscan_down_extra() { FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (self.count >= 14) { // 1.5s down + if (self.client_thinkindex == 1) + FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); + + if (self.client_thinkindex >= 15) { // 1.5s down self.fire_held_down = 0; self.tfstate &= ~TFSTATE_AIMING; if (!cannon_move) @@ -493,14 +326,21 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); } - } else if (self.count % 2 == 0) { - self.weaponframe = (self.weaponframe + 1) % 4; } - - self.count++; Attack_Finished(wi->attack_time); }; +anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; +anim_t anim_asscan_fire = { 1, 4, {103}, {2, 4}, FALSE, TRUE}; +anim_t anim_asscan_down = { 1, 8, {103}, {1, 1, 2, 2, 3, 3, 4, 4}, FALSE, TRUE}; + +void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } +void player_asscan_up1() { self.client_thinkindex = 0; player_asscan_upN(); } + +void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } +void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } +void player_asscan_down1() { self.client_thinkindex = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } + void () player_light1 =[105, player_light2] { muzzleflash(); if (!self.button0 || intermission_running) { @@ -530,31 +370,6 @@ void () player_light2 =[106, player_light1] { Attack_Finished(0.2); }; -void () player_rocket1 =[107, player_rocket2] { - self.weaponframe = 1; - muzzleflash(); -}; - -void () player_rocket2 =[108, player_rocket3] { - self.weaponframe = 2; -}; - -void () player_rocket3 =[109, player_rocket4] { - self.weaponframe = 3; -}; - -void () player_rocket4 =[110, player_rocket5] { - self.weaponframe = 4; -}; - -void () player_rocket5 =[111, player_rocket6] { - self.weaponframe = 5; -}; - -void () player_rocket6 =[112, player_run] { - self.weaponframe = 6; -}; - void (float num_bubbles) DeathBubbles; void () PainSound = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index dae34f8c..05639f60 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -195,7 +195,7 @@ void (float att_delay) Attack_Finished = { self.attack_finished = self.client_time + att_delay; }; -float () W_FireAxe = { +int () W_FireAxe = { local vector source; local vector org; local vector def; @@ -394,7 +394,7 @@ int () W_FireSpanner = { } }; -float () W_FireMedikit = { +int () W_FireMedikit = { local vector source; local vector org; local float healam; @@ -1607,23 +1607,16 @@ void () W_ChangeToBestWeapon = { void () player_axe1; void () player_axeb1; - void () player_spanner1; -void () player_spanner2; -void () player_spanner3; -void () player_spanner4; - void () player_knife1; void () player_knifeb1; - void () player_shot1; void () player_nail1; void () player_light1; void () player_rocket1; void () player_autorifle1; -void () player_assaultcannonup; -void () player_assaultcannondown; +void () player_asscan_up1; void () player_medikit1; void () player_medikitb1; @@ -1729,7 +1722,7 @@ void () W_Attack = { self.immune_to_check = time + 5; self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); - player_assaultcannonup(); + player_asscan_up1(); } } else if (ws.weapon == WEAP_FLAMETHROWER) { player_shot1(); From 3fd8fa38cb08aecf18160f9dcb437ee8b4f41582 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:03:46 -0700 Subject: [PATCH 1717/2474] Add weapon prediction infrastructure Create a per-player entity for storing and communicating weapon-prediction state. Introduce a hybrid-driven client_think() that can be used to synchronize and initiate animation. Much of this infrastructure is inspired by the ktx/reki implementations. Annoying subtlety: We use (deprecated) visible dimension stuff for the flash code, if this isn't set, no one gets updates on the entity. --- csqc/csprogs.src | 1 + csqc/main.qc | 7 +- share/defs.h | 2 +- share/fo_weapon_predict.qc | 304 +++++++++++++++++++++++++++++++++++++ share/fo_weapons.qc | 7 + ssqc/client.qc | 7 + ssqc/progs.src | 2 + 7 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 share/fo_weapon_predict.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 81b6c037..437e56c6 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -13,6 +13,7 @@ csextradefs.qc ../share/common_helpers.qc ../share/common_vote.qc ../share/fo_weapons.qc +../share/fo_weapon_predict.qc sui_sys.qc vote.qc status.qc diff --git a/csqc/main.qc b/csqc/main.qc index 60b27f43..03d77eda 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,6 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // } FO_Weapons_Init(); + FO_WeaponPred_Init(FALSE); // Server packet enables. CsGrenTimer::Init(); registercommand("fo_hud_editor"); @@ -123,7 +124,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) setproperty(VF_DRAWENGINESBAR, 1); - addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view + addentities((intermission?0:wp_model_mask)|MASK_ENGINE); renderscene(); @@ -401,6 +402,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { void(float isnew) CSQC_Ent_Update = { float etype = readbyte(); switch (etype) { + case ENT_WEAPONPRED: + EntUpdate_WeaponPred(isnew); + break; default: error("Unhandled CSQC entity\n"); return; @@ -408,7 +412,6 @@ void(float isnew) CSQC_Ent_Update = { }; void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and will no longer be tracked... - print("CSQC_Ent_Remove\n"); remove(self); }; diff --git a/share/defs.h b/share/defs.h index ad1d2145..92a38b23 100644 --- a/share/defs.h +++ b/share/defs.h @@ -298,7 +298,7 @@ /*======================================================*/ // Opaque token that encapsulates slots for correctness. -struct Slot { int id; }; +typedef struct { int id; } Slot; // Some of the toggleflags aren't used anymore, but the bits are still // there to provide compatability with old maps diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc new file mode 100644 index 00000000..a743434c --- /dev/null +++ b/share/fo_weapon_predict.qc @@ -0,0 +1,304 @@ +#define ENT_WEAPONPRED 100 + +enumflags { + FOWP_CTIME, + FOWP_IMPULSE, + FOWP_TFSTATE, + FOWP_CLIP, + FOWP_THINK, + FOWP_TFSTATE, + FOWP_WF, + FOWP_CLASS, +}; +#define FOWP_ALL 0xFF + +struct predict_tf_state { + int playerclass; + int impulse; + Slot current_slot, queue_slot; + + float tfstate; + + float client_time; + int weaponframe; + + float attack_finished; + float client_nextthink; + float client_thinkindex; +}; + +#ifdef SSQC +.float weapon_pred_enabled; +.predict_tf_state predict_state; +.entity predict_entity; + +.float client_nextthink; +.float client_thinkindex; +#else +predict_tf_state pstate_pred, pstate_server; + +struct pengine_t { + float is_effectframe; + float last_effectframe; +} pengine; + +#define MASK_PRED_VIEWMODEL 256 +// Must include MASK_PRED_VIEWMODEL or we lose updates. +// We only add/remove MASK_VIEWMODEL. +float wp_model_mask; + +void FO_WeaponPred_Init(float enabled) { + wp_model_mask = enabled ? MASK_PRED_VIEWMODEL : MASK_VIEWMODEL; +} +#endif + +#ifdef SSQC +#define OP1(_op, _f1) (player.predict_state.##_f1 _op player.##_f1) +#define OP2(_op, _j, _f1, _f2) OP1(_op, _f2) _j OP1(_op, _f1) +#define OP3(_op, _j, _f1, _f2, _f3) OP2(_op, _j, _f2, _f3) _j OP1(_op, _f1) +#define OP4(_op, _j, _f1, _f2, _f3, _f4) OP3(_op, _j, _f2, _f3, _f4) _j OP1(_op, _f1) +#define M1(_bit, _f1) if (OP1(!=, _f1)) { mask |= _bit; OP1(=, _f1); } +#define M2(_bit, _f1, _f2) if (OP2(!=, ||, _f1, _f2)) { mask |= _bit; OP2(=, ;, _f1, _f2); } +#define M3(_bit, _f1, _f2, _f3) if (OP3(!=, ||, _f1, _f2, _f3)) { mask |= _bit; OP3(=, ;, _f1, _f2, _f3); } +#define M4(_bit, _f1, _f2, _f3, _f4) if (OP4(!=, ||, _f1, _f2, _f3, _f4)) { mask |= _bit; OP4(=, ;, _f1, _f2, _f3, _f4); } + +void UpdateWeaponPred(entity player) { + float mask = FOWP_CTIME; + + player.predict_state.client_time = player.client_time; + + M1(FOWP_CLASS, playerclass); + M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); + M1(FOWP_TFSTATE, tfstate); + M3(FOWP_THINK, attack_finished, client_nextthink, client_thinkindex) + + player.predict_entity.SendFlags = mask; +} + +#undef OP1 +#undef OP2 +#undef OP3 +#undef OP4 +#undef M1 +#undef M2 +#undef M3 +#undef M4 +#endif + +#ifdef SSQC +#define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) +float WeaponPred_SendEntity(entity to_player, float sendflags) { + if (to_player != self.owner) + return FALSE; + + WriteByte(MSG_ENTITY, ENT_WEAPONPRED); + WriteByte(MSG_ENTITY, sendflags); +#else +float() ReadByte = #360; +float() ReadFloat = #367; +void InitPredEnt(entity e); + +#define COMM(_type, _field) pstate_server.##_field = Read##_type() +void EntUpdate_WeaponPred(float isnew) { + float sendflags = readbyte(); +#endif + if (sendflags & FOWP_CTIME) { + COMM(Float, client_time); + } + + if (sendflags & FOWP_CLASS) { + COMM(Byte, playerclass); + } + + if (sendflags & FOWP_IMPULSE) { + COMM(Byte, impulse); + COMM(Byte, current_slot.id); + COMM(Byte, queue_slot.id); + } + + if (sendflags & FOWP_TFSTATE) { + COMM(Float, tfstate); + } + + if (sendflags & FOWP_THINK) { + COMM(Float, client_nextthink); + COMM(Float, client_thinkindex); + } + + if (sendflags & FOWP_WF) { + COMM(Byte, weaponframe); + COMM(Float, attack_finished); + } +#ifdef SSQC + return TRUE; +#else + if (isnew) + InitPredEnt(self); +#endif +} + +#ifdef SSQC +float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); + +inline float WeaponPred_Active(entity player) { + return player.weapon_pred_enabled; +} + +void WeaponPred_Init(entity player) { + // Server side is once per connect. + if (!FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "on")) { + player.weapon_pred_enabled = FALSE; + return; + } + + player.weapon_pred_enabled = TRUE; + + entity pe = spawn(); + pe.owner = player; + pe.classname = "WeaponPred"; + pe.dimension_seen = DMN_FLASH | DMN_NOFLASH; + pe.pvsflags = PVSF_IGNOREPVS; + pe.SendEntity = WeaponPred_SendEntity; + setorigin(pe, [0, 0, 0]); + + player.predict_entity = pe; + sprint(self, PRINT_HIGH, "FortressOne: Weapon Prediction Active v0\n"); +} + +void WeaponPred_TearDown(entity player) { + if (!player.weapon_pred_enabled) + return; + + dremove(player.predict_entity); +} + +void WeaponPred_DoServerClientThink() { + while (self.client_think && self.client_time > self.client_nextthink) { + float held_client_time = self.client_time; + + self->client_time = self->client_nextthink; + self->client_nextthink = 0; + self->client_think(); + + self->client_time = held_client_time; + } +} +#endif + +#ifdef CSQC +void WeaponPred_ChangeWeapon(float input) { + Slot slot = FO_SlotByInput(input); + if (IsSlotNull(slot)) + return; // Unrecognized + + pstate_pred.current_slot = slot; + pstate_pred.weaponframe = 0; + + // UpdateViewModel will propagate. +} + +void WeaponPred_Impulse() { + if (!pstate_pred.impulse) + return; + + float clear = FALSE; + if (pstate_pred.impulse <= 7) { // Change weapon. + WeaponPred_ChangeWeapon(pstate_pred.impulse); + clear = TRUE; + } + + if (clear) + pstate_pred.impulse = 0; +} + +void WeaponPred_Attack() { + Slot slot = pstate_pred.current_slot; + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + + pstate_pred.client_thinkindex = 1; + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; +} + + +void WeaponPred_DoClientThink(void) { + +} + +void WeaponPred_UpdateViewModel() { + float pmodelindex, pframe; + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + pmodelindex = (wi->models)->modelindex; + pframe = pstate_pred.weaponframe; + + if (self.modelindex != pmodelindex) { + self.frame = pframe; + self.modelindex = pmodelindex; + self.lerpfrac = 0; + } else if (self.frame != pframe) { + self.frame2 = self.frame; + self.frame = pframe; + self.lerpfrac = 1; + } + + self.lerpfrac = max(0, self.lerpfrac - frametime * 10); +} + +float WeaponPred_ClientThink() { + pstate_pred = pstate_server; + + int pframe = servercommandframe + 1; + int eframe = clientcommandframe; + for(; pframe <= eframe; pframe++) { + int success = getinputstate(pframe); + if (!success || input_timelength <= 0) + break; + makevectors(input_angles); + + if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { + pengine.is_effectframe = TRUE; + pengine.last_effectframe = pframe; + } else { + pengine.is_effectframe = FALSE; + } + + pstate_pred.client_time += input_timelength; + if (input_impulse) + pstate_pred.impulse = input_impulse; + + if (pstate_pred.client_nextthink && + pstate_pred.client_time >= pstate_pred.client_nextthink) { + float held_client_time = pstate_pred.client_time; + + pstate_pred.client_time = pstate_pred.client_nextthink; + pstate_pred.client_nextthink = 0; + WeaponPred_DoClientThink(); + pstate_pred.client_time = held_client_time; + } + + if (pstate_pred.client_time >= pstate_pred.attack_finished) { + WeaponPred_Impulse(); + + if (input_buttons & BUTTON0) + WeaponPred_Attack(); + } + + } + + WeaponPred_UpdateViewModel(); + return PREDRAW_AUTOADD; +} + +void InitPredEnt(entity pe) { + pe.predraw = WeaponPred_ClientThink; + + self.drawmask = MASK_PRED_VIEWMODEL; + self.renderflags = RF_VIEWMODEL; + + FO_WeaponPred_Init(TRUE); + +} +#endif diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index fa0d3768..2d4adb38 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -165,6 +165,10 @@ string FO_GetWeapName(float weapon) { struct FO_WeapModels { int weapon; string model; + + // Automatically populated. + int modelindex; + }; // Indexed by WEAP_to_index() @@ -582,6 +586,9 @@ void FO_Weapons_Init() { FO_WeapModels* wm = &weapon_models[i]; ASSERTD_EQ(WEAP_to_index(wm->weapon), i); precache_model(wm->model); +#ifdef CSQC + wm->modelindex = getmodelindex(wm->model); +#endif wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; diff --git a/ssqc/client.qc b/ssqc/client.qc index 3aeaf5a4..50478d8d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -72,6 +72,8 @@ void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); void StopAssCan(); +void WeaponPred_Init(entity player); +void WeaponPred_TearDown(entity player); void (float n) CSEv_SetPlayerImpulse_f = { bprint(PRINT_HIGH, self.netname, "\n"); @@ -2918,6 +2920,8 @@ void () PlayerPostThink = { FO_FillCurrentWeapState(&ws); self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; + if (WeaponPred_Active(self)) + UpdateWeaponPred(self); if (self.view_ofs == '0 0 0') { return; @@ -3060,6 +3064,8 @@ void () ClientConnect = { } if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + WeaponPred_Init(self); + InitAllStatuses(self); UpdateClientMOTD(self); UpdateClientTeamScores(self); @@ -3198,6 +3204,7 @@ void () ClientDisconnect = { UnvoteForMap(self); } + WeaponPred_TearDown(self); }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { diff --git a/ssqc/progs.src b/ssqc/progs.src index a838a65b..6276ed43 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -15,7 +15,9 @@ defs.qc qw.qc debug.qc time.qc +../share/defs.h ../share/fo_weapons.qc +../share/fo_weapon_predict.qc events.qc roles.qc q3defs.qc From d5a25f5669b65ecfc6944eecff55ce78241f94fb Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 9 Oct 2022 19:37:07 -0700 Subject: [PATCH 1718/2474] Add model animations for the majority of weapons Unsupported weapons automatically fall-back to use the engine representation. --- csqc/csprogs.src | 2 + csqc/weapon_predict.qc | 56 ++++++ share/fo_animate.qc | 345 +++++++++++++++++++++++++++++++++++++ share/fo_weapon_predict.qc | 67 +++++-- share/fo_weapons.qc | 51 +++--- ssqc/player.qc | 258 --------------------------- ssqc/progs.src | 1 + ssqc/time.qc | 9 - ssqc/weapons.qc | 2 +- 9 files changed, 484 insertions(+), 307 deletions(-) create mode 100644 csqc/weapon_predict.qc create mode 100644 share/fo_animate.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 437e56c6..22a26953 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -14,10 +14,12 @@ csextradefs.qc ../share/common_vote.qc ../share/fo_weapons.qc ../share/fo_weapon_predict.qc +../share/fo_animate.qc sui_sys.qc vote.qc status.qc menu.qc +weapon_predict.qc main.qc events.qc hud_helpers.qc diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc new file mode 100644 index 00000000..157f8a53 --- /dev/null +++ b/csqc/weapon_predict.qc @@ -0,0 +1,56 @@ +static void prandom(void() option1, void() option2) { + option1(); +} + +void FO_CSQC_Animate(float fired) { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + if (pstate_pred.client_thinkindex == 0 && !fired) { + player_run(); + return; + } + + switch (wi->weapon) { + case WEAP_ROCKET_LAUNCHER: + case WEAP_INCENDIARY: + case WEAP_GRENADE_LAUNCHER: + case WEAP_PIPE_LAUNCHER: + player_rocketN(); break; + + case WEAP_TRANQ: + case WEAP_RAILGUN: + case WEAP_SHOTGUN: + case WEAP_SUPER_SHOTGUN: + player_shotN(); break; + + case WEAP_FLAMETHROWER: + player_flamethrowerN(); break; + + case WEAP_NAILGUN: + case WEAP_SUPER_NAILGUN: + player_nailN(); break; + + case WEAP_AXE: + prandom(player_axeN, player_axebN); break; + case WEAP_KNIFE: + prandom(player_knifeN, player_knifebN); break; + case WEAP_MEDIKIT: + prandom(player_medikitN, player_medikitbN); break; + + case WEAP_SPANNER: + player_spannerN(); break; + } +} + +void FO_CSQC_Fire() { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + pstate_pred.client_thinkindex = 0; + + // Must be set prior to animation code, which might internally modify. + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + + FO_CSQC_Animate(TRUE); +} diff --git a/share/fo_animate.qc b/share/fo_animate.qc new file mode 100644 index 00000000..a11e14c0 --- /dev/null +++ b/share/fo_animate.qc @@ -0,0 +1,345 @@ +struct anim_t { + int num_frames, num_wf; + int frames[9]; + int weaponframes[9]; + int muzzle_flash; // muzzle flash on weaponframe index 0 + int loop; +}; + +static void think_nop() {} + +#ifdef SSQC + +void nail_extra(); +void asscan_up_extra(); +void asscan_fire_extra(); +void asscan_down_extra(); +void W_PrintWeaponMessage(); +void W_ChangeToBestWeapon(); +void W_FireSpikes(float ox); +void W_FireAssaultCannon(); +int W_FireAxe(); +int W_FireKnife(); +int W_FireMedikit(); +int W_FireSpanner(); + +void SuperDamageSound(); +void FO_Sound(entity e, float chan, string samp, float vol, float atten); +void TeamFortress_SetSpeed(entity p); + +void player_run(); +void player_stand1(); +void player_asscan_fire(); +void player_asscan_down1(); + +static inline void *thinkindex() { return &self.client_thinkindex; } + +void FO_SetClientThink(void() func, float offset, float override = TRUE) { + self.think = think_nop; + self.nextthink = 0; + + self.client_think = func; + self.client_nextthink = self.client_time + offset; +} + +void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { + int tidx = self.client_thinkindex++; + + int wfi = tidx % anim->num_wf; + self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; + if (wfi == 0 && anim->muzzle_flash) + muzzleflash(); + + int fi = tidx % anim->num_frames; + self.frame = anim->frames[fi] ?: anim->frames[0] + fi; + + if (fi == anim->num_frames - 1 && !anim->loop) + FO_SetClientThink(player_run, 0.1); + else + FO_SetClientThink(parent_thunk, 0.1); + + if (extra != think_nop) + extra(); +} + +static void axe_extra() { + float weapon = FO_CurrentWeapon(); + float* flag; + int() w_attack; + + // We'd use default below but compiler can't recognize that init is + // guaranteed then. + flag = &superaxe; + w_attack = W_FireAxe; + + switch (weapon) { + case WEAP_MEDIKIT: + flag = &supermedikit; + w_attack = W_FireMedikit; + break; + case WEAP_SPANNER: + flag = &superspanner; + w_attack = W_FireSpanner; + break; + case WEAP_KNIFE: + flag = &superknife; + w_attack = W_FireKnife; + break; + } + + if (self.weaponframe == 1) + self.hit_in_current_animation = FALSE; + + if ((*flag && !self.hit_in_current_animation) || + (!*flag && self.weaponframe == 3)) + self.hit_in_current_animation = w_attack(); + + if (weapon == WEAP_KNIFE && superknife && superknife_multihit) + self.hit_in_current_animation = FALSE; +} + +void nail_extra() { + if (!self.button0 || intermission_running) { + player_run(); + return; + } + + float idx = (self.client_thinkindex - 1) % 2; + if (idx == 0 || !old_ng_rof) { + SuperDamageSound(); + W_FireSpikes(self.nailpos ? 4 : -4); + self.nailpos = 1 - self.nailpos; + } +} + +static float CheckNeedAssaultCannonDown() { + FO_WeapState ws; + FO_FillWeapState(self, MakeSlot(1), &ws); + + if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || + ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { + self.tfstate |= TFSTATE_AIMING; + TeamFortress_SetSpeed(self); + player_asscan_down1(); + return TRUE; + } + return FALSE; +} + +void asscan_up_extra() { + if (CheckNeedAssaultCannonDown()) + return; + + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + self.fire_held_down = 1; + if (self.client_thinkindex == 1) // Already incremented + FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); + SuperDamageSound(); + + if (self.client_thinkindex == 6) // 600ms spin up + player_asscan_fire(); + else + Attack_Finished(wi->attack_time); +} + +void asscan_fire_extra() { + if (CheckNeedAssaultCannonDown()) + return; + + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) + && !(self.tfstate & TFSTATE_LOCK)) { + + if (self.client_thinkindex % 2 == 0) { + muzzleflash(); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); + } + + SuperDamageSound(); + + self.tfstate |= TFSTATE_AIMING; + if (!cannon_move) + self.tfstate |= TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + + // Halve firing speed when moving too fast. + if (vlen(self.velocity) < 30 || self.count % 2 == 0) + W_FireAssaultCannon(); + } else { + FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); + self.weaponframe = self.weaponframe == 2 ? 0 : 2; + } + Attack_Finished(wi->attack_time); +} + +void asscan_down_extra() { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if (self.client_thinkindex == 1) + FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); + + if (self.client_thinkindex >= 15) { // 1.5s down + self.fire_held_down = 0; + self.tfstate &= ~TFSTATE_AIMING; + if (!cannon_move) + self.tfstate &= ~TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + + player_run(); + if (self.ammo_cells < 7 || !FO_CheckForReload()) { + W_PrintWeaponMessage(); + W_ChangeToBestWeapon(); + } + } + Attack_Finished(wi->attack_time); +}; + +void player_run() { + FO_SetClientThink(player_run, 0.1); + self.client_thinkindex = 0; + + self.frame = 6; + self.weaponframe = 0; + + if (!self.velocity_x && !self.velocity_y) { + self.walkframe = 0; + player_stand1(); + return; + } + + // Note: Reverses animation when walking backwards + self.walkframe = (self.walkframe + (self.movement_x < 0 ? -1 : 1) + 6) % 6; + self.frame = (IsSlotMelee(self.current_slot) ? 0 : 6) + self.walkframe; +}; + +void player_stand1() { + FO_SetClientThink(player_stand1, 0.1); + self.client_thinkindex = 0; + + self.frame = 17; + self.weaponframe = 0; + + if (self.velocity_x || self.velocity_y) { + self.walkframe = 0; + player_run(); + return; + } + + if (IsSlotMelee(self.current_slot)) { + if (self.walkframe >= 12) + self.walkframe = 0; + self.frame = 17 + self.walkframe; + } else { + if (self.walkframe >= 5) + self.walkframe = 0; + self.frame = 12 + self.walkframe; + } + self.walkframe++; +}; + +#else /* CSQC */ +static inline void *thinkindex() { return &pstate_pred.client_thinkindex; } + +void FO_SetClientThink(void() func, float offset, float override = TRUE) { + pstate_pred.client_nextthink = pstate_pred.client_time + offset; +} + +void player_run() { + pstate_pred.firing = FALSE; + pstate_pred.client_nextthink = 0; + pstate_pred.client_thinkindex = 0; + pstate_pred.weaponframe = 0; +} + +void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { + float tidx = (*thinkindex())++; + + float fi = tidx % anim->num_frames; + float wfi = tidx % anim->num_wf; + + float wf = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; + pstate_pred.weaponframe = wf; + + float loop = anim->loop && (input_buttons & BUTTON0); + + if (tidx > anim->num_frames - 1 && !loop) { + // Special case for CSQC since we could predict through the wrap. + player_run(); + } else if (fi == anim->num_frames - 1 && !loop) { + FO_SetClientThink(player_run, 0.1); + } else + FO_SetClientThink(parent_thunk, 0.1); + + if (extra != think_nop) + extra(); +} + +static void axe_extra() {} +static void nail_extra() { + pstate_pred.firing = TRUE; +} +static void asscan_up_extra() {} +static void asscan_fire_extra() {} +static void asscan_down_extra() {} + +#endif + +anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; +void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } +void player_rocket1() { *thinkindex() = 0; player_rocketN(); } + +anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; +void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } +void player_shot1() { *thinkindex() = 0; player_shotN(); } + + +anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; +void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } +void player_autorifle1() { *thinkindex() = 0; player_autorifleN(); } + +anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; +void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } +void player_axe1() { *thinkindex() = 0; player_axeN(); } + +anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; +void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } +void player_axeb1() { *thinkindex() = 0; player_axebN(); } + +void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } +void player_spanner1() { *thinkindex() = 0; player_spannerN(); } + +void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } +void player_knife1() { *thinkindex() = 0; player_knifeN(); } + +void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } +void player_knifeb1() { *thinkindex() = 0; player_knifebN(); } + +void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } +void player_medikit1() { *thinkindex() = 0; player_medikitN(); } + +void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } +void player_medikitb1() { *thinkindex() = 0; player_medikitbN(); } + +anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; +void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } +void player_nail1() { *thinkindex() = 0; player_nailN(); } + +anim_t anim_flamethrower = { 2, 6, {103, 104}, {1}, FALSE, TRUE }; +void player_flamethrowerN() { + client_anim_frames(player_flamethrowerN, think_nop, &anim_flamethrower); +} +void player_flamethrower1() { *thinkindex() = 0; player_flamethrowerN(); } + +anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; +anim_t anim_asscan_fire = { 1, 2, {103}, {2, 4}, FALSE, TRUE}; +anim_t anim_asscan_down = { 1, 6, {103}, {1, 1, 2, 2, 3, 3}, FALSE, TRUE}; + +void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } +void player_asscan_up1() { *thinkindex() = 0; player_asscan_upN(); } + +void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } +void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } +void player_asscan_down1() { *thinkindex() = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } + diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc index a743434c..aef06b0a 100644 --- a/share/fo_weapon_predict.qc +++ b/share/fo_weapon_predict.qc @@ -20,11 +20,14 @@ struct predict_tf_state { float tfstate; float client_time; - int weaponframe; + float weaponframe; float attack_finished; float client_nextthink; float client_thinkindex; + + // Used for prediction, not actually communicated. Reset each frame. + float firing; }; #ifdef SSQC @@ -121,13 +124,13 @@ void EntUpdate_WeaponPred(float isnew) { } if (sendflags & FOWP_THINK) { + COMM(Float, attack_finished); COMM(Float, client_nextthink); COMM(Float, client_thinkindex); } if (sendflags & FOWP_WF) { COMM(Byte, weaponframe); - COMM(Float, attack_finished); } #ifdef SSQC return TRUE; @@ -186,11 +189,13 @@ void WeaponPred_DoServerClientThink() { #endif #ifdef CSQC -void WeaponPred_ChangeWeapon(float input) { - Slot slot = FO_SlotByInput(input); - if (IsSlotNull(slot)) - return; // Unrecognized +static Slot InputToSlot(float input) { + Slot result = FO_SlotByInput(input); + return result; +} +void WeaponPred_ChangeWeapon(Slot slot) { + // TODO: Check ammo etc pstate_pred.current_slot = slot; pstate_pred.weaponframe = 0; @@ -201,28 +206,48 @@ void WeaponPred_Impulse() { if (!pstate_pred.impulse) return; - float clear = FALSE; + Slot queue_slot = SlotNull; + if (pstate_pred.impulse <= 7) { // Change weapon. - WeaponPred_ChangeWeapon(pstate_pred.impulse); - clear = TRUE; + Slot slot = InputToSlot(pstate_pred.impulse); + if (!IsSlotNull(slot)) + pstate_pred.queue_slot = slot; + pstate_pred.impulse = 0; + } + + if (pstate_pred.client_time < pstate_pred.attack_finished) + return; + + if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { + WeaponPred_ChangeWeapon(pstate_pred.queue_slot); + pstate_pred.queue_slot = SlotNull; } + float clear = FALSE; if (clear) pstate_pred.impulse = 0; } +void FO_CSQC_Fire(); + void WeaponPred_Attack() { + if (pstate_pred.firing) // Already in a continuous attack. + return; + Slot slot = pstate_pred.current_slot; FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - pstate_pred.client_thinkindex = 1; + pstate_pred.client_thinkindex = 0; pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + + FO_CSQC_Fire(); } +void FO_CSQC_Animate(float fired); void WeaponPred_DoClientThink(void) { - + FO_CSQC_Animate(FALSE); } void WeaponPred_UpdateViewModel() { @@ -231,6 +256,16 @@ void WeaponPred_UpdateViewModel() { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); + if (wi->predict_type == NO_PREDICT) { + // Fall back to engine. + self.modelindex = 0; + wp_model_mask |= MASK_VIEWMODEL; + return; + } else { + wp_model_mask &= ~MASK_VIEWMODEL; + + } + pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; @@ -279,13 +314,11 @@ float WeaponPred_ClientThink() { pstate_pred.client_time = held_client_time; } - if (pstate_pred.client_time >= pstate_pred.attack_finished) { - WeaponPred_Impulse(); - - if (input_buttons & BUTTON0) - WeaponPred_Attack(); - } + WeaponPred_Impulse(); + if ((input_buttons & BUTTON0) && + (pstate_pred.client_time >= pstate_pred.attack_finished)) + WeaponPred_Attack(); } WeaponPred_UpdateViewModel(); diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 2d4adb38..440bc2c6 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -80,8 +80,15 @@ enum AmmoType { struct FO_WeapModels; struct FO_WeapToItem; +enum PredictionType { + NO_PREDICT, + PRED_MODEL, + PRED_PROJ, +}; + struct FO_WeapInfo { int weapon; // Verification + int predict_type; AmmoType ammo_type; float clip_size; float ammo_per_shot; @@ -98,28 +105,28 @@ struct FO_WeapInfo { // REQUIRES: weapon at index i == WEAP_to_index(weap) // -ve values are placeholders signifying conditional init based on game modes. FO_WeapInfo weapon_info[] = { - { WEAP_NONE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_MEDIKIT, AMMO_CELLS, 0, 0, 0.5, 0 }, - { WEAP_SPANNER, AMMO_CELLS, 0, 0, 0.5, 0 }, - { WEAP_AXE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_SNIPER_RIFLE, AMMO_SHELLS, -9, 1, 1.5, 4 }, - { WEAP_AUTO_RIFLE, AMMO_SHELLS, 0, 1, 0.1, 0 }, - { WEAP_SHOTGUN, AMMO_SHELLS, 8, 1, 0.5, 2 }, - { WEAP_SUPER_SHOTGUN, AMMO_SHELLS, 16, 2, 0.7, 3 }, - { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, - { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 2, 0.2, 0 }, - { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, - { WEAP_PIPE_LAUNCHER, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL - { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, - { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, - { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, - { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, - { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, - { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, - { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, + { WEAP_NONE, NO_PREDICT, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_HOOK, NO_PREDICT, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_KNIFE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_MEDIKIT, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, + { WEAP_SPANNER, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, + { WEAP_AXE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_SNIPER_RIFLE, NO_PREDICT, AMMO_SHELLS, -9, 1, 1.5, 4 }, + { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0 }, + { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, + { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, + { WEAP_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.2, 0 }, + { WEAP_SUPER_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 2, 0.2, 0 }, + { WEAP_GRENADE_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 6, 1, 0.6, 4 }, + { WEAP_PIPE_LAUNCHER, PRED_MODEL, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL + { WEAP_FLAMETHROWER, PRED_MODEL, AMMO_CELLS, 0, 1, 0.15, 0 }, + { WEAP_ROCKET_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 4, 1, 0.8, 5 }, + { WEAP_INCENDIARY, PRED_MODEL, AMMO_ROCKETS, 0, 3, -9, 0 }, + { WEAP_ASSAULT_CANNON, NO_PREDICT, AMMO_SHELLS, -9, 1, 0.2, 4 }, + { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, + { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, + { WEAP_TRANQ, NO_PREDICT, AMMO_SHELLS, 0, 1, 1.5, 0 }, + { WEAP_RAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.4, 0 }, }; inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { diff --git a/ssqc/player.qc b/ssqc/player.qc index bf06a2fe..0e74bd42 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -83,264 +83,6 @@ void () player_touch = { } }; -void player_stand1() { - FO_SetClientThink(player_stand1, 0.1); - - self.frame = 17; - self.weaponframe = 0; - - if (self.velocity_x || self.velocity_y) { - self.walkframe = 0; - player_run(); - return; - } - - if (IsSlotMelee(self.current_slot)) { - if (self.walkframe >= 12) - self.walkframe = 0; - self.frame = 17 + self.walkframe; - } else { - if (self.walkframe >= 5) - self.walkframe = 0; - self.frame = 12 + self.walkframe; - } - self.walkframe++; -}; - -void player_run() { - FO_SetClientThink(player_run, 0.1); - - self.frame = 6; - self.weaponframe = 0; - - if (!self.velocity_x && !self.velocity_y) { - self.walkframe = 0; - player_stand1(); - return; - } - - // Note: Reverses animation when walking backwards - self.walkframe = (self.walkframe + (self.movement_x < 0 ? -1 : 1) + 6) % 6; - self.frame = (IsSlotMelee(self.current_slot) ? 0 : 6) + self.walkframe; -}; - -static void think_nop() {} - -struct anim_t { - int num_frames, num_wf; - int frames[9]; - int weaponframes[9]; - int muzzle_flash; // muzzle flash on weaponframe index 0 - int loop; -}; - -void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - int tidx = self.client_thinkindex++; - - int wfi = tidx % anim->num_wf; - self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; - if (wfi == 0 && anim->muzzle_flash) - muzzleflash(); - - int fi = tidx % anim->num_frames; - self.frame = anim->frames[fi] ?: anim->frames[0] + fi; - - if (wfi == anim->num_wf - 1 && !anim->loop) - FO_SetClientThink(player_run, 0.1); - else - FO_SetClientThink(parent_thunk, 0.1); - - if (extra != think_nop) - extra(); -} - -anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; -void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } -void player_rocket1() { self.client_thinkindex = 0; player_rocketN(); } - -anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; -void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } -void player_shot1() { self.client_thinkindex = 0; player_shotN(); } - - -anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; -void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } -void player_autorifle1() { self.client_thinkindex = 0; player_autorifleN(); } - - -static void axe_extra() { - float weapon = FO_CurrentWeapon(); - float* flag; - int() w_attack; - - // We'd use default below but compiler can't recognize that init is - // guaranteed then. - flag = &superaxe; - w_attack = W_FireAxe; - - switch (weapon) { - case WEAP_MEDIKIT: - flag = &supermedikit; - w_attack = W_FireMedikit; - break; - case WEAP_SPANNER: - flag = &superspanner; - w_attack = W_FireSpanner; - break; - case WEAP_KNIFE: - flag = &superknife; - w_attack = W_FireKnife; - break; - } - - if ((*flag && !self.hit_in_current_animation) || - (!*flag && self.weaponframe == 3)) - self.hit_in_current_animation = w_attack(); - - if (weapon == WEAP_KNIFE && superknife && superknife_multihit) - self.hit_in_current_animation = FALSE; -} - -anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; -void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } -void player_axe1() { self.client_thinkindex = 0; player_axeN(); } - -anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; -void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } -void player_axeb1() { self.client_thinkindex = 0; player_axebN(); } - -void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } -void player_spanner1() { self.client_thinkindex = 0; player_spannerN(); } - -void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } -void player_knife1() { self.client_thinkindex = 0; player_knifeN(); } - -// TODO: zel had this on 125, but I think it should be on 124. Double check. -void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } -void player_knifeb1() { self.client_thinkindex = 0; player_knifebN(); } - -void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } -void player_medikit1() { self.client_thinkindex = 0; player_medikitN(); } - -// TODO: zel had this on 125, but I think it should be on 124. Double check. -void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } -void player_medikitb1() { self.client_thinkindex = 0; player_medikitbN(); } - - -void nail_extra() { - if (!self.button0 || intermission_running) { - player_run(); - return; - } - - float idx = (self.client_thinkindex - 1) % 2; - if (idx == 0 || !old_ng_rof) { - SuperDamageSound(); - W_FireSpikes(self.nailpos ? 4 : -4); - self.nailpos = 1 - self.nailpos; - } -} - -anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; -void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } -void player_nail1() { self.client_thinkindex = 0; player_nailN(); } - -void player_asscan_fire(); -void player_asscan_down1(); - -static float CheckNeedAssaultCannonDown() { - FO_WeapState ws; - FO_FillWeapState(self, MakeSlot(1), &ws); - - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || - ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { - self.tfstate |= TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - player_asscan_down1(); - return TRUE; - } - return FALSE; -} - -void asscan_up_extra() { - if (CheckNeedAssaultCannonDown()) - return; - - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - self.fire_held_down = 1; - if (self.client_thinkindex == 1) // Already incremented - FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - SuperDamageSound(); - - if (self.client_thinkindex == 6) // 600ms spin up - player_asscan_fire(); - else - Attack_Finished(wi->attack_time); -} - -void asscan_fire_extra() { - if (CheckNeedAssaultCannonDown()) - return; - - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) - && !(self.tfstate & TFSTATE_LOCK)) { - - if (self.client_thinkindex % 2 == 0) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - - SuperDamageSound(); - - self.tfstate |= TFSTATE_AIMING; - if (!cannon_move) - self.tfstate |= TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - - // Halve firing speed when moving too fast. - if (vlen(self.velocity) < 30 || self.count % 2 == 0) - W_FireAssaultCannon(); - } else { - FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); - self.weaponframe = self.weaponframe == 2 ? 0 : 2; - } - Attack_Finished(wi->attack_time); -} - -void asscan_down_extra() { - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (self.client_thinkindex == 1) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); - - if (self.client_thinkindex >= 15) { // 1.5s down - self.fire_held_down = 0; - self.tfstate &= ~TFSTATE_AIMING; - if (!cannon_move) - self.tfstate &= ~TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - - player_run(); - if (self.ammo_cells < 7 || !FO_CheckForReload()) { - W_PrintWeaponMessage(); - W_ChangeToBestWeapon(); - } - } - Attack_Finished(wi->attack_time); -}; - -anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; -anim_t anim_asscan_fire = { 1, 4, {103}, {2, 4}, FALSE, TRUE}; -anim_t anim_asscan_down = { 1, 8, {103}, {1, 1, 2, 2, 3, 3, 4, 4}, FALSE, TRUE}; - -void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } -void player_asscan_up1() { self.client_thinkindex = 0; player_asscan_upN(); } - -void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } -void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } -void player_asscan_down1() { self.client_thinkindex = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } - void () player_light1 =[105, player_light2] { muzzleflash(); if (!self.button0 || intermission_running) { diff --git a/ssqc/progs.src b/ssqc/progs.src index 6276ed43..414de5b3 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -18,6 +18,7 @@ time.qc ../share/defs.h ../share/fo_weapons.qc ../share/fo_weapon_predict.qc +../share/fo_animate.qc events.qc roles.qc q3defs.qc diff --git a/ssqc/time.qc b/ssqc/time.qc index f827530b..c77f2fb4 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -21,15 +21,6 @@ inline float client_to_global_time(float ctime) { } -static void think_nop() {} -void FO_SetClientThink(void() func, float offset, float override = TRUE) { - self.think = think_nop; - self.nextthink = 0; - - self.client_think = func; - self.client_nextthink = self.client_time + offset; -} - void FO_CheckClientThink() { if (self.client_nextthink && self.client_time >= self.client_nextthink) { float held_client_time = self.client_time; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 05639f60..3b0f0f4f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1725,7 +1725,7 @@ void () W_Attack = { player_asscan_up1(); } } else if (ws.weapon == WEAP_FLAMETHROWER) { - player_shot1(); + player_flamethrower1(); W_FireFlame(); if (self.waterlevel > 2) Attack_Finished(1); From 9a1c59d3f74e484cfbe08821d8070b7769f33046 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 14:09:12 -0700 Subject: [PATCH 1719/2474] Implement predicted reload and ammo tracking Client side handling around all of the ammo/clip details so that we can reload (and not predict firing) correctly. Integrates with displayed ammo/clip/etc. --- csqc/status.qc | 12 +-- csqc/weapon_predict.qc | 12 --- share/fo_weapon_predict.qc | 205 +++++++++++++++++++++++++++++++++---- share/fo_weapons.qc | 36 ++++--- ssqc/qw.qc | 2 + 5 files changed, 216 insertions(+), 51 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 7e9128af..efea8c5f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1112,7 +1112,7 @@ var FO_Hud_Panel Hud_Panels[] = { // Style, Snap, Status {"hudoptions",FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return DrawPanel.id;}, 1}, - {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return WP_GetClip(); }}, {"fragstreak",FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {"caps",FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, {"gren1",FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, @@ -1131,14 +1131,14 @@ var FO_Hud_Panel Hud_Panels[] = { {"mapmenu",FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"health",FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, {"face",FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0, drawFacePanel, {return "";}, 0, 34}, - {"ammo",FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(getstatf(STAT_AMMO));}, 0, 34}, + {"ammo",FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(WP_CurrentAmmo());}, 0, 34}, {"ammoicon",FO_HUD_AMMO_ICON_NAME , '42 -2', '24 24', 1,0,1,0, drawAmmoPanel, {return "";}, 0, 34}, {"armour",FO_HUD_ARMOUR_NAME, '-134 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}, 0, 34}, {"armouricon",FO_HUD_ARMOUR_ICON_NAME,'-182 -2', '24 24', 1,0,1,0, drawArmourPanel, {return "";}, 0, 34}, - {"invshells",FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(getstatf(STAT_SHELLS));}, 1, 33}, - {"invnails",FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(getstatf(STAT_NAILS));}, 1, 33}, - {"invrockets",FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(getstatf(STAT_ROCKETS));}, 1, 33}, - {"invcells",FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, + {"invshells",FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(WP_GetAmmo(AMMO_SHELLS));}, 1, 33}, + {"invnails",FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(WP_GetAmmo(AMMO_NAILS));}, 1, 33}, + {"invrockets",FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(WP_GetAmmo(AMMO_ROCKETS));}, 1, 33}, + {"invcells",FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(WP_GetAmmo(AMMO_CELLS));}, 1, 33}, {"gameclock","Game Clock", '0 0' , '108 24', 1,0.8,1,0, drawClockPanel, {return gameClockString();}, 0, 10}, {"quad","Quad Icon", '-200 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}, 0, 36}, {"pent","Pentagram Icon", '-170 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}, 0, 36}, diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 157f8a53..2f465619 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -42,15 +42,3 @@ void FO_CSQC_Animate(float fired) { player_spannerN(); break; } } - -void FO_CSQC_Fire() { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - pstate_pred.client_thinkindex = 0; - - // Must be set prior to animation code, which might internally modify. - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - - FO_CSQC_Animate(TRUE); -} diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc index aef06b0a..31e4dc3a 100644 --- a/share/fo_weapon_predict.qc +++ b/share/fo_weapon_predict.qc @@ -9,8 +9,9 @@ enumflags { FOWP_TFSTATE, FOWP_WF, FOWP_CLASS, + FOWP_RELOAD, }; -#define FOWP_ALL 0xFF +#define FOWP_ALL 0xFFFF struct predict_tf_state { int playerclass; @@ -26,8 +27,13 @@ struct predict_tf_state { float client_nextthink; float client_thinkindex; + float reload_finished; + float clip_fired[4]; + + // Used for prediction, not actually communicated. Reset each frame. - float firing; + float ammo_used[AMMO_NUM_TYPES]; + float firing; }; #ifdef SSQC @@ -49,8 +55,12 @@ struct pengine_t { // Must include MASK_PRED_VIEWMODEL or we lose updates. // We only add/remove MASK_VIEWMODEL. float wp_model_mask; +float wp_enabled; + +static int WP_Enabled() { return wp_enabled; } void FO_WeaponPred_Init(float enabled) { + wp_enabled = enabled; wp_model_mask = enabled ? MASK_PRED_VIEWMODEL : MASK_VIEWMODEL; } #endif @@ -73,7 +83,10 @@ void UpdateWeaponPred(entity player) { M1(FOWP_CLASS, playerclass); M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); M1(FOWP_TFSTATE, tfstate); - M3(FOWP_THINK, attack_finished, client_nextthink, client_thinkindex) + M2(FOWP_WF, attack_finished, weaponframe); + M2(FOWP_THINK, client_nextthink, client_thinkindex); + M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) + M1(FOWP_RELOAD, reload_finished) player.predict_entity.SendFlags = mask; } @@ -95,7 +108,7 @@ float WeaponPred_SendEntity(entity to_player, float sendflags) { return FALSE; WriteByte(MSG_ENTITY, ENT_WEAPONPRED); - WriteByte(MSG_ENTITY, sendflags); + WriteFloat(MSG_ENTITY, sendflags); #else float() ReadByte = #360; float() ReadFloat = #367; @@ -103,7 +116,7 @@ void InitPredEnt(entity e); #define COMM(_type, _field) pstate_server.##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { - float sendflags = readbyte(); + float sendflags = readfloat(); #endif if (sendflags & FOWP_CTIME) { COMM(Float, client_time); @@ -124,14 +137,25 @@ void EntUpdate_WeaponPred(float isnew) { } if (sendflags & FOWP_THINK) { - COMM(Float, attack_finished); COMM(Float, client_nextthink); COMM(Float, client_thinkindex); } if (sendflags & FOWP_WF) { + COMM(Float, attack_finished); COMM(Byte, weaponframe); } + + if (sendflags & FOWP_CLIP) { + COMM(Byte, clip_fired[0]); + COMM(Byte, clip_fired[1]); + COMM(Byte, clip_fired[2]); + COMM(Byte, clip_fired[3]); + } + + if (sendflags & FOWP_RELOAD) + COMM(Float, reload_finished); + #ifdef SSQC return TRUE; #else @@ -195,27 +219,25 @@ static Slot InputToSlot(float input) { } void WeaponPred_ChangeWeapon(Slot slot) { - // TODO: Check ammo etc pstate_pred.current_slot = slot; pstate_pred.weaponframe = 0; // UpdateViewModel will propagate. } -void WeaponPred_Impulse() { - if (!pstate_pred.impulse) - return; - - Slot queue_slot = SlotNull; +void WeaponPred_Reload(); - if (pstate_pred.impulse <= 7) { // Change weapon. +void WeaponPred_Impulse() { + // Note: We might have no impulse, but a queued slot here. + if (pstate_pred.impulse >= 1 && pstate_pred.impulse <= 7) { // Change weapon Slot slot = InputToSlot(pstate_pred.impulse); if (!IsSlotNull(slot)) pstate_pred.queue_slot = slot; pstate_pred.impulse = 0; } - if (pstate_pred.client_time < pstate_pred.attack_finished) + if (pstate_pred.client_time < pstate_pred.attack_finished || + (pstate_pred.tfstate & TFSTATE_RELOADING)) return; if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { @@ -223,13 +245,151 @@ void WeaponPred_Impulse() { pstate_pred.queue_slot = SlotNull; } + if (!pstate_pred.impulse) + return; + float clear = FALSE; + + if (pstate_pred.impulse == TF_RELOAD) { + WeaponPred_Reload(); + clear = TRUE; + } + if (clear) pstate_pred.impulse = 0; } void FO_CSQC_Fire(); +static float AmmoToStat(float ammo_type) { + switch (ammo_type) { + case AMMO_SHELLS: return STAT_SHELLS; + case AMMO_ROCKETS: return STAT_ROCKETS; + case AMMO_NAILS: return STAT_NAILS; + case AMMO_CELLS: return STAT_CELLS; + } + return STAT_AMMO; +} + +float WP_GetAmmo(float ammo_type) { + if (!WP_Enabled()) + return getstatf(AmmoToStat(ammo_type)); + + if (ammo_type == AMMO_NONE) + return 0; + + float base = getstatf(AmmoToStat(ammo_type)); + base -= pstate_pred.ammo_used[ammo_type]; + return max(0, base); +} + +float WP_CurrentAmmo() { + if (!WP_Enabled()) + return getstatf(STAT_AMMO); + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + return WP_GetAmmo(wi->ammo_type); +} + +static float* ClipFired() { + float index = SlotIndex(pstate_pred.current_slot); + if (pstate_pred.playerclass == PC_DEMOMAN && + index == 1) + index = 0; // Special case: Pipebomb shares with Grenadel launcher. + + return &pstate_pred.clip_fired[index]; +} + +string WP_GetClip() { + if (!WP_Enabled()) + return SBAR.ClipSize; + + Slot slot = pstate_pred.current_slot; + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + + if (!wi->needs_reload || IsSlotNull(slot)) + return ""; + + float capacity = wi->clip_size; + float still_loading = 0; + float fired = *ClipFired(); + + if (pstate_pred.tfstate & TFSTATE_RELOADING) + still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, + pstate_pred.reload_finished); + + float clip = capacity - fired - still_loading; + return sprintf("%d/%d", clip, wi->clip_size); +} + +void WeaponPred_CheckReloadFinished() { + if ((pstate_pred.tfstate & TFSTATE_RELOADING) && + pstate_pred.client_time >= pstate_pred.reload_finished) { + pstate_pred.tfstate &= ~TFSTATE_RELOADING; + + if (pengine.is_effectframe) + print("Finished reloading\n"); + } +} + +void WeaponPred_Reload() { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + if (!wi->needs_reload) + return; + + float clip_fired = *ClipFired(); + float ammo_rem = WP_GetAmmo(wi->ammo_type); + + string msg; + if (!FO_CheckCanReload(wi, ammo_rem, clip_fired, msg)) { + if (pengine.is_effectframe) + print(msg); + return; + } + + if (pengine.is_effectframe) + print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); + + pstate_pred.tfstate |= TFSTATE_RELOADING; + float amt = min(ammo_rem, clip_fired); + (*ClipFired()) -= amt; + + pstate_pred.reload_finished = pstate_pred.client_time + + (amt / wi->clip_size) * wi->full_reload_time; +} + +float WeaponPred_IsReloading() { + return pstate_pred.tfstate & TFSTATE_RELOADING; +} + + +float WeaponPred_ConsumeAmmo(FO_WeapInfo* wi) { + if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) + return TRUE; + + int ammo = WP_GetAmmo(wi->ammo_type); + if (wi->ammo_per_shot > ammo) + return FALSE; + + if (wi->needs_reload) { + if (*ClipFired() >= wi->clip_size) { + WeaponPred_Reload(); + return FALSE; + } + } + + pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; + *ClipFired() += wi->ammo_per_shot; + + return TRUE; +} + +void FO_CSQC_Animate(float fired); + void WeaponPred_Attack() { if (pstate_pred.firing) // Already in a continuous attack. return; @@ -238,14 +398,16 @@ void WeaponPred_Attack() { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + if (!WeaponPred_ConsumeAmmo(wi)) + return; + + // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 0; pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - FO_CSQC_Fire(); + FO_CSQC_Animate(TRUE); } -void FO_CSQC_Animate(float fired); - void WeaponPred_DoClientThink(void) { FO_CSQC_Animate(FALSE); } @@ -266,6 +428,11 @@ void WeaponPred_UpdateViewModel() { } + if (pstate_pred.tfstate & TFSTATE_RELOADING) { + self.modelindex = 0; + return; + } + pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; @@ -314,11 +481,14 @@ float WeaponPred_ClientThink() { pstate_pred.client_time = held_client_time; } + WeaponPred_CheckReloadFinished(); WeaponPred_Impulse(); if ((input_buttons & BUTTON0) && + (pstate_pred.tfstate & TFSTATE_RELOADING == 0) && (pstate_pred.client_time >= pstate_pred.attack_finished)) WeaponPred_Attack(); + } WeaponPred_UpdateViewModel(); @@ -332,6 +502,5 @@ void InitPredEnt(entity pe) { self.renderflags = RF_VIEWMODEL; FO_WeaponPred_Init(TRUE); - } #endif diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 440bc2c6..7b503580 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -228,9 +228,6 @@ Slot WEAP_to_slot(float playerclass, float weapon) { return SlotNull; } -// Internal clip storage for both SSQC/CSQC. -.float clip_fired[TF_NUM_SLOTS]; - struct FO_WeapToItem { int weapon; float it_weapon; @@ -306,11 +303,26 @@ float FO_WeaponsMask(entity player) { return mask; } +// Slightly awkward construction, but convenient for calling from CSQC and SSQC. float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) { float tick = (wi->ammo_per_shot / wi->clip_size) * wi->full_reload_time; return ceil((reload_finished - now) / tick) * wi->ammo_per_shot; } +float FO_CheckCanReload(FO_WeapInfo* wi, int ammo_remaining, int clip_fired, + __out string msg) { + if (clip_fired == 0) + msg = "Clip full\n"; + else if (ammo_remaining == 0) + msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); + else if (wi->clip_size - clip_fired == ammo_remaining) + msg = strcat("All ", AMMO_to_s[wi->ammo_type], " are in the clip\n"); + else + return TRUE; + + return FALSE; // msg filled in above. +} + #ifdef SSQC struct FO_WeapState { float weapon; @@ -424,22 +436,15 @@ void FO_ReloadSlot(Slot slot, float force) { if (!wi->needs_reload) return; - string msg = string_null; - if (*ws->clip_fired == 0) - msg = "Clip full\n"; - else if (*ws->ammo_remaining == 0) - msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); - else if (wi->clip_size - *ws->clip_fired == *ws->ammo_remaining) - msg = strcat("All ", AMMO_to_s[wi->ammo_type], "are in the clip\n"); - - if (msg != string_null) { + string msg; + if (!FO_CheckCanReload(wi, *ws->ammo_remaining, *ws->clip_fired, msg)) { sprint(self, PRINT_HIGH, msg); return; - } else { - sprint(self, PRINT_HIGH, strcat("Reloading ", - FO_GetWeapName(ws->weapon), "...\n")); } + sprint(self, PRINT_HIGH, + strcat("Reloading ", FO_GetWeapName(ws->weapon), "...\n")); + Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. self.weaponmodel = ""; @@ -454,6 +459,7 @@ void FO_ReloadSlot(Slot slot, float force) { // TODO: Make ammo in clip independent from ammo_remaining (so you can't // have shots in clip that are discarded and other weirdness.) (*ws->clip_fired) -= reload_count; + self.last_still_loading = reload_count; self.reload_finished = self.client_time + reload_duration; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d61093c1..856d7c55 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -236,6 +236,8 @@ float coop; .float reload_assault_cannon; // Only use above for map ent compatibility. +.float clip_fired[TF_NUM_SLOTS]; + // Assault Cannon .float heat; From 1c2b892ae286667a067ce580f6a8696403a5e9a7 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 11:12:04 -0700 Subject: [PATCH 1720/2474] Periodic full refresh of predict state Occasionally see gaps, unclear if dropped packet or missing sync but force a periodic full refresh for sanity. Also add a (arbitrary) lower bound of 40msec around which dont enable prediction for now. Also add some global and per-client enable/disable twiddles. --- share/fo_weapon_predict.qc | 42 +++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc index 31e4dc3a..432f2fca 100644 --- a/share/fo_weapon_predict.qc +++ b/share/fo_weapon_predict.qc @@ -1,4 +1,5 @@ #define ENT_WEAPONPRED 100 +string wp_version = "v0"; enumflags { FOWP_CTIME, @@ -37,6 +38,31 @@ struct predict_tf_state { }; #ifdef SSQC + +float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); +float CF_GetSetting(string ps_short, string ps_setting, string ps_default); + +static float GlobalEnable() { + return CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); +} + +static float GlobalDisable() { + return CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); +} + +static float ClientEnable() { + // client_ping is not yet initialized. + float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; + + if (GlobalDisable() || ping < 40 * MSEC) + return FALSE; + + if (GlobalEnable()) + return TRUE; + + return FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "off"); +} + .float weapon_pred_enabled; .predict_tf_state predict_state; .entity predict_entity; @@ -75,9 +101,17 @@ void FO_WeaponPred_Init(float enabled) { #define M3(_bit, _f1, _f2, _f3) if (OP3(!=, ||, _f1, _f2, _f3)) { mask |= _bit; OP3(=, ;, _f1, _f2, _f3); } #define M4(_bit, _f1, _f2, _f3, _f4) if (OP4(!=, ||, _f1, _f2, _f3, _f4)) { mask |= _bit; OP4(=, ;, _f1, _f2, _f3, _f4); } +predict_tf_state blank_state; +.float last_full_predict_refresh; + void UpdateWeaponPred(entity player) { float mask = FOWP_CTIME; + if (time - player.last_full_predict_refresh > 1000 * MSEC) { + player.predict_state = blank_state; + player.last_full_predict_refresh = time; + } + player.predict_state.client_time = player.client_time; M1(FOWP_CLASS, playerclass); @@ -165,15 +199,12 @@ void EntUpdate_WeaponPred(float isnew) { } #ifdef SSQC -float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); - inline float WeaponPred_Active(entity player) { return player.weapon_pred_enabled; } void WeaponPred_Init(entity player) { - // Server side is once per connect. - if (!FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "on")) { + if (!ClientEnable()) { // Server side is once per connect. player.weapon_pred_enabled = FALSE; return; } @@ -189,7 +220,8 @@ void WeaponPred_Init(entity player) { setorigin(pe, [0, 0, 0]); player.predict_entity = pe; - sprint(self, PRINT_HIGH, "FortressOne: Weapon Prediction Active v0\n"); + sprint(self, PRINT_HIGH, + "FortressOne: Weapon Prediction Active ", wp_version, "\n"); } void WeaponPred_TearDown(entity player) { From ea38910fb080e38f6b9781006881688eb5cb4d81 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 18:58:39 -0700 Subject: [PATCH 1721/2474] Rewrite reloading Synchronizing client and server state for prediction and latency corection benefits from some clean touch points to work with and the current reload code is a spaghetti nightmare. Rework it while also coalescing the state we'll need for weapon prediction. Can be temporarily toggled with `rcon localinfo dunr off` --- share/defs.h | 1 + ssqc/actions.qc | 31 +++++++++++++++----- ssqc/progs.src | 1 + ssqc/weapons.qc | 77 ++++++++++++++++++++----------------------------- 4 files changed, 57 insertions(+), 53 deletions(-) diff --git a/share/defs.h b/share/defs.h index c7f48f09..a335c43c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -724,6 +724,7 @@ #define WEAP_DETPACK 131072 #define WEAP_TRANQ 262144 #define WEAP_LASER 524288 +#define WEAP_RAILGUN 524288 // still room for 12 more weapons // but we can remove some by giving the weapons // a weapon mode (like the rifle) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 99d2b3e8..d77f6780 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -485,7 +485,17 @@ void () RestoreDefaultWeapon = { } }; -void TeamFortress_ReloadWeapon(float weap) +void TeamFortress_OldReloadWeapon(float weap); +void FO_ReloadWeapon(float weap, float force); + +void TeamFortress_ReloadWeapon(float weap, float force) { + if (FO_UseNewReload()) + FO_ReloadWeapon(weap, force); + else + TeamFortress_OldReloadWeapon(weap); +} + +void TeamFortress_OldReloadWeapon(float weap) { RestoreDefaultWeapon(); @@ -496,6 +506,7 @@ void TeamFortress_ReloadWeapon(float weap) if (self.tfstate & TFSTATE_RELOADING) { return; } + if (weap == WEAP_SHOTGUN) { if (self.ammo_shells == 0) { sprint(self, PRINT_HIGH, "Out of shells\n"); @@ -759,7 +770,11 @@ void TeamFortress_ReloadWeapon(float weap) } void () TeamFortress_ReloadCurrentWeapon = { - TeamFortress_ReloadWeapon(self.current_weapon); + TeamFortress_ReloadWeapon(self.current_weapon, FALSE); +}; + +void () TeamFortress_ForceReloadCurrentWeapon = { + TeamFortress_ReloadWeapon(self.current_weapon, TRUE); }; void (float slot) TeamFortress_ReloadSlot = { @@ -778,7 +793,7 @@ void (float slot) TeamFortress_ReloadSlot = { return; weap = W_WeaponSlot3(); } - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); } else { if (slot < 1 || slot > 7) @@ -798,7 +813,7 @@ void (float slot) TeamFortress_ReloadSlot = { else if (slot == 7) weap = W_OldWeaponSlot7(); if (weap != 0) - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); } }; @@ -809,7 +824,7 @@ void () TeamFortress_ReloadNext = { // reload current slot first slot = W_GetSlot(self.current_weapon); if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon); + TeamFortress_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -828,7 +843,7 @@ void () TeamFortress_ReloadNext = { if (CheckForAmmo(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); reload = 1; break; } @@ -837,7 +852,7 @@ void () TeamFortress_ReloadNext = { else { slot = W_OldGetSlot(self.current_weapon); if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon); + TeamFortress_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -860,7 +875,7 @@ void () TeamFortress_ReloadNext = { if (CheckForAmmo(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap); + TeamFortress_ReloadWeapon(weap, FALSE); reload = 1; break; } diff --git a/ssqc/progs.src b/ssqc/progs.src index f7346ea1..2bd3c685 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -29,6 +29,7 @@ items.qc locfiles.qc antilag.qc combat.qc +../share/fo_weapons.qc weapons.qc world.qc client.qc diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 6939a302..d3a06182 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -46,6 +46,7 @@ void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void (entity pe_player, float f_type) CF_Identify; void () TeamFortress_ReloadCurrentWeapon; +void () TeamFortress_ForceReloadCurrentWeapon; void (float slot) TeamFortress_ReloadSlot; void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; @@ -1928,63 +1929,49 @@ void () W_Reload_assault_cannon = { Status_Refresh(self.owner); }; +float FO_CheckForReload(); + float () CheckForReload = { - if (self.current_weapon == WEAP_SHOTGUN) { - if (self.reload_shotgun >= 8 && self.ammo_shells > 0) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } + if (FO_UseNewReload()) + return FO_CheckForReload(); - return 1; - } - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } + float need_reload = FALSE; - return 1; - } + if (self.current_weapon == WEAP_SHOTGUN) { + if (self.reload_shotgun >= 8 && self.ammo_shells > 0) + need_reload = TRUE; + } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { + if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) + need_reload = TRUE; } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } - - return 1; - } + if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) + need_reload = TRUE; } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } - - return 1; - } + if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) + need_reload = TRUE; } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { - if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } - - return 1; - } + if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) + need_reload = TRUE; } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if (self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE && self.ammo_shells > 0) { - if (force_reload) { - TeamFortress_ReloadCurrentWeapon(); - } + if (fo_hwguy && self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE + && self.ammo_shells > 0) + need_reload = TRUE; + } - return 1; - } - } + if (need_reload) { + if (force_reload) + TeamFortress_ForceReloadCurrentWeapon(); + return 1; + } else { + return 0; } - return 0; }; +float FO_CheckForAmmo(float weapon); float (float weap) CheckForAmmo = { + if (FO_UseNewReload()) + return FO_CheckForAmmo(weap); + if (weap == WEAP_SHOTGUN) { if (self.reload_shotgun >= 1 && self.ammo_shells > self.reload_shotgun) return 1; From 438945be5c187fe812e5a5303e91fd7907a7fd69 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 18:19:06 -0700 Subject: [PATCH 1722/2474] Add client_time Rather than implementing a-la-carte ping correction, introduce a centrally updated notion of client_time, that we can use in place of time when calculating next think times. We can also simplify all of the places we are careful not to go backwards in time by ensuring it's monotonically increasing. Update weapon projection to be based on client_time. Also document some errors in the current math that we'll forrect in the future. --- ssqc/antilag.qc | 32 +++++++++++++++++++++++++++++++- ssqc/client.qc | 9 +++++++++ ssqc/qw.qc | 18 +++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 4f37f058..ee556c27 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -298,6 +298,7 @@ void RL_RestorePresent(RewindState* head) { class FOPlayer { RewindState* rewind_; + void() FOPlayer = { rewind_ = AllocRewind(this); RL_Insert(&rewind_players, rewind_); @@ -376,4 +377,33 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { void UnrewindPlayer(entity p) { FOPlayer fop = (FOPlayer)p; fop.RestoreNow(); -} \ No newline at end of file +} + +.float client_time_internal; +float client_time(optional float ct_type = CT_NOEXTERNALEFFECT) { + return self.client_time_internal; +} + +void AL_UpdateClientTime(entity player) { + float offset; + + // Naively, we might want to offset by rtt/2, because that's how old the + // client's input is. However, the client's input is also relative to a + // world view that is itself rtt/2 behind. [Client is a full rtt behind, + // and it interpolates ahead to rtt/2 behind.] + // This means that if we want, say, "run to a position and perform an action" + // to have equivalent time, we need to correct by a full rtt. + offset = infokeyf(player, INFOKEY_P_PING) / 1000; + + offset = min(offset, antilag_settings.max_client_time_offset); + + float old_client_time = player.client_time_internal + if (time - offset > player.client_time_internal) + player.client_time_internal = time - offset; + + // Monotonically increasing and not dragging beyond 75% of time as/if RTT + // changes. + player.client_time_internal = max(player.client_time_internal, + old_client_time + (1/77.0 * 0.75)); +} + diff --git a/ssqc/client.qc b/ssqc/client.qc index 7ed1ed93..7b382a25 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -619,6 +619,10 @@ void () DecodeLevelParms = { airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); + // client_time max delta + antilag_settings.max_client_time_offset = + CF_GetSetting("almcto", "al_max_client_time_offset", "200"); + // project projectile weapons by player ping project_weapons = CF_GetSetting("pw", "project_weapons", "off"); @@ -2691,7 +2695,12 @@ void () CheckWaterJump = { } }; +void AL_UpdateClientTime(entity player); + void () PlayerPreThink = { + // We'll use this time for calculating ping adjusted expiration / projection / etc. + AL_UpdateClientTime(self); + if (self.impulse) { if (self.impulse == TF_VOTENEXT) { Vote_NextMap(self); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 38ff9d8a..4e3e46da 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -3,6 +3,21 @@ void (entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate; typedef void (float n) f_void_float; +enum { + CT_NOEXTERNALEFFECT, // No external effects (e.g. reload, build, prime, etc) +}; + +struct antilag_settings_t { + float max_client_time_offset; +} antilag_settings; + +// A monotonically increasing, latency corrected notion of client-time. +// Monotonicity guarantees that for some offset `o`: +// at t1: client_time() + o < at t2: client_time() + o FOR t2 > t1 +// E.g. That you never have to worry about the correction reordering events +// that `time + o` would not. +float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); + //=========================================================================== // TEAMFORTRESS Defs //=========================================================================== @@ -788,10 +803,11 @@ string goal_class_names[7] = { // people complain about settings, let's track them -string settings_to_track_list[3] = { +string settings_to_track_list[4] = { "sv_antilag", "project_weapons", "project_grenades", + "al_max_client_time_offset", }; typedef struct setting_t { From f56a6166e211a61faec2ee84cc3cd4f320fc10e4 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 20:17:27 -0700 Subject: [PATCH 1723/2474] Move weapon projection to use client_time The original code followed the reasoning: `Project projectiles forward in time based on ping up to configurable maximum (default 100ms). Effective projection time is maximum / 2 (eg 50ms), because we assume RTT is evenly distributed in both directions - and we want the server to spawn the entity in the position it would have have been if it had received the message (player_ping / 2) ago.` This was is not quite correct. It's true the client fired rtt/2 ago, however, this is not the whole story. The point that client fired from an was also an interpolated point at time-rtt/2. --- ssqc/antilag.qc | 63 ++++++++++++++++++++++++++----------------------- ssqc/client.qc | 1 + ssqc/qw.qc | 2 ++ 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index ee556c27..27c76a29 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,31 +1,24 @@ void AL_ProjectProjectile (entity projectile) { - // Project projectiles forward in time based on ping up to configurable maximum (default 100ms). - // Effective projection time is maximum / 2 (eg 50ms), because we assume RTT is evenly distributed in both - // directions - and we want the server to spawn the entity in the position it would have - // have been if it had received the message (player_ping / 2) ago. - local float player_ping_s = infokeyf(self, INFOKEY_P_PING) / 1000; - - if (player_ping_s > project_weapons_max_latency) { - player_ping_s = project_weapons_max_latency; - } else if (player_ping_s <= 0.0013) { // Ping 13ms or lower? Don't do anything - return; - } - - local float time_offset = (player_ping_s / 2); - local vector projected_origin = projectile.origin + (projectile.velocity * time_offset); - - // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin - // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED - // because by tracing between old origin and projected origin we effectively have a single (last) frame - // rewind at the projected origin. The effect is high ping players are disadvantaged in close combat. - // This is preferable to unhappy low ping players. - traceline(projectile.origin, projected_origin, 0, self); - - if (trace_fraction < 1) { - projected_origin = trace_endpos; - } - - setorigin(projectile, projected_origin); + float time_offset = time - client_time(CT_SLOW_PROJECTILE); + + if (time_offset <= 0.013) // ping 13ms or lower? Don't do anything + return; + + vector projected_origin = projectile.origin + (projectile.velocity * time_offset); + // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin + // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED + // because by tracing between old origin and projected origin we effectively have a single (last) frame + // rewind at the projected origin. The effect is high ping players are disadvantaged in close combat. + // This is preferable to unhappy low ping players. + // + // XXX This will updated to use rewind. + traceline(projectile.origin, projected_origin, 0, self); + + if (trace_fraction < 1) { + projected_origin = trace_endpos; + } + + setorigin(projectile, projected_origin); } float AL_GrenadeOffset() { @@ -380,8 +373,20 @@ void UnrewindPlayer(entity p) { } .float client_time_internal; + float client_time(optional float ct_type = CT_NOEXTERNALEFFECT) { - return self.client_time_internal; + if (ct_type == CT_NOEXTERNALEFFECT) + return self.client_time_internal; + + float offset = time - self.client_time_internal; + float max_offset = 0; + switch (ct_type) { + case CT_SLOW_PROJECTILE: + max_offset = antilag_settings.max_projectile_slow_offset; + break; + } + + return max(self.client_time_internal, time - max_offset); } void AL_UpdateClientTime(entity player) { @@ -397,7 +402,7 @@ void AL_UpdateClientTime(entity player) { offset = min(offset, antilag_settings.max_client_time_offset); - float old_client_time = player.client_time_internal + float old_client_time = player.client_time_internal; if (time - offset > player.client_time_internal) player.client_time_internal = time - offset; diff --git a/ssqc/client.qc b/ssqc/client.qc index 7b382a25..46745aa7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -628,6 +628,7 @@ void () DecodeLevelParms = { // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); + antilag_settings.max_projectile_slow_offset = project_weapons_max_latency / 2; // Correct grenade prime timing by player ping. project_grenades = CF_GetSetting("pg", "project_grenades", "on"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 4e3e46da..06445423 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -5,10 +5,12 @@ typedef void (float n) f_void_float; enum { CT_NOEXTERNALEFFECT, // No external effects (e.g. reload, build, prime, etc) + CT_SLOW_PROJECTILE, // Projectile for which judder is noticable (e.g. rocket) }; struct antilag_settings_t { float max_client_time_offset; + float max_projectile_slow_offset; } antilag_settings; // A monotonically increasing, latency corrected notion of client-time. From d82e8b29cbb587b09f4085094e21fa1eee761911 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Sep 2022 18:53:56 -0700 Subject: [PATCH 1724/2474] Move grenade offsets to use client-time, eliminate AL_GrenadeOffset --- README.md | 3 --- ssqc/antilag.qc | 17 ----------------- ssqc/client.qc | 4 ---- ssqc/qw.qc | 4 +--- ssqc/tfort.qc | 15 ++++++--------- 5 files changed, 7 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 10e33d02..35be689c 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,6 @@ FortressOne Server New features ------ -* `localinfo project_grenades 0/1` [default: 0] Adjust the point at which - grenades are primed to correct for client latency. Does not allow players to -throw grenades any faster, or more frequently; only more consistently. * Server option to limit `sv_maxclients` to current number of players during quad gametime. `localinfo limit_quad_players 0/1`. Default: `1`. * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 27c76a29..07157db6 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -21,23 +21,6 @@ void AL_ProjectProjectile (entity projectile) { setorigin(projectile, projected_origin); } -float AL_GrenadeOffset() { - if (!project_grenades) - return 0; - - local float offset = infokeyf(self, INFOKEY_P_PING) / 1000; - local float smallest_grenade_think = 0.5; - - offset /= 2; - // Make sure we'll always order before first think. - offset = min(offset, smallest_grenade_think - 0.1); - - // Don't allow prime to move before throw (or to the same frame). - offset = min(offset, time - (self.last_throw + 0.013)); - - return offset; -} - #define DEBUG_ANTILAG 0 #if DEBUG_ANTILAG diff --git a/ssqc/client.qc b/ssqc/client.qc index 46745aa7..3428f491 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -630,9 +630,6 @@ void () DecodeLevelParms = { project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); antilag_settings.max_projectile_slow_offset = project_weapons_max_latency / 2; - // Correct grenade prime timing by player ping. - project_grenades = CF_GetSetting("pg", "project_grenades", "on"); - // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { @@ -1027,7 +1024,6 @@ void () DecodeLevelParms = { medicaura = FALSE; medicnocuss = FALSE; project_weapons = FALSE; - project_grenades = TRUE; distance_based_cuss_duration = FALSE; pyro_type = 1; drop_grenades = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 06445423..e8a919a9 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -617,7 +617,6 @@ float max_armor_hwguy; float project_weapons; float project_weapons_max_latency; -float project_grenades; float ng_velocity; float ng_damage; @@ -805,10 +804,9 @@ string goal_class_names[7] = { // people complain about settings, let's track them -string settings_to_track_list[4] = { +string settings_to_track_list[3] = { "sv_antilag", "project_weapons", - "project_grenades", "al_max_client_time_offset", }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index d5e69479..b4e418fa 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -934,8 +934,7 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { void () FO_GrenadeThink; -// is_player defines whether this originated from the player or server. Player -// generated primes are corrected for latency when project_grenades is on. +// is_player defines whether this originated from the player or server. void (float inp, float is_player) TeamFortress_PrimeGrenade = { local float gtype; local string gs; @@ -1100,13 +1099,11 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { else if (inp == 2) tGrenade.impulse = TF_GRENADE_2; - local float lag_adjust = is_player ? AL_GrenadeOffset() : 0; - - tGrenade.nextthink = time + 0.8 - lag_adjust; + tGrenade.nextthink = client_time() + 0.8; if (gtype == GR_TYPE_CALTROP) - tGrenade.heat = time + 0.5 + 0.5 - lag_adjust; + tGrenade.heat = client_time() + 0.5 + 0.5; else { - tGrenade.heat = time + 3 + 0.8 - lag_adjust; + tGrenade.heat = client_time() + 3 + 0.8; RemoveGrenadeTimers(); @@ -1114,7 +1111,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { local float notimers = stof(infokey(self, "nt")); if (grentimers && notimers != 1) { timer = spawn(); - timer.nextthink = time + 0.8 - lag_adjust; + timer.nextthink = client_time() + 0.8; timer.think = GrenadeTimer; timer.heat = 4; timer.owner = self; @@ -2918,7 +2915,7 @@ void () TeamFortress_ExplodePerson = { newmis.velocity = '0 0 0'; newmis.angles = vectoangles(newmis.velocity); newmis.think = SUB_Null; - newmis.nextthink = time + 0.1; + newmis.nextthink = time + 0.1; // Server generated, no client time here. if (self.weapon == GR_TYPE_NORMAL) { newmis.touch = NormalGrenadeTouch; From 6c474dd9344ae009fa837148d0fbcd3230fb95c1 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:12:24 -0700 Subject: [PATCH 1725/2474] Use clienttime for reload and attack_finished Correct for voluntary reloads/attacks --- ssqc/weapons.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d3a06182..92bde134 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -201,9 +201,9 @@ float () crandom = { void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) - self.attack_finished = time + att_delay * 2; + self.attack_finished = client_time() + att_delay * 2; else - self.attack_finished = time + att_delay; + self.attack_finished = client_time() + att_delay; }; float () W_FireAxe = { From ca3c741c1490181b49734f418f715bffb8564597 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:21:48 -0700 Subject: [PATCH 1726/2474] Correct engineer build times for ping This is technically a small buff for a higher ping engineer in that the gun will be visibly under construction for a very small amount of reduced time. This seems fine. --- ssqc/engineer.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 5b9ca751..f63b7bdc 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -525,7 +525,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/disp.mdl"; newmis.netname = "dispenser"; - btime = time + 2; + btime = client_time() + 2; self.dispenser_ticks = 0; } else if (objtobuild == 2) { if (self.has_sentry) { @@ -537,7 +537,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/turrbase.mdl"; newmis.netname = "sentrygun"; - btime = time + 5; + btime = client_time() + 5; self.sentry_ticks = 0; } if (CheckArea(newmis, self) == 0) { From 5cce180b5407f8103e1db2331b871b6c0935b562 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:31:02 -0700 Subject: [PATCH 1727/2474] Correct spy actions for latency --- ssqc/client.qc | 4 ++-- ssqc/commands.qc | 2 +- ssqc/menu.qc | 18 +++++++++--------- ssqc/spy.qc | 34 +++++++++++++++++----------------- ssqc/tfort.qc | 4 ++-- ssqc/tfortmap.qc | 8 ++++---- ssqc/weapons.qc | 38 +++++++++++++++++++------------------- 7 files changed, 54 insertions(+), 54 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 3428f491..e435b706 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2303,10 +2303,10 @@ void () PutClientInServer = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a40dec71..510d136d 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -511,7 +511,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { //Menu_Spy_Color_Input(stof(arg3)); farg3 = stof(arg3); if (farg3 > 0 && farg3 <= number_of_teams) - CF_Spy_ChangeColor(self, farg3); + CF_Spy_ChangeColor(self, farg3, TRUE); else Menu_Spy_Input(1); break; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index d999ecfa..7df35e38 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -2,8 +2,8 @@ // This file handles all menu functions and displays. //====================================================== -void (entity pe_player, float pf_class) CF_Spy_ChangeSkin; -void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor; +void (entity pe_player, float pf_class, float is_user) CF_Spy_ChangeSkin; +void (entity pe_player, float pf_team_no, float is_user) CF_Spy_ChangeColor; void (float issilent, float force) FO_Spy_Feign; void () FO_Spy_FeignOnNextDamage; void () FO_Spy_Unfeign; @@ -73,8 +73,8 @@ void (float inp) Menu_Scout_Input; void (float inp) Menu_Spy_Input; void (float inp) Menu_Spy_Skin_Input; void (float inp) Menu_Spy_Color_Input; -void (entity player) FO_Spy_DisguiseLast; -void (entity player) FO_Spy_DisguiseLastSpawned; +void (entity player, float is_user) FO_Spy_DisguiseLast; +void (entity player, float is_user) FO_Spy_DisguiseLastSpawned; void () Menu_Demoman; void () Menu_Demoman_Cancel; @@ -582,7 +582,7 @@ void (float inp) Menu_Spy_Input = { else Menu_Spy_Skin(); } else if (inp == 2 && !invis_only) { - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, TRUE); } else if (inp == 3) { FO_Spy_Feign(1, 0); if (self.is_feigning) { @@ -663,13 +663,13 @@ void (float inp) Menu_Spy_Skin_Input = { else if (number_of_teams > 2) Menu_Spy_Color(); else if (self.team_no == 1) - CF_Spy_ChangeColor(self, 2); + CF_Spy_ChangeColor(self, 2, TRUE); else - CF_Spy_ChangeColor(self, 1); + CF_Spy_ChangeColor(self, 1, TRUE); } if (self.skin != inp) - CF_Spy_ChangeSkin(self, inp); + CF_Spy_ChangeSkin(self, inp, TRUE); }; void () Menu_Spy_Skin = { @@ -711,7 +711,7 @@ void (float inp) Menu_Spy_Color_Input = { else if (inp == 4 && color == 11) Menu_Spy_Color(); else if (inp > 0 && inp <= number_of_teams) - CF_Spy_ChangeColor(self, inp); + CF_Spy_ChangeColor(self, inp, TRUE); }; void () Menu_Spy_Color = { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 6aab6be0..f4d0197a 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -672,7 +672,7 @@ void () CF_Spy_Invisible = { e_timer.classname = "spytimer"; e_timer.owner = self; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 1; + e_timer.nextthink = client_time() + 1; } Status_Refresh(self); @@ -727,9 +727,9 @@ void () CF_Spy_DisguiseStop = { Status_Refresh(self); }; -void (entity player) FO_Spy_DisguiseLast = { +void (entity player, float is_user) FO_Spy_DisguiseLast = { if (!player.last_selected_skin) { - FO_Spy_DisguiseLastSpawned(player); + FO_Spy_DisguiseLastSpawned(player, is_user); return; } @@ -748,11 +748,11 @@ void (entity player) FO_Spy_DisguiseLast = { } } - CF_Spy_ChangeColor(player, undercover_team); - CF_Spy_ChangeSkin(player, player.last_selected_skin); + CF_Spy_ChangeColor(player, undercover_team, is_user); + CF_Spy_ChangeSkin(player, player.last_selected_skin, is_user); }; -void (entity player) FO_Spy_DisguiseLastSpawned = { +void (entity player, float is_user) FO_Spy_DisguiseLastSpawned = { local entity te = find(world, classname, "player"); local float latest_spawn_time = 0; local entity enemy_to_disguise_as = world; @@ -778,10 +778,10 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { } if (enemy_to_disguise_as.team_no) { - CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no); + CF_Spy_ChangeColor(player, enemy_to_disguise_as.team_no, is_user); if (enemy_to_disguise_as.skin) { - CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin); + CF_Spy_ChangeSkin(player, enemy_to_disguise_as.skin, is_user); } } else { local float undercover_team; @@ -791,7 +791,7 @@ void (entity player) FO_Spy_DisguiseLastSpawned = { undercover_team = 1; } - CF_Spy_ChangeColor(player, undercover_team); + CF_Spy_ChangeColor(player, undercover_team, is_user); } }; @@ -900,7 +900,7 @@ void () CF_Spy_UndercoverThink = { TeamFortress_SetSkin(self.owner); if (self.owner.queue_team) { - CF_Spy_ChangeColor(self.owner, self.owner.queue_team); + CF_Spy_ChangeColor(self.owner, self.owner.queue_team, FALSE); } else { if (self.owner.undercover_team) s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); @@ -921,7 +921,7 @@ void () CF_Spy_UndercoverThink = { TeamFortress_SetSkin(self.owner); if (self.owner.queue_skin) { - CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin); + CF_Spy_ChangeSkin(self.owner, self.owner.queue_skin, FALSE); } else { s_team = TeamFortress_TeamGetColorString(self.owner.undercover_team); if (self.owner.undercover_skin) @@ -943,7 +943,7 @@ void () CF_Spy_UndercoverThink = { dremove(self); }; -void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { +void (entity pe_player, float pf_class, float is_user) CF_Spy_ChangeSkin = { pe_player.last_selected_skin = pf_class; // stop if you're already disguised as the requested skin @@ -993,13 +993,13 @@ void (entity pe_player, float pf_class) CF_Spy_ChangeSkin = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 1; + e_timer.nextthink = (is_user ? client_time() : time) + 1; e_timer.skin = pf_class; Status_Refresh(pe_player); }; -void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { +void (entity pe_player, float pf_team_no, float is_user) CF_Spy_ChangeColor = { local entity e_timer; local float f_team_color = TeamFortress_TeamGetColor(pf_team_no) - 1; @@ -1047,7 +1047,7 @@ void (entity pe_player, float pf_team_no) CF_Spy_ChangeColor = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = time + 1; + e_timer.nextthink = (is_user ? client_time() : time) + 1; e_timer.team = pf_team_no; Status_Refresh(pe_player); @@ -1522,10 +1522,10 @@ void (entity spy) Spy_RemoveDisguise = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b4e418fa..f7ed591d 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -353,10 +353,10 @@ void (float inp) TeamFortress_ChangeClass = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 01090a83..47c37a3f 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1140,10 +1140,10 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(Player); + FO_Spy_DisguiseLastSpawned(Player, FALSE); break; case 2: - FO_Spy_DisguiseLast(Player); + FO_Spy_DisguiseLast(Player, FALSE); break; } } @@ -3056,10 +3056,10 @@ void () DropGoalItems = { if (self.playerclass == PC_SPY) { switch(autodisguise) { case 1: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, FALSE); break; case 2: - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, FALSE); break; } } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 92bde134..56e932a5 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -3146,43 +3146,43 @@ void () ImpulseCommands = { } else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) FO_Spy_FeignCmd(1); else if (self.impulse == TF_DISGUISE_RESET && self.playerclass == PC_SPY) { - CF_Spy_ChangeSkin(self, 8); - CF_Spy_ChangeColor(self, self.team_no); + CF_Spy_ChangeSkin(self, 8, TRUE); + CF_Spy_ChangeColor(self, self.team_no, TRUE); } else if (self.impulse == TF_DISGUISE_SCOUT && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 1); + CF_Spy_ChangeSkin(self, 1, TRUE); else if (self.impulse == TF_DISGUISE_SNIPER && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 2); + CF_Spy_ChangeSkin(self, 2, TRUE); else if (self.impulse == TF_DISGUISE_SOLDIER && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 3); + CF_Spy_ChangeSkin(self, 3, TRUE); else if (self.impulse == TF_DISGUISE_DEMOMAN && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 4); + CF_Spy_ChangeSkin(self, 4, TRUE); else if (self.impulse == TF_DISGUISE_MEDIC && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 5); + CF_Spy_ChangeSkin(self, 5, TRUE); else if (self.impulse == TF_DISGUISE_HWGUY && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 6); + CF_Spy_ChangeSkin(self, 6, TRUE); else if (self.impulse == TF_DISGUISE_PYRO && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 7); + CF_Spy_ChangeSkin(self, 7, TRUE); else if (self.impulse == TF_DISGUISE_ENGINEER && self.playerclass == PC_SPY) - CF_Spy_ChangeSkin(self, 9); + CF_Spy_ChangeSkin(self, 9, TRUE); else if (self.impulse == TF_DISGUISE_BLUE && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 1); + CF_Spy_ChangeColor(self, 1, TRUE); else if (self.impulse == TF_DISGUISE_RED && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 2); + CF_Spy_ChangeColor(self, 2, TRUE); else if (self.impulse == TF_DISGUISE_YELLOW && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 3); + CF_Spy_ChangeColor(self, 3, TRUE); else if (self.impulse == TF_DISGUISE_GREEN && self.playerclass == PC_SPY) - CF_Spy_ChangeColor(self, 4); + CF_Spy_ChangeColor(self, 4, TRUE); else if (self.impulse == TF_DISGUISE_ENEMY && self.playerclass == PC_SPY) { if (number_of_teams > 2) Menu_Spy_Color(); else if (self.team_no == 1) - CF_Spy_ChangeColor(self, 2); + CF_Spy_ChangeColor(self, 2, TRUE); else - CF_Spy_ChangeColor(self, 1); + CF_Spy_ChangeColor(self, 1, TRUE); } else if (self.impulse == TF_DISGUISE_LAST && self.playerclass == PC_SPY) - FO_Spy_DisguiseLast(self); + FO_Spy_DisguiseLast(self, TRUE); else if (self.impulse == TF_DISGUISE_LAST_SPAWNED && self.playerclass == PC_SPY) - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, TRUE); else if ((self.impulse == TF_DEMOMAN_DETPACK) && (self.playerclass == PC_DEMOMAN)) TeamFortress_DetpackMenu(); @@ -3477,7 +3477,7 @@ void () ButtonFrame = { TeamFortress_ToggleDetpack(5); break; case PC_SPY: - FO_Spy_DisguiseLastSpawned(self); + FO_Spy_DisguiseLastSpawned(self, TRUE); break; case PC_ENGINEER: FO_Engineer_ToggleSentry(); From 4f0846675134f8af1903e6fb7cf6d44f389b313a Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 02:53:26 -0700 Subject: [PATCH 1728/2474] Add new files Helps if you git add new files. --- share/fo_weapons.qc | 337 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 share/fo_weapons.qc diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc new file mode 100644 index 00000000..5a9d80d7 --- /dev/null +++ b/share/fo_weapons.qc @@ -0,0 +1,337 @@ +enum AmmoType { + AMMO_NONE, + AMMO_SHELLS, + AMMO_NAILS, + AMMO_CELLS, + AMMO_ROCKETS, + AMMO_GRENADES, // Rockets really +}; + +// REQUIRES: Order must match above. +static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; + +static float* AMMO_to_p(entity player, AmmoType ammo_type) { + switch (ammo_type) { + case AMMO_NONE: return __NULL__; + case AMMO_SHELLS: return &player.ammo_shells; + case AMMO_CELLS: return &player.ammo_cells; + case AMMO_NAILS: return &player.ammo_nails; + case AMMO_ROCKETS: return &player.ammo_rockets; + case AMMO_GRENADES: return &player.ammo_rockets; + } + error(sprintf("UNK AMMO_TYPE=%d\n", ammo_type)); + return __NULL__; +} + +struct FO_WeapInfo { + float weapon; + + /* These are always constant and relative to weapon. */ + string name; + string model[2]; // indexed by weaponmode + AmmoType ammo_type; + float ammo_per_shot; + float needs_reload; + float full_reload_time; + float clip_size; + float attack_time; + + /* These are relative to the player passed. */ + float* ammo_remaining; + float* clip_fired; +}; + +void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { + wi->weapon = weapon; + wi->ammo_per_shot = 1; + wi->needs_reload = TRUE; + switch (weapon) { + /* NONE */ + case WEAP_HOOK: + wi->name = "Hook"; + wi->model[0] = "progs/v_grap.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_KNIFE: + wi->name = "Knife"; + wi->model[0] = "progs/v_knife.mdl"; + wi->model[1] = "progs/v_knife2.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_MEDIKIT: + wi->name = "BioAxe"; + wi->model[0] = "progs/v_medi.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_SPANNER: + wi->name = "Spanner"; + wi->model[0] = "progs/v_spanner.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + case WEAP_AXE: + wi->name = "Axe"; + wi->model[0] = "progs/v_axe.mdl"; + wi->ammo_type = AMMO_NONE; + wi->needs_reload = FALSE; + wi->attack_time = 0.5; + break; + /* SHELLS */ + case WEAP_SHOTGUN: + wi->name = "Shotgun"; + wi->model[0] = "progs/v_shot.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->clip_size = 8; + wi->attack_time = 0.5; + wi->full_reload_time = 2; + wi->clip_fired = &player.reload_shotgun; + break; + case WEAP_SUPER_SHOTGUN: + wi->name = "Super Shotgun"; + wi->model[0] = "progs/v_shot2.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->clip_size = 16; + wi->ammo_per_shot = 2; + wi->attack_time = 0.7; + wi->full_reload_time = 3; + wi->clip_fired = &player.reload_super_shotgun; + break; + case WEAP_SNIPER_RIFLE: + wi->name = "Sniper Rifle"; + wi->model[0] = "progs/v_srifle.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->attack_time = 1.5; + if (sniperreload) { + wi->clip_size = 1; + wi->full_reload_time = 4; + wi->clip_fired = &self.reload_sniper_rifle; + } else { + wi->needs_reload = FALSE; + } + break; + case WEAP_AUTO_RIFLE: + wi->name = "Sniper Rifle"; + wi->model[0] = "progs/v_srifle.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->needs_reload = FALSE; + wi->attack_time = 0.1; + break; + case WEAP_TRANQ: + wi->name = "Tranq Gun"; + wi->model[0] = "progs/v_tranq.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->needs_reload = FALSE; + wi->attack_time = 1.5; + break; + case WEAP_ASSAULT_CANNON: + wi->name = "Assault Cannon"; + wi->model[0] = "progs/v_asscan.mdl"; + wi->ammo_type = AMMO_SHELLS; + wi->clip_size = 100; + wi->full_reload_time = 4; + wi->clip_fired = &player.reload_assault_cannon; + break; + /* NAILS */ + case WEAP_NAILGUN: + wi->name = "Nailgun"; + wi->model[0] = "progs/v_nail.mdl"; + wi->ammo_type = AMMO_NAILS; + wi->ammo_per_shot = 2; + wi->attack_time = 0.2; + wi->needs_reload = FALSE; + break; + case WEAP_SUPER_NAILGUN: + wi->name = "Super Nailgun"; + wi->model[0] = "progs/v_nail2.mdl"; + wi->ammo_type = AMMO_NAILS; + wi->ammo_per_shot = 4; + wi->attack_time = 0.2; + wi->needs_reload = FALSE; + break; + case WEAP_RAILGUN: + wi->name = "Railgun"; + wi->model[0] = "progs/v_rail.mdl"; + wi->ammo_type = AMMO_NAILS; + wi->ammo_type = AMMO_NAILS; + wi->needs_reload = FALSE; + wi->attack_time = 0.4; + break; + /* ROCKETS */ + case WEAP_GRENADE_LAUNCHER: + wi->name = "Grenade Launcher"; + wi->model[0] = "progs/v_rock.mdl"; + wi->model[1] = "progs/v_pipe.mdl"; + wi->ammo_type = AMMO_ROCKETS; + wi->clip_size = 6; + wi->attack_time = 0.6; + wi->full_reload_time = 4; + wi->clip_fired = &player->reload_grenade_launcher; + case WEAP_ROCKET_LAUNCHER: + wi->name = "Rocket Launcher"; + wi->model[0] = "progs/v_rock2.mdl"; + wi->ammo_type = AMMO_ROCKETS; + wi->clip_size = 4; + wi->clip_fired = &player->reload_rocket_launcher; + wi->full_reload_time = 5; + wi->attack_time = 0.8; + break; + case WEAP_INCENDIARY: + wi->name = "Incendiary Launcher"; + wi->model[0] = "progs/v_irock.mdl"; + wi->ammo_type = AMMO_ROCKETS; + wi->ammo_per_shot = 3; + wi->attack_time = 0.9; + switch (pyro_type) { + case PYRO_ORIGINAL: wi->attack_time = 1.2; break; + case PYRO_OZTF: wi->attack_time = 0.9; break; + case PYRO_FO: wi->attack_time = 0.9; break; + } + wi->needs_reload = FALSE; + break; + /* CELLS */ + case WEAP_LIGHTNING: + error("Should never be invoked\n"); + case WEAP_FLAMETHROWER: + wi->name = "Flamethrower"; + wi->model[0] = "progs/v_flame.mdl"; + wi->ammo_type = AMMO_CELLS; + wi->needs_reload = FALSE; + wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; + break; + case WEAP_DETPACK: + error("Should never be invoked\n"); + } + + wi->ammo_remaining = AMMO_to_p(player, wi->ammo_type); + if (!wi->needs_reload) { + wi->clip_fired = __NULL__; + } +} + +#ifdef SSQC +void TeamFortress_OldReloadWeapon(float weap); +void () RestoreDefaultWeapon; +void (entity pl) Status_Refresh; +void (entity pl, float swap) W_WeaponState_Load; +void (float att_delay) Attack_Finished; + +static void FOT_ReloadTimer() { + FO_WeapInfo wi; + FO_FillWeapInfo(self.owner, self.current_weapon, &wi); + + if (time == self.heat) { + // Reload finished + self.owner.tfstate &= ~TFSTATE_RELOADING; + self.owner.weaponmodel = wi->model[self.owner.weaponmode]; + sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); + dremove(self); + W_WeaponState_Load(self.owner, 0); + } else { + // Refresh clip + if (wi.weapon != WEAP_SNIPER_RIFLE) + self.owner.reload_clipsize += 1; + else + self.owner.reload_sniper_ticks += 1; + + self.nextthink = min(time + self.owner.reload_tick, self.heat); + } + Status_Refresh(self.owner); +} + +float FO_UseNewReload() { + return CF_GetSetting("dunr", "debug_use_new_reload", "on"); +} + +float FO_CheckForAmmo(float weapon) { + FO_WeapInfo wi; + FO_FillWeapInfo(self, weapon, &wi); + + if (wi->needs_reload && *wi->clip_fired > 0 + && *wi->ammo_remaining > wi->ammo_per_shot) + return 1; + + return 0; +} + +void () TeamFortress_ForceReloadCurrentWeapon; +float FO_CheckForReload() { + FO_WeapInfo wi; + FO_FillWeapInfo(self, self.current_weapon, &wi); + + if (*wi->clip_fired >= wi->clip_size && *wi->ammo_remaining > 0) { + if (force_reload) + TeamFortress_ForceReloadCurrentWeapon(); + return 1; + } else { + return 0; + } +} + +void FO_ReloadWeapon(float weapon, float force) { + RestoreDefaultWeapon(); + if (self.tfstate & TFSTATE_RELOADING) + return; + + FO_WeapInfo wi; + FO_FillWeapInfo(self, weapon, &wi); + + if (!wi->needs_reload) + return; + + string msg = string_null; + if (*wi->clip_fired == 0) + msg = "Clip full\n"; + else if (*wi->ammo_remaining == 0) + msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); + else if (wi->clip_size - *wi->clip_fired == *wi->ammo_remaining) + msg = strcat("All ", AMMO_to_s[wi->ammo_type], "are in the clip\n"); + + if (msg != string_null) { + sprint(self, PRINT_HIGH, msg); + return; + } else { + sprint(self, PRINT_HIGH, strcat("Reloading ", wi->name, "...\n")); + } + + Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. + + self.weaponmodel = ""; + self.weaponframe = 0; + self.tfstate |= TFSTATE_RELOADING; + Status_Refresh(self); + + float reload_count = min(*wi->clip_fired, *wi->ammo_remaining); + float reload_duration = + (reload_count / wi->clip_size) * wi->full_reload_time; + + *wi->clip_fired -= reload_count; + + // Sets up for status bar. + self.reload_time = time + reload_duration; + self.reload_tick = reload_duration / reload_count; + self.reload_clipsize = wi->clip_size - reload_count; + + // Actual entity that will update status bar / clear reload. + entity reload_timer = spawn(); + reload_timer.owner = self; + reload_timer.current_weapon = weapon; + reload_timer.classname = "timer"; + reload_timer.think = FOT_ReloadTimer; + + // TODO: Remove this hack. + if (weapon == WEAP_SNIPER_RIFLE) { + self.reload_tick = 1; + self.reload_sniper_ticks = 0; + } + + // It turns out, even on forced reloads we should use the client_time() not + // the server time as the action that forced the reload (firing the last + // shot), was client relative. + reload_timer.heat = client_time() + reload_duration; + reload_timer.nextthink = client_time() + self.reload_tick; + +} +#endif From 5162d1ef9f08786ffd3dd24ef014d2cd46fa0503 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 03:09:56 -0700 Subject: [PATCH 1729/2474] Ensure overflows terminate --- share/fo_weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 5a9d80d7..21709026 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -222,7 +222,7 @@ static void FOT_ReloadTimer() { FO_WeapInfo wi; FO_FillWeapInfo(self.owner, self.current_weapon, &wi); - if (time == self.heat) { + if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; self.owner.weaponmodel = wi->model[self.owner.weaponmode]; From 9e6253444d7f762a447696bd4dd12325e4fbf50d Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 13:07:22 -0700 Subject: [PATCH 1730/2474] Add missing breaks (fix no reload on grenade launcher) When filling in the switch table for all the weapons a few breaks were missed at the end. This was resulting in (for example) grenade launcher not needing reload. --- share/fo_weapons.qc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 21709026..ce2656ea 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -53,6 +53,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_KNIFE: wi->name = "Knife"; wi->model[0] = "progs/v_knife.mdl"; @@ -60,18 +61,21 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_MEDIKIT: wi->name = "BioAxe"; wi->model[0] = "progs/v_medi.mdl"; wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_SPANNER: wi->name = "Spanner"; wi->model[0] = "progs/v_spanner.mdl"; wi->ammo_type = AMMO_NONE; wi->needs_reload = FALSE; wi->attack_time = 0.5; + break; case WEAP_AXE: wi->name = "Axe"; wi->model[0] = "progs/v_axe.mdl"; @@ -169,6 +173,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->attack_time = 0.6; wi->full_reload_time = 4; wi->clip_fired = &player->reload_grenade_launcher; + break; case WEAP_ROCKET_LAUNCHER: wi->name = "Rocket Launcher"; wi->model[0] = "progs/v_rock2.mdl"; @@ -192,7 +197,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->needs_reload = FALSE; break; /* CELLS */ - case WEAP_LIGHTNING: error("Should never be invoked\n"); case WEAP_FLAMETHROWER: wi->name = "Flamethrower"; @@ -201,7 +205,10 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->needs_reload = FALSE; wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; break; + /* NOT USED */ + case WEAP_LIGHTNING: case WEAP_DETPACK: + default: error("Should never be invoked\n"); } From 9412ccce6d9c480c49099db4fca751b11a8c2bbd Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 03:07:31 -0700 Subject: [PATCH 1731/2474] Update antilag detpipe to use client_time Removed `project_max_latency`, it's now implicit from client_time (and tunables). --- ssqc/antilag.qc | 22 ++++++++-------------- ssqc/client.qc | 3 +++ ssqc/qw.qc | 4 +++- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 07157db6..7d7bbad2 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -325,26 +325,20 @@ class FOPlayer { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { - // Live changeagble for now. - float project_detpipe = CF_GetSetting("pd", "project_detpipe", "on"); - // Want to lower this in time, but good for testing. - float project_detpipe_max_lat = - CF_GetSetting("pdml", "project_max_latency", "500") / 1000; - - if (!project_detpipe) + if (antilag_settings.rewind_detpipe) return FALSE; - project_detpipe_max_lat = min(project_detpipe_max_lat, - ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT) * 2); + float rewind_max_offset = ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT); + farthest_rewind_point = max(farthest_rewind_point, + time - rewind_max_offset); - local float rtt = infokeyf(self, INFOKEY_P_PING) / 1000; - rtt = min(rtt, project_detpipe_max_lat); + // Det was pushed at client_time(), let's see if we can get there. + float rewind_to = max(farthest_rewind_point, client_time()); - if (rtt < 0.013) + // Ignore for LAN pings. + if (time - rewind_to < 0.013) return FALSE; - float rewind_to = max(farthest_rewind_point, time - rtt / 2); - FOPlayer fop = (FOPlayer)self; fop.RewindExcept(rewind_to); return TRUE; diff --git a/ssqc/client.qc b/ssqc/client.qc index e435b706..2b43cc50 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -619,6 +619,9 @@ void () DecodeLevelParms = { airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); + // client_time max delta + antilag_settings.rewind_detpipe = + CF_GetSetting("alrd", "al_rewind_detpipe", "on"); // client_time max delta antilag_settings.max_client_time_offset = CF_GetSetting("almcto", "al_max_client_time_offset", "200"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index e8a919a9..b81e88da 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -11,6 +11,7 @@ enum { struct antilag_settings_t { float max_client_time_offset; float max_projectile_slow_offset; + float rewind_detpipe; } antilag_settings; // A monotonically increasing, latency corrected notion of client-time. @@ -804,9 +805,10 @@ string goal_class_names[7] = { // people complain about settings, let's track them -string settings_to_track_list[3] = { +string settings_to_track_list[4] = { "sv_antilag", "project_weapons", + "al_rewind_detpipe", "al_max_client_time_offset", }; From 8bd735b7d3a5c0a78b7e7d25412831dd4ab7059a Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:05:19 -0700 Subject: [PATCH 1732/2474] Rename Laser to Railgun For legacy reasons the railgun is a laser in the code. Fix this. --- share/defs.h | 3 +-- share/fo_weapons.qc | 1 - ssqc/tfort.qc | 2 +- ssqc/weapons.qc | 20 ++++++++++---------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/share/defs.h b/share/defs.h index a335c43c..3d0a8e5b 100644 --- a/share/defs.h +++ b/share/defs.h @@ -723,7 +723,6 @@ #define WEAP_LIGHTNING 65536 #define WEAP_DETPACK 131072 #define WEAP_TRANQ 262144 -#define WEAP_LASER 524288 #define WEAP_RAILGUN 524288 // still room for 12 more weapons // but we can remove some by giving the weapons @@ -1144,7 +1143,7 @@ #define PC_ENGINEER_INITARMORTYPE 0.3 #define PC_ENGINEER_ARMORCLASSES 31 // ALL #define PC_ENGINEER_INITARMORCLASS 0 -#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN +#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_RAILGUN | WEAP_SUPER_SHOTGUN #define PC_ENGINEER_MAXAMMO_SHOT 50 #define PC_ENGINEER_MAXAMMO_NAIL 50 #define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index ce2656ea..2f7e43af 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -197,7 +197,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->needs_reload = FALSE; break; /* CELLS */ - error("Should never be invoked\n"); case WEAP_FLAMETHROWER: wi->name = "Flamethrower"; wi->model[0] = "progs/v_flame.mdl"; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f7ed591d..57fcbf05 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2273,7 +2273,7 @@ void () TeamFortress_SetEquipment = { else self.maxarmor = PC_ENGINEER_MAXARMOR; if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_LASER; + self.current_weapon = WEAP_RAILGUN; self.items_allowed = PC_ENGINEER_WEAPONS; self.items = self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 56e932a5..9a2e2ca8 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1737,7 +1737,7 @@ void (entity pl) W_SetCurrentAmmo = { } pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_LASER) { + } else if (pl.current_weapon == WEAP_RAILGUN) { pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_rail.mdl"; @@ -1785,8 +1785,8 @@ float () W_BestWeapon = { return WEAP_FLAMETHROWER; else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) return WEAP_SUPER_NAILGUN; - else if (self.ammo_nails >= 1 && it & WEAP_LASER) - return WEAP_LASER; + else if (self.ammo_nails >= 1 && it & WEAP_RAILGUN) + return WEAP_RAILGUN; else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) return WEAP_TRANQ; else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) @@ -2187,7 +2187,7 @@ void () W_Attack = { player_shot1(); W_FireTranq(); Attack_Finished(1.5); - } else if (self.current_weapon == WEAP_LASER) { + } else if (self.current_weapon == WEAP_RAILGUN) { FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireLaser(); @@ -2238,7 +2238,7 @@ float (float weap) W_GetSlot = { || (!cf_pyro_impulses && weap == WEAP_INCENDIARY) || (cf_pyro_impulses && weap == WEAP_FLAMETHROWER) || weap == WEAP_TRANQ - || weap == WEAP_LASER + || weap == WEAP_RAILGUN || weap == WEAP_ASSAULT_CANNON) { return 1; } else if (weap == WEAP_SUPER_SHOTGUN @@ -2274,7 +2274,7 @@ float (float weap) W_OldGetSlot = { else if (weap == WEAP_SHOTGUN || weap == WEAP_SNIPER_RIFLE || weap == WEAP_TRANQ - || weap == WEAP_LASER) + || weap == WEAP_RAILGUN) return 2; else if (weap == WEAP_SUPER_SHOTGUN || weap == WEAP_AUTO_RIFLE) @@ -2465,7 +2465,7 @@ float () W_OldWeaponSlot2 = { else if (self.playerclass == PC_SPY) return WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) - return WEAP_LASER; + return WEAP_RAILGUN; return 0; }; @@ -2542,7 +2542,7 @@ float () W_WeaponSlot1 = { else if (self.playerclass == PC_SPY) return WEAP_TRANQ; else if (self.playerclass == PC_ENGINEER) - return WEAP_LASER; + return WEAP_RAILGUN; return 0; }; @@ -2672,7 +2672,7 @@ float (float newSlot) W_OldImpulseFromNewSlot = { return W_OldGetSlot(WEAP_TRANQ); } else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_LASER); + return W_OldGetSlot(WEAP_RAILGUN); } } else if (newSlot == 2) { @@ -2730,7 +2730,7 @@ float (float newSlot) W_OldImpulseFromNewSlot = { return W_OldGetSlot(WEAP_NAILGUN); } else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_LASER); + return W_OldGetSlot(WEAP_RAILGUN); } } else if (newSlot == 4) { From 2a3ff456379a2b0ab13fa263ab636dbb6a0bccc8 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:04:37 -0700 Subject: [PATCH 1733/2474] Remove old reload code, migrate fully to new implementation. Large simplification to attack code since reload and clip interaction is generic rather than per-weap. Fixed a frustrating edge case: If you fire as spy when you need to reload, you'd previously drop your disguise before reload is forced, even though you never actually fired to reveal it. Leaving you undisguised and helpless. --- share/fo_weapons.qc | 40 ++---- ssqc/actions.qc | 320 ++------------------------------------------ ssqc/hwguy.qc | 2 +- ssqc/progs.src | 2 +- ssqc/status.qc | 90 ++----------- ssqc/weapons.qc | 231 +++----------------------------- 6 files changed, 63 insertions(+), 622 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 2f7e43af..9b2c753e 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -44,14 +44,13 @@ struct FO_WeapInfo { void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->weapon = weapon; wi->ammo_per_shot = 1; - wi->needs_reload = TRUE; + wi->clip_size = 0; switch (weapon) { /* NONE */ case WEAP_HOOK: wi->name = "Hook"; wi->model[0] = "progs/v_grap.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_KNIFE: @@ -59,28 +58,24 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->model[0] = "progs/v_knife.mdl"; wi->model[1] = "progs/v_knife2.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_MEDIKIT: wi->name = "BioAxe"; wi->model[0] = "progs/v_medi.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_SPANNER: wi->name = "Spanner"; wi->model[0] = "progs/v_spanner.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; case WEAP_AXE: wi->name = "Axe"; wi->model[0] = "progs/v_axe.mdl"; wi->ammo_type = AMMO_NONE; - wi->needs_reload = FALSE; wi->attack_time = 0.5; break; /* SHELLS */ @@ -112,22 +107,18 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->clip_size = 1; wi->full_reload_time = 4; wi->clip_fired = &self.reload_sniper_rifle; - } else { - wi->needs_reload = FALSE; } break; case WEAP_AUTO_RIFLE: wi->name = "Sniper Rifle"; wi->model[0] = "progs/v_srifle.mdl"; wi->ammo_type = AMMO_SHELLS; - wi->needs_reload = FALSE; wi->attack_time = 0.1; break; case WEAP_TRANQ: wi->name = "Tranq Gun"; wi->model[0] = "progs/v_tranq.mdl"; wi->ammo_type = AMMO_SHELLS; - wi->needs_reload = FALSE; wi->attack_time = 1.5; break; case WEAP_ASSAULT_CANNON: @@ -137,6 +128,8 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->clip_size = 100; wi->full_reload_time = 4; wi->clip_fired = &player.reload_assault_cannon; + if (fo_hwguy) + wi->clip_size = PC_HVYWEAP_ASSCAN_CLIPSIZE; break; /* NAILS */ case WEAP_NAILGUN: @@ -145,7 +138,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NAILS; wi->ammo_per_shot = 2; wi->attack_time = 0.2; - wi->needs_reload = FALSE; break; case WEAP_SUPER_NAILGUN: wi->name = "Super Nailgun"; @@ -153,14 +145,12 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { wi->ammo_type = AMMO_NAILS; wi->ammo_per_shot = 4; wi->attack_time = 0.2; - wi->needs_reload = FALSE; break; case WEAP_RAILGUN: wi->name = "Railgun"; wi->model[0] = "progs/v_rail.mdl"; wi->ammo_type = AMMO_NAILS; wi->ammo_type = AMMO_NAILS; - wi->needs_reload = FALSE; wi->attack_time = 0.4; break; /* ROCKETS */ @@ -194,14 +184,12 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { case PYRO_OZTF: wi->attack_time = 0.9; break; case PYRO_FO: wi->attack_time = 0.9; break; } - wi->needs_reload = FALSE; break; /* CELLS */ case WEAP_FLAMETHROWER: wi->name = "Flamethrower"; wi->model[0] = "progs/v_flame.mdl"; wi->ammo_type = AMMO_CELLS; - wi->needs_reload = FALSE; wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; break; /* NOT USED */ @@ -211,6 +199,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { error("Should never be invoked\n"); } + wi->needs_reload = wi->clip_size > 0; wi->ammo_remaining = AMMO_to_p(player, wi->ammo_type); if (!wi->needs_reload) { wi->clip_fired = __NULL__; @@ -218,7 +207,6 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { } #ifdef SSQC -void TeamFortress_OldReloadWeapon(float weap); void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; void (entity pl, float swap) W_WeaponState_Load; @@ -247,19 +235,18 @@ static void FOT_ReloadTimer() { Status_Refresh(self.owner); } -float FO_UseNewReload() { - return CF_GetSetting("dunr", "debug_use_new_reload", "on"); -} - -float FO_CheckForAmmo(float weapon) { +float FO_CanReload(float weapon) { FO_WeapInfo wi; FO_FillWeapInfo(self, weapon, &wi); + if (wi->ammo_type == AMMO_NONE) + return FALSE; + if (wi->needs_reload && *wi->clip_fired > 0 && *wi->ammo_remaining > wi->ammo_per_shot) - return 1; + return TRUE; - return 0; + return FALSE; } void () TeamFortress_ForceReloadCurrentWeapon; @@ -267,12 +254,13 @@ float FO_CheckForReload() { FO_WeapInfo wi; FO_FillWeapInfo(self, self.current_weapon, &wi); - if (*wi->clip_fired >= wi->clip_size && *wi->ammo_remaining > 0) { + if (wi->needs_reload && *wi->clip_fired >= wi->clip_size && + *wi->ammo_remaining > 0) { if (force_reload) TeamFortress_ForceReloadCurrentWeapon(); - return 1; + return TRUE; } else { - return 0; + return FALSE; } } diff --git a/ssqc/actions.qc b/ssqc/actions.qc index d77f6780..21e773ba 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -2,8 +2,6 @@ // Non Class-Specific Impulse Commands //======================================================== -void () TeamFortress_ClipTick; - void () TeamFortress_Discard = { local string s = infokey(self,"keepcells"); local float c = stof(s); @@ -485,296 +483,12 @@ void () RestoreDefaultWeapon = { } }; -void TeamFortress_OldReloadWeapon(float weap); -void FO_ReloadWeapon(float weap, float force); - -void TeamFortress_ReloadWeapon(float weap, float force) { - if (FO_UseNewReload()) - FO_ReloadWeapon(weap, force); - else - TeamFortress_OldReloadWeapon(weap); -} - -void TeamFortress_OldReloadWeapon(float weap) -{ - RestoreDefaultWeapon(); - - local float reloadtime = 0; - local float reloadamount = 0; - local entity tWeapon, tClip; - - if (self.tfstate & TFSTATE_RELOADING) { - return; - } - - if (weap == WEAP_SHOTGUN) { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - if (self.reload_shotgun == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((8 - self.reload_shotgun) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - if (self.ammo_shells >= 1) { - self.current_weapon = weap; - if (self.reload_shotgun >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_shotgun; - Attack_Finished(0.4); - self.reload_clipsize = (8 - reloadamount); - reloadtime = (8 - reloadamount) / 8; - reloadtime = 2 - 2 * reloadtime; - self.reload_shotgun = 0; - if (self.ammo_shells < 8) { - self.reload_shotgun = 8 - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Shotgun...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_shotgun; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_SUPER_SHOTGUN) { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - if (self.reload_super_shotgun == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((16 - self.reload_super_shotgun) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - if (self.ammo_shells >= 2) { - self.current_weapon = weap; - if (self.reload_super_shotgun >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_super_shotgun; - Attack_Finished(0.7); - self.reload_clipsize = (16 - reloadamount); - reloadtime = (16 - reloadamount) / 16; - reloadtime = 3 - (3 * reloadtime); - self.reload_super_shotgun = 0; - if (self.ammo_shells < 16) { - self.reload_super_shotgun = 16 - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Super Shotgun...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_super_shotgun; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_SNIPER_RIFLE) { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - if (self.reload_sniper_rifle == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((16 - self.reload_sniper_rifle) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - if (self.ammo_shells >= 1) { - self.current_weapon = weap; - if (self.reload_super_shotgun >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_sniper_rifle; - Attack_Finished(1.5); - self.reload_clipsize = (1 - reloadamount); - self.reload_sniper_rifle = 0; - self.reload_sniper_ticks = 0; - if (self.ammo_shells < 1) { - self.reload_sniper_rifle = 1 - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Sniper Rifle...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + 1; // this will tick four times before finishing reload - tWeapon.think = W_Reload_sniper_rifle_tick; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.ammo_rockets == 0) { - sprint(self, PRINT_HIGH, "Out of grenades\n"); - return; - } - if (self.reload_grenade_launcher == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((6 - self.reload_grenade_launcher) == - self.ammo_rockets) { - sprint(self, PRINT_HIGH, "All grenades are in the clip\n"); - return; - } - if (self.ammo_rockets >= 1) { - self.current_weapon = weap; - if (self.reload_grenade_launcher >= self.ammo_rockets) - reloadamount = self.ammo_rockets; - else - reloadamount = self.reload_grenade_launcher; - Attack_Finished(0.6); - self.reload_clipsize = (6 - reloadamount); - reloadtime = (6 - reloadamount) / 6; - reloadtime = 4 - 4 * reloadtime; - self.reload_grenade_launcher = 0; - if (self.ammo_rockets < 6) { - self.reload_grenade_launcher = - 6 - self.ammo_rockets; - } - sprint(self, PRINT_HIGH, "Reloading Grenade Launcher...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_grenade_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_ROCKET_LAUNCHER) { - if (self.ammo_rockets == 0) { - sprint(self, PRINT_HIGH, "Out of rockets\n"); - return; - } - if (self.reload_rocket_launcher == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - if ((4 - self.reload_rocket_launcher) == - self.ammo_rockets) { - sprint(self, PRINT_HIGH, "All rockets are in the clip\n"); - return; - } - if (self.ammo_rockets >= 1) { - self.current_weapon = weap; - if (self.reload_rocket_launcher >= self.ammo_rockets) - reloadamount = self.ammo_rockets; - else - reloadamount = self.reload_rocket_launcher; - Attack_Finished(0.8); - self.reload_clipsize = (4 - reloadamount); - reloadtime = (4 - reloadamount) / 4; - reloadtime = 5 - (5 * reloadtime); - self.reload_rocket_launcher = 0; - if (self.ammo_rockets < 4) { - self.reload_rocket_launcher = - 4 - self.ammo_rockets; - } - sprint(self, PRINT_HIGH, "Reloading Rocket Launcher...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_rocket_launcher; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } else if (weap == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if (self.ammo_shells == 0) { - sprint(self, PRINT_HIGH, "Out of shells\n"); - return; - } - - if (self.reload_assault_cannon == 0) { - sprint(self, PRINT_HIGH, "Clip full\n"); - return; - } - - if ((PC_HVYWEAP_ASSCAN_CLIPSIZE - self.reload_assault_cannon) == self.ammo_shells) { - sprint(self, PRINT_HIGH, "All shells are in the clip\n"); - return; - } - - if (self.ammo_shells >= 1) { - self.current_weapon = weap; - if (self.reload_assault_cannon >= self.ammo_shells) - reloadamount = self.ammo_shells; - else - reloadamount = self.reload_assault_cannon; - Attack_Finished(0.8); - self.reload_clipsize = (PC_HVYWEAP_ASSCAN_CLIPSIZE - reloadamount); - reloadtime = (PC_HVYWEAP_ASSCAN_CLIPSIZE - reloadamount) / PC_HVYWEAP_ASSCAN_CLIPSIZE; - reloadtime = 4 - (4 * reloadtime); - self.reload_assault_cannon = 0; - if (self.ammo_shells < PC_HVYWEAP_ASSCAN_CLIPSIZE) { - self.reload_assault_cannon = PC_HVYWEAP_ASSCAN_CLIPSIZE - self.ammo_shells; - } - sprint(self, PRINT_HIGH, "Reloading Assault Cannon...\n"); - self.tfstate = self.tfstate | TFSTATE_RELOADING; - Status_Refresh(self); - tWeapon = spawn(); - tWeapon.owner = self; - tWeapon.classname = "timer"; - tWeapon.nextthink = time + reloadtime; - tWeapon.think = W_Reload_assault_cannon; - self.weaponmodel = ""; - self.weaponframe = 0; - } else { - sprint(self, PRINT_HIGH, "Not enough ammo to reload\n"); - } - } - } - - if (reloadamount && reloadtime) { - self.reload_time = time + reloadtime; - self.reload_tick = reloadtime / reloadamount; - tClip = spawn(); - tClip.owner = self; - tClip.classname = "timer"; - tClip.nextthink = time + self.reload_tick; - tClip.think = TeamFortress_ClipTick; - } -} - void () TeamFortress_ReloadCurrentWeapon = { - TeamFortress_ReloadWeapon(self.current_weapon, FALSE); + FO_ReloadWeapon(self.current_weapon, FALSE); }; void () TeamFortress_ForceReloadCurrentWeapon = { - TeamFortress_ReloadWeapon(self.current_weapon, TRUE); + FO_ReloadWeapon(self.current_weapon, TRUE); }; void (float slot) TeamFortress_ReloadSlot = { @@ -793,7 +507,7 @@ void (float slot) TeamFortress_ReloadSlot = { return; weap = W_WeaponSlot3(); } - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); } else { if (slot < 1 || slot > 7) @@ -813,7 +527,7 @@ void (float slot) TeamFortress_ReloadSlot = { else if (slot == 7) weap = W_OldWeaponSlot7(); if (weap != 0) - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); } }; @@ -823,8 +537,8 @@ void () TeamFortress_ReloadNext = { if (!IsUsingOldImpulses()) { // reload current slot first slot = W_GetSlot(self.current_weapon); - if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon, FALSE); + if (FO_CanReload(self.current_weapon)) { + FO_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -841,9 +555,9 @@ void () TeamFortress_ReloadNext = { weap = W_WeaponSlot3(); } - if (CheckForAmmo(weap)) { + if (FO_CanReload(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); reload = 1; break; } @@ -851,8 +565,8 @@ void () TeamFortress_ReloadNext = { } else { slot = W_OldGetSlot(self.current_weapon); - if (CheckForAmmo(self.current_weapon)) { - TeamFortress_ReloadWeapon(self.current_weapon, FALSE); + if (FO_CanReload(self.current_weapon)) { + FO_ReloadWeapon(self.current_weapon, FALSE); reload = 1; return; } @@ -873,9 +587,9 @@ void () TeamFortress_ReloadNext = { else if (slot == 7) weap = W_OldWeaponSlot7(); - if (CheckForAmmo(weap)) { + if (FO_CanReload(weap)) { self.current_weapon = weap; - TeamFortress_ReloadWeapon(weap, FALSE); + FO_ReloadWeapon(weap, FALSE); reload = 1; break; } @@ -887,16 +601,6 @@ void () TeamFortress_ReloadNext = { sprint(self, PRINT_HIGH, "All clips full\n"); }; -void () TeamFortress_ClipTick = { - if (time < self.owner.reload_time) { - self.owner.reload_clipsize = self.owner.reload_clipsize + 1; - Status_Refresh(self.owner); - self.nextthink = time + self.owner.reload_tick; - } else { - dremove(self); - } -}; - entity TeamFortress_GetPracticeSpawn(entity e) = { local entity spt = find(world, classname, "practicespawn"); diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 73739a18..e6e0550b 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -115,7 +115,7 @@ void FireAssCan (float shotcount, vector dir, vector spread) { self.reload_assault_cannon = self.reload_assault_cannon + 1; Status_Refresh(self); - CheckForReload(); + FO_CheckForReload(); vector bullet_dir, spread_dir, rand_dir, org; float bullet_speed, var_speed; diff --git a/ssqc/progs.src b/ssqc/progs.src index 2bd3c685..5cd0b0b3 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -16,6 +16,7 @@ events.qc roles.qc q3defs.qc debug.qc +../share/fo_weapons.qc status.qc functions.qc menu.qc @@ -29,7 +30,6 @@ items.qc locfiles.qc antilag.qc combat.qc -../share/fo_weapons.qc weapons.qc world.qc client.qc diff --git a/ssqc/status.qc b/ssqc/status.qc index f23d22cc..1e2f383a 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -6,7 +6,6 @@ string(float num) RedScoreToString; string(float num) YellowScoreToString; string(float num) GreenScoreToString; string(entity pl, float csqcactive) ClipSizeToString; -float(entity pl) GetClipSize; string(entity pl) SniperPowerToString; string(entity pl) DetpackToString; string(entity pl) AuraToString; @@ -753,6 +752,9 @@ string GetSBClipString(entity pl, float csqcactive) string msg = ""; if (pl.tfstate & TFSTATE_RELOADING) { + FO_WeapInfo wi; + FO_FillWeapInfo(pl, pl.current_weapon, &wi); + if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); } else { @@ -762,7 +764,7 @@ string GetSBClipString(entity pl, float csqcactive) msg = csqcactive ? "0" : " 0"; msg = strcat(msg, "/"); - msg = strcat(msg, (csqcactive ? ftos(GetClipSize(pl)) : strpadr(ftos(GetClipSize(pl)), 3))); + msg = strcat(msg, (csqcactive ? ftos(wi->clip_size) : strpadr(ftos(wi->clip_size), 3))); } } else @@ -1331,89 +1333,25 @@ string(float num) GreenScoreToString = string(entity pl, float csqcactive) ClipSizeToString = { - local string st = ""; - local float num = 0, max; - - max = GetClipSize(pl); - if (pl.current_weapon == WEAP_SHOTGUN) { - if ((max - pl.reload_shotgun) > pl.ammo_shells) - pl.reload_shotgun = max - pl.ammo_shells; - num = max - pl.reload_shotgun; - } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { - if ((max - pl.reload_super_shotgun) > pl.ammo_shells) - pl.reload_super_shotgun = max - pl.ammo_shells; - num = (max - pl.reload_super_shotgun); - } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { - if (!sniperreload) - return ""; - if ((max - pl.reload_sniper_rifle) > pl.ammo_shells) - pl.reload_sniper_rifle = max - pl.ammo_shells; - num = (max - pl.reload_sniper_rifle); - } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { - if ((max - pl.reload_grenade_launcher) > pl.ammo_rockets) - pl.reload_grenade_launcher = (max - pl.ammo_rockets); - num = (max - pl.reload_grenade_launcher); - } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { - if ((max - pl.reload_rocket_launcher) > pl.ammo_rockets) - pl.reload_rocket_launcher = (max - pl.ammo_rockets); - num = (max - pl.reload_rocket_launcher); - } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if ((max - pl.reload_assault_cannon) > pl.ammo_shells) - pl.reload_assault_cannon = (max - pl.ammo_shells); - num = (max - pl.reload_assault_cannon); - } - } else + FO_WeapInfo wi; + FO_FillWeapInfo(pl, pl.current_weapon, &wi); + + if (!wi->needs_reload) return ""; - if (num > 999) - num = 999; + if (wi->clip_size - *wi->clip_fired > *wi->ammo_remaining) + *wi->clip_fired = wi->clip_size - *wi->ammo_remaining; + float rem = min(wi->clip_size - *wi->clip_fired, 999); + string st = ""; if (csqcactive) - { - st = strcat(ftos(floor(num)), "/", ftos(max)); - } + st = strcat(ftos(floor(rem)), "/", ftos(wi->clip_size)); else - { - st = strpadl(ftos(floor(num)), 2); - st = strcat(st, "/"); - st = strcat(st, strpadr(ftos(max), 3)); - } - - + st = strcat(strpadl(ftos(rem), 2), "/", strpadr(ftos(wi->clip_size), 3)); return st; }; -float GetClipSize(entity pl) -{ - switch (pl.current_weapon) - { - case WEAP_SHOTGUN: - return 8; - case WEAP_SUPER_SHOTGUN: - return 16; - case WEAP_SNIPER_RIFLE: - return 1; - case WEAP_GRENADE_LAUNCHER: - return 6; - case WEAP_ROCKET_LAUNCHER: - return 4; - case WEAP_ASSAULT_CANNON: - if (fo_hwguy) - { - return PC_HVYWEAP_ASSCAN_CLIPSIZE; - } - else - { - return 0; - } - default: - return 0; - } -} - string(entity pl) DisguiseToString = { local string st = ""; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 9a2e2ca8..70492d4d 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -80,7 +80,7 @@ void () UseSpecialSkill; void () UseSpecialSkill2; void () RemoveFlare; void () ScannerSwitch; -float () CheckForReload; +float () FO_CheckForReload; void (float all) TeamFortress_TeamShowScores; void (entity Player) TeamFortress_TeamShowMemberClasses; @@ -1839,163 +1839,6 @@ void () W_ChangeToBestWeapon = { W_PrintWeaponMessage(); } -float () W_CheckNoAmmo = { - if (self.current_weapon == WEAP_AXE - || self.current_weapon == WEAP_SPANNER - || self.current_weapon == WEAP_KNIFE - || self.current_weapon == WEAP_MEDIKIT) - return 1; - else if (self.current_weapon == WEAP_SUPER_NAILGUN && self.currentammo >= 4) - return 1; - else if (self.current_weapon == WEAP_INCENDIARY && self.currentammo >= 3) - return 1; - else if ((self.current_weapon == WEAP_SUPER_SHOTGUN || self.current_weapon == WEAP_NAILGUN) - && self.currentammo >= 2) - return 1; - else if (self.currentammo > 0) - return 1; - - W_ChangeToBestWeapon(); - return 0; -}; - -void () W_Reload_shotgun = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_shot.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void () W_Reload_super_shotgun = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_shot2.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void (entity pl) W_Reload_sniper_rifle = { - pl.reload_sniper_ticks = 0; - pl.tfstate = pl.tfstate - (pl.tfstate & TFSTATE_RELOADING); - pl.weaponmodel = "progs/v_srifle.mdl"; - sprint(pl, PRINT_HIGH, "Finished reloading\n"); - W_WeaponState_Load(pl, 0); - Status_Refresh(pl); -}; - -void () W_Reload_sniper_rifle_tick = { - self.owner.reload_sniper_ticks = self.owner.reload_sniper_ticks + 1; - - if (self.owner.reload_sniper_ticks >= 4) { - W_Reload_sniper_rifle(self.owner); - dremove(self); - return; - } - - Status_Refresh(self.owner); - self.nextthink = time + 1; -} - -void () W_Reload_grenade_launcher = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - if (self.owner.weaponmode == 0) - self.owner.weaponmodel = "progs/v_rock.mdl"; - else - self.owner.weaponmodel = "progs/v_pipe.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void () W_Reload_rocket_launcher = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_rock2.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -void () W_Reload_assault_cannon = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING); - self.owner.weaponmodel = "progs/v_asscan.mdl"; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - W_WeaponState_Load(self.owner, 0); - Status_Refresh(self.owner); -}; - -float FO_CheckForReload(); - -float () CheckForReload = { - if (FO_UseNewReload()) - return FO_CheckForReload(); - - float need_reload = FALSE; - - if (self.current_weapon == WEAP_SHOTGUN) { - if (self.reload_shotgun >= 8 && self.ammo_shells > 0) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - if (self.reload_super_shotgun >= 16 && self.ammo_shells > 0) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > 0 && sniperreload) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - if ((self.reload_grenade_launcher >= 6) && (self.ammo_rockets > 0)) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { - if ((self.reload_rocket_launcher >= 4) && (self.ammo_rockets > 0)) - need_reload = TRUE; - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy && self.reload_assault_cannon >= PC_HVYWEAP_ASSCAN_CLIPSIZE - && self.ammo_shells > 0) - need_reload = TRUE; - } - - if (need_reload) { - if (force_reload) - TeamFortress_ForceReloadCurrentWeapon(); - return 1; - } else { - return 0; - } -}; - -float FO_CheckForAmmo(float weapon); -float (float weap) CheckForAmmo = { - if (FO_UseNewReload()) - return FO_CheckForAmmo(weap); - - if (weap == WEAP_SHOTGUN) { - if (self.reload_shotgun >= 1 && self.ammo_shells > self.reload_shotgun) - return 1; - } else if (weap == WEAP_SUPER_SHOTGUN) { - if (self.reload_super_shotgun >= 2 && self.ammo_shells > self.reload_super_shotgun) - return 1; - } else if (weap == WEAP_SNIPER_RIFLE) { - if (self.reload_sniper_rifle >= 1 && self.ammo_shells > self.reload_sniper_rifle && sniperreload) - return 1; - } else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.reload_grenade_launcher >= 1 && self.ammo_rockets > self.reload_grenade_launcher) - return 1; - } else if (weap == WEAP_ROCKET_LAUNCHER) { - if (self.reload_rocket_launcher >= 1 && self.ammo_rockets > self.reload_rocket_launcher) - return 1; - } else if (weap == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) { - if (self.reload_assault_cannon >= 1 && self.ammo_shells > self.reload_assault_cannon) - return 1; - } - } - return 0; -}; - void () player_axe1; void () player_axeb1; @@ -2021,10 +1864,9 @@ void () player_medikit1; void () player_medikitb1; void () W_Attack = { - local float r; - - if (!W_CheckNoAmmo()) - return; + FO_WeapInfo wi; + FO_FillWeapInfo(self, self.current_weapon, &wi); + float r; if (self.has_disconnected == TRUE) return; @@ -2032,7 +1874,17 @@ void () W_Attack = { if (self.tfstate & TFSTATE_RELOADING || self.is_detpacking) return; - if(no_fire_mode) + if (no_fire_mode) + return; + + // Out of ammo? + if (wi->ammo_type != AMMO_NONE && + *wi->ammo_remaining < wi->ammo_per_shot) { + W_ChangeToBestWeapon(); + return; + } + // Fired into forced reload? + if (FO_CheckForReload()) return; if ((self.is_undercover || (self.undercover_team != 0)) || @@ -2043,7 +1895,6 @@ void () W_Attack = { self.show_hostile = time + 1; if (self.current_weapon == WEAP_AXE) { - Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) @@ -2051,7 +1902,6 @@ void () W_Attack = { else player_axeb1(); } else if (self.current_weapon == WEAP_KNIFE) { - Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) @@ -2059,77 +1909,48 @@ void () W_Attack = { else player_knifeb1(); } else if (self.current_weapon == WEAP_SPANNER) { - Attack_Finished(0.5); FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); player_spanner1(); } else if (self.current_weapon == WEAP_SHOTGUN) { - if (CheckForReload() == TRUE) - return; player_shot1(); W_FireShotgun(); self.reload_shotgun = self.reload_shotgun + 1; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.5); } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { - if (CheckForReload() == TRUE) - return; player_shot1(); W_FireSuperShotgun(); self.reload_super_shotgun = self.reload_super_shotgun + 2; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.7); } else if (self.current_weapon == WEAP_NAILGUN) { player_nail1(); } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { player_nail1(); } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { - if (CheckForReload() == TRUE) - return; player_rocket1(); W_FireGrenade(); self.reload_grenade_launcher = self.reload_grenade_launcher + 1; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.6); } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { - if (CheckForReload() == TRUE) - return; player_rocket1(); W_FireRocket(); self.reload_rocket_launcher = self.reload_rocket_launcher + 1; Status_Refresh(self); - CheckForReload(); - Attack_Finished(0.8); } else if (self.current_weapon == WEAP_LIGHTNING) { player_light1(); - Attack_Finished(0.1); FO_Sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { if (self.flags & FL_ONGROUND) { - if (CheckForReload() == TRUE) - return; player_shot1(); W_FireSniperRifle(); if (sniperreload) { self.reload_sniper_rifle = self.reload_sniper_rifle + 1; Status_Refresh(self); - CheckForReload(); } - Attack_Finished(1.5); } } else if (self.current_weapon == WEAP_AUTO_RIFLE) { player_autorifle1(); W_FireAutoRifle(); - Attack_Finished(0.1); } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { - if (fo_hwguy) - { - if (CheckForReload() == TRUE) - return; - } - if (self.ammo_cells < 7) { if (time >= self.antispam_assault_cannon) { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); @@ -2157,19 +1978,6 @@ void () W_Attack = { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); - switch (pyro_type) - { - case PYRO_ORIGINAL: - Attack_Finished(1.2); - break; - case PYRO_OZTF: - Attack_Finished(0.9); - break; - case PYRO_FO: - //Attack_Finished(PC_PYRO_LAVA_RETICK); - Attack_Finished(0.9); - break; - } } else if (time >= self.antispam_incendiary_cannon) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; @@ -2181,19 +1989,22 @@ void () W_Attack = { player_medikit1(); else player_medikitb1(); - Attack_Finished(0.5); } else if (self.current_weapon == WEAP_TRANQ) { FO_Sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); player_shot1(); W_FireTranq(); - Attack_Finished(1.5); } else if (self.current_weapon == WEAP_RAILGUN) { FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireLaser(); - Attack_Finished(0.4); } + if (self.current_weapon != WEAP_FLAMETHROWER) + Attack_Finished(wi->attack_time); + + if (wi->needs_reload) + FO_CheckForReload(); + //These weapons have to log each projectile launched/bullet fired if (self.current_weapon != WEAP_ASSAULT_CANNON || self.current_weapon != WEAP_NAILGUN || From 40b668ad5396b7eecf164745de386f48b020089d Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:19:55 -0700 Subject: [PATCH 1734/2474] Add WEAP->Index conversion Useful so that we can have lookup tables indexed by weapon, which is otherwise a flag bit value. --- csqc/csprogs.src | 1 + csqc/main.qc | 1 + share/defs.h | 44 ++++++++++++++++++++++++-------------------- share/fo_weapons.qc | 42 +++++++++++++++++++++++++++++++++++++++++- ssqc/client.qc | 5 +++-- 5 files changed, 70 insertions(+), 23 deletions(-) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 2aa77962..37747e32 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -11,6 +11,7 @@ csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc +../share/fo_weapons.qc sui_sys.qc vote.qc status.qc diff --git a/csqc/main.qc b/csqc/main.qc index 7f5bd666..3e7f7994 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -27,6 +27,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_pic(HudIcons[i].icon); // } + FO_Weapons_Init(); CsGrenTimer::Init(); registercommand("fo_hud_editor"); diff --git a/share/defs.h b/share/defs.h index 3d0a8e5b..fef62997 100644 --- a/share/defs.h +++ b/share/defs.h @@ -704,26 +704,30 @@ /* New Weapon Defines */ /*======================================================*/ -#define WEAP_HOOK 1 -#define WEAP_KNIFE 2 -#define WEAP_MEDIKIT 4 -#define WEAP_SPANNER 8 -#define WEAP_AXE 16 -#define WEAP_SNIPER_RIFLE 32 -#define WEAP_AUTO_RIFLE 64 -#define WEAP_SHOTGUN 128 -#define WEAP_SUPER_SHOTGUN 256 -#define WEAP_NAILGUN 512 -#define WEAP_SUPER_NAILGUN 1024 -#define WEAP_GRENADE_LAUNCHER 2048 -#define WEAP_FLAMETHROWER 4096 -#define WEAP_ROCKET_LAUNCHER 8192 -#define WEAP_INCENDIARY 16384 -#define WEAP_ASSAULT_CANNON 32768 -#define WEAP_LIGHTNING 65536 -#define WEAP_DETPACK 131072 -#define WEAP_TRANQ 262144 -#define WEAP_RAILGUN 524288 +enumflags { + WEAP_HOOK, + WEAP_KNIFE, + WEAP_MEDIKIT, + WEAP_SPANNER, + WEAP_AXE, + WEAP_SNIPER_RIFLE, + WEAP_AUTO_RIFLE, + WEAP_SHOTGUN, + WEAP_SUPER_SHOTGUN, + WEAP_NAILGUN, + WEAP_SUPER_NAILGUN, + WEAP_GRENADE_LAUNCHER, + WEAP_FLAMETHROWER, + WEAP_ROCKET_LAUNCHER, + WEAP_INCENDIARY, + WEAP_ASSAULT_CANNON, + WEAP_LIGHTNING, + WEAP_DETPACK, + WEAP_TRANQ, + WEAP_RAILGUN, + WEAP_LAST = WEAP_RAILGUN, +}; + // still room for 12 more weapons // but we can remove some by giving the weapons // a weapon mode (like the rifle) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 9b2c753e..adda5d1c 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -1,3 +1,40 @@ +#ifdef CSQC +/* + * This is a hack so that we can have our client entity be closer to server for + * shared code. We'll refactor this on both sides to be cleaner incrementally, + * but it gets us started. + */ +.float reload_rocket_launcher; +.float reload_grenade_launcher; +.float reload_shotgun; +.float reload_super_shotgun; +.float reload_super_shotgun; +.float reload_assault_cannon; +.float reload_sniper_rifle; +.float waterlevel; + +.float ammo_shells; +.float ammo_nails; +.float ammo_rockets; +.float ammo_cells; + +float fo_hwguy = TRUE; +float sniperreload = FALSE; +float pyro_type = PYRO_FO; +#endif + +// Convert a weapon-bit to a linear index. +static float WEAP_to_index(float weapon) { + float index = 0; + for (; weapon > 0; weapon >>= 1, index++) { + if (weapon >= 64) { + weapon >>= 6; + index += 6; + } + } + return index - 1; // Want zero-offset. +} + enum AmmoType { AMMO_NONE, AMMO_SHELLS, @@ -196,7 +233,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { case WEAP_LIGHTNING: case WEAP_DETPACK: default: - error("Should never be invoked\n"); + error(sprintf("ID=%d should never be invoked\n", weapon)); } wi->needs_reload = wi->clip_size > 0; @@ -329,3 +366,6 @@ void FO_ReloadWeapon(float weapon, float force) { } #endif + +void FO_Weapons_Init() { +} diff --git a/ssqc/client.qc b/ssqc/client.qc index 2b43cc50..2a46e9cf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1076,8 +1076,9 @@ void () DecodeLevelParms = { } if (parm15) self.is_admin = parm15; - - + + // Must be after we've set up conditional options (e.g. hwguy reload). + FO_Weapons_Init(); /* local entity p = find(world, classname, "player"); while (p != world) { From 0d17563fb4d54d6d40a5c6ea20ec43efd7e22929 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 21:02:29 -0700 Subject: [PATCH 1735/2474] refactor on weapindex --- share/fo_weapons.qc | 350 +++++++++++++++++++++++++------------------- ssqc/status.qc | 14 +- ssqc/weapons.qc | 7 +- 3 files changed, 209 insertions(+), 162 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index adda5d1c..bf761eb4 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -41,9 +41,98 @@ enum AmmoType { AMMO_NAILS, AMMO_CELLS, AMMO_ROCKETS, - AMMO_GRENADES, // Rockets really + AMMO_NUM_TYPES = AMMO_ROCKETS + 1, }; +struct FO_WeapInfo { + int weapon; // Verification + AmmoType ammo_type; + int clip_size; + int ammo_per_shot; + float attack_time; + float full_reload_time; + + // Fields below this are automatically initialized by Init. Do not include + // in table. + float needs_reload; +}; + +// REQUIRES: weapon at index i == WEAP_to_index(weap) +// -ve values are placeholders signifying conditional init based on game modes. +FO_WeapInfo weapon_info[] = { + { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_MEDIKIT, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_SPANNER, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_AXE, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_SNIPER_RIFLE, AMMO_SHELLS, -9, 1, 1.5, 4 }, + { WEAP_AUTO_RIFLE, AMMO_SHELLS, 0, 1, 0.1, 0 }, + { WEAP_SHOTGUN, AMMO_SHELLS, 8, 1, 0.5, 2 }, + { WEAP_SUPER_SHOTGUN, AMMO_SHELLS, 16, 2, 0.7, 3 }, + { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, + { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 4, 0.2, 0 }, + { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, + { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, + { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, + { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, + { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0, 4 }, + { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, + { WEAP_DETPACK, AMMO_NONE, 0, 0, -1, 0 }, + { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, + { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, +}; + +struct FO_ClassWeapons { + float id; + float slots[4]; + FO_WeapInfo *info[4]; +}; + +// Indexed by class ID, e.g. PC_SOLDIER +FO_ClassWeapons class_weapons[] = { + { PC_UNDEFINED, { 0, 0, 0, 0 } }, + { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, + { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, + { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_GRENADE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_MEDIC, { WEAP_SUPER_NAILGUN, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_MEDIKIT } }, + { PC_HVYWEAP, { WEAP_ASSAULT_CANNON, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, + { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, +}; + +inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { + return &weapon_info[WEAP_to_index(weapon)]; +} + +// Indexed by WEAP_to_index(). We keep them out of the main table just to keep +// things a little more wieldly/readable. +static string weapon_names[] = { + "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", "Sniper Rifle", + "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", "Grenade Launcher", + "Flamethrower", "Rocket Launcher", "Incendiary Launcher", "Assault Cannon", + "Lightning Gun", "Detpack", "Tranquilizer", "Railgun" +}; + +inline string FO_GetWeapName(float weapon) { + return weapon_names[WEAP_to_index(weapon)]; +} + +struct FO_WeapState { + float weapon; + + // Constant and relative to weapon. TODO, migrate similar to WeapInfo. + FO_WeapInfo* wi; + string model[2]; // indexed by weaponmode + + /* These are relative to the player passed. */ + float* ammo_remaining; + float* clip_fired; +}; + +struct FO_WeapInfo weap_info_by_index[32]; + // REQUIRES: Order must match above. static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; @@ -54,180 +143,90 @@ static float* AMMO_to_p(entity player, AmmoType ammo_type) { case AMMO_CELLS: return &player.ammo_cells; case AMMO_NAILS: return &player.ammo_nails; case AMMO_ROCKETS: return &player.ammo_rockets; - case AMMO_GRENADES: return &player.ammo_rockets; } error(sprintf("UNK AMMO_TYPE=%d\n", ammo_type)); return __NULL__; } -struct FO_WeapInfo { - float weapon; - - /* These are always constant and relative to weapon. */ - string name; - string model[2]; // indexed by weaponmode - AmmoType ammo_type; - float ammo_per_shot; - float needs_reload; - float full_reload_time; - float clip_size; - float attack_time; +float WEAP_to_slot(float class, float weapon) { + for (float i = 0; i < 4; i++) + if (class_weapons[class].slots[i] == weapon) + return i; + return -1; +} - /* These are relative to the player passed. */ - float* ammo_remaining; - float* clip_fired; -}; +void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { + ws->weapon = weapon; + ws->wi = FO_GetWeapInfo(weapon); -void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { - wi->weapon = weapon; - wi->ammo_per_shot = 1; - wi->clip_size = 0; switch (weapon) { /* NONE */ case WEAP_HOOK: - wi->name = "Hook"; - wi->model[0] = "progs/v_grap.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_grap.mdl"; break; case WEAP_KNIFE: - wi->name = "Knife"; - wi->model[0] = "progs/v_knife.mdl"; - wi->model[1] = "progs/v_knife2.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_knife.mdl"; + ws->model[1] = "progs/v_knife2.mdl"; break; case WEAP_MEDIKIT: - wi->name = "BioAxe"; - wi->model[0] = "progs/v_medi.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_medi.mdl"; break; case WEAP_SPANNER: - wi->name = "Spanner"; - wi->model[0] = "progs/v_spanner.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_spanner.mdl"; break; case WEAP_AXE: - wi->name = "Axe"; - wi->model[0] = "progs/v_axe.mdl"; - wi->ammo_type = AMMO_NONE; - wi->attack_time = 0.5; + ws->model[0] = "progs/v_axe.mdl"; break; /* SHELLS */ case WEAP_SHOTGUN: - wi->name = "Shotgun"; - wi->model[0] = "progs/v_shot.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->clip_size = 8; - wi->attack_time = 0.5; - wi->full_reload_time = 2; - wi->clip_fired = &player.reload_shotgun; + ws->model[0] = "progs/v_shot.mdl"; + ws->clip_fired = &player.reload_shotgun; break; case WEAP_SUPER_SHOTGUN: - wi->name = "Super Shotgun"; - wi->model[0] = "progs/v_shot2.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->clip_size = 16; - wi->ammo_per_shot = 2; - wi->attack_time = 0.7; - wi->full_reload_time = 3; - wi->clip_fired = &player.reload_super_shotgun; + ws->model[0] = "progs/v_shot2.mdl"; + ws->clip_fired = &player.reload_super_shotgun; break; case WEAP_SNIPER_RIFLE: - wi->name = "Sniper Rifle"; - wi->model[0] = "progs/v_srifle.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->attack_time = 1.5; - if (sniperreload) { - wi->clip_size = 1; - wi->full_reload_time = 4; - wi->clip_fired = &self.reload_sniper_rifle; - } + ws->model[0] = "progs/v_srifle.mdl"; + if (sniperreload) + ws->clip_fired = &player.reload_sniper_rifle; break; case WEAP_AUTO_RIFLE: - wi->name = "Sniper Rifle"; - wi->model[0] = "progs/v_srifle.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->attack_time = 0.1; + ws->model[0] = "progs/v_srifle.mdl"; break; case WEAP_TRANQ: - wi->name = "Tranq Gun"; - wi->model[0] = "progs/v_tranq.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->attack_time = 1.5; + ws->model[0] = "progs/v_tranq.mdl"; break; case WEAP_ASSAULT_CANNON: - wi->name = "Assault Cannon"; - wi->model[0] = "progs/v_asscan.mdl"; - wi->ammo_type = AMMO_SHELLS; - wi->clip_size = 100; - wi->full_reload_time = 4; - wi->clip_fired = &player.reload_assault_cannon; - if (fo_hwguy) - wi->clip_size = PC_HVYWEAP_ASSCAN_CLIPSIZE; + ws->model[0] = "progs/v_asscan.mdl"; + ws->clip_fired = &player.reload_assault_cannon; break; /* NAILS */ case WEAP_NAILGUN: - wi->name = "Nailgun"; - wi->model[0] = "progs/v_nail.mdl"; - wi->ammo_type = AMMO_NAILS; - wi->ammo_per_shot = 2; - wi->attack_time = 0.2; + ws->model[0] = "progs/v_nail.mdl"; break; case WEAP_SUPER_NAILGUN: - wi->name = "Super Nailgun"; - wi->model[0] = "progs/v_nail2.mdl"; - wi->ammo_type = AMMO_NAILS; - wi->ammo_per_shot = 4; - wi->attack_time = 0.2; + ws->model[0] = "progs/v_nail2.mdl"; break; case WEAP_RAILGUN: - wi->name = "Railgun"; - wi->model[0] = "progs/v_rail.mdl"; - wi->ammo_type = AMMO_NAILS; - wi->ammo_type = AMMO_NAILS; - wi->attack_time = 0.4; + ws->model[0] = "progs/v_rail.mdl"; break; /* ROCKETS */ case WEAP_GRENADE_LAUNCHER: - wi->name = "Grenade Launcher"; - wi->model[0] = "progs/v_rock.mdl"; - wi->model[1] = "progs/v_pipe.mdl"; - wi->ammo_type = AMMO_ROCKETS; - wi->clip_size = 6; - wi->attack_time = 0.6; - wi->full_reload_time = 4; - wi->clip_fired = &player->reload_grenade_launcher; + ws->model[0] = "progs/v_rock.mdl"; + ws->model[1] = "progs/v_pipe.mdl"; + ws->clip_fired = &player.reload_grenade_launcher; break; case WEAP_ROCKET_LAUNCHER: - wi->name = "Rocket Launcher"; - wi->model[0] = "progs/v_rock2.mdl"; - wi->ammo_type = AMMO_ROCKETS; - wi->clip_size = 4; - wi->clip_fired = &player->reload_rocket_launcher; - wi->full_reload_time = 5; - wi->attack_time = 0.8; + ws->model[0] = "progs/v_rock2.mdl"; + ws->clip_fired = &player.reload_rocket_launcher; break; case WEAP_INCENDIARY: - wi->name = "Incendiary Launcher"; - wi->model[0] = "progs/v_irock.mdl"; - wi->ammo_type = AMMO_ROCKETS; - wi->ammo_per_shot = 3; - wi->attack_time = 0.9; - switch (pyro_type) { - case PYRO_ORIGINAL: wi->attack_time = 1.2; break; - case PYRO_OZTF: wi->attack_time = 0.9; break; - case PYRO_FO: wi->attack_time = 0.9; break; - } + ws->model[0] = "progs/v_irock.mdl"; break; /* CELLS */ case WEAP_FLAMETHROWER: - wi->name = "Flamethrower"; - wi->model[0] = "progs/v_flame.mdl"; - wi->ammo_type = AMMO_CELLS; - wi->attack_time = (player.waterlevel > 2) ? 1 : 0.15; + ws->model[0] = "progs/v_flame.mdl"; break; /* NOT USED */ case WEAP_LIGHTNING: @@ -236,11 +235,7 @@ void FO_FillWeapInfo(entity player, float weapon, FO_WeapInfo* wi) { error(sprintf("ID=%d should never be invoked\n", weapon)); } - wi->needs_reload = wi->clip_size > 0; - wi->ammo_remaining = AMMO_to_p(player, wi->ammo_type); - if (!wi->needs_reload) { - wi->clip_fired = __NULL__; - } + ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); } #ifdef SSQC @@ -250,19 +245,19 @@ void (entity pl, float swap) W_WeaponState_Load; void (float att_delay) Attack_Finished; static void FOT_ReloadTimer() { - FO_WeapInfo wi; - FO_FillWeapInfo(self.owner, self.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self.owner, self.current_weapon, &ws); if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = wi->model[self.owner.weaponmode]; + self.owner.weaponmodel = ws->model[self.owner.weaponmode]; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); } else { // Refresh clip - if (wi.weapon != WEAP_SNIPER_RIFLE) + if (ws->weapon != WEAP_SNIPER_RIFLE) self.owner.reload_clipsize += 1; else self.owner.reload_sniper_ticks += 1; @@ -273,14 +268,15 @@ static void FOT_ReloadTimer() { } float FO_CanReload(float weapon) { - FO_WeapInfo wi; - FO_FillWeapInfo(self, weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, weapon, &ws); + FO_WeapInfo* wi = ws->wi; if (wi->ammo_type == AMMO_NONE) return FALSE; - if (wi->needs_reload && *wi->clip_fired > 0 - && *wi->ammo_remaining > wi->ammo_per_shot) + if (wi->needs_reload && *ws->clip_fired > 0 + && *ws->ammo_remaining > wi->ammo_per_shot) return TRUE; return FALSE; @@ -288,11 +284,12 @@ float FO_CanReload(float weapon) { void () TeamFortress_ForceReloadCurrentWeapon; float FO_CheckForReload() { - FO_WeapInfo wi; - FO_FillWeapInfo(self, self.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, self.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; - if (wi->needs_reload && *wi->clip_fired >= wi->clip_size && - *wi->ammo_remaining > 0) { + if (wi->needs_reload && *ws->clip_fired >= wi->clip_size && + *ws->ammo_remaining > 0) { if (force_reload) TeamFortress_ForceReloadCurrentWeapon(); return TRUE; @@ -306,25 +303,27 @@ void FO_ReloadWeapon(float weapon, float force) { if (self.tfstate & TFSTATE_RELOADING) return; - FO_WeapInfo wi; - FO_FillWeapInfo(self, weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, weapon, &ws); + FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) return; string msg = string_null; - if (*wi->clip_fired == 0) + if (*ws->clip_fired == 0) msg = "Clip full\n"; - else if (*wi->ammo_remaining == 0) + else if (*ws->ammo_remaining == 0) msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); - else if (wi->clip_size - *wi->clip_fired == *wi->ammo_remaining) + else if (wi->clip_size - *ws->clip_fired == *ws->ammo_remaining) msg = strcat("All ", AMMO_to_s[wi->ammo_type], "are in the clip\n"); if (msg != string_null) { sprint(self, PRINT_HIGH, msg); return; } else { - sprint(self, PRINT_HIGH, strcat("Reloading ", wi->name, "...\n")); + sprint(self, PRINT_HIGH, strcat("Reloading ", + FO_GetWeapName(ws->weapon), "...\n")); } Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. @@ -334,11 +333,11 @@ void FO_ReloadWeapon(float weapon, float force) { self.tfstate |= TFSTATE_RELOADING; Status_Refresh(self); - float reload_count = min(*wi->clip_fired, *wi->ammo_remaining); + float reload_count = min(*ws->clip_fired, *ws->ammo_remaining); float reload_duration = (reload_count / wi->clip_size) * wi->full_reload_time; - *wi->clip_fired -= reload_count; + *ws->clip_fired -= reload_count; // Sets up for status bar. self.reload_time = time + reload_duration; @@ -365,7 +364,54 @@ void FO_ReloadWeapon(float weapon, float force) { reload_timer.nextthink = client_time() + self.reload_tick; } + +void FO_InstantReloadAllWeapons(entity player) { + player.tfstate &= ~TFSTATE_RELOADING; + player.reload_shotgun = 0; + player.reload_super_shotgun = 0; + player.reload_grenade_launcher = 0; + player.reload_rocket_launcher = 0; + player.reload_sniper_rifle = 0; + player.reload_assault_cannon = 0; +} #endif void FO_Weapons_Init() { + float i, j; + + if (weapon_names.length != weapon_info.length) + error("Weapon Names/Weapon Info inconsistency\n"); + + FO_WeapInfo* WI_ac = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + WI_ac->clip_size = fo_hwguy ? PC_HVYWEAP_ASSCAN_CLIPSIZE : 0; + FO_WeapInfo* WI_sr = FO_GetWeapInfo(WEAP_SNIPER_RIFLE); + WI_sr->clip_size = sniperreload ? 1 : 0; + + FO_WeapInfo* WI_ir = FO_GetWeapInfo(WEAP_INCENDIARY); + switch (pyro_type) { + case PYRO_ORIGINAL: WI_ir->attack_time = 1.2; break; + case PYRO_OZTF: + case PYRO_FO: + default: + WI_ir->attack_time = 0.9; break; + } + + for (i = 0; i < weapon_info.length; i++) { + FO_WeapInfo* wi = &weapon_info[i]; + if (WEAP_to_index(wi->weapon) != i) + error(sprintf("Mismatch at index %d\n", i)); + + wi->needs_reload = wi->clip_size > 0; + } + + for (i = 0; i < class_weapons.length; i++) { + for (j = 0; j < 4; j++) { + FO_ClassWeapons* cw = &class_weapons[i]; + + if (cw->slots[j]) + cw->info[j] = &weap_info_by_index[WEAP_to_index(cw->slots[j])]; + else + cw->info[j] = __NULL__; + } + } } diff --git a/ssqc/status.qc b/ssqc/status.qc index 1e2f383a..8729cf1e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -752,8 +752,7 @@ string GetSBClipString(entity pl, float csqcactive) string msg = ""; if (pl.tfstate & TFSTATE_RELOADING) { - FO_WeapInfo wi; - FO_FillWeapInfo(pl, pl.current_weapon, &wi); + FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); @@ -1333,15 +1332,16 @@ string(float num) GreenScoreToString = string(entity pl, float csqcactive) ClipSizeToString = { - FO_WeapInfo wi; - FO_FillWeapInfo(pl, pl.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(pl, pl.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) return ""; - if (wi->clip_size - *wi->clip_fired > *wi->ammo_remaining) - *wi->clip_fired = wi->clip_size - *wi->ammo_remaining; - float rem = min(wi->clip_size - *wi->clip_fired, 999); + if (wi->clip_size - *ws->clip_fired > *ws->ammo_remaining) + *ws->clip_fired = wi->clip_size - *ws->ammo_remaining; + float rem = min(wi->clip_size - *ws->clip_fired, 999); string st = ""; if (csqcactive) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 70492d4d..11b59ff9 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1864,8 +1864,9 @@ void () player_medikit1; void () player_medikitb1; void () W_Attack = { - FO_WeapInfo wi; - FO_FillWeapInfo(self, self.current_weapon, &wi); + FO_WeapState ws; + FO_FillWeapState(self, self.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; float r; if (self.has_disconnected == TRUE) @@ -1879,7 +1880,7 @@ void () W_Attack = { // Out of ammo? if (wi->ammo_type != AMMO_NONE && - *wi->ammo_remaining < wi->ammo_per_shot) { + *ws->ammo_remaining < wi->ammo_per_shot) { W_ChangeToBestWeapon(); return; } From 7d27109c1be44e2c0f46c5e0b46cfb91b7cf09e3 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 16:46:35 -0700 Subject: [PATCH 1736/2474] Eliminate reload_ spaghetti step 1. Migrates all references to reload_ types to be internal to our new implementation and with FO_WeapState to indirect. --- ssqc/client.qc | 8 +--- ssqc/hwguy.qc | 7 +++- ssqc/tfortmap.qc | 107 ++++++++++++++++------------------------------- ssqc/weapons.qc | 17 ++++---- 4 files changed, 52 insertions(+), 87 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 2a46e9cf..07d2579b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2098,13 +2098,7 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; - self.reload_shotgun = 0; - self.reload_super_shotgun = 0; - self.reload_grenade_launcher = 0; - self.reload_rocket_launcher = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RELOADING); - self.reload_sniper_rifle = 0; - self.reload_assault_cannon = 0; + FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; self.fire_held_down = 0; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index e6e0550b..174debaa 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -113,10 +113,15 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) void FireAssCan (float shotcount, vector dir, vector spread) { - self.reload_assault_cannon = self.reload_assault_cannon + 1; + FO_WeapState ws; + FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + + Status_Refresh(self); FO_CheckForReload(); + *ws->clip_fired += 1; + vector bullet_dir, spread_dir, rand_dir, org; float bullet_speed, var_speed; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 47c37a3f..158f8d2d 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -834,74 +834,44 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack; //refill the clip if stock_reload is 2 if (stock_reload == 2) { - if(Goal.ammo_shells) { - if(Player.current_weapon == WEAP_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); - if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); - if(Player.current_weapon == WEAP_SNIPER_RIFLE) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); - - if(Player.current_weapon == WEAP_ASSAULT_CANNON) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_assault_cannon = max(Player.reload_assault_cannon - Goal.ammo_shells, 0); - } - if(Goal.ammo_rockets) { - if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); - if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); + FO_WeapState ws; + FO_FillWeapState(Player, Player.current_weapon, &ws); + FO_WeapInfo* wi = ws->wi; + + + float* ammo_ptr = __NULL__; + if (Goal.ammo_shells && wi->ammo_type == AMMO_SHELLS) + ammo_ptr = &Goal.ammo_shells; + else if (Goal.ammo_rockets && wi->ammo_type == AMMO_ROCKETS) + ammo_ptr = &Goal.ammo_rockets; + else if (Goal.ammo_cells && wi->ammo_type == AMMO_CELLS) + ammo_ptr = &Goal.ammo_cells; + else if (Goal.ammo_cells && wi->ammo_type == AMMO_NAILS) + ammo_ptr = &Goal.ammo_nails; + + if (wi->needs_reload && ammo_ptr != __NULL__) { + Player.tfstate &= ~TFSTATE_RELOADING; + *ws->clip_fired = max(*ws->clip_fired - *ammo_ptr, 0); } } else { //for use in map entities without specifically enabling the general override - if(Goal.reload_shotgun) { - if(Player.current_weapon == WEAP_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_shotgun = max(Player.reload_shotgun - Goal.ammo_shells, 0); - } - if(Goal.reload_super_shotgun) { - if(Player.current_weapon == WEAP_SUPER_SHOTGUN) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_super_shotgun = max(Player.reload_super_shotgun - Goal.ammo_shells, 0); - } - if(Goal.reload_sniper_rifle) { - if(Player.current_weapon == WEAP_SNIPER_RIFLE) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_sniper_rifle = max(Player.reload_sniper_rifle - Goal.ammo_shells, 0); - } - if(Goal.reload_grenade_launcher) { - if(Player.current_weapon == WEAP_GRENADE_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_grenade_launcher = max(Player.reload_grenade_launcher - Goal.ammo_rockets, 0); + FO_WeapState ws; + FO_FillWeapState(Player, Player.current_weapon, &ws); + + if ((Goal.reload_shotgun && ws.weapon == WEAP_SHOTGUN) || + (Goal.reload_super_shotgun && ws.weapon == WEAP_SUPER_SHOTGUN) || + (Goal.reload_sniper_rifle && ws.weapon == WEAP_SNIPER_RIFLE) || + (Goal.reload_assault_cannon && ws.weapon == WEAP_ASSAULT_CANNON)) { + Player.tfstate &= ~TFSTATE_RELOADING; + *ws->clip_fired = max(*ws->clip_fired - Goal.ammo_shells, 0); } - if(Goal.reload_rocket_launcher) { - if(Player.current_weapon == WEAP_ROCKET_LAUNCHER) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_rocket_launcher = max(Player.reload_rocket_launcher - Goal.ammo_rockets, 0); + + if ((Goal.reload_grenade_launcher && ws.weapon == WEAP_GRENADE_LAUNCHER) || + (Goal.reload_rocket_launcher && ws.weapon == WEAP_ROCKET_LAUNCHER)) { + Player.tfstate &= ~TFSTATE_RELOADING; + *ws->clip_fired = max(*ws->clip_fired - Goal.ammo_rockets, 0); } - if (Goal.reload_assault_cannon) - { - if(Player.current_weapon == WEAP_ASSAULT_CANNON) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - } - Player.reload_assault_cannon = max(Player.reload_assault_cannon - Goal.ammo_shells, 0); - } + } Player.no_grenades_1 = Player.no_grenades_1 + Goal.no_grenades_1; @@ -1057,15 +1027,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { dremove(te); } //Refill the clip while restocking - if (stock_reload) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RELOADING); - Player.reload_shotgun = 0; - Player.reload_super_shotgun = 0; - Player.reload_grenade_launcher = 0; - Player.reload_rocket_launcher = 0; - Player.reload_sniper_rifle = 0; - Player.reload_assault_cannon = 0; - } + if (stock_reload) + FO_InstantReloadAllWeapons(Player); } } } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 11b59ff9..362b9030 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1864,10 +1864,10 @@ void () player_medikit1; void () player_medikitb1; void () W_Attack = { + float r; FO_WeapState ws; FO_FillWeapState(self, self.current_weapon, &ws); FO_WeapInfo* wi = ws->wi; - float r; if (self.has_disconnected == TRUE) return; @@ -1888,6 +1888,12 @@ void () W_Attack = { if (FO_CheckForReload()) return; + if (wi->needs_reload) { + if (FO_CheckForReload()) + return; + *ws->clip_fired += wi->ammo_per_shot; + } + if ((self.is_undercover || (self.undercover_team != 0)) || (self.undercover_skin != 0)) Spy_RemoveDisguise(self); @@ -1915,12 +1921,10 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_SHOTGUN) { player_shot1(); W_FireShotgun(); - self.reload_shotgun = self.reload_shotgun + 1; Status_Refresh(self); } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { player_shot1(); W_FireSuperShotgun(); - self.reload_super_shotgun = self.reload_super_shotgun + 2; Status_Refresh(self); } else if (self.current_weapon == WEAP_NAILGUN) { player_nail1(); @@ -1929,12 +1933,10 @@ void () W_Attack = { } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { player_rocket1(); W_FireGrenade(); - self.reload_grenade_launcher = self.reload_grenade_launcher + 1; Status_Refresh(self); } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { player_rocket1(); W_FireRocket(); - self.reload_rocket_launcher = self.reload_rocket_launcher + 1; Status_Refresh(self); } else if (self.current_weapon == WEAP_LIGHTNING) { player_light1(); @@ -1944,7 +1946,6 @@ void () W_Attack = { player_shot1(); W_FireSniperRifle(); if (sniperreload) { - self.reload_sniper_rifle = self.reload_sniper_rifle + 1; Status_Refresh(self); } } @@ -2003,8 +2004,10 @@ void () W_Attack = { if (self.current_weapon != WEAP_FLAMETHROWER) Attack_Finished(wi->attack_time); - if (wi->needs_reload) + if (wi->needs_reload) { + *ws->clip_fired += wi->ammo_per_shot; FO_CheckForReload(); + } //These weapons have to log each projectile launched/bullet fired if (self.current_weapon != WEAP_ASSAULT_CANNON || From 0be45c1f0fc62309393c857118feb9490e04388c Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 13:57:20 -0700 Subject: [PATCH 1737/2474] Migrate clip state to be allocated and referenced rather than having bespoke per-weapon clip allocations. Weapons with clips have storage/tracking automatically allocated and performed. --- share/fo_weapons.qc | 76 +++++++++++++++++++++++++-------------------- ssqc/weapons.qc | 7 +---- 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index bf761eb4..22c98c09 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -55,6 +55,7 @@ struct FO_WeapInfo { // Fields below this are automatically initialized by Init. Do not include // in table. float needs_reload; + int storage_index; // Allocated by init }; // REQUIRES: weapon at index i == WEAP_to_index(weap) @@ -119,20 +120,6 @@ inline string FO_GetWeapName(float weapon) { return weapon_names[WEAP_to_index(weapon)]; } -struct FO_WeapState { - float weapon; - - // Constant and relative to weapon. TODO, migrate similar to WeapInfo. - FO_WeapInfo* wi; - string model[2]; // indexed by weaponmode - - /* These are relative to the player passed. */ - float* ammo_remaining; - float* clip_fired; -}; - -struct FO_WeapInfo weap_info_by_index[32]; - // REQUIRES: Order must match above. static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; @@ -155,9 +142,32 @@ float WEAP_to_slot(float class, float weapon) { return -1; } +// Internal clip storage for both SSQC/CSQC. +#define CLIP_STORAGE_SIZE 8 +.float clip_fired[CLIP_STORAGE_SIZE]; + +#ifdef SSQC +struct FO_WeapState { + float weapon; + + // Constant and relative to weapon. TODO, migrate similar to WeapInfo. + FO_WeapInfo* wi; + string model[2]; // indexed by weaponmode + + /* These are relative to the player passed. */ + float* ammo_remaining; + float* clip_fired; +}; + + void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { ws->weapon = weapon; - ws->wi = FO_GetWeapInfo(weapon); + FO_WeapInfo* wi = FO_GetWeapInfo(weapon); + ws->wi = wi; + + if (wi->needs_reload) + ws->clip_fired = &player.clip_fired[wi->storage_index]; + ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); switch (weapon) { /* NONE */ @@ -180,16 +190,12 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { /* SHELLS */ case WEAP_SHOTGUN: ws->model[0] = "progs/v_shot.mdl"; - ws->clip_fired = &player.reload_shotgun; break; case WEAP_SUPER_SHOTGUN: ws->model[0] = "progs/v_shot2.mdl"; - ws->clip_fired = &player.reload_super_shotgun; break; case WEAP_SNIPER_RIFLE: ws->model[0] = "progs/v_srifle.mdl"; - if (sniperreload) - ws->clip_fired = &player.reload_sniper_rifle; break; case WEAP_AUTO_RIFLE: ws->model[0] = "progs/v_srifle.mdl"; @@ -199,7 +205,6 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { break; case WEAP_ASSAULT_CANNON: ws->model[0] = "progs/v_asscan.mdl"; - ws->clip_fired = &player.reload_assault_cannon; break; /* NAILS */ case WEAP_NAILGUN: @@ -215,11 +220,9 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { case WEAP_GRENADE_LAUNCHER: ws->model[0] = "progs/v_rock.mdl"; ws->model[1] = "progs/v_pipe.mdl"; - ws->clip_fired = &player.reload_grenade_launcher; break; case WEAP_ROCKET_LAUNCHER: ws->model[0] = "progs/v_rock2.mdl"; - ws->clip_fired = &player.reload_rocket_launcher; break; case WEAP_INCENDIARY: ws->model[0] = "progs/v_irock.mdl"; @@ -234,11 +237,8 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { default: error(sprintf("ID=%d should never be invoked\n", weapon)); } - - ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); } -#ifdef SSQC void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; void (entity pl, float swap) W_WeaponState_Load; @@ -367,12 +367,8 @@ void FO_ReloadWeapon(float weapon, float force) { void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; - player.reload_shotgun = 0; - player.reload_super_shotgun = 0; - player.reload_grenade_launcher = 0; - player.reload_rocket_launcher = 0; - player.reload_sniper_rifle = 0; - player.reload_assault_cannon = 0; + for (int i = 0; i < CLIP_STORAGE_SIZE; i++) + player.clip_fired[i] = 0; } #endif @@ -396,20 +392,34 @@ void FO_Weapons_Init() { WI_ir->attack_time = 0.9; break; } + float clips_allocated = 0; for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; if (WEAP_to_index(wi->weapon) != i) error(sprintf("Mismatch at index %d\n", i)); - wi->needs_reload = wi->clip_size > 0; + + if (wi->clip_size > 0) { + if (wi->clip_size > 0) + wi->needs_reload = TRUE; + // We always allocate a storage index for something that can have + // reload to save negotiating between client and server around + // localinfo tunables. + wi->storage_index = clips_allocated++; + } else { + wi->needs_reload = FALSE; + wi->storage_index = -1; // Make sure we'll OOB. + } } + if (clips_allocated > CLIP_STORAGE_SIZE) + error("Insufficient clip storage"); for (i = 0; i < class_weapons.length; i++) { for (j = 0; j < 4; j++) { FO_ClassWeapons* cw = &class_weapons[i]; if (cw->slots[j]) - cw->info[j] = &weap_info_by_index[WEAP_to_index(cw->slots[j])]; + cw->info[j] = &weapon_info[WEAP_to_index(cw->slots[j])]; else cw->info[j] = __NULL__; } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 362b9030..e5da4b83 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1884,16 +1884,11 @@ void () W_Attack = { W_ChangeToBestWeapon(); return; } + // Fired into forced reload? if (FO_CheckForReload()) return; - if (wi->needs_reload) { - if (FO_CheckForReload()) - return; - *ws->clip_fired += wi->ammo_per_shot; - } - if ((self.is_undercover || (self.undercover_team != 0)) || (self.undercover_skin != 0)) Spy_RemoveDisguise(self); From 8f6417e7001be29c99a65675b951d21fd41e784f Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 03:28:06 -0700 Subject: [PATCH 1738/2474] Move models out of WeapState We'll put them somewhere better in another patch, but now that we've gotten everything to tables they're the last wart standing. --- share/fo_weapons.qc | 109 +++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 71 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 22c98c09..bd5ca92e 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -44,6 +44,8 @@ enum AmmoType { AMMO_NUM_TYPES = AMMO_ROCKETS + 1, }; +struct FO_WeapModels; + struct FO_WeapInfo { int weapon; // Verification AmmoType ammo_type; @@ -56,6 +58,7 @@ struct FO_WeapInfo { // in table. float needs_reload; int storage_index; // Allocated by init + FO_WeapModels* models; }; // REQUIRES: weapon at index i == WEAP_to_index(weap) @@ -120,6 +123,34 @@ inline string FO_GetWeapName(float weapon) { return weapon_names[WEAP_to_index(weapon)]; } +struct FO_WeapModels { + string mode[2]; +}; + +// Indexed by WEAP_to_index() and player.weaponmode +static FO_WeapModels weapon_models[] = { +/* WEAP_HOOK, */ {{"progs/v_grap.mdl" }}, +/* WEAP_KNIFE, */ {{"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, +/* WEAP_MEDIKIT, */ {{"progs/v_medi.mdl"}}, +/* WEAP_SPANNER, */ {{"progs/v_span.mdl"}}, +/* WEAP_AXE, */ {{"progs/v_axe.mdl"}}, +/* WEAP_SNIPER_RIFLE, */ {{"progs/v_srifle.mdl"}}, +/* WEAP_AUTO_RIFLE, */ {{"progs/v_srifle.mdl"}}, +/* WEAP_SHOTGUN, */ {{"progs/v_shot.mdl"}}, +/* WEAP_SUPER_SHOTGUN, */ {{"progs/v_shot2.mdl"}}, +/* WEAP_NAILGUN, */ {{"progs/v_nail.mdl"}}, +/* WEAP_SUPER_NAILGUN, */ {{"progs/v_nail2.mdl"}}, +/* WEAP_GRENADE_LAUNCHER, */ {{"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, +/* WEAP_FLAMETHROWER, */ {{"progs/v_flame.mdl"}}, +/* WEAP_ROCKET_LAUNCHER, */ {{"progs/v_rock2.mdl"}}, +/* WEAP_INCENDIARY, */ {{"progs/v_irock.mdl"}}, +/* WEAP_ASSAULT_CANNON, */ {{"progs/v_asscan.mdl"}}, +/* WEAP_LIGHTNING, */ {{}}, +/* WEAP_DETPACK, */ {{}}, +/* WEAP_TRANQ, */ {{"progs/v_tranq.mdl"}}, +/* WEAP_RAILGUN, */ {{"progs/v_rail.mdl"}}, +}; + // REQUIRES: Order must match above. static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; @@ -152,7 +183,6 @@ struct FO_WeapState { // Constant and relative to weapon. TODO, migrate similar to WeapInfo. FO_WeapInfo* wi; - string model[2]; // indexed by weaponmode /* These are relative to the player passed. */ float* ammo_remaining; @@ -168,75 +198,6 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { if (wi->needs_reload) ws->clip_fired = &player.clip_fired[wi->storage_index]; ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); - - switch (weapon) { - /* NONE */ - case WEAP_HOOK: - ws->model[0] = "progs/v_grap.mdl"; - break; - case WEAP_KNIFE: - ws->model[0] = "progs/v_knife.mdl"; - ws->model[1] = "progs/v_knife2.mdl"; - break; - case WEAP_MEDIKIT: - ws->model[0] = "progs/v_medi.mdl"; - break; - case WEAP_SPANNER: - ws->model[0] = "progs/v_spanner.mdl"; - break; - case WEAP_AXE: - ws->model[0] = "progs/v_axe.mdl"; - break; - /* SHELLS */ - case WEAP_SHOTGUN: - ws->model[0] = "progs/v_shot.mdl"; - break; - case WEAP_SUPER_SHOTGUN: - ws->model[0] = "progs/v_shot2.mdl"; - break; - case WEAP_SNIPER_RIFLE: - ws->model[0] = "progs/v_srifle.mdl"; - break; - case WEAP_AUTO_RIFLE: - ws->model[0] = "progs/v_srifle.mdl"; - break; - case WEAP_TRANQ: - ws->model[0] = "progs/v_tranq.mdl"; - break; - case WEAP_ASSAULT_CANNON: - ws->model[0] = "progs/v_asscan.mdl"; - break; - /* NAILS */ - case WEAP_NAILGUN: - ws->model[0] = "progs/v_nail.mdl"; - break; - case WEAP_SUPER_NAILGUN: - ws->model[0] = "progs/v_nail2.mdl"; - break; - case WEAP_RAILGUN: - ws->model[0] = "progs/v_rail.mdl"; - break; - /* ROCKETS */ - case WEAP_GRENADE_LAUNCHER: - ws->model[0] = "progs/v_rock.mdl"; - ws->model[1] = "progs/v_pipe.mdl"; - break; - case WEAP_ROCKET_LAUNCHER: - ws->model[0] = "progs/v_rock2.mdl"; - break; - case WEAP_INCENDIARY: - ws->model[0] = "progs/v_irock.mdl"; - break; - /* CELLS */ - case WEAP_FLAMETHROWER: - ws->model[0] = "progs/v_flame.mdl"; - break; - /* NOT USED */ - case WEAP_LIGHTNING: - case WEAP_DETPACK: - default: - error(sprintf("ID=%d should never be invoked\n", weapon)); - } } void () RestoreDefaultWeapon; @@ -251,7 +212,7 @@ static void FOT_ReloadTimer() { if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = ws->model[self.owner.weaponmode]; + self.owner.weaponmodel = ((ws->wi)->models)->mode[self.owner.weaponmode]; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); @@ -410,6 +371,12 @@ void FO_Weapons_Init() { wi->needs_reload = FALSE; wi->storage_index = -1; // Make sure we'll OOB. } + + FO_WeapModels* wm = &weapon_models[i]; + for (j = 0; j < 2; j++) + if (wm->mode[j] != "") + precache_model(wm->mode[j]); + wi->models = wm; } if (clips_allocated > CLIP_STORAGE_SIZE) error("Insufficient clip storage"); From dba6bf5c69a2b84a6ecbf6eb6a1ed5ee9000b666 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 15:11:18 -0700 Subject: [PATCH 1739/2474] Add WEAP_NONE There are a few cases where there's no weapon (e.g. setting detpack) add WEAP_NONE to handle this properly. --- share/defs.h | 1 + share/fo_weapons.qc | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/share/defs.h b/share/defs.h index fef62997..b78b7ea4 100644 --- a/share/defs.h +++ b/share/defs.h @@ -704,6 +704,7 @@ /* New Weapon Defines */ /*======================================================*/ +#define WEAP_NONE 0 enumflags { WEAP_HOOK, WEAP_KNIFE, diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index bd5ca92e..f29409f3 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -32,7 +32,7 @@ static float WEAP_to_index(float weapon) { index += 6; } } - return index - 1; // Want zero-offset. + return index; } enum AmmoType { @@ -64,6 +64,7 @@ struct FO_WeapInfo { // REQUIRES: weapon at index i == WEAP_to_index(weap) // -ve values are placeholders signifying conditional init based on game modes. FO_WeapInfo weapon_info[] = { + { WEAP_NONE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_MEDIKIT, AMMO_NONE, 0, 0, 0.5, 0 }, @@ -81,7 +82,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0, 4 }, { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, - { WEAP_DETPACK, AMMO_NONE, 0, 0, -1, 0 }, + { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, }; @@ -113,10 +114,11 @@ inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { - "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", "Sniper Rifle", - "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", "Grenade Launcher", - "Flamethrower", "Rocket Launcher", "Incendiary Launcher", "Assault Cannon", - "Lightning Gun", "Detpack", "Tranquilizer", "Railgun" + "None", "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", + "Sniper Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", + "Grenade Launcher", "Flamethrower", "Rocket Launcher", + "Incendiary Launcher", "Assault Cannon", "Lightning Gun", "Detpack", + "Tranquilizer", "Railgun" }; inline string FO_GetWeapName(float weapon) { @@ -156,13 +158,14 @@ static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; static float* AMMO_to_p(entity player, AmmoType ammo_type) { switch (ammo_type) { - case AMMO_NONE: return __NULL__; case AMMO_SHELLS: return &player.ammo_shells; case AMMO_CELLS: return &player.ammo_cells; case AMMO_NAILS: return &player.ammo_nails; case AMMO_ROCKETS: return &player.ammo_rockets; + default: + case AMMO_NONE: + return __NULL__; } - error(sprintf("UNK AMMO_TYPE=%d\n", ammo_type)); return __NULL__; } @@ -361,8 +364,7 @@ void FO_Weapons_Init() { if (wi->clip_size > 0) { - if (wi->clip_size > 0) - wi->needs_reload = TRUE; + wi->needs_reload = TRUE; // We always allocate a storage index for something that can have // reload to save negotiating between client and server around // localinfo tunables. From 6024cbbfe44e03a0b591c74fc9e7357cdb306147 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 16:15:06 -0700 Subject: [PATCH 1740/2474] Add WEAP_NONE placeholders to other tables --- share/fo_weapons.qc | 47 ++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index f29409f3..140f1d01 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -126,31 +126,33 @@ inline string FO_GetWeapName(float weapon) { } struct FO_WeapModels { + int weapon; string mode[2]; }; // Indexed by WEAP_to_index() and player.weaponmode static FO_WeapModels weapon_models[] = { -/* WEAP_HOOK, */ {{"progs/v_grap.mdl" }}, -/* WEAP_KNIFE, */ {{"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, -/* WEAP_MEDIKIT, */ {{"progs/v_medi.mdl"}}, -/* WEAP_SPANNER, */ {{"progs/v_span.mdl"}}, -/* WEAP_AXE, */ {{"progs/v_axe.mdl"}}, -/* WEAP_SNIPER_RIFLE, */ {{"progs/v_srifle.mdl"}}, -/* WEAP_AUTO_RIFLE, */ {{"progs/v_srifle.mdl"}}, -/* WEAP_SHOTGUN, */ {{"progs/v_shot.mdl"}}, -/* WEAP_SUPER_SHOTGUN, */ {{"progs/v_shot2.mdl"}}, -/* WEAP_NAILGUN, */ {{"progs/v_nail.mdl"}}, -/* WEAP_SUPER_NAILGUN, */ {{"progs/v_nail2.mdl"}}, -/* WEAP_GRENADE_LAUNCHER, */ {{"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, -/* WEAP_FLAMETHROWER, */ {{"progs/v_flame.mdl"}}, -/* WEAP_ROCKET_LAUNCHER, */ {{"progs/v_rock2.mdl"}}, -/* WEAP_INCENDIARY, */ {{"progs/v_irock.mdl"}}, -/* WEAP_ASSAULT_CANNON, */ {{"progs/v_asscan.mdl"}}, -/* WEAP_LIGHTNING, */ {{}}, -/* WEAP_DETPACK, */ {{}}, -/* WEAP_TRANQ, */ {{"progs/v_tranq.mdl"}}, -/* WEAP_RAILGUN, */ {{"progs/v_rail.mdl"}}, + { WEAP_NONE, {""}}, + { WEAP_HOOK, {"progs/v_grap.mdl" }}, + { WEAP_KNIFE, {"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, + { WEAP_MEDIKIT, {"progs/v_medi.mdl"}}, + { WEAP_SPANNER, {"progs/v_span.mdl"}}, + { WEAP_AXE, {"progs/v_axe.mdl"}}, + { WEAP_SNIPER_RIFLE, {"progs/v_srifle.mdl"}}, + { WEAP_AUTO_RIFLE, {"progs/v_srifle.mdl"}}, + { WEAP_SHOTGUN, {"progs/v_shot.mdl"}}, + { WEAP_SUPER_SHOTGUN, {"progs/v_shot2.mdl"}}, + { WEAP_NAILGUN, {"progs/v_nail.mdl"}}, + { WEAP_SUPER_NAILGUN, {"progs/v_nail2.mdl"}}, + { WEAP_GRENADE_LAUNCHER, {"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, + { WEAP_FLAMETHROWER, {"progs/v_flame.mdl"}}, + { WEAP_ROCKET_LAUNCHER, {"progs/v_rock2.mdl"}}, + { WEAP_INCENDIARY, {"progs/v_irock.mdl"}}, + { WEAP_ASSAULT_CANNON, {"progs/v_asscan.mdl"}}, + { WEAP_LIGHTNING, {""}}, + { WEAP_DETPACK, {""}}, + { WEAP_TRANQ, {"progs/v_tranq.mdl"}}, + { WEAP_RAILGUN, {"progs/v_rail.mdl"}}, }; // REQUIRES: Order must match above. @@ -360,8 +362,7 @@ void FO_Weapons_Init() { for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; if (WEAP_to_index(wi->weapon) != i) - error(sprintf("Mismatch at index %d\n", i)); - + error(sprintf("WI mismatch at index %d\n", i)); if (wi->clip_size > 0) { wi->needs_reload = TRUE; @@ -375,6 +376,8 @@ void FO_Weapons_Init() { } FO_WeapModels* wm = &weapon_models[i]; + if (WEAP_to_index(wm->weapon) != i) + error(sprintf("WM mismatch at index %d\n", i)); for (j = 0; j < 2; j++) if (wm->mode[j] != "") precache_model(wm->mode[j]); From 858159498719d92f1d952af5bdff677f45eabf43 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 13:39:50 -0700 Subject: [PATCH 1741/2474] Remove old medikit Adds complexity no longer worth maintaining. --- ssqc/actions.qc | 13 ++----------- ssqc/client.qc | 5 ----- ssqc/engineer.qc | 3 --- ssqc/medic.qc | 14 +++----------- ssqc/qw.qc | 1 - ssqc/tfort.qc | 1 - ssqc/weapons.qc | 39 +++------------------------------------ 7 files changed, 8 insertions(+), 68 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 21e773ba..ce0a410e 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -34,14 +34,8 @@ void () TeamFortress_Discard = { break; case PC_MEDIC: newmis.ammo_rockets = self.ammo_rockets; - if (!medicaura && old_medikit) { - newmis.ammo_cells = self.ammo_cells; - } - else - { - if(c > 0) - newmis.ammo_cells = c; - } + if(c > 0) + newmis.ammo_cells = c; break; case PC_SNIPER: newmis.ammo_rockets = self.ammo_rockets; @@ -135,9 +129,6 @@ void () TeamFortress_Discard_DropAmmo = { break; case PC_MEDIC: disc = self.ammo_rockets; - if (!medicaura && old_medikit) { - disc += self.ammo_cells; - } break; case PC_SNIPER: case PC_SPY: diff --git a/ssqc/client.qc b/ssqc/client.qc index 07d2579b..3e613e0c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -483,9 +483,6 @@ void () DecodeLevelParms = { // allow medic aura [on] medicaura = CF_GetSetting("ma", "medicaura", "on"); - // use old tf style medikit (don't insta-heal max+50) [off] - old_medikit = CF_GetSetting("om", "old_medikit", "off"); - // use old tf style bioweapon (less damage) [off] old_biodamage = CF_GetSetting("ob", "old_biodamage", "off"); @@ -867,7 +864,6 @@ void () DecodeLevelParms = { detpipe_limit_world = -1; old_pipecooldown = FALSE; medicaura = TRUE; - old_medikit = FALSE; old_biodamage = FALSE; cannon_lock = TRUE; cannon_air = TRUE; @@ -947,7 +943,6 @@ void () DecodeLevelParms = { detpipe_limit_world = 7; old_pipecooldown = TRUE; medicaura = FALSE; - old_medikit = TRUE; old_biodamage = TRUE; cannon_lock = FALSE; cannon_air = TRUE; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f63b7bdc..a254b3f0 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -261,9 +261,6 @@ void () EMPGrenadeExplode = { break; case PC_MEDIC: expsize = expsize - te.maxammo_rockets * .75 * 2; - if (!medicaura && old_medikit) { - expsize = expsize - te.maxammo_cells * .75; - } break; case PC_SNIPER: case PC_SPY: diff --git a/ssqc/medic.qc b/ssqc/medic.qc index 17dd697b..4e9d5344 100644 --- a/ssqc/medic.qc +++ b/ssqc/medic.qc @@ -73,7 +73,7 @@ void () CF_Medic_AuraFindPlayers = { } self.owner.ammo_cells = self.owner.ammo_cells - ceil(PC_MEDIC_MAXAMMO_CELL / 20); - if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) + if (self.owner.current_weapon == WEAP_MEDIKIT) self.owner.currentammo = self.owner.ammo_cells; }; @@ -83,10 +83,6 @@ void () CF_Medic_RegenerateCells = { local entity oldself; local float f_newcells = self.owner.ammo_cells + min(ceil(PC_MEDIC_MAXAMMO_CELL * (PC_MEDIC_CELL_REGEN_PERCENT / 100)), ceil(PC_MEDIC_MAXAMMO_CELL - self.owner.ammo_cells)); - // don't regenerate cells if not using aura or new medikit - if (!medicaura && old_medikit) - return; - // skip this regen tick if on cooldown if (time <= self.owner.regen_cooldown) { self.nextthink = time + 1; @@ -104,7 +100,7 @@ void () CF_Medic_RegenerateCells = { else if (f_newcells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2) && f_newcells < ceil(PC_MEDIC_MAXAMMO_CELL / 2 + PC_MEDIC_MAXAMMO_CELL / 10)) Status_Refresh(self.owner); - if (self.owner.current_weapon == WEAP_MEDIKIT && !old_medikit) + if (self.owner.current_weapon == WEAP_MEDIKIT) self.owner.currentammo = self.owner.ammo_cells; } @@ -128,11 +124,7 @@ void () CF_Medic_Regenerate = { } // only regen if half of max or more cells with new medikit - if (!old_medikit) { - if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { - return; - } - } else if (self.owner.health >= self.owner.max_health || self.owner.ammo_medikit) { + if (self.owner.health >= self.owner.max_health || self.owner.ammo_cells < ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { return; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index b81e88da..f5c4354e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -568,7 +568,6 @@ float old_sniperrange; float detpipe_limit_world; float old_pipecooldown; float medicaura; -float old_medikit; float old_biodamage; float flame_knockback; float build_water; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 57fcbf05..f8354d90 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -731,7 +731,6 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "\n== Combat Medic ==\n"); CF_PrintSetting("Medic aura ability", medicaura, "", 1); - CF_PrintSetting("Old medikit behaviour", old_medikit, "", 1); CF_PrintSetting("Old bioweapon damage", old_sniperrange, "", 1); sprint(self, PRINT_HIGH, "\n== Heavy Weapons Guy ==\n"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e5da4b83..914586df 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -563,37 +563,7 @@ float () W_FireMedikit = { } return TRUE; } - if (old_medikit) { - - if (healam > 0 && trace_ent.health < trace_ent.max_health) { - - FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); - trace_ent.axhitme = 1; - SpawnBlood(org, 20); - T_Heal(trace_ent, healam, 0); - - } else if (trace_ent.health >= trace_ent.max_health && trace_ent.health < (trace_ent.max_health + 50)) { - - healam = 5; - if (healam > (self.ammo_medikit * 5)) - healam = self.ammo_medikit * 5; - - if (healam > 0) { - FO_Sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM); - T_Heal(trace_ent, healam, 1); - self.ammo_medikit = self.ammo_medikit - rint(healam / 5); - - if (!(trace_ent.items & IT_SUPERHEALTH)) { - trace_ent.items = trace_ent.items | IT_SUPERHEALTH; - newmis = spawn(); - newmis.nextthink = time + 5; - newmis.think = item_megahealth_rot; - newmis.owner = trace_ent; - } - } - } - - } else if (trace_ent.health < (trace_ent.max_health + 50)) { + if (trace_ent.health < (trace_ent.max_health + 50)) { if (self.ammo_cells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2)) { healam = trace_ent.max_health - trace_ent.health + 50; @@ -1722,11 +1692,8 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_MEDIKIT) { - if (!old_medikit) { - pl.currentammo = pl.ammo_cells; - pl.items = pl.items | IT_CELLS; - } else - pl.currentammo = 0; + pl.currentammo = pl.ammo_cells; + pl.items = pl.items | IT_CELLS; pl.weaponmodel = "progs/v_medi.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_TRANQ) { From 3a4aa8f78708136bb6c4a1ecf17bf55c1775a550 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 13:37:25 -0700 Subject: [PATCH 1742/2474] Eliminate currentammo Current ammo is a bit of a kludge that tries to copy the current ammo into a singly named accessor. We have WeapState for this now so we can get rid of it. This also fixes cells not showing up for bioaxe/spanner. --- share/fo_weapons.qc | 4 ++-- ssqc/actions.qc | 1 - ssqc/client.qc | 14 ++++++++++++-- ssqc/defs.qc | 1 - ssqc/demoman.qc | 2 -- ssqc/engineer.qc | 12 ------------ ssqc/items.qc | 5 ----- ssqc/medic.qc | 5 ----- ssqc/menu.qc | 5 ----- ssqc/player.qc | 1 - ssqc/pyro.qc | 5 ----- ssqc/scout.qc | 4 ---- ssqc/spy.qc | 2 -- ssqc/tfort.qc | 5 ----- ssqc/tfortmap.qc | 2 -- ssqc/vote.qc | 2 -- ssqc/weapons.qc | 47 ++++++++------------------------------------- 17 files changed, 22 insertions(+), 95 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 140f1d01..16fe3928 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -67,8 +67,8 @@ FO_WeapInfo weapon_info[] = { { WEAP_NONE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_MEDIKIT, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_SPANNER, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_MEDIKIT, AMMO_CELLS, 0, 0, 0.5, 0 }, + { WEAP_SPANNER, AMMO_CELLS, 0, 0, 0.5, 0 }, { WEAP_AXE, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_SNIPER_RIFLE, AMMO_SHELLS, -9, 1, 1.5, 4 }, { WEAP_AUTO_RIFLE, AMMO_SHELLS, 0, 1, 0.1, 0 }, diff --git a/ssqc/actions.qc b/ssqc/actions.qc index ce0a410e..c973f451 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -86,7 +86,6 @@ void () TeamFortress_Discard = { else self.ammo_cells = 0; } - W_SetCurrentAmmo(self); FO_Sound(self, CHAN_AUTO, "weapons/lock4.wav", 1, ATTN_NORM); newmis.enemy = self; newmis.health = time; diff --git a/ssqc/client.qc b/ssqc/client.qc index 3e613e0c..f813f337 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2192,7 +2192,6 @@ void () PutClientInServer = { stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - W_SetCurrentAmmo(self); if (self.current_weaponslot && self.last_playerclass == self.playerclass) W_ChangeWeapon(self.current_weaponslot); else { @@ -2779,11 +2778,15 @@ void () PlayerPreThink = { if ((time < self.pausetime) || (cease_fire == 1)) { self.velocity = '0 0 0'; } + +#if 0 + FO_WeapState ws; + FO_FillWeapState(self, self.weapon, &ws); if (time > self.attack_finished && !self.currentammo && self.weapon > WEAP_AXE) { W_ChangeWeapon(W_BestWeaponSlot()); - W_SetCurrentAmmo(self); W_WeaponState_Save(self); } +#endif }; void () CheckPowerups = { @@ -2949,11 +2952,18 @@ void () CheckPowerups = { } }; +void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws); + void () PlayerPostThink = { UpdateScoreboardInfo(self); FOPlayer fop = (FOPlayer)self; fop.RewindUpdate(); + FO_WeapState ws; + FO_FillWeapState(self, self.current_weapon, &ws); + self.currentammo = + (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; + if (self.view_ofs == '0 0 0') { return; } diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 86a566c2..66a6410a 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -119,7 +119,6 @@ void end_sys_globals; .float weapon; .string weaponmodel; .float weaponframe; -.float currentammo; .float ammo_shells, ammo_nails, ammo_rockets, ammo_cells; .float items; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 87782c59..954dd26b 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -270,7 +270,6 @@ void () TeamFortress_DetpackStop = { self.current_weapon = self.next_weapon; Status_Refresh(self); - W_SetCurrentAmmo(self); TeamFortress_SetSpeed(self); self.pausetime = time; }; @@ -296,7 +295,6 @@ void () TeamFortress_DetpackSet = { self.is_detpacking = 0; self.current_weapon = self.next_weapon; Status_Refresh(self); - W_SetCurrentAmmo(self); self = oldself; newmis = spawn(); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index a254b3f0..7ea37512 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -82,7 +82,6 @@ void () W_FireLaser = { local vector vec, org; self.ammo_nails = self.ammo_nails - 1; - self.currentammo = self.ammo_nails; makevectors(self.v_angle); org = self.origin + v_forward * 8; @@ -300,7 +299,6 @@ void () EMPGrenadeExplode = { } oldself = self; self = te; - W_SetCurrentAmmo(self); self = oldself; } else { te.think = SUB_Remove; @@ -408,7 +406,6 @@ void () TeamFortress_EngineerBuildStop = { self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_WALK; TeamFortress_SetSpeed(self); - W_SetCurrentAmmo(self); } } @@ -605,7 +602,6 @@ void (float objtobuild) TeamFortress_Build = { newmis.classname = "building_sentrygun"; newmis.weapon = 0; } - W_SetCurrentAmmo(self); } oldmis = newmis; @@ -1023,7 +1019,6 @@ void () TeamFortress_FinishedBuilding = { UpdateClient_Sentry(self, oldself); } } - W_SetCurrentAmmo(self); self = oldself; }; @@ -1105,7 +1100,6 @@ void (entity disp) Engineer_UseDispenser = { ThrowGib("progs/dgib1.mdl", -30); ThrowGib("progs/dgib2.mdl", -50); ThrowGib("progs/dgib3.mdl", -50); - W_SetCurrentAmmo(self); return; } @@ -1115,7 +1109,6 @@ void (entity disp) Engineer_UseDispenser = { self.ammo_cells = self.ammo_cells + ENG_DISPENSER_COST; if (self.ammo_cells > self.maxammo_cells) self.ammo_cells = self.maxammo_cells; - W_SetCurrentAmmo(self); self = disp.real_owner; TeamFortress_EngineerBuildStop(); return; @@ -1190,7 +1183,6 @@ void (entity disp) Engineer_Dispenser_InsertAmmo = { disp.ammo_cells = (disp.ammo_cells + cells); if ((shells + nails + rockets + cells) > 0) { - W_SetCurrentAmmo(self); sprint(self, PRINT_HIGH, "You insert "); if (shells > 0) sprint(self, PRINT_HIGH, ftos(shells), " shells"); @@ -1292,7 +1284,6 @@ void (entity gun) Engineer_UseSentryGun = { self.ammo_cells = self.maxammo_cells; if (gun.trigger_field != world) dremove (gun.trigger_field); - W_SetCurrentAmmo(self); self = gun.real_owner; TeamFortress_EngineerBuildStop(); return; @@ -1311,7 +1302,6 @@ void (entity gun) Engineer_UseSentryGun = { ThrowGib("progs/tgib1.mdl", -30); ThrowGib("progs/tgib2.mdl", -50); ThrowGib("progs/tgib3.mdl", -50); - W_SetCurrentAmmo(self); return; } } @@ -1382,7 +1372,6 @@ void (entity gun) Engineer_SentryGun_InsertAmmo = { } if ((shells + rockets) > 0) { - W_SetCurrentAmmo(self); ammo = "You insert "; if (shells > 0) ammo = strcat(ammo, strcat(ftos(floor(shells)), " shells")); @@ -1483,7 +1472,6 @@ void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { self = eng; self.ammo_cells = self.ammo_cells + 100; bound_other_ammo(self); - W_SetCurrentAmmo(self); self = oldself; } if (te.real_owner.building == te) { diff --git a/ssqc/items.qc b/ssqc/items.qc index 068981c9..a9cfc7d7 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -262,7 +262,6 @@ void () health_touch = { self.think = SUB_regen; } activator = other; - W_SetCurrentAmmo(self); SUB_UseTargets(); } } @@ -398,7 +397,6 @@ void () armor_touch = { } oldself = self; self = other; - W_SetCurrentAmmo(self); self = oldself; } value = other.maxarmor; @@ -644,7 +642,6 @@ void () weapon_touch = { stemp = self; self = other; Deathmatch_Weapon(old, new); - W_SetCurrentAmmo(self); self = stemp; if (leave) return; @@ -879,7 +876,6 @@ void () ammo_touch = { sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); stemp = self; self = other; - W_SetCurrentAmmo(self); self = stemp; } Respawn_Item(self, other); @@ -1347,7 +1343,6 @@ void () BackpackTouch = { stuffcmd(other, "bf\n"); dremove(self); self = other; - W_SetCurrentAmmo(self); }; void () DropBackpack = { diff --git a/ssqc/medic.qc b/ssqc/medic.qc index 4e9d5344..af64b495 100644 --- a/ssqc/medic.qc +++ b/ssqc/medic.qc @@ -73,8 +73,6 @@ void () CF_Medic_AuraFindPlayers = { } self.owner.ammo_cells = self.owner.ammo_cells - ceil(PC_MEDIC_MAXAMMO_CELL / 20); - if (self.owner.current_weapon == WEAP_MEDIKIT) - self.owner.currentammo = self.owner.ammo_cells; }; // increases the medic's cells two times per second @@ -99,9 +97,6 @@ void () CF_Medic_RegenerateCells = { Status_Refresh(self.owner); else if (f_newcells >= ceil(PC_MEDIC_MAXAMMO_CELL / 2) && f_newcells < ceil(PC_MEDIC_MAXAMMO_CELL / 2 + PC_MEDIC_MAXAMMO_CELL / 10)) Status_Refresh(self.owner); - - if (self.owner.current_weapon == WEAP_MEDIKIT) - self.owner.currentammo = self.owner.ammo_cells; } // Update drop ammo menu if cells are diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 7df35e38..c7748ba4 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -52,8 +52,6 @@ void () TeamFortress_EngineerBuildStop; void (entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage; -void (entity pl) W_SetCurrentAmmo; - void (entity p) bound_other_ammo; float (float v) anglemod; @@ -853,7 +851,6 @@ void (float inp) Menu_Engineer_Input = { dremove (te); self.has_sentry = 0; dismantle_sentrygun = 1; - W_SetCurrentAmmo(self); } } te = te.chain; @@ -872,7 +869,6 @@ void (float inp) Menu_Engineer_Input = { dremove (te); self.has_dispenser = 0; dismantle_dispenser = 1; - W_SetCurrentAmmo(self); } } te = te.chain; @@ -1159,7 +1155,6 @@ void (float inp) Menu_Dispenser_Input = { self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)); } - W_SetCurrentAmmo(self); } }; diff --git a/ssqc/player.qc b/ssqc/player.qc index 2adf5b49..ab5940ae 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -573,7 +573,6 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { self.current_weapon = W_BestWeapon(); self.current_weaponslot = W_BestWeaponSlot(); - W_SetCurrentAmmo(self); W_PrintWeaponMessage(); return; } diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index b3a55eca..c09a4c2d 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -548,7 +548,6 @@ void () W_FireFlame = { return; } self.ammo_cells = self.ammo_cells - 1; - self.currentammo = self.ammo_cells; FO_Sound(self, CHAN_AUTO, "weapons/flmfire2.wav", 1, ATTN_NORM); flame = spawn(); flame.owner = self; @@ -673,7 +672,6 @@ void () W_FireIncendiaryCannon = { return; } self.ammo_rockets = self.ammo_rockets - 3; - self.currentammo = self.ammo_rockets; FO_Sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); KickPlayer(-3, self); newmis = spawn(); @@ -722,7 +720,6 @@ void () TeamFortress_IncendiaryCannon = { return; } self.current_weapon = WEAP_INCENDIARY; - W_SetCurrentAmmo(self); }; void () TeamFortress_FlameThrower = { @@ -734,7 +731,6 @@ void () TeamFortress_FlameThrower = { return; } self.current_weapon = WEAP_FLAMETHROWER; - W_SetCurrentAmmo(self); }; void () AirBlastReloadFinished = { @@ -897,7 +893,6 @@ void () UseAirBlastV2 = { } self.ammo_cells = self.ammo_cells - cellcost; - W_SetCurrentAmmo(self); ent = findradius(ab_origin, abrange); while (ent) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 1ef2a762..0d5ce0de 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -564,7 +564,6 @@ void () TeamFortress_Scan = { sprint(self.owner, PRINT_HIGH, "Not enough cells to run scanner\n"); self.owner.ammo_cells = 0; - W_SetCurrentAmmo(self); self.owner.ScannerOn = 0; dremove(self); return; @@ -572,7 +571,6 @@ void () TeamFortress_Scan = { if (scancost > self.owner.ammo_cells) { scanrange = self.owner.ammo_cells * 20; scancost = self.owner.ammo_cells; - W_SetCurrentAmmo(self); } scen = 0; scfr = 0; @@ -592,7 +590,6 @@ void () TeamFortress_Scan = { if (self.owner.ammo_cells < 0) { self.owner.ammo_cells = 0; } - W_SetCurrentAmmo(self); scanrange = scanrange * 25; list = T_RadiusScan(self.owner, scanrange, scen, scfr); } @@ -728,7 +725,6 @@ void () TeamFortress_Scan = { self.nextthink = time + 2; return; } - W_SetCurrentAmmo(self); self.nextthink = time + 2; return; }; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index f4d0197a..a144ca1b 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -604,7 +604,6 @@ void () FO_Spy_Unfeign = { // load saved weapon state and set current ammo W_WeaponState_Load(self, 0); - W_SetCurrentAmmo(self); // allow spy to move again self.movetype = MOVETYPE_WALK; @@ -1381,7 +1380,6 @@ void () HallucinationTimer = { void () W_FireTranq = { self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; KickPlayer(-2, self); newmis = spawn(); newmis.owner = self; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f8354d90..775d6deb 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2326,7 +2326,6 @@ void () TeamFortress_SetEquipment = { else if (self.armortype >= 0.3) self.items = self.items | IT_ARMOR1; - W_SetCurrentAmmo(self); if (self.last_playerclass != self.playerclass) self.current_weaponslot = W_BestWeaponSlot(); }; @@ -2716,7 +2715,6 @@ void (float type, float ammo) TeamFortress_DropAmmo = { } self.ammo_cells = self.ammo_cells - ammo; } - W_SetCurrentAmmo(self); newmis = spawn(); newmis.aflag = ammo; newmis.weapon = type; @@ -2780,7 +2778,6 @@ void () TeamFortress_AmmoboxTouch = { FO_Sound(other, CHAN_AUTO, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); self = other; - W_SetCurrentAmmo(self); return; } else if ((other.playerclass == PC_SCOUT) || (other.playerclass == PC_ENGINEER)) { @@ -2869,7 +2866,6 @@ void () TeamFortress_AmmoboxTouch = { FO_Sound(other, CHAN_ITEM, "weapons/lock4.wav", 1, 1); stuffcmd(other, "bf\n"); self = other; - W_SetCurrentAmmo(self); }; void () TeamFortress_AssaultWeapon = { @@ -2896,7 +2892,6 @@ void () TeamFortress_AssaultWeapon = { return; } self.current_weapon = WEAP_ASSAULT_CANNON; - W_SetCurrentAmmo(self); }; void () TeamFortress_ExplodePerson = { diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 158f8d2d..d2a52987 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1037,7 +1037,6 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { oldself = self; self = Player; TeamFortress_CheckClassStats(); - W_SetCurrentAmmo(self); self = oldself; } if ((Player.playerclass == PC_SPY) && @@ -1239,7 +1238,6 @@ void (entity Goal, entity Player) RemoveResults = { oldself = self; self = Player; TeamFortress_CheckClassStats(); - W_SetCurrentAmmo(self); self = oldself; }; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index fa1c9a1c..235acaa2 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1238,7 +1238,6 @@ void () AnarchyMode = { e.super_damage_finished = time + 666; //e.effects = e.effects | EF_BLUE; } - W_SetCurrentAmmo(e); TeamFortress_SetSpeed(e); e = find(e, classname, "player"); } @@ -1270,7 +1269,6 @@ void () EndVoting = { e.current_weapon = 0; e.super_damage_finished = 0; //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; - W_SetCurrentAmmo(e); TeamFortress_SetSpeed(e); e.health = 100; e = find(e, classname, "player"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 914586df..def0b222 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -135,6 +135,7 @@ float () IsUsingOldImpulses; float () IsUsingCFImpulses; void (float inp) W_OldWeaponSlot; +void (entity pl) W_UpdateCurrentWeapon; void (entity ent, float num) SetFlameCount; @@ -578,9 +579,6 @@ float () W_FireMedikit = { FO_Sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM); } - if (self.current_weapon == WEAP_MEDIKIT) - self.currentammo = self.ammo_cells; - Status_Refresh(self); T_Heal(trace_ent, healam, 1); @@ -809,7 +807,6 @@ void () W_FireShotgun = { KickPlayer(-2, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_SHOTGUN; FireBullets(6, dir, '0.04 0.04 0'); @@ -818,7 +815,7 @@ void () W_FireShotgun = { void () W_FireSuperShotgun = { local vector dir; - if (self.currentammo == 1) { + if (self.ammo_shells == 1) { W_FireShotgun(); return; } @@ -826,7 +823,6 @@ void () W_FireSuperShotgun = { KickPlayer(-4, self); self.ammo_shells = self.ammo_shells - 2; - self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_SSHOTGUN; FireBullets(14, dir, '0.14 0.08 0'); @@ -866,7 +862,6 @@ void () W_FireSniperRifle = { FO_Sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); KickPlayer(-2, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; makevectors(self.v_angle); src = self.origin + v_forward * 10; @@ -968,7 +963,6 @@ void () W_FireAutoRifle = { KickPlayer(-1, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; makevectors(self.v_angle); dir = v_forward; deathmsg = DMSG_AUTORIFLE; @@ -981,7 +975,6 @@ void () W_FireAssaultCannon = { KickPlayer(-4, self); self.ammo_shells = self.ammo_shells - 1; - self.currentammo = self.ammo_shells; dir = aim(self, 100000); deathmsg = DMSG_ASSAULTCANNON; @@ -1105,7 +1098,6 @@ void () T_MissileTouch = { void () W_FireRocket = { self.ammo_rockets = self.ammo_rockets - 1; - self.currentammo = self.ammo_rockets; FO_Sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); KickPlayer(-2, self); @@ -1192,7 +1184,7 @@ void () W_FireLightning = { if (self.waterlevel > 1) { cells = self.ammo_cells; self.ammo_cells = 0; - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); deathmsg = DMSG_LIGHTNING; T_RadiusDamage(self, self, 35 * cells, world); return; @@ -1204,7 +1196,6 @@ void () W_FireLightning = { KickPlayer(-2, self); self.ammo_cells = self.ammo_cells - 1; - self.currentammo = self.ammo_cells; org = self.origin + '0 0 16'; traceline(org, org + v_forward * 600, 1, self); @@ -1309,7 +1300,6 @@ void () ExplodeOldestPipebomb = { void () W_FireGrenade = { self.ammo_rockets = self.ammo_rockets - 1; - self.currentammo = self.ammo_rockets; FO_Sound(self, CHAN_WEAPON, "weapons/grenade.wav", 1, 1); KickPlayer(-2, self); newmis = spawn(); @@ -1394,7 +1384,6 @@ void () W_FireSuperSpikes = { self.ammo_nails = self.ammo_nails - 4; else self.ammo_nails = self.ammo_nails - 2; - self.currentammo = self.ammo_nails; dir = aim(self, 1000); launch_spike(self.origin + '0 0 16', dir); LogEventAttack(self); @@ -1421,10 +1410,8 @@ void (float ox) W_FireSpikes = { FO_Sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); if ((self.ammo_nails == 1) || !old_ng_rof) { self.ammo_nails = self.ammo_nails - 1; - self.currentammo = self.ammo_nails; } else { self.ammo_nails = self.ammo_nails - 2; - self.currentammo = self.ammo_nails; } dir = aim(self, 1000); launch_spike(self.origin + '0 0 16' + v_right * ox, dir); @@ -1573,7 +1560,7 @@ void () superspike_touch = { dremove(self); }; -void (entity pl) W_SetCurrentAmmo = { +void (entity pl) W_UpdateCurrentWeapon = { entity oldself; if ((pl.health <= 0) || (pl.current_weapon == 0)) @@ -1586,22 +1573,18 @@ void (entity pl) W_SetCurrentAmmo = { pl.weapon = 0; if (pl.current_weapon == WEAP_AXE) { - pl.currentammo = 0; pl.weaponmodel = "progs/v_axe.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_KNIFE) { - pl.currentammo = 0; if (pl.weaponmode == 0) pl.weaponmodel = "progs/v_knife.mdl"; else pl.weaponmodel = "progs/v_knife2.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_SPANNER) { - pl.currentammo = pl.ammo_cells; pl.weaponmodel = "progs/v_span.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_SHOTGUN) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_shot.mdl"; pl.weaponframe = 0; @@ -1609,7 +1592,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_shot2.mdl"; pl.weaponframe = 0; @@ -1617,7 +1599,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SUPER_SHOTGUN; } else if (pl.current_weapon == WEAP_NAILGUN) { - pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_nail.mdl"; pl.weaponframe = 0; @@ -1625,7 +1606,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_NAILS; pl.weapon = IT_NAILGUN; } else if (pl.current_weapon == WEAP_SUPER_NAILGUN) { - pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_nail2.mdl"; pl.weaponframe = 0; @@ -1633,7 +1613,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_NAILS; pl.weapon = IT_SUPER_NAILGUN; } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { - pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { if (pl.weaponmode == 0) pl.weaponmodel = "progs/v_rock.mdl"; @@ -1644,7 +1623,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.weapon = IT_GRENADE_LAUNCHER; pl.items = pl.items | IT_ROCKETS; } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { - pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_rock2.mdl"; pl.weaponframe = 0; @@ -1652,7 +1630,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_srifle.mdl"; pl.weaponframe = 0; @@ -1660,7 +1637,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; } else if (pl.current_weapon == WEAP_AUTO_RIFLE) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_srifle.mdl"; pl.weaponframe = 0; @@ -1668,7 +1644,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SUPER_SHOTGUN; } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_asscan.mdl"; pl.weaponframe = 0; @@ -1676,7 +1651,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_FLAMETHROWER) { - pl.currentammo = pl.ammo_cells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_flame.mdl"; pl.weaponframe = 0; @@ -1684,7 +1658,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_CELLS; pl.weapon = IT_GRENADE_LAUNCHER; } else if (pl.current_weapon == WEAP_INCENDIARY) { - pl.currentammo = pl.ammo_rockets; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_irock.mdl"; pl.weaponframe = 0; @@ -1692,12 +1665,10 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_ROCKETS; pl.weapon = IT_ROCKET_LAUNCHER; } else if (pl.current_weapon == WEAP_MEDIKIT) { - pl.currentammo = pl.ammo_cells; pl.items = pl.items | IT_CELLS; pl.weaponmodel = "progs/v_medi.mdl"; pl.weaponframe = 0; } else if (pl.current_weapon == WEAP_TRANQ) { - pl.currentammo = pl.ammo_shells; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_tranq.mdl"; pl.weaponframe = 0; @@ -1705,7 +1676,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_SHELLS; pl.weapon = IT_SHOTGUN; } else if (pl.current_weapon == WEAP_RAILGUN) { - pl.currentammo = pl.ammo_nails; if (!(pl.tfstate & TFSTATE_RELOADING)) { pl.weaponmodel = "progs/v_rail.mdl"; pl.weaponframe = 0; @@ -1713,7 +1683,6 @@ void (entity pl) W_SetCurrentAmmo = { pl.items = pl.items | IT_NAILS; pl.weapon = IT_SHOTGUN; } else { - pl.currentammo = 0; pl.weaponmodel = ""; pl.weaponframe = 0; } @@ -1801,7 +1770,7 @@ void () W_ChangeToBestWeapon = { self.current_weaponslot = slot; self.current_weapon = self.next_weapon; self.weaponmode = self.next_weaponmode; - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); W_WeaponState_Save(self); W_PrintWeaponMessage(); } @@ -1921,7 +1890,7 @@ void () W_Attack = { self.antispam_assault_cannon = time + 3; } W_ChangeWeapon(W_BestWeaponSlot()); - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); W_WeaponState_Save(self); } else { self.ammo_cells = self.ammo_cells - 7; @@ -2582,7 +2551,7 @@ void (entity pl, float swap) W_WeaponState_Load = { pl.queue_weaponstate = 0; W_WeaponState_Save(pl); - W_SetCurrentAmmo(pl); + W_UpdateCurrentWeapon(pl); Status_Refresh(pl); } @@ -2654,7 +2623,7 @@ void (float inp) W_ChangeWeapon = { if (!self.is_quickfiring && !self.has_quickfired) W_WeaponState_Save(self); - W_SetCurrentAmmo(self); + W_UpdateCurrentWeapon(self); Status_Refresh(self); self.queue_weaponslot = 0; }; From c8f9017e544f6203777638bfd3590dc23a2cb4a7 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 13:03:57 -0700 Subject: [PATCH 1743/2474] Simplify item interaction --- share/fo_weapons.qc | 60 +++++++++++++++++++- ssqc/client.qc | 15 ++--- ssqc/engineer.qc | 2 +- ssqc/menu.qc | 4 +- ssqc/tfort.qc | 53 +----------------- ssqc/vote.qc | 1 - ssqc/weapons.qc | 131 +++----------------------------------------- 7 files changed, 78 insertions(+), 188 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 16fe3928..1fcf91fd 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -45,6 +45,7 @@ enum AmmoType { }; struct FO_WeapModels; +struct FO_WeapToItem; struct FO_WeapInfo { int weapon; // Verification @@ -59,6 +60,7 @@ struct FO_WeapInfo { float needs_reload; int storage_index; // Allocated by init FO_WeapModels* models; + FO_WeapToItem* items; }; // REQUIRES: weapon at index i == WEAP_to_index(weap) @@ -95,7 +97,7 @@ struct FO_ClassWeapons { // Indexed by class ID, e.g. PC_SOLDIER FO_ClassWeapons class_weapons[] = { - { PC_UNDEFINED, { 0, 0, 0, 0 } }, + { PC_UNDEFINED, { 0, 0, 0, WEAP_AXE } }, { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, @@ -105,6 +107,7 @@ FO_ClassWeapons class_weapons[] = { { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, + { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { @@ -182,6 +185,47 @@ float WEAP_to_slot(float class, float weapon) { #define CLIP_STORAGE_SIZE 8 .float clip_fired[CLIP_STORAGE_SIZE]; +struct FO_WeapToItem { + int weapon; + float it_weapon; + + // Fields below this line automatically populated. + float ammo_mask; +}; + +FO_WeapToItem weapon_to_items[] = { + { WEAP_NONE, 0}, + { WEAP_HOOK, IT_HOOK}, + { WEAP_KNIFE, 0}, + { WEAP_MEDIKIT, 0}, + { WEAP_SPANNER, 0}, + { WEAP_AXE, 0}, + { WEAP_SNIPER_RIFLE, IT_SHOTGUN}, + { WEAP_AUTO_RIFLE, IT_SUPER_SHOTGUN}, + { WEAP_SHOTGUN, IT_SHOTGUN}, + { WEAP_SUPER_SHOTGUN, IT_SUPER_SHOTGUN}, + { WEAP_NAILGUN, IT_NAILGUN}, + { WEAP_SUPER_NAILGUN, IT_SUPER_NAILGUN}, + { WEAP_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER}, + { WEAP_FLAMETHROWER, IT_GRENADE_LAUNCHER}, + { WEAP_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER}, + { WEAP_INCENDIARY, IT_ROCKET_LAUNCHER}, + { WEAP_ASSAULT_CANNON, IT_ROCKET_LAUNCHER}, + { WEAP_LIGHTNING, IT_LIGHTNING}, + { WEAP_DETPACK, 0}, + { WEAP_TRANQ, IT_SHOTGUN}, + { WEAP_RAILGUN, IT_SHOTGUN}, +}; + +float FO_ClassWeaponItemMask(float class) { + float mask = 0; + for (float i = 0; i < 4; i++) { + FO_WeapInfo* wi = class_weapons[class].info[i]; + mask |= wi ? (wi->items)->it_weapon : 0; + } + return mask; +} + #ifdef SSQC struct FO_WeapState { float weapon; @@ -378,11 +422,23 @@ void FO_Weapons_Init() { FO_WeapModels* wm = &weapon_models[i]; if (WEAP_to_index(wm->weapon) != i) error(sprintf("WM mismatch at index %d\n", i)); + for (j = 0; j < 2; j++) if (wm->mode[j] != "") precache_model(wm->mode[j]); wi->models = wm; - } + + FO_WeapToItem* wti = &weapon_to_items[i]; + if (WEAP_to_index(wti->weapon) != i) + error(sprintf("WTI mismatch at index %d\n", i)); + wi->items = wti; + switch (wi->ammo_type) { + case AMMO_SHELLS: wti->ammo_mask = IT_SHELLS; break; + case AMMO_CELLS: wti->ammo_mask = IT_CELLS; break; + case AMMO_NAILS: wti->ammo_mask = IT_NAILS; break; + case AMMO_ROCKETS: wti->ammo_mask = IT_ROCKETS; break; + } +} if (clips_allocated > CLIP_STORAGE_SIZE) error("Insufficient clip storage"); diff --git a/ssqc/client.qc b/ssqc/client.qc index f813f337..dd909ac1 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -100,11 +100,8 @@ void () SetChangeParms = { SetNewParms(); return; } - self.items = - self.items - - (self. - items & (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY - | IT_SUIT | IT_QUAD)); + self.items &= ~(IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | + IT_SUIT | IT_QUAD); if (self.health > 100) self.health = 100; if (self.health < 50) @@ -2827,7 +2824,7 @@ void () CheckPowerups = { } } if (self.invisible_finished < time) { - self.items = self.items - IT_INVISIBILITY; + self.items &= ~IT_INVISIBILITY; self.invisible_finished = 0; self.invisible_time = 0; } @@ -2858,7 +2855,7 @@ void () CheckPowerups = { } } if (self.invincible_finished < time) { - self.items = self.items - 1048576; + self.items &= ~IT_INVULNERABILITY; self.invincible_time = 0; self.invincible_finished = 0; } @@ -2901,7 +2898,7 @@ void () CheckPowerups = { } } if (self.super_damage_finished < time) { - self.items = self.items - IT_QUAD; + self.items &= ~IT_QUAD; self.super_damage_finished = 0; self.super_time = 0; } @@ -2945,7 +2942,7 @@ void () CheckPowerups = { } } if (self.radsuit_finished < time) { - self.items = self.items - 2097152; + self.items &= ~IT_SUIT; self.rad_time = 0; self.radsuit_finished = 0; } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 7ea37512..8080473a 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1225,7 +1225,7 @@ void (entity disp) Engineer_Dispenser_InsertArmor = { if (self.armorvalue == 0) { self.armortype = 0; self.armorclass = 0; - self.items = (self.items - (self.items & ((IT_ARMOR1 | IT_ARMOR2) | IT_ARMOR3))); + self.items &= ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3); } if (armor > 0) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index c7748ba4..a865ef1f 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1151,9 +1151,7 @@ void (float inp) Menu_Dispenser_Input = { if (self.armorvalue == 0) { self.armortype = 0; self.armorclass = 0; - self.items = - self.items - - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)); + self.items &= ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3); } } }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 775d6deb..8dc90bb4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1566,8 +1566,8 @@ void () TeamFortress_SetEquipment = { Team_Role * role = GetTeamRole(self.team_no); kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); + self.items = FO_ClassWeaponItemMask(self.playerclass) | kept_items; - self.items = 0; self.weapons_carried = 0; if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; @@ -1616,7 +1616,6 @@ void () TeamFortress_SetEquipment = { self.maxammo_medikit = 0; self.ammo_detpack = 0; self.maxammo_detpack = 0; - self.items_allowed = 0; self.armor_allowed = 0; self.maxarmor = 0; self.respawn_time = 0; @@ -1626,8 +1625,6 @@ void () TeamFortress_SetEquipment = { if (self.team_no == 0) self.lives = -1; - self.items = self.items | kept_items; - if (self.playerclass == PC_SCOUT) { self.weapons_carried = self.weapons_carried | PC_SCOUT_WEAPONS; @@ -1691,10 +1688,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_SCOUT_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_NAILGUN; - - self.items_allowed = PC_SCOUT_WEAPONS; - - self.items = self.items | IT_SHOTGUN | IT_NAILGUN; } else if (self.playerclass == PC_SNIPER) { self.weapons_carried = self.weapons_carried | PC_SNIPER_WEAPONS; @@ -1749,10 +1742,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_SNIPER_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SNIPER_RIFLE; - - self.items_allowed = PC_SNIPER_WEAPONS; - self.items = - self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN; } else if (self.playerclass == PC_SOLDIER) { self.weapons_carried = self.weapons_carried | PC_SOLDIER_WEAPONS; @@ -1819,11 +1808,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_SOLDIER_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_ROCKET_LAUNCHER; - - self.items_allowed = PC_SOLDIER_WEAPONS; - self.items = - self. - items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_DEMOMAN) { self.weapons_carried = self.weapons_carried | PC_DEMOMAN_WEAPONS; @@ -1881,9 +1865,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_DEMOMAN_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_GRENADE_LAUNCHER; - - self.items_allowed = PC_DEMOMAN_WEAPONS; - self.items = self.items | IT_SHOTGUN | IT_GRENADE_LAUNCHER; } else if (self.playerclass == PC_MEDIC) { self.weapons_carried = self.weapons_carried | PC_MEDIC_WEAPONS; @@ -1964,10 +1945,6 @@ void () TeamFortress_SetEquipment = { te.think = CF_Medic_AuraFindPlayers; te.owner = self; te.classname = "timer"; - - self.items_allowed = PC_MEDIC_WEAPONS; - self.items = - self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_SUPER_NAILGUN; } else if (self.playerclass == PC_HVYWEAP) { self.weapons_carried = self.weapons_carried | PC_HVYWEAP_WEAPONS; @@ -2016,7 +1993,6 @@ void () TeamFortress_SetEquipment = { self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1; self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2; - self.tf_items = PC_HVYWEAP_TF_ITEMS; self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS; self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE; @@ -2029,11 +2005,6 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_SUPER_SHOTGUN; - - self.items_allowed = PC_HVYWEAP_WEAPONS; - self.items = - self. - items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_PYRO) { self.weapons_carried = self.weapons_carried | PC_PYRO_WEAPONS; @@ -2078,7 +2049,6 @@ void () TeamFortress_SetEquipment = { self.tp_grenades_1 = PC_PYRO_GRENADE_TYPE_1; self.tp_grenades_2 = PC_PYRO_GRENADE_TYPE_2; - self.tf_items = PC_PYRO_TF_ITEMS; self.armorclass = self.armorclass | PC_PYRO_INITARMORCLASS; self.armor_allowed = PC_PYRO_MAXARMORTYPE; @@ -2088,11 +2058,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_PYRO_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_FLAMETHROWER; - - self.items_allowed = PC_PYRO_WEAPONS; - self.items = - self. - items | IT_SHOTGUN | IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER; } else if (self.playerclass == PC_CIVILIAN) { self.weapons_carried = self.weapons_carried | PC_CIVILIAN_WEAPONS; @@ -2147,9 +2112,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = PC_CIVILIAN_MAXARMOR; if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_AXE; - - self.items_allowed = PC_CIVILIAN_WEAPONS; - self.items = 0; } else if (self.playerclass == PC_SPY) { self.weapons_carried = self.weapons_carried | PC_SPY_WEAPONS; @@ -2207,10 +2169,6 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_TRANQ; - self.items_allowed = PC_SPY_WEAPONS; - self.items = - self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN; - if (invis_only == 1) { te = spawn(); te.nextthink = time + PC_SPY_CELL_REGEN_TIME; @@ -2274,10 +2232,7 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weapon = WEAP_RAILGUN; - self.items_allowed = PC_ENGINEER_WEAPONS; - self.items = self.items | IT_SHOTGUN | IT_SUPER_SHOTGUN; } else if (self.playerclass == PC_UNDEFINED) { - self.items = 0; self.ammo_rockets = 0; self.ammo_nails = 0; self.ammo_shells = 0; @@ -2350,7 +2305,7 @@ float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { }; float (entity Retriever, float WeaponType) TeamFortress_CanGetWeapon = { - if (Retriever.items_allowed & WeaponType) + if (Retriever.items & WeaponType) return TRUE; return FALSE; @@ -3146,9 +3101,7 @@ void () TeamFortress_RegenerateCells = { if (self.owner.ammo_cells == 0) { self.owner.is_undercover = 0; self.owner.modelindex = modelindex_player; - self.owner.items = - self.owner.items - - (self.owner.items & IT_INVISIBILITY); + self.owner.items &= ~IT_INVISIBILITY; } else { self.owner.ammo_cells = self.owner.ammo_cells - PC_SPY_CELL_USAGE; diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 235acaa2..22a652a0 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1228,7 +1228,6 @@ void () AnarchyMode = { vote_anarchy_mode = TRUE; local entity e = find(world, classname, "player"); while(e) { - e.items_allowed = IT_AXE | IT_QUAD; e.items = IT_AXE; e.weapons_carried = IT_AXE; e.current_weapon = WEAP_AXE; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index def0b222..a7a88775 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1566,131 +1566,18 @@ void (entity pl) W_UpdateCurrentWeapon = { if ((pl.health <= 0) || (pl.current_weapon == 0)) return; - if (!(self.tfstate & TFSTATE_AIMING) && !(self.tfstate & TFSTATE_CANT_MOVE)) - /* player_run(); */ - - pl.items = pl.items - (pl.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS)); - pl.weapon = 0; - - if (pl.current_weapon == WEAP_AXE) { - pl.weaponmodel = "progs/v_axe.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_KNIFE) { - if (pl.weaponmode == 0) - pl.weaponmodel = "progs/v_knife.mdl"; - else - pl.weaponmodel = "progs/v_knife2.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_SPANNER) { - pl.weaponmodel = "progs/v_span.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_SHOTGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_shot.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_SUPER_SHOTGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_shot2.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SUPER_SHOTGUN; - } else if (pl.current_weapon == WEAP_NAILGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_nail.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_NAILS; - pl.weapon = IT_NAILGUN; - } else if (pl.current_weapon == WEAP_SUPER_NAILGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_nail2.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_NAILS; - pl.weapon = IT_SUPER_NAILGUN; - } else if (pl.current_weapon == WEAP_GRENADE_LAUNCHER) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - if (pl.weaponmode == 0) - pl.weaponmodel = "progs/v_rock.mdl"; - else - pl.weaponmodel = "progs/v_pipe.mdl"; - pl.weaponframe = 0; - } - pl.weapon = IT_GRENADE_LAUNCHER; - pl.items = pl.items | IT_ROCKETS; - } else if (pl.current_weapon == WEAP_ROCKET_LAUNCHER) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_rock2.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_ROCKETS; - pl.weapon = IT_ROCKET_LAUNCHER; - } else if (pl.current_weapon == WEAP_SNIPER_RIFLE) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_srifle.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_AUTO_RIFLE) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_srifle.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SUPER_SHOTGUN; - } else if (pl.current_weapon == WEAP_ASSAULT_CANNON) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_asscan.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_ROCKET_LAUNCHER; - } else if (pl.current_weapon == WEAP_FLAMETHROWER) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_flame.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_CELLS; - pl.weapon = IT_GRENADE_LAUNCHER; - } else if (pl.current_weapon == WEAP_INCENDIARY) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_irock.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_ROCKETS; - pl.weapon = IT_ROCKET_LAUNCHER; - } else if (pl.current_weapon == WEAP_MEDIKIT) { - pl.items = pl.items | IT_CELLS; - pl.weaponmodel = "progs/v_medi.mdl"; - pl.weaponframe = 0; - } else if (pl.current_weapon == WEAP_TRANQ) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_tranq.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_SHELLS; - pl.weapon = IT_SHOTGUN; - } else if (pl.current_weapon == WEAP_RAILGUN) { - if (!(pl.tfstate & TFSTATE_RELOADING)) { - pl.weaponmodel = "progs/v_rail.mdl"; - pl.weaponframe = 0; - } - pl.items = pl.items | IT_NAILS; - pl.weapon = IT_SHOTGUN; + FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); + pl.items &= ~(IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS); + // TODO: Shouldn't this always be union? Carrying prior behavior for now. + pl.items |= (wi->items)->ammo_mask; + pl.weapon = (wi->items)->it_weapon; + + if (pl.tfstate & TFSTATE_RELOADING == 0 || pl.is_feigning) { + pl.weaponmodel = (wi->models)->mode[pl.weaponmode]; } else { pl.weaponmodel = ""; - pl.weaponframe = 0; - } - - if (pl.is_feigning) { - pl.weaponmodel = ""; - pl.weaponframe = 0; } + pl.weaponframe = 0; // refresh engineer build menu when ammo updated if (pl.menu_input == Menu_Engineer_Input) From e480dfaa13ea3fcafa2b504bdac221264321465a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 17:18:31 -0700 Subject: [PATCH 1744/2474] Move init to FIRST_ENTRY only --- ssqc/client.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index dd909ac1..18359e3f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1047,6 +1047,9 @@ void () DecodeLevelParms = { max_active_gren2_soldier = 1; round_delay_time = 10; } + + // Must be after we've set up conditional options (e.g. hwguy reload). + FO_Weapons_Init(); } if (parm11) @@ -1069,8 +1072,6 @@ void () DecodeLevelParms = { if (parm15) self.is_admin = parm15; - // Must be after we've set up conditional options (e.g. hwguy reload). - FO_Weapons_Init(); /* local entity p = find(world, classname, "player"); while (p != world) { From 7761ea9fdc3a39b393de12f803f8c890665cc1e3 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 12:18:37 -0700 Subject: [PATCH 1745/2474] Eliminate all the weaponmode edgecases. Add a separate weapon entry for pipebombs. --- share/defs.h | 3 +- share/fo_weapons.qc | 74 ++++++++++++++++++++++------------------ ssqc/clan.qc | 2 +- ssqc/client.qc | 4 +-- ssqc/combat.qc | 2 +- ssqc/demoman.qc | 8 ++--- ssqc/doors.qc | 2 +- ssqc/events.qc | 82 ++++++--------------------------------------- ssqc/plats.qc | 2 +- ssqc/progs.src | 4 +-- ssqc/quadmode.qc | 2 +- ssqc/qw.qc | 6 +--- ssqc/tfort.qc | 8 ++--- ssqc/weapons.qc | 67 ++++++++++++------------------------ 14 files changed, 94 insertions(+), 172 deletions(-) diff --git a/share/defs.h b/share/defs.h index b78b7ea4..53b2dbd1 100644 --- a/share/defs.h +++ b/share/defs.h @@ -718,6 +718,7 @@ enumflags { WEAP_NAILGUN, WEAP_SUPER_NAILGUN, WEAP_GRENADE_LAUNCHER, + WEAP_PIPE_LAUNCHER, WEAP_FLAMETHROWER, WEAP_ROCKET_LAUNCHER, WEAP_INCENDIARY, @@ -957,7 +958,7 @@ enumflags { #define PC_DEMOMAN_INITARMORTYPE 0.6 #define PC_DEMOMAN_ARMORCLASSES 31 // ALL #define PC_DEMOMAN_INITARMORCLASS 0 //4 // AT_SAVEEXPLOSION -#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK +#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_PIPE_LAUNCHER | WEAP_DETPACK #define PC_DEMOMAN_MAXAMMO_SHOT 75 #define PC_DEMOMAN_MAXAMMO_NAIL 50 #define PC_DEMOMAN_MAXAMMO_CELL 50 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 1fcf91fd..eee6ac8d 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -79,6 +79,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 4, 0.2, 0 }, { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, + { WEAP_PIPE_LAUNCHER, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, @@ -101,7 +102,7 @@ FO_ClassWeapons class_weapons[] = { { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, - { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_GRENADE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, + { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_MEDIC, { WEAP_SUPER_NAILGUN, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_MEDIKIT } }, { PC_HVYWEAP, { WEAP_ASSAULT_CANNON, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, @@ -117,45 +118,46 @@ inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { - "None", "Hook", "Knife", "BioAxe", "Spanner", "Axe", "Sniper Rifle", - "Sniper Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", - "Grenade Launcher", "Flamethrower", "Rocket Launcher", + "None", "Hook", "Knife", "Medikit", "Spanner", "Axe", "Sniper Rifle", + "Auto Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", + "Grenade Launcher", "Pipebomb Launcher", "Flamethrower", "Rocket Launcher", "Incendiary Launcher", "Assault Cannon", "Lightning Gun", "Detpack", "Tranquilizer", "Railgun" }; -inline string FO_GetWeapName(float weapon) { +string FO_GetWeapName(float weapon) { return weapon_names[WEAP_to_index(weapon)]; } struct FO_WeapModels { int weapon; - string mode[2]; + string model; }; -// Indexed by WEAP_to_index() and player.weaponmode +// Indexed by WEAP_to_index() static FO_WeapModels weapon_models[] = { - { WEAP_NONE, {""}}, - { WEAP_HOOK, {"progs/v_grap.mdl" }}, - { WEAP_KNIFE, {"progs/v_knife.mdl", "progs/v_knife2.mdl" }}, - { WEAP_MEDIKIT, {"progs/v_medi.mdl"}}, - { WEAP_SPANNER, {"progs/v_span.mdl"}}, - { WEAP_AXE, {"progs/v_axe.mdl"}}, - { WEAP_SNIPER_RIFLE, {"progs/v_srifle.mdl"}}, - { WEAP_AUTO_RIFLE, {"progs/v_srifle.mdl"}}, - { WEAP_SHOTGUN, {"progs/v_shot.mdl"}}, - { WEAP_SUPER_SHOTGUN, {"progs/v_shot2.mdl"}}, - { WEAP_NAILGUN, {"progs/v_nail.mdl"}}, - { WEAP_SUPER_NAILGUN, {"progs/v_nail2.mdl"}}, - { WEAP_GRENADE_LAUNCHER, {"progs/v_rock.mdl", "progs/v_pipe.mdl"}}, - { WEAP_FLAMETHROWER, {"progs/v_flame.mdl"}}, - { WEAP_ROCKET_LAUNCHER, {"progs/v_rock2.mdl"}}, - { WEAP_INCENDIARY, {"progs/v_irock.mdl"}}, - { WEAP_ASSAULT_CANNON, {"progs/v_asscan.mdl"}}, - { WEAP_LIGHTNING, {""}}, - { WEAP_DETPACK, {""}}, - { WEAP_TRANQ, {"progs/v_tranq.mdl"}}, - { WEAP_RAILGUN, {"progs/v_rail.mdl"}}, + { WEAP_NONE, ""}, + { WEAP_HOOK, "progs/v_grap.mdl" }, + { WEAP_KNIFE, "progs/v_knife.mdl" }, + { WEAP_MEDIKIT, "progs/v_medi.mdl" }, + { WEAP_SPANNER, "progs/v_span.mdl" }, + { WEAP_AXE, "progs/v_axe.mdl" }, + { WEAP_SNIPER_RIFLE, "progs/v_srifle.mdl" }, + { WEAP_AUTO_RIFLE, "progs/v_srifle.mdl" }, + { WEAP_SHOTGUN, "progs/v_shot.mdl" }, + { WEAP_SUPER_SHOTGUN, "progs/v_shot2.mdl" }, + { WEAP_NAILGUN, "progs/v_nail.mdl" }, + { WEAP_SUPER_NAILGUN, "progs/v_nail2.mdl" }, + { WEAP_GRENADE_LAUNCHER, "progs/v_rock.mdl" }, + { WEAP_PIPE_LAUNCHER, "progs/v_pipe.mdl" }, + { WEAP_FLAMETHROWER, "progs/v_flame.mdl" }, + { WEAP_ROCKET_LAUNCHER, "progs/v_rock2.mdl" }, + { WEAP_INCENDIARY, "progs/v_irock.mdl" }, + { WEAP_ASSAULT_CANNON, "progs/v_asscan.mdl" }, + { WEAP_LIGHTNING, "" }, + { WEAP_DETPACK, "" }, + { WEAP_TRANQ, "progs/v_tranq.mdl" }, + { WEAP_RAILGUN, "progs/v_rail.mdl" }, }; // REQUIRES: Order must match above. @@ -207,6 +209,7 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_NAILGUN, IT_NAILGUN}, { WEAP_SUPER_NAILGUN, IT_SUPER_NAILGUN}, { WEAP_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER}, + { WEAP_PIPE_LAUNCHER, IT_GRENADE_LAUNCHER}, { WEAP_FLAMETHROWER, IT_GRENADE_LAUNCHER}, { WEAP_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER}, { WEAP_INCENDIARY, IT_ROCKET_LAUNCHER}, @@ -261,7 +264,7 @@ static void FOT_ReloadTimer() { if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = ((ws->wi)->models)->mode[self.owner.weaponmode]; + self.owner.weaponmodel = ((ws->wi)->models)->model; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); W_WeaponState_Load(self.owner, 0); @@ -408,7 +411,14 @@ void FO_Weapons_Init() { if (WEAP_to_index(wi->weapon) != i) error(sprintf("WI mismatch at index %d\n", i)); - if (wi->clip_size > 0) { + if (wi->weapon == WEAP_PIPE_LAUNCHER) { + FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); + wi->ammo_type = parent->ammo_type; + wi->clip_size = parent->clip_size; + wi->storage_index = parent->storage_index; + wi->full_reload_time = parent->full_reload_time; + wi->needs_reload = parent->needs_reload; + } else if (wi->clip_size > 0) { wi->needs_reload = TRUE; // We always allocate a storage index for something that can have // reload to save negotiating between client and server around @@ -423,9 +433,7 @@ void FO_Weapons_Init() { if (WEAP_to_index(wm->weapon) != i) error(sprintf("WM mismatch at index %d\n", i)); - for (j = 0; j < 2; j++) - if (wm->mode[j] != "") - precache_model(wm->mode[j]); + precache_model(wm->model); wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; diff --git a/ssqc/clan.qc b/ssqc/clan.qc index f70ed66e..980a8cc7 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -84,7 +84,7 @@ void () StartMatch = } te = find(world, classname, "detpack"); while (te){ - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed (te.enemy); dremove(te.oldenemy); dremove(te.observer_list); diff --git a/ssqc/client.qc b/ssqc/client.qc index 18359e3f..2dc4148b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1413,7 +1413,7 @@ void () RemovePlayerOwnedEnts = { te = find(world, classname, "detpack"); while (te) { if (te.owner == self) { - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed(te.enemy); dremove(te.oldenemy); dremove(te.observer_list); @@ -1426,7 +1426,7 @@ void () RemovePlayerOwnedEnts = { te = find(world, classname, "countdown_timer"); while (te) { if (te.owner == self) { - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed(te.enemy); dremove(te.oldenemy); dremove(te.observer_list); diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 959f732c..8969a187 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -672,7 +672,7 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, if (targ.health <= 0) { if ((inflictor.classname == "detpack") - && (inflictor.weaponmode == 1) && (inflictor.enemy == targ)) + && (inflictor.is_disarming) && (inflictor.enemy == targ)) deathmsg = DMSG_DETPACK_DIS; LogEventKill(attacker, targ, inflictor); Killed(targ, attacker); diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 954dd26b..2ac726cc 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -312,7 +312,7 @@ void () TeamFortress_DetpackSet = { newmis.angles_y = self.owner.angles_y; newmis.velocity = '0 0 0'; newmis.avelocity = '0 0 0'; - newmis.weaponmode = 0; + newmis.is_disarming = FALSE; newmis.touch = TeamFortress_DetpackTouch; FO_SetModel(newmis, "progs/detpack.mdl"); @@ -410,7 +410,7 @@ void () TeamFortress_DetpackExplode = { } else sprint(self.owner, PRINT_HIGH, "Your detpack fizzled out\n"); - if (self.weaponmode == 1) { + if (self.is_disarming) { TeamFortress_SetSpeed(self.enemy); dremove(self.oldenemy); dremove(self.observer_list); @@ -430,7 +430,7 @@ void () TeamFortress_DetpackTouch = { return; if (other.deadflag) return; - if (self.weaponmode == 1) + if (self.is_disarming) return; if ((other.team_no == self.owner.team_no) && (self.owner.team_no != 0)) @@ -462,7 +462,7 @@ void () TeamFortress_DetpackTouch = { disarm.nextthink = time + 3; disarm.think = TeamFortress_DetpackDisarm; - self.weaponmode = 1; + self.is_disarming = TRUE; self.enemy = other; self.observer_list = disarm; }; diff --git a/ssqc/doors.qc b/ssqc/doors.qc index dda88cd7..9ed830a9 100644 --- a/ssqc/doors.qc +++ b/ssqc/doors.qc @@ -7,7 +7,7 @@ void () door_blocked = { if (other.classname == "detpack") { sprint(other.owner, PRINT_HIGH, "Your detpack was squashed\n"); - if (other.weaponmode == 1) { + if (other.is_disarming) { TeamFortress_SetSpeed(other.enemy); dremove(other.observer_list); diff --git a/ssqc/events.qc b/ssqc/events.qc index 88cc143a..77be41b7 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -94,75 +94,15 @@ void (entity player, float previous, float next, float timeplayed) LogEventChang logevent(event); } -string (float code, float mode) GetWeaponName = { - if (code == 1) { - return "hook"; +string (float weapon) GetWeaponName = { + if (weapon >= 1 && weapon <= WEAP_LAST) { + string name = FO_GetWeapName(weapon); + name = strtolower(name); + name = strreplace(name, " ", ""); + return name; } - else if (code == 4) { - return "medikit"; - } - else if (code == 8) { - return "spanner"; - } - else if (code == 16) { - return "axe"; - } - else if (code == 32) { - return "sniperrifle"; - } - else if (code == 64) { - return "autorifle"; - } - else if (code == 128) { - return "shotgun"; - } - else if (code == 256) { - return "supershotgun"; - } - else if (code == 512) { - return "nailgun"; - } - else if (code == 1024) { - return "supernailgun"; - } - else if (code == 2048) { - if (mode == 0) - return "grenadelauncher"; - else if (mode == 1) - return "pipebomblauncher"; - } - else if (code == 4096) { - return "flamethrower"; - } - else if (code == 8192) { - return "rocketlauncher"; - } - else if (code == 16384) { - return "incendiary"; - } - else if (code == 32768) { - return "assaultcannon"; - } - else if (code == 65536) { - return "lightning"; - } - else if (code == 131072) { - return "plasmagun"; - } - else if (code == 262144) { - return "tranquilizer"; - } - else if (code == 524288) { - return "railgun"; - } - else if (code == 1048576) { - return "tribolt"; - } - else if (code == 2097152) { - return "sniperrail"; - } - else - return "undefined"; + + return "undefined"; } void (entity attacker, entity target, string afflictionType) LogAffliction = { @@ -230,7 +170,7 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon, attacker.weaponmode); + inflictorId = GetWeaponName(attacker.current_weapon); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -332,7 +272,7 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { killKind = "enemy"; if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon, attacker.weaponmode); + inflictorId = GetWeaponName(attacker.current_weapon); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -446,7 +386,7 @@ void (entity attacker) LogEventAttack = { if (canlog == 0) return; local string event; - event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(attacker.current_weapon, attacker.weaponmode), ftos(gametime), gametimestamp); + event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(attacker.current_weapon), ftos(gametime), gametimestamp); logevent(event); } diff --git a/ssqc/plats.qc b/ssqc/plats.qc index 2b3ab748..d681cb57 100644 --- a/ssqc/plats.qc +++ b/ssqc/plats.qc @@ -147,7 +147,7 @@ void () plat_trigger_use = { void () plat_crush = { if (other.classname == "detpack") { sprint(other.owner, PRINT_HIGH, "Your detpack was squashed\n"); - if (other.weaponmode == 1) { + if (other.is_disarming) { TeamFortress_SetSpeed(other.enemy); dremove(other.observer_list); } diff --git a/ssqc/progs.src b/ssqc/progs.src index 5cd0b0b3..e69fee0a 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -12,11 +12,11 @@ defs.qc ../share/commondefs.qc ../share/common_helpers.qc qw.qc +debug.qc +../share/fo_weapons.qc events.qc roles.qc q3defs.qc -debug.qc -../share/fo_weapons.qc status.qc functions.qc menu.qc diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 0e59bb2c..10bb0b2e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -520,7 +520,7 @@ void () StartQuadRound = } te = find(world, classname, "detpack"); while (te){ - if (te.weaponmode == 1) { + if (te.is_disarming == 1) { TeamFortress_SetSpeed (te.enemy); dremove(te.oldenemy); dremove(te.observer_list); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index f5c4354e..709ff91a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -130,8 +130,7 @@ float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); .float maxfbspeed; // Maximum forward/back speed .float maxstrafespeed; // Maximum side speed -.float weaponmode; // Used for multiple mode weapons -.float last_weaponmode; // Last weapon's weapon mode +.float is_disarming; .float motd; // Used to display MOTD .float current_menu; .float current_menu_type; @@ -216,15 +215,12 @@ float coop; .float queue_weaponslot; // the weaponslot to switch to when possible .float queue_weaponstate; // the weaponstate to load when possible .float next_weapon; // used by weapon slots to communicate which weapon to select -.float next_weaponmode; // used by weapon slots to communicate which weapon mode to select // weapon states .float weaponstate_current_weaponslot; .float weaponstate_last_weaponslot; .float weaponstate_current_weapon; .float weaponstate_last_weapon; -.float weaponstate_weaponmode; -.float weaponstate_last_weaponmode; .float ammo_medikit; // Ammo used for the medikit .float maxammo_medikit; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 8dc90bb4..2df04c55 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1572,8 +1572,6 @@ void () TeamFortress_SetEquipment = { if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; self.last_weapon = 0; - self.weaponmode = 0; - self.last_weaponmode = 0; self.current_weaponslot = W_BestWeaponSlot(); self.last_weaponslot = 2; W_WeaponState_Save(self); @@ -2283,6 +2281,8 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) self.current_weaponslot = W_BestWeaponSlot(); + + W_UpdateCurrentWeapon(self); }; float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { @@ -2447,8 +2447,8 @@ void () TeamFortress_RemoveTimers = { te = find(world, classname, "detpack"); while (te) { - if ((te.weaponmode == 1) && (te.enemy == self)) - te.weaponmode = 0; + if ((te.is_disarming) && (te.enemy == self)) + te.is_disarming = FALSE; te = find(te, classname, "detpack"); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index a7a88775..749cdaf7 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -256,8 +256,7 @@ int () W_FireKnife = { trace_ent.axhitme = 1; SpawnBlood(org, 20); - self.weaponmode = 1; - self.weaponmodel = "progs/v_knife2.mdl"; + // TODO: Rework knife bloodying // Check direction of Attack makevectors(trace_ent.v_angle); @@ -1307,7 +1306,7 @@ void () W_FireGrenade = { newmis.owner = self; newmis.movetype = 10; newmis.solid = 2; - if ((self.weaponmode == 0) || (cb_prematch)) { + if (self.current_weapon == WEAP_GRENADE_LAUNCHER || cb_prematch) { newmis.weapon = 5; newmis.classname = "grenade"; newmis.skin = 1; @@ -1573,7 +1572,7 @@ void (entity pl) W_UpdateCurrentWeapon = { pl.weapon = (wi->items)->it_weapon; if (pl.tfstate & TFSTATE_RELOADING == 0 || pl.is_feigning) { - pl.weaponmodel = (wi->models)->mode[pl.weaponmode]; + pl.weaponmodel = (wi->models)->model; } else { pl.weaponmodel = ""; } @@ -1653,10 +1652,8 @@ void () W_ChangeToBestWeapon = { //self.last_weaponslot = self.current_weaponslot; //self.last_weapon = self.current_weapon; - //self.last_weaponmode = self.weaponmode; self.current_weaponslot = slot; self.current_weapon = self.next_weapon; - self.weaponmode = self.next_weaponmode; W_UpdateCurrentWeapon(self); W_WeaponState_Save(self); W_PrintWeaponMessage(); @@ -1752,6 +1749,10 @@ void () W_Attack = { player_rocket1(); W_FireGrenade(); Status_Refresh(self); + } else if (self.current_weapon == WEAP_PIPE_LAUNCHER) { + player_rocket1(); + W_FireGrenade(); + Status_Refresh(self); } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { player_rocket1(); W_FireRocket(); @@ -1846,12 +1847,12 @@ void () W_PrintWeaponMessage = { switch (self.current_weapon) { case WEAP_GRENADE_LAUNCHER: - if (self.weaponmode == GL_NORMAL) - sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); - else if (cb_prematch) - sprint(self, PRINT_MEDIUM, - "Pipebomb mode not available in prematch\n"); - else if (self.weaponmode == GL_PIPEBOMB) + sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); + break; + case WEAP_PIPE_LAUNCHER: + if (cb_prematch) + sprint(self, PRINT_MEDIUM, "Pipebomb mode not available in prematch\n"); + else sprint(self, PRINT_MEDIUM, "Pipebomb mode\n"); break; case WEAP_SNIPER_RIFLE: @@ -1889,11 +1890,6 @@ float (float weap) W_GetSlot = { return 1; else return 3; - } else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.weaponmode == 0) - return 1; - else - return 2; } return 0; }; @@ -1923,12 +1919,11 @@ float (float weap) W_OldGetSlot = { || weap == WEAP_ASSAULT_CANNON || weap == WEAP_INCENDIARY) return 7; - else if (weap == WEAP_GRENADE_LAUNCHER) { - if (self.weaponmode == 0) - return 6; - else - return 7; - } + else if (weap == WEAP_GRENADE_LAUNCHER) + return 6; + else if (weap == WEAP_PIPE_LAUNCHER) + return 7; + return 0; }; @@ -2131,10 +2126,8 @@ float () W_OldWeaponSlot5 = { }; float () W_OldWeaponSlot6 = { - if (self.playerclass == PC_DEMOMAN) { - self.next_weaponmode = 0; + if (self.playerclass == PC_DEMOMAN) return WEAP_GRENADE_LAUNCHER; - } else if (self.playerclass == PC_PYRO) return WEAP_FLAMETHROWER; return 0; @@ -2144,7 +2137,7 @@ float () W_OldWeaponSlot7 = { if (self.playerclass == PC_SOLDIER) return WEAP_ROCKET_LAUNCHER; if (self.playerclass == PC_DEMOMAN) - return WEAP_GRENADE_LAUNCHER; + return WEAP_PIPE_LAUNCHER; else if (self.playerclass == PC_HVYWEAP) return WEAP_ASSAULT_CANNON; else if (self.playerclass == PC_PYRO) @@ -2192,7 +2185,7 @@ float () W_WeaponSlot2 = { || self.playerclass == PC_ENGINEER) return WEAP_SUPER_SHOTGUN; else if (self.playerclass == PC_DEMOMAN) { - return WEAP_GRENADE_LAUNCHER; // weaponmode = 1 (pipebomb launcher) + return WEAP_PIPE_LAUNCHER; } else if (self.playerclass == PC_PYRO) if (cf_pyro_impulses) { return WEAP_INCENDIARY; @@ -2233,13 +2226,10 @@ float () W_WeaponSlot4 = { }; void (float slot) W_WeaponSlot = { - self.next_weaponmode = 0; if (slot == 1) self.next_weapon = W_WeaponSlot1(); else if (slot == 2) { self.next_weapon = W_WeaponSlot2(); - if (self.next_weapon == WEAP_GRENADE_LAUNCHER) - self.next_weaponmode = 1; } else if (slot == 3) self.next_weapon = W_WeaponSlot3(); @@ -2248,7 +2238,6 @@ void (float slot) W_WeaponSlot = { }; void (float inp) W_OldWeaponSlot = { - self.next_weaponmode = 0; if (inp == TF_SLOT1) { self.next_weapon = W_OldWeaponSlot1(); } @@ -2269,8 +2258,6 @@ void (float inp) W_OldWeaponSlot = { } else if (inp == 7) { self.next_weapon = W_OldWeaponSlot7(); - if (self.next_weapon == WEAP_GRENADE_LAUNCHER) - self.next_weaponmode = 1; } if (self.next_weapon == 0) { self.next_weapon = self.current_weapon; @@ -2415,8 +2402,6 @@ void (entity pl) W_WeaponState_Save = { pl.weaponstate_last_weaponslot = pl.last_weaponslot; pl.weaponstate_current_weapon = pl.current_weapon; pl.weaponstate_last_weapon = pl.last_weapon; - pl.weaponstate_weaponmode = pl.weaponmode; - pl.weaponstate_last_weaponmode = pl.last_weaponmode; } void (entity pl, float swap) W_WeaponState_Load = { @@ -2425,15 +2410,11 @@ void (entity pl, float swap) W_WeaponState_Load = { pl.last_weaponslot = pl.weaponstate_last_weaponslot; pl.current_weapon = pl.weaponstate_current_weapon; pl.last_weapon = pl.weaponstate_last_weapon; - pl.weaponmode = pl.weaponstate_weaponmode; - pl.last_weaponmode = pl.weaponstate_last_weaponmode; } else { pl.current_weaponslot = pl.weaponstate_last_weaponslot; pl.last_weaponslot = pl.weaponstate_current_weaponslot; pl.current_weapon = pl.weaponstate_last_weapon; pl.last_weapon = pl.weaponstate_current_weapon; - pl.weaponmode = pl.weaponstate_last_weaponmode; - pl.last_weaponmode = pl.weaponstate_weaponmode; } pl.queue_weaponstate = 0; @@ -2495,13 +2476,11 @@ void (float inp) W_ChangeWeapon = { } // don't update current/last weapon information if next weapon is the same as current - if (self.current_weapon != self.next_weapon || self.weaponmode != self.next_weaponmode) { + if (self.current_weapon != self.next_weapon) { self.last_weaponslot = self.current_weaponslot; self.current_weaponslot = self.queue_weaponslot; self.last_weapon = self.current_weapon; self.current_weapon = self.next_weapon; - self.last_weaponmode = self.weaponmode; - self.weaponmode = self.next_weaponmode; if (!self.is_quickfiring) W_PrintWeaponMessage(); @@ -3463,8 +3442,6 @@ void () W_WeaponFrame = { SuperDamageSound(); W_Attack(); } - } else if (self.playerclass == 0) { - self.weaponmode = 0; } else if (self.tfstate & TFSTATE_AIMING) { W_Attack(); self.tfstate = self.tfstate - TFSTATE_AIMING; From 1c6a4453b38bd7f5d46c5f420618f413a548abf9 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 26 Sep 2022 12:18:59 -0700 Subject: [PATCH 1746/2474] Refactor everything to use the new weapon code This indavertently became a huge diff. It was too awkward to separate this stuff as the touch points were super entwined. - Class loadouts are now all generated from our class tables. - Eliminate everything around , we now work purely in weapons. When we need something else, we convert it to a weapon. - Remove `chweap_wait_atk`. We have queueing, it's not used for any of our game modes, and it adds complexity. --- share/defs.h | 10 - share/fo_weapons.qc | 42 ++- ssqc/actions.qc | 115 +------ ssqc/client.qc | 22 +- ssqc/demoman.qc | 11 +- ssqc/player.qc | 3 +- ssqc/qw.qc | 5 +- ssqc/spy.qc | 6 +- ssqc/tfort.qc | 63 +--- ssqc/weapons.qc | 748 +++++++++----------------------------------- 10 files changed, 218 insertions(+), 807 deletions(-) diff --git a/share/defs.h b/share/defs.h index 53b2dbd1..49670e60 100644 --- a/share/defs.h +++ b/share/defs.h @@ -870,7 +870,6 @@ enumflags { #define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned #define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class #define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned -#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN #define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry #define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry #define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry @@ -901,7 +900,6 @@ enumflags { #define PC_SNIPER_INITARMORTYPE 0.3 #define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL #define PC_SNIPER_INITARMORCLASS 0 -#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN #define PC_SNIPER_MAXAMMO_SHOT 75 #define PC_SNIPER_MAXAMMO_NAIL 100 #define PC_SNIPER_MAXAMMO_CELL 50 @@ -929,7 +927,6 @@ enumflags { #define PC_SOLDIER_INITARMORTYPE 0.8 #define PC_SOLDIER_ARMORCLASSES 31 // ALL #define PC_SOLDIER_INITARMORCLASS 0 -#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER #define PC_SOLDIER_MAXAMMO_SHOT 100 #define PC_SOLDIER_MAXAMMO_NAIL 100 #define PC_SOLDIER_MAXAMMO_CELL 50 @@ -958,7 +955,6 @@ enumflags { #define PC_DEMOMAN_INITARMORTYPE 0.6 #define PC_DEMOMAN_ARMORCLASSES 31 // ALL #define PC_DEMOMAN_INITARMORCLASS 0 //4 // AT_SAVEEXPLOSION -#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_PIPE_LAUNCHER | WEAP_DETPACK #define PC_DEMOMAN_MAXAMMO_SHOT 75 #define PC_DEMOMAN_MAXAMMO_NAIL 50 #define PC_DEMOMAN_MAXAMMO_CELL 50 @@ -990,7 +986,6 @@ enumflags { #define PC_MEDIC_INITARMORTYPE 0.3 #define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION #define PC_MEDIC_INITARMORCLASS 0 -#define PC_MEDIC_WEAPONS WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN #define PC_MEDIC_MAXAMMO_SHOT 75 #define PC_MEDIC_MAXAMMO_NAIL 150 #define PC_MEDIC_MAXAMMO_CELL 50 @@ -1032,7 +1027,6 @@ enumflags { #define PC_HVYWEAP_INITARMORTYPE 0.8 #define PC_HVYWEAP_ARMORCLASSES 31 // ALL #define PC_HVYWEAP_INITARMORCLASS 0 -#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN #define PC_HVYWEAP_MAXAMMO_SHOT 200 #define PC_HVYWEAP_MAXAMMO_NAIL 200 #define PC_HVYWEAP_MAXAMMO_CELL 50 @@ -1064,7 +1058,6 @@ enumflags { #define PC_PYRO_INITARMORTYPE 0.6 #define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION #define PC_PYRO_INITARMORCLASS 16 // AT_SAVEFIRE -#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN #define PC_PYRO_MAXAMMO_SHOT 40 #define PC_PYRO_MAXAMMO_NAIL 50 #define PC_PYRO_MAXAMMO_CELL 200 @@ -1116,7 +1109,6 @@ enumflags { #define PC_SPY_INITARMORTYPE 0.6 #define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION #define PC_SPY_INITARMORCLASS 0 -#define PC_SPY_WEAPONS WEAP_KNIFE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN #define PC_SPY_MAXAMMO_SHOT 40 #define PC_SPY_MAXAMMO_NAIL 100 #define PC_SPY_MAXAMMO_CELL 30 @@ -1149,7 +1141,6 @@ enumflags { #define PC_ENGINEER_INITARMORTYPE 0.3 #define PC_ENGINEER_ARMORCLASSES 31 // ALL #define PC_ENGINEER_INITARMORCLASS 0 -#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_RAILGUN | WEAP_SUPER_SHOTGUN #define PC_ENGINEER_MAXAMMO_SHOT 50 #define PC_ENGINEER_MAXAMMO_NAIL 50 #define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal @@ -1179,7 +1170,6 @@ enumflags { #define PC_CIVILIAN_INITARMORTYPE 0 #define PC_CIVILIAN_ARMORCLASSES 0 #define PC_CIVILIAN_INITARMORCLASS 0 -#define PC_CIVILIAN_WEAPONS WEAP_AXE #define PC_CIVILIAN_MAXAMMO_SHOT 0 #define PC_CIVILIAN_MAXAMMO_NAIL 0 #define PC_CIVILIAN_MAXAMMO_CELL 0 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index eee6ac8d..86565b33 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -12,6 +12,7 @@ .float reload_assault_cannon; .float reload_sniper_rifle; .float waterlevel; +.float playerclass; .float ammo_shells; .float ammo_nails; @@ -90,6 +91,9 @@ FO_WeapInfo weapon_info[] = { { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, }; +inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { + return &weapon_info[WEAP_to_index(weapon)]; +} struct FO_ClassWeapons { float id; float slots[4]; @@ -111,10 +115,6 @@ FO_ClassWeapons class_weapons[] = { { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; -inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { - return &weapon_info[WEAP_to_index(weapon)]; -} - // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { @@ -220,11 +220,37 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_RAILGUN, IT_SHOTGUN}, }; +FO_WeapInfo* FO_ClassWeaponSlot(float class, float slot) { + FO_ClassWeapons* cw = &class_weapons[class]; + return cw->info[slot - 1] ? cw->info[slot - 1] : __NULL__; +} + +float FO_ClassWeapMask(float class) { + float result = 0; + for (int i = 1; i <= 4; i++) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); + if (wi) + result |= (wi->items)->it_weapon; + } + return result; +} + float FO_ClassWeaponItemMask(float class) { float mask = 0; - for (float i = 0; i < 4; i++) { - FO_WeapInfo* wi = class_weapons[class].info[i]; - mask |= wi ? (wi->items)->it_weapon : 0; + for (float i = 1; i <= 4; i++) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); + if (wi) + mask |= (wi->items)->it_weapon; + } + return mask; +} + +float FO_CurrentWeaponsMask() { + float mask = 0; + for (float i = 1; i <= 4; i++) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, i); + if (wi) + mask |= wi->weapon; } return mask; } @@ -254,7 +280,6 @@ void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; -void (entity pl, float swap) W_WeaponState_Load; void (float att_delay) Attack_Finished; static void FOT_ReloadTimer() { @@ -267,7 +292,6 @@ static void FOT_ReloadTimer() { self.owner.weaponmodel = ((ws->wi)->models)->model; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); - W_WeaponState_Load(self.owner, 0); } else { // Refresh clip if (ws->weapon != WEAP_SNIPER_RIFLE) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index c973f451..452585f0 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -467,9 +467,9 @@ void (entity pe_player, float f_type) CF_Identify = { }; void () RestoreDefaultWeapon = { - local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); + float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); if (default_weapon >= 1 && default_weapon <= 4) { - W_ChangeWeapon(default_weapon); + W_ChangeWeapon(W_WeaponBySlot(default_weapon)); } }; @@ -482,114 +482,31 @@ void () TeamFortress_ForceReloadCurrentWeapon = { }; void (float slot) TeamFortress_ReloadSlot = { - local float weap = 0; + float weap = W_WeaponBySlot(slot); - if (!IsUsingOldImpulses()) { - if (slot < 1 || slot > 3) - return; + FO_ReloadWeapon(weap, FALSE); +} - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) - return; - weap = W_WeaponSlot3(); - } - FO_ReloadWeapon(weap, FALSE); - } - else { - if (slot < 1 || slot > 7) - return; - if (slot == 1) - weap = W_OldWeaponSlot1(); - else if (slot == 2) - weap = W_OldWeaponSlot2(); - else if (slot == 3) - weap = W_OldWeaponSlot3(); - else if (slot == 4) - weap = W_OldWeaponSlot4(); - else if (slot == 5) - weap = W_OldWeaponSlot5(); - else if (slot == 6) - weap = W_OldWeaponSlot6(); - else if (slot == 7) - weap = W_OldWeaponSlot7(); - if (weap != 0) - FO_ReloadWeapon(weap, FALSE); - } -}; +float W_FindPrevNextWeapon(float weapon, float is_prev); void () TeamFortress_ReloadNext = { - local float slot, reload = 0, weap = 0; - - if (!IsUsingOldImpulses()) { - // reload current slot first - slot = W_GetSlot(self.current_weapon); - if (FO_CanReload(self.current_weapon)) { - FO_ReloadWeapon(self.current_weapon, FALSE); - reload = 1; - return; - } - - // then go through each slot - for (slot = 1; slot < 4; slot++) { - if (slot == 1) - weap = W_WeaponSlot1(); - else if (slot == 2) - weap = W_WeaponSlot2(); - else if (slot == 3) { - if (self.playerclass == PC_SCOUT || self.playerclass == PC_ENGINEER) - break; - weap = W_WeaponSlot3(); - } + float weapon = self.current_weapon; - if (FO_CanReload(weap)) { - self.current_weapon = weap; - FO_ReloadWeapon(weap, FALSE); - reload = 1; + if (!FO_CanReload(weapon)) { + for (int i = 0; i < 3; i++) { + weapon = W_FindPrevNextWeapon(weapon, FALSE); + if (FO_CanReload(weapon)) break; - } - } - } - else { - slot = W_OldGetSlot(self.current_weapon); - if (FO_CanReload(self.current_weapon)) { - FO_ReloadWeapon(self.current_weapon, FALSE); - reload = 1; - return; - } - // then go through each slot - for (slot = 1; slot < GetLastWeaponImpulse(); slot++) { - if (slot == 1) - weap = W_OldWeaponSlot1(); - else if (slot == 2) - weap = W_OldWeaponSlot2(); - else if (slot == 3) - weap = W_OldWeaponSlot3(); - else if (slot == 4) - weap = W_OldWeaponSlot4(); - else if (slot == 5) - weap = W_OldWeaponSlot5(); - else if (slot == 6) - weap = W_OldWeaponSlot6(); - else if (slot == 7) - weap = W_OldWeaponSlot7(); - - if (FO_CanReload(weap)) { - self.current_weapon = weap; - FO_ReloadWeapon(weap, FALSE); - reload = 1; - break; - } } } - if (!reload) + if (FO_CanReload(weapon)) { + FO_ReloadWeapon(weapon, FALSE); RestoreDefaultWeapon(); + } else { sprint(self, PRINT_HIGH, "All clips full\n"); -}; + } +} entity TeamFortress_GetPracticeSpawn(entity e) = { diff --git a/ssqc/client.qc b/ssqc/client.qc index 2dc4148b..5cee5312 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -58,7 +58,6 @@ void () StartQuadRound; void (string cl_pwd) Admin_Check; void () Admin_Aliases; void () PreMatch_Message; -float () GetLastWeaponImpulse; void () UpdateReadyStatus; float () CheckAllPlayersReady; string(float)TeamFortress_TeamGetColorString; @@ -680,9 +679,6 @@ void () DecodeLevelParms = { // ceasefire type - 0: default; 1: pause ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); - // wait until attack_finished is over before changing weapons - chweap_wait_attfinished = CF_GetSetting("cwaf", "chweap_wait_atk", "on"); - // enable flag model following the player who has it flag_follow = CF_GetSetting("flagfollow", "flag_follow", "on"); @@ -999,7 +995,6 @@ void () DecodeLevelParms = { if (st == "on") { server_huetf = TRUE; impulse_queue = TRUE; - chweap_wait_attfinished = FALSE; flag_follow = FALSE; ng_velocity = 1000; ng_damage = 18; @@ -2112,9 +2107,6 @@ void () PutClientInServer = { return; } - if (self.last_playerclass == 0) - self.last_playerclass = self.playerclass; - // remove prime timers to avoid getting an old grenade in your face te = find(world, classname, "primetimer"); while (te != world) { @@ -2177,6 +2169,7 @@ void () PutClientInServer = { TeamFortress_PrintClassName(self, self.playerclass, self.tfstate & TFSTATE_RANDOMPC); + self.attack_finished = 0; // Allow below to change weapon freely. TeamFortress_SetEquipment(); TeamFortress_SetHealth(); TeamFortress_SetSpeed(self); @@ -2190,12 +2183,6 @@ void () PutClientInServer = { stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - if (self.current_weaponslot && self.last_playerclass == self.playerclass) - W_ChangeWeapon(self.current_weaponslot); - else { - W_ChangeWeapon(W_BestWeaponSlot()); - } - self.last_playerclass = self.playerclass; self.attack_finished = time + 0.3; self.th_pain = player_pain; @@ -3829,11 +3816,8 @@ float () IsUsingCFImpulses = { return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); } -float () GetLastWeaponImpulse = { - if (IsUsingOldImpulses()) - return 7; - else - return 4; +float GetMaxWeaponInput() { + return IsUsingOldImpulses() ? 7 : 4; } void () InitReverseCap = { diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 2ac726cc..181b6b07 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -224,8 +224,9 @@ void (float timer) TeamFortress_SetDetpack = { self.ammo_detpack = self.ammo_detpack - 1; self.immune_to_check = time + 10; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - self.weapon = self.current_weapon; - self.next_weapon = self.current_weapon; + self.weapon = IT_AXE; + self.queue_weapon = self.current_weapon; + self.current_weapon = 0; self.weaponmodel = ""; self.weaponframe = 0; @@ -267,7 +268,8 @@ void () TeamFortress_DetpackStop = { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); self.is_detpacking = 0; self.detpack_left = 0; - self.current_weapon = self.next_weapon; + self.current_weapon = self.queue_weapon; + self.queue_weapon = 0; Status_Refresh(self); TeamFortress_SetSpeed(self); @@ -293,7 +295,8 @@ void () TeamFortress_DetpackSet = { oldself = self; self = self.owner; self.is_detpacking = 0; - self.current_weapon = self.next_weapon; + self.current_weapon = self.queue_weapon; + self.queue_weapon = 0; Status_Refresh(self); self = oldself; diff --git a/ssqc/player.qc b/ssqc/player.qc index ab5940ae..895675ac 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -571,9 +571,8 @@ void () player_assaultcannondown1 =[103, player_assaultcannondown1] { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); TeamFortress_SetSpeed(self); if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { - self.current_weapon = W_BestWeapon(); - self.current_weaponslot = W_BestWeaponSlot(); W_PrintWeaponMessage(); + W_ChangeToBestWeapon(); return; } player_run(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 709ff91a..5e7a6d23 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -212,9 +212,7 @@ float coop; .float last_weapon; // the last weapon the player was using .float current_weaponslot; // the currently equipped weaponslot .float last_weaponslot; // the last equipped weaponslot -.float queue_weaponslot; // the weaponslot to switch to when possible -.float queue_weaponstate; // the weaponstate to load when possible -.float next_weapon; // used by weapon slots to communicate which weapon to select +.float queue_weapon; // the weapon to switch to when possible // weapon states .float weaponstate_current_weaponslot; @@ -634,7 +632,6 @@ string pause_actor; float unpause_requested; float unpause_countdown; float unpause_lastcountnumber; -float chweap_wait_attfinished; float override_mapclasses; float solid_detpack; float walls_block_emp; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index a144ca1b..9bb3b179 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -498,9 +498,7 @@ void (float issilent, float force) FO_Spy_Feign = { setsize(self, '-16 -16 -24', '16 16 -16'); // set weapon state and remove weapon viewmodel - W_WeaponState_Save(self); - self.weaponmodel = ""; - self.weaponframe = 0; + W_QueueAndDisableWeapon(); // set view height to ground self.view_ofs = '0 0 4'; @@ -603,7 +601,7 @@ void () FO_Spy_Unfeign = { self.feign_areachecked = 0; // load saved weapon state and set current ammo - W_WeaponState_Load(self, 0); + W_UpdateCurrentWeapon(self); // allow spy to move again self.movetype = MOVETYPE_WALK; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2df04c55..7a7e4832 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -340,7 +340,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(W_BestWeaponSlot()); + W_ChangeWeapon(W_BestWeapon()); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; @@ -544,10 +544,11 @@ void () TeamFortress_Inventory = { if (self.tf_items & NIT_SCANNER) sprint(self, PRINT_HIGH, "Scanner\n"); - if (self.weapons_carried & WEAP_MEDIKIT) + float current_weapons = FO_CurrentWeaponsMask(); + if (current_weapons & WEAP_MEDIKIT) sprint(self, PRINT_HIGH, "Medikit\n"); - if (self.weapons_carried & WEAP_DETPACK) { + if (current_weapons & WEAP_DETPACK) { if (self.ammo_detpack > 0) { st = ftos(self.ammo_detpack); sprint(self, PRINT_HIGH, st, " detpack"); @@ -1568,13 +1569,9 @@ void () TeamFortress_SetEquipment = { kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); self.items = FO_ClassWeaponItemMask(self.playerclass) | kept_items; - self.weapons_carried = 0; if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { self.current_weapon = 0; self.last_weapon = 0; - self.current_weaponslot = W_BestWeaponSlot(); - self.last_weaponslot = 2; - W_WeaponState_Save(self); } self.tf_items = 0; @@ -1624,8 +1621,6 @@ void () TeamFortress_SetEquipment = { self.lives = -1; if (self.playerclass == PC_SCOUT) { - self.weapons_carried = self.weapons_carried | PC_SCOUT_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SCOUT_MAXAMMO_ROCKET; self.ammo_nails = PC_SCOUT_MAXAMMO_NAIL; @@ -1684,11 +1679,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_SCOUT_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_NAILGUN; } else if (self.playerclass == PC_SNIPER) { - self.weapons_carried = self.weapons_carried | PC_SNIPER_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SNIPER_MAXAMMO_ROCKET; self.ammo_nails = PC_SNIPER_MAXAMMO_NAIL; @@ -1738,11 +1729,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_SNIPER_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_SNIPER_RIFLE; } else if (self.playerclass == PC_SOLDIER) { - self.weapons_carried = self.weapons_carried | PC_SOLDIER_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET; self.ammo_nails = PC_SOLDIER_MAXAMMO_NAIL; @@ -1804,11 +1791,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 200; else self.maxarmor = PC_SOLDIER_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_ROCKET_LAUNCHER; } else if (self.playerclass == PC_DEMOMAN) { - self.weapons_carried = self.weapons_carried | PC_DEMOMAN_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET; self.ammo_nails = PC_DEMOMAN_MAXAMMO_NAIL; @@ -1861,11 +1844,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 120; else self.maxarmor = PC_DEMOMAN_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_GRENADE_LAUNCHER; } else if (self.playerclass == PC_MEDIC) { - self.weapons_carried = self.weapons_carried | PC_MEDIC_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_MEDIC_MAXAMMO_ROCKET; self.ammo_nails = PC_MEDIC_MAXAMMO_NAIL; @@ -1920,8 +1899,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 100; else self.maxarmor = PC_MEDIC_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_SUPER_NAILGUN; self.ammo_medikit = PC_MEDIC_INITAMMO_MEDIKIT; self.maxammo_medikit = PC_MEDIC_MAXAMMO_MEDIKIT; @@ -1944,8 +1921,6 @@ void () TeamFortress_SetEquipment = { te.owner = self; te.classname = "timer"; } else if (self.playerclass == PC_HVYWEAP) { - self.weapons_carried = self.weapons_carried | PC_HVYWEAP_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET; self.ammo_nails = PC_HVYWEAP_MAXAMMO_NAIL; @@ -2001,11 +1976,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = max_armor_hwguy; } - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_SUPER_SHOTGUN; } else if (self.playerclass == PC_PYRO) { - self.weapons_carried = self.weapons_carried | PC_PYRO_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_PYRO_MAXAMMO_ROCKET; self.ammo_nails = PC_PYRO_MAXAMMO_NAIL; @@ -2054,11 +2025,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 150; else self.maxarmor = PC_PYRO_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_FLAMETHROWER; } else if (self.playerclass == PC_CIVILIAN) { - self.weapons_carried = self.weapons_carried | PC_CIVILIAN_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_CIVILIAN_MAXAMMO_ROCKET; self.ammo_nails = PC_CIVILIAN_MAXAMMO_NAIL; @@ -2108,11 +2075,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 0; else self.maxarmor = PC_CIVILIAN_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_AXE; } else if (self.playerclass == PC_SPY) { - self.weapons_carried = self.weapons_carried | PC_SPY_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_SPY_MAXAMMO_ROCKET; self.ammo_nails = PC_SPY_MAXAMMO_NAIL; @@ -2164,8 +2127,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 100; else self.maxarmor = PC_SPY_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_TRANQ; if (invis_only == 1) { te = spawn(); @@ -2175,8 +2136,6 @@ void () TeamFortress_SetEquipment = { te.classname = "timer"; } } else if (self.playerclass == PC_ENGINEER) { - self.weapons_carried = self.weapons_carried | PC_ENGINEER_WEAPONS; - if (spawnfull) { self.ammo_rockets = PC_ENGINEER_MAXAMMO_ROCKET; self.ammo_nails = PC_ENGINEER_MAXAMMO_NAIL; @@ -2227,8 +2186,6 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 50; else self.maxarmor = PC_ENGINEER_MAXARMOR; - if (self.last_playerclass != self.playerclass) - self.current_weapon = WEAP_RAILGUN; } else if (self.playerclass == PC_UNDEFINED) { self.ammo_rockets = 0; @@ -2248,7 +2205,6 @@ void () TeamFortress_SetEquipment = { self.armorvalue = 0; self.weapon = 0; self.current_weapon = 0; - self.weapons_carried = 0; self.flags = FL_CLIENT | FL_NOTARGET; self.waterlevel = 3; @@ -2280,9 +2236,10 @@ void () TeamFortress_SetEquipment = { self.items = self.items | IT_ARMOR1; if (self.last_playerclass != self.playerclass) - self.current_weaponslot = W_BestWeaponSlot(); - - W_UpdateCurrentWeapon(self); + W_ChangeToBestWeapon(); + else + W_UpdateCurrentWeapon(self); + self.last_playerclass = self.playerclass; }; float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo = { @@ -2828,7 +2785,7 @@ void () TeamFortress_AssaultWeapon = { if (self.tfstate & TFSTATE_RELOADING) return; - if (!(self.weapons_carried & WEAP_ASSAULT_CANNON)) + if (FO_CurrentWeaponsMask() & WEAP_ASSAULT_CANNON == 0) return; if (self.heat > 0) { @@ -2846,7 +2803,7 @@ void () TeamFortress_AssaultWeapon = { self.antispam_assault_cannon = time + 3; return; } - self.current_weapon = WEAP_ASSAULT_CANNON; + W_ChangeWeapon(WEAP_ASSAULT_CANNON); }; void () TeamFortress_ExplodePerson = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 749cdaf7..ef9cfee6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -12,8 +12,8 @@ void () OldConcussionGrenadeTimer; void (float inp) W_ChangeWeapon; void () W_ChangeToBestWeapon; -void (float slot) W_WeaponSlot; -void (entity pl) W_WeaponState_Save; +float (float slot) W_WeaponBySlot; +float (float impulse) W_WeaponByImpulse; void () W_PrintWeaponMessage; void () button_fire; @@ -107,10 +107,8 @@ void () TeamFortress_NailGrenInfo; void () BioInfection_Decay; void () BioInfection_MonsterDecay; -void (entity pl, float swap) W_WeaponState_Load; float (float weap) W_GetSlot; float (float weap) W_OldGetSlot; -float () W_BestWeaponSlot; void () W_FireFlame; void () W_FireIncendiaryCannon; void () W_FireTranq; @@ -130,11 +128,11 @@ void () StartTimer; void () ToggleInvincibility; -float () GetLastWeaponImpulse; +float () GetMaxWeaponInput; float () IsUsingOldImpulses; float () IsUsingCFImpulses; -void (float inp) W_OldWeaponSlot; +float (float impulse) W_WeaponByImpulse; void (entity pl) W_UpdateCurrentWeapon; @@ -1571,11 +1569,10 @@ void (entity pl) W_UpdateCurrentWeapon = { pl.items |= (wi->items)->ammo_mask; pl.weapon = (wi->items)->it_weapon; - if (pl.tfstate & TFSTATE_RELOADING == 0 || pl.is_feigning) { + if ((pl.tfstate & TFSTATE_RELOADING == 0) && !pl.is_feigning) pl.weaponmodel = (wi->models)->model; - } else { + else pl.weaponmodel = ""; - } pl.weaponframe = 0; // refresh engineer build menu when ammo updated @@ -1590,9 +1587,9 @@ void (entity pl) W_UpdateCurrentWeapon = { }; float () W_BestWeapon = { - local float it; + float it = FO_CurrentWeaponsMask(); - it = self.weapons_carried; + // TODO: Clean-up this at some point. It at least works with WEAPs. if ((self.ammo_cells >= 1 && it & WEAP_LIGHTNING) && self.waterlevel <= 1) return WEAP_LIGHTNING; else if ((self.ammo_cells >= 7 && self.ammo_shells >= 1) && it & WEAP_ASSAULT_CANNON) @@ -1631,32 +1628,8 @@ float () W_BestWeapon = { return 0; }; -float () W_BestWeaponSlot = { - local float weap; - - weap = W_BestWeapon(); - - if (!IsUsingOldImpulses()) - return W_GetSlot(weap); - else - return W_OldGetSlot(weap); -}; - void () W_ChangeToBestWeapon = { - local float slot = W_BestWeaponSlot(); - - if (!IsUsingOldImpulses()) - W_WeaponSlot(slot); - else - W_OldWeaponSlot(slot); - - //self.last_weaponslot = self.current_weaponslot; - //self.last_weapon = self.current_weapon; - self.current_weaponslot = slot; - self.current_weapon = self.next_weapon; - W_UpdateCurrentWeapon(self); - W_WeaponState_Save(self); - W_PrintWeaponMessage(); + W_ChangeWeapon(W_BestWeapon()); } void () player_axe1; @@ -1777,9 +1750,7 @@ void () W_Attack = { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); self.antispam_assault_cannon = time + 3; } - W_ChangeWeapon(W_BestWeaponSlot()); - W_UpdateCurrentWeapon(self); - W_WeaponState_Save(self); + W_ChangeToBestWeapon(); } else { self.ammo_cells = self.ammo_cells - 7; self.heat = 1; @@ -2069,548 +2040,168 @@ float (float inp) W_OldAmmoSlot = { return 1; }; -float () W_OldWeaponSlot1 = { - if (self.weapons_carried & WEAP_MEDIKIT) - return WEAP_MEDIKIT; - else if (self.weapons_carried & WEAP_KNIFE) - return WEAP_KNIFE; - else if (self.weapons_carried & WEAP_SPANNER) - return WEAP_SPANNER; - else - return WEAP_AXE; -}; - -float () W_OldWeaponSlot2 = { - if (self.playerclass == PC_SCOUT - ||self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO) - return WEAP_SHOTGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_SNIPER_RIFLE; - else if (self.playerclass == PC_SPY) - return WEAP_TRANQ; - else if (self.playerclass == PC_ENGINEER) - return WEAP_RAILGUN; - return 0; -}; - -float () W_OldWeaponSlot3 = { - if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - return WEAP_SUPER_SHOTGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_AUTO_RIFLE; - return 0; -}; - -float () W_OldWeaponSlot4 = { - if (self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - return WEAP_NAILGUN; - return 0; -}; - -float () W_OldWeaponSlot5 = { - if (self.playerclass == PC_MEDIC) - return WEAP_SUPER_NAILGUN; - else if (self.playerclass == PC_PYRO) - return WEAP_FLAMETHROWER; - return 0; -}; - -float () W_OldWeaponSlot6 = { - if (self.playerclass == PC_DEMOMAN) - return WEAP_GRENADE_LAUNCHER; - else if (self.playerclass == PC_PYRO) - return WEAP_FLAMETHROWER; - return 0; -}; - -float () W_OldWeaponSlot7 = { - if (self.playerclass == PC_SOLDIER) - return WEAP_ROCKET_LAUNCHER; - if (self.playerclass == PC_DEMOMAN) - return WEAP_PIPE_LAUNCHER; - else if (self.playerclass == PC_HVYWEAP) - return WEAP_ASSAULT_CANNON; - else if (self.playerclass == PC_PYRO) - return WEAP_INCENDIARY; - return 0; -}; - -float () W_WeaponSlot1 = { - local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - if (self.playerclass == PC_SCOUT) - return WEAP_NAILGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_SNIPER_RIFLE; - else if (self.playerclass == PC_SOLDIER) - return WEAP_ROCKET_LAUNCHER; - else if (self.playerclass == PC_DEMOMAN) - return WEAP_GRENADE_LAUNCHER; - else if (self.playerclass == PC_MEDIC) - return WEAP_SUPER_NAILGUN; - else if (self.playerclass == PC_HVYWEAP) - return WEAP_ASSAULT_CANNON; - else if (self.playerclass == PC_PYRO) - if (cf_pyro_impulses) { - return WEAP_FLAMETHROWER; - } else { - return WEAP_INCENDIARY; - } - else if (self.playerclass == PC_SPY) - return WEAP_TRANQ; - else if (self.playerclass == PC_ENGINEER) - return WEAP_RAILGUN; - return 0; -}; +struct ImpulseWeapons { + int class; + float weapons[7]; +}; + +static ImpulseWeapons impulse_weapons[] = { + { PC_UNDEFINED, { WEAP_AXE } }, + { PC_SCOUT, + { WEAP_AXE, WEAP_SHOTGUN, 0, WEAP_NAILGUN } }, + { PC_SNIPER, + { WEAP_AXE, WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN } }, + { PC_SOLDIER, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, + { PC_DEMOMAN, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, + { PC_MEDIC, + { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, + { PC_HVYWEAP, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, + { PC_PYRO, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, + { PC_SPY, + { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, + { PC_ENGINEER, + { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, + { PC_CIVILIAN, { WEAP_AXE } }, +}; + +float W_WeaponByImpulse(float impulse) { + if (impulse <= 1 || impulse >= 7) return 0; + return impulse_weapons[self.playerclass].weapons[impulse - 1]; +} -float () W_WeaponSlot2 = { - local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - if (self.playerclass == PC_SCOUT) - return WEAP_SHOTGUN; - else if (self.playerclass == PC_SNIPER) - return WEAP_AUTO_RIFLE; - else if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - return WEAP_SUPER_SHOTGUN; - else if (self.playerclass == PC_DEMOMAN) { - return WEAP_PIPE_LAUNCHER; - } else if (self.playerclass == PC_PYRO) - if (cf_pyro_impulses) { - return WEAP_INCENDIARY; - } else { - return WEAP_FLAMETHROWER; - } - return 0; -}; +static float HandlePyroSlotSwap(float slot) { + float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); + if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) + slot = 3 - slot; + return slot; +} -float () W_WeaponSlot3 = { - if (self.playerclass == PC_SCOUT - || self.playerclass == PC_ENGINEER) { +float W_WeaponBySlot(float slot) { + FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, + HandlePyroSlotSwap(slot)); + if (!wi) { sprint(self, PRINT_HIGH, "No weapon\n"); return 0; } - if (self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - return WEAP_NAILGUN; - else if (self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO) - return WEAP_SHOTGUN; - return 0; -}; - -float () W_WeaponSlot4 = { - if (self.weapons_carried & WEAP_MEDIKIT) - return WEAP_MEDIKIT; - else if (self.weapons_carried & WEAP_KNIFE) - return WEAP_KNIFE; - else if (self.weapons_carried & WEAP_SPANNER) - return WEAP_SPANNER; - else - return WEAP_AXE; -}; - -void (float slot) W_WeaponSlot = { - if (slot == 1) - self.next_weapon = W_WeaponSlot1(); - else if (slot == 2) { - self.next_weapon = W_WeaponSlot2(); - } - else if (slot == 3) - self.next_weapon = W_WeaponSlot3(); - else if (slot == 4) - self.next_weapon = W_WeaponSlot4(); -}; - -void (float inp) W_OldWeaponSlot = { - if (inp == TF_SLOT1) { - self.next_weapon = W_OldWeaponSlot1(); - } - else if (inp == TF_SLOT2) { - self.next_weapon = W_OldWeaponSlot2(); - } - else if (inp == TF_SLOT3) { - self.next_weapon = W_OldWeaponSlot3(); - } - else if (inp == TF_SLOT4) { - self.next_weapon = W_OldWeaponSlot4(); - } - else if (inp == 5) { - self.next_weapon = W_OldWeaponSlot5(); - } - else if (inp == 6) { - self.next_weapon = W_OldWeaponSlot6(); - } - else if (inp == 7) { - self.next_weapon = W_OldWeaponSlot7(); - } - if (self.next_weapon == 0) { - self.next_weapon = self.current_weapon; - sprint(self, PRINT_HIGH, "No weapon\n"); - } + return wi->weapon; } -float (float newSlot) W_OldImpulseFromNewSlot = { - if (newSlot == 1) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_SNIPER_RIFLE); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_ROCKET_LAUNCHER); - } - else if (self.playerclass == PC_DEMOMAN) { - return 6; - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_SUPER_NAILGUN); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_ASSAULT_CANNON); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_INCENDIARY); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_TRANQ); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_RAILGUN); - } - } - else if (newSlot == 2) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_AUTO_RIFLE); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_DEMOMAN) { - return 7; - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_FLAMETHROWER); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_SUPER_SHOTGUN); - } - } - else if (newSlot == 3) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_DEMOMAN) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_SHOTGUN); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_NAILGUN); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_RAILGUN); - } - } - else if (newSlot == 4) { - if (self.playerclass == PC_SCOUT) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_SNIPER) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_SOLDIER) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_DEMOMAN) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_MEDIC) { - return W_OldGetSlot(WEAP_MEDIKIT); - } - else if (self.playerclass == PC_HVYWEAP) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_PYRO) { - return W_OldGetSlot(WEAP_AXE); - } - else if (self.playerclass == PC_SPY) { - return W_OldGetSlot(WEAP_KNIFE); - } - else if (self.playerclass == PC_ENGINEER) { - return W_OldGetSlot(WEAP_SPANNER); - } - } - return 0; +float W_GetWeaponByInput(float input) { + if (IsUsingOldImpulses()) + return W_WeaponByImpulse(input); + else + return W_WeaponBySlot(input); } -void () W_AmmoError = { +static void W_AmmoError() { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); else if (self.noammo == 2 && time >= self.antispam_assault_cannon) { sprint(self, PRINT_HIGH, "Not enough cells to power the assault cannon\n"); self.antispam_assault_cannon = time + 3; } -}; +} -void (entity pl) W_WeaponState_Save = { - if (!WeaponReady(pl)) +void W_ChangeWeaponByInput(float input) { + if (input < 1 || input > GetMaxWeaponInput()) return; - pl.weaponstate_current_weaponslot = pl.current_weaponslot; - pl.weaponstate_last_weaponslot = pl.last_weaponslot; - pl.weaponstate_current_weapon = pl.current_weapon; - pl.weaponstate_last_weapon = pl.last_weapon; -} - -void (entity pl, float swap) W_WeaponState_Load = { - if (!swap) { - pl.current_weaponslot = pl.weaponstate_current_weaponslot; - pl.last_weaponslot = pl.weaponstate_last_weaponslot; - pl.current_weapon = pl.weaponstate_current_weapon; - pl.last_weapon = pl.weaponstate_last_weapon; - } else { - pl.current_weaponslot = pl.weaponstate_last_weaponslot; - pl.last_weaponslot = pl.weaponstate_current_weaponslot; - pl.current_weapon = pl.weaponstate_last_weapon; - pl.last_weapon = pl.weaponstate_current_weapon; - } - pl.queue_weaponstate = 0; + float weapon = W_GetWeaponByInput(input); + if (weapon == 0) + return; - W_WeaponState_Save(pl); - W_UpdateCurrentWeapon(pl); - Status_Refresh(pl); + W_ChangeWeapon(weapon); } -float (entity pl) W_WeaponState_Check = { - // bprint(2,ftos(pl.current_weaponslot == pl.weaponstate_current_weaponslot)); - //bprint(2,"\n"); - if (pl.current_weaponslot == pl.weaponstate_current_weaponslot - && pl.last_weaponslot == pl.weaponstate_last_weaponslot) - return 1; - else - return 0; +void W_QueueAndDisableWeapon() { + self.queue_weapon = self.current_weapon; + // We don't want to actually call Update/Change since that could affect what + // other players see. Caller should be setting some state that holds back + // the queue (e.g. feigned). + self.current_weapon = WEAP_NONE; + self.weaponmodel = ""; + self.weaponframe = 0; } -void (float inp) W_ChangeWeapon = { - if(self.playerclass == PC_CIVILIAN) { - inp = TF_SLOT4; - } - - if (inp < TF_SLOT1 || inp > GetLastWeaponImpulse()) - return; - +void W_ChangeWeapon(float weapon) { if (self.playerclass == 0) return; // queue next weapon if queue is not empty or has changed - if (!self.queue_weaponslot || inp != self.queue_weaponslot) - self.queue_weaponslot = inp; + if (!self.queue_weapon || weapon != self.queue_weapon) + self.queue_weapon = weapon; // halt if weapon is not ready to be fired - if (!WeaponReady(self) && chweap_wait_attfinished) + if (!WeaponReady(self)) return; - - if (IsUsingOldImpulses()) { - if(self.playerclass == PC_CIVILIAN) { - inp = TF_SLOT1; - } - // check for ammo - if (! W_OldAmmoSlot(inp)) { - W_AmmoError(); - self.queue_weaponslot = 0; - return; - } - W_OldWeaponSlot(inp); - } - else { - // check for ammo - if (! W_AmmoSlot(inp)) { - W_AmmoError(); - self.queue_weaponslot = 0; - return; - } - W_WeaponSlot(inp); - } + self.queue_weapon = 0; - // don't update current/last weapon information if next weapon is the same as current - if (self.current_weapon != self.next_weapon) { - self.last_weaponslot = self.current_weaponslot; - self.current_weaponslot = self.queue_weaponslot; - self.last_weapon = self.current_weapon; - self.current_weapon = self.next_weapon; + FO_WeapState ws; + FO_FillWeapState(self, weapon, &ws); - if (!self.is_quickfiring) - W_PrintWeaponMessage(); + if (*ws->ammo_remaining == 0) { + W_AmmoError(); + return; } - if (!self.is_quickfiring && !self.has_quickfired) - W_WeaponState_Save(self); + if (self.current_weapon == weapon) + return; + + self.last_weapon = self.current_weapon; + + if (!self.is_quickfiring) + W_PrintWeaponMessage(); + self.current_weapon = weapon; W_UpdateCurrentWeapon(self); Status_Refresh(self); - self.queue_weaponslot = 0; }; -void () CycleWeaponLast = { - if (!self.last_weaponslot) +void W_ChangeWeaponLast() { + if (self.last_weapon == 0) return; - if (!self.is_quickfiring) - W_ChangeWeapon(self.last_weaponslot); - else - W_WeaponState_Load(self, 1); + W_ChangeWeapon(self.last_weapon); }; -void () CycleWeaponNext = { - local float slot, next; +float W_FindPrevNextWeapon(float weapon, float is_prev) { + int i; + float *table = IsUsingOldImpulses() ? + impulse_weapons[self.playerclass].weapons : + class_weapons[self.playerclass].slots; - if (self.weaponmodel == string_null || self.current_weapon == 0) - return; + float len = GetMaxWeaponInput(); + for (i = 0; i < len; i++) + if (table[i] == weapon) + break; - next = 0; - if (!IsUsingOldImpulses()) { - for (slot = 1; slot <= 4; slot++) { - next = (slot == 4) ? 1 : (slot + 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 4) ? 1 : (next + 1); - break; - } - } - } - else if (IsUsingOldImpulses()) { - for (slot = self.current_weaponslot; slot <= GetLastWeaponImpulse(); slot++) { - next = (slot == GetLastWeaponImpulse()) ? 1 : (slot + 1); - if (next == 1) { - if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) - break; - } - else if (next == 2) { - if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) - break; - } - else if (next == 3) { - if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) - break; - } - else if (next == 4) { - if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) - break; - } - else if (next == 5) { - if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) - break; - } - else if (next == 6) { - if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) - break; - } - else if (next == 7) { - if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) - break; - } - } - } - W_ChangeWeapon(next); -}; + float direction = is_prev ? -1 : 1; + do { + i = (i + direction + len) % len; + } while (table[i] == 0); -void () CycleWeaponPrev = { - local float slot, next; + return table[i]; +} +void W_ChangeWeaponNext() { if (self.weaponmodel == string_null || self.current_weapon == 0) return; - next = 0; - if (!IsUsingOldImpulses()) { - for (slot = 1; slot <= 4; slot++) { - next = (slot == 1) ? 4 : (slot - 1); - if (self.current_weaponslot == slot) { - while (! W_AmmoSlot(next)) - next = (next == 1) ? 4 : (next - 1); - break; - } - } - } - else { - for (slot = self.current_weaponslot; slot >= 1; slot--) { - next = (slot == 1) ? GetLastWeaponImpulse() : (slot - 1); - if (next == 1) { - if (W_OldWeaponSlot1() && W_OldAmmoSlot(next)) - break; - } - else if (next == 2) { - if (W_OldWeaponSlot2() && W_OldAmmoSlot(next)) - break; - } - else if (next == 3) { - if (W_OldWeaponSlot3() && W_OldAmmoSlot(next)) - break; - } - else if (next == 4) { - if (W_OldWeaponSlot4() && W_OldAmmoSlot(next)) - break; - } - else if (next == 5) { - if (W_OldWeaponSlot5() && W_OldAmmoSlot(next)) - break; - } - else if (next == 6) { - if (W_OldWeaponSlot6() && W_OldAmmoSlot(next)) - break; - } - else if (next == 7) { - if (W_OldWeaponSlot7() && W_OldAmmoSlot(next)) - break; - } - } - } - + W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, FALSE)); +} - W_ChangeWeapon(next); -}; +void W_ChangeWeaponPrev() { + if (self.weaponmodel == string_null || self.current_weapon == 0) + return; + + W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, TRUE)); +} void () PreMatchImpulses; void () DeadImpulses; @@ -2660,19 +2251,19 @@ void () ImpulseCommands = { CF_Spy_DisguiseStop(); else if (self.playerclass == PC_ENGINEER && self.is_building) { TeamFortress_EngineerBuildStop(); - CycleWeaponLast(); + W_ChangeWeaponLast(); } else if (self.playerclass == PC_DEMOMAN && self.is_detpacking) { TeamFortress_DetpackStop(); - CycleWeaponLast(); + W_ChangeWeaponLast(); } } else if (self.impulse == TF_TOGGLEVOTE) Vote_ToggleMenu(self); if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { if (self.impulse == TF_WEAPNEXT) - CycleWeaponNext(); + W_ChangeWeaponNext(); else if (self.impulse == TF_WEAPPREV) - CycleWeaponPrev(); + W_ChangeWeaponPrev(); else if (self.impulse == TF_RELOAD) TeamFortress_ReloadCurrentWeapon(); else if (self.impulse == TF_RELOAD_SLOT1) @@ -2824,9 +2415,9 @@ void () ImpulseCommands = { void () PreMatchImpulses = { if (self.impulse == TF_WEAPNEXT) - CycleWeaponNext(); + W_ChangeWeaponNext(); else if (self.impulse == TF_WEAPPREV) - CycleWeaponPrev(); + W_ChangeWeaponPrev(); if (self.impulse == TF_INVENTORY) TeamFortress_Inventory(); @@ -3210,16 +2801,9 @@ void () W_WeaponFrame = { return; if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { - - // change to last weapon now - if (WeaponReady(self)) - CycleWeaponLast(); - // change to weaponstate (prior to quick fire) when weapon is ready - else if (self.is_quickfiring) - self.queue_weaponstate = 2; - // change to last weapon when weapon is ready - else - self.queue_weaponslot = self.last_weaponslot; + W_ChangeWeaponLast(); + self.impulse = 0; + return; } // when +slotX bind is released, this gets issued @@ -3237,73 +2821,31 @@ void () W_WeaponFrame = { self.has_quickfired = 0; } + float can_change_weapon = WeaponReady(self) && + !self.is_detpacking && !(self.is_building && !engineer_move); - // slot 1-4 (or 1-7) binds - if (self.impulse >= 1 && self.impulse <= GetLastWeaponImpulse() && (WeaponReady(self) || !chweap_wait_attfinished) - && !(self.is_building && !engineer_move) && !self.is_detpacking) { - - if (!(self.tfstate & TFSTATE_RELOADING)) { - // load weapon state if current state doesn't match stored state - if (!W_WeaponState_Check(self)) - W_WeaponState_Load(self, 0); - - // obviously not quickfiring if we're changing weapon - self.is_quickfiring = 0; - self.has_quickfired = 0; - W_ChangeWeapon(self.impulse); - } - else if (!chweap_wait_attfinished) { - //clears impulse so it doesn't switch weapons just after reloading - self.impulse = 0; - } - - // regular attack (both +attack and -attack) - } else if (!self.impulse && !self.is_quickfiring) { + if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() && + can_change_weapon) { + // slot 1-4 (or 1-7) binds - // load weapon state if current state doesn't match - // stored state, if weapon is ready - if (!W_WeaponState_Check(self) && WeaponReady(self) && !(self.tfstate & TFSTATE_AIMING)) { - W_WeaponState_Load(self, 0); - } + // obviously not quickfiring if we're changing weapon + self.is_quickfiring = 0; + self.has_quickfired = 0; + W_ChangeWeaponByInput(self.impulse); + self.impulse = 0; + } else if (self.impulse >= TF_QUICKSLOT1 && + self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { // +slot1-4 quick fire - } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && !self.is_detpacking) { self.is_quickfiring = 1; self.has_quickfired = 0; - if (WeaponReady(self)) { - if (!IsUsingOldImpulses()) { - if (self.impulse == TF_QUICKSLOT1) - W_ChangeWeapon(1); - else if (self.impulse == TF_QUICKSLOT2) - W_ChangeWeapon(2); - else if (self.impulse == TF_QUICKSLOT3) - W_ChangeWeapon(3); - else if (self.impulse == TF_QUICKSLOT4) - W_ChangeWeapon(4); - } else { - if (self.impulse == TF_QUICKSLOT1) - W_ChangeWeapon(W_OldImpulseFromNewSlot(1)); - else if (self.impulse == TF_QUICKSLOT2) - W_ChangeWeapon(W_OldImpulseFromNewSlot(2)); - else if (self.impulse == TF_QUICKSLOT3) - W_ChangeWeapon(W_OldImpulseFromNewSlot(3)); - else if (self.impulse == TF_QUICKSLOT4) - W_ChangeWeapon(W_OldImpulseFromNewSlot(4)); - } - } - + // Manually check so that we don't queue otherwise. + if (self.tfstate & TFSTATE_RELOADING) + W_ChangeWeapon(W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1)); + } else if (self.queue_weapon > 0 && can_change_weapon) { // change weapon if queue_weaponslot has been set - } else if (self.queue_weaponslot > 0) { - W_ChangeWeapon(self.queue_weaponslot); - // load weapon state - } else if (self.queue_weaponstate && WeaponReady(self)) { - // load weaponstate saved from before quick fire started - if (self.queue_weaponstate == 1) - W_WeaponState_Load(self, 0); - // load swapped weaponstate - else - W_WeaponState_Load(self, 1); + W_ChangeWeapon(self.queue_weapon); } if (self.impulse == TF_CHANGETEAM) { From fcd4a5453a6df73ce11bbda5ab50a4d570447cf0 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 02:00:58 -0700 Subject: [PATCH 1747/2474] All of the quickfire stuff had gotten pretty messy, it's not needed now that weapon queuing just works. Rip it out. --- ssqc/qw.qc | 3 +-- ssqc/weapons.qc | 40 +++++++++++----------------------------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 5e7a6d23..3759b39e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -48,9 +48,8 @@ float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in -.float is_quickfiring; // TRUE for a player if they're using the quick slots .float is_concussed; // TRUE for a player who is affected by concussion grenade -.float has_quickfired; // TRUE for a player that has stopped quick firing (until weapon is ready) +.float qf_swap_last_weapon; // TRUE if +slotX was initated from another slot .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team .float has_changedclass; // TRUE for a player that has changed class diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ef9cfee6..b2aa72ff 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2155,9 +2155,6 @@ void W_ChangeWeapon(float weapon) { self.last_weapon = self.current_weapon; - if (!self.is_quickfiring) - W_PrintWeaponMessage(); - self.current_weapon = weapon; W_UpdateCurrentWeapon(self); Status_Refresh(self); @@ -2806,43 +2803,28 @@ void () W_WeaponFrame = { return; } - // when +slotX bind is released, this gets issued - if (self.impulse == TF_QUICKSTOP && self.is_quickfiring) { - - self.has_quickfired = 1; - self.impulse = 0; - - } - - // unset quick firing variables when quick weapon has finished firing - if (self.is_quickfiring && self.has_quickfired && WeaponReady(self)) { + // +slot/-slot handle attack; we only need to swap back to last weapon. + // Let's see if we can get away with just treating this as last weapon; + // there were already so many edge cases in the old code such as swapping on + // an empty weapon. + if (self.impulse == TF_QUICKSTOP) + self.impulse = self.qf_swap_last_weapon ? TF_WEAPLAST : 0; - self.is_quickfiring = 0; - self.has_quickfired = 0; - - } float can_change_weapon = WeaponReady(self) && !self.is_detpacking && !(self.is_building && !engineer_move); + // TODO: Open up queueing by moving queue can_change to ChangeWeapon? if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() && can_change_weapon) { // slot 1-4 (or 1-7) binds - - // obviously not quickfiring if we're changing weapon - self.is_quickfiring = 0; - self.has_quickfired = 0; - W_ChangeWeaponByInput(self.impulse); self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - // +slot1-4 quick fire - self.is_quickfiring = 1; - self.has_quickfired = 0; - - // Manually check so that we don't queue otherwise. - if (self.tfstate & TFSTATE_RELOADING) - W_ChangeWeapon(W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1)); + float weapon = W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1); + self.qf_swap_last_weapon = weapon != self.current_weapon; + W_ChangeWeapon(weapon); + self.impulse = 0; } else if (self.queue_weapon > 0 && can_change_weapon) { // change weapon if queue_weaponslot has been set W_ChangeWeapon(self.queue_weapon); From e3125a8a184d38e8ee4e1448403172173c2487bb Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 02:22:41 -0700 Subject: [PATCH 1748/2474] Make detpacks work again. Just use ammo check rather than carried_items. --- ssqc/demoman.qc | 20 ++++---------------- ssqc/tfort.qc | 14 ++++++-------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 181b6b07..0dee0066 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -158,11 +158,6 @@ void (float timer) TeamFortress_SetDetpack = { self.impulse = 0; self.last_impulse = 0; - if (!(self.weapons_carried & WEAP_DETPACK)) { - sprint(self, PRINT_HIGH, "You don't have a detpack\n"); - return; - } - if (self.ammo_detpack <= 0) { sprint(self, PRINT_HIGH, "You don't have any detpacks left\n"); return; @@ -224,12 +219,9 @@ void (float timer) TeamFortress_SetDetpack = { self.ammo_detpack = self.ammo_detpack - 1; self.immune_to_check = time + 10; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - self.weapon = IT_AXE; - self.queue_weapon = self.current_weapon; - self.current_weapon = 0; - self.weaponmodel = ""; - self.weaponframe = 0; + self.weapon = IT_AXE; + W_QueueAndDisableWeapon(); Status_Refresh(self); TeamFortress_SetSpeed(self); @@ -266,10 +258,8 @@ void () TeamFortress_DetpackStop = { dremove(detpack_timer); self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - self.is_detpacking = 0; + self.is_detpacking = 0; // Weapon is queued. self.detpack_left = 0; - self.current_weapon = self.queue_weapon; - self.queue_weapon = 0; Status_Refresh(self); TeamFortress_SetSpeed(self); @@ -294,9 +284,7 @@ void () TeamFortress_DetpackSet = { FO_Sound(self.owner, CHAN_VOICE, "doors/medtry.wav", 1, ATTN_NORM); oldself = self; self = self.owner; - self.is_detpacking = 0; - self.current_weapon = self.queue_weapon; - self.queue_weapon = 0; + self.is_detpacking = 0; // Weapon is queued. Status_Refresh(self); self = oldself; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 7a7e4832..d6fac766 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -548,14 +548,12 @@ void () TeamFortress_Inventory = { if (current_weapons & WEAP_MEDIKIT) sprint(self, PRINT_HIGH, "Medikit\n"); - if (current_weapons & WEAP_DETPACK) { - if (self.ammo_detpack > 0) { - st = ftos(self.ammo_detpack); - sprint(self, PRINT_HIGH, st, " detpack"); - if (self.ammo_detpack > 1) - sprint(self, PRINT_HIGH, "s"); - sprint(self, PRINT_HIGH, "\n"); - } + if (self.ammo_detpack > 0) { + st = ftos(self.ammo_detpack); + sprint(self, PRINT_HIGH, st, " detpack"); + if (self.ammo_detpack > 1) + sprint(self, PRINT_HIGH, "s"); + sprint(self, PRINT_HIGH, "\n"); } if (self.playerclass == PC_SPY && invis_only) { From e95a0cb40d6a717147ac7e0aa2edb4870798b85d Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 22:52:41 -0700 Subject: [PATCH 1749/2474] Fix attack_finished nits A few weapons implement attacks via the animation code, namely the assault cannon, and both nailguns. While this had no interaction with the nailguns, as their own animation code was setting the same attack_finished values, this was causing problems with the assault cannon that uses out of band synchronization around spin-up/spin-down. For completeness, exclude all 3 from setting attack-finished. At some point nailguns can probably have it pulled out of the animation code but that's a question for another day (might matter for NG more than SNG). --- ssqc/hwguy.qc | 1 - ssqc/weapons.qc | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 174debaa..23336746 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -116,7 +116,6 @@ void FireAssCan (float shotcount, vector dir, vector spread) FO_WeapState ws; FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); - Status_Refresh(self); FO_CheckForReload(); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index b2aa72ff..8cb4b995 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1791,7 +1791,10 @@ void () W_Attack = { W_FireLaser(); } - if (self.current_weapon != WEAP_FLAMETHROWER) + if (self.current_weapon != WEAP_FLAMETHROWER && // Variable + self.current_weapon != WEAP_ASSAULT_CANNON && // In animation + self.current_weapon != WEAP_NAILGUN && // In animation + self.current_weapon != WEAP_SUPER_NAILGUN) // In animation Attack_Finished(wi->attack_time); if (wi->needs_reload) { From a3accc26d2518eb5ef086adc38406a16059d4ec0 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 27 Sep 2022 23:32:47 -0700 Subject: [PATCH 1750/2474] Fix weapon nits - Autorifle wasn't on the right slot for sniper - NG/SNG had bugs in both new and old code with attack finished interactions on running out of ammo (in the old code the animation would keep generating muzzle flashes, in the new code it would stop firing but not switch). Now properly works. - There was a ton of spaghetti in the old hwguy cannon implementation, missing weapon switches on certain ammo cases, duplication across multiple animation functions. Not all of this seemed to be working right so just rip it all out and rewrite it. Seems good now. --- share/fo_weapons.qc | 18 +++- ssqc/client.qc | 4 +- ssqc/player.qc | 206 ++++++++++++-------------------------------- ssqc/tfort.qc | 5 -- ssqc/weapons.qc | 45 +++++----- 5 files changed, 96 insertions(+), 182 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 86565b33..e2c002d9 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -22,6 +22,7 @@ float fo_hwguy = TRUE; float sniperreload = FALSE; float pyro_type = PYRO_FO; +float old_ng_rof = FALSE; #endif // Convert a weapon-bit to a linear index. @@ -78,13 +79,13 @@ FO_WeapInfo weapon_info[] = { { WEAP_SHOTGUN, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, AMMO_SHELLS, 16, 2, 0.7, 3 }, { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, - { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 4, 0.2, 0 }, + { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 2, 0.2, 0 }, { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, { WEAP_PIPE_LAUNCHER, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0, 4 }, + { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, @@ -94,6 +95,7 @@ FO_WeapInfo weapon_info[] = { inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { return &weapon_info[WEAP_to_index(weapon)]; } + struct FO_ClassWeapons { float id; float slots[4]; @@ -104,7 +106,7 @@ struct FO_ClassWeapons { FO_ClassWeapons class_weapons[] = { { PC_UNDEFINED, { 0, 0, 0, WEAP_AXE } }, { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, - { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_SNIPER_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, + { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_MEDIC, { WEAP_SUPER_NAILGUN, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_MEDIKIT } }, @@ -429,6 +431,14 @@ void FO_Weapons_Init() { WI_ir->attack_time = 0.9; break; } + // Consider just removing this? + if (old_ng_rof) { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_NAILGUN); + wi->ammo_per_shot = 2; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); + wi->ammo_per_shot = 4; + } + float clips_allocated = 0; for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; @@ -470,7 +480,7 @@ void FO_Weapons_Init() { case AMMO_NAILS: wti->ammo_mask = IT_NAILS; break; case AMMO_ROCKETS: wti->ammo_mask = IT_ROCKETS; break; } -} + } if (clips_allocated > CLIP_STORAGE_SIZE) error("Insufficient clip storage"); diff --git a/ssqc/client.qc b/ssqc/client.qc index 5cee5312..c74ade9f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2516,7 +2516,7 @@ void () PlayerJump = { self.weaponframe = 0; self.heat = 0; self.count = 1; - player_assaultcannondown1(); + player_assaultcannondown(); } return; } @@ -2545,7 +2545,7 @@ void () PlayerJump = { self.weaponframe = 0; self.count = 1; self.heat = 0; - player_assaultcannondown1(); + player_assaultcannondown(); } else { self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); diff --git a/ssqc/player.qc b/ssqc/player.qc index 895675ac..8b8277ff 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -387,7 +387,6 @@ void () player_nail1 =[103, player_nail2] { W_FireSpikes(-4); self.nailpos = 0; } - Attack_Finished(0.2); }; void () player_nail2 =[104, player_nail1] { @@ -409,185 +408,94 @@ void () player_nail2 =[104, player_nail1] { self.nailpos = 0; } } - Attack_Finished(0.2); }; -void () player_assaultcannonup1 =[103, player_assaultcannonup2] { - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; +static float CheckNeedAssaultCannonDown() { + FO_WeapState ws; + FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + + if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || + ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { + self.tfstate |= TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.count = 1; - self.heat = 0; - player_assaultcannondown1(); - return; + player_assaultcannondown(); + return TRUE; } + return FALSE; +} +void () player_assaultcannon; + +void () player_assaultcannonup =[103, player_assaultcannonup] { + if (CheckNeedAssaultCannonDown()) + return; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + self.fire_held_down = 1; - if (self.heat == 1) { + if (self.count == 0) FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - } + SuperDamageSound(); - Attack_Finished(0.2); - if ((self.heat != 2) && (self.heat != 4)) { - if (self.weaponframe >= 3) { - self.weaponframe = 0; - } else { - self.weaponframe = self.weaponframe + 1; - } - } - self.heat = self.heat + 1; - if (self.heat >= 7) { - self.heat = 0; - player_assaultcannon1(); - } + if ((self.heat != 2) && (self.heat != 4)) + self.weaponframe = (self.weaponframe + 1) % 4; + + if (self.count++ >= 5) // 600ms spin up + player_assaultcannon(); + else + Attack_Finished(wi->attack_time); }; -void () player_assaultcannonup2 =[103, player_assaultcannonup1] { - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.count = 1; - self.heat = 0; - player_assaultcannondown1(); +void () player_assaultcannon =[103, player_assaultcannon] { + if (CheckNeedAssaultCannonDown()) return; - } - SuperDamageSound(); - Attack_Finished(0.2); - if (((self.heat != 2) && (self.heat != 4)) && (self.heat != 7)) { - if ((self.weaponframe == 2) && (self.heat >= 9)) { - self.weaponframe = 0; - } else { - if (self.weaponframe >= 3) { - self.weaponframe = 0; - } else { - self.weaponframe = self.weaponframe + 1; - } - } - } - self.heat = self.heat + 1; - if (self.heat >= 13) { - self.heat = 0; - player_assaultcannon1(); - } -}; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); -void () player_assaultcannon1 =[103, player_assaultcannon2] { - if (fo_hwguy) - { - if (self.tfstate & TFSTATE_RELOADING || self.reload_assault_cannon == PC_HVYWEAP_ASSCAN_CLIPSIZE) - { - self.count = 1; - player_assaultcannondown1(); - return; + if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) + && !(self.tfstate & TFSTATE_LOCK)) { + if (self.count % 2 == 0) { + muzzleflash(); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); } - } - - if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) <= 30) - && !(self.tfstate & TFSTATE_LOCK)) { - muzzleflash(); - FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - - if (self.weaponframe == 2) - self.weaponframe = 4; - else - self.weaponframe = 2; SuperDamageSound(); + self.weaponframe = self.weaponframe == 2 ? 4 : 2; - self.tfstate = self.tfstate | TFSTATE_AIMING; + self.tfstate |= TFSTATE_AIMING; if (!cannon_move) - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + self.tfstate |= TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); - W_FireAssaultCannon(); + // Halve firing speed when moving too fast. + if (vlen(self.velocity) < 30 || self.count % 2 == 0) + W_FireAssaultCannon(); } else { FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); - - if (self.weaponframe == 2) - self.weaponframe = 0; - else - self.weaponframe = 2; + self.weaponframe = self.weaponframe == 2 ? 0 : 2; } - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - if (!cannon_move) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.count = 1; - player_assaultcannondown1(); - return; - } - Attack_Finished(0.2); -}; - -void () player_assaultcannon2 =[104, player_assaultcannon1] { - if (fo_hwguy) - { - if (self.tfstate & TFSTATE_RELOADING || self.reload_assault_cannon == PC_HVYWEAP_ASSCAN_CLIPSIZE) - { - self.count = 1; - player_assaultcannondown1(); - return; - } - } - if (vlen(self.velocity) < 30 && !(self.tfstate & TFSTATE_LOCK)) { - if (self.weaponframe == 2) { - self.weaponframe = 4; - } else { - self.weaponframe = 2; - } - SuperDamageSound(); - W_FireAssaultCannon(); - self.heat = self.heat + 0.1; - } else { - if (self.weaponframe == 2) { - self.weaponframe = 0; - } else { - self.weaponframe = 2; - } - } - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - if (!cannon_move) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.count = 1; - player_assaultcannondown1(); - return; - } - Attack_Finished(0.2); + self.count++; + Attack_Finished(wi->attack_time); }; -void () player_assaultcannondown1 =[103, player_assaultcannondown1] { - if (self.count == 1) { +void () player_assaultcannondown =[103, player_assaultcannondown] { + if (self.count == 0) FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); - self.heat = 0; - } - if (self.count >= 15) { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if (self.count >= 14) { self.fire_held_down = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_AIMING); + self.tfstate &= ~TFSTATE_AIMING; if (!cannon_move) - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.tfstate &= ~TFSTATE_CANT_MOVE; TeamFortress_SetSpeed(self); - if ((self.ammo_shells < 1) || (self.ammo_cells < 7)) { + + player_run(); + if (self.ammo_cells < 7 || !FO_CheckForReload()) { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); - return; - } - player_run(); - return; - } - if ((((self.count != 8) && (self.count != 10)) && (self.count != 12)) - && (self.count != 14)) { - if (self.weaponframe == 3) { - self.weaponframe = 0; - } else { - self.weaponframe = self.weaponframe + 1; } - } - self.count = self.count + 1; - Attack_Finished(0.2); + } else if (++self.count % 2 == 0) + self.weaponframe = (self.weaponframe + 1) % 4; + Attack_Finished(wi->attack_time); }; void () player_light1 =[105, player_light2] { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index d6fac766..e08fb981 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2786,11 +2786,6 @@ void () TeamFortress_AssaultWeapon = { if (FO_CurrentWeaponsMask() & WEAP_ASSAULT_CANNON == 0) return; - if (self.heat > 0) { - sprint(self, PRINT_HIGH, "The Assault Cannon is still overheated\n"); - return; - } - if (self.ammo_shells < 1) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); return; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 8cb4b995..be6b8c27 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1374,13 +1374,12 @@ void (vector org, vector dir) launch_spike = { void () W_FireSuperSpikes = { local vector dir; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); FO_Sound(self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); - if (old_ng_rof) - self.ammo_nails = self.ammo_nails - 4; - else - self.ammo_nails = self.ammo_nails - 2; + self.ammo_nails -= wi->ammo_per_shot; + dir = aim(self, 1000); launch_spike(self.origin + '0 0 16', dir); LogEventAttack(self); @@ -1389,31 +1388,33 @@ void () W_FireSuperSpikes = { FO_SetModel(newmis, "progs/s_spike.mdl"); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); KickPlayer(-3, self); + + Attack_Finished(wi->attack_time); }; void (float ox) W_FireSpikes = { local vector dir; + FO_WeapInfo* wi = FO_GetWeapInfo(self.current_weapon); makevectors(self.v_angle); - if (((self.ammo_nails >= 4) || ((self.ammo_nails >= 2) && !old_ng_rof)) && - (self.current_weapon == WEAP_SUPER_NAILGUN)) { - W_FireSuperSpikes(); - return; - } - if (self.ammo_nails < 1) { + + if (self.ammo_nails < wi->ammo_per_shot) { W_ChangeToBestWeapon(); return; + } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { + W_FireSuperSpikes(); + return; } + FO_Sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); - if ((self.ammo_nails == 1) || !old_ng_rof) { - self.ammo_nails = self.ammo_nails - 1; - } else { - self.ammo_nails = self.ammo_nails - 2; - } + self.ammo_nails -= wi->ammo_per_shot; + dir = aim(self, 1000); launch_spike(self.origin + '0 0 16' + v_right * ox, dir); LogEventAttack(self); KickPlayer(-3, self); + + Attack_Finished(wi->attack_time); }; void () t_climb = { @@ -1649,9 +1650,8 @@ void () player_light1; void () player_rocket1; void () player_autorifle1; -void () player_assaultcannon1; -void () player_assaultcannonup1; -void () player_assaultcannondown1; +void () player_assaultcannonup; +void () player_assaultcannondown; void () player_medikit1; void () player_medikitb1; @@ -1752,12 +1752,12 @@ void () W_Attack = { } W_ChangeToBestWeapon(); } else { - self.ammo_cells = self.ammo_cells - 7; - self.heat = 1; + self.ammo_cells -= - 7; + self.count = 0; self.immune_to_check = time + 5; self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); - player_assaultcannonup1(); + player_assaultcannonup(); } } else if (self.current_weapon == WEAP_FLAMETHROWER) { player_shot1(); @@ -1798,7 +1798,8 @@ void () W_Attack = { Attack_Finished(wi->attack_time); if (wi->needs_reload) { - *ws->clip_fired += wi->ammo_per_shot; + if (self.current_weapon != WEAP_ASSAULT_CANNON) // In animation + *ws->clip_fired += wi->ammo_per_shot; FO_CheckForReload(); } From 783652e45b28540f0796afae45df402c47d6131c Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 17:36:31 -0700 Subject: [PATCH 1751/2474] Fix spin-down sound Moved an offset in prior commit, was skipping spindown sound on first frame --- ssqc/player.qc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 8b8277ff..04257777 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -418,7 +418,7 @@ static float CheckNeedAssaultCannonDown() { ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { self.tfstate |= TFSTATE_AIMING; TeamFortress_SetSpeed(self); - self.count = 1; + self.count = 0; player_assaultcannondown(); return TRUE; } @@ -481,7 +481,7 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (self.count >= 14) { + if (self.count >= 14) { // 1.5s down self.fire_held_down = 0; self.tfstate &= ~TFSTATE_AIMING; if (!cannon_move) @@ -493,8 +493,10 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); } - } else if (++self.count % 2 == 0) + } else if (self.count % 2 == 0) self.weaponframe = (self.weaponframe + 1) % 4; + + self.count++; Attack_Finished(wi->attack_time); }; From 590b602fd99aa50e0bfb71a56b2fb399b1be4168 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 19:13:27 -0700 Subject: [PATCH 1752/2474] OOB slot check We've seen a single crash on an OOB array of size 4, this is the obvious candidate. --- share/fo_weapons.qc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index e2c002d9..9e7b32ff 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -222,8 +222,20 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_RAILGUN, IT_SHOTGUN}, }; +float BoundSlotInput(float slot) { + if (slot < 1 || slot > 4) { +#ifdef SSQC + sprint(self, PRINT_HIGH, sprintf("Error: slot %d OOB\n", slot)); +#endif + return 1; + } else { + return slot; + } +} + FO_WeapInfo* FO_ClassWeaponSlot(float class, float slot) { FO_ClassWeapons* cw = &class_weapons[class]; + slot = BoundSlotInput(slot); return cw->info[slot - 1] ? cw->info[slot - 1] : __NULL__; } From 5daa5e40f1c3a4155bc051f8f83d339b9a1a1d07 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 28 Sep 2022 21:18:45 -0700 Subject: [PATCH 1753/2474] Re-enable antilag It turns out the undefined optional behavior dominates default parameter, so: foo(optional int param = 1) Will be invoked with param = and not 1. This was disabling antilag by selecting an undefined mode with a max of 0. --- ssqc/antilag.qc | 12 ++++-------- ssqc/qw.qc | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 7d7bbad2..7c82b62c 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -351,12 +351,12 @@ void UnrewindPlayer(entity p) { .float client_time_internal; -float client_time(optional float ct_type = CT_NOEXTERNALEFFECT) { +float client_time(float ct_type = CT_NOEXTERNALEFFECT) { if (ct_type == CT_NOEXTERNALEFFECT) return self.client_time_internal; float offset = time - self.client_time_internal; - float max_offset = 0; + float max_offset = antilag_settings.max_client_time_offset; switch (ct_type) { case CT_SLOW_PROJECTILE: max_offset = antilag_settings.max_projectile_slow_offset; @@ -379,13 +379,9 @@ void AL_UpdateClientTime(entity player) { offset = min(offset, antilag_settings.max_client_time_offset); - float old_client_time = player.client_time_internal; - if (time - offset > player.client_time_internal) - player.client_time_internal = time - offset; - // Monotonically increasing and not dragging beyond 75% of time as/if RTT // changes. - player.client_time_internal = max(player.client_time_internal, - old_client_time + (1/77.0 * 0.75)); + player.client_time_internal = + max(time - offset, player.client_time_internal + (1/77.0 * 0.75)); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 3759b39e..bb776224 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -19,7 +19,7 @@ struct antilag_settings_t { // at t1: client_time() + o < at t2: client_time() + o FOR t2 > t1 // E.g. That you never have to worry about the correction reordering events // that `time + o` would not. -float client_time(optional float ct_type = CT_NOEXTERNALEFFECT); +float client_time(float ct_type = CT_NOEXTERNALEFFECT); //=========================================================================== // TEAMFORTRESS Defs From dc68fc5465e47d64205477d6ec28fe51c2b1c726 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 29 Sep 2022 20:30:52 -0700 Subject: [PATCH 1754/2474] Fix impulse 1/7 We still support the old impulses when `old_weapon_impulses` is set, but the filtering was too aggressive (<=1 vs <1, same for 7). --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index be6b8c27..d02feb8a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2073,7 +2073,7 @@ static ImpulseWeapons impulse_weapons[] = { }; float W_WeaponByImpulse(float impulse) { - if (impulse <= 1 || impulse >= 7) return 0; + if (impulse < 1 || impulse > 7) return 0; return impulse_weapons[self.playerclass].weapons[impulse - 1]; } From d598deae84fc28eb504d5075bcd30a707e88b777 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 30 Sep 2022 00:53:01 -0700 Subject: [PATCH 1755/2474] Ensure ping correction can't affect firing rate In adjusting attack_finished for ping we need to make this on both sides, e.g. when the client fires and when we subsequently check. In missing the second we'd allow firing rate to increase with latency. Also re-add catch-all that was previosuly present for no ammo and minor cleanup. --- ssqc/client.qc | 15 ++++++++------- ssqc/weapons.qc | 24 +++++++++++++----------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c74ade9f..a793df85 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2184,7 +2184,7 @@ void () PutClientInServer = { stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - self.attack_finished = time + 0.3; + self.attack_finished = client_time() + 0.3; self.th_pain = player_pain; self.th_die = PlayerDie; self.height = 0; @@ -2764,14 +2764,15 @@ void () PlayerPreThink = { self.velocity = '0 0 0'; } -#if 0 + // Catch all. FO_WeapState ws; - FO_FillWeapState(self, self.weapon, &ws); - if (time > self.attack_finished && !self.currentammo && self.weapon > WEAP_AXE) { - W_ChangeWeapon(W_BestWeaponSlot()); - W_WeaponState_Save(self); + FO_FillWeapState(self, self.current_weapon, &ws); + if ((client_time() > self.attack_finished) && + (self.current_weapon > WEAP_AXE) && + ((ws->wi)->ammo_type != AMMO_NONE)) { + if (*ws->ammo_remaining == 0) + W_ChangeToBestWeapon(); } -#endif }; void () CheckPowerups = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d02feb8a..2bee5f3b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -200,9 +200,11 @@ float () crandom = { void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) - self.attack_finished = client_time() + att_delay * 2; - else - self.attack_finished = client_time() + att_delay; + att_delay *= 2; + + // Ensure we hold firing rate constant with jitter. + self.attack_finished = max(client_time() + att_delay, + self.attack_finished + att_delay); }; float () W_FireAxe = { @@ -1810,12 +1812,12 @@ void () W_Attack = { LogEventAttack(self); }; -float (entity pl) WeaponReady = { - if (time >= pl.attack_finished && !(pl.tfstate & TFSTATE_RELOADING)) { - return 1; - } +float WeaponReady() { + if (client_time() >= self.attack_finished && + !(self.tfstate & TFSTATE_RELOADING)) + return TRUE; - return 0; + return FALSE; } void () W_PrintWeaponMessage = { @@ -2141,7 +2143,7 @@ void W_ChangeWeapon(float weapon) { self.queue_weapon = weapon; // halt if weapon is not ready to be fired - if (!WeaponReady(self)) + if (!WeaponReady()) return; self.queue_weapon = 0; @@ -2814,7 +2816,7 @@ void () W_WeaponFrame = { if (self.impulse == TF_QUICKSTOP) self.impulse = self.qf_swap_last_weapon ? TF_WEAPLAST : 0; - float can_change_weapon = WeaponReady(self) && + float can_change_weapon = WeaponReady() && !self.is_detpacking && !(self.is_building && !engineer_move); // TODO: Open up queueing by moving queue can_change to ChangeWeapon? @@ -2923,7 +2925,7 @@ void () W_WeaponFrame = { return; } - if (!WeaponReady(self)) + if (!WeaponReady()) return; if (self.impulse != 0 && self.has_disconnected == 0) From d0f31e7e25db87f9fc4e92837f4d66948e3ab0c1 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 30 Sep 2022 13:34:55 -0700 Subject: [PATCH 1756/2474] Tie attack_finished to client_time() for now The prior approach failed to account for the fact that some of weapon animations have attack_finished embedded in them, resulting in overlapping calls. This was pushing the finished time out unreasonably. Just remove the max for now, we're going to make some other changes that will smooth out client_time in the face of jitter anyway. --- share/fo_weapons.qc | 2 +- ssqc/player.qc | 5 +++-- ssqc/weapons.qc | 4 +--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 9e7b32ff..ced3c2cc 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -85,7 +85,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, + { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, diff --git a/ssqc/player.qc b/ssqc/player.qc index 04257777..b5cf4e1c 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -436,7 +436,7 @@ void () player_assaultcannonup =[103, player_assaultcannonup] { FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); SuperDamageSound(); - if ((self.heat != 2) && (self.heat != 4)) + if ((self.count != 2) && (self.count != 4)) self.weaponframe = (self.weaponframe + 1) % 4; if (self.count++ >= 5) // 600ms spin up @@ -493,8 +493,9 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); } - } else if (self.count % 2 == 0) + } else if (self.count % 2 == 0) { self.weaponframe = (self.weaponframe + 1) % 4; + } self.count++; Attack_Finished(wi->attack_time); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2bee5f3b..3ed4b966 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -202,9 +202,7 @@ void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) att_delay *= 2; - // Ensure we hold firing rate constant with jitter. - self.attack_finished = max(client_time() + att_delay, - self.attack_finished + att_delay); + self.attack_finished = client_time() + att_delay; }; float () W_FireAxe = { From b77db46baf1dc96417c6c33d71663d975fa8f345 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 29 Sep 2022 01:01:49 -0700 Subject: [PATCH 1757/2474] Delete unused FLAGINFO code --- csqc/main.qc | 9 ++------- ssqc/client.qc | 11 ----------- ssqc/status.qc | 7 ------- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3e7f7994..60b27f43 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -399,19 +399,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { }; void(float isnew) CSQC_Ent_Update = { - print("CSQC_Ent_Update, new: ", ftos(isnew), "\n"); float etype = readbyte(); - string s; switch (etype) { - case MSG_FLAGINFO: - s = readstring(); - print("CSQC_Ent_Update, Flag info: ", s, "\n"); - break; default: - error("Unhandled CSQC entity\n"); //you can change it to a print, but if you're not using sv_csqcdebug 1 doing so would just confuse people over the real cause. + error("Unhandled CSQC entity\n"); return; } }; + void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and will no longer be tracked... print("CSQC_Ent_Remove\n"); remove(self); diff --git a/ssqc/client.qc b/ssqc/client.qc index a793df85..cb1aab0a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -216,12 +216,6 @@ void InitPrematch() } } -void (entity goalitem) SetFlagSendMethod = { - if(goalitem) { - goalitem.SendEntity = SendClientFlagStatus; - } -} - void () DecodeLevelParms = { local float fl; local string st; @@ -263,11 +257,6 @@ void () DecodeLevelParms = { if ((number_of_teams <= 0) || (number_of_teams >= 5)) number_of_teams = 4; - //SetFlagSendMethod(Finditem(ent.display_item_status1)); - //SetFlagSendMethod(Finditem(ent.display_item_status2)); - //SetFlagSendMethod(Finditem(ent.display_item_status3)); - //SetFlagSendMethod(Finditem(ent.display_item_status4)); - } else { ent = find(world, classname, "info_player_team1"); diff --git a/ssqc/status.qc b/ssqc/status.qc index 8729cf1e..ce510d90 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -694,13 +694,6 @@ void (entity Player, entity Item) UpdateClientFlagStatus = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -float(entity playerent, float changedflags) SendClientFlagStatus = { - bprint(PRINT_HIGH, "SendClientFlagStatus, for: ",playerent.netname,"\n"); - WriteByte (MSG_ENTITY, MSG_FLAGINFO); - WriteString (MSG_ENTITY, self.mdl); - return TRUE; -} - string (entity Player, entity Item, float teamno) GetItemStatus = { local string st = ""; switch (teamno) From 6d9d0c5aa47e9d1db8a2b0e23557607b6c682830 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 30 Sep 2022 11:05:48 -0700 Subject: [PATCH 1758/2474] Make WeapState operate on current weapon and clip-storage be slot-based --- share/defs.h | 5 + share/fo_weapons.qc | 234 ++++++++++++++++++++++----------- ssqc/actions.qc | 37 ++---- ssqc/client.qc | 13 +- ssqc/engineer.qc | 14 +- ssqc/events.qc | 6 +- ssqc/items.qc | 45 ++----- ssqc/player.qc | 10 +- ssqc/pyro.qc | 22 ---- ssqc/qw.qc | 19 +-- ssqc/scout.qc | 4 +- ssqc/sniper.qc | 2 +- ssqc/status.qc | 6 +- ssqc/tfort.qc | 33 +---- ssqc/tfortmap.qc | 4 +- ssqc/vote.qc | 8 +- ssqc/weapons.qc | 313 ++++++++++++++++---------------------------- 17 files changed, 336 insertions(+), 439 deletions(-) diff --git a/share/defs.h b/share/defs.h index 49670e60..9b748b06 100644 --- a/share/defs.h +++ b/share/defs.h @@ -372,10 +372,15 @@ /*======================================================*/ /* Impulse Defines */ /*======================================================*/ +#define TF_SLOT_NONE 0 #define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) #define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) #define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) #define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_SLOT_LAST TF_SLOT4 +#define TF_SLOT_MELEE TF_SLOT4 +#define TF_NUM_SLOTS (TF_SLOT_LAST - TF_SLOT1 + 1) + #define TF_CLASSMENU 5 // Brings up class menu // unused 6 // unused 7 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index ced3c2cc..3826e537 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -4,13 +4,6 @@ * shared code. We'll refactor this on both sides to be cleaner incrementally, * but it gets us started. */ -.float reload_rocket_launcher; -.float reload_grenade_launcher; -.float reload_shotgun; -.float reload_super_shotgun; -.float reload_super_shotgun; -.float reload_assault_cannon; -.float reload_sniper_rifle; .float waterlevel; .float playerclass; @@ -57,10 +50,9 @@ struct FO_WeapInfo { float attack_time; float full_reload_time; - // Fields below this are automatically initialized by Init. Do not include - // in table. + // Fields below this are automatically initialized by Init. + // ** Do not include in table. ** float needs_reload; - int storage_index; // Allocated by init FO_WeapModels* models; FO_WeapToItem* items; }; @@ -114,6 +106,7 @@ FO_ClassWeapons class_weapons[] = { { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, + { PC_RANDOM, { 0, 0, 0, WEAP_AXE } }, // TODO: Probably needs attention { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; @@ -181,13 +174,12 @@ static float* AMMO_to_p(entity player, AmmoType ammo_type) { float WEAP_to_slot(float class, float weapon) { for (float i = 0; i < 4; i++) if (class_weapons[class].slots[i] == weapon) - return i; + return i + TF_SLOT1; return -1; } // Internal clip storage for both SSQC/CSQC. -#define CLIP_STORAGE_SIZE 8 -.float clip_fired[CLIP_STORAGE_SIZE]; +.float clip_fired[TF_SLOT_LAST - TF_SLOT1 + 1]; struct FO_WeapToItem { int weapon; @@ -223,46 +215,50 @@ FO_WeapToItem weapon_to_items[] = { }; float BoundSlotInput(float slot) { - if (slot < 1 || slot > 4) { -#ifdef SSQC - sprint(self, PRINT_HIGH, sprintf("Error: slot %d OOB\n", slot)); -#endif - return 1; + if (slot < TF_SLOT1 || slot > TF_SLOT4) { + return TF_SLOT4; } else { return slot; } } -FO_WeapInfo* FO_ClassWeaponSlot(float class, float slot) { +FO_WeapInfo* FO_SlotWeapInfo(float class, float slot) { + if (slot == TF_SLOT_NONE) + return FO_GetWeapInfo(WEAP_NONE); + FO_ClassWeapons* cw = &class_weapons[class]; slot = BoundSlotInput(slot); - return cw->info[slot - 1] ? cw->info[slot - 1] : __NULL__; + return cw->info[slot - TF_SLOT1] ? cw->info[slot - TF_SLOT1] : + FO_GetWeapInfo(WEAP_NONE); +} + +float FO_ClassWeaponBySlot(float class, float slot) { + FO_WeapInfo* wi = FO_SlotWeapInfo(class, slot); + if (!wi) + return WEAP_NONE; + + return wi->weapon; +} + +float FO_WeaponSlot(float slot) { + return FO_ClassWeaponBySlot(self.playerclass, slot); } -float FO_ClassWeapMask(float class) { + +float FO_ClassWeapItemMask(float class) { float result = 0; - for (int i = 1; i <= 4; i++) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); + for (int i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(class, i); if (wi) result |= (wi->items)->it_weapon; } return result; } -float FO_ClassWeaponItemMask(float class) { +float FO_WeaponsMask(entity player) { float mask = 0; - for (float i = 1; i <= 4; i++) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(class, i); - if (wi) - mask |= (wi->items)->it_weapon; - } - return mask; -} - -float FO_CurrentWeaponsMask() { - float mask = 0; - for (float i = 1; i <= 4; i++) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, i); + for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, i); if (wi) mask |= wi->weapon; } @@ -272,6 +268,7 @@ float FO_CurrentWeaponsMask() { #ifdef SSQC struct FO_WeapState { float weapon; + float slot; // Constant and relative to weapon. TODO, migrate similar to WeapInfo. FO_WeapInfo* wi; @@ -282,28 +279,49 @@ struct FO_WeapState { }; -void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws) { - ws->weapon = weapon; - FO_WeapInfo* wi = FO_GetWeapInfo(weapon); - ws->wi = wi; +void FO_FillWeapState(entity player, float slot, FO_WeapState* result) { + if (slot < 0 || slot > 4) error(sprintf("SLOT %d OOB\n", slot)); - if (wi->needs_reload) - ws->clip_fired = &player.clip_fired[wi->storage_index]; - ws->ammo_remaining = AMMO_to_p(player, (ws->wi)->ammo_type); + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, slot); + + result->weapon = wi->weapon; + result->slot = slot; + result->wi = wi; + + result->ammo_remaining = AMMO_to_p(player, wi->ammo_type); + + if (slot != TF_SLOT_NONE) + result->clip_fired = &player.clip_fired[slot - TF_SLOT1]; + else + result->clip_fired = __NULL__; +} + +float FO_ClassWeaponBySlot(float class, float slot); + +inline float FO_CurrentWeapon() { + return FO_ClassWeaponBySlot(self.playerclass, self.current_slot); +} + +inline float FO_PlayerCurrentWeapon(entity player) { + return FO_ClassWeaponBySlot(player.playerclass, player.current_slot); +} + +inline void FO_FillCurrentWeapState(FO_WeapState* result) { + FO_FillWeapState(self, self.current_slot, result); } -void () RestoreDefaultWeapon; void (entity pl) Status_Refresh; void (float att_delay) Attack_Finished; static void FOT_ReloadTimer() { FO_WeapState ws; - FO_FillWeapState(self.owner, self.current_weapon, &ws); + FO_FillWeapState(self.owner, self.owner.current_slot, &ws); if (time >= self.heat) { // Reload finished self.owner.tfstate &= ~TFSTATE_RELOADING; self.owner.weaponmodel = ((ws->wi)->models)->model; + self.owner.weaponframe = 0; sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); dremove(self); } else { @@ -318,9 +336,9 @@ static void FOT_ReloadTimer() { Status_Refresh(self.owner); } -float FO_CanReload(float weapon) { +float FO_CanReload(float slot) { FO_WeapState ws; - FO_FillWeapState(self, weapon, &ws); + FO_FillWeapState(self, slot, &ws); FO_WeapInfo* wi = ws->wi; if (wi->ammo_type == AMMO_NONE) @@ -333,29 +351,14 @@ float FO_CanReload(float weapon) { return FALSE; } -void () TeamFortress_ForceReloadCurrentWeapon; -float FO_CheckForReload() { - FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); - FO_WeapInfo* wi = ws->wi; - - if (wi->needs_reload && *ws->clip_fired >= wi->clip_size && - *ws->ammo_remaining > 0) { - if (force_reload) - TeamFortress_ForceReloadCurrentWeapon(); - return TRUE; - } else { - return FALSE; - } -} - -void FO_ReloadWeapon(float weapon, float force) { +void () RestoreDefaultWeapon; +void FO_ReloadSlot(float slot, float force) { RestoreDefaultWeapon(); if (self.tfstate & TFSTATE_RELOADING) return; FO_WeapState ws; - FO_FillWeapState(self, weapon, &ws); + FO_FillWeapState(self, slot, &ws); FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) @@ -398,12 +401,11 @@ void FO_ReloadWeapon(float weapon, float force) { // Actual entity that will update status bar / clear reload. entity reload_timer = spawn(); reload_timer.owner = self; - reload_timer.current_weapon = weapon; reload_timer.classname = "timer"; reload_timer.think = FOT_ReloadTimer; // TODO: Remove this hack. - if (weapon == WEAP_SNIPER_RIFLE) { + if (ws.weapon == WEAP_SNIPER_RIFLE) { self.reload_tick = 1; self.reload_sniper_ticks = 0; } @@ -416,13 +418,88 @@ void FO_ReloadWeapon(float weapon, float force) { } +float FO_CheckForReload() { + FO_WeapState ws; + FO_FillCurrentWeapState(&ws); + FO_WeapInfo* wi = ws->wi; + + if (wi->needs_reload && *ws->clip_fired >= wi->clip_size && + *ws->ammo_remaining > 0) { + if (force_reload) + FO_ReloadSlot(self.current_slot, TRUE); + return TRUE; + } else { + return FALSE; + } +} + void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; - for (int i = 0; i < CLIP_STORAGE_SIZE; i++) + for (int i = 0; i < 4; i++) player.clip_fired[i] = 0; } #endif +struct ImpulseWeapon { + int class; + float weapons[7]; + + // Autogenerated + float slots[7]; +}; + +ImpulseWeapon impulse_weapons[] = { + { PC_UNDEFINED, { WEAP_AXE } }, + { PC_SCOUT, + { WEAP_AXE, WEAP_SHOTGUN, 0, WEAP_NAILGUN } }, + { PC_SNIPER, + { WEAP_AXE, WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN } }, + { PC_SOLDIER, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, + { PC_DEMOMAN, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, + { PC_MEDIC, + { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, + { PC_HVYWEAP, + { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, + { PC_PYRO, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, + { PC_SPY, + { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, + { PC_ENGINEER, + { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, + { PC_CIVILIAN, { WEAP_AXE } }, +}; + +float FO_ImpulseToSlot(float impulse) { + if (impulse < 1 || impulse > 7) return 0; + return impulse_weapons[self.playerclass].slots[impulse - 1]; +} + +#ifdef SSQC +float IsUsingOldImpulses(); + +float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; +static float IsPyroSlotSwapped() { + return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); +} +#else +float IsUsingOldImpulses() { return FALSE; } + +static float IsPyroSlotSwapped() { return FALSE; } +#endif + +static float HandlePyroSlotSwap(float slot) { + float cf_pyro_impulses = IsPyroSlotSwapped(); + if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) + slot = 3 - slot; + return slot; +} + +float FO_SlotByInput(float input) { + return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : input; +} + void FO_Weapons_Init() { float i, j; @@ -451,7 +528,6 @@ void FO_Weapons_Init() { wi->ammo_per_shot = 4; } - float clips_allocated = 0; for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; if (WEAP_to_index(wi->weapon) != i) @@ -461,24 +537,17 @@ void FO_Weapons_Init() { FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); wi->ammo_type = parent->ammo_type; wi->clip_size = parent->clip_size; - wi->storage_index = parent->storage_index; wi->full_reload_time = parent->full_reload_time; wi->needs_reload = parent->needs_reload; } else if (wi->clip_size > 0) { wi->needs_reload = TRUE; - // We always allocate a storage index for something that can have - // reload to save negotiating between client and server around - // localinfo tunables. - wi->storage_index = clips_allocated++; } else { wi->needs_reload = FALSE; - wi->storage_index = -1; // Make sure we'll OOB. } FO_WeapModels* wm = &weapon_models[i]; if (WEAP_to_index(wm->weapon) != i) error(sprintf("WM mismatch at index %d\n", i)); - precache_model(wm->model); wi->models = wm; @@ -493,8 +562,6 @@ void FO_Weapons_Init() { case AMMO_ROCKETS: wti->ammo_mask = IT_ROCKETS; break; } } - if (clips_allocated > CLIP_STORAGE_SIZE) - error("Insufficient clip storage"); for (i = 0; i < class_weapons.length; i++) { for (j = 0; j < 4; j++) { @@ -503,7 +570,16 @@ void FO_Weapons_Init() { if (cw->slots[j]) cw->info[j] = &weapon_info[WEAP_to_index(cw->slots[j])]; else - cw->info[j] = __NULL__; + cw->info[j] = &weapon_info[0]; // WEAP_NONE } } + + for (i = 0; i < impulse_weapons.length; i++) { + ImpulseWeapon* iw = &impulse_weapons[i]; + + for (j = 0; j < 7; j++) + if (iw->weapons[j]) + iw->slots[j] = WEAP_to_slot(iw->class, iw->weapons[j]); + } } + diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 452585f0..0367bffd 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -469,39 +469,28 @@ void (entity pe_player, float f_type) CF_Identify = { void () RestoreDefaultWeapon = { float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); if (default_weapon >= 1 && default_weapon <= 4) { - W_ChangeWeapon(W_WeaponBySlot(default_weapon)); + W_ChangeWeaponSlot(default_weapon); } }; -void () TeamFortress_ReloadCurrentWeapon = { - FO_ReloadWeapon(self.current_weapon, FALSE); -}; - -void () TeamFortress_ForceReloadCurrentWeapon = { - FO_ReloadWeapon(self.current_weapon, TRUE); -}; - -void (float slot) TeamFortress_ReloadSlot = { - float weap = W_WeaponBySlot(slot); - - FO_ReloadWeapon(weap, FALSE); -} - -float W_FindPrevNextWeapon(float weapon, float is_prev); - void () TeamFortress_ReloadNext = { - float weapon = self.current_weapon; + float slot = self.current_slot; + + if (!FO_CanReload(slot)) { + for (int i = 1; i < TF_NUM_SLOTS; i++) { + slot = slot + 1; // Easier to read than mod version because 1-base. + if (slot > TF_SLOT_LAST) + slot -= TF_NUM_SLOTS; + sprint(self, PRINT_HIGH, sprintf("checking %d\n", slot)); - if (!FO_CanReload(weapon)) { - for (int i = 0; i < 3; i++) { - weapon = W_FindPrevNextWeapon(weapon, FALSE); - if (FO_CanReload(weapon)) + if (FO_CanReload(slot)) break; } } - if (FO_CanReload(weapon)) { - FO_ReloadWeapon(weapon, FALSE); + if (FO_CanReload(slot)) { + sprint(self, PRINT_HIGH, sprintf("reloading %d\n", slot)); + FO_ReloadSlot(slot, FALSE); RestoreDefaultWeapon(); } else { sprint(self, PRINT_HIGH, "All clips full\n"); diff --git a/ssqc/client.qc b/ssqc/client.qc index cb1aab0a..68d3da8e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -118,7 +118,7 @@ void () SetChangeParms = { parm5 = self.ammo_nails; parm6 = self.ammo_rockets; parm7 = self.ammo_cells; - parm8 = self.current_weapon; + parm8 = self.current_slot; parm9 = self.armortype * 100; parm10 = 0; parm11 = 0; @@ -2497,7 +2497,7 @@ void () PlayerJump = { else FO_Sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } - if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); @@ -2521,7 +2521,7 @@ void () PlayerJump = { FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); - if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { if (!cannon_air) { if (self.antispam_cannon_air < time) { sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); @@ -2755,10 +2755,9 @@ void () PlayerPreThink = { // Catch all. FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); if ((client_time() > self.attack_finished) && - (self.current_weapon > WEAP_AXE) && - ((ws->wi)->ammo_type != AMMO_NONE)) { + (ws.weapon > WEAP_AXE) && ((ws->wi)->ammo_type != AMMO_NONE)) { if (*ws->ammo_remaining == 0) W_ChangeToBestWeapon(); } @@ -2935,7 +2934,7 @@ void () PlayerPostThink = { fop.RewindUpdate(); FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 8080473a..9b3beb0c 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -402,10 +402,10 @@ void () TeamFortress_EngineerBuildStop = { self.is_building = 0; self.building_percentage = 0; if (!engineer_move) { - self.current_weapon = self.weapon; - self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; + self.tfstate &= ~TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_WALK; TeamFortress_SetSpeed(self); + // Old weapon already queued. } } @@ -555,10 +555,8 @@ void (float objtobuild) TeamFortress_Build = { self.immune_to_check = time + 5; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_NONE; - self.weapon = self.current_weapon; - self.current_weapon = 0; - self.weaponmodel = ""; - self.weaponframe = 0; + + W_QueueAndDisableWeapon(); TeamFortress_SetSpeed(self); Menu_Engineer_Cancel(); } @@ -906,10 +904,10 @@ void () TeamFortress_FinishedBuilding = { self.is_building = FALSE; self.building_percentage = 0; if (!engineer_move) { - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + self.tfstate &= ~TFSTATE_CANT_MOVE; self.movetype = MOVETYPE_WALK; - self.current_weapon = self.weapon; TeamFortress_SetSpeed(self); + // Weapon should be queued. } Status_Refresh(self); diff --git a/ssqc/events.qc b/ssqc/events.qc index 77be41b7..fbeda3f9 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -170,7 +170,7 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon); + inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -272,7 +272,7 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { killKind = "enemy"; if (inflictor.classname == "player") - inflictorId = GetWeaponName(attacker.current_weapon); + inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); else { inflictorId = inflictor.classname; if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { @@ -386,7 +386,7 @@ void (entity attacker) LogEventAttack = { if (canlog == 0) return; local string event; - event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(attacker.current_weapon), ftos(gametime), gametimestamp); + event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(FO_PlayerCurrentWeapon(attacker)), ftos(gametime), gametimestamp); logevent(event); } diff --git a/ssqc/items.qc b/ssqc/items.qc index a9cfc7d7..8cea4a1a 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -241,7 +241,7 @@ void () health_touch = { } } else { if (!T_Heal(other, self.healamount, 0)) { - if (other.weapons_carried & 4) { + if (FO_WeaponsMask(other) & WEAP_MEDIKIT) { if (other.ammo_medikit < other.maxammo_medikit) { other.ammo_medikit = other.ammo_medikit + self.healamount; @@ -317,7 +317,6 @@ void () armor_touch = { local float value; local float bit; local string s; - local entity oldself; if (other.health <= 0) { return; @@ -395,9 +394,6 @@ void () armor_touch = { if (other.ammo_cells > other.maxammo_cells) { other.ammo_cells = other.maxammo_cells; } - oldself = self; - self = other; - self = oldself; } value = other.maxarmor; } @@ -507,9 +503,6 @@ float (float w) RankForWeapon = { return 7; }; -void (float old, float new) Deathmatch_Weapon = { -}; - void () ammo_touch; void (entity ritem, entity act) Respawn_Item = { @@ -531,15 +524,12 @@ void (entity ritem, entity act) Respawn_Item = { self = oldself; }; -float () W_BestWeapon; - void () weapon_touch = { local float hadammo; - local float best; local float new; local float old; - local entity stemp; local float leave; + float other_weapons_carried = FO_WeaponsMask(other); new = 0; if (!(other.flags & 8)) @@ -551,17 +541,13 @@ void () weapon_touch = { if (cb_prematch == 1) return; - stemp = self; - self = other; - best = W_BestWeapon(); - self = stemp; if ((deathmatch == 2) || coop) { leave = 1; } else { leave = 0; } if (self.classname == "weapon_nailgun") { - if (leave && (other.weapons_carried & WEAP_NAILGUN)) { + if (leave && (other_weapons_carried & WEAP_NAILGUN)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_NAILGUN)) { @@ -572,7 +558,7 @@ void () weapon_touch = { other.ammo_nails = other.ammo_nails + 30; } else { if (self.classname == "weapon_supernailgun") { - if (leave && (other.weapons_carried & WEAP_SUPER_NAILGUN)) { + if (leave && (other_weapons_carried & WEAP_SUPER_NAILGUN)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_SUPER_NAILGUN)) { @@ -583,7 +569,7 @@ void () weapon_touch = { other.ammo_nails = other.ammo_nails + 30; } else { if (self.classname == "weapon_supershotgun") { - if (leave && (other.weapons_carried & WEAP_SUPER_SHOTGUN)) { + if (leave && (other_weapons_carried & WEAP_SUPER_SHOTGUN)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_SUPER_SHOTGUN)) { @@ -594,7 +580,7 @@ void () weapon_touch = { other.ammo_shells = other.ammo_shells + 5; } else { if (self.classname == "weapon_rocketlauncher") { - if (leave && (other.weapons_carried & WEAP_ROCKET_LAUNCHER)) { + if (leave && (other_weapons_carried & WEAP_ROCKET_LAUNCHER)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_ROCKET_LAUNCHER)) { @@ -605,7 +591,7 @@ void () weapon_touch = { other.ammo_rockets = other.ammo_rockets + 5; } else { if (self.classname == "weapon_grenadelauncher") { - if (leave && (other.weapons_carried & WEAP_GRENADE_LAUNCHER)) { + if (leave && (other_weapons_carried & WEAP_GRENADE_LAUNCHER)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_GRENADE_LAUNCHER)) { @@ -616,7 +602,7 @@ void () weapon_touch = { other.ammo_rockets = other.ammo_rockets + 5; } else { if (self.classname == "weapon_lightning") { - if (leave && (other.weapons_carried & WEAP_LIGHTNING)) { + if (leave && (other_weapons_carried & WEAP_LIGHTNING)) { return; } if (!TeamFortress_CanGetWeapon(other, WEAP_LIGHTNING)) { @@ -637,12 +623,6 @@ void () weapon_touch = { FO_Sound(other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM); stuffcmd(other, "bf\n"); bound_other_ammo(other); - old = other.weapons_carried; - other.weapons_carried = other.weapons_carried | new; - stemp = self; - self = other; - Deathmatch_Weapon(old, new); - self = stemp; if (leave) return; Respawn_Item(self, other); @@ -810,8 +790,6 @@ float () GetGrenadePossibility = { }; void () ammo_touch = { - local entity stemp; - local float best; local float gotgren; local float gotbox; @@ -829,10 +807,6 @@ void () ammo_touch = { } gotgren = 0; gotbox = 0; - stemp = self; - self = other; - best = W_BestWeapon(); - self = stemp; if (self.weapon == 1) { if (other.ammo_shells >= TeamFortress_GetMaxAmmo(other, 256)) { return; @@ -874,9 +848,6 @@ void () ammo_touch = { if (gotbox) { bound_other_ammo(other); sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); - stemp = self; - self = other; - self = stemp; } Respawn_Item(self, other); }; diff --git a/ssqc/player.qc b/ssqc/player.qc index b5cf4e1c..a81a28f2 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -90,7 +90,7 @@ void () player_stand1 =[17, player_stand1] { player_run(); return; } - if (self.current_weapon <= 16) { + if (self.current_slot == TF_SLOT_MELEE) { if (self.walkframe >= 12) { self.walkframe = 0; } @@ -111,7 +111,7 @@ void () player_run =[6, player_run] { player_stand1(); return; } - if (self.current_weapon <= 16) { + if (FO_CurrentWeapon() <= WEAP_AXE) { if (self.walkframe >= 6) { self.walkframe = 0; } @@ -682,10 +682,10 @@ void (entity et, float f) player_pain = { PainSound(); return; } - if (self.button0 && (self.current_weapon == 32768)) + if (self.button0 && (FO_CurrentWeapon() == WEAP_INCENDIARY)) return; - if (self.current_weapon <= 16) + if (FO_CurrentWeapon() <= WEAP_AXE) player_axpain1(); else player_pain1(); @@ -925,7 +925,7 @@ void () PlayerDie = { DeathSound(); self.angles_x = 0; self.angles_z = 0; - if (self.current_weapon <= 16) { + if (FO_CurrentWeapon() <= WEAP_AXE) { player_die_ax1(); TeamFortress_SetupRespawn(0); return; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index c09a4c2d..6468290b 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -711,28 +711,6 @@ void () W_FireIncendiaryCannon = { } }; -void () TeamFortress_IncendiaryCannon = { - if (!(self.weapons_carried & WEAP_INCENDIARY)) { - return; - } - if (self.ammo_rockets < 3) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } - self.current_weapon = WEAP_INCENDIARY; -}; - -void () TeamFortress_FlameThrower = { - if (!(self.weapons_carried & WEAP_FLAMETHROWER)) { - return; - } - if (self.ammo_cells < 1) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } - self.current_weapon = WEAP_FLAMETHROWER; -}; - void () AirBlastReloadFinished = { self.owner.airblast_cooldown = 0; sprint(self.owner, PRINT_HIGH, "Airblast ready\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bb776224..7f46aef5 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -49,7 +49,7 @@ float client_time(float ct_type = CT_NOEXTERNALEFFECT); .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float is_concussed; // TRUE for a player who is affected by concussion grenade -.float qf_swap_last_weapon; // TRUE if +slotX was initated from another slot +.float qf_swap_last_slot; // TRUE if +slotX was initiated from another slot .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team .float has_changedclass; // TRUE for a player that has changed class @@ -206,18 +206,9 @@ float coop; /*==============================================*/ /* New Weapon variables */ /*==============================================*/ -.float weapons_carried; // the weapons the player is carrying -.float current_weapon; // the weapon the player is using -.float last_weapon; // the last weapon the player was using -.float current_weaponslot; // the currently equipped weaponslot -.float last_weaponslot; // the last equipped weaponslot -.float queue_weapon; // the weapon to switch to when possible - -// weapon states -.float weaponstate_current_weaponslot; -.float weaponstate_last_weaponslot; -.float weaponstate_current_weapon; -.float weaponstate_last_weapon; +.float current_slot; // the currently equipped (weapon) slot +.float last_slot; // the last slot the player was using +.float queue_slot; // the slot to switch to when possible .float ammo_medikit; // Ammo used for the medikit .float maxammo_medikit; @@ -226,7 +217,7 @@ float coop; .float noammo; // used for no ammo error messages // variables used for reloading -.float reload_shotgun; +.float reload_shotgun; // Only use for map compatibility. .float reload_super_shotgun; .float reload_sniper_rifle; .float reload_grenade_launcher; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 0d5ce0de..927f7a57 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -484,7 +484,9 @@ void () ConcussionGrenadeTimer = { pos = pointcontents(src); if ((self.owner.flags & 512) || (self.owner.flags & 16)) { - if (!self.owner.is_feigning && !(self.owner.current_weapon == WEAP_ASSAULT_CANNON && !cannon_conc && self.owner.button0)) { + if (!self.owner.is_feigning && + !(FO_PlayerCurrentWeapon(self.owner) == WEAP_ASSAULT_CANNON && + !cannon_conc && self.owner.button0)) { makevectors(self.owner.v_angle); stumble = crandom() * self.health; if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { diff --git a/ssqc/sniper.qc b/ssqc/sniper.qc index a5d7bb61..49ab796e 100644 --- a/ssqc/sniper.qc +++ b/ssqc/sniper.qc @@ -119,7 +119,7 @@ void () SniperSight_Update = { local vector org; if (!(self.owner.tfstate & TFSTATE_AIMING) || - (self.owner.current_weapon != WEAP_SNIPER_RIFLE)) { + (FO_PlayerCurrentWeapon(self.owner) != WEAP_SNIPER_RIFLE)) { self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_AIMING); diff --git a/ssqc/status.qc b/ssqc/status.qc index ce510d90..156ba7ee 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -745,7 +745,7 @@ string GetSBClipString(entity pl, float csqcactive) string msg = ""; if (pl.tfstate & TFSTATE_RELOADING) { - FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); + FO_WeapInfo* wi = FO_GetWeapInfo(FO_PlayerCurrentWeapon(pl)); if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); @@ -1326,7 +1326,7 @@ string(float num) GreenScoreToString = string(entity pl, float csqcactive) ClipSizeToString = { FO_WeapState ws; - FO_FillWeapState(pl, pl.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); FO_WeapInfo* wi = ws->wi; if (!wi->needs_reload) @@ -1474,7 +1474,7 @@ string(entity pl) AuraToString = string(entity pl) AssaultCannonToString = { - if (pl.current_weapon == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_LOCK)) + if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON && (pl.tfstate & TFSTATE_LOCK)) return Q"\sAssault Cannon Locked\s"; else return ""; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e08fb981..f5ea8890 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -340,7 +340,7 @@ void (float inp) TeamFortress_ChangeClass = { TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); TeamFortress_ExecClassScript(self); - W_ChangeWeapon(W_BestWeapon()); + W_ChangeToBestWeapon(); if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; @@ -544,7 +544,7 @@ void () TeamFortress_Inventory = { if (self.tf_items & NIT_SCANNER) sprint(self, PRINT_HIGH, "Scanner\n"); - float current_weapons = FO_CurrentWeaponsMask(); + float current_weapons = FO_WeaponsMask(self); if (current_weapons & WEAP_MEDIKIT) sprint(self, PRINT_HIGH, "Medikit\n"); @@ -1565,11 +1565,11 @@ void () TeamFortress_SetEquipment = { Team_Role * role = GetTeamRole(self.team_no); kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); - self.items = FO_ClassWeaponItemMask(self.playerclass) | kept_items; + self.items = FO_ClassWeapItemMask(self.playerclass) | kept_items; if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { - self.current_weapon = 0; - self.last_weapon = 0; + self.current_slot = 0; + self.last_slot = 0; } self.tf_items = 0; @@ -2202,7 +2202,7 @@ void () TeamFortress_SetEquipment = { self.armortype = 0; self.armorvalue = 0; self.weapon = 0; - self.current_weapon = 0; + self.current_slot = 0; self.flags = FL_CLIENT | FL_NOTARGET; self.waterlevel = 3; @@ -2778,27 +2778,6 @@ void () TeamFortress_AmmoboxTouch = { self = other; }; -void () TeamFortress_AssaultWeapon = { - self.impulse = 0; - if (self.tfstate & TFSTATE_RELOADING) - return; - - if (FO_CurrentWeaponsMask() & WEAP_ASSAULT_CANNON == 0) - return; - - if (self.ammo_shells < 1) { - sprint(self, PRINT_HIGH, "Not enough ammo\n"); - return; - } - - if (self.ammo_cells < 7 && time >= self.antispam_assault_cannon) { - sprint(self, PRINT_HIGH, "Not enough cells to power the Assault Cannon\n"); - self.antispam_assault_cannon = time + 3; - return; - } - W_ChangeWeapon(WEAP_ASSAULT_CANNON); -}; - void () TeamFortress_ExplodePerson = { local entity te; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index d2a52987..97292d68 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -835,7 +835,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { //refill the clip if stock_reload is 2 if (stock_reload == 2) { FO_WeapState ws; - FO_FillWeapState(Player, Player.current_weapon, &ws); + FO_FillWeapState(Player, Player.current_slot, &ws); FO_WeapInfo* wi = ws->wi; @@ -856,7 +856,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } else { //for use in map entities without specifically enabling the general override FO_WeapState ws; - FO_FillWeapState(Player, Player.current_weapon, &ws); + FO_FillWeapState(Player, Player.current_slot, &ws); if ((Goal.reload_shotgun && ws.weapon == WEAP_SHOTGUN) || (Goal.reload_super_shotgun && ws.weapon == WEAP_SUPER_SHOTGUN) || diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 22a652a0..7d277cf3 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1228,9 +1228,8 @@ void () AnarchyMode = { vote_anarchy_mode = TRUE; local entity e = find(world, classname, "player"); while(e) { - e.items = IT_AXE; - e.weapons_carried = IT_AXE; - e.current_weapon = WEAP_AXE; + // TODO: Add a no weap switch to handle this like it used to. + e.current_slot = TF_SLOT4; if(e.vote_map) { e.items |= IT_QUAD; e.tfstate &= 128; @@ -1264,8 +1263,7 @@ void () EndVoting = { while(e) { e.vote_map = world; e.items = 0; - e.weapons_carried = 0; - e.current_weapon = 0; + e.current_slot = TF_SLOT4; e.super_damage_finished = 0; //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; TeamFortress_SetSpeed(e); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 3ed4b966..5880f678 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -10,10 +10,8 @@ void () SuperDamageSound; void () ConcussionGrenadeTimer; void () OldConcussionGrenadeTimer; -void (float inp) W_ChangeWeapon; +void (float slot) W_ChangeWeaponSlot; void () W_ChangeToBestWeapon; -float (float slot) W_WeaponBySlot; -float (float impulse) W_WeaponByImpulse; void () W_PrintWeaponMessage; void () button_fire; @@ -27,9 +25,6 @@ void () TeamFortress_DisplayLegalClasses; void () TeamFortress_ShowIDs; void () TeamFortress_ShowTF; -void () TeamFortress_AssaultWeapon; -void () TeamFortress_IncendiaryCannon; -void () TeamFortress_FlameThrower; void (float inp, float is_player) TeamFortress_PrimeGrenade; void () TeamFortress_ThrowGrenade; void (float inp) TeamFortress_PrimeThrowGrenade; @@ -45,9 +40,6 @@ void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void (entity pe_player, float f_type) CF_Identify; -void () TeamFortress_ReloadCurrentWeapon; -void () TeamFortress_ForceReloadCurrentWeapon; -void (float slot) TeamFortress_ReloadSlot; void () TeamFortress_ReloadNext; void () Sniper_ZoomToggle; void (float zoom_in) Sniper_ZoomAdjust; @@ -132,10 +124,8 @@ float () GetMaxWeaponInput; float () IsUsingOldImpulses; float () IsUsingCFImpulses; -float (float impulse) W_WeaponByImpulse; void (entity pl) W_UpdateCurrentWeapon; - void (entity ent, float num) SetFlameCount; .float button3_keydown; @@ -780,20 +770,20 @@ void (float shotcount, vector dir, vector spread) FireBullets = { traceline(src, (src + (direction * 2048)), MOVE_LAGGED, self); if (trace_fraction != 1) { - if (self.current_weapon != WEAP_ASSAULT_CANNON) + if (FO_CurrentWeapon() != WEAP_ASSAULT_CANNON) TraceAttack(4, direction); else TraceAttack(8, direction); } shotcount = shotcount - 1; - if (self.current_weapon == WEAP_ASSAULT_CANNON) { + if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON) { puff_org = trace_endpos + direction; Multi_Finish(); } } ApplyMultiDamage(); - if (self.current_weapon != WEAP_ASSAULT_CANNON) + if (FO_CurrentWeapon() != WEAP_ASSAULT_CANNON) Multi_Finish(); }; @@ -1304,7 +1294,7 @@ void () W_FireGrenade = { newmis.owner = self; newmis.movetype = 10; newmis.solid = 2; - if (self.current_weapon == WEAP_GRENADE_LAUNCHER || cb_prematch) { + if (FO_CurrentWeapon() == WEAP_GRENADE_LAUNCHER || cb_prematch) { newmis.weapon = 5; newmis.classname = "grenade"; newmis.skin = 1; @@ -1394,14 +1384,16 @@ void () W_FireSuperSpikes = { void (float ox) W_FireSpikes = { local vector dir; - FO_WeapInfo* wi = FO_GetWeapInfo(self.current_weapon); + FO_WeapState ws; + FO_FillCurrentWeapState(&ws); + FO_WeapInfo* wi = ws->wi; makevectors(self.v_angle); if (self.ammo_nails < wi->ammo_per_shot) { W_ChangeToBestWeapon(); return; - } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { + } else if (ws.weapon == WEAP_SUPER_NAILGUN) { W_FireSuperSpikes(); return; } @@ -1561,10 +1553,13 @@ void () superspike_touch = { void (entity pl) W_UpdateCurrentWeapon = { entity oldself; - if ((pl.health <= 0) || (pl.current_weapon == 0)) + if ((pl.health <= 0) || (pl.current_slot == 0)) return; - FO_WeapInfo* wi = FO_GetWeapInfo(pl.current_weapon); + FO_WeapState ws; + FO_FillWeapState(pl, pl.current_slot, &ws); + FO_WeapInfo* wi = ws.wi; + pl.items &= ~(IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS); // TODO: Shouldn't this always be union? Carrying prior behavior for now. pl.items |= (wi->items)->ammo_mask; @@ -1587,50 +1582,24 @@ void (entity pl) W_UpdateCurrentWeapon = { } }; -float () W_BestWeapon = { - float it = FO_CurrentWeaponsMask(); - - // TODO: Clean-up this at some point. It at least works with WEAPs. - if ((self.ammo_cells >= 1 && it & WEAP_LIGHTNING) && self.waterlevel <= 1) - return WEAP_LIGHTNING; - else if ((self.ammo_cells >= 7 && self.ammo_shells >= 1) && it & WEAP_ASSAULT_CANNON) - return WEAP_ASSAULT_CANNON; - else if (self.ammo_rockets >= 1 && it & WEAP_GRENADE_LAUNCHER) - return WEAP_GRENADE_LAUNCHER; - else if (self.ammo_rockets >= 1 && it & WEAP_ROCKET_LAUNCHER) - return WEAP_ROCKET_LAUNCHER; - else if (self.ammo_rockets >= 3 && it & WEAP_INCENDIARY) - return WEAP_INCENDIARY; - else if (self.ammo_cells >= 1 && it & WEAP_FLAMETHROWER) - return WEAP_FLAMETHROWER; - else if (self.ammo_nails >= 2 && it & WEAP_SUPER_NAILGUN) - return WEAP_SUPER_NAILGUN; - else if (self.ammo_nails >= 1 && it & WEAP_RAILGUN) - return WEAP_RAILGUN; - else if (self.ammo_shells >= 1 && it & WEAP_TRANQ) - return WEAP_TRANQ; - else if (self.ammo_shells >= 2 && it & WEAP_SUPER_SHOTGUN) - return WEAP_SUPER_SHOTGUN; - else if (self.ammo_shells >= 1 && it & WEAP_SNIPER_RIFLE) - return WEAP_SNIPER_RIFLE; - else if (self.ammo_nails >= 1 && it & WEAP_NAILGUN) - return WEAP_NAILGUN; - else if (self.ammo_shells >= 1 && it & WEAP_SHOTGUN) - return WEAP_SHOTGUN; - else if (it & WEAP_MEDIKIT) - return WEAP_MEDIKIT; - else if (it & WEAP_KNIFE) - return WEAP_KNIFE; - else if (it & WEAP_SPANNER) - return WEAP_SPANNER; - else if (it & WEAP_AXE) - return WEAP_AXE; +float W_BestWeaponSlot() { + FO_WeapState ws; + for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { + FO_FillWeapState(self, i, &ws); - return 0; + // AC also takes cells to fire. + if (ws->weapon == WEAP_ASSAULT_CANNON && self.ammo_cells < 7) + continue; + + if (ws.weapon != WEAP_NONE && + ((ws.wi)->ammo_type == AMMO_NONE || *ws.ammo_remaining)) + return i; + } + return TF_SLOT4; }; void () W_ChangeToBestWeapon = { - W_ChangeWeapon(W_BestWeapon()); + W_ChangeWeaponSlot(W_BestWeaponSlot()); } void () player_axe1; @@ -1659,7 +1628,7 @@ void () player_medikitb1; void () W_Attack = { float r; FO_WeapState ws; - FO_FillWeapState(self, self.current_weapon, &ws); + FO_FillCurrentWeapState(&ws); FO_WeapInfo* wi = ws->wi; if (self.has_disconnected == TRUE) @@ -1689,51 +1658,51 @@ void () W_Attack = { makevectors(self.v_angle); self.show_hostile = time + 1; - if (self.current_weapon == WEAP_AXE) { + if (ws.weapon == WEAP_AXE) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) player_axe1(); else player_axeb1(); - } else if (self.current_weapon == WEAP_KNIFE) { + } else if (ws.weapon == WEAP_KNIFE) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) player_knife1(); else player_knifeb1(); - } else if (self.current_weapon == WEAP_SPANNER) { + } else if (ws.weapon == WEAP_SPANNER) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); player_spanner1(); - } else if (self.current_weapon == WEAP_SHOTGUN) { + } else if (ws.weapon == WEAP_SHOTGUN) { player_shot1(); W_FireShotgun(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_SUPER_SHOTGUN) { + } else if (ws.weapon == WEAP_SUPER_SHOTGUN) { player_shot1(); W_FireSuperShotgun(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_NAILGUN) { + } else if (ws.weapon == WEAP_NAILGUN) { player_nail1(); - } else if (self.current_weapon == WEAP_SUPER_NAILGUN) { + } else if (ws.weapon == WEAP_SUPER_NAILGUN) { player_nail1(); - } else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) { + } else if (ws.weapon == WEAP_GRENADE_LAUNCHER) { player_rocket1(); W_FireGrenade(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_PIPE_LAUNCHER) { + } else if (ws.weapon == WEAP_PIPE_LAUNCHER) { player_rocket1(); W_FireGrenade(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) { + } else if (ws.weapon == WEAP_ROCKET_LAUNCHER) { player_rocket1(); W_FireRocket(); Status_Refresh(self); - } else if (self.current_weapon == WEAP_LIGHTNING) { + } else if (ws.weapon == WEAP_LIGHTNING) { player_light1(); FO_Sound(self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); - } else if (self.current_weapon == WEAP_SNIPER_RIFLE) { + } else if (ws.weapon == WEAP_SNIPER_RIFLE) { if (self.flags & FL_ONGROUND) { player_shot1(); W_FireSniperRifle(); @@ -1741,10 +1710,10 @@ void () W_Attack = { Status_Refresh(self); } } - } else if (self.current_weapon == WEAP_AUTO_RIFLE) { + } else if (ws.weapon == WEAP_AUTO_RIFLE) { player_autorifle1(); W_FireAutoRifle(); - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { + } else if (ws.weapon == WEAP_ASSAULT_CANNON) { if (self.ammo_cells < 7) { if (time >= self.antispam_assault_cannon) { sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); @@ -1759,14 +1728,14 @@ void () W_Attack = { TeamFortress_SetSpeed(self); player_assaultcannonup(); } - } else if (self.current_weapon == WEAP_FLAMETHROWER) { + } else if (ws.weapon == WEAP_FLAMETHROWER) { player_shot1(); W_FireFlame(); if (self.waterlevel > 2) Attack_Finished(1); else Attack_Finished(0.15); - } else if (self.current_weapon == WEAP_INCENDIARY) { + } else if (ws.weapon == WEAP_INCENDIARY) { if (self.ammo_rockets >= 3) { player_rocket1(); W_FireIncendiaryCannon(); @@ -1774,39 +1743,38 @@ void () W_Attack = { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; } - } else if (self.current_weapon == WEAP_MEDIKIT) { + } else if (ws.weapon == WEAP_MEDIKIT) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); r = random(); if (r < 0.5) player_medikit1(); else player_medikitb1(); - } else if (self.current_weapon == WEAP_TRANQ) { + } else if (ws.weapon == WEAP_TRANQ) { FO_Sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); player_shot1(); W_FireTranq(); - } else if (self.current_weapon == WEAP_RAILGUN) { + } else if (ws.weapon == WEAP_RAILGUN) { FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireLaser(); } - if (self.current_weapon != WEAP_FLAMETHROWER && // Variable - self.current_weapon != WEAP_ASSAULT_CANNON && // In animation - self.current_weapon != WEAP_NAILGUN && // In animation - self.current_weapon != WEAP_SUPER_NAILGUN) // In animation + if (ws.weapon != WEAP_FLAMETHROWER && // Variable + ws.weapon != WEAP_ASSAULT_CANNON && // In animation + ws.weapon != WEAP_NAILGUN && // In animation + ws.weapon != WEAP_SUPER_NAILGUN) // In animation Attack_Finished(wi->attack_time); if (wi->needs_reload) { - if (self.current_weapon != WEAP_ASSAULT_CANNON) // In animation + if (ws.weapon != WEAP_ASSAULT_CANNON) // In animation *ws->clip_fired += wi->ammo_per_shot; FO_CheckForReload(); } //These weapons have to log each projectile launched/bullet fired - if (self.current_weapon != WEAP_ASSAULT_CANNON || - self.current_weapon != WEAP_NAILGUN || - self.current_weapon != WEAP_SUPER_NAILGUN) + if (ws.weapon != WEAP_ASSAULT_CANNON || ws.weapon != WEAP_NAILGUN || + ws.weapon != WEAP_SUPER_NAILGUN) LogEventAttack(self); }; @@ -1819,7 +1787,7 @@ float WeaponReady() { } void () W_PrintWeaponMessage = { - switch (self.current_weapon) + switch (FO_CurrentWeapon()) { case WEAP_GRENADE_LAUNCHER: sprint(self, PRINT_MEDIUM, "Normal grenade mode\n"); @@ -2044,64 +2012,6 @@ float (float inp) W_OldAmmoSlot = { return 1; }; -struct ImpulseWeapons { - int class; - float weapons[7]; -}; - -static ImpulseWeapons impulse_weapons[] = { - { PC_UNDEFINED, { WEAP_AXE } }, - { PC_SCOUT, - { WEAP_AXE, WEAP_SHOTGUN, 0, WEAP_NAILGUN } }, - { PC_SNIPER, - { WEAP_AXE, WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN } }, - { PC_SOLDIER, - { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, - { PC_DEMOMAN, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, - { PC_MEDIC, - { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, - { PC_HVYWEAP, - { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, - { PC_PYRO, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, - { PC_SPY, - { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, - { PC_ENGINEER, - { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, - { PC_CIVILIAN, { WEAP_AXE } }, -}; - -float W_WeaponByImpulse(float impulse) { - if (impulse < 1 || impulse > 7) return 0; - return impulse_weapons[self.playerclass].weapons[impulse - 1]; -} - -static float HandlePyroSlotSwap(float slot) { - float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) - slot = 3 - slot; - return slot; -} - -float W_WeaponBySlot(float slot) { - FO_WeapInfo* wi = FO_ClassWeaponSlot(self.playerclass, - HandlePyroSlotSwap(slot)); - if (!wi) { - sprint(self, PRINT_HIGH, "No weapon\n"); - return 0; - } - - return wi->weapon; -} - -float W_GetWeaponByInput(float input) { - if (IsUsingOldImpulses()) - return W_WeaponByImpulse(input); - else - return W_WeaponBySlot(input); -} - static void W_AmmoError() { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -2115,93 +2025,100 @@ void W_ChangeWeaponByInput(float input) { if (input < 1 || input > GetMaxWeaponInput()) return; - float weapon = W_GetWeaponByInput(input); - if (weapon == 0) + float slot = FO_SlotByInput(input); + if (slot == TF_SLOT_NONE) return; - W_ChangeWeapon(weapon); + W_ChangeWeaponSlot(slot); } void W_QueueAndDisableWeapon() { - self.queue_weapon = self.current_weapon; + self.queue_slot = self.current_slot; // We don't want to actually call Update/Change since that could affect what // other players see. Caller should be setting some state that holds back // the queue (e.g. feigned). - self.current_weapon = WEAP_NONE; + self.current_slot = TF_SLOT_NONE; self.weaponmodel = ""; self.weaponframe = 0; } -void W_ChangeWeapon(float weapon) { +void W_ChangeWeaponSlot(float slot) { if (self.playerclass == 0) return; + FO_WeapState ws; + FO_FillWeapState(self, slot, &ws); + if (ws.weapon == WEAP_NONE) + return; + // queue next weapon if queue is not empty or has changed - if (!self.queue_weapon || weapon != self.queue_weapon) - self.queue_weapon = weapon; + if (!self.queue_slot || slot != self.queue_slot) + self.queue_slot = slot; // halt if weapon is not ready to be fired if (!WeaponReady()) return; - self.queue_weapon = 0; - - FO_WeapState ws; - FO_FillWeapState(self, weapon, &ws); + self.queue_slot = 0; if (*ws->ammo_remaining == 0) { W_AmmoError(); return; } - if (self.current_weapon == weapon) + if (self.current_slot == slot) return; - self.last_weapon = self.current_weapon; + self.last_slot = self.current_slot; + self.current_slot = slot; - self.current_weapon = weapon; W_UpdateCurrentWeapon(self); Status_Refresh(self); }; void W_ChangeWeaponLast() { - if (self.last_weapon == 0) - return; - - W_ChangeWeapon(self.last_weapon); + if (self.last_slot) + W_ChangeWeaponSlot(self.last_slot); }; -float W_FindPrevNextWeapon(float weapon, float is_prev) { - int i; - float *table = IsUsingOldImpulses() ? - impulse_weapons[self.playerclass].weapons : - class_weapons[self.playerclass].slots; +float W_FindPrevNextWeaponSlot(float slot, float is_prev) { + float i, len; - float len = GetMaxWeaponInput(); - for (i = 0; i < len; i++) - if (table[i] == weapon) - break; + float *table; + + if (IsUsingOldImpulses()) { + table = impulse_weapons[self.playerclass].slots; + len = impulse_weapons[self.playerclass].slots.length; + for (i = 0; i < 7; i++) + if (table[i] == slot) + break; + } else { + table = class_weapons[self.playerclass].slots; + len = class_weapons[self.playerclass].slots.length; + i = slot - TF_SLOT1; // Table is 0-index. + } float direction = is_prev ? -1 : 1; do { i = (i + direction + len) % len; } while (table[i] == 0); - return table[i]; + dprint(sprintf("FPN s=%d ip=%d i=%d\n", slot, is_prev, i)); + return IsUsingOldImpulses() ? table[i] : i + TF_SLOT1; } void W_ChangeWeaponNext() { - if (self.weaponmodel == string_null || self.current_weapon == 0) + if (self.weaponmodel == string_null || self.current_slot == 0) return; - W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, FALSE)); + W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, FALSE)); } void W_ChangeWeaponPrev() { - if (self.weaponmodel == string_null || self.current_weapon == 0) + if (self.weaponmodel == string_null || self.current_slot == 0) return; - W_ChangeWeapon(W_FindPrevNextWeapon(self.current_weapon, TRUE)); + W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, TRUE)); } void () PreMatchImpulses; @@ -2266,13 +2183,13 @@ void () ImpulseCommands = { else if (self.impulse == TF_WEAPPREV) W_ChangeWeaponPrev(); else if (self.impulse == TF_RELOAD) - TeamFortress_ReloadCurrentWeapon(); + FO_ReloadSlot(self.current_slot, FALSE); else if (self.impulse == TF_RELOAD_SLOT1) - TeamFortress_ReloadSlot(1); + FO_ReloadSlot(TF_SLOT1, FALSE); else if (self.impulse == TF_RELOAD_SLOT2) - TeamFortress_ReloadSlot(2); + FO_ReloadSlot(TF_SLOT2, FALSE); else if (self.impulse == TF_RELOAD_SLOT3) - TeamFortress_ReloadSlot(3); + FO_ReloadSlot(TF_SLOT3, FALSE); else if (self.impulse == TF_RELOAD_NEXT) TeamFortress_ReloadNext(); else if (self.impulse == TF_DETPACK_5) @@ -2650,17 +2567,11 @@ void () ButtonFrame = { if (input_buttons & BUTTON4) { switch (self.playerclass) { case PC_SOLDIER: - if (IsUsingOldImpulses()) { - self.impulse = 7; - } else { - self.impulse = TF_SLOT1; - } + self.impulse = TF_SLOT1; // Intercepted by InterceptRocketJump() break; case PC_PYRO: - if (IsUsingOldImpulses()) { - self.impulse = 7; - } else if (IsUsingCFImpulses()) { + if (IsUsingCFImpulses()) { self.impulse = TF_SLOT2; } else { self.impulse = TF_SLOT1; @@ -2793,7 +2704,7 @@ void () W_WeaponFrame = { return; } - if ((self.is_feigning) && + if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && (self.impulse != TF_MEDIC_HELPME) && @@ -2812,7 +2723,7 @@ void () W_WeaponFrame = { // there were already so many edge cases in the old code such as swapping on // an empty weapon. if (self.impulse == TF_QUICKSTOP) - self.impulse = self.qf_swap_last_weapon ? TF_WEAPLAST : 0; + self.impulse = self.qf_swap_last_slot ? TF_WEAPLAST : 0; float can_change_weapon = WeaponReady() && !self.is_detpacking && !(self.is_building && !engineer_move); @@ -2825,13 +2736,13 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - float weapon = W_WeaponBySlot(self.impulse - TF_QUICKSLOT1 + 1); - self.qf_swap_last_weapon = weapon != self.current_weapon; - W_ChangeWeapon(weapon); + float slot = self.impulse - TF_QUICKSLOT1 + TF_SLOT1; + self.qf_swap_last_slot = slot != self.current_slot; + W_ChangeWeaponSlot(slot); self.impulse = 0; - } else if (self.queue_weapon > 0 && can_change_weapon) { - // change weapon if queue_weaponslot has been set - W_ChangeWeapon(self.queue_weapon); + } else if (self.queue_slot > 0 && can_change_weapon) { + // change slot if queue_slot has been set + W_ChangeWeaponSlot(self.queue_slot); } if (self.impulse == TF_CHANGETEAM) { @@ -2935,7 +2846,7 @@ void () W_WeaponFrame = { && (!self.fire_held_down || (self.fire_held_down && self.heat == 0 && self.playerclass == PC_HVYWEAP))) { - if (self.current_weapon == WEAP_SNIPER_RIFLE) { + if (FO_CurrentWeapon() == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) { self.heat = self.heat + 3; @@ -2958,7 +2869,7 @@ void () W_WeaponFrame = { TeamFortress_SetSpeed(self); } } - } else if (self.current_weapon == WEAP_ASSAULT_CANNON) { + } else if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON) { if (self.flags & FL_ONGROUND || cannon_air) { SuperDamageSound(); W_Attack(); From d9aca9bf938cb029350786e0d14001d5ae60444b Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 2 Oct 2022 17:14:52 -0700 Subject: [PATCH 1759/2474] Harden interfaces with opaque Slot tokens We've seen one or two crashes with out of bound slots, the code is also confusing in terms of trying to determine when you need to do input checking and when you can just trust that a slot is valid. Try to better formalize this by introducing an opaque slot token type that references valid slots. --- share/defs.h | 16 +-- share/fo_weapons.qc | 86 ++++++++------- ssqc/actions.qc | 15 ++- ssqc/client.qc | 4 +- ssqc/hwguy.qc | 2 +- ssqc/player.qc | 4 +- ssqc/qw.qc | 6 +- ssqc/tfort.qc | 9 +- ssqc/tforthlp.qc | 8 +- ssqc/vote.qc | 4 +- ssqc/weapons.qc | 250 +++++++++++--------------------------------- 11 files changed, 144 insertions(+), 260 deletions(-) diff --git a/share/defs.h b/share/defs.h index 9b748b06..ad1d2145 100644 --- a/share/defs.h +++ b/share/defs.h @@ -297,6 +297,9 @@ /* Toggleable Game Settings */ /*======================================================*/ +// Opaque token that encapsulates slots for correctness. +struct Slot { int id; }; + // Some of the toggleflags aren't used anymore, but the bits are still // there to provide compatability with old maps #define TFLAG_CLASS_PERSIST 1 // Persistent Classes Bit @@ -372,14 +375,11 @@ /*======================================================*/ /* Impulse Defines */ /*======================================================*/ -#define TF_SLOT_NONE 0 -#define TF_SLOT1 1 // Changes weapon to slot 1 (primary weapon) -#define TF_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) -#define TF_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) -#define TF_SLOT4 4 // Changes weapon to slot 4 (melee weapon) -#define TF_SLOT_LAST TF_SLOT4 -#define TF_SLOT_MELEE TF_SLOT4 -#define TF_NUM_SLOTS (TF_SLOT_LAST - TF_SLOT1 + 1) +#define TF_IMPULSE_SLOT1 1 // Changes weapon to slot 1 (primary weapon) +#define TF_IMPULSE_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) +#define TF_IMPULSE_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) +#define TF_IMPULSE_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_NUM_SLOTS 4 #define TF_CLASSMENU 5 // Brings up class menu // unused 6 diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 3826e537..ebaf66a3 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -18,6 +18,26 @@ float pyro_type = PYRO_FO; float old_ng_rof = FALSE; #endif +// Careful: Slots are not 0-indexed they start from 1. +// Use SlotIndex() to convert a slot if you're indexing an array. +Slot MakeSlot(float slot_num) { + if (slot_num < 1 || slot_num > TF_NUM_SLOTS) + error(sprintf("invalid slot %d\n", slot_num)); + + Slot result; + result.id = slot_num; + return result; +} + +const Slot SlotMelee = { 4 }; +const Slot SlotNull = { 0 }; +inline float IsSlotNull(Slot slot) { return slot.id == 0; } +inline float IsSlotMelee(Slot slot) { return slot.id == 3; } +inline float IsSameSlot(Slot slot1, Slot slot2) { return slot1.id == slot2.id; } + +// Returns dense [0..TF_NUM_SLOTS-1] +float SlotIndex(Slot slot) { return slot.id - 1; } + // Convert a weapon-bit to a linear index. static float WEAP_to_index(float weapon) { float index = 0; @@ -171,15 +191,16 @@ static float* AMMO_to_p(entity player, AmmoType ammo_type) { return __NULL__; } -float WEAP_to_slot(float class, float weapon) { - for (float i = 0; i < 4; i++) - if (class_weapons[class].slots[i] == weapon) - return i + TF_SLOT1; - return -1; +Slot WEAP_to_slot(float playerclass, float weapon) { + for (float i = 0; i < TF_NUM_SLOTS; i++) { + if (class_weapons[playerclass].slots[i] == weapon) + return MakeSlot(i + 1); + } + return SlotNull; } // Internal clip storage for both SSQC/CSQC. -.float clip_fired[TF_SLOT_LAST - TF_SLOT1 + 1]; +.float clip_fired[TF_NUM_SLOTS]; struct FO_WeapToItem { int weapon; @@ -214,25 +235,16 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_RAILGUN, IT_SHOTGUN}, }; -float BoundSlotInput(float slot) { - if (slot < TF_SLOT1 || slot > TF_SLOT4) { - return TF_SLOT4; - } else { - return slot; - } -} - -FO_WeapInfo* FO_SlotWeapInfo(float class, float slot) { - if (slot == TF_SLOT_NONE) +FO_WeapInfo* FO_SlotWeapInfo(float class, Slot slot) { + if (IsSlotNull(slot)) return FO_GetWeapInfo(WEAP_NONE); FO_ClassWeapons* cw = &class_weapons[class]; - slot = BoundSlotInput(slot); - return cw->info[slot - TF_SLOT1] ? cw->info[slot - TF_SLOT1] : + return cw->info[SlotIndex(slot)] ? cw->info[SlotIndex(slot)] : FO_GetWeapInfo(WEAP_NONE); } -float FO_ClassWeaponBySlot(float class, float slot) { +float FO_ClassWeaponBySlot(float class, Slot slot) { FO_WeapInfo* wi = FO_SlotWeapInfo(class, slot); if (!wi) return WEAP_NONE; @@ -240,15 +252,15 @@ float FO_ClassWeaponBySlot(float class, float slot) { return wi->weapon; } -float FO_WeaponSlot(float slot) { +float FO_WeaponSlot(Slot slot) { return FO_ClassWeaponBySlot(self.playerclass, slot); } float FO_ClassWeapItemMask(float class) { float result = 0; - for (int i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { - FO_WeapInfo* wi = FO_SlotWeapInfo(class, i); + for (int i = 1; i <= TF_NUM_SLOTS; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(class, MakeSlot(i)); if (wi) result |= (wi->items)->it_weapon; } @@ -257,8 +269,8 @@ float FO_ClassWeapItemMask(float class) { float FO_WeaponsMask(entity player) { float mask = 0; - for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { - FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, i); + for (float i = 1; i <= TF_NUM_SLOTS; i++) { + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, MakeSlot(i)); if (wi) mask |= wi->weapon; } @@ -268,7 +280,7 @@ float FO_WeaponsMask(entity player) { #ifdef SSQC struct FO_WeapState { float weapon; - float slot; + Slot slot; // Constant and relative to weapon. TODO, migrate similar to WeapInfo. FO_WeapInfo* wi; @@ -279,9 +291,7 @@ struct FO_WeapState { }; -void FO_FillWeapState(entity player, float slot, FO_WeapState* result) { - if (slot < 0 || slot > 4) error(sprintf("SLOT %d OOB\n", slot)); - +void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, slot); result->weapon = wi->weapon; @@ -290,13 +300,13 @@ void FO_FillWeapState(entity player, float slot, FO_WeapState* result) { result->ammo_remaining = AMMO_to_p(player, wi->ammo_type); - if (slot != TF_SLOT_NONE) - result->clip_fired = &player.clip_fired[slot - TF_SLOT1]; + if (!IsSlotNull(slot)) + result->clip_fired = &player.clip_fired[SlotIndex(slot)]; else result->clip_fired = __NULL__; } -float FO_ClassWeaponBySlot(float class, float slot); +float FO_ClassWeaponBySlot(float class, Slot slot); inline float FO_CurrentWeapon() { return FO_ClassWeaponBySlot(self.playerclass, self.current_slot); @@ -336,7 +346,7 @@ static void FOT_ReloadTimer() { Status_Refresh(self.owner); } -float FO_CanReload(float slot) { +float FO_CanReload(Slot slot) { FO_WeapState ws; FO_FillWeapState(self, slot, &ws); FO_WeapInfo* wi = ws->wi; @@ -352,7 +362,7 @@ float FO_CanReload(float slot) { } void () RestoreDefaultWeapon; -void FO_ReloadSlot(float slot, float force) { +void FO_ReloadSlot(Slot slot, float force) { RestoreDefaultWeapon(); if (self.tfstate & TFSTATE_RELOADING) return; @@ -445,7 +455,7 @@ struct ImpulseWeapon { float weapons[7]; // Autogenerated - float slots[7]; + Slot slots[7]; }; ImpulseWeapon impulse_weapons[] = { @@ -471,7 +481,7 @@ ImpulseWeapon impulse_weapons[] = { { PC_CIVILIAN, { WEAP_AXE } }, }; -float FO_ImpulseToSlot(float impulse) { +Slot FO_ImpulseToSlot(float impulse) { if (impulse < 1 || impulse > 7) return 0; return impulse_weapons[self.playerclass].slots[impulse - 1]; } @@ -496,10 +506,12 @@ static float HandlePyroSlotSwap(float slot) { return slot; } -float FO_SlotByInput(float input) { - return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : input; +Slot FO_SlotByInput(float input) { + return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : MakeSlot(input); } +float getv(float v) { return v; } + void FO_Weapons_Init() { float i, j; diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 0367bffd..259389e4 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -468,28 +468,25 @@ void (entity pe_player, float f_type) CF_Identify = { void () RestoreDefaultWeapon = { float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); - if (default_weapon >= 1 && default_weapon <= 4) { - W_ChangeWeaponSlot(default_weapon); + if (default_weapon >= 1 && default_weapon <= TF_NUM_SLOTS) { + W_ChangeWeaponSlot(MakeSlot(default_weapon)); } }; void () TeamFortress_ReloadNext = { - float slot = self.current_slot; + Slot slot = self.current_slot; if (!FO_CanReload(slot)) { - for (int i = 1; i < TF_NUM_SLOTS; i++) { - slot = slot + 1; // Easier to read than mod version because 1-base. - if (slot > TF_SLOT_LAST) - slot -= TF_NUM_SLOTS; - sprint(self, PRINT_HIGH, sprintf("checking %d\n", slot)); + int base = SlotIndex(slot); + for (int i = 1; i < TF_NUM_SLOTS; i++) { + slot = MakeSlot(1 + ((base + 1) % TF_NUM_SLOTS)); if (FO_CanReload(slot)) break; } } if (FO_CanReload(slot)) { - sprint(self, PRINT_HIGH, sprintf("reloading %d\n", slot)); FO_ReloadSlot(slot, FALSE); RestoreDefaultWeapon(); } else { diff --git a/ssqc/client.qc b/ssqc/client.qc index 68d3da8e..80212fd3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -118,7 +118,7 @@ void () SetChangeParms = { parm5 = self.ammo_nails; parm6 = self.ammo_rockets; parm7 = self.ammo_cells; - parm8 = self.current_slot; + parm8 = SlotIndex(self.current_slot) + 1; parm9 = self.armortype * 100; parm10 = 0; parm11 = 0; @@ -2926,8 +2926,6 @@ void () CheckPowerups = { } }; -void FO_FillWeapState(entity player, float weapon, FO_WeapState* ws); - void () PlayerPostThink = { UpdateScoreboardInfo(self); FOPlayer fop = (FOPlayer)self; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 23336746..dd7ec290 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -114,7 +114,7 @@ void LaunchAssCan(vector org, vector dir, float proj_speed) void FireAssCan (float shotcount, vector dir, vector spread) { FO_WeapState ws; - FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + FO_FillWeapState(self, MakeSlot(1), &ws); Status_Refresh(self); FO_CheckForReload(); diff --git a/ssqc/player.qc b/ssqc/player.qc index a81a28f2..12a962e2 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -90,7 +90,7 @@ void () player_stand1 =[17, player_stand1] { player_run(); return; } - if (self.current_slot == TF_SLOT_MELEE) { + if (IsSlotMelee(self.current_slot)) { if (self.walkframe >= 12) { self.walkframe = 0; } @@ -412,7 +412,7 @@ void () player_nail2 =[104, player_nail1] { static float CheckNeedAssaultCannonDown() { FO_WeapState ws; - FO_FillWeapState(self, WEAP_ASSAULT_CANNON, &ws); + FO_FillWeapState(self, MakeSlot(1), &ws); if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 7f46aef5..6457e80b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -206,9 +206,9 @@ float coop; /*==============================================*/ /* New Weapon variables */ /*==============================================*/ -.float current_slot; // the currently equipped (weapon) slot -.float last_slot; // the last slot the player was using -.float queue_slot; // the slot to switch to when possible +.Slot current_slot; // the currently equipped (weapon) slot +.Slot last_slot; // the last slot the player was using +.Slot queue_slot; // the slot to switch to when possible .float ammo_medikit; // Ammo used for the medikit .float maxammo_medikit; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f5ea8890..4658c89d 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1567,9 +1567,10 @@ void () TeamFortress_SetEquipment = { kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); self.items = FO_ClassWeapItemMask(self.playerclass) | kept_items; - if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { - self.current_slot = 0; - self.last_slot = 0; + if (!remember_weapon || self.last_playerclass != self.playerclass || + (self.tfstate & TFSTATE_RANDOMPC)) { + self.current_slot = SlotMelee; + self.last_slot = SlotNull; } self.tf_items = 0; @@ -2202,7 +2203,7 @@ void () TeamFortress_SetEquipment = { self.armortype = 0; self.armorvalue = 0; self.weapon = 0; - self.current_slot = 0; + self.current_slot = SlotNull; self.flags = FL_CLIENT | FL_NOTARGET; self.waterlevel = 3; diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 3be9685e..44368883 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -85,10 +85,10 @@ void () TeamFortress_MOTD = { } else { TeamFortress_AliasString("menu", "cmd menu"); } - TeamFortress_Alias("slot1", TF_SLOT1, 0); - TeamFortress_Alias("slot2", TF_SLOT2, 0); - TeamFortress_Alias("slot3", TF_SLOT3, 0); - TeamFortress_Alias("slot4", TF_SLOT4, 0); + TeamFortress_Alias("slot1", TF_IMPULSE_SLOT1, 0); + TeamFortress_Alias("slot2", TF_IMPULSE_SLOT2, 0); + TeamFortress_Alias("slot3", TF_IMPULSE_SLOT3, 0); + TeamFortress_Alias("slot4", TF_IMPULSE_SLOT4, 0); // you shouldn't use these in fte, use setinfo default_weapon and +quick instead // leaving in to prevent breaking change diff --git a/ssqc/vote.qc b/ssqc/vote.qc index 7d277cf3..56f50ca8 100644 --- a/ssqc/vote.qc +++ b/ssqc/vote.qc @@ -1229,7 +1229,7 @@ void () AnarchyMode = { local entity e = find(world, classname, "player"); while(e) { // TODO: Add a no weap switch to handle this like it used to. - e.current_slot = TF_SLOT4; + e.current_slot = SlotMelee; if(e.vote_map) { e.items |= IT_QUAD; e.tfstate &= 128; @@ -1263,7 +1263,7 @@ void () EndVoting = { while(e) { e.vote_map = world; e.items = 0; - e.current_slot = TF_SLOT4; + e.current_slot = SlotMelee; e.super_damage_finished = 0; //if(e.effects & EF_BLUE) e.effects = e.effects - EF_BLUE; TeamFortress_SetSpeed(e); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5880f678..fdb15faf 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -10,7 +10,7 @@ void () SuperDamageSound; void () ConcussionGrenadeTimer; void () OldConcussionGrenadeTimer; -void (float slot) W_ChangeWeaponSlot; +void (Slot slot) W_ChangeWeaponSlot; void () W_ChangeToBestWeapon; void () W_PrintWeaponMessage; @@ -1553,7 +1553,7 @@ void () superspike_touch = { void (entity pl) W_UpdateCurrentWeapon = { entity oldself; - if ((pl.health <= 0) || (pl.current_slot == 0)) + if ((pl.health <= 0) || IsSlotNull(pl.current_slot)) return; FO_WeapState ws; @@ -1582,20 +1582,23 @@ void (entity pl) W_UpdateCurrentWeapon = { } }; -float W_BestWeaponSlot() { +Slot W_BestWeaponSlot() { FO_WeapState ws; - for (float i = TF_SLOT1; i <= TF_SLOT_LAST; i++) { - FO_FillWeapState(self, i, &ws); + for (float i = 1; i <= TF_NUM_SLOTS; i++) { + Slot slot = MakeSlot(i); + FO_FillWeapState(self, slot, &ws); // AC also takes cells to fire. if (ws->weapon == WEAP_ASSAULT_CANNON && self.ammo_cells < 7) continue; + // We don't need to handle out of ammo medi/spanner here because of + // fallback below. if (ws.weapon != WEAP_NONE && ((ws.wi)->ammo_type == AMMO_NONE || *ws.ammo_remaining)) - return i; + return slot; } - return TF_SLOT4; + return SlotMelee; }; void () W_ChangeToBestWeapon = { @@ -1870,148 +1873,6 @@ float (float weap) W_OldGetSlot = { return 0; }; -float (float inp) W_AmmoSlot = { - local float cf_pyro_impulses = FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); - self.noammo = 0; - - if (inp == TF_SLOT1) { - if (self.playerclass == PC_SCOUT && self.ammo_nails < 2) - self.noammo = 1; - else if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_SOLDIER && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_MEDIC && self.ammo_nails < 4) - self.noammo = 1; - else if (self.playerclass == PC_HVYWEAP) { - if (self.ammo_shells < 1) - self.noammo = 1; - else if (self.ammo_cells < 7) - self.noammo = 2; - } else if (self.playerclass == PC_PYRO && !cf_pyro_impulses && self.ammo_rockets < 3) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && cf_pyro_impulses && self.ammo_cells < 3) - self.noammo = 1; - else if (self.playerclass == PC_SPY && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_ENGINEER && self.ammo_nails < 1) - self.noammo = 1; - } else if (inp == TF_SLOT2) { - if (self.playerclass == PC_SCOUT && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) - self.noammo = 1; - else if ((self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - && self.ammo_shells < 2) - self.noammo = 1; - else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && !cf_pyro_impulses && self.ammo_cells < 1) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && cf_pyro_impulses && self.ammo_rockets < 1) - self.noammo = 1; - } else if (inp == TF_SLOT3) { - if (self.playerclass == PC_SCOUT - || self.playerclass == PC_ENGINEER) - return 0; - if ((self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - && self.ammo_nails < 2) - self.noammo = 1; - else if ((self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO) - && self.ammo_shells < 1) - self.noammo = 1; - } else if (inp == TF_SLOT4) - return 1; - - if (self.noammo > 0) - return 0; - else - return 1; -}; - -float (float inp) W_OldAmmoSlot = { - self.noammo = 0; - if (inp == TF_SLOT1) { - return 1; - } - else if (inp == TF_SLOT2) { - if ((self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SOLDIER - || self.playerclass == PC_DEMOMAN - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_PYRO - || self.playerclass == PC_SPY) - && self.ammo_shells < 1) - self.noammo = 1; - else if (self.playerclass == PC_ENGINEER && self.ammo_nails < 1) - self.noammo = 1; - - } - else if (inp == TF_SLOT3) { - if (self.playerclass == PC_SNIPER && self.ammo_shells < 1) - self.noammo = 1; - else if ((self.playerclass == PC_SOLDIER - || self.playerclass == PC_MEDIC - || self.playerclass == PC_HVYWEAP - || self.playerclass == PC_SPY - || self.playerclass == PC_ENGINEER) - && self.ammo_shells < 2) - self.noammo = 1; - } - else if (inp == TF_SLOT4) { - if ((self.playerclass == PC_SCOUT - || self.playerclass == PC_SNIPER - || self.playerclass == PC_SPY) - && self.ammo_nails < 2) - self.noammo = 1; - } - else if (inp == 5) { - if (self.playerclass == PC_MEDIC && self.ammo_nails < 4) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) - self.noammo = 1; - } - else if (inp == 6) { - if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_PYRO && self.ammo_cells < 1) - self.noammo = 1; - - } - else if (inp == 7) { - if (self.playerclass == PC_SOLDIER && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_DEMOMAN && self.ammo_rockets < 1) - self.noammo = 1; - else if (self.playerclass == PC_HVYWEAP) { - if (self.ammo_shells < 1) - self.noammo = 1; - else if (self.ammo_cells < 7) - self.noammo = 2; - } - else if (self.playerclass == PC_PYRO && self.ammo_rockets < 3) - self.noammo = 1; - - } - if (self.noammo > 0) - return 0; - else - return 1; -}; - static void W_AmmoError() { if (self.noammo == 1) sprint(self, PRINT_HIGH, "Not enough ammo\n"); @@ -2025,8 +1886,8 @@ void W_ChangeWeaponByInput(float input) { if (input < 1 || input > GetMaxWeaponInput()) return; - float slot = FO_SlotByInput(input); - if (slot == TF_SLOT_NONE) + Slot slot = FO_SlotByInput(input); + if (IsSlotNull(slot)) return; W_ChangeWeaponSlot(slot); @@ -2037,12 +1898,12 @@ void W_QueueAndDisableWeapon() { // We don't want to actually call Update/Change since that could affect what // other players see. Caller should be setting some state that holds back // the queue (e.g. feigned). - self.current_slot = TF_SLOT_NONE; + self.current_slot = SlotNull; self.weaponmodel = ""; self.weaponframe = 0; } -void W_ChangeWeaponSlot(float slot) { +void W_ChangeWeaponSlot(Slot slot) { if (self.playerclass == 0) return; @@ -2052,21 +1913,22 @@ void W_ChangeWeaponSlot(float slot) { return; // queue next weapon if queue is not empty or has changed - if (!self.queue_slot || slot != self.queue_slot) + if (IsSlotNull(self.queue_slot) || !IsSameSlot(slot, self.queue_slot)) self.queue_slot = slot; // halt if weapon is not ready to be fired if (!WeaponReady()) return; - self.queue_slot = 0; + self.queue_slot = SlotNull; - if (*ws->ammo_remaining == 0) { + // We still allow swapping to medikit/spanner with no ammo. + if (*ws->ammo_remaining == 0 && !IsSlotMelee(slot)) { W_AmmoError(); return; } - if (self.current_slot == slot) + if (IsSameSlot(slot, self.current_slot)) return; self.last_slot = self.current_slot; @@ -2077,45 +1939,54 @@ void W_ChangeWeaponSlot(float slot) { }; void W_ChangeWeaponLast() { - if (self.last_slot) + if (!IsSlotNull(self.last_slot)) W_ChangeWeaponSlot(self.last_slot); }; -float W_FindPrevNextWeaponSlot(float slot, float is_prev) { +Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { float i, len; - - float *table; + float direction = is_prev ? -1 : 1; if (IsUsingOldImpulses()) { - table = impulse_weapons[self.playerclass].slots; - len = impulse_weapons[self.playerclass].slots.length; - for (i = 0; i < 7; i++) - if (table[i] == slot) + Slot* impulse_table = impulse_weapons[self.playerclass].slots; + // For reasons that seem to rhyme with -ompilerbug, reads from + // impulse_table[offset] return junk so we use a pointer cursor. + Slot* cur; + len = 7; + + for (i = 0; i < len; i++) { + cur = &impulse_table[i]; + if (IsSameSlot(*cur, slot)) break; + } + do { + i = (i + direction + len) % len; + cur = &impulse_table[i]; + } while (IsSlotNull(*cur)); + + return *cur; } else { - table = class_weapons[self.playerclass].slots; - len = class_weapons[self.playerclass].slots.length; - i = slot - TF_SLOT1; // Table is 0-index. - } + float* slot_weaps = class_weapons[self.playerclass].slots; + len = 4; + i = SlotIndex(slot); - float direction = is_prev ? -1 : 1; - do { - i = (i + direction + len) % len; - } while (table[i] == 0); + do { + i = (i + direction + len) % len; + } while (slot_weaps[i] == 0); - dprint(sprintf("FPN s=%d ip=%d i=%d\n", slot, is_prev, i)); - return IsUsingOldImpulses() ? table[i] : i + TF_SLOT1; + return MakeSlot(i + 1); + } } void W_ChangeWeaponNext() { - if (self.weaponmodel == string_null || self.current_slot == 0) + if (self.weaponmodel == string_null || IsSlotNull(self.current_slot)) return; W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, FALSE)); } void W_ChangeWeaponPrev() { - if (self.weaponmodel == string_null || self.current_slot == 0) + if (self.weaponmodel == string_null || IsSlotNull(self.current_slot)) return; W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, TRUE)); @@ -2185,11 +2056,11 @@ void () ImpulseCommands = { else if (self.impulse == TF_RELOAD) FO_ReloadSlot(self.current_slot, FALSE); else if (self.impulse == TF_RELOAD_SLOT1) - FO_ReloadSlot(TF_SLOT1, FALSE); + FO_ReloadSlot(MakeSlot(1), FALSE); else if (self.impulse == TF_RELOAD_SLOT2) - FO_ReloadSlot(TF_SLOT2, FALSE); + FO_ReloadSlot(MakeSlot(2), FALSE); else if (self.impulse == TF_RELOAD_SLOT3) - FO_ReloadSlot(TF_SLOT3, FALSE); + FO_ReloadSlot(MakeSlot(3), FALSE); else if (self.impulse == TF_RELOAD_NEXT) TeamFortress_ReloadNext(); else if (self.impulse == TF_DETPACK_5) @@ -2567,14 +2438,14 @@ void () ButtonFrame = { if (input_buttons & BUTTON4) { switch (self.playerclass) { case PC_SOLDIER: - self.impulse = TF_SLOT1; + self.impulse = TF_IMPULSE_SLOT1; // Intercepted by InterceptRocketJump() break; case PC_PYRO: if (IsUsingCFImpulses()) { - self.impulse = TF_SLOT2; + self.impulse = TF_IMPULSE_SLOT2; } else { - self.impulse = TF_SLOT1; + self.impulse = TF_IMPULSE_SLOT1; } // Intercepted by InterceptRocketJump() break; @@ -2736,11 +2607,16 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - float slot = self.impulse - TF_QUICKSLOT1 + TF_SLOT1; - self.qf_swap_last_slot = slot != self.current_slot; - W_ChangeWeaponSlot(slot); + Slot slot = MakeSlot(self.impulse - TF_QUICKSLOT1 + 1); + + if (IsSameSlot(slot, self.current_slot)) { + self.qf_swap_last_slot = FALSE; + } else { + self.qf_swap_last_slot = TRUE; + W_ChangeWeaponSlot(slot); + } self.impulse = 0; - } else if (self.queue_slot > 0 && can_change_weapon) { + } else if (!IsSlotNull(self.queue_slot) && can_change_weapon) { // change slot if queue_slot has been set W_ChangeWeaponSlot(self.queue_slot); } From d5af260d9f87d59f85db3ee24fc1ad4b31652e73 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 12:27:24 -0700 Subject: [PATCH 1760/2474] Make sure we swap pyro 1/2 slots with cf_pyro_impulses Also extend handling to default_weapon which I'm not sure was covered before (although not commonly used). --- share/fo_weapons.qc | 17 ++++++++++------- ssqc/weapons.qc | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index ebaf66a3..aae000c2 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -499,19 +499,22 @@ float IsUsingOldImpulses() { return FALSE; } static float IsPyroSlotSwapped() { return FALSE; } #endif -static float HandlePyroSlotSwap(float slot) { +float InputHandlePyroSlotSwap(float input) { float cf_pyro_impulses = IsPyroSlotSwapped(); - if (self.playerclass == PC_PYRO && cf_pyro_impulses && (slot == 1 || slot == 2)) - slot = 3 - slot; - return slot; + if (self.playerclass == PC_PYRO && cf_pyro_impulses && (input == 1 || input == 2)) + input = 3 - input; + return input; } Slot FO_SlotByInput(float input) { - return IsUsingOldImpulses() ? FO_ImpulseToSlot(input) : MakeSlot(input); + if (IsUsingOldImpulses()) { + return FO_ImpulseToSlot(input); + } else { + input = InputHandlePyroSlotSwap(input); + return MakeSlot(input); + } } -float getv(float v) { return v; } - void FO_Weapons_Init() { float i, j; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fdb15faf..be927a1f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2384,7 +2384,7 @@ void () ButtonFrame = { local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); if (default_weapon >= 1 && default_weapon <= 4) { - self.impulse = default_weapon; + self.impulse = InputHandlePyroSlotSwap(default_weapon); } } From 53e3975690f832961e71aae0460177d269076f06 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 13:57:17 -0700 Subject: [PATCH 1761/2474] Also handle CFPI with weapnext/weapprev This is a little annoying since we're trying to walk [1234/4321] but with CFPI we must also consider [2134]/[4312]. --- ssqc/weapons.qc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index be927a1f..6c612030 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1968,13 +1968,16 @@ Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { } else { float* slot_weaps = class_weapons[self.playerclass].slots; len = 4; - i = SlotIndex(slot); + // This is a little subtle, we need to transform the index both before + // and after the walk so that we don't walk back into ourselves. + i = InputHandlePyroSlotSwap(SlotIndex(slot) + 1) - 1; do { i = (i + direction + len) % len; } while (slot_weaps[i] == 0); - return MakeSlot(i + 1); + i = InputHandlePyroSlotSwap(i + 1); + return MakeSlot(i); } } From 74a83e07e578b3262d6df72deb8738d75b033bf4 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 16:28:41 -0700 Subject: [PATCH 1762/2474] Make sure ReloadSlot checks for not a nullslot Generically called from impulse commands, could be no weapon. --- share/fo_weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index aae000c2..f1c9d9a0 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -364,7 +364,7 @@ float FO_CanReload(Slot slot) { void () RestoreDefaultWeapon; void FO_ReloadSlot(Slot slot, float force) { RestoreDefaultWeapon(); - if (self.tfstate & TFSTATE_RELOADING) + if (self.tfstate & TFSTATE_RELOADING || IsSlotNull(slot)) return; FO_WeapState ws; From e72a32b371c7f03e9e44e38a0e7be0a70a076907 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 20:49:15 -0700 Subject: [PATCH 1763/2474] Fix impulse 6/7 to grenade/pipe under old_weapon_impulses Also restore flavour text for bvr. --- share/fo_weapons.qc | 2 +- ssqc/weapons.qc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index f1c9d9a0..3d6e0225 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -467,7 +467,7 @@ ImpulseWeapon impulse_weapons[] = { { PC_SOLDIER, { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, { PC_DEMOMAN, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, { PC_MEDIC, { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, { PC_HVYWEAP, diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 6c612030..e16994f9 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1935,6 +1935,7 @@ void W_ChangeWeaponSlot(Slot slot) { self.current_slot = slot; W_UpdateCurrentWeapon(self); + W_PrintWeaponMessage(); Status_Refresh(self); }; From b8ec9dc144be13faac5497abe811640aeff51926 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 4 Oct 2022 00:40:05 -0700 Subject: [PATCH 1764/2474] Add debug helpers Better error messages, active comments. --- csqc/csprogs.src | 1 + csqc/sui_sys.qc | 1 - menu/menu.src | 1 + share/debug.qc | 65 +++++++++++++++++++++++++++++++++++++++++++++ share/fo_weapons.qc | 47 +++++++++++++++----------------- ssqc/antilag.qc | 22 +++++++-------- ssqc/progs.src | 1 + 7 files changed, 101 insertions(+), 37 deletions(-) create mode 100644 share/debug.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 37747e32..81b6c037 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -8,6 +8,7 @@ csdefs.qc csextradefs.qc +../share/debug.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 4e11eaa3..16896adc 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -5,7 +5,6 @@ // The API is made simple and easy to build upon, but cuts have been made // to keep complexity low. // -#define printf(x, ...) print(sprintf(x, __VA_ARGS__)) #ifdef MENU const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ diff --git a/menu/menu.src b/menu/menu.src index ce60d2ea..c5b8dc78 100644 --- a/menu/menu.src +++ b/menu/menu.src @@ -8,6 +8,7 @@ #includelist ../share/fteextensions.qc //also sets up system defs +../share/debug.qc ../menusys/mitems.qc //root item type ../menusys/mitems_common.qc //basic types diff --git a/share/debug.qc b/share/debug.qc new file mode 100644 index 00000000..c94c4b1c --- /dev/null +++ b/share/debug.qc @@ -0,0 +1,65 @@ +#ifdef SSQC + +// printf that works in any context +#define printf(...) bprint(PRINT_HIGH, sprintf(__VA_ARGS__)) +#define printd(...) dprint(sprintf(__VA_ARGS__)) + +#else + +#define printf(...) print(sprintf(__VA_ARGS__)) + +#endif + +#define MSEC 0.001 +#define SEC 1 + +#define errors(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__)) +#define errorf(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__, __VA_ARGS__)) + +#define _ASSERT_OP(_op, _invop, _fmt, _v1, _v2) \ + if (!((_v1) _op (_v2))) \ + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ + #_v1, #_v2, _v1, _v2) + +#define __ASSERT_OP(_op, _invop, _fmt, _v1, _v2, __v1, __v2) \ + if (!((__v1) _op (__v2))) \ + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ + #_v1, #_v2, __v1, __v2) + +#define ASSERTF_EQ(_v1, _v2) _ASSERT_OP(==, !=, %0.2f, _v1, _v2) +#define ASSERTF_NE(_v1, _v2) _ASSERT_OP(!=, ==, %0.2f, _v1, _v2) +#define ASSERTF_GT(_v1, _v2) _ASSERT_OP( >, <=, %0.2f, _v1, _v2) +#define ASSERTF_GE(_v1, _v2) _ASSERT_OP(>=, <, %0.2f, _v1, _v2) +#define ASSERTF_LT(_v1, _v2) _ASSERT_OP( <, >=, %0.2f, _v1, _v2) +#define ASSERTF_LE(_v1, _v2) _ASSERT_OP(<=, <, %0.2f, _v1, _v2) + + +// Work around general weird behaviors with __int +float __as_float(float v) { return v; } + +#define ASSERTD_EQ(_v1, _v2) __ASSERT_OP(==, !=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_NE(_v1, _v2) __ASSERT_OP(!=, ==, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_GT(_v1, _v2) __ASSERT_OP( >, <=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_GE(_v1, _v2) __ASSERT_OP(>=, <, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_LT(_v1, _v2) __ASSERT_OP( <, >=, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) +#define ASSERTD_LE(_v1, _v2) __ASSERT_OP(<=, <, %d, _v1, _v2, __as_float(_v1), __as_float(_v2)) + +#define ASSERTS_EQ(_v1, _v2) _ASSERT_OP(==, !=, %s, _v1, _v2) +#define ASSERTS_NE(_v1, _v2) _ASSERT_OP(!=, ==, %s, _v1, _v2) + +#define ASSERTF_TRUE(_v1) ASSERTF_EQ(_v1, TRUE) +#define ASSERTF_FALSE(_v1) ASSERTF_EQ(_v1, FALSE) + + +#define __CONCAT(_a, _b) _a ## _b +#define _PRINT_ONCE(_n, ...) \ + do { static float _n; if (!_n) { _n = TRUE; printf(__VA_ARGS__); } } while (0) +#define _PRINT_EVERY(_n, _p, ...) \ + do { static float _n; if (time > _n + _p) { _n = time + _p; printf(__VA_ARGS__); } } while (0) + +#define PRINT_ONCE(...) _PRINT_ONCE(__CONCAT(__once, __LINE__), __VA_ARGS__) +#define PRINT_EVERY(_p, ...) _PRINT_EVERY(__CONCAT(__every, __LINE_), _p, __VA_ARGS__) + +#define EPS 0.001 +#define FEQ(_v1, _v2) (fabs(_v1 - _v2) < EPS) +#define FNEQ(_v1, _v2) (fabs(_v1 - _v2) >= EPS) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 3d6e0225..84b41a60 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -22,7 +22,7 @@ float old_ng_rof = FALSE; // Use SlotIndex() to convert a slot if you're indexing an array. Slot MakeSlot(float slot_num) { if (slot_num < 1 || slot_num > TF_NUM_SLOTS) - error(sprintf("invalid slot %d\n", slot_num)); + errorf("invalid slot %d\n", slot_num); Slot result; result.id = slot_num; @@ -518,8 +518,7 @@ Slot FO_SlotByInput(float input) { void FO_Weapons_Init() { float i, j; - if (weapon_names.length != weapon_info.length) - error("Weapon Names/Weapon Info inconsistency\n"); + ASSERTD_EQ(weapon_names.length, weapon_info.length); FO_WeapInfo* WI_ac = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); WI_ac->clip_size = fo_hwguy ? PC_HVYWEAP_ASSCAN_CLIPSIZE : 0; @@ -545,30 +544,28 @@ void FO_Weapons_Init() { for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; - if (WEAP_to_index(wi->weapon) != i) - error(sprintf("WI mismatch at index %d\n", i)); - - if (wi->weapon == WEAP_PIPE_LAUNCHER) { - FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); - wi->ammo_type = parent->ammo_type; - wi->clip_size = parent->clip_size; - wi->full_reload_time = parent->full_reload_time; - wi->needs_reload = parent->needs_reload; - } else if (wi->clip_size > 0) { - wi->needs_reload = TRUE; - } else { - wi->needs_reload = FALSE; - } - - FO_WeapModels* wm = &weapon_models[i]; - if (WEAP_to_index(wm->weapon) != i) - error(sprintf("WM mismatch at index %d\n", i)); - precache_model(wm->model); - wi->models = wm; + ASSERTD_EQ(WEAP_to_index(wi->weapon), i); + + if (wi->weapon == WEAP_PIPE_LAUNCHER) { + FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); + wi->ammo_type = parent->ammo_type; + wi->clip_size = parent->clip_size; + wi->full_reload_time = parent->full_reload_time; + wi->needs_reload = parent->needs_reload; + } else if (wi->clip_size > 0) { + wi->needs_reload = TRUE; + } else { + wi->needs_reload = FALSE; + } + + FO_WeapModels* wm = &weapon_models[i]; + ASSERTD_EQ(WEAP_to_index(wm->weapon), i); + precache_model(wm->model); + wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; - if (WEAP_to_index(wti->weapon) != i) - error(sprintf("WTI mismatch at index %d\n", i)); + ASSERTD_EQ(WEAP_to_index(wti->weapon), i); + wi->items = wti; switch (wi->ammo_type) { case AMMO_SHELLS: wti->ammo_mask = IT_SHELLS; break; diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 7c82b62c..609f4d49 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -23,12 +23,12 @@ void AL_ProjectProjectile (entity projectile) { #define DEBUG_ANTILAG 0 -#if DEBUG_ANTILAG -#define printf(...) sprint(self, PRINT_HIGH, sprintf(__VA_ARGS__)) -#define printd(...) dprint(sprintf(__VA_ARGS__)) +#ifndef DEBUG_ANTILAG +#define al_printf(...) printf(__VA_ARGS__) +#define al_printd(...) dprint(__VA_ARGS__) #else -#define printf(...) -#define printd(...) +#define al_printf(...) +#define al_printd(...) #endif #define AL_MAX_REWINDS 25 @@ -157,14 +157,14 @@ SeekResult SeekBasic(RewindState* target, float when) { #if 0 void CompareSeek(SeekResult s1, SeekResult, s2) { if (before != (r.before)->time) - error(sprintf("before mismatch w=%f seek=%f check=%f\n", - when, (r.before)->time, before)); + errorf("before mismatch w=%f seek=%f check=%f\n", + when, (r.before)->time, before); if (after != (r.after)->time) - error(sprintf("after mismatch w=%f seek=%f check=%f\n", - when, (r.after)->time, after)); + errorf("after mismatch w=%f seek=%f check=%f\n", + when, (r.after)->time, after); if (nearest != (r.nearest)->time) - error(sprintf("nearest mismatch w=%f seek=%f check=%f\n", - when, (r.nearest)->time, nearest)); + errorf("nearest mismatch w=%f seek=%f check=%f\n", + when, (r.nearest)->time, nearest); } diff --git a/ssqc/progs.src b/ssqc/progs.src index e69fee0a..b8d67bdf 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -8,6 +8,7 @@ #includelist ../share/fteextensions.qc +../share/debug.qc defs.qc ../share/commondefs.qc ../share/common_helpers.qc From 872cad127abc91d71830c5683b9612163bba7ef1 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 01:52:57 -0700 Subject: [PATCH 1765/2474] Fix inversion on detpipe enable --- ssqc/antilag.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 609f4d49..e1eabc77 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -325,7 +325,7 @@ class FOPlayer { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { - if (antilag_settings.rewind_detpipe) + if (!antilag_settings.rewind_detpipe) return FALSE; float rewind_max_offset = ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT); From 29dbc52d9b510c3c1ecade98ce920dbf1cb7b41e Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 02:03:34 -0700 Subject: [PATCH 1766/2474] Make CFPI work with quickslots hydro pointed out that the quick slot inputs are are another place we need to carry the pyro slot swap option. --- ssqc/weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e16994f9..9971b8f6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2611,7 +2611,8 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - Slot slot = MakeSlot(self.impulse - TF_QUICKSLOT1 + 1); + float input = InputHandlePyroSlotSwap(self.impulse - TF_QUICKSLOT1 + 1); + Slot slot = MakeSlot(input); if (IsSameSlot(slot, self.current_slot)) { self.qf_swap_last_slot = FALSE; From b923ae60faad926bb452faf3de78002ed5ab1c39 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 5 Oct 2022 02:57:17 -0700 Subject: [PATCH 1767/2474] In the midst of giving this another pass, but I think this is actually closer to correct after all. --- ssqc/antilag.qc | 2 +- ssqc/client.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index e1eabc77..d1e82c0c 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,5 +1,5 @@ void AL_ProjectProjectile (entity projectile) { - float time_offset = time - client_time(CT_SLOW_PROJECTILE); + float time_offset = (time - client_time(CT_SLOW_PROJECTILE)) / 2; if (time_offset <= 0.013) // ping 13ms or lower? Don't do anything return; diff --git a/ssqc/client.qc b/ssqc/client.qc index 80212fd3..bf668a0a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -613,7 +613,7 @@ void () DecodeLevelParms = { // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); - antilag_settings.max_projectile_slow_offset = project_weapons_max_latency / 2; + antilag_settings.max_projectile_slow_offset = project_weapons_max_latency; // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); From f587b9bc43b6f6690b41220a73e2760bff5e0b93 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 6 Oct 2022 17:52:01 -0700 Subject: [PATCH 1768/2474] Fix off-by-one on Melee slot and add some logging for high indexes We're seeing a rare crash with an index of 4 (e.g. an effective slot 5), add some logging / hardening against this. --- share/fo_weapons.qc | 26 ++++++++++++++++++++++---- ssqc/client.qc | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 84b41a60..90f89cf8 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -18,9 +18,22 @@ float pyro_type = PYRO_FO; float old_ng_rof = FALSE; #endif +// Some preprocessor bug is making __LINE__ not substitute right here most of +// the time. Oh well, even if we just get file it's good enough to narrow. +#define CheckSlot(slot_num) _CheckSlot(__FILE__, __LINE__, slot_num) +float _CheckSlot(string file, float line, float slot_num) { + if (slot_num < 1 || slot_num > TF_NUM_SLOTS) { + printf("%s:%d: Invalid slot (%d). Continuing.\n", + file, line, slot_num); + return 4; + } + return slot_num; +} + +#define MakeSlot(slot_num) _MakeSlot(CheckSlot(slot_num)) // Careful: Slots are not 0-indexed they start from 1. // Use SlotIndex() to convert a slot if you're indexing an array. -Slot MakeSlot(float slot_num) { +Slot _MakeSlot(float slot_num) { if (slot_num < 1 || slot_num > TF_NUM_SLOTS) errorf("invalid slot %d\n", slot_num); @@ -32,11 +45,16 @@ Slot MakeSlot(float slot_num) { const Slot SlotMelee = { 4 }; const Slot SlotNull = { 0 }; inline float IsSlotNull(Slot slot) { return slot.id == 0; } -inline float IsSlotMelee(Slot slot) { return slot.id == 3; } +inline float IsSlotMelee(Slot slot) { return slot.id == 4; } inline float IsSameSlot(Slot slot1, Slot slot2) { return slot1.id == slot2.id; } // Returns dense [0..TF_NUM_SLOTS-1] -float SlotIndex(Slot slot) { return slot.id - 1; } +float SlotIndex(Slot slot) { + if (slot.id > 4) { + printf("ERROR: OOB slot id (%d) found. Continuing.\n", (float)slot.id); + return TF_NUM_SLOTS - 1; + } + return slot.id - 1; } // Convert a weapon-bit to a linear index. static float WEAP_to_index(float weapon) { @@ -445,7 +463,7 @@ float FO_CheckForReload() { void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; - for (int i = 0; i < 4; i++) + for (int i = 0; i < TF_NUM_SLOTS; i++) player.clip_fired[i] = 0; } #endif diff --git a/ssqc/client.qc b/ssqc/client.qc index bf668a0a..5c2d0482 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2075,6 +2075,7 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; + self.current_slot = SlotMelee; FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; From bd0dce084dba50efabbc4c1143ded9dae87e706b Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 6 Oct 2022 21:37:27 -0700 Subject: [PATCH 1769/2474] Spawn with SlotNull not Melee This was intended as a conservative state reset but it triggers other last selected weapon logic later and results in always spawning with axe, Null's a more correct choice anyway. --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5c2d0482..4c019e62 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2075,7 +2075,7 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; - self.current_slot = SlotMelee; + self.current_slot = SlotNull; FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; From b223363368b8304dbf94b8d7e3cd04f007671e1d Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 7 Oct 2022 16:48:37 -0700 Subject: [PATCH 1770/2474] Fix Ammo table A missing comma was resulting in silent string concatenation and a table size of 4. This was leading to OOB references that looked like they were on slots but were really on ammo. Originally I was going to restore grenades as an ammo type here (with flavour text) as well but other stuff is yielding a message first so will look at that later. --- share/fo_weapons.qc | 2 +- ssqc/client.qc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 90f89cf8..668302ee 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -194,7 +194,7 @@ static FO_WeapModels weapon_models[] = { }; // REQUIRES: Order must match above. -static string AMMO_to_s[] = {"shells", "cells", "nails" "rockets", "grenades"}; +static string AMMO_to_s[] = {"none", "shells", "nails", "cells", "rockets"}; static float* AMMO_to_p(entity player, AmmoType ammo_type) { switch (ammo_type) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 4c019e62..bf668a0a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2075,7 +2075,6 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; - self.current_slot = SlotNull; FO_InstantReloadAllWeapons(self); self.immune_to_check = time + 10; From 94cb1ee5878139042d6c899a3a578fd03b6014da Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 09:45:06 -0700 Subject: [PATCH 1771/2474] Make sure pipe/grenade launcher share clip Inadvertently removed in the collapse to slot/clip based storage. --- share/fo_weapons.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 668302ee..d20dcb36 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -322,6 +322,10 @@ void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { result->clip_fired = &player.clip_fired[SlotIndex(slot)]; else result->clip_fired = __NULL__; + + // Special case: Overlap with grenade launcher. + if (wi->weapon == WEAP_PIPE_LAUNCHER) + result->clip_fired = &player.clip_fired[0]; } float FO_ClassWeaponBySlot(float class, Slot slot); From 7fb8e379e68e617186eacabe8129e6b334321a9a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 10:07:02 -0700 Subject: [PATCH 1772/2474] Introduce stable clock `time` turns out to not be particularly well-aligned with frames, with it being often +/- half a frame by timing. Improve this by introducing a stable client_time clock (which subsumes some of the prior notion). Infrastructure for aligning think events (such as animation) with this clock (which can then be more strongly aligned with the client) is added. While we're here, migrate a bunch of other things that we're going to need to synchronize with this clock (too much really, but hard to split now). At least we simplified the reload timing and tracking in the transition. We pull a bunch of things back to time (e.g. pipecooldown) are not migrated yet since we need to also unify client_time with rewind or just generally test and tune. --- share/fo_weapons.qc | 89 ++++++++++++++++++++++----------------------- ssqc/actions.qc | 8 ++-- ssqc/antilag.qc | 45 +++-------------------- ssqc/client.qc | 28 +++++--------- ssqc/engineer.qc | 4 +- ssqc/progs.src | 1 + ssqc/qw.qc | 35 +++++++++++------- ssqc/spy.qc | 6 +-- ssqc/status.qc | 43 ++++------------------ ssqc/tfort.qc | 12 +++--- ssqc/time.qc | 50 +++++++++++++++++++++++++ ssqc/weapons.qc | 7 +++- 12 files changed, 158 insertions(+), 170 deletions(-) create mode 100644 ssqc/time.qc diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index d20dcb36..fa0d3768 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -83,8 +83,8 @@ struct FO_WeapToItem; struct FO_WeapInfo { int weapon; // Verification AmmoType ammo_type; - int clip_size; - int ammo_per_shot; + float clip_size; + float ammo_per_shot; float attack_time; float full_reload_time; @@ -295,6 +295,11 @@ float FO_WeaponsMask(entity player) { return mask; } +float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) { + float tick = (wi->ammo_per_shot / wi->clip_size) * wi->full_reload_time; + return ceil((reload_finished - now) / tick) * wi->ammo_per_shot; +} + #ifdef SSQC struct FO_WeapState { float weapon; @@ -345,27 +350,39 @@ inline void FO_FillCurrentWeapState(FO_WeapState* result) { void (entity pl) Status_Refresh; void (float att_delay) Attack_Finished; -static void FOT_ReloadTimer() { +// Hack until we fix Status_Refresh() to not be awful. +.float last_still_loading; + +float FO_ReloadFrame() { + if (self.tfstate & TFSTATE_RELOADING == 0) + return FALSE; + FO_WeapState ws; - FO_FillWeapState(self.owner, self.owner.current_slot, &ws); - - if (time >= self.heat) { - // Reload finished - self.owner.tfstate &= ~TFSTATE_RELOADING; - self.owner.weaponmodel = ((ws->wi)->models)->model; - self.owner.weaponframe = 0; - sprint(self.owner, PRINT_HIGH, "Finished reloading\n"); - dremove(self); - } else { - // Refresh clip - if (ws->weapon != WEAP_SNIPER_RIFLE) - self.owner.reload_clipsize += 1; - else - self.owner.reload_sniper_ticks += 1; + FO_FillWeapState(self, self.current_slot, &ws); + FO_WeapInfo* wi = ws.wi; + + if (wi->weapon == WEAP_NONE) + return FALSE; - self.nextthink = min(time + self.owner.reload_tick, self.heat); + if (self.client_time >= self.reload_finished) { + self.tfstate &= ~TFSTATE_RELOADING; + self.weaponmodel = ((ws->wi)->models)->model; + self.weaponframe = 0; + self.last_still_loading = 0; + Status_Refresh(self); + sprint(self, PRINT_HIGH, "Finished reloading\n"); + + return FALSE; } - Status_Refresh(self.owner); + + float still_loading = FO_NumClipStillLoading(wi, self.client_time, + self.reload_finished); + if (self.last_still_loading != still_loading) { + self.last_still_loading = still_loading; + Status_Refresh(self); + } + + return TRUE; } float FO_CanReload(Slot slot) { @@ -423,31 +440,11 @@ void FO_ReloadSlot(Slot slot, float force) { float reload_duration = (reload_count / wi->clip_size) * wi->full_reload_time; - *ws->clip_fired -= reload_count; - - // Sets up for status bar. - self.reload_time = time + reload_duration; - self.reload_tick = reload_duration / reload_count; - self.reload_clipsize = wi->clip_size - reload_count; - - // Actual entity that will update status bar / clear reload. - entity reload_timer = spawn(); - reload_timer.owner = self; - reload_timer.classname = "timer"; - reload_timer.think = FOT_ReloadTimer; - - // TODO: Remove this hack. - if (ws.weapon == WEAP_SNIPER_RIFLE) { - self.reload_tick = 1; - self.reload_sniper_ticks = 0; - } - - // It turns out, even on forced reloads we should use the client_time() not - // the server time as the action that forced the reload (firing the last - // shot), was client relative. - reload_timer.heat = client_time() + reload_duration; - reload_timer.nextthink = client_time() + self.reload_tick; - + // TODO: Make ammo in clip independent from ammo_remaining (so you can't + // have shots in clip that are discarded and other weirdness.) + (*ws->clip_fired) -= reload_count; + self.last_still_loading = reload_count; + self.reload_finished = self.client_time + reload_duration; } float FO_CheckForReload() { @@ -467,6 +464,8 @@ float FO_CheckForReload() { void FO_InstantReloadAllWeapons(entity player) { player.tfstate &= ~TFSTATE_RELOADING; + player.reload_finished = 0; + player.last_still_loading = 0; for (int i = 0; i < TF_NUM_SLOTS; i++) player.clip_fired[i] = 0; } diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 259389e4..ca3537ec 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -160,13 +160,13 @@ void () TeamFortress_Discard_DropAmmo = { void () TeamFortress_SaveMe = { local entity te, tl; - if (self.last_saveme_sound < time) { + if (self.client_time > self.next_saveme_sound) { if (random() < 0.8) FO_Sound(self, CHAN_WEAPON, "speech/saveme1.wav", 1, ATTN_NORM); else FO_Sound(self, CHAN_WEAPON, "speech/saveme2.wav", 1, ATTN_NORM); - self.last_saveme_sound = time + 4; + self.next_saveme_sound = self.client_time + 4; } te = find(world, classname, "player"); while (te) { @@ -258,7 +258,7 @@ void (entity pe_player) FO_Spectator_Identify = { } // refresh status bar - pe_player.ident_time = time + 0.5; + pe_player.ident_time = self.client_time + 0.5; if(pe_player.ident_string != s_id_string) { pe_player.ident_string = s_id_string; //if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { @@ -452,7 +452,7 @@ void (entity pe_player, float f_type) CF_Identify = { s_id_string = strcat(s_id_string, s_class); } - pe_player.ident_time = time + 0.5; + pe_player.ident_time = self.client_time + 0.5; // don't update memory when the id string is the same if (pe_player.ident_string == s_id_string) { diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index d1e82c0c..eabe93db 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,7 +1,7 @@ void AL_ProjectProjectile (entity projectile) { - float time_offset = (time - client_time(CT_SLOW_PROJECTILE)) / 2; + float time_offset = self.client_time - remote_client_time(CT_SLOW_PROJECTILE); - if (time_offset <= 0.013) // ping 13ms or lower? Don't do anything + if (time_offset <= 13 * MSEC) // ping 13ms or lower? Don't do anything return; vector projected_origin = projectile.origin + (projectile.velocity * time_offset); @@ -332,8 +332,9 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { farthest_rewind_point = max(farthest_rewind_point, time - rewind_max_offset); - // Det was pushed at client_time(), let's see if we can get there. - float rewind_to = max(farthest_rewind_point, client_time()); + // Det was pushed at remote_client_time(), let's see if we can get there. + float rewind_to = max(farthest_rewind_point, + client_to_global_time(remote_client_time())); // Ignore for LAN pings. if (time - rewind_to < 0.013) @@ -349,39 +350,3 @@ void UnrewindPlayer(entity p) { fop.RestoreNow(); } -.float client_time_internal; - -float client_time(float ct_type = CT_NOEXTERNALEFFECT) { - if (ct_type == CT_NOEXTERNALEFFECT) - return self.client_time_internal; - - float offset = time - self.client_time_internal; - float max_offset = antilag_settings.max_client_time_offset; - switch (ct_type) { - case CT_SLOW_PROJECTILE: - max_offset = antilag_settings.max_projectile_slow_offset; - break; - } - - return max(self.client_time_internal, time - max_offset); -} - -void AL_UpdateClientTime(entity player) { - float offset; - - // Naively, we might want to offset by rtt/2, because that's how old the - // client's input is. However, the client's input is also relative to a - // world view that is itself rtt/2 behind. [Client is a full rtt behind, - // and it interpolates ahead to rtt/2 behind.] - // This means that if we want, say, "run to a position and perform an action" - // to have equivalent time, we need to correct by a full rtt. - offset = infokeyf(player, INFOKEY_P_PING) / 1000; - - offset = min(offset, antilag_settings.max_client_time_offset); - - // Monotonically increasing and not dragging beyond 75% of time as/if RTT - // changes. - player.client_time_internal = - max(time - offset, player.client_time_internal + (1/77.0 * 0.75)); -} - diff --git a/ssqc/client.qc b/ssqc/client.qc index bf668a0a..47d0f2dd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -450,9 +450,6 @@ void () DecodeLevelParms = { // use old tf style dropflag (map decides on/off) [off] old_dropflag = CF_GetSetting("odf", "old_dropflag", "off"); - // show ticking clip ammo in sbar when reloading [on] - reload_cliptick = CF_GetSetting("rc", "reload_cliptick", "on"); - // use old tf sniper range (shorter) [off] old_sniperrange = CF_GetSetting("os", "old_sniperrange", "off"); @@ -601,19 +598,18 @@ void () DecodeLevelParms = { airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); - // client_time max delta + // remote_client_time max delta antilag_settings.rewind_detpipe = CF_GetSetting("alrd", "al_rewind_detpipe", "on"); - // client_time max delta - antilag_settings.max_client_time_offset = - CF_GetSetting("almcto", "al_max_client_time_offset", "200"); + // maximum ping we'll have effect at + antilag_settings.max_ping = CF_GetSetting("almp", "al_max_ping", "200"); // project projectile weapons by player ping project_weapons = CF_GetSetting("pw", "project_weapons", "off"); // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); - antilag_settings.max_projectile_slow_offset = project_weapons_max_latency; + antilag_settings.max_projectile_slow_ping = project_weapons_max_latency; // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); @@ -838,7 +834,6 @@ void () DecodeLevelParms = { remember_weapon = TRUE; discammo_pickup = FALSE; old_dropflag = FALSE; - reload_cliptick = TRUE; scoutdash = TRUE; sniperreload = TRUE; old_sniperrange = FALSE; @@ -917,7 +912,6 @@ void () DecodeLevelParms = { remember_weapon = FALSE; discammo_pickup = TRUE; old_dropflag = TRUE; - reload_cliptick = FALSE; scoutdash = FALSE; sniperreload = FALSE; old_sniperrange = TRUE; @@ -1962,7 +1956,7 @@ void (entity p) SetVoteParams = { stuffcmd(p, strcat("color ", ftos(rint(random() * 12)), " ", ftos(rint(random() * 12)), "\n")); p.takedamage = DAMAGE_AIM; //DAMAGE_YES; - p.attack_finished = time + 0.3; + p.attack_finished = self.client_time + 0.3; p.th_pain = player_pain; p.th_die = PlayerDie; p.height = 0; @@ -2068,7 +2062,7 @@ void () PutClientInServer = { self.invincible_finished = 0; self.effects = 0; self.invincible_time = 0; - self.spawn_time = time; + self.spawn_time = self.client_time; self.vote_close = 0; self.has_throwngren = FALSE; self.saveme_time = 0; @@ -2173,7 +2167,7 @@ void () PutClientInServer = { stuffcmd(self, "v_cshift; wait; bf\n"); SetTeamName(self); - self.attack_finished = client_time() + 0.3; + self.attack_finished = self.client_time + 0.3; self.th_pain = player_pain; self.th_die = PlayerDie; self.height = 0; @@ -2658,11 +2652,8 @@ void () CheckWaterJump = { } }; -void AL_UpdateClientTime(entity player); - void () PlayerPreThink = { - // We'll use this time for calculating ping adjusted expiration / projection / etc. - AL_UpdateClientTime(self); + FO_UpdateClientTime(); if (self.impulse) { if (self.impulse == TF_VOTENEXT) { @@ -2756,7 +2747,7 @@ void () PlayerPreThink = { // Catch all. FO_WeapState ws; FO_FillCurrentWeapState(&ws); - if ((client_time() > self.attack_finished) && + if ((self.client_time > self.attack_finished) && (ws.weapon > WEAP_AXE) && ((ws->wi)->ammo_type != AMMO_NONE)) { if (*ws->ammo_remaining == 0) W_ChangeToBestWeapon(); @@ -2927,6 +2918,7 @@ void () CheckPowerups = { }; void () PlayerPostThink = { + FO_CheckClientThink(); UpdateScoreboardInfo(self); FOPlayer fop = (FOPlayer)self; fop.RewindUpdate(); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 9b3beb0c..a5a9fe27 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -519,7 +519,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/disp.mdl"; newmis.netname = "dispenser"; - btime = client_time() + 2; + btime = time + 2; self.dispenser_ticks = 0; } else if (objtobuild == 2) { if (self.has_sentry) { @@ -531,7 +531,7 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '16 16 48'; newmis.mdl = "progs/turrbase.mdl"; newmis.netname = "sentrygun"; - btime = client_time() + 5; + btime = time + 5; self.sentry_ticks = 0; } if (CheckArea(newmis, self) == 0) { diff --git a/ssqc/progs.src b/ssqc/progs.src index b8d67bdf..a838a65b 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -14,6 +14,7 @@ defs.qc ../share/common_helpers.qc qw.qc debug.qc +time.qc ../share/fo_weapons.qc events.qc roles.qc diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 6457e80b..d61093c1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -9,17 +9,25 @@ enum { }; struct antilag_settings_t { - float max_client_time_offset; - float max_projectile_slow_offset; + float max_ping; + float max_projectile_slow_ping; float rewind_detpipe; } antilag_settings; -// A monotonically increasing, latency corrected notion of client-time. -// Monotonicity guarantees that for some offset `o`: -// at t1: client_time() + o < at t2: client_time() + o FOR t2 > t1 +.float client_time; // A stable/predictable client clock +.float client_ping; // ping used for prediction [capped] +.float last_remote_client_time; // For monoticity + +.void() client_think; // client-time relative think +.float client_thinkindex; +.float client_nextthink; + +// A monotonically non-decreasing, latency corrected notion of remote +// client-time. Monotonicity guarantees that for some offset `o`: +// at t1: remote_client_time() + o < at t2: lag_time() + o FOR t2 > t1 // E.g. That you never have to worry about the correction reordering events // that `time + o` would not. -float client_time(float ct_type = CT_NOEXTERNALEFFECT); +float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT); //=========================================================================== // TEAMFORTRESS Defs @@ -217,16 +225,16 @@ float coop; .float noammo; // used for no ammo error messages // variables used for reloading -.float reload_shotgun; // Only use for map compatibility. +.float reload_finished; // when the reload will finish + +// Only use below for map ent compatibility. +.float reload_shotgun; .float reload_super_shotgun; .float reload_sniper_rifle; .float reload_grenade_launcher; .float reload_rocket_launcher; .float reload_assault_cannon; -.float reload_tick; // how often the status bar should be refreshed during reload -.float reload_time; // when the reload will finish -.float reload_clipsize; // how much ammo is currently in the reloading clip -.float reload_sniper_ticks; // used to indicate when sniper rifle (with only 1 clip) will be reloaded +// Only use above for map ent compatibility. // Assault Cannon .float heat; @@ -240,7 +248,7 @@ float coop; .float immune_to_check; // Make sure people don't do too many saveme sounds -.float last_saveme_sound; +.float next_saveme_sound; .float no_active_nail_grens; @@ -546,7 +554,6 @@ float id_extended; float remember_weapon; float discammo_pickup; float old_dropflag; -float reload_cliptick; float old_sniperrange; //float detpipe_limit; float detpipe_limit_world; @@ -791,7 +798,7 @@ string settings_to_track_list[4] = { "sv_antilag", "project_weapons", "al_rewind_detpipe", - "al_max_client_time_offset", + "al_max_remote_client_time_offset", }; typedef struct setting_t { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 9bb3b179..a23d4165 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -669,7 +669,7 @@ void () CF_Spy_Invisible = { e_timer.classname = "spytimer"; e_timer.owner = self; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = client_time() + 1; + e_timer.nextthink = time + 1; } Status_Refresh(self); @@ -990,7 +990,7 @@ void (entity pe_player, float pf_class, float is_user) CF_Spy_ChangeSkin = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = (is_user ? client_time() : time) + 1; + e_timer.nextthink = (is_user ? time : time) + 1; e_timer.skin = pf_class; Status_Refresh(pe_player); @@ -1044,7 +1044,7 @@ void (entity pe_player, float pf_team_no, float is_user) CF_Spy_ChangeColor = { e_timer.classname = "spytimer"; e_timer.owner = pe_player; e_timer.think = CF_Spy_UndercoverThink; - e_timer.nextthink = (is_user ? client_time() : time) + 1; + e_timer.nextthink = (is_user ? time : time) + 1; e_timer.team = pf_team_no; Status_Refresh(pe_player); diff --git a/ssqc/status.qc b/ssqc/status.qc index 156ba7ee..5c186ddf 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -740,33 +740,6 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { return st; } -string GetSBClipString(entity pl, float csqcactive) -{ - string msg = ""; - if (pl.tfstate & TFSTATE_RELOADING) - { - FO_WeapInfo* wi = FO_GetWeapInfo(FO_PlayerCurrentWeapon(pl)); - - if ((sniperreloadpercent) && (reload_cliptick) && (pl.playerclass == PC_SNIPER)) { - msg = csqcactive ? strcat(ftos(25 * pl.reload_sniper_ticks), "%") : strcat(strpadl(ftos(25 * pl.reload_sniper_ticks), 3), "% "); - } else { - if (reload_cliptick) - msg = csqcactive ? ftos(pl.reload_clipsize) : strpadl(ftos(pl.reload_clipsize), 2); - else - msg = csqcactive ? "0" : " 0"; - - msg = strcat(msg, "/"); - msg = strcat(msg, (csqcactive ? ftos(wi->clip_size) : strpadr(ftos(wi->clip_size), 3))); - } - } - else - { - msg = ClipSizeToString(pl, csqcactive); - } - - return msg; -} - string GetSBClassInfo(entity pl, float csqcactive) { string st1 = ""; @@ -831,7 +804,7 @@ void UpdateClientIDString(entity pl) { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_ID); // identify - if (pl.ident_string && time < pl.ident_time) { + if (pl.ident_string && self.client_time < pl.ident_time) { WriteString(MSG_MULTICAST, pl.ident_string); } else { WriteString(MSG_MULTICAST, ""); @@ -848,7 +821,7 @@ void UpdateClientStatusBar(entity pl) string msg = ""; msg_entity = pl; - string clipMsg = GetSBClipString(pl, TRUE); + string clipMsg = ClipSizeToString(pl, TRUE); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SBAR); @@ -1264,7 +1237,7 @@ void (entity pl) RefreshStatusBar = { st2 = ""; // status line 3 column 2 - clip size - st2 = strcat(Q"\sClip\s: ", GetSBClipString(pl, csqcactive)); + st2 = strcat(Q"\sClip\s: ", ClipSizeToString(pl, csqcactive)); // status line 3 column 3 - grenade 1 count st3 = strcat(Q"\sGren1\s: ", ftos(pl.no_grenades_1)); @@ -1280,7 +1253,7 @@ void (entity pl) RefreshStatusBar = { s3 = strzone(s3); // identify - if (pl.ident_string != string_null && time < pl.ident_time) { + if (pl.ident_string != string_null && self.client_time < pl.ident_time) { ident = strcat(pl.ident_string, "\n\n"); } else { ident = "\n\n\n\n"; @@ -1332,15 +1305,13 @@ string(entity pl, float csqcactive) ClipSizeToString = if (!wi->needs_reload) return ""; - if (wi->clip_size - *ws->clip_fired > *ws->ammo_remaining) - *ws->clip_fired = wi->clip_size - *ws->ammo_remaining; - float rem = min(wi->clip_size - *ws->clip_fired, 999); + float clip_rem = min(wi->clip_size - *ws->clip_fired - pl.last_still_loading, 999); string st = ""; if (csqcactive) - st = strcat(ftos(floor(rem)), "/", ftos(wi->clip_size)); + st = strcat(ftos(floor(clip_rem)), "/", ftos(wi->clip_size)); else - st = strcat(strpadl(ftos(rem), 2), "/", strpadr(ftos(wi->clip_size), 3)); + st = strcat(strpadl(ftos(clip_rem), 2), "/", strpadr(ftos(wi->clip_size), 3)); return st; }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 4658c89d..500243cc 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -25,7 +25,7 @@ void () AutoId = { return; } - if (time > self.ident_time || !self.ident_time) { + if (self.client_time > self.ident_time || !self.ident_time) { // remove ident string from memory if (self.ident_string != string_null) { @@ -663,7 +663,6 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Old dropflag behaviour", old_dropflag, "", 1); CF_PrintSetting("Remember weapon", remember_weapon, "", 1); CF_PrintSetting("Pick up discarded ammo", discammo_pickup, "", 1); - CF_PrintSetting("Reload clip tick", reload_cliptick, "", 1); CF_PrintSetting("ID extras", id_extended, "", 1); CF_PrintSetting("Display class tips", classtips, "", 1); CF_PrintSetting("Old grenades", old_grens, "", 1); @@ -1097,11 +1096,12 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { else if (inp == 2) tGrenade.impulse = TF_GRENADE_2; - tGrenade.nextthink = client_time() + 0.8; + float time_base = client_to_global_time(remote_client_time()); + tGrenade.nextthink = time_base + 0.8; if (gtype == GR_TYPE_CALTROP) - tGrenade.heat = client_time() + 0.5 + 0.5; + tGrenade.heat = time_base + 0.5 + 0.5; else { - tGrenade.heat = client_time() + 3 + 0.8; + tGrenade.heat = time_base + 3 + 0.8; RemoveGrenadeTimers(); @@ -1109,7 +1109,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { local float notimers = stof(infokey(self, "nt")); if (grentimers && notimers != 1) { timer = spawn(); - timer.nextthink = client_time() + 0.8; + timer.nextthink = time_base + 0.8; timer.think = GrenadeTimer; timer.heat = 4; timer.owner = self; diff --git a/ssqc/time.qc b/ssqc/time.qc new file mode 100644 index 00000000..f827530b --- /dev/null +++ b/ssqc/time.qc @@ -0,0 +1,50 @@ +float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT) { + float offset = self.client_ping; // Already bounded by max_ping + + switch (ct_type) { + case CT_SLOW_PROJECTILE: + offset = min(offset, antilag_settings.max_projectile_slow_ping); + break; + } + + float target = self.client_time - offset; + if (self.last_remote_client_time > target) + return self.last_remote_client_time; + + self.last_remote_client_time = target; + return target; +} + +// Note: Delta has jitter of up to ~frame +inline float client_to_global_time(float ctime) { + return time + (ctime - self.client_time); +} + + +static void think_nop() {} +void FO_SetClientThink(void() func, float offset, float override = TRUE) { + self.think = think_nop; + self.nextthink = 0; + + self.client_think = func; + self.client_nextthink = self.client_time + offset; +} + +void FO_CheckClientThink() { + if (self.client_nextthink && self.client_time >= self.client_nextthink) { + float held_client_time = self.client_time; + + self.client_time = self.client_nextthink; + self.client_nextthink = 0; + self.client_think(); + + self.client_time = held_client_time; + } +} + +void FO_UpdateClientTime() { + self.client_time += frametime; + + float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; + self.client_ping = min(antilag_settings.max_ping, ping); +} diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 9971b8f6..dae34f8c 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -192,7 +192,7 @@ void (float att_delay) Attack_Finished = { if (self.tfstate & TFSTATE_TRANQUILISED) att_delay *= 2; - self.attack_finished = client_time() + att_delay; + self.attack_finished = self.client_time + att_delay; }; float () W_FireAxe = { @@ -1782,7 +1782,7 @@ void () W_Attack = { }; float WeaponReady() { - if (client_time() >= self.attack_finished && + if (self.client_time >= self.attack_finished && !(self.tfstate & TFSTATE_RELOADING)) return TRUE; @@ -2579,6 +2579,9 @@ void () W_WeaponFrame = { return; } + if (FO_ReloadFrame()) + return; + if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && From 2a030e9faad6ca2c0e9fda4cba40e0f7a0a7ae07 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 6 Oct 2022 01:45:09 -0700 Subject: [PATCH 1773/2474] Move animations to client_time Index animations off client_time so that they can be more tightly synchronized, also repackage them so that we can share animation definition between CSQC and SSQC. --- ssqc/client.qc | 27 +-- ssqc/hwguy.qc | 11 ++ ssqc/player.qc | 457 ++++++++++++++---------------------------------- ssqc/weapons.qc | 15 +- 4 files changed, 160 insertions(+), 350 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 47d0f2dd..3aeaf5a4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -71,6 +71,8 @@ entity (entity e)TeamFortress_GetPracticeSpawn; void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); +void StopAssCan(); + void (float n) CSEv_SetPlayerImpulse_f = { bprint(PRINT_HIGH, self.netname, "\n"); bprint(PRINT_HIGH, "setting impulse ", ftos(n), "\n"); @@ -2467,6 +2469,8 @@ void () PlayerDeathThink = { } }; +void player_asscan_down1(); + void () PlayerJump = { local entity te; local float stumble; @@ -2491,16 +2495,10 @@ void () PlayerJump = { else FO_Sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } - if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.heat = 0; - self.count = 1; - player_assaultcannondown(); - } + + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) + StopAssCan(); + return; } @@ -2521,14 +2519,7 @@ void () PlayerJump = { sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); self.antispam_cannon_air = time + 3; } - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); - self.weaponframe = 0; - self.count = 1; - self.heat = 0; - player_assaultcannondown(); + StopAssCan(); } else { self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index dd7ec290..a8b42038 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -142,6 +142,17 @@ void FireAssCan (float shotcount, vector dir, vector spread) } } +void StopAssCan() { + if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { + self.tfstate = self.tfstate | TFSTATE_AIMING; + TeamFortress_SetSpeed(self); + self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); + TeamFortress_SetSpeed(self); + //self.weaponframe = 0; + player_asscan_down1(); + } +} + void FO_LockToggle () { if (self.tfstate & TFSTATE_LOCK) { self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); diff --git a/ssqc/player.qc b/ssqc/player.qc index 12a962e2..bf06a2fe 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -83,332 +83,170 @@ void () player_touch = { } }; -void () player_stand1 =[17, player_stand1] { +void player_stand1() { + FO_SetClientThink(player_stand1, 0.1); + + self.frame = 17; self.weaponframe = 0; + if (self.velocity_x || self.velocity_y) { self.walkframe = 0; player_run(); return; } + if (IsSlotMelee(self.current_slot)) { - if (self.walkframe >= 12) { + if (self.walkframe >= 12) self.walkframe = 0; - } self.frame = 17 + self.walkframe; } else { - if (self.walkframe >= 5) { + if (self.walkframe >= 5) self.walkframe = 0; - } self.frame = 12 + self.walkframe; } - self.walkframe = self.walkframe + 1; + self.walkframe++; }; -void () player_run =[6, player_run] { +void player_run() { + FO_SetClientThink(player_run, 0.1); + + self.frame = 6; self.weaponframe = 0; + if (!self.velocity_x && !self.velocity_y) { self.walkframe = 0; player_stand1(); return; } - if (FO_CurrentWeapon() <= WEAP_AXE) { - if (self.walkframe >= 6) { - self.walkframe = 0; - } - self.frame = 0 + self.walkframe; - } else { - if (self.walkframe >= 6) { - self.walkframe = 0; - } - self.frame = self.frame + self.walkframe; - } - self.walkframe = self.walkframe + 1; -}; - -void () player_shot1 =[113, player_shot2] { - self.weaponframe = 1; - muzzleflash(); -}; - -void () player_shot2 =[114, player_shot3] { - self.weaponframe = 2; -}; - -void () player_shot3 =[115, player_shot4] { - self.weaponframe = 3; -}; - -void () player_shot4 =[116, player_shot5] { - self.weaponframe = 4; -}; - -void () player_shot5 =[117, player_shot6] { - self.weaponframe = 5; -}; - -void () player_shot6 =[118, player_run] { - self.weaponframe = 6; -}; - -void () player_autorifle1 =[113, player_autorifle2] { - self.weaponframe = 1; - muzzleflash(); -}; - -void () player_autorifle2 =[114, player_autorifle3] { - self.weaponframe = 2; -}; - -void () player_autorifle3 =[118, player_run] { - self.weaponframe = 6; -}; - -void () player_axe1 =[119, player_axe2] { - self.weaponframe = 1; - - if (superaxe) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axe2 =[120, player_axe3] { - self.weaponframe = 2; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axe3 =[121, player_axe4] { - self.weaponframe = 3; - - if (!superaxe) - W_FireAxe(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axe4 =[122, player_run] { - self.weaponframe = 4; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb1 =[124, player_axeb2] { - self.weaponframe = 5; - - if (superaxe) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb2 =[125, player_axeb3] { - self.weaponframe = 6; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb3 =[126, player_axeb4] { - self.weaponframe = 7; - - if (!superaxe) - W_FireAxe(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_axeb4 =[127, player_run] { - self.weaponframe = 8; - - if (superaxe && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireAxe(); -}; - -void () player_spanner1 =[119, player_spanner2] { - self.weaponframe = 1; - - if (superspanner) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_spanner2 =[120, player_spanner3] { - self.weaponframe = 2; - - if (superspanner && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_spanner3 =[121, player_spanner4] { - self.weaponframe = 3; - - if (!superspanner) - W_FireSpanner(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_spanner4 =[122, player_run] { - self.weaponframe = 4; - - if (superspanner && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireSpanner(); -}; - -void () player_knife1 =[119, player_knife2] { - self.weaponframe = 1; - - if (superknife) - self.hit_in_current_animation = W_FireKnife(); -}; - -void () player_knife2 =[120, player_knife3] { - self.weaponframe = 2; - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); + // Note: Reverses animation when walking backwards + self.walkframe = (self.walkframe + (self.movement_x < 0 ? -1 : 1) + 6) % 6; + self.frame = (IsSlotMelee(self.current_slot) ? 0 : 6) + self.walkframe; }; -void () player_knife3 =[121, player_knife4] { - self.weaponframe = 3; +static void think_nop() {} - if (!superknife || (superknife_multihit && !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); +struct anim_t { + int num_frames, num_wf; + int frames[9]; + int weaponframes[9]; + int muzzle_flash; // muzzle flash on weaponframe index 0 + int loop; }; -void () player_knife4 =[122, player_run] { - self.weaponframe = 4; +void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { + int tidx = self.client_thinkindex++; - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; + int wfi = tidx % anim->num_wf; + self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; + if (wfi == 0 && anim->muzzle_flash) + muzzleflash(); -void () player_knifeb1 =[125, player_knifeb2] { - self.weaponframe = 5; + int fi = tidx % anim->num_frames; + self.frame = anim->frames[fi] ?: anim->frames[0] + fi; - if (superknife) - self.hit_in_current_animation = W_FireKnife(); -}; + if (wfi == anim->num_wf - 1 && !anim->loop) + FO_SetClientThink(player_run, 0.1); + else + FO_SetClientThink(parent_thunk, 0.1); -void () player_knifeb2 =[126, player_knifeb3] { - self.weaponframe = 6; + if (extra != think_nop) + extra(); +} - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; +anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; +void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } +void player_rocket1() { self.client_thinkindex = 0; player_rocketN(); } -void () player_knifeb3 =[127, player_knifeb4] { - self.weaponframe = 7; +anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; +void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } +void player_shot1() { self.client_thinkindex = 0; player_shotN(); } - if (!superknife || (superknife_multihit && !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; -void () player_knifeb4 =[128, player_run] { - self.weaponframe = 8; +anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; +void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } +void player_autorifle1() { self.client_thinkindex = 0; player_autorifleN(); } - if (superknife && (superknife_multihit || !self.hit_in_current_animation)) - self.hit_in_current_animation = W_FireKnife(); -}; -void () player_medikit1 =[119, player_medikit2] { - self.weaponframe = 1; +static void axe_extra() { + float weapon = FO_CurrentWeapon(); + float* flag; + int() w_attack; - if (supermedikit) - self.hit_in_current_animation = W_FireMedikit(); -}; + // We'd use default below but compiler can't recognize that init is + // guaranteed then. + flag = &superaxe; + w_attack = W_FireAxe; -void () player_medikit2 =[120, player_medikit3] { - self.weaponframe = 2; + switch (weapon) { + case WEAP_MEDIKIT: + flag = &supermedikit; + w_attack = W_FireMedikit; + break; + case WEAP_SPANNER: + flag = &superspanner; + w_attack = W_FireSpanner; + break; + case WEAP_KNIFE: + flag = &superknife; + w_attack = W_FireKnife; + break; + } - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; + if ((*flag && !self.hit_in_current_animation) || + (!*flag && self.weaponframe == 3)) + self.hit_in_current_animation = w_attack(); -void () player_medikit3 =[121, player_medikit4] { - self.weaponframe = 3; + if (weapon == WEAP_KNIFE && superknife && superknife_multihit) + self.hit_in_current_animation = FALSE; +} - if (!supermedikit) - W_FireMedikit(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; +anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; +void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } +void player_axe1() { self.client_thinkindex = 0; player_axeN(); } -void () player_medikit4 =[122, player_run] { - self.weaponframe = 4; +anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; +void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } +void player_axeb1() { self.client_thinkindex = 0; player_axebN(); } - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; +void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } +void player_spanner1() { self.client_thinkindex = 0; player_spannerN(); } -void () player_medikitb1 =[125, player_medikitb2] { - self.weaponframe = 5; +void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } +void player_knife1() { self.client_thinkindex = 0; player_knifeN(); } - if (supermedikit) - self.hit_in_current_animation = W_FireMedikit(); -}; - -void () player_medikitb2 =[126, player_medikitb3] { - self.weaponframe = 6; +// TODO: zel had this on 125, but I think it should be on 124. Double check. +void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } +void player_knifeb1() { self.client_thinkindex = 0; player_knifebN(); } - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; +void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } +void player_medikit1() { self.client_thinkindex = 0; player_medikitN(); } -void () player_medikitb3 =[127, player_medikitb4] { - self.weaponframe = 7; +// TODO: zel had this on 125, but I think it should be on 124. Double check. +void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } +void player_medikitb1() { self.client_thinkindex = 0; player_medikitbN(); } - if (!supermedikit) - W_FireMedikit(); - else if (!self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; -void () player_medikitb4 =[128, player_run] { - self.weaponframe = 8; - - if (supermedikit && !self.hit_in_current_animation) - self.hit_in_current_animation = W_FireMedikit(); -}; - -void () player_nail1 =[103, player_nail2] { - muzzleflash(); +void nail_extra() { if (!self.button0 || intermission_running) { player_run(); return; } - self.weaponframe = self.weaponframe + 1; - if (self.weaponframe == 9) { - self.weaponframe = 1; - } - SuperDamageSound(); - if (self.nailpos == 0) { - W_FireSpikes(4); - self.nailpos = 1; - } else { - W_FireSpikes(-4); - self.nailpos = 0; - } -}; -void () player_nail2 =[104, player_nail1] { - if (!self.button0 || intermission_running) { - player_run(); - return; - } - self.weaponframe = self.weaponframe + 1; - if (self.weaponframe == 9) { - self.weaponframe = 1; - } - if (!old_ng_rof) { + float idx = (self.client_thinkindex - 1) % 2; + if (idx == 0 || !old_ng_rof) { SuperDamageSound(); - if (self.nailpos == 0) { - W_FireSpikes(4); - self.nailpos = 1; - } else { - W_FireSpikes(-4); - self.nailpos = 0; - } - } -}; + W_FireSpikes(self.nailpos ? 4 : -4); + self.nailpos = 1 - self.nailpos; + } +} + +anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; +void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } +void player_nail1() { self.client_thinkindex = 0; player_nailN(); } + +void player_asscan_fire(); +void player_asscan_down1(); static float CheckNeedAssaultCannonDown() { FO_WeapState ws; @@ -418,47 +256,42 @@ static float CheckNeedAssaultCannonDown() { ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { self.tfstate |= TFSTATE_AIMING; TeamFortress_SetSpeed(self); - self.count = 0; - player_assaultcannondown(); + player_asscan_down1(); return TRUE; } return FALSE; } -void () player_assaultcannon; -void () player_assaultcannonup =[103, player_assaultcannonup] { +void asscan_up_extra() { if (CheckNeedAssaultCannonDown()) return; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); self.fire_held_down = 1; - if (self.count == 0) + if (self.client_thinkindex == 1) // Already incremented FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - SuperDamageSound(); - if ((self.count != 2) && (self.count != 4)) - self.weaponframe = (self.weaponframe + 1) % 4; - if (self.count++ >= 5) // 600ms spin up - player_assaultcannon(); + if (self.client_thinkindex == 6) // 600ms spin up + player_asscan_fire(); else Attack_Finished(wi->attack_time); -}; +} -void () player_assaultcannon =[103, player_assaultcannon] { +void asscan_fire_extra() { if (CheckNeedAssaultCannonDown()) return; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) && !(self.tfstate & TFSTATE_LOCK)) { - if (self.count % 2 == 0) { - muzzleflash(); + + if (self.client_thinkindex % 2 == 0) FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - } SuperDamageSound(); - self.weaponframe = self.weaponframe == 2 ? 4 : 2; self.tfstate |= TFSTATE_AIMING; if (!cannon_move) @@ -472,16 +305,16 @@ void () player_assaultcannon =[103, player_assaultcannon] { FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); self.weaponframe = self.weaponframe == 2 ? 0 : 2; } - self.count++; Attack_Finished(wi->attack_time); -}; +} -void () player_assaultcannondown =[103, player_assaultcannondown] { - if (self.count == 0) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); +void asscan_down_extra() { FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (self.count >= 14) { // 1.5s down + if (self.client_thinkindex == 1) + FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); + + if (self.client_thinkindex >= 15) { // 1.5s down self.fire_held_down = 0; self.tfstate &= ~TFSTATE_AIMING; if (!cannon_move) @@ -493,14 +326,21 @@ void () player_assaultcannondown =[103, player_assaultcannondown] { W_PrintWeaponMessage(); W_ChangeToBestWeapon(); } - } else if (self.count % 2 == 0) { - self.weaponframe = (self.weaponframe + 1) % 4; } - - self.count++; Attack_Finished(wi->attack_time); }; +anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; +anim_t anim_asscan_fire = { 1, 4, {103}, {2, 4}, FALSE, TRUE}; +anim_t anim_asscan_down = { 1, 8, {103}, {1, 1, 2, 2, 3, 3, 4, 4}, FALSE, TRUE}; + +void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } +void player_asscan_up1() { self.client_thinkindex = 0; player_asscan_upN(); } + +void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } +void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } +void player_asscan_down1() { self.client_thinkindex = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } + void () player_light1 =[105, player_light2] { muzzleflash(); if (!self.button0 || intermission_running) { @@ -530,31 +370,6 @@ void () player_light2 =[106, player_light1] { Attack_Finished(0.2); }; -void () player_rocket1 =[107, player_rocket2] { - self.weaponframe = 1; - muzzleflash(); -}; - -void () player_rocket2 =[108, player_rocket3] { - self.weaponframe = 2; -}; - -void () player_rocket3 =[109, player_rocket4] { - self.weaponframe = 3; -}; - -void () player_rocket4 =[110, player_rocket5] { - self.weaponframe = 4; -}; - -void () player_rocket5 =[111, player_rocket6] { - self.weaponframe = 5; -}; - -void () player_rocket6 =[112, player_run] { - self.weaponframe = 6; -}; - void (float num_bubbles) DeathBubbles; void () PainSound = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index dae34f8c..05639f60 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -195,7 +195,7 @@ void (float att_delay) Attack_Finished = { self.attack_finished = self.client_time + att_delay; }; -float () W_FireAxe = { +int () W_FireAxe = { local vector source; local vector org; local vector def; @@ -394,7 +394,7 @@ int () W_FireSpanner = { } }; -float () W_FireMedikit = { +int () W_FireMedikit = { local vector source; local vector org; local float healam; @@ -1607,23 +1607,16 @@ void () W_ChangeToBestWeapon = { void () player_axe1; void () player_axeb1; - void () player_spanner1; -void () player_spanner2; -void () player_spanner3; -void () player_spanner4; - void () player_knife1; void () player_knifeb1; - void () player_shot1; void () player_nail1; void () player_light1; void () player_rocket1; void () player_autorifle1; -void () player_assaultcannonup; -void () player_assaultcannondown; +void () player_asscan_up1; void () player_medikit1; void () player_medikitb1; @@ -1729,7 +1722,7 @@ void () W_Attack = { self.immune_to_check = time + 5; self.tfstate = self.tfstate | TFSTATE_AIMING; TeamFortress_SetSpeed(self); - player_assaultcannonup(); + player_asscan_up1(); } } else if (ws.weapon == WEAP_FLAMETHROWER) { player_shot1(); From 169cfc84b02bc2bdf9d13ee69f8407d5eeec8d94 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Sep 2022 11:03:46 -0700 Subject: [PATCH 1774/2474] Add weapon prediction infrastructure Create a per-player entity for storing and communicating weapon-prediction state. Introduce a hybrid-driven client_think() that can be used to synchronize and initiate animation. Much of this infrastructure is inspired by the ktx/reki implementations. Annoying subtlety: We use (deprecated) visible dimension stuff for the flash code, if this isn't set, no one gets updates on the entity. --- csqc/csprogs.src | 1 + csqc/main.qc | 7 +- share/defs.h | 2 +- share/fo_weapon_predict.qc | 304 +++++++++++++++++++++++++++++++++++++ share/fo_weapons.qc | 7 + ssqc/client.qc | 7 + ssqc/progs.src | 2 + 7 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 share/fo_weapon_predict.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 81b6c037..437e56c6 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -13,6 +13,7 @@ csextradefs.qc ../share/common_helpers.qc ../share/common_vote.qc ../share/fo_weapons.qc +../share/fo_weapon_predict.qc sui_sys.qc vote.qc status.qc diff --git a/csqc/main.qc b/csqc/main.qc index 60b27f43..03d77eda 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,6 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // } FO_Weapons_Init(); + FO_WeaponPred_Init(FALSE); // Server packet enables. CsGrenTimer::Init(); registercommand("fo_hud_editor"); @@ -123,7 +124,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) setproperty(VF_DRAWENGINESBAR, 1); - addentities((intermission?0:MASK_VIEWMODEL)|MASK_ENGINE); // add entities with these rendermask field var's to our view + addentities((intermission?0:wp_model_mask)|MASK_ENGINE); renderscene(); @@ -401,6 +402,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { void(float isnew) CSQC_Ent_Update = { float etype = readbyte(); switch (etype) { + case ENT_WEAPONPRED: + EntUpdate_WeaponPred(isnew); + break; default: error("Unhandled CSQC entity\n"); return; @@ -408,7 +412,6 @@ void(float isnew) CSQC_Ent_Update = { }; void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and will no longer be tracked... - print("CSQC_Ent_Remove\n"); remove(self); }; diff --git a/share/defs.h b/share/defs.h index ad1d2145..92a38b23 100644 --- a/share/defs.h +++ b/share/defs.h @@ -298,7 +298,7 @@ /*======================================================*/ // Opaque token that encapsulates slots for correctness. -struct Slot { int id; }; +typedef struct { int id; } Slot; // Some of the toggleflags aren't used anymore, but the bits are still // there to provide compatability with old maps diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc new file mode 100644 index 00000000..a743434c --- /dev/null +++ b/share/fo_weapon_predict.qc @@ -0,0 +1,304 @@ +#define ENT_WEAPONPRED 100 + +enumflags { + FOWP_CTIME, + FOWP_IMPULSE, + FOWP_TFSTATE, + FOWP_CLIP, + FOWP_THINK, + FOWP_TFSTATE, + FOWP_WF, + FOWP_CLASS, +}; +#define FOWP_ALL 0xFF + +struct predict_tf_state { + int playerclass; + int impulse; + Slot current_slot, queue_slot; + + float tfstate; + + float client_time; + int weaponframe; + + float attack_finished; + float client_nextthink; + float client_thinkindex; +}; + +#ifdef SSQC +.float weapon_pred_enabled; +.predict_tf_state predict_state; +.entity predict_entity; + +.float client_nextthink; +.float client_thinkindex; +#else +predict_tf_state pstate_pred, pstate_server; + +struct pengine_t { + float is_effectframe; + float last_effectframe; +} pengine; + +#define MASK_PRED_VIEWMODEL 256 +// Must include MASK_PRED_VIEWMODEL or we lose updates. +// We only add/remove MASK_VIEWMODEL. +float wp_model_mask; + +void FO_WeaponPred_Init(float enabled) { + wp_model_mask = enabled ? MASK_PRED_VIEWMODEL : MASK_VIEWMODEL; +} +#endif + +#ifdef SSQC +#define OP1(_op, _f1) (player.predict_state.##_f1 _op player.##_f1) +#define OP2(_op, _j, _f1, _f2) OP1(_op, _f2) _j OP1(_op, _f1) +#define OP3(_op, _j, _f1, _f2, _f3) OP2(_op, _j, _f2, _f3) _j OP1(_op, _f1) +#define OP4(_op, _j, _f1, _f2, _f3, _f4) OP3(_op, _j, _f2, _f3, _f4) _j OP1(_op, _f1) +#define M1(_bit, _f1) if (OP1(!=, _f1)) { mask |= _bit; OP1(=, _f1); } +#define M2(_bit, _f1, _f2) if (OP2(!=, ||, _f1, _f2)) { mask |= _bit; OP2(=, ;, _f1, _f2); } +#define M3(_bit, _f1, _f2, _f3) if (OP3(!=, ||, _f1, _f2, _f3)) { mask |= _bit; OP3(=, ;, _f1, _f2, _f3); } +#define M4(_bit, _f1, _f2, _f3, _f4) if (OP4(!=, ||, _f1, _f2, _f3, _f4)) { mask |= _bit; OP4(=, ;, _f1, _f2, _f3, _f4); } + +void UpdateWeaponPred(entity player) { + float mask = FOWP_CTIME; + + player.predict_state.client_time = player.client_time; + + M1(FOWP_CLASS, playerclass); + M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); + M1(FOWP_TFSTATE, tfstate); + M3(FOWP_THINK, attack_finished, client_nextthink, client_thinkindex) + + player.predict_entity.SendFlags = mask; +} + +#undef OP1 +#undef OP2 +#undef OP3 +#undef OP4 +#undef M1 +#undef M2 +#undef M3 +#undef M4 +#endif + +#ifdef SSQC +#define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) +float WeaponPred_SendEntity(entity to_player, float sendflags) { + if (to_player != self.owner) + return FALSE; + + WriteByte(MSG_ENTITY, ENT_WEAPONPRED); + WriteByte(MSG_ENTITY, sendflags); +#else +float() ReadByte = #360; +float() ReadFloat = #367; +void InitPredEnt(entity e); + +#define COMM(_type, _field) pstate_server.##_field = Read##_type() +void EntUpdate_WeaponPred(float isnew) { + float sendflags = readbyte(); +#endif + if (sendflags & FOWP_CTIME) { + COMM(Float, client_time); + } + + if (sendflags & FOWP_CLASS) { + COMM(Byte, playerclass); + } + + if (sendflags & FOWP_IMPULSE) { + COMM(Byte, impulse); + COMM(Byte, current_slot.id); + COMM(Byte, queue_slot.id); + } + + if (sendflags & FOWP_TFSTATE) { + COMM(Float, tfstate); + } + + if (sendflags & FOWP_THINK) { + COMM(Float, client_nextthink); + COMM(Float, client_thinkindex); + } + + if (sendflags & FOWP_WF) { + COMM(Byte, weaponframe); + COMM(Float, attack_finished); + } +#ifdef SSQC + return TRUE; +#else + if (isnew) + InitPredEnt(self); +#endif +} + +#ifdef SSQC +float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); + +inline float WeaponPred_Active(entity player) { + return player.weapon_pred_enabled; +} + +void WeaponPred_Init(entity player) { + // Server side is once per connect. + if (!FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "on")) { + player.weapon_pred_enabled = FALSE; + return; + } + + player.weapon_pred_enabled = TRUE; + + entity pe = spawn(); + pe.owner = player; + pe.classname = "WeaponPred"; + pe.dimension_seen = DMN_FLASH | DMN_NOFLASH; + pe.pvsflags = PVSF_IGNOREPVS; + pe.SendEntity = WeaponPred_SendEntity; + setorigin(pe, [0, 0, 0]); + + player.predict_entity = pe; + sprint(self, PRINT_HIGH, "FortressOne: Weapon Prediction Active v0\n"); +} + +void WeaponPred_TearDown(entity player) { + if (!player.weapon_pred_enabled) + return; + + dremove(player.predict_entity); +} + +void WeaponPred_DoServerClientThink() { + while (self.client_think && self.client_time > self.client_nextthink) { + float held_client_time = self.client_time; + + self->client_time = self->client_nextthink; + self->client_nextthink = 0; + self->client_think(); + + self->client_time = held_client_time; + } +} +#endif + +#ifdef CSQC +void WeaponPred_ChangeWeapon(float input) { + Slot slot = FO_SlotByInput(input); + if (IsSlotNull(slot)) + return; // Unrecognized + + pstate_pred.current_slot = slot; + pstate_pred.weaponframe = 0; + + // UpdateViewModel will propagate. +} + +void WeaponPred_Impulse() { + if (!pstate_pred.impulse) + return; + + float clear = FALSE; + if (pstate_pred.impulse <= 7) { // Change weapon. + WeaponPred_ChangeWeapon(pstate_pred.impulse); + clear = TRUE; + } + + if (clear) + pstate_pred.impulse = 0; +} + +void WeaponPred_Attack() { + Slot slot = pstate_pred.current_slot; + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + + pstate_pred.client_thinkindex = 1; + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; +} + + +void WeaponPred_DoClientThink(void) { + +} + +void WeaponPred_UpdateViewModel() { + float pmodelindex, pframe; + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + pmodelindex = (wi->models)->modelindex; + pframe = pstate_pred.weaponframe; + + if (self.modelindex != pmodelindex) { + self.frame = pframe; + self.modelindex = pmodelindex; + self.lerpfrac = 0; + } else if (self.frame != pframe) { + self.frame2 = self.frame; + self.frame = pframe; + self.lerpfrac = 1; + } + + self.lerpfrac = max(0, self.lerpfrac - frametime * 10); +} + +float WeaponPred_ClientThink() { + pstate_pred = pstate_server; + + int pframe = servercommandframe + 1; + int eframe = clientcommandframe; + for(; pframe <= eframe; pframe++) { + int success = getinputstate(pframe); + if (!success || input_timelength <= 0) + break; + makevectors(input_angles); + + if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { + pengine.is_effectframe = TRUE; + pengine.last_effectframe = pframe; + } else { + pengine.is_effectframe = FALSE; + } + + pstate_pred.client_time += input_timelength; + if (input_impulse) + pstate_pred.impulse = input_impulse; + + if (pstate_pred.client_nextthink && + pstate_pred.client_time >= pstate_pred.client_nextthink) { + float held_client_time = pstate_pred.client_time; + + pstate_pred.client_time = pstate_pred.client_nextthink; + pstate_pred.client_nextthink = 0; + WeaponPred_DoClientThink(); + pstate_pred.client_time = held_client_time; + } + + if (pstate_pred.client_time >= pstate_pred.attack_finished) { + WeaponPred_Impulse(); + + if (input_buttons & BUTTON0) + WeaponPred_Attack(); + } + + } + + WeaponPred_UpdateViewModel(); + return PREDRAW_AUTOADD; +} + +void InitPredEnt(entity pe) { + pe.predraw = WeaponPred_ClientThink; + + self.drawmask = MASK_PRED_VIEWMODEL; + self.renderflags = RF_VIEWMODEL; + + FO_WeaponPred_Init(TRUE); + +} +#endif diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index fa0d3768..2d4adb38 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -165,6 +165,10 @@ string FO_GetWeapName(float weapon) { struct FO_WeapModels { int weapon; string model; + + // Automatically populated. + int modelindex; + }; // Indexed by WEAP_to_index() @@ -582,6 +586,9 @@ void FO_Weapons_Init() { FO_WeapModels* wm = &weapon_models[i]; ASSERTD_EQ(WEAP_to_index(wm->weapon), i); precache_model(wm->model); +#ifdef CSQC + wm->modelindex = getmodelindex(wm->model); +#endif wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; diff --git a/ssqc/client.qc b/ssqc/client.qc index 3aeaf5a4..50478d8d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -72,6 +72,8 @@ void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); void StopAssCan(); +void WeaponPred_Init(entity player); +void WeaponPred_TearDown(entity player); void (float n) CSEv_SetPlayerImpulse_f = { bprint(PRINT_HIGH, self.netname, "\n"); @@ -2918,6 +2920,8 @@ void () PlayerPostThink = { FO_FillCurrentWeapState(&ws); self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; + if (WeaponPred_Active(self)) + UpdateWeaponPred(self); if (self.view_ofs == '0 0 0') { return; @@ -3060,6 +3064,8 @@ void () ClientConnect = { } if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + WeaponPred_Init(self); + InitAllStatuses(self); UpdateClientMOTD(self); UpdateClientTeamScores(self); @@ -3198,6 +3204,7 @@ void () ClientDisconnect = { UnvoteForMap(self); } + WeaponPred_TearDown(self); }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { diff --git a/ssqc/progs.src b/ssqc/progs.src index a838a65b..6276ed43 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -15,7 +15,9 @@ defs.qc qw.qc debug.qc time.qc +../share/defs.h ../share/fo_weapons.qc +../share/fo_weapon_predict.qc events.qc roles.qc q3defs.qc From 857281d3aac56ffa7692943debff6b2ed70b7f60 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 9 Oct 2022 19:37:07 -0700 Subject: [PATCH 1775/2474] Add model animations for the majority of weapons Unsupported weapons automatically fall-back to use the engine representation. --- csqc/csprogs.src | 2 + csqc/weapon_predict.qc | 56 ++++++ share/fo_animate.qc | 345 +++++++++++++++++++++++++++++++++++++ share/fo_weapon_predict.qc | 67 +++++-- share/fo_weapons.qc | 51 +++--- ssqc/player.qc | 258 --------------------------- ssqc/progs.src | 1 + ssqc/time.qc | 9 - ssqc/weapons.qc | 2 +- 9 files changed, 484 insertions(+), 307 deletions(-) create mode 100644 csqc/weapon_predict.qc create mode 100644 share/fo_animate.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 437e56c6..22a26953 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -14,10 +14,12 @@ csextradefs.qc ../share/common_vote.qc ../share/fo_weapons.qc ../share/fo_weapon_predict.qc +../share/fo_animate.qc sui_sys.qc vote.qc status.qc menu.qc +weapon_predict.qc main.qc events.qc hud_helpers.qc diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc new file mode 100644 index 00000000..157f8a53 --- /dev/null +++ b/csqc/weapon_predict.qc @@ -0,0 +1,56 @@ +static void prandom(void() option1, void() option2) { + option1(); +} + +void FO_CSQC_Animate(float fired) { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + if (pstate_pred.client_thinkindex == 0 && !fired) { + player_run(); + return; + } + + switch (wi->weapon) { + case WEAP_ROCKET_LAUNCHER: + case WEAP_INCENDIARY: + case WEAP_GRENADE_LAUNCHER: + case WEAP_PIPE_LAUNCHER: + player_rocketN(); break; + + case WEAP_TRANQ: + case WEAP_RAILGUN: + case WEAP_SHOTGUN: + case WEAP_SUPER_SHOTGUN: + player_shotN(); break; + + case WEAP_FLAMETHROWER: + player_flamethrowerN(); break; + + case WEAP_NAILGUN: + case WEAP_SUPER_NAILGUN: + player_nailN(); break; + + case WEAP_AXE: + prandom(player_axeN, player_axebN); break; + case WEAP_KNIFE: + prandom(player_knifeN, player_knifebN); break; + case WEAP_MEDIKIT: + prandom(player_medikitN, player_medikitbN); break; + + case WEAP_SPANNER: + player_spannerN(); break; + } +} + +void FO_CSQC_Fire() { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + pstate_pred.client_thinkindex = 0; + + // Must be set prior to animation code, which might internally modify. + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + + FO_CSQC_Animate(TRUE); +} diff --git a/share/fo_animate.qc b/share/fo_animate.qc new file mode 100644 index 00000000..a11e14c0 --- /dev/null +++ b/share/fo_animate.qc @@ -0,0 +1,345 @@ +struct anim_t { + int num_frames, num_wf; + int frames[9]; + int weaponframes[9]; + int muzzle_flash; // muzzle flash on weaponframe index 0 + int loop; +}; + +static void think_nop() {} + +#ifdef SSQC + +void nail_extra(); +void asscan_up_extra(); +void asscan_fire_extra(); +void asscan_down_extra(); +void W_PrintWeaponMessage(); +void W_ChangeToBestWeapon(); +void W_FireSpikes(float ox); +void W_FireAssaultCannon(); +int W_FireAxe(); +int W_FireKnife(); +int W_FireMedikit(); +int W_FireSpanner(); + +void SuperDamageSound(); +void FO_Sound(entity e, float chan, string samp, float vol, float atten); +void TeamFortress_SetSpeed(entity p); + +void player_run(); +void player_stand1(); +void player_asscan_fire(); +void player_asscan_down1(); + +static inline void *thinkindex() { return &self.client_thinkindex; } + +void FO_SetClientThink(void() func, float offset, float override = TRUE) { + self.think = think_nop; + self.nextthink = 0; + + self.client_think = func; + self.client_nextthink = self.client_time + offset; +} + +void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { + int tidx = self.client_thinkindex++; + + int wfi = tidx % anim->num_wf; + self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; + if (wfi == 0 && anim->muzzle_flash) + muzzleflash(); + + int fi = tidx % anim->num_frames; + self.frame = anim->frames[fi] ?: anim->frames[0] + fi; + + if (fi == anim->num_frames - 1 && !anim->loop) + FO_SetClientThink(player_run, 0.1); + else + FO_SetClientThink(parent_thunk, 0.1); + + if (extra != think_nop) + extra(); +} + +static void axe_extra() { + float weapon = FO_CurrentWeapon(); + float* flag; + int() w_attack; + + // We'd use default below but compiler can't recognize that init is + // guaranteed then. + flag = &superaxe; + w_attack = W_FireAxe; + + switch (weapon) { + case WEAP_MEDIKIT: + flag = &supermedikit; + w_attack = W_FireMedikit; + break; + case WEAP_SPANNER: + flag = &superspanner; + w_attack = W_FireSpanner; + break; + case WEAP_KNIFE: + flag = &superknife; + w_attack = W_FireKnife; + break; + } + + if (self.weaponframe == 1) + self.hit_in_current_animation = FALSE; + + if ((*flag && !self.hit_in_current_animation) || + (!*flag && self.weaponframe == 3)) + self.hit_in_current_animation = w_attack(); + + if (weapon == WEAP_KNIFE && superknife && superknife_multihit) + self.hit_in_current_animation = FALSE; +} + +void nail_extra() { + if (!self.button0 || intermission_running) { + player_run(); + return; + } + + float idx = (self.client_thinkindex - 1) % 2; + if (idx == 0 || !old_ng_rof) { + SuperDamageSound(); + W_FireSpikes(self.nailpos ? 4 : -4); + self.nailpos = 1 - self.nailpos; + } +} + +static float CheckNeedAssaultCannonDown() { + FO_WeapState ws; + FO_FillWeapState(self, MakeSlot(1), &ws); + + if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || + ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { + self.tfstate |= TFSTATE_AIMING; + TeamFortress_SetSpeed(self); + player_asscan_down1(); + return TRUE; + } + return FALSE; +} + +void asscan_up_extra() { + if (CheckNeedAssaultCannonDown()) + return; + + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + self.fire_held_down = 1; + if (self.client_thinkindex == 1) // Already incremented + FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); + SuperDamageSound(); + + if (self.client_thinkindex == 6) // 600ms spin up + player_asscan_fire(); + else + Attack_Finished(wi->attack_time); +} + +void asscan_fire_extra() { + if (CheckNeedAssaultCannonDown()) + return; + + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) + && !(self.tfstate & TFSTATE_LOCK)) { + + if (self.client_thinkindex % 2 == 0) { + muzzleflash(); + FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); + } + + SuperDamageSound(); + + self.tfstate |= TFSTATE_AIMING; + if (!cannon_move) + self.tfstate |= TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + + // Halve firing speed when moving too fast. + if (vlen(self.velocity) < 30 || self.count % 2 == 0) + W_FireAssaultCannon(); + } else { + FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); + self.weaponframe = self.weaponframe == 2 ? 0 : 2; + } + Attack_Finished(wi->attack_time); +} + +void asscan_down_extra() { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if (self.client_thinkindex == 1) + FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); + + if (self.client_thinkindex >= 15) { // 1.5s down + self.fire_held_down = 0; + self.tfstate &= ~TFSTATE_AIMING; + if (!cannon_move) + self.tfstate &= ~TFSTATE_CANT_MOVE; + TeamFortress_SetSpeed(self); + + player_run(); + if (self.ammo_cells < 7 || !FO_CheckForReload()) { + W_PrintWeaponMessage(); + W_ChangeToBestWeapon(); + } + } + Attack_Finished(wi->attack_time); +}; + +void player_run() { + FO_SetClientThink(player_run, 0.1); + self.client_thinkindex = 0; + + self.frame = 6; + self.weaponframe = 0; + + if (!self.velocity_x && !self.velocity_y) { + self.walkframe = 0; + player_stand1(); + return; + } + + // Note: Reverses animation when walking backwards + self.walkframe = (self.walkframe + (self.movement_x < 0 ? -1 : 1) + 6) % 6; + self.frame = (IsSlotMelee(self.current_slot) ? 0 : 6) + self.walkframe; +}; + +void player_stand1() { + FO_SetClientThink(player_stand1, 0.1); + self.client_thinkindex = 0; + + self.frame = 17; + self.weaponframe = 0; + + if (self.velocity_x || self.velocity_y) { + self.walkframe = 0; + player_run(); + return; + } + + if (IsSlotMelee(self.current_slot)) { + if (self.walkframe >= 12) + self.walkframe = 0; + self.frame = 17 + self.walkframe; + } else { + if (self.walkframe >= 5) + self.walkframe = 0; + self.frame = 12 + self.walkframe; + } + self.walkframe++; +}; + +#else /* CSQC */ +static inline void *thinkindex() { return &pstate_pred.client_thinkindex; } + +void FO_SetClientThink(void() func, float offset, float override = TRUE) { + pstate_pred.client_nextthink = pstate_pred.client_time + offset; +} + +void player_run() { + pstate_pred.firing = FALSE; + pstate_pred.client_nextthink = 0; + pstate_pred.client_thinkindex = 0; + pstate_pred.weaponframe = 0; +} + +void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { + float tidx = (*thinkindex())++; + + float fi = tidx % anim->num_frames; + float wfi = tidx % anim->num_wf; + + float wf = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; + pstate_pred.weaponframe = wf; + + float loop = anim->loop && (input_buttons & BUTTON0); + + if (tidx > anim->num_frames - 1 && !loop) { + // Special case for CSQC since we could predict through the wrap. + player_run(); + } else if (fi == anim->num_frames - 1 && !loop) { + FO_SetClientThink(player_run, 0.1); + } else + FO_SetClientThink(parent_thunk, 0.1); + + if (extra != think_nop) + extra(); +} + +static void axe_extra() {} +static void nail_extra() { + pstate_pred.firing = TRUE; +} +static void asscan_up_extra() {} +static void asscan_fire_extra() {} +static void asscan_down_extra() {} + +#endif + +anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; +void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } +void player_rocket1() { *thinkindex() = 0; player_rocketN(); } + +anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; +void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } +void player_shot1() { *thinkindex() = 0; player_shotN(); } + + +anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; +void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } +void player_autorifle1() { *thinkindex() = 0; player_autorifleN(); } + +anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; +void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } +void player_axe1() { *thinkindex() = 0; player_axeN(); } + +anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; +void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } +void player_axeb1() { *thinkindex() = 0; player_axebN(); } + +void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } +void player_spanner1() { *thinkindex() = 0; player_spannerN(); } + +void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } +void player_knife1() { *thinkindex() = 0; player_knifeN(); } + +void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } +void player_knifeb1() { *thinkindex() = 0; player_knifebN(); } + +void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } +void player_medikit1() { *thinkindex() = 0; player_medikitN(); } + +void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } +void player_medikitb1() { *thinkindex() = 0; player_medikitbN(); } + +anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; +void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } +void player_nail1() { *thinkindex() = 0; player_nailN(); } + +anim_t anim_flamethrower = { 2, 6, {103, 104}, {1}, FALSE, TRUE }; +void player_flamethrowerN() { + client_anim_frames(player_flamethrowerN, think_nop, &anim_flamethrower); +} +void player_flamethrower1() { *thinkindex() = 0; player_flamethrowerN(); } + +anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; +anim_t anim_asscan_fire = { 1, 2, {103}, {2, 4}, FALSE, TRUE}; +anim_t anim_asscan_down = { 1, 6, {103}, {1, 1, 2, 2, 3, 3}, FALSE, TRUE}; + +void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } +void player_asscan_up1() { *thinkindex() = 0; player_asscan_upN(); } + +void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } +void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } +void player_asscan_down1() { *thinkindex() = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } + diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc index a743434c..aef06b0a 100644 --- a/share/fo_weapon_predict.qc +++ b/share/fo_weapon_predict.qc @@ -20,11 +20,14 @@ struct predict_tf_state { float tfstate; float client_time; - int weaponframe; + float weaponframe; float attack_finished; float client_nextthink; float client_thinkindex; + + // Used for prediction, not actually communicated. Reset each frame. + float firing; }; #ifdef SSQC @@ -121,13 +124,13 @@ void EntUpdate_WeaponPred(float isnew) { } if (sendflags & FOWP_THINK) { + COMM(Float, attack_finished); COMM(Float, client_nextthink); COMM(Float, client_thinkindex); } if (sendflags & FOWP_WF) { COMM(Byte, weaponframe); - COMM(Float, attack_finished); } #ifdef SSQC return TRUE; @@ -186,11 +189,13 @@ void WeaponPred_DoServerClientThink() { #endif #ifdef CSQC -void WeaponPred_ChangeWeapon(float input) { - Slot slot = FO_SlotByInput(input); - if (IsSlotNull(slot)) - return; // Unrecognized +static Slot InputToSlot(float input) { + Slot result = FO_SlotByInput(input); + return result; +} +void WeaponPred_ChangeWeapon(Slot slot) { + // TODO: Check ammo etc pstate_pred.current_slot = slot; pstate_pred.weaponframe = 0; @@ -201,28 +206,48 @@ void WeaponPred_Impulse() { if (!pstate_pred.impulse) return; - float clear = FALSE; + Slot queue_slot = SlotNull; + if (pstate_pred.impulse <= 7) { // Change weapon. - WeaponPred_ChangeWeapon(pstate_pred.impulse); - clear = TRUE; + Slot slot = InputToSlot(pstate_pred.impulse); + if (!IsSlotNull(slot)) + pstate_pred.queue_slot = slot; + pstate_pred.impulse = 0; + } + + if (pstate_pred.client_time < pstate_pred.attack_finished) + return; + + if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { + WeaponPred_ChangeWeapon(pstate_pred.queue_slot); + pstate_pred.queue_slot = SlotNull; } + float clear = FALSE; if (clear) pstate_pred.impulse = 0; } +void FO_CSQC_Fire(); + void WeaponPred_Attack() { + if (pstate_pred.firing) // Already in a continuous attack. + return; + Slot slot = pstate_pred.current_slot; FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - pstate_pred.client_thinkindex = 1; + pstate_pred.client_thinkindex = 0; pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + + FO_CSQC_Fire(); } +void FO_CSQC_Animate(float fired); void WeaponPred_DoClientThink(void) { - + FO_CSQC_Animate(FALSE); } void WeaponPred_UpdateViewModel() { @@ -231,6 +256,16 @@ void WeaponPred_UpdateViewModel() { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); + if (wi->predict_type == NO_PREDICT) { + // Fall back to engine. + self.modelindex = 0; + wp_model_mask |= MASK_VIEWMODEL; + return; + } else { + wp_model_mask &= ~MASK_VIEWMODEL; + + } + pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; @@ -279,13 +314,11 @@ float WeaponPred_ClientThink() { pstate_pred.client_time = held_client_time; } - if (pstate_pred.client_time >= pstate_pred.attack_finished) { - WeaponPred_Impulse(); - - if (input_buttons & BUTTON0) - WeaponPred_Attack(); - } + WeaponPred_Impulse(); + if ((input_buttons & BUTTON0) && + (pstate_pred.client_time >= pstate_pred.attack_finished)) + WeaponPred_Attack(); } WeaponPred_UpdateViewModel(); diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 2d4adb38..440bc2c6 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -80,8 +80,15 @@ enum AmmoType { struct FO_WeapModels; struct FO_WeapToItem; +enum PredictionType { + NO_PREDICT, + PRED_MODEL, + PRED_PROJ, +}; + struct FO_WeapInfo { int weapon; // Verification + int predict_type; AmmoType ammo_type; float clip_size; float ammo_per_shot; @@ -98,28 +105,28 @@ struct FO_WeapInfo { // REQUIRES: weapon at index i == WEAP_to_index(weap) // -ve values are placeholders signifying conditional init based on game modes. FO_WeapInfo weapon_info[] = { - { WEAP_NONE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_HOOK, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_KNIFE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_MEDIKIT, AMMO_CELLS, 0, 0, 0.5, 0 }, - { WEAP_SPANNER, AMMO_CELLS, 0, 0, 0.5, 0 }, - { WEAP_AXE, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_SNIPER_RIFLE, AMMO_SHELLS, -9, 1, 1.5, 4 }, - { WEAP_AUTO_RIFLE, AMMO_SHELLS, 0, 1, 0.1, 0 }, - { WEAP_SHOTGUN, AMMO_SHELLS, 8, 1, 0.5, 2 }, - { WEAP_SUPER_SHOTGUN, AMMO_SHELLS, 16, 2, 0.7, 3 }, - { WEAP_NAILGUN, AMMO_NAILS, 0, 1, 0.2, 0 }, - { WEAP_SUPER_NAILGUN, AMMO_NAILS, 0, 2, 0.2, 0 }, - { WEAP_GRENADE_LAUNCHER, AMMO_ROCKETS, 6, 1, 0.6, 4 }, - { WEAP_PIPE_LAUNCHER, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL - { WEAP_FLAMETHROWER, AMMO_CELLS, 0, 1, 0.15, 0 }, - { WEAP_ROCKET_LAUNCHER, AMMO_ROCKETS, 4, 1, 0.8, 5 }, - { WEAP_INCENDIARY, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, AMMO_SHELLS, -9, 1, 0.2, 4 }, - { WEAP_LIGHTNING, AMMO_CELLS, 0, 1, 0.1, 0 }, - { WEAP_DETPACK, AMMO_NONE, 0, 0, 0, 0 }, - { WEAP_TRANQ, AMMO_SHELLS, 0, 1, 1.5, 0 }, - { WEAP_RAILGUN, AMMO_NAILS, 0, 1, 0.4, 0 }, + { WEAP_NONE, NO_PREDICT, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_HOOK, NO_PREDICT, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_KNIFE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_MEDIKIT, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, + { WEAP_SPANNER, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, + { WEAP_AXE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, + { WEAP_SNIPER_RIFLE, NO_PREDICT, AMMO_SHELLS, -9, 1, 1.5, 4 }, + { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0 }, + { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, + { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, + { WEAP_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.2, 0 }, + { WEAP_SUPER_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 2, 0.2, 0 }, + { WEAP_GRENADE_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 6, 1, 0.6, 4 }, + { WEAP_PIPE_LAUNCHER, PRED_MODEL, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL + { WEAP_FLAMETHROWER, PRED_MODEL, AMMO_CELLS, 0, 1, 0.15, 0 }, + { WEAP_ROCKET_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 4, 1, 0.8, 5 }, + { WEAP_INCENDIARY, PRED_MODEL, AMMO_ROCKETS, 0, 3, -9, 0 }, + { WEAP_ASSAULT_CANNON, NO_PREDICT, AMMO_SHELLS, -9, 1, 0.2, 4 }, + { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, + { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, + { WEAP_TRANQ, NO_PREDICT, AMMO_SHELLS, 0, 1, 1.5, 0 }, + { WEAP_RAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.4, 0 }, }; inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { diff --git a/ssqc/player.qc b/ssqc/player.qc index bf06a2fe..0e74bd42 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -83,264 +83,6 @@ void () player_touch = { } }; -void player_stand1() { - FO_SetClientThink(player_stand1, 0.1); - - self.frame = 17; - self.weaponframe = 0; - - if (self.velocity_x || self.velocity_y) { - self.walkframe = 0; - player_run(); - return; - } - - if (IsSlotMelee(self.current_slot)) { - if (self.walkframe >= 12) - self.walkframe = 0; - self.frame = 17 + self.walkframe; - } else { - if (self.walkframe >= 5) - self.walkframe = 0; - self.frame = 12 + self.walkframe; - } - self.walkframe++; -}; - -void player_run() { - FO_SetClientThink(player_run, 0.1); - - self.frame = 6; - self.weaponframe = 0; - - if (!self.velocity_x && !self.velocity_y) { - self.walkframe = 0; - player_stand1(); - return; - } - - // Note: Reverses animation when walking backwards - self.walkframe = (self.walkframe + (self.movement_x < 0 ? -1 : 1) + 6) % 6; - self.frame = (IsSlotMelee(self.current_slot) ? 0 : 6) + self.walkframe; -}; - -static void think_nop() {} - -struct anim_t { - int num_frames, num_wf; - int frames[9]; - int weaponframes[9]; - int muzzle_flash; // muzzle flash on weaponframe index 0 - int loop; -}; - -void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - int tidx = self.client_thinkindex++; - - int wfi = tidx % anim->num_wf; - self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; - if (wfi == 0 && anim->muzzle_flash) - muzzleflash(); - - int fi = tidx % anim->num_frames; - self.frame = anim->frames[fi] ?: anim->frames[0] + fi; - - if (wfi == anim->num_wf - 1 && !anim->loop) - FO_SetClientThink(player_run, 0.1); - else - FO_SetClientThink(parent_thunk, 0.1); - - if (extra != think_nop) - extra(); -} - -anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; -void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } -void player_rocket1() { self.client_thinkindex = 0; player_rocketN(); } - -anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; -void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } -void player_shot1() { self.client_thinkindex = 0; player_shotN(); } - - -anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; -void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } -void player_autorifle1() { self.client_thinkindex = 0; player_autorifleN(); } - - -static void axe_extra() { - float weapon = FO_CurrentWeapon(); - float* flag; - int() w_attack; - - // We'd use default below but compiler can't recognize that init is - // guaranteed then. - flag = &superaxe; - w_attack = W_FireAxe; - - switch (weapon) { - case WEAP_MEDIKIT: - flag = &supermedikit; - w_attack = W_FireMedikit; - break; - case WEAP_SPANNER: - flag = &superspanner; - w_attack = W_FireSpanner; - break; - case WEAP_KNIFE: - flag = &superknife; - w_attack = W_FireKnife; - break; - } - - if ((*flag && !self.hit_in_current_animation) || - (!*flag && self.weaponframe == 3)) - self.hit_in_current_animation = w_attack(); - - if (weapon == WEAP_KNIFE && superknife && superknife_multihit) - self.hit_in_current_animation = FALSE; -} - -anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; -void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } -void player_axe1() { self.client_thinkindex = 0; player_axeN(); } - -anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; -void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } -void player_axeb1() { self.client_thinkindex = 0; player_axebN(); } - -void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } -void player_spanner1() { self.client_thinkindex = 0; player_spannerN(); } - -void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } -void player_knife1() { self.client_thinkindex = 0; player_knifeN(); } - -// TODO: zel had this on 125, but I think it should be on 124. Double check. -void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } -void player_knifeb1() { self.client_thinkindex = 0; player_knifebN(); } - -void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } -void player_medikit1() { self.client_thinkindex = 0; player_medikitN(); } - -// TODO: zel had this on 125, but I think it should be on 124. Double check. -void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } -void player_medikitb1() { self.client_thinkindex = 0; player_medikitbN(); } - - -void nail_extra() { - if (!self.button0 || intermission_running) { - player_run(); - return; - } - - float idx = (self.client_thinkindex - 1) % 2; - if (idx == 0 || !old_ng_rof) { - SuperDamageSound(); - W_FireSpikes(self.nailpos ? 4 : -4); - self.nailpos = 1 - self.nailpos; - } -} - -anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; -void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } -void player_nail1() { self.client_thinkindex = 0; player_nailN(); } - -void player_asscan_fire(); -void player_asscan_down1(); - -static float CheckNeedAssaultCannonDown() { - FO_WeapState ws; - FO_FillWeapState(self, MakeSlot(1), &ws); - - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || - ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { - self.tfstate |= TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - player_asscan_down1(); - return TRUE; - } - return FALSE; -} - -void asscan_up_extra() { - if (CheckNeedAssaultCannonDown()) - return; - - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - self.fire_held_down = 1; - if (self.client_thinkindex == 1) // Already incremented - FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - SuperDamageSound(); - - if (self.client_thinkindex == 6) // 600ms spin up - player_asscan_fire(); - else - Attack_Finished(wi->attack_time); -} - -void asscan_fire_extra() { - if (CheckNeedAssaultCannonDown()) - return; - - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) - && !(self.tfstate & TFSTATE_LOCK)) { - - if (self.client_thinkindex % 2 == 0) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - - SuperDamageSound(); - - self.tfstate |= TFSTATE_AIMING; - if (!cannon_move) - self.tfstate |= TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - - // Halve firing speed when moving too fast. - if (vlen(self.velocity) < 30 || self.count % 2 == 0) - W_FireAssaultCannon(); - } else { - FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); - self.weaponframe = self.weaponframe == 2 ? 0 : 2; - } - Attack_Finished(wi->attack_time); -} - -void asscan_down_extra() { - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (self.client_thinkindex == 1) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); - - if (self.client_thinkindex >= 15) { // 1.5s down - self.fire_held_down = 0; - self.tfstate &= ~TFSTATE_AIMING; - if (!cannon_move) - self.tfstate &= ~TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - - player_run(); - if (self.ammo_cells < 7 || !FO_CheckForReload()) { - W_PrintWeaponMessage(); - W_ChangeToBestWeapon(); - } - } - Attack_Finished(wi->attack_time); -}; - -anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; -anim_t anim_asscan_fire = { 1, 4, {103}, {2, 4}, FALSE, TRUE}; -anim_t anim_asscan_down = { 1, 8, {103}, {1, 1, 2, 2, 3, 3, 4, 4}, FALSE, TRUE}; - -void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } -void player_asscan_up1() { self.client_thinkindex = 0; player_asscan_upN(); } - -void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } -void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } -void player_asscan_down1() { self.client_thinkindex = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } - void () player_light1 =[105, player_light2] { muzzleflash(); if (!self.button0 || intermission_running) { diff --git a/ssqc/progs.src b/ssqc/progs.src index 6276ed43..414de5b3 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -18,6 +18,7 @@ time.qc ../share/defs.h ../share/fo_weapons.qc ../share/fo_weapon_predict.qc +../share/fo_animate.qc events.qc roles.qc q3defs.qc diff --git a/ssqc/time.qc b/ssqc/time.qc index f827530b..c77f2fb4 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -21,15 +21,6 @@ inline float client_to_global_time(float ctime) { } -static void think_nop() {} -void FO_SetClientThink(void() func, float offset, float override = TRUE) { - self.think = think_nop; - self.nextthink = 0; - - self.client_think = func; - self.client_nextthink = self.client_time + offset; -} - void FO_CheckClientThink() { if (self.client_nextthink && self.client_time >= self.client_nextthink) { float held_client_time = self.client_time; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 05639f60..3b0f0f4f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1725,7 +1725,7 @@ void () W_Attack = { player_asscan_up1(); } } else if (ws.weapon == WEAP_FLAMETHROWER) { - player_shot1(); + player_flamethrower1(); W_FireFlame(); if (self.waterlevel > 2) Attack_Finished(1); From 1d3eca00616ea3d5c79b432fd3fd0e50a290c92b Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 3 Oct 2022 14:09:12 -0700 Subject: [PATCH 1776/2474] Implement predicted reload and ammo tracking Client side handling around all of the ammo/clip details so that we can reload (and not predict firing) correctly. Integrates with displayed ammo/clip/etc. --- csqc/status.qc | 12 +-- csqc/weapon_predict.qc | 12 --- share/fo_weapon_predict.qc | 205 +++++++++++++++++++++++++++++++++---- share/fo_weapons.qc | 36 ++++--- ssqc/qw.qc | 2 + 5 files changed, 216 insertions(+), 51 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 7e9128af..efea8c5f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1112,7 +1112,7 @@ var FO_Hud_Panel Hud_Panels[] = { // Style, Snap, Status {"hudoptions",FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return DrawPanel.id;}, 1}, - {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return SBAR.ClipSize; }}, + {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return WP_GetClip(); }}, {"fragstreak",FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {"caps",FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, {"gren1",FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, @@ -1131,14 +1131,14 @@ var FO_Hud_Panel Hud_Panels[] = { {"mapmenu",FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, {"health",FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, {"face",FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0, drawFacePanel, {return "";}, 0, 34}, - {"ammo",FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(getstatf(STAT_AMMO));}, 0, 34}, + {"ammo",FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(WP_CurrentAmmo());}, 0, 34}, {"ammoicon",FO_HUD_AMMO_ICON_NAME , '42 -2', '24 24', 1,0,1,0, drawAmmoPanel, {return "";}, 0, 34}, {"armour",FO_HUD_ARMOUR_NAME, '-134 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}, 0, 34}, {"armouricon",FO_HUD_ARMOUR_ICON_NAME,'-182 -2', '24 24', 1,0,1,0, drawArmourPanel, {return "";}, 0, 34}, - {"invshells",FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(getstatf(STAT_SHELLS));}, 1, 33}, - {"invnails",FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(getstatf(STAT_NAILS));}, 1, 33}, - {"invrockets",FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(getstatf(STAT_ROCKETS));}, 1, 33}, - {"invcells",FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(getstatf(STAT_CELLS));}, 1, 33}, + {"invshells",FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(WP_GetAmmo(AMMO_SHELLS));}, 1, 33}, + {"invnails",FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(WP_GetAmmo(AMMO_NAILS));}, 1, 33}, + {"invrockets",FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(WP_GetAmmo(AMMO_ROCKETS));}, 1, 33}, + {"invcells",FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(WP_GetAmmo(AMMO_CELLS));}, 1, 33}, {"gameclock","Game Clock", '0 0' , '108 24', 1,0.8,1,0, drawClockPanel, {return gameClockString();}, 0, 10}, {"quad","Quad Icon", '-200 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}, 0, 36}, {"pent","Pentagram Icon", '-170 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}, 0, 36}, diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 157f8a53..2f465619 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -42,15 +42,3 @@ void FO_CSQC_Animate(float fired) { player_spannerN(); break; } } - -void FO_CSQC_Fire() { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - pstate_pred.client_thinkindex = 0; - - // Must be set prior to animation code, which might internally modify. - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - - FO_CSQC_Animate(TRUE); -} diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc index aef06b0a..31e4dc3a 100644 --- a/share/fo_weapon_predict.qc +++ b/share/fo_weapon_predict.qc @@ -9,8 +9,9 @@ enumflags { FOWP_TFSTATE, FOWP_WF, FOWP_CLASS, + FOWP_RELOAD, }; -#define FOWP_ALL 0xFF +#define FOWP_ALL 0xFFFF struct predict_tf_state { int playerclass; @@ -26,8 +27,13 @@ struct predict_tf_state { float client_nextthink; float client_thinkindex; + float reload_finished; + float clip_fired[4]; + + // Used for prediction, not actually communicated. Reset each frame. - float firing; + float ammo_used[AMMO_NUM_TYPES]; + float firing; }; #ifdef SSQC @@ -49,8 +55,12 @@ struct pengine_t { // Must include MASK_PRED_VIEWMODEL or we lose updates. // We only add/remove MASK_VIEWMODEL. float wp_model_mask; +float wp_enabled; + +static int WP_Enabled() { return wp_enabled; } void FO_WeaponPred_Init(float enabled) { + wp_enabled = enabled; wp_model_mask = enabled ? MASK_PRED_VIEWMODEL : MASK_VIEWMODEL; } #endif @@ -73,7 +83,10 @@ void UpdateWeaponPred(entity player) { M1(FOWP_CLASS, playerclass); M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); M1(FOWP_TFSTATE, tfstate); - M3(FOWP_THINK, attack_finished, client_nextthink, client_thinkindex) + M2(FOWP_WF, attack_finished, weaponframe); + M2(FOWP_THINK, client_nextthink, client_thinkindex); + M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) + M1(FOWP_RELOAD, reload_finished) player.predict_entity.SendFlags = mask; } @@ -95,7 +108,7 @@ float WeaponPred_SendEntity(entity to_player, float sendflags) { return FALSE; WriteByte(MSG_ENTITY, ENT_WEAPONPRED); - WriteByte(MSG_ENTITY, sendflags); + WriteFloat(MSG_ENTITY, sendflags); #else float() ReadByte = #360; float() ReadFloat = #367; @@ -103,7 +116,7 @@ void InitPredEnt(entity e); #define COMM(_type, _field) pstate_server.##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { - float sendflags = readbyte(); + float sendflags = readfloat(); #endif if (sendflags & FOWP_CTIME) { COMM(Float, client_time); @@ -124,14 +137,25 @@ void EntUpdate_WeaponPred(float isnew) { } if (sendflags & FOWP_THINK) { - COMM(Float, attack_finished); COMM(Float, client_nextthink); COMM(Float, client_thinkindex); } if (sendflags & FOWP_WF) { + COMM(Float, attack_finished); COMM(Byte, weaponframe); } + + if (sendflags & FOWP_CLIP) { + COMM(Byte, clip_fired[0]); + COMM(Byte, clip_fired[1]); + COMM(Byte, clip_fired[2]); + COMM(Byte, clip_fired[3]); + } + + if (sendflags & FOWP_RELOAD) + COMM(Float, reload_finished); + #ifdef SSQC return TRUE; #else @@ -195,27 +219,25 @@ static Slot InputToSlot(float input) { } void WeaponPred_ChangeWeapon(Slot slot) { - // TODO: Check ammo etc pstate_pred.current_slot = slot; pstate_pred.weaponframe = 0; // UpdateViewModel will propagate. } -void WeaponPred_Impulse() { - if (!pstate_pred.impulse) - return; - - Slot queue_slot = SlotNull; +void WeaponPred_Reload(); - if (pstate_pred.impulse <= 7) { // Change weapon. +void WeaponPred_Impulse() { + // Note: We might have no impulse, but a queued slot here. + if (pstate_pred.impulse >= 1 && pstate_pred.impulse <= 7) { // Change weapon Slot slot = InputToSlot(pstate_pred.impulse); if (!IsSlotNull(slot)) pstate_pred.queue_slot = slot; pstate_pred.impulse = 0; } - if (pstate_pred.client_time < pstate_pred.attack_finished) + if (pstate_pred.client_time < pstate_pred.attack_finished || + (pstate_pred.tfstate & TFSTATE_RELOADING)) return; if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { @@ -223,13 +245,151 @@ void WeaponPred_Impulse() { pstate_pred.queue_slot = SlotNull; } + if (!pstate_pred.impulse) + return; + float clear = FALSE; + + if (pstate_pred.impulse == TF_RELOAD) { + WeaponPred_Reload(); + clear = TRUE; + } + if (clear) pstate_pred.impulse = 0; } void FO_CSQC_Fire(); +static float AmmoToStat(float ammo_type) { + switch (ammo_type) { + case AMMO_SHELLS: return STAT_SHELLS; + case AMMO_ROCKETS: return STAT_ROCKETS; + case AMMO_NAILS: return STAT_NAILS; + case AMMO_CELLS: return STAT_CELLS; + } + return STAT_AMMO; +} + +float WP_GetAmmo(float ammo_type) { + if (!WP_Enabled()) + return getstatf(AmmoToStat(ammo_type)); + + if (ammo_type == AMMO_NONE) + return 0; + + float base = getstatf(AmmoToStat(ammo_type)); + base -= pstate_pred.ammo_used[ammo_type]; + return max(0, base); +} + +float WP_CurrentAmmo() { + if (!WP_Enabled()) + return getstatf(STAT_AMMO); + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + return WP_GetAmmo(wi->ammo_type); +} + +static float* ClipFired() { + float index = SlotIndex(pstate_pred.current_slot); + if (pstate_pred.playerclass == PC_DEMOMAN && + index == 1) + index = 0; // Special case: Pipebomb shares with Grenadel launcher. + + return &pstate_pred.clip_fired[index]; +} + +string WP_GetClip() { + if (!WP_Enabled()) + return SBAR.ClipSize; + + Slot slot = pstate_pred.current_slot; + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + + if (!wi->needs_reload || IsSlotNull(slot)) + return ""; + + float capacity = wi->clip_size; + float still_loading = 0; + float fired = *ClipFired(); + + if (pstate_pred.tfstate & TFSTATE_RELOADING) + still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, + pstate_pred.reload_finished); + + float clip = capacity - fired - still_loading; + return sprintf("%d/%d", clip, wi->clip_size); +} + +void WeaponPred_CheckReloadFinished() { + if ((pstate_pred.tfstate & TFSTATE_RELOADING) && + pstate_pred.client_time >= pstate_pred.reload_finished) { + pstate_pred.tfstate &= ~TFSTATE_RELOADING; + + if (pengine.is_effectframe) + print("Finished reloading\n"); + } +} + +void WeaponPred_Reload() { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + if (!wi->needs_reload) + return; + + float clip_fired = *ClipFired(); + float ammo_rem = WP_GetAmmo(wi->ammo_type); + + string msg; + if (!FO_CheckCanReload(wi, ammo_rem, clip_fired, msg)) { + if (pengine.is_effectframe) + print(msg); + return; + } + + if (pengine.is_effectframe) + print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); + + pstate_pred.tfstate |= TFSTATE_RELOADING; + float amt = min(ammo_rem, clip_fired); + (*ClipFired()) -= amt; + + pstate_pred.reload_finished = pstate_pred.client_time + + (amt / wi->clip_size) * wi->full_reload_time; +} + +float WeaponPred_IsReloading() { + return pstate_pred.tfstate & TFSTATE_RELOADING; +} + + +float WeaponPred_ConsumeAmmo(FO_WeapInfo* wi) { + if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) + return TRUE; + + int ammo = WP_GetAmmo(wi->ammo_type); + if (wi->ammo_per_shot > ammo) + return FALSE; + + if (wi->needs_reload) { + if (*ClipFired() >= wi->clip_size) { + WeaponPred_Reload(); + return FALSE; + } + } + + pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; + *ClipFired() += wi->ammo_per_shot; + + return TRUE; +} + +void FO_CSQC_Animate(float fired); + void WeaponPred_Attack() { if (pstate_pred.firing) // Already in a continuous attack. return; @@ -238,14 +398,16 @@ void WeaponPred_Attack() { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + if (!WeaponPred_ConsumeAmmo(wi)) + return; + + // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 0; pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - FO_CSQC_Fire(); + FO_CSQC_Animate(TRUE); } -void FO_CSQC_Animate(float fired); - void WeaponPred_DoClientThink(void) { FO_CSQC_Animate(FALSE); } @@ -266,6 +428,11 @@ void WeaponPred_UpdateViewModel() { } + if (pstate_pred.tfstate & TFSTATE_RELOADING) { + self.modelindex = 0; + return; + } + pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; @@ -314,11 +481,14 @@ float WeaponPred_ClientThink() { pstate_pred.client_time = held_client_time; } + WeaponPred_CheckReloadFinished(); WeaponPred_Impulse(); if ((input_buttons & BUTTON0) && + (pstate_pred.tfstate & TFSTATE_RELOADING == 0) && (pstate_pred.client_time >= pstate_pred.attack_finished)) WeaponPred_Attack(); + } WeaponPred_UpdateViewModel(); @@ -332,6 +502,5 @@ void InitPredEnt(entity pe) { self.renderflags = RF_VIEWMODEL; FO_WeaponPred_Init(TRUE); - } #endif diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc index 440bc2c6..7b503580 100644 --- a/share/fo_weapons.qc +++ b/share/fo_weapons.qc @@ -228,9 +228,6 @@ Slot WEAP_to_slot(float playerclass, float weapon) { return SlotNull; } -// Internal clip storage for both SSQC/CSQC. -.float clip_fired[TF_NUM_SLOTS]; - struct FO_WeapToItem { int weapon; float it_weapon; @@ -306,11 +303,26 @@ float FO_WeaponsMask(entity player) { return mask; } +// Slightly awkward construction, but convenient for calling from CSQC and SSQC. float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) { float tick = (wi->ammo_per_shot / wi->clip_size) * wi->full_reload_time; return ceil((reload_finished - now) / tick) * wi->ammo_per_shot; } +float FO_CheckCanReload(FO_WeapInfo* wi, int ammo_remaining, int clip_fired, + __out string msg) { + if (clip_fired == 0) + msg = "Clip full\n"; + else if (ammo_remaining == 0) + msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); + else if (wi->clip_size - clip_fired == ammo_remaining) + msg = strcat("All ", AMMO_to_s[wi->ammo_type], " are in the clip\n"); + else + return TRUE; + + return FALSE; // msg filled in above. +} + #ifdef SSQC struct FO_WeapState { float weapon; @@ -424,22 +436,15 @@ void FO_ReloadSlot(Slot slot, float force) { if (!wi->needs_reload) return; - string msg = string_null; - if (*ws->clip_fired == 0) - msg = "Clip full\n"; - else if (*ws->ammo_remaining == 0) - msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); - else if (wi->clip_size - *ws->clip_fired == *ws->ammo_remaining) - msg = strcat("All ", AMMO_to_s[wi->ammo_type], "are in the clip\n"); - - if (msg != string_null) { + string msg; + if (!FO_CheckCanReload(wi, *ws->ammo_remaining, *ws->clip_fired, msg)) { sprint(self, PRINT_HIGH, msg); return; - } else { - sprint(self, PRINT_HIGH, strcat("Reloading ", - FO_GetWeapName(ws->weapon), "...\n")); } + sprint(self, PRINT_HIGH, + strcat("Reloading ", FO_GetWeapName(ws->weapon), "...\n")); + Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. self.weaponmodel = ""; @@ -454,6 +459,7 @@ void FO_ReloadSlot(Slot slot, float force) { // TODO: Make ammo in clip independent from ammo_remaining (so you can't // have shots in clip that are discarded and other weirdness.) (*ws->clip_fired) -= reload_count; + self.last_still_loading = reload_count; self.reload_finished = self.client_time + reload_duration; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d61093c1..856d7c55 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -236,6 +236,8 @@ float coop; .float reload_assault_cannon; // Only use above for map ent compatibility. +.float clip_fired[TF_NUM_SLOTS]; + // Assault Cannon .float heat; From 25e0dd3a1d99da855b90c0be8638399cc3ca274e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 11:12:04 -0700 Subject: [PATCH 1777/2474] Periodic full refresh of predict state Occasionally see gaps, unclear if dropped packet or missing sync but force a periodic full refresh for sanity. Also add a (arbitrary) lower bound of 40msec around which dont enable prediction for now. Also add some global and per-client enable/disable twiddles. --- share/fo_weapon_predict.qc | 42 +++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc index 31e4dc3a..432f2fca 100644 --- a/share/fo_weapon_predict.qc +++ b/share/fo_weapon_predict.qc @@ -1,4 +1,5 @@ #define ENT_WEAPONPRED 100 +string wp_version = "v0"; enumflags { FOWP_CTIME, @@ -37,6 +38,31 @@ struct predict_tf_state { }; #ifdef SSQC + +float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); +float CF_GetSetting(string ps_short, string ps_setting, string ps_default); + +static float GlobalEnable() { + return CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); +} + +static float GlobalDisable() { + return CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); +} + +static float ClientEnable() { + // client_ping is not yet initialized. + float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; + + if (GlobalDisable() || ping < 40 * MSEC) + return FALSE; + + if (GlobalEnable()) + return TRUE; + + return FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "off"); +} + .float weapon_pred_enabled; .predict_tf_state predict_state; .entity predict_entity; @@ -75,9 +101,17 @@ void FO_WeaponPred_Init(float enabled) { #define M3(_bit, _f1, _f2, _f3) if (OP3(!=, ||, _f1, _f2, _f3)) { mask |= _bit; OP3(=, ;, _f1, _f2, _f3); } #define M4(_bit, _f1, _f2, _f3, _f4) if (OP4(!=, ||, _f1, _f2, _f3, _f4)) { mask |= _bit; OP4(=, ;, _f1, _f2, _f3, _f4); } +predict_tf_state blank_state; +.float last_full_predict_refresh; + void UpdateWeaponPred(entity player) { float mask = FOWP_CTIME; + if (time - player.last_full_predict_refresh > 1000 * MSEC) { + player.predict_state = blank_state; + player.last_full_predict_refresh = time; + } + player.predict_state.client_time = player.client_time; M1(FOWP_CLASS, playerclass); @@ -165,15 +199,12 @@ void EntUpdate_WeaponPred(float isnew) { } #ifdef SSQC -float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); - inline float WeaponPred_Active(entity player) { return player.weapon_pred_enabled; } void WeaponPred_Init(entity player) { - // Server side is once per connect. - if (!FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "on")) { + if (!ClientEnable()) { // Server side is once per connect. player.weapon_pred_enabled = FALSE; return; } @@ -189,7 +220,8 @@ void WeaponPred_Init(entity player) { setorigin(pe, [0, 0, 0]); player.predict_entity = pe; - sprint(self, PRINT_HIGH, "FortressOne: Weapon Prediction Active v0\n"); + sprint(self, PRINT_HIGH, + "FortressOne: Weapon Prediction Active ", wp_version, "\n"); } void WeaponPred_TearDown(entity player) { From 784a7ae614bbd239527db319b74b8947009743d9 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 13:27:31 -0700 Subject: [PATCH 1778/2474] Refactor 1 Some refactoring and clean-up --- csqc/csprogs.src | 6 +++--- share/{fo_animate.qc => animate.qc} | 0 share/{fo_weapon_predict.qc => weapon_predict.qc} | 0 share/{fo_weapons.qc => weapons.qc} | 0 ssqc/progs.src | 6 +++--- 5 files changed, 6 insertions(+), 6 deletions(-) rename share/{fo_animate.qc => animate.qc} (100%) rename share/{fo_weapon_predict.qc => weapon_predict.qc} (100%) rename share/{fo_weapons.qc => weapons.qc} (100%) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 22a26953..c50df223 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -12,9 +12,9 @@ csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc -../share/fo_weapons.qc -../share/fo_weapon_predict.qc -../share/fo_animate.qc +../share/weapons.qc +../share/weapon_predict.qc +../share/animate.qc sui_sys.qc vote.qc status.qc diff --git a/share/fo_animate.qc b/share/animate.qc similarity index 100% rename from share/fo_animate.qc rename to share/animate.qc diff --git a/share/fo_weapon_predict.qc b/share/weapon_predict.qc similarity index 100% rename from share/fo_weapon_predict.qc rename to share/weapon_predict.qc diff --git a/share/fo_weapons.qc b/share/weapons.qc similarity index 100% rename from share/fo_weapons.qc rename to share/weapons.qc diff --git a/ssqc/progs.src b/ssqc/progs.src index 414de5b3..6d067d32 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -16,9 +16,9 @@ qw.qc debug.qc time.qc ../share/defs.h -../share/fo_weapons.qc -../share/fo_weapon_predict.qc -../share/fo_animate.qc +../share/weapons.qc +../share/weapon_predict.qc +../share/animate.qc events.qc roles.qc q3defs.qc From f76d0265ff1c7101b21bb13c79405562face75ab Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 13:29:31 -0700 Subject: [PATCH 1779/2474] Refactor 2 More refactoring and cleanup --- csqc/csprogs.src | 2 +- csqc/main.qc | 2 +- csqc/weapon_predict.qc | 206 ++++++++++++++++++++++++++++++++++- share/weapon_predict.qc | 236 +++------------------------------------- ssqc/client.qc | 2 +- 5 files changed, 225 insertions(+), 223 deletions(-) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index c50df223..86ba3b15 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -15,11 +15,11 @@ csextradefs.qc ../share/weapons.qc ../share/weapon_predict.qc ../share/animate.qc +weapon_predict.qc sui_sys.qc vote.qc status.qc menu.qc -weapon_predict.qc main.qc events.qc hud_helpers.qc diff --git a/csqc/main.qc b/csqc/main.qc index 03d77eda..3afd3da7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,7 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // } FO_Weapons_Init(); - FO_WeaponPred_Init(FALSE); // Server packet enables. + FO_WP_Init(FALSE); // Server packet enables. CsGrenTimer::Init(); registercommand("fo_hud_editor"); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2f465619..0eb0db36 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,8 +1,180 @@ +static Slot InputToSlot(float input) { + Slot result = FO_SlotByInput(input); + return result; +} + +inline float WP_IsReloading() { + return pstate_pred.tfstate & TFSTATE_RELOADING; +} + +void WP_ChangeWeapon(Slot slot) { + pstate_pred.current_slot = slot; + pstate_pred.weaponframe = 0; + + // UpdateViewModel will propagate. +} + +void WP_Reload(); + +void WP_Impulse() { + // Note: We might have no impulse, but a queued slot here. + if (pstate_pred.impulse >= 1 && pstate_pred.impulse <= 7) { // Change weapon + Slot slot = InputToSlot(pstate_pred.impulse); + if (!IsSlotNull(slot)) + pstate_pred.queue_slot = slot; + pstate_pred.impulse = 0; + } + + if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) + return; + + if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { + WP_ChangeWeapon(pstate_pred.queue_slot); + pstate_pred.queue_slot = SlotNull; + } + + if (!pstate_pred.impulse) + return; + + float clear = FALSE; + + if (pstate_pred.impulse == TF_RELOAD) { + WP_Reload(); + clear = TRUE; + } + + if (clear) + pstate_pred.impulse = 0; +} + +static float AmmoToStat(float ammo_type) { + switch (ammo_type) { + case AMMO_SHELLS: return STAT_SHELLS; + case AMMO_ROCKETS: return STAT_ROCKETS; + case AMMO_NAILS: return STAT_NAILS; + case AMMO_CELLS: return STAT_CELLS; + } + return STAT_AMMO; +} + +float WP_GetAmmo(float ammo_type) { + if (!WP_Enabled()) + return getstatf(AmmoToStat(ammo_type)); + + if (ammo_type == AMMO_NONE) + return 0; + + float base = getstatf(AmmoToStat(ammo_type)); + base -= pstate_pred.ammo_used[ammo_type]; + return max(0, base); +} + +float WP_CurrentAmmo() { + if (!WP_Enabled()) + return getstatf(STAT_AMMO); + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + return WP_GetAmmo(wi->ammo_type); +} + +static float* ClipFired() { + float index = SlotIndex(pstate_pred.current_slot); + if (pstate_pred.playerclass == PC_DEMOMAN && + index == 1) + index = 0; // Special case: Pipebomb shares with Grenadel launcher. + + return &pstate_pred.clip_fired[index]; +} + +string WP_GetClip() { + if (!WP_Enabled()) + return SBAR.ClipSize; + + Slot slot = pstate_pred.current_slot; + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + + if (!wi->needs_reload || IsSlotNull(slot)) + return ""; + + float capacity = wi->clip_size; + float still_loading = 0; + float fired = *ClipFired(); + + if (WP_IsReloading()) + still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, + pstate_pred.reload_finished); + + float clip = capacity - fired - still_loading; + return sprintf("%d/%d", clip, wi->clip_size); +} + + +void WP_Reload() { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + if (!wi->needs_reload) + return; + + float clip_fired = *ClipFired(); + float ammo_rem = WP_GetAmmo(wi->ammo_type); + + string msg; + if (!FO_CheckCanReload(wi, ammo_rem, clip_fired, msg)) { + if (pengine.is_effectframe) + print(msg); + return; + } + + if (pengine.is_effectframe) + print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); + + pstate_pred.tfstate |= TFSTATE_RELOADING; + float amt = min(ammo_rem, clip_fired); + (*ClipFired()) -= amt; + + pstate_pred.reload_finished = pstate_pred.client_time + + (amt / wi->clip_size) * wi->full_reload_time; +} + +void WP_CheckReloadFinished() { + if (WP_IsReloading() && pstate_pred.client_time >= pstate_pred.reload_finished) { + pstate_pred.tfstate &= ~TFSTATE_RELOADING; + + if (pengine.is_effectframe) + print("Finished reloading\n"); + } +} + + +float WP_ConsumeAmmo(FO_WeapInfo* wi) { + if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) + return TRUE; + + int ammo = WP_GetAmmo(wi->ammo_type); + if (wi->ammo_per_shot > ammo) + return FALSE; + + if (wi->needs_reload) { + if (*ClipFired() >= wi->clip_size) { + WP_Reload(); + return FALSE; + } + } + + pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; + *ClipFired() += wi->ammo_per_shot; + + return TRUE; +} + static void prandom(void() option1, void() option2) { option1(); } -void FO_CSQC_Animate(float fired) { +void WP_AnimateModel(float fired) { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); @@ -42,3 +214,35 @@ void FO_CSQC_Animate(float fired) { player_spannerN(); break; } } + +void WP_DoClientThink(void) { + WP_AnimateModel(FALSE); +} + +void WP_Attack() { + if (pstate_pred.firing) // Already in a continuous attack. + return; + + Slot slot = pstate_pred.current_slot; + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + + if (!WP_ConsumeAmmo(wi)) + return; + + // Must be set prior to animation code, which might internally modify. + pstate_pred.client_thinkindex = 0; + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + + WP_AnimateModel(TRUE); +} + +void WP_Frame() { + WP_CheckReloadFinished(); + WP_Impulse(); + + if ((input_buttons & BUTTON0) && !WP_IsReloading() && + (pstate_pred.client_time >= pstate_pred.attack_finished)) + WP_Attack(); +} + diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 432f2fca..e5ff98fa 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -83,9 +83,9 @@ struct pengine_t { float wp_model_mask; float wp_enabled; -static int WP_Enabled() { return wp_enabled; } +inline int WP_Enabled() { return wp_enabled; } -void FO_WeaponPred_Init(float enabled) { +void FO_WP_Init(float enabled) { wp_enabled = enabled; wp_model_mask = enabled ? MASK_PRED_VIEWMODEL : MASK_VIEWMODEL; } @@ -104,7 +104,7 @@ void FO_WeaponPred_Init(float enabled) { predict_tf_state blank_state; .float last_full_predict_refresh; -void UpdateWeaponPred(entity player) { +void WeaponPred_Update(entity player) { float mask = FOWP_CTIME; if (time - player.last_full_predict_refresh > 1000 * MSEC) { @@ -137,7 +137,7 @@ void UpdateWeaponPred(entity player) { #ifdef SSQC #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) -float WeaponPred_SendEntity(entity to_player, float sendflags) { +float WP_SendEntity(entity to_player, float sendflags) { if (to_player != self.owner) return FALSE; @@ -216,7 +216,7 @@ void WeaponPred_Init(entity player) { pe.classname = "WeaponPred"; pe.dimension_seen = DMN_FLASH | DMN_NOFLASH; pe.pvsflags = PVSF_IGNOREPVS; - pe.SendEntity = WeaponPred_SendEntity; + pe.SendEntity = WP_SendEntity; setorigin(pe, [0, 0, 0]); player.predict_entity = pe; @@ -245,206 +245,8 @@ void WeaponPred_DoServerClientThink() { #endif #ifdef CSQC -static Slot InputToSlot(float input) { - Slot result = FO_SlotByInput(input); - return result; -} - -void WeaponPred_ChangeWeapon(Slot slot) { - pstate_pred.current_slot = slot; - pstate_pred.weaponframe = 0; - - // UpdateViewModel will propagate. -} - -void WeaponPred_Reload(); - -void WeaponPred_Impulse() { - // Note: We might have no impulse, but a queued slot here. - if (pstate_pred.impulse >= 1 && pstate_pred.impulse <= 7) { // Change weapon - Slot slot = InputToSlot(pstate_pred.impulse); - if (!IsSlotNull(slot)) - pstate_pred.queue_slot = slot; - pstate_pred.impulse = 0; - } - - if (pstate_pred.client_time < pstate_pred.attack_finished || - (pstate_pred.tfstate & TFSTATE_RELOADING)) - return; - - if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { - WeaponPred_ChangeWeapon(pstate_pred.queue_slot); - pstate_pred.queue_slot = SlotNull; - } - - if (!pstate_pred.impulse) - return; - - float clear = FALSE; - - if (pstate_pred.impulse == TF_RELOAD) { - WeaponPred_Reload(); - clear = TRUE; - } - - if (clear) - pstate_pred.impulse = 0; -} - -void FO_CSQC_Fire(); - -static float AmmoToStat(float ammo_type) { - switch (ammo_type) { - case AMMO_SHELLS: return STAT_SHELLS; - case AMMO_ROCKETS: return STAT_ROCKETS; - case AMMO_NAILS: return STAT_NAILS; - case AMMO_CELLS: return STAT_CELLS; - } - return STAT_AMMO; -} - -float WP_GetAmmo(float ammo_type) { - if (!WP_Enabled()) - return getstatf(AmmoToStat(ammo_type)); - - if (ammo_type == AMMO_NONE) - return 0; - - float base = getstatf(AmmoToStat(ammo_type)); - base -= pstate_pred.ammo_used[ammo_type]; - return max(0, base); -} - -float WP_CurrentAmmo() { - if (!WP_Enabled()) - return getstatf(STAT_AMMO); - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - return WP_GetAmmo(wi->ammo_type); -} - -static float* ClipFired() { - float index = SlotIndex(pstate_pred.current_slot); - if (pstate_pred.playerclass == PC_DEMOMAN && - index == 1) - index = 0; // Special case: Pipebomb shares with Grenadel launcher. - - return &pstate_pred.clip_fired[index]; -} - -string WP_GetClip() { - if (!WP_Enabled()) - return SBAR.ClipSize; - - Slot slot = pstate_pred.current_slot; - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - - if (!wi->needs_reload || IsSlotNull(slot)) - return ""; - - float capacity = wi->clip_size; - float still_loading = 0; - float fired = *ClipFired(); - - if (pstate_pred.tfstate & TFSTATE_RELOADING) - still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, - pstate_pred.reload_finished); - - float clip = capacity - fired - still_loading; - return sprintf("%d/%d", clip, wi->clip_size); -} - -void WeaponPred_CheckReloadFinished() { - if ((pstate_pred.tfstate & TFSTATE_RELOADING) && - pstate_pred.client_time >= pstate_pred.reload_finished) { - pstate_pred.tfstate &= ~TFSTATE_RELOADING; - - if (pengine.is_effectframe) - print("Finished reloading\n"); - } -} - -void WeaponPred_Reload() { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - if (!wi->needs_reload) - return; - - float clip_fired = *ClipFired(); - float ammo_rem = WP_GetAmmo(wi->ammo_type); - - string msg; - if (!FO_CheckCanReload(wi, ammo_rem, clip_fired, msg)) { - if (pengine.is_effectframe) - print(msg); - return; - } - - if (pengine.is_effectframe) - print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); - - pstate_pred.tfstate |= TFSTATE_RELOADING; - float amt = min(ammo_rem, clip_fired); - (*ClipFired()) -= amt; - - pstate_pred.reload_finished = pstate_pred.client_time + - (amt / wi->clip_size) * wi->full_reload_time; -} - -float WeaponPred_IsReloading() { - return pstate_pred.tfstate & TFSTATE_RELOADING; -} - - -float WeaponPred_ConsumeAmmo(FO_WeapInfo* wi) { - if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) - return TRUE; - - int ammo = WP_GetAmmo(wi->ammo_type); - if (wi->ammo_per_shot > ammo) - return FALSE; - - if (wi->needs_reload) { - if (*ClipFired() >= wi->clip_size) { - WeaponPred_Reload(); - return FALSE; - } - } - - pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; - *ClipFired() += wi->ammo_per_shot; - - return TRUE; -} - -void FO_CSQC_Animate(float fired); - -void WeaponPred_Attack() { - if (pstate_pred.firing) // Already in a continuous attack. - return; - - Slot slot = pstate_pred.current_slot; - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - - if (!WeaponPred_ConsumeAmmo(wi)) - return; - - // Must be set prior to animation code, which might internally modify. - pstate_pred.client_thinkindex = 0; - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - - FO_CSQC_Animate(TRUE); -} - -void WeaponPred_DoClientThink(void) { - FO_CSQC_Animate(FALSE); -} - -void WeaponPred_UpdateViewModel() { +float WP_IsReloading(); +void WP_UpdateViewModel() { float pmodelindex, pframe; FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, @@ -460,7 +262,7 @@ void WeaponPred_UpdateViewModel() { } - if (pstate_pred.tfstate & TFSTATE_RELOADING) { + if (WP_IsReloading()) { self.modelindex = 0; return; } @@ -481,7 +283,10 @@ void WeaponPred_UpdateViewModel() { self.lerpfrac = max(0, self.lerpfrac - frametime * 10); } -float WeaponPred_ClientThink() { +void WP_Frame(); +void WP_DoClientThink(); + +float WP_ClientThink() { pstate_pred = pstate_server; int pframe = servercommandframe + 1; @@ -509,30 +314,23 @@ float WeaponPred_ClientThink() { pstate_pred.client_time = pstate_pred.client_nextthink; pstate_pred.client_nextthink = 0; - WeaponPred_DoClientThink(); + WP_DoClientThink(); pstate_pred.client_time = held_client_time; } - WeaponPred_CheckReloadFinished(); - WeaponPred_Impulse(); - - if ((input_buttons & BUTTON0) && - (pstate_pred.tfstate & TFSTATE_RELOADING == 0) && - (pstate_pred.client_time >= pstate_pred.attack_finished)) - WeaponPred_Attack(); - + WP_Frame(); } - WeaponPred_UpdateViewModel(); + WP_UpdateViewModel(); return PREDRAW_AUTOADD; } void InitPredEnt(entity pe) { - pe.predraw = WeaponPred_ClientThink; + pe.predraw = WP_ClientThink; self.drawmask = MASK_PRED_VIEWMODEL; self.renderflags = RF_VIEWMODEL; - FO_WeaponPred_Init(TRUE); + FO_WP_Init(TRUE); } #endif diff --git a/ssqc/client.qc b/ssqc/client.qc index 50478d8d..a9166b49 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2921,7 +2921,7 @@ void () PlayerPostThink = { self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; if (WeaponPred_Active(self)) - UpdateWeaponPred(self); + WeaponPred_Update(self); if (self.view_ofs == '0 0 0') { return; From 776a384c20474f586c857005a5d252df07a49d96 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 13:46:05 -0700 Subject: [PATCH 1780/2474] Projectile prediction infrastructure Adds basic projection for nails and rockets, does not yet remove client side entities when server side ones show up -- just tries to align expiry with appearance as a first pass. --- csqc/weapon_predict.qc | 212 +++++++++++++++++++++++++++++++++++++++- share/animate.qc | 22 ++++- share/weapon_predict.qc | 15 +++ share/weapons.qc | 8 +- 4 files changed, 251 insertions(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 0eb0db36..73a7e43c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,3 +1,7 @@ +//////////////////////////////////////////////////////////////////////////////// +/// Weapon models +//////////////////////////////////////////////////////////////////////////////// + static Slot InputToSlot(float input) { Slot result = FO_SlotByInput(input); return result; @@ -219,6 +223,8 @@ void WP_DoClientThink(void) { WP_AnimateModel(FALSE); } +void PP_Fire(); + void WP_Attack() { if (pstate_pred.firing) // Already in a continuous attack. return; @@ -232,9 +238,12 @@ void WP_Attack() { // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 0; - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; WP_AnimateModel(TRUE); + PP_Fire(); + + // We set this after so that weapons such as NG can handle correctly. + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; } void WP_Frame() { @@ -246,3 +255,204 @@ void WP_Frame() { WP_Attack(); } + +//////////////////////////////////////////////////////////////////////////////// +/// Projectiles +//////////////////////////////////////////////////////////////////////////////// + +entity predicted_projectiles; +.entity pred_next, pred_prev; + +.vector s_origin, old_origin; + +.float starttime, endtime, p_time; +.float traileffectnum; + +struct trail_table_entry { + string eff_name[2]; + + // Automatically initialized below this line. + float trail[2]; +}; + +trail_table_entry trail_table[] = { + {{"TR_GRENADE", "TR_ROCKET" }}, + {{"TR_ROCKET", "TR_GRENADE" }}, + {{"TR_ALTROCKET" }}, + {{"TR_BLOOD" }}, + {{"TR_SLIGHTBLOOD" }}, + {{"TR_WIZSPIKE" }}, + {{"TR_KNIGHTSPIKE" }}, + {{"TR_VORESPIKE" }}, + {{"TE_RAILTRAIL"}}, +}; + +float nail_trail; + +void PP_Init() { + for (float i = 0; i < trail_table.length; i++) { + for (float j = 0; j < 2; j++) { + trail_table_entry* entry = &trail_table[i]; + + string name = entry->eff_name[j]; + if (name == "") + name = entry->eff_name[0]; + + entry->trail[j] = particleeffectnum(name); + } + } + + nail_trail = particleeffectnum("tr_spike"); +} + +void PP_Cleanup(entity proj) { + if (predicted_projectiles == proj) + predicted_projectiles = proj.pred_next; + + if (proj.pred_prev) + proj.pred_prev.pred_next = proj.pred_next; + + if (proj.pred_next) + proj.pred_next.pred_prev = proj.pred_prev; + + remove(proj); +} + + +DEFCVAR_FLOAT(r_rocketlight, 1); +DEFCVAR_FLOAT(r_rocketlight, 1); +DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); + +float PP_PredrawActive() { + float delta = time - self.starttime; + + if (delta < 0) + return PREDRAW_NEXT; // Forward projection is bounded. + + self.origin = self.s_origin + self.velocity * delta; + setorigin(self, self.origin); + + // we need to space out the particles incase we're running at very high fps + if (time > self.p_time) { + if (self.p_time) { + traceline(self.oldorigin, self.origin, MOVE_NOMONSTERS, self); + if (trace_fraction < 1) { + self.oldorigin = trace_endpos; + return PREDRAW_NEXT; + } + + if (self.traileffectnum) + trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); + } + + self.p_time = time + 0.013; + self.oldorigin = self.origin; + } + +#if 0 // TODO + if (self.modelflags & MF_ROCKET && CVARF(r_rocketlight)) { + dynamiclight_add(self.origin, 200, CVARS(r_rocketlight_color), 0); + } +#endif + + return PREDRAW_AUTOADD; +} + +float PP_Predraw() { + if (time > self.endtime + 0.05) { + PP_Cleanup(self); + return PREDRAW_NEXT; + } + + return PP_PredrawActive(); +} + +DEFCVAR_FLOAT(r_rockettrail, 1); +DEFCVAR_FLOAT(r_grenadetrail, 1); + +int PP_FindTrail(int is_grenade) +{ + float idx = (is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail)) - 1; + + if (idx >= 0 && idx < trail_table.length) + return trail_table[idx].trail[is_grenade]; + + return 0; +} + +entity PP_CreateProjectile(fo_projectile* desc, vector offset) { + entity proj = spawn(); + + // TODO: Communicate with server around this. + // Note: We use true time here since the created projectiles exist outside of + // our prediction. + float start_offset = max(0, pstate_pred.client_ping - 0.1); + proj.starttime = time + start_offset; + proj.endtime = time + pstate_pred.client_ping; + + proj.predraw = PP_Predraw; + proj.drawmask = MASK_ENGINE; + + proj.p_time = 0; + proj.s_origin = pmove_org + offset + v_forward * 8; + proj.s_origin[2] += 16; + proj.velocity = v_forward * desc->speed; + + proj.old_origin = proj.s_origin + 0.013 * proj.velocity; + proj.origin = proj.old_origin; + + proj.angles = input_angles; proj.angles[0] *= -1; + + setmodel(proj, desc->model); + + proj.pred_next = predicted_projectiles; + if (predicted_projectiles) + predicted_projectiles.pred_prev = proj; + predicted_projectiles = proj; + + return proj; +} + +void PP_FireRocket(float is_soldier) { + fo_projectile* desc = is_soldier ? &fpp_rocket : &fpp_incendiary; + + entity proj = PP_CreateProjectile(desc, [0, 0, 0]); + if (is_soldier) + proj.traileffectnum = PP_FindTrail(FALSE); +} + +void PP_FireNG(float off) { + fo_projectile* desc; + vector offset = [0, 0, 0]; + + if (off == 0) { + desc = &fpp_super_nail; + } else { + desc = &fpp_nail; + offset = off * v_right; + } + + entity proj = PP_CreateProjectile(desc, offset); + proj.traileffectnum = nail_trail; +} + +void PP_Fire() { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + if (wi->predict_type != PRED_PROJ) + return; + + if (!pengine.is_effectframe) + return; + + switch (wi->weapon) { + case WEAP_NAILGUN: + case WEAP_SUPER_NAILGUN: + break; // Handled in animation. + + case WEAP_ROCKET_LAUNCHER: PP_FireRocket(TRUE); break; + case WEAP_INCENDIARY: PP_FireRocket(FALSE); break; + } +} + diff --git a/share/animate.qc b/share/animate.qc index a11e14c0..0499fd1e 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -107,7 +107,7 @@ void nail_extra() { float idx = (self.client_thinkindex - 1) % 2; if (idx == 0 || !old_ng_rof) { SuperDamageSound(); - W_FireSpikes(self.nailpos ? 4 : -4); + W_FireSpikes(idx ? 4 : -4); self.nailpos = 1 - self.nailpos; } } @@ -277,8 +277,28 @@ void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { } static void axe_extra() {} + +void PP_FireNG(float off); + static void nail_extra() { pstate_pred.firing = TRUE; + + if (pstate_pred.client_time < pstate_pred.attack_finished) + return; + + if (!pengine.is_effectframe) + return; + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + float idx = (*thinkindex() - 1) % 2; + if (wi->weapon == WEAP_NAILGUN) + PP_FireNG(idx ? 4 : -4); + else + PP_FireNG(0); + } static void asscan_up_extra() {} static void asscan_fire_extra() {} diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index e5ff98fa..688e2600 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -22,6 +22,7 @@ struct predict_tf_state { float tfstate; float client_time; + float client_ping; float weaponframe; float attack_finished; @@ -37,6 +38,16 @@ struct predict_tf_state { float firing; }; +struct fo_projectile { + float speed; + string model; +}; + +fo_projectile fpp_rocket = { PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl" }; +fo_projectile fpp_incendiary = { 800, "progs/lavaball.mdl" }; +fo_projectile fpp_nail = { 1000, "progs/spike.mdl" }; +fo_projectile fpp_super_nail = { 1000, "progs/s_spike.mdl" }; + #ifdef SSQC float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); @@ -113,6 +124,7 @@ void WeaponPred_Update(entity player) { } player.predict_state.client_time = player.client_time; + player.predict_state.client_ping = player.client_ping; M1(FOWP_CLASS, playerclass); M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); @@ -154,6 +166,7 @@ void EntUpdate_WeaponPred(float isnew) { #endif if (sendflags & FOWP_CTIME) { COMM(Float, client_time); + COMM(Float, client_ping); } if (sendflags & FOWP_CLASS) { @@ -325,12 +338,14 @@ float WP_ClientThink() { return PREDRAW_AUTOADD; } +void PP_Init(); void InitPredEnt(entity pe) { pe.predraw = WP_ClientThink; self.drawmask = MASK_PRED_VIEWMODEL; self.renderflags = RF_VIEWMODEL; + PP_Init(); FO_WP_Init(TRUE); } #endif diff --git a/share/weapons.qc b/share/weapons.qc index 7b503580..9bf9915c 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -115,13 +115,13 @@ FO_WeapInfo weapon_info[] = { { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0 }, { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, - { WEAP_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.2, 0 }, - { WEAP_SUPER_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 2, 0.2, 0 }, + { WEAP_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.2, 0 }, + { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 2, 0.2, 0 }, { WEAP_GRENADE_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 6, 1, 0.6, 4 }, { WEAP_PIPE_LAUNCHER, PRED_MODEL, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, PRED_MODEL, AMMO_CELLS, 0, 1, 0.15, 0 }, - { WEAP_ROCKET_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 4, 1, 0.8, 5 }, - { WEAP_INCENDIARY, PRED_MODEL, AMMO_ROCKETS, 0, 3, -9, 0 }, + { WEAP_ROCKET_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 4, 1, 0.8, 5 }, + { WEAP_INCENDIARY, PRED_PROJ, AMMO_ROCKETS, 0, 3, -9, 0 }, { WEAP_ASSAULT_CANNON, NO_PREDICT, AMMO_SHELLS, -9, 1, 0.2, 4 }, { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, From 2fce7f0736f81865f4e7f205b14ee6dec2e36c8d Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 16:51:01 -0700 Subject: [PATCH 1781/2474] Move death animations to client_time This turns out to be important since Player_Dead is set in the last frame. Also hide client-side weapons/block input when dead --- csqc/weapon_predict.qc | 5 + share/animate.qc | 4 +- ssqc/player.qc | 207 +++++------------------------------------ 3 files changed, 30 insertions(+), 186 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 73a7e43c..3943b662 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -247,6 +247,11 @@ void WP_Attack() { } void WP_Frame() { + if (getstatf(STAT_HEALTH) < 0) { + pstate_pred.current_slot = SlotNull; + return; + } + WP_CheckReloadFinished(); WP_Impulse(); diff --git a/share/animate.qc b/share/animate.qc index 0499fd1e..45e7e26c 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -1,6 +1,6 @@ struct anim_t { int num_frames, num_wf; - int frames[9]; + int frames[20]; int weaponframes[9]; int muzzle_flash; // muzzle flash on weaponframe index 0 int loop; @@ -32,7 +32,7 @@ void player_stand1(); void player_asscan_fire(); void player_asscan_down1(); -static inline void *thinkindex() { return &self.client_thinkindex; } +inline void *thinkindex() { return &self.client_thinkindex; } void FO_SetClientThink(void() func, float offset, float override = TRUE) { self.think = think_nop; diff --git a/ssqc/player.qc b/ssqc/player.qc index 0e74bd42..3cde777c 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -322,6 +322,7 @@ void () DeathSound = { }; void () PlayerDead = { + self.client_nextthink = -1; self.nextthink = -1; self.deadflag = 2; }; @@ -510,197 +511,35 @@ void () set_suicide_frame = { setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); }; -void () player_diea1 =[50, player_diea2] { -}; - -void () player_diea2 =[51, player_diea3] { -}; - -void () player_diea3 =[52, player_diea4] { -}; - -void () player_diea4 =[53, player_diea5] { -}; - -void () player_diea5 =[54, player_diea6] { -}; - -void () player_diea6 =[55, player_diea7] { -}; - -void () player_diea7 =[56, player_diea8] { -}; - -void () player_diea8 =[57, player_diea9] { -}; - -void () player_diea9 =[58, player_diea10] { -}; - -void () player_diea10 =[59, player_diea11] { -}; - -void () player_diea11 =[60, player_diea11] { - PlayerDead(); -}; - -void () player_dieb1 =[61, player_dieb2] { -}; - -void () player_dieb2 =[62, player_dieb3] { -}; - -void () player_dieb3 =[63, player_dieb4] { -}; - -void () player_dieb4 =[64, player_dieb5] { -}; - -void () player_dieb5 =[65, player_dieb6] { -}; - -void () player_dieb6 =[66, player_dieb7] { -}; - -void () player_dieb7 =[67, player_dieb8] { -}; - -void () player_dieb8 =[68, player_dieb9] { -}; - -void () player_dieb9 =[69, player_dieb9] { - PlayerDead(); -}; - -void () player_diec1 =[70, player_diec2] { -}; - -void () player_diec2 =[71, player_diec3] { -}; - -void () player_diec3 =[72, player_diec4] { -}; - -void () player_diec4 =[73, player_diec5] { -}; - -void () player_diec5 =[74, player_diec6] { -}; - -void () player_diec6 =[75, player_diec7] { -}; - -void () player_diec7 =[76, player_diec8] { -}; - -void () player_diec8 =[77, player_diec9] { -}; - -void () player_diec9 =[78, player_diec10] { -}; - -void () player_diec10 =[79, player_diec11] { -}; - -void () player_diec11 =[80, player_diec12] { -}; - -void () player_diec12 =[81, player_diec13] { -}; - -void () player_diec13 =[82, player_diec14] { -}; - -void () player_diec14 =[83, player_diec15] { -}; - -void () player_diec15 =[84, player_diec15] { - PlayerDead(); -}; - -void () player_died1 =[85, player_died2] { -}; - -void () player_died2 =[86, player_died3] { -}; - -void () player_died3 =[87, player_died4] { -}; - -void () player_died4 =[88, player_died5] { -}; - -void () player_died5 =[89, player_died6] { -}; - -void () player_died6 =[90, player_died7] { -}; - -void () player_died7 =[91, player_died8] { -}; - -void () player_died8 =[92, player_died9] { -}; - -void () player_died9 =[93, player_died9] { - PlayerDead(); -}; -void () player_diee1 =[94, player_diee2] { -}; - -void () player_diee2 =[95, player_diee3] { -}; +void player_die_extra() { + if (self.client_thinkindex >= 9) + PlayerDead(); +} -void () player_diee3 =[96, player_diee4] { -}; +anim_t anim_player_diea1 = { 11, 1, {50}, {0}, FALSE, FALSE }; +void player_dieaN() { client_anim_frames(player_dieaN, player_die_extra, &anim_player_diea1); } +void player_diea1() { *thinkindex() = 0; player_dieaN(); } -void () player_diee4 =[97, player_diee5] { -}; +anim_t anim_player_dieb1 = { 9, 1, {61}, {0}, FALSE, FALSE }; +void player_diebN() { client_anim_frames(player_diebN, player_die_extra, &anim_player_dieb1); } +void player_dieb1() { *thinkindex() = 0; player_diebN(); } -void () player_diee5 =[98, player_diee6] { -}; +anim_t anim_player_diec1 = { 15, 1, {70}, {0}, FALSE, FALSE }; +void player_diecN() { client_anim_frames(player_diecN, player_die_extra, &anim_player_diec1); } +void player_diec1() { *thinkindex() = 0; player_diecN(); } -void () player_diee6 =[99, player_diee7] { -}; +anim_t anim_player_died1 = { 9, 1, {85}, {0}, FALSE, FALSE }; +void player_diedN() { client_anim_frames(player_diedN, player_die_extra, &anim_player_died1); } +void player_died1() { *thinkindex() = 0; player_diedN(); } -void () player_diee7 =[100, player_diee8] { -}; +anim_t anim_player_diee1 = { 9, 1, {94}, {0}, FALSE, FALSE }; +void player_dieeN() { client_anim_frames(player_dieeN, player_die_extra, &anim_player_diee1); } +void player_diee1() { *thinkindex() = 0; player_dieeN(); } -void () player_diee8 =[101, player_diee9] { -}; - -void () player_diee9 =[102, player_diee9] { - PlayerDead(); -}; - -void () player_die_ax1 =[41, player_die_ax2] { -}; - -void () player_die_ax2 =[42, player_die_ax3] { -}; - -void () player_die_ax3 =[43, player_die_ax4] { -}; - -void () player_die_ax4 =[44, player_die_ax5] { -}; - -void () player_die_ax5 =[45, player_die_ax6] { -}; - -void () player_die_ax6 =[46, player_die_ax7] { -}; - -void () player_die_ax7 =[47, player_die_ax8] { -}; - -void () player_die_ax8 =[48, player_die_ax9] { -}; - -void () player_die_ax9 =[49, player_die_ax9] { - PlayerDead(); -}; +anim_t anim_player_die_ax = { 9, 1, {41}, {0}, FALSE, FALSE }; +void player_die_axN() { client_anim_frames(player_die_axN, player_die_extra, &anim_player_die_ax); } +void player_die_ax1() { *thinkindex() = 0; player_die_axN(); } void () Headless_Think = { self.frame = self.frame + 1; From 4183d6a2d635424ec66830e044a2782b1777e38c Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 16:51:01 -0700 Subject: [PATCH 1782/2474] Move death animations to client_time This turns out to be important since Player_Dead is set in the last frame. Also hide client-side weapons/block input when dead --- csqc/weapon_predict.qc | 6 +- share/animate.qc | 4 +- ssqc/player.qc | 207 +++++------------------------------------ 3 files changed, 30 insertions(+), 187 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 73a7e43c..b4e53139 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -247,6 +247,11 @@ void WP_Attack() { } void WP_Frame() { + if (getstatf(STAT_HEALTH) < 0) { + pstate_pred.current_slot = SlotNull; + return; + } + WP_CheckReloadFinished(); WP_Impulse(); @@ -455,4 +460,3 @@ void PP_Fire() { case WEAP_INCENDIARY: PP_FireRocket(FALSE); break; } } - diff --git a/share/animate.qc b/share/animate.qc index 0499fd1e..45e7e26c 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -1,6 +1,6 @@ struct anim_t { int num_frames, num_wf; - int frames[9]; + int frames[20]; int weaponframes[9]; int muzzle_flash; // muzzle flash on weaponframe index 0 int loop; @@ -32,7 +32,7 @@ void player_stand1(); void player_asscan_fire(); void player_asscan_down1(); -static inline void *thinkindex() { return &self.client_thinkindex; } +inline void *thinkindex() { return &self.client_thinkindex; } void FO_SetClientThink(void() func, float offset, float override = TRUE) { self.think = think_nop; diff --git a/ssqc/player.qc b/ssqc/player.qc index 0e74bd42..3cde777c 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -322,6 +322,7 @@ void () DeathSound = { }; void () PlayerDead = { + self.client_nextthink = -1; self.nextthink = -1; self.deadflag = 2; }; @@ -510,197 +511,35 @@ void () set_suicide_frame = { setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); }; -void () player_diea1 =[50, player_diea2] { -}; - -void () player_diea2 =[51, player_diea3] { -}; - -void () player_diea3 =[52, player_diea4] { -}; - -void () player_diea4 =[53, player_diea5] { -}; - -void () player_diea5 =[54, player_diea6] { -}; - -void () player_diea6 =[55, player_diea7] { -}; - -void () player_diea7 =[56, player_diea8] { -}; - -void () player_diea8 =[57, player_diea9] { -}; - -void () player_diea9 =[58, player_diea10] { -}; - -void () player_diea10 =[59, player_diea11] { -}; - -void () player_diea11 =[60, player_diea11] { - PlayerDead(); -}; - -void () player_dieb1 =[61, player_dieb2] { -}; - -void () player_dieb2 =[62, player_dieb3] { -}; - -void () player_dieb3 =[63, player_dieb4] { -}; - -void () player_dieb4 =[64, player_dieb5] { -}; - -void () player_dieb5 =[65, player_dieb6] { -}; - -void () player_dieb6 =[66, player_dieb7] { -}; - -void () player_dieb7 =[67, player_dieb8] { -}; - -void () player_dieb8 =[68, player_dieb9] { -}; - -void () player_dieb9 =[69, player_dieb9] { - PlayerDead(); -}; - -void () player_diec1 =[70, player_diec2] { -}; - -void () player_diec2 =[71, player_diec3] { -}; - -void () player_diec3 =[72, player_diec4] { -}; - -void () player_diec4 =[73, player_diec5] { -}; - -void () player_diec5 =[74, player_diec6] { -}; - -void () player_diec6 =[75, player_diec7] { -}; - -void () player_diec7 =[76, player_diec8] { -}; - -void () player_diec8 =[77, player_diec9] { -}; - -void () player_diec9 =[78, player_diec10] { -}; - -void () player_diec10 =[79, player_diec11] { -}; - -void () player_diec11 =[80, player_diec12] { -}; - -void () player_diec12 =[81, player_diec13] { -}; - -void () player_diec13 =[82, player_diec14] { -}; - -void () player_diec14 =[83, player_diec15] { -}; - -void () player_diec15 =[84, player_diec15] { - PlayerDead(); -}; - -void () player_died1 =[85, player_died2] { -}; - -void () player_died2 =[86, player_died3] { -}; - -void () player_died3 =[87, player_died4] { -}; - -void () player_died4 =[88, player_died5] { -}; - -void () player_died5 =[89, player_died6] { -}; - -void () player_died6 =[90, player_died7] { -}; - -void () player_died7 =[91, player_died8] { -}; - -void () player_died8 =[92, player_died9] { -}; - -void () player_died9 =[93, player_died9] { - PlayerDead(); -}; -void () player_diee1 =[94, player_diee2] { -}; - -void () player_diee2 =[95, player_diee3] { -}; +void player_die_extra() { + if (self.client_thinkindex >= 9) + PlayerDead(); +} -void () player_diee3 =[96, player_diee4] { -}; +anim_t anim_player_diea1 = { 11, 1, {50}, {0}, FALSE, FALSE }; +void player_dieaN() { client_anim_frames(player_dieaN, player_die_extra, &anim_player_diea1); } +void player_diea1() { *thinkindex() = 0; player_dieaN(); } -void () player_diee4 =[97, player_diee5] { -}; +anim_t anim_player_dieb1 = { 9, 1, {61}, {0}, FALSE, FALSE }; +void player_diebN() { client_anim_frames(player_diebN, player_die_extra, &anim_player_dieb1); } +void player_dieb1() { *thinkindex() = 0; player_diebN(); } -void () player_diee5 =[98, player_diee6] { -}; +anim_t anim_player_diec1 = { 15, 1, {70}, {0}, FALSE, FALSE }; +void player_diecN() { client_anim_frames(player_diecN, player_die_extra, &anim_player_diec1); } +void player_diec1() { *thinkindex() = 0; player_diecN(); } -void () player_diee6 =[99, player_diee7] { -}; +anim_t anim_player_died1 = { 9, 1, {85}, {0}, FALSE, FALSE }; +void player_diedN() { client_anim_frames(player_diedN, player_die_extra, &anim_player_died1); } +void player_died1() { *thinkindex() = 0; player_diedN(); } -void () player_diee7 =[100, player_diee8] { -}; +anim_t anim_player_diee1 = { 9, 1, {94}, {0}, FALSE, FALSE }; +void player_dieeN() { client_anim_frames(player_dieeN, player_die_extra, &anim_player_diee1); } +void player_diee1() { *thinkindex() = 0; player_dieeN(); } -void () player_diee8 =[101, player_diee9] { -}; - -void () player_diee9 =[102, player_diee9] { - PlayerDead(); -}; - -void () player_die_ax1 =[41, player_die_ax2] { -}; - -void () player_die_ax2 =[42, player_die_ax3] { -}; - -void () player_die_ax3 =[43, player_die_ax4] { -}; - -void () player_die_ax4 =[44, player_die_ax5] { -}; - -void () player_die_ax5 =[45, player_die_ax6] { -}; - -void () player_die_ax6 =[46, player_die_ax7] { -}; - -void () player_die_ax7 =[47, player_die_ax8] { -}; - -void () player_die_ax8 =[48, player_die_ax9] { -}; - -void () player_die_ax9 =[49, player_die_ax9] { - PlayerDead(); -}; +anim_t anim_player_die_ax = { 9, 1, {41}, {0}, FALSE, FALSE }; +void player_die_axN() { client_anim_frames(player_die_axN, player_die_extra, &anim_player_die_ax); } +void player_die_ax1() { *thinkindex() = 0; player_die_axN(); } void () Headless_Think = { self.frame = self.frame + 1; From f7fdaee6ad6de0cf81119dd939c1144a69695c9b Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 17:14:49 -0700 Subject: [PATCH 1783/2474] Fix merge nits --- csqc/csprogs.src | 3 +- csqc/weapon_predict.qc | 2 +- share/fo_animate.qc | 345 -------------------- share/fo_weapon_predict.qc | 538 ------------------------------- share/fo_weapons.qc | 638 ------------------------------------- 5 files changed, 2 insertions(+), 1524 deletions(-) delete mode 100644 share/fo_animate.qc delete mode 100644 share/fo_weapon_predict.qc delete mode 100644 share/fo_weapons.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index a58e69a4..f30a5822 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -19,12 +19,11 @@ weapon_predict.qc sui_sys.qc vote.qc status.qc +settings.qc menu.qc -weapon_predict.qc main.qc events.qc hud_helpers.qc hud.qc -settings.qc input.qc #endlist diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 4ef9f5a7..b4e53139 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -459,4 +459,4 @@ void PP_Fire() { case WEAP_ROCKET_LAUNCHER: PP_FireRocket(TRUE); break; case WEAP_INCENDIARY: PP_FireRocket(FALSE); break; } -} \ No newline at end of file +} diff --git a/share/fo_animate.qc b/share/fo_animate.qc deleted file mode 100644 index a11e14c0..00000000 --- a/share/fo_animate.qc +++ /dev/null @@ -1,345 +0,0 @@ -struct anim_t { - int num_frames, num_wf; - int frames[9]; - int weaponframes[9]; - int muzzle_flash; // muzzle flash on weaponframe index 0 - int loop; -}; - -static void think_nop() {} - -#ifdef SSQC - -void nail_extra(); -void asscan_up_extra(); -void asscan_fire_extra(); -void asscan_down_extra(); -void W_PrintWeaponMessage(); -void W_ChangeToBestWeapon(); -void W_FireSpikes(float ox); -void W_FireAssaultCannon(); -int W_FireAxe(); -int W_FireKnife(); -int W_FireMedikit(); -int W_FireSpanner(); - -void SuperDamageSound(); -void FO_Sound(entity e, float chan, string samp, float vol, float atten); -void TeamFortress_SetSpeed(entity p); - -void player_run(); -void player_stand1(); -void player_asscan_fire(); -void player_asscan_down1(); - -static inline void *thinkindex() { return &self.client_thinkindex; } - -void FO_SetClientThink(void() func, float offset, float override = TRUE) { - self.think = think_nop; - self.nextthink = 0; - - self.client_think = func; - self.client_nextthink = self.client_time + offset; -} - -void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - int tidx = self.client_thinkindex++; - - int wfi = tidx % anim->num_wf; - self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; - if (wfi == 0 && anim->muzzle_flash) - muzzleflash(); - - int fi = tidx % anim->num_frames; - self.frame = anim->frames[fi] ?: anim->frames[0] + fi; - - if (fi == anim->num_frames - 1 && !anim->loop) - FO_SetClientThink(player_run, 0.1); - else - FO_SetClientThink(parent_thunk, 0.1); - - if (extra != think_nop) - extra(); -} - -static void axe_extra() { - float weapon = FO_CurrentWeapon(); - float* flag; - int() w_attack; - - // We'd use default below but compiler can't recognize that init is - // guaranteed then. - flag = &superaxe; - w_attack = W_FireAxe; - - switch (weapon) { - case WEAP_MEDIKIT: - flag = &supermedikit; - w_attack = W_FireMedikit; - break; - case WEAP_SPANNER: - flag = &superspanner; - w_attack = W_FireSpanner; - break; - case WEAP_KNIFE: - flag = &superknife; - w_attack = W_FireKnife; - break; - } - - if (self.weaponframe == 1) - self.hit_in_current_animation = FALSE; - - if ((*flag && !self.hit_in_current_animation) || - (!*flag && self.weaponframe == 3)) - self.hit_in_current_animation = w_attack(); - - if (weapon == WEAP_KNIFE && superknife && superknife_multihit) - self.hit_in_current_animation = FALSE; -} - -void nail_extra() { - if (!self.button0 || intermission_running) { - player_run(); - return; - } - - float idx = (self.client_thinkindex - 1) % 2; - if (idx == 0 || !old_ng_rof) { - SuperDamageSound(); - W_FireSpikes(self.nailpos ? 4 : -4); - self.nailpos = 1 - self.nailpos; - } -} - -static float CheckNeedAssaultCannonDown() { - FO_WeapState ws; - FO_FillWeapState(self, MakeSlot(1), &ws); - - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || - ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { - self.tfstate |= TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - player_asscan_down1(); - return TRUE; - } - return FALSE; -} - -void asscan_up_extra() { - if (CheckNeedAssaultCannonDown()) - return; - - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - self.fire_held_down = 1; - if (self.client_thinkindex == 1) // Already incremented - FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - SuperDamageSound(); - - if (self.client_thinkindex == 6) // 600ms spin up - player_asscan_fire(); - else - Attack_Finished(wi->attack_time); -} - -void asscan_fire_extra() { - if (CheckNeedAssaultCannonDown()) - return; - - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) - && !(self.tfstate & TFSTATE_LOCK)) { - - if (self.client_thinkindex % 2 == 0) { - muzzleflash(); - FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - } - - SuperDamageSound(); - - self.tfstate |= TFSTATE_AIMING; - if (!cannon_move) - self.tfstate |= TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - - // Halve firing speed when moving too fast. - if (vlen(self.velocity) < 30 || self.count % 2 == 0) - W_FireAssaultCannon(); - } else { - FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); - self.weaponframe = self.weaponframe == 2 ? 0 : 2; - } - Attack_Finished(wi->attack_time); -} - -void asscan_down_extra() { - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (self.client_thinkindex == 1) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); - - if (self.client_thinkindex >= 15) { // 1.5s down - self.fire_held_down = 0; - self.tfstate &= ~TFSTATE_AIMING; - if (!cannon_move) - self.tfstate &= ~TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - - player_run(); - if (self.ammo_cells < 7 || !FO_CheckForReload()) { - W_PrintWeaponMessage(); - W_ChangeToBestWeapon(); - } - } - Attack_Finished(wi->attack_time); -}; - -void player_run() { - FO_SetClientThink(player_run, 0.1); - self.client_thinkindex = 0; - - self.frame = 6; - self.weaponframe = 0; - - if (!self.velocity_x && !self.velocity_y) { - self.walkframe = 0; - player_stand1(); - return; - } - - // Note: Reverses animation when walking backwards - self.walkframe = (self.walkframe + (self.movement_x < 0 ? -1 : 1) + 6) % 6; - self.frame = (IsSlotMelee(self.current_slot) ? 0 : 6) + self.walkframe; -}; - -void player_stand1() { - FO_SetClientThink(player_stand1, 0.1); - self.client_thinkindex = 0; - - self.frame = 17; - self.weaponframe = 0; - - if (self.velocity_x || self.velocity_y) { - self.walkframe = 0; - player_run(); - return; - } - - if (IsSlotMelee(self.current_slot)) { - if (self.walkframe >= 12) - self.walkframe = 0; - self.frame = 17 + self.walkframe; - } else { - if (self.walkframe >= 5) - self.walkframe = 0; - self.frame = 12 + self.walkframe; - } - self.walkframe++; -}; - -#else /* CSQC */ -static inline void *thinkindex() { return &pstate_pred.client_thinkindex; } - -void FO_SetClientThink(void() func, float offset, float override = TRUE) { - pstate_pred.client_nextthink = pstate_pred.client_time + offset; -} - -void player_run() { - pstate_pred.firing = FALSE; - pstate_pred.client_nextthink = 0; - pstate_pred.client_thinkindex = 0; - pstate_pred.weaponframe = 0; -} - -void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - float tidx = (*thinkindex())++; - - float fi = tidx % anim->num_frames; - float wfi = tidx % anim->num_wf; - - float wf = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; - pstate_pred.weaponframe = wf; - - float loop = anim->loop && (input_buttons & BUTTON0); - - if (tidx > anim->num_frames - 1 && !loop) { - // Special case for CSQC since we could predict through the wrap. - player_run(); - } else if (fi == anim->num_frames - 1 && !loop) { - FO_SetClientThink(player_run, 0.1); - } else - FO_SetClientThink(parent_thunk, 0.1); - - if (extra != think_nop) - extra(); -} - -static void axe_extra() {} -static void nail_extra() { - pstate_pred.firing = TRUE; -} -static void asscan_up_extra() {} -static void asscan_fire_extra() {} -static void asscan_down_extra() {} - -#endif - -anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; -void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } -void player_rocket1() { *thinkindex() = 0; player_rocketN(); } - -anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; -void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } -void player_shot1() { *thinkindex() = 0; player_shotN(); } - - -anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; -void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } -void player_autorifle1() { *thinkindex() = 0; player_autorifleN(); } - -anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; -void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } -void player_axe1() { *thinkindex() = 0; player_axeN(); } - -anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; -void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } -void player_axeb1() { *thinkindex() = 0; player_axebN(); } - -void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } -void player_spanner1() { *thinkindex() = 0; player_spannerN(); } - -void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } -void player_knife1() { *thinkindex() = 0; player_knifeN(); } - -void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } -void player_knifeb1() { *thinkindex() = 0; player_knifebN(); } - -void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } -void player_medikit1() { *thinkindex() = 0; player_medikitN(); } - -void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } -void player_medikitb1() { *thinkindex() = 0; player_medikitbN(); } - -anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; -void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } -void player_nail1() { *thinkindex() = 0; player_nailN(); } - -anim_t anim_flamethrower = { 2, 6, {103, 104}, {1}, FALSE, TRUE }; -void player_flamethrowerN() { - client_anim_frames(player_flamethrowerN, think_nop, &anim_flamethrower); -} -void player_flamethrower1() { *thinkindex() = 0; player_flamethrowerN(); } - -anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; -anim_t anim_asscan_fire = { 1, 2, {103}, {2, 4}, FALSE, TRUE}; -anim_t anim_asscan_down = { 1, 6, {103}, {1, 1, 2, 2, 3, 3}, FALSE, TRUE}; - -void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } -void player_asscan_up1() { *thinkindex() = 0; player_asscan_upN(); } - -void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } -void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } -void player_asscan_down1() { *thinkindex() = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } - diff --git a/share/fo_weapon_predict.qc b/share/fo_weapon_predict.qc deleted file mode 100644 index 432f2fca..00000000 --- a/share/fo_weapon_predict.qc +++ /dev/null @@ -1,538 +0,0 @@ -#define ENT_WEAPONPRED 100 -string wp_version = "v0"; - -enumflags { - FOWP_CTIME, - FOWP_IMPULSE, - FOWP_TFSTATE, - FOWP_CLIP, - FOWP_THINK, - FOWP_TFSTATE, - FOWP_WF, - FOWP_CLASS, - FOWP_RELOAD, -}; -#define FOWP_ALL 0xFFFF - -struct predict_tf_state { - int playerclass; - int impulse; - Slot current_slot, queue_slot; - - float tfstate; - - float client_time; - float weaponframe; - - float attack_finished; - float client_nextthink; - float client_thinkindex; - - float reload_finished; - float clip_fired[4]; - - - // Used for prediction, not actually communicated. Reset each frame. - float ammo_used[AMMO_NUM_TYPES]; - float firing; -}; - -#ifdef SSQC - -float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); -float CF_GetSetting(string ps_short, string ps_setting, string ps_default); - -static float GlobalEnable() { - return CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); -} - -static float GlobalDisable() { - return CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); -} - -static float ClientEnable() { - // client_ping is not yet initialized. - float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; - - if (GlobalDisable() || ping < 40 * MSEC) - return FALSE; - - if (GlobalEnable()) - return TRUE; - - return FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "off"); -} - -.float weapon_pred_enabled; -.predict_tf_state predict_state; -.entity predict_entity; - -.float client_nextthink; -.float client_thinkindex; -#else -predict_tf_state pstate_pred, pstate_server; - -struct pengine_t { - float is_effectframe; - float last_effectframe; -} pengine; - -#define MASK_PRED_VIEWMODEL 256 -// Must include MASK_PRED_VIEWMODEL or we lose updates. -// We only add/remove MASK_VIEWMODEL. -float wp_model_mask; -float wp_enabled; - -static int WP_Enabled() { return wp_enabled; } - -void FO_WeaponPred_Init(float enabled) { - wp_enabled = enabled; - wp_model_mask = enabled ? MASK_PRED_VIEWMODEL : MASK_VIEWMODEL; -} -#endif - -#ifdef SSQC -#define OP1(_op, _f1) (player.predict_state.##_f1 _op player.##_f1) -#define OP2(_op, _j, _f1, _f2) OP1(_op, _f2) _j OP1(_op, _f1) -#define OP3(_op, _j, _f1, _f2, _f3) OP2(_op, _j, _f2, _f3) _j OP1(_op, _f1) -#define OP4(_op, _j, _f1, _f2, _f3, _f4) OP3(_op, _j, _f2, _f3, _f4) _j OP1(_op, _f1) -#define M1(_bit, _f1) if (OP1(!=, _f1)) { mask |= _bit; OP1(=, _f1); } -#define M2(_bit, _f1, _f2) if (OP2(!=, ||, _f1, _f2)) { mask |= _bit; OP2(=, ;, _f1, _f2); } -#define M3(_bit, _f1, _f2, _f3) if (OP3(!=, ||, _f1, _f2, _f3)) { mask |= _bit; OP3(=, ;, _f1, _f2, _f3); } -#define M4(_bit, _f1, _f2, _f3, _f4) if (OP4(!=, ||, _f1, _f2, _f3, _f4)) { mask |= _bit; OP4(=, ;, _f1, _f2, _f3, _f4); } - -predict_tf_state blank_state; -.float last_full_predict_refresh; - -void UpdateWeaponPred(entity player) { - float mask = FOWP_CTIME; - - if (time - player.last_full_predict_refresh > 1000 * MSEC) { - player.predict_state = blank_state; - player.last_full_predict_refresh = time; - } - - player.predict_state.client_time = player.client_time; - - M1(FOWP_CLASS, playerclass); - M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); - M1(FOWP_TFSTATE, tfstate); - M2(FOWP_WF, attack_finished, weaponframe); - M2(FOWP_THINK, client_nextthink, client_thinkindex); - M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) - M1(FOWP_RELOAD, reload_finished) - - player.predict_entity.SendFlags = mask; -} - -#undef OP1 -#undef OP2 -#undef OP3 -#undef OP4 -#undef M1 -#undef M2 -#undef M3 -#undef M4 -#endif - -#ifdef SSQC -#define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) -float WeaponPred_SendEntity(entity to_player, float sendflags) { - if (to_player != self.owner) - return FALSE; - - WriteByte(MSG_ENTITY, ENT_WEAPONPRED); - WriteFloat(MSG_ENTITY, sendflags); -#else -float() ReadByte = #360; -float() ReadFloat = #367; -void InitPredEnt(entity e); - -#define COMM(_type, _field) pstate_server.##_field = Read##_type() -void EntUpdate_WeaponPred(float isnew) { - float sendflags = readfloat(); -#endif - if (sendflags & FOWP_CTIME) { - COMM(Float, client_time); - } - - if (sendflags & FOWP_CLASS) { - COMM(Byte, playerclass); - } - - if (sendflags & FOWP_IMPULSE) { - COMM(Byte, impulse); - COMM(Byte, current_slot.id); - COMM(Byte, queue_slot.id); - } - - if (sendflags & FOWP_TFSTATE) { - COMM(Float, tfstate); - } - - if (sendflags & FOWP_THINK) { - COMM(Float, client_nextthink); - COMM(Float, client_thinkindex); - } - - if (sendflags & FOWP_WF) { - COMM(Float, attack_finished); - COMM(Byte, weaponframe); - } - - if (sendflags & FOWP_CLIP) { - COMM(Byte, clip_fired[0]); - COMM(Byte, clip_fired[1]); - COMM(Byte, clip_fired[2]); - COMM(Byte, clip_fired[3]); - } - - if (sendflags & FOWP_RELOAD) - COMM(Float, reload_finished); - -#ifdef SSQC - return TRUE; -#else - if (isnew) - InitPredEnt(self); -#endif -} - -#ifdef SSQC -inline float WeaponPred_Active(entity player) { - return player.weapon_pred_enabled; -} - -void WeaponPred_Init(entity player) { - if (!ClientEnable()) { // Server side is once per connect. - player.weapon_pred_enabled = FALSE; - return; - } - - player.weapon_pred_enabled = TRUE; - - entity pe = spawn(); - pe.owner = player; - pe.classname = "WeaponPred"; - pe.dimension_seen = DMN_FLASH | DMN_NOFLASH; - pe.pvsflags = PVSF_IGNOREPVS; - pe.SendEntity = WeaponPred_SendEntity; - setorigin(pe, [0, 0, 0]); - - player.predict_entity = pe; - sprint(self, PRINT_HIGH, - "FortressOne: Weapon Prediction Active ", wp_version, "\n"); -} - -void WeaponPred_TearDown(entity player) { - if (!player.weapon_pred_enabled) - return; - - dremove(player.predict_entity); -} - -void WeaponPred_DoServerClientThink() { - while (self.client_think && self.client_time > self.client_nextthink) { - float held_client_time = self.client_time; - - self->client_time = self->client_nextthink; - self->client_nextthink = 0; - self->client_think(); - - self->client_time = held_client_time; - } -} -#endif - -#ifdef CSQC -static Slot InputToSlot(float input) { - Slot result = FO_SlotByInput(input); - return result; -} - -void WeaponPred_ChangeWeapon(Slot slot) { - pstate_pred.current_slot = slot; - pstate_pred.weaponframe = 0; - - // UpdateViewModel will propagate. -} - -void WeaponPred_Reload(); - -void WeaponPred_Impulse() { - // Note: We might have no impulse, but a queued slot here. - if (pstate_pred.impulse >= 1 && pstate_pred.impulse <= 7) { // Change weapon - Slot slot = InputToSlot(pstate_pred.impulse); - if (!IsSlotNull(slot)) - pstate_pred.queue_slot = slot; - pstate_pred.impulse = 0; - } - - if (pstate_pred.client_time < pstate_pred.attack_finished || - (pstate_pred.tfstate & TFSTATE_RELOADING)) - return; - - if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { - WeaponPred_ChangeWeapon(pstate_pred.queue_slot); - pstate_pred.queue_slot = SlotNull; - } - - if (!pstate_pred.impulse) - return; - - float clear = FALSE; - - if (pstate_pred.impulse == TF_RELOAD) { - WeaponPred_Reload(); - clear = TRUE; - } - - if (clear) - pstate_pred.impulse = 0; -} - -void FO_CSQC_Fire(); - -static float AmmoToStat(float ammo_type) { - switch (ammo_type) { - case AMMO_SHELLS: return STAT_SHELLS; - case AMMO_ROCKETS: return STAT_ROCKETS; - case AMMO_NAILS: return STAT_NAILS; - case AMMO_CELLS: return STAT_CELLS; - } - return STAT_AMMO; -} - -float WP_GetAmmo(float ammo_type) { - if (!WP_Enabled()) - return getstatf(AmmoToStat(ammo_type)); - - if (ammo_type == AMMO_NONE) - return 0; - - float base = getstatf(AmmoToStat(ammo_type)); - base -= pstate_pred.ammo_used[ammo_type]; - return max(0, base); -} - -float WP_CurrentAmmo() { - if (!WP_Enabled()) - return getstatf(STAT_AMMO); - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - return WP_GetAmmo(wi->ammo_type); -} - -static float* ClipFired() { - float index = SlotIndex(pstate_pred.current_slot); - if (pstate_pred.playerclass == PC_DEMOMAN && - index == 1) - index = 0; // Special case: Pipebomb shares with Grenadel launcher. - - return &pstate_pred.clip_fired[index]; -} - -string WP_GetClip() { - if (!WP_Enabled()) - return SBAR.ClipSize; - - Slot slot = pstate_pred.current_slot; - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - - if (!wi->needs_reload || IsSlotNull(slot)) - return ""; - - float capacity = wi->clip_size; - float still_loading = 0; - float fired = *ClipFired(); - - if (pstate_pred.tfstate & TFSTATE_RELOADING) - still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, - pstate_pred.reload_finished); - - float clip = capacity - fired - still_loading; - return sprintf("%d/%d", clip, wi->clip_size); -} - -void WeaponPred_CheckReloadFinished() { - if ((pstate_pred.tfstate & TFSTATE_RELOADING) && - pstate_pred.client_time >= pstate_pred.reload_finished) { - pstate_pred.tfstate &= ~TFSTATE_RELOADING; - - if (pengine.is_effectframe) - print("Finished reloading\n"); - } -} - -void WeaponPred_Reload() { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - if (!wi->needs_reload) - return; - - float clip_fired = *ClipFired(); - float ammo_rem = WP_GetAmmo(wi->ammo_type); - - string msg; - if (!FO_CheckCanReload(wi, ammo_rem, clip_fired, msg)) { - if (pengine.is_effectframe) - print(msg); - return; - } - - if (pengine.is_effectframe) - print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); - - pstate_pred.tfstate |= TFSTATE_RELOADING; - float amt = min(ammo_rem, clip_fired); - (*ClipFired()) -= amt; - - pstate_pred.reload_finished = pstate_pred.client_time + - (amt / wi->clip_size) * wi->full_reload_time; -} - -float WeaponPred_IsReloading() { - return pstate_pred.tfstate & TFSTATE_RELOADING; -} - - -float WeaponPred_ConsumeAmmo(FO_WeapInfo* wi) { - if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) - return TRUE; - - int ammo = WP_GetAmmo(wi->ammo_type); - if (wi->ammo_per_shot > ammo) - return FALSE; - - if (wi->needs_reload) { - if (*ClipFired() >= wi->clip_size) { - WeaponPred_Reload(); - return FALSE; - } - } - - pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; - *ClipFired() += wi->ammo_per_shot; - - return TRUE; -} - -void FO_CSQC_Animate(float fired); - -void WeaponPred_Attack() { - if (pstate_pred.firing) // Already in a continuous attack. - return; - - Slot slot = pstate_pred.current_slot; - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - - if (!WeaponPred_ConsumeAmmo(wi)) - return; - - // Must be set prior to animation code, which might internally modify. - pstate_pred.client_thinkindex = 0; - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - - FO_CSQC_Animate(TRUE); -} - -void WeaponPred_DoClientThink(void) { - FO_CSQC_Animate(FALSE); -} - -void WeaponPred_UpdateViewModel() { - float pmodelindex, pframe; - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - if (wi->predict_type == NO_PREDICT) { - // Fall back to engine. - self.modelindex = 0; - wp_model_mask |= MASK_VIEWMODEL; - return; - } else { - wp_model_mask &= ~MASK_VIEWMODEL; - - } - - if (pstate_pred.tfstate & TFSTATE_RELOADING) { - self.modelindex = 0; - return; - } - - pmodelindex = (wi->models)->modelindex; - pframe = pstate_pred.weaponframe; - - if (self.modelindex != pmodelindex) { - self.frame = pframe; - self.modelindex = pmodelindex; - self.lerpfrac = 0; - } else if (self.frame != pframe) { - self.frame2 = self.frame; - self.frame = pframe; - self.lerpfrac = 1; - } - - self.lerpfrac = max(0, self.lerpfrac - frametime * 10); -} - -float WeaponPred_ClientThink() { - pstate_pred = pstate_server; - - int pframe = servercommandframe + 1; - int eframe = clientcommandframe; - for(; pframe <= eframe; pframe++) { - int success = getinputstate(pframe); - if (!success || input_timelength <= 0) - break; - makevectors(input_angles); - - if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { - pengine.is_effectframe = TRUE; - pengine.last_effectframe = pframe; - } else { - pengine.is_effectframe = FALSE; - } - - pstate_pred.client_time += input_timelength; - if (input_impulse) - pstate_pred.impulse = input_impulse; - - if (pstate_pred.client_nextthink && - pstate_pred.client_time >= pstate_pred.client_nextthink) { - float held_client_time = pstate_pred.client_time; - - pstate_pred.client_time = pstate_pred.client_nextthink; - pstate_pred.client_nextthink = 0; - WeaponPred_DoClientThink(); - pstate_pred.client_time = held_client_time; - } - - WeaponPred_CheckReloadFinished(); - WeaponPred_Impulse(); - - if ((input_buttons & BUTTON0) && - (pstate_pred.tfstate & TFSTATE_RELOADING == 0) && - (pstate_pred.client_time >= pstate_pred.attack_finished)) - WeaponPred_Attack(); - - } - - WeaponPred_UpdateViewModel(); - return PREDRAW_AUTOADD; -} - -void InitPredEnt(entity pe) { - pe.predraw = WeaponPred_ClientThink; - - self.drawmask = MASK_PRED_VIEWMODEL; - self.renderflags = RF_VIEWMODEL; - - FO_WeaponPred_Init(TRUE); -} -#endif diff --git a/share/fo_weapons.qc b/share/fo_weapons.qc deleted file mode 100644 index 7b503580..00000000 --- a/share/fo_weapons.qc +++ /dev/null @@ -1,638 +0,0 @@ -#ifdef CSQC -/* - * This is a hack so that we can have our client entity be closer to server for - * shared code. We'll refactor this on both sides to be cleaner incrementally, - * but it gets us started. - */ -.float waterlevel; -.float playerclass; - -.float ammo_shells; -.float ammo_nails; -.float ammo_rockets; -.float ammo_cells; - -float fo_hwguy = TRUE; -float sniperreload = FALSE; -float pyro_type = PYRO_FO; -float old_ng_rof = FALSE; -#endif - -// Some preprocessor bug is making __LINE__ not substitute right here most of -// the time. Oh well, even if we just get file it's good enough to narrow. -#define CheckSlot(slot_num) _CheckSlot(__FILE__, __LINE__, slot_num) -float _CheckSlot(string file, float line, float slot_num) { - if (slot_num < 1 || slot_num > TF_NUM_SLOTS) { - printf("%s:%d: Invalid slot (%d). Continuing.\n", - file, line, slot_num); - return 4; - } - return slot_num; -} - -#define MakeSlot(slot_num) _MakeSlot(CheckSlot(slot_num)) -// Careful: Slots are not 0-indexed they start from 1. -// Use SlotIndex() to convert a slot if you're indexing an array. -Slot _MakeSlot(float slot_num) { - if (slot_num < 1 || slot_num > TF_NUM_SLOTS) - errorf("invalid slot %d\n", slot_num); - - Slot result; - result.id = slot_num; - return result; -} - -const Slot SlotMelee = { 4 }; -const Slot SlotNull = { 0 }; -inline float IsSlotNull(Slot slot) { return slot.id == 0; } -inline float IsSlotMelee(Slot slot) { return slot.id == 4; } -inline float IsSameSlot(Slot slot1, Slot slot2) { return slot1.id == slot2.id; } - -// Returns dense [0..TF_NUM_SLOTS-1] -float SlotIndex(Slot slot) { - if (slot.id > 4) { - printf("ERROR: OOB slot id (%d) found. Continuing.\n", (float)slot.id); - return TF_NUM_SLOTS - 1; - } - return slot.id - 1; } - -// Convert a weapon-bit to a linear index. -static float WEAP_to_index(float weapon) { - float index = 0; - for (; weapon > 0; weapon >>= 1, index++) { - if (weapon >= 64) { - weapon >>= 6; - index += 6; - } - } - return index; -} - -enum AmmoType { - AMMO_NONE, - AMMO_SHELLS, - AMMO_NAILS, - AMMO_CELLS, - AMMO_ROCKETS, - AMMO_NUM_TYPES = AMMO_ROCKETS + 1, -}; - -struct FO_WeapModels; -struct FO_WeapToItem; - -enum PredictionType { - NO_PREDICT, - PRED_MODEL, - PRED_PROJ, -}; - -struct FO_WeapInfo { - int weapon; // Verification - int predict_type; - AmmoType ammo_type; - float clip_size; - float ammo_per_shot; - float attack_time; - float full_reload_time; - - // Fields below this are automatically initialized by Init. - // ** Do not include in table. ** - float needs_reload; - FO_WeapModels* models; - FO_WeapToItem* items; -}; - -// REQUIRES: weapon at index i == WEAP_to_index(weap) -// -ve values are placeholders signifying conditional init based on game modes. -FO_WeapInfo weapon_info[] = { - { WEAP_NONE, NO_PREDICT, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_HOOK, NO_PREDICT, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_KNIFE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_MEDIKIT, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, - { WEAP_SPANNER, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, - { WEAP_AXE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_SNIPER_RIFLE, NO_PREDICT, AMMO_SHELLS, -9, 1, 1.5, 4 }, - { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0 }, - { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, - { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, - { WEAP_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.2, 0 }, - { WEAP_SUPER_NAILGUN, PRED_MODEL, AMMO_NAILS, 0, 2, 0.2, 0 }, - { WEAP_GRENADE_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 6, 1, 0.6, 4 }, - { WEAP_PIPE_LAUNCHER, PRED_MODEL, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL - { WEAP_FLAMETHROWER, PRED_MODEL, AMMO_CELLS, 0, 1, 0.15, 0 }, - { WEAP_ROCKET_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 4, 1, 0.8, 5 }, - { WEAP_INCENDIARY, PRED_MODEL, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, NO_PREDICT, AMMO_SHELLS, -9, 1, 0.2, 4 }, - { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, - { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, - { WEAP_TRANQ, NO_PREDICT, AMMO_SHELLS, 0, 1, 1.5, 0 }, - { WEAP_RAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.4, 0 }, -}; - -inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { - return &weapon_info[WEAP_to_index(weapon)]; -} - -struct FO_ClassWeapons { - float id; - float slots[4]; - FO_WeapInfo *info[4]; -}; - -// Indexed by class ID, e.g. PC_SOLDIER -FO_ClassWeapons class_weapons[] = { - { PC_UNDEFINED, { 0, 0, 0, WEAP_AXE } }, - { PC_SCOUT, { WEAP_NAILGUN, WEAP_SHOTGUN, 0, WEAP_AXE } }, - { PC_SNIPER, { WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN, WEAP_AXE } }, - { PC_SOLDIER, { WEAP_ROCKET_LAUNCHER, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, - { PC_DEMOMAN, { WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER, WEAP_SHOTGUN, WEAP_AXE } }, - { PC_MEDIC, { WEAP_SUPER_NAILGUN, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_MEDIKIT } }, - { PC_HVYWEAP, { WEAP_ASSAULT_CANNON, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, - { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, - { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, - { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, - { PC_RANDOM, { 0, 0, 0, WEAP_AXE } }, // TODO: Probably needs attention - { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, -}; - -// Indexed by WEAP_to_index(). We keep them out of the main table just to keep -// things a little more wieldly/readable. -static string weapon_names[] = { - "None", "Hook", "Knife", "Medikit", "Spanner", "Axe", "Sniper Rifle", - "Auto Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", - "Grenade Launcher", "Pipebomb Launcher", "Flamethrower", "Rocket Launcher", - "Incendiary Launcher", "Assault Cannon", "Lightning Gun", "Detpack", - "Tranquilizer", "Railgun" -}; - -string FO_GetWeapName(float weapon) { - return weapon_names[WEAP_to_index(weapon)]; -} - -struct FO_WeapModels { - int weapon; - string model; - - // Automatically populated. - int modelindex; - -}; - -// Indexed by WEAP_to_index() -static FO_WeapModels weapon_models[] = { - { WEAP_NONE, ""}, - { WEAP_HOOK, "progs/v_grap.mdl" }, - { WEAP_KNIFE, "progs/v_knife.mdl" }, - { WEAP_MEDIKIT, "progs/v_medi.mdl" }, - { WEAP_SPANNER, "progs/v_span.mdl" }, - { WEAP_AXE, "progs/v_axe.mdl" }, - { WEAP_SNIPER_RIFLE, "progs/v_srifle.mdl" }, - { WEAP_AUTO_RIFLE, "progs/v_srifle.mdl" }, - { WEAP_SHOTGUN, "progs/v_shot.mdl" }, - { WEAP_SUPER_SHOTGUN, "progs/v_shot2.mdl" }, - { WEAP_NAILGUN, "progs/v_nail.mdl" }, - { WEAP_SUPER_NAILGUN, "progs/v_nail2.mdl" }, - { WEAP_GRENADE_LAUNCHER, "progs/v_rock.mdl" }, - { WEAP_PIPE_LAUNCHER, "progs/v_pipe.mdl" }, - { WEAP_FLAMETHROWER, "progs/v_flame.mdl" }, - { WEAP_ROCKET_LAUNCHER, "progs/v_rock2.mdl" }, - { WEAP_INCENDIARY, "progs/v_irock.mdl" }, - { WEAP_ASSAULT_CANNON, "progs/v_asscan.mdl" }, - { WEAP_LIGHTNING, "" }, - { WEAP_DETPACK, "" }, - { WEAP_TRANQ, "progs/v_tranq.mdl" }, - { WEAP_RAILGUN, "progs/v_rail.mdl" }, -}; - -// REQUIRES: Order must match above. -static string AMMO_to_s[] = {"none", "shells", "nails", "cells", "rockets"}; - -static float* AMMO_to_p(entity player, AmmoType ammo_type) { - switch (ammo_type) { - case AMMO_SHELLS: return &player.ammo_shells; - case AMMO_CELLS: return &player.ammo_cells; - case AMMO_NAILS: return &player.ammo_nails; - case AMMO_ROCKETS: return &player.ammo_rockets; - default: - case AMMO_NONE: - return __NULL__; - } - return __NULL__; -} - -Slot WEAP_to_slot(float playerclass, float weapon) { - for (float i = 0; i < TF_NUM_SLOTS; i++) { - if (class_weapons[playerclass].slots[i] == weapon) - return MakeSlot(i + 1); - } - return SlotNull; -} - -struct FO_WeapToItem { - int weapon; - float it_weapon; - - // Fields below this line automatically populated. - float ammo_mask; -}; - -FO_WeapToItem weapon_to_items[] = { - { WEAP_NONE, 0}, - { WEAP_HOOK, IT_HOOK}, - { WEAP_KNIFE, 0}, - { WEAP_MEDIKIT, 0}, - { WEAP_SPANNER, 0}, - { WEAP_AXE, 0}, - { WEAP_SNIPER_RIFLE, IT_SHOTGUN}, - { WEAP_AUTO_RIFLE, IT_SUPER_SHOTGUN}, - { WEAP_SHOTGUN, IT_SHOTGUN}, - { WEAP_SUPER_SHOTGUN, IT_SUPER_SHOTGUN}, - { WEAP_NAILGUN, IT_NAILGUN}, - { WEAP_SUPER_NAILGUN, IT_SUPER_NAILGUN}, - { WEAP_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER}, - { WEAP_PIPE_LAUNCHER, IT_GRENADE_LAUNCHER}, - { WEAP_FLAMETHROWER, IT_GRENADE_LAUNCHER}, - { WEAP_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER}, - { WEAP_INCENDIARY, IT_ROCKET_LAUNCHER}, - { WEAP_ASSAULT_CANNON, IT_ROCKET_LAUNCHER}, - { WEAP_LIGHTNING, IT_LIGHTNING}, - { WEAP_DETPACK, 0}, - { WEAP_TRANQ, IT_SHOTGUN}, - { WEAP_RAILGUN, IT_SHOTGUN}, -}; - -FO_WeapInfo* FO_SlotWeapInfo(float class, Slot slot) { - if (IsSlotNull(slot)) - return FO_GetWeapInfo(WEAP_NONE); - - FO_ClassWeapons* cw = &class_weapons[class]; - return cw->info[SlotIndex(slot)] ? cw->info[SlotIndex(slot)] : - FO_GetWeapInfo(WEAP_NONE); -} - -float FO_ClassWeaponBySlot(float class, Slot slot) { - FO_WeapInfo* wi = FO_SlotWeapInfo(class, slot); - if (!wi) - return WEAP_NONE; - - return wi->weapon; -} - -float FO_WeaponSlot(Slot slot) { - return FO_ClassWeaponBySlot(self.playerclass, slot); -} - - -float FO_ClassWeapItemMask(float class) { - float result = 0; - for (int i = 1; i <= TF_NUM_SLOTS; i++) { - FO_WeapInfo* wi = FO_SlotWeapInfo(class, MakeSlot(i)); - if (wi) - result |= (wi->items)->it_weapon; - } - return result; -} - -float FO_WeaponsMask(entity player) { - float mask = 0; - for (float i = 1; i <= TF_NUM_SLOTS; i++) { - FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, MakeSlot(i)); - if (wi) - mask |= wi->weapon; - } - return mask; -} - -// Slightly awkward construction, but convenient for calling from CSQC and SSQC. -float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) { - float tick = (wi->ammo_per_shot / wi->clip_size) * wi->full_reload_time; - return ceil((reload_finished - now) / tick) * wi->ammo_per_shot; -} - -float FO_CheckCanReload(FO_WeapInfo* wi, int ammo_remaining, int clip_fired, - __out string msg) { - if (clip_fired == 0) - msg = "Clip full\n"; - else if (ammo_remaining == 0) - msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); - else if (wi->clip_size - clip_fired == ammo_remaining) - msg = strcat("All ", AMMO_to_s[wi->ammo_type], " are in the clip\n"); - else - return TRUE; - - return FALSE; // msg filled in above. -} - -#ifdef SSQC -struct FO_WeapState { - float weapon; - Slot slot; - - // Constant and relative to weapon. TODO, migrate similar to WeapInfo. - FO_WeapInfo* wi; - - /* These are relative to the player passed. */ - float* ammo_remaining; - float* clip_fired; -}; - - -void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { - FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, slot); - - result->weapon = wi->weapon; - result->slot = slot; - result->wi = wi; - - result->ammo_remaining = AMMO_to_p(player, wi->ammo_type); - - if (!IsSlotNull(slot)) - result->clip_fired = &player.clip_fired[SlotIndex(slot)]; - else - result->clip_fired = __NULL__; - - // Special case: Overlap with grenade launcher. - if (wi->weapon == WEAP_PIPE_LAUNCHER) - result->clip_fired = &player.clip_fired[0]; -} - -float FO_ClassWeaponBySlot(float class, Slot slot); - -inline float FO_CurrentWeapon() { - return FO_ClassWeaponBySlot(self.playerclass, self.current_slot); -} - -inline float FO_PlayerCurrentWeapon(entity player) { - return FO_ClassWeaponBySlot(player.playerclass, player.current_slot); -} - -inline void FO_FillCurrentWeapState(FO_WeapState* result) { - FO_FillWeapState(self, self.current_slot, result); -} - -void (entity pl) Status_Refresh; -void (float att_delay) Attack_Finished; - -// Hack until we fix Status_Refresh() to not be awful. -.float last_still_loading; - -float FO_ReloadFrame() { - if (self.tfstate & TFSTATE_RELOADING == 0) - return FALSE; - - FO_WeapState ws; - FO_FillWeapState(self, self.current_slot, &ws); - FO_WeapInfo* wi = ws.wi; - - if (wi->weapon == WEAP_NONE) - return FALSE; - - if (self.client_time >= self.reload_finished) { - self.tfstate &= ~TFSTATE_RELOADING; - self.weaponmodel = ((ws->wi)->models)->model; - self.weaponframe = 0; - self.last_still_loading = 0; - Status_Refresh(self); - sprint(self, PRINT_HIGH, "Finished reloading\n"); - - return FALSE; - } - - float still_loading = FO_NumClipStillLoading(wi, self.client_time, - self.reload_finished); - if (self.last_still_loading != still_loading) { - self.last_still_loading = still_loading; - Status_Refresh(self); - } - - return TRUE; -} - -float FO_CanReload(Slot slot) { - FO_WeapState ws; - FO_FillWeapState(self, slot, &ws); - FO_WeapInfo* wi = ws->wi; - - if (wi->ammo_type == AMMO_NONE) - return FALSE; - - if (wi->needs_reload && *ws->clip_fired > 0 - && *ws->ammo_remaining > wi->ammo_per_shot) - return TRUE; - - return FALSE; -} - -void () RestoreDefaultWeapon; -void FO_ReloadSlot(Slot slot, float force) { - RestoreDefaultWeapon(); - if (self.tfstate & TFSTATE_RELOADING || IsSlotNull(slot)) - return; - - FO_WeapState ws; - FO_FillWeapState(self, slot, &ws); - FO_WeapInfo* wi = ws->wi; - - if (!wi->needs_reload) - return; - - string msg; - if (!FO_CheckCanReload(wi, *ws->ammo_remaining, *ws->clip_fired, msg)) { - sprint(self, PRINT_HIGH, msg); - return; - } - - sprint(self, PRINT_HIGH, - strcat("Reloading ", FO_GetWeapName(ws->weapon), "...\n")); - - Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. - - self.weaponmodel = ""; - self.weaponframe = 0; - self.tfstate |= TFSTATE_RELOADING; - Status_Refresh(self); - - float reload_count = min(*ws->clip_fired, *ws->ammo_remaining); - float reload_duration = - (reload_count / wi->clip_size) * wi->full_reload_time; - - // TODO: Make ammo in clip independent from ammo_remaining (so you can't - // have shots in clip that are discarded and other weirdness.) - (*ws->clip_fired) -= reload_count; - - self.last_still_loading = reload_count; - self.reload_finished = self.client_time + reload_duration; -} - -float FO_CheckForReload() { - FO_WeapState ws; - FO_FillCurrentWeapState(&ws); - FO_WeapInfo* wi = ws->wi; - - if (wi->needs_reload && *ws->clip_fired >= wi->clip_size && - *ws->ammo_remaining > 0) { - if (force_reload) - FO_ReloadSlot(self.current_slot, TRUE); - return TRUE; - } else { - return FALSE; - } -} - -void FO_InstantReloadAllWeapons(entity player) { - player.tfstate &= ~TFSTATE_RELOADING; - player.reload_finished = 0; - player.last_still_loading = 0; - for (int i = 0; i < TF_NUM_SLOTS; i++) - player.clip_fired[i] = 0; -} -#endif - -struct ImpulseWeapon { - int class; - float weapons[7]; - - // Autogenerated - Slot slots[7]; -}; - -ImpulseWeapon impulse_weapons[] = { - { PC_UNDEFINED, { WEAP_AXE } }, - { PC_SCOUT, - { WEAP_AXE, WEAP_SHOTGUN, 0, WEAP_NAILGUN } }, - { PC_SNIPER, - { WEAP_AXE, WEAP_SNIPER_RIFLE, WEAP_AUTO_RIFLE, WEAP_NAILGUN } }, - { PC_SOLDIER, - { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ROCKET_LAUNCHER } }, - { PC_DEMOMAN, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, 0, WEAP_GRENADE_LAUNCHER, WEAP_PIPE_LAUNCHER} }, - { PC_MEDIC, - { WEAP_MEDIKIT, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SUPER_NAILGUN } }, - { PC_HVYWEAP, - { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, - { PC_PYRO, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, - { PC_SPY, - { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, - { PC_ENGINEER, - { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, - { PC_CIVILIAN, { WEAP_AXE } }, -}; - -Slot FO_ImpulseToSlot(float impulse) { - if (impulse < 1 || impulse > 7) return 0; - return impulse_weapons[self.playerclass].slots[impulse - 1]; -} - -#ifdef SSQC -float IsUsingOldImpulses(); - -float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; -static float IsPyroSlotSwapped() { - return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); -} -#else -float IsUsingOldImpulses() { return FALSE; } - -static float IsPyroSlotSwapped() { return FALSE; } -#endif - -float InputHandlePyroSlotSwap(float input) { - float cf_pyro_impulses = IsPyroSlotSwapped(); - if (self.playerclass == PC_PYRO && cf_pyro_impulses && (input == 1 || input == 2)) - input = 3 - input; - return input; -} - -Slot FO_SlotByInput(float input) { - if (IsUsingOldImpulses()) { - return FO_ImpulseToSlot(input); - } else { - input = InputHandlePyroSlotSwap(input); - return MakeSlot(input); - } -} - -void FO_Weapons_Init() { - float i, j; - - ASSERTD_EQ(weapon_names.length, weapon_info.length); - - FO_WeapInfo* WI_ac = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - WI_ac->clip_size = fo_hwguy ? PC_HVYWEAP_ASSCAN_CLIPSIZE : 0; - FO_WeapInfo* WI_sr = FO_GetWeapInfo(WEAP_SNIPER_RIFLE); - WI_sr->clip_size = sniperreload ? 1 : 0; - - FO_WeapInfo* WI_ir = FO_GetWeapInfo(WEAP_INCENDIARY); - switch (pyro_type) { - case PYRO_ORIGINAL: WI_ir->attack_time = 1.2; break; - case PYRO_OZTF: - case PYRO_FO: - default: - WI_ir->attack_time = 0.9; break; - } - - // Consider just removing this? - if (old_ng_rof) { - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_NAILGUN); - wi->ammo_per_shot = 2; - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); - wi->ammo_per_shot = 4; - } - - for (i = 0; i < weapon_info.length; i++) { - FO_WeapInfo* wi = &weapon_info[i]; - ASSERTD_EQ(WEAP_to_index(wi->weapon), i); - - if (wi->weapon == WEAP_PIPE_LAUNCHER) { - FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); - wi->ammo_type = parent->ammo_type; - wi->clip_size = parent->clip_size; - wi->full_reload_time = parent->full_reload_time; - wi->needs_reload = parent->needs_reload; - } else if (wi->clip_size > 0) { - wi->needs_reload = TRUE; - } else { - wi->needs_reload = FALSE; - } - - FO_WeapModels* wm = &weapon_models[i]; - ASSERTD_EQ(WEAP_to_index(wm->weapon), i); - precache_model(wm->model); -#ifdef CSQC - wm->modelindex = getmodelindex(wm->model); -#endif - wi->models = wm; - - FO_WeapToItem* wti = &weapon_to_items[i]; - ASSERTD_EQ(WEAP_to_index(wti->weapon), i); - - wi->items = wti; - switch (wi->ammo_type) { - case AMMO_SHELLS: wti->ammo_mask = IT_SHELLS; break; - case AMMO_CELLS: wti->ammo_mask = IT_CELLS; break; - case AMMO_NAILS: wti->ammo_mask = IT_NAILS; break; - case AMMO_ROCKETS: wti->ammo_mask = IT_ROCKETS; break; - } - } - - for (i = 0; i < class_weapons.length; i++) { - for (j = 0; j < 4; j++) { - FO_ClassWeapons* cw = &class_weapons[i]; - - if (cw->slots[j]) - cw->info[j] = &weapon_info[WEAP_to_index(cw->slots[j])]; - else - cw->info[j] = &weapon_info[0]; // WEAP_NONE - } - } - - for (i = 0; i < impulse_weapons.length; i++) { - ImpulseWeapon* iw = &impulse_weapons[i]; - - for (j = 0; j < 7; j++) - if (iw->weapons[j]) - iw->slots[j] = WEAP_to_slot(iw->class, iw->weapons[j]); - } -} - From 9420e6f6b51edf598f76692d9df19ff0a06b162a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 21:06:58 -0700 Subject: [PATCH 1784/2474] Shared PRNG Introduce a PRNG that is symmetric between client and server. Use this (to start) for animations. --- csqc/weapon_predict.qc | 5 ++++- share/weapon_predict.qc | 26 ++++++++++++++++++++++++++ ssqc/weapons.qc | 10 +++------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index b4e53139..5a7190ac 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -175,7 +175,10 @@ float WP_ConsumeAmmo(FO_WeapInfo* wi) { } static void prandom(void() option1, void() option2) { - option1(); + if (shared_prng(self) < 0.5) + option1(); + else + option2(); } void WP_AnimateModel(float fired) { diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 688e2600..b02681d1 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -11,6 +11,7 @@ enumflags { FOWP_WF, FOWP_CLASS, FOWP_RELOAD, + FOWP_RNG, }; #define FOWP_ALL 0xFFFF @@ -31,6 +32,7 @@ struct predict_tf_state { float reload_finished; float clip_fired[4]; + int lfsr_state; // Used for prediction, not actually communicated. Reset each frame. @@ -102,6 +104,26 @@ void FO_WP_Init(float enabled) { } #endif +#ifdef SSQC +.int lfsr_state; // Shared random number generator +static inline int get_lfsr_state(entity pl) { return pl.lfsr_state; } +static inline void set_lfsr_state(entity pl, int v) { pl.lfsr_state = v; } +#else +static inline int get_lfsr_state(entity pl) { return pstate_pred.lfsr_state; } +static inline void set_lfsr_state(entity pl, int v) { pstate_pred.lfsr_state = v; } +#endif + +float shared_prng(entity pl) { // A 16-bit xor-shift LFSR. + int v = get_lfsr_state(pl); + v ^= (v >> 7); + v ^= (v << 9); + v &= 65535; + v ^= (v >> 13); + set_lfsr_state(pl, v); + + return (float)v / 65535.0; +} + #ifdef SSQC #define OP1(_op, _f1) (player.predict_state.##_f1 _op player.##_f1) #define OP2(_op, _j, _f1, _f2) OP1(_op, _f2) _j OP1(_op, _f1) @@ -133,6 +155,7 @@ void WeaponPred_Update(entity player) { M2(FOWP_THINK, client_nextthink, client_thinkindex); M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) M1(FOWP_RELOAD, reload_finished) + M1(FOWP_RNG, lfsr_state) player.predict_entity.SendFlags = mask; } @@ -203,6 +226,9 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_RELOAD) COMM(Float, reload_finished); + if (sendflags & FOWP_RNG) + COMM(Float, lfsr_state); + #ifdef SSQC return TRUE; #else diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 3b0f0f4f..364b2e84 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1622,7 +1622,6 @@ void () player_medikit1; void () player_medikitb1; void () W_Attack = { - float r; FO_WeapState ws; FO_FillCurrentWeapState(&ws); FO_WeapInfo* wi = ws->wi; @@ -1656,15 +1655,13 @@ void () W_Attack = { if (ws.weapon == WEAP_AXE) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); - r = random(); - if (r < 0.5) + if (shared_prng(self) < 0.5) player_axe1(); else player_axeb1(); } else if (ws.weapon == WEAP_KNIFE) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); - r = random(); - if (r < 0.5) + if (shared_prng(self) < 0.5) player_knife1(); else player_knifeb1(); @@ -1741,8 +1738,7 @@ void () W_Attack = { } } else if (ws.weapon == WEAP_MEDIKIT) { FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); - r = random(); - if (r < 0.5) + if (shared_prng(self) < 0.5) player_medikit1(); else player_medikitb1(); From 859882dc85883987b3509df66d80425fafa5fe30 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 21:15:09 -0700 Subject: [PATCH 1785/2474] Make sure death animations are terminal Clearing client_nextthink was still allowing player_run to proceed resulting in wrong frame for body. --- ssqc/player.qc | 5 +++-- ssqc/time.qc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 3cde777c..f3da1eb7 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -324,7 +324,7 @@ void () DeathSound = { void () PlayerDead = { self.client_nextthink = -1; self.nextthink = -1; - self.deadflag = 2; + self.deadflag = DEAD_DEAD; }; vector(float dm) VelocityForDamage = @@ -513,7 +513,8 @@ void () set_suicide_frame = { void player_die_extra() { - if (self.client_thinkindex >= 9) + // Death animations are variable length, this always picks up last frame. + if (self.client_think == player_run) PlayerDead(); } diff --git a/ssqc/time.qc b/ssqc/time.qc index c77f2fb4..3e735895 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -22,7 +22,7 @@ inline float client_to_global_time(float ctime) { void FO_CheckClientThink() { - if (self.client_nextthink && self.client_time >= self.client_nextthink) { + if (self.client_nextthink > 0 && self.client_time >= self.client_nextthink) { float held_client_time = self.client_time; self.client_time = self.client_nextthink; From d47ec8d54757b8e5bb3509d2fd44ccafc4d5e55f Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 21:35:16 -0700 Subject: [PATCH 1786/2474] Time and Prediction touchups Clean up nits around new stuff --- csqc/weapon_predict.qc | 14 +++++++------- share/weapon_predict.qc | 4 ++-- ssqc/antilag.qc | 3 +-- ssqc/client.qc | 2 +- ssqc/tfort.qc | 2 +- ssqc/time.qc | 11 +++++++---- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 5a7190ac..7ba90047 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -271,7 +271,7 @@ void WP_Frame() { entity predicted_projectiles; .entity pred_next, pred_prev; -.vector s_origin, old_origin; +.vector s_origin; .float starttime, endtime, p_time; .float traileffectnum; @@ -348,12 +348,12 @@ float PP_PredrawActive() { self.oldorigin = trace_endpos; return PREDRAW_NEXT; } - - if (self.traileffectnum) - trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); } - self.p_time = time + 0.013; + if (self.traileffectnum) + trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); + + self.p_time = time + frametime; self.oldorigin = self.origin; } @@ -406,8 +406,8 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { proj.s_origin[2] += 16; proj.velocity = v_forward * desc->speed; - proj.old_origin = proj.s_origin + 0.013 * proj.velocity; - proj.origin = proj.old_origin; + proj.oldorigin = proj.s_origin + frametime * proj.velocity; + proj.origin = proj.oldorigin; proj.angles = input_angles; proj.angles[0] *= -1; diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index b02681d1..48301ac0 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -47,8 +47,8 @@ struct fo_projectile { fo_projectile fpp_rocket = { PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl" }; fo_projectile fpp_incendiary = { 800, "progs/lavaball.mdl" }; -fo_projectile fpp_nail = { 1000, "progs/spike.mdl" }; -fo_projectile fpp_super_nail = { 1000, "progs/s_spike.mdl" }; +fo_projectile fpp_nail = { 1500, "progs/spike.mdl" }; +fo_projectile fpp_super_nail = { 1500, "progs/s_spike.mdl" }; #ifdef SSQC diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index eabe93db..ce987249 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -333,8 +333,7 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { time - rewind_max_offset); // Det was pushed at remote_client_time(), let's see if we can get there. - float rewind_to = max(farthest_rewind_point, - client_to_global_time(remote_client_time())); + float rewind_to = max(farthest_rewind_point, remote_time()); // Ignore for LAN pings. if (time - rewind_to < 0.013) diff --git a/ssqc/client.qc b/ssqc/client.qc index a9166b49..4fe5d941 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2066,7 +2066,7 @@ void () PutClientInServer = { self.invincible_finished = 0; self.effects = 0; self.invincible_time = 0; - self.spawn_time = self.client_time; + self.spawn_time = time; self.vote_close = 0; self.has_throwngren = FALSE; self.saveme_time = 0; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 500243cc..616b6659 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1096,7 +1096,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { else if (inp == 2) tGrenade.impulse = TF_GRENADE_2; - float time_base = client_to_global_time(remote_client_time()); + float time_base = remote_time(); tGrenade.nextthink = time_base + 0.8; if (gtype == GR_TYPE_CALTROP) tGrenade.heat = time_base + 0.5 + 0.5; diff --git a/ssqc/time.qc b/ssqc/time.qc index 3e735895..30c29a22 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -3,15 +3,14 @@ float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT) { switch (ct_type) { case CT_SLOW_PROJECTILE: - offset = min(offset, antilag_settings.max_projectile_slow_ping); + offset = min(offset, antilag_settings.max_projectile_slow_ping) / 2; break; } float target = self.client_time - offset; - if (self.last_remote_client_time > target) - return self.last_remote_client_time; - + target = max(target, self.last_remote_client_time); // prevent jitter self.last_remote_client_time = target; + return target; } @@ -20,6 +19,10 @@ inline float client_to_global_time(float ctime) { return time + (ctime - self.client_time); } +// Ping corrected `time`. +float remote_time(float ct_type = CT_NOEXTERNALEFFECT) { + return client_to_global_time(remote_client_time(ct_type)); +} void FO_CheckClientThink() { if (self.client_nextthink > 0 && self.client_time >= self.client_nextthink) { From 0c5d2843a5a2793a8a5fa6468f473f5ac30a66fb Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 21:52:17 -0700 Subject: [PATCH 1787/2474] Synchronize projectiles with server Takes over networking and representation of projectiles when enabled so that client side projectiles can be tightly matched. --- csqc/main.qc | 3 + csqc/weapon_predict.qc | 97 +++++++++++++++++------ share/weapon_predict.qc | 170 +++++++++++++++++++++++++++++++++++----- ssqc/client.qc | 8 +- ssqc/weapons.qc | 4 + 5 files changed, 236 insertions(+), 46 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3afd3da7..1e6b4c85 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -405,6 +405,9 @@ void(float isnew) CSQC_Ent_Update = { case ENT_WEAPONPRED: EntUpdate_WeaponPred(isnew); break; + case ENT_PROJECTILE: + EntUpdate_Projectile(isnew); + break; default: error("Unhandled CSQC entity\n"); return; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 7ba90047..54aa5c83 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,7 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// - static Slot InputToSlot(float input) { Slot result = FO_SlotByInput(input); return result; @@ -298,6 +297,8 @@ trail_table_entry trail_table[] = { float nail_trail; void PP_Init() { + InitFppProjectiles(); + for (float i = 0; i < trail_table.length; i++) { for (float j = 0; j < 2; j++) { trail_table_entry* entry = &trail_table[i]; @@ -309,8 +310,6 @@ void PP_Init() { entry->trail[j] = particleeffectnum(name); } } - - nail_trail = particleeffectnum("tr_spike"); } void PP_Cleanup(entity proj) { @@ -332,12 +331,12 @@ DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); float PP_PredrawActive() { - float delta = time - self.starttime; + float delta = time - self.s_time; - if (delta < 0) + if (delta < 0.05) return PREDRAW_NEXT; // Forward projection is bounded. - self.origin = self.s_origin + self.velocity * delta; + self.origin = self.s_origin + (self.velocity * delta); setorigin(self, self.origin); // we need to space out the particles incase we're running at very high fps @@ -352,7 +351,6 @@ float PP_PredrawActive() { if (self.traileffectnum) trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); - self.p_time = time + frametime; self.oldorigin = self.origin; } @@ -366,9 +364,10 @@ float PP_PredrawActive() { return PREDRAW_AUTOADD; } -float PP_Predraw() { - if (time > self.endtime + 0.05) { - PP_Cleanup(self); +float PP_PredrawPredicted() { + if (time < self.starttime || time > self.endtime) { + if (time > self.endtime + 0.05) + PP_Cleanup(self); return PREDRAW_NEXT; } @@ -378,35 +377,45 @@ float PP_Predraw() { DEFCVAR_FLOAT(r_rockettrail, 1); DEFCVAR_FLOAT(r_grenadetrail, 1); -int PP_FindTrail(int is_grenade) +int PP_FindTrail(entity e) { - float idx = (is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail)) - 1; - - if (idx >= 0 && idx < trail_table.length) - return trail_table[idx].trail[is_grenade]; + if (e.modelflags & (MF_GRENADE | MF_ROCKET)) { + float is_grenade = !!(e.modelflags & MF_GRENADE); + float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; + + if (idx >= 0 && idx < trail_table.length) + return trail_table[idx].trail[is_grenade]; + } else if (self.modelindex == fpp_nail.modelindex) { + return fpp_nail.trailindex; + } else if (self.modelindex == fpp_super_nail.modelindex) { + return fpp_super_nail.trailindex; + } return 0; } +static float PP_EPS = 0.05; + entity PP_CreateProjectile(fo_projectile* desc, vector offset) { entity proj = spawn(); // TODO: Communicate with server around this. // Note: We use true time here since the created projectiles exist outside of // our prediction. - float start_offset = max(0, pstate_pred.client_ping - 0.1); - proj.starttime = time + start_offset; - proj.endtime = time + pstate_pred.client_ping; + float start_offset = max(0, (pstate_pred.client_ping - 0.1) / 2); + proj.s_time = time + start_offset - 1*frametime/2; + proj.starttime = proj.s_time; + proj.endtime = time + pstate_pred.client_ping + PP_EPS; - proj.predraw = PP_Predraw; + proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_ENGINE; proj.p_time = 0; - proj.s_origin = pmove_org + offset + v_forward * 8; + proj.s_origin = pmove_org + offset + (v_forward * 8); proj.s_origin[2] += 16; proj.velocity = v_forward * desc->speed; - proj.oldorigin = proj.s_origin + frametime * proj.velocity; + proj.oldorigin = proj.s_origin + (0.05 * proj.velocity); proj.origin = proj.oldorigin; proj.angles = input_angles; proj.angles[0] *= -1; @@ -425,8 +434,7 @@ void PP_FireRocket(float is_soldier) { fo_projectile* desc = is_soldier ? &fpp_rocket : &fpp_incendiary; entity proj = PP_CreateProjectile(desc, [0, 0, 0]); - if (is_soldier) - proj.traileffectnum = PP_FindTrail(FALSE); + proj.traileffectnum = PP_FindTrail(proj); } void PP_FireNG(float off) { @@ -441,7 +449,7 @@ void PP_FireNG(float off) { } entity proj = PP_CreateProjectile(desc, offset); - proj.traileffectnum = nail_trail; + proj.traileffectnum = PP_FindTrail(proj); } void PP_Fire() { @@ -463,3 +471,44 @@ void PP_Fire() { case WEAP_INCENDIARY: PP_FireRocket(FALSE); break; } } + +DEFCVAR_FLOAT(pp_show_match_dist, 0); + +float PredProjectile_MatchProjectile() { + self.origin = self.s_origin + self.velocity * (time - self.s_time); + + entity proj; + for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { + if (proj.modelindex != self.modelindex) + continue; + + float diff = vlen(proj.origin - self.origin); + if (CVARF(pp_show_match_dist) == 1) + printf("Match D=%0.3f\n", diff); + if (diff > 100) // TODO: This should be much tighter.. but we got time. + continue; + + if (fabs(time - (proj.endtime - PP_EPS)) > PP_EPS * 0.9) + continue; + + self.oldorigin = proj.origin; // Mate up trails. + PP_Cleanup(proj); + + return TRUE; + } + + return FALSE; +} + +void InitProjPredEnt(entity pe) { + self.drawmask = MASK_ENGINE; + self.predraw = PP_PredrawActive; + + // Force modelflags refresh + setmodel(self, modelnameforindex(self.modelindex)); + + self.traileffectnum = PP_FindTrail(self); + self.oldorigin = self.s_origin; + + PredProjectile_MatchProjectile(); +} diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 48301ac0..8b93b335 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -1,4 +1,6 @@ #define ENT_WEAPONPRED 100 +#define ENT_PROJECTILE 101 + string wp_version = "v0"; enumflags { @@ -9,10 +11,17 @@ enumflags { FOWP_THINK, FOWP_TFSTATE, FOWP_WF, + FOWP_AF, FOWP_CLASS, FOWP_RELOAD, FOWP_RNG, }; + +enumflags { + FOPP_POS, + FOPP_INIT, +}; + #define FOWP_ALL 0xFFFF struct predict_tf_state { @@ -40,9 +49,15 @@ struct predict_tf_state { float firing; }; +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; + struct fo_projectile { float speed; string model; + + // Automatically initialized below this line. + int modelindex; + int trailindex; }; fo_projectile fpp_rocket = { PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl" }; @@ -50,27 +65,55 @@ fo_projectile fpp_incendiary = { 800, "progs/lavaball.mdl" }; fo_projectile fpp_nail = { 1500, "progs/spike.mdl" }; fo_projectile fpp_super_nail = { 1500, "progs/s_spike.mdl" }; -#ifdef SSQC -float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); -float CF_GetSetting(string ps_short, string ps_setting, string ps_default); +void InitFppProjectiles() { + fo_projectile* fpp_list[] = + { &fpp_rocket, &fpp_incendiary, &fpp_nail, &fpp_super_nail }; -static float GlobalEnable() { - return CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); + for (float i = 0; i < fpp_list.length; i++) { + fo_projectile* desc = fpp_list[i]; + desc->modelindex = getmodelindex(desc->model); + } } -static float GlobalDisable() { - return CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); +#ifdef SSQC + +struct weaponpred_settings_t { + float global_enable; + float global_disable; + float new_projectiles; +} weaponpred_settings; + +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +static float init_once; +void WeaponPred_Init() { + if (init_once) + return; + init_once = TRUE; + + printf("WeaponPred_Init\n"); + // Regular init is too late for this. + weaponpred_settings.global_enable = + CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); + weaponpred_settings.global_disable = + CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); + weaponpred_settings.new_projectiles = + CF_GetSetting("wpnp", "weapon_pred_new_projectiles", "off"); + + InitFppProjectiles(); } static float ClientEnable() { + WeaponPred_Init(); + // client_ping is not yet initialized. float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; - if (GlobalDisable() || ping < 40 * MSEC) + + if (weaponpred_settings.global_disable || ping < 40 * MSEC) return FALSE; - if (GlobalEnable()) + if (weaponpred_settings.global_enable) return TRUE; return FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "off"); @@ -140,7 +183,7 @@ predict_tf_state blank_state; void WeaponPred_Update(entity player) { float mask = FOWP_CTIME; - if (time - player.last_full_predict_refresh > 1000 * MSEC) { + if (time - player.last_full_predict_refresh > 5000 * MSEC) { player.predict_state = blank_state; player.last_full_predict_refresh = time; } @@ -151,7 +194,8 @@ void WeaponPred_Update(entity player) { M1(FOWP_CLASS, playerclass); M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); M1(FOWP_TFSTATE, tfstate); - M2(FOWP_WF, attack_finished, weaponframe); + M1(FOWP_WF, weaponframe); + M1(FOWP_AF, attack_finished); M2(FOWP_THINK, client_nextthink, client_thinkindex); M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) M1(FOWP_RELOAD, reload_finished) @@ -181,7 +225,7 @@ float WP_SendEntity(entity to_player, float sendflags) { #else float() ReadByte = #360; float() ReadFloat = #367; -void InitPredEnt(entity e); +void InitWeapPredEnt(entity e); #define COMM(_type, _field) pstate_server.##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { @@ -212,10 +256,13 @@ void EntUpdate_WeaponPred(float isnew) { } if (sendflags & FOWP_WF) { - COMM(Float, attack_finished); COMM(Byte, weaponframe); } + if (sendflags & FOWP_AF) { + COMM(Float, attack_finished); + } + if (sendflags & FOWP_CLIP) { COMM(Byte, clip_fired[0]); COMM(Byte, clip_fired[1]); @@ -233,16 +280,78 @@ void EntUpdate_WeaponPred(float isnew) { return TRUE; #else if (isnew) - InitPredEnt(self); + InitWeapPredEnt(self); +#endif +} +#undef COMM + + +#ifdef SSQC +#define COMM(_type, _field) Write##_type(MSG_ENTITY, self.##_field) +#define COMMD(_type, _dest, _field) COMM(_type, _field) +#define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) +float PP_SendEntity(entity to_player, float sendflags) { + WriteByte(MSG_ENTITY, ENT_PROJECTILE); + WriteByte(MSG_ENTITY, sendflags); +#else + +float() ReadByte = #360; +float() ReadShort = #362; +float() ReadCoord = #364; +float() ReadAngle = #365; +float() ReadFloat = #367; + +void InitProjPredEnt(entity e); + +.vector s_origin; +.float s_time; + +#define COMMD(_type, _dest, _field) self.##_dest = Read##_type() +#define COMMO(_type, _dest, _src) ##_dest = Read##_type() +#define COMM(_type, _field) COMMD(_type, _field, _field) +void InitProjPredEnt(entity pe); + +void EntUpdate_Projectile(float isnew) { + float sendflags = readbyte(); +#endif + if (sendflags & FOPP_POS) { + COMMD(Coord, s_origin[0], origin[0]); + COMMD(Coord, s_origin[1], origin[1]); + COMMD(Coord, s_origin[2], origin[2]); + + COMM(Coord, velocity[0]); + COMM(Coord, velocity[1]); + COMM(Coord, velocity[2]); + + COMMO(Float, self.s_time, time); + } + + if (sendflags & FOPP_INIT) { + COMM(Short, modelindex); + COMM(Short, effects); + + COMM(Angle, angles[0]); + COMM(Angle, angles[1]); + COMM(Angle, angles[2]); + } + +#ifdef SSQC + return TRUE; +#else + if (isnew) + InitProjPredEnt(self); #endif } +#undef COMMD +#undef COMMO +#undef COMM #ifdef SSQC inline float WeaponPred_Active(entity player) { return player.weapon_pred_enabled; } -void WeaponPred_Init(entity player) { +void WeaponPred_InitPlayer(entity player) { if (!ClientEnable()) { // Server side is once per connect. player.weapon_pred_enabled = FALSE; return; @@ -259,8 +368,10 @@ void WeaponPred_Init(entity player) { setorigin(pe, [0, 0, 0]); player.predict_entity = pe; - sprint(self, PRINT_HIGH, + sprint(player, PRINT_HIGH, "FortressOne: Weapon Prediction Active ", wp_version, "\n"); + sprint(player, PRINT_HIGH, "FortressOne: New projectiles ", + weaponpred_settings.new_projectiles ? "enabled\n" : "disabled\n"); } void WeaponPred_TearDown(entity player) { @@ -281,6 +392,16 @@ void WeaponPred_DoServerClientThink() { self->client_time = held_client_time; } } + +void PredProj_Add(entity mis) { + mis.dimension_seen = DMN_NOFLASH; + + if (!weaponpred_settings.new_projectiles) + return; + + mis.SendEntity = PP_SendEntity; + mis.SendFlags = 255; +} #endif #ifdef CSQC @@ -325,6 +446,8 @@ void WP_UpdateViewModel() { void WP_Frame(); void WP_DoClientThink(); +float pf, ef; + float WP_ClientThink() { pstate_pred = pstate_server; @@ -332,11 +455,16 @@ float WP_ClientThink() { int eframe = clientcommandframe; for(; pframe <= eframe; pframe++) { int success = getinputstate(pframe); - if (!success || input_timelength <= 0) + if (!success || input_timelength <= 0) { + if (pframe < eframe - 1) + printf("ended at %d/%d\n", (float)pframe, (float)eframe); break; + } makevectors(input_angles); + pf = pframe; + ef = eframe; - if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { + if (pframe >= eframe - 1 && pframe > pengine.last_effectframe) { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; } else { @@ -365,7 +493,8 @@ float WP_ClientThink() { } void PP_Init(); -void InitPredEnt(entity pe) { + +void InitWeapPredEnt(entity pe) { pe.predraw = WP_ClientThink; self.drawmask = MASK_PRED_VIEWMODEL; @@ -374,4 +503,7 @@ void InitPredEnt(entity pe) { PP_Init(); FO_WP_Init(TRUE); } + +float PP_Predraw(); + #endif diff --git a/ssqc/client.qc b/ssqc/client.qc index 4fe5d941..4535363d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -72,7 +72,8 @@ void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); void StopAssCan(); -void WeaponPred_Init(entity player); +void WeaponPred_Init(); +void WeaponPred_InitPlayer(entity player); void WeaponPred_TearDown(entity player); void (float n) CSEv_SetPlayerImpulse_f = { @@ -1032,6 +1033,7 @@ void () DecodeLevelParms = { // Must be after we've set up conditional options (e.g. hwguy reload). FO_Weapons_Init(); + InitFppProjectiles(); } if (parm11) @@ -2740,7 +2742,7 @@ void () PlayerPreThink = { // Catch all. FO_WeapState ws; FO_FillCurrentWeapState(&ws); - if ((self.client_time > self.attack_finished) && + if ((self.client_time >= self.attack_finished) && (ws.weapon > WEAP_AXE) && ((ws->wi)->ammo_type != AMMO_NONE)) { if (*ws->ammo_remaining == 0) W_ChangeToBestWeapon(); @@ -3064,7 +3066,7 @@ void () ClientConnect = { } if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - WeaponPred_Init(self); + WeaponPred_InitPlayer(self); InitAllStatuses(self); UpdateClientMOTD(self); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 364b2e84..87ff4284 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1113,6 +1113,8 @@ void () W_FireRocket = { if (project_weapons) { AL_ProjectProjectile(newmis); } + + PredProj_Add(newmis); }; void (entity from, float damage) LightningHit = { @@ -1360,6 +1362,8 @@ void (vector org, vector dir) launch_spike = { if (project_weapons) { AL_ProjectProjectile(newmis); } + + PredProj_Add(newmis); }; void () W_FireSuperSpikes = { From d58ac9f5d0e2d4a66ce95602bb005d1bc59c44f6 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Oct 2022 21:52:17 -0700 Subject: [PATCH 1788/2474] Synchronize projectiles with server Takes over networking and representation of projectiles when enabled so that client side projectiles can be tightly matched. --- csqc/main.qc | 3 + csqc/weapon_predict.qc | 97 +++++++++++++++++------ share/weapon_predict.qc | 170 +++++++++++++++++++++++++++++++++++----- ssqc/client.qc | 8 +- ssqc/weapons.qc | 8 +- 5 files changed, 238 insertions(+), 48 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3afd3da7..1e6b4c85 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -405,6 +405,9 @@ void(float isnew) CSQC_Ent_Update = { case ENT_WEAPONPRED: EntUpdate_WeaponPred(isnew); break; + case ENT_PROJECTILE: + EntUpdate_Projectile(isnew); + break; default: error("Unhandled CSQC entity\n"); return; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 7ba90047..54aa5c83 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,7 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// - static Slot InputToSlot(float input) { Slot result = FO_SlotByInput(input); return result; @@ -298,6 +297,8 @@ trail_table_entry trail_table[] = { float nail_trail; void PP_Init() { + InitFppProjectiles(); + for (float i = 0; i < trail_table.length; i++) { for (float j = 0; j < 2; j++) { trail_table_entry* entry = &trail_table[i]; @@ -309,8 +310,6 @@ void PP_Init() { entry->trail[j] = particleeffectnum(name); } } - - nail_trail = particleeffectnum("tr_spike"); } void PP_Cleanup(entity proj) { @@ -332,12 +331,12 @@ DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); float PP_PredrawActive() { - float delta = time - self.starttime; + float delta = time - self.s_time; - if (delta < 0) + if (delta < 0.05) return PREDRAW_NEXT; // Forward projection is bounded. - self.origin = self.s_origin + self.velocity * delta; + self.origin = self.s_origin + (self.velocity * delta); setorigin(self, self.origin); // we need to space out the particles incase we're running at very high fps @@ -352,7 +351,6 @@ float PP_PredrawActive() { if (self.traileffectnum) trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); - self.p_time = time + frametime; self.oldorigin = self.origin; } @@ -366,9 +364,10 @@ float PP_PredrawActive() { return PREDRAW_AUTOADD; } -float PP_Predraw() { - if (time > self.endtime + 0.05) { - PP_Cleanup(self); +float PP_PredrawPredicted() { + if (time < self.starttime || time > self.endtime) { + if (time > self.endtime + 0.05) + PP_Cleanup(self); return PREDRAW_NEXT; } @@ -378,35 +377,45 @@ float PP_Predraw() { DEFCVAR_FLOAT(r_rockettrail, 1); DEFCVAR_FLOAT(r_grenadetrail, 1); -int PP_FindTrail(int is_grenade) +int PP_FindTrail(entity e) { - float idx = (is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail)) - 1; - - if (idx >= 0 && idx < trail_table.length) - return trail_table[idx].trail[is_grenade]; + if (e.modelflags & (MF_GRENADE | MF_ROCKET)) { + float is_grenade = !!(e.modelflags & MF_GRENADE); + float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; + + if (idx >= 0 && idx < trail_table.length) + return trail_table[idx].trail[is_grenade]; + } else if (self.modelindex == fpp_nail.modelindex) { + return fpp_nail.trailindex; + } else if (self.modelindex == fpp_super_nail.modelindex) { + return fpp_super_nail.trailindex; + } return 0; } +static float PP_EPS = 0.05; + entity PP_CreateProjectile(fo_projectile* desc, vector offset) { entity proj = spawn(); // TODO: Communicate with server around this. // Note: We use true time here since the created projectiles exist outside of // our prediction. - float start_offset = max(0, pstate_pred.client_ping - 0.1); - proj.starttime = time + start_offset; - proj.endtime = time + pstate_pred.client_ping; + float start_offset = max(0, (pstate_pred.client_ping - 0.1) / 2); + proj.s_time = time + start_offset - 1*frametime/2; + proj.starttime = proj.s_time; + proj.endtime = time + pstate_pred.client_ping + PP_EPS; - proj.predraw = PP_Predraw; + proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_ENGINE; proj.p_time = 0; - proj.s_origin = pmove_org + offset + v_forward * 8; + proj.s_origin = pmove_org + offset + (v_forward * 8); proj.s_origin[2] += 16; proj.velocity = v_forward * desc->speed; - proj.oldorigin = proj.s_origin + frametime * proj.velocity; + proj.oldorigin = proj.s_origin + (0.05 * proj.velocity); proj.origin = proj.oldorigin; proj.angles = input_angles; proj.angles[0] *= -1; @@ -425,8 +434,7 @@ void PP_FireRocket(float is_soldier) { fo_projectile* desc = is_soldier ? &fpp_rocket : &fpp_incendiary; entity proj = PP_CreateProjectile(desc, [0, 0, 0]); - if (is_soldier) - proj.traileffectnum = PP_FindTrail(FALSE); + proj.traileffectnum = PP_FindTrail(proj); } void PP_FireNG(float off) { @@ -441,7 +449,7 @@ void PP_FireNG(float off) { } entity proj = PP_CreateProjectile(desc, offset); - proj.traileffectnum = nail_trail; + proj.traileffectnum = PP_FindTrail(proj); } void PP_Fire() { @@ -463,3 +471,44 @@ void PP_Fire() { case WEAP_INCENDIARY: PP_FireRocket(FALSE); break; } } + +DEFCVAR_FLOAT(pp_show_match_dist, 0); + +float PredProjectile_MatchProjectile() { + self.origin = self.s_origin + self.velocity * (time - self.s_time); + + entity proj; + for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { + if (proj.modelindex != self.modelindex) + continue; + + float diff = vlen(proj.origin - self.origin); + if (CVARF(pp_show_match_dist) == 1) + printf("Match D=%0.3f\n", diff); + if (diff > 100) // TODO: This should be much tighter.. but we got time. + continue; + + if (fabs(time - (proj.endtime - PP_EPS)) > PP_EPS * 0.9) + continue; + + self.oldorigin = proj.origin; // Mate up trails. + PP_Cleanup(proj); + + return TRUE; + } + + return FALSE; +} + +void InitProjPredEnt(entity pe) { + self.drawmask = MASK_ENGINE; + self.predraw = PP_PredrawActive; + + // Force modelflags refresh + setmodel(self, modelnameforindex(self.modelindex)); + + self.traileffectnum = PP_FindTrail(self); + self.oldorigin = self.s_origin; + + PredProjectile_MatchProjectile(); +} diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 48301ac0..8b93b335 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -1,4 +1,6 @@ #define ENT_WEAPONPRED 100 +#define ENT_PROJECTILE 101 + string wp_version = "v0"; enumflags { @@ -9,10 +11,17 @@ enumflags { FOWP_THINK, FOWP_TFSTATE, FOWP_WF, + FOWP_AF, FOWP_CLASS, FOWP_RELOAD, FOWP_RNG, }; + +enumflags { + FOPP_POS, + FOPP_INIT, +}; + #define FOWP_ALL 0xFFFF struct predict_tf_state { @@ -40,9 +49,15 @@ struct predict_tf_state { float firing; }; +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; + struct fo_projectile { float speed; string model; + + // Automatically initialized below this line. + int modelindex; + int trailindex; }; fo_projectile fpp_rocket = { PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl" }; @@ -50,27 +65,55 @@ fo_projectile fpp_incendiary = { 800, "progs/lavaball.mdl" }; fo_projectile fpp_nail = { 1500, "progs/spike.mdl" }; fo_projectile fpp_super_nail = { 1500, "progs/s_spike.mdl" }; -#ifdef SSQC -float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, string ps_default); -float CF_GetSetting(string ps_short, string ps_setting, string ps_default); +void InitFppProjectiles() { + fo_projectile* fpp_list[] = + { &fpp_rocket, &fpp_incendiary, &fpp_nail, &fpp_super_nail }; -static float GlobalEnable() { - return CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); + for (float i = 0; i < fpp_list.length; i++) { + fo_projectile* desc = fpp_list[i]; + desc->modelindex = getmodelindex(desc->model); + } } -static float GlobalDisable() { - return CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); +#ifdef SSQC + +struct weaponpred_settings_t { + float global_enable; + float global_disable; + float new_projectiles; +} weaponpred_settings; + +float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +static float init_once; +void WeaponPred_Init() { + if (init_once) + return; + init_once = TRUE; + + printf("WeaponPred_Init\n"); + // Regular init is too late for this. + weaponpred_settings.global_enable = + CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); + weaponpred_settings.global_disable = + CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); + weaponpred_settings.new_projectiles = + CF_GetSetting("wpnp", "weapon_pred_new_projectiles", "off"); + + InitFppProjectiles(); } static float ClientEnable() { + WeaponPred_Init(); + // client_ping is not yet initialized. float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; - if (GlobalDisable() || ping < 40 * MSEC) + + if (weaponpred_settings.global_disable || ping < 40 * MSEC) return FALSE; - if (GlobalEnable()) + if (weaponpred_settings.global_enable) return TRUE; return FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "off"); @@ -140,7 +183,7 @@ predict_tf_state blank_state; void WeaponPred_Update(entity player) { float mask = FOWP_CTIME; - if (time - player.last_full_predict_refresh > 1000 * MSEC) { + if (time - player.last_full_predict_refresh > 5000 * MSEC) { player.predict_state = blank_state; player.last_full_predict_refresh = time; } @@ -151,7 +194,8 @@ void WeaponPred_Update(entity player) { M1(FOWP_CLASS, playerclass); M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); M1(FOWP_TFSTATE, tfstate); - M2(FOWP_WF, attack_finished, weaponframe); + M1(FOWP_WF, weaponframe); + M1(FOWP_AF, attack_finished); M2(FOWP_THINK, client_nextthink, client_thinkindex); M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) M1(FOWP_RELOAD, reload_finished) @@ -181,7 +225,7 @@ float WP_SendEntity(entity to_player, float sendflags) { #else float() ReadByte = #360; float() ReadFloat = #367; -void InitPredEnt(entity e); +void InitWeapPredEnt(entity e); #define COMM(_type, _field) pstate_server.##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { @@ -212,10 +256,13 @@ void EntUpdate_WeaponPred(float isnew) { } if (sendflags & FOWP_WF) { - COMM(Float, attack_finished); COMM(Byte, weaponframe); } + if (sendflags & FOWP_AF) { + COMM(Float, attack_finished); + } + if (sendflags & FOWP_CLIP) { COMM(Byte, clip_fired[0]); COMM(Byte, clip_fired[1]); @@ -233,16 +280,78 @@ void EntUpdate_WeaponPred(float isnew) { return TRUE; #else if (isnew) - InitPredEnt(self); + InitWeapPredEnt(self); +#endif +} +#undef COMM + + +#ifdef SSQC +#define COMM(_type, _field) Write##_type(MSG_ENTITY, self.##_field) +#define COMMD(_type, _dest, _field) COMM(_type, _field) +#define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) +float PP_SendEntity(entity to_player, float sendflags) { + WriteByte(MSG_ENTITY, ENT_PROJECTILE); + WriteByte(MSG_ENTITY, sendflags); +#else + +float() ReadByte = #360; +float() ReadShort = #362; +float() ReadCoord = #364; +float() ReadAngle = #365; +float() ReadFloat = #367; + +void InitProjPredEnt(entity e); + +.vector s_origin; +.float s_time; + +#define COMMD(_type, _dest, _field) self.##_dest = Read##_type() +#define COMMO(_type, _dest, _src) ##_dest = Read##_type() +#define COMM(_type, _field) COMMD(_type, _field, _field) +void InitProjPredEnt(entity pe); + +void EntUpdate_Projectile(float isnew) { + float sendflags = readbyte(); +#endif + if (sendflags & FOPP_POS) { + COMMD(Coord, s_origin[0], origin[0]); + COMMD(Coord, s_origin[1], origin[1]); + COMMD(Coord, s_origin[2], origin[2]); + + COMM(Coord, velocity[0]); + COMM(Coord, velocity[1]); + COMM(Coord, velocity[2]); + + COMMO(Float, self.s_time, time); + } + + if (sendflags & FOPP_INIT) { + COMM(Short, modelindex); + COMM(Short, effects); + + COMM(Angle, angles[0]); + COMM(Angle, angles[1]); + COMM(Angle, angles[2]); + } + +#ifdef SSQC + return TRUE; +#else + if (isnew) + InitProjPredEnt(self); #endif } +#undef COMMD +#undef COMMO +#undef COMM #ifdef SSQC inline float WeaponPred_Active(entity player) { return player.weapon_pred_enabled; } -void WeaponPred_Init(entity player) { +void WeaponPred_InitPlayer(entity player) { if (!ClientEnable()) { // Server side is once per connect. player.weapon_pred_enabled = FALSE; return; @@ -259,8 +368,10 @@ void WeaponPred_Init(entity player) { setorigin(pe, [0, 0, 0]); player.predict_entity = pe; - sprint(self, PRINT_HIGH, + sprint(player, PRINT_HIGH, "FortressOne: Weapon Prediction Active ", wp_version, "\n"); + sprint(player, PRINT_HIGH, "FortressOne: New projectiles ", + weaponpred_settings.new_projectiles ? "enabled\n" : "disabled\n"); } void WeaponPred_TearDown(entity player) { @@ -281,6 +392,16 @@ void WeaponPred_DoServerClientThink() { self->client_time = held_client_time; } } + +void PredProj_Add(entity mis) { + mis.dimension_seen = DMN_NOFLASH; + + if (!weaponpred_settings.new_projectiles) + return; + + mis.SendEntity = PP_SendEntity; + mis.SendFlags = 255; +} #endif #ifdef CSQC @@ -325,6 +446,8 @@ void WP_UpdateViewModel() { void WP_Frame(); void WP_DoClientThink(); +float pf, ef; + float WP_ClientThink() { pstate_pred = pstate_server; @@ -332,11 +455,16 @@ float WP_ClientThink() { int eframe = clientcommandframe; for(; pframe <= eframe; pframe++) { int success = getinputstate(pframe); - if (!success || input_timelength <= 0) + if (!success || input_timelength <= 0) { + if (pframe < eframe - 1) + printf("ended at %d/%d\n", (float)pframe, (float)eframe); break; + } makevectors(input_angles); + pf = pframe; + ef = eframe; - if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { + if (pframe >= eframe - 1 && pframe > pengine.last_effectframe) { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; } else { @@ -365,7 +493,8 @@ float WP_ClientThink() { } void PP_Init(); -void InitPredEnt(entity pe) { + +void InitWeapPredEnt(entity pe) { pe.predraw = WP_ClientThink; self.drawmask = MASK_PRED_VIEWMODEL; @@ -374,4 +503,7 @@ void InitPredEnt(entity pe) { PP_Init(); FO_WP_Init(TRUE); } + +float PP_Predraw(); + #endif diff --git a/ssqc/client.qc b/ssqc/client.qc index 4fe5d941..4535363d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -72,7 +72,8 @@ void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); void StopAssCan(); -void WeaponPred_Init(entity player); +void WeaponPred_Init(); +void WeaponPred_InitPlayer(entity player); void WeaponPred_TearDown(entity player); void (float n) CSEv_SetPlayerImpulse_f = { @@ -1032,6 +1033,7 @@ void () DecodeLevelParms = { // Must be after we've set up conditional options (e.g. hwguy reload). FO_Weapons_Init(); + InitFppProjectiles(); } if (parm11) @@ -2740,7 +2742,7 @@ void () PlayerPreThink = { // Catch all. FO_WeapState ws; FO_FillCurrentWeapState(&ws); - if ((self.client_time > self.attack_finished) && + if ((self.client_time >= self.attack_finished) && (ws.weapon > WEAP_AXE) && ((ws->wi)->ammo_type != AMMO_NONE)) { if (*ws->ammo_remaining == 0) W_ChangeToBestWeapon(); @@ -3064,7 +3066,7 @@ void () ClientConnect = { } if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - WeaponPred_Init(self); + WeaponPred_InitPlayer(self); InitAllStatuses(self); UpdateClientMOTD(self); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 364b2e84..f5ae58b7 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1113,6 +1113,8 @@ void () W_FireRocket = { if (project_weapons) { AL_ProjectProjectile(newmis); } + + PredProj_Add(newmis); }; void (entity from, float damage) LightningHit = { @@ -1360,6 +1362,8 @@ void (vector org, vector dir) launch_spike = { if (project_weapons) { AL_ProjectProjectile(newmis); } + + PredProj_Add(newmis); }; void () W_FireSuperSpikes = { @@ -2547,6 +2551,8 @@ void () W_WeaponFrame = { return; } + FO_ReloadFrame(); + if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 10) { Menu_Input(self.impulse); @@ -2568,8 +2574,6 @@ void () W_WeaponFrame = { return; } - if (FO_ReloadFrame()) - return; if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && From fe7feff9118fdce4fe6a0fd0aeac00158ad4b4cd Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 12 Oct 2022 17:12:19 -0700 Subject: [PATCH 1789/2474] Fix reload impulse blocking Pulling reload out of a timer was leading to an early return that blocked some impulses. This was not obvious since the new button commands directly invoke them and were not blocked. Fix this. We should also make the buttons trigger the standard impulse paths so this discrepancy isn't possible in the future (particularly the inverse, a command that should be blocked by reload, but isn't.) --- share/weapons.qc | 10 ++++------ ssqc/client.qc | 2 ++ ssqc/weapons.qc | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/share/weapons.qc b/share/weapons.qc index 9bf9915c..9c33daa5 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -376,16 +376,16 @@ void (float att_delay) Attack_Finished; // Hack until we fix Status_Refresh() to not be awful. .float last_still_loading; -float FO_ReloadFrame() { +void FO_ReloadFrame() { if (self.tfstate & TFSTATE_RELOADING == 0) - return FALSE; + return; FO_WeapState ws; FO_FillWeapState(self, self.current_slot, &ws); FO_WeapInfo* wi = ws.wi; if (wi->weapon == WEAP_NONE) - return FALSE; + return; if (self.client_time >= self.reload_finished) { self.tfstate &= ~TFSTATE_RELOADING; @@ -395,7 +395,7 @@ float FO_ReloadFrame() { Status_Refresh(self); sprint(self, PRINT_HIGH, "Finished reloading\n"); - return FALSE; + return; } float still_loading = FO_NumClipStillLoading(wi, self.client_time, @@ -404,8 +404,6 @@ float FO_ReloadFrame() { self.last_still_loading = still_loading; Status_Refresh(self); } - - return TRUE; } float FO_CanReload(Slot slot) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 4535363d..48359378 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2969,11 +2969,13 @@ void () PlayerPostThink = { RefreshStatusBar(self); CheckPowerups(); + FO_ReloadFrame(); W_WeaponFrame(); //TeamFortress_CheckforCheats(); //TeamFortress_SetSpeed(self); } else { CheckPowerups(); + FO_ReloadFrame(); ButtonFrame(); W_WeaponFrame(); if (self.motd <= 400) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f5ae58b7..35dd984e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2551,8 +2551,6 @@ void () W_WeaponFrame = { return; } - FO_ReloadFrame(); - if (self.menu_input) { if (self.impulse > 0 && self.impulse <= 10) { Menu_Input(self.impulse); From ac072ceabf975ee18df22f008ada075e5d95191b Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 12 Oct 2022 17:58:06 -0700 Subject: [PATCH 1790/2474] Trail particles for predicted and new projectiles These worked for rockets and nails but now also for nails and incendiary. --- csqc/weapon_predict.qc | 13 ++++++++----- share/weapon_predict.qc | 21 +++++++++++---------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 54aa5c83..8424381a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -385,10 +385,12 @@ int PP_FindTrail(entity e) if (idx >= 0 && idx < trail_table.length) return trail_table[idx].trail[is_grenade]; - } else if (self.modelindex == fpp_nail.modelindex) { - return fpp_nail.trailindex; - } else if (self.modelindex == fpp_super_nail.modelindex) { - return fpp_super_nail.trailindex; + } + + fo_projectile* fpp_list[] = { &fpp_incendiary, &fpp_nail, &fpp_super_nail }; + for (float i = 0; i < fpp_list.length; i++) { + fo_projectile* desc = fpp_list[i]; + if (e.modelindex == desc->modelindex) return desc->trailindex; } return 0; @@ -500,7 +502,8 @@ float PredProjectile_MatchProjectile() { return FALSE; } -void InitProjPredEnt(entity pe) { +// Called on `self`. +void InitProjPredEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 8b93b335..ecce5be2 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -54,16 +54,17 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; struct fo_projectile { float speed; string model; + string trail; // Automatically initialized below this line. - int modelindex; - int trailindex; + float modelindex; + float trailindex; }; -fo_projectile fpp_rocket = { PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl" }; -fo_projectile fpp_incendiary = { 800, "progs/lavaball.mdl" }; -fo_projectile fpp_nail = { 1500, "progs/spike.mdl" }; -fo_projectile fpp_super_nail = { 1500, "progs/s_spike.mdl" }; +fo_projectile fpp_rocket = { PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl", "" }; +fo_projectile fpp_incendiary = { 800, "progs/lavaball.mdl", "t_lavaball" }; +fo_projectile fpp_nail = { 1500, "progs/spike.mdl", "tr_spike" }; +fo_projectile fpp_super_nail = { 1500, "progs/s_spike.mdl", "tr_spike" }; void InitFppProjectiles() { @@ -73,6 +74,8 @@ void InitFppProjectiles() { for (float i = 0; i < fpp_list.length; i++) { fo_projectile* desc = fpp_list[i]; desc->modelindex = getmodelindex(desc->model); + if (desc->trail != "") + desc->trailindex = particleeffectnum(strcat("fo-particles.",desc->trail)); } } @@ -91,7 +94,6 @@ void WeaponPred_Init() { return; init_once = TRUE; - printf("WeaponPred_Init\n"); // Regular init is too late for this. weaponpred_settings.global_enable = CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); @@ -301,7 +303,7 @@ float() ReadCoord = #364; float() ReadAngle = #365; float() ReadFloat = #367; -void InitProjPredEnt(entity e); +void InitProjPredEnt(); .vector s_origin; .float s_time; @@ -309,7 +311,6 @@ void InitProjPredEnt(entity e); #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() #define COMMO(_type, _dest, _src) ##_dest = Read##_type() #define COMM(_type, _field) COMMD(_type, _field, _field) -void InitProjPredEnt(entity pe); void EntUpdate_Projectile(float isnew) { float sendflags = readbyte(); @@ -339,7 +340,7 @@ void EntUpdate_Projectile(float isnew) { return TRUE; #else if (isnew) - InitProjPredEnt(self); + InitProjPredEnt(); #endif } #undef COMMD From dd6d376727dd6715eb1c7627840287b0cf58e01c Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 13 Oct 2022 03:13:10 -0700 Subject: [PATCH 1791/2474] Improve and auto-tune prediction offsets Matching for rockets is now much more precise. --- csqc/weapon_predict.qc | 59 +++++++++++++++++++++++++++-------------- share/weapon_predict.qc | 21 ++++++++------- ssqc/antilag.qc | 1 + ssqc/weapons.qc | 6 ++--- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 8424381a..1b15317c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -270,8 +270,6 @@ void WP_Frame() { entity predicted_projectiles; .entity pred_next, pred_prev; -.vector s_origin; - .float starttime, endtime, p_time; .float traileffectnum; @@ -296,6 +294,8 @@ trail_table_entry trail_table[] = { float nail_trail; +float corr_s; // Auto-tuning correction factor. + void PP_Init() { InitFppProjectiles(); @@ -310,6 +310,8 @@ void PP_Init() { entry->trail[j] = particleeffectnum(name); } } + + corr_s = 0.04; // Ballpark factor for many common pings. } void PP_Cleanup(entity proj) { @@ -333,9 +335,6 @@ DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); float PP_PredrawActive() { float delta = time - self.s_time; - if (delta < 0.05) - return PREDRAW_NEXT; // Forward projection is bounded. - self.origin = self.s_origin + (self.velocity * delta); setorigin(self, self.origin); @@ -401,24 +400,30 @@ static float PP_EPS = 0.05; entity PP_CreateProjectile(fo_projectile* desc, vector offset) { entity proj = spawn(); + float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000.0; + // TODO: Communicate with server around this. // Note: We use true time here since the created projectiles exist outside of // our prediction. - float start_offset = max(0, (pstate_pred.client_ping - 0.1) / 2); - proj.s_time = time + start_offset - 1*frametime/2; - proj.starttime = proj.s_time; + float start_offset = max(0, pstate_pred.client_ping - 0.1) + // Server project + max(0, ping - pstate_pred.client_ping); // Uncorrected error + + proj.s_time = time + start_offset / 2 + corr_s; + + proj.starttime = proj.s_time + 2/77.0; proj.endtime = time + pstate_pred.client_ping + PP_EPS; proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_ENGINE; + setsize(proj, [0,0,0], [0,0,0]); proj.p_time = 0; - proj.s_origin = pmove_org + offset + (v_forward * 8); + proj.s_origin = pmove_org + offset; proj.s_origin[2] += 16; proj.velocity = v_forward * desc->speed; - proj.oldorigin = proj.s_origin + (0.05 * proj.velocity); - proj.origin = proj.oldorigin; + proj.oldorigin = proj.s_origin; + setorigin(proj, proj.oldorigin); proj.angles = input_angles; proj.angles[0] *= -1; @@ -435,7 +440,10 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { void PP_FireRocket(float is_soldier) { fo_projectile* desc = is_soldier ? &fpp_rocket : &fpp_incendiary; - entity proj = PP_CreateProjectile(desc, [0, 0, 0]); + vector ovf = v_forward; + makevectors(input_angles); + ASSERTF_EQ(vlen(ovf - v_forward), 0); + entity proj = PP_CreateProjectile(desc, v_forward * 8); proj.traileffectnum = PP_FindTrail(proj); } @@ -477,6 +485,8 @@ void PP_Fire() { DEFCVAR_FLOAT(pp_show_match_dist, 0); float PredProjectile_MatchProjectile() { + float delta_t = time - self.s_time; + vector delta_p = self.velocity * delta_t; self.origin = self.s_origin + self.velocity * (time - self.s_time); entity proj; @@ -484,18 +494,26 @@ float PredProjectile_MatchProjectile() { if (proj.modelindex != self.modelindex) continue; - float diff = vlen(proj.origin - self.origin); - if (CVARF(pp_show_match_dist) == 1) - printf("Match D=%0.3f\n", diff); - if (diff > 100) // TODO: This should be much tighter.. but we got time. + if (fabs(proj.s_time - self.s_time) > 0.15) continue; - if (fabs(time - (proj.endtime - PP_EPS)) > PP_EPS * 0.9) - continue; + float diff2 = self.s_time - proj.s_time; + float sgn = diff2 > 0 ? 1 : -1; + float c_s = 0; + if (fabs(diff2) > 1/154.0) + c_s = corr_s + diff2/2 + sgn * 1/77.0; + corr_s = corr_s ? corr_s * 0.9 + 0.1 * c_s : c_s; self.oldorigin = proj.origin; // Mate up trails. - PP_Cleanup(proj); + if (CVARF(pp_show_match_dist) == 1) { + proj.origin = proj.s_origin + delta_p; + printf(" p_diff = %0.3f / %0.3f\n", + vlen(proj.s_origin - self.s_origin), vlen(proj.origin - self.origin)); + printf(" D2=%0.4f c_s=%0.4f corr_s=%0.4f\n", diff2, c_s, corr_s); + } + + PP_Cleanup(proj); return TRUE; } @@ -513,5 +531,6 @@ void InitProjPredEnt() { self.traileffectnum = PP_FindTrail(self); self.oldorigin = self.s_origin; - PredProjectile_MatchProjectile(); + if (self.owner_entnum == player_localentnum) + PredProjectile_MatchProjectile(); } diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index ecce5be2..63e3b708 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -289,6 +289,8 @@ void EntUpdate_WeaponPred(float isnew) { #ifdef SSQC +.float s_time; +.vector s_origin; #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.##_field) #define COMMD(_type, _dest, _field) COMM(_type, _field) #define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) @@ -307,6 +309,7 @@ void InitProjPredEnt(); .vector s_origin; .float s_time; +.float owner_entnum; #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() #define COMMO(_type, _dest, _src) ##_dest = Read##_type() @@ -316,15 +319,15 @@ void EntUpdate_Projectile(float isnew) { float sendflags = readbyte(); #endif if (sendflags & FOPP_POS) { - COMMD(Coord, s_origin[0], origin[0]); - COMMD(Coord, s_origin[1], origin[1]); - COMMD(Coord, s_origin[2], origin[2]); + COMM(Coord, s_origin[0]); + COMM(Coord, s_origin[1]); + COMM(Coord, s_origin[2]); COMM(Coord, velocity[0]); COMM(Coord, velocity[1]); COMM(Coord, velocity[2]); - COMMO(Float, self.s_time, time); + COMM(Float, s_time); } if (sendflags & FOPP_INIT) { @@ -337,8 +340,10 @@ void EntUpdate_Projectile(float isnew) { } #ifdef SSQC + WriteEntity(MSG_ENTITY, self.owner); return TRUE; #else + self.owner_entnum = readentitynum(); if (isnew) InitProjPredEnt(); #endif @@ -400,6 +405,7 @@ void PredProj_Add(entity mis) { if (!weaponpred_settings.new_projectiles) return; + mis.s_origin = mis.origin; mis.SendEntity = PP_SendEntity; mis.SendFlags = 255; } @@ -455,12 +461,9 @@ float WP_ClientThink() { int pframe = servercommandframe + 1; int eframe = clientcommandframe; for(; pframe <= eframe; pframe++) { - int success = getinputstate(pframe); - if (!success || input_timelength <= 0) { - if (pframe < eframe - 1) - printf("ended at %d/%d\n", (float)pframe, (float)eframe); + if (!getinputstate(pframe) || input_timelength <= 0) break; - } + makevectors(input_angles); pf = pframe; ef = eframe; diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index ce987249..dbb58679 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,6 +1,7 @@ void AL_ProjectProjectile (entity projectile) { float time_offset = self.client_time - remote_client_time(CT_SLOW_PROJECTILE); + projectile.s_time = time - time_offset; if (time_offset <= 13 * MSEC) // ping 13ms or lower? Don't do anything return; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 35dd984e..2b5cdfb8 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1110,11 +1110,10 @@ void () W_FireRocket = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + PredProj_Add(newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } - - PredProj_Add(newmis); }; void (entity from, float damage) LightningHit = { @@ -1359,11 +1358,10 @@ void (vector org, vector dir) launch_spike = { newmis.velocity = dir * ng_velocity; + PredProj_Add(newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } - - PredProj_Add(newmis); }; void () W_FireSuperSpikes = { From 08e02a603aface690e2391febb54e58faf7927fb Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 13 Oct 2022 12:47:16 -0700 Subject: [PATCH 1792/2474] Projection refinements - Speed up animation convergence time - Defer animation start to line up with remote fire - Tweak how we match start of firing for cleaner animations - Nails are now predicted nicely - Add csqc debug dump - Previously full refresh could miss zero fields that had been lost due to packet drops, fixed. - Pyro rockets now matched up with server side --- csqc/main.qc | 7 ++++ csqc/weapon_predict.qc | 73 ++++++++++++++++++++++++++++++++--------- share/animate.qc | 5 +-- share/defs.h | 2 +- share/weapon_predict.qc | 6 +++- ssqc/pyro.qc | 1 + 6 files changed, 72 insertions(+), 22 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1e6b4c85..76f40d71 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -418,6 +418,8 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; +void WPP_Dump(); + noref void CSQC_Input_Frame() { local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; @@ -435,6 +437,11 @@ noref void CSQC_Input_Frame() { zoomed_in = !zoomed_in; } + if (input_impulse == TF_DEBUG_CSQC) { + WPP_Dump(); + input_impulse = 0; + } + Sync_GameState(); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 1b15317c..7211f8dd 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,6 +1,16 @@ +DEFCVAR_FLOAT(wpp_debug, 0); + //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// +float animate_s_time; + +// Corrections for when we can recognize that we missed a packet. +void WP_ServerUpdate() { + if (pstate_server.attack_finished < pstate_server.client_time) + pstate_server.weaponframe = 0; +} + static Slot InputToSlot(float input) { Slot result = FO_SlotByInput(input); return result; @@ -180,15 +190,32 @@ static void prandom(void() option1, void() option2) { option2(); } +float PP_PredictStartOffset(); + void WP_AnimateModel(float fired) { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); - if (pstate_pred.client_thinkindex == 0 && !fired) { + if (pstate_pred.client_thinkindex == 0) { player_run(); return; } + if (fired) { + // If our latency is higher than projection, synchronize animation with + // when it will actually start/finish. + float offset = max(PP_PredictStartOffset(), 0); + + + if (offset > 0) { + if ((CVARF(wpp_debug) & 2) && pengine.is_effectframe) + printf("held for %0.3f\n", offset); + pstate_pred.client_nextthink = animate_s_time; + return; + } + + } + switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: case WEAP_INCENDIARY: @@ -239,7 +266,7 @@ void WP_Attack() { return; // Must be set prior to animation code, which might internally modify. - pstate_pred.client_thinkindex = 0; + pstate_pred.client_thinkindex = 1; WP_AnimateModel(TRUE); PP_Fire(); @@ -248,6 +275,16 @@ void WP_Attack() { pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; } +void WPP_Dump() { + printf("cti p=%d s=%d wf=%d/%d\n", + pstate_pred.client_thinkindex, pstate_server.client_thinkindex, + pstate_pred.weaponframe, pstate_server.weaponframe); + printf("t=%4.3f (%4.3f) af=%4.3f (%4.3f) rf=%4.3f (%4.3f)\n", + pstate_pred.client_time, pstate_server.client_time, + pstate_pred.attack_finished, pstate_server.attack_finished, + pstate_pred.reload_finished, pstate_server.reload_finished); +} + void WP_Frame() { if (getstatf(STAT_HEALTH) < 0) { pstate_pred.current_slot = SlotNull; @@ -395,11 +432,9 @@ int PP_FindTrail(entity e) return 0; } -static float PP_EPS = 0.05; - -entity PP_CreateProjectile(fo_projectile* desc, vector offset) { - entity proj = spawn(); - +// Predict the effective start time of something we fire right now, accounting +// for server side projection, ping fluctuation, etc. +inline float PP_PredictStartOffset() { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000.0; // TODO: Communicate with server around this. @@ -408,9 +443,16 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { float start_offset = max(0, pstate_pred.client_ping - 0.1) + // Server project max(0, ping - pstate_pred.client_ping); // Uncorrected error - proj.s_time = time + start_offset / 2 + corr_s; + return start_offset / 2 + corr_s; +} + +static float PP_EPS = 0.05; + +entity PP_CreateProjectile(fo_projectile* desc, vector offset) { + entity proj = spawn(); - proj.starttime = proj.s_time + 2/77.0; + proj.s_time = time + PP_PredictStartOffset(); + proj.starttime = max(time + 2/77.0, proj.s_time); proj.endtime = time + pstate_pred.client_ping + PP_EPS; proj.predraw = PP_PredrawPredicted; @@ -422,7 +464,7 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { proj.s_origin[2] += 16; proj.velocity = v_forward * desc->speed; - proj.oldorigin = proj.s_origin; + proj.oldorigin = proj.s_origin + 1/77.0 * proj.velocity; setorigin(proj, proj.oldorigin); proj.angles = input_angles; proj.angles[0] *= -1; @@ -482,8 +524,6 @@ void PP_Fire() { } } -DEFCVAR_FLOAT(pp_show_match_dist, 0); - float PredProjectile_MatchProjectile() { float delta_t = time - self.s_time; vector delta_p = self.velocity * delta_t; @@ -502,14 +542,15 @@ float PredProjectile_MatchProjectile() { float c_s = 0; if (fabs(diff2) > 1/154.0) c_s = corr_s + diff2/2 + sgn * 1/77.0; - corr_s = corr_s ? corr_s * 0.9 + 0.1 * c_s : c_s; + corr_s = corr_s ? corr_s * 0.5 + 0.5 * c_s : c_s; self.oldorigin = proj.origin; // Mate up trails. - if (CVARF(pp_show_match_dist) == 1) { + if (CVARF(wpp_debug) & 1) { proj.origin = proj.s_origin + delta_p; - printf(" p_diff = %0.3f / %0.3f\n", - vlen(proj.s_origin - self.s_origin), vlen(proj.origin - self.origin)); + printf(" p_diff = %0.3f / %0.3f t=%0.3f\n", + vlen(proj.s_origin - self.s_origin), vlen(proj.origin - self.origin), + vlen(proj.origin - self.origin) / vlen(self.velocity)); printf(" D2=%0.4f c_s=%0.4f corr_s=%0.4f\n", diff2, c_s, corr_s); } diff --git a/share/animate.qc b/share/animate.qc index 45e7e26c..54212c34 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -254,7 +254,7 @@ void player_run() { } void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - float tidx = (*thinkindex())++; + float tidx = (*thinkindex())++ - 1; float fi = tidx % anim->num_frames; float wfi = tidx % anim->num_wf; @@ -283,9 +283,6 @@ void PP_FireNG(float off); static void nail_extra() { pstate_pred.firing = TRUE; - if (pstate_pred.client_time < pstate_pred.attack_finished) - return; - if (!pengine.is_effectframe) return; diff --git a/share/defs.h b/share/defs.h index 92a38b23..12073b2a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -626,7 +626,7 @@ typedef struct { int id; } Slot; // unused 247 // unused 248 // unused 249 -// unused 250 +#define TF_DEBUG_CSQC 250 // unused 251 // unused 252 // unused 253 diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 63e3b708..b94e7b9b 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -188,6 +188,7 @@ void WeaponPred_Update(entity player) { if (time - player.last_full_predict_refresh > 5000 * MSEC) { player.predict_state = blank_state; player.last_full_predict_refresh = time; + mask = -1; } player.predict_state.client_time = player.client_time; @@ -228,6 +229,7 @@ float WP_SendEntity(entity to_player, float sendflags) { float() ReadByte = #360; float() ReadFloat = #367; void InitWeapPredEnt(entity e); +void WP_ServerUpdate(); #define COMM(_type, _field) pstate_server.##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { @@ -283,6 +285,8 @@ void EntUpdate_WeaponPred(float isnew) { #else if (isnew) InitWeapPredEnt(self); + else + WP_ServerUpdate(); #endif } #undef COMM @@ -479,7 +483,7 @@ float WP_ClientThink() { if (input_impulse) pstate_pred.impulse = input_impulse; - if (pstate_pred.client_nextthink && + while (pstate_pred.client_nextthink && pstate_pred.client_time >= pstate_pred.client_nextthink) { float held_client_time = pstate_pred.client_time; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 6468290b..2fa3a9c2 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -706,6 +706,7 @@ void () W_FireIncendiaryCannon = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + PredProj_Add(newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } From 6987df8f792da82ec58de7b47fff89702c6c08c4 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 14 Oct 2022 15:45:29 -0700 Subject: [PATCH 1793/2474] More compiler flags Sanity around short circuiting and float checks --- csqc/csprogs.src | 2 ++ ssqc/progs.src | 2 ++ 2 files changed, 4 insertions(+) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 86ba3b15..49b381e7 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -1,6 +1,8 @@ #pragma target fte_5768 #pragma optimise 3 #pragma flag enable subscope +#pragma flag enable iffloat +#pragma flag enable lo #pragma progs_dat "../csprogs.dat" diff --git a/ssqc/progs.src b/ssqc/progs.src index 6d067d32..6e0eb961 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -1,6 +1,8 @@ #pragma target fte_5768 #pragma optimise 3 #pragma flag enable subscope +#pragma flag enable iffloat +#pragma flag enable lo #pragma progs_dat "../qwprogs.dat" From bc2d351ba7290d455fee79f6561e922bfb143c84 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 14 Oct 2022 16:35:31 -0700 Subject: [PATCH 1794/2474] Make new projectiles independent of prediction Taking over projectile networking means that they're not natively handled by the engine for particle effects etc. This means that we always need some client side support for stitching things together (this only applies to CSQC clients, old clients get old netcode) even when prediction is otherwise disabled. --- csqc/main.qc | 1 + csqc/weapon_predict.qc | 36 +++++++++++++++++++++--------------- share/weapon_predict.qc | 16 ++++++++-------- ssqc/client.qc | 1 - 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1e6b4c85..9fc6ad88 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,6 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // } FO_Weapons_Init(); + FO_PP_Init(); // Some of this is always used by custom projectiles. FO_WP_Init(FALSE); // Server packet enables. CsGrenTimer::Init(); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 1b15317c..5cca0382 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -296,7 +296,7 @@ float nail_trail; float corr_s; // Auto-tuning correction factor. -void PP_Init() { +void FO_PP_Init() { InitFppProjectiles(); for (float i = 0; i < trail_table.length; i++) { @@ -347,9 +347,9 @@ float PP_PredrawActive() { return PREDRAW_NEXT; } } - if (self.traileffectnum) trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); + self.p_time = time + frametime; self.oldorigin = self.origin; } @@ -396,6 +396,13 @@ int PP_FindTrail(entity e) } static float PP_EPS = 0.05; +DEFCVAR_FLOAT(pp_trail_offset, 0.05); + +static inline void PP_InitTrail(entity proj) { + proj.oldorigin = proj.s_origin + CVARF(pp_trail_offset) * proj.velocity; + proj.p_time = time + CVARF(pp_trail_offset); + proj.traileffectnum = PP_FindTrail(proj); +} entity PP_CreateProjectile(fo_projectile* desc, vector offset) { entity proj = spawn(); @@ -422,13 +429,14 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { proj.s_origin[2] += 16; proj.velocity = v_forward * desc->speed; - proj.oldorigin = proj.s_origin; - setorigin(proj, proj.oldorigin); + setorigin(proj, proj.s_origin); proj.angles = input_angles; proj.angles[0] *= -1; setmodel(proj, desc->model); + PP_InitTrail(proj); + proj.pred_next = predicted_projectiles; if (predicted_projectiles) predicted_projectiles.pred_prev = proj; @@ -444,7 +452,6 @@ void PP_FireRocket(float is_soldier) { makevectors(input_angles); ASSERTF_EQ(vlen(ovf - v_forward), 0); entity proj = PP_CreateProjectile(desc, v_forward * 8); - proj.traileffectnum = PP_FindTrail(proj); } void PP_FireNG(float off) { @@ -459,7 +466,6 @@ void PP_FireNG(float off) { } entity proj = PP_CreateProjectile(desc, offset); - proj.traileffectnum = PP_FindTrail(proj); } void PP_Fire() { @@ -485,12 +491,8 @@ void PP_Fire() { DEFCVAR_FLOAT(pp_show_match_dist, 0); float PredProjectile_MatchProjectile() { - float delta_t = time - self.s_time; - vector delta_p = self.velocity * delta_t; - self.origin = self.s_origin + self.velocity * (time - self.s_time); - entity proj; - for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { + for(entity proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { if (proj.modelindex != self.modelindex) continue; @@ -504,10 +506,11 @@ float PredProjectile_MatchProjectile() { c_s = corr_s + diff2/2 + sgn * 1/77.0; corr_s = corr_s ? corr_s * 0.9 + 0.1 * c_s : c_s; - self.oldorigin = proj.origin; // Mate up trails. + self.oldorigin = proj.oldorigin; // Mate up trails. + self.p_time = proj.p_time; if (CVARF(pp_show_match_dist) == 1) { - proj.origin = proj.s_origin + delta_p; + self.origin = self.s_origin + self.velocity * (time - self.s_time); printf(" p_diff = %0.3f / %0.3f\n", vlen(proj.s_origin - self.s_origin), vlen(proj.origin - self.origin)); printf(" D2=%0.4f c_s=%0.4f corr_s=%0.4f\n", diff2, c_s, corr_s); @@ -528,9 +531,12 @@ void InitProjPredEnt() { // Force modelflags refresh setmodel(self, modelnameforindex(self.modelindex)); - self.traileffectnum = PP_FindTrail(self); - self.oldorigin = self.s_origin; + self.oldorigin = self.s_origin + CVARF(pp_trail_offset) * self.velocity; + self.p_time = time + CVARF(pp_trail_offset); + + PP_InitTrail(self); // Note: Might be overwritten by inherited match. if (self.owner_entnum == player_localentnum) PredProjectile_MatchProjectile(); + } diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 63e3b708..07cd041e 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -88,8 +88,8 @@ struct weaponpred_settings_t { } weaponpred_settings; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; -static float init_once; -void WeaponPred_Init() { +void WeaponPred_InitOnce() { + static float init_once; if (init_once) return; init_once = TRUE; @@ -106,7 +106,7 @@ void WeaponPred_Init() { } static float ClientEnable() { - WeaponPred_Init(); + WeaponPred_InitOnce(); // client_ping is not yet initialized. float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; @@ -358,6 +358,11 @@ inline float WeaponPred_Active(entity player) { } void WeaponPred_InitPlayer(entity player) { + WeaponPred_InitOnce(); + + sprint(player, PRINT_HIGH, "FortressOne: New projectiles ", + weaponpred_settings.new_projectiles ? "enabled\n" : "disabled\n"); + if (!ClientEnable()) { // Server side is once per connect. player.weapon_pred_enabled = FALSE; return; @@ -376,8 +381,6 @@ void WeaponPred_InitPlayer(entity player) { player.predict_entity = pe; sprint(player, PRINT_HIGH, "FortressOne: Weapon Prediction Active ", wp_version, "\n"); - sprint(player, PRINT_HIGH, "FortressOne: New projectiles ", - weaponpred_settings.new_projectiles ? "enabled\n" : "disabled\n"); } void WeaponPred_TearDown(entity player) { @@ -496,15 +499,12 @@ float WP_ClientThink() { return PREDRAW_AUTOADD; } -void PP_Init(); - void InitWeapPredEnt(entity pe) { pe.predraw = WP_ClientThink; self.drawmask = MASK_PRED_VIEWMODEL; self.renderflags = RF_VIEWMODEL; - PP_Init(); FO_WP_Init(TRUE); } diff --git a/ssqc/client.qc b/ssqc/client.qc index 48359378..b46ec90e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -72,7 +72,6 @@ void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); void StopAssCan(); -void WeaponPred_Init(); void WeaponPred_InitPlayer(entity player); void WeaponPred_TearDown(entity player); From c6246849cfae2d164e5dc1cfbe4e760fa0c20c10 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 13 Oct 2022 12:47:16 -0700 Subject: [PATCH 1795/2474] Projection refinements - Speed up animation convergence time - Defer animation start to line up with remote fire - Tweak how we match start of firing for cleaner animations - Nails are now predicted nicely - Add csqc debug dump - Previously full refresh could miss zero fields that had been lost due to packet drops, fixed. - Pyro rockets now matched up with server side --- csqc/main.qc | 7 ++++ csqc/weapon_predict.qc | 84 +++++++++++++++++++++++++++++++---------- share/animate.qc | 7 +--- share/defs.h | 2 +- share/weapon_predict.qc | 6 ++- ssqc/pyro.qc | 1 + 6 files changed, 80 insertions(+), 27 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 9fc6ad88..4f75b871 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -419,6 +419,8 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; +void WPP_Dump(); + noref void CSQC_Input_Frame() { local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; @@ -436,6 +438,11 @@ noref void CSQC_Input_Frame() { zoomed_in = !zoomed_in; } + if (input_impulse == TF_DEBUG_CSQC) { + WPP_Dump(); + input_impulse = 0; + } + Sync_GameState(); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 5cca0382..c8bf5300 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,6 +1,16 @@ +DEFCVAR_FLOAT(wpp_debug, 0); + //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// +float animate_s_time; + +// Corrections for when we can recognize that we missed a packet. +void WP_ServerUpdate() { + if (pstate_server.attack_finished < pstate_server.client_time) + pstate_server.weaponframe = 0; +} + static Slot InputToSlot(float input) { Slot result = FO_SlotByInput(input); return result; @@ -180,15 +190,32 @@ static void prandom(void() option1, void() option2) { option2(); } +float PP_PredictStartOffset(); + void WP_AnimateModel(float fired) { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); - if (pstate_pred.client_thinkindex == 0 && !fired) { + if (pstate_pred.client_thinkindex == 0) { player_run(); return; } + if (fired) { + // If our latency is higher than projection, synchronize animation with + // when it will actually start/finish. + float offset = max(PP_PredictStartOffset(), 0); + + + if (offset > 0) { + if ((CVARF(wpp_debug) & 2) && pengine.is_effectframe) + printf("held for %0.3f\n", offset); + pstate_pred.client_nextthink = animate_s_time; + return; + } + + } + switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: case WEAP_INCENDIARY: @@ -239,7 +266,7 @@ void WP_Attack() { return; // Must be set prior to animation code, which might internally modify. - pstate_pred.client_thinkindex = 0; + pstate_pred.client_thinkindex = 1; WP_AnimateModel(TRUE); PP_Fire(); @@ -248,6 +275,16 @@ void WP_Attack() { pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; } +void WPP_Dump() { + printf("cti p=%d s=%d wf=%d/%d\n", + pstate_pred.client_thinkindex, pstate_server.client_thinkindex, + pstate_pred.weaponframe, pstate_server.weaponframe); + printf("t=%4.3f (%4.3f) af=%4.3f (%4.3f) rf=%4.3f (%4.3f)\n", + pstate_pred.client_time, pstate_server.client_time, + pstate_pred.attack_finished, pstate_server.attack_finished, + pstate_pred.reload_finished, pstate_server.reload_finished); +} + void WP_Frame() { if (getstatf(STAT_HEALTH) < 0) { pstate_pred.current_slot = SlotNull; @@ -294,7 +331,7 @@ trail_table_entry trail_table[] = { float nail_trail; -float corr_s; // Auto-tuning correction factor. +static float corr_s; // Auto-tuning correction factor. void FO_PP_Init() { InitFppProjectiles(); @@ -404,9 +441,9 @@ static inline void PP_InitTrail(entity proj) { proj.traileffectnum = PP_FindTrail(proj); } -entity PP_CreateProjectile(fo_projectile* desc, vector offset) { - entity proj = spawn(); - +// Predict the effective start time of something we fire right now, accounting +// for server side projection, ping fluctuation, etc. +inline float PP_PredictStartOffset() { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000.0; // TODO: Communicate with server around this. @@ -415,9 +452,16 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { float start_offset = max(0, pstate_pred.client_ping - 0.1) + // Server project max(0, ping - pstate_pred.client_ping); // Uncorrected error - proj.s_time = time + start_offset / 2 + corr_s; + return start_offset / 2 + corr_s; +} + +static float PP_EPS = 0.05; + +entity PP_CreateProjectile(fo_projectile* desc, vector offset) { + entity proj = spawn(); - proj.starttime = proj.s_time + 2/77.0; + proj.s_time = time + PP_PredictStartOffset(); + proj.starttime = max(time + 2/77.0, proj.s_time); proj.endtime = time + pstate_pred.client_ping + PP_EPS; proj.predraw = PP_PredrawPredicted; @@ -488,8 +532,6 @@ void PP_Fire() { } } -DEFCVAR_FLOAT(pp_show_match_dist, 0); - float PredProjectile_MatchProjectile() { entity proj; for(entity proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { @@ -499,21 +541,23 @@ float PredProjectile_MatchProjectile() { if (fabs(proj.s_time - self.s_time) > 0.15) continue; - float diff2 = self.s_time - proj.s_time; - float sgn = diff2 > 0 ? 1 : -1; + float diff_t = self.s_time - proj.s_time; + float sgn = diff_t > 0 ? 1 : -1; float c_s = 0; - if (fabs(diff2) > 1/154.0) - c_s = corr_s + diff2/2 + sgn * 1/77.0; - corr_s = corr_s ? corr_s * 0.9 + 0.1 * c_s : c_s; + if (fabs(diff_t) > 1/154.0) { + c_s = corr_s + diff_t/2 + sgn * 1/77.0; + corr_s = corr_s ? corr_s * 0.7 + 0.3 * c_s : c_s; + } self.oldorigin = proj.oldorigin; // Mate up trails. self.p_time = proj.p_time; - if (CVARF(pp_show_match_dist) == 1) { - self.origin = self.s_origin + self.velocity * (time - self.s_time); - printf(" p_diff = %0.3f / %0.3f\n", - vlen(proj.s_origin - self.s_origin), vlen(proj.origin - self.origin)); - printf(" D2=%0.4f c_s=%0.4f corr_s=%0.4f\n", diff2, c_s, corr_s); + if (CVARF(wpp_debug) & 1) { + proj.origin = proj.s_origin + (time - proj.s_time) * self.velocity; + printf(" p_diff = %0.3f / %0.3f t=%0.3f\n", + vlen(proj.s_origin - self.s_origin), vlen(proj.origin - self.origin), + vlen(proj.origin - self.origin) / vlen(self.velocity)); + printf(" error=%0.4f c_s=%0.4f corr_s=%0.4f\n", diff_t, c_s, corr_s); } PP_Cleanup(proj); diff --git a/share/animate.qc b/share/animate.qc index 45e7e26c..8eee963b 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -203,7 +203,7 @@ void player_run() { self.frame = 6; self.weaponframe = 0; - if (!self.velocity_x && !self.velocity_y) { + if (!(self.velocity_x || self.velocity_y)) { self.walkframe = 0; player_stand1(); return; @@ -254,7 +254,7 @@ void player_run() { } void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - float tidx = (*thinkindex())++; + float tidx = (*thinkindex())++ - 1; float fi = tidx % anim->num_frames; float wfi = tidx % anim->num_wf; @@ -283,9 +283,6 @@ void PP_FireNG(float off); static void nail_extra() { pstate_pred.firing = TRUE; - if (pstate_pred.client_time < pstate_pred.attack_finished) - return; - if (!pengine.is_effectframe) return; diff --git a/share/defs.h b/share/defs.h index 92a38b23..12073b2a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -626,7 +626,7 @@ typedef struct { int id; } Slot; // unused 247 // unused 248 // unused 249 -// unused 250 +#define TF_DEBUG_CSQC 250 // unused 251 // unused 252 // unused 253 diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 07cd041e..9c266ee6 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -188,6 +188,7 @@ void WeaponPred_Update(entity player) { if (time - player.last_full_predict_refresh > 5000 * MSEC) { player.predict_state = blank_state; player.last_full_predict_refresh = time; + mask = -1; } player.predict_state.client_time = player.client_time; @@ -228,6 +229,7 @@ float WP_SendEntity(entity to_player, float sendflags) { float() ReadByte = #360; float() ReadFloat = #367; void InitWeapPredEnt(entity e); +void WP_ServerUpdate(); #define COMM(_type, _field) pstate_server.##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { @@ -283,6 +285,8 @@ void EntUpdate_WeaponPred(float isnew) { #else if (isnew) InitWeapPredEnt(self); + else + WP_ServerUpdate(); #endif } #undef COMM @@ -482,7 +486,7 @@ float WP_ClientThink() { if (input_impulse) pstate_pred.impulse = input_impulse; - if (pstate_pred.client_nextthink && + while (pstate_pred.client_nextthink && pstate_pred.client_time >= pstate_pred.client_nextthink) { float held_client_time = pstate_pred.client_time; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 6468290b..2fa3a9c2 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -706,6 +706,7 @@ void () W_FireIncendiaryCannon = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + PredProj_Add(newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } From 6815c913fb0a306c9c9cc1c8829597708d19aeba Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 14 Oct 2022 00:56:36 -0700 Subject: [PATCH 1796/2474] Overhaul and tighten - Unify thinkindex=1 logic to server side as well - Re-do how we queue weapon frame animations for more consistency - Tune trails so they don't feel different (with prediction they can start sooner, even with lan pings, since we don't have to wait for projectile to get back from server which takes at least a frame). - Handle running out of ammo while firing better - Fix edge case where we were dropping input frames at high fps --- csqc/weapon_predict.qc | 215 ++++++++++++++++++++++++---------------- share/animate.qc | 50 ++++------ share/weapon_predict.qc | 12 ++- ssqc/player.qc | 12 +-- 4 files changed, 162 insertions(+), 127 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c8bf5300..c5e48623 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,5 +1,13 @@ DEFCVAR_FLOAT(wpp_debug, 0); +inline FO_WeapInfo* WP_CurrentWeapon() { + return FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); +} + +static inline float IsEffectFrame() { + return pengine.is_effectframe; +} + //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// @@ -20,10 +28,15 @@ inline float WP_IsReloading() { return pstate_pred.tfstate & TFSTATE_RELOADING; } +float WP_CheckAmmo(FO_WeapInfo* wi); + void WP_ChangeWeapon(Slot slot) { + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + if (!WP_CheckAmmo(wi)) + return; + pstate_pred.current_slot = slot; pstate_pred.weaponframe = 0; - // UpdateViewModel will propagate. } @@ -86,10 +99,7 @@ float WP_CurrentAmmo() { if (!WP_Enabled()) return getstatf(STAT_AMMO); - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - return WP_GetAmmo(wi->ammo_type); + return WP_GetAmmo(WP_CurrentWeapon()->ammo_type); } static float* ClipFired() { @@ -125,8 +135,7 @@ string WP_GetClip() { void WP_Reload() { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); + FO_WeapInfo* wi = WP_CurrentWeapon(); if (!wi->needs_reload) return; @@ -161,16 +170,16 @@ void WP_CheckReloadFinished() { } } - -float WP_ConsumeAmmo(FO_WeapInfo* wi) { +float WP_CheckAmmo(FO_WeapInfo* wi) { if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) return TRUE; int ammo = WP_GetAmmo(wi->ammo_type); - if (wi->ammo_per_shot > ammo) - return FALSE; + return ammo > wi->ammo_per_shot; +} - if (wi->needs_reload) { +float WP_ConsumeAmmo(FO_WeapInfo* wi) { + if (!WP_CheckAmmo(wi) || wi->needs_reload) { if (*ClipFired() >= wi->clip_size) { WP_Reload(); return FALSE; @@ -192,31 +201,13 @@ static void prandom(void() option1, void() option2) { float PP_PredictStartOffset(); -void WP_AnimateModel(float fired) { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - +void WP_AnimateModel() { if (pstate_pred.client_thinkindex == 0) { player_run(); return; } - if (fired) { - // If our latency is higher than projection, synchronize animation with - // when it will actually start/finish. - float offset = max(PP_PredictStartOffset(), 0); - - - if (offset > 0) { - if ((CVARF(wpp_debug) & 2) && pengine.is_effectframe) - printf("held for %0.3f\n", offset); - pstate_pred.client_nextthink = animate_s_time; - return; - } - - } - - switch (wi->weapon) { + switch (WP_CurrentWeapon()->weapon) { case WEAP_ROCKET_LAUNCHER: case WEAP_INCENDIARY: case WEAP_GRENADE_LAUNCHER: @@ -242,37 +233,13 @@ void WP_AnimateModel(float fired) { prandom(player_knifeN, player_knifebN); break; case WEAP_MEDIKIT: prandom(player_medikitN, player_medikitbN); break; - case WEAP_SPANNER: player_spannerN(); break; } } void WP_DoClientThink(void) { - WP_AnimateModel(FALSE); -} - -void PP_Fire(); - -void WP_Attack() { - if (pstate_pred.firing) // Already in a continuous attack. - return; - - Slot slot = pstate_pred.current_slot; - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - - if (!WP_ConsumeAmmo(wi)) - return; - - // Must be set prior to animation code, which might internally modify. - pstate_pred.client_thinkindex = 1; - - WP_AnimateModel(TRUE); - PP_Fire(); - - // We set this after so that weapons such as NG can handle correctly. - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + WP_AnimateModel(); } void WPP_Dump() { @@ -283,8 +250,15 @@ void WPP_Dump() { pstate_pred.client_time, pstate_server.client_time, pstate_pred.attack_finished, pstate_server.attack_finished, pstate_pred.reload_finished, pstate_server.reload_finished); + printf("clip=%d/%d ammo_used=%d\n", + pstate_pred.clip_fired[SlotIndex(pstate_pred.current_slot)], + pstate_server.clip_fired[SlotIndex(pstate_pred.current_slot)], + pstate_pred.ammo_used[WP_CurrentWeapon()->ammo_type]); } +void WP_Attack(); + +float td; void WP_Frame() { if (getstatf(STAT_HEALTH) < 0) { pstate_pred.current_slot = SlotNull; @@ -295,7 +269,7 @@ void WP_Frame() { WP_Impulse(); if ((input_buttons & BUTTON0) && !WP_IsReloading() && - (pstate_pred.client_time >= pstate_pred.attack_finished)) + (pstate_pred.client_time >= pstate_pred.attack_finished)) WP_Attack(); } @@ -383,6 +357,7 @@ float PP_PredrawActive() { self.oldorigin = trace_endpos; return PREDRAW_NEXT; } + } if (self.traileffectnum) trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); @@ -402,7 +377,7 @@ float PP_PredrawActive() { float PP_PredrawPredicted() { if (time < self.starttime || time > self.endtime) { - if (time > self.endtime + 0.05) + if (time > self.endtime) PP_Cleanup(self); return PREDRAW_NEXT; } @@ -433,11 +408,11 @@ int PP_FindTrail(entity e) } static float PP_EPS = 0.05; -DEFCVAR_FLOAT(pp_trail_offset, 0.05); +DEFCVAR_FLOAT(pp_trail_start, 50); static inline void PP_InitTrail(entity proj) { - proj.oldorigin = proj.s_origin + CVARF(pp_trail_offset) * proj.velocity; - proj.p_time = time + CVARF(pp_trail_offset); + proj.oldorigin = proj.s_origin + CVARF(pp_trail_start) * MSEC * proj.velocity; + proj.p_time = time + CVARF(pp_trail_start * MSEC); proj.traileffectnum = PP_FindTrail(proj); } @@ -461,7 +436,7 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { entity proj = spawn(); proj.s_time = time + PP_PredictStartOffset(); - proj.starttime = max(time + 2/77.0, proj.s_time); + proj.starttime = max(time + CVARF(pp_trail_start) * MSEC, proj.s_time); proj.endtime = time + pstate_pred.client_ping + PP_EPS; proj.predraw = PP_PredrawPredicted; @@ -490,6 +465,9 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { } void PP_FireRocket(float is_soldier) { + if (!IsEffectFrame()) + return; + fo_projectile* desc = is_soldier ? &fpp_rocket : &fpp_incendiary; vector ovf = v_forward; @@ -499,6 +477,9 @@ void PP_FireRocket(float is_soldier) { } void PP_FireNG(float off) { + if (!IsEffectFrame()) + return; + fo_projectile* desc; vector offset = [0, 0, 0]; @@ -512,36 +493,100 @@ void PP_FireNG(float off) { entity proj = PP_CreateProjectile(desc, offset); } -void PP_Fire() { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); +void PP_NailFrame() { + if (input_buttons & BUTTON0 == 0) { + player_run(); + return; + } + + pstate_pred.firing = TRUE; - if (wi->predict_type != PRED_PROJ) + FO_WeapInfo* wi = WP_CurrentWeapon(); + WP_ConsumeAmmo(wi); + + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + float idx = (pstate_pred.client_thinkindex + 1) % 2; + if (wi->weapon == WEAP_NAILGUN) + PP_FireNG(idx ? 4 : -4); + else + PP_FireNG(0); + +} + +void WP_Attack() { + Slot slot = pstate_pred.current_slot; + FO_WeapInfo* wi = WP_CurrentWeapon(); + + if (wi->predict_type == NO_PREDICT) return; - if (!pengine.is_effectframe) + // Whether firing occurs here, or is embedded in the frame animation code + // (because continuous fire). + int in_anim = wi->weapon == WEAP_NAILGUN || + wi->weapon == WEAP_SUPER_NAILGUN; + + if ((in_anim && !WP_CheckAmmo(wi)) || (!in_anim && !WP_ConsumeAmmo(wi))) return; - switch (wi->weapon) { - case WEAP_NAILGUN: - case WEAP_SUPER_NAILGUN: - break; // Handled in animation. + // OK. We're ready to pew. + // Must be set prior to animation code, which might internally modify. + pstate_pred.client_thinkindex = 1; + + switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: PP_FireRocket(TRUE); break; case WEAP_INCENDIARY: PP_FireRocket(FALSE); break; } + + float af = pstate_pred.attack_finished; + + if (!in_anim) + pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + + +#if 0 + // If our latency is higher than forward projection, synchronize animation + // with when it will actually start/finish. The projectile internally + // synchronizes also. + // + // ** Not currently doing this because playing animation in advance is better + // for understanding attack_finished as a player. ** + float offset = + // max(PP_PredictStartOffset() - 2/77.0, 0); + if (offset > 0) { + if ((CVARF(wpp_debug) & 2) && pengine.is_effectframe) + printf("held for %0.3f\n", offset); + + pstate_pred.client_nextthink = animate_s_time; + return; + } +#endif + + WP_AnimateModel(); } float PredProjectile_MatchProjectile() { - entity proj; - for(entity proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { + entity proj, match = __NULL__; + float best = 0.2; + for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { if (proj.modelindex != self.modelindex) continue; - if (fabs(proj.s_time - self.s_time) > 0.15) - continue; + float d = fabs(proj.s_time - self.s_time); + if (d < best) { + best = d; + match = proj; + } + + if (vlen(proj.s_origin - self.s_origin) < 32) { + match = proj; + break; + } + + } - float diff_t = self.s_time - proj.s_time; + if (match) { + float diff_t = self.s_time - match.s_time; float sgn = diff_t > 0 ? 1 : -1; float c_s = 0; if (fabs(diff_t) > 1/154.0) { @@ -549,18 +594,18 @@ float PredProjectile_MatchProjectile() { corr_s = corr_s ? corr_s * 0.7 + 0.3 * c_s : c_s; } - self.oldorigin = proj.oldorigin; // Mate up trails. - self.p_time = proj.p_time; + self.oldorigin = match.oldorigin; // Mate up trails. + self.p_time = match.p_time; if (CVARF(wpp_debug) & 1) { - proj.origin = proj.s_origin + (time - proj.s_time) * self.velocity; + match.origin = match.s_origin + (time - match.s_time) * self.velocity; printf(" p_diff = %0.3f / %0.3f t=%0.3f\n", - vlen(proj.s_origin - self.s_origin), vlen(proj.origin - self.origin), - vlen(proj.origin - self.origin) / vlen(self.velocity)); + vlen(match.s_origin - self.s_origin), vlen(match.origin - self.origin), + vlen(match.origin - self.origin) / vlen(self.velocity)); printf(" error=%0.4f c_s=%0.4f corr_s=%0.4f\n", diff_t, c_s, corr_s); } - PP_Cleanup(proj); + PP_Cleanup(match); return TRUE; } @@ -575,8 +620,8 @@ void InitProjPredEnt() { // Force modelflags refresh setmodel(self, modelnameforindex(self.modelindex)); - self.oldorigin = self.s_origin + CVARF(pp_trail_offset) * self.velocity; - self.p_time = time + CVARF(pp_trail_offset); + self.oldorigin = self.s_origin + CVARF(pp_trail_start) * MSEC * self.velocity; + self.p_time = time + CVARF(pp_trail_start) * MSEC; PP_InitTrail(self); // Note: Might be overwritten by inherited match. diff --git a/share/animate.qc b/share/animate.qc index 8eee963b..a4cbbe4a 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -43,7 +43,7 @@ void FO_SetClientThink(void() func, float offset, float override = TRUE) { } void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - int tidx = self.client_thinkindex++; + int tidx = self.client_thinkindex++ - 1; int wfi = tidx % anim->num_wf; self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; @@ -278,25 +278,9 @@ void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { static void axe_extra() {} -void PP_FireNG(float off); +void PP_NailFrame(); +void nail_extra() { PP_NailFrame(); } -static void nail_extra() { - pstate_pred.firing = TRUE; - - if (!pengine.is_effectframe) - return; - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - float idx = (*thinkindex() - 1) % 2; - if (wi->weapon == WEAP_NAILGUN) - PP_FireNG(idx ? 4 : -4); - else - PP_FireNG(0); - -} static void asscan_up_extra() {} static void asscan_fire_extra() {} static void asscan_down_extra() {} @@ -305,58 +289,58 @@ static void asscan_down_extra() {} anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } -void player_rocket1() { *thinkindex() = 0; player_rocketN(); } +void player_rocket1() { *thinkindex() = 1; player_rocketN(); } anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } -void player_shot1() { *thinkindex() = 0; player_shotN(); } +void player_shot1() { *thinkindex() = 1; player_shotN(); } anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } -void player_autorifle1() { *thinkindex() = 0; player_autorifleN(); } +void player_autorifle1() { *thinkindex() = 1; player_autorifleN(); } anim_t anim_axea = { 4, 4, {119}, {1}, FALSE }; void player_axeN() { client_anim_frames(player_axeN, axe_extra, &anim_axea); } -void player_axe1() { *thinkindex() = 0; player_axeN(); } +void player_axe1() { *thinkindex() = 1; player_axeN(); } anim_t anim_axeb = { 4, 4, {124}, {5}, FALSE }; void player_axebN() { client_anim_frames(player_axebN, axe_extra, &anim_axeb); } -void player_axeb1() { *thinkindex() = 0; player_axebN(); } +void player_axeb1() { *thinkindex() = 1; player_axebN(); } void player_spannerN() { client_anim_frames(player_spannerN, axe_extra, &anim_axea); } -void player_spanner1() { *thinkindex() = 0; player_spannerN(); } +void player_spanner1() { *thinkindex() = 1; player_spannerN(); } void player_knifeN() { client_anim_frames(player_knifeN, axe_extra, &anim_axea); } -void player_knife1() { *thinkindex() = 0; player_knifeN(); } +void player_knife1() { *thinkindex() = 1; player_knifeN(); } void player_knifebN() { client_anim_frames(player_knifebN, axe_extra, &anim_axeb); } -void player_knifeb1() { *thinkindex() = 0; player_knifebN(); } +void player_knifeb1() { *thinkindex() = 1; player_knifebN(); } void player_medikitN() { client_anim_frames(player_medikitN, axe_extra, &anim_axea); } -void player_medikit1() { *thinkindex() = 0; player_medikitN(); } +void player_medikit1() { *thinkindex() = 1; player_medikitN(); } void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_axeb); } -void player_medikitb1() { *thinkindex() = 0; player_medikitbN(); } +void player_medikitb1() { *thinkindex() = 1; player_medikitbN(); } anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } -void player_nail1() { *thinkindex() = 0; player_nailN(); } +void player_nail1() { *thinkindex() = 1; player_nailN(); } anim_t anim_flamethrower = { 2, 6, {103, 104}, {1}, FALSE, TRUE }; void player_flamethrowerN() { client_anim_frames(player_flamethrowerN, think_nop, &anim_flamethrower); } -void player_flamethrower1() { *thinkindex() = 0; player_flamethrowerN(); } +void player_flamethrower1() { *thinkindex() = 1; player_flamethrowerN(); } anim_t anim_asscan_up = { 1, 4, {103}, {1, 1, 2, 2}, FALSE, TRUE}; anim_t anim_asscan_fire = { 1, 2, {103}, {2, 4}, FALSE, TRUE}; anim_t anim_asscan_down = { 1, 6, {103}, {1, 1, 2, 2, 3, 3}, FALSE, TRUE}; void player_asscan_upN() { client_anim_frames(player_asscan_upN, asscan_up_extra, &anim_asscan_up); } -void player_asscan_up1() { *thinkindex() = 0; player_asscan_upN(); } +void player_asscan_up1() { *thinkindex() = 1; player_asscan_upN(); } void player_asscan_fire() { client_anim_frames(player_asscan_fire, asscan_fire_extra, &anim_asscan_fire); } void player_asscan_downN() { client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } -void player_asscan_down1() { *thinkindex() = 0; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } +void player_asscan_down1() { *thinkindex() = 1; client_anim_frames(player_asscan_downN, asscan_down_extra, &anim_asscan_down); } diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 9c266ee6..0d0c763d 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -111,8 +111,10 @@ static float ClientEnable() { // client_ping is not yet initialized. float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; + float min_ping = + FO_GetUserSetting(self, "fowpmp", "fo_weapon_predict_minping", "40"); - if (weaponpred_settings.global_disable || ping < 40 * MSEC) + if (weaponpred_settings.global_disable || ping < min_ping * MSEC) return FALSE; if (weaponpred_settings.global_enable) @@ -364,7 +366,7 @@ inline float WeaponPred_Active(entity player) { void WeaponPred_InitPlayer(entity player) { WeaponPred_InitOnce(); - sprint(player, PRINT_HIGH, "FortressOne: New projectiles ", + sprint(player, PRINT_HIGH, "FortressOne: CSQC projectiles ", weaponpred_settings.new_projectiles ? "enabled\n" : "disabled\n"); if (!ClientEnable()) { // Server side is once per connect. @@ -462,8 +464,12 @@ void WP_DoClientThink(); float pf, ef; +float last_time; +float gen; + float WP_ClientThink() { pstate_pred = pstate_server; + gen++; int pframe = servercommandframe + 1; int eframe = clientcommandframe; @@ -475,7 +481,7 @@ float WP_ClientThink() { pf = pframe; ef = eframe; - if (pframe >= eframe - 1 && pframe > pengine.last_effectframe) { + if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; } else { diff --git a/ssqc/player.qc b/ssqc/player.qc index f3da1eb7..e147bbf2 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -520,27 +520,27 @@ void player_die_extra() { anim_t anim_player_diea1 = { 11, 1, {50}, {0}, FALSE, FALSE }; void player_dieaN() { client_anim_frames(player_dieaN, player_die_extra, &anim_player_diea1); } -void player_diea1() { *thinkindex() = 0; player_dieaN(); } +void player_diea1() { *thinkindex() = 1; player_dieaN(); } anim_t anim_player_dieb1 = { 9, 1, {61}, {0}, FALSE, FALSE }; void player_diebN() { client_anim_frames(player_diebN, player_die_extra, &anim_player_dieb1); } -void player_dieb1() { *thinkindex() = 0; player_diebN(); } +void player_dieb1() { *thinkindex() = 1; player_diebN(); } anim_t anim_player_diec1 = { 15, 1, {70}, {0}, FALSE, FALSE }; void player_diecN() { client_anim_frames(player_diecN, player_die_extra, &anim_player_diec1); } -void player_diec1() { *thinkindex() = 0; player_diecN(); } +void player_diec1() { *thinkindex() = 1; player_diecN(); } anim_t anim_player_died1 = { 9, 1, {85}, {0}, FALSE, FALSE }; void player_diedN() { client_anim_frames(player_diedN, player_die_extra, &anim_player_died1); } -void player_died1() { *thinkindex() = 0; player_diedN(); } +void player_died1() { *thinkindex() = 1; player_diedN(); } anim_t anim_player_diee1 = { 9, 1, {94}, {0}, FALSE, FALSE }; void player_dieeN() { client_anim_frames(player_dieeN, player_die_extra, &anim_player_diee1); } -void player_diee1() { *thinkindex() = 0; player_dieeN(); } +void player_diee1() { *thinkindex() = 1; player_dieeN(); } anim_t anim_player_die_ax = { 9, 1, {41}, {0}, FALSE, FALSE }; void player_die_axN() { client_anim_frames(player_die_axN, player_die_extra, &anim_player_die_ax); } -void player_die_ax1() { *thinkindex() = 0; player_die_axN(); } +void player_die_ax1() { *thinkindex() = 1; player_die_axN(); } void () Headless_Think = { self.frame = self.frame + 1; From c971eac4599a5eae5e245d0df03f8e4b835e055a Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 15 Oct 2022 01:09:46 -0700 Subject: [PATCH 1797/2474] Add Flamethrower prediction Also do some minor clean up and refactoring as we're adding types. --- csqc/weapon_predict.qc | 105 ++++++++++++++++++++++------------------ share/animate.qc | 7 +-- share/weapon_predict.qc | 29 ++++++----- share/weapons.qc | 2 +- ssqc/pyro.qc | 5 ++ 5 files changed, 83 insertions(+), 65 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c5e48623..6675de06 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -102,7 +102,7 @@ float WP_CurrentAmmo() { return WP_GetAmmo(WP_CurrentWeapon()->ammo_type); } -static float* ClipFired() { +float* WP_ClipFired() { float index = SlotIndex(pstate_pred.current_slot); if (pstate_pred.playerclass == PC_DEMOMAN && index == 1) @@ -123,7 +123,7 @@ string WP_GetClip() { float capacity = wi->clip_size; float still_loading = 0; - float fired = *ClipFired(); + float fired = *WP_ClipFired(); if (WP_IsReloading()) still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, @@ -140,7 +140,7 @@ void WP_Reload() { if (!wi->needs_reload) return; - float clip_fired = *ClipFired(); + float clip_fired = *WP_ClipFired(); float ammo_rem = WP_GetAmmo(wi->ammo_type); string msg; @@ -155,7 +155,7 @@ void WP_Reload() { pstate_pred.tfstate |= TFSTATE_RELOADING; float amt = min(ammo_rem, clip_fired); - (*ClipFired()) -= amt; + (*WP_ClipFired()) -= amt; pstate_pred.reload_finished = pstate_pred.client_time + (amt / wi->clip_size) * wi->full_reload_time; @@ -180,14 +180,14 @@ float WP_CheckAmmo(FO_WeapInfo* wi) { float WP_ConsumeAmmo(FO_WeapInfo* wi) { if (!WP_CheckAmmo(wi) || wi->needs_reload) { - if (*ClipFired() >= wi->clip_size) { + if (*WP_ClipFired() >= wi->clip_size) { WP_Reload(); return FALSE; } } pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; - *ClipFired() += wi->ammo_per_shot; + *WP_ClipFired() += wi->ammo_per_shot; return TRUE; } @@ -258,8 +258,31 @@ void WPP_Dump() { void WP_Attack(); +void MP_SetSpeed() { + static float prev_state; + + if (!IsEffectFrame()) + return; + + if (pstate_pred.tfstate & TFSTATE_AIMING == prev_state) + return; + + prev_state = pstate_pred.tfstate & TFSTATE_AIMING; + + string mspeed = "999"; + if (pstate_pred.tfstate & TFSTATE_AIMING) + mspeed = "80"; + + localcmd("cl_forwardspeed ", mspeed, "\n"); + localcmd("cl_sidespeed ", mspeed, "\n"); + localcmd("cl_backspeed ", mspeed, "\n"); +} + + float td; void WP_Frame() { + MP_SetSpeed(); + if (getstatf(STAT_HEALTH) < 0) { pstate_pred.current_slot = SlotNull; return; @@ -398,9 +421,8 @@ int PP_FindTrail(entity e) return trail_table[idx].trail[is_grenade]; } - fo_projectile* fpp_list[] = { &fpp_incendiary, &fpp_nail, &fpp_super_nail }; - for (float i = 0; i < fpp_list.length; i++) { - fo_projectile* desc = fpp_list[i]; + for (float i = 0; i < fpp_types.length; i++) { + fo_projectile* desc = &fpp_types[i]; if (e.modelindex == desc->modelindex) return desc->trailindex; } @@ -437,7 +459,7 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { proj.s_time = time + PP_PredictStartOffset(); proj.starttime = max(time + CVARF(pp_trail_start) * MSEC, proj.s_time); - proj.endtime = time + pstate_pred.client_ping + PP_EPS; + proj.endtime = time + pstate_pred.client_ping + PP_EPS + 2; proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_ENGINE; @@ -452,7 +474,7 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { proj.angles = input_angles; proj.angles[0] *= -1; - setmodel(proj, desc->model); + setmodelindex(proj, desc->modelindex); PP_InitTrail(proj); @@ -464,33 +486,8 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { return proj; } -void PP_FireRocket(float is_soldier) { - if (!IsEffectFrame()) - return; - - fo_projectile* desc = is_soldier ? &fpp_rocket : &fpp_incendiary; - - vector ovf = v_forward; - makevectors(input_angles); - ASSERTF_EQ(vlen(ovf - v_forward), 0); - entity proj = PP_CreateProjectile(desc, v_forward * 8); -} - -void PP_FireNG(float off) { - if (!IsEffectFrame()) - return; - - fo_projectile* desc; - vector offset = [0, 0, 0]; - - if (off == 0) { - desc = &fpp_super_nail; - } else { - desc = &fpp_nail; - offset = off * v_right; - } +void PP_AssCanFrame() { - entity proj = PP_CreateProjectile(desc, offset); } void PP_NailFrame() { @@ -503,14 +500,17 @@ void PP_NailFrame() { FO_WeapInfo* wi = WP_CurrentWeapon(); WP_ConsumeAmmo(wi); - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + float idx = (pstate_pred.client_thinkindex + 1) % 2; - if (wi->weapon == WEAP_NAILGUN) - PP_FireNG(idx ? 4 : -4); - else - PP_FireNG(0); + if (!IsEffectFrame()) + return; + + float off = 0; + if (wi->weapon == WEAP_NAILGUN) // Else: SNG, no offset. + off = idx ? 4 : -4; + PP_CreateProjectile(&fpp_types[FPP_NAIL], v_right * off); } void WP_Attack() { @@ -523,7 +523,8 @@ void WP_Attack() { // Whether firing occurs here, or is embedded in the frame animation code // (because continuous fire). int in_anim = wi->weapon == WEAP_NAILGUN || - wi->weapon == WEAP_SUPER_NAILGUN; + wi->weapon == WEAP_SUPER_NAILGUN || + wi->weapon == WEAP_ASSAULT_CANNON; if ((in_anim && !WP_CheckAmmo(wi)) || (!in_anim && !WP_ConsumeAmmo(wi))) return; @@ -533,9 +534,18 @@ void WP_Attack() { // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 1; - switch (wi->weapon) { - case WEAP_ROCKET_LAUNCHER: PP_FireRocket(TRUE); break; - case WEAP_INCENDIARY: PP_FireRocket(FALSE); break; + if (IsEffectFrame() && !in_anim) { + switch (wi->weapon) { + case WEAP_ROCKET_LAUNCHER: + PP_CreateProjectile(&fpp_types[FPP_ROCKET], v_forward * 8); + break; + case WEAP_INCENDIARY: + PP_CreateProjectile(&fpp_types[FPP_INCENDIARY], v_forward * 8); + break; + case WEAP_FLAMETHROWER: + PP_CreateProjectile(&fpp_types[FPP_FLAMETHROWER], v_forward * 16); + break; + } } float af = pstate_pred.attack_finished; @@ -619,6 +629,7 @@ void InitProjPredEnt() { // Force modelflags refresh setmodel(self, modelnameforindex(self.modelindex)); + setsize(self, [0,0,0], [0,0,0]); self.oldorigin = self.s_origin + CVARF(pp_trail_start) * MSEC * self.velocity; self.p_time = time + CVARF(pp_trail_start) * MSEC; @@ -626,6 +637,6 @@ void InitProjPredEnt() { PP_InitTrail(self); // Note: Might be overwritten by inherited match. if (self.owner_entnum == player_localentnum) - PredProjectile_MatchProjectile(); + PredProjectile_MatchProjectile(); } diff --git a/share/animate.qc b/share/animate.qc index a4cbbe4a..260a8c50 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -181,12 +181,7 @@ void asscan_down_extra() { FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); if (self.client_thinkindex >= 15) { // 1.5s down - self.fire_held_down = 0; self.tfstate &= ~TFSTATE_AIMING; - if (!cannon_move) - self.tfstate &= ~TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); - player_run(); if (self.ammo_cells < 7 || !FO_CheckForReload()) { W_PrintWeaponMessage(); @@ -327,7 +322,7 @@ anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } void player_nail1() { *thinkindex() = 1; player_nailN(); } -anim_t anim_flamethrower = { 2, 6, {103, 104}, {1}, FALSE, TRUE }; +anim_t anim_flamethrower = { 6, 6, {113}, {1}, TRUE, FALSE }; void player_flamethrowerN() { client_anim_frames(player_flamethrowerN, think_nop, &anim_flamethrower); } diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 0d0c763d..872c64ca 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -1,7 +1,7 @@ #define ENT_WEAPONPRED 100 #define ENT_PROJECTILE 101 -string wp_version = "v0"; +string wp_version = "v1"; enumflags { FOWP_CTIME, @@ -51,7 +51,15 @@ struct predict_tf_state { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +enum { + FPP_ROCKET, + FPP_INCENDIARY, + FPP_NAIL, + FPP_FLAMETHROWER, +}; + struct fo_projectile { + int id; float speed; string model; string trail; @@ -61,18 +69,17 @@ struct fo_projectile { float trailindex; }; -fo_projectile fpp_rocket = { PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl", "" }; -fo_projectile fpp_incendiary = { 800, "progs/lavaball.mdl", "t_lavaball" }; -fo_projectile fpp_nail = { 1500, "progs/spike.mdl", "tr_spike" }; -fo_projectile fpp_super_nail = { 1500, "progs/s_spike.mdl", "tr_spike" }; - +fo_projectile fpp_types[] = { + { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl", "" }, + { FPP_INCENDIARY, 800, "progs/lavaball.mdl", "t_lavaball" }, + { FPP_NAIL, 1500, "progs/spike.mdl", "tr_spike" }, + { FPP_FLAMETHROWER, 600, "progs/s_explod.spr", "explodesprite" }, +}; void InitFppProjectiles() { - fo_projectile* fpp_list[] = - { &fpp_rocket, &fpp_incendiary, &fpp_nail, &fpp_super_nail }; - - for (float i = 0; i < fpp_list.length; i++) { - fo_projectile* desc = fpp_list[i]; + for (float i = 0; i < fpp_types.length; i++) { + fo_projectile* desc = &fpp_types[i]; + ASSERTD_EQ(i, desc->id); desc->modelindex = getmodelindex(desc->model); if (desc->trail != "") desc->trailindex = particleeffectnum(strcat("fo-particles.",desc->trail)); diff --git a/share/weapons.qc b/share/weapons.qc index 9c33daa5..fd52b183 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -119,7 +119,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 2, 0.2, 0 }, { WEAP_GRENADE_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 6, 1, 0.6, 4 }, { WEAP_PIPE_LAUNCHER, PRED_MODEL, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL - { WEAP_FLAMETHROWER, PRED_MODEL, AMMO_CELLS, 0, 1, 0.15, 0 }, + { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, PRED_PROJ, AMMO_ROCKETS, 0, 3, -9, 0 }, { WEAP_ASSAULT_CANNON, NO_PREDICT, AMMO_SHELLS, -9, 1, 0.2, 4 }, diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 2fa3a9c2..6b3c65a1 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -573,6 +573,11 @@ void () W_FireFlame = { FO_SetModel(flame, "progs/s_explod.spr"); setsize(flame, '0 0 0', '0 0 0'); setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); + + PredProj_Add(flame); + if (project_weapons) { + AL_ProjectProjectile(flame); + } }; void () IncendiaryRadius = { From 2d5f6ebe92707c11147be705f19a0056393c2590 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 15 Oct 2022 03:09:44 -0700 Subject: [PATCH 1798/2474] Add support for old impulses and quickslots --- csqc/weapon_predict.qc | 23 ++++++++++++++++++----- share/weapon_predict.qc | 5 +++-- share/weapons.qc | 17 +++++++++++++---- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6675de06..24a9fdf8 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -35,6 +35,7 @@ void WP_ChangeWeapon(Slot slot) { if (!WP_CheckAmmo(wi)) return; + pstate_pred.last_slot = pstate_pred.current_slot; pstate_pred.current_slot = slot; pstate_pred.weaponframe = 0; // UpdateViewModel will propagate. @@ -44,12 +45,24 @@ void WP_Reload(); void WP_Impulse() { // Note: We might have no impulse, but a queued slot here. - if (pstate_pred.impulse >= 1 && pstate_pred.impulse <= 7) { // Change weapon - Slot slot = InputToSlot(pstate_pred.impulse); - if (!IsSlotNull(slot)) - pstate_pred.queue_slot = slot; - pstate_pred.impulse = 0; + + float match = TRUE; + switch (pstate_pred.impulse) { + case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: + pstate_pred.impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. + case 1: case 2: case 3: case 4: case 5: case 6: case 7: { + Slot slot = InputToSlot(pstate_pred.impulse); + if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) + pstate_pred.queue_slot = slot; + break; + } + case TF_WEAPLAST: + pstate_pred.queue_slot = pstate_pred.last_slot; break; + default: + match = FALSE; } + if (match) + pstate_pred.impulse = 0; if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) return; diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index 872c64ca..b080867e 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -27,7 +27,7 @@ enumflags { struct predict_tf_state { int playerclass; int impulse; - Slot current_slot, queue_slot; + Slot current_slot, queue_slot, last_slot; float tfstate; @@ -204,7 +204,7 @@ void WeaponPred_Update(entity player) { player.predict_state.client_ping = player.client_ping; M1(FOWP_CLASS, playerclass); - M3(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id); + M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); M1(FOWP_TFSTATE, tfstate); M1(FOWP_WF, weaponframe); M1(FOWP_AF, attack_finished); @@ -257,6 +257,7 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Byte, impulse); COMM(Byte, current_slot.id); COMM(Byte, queue_slot.id); + COMM(Byte, last_slot.id); } if (sendflags & FOWP_TFSTATE) { diff --git a/share/weapons.qc b/share/weapons.qc index fd52b183..32f21a77 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -518,7 +518,7 @@ ImpulseWeapon impulse_weapons[] = { }; Slot FO_ImpulseToSlot(float impulse) { - if (impulse < 1 || impulse > 7) return 0; + if (impulse < 1 || impulse > 7) return SlotNull; return impulse_weapons[self.playerclass].slots[impulse - 1]; } @@ -530,9 +530,15 @@ static float IsPyroSlotSwapped() { return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); } #else -float IsUsingOldImpulses() { return FALSE; } +string(entity e, string key) infokey = #80; -static float IsPyroSlotSwapped() { return FALSE; } +float IsUsingOldImpulses() { + return getplayerkeyfloat(player_localnum, "owi"); +} + +static float IsPyroSlotSwapped() { + return getplayerkeyfloat(player_localnum, "cfpi"); +} #endif float InputHandlePyroSlotSwap(float input) { @@ -547,7 +553,10 @@ Slot FO_SlotByInput(float input) { return FO_ImpulseToSlot(input); } else { input = InputHandlePyroSlotSwap(input); - return MakeSlot(input); + if (input >= 1 && input <= TF_NUM_SLOTS) + return MakeSlot(input); + else + return SlotNull; } } From a10b62d658ceb622dbc5f26a8d114020bc29dd69 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 15 Oct 2022 03:10:41 -0700 Subject: [PATCH 1799/2474] Fix autoid / detpack frame Quick and dirty fix for detpacking not showing an axe. --- share/animate.qc | 2 +- ssqc/demoman.qc | 1 - ssqc/tfort.qc | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/share/animate.qc b/share/animate.qc index 260a8c50..41e66da7 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -222,7 +222,7 @@ void player_stand1() { return; } - if (IsSlotMelee(self.current_slot)) { + if (IsSlotMelee(self.current_slot) || self.is_detpacking) { if (self.walkframe >= 12) self.walkframe = 0; self.frame = 17 + self.walkframe; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 0dee0066..045eb6d4 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -220,7 +220,6 @@ void (float timer) TeamFortress_SetDetpack = { self.immune_to_check = time + 10; self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - self.weapon = IT_AXE; W_QueueAndDisableWeapon(); Status_Refresh(self); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 616b6659..0ba78f3f 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -25,7 +25,7 @@ void () AutoId = { return; } - if (self.client_time > self.ident_time || !self.ident_time) { + if (time > self.ident_time || !self.ident_time) { // remove ident string from memory if (self.ident_string != string_null) { From 4f222056514fe8ee24ace6e9d6f10f4ae7e95aff Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 15 Oct 2022 14:22:16 -0700 Subject: [PATCH 1800/2474] Re-enable projectile matching for SNG It needs its own type because projectile is a different model. --- csqc/weapon_predict.qc | 8 ++++---- share/weapon_predict.qc | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 24a9fdf8..f25aad8a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -520,10 +520,10 @@ void PP_NailFrame() { if (!IsEffectFrame()) return; - float off = 0; - if (wi->weapon == WEAP_NAILGUN) // Else: SNG, no offset. - off = idx ? 4 : -4; - PP_CreateProjectile(&fpp_types[FPP_NAIL], v_right * off); + if (wi->weapon == WEAP_NAILGUN) + PP_CreateProjectile(&fpp_types[FPP_NAIL], v_right * (idx ? 4: - 4)); + else + PP_CreateProjectile(&fpp_types[FPP_SUPER_NAIL], '0 0 0'); } void WP_Attack() { diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index b080867e..a6d02bc5 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -55,6 +55,7 @@ enum { FPP_ROCKET, FPP_INCENDIARY, FPP_NAIL, + FPP_SUPER_NAIL, FPP_FLAMETHROWER, }; @@ -73,6 +74,7 @@ fo_projectile fpp_types[] = { { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl", "" }, { FPP_INCENDIARY, 800, "progs/lavaball.mdl", "t_lavaball" }, { FPP_NAIL, 1500, "progs/spike.mdl", "tr_spike" }, + { FPP_SUPER_NAIL, 1500, "progs/s_spike.mdl", "tr_spike" }, { FPP_FLAMETHROWER, 600, "progs/s_explod.spr", "explodesprite" }, }; From 6f019d5364d7f40017484dfffd90dffe90792d32 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 16 Oct 2022 03:23:08 -0700 Subject: [PATCH 1801/2474] Fix hwguy/demoman buglets Fix hwguy slow speed after firing (bits from next patch series leaked) Fix demoman not being able to fire after setting detpack while reloading (note, client side weaponmodel is showing up on the latter case still, but you can't actually fire. Will fix this properly by moving it into tfstate.) --- csqc/weapon_predict.qc | 5 +++-- share/animate.qc | 2 ++ share/weapons.qc | 10 +++++----- ssqc/weapons.qc | 5 +++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f25aad8a..e2530bac 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -263,10 +263,11 @@ void WPP_Dump() { pstate_pred.client_time, pstate_server.client_time, pstate_pred.attack_finished, pstate_server.attack_finished, pstate_pred.reload_finished, pstate_server.reload_finished); - printf("clip=%d/%d ammo_used=%d\n", + printf("clip=%d/%d ammo_used=%d tfstate=%d/%d\n", pstate_pred.clip_fired[SlotIndex(pstate_pred.current_slot)], pstate_server.clip_fired[SlotIndex(pstate_pred.current_slot)], - pstate_pred.ammo_used[WP_CurrentWeapon()->ammo_type]); + pstate_pred.ammo_used[WP_CurrentWeapon()->ammo_type], + pstate_pred.tfstate, pstate_server.tfstate); } void WP_Attack(); diff --git a/share/animate.qc b/share/animate.qc index 41e66da7..b19e19d4 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -182,6 +182,8 @@ void asscan_down_extra() { if (self.client_thinkindex >= 15) { // 1.5s down self.tfstate &= ~TFSTATE_AIMING; + TeamFortress_SetSpeed(self); + self.fire_held_down = 0; player_run(); if (self.ammo_cells < 7 || !FO_CheckForReload()) { W_PrintWeaponMessage(); diff --git a/share/weapons.qc b/share/weapons.qc index 32f21a77..bf65ca14 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -375,6 +375,7 @@ void (float att_delay) Attack_Finished; // Hack until we fix Status_Refresh() to not be awful. .float last_still_loading; +void W_UpdateCurrentWeapon(entity pl);; void FO_ReloadFrame() { if (self.tfstate & TFSTATE_RELOADING == 0) @@ -384,13 +385,9 @@ void FO_ReloadFrame() { FO_FillWeapState(self, self.current_slot, &ws); FO_WeapInfo* wi = ws.wi; - if (wi->weapon == WEAP_NONE) - return; - if (self.client_time >= self.reload_finished) { self.tfstate &= ~TFSTATE_RELOADING; - self.weaponmodel = ((ws->wi)->models)->model; - self.weaponframe = 0; + W_UpdateCurrentWeapon(self); self.last_still_loading = 0; Status_Refresh(self); sprint(self, PRINT_HIGH, "Finished reloading\n"); @@ -398,6 +395,9 @@ void FO_ReloadFrame() { return; } + if (wi->weapon == WEAP_NONE) + return; + float still_loading = FO_NumClipStillLoading(wi, self.client_time, self.reload_finished); if (self.last_still_loading != still_loading) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2b5cdfb8..42bc7268 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1567,9 +1567,10 @@ void (entity pl) W_UpdateCurrentWeapon = { pl.items |= (wi->items)->ammo_mask; pl.weapon = (wi->items)->it_weapon; - if ((pl.tfstate & TFSTATE_RELOADING == 0) && !pl.is_feigning) + if ((pl.tfstate & TFSTATE_RELOADING == 0) && !pl.is_feigning && + !pl.is_detpacking) { pl.weaponmodel = (wi->models)->model; - else + } else pl.weaponmodel = ""; pl.weaponframe = 0; From 8beeea74a4e068e1291670ea77ffce72d86660dc Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 17 Oct 2022 01:42:23 -0700 Subject: [PATCH 1802/2474] Big tfstate cleanup - Introduce TFSTATE_NO_WEAPON to handle cases where firing is disabled (e.g. detpack, feign, etc). This both standardizes behaviors and allows prediction sync. - Migrate TFSTATE flags to enumflags, remove a bunch of stale ones - Move speed synchronization into Think (triggered off changes in tfstate) rather than trying to make SetSpeeds. - Fix a bug where heavy could fire too fast while moving. - Fix several bug with feign (new and old) --- share/animate.qc | 14 +- share/defs.h | 46 +++-- share/weapon_predict.qc | 2 +- share/weapons.qc | 4 +- ssqc/admin.qc | 6 +- ssqc/client.qc | 36 ++-- ssqc/demoman.qc | 21 +- ssqc/engineer.qc | 12 +- ssqc/hwguy.qc | 3 - ssqc/player.qc | 2 +- ssqc/qw.qc | 1 + ssqc/scout.qc | 6 +- ssqc/sniper.qc | 4 +- ssqc/spy.qc | 414 ++++++---------------------------------- ssqc/tfort.qc | 27 +-- ssqc/weapons.qc | 88 ++++----- 16 files changed, 174 insertions(+), 512 deletions(-) diff --git a/share/animate.qc b/share/animate.qc index b19e19d4..13a94417 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -4,9 +4,10 @@ struct anim_t { int weaponframes[9]; int muzzle_flash; // muzzle flash on weaponframe index 0 int loop; + int freeze_last_frame; // used for feigning death }; -static void think_nop() {} +void think_nop() {} #ifdef SSQC @@ -25,7 +26,6 @@ int W_FireSpanner(); void SuperDamageSound(); void FO_Sound(entity e, float chan, string samp, float vol, float atten); -void TeamFortress_SetSpeed(entity p); void player_run(); void player_stand1(); @@ -51,9 +51,11 @@ void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { muzzleflash(); int fi = tidx % anim->num_frames; + if (tidx >= anim->num_frames && anim->freeze_last_frame) + fi = anim->num_frames - 1; self.frame = anim->frames[fi] ?: anim->frames[0] + fi; - if (fi == anim->num_frames - 1 && !anim->loop) + if (fi == anim->num_frames - 1 && !anim->loop && !anim->freeze_last_frame) FO_SetClientThink(player_run, 0.1); else FO_SetClientThink(parent_thunk, 0.1); @@ -119,7 +121,6 @@ static float CheckNeedAssaultCannonDown() { if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { self.tfstate |= TFSTATE_AIMING; - TeamFortress_SetSpeed(self); player_asscan_down1(); return TRUE; } @@ -130,6 +131,7 @@ void asscan_up_extra() { if (CheckNeedAssaultCannonDown()) return; + self.tfstate |= TFSTATE_AIMING; FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); self.fire_held_down = 1; @@ -162,10 +164,9 @@ void asscan_fire_extra() { self.tfstate |= TFSTATE_AIMING; if (!cannon_move) self.tfstate |= TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); // Halve firing speed when moving too fast. - if (vlen(self.velocity) < 30 || self.count % 2 == 0) + if (vlen(self.velocity) < 30 || self.client_thinkindex % 2 == 1) W_FireAssaultCannon(); } else { FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); @@ -182,7 +183,6 @@ void asscan_down_extra() { if (self.client_thinkindex >= 15) { // 1.5s down self.tfstate &= ~TFSTATE_AIMING; - TeamFortress_SetSpeed(self); self.fire_held_down = 0; player_run(); if (self.ammo_cells < 7 || !FO_CheckForReload()) { diff --git a/share/defs.h b/share/defs.h index 12073b2a..fe259e9c 100644 --- a/share/defs.h +++ b/share/defs.h @@ -241,27 +241,31 @@ //=========================================================================== // TeamFortress State Flags -#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade -#define TFSTATE_RELOADING 2 // Whether the player is reloading -#define TFSTATE_ALTKILL 4 // TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE -#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn -#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon -#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) -#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) -#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) -#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) -#define TFSTATE_BURNING 512 // Is on fire -#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade -#define TFSTATE_AIMING 2048 // is using the laser sight -#define TFSTATE_LOCK 4096 // this state will stop hwguy from shooting assault cannon -#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire, as sentry gun, indicate it needs to die -#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating -#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised -#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack -// FIXME - concussion and flash states aren't set or tested... -#define TFSTATE_FLAMES_MAX 131072 -#define TFSTATE_FLASHED 262144 -#define TFSTATE_CONCUSSED 524288 +enumflags { + TFSTATE_GRENPRIMED, // Whether the player has a primed grenade + TFSTATE_RELOADING, // Whether the player is reloading + TFSTATE_AIMING, // is using the laser sight or spinning + TFSTATE_CANT_MOVE, + TFSTATE_NO_WEAPON, // Weapon is disabled and not visible (e.g. detpack) + // (Note: We don't use NO_WEAPON for reloading + // as it could result in stacked no-weapon states.) + TFSTATE_INFECTED, // set when player is infected by the bioweapon + TFSTATE_INVINCIBLE, // Player has permanent Invincibility (Usually by GoalItem) + TFSTATE_INVISIBLE, // Player has permanent Invisibility (Usually by GoalItem) + TFSTATE_QUAD, // Player has permanent Quad Damage (Usually by GoalItem) + TFSTATE_RADSUIT, // Player has permanent Radsuit (Usually by GoalItem) + TFSTATE_BURNING, // Is on fire + TFSTATE_GRENTHROWING, // is throwing a grenade + TFSTATE_LOCK, // assault cannon locked + TFSTATE_RESPAWN_READY, // is waiting for respawn, and has pressed fire, + // as sentry gun,indicate it needs to die + TFSTATE_HALLUCINATING, // set when player is hallucinating + TFSTATE_TRANQUILISED, // set when player is tranquilised + TFSTATE_FLAMES_MAX, // Peak burnination. + TFSTATE_RANDOMPC, // Whether Playerclass is random, new one each respawn +}; + +#define TFSTATE_AC_MASK (TFSTATE_AC_SPINUP|TFSTATE_AC_SPINNING|TFSTATE_AC_SPINDOWN) // Defines used by TF_T_Damage (see combat.qc) #define TF_TD_IGNOREARMOR 1 // Bypasses the armor of the target diff --git a/share/weapon_predict.qc b/share/weapon_predict.qc index a6d02bc5..f1d095f0 100644 --- a/share/weapon_predict.qc +++ b/share/weapon_predict.qc @@ -448,7 +448,7 @@ void WP_UpdateViewModel() { } - if (WP_IsReloading()) { + if (pstate_pred.tfstate & (TFSTATE_NO_WEAPON | TFSTATE_RELOADING)) { self.modelindex = 0; return; } diff --git a/share/weapons.qc b/share/weapons.qc index bf65ca14..97da5db7 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -375,7 +375,7 @@ void (float att_delay) Attack_Finished; // Hack until we fix Status_Refresh() to not be awful. .float last_still_loading; -void W_UpdateCurrentWeapon(entity pl);; +void W_UpdateCurrentWeapon(entity pl); void FO_ReloadFrame() { if (self.tfstate & TFSTATE_RELOADING == 0) @@ -445,8 +445,6 @@ void FO_ReloadSlot(Slot slot, float force) { Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. - self.weaponmodel = ""; - self.weaponframe = 0; self.tfstate |= TFSTATE_RELOADING; Status_Refresh(self); diff --git a/ssqc/admin.qc b/ssqc/admin.qc index bd56df78..b6d204b1 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -152,8 +152,7 @@ void () Admin_CeaseFire = { while (te) { CenterPrint3(te, "CEASE FIRE\nCalled by: ", self.netname, "\n"); te.immune_to_check = (time + 5); - te.tfstate = (te.tfstate | TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(te); + te.tfstate |= TFSTATE_CANT_MOVE; te = find(te, classname, "player"); } te = spawn(); @@ -180,8 +179,7 @@ void () Admin_CeaseFire = { while (te) { CenterPrint3(te, "RESUME FIRE\nCalled by: ", self.netname, "\n"); te.immune_to_check = (time + 5); - te.tfstate = (te.tfstate - (te.tfstate & TFSTATE_CANT_MOVE)); - TeamFortress_SetSpeed (te); + te.tfstate &= ~TFSTATE_CANT_MOVE; te = find (te, classname, "player"); } } diff --git a/ssqc/client.qc b/ssqc/client.qc index b46ec90e..8eba60e2 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1688,7 +1688,7 @@ void () ClientKill = { set_suicide_frame(); self.modelindex = modelindex_player; - self.weaponmodel = ""; + self.tfstate |= TFSTATE_NO_WEAPON; self.view_ofs = '0 0 -8'; self.movetype = MOVETYPE_NONE; TeamFortress_RemoveTimers(); @@ -2251,8 +2251,7 @@ void () PutClientInServer = { if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); + self.tfstate |= TFSTATE_CANT_MOVE; } if (self.playerclass == 0 && self.team_no > 0) { @@ -2524,8 +2523,7 @@ void () PlayerJump = { } StopAssCan(); } else { - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); + self.tfstate |= TFSTATE_AIMING; } } @@ -2713,8 +2711,7 @@ void () PlayerPreThink = { self.feign_areachecked = 1; if (!(self.tfstate & TFSTATE_CANT_MOVE)) { self.movetype = MOVETYPE_NONE; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); + self.tfstate |= TFSTATE_CANT_MOVE; } } } @@ -2911,6 +2908,19 @@ void () CheckPowerups = { } }; +void FO_HandleTFStateUpdate() { + if (self.last_tfstate == self.tfstate) + return; + + float state_changed = self.last_tfstate ^ self.tfstate; + if (state_changed & TFSTATE_NO_WEAPON) + W_UpdateWeaponModel(self); + if (state_changed & (TFSTATE_AIMING | TFSTATE_CANT_MOVE | TFSTATE_TRANQUILISED)) + TeamFortress_SetSpeed(self); + + self.last_tfstate = self.tfstate; +} + void () PlayerPostThink = { FO_CheckClientThink(); UpdateScoreboardInfo(self); @@ -2962,16 +2972,12 @@ void () PlayerPostThink = { } } self.jump_flag = self.velocity_z; - - if(votemode) { - if (time >= self.StatusRefreshTime) - RefreshStatusBar(self); + if(votemode) { CheckPowerups(); FO_ReloadFrame(); W_WeaponFrame(); //TeamFortress_CheckforCheats(); - //TeamFortress_SetSpeed(self); } else { CheckPowerups(); FO_ReloadFrame(); @@ -2984,13 +2990,15 @@ void () PlayerPostThink = { self.cheat_check = time + 5; } } - if (time >= self.StatusRefreshTime) - RefreshStatusBar(self); if (self.cheat_check <= time) { TeamFortress_CheckTeamCheats(); self.cheat_check = time + 3; } } + + FO_HandleTFStateUpdate(); + if (time >= self.StatusRefreshTime) + RefreshStatusBar(self); }; void () UpdateAllClientsTeamScores = { diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 045eb6d4..346a2e99 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -218,12 +218,9 @@ void (float timer) TeamFortress_SetDetpack = { self.detpack_left = timer; self.ammo_detpack = self.ammo_detpack - 1; self.immune_to_check = time + 10; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - - W_QueueAndDisableWeapon(); + self.tfstate |= TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON; Status_Refresh(self); - TeamFortress_SetSpeed(self); self.pausetime = time + 3; stimer = ftos(timer); @@ -256,12 +253,11 @@ void () TeamFortress_DetpackStop = { self.ammo_detpack = self.ammo_detpack + 1; dremove(detpack_timer); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - self.is_detpacking = 0; // Weapon is queued. + self.is_detpacking = 0; + self.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); self.detpack_left = 0; Status_Refresh(self); - TeamFortress_SetSpeed(self); self.pausetime = time; }; @@ -278,8 +274,7 @@ void () TeamFortress_DetpackSet = { self.owner.is_detpacking = 0; Menu_Close(self.owner); - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self.owner); + self.owner.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); FO_Sound(self.owner, CHAN_VOICE, "doors/medtry.wav", 1, ATTN_NORM); oldself = self; self = self.owner; @@ -401,7 +396,6 @@ void () TeamFortress_DetpackExplode = { sprint(self.owner, PRINT_HIGH, "Your detpack fizzled out\n"); if (self.is_disarming) { - TeamFortress_SetSpeed(self.enemy); dremove(self.oldenemy); dremove(self.observer_list); } @@ -439,12 +433,10 @@ void () TeamFortress_DetpackTouch = { } other.immune_to_check = time + 5; - other.tfstate = other.tfstate | TFSTATE_CANT_MOVE; + other.tfstate |= (TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); sprint(other, PRINT_HIGH, "Disarming detpack...\n"); - TeamFortress_SetSpeed(other); - disarm = spawn(); disarm.owner = other; disarm.enemy = self; @@ -464,9 +456,8 @@ void () TeamFortress_DetpackDisarm = { } bprint(PRINT_MEDIUM, self.enemy.owner.netname, "'s detpack was defused by ", self.owner.netname, "\n"); - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_CANT_MOVE); + self.owner.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); TF_AddFrags(self.owner, 1); - TeamFortress_SetSpeed(self.owner); self.enemy.owner.detpack_left = 0; Status_Refresh(self.enemy.owner); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index a5a9fe27..e4fa286c 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -402,10 +402,8 @@ void () TeamFortress_EngineerBuildStop = { self.is_building = 0; self.building_percentage = 0; if (!engineer_move) { - self.tfstate &= ~TFSTATE_CANT_MOVE; + self.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); self.movetype = MOVETYPE_WALK; - TeamFortress_SetSpeed(self); - // Old weapon already queued. } } @@ -553,11 +551,9 @@ void (float objtobuild) TeamFortress_Build = { self.is_building = 1; if (!engineer_move) { self.immune_to_check = time + 5; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; + self.tfstate |= TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON; self.movetype = MOVETYPE_NONE; - W_QueueAndDisableWeapon(); - TeamFortress_SetSpeed(self); Menu_Engineer_Cancel(); } @@ -904,10 +900,8 @@ void () TeamFortress_FinishedBuilding = { self.is_building = FALSE; self.building_percentage = 0; if (!engineer_move) { - self.tfstate &= ~TFSTATE_CANT_MOVE; + self.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); self.movetype = MOVETYPE_WALK; - TeamFortress_SetSpeed(self); - // Weapon should be queued. } Status_Refresh(self); diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index a8b42038..1fb26f85 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -145,9 +145,6 @@ void FireAssCan (float shotcount, vector dir, vector spread) void StopAssCan() { if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); //self.weaponframe = 0; player_asscan_down1(); } diff --git a/ssqc/player.qc b/ssqc/player.qc index e147bbf2..ab06442d 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -465,7 +465,7 @@ void () PlayerDie = { if (deathmatch || coop) DropBackpack(); - self.weaponmodel = ""; + self.tfstate |= TFSTATE_NO_WEAPON; self.view_ofs = '0 0 -8'; self.deadflag = DEAD_DYING; self.solid = SOLID_NOT; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 856d7c55..a2b5adf2 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -110,6 +110,7 @@ float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT); .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types .float tfstate; // State flags for TeamFortress +.float last_tfstate; // Internal cache of tfstate for detecting updates .entity linked_list; // Used just like chain. Has to be separate so // it doesn't interfere with chain. See T_RadiusScan diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 927f7a57..e5a62026 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -225,7 +225,7 @@ void FO_FlashExplode() if (te.classname == "player") { traceline(self.origin, te.origin, 1, self); if (trace_fraction == 1) { - LogEventAffliction(self.owner, te, TFSTATE_FLASHED); + // LogEventAffliction(self.owner, te, TFSTATE_FLASHED); sprint(te, PRINT_HIGH, "You have been flashed!\n"); org = te.origin + (te.mins + te.maxs) * 0.5; frac = (rad - vlen(self.origin - org)) / rad; @@ -303,7 +303,7 @@ void () FlashGrenadeExplode = { if (te.classname == "player") { traceline(self.origin, te.origin, 1, self); if (trace_fraction == 1) { - LogEventAffliction(self.owner, te, TFSTATE_FLASHED); + // LogEventAffliction(self.owner, te, TFSTATE_FLASHED); if (vlen(self.origin - te.origin) <= 200) { deathmsg = DMSG_GREN_FLASH; TF_T_Damage(te, self, self.owner, 60, 2, 16 | 4); @@ -894,7 +894,7 @@ void (entity inflictor, entity attacker, float bounce, te.nextthink = time + 0.25; } } else { - LogEventAffliction(attacker, head, TFSTATE_CONCUSSED); + // LogEventAffliction(attacker, head, TFSTATE_CONCUSSED); if (old_grens == TRUE) { stuffcmd(head, "v_idlescale 100\n"); stuffcmd(head, "fov 130\n"); diff --git a/ssqc/sniper.qc b/ssqc/sniper.qc index 49ab796e..1c35db55 100644 --- a/ssqc/sniper.qc +++ b/ssqc/sniper.qc @@ -121,9 +121,7 @@ void () SniperSight_Update = { if (!(self.owner.tfstate & TFSTATE_AIMING) || (FO_PlayerCurrentWeapon(self.owner) != WEAP_SNIPER_RIFLE)) { - self.owner.tfstate = - self.owner.tfstate - (self.owner.tfstate & TFSTATE_AIMING); - TeamFortress_SetSpeed(self.owner); + self.owner.tfstate &= ~TFSTATE_AIMING; self.owner.heat = 0; dremove(self); return; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index a23d4165..5f3a3e7e 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -5,353 +5,57 @@ void () T_TranqDartTouch; void () Spy_DropBackpack; void (entity targ, entity attacker) KillSound; -void () spy_diea1 =[50, spy_diea2] { -}; - -void () spy_diea2 =[51, spy_diea3] { -}; - -void () spy_diea3 =[52, spy_diea4] { -}; - -void () spy_diea4 =[53, spy_diea5] { -}; - -void () spy_diea5 =[54, spy_diea6] { -}; - -void () spy_diea6 =[55, spy_diea7] { -}; - -void () spy_diea7 =[56, spy_diea8] { -}; - -void () spy_diea8 =[57, spy_diea9] { -}; - -void () spy_diea9 =[58, spy_diea10] { -}; - -void () spy_diea10 =[59, spy_diea11] { -}; - -void () spy_diea11 =[60, spy_diea11] { -}; - -void () spy_dieb1 =[61, spy_dieb2] { -}; - -void () spy_dieb2 =[62, spy_dieb3] { -}; - -void () spy_dieb3 =[63, spy_dieb4] { -}; - -void () spy_dieb4 =[64, spy_dieb5] { -}; - -void () spy_dieb5 =[65, spy_dieb6] { -}; - -void () spy_dieb6 =[66, spy_dieb7] { -}; - -void () spy_dieb7 =[67, spy_dieb8] { -}; - -void () spy_dieb8 =[68, spy_dieb9] { -}; - -void () spy_dieb9 =[69, spy_dieb9] { -}; - -void () spy_diec1 =[70, spy_diec2] { -}; - -void () spy_diec2 =[71, spy_diec3] { -}; - -void () spy_diec3 =[72, spy_diec4] { -}; - -void () spy_diec4 =[73, spy_diec5] { -}; - -void () spy_diec5 =[74, spy_diec6] { -}; - -void () spy_diec6 =[75, spy_diec7] { -}; - -void () spy_diec7 =[76, spy_diec8] { -}; - -void () spy_diec8 =[77, spy_diec9] { -}; - -void () spy_diec9 =[78, spy_diec10] { -}; - -void () spy_diec10 =[79, spy_diec11] { -}; - -void () spy_diec11 =[80, spy_diec12] { -}; - -void () spy_diec12 =[81, spy_diec13] { -}; - -void () spy_diec13 =[82, spy_diec14] { -}; - -void () spy_diec14 =[83, spy_diec15] { -}; - -void () spy_diec15 =[84, spy_diec15] { -}; - -void () spy_died1 =[85, spy_died2] { -}; - -void () spy_died2 =[86, spy_died3] { -}; - -void () spy_died3 =[87, spy_died4] { -}; - -void () spy_died4 =[88, spy_died5] { -}; - -void () spy_died5 =[89, spy_died6] { -}; - -void () spy_died6 =[90, spy_died7] { -}; - -void () spy_died7 =[91, spy_died8] { -}; - -void () spy_died8 =[92, spy_died9] { -}; - -void () spy_died9 =[93, spy_died9] { -}; - -void () spy_diee1 =[94, spy_diee2] { -}; - -void () spy_diee2 =[95, spy_diee3] { -}; - -void () spy_diee3 =[96, spy_diee4] { -}; - -void () spy_diee4 =[97, spy_diee5] { -}; - -void () spy_diee5 =[98, spy_diee6] { -}; - -void () spy_diee6 =[99, spy_diee7] { -}; - -void () spy_diee7 =[100, spy_diee8] { -}; - -void () spy_diee8 =[101, spy_diee9] { -}; - -void () spy_diee9 =[102, spy_diee9] { -}; - -void () spy_die_ax1 =[41, spy_die_ax2] { -}; - -void () spy_die_ax2 =[42, spy_die_ax3] { -}; - -void () spy_die_ax3 =[43, spy_die_ax4] { -}; - -void () spy_die_ax4 =[44, spy_die_ax5] { -}; - -void () spy_die_ax5 =[45, spy_die_ax6] { -}; - -void () spy_die_ax6 =[46, spy_die_ax7] { -}; - -void () spy_die_ax7 =[47, spy_die_ax8] { -}; - -void () spy_die_ax8 =[48, spy_die_ax9] { -}; - -void () spy_die_ax9 =[49, spy_die_ax9] { -}; - -void () spy_upb1 =[69, spy_upb2] { -}; - -void () spy_upb2 =[68, spy_upb3] { -}; - -void () spy_upb3 =[67, spy_upb4] { -}; - -void () spy_upb4 =[66, spy_upb5] { -}; - -void () spy_upb5 =[65, spy_upb6] { -}; - -void () spy_upb6 =[64, spy_upb7] { -}; - -void () spy_upb7 =[63, spy_upb8] { -}; - -void () spy_upb8 =[62, spy_upb9] { -}; - -void () spy_upb9 =[61, spy_upb9] { - player_stand1(); -}; - -void () spy_upc1 =[84, spy_upc2] { -}; - -void () spy_upc2 =[83, spy_upc3] { -}; - -void () spy_upc3 =[82, spy_upc4] { -}; - -void () spy_upc4 =[81, spy_upc5] { -}; - -void () spy_upc5 =[80, spy_upc6] { -}; - -void () spy_upc6 =[79, spy_upc7] { -}; - -void () spy_upc7 =[78, spy_upc8] { -}; - -void () spy_upc8 =[77, spy_upc9] { -}; - -void () spy_upc9 =[76, spy_upc10] { -}; - -void () spy_upc10 =[75, spy_upc11] { -}; - -void () spy_upc11 =[74, spy_upc12] { -}; - -void () spy_upc12 =[73, spy_upc13] { -}; - -void () spy_upc13 =[72, spy_upc14] { -}; - -void () spy_upc14 =[71, spy_upc15] { -}; - -void () spy_upc15 =[70, spy_upc15] { - player_stand1(); -}; - -void () spy_upd1 =[93, spy_upd2] { -}; - -void () spy_upd2 =[92, spy_upd3] { -}; - -void () spy_upd3 =[91, spy_upd4] { -}; - -void () spy_upd4 =[90, spy_upd5] { -}; - -void () spy_upd5 =[89, spy_upd6] { -}; - -void () spy_upd6 =[88, spy_upd7] { -}; - -void () spy_upd7 =[87, spy_upd8] { -}; - -void () spy_upd8 =[86, spy_upd9] { -}; - -void () spy_upd9 =[85, spy_upd9] { - player_stand1(); -}; - -void () spy_upe1 =[94, spy_upe9] { -}; - -void () spy_upe9; -void () spy_upe2 =[95, spy_upe8] { -}; - -void () spy_upe8; -void () spy_upe3 =[96, spy_upe7] { -}; - -void () spy_upe7; -void () spy_upe4 =[97, spy_upe6] { -}; - -void () spy_upe6; -void () spy_upe5 =[98, spy_upe5] { -}; - -void () spy_upe6 =[99, spy_upe4] { -}; - -void () spy_upe7 =[100, spy_upe3] { -}; - -void () spy_upe8 =[101, spy_upe2] { -}; - -void () spy_upe9 =[102, spy_upe1] { - player_stand1(); -}; - -void () spy_upaxe1 =[49, spy_upaxe2] { -}; - -void () spy_upaxe2 =[48, spy_upaxe3] { -}; - -void () spy_upaxe3 =[47, spy_upaxe4] { -}; - -void () spy_upaxe4 =[46, spy_upaxe5] { -}; +anim_t anim_spy_diea1 = { 11, 1, {50}, {0}, FALSE, FALSE, TRUE }; +void spy_dieaN() { client_anim_frames(spy_dieaN, think_nop, &anim_spy_diea1); } +void spy_diea1() { *thinkindex() = 1; spy_dieaN(); } + +anim_t anim_spy_dieb1 = { 9, 1, {61}, {0}, FALSE, FALSE, TRUE }; +void spy_diebN() { client_anim_frames(spy_diebN, think_nop, &anim_spy_dieb1); } +void spy_dieb1() { *thinkindex() = 1; spy_diebN(); } + +anim_t anim_spy_diec1 = { 15, 1, {70}, {0}, FALSE, FALSE, TRUE }; +void spy_diecN() { client_anim_frames(spy_diecN, think_nop, &anim_spy_diec1); } +void spy_diec1() { *thinkindex() = 1; spy_diecN(); } + +anim_t anim_spy_died1 = { 9, 1, {85}, {0}, FALSE, FALSE, TRUE }; +void spy_diedN() { client_anim_frames(spy_diedN, think_nop, &anim_spy_died1); } +void spy_died1() { *thinkindex() = 1; spy_diedN(); } + +anim_t anim_spy_diee1 = { 9, 1, {94}, {0}, FALSE, FALSE, TRUE }; +void spy_dieeN() { client_anim_frames(spy_dieeN, think_nop, &anim_spy_diee1); } +void spy_diee1() { *thinkindex() = 1; spy_dieeN(); } + +anim_t anim_spy_die_ax1 = { 9, 1, {41}, {0}, FALSE, FALSE, TRUE }; +void spy_die_axN() { client_anim_frames(spy_die_axN, think_nop, &anim_spy_die_ax1); } +void spy_die_ax1() { *thinkindex() = 1; spy_die_axN(); } + +void spy_up_extra() { + // Death animations are variable length, this always picks up last frame. + // Animation transition to stand would take an extra 100ms. + if (self.client_think == player_run) + player_stand1(); +} -void () spy_upaxe5 =[45, spy_upaxe6] { -}; +anim_t anim_spy_upb1 = { 9, 1, {69, 68, 67, 66, 65, 64, 63, 62, 61}, {0}, FALSE, FALSE }; +void spy_upbN() { client_anim_frames(spy_upbN, spy_up_extra, &anim_spy_upb1); } +void spy_upb1() { *thinkindex() = 1; spy_upbN(); } -void () spy_upaxe6 =[44, spy_upaxe7] { -}; +anim_t anim_spy_upc1 = + { 15, 1, {84,83,82,81,80,79,78,77,76,75,74,73,72,71,70}, {0}, FALSE, FALSE }; +void spy_upcN() { client_anim_frames(spy_upcN, spy_up_extra, &anim_spy_upc1); } +void spy_upc1() { *thinkindex() = 1; spy_upcN(); } -void () spy_upaxe7 =[43, spy_upaxe8] { -}; +anim_t anim_spy_upd1 = { 9, 1, {93, 92, 91, 90, 89, 88, 87, 86, 85}, {0}, FALSE, FALSE }; +void spy_updN() { client_anim_frames(spy_updN, spy_up_extra, &anim_spy_upd1); } +void spy_upd1() { *thinkindex() = 1; spy_updN(); } -void () spy_upaxe8 =[42, spy_upaxe9] { -}; +anim_t anim_spy_upe1 = { 9, 1, {102, 101, 100, 99, 98, 97, 96, 95, 94}, {0}, FALSE, FALSE }; +void spy_upeN() { client_anim_frames(spy_upeN, spy_up_extra, &anim_spy_upe1); } +void spy_upe1() { *thinkindex() = 1; spy_upeN(); } -void () spy_upaxe9 =[41, spy_upaxe9] { - player_stand1(); -}; +anim_t anim_spy_upaxe1 = { 9, 1, {49, 48, 47, 46, 45, 44, 43, 32, 41}, {0}, FALSE, FALSE }; +void spy_upaxeN() { client_anim_frames(spy_upaxeN, spy_up_extra, &anim_spy_upaxe1); } +void spy_upaxe1() { *thinkindex() = 1; spy_upaxeN(); } float (entity pe_player) Spy_CheckArea = { local entity at_spot = findradius(pe_player.origin, 64); @@ -379,10 +83,8 @@ void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch = { pe_player.velocity_y = 0; pe_player.movetype = MOVETYPE_TOSS; //This is needed for plats that have a virtual presence and this causes you to fall slowly when inside it - if(!dontstopdead) { - pe_player.tfstate = pe_player.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(pe_player); - } + if(!dontstopdead) + pe_player.tfstate |= TFSTATE_CANT_MOVE; } } }; @@ -393,7 +95,7 @@ void () CF_Spy_AirThink = { if(self.owner.deadflag >= 2) { // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) self.owner.movetype = MOVETYPE_NONE; - self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; + self.owner.tfstate |= TFSTATE_CANT_MOVE; dremove(self); return; } @@ -418,7 +120,7 @@ void () CF_Spy_AirThink = { } else { self.owner.movetype = MOVETYPE_NONE; } - self.owner.tfstate = self.owner.tfstate | TFSTATE_CANT_MOVE; + self.owner.tfstate |= TFSTATE_CANT_MOVE; } } @@ -426,9 +128,6 @@ void () CF_Spy_AirThink = { else { self.owner.movetype = MOVETYPE_TOSS; } - - TeamFortress_SetSpeed(self.owner); - } self.nextthink = time + 0.1; @@ -498,7 +197,7 @@ void (float issilent, float force) FO_Spy_Feign = { setsize(self, '-16 -16 -24', '16 16 -16'); // set weapon state and remove weapon viewmodel - W_QueueAndDisableWeapon(); + self.tfstate |= TFSTATE_NO_WEAPON; // set view height to ground self.view_ofs = '0 0 4'; @@ -543,7 +242,7 @@ void (float issilent, float force) FO_Spy_Feign = { } // die with axe equipped if carrying axe, medikit, knife or spanner - if (self.weapon <= WEAP_AXE) { + if (IsSlotMelee(self.current_slot)) { spy_die_ax1(); return; } @@ -605,8 +304,7 @@ void () FO_Spy_Unfeign = { // allow spy to move again self.movetype = MOVETYPE_WALK; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_CANT_MOVE); - TeamFortress_SetSpeed(self); + self.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); // set revive animation local float i; @@ -1428,14 +1126,13 @@ void () T_TranqDartTouch = { } } else { sprint(other, 2, "You feel tired...\n"); - other.tfstate = other.tfstate | TFSTATE_TRANQUILISED; + other.tfstate |= TFSTATE_TRANQUILISED; timer = spawn(); timer.nextthink = time + 15; timer.think = TranquiliserTimer; timer.classname = "timer"; timer.owner = other; timer.team_no = self.owner.team_no; - TeamFortress_SetSpeed(other); } } spawn_touchblood(9); @@ -1461,8 +1158,7 @@ void () T_TranqDartTouch = { }; void () TranquiliserTimer = { - self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_TRANQUILISED); - TeamFortress_SetSpeed(self.owner); + self.owner.tfstate &= ~TFSTATE_TRANQUILISED; sprint(self.owner, PRINT_HIGH, "You feel more alert now\n"); dremove(self); }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 0ba78f3f..c1761d1e 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -344,8 +344,7 @@ void (float inp) TeamFortress_ChangeClass = { if (cease_fire) { sprint(self, PRINT_HIGH, "\n\nCease fire mode\n"); self.immune_to_check = time + 10; - self.tfstate = self.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); + self.tfstate |= TFSTATE_CANT_MOVE; } self.spawn_time = time; @@ -1286,7 +1285,7 @@ void (entity p) TeamFortress_SetSpeed = { local entity te; stuffcmd(p, "cl_movespeedkey 1\n"); - if (p.tfstate & TFSTATE_CANT_MOVE || (p.is_building == 1 && !engineer_move) || p.is_detpacking > 0) { + if (p.tfstate & TFSTATE_CANT_MOVE) { #ifdef STOP_MOUSE_MOVEMENT stuffcmd(p, "m_forward 0\n"); stuffcmd(p, "m_side 0\n"); @@ -1379,16 +1378,8 @@ void (entity p) TeamFortress_SetSpeed = { } } sp = ftos(p.maxfbspeed); - stuffcmd(p, "cl_backspeed "); - stuffcmd(p, sp); - stuffcmd(p, "\n"); - stuffcmd(p, "cl_forwardspeed "); - stuffcmd(p, sp); - stuffcmd(p, "\n"); - sp = ftos(p.maxstrafespeed); - stuffcmd(p, "cl_sidespeed "); - stuffcmd(p, sp); - stuffcmd(p, "\n"); + stuffcmd(p, "cl_backspeed ", sp, "; cl_forwardspeed ", sp, + "; cl_sidespeed ", sp, "\n"); p.maxspeed = p.maxfbspeed; }; @@ -2236,8 +2227,8 @@ void () TeamFortress_SetEquipment = { if (self.last_playerclass != self.playerclass) W_ChangeToBestWeapon(); - else - W_UpdateCurrentWeapon(self); + + W_UpdateCurrentWeapon(self); self.last_playerclass = self.playerclass; }; @@ -2356,8 +2347,7 @@ void () TeamFortress_RemoveTimers = { self.is_building = 0; self.building = world; if (self.tfstate & TFSTATE_AIMING) { - self.tfstate = self.tfstate - TFSTATE_AIMING; - TeamFortress_SetSpeed(self); + self.tfstate &= ~TFSTATE_AIMING; self.heat = 0; } if (self.tfstate & TFSTATE_INFECTED) @@ -3213,8 +3203,7 @@ void (entity p) KickCheater = { p.touch = SUB_Null; p.health = 0; p.solid = SOLID_NOT; - p.tfstate = p.tfstate | TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(p); + p.tfstate |= TFSTATE_CANT_MOVE; TeamFortress_RemoveTimers(); }; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 42bc7268..5139cfa1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -478,10 +478,7 @@ int () W_FireMedikit = { if (te != world) { - trace_ent.tfstate = - trace_ent.tfstate - - (trace_ent.tfstate & TFSTATE_TRANQUILISED); - TeamFortress_SetSpeed(trace_ent); + trace_ent.tfstate &= ~TFSTATE_TRANQUILISED; SpawnBlood(org, 20); bprint(PRINT_MEDIUM, self.netname, " healed ", @@ -1552,6 +1549,17 @@ void () superspike_touch = { dremove(self); }; +void W_UpdateWeaponModel(entity pl) { + FO_WeapState ws; + FO_FillWeapState(pl, pl.current_slot, &ws); + FO_WeapInfo* wi = ws.wi; + + if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) + pl.weaponmodel = (wi->models)->model; + else + pl.weaponmodel = ""; +} + void (entity pl) W_UpdateCurrentWeapon = { entity oldself; @@ -1567,11 +1575,7 @@ void (entity pl) W_UpdateCurrentWeapon = { pl.items |= (wi->items)->ammo_mask; pl.weapon = (wi->items)->it_weapon; - if ((pl.tfstate & TFSTATE_RELOADING == 0) && !pl.is_feigning && - !pl.is_detpacking) { - pl.weaponmodel = (wi->models)->model; - } else - pl.weaponmodel = ""; + W_UpdateWeaponModel(pl); pl.weaponframe = 0; // refresh engineer build menu when ammo updated @@ -1632,7 +1636,8 @@ void () W_Attack = { if (self.has_disconnected == TRUE) return; - if (self.tfstate & TFSTATE_RELOADING || self.is_detpacking) + if (self.tfstate & TFSTATE_RELOADING || + self.tfstate & TFSTATE_NO_WEAPON) return; if (no_fire_mode) @@ -1720,8 +1725,7 @@ void () W_Attack = { self.ammo_cells -= - 7; self.count = 0; self.immune_to_check = time + 5; - self.tfstate = self.tfstate | TFSTATE_AIMING; - TeamFortress_SetSpeed(self); + self.tfstate |= TFSTATE_AIMING; player_asscan_up1(); } } else if (ws.weapon == WEAP_FLAMETHROWER) { @@ -1775,7 +1779,7 @@ void () W_Attack = { float WeaponReady() { if (self.client_time >= self.attack_finished && - !(self.tfstate & TFSTATE_RELOADING)) + !(self.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON))) return TRUE; return FALSE; @@ -1885,20 +1889,13 @@ void W_ChangeWeaponByInput(float input) { W_ChangeWeaponSlot(slot); } -void W_QueueAndDisableWeapon() { - self.queue_slot = self.current_slot; - // We don't want to actually call Update/Change since that could affect what - // other players see. Caller should be setting some state that holds back - // the queue (e.g. feigned). - self.current_slot = SlotNull; - self.weaponmodel = ""; - self.weaponframe = 0; -} - void W_ChangeWeaponSlot(Slot slot) { if (self.playerclass == 0) return; + if (!IsSlotNull(slot)) + slot = MakeSlot(1); + FO_WeapState ws; FO_FillWeapState(self, slot, &ws); if (ws.weapon == WEAP_NONE) @@ -1975,17 +1972,13 @@ Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { } void W_ChangeWeaponNext() { - if (self.weaponmodel == string_null || IsSlotNull(self.current_slot)) - return; - - W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, FALSE)); + Slot slot = IsSlotNull(self.current_slot) ? MakeSlot(1) : self.current_slot; + W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, FALSE)); } void W_ChangeWeaponPrev() { - if (self.weaponmodel == string_null || IsSlotNull(self.current_slot)) - return; - - W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(self.current_slot, TRUE)); + Slot slot = IsSlotNull(self.current_slot) ? MakeSlot(1) : self.current_slot; + W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, TRUE)); } void () PreMatchImpulses; @@ -2044,7 +2037,7 @@ void () ImpulseCommands = { } else if (self.impulse == TF_TOGGLEVOTE) Vote_ToggleMenu(self); - if ((!self.is_building && !self.is_detpacking) && !self.is_feigning) { + if (self.tfstate & TFSTATE_NO_WEAPON == 0) { if (self.impulse == TF_WEAPNEXT) W_ChangeWeaponNext(); else if (self.impulse == TF_WEAPPREV) @@ -2067,11 +2060,10 @@ void () ImpulseCommands = { TeamFortress_SetDetpack(50); else if (self.impulse == TF_DROP_AMMO) { Menu_Drop(); - } - else if (self.impulse == TF_PRACSPAWN_PLACE) - TeamFortress_PlacePracticeSpawn(self); - else if (self.impulse == TF_PRACSPAWN_REMOVE) - TeamFortress_RemovePracticeSpawn(self); + } else if (self.impulse == TF_PRACSPAWN_PLACE) + TeamFortress_PlacePracticeSpawn(self); + else if (self.impulse == TF_PRACSPAWN_REMOVE) + TeamFortress_RemovePracticeSpawn(self); } if (self.impulse == TF_INVENTORY) @@ -2129,9 +2121,9 @@ void () ImpulseCommands = { Menu_Spy_Skin(); } else if ((self.impulse == TF_SPY_DIE) && (self.playerclass == PC_SPY)) FO_Spy_FeignCmd(0); - else if ((self.impulse == TF_SPY_DIE_ON) && (self.playerclass == PC_SPY)) { + else if ((self.impulse == TF_SPY_DIE_ON) && (self.playerclass == PC_SPY)) FO_Spy_FeignOnNextDamage(); - } else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) + else if ((self.impulse == TF_SPY_SILENT_DIE) && (self.playerclass == PC_SPY)) FO_Spy_FeignCmd(1); else if (self.impulse == TF_DISGUISE_RESET && self.playerclass == PC_SPY) { CF_Spy_ChangeSkin(self, 8, TRUE); @@ -2571,7 +2563,6 @@ void () W_WeaponFrame = { return; } - if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && @@ -2593,8 +2584,7 @@ void () W_WeaponFrame = { if (self.impulse == TF_QUICKSTOP) self.impulse = self.qf_swap_last_slot ? TF_WEAPLAST : 0; - float can_change_weapon = WeaponReady() && - !self.is_detpacking && !(self.is_building && !engineer_move); + float can_change_weapon = WeaponReady(); // TODO: Open up queueing by moving queue can_change to ChangeWeapon? if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() && @@ -2687,6 +2677,10 @@ void () W_WeaponFrame = { case TF_CHANGEPC_RANDOM: case TF_INVENTORY: case FLAG_INFO: + case TF_SPY_DIE: + case TF_SPY_DIE_ON: + case TF_SPY_DIE_OFF: + case TF_SPY_SILENT_DIE: ImpulseCommands(); return; // allows setting detpack while reloading on toggle, defaults to off @@ -2738,9 +2732,8 @@ void () W_WeaponFrame = { if (vlen(tv) <= 50) { SniperSight_Create(); self.heat = 50; - self.tfstate = self.tfstate | 2048; + self.tfstate |= TFSTATE_AIMING; self.power_full = 0; - TeamFortress_SetSpeed(self); } } } else if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON) { @@ -2757,12 +2750,7 @@ void () W_WeaponFrame = { } } else if (self.tfstate & TFSTATE_AIMING) { W_Attack(); - self.tfstate = self.tfstate - TFSTATE_AIMING; - TeamFortress_SetSpeed(self); - self.heat = 0; - } else if (self.tfstate & TFSTATE_CANT_MOVE && !self.is_feigning) { - self.tfstate = self.tfstate - TFSTATE_CANT_MOVE; - TeamFortress_SetSpeed(self); + self.tfstate &= ~TFSTATE_AIMING; self.heat = 0; } }; From 4dc9b7535e9540b1d6e92decfec1d9b3388b7a02 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 17 Oct 2022 14:49:15 -0700 Subject: [PATCH 1803/2474] Fix inverted slot check A null check was inverted on the last commit, blocking some operations --- ssqc/weapons.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5139cfa1..cdc59c26 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1893,8 +1893,8 @@ void W_ChangeWeaponSlot(Slot slot) { if (self.playerclass == 0) return; - if (!IsSlotNull(slot)) - slot = MakeSlot(1); + if (IsSlotNull(slot)) + slot = SlotMelee; // Make Nulls noticeable... FO_WeapState ws; FO_FillWeapState(self, slot, &ws); @@ -1972,12 +1972,12 @@ Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { } void W_ChangeWeaponNext() { - Slot slot = IsSlotNull(self.current_slot) ? MakeSlot(1) : self.current_slot; + Slot slot = IsSlotNull(self.current_slot) ? SlotMelee : self.current_slot; W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, FALSE)); } void W_ChangeWeaponPrev() { - Slot slot = IsSlotNull(self.current_slot) ? MakeSlot(1) : self.current_slot; + Slot slot = IsSlotNull(self.current_slot) ? SlotMelee : self.current_slot; W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, TRUE)); } From 43be486c67deb5fdde165d0576b69c82cacfc56f Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 19 Oct 2022 16:49:08 -0700 Subject: [PATCH 1804/2474] Fix weapon model showing during reload The update function handled reload, the wrapper wasn't watching for it. --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 8eba60e2..727b40bc 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2913,7 +2913,7 @@ void FO_HandleTFStateUpdate() { return; float state_changed = self.last_tfstate ^ self.tfstate; - if (state_changed & TFSTATE_NO_WEAPON) + if (state_changed & (TFSTATE_NO_WEAPON | TFSTATE_RELOADING)) W_UpdateWeaponModel(self); if (state_changed & (TFSTATE_AIMING | TFSTATE_CANT_MOVE | TFSTATE_TRANQUILISED)) TeamFortress_SetSpeed(self); From e4e1597effda3c6d4b42cfb2a2dabc7b0025a8de Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 19 Oct 2022 16:45:17 -0700 Subject: [PATCH 1805/2474] Dyamic enable for CSQC weapon and projectile prediction Generally makes the feature dynamically enabled, rather than at map load and connect time. Global controls: wp_global_enable (wpge) [on/off] (default: off) wp_global_disable (wpgd) [on/off] (default: off) pp_global_enable (pppp) [on/off] (default: off) pp_global_disable (ppgd) [on/off] (default: off) [Where "wp" controls weapon model prediction, and "pp" projectile prediction ] Which combine with client side controls: fo_weap_predict [-1, 0, 1] (default: -1 => off unless explicitly enabled) fo_proj_predict [-1, 0, 1] (default: -1 => on when ping > min ping) fo_wp_minping [40] Client settings of 0/1 dominate server settings except for global disables which force all clients off. Client settings of -1 use the default/server global enable state when ping is higher than fo_wp_minping. We use a moving average and only update when the variance is sufficiently low (e.g. temporary spikes should not be pushing projectiles on and off) [ We currently default weapon prediction to off as there is still the occasional frame skip, derpy animation. ] --- csqc/csprogs.src | 2 +- csqc/main.qc | 4 +- csqc/weapon_predict.qc | 262 ++++++++++++++++++++- share/{weapon_predict.qc => prediction.qc} | 212 +++++------------ ssqc/client.qc | 4 +- ssqc/progs.src | 2 +- 6 files changed, 317 insertions(+), 169 deletions(-) rename share/{weapon_predict.qc => prediction.qc} (71%) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 49b381e7..8c163ac6 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -15,7 +15,7 @@ csextradefs.qc ../share/common_helpers.qc ../share/common_vote.qc ../share/weapons.qc -../share/weapon_predict.qc +../share/prediction.qc ../share/animate.qc weapon_predict.qc sui_sys.qc diff --git a/csqc/main.qc b/csqc/main.qc index 4f75b871..30c7bef3 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -29,7 +29,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Weapons_Init(); FO_PP_Init(); // Some of this is always used by custom projectiles. - FO_WP_Init(FALSE); // Server packet enables. CsGrenTimer::Init(); registercommand("fo_hud_editor"); @@ -125,7 +124,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) setproperty(VF_DRAWENGINESBAR, 1); - addentities((intermission?0:wp_model_mask)|MASK_ENGINE); + addentities((intermission?0:WPP_ViewModelMask())|MASK_ENGINE); renderscene(); @@ -443,6 +442,7 @@ noref void CSQC_Input_Frame() { input_impulse = 0; } + WPP_UpdateEnable(FALSE); Sync_GameState(); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index e2530bac..967808bc 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,7 +1,146 @@ DEFCVAR_FLOAT(wpp_debug, 0); -inline FO_WeapInfo* WP_CurrentWeapon() { - return FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); + +DEFCVAR_FLOAT(fo_wp_minping, 40); +DEFCVAR_FLOAT(fo_weap_predict, -1); +DEFCVAR_FLOAT(fo_proj_predict, -1); + +float default_proj_predict = TRUE; +float default_weap_predict = FALSE; + +void WP_UpdateViewModel(entity pweap_ent); + +static inline float sq(float x) { return x * x; } + +#define NUM_PING_SAMPLES 20 + +struct { + float s1, s2, count; +} avg_ping; + +static void update_avg_ping() { + static float samples[NUM_PING_SAMPLES]; + + // We use a fairly low clamp here because: + // a) We want to limit the effect of momentary total loss + // b) We actually want high pings to have low effective variance and + // trigger it on consistently. + float new = min(getplayerkeyfloat(player_localnum, INFOKEY_P_PING), 200); + + float idx = avg_ping.count++ % NUM_PING_SAMPLES; + float old = samples[idx]; + samples[idx] = new; + + avg_ping.s1 += new - old; + avg_ping.s2 += sq(new) - sq(old); +} + +static float get_avg_ping(float* mean, float* variance) { + float n = max(min(NUM_PING_SAMPLES, avg_ping.count), 2); + *mean = avg_ping.s1 / n; + *variance = (avg_ping.s2 - sq(avg_ping.s1)/n) / (n - 1); + return n; +} + +// Order of preference: +// server disable, client enable/disable, server/ping enable +static float CalcPredEnabled(float current_enable, + float unspec_default /* meaning of '-1' */, + float server_disable, float server_enable, + float client_value, string* set_by) { + if (server_disable || client_value == 0) { + *set_by = server_disable ? "[server disable]" : "[cvar disable]"; + + return FALSE; + } + if (client_value == 1) { + *set_by = sprintf("[cvar enable]"); + return TRUE; + } + + if (CVARF(fo_wp_minping) < 0) + return current_enable; + + float ping_enable, avg, variance; + + get_avg_ping(&avg, &variance); + // We wait until 5ms over target (or 5 ms under target) when flipping, to + // avoid flip flopping when ping is right at target. + if (variance < sq(15)) + ping_enable = avg > CVARF(fo_wp_minping) + (current_enable ? -5 : 5); + else + return current_enable; // variance too high, don't change anything. + + + if (unspec_default || server_enable) { + if (ping_enable) { + *set_by = sprintf("[ping] (fo_wp_minping=%0.0f / avg=%0.0f var=%0.0f)", + CVARF(fo_wp_minping), avg, variance); + return TRUE; + } else { + *set_by = "[lan mode <40]"; + return FALSE; + } + } + + *set_by = "[default]"; + return FALSE; +} + +#define ENABLE_CHECK_PERIOD 2 +static float next_wpp_enable_check; +static float next_ping_update; + +void WPP_UpdateEnable(float force) { + if (time > next_ping_update) { + update_avg_ping(); + next_ping_update = time + ENABLE_CHECK_PERIOD / NUM_PING_SAMPLES; + + float avg, variance; + get_avg_ping(&avg, &variance); + } + + if (avg_ping.count < NUM_PING_SAMPLES / 2) + return; // Skip until we have a useful number of samples. + + if (!force && time < next_wpp_enable_check) + return; + next_wpp_enable_check = time + ENABLE_CHECK_PERIOD; + + // Tristate: 1 => force on, 0 => force off, -1 => up to minping/server + float wp_new = -1, pp_new = -1; + string wp_source, pp_source; + + wp_new = CalcPredEnabled(pengine.wp_enabled, default_weap_predict, + pstate_server.predict_flags & PF_WP_DISABLE, + pstate_server.predict_flags & PF_WP_ENABLE, + CVARF(fo_weap_predict), &wp_source); + + pp_new = CalcPredEnabled(pengine.pp_enabled, default_proj_predict, + pstate_server.predict_flags & PF_PP_DISABLE, + pstate_server.predict_flags & PF_PP_ENABLE, + CVARF(fo_proj_predict), &pp_source); + + static float once; + if (wp_new != pengine.wp_enabled || !once) { + printf("FortressOne: Weapon prediction %s %s\n", + wp_new ? "enabled" : "disabled", wp_source); + pengine.wp_enabled = wp_new; + } + + if (pp_new != pengine.pp_enabled || !once) { + printf("FortressOne: Projectile prediction %s %s\n", + pp_new ? "enabled" : "disabled", pp_source); + pengine.pp_enabled = pp_new; + } + once = TRUE; + + // We always need to "render" the view model to trigger predraw compute. + pengine.view_mask = MASK_PRED_VIEWMODEL | + (pp_new ? MASK_PRED_PROJECTILE : 0); + + if (pengine.pweap_ent != __NULL__) + WP_UpdateViewModel(pengine.pweap_ent); } static inline float IsEffectFrame() { @@ -13,6 +152,10 @@ static inline float IsEffectFrame() { //////////////////////////////////////////////////////////////////////////////// float animate_s_time; +inline FO_WeapInfo* WP_CurrentWeapon() { + return FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); +} + // Corrections for when we can recognize that we missed a packet. void WP_ServerUpdate() { if (pstate_server.attack_finished < pstate_server.client_time) @@ -251,10 +394,6 @@ void WP_AnimateModel() { } } -void WP_DoClientThink(void) { - WP_AnimateModel(); -} - void WPP_Dump() { printf("cti p=%d s=%d wf=%d/%d\n", pstate_pred.client_thinkindex, pstate_server.client_thinkindex, @@ -263,11 +402,15 @@ void WPP_Dump() { pstate_pred.client_time, pstate_server.client_time, pstate_pred.attack_finished, pstate_server.attack_finished, pstate_pred.reload_finished, pstate_server.reload_finished); - printf("clip=%d/%d ammo_used=%d tfstate=%d/%d\n", - pstate_pred.clip_fired[SlotIndex(pstate_pred.current_slot)], - pstate_server.clip_fired[SlotIndex(pstate_pred.current_slot)], + + int slot_index = SlotIndex(pstate_pred.current_slot); + if (slot_index >= 0) { + printf("clip=%d/%d ammo_used=%d tfstate=%d/%d\n", + pstate_pred.clip_fired[slot_index], + pstate_server.clip_fired[slot_index], pstate_pred.ammo_used[WP_CurrentWeapon()->ammo_type], pstate_pred.tfstate, pstate_server.tfstate); + } } void WP_Attack(); @@ -469,6 +612,7 @@ inline float PP_PredictStartOffset() { static float PP_EPS = 0.05; entity PP_CreateProjectile(fo_projectile* desc, vector offset) { + printf("PredProj Create\n"); entity proj = spawn(); proj.s_time = time + PP_PredictStartOffset(); @@ -476,7 +620,7 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { proj.endtime = time + pstate_pred.client_ping + PP_EPS + 2; proj.predraw = PP_PredrawPredicted; - proj.drawmask = MASK_ENGINE; + proj.drawmask = MASK_PRED_PROJECTILE; setsize(proj, [0,0,0], [0,0,0]); proj.p_time = 0; @@ -518,7 +662,7 @@ void PP_NailFrame() { float idx = (pstate_pred.client_thinkindex + 1) % 2; - if (!IsEffectFrame()) + if (!IsEffectFrame() || !PP_Enabled()) return; if (wi->weapon == WEAP_NAILGUN) @@ -548,7 +692,7 @@ void WP_Attack() { // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 1; - if (IsEffectFrame() && !in_anim) { + if (PP_Enabled() && IsEffectFrame() && !in_anim) { switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: PP_CreateProjectile(&fpp_types[FPP_ROCKET], v_forward * 8); @@ -650,7 +794,101 @@ void InitProjPredEnt() { PP_InitTrail(self); // Note: Might be overwritten by inherited match. + // We still check this with projectile prediction as there could be in + // flight projectiles on the transition. This is effectively a nop in the + // off case since the projectile list will just be empty. if (self.owner_entnum == player_localentnum) PredProjectile_MatchProjectile(); } + +void WP_UpdateViewModel(entity pweap_ent) { + float pmodelindex, pframe; + + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, + pstate_pred.current_slot); + + // Note, even if the predicted weapon model is not visible we might still be + // using it to generated predicted projectiles. E.g. we need to keep + // PRED_VIEWMODEL in the render mask. + if (!WP_Enabled() || wi->predict_type == NO_PREDICT) { + // Fall back to engine. + pweap_ent.modelindex = 0; + pengine.view_mask |= MASK_VIEWMODEL; + return; + } else { + pengine.view_mask &= ~MASK_VIEWMODEL; + } + + if (pstate_pred.tfstate & (TFSTATE_NO_WEAPON | TFSTATE_RELOADING)) { + pweap_ent.modelindex = 0; + return; + } + + pmodelindex = (wi->models)->modelindex; + pframe = pstate_pred.weaponframe; + + if (pweap_ent.modelindex != pmodelindex) { + pweap_ent.frame = pframe; + pweap_ent.modelindex = pmodelindex; + pweap_ent.lerpfrac = 0; + } else if (self.frame != pframe) { + pweap_ent.frame2 = self.frame; + pweap_ent.frame = pframe; + pweap_ent.lerpfrac = 1; + } + + pweap_ent.lerpfrac = max(0, pweap_ent.lerpfrac - frametime * 10); +} + +float WP_ClientThink() { + // Can only fully disable if both weapon and projectile prediction are off. + if (!WP_Enabled() && !PP_Enabled()) + return PREDRAW_NEXT; + + pstate_pred = pstate_server; + + int pframe = servercommandframe + 1; + int eframe = clientcommandframe; + for(; pframe <= eframe; pframe++) { + if (!getinputstate(pframe) || input_timelength <= 0) + break; + + makevectors(input_angles); + if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { + pengine.is_effectframe = TRUE; + pengine.last_effectframe = pframe; + } else { + pengine.is_effectframe = FALSE; + } + + pstate_pred.client_time += input_timelength; + if (input_impulse) + pstate_pred.impulse = input_impulse; + + while (pstate_pred.client_nextthink && + pstate_pred.client_time >= pstate_pred.client_nextthink) { + float held_client_time = pstate_pred.client_time; + + pstate_pred.client_time = pstate_pred.client_nextthink; + pstate_pred.client_nextthink = 0; + WP_AnimateModel(); + pstate_pred.client_time = held_client_time; + } + + WP_Frame(); + } + + WP_UpdateViewModel(self); + return PREDRAW_AUTOADD; +} + +void InitWeapPredEnt(entity pe) { + pe.predraw = WP_ClientThink; + + self.drawmask = MASK_PRED_VIEWMODEL; + self.renderflags = RF_VIEWMODEL; + + pengine.pweap_ent = self; +} + diff --git a/share/weapon_predict.qc b/share/prediction.qc similarity index 71% rename from share/weapon_predict.qc rename to share/prediction.qc index f1d095f0..86cd5de0 100644 --- a/share/weapon_predict.qc +++ b/share/prediction.qc @@ -1,7 +1,7 @@ #define ENT_WEAPONPRED 100 #define ENT_PROJECTILE 101 -string wp_version = "v1"; +string wp_version = "v0.1"; enumflags { FOWP_CTIME, @@ -15,6 +15,7 @@ enumflags { FOWP_CLASS, FOWP_RELOAD, FOWP_RNG, + FOWP_PREDICT_FLAGS, }; enumflags { @@ -24,8 +25,15 @@ enumflags { #define FOWP_ALL 0xFFFF +#define PF_WP_ENABLE 1 +#define PF_WP_DISABLE 2 +#define PF_PP_ENABLE 4 +#define PF_PP_DISABLE 8 +#define PF_ED_MASK (PF_WP_ENABLE | PF_WP_DISABLE | PF_PP_ENABLE | PF_PP_DISABLE) + struct predict_tf_state { int playerclass; + int predict_flags; int impulse; Slot current_slot, queue_slot, last_slot; @@ -114,50 +122,34 @@ void WeaponPred_InitOnce() { InitFppProjectiles(); } -static float ClientEnable() { - WeaponPred_InitOnce(); - - // client_ping is not yet initialized. - float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; - - float min_ping = - FO_GetUserSetting(self, "fowpmp", "fo_weapon_predict_minping", "40"); - - if (weaponpred_settings.global_disable || ping < min_ping * MSEC) - return FALSE; - - if (weaponpred_settings.global_enable) - return TRUE; - - return FO_GetUserSetting(self, "fowp", "fo_weapon_predict", "off"); -} - -.float weapon_pred_enabled; .predict_tf_state predict_state; .entity predict_entity; .float client_nextthink; .float client_thinkindex; #else -predict_tf_state pstate_pred, pstate_server; struct pengine_t { + float pp_enabled; + float wp_enabled; float is_effectframe; float last_effectframe; + + entity pweap_ent; + + // Must include MASK_PRED_VIEWMODEL or we lose updates. + // We only add/remove MASK_VIEWMODEL and MASK_PRED_PROJECTILE + float view_mask; } pengine; -#define MASK_PRED_VIEWMODEL 256 -// Must include MASK_PRED_VIEWMODEL or we lose updates. -// We only add/remove MASK_VIEWMODEL. -float wp_model_mask; -float wp_enabled; +inline float PP_Enabled() { return pengine.pp_enabled; } +inline float WP_Enabled() { return pengine.wp_enabled; } +inline float WPP_ViewModelMask() { return pengine.view_mask; } -inline int WP_Enabled() { return wp_enabled; } +predict_tf_state pstate_pred, pstate_server; +#define MASK_PRED_VIEWMODEL 256 +#define MASK_PRED_PROJECTILE 512 -void FO_WP_Init(float enabled) { - wp_enabled = enabled; - wp_model_mask = enabled ? MASK_PRED_VIEWMODEL : MASK_VIEWMODEL; -} #endif #ifdef SSQC @@ -193,12 +185,42 @@ float shared_prng(entity pl) { // A 16-bit xor-shift LFSR. predict_tf_state blank_state; .float last_full_predict_refresh; +static void WeaponPred_UpdatePredictionFlags() { + float wpp_enable = FALSE, wp_enable = FALSE, pp_enable = FALSE; + float wpp_disable = FALSE, wp_disable = FALSE, pp_disable = FALSE; + + wp_enable = CF_GetSetting("wpge", "wp_global_enable", "off"); + wp_disable = CF_GetSetting("wpgd", "wp_global_disable", "off"); + pp_enable = CF_GetSetting("ppge", "pp_global_enable", "off"); + pp_disable = CF_GetSetting("ppgd", "pp_global_disable", "off"); + wpp_enable = CF_GetSetting("wppge", "wpp_global_enable", "off"); + wpp_disable = CF_GetSetting("wppge", "wpp_global_disable", "off"); + + float wp_mask = 0, pp_mask = 0; + + // Disables dominate enables. + if (wpp_disable || wp_disable) + wp_mask = PF_WP_DISABLE; + else if (wpp_enable || wp_enable) + wp_mask = PF_WP_ENABLE; + if (wpp_disable || pp_disable) + pp_mask = PF_PP_DISABLE; + else if (wpp_enable || pp_enable) + pp_mask = PF_PP_ENABLE; + + self.predict_state.predict_flags &= ~PF_ED_MASK; + self.predict_state.predict_flags |= wp_mask | pp_mask; + + // Note: Flag to send is simply the all-bits periodic. +} + void WeaponPred_Update(entity player) { float mask = FOWP_CTIME; - if (time - player.last_full_predict_refresh > 5000 * MSEC) { + if (time - player.last_full_predict_refresh >= 1000 * MSEC) { player.predict_state = blank_state; player.last_full_predict_refresh = time; + WeaponPred_UpdatePredictionFlags(); mask = -1; } @@ -246,6 +268,9 @@ void WP_ServerUpdate(); void EntUpdate_WeaponPred(float isnew) { float sendflags = readfloat(); #endif + if (sendflags & FOWP_PREDICT_FLAGS) + COMM(Float, predict_flags); + if (sendflags & FOWP_CTIME) { COMM(Float, client_time); COMM(Float, client_ping); @@ -369,23 +394,14 @@ void EntUpdate_Projectile(float isnew) { #undef COMM #ifdef SSQC -inline float WeaponPred_Active(entity player) { - return player.weapon_pred_enabled; -} - void WeaponPred_InitPlayer(entity player) { WeaponPred_InitOnce(); + sprint(player, PRINT_HIGH, + "FortressOne: Weapon Prediction ", wp_version, "\n"); sprint(player, PRINT_HIGH, "FortressOne: CSQC projectiles ", weaponpred_settings.new_projectiles ? "enabled\n" : "disabled\n"); - if (!ClientEnable()) { // Server side is once per connect. - player.weapon_pred_enabled = FALSE; - return; - } - - player.weapon_pred_enabled = TRUE; - entity pe = spawn(); pe.owner = player; pe.classname = "WeaponPred"; @@ -395,15 +411,11 @@ void WeaponPred_InitPlayer(entity player) { setorigin(pe, [0, 0, 0]); player.predict_entity = pe; - sprint(player, PRINT_HIGH, - "FortressOne: Weapon Prediction Active ", wp_version, "\n"); } void WeaponPred_TearDown(entity player) { - if (!player.weapon_pred_enabled) - return; - - dremove(player.predict_entity); + if (player.predict_entity != __NULL__) + dremove(player.predict_entity); } void WeaponPred_DoServerClientThink() { @@ -429,105 +441,3 @@ void PredProj_Add(entity mis) { mis.SendFlags = 255; } #endif - -#ifdef CSQC -float WP_IsReloading(); -void WP_UpdateViewModel() { - float pmodelindex, pframe; - - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); - - if (wi->predict_type == NO_PREDICT) { - // Fall back to engine. - self.modelindex = 0; - wp_model_mask |= MASK_VIEWMODEL; - return; - } else { - wp_model_mask &= ~MASK_VIEWMODEL; - - } - - if (pstate_pred.tfstate & (TFSTATE_NO_WEAPON | TFSTATE_RELOADING)) { - self.modelindex = 0; - return; - } - - pmodelindex = (wi->models)->modelindex; - pframe = pstate_pred.weaponframe; - - if (self.modelindex != pmodelindex) { - self.frame = pframe; - self.modelindex = pmodelindex; - self.lerpfrac = 0; - } else if (self.frame != pframe) { - self.frame2 = self.frame; - self.frame = pframe; - self.lerpfrac = 1; - } - - self.lerpfrac = max(0, self.lerpfrac - frametime * 10); -} - -void WP_Frame(); -void WP_DoClientThink(); - -float pf, ef; - -float last_time; -float gen; - -float WP_ClientThink() { - pstate_pred = pstate_server; - gen++; - - int pframe = servercommandframe + 1; - int eframe = clientcommandframe; - for(; pframe <= eframe; pframe++) { - if (!getinputstate(pframe) || input_timelength <= 0) - break; - - makevectors(input_angles); - pf = pframe; - ef = eframe; - - if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { - pengine.is_effectframe = TRUE; - pengine.last_effectframe = pframe; - } else { - pengine.is_effectframe = FALSE; - } - - pstate_pred.client_time += input_timelength; - if (input_impulse) - pstate_pred.impulse = input_impulse; - - while (pstate_pred.client_nextthink && - pstate_pred.client_time >= pstate_pred.client_nextthink) { - float held_client_time = pstate_pred.client_time; - - pstate_pred.client_time = pstate_pred.client_nextthink; - pstate_pred.client_nextthink = 0; - WP_DoClientThink(); - pstate_pred.client_time = held_client_time; - } - - WP_Frame(); - } - - WP_UpdateViewModel(); - return PREDRAW_AUTOADD; -} - -void InitWeapPredEnt(entity pe) { - pe.predraw = WP_ClientThink; - - self.drawmask = MASK_PRED_VIEWMODEL; - self.renderflags = RF_VIEWMODEL; - - FO_WP_Init(TRUE); -} - -float PP_Predraw(); - -#endif diff --git a/ssqc/client.qc b/ssqc/client.qc index 727b40bc..c8e840ee 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2931,8 +2931,8 @@ void () PlayerPostThink = { FO_FillCurrentWeapState(&ws); self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; - if (WeaponPred_Active(self)) - WeaponPred_Update(self); + + WeaponPred_Update(self); if (self.view_ofs == '0 0 0') { return; diff --git a/ssqc/progs.src b/ssqc/progs.src index 6e0eb961..f3346b56 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -19,7 +19,7 @@ debug.qc time.qc ../share/defs.h ../share/weapons.qc -../share/weapon_predict.qc +../share/prediction.qc ../share/animate.qc events.qc roles.qc From 7689a049700f5f6dc4acf309fb8c30d7b0b80609 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 00:15:56 -0700 Subject: [PATCH 1806/2474] Enable CSQC projectiles by default Take over the networking of supported projectiles by default. This can be disabled via `localinfo fo_projectiles off`. Legacy clients will continue to use engine projectiles. --- csqc/weapon_predict.qc | 7 ++++++- share/prediction.qc | 32 +++----------------------------- ssqc/client.qc | 8 +++----- ssqc/pyro.qc | 10 ++++------ ssqc/qw.qc | 3 ++- ssqc/weapons.qc | 10 +++++----- ssqc/world.qc | 3 +++ 7 files changed, 26 insertions(+), 47 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 967808bc..52d1b9fb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -523,8 +523,12 @@ DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); +// A small time based correction factor (2 frames) that results in more precise +// overlap with where the engine projectiles were previously rendered. +static float orig_proj_offset = 2/77.0; + float PP_PredrawActive() { - float delta = time - self.s_time; + float delta = time - self.s_time + orig_proj_offset; self.origin = self.s_origin + (self.velocity * delta); setorigin(self, self.origin); @@ -767,6 +771,7 @@ float PredProjectile_MatchProjectile() { if (CVARF(wpp_debug) & 1) { match.origin = match.s_origin + (time - match.s_time) * self.velocity; + self.origin = self.s_origin + (time - match.s_time) * self.velocity; printf(" p_diff = %0.3f / %0.3f t=%0.3f\n", vlen(match.s_origin - self.s_origin), vlen(match.origin - self.origin), vlen(match.origin - self.origin) / vlen(self.velocity)); diff --git a/share/prediction.qc b/share/prediction.qc index 86cd5de0..a50b196e 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -98,30 +98,6 @@ void InitFppProjectiles() { #ifdef SSQC -struct weaponpred_settings_t { - float global_enable; - float global_disable; - float new_projectiles; -} weaponpred_settings; - -float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; -void WeaponPred_InitOnce() { - static float init_once; - if (init_once) - return; - init_once = TRUE; - - // Regular init is too late for this. - weaponpred_settings.global_enable = - CF_GetSetting("wpge", "weapon_pred_global_enable", "off"); - weaponpred_settings.global_disable = - CF_GetSetting("wpgd", "weapon_pred_global_disable", "off"); - weaponpred_settings.new_projectiles = - CF_GetSetting("wpnp", "weapon_pred_new_projectiles", "off"); - - InitFppProjectiles(); -} - .predict_tf_state predict_state; .entity predict_entity; @@ -395,12 +371,10 @@ void EntUpdate_Projectile(float isnew) { #ifdef SSQC void WeaponPred_InitPlayer(entity player) { - WeaponPred_InitOnce(); - sprint(player, PRINT_HIGH, "FortressOne: Weapon Prediction ", wp_version, "\n"); sprint(player, PRINT_HIGH, "FortressOne: CSQC projectiles ", - weaponpred_settings.new_projectiles ? "enabled\n" : "disabled\n"); + fo_projectiles ? "enabled\n" : "disabled\n"); entity pe = spawn(); pe.owner = player; @@ -433,11 +407,11 @@ void WeaponPred_DoServerClientThink() { void PredProj_Add(entity mis) { mis.dimension_seen = DMN_NOFLASH; - if (!weaponpred_settings.new_projectiles) + if (!fo_projectiles) return; mis.s_origin = mis.origin; mis.SendEntity = PP_SendEntity; - mis.SendFlags = 255; + mis.SendFlags = 0xff; } #endif diff --git a/ssqc/client.qc b/ssqc/client.qc index c8e840ee..b268e61e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -608,6 +608,9 @@ void () DecodeLevelParms = { // maximum ping we'll have effect at antilag_settings.max_ping = CF_GetSetting("almp", "al_max_ping", "200"); + // CSQC projectiles + fo_projectiles = CF_GetSetting("focp", "fo_csqc_projectiles", "on"); + // project projectile weapons by player ping project_weapons = CF_GetSetting("pw", "project_weapons", "off"); @@ -632,8 +635,6 @@ void () DecodeLevelParms = { } // fortress one - // use old 1000 unit velocity for nailguns - ng_velocity = CF_GetSetting("ngv", "ng_velocity", "1500"); ng_damage = CF_GetSetting("ngd", "ng_damage", "9"); sng_damage = CF_GetSetting("sngd", "sng_damage", "13"); @@ -868,7 +869,6 @@ void () DecodeLevelParms = { sniperreloadpercent = TRUE; buildstatus = TRUE; old_hp_armor = FALSE; - ng_velocity = 1500; old_ng_rof = FALSE; superaxe = TRUE; supermedikit = TRUE; @@ -946,7 +946,6 @@ void () DecodeLevelParms = { sniperreloadpercent = FALSE; buildstatus = FALSE; old_hp_armor = TRUE; - ng_velocity = 1000; superaxe = FALSE; supermedikit = FALSE; superspanner = FALSE; @@ -983,7 +982,6 @@ void () DecodeLevelParms = { server_huetf = TRUE; impulse_queue = TRUE; flag_follow = FALSE; - ng_velocity = 1000; ng_damage = 18; sng_damage = 26; superaxe = FALSE; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 6b3c65a1..b9c7df0f 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -558,7 +558,7 @@ void () W_FireFlame = { flame.velocity = aim(self, 10000); if (pyro_type == PYRO_FO) { - flame.velocity = flame.velocity * 600; + flame.velocity = flame.velocity * fpp_types[FPP_FLAMETHROWER].speed; flame.nextthink = time + 0.15; } else @@ -570,7 +570,7 @@ void () W_FireFlame = { flame.touch = Flamer_stream_touch; flame.think = s_explode1; - FO_SetModel(flame, "progs/s_explod.spr"); + FO_SetModel(flame, fpp_types[FPP_FLAMETHROWER].model); setsize(flame, '0 0 0', '0 0 0'); setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); @@ -693,13 +693,11 @@ void () W_FireIncendiaryCannon = { } else { - newmis.velocity = newmis.velocity * 800; + newmis.velocity = newmis.velocity * fpp_types[FPP_INCENDIARY].speed; newmis.think = IncendiaryRadius_OZTF; if (pyro_type == PYRO_FO) - { - rktmdl = "progs/lavaball.mdl"; - } + rktmdl = fpp_types[FPP_INCENDIARY].model; } newmis.angles = vectoangles(newmis.velocity); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a2b5adf2..bf348ea2 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -612,7 +612,6 @@ float max_armor_hwguy; float project_weapons; float project_weapons_max_latency; -float ng_velocity; float ng_damage; float sng_damage; float superaxe; @@ -655,6 +654,8 @@ float deathammo_cells; float reverse_cap; float engineer_move; +float fo_projectiles; + float numlocs; typedef struct {vector pos; string desc;} loc_t; loc_t *locs; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index cdc59c26..7c05d7d8 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1092,7 +1092,7 @@ void () W_FireRocket = { makevectors(self.v_angle); newmis.velocity = v_forward; - newmis.velocity = newmis.velocity * PC_SOLDIER_ROCKET_SPEED; + newmis.velocity = newmis.velocity * fpp_types[FPP_ROCKET].speed; newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_MissileTouch; @@ -1103,7 +1103,7 @@ void () W_FireRocket = { newmis.weapon = DMSG_ROCKETL; newmis.classname = "proj_rocket"; - FO_SetModel(newmis, "progs/missile.mdl"); + FO_SetModel(newmis, fpp_types[FPP_ROCKET].model); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); @@ -1349,11 +1349,11 @@ void (vector org, vector dir) launch_spike = { newmis.classname = "spike"; newmis.think = SUB_Remove; newmis.nextthink = time + 6; - FO_SetModel(newmis, "progs/spike.mdl"); + FO_SetModel(newmis, fpp_types[FPP_NAIL].model); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin(newmis, org); - newmis.velocity = dir * ng_velocity; + newmis.velocity = dir * fpp_types[FPP_NAIL].speed; PredProj_Add(newmis); if (project_weapons) { @@ -1374,7 +1374,7 @@ void () W_FireSuperSpikes = { LogEventAttack(self); newmis.touch = superspike_touch; newmis.weapon = DMSG_SNAILGUN; - FO_SetModel(newmis, "progs/s_spike.mdl"); + FO_SetModel(newmis, fpp_types[FPP_SUPER_NAIL].model); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); KickPlayer(-3, self); diff --git a/ssqc/world.qc b/ssqc/world.qc index 0347b1f5..54954a47 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -4,6 +4,8 @@ void () TerminateStaleServer; string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; +void InitFppProjectiles(); + void () main = { dprint("main function\n"); precache_file("progs.dat"); @@ -372,6 +374,7 @@ void () worldspawn = { } + InitFppProjectiles(); dimension_send = DMN_NOFLASH; settings_to_track = memalloc(sizeof(*settings_to_track)*settings_to_track_list.length); From 104b4cd289eb3baa469c40a9a4839fc079d1bdee Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 09:47:27 -0700 Subject: [PATCH 1807/2474] Fix AutoId There was still a clock mismatch in a different file after prior commit. --- ssqc/actions.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index ca3537ec..f318f57e 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -160,13 +160,13 @@ void () TeamFortress_Discard_DropAmmo = { void () TeamFortress_SaveMe = { local entity te, tl; - if (self.client_time > self.next_saveme_sound) { + if (time > self.next_saveme_sound) { if (random() < 0.8) FO_Sound(self, CHAN_WEAPON, "speech/saveme1.wav", 1, ATTN_NORM); else FO_Sound(self, CHAN_WEAPON, "speech/saveme2.wav", 1, ATTN_NORM); - self.next_saveme_sound = self.client_time + 4; + self.next_saveme_sound = time + 4; } te = find(world, classname, "player"); while (te) { @@ -258,7 +258,7 @@ void (entity pe_player) FO_Spectator_Identify = { } // refresh status bar - pe_player.ident_time = self.client_time + 0.5; + pe_player.ident_time = time + 0.5; if(pe_player.ident_string != s_id_string) { pe_player.ident_string = s_id_string; //if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { @@ -452,7 +452,7 @@ void (entity pe_player, float f_type) CF_Identify = { s_id_string = strcat(s_id_string, s_class); } - pe_player.ident_time = self.client_time + 0.5; + pe_player.ident_time = time + 0.5; // don't update memory when the id string is the same if (pe_player.ident_string == s_id_string) { From ae2d032fb1d2b4101d6d98722ed13a775aa87356 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 13:17:56 -0700 Subject: [PATCH 1808/2474] Remove stray debug message --- csqc/weapon_predict.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 52d1b9fb..91f8f787 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -616,7 +616,6 @@ inline float PP_PredictStartOffset() { static float PP_EPS = 0.05; entity PP_CreateProjectile(fo_projectile* desc, vector offset) { - printf("PredProj Create\n"); entity proj = spawn(); proj.s_time = time + PP_PredictStartOffset(); From 38f357722895b1cf40941571db6a883194746956 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 12:10:41 -0700 Subject: [PATCH 1809/2474] Propagate CSQC prediction state back to server (via setinfo) Use this to suppress duplicated messages, e.g reload messages are now either generated server side, or by client, not both. --- csqc/weapon_predict.qc | 30 +++++++++++++++++++++--------- share/prediction.qc | 12 ++++++++++++ share/weapons.qc | 9 ++++++--- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 91f8f787..40c9a261 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -12,6 +12,12 @@ void WP_UpdateViewModel(entity pweap_ent); static inline float sq(float x) { return x * x; } +#define csqc_print(...) \ + do { if (CVARF(wpp_debug) & 4) \ + print("CSQC: ", __VA_ARGS__); \ + else \ + print(__VA_ARGS__); } while(0) + #define NUM_PING_SAMPLES 20 struct { @@ -90,6 +96,7 @@ static float CalcPredEnabled(float current_enable, #define ENABLE_CHECK_PERIOD 2 static float next_wpp_enable_check; static float next_ping_update; +void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; void WPP_UpdateEnable(float force) { if (time > next_ping_update) { @@ -135,6 +142,9 @@ void WPP_UpdateEnable(float force) { } once = TRUE; + float wpp_status = (pengine.wp_enabled ? CSQC_WEAP_PRED : 0) + + (pengine.pp_enabled ? CSQC_PROJ_PRED : 0); + setlocaluserinfo(player_localnum, "fo_wpp_status", ftos(wpp_status)); // We always need to "render" the view model to trigger predraw compute. pengine.view_mask = MASK_PRED_VIEWMODEL | (pp_new ? MASK_PRED_PROJECTILE : 0); @@ -293,7 +303,7 @@ string WP_GetClip() { void WP_Reload() { FO_WeapInfo* wi = WP_CurrentWeapon(); - if (!wi->needs_reload) + if (!wi->needs_reload || WP_IsReloading()) return; float clip_fired = *WP_ClipFired(); @@ -301,13 +311,13 @@ void WP_Reload() { string msg; if (!FO_CheckCanReload(wi, ammo_rem, clip_fired, msg)) { - if (pengine.is_effectframe) - print(msg); + if (IsEffectFrame()) + csqc_print(msg); return; } - if (pengine.is_effectframe) - print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); + if (IsEffectFrame()) + csqc_print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); pstate_pred.tfstate |= TFSTATE_RELOADING; float amt = min(ammo_rem, clip_fired); @@ -321,8 +331,8 @@ void WP_CheckReloadFinished() { if (WP_IsReloading() && pstate_pred.client_time >= pstate_pred.reload_finished) { pstate_pred.tfstate &= ~TFSTATE_RELOADING; - if (pengine.is_effectframe) - print("Finished reloading\n"); + if (IsEffectFrame()) + csqc_print("Finished reloading\n"); } } @@ -445,8 +455,10 @@ void WP_Frame() { return; } - WP_CheckReloadFinished(); - WP_Impulse(); + if (WP_Enabled()) { + WP_CheckReloadFinished(); + WP_Impulse(); + } if ((input_buttons & BUTTON0) && !WP_IsReloading() && (pstate_pred.client_time >= pstate_pred.attack_finished)) diff --git a/share/prediction.qc b/share/prediction.qc index a50b196e..b3898b1a 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -31,6 +31,11 @@ enumflags { #define PF_PP_DISABLE 8 #define PF_ED_MASK (PF_WP_ENABLE | PF_WP_DISABLE | PF_PP_ENABLE | PF_PP_DISABLE) +enumflags { + CSQC_WEAP_PRED, + CSQC_PROJ_PRED, +}; + struct predict_tf_state { int playerclass; int predict_flags; @@ -224,6 +229,13 @@ void WeaponPred_Update(entity player) { #undef M2 #undef M3 #undef M4 + +void sprint_pred(entity client, float msglevel, string s, optional string s2, + optional string s3, optional string s4, optional string s5) { + if (infokeyf(client, "fo_wpp_status") & CSQC_WEAP_PRED) + return; // Message generated client-side. + sprint(client, msglevel, s, s2, s3, s4, s5); +} #endif #ifdef SSQC diff --git a/share/weapons.qc b/share/weapons.qc index 97da5db7..028a0cdd 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -376,6 +376,9 @@ void (float att_delay) Attack_Finished; // Hack until we fix Status_Refresh() to not be awful. .float last_still_loading; void W_UpdateCurrentWeapon(entity pl); +void sprint_pred(entity client, float msglevel, string s, optional string s2, + optional string s3, optional string s4, optional string s5); + void FO_ReloadFrame() { if (self.tfstate & TFSTATE_RELOADING == 0) @@ -390,7 +393,7 @@ void FO_ReloadFrame() { W_UpdateCurrentWeapon(self); self.last_still_loading = 0; Status_Refresh(self); - sprint(self, PRINT_HIGH, "Finished reloading\n"); + sprint_pred(self, PRINT_HIGH, "Finished reloading\n"); return; } @@ -436,11 +439,11 @@ void FO_ReloadSlot(Slot slot, float force) { string msg; if (!FO_CheckCanReload(wi, *ws->ammo_remaining, *ws->clip_fired, msg)) { - sprint(self, PRINT_HIGH, msg); + sprint_pred(self, PRINT_HIGH, msg); return; } - sprint(self, PRINT_HIGH, + sprint_pred(self, PRINT_HIGH, strcat("Reloading ", FO_GetWeapName(ws->weapon), "...\n")); Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. From e53a4461cc1d7cbd4d41ceb08d87f5fa1ab69b6f Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 15:35:40 -0700 Subject: [PATCH 1810/2474] Prediction improvements - Fix a case where firing while standing still with high latency projectiles could be mis-matched, resulting in warping/funny looking trails. - Add a missing predicted reload check when you fire the last shot in the clip but have ammo remaining (this was still working before, but only because we saw the server set RELOADING) --- csqc/weapon_predict.qc | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 40c9a261..efc38941 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -344,17 +344,26 @@ float WP_CheckAmmo(FO_WeapInfo* wi) { return ammo > wi->ammo_per_shot; } -float WP_ConsumeAmmo(FO_WeapInfo* wi) { +float WP_ReloadIfNeeded(FO_WeapInfo* wi) { if (!WP_CheckAmmo(wi) || wi->needs_reload) { if (*WP_ClipFired() >= wi->clip_size) { WP_Reload(); - return FALSE; + return TRUE; } } + return FALSE; +} + +float WP_ConsumeAmmo(FO_WeapInfo* wi) { + if (WP_ReloadIfNeeded(wi)) + return FALSE; + pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; *WP_ClipFired() += wi->ammo_per_shot; + WP_ReloadIfNeeded(wi); + return TRUE; } @@ -751,6 +760,8 @@ void WP_Attack() { float PredProjectile_MatchProjectile() { entity proj, match = __NULL__; float best = 0.2; + + self.origin = self.s_origin + (time - self.s_time) * self.velocity; for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { if (proj.modelindex != self.modelindex) continue; @@ -759,13 +770,13 @@ float PredProjectile_MatchProjectile() { if (d < best) { best = d; match = proj; - } - if (vlen(proj.s_origin - self.s_origin) < 32) { - match = proj; - break; + proj.origin = proj.s_origin + (time - proj.s_time) * self.velocity; + if (vlen(proj.origin - self.origin) < 32) { + match = proj; + break; + } } - } if (match) { @@ -781,8 +792,6 @@ float PredProjectile_MatchProjectile() { self.p_time = match.p_time; if (CVARF(wpp_debug) & 1) { - match.origin = match.s_origin + (time - match.s_time) * self.velocity; - self.origin = self.s_origin + (time - match.s_time) * self.velocity; printf(" p_diff = %0.3f / %0.3f t=%0.3f\n", vlen(match.s_origin - self.s_origin), vlen(match.origin - self.origin), vlen(match.origin - self.origin) / vlen(self.velocity)); From f0eaa635cee2bf4eff8bb6a393808cafbf0c7b57 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 16:27:52 -0700 Subject: [PATCH 1811/2474] Avoid double events at ultra-low pings While generally these should just be disabled at super low pings, sometimes people just set things up wrong or are trying to test things. There's an annoying problem for super low pings that we can catch up to the frame preceding our input, and generate a new input frame, even though the frame we're about to receive would prevent it. Handle this by deferring the effect frame by 1 server frame in this instance. --- csqc/weapon_predict.qc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index efc38941..831fe81a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -13,10 +13,10 @@ void WP_UpdateViewModel(entity pweap_ent); static inline float sq(float x) { return x * x; } #define csqc_print(...) \ - do { if (CVARF(wpp_debug) & 4) \ + do { if (CVARF(wpp_debug) & 4) { \ print("CSQC: ", __VA_ARGS__); \ - else \ - print(__VA_ARGS__); } while(0) + SetHadEffect(); \ + } else { print(__VA_ARGS__); } } while(0) #define NUM_PING_SAMPLES 20 @@ -157,6 +157,16 @@ static inline float IsEffectFrame() { return pengine.is_effectframe; } +static void SetHadEffect() { + // At ultra-low latencies it's possible that we're only one frame in front + // of the server. But this can mean that we get that frame back immediately + // (and our input applies to the one after it). + if (servercommandframe + 2 >= pengine.last_effectframe) { + pengine.last_effectframe++; + if (CVARF(wpp_debug) & 8) print("Effect bump!\n"); + } +} + //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// @@ -637,6 +647,7 @@ inline float PP_PredictStartOffset() { static float PP_EPS = 0.05; entity PP_CreateProjectile(fo_projectile* desc, vector offset) { + SetHadEffect(); entity proj = spawn(); proj.s_time = time + PP_PredictStartOffset(); @@ -730,12 +741,9 @@ void WP_Attack() { } } - float af = pstate_pred.attack_finished; - if (!in_anim) pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; - #if 0 // If our latency is higher than forward projection, synchronize animation // with when it will actually start/finish. The projectile internally From 65e9f5dde03bcbe975dd7e8a51fe7fde2fd0e7c2 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 16:42:51 -0700 Subject: [PATCH 1812/2474] Move init and print legacy message We moved to a regular global for new projectile enabled status, but localinfo parsing was occurring later in client connect, resulting in incorrect state being shown to the first client. Just move our initialization later, and while we're here, print a broadcast calling out legacy clients. --- share/prediction.qc | 5 +++++ ssqc/client.qc | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/share/prediction.qc b/share/prediction.qc index b3898b1a..7debe07f 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -383,6 +383,11 @@ void EntUpdate_Projectile(float isnew) { #ifdef SSQC void WeaponPred_InitPlayer(entity player) { + if (!infokeyf(player, INFOKEY_P_CSQCACTIVE)) { + bprint(PRINT_HIGH, player.netname, " is using a legacy non-CSQC client.\n"); + return; + } + sprint(player, PRINT_HIGH, "FortressOne: Weapon Prediction ", wp_version, "\n"); sprint(player, PRINT_HIGH, "FortressOne: CSQC projectiles ", diff --git a/ssqc/client.qc b/ssqc/client.qc index b268e61e..6e62be43 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2103,6 +2103,8 @@ void () PutClientInServer = { DecodeLevelParms(); + WeaponPred_InitPlayer(self); + if (self.playerclass != PC_CIVILIAN && TeamFortress_TeamIsCivilian(self.team_no)) { TeamFortress_ChangeClass(11); } @@ -3073,8 +3075,6 @@ void () ClientConnect = { } if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - WeaponPred_InitPlayer(self); - InitAllStatuses(self); UpdateClientMOTD(self); UpdateClientTeamScores(self); From c4776fda85893d8ebd17081d127b0e0031daea53 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 16:53:59 -0700 Subject: [PATCH 1813/2474] Add clientside projectiles for Tranq and Railgun --- csqc/weapon_predict.qc | 6 ++++++ share/prediction.qc | 4 ++++ share/weapons.qc | 4 ++-- ssqc/engineer.qc | 3 ++- ssqc/spy.qc | 1 + ssqc/weapons.qc | 4 ++-- 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 831fe81a..19240003 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -738,6 +738,12 @@ void WP_Attack() { case WEAP_FLAMETHROWER: PP_CreateProjectile(&fpp_types[FPP_FLAMETHROWER], v_forward * 16); break; + case WEAP_TRANQ: + PP_CreateProjectile(&fpp_types[FPP_TRANQ], v_forward * 8); + break; + case WEAP_RAILGUN: + PP_CreateProjectile(&fpp_types[FPP_RAILGUN], '0 0 0'); + break; } } diff --git a/share/prediction.qc b/share/prediction.qc index 7debe07f..e1c7639b 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -70,6 +70,8 @@ enum { FPP_NAIL, FPP_SUPER_NAIL, FPP_FLAMETHROWER, + FPP_TRANQ, + FPP_RAILGUN, }; struct fo_projectile { @@ -89,6 +91,8 @@ fo_projectile fpp_types[] = { { FPP_NAIL, 1500, "progs/spike.mdl", "tr_spike" }, { FPP_SUPER_NAIL, 1500, "progs/s_spike.mdl", "tr_spike" }, { FPP_FLAMETHROWER, 600, "progs/s_explod.spr", "explodesprite" }, + { FPP_TRANQ, PC_SPY_TRANQSPEED, "progs/spike.mdl", "tr_spike" }, + { FPP_RAILGUN, PC_ENGINEER_RAILSPEED, "progs/e_spike1.mdl", "te_railtrail" }, }; void InitFppProjectiles() { diff --git a/share/weapons.qc b/share/weapons.qc index 028a0cdd..badec7ce 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -125,8 +125,8 @@ FO_WeapInfo weapon_info[] = { { WEAP_ASSAULT_CANNON, NO_PREDICT, AMMO_SHELLS, -9, 1, 0.2, 4 }, { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, - { WEAP_TRANQ, NO_PREDICT, AMMO_SHELLS, 0, 1, 1.5, 0 }, - { WEAP_RAILGUN, PRED_MODEL, AMMO_NAILS, 0, 1, 0.4, 0 }, + { WEAP_TRANQ, PRED_PROJ, AMMO_SHELLS, 0, 1, 1.5, 0 }, + { WEAP_RAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.4, 0 }, }; inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index e4fa286c..f859a2a9 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -78,7 +78,7 @@ void () LaserBolt_Touch = { dremove(self); }; -void () W_FireLaser = { +void () W_FireRailgun = { local vector vec, org; self.ammo_nails = self.ammo_nails - 1; @@ -108,6 +108,7 @@ void () W_FireLaser = { newmis.touch = LaserBolt_Touch; newmis.classname = "railslug"; + PredProj_Add(newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 5f3a3e7e..182791e1 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1092,6 +1092,7 @@ void () W_FireTranq = { FO_SetModel(newmis, "progs/spike.mdl"); setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + PredProj_Add(newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 7c05d7d8..e670f79b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -104,7 +104,7 @@ float (float weap) W_OldGetSlot; void () W_FireFlame; void () W_FireIncendiaryCannon; void () W_FireTranq; -void () W_FireLaser; +void () W_FireRailgun; void () HallucinationTimer; void () TranquiliserTimer; @@ -1756,7 +1756,7 @@ void () W_Attack = { } else if (ws.weapon == WEAP_RAILGUN) { FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); - W_FireLaser(); + W_FireRailgun(); } if (ws.weapon != WEAP_FLAMETHROWER && // Variable From 8e940492b9b00536db590670d229f0986342b77c Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 18:58:22 -0700 Subject: [PATCH 1814/2474] Seat != playernum Zero seems to be correct. No docs. --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 19240003..18b99cc7 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -144,7 +144,7 @@ void WPP_UpdateEnable(float force) { float wpp_status = (pengine.wp_enabled ? CSQC_WEAP_PRED : 0) + (pengine.pp_enabled ? CSQC_PROJ_PRED : 0); - setlocaluserinfo(player_localnum, "fo_wpp_status", ftos(wpp_status)); + setlocaluserinfo(0, "fo_wpp_status", ftos(wpp_status)); // We always need to "render" the view model to trigger predraw compute. pengine.view_mask = MASK_PRED_VIEWMODEL | (pp_new ? MASK_PRED_PROJECTILE : 0); From cbe7ff8a732aa4d79f65627b085c69fcb0017205 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 21 Oct 2022 20:51:48 -0700 Subject: [PATCH 1815/2474] Turn on weapon prediction by default Originally was separating this but it's behaving fairly well with latest updates and turns out to actually matter for projectiles (since otherwise you can change weapons fast enough that client still thinks you are using previous weapon and creates incorrect predicted projectiles). Could possibly separate tracking and rendering in the future but goal is to just make this unnecessary and always automatically on. --- csqc/weapon_predict.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 18b99cc7..63e791a2 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,12 +1,12 @@ DEFCVAR_FLOAT(wpp_debug, 0); -DEFCVAR_FLOAT(fo_wp_minping, 40); +DEFCVAR_FLOAT(fo_wp_minping, 50); DEFCVAR_FLOAT(fo_weap_predict, -1); DEFCVAR_FLOAT(fo_proj_predict, -1); float default_proj_predict = TRUE; -float default_weap_predict = FALSE; +float default_weap_predict = TRUE; void WP_UpdateViewModel(entity pweap_ent); From 5811d1e61fdabb3078647e18118c2e8daf21dd6c Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 22 Oct 2022 07:59:44 -0700 Subject: [PATCH 1816/2474] Temporarily put things behind a flag Most of the core working well, but some details to handle (more cvar support and quick switch in particular) --- csqc/weapon_predict.qc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 63e791a2..f4471b17 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,12 +1,11 @@ DEFCVAR_FLOAT(wpp_debug, 0); +DEFCVAR_FLOAT(fo_wpp_beta, 0); DEFCVAR_FLOAT(fo_wp_minping, 50); DEFCVAR_FLOAT(fo_weap_predict, -1); DEFCVAR_FLOAT(fo_proj_predict, -1); -float default_proj_predict = TRUE; -float default_weap_predict = TRUE; void WP_UpdateViewModel(entity pweap_ent); @@ -118,12 +117,12 @@ void WPP_UpdateEnable(float force) { float wp_new = -1, pp_new = -1; string wp_source, pp_source; - wp_new = CalcPredEnabled(pengine.wp_enabled, default_weap_predict, + wp_new = CalcPredEnabled(pengine.wp_enabled, CVARF(fo_wpp_beta), pstate_server.predict_flags & PF_WP_DISABLE, pstate_server.predict_flags & PF_WP_ENABLE, CVARF(fo_weap_predict), &wp_source); - pp_new = CalcPredEnabled(pengine.pp_enabled, default_proj_predict, + pp_new = CalcPredEnabled(pengine.pp_enabled, CVARF(fo_wpp_beta), pstate_server.predict_flags & PF_PP_DISABLE, pstate_server.predict_flags & PF_PP_ENABLE, CVARF(fo_proj_predict), &pp_source); From 3eb5599ed2ee92e598a7c6e252a3cffab9f3b895 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 22 Oct 2022 17:53:43 -0700 Subject: [PATCH 1817/2474] Support transparent weapon Support r_drawviewmodel transparency/hiding. --- csqc/weapon_predict.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f4471b17..bf8c88bb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -840,6 +840,8 @@ void InitProjPredEnt() { } +DEFCVAR_FLOAT(r_drawviewmodel, 1); + void WP_UpdateViewModel(entity pweap_ent) { float pmodelindex, pframe; @@ -858,11 +860,13 @@ void WP_UpdateViewModel(entity pweap_ent) { pengine.view_mask &= ~MASK_VIEWMODEL; } - if (pstate_pred.tfstate & (TFSTATE_NO_WEAPON | TFSTATE_RELOADING)) { + if (pstate_pred.tfstate & (TFSTATE_NO_WEAPON | TFSTATE_RELOADING) || + CVARF(r_drawviewmodel) == 0) { pweap_ent.modelindex = 0; return; } + pweap_ent.alpha = CVARF(r_drawviewmodel); pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; From 0e48dbd46b34c41fc97e5c78efd2840ab5e93d88 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 22 Oct 2022 18:19:57 -0700 Subject: [PATCH 1818/2474] Support cl_r2g Allow substitution of grenade.mdl for missile.mdl --- csqc/weapon_predict.qc | 32 ++++++++++++++++++++++---------- share/prediction.qc | 2 ++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index bf8c88bb..f81e576a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,12 +1,13 @@ -DEFCVAR_FLOAT(wpp_debug, 0); +.float server_modelindex; // Track the server modelindex for matching, since it + // can be overridden client-side. +DEFCVAR_FLOAT(wpp_debug, 0); DEFCVAR_FLOAT(fo_wpp_beta, 0); DEFCVAR_FLOAT(fo_wp_minping, 50); DEFCVAR_FLOAT(fo_weap_predict, -1); DEFCVAR_FLOAT(fo_proj_predict, -1); - void WP_UpdateViewModel(entity pweap_ent); static inline float sq(float x) { return x * x; } @@ -604,8 +605,10 @@ DEFCVAR_FLOAT(r_grenadetrail, 1); int PP_FindTrail(entity e) { - if (e.modelflags & (MF_GRENADE | MF_ROCKET)) { - float is_grenade = !!(e.modelflags & MF_GRENADE); + float is_rocket = e.server_modelindex == fpp_types[FPP_ROCKET].modelindex; + float is_grenade = e.server_modelindex == fpp_types[FPP_GRENADE].modelindex; + + if (is_rocket || is_grenade) { float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; if (idx >= 0 && idx < trail_table.length) @@ -614,7 +617,8 @@ int PP_FindTrail(entity e) for (float i = 0; i < fpp_types.length; i++) { fo_projectile* desc = &fpp_types[i]; - if (e.modelindex == desc->modelindex) return desc->trailindex; + if (e.server_modelindex == desc->modelindex) + return desc->trailindex; } return 0; @@ -645,6 +649,8 @@ inline float PP_PredictStartOffset() { static float PP_EPS = 0.05; +DEFCVAR_FLOAT(cl_r2g, 0); + entity PP_CreateProjectile(fo_projectile* desc, vector offset) { SetHadEffect(); entity proj = spawn(); @@ -666,7 +672,12 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { proj.angles = input_angles; proj.angles[0] *= -1; - setmodelindex(proj, desc->modelindex); + proj.server_modelindex = desc->modelindex; + + float modelindex = desc->modelindex; + if (modelindex == fpp_types[FPP_ROCKET].modelindex && CVARF(cl_r2g) == 1) + modelindex = fpp_types[FPP_GRENADE].modelindex; + setmodelindex(proj, modelindex); PP_InitTrail(proj); @@ -776,7 +787,7 @@ float PredProjectile_MatchProjectile() { self.origin = self.s_origin + (time - self.s_time) * self.velocity; for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { - if (proj.modelindex != self.modelindex) + if (proj.server_modelindex != self.server_modelindex) continue; float d = fabs(proj.s_time - self.s_time); @@ -823,13 +834,15 @@ void InitProjPredEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; - // Force modelflags refresh - setmodel(self, modelnameforindex(self.modelindex)); + self.server_modelindex = self.modelindex; setsize(self, [0,0,0], [0,0,0]); self.oldorigin = self.s_origin + CVARF(pp_trail_start) * MSEC * self.velocity; self.p_time = time + CVARF(pp_trail_start) * MSEC; + if (CVARF(cl_r2g) && self.server_modelindex == fpp_types[FPP_ROCKET].modelindex) + setmodelindex(self, fpp_types[FPP_GRENADE].modelindex); + PP_InitTrail(self); // Note: Might be overwritten by inherited match. // We still check this with projectile prediction as there could be in @@ -837,7 +850,6 @@ void InitProjPredEnt() { // off case since the projectile list will just be empty. if (self.owner_entnum == player_localentnum) PredProjectile_MatchProjectile(); - } DEFCVAR_FLOAT(r_drawviewmodel, 1); diff --git a/share/prediction.qc b/share/prediction.qc index e1c7639b..6a88c176 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -66,6 +66,7 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; enum { FPP_ROCKET, + FPP_GRENADE, FPP_INCENDIARY, FPP_NAIL, FPP_SUPER_NAIL, @@ -87,6 +88,7 @@ struct fo_projectile { fo_projectile fpp_types[] = { { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl", "" }, + { FPP_GRENADE, 600, "progs/grenade.mdl", "t_grenade" }, { FPP_INCENDIARY, 800, "progs/lavaball.mdl", "t_lavaball" }, { FPP_NAIL, 1500, "progs/spike.mdl", "tr_spike" }, { FPP_SUPER_NAIL, 1500, "progs/s_spike.mdl", "tr_spike" }, From 1f2f47e0c80543135dd3774f02975e3474c9ead2 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 22 Oct 2022 15:37:54 -0700 Subject: [PATCH 1819/2474] Implement TF_QUICKSTOP - Client-side quickstop for swapping back. - Synchronized state regarding whether quickslot swapped - Don't create projectiles for unsynchronized quickslots, this is a temporary measure to avoid creating dummy projectiles when packetloss does things with the impulse. --- csqc/weapon_predict.qc | 26 ++++++++++++++++++++++---- share/defs.h | 1 + ssqc/qw.qc | 1 - ssqc/weapons.qc | 13 +++++++++---- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f81e576a..2b7cb601 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -210,15 +210,26 @@ void WP_Impulse() { // Note: We might have no impulse, but a queued slot here. float match = TRUE; + float quick_swap = FALSE; switch (pstate_pred.impulse) { case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: pstate_pred.impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. + quick_swap = TRUE; case 1: case 2: case 3: case 4: case 5: case 6: case 7: { Slot slot = InputToSlot(pstate_pred.impulse); - if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) + if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) { + if (quick_swap) + pstate_pred.tfstate |= TFSTATE_QUICKSLOT; pstate_pred.queue_slot = slot; + } break; } + case TF_QUICKSTOP: + if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) { + pstate_pred.impulse = 0; + break; + } + pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. case TF_WEAPLAST: pstate_pred.queue_slot = pstate_pred.last_slot; break; default: @@ -651,10 +662,19 @@ static float PP_EPS = 0.05; DEFCVAR_FLOAT(cl_r2g, 0); -entity PP_CreateProjectile(fo_projectile* desc, vector offset) { +void PP_CreateProjectile(fo_projectile* desc, vector offset) { SetHadEffect(); entity proj = spawn(); + // Packet loss doesnt guarantee the server will actually register quickslot + // since it's a separate command from the attack. We can improve this in the + // future via either a button or just combining them on an impulse. But for + // now just dont create the projectile, it's usually swapping to a hitscan + // weapon anyway. + if (pstate_pred.tfstate & TFSTATE_QUICKSLOT && + !(pstate_server.tfstate & TFSTATE_QUICKSLOT)) + return; + proj.s_time = time + PP_PredictStartOffset(); proj.starttime = max(time + CVARF(pp_trail_start) * MSEC, proj.s_time); proj.endtime = time + pstate_pred.client_ping + PP_EPS + 2; @@ -685,8 +705,6 @@ entity PP_CreateProjectile(fo_projectile* desc, vector offset) { if (predicted_projectiles) predicted_projectiles.pred_prev = proj; predicted_projectiles = proj; - - return proj; } void PP_AssCanFrame() { diff --git a/share/defs.h b/share/defs.h index fe259e9c..8f471eec 100644 --- a/share/defs.h +++ b/share/defs.h @@ -249,6 +249,7 @@ enumflags { TFSTATE_NO_WEAPON, // Weapon is disabled and not visible (e.g. detpack) // (Note: We don't use NO_WEAPON for reloading // as it could result in stacked no-weapon states.) + TFSTATE_QUICKSLOT, // QUICKSTOP should change to last weapon. TFSTATE_INFECTED, // set when player is infected by the bioweapon TFSTATE_INVINCIBLE, // Player has permanent Invincibility (Usually by GoalItem) TFSTATE_INVISIBLE, // Player has permanent Invisibility (Usually by GoalItem) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bf348ea2..dd9932ec 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -57,7 +57,6 @@ float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT); .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float is_concussed; // TRUE for a player who is affected by concussion grenade -.float qf_swap_last_slot; // TRUE if +slotX was initiated from another slot .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team .float has_changedclass; // TRUE for a player that has changed class diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e670f79b..b056076e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2581,8 +2581,13 @@ void () W_WeaponFrame = { // Let's see if we can get away with just treating this as last weapon; // there were already so many edge cases in the old code such as swapping on // an empty weapon. - if (self.impulse == TF_QUICKSTOP) - self.impulse = self.qf_swap_last_slot ? TF_WEAPLAST : 0; + if (self.impulse == TF_QUICKSTOP) { + if (self.tfstate & TFSTATE_QUICKSLOT) + self.impulse = TF_WEAPLAST; + else + self.impulse = 0; + self.tfstate &= ~TFSTATE_QUICKSLOT; + } float can_change_weapon = WeaponReady(); @@ -2598,9 +2603,9 @@ void () W_WeaponFrame = { Slot slot = MakeSlot(input); if (IsSameSlot(slot, self.current_slot)) { - self.qf_swap_last_slot = FALSE; + self.tfstate &= ~TFSTATE_QUICKSLOT; } else { - self.qf_swap_last_slot = TRUE; + self.tfstate |= TFSTATE_QUICKSLOT; W_ChangeWeaponSlot(slot); } self.impulse = 0; From cded2a6e92e3b00545cc4b63be74d7eb2df57b47 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 01:53:20 -0700 Subject: [PATCH 1820/2474] Match client-side sound with animation Add client-side sound for all predicted weapons, match up with animations, and conditionally filter server sounds whenever prediction occurred. Also, substitute sound later when we realize prediction was missed. --- csqc/events.qc | 12 ++++-- csqc/weapon_predict.qc | 66 +++++++++++++++++++++++++++------ share/defs.h | 1 + share/prediction.qc | 83 +++++++++++++++++++++++++++++++++++++----- ssqc/client.qc | 1 + ssqc/engineer.qc | 2 + ssqc/pyro.qc | 4 +- ssqc/scout.qc | 6 +-- ssqc/weapons.qc | 22 +++++------ ssqc/world.qc | 1 - 10 files changed, 155 insertions(+), 43 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index a6f5a9a3..c5428122 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -524,12 +524,16 @@ void ParseSBAR() } } -float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound = { - // Filter out sounds we may have generated locally, unless we're just - // pretending to be that entity. - if (entnum != player_localentnum || is_spectator || is_observer) +float(float ent_num, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound = { + // Sound sent to our predicted weapon is expected to have been client-side. + if (ent_num == pengine.pweap_ent.entnum) + return 1; + + // Sounds from remote entities are not local and we should always play. + if (ent_num != player_localentnum || is_spectator || is_observer) return 0; + // Sounds below this line are conditionally filtered. switch(soundname) { case "player/plyrjmp8.wav": case "player/land.wav": diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2b7cb601..f99a090c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -172,6 +172,20 @@ static void SetHadEffect() { //////////////////////////////////////////////////////////////////////////////// float animate_s_time; +static entity pred_sound_entity; + +void Pred_Sound(int snd) { + if (pstate_pred.tfstate & TFSTATE_FLASHED) + return; + + setorigin(pred_sound_entity, pmove_org); + sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, 1, ATTN_NORM); +} + +void PredProj_Sound(int proj_type) { + Pred_Sound(fpp_types[proj_type].snd); +} + inline FO_WeapInfo* WP_CurrentWeapon() { return FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); } @@ -530,6 +544,9 @@ float nail_trail; static float corr_s; // Auto-tuning correction factor. void FO_PP_Init() { + // Entity we'll attach locally generated sound to. + pred_sound_entity = spawn(); + InitFppProjectiles(); for (float i = 0; i < trail_table.length; i++) { @@ -662,7 +679,11 @@ static float PP_EPS = 0.05; DEFCVAR_FLOAT(cl_r2g, 0); -void PP_CreateProjectile(fo_projectile* desc, vector offset) { +void PP_CreateProjectile(int proj_type, vector offset) { + fo_projectile* desc = &fpp_types[proj_type]; + + PredProj_Sound(proj_type); + SetHadEffect(); entity proj = spawn(); @@ -729,9 +750,9 @@ void PP_NailFrame() { return; if (wi->weapon == WEAP_NAILGUN) - PP_CreateProjectile(&fpp_types[FPP_NAIL], v_right * (idx ? 4: - 4)); + PP_CreateProjectile(FPP_NAIL, v_right * (idx ? 4: - 4)); else - PP_CreateProjectile(&fpp_types[FPP_SUPER_NAIL], '0 0 0'); + PP_CreateProjectile(FPP_SUPER_NAIL, '0 0 0'); } void WP_Attack() { @@ -758,20 +779,30 @@ void WP_Attack() { if (PP_Enabled() && IsEffectFrame() && !in_anim) { switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: - PP_CreateProjectile(&fpp_types[FPP_ROCKET], v_forward * 8); + PP_CreateProjectile(FPP_ROCKET, v_forward * 8); break; case WEAP_INCENDIARY: - PP_CreateProjectile(&fpp_types[FPP_INCENDIARY], v_forward * 8); + PP_CreateProjectile(FPP_INCENDIARY, v_forward * 8); break; case WEAP_FLAMETHROWER: - PP_CreateProjectile(&fpp_types[FPP_FLAMETHROWER], v_forward * 16); + PP_CreateProjectile(FPP_FLAMETHROWER, v_forward * 16); break; case WEAP_TRANQ: - PP_CreateProjectile(&fpp_types[FPP_TRANQ], v_forward * 8); + PP_CreateProjectile(FPP_TRANQ, v_forward * 8); break; case WEAP_RAILGUN: - PP_CreateProjectile(&fpp_types[FPP_RAILGUN], '0 0 0'); + PP_CreateProjectile(FPP_RAILGUN, '0 0 0'); break; + case WEAP_GRENADE_LAUNCHER: + case WEAP_PIPE_LAUNCHER: + Pred_Sound(SND_GREN); break; + case WEAP_AXE: + case WEAP_KNIFE: + case WEAP_SPANNER: + case WEAP_MEDIKIT: + Pred_Sound(SND_AXE); break; + case WEAP_SHOTGUN: Pred_Sound(SND_SG); break; + case WEAP_SUPER_SHOTGUN: Pred_Sound(SND_SSG); break; } } @@ -847,6 +878,14 @@ float PredProjectile_MatchProjectile() { return FALSE; } +static int Proj_FindFPP(entity ent) { + for (float i = 0; i < fpp_types.length; i++) { + if (fpp_types[i].modelindex == ent.server_modelindex) + return i; + } + return -1; +} + // Called on `self`. void InitProjPredEnt() { self.drawmask = MASK_ENGINE; @@ -866,8 +905,11 @@ void InitProjPredEnt() { // We still check this with projectile prediction as there could be in // flight projectiles on the transition. This is effectively a nop in the // off case since the projectile list will just be empty. - if (self.owner_entnum == player_localentnum) - PredProjectile_MatchProjectile(); + if (self.owner_entnum == player_localentnum && + !PredProjectile_MatchProjectile()) { + // Missing projectile implies we missed the local sound, patch it up. + PredProj_Sound(Proj_FindFPP(self)); + } } DEFCVAR_FLOAT(r_drawviewmodel, 1); @@ -890,8 +932,8 @@ void WP_UpdateViewModel(entity pweap_ent) { pengine.view_mask &= ~MASK_VIEWMODEL; } - if (pstate_pred.tfstate & (TFSTATE_NO_WEAPON | TFSTATE_RELOADING) || - CVARF(r_drawviewmodel) == 0) { + static float no_weap_mask = TFSTATE_NO_WEAPON | TFSTATE_RELOADING | TFSTATE_FLASHED; + if (pstate_pred.tfstate & no_weap_mask || CVARF(r_drawviewmodel) == 0) { pweap_ent.modelindex = 0; return; } diff --git a/share/defs.h b/share/defs.h index 8f471eec..23173516 100644 --- a/share/defs.h +++ b/share/defs.h @@ -249,6 +249,7 @@ enumflags { TFSTATE_NO_WEAPON, // Weapon is disabled and not visible (e.g. detpack) // (Note: We don't use NO_WEAPON for reloading // as it could result in stacked no-weapon states.) + TFSTATE_FLASHED, TFSTATE_QUICKSLOT, // QUICKSTOP should change to last weapon. TFSTATE_INFECTED, // set when player is infected by the bioweapon TFSTATE_INVINCIBLE, // Player has permanent Invincibility (Usually by GoalItem) diff --git a/share/prediction.qc b/share/prediction.qc index 6a88c176..bcad9a65 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -64,6 +64,37 @@ struct predict_tf_state { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +struct fo_predsnd { + int id; + string sound; +}; + +enum { + SND_AXE, + SND_SG, + SND_SSG, + SND_RL, + SND_GREN, + SND_NAIL, + SND_SNAIL, + SND_FLAMETHROWER, + SND_RAILGUN, + SND_TRANQ, +}; + +fo_predsnd snd_types[] = { + { SND_AXE, "ax1.wav" }, + { SND_SG, "guncock.wav" }, + { SND_SSG, "shotgn2.wav" }, + { SND_RL, "sgun1.wav" }, + { SND_GREN, "grenade.wav" }, + { SND_NAIL, "rocket1i.wav" }, + { SND_SNAIL, "spike2.wav" }, + { SND_FLAMETHROWER, "flmfire2.wav" }, + { SND_RAILGUN, "railgun.wav" }, + { SND_TRANQ, "dartgun.wav" }, +}; + enum { FPP_ROCKET, FPP_GRENADE, @@ -80,6 +111,7 @@ struct fo_projectile { float speed; string model; string trail; + int snd; // Automatically initialized below this line. float modelindex; @@ -87,24 +119,39 @@ struct fo_projectile { }; fo_projectile fpp_types[] = { - { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "progs/missile.mdl", "" }, - { FPP_GRENADE, 600, "progs/grenade.mdl", "t_grenade" }, - { FPP_INCENDIARY, 800, "progs/lavaball.mdl", "t_lavaball" }, - { FPP_NAIL, 1500, "progs/spike.mdl", "tr_spike" }, - { FPP_SUPER_NAIL, 1500, "progs/s_spike.mdl", "tr_spike" }, - { FPP_FLAMETHROWER, 600, "progs/s_explod.spr", "explodesprite" }, - { FPP_TRANQ, PC_SPY_TRANQSPEED, "progs/spike.mdl", "tr_spike" }, - { FPP_RAILGUN, PC_ENGINEER_RAILSPEED, "progs/e_spike1.mdl", "te_railtrail" }, + { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "", SND_RL }, + { FPP_GRENADE, 600, "grenade.mdl", "t_grenade", SND_GREN }, + { FPP_INCENDIARY, 800, "lavaball.mdl", "t_lavaball", SND_RL }, + { FPP_NAIL, 1500, "spike.mdl", "tr_spike", SND_NAIL }, + { FPP_SUPER_NAIL, 1500, "s_spike.mdl", "tr_spike", SND_SNAIL }, + { FPP_FLAMETHROWER, 600, "s_explod.spr", "explodesprite", SND_FLAMETHROWER }, + { FPP_TRANQ, PC_SPY_TRANQSPEED, "spike.mdl", "tr_spike", SND_TRANQ }, + { FPP_RAILGUN, PC_ENGINEER_RAILSPEED, "e_spike1.mdl", "te_railtrail", SND_RAILGUN }, }; + void InitFppProjectiles() { - for (float i = 0; i < fpp_types.length; i++) { + float i; + static int once; + ASSERTD_EQ(once, 0); + once = 1; + + for (i = 0; i < fpp_types.length; i++) { fo_projectile* desc = &fpp_types[i]; ASSERTD_EQ(i, desc->id); + desc->model = strcat("progs/", desc->model); desc->modelindex = getmodelindex(desc->model); if (desc->trail != "") desc->trailindex = particleeffectnum(strcat("fo-particles.",desc->trail)); } + + for (i = 0; i < snd_types.length; i++) { + fo_predsnd* snd = &snd_types[i]; + + ASSERTD_EQ(i, snd->id); + snd->sound = strcat("weapons/", snd->sound); + precache_sound(snd->sound); + } } #ifdef SSQC @@ -427,6 +474,24 @@ void WeaponPred_DoServerClientThink() { } } +void FO_Sound(entity e, float chan, string samp, float vol, float atten); + +void Pred_Sound(float snd) { + entity target = self; + string wav = snd_types[snd].sound; + + if (infokeyf(self, "fo_wpp_status") & CSQC_WEAP_PRED == 1) { + target = self.predict_entity; + setorigin(target, self.origin); + } + + FO_Sound(target, CHAN_WEAPON, wav, 1, ATTN_NORM); +} + +void PredProj_Sound(float proj_type) { + Pred_Sound(fpp_types[proj_type].snd); +} + void PredProj_Add(entity mis) { mis.dimension_seen = DMN_NOFLASH; diff --git a/ssqc/client.qc b/ssqc/client.qc index 6e62be43..d2bcdfb5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2019,6 +2019,7 @@ void (float all_dimensions) SetDimensions = { if (all_dimensions) { self.dimension_seen = DMN_NOFLASH; + self.tfstate &= ~TFSTATE_FLASHED; switch (self.team_no) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f859a2a9..aacc6bf4 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -81,6 +81,8 @@ void () LaserBolt_Touch = { void () W_FireRailgun = { local vector vec, org; + Pred_Sound(SND_RAILGUN); + self.ammo_nails = self.ammo_nails - 1; makevectors(self.v_angle); diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index b9c7df0f..c61c93ec 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -548,7 +548,7 @@ void () W_FireFlame = { return; } self.ammo_cells = self.ammo_cells - 1; - FO_Sound(self, CHAN_AUTO, "weapons/flmfire2.wav", 1, ATTN_NORM); + Pred_Sound(SND_FLAMETHROWER); flame = spawn(); flame.owner = self; flame.movetype = MOVETYPE_FLYMISSILE; @@ -677,7 +677,7 @@ void () W_FireIncendiaryCannon = { return; } self.ammo_rockets = self.ammo_rockets - 3; - FO_Sound(self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); + Pred_Sound(SND_RL); KickPlayer(-3, self); newmis = spawn(); newmis.owner = self; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index e5a62026..40fb8cf0 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -205,13 +205,13 @@ void FO_FlashTimer() void SetFlashDimension(entity te) { - FO_FlashDimension = ((FO_FlashDimension + 1) == 8) ? DMN_FLASH : FO_FlashDimension + 1; + FO_FlashDimension = ((FO_FlashDimension - DMN_FLASH + 1) % 7) + DMN_FLASH; float playerdimension = 1<ammo_per_shot; @@ -1397,7 +1397,7 @@ void (float ox) W_FireSpikes = { return; } - FO_Sound(self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); + PredProj_Sound(FPP_NAIL); self.ammo_nails -= wi->ammo_per_shot; dir = aim(self, 1000); @@ -1662,19 +1662,19 @@ void () W_Attack = { self.show_hostile = time + 1; if (ws.weapon == WEAP_AXE) { - FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + Pred_Sound(SND_AXE); if (shared_prng(self) < 0.5) player_axe1(); else player_axeb1(); } else if (ws.weapon == WEAP_KNIFE) { - FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + Pred_Sound(SND_AXE); if (shared_prng(self) < 0.5) player_knife1(); else player_knifeb1(); } else if (ws.weapon == WEAP_SPANNER) { - FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + Pred_Sound(SND_AXE); player_spanner1(); } else if (ws.weapon == WEAP_SHOTGUN) { player_shot1(); @@ -1744,17 +1744,15 @@ void () W_Attack = { self.antispam_incendiary_cannon = time + 3; } } else if (ws.weapon == WEAP_MEDIKIT) { - FO_Sound(self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); + Pred_Sound(SND_AXE); if (shared_prng(self) < 0.5) player_medikit1(); else player_medikitb1(); } else if (ws.weapon == WEAP_TRANQ) { - FO_Sound(self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM); player_shot1(); W_FireTranq(); } else if (ws.weapon == WEAP_RAILGUN) { - FO_Sound(self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM); player_shot1(); W_FireRailgun(); } diff --git a/ssqc/world.qc b/ssqc/world.qc index 54954a47..4048d44d 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -374,7 +374,6 @@ void () worldspawn = { } - InitFppProjectiles(); dimension_send = DMN_NOFLASH; settings_to_track = memalloc(sizeof(*settings_to_track)*settings_to_track_list.length); From 87bb432d77b7082ec3baf9dfd5321d13fb3a57a6 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 16:17:00 -0700 Subject: [PATCH 1821/2474] Fill in predicted missing sound less aggressively Try to filter out when we're not matching the projectile but did create/play a sound by just looking at how recently we played something. --- csqc/weapon_predict.qc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f99a090c..f1441843 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -41,13 +41,19 @@ static void update_avg_ping() { avg_ping.s2 += sq(new) - sq(old); } -static float get_avg_ping(float* mean, float* variance) { +static float fill_avg_ping(float* mean, float* variance) { float n = max(min(NUM_PING_SAMPLES, avg_ping.count), 2); *mean = avg_ping.s1 / n; *variance = (avg_ping.s2 - sq(avg_ping.s1)/n) / (n - 1); return n; } +inline float get_avg_ping() { + float avg, variance; + fill_avg_ping(&avg, &variance); + return avg; +} + // Order of preference: // server disable, client enable/disable, server/ping enable static float CalcPredEnabled(float current_enable, @@ -69,7 +75,7 @@ static float CalcPredEnabled(float current_enable, float ping_enable, avg, variance; - get_avg_ping(&avg, &variance); + fill_avg_ping(&avg, &variance); // We wait until 5ms over target (or 5 ms under target) when flipping, to // avoid flip flopping when ping is right at target. if (variance < sq(15)) @@ -102,9 +108,6 @@ void WPP_UpdateEnable(float force) { if (time > next_ping_update) { update_avg_ping(); next_ping_update = time + ENABLE_CHECK_PERIOD / NUM_PING_SAMPLES; - - float avg, variance; - get_avg_ping(&avg, &variance); } if (avg_ping.count < NUM_PING_SAMPLES / 2) @@ -173,11 +176,13 @@ static void SetHadEffect() { float animate_s_time; static entity pred_sound_entity; +static float last_pred_sound; void Pred_Sound(int snd) { if (pstate_pred.tfstate & TFSTATE_FLASHED) return; + last_pred_sound = time; setorigin(pred_sound_entity, pmove_org); sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, 1, ATTN_NORM); } @@ -906,7 +911,8 @@ void InitProjPredEnt() { // flight projectiles on the transition. This is effectively a nop in the // off case since the projectile list will just be empty. if (self.owner_entnum == player_localentnum && - !PredProjectile_MatchProjectile()) { + !PredProjectile_MatchProjectile() && + time - last_pred_sound > 75 * MSEC) { // Missing projectile implies we missed the local sound, patch it up. PredProj_Sound(Proj_FindFPP(self)); } From c471280a3010b0607cc9593b8b0c09807616755b Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 16:34:34 -0700 Subject: [PATCH 1822/2474] Prevent re-init of prediction The current settings decode is a mess and where we have to sit ends up being multiply invoked. Just put a guard around it for now. --- share/prediction.qc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/share/prediction.qc b/share/prediction.qc index bcad9a65..085a8220 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -435,7 +435,16 @@ void EntUpdate_Projectile(float isnew) { #undef COMM #ifdef SSQC +.float wpp_init; + void WeaponPred_InitPlayer(entity player) { + // PutClientInServer is called every spawn. At some point we'll clean up + // parameter decode so that it can happen earlier and this nonsense goes + // away. + if (player.wpp_init) + return; + player.wpp_init = TRUE; + if (!infokeyf(player, INFOKEY_P_CSQCACTIVE)) { bprint(PRINT_HIGH, player.netname, " is using a legacy non-CSQC client.\n"); return; From 84968d73475ad5a54e523fb55a04ae1b02fe100c Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 16:49:32 -0700 Subject: [PATCH 1823/2474] Fix double-print messages Forwarding of optional parameters seems to tickle some compiler bugs duplicating arguments, just remove since we don't actually have any multi-param sites. --- share/prediction.qc | 5 ++--- share/weapons.qc | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/share/prediction.qc b/share/prediction.qc index 085a8220..ca283e80 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -283,11 +283,10 @@ void WeaponPred_Update(entity player) { #undef M3 #undef M4 -void sprint_pred(entity client, float msglevel, string s, optional string s2, - optional string s3, optional string s4, optional string s5) { +void sprint_pred(entity client, float msglevel, string s) { if (infokeyf(client, "fo_wpp_status") & CSQC_WEAP_PRED) return; // Message generated client-side. - sprint(client, msglevel, s, s2, s3, s4, s5); + sprint(client, msglevel, s); } #endif diff --git a/share/weapons.qc b/share/weapons.qc index badec7ce..f08b1a6a 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -376,9 +376,7 @@ void (float att_delay) Attack_Finished; // Hack until we fix Status_Refresh() to not be awful. .float last_still_loading; void W_UpdateCurrentWeapon(entity pl); -void sprint_pred(entity client, float msglevel, string s, optional string s2, - optional string s3, optional string s4, optional string s5); - +void sprint_pred(entity client, float msglevel, string s); void FO_ReloadFrame() { if (self.tfstate & TFSTATE_RELOADING == 0) From e4b1c13dd71dfb73527f3841e5cea5c374ab0566 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 17:14:16 -0700 Subject: [PATCH 1824/2474] Clientside WEAPPREV/WEAPNEXT Implement CSQC handling of these as well as the warts around old weapon impulses and swapped pyro impulses. --- csqc/weapon_predict.qc | 13 ++++++++++ share/weapons.qc | 58 ++++++++++++++++++++++++++++++++++++++++-- ssqc/weapons.qc | 42 ++---------------------------- 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f1441843..04325208 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -243,6 +243,7 @@ void WP_Impulse() { } break; } + case TF_QUICKSTOP: if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) { pstate_pred.impulse = 0; @@ -251,6 +252,16 @@ void WP_Impulse() { pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. case TF_WEAPLAST: pstate_pred.queue_slot = pstate_pred.last_slot; break; + + case TF_WEAPNEXT: + pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( + pstate_pred.playerclass, pstate_pred.current_slot, FALSE); + break; + case TF_WEAPPREV: + pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( + pstate_pred.playerclass, pstate_pred.current_slot, TRUE); + break; + default: match = FALSE; } @@ -692,6 +703,7 @@ void PP_CreateProjectile(int proj_type, vector offset) { SetHadEffect(); entity proj = spawn(); +#if 0 // Packet loss doesnt guarantee the server will actually register quickslot // since it's a separate command from the attack. We can improve this in the // future via either a button or just combining them on an impulse. But for @@ -700,6 +712,7 @@ void PP_CreateProjectile(int proj_type, vector offset) { if (pstate_pred.tfstate & TFSTATE_QUICKSLOT && !(pstate_server.tfstate & TFSTATE_QUICKSLOT)) return; +#endif proj.s_time = time + PP_PredictStartOffset(); proj.starttime = max(time + CVARF(pp_trail_start) * MSEC, proj.s_time); diff --git a/share/weapons.qc b/share/weapons.qc index f08b1a6a..0c290b77 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -531,12 +531,27 @@ static float IsPyroSlotSwapped() { #else string(entity e, string key) infokey = #80; +static float csqc_get_user_setting(string s_short, string s_long, string def) { + string s = getplayerkeyvalue(player_localnum, s_short); + if (s == "") { + s = getplayerkeyvalue(player_localnum, s_long); + if (s == "") + s = def; + } + + switch (s) { + case "on": return TRUE; + case "off": return FALSE; + default: return stof(s); + } +} + float IsUsingOldImpulses() { - return getplayerkeyfloat(player_localnum, "owi"); + return csqc_get_user_setting("owi", "old_weapon_impulses", "off"); } static float IsPyroSlotSwapped() { - return getplayerkeyfloat(player_localnum, "cfpi"); + return csqc_get_user_setting("cfpi", "cf_pyro_impulses", "off"); } #endif @@ -559,6 +574,45 @@ Slot FO_SlotByInput(float input) { } } +Slot FO_FindPrevNextWeaponSlot(float playerclass, Slot slot, float is_prev) { + float i, len; + float direction = is_prev ? -1 : 1; + + if (IsUsingOldImpulses()) { + Slot* impulse_table = impulse_weapons[playerclass].slots; + // For reasons that seem to rhyme with -ompilerbug, reads from + // impulse_table[offset] return junk so we use a pointer cursor. + Slot* cur; + len = 7; + + for (i = 0; i < len; i++) { + cur = &impulse_table[i]; + if (IsSameSlot(*cur, slot)) + break; + } + do { + i = (i + direction + len) % len; + cur = &impulse_table[i]; + } while (IsSlotNull(*cur)); + + return *cur; + } else { + float* slot_weaps = class_weapons[playerclass].slots; + len = 4; + + // This is a little subtle, we need to transform the index both before + // and after the walk so that we don't walk back into ourselves. + i = InputHandlePyroSlotSwap(SlotIndex(slot) + 1) - 1; + do { + i = (i + direction + len) % len; + } while (slot_weaps[i] == 0); + + i = InputHandlePyroSlotSwap(i + 1); + return MakeSlot(i); + } +} + + void FO_Weapons_Init() { float i, j; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 9395bb48..38fc39fb 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1931,52 +1931,14 @@ void W_ChangeWeaponLast() { W_ChangeWeaponSlot(self.last_slot); }; -Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { - float i, len; - float direction = is_prev ? -1 : 1; - - if (IsUsingOldImpulses()) { - Slot* impulse_table = impulse_weapons[self.playerclass].slots; - // For reasons that seem to rhyme with -ompilerbug, reads from - // impulse_table[offset] return junk so we use a pointer cursor. - Slot* cur; - len = 7; - - for (i = 0; i < len; i++) { - cur = &impulse_table[i]; - if (IsSameSlot(*cur, slot)) - break; - } - do { - i = (i + direction + len) % len; - cur = &impulse_table[i]; - } while (IsSlotNull(*cur)); - - return *cur; - } else { - float* slot_weaps = class_weapons[self.playerclass].slots; - len = 4; - - // This is a little subtle, we need to transform the index both before - // and after the walk so that we don't walk back into ourselves. - i = InputHandlePyroSlotSwap(SlotIndex(slot) + 1) - 1; - do { - i = (i + direction + len) % len; - } while (slot_weaps[i] == 0); - - i = InputHandlePyroSlotSwap(i + 1); - return MakeSlot(i); - } -} - void W_ChangeWeaponNext() { Slot slot = IsSlotNull(self.current_slot) ? SlotMelee : self.current_slot; - W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, FALSE)); + W_ChangeWeaponSlot(FO_FindPrevNextWeaponSlot(self.playerclass, slot, FALSE)); } void W_ChangeWeaponPrev() { Slot slot = IsSlotNull(self.current_slot) ? SlotMelee : self.current_slot; - W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, TRUE)); + W_ChangeWeaponSlot(FO_FindPrevNextWeaponSlot(self.playerclass, slot, TRUE)); } void () PreMatchImpulses; From ce1c35daccd43933fa9ab9a606ce7bf5c2439f68 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 17:14:16 -0700 Subject: [PATCH 1825/2474] Clientside WEAPPREV/WEAPNEXT Implement CSQC handling of these as well as the warts around old weapon impulses and swapped pyro impulses. --- csqc/weapon_predict.qc | 8 ++++++ share/weapons.qc | 58 ++++++++++++++++++++++++++++++++++++++++-- ssqc/weapons.qc | 42 ++---------------------------- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f1441843..184c1516 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -249,6 +249,14 @@ void WP_Impulse() { break; } pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. + case TF_WEAPNEXT: + pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( + pstate_pred.playerclass, pstate_pred.current_slot, FALSE); + break; + case TF_WEAPPREV: + pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( + pstate_pred.playerclass, pstate_pred.current_slot, TRUE); + break; case TF_WEAPLAST: pstate_pred.queue_slot = pstate_pred.last_slot; break; default: diff --git a/share/weapons.qc b/share/weapons.qc index f08b1a6a..0c290b77 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -531,12 +531,27 @@ static float IsPyroSlotSwapped() { #else string(entity e, string key) infokey = #80; +static float csqc_get_user_setting(string s_short, string s_long, string def) { + string s = getplayerkeyvalue(player_localnum, s_short); + if (s == "") { + s = getplayerkeyvalue(player_localnum, s_long); + if (s == "") + s = def; + } + + switch (s) { + case "on": return TRUE; + case "off": return FALSE; + default: return stof(s); + } +} + float IsUsingOldImpulses() { - return getplayerkeyfloat(player_localnum, "owi"); + return csqc_get_user_setting("owi", "old_weapon_impulses", "off"); } static float IsPyroSlotSwapped() { - return getplayerkeyfloat(player_localnum, "cfpi"); + return csqc_get_user_setting("cfpi", "cf_pyro_impulses", "off"); } #endif @@ -559,6 +574,45 @@ Slot FO_SlotByInput(float input) { } } +Slot FO_FindPrevNextWeaponSlot(float playerclass, Slot slot, float is_prev) { + float i, len; + float direction = is_prev ? -1 : 1; + + if (IsUsingOldImpulses()) { + Slot* impulse_table = impulse_weapons[playerclass].slots; + // For reasons that seem to rhyme with -ompilerbug, reads from + // impulse_table[offset] return junk so we use a pointer cursor. + Slot* cur; + len = 7; + + for (i = 0; i < len; i++) { + cur = &impulse_table[i]; + if (IsSameSlot(*cur, slot)) + break; + } + do { + i = (i + direction + len) % len; + cur = &impulse_table[i]; + } while (IsSlotNull(*cur)); + + return *cur; + } else { + float* slot_weaps = class_weapons[playerclass].slots; + len = 4; + + // This is a little subtle, we need to transform the index both before + // and after the walk so that we don't walk back into ourselves. + i = InputHandlePyroSlotSwap(SlotIndex(slot) + 1) - 1; + do { + i = (i + direction + len) % len; + } while (slot_weaps[i] == 0); + + i = InputHandlePyroSlotSwap(i + 1); + return MakeSlot(i); + } +} + + void FO_Weapons_Init() { float i, j; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 9395bb48..38fc39fb 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1931,52 +1931,14 @@ void W_ChangeWeaponLast() { W_ChangeWeaponSlot(self.last_slot); }; -Slot W_FindPrevNextWeaponSlot(Slot slot, float is_prev) { - float i, len; - float direction = is_prev ? -1 : 1; - - if (IsUsingOldImpulses()) { - Slot* impulse_table = impulse_weapons[self.playerclass].slots; - // For reasons that seem to rhyme with -ompilerbug, reads from - // impulse_table[offset] return junk so we use a pointer cursor. - Slot* cur; - len = 7; - - for (i = 0; i < len; i++) { - cur = &impulse_table[i]; - if (IsSameSlot(*cur, slot)) - break; - } - do { - i = (i + direction + len) % len; - cur = &impulse_table[i]; - } while (IsSlotNull(*cur)); - - return *cur; - } else { - float* slot_weaps = class_weapons[self.playerclass].slots; - len = 4; - - // This is a little subtle, we need to transform the index both before - // and after the walk so that we don't walk back into ourselves. - i = InputHandlePyroSlotSwap(SlotIndex(slot) + 1) - 1; - do { - i = (i + direction + len) % len; - } while (slot_weaps[i] == 0); - - i = InputHandlePyroSlotSwap(i + 1); - return MakeSlot(i); - } -} - void W_ChangeWeaponNext() { Slot slot = IsSlotNull(self.current_slot) ? SlotMelee : self.current_slot; - W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, FALSE)); + W_ChangeWeaponSlot(FO_FindPrevNextWeaponSlot(self.playerclass, slot, FALSE)); } void W_ChangeWeaponPrev() { Slot slot = IsSlotNull(self.current_slot) ? SlotMelee : self.current_slot; - W_ChangeWeaponSlot(W_FindPrevNextWeaponSlot(slot, TRUE)); + W_ChangeWeaponSlot(FO_FindPrevNextWeaponSlot(self.playerclass, slot, TRUE)); } void () PreMatchImpulses; From 22e90035ae86e41778edd98287a1eed58838e5dd Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 17:25:14 -0700 Subject: [PATCH 1826/2474] Reorder TF_WEAPLAST check and disable workaround Last commit inadvertently reordered a fall-through case. Also try disabling the quickslot wrong projectile work around; believe that the previously reported cases were probably just people using WEAPPREV/NEXT. It's possible to do this with packet loss and quickslots, but much less common and the feel improvement on the times you don't drop packets is probably worth the occasional false projectile. From 1072dc98c194683d338b00f55b7acb2077be99ba Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 17:28:18 -0700 Subject: [PATCH 1827/2474] Reorder TF_WEAPLAST check and disable workaround Last commit inadvertently reordered a fall-through case. Also try disabling the quickslot wrong projectile work around; believe that the previously reported cases were probably just people using WEAPPREV/NEXT. It's possible to do this with packet loss and quickslots, but much less common and the feel improvement on the times you don't drop packets is probably worth the occasional false projectile. --- csqc/weapon_predict.qc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 184c1516..04325208 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -243,12 +243,16 @@ void WP_Impulse() { } break; } + case TF_QUICKSTOP: if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) { pstate_pred.impulse = 0; break; } pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. + case TF_WEAPLAST: + pstate_pred.queue_slot = pstate_pred.last_slot; break; + case TF_WEAPNEXT: pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( pstate_pred.playerclass, pstate_pred.current_slot, FALSE); @@ -257,8 +261,7 @@ void WP_Impulse() { pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( pstate_pred.playerclass, pstate_pred.current_slot, TRUE); break; - case TF_WEAPLAST: - pstate_pred.queue_slot = pstate_pred.last_slot; break; + default: match = FALSE; } @@ -700,6 +703,7 @@ void PP_CreateProjectile(int proj_type, vector offset) { SetHadEffect(); entity proj = spawn(); +#if 0 // Packet loss doesnt guarantee the server will actually register quickslot // since it's a separate command from the attack. We can improve this in the // future via either a button or just combining them on an impulse. But for @@ -708,6 +712,7 @@ void PP_CreateProjectile(int proj_type, vector offset) { if (pstate_pred.tfstate & TFSTATE_QUICKSLOT && !(pstate_server.tfstate & TFSTATE_QUICKSLOT)) return; +#endif proj.s_time = time + PP_PredictStartOffset(); proj.starttime = max(time + CVARF(pp_trail_start) * MSEC, proj.s_time); From b1044acbdee9769a2e2e60a29ab85ddec87b0a09 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 23 Oct 2022 21:17:54 -0700 Subject: [PATCH 1828/2474] Mark default_weapon unsupported Disable prediction when default_weapon is enabled, we'll remove it in ~a week after posting an announcement of its deprecation. --- csqc/weapon_predict.qc | 8 ++++++++ share/weapons.qc | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 04325208..dab0a043 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -54,12 +54,20 @@ inline float get_avg_ping() { return avg; } +float csqc_get_user_setting(string s_short, string s_long, string def); + // Order of preference: // server disable, client enable/disable, server/ping enable static float CalcPredEnabled(float current_enable, float unspec_default /* meaning of '-1' */, float server_disable, float server_enable, float client_value, string* set_by) { + if (csqc_get_user_setting("dw", "default_weapon", "0")) { + *set_by = "[default_weapon unsupported, talk to newby to fix your " \ + "config to not need it]"; + return FALSE; + } + if (server_disable || client_value == 0) { *set_by = server_disable ? "[server disable]" : "[cvar disable]"; diff --git a/share/weapons.qc b/share/weapons.qc index 0c290b77..4ccce7f2 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -531,7 +531,7 @@ static float IsPyroSlotSwapped() { #else string(entity e, string key) infokey = #80; -static float csqc_get_user_setting(string s_short, string s_long, string def) { +float csqc_get_user_setting(string s_short, string s_long, string def) { string s = getplayerkeyvalue(player_localnum, s_short); if (s == "") { s = getplayerkeyvalue(player_localnum, s_long); From 9eda7a5ec5d331562e6ea13856edb292deb54a27 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 24 Oct 2022 09:58:40 -0700 Subject: [PATCH 1829/2474] Fix Tranq sound From 34a2b3729ea226f0b358cc7319a86ce08e78c369 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 24 Oct 2022 15:57:00 -0700 Subject: [PATCH 1830/2474] Fix some sound issues The projectile matching on sound was becoming confused by attacks which share a projectile (e.g. nailgun and tranq), allowing the wrong sound to be played in some cases. Fix this and some other sound nits (e.g. AC) --- csqc/weapon_predict.qc | 44 ++++++++++--------------------- share/animate.qc | 17 +++++++----- share/prediction.qc | 21 ++++++++++----- ssqc/engineer.qc | 12 +++------ ssqc/misc.qc | 21 +++++++++++++++ ssqc/pyro.qc | 14 ++-------- ssqc/spy.qc | 7 +++-- ssqc/weapons.qc | 59 ++++++++++++++---------------------------- 8 files changed, 89 insertions(+), 106 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index dab0a043..bc4cf31b 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,6 +1,3 @@ -.float server_modelindex; // Track the server modelindex for matching, since it - // can be overridden client-side. - DEFCVAR_FLOAT(wpp_debug, 0); DEFCVAR_FLOAT(fo_wpp_beta, 0); @@ -657,8 +654,8 @@ DEFCVAR_FLOAT(r_grenadetrail, 1); int PP_FindTrail(entity e) { - float is_rocket = e.server_modelindex == fpp_types[FPP_ROCKET].modelindex; - float is_grenade = e.server_modelindex == fpp_types[FPP_GRENADE].modelindex; + float is_rocket = e.fpp_index == FPP_ROCKET; + float is_grenade = e.fpp_index == FPP_GRENADE; if (is_rocket || is_grenade) { float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; @@ -667,13 +664,7 @@ int PP_FindTrail(entity e) return trail_table[idx].trail[is_grenade]; } - for (float i = 0; i < fpp_types.length; i++) { - fo_projectile* desc = &fpp_types[i]; - if (e.server_modelindex == desc->modelindex) - return desc->trailindex; - } - - return 0; + return fpp_types[e.fpp_index].trailindex; } static float PP_EPS = 0.05; @@ -711,6 +702,8 @@ void PP_CreateProjectile(int proj_type, vector offset) { SetHadEffect(); entity proj = spawn(); + proj.fpp_index = proj_type; + #if 0 // Packet loss doesnt guarantee the server will actually register quickslot // since it's a separate command from the attack. We can improve this in the @@ -739,12 +732,8 @@ void PP_CreateProjectile(int proj_type, vector offset) { proj.angles = input_angles; proj.angles[0] *= -1; - proj.server_modelindex = desc->modelindex; - - float modelindex = desc->modelindex; - if (modelindex == fpp_types[FPP_ROCKET].modelindex && CVARF(cl_r2g) == 1) - modelindex = fpp_types[FPP_GRENADE].modelindex; - setmodelindex(proj, modelindex); + if (self.fpp_index == FPP_ROCKET && CVARF(cl_r2g) == 1) + setmodelindex(proj, fpp_types[FPP_GRENADE].modelindex); PP_InitTrail(proj); @@ -862,7 +851,7 @@ float PredProjectile_MatchProjectile() { self.origin = self.s_origin + (time - self.s_time) * self.velocity; for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { - if (proj.server_modelindex != self.server_modelindex) + if (proj.fpp_index != self.fpp_index) continue; float d = fabs(proj.s_time - self.s_time); @@ -904,26 +893,19 @@ float PredProjectile_MatchProjectile() { return FALSE; } -static int Proj_FindFPP(entity ent) { - for (float i = 0; i < fpp_types.length; i++) { - if (fpp_types[i].modelindex == ent.server_modelindex) - return i; - } - return -1; -} - // Called on `self`. void InitProjPredEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; - self.server_modelindex = self.modelindex; + ASSERTF_EQ(self.effects, 0); + setmodelindex(self, fpp_types[self.fpp_index].modelindex); setsize(self, [0,0,0], [0,0,0]); self.oldorigin = self.s_origin + CVARF(pp_trail_start) * MSEC * self.velocity; self.p_time = time + CVARF(pp_trail_start) * MSEC; - if (CVARF(cl_r2g) && self.server_modelindex == fpp_types[FPP_ROCKET].modelindex) + if (CVARF(cl_r2g) && self.fpp_index == FPP_ROCKET) setmodelindex(self, fpp_types[FPP_GRENADE].modelindex); PP_InitTrail(self); // Note: Might be overwritten by inherited match. @@ -934,8 +916,10 @@ void InitProjPredEnt() { if (self.owner_entnum == player_localentnum && !PredProjectile_MatchProjectile() && time - last_pred_sound > 75 * MSEC) { + // Missing projectile implies we missed the local sound, patch it up. - PredProj_Sound(Proj_FindFPP(self)); + if (PP_Enabled()) + PredProj_Sound(self.fpp_index); } } diff --git a/share/animate.qc b/share/animate.qc index 13a94417..432590f0 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -128,6 +128,8 @@ static float CheckNeedAssaultCannonDown() { } void asscan_up_extra() { + float tidx = *thinkindex() - 1; + if (CheckNeedAssaultCannonDown()) return; @@ -135,17 +137,19 @@ void asscan_up_extra() { FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); self.fire_held_down = 1; - if (self.client_thinkindex == 1) // Already incremented + if (tidx == 1) FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); SuperDamageSound(); - if (self.client_thinkindex == 6) // 600ms spin up + if (tidx == 6) // 600ms spin up player_asscan_fire(); else Attack_Finished(wi->attack_time); } void asscan_fire_extra() { + float tidx = *thinkindex() - 1; + if (CheckNeedAssaultCannonDown()) return; @@ -154,7 +158,7 @@ void asscan_fire_extra() { if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) && !(self.tfstate & TFSTATE_LOCK)) { - if (self.client_thinkindex % 2 == 0) { + if (tidx % 2 == 1) { muzzleflash(); FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); } @@ -166,7 +170,7 @@ void asscan_fire_extra() { self.tfstate |= TFSTATE_CANT_MOVE; // Halve firing speed when moving too fast. - if (vlen(self.velocity) < 30 || self.client_thinkindex % 2 == 1) + if (vlen(self.velocity) < 30 || tidx % 2 == 1) W_FireAssaultCannon(); } else { FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); @@ -176,12 +180,13 @@ void asscan_fire_extra() { } void asscan_down_extra() { + float tidx = *thinkindex() - 1; FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (self.client_thinkindex == 1) + if (tidx == 1) FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); - if (self.client_thinkindex >= 15) { // 1.5s down + if (tidx >= 15) { // 1.5s down self.tfstate &= ~TFSTATE_AIMING; self.fire_held_down = 0; player_run(); diff --git a/share/prediction.qc b/share/prediction.qc index ca283e80..97788ea8 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -1,6 +1,11 @@ #define ENT_WEAPONPRED 100 #define ENT_PROJECTILE 101 +// Below apply to both CSQC & SSQC ents +.float fpp_index; // Projectile type +.vector s_origin; // Spawning origin (at s_time); matched for client/server +.float s_time; // Time spawned (in client_time) + string wp_version = "v0.1"; enumflags { @@ -370,8 +375,6 @@ void EntUpdate_WeaponPred(float isnew) { #ifdef SSQC -.float s_time; -.vector s_origin; #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.##_field) #define COMMD(_type, _dest, _field) COMM(_type, _field) #define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) @@ -388,8 +391,6 @@ float() ReadFloat = #367; void InitProjPredEnt(); -.vector s_origin; -.float s_time; .float owner_entnum; #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() @@ -412,7 +413,7 @@ void EntUpdate_Projectile(float isnew) { } if (sendflags & FOPP_INIT) { - COMM(Short, modelindex); + COMM(Byte, fpp_index); COMM(Short, effects); COMM(Angle, angles[0]); @@ -500,12 +501,20 @@ void PredProj_Sound(float proj_type) { Pred_Sound(fpp_types[proj_type].snd); } -void PredProj_Add(entity mis) { +void FOProj_Init(int fpp_type, entity mis) { + // This init always needs to occur. mis.dimension_seen = DMN_NOFLASH; + PredProj_Sound(fpp_type); + + mis.modelindex = fpp_types[fpp_type].modelindex; + setsize(mis, '0 0 0', '0 0 0'); + + // Below here is only when we're using new projectile networking. if (!fo_projectiles) return; + mis.fpp_index = fpp_type; mis.s_origin = mis.origin; mis.SendEntity = PP_SendEntity; mis.SendFlags = 0xff; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index aacc6bf4..f5733ab9 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -81,8 +81,6 @@ void () LaserBolt_Touch = { void () W_FireRailgun = { local vector vec, org; - Pred_Sound(SND_RAILGUN); - self.ammo_nails = self.ammo_nails - 1; makevectors(self.v_angle); @@ -96,21 +94,17 @@ void () W_FireRailgun = { newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_TRIGGER; - FO_SetModel(newmis, "progs/e_spike1.mdl"); - setsize(newmis, '0 0 0', '0 0 0'); - - setorigin(newmis, org + '0 0 16'); - newmis.velocity = vec * PC_ENGINEER_RAILSPEED; + newmis.velocity = vec * fpp_types[FPP_RAILGUN].speed; newmis.angles = vectoangles(newmis.velocity); - newmis.oldorigin = newmis.velocity; newmis.nextthink = time + 5; newmis.think = SUB_Remove; newmis.touch = LaserBolt_Touch; newmis.classname = "railslug"; + setorigin(newmis, org + '0 0 16'); - PredProj_Add(newmis); + FOProj_Init(FPP_RAILGUN, newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } diff --git a/ssqc/misc.qc b/ssqc/misc.qc index 48b27019..13857a30 100644 --- a/ssqc/misc.qc +++ b/ssqc/misc.qc @@ -301,6 +301,27 @@ void (vector org, vector vec) LaunchLaser = { newmis.touch = Laser_Touch; }; +void (vector org, vector dir) launch_spike = { + newmis = spawn(); + newmis.voided = 0; + newmis.owner = self; + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.solid = SOLID_BBOX; + + newmis.angles = vectoangles(dir); + newmis.touch = spike_touch; + newmis.weapon = DMSG_NAILGUN; + newmis.classname = "spike"; + newmis.think = SUB_Remove; + newmis.nextthink = time + 6; + FO_SetModel(newmis, fpp_types[FPP_NAIL].model); + setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); + setorigin(newmis, org); + + newmis.velocity = dir * fpp_types[FPP_NAIL].speed; +}; + + void () spikeshooter_use = { if (self.spawnflags & 2) { FO_Sound(self, CHAN_VOICE, "enforcer/enfire.wav", 1, ATTN_NORM); diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index c61c93ec..4c5335fc 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -548,7 +548,6 @@ void () W_FireFlame = { return; } self.ammo_cells = self.ammo_cells - 1; - Pred_Sound(SND_FLAMETHROWER); flame = spawn(); flame.owner = self; flame.movetype = MOVETYPE_FLYMISSILE; @@ -570,11 +569,9 @@ void () W_FireFlame = { flame.touch = Flamer_stream_touch; flame.think = s_explode1; - FO_SetModel(flame, fpp_types[FPP_FLAMETHROWER].model); - setsize(flame, '0 0 0', '0 0 0'); setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); - PredProj_Add(flame); + FOProj_Init(FPP_FLAMETHROWER, flame); if (project_weapons) { AL_ProjectProjectile(flame); } @@ -677,7 +674,6 @@ void () W_FireIncendiaryCannon = { return; } self.ammo_rockets = self.ammo_rockets - 3; - Pred_Sound(SND_RL); KickPlayer(-3, self); newmis = spawn(); newmis.owner = self; @@ -685,7 +681,6 @@ void () W_FireIncendiaryCannon = { newmis.solid = SOLID_BBOX; makevectors(self.v_angle); newmis.velocity = aim(self, 1000); - string rktmdl = "progs/missile.mdl"; if (pyro_type == PYRO_ORIGINAL) { newmis.velocity = newmis.velocity * 600; @@ -695,9 +690,6 @@ void () W_FireIncendiaryCannon = { { newmis.velocity = newmis.velocity * fpp_types[FPP_INCENDIARY].speed; newmis.think = IncendiaryRadius_OZTF; - - if (pyro_type == PYRO_FO) - rktmdl = fpp_types[FPP_INCENDIARY].model; } newmis.angles = vectoangles(newmis.velocity); @@ -705,11 +697,9 @@ void () W_FireIncendiaryCannon = { newmis.nextthink = time + 5; newmis.weapon = DMSG_INCENDIARY; newmis.classname = "pyro_rocket"; - FO_SetModel(newmis, rktmdl); - setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); - PredProj_Add(newmis); + FOProj_Init(FPP_INCENDIARY, newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 182791e1..24d6835c 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1083,16 +1083,15 @@ void () W_FireTranq = { newmis.solid = 2; makevectors(self.v_angle); newmis.velocity = v_forward; - newmis.velocity = newmis.velocity * PC_SPY_TRANQSPEED; + newmis.velocity = newmis.velocity * fpp_types[FPP_TRANQ].speed; newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_TranqDartTouch; newmis.think = SUB_Remove; newmis.nextthink = time + 6; newmis.classname = "proj_tranq"; - FO_SetModel(newmis, "progs/spike.mdl"); - setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); - PredProj_Add(newmis); + + FOProj_Init(FPP_TRANQ, newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 38fc39fb..d97b8c60 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1106,8 +1106,7 @@ void () W_FireRocket = { setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); - PredProj_Sound(FPP_ROCKET); - PredProj_Add(newmis); + FOProj_Init(FPP_ROCKET, newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } @@ -1336,53 +1335,38 @@ void () W_FireGrenade = { void () spike_touch; void () superspike_touch; -void (vector org, vector dir) launch_spike = { +entity (int fpp_type, vector offset) W_FireNail = { newmis = spawn(); newmis.voided = 0; newmis.owner = self; newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_BBOX; - newmis.angles = vectoangles(dir); - newmis.touch = spike_touch; - newmis.weapon = DMSG_NAILGUN; + newmis.angles = vectoangles(aim(self, 1000)); newmis.classname = "spike"; newmis.think = SUB_Remove; newmis.nextthink = time + 6; - FO_SetModel(newmis, fpp_types[FPP_NAIL].model); - setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); - setorigin(newmis, org); + setorigin(newmis, self.origin + offset + '0 0 16'); - newmis.velocity = dir * fpp_types[FPP_NAIL].speed; + newmis.velocity = aim(self, 1000) * fpp_types[fpp_type].speed; - PredProj_Add(newmis); + if (fpp_type == FPP_NAIL) { + newmis.weapon = DMSG_NAILGUN; + newmis.touch = spike_touch; + } else { // fpp_type == FPP_SUPER_NAIL + newmis.touch = superspike_touch; + newmis.weapon = DMSG_SNAILGUN; + } + + FOProj_Init(fpp_type, newmis); if (project_weapons) { AL_ProjectProjectile(newmis); } -}; - -void () W_FireSuperSpikes = { - local vector dir; - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); - - PredProj_Sound(FPP_SUPER_NAIL); - - self.ammo_nails -= wi->ammo_per_shot; - - dir = aim(self, 1000); - launch_spike(self.origin + '0 0 16', dir); - LogEventAttack(self); - newmis.touch = superspike_touch; - newmis.weapon = DMSG_SNAILGUN; - FO_SetModel(newmis, fpp_types[FPP_SUPER_NAIL].model); - setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); - KickPlayer(-3, self); - Attack_Finished(wi->attack_time); + return newmis; }; void (float ox) W_FireSpikes = { - local vector dir; FO_WeapState ws; FO_FillCurrentWeapState(&ws); FO_WeapInfo* wi = ws->wi; @@ -1392,19 +1376,16 @@ void (float ox) W_FireSpikes = { if (self.ammo_nails < wi->ammo_per_shot) { W_ChangeToBestWeapon(); return; - } else if (ws.weapon == WEAP_SUPER_NAILGUN) { - W_FireSuperSpikes(); - return; } - PredProj_Sound(FPP_NAIL); - self.ammo_nails -= wi->ammo_per_shot; + *ws->ammo_remaining -= wi->ammo_per_shot; + if (wi->weapon == WEAP_NAILGUN) + W_FireNail(FPP_NAIL, v_right * ox); + else + W_FireNail(FPP_SUPER_NAIL, '0 0 0'); - dir = aim(self, 1000); - launch_spike(self.origin + '0 0 16' + v_right * ox, dir); LogEventAttack(self); KickPlayer(-3, self); - Attack_Finished(wi->attack_time); }; From 3dc9dff4e49ddd66cdda4efbd87e693129872392 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 24 Oct 2022 17:50:24 -0700 Subject: [PATCH 1831/2474] Simplify WP/PP Enabled Projectile prediction depends on weapon prediction to know when to generate the projectile (including cases such as being blocked out by reload, what the correct projectile is, etc). Simplify enable state by making this dependence more clear, eliminating some code where we briefly considered supporting PP without WP. --- csqc/main.qc | 5 ++++ csqc/weapon_predict.qc | 63 +++++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 30c7bef3..da60c9d2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -84,6 +84,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("vote_addmap"); registercommand("vote_removemap"); + + registercommand("fo_wpp_status"); registercvar("fo_hud_idle_alpha", "0.3"); for(float i = 0; i < MENU_OPTION.length - 1; i++) { registercvar(strcat("fo_menu_option_",MENU_OPTION[i]), MENU_OPTION[i]); @@ -388,6 +390,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("-button4\n"); } break; + case "fo_wpp_status": + WPP_Status(); + break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); break; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index bc4cf31b..e14a4e9c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -12,7 +12,6 @@ static inline float sq(float x) { return x * x; } #define csqc_print(...) \ do { if (CVARF(wpp_debug) & 4) { \ print("CSQC: ", __VA_ARGS__); \ - SetHadEffect(); \ } else { print(__VA_ARGS__); } } while(0) #define NUM_PING_SAMPLES 20 @@ -58,13 +57,20 @@ float csqc_get_user_setting(string s_short, string s_long, string def); static float CalcPredEnabled(float current_enable, float unspec_default /* meaning of '-1' */, float server_disable, float server_enable, - float client_value, string* set_by) { + float client_value, + float dependent_enabled, string* set_by) { if (csqc_get_user_setting("dw", "default_weapon", "0")) { *set_by = "[default_weapon unsupported, talk to newby to fix your " \ "config to not need it]"; return FALSE; } + if (!dependent_enabled) { + // PP depends on WP, so !WP => !PP + *set_by = "[weapon prediction disabled]"; + return FALSE; + } + if (server_disable || client_value == 0) { *set_by = server_disable ? "[server disable]" : "[cvar disable]"; @@ -109,6 +115,26 @@ static float next_wpp_enable_check; static float next_ping_update; void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; +void WPP_Status() { + string wp_source, pp_source; + float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; + + CalcPredEnabled(wp_enabled, CVARF(fo_wpp_beta), + pstate_server.predict_flags & PF_WP_DISABLE, + pstate_server.predict_flags & PF_WP_ENABLE, + CVARF(fo_weap_predict), TRUE, &wp_source); + + CalcPredEnabled(pp_enabled, CVARF(fo_wpp_beta), + pstate_server.predict_flags & PF_PP_DISABLE, + pstate_server.predict_flags & PF_PP_ENABLE, + CVARF(fo_proj_predict), wp_enabled, &pp_source); + + printf("FortressOne: Weapon prediction %s %s\n", + wp_enabled ? "enabled" : "disabled", wp_source); + printf("FortressOne: Projectile prediction %s %s\n", + pp_enabled ? "enabled" : "disabled", pp_source); +} + void WPP_UpdateEnable(float force) { if (time > next_ping_update) { update_avg_ping(); @@ -129,12 +155,12 @@ void WPP_UpdateEnable(float force) { wp_new = CalcPredEnabled(pengine.wp_enabled, CVARF(fo_wpp_beta), pstate_server.predict_flags & PF_WP_DISABLE, pstate_server.predict_flags & PF_WP_ENABLE, - CVARF(fo_weap_predict), &wp_source); + CVARF(fo_weap_predict), TRUE, &wp_source); pp_new = CalcPredEnabled(pengine.pp_enabled, CVARF(fo_wpp_beta), pstate_server.predict_flags & PF_PP_DISABLE, pstate_server.predict_flags & PF_PP_ENABLE, - CVARF(fo_proj_predict), &pp_source); + CVARF(fo_proj_predict), wp_new, &pp_source); static float once; if (wp_new != pengine.wp_enabled || !once) { @@ -161,11 +187,10 @@ void WPP_UpdateEnable(float force) { WP_UpdateViewModel(pengine.pweap_ent); } -static inline float IsEffectFrame() { - return pengine.is_effectframe; -} +static float IsEffectFrame() { + if (!pengine.is_effectframe) + return FALSE; -static void SetHadEffect() { // At ultra-low latencies it's possible that we're only one frame in front // of the server. But this can mean that we get that frame back immediately // (and our input applies to the one after it). @@ -173,6 +198,7 @@ static void SetHadEffect() { pengine.last_effectframe++; if (CVARF(wpp_debug) & 8) print("Effect bump!\n"); } + return TRUE; } //////////////////////////////////////////////////////////////////////////////// @@ -324,7 +350,7 @@ float WP_CurrentAmmo() { return WP_GetAmmo(WP_CurrentWeapon()->ammo_type); } -float* WP_ClipFired() { +static float* WP_ClipFired() { float index = SlotIndex(pstate_pred.current_slot); if (pstate_pred.playerclass == PC_DEMOMAN && index == 1) @@ -520,10 +546,8 @@ void WP_Frame() { return; } - if (WP_Enabled()) { - WP_CheckReloadFinished(); - WP_Impulse(); - } + WP_CheckReloadFinished(); + WP_Impulse(); if ((input_buttons & BUTTON0) && !WP_IsReloading() && (pstate_pred.client_time >= pstate_pred.attack_finished)) @@ -699,7 +723,9 @@ void PP_CreateProjectile(int proj_type, vector offset) { PredProj_Sound(proj_type); - SetHadEffect(); + if (!PP_Enabled()) + return; + entity proj = spawn(); proj.fpp_index = proj_type; @@ -761,7 +787,7 @@ void PP_NailFrame() { float idx = (pstate_pred.client_thinkindex + 1) % 2; - if (!IsEffectFrame() || !PP_Enabled()) + if (!IsEffectFrame()) return; if (wi->weapon == WEAP_NAILGUN) @@ -791,7 +817,7 @@ void WP_Attack() { // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 1; - if (PP_Enabled() && IsEffectFrame() && !in_anim) { + if (IsEffectFrame() && !in_anim) { switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: PP_CreateProjectile(FPP_ROCKET, v_forward * 8); @@ -918,7 +944,7 @@ void InitProjPredEnt() { time - last_pred_sound > 75 * MSEC) { // Missing projectile implies we missed the local sound, patch it up. - if (PP_Enabled()) + if (WP_Enabled()) PredProj_Sound(self.fpp_index); } } @@ -967,8 +993,7 @@ void WP_UpdateViewModel(entity pweap_ent) { } float WP_ClientThink() { - // Can only fully disable if both weapon and projectile prediction are off. - if (!WP_Enabled() && !PP_Enabled()) + if (!WP_Enabled()) return PREDRAW_NEXT; pstate_pred = pstate_server; From 0def055304193f33a85d472eca8f11a23158b224 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 25 Oct 2022 01:11:40 -0700 Subject: [PATCH 1832/2474] Synchronized Config State There's several tunables that we need to synchronize between client and server to ensure accurate prediction; further, these are invisible since they're stored in localinfo server side. Implement a config entity that watches for updates and handles propagating config state to all clients. --- csqc/main.qc | 8 +- csqc/weapon_predict.qc | 76 +++++++++++------ share/prediction.qc | 180 ++++++++++++++++++++++++++++------------- ssqc/world.qc | 1 + 4 files changed, 182 insertions(+), 83 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index da60c9d2..f3e09928 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,6 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // } FO_Weapons_Init(); + WeapPred_InitDefaultConfig(); FO_PP_Init(); // Some of this is always used by custom projectiles. CsGrenTimer::Init(); @@ -85,7 +86,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("vote_addmap"); registercommand("vote_removemap"); - registercommand("fo_wpp_status"); + registercommand("wpp_status"); registercvar("fo_hud_idle_alpha", "0.3"); for(float i = 0; i < MENU_OPTION.length - 1; i++) { registercvar(strcat("fo_menu_option_",MENU_OPTION[i]), MENU_OPTION[i]); @@ -390,7 +391,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("-button4\n"); } break; - case "fo_wpp_status": + case "wpp_status": WPP_Status(); break; case "vote_addmap": @@ -407,6 +408,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { void(float isnew) CSQC_Ent_Update = { float etype = readbyte(); switch (etype) { + case ENT_CONFIG: + EntUpdate_Config(); + break; case ENT_WEAPONPRED: EntUpdate_WeaponPred(isnew); break; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index e14a4e9c..6851a1dd 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,9 +1,16 @@ DEFCVAR_FLOAT(wpp_debug, 0); DEFCVAR_FLOAT(fo_wpp_beta, 0); -DEFCVAR_FLOAT(fo_wp_minping, 50); -DEFCVAR_FLOAT(fo_weap_predict, -1); -DEFCVAR_FLOAT(fo_proj_predict, -1); +DEFCVAR_FLOAT(wpp_min_ping, -1); +DEFCVAR_FLOAT(wpp_weap_predict, -1); +DEFCVAR_FLOAT(wpp_proj_predict, -1); + +float WP_MinPing() { + if (CVARF(wpp_min_ping) == -1) + return fo_config.wp_default_min_ping_ms; + else + return CVARF(wpp_min_ping); +} void WP_UpdateViewModel(entity pweap_ent); @@ -81,7 +88,7 @@ static float CalcPredEnabled(float current_enable, return TRUE; } - if (CVARF(fo_wp_minping) < 0) + if (WP_MinPing() == 0) return current_enable; float ping_enable, avg, variance; @@ -90,18 +97,18 @@ static float CalcPredEnabled(float current_enable, // We wait until 5ms over target (or 5 ms under target) when flipping, to // avoid flip flopping when ping is right at target. if (variance < sq(15)) - ping_enable = avg > CVARF(fo_wp_minping) + (current_enable ? -5 : 5); + ping_enable = avg > WP_MinPing() + (current_enable ? -5 : 5); else return current_enable; // variance too high, don't change anything. if (unspec_default || server_enable) { if (ping_enable) { - *set_by = sprintf("[ping] (fo_wp_minping=%0.0f / avg=%0.0f var=%0.0f)", - CVARF(fo_wp_minping), avg, variance); + *set_by = sprintf("[ping >%d] (avg=%0.0f var=%0.0f)", + WP_MinPing(), avg, variance); return TRUE; } else { - *set_by = "[lan mode <40]"; + *set_by = sprintf("[lan mode <%d]", WP_MinPing()); return FALSE; } } @@ -115,25 +122,44 @@ static float next_wpp_enable_check; static float next_ping_update; void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; +#define PRINT_CONFIG(_field) \ + if (fo_config.##_field) printf(" ." #_field " = %d\n", fo_config.##_field) void WPP_Status() { string wp_source, pp_source; float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; CalcPredEnabled(wp_enabled, CVARF(fo_wpp_beta), - pstate_server.predict_flags & PF_WP_DISABLE, - pstate_server.predict_flags & PF_WP_ENABLE, - CVARF(fo_weap_predict), TRUE, &wp_source); + fo_config.wp_global_disable, fo_config.wp_global_enable, + CVARF(wpp_weap_predict), TRUE, &wp_source); CalcPredEnabled(pp_enabled, CVARF(fo_wpp_beta), - pstate_server.predict_flags & PF_PP_DISABLE, - pstate_server.predict_flags & PF_PP_ENABLE, - CVARF(fo_proj_predict), wp_enabled, &pp_source); + fo_config.pp_global_disable, fo_config.pp_global_enable, + CVARF(wpp_proj_predict), wp_enabled, &pp_source); - printf("FortressOne: Weapon prediction %s %s\n", + printf("Prediction Status:\n"); + printf(" Weapon prediction %s %s\n", wp_enabled ? "enabled" : "disabled", wp_source); - printf("FortressOne: Projectile prediction %s %s\n", + printf(" Projectile prediction %s %s\n", pp_enabled ? "enabled" : "disabled", pp_source); + + float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); + float avg, variance; + fill_avg_ping(&avg, &variance); + printf(" inst_ping = %d avg_ping = %d var = %d\n", ping, avg, variance); + + printf("Config:\n"); + PRINT_CONFIG(max_rewind_slow_projectile_ms); + PRINT_CONFIG(max_rewind_fast_projectile_ms); + PRINT_CONFIG(rewind_fast_projectile_thresh); + PRINT_CONFIG(wp_default_min_ping_ms); + PRINT_CONFIG(wp_global_enable); + PRINT_CONFIG(wp_global_disable); + PRINT_CONFIG(pp_global_enable); + PRINT_CONFIG(pp_global_disable); + PRINT_CONFIG(wpp_global_enable); + PRINT_CONFIG(wpp_global_disable); } +#undef PRINT_CONFIG void WPP_UpdateEnable(float force) { if (time > next_ping_update) { @@ -148,19 +174,19 @@ void WPP_UpdateEnable(float force) { return; next_wpp_enable_check = time + ENABLE_CHECK_PERIOD; - // Tristate: 1 => force on, 0 => force off, -1 => up to minping/server + // For wpp_weap_predict and wpp_proj_predict we use a tristate: + // 1 => force on, 0 => force off, -1 => up to min_ping/server + float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; float wp_new = -1, pp_new = -1; string wp_source, pp_source; - wp_new = CalcPredEnabled(pengine.wp_enabled, CVARF(fo_wpp_beta), - pstate_server.predict_flags & PF_WP_DISABLE, - pstate_server.predict_flags & PF_WP_ENABLE, - CVARF(fo_weap_predict), TRUE, &wp_source); + wp_new = CalcPredEnabled(wp_enabled, CVARF(fo_wpp_beta), + fo_config.wp_global_disable, fo_config.wp_global_enable, + CVARF(wpp_weap_predict), TRUE, &wp_source); - pp_new = CalcPredEnabled(pengine.pp_enabled, CVARF(fo_wpp_beta), - pstate_server.predict_flags & PF_PP_DISABLE, - pstate_server.predict_flags & PF_PP_ENABLE, - CVARF(fo_proj_predict), wp_new, &pp_source); + pp_new = CalcPredEnabled(pp_enabled, CVARF(fo_wpp_beta), + fo_config.pp_global_disable, fo_config.pp_global_enable, + CVARF(wpp_proj_predict), wp_new, &pp_source); static float once; if (wp_new != pengine.wp_enabled || !once) { diff --git a/share/prediction.qc b/share/prediction.qc index 97788ea8..62b7a4ef 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -1,12 +1,28 @@ -#define ENT_WEAPONPRED 100 -#define ENT_PROJECTILE 101 +#define ENT_CONFIG 100 +#define ENT_WEAPONPRED 101 +#define ENT_PROJECTILE 102 // Below apply to both CSQC & SSQC ents -.float fpp_index; // Projectile type +.float fpp_index; // Projectile type .vector s_origin; // Spawning origin (at s_time); matched for client/server .float s_time; // Time spawned (in client_time) -string wp_version = "v0.1"; +string wp_version = "v0.2"; + +var struct { + float max_rewind_slow_projectile_ms; + float max_rewind_fast_projectile_ms; + float rewind_fast_projectile_thresh; + float wp_default_min_ping_ms; + + float wp_global_enable; + float wp_global_disable; + float pp_global_enable; + float pp_global_disable; + float wpp_global_enable; + float wpp_global_disable; + +} fo_config; enumflags { FOWP_CTIME, @@ -30,12 +46,6 @@ enumflags { #define FOWP_ALL 0xFFFF -#define PF_WP_ENABLE 1 -#define PF_WP_DISABLE 2 -#define PF_PP_ENABLE 4 -#define PF_PP_DISABLE 8 -#define PF_ED_MASK (PF_WP_ENABLE | PF_WP_DISABLE | PF_PP_ENABLE | PF_PP_DISABLE) - enumflags { CSQC_WEAP_PRED, CSQC_PROJ_PRED, @@ -224,42 +234,12 @@ float shared_prng(entity pl) { // A 16-bit xor-shift LFSR. predict_tf_state blank_state; .float last_full_predict_refresh; -static void WeaponPred_UpdatePredictionFlags() { - float wpp_enable = FALSE, wp_enable = FALSE, pp_enable = FALSE; - float wpp_disable = FALSE, wp_disable = FALSE, pp_disable = FALSE; - - wp_enable = CF_GetSetting("wpge", "wp_global_enable", "off"); - wp_disable = CF_GetSetting("wpgd", "wp_global_disable", "off"); - pp_enable = CF_GetSetting("ppge", "pp_global_enable", "off"); - pp_disable = CF_GetSetting("ppgd", "pp_global_disable", "off"); - wpp_enable = CF_GetSetting("wppge", "wpp_global_enable", "off"); - wpp_disable = CF_GetSetting("wppge", "wpp_global_disable", "off"); - - float wp_mask = 0, pp_mask = 0; - - // Disables dominate enables. - if (wpp_disable || wp_disable) - wp_mask = PF_WP_DISABLE; - else if (wpp_enable || wp_enable) - wp_mask = PF_WP_ENABLE; - if (wpp_disable || pp_disable) - pp_mask = PF_PP_DISABLE; - else if (wpp_enable || pp_enable) - pp_mask = PF_PP_ENABLE; - - self.predict_state.predict_flags &= ~PF_ED_MASK; - self.predict_state.predict_flags |= wp_mask | pp_mask; - - // Note: Flag to send is simply the all-bits periodic. -} - void WeaponPred_Update(entity player) { float mask = FOWP_CTIME; if (time - player.last_full_predict_refresh >= 1000 * MSEC) { player.predict_state = blank_state; player.last_full_predict_refresh = time; - WeaponPred_UpdatePredictionFlags(); mask = -1; } @@ -295,6 +275,48 @@ void sprint_pred(entity client, float msglevel, string s) { } #endif +#ifdef CSQC +float() ReadByte = #360; +float() ReadShort = #362; +float() ReadCoord = #364; +float() ReadAngle = #365; +float() ReadFloat = #367; + +void InitWeapPredEnt(entity e); +void WP_ServerUpdate(); +void InitProjPredEnt(); +void WPP_UpdateEnable(float force); + +.float owner_entnum; +#endif + +#ifdef SSQC +#define COMM(_type, _field) Write##_type(MSG_ENTITY, fo_config.##_field) +float WP_SendConfig(entity to_player, float sendflags) { + WriteByte(MSG_ENTITY, ENT_CONFIG); +#else +#define COMM(_type, _field) fo_config.##_field = Read##_type() +void EntUpdate_Config() { +#endif + COMM(Float, max_rewind_slow_projectile_ms); + COMM(Float, max_rewind_fast_projectile_ms); + COMM(Float, rewind_fast_projectile_thresh); + COMM(Float, wp_default_min_ping_ms); + COMM(Float, wp_global_enable); + COMM(Float, wp_global_disable); + COMM(Float, pp_global_enable); + COMM(Float, pp_global_disable); + COMM(Float, wpp_global_enable); + COMM(Float, wpp_global_disable); + +#ifdef SSQC + return TRUE; +#else + WPP_UpdateEnable(TRUE); +#endif +} +#undef COMM + #ifdef SSQC #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) float WP_SendEntity(entity to_player, float sendflags) { @@ -304,11 +326,6 @@ float WP_SendEntity(entity to_player, float sendflags) { WriteByte(MSG_ENTITY, ENT_WEAPONPRED); WriteFloat(MSG_ENTITY, sendflags); #else -float() ReadByte = #360; -float() ReadFloat = #367; -void InitWeapPredEnt(entity e); -void WP_ServerUpdate(); - #define COMM(_type, _field) pstate_server.##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { float sendflags = readfloat(); @@ -383,16 +400,6 @@ float PP_SendEntity(entity to_player, float sendflags) { WriteByte(MSG_ENTITY, sendflags); #else -float() ReadByte = #360; -float() ReadShort = #362; -float() ReadCoord = #364; -float() ReadAngle = #365; -float() ReadFloat = #367; - -void InitProjPredEnt(); - -.float owner_entnum; - #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() #define COMMO(_type, _dest, _src) ##_dest = Read##_type() #define COMM(_type, _field) COMMD(_type, _field, _field) @@ -434,9 +441,70 @@ void EntUpdate_Projectile(float isnew) { #undef COMMO #undef COMM +void WeapPred_InitDefaultConfig() { + fo_config.max_rewind_slow_projectile_ms = 100; + fo_config.max_rewind_fast_projectile_ms = 150; + fo_config.rewind_fast_projectile_thresh = 1500; + fo_config.wp_default_min_ping_ms = 45; +} + #ifdef SSQC -.float wpp_init; +entity config_entity; + +#define CONFIG_UPDATE(_fl, _ps_short, _field) \ + do { string _cur = ftos(fo_config.##_field); \ + float _val = CF_GetSetting(_ps_short, #_field, _cur); \ + if (_val != fo_config.##_field) { \ + fo_config.##_field = _val; _fl = TRUE; \ + } \ + } while (0) + +static void WeaponPred_CheckConfigUpdate() { + float update = FALSE; + + // Target is also the long form localinfo name. + CONFIG_UPDATE(update, "mrsp", max_rewind_slow_projectile_ms); + CONFIG_UPDATE(update, "mrfp", max_rewind_fast_projectile_ms); + CONFIG_UPDATE(update, "rfpt", rewind_fast_projectile_thresh); + CONFIG_UPDATE(update, "wpdmp", wp_default_min_ping_ms); + CONFIG_UPDATE(update, "wpge", wp_global_enable); + CONFIG_UPDATE(update, "wpgd", wp_global_disable); + CONFIG_UPDATE(update, "ppge", pp_global_enable); + CONFIG_UPDATE(update, "ppgd", pp_global_disable); + CONFIG_UPDATE(update, "wppge", wpp_global_enable); + CONFIG_UPDATE(update, "wppge", wpp_global_disable); + + if (update) + print("saw update! %d", fo_config.wp_global_disable); + + + static float last_force_refresh; + if (time > last_force_refresh + 5) { + update = TRUE; + last_force_refresh = time; + } + + if (update) + config_entity.SendFlags = 1; + config_entity.nextthink = time + 0.25; +}; +#undef CONFIG_UPDATE + +void WeaponPred_Init() { + WeapPred_InitDefaultConfig(); + + config_entity = spawn(); + + config_entity.dimension_seen = DMN_FLASH | DMN_NOFLASH; + config_entity.pvsflags = PVSF_IGNOREPVS; + config_entity.SendEntity = WP_SendConfig; + + config_entity.think = WeaponPred_CheckConfigUpdate; + config_entity.nextthink = time + 0.5; +} + +.float wpp_init; void WeaponPred_InitPlayer(entity player) { // PutClientInServer is called every spawn. At some point we'll clean up // parameter decode so that it can happen earlier and this nonsense goes diff --git a/ssqc/world.qc b/ssqc/world.qc index 4048d44d..6fc39a16 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -375,6 +375,7 @@ void () worldspawn = { } dimension_send = DMN_NOFLASH; + WeaponPred_Init(); settings_to_track = memalloc(sizeof(*settings_to_track)*settings_to_track_list.length); for (float i = 0; i < settings_to_track_list.length; i++) From 378a2f1aa831ee868849fbf8d9ba2860a2fb6cc9 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 25 Oct 2022 00:01:33 -0700 Subject: [PATCH 1833/2474] Rewrite projectile projection This commit fundamentally improves the accuracy of projected projectiles by reworking the calculation of s_time. It also unifies actual forward projection into a new (currently just forked) implementation which pairs with the client side implementation and accounts for projectile speed in the projection. While the auto-tuning was working well in terms of the actual matching there were some cases where it could fall into local minima on continuous attacks such as nailguns where correction pushed the entire match-stream into an off-by-one. These were rooted in some incorrect interactions with the 3 notions of time that we're working with: client side time, forward predicted client side time, and server side time. Taking another pass through this and rewriting these calculations has removed the resultant error term and required auto correction that was leading to the above. --- csqc/weapon_predict.qc | 62 +++++++++++++----------------------------- share/commondefs.qc | 15 ++++++++++ share/prediction.qc | 47 ++++++++++++++------------------ ssqc/antilag.qc | 33 +++++++++++++++++++--- ssqc/client.qc | 3 -- ssqc/engineer.qc | 3 -- ssqc/pyro.qc | 6 ---- ssqc/qw.qc | 7 ++--- ssqc/spy.qc | 3 -- ssqc/time.qc | 12 ++++---- ssqc/weapons.qc | 17 +++--------- 11 files changed, 97 insertions(+), 111 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6851a1dd..64203ae3 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -482,8 +482,6 @@ static void prandom(void() option1, void() option2) { option2(); } -float PP_PredictStartOffset(); - void WP_AnimateModel() { if (pstate_pred.client_thinkindex == 0) { player_run(); @@ -612,8 +610,6 @@ trail_table_entry trail_table[] = { float nail_trail; -static float corr_s; // Auto-tuning correction factor. - void FO_PP_Init() { // Entity we'll attach locally generated sound to. pred_sound_entity = spawn(); @@ -631,8 +627,6 @@ void FO_PP_Init() { entry->trail[j] = particleeffectnum(name); } } - - corr_s = 0.04; // Ballpark factor for many common pings. } void PP_Cleanup(entity proj) { @@ -653,12 +647,8 @@ DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); -// A small time based correction factor (2 frames) that results in more precise -// overlap with where the engine projectiles were previously rendered. -static float orig_proj_offset = 2/77.0; - float PP_PredrawActive() { - float delta = time - self.s_time + orig_proj_offset; + float delta = time - self.s_time; self.origin = self.s_origin + (self.velocity * delta); setorigin(self, self.origin); @@ -718,7 +708,7 @@ int PP_FindTrail(entity e) } static float PP_EPS = 0.05; -DEFCVAR_FLOAT(pp_trail_start, 50); +DEFCVAR_FLOAT(pp_trail_start, 20); static inline void PP_InitTrail(entity proj) { proj.oldorigin = proj.s_origin + CVARF(pp_trail_start) * MSEC * proj.velocity; @@ -728,16 +718,12 @@ static inline void PP_InitTrail(entity proj) { // Predict the effective start time of something we fire right now, accounting // for server side projection, ping fluctuation, etc. -inline float PP_PredictStartOffset() { - float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000.0; - - // TODO: Communicate with server around this. - // Note: We use true time here since the created projectiles exist outside of - // our prediction. - float start_offset = max(0, pstate_pred.client_ping - 0.1) + // Server project - max(0, ping - pstate_pred.client_ping); // Uncorrected error +float PP_StartOffset(int fpp_type) { + int max_credit = max_rewind_credit_ms(fpp_type); + float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); - return start_offset / 2 + corr_s; + return (max(pstate_pred.client_ping - max_credit, 0) + + ping - pstate_pred.client_ping) / 1000.0; } static float PP_EPS = 0.05; @@ -767,9 +753,10 @@ void PP_CreateProjectile(int proj_type, vector offset) { return; #endif - proj.s_time = time + PP_PredictStartOffset(); + // Note: We use true time here as created projectiles exist outside of pred. + proj.s_time = time + PP_StartOffset(proj_type); proj.starttime = max(time + CVARF(pp_trail_start) * MSEC, proj.s_time); - proj.endtime = time + pstate_pred.client_ping + PP_EPS + 2; + proj.endtime = time + pstate_pred.client_ping / 1000.0 + PP_EPS; proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; @@ -899,43 +886,33 @@ void WP_Attack() { float PredProjectile_MatchProjectile() { entity proj, match = __NULL__; - float best = 0.2; + float best = 32; self.origin = self.s_origin + (time - self.s_time) * self.velocity; + for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { if (proj.fpp_index != self.fpp_index) continue; - float d = fabs(proj.s_time - self.s_time); + if (time > proj.endtime - 0.01) + break; // Projectile list is time ordered + + float d = vlen(proj.origin - self.origin); if (d < best) { best = d; match = proj; - - proj.origin = proj.s_origin + (time - proj.s_time) * self.velocity; - if (vlen(proj.origin - self.origin) < 32) { - match = proj; - break; - } } } if (match) { - float diff_t = self.s_time - match.s_time; - float sgn = diff_t > 0 ? 1 : -1; - float c_s = 0; - if (fabs(diff_t) > 1/154.0) { - c_s = corr_s + diff_t/2 + sgn * 1/77.0; - corr_s = corr_s ? corr_s * 0.7 + 0.3 * c_s : c_s; - } - self.oldorigin = match.oldorigin; // Mate up trails. self.p_time = match.p_time; if (CVARF(wpp_debug) & 1) { - printf(" p_diff = %0.3f / %0.3f t=%0.3f\n", + printf(" p_diff = %0.3f / %0.3f t=%0.3f, error_s = %0.3f\n", vlen(match.s_origin - self.s_origin), vlen(match.origin - self.origin), - vlen(match.origin - self.origin) / vlen(self.velocity)); - printf(" error=%0.4f c_s=%0.4f corr_s=%0.4f\n", diff_t, c_s, corr_s); + vlen(match.origin - self.origin) / vlen(self.velocity), + self.s_time - match.s_time); } PP_Cleanup(match); @@ -950,7 +927,6 @@ void InitProjPredEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; - ASSERTF_EQ(self.effects, 0); setmodelindex(self, fpp_types[self.fpp_index].modelindex); setsize(self, [0,0,0], [0,0,0]); diff --git a/share/commondefs.qc b/share/commondefs.qc index 71bd23ff..1105827e 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,3 +1,18 @@ +var struct { + float max_rewind_ms; + float max_rewind_slow_projectile_ms; + float max_rewind_fast_projectile_ms; + float rewind_fast_projectile_thresh; + float wp_default_min_ping_ms; + + float wp_global_enable; + float wp_global_disable; + float pp_global_enable; + float pp_global_disable; + float wpp_global_enable; + float wpp_global_disable; +} fo_config; + #define MAX_FLAGINFO_LINES 10 #define ENG_BUILDING_DISMANTLE_DISTANCE 100 #define ENG_BUILDING_MAINT_DISTANCE 80 diff --git a/share/prediction.qc b/share/prediction.qc index 62b7a4ef..214baf6a 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -9,21 +9,6 @@ string wp_version = "v0.2"; -var struct { - float max_rewind_slow_projectile_ms; - float max_rewind_fast_projectile_ms; - float rewind_fast_projectile_thresh; - float wp_default_min_ping_ms; - - float wp_global_enable; - float wp_global_disable; - float pp_global_enable; - float pp_global_disable; - float wpp_global_enable; - float wpp_global_disable; - -} fo_config; - enumflags { FOWP_CTIME, FOWP_IMPULSE, @@ -134,8 +119,8 @@ struct fo_projectile { }; fo_projectile fpp_types[] = { - { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "", SND_RL }, - { FPP_GRENADE, 600, "grenade.mdl", "t_grenade", SND_GREN }, + { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "", SND_RL }, + { FPP_GRENADE, 600, "grenade.mdl", "t_grenade", SND_GREN }, { FPP_INCENDIARY, 800, "lavaball.mdl", "t_lavaball", SND_RL }, { FPP_NAIL, 1500, "spike.mdl", "tr_spike", SND_NAIL }, { FPP_SUPER_NAIL, 1500, "s_spike.mdl", "tr_spike", SND_SNAIL }, @@ -144,7 +129,6 @@ fo_projectile fpp_types[] = { { FPP_RAILGUN, PC_ENGINEER_RAILSPEED, "e_spike1.mdl", "te_railtrail", SND_RAILGUN }, }; - void InitFppProjectiles() { float i; static int once; @@ -169,6 +153,12 @@ void InitFppProjectiles() { } } +float max_rewind_credit_ms(int fpp_type) { + return fpp_types[fpp_type].speed < fo_config.rewind_fast_projectile_thresh ? + fo_config.max_rewind_slow_projectile_ms : + fo_config.max_rewind_fast_projectile_ms; +} + #ifdef SSQC .predict_tf_state predict_state; @@ -421,7 +411,6 @@ void EntUpdate_Projectile(float isnew) { if (sendflags & FOPP_INIT) { COMM(Byte, fpp_index); - COMM(Short, effects); COMM(Angle, angles[0]); COMM(Angle, angles[1]); @@ -443,9 +432,9 @@ void EntUpdate_Projectile(float isnew) { void WeapPred_InitDefaultConfig() { fo_config.max_rewind_slow_projectile_ms = 100; - fo_config.max_rewind_fast_projectile_ms = 150; + fo_config.max_rewind_fast_projectile_ms = 100; fo_config.rewind_fast_projectile_thresh = 1500; - fo_config.wp_default_min_ping_ms = 45; + fo_config.wp_default_min_ping_ms = 40; } #ifdef SSQC @@ -569,6 +558,8 @@ void PredProj_Sound(float proj_type) { Pred_Sound(fpp_types[proj_type].snd); } +void WeaponPred_ProjectProjectile(int fpp_type, entity projectile); + void FOProj_Init(int fpp_type, entity mis) { // This init always needs to occur. mis.dimension_seen = DMN_NOFLASH; @@ -578,13 +569,15 @@ void FOProj_Init(int fpp_type, entity mis) { mis.modelindex = fpp_types[fpp_type].modelindex; setsize(mis, '0 0 0', '0 0 0'); - // Below here is only when we're using new projectile networking. - if (!fo_projectiles) - return; - mis.fpp_index = fpp_type; mis.s_origin = mis.origin; - mis.SendEntity = PP_SendEntity; - mis.SendFlags = 0xff; + mis.s_time = time; + + WeaponPred_ProjectProjectile(fpp_type, mis); + + if (fo_projectiles) { + mis.SendEntity = PP_SendEntity; + mis.SendFlags = 0xff; + } } #endif diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index dbb58679..7f701bb2 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,10 +1,19 @@ -void AL_ProjectProjectile (entity projectile) { - float time_offset = self.client_time - remote_client_time(CT_SLOW_PROJECTILE); +static float NoLanProject() { + if (self.client_ping <= 25) { + self.s_time = time; // Still need to potentially setup for networking + return TRUE; + } + return FALSE; +} - projectile.s_time = time - time_offset; - if (time_offset <= 13 * MSEC) // ping 13ms or lower? Don't do anything +void AL_ProjectProjectile (entity projectile) { + if (NoLanProject()) return; + float time_offset = + min(self.client_ping, fo_config.max_rewind_slow_projectile_ms) / 1000.0; + + projectile.s_time = time - time_offset; vector projected_origin = projectile.origin + (projectile.velocity * time_offset); // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED @@ -22,6 +31,22 @@ void AL_ProjectProjectile (entity projectile) { setorigin(projectile, projected_origin); } +void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { + if (NoLanProject()) + return; + + float max_credit = max_rewind_credit_ms(fpp_type); + float time_offset = min(self.client_ping, max_credit) / 1000.0; + + projectile.s_time = time - time_offset; + vector projected_origin = projectile.origin + (projectile.velocity * time_offset); + traceline(projectile.origin, projected_origin, 0, self); + + if (trace_fraction < 1) + projected_origin = trace_endpos; + + setorigin(projectile, projected_origin); +} #define DEBUG_ANTILAG 0 #ifndef DEBUG_ANTILAG diff --git a/ssqc/client.qc b/ssqc/client.qc index d2bcdfb5..bcefb192 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -605,8 +605,6 @@ void () DecodeLevelParms = { // remote_client_time max delta antilag_settings.rewind_detpipe = CF_GetSetting("alrd", "al_rewind_detpipe", "on"); - // maximum ping we'll have effect at - antilag_settings.max_ping = CF_GetSetting("almp", "al_max_ping", "200"); // CSQC projectiles fo_projectiles = CF_GetSetting("focp", "fo_csqc_projectiles", "on"); @@ -616,7 +614,6 @@ void () DecodeLevelParms = { // max projectile projection latency (default 100ms) project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); - antilag_settings.max_projectile_slow_ping = project_weapons_max_latency; // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f5733ab9..be050f24 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -105,9 +105,6 @@ void () W_FireRailgun = { setorigin(newmis, org + '0 0 16'); FOProj_Init(FPP_RAILGUN, newmis); - if (project_weapons) { - AL_ProjectProjectile(newmis); - } }; void () EMPExplode = { diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 4c5335fc..40da0cac 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -572,9 +572,6 @@ void () W_FireFlame = { setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); FOProj_Init(FPP_FLAMETHROWER, flame); - if (project_weapons) { - AL_ProjectProjectile(flame); - } }; void () IncendiaryRadius = { @@ -700,9 +697,6 @@ void () W_FireIncendiaryCannon = { setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); FOProj_Init(FPP_INCENDIARY, newmis); - if (project_weapons) { - AL_ProjectProjectile(newmis); - } }; void () AirBlastReloadFinished = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index dd9932ec..36bf214c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -5,17 +5,16 @@ typedef void (float n) f_void_float; enum { CT_NOEXTERNALEFFECT, // No external effects (e.g. reload, build, prime, etc) - CT_SLOW_PROJECTILE, // Projectile for which judder is noticable (e.g. rocket) + CT_SLOW_PROJECTILE, // Slow proj => more judder (e.g. rocket) + CT_FAST_PROJECTILE, // Fast proj => less judder (e.g. heavy bullet) }; struct antilag_settings_t { - float max_ping; - float max_projectile_slow_ping; float rewind_detpipe; } antilag_settings; .float client_time; // A stable/predictable client clock -.float client_ping; // ping used for prediction [capped] +.float client_ping; // ping used for prediction .float last_remote_client_time; // For monoticity .void() client_think; // client-time relative think diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 24d6835c..6d4465c1 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1092,9 +1092,6 @@ void () W_FireTranq = { setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); FOProj_Init(FPP_TRANQ, newmis); - if (project_weapons) { - AL_ProjectProjectile(newmis); - } }; void () T_TranqDartTouch = { diff --git a/ssqc/time.qc b/ssqc/time.qc index 30c29a22..a5e33494 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -1,13 +1,16 @@ float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT) { - float offset = self.client_ping; // Already bounded by max_ping + float offset = min(self.client_ping, fo_config.max_rewind_ms); switch (ct_type) { case CT_SLOW_PROJECTILE: - offset = min(offset, antilag_settings.max_projectile_slow_ping) / 2; + offset = min(offset, fo_config.max_rewind_slow_projectile_ms); + break; + case CT_FAST_PROJECTILE: + offset = min(offset, fo_config.max_rewind_fast_projectile_ms); break; } - float target = self.client_time - offset; + float target = self.client_time - offset / 1000.0; target = max(target, self.last_remote_client_time); // prevent jitter self.last_remote_client_time = target; @@ -39,6 +42,5 @@ void FO_CheckClientThink() { void FO_UpdateClientTime() { self.client_time += frametime; - float ping = infokeyf(self, INFOKEY_P_PING) / 1000.0; - self.client_ping = min(antilag_settings.max_ping, ping); + self.client_ping = infokeyf(self, INFOKEY_P_PING); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d97b8c60..233dfacf 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1081,17 +1081,13 @@ void () T_MissileTouch = { }; void () W_FireRocket = { - self.ammo_rockets = self.ammo_rockets - 1; - KickPlayer(-2, self); - newmis = spawn(); newmis.owner = self; newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_BBOX; makevectors(self.v_angle); - newmis.velocity = v_forward; - newmis.velocity = newmis.velocity * fpp_types[FPP_ROCKET].speed; + newmis.velocity = v_forward * fpp_types[FPP_ROCKET].speed; newmis.angles = vectoangles(newmis.velocity); newmis.touch = T_MissileTouch; @@ -1102,14 +1098,12 @@ void () W_FireRocket = { newmis.weapon = DMSG_ROCKETL; newmis.classname = "proj_rocket"; - FO_SetModel(newmis, fpp_types[FPP_ROCKET].model); - setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); FOProj_Init(FPP_ROCKET, newmis); - if (project_weapons) { - AL_ProjectProjectile(newmis); - } + + self.ammo_rockets = self.ammo_rockets - 1; + KickPlayer(-2, self); }; void (entity from, float damage) LightningHit = { @@ -1359,9 +1353,6 @@ entity (int fpp_type, vector offset) W_FireNail = { } FOProj_Init(fpp_type, newmis); - if (project_weapons) { - AL_ProjectProjectile(newmis); - } return newmis; }; From 4a59df1fffb6638295e9e167ade2c2f74fdcc1e3 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 25 Oct 2022 12:35:20 -0700 Subject: [PATCH 1834/2474] Introduce PRNG types and cleanup - To avoid pertubartion when one thing is simulated perfectly and another not, introduce indexed PRNGs so that each action can be independent. - Add support for specifying volume to predicted sounds - Add missing max_rewind_ms to config updates and clamp by it + sane max/mins. - Fix predicted melee animation choice w/ new RNG --- csqc/weapon_predict.qc | 40 +++++++++++--------- share/defs.h | 6 +++ share/prediction.qc | 83 ++++++++++++++++++++++++------------------ ssqc/client.qc | 6 +++ ssqc/qw.qc | 2 + ssqc/weapons.qc | 6 +-- 6 files changed, 86 insertions(+), 57 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 64203ae3..2307d74c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -148,6 +148,7 @@ void WPP_Status() { printf(" inst_ping = %d avg_ping = %d var = %d\n", ping, avg, variance); printf("Config:\n"); + PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); @@ -227,6 +228,9 @@ static float IsEffectFrame() { return TRUE; } +void Attack_Finished(float attack_time) { + pstate_pred.attack_finished = pstate_pred.client_time + attack_time; +} //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// @@ -235,17 +239,20 @@ float animate_s_time; static entity pred_sound_entity; static float last_pred_sound; -void Pred_Sound(int snd) { +void Pred_Sound(int snd, float vol = 1) { if (pstate_pred.tfstate & TFSTATE_FLASHED) return; + if (!IsEffectFrame()) + return FALSE; + last_pred_sound = time; setorigin(pred_sound_entity, pmove_org); - sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, 1, ATTN_NORM); + sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, vol, ATTN_NORM); } -void PredProj_Sound(int proj_type) { - Pred_Sound(fpp_types[proj_type].snd); +void PredProj_Sound(int proj_type, float vol = 1) { + Pred_Sound(fpp_types[proj_type].snd, vol); } inline FO_WeapInfo* WP_CurrentWeapon() { @@ -475,12 +482,7 @@ float WP_ConsumeAmmo(FO_WeapInfo* wi) { return TRUE; } -static void prandom(void() option1, void() option2) { - if (shared_prng(self) < 0.5) - option1(); - else - option2(); -} +var void() melee_anim = player_axeN; void WP_AnimateModel() { if (pstate_pred.client_thinkindex == 0) { @@ -509,13 +511,11 @@ void WP_AnimateModel() { player_nailN(); break; case WEAP_AXE: - prandom(player_axeN, player_axebN); break; case WEAP_KNIFE: - prandom(player_knifeN, player_knifebN); break; case WEAP_MEDIKIT: - prandom(player_medikitN, player_medikitbN); break; + melee_anim(); break; case WEAP_SPANNER: - player_spannerN(); break; + player_axe1(); break; } } @@ -783,7 +783,6 @@ void PP_CreateProjectile(int proj_type, vector offset) { } void PP_AssCanFrame() { - } void PP_NailFrame() { @@ -796,7 +795,7 @@ void PP_NailFrame() { FO_WeapInfo* wi = WP_CurrentWeapon(); WP_ConsumeAmmo(wi); - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + Attack_Finished(wi->attack_time); float idx = (pstate_pred.client_thinkindex + 1) % 2; @@ -847,21 +846,26 @@ void WP_Attack() { case WEAP_RAILGUN: PP_CreateProjectile(FPP_RAILGUN, '0 0 0'); break; + case WEAP_GRENADE_LAUNCHER: case WEAP_PIPE_LAUNCHER: Pred_Sound(SND_GREN); break; + case WEAP_AXE: case WEAP_KNIFE: - case WEAP_SPANNER: case WEAP_MEDIKIT: + melee_anim = shared_prng(PRNG_AXE) < 0.5 ? player_axeN : player_axebN; + // Fall through for sound. + case WEAP_SPANNER: Pred_Sound(SND_AXE); break; + case WEAP_SHOTGUN: Pred_Sound(SND_SG); break; case WEAP_SUPER_SHOTGUN: Pred_Sound(SND_SSG); break; } } if (!in_anim) - pstate_pred.attack_finished = pstate_pred.client_time + wi->attack_time; + Attack_Finished(wi->attack_time); #if 0 // If our latency is higher than forward projection, synchronize animation diff --git a/share/defs.h b/share/defs.h index 23173516..91d94e9d 100644 --- a/share/defs.h +++ b/share/defs.h @@ -269,6 +269,12 @@ enumflags { #define TFSTATE_AC_MASK (TFSTATE_AC_SPINUP|TFSTATE_AC_SPINNING|TFSTATE_AC_SPINDOWN) +enum { + PRNG_AXE, + PRNG_HWGUY, + PRNG_NUM_STATES, +}; + // Defines used by TF_T_Damage (see combat.qc) #define TF_TD_IGNOREARMOR 1 // Bypasses the armor of the target #define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) diff --git a/share/prediction.qc b/share/prediction.qc index 214baf6a..705909cf 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -54,7 +54,7 @@ struct predict_tf_state { float reload_finished; float clip_fired[4]; - int lfsr_state; + int prng_base[PRNG_NUM_STATES]; // Used for prediction, not actually communicated. Reset each frame. @@ -164,8 +164,6 @@ float max_rewind_credit_ms(int fpp_type) { .predict_tf_state predict_state; .entity predict_entity; -.float client_nextthink; -.float client_thinkindex; #else struct pengine_t { @@ -192,23 +190,25 @@ predict_tf_state pstate_pred, pstate_server; #endif #ifdef SSQC -.int lfsr_state; // Shared random number generator -static inline int get_lfsr_state(entity pl) { return pl.lfsr_state; } -static inline void set_lfsr_state(entity pl, int v) { pl.lfsr_state = v; } +inline int* prng_state(int type) { return &self.prng_base[type]; } #else -static inline int get_lfsr_state(entity pl) { return pstate_pred.lfsr_state; } -static inline void set_lfsr_state(entity pl, int v) { pstate_pred.lfsr_state = v; } +inline int* prng_state(int type) { return &pstate_pred.prng_base[type]; } #endif -float shared_prng(entity pl) { // A 16-bit xor-shift LFSR. - int v = get_lfsr_state(pl); +int lfsr_prng_raw(int v) { // A 16-bit xor-shift LFSR. v ^= (v >> 7); v ^= (v << 9); v &= 65535; v ^= (v >> 13); - set_lfsr_state(pl, v); + return v; +} + +float lsfr_prng(int prev) { + return lfsr_prng_raw(prev) / 65535.0; +} - return (float)v / 65535.0; +float shared_prng(int type) { + return (*prng_state(type) = lfsr_prng_raw(*prng_state(type))) / 65535.0; } #ifdef SSQC @@ -244,7 +244,7 @@ void WeaponPred_Update(entity player) { M2(FOWP_THINK, client_nextthink, client_thinkindex); M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) M1(FOWP_RELOAD, reload_finished) - M1(FOWP_RNG, lfsr_state) + M2(FOWP_RNG, prng_base[0], prng_base[1]) player.predict_entity.SendFlags = mask; } @@ -288,6 +288,7 @@ float WP_SendConfig(entity to_player, float sendflags) { #define COMM(_type, _field) fo_config.##_field = Read##_type() void EntUpdate_Config() { #endif + COMM(Float, max_rewind_ms); COMM(Float, max_rewind_slow_projectile_ms); COMM(Float, max_rewind_fast_projectile_ms); COMM(Float, rewind_fast_projectile_thresh); @@ -366,8 +367,10 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_RELOAD) COMM(Float, reload_finished); - if (sendflags & FOWP_RNG) - COMM(Float, lfsr_state); + if (sendflags & FOWP_RNG) { + COMM(Float, prng_base[0]); + COMM(Float, prng_base[1]); + } #ifdef SSQC return TRUE; @@ -431,6 +434,7 @@ void EntUpdate_Projectile(float isnew) { #undef COMM void WeapPred_InitDefaultConfig() { + fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 100; fo_config.max_rewind_fast_projectile_ms = 100; fo_config.rewind_fast_projectile_thresh = 1500; @@ -441,32 +445,38 @@ void WeapPred_InitDefaultConfig() { entity config_entity; -#define CONFIG_UPDATE(_fl, _ps_short, _field) \ +#define CONFIG_UPDATE(_ps_short, _field) \ do { string _cur = ftos(fo_config.##_field); \ float _val = CF_GetSetting(_ps_short, #_field, _cur); \ if (_val != fo_config.##_field) { \ - fo_config.##_field = _val; _fl = TRUE; \ + fo_config.##_field = _val; update = TRUE; \ } \ } while (0) +#define CLAMP_UPDATE(_field, _clamp_low, _clamp_high) \ + do { if (fo_config.##_field < _clamp_low || fo_config.##_field > _clamp_high) { \ + fo_config.##_field = max(min(fo_config.##_field, _clamp_high), _clamp_low); \ + update = TRUE; \ + } } while (0) static void WeaponPred_CheckConfigUpdate() { float update = FALSE; // Target is also the long form localinfo name. - CONFIG_UPDATE(update, "mrsp", max_rewind_slow_projectile_ms); - CONFIG_UPDATE(update, "mrfp", max_rewind_fast_projectile_ms); - CONFIG_UPDATE(update, "rfpt", rewind_fast_projectile_thresh); - CONFIG_UPDATE(update, "wpdmp", wp_default_min_ping_ms); - CONFIG_UPDATE(update, "wpge", wp_global_enable); - CONFIG_UPDATE(update, "wpgd", wp_global_disable); - CONFIG_UPDATE(update, "ppge", pp_global_enable); - CONFIG_UPDATE(update, "ppgd", pp_global_disable); - CONFIG_UPDATE(update, "wppge", wpp_global_enable); - CONFIG_UPDATE(update, "wppge", wpp_global_disable); - - if (update) - print("saw update! %d", fo_config.wp_global_disable); - + CONFIG_UPDATE("mrt", max_rewind_ms); + CONFIG_UPDATE("mrsp", max_rewind_slow_projectile_ms); + CONFIG_UPDATE("mrfp", max_rewind_fast_projectile_ms); + CONFIG_UPDATE("rfpt", rewind_fast_projectile_thresh); + CONFIG_UPDATE("wpdmp", wp_default_min_ping_ms); + CONFIG_UPDATE("wpge", wp_global_enable); + CONFIG_UPDATE("wpgd", wp_global_disable); + CONFIG_UPDATE("ppge", pp_global_enable); + CONFIG_UPDATE("ppgd", pp_global_disable); + CONFIG_UPDATE("wppge", wpp_global_enable); + CONFIG_UPDATE("wppge", wpp_global_disable); + + CLAMP_UPDATE(max_rewind_ms, 0, 250); + CLAMP_UPDATE(max_rewind_slow_projectile_ms, 0, fo_config.max_rewind_ms); + CLAMP_UPDATE(max_rewind_fast_projectile_ms, 0, fo_config.max_rewind_ms); static float last_force_refresh; if (time > last_force_refresh + 5) { @@ -478,6 +488,7 @@ static void WeaponPred_CheckConfigUpdate() { config_entity.SendFlags = 1; config_entity.nextthink = time + 0.25; }; +#undef CLAMP_UPDATE #undef CONFIG_UPDATE void WeaponPred_Init() { @@ -542,7 +553,7 @@ void WeaponPred_DoServerClientThink() { void FO_Sound(entity e, float chan, string samp, float vol, float atten); -void Pred_Sound(float snd) { +void Pred_Sound(int snd, float vol = 1) { entity target = self; string wav = snd_types[snd].sound; @@ -551,11 +562,11 @@ void Pred_Sound(float snd) { setorigin(target, self.origin); } - FO_Sound(target, CHAN_WEAPON, wav, 1, ATTN_NORM); + FO_Sound(target, CHAN_WEAPON, wav, vol, ATTN_NORM); } -void PredProj_Sound(float proj_type) { - Pred_Sound(fpp_types[proj_type].snd); +void PredProj_Sound(int proj_type, float vol = 1) { + Pred_Sound(fpp_types[proj_type].snd, vol); } void WeaponPred_ProjectProjectile(int fpp_type, entity projectile); @@ -577,7 +588,7 @@ void FOProj_Init(int fpp_type, entity mis) { if (fo_projectiles) { mis.SendEntity = PP_SendEntity; - mis.SendFlags = 0xff; + mis.SendFlags = FOPP_POS | FOPP_INIT; } } #endif diff --git a/ssqc/client.qc b/ssqc/client.qc index bcefb192..63a6d9dc 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2072,6 +2072,12 @@ void () PutClientInServer = { FO_InstantReloadAllWeapons(self); + // Only need initial init here. + if (!self.prng_base[PRNG_AXE]) + self.prng_base[PRNG_AXE] = 65535 * random(); + // For hwguy we rotate the seed value, each seed generates many random nums. + self.prng_base[PRNG_HWGUY] = 65535 * random(); + self.immune_to_check = time + 10; self.fire_held_down = 0; SetDimensions(TRUE); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 36bf214c..2d083779 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -21,6 +21,8 @@ struct antilag_settings_t { .float client_thinkindex; .float client_nextthink; +.int prng_base[PRNG_NUM_STATES]; + // A monotonically non-decreasing, latency corrected notion of remote // client-time. Monotonicity guarantees that for some offset `o`: // at t1: remote_client_time() + o < at t2: lag_time() + o FOR t2 > t1 diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 233dfacf..69385a4e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1635,13 +1635,13 @@ void () W_Attack = { if (ws.weapon == WEAP_AXE) { Pred_Sound(SND_AXE); - if (shared_prng(self) < 0.5) + if (shared_prng(PRNG_AXE) < 0.5) player_axe1(); else player_axeb1(); } else if (ws.weapon == WEAP_KNIFE) { Pred_Sound(SND_AXE); - if (shared_prng(self) < 0.5) + if (shared_prng(PRNG_AXE) < 0.5) player_knife1(); else player_knifeb1(); @@ -1717,7 +1717,7 @@ void () W_Attack = { } } else if (ws.weapon == WEAP_MEDIKIT) { Pred_Sound(SND_AXE); - if (shared_prng(self) < 0.5) + if (shared_prng(PRNG_AXE) < 0.5) player_medikit1(); else player_medikitb1(); From c50960b864419240a80e9f2b937ace2e9f25e798 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 27 Oct 2022 01:16:33 -0700 Subject: [PATCH 1835/2474] Simplify trails and fix missing setmodelindex --- csqc/weapon_predict.qc | 20 ++++++++++---------- share/prediction.qc | 5 +++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2307d74c..cfc0e773 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -647,6 +647,7 @@ DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); +.float trail_started; float PP_PredrawActive() { float delta = time - self.s_time; @@ -661,11 +662,11 @@ float PP_PredrawActive() { self.oldorigin = trace_endpos; return PREDRAW_NEXT; } - } - if (self.traileffectnum) + if (self.traileffectnum && self.trail_started) trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); + self.trail_started = TRUE; self.p_time = time + frametime; self.oldorigin = self.origin; } @@ -708,11 +709,10 @@ int PP_FindTrail(entity e) } static float PP_EPS = 0.05; -DEFCVAR_FLOAT(pp_trail_start, 20); static inline void PP_InitTrail(entity proj) { - proj.oldorigin = proj.s_origin + CVARF(pp_trail_start) * MSEC * proj.velocity; - proj.p_time = time + CVARF(pp_trail_start * MSEC); + proj.p_time = proj.s_time + 1/77.0; + proj.oldorigin = proj.s_origin; proj.traileffectnum = PP_FindTrail(proj); } @@ -755,7 +755,7 @@ void PP_CreateProjectile(int proj_type, vector offset) { // Note: We use true time here as created projectiles exist outside of pred. proj.s_time = time + PP_StartOffset(proj_type); - proj.starttime = max(time + CVARF(pp_trail_start) * MSEC, proj.s_time); + proj.starttime = proj.s_time; proj.endtime = time + pstate_pred.client_ping / 1000.0 + PP_EPS; proj.predraw = PP_PredrawPredicted; @@ -773,6 +773,8 @@ void PP_CreateProjectile(int proj_type, vector offset) { if (self.fpp_index == FPP_ROCKET && CVARF(cl_r2g) == 1) setmodelindex(proj, fpp_types[FPP_GRENADE].modelindex); + else + setmodelindex(proj, fpp_types[proj.fpp_index].modelindex); PP_InitTrail(proj); @@ -911,6 +913,7 @@ float PredProjectile_MatchProjectile() { if (match) { self.oldorigin = match.oldorigin; // Mate up trails. self.p_time = match.p_time; + self.trail_started = match.trail_started; if (CVARF(wpp_debug) & 1) { printf(" p_diff = %0.3f / %0.3f t=%0.3f, error_s = %0.3f\n", @@ -927,16 +930,13 @@ float PredProjectile_MatchProjectile() { } // Called on `self`. -void InitProjPredEnt() { +void InitProjectileEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; setmodelindex(self, fpp_types[self.fpp_index].modelindex); setsize(self, [0,0,0], [0,0,0]); - self.oldorigin = self.s_origin + CVARF(pp_trail_start) * MSEC * self.velocity; - self.p_time = time + CVARF(pp_trail_start) * MSEC; - if (CVARF(cl_r2g) && self.fpp_index == FPP_ROCKET) setmodelindex(self, fpp_types[FPP_GRENADE].modelindex); diff --git a/share/prediction.qc b/share/prediction.qc index 705909cf..80bbe824 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -274,7 +274,7 @@ float() ReadFloat = #367; void InitWeapPredEnt(entity e); void WP_ServerUpdate(); -void InitProjPredEnt(); +void InitProjectileEnt(); void WPP_UpdateEnable(float force); .float owner_entnum; @@ -426,7 +426,7 @@ void EntUpdate_Projectile(float isnew) { #else self.owner_entnum = readentitynum(); if (isnew) - InitProjPredEnt(); + InitProjectileEnt(); #endif } #undef COMMD @@ -586,6 +586,7 @@ void FOProj_Init(int fpp_type, entity mis) { WeaponPred_ProjectProjectile(fpp_type, mis); + // Below is conditional on using custom SendEntity. if (fo_projectiles) { mis.SendEntity = PP_SendEntity; mis.SendFlags = FOPP_POS | FOPP_INIT; From d6ff047a9e0333e0a5c0952cb409875098d1ef9b Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 25 Oct 2022 17:22:46 -0700 Subject: [PATCH 1836/2474] Unify nailguns between server and client Unifies the implementation of both server and client nailguns so that weapon prediction and actual server side just use the same implementation. Guaranteeing matching. Remove legacy old_ng_rof. --- csqc/weapon_predict.qc | 118 ++++++++++++++++++++++++----------------- share/animate.qc | 67 +++++++++++------------ share/prediction.qc | 1 - share/weapons.qc | 9 ---- ssqc/client.qc | 6 --- ssqc/qw.qc | 2 - 6 files changed, 102 insertions(+), 101 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index cfc0e773..43b76f3a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -274,7 +274,43 @@ inline float WP_IsReloading() { return pstate_pred.tfstate & TFSTATE_RELOADING; } -float WP_CheckAmmo(FO_WeapInfo* wi); +static float AmmoToStat(float ammo_type) { + switch (ammo_type) { + case AMMO_SHELLS: return STAT_SHELLS; + case AMMO_ROCKETS: return STAT_ROCKETS; + case AMMO_NAILS: return STAT_NAILS; + case AMMO_CELLS: return STAT_CELLS; + } + return STAT_AMMO; +} + +float WP_GetAmmo(float ammo_type) { + if (!WP_Enabled()) + return getstatf(AmmoToStat(ammo_type)); + + if (ammo_type == AMMO_NONE) + return 0; + + float base = getstatf(AmmoToStat(ammo_type)); + base -= pstate_pred.ammo_used[ammo_type]; + return max(0, base); +} + +float WP_CurrentAmmo() { + if (!WP_Enabled()) + return getstatf(STAT_AMMO); + + return WP_GetAmmo(WP_CurrentWeapon()->ammo_type); +} + + +float WP_CheckAmmo(FO_WeapInfo* wi) { + if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) + return TRUE; + + int ammo = WP_GetAmmo(wi->ammo_type); + return ammo > wi->ammo_per_shot; +} void WP_ChangeWeapon(Slot slot) { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); @@ -287,6 +323,27 @@ void WP_ChangeWeapon(Slot slot) { // UpdateViewModel will propagate. } +Slot WP_BestWeaponSlot() { + for (float i = 1; i <= TF_NUM_SLOTS; i++) { + Slot slot = MakeSlot(i); + FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + + if (wi->weapon == WEAP_ASSAULT_CANNON && WP_GetAmmo(AMMO_CELLS) < 7) + continue; + + if (wi->weapon == WEAP_NONE || !WP_CheckAmmo(wi)) + continue; + + return slot; + } + + return SlotMelee; +} + +void W_ChangeToBestWeapon() { + WP_ChangeWeapon(WP_BestWeaponSlot()); +} + void WP_Reload(); void WP_Impulse() { @@ -294,6 +351,7 @@ void WP_Impulse() { float match = TRUE; float quick_swap = FALSE; + switch (pstate_pred.impulse) { case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: pstate_pred.impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. @@ -335,7 +393,7 @@ void WP_Impulse() { if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) return; - if (!IsSlotNull(pstate_pred.queue_slot) && !pstate_pred.firing) { + if (!IsSlotNull(pstate_pred.queue_slot)) { WP_ChangeWeapon(pstate_pred.queue_slot); pstate_pred.queue_slot = SlotNull; } @@ -354,35 +412,6 @@ void WP_Impulse() { pstate_pred.impulse = 0; } -static float AmmoToStat(float ammo_type) { - switch (ammo_type) { - case AMMO_SHELLS: return STAT_SHELLS; - case AMMO_ROCKETS: return STAT_ROCKETS; - case AMMO_NAILS: return STAT_NAILS; - case AMMO_CELLS: return STAT_CELLS; - } - return STAT_AMMO; -} - -float WP_GetAmmo(float ammo_type) { - if (!WP_Enabled()) - return getstatf(AmmoToStat(ammo_type)); - - if (ammo_type == AMMO_NONE) - return 0; - - float base = getstatf(AmmoToStat(ammo_type)); - base -= pstate_pred.ammo_used[ammo_type]; - return max(0, base); -} - -float WP_CurrentAmmo() { - if (!WP_Enabled()) - return getstatf(STAT_AMMO); - - return WP_GetAmmo(WP_CurrentWeapon()->ammo_type); -} - static float* WP_ClipFired() { float index = SlotIndex(pstate_pred.current_slot); if (pstate_pred.playerclass == PC_DEMOMAN && @@ -414,7 +443,6 @@ string WP_GetClip() { return sprintf("%d/%d", clip, wi->clip_size); } - void WP_Reload() { FO_WeapInfo* wi = WP_CurrentWeapon(); @@ -451,14 +479,6 @@ void WP_CheckReloadFinished() { } } -float WP_CheckAmmo(FO_WeapInfo* wi) { - if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) - return TRUE; - - int ammo = WP_GetAmmo(wi->ammo_type); - return ammo > wi->ammo_per_shot; -} - float WP_ReloadIfNeeded(FO_WeapInfo* wi) { if (!WP_CheckAmmo(wi) || wi->needs_reload) { if (*WP_ClipFired() >= wi->clip_size) { @@ -787,28 +807,26 @@ void PP_CreateProjectile(int proj_type, vector offset) { void PP_AssCanFrame() { } -void PP_NailFrame() { - if (input_buttons & BUTTON0 == 0) { - player_run(); +void (float ox) W_FireSpikes = { + FO_WeapInfo* wi = WP_CurrentWeapon(); + + if (!WP_CheckAmmo(wi)) { + W_ChangeToBestWeapon(); return; } - pstate_pred.firing = TRUE; - - FO_WeapInfo* wi = WP_CurrentWeapon(); WP_ConsumeAmmo(wi); Attack_Finished(wi->attack_time); - float idx = (pstate_pred.client_thinkindex + 1) % 2; - if (!IsEffectFrame()) return; if (wi->weapon == WEAP_NAILGUN) - PP_CreateProjectile(FPP_NAIL, v_right * (idx ? 4: - 4)); + PP_CreateProjectile(FPP_NAIL, ox * v_right); else PP_CreateProjectile(FPP_SUPER_NAIL, '0 0 0'); -} + +}; void WP_Attack() { Slot slot = pstate_pred.current_slot; diff --git a/share/animate.qc b/share/animate.qc index 432590f0..f220b8cb 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -11,13 +11,11 @@ void think_nop() {} #ifdef SSQC -void nail_extra(); void asscan_up_extra(); void asscan_fire_extra(); void asscan_down_extra(); void W_PrintWeaponMessage(); void W_ChangeToBestWeapon(); -void W_FireSpikes(float ox); void W_FireAssaultCannon(); int W_FireAxe(); int W_FireKnife(); @@ -33,6 +31,9 @@ void player_asscan_fire(); void player_asscan_down1(); inline void *thinkindex() { return &self.client_thinkindex; } +static inline float has_button0() { return self.button0; } +static inline float is_intermission() { return intermission_running; } + void FO_SetClientThink(void() func, float offset, float override = TRUE) { self.think = think_nop; @@ -100,20 +101,6 @@ static void axe_extra() { self.hit_in_current_animation = FALSE; } -void nail_extra() { - if (!self.button0 || intermission_running) { - player_run(); - return; - } - - float idx = (self.client_thinkindex - 1) % 2; - if (idx == 0 || !old_ng_rof) { - SuperDamageSound(); - W_FireSpikes(idx ? 4 : -4); - self.nailpos = 1 - self.nailpos; - } -} - static float CheckNeedAssaultCannonDown() { FO_WeapState ws; FO_FillWeapState(self, MakeSlot(1), &ws); @@ -243,20 +230,35 @@ void player_stand1() { #else /* CSQC */ static inline void *thinkindex() { return &pstate_pred.client_thinkindex; } +static inline float has_button0() { return input_buttons & BUTTON0; } +static inline float is_intermission() { return intermission; } +static void SuperDamageSound() {} // TODO void FO_SetClientThink(void() func, float offset, float override = TRUE) { pstate_pred.client_nextthink = pstate_pred.client_time + offset; } void player_run() { - pstate_pred.firing = FALSE; pstate_pred.client_nextthink = 0; pstate_pred.client_thinkindex = 0; pstate_pred.weaponframe = 0; } +// When `extra()` is specified, it is responsible ending looped animations. +// [ Typically because +attack (button0) has been released. ] void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - float tidx = (*thinkindex())++ - 1; + float tidx = *thinkindex()++ - 1; + + float loop = anim->loop; + if (loop && extra == think_nop && !(input_buttons & BUTTON0)) + loop = TRUE; + + if (tidx > anim->num_frames - 1 && !loop) { + player_run(); + return; + } else { + pstate_pred.client_nextthink = pstate_pred.client_time + 0.1; + } float fi = tidx % anim->num_frames; float wfi = tidx % anim->num_wf; @@ -264,31 +266,31 @@ void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { float wf = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; pstate_pred.weaponframe = wf; - float loop = anim->loop && (input_buttons & BUTTON0); - - if (tidx > anim->num_frames - 1 && !loop) { - // Special case for CSQC since we could predict through the wrap. - player_run(); - } else if (fi == anim->num_frames - 1 && !loop) { - FO_SetClientThink(player_run, 0.1); - } else - FO_SetClientThink(parent_thunk, 0.1); - if (extra != think_nop) extra(); } static void axe_extra() {} -void PP_NailFrame(); -void nail_extra() { PP_NailFrame(); } - static void asscan_up_extra() {} static void asscan_fire_extra() {} static void asscan_down_extra() {} #endif +void W_FireSpikes(float ox); +// Shared by both client and server side. +void nail_extra_csqc_ssqc() { + if (!has_button0() || is_intermission()) { + player_run(); + return; + } + + float tidx = *thinkindex() % 2; // 1 based, and incremented. + SuperDamageSound(); + W_FireSpikes(tidx ? 4 : -4); +} + anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } void player_rocket1() { *thinkindex() = 1; player_rocketN(); } @@ -297,7 +299,6 @@ anim_t anim_shotgun = { 6, 6, {113}, {1}, TRUE }; void player_shotN() { client_anim_frames(player_shotN, think_nop, &anim_shotgun); } void player_shot1() { *thinkindex() = 1; player_shotN(); } - anim_t anim_autorifle = { 3, 3, {113, 114, 118}, {1, 2, 6}, TRUE }; void player_autorifleN() { client_anim_frames(player_autorifleN, think_nop, &anim_autorifle); } void player_autorifle1() { *thinkindex() = 1; player_autorifleN(); } @@ -326,7 +327,7 @@ void player_medikitbN() { client_anim_frames(player_medikitbN, axe_extra, &anim_ void player_medikitb1() { *thinkindex() = 1; player_medikitbN(); } anim_t anim_nailgun = { 2, 8, {103, 104}, {1}, TRUE, TRUE }; -void player_nailN() { client_anim_frames(player_nailN, nail_extra, &anim_nailgun); } +void player_nailN() { client_anim_frames(player_nailN, nail_extra_csqc_ssqc, &anim_nailgun); } void player_nail1() { *thinkindex() = 1; player_nailN(); } anim_t anim_flamethrower = { 6, 6, {113}, {1}, TRUE, FALSE }; diff --git a/share/prediction.qc b/share/prediction.qc index 80bbe824..9738aa70 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -59,7 +59,6 @@ struct predict_tf_state { // Used for prediction, not actually communicated. Reset each frame. float ammo_used[AMMO_NUM_TYPES]; - float firing; }; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; diff --git a/share/weapons.qc b/share/weapons.qc index 4ccce7f2..8d565109 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -15,7 +15,6 @@ float fo_hwguy = TRUE; float sniperreload = FALSE; float pyro_type = PYRO_FO; -float old_ng_rof = FALSE; #endif // Some preprocessor bug is making __LINE__ not substitute right here most of @@ -632,14 +631,6 @@ void FO_Weapons_Init() { WI_ir->attack_time = 0.9; break; } - // Consider just removing this? - if (old_ng_rof) { - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_NAILGUN); - wi->ammo_per_shot = 2; - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); - wi->ammo_per_shot = 4; - } - for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; ASSERTD_EQ(WEAP_to_index(wi->weapon), i); diff --git a/ssqc/client.qc b/ssqc/client.qc index 63a6d9dc..d4b2b2b9 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -635,9 +635,6 @@ void () DecodeLevelParms = { ng_damage = CF_GetSetting("ngd", "ng_damage", "9"); sng_damage = CF_GetSetting("sngd", "sng_damage", "13"); - // use old ROF for nailguns - old_ng_rof = CF_GetSetting("ongrof", "old_ng_rof", "off"); - // allow axe to hit on any frame of animation superaxe = CF_GetSetting("ss", "superaxe", "on"); @@ -866,7 +863,6 @@ void () DecodeLevelParms = { sniperreloadpercent = TRUE; buildstatus = TRUE; old_hp_armor = FALSE; - old_ng_rof = FALSE; superaxe = TRUE; supermedikit = TRUE; superspanner = FALSE; @@ -948,7 +944,6 @@ void () DecodeLevelParms = { superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; - old_ng_rof = TRUE; pyro_type = PYRO_ORIGINAL; Role_None.gren1_limits[1] = 4; Role_None.gren1_limits[2] = 4; @@ -986,7 +981,6 @@ void () DecodeLevelParms = { superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; - old_ng_rof = TRUE; scoutdash = FALSE; fo_flash = FALSE; nailgren_type = NGR_TYPE_NAIL; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 2d083779..5396ef1b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -433,7 +433,6 @@ float already_chosen_map; // flash grenade level .float FlashTime; -.float nailpos; // anti spam .float antispam_detpack; // don't spam detpack messages @@ -619,7 +618,6 @@ float supermedikit; float superspanner; float superknife; float superknife_multihit; -float old_ng_rof; float impulse_queue; float detpack_when_reloading; float pyro_type; From 154449ba162c73d7b933613de2b40a66544560d2 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 15 Oct 2022 02:41:11 -0700 Subject: [PATCH 1837/2474] Client-side assault cannon Full rewrite of assault cannon code, including the interactions with the impulse loop (no more fire_held_down). Introduces a client-side implementation which is fully shared with the server implementation, including synchronized random numbers so that we can generate client side projectiles for the random spray correctly. Removes a bunch of legacy options (e.g. there is now only fo_hwguy). --- csqc/hud.qc | 2 +- csqc/weapon_predict.qc | 100 ++++++++++++++++--- share/animate.qc | 222 ++++++++++++++++++++++------------------- share/defs.h | 12 ++- share/prediction.qc | 103 +++++++++++++++++-- share/weapons.qc | 5 +- ssqc/client.qc | 22 ++-- ssqc/hwguy.qc | 113 +++++---------------- ssqc/qw.qc | 2 - ssqc/weapons.qc | 36 +++---- ssqc/world.qc | 1 - 11 files changed, 352 insertions(+), 266 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 6245acc8..03e93c24 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -969,7 +969,7 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } break; case PC_HVYWEAP: - if (SBAR.LockedCannon) + if (WP_LockedCannon()) { icon = ICON_HWGUY; //HudIcons[playerclass+6].icon; drawpic(pos, icon, size, '1 1 1', 1, 0); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 43b76f3a..93c6b3ee 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -239,15 +239,15 @@ float animate_s_time; static entity pred_sound_entity; static float last_pred_sound; -void Pred_Sound(int snd, float vol = 1) { - if (pstate_pred.tfstate & TFSTATE_FLASHED) +void Pred_Sound(SoundIndex snd, float vol = 1) { + if (snd == SND_NONE || !IsEffectFrame() || pstate_pred.tfstate & TFSTATE_FLASHED) return; - if (!IsEffectFrame()) - return FALSE; - + ASSERTD_GE(snd, SND_FIRST); + snd -= SND_FIRST; last_pred_sound = time; setorigin(pred_sound_entity, pmove_org); + /* sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, vol, ATTN_NORM); */ sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, vol, ATTN_NORM); } @@ -346,8 +346,36 @@ void W_ChangeToBestWeapon() { void WP_Reload(); +float WP_LockedCannon() { + if (!WP_Enabled()) + return SBAR.LockedCannon; + return pstate_pred.tfstate & TFSTATE_LOCK; +} + +static void WP_HandleHeavyInputs() { + if (pstate_pred.playerclass != PC_HVYWEAP) + return; + + // +special toggles lock. + if (pstate_pred.buttons_down & BUTTON3) + pstate_pred.tfstate ^= TFSTATE_LOCK; + + float match = TRUE; + switch (pstate_pred.impulse) { + case TF_LOCKON: pstate_pred.tfstate |= TFSTATE_LOCK; break; + case TF_LOCKOFF: pstate_pred.tfstate &= ~TFSTATE_LOCK; break; + case TF_SPECIAL_SKILL: pstate_pred.tfstate ^= TFSTATE_LOCK; break; + default: + match = FALSE; + } + + if (match) + pstate_pred.impulse = 0; +} + void WP_Impulse() { // Note: We might have no impulse, but a queued slot here. + WP_HandleHeavyInputs(); float match = TRUE; float quick_swap = FALSE; @@ -412,7 +440,7 @@ void WP_Impulse() { pstate_pred.impulse = 0; } -static float* WP_ClipFired() { +float* WP_ClipFired() { float index = SlotIndex(pstate_pred.current_slot); if (pstate_pred.playerclass == PC_DEMOMAN && index == 1) @@ -530,12 +558,16 @@ void WP_AnimateModel() { case WEAP_SUPER_NAILGUN: player_nailN(); break; + case WEAP_ASSAULT_CANNON: + player_assault_cannon(); + break; + case WEAP_AXE: case WEAP_KNIFE: case WEAP_MEDIKIT: melee_anim(); break; case WEAP_SPANNER: - player_axe1(); break; + player_axeN(); break; } } @@ -561,6 +593,8 @@ void WPP_Dump() { void WP_Attack(); void MP_SetSpeed() { +#if 0 + // This wants ping correction to not be a punishment... static float prev_state; if (!IsEffectFrame()) @@ -578,6 +612,7 @@ void MP_SetSpeed() { localcmd("cl_forwardspeed ", mspeed, "\n"); localcmd("cl_sidespeed ", mspeed, "\n"); localcmd("cl_backspeed ", mspeed, "\n"); +#endif } @@ -750,13 +785,13 @@ static float PP_EPS = 0.05; DEFCVAR_FLOAT(cl_r2g, 0); -void PP_CreateProjectile(int proj_type, vector offset) { +entity PP_CreateProjectile(int proj_type, vector offset) { fo_projectile* desc = &fpp_types[proj_type]; PredProj_Sound(proj_type); if (!PP_Enabled()) - return; + return __NULL__; entity proj = spawn(); @@ -770,7 +805,7 @@ void PP_CreateProjectile(int proj_type, vector offset) { // weapon anyway. if (pstate_pred.tfstate & TFSTATE_QUICKSLOT && !(pstate_server.tfstate & TFSTATE_QUICKSLOT)) - return; + return __NULL__; #endif // Note: We use true time here as created projectiles exist outside of pred. @@ -802,9 +837,18 @@ void PP_CreateProjectile(int proj_type, vector offset) { if (predicted_projectiles) predicted_projectiles.pred_prev = proj; predicted_projectiles = proj; + + return proj; } -void PP_AssCanFrame() { +void W_FireAssaultCannon() { + FO_WeapInfo* wi = WP_CurrentWeapon(); + WP_ConsumeAmmo(wi); + + if (!IsEffectFrame() || !PP_Enabled()) + return; + + WeapPred_FireAssCan(input_angles, 5, '0.04 0.04 0'); } void (float ox) W_FireSpikes = { @@ -828,6 +872,22 @@ void (float ox) W_FireSpikes = { }; +void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { + vector offset = org - pmove_org - '0 0 16'; + entity proj = PP_CreateProjectile(FPP_ASSAULT_CANNON, offset); + + if (proj == __NULL__) + return; + + proj.s_origin = org; + setorigin(proj, org); + proj.frame = hwguy_random() * 15; + proj.skin = 16 + hwguy_random() * 7; + proj.velocity = dir * proj_speed; + proj.angles = vectoangles(dir); + proj.wpp_aux = WP_GetAmmo(AMMO_SHELLS) * 100 + index; +} + void WP_Attack() { Slot slot = pstate_pred.current_slot; FO_WeapInfo* wi = WP_CurrentWeapon(); @@ -867,6 +927,9 @@ void WP_Attack() { PP_CreateProjectile(FPP_RAILGUN, '0 0 0'); break; + case WEAP_ASSAULT_CANNON: + break; + case WEAP_GRENADE_LAUNCHER: case WEAP_PIPE_LAUNCHER: Pred_Sound(SND_GREN); break; @@ -887,6 +950,10 @@ void WP_Attack() { if (!in_anim) Attack_Finished(wi->attack_time); + // Start the AC state machine when necessary. + if (wi->weapon == WEAP_ASSAULT_CANNON && + (pstate_pred.tfstate & TFSTATE_AC_MASK) == 0) + pstate_pred.tfstate |= TFSTATE_AC_SPINUP; #if 0 // If our latency is higher than forward projection, synchronize animation // with when it will actually start/finish. The projectile internally @@ -915,12 +982,13 @@ float PredProjectile_MatchProjectile() { self.origin = self.s_origin + (time - self.s_time) * self.velocity; for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { - if (proj.fpp_index != self.fpp_index) + if (proj.fpp_index != self.fpp_index || proj.wpp_aux != self.wpp_aux) continue; if (time > proj.endtime - 0.01) break; // Projectile list is time ordered + proj.origin = proj.s_origin + (time - self.s_time) * proj.velocity; float d = vlen(proj.origin - self.origin); if (d < best) { best = d; @@ -1022,12 +1090,20 @@ float WP_ClientThink() { pstate_pred = pstate_server; + getinputstate(servercommandframe); // Setup first read for old_buttons. + + float old_input_buttons; int pframe = servercommandframe + 1; int eframe = clientcommandframe; for(; pframe <= eframe; pframe++) { + old_input_buttons = input_buttons; if (!getinputstate(pframe) || input_timelength <= 0) break; + pstate_pred.buttons_held = input_buttons; + pstate_pred.buttons_up = old_input_buttons & (~input_buttons); + pstate_pred.buttons_down = (~old_input_buttons) & input_buttons; + makevectors(input_angles); if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { pengine.is_effectframe = TRUE; diff --git a/share/animate.qc b/share/animate.qc index f220b8cb..34b8a134 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -1,5 +1,5 @@ struct anim_t { - int num_frames, num_wf; + float num_frames, num_wf; int frames[20]; int weaponframes[9]; int muzzle_flash; // muzzle flash on weaponframe index 0 @@ -9,13 +9,12 @@ struct anim_t { void think_nop() {} +void W_ChangeToBestWeapon(); +void Pred_Sound(SoundIndex snd, float vol = 1); + #ifdef SSQC -void asscan_up_extra(); -void asscan_fire_extra(); -void asscan_down_extra(); void W_PrintWeaponMessage(); -void W_ChangeToBestWeapon(); void W_FireAssaultCannon(); int W_FireAxe(); int W_FireKnife(); @@ -23,7 +22,6 @@ int W_FireMedikit(); int W_FireSpanner(); void SuperDamageSound(); -void FO_Sound(entity e, float chan, string samp, float vol, float atten); void player_run(); void player_stand1(); @@ -31,9 +29,14 @@ void player_asscan_fire(); void player_asscan_down1(); inline void *thinkindex() { return &self.client_thinkindex; } -static inline float has_button0() { return self.button0; } +static inline float *tf_state() { return &self.tfstate; } +static inline float is_attacking() { return self.button0; } static inline float is_intermission() { return intermission_running; } - +static inline vector get_velocity() { return self.velocity; } +static inline void set_weapon_frame(int f) { self.weaponframe = f; } +static inline float get_clip_fired() { + return self.clip_fired[SlotIndex(self.current_slot)]; +} void FO_SetClientThink(void() func, float offset, float override = TRUE) { self.think = think_nop; @@ -44,7 +47,7 @@ void FO_SetClientThink(void() func, float offset, float override = TRUE) { } void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - int tidx = self.client_thinkindex++ - 1; + float tidx = *thinkindex()++ - 1; int wfi = tidx % anim->num_wf; self.weaponframe = anim->weaponframes[wfi] ?: anim->weaponframes[0] + wfi; @@ -101,93 +104,10 @@ static void axe_extra() { self.hit_in_current_animation = FALSE; } -static float CheckNeedAssaultCannonDown() { - FO_WeapState ws; - FO_FillWeapState(self, MakeSlot(1), &ws); - - if ((!self.button0 || (self.ammo_shells < 1)) || intermission_running || - ((ws->wi)->needs_reload && *ws->clip_fired == (ws->wi)->clip_size)) { - self.tfstate |= TFSTATE_AIMING; - player_asscan_down1(); - return TRUE; - } - return FALSE; -} - -void asscan_up_extra() { - float tidx = *thinkindex() - 1; - - if (CheckNeedAssaultCannonDown()) - return; - - self.tfstate |= TFSTATE_AIMING; - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - self.fire_held_down = 1; - if (tidx == 1) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan1.wav", 1, 1); - SuperDamageSound(); - - if (tidx == 6) // 600ms spin up - player_asscan_fire(); - else - Attack_Finished(wi->attack_time); -} - -void asscan_fire_extra() { - float tidx = *thinkindex() - 1; - - if (CheckNeedAssaultCannonDown()) - return; - - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (((vlen(self.velocity) <= 90 && !cannon_movespin) || vlen(self.velocity) < 30) - && !(self.tfstate & TFSTATE_LOCK)) { - - if (tidx % 2 == 1) { - muzzleflash(); - FO_Sound(self, CHAN_WEAPON, "weapons/asscan2.wav", 1, ATTN_NORM); - } - - SuperDamageSound(); - - self.tfstate |= TFSTATE_AIMING; - if (!cannon_move) - self.tfstate |= TFSTATE_CANT_MOVE; - - // Halve firing speed when moving too fast. - if (vlen(self.velocity) < 30 || tidx % 2 == 1) - W_FireAssaultCannon(); - } else { - FO_Sound(self, CHAN_WEAPON, "weapons/asscan4.wav", 0.5, ATTN_NORM); - self.weaponframe = self.weaponframe == 2 ? 0 : 2; - } - Attack_Finished(wi->attack_time); -} - -void asscan_down_extra() { - float tidx = *thinkindex() - 1; - FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - - if (tidx == 1) - FO_Sound(self, CHAN_WEAPON, "weapons/asscan3.wav", 0.8, 1); - - if (tidx >= 15) { // 1.5s down - self.tfstate &= ~TFSTATE_AIMING; - self.fire_held_down = 0; - player_run(); - if (self.ammo_cells < 7 || !FO_CheckForReload()) { - W_PrintWeaponMessage(); - W_ChangeToBestWeapon(); - } - } - Attack_Finished(wi->attack_time); -}; - void player_run() { - FO_SetClientThink(player_run, 0.1); + ASSERTD_EQ(self.tfstate & TFSTATE_AC_MASK, 0); self.client_thinkindex = 0; + FO_SetClientThink(player_run, 0.1); self.frame = 6; self.weaponframe = 0; @@ -204,8 +124,8 @@ void player_run() { }; void player_stand1() { - FO_SetClientThink(player_stand1, 0.1); self.client_thinkindex = 0; + FO_SetClientThink(player_stand1, 0.1); self.frame = 17; self.weaponframe = 0; @@ -227,16 +147,17 @@ void player_stand1() { } self.walkframe++; }; - #else /* CSQC */ static inline void *thinkindex() { return &pstate_pred.client_thinkindex; } -static inline float has_button0() { return input_buttons & BUTTON0; } +static inline float *tf_state() { return &pstate_pred.tfstate; } +static inline float is_attacking() { return input_buttons & BUTTON0; } static inline float is_intermission() { return intermission; } static void SuperDamageSound() {} // TODO - -void FO_SetClientThink(void() func, float offset, float override = TRUE) { - pstate_pred.client_nextthink = pstate_pred.client_time + offset; -} +static inline vector get_velocity() { return pmove_vel; } +static inline void set_weapon_frame(int f) { self.frame = f; } +static inline void muzzleflash() {} +float* WP_ClipFired(); +static inline float get_clip_fired() { return *WP_ClipFired(); } void player_run() { pstate_pred.client_nextthink = 0; @@ -272,16 +193,28 @@ void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { static void axe_extra() {} -static void asscan_up_extra() {} -static void asscan_fire_extra() {} -static void asscan_down_extra() {} +void player_asscan_fire(); +void player_asscan_upN(); +void player_asscan_downN(); + +void player_assault_cannon() { + switch (pstate_pred.tfstate & TFSTATE_AC_MASK) { + case TFSTATE_AC_SPINUP: player_asscan_upN(); break; + case TFSTATE_AC_SPINNING: player_asscan_fire(); break; + case TFSTATE_AC_SPINDOWN: player_asscan_downN(); break; + } +} +void Attack_Finished(float attack_time); +float WP_ReloadIfNeeded(FO_WeapInfo* wi); +FO_WeapInfo* WP_CurrentWeapon(); +static inline float FO_CheckForReload() { return WP_ReloadIfNeeded(WP_CurrentWeapon()); } #endif void W_FireSpikes(float ox); // Shared by both client and server side. void nail_extra_csqc_ssqc() { - if (!has_button0() || is_intermission()) { + if (!is_attacking() || is_intermission()) { player_run(); return; } @@ -291,6 +224,85 @@ void nail_extra_csqc_ssqc() { W_FireSpikes(tidx ? 4 : -4); } +void player_asscan_down1(); +static float CheckNeedAssaultCannonDown() { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if ((!is_attacking() || (get_shells() < 1)) || is_intermission() || + get_clip_fired() == wi->clip_size) { + player_asscan_down1(); + return TRUE; + } + return FALSE; +} + +void asscan_up_extra() { + float tidx = *thinkindex() - 1; // Already incremented. + *tf_state() = (*tf_state() & ~TFSTATE_AC_MASK) | + (TFSTATE_AC_SPINUP | TFSTATE_AIMING); + + if (CheckNeedAssaultCannonDown()) + return; + + if (tidx == 1) + Pred_Sound(SND_ASSCAN_UP); + SuperDamageSound(); + + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + if (tidx == 6) // 600ms spin up + player_asscan_fire(); + else + Attack_Finished(wi->attack_time); +} + +void W_FireAssaultCannon(); +void asscan_fire_extra() { + float tidx = *thinkindex() - 1; // Already incremented. + *tf_state() = (*tf_state() & ~TFSTATE_AC_MASK) | + (TFSTATE_AC_SPINNING | TFSTATE_AIMING); + + if (CheckNeedAssaultCannonDown()) + return; + + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + + if (vlen(get_velocity()) <= 90 && !(*tf_state () & TFSTATE_LOCK)) { + if (tidx % 2 == 1) { // 1-based + muzzleflash(); + Pred_Sound(SND_ASSCAN_FIRE); + } + + SuperDamageSound(); + + set_weapon_frame(tidx % 2 ? 2 : 4); + // Halve firing speed when moving too fast. + if (vlen(get_velocity()) < 30 || tidx % 2 == 1) + W_FireAssaultCannon(); + } else { + Pred_Sound(SND_ASSCAN_SPIN, 0.5); + set_weapon_frame(tidx % 2 ? 2 : 0); + } + Attack_Finished(wi->attack_time); +} + +void asscan_down_extra() { + float tidx = *thinkindex() - 1; // Already incremented. + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); + *tf_state() = (*tf_state() & ~TFSTATE_AC_MASK) | + TFSTATE_AIMING | TFSTATE_AC_SPINDOWN; + + if (tidx == 1) + Pred_Sound(SND_ASSCAN_DOWN, 0.8); + + if (tidx >= 15) { // 1.5s down + *tf_state() &= ~(TFSTATE_AC_MASK | TFSTATE_AIMING); + player_run(); + if (self.ammo_cells < 7 || !FO_CheckForReload()) + W_ChangeToBestWeapon(); + } + Attack_Finished(wi->attack_time); +}; + anim_t anim_rocket = { 6, 6, {107}, {1}, TRUE }; void player_rocketN() { client_anim_frames(player_rocketN, think_nop, &anim_rocket); } void player_rocket1() { *thinkindex() = 1; player_rocketN(); } diff --git a/share/defs.h b/share/defs.h index 91d94e9d..026e3b1a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -251,6 +251,10 @@ enumflags { // as it could result in stacked no-weapon states.) TFSTATE_FLASHED, TFSTATE_QUICKSLOT, // QUICKSTOP should change to last weapon. + TFSTATE_AC_SPINUP, // These cover the 3 assault cannon states. + TFSTATE_AC_SPINNING, + TFSTATE_AC_SPINDOWN, + TFSTATE_LOCK, // assault cannon locked TFSTATE_INFECTED, // set when player is infected by the bioweapon TFSTATE_INVINCIBLE, // Player has permanent Invincibility (Usually by GoalItem) TFSTATE_INVISIBLE, // Player has permanent Invisibility (Usually by GoalItem) @@ -258,16 +262,17 @@ enumflags { TFSTATE_RADSUIT, // Player has permanent Radsuit (Usually by GoalItem) TFSTATE_BURNING, // Is on fire TFSTATE_GRENTHROWING, // is throwing a grenade - TFSTATE_LOCK, // assault cannon locked + TFSTATE_AIMING, // is using the laser sight or spinning cannon TFSTATE_RESPAWN_READY, // is waiting for respawn, and has pressed fire, // as sentry gun,indicate it needs to die TFSTATE_HALLUCINATING, // set when player is hallucinating TFSTATE_TRANQUILISED, // set when player is tranquilised TFSTATE_FLAMES_MAX, // Peak burnination. - TFSTATE_RANDOMPC, // Whether Playerclass is random, new one each respawn + TFSTATE_RANDOMPC, }; #define TFSTATE_AC_MASK (TFSTATE_AC_SPINUP|TFSTATE_AC_SPINNING|TFSTATE_AC_SPINDOWN) +#define TFSTATE_AC_FIRING (TFSTATE_AC_SPINUP|TFSTATE_AC_SPINNING) enum { PRNG_AXE, @@ -1059,9 +1064,6 @@ enumflags { #define PC_HVYWEAP_GRENADE_MAX_1 4 #define PC_HVYWEAP_GRENADE_MAX_2 1 #define PC_HVYWEAP_TF_ITEMS 0 -#define PC_HVYWEAP_PROJSPEED 3000 -#define PC_HVYWEAP_ASSCAN_CLIPSIZE 100 -#define MODEL_PROJ_DIAM2 "progs/proj_diam2.mdl" // Class Details for PYRO diff --git a/share/prediction.qc b/share/prediction.qc index 9738aa70..1efa7a3a 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -27,6 +27,7 @@ enumflags { enumflags { FOPP_POS, FOPP_INIT, + FOPP_AUX, }; #define FOWP_ALL 0xFFFF @@ -57,19 +58,17 @@ struct predict_tf_state { int prng_base[PRNG_NUM_STATES]; - // Used for prediction, not actually communicated. Reset each frame. + // Used for prediction, not actually communicated. Reset each frame. float ammo_used[AMMO_NUM_TYPES]; + float buttons_down, buttons_up, buttons_held; }; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; -struct fo_predsnd { - int id; - string sound; -}; - -enum { - SND_AXE, +enum SoundIndex:float { + SND_NONE = 0, + SND_FIRST = 2000, + SND_AXE = SND_FIRST, SND_SG, SND_SSG, SND_RL, @@ -79,6 +78,15 @@ enum { SND_FLAMETHROWER, SND_RAILGUN, SND_TRANQ, + SND_ASSCAN_UP, + SND_ASSCAN_FIRE, + SND_ASSCAN_DOWN, + SND_ASSCAN_SPIN, +}; + +struct fo_predsnd { + SoundIndex id; + string sound; }; fo_predsnd snd_types[] = { @@ -92,6 +100,10 @@ fo_predsnd snd_types[] = { { SND_FLAMETHROWER, "flmfire2.wav" }, { SND_RAILGUN, "railgun.wav" }, { SND_TRANQ, "dartgun.wav" }, + { SND_ASSCAN_UP, "asscan1.wav" }, + { SND_ASSCAN_FIRE, "asscan2.wav" }, + { SND_ASSCAN_DOWN, "asscan3.wav" }, + { SND_ASSCAN_SPIN, "asscan4.wav" }, }; enum { @@ -103,6 +115,7 @@ enum { FPP_FLAMETHROWER, FPP_TRANQ, FPP_RAILGUN, + FPP_ASSAULT_CANNON, }; struct fo_projectile { @@ -110,7 +123,7 @@ struct fo_projectile { float speed; string model; string trail; - int snd; + SoundIndex snd; // Automatically initialized below this line. float modelindex; @@ -126,6 +139,7 @@ fo_projectile fpp_types[] = { { FPP_FLAMETHROWER, 600, "s_explod.spr", "explodesprite", SND_FLAMETHROWER }, { FPP_TRANQ, PC_SPY_TRANQSPEED, "spike.mdl", "tr_spike", SND_TRANQ }, { FPP_RAILGUN, PC_ENGINEER_RAILSPEED, "e_spike1.mdl", "te_railtrail", SND_RAILGUN }, + { FPP_ASSAULT_CANNON, 3000, "proj_diam2.mdl", "tr_asscan", SND_NONE /* in anim */ }, }; void InitFppProjectiles() { @@ -146,7 +160,7 @@ void InitFppProjectiles() { for (i = 0; i < snd_types.length; i++) { fo_predsnd* snd = &snd_types[i]; - ASSERTD_EQ(i, snd->id); + ASSERTD_EQ(SND_FIRST + i, snd->id); snd->sound = strcat("weapons/", snd->sound); precache_sound(snd->sound); } @@ -158,6 +172,8 @@ float max_rewind_credit_ms(int fpp_type) { fo_config.max_rewind_fast_projectile_ms; } +.float wpp_aux; + #ifdef SSQC .predict_tf_state predict_state; @@ -419,6 +435,10 @@ void EntUpdate_Projectile(float isnew) { COMM(Angle, angles[2]); } + if (sendflags & FOPP_AUX) { + COMM(Short, wpp_aux); + } + #ifdef SSQC WriteEntity(MSG_ENTITY, self.owner); return TRUE; @@ -552,7 +572,13 @@ void WeaponPred_DoServerClientThink() { void FO_Sound(entity e, float chan, string samp, float vol, float atten); -void Pred_Sound(int snd, float vol = 1) { +void Pred_Sound(SoundIndex snd, float vol = 1) { + if (snd == SND_NONE) + return; + + ASSERTD_GE(snd, SND_FIRST); + snd -= SND_FIRST; + entity target = self; string wav = snd_types[snd].sound; @@ -589,6 +615,61 @@ void FOProj_Init(int fpp_type, entity mis) { if (fo_projectiles) { mis.SendEntity = PP_SendEntity; mis.SendFlags = FOPP_POS | FOPP_INIT; + if (mis.wpp_aux) + mis.SendFlags |= FOPP_AUX; } } #endif + +#ifdef CSQC +float WP_GetAmmo(float ammo_type); +float get_shells() { return WP_GetAmmo(AMMO_SHELLS); } +static inline vector get_origin() { return pmove_org; } +#else +float get_shells() { return self.ammo_shells; } +static inline vector get_origin() { return self.origin; } +#endif + +// Randomize by ammo index for consistency even if a packet/prediction misses. +float hwguy_random_index; + +void reset_hwguy_random() { + hwguy_random_index = (*prng_state(PRNG_HWGUY) + get_shells() * 211) & 65535; + ASSERTD_NE(hwguy_random_index, 0); +} + +float hwguy_random() { + float index = hwguy_random_index; + float r = (hwguy_random_index = lfsr_prng_raw(hwguy_random_index)) / 65535.0; + return r; +} + +float hwguy_crandom() { + return 2 * (hwguy_random() - 0.5); +} + +void FO_FireAssCanPellet(vector org, vector spread_dir, float var_speed, int index); + +void WeapPred_FireAssCan(vector vangle, float shotcount, + vector spread) { + vector bullet_dir, spread_dir, rand_dir, org; + float bullet_speed, var_speed; + + reset_hwguy_random(); + + makevectors(vangle); + + // Infront of player model and down towards gun + bullet_speed = fpp_types[FPP_ASSAULT_CANNON].speed; + bullet_dir = v_forward; + + for (int i = 0; i < shotcount; i++) { + var_speed = hwguy_crandom()*10 + bullet_speed; // Slight speed variance + rand_dir = (hwguy_crandom()*spread_x) * v_right + + (hwguy_crandom()*spread_y) * v_up; + spread_dir = bullet_dir + rand_dir; + org = get_origin() + '0 0 10' + rand_dir; + + FO_FireAssCanPellet(org, spread_dir, var_speed, i); + } +} diff --git a/share/weapons.qc b/share/weapons.qc index 8d565109..cc0f2db2 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -12,7 +12,6 @@ .float ammo_rockets; .float ammo_cells; -float fo_hwguy = TRUE; float sniperreload = FALSE; float pyro_type = PYRO_FO; #endif @@ -121,7 +120,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, PRED_PROJ, AMMO_ROCKETS, 0, 3, -9, 0 }, - { WEAP_ASSAULT_CANNON, NO_PREDICT, AMMO_SHELLS, -9, 1, 0.2, 4 }, + { WEAP_ASSAULT_CANNON, PRED_PROJ, AMMO_SHELLS, 100, 1, 0.2, 4 }, { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, PRED_PROJ, AMMO_SHELLS, 0, 1, 1.5, 0 }, @@ -617,8 +616,6 @@ void FO_Weapons_Init() { ASSERTD_EQ(weapon_names.length, weapon_info.length); - FO_WeapInfo* WI_ac = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - WI_ac->clip_size = fo_hwguy ? PC_HVYWEAP_ASSCAN_CLIPSIZE : 0; FO_WeapInfo* WI_sr = FO_GetWeapInfo(WEAP_SNIPER_RIFLE); WI_sr->clip_size = sniperreload ? 1 : 0; diff --git a/ssqc/client.qc b/ssqc/client.qc index d4b2b2b9..c4ecd392 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -505,9 +505,6 @@ void () DecodeLevelParms = { // assault cannon accuracy (0 = cf, 1 = tf 2.8, 2 = tf 2.9) [0] cannon_accuracy = CF_GetSetting("cac", "cannon_accuracy", "0"); - // projectile FO style hwguy - fo_hwguy = CF_GetSetting("fohw", "fo_hwguy", "on"); - // allow feign death in air [on] feign_air = CF_GetSetting("fa", "feign_air", "on"); @@ -2073,10 +2070,9 @@ void () PutClientInServer = { self.prng_base[PRNG_HWGUY] = 65535 * random(); self.immune_to_check = time + 10; - self.fire_held_down = 0; SetDimensions(TRUE); self.special_cooldown = 0; - + setmodel(self, string_null); modelindex_null = self.modelindex; @@ -2496,7 +2492,7 @@ void () PlayerJump = { FO_Sound(self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); } - if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) + if (self.tfstate & TFSTATE_AC_FIRING) StopAssCan(); return; @@ -2513,16 +2509,12 @@ void () PlayerJump = { FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); - if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { - if (!cannon_air) { - if (self.antispam_cannon_air < time) { - sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); - self.antispam_cannon_air = time + 3; - } - StopAssCan(); - } else { - self.tfstate |= TFSTATE_AIMING; + if (!cannon_air && self.tfstate & TFSTATE_AC_FIRING) { + if (self.antispam_cannon_air < time) { + sprint(self, PRINT_MEDIUM, "You cannot fire the assault cannon without your feet on the ground...\n"); + self.antispam_cannon_air = time + 3; } + StopAssCan(); } if (old_grens != 1) { diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 1fb26f85..7c652f5d 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -52,110 +52,47 @@ void AssCanBulletTouch() dremove(self); }; -//====================================================================== -// Vector randomizer, used mostly for avelocity setups - -vector(float base, float rndmix, float plusminus) vecrand = -{ - local vector vecmix; - if (plusminus) { - vecmix_x = base + crandom() * rndmix; - vecmix_y = base + crandom() * rndmix; - vecmix_z = base + crandom() * rndmix; - } - else { - vecmix_x = base + random() * rndmix; - vecmix_y = base + random() * rndmix; - vecmix_z = base + random() * rndmix; - } - return vecmix; -}; - -void LaunchAssCan(vector org, vector dir, float proj_speed) +void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { local float num; - + newmis = spawn(); - newmis.owner = self; - newmis.classname = "proj_bullet"; - - newmis.movetype = MOVETYPE_FLY; // Small collision - - newmis.solid = SOLID_BBOX; - newmis.touch = AssCanBulletTouch; - - if (asscanrange > 0) { - num = (1 / proj_speed) * asscanrange; - newmis.think = AssCanBulletThink; - newmis.nextthink = time + num; // Projectile range / gravity - } else { - newmis.think = SUB_Remove; - newmis.nextthink = time + 5; // Stop projectile going forever - } - - newmis.mdl = MODEL_PROJ_DIAM2; - FO_SetModel(newmis, newmis.mdl); // Diamond model - newmis.frame = random()*15; // Full range of sizes - newmis.skin = 16 + random()*7; // Bright colours - newmis.weapon = DMSG_ASSAULTCANNON; + newmis.owner = self; + newmis.classname = "proj_bullet"; - newmis.velocity = dir * proj_speed; // Constant speed multiplier - newmis.angles = vectoangles(dir); // Create direction angle - setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); // Zero size - setorigin (newmis, org); // Move to starting position + newmis.movetype = MOVETYPE_FLY; // Small collision - newmis.avelocity = vecrand(100, 200, FALSE); + newmis.solid = SOLID_BBOX; + newmis.touch = AssCanBulletTouch; - if (project_weapons) { - AL_ProjectProjectile(newmis); + if (asscanrange > 0) { + num = (1 / proj_speed) * asscanrange; + newmis.think = AssCanBulletThink; + newmis.nextthink = time + num; // Projectile range / gravity + } else { + newmis.think = SUB_Remove; + newmis.nextthink = time + 5; // Stop projectile going forever } -} - -void FireAssCan (float shotcount, vector dir, vector spread) -{ - FO_WeapState ws; - FO_FillWeapState(self, MakeSlot(1), &ws); - Status_Refresh(self); - FO_CheckForReload(); - - *ws->clip_fired += 1; - - vector bullet_dir, spread_dir, rand_dir, org; - float bullet_speed, var_speed; - - makevectors(self.v_angle); - - // Infront of player model and down towards gun - bullet_speed = PC_HVYWEAP_PROJSPEED; - bullet_dir = normalize(v_forward * bullet_speed); - - while (shotcount > 0) { - var_speed = crandom()*10 + bullet_speed; // Slight speed variance - rand_dir = (crandom()*spread_x) * v_right + (crandom()*spread_y) * v_up; - spread_dir = bullet_dir + rand_dir; - org = self.origin + '0 0 10' + rand_dir; + newmis.frame = hwguy_random()*15; // Full range of sizes + newmis.skin = 16 + hwguy_random()*7; // Bright colours + newmis.weapon = DMSG_ASSAULTCANNON; - LaunchAssCan(org, spread_dir, var_speed); + newmis.velocity = dir * proj_speed; // Constant speed multiplier + newmis.angles = vectoangles(dir); // Create direction angle + setorigin (newmis, org); // Move to starting position - shotcount = shotcount - 1; - } + newmis.wpp_aux = self.ammo_shells * 100 + index; + FOProj_Init(FPP_ASSAULT_CANNON, newmis); } void StopAssCan() { - if (self.fire_held_down && (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON)) { - self.tfstate = self.tfstate | TFSTATE_AIMING; - //self.weaponframe = 0; - player_asscan_down1(); - } + if (self.tfstate & TFSTATE_AC_FIRING) + player_asscan_down1(); } void FO_LockToggle () { - if (self.tfstate & TFSTATE_LOCK) { - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_LOCK); - } else { - self.tfstate = self.tfstate | TFSTATE_LOCK; - } + self.tfstate ^= TFSTATE_LOCK; Status_Refresh(self); /* self.impulse = 0; */ diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 5396ef1b..028baea7 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -422,7 +422,6 @@ float live_camera; float already_chosen_map; .float disptimer; -.float fire_held_down; .float hit_in_current_animation; // Set on knife attack if a hit is recorded to prevent combo hits // sniper location damage stuff @@ -570,7 +569,6 @@ float cannon_move; float cannon_movespin; float cannon_conc; float cannon_accuracy; -float fo_hwguy; float feign_air; float feign_pack; float feign_msg; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 69385a4e..ef841dc2 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -953,30 +953,25 @@ void () W_FireAutoRifle = { FireSniperBullet(dir, 8); }; -void FireAssCan (float shotcount, vector dir, vector spread); void () W_FireAssaultCannon = { + FO_WeapState ws; + FO_FillCurrentWeapState(&ws); + + FO_CheckForReload(); + + *ws->clip_fired += 1; + *ws->ammo_remaining -= (ws->wi)->ammo_per_shot; + Status_Refresh(self); + local vector dir; KickPlayer(-4, self); - self.ammo_shells = self.ammo_shells - 1; + dir = aim(self, 100000); deathmsg = DMSG_ASSAULTCANNON; - - if (fo_hwguy == FALSE) - { - if (cannon_accuracy == 1) - FireBullets(5, dir, '0 0 0'); - else if (cannon_accuracy == 2) - FireBullets(5, dir, '0.1 0.1 0'); - else if (vlen(self.velocity) < 50) - FireBullets(5, dir, '0.075 0.075 0'); - else - FireBullets(5, dir, '0.15 0.15 0'); - } - else - { - FireAssCan(5, dir, '0.04 0.04 0'); - } + + WeapPred_FireAssCan(self.v_angle, 5, '0.04 0.04 0'); + LogEventAttack(self); }; @@ -2647,10 +2642,7 @@ void () W_WeaponFrame = { if (cease_fire) return; - if (self.button0 - && (!self.fire_held_down - || - (self.fire_held_down && self.heat == 0 && self.playerclass == PC_HVYWEAP))) { + if (self.button0) { if (FO_CurrentWeapon() == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < 400) { diff --git a/ssqc/world.qc b/ssqc/world.qc index 6fc39a16..1bbde10e 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -280,7 +280,6 @@ void () worldspawn = { precache_sound2("speech/saveme2.wav"); precache_model2("progs/detpack2.mdl"); precache_model2("progs/grenade3.mdl"); - precache_model2(MODEL_PROJ_DIAM2); precache_sound("grentimer.wav"); precache_sound("mcp_grentimer1.wav"); precache_sound("mcp_grentimer2.wav"); From 4110863b7e750c081c09b9f310c20ae846737679 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 27 Oct 2022 13:07:46 -0700 Subject: [PATCH 1838/2474] Make sure projectiles appear on legacy clients modelindex can be manipulated independently of model --- share/prediction.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/prediction.qc b/share/prediction.qc index 1efa7a3a..f1682523 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -602,7 +602,7 @@ void FOProj_Init(int fpp_type, entity mis) { PredProj_Sound(fpp_type); - mis.modelindex = fpp_types[fpp_type].modelindex; + setmodel(mis, fpp_types[fpp_type].model); setsize(mis, '0 0 0', '0 0 0'); mis.fpp_index = fpp_type; From 27846df5a6c86a6aee24d1ce88b53bd7d006a959 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 30 Oct 2022 10:52:00 -0700 Subject: [PATCH 1839/2474] Make sure we don't try to send prediction updates to legacy clients We don't create the ent for !CSQC clients, so attempting to update is equivalent to trying to write on world. --- share/prediction.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/prediction.qc b/share/prediction.qc index f1682523..2793440c 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -240,6 +240,9 @@ predict_tf_state blank_state; .float last_full_predict_refresh; void WeaponPred_Update(entity player) { + if (player.predict_entity == __NULL__) + return; + float mask = FOWP_CTIME; if (time - player.last_full_predict_refresh >= 1000 * MSEC) { From 00035d4c3375459b4c816469b84b5a3f9795e41c Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 30 Oct 2022 10:57:38 -0700 Subject: [PATCH 1840/2474] Handle PRNG edge-case If our mod residue and PRNG state align it's possible to hit 0 which kills our LSFR. Handle this case explicitly. --- share/prediction.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/prediction.qc b/share/prediction.qc index 2793440c..d0543602 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -638,7 +638,8 @@ float hwguy_random_index; void reset_hwguy_random() { hwguy_random_index = (*prng_state(PRNG_HWGUY) + get_shells() * 211) & 65535; - ASSERTD_NE(hwguy_random_index, 0); + if (hwguy_random_index == 0) + hwguy_random_index = (get_shells() + 1) * 211; } float hwguy_random() { From 1f90e9eaa40671573cbabe9fd6da2d21eab513d7 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 31 Oct 2022 15:20:08 -0700 Subject: [PATCH 1841/2474] Add internal profiling support Add some basic sub-instrumentation allowing arbitrary blocks to be profiled using a new perf_sampler type paired with perf_{start, finish}_sample. The (average, randomized) sampling rate as well as the number of samples can be defined. --- csqc/csprogs.src | 1 + csqc/main.qc | 60 +++++++++++++++++++++++ csqc/profile.qc | 107 +++++++++++++++++++++++++++++++++++++++++ csqc/weapon_predict.qc | 35 +++----------- 4 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 csqc/profile.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index aea10340..179f961f 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -11,6 +11,7 @@ csdefs.qc csextradefs.qc ../share/debug.qc +profile.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc diff --git a/csqc/main.qc b/csqc/main.qc index 2051eff2..fe7a9446 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -13,11 +13,15 @@ void AddGrenTimer(float grentype, float offset); void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); +void Perf_Status(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); } +DECLARE_PERF_SAMPLER(frame_timing, 60, 0.1); +DECLARE_PERF_SAMPLER(hud_timing, 60, 0.1); + noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); @@ -27,6 +31,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_pic(HudIcons[i].icon); // } + INIT_PERF_SAMPLER(frame_timing); + INIT_PERF_SAMPLER(hud_timing); + FO_Weapons_Init(); WeapPred_InitDefaultConfig(); FO_PP_Init(); // Some of this is always used by custom projectiles. @@ -81,6 +88,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("vote_removemap"); registercommand("wpp_status"); + registercommand("perf_status"); for(float i = 0; i < MENU_OPTION.length - 1; i++) { registercvar(strcat("fo_menu_option_",MENU_OPTION[i]), MENU_OPTION[i]); } @@ -112,6 +120,7 @@ noref void() CSQC_WorldLoaded = { } noref void(float width, float height, float menushown) CSQC_UpdateView = { + float fts = perf_start_sample(&frame_timing); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! @@ -124,12 +133,14 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); + float hts = perf_start_sample(&hud_timing, fts); ScreenSize = [width, height, menushown]; SBAR.Hint = ""; sui_begin(width, height); Menu_Draw(width, height, menushown); Hud_Draw(width, height); sui_end(); + perf_finish_sample(&hud_timing, hts); if (CVARF(fo_csjumpsounds)) { local float health = getstatf(STAT_HEALTH); @@ -160,6 +171,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { last_vel_z = pmove_vel_z; last_pmove_onground = pmove_onground; } + perf_finish_sample(&frame_timing, fts); } noref float(string cmd) CSQC_ConsoleCommand = { @@ -387,6 +399,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "wpp_status": WPP_Status(); break; + case "perf_status": + Perf_Status(); + break; case "vote_addmap": AddVoteMap(argv(1),argv(2),argv(3),stof(argv(4)),stof(argv(5)),stof(argv(6)),TRUE); break; @@ -515,3 +530,48 @@ void Sync_GameState() { _Sync_ServerCommandFrame(); _Sync_ClientCommandFrame(); } + +static string to_precision(float f, float p) { + string fmt = strcat("%0.", ftos(p), "f"); + return sprintf(fmt, f); +} + +static float get_precision() { + float t = gettime(1); + + // For (debug) clients which have modified gettime to report with more + // precision. + return (t*1000 == ceil(t*1000)) ? 3 : 5; +} + +static float gettime_lat() { + const float trials = 1000; + float s = gettime(1), f, i; + for (i = 0; i < trials; i++) + gettime(1); + return (gettime(1) - s)/trials; +} + +// Note while this works with ms +void Perf_Status() { + printf("Performance Stats:\n"); + float avg, variance, minv, maxv; + + float prec = get_precision(); + if (prec > 3) + printf("gettime() timing = %0.5f\n", gettime_lat()); + + compute_avg(&frame_timing.samples, &avg, &variance); + compute_maxmin(&frame_timing.samples, &minv, &maxv); + printf(" Frame render (%d) avg=%s var=%0.3f min=%s max=%s\n", + (float)min(frame_timing.samples.count, frame_timing.samples.max_count), + to_precision(avg, prec), variance, + to_precision(minv, prec), to_precision(maxv, prec)); + + compute_avg(&hud_timing.samples, &avg, &variance); + compute_maxmin(&hud_timing.samples, &minv, &maxv); + printf(" HUD render (%d) avg=%s var=%0.3f min=%s max=%s\n", + (float)min(hud_timing.samples.count, hud_timing.samples.max_count), + to_precision(avg, prec), variance, + to_precision(minv, prec), to_precision(maxv, prec)); +} diff --git a/csqc/profile.qc b/csqc/profile.qc new file mode 100644 index 00000000..41fab962 --- /dev/null +++ b/csqc/profile.qc @@ -0,0 +1,107 @@ +inline float sq(float x) { return x * x; } + +struct perf_samples { + float* values; + int max_count; + int count; +}; + +float perf_add_sample(perf_samples* ps, float v) { + float idx = ps->count++ % ps->max_count; + float old = ps->values[idx]; + ps->values[idx] = v; + return old; +} + +struct moving_avg { + perf_samples samples; + float s1, s2; +}; + +void update_online_avg(moving_avg* avg, float newv) { + float oldv = perf_add_sample(&avg->samples, newv); + + avg->s1 += newv - oldv; + avg->s2 += newv*newv - oldv*oldv; +} + +float read_online_avg(struct moving_avg* avg, float* mean, float* variance) { + float n = max(min(avg->samples.count, 2), avg->samples.max_count); + + *mean = avg->s1 / n; + *variance = (avg->s2 - sq(avg->s1)/n) / (n - 1); + return n; +} + +void compute_avg(struct perf_samples* samples, float* mean, float* variance) { + if (samples->count < 2) { + *mean = samples->values[0]; + *variance = 0; + return; + } + + float K = samples->values[0]; + float i, n, s1, s2; + s1 = s2 = 0; + n = min(samples->count, samples->max_count); + for (i = 0; i < n; i++) { + s1 += samples->values[i] - K; + s2 += sq(samples->values[i] - K); + } + + *mean = s1/n + K; + *variance = (s2 - sq(s1) / n) / (n - 1); +} + +void compute_maxmin(struct perf_samples* samples, float* minv, float* maxv) { + *minv = *maxv = 0; + + if (samples->count > 0) + *minv = *maxv = samples->values[0]; + + for (float i = 1; i < min(samples->max_count, samples->count); i++) { + *minv = min(*minv, samples->values[i]); + *maxv = max(*maxv, samples->values[i]); + } +} + +// Must orchestrate calling INIT before use. +#define DECLARE_MOVING_AVG(_v, _c) \ + var float _v##_samples[_c]; \ + var moving_avg _v + +#define INIT_PERF_SAMPLES(_ps, _backing) \ + do { \ + (_ps)->values = _backing; (_ps)->max_count = (_backing).length; (_ps)->count = 0; \ + } while (0) + +#define INIT_MOVING_AVG(_v) INIT_PERF_SAMPLES(_v.samples, _v##_samples) + + +struct perf_sampler { + float interval; + perf_samples samples; + + float next_sample; // In game time, we want no exits. + float sample_start; // External [e.g. gettime(1)] based +}; + +float perf_start_sample(perf_sampler* ps, float force = FALSE) { + if (time < ps->next_sample && !force) + return FALSE; + ps->sample_start = gettime(1); // cltime + return TRUE; // Might return a (1-based) index at some point +} + +void perf_finish_sample(perf_sampler* ps, float idx) { + if (idx == 0) + return; // Not sampled. + ps->next_sample = cltime + (random() + random()) * ps->interval; + perf_add_sample(&ps->samples, gettime(1) - ps->sample_start); +} + +#define DECLARE_PERF_SAMPLER(_v, _c, _i) \ + var float _v##_samples[_c]; \ + var perf_sampler _v = { _i } + +#define INIT_PERF_SAMPLER(_v) INIT_PERF_SAMPLES(_v.samples, _v##_samples) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 532cbd26..5a0f0089 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -14,47 +14,25 @@ float WP_MinPing() { void WP_UpdateViewModel(entity pweap_ent); -static inline float sq(float x) { return x * x; } - #define csqc_print(...) \ do { if (CVARF(wpp_debug) & 4) { \ print("CSQC: ", __VA_ARGS__); \ } else { print(__VA_ARGS__); } } while(0) -#define NUM_PING_SAMPLES 20 - -struct { - float s1, s2, count; -} avg_ping; +DECLARE_MOVING_AVG(avg_ping, 20); static void update_avg_ping() { - static float samples[NUM_PING_SAMPLES]; - // We use a fairly low clamp here because: // a) We want to limit the effect of momentary total loss // b) We actually want high pings to have low effective variance and // trigger it on consistently. - float new = min(getplayerkeyfloat(player_localnum, INFOKEY_P_PING), 200); - - float idx = avg_ping.count++ % NUM_PING_SAMPLES; - float old = samples[idx]; - samples[idx] = new; + float newv = min(getplayerkeyfloat(player_localnum, INFOKEY_P_PING), 200); - avg_ping.s1 += new - old; - avg_ping.s2 += sq(new) - sq(old); + update_online_avg(&avg_ping, newv); } static float fill_avg_ping(float* mean, float* variance) { - float n = max(min(NUM_PING_SAMPLES, avg_ping.count), 2); - *mean = avg_ping.s1 / n; - *variance = (avg_ping.s2 - sq(avg_ping.s1)/n) / (n - 1); - return n; -} - -inline float get_avg_ping() { - float avg, variance; - fill_avg_ping(&avg, &variance); - return avg; + return read_online_avg(&avg_ping, mean, variance); } float csqc_get_user_setting(string s_short, string s_long, string def); @@ -165,10 +143,10 @@ void WPP_Status() { void WPP_UpdateEnable(float force) { if (time > next_ping_update) { update_avg_ping(); - next_ping_update = time + ENABLE_CHECK_PERIOD / NUM_PING_SAMPLES; + next_ping_update = time + ENABLE_CHECK_PERIOD / avg_ping.samples.max_count; } - if (avg_ping.count < NUM_PING_SAMPLES / 2) + if (avg_ping.samples.count < 5) return; // Skip until we have a useful number of samples. if (!force && time < next_wpp_enable_check) @@ -669,6 +647,7 @@ void FO_PP_Init() { // Entity we'll attach locally generated sound to. pred_sound_entity = spawn(); + INIT_MOVING_AVG(avg_ping); InitFppProjectiles(); for (float i = 0; i < trail_table.length; i++) { From fbef84c971dda09ebe836534f472d5bc693f5936 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 31 Oct 2022 11:30:43 -0700 Subject: [PATCH 1842/2474] Replace O(n) string look-ups in HUD/Menu implementation The HUD/Menu code currently depends on (string) named elements and O(n) search lookups every time a given string is needed. This is directly in the render path and fairly expensive. Rework this so that elements are uniquely addressed/indexed, allowing O(1) search. Improves HUD render time from ~1.8-1.9ms to 1.6ms. There's also a significant (larger) improvement on showscores/editor rendering, but this doesn't matter since it's not in the game path; although showcores should drop FPS less now. While we're here.. cut away some of the dense undergrowth of old code. But not too much. --- csqc/csextradefs.qc | 143 ++++++++++----- csqc/events.qc | 2 +- csqc/hud.qc | 389 +++++++++++++++++++---------------------- csqc/hud_helpers.qc | 45 ++--- csqc/input.qc | 2 +- csqc/main.qc | 11 +- csqc/menu.qc | 59 ++++++- csqc/status.qc | 416 +++++++++++++++++++------------------------- csqc/sui_sys.qc | 92 +++------- 9 files changed, 571 insertions(+), 588 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 5a2b0b1a..ec16e9ba 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -113,17 +113,6 @@ float zoomed_in; .float votecount; .float localmap; -float(string) GetDrawPanel; -void(string id, string identify) Hud_DrawIdentifyPanel; -void (string panelid, float display, string text) Hud_DrawHudOptionsPanel; -void (string id, float playerclass) Hud_DrawClassInfoPanel; -void (string panelid) Hud_DrawFlagStatusBar; -void (string panelid) Hud_DrawTeamScorePanel; -void (string panelid) Hud_DrawMapMenuPanel; -float(string id, vector pos, vector size, float alpha, float enabled) hud_panel; -vector(float panelid) getPosition; -vector(float panelid) getFillSize; - void () SUB_Null = { }; @@ -407,9 +396,94 @@ FO_TeamScores TS; float TeamScore[4]; +enum PanelID:float { + HUDP_INVALID = 0, // Reserve 0 so we can recognize an uninit menu + HUDP_FIRST = 100, + HUDP_OPTIONS = HUDP_FIRST, + HUDP_CLIPSIZE, + HUDP_FRAGSTREAK, + HUDP_CAPS, + HUDP_GREN1, + HUDP_GREN2, + HUDP_SPECIAL, + HUDP_IDENTIFY, + HUDP_FLAGINFO, + HUDP_GRENTIMER, + HUDP_MENU, + HUDP_MOTD, + HUDP_MENU_HINT, + HUDP_GAME_MODE, + HUDP_READY, + HUDP_SHOWSCORES, + HUDP_TEAMSCORE, + HUDP_MAP_MENU, + HUDP_HEALTH, + HUDP_FACE, + HUDP_AMMO, + HUDP_AMMOICON, + HUDP_ARMOUR, + HUDP_ARMOURICON, + HUDP_INVSHELLS, + HUDP_INVNAILS, + HUDP_INVROCKETS, + HUDP_INVCELLS, + HUDP_GAMECLOCK, + HUDP_QUAD, + HUDP_PENT, + HUDP_RING, + HUDP_SUIT, + HUDP_KEY1, + HUDP_KEY2, + HUDP_RUNE1, + HUDP_RUNE2, + HUDP_RUNE3, + HUDP_RUNE4, + HUDP_GUN2, + HUDP_GUN3, + HUDP_GUN4, + HUDP_GUN5, + HUDP_GUN6, + HUDP_GUN7, + HUDP_GUN8, + HUDP_SPEED, + HUDP_LAST = HUDP_SPEED, + + HUDP_GAP = 500, // Just to make ids larger than this distinguishable. + + HUDP_OPTION_LIST, + HUDP_OPTION_PANEL, + + HUDB_FIRST, + HUDB_MAP_VOTE, + HUDB_MAP_CHANGE, + HUDB_OPTION_LIST, + HUDB_OPTION_SCROLLUP, + HUDB_OPTION_SCROLLDOWN, + HUDB_LAST, + + HUDE_FIRST, + HUDE_OPTION_SCALE_SLIDER, + HUDE_OPTION_TEXTSCALE_SLIDER, + HUDE_OPTION_SCALE_SCROLL, + HUDE_OPTION_TEXTALIGN_TOGGLE, + HUDE_OPTION_SHOWHIDE_TOGGLE, + HUDE_OPTION_HSNAP_TOGGLE, + HUDE_OPTION_VSNAP_TOGGLE, + HUDE_OPTION_SHOWALL_TOGGLE, + HUDE_LAST, + + HUDL_FIRST = HUDB_LAST, + HUDL_OPTION_BASE = 1000, + HUDL_MAP_BASE = 2000, + HUDL_LAST = 3000, + + HUD_LAST = 10000, +}; + // hud stuff typedef struct { - string id; + PanelID id; + string SaveName; string Name; vector Position; vector FillSize; @@ -417,7 +491,7 @@ typedef struct { float TextScale; float Display; float Orientation; - void(string panelid, float display, string text) drawPanel; + void(float display, string text) drawPanel; string() getValue; float Style; float Snap; @@ -442,6 +516,17 @@ enumflags { FL_GT_ADJPING }; +float(PanelID) GetDrawPanel; +void(string identify) Hud_DrawIdentifyPanel; +void (float display, string text) Hud_DrawHudOptionsPanel; +void (float playerclass) Hud_DrawClassInfoPanel; +void () Hud_DrawFlagStatusBar; +void () Hud_DrawTeamScorePanel; +void () Hud_DrawMapMenuPanel; +float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel; +vector(PanelID) getPosition; +vector(PanelID) getFillSize; + class CsGrenTimer; CsGrenTimer grentimers[NUM_GREN_TIMERS]; @@ -491,6 +576,7 @@ class CsGrenTimer { last_ = grentimers[next_index_]; return last_; }; + static void() SyncPause { // Time froze, but sound kept running, realign. for (float i = 0; i < grentimers.length; i++) @@ -549,37 +635,6 @@ string FO_ScoreBoardColumns[] = { "dmgt" }; -enum { - HUD_PANEL_HUDOPTIONS, - HUD_PANEL_CLIPSIZE, - HUD_PANEL_FRAGSTREAK, - HUD_PANEL_CAPS, - HUD_PANEL_GREN1, - HUD_PANEL_GREN2, - HUD_PANEL_PLAYERCLASS, - HUD_PANEL_IDENTIFY, - HUD_PANEL_FLAGINFO, - HUD_PANEL_GRENTIMER, - HUD_PANEL_MENU, - HUD_PANEL_MOTD, - HUD_PANEL_MENU_HINT, - HUD_PANEL_GAME_MODE, - HUD_PANEL_READY, - HUD_PANEL_SHOWSCORES, - HUD_PANEL_TEAM_SCORE, - HUD_PANEL_MAP_MENU, - HUD_PANEL_HEALTH, - HUD_PANEL_FACE, - HUD_PANEL_AMMO, - HUD_PANEL_AMMO_ICON, - HUD_PANEL_ARMOUR, - HUD_PANEL_ARMOUR_ICON, - HUD_PANEL_INV_SHELLS, - HUD_PANEL_INV_NAILS, - HUD_PANEL_INV_ROCKETS, - HUD_PANEL_INV_CELLS, -}; - #define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" #define FOCMD_GRENTIMER "fo_grentimer" #define FOCMD_GRENTIMERSOUND "fo_grentimersound" diff --git a/csqc/events.qc b/csqc/events.qc index 1436e547..5f69a42b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -196,7 +196,7 @@ void() CSQC_Parse_Event = { FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_PICK, 0); break; case CLIENT_MENU_MAPS: - showVoteMenu(!Hud_Panels[HUD_PANEL_MAP_MENU].Display); + showVoteMenu(!getHudPanel(HUDP_MAP_MENU)->Display); break; } break; diff --git a/csqc/hud.qc b/csqc/hud.qc index f66d87ec..78fa336c 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,32 +1,14 @@ -float GetDrawPanel(string id) -{ - for(float i = 0; i < Hud_Panels.length; i++) { - if(Hud_Panels[i].id == id) { - DrawPanel = Hud_Panels[i]; - return i; - } +inline float GetDrawPanel(PanelID id) { + if (id >= HUDP_FIRST && id <= HUDP_LAST) { + DrawPanel = *getHudPanel(id); + return id; } -// for(float i = 0; i < Hud_ExtraPanels.length; i++) { -// if(Hud_ExtraPanels[i].id == id) { -// DrawPanel = Hud_ExtraPanels[i]; -// return i; -// } -// } - return -1; + return HUDP_INVALID; } -void SetDrawPanel(string id) -{ - for(float i = 0; i < Hud_Panels.length; i++) { - if(Hud_Panels[i].id == id) { - Hud_Panels[i] = DrawPanel; - } - } -// for(float i = 0; i < Hud_ExtraPanels.length; i++) { -// if(Hud_ExtraPanels[i].id == id) { -// Hud_ExtraPanels[i] = DrawPanel; -// } -// } +inline void SetDrawPanel(PanelID id) { + if (id >= HUDP_FIRST && id <= HUDP_LAST) + *getHudPanel(id) = DrawPanel; } void Hud_WriteCfg(string path) @@ -36,14 +18,8 @@ void Hud_WriteCfg(string path) filehandle = fopen(path, FILE_WRITE); string line = ""; - for(float i = 0; i < Hud_Panels.length; i++) { - DrawPanel = Hud_Panels[i]; - line = GetPanelString(line, Hud_Panels[i].id); - } -// for(float i = 0; i < Hud_ExtraPanels.length; i++) { -// DrawPanel = Hud_ExtraPanels[i]; -// line = GetPanelString(line, Hud_ExtraPanels[i].id); -// } + for(float i = HUDP_FIRST; i <= HUDP_LAST; i++) + line = GetPanelString(line, getHudPanel(i)); fputs(filehandle, line); fclose(filehandle); @@ -51,7 +27,7 @@ void Hud_WriteCfg(string path) void FO_Hud_Editor_LoadDefaultSettings() { - Hud_Panels[HUD_PANEL_HUDOPTIONS].drawPanel = Hud_DrawHudOptionsPanel; + getHudPanel(HUDP_OPTIONS)->drawPanel = Hud_DrawHudOptionsPanel; vector vsize = (vector)getproperty(VF_SCREENVSIZE); float width = vsize_x; float height = vsize_y; @@ -71,55 +47,55 @@ void FO_Hud_Editor_LoadDefaultSettings() for(float i = 0; i < Hud_Panels.length; i++) { pos = [pos_x, pos_y - 2 - 24]; - Hud_Panels[i].Position = pos; - //Hud_Panels[i].FillSize = fillSize; - Hud_Panels[i].Scale = scale; - Hud_Panels[i].Display = display; - Hud_Panels[i].Orientation = Orientation; + getHudPanel(i)->Position = pos; + //getHudPanel(i)->FillSize = fillSize; + getHudPanel(i)->Scale = scale; + getHudPanel(i)->Display = display; + getHudPanel(i)->Orientation = Orientation; //pnl.Name = name; } */ //Default menus, id, ready and MOTD to centre of the screen - Hud_Panels[HUD_PANEL_GAME_MODE].Position = [width - Hud_Panels[HUD_PANEL_GAME_MODE].FillSize.x, 30]; - Hud_Panels[HUD_PANEL_GAME_MODE].Orientation = FO_HUD_INSERT_AFTER; - Hud_Panels[HUD_PANEL_MOTD].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MOTD].FillSize.x / 2), 30]; - Hud_Panels[HUD_PANEL_READY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_READY].FillSize.x / 2), 30]; - Hud_Panels[HUD_PANEL_MENU_HINT].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), 80]; - Hud_Panels[HUD_PANEL_MENU_HINT].Orientation = FO_HUD_INSERT_MIDDLE; - Hud_Panels[HUD_PANEL_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2), 120]; - Hud_Panels[HUD_PANEL_IDENTIFY].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_IDENTIFY].FillSize.x / 2), height - 100]; - Hud_Panels[HUD_PANEL_CLIPSIZE].Position = [(width / 2) + 16, height - 50]; - Hud_Panels[HUD_PANEL_CLIPSIZE].Scale = 0.75; - Hud_Panels[HUD_PANEL_GREN1].Position = [(width / 2) - 16 - (Hud_Panels[HUD_PANEL_GREN1].FillSize.x * 3), height - 50]; - Hud_Panels[HUD_PANEL_GREN1].Scale = 0.75; - Hud_Panels[HUD_PANEL_GREN2].Position = [(width / 2) - 16 - Hud_Panels[HUD_PANEL_GREN2].FillSize.x * 0.75, height - 50]; - Hud_Panels[HUD_PANEL_GREN2].Scale = 0.75; - Hud_Panels[HUD_PANEL_GRENTIMER].Position = [(width / 2) + 16, (height / 2) + 32]; - Hud_Panels[HUD_PANEL_GRENTIMER].Scale = 0.75; - Hud_Panels[HUD_PANEL_FLAGINFO].Orientation = FO_HUD_INSERT_AFTER; - Hud_Panels[HUD_PANEL_FLAGINFO].Position = [width - 24, (height / 2) - 8]; - Hud_Panels[HUD_PANEL_FRAGSTREAK].Display = 0; - Hud_Panels[HUD_PANEL_CAPS].Display = 0; - Hud_Panels[HUD_PANEL_PLAYERCLASS].Position = [0, 180]; - Hud_Panels[HUD_PANEL_SHOWSCORES].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_SHOWSCORES].FillSize.x / 2), 30]; - Hud_Panels[HUD_PANEL_SHOWSCORES].Scale = 1.00; - Hud_Panels[HUD_PANEL_TEAM_SCORE].Position = [(width - Hud_Panels[HUD_PANEL_TEAM_SCORE].FillSize.x), 0]; - Hud_Panels[HUD_PANEL_MAP_MENU].Position = [(width / 2) - (Hud_Panels[HUD_PANEL_MAP_MENU].FillSize.x / 2), 30]; - Hud_Panels[HUD_PANEL_MAP_MENU].Scale = 1.00; + getHudPanel(HUDP_GAME_MODE)->Position = [width - getHudPanel(HUDP_GAME_MODE)->FillSize.x, 30]; + getHudPanel(HUDP_GAME_MODE)->Orientation = FO_HUD_INSERT_AFTER; + getHudPanel(HUDP_MOTD)->Position = [(width / 2) - (getHudPanel(HUDP_MOTD)->FillSize.x / 2), 30]; + getHudPanel(HUDP_READY)->Position = [(width / 2) - (getHudPanel(HUDP_READY)->FillSize.x / 2), 30]; + getHudPanel(HUDP_MENU_HINT)->Position = [(width / 2) - (getHudPanel(HUDP_MENU)->FillSize.x / 2), 80]; + getHudPanel(HUDP_MENU_HINT)->Orientation = FO_HUD_INSERT_MIDDLE; + getHudPanel(HUDP_MENU)->Position = [(width / 2) - (getHudPanel(HUDP_MENU)->FillSize.x / 2), 120]; + getHudPanel(HUDP_IDENTIFY)->Position = [(width / 2) - (getHudPanel(HUDP_IDENTIFY)->FillSize.x / 2), height - 100]; + getHudPanel(HUDP_CLIPSIZE)->Position = [(width / 2) + 16, height - 50]; + getHudPanel(HUDP_CLIPSIZE)->Scale = 0.75; + getHudPanel(HUDP_GREN1)->Position = [(width / 2) - 16 - (getHudPanel(HUDP_GREN1)->FillSize.x * 3), height - 50]; + getHudPanel(HUDP_GREN1)->Scale = 0.75; + getHudPanel(HUDP_GREN2)->Position = [(width / 2) - 16 - getHudPanel(HUDP_GREN2)->FillSize.x * 0.75, height - 50]; + getHudPanel(HUDP_GREN2)->Scale = 0.75; + getHudPanel(HUDP_GRENTIMER)->Position = [(width / 2) + 16, (height / 2) + 32]; + getHudPanel(HUDP_GRENTIMER)->Scale = 0.75; + getHudPanel(HUDP_FLAGINFO)->Orientation = FO_HUD_INSERT_AFTER; + getHudPanel(HUDP_FLAGINFO)->Position = [width - 24, (height / 2) - 8]; + getHudPanel(HUDP_FRAGSTREAK)->Display = 0; + getHudPanel(HUDP_CAPS)->Display = 0; + getHudPanel(HUDP_SPECIAL)->Position = [0, 180]; + getHudPanel(HUDP_SHOWSCORES)->Position = [(width / 2) - (getHudPanel(HUDP_SHOWSCORES)->FillSize.x / 2), 30]; + getHudPanel(HUDP_SHOWSCORES)->Scale = 1.00; + getHudPanel(HUDP_TEAMSCORE)->Position = [(width - getHudPanel(HUDP_TEAMSCORE)->FillSize.x), 0]; + getHudPanel(HUDP_MAP_MENU)->Position = [(width / 2) - (getHudPanel(HUDP_MAP_MENU)->FillSize.x / 2), 30]; + getHudPanel(HUDP_MAP_MENU)->Scale = 1.00; } void FO_Hud_Editor_List_Panels() = { print("^1Available HUD Elements:^7\n"); for(float i = 0; i < Hud_Panels.length; i++) { - print(Hud_Panels[i].id, ": ", Hud_Panels[i].Name, "\n"); + print(getHudPanel(i)->SaveName, ": ", getHudPanel(i)->Name, "\n"); } // for(float i = 0; i < Hud_ExtraPanels.length; i++) { // print(Hud_ExtraPanels[i].id, ": ", Hud_ExtraPanels[i].Name, "\n"); // } } -string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { +string FO_Hud_Editor_Get_Panel_Setting(string panel_name, string setting) = { /* float id = getHudPanel(panelid); if(id < 0) { @@ -127,15 +103,17 @@ string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { return ""; } */ - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + FO_Hud_Panel* panel = getHudPanelBySaveName(panel_name); if(!panel || &panel == &NullPanel) { - print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + print("^1HUD Element^7 '", panel_name, "' does not exist!\n"); return ""; } switch (setting) { - case "id": - return panel.id; + case "_id": + return ftos(panel.id); + case "saveName": + return panel.SaveName; case "name": return panel.Name; case "position": @@ -161,7 +139,7 @@ string FO_Hud_Editor_Get_Panel_Setting(string panelid, string setting) = { return ""; } -void FO_Hud_Editor_Show_Panel(string panelid) = { +void FO_Hud_Editor_Show_Panel(string panel_name) = { /* float id = getHudPanel(panelid); if(id < 0) { @@ -169,9 +147,9 @@ void FO_Hud_Editor_Show_Panel(string panelid) = { return; } */ - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + FO_Hud_Panel* panel = getHudPanelBySaveName(panel_name); if(!panel || &panel == &NullPanel) { - print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + print("^1HUD Element^7 '", panel_name, "' does not exist!\n"); return; } print("^1id^7: ", panel.id, "\n"); @@ -186,20 +164,20 @@ void FO_Hud_Editor_Show_Panel(string panelid) = { print("\tstyle: ", ftos(panel.Style), "\n"); } -void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting) = { - if(panelid == "help" || panelid == "?") { +void FO_Hud_Editor_Print_Panel_Setting(string panel_name, string setting) = { + if(panel_name == "help" || panel_name == "?") { print("^1orientation^7: Extends from base to the... 0 = Left, 1 = Right, 2 = Middle (where applicable)\n"); print("^1snap^7: 0 = None, Horzontal: 1/2/4 = Left/Centre/Right, Vertical: 8/16/32 = Top/Middle/Bottom)\n"); return; } if(setting == "") { - FO_Hud_Editor_Show_Panel(panelid); + FO_Hud_Editor_Show_Panel(panel_name); } else { - print(FO_Hud_Editor_Get_Panel_Setting(panelid, setting), "\n"); + print(FO_Hud_Editor_Get_Panel_Setting(panel_name, setting), "\n"); } } -void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string value) = { +void FO_Hud_Editor_Set_Panel_Setting(string panel_name, string setting, string value) = { /* float id = getHudPanel(panelid); if(id < 0) { @@ -209,9 +187,9 @@ void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string valu */ float val = 0; - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + FO_Hud_Panel* panel = getHudPanelBySaveName(panel_name); if(!panel || &panel == &NullPanel) { - print("^1HUD Element^7 '", panelid, "' does not exist!\n"); + print("^1HUD Element^7 '", panel_name, "' does not exist!\n"); return; } switch (setting) { @@ -279,7 +257,7 @@ float GetTextAlignOffset(float pos, float width, float iconsize, string text, fl return pos + iconsize; } //MEHT this is a sui example thing -void(string id, vector pos, vector size, string name, string command) bind_button = +void(PanelID id, vector pos, vector size, string name, string command) bind_button = { sui_push_frame(pos, size); sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); @@ -293,11 +271,10 @@ void(string id, vector pos, vector size, string name, string command) bind_butto }; void (float dx, float dy) Hud_MapMenuPanel_Move = { - FO_Hud_Panel* panel = &Hud_Panels[HUD_PANEL_MAP_MENU]; - if( - Mouse.x > panel.Position.x && - Mouse.y > panel.Position.y && - Mouse.x < (panel.Position.x + panel.FillSize.x * panel.Scale) && + FO_Hud_Panel* panel = getHudPanel(HUDP_MAP_MENU); + if (Mouse.x > panel.Position.x && + Mouse.y > panel.Position.y && + Mouse.x < (panel.Position.x + panel.FillSize.x * panel.Scale) && Mouse.y < (panel.Position.y + panel.FillSize.y * panel.Scale) ) { panel.Position.x += dx; @@ -305,15 +282,15 @@ void (float dx, float dy) Hud_MapMenuPanel_Move = { } }; -void(string panelid) Hud_DrawMapMenuPanel = { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); +void() Hud_DrawMapMenuPanel = { + FO_Hud_Panel* panel = getHudPanel(HUDP_MAP_MENU); local vector fillsize = panel.FillSize * panel.Scale; local float alpha = fo_hud_editor?0.2:0.9; local vector position = getPanelPosition(panel); if(panel.Display) { setcursormode(TRUE); } - if (hud_panel(panelid, position, fillsize, alpha, panel.Display)) { + if (hud_panel(panel->id, position, fillsize, alpha, panel.Display)) { // click event if (fo_hud_editor) { @@ -426,7 +403,7 @@ void(string panelid) Hud_DrawMapMenuPanel = { } else { textcolour = MENU_TEXT_1; } - if(hud_colour_button(strcat("listitem",ftos(cnt)),[0,0], listitemsize, mc.owner.name, bgcolour, [listitemsize.y, listitemsize.y], textcolour, SUI_ALIGN_START, 2, alpha, alpha, 1)) { + if(hud_colour_button(HUDL_MAP_BASE + cnt,[0,0], listitemsize, mc.owner.name, bgcolour, [listitemsize.y, listitemsize.y], textcolour, SUI_ALIGN_START, 2, alpha, alpha, 1)) { vote_selected_item = mc; vote_selected_index = cnt; } @@ -550,16 +527,16 @@ void(string panelid) Hud_DrawMapMenuPanel = { sui_push_frame(descriptionpos + [0, listitemsize.y * 3 + padding], [mapinfowidth - padding * 2, listitemsize.y * 3]); sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]); if(current_vote_selected) { - if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Unvote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { + if(hud_colour_button(HUDB_MAP_VOTE, [0,0], listitemsize + [0,padding], "Unvote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { localcmd("cmd break\n"); //current_vote = world; } } else { - if(hud_colour_button("vote_button", [0,0], listitemsize + [0,padding], "Vote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { + if(hud_colour_button(HUDB_MAP_VOTE, [0,0], listitemsize + [0,padding], "Vote", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { localcmd("cmd votemap ", vote_selected_item.owner.name, "\n"); } } - if(hud_colour_button("change_button", [0 - listitemsize.x - padding,0], listitemsize + [0,padding], "Change Now", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_WARNING, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { + if(hud_colour_button(HUDB_MAP_CHANGE, [0 - listitemsize.x - padding,0], listitemsize + [0,padding], "Change Now", MENU_BUTTON, [listitemsize.y,listitemsize.y], MENU_TEXT_WARNING, SUI_ALIGN_CENTER, 0, 1, 1, 0)) { if(is_admin) { localcmd("cmd map ", vote_selected_item.owner.name, "\n"); } else { @@ -571,9 +548,9 @@ void(string panelid) Hud_DrawMapMenuPanel = { } -void(string panelid) Hud_DrawTeamScorePanel = { +void() Hud_DrawTeamScorePanel = { float alpha = 0; - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + FO_Hud_Panel* panel = getHudPanel(HUDP_TEAMSCORE); //vector size = getFillSize(id); float textScale = panel.Scale; //panel.TextScale; //panel.TextScale?panel.TextScale:panel.Scale; @@ -590,7 +567,7 @@ void(string panelid) Hud_DrawTeamScorePanel = { fillsize = fillsize * textScale; vector position = getPanelPosition(panel); - if (hud_panel(panelid, position, fillsize, alpha, Hud_Panels[HUD_PANEL_TEAM_SCORE].Display)) + if (hud_panel(panel->id, position, fillsize, alpha, getHudPanel(HUDP_TEAMSCORE)->Display)) { // click event if (fo_hud_editor) @@ -623,79 +600,74 @@ void(string panelid) Hud_DrawTeamScorePanel = { } }; -void Hud_DrawFlagStatusBar(string panelid) +void Hud_DrawFlagStatusBar() { vector pos; float sizey, sizex; - sizey = FO_Hud_Icon_Size_y * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; - sizex = FO_Hud_Icon_Size_x * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; + sizey = FO_Hud_Icon_Size_y * getHudPanel(HUDP_FLAGINFO)->Scale; + sizex = FO_Hud_Icon_Size_x * getHudPanel(HUDP_FLAGINFO)->Scale; float flagInfoCount = 0; - for (float i = FlagInfoLines.length - 1; i >= 0; i--) - { - if (FlagInfoLines[i].id) - { + for (float i = FlagInfoLines.length - 1; i >= 0; i--) { + if (FlagInfoLines[i].id) flagInfoCount++; - } } //Show one for reference even on maps without if(fo_hud_editor && !flagInfoCount) { flagInfoCount = 1; } vector fillsize = [sizex * 4, sizey * flagInfoCount]; - Hud_Panels[HUD_PANEL_FLAGINFO].FillSize = fillsize; - //pos = getPosition(HUD_PANEL_FLAGINFO); //Hud_Panels[HUD_PANEL_FLAGINFO].Position; - pos = getScaledPanelPosition(getHudPanelPointer(HUD_PANEL_FLAGINFO), 1); + FO_Hud_Panel* panel = getHudPanel(HUDP_FLAGINFO); + panel->FillSize = fillsize; + //pos = getPosition(HUDP_FLAGINFO); //getHudPanel(HUDP_FLAGINFO)->Position; + pos = getScaledPanelPosition(panel, 1); float alpha = 0; - if (hud_panel(panelid, pos, fillsize, alpha, Hud_Panels[HUD_PANEL_FLAGINFO].Display)) - { + if (hud_panel(panel->id, pos, fillsize, alpha, getHudPanel(HUDP_FLAGINFO)->Display)) { // click event if (fo_hud_editor) { - + // TODO: Delete? Anything? } } - - for (float i = 0; i < flagInfoCount; i++) - { - if (FlagInfoLines[i].id) - { - alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? CVARF(fo_hud_idle_alpha) : 1; - string icon = FlagInfoLines[i].icon.filename; - vector iconcolour = FlagInfoLines[i].icon.colour; - float bigfont = 8 * (Hud_Panels[HUD_PANEL_FLAGINFO].TextScale ? Hud_Panels[HUD_PANEL_FLAGINFO].TextScale : Hud_Panels[HUD_PANEL_FLAGINFO].Scale); - float bigfontvoffset = sizey / 2 - bigfont / 2; //Center text against the icon + + for (float i = 0; i < flagInfoCount; i++) { + if (FlagInfoLines[i].id) { + alpha = FlagInfoLines[i].state == FLAGINFO_HOME ? CVARF(fo_hud_idle_alpha) : 1; + string icon = FlagInfoLines[i].icon.filename; + vector iconcolour = FlagInfoLines[i].icon.colour; + float bigfont = 8 * (getHudPanel(HUDP_FLAGINFO)->TextScale ? getHudPanel(HUDP_FLAGINFO)->TextScale : getHudPanel(HUDP_FLAGINFO)->Scale); + float bigfontvoffset = sizey / 2 - bigfont / 2; //Center text against the icon if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); - } + // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); + } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,Hud_Panels[HUD_PANEL_FLAGINFO].Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); - } - + // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); + drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); + } + drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); - + if (FlagInfoLines[i].timeleft >= 0) { - string stime = ftos(FlagInfoLines[i].timeleft); - float smallfont = 6 * Hud_Panels[HUD_PANEL_FLAGINFO].Scale; - drawstring([pos_x + sizex - stringwidth(stime, 1, [smallfont, smallfont]), pos_y + sizey * (i + 1) - smallfont, 0], stime, [smallfont, smallfont], '1 1 1', 1, 0); - } - } + string stime = ftos(FlagInfoLines[i].timeleft); + float smallfont = 6 * getHudPanel(HUDP_FLAGINFO)->Scale; + drawstring([pos_x + sizex - stringwidth(stime, 1, [smallfont, smallfont]), pos_y + sizey * (i + 1) - smallfont, 0], stime, [smallfont, smallfont], '1 1 1', 1, 0); + } + } } } -void Hud_ScrollPanelSelector(float num, float numlines) { - float newpos = Hud_Panels[HUD_PANEL_HUDOPTIONS].Status + num; +void Hud_ScrollPanelSelector(float num, float numlines) { // XXX + float newpos = getHudPanel(HUDP_OPTIONS)->Status + num; if(newpos < 1) { - Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = 1; + getHudPanel(HUDP_OPTIONS)->Status = 1; } else if(newpos > (Hud_Panels.length - numlines)) { - Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = Hud_Panels.length - (numlines - 1); + getHudPanel(HUDP_OPTIONS)->Status = Hud_Panels.length - (numlines - 1); } else { - Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = newpos; + getHudPanel(HUDP_OPTIONS)->Status = newpos; } } @@ -703,9 +675,9 @@ void Hud_ScrollPanelSelector(float num, float numlines) { void Hud_DrawHudOptionsPanelSelector() { if(!fo_hud_editor) return; - vector pos = getPosition(HUD_PANEL_HUDOPTIONS); //Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; //Start with option panel's pos - vector size = Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale; //for simplicity, use the same size as options panel - float textsize = 8 * (Hud_Panels[HUD_PANEL_HUDOPTIONS].TextScale ? Hud_Panels[HUD_PANEL_HUDOPTIONS].TextScale : Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale); + vector pos = getPosition(HUDP_OPTIONS); //getHudPanel(HUDP_OPTIONS)->Position; //Start with option panel's pos + vector size = getHudPanel(HUDP_OPTIONS)->FillSize * getHudPanel(HUDP_OPTIONS)->Scale; //for simplicity, use the same size as options panel + float textsize = 8 * (getHudPanel(HUDP_OPTIONS)->TextScale ? getHudPanel(HUDP_OPTIONS)->TextScale : getHudPanel(HUDP_OPTIONS)->Scale); if((pos.x + (size.x * 2)) < ScreenSize.x) { //If there's room on the screen, draw to the right of options panel pos.x = pos.x + size.x; @@ -713,7 +685,7 @@ void Hud_DrawHudOptionsPanelSelector() { pos.x = pos.x - size.x; } - if (hud_panel("hud_option_panel_list", pos, size, 0, 1)) + if (hud_panel(HUDP_OPTION_LIST, pos, size, 0, 1)) { // click event } @@ -722,71 +694,72 @@ void Hud_DrawHudOptionsPanelSelector() { //Need to draw scrollbar? if((Hud_Panels.length * (textsize + 2)) > size.y) { //Scrollbar buttons - if(hud_button("hud_option_panel_list_scrollup", pos + [size.x - textsize - 2,2], [textsize, textsize], "^")) { + if(hud_button(HUDB_OPTION_SCROLLUP, pos + [size.x - textsize - 2,2], [textsize, textsize], "^")) { Hud_ScrollPanelSelector(-1, numlines); } - if(hud_button("hud_option_panel_list_scrolldown", pos + [size.x - textsize - 2, size.y - textsize - 2], [textsize, textsize], "v")) { + if(hud_button(HUDB_OPTION_SCROLLDOWN, pos + [size.x - textsize - 2, size.y - textsize - 2], [textsize, textsize], "v")) { Hud_ScrollPanelSelector(1, numlines); } } + for(float i = 0,j = 0; i < min(numlines, Hud_Panels.length); i++) { - j = i + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status - 1; - if(hud_button(strcat("hud_option_panel_list_item", ftos(i)), pos + [2, (textsize + 2) * i], [size.x - textsize - 4, textsize + 2], Hud_Panels[j].Name)) { - Editor_SelectedPanel_Index = j; + j = i + getHudPanel(HUDP_OPTIONS)->Status - 1; + if(hud_button(HUDL_OPTION_BASE + i, pos + [2, (textsize + 2) * i], [size.x - textsize - 4, textsize + 2], getHudPanel(j + HUDP_FIRST)->Name)) { + Editor_SelectedPanel_Index = j + HUDP_FIRST; } } // for(float i = 0,j = 0; i < min(numlines, Hud_ExtraPanels.length); i++) { -// j = i + Hud_Panels[HUD_PANEL_HUDOPTIONS].Status - 1; +// j = i + getHudPanel(HUDP_OPTIONS)->Status - 1; // if(hud_button(strcat("hud_option_panel_list_item", ftos(i)), pos + [2, (textsize + 2) * i], [size.x - textsize - 4, textsize + 2], Hud_ExtraPanels[j].Name)) { // Editor_SelectedPanel_Index = j; // } // } } -void Hud_DrawHudOptionsPanel(string panelid, float display, string text) -{ +void Hud_DrawHudOptionsPanel(float display, string text) { if(!fo_hud_editor) return; - vector pos = getPosition(HUD_PANEL_HUDOPTIONS); //Hud_Panels[HUD_PANEL_HUDOPTIONS].Position; - vector size = Hud_Panels[HUD_PANEL_HUDOPTIONS].FillSize * Hud_Panels[HUD_PANEL_HUDOPTIONS].Scale; - if (hud_panel(Hud_Panels[HUD_PANEL_HUDOPTIONS].id, pos, size, 0, Hud_Panels[HUD_PANEL_HUDOPTIONS].Display)) - { - // click event - Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = 0; - } - - FO_Hud_Panel* selectedPanel = &Hud_Panels[Editor_SelectedPanel_Index]; - + FO_Hud_Panel* panel = getHudPanel(HUDP_OPTIONS); + vector pos = getPosition(HUDP_OPTIONS); //getHudPanel(HUDP_OPTIONS)->Position; + vector size = panel->FillSize * panel->Scale; + if (hud_panel(panel->id, pos, size, 0, panel->Display)) + panel->Status = 0; // click event0 + + if (Editor_SelectedPanel_Index < HUDP_FIRST || Editor_SelectedPanel_Index > HUDP_LAST) + Editor_SelectedPanel_Index = HUDP_FIRST; + + FO_Hud_Panel* selectedPanel = getHudPanel(Editor_SelectedPanel_Index); + //drawstring(pos + [4,4], selectedPanel.Name, [8,8], MENU_SELECTED, 1, 0); - if(hud_button("hud_option_panel_list_button", pos + [4,2], [140, 10], strcat(selectedPanel.Name, " >"))) { - Hud_Panels[HUD_PANEL_HUDOPTIONS].Status = !Hud_Panels[HUD_PANEL_HUDOPTIONS].Status; + if(hud_button(HUDB_OPTION_LIST, pos + [4,2], [140, 10], strcat(selectedPanel.Name, " >"))) { + getHudPanel(HUDP_OPTIONS)->Status = !getHudPanel(HUDP_OPTIONS)->Status; } float fscale = selectedPanel.Scale; drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); - hud_slider("hud_option_scale_scroll", pos + [8,24], [136,8], [0.2,5.0,24], fscale); + hud_slider(HUDE_OPTION_SCALE_SLIDER, pos + [8,24], [136,8], [0.2,5.0,24], fscale); if(fscale != selectedPanel.Scale) { - Hud_Panels[Editor_SelectedPanel_Index].Scale = fscale; + getHudPanel(Editor_SelectedPanel_Index)->Scale = fscale; } + float ftscale = selectedPanel.TextScale; drawstring(pos + [4,34], strcat("Text Scale: ",ftos(rint(ftscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); - hud_slider("hud_option_textscale_scroll", pos + [8,44], [136,8], [0,5.0,25], ftscale); - if(ftscale != selectedPanel.TextScale) { - Hud_Panels[Editor_SelectedPanel_Index].TextScale = ftscale; - } + hud_slider(HUDE_OPTION_TEXTSCALE_SLIDER, pos + [8,44], [136,8], [0,5.0,25], ftscale); + if(ftscale != selectedPanel.TextScale) + getHudPanel(Editor_SelectedPanel_Index)->TextScale = ftscale; float ftextalign = selectedPanel.Orientation; //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.Orientation ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); - if(hud_button("hud_option_textalign_toggle", pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.Orientation])) { - Hud_Panels[Editor_SelectedPanel_Index].Orientation = (selectedPanel.Orientation + 1) % 3; + if(hud_button(HUDE_OPTION_TEXTALIGN_TOGGLE, pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.Orientation])) { + getHudPanel(Editor_SelectedPanel_Index)->Orientation = (selectedPanel.Orientation + 1) % 3; } //hud_slider("hud_option_textalign_scroll", pos + [8,64], [32,8], [0,1,1], ftextalign); //if(ftextalign != selectedPanel.Orientation) { - // Hud_Panels[Editor_SelectedPanel_Index].Orientation = ftextalign; + // getHudPanel(Editor_SelectedPanel_Index)->Orientation = ftextalign; //} - if(hud_button("hud_option_show_hide_toggle", pos + [4,74], [140, 16], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { - Hud_Panels[Editor_SelectedPanel_Index].Display = !selectedPanel.Display; + if(hud_button(HUDE_OPTION_SHOWHIDE_TOGGLE, pos + [4,74], [140, 16], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { + getHudPanel(Editor_SelectedPanel_Index)->Display = !selectedPanel.Display; } drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); @@ -794,48 +767,49 @@ void Hud_DrawHudOptionsPanel(string panelid, float display, string text) local float snap = 0; local string ssnap; - if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 2) { + if(getHudPanel(Editor_SelectedPanel_Index)->Snap & 2) { snap = 1; - } else if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 4) { + } else if(getHudPanel(Editor_SelectedPanel_Index)->Snap & 4) { snap = 2; } else { snap = 0; } drawstring(pos + [4,130], "Hor. Snap: ", [8,8], MENU_SELECTED, 1, 0); - if(hud_button("hud_option_hsnap_toggle", pos + [size.x - 6 - 56,126], [56, 16], HUD_HORIZONTAL_ALIGN[snap])) { + if(hud_button(HUDE_OPTION_HSNAP_TOGGLE, pos + [size.x - 6 - 56,126], [56, 16], HUD_HORIZONTAL_ALIGN[snap])) { snap = (snap + 1) % 3; - Hud_Panels[Editor_SelectedPanel_Index].Position.x = 0; - Hud_Panels[Editor_SelectedPanel_Index].Snap -= (Hud_Panels[Editor_SelectedPanel_Index].Snap & 7); - Hud_Panels[Editor_SelectedPanel_Index].Snap += pow(2,snap); + getHudPanel(Editor_SelectedPanel_Index)->Position.x = 0; + getHudPanel(Editor_SelectedPanel_Index)->Snap -= (getHudPanel(Editor_SelectedPanel_Index)->Snap & 7); + getHudPanel(Editor_SelectedPanel_Index)->Snap += pow(2,snap); } - if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 16) { + if(getHudPanel(Editor_SelectedPanel_Index)->Snap & 16) { snap = 1; - } else if(Hud_Panels[Editor_SelectedPanel_Index].Snap & 32) { + } else if(getHudPanel(Editor_SelectedPanel_Index)->Snap & 32) { snap = 2; } else { snap = 0; } drawstring(pos + [4,148], "Ver. Snap: ", [8,8], MENU_SELECTED, 1, 0); - if(hud_button("hud_option_vsnap_toggle", pos + [size.x - 6 - 56,144], [56, 16], HUD_VERTICAL_ALIGN[snap])) { + if(hud_button(HUDE_OPTION_VSNAP_TOGGLE, pos + [size.x - 6 - 56,144], [56, 16], HUD_VERTICAL_ALIGN[snap])) { snap = (snap + 1) % 3; - Hud_Panels[Editor_SelectedPanel_Index].Position.y = 0; - Hud_Panels[Editor_SelectedPanel_Index].Snap -= (Hud_Panels[Editor_SelectedPanel_Index].Snap & 56); - Hud_Panels[Editor_SelectedPanel_Index].Snap += pow(2,(snap + 3)); + getHudPanel(Editor_SelectedPanel_Index)->Position.y = 0; + getHudPanel(Editor_SelectedPanel_Index)->Snap -= (getHudPanel(Editor_SelectedPanel_Index)->Snap & 56); + getHudPanel(Editor_SelectedPanel_Index)->Snap += pow(2,(snap + 3)); } - if(hud_button("hud_option_show_all_toggle", pos + [4,162], [140, 16], Hud_Panels[HUD_PANEL_HUDOPTIONS].Style ? "Show All" : "Hide Disabled")) { - Hud_Panels[HUD_PANEL_HUDOPTIONS].Style = !Hud_Panels[HUD_PANEL_HUDOPTIONS].Style; + if(hud_button(HUDE_OPTION_SHOWALL_TOGGLE, pos + [4,162], [140, 16], getHudPanel(HUDP_OPTIONS)->Style ? "Show All" : "Hide Disabled")) { + getHudPanel(HUDP_OPTIONS)->Style = !getHudPanel(HUDP_OPTIONS)->Style; } - if(Hud_Panels[HUD_PANEL_HUDOPTIONS].Status) { + if(getHudPanel(HUDP_OPTIONS)->Status) { Hud_DrawHudOptionsPanelSelector(); } } -void Hud_DrawClassInfoPanel(string id, float playerclass) +void Hud_DrawClassInfoPanel(float playerclass) { + const float id = HUDP_SPECIAL; vector pos; - pos = getPosition(HUD_PANEL_PLAYERCLASS); //DrawPanel.Position; + pos = getPosition(id); //DrawPanel.Position; if(fo_hud_editor) { hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display); @@ -1095,8 +1069,9 @@ void Hud_DrawClassInfoPanel(string id, float playerclass) } } -void Hud_DrawIdentifyPanel(string id, string identify) -{ +void Hud_DrawIdentifyPanel(string identify) { + const float id = HUDP_IDENTIFY; + DrawPanel = *getHudPanel(id); if (!DrawPanel.Display && !fo_hud_editor) return; @@ -1136,15 +1111,16 @@ void Hud_DrawIdentifyPanel(string id, string identify) } } -void Hud_DrawPanel(FO_Hud_Panel* panel, float index) { +void Hud_DrawPanel(FO_Hud_Panel* panel) { float offset = 0; if(sui_is_last_clicked(panel.id)) { - Editor_SelectedPanel_Index = index; + Editor_SelectedPanel_Index = panel->id; } - if(!Hud_Panels[HUD_PANEL_HUDOPTIONS].Style || panel.Display || (fo_hud_editor && index == Editor_SelectedPanel_Index)) { - panel.drawPanel( panel.id, panel.Display, panel.getValue()); + if(!getHudPanel(HUDP_OPTIONS)->Style || panel.Display || (fo_hud_editor && panel->id == Editor_SelectedPanel_Index)) { + if (panel.Display || fo_hud_editor) + panel.drawPanel(panel.id, panel.getValue()); //Draw panel names when editing - if(fo_hud_editor && panel.id != "hudoptionspanel") { + if(fo_hud_editor && panel->id != HUDP_OPTIONS) { switch (panel.Orientation) { case FO_HUD_INSERT_BEFORE: offset = 2; @@ -1156,19 +1132,20 @@ void Hud_DrawPanel(FO_Hud_Panel* panel, float index) { offset = (panel.FillSize.x / 2) - (strlen(panel.Name) * 3); //because 3 = 6/2 break; } - //drawstring(Hud_Panels[i].Position + [offset,2], Hud_Panels[i].Name, '6 6', '0 1 0', 1, 0); + //drawstring(getHudPanel(i)->Position + [offset,2], getHudPanel(i)->Name, '6 6', '0 1 0', 1, 0); drawstring(getScaledPanelPosition(panel,1) + [offset,2], panel.Name, '6 6', '0 1 0', 1, 0); } - } + } } void Hud_Draw(float width, float height) { - for(float i = 0; i < Hud_Panels.length; i++) { - Hud_DrawPanel(&(Hud_Panels[i]), i); + for(float i = HUDP_FIRST; i <= HUDP_LAST; i++) { + FO_Hud_Panel* panel = getHudPanel(i); + if (!panel->Display && !fo_hud_editor) + continue; // Fast-path skip. + + Hud_DrawPanel(panel); } -// for(float i = 0; i < Hud_ExtraPanels.length; i++) { -// Hud_DrawPanel(&(Hud_ExtraPanels[i]), i); -// } HudSettings.MousePos = [Mouse.x, Mouse.y]; } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 385af80d..c9bd4b03 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -1,6 +1,6 @@ void Hud_WriteCfg(string path); -float GetDrawPanel(string id); -void SetDrawPanel(string id); +float GetDrawPanel(PanelID id); +void SetDrawPanel(PanelID id); void FO_Hud_Editor() { @@ -30,7 +30,7 @@ float(float fo_align) fo_to_sui_aligntment = { return HUD_ALIGN_CENTER; }; -void(string id, vector pos, vector size, vector minmaxsteps, __inout float value) hud_slider = +void(PanelID id, vector pos, vector size, vector minmaxsteps, __inout float value) hud_slider = { sui_push_frame(pos, size); @@ -47,7 +47,7 @@ void(string id, vector pos, vector size, vector minmaxsteps, __inout float value }; -vector UpdatePos(string id, vector mousepos) +vector UpdatePos(PanelID id, vector mousepos) { vector pos; // switch (id) @@ -71,7 +71,7 @@ vector UpdatePos(string id, vector mousepos) return pos; } -float(string id, vector pos, vector size, float alpha, float enabled) hud_panel = +float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel = { vector basecolor = MENU_BG; vector outlinecolour = enabled ? MENU_BORDER : MENU_UNSELECTED; @@ -106,8 +106,8 @@ float(string id, vector pos, vector size, float alpha, float enabled) hud_panel basecolor = MENU_BG - MENU_DARKEN * 0.1; } // Make options panel switch back to last selected element after dragging - if(sui_is_released(id) && id == "hudoptionspanel") { - _last_clicked_actions[0] = Hud_Panels[Editor_SelectedPanel_Index].id; + if(sui_is_released(id) && id == HUDP_OPTIONS) { + _last_clicked_actions[0] = getHudPanel(Editor_SelectedPanel_Index)->id; } } @@ -230,15 +230,16 @@ void Hud_DrawStringLMPThreshold(vector pos, string value, float size, float thre } } -string GetPanelString(string line, string name) +string GetPanelString(string line, FO_Hud_Panel* panel) { - line = FormatCfgVector(line, strcat(name, ".position"), DrawPanel.Position); - line = FormatCfgString(line, strcat(name, ".scale"), ftos(DrawPanel.Scale)); - line = FormatCfgString(line, strcat(name, ".textscale"), ftos(DrawPanel.TextScale)); - line = FormatCfgString(line, strcat(name, ".display"), ftos(DrawPanel.Display)); - line = FormatCfgString(line, strcat(name, ".nodeinsertloc"), ftos(DrawPanel.Orientation)); - line = FormatCfgString(line, strcat(name, ".snap"), ftos(DrawPanel.Snap)); - line = FormatCfgString(line, strcat(name, ".style"), ftos(DrawPanel.Style)); + string sn = panel->SaveName; + line = FormatCfgVector(line, strcat(sn, ".position"), panel->Position); + line = FormatCfgString(line, strcat(sn, ".scale"), ftos(panel->Scale)); + line = FormatCfgString(line, strcat(sn, ".textscale"), ftos(panel->TextScale)); + line = FormatCfgString(line, strcat(sn, ".display"), ftos(panel->Display)); + line = FormatCfgString(line, strcat(sn, ".nodeinsertloc"), ftos(panel->Orientation)); + line = FormatCfgString(line, strcat(sn, ".snap"), ftos(panel->Snap)); + line = FormatCfgString(line, strcat(sn, ".style"), ftos(panel->Style)); return line; } @@ -287,14 +288,14 @@ void FO_Hud_Editor_LoadSettings(string filename) count = tokenizebyseparator(field, "."); string pnl; pnl = argv(0); - panel = getAnyHudPanelByNamePointer(pnl); + panel = getHudPanelBySaveName(pnl); if(!panel || &panel == &NullPanel) { if(strlen(pnl) < 6) { ln = fgets(filehandle); continue; } pnl = substring(pnl, 0, strlen(pnl) - 5); - panel = getAnyHudPanelByNamePointer(pnl); + panel = getHudPanelBySaveName(pnl); if(!panel || &panel == &NullPanel) { ln = fgets(filehandle); continue; @@ -342,10 +343,10 @@ void FO_Hud_Editor_LoadSettings(string filename) // write a new file Hud_WriteCfg(filename); } - if(Hud_Panels[HUD_PANEL_MENU].Position.x < 0) Hud_Panels[HUD_PANEL_MENU].Position.x = 10; - if(Hud_Panels[HUD_PANEL_MENU].Position.y < 0) Hud_Panels[HUD_PANEL_MENU].Position.y = 10; - if(Hud_Panels[HUD_PANEL_MENU].Position.x + Hud_Panels[HUD_PANEL_MENU].FillSize.x > vsize_x) Hud_Panels[HUD_PANEL_MENU].Position.x = vsize_x / 2 - Hud_Panels[HUD_PANEL_MENU].FillSize.x / 2; - if(Hud_Panels[HUD_PANEL_MENU].Position.y + Hud_Panels[HUD_PANEL_MENU].FillSize.y > vsize_y) Hud_Panels[HUD_PANEL_MENU].Position.y = 64; + if(getHudPanel(HUDP_MENU)->Position.x < 0) getHudPanel(HUDP_MENU)->Position.x = 10; + if(getHudPanel(HUDP_MENU)->Position.y < 0) getHudPanel(HUDP_MENU)->Position.y = 10; + if(getHudPanel(HUDP_MENU)->Position.x + getHudPanel(HUDP_MENU)->FillSize.x > vsize_x) getHudPanel(HUDP_MENU)->Position.x = vsize_x / 2 - getHudPanel(HUDP_MENU)->FillSize.x / 2; + if(getHudPanel(HUDP_MENU)->Position.y + getHudPanel(HUDP_MENU)->FillSize.y > vsize_y) getHudPanel(HUDP_MENU)->Position.y = 64; } @@ -367,7 +368,7 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float // draws value string using lmps void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon, float icon_alpha) { - if (!panel || &panel == &NullPanel || (!panel.Display && !fo_hud_editor)) + if (!panel.Display && !fo_hud_editor) return; vector pos; diff --git a/csqc/input.qc b/csqc/input.qc index 9d449e84..247f95cd 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -60,7 +60,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return (fo_hud_editor || menu_mouse); default: } - } else if(Hud_Panels[HUD_PANEL_MAP_MENU].Display) { + } else if(getHudPanel(HUDP_MAP_MENU)->Display) { switch (evtype) { case IE_MOUSEDELTA: return TRUE; diff --git a/csqc/main.qc b/csqc/main.qc index fe7a9446..93b15385 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -3,9 +3,8 @@ void Hud_Draw(float width, float height); void FO_Hud_Editor_LoadSettings(string); void FO_Hud_Editor_LoadDefaultSettings(); void FO_Hud_Editor_List_Panels(); -void FO_Hud_Editor_Show_Panel(string panelid); -void FO_Hud_Editor_Print_Panel_Setting(string panelid, string setting); -void FO_Hud_Editor_Set_Panel_Setting(string panelid, string setting, string value); +void FO_Hud_Editor_Print_Panel_Setting(string, string setting); +void FO_Hud_Editor_Set_Panel_Setting(string, string setting, string value); void Hud_WriteCfg(string path); void FO_LoadSettings(); void FO_WriteSettings(); @@ -14,6 +13,7 @@ void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); void Perf_Status(); +void FO_Hud_Init(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -34,6 +34,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { INIT_PERF_SAMPLER(frame_timing); INIT_PERF_SAMPLER(hud_timing); + FO_Hud_Init(); FO_Weapons_Init(); WeapPred_InitDefaultConfig(); FO_PP_Init(); // Some of this is always used by custom projectiles. @@ -97,7 +98,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); FO_LoadSettings(); - MenuPanel = getAnyHudPanelByNamePointer("menu"); + MenuPanel = getHudPanel(HUDP_MENU); CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; @@ -234,7 +235,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; case "fo_menu_vote": //FO_Menu_Vote(TRUE); - showVoteMenu(!Hud_Panels[HUD_PANEL_MAP_MENU].Display); + showVoteMenu(!getHudPanel(HUDP_MAP_MENU)->Display); break; case "fo_menu_special": FO_Menu_Special(TRUE); diff --git a/csqc/menu.qc b/csqc/menu.qc index 0ca07f8f..74235485 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -21,6 +21,8 @@ typedef struct { float state; //active/disabled void() action; vector colour; + + PanelID id; // Must be last member, automatically initialized. } fo_menu_option; typedef struct { @@ -34,6 +36,8 @@ typedef struct { void() update; float page; string description; + + PanelID id; // Must be after statically initialized members. } fo_menu; class fo_menu_option_2 { @@ -659,7 +663,7 @@ vector fo_menu_draw(fo_menu * menu) = { return position; } - Hud_Panels[HUD_PANEL_MAP_MENU].Display = FALSE; + getHudPanel(HUDP_MAP_MENU).Display = FALSE; thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); @@ -679,7 +683,6 @@ vector fo_menu_draw(fo_menu * menu) = { local vector buttonpos = position; local float buttonhover = FALSE; local vector smalltext = MENU_TEXT_SMALL * textscale, mediumtext = MENU_TEXT_MEDIUM * textscale; - local string id = strcat("fo_menu_",menu.title); local vector tempcolour; local float alignment = SUI_ALIGN_START; local vector bgcolour = (menu.flags & FO_MENU_FLAG_WARNING)?MENU_BG_WARNING:MENU_BG; @@ -687,7 +690,7 @@ vector fo_menu_draw(fo_menu * menu) = { menusize.y = titleoffset + menu.num_opts * (buttonsize.y + padding); - if (sui_is_held(id)) { + if (sui_is_held(menu->id)) { position = position + [Mouse.x, Mouse.y] - HudSettings.MousePos; MenuPanel.Position = MenuPanel.Position + [Mouse.x, Mouse.y] - HudSettings.MousePos; } @@ -698,7 +701,7 @@ vector fo_menu_draw(fo_menu * menu) = { sui_fill([0, 0], menusize, bgcolour, FO_MENU_TRANSPARENCY, 0); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - sui_action_element([0, 0], menusize, id, sui_noop); + sui_action_element([0, 0], menusize, menu.id, sui_noop); sui_pop_frame(); drawstring( @@ -736,7 +739,7 @@ vector fo_menu_draw(fo_menu * menu) = { if(menu.options[i].state == FO_MENU_STATE_NORMAL) { //if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), position + [padding, titleoffset + row * (buttonsize.y + padding)] + shortcutoffset, buttonsize - shortcutoffset - valueoffset, menu.options[i].name, menu.options[i].colour, smalltext, SUI_ALIGN_START, padding * 3 + smalltext.x)) { - if(hud_colour_button(strcat("fo_menu_",menu.title,"_",menu.options[i].name), buttonpos, buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, MENU_TEXT_1, alignment, shortcutoffset.x, 0.6, 1, 0)) { + if(hud_colour_button(menu.options[i].id, buttonpos, buttonsize, menu.options[i].name, menu.options[i].colour, smalltext, MENU_TEXT_1, alignment, shortcutoffset.x, 0.6, 1, 0)) { menu.options[i].action(); } } else if(menu.options[i].state == FO_MENU_STATE_DISABLED) { @@ -1305,8 +1308,52 @@ void (float show) showVoteMenu = { Menu_Cancel(); } setcursormode(show); - Hud_Panels[HUD_PANEL_MAP_MENU].Display = show; + getHudPanel(HUDP_MAP_MENU)->Display = show; if(show) { CurrentMenu = &FO_MENU_VOTE; } }; + +#define INIT_MENU_IDS(_target) \ + do { \ + _target.id = ++next_id; \ + for (i = 0; i < _target.options.length; i++) \ + _target.options[i].id = ++next_id; \ + } while (0) + +void FO_Hud_Init() { + float i; + ASSERTD_EQ(Hud_Panels.length, HUDP_LAST - HUDP_FIRST + 1); + + for (i = 0; i < Hud_Panels.length; i++) + ASSERTD_EQ(i + HUDP_FIRST, Hud_Panels[i].id); + float next_id = HUD_LAST + 1; + + DrawPanel = *getHudPanel(HUDP_OPTIONS); // XXX + INIT_MENU_IDS(FO_MENU_GAME); + INIT_MENU_IDS(FO_MENU_GAME_SPECTATOR); + INIT_MENU_IDS(FO_MENU_SPECTATOR_TRACK); + INIT_MENU_IDS(FO_MENU_TEAM); + INIT_MENU_IDS(FO_MENU_CLASS); + INIT_MENU_IDS(FO_MENU_DROPAMMO); + INIT_MENU_IDS(FO_MENU_SCOUT); + INIT_MENU_IDS(FO_MENU_SPY); + INIT_MENU_IDS(FO_MENU_SPY_TEAM); + INIT_MENU_IDS(FO_MENU_SPY_SKIN); + INIT_MENU_IDS(FO_MENU_DETPACK); + INIT_MENU_IDS(FO_MENU_DETPACK_CANCEL); + INIT_MENU_IDS(FO_MENU_BUILD); + INIT_MENU_IDS(FO_MENU_BUILD_CANCEL); + INIT_MENU_IDS(FO_MENU_SENTRY_MAINTAIN); + INIT_MENU_IDS(FO_MENU_SENTRY_ROTATE); + INIT_MENU_IDS(FO_MENU_ADMIN_MAIN); + INIT_MENU_IDS(FO_MENU_ADMIN_MODES); + INIT_MENU_IDS(FO_MENU_ADMIN_SETTINGS); + INIT_MENU_IDS(FO_MENU_ADMIN_PLAYERS); + INIT_MENU_IDS(FO_MENU_ADMIN_ROUNDS); + INIT_MENU_IDS(FO_MENU_ADMIN_QUAD_TIMELIMIT); + INIT_MENU_IDS(FO_MENU_ADMIN_TIMELIMIT); + INIT_MENU_IDS(FO_MENU_ADMIN_FRAGLIMIT); + INIT_MENU_IDS(FO_MENU_VOTE); +} +#undef INIT_MENU_IDS diff --git a/csqc/status.qc b/csqc/status.qc index efea8c5f..25b927cb 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -4,148 +4,120 @@ vector (FO_Hud_Panel* panel) getPanelPosition; vector (FO_Hud_Panel* panel) getPanelFillSize; void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string, float); void Hud_DrawLMPThreshold(FO_Hud_Panel*, string, float); -FO_Hud_Panel* getHudPanelPointer(float); -FO_Hud_Panel* getAnyHudPanelByNamePointer(string); +FO_Hud_Panel* getHudPanel(PanelID); -void(string panelid, float display, string text) drawClipSize = { +void(PanelID ignored, string text) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) - { - Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_CLIPSIZE, 1); - } + Hud_DrawPanelLMP(getHudPanel(HUDP_CLIPSIZE), text, ICON_CLIPSIZE, 1); }; -void(string panelid, float display, string text) drawIdentify = { +void(PanelID ignored, string text) drawIdentify = { if (strlen(SBAR.Identify) > 0 || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawIdentifyPanel(panelid, text); - } + Hud_DrawIdentifyPanel(text); }; -void(string panelid, float display, string text) drawTeamScorePanel = { - if (display || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawTeamScorePanel(panelid); - } +void(PanelID ignored, string text) drawTeamScorePanel = { + Hud_DrawTeamScorePanel(); }; -void(string panelid, float display, string text) drawMapMenuPanel = { - if (display || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawMapMenuPanel(panelid); - } +void(PanelID ignored, string text) drawMapMenuPanel = { + Hud_DrawMapMenuPanel(); }; -void(string panelid, float display, string text) drawFlagInfo = { - if (display || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawFlagStatusBar(panelid); - } +void(PanelID ignored, string text) drawFlagInfo = { + Hud_DrawFlagStatusBar(); }; -void(string panelid, float display, string text, string icon) drawIconPanel = { - if (display || fo_hud_editor) - { - Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, icon, 1); - } +void(PanelID panelid, string text, string icon) drawIconPanel = { + Hud_DrawPanelLMP(getHudPanel(panelid), text, icon, 1); }; -void(string panelid, float display, string text) drawFragStreakPanel = { - drawIconPanel(panelid, display, text, ICON_FRAGSTREAK); +void(PanelID panelid, string text) drawFragStreakPanel = { + drawIconPanel(HUDP_FRAGSTREAK, text, ICON_FRAGSTREAK); }; -void(string panelid, float display, string text) drawCapsPanel = { - drawIconPanel(panelid, display, text, ICON_CAPS); +void(PanelID ignored, string text) drawCapsPanel = { + drawIconPanel(HUDP_CAPS, text, ICON_CAPS); }; -void(string panelid, float display, string text) drawGren1Panel = { +void(PanelID panelid, string text) drawGren1Panel = { local float playerclass = SBAR.PlayerClass; - if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) { + if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) return; - } local float gren_type = getstatf(STAT_TP_GREN1); local string icon = GrenadeIcons[gren_type].icon; - drawIconPanel(panelid, display, text, icon); + drawIconPanel(HUDP_GREN1, text, icon); }; -void(string panelid, float display, string text) drawGren2Panel = { +void(PanelID ignored, string text) drawGren2Panel = { local float playerclass = SBAR.PlayerClass; - if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) { + if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) return; - } local float gren_type = getstatf(STAT_TP_GREN2); local string icon = GrenadeIcons[gren_type].icon; - drawIconPanel(panelid, display, text, icon); + drawIconPanel(HUDP_GREN2, text, icon); }; -void(string panelid, float display, string text) drawSpecial = { +void(PanelID ignored, string text) drawSpecial = { if (SBAR.PlayerClass || fo_hud_editor) - { - GetDrawPanel(panelid); - Hud_DrawClassInfoPanel(panelid, SBAR.PlayerClass); - } + Hud_DrawClassInfoPanel(SBAR.PlayerClass); }; -void(string panelid, float display, string text) drawGrenTimerPanel = { +void(PanelID panelid, string text) drawGrenTimerPanel = { float timeleft; float timercount = 0; - if (display) { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); - float Scale = panel.Scale; - float TextScale = panel.TextScale; - FO_Hud_Panel panel2; - panel2.Position = panel.Position; - panel2.Scale = panel.Scale; - panel2.TextScale = panel.TextScale; - panel2.Display = panel.Display; - panel2.FillSize = panel.FillSize; - - CsGrenTimer lt = CsGrenTimer::GetLast(); - // We want to render in reverse mod order from the last primed grenade - // here, that way we'll properly stack timers relative to expiry. - for (float i = grentimers.length; i > 0; i--) { - CsGrenTimer gt = grentimers[(lt.index() + i) % grentimers.length]; - - if (!gt.active()) - continue; + FO_Hud_Panel* panel = getHudPanel(panelid); + float Scale = panel.Scale; + float TextScale = panel.TextScale; + FO_Hud_Panel panel2; + panel2.Position = panel.Position; + panel2.Scale = panel.Scale; + panel2.TextScale = panel.TextScale; + panel2.Display = panel.Display; + panel2.FillSize = panel.FillSize; + + CsGrenTimer lt = CsGrenTimer::GetLast(); + // We want to render in reverse mod order from the last primed grenade + // here, that way we'll properly stack timers relative to expiry. + for (float i = grentimers.length; i > 0; i--) { + CsGrenTimer gt = grentimers[(lt.index() + i) % grentimers.length]; + + if (!gt.active()) + continue; - timeleft = floor(gt.expiry() - time) + 1; - if (timeleft < 1) - continue; + timeleft = floor(gt.expiry() - time) + 1; + if (timeleft < 1) + continue; - if (timercount) { - panel2.Scale = Scale * 0.8; - panel2.TextScale = TextScale * 0.8; - } + if (timercount) { + panel2.Scale = Scale * 0.8; + panel2.TextScale = TextScale * 0.8; + } - // It's technically possible to get a primed message before thrown - // if things get reordered, but since we can only ever have one - // grenade primed, we can obscure this by always considering - // grenades after the first as primed. - float alpha = (gt.is_thrown() || timercount) ? 0.3 : 1.0; - Hud_DrawPanelLMP(&panel2, ftos(timeleft), + // It's technically possible to get a primed message before thrown + // if things get reordered, but since we can only ever have one + // grenade primed, we can obscure this by always considering + // grenades after the first as primed. + float alpha = (gt.is_thrown() || timercount) ? 0.3 : 1.0; + Hud_DrawPanelLMP(&panel2, ftos(timeleft), GrenadeIcons[gt.grentype()].icon, alpha); - panel2.Position = panel2.Position + - [0, panel2.FillSize.y * panel2.Scale]; - timercount++; - } - } - if(fo_hud_editor && (!display || !timercount)) { - Hud_DrawPanelLMP(getAnyHudPanelByNamePointer(panelid), text, ICON_GREN_NORMAL, 1); + panel2.Position = panel2.Position + + [0, panel2.FillSize.y * panel2.Scale]; + timercount++; } + + if(fo_hud_editor && !timercount) + Hud_DrawPanelLMP(getHudPanel(panelid), text, ICON_GREN_NORMAL, 1); }; -void(string panelid, float display, string text) drawFacePanel = { +void(PanelID panelid, string text) drawFacePanel = { if (!CVARF(fo_fte_hud)) return; @@ -181,10 +153,10 @@ void(string panelid, float display, string text) drawFacePanel = { } } - drawIconPanel(panelid, display, text, icon); + drawIconPanel(panelid, text, icon); }; -void(string panelid, float display, string text) drawArmourPanel = { +void(PanelID panelid, string text) drawArmourPanel = { if(!CVARF(fo_fte_hud)) return; @@ -200,10 +172,10 @@ void(string panelid, float display, string text) drawArmourPanel = { else if(items & IT_ARMOR3) icon = ArmourIcons[3].icon; } - if(icon != "") drawIconPanel(panelid, display, text, icon); + if(icon != "") drawIconPanel(panelid, text, icon); }; -void(string panelid, float display, string text) drawAmmoPanel = { +void(PanelID panelid, string text) drawAmmoPanel = { if(!CVARF(fo_fte_hud)) return; @@ -215,42 +187,42 @@ void(string panelid, float display, string text) drawAmmoPanel = { else if(items & IT_ROCKETS) icon = AmmoIcons[2].icon; else if(items & IT_CELLS) icon = AmmoIcons[3].icon; - if(icon != "") drawIconPanel(panelid, display, text, icon); + if(icon != "") drawIconPanel(panelid, text, icon); }; -void(string panelid, float display, string text) drawInvIconPanel = { +void(PanelID panelid, string text) drawInvIconPanel = { if(!CVARF(fo_fte_hud)) return; if(text && text != "") { - drawIconPanel(panelid, display, "", text); + drawIconPanel(panelid, "", text); } else if(fo_hud_editor) { - drawIconPanel(panelid, display, "", FaceIcons[0].icon); + drawIconPanel(panelid, "", FaceIcons[0].icon); } }; -void(string panelid, float display, string text) drawInvShellsPanel = { +void(PanelID panelid, string text) drawInvShellsPanel = { if(!CVARF(fo_fte_hud)) return; - drawIconPanel(panelid, display, text, AmmoIcons[0].icon); + drawIconPanel(panelid, text, AmmoIcons[0].icon); }; -void(string panelid, float display, string text) drawInvNailsPanel = { +void(PanelID panelid, string text) drawInvNailsPanel = { if(!CVARF(fo_fte_hud)) return; - drawIconPanel(panelid, display, text, AmmoIcons[1].icon); + drawIconPanel(panelid, text, AmmoIcons[1].icon); }; -void(string panelid, float display, string text) drawInvRocketsPanel = { +void(PanelID panelid, string text) drawInvRocketsPanel = { if(!CVARF(fo_fte_hud)) return; - drawIconPanel(panelid, display, text, AmmoIcons[2].icon); + drawIconPanel(panelid, text, AmmoIcons[2].icon); }; -void(string panelid, float display, string text) drawInvCellsPanel = { +void(PanelID panelid, string text) drawInvCellsPanel = { if(!CVARF(fo_fte_hud)) return; - drawIconPanel(panelid, display, text, AmmoIcons[3].icon); + drawIconPanel(panelid, text, AmmoIcons[3].icon); }; string(float gunnum) getGunIcon = { @@ -286,32 +258,29 @@ string(float gunnum) getGunIcon = { return retval; }; -void(string panelid, float display, string text, float threshold) drawBigNumberPanel = { - if (display || fo_hud_editor) - { - Hud_DrawLMPThreshold(getAnyHudPanelByNamePointer(panelid), text, threshold); - } +void(PanelID panelid, string text, float threshold) drawBigNumberPanel = { + Hud_DrawLMPThreshold(getHudPanel(panelid), text, threshold); }; -void(string panelid, float display, string text) drawHealthTextPanel = { +void(PanelID panelid, string text) drawHealthArmourTextPanel = { if(!CVARF(fo_fte_hud)) return; - drawBigNumberPanel(panelid, display, text, 26); + drawBigNumberPanel(panelid, text, 26); }; -void(string panelid, float display, string text) drawAmmoTextPanel = { +void(PanelID panelid, string text) drawAmmoTextPanel = { if(!CVARF(fo_fte_hud)) return; - drawBigNumberPanel(panelid, display, text, 11); + drawBigNumberPanel(HUDP_AMMO, text, 11); }; -void(string panelid, float display, string text) drawClockPanel = { +void(PanelID panelid, string text) drawClockPanel = { if(!CVARF(fo_fte_hud)) return; - drawBigNumberPanel(panelid, display, text, 0); + drawBigNumberPanel(HUDP_GAMECLOCK, text, 0); }; string clockString() { @@ -353,11 +322,11 @@ string gameClockString() { return tmp; }; -void(string panelid, float display, string text) doNothing = {}; +static void(PanelID panelid, string text) doNothing = {}; -void(string panelid, float display, string text) drawSimplePanel = { +void(PanelID panelid, string text) drawSimplePanel = { if (fo_hud_editor) { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); + FO_Hud_Panel* panel = getHudPanel(panelid); if(panel && &panel != &NullPanel) { if (hud_panel(panelid, getPanelPosition(panel), getPanelFillSize(panel), 0.3, 1)) { // click event @@ -366,8 +335,8 @@ void(string panelid, float display, string text) drawSimplePanel = { } } -void(string panelid, float display, string text) drawTextPanel = { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); +void(PanelID panelid, string text) drawTextPanel = { + FO_Hud_Panel* panel = getHudPanel(panelid); vector position = getPanelPosition(panel); vector size = getPanelFillSize(panel); @@ -376,13 +345,12 @@ void(string panelid, float display, string text) drawTextPanel = { local float transparency = 0.3; local float lines; if (fo_hud_editor) { + string name = getHudPanel(panelid)->Name; drawstring( - [GetTextAlignOffset(position.x,size.x,padding,panelid,mediumtext.x,panel.Orientation), padding*2 + position.y], - panelid, - mediumtext, - MENU_TEXT_1, - 1, - 0 + [GetTextAlignOffset(position.x, size.x, padding, name, + mediumtext.x, panel.Orientation), + padding*2 + position.y], + name, mediumtext, MENU_TEXT_1, 1, 0 ); if (hud_panel(panelid, position, size, transparency, panel.Display)) { // click event @@ -409,12 +377,10 @@ void(string panelid, float display, string text) drawTextPanel = { line = strtrim(line); if (strlen(line) > 0) { drawstring( - [GetTextAlignOffset(position.x,size.x,padding,line,mediumtext.x,panel.Orientation), position.y + padding + mediumtext.y*i], - line, - mediumtext, - MENU_TEXT_1, - 1, - 0 + [GetTextAlignOffset(position.x, size.x, padding, line, + mediumtext.x, panel.Orientation), + position.y + padding + mediumtext.y*i], + line, mediumtext, MENU_TEXT_1, 1, 0 ); } } @@ -422,8 +388,8 @@ void(string panelid, float display, string text) drawTextPanel = { } } -void(string panelid, float display, string text) drawMOTDPanel = { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); +void(PanelID panelid, string text) drawMOTDPanel = { + FO_Hud_Panel* panel = getHudPanel(panelid); //vector position = getPosition(id); //vector size = getFillSize(id); @@ -493,8 +459,8 @@ void(string panelid, float display, string text) drawMOTDPanel = { //} } -void(string panelid, float display, string text) drawGameModePanel = { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); +void(PanelID panelid, string text) drawGameModePanel = { + FO_Hud_Panel* panel = getHudPanel(panelid); vector position = getPanelPosition(panel); vector size = getPanelFillSize(panel); @@ -542,18 +508,16 @@ void(string panelid, float display, string text) drawGameModePanel = { } if(message) { drawstring( - [GetTextAlignOffset(position.x,size.x,padding,message,mediumtext.x,panel.Orientation), position.y], - message, - mediumtext, - MENU_TEXT_1, - 1, - 0 + [GetTextAlignOffset( + position.x, size.x, padding, message, mediumtext.x, + panel.Orientation), position.y], + message, mediumtext, MENU_TEXT_1, 1, 0 ); } } -void(string panelid, float display, string text) drawReadyPanel = { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); +void(PanelID panelid, string text) drawReadyPanel = { + FO_Hud_Panel* panel = getHudPanel(panelid); vector position = getPanelPosition(panel); vector size = getPanelFillSize(panel); @@ -601,11 +565,7 @@ void(string panelid, float display, string text) drawReadyPanel = { drawstring( [pos_aligned, alert_text_position.y], - alert_text_message, - alert_text_size, - textcolour, - 1, - 0 + alert_text_message, alert_text_size, textcolour, 1, 0 ); position.y = alert_text_position.y + alert_text_size.y + textsize.y; @@ -634,11 +594,7 @@ void(string panelid, float display, string text) drawReadyPanel = { drawstring( [pos_aligned, alert_text_position.y], - alert_text_message, - alert_text_size, - textcolour, - 1, - 0 + alert_text_message, alert_text_size, textcolour, 1, 0 ); position.y = alert_text_position.y + alert_text_size.y + textsize.y; @@ -662,12 +618,7 @@ void(string panelid, float display, string text) drawReadyPanel = { if(message) { pos_aligned = GetTextAlignOffset(position.x,size.x,padding,message,textsize.x,panel.Orientation); drawstring( - [pos_aligned, position.y], - message, - textsize, - textcolour, - 1, - 0 + [pos_aligned, position.y], message, textsize, textcolour, 1, 0 ); } } @@ -952,8 +903,8 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel return position; }; -void(string panelid, float display, string text) drawShowScoresPanel = { - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer(panelid); +void(PanelID panelid, string text) drawShowScoresPanel = { + FO_Hud_Panel* panel = getHudPanel(panelid); vector position = getPanelPosition(panel); vector size = getPanelFillSize(panel); @@ -1101,89 +1052,82 @@ void(string panelid, float display, string text) drawShowScoresPanel = { void (float show) FO_Show_Scores = { showingscores = show; - FO_Hud_Panel* panel = getAnyHudPanelByNamePointer("showscores"); + FO_Hud_Panel* panel = getHudPanel(HUDP_SHOWSCORES); if(panel && &panel != &NullPanel) panel.Display = show; }; var FO_Hud_Panel Hud_Panels[] = { // id, Name, Position, FillSize, Scale, TextScale, Display, Orientation, -// void drawPanel(string panelid, float display, string text, string icon), +// void drawPanel(PanelID panelid, string text, string icon), // string getValue(), // Style, Snap, Status - {"hudoptions",FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return DrawPanel.id;}, 1}, - {"clipsize",FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return WP_GetClip(); }}, - {"fragstreak",FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, - {"caps",FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, - {"gren1",FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, - {"gren2",FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0, drawGren2Panel, {return ftos(getstatf(STAT_NO_GREN2));}}, - {"playerclass",FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {"identify",FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, - {"flaginfo",FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0, drawFlagInfo, {return "";}}, - {"grentimer",FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0, drawGrenTimerPanel, {return "";}}, - {"menu","Menu", '10 110', '300 200',1,0,1,0, drawSimplePanel, {return "";}}, - {"motd",FO_HUD_MOTD_NAME, '150 100', '100 24', 1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, - {"menuhint",FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, - {"gamemode",FO_HUD_GAME_MODE_NAME, '100 140', '100 10', 1,0,1,0, drawGameModePanel, {return "";}}, - {"ready",FO_HUD_READY_NAME, '10 100', '100 10', 2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, - {"showscores",FO_HUD_SHOWSCORES_NAME, '10 100', '600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, - {"teamscore",FO_HUD_TEAM_SCORE_NAME, '0 0', '72 12', 2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, - {"mapmenu",FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, - {"health",FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, - {"face",FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0, drawFacePanel, {return "";}, 0, 34}, - {"ammo",FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(WP_CurrentAmmo());}, 0, 34}, - {"ammoicon",FO_HUD_AMMO_ICON_NAME , '42 -2', '24 24', 1,0,1,0, drawAmmoPanel, {return "";}, 0, 34}, - {"armour",FO_HUD_ARMOUR_NAME, '-134 -2', '72 24', 1,0,1,0, drawHealthTextPanel, {return ftos(getstatf(STAT_ARMOR));}, 0, 34}, - {"armouricon",FO_HUD_ARMOUR_ICON_NAME,'-182 -2', '24 24', 1,0,1,0, drawArmourPanel, {return "";}, 0, 34}, - {"invshells",FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(WP_GetAmmo(AMMO_SHELLS));}, 1, 33}, - {"invnails",FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(WP_GetAmmo(AMMO_NAILS));}, 1, 33}, - {"invrockets",FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(WP_GetAmmo(AMMO_ROCKETS));}, 1, 33}, - {"invcells",FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(WP_GetAmmo(AMMO_CELLS));}, 1, 33}, - {"gameclock","Game Clock", '0 0' , '108 24', 1,0.8,1,0, drawClockPanel, {return gameClockString();}, 0, 10}, - {"quad","Quad Icon", '-200 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}, 0, 36}, - {"pent","Pentagram Icon", '-170 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}, 0, 36}, - {"ring","Ring Icon", '-140 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVISIBILITY)?"textures/wad/sb_invis":"";}, 0, 36}, - {"suit","Biosuit Icon", '-110 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_SUIT)?"textures/wad/sb_suit":"";}, 0, 36}, - {"key1","Silver Key", '140 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY1)?"textures/wad/sb_key1":"";}, 0, 34}, - {"key2","Gold Key", '160 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY2)?"textures/wad/sb_key2":"";}, 0, 34}, - {"rune1","Earth Rune", '-200 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 1)?"textures/wad/sb_sigi1":"";}, 0, 34}, - {"rune2","Black Rune", '-170 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 2)?"textures/wad/sb_sigil2":"";}, 0, 34}, - {"rune3","Hell Rune", '-140 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 4)?"textures/wad/sb_sigil3":"";}, 0, 34}, - {"rune4","Elder Rune", '-110 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 8)?"textures/wad/sb_sigil4":"";}, 0, 34}, - {"gun2","Shotgun", '-4 -170', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SHOTGUN);}, 0, 36}, - {"gun3","Super Shotgun", '-4 -150', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_SHOTGUN);}, 0, 36}, - {"gun4","Nailgun", '-4 -130', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_NAILGUN);}, 0, 36}, - {"gun5","Super Nailgun", '-4 -110', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_NAILGUN);}, 0, 36}, - {"gun6","Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, - {"gun7","Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, - {"gun8","Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {"speed","Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, + {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return getHudPanel(DrawPanel.id)->Name;}, 1}, + {HUDP_CLIPSIZE, "clipsize", FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return WP_GetClip(); }}, + {HUDP_FRAGSTREAK, "fragstreak", FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, + {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, + {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, + {HUDP_GREN2, "gren2", FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0, drawGren2Panel, {return ftos(getstatf(STAT_NO_GREN2));}}, + {HUDP_SPECIAL, "playerclass", FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {HUDP_IDENTIFY, "identify", FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, + {HUDP_FLAGINFO, "flaginfo", FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0, drawFlagInfo, {return "";}}, + {HUDP_GRENTIMER, "grentimer", FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0, drawGrenTimerPanel, {return "";}}, + {HUDP_MENU, "menu", "Menu", '10 110', '300 200',1,0,1,0, drawSimplePanel, {return "";}}, + {HUDP_MOTD, "motd", FO_HUD_MOTD_NAME, '150 100', '100 24', 1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, + {HUDP_MENU_HINT, "menuhint", FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, + {HUDP_GAME_MODE, "gamemode", FO_HUD_GAME_MODE_NAME, '100 140', '100 10', 1,0,1,0, drawGameModePanel, {return "";}}, + {HUDP_READY, "ready", FO_HUD_READY_NAME, '10 100', '100 10', 2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, + {HUDP_SHOWSCORES, "showscores", FO_HUD_SHOWSCORES_NAME, '10 100', '600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, + {HUDP_TEAMSCORE, "teamscore", FO_HUD_TEAM_SCORE_NAME, '0 0', '72 12', 2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, + {HUDP_MAP_MENU, "mapmenu", FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, + {HUDP_HEALTH, "health", FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0, drawHealthArmourTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, + {HUDP_FACE, "face", FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0, drawFacePanel, {return "";}, 0, 34}, + {HUDP_AMMO, "ammo", FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(WP_CurrentAmmo());}, 0, 34}, + {HUDP_AMMOICON, "ammoicon", FO_HUD_AMMO_ICON_NAME , '42 -2', '24 24', 1,0,1,0, drawAmmoPanel, {return "";}, 0, 34}, + {HUDP_ARMOUR, "armour", FO_HUD_ARMOUR_NAME, '-134 -2', '72 24', 1,0,1,0, drawHealthArmourTextPanel, {return ftos(getstatf(STAT_ARMOR));}, 0, 34}, + {HUDP_ARMOURICON, "armouricon", FO_HUD_ARMOUR_ICON_NAME,'-182 -2', '24 24', 1,0,1,0, drawArmourPanel, {return "";}, 0, 34}, + {HUDP_INVSHELLS, "invshells", FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(WP_GetAmmo(AMMO_SHELLS));}, 1, 33}, + {HUDP_INVNAILS, "invnails", FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(WP_GetAmmo(AMMO_NAILS));}, 1, 33}, + {HUDP_INVROCKETS, "invrockets", FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(WP_GetAmmo(AMMO_ROCKETS));}, 1, 33}, + {HUDP_INVCELLS, "invcells", FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(WP_GetAmmo(AMMO_CELLS));}, 1, 33}, + {HUDP_GAMECLOCK, "gameclock", "Game Clock", '0 0' , '108 24', 1,0.8,1,0, drawClockPanel, {return gameClockString();}, 0, 10}, + {HUDP_QUAD, "quad", "Quad Icon", '-200 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}, 0, 36}, + {HUDP_PENT, "pent", "Pentagram Icon", '-170 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}, 0, 36}, + {HUDP_RING, "ring", "Ring Icon", '-140 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVISIBILITY)?"textures/wad/sb_invis":"";}, 0, 36}, + {HUDP_SUIT, "suit", "Biosuit Icon", '-110 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_SUIT)?"textures/wad/sb_suit":"";}, 0, 36}, + {HUDP_KEY1, "key1", "Silver Key", '140 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY1)?"textures/wad/sb_key1":"";}, 0, 34}, + {HUDP_KEY2, "key2", "Gold Key", '160 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY2)?"textures/wad/sb_key2":"";}, 0, 34}, + {HUDP_RUNE1, "rune1", "Earth Rune", '-200 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 1)?"textures/wad/sb_sigi1":"";}, 0, 34}, + {HUDP_RUNE2, "rune2", "Black Rune", '-170 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 2)?"textures/wad/sb_sigil2":"";}, 0, 34}, + {HUDP_RUNE3, "rune3", "Hell Rune", '-140 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 4)?"textures/wad/sb_sigil3":"";}, 0, 34}, + {HUDP_RUNE4, "rune4", "Elder Rune", '-110 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 8)?"textures/wad/sb_sigil4":"";}, 0, 34}, + {HUDP_GUN2, "gun2", "Shotgun", '-4 -170', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SHOTGUN);}, 0, 36}, + {HUDP_GUN3, "gun3", "Super Shotgun", '-4 -150', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_SHOTGUN);}, 0, 36}, + {HUDP_GUN4, "gun4", "Nailgun", '-4 -130', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_NAILGUN);}, 0, 36}, + {HUDP_GUN5, "gun5", "Super Nailgun", '-4 -110', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_NAILGUN);}, 0, 36}, + {HUDP_GUN6, "gun6", "Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, + {HUDP_GUN7, "gun7", "Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, + {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, + {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, }; -//var FO_Hud_Panel Hud_ExtraPanels[] = { -//}; - -FO_Hud_Panel* (float panelid) getHudPanelPointer = { - return &(Hud_Panels[panelid]); +inline FO_Hud_Panel* (PanelID panelid) getHudPanel = { + ASSERTD_NE(panelid, HUDP_INVALID); + return &Hud_Panels[panelid - HUDP_FIRST]; }; -FO_Hud_Panel* (string panelid) getAnyHudPanelByNamePointer = { - for(float i = 0; i < Hud_Panels.length; i++) { - if(Hud_Panels[i].id == panelid) { - return &(Hud_Panels[i]); - } - } -// for(float i = 0; i < Hud_ExtraPanels.length; i++) { -// if(Hud_ExtraPanels[i].id == panelid) { -// return &(Hud_ExtraPanels[i]); -// } -// } +FO_Hud_Panel* (string save_name) getHudPanelBySaveName = { + for(float i = HUDP_FIRST; i <= HUDP_LAST; i++) { + FO_Hud_Panel* panel = getHudPanel(i); + if (panel->SaveName == save_name) + return panel; + } return &NullPanel; }; vector (FO_Hud_Panel* panel, float scale) getScaledPanelPosition = { if(panel.Snap == HUD_SNAP_NONE) { - return panel.Position; //Hud_Panels[panelid].Position; + return panel.Position; } vector v = panel.Position; //if(panel.Snap & HUD_SNAP_LEFT) v.x; @@ -1199,12 +1143,12 @@ vector (FO_Hud_Panel* panel) getPanelPosition = { return getScaledPanelPosition(panel, panel.Scale); } -vector(float panelid) getPosition = { - FO_Hud_Panel* panel = getHudPanelPointer(panelid); +vector(PanelID panelid) getPosition = { + FO_Hud_Panel* panel = getHudPanel(panelid); return getPanelPosition(panel); } -vector(float panelid) getFillSize = { - return Hud_Panels[panelid].FillSize; +vector(PanelID panelid) getFillSize = { + return getHudPanel(panelid)->FillSize; } vector (FO_Hud_Panel* panel) getPanelFillSize = { diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 16896adc..cdbc1789 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -186,7 +186,7 @@ vector _cursor_relative_hover; struct _action_element_t { vector pos; vector size; - string id; + PanelID id; void(float index, vector click_ratios) action; }; const float MAX_ACTION_ELEMENTS = 256; @@ -218,11 +218,11 @@ void() _action_element_count_sanity = }; const float MAX_MOUSE_ACTIONS = 16; -string _hover_actions[MAX_MOUSE_ACTIONS]; -string _click_actions[MAX_MOUSE_ACTIONS]; -string _hold_actions[MAX_MOUSE_ACTIONS]; -string _release_actions[MAX_MOUSE_ACTIONS]; -string _last_clicked_actions[MAX_MOUSE_ACTIONS]; +PanelID _hover_actions[MAX_MOUSE_ACTIONS]; +PanelID _click_actions[MAX_MOUSE_ACTIONS]; +PanelID _hold_actions[MAX_MOUSE_ACTIONS]; +PanelID _release_actions[MAX_MOUSE_ACTIONS]; +PanelID _last_clicked_actions[MAX_MOUSE_ACTIONS]; float _hover_action_count; float _click_action_count; @@ -256,30 +256,19 @@ float() sui_click_held = { return _holding_click; }; // click: on mouse1 button down AND button op, once // Returns true if id was the topmost click (what usually is cared about the most) -float(string id) sui_is_clicked = +float(PanelID id) sui_is_clicked = { return _click_action_count > 0 && _click_actions[0] == id; }; -// Returns the index of the clicked id, -1 if wasn't hit at all. 0 is topmost -float(string id) sui_click_index = -{ - for (int i = 0; i < _click_action_count; i++) - { - if (_click_actions[i] == id) return i; - } - return -1; -}; - - // hover: mouse is on top of the action element id -float(string id) sui_is_hovered = +float(PanelID id) sui_is_hovered = { return _hover_action_count > 0 && _hover_actions[0] == id; }; -float(string id) sui_hover_index = +float(PanelID id) sui_hover_index = { for (int i = 0; i < _hover_action_count; i++) { @@ -291,55 +280,25 @@ float(string id) sui_hover_index = // hold: mouse button was clicked on top of this id and is held down, but not necessarily over this id anymore -float(string id) sui_is_held = +float(PanelID id) sui_is_held = { return _hold_action_count > 0 && _hold_actions[0] == id; }; -float(string id) sui_hold_index = -{ - for (int i = 0; i < _hold_action_count; i++) - { - if (_hold_actions[i] == id) return i; - } - return -1; -}; - - // last clicked: is this the last action element that was clicked, good for focusing on input boxes for example -float(string id) sui_is_last_clicked = +float(PanelID id) sui_is_last_clicked = { return _last_clicked_action_count > 0 && _last_clicked_actions[0] == id; }; -float(string id) sui_last_clicked_index = -{ - for (int i = 0; i < _last_clicked_action_count; i++) - { - if (_last_clicked_actions[i] == id) return i; - } - return -1; -}; - - // release: a thing was held, but now it was released, once -float(string id) sui_is_released = +float(PanelID id) sui_is_released = { return _release_action_count > 0 && _release_actions[0] == id; }; -float(string id) sui_release_index = -{ - for (int i = 0; i < _release_action_count; i++) - { - if (_release_actions[i] == id) return i; - } - return -1; -}; - - float(float num) mouse_action_sanity = { if (num >= MAX_MOUSE_ACTIONS) @@ -426,7 +385,7 @@ void() _sui_mouse1_up = _holding_click = FALSE; }; -void(vector pos, vector size, string id, void(float index, vector click_ratios) action) sui_action_element = +void(vector pos, vector size, PanelID id, void(float index, vector click_ratios) action) sui_action_element = { if (!_sui_draw_initialized) { @@ -756,7 +715,7 @@ void(float index, vector click_ratios) sui_noop = {}; void(float value) sui_slider_noop = {}; -float(string id, vector pos, vector size, vector minmaxsteps, float value, void(float value) action) sui_slidercontrol = +float(PanelID id, vector pos, vector size, vector minmaxsteps, float value, void(float value) action) sui_slidercontrol = { sui_action_element(pos, size, id, sui_noop); float newvalue = value; @@ -777,7 +736,7 @@ float(string id, vector pos, vector size, vector minmaxsteps, float value, void( return newvalue; }; -void(string id, vector pos, vector size, __inout string text, __inout float cursor) sui_text_input = +void(PanelID id, vector pos, vector size, __inout string text, __inout float cursor) sui_text_input = { sui_action_element(pos, size, id, sui_noop); if (sui_is_clicked(id)) cursor = strlen(text); @@ -789,8 +748,9 @@ void(string id, vector pos, vector size, __inout string text, __inout float curs } }; +FO_Hud_Panel* (PanelID panelid) getHudPanel; -void(string id, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scrollbar = +void(PanelID id, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scrollbar = { vector maxoffset = contentsize - size; maxoffset_x = max(0, maxoffset_x); @@ -801,7 +761,6 @@ void(string id, vector size, vector contentsize, __inout vector offset, vector s vector barpos, barsize; float scan = 0; float char = 0; - string barname; if (maxoffset_y > 0 && contentsize_y > 0) { sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]); @@ -810,9 +769,8 @@ void(string id, vector size, vector contentsize, __inout vector offset, vector s length = (size_y / contentsize_y) * size_y; barpos = [0, ofs]; barsize = [scrollbar_widths_y, length]; - barname = strcat(id, "vbar"); - if (sui_is_held(barname)) + if (sui_is_held(id)) { vector anchor = barpos + _cursor_relative_click; sui_transform_point(anchor); @@ -820,14 +778,14 @@ void(string id, vector size, vector contentsize, __inout vector offset, vector s offset_y += (diff * contentsize_y) / size_y; // * contentsize_y; // (size_y / contentsize_y); } - sui_fill(barpos, barsize, '0.1 0.1 0.1' * (1 - sui_is_hovered(barname)), 0.66, 0); - sui_action_element(barpos, barsize, barname, sui_noop); + sui_fill(barpos, barsize, '0.1 0.1 0.1' * (1 - sui_is_hovered(id)), 0.66, 0); + sui_action_element(barpos, barsize, id, sui_noop); sui_pop_frame(); } sui_pop_frame(); }; -void(string id, vector pos, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scroll_view_begin = +void(PanelID id, vector pos, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scroll_view_begin = { // make space for scrollbars sui_push_frame(pos, size - [scrollbar_widths_y, scrollbar_widths_x]); @@ -876,7 +834,7 @@ float _sui_list_first; float _sui_list_last; float _sui_list_pos; int _sui_list_index; -void(string id, vector pos, vector size, vector itemsize, float numitems, __inout vector offset, vector scrollbar_widths) sui_list_view_begin = +void(PanelID id, vector pos, vector size, vector itemsize, float numitems, __inout vector offset, vector scrollbar_widths) sui_list_view_begin = { vector contentsize = [itemsize_x, itemsize_y * numitems]; sui_scroll_view_begin(id, pos, size, contentsize, offset, scrollbar_widths); @@ -902,7 +860,7 @@ void() sui_list_view_end = sui_scroll_view_end(); }; -string(string id, vector pos, vector size, string name, string command) sui_binder = +string(PanelID id, vector pos, vector size, string name, string command) sui_binder = { sui_action_element(pos, size, id, sui_noop); if (sui_is_released(id)) @@ -935,7 +893,7 @@ void() sui_draw_bind_overlay = * Flags: 1 = No Border * */ -float(string id, vector pos, vector size, string text, vector colour, vector textsize, vector textcolour, float alignment, float padding, float alpha, float textalpha, float flags) hud_colour_button = +float(PanelID id, vector pos, vector size, string text, vector colour, vector textsize, vector textcolour, float alignment, float padding, float alpha, float textalpha, float flags) hud_colour_button = { sui_push_frame(pos, size); vector basecolor = sui_is_hovered(id) ? colour + MENU_HIGHLIGHT * 0.1 : colour; @@ -956,7 +914,7 @@ float(string id, vector pos, vector size, string text, vector colour, vector tex return sui_is_clicked(id); }; -float(string id, vector pos, vector size, string text) hud_button = { +float(PanelID id, vector pos, vector size, string text) hud_button = { return hud_colour_button(id, pos, size, text, MENU_BUTTON, MENU_TEXT_SMALL, MENU_TEXT_1, SUI_ALIGN_CENTER, 0, 0.6, 1, 0); } From 51018bbbc5c91e12fb137e030f9549487678fda5 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 2 Nov 2022 23:22:17 -0700 Subject: [PATCH 1843/2474] Hud fixes and clean-up - Ensure the options panel is rendered last, so that it does not fall under huge panels (e.g. map vote, or scores) when their properties are edited. - Eliminate "DrawPanel" semantics, these seem unnecessary and were leading to bugs where (for example) identify was inheriting the size of other panels during editing. - Don't allow unsafe properties such as scale on the options panel to be edited (instant loop that pushes you to max/min since it moves the panel with the slider.) --- csqc/csextradefs.qc | 9 ++- csqc/hud.qc | 167 +++++++++++++++++++------------------------- csqc/hud_helpers.qc | 39 ++++------- csqc/menu.qc | 2 +- csqc/status.qc | 6 +- 5 files changed, 92 insertions(+), 131 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index ec16e9ba..0168452d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -399,8 +399,7 @@ float TeamScore[4]; enum PanelID:float { HUDP_INVALID = 0, // Reserve 0 so we can recognize an uninit menu HUDP_FIRST = 100, - HUDP_OPTIONS = HUDP_FIRST, - HUDP_CLIPSIZE, + HUDP_CLIPSIZE = HUDP_FIRST, HUDP_FRAGSTREAK, HUDP_CAPS, HUDP_GREN1, @@ -446,7 +445,9 @@ enum PanelID:float { HUDP_GUN7, HUDP_GUN8, HUDP_SPEED, - HUDP_LAST = HUDP_SPEED, + HUDP_OPTIONS, // Should be the last HUD element so that it's always on top. + HUDP_LAST = HUDP_OPTIONS, + HUDP_COUNT, HUDP_GAP = 500, // Just to make ids larger than this distinguishable. @@ -500,7 +501,6 @@ typedef struct { } FO_Hud_Panel; FO_Hud_Panel NullPanel; -FO_Hud_Panel DrawPanel; FO_Hud_Panel NewPanel; FO_Hud_Panel* MenuPanel; float Editor_SelectedPanel_Index; @@ -516,7 +516,6 @@ enumflags { FL_GT_ADJPING }; -float(PanelID) GetDrawPanel; void(string identify) Hud_DrawIdentifyPanel; void (float display, string text) Hud_DrawHudOptionsPanel; void (float playerclass) Hud_DrawClassInfoPanel; diff --git a/csqc/hud.qc b/csqc/hud.qc index 78fa336c..d1204e80 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1,16 +1,3 @@ -inline float GetDrawPanel(PanelID id) { - if (id >= HUDP_FIRST && id <= HUDP_LAST) { - DrawPanel = *getHudPanel(id); - return id; - } - return HUDP_INVALID; -} - -inline void SetDrawPanel(PanelID id) { - if (id >= HUDP_FIRST && id <= HUDP_LAST) - *getHudPanel(id) = DrawPanel; -} - void Hud_WriteCfg(string path) { // this overwrites @@ -736,30 +723,32 @@ void Hud_DrawHudOptionsPanel(float display, string text) { getHudPanel(HUDP_OPTIONS)->Status = !getHudPanel(HUDP_OPTIONS)->Status; } - float fscale = selectedPanel.Scale; - drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); - hud_slider(HUDE_OPTION_SCALE_SLIDER, pos + [8,24], [136,8], [0.2,5.0,24], fscale); - if(fscale != selectedPanel.Scale) { - getHudPanel(Editor_SelectedPanel_Index)->Scale = fscale; - } - float ftscale = selectedPanel.TextScale; - drawstring(pos + [4,34], strcat("Text Scale: ",ftos(rint(ftscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); - hud_slider(HUDE_OPTION_TEXTSCALE_SLIDER, pos + [8,44], [136,8], [0,5.0,25], ftscale); - if(ftscale != selectedPanel.TextScale) - getHudPanel(Editor_SelectedPanel_Index)->TextScale = ftscale; - float ftextalign = selectedPanel.Orientation; - //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.Orientation ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); - drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); - if(hud_button(HUDE_OPTION_TEXTALIGN_TOGGLE, pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.Orientation])) { - getHudPanel(Editor_SelectedPanel_Index)->Orientation = (selectedPanel.Orientation + 1) % 3; - } - //hud_slider("hud_option_textalign_scroll", pos + [8,64], [32,8], [0,1,1], ftextalign); - //if(ftextalign != selectedPanel.Orientation) { - // getHudPanel(Editor_SelectedPanel_Index)->Orientation = ftextalign; - //} - if(hud_button(HUDE_OPTION_SHOWHIDE_TOGGLE, pos + [4,74], [140, 16], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { - getHudPanel(Editor_SelectedPanel_Index)->Display = !selectedPanel.Display; + if (selectedPanel != panel) { + float fscale = selectedPanel.Scale; + drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); + hud_slider(HUDE_OPTION_SCALE_SLIDER, pos + [8,24], [136,8], [0.2,5.0,24], fscale); + if(fscale != selectedPanel.Scale) + getHudPanel(Editor_SelectedPanel_Index)->Scale = fscale; + + float ftscale = selectedPanel.TextScale; + drawstring(pos + [4,34], strcat("Text Scale: ",ftos(rint(ftscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); + hud_slider(HUDE_OPTION_TEXTSCALE_SLIDER, pos + [8,44], [136,8], [0,5.0,25], ftscale); + if(ftscale != selectedPanel.TextScale) + getHudPanel(Editor_SelectedPanel_Index)->TextScale = ftscale; + float ftextalign = selectedPanel.Orientation; + //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.Orientation ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); + drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); + if(hud_button(HUDE_OPTION_TEXTALIGN_TOGGLE, pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.Orientation])) { + getHudPanel(Editor_SelectedPanel_Index)->Orientation = (selectedPanel.Orientation + 1) % 3; + } + //hud_slider("hud_option_textalign_scroll", pos + [8,64], [32,8], [0,1,1], ftextalign); + //if(ftextalign != selectedPanel.Orientation) { + // getHudPanel(Editor_SelectedPanel_Index)->Orientation = ftextalign; + //} + if(hud_button(HUDE_OPTION_SHOWHIDE_TOGGLE, pos + [4,74], [140, 16], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { + getHudPanel(Editor_SelectedPanel_Index)->Display = !selectedPanel.Display; + } } drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); @@ -808,39 +797,31 @@ void Hud_DrawHudOptionsPanel(float display, string text) { void Hud_DrawClassInfoPanel(float playerclass) { const float id = HUDP_SPECIAL; - vector pos; - pos = getPosition(id); //DrawPanel.Position; + FO_Hud_Panel* panel = getHudPanel(id); + vector pos = getPanelPosition(panel); if(fo_hud_editor) { - hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display); - drawpic(pos, "textures/wad/face1", FO_Hud_Icon_Size * DrawPanel.Scale, '1 1 1', 1, 0); + hud_panel(id, pos, panel->FillSize * panel->Scale, 0, panel->Display); + drawpic(pos, "textures/wad/face1", FO_Hud_Icon_Size * panel->Scale, '1 1 1', 1, 0); return; } - if (!fo_hud_editor && !DrawPanel.Display) + if (!fo_hud_editor && !panel->Display) return; - switch (SBAR.PlayerClass) - { + switch (SBAR.PlayerClass) { case PC_SOLDIER: return; } - if (SBAR.PlayerClass) - { - - if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) - { + if (SBAR.PlayerClass) { + if (hud_panel(id, pos, panel->FillSize * panel->Scale, 0, panel->Display)) { // click event - if (fo_hud_editor) - { - - } } float val; - vector size = FO_Hud_Icon_Size * DrawPanel.Scale; - vector fontSize = FO_Hud_Icon_Font_Size * (DrawPanel.TextScale ? DrawPanel.TextScale : DrawPanel.Scale); + vector size = FO_Hud_Icon_Size * panel->Scale; + vector fontSize = FO_Hud_Icon_Font_Size * (panel->TextScale ? panel->TextScale : panel->Scale); pos = [pos_x + 2, pos_y + 2, 0]; vector basepos = pos; vector colour = '1 1 1'; @@ -860,16 +841,16 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = SBAR.ScannerOn ? "Scanning" : "Offline"; - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.ScannerOn) { msg = SBAR.ScannerRange ? strcat("Dist: ", ftos(SBAR.ScannerRange)) : "No targets"; - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); if (SBAR.ScannerRange) { msg = (SBAR.ScannerTeamNo == team_no) ? "Friendly" : "Enemy"; msg = strcat(msg, " ", ClassToString(SBAR.ScannerPlayerClass)); - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } break; @@ -880,13 +861,13 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("Dam: ", ftos(SBAR.SniperDam)); - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.SniperMax) { msg = "(100%)"; colour = '1 0 0'; - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } break; @@ -897,10 +878,10 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Setting"; - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat(ftos(SBAR.DetpackLeft), " (", ftos(SBAR.IsDetpacking), ") secs left"); - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else if (SBAR.DetpackLeft) { @@ -908,7 +889,7 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat(ftos(SBAR.DetpackLeft), " secs left"); - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; case PC_MEDIC: @@ -916,28 +897,28 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = SBAR.AuraActive ? "On" : "Off"; - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.AuraActive) { if (SBAR.HealCount) { msg = strcat(ftos(SBAR.HealCount), " players healed"); - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); msg = strcat("for ", ftos(SBAR.HealAmount), " hp"); - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else { if (SBAR.AuraStatus == PC_MEDIC_AURA_OUTOFPOWER) { msg = "Out of power"; - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else if (SBAR.AuraStatus == PC_MEDIC_AURA_RECHARGING) { msg = "Recharging"; - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } } @@ -949,7 +930,7 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Assault Cannon Locked"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; case PC_PYRO: @@ -959,7 +940,7 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Airblast Cooling Down"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } else if (!SBAR.AirBlast) { @@ -967,7 +948,7 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Airblast Ready"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; case PC_SPY: @@ -979,14 +960,14 @@ void Hud_DrawClassInfoPanel(float playerclass) if (SBAR.InvisOnly) { msg = "Invisible"; - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } else { msg = "Undercover"; - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat(TeamToString(SBAR.UndercoverTeam), " ", ClassToString(SBAR.UndercoverSkin)); - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } else if (SBAR.IsUndercover == 2) @@ -997,14 +978,14 @@ void Hud_DrawClassInfoPanel(float playerclass) if (SBAR.InvisOnly) { msg = "Invisible"; - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat("In ", ftos(SBAR.UndercoverTimer), " secs"); - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else { msg = "Disguising"; - pos = DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.DisguiseTeam) { msg = strcat("(", TeamToString(SBAR.DisguiseTeam), SBAR.QueueSkin ? "" : ") "); @@ -1031,7 +1012,7 @@ void Hud_DrawClassInfoPanel(float playerclass) msg2 = strcat(ClassToString(SBAR.UndercoverSkin)); } msg = strcat(msg, msg2); - DrawOffsetString(msg, size, fontSize, pos, basepos, TRUE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } break; @@ -1042,7 +1023,7 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(rint(SBAR.SentryHealth)), " S: ", ftos(rint(SBAR.SentryAmmoShells)), " R: ", ftos(rint(SBAR.SentryAmmoRockets))); - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } else if (SBAR.IsBuilding) { @@ -1050,7 +1031,7 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat(ftos(SBAR.BuildingPercentage), "%"); - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } // disp @@ -1062,7 +1043,7 @@ void Hud_DrawClassInfoPanel(float playerclass) drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("H: ", ftos(rint(SBAR.DispenserHealth))); - DrawOffsetString(msg, size, fontSize, pos, basepos, FALSE, colour); + DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; } @@ -1071,39 +1052,31 @@ void Hud_DrawClassInfoPanel(float playerclass) void Hud_DrawIdentifyPanel(string identify) { const float id = HUDP_IDENTIFY; - DrawPanel = *getHudPanel(id); - if (!DrawPanel.Display && !fo_hud_editor) + FO_Hud_Panel* panel = getHudPanel(id); + if (!panel->Display && !fo_hud_editor) return; - - if(fo_hud_editor && !identify) { + + if(fo_hud_editor && !identify) identify = "\n"; - } vector pos; - pos = DrawPanel.Position; + pos = getPanelPosition(panel); - if (hud_panel(id, pos, DrawPanel.FillSize * DrawPanel.Scale, 0, DrawPanel.Display)) - { + if (hud_panel(id, pos, panel->FillSize * panel->Scale, 0, panel->Display)) { // click event - if (fo_hud_editor) - { - - } } - vector fontSize = FO_Hud_Icon_Font_Size * DrawPanel.Scale; + vector fontSize = FO_Hud_Icon_Font_Size * panel->Scale; float count = tokenizebyseparator(identify, "\n"); float msgcount = 0; string msg = ""; - for (float f = 0; f <= count; f++) - { + for (float f = 0; f <= count; f++) { msg = argv(f); // tokenize doesn't handle newlines very well msg = strreplace("\n", "", msg); msg = strtrim(msg); - if (strlen(msg) > 0) - { + if (strlen(msg) > 0) { pos = pos + [0, (fontSize_y * msgcount), 0]; drawstring(pos, msg, fontSize, '1 1 1', 1, 0); msgcount++; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index c9bd4b03..1524d372 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -1,6 +1,4 @@ void Hud_WriteCfg(string path); -float GetDrawPanel(PanelID id); -void SetDrawPanel(PanelID id); void FO_Hud_Editor() { @@ -49,24 +47,13 @@ void(PanelID id, vector pos, vector size, vector minmaxsteps, __inout float valu vector UpdatePos(PanelID id, vector mousepos) { + if (id < HUDP_FIRST || id > HUDP_LAST) + return '0 0 0'; + vector pos; -// switch (id) -// { -// case "flagiconpanel": -// if (HudSettings.MousePos != [0, 0]) -// { -// pos = HudSettings.FlagIcon.Position + mousepos - HudSettings.MousePos; -// HudSettings.FlagIcon.Position = pos; -// } -// break; - -// default: - GetDrawPanel(id); - pos = DrawPanel.Position + mousepos - HudSettings.MousePos; - DrawPanel.Position = pos; - SetDrawPanel(id); -// break; -// } + FO_Hud_Panel* panel = getHudPanel(id); + pos = panel->Position + mousepos - HudSettings.MousePos; + panel->Position = pos; return pos; } @@ -372,7 +359,7 @@ void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon, float icon_a return; vector pos; - pos = getPanelPosition(panel); //getPosition(fid); //DrawPanel.Position; + pos = getPanelPosition(panel); //getPosition(fid); vector scaledFillSize = panel.FillSize * panel.Scale; //if(scaledFill @@ -419,7 +406,7 @@ void Hud_DrawLMPThreshold(FO_Hud_Panel* panel, string val, float threshold) return; vector pos; - pos = getPanelPosition(panel); //getPosition(fid); //DrawPanel.Position; + pos = getPanelPosition(panel); float textScale = panel.TextScale ? panel.TextScale : panel.Scale; vector fillScale = panel.FillSize * textScale; @@ -453,19 +440,21 @@ void Hud_DrawLMPThreshold(FO_Hud_Panel* panel, string val, float threshold) Hud_DrawStringLMPThreshold(pos + [offset,0], val, textSize, threshold); } -vector GetStringOffsetPos(string msg, vector size, vector fontSize, vector pos, vector basepos, float newline) +vector GetStringOffsetPos(float orientation, string msg, vector size, vector fontSize, + vector pos, vector basepos, float newline) { float len, offset; len = strlen(msg); - offset = (DrawPanel.Orientation == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + size_x + (fontSize_x * len)) * -1; + offset = (orientation == FO_HUD_INSERT_BEFORE) ? 2 + size_x : (2 + size_x + (fontSize_x * len)) * -1; pos = [basepos_x + offset, newline ? pos_y + 2 + ((size_y - fontSize_y) * .5) : pos_y + ((size_y - fontSize_y) * .5), 0]; return pos; } -vector DrawOffsetString(string msg, vector size, vector fontSize, vector pos, vector basepos, float newline, vector colour) +vector DrawOffsetString(float orientation, string msg, vector size, + vector fontSize, vector pos, vector basepos, float newline, vector colour) { - pos = GetStringOffsetPos(msg, size, fontSize, pos, basepos, newline); + pos = GetStringOffsetPos(orientation, msg, size, fontSize, pos, basepos, newline); drawstring(pos, msg, fontSize, colour, 1, 0); return pos; diff --git a/csqc/menu.qc b/csqc/menu.qc index 74235485..bc000ecb 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -1329,7 +1329,7 @@ void FO_Hud_Init() { ASSERTD_EQ(i + HUDP_FIRST, Hud_Panels[i].id); float next_id = HUD_LAST + 1; - DrawPanel = *getHudPanel(HUDP_OPTIONS); // XXX + /* DrawPanel = *getHudPanel(HUDP_OPTIONS); // XXX */ INIT_MENU_IDS(FO_MENU_GAME); INIT_MENU_IDS(FO_MENU_GAME_SPECTATOR); INIT_MENU_IDS(FO_MENU_SPECTATOR_TRACK); diff --git a/csqc/status.qc b/csqc/status.qc index 25b927cb..3d956849 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -12,7 +12,7 @@ void(PanelID ignored, string text) drawClipSize = { }; void(PanelID ignored, string text) drawIdentify = { - if (strlen(SBAR.Identify) > 0 || fo_hud_editor) + if (strlen(text) > 0 || fo_hud_editor) Hud_DrawIdentifyPanel(text); }; @@ -1062,14 +1062,13 @@ var FO_Hud_Panel Hud_Panels[] = { // string getValue(), // Style, Snap, Status - {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return getHudPanel(DrawPanel.id)->Name;}, 1}, {HUDP_CLIPSIZE, "clipsize", FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return WP_GetClip(); }}, {HUDP_FRAGSTREAK, "fragstreak", FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, {HUDP_GREN2, "gren2", FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0, drawGren2Panel, {return ftos(getstatf(STAT_NO_GREN2));}}, {HUDP_SPECIAL, "playerclass", FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {HUDP_IDENTIFY, "identify", FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, drawTextPanel, {return SBAR.Identify;}}, + {HUDP_IDENTIFY, "identify", FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, drawIdentify, {return SBAR.Identify;}}, {HUDP_FLAGINFO, "flaginfo", FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0, drawFlagInfo, {return "";}}, {HUDP_GRENTIMER, "grentimer", FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0, drawGrenTimerPanel, {return "";}}, {HUDP_MENU, "menu", "Menu", '10 110', '300 200',1,0,1,0, drawSimplePanel, {return "";}}, @@ -1109,6 +1108,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_GUN7, "gun7", "Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, + {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return "";}, 1}, }; inline FO_Hud_Panel* (PanelID panelid) getHudPanel = { From 922d46aec58381fbb10bc7b006cd4f5a6283849a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 31 Oct 2022 14:42:27 -0700 Subject: [PATCH 1844/2474] Introduce HUD render cache The HUD code allows a fairly sophisticated extent of customization, however it is expensive to compute the end product of all of these knobs on a per-frame state. Instead of rendering from scratch every time, introduce a render time and an FPS target. For frames out of the FPS target we use the cached rendering. Improves average HUD render time to 1ms --- csqc/csextradefs.qc | 122 ++++++++++++++++++++++++++++++++++++++++++++ csqc/hud.qc | 122 ++++++++++++++++++++++---------------------- csqc/hud_helpers.qc | 30 +++++------ csqc/main.qc | 24 ++++++--- csqc/menu.qc | 8 +-- csqc/profile.qc | 2 +- csqc/status.qc | 16 +++--- csqc/sui_sys.qc | 14 ++--- 8 files changed, 233 insertions(+), 105 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 0168452d..09756bd8 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -526,6 +526,128 @@ float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel vector(PanelID) getPosition; vector(PanelID) getFillSize; +enum { + D_drawpic, + D_drawstring, + D_drawfill, +}; + +struct Draw_Args { + int type; + vector pos; + string s_arg; + vector size; + vector rgb; + float alpha; + float drawflag; +}; + +struct { + int enabled; + float last_update; + int draw_direct; + Draw_Args draw_cache[255]; + int draw_count; +} hud_render_cache; + +DEFCVAR_FLOAT(fo_hud_cache, 1) +DEFCVAR_FLOAT(fo_hud_fps, 60) + +// Returns true if HUD should be re-rendered this frame. +float HRC_NewFrame() { + float fps = max(min(CVARF(fo_hud_fps), 77 * 2), 30); + + // Rate limit even the more complicated enable checks. + if (time < hud_render_cache.last_update + 1/fps) + return !hud_render_cache.enabled; + hud_render_cache.last_update = time; + + if (!CVARF(fo_hud_cache) || + fo_hud_menu_active || fo_hud_editor || showingscores) { + // Either explicitly disabled, or rendering a more complicated scene + // like the editor for which we'll just display in place. + hud_render_cache.enabled = FALSE; + return TRUE; + } + + + hud_render_cache.enabled = TRUE; + hud_render_cache.draw_count = 0; + + return TRUE; +} + +static inline Draw_Args* next_args() { + return &hud_render_cache.draw_cache[hud_render_cache.draw_count++]; +} + +void HRC_drawpic(vector pos, string pic, vector size, vector rgb='1 1 1', + float alpha=1, float drawflag=0) { + if (pic == "") + return; + /* print("draw ", pic, "\n"); */ + if (!hud_render_cache.enabled) { + drawpic(pos, pic, size, rgb, alpha, drawflag); + } else { + Draw_Args* args = next_args(); + args->type = D_drawpic; + args->pos = pos; + args->s_arg = pic; + args->size = size; + args->rgb = rgb; + args->alpha = alpha; + args->drawflag = drawflag; + } +} + +void HRC_drawstring(vector pos, string text, vector size, vector rgb='1 1 1', + float alpha=1, float drawflag=0) { + if (text == "") + return; + /* print("write ", text, "\n"); */ + if (!hud_render_cache.enabled) { + drawstring(pos, text, size, rgb, alpha, drawflag); + } else { + Draw_Args* args = next_args(); + args->type = D_drawstring; + args->pos = pos; + args->s_arg = text; + args->size = size; + args->rgb = rgb; + args->alpha = alpha; + args->drawflag = drawflag; + } +} + +void HRC_drawfill(vector pos, vector size, vector rgb, + float alpha=1, float drawflag=0) { + if (!hud_render_cache.enabled) { + drawfill(pos, size, rgb, alpha, drawflag); + } else { + Draw_Args* args = next_args(); + args->type = D_drawfill; + args->pos = pos; + args->size = size; + args->rgb = rgb; + args->alpha = alpha; + args->drawflag = drawflag; + } +} + +void HRC_Render() { + if (!hud_render_cache.enabled) + return; + + for (int i = 0; i < hud_render_cache.draw_count; i++) { + Draw_Args* args = &hud_render_cache.draw_cache[i]; + if (args->type == D_drawpic) + drawpic(args->pos, args->s_arg, args->size, args->rgb, args->alpha, args->drawflag); + else if (args->type == D_drawstring) + drawstring(args->pos, args->s_arg, args->size, args->rgb, args->alpha, args->drawflag); + else if (args->type == D_drawfill) + drawfill(args->pos, args->size, args->rgb, args->alpha, args->drawflag); + } +} class CsGrenTimer; CsGrenTimer grentimers[NUM_GREN_TIMERS]; diff --git a/csqc/hud.qc b/csqc/hud.qc index d1204e80..1f3c0023 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -579,7 +579,7 @@ void() Hud_DrawTeamScorePanel = { offset = (fillsize_x) * i; score_position_x = score_position_x + offset; //message = strcat(message, strpad(-3, ftos(TS.team1score))); - drawfill(score_position, fillsize, TEXT_TEAM_COLOUR[i], 0.5, 0); + HRC_drawfill(score_position, fillsize, TEXT_TEAM_COLOUR[i], 0.5, 0); val = ftos(TeamScore[i]); len = strlen(val); textOffset = (12 * textScale * (3 - len)); @@ -626,22 +626,22 @@ void Hud_DrawFlagStatusBar() float bigfontvoffset = sizey / 2 - bigfont / 2; //Center text against the icon if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); + // HRC_drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); + HRC_drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - // drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); - drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); + // HRC_drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); + HRC_drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); } - drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); + HRC_drawpic([pos_x, pos_y + sizey * i, 0], icon, [sizex, sizey, 0], iconcolour, alpha, 0); if (FlagInfoLines[i].timeleft >= 0) { string stime = ftos(FlagInfoLines[i].timeleft); float smallfont = 6 * getHudPanel(HUDP_FLAGINFO)->Scale; - drawstring([pos_x + sizex - stringwidth(stime, 1, [smallfont, smallfont]), pos_y + sizey * (i + 1) - smallfont, 0], stime, [smallfont, smallfont], '1 1 1', 1, 0); + HRC_drawstring([pos_x + sizex - stringwidth(stime, 1, [smallfont, smallfont]), pos_y + sizey * (i + 1) - smallfont, 0], stime, [smallfont, smallfont], '1 1 1', 1, 0); } } } @@ -666,7 +666,7 @@ void Hud_DrawHudOptionsPanelSelector() { vector size = getHudPanel(HUDP_OPTIONS)->FillSize * getHudPanel(HUDP_OPTIONS)->Scale; //for simplicity, use the same size as options panel float textsize = 8 * (getHudPanel(HUDP_OPTIONS)->TextScale ? getHudPanel(HUDP_OPTIONS)->TextScale : getHudPanel(HUDP_OPTIONS)->Scale); if((pos.x + (size.x * 2)) < ScreenSize.x) { - //If there's room on the screen, draw to the right of options panel + //If there's room on the screen, HRC_draw to the right of options panel pos.x = pos.x + size.x; } else { pos.x = pos.x - size.x; @@ -678,7 +678,7 @@ void Hud_DrawHudOptionsPanelSelector() { } float numlines = rint(size.y / (textsize + 2)); - //Need to draw scrollbar? + //Need to HRC_draw scrollbar? if((Hud_Panels.length * (textsize + 2)) > size.y) { //Scrollbar buttons if(hud_button(HUDB_OPTION_SCROLLUP, pos + [size.x - textsize - 2,2], [textsize, textsize], "^")) { @@ -722,23 +722,22 @@ void Hud_DrawHudOptionsPanel(float display, string text) { if(hud_button(HUDB_OPTION_LIST, pos + [4,2], [140, 10], strcat(selectedPanel.Name, " >"))) { getHudPanel(HUDP_OPTIONS)->Status = !getHudPanel(HUDP_OPTIONS)->Status; } - if (selectedPanel != panel) { float fscale = selectedPanel.Scale; - drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); hud_slider(HUDE_OPTION_SCALE_SLIDER, pos + [8,24], [136,8], [0.2,5.0,24], fscale); if(fscale != selectedPanel.Scale) getHudPanel(Editor_SelectedPanel_Index)->Scale = fscale; float ftscale = selectedPanel.TextScale; - drawstring(pos + [4,34], strcat("Text Scale: ",ftos(rint(ftscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [4,34], strcat("Text Scale: ",ftos(rint(ftscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); hud_slider(HUDE_OPTION_TEXTSCALE_SLIDER, pos + [8,44], [136,8], [0,5.0,25], ftscale); if(ftscale != selectedPanel.TextScale) getHudPanel(Editor_SelectedPanel_Index)->TextScale = ftscale; float ftextalign = selectedPanel.Orientation; //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.Orientation ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); - drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); if(hud_button(HUDE_OPTION_TEXTALIGN_TOGGLE, pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.Orientation])) { getHudPanel(Editor_SelectedPanel_Index)->Orientation = (selectedPanel.Orientation + 1) % 3; } @@ -750,9 +749,9 @@ void Hud_DrawHudOptionsPanel(float display, string text) { getHudPanel(Editor_SelectedPanel_Index)->Display = !selectedPanel.Display; } } - drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); - drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); - drawstring(pos + [10,116], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [10,106], strcat("x: ",ftos(selectedPanel.Position.x)), [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [10,116], strcat("y: ",ftos(selectedPanel.Position.y)), [8,8], MENU_SELECTED, 1, 0); local float snap = 0; local string ssnap; @@ -763,7 +762,7 @@ void Hud_DrawHudOptionsPanel(float display, string text) { } else { snap = 0; } - drawstring(pos + [4,130], "Hor. Snap: ", [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [4,130], "Hor. Snap: ", [8,8], MENU_SELECTED, 1, 0); if(hud_button(HUDE_OPTION_HSNAP_TOGGLE, pos + [size.x - 6 - 56,126], [56, 16], HUD_HORIZONTAL_ALIGN[snap])) { snap = (snap + 1) % 3; getHudPanel(Editor_SelectedPanel_Index)->Position.x = 0; @@ -777,7 +776,7 @@ void Hud_DrawHudOptionsPanel(float display, string text) { } else { snap = 0; } - drawstring(pos + [4,148], "Ver. Snap: ", [8,8], MENU_SELECTED, 1, 0); + HRC_drawstring(pos + [4,148], "Ver. Snap: ", [8,8], MENU_SELECTED, 1, 0); if(hud_button(HUDE_OPTION_VSNAP_TOGGLE, pos + [size.x - 6 - 56,144], [56, 16], HUD_VERTICAL_ALIGN[snap])) { snap = (snap + 1) % 3; getHudPanel(Editor_SelectedPanel_Index)->Position.y = 0; @@ -802,7 +801,7 @@ void Hud_DrawClassInfoPanel(float playerclass) if(fo_hud_editor) { hud_panel(id, pos, panel->FillSize * panel->Scale, 0, panel->Display); - drawpic(pos, "textures/wad/face1", FO_Hud_Icon_Size * panel->Scale, '1 1 1', 1, 0); + HRC_drawpic(pos, "textures/wad/face1", FO_Hud_Icon_Size * panel->Scale, '1 1 1', 1, 0); return; } @@ -830,7 +829,7 @@ void Hud_DrawClassInfoPanel(float playerclass) //icon = HudIcons[playerclass-1].icon; /* icon = HudIcons[playerclass+6].icon; */ - /* drawpic(pos, icon, size, '1 1 1', 1, 0); */ + /* HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); */ float len = 0, offset = 0; @@ -838,19 +837,19 @@ void Hud_DrawClassInfoPanel(float playerclass) { case PC_SCOUT: icon = ICON_SCOUT; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = SBAR.ScannerOn ? "Scanning" : "Offline"; - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.ScannerOn) { msg = SBAR.ScannerRange ? strcat("Dist: ", ftos(SBAR.ScannerRange)) : "No targets"; - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); if (SBAR.ScannerRange) { msg = (SBAR.ScannerTeamNo == team_no) ? "Friendly" : "Enemy"; msg = strcat(msg, " ", ClassToString(SBAR.ScannerPlayerClass)); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } break; @@ -858,16 +857,16 @@ void Hud_DrawClassInfoPanel(float playerclass) if (SBAR.SniperDam) { icon = ICON_SNIPER; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("Dam: ", ftos(SBAR.SniperDam)); - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.SniperMax) { msg = "(100%)"; colour = '1 0 0'; - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } break; @@ -875,50 +874,50 @@ void Hud_DrawClassInfoPanel(float playerclass) if (SBAR.IsDetpacking) { icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Setting"; - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat(ftos(SBAR.DetpackLeft), " (", ftos(SBAR.IsDetpacking), ") secs left"); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else if (SBAR.DetpackLeft) { icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat(ftos(SBAR.DetpackLeft), " secs left"); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; case PC_MEDIC: icon = ICON_MEDIC; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = SBAR.AuraActive ? "On" : "Off"; - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.AuraActive) { if (SBAR.HealCount) { msg = strcat(ftos(SBAR.HealCount), " players healed"); - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); msg = strcat("for ", ftos(SBAR.HealAmount), " hp"); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else { if (SBAR.AuraStatus == PC_MEDIC_AURA_OUTOFPOWER) { msg = "Out of power"; - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else if (SBAR.AuraStatus == PC_MEDIC_AURA_RECHARGING) { msg = "Recharging"; - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } } @@ -927,65 +926,65 @@ void Hud_DrawClassInfoPanel(float playerclass) if (WP_LockedCannon()) { icon = ICON_HWGUY; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Assault Cannon Locked"; - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; case PC_PYRO: if (SBAR.AirBlast) { icon = ICON_PYRO; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Airblast Cooling Down"; - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } else if (!SBAR.AirBlast) { icon = ICON_PYRO; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = "Airblast Ready"; - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; case PC_SPY: if (SBAR.IsUndercover == 1) { icon = ICON_SPY; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.InvisOnly) { msg = "Invisible"; - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } else { msg = "Undercover"; - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat(TeamToString(SBAR.UndercoverTeam), " ", ClassToString(SBAR.UndercoverSkin)); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } else if (SBAR.IsUndercover == 2) { icon = ICON_SPY; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); if (SBAR.InvisOnly) { msg = "Invisible"; - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); msg = strcat("In ", ftos(SBAR.UndercoverTimer), " secs"); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } else { msg = "Disguising"; - pos = DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); if (SBAR.DisguiseTeam) { msg = strcat("(", TeamToString(SBAR.DisguiseTeam), SBAR.QueueSkin ? "" : ") "); @@ -1012,7 +1011,7 @@ void Hud_DrawClassInfoPanel(float playerclass) msg2 = strcat(ClassToString(SBAR.UndercoverSkin)); } msg = strcat(msg, msg2); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } break; @@ -1020,18 +1019,18 @@ void Hud_DrawClassInfoPanel(float playerclass) if (SBAR.HasSentry) { icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(rint(SBAR.SentryHealth)), " S: ", ftos(rint(SBAR.SentryAmmoShells)), " R: ", ftos(rint(SBAR.SentryAmmoRockets))); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } else if (SBAR.IsBuilding) { icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat(ftos(SBAR.BuildingPercentage), "%"); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } // disp @@ -1040,10 +1039,10 @@ void Hud_DrawClassInfoPanel(float playerclass) if (SBAR.HasDispenser) { icon = ICON_ENGINEER_DISP; //HudIcons[playerclass + 7].icon; - drawpic(pos, icon, size, '1 1 1', 1, 0); + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); msg = strcat("H: ", ftos(rint(SBAR.DispenserHealth))); - DrawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } break; } @@ -1078,7 +1077,7 @@ void Hud_DrawIdentifyPanel(string identify) { msg = strtrim(msg); if (strlen(msg) > 0) { pos = pos + [0, (fontSize_y * msgcount), 0]; - drawstring(pos, msg, fontSize, '1 1 1', 1, 0); + HRC_drawstring(pos, msg, fontSize, '1 1 1', 1, 0); msgcount++; } } @@ -1105,8 +1104,7 @@ void Hud_DrawPanel(FO_Hud_Panel* panel) { offset = (panel.FillSize.x / 2) - (strlen(panel.Name) * 3); //because 3 = 6/2 break; } - //drawstring(getHudPanel(i)->Position + [offset,2], getHudPanel(i)->Name, '6 6', '0 1 0', 1, 0); - drawstring(getScaledPanelPosition(panel,1) + [offset,2], panel.Name, '6 6', '0 1 0', 1, 0); + HRC_drawstring(getScaledPanelPosition(panel,1) + [offset,2], panel.Name, '6 6', '0 1 0', 1, 0); } } } diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 1524d372..ae3031a6 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -84,7 +84,7 @@ float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel alpha = 0.6; basecolor = MENU_BG + MENU_HIGHLIGHT * 0.1; //FO_Hud_Panel hoverpanel = GetPanelById(id); - //drawstring([Mouse.x, Mouse.y], hoverpanel.Name, '8 8', '1 0 0', 1, 0); + //HRC_drawstring([Mouse.x, Mouse.y], hoverpanel.Name, '8 8', '1 0 0', 1, 0); } if (sui_is_held(id)) @@ -109,7 +109,7 @@ float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel return sui_is_clicked(id); }; -// this draws backwards, haven't bothered to change as we don't use it +// this HRC_draws backwards, haven't bothered to change as we don't use it void Hud_DrawLargeValue(vector pos, float value, float threshhold, float size) { float c; @@ -126,13 +126,13 @@ void Hud_DrawLargeValue(vector pos, float value, float threshhold, float size) while(isamples.count, 2), avg->samples.max_count); *mean = avg->s1 / n; - *variance = (avg->s2 - sq(avg->s1)/n) / (n - 1); + *variance = (avg->s2 - sq(avg->s1) / n) / (n - 1); return n; } diff --git a/csqc/status.qc b/csqc/status.qc index 3d956849..abfef9cd 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -346,7 +346,7 @@ void(PanelID panelid, string text) drawTextPanel = { local float lines; if (fo_hud_editor) { string name = getHudPanel(panelid)->Name; - drawstring( + HRC_drawstring( [GetTextAlignOffset(position.x, size.x, padding, name, mediumtext.x, panel.Orientation), padding*2 + position.y], @@ -376,7 +376,7 @@ void(PanelID panelid, string text) drawTextPanel = { line = strreplace("\n", "", line); line = strtrim(line); if (strlen(line) > 0) { - drawstring( + HRC_drawstring( [GetTextAlignOffset(position.x, size.x, padding, line, mediumtext.x, panel.Orientation), position.y + padding + mediumtext.y*i], @@ -420,7 +420,7 @@ void(PanelID panelid, string text) drawMOTDPanel = { local string motd = serverkey("hostname"); sui_text([0,0], mediumtext*textscale*1.5, motd, MENU_TEXT_4, 1, 0); /* - drawstring( + HRC_drawstring( position + [size.x / 2 - stringwidth(motd,1,mediumtext*1.5)/2,padding*2], motd, mediumtext*1.5, @@ -443,7 +443,7 @@ void(PanelID panelid, string text) drawMOTDPanel = { if (strlen(tempstr) > 0) { sui_text([0,mediumtext.y*textscale * (i+2)], mediumtext*textscale, tempstr, MENU_TEXT_1, 1, 0); /* - drawstring( + HRC_drawstring( position + [size.x / 2 - stringwidth(motd,1,mediumtext)/2,padding*2 + mediumtext.y*(i+2)], motd, mediumtext, @@ -507,7 +507,7 @@ void(PanelID panelid, string text) drawGameModePanel = { } } if(message) { - drawstring( + HRC_drawstring( [GetTextAlignOffset( position.x, size.x, padding, message, mediumtext.x, panel.Orientation), position.y], @@ -563,7 +563,7 @@ void(PanelID panelid, string text) drawReadyPanel = { panel.Orientation ); - drawstring( + HRC_drawstring( [pos_aligned, alert_text_position.y], alert_text_message, alert_text_size, textcolour, 1, 0 ); @@ -592,7 +592,7 @@ void(PanelID panelid, string text) drawReadyPanel = { panel.Orientation ); - drawstring( + HRC_drawstring( [pos_aligned, alert_text_position.y], alert_text_message, alert_text_size, textcolour, 1, 0 ); @@ -617,7 +617,7 @@ void(PanelID panelid, string text) drawReadyPanel = { } if(message) { pos_aligned = GetTextAlignOffset(position.x,size.x,padding,message,textsize.x,panel.Orientation); - drawstring( + HRC_drawstring( [pos_aligned, position.y], message, textsize, textcolour, 1, 0 ); } diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index cdbc1789..6d0a4c6a 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -679,14 +679,14 @@ void() sui_end = void(vector pos, vector size, vector color, float alpha, float flags) sui_fill = { sui_transform_box(pos, size); - drawfill(pos, size, color, alpha, flags); + HRC_drawfill(pos, size, color, alpha, flags); }; void(vector pos, vector size, string pic, vector color, float alpha, float flags) sui_pic = { sui_transform_box(pos, size); - drawpic(pos, pic, size, color, alpha, flags); + HRC_drawpic(pos, pic, size, color, alpha, flags); }; void(vector pos, vector size, float width, vector color, float alpha, float flags) sui_border_box = @@ -694,13 +694,13 @@ void(vector pos, vector size, float width, vector color, float alpha, float flag sui_transform_box(pos, size); // Top line - drawfill(pos, [size_x, width], color, alpha, flags); + HRC_drawfill(pos, [size_x, width], color, alpha, flags); // Bottom line - drawfill([pos_x, pos_y + size_y - width], [size_x, width], color, alpha, flags); + HRC_drawfill([pos_x, pos_y + size_y - width], [size_x, width], color, alpha, flags); // Left line - drawfill([pos_x, pos_y + width], [width, size_y - width * 2], color, alpha, flags); + HRC_drawfill([pos_x, pos_y + width], [width, size_y - width * 2], color, alpha, flags); // Right line - drawfill([pos_x + size_x - width, pos_y + width], [width, size_y - width * 2], color, alpha, flags); + HRC_drawfill([pos_x + size_x - width, pos_y + width], [width, size_y - width * 2], color, alpha, flags); }; @@ -708,7 +708,7 @@ void(vector pos, vector size, string text, vector color, float alpha, float flag { sui_transform_box(pos, [stringwidth(text, 1, size), size_y]); - drawstring(pos, text, size, color, alpha, flags); + HRC_drawstring(pos, text, size, color, alpha, flags); }; void(float index, vector click_ratios) sui_noop = {}; From 5e179a9c18b02e4dba432868928b106a3f7b919b Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 1 Nov 2022 00:39:53 -0700 Subject: [PATCH 1845/2474] Implement partial rendering Now that we have a render cache, we can apply a very good trick: we don't need to render all of the hud every frame. Instead, implement a per-element timing and FPS (controlled by fo_hud_fps) so that we only render one element per frame -- the oldest element that needs rendering. If no elements need rendering, then do nothing. This improves average HUD render time to 0.07ms, with a maximum observed time of 0.2ms. FPS with moderate geometry improves by ~400-500fps on my machine, with simple geometry >1000fps. Even though people play with an FPS cap, the important change is that the frame latency reduction reduces the sensation of mouse hitches when there are expensive hud elements. --- csqc/csextradefs.qc | 70 +++++++++++++++++++++++++++++++++++---------- csqc/hud.qc | 51 +++++++++++++++++++++++++++++++++ csqc/main.qc | 31 ++++++++++---------- 3 files changed, 122 insertions(+), 30 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 09756bd8..85f93330 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -447,7 +447,6 @@ enum PanelID:float { HUDP_SPEED, HUDP_OPTIONS, // Should be the last HUD element so that it's always on top. HUDP_LAST = HUDP_OPTIONS, - HUDP_COUNT, HUDP_GAP = 500, // Just to make ids larger than this distinguishable. @@ -476,7 +475,6 @@ enum PanelID:float { HUDL_FIRST = HUDB_LAST, HUDL_OPTION_BASE = 1000, HUDL_MAP_BASE = 2000, - HUDL_LAST = 3000, HUD_LAST = 10000, }; @@ -527,12 +525,14 @@ vector(PanelID) getPosition; vector(PanelID) getFillSize; enum { + D_skip, D_drawpic, D_drawstring, D_drawfill, }; struct Draw_Args { + PanelID id; int type; vector pos; string s_arg; @@ -544,23 +544,32 @@ struct Draw_Args { struct { int enabled; + PanelID active_panel; float last_update; int draw_direct; Draw_Args draw_cache[255]; int draw_count; + float free_cache[255]; + int free_count; } hud_render_cache; DEFCVAR_FLOAT(fo_hud_cache, 1) DEFCVAR_FLOAT(fo_hud_fps, 60) +enum { + HRC_NF_NO_UPDATE = 0, + HRC_NF_FULL, + HRC_NF_PARTIAL, +}; + +inline float HRC_fps_time() { return 1/max(min(CVARF(fo_hud_fps), 77 * 2), 30); } + // Returns true if HUD should be re-rendered this frame. float HRC_NewFrame() { - float fps = max(min(CVARF(fo_hud_fps), 77 * 2), 30); - // Rate limit even the more complicated enable checks. - if (time < hud_render_cache.last_update + 1/fps) - return !hud_render_cache.enabled; - hud_render_cache.last_update = time; + /* if (time < hud_render_cache.last_update + HRC_fps_time()) */ + /* return !hud_render_cache.enabled; */ + /* hud_render_cache.last_update = time; */ if (!CVARF(fo_hud_cache) || fo_hud_menu_active || fo_hud_editor || showingscores) { @@ -570,22 +579,52 @@ float HRC_NewFrame() { return TRUE; } - hud_render_cache.enabled = TRUE; - hud_render_cache.draw_count = 0; + return FALSE; +} + +void HRC_Invalidate(PanelID panel) { + float i, j; + + for (i = 0; i < hud_render_cache.draw_count; i++) { + if (hud_render_cache.draw_cache[i].id == panel + 1) { + hud_render_cache.draw_cache[i].id = 0; + hud_render_cache.draw_cache[i].type = D_skip; + hud_render_cache.free_cache[hud_render_cache.free_count++] = i; + } + } - return TRUE; + // Ascending order sort so that we don't end up inverting rendering order + // when pulling from the free-list. + for (i = 0; i < hud_render_cache.free_count; i++) + for (j = i + 1; j < hud_render_cache.free_count; j++) + if (hud_render_cache.free_cache[i] < hud_render_cache.free_cache[j]) { + float tmp = hud_render_cache.free_cache[i]; + hud_render_cache.free_cache[i] = hud_render_cache.free_cache[j]; + hud_render_cache.free_cache[j] = tmp; + } } -static inline Draw_Args* next_args() { - return &hud_render_cache.draw_cache[hud_render_cache.draw_count++]; +void HRC_SetActive(PanelID panel) { + hud_render_cache.active_panel = panel; +} + +static Draw_Args* next_args() { + float idx; + if (hud_render_cache.free_count) + idx = hud_render_cache.free_cache[--hud_render_cache.free_count]; + else + idx = hud_render_cache.draw_count++; + + Draw_Args* result = &hud_render_cache.draw_cache[idx]; + result->id = hud_render_cache.active_panel + 1; // 1-based, 0 => free. + return result; } void HRC_drawpic(vector pos, string pic, vector size, vector rgb='1 1 1', float alpha=1, float drawflag=0) { if (pic == "") return; - /* print("draw ", pic, "\n"); */ if (!hud_render_cache.enabled) { drawpic(pos, pic, size, rgb, alpha, drawflag); } else { @@ -604,7 +643,6 @@ void HRC_drawstring(vector pos, string text, vector size, vector rgb='1 1 1', float alpha=1, float drawflag=0) { if (text == "") return; - /* print("write ", text, "\n"); */ if (!hud_render_cache.enabled) { drawstring(pos, text, size, rgb, alpha, drawflag); } else { @@ -640,7 +678,9 @@ void HRC_Render() { for (int i = 0; i < hud_render_cache.draw_count; i++) { Draw_Args* args = &hud_render_cache.draw_cache[i]; - if (args->type == D_drawpic) + if (args->type == D_skip) + continue; + else if (args->type == D_drawpic) drawpic(args->pos, args->s_arg, args->size, args->rgb, args->alpha, args->drawflag); else if (args->type == D_drawstring) drawstring(args->pos, args->s_arg, args->size, args->rgb, args->alpha, args->drawflag); diff --git a/csqc/hud.qc b/csqc/hud.qc index 1f3c0023..017996ed 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1120,3 +1120,54 @@ void Hud_Draw(float width, float height) } HudSettings.MousePos = [Mouse.x, Mouse.y]; } + +const static float HUDP_COUNT = HUDP_LAST - HUDP_FIRST + 1; + +struct { + float last_draw[HUDP_COUNT]; + float idx; +} incremental_hud; + +void Hud_UpdateView(float width, float height, float menushown, float perf_sample) { + float hud_update = HRC_NewFrame(); + + if (HRC_NewFrame()) { + float hts = perf_start_sample(&hud_timing, perf_sample); + ScreenSize = [width, height, menushown]; + SBAR.Hint = ""; + sui_begin(width, height); + Menu_Draw(width, height, menushown); + Hud_Draw(width, height); + sui_end(); + perf_finish_sample(&hud_timing, hts); + return; + } + + if (!hud_render_cache.enabled) + return; + + // Skip any not-displayed elements. + float i = 0, idx = incremental_hud.idx; + while (!getHudPanel(HUDP_FIRST + idx)->Display && + i < HUDP_COUNT) { i++; idx = (idx + 1) % HUDP_COUNT; + } + incremental_hud.idx = idx; + + PanelID id = idx + HUDP_FIRST; + // Time ordered and oldest. + if (time >= incremental_hud.last_draw[idx] + HRC_fps_time()) { + float hts = perf_start_sample(&hud_partial_timing, perf_sample); + sui_begin(width, height); + HRC_Invalidate(id); + HRC_SetActive(id); + Hud_DrawPanel(getHudPanel(id)); + sui_end(); + perf_finish_sample(&hud_partial_timing, hts); + + incremental_hud.last_draw[idx] = time; + // We'll start searching from here for next incremental update. + incremental_hud.idx = (incremental_hud.idx + 1) % HUDP_COUNT; + } + + HRC_Render(); +} diff --git a/csqc/main.qc b/csqc/main.qc index 7a7b8b40..d9e93539 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -21,6 +21,7 @@ void GetSelf() = { DECLARE_PERF_SAMPLER(frame_timing, 60, 0.1); DECLARE_PERF_SAMPLER(hud_timing, 60, 0.1); +DECLARE_PERF_SAMPLER(hud_partial_timing, 60, 0.1); noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); @@ -33,6 +34,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { INIT_PERF_SAMPLER(frame_timing); INIT_PERF_SAMPLER(hud_timing); + INIT_PERF_SAMPLER(hud_partial_timing); FO_Hud_Init(); FO_Weapons_Init(); @@ -120,8 +122,7 @@ noref void() CSQC_WorldLoaded = { localcmd("menu_restart\n"); } -float HRC_NewFrame(); -void HRC_Render(); +void Hud_UpdateView(float width, float height, float menushown, float perf_sample); noref void(float width, float height, float menushown) CSQC_UpdateView = { float fts = perf_start_sample(&frame_timing); @@ -137,19 +138,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); - static float last; - - if (HRC_NewFrame()) { - float hts = perf_start_sample(&hud_timing, fts); - ScreenSize = [width, height, menushown]; - SBAR.Hint = ""; - sui_begin(width, height); - Menu_Draw(width, height, menushown); - Hud_Draw(width, height); - sui_end(); - perf_finish_sample(&hud_timing, hts); - } - HRC_Render(); + Hud_UpdateView(width, height, menushown, fts); if (CVARF(fo_csjumpsounds)) { local float health = getstatf(STAT_HEALTH); @@ -570,6 +559,11 @@ void Perf_Status() { if (prec > 3) printf("gettime() timing = %0.5f\n", gettime_lat()); + + printf("HUD cache used=%d freelist=%d\n", + (float)hud_render_cache.draw_count, + (float)hud_render_cache.free_count); + compute_avg(&frame_timing.samples, &avg, &variance); compute_maxmin(&frame_timing.samples, &minv, &maxv); printf(" Frame render (%d) avg=%s var=%0.3f min=%s max=%s\n", @@ -583,4 +577,11 @@ void Perf_Status() { (float)min(hud_timing.samples.count, hud_timing.samples.max_count), to_precision(avg, prec), variance, to_precision(minv, prec), to_precision(maxv, prec)); + + compute_avg(&hud_partial_timing.samples, &avg, &variance); + compute_maxmin(&hud_partial_timing.samples, &minv, &maxv); + printf(" HUD partial (%d) avg=%s var=%0.3f min=%s max=%s\n", + (float)min(hud_partial_timing.samples.count, hud_partial_timing.samples.max_count), + to_precision(avg, prec), variance, + to_precision(minv, prec), to_precision(maxv, prec)); } From 99c4ebd75268d1c5c8987fdfb68dfd288a6e72b6 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 3 Nov 2022 03:40:18 -0700 Subject: [PATCH 1846/2474] Making profiling togglable Disable profiling by default, now controlled by fo_enable_profiling 0/1 --- csqc/profile.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/csqc/profile.qc b/csqc/profile.qc index 8dd724d9..b328cd34 100644 --- a/csqc/profile.qc +++ b/csqc/profile.qc @@ -1,3 +1,5 @@ +DEFCVAR_FLOAT(fo_enable_profiling, 0); + inline float sq(float x) { return x * x; } struct perf_samples { @@ -87,6 +89,9 @@ struct perf_sampler { }; float perf_start_sample(perf_sampler* ps, float force = FALSE) { + if (!CVARF(fo_enable_profiling)) + return FALSE; + if (time < ps->next_sample && !force) return FALSE; ps->sample_start = gettime(1); // cltime @@ -94,7 +99,7 @@ float perf_start_sample(perf_sampler* ps, float force = FALSE) { } void perf_finish_sample(perf_sampler* ps, float idx) { - if (idx == 0) + if (idx == FALSE) return; // Not sampled. ps->next_sample = cltime + (random() + random()) * ps->interval; perf_add_sample(&ps->samples, gettime(1) - ps->sample_start); From dff5279724418316cfc84b696bcb99f1c924fe5b Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 3 Nov 2022 17:43:00 -0700 Subject: [PATCH 1847/2474] Fix fo_hud cmd Use constants vs array index --- csqc/hud.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index 017996ed..8fb73139 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -74,9 +74,8 @@ void FO_Hud_Editor_LoadDefaultSettings() void FO_Hud_Editor_List_Panels() = { print("^1Available HUD Elements:^7\n"); - for(float i = 0; i < Hud_Panels.length; i++) { + for (float i = HUDP_FIRST; i <= HUDP_LAST; i++) print(getHudPanel(i)->SaveName, ": ", getHudPanel(i)->Name, "\n"); - } // for(float i = 0; i < Hud_ExtraPanels.length; i++) { // print(Hud_ExtraPanels[i].id, ": ", Hud_ExtraPanels[i].Name, "\n"); // } From 75a1fe6fa10f40115bd688f89c079233e9fbf9fe Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Nov 2022 03:10:09 +1100 Subject: [PATCH 1848/2474] Don't play jump sound when on ground and submerged. Bug here: https://www.twitch.tv/videos/1610646813 You can make this happen by looking down and moving forward while pressing jump. This commit also moves swimming sounds to client side for consistency. --- csqc/csextradefs.qc | 1 + csqc/events.qc | 2 + csqc/main.qc | 132 ++++++++++++++++++++++++++------------------ ssqc/client.qc | 4 +- 4 files changed, 82 insertions(+), 57 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1c5e9550..f2a1d79e 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -540,6 +540,7 @@ float speed; float jump_counter; float grentimer_waiting; float jumpsound_cooldown; +float swimsound_cooldown; float last_pmove_onground; float last_vel_z; diff --git a/csqc/events.qc b/csqc/events.qc index b68a0390..b986b9d9 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -454,6 +454,8 @@ float(float entnum, float channel, string soundname, float vol, float attenuatio case "player/land.wav": case "player/land2.wav": case "player/h2ojump.wav": + case "player/water1.wav": + case "player/water2.wav": if (CVARF(fo_csjumpsounds)) { return 1; } else { diff --git a/csqc/main.qc b/csqc/main.qc index f76a10c1..51424463 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,6 +14,7 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); +void PlayCSJumpSounds(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -132,35 +133,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Hud_Draw(width, height); sui_end(); - if (CVARF(fo_csjumpsounds)) { - local float health = getstatf(STAT_HEALTH); - local float paused = getstatf(STAT_PAUSED); - - if (pmove_onground && health > 0 && !paused) { - // jumping - getinputstate(clientcommandframe); // without this the input buttons are innacurate - if ((input_buttons & BUTTON2) && (pmove_vel_z < 180 /* not sliding */)) { - if (jumpsound_cooldown < time) { - jumpsound_cooldown = time + 0.01; - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); - } - } - - // landing - if (!last_pmove_onground && last_vel_z < -300) { - if (pointcontents(pmove_org) == CONTENT_WATER) { - localsound("player/h2ojump.wav", CHAN_VOICE, 1); - } else if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_VOICE, 1); - } else { - localsound("player/land.wav", CHAN_VOICE, 1); - } - } - } - - last_vel_z = pmove_vel_z; - last_pmove_onground = pmove_onground; - } + PlayCSJumpSounds(); } noref float(string cmd) CSQC_ConsoleCommand = { @@ -351,30 +324,30 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-dropflag": localcmd("-button7\n"); break; - // case "+quick1": - // localcmd("+button8\n"); - // break; - // case "-quick1": - // localcmd("-button8\n"); - // break; - // case "+quick2": - // localcmd("+button9\n"); - // break; - // case "-quick2": - // localcmd("-button9\n"); - // break; - // case "+quick3": - // localcmd("+button10\n"); - // break; - // case "-quick3": - // localcmd("-button10\n"); - // break; - // case "+quick4": - // localcmd("+button11\n"); - // break; - // case "-quick4": - // localcmd("-button11\n"); - // break; + // case "+quick1": + // localcmd("+button8\n"); + // break; + // case "-quick1": + // localcmd("-button8\n"); + // break; + // case "+quick2": + // localcmd("+button9\n"); + // break; + // case "-quick2": + // localcmd("-button9\n"); + // break; + // case "+quick3": + // localcmd("+button10\n"); + // break; + // case "-quick3": + // localcmd("-button10\n"); + // break; + // case "+quick4": + // localcmd("+button11\n"); + // break; + // case "-quick4": + // localcmd("-button11\n"); + // break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { localcmd("+button4\n"); @@ -491,7 +464,7 @@ void _Sync_ServerCommandFrame() { is_observer = FALSE; vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), - getstatf(STAT_VELOCITY_Z)]; + getstatf(STAT_VELOCITY_Z)]; speed = sqrt(vel.x * vel.x + vel.y * vel.y); local float health = getstatf(STAT_HEALTH); @@ -516,7 +489,7 @@ void _Sync_ClientCommandFrame() { // Client command frames are regenerated beyond the server frame, so we // cannot check that we have not seen this client command frame alone. if (last_servercommandframe == servercommandframe && - last_clientcommandframe == clientcommandframe) + last_clientcommandframe == clientcommandframe) return; last_clientcommandframe = clientcommandframe; } @@ -527,3 +500,52 @@ void Sync_GameState() { _Sync_ServerCommandFrame(); _Sync_ClientCommandFrame(); } + +void PlayCSJumpSounds() { + if (!CVARF(fo_csjumpsounds)) { + return; + } + + if (getstatf(STAT_PAUSED)) { + return; + } + + if (pmove_onground && getstatf(STAT_HEALTH) > 0) { + // jumping + local float org = pointcontents(pmove_org); + local float submerged = (org == CONTENT_WATER || org == CONTENT_SLIME || org == CONTENT_LAVA); + getinputstate(clientcommandframe); // without this the input buttons are innacurate + + if ((input_buttons & BUTTON2) && (pmove_vel_z < 180 /* not sliding */)) { + if (submerged) { + if (swimsound_cooldown < time) { + swimsound_cooldown = time + 1; + if (random() < 0.5) { + localsound("player/water1.wav", CHAN_BODY, 1); + } else { + localsound("player/water2.wav", CHAN_BODY, 1); + } + } + } else { + if (jumpsound_cooldown < time) { + jumpsound_cooldown = time + 0.013; // should be inverse of server fps; + localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + } + } + } + + // landing + if (!last_pmove_onground && last_vel_z < -300) { + if (pointcontents(pmove_org) == CONTENT_WATER) { + localsound("player/h2ojump.wav", CHAN_VOICE, 1); + } else if (last_vel_z < -650) { + localsound("player/land2.wav", CHAN_VOICE, 1); + } else { + localsound("player/land.wav", CHAN_VOICE, 1); + } + } + } + + last_vel_z = pmove_vel_z; + last_pmove_onground = pmove_onground; +}; diff --git a/ssqc/client.qc b/ssqc/client.qc index c8f84dc5..f7b9d6c8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2516,9 +2516,9 @@ void () PlayerJump = { return; if (self.waterlevel >= 2) { - if (self.watertype == -3) + if (self.watertype == CONTENT_WATER) self.velocity_z = 100; - else if (self.watertype == -4) + else if (self.watertype == CONTENT_SLIME) self.velocity_z = 80; else self.velocity_z = 50; From 931760d3e7461296160bf5c133ed0ad498718f34 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 5 Nov 2022 03:33:17 +1100 Subject: [PATCH 1849/2474] Don't assume server maxfps --- csqc/csextradefs.qc | 2 ++ csqc/main.qc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f2a1d79e..468e7dee 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -561,3 +561,5 @@ string(string s) strtrim = #0:strtrim; /* Trims the whitespace from the start+end of the string. */ float(float playernum, string keyname, optional float assumevalue) getplayerkeyfloat = #0:getplayerkeyfloat; /* Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ +float(string key, optional float assumevalue) serverkeyfloat = #0:serverkeyfloat; /* + Version of serverkey that returns the value as a float (which avoids tempstrings). */ diff --git a/csqc/main.qc b/csqc/main.qc index 51424463..579d28f4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -528,7 +528,7 @@ void PlayCSJumpSounds() { } } else { if (jumpsound_cooldown < time) { - jumpsound_cooldown = time + 0.013; // should be inverse of server fps; + jumpsound_cooldown = time + (1 / serverkeyfloat("maxfps")); localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); } } From 60af5de1be83f65a3291fdf76977b5b3552c35ac Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 5 Nov 2022 01:52:36 -0700 Subject: [PATCH 1850/2474] HUD fixes - The HUD editor let you arbitrarily hide/show panels such as the map menu. Clients that had this as shown were getting it stuck in the render cache. Introduce system panels for which this type of edit is not possible and sanitize on load/save. - Reorder panels so that large panels render on the bottom for editing. - Dead code cleanup and removal. --- csqc/csextradefs.qc | 18 +++++--- csqc/events.qc | 1 + csqc/hud.qc | 79 ++++++++++++--------------------- csqc/hud_helpers.qc | 57 ++++++++++++++++++++---- csqc/menu.qc | 5 +-- csqc/status.qc | 105 +++++++++++++++++++++++--------------------- 6 files changed, 146 insertions(+), 119 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 85f93330..cf74e7ab 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -399,7 +399,12 @@ float TeamScore[4]; enum PanelID:float { HUDP_INVALID = 0, // Reserve 0 so we can recognize an uninit menu HUDP_FIRST = 100, - HUDP_CLIPSIZE = HUDP_FIRST, + HUDP_TEAMSCORE = HUDP_FIRST, // We put this first so that we open to below. + HUDP_MAP_MENU, // We put these up front so that they are + HUDP_SHOWSCORES, // rendered under other elements when editing + HUDP_MENU, + HUDP_MENU_HINT, + HUDP_CLIPSIZE, HUDP_FRAGSTREAK, HUDP_CAPS, HUDP_GREN1, @@ -408,14 +413,9 @@ enum PanelID:float { HUDP_IDENTIFY, HUDP_FLAGINFO, HUDP_GRENTIMER, - HUDP_MENU, HUDP_MOTD, - HUDP_MENU_HINT, HUDP_GAME_MODE, HUDP_READY, - HUDP_SHOWSCORES, - HUDP_TEAMSCORE, - HUDP_MAP_MENU, HUDP_HEALTH, HUDP_FACE, HUDP_AMMO, @@ -490,6 +490,7 @@ typedef struct { float TextScale; float Display; float Orientation; + float System; // System panel display is not user managed (e.g. vote menu) void(float display, string text) drawPanel; string() getValue; float Style; @@ -605,6 +606,11 @@ void HRC_Invalidate(PanelID panel) { } } +void HRC_InvalidateAll() { + hud_render_cache.draw_count = 0; + hud_render_cache.free_count = 0; +} + void HRC_SetActive(PanelID panel) { hud_render_cache.active_panel = panel; } diff --git a/csqc/events.qc b/csqc/events.qc index 5f69a42b..bffd0859 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -269,6 +269,7 @@ void() CSQC_Parse_Event = { if(rtr) { round_time_remaining = time + rtr; } + FO_Hud_ShowPanel(HUDP_MOTD); break; case MSG_TEAM_SCORES: TeamScore[0] = readfloat(); diff --git a/csqc/hud.qc b/csqc/hud.qc index 8fb73139..d49c8de2 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -22,27 +22,6 @@ void FO_Hud_Editor_LoadDefaultSettings() // check struct, put defaults in float yoffset = height - 64; - // TODO - maybe implement these to allow for pivoting of items -/* - vector pos, fill; - float scale, display, Orientation; - pos = [width - 8 - FO_HUD_CLIPSIZE_PANEL_X, height - 8 - FO_HUD_CLIPSIZE_PANEL_Y]; - scale = 1; - display = 1; - Orientation = FO_HUD_INSERT_BEFORE; - fill = [FO_HUD_CLIPSIZE_PANEL_X, FO_HUD_CLIPSIZE_PANEL_Y]; - - for(float i = 0; i < Hud_Panels.length; i++) { - pos = [pos_x, pos_y - 2 - 24]; - getHudPanel(i)->Position = pos; - //getHudPanel(i)->FillSize = fillSize; - getHudPanel(i)->Scale = scale; - getHudPanel(i)->Display = display; - getHudPanel(i)->Orientation = Orientation; - //pnl.Name = name; - } -*/ - //Default menus, id, ready and MOTD to centre of the screen getHudPanel(HUDP_GAME_MODE)->Position = [width - getHudPanel(HUDP_GAME_MODE)->FillSize.x, 30]; getHudPanel(HUDP_GAME_MODE)->Orientation = FO_HUD_INSERT_AFTER; @@ -70,6 +49,7 @@ void FO_Hud_Editor_LoadDefaultSettings() getHudPanel(HUDP_TEAMSCORE)->Position = [(width - getHudPanel(HUDP_TEAMSCORE)->FillSize.x), 0]; getHudPanel(HUDP_MAP_MENU)->Position = [(width / 2) - (getHudPanel(HUDP_MAP_MENU)->FillSize.x / 2), 30]; getHudPanel(HUDP_MAP_MENU)->Scale = 1.00; + getHudPanel(HUDP_MAP_MENU)->Display = 0; } void FO_Hud_Editor_List_Panels() = { @@ -198,7 +178,7 @@ void FO_Hud_Editor_Set_Panel_Setting(string panel_name, string setting, string v panel.TextScale = stof(value); break; case "show": - panel.Display = stof(value); + FO_Hud_SetDisplay(panel->id, stof(value)); break; case "orientation": panel.Orientation = stof(value); @@ -273,20 +253,15 @@ void() Hud_DrawMapMenuPanel = { local vector fillsize = panel.FillSize * panel.Scale; local float alpha = fo_hud_editor?0.2:0.9; local vector position = getPanelPosition(panel); - if(panel.Display) { + if(panel.Display) setcursormode(TRUE); - } if (hud_panel(panel->id, position, fillsize, alpha, panel.Display)) { // click event - if (fo_hud_editor) { - - } } - if(fo_hud_editor) { + if (fo_hud_editor) return; - } - + local vector bgcolour = MENU_BG_DARK, textcolour = MENU_TEXT_1; local float textscale = 1, padding = 4, cnt = 0; local float titlesize = 12; @@ -304,7 +279,7 @@ void() Hud_DrawMapMenuPanel = { local vector listviewsize = [listitemsize.x, fillsize.y - padding * 3 - listitemsize.y]; local float visiblelistitems = floor(listviewsize.y / listitemsize.y); - + //Window title sui_push_frame(position + [padding,padding], [fillsize.x - padding * 2, titlesize]); sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); @@ -625,12 +600,10 @@ void Hud_DrawFlagStatusBar() float bigfontvoffset = sizey / 2 - bigfont / 2; //Center text against the icon if (FlagInfoLines[i].state == FLAGINFO_CARRIED) { - // HRC_drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); HRC_drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].carrier,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].carrier, [bigfont,bigfont], '1 0 0', 1, 0); } else if (FlagInfoLines[i].state == FLAGINFO_DROPPED && FlagInfoLines[i].locname) { - // HRC_drawstring([pos_x + sizex, pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); HRC_drawstring([GetTextAlignOffset(pos_x,sizex,sizex,FlagInfoLines[i].locname,bigfont,getHudPanel(HUDP_FLAGINFO)->Orientation), pos_y + bigfontvoffset + sizey * i, 0], FlagInfoLines[i].locname, [bigfont,bigfont], '1 1 1', 1, 0); } @@ -665,7 +638,7 @@ void Hud_DrawHudOptionsPanelSelector() { vector size = getHudPanel(HUDP_OPTIONS)->FillSize * getHudPanel(HUDP_OPTIONS)->Scale; //for simplicity, use the same size as options panel float textsize = 8 * (getHudPanel(HUDP_OPTIONS)->TextScale ? getHudPanel(HUDP_OPTIONS)->TextScale : getHudPanel(HUDP_OPTIONS)->Scale); if((pos.x + (size.x * 2)) < ScreenSize.x) { - //If there's room on the screen, HRC_draw to the right of options panel + //If there's room on the screen, draw to the right of options panel pos.x = pos.x + size.x; } else { pos.x = pos.x - size.x; @@ -677,7 +650,7 @@ void Hud_DrawHudOptionsPanelSelector() { } float numlines = rint(size.y / (textsize + 2)); - //Need to HRC_draw scrollbar? + // Need to draw scrollbar? if((Hud_Panels.length * (textsize + 2)) > size.y) { //Scrollbar buttons if(hud_button(HUDB_OPTION_SCROLLUP, pos + [size.x - textsize - 2,2], [textsize, textsize], "^")) { @@ -722,30 +695,31 @@ void Hud_DrawHudOptionsPanel(float display, string text) { getHudPanel(HUDP_OPTIONS)->Status = !getHudPanel(HUDP_OPTIONS)->Status; } - if (selectedPanel != panel) { - float fscale = selectedPanel.Scale; + if (selectedPanel != panel /* Don't allow editing the options panel itself */) { + float fscale = selectedPanel->Scale; HRC_drawstring(pos + [4,12], strcat("Scale: ",ftos(rint(fscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); hud_slider(HUDE_OPTION_SCALE_SLIDER, pos + [8,24], [136,8], [0.2,5.0,24], fscale); - if(fscale != selectedPanel.Scale) - getHudPanel(Editor_SelectedPanel_Index)->Scale = fscale; + if(fscale != selectedPanel->Scale) + selectedPanel->Scale = fscale; - float ftscale = selectedPanel.TextScale; - HRC_drawstring(pos + [4,34], strcat("Text Scale: ",ftos(rint(ftscale * 100)), "%"), [8,8], MENU_SELECTED, 1, 0); + float ftscale = selectedPanel->TextScale; + string scales = ftscale ? strcat(ftos(rint(ftscale * 100)), "%") : "Auto"; + HRC_drawstring(pos + [4,34], strcat("Text Scale: ",scales), [8,8], MENU_SELECTED, 1, 0); hud_slider(HUDE_OPTION_TEXTSCALE_SLIDER, pos + [8,44], [136,8], [0,5.0,25], ftscale); - if(ftscale != selectedPanel.TextScale) + if(ftscale != selectedPanel->TextScale) getHudPanel(Editor_SelectedPanel_Index)->TextScale = ftscale; - float ftextalign = selectedPanel.Orientation; - //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel.Orientation ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); + float ftextalign = selectedPanel->Orientation; + //drawstring(pos + [4,54], strcat("Text Pos: ", selectedPanel->Orientation ? "Left" : "Right"), [8,8], MENU_SELECTED, 1, 0); HRC_drawstring(pos + [4,60], "Text Pos: ", [8,8], MENU_SELECTED, 1, 0); - if(hud_button(HUDE_OPTION_TEXTALIGN_TOGGLE, pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel.Orientation])) { - getHudPanel(Editor_SelectedPanel_Index)->Orientation = (selectedPanel.Orientation + 1) % 3; + if(hud_button(HUDE_OPTION_TEXTALIGN_TOGGLE, pos + [size.x - 6 - 56,56], [56, 16], HUD_ALIGN[selectedPanel->Orientation])) { + selectedPanel->Orientation = (selectedPanel->Orientation + 1) % 3; } //hud_slider("hud_option_textalign_scroll", pos + [8,64], [32,8], [0,1,1], ftextalign); - //if(ftextalign != selectedPanel.Orientation) { + //if(ftextalign != selectedPanel->Orientation) { // getHudPanel(Editor_SelectedPanel_Index)->Orientation = ftextalign; //} - if(hud_button(HUDE_OPTION_SHOWHIDE_TOGGLE, pos + [4,74], [140, 16], selectedPanel.Display ? "Hide Panel" : "Show Panel")) { - getHudPanel(Editor_SelectedPanel_Index)->Display = !selectedPanel.Display; + if(!selectedPanel->System && hud_button(HUDE_OPTION_SHOWHIDE_TOGGLE, pos + [4,74], [140, 16], selectedPanel->Display ? "Hide Panel" : "Show Panel")) { + FO_Hud_SetDisplay(selectedPanel->id, !selectedPanel->Display); } } HRC_drawstring(pos + [4,96],"Position: ", [8,8], MENU_SELECTED, 1, 0); @@ -754,9 +728,9 @@ void Hud_DrawHudOptionsPanel(float display, string text) { local float snap = 0; local string ssnap; - if(getHudPanel(Editor_SelectedPanel_Index)->Snap & 2) { + if(selectedPanel->Snap & 2) { snap = 1; - } else if(getHudPanel(Editor_SelectedPanel_Index)->Snap & 4) { + } else if(selectedPanel->Snap & 4) { snap = 2; } else { snap = 0; @@ -783,9 +757,10 @@ void Hud_DrawHudOptionsPanel(float display, string text) { getHudPanel(Editor_SelectedPanel_Index)->Snap += pow(2,(snap + 3)); } - if(hud_button(HUDE_OPTION_SHOWALL_TOGGLE, pos + [4,162], [140, 16], getHudPanel(HUDP_OPTIONS)->Style ? "Show All" : "Hide Disabled")) { + if(hud_button(HUDE_OPTION_SHOWALL_TOGGLE, pos + [4,162], [140, 16], getHudPanel(HUDP_OPTIONS)->Style ? "Show All" : "Show HUD Only")) { getHudPanel(HUDP_OPTIONS)->Style = !getHudPanel(HUDP_OPTIONS)->Style; } + FO_Hud_ShowPanel(HUDP_OPTIONS); if(getHudPanel(HUDP_OPTIONS)->Status) { Hud_DrawHudOptionsPanelSelector(); diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index ae3031a6..267e89b4 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -1,4 +1,5 @@ void Hud_WriteCfg(string path); +void FO_Hud_InitSystemPanels(); void FO_Hud_Editor() { @@ -7,11 +8,14 @@ void FO_Hud_Editor() fo_hud_editor = FALSE; setcursormode(FALSE); + FO_Hud_InitSystemPanels(); Hud_WriteCfg(FO_HUD_CONFIG_PATH); } else { fo_hud_editor = TRUE; + FO_Hud_InitSystemPanels(); + FO_Hud_ShowPanel(HUDP_OPTIONS); setcursormode(TRUE); } } @@ -83,8 +87,6 @@ float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel { alpha = 0.6; basecolor = MENU_BG + MENU_HIGHLIGHT * 0.1; - //FO_Hud_Panel hoverpanel = GetPanelById(id); - //HRC_drawstring([Mouse.x, Mouse.y], hoverpanel.Name, '8 8', '1 0 0', 1, 0); } if (sui_is_held(id)) @@ -109,7 +111,7 @@ float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel return sui_is_clicked(id); }; -// this HRC_draws backwards, haven't bothered to change as we don't use it +// this draws backwards, haven't bothered to change as we don't use it void Hud_DrawLargeValue(vector pos, float value, float threshhold, float size) { float c; @@ -231,6 +233,44 @@ string GetPanelString(string line, FO_Hud_Panel* panel) return line; } +void FO_Hud_HidePanel(PanelID id) { + getHudPanel(id)->Display = FALSE; + HRC_Invalidate(id); +} + +void FO_Hud_ShowPanel(PanelID id) { + getHudPanel(id)->Display = TRUE; +} + +void FO_Hud_SetDisplay(PanelID id, float display) { + if (display) + FO_Hud_ShowPanel(id); + else + FO_Hud_HidePanel(id); +} + +// Hide panels that are used by other systems, e.g. scores or map voting menu, +// that we don't want bein inadvertently rendered. +void FO_Hud_InitSystemPanels() { + for (float i = HUDP_FIRST; i <= HUDP_LAST; i++) { + FO_Hud_Panel* panel = getHudPanel(i); + if (panel->System) { + switch (panel->id) { + case HUDP_MOTD: + case HUDP_READY: + FO_Hud_ShowPanel(i); + break; + + case HUDP_MAP_MENU: // Enumerated for readability, not necessity + case HUDP_MENU: + default: + FO_Hud_HidePanel(i); + break; + } + } + } +} + float firstrun; void FO_Hud_Editor_LoadSettings(string filename) { @@ -304,7 +344,7 @@ void FO_Hud_Editor_LoadSettings(string filename) panel.TextScale = stof(val); break; case "display": - panel.Display = stof(val); + FO_Hud_SetDisplay(panel->id, stof(val)); break; case "nodeinsertloc": panel.Orientation = stof(val); @@ -335,9 +375,11 @@ void FO_Hud_Editor_LoadSettings(string filename) if(getHudPanel(HUDP_MENU)->Position.x + getHudPanel(HUDP_MENU)->FillSize.x > vsize_x) getHudPanel(HUDP_MENU)->Position.x = vsize_x / 2 - getHudPanel(HUDP_MENU)->FillSize.x / 2; if(getHudPanel(HUDP_MENU)->Position.y + getHudPanel(HUDP_MENU)->FillSize.y > vsize_y) getHudPanel(HUDP_MENU)->Position.y = 64; - + FO_Hud_InitSystemPanels(); } + +// Inherits active render cache id void GetNewPanel(vector pos, vector fillSize, float scale, float display, float orientation, string name) { FO_Hud_Panel pnl; @@ -352,7 +394,7 @@ void GetNewPanel(vector pos, vector fillSize, float scale, float display, float NewPanel = pnl; } -// HRC_draws value string using lmps +// draws value string using lmps void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon, float icon_alpha) { if (!panel.Display && !fo_hud_editor) @@ -372,9 +414,7 @@ void Hud_DrawPanelLMP(FO_Hud_Panel* panel, string val, string icon, float icon_a } } - //vector size = FO_Hud_Icon_Size * panel.Scale; pos = [pos_x + 2, pos_y + 2, 0]; - //HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); HRC_drawpic(pos, icon, scaledFillSize, '1 1 1', icon_alpha, 0); @@ -421,7 +461,6 @@ void Hud_DrawLMPThreshold(FO_Hud_Panel* panel, string val, float threshold) pos = [pos_x + 2, pos_y + 2, 0]; /* vector size = FO_Hud_Icon_Size * panel.Scale; - //HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); pos = [pos_x + offset, pos_y, 0]; diff --git a/csqc/menu.qc b/csqc/menu.qc index c52a8e61..85701147 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -12,6 +12,7 @@ void (float force) FO_Menu_Spy_Team; void (float force) FO_Menu_Class; void (float force) showVoteMenu; void FO_Menu_Admin_Players(float force, float type, float page); +void FO_Hud_SetDisplay(PanelID id, float display); typedef struct { string shortcut; //key to press. if omitted - mouse only @@ -663,8 +664,6 @@ vector fo_menu_draw(fo_menu * menu) = { return position; } - getHudPanel(HUDP_MAP_MENU).Display = FALSE; - thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); @@ -1308,7 +1307,7 @@ void (float show) showVoteMenu = { Menu_Cancel(); } setcursormode(show); - getHudPanel(HUDP_MAP_MENU)->Display = show; + FO_Hud_SetDisplay(HUDP_MAP_MENU, show); if(show) { CurrentMenu = &FO_MENU_VOTE; } diff --git a/csqc/status.qc b/csqc/status.qc index abfef9cd..fe846fd5 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -5,6 +5,8 @@ vector (FO_Hud_Panel* panel) getPanelFillSize; void Hud_DrawPanelLMP(FO_Hud_Panel*, string, string, float); void Hud_DrawLMPThreshold(FO_Hud_Panel*, string, float); FO_Hud_Panel* getHudPanel(PanelID); +void FO_Hud_HidePanel(PanelID id); +void FO_Hud_ShowPanel(PanelID id); void(PanelID ignored, string text) drawClipSize = { if (SBAR.ClipSize != "" || fo_hud_editor) @@ -391,6 +393,10 @@ void(PanelID panelid, string text) drawTextPanel = { void(PanelID panelid, string text) drawMOTDPanel = { FO_Hud_Panel* panel = getHudPanel(panelid); + // No need to render MOTD once expired. + if (time > motd_expiry && panel->Display) + FO_Hud_HidePanel(panel->id); + //vector position = getPosition(id); //vector size = getFillSize(id); vector position = getPanelPosition(panel); //panel.Position; @@ -410,6 +416,8 @@ void(PanelID panelid, string text) drawMOTDPanel = { // click event } } + + if((showingscores || !panel.Display) && !fo_hud_editor) { return; } @@ -1052,8 +1060,7 @@ void(PanelID panelid, string text) drawShowScoresPanel = { void (float show) FO_Show_Scores = { showingscores = show; - FO_Hud_Panel* panel = getHudPanel(HUDP_SHOWSCORES); - if(panel && &panel != &NullPanel) panel.Display = show; + getHudPanel(HUDP_SHOWSCORES)->Display = show; }; var FO_Hud_Panel Hud_Panels[] = { @@ -1062,53 +1069,53 @@ var FO_Hud_Panel Hud_Panels[] = { // string getValue(), // Style, Snap, Status - {HUDP_CLIPSIZE, "clipsize", FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0, drawClipSize, { return WP_GetClip(); }}, - {HUDP_FRAGSTREAK, "fragstreak", FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, - {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, - {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, - {HUDP_GREN2, "gren2", FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0, drawGren2Panel, {return ftos(getstatf(STAT_NO_GREN2));}}, - {HUDP_SPECIAL, "playerclass", FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, - {HUDP_IDENTIFY, "identify", FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, drawIdentify, {return SBAR.Identify;}}, - {HUDP_FLAGINFO, "flaginfo", FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0, drawFlagInfo, {return "";}}, - {HUDP_GRENTIMER, "grentimer", FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0, drawGrenTimerPanel, {return "";}}, - {HUDP_MENU, "menu", "Menu", '10 110', '300 200',1,0,1,0, drawSimplePanel, {return "";}}, - {HUDP_MOTD, "motd", FO_HUD_MOTD_NAME, '150 100', '100 24', 1,0,1,0, drawMOTDPanel, {return SBAR.MOTD;}}, - {HUDP_MENU_HINT, "menuhint", FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0, drawTextPanel, {return SBAR.Hint;}}, - {HUDP_GAME_MODE, "gamemode", FO_HUD_GAME_MODE_NAME, '100 140', '100 10', 1,0,1,0, drawGameModePanel, {return "";}}, - {HUDP_READY, "ready", FO_HUD_READY_NAME, '10 100', '100 10', 2,0,1,FO_HUD_INSERT_MIDDLE, drawReadyPanel, {return SBAR.Hint;}}, - {HUDP_SHOWSCORES, "showscores", FO_HUD_SHOWSCORES_NAME, '10 100', '600 200',1,0,0,FO_HUD_INSERT_MIDDLE, drawShowScoresPanel, {return "";}}, - {HUDP_TEAMSCORE, "teamscore", FO_HUD_TEAM_SCORE_NAME, '0 0', '72 12', 2,0,1,FO_HUD_INSERT_AFTER, drawTeamScorePanel, {return "";}}, - {HUDP_MAP_MENU, "mapmenu", FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, drawMapMenuPanel, {return "";}}, - {HUDP_HEALTH, "health", FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0, drawHealthArmourTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, - {HUDP_FACE, "face", FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0, drawFacePanel, {return "";}, 0, 34}, - {HUDP_AMMO, "ammo", FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0, drawAmmoTextPanel, {return ftos(WP_CurrentAmmo());}, 0, 34}, - {HUDP_AMMOICON, "ammoicon", FO_HUD_AMMO_ICON_NAME , '42 -2', '24 24', 1,0,1,0, drawAmmoPanel, {return "";}, 0, 34}, - {HUDP_ARMOUR, "armour", FO_HUD_ARMOUR_NAME, '-134 -2', '72 24', 1,0,1,0, drawHealthArmourTextPanel, {return ftos(getstatf(STAT_ARMOR));}, 0, 34}, - {HUDP_ARMOURICON, "armouricon", FO_HUD_ARMOUR_ICON_NAME,'-182 -2', '24 24', 1,0,1,0, drawArmourPanel, {return "";}, 0, 34}, - {HUDP_INVSHELLS, "invshells", FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0, drawInvShellsPanel, {return ftos(WP_GetAmmo(AMMO_SHELLS));}, 1, 33}, - {HUDP_INVNAILS, "invnails", FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0, drawInvNailsPanel, {return ftos(WP_GetAmmo(AMMO_NAILS));}, 1, 33}, - {HUDP_INVROCKETS, "invrockets", FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0, drawInvRocketsPanel, {return ftos(WP_GetAmmo(AMMO_ROCKETS));}, 1, 33}, - {HUDP_INVCELLS, "invcells", FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0, drawInvCellsPanel, {return ftos(WP_GetAmmo(AMMO_CELLS));}, 1, 33}, - {HUDP_GAMECLOCK, "gameclock", "Game Clock", '0 0' , '108 24', 1,0.8,1,0, drawClockPanel, {return gameClockString();}, 0, 10}, - {HUDP_QUAD, "quad", "Quad Icon", '-200 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}, 0, 36}, - {HUDP_PENT, "pent", "Pentagram Icon", '-170 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}, 0, 36}, - {HUDP_RING, "ring", "Ring Icon", '-140 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVISIBILITY)?"textures/wad/sb_invis":"";}, 0, 36}, - {HUDP_SUIT, "suit", "Biosuit Icon", '-110 -30','26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_SUIT)?"textures/wad/sb_suit":"";}, 0, 36}, - {HUDP_KEY1, "key1", "Silver Key", '140 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY1)?"textures/wad/sb_key1":"";}, 0, 34}, - {HUDP_KEY2, "key2", "Gold Key", '160 -30', '26 26', 0.6,1.4,1,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY2)?"textures/wad/sb_key2":"";}, 0, 34}, - {HUDP_RUNE1, "rune1", "Earth Rune", '-200 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 1)?"textures/wad/sb_sigi1":"";}, 0, 34}, - {HUDP_RUNE2, "rune2", "Black Rune", '-170 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 2)?"textures/wad/sb_sigil2":"";}, 0, 34}, - {HUDP_RUNE3, "rune3", "Hell Rune", '-140 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 4)?"textures/wad/sb_sigil3":"";}, 0, 34}, - {HUDP_RUNE4, "rune4", "Elder Rune", '-110 0', '26 26', 1,1.4,1,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 8)?"textures/wad/sb_sigil4":"";}, 0, 34}, - {HUDP_GUN2, "gun2", "Shotgun", '-4 -170', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SHOTGUN);}, 0, 36}, - {HUDP_GUN3, "gun3", "Super Shotgun", '-4 -150', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_SHOTGUN);}, 0, 36}, - {HUDP_GUN4, "gun4", "Nailgun", '-4 -130', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_NAILGUN);}, 0, 36}, - {HUDP_GUN5, "gun5", "Super Nailgun", '-4 -110', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_NAILGUN);}, 0, 36}, - {HUDP_GUN6, "gun6", "Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, - {HUDP_GUN7, "gun7", "Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, - {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, - {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0, doNothing, {return "";}, 1}, + {HUDP_TEAMSCORE, "teamscore", FO_HUD_TEAM_SCORE_NAME, '0 0', '72 12', 2,0,1,FO_HUD_INSERT_AFTER, 0, drawTeamScorePanel, {return "";}}, + {HUDP_MAP_MENU, "mapmenu", FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, 1, drawMapMenuPanel, {return "";}}, + {HUDP_SHOWSCORES, "showscores", FO_HUD_SHOWSCORES_NAME, '10 100', '600 200',1,0,1,FO_HUD_INSERT_MIDDLE, 1, drawShowScoresPanel, {return "";}}, + {HUDP_MENU, "menu", "Menu", '10 110', '300 200',1,0,1,0,1, drawSimplePanel, {return "";}}, + {HUDP_MENU_HINT, "menuhint", FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0,0, drawTextPanel, {return SBAR.Hint;}}, + {HUDP_CLIPSIZE, "clipsize", FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0,0, drawClipSize, { return WP_GetClip(); }}, + {HUDP_FRAGSTREAK, "fragstreak", FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, + {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, + {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, + {HUDP_GREN2, "gren2", FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0,0, drawGren2Panel, {return ftos(getstatf(STAT_NO_GREN2));}}, + {HUDP_SPECIAL, "playerclass", FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {HUDP_IDENTIFY, "identify", FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, 0, drawIdentify, {return SBAR.Identify;}}, + {HUDP_FLAGINFO, "flaginfo", FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0,0, drawFlagInfo, {return "";}}, + {HUDP_GRENTIMER, "grentimer", FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0,0, drawGrenTimerPanel, {return "";}}, + {HUDP_MOTD, "motd", FO_HUD_MOTD_NAME, '150 100', '100 24', 1,0,1,0,0, drawMOTDPanel, {return SBAR.MOTD;}}, + {HUDP_GAME_MODE, "gamemode", FO_HUD_GAME_MODE_NAME, '100 140', '100 10', 1,0,1,0,0, drawGameModePanel, {return "";}}, + {HUDP_READY, "ready", FO_HUD_READY_NAME, '10 100', '100 10', 2,0,1,FO_HUD_INSERT_MIDDLE, 1, drawReadyPanel, {return SBAR.Hint;}}, + {HUDP_HEALTH, "health", FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0,0, drawHealthArmourTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, + {HUDP_FACE, "face", FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0,0, drawFacePanel, {return "";}, 0, 34}, + {HUDP_AMMO, "ammo", FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0,0, drawAmmoTextPanel, {return ftos(WP_CurrentAmmo());}, 0, 34}, + {HUDP_AMMOICON, "ammoicon", FO_HUD_AMMO_ICON_NAME , '42 -2', '24 24', 1,0,1,0,0, drawAmmoPanel, {return "";}, 0, 34}, + {HUDP_ARMOUR, "armour", FO_HUD_ARMOUR_NAME, '-134 -2', '72 24', 1,0,1,0,0, drawHealthArmourTextPanel, {return ftos(getstatf(STAT_ARMOR));}, 0, 34}, + {HUDP_ARMOURICON, "armouricon", FO_HUD_ARMOUR_ICON_NAME,'-182 -2', '24 24', 1,0,1,0,0, drawArmourPanel, {return "";}, 0, 34}, + {HUDP_INVSHELLS, "invshells", FO_HUD_INV_SHELLS_NAME, '-2 -244', '24 24', 1,1.4,1,0,0, drawInvShellsPanel, {return ftos(WP_GetAmmo(AMMO_SHELLS));}, 1, 33}, + {HUDP_INVNAILS, "invnails", FO_HUD_INV_NAILS_NAME, '-2 -220', '24 24', 1,1.4,1,0,0, drawInvNailsPanel, {return ftos(WP_GetAmmo(AMMO_NAILS));}, 1, 33}, + {HUDP_INVROCKETS, "invrockets", FO_HUD_INV_ROCKETS_NAME,'-2 -196', '24 24', 1,1.4,1,0,0, drawInvRocketsPanel, {return ftos(WP_GetAmmo(AMMO_ROCKETS));}, 1, 33}, + {HUDP_INVCELLS, "invcells", FO_HUD_INV_CELLS_NAME, '-2 -172', '24 24', 1,1.4,1,0,0, drawInvCellsPanel, {return ftos(WP_GetAmmo(AMMO_CELLS));}, 1, 33}, + {HUDP_GAMECLOCK, "gameclock", "Game Clock", '0 0' , '108 24', 1,0.8,1,0,0, drawClockPanel, {return gameClockString();}, 0, 10}, + {HUDP_QUAD, "quad", "Quad Icon", '-200 -30','26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_QUAD)?"textures/wad/sb_quad":"";}, 0, 36}, + {HUDP_PENT, "pent", "Pentagram Icon", '-170 -30','26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVULNERABILITY)?"textures/wad/sb_invuln":"";}, 0, 36}, + {HUDP_RING, "ring", "Ring Icon", '-140 -30','26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_INVISIBILITY)?"textures/wad/sb_invis":"";}, 0, 36}, + {HUDP_SUIT, "suit", "Biosuit Icon", '-110 -30','26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_SUIT)?"textures/wad/sb_suit":"";}, 0, 36}, + {HUDP_KEY1, "key1", "Silver Key", '140 -30', '26 26', 0.6,1.4,1,0,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY1)?"textures/wad/sb_key1":"";}, 0, 34}, + {HUDP_KEY2, "key2", "Gold Key", '160 -30', '26 26', 0.6,1.4,1,0,0, drawInvIconPanel, {return (getstatf(STAT_ITEMS) & IT_KEY2)?"textures/wad/sb_key2":"";}, 0, 34}, + {HUDP_RUNE1, "rune1", "Earth Rune", '-200 0', '26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 1)?"textures/wad/sb_sigi1":"";}, 0, 34}, + {HUDP_RUNE2, "rune2", "Black Rune", '-170 0', '26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 2)?"textures/wad/sb_sigil2":"";}, 0, 34}, + {HUDP_RUNE3, "rune3", "Hell Rune", '-140 0', '26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 4)?"textures/wad/sb_sigil3":"";}, 0, 34}, + {HUDP_RUNE4, "rune4", "Elder Rune", '-110 0', '26 26', 1,1.4,1,0,0, drawInvIconPanel, {return (getstatbits(STAT_ITEMS,28,4) & 8)?"textures/wad/sb_sigil4":"";}, 0, 34}, + {HUDP_GUN2, "gun2", "Shotgun", '-4 -170', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_SHOTGUN);}, 0, 36}, + {HUDP_GUN3, "gun3", "Super Shotgun", '-4 -150', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_SHOTGUN);}, 0, 36}, + {HUDP_GUN4, "gun4", "Nailgun", '-4 -130', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_NAILGUN);}, 0, 36}, + {HUDP_GUN5, "gun5", "Super Nailgun", '-4 -110', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_SUPER_NAILGUN);}, 0, 36}, + {HUDP_GUN6, "gun6", "Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, + {HUDP_GUN7, "gun7", "Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, + {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, + {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, + {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0,1, doNothing, {return "";}, 1}, }; inline FO_Hud_Panel* (PanelID panelid) getHudPanel = { From 3f57bbac44ad02fa6ae5d0ab6f077f447112c00e Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 5 Nov 2022 02:17:50 -0700 Subject: [PATCH 1851/2474] Fix sticky autoid --- ssqc/status.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/status.qc b/ssqc/status.qc index 5c186ddf..cbd0a79f 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -804,7 +804,7 @@ void UpdateClientIDString(entity pl) { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_ID); // identify - if (pl.ident_string && self.client_time < pl.ident_time) { + if (pl.ident_string && time < pl.ident_time) { WriteString(MSG_MULTICAST, pl.ident_string); } else { WriteString(MSG_MULTICAST, ""); @@ -1253,7 +1253,7 @@ void (entity pl) RefreshStatusBar = { s3 = strzone(s3); // identify - if (pl.ident_string != string_null && self.client_time < pl.ident_time) { + if (pl.ident_string != string_null && time < pl.ident_time) { ident = strcat(pl.ident_string, "\n\n"); } else { ident = "\n\n\n\n"; From 7e61c2bb520a509b0ce06c3a6db03e0c89bcad73 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 6 Nov 2022 01:03:03 -0700 Subject: [PATCH 1852/2474] Fix handling of legacy/invalid panels Null skip was comparing address of local pointer, also add explicit !HUDP_INVALID check on id. --- csqc/hud_helpers.qc | 121 ++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 267e89b4..c26267e2 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -275,7 +275,7 @@ float firstrun; void FO_Hud_Editor_LoadSettings(string filename) { if(!filename || filename == "") return; - + vector vsize = (vector)getproperty(VF_SCREENVSIZE); float width = vsize_x; float height = vsize_y; @@ -290,14 +290,12 @@ void FO_Hud_Editor_LoadSettings(string filename) // fte does weird stuff and writes/reads this to/from a "gamedir/data/file" float filehandle; filehandle = fopen(filename, FILE_READ); - if (filehandle >= 0) { + if (filehandle >= 0) { // get number of lines string ln; ln = fgets(filehandle); - while (ln) - { - if (strlen(ln) > 0) - { + while (ln) { + if (strlen(ln) > 0) { ln = strreplace("\n", "", ln); string val, field; @@ -308,72 +306,65 @@ void FO_Hud_Editor_LoadSettings(string filename) val = argv(1); val = strtrim(val); - //switch(field) - //{ - - //default: - count = tokenizebyseparator(field, "."); - string pnl; - pnl = argv(0); - panel = getHudPanelBySaveName(pnl); - if(!panel || &panel == &NullPanel) { - if(strlen(pnl) < 6) { - ln = fgets(filehandle); - continue; - } - pnl = substring(pnl, 0, strlen(pnl) - 5); - panel = getHudPanelBySaveName(pnl); - if(!panel || &panel == &NullPanel) { - ln = fgets(filehandle); - continue; - } - } - - switch (argv(1)) - { - case "position": - count = tokenizebyseparator(val, ","); - x = stof(argv(0)); - y = stof(argv(1)); - panel.Position = [x, y]; - break; - case "scale": - panel.Scale = stof(val); - break; - case "textscale": - panel.TextScale = stof(val); - break; - case "display": - FO_Hud_SetDisplay(panel->id, stof(val)); - break; - case "nodeinsertloc": - panel.Orientation = stof(val); - break; - case "snap": - panel.Snap = stof(val); - break; - case "style": - panel.Style = stof(val); - break; - } - - //SetDrawPanel(pnl); - //break; - //} + count = tokenizebyseparator(field, "."); + string pnl; + pnl = argv(0); + panel = getHudPanelBySaveName(pnl); + if(!panel || panel == &NullPanel) { + if(strlen(pnl) < 6) { + ln = fgets(filehandle); + continue; + } + pnl = substring(pnl, 0, strlen(pnl) - 5); + panel = getHudPanelBySaveName(pnl); + if(!panel || panel == &NullPanel) { + ln = fgets(filehandle); + continue; + } + } + + if (panel->id == HUDP_INVALID) + continue; + + switch (argv(1)) + { + case "position": + count = tokenizebyseparator(val, ","); + x = stof(argv(0)); + y = stof(argv(1)); + panel.Position = [x, y]; + break; + case "scale": + panel.Scale = stof(val); + break; + case "textscale": + panel.TextScale = stof(val); + break; + case "display": + FO_Hud_SetDisplay(panel->id, stof(val)); + break; + case "nodeinsertloc": + panel.Orientation = stof(val); + break; + case "snap": + panel.Snap = stof(val); + break; + case "style": + panel.Style = stof(val); + break; + } } ln = fgets(filehandle); } fclose(filehandle); - } - else - { + } else { // write a new file Hud_WriteCfg(filename); } - if(getHudPanel(HUDP_MENU)->Position.x < 0) getHudPanel(HUDP_MENU)->Position.x = 10; - if(getHudPanel(HUDP_MENU)->Position.y < 0) getHudPanel(HUDP_MENU)->Position.y = 10; - if(getHudPanel(HUDP_MENU)->Position.x + getHudPanel(HUDP_MENU)->FillSize.x > vsize_x) getHudPanel(HUDP_MENU)->Position.x = vsize_x / 2 - getHudPanel(HUDP_MENU)->FillSize.x / 2; - if(getHudPanel(HUDP_MENU)->Position.y + getHudPanel(HUDP_MENU)->FillSize.y > vsize_y) getHudPanel(HUDP_MENU)->Position.y = 64; + if (getHudPanel(HUDP_MENU)->Position.x < 0) getHudPanel(HUDP_MENU)->Position.x = 10; + if (getHudPanel(HUDP_MENU)->Position.y < 0) getHudPanel(HUDP_MENU)->Position.y = 10; + if (getHudPanel(HUDP_MENU)->Position.x + getHudPanel(HUDP_MENU)->FillSize.x > vsize_x) getHudPanel(HUDP_MENU)->Position.x = vsize_x / 2 - getHudPanel(HUDP_MENU)->FillSize.x / 2; + if (getHudPanel(HUDP_MENU)->Position.y + getHudPanel(HUDP_MENU)->FillSize.y > vsize_y) getHudPanel(HUDP_MENU)->Position.y = 64; FO_Hud_InitSystemPanels(); } From 906c8b8ab9ef98fde1e254365f8d421d5b03d8ee Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 6 Nov 2022 21:57:56 +1100 Subject: [PATCH 1853/2474] Deal with various liquid sounds client side - Deal with various liquid types, in and out - Put standard jump sound onto channel auto to stop it getting clobbered (long standing bug, e.g. when jumping in shallow water). --- csqc/csdefs.qc | 3 ++ csqc/csextradefs.qc | 3 +- csqc/events.qc | 4 ++ csqc/main.qc | 103 +++++++++++++++++++++++++++++++++++--------- ssqc/client.qc | 30 +++++++------ 5 files changed, 109 insertions(+), 34 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index 37b5e5aa..e483be19 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -459,6 +459,9 @@ const float SLIST_TEST_GREATEREQUAL = 6; const float SLIST_TEST_NOTEQUAL = 7; const float SLIST_TEST_STARTSWITH = 8; const float SLIST_TEST_NOTSTARTSWITH = 9; +const vector PLAYER_MINS = [-16, -16, -24]; +const vector PLAYER_MAXS = [16, 16, 24]; + void(vector vang) makevectors = #1; /* Takes an angle vector (pitch,yaw,roll). Writes its results into v_forward, v_right, v_up vectors. */ diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 468e7dee..d96c5745 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -541,8 +541,9 @@ float jump_counter; float grentimer_waiting; float jumpsound_cooldown; float swimsound_cooldown; -float last_pmove_onground; +float last_onground; float last_vel_z; +float last_waterlevel; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/events.qc b/csqc/events.qc index b986b9d9..a18430be 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -456,6 +456,10 @@ float(float entnum, float channel, string soundname, float vol, float attenuatio case "player/h2ojump.wav": case "player/water1.wav": case "player/water2.wav": + case "player/inlava.wav": + case "player/inh2o.wav": + case "player/slimbrn2.wav": + case "misc/outwater.wav": if (CVARF(fo_csjumpsounds)) { return 1; } else { diff --git a/csqc/main.qc b/csqc/main.qc index 579d28f4..563b85a1 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,6 +14,8 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); +float InFluid(vector point); +float CalculateWaterLevel(); void PlayCSJumpSounds(); void GetSelf() = { @@ -25,9 +27,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_model("progs/weapons/v_rock.mdl"); -// for (float i = 0; i < HudIcons.length; i++) { -// precache_pic(HudIcons[i].icon); -// } + // for (float i = 0; i < HudIcons.length; i++) { + // precache_pic(HudIcons[i].icon); + // } registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); @@ -90,9 +92,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); FO_LoadSettings(); - + MenuPanel = getAnyHudPanelByNamePointer("menu"); - + CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; is_admin = FALSE; @@ -481,8 +483,6 @@ void _Sync_ServerCommandFrame() { } } -float last_pmove_onground; -float last_vel_z; float last_clientcommandframe; // REQUIRES: Must be called after _Sync_ServerCommandFrame. void _Sync_ClientCommandFrame() { @@ -501,6 +501,45 @@ void Sync_GameState() { _Sync_ClientCommandFrame(); } +float InFluid(vector point){ + local float cont = pointcontents(point); + + if (cont == CONTENT_WATER || cont == CONTENT_SLIME || cont == CONTENT_LAVA) { + return 1; + } else { + return 0; + } +} + +float CalculateWaterLevel() { + local vector point = pmove_org; + local float default_viewheight = 22; + local float waterlevel = 0; + + point[2] = pmove_org[2] + PLAYER_MINS[2] + 1; // feet + if (!InFluid(point)) { + return waterlevel; + } else { + waterlevel++; + } + + point[2] = pmove_org[2] + (PLAYER_MINS[2] + PLAYER_MAXS[2]) * 0.5; // waist + if (!InFluid(point)) { + return waterlevel; + } else { + waterlevel++; + } + + point[2] = pmove_org[2] + PLAYER_MINS[2] + PLAYER_MAXS[2] + default_viewheight; // eyes + if (!InFluid(point)) { + return waterlevel; + } else { + waterlevel++; + } + + return waterlevel; +} + void PlayCSJumpSounds() { if (!CVARF(fo_csjumpsounds)) { return; @@ -510,14 +549,12 @@ void PlayCSJumpSounds() { return; } - if (pmove_onground && getstatf(STAT_HEALTH) > 0) { - // jumping - local float org = pointcontents(pmove_org); - local float submerged = (org == CONTENT_WATER || org == CONTENT_SLIME || org == CONTENT_LAVA); - getinputstate(clientcommandframe); // without this the input buttons are innacurate + local float waterlevel = CalculateWaterLevel(); - if ((input_buttons & BUTTON2) && (pmove_vel_z < 180 /* not sliding */)) { - if (submerged) { + if (getstatf(STAT_HEALTH) > 0) { + // jumping + if ((input_buttons & BUTTON2)) { + if (waterlevel >= 2) { if (swimsound_cooldown < time) { swimsound_cooldown = time + 1; if (random() < 0.5) { @@ -527,25 +564,51 @@ void PlayCSJumpSounds() { } } } else { - if (jumpsound_cooldown < time) { - jumpsound_cooldown = time + (1 / serverkeyfloat("maxfps")); - localsound("player/plyrjmp8.wav", CHAN_BODY, cvar(FOCMD_JUMPVOLUME)); + if (pmove_onground && pmove_vel_z < 180 /*not sliding*/ ) { + if (jumpsound_cooldown < time) { + jumpsound_cooldown = time + (1 / serverkeyfloat("maxfps")); + localsound("player/plyrjmp8.wav", CHAN_AUTO, cvar(FOCMD_JUMPVOLUME)); + } } } } // landing - if (!last_pmove_onground && last_vel_z < -300) { + if (pmove_onground && !last_onground && last_vel_z < -300) { if (pointcontents(pmove_org) == CONTENT_WATER) { - localsound("player/h2ojump.wav", CHAN_VOICE, 1); + localsound("player/h2ojump.wav", CHAN_BODY, 1); } else if (last_vel_z < -650) { localsound("player/land2.wav", CHAN_VOICE, 1); } else { localsound("player/land.wav", CHAN_VOICE, 1); } } + + // entering water + if (waterlevel > 0 && last_waterlevel == 0) { + local vector feet = pmove_org; + feet[2] = pmove_org[2] + PLAYER_MINS[2] + 1; + + switch(pointcontents(feet)) { + case CONTENT_LAVA: + localsound("player/inlava.wav", CHAN_BODY, 1); + break; + case CONTENT_WATER: + localsound("player/inh2o.wav", CHAN_BODY, 1); + break; + case CONTENT_SLIME: + localsound("player/slimbrn2.wav", CHAN_BODY, 1); + break; + } + } + + // exiting water + if (waterlevel == 0 && last_waterlevel > 0) { + localsound("misc/outwater.wav", CHAN_BODY, 1); + } } last_vel_z = pmove_vel_z; - last_pmove_onground = pmove_onground; + last_onground = pmove_onground; + last_waterlevel = waterlevel; }; diff --git a/ssqc/client.qc b/ssqc/client.qc index f7b9d6c8..6f7191b3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2552,7 +2552,7 @@ void () PlayerJump = { self.flags = self.flags - (self.flags & FL_JUMPRELEASED); self.button2 = 0; - FO_Sound(self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + FO_Sound(self, CHAN_AUTO, "player/plyrjmp8.wav", 1, ATTN_NORM); if (self.fire_held_down && (self.current_weapon == WEAP_ASSAULT_CANNON)) { if (!cannon_air) { @@ -2619,10 +2619,11 @@ void () WaterMove = { self.pain_finished = time + 1; } } + if (!self.waterlevel) { - if (self.flags & 16) { + if (self.flags & FL_INWATER) { FO_Sound(self, CHAN_BODY, "misc/outwater.wav", 1, 1); - self.flags = self.flags - 16; + self.flags = self.flags - FL_INWATER; } return; } @@ -2648,17 +2649,19 @@ void () WaterMove = { } } } - if (!(self.flags & 16)) { - if (self.watertype == CONTENT_LAVA) { - FO_Sound(self, CHAN_BODY, "player/inlava.wav", 1, 1); - } - if (self.watertype == -3) { - FO_Sound(self, CHAN_BODY, "player/inh2o.wav", 1, 1); - } - if (self.watertype == -4) { - FO_Sound(self, CHAN_BODY, "player/slimbrn2.wav", 1, 1); + if (!(self.flags & FL_INWATER)) { + switch(self.watertype) { + case CONTENT_LAVA: + FO_Sound(self, CHAN_BODY, "player/inlava.wav", 1, 1); + break; + case CONTENT_WATER: + FO_Sound(self, CHAN_BODY, "player/inh2o.wav", 1, 1); + break; + case CONTENT_SLIME: + FO_Sound(self, CHAN_BODY, "player/slimbrn2.wav", 1, 1); + break; } - self.flags = self.flags + 16; + self.flags = self.flags + FL_INWATER; self.dmgtime = 0; } }; @@ -2727,6 +2730,7 @@ void () PlayerPreThink = { if (self.playerclass != 0 || votemode) { WaterMove(); } + if (self.deadflag >= 2) { PlayerDeathThink(); return; From 2e683ccd6cbe84bb1b86e8a406f016f60fa1f566 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 6 Nov 2022 22:23:27 +1100 Subject: [PATCH 1854/2474] Refactor --- csqc/csdefs.qc | 2 -- csqc/csextradefs.qc | 4 ++++ csqc/main.qc | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/csqc/csdefs.qc b/csqc/csdefs.qc index e483be19..4990f55b 100644 --- a/csqc/csdefs.qc +++ b/csqc/csdefs.qc @@ -459,8 +459,6 @@ const float SLIST_TEST_GREATEREQUAL = 6; const float SLIST_TEST_NOTEQUAL = 7; const float SLIST_TEST_STARTSWITH = 8; const float SLIST_TEST_NOTSTARTSWITH = 9; -const vector PLAYER_MINS = [-16, -16, -24]; -const vector PLAYER_MAXS = [16, 16, 24]; void(vector vang) makevectors = #1; /* Takes an angle vector (pitch,yaw,roll). Writes its results into v_forward, v_right, v_up vectors. */ diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d96c5745..9c14176f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -41,6 +41,10 @@ vector TEXT_TEAM_COLOUR[] = { MENU_TEXT_GREEN_FO }; +const float DEFAULT_VIEWHEIGHT = 22; +const vector PLAYER_MINS = [-16, -16, -24]; +const vector PLAYER_MAXS = [16, 16, 24]; + #define FO_MENU_FLAG_USE_MOUSE 1 #define FO_MENU_FLAG_CENTER 2 #define FO_MENU_FLAG_SHOW_SHORTCUTS 4 diff --git a/csqc/main.qc b/csqc/main.qc index 563b85a1..3b75ac71 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -513,7 +513,6 @@ float InFluid(vector point){ float CalculateWaterLevel() { local vector point = pmove_org; - local float default_viewheight = 22; local float waterlevel = 0; point[2] = pmove_org[2] + PLAYER_MINS[2] + 1; // feet @@ -530,7 +529,7 @@ float CalculateWaterLevel() { waterlevel++; } - point[2] = pmove_org[2] + PLAYER_MINS[2] + PLAYER_MAXS[2] + default_viewheight; // eyes + point[2] = pmove_org[2] + PLAYER_MINS[2] + PLAYER_MAXS[2] + DEFAULT_VIEWHEIGHT; // eyes if (!InFluid(point)) { return waterlevel; } else { From dfcef58798243d9027797cc4e3e6201a3e19e26f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 7 Nov 2022 01:47:28 +1100 Subject: [PATCH 1855/2474] Temp fix to stop multiple jump sounds playing sometimes, until I work out why --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index fd537c8d..d1fbdae4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -626,7 +626,7 @@ void PlayCSJumpSounds() { } else { if (pmove_onground && pmove_vel_z < 180 /*not sliding*/ ) { if (jumpsound_cooldown < time) { - jumpsound_cooldown = time + (1 / serverkeyfloat("maxfps")); + jumpsound_cooldown = time + (2 / serverkeyfloat("maxfps")); localsound("player/plyrjmp8.wav", CHAN_AUTO, cvar(FOCMD_JUMPVOLUME)); } } From bab85cc91211ed57d6dd60c446811f626e0b5e32 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 7 Nov 2022 10:59:34 -0800 Subject: [PATCH 1856/2474] HUD fixes - Make hint a system panel (before, some people had made it visible in the hud editor and it was showing up where we didnt want it to) - Minor cleanups --- csqc/csextradefs.qc | 39 ++++++++++++++++++------------------ csqc/hud.qc | 3 +-- csqc/menu.qc | 4 ++++ csqc/status.qc | 49 ++++++++++++++++++--------------------------- 4 files changed, 44 insertions(+), 51 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index cf74e7ab..9c0c0c0f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -565,25 +565,6 @@ enum { inline float HRC_fps_time() { return 1/max(min(CVARF(fo_hud_fps), 77 * 2), 30); } -// Returns true if HUD should be re-rendered this frame. -float HRC_NewFrame() { - // Rate limit even the more complicated enable checks. - /* if (time < hud_render_cache.last_update + HRC_fps_time()) */ - /* return !hud_render_cache.enabled; */ - /* hud_render_cache.last_update = time; */ - - if (!CVARF(fo_hud_cache) || - fo_hud_menu_active || fo_hud_editor || showingscores) { - // Either explicitly disabled, or rendering a more complicated scene - // like the editor for which we'll just display in place. - hud_render_cache.enabled = FALSE; - return TRUE; - } - - hud_render_cache.enabled = TRUE; - return FALSE; -} - void HRC_Invalidate(PanelID panel) { float i, j; @@ -615,6 +596,26 @@ void HRC_SetActive(PanelID panel) { hud_render_cache.active_panel = panel; } +// Returns true if HUD should be re-rendered this frame. +float HRC_NewFrame() { + // Rate limit even the more complicated enable checks. + /* if (time < hud_render_cache.last_update + HRC_fps_time()) */ + /* return !hud_render_cache.enabled; */ + /* hud_render_cache.last_update = time; */ + + if (!CVARF(fo_hud_cache) || + fo_hud_menu_active || fo_hud_editor || showingscores) { + // Either explicitly disabled, or rendering a more complicated scene + // like the editor for which we'll just display in place. + hud_render_cache.enabled = FALSE; + return TRUE; + } + + hud_render_cache.enabled = TRUE; + return FALSE; +} + + static Draw_Args* next_args() { float idx; if (hud_render_cache.free_count) diff --git a/csqc/hud.qc b/csqc/hud.qc index d49c8de2..9bae5d4d 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1105,10 +1105,9 @@ struct { void Hud_UpdateView(float width, float height, float menushown, float perf_sample) { float hud_update = HRC_NewFrame(); + ScreenSize = [width, height, menushown]; if (HRC_NewFrame()) { float hts = perf_start_sample(&hud_timing, perf_sample); - ScreenSize = [width, height, menushown]; - SBAR.Hint = ""; sui_begin(width, height); Menu_Draw(width, height, menushown); Hud_Draw(width, height); diff --git a/csqc/menu.qc b/csqc/menu.qc index 85701147..99472c7b 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -664,6 +664,9 @@ vector fo_menu_draw(fo_menu * menu) = { return position; } + FO_Hud_ShowPanel(HUDP_MENU_HINT); + SBAR.Hint = ""; + thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); @@ -836,6 +839,7 @@ void Menu_Cancel() = { setcursormode(FALSE); fo_hud_menu_active = FALSE; } + FO_Hud_HidePanel(HUDP_MENU_HINT); } void Menu_Draw(float width, float height, float menushown) = { diff --git a/csqc/status.qc b/csqc/status.qc index fe846fd5..ddbbe0db 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -339,7 +339,7 @@ void(PanelID panelid, string text) drawSimplePanel = { void(PanelID panelid, string text) drawTextPanel = { FO_Hud_Panel* panel = getHudPanel(panelid); - + vector position = getPanelPosition(panel); vector size = getPanelFillSize(panel); vector mediumtext = MENU_TEXT_SMALL * panel.Scale; @@ -349,42 +349,31 @@ void(PanelID panelid, string text) drawTextPanel = { if (fo_hud_editor) { string name = getHudPanel(panelid)->Name; HRC_drawstring( - [GetTextAlignOffset(position.x, size.x, padding, name, - mediumtext.x, panel.Orientation), - padding*2 + position.y], - name, mediumtext, MENU_TEXT_1, 1, 0 - ); + [GetTextAlignOffset(position.x, size.x, padding, name, + mediumtext.x, panel.Orientation), + padding*2 + position.y], + name, mediumtext, MENU_TEXT_1, 1, 0 + ); if (hud_panel(panelid, position, size, transparency, panel.Display)) { // click event } } else { - if(showingscores || !panel.Display) { + if (showingscores || !panel.Display || text == "") return; - } - if(text && text != "") { - //sui_border_box(position, size, 1, MENU_BORDER, transparency, 0); - //sui_push_frame(position, size); - - //sui_fill([0, 0], size, MENU_BG, transparency, 0); - //sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); - //sui_action_element([0, 0], size, panelid, sui_noop); - //sui_pop_frame(); - lines = tokenizebyseparator(text, "\n"); - local string line; - for (float i = 0; i <= lines; i++) { - line = argv(i); - // tokenize doesn't handle newlines very well - line = strreplace("\n", "", line); - line = strtrim(line); - if (strlen(line) > 0) { - HRC_drawstring( + lines = tokenizebyseparator(text, "\n"); + string line; + for (float i = 0; i <= lines; i++) { + line = argv(i); + // tokenize doesn't handle newlines very well + line = strtrim(strreplace("\n", "", line)); + if (strlen(line) > 0) { + HRC_drawstring( [GetTextAlignOffset(position.x, size.x, padding, line, mediumtext.x, panel.Orientation), position.y + padding + mediumtext.y*i], line, mediumtext, MENU_TEXT_1, 1, 0 - ); - } + ); } } } @@ -418,9 +407,9 @@ void(PanelID panelid, string text) drawMOTDPanel = { } - if((showingscores || !panel.Display) && !fo_hud_editor) { + if ((showingscores || !panel.Display || text == "") && !fo_hud_editor) return; - } + //if(text && text != "") { if((!intermission && time < motd_expiry && !team_no) || fo_hud_editor) { sui_push_frame(position, size); @@ -1073,7 +1062,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_MAP_MENU, "mapmenu", FO_HUD_MAP_MENU_NAME, '10 30', '800 400',1,0,1,FO_HUD_INSERT_MIDDLE, 1, drawMapMenuPanel, {return "";}}, {HUDP_SHOWSCORES, "showscores", FO_HUD_SHOWSCORES_NAME, '10 100', '600 200',1,0,1,FO_HUD_INSERT_MIDDLE, 1, drawShowScoresPanel, {return "";}}, {HUDP_MENU, "menu", "Menu", '10 110', '300 200',1,0,1,0,1, drawSimplePanel, {return "";}}, - {HUDP_MENU_HINT, "menuhint", FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0,0, drawTextPanel, {return SBAR.Hint;}}, + {HUDP_MENU_HINT, "menuhint", FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0,1, drawTextPanel, {return SBAR.Hint;}}, {HUDP_CLIPSIZE, "clipsize", FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0,0, drawClipSize, { return WP_GetClip(); }}, {HUDP_FRAGSTREAK, "fragstreak", FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, From b8fdeeff3169aedf2c3a659c5833a80d36a72e2c Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 8 Nov 2022 16:44:34 -0800 Subject: [PATCH 1857/2474] Only intercept inputs when menus are active We dont want to intercept/buffer all client inputs; particularly if they're playing when the input is made. --- csqc/input.qc | 64 +++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 247f95cd..892640ff 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -1,56 +1,39 @@ void Menu_Cancel(); void FO_Menu_Game(float); +static float HudInputEscape() { + if (!fo_hud_menu_active && !fo_hud_editor) + return FALSE; + + Menu_Cancel(); + fo_hud_editor = FALSE; + return TRUE; +} + float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { - float used = sui_input_event(evtype, scanx, chary, devid); - //if(evtype == IE_KEYDOWN) print("Key down: ", ftos(scanx), ", char: ", ftos(chary), "\n"); - float menu_mouse = (fo_hud_menu_active && (CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)); - if (fo_hud_editor || fo_hud_menu_active) - { - switch (evtype) - { + if (fo_hud_editor || fo_hud_menu_active) { + sui_input_event(evtype, scanx, chary, devid); + float menu_mouse = (fo_hud_menu_active && (CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)); + switch (evtype) { case IE_KEYUP: - switch (scanx) - { - case K_ESCAPE: - if(fo_hud_menu_active) { - Menu_Cancel(); - return TRUE; - } - if(fo_hud_editor) { - fo_hud_editor = FALSE; - return TRUE; - } - break; - case K_MOUSE1: - // work out if on a button - break; - } + if (scanx == K_ESCAPE && HudInputEscape()) + return TRUE; break; case IE_KEYDOWN: - switch (scanx) - { + switch (scanx) { case K_ESCAPE: - if(fo_hud_menu_active) { - //Menu_Cancel(); - return TRUE; - } - if(fo_hud_editor) { - //fo_hud_editor = FALSE; + if (HudInputEscape()) return TRUE; - } break; case K_MOUSE1: - if(!fo_hud_editor && fo_hud_menu_active && !(CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)) { + if(!fo_hud_editor && fo_hud_menu_active && + !(CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)) break; - } - // work out if on a button + return TRUE; - break; } - if(fo_hud_menu_active) { + if(fo_hud_menu_active) return fo_menu_process_input(CurrentMenu, scanx); - } break; case IE_MOUSEDELTA: return (fo_hud_editor || menu_mouse); @@ -58,9 +41,9 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { Mouse.x = scanx; Mouse.y = chary; return (fo_hud_editor || menu_mouse); - default: } } else if(getHudPanel(HUDP_MAP_MENU)->Display) { + sui_input_event(evtype, scanx, chary, devid); switch (evtype) { case IE_MOUSEDELTA: return TRUE; @@ -69,7 +52,8 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { PrevMouse.y = Mouse.y; Mouse.x = scanx; Mouse.y = chary; - if(MouseDown) Hud_MapMenuPanel_Move(Mouse.x - PrevMouse.x, Mouse.y - PrevMouse.y); + if (MouseDown) + Hud_MapMenuPanel_Move(Mouse.x - PrevMouse.x, Mouse.y - PrevMouse.y); return TRUE; case IE_KEYDOWN: switch (scanx) { From f82e1828f90934a93ee9d043d238f541de7445b7 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 01:50:18 -0800 Subject: [PATCH 1858/2474] Move newmis behaviors to quakec Using 'newmis' to initialize an entity triggers special handling in qwsv that forwards it for 50ms arbitrarily. This is awkward to rectify with projectile physics as it does it with a 50ms physics window. Move this behavior into quakec and split the 50ms into a fixed and dynamic period, so that we can open up the range at which predictiles feel uniform slightly. --- csqc/weapon_predict.qc | 145 +++++++++++++++++++++-------------------- share/commondefs.qc | 1 + share/prediction.qc | 72 +++++++++++++++----- ssqc/antilag.qc | 12 ++-- ssqc/engineer.qc | 26 ++++---- ssqc/hwguy.qc | 36 +++++----- ssqc/pyro.qc | 39 ++++++----- ssqc/spy.qc | 28 ++++---- ssqc/weapons.qc | 54 +++++++-------- 9 files changed, 228 insertions(+), 185 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 93c6b3ee..d41ed133 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -148,6 +148,7 @@ void WPP_Status() { printf(" inst_ping = %d avg_ping = %d var = %d\n", ping, avg, variance); printf("Config:\n"); + PRINT_CONFIG(dynamic_newmis_ms); PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); PRINT_CONFIG(max_rewind_fast_projectile_ms); @@ -697,6 +698,42 @@ void PP_Cleanup(entity proj) { remove(proj); } +DEFCVAR_FLOAT(r_rockettrail, 1); +DEFCVAR_FLOAT(r_grenadetrail, 1); + +int FPP_FindTrail(entity e) +{ + float is_rocket = e.fpp_index == FPP_ROCKET; + float is_grenade = e.fpp_index == FPP_GRENADE; + + if (is_rocket || is_grenade) { + float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; + + if (idx >= 0 && idx < trail_table.length) + return trail_table[idx].trail[is_grenade]; + } + + return fpp_types[e.fpp_index].trailindex; +} + +DEFCVAR_FLOAT(cl_r2g, 0); + +entity FPP_Init(int fpp_type, entity proj) { + fo_projectile* desc = &fpp_types[fpp_type]; + + proj.fpp_index = fpp_type; + + if (fpp_type == FPP_ROCKET && CVARF(cl_r2g) == 1) + setmodelindex(proj, fpp_types[FPP_GRENADE].modelindex); + else + setmodelindex(proj, desc->modelindex); + + /* proj.p_time = proj.s_time + 1/77.0; */ + proj.oldorigin = proj.s_origin; + proj.traileffectnum = FPP_FindTrail(proj); + + return proj; +} DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_FLOAT(r_rocketlight, 1); @@ -718,8 +755,7 @@ float PP_PredrawActive() { return PREDRAW_NEXT; } } - if (self.traileffectnum && self.trail_started) - trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); + trailparticles(self.traileffectnum, self, self.oldorigin, self.origin); self.trail_started = TRUE; self.p_time = time + frametime; @@ -745,57 +781,34 @@ float PP_PredrawPredicted() { return PP_PredrawActive(); } -DEFCVAR_FLOAT(r_rockettrail, 1); -DEFCVAR_FLOAT(r_grenadetrail, 1); - -int PP_FindTrail(entity e) -{ - float is_rocket = e.fpp_index == FPP_ROCKET; - float is_grenade = e.fpp_index == FPP_GRENADE; - - if (is_rocket || is_grenade) { - float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; - - if (idx >= 0 && idx < trail_table.length) - return trail_table[idx].trail[is_grenade]; - } - - return fpp_types[e.fpp_index].trailindex; -} - static float PP_EPS = 0.05; -static inline void PP_InitTrail(entity proj) { - proj.p_time = proj.s_time + 1/77.0; - proj.oldorigin = proj.s_origin; - proj.traileffectnum = PP_FindTrail(proj); +static vector PredProj_Pos(entity proj) { + float offset = time - proj.s_time; + return proj.s_origin + offset * proj.velocity; } // Predict the effective start time of something we fire right now, accounting // for server side projection, ping fluctuation, etc. float PP_StartOffset(int fpp_type) { - int max_credit = max_rewind_credit_ms(fpp_type); - float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); + float max_credit = max_rewind_credit_ms(fpp_type); + // Server will credit full frame, average out to middle of prior. + const float frame_cor = 1.5 * 1/77.0; - return (max(pstate_pred.client_ping - max_credit, 0) + - ping - pstate_pred.client_ping) / 1000.0; + return (max(pstate_pred.client_ping - max_credit - dynamic_newmis_ms(), 0) + - static_newmis_ms(fpp_type)) / 1000.0 - frame_cor; } static float PP_EPS = 0.05; -DEFCVAR_FLOAT(cl_r2g, 0); - -entity PP_CreateProjectile(int proj_type, vector offset) { - fo_projectile* desc = &fpp_types[proj_type]; - - PredProj_Sound(proj_type); +entity PP_CreateProjectile(int fpp_type, vector offset) { + PredProj_Sound(fpp_type); if (!PP_Enabled()) return __NULL__; entity proj = spawn(); - - proj.fpp_index = proj_type; + FPP_Init(fpp_type, proj); #if 0 // Packet loss doesnt guarantee the server will actually register quickslot @@ -809,30 +822,23 @@ entity PP_CreateProjectile(int proj_type, vector offset) { #endif // Note: We use true time here as created projectiles exist outside of pred. - proj.s_time = time + PP_StartOffset(proj_type); - proj.starttime = proj.s_time; - proj.endtime = time + pstate_pred.client_ping / 1000.0 + PP_EPS; + proj.s_time = time + PP_StartOffset(fpp_type); + proj.starttime = max(time, proj.s_time); + proj.endtime = proj.starttime + pstate_pred.client_ping / 1000.0 + PP_EPS; proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; setsize(proj, [0,0,0], [0,0,0]); - proj.p_time = 0; proj.s_origin = pmove_org + offset; proj.s_origin[2] += 16; - proj.velocity = v_forward * desc->speed; + proj.velocity = v_forward * fpp_types[fpp_type].speed; - setorigin(proj, proj.s_origin); + proj.origin = PredProj_Pos(proj); + proj.oldorigin = proj.origin; proj.angles = input_angles; proj.angles[0] *= -1; - if (self.fpp_index == FPP_ROCKET && CVARF(cl_r2g) == 1) - setmodelindex(proj, fpp_types[FPP_GRENADE].modelindex); - else - setmodelindex(proj, fpp_types[proj.fpp_index].modelindex); - - PP_InitTrail(proj); - proj.pred_next = predicted_projectiles; if (predicted_projectiles) predicted_projectiles.pred_prev = proj; @@ -977,9 +983,7 @@ void WP_Attack() { float PredProjectile_MatchProjectile() { entity proj, match = __NULL__; - float best = 32; - - self.origin = self.s_origin + (time - self.s_time) * self.velocity; + float best = 200; for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { if (proj.fpp_index != self.fpp_index || proj.wpp_aux != self.wpp_aux) @@ -988,7 +992,7 @@ float PredProjectile_MatchProjectile() { if (time > proj.endtime - 0.01) break; // Projectile list is time ordered - proj.origin = proj.s_origin + (time - self.s_time) * proj.velocity; + proj.origin = PredProj_Pos(proj); float d = vlen(proj.origin - self.origin); if (d < best) { best = d; @@ -1002,10 +1006,13 @@ float PredProjectile_MatchProjectile() { self.trail_started = match.trail_started; if (CVARF(wpp_debug) & 1) { - printf(" p_diff = %0.3f / %0.3f t=%0.3f, error_s = %0.3f\n", - vlen(match.s_origin - self.s_origin), vlen(match.origin - self.origin), - vlen(match.origin - self.origin) / vlen(self.velocity), - self.s_time - match.s_time); + string s = sprintf(" p_diff = %0.3f, t_e=%0.3f", + vlen(match.origin - self.origin), + vlen(match.origin - self.origin) / vlen(self.velocity)); + s = strcat(s, sprintf(" [c=%0.3f/%0.3f (s_t=%0.3f) s=%0.3f/%0.3f]\n", + vlen(match.origin - pmove_org),time, match.s_time, + vlen(self.origin - pmove_org),self.s_time)); + print(s); } PP_Cleanup(match); @@ -1020,25 +1027,25 @@ void InitProjectileEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; - setmodelindex(self, fpp_types[self.fpp_index].modelindex); - setsize(self, [0,0,0], [0,0,0]); - - if (CVARF(cl_r2g) && self.fpp_index == FPP_ROCKET) - setmodelindex(self, fpp_types[FPP_GRENADE].modelindex); + FPP_Init(self.fpp_index, self); - PP_InitTrail(self); // Note: Might be overwritten by inherited match. + self.origin = self.s_origin + (time - self.s_time) * self.velocity; // We still check this with projectile prediction as there could be in // flight projectiles on the transition. This is effectively a nop in the // off case since the projectile list will just be empty. - if (self.owner_entnum == player_localentnum && - !PredProjectile_MatchProjectile() && - time - last_pred_sound > 75 * MSEC) { - - // Missing projectile implies we missed the local sound, patch it up. - if (WP_Enabled()) + float has_predicted = FALSE; + if (self.owner_entnum == player_localentnum) { + has_predicted = PredProjectile_MatchProjectile(); + if (WP_Enabled() && !has_predicted && + self.s_time > last_pred_sound + PP_EPS/2) + // Missing projectile implies we missed the local sound, patch it up. PredProj_Sound(self.fpp_index); } + + if (!has_predicted) { + self.oldorigin = self.origin; + } } DEFCVAR_FLOAT(r_drawviewmodel, 1); diff --git a/share/commondefs.qc b/share/commondefs.qc index 1105827e..4a1ba000 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,4 +1,5 @@ var struct { + float dynamic_newmis_ms; float max_rewind_ms; float max_rewind_slow_projectile_ms; float max_rewind_fast_projectile_ms; diff --git a/share/prediction.qc b/share/prediction.qc index d0543602..f9743191 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -4,8 +4,10 @@ // Below apply to both CSQC & SSQC ents .float fpp_index; // Projectile type -.vector s_origin; // Spawning origin (at s_time); matched for client/server -.float s_time; // Time spawned (in client_time) +#ifdef CSQC +.vector s_origin; +.float s_time; +#endif string wp_version = "v0.2"; @@ -172,6 +174,26 @@ float max_rewind_credit_ms(int fpp_type) { fo_config.max_rewind_fast_projectile_ms; } + +// The original QW implementation always forwards projectiles by 50ms, in a +// similar way to our own antilag projection. However, this is done in a +// difficult to correct for fashion (especially with more complicated +// projectiles such as grenades) as well as not reflecting the ping times of +// today. We split this into a ping independent and ping dependent portion, to +// slightly widen the range at which feel and timing is uniform. +// +// NOTE: DO NOT USE NEWMIS FOR FO PROJECTILES. THE NEWMIS CORRECTION IS NOW +// MADE EXPLICITLY RATHER THAN IMPLICITLY. [WE AUTOMATICALLY STRIP NEWMIS +// FROM PROJECTILES PASSED TO US.] +float static_newmis_ms(int fpp_type) { + if (fpp_type == FPP_FLAMETHROWER || fpp_type == FPP_ASSAULT_CANNON) + return 0; + + return 50 - fo_config.dynamic_newmis_ms; +} +inline float dynamic_newmis_ms() { + return fo_config.dynamic_newmis_ms; +} .float wpp_aux; #ifdef SSQC @@ -306,6 +328,7 @@ float WP_SendConfig(entity to_player, float sendflags) { #define COMM(_type, _field) fo_config.##_field = Read##_type() void EntUpdate_Config() { #endif + COMM(Float, dynamic_newmis_ms); COMM(Float, max_rewind_ms); COMM(Float, max_rewind_slow_projectile_ms); COMM(Float, max_rewind_fast_projectile_ms); @@ -419,15 +442,16 @@ void EntUpdate_Projectile(float isnew) { float sendflags = readbyte(); #endif if (sendflags & FOPP_POS) { - COMM(Coord, s_origin[0]); - COMM(Coord, s_origin[1]); - COMM(Coord, s_origin[2]); + COMMD(Coord, s_origin[0], origin[0]); + COMMD(Coord, s_origin[1], origin[1]); + COMMD(Coord, s_origin[2], origin[2]); COMM(Coord, velocity[0]); COMM(Coord, velocity[1]); COMM(Coord, velocity[2]); - COMM(Float, s_time); + COMMO(Float, self.s_time, time); + } if (sendflags & FOPP_INIT) { @@ -456,6 +480,7 @@ void EntUpdate_Projectile(float isnew) { #undef COMM void WeapPred_InitDefaultConfig() { + fo_config.dynamic_newmis_ms = 25; fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 100; fo_config.max_rewind_fast_projectile_ms = 100; @@ -484,6 +509,7 @@ static void WeaponPred_CheckConfigUpdate() { float update = FALSE; // Target is also the long form localinfo name. + CONFIG_UPDATE("dnm", dynamic_newmis_ms); CONFIG_UPDATE("mrt", max_rewind_ms); CONFIG_UPDATE("mrsp", max_rewind_slow_projectile_ms); CONFIG_UPDATE("mrfp", max_rewind_fast_projectile_ms); @@ -496,6 +522,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_enable); CONFIG_UPDATE("wppge", wpp_global_disable); + CLAMP_UPDATE(dynamic_newmis_ms, 0, 50); CLAMP_UPDATE(max_rewind_ms, 0, 250); CLAMP_UPDATE(max_rewind_slow_projectile_ms, 0, fo_config.max_rewind_ms); CLAMP_UPDATE(max_rewind_fast_projectile_ms, 0, fo_config.max_rewind_ms); @@ -599,20 +626,33 @@ void PredProj_Sound(int proj_type, float vol = 1) { void WeaponPred_ProjectProjectile(int fpp_type, entity projectile); -void FOProj_Init(int fpp_type, entity mis) { - // This init always needs to occur. - mis.dimension_seen = DMN_NOFLASH; +entity FOProj_Create(int fpp_type) { + entity prj = spawn(); - PredProj_Sound(fpp_type); + prj.fpp_index = fpp_type; + prj.dimension_seen = DMN_NOFLASH; + setmodel(prj, fpp_types[fpp_type].model); + setsize(prj, '0 0 0', '0 0 0'); - setmodel(mis, fpp_types[fpp_type].model); - setsize(mis, '0 0 0', '0 0 0'); + return prj; +} - mis.fpp_index = fpp_type; - mis.s_origin = mis.origin; - mis.s_time = time; - WeaponPred_ProjectProjectile(fpp_type, mis); +void FOProj_Finalize(entity mis) { + int fpp_type = mis.fpp_index; + // We explicitly do not use newmis. Newmis internally implements a fixed + // 50m forward of physics handling (equivalent to our projection below) + // which cannot be nicely unwound or accounted for.ammo_shells + // + // For our projectiles we continue to always project by at least 25ms. + // The remaining 25ms is moved to ping dependent correction. + if (newmis == mis) { + PRINT_ONCE("Error: fpp=%d used with newmis\n", (float)fpp_type); + newmis = __NULL__; + } + + PredProj_Sound(fpp_type); + WeaponPred_ProjectProjectile(mis.fpp_index, mis); // Below is conditional on using custom SendEntity. if (fo_projectiles) { diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 7f701bb2..4c93fdde 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,8 +1,6 @@ static float NoLanProject() { - if (self.client_ping <= 25) { - self.s_time = time; // Still need to potentially setup for networking + if (self.client_ping <= 25) return TRUE; - } return FALSE; } @@ -13,7 +11,6 @@ void AL_ProjectProjectile (entity projectile) { float time_offset = min(self.client_ping, fo_config.max_rewind_slow_projectile_ms) / 1000.0; - projectile.s_time = time - time_offset; vector projected_origin = projectile.origin + (projectile.velocity * time_offset); // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED @@ -35,11 +32,10 @@ void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { if (NoLanProject()) return; - float max_credit = max_rewind_credit_ms(fpp_type); - float time_offset = min(self.client_ping, max_credit) / 1000.0; + float max_credit = max_rewind_credit_ms(fpp_type) + dynamic_newmis_ms(); + float time_offset = min(self.client_ping, max_credit) + static_newmis_ms(fpp_type); - projectile.s_time = time - time_offset; - vector projected_origin = projectile.origin + (projectile.velocity * time_offset); + vector projected_origin = projectile.origin + (projectile.velocity * (time_offset / 1000.0)); traceline(projectile.origin, projected_origin, 0, self); if (trace_fraction < 1) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index be050f24..705be172 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -88,23 +88,23 @@ void () W_FireRailgun = { vec = aim(self, 10000); vec = normalize(vec); - newmis = spawn(); - newmis.owner = self; - newmis.enemy = self; - newmis.movetype = MOVETYPE_FLYMISSILE; - newmis.solid = SOLID_TRIGGER; + entity proj = FOProj_Create(FPP_RAILGUN); + proj.owner = self; + proj.enemy = self; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.solid = SOLID_TRIGGER; - newmis.velocity = vec * fpp_types[FPP_RAILGUN].speed; - newmis.angles = vectoangles(newmis.velocity); + proj.velocity = vec * fpp_types[FPP_RAILGUN].speed; + proj.angles = vectoangles(proj.velocity); - newmis.nextthink = time + 5; - newmis.think = SUB_Remove; - newmis.touch = LaserBolt_Touch; - newmis.classname = "railslug"; - setorigin(newmis, org + '0 0 16'); + proj.nextthink = time + 5; + proj.think = SUB_Remove; + proj.touch = LaserBolt_Touch; + proj.classname = "railslug"; + setorigin(proj, org + '0 0 16'); - FOProj_Init(FPP_RAILGUN, newmis); + FOProj_Finalize(proj); }; void () EMPExplode = { diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 7c652f5d..d37780b4 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -56,34 +56,34 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { local float num; - newmis = spawn(); - newmis.owner = self; - newmis.classname = "proj_bullet"; + entity proj = FOProj_Create(FPP_ASSAULT_CANNON); + proj.owner = self; + proj.classname = "proj_bullet"; - newmis.movetype = MOVETYPE_FLY; // Small collision + proj.movetype = MOVETYPE_FLY; // Small collision - newmis.solid = SOLID_BBOX; - newmis.touch = AssCanBulletTouch; + proj.solid = SOLID_BBOX; + proj.touch = AssCanBulletTouch; if (asscanrange > 0) { num = (1 / proj_speed) * asscanrange; - newmis.think = AssCanBulletThink; - newmis.nextthink = time + num; // Projectile range / gravity + proj.think = AssCanBulletThink; + proj.nextthink = time + num; // Projectile range / gravity } else { - newmis.think = SUB_Remove; - newmis.nextthink = time + 5; // Stop projectile going forever + proj.think = SUB_Remove; + proj.nextthink = time + 5; // Stop projectile going forever } - newmis.frame = hwguy_random()*15; // Full range of sizes - newmis.skin = 16 + hwguy_random()*7; // Bright colours - newmis.weapon = DMSG_ASSAULTCANNON; + proj.frame = hwguy_random()*15; // Full range of sizes + proj.skin = 16 + hwguy_random()*7; // Bright colours + proj.weapon = DMSG_ASSAULTCANNON; - newmis.velocity = dir * proj_speed; // Constant speed multiplier - newmis.angles = vectoangles(dir); // Create direction angle - setorigin (newmis, org); // Move to starting position + proj.velocity = dir * proj_speed; // Constant speed multiplier + proj.angles = vectoangles(dir); // Create direction angle + setorigin (proj, org); // Move to starting position - newmis.wpp_aux = self.ammo_shells * 100 + index; - FOProj_Init(FPP_ASSAULT_CANNON, newmis); + proj.wpp_aux = self.ammo_shells * 100 + index; + FOProj_Finalize(proj); } void StopAssCan() { diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 40da0cac..214bb9d5 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -533,7 +533,6 @@ void (float num_bubbles, vector bub_origin) NewBubbles = { }; void () W_FireFlame = { - local entity flame; local float rn; if (self.waterlevel > 2) { @@ -548,7 +547,7 @@ void () W_FireFlame = { return; } self.ammo_cells = self.ammo_cells - 1; - flame = spawn(); + entity flame = FOProj_Create(FPP_FLAMETHROWER); flame.owner = self; flame.movetype = MOVETYPE_FLYMISSILE; flame.solid = SOLID_BBOX; @@ -571,7 +570,7 @@ void () W_FireFlame = { setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); - FOProj_Init(FPP_FLAMETHROWER, flame); + FOProj_Finalize(flame); }; void () IncendiaryRadius = { @@ -672,31 +671,31 @@ void () W_FireIncendiaryCannon = { } self.ammo_rockets = self.ammo_rockets - 3; KickPlayer(-3, self); - newmis = spawn(); - newmis.owner = self; - newmis.movetype = MOVETYPE_FLYMISSILE; - newmis.solid = SOLID_BBOX; + entity proj = FOProj_Create(FPP_INCENDIARY); + proj.owner = self; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.solid = SOLID_BBOX; makevectors(self.v_angle); - newmis.velocity = aim(self, 1000); + proj.velocity = aim(self, 1000); if (pyro_type == PYRO_ORIGINAL) { - newmis.velocity = newmis.velocity * 600; - newmis.think = SUB_Remove; + proj.velocity = proj.velocity * 600; + proj.think = SUB_Remove; } else { - newmis.velocity = newmis.velocity * fpp_types[FPP_INCENDIARY].speed; - newmis.think = IncendiaryRadius_OZTF; + proj.velocity = proj.velocity * fpp_types[FPP_INCENDIARY].speed; + proj.think = IncendiaryRadius_OZTF; } - newmis.angles = vectoangles(newmis.velocity); - newmis.touch = T_IncendiaryTouch; - newmis.nextthink = time + 5; - newmis.weapon = DMSG_INCENDIARY; - newmis.classname = "pyro_rocket"; - setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); - - FOProj_Init(FPP_INCENDIARY, newmis); + proj.angles = vectoangles(proj.velocity); + proj.touch = T_IncendiaryTouch; + proj.nextthink = time + 5; + proj.weapon = DMSG_INCENDIARY; + proj.classname = "pyro_rocket"; + setorigin(proj, self.origin + v_forward * 8 + '0 0 16'); + + FOProj_Finalize(proj); }; void () AirBlastReloadFinished = { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 6d4465c1..9a93972a 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1077,21 +1077,21 @@ void () HallucinationTimer = { void () W_FireTranq = { self.ammo_shells = self.ammo_shells - 1; KickPlayer(-2, self); - newmis = spawn(); - newmis.owner = self; - newmis.movetype = 9; - newmis.solid = 2; + entity proj = FOProj_Create(FPP_TRANQ); + proj.owner = self; + proj.movetype = 9; + proj.solid = 2; makevectors(self.v_angle); - newmis.velocity = v_forward; - newmis.velocity = newmis.velocity * fpp_types[FPP_TRANQ].speed; - newmis.angles = vectoangles(newmis.velocity); - newmis.touch = T_TranqDartTouch; - newmis.think = SUB_Remove; - newmis.nextthink = time + 6; - newmis.classname = "proj_tranq"; - setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); - - FOProj_Init(FPP_TRANQ, newmis); + proj.velocity = v_forward; + proj.velocity = proj.velocity * fpp_types[FPP_TRANQ].speed; + proj.angles = vectoangles(proj.velocity); + proj.touch = T_TranqDartTouch; + proj.think = SUB_Remove; + proj.nextthink = time + 6; + proj.classname = "proj_tranq"; + setorigin(proj, self.origin + v_forward * 8 + '0 0 16'); + + FOProj_Finalize(proj); }; void () T_TranqDartTouch = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ef841dc2..2d6d0c1e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1076,26 +1076,26 @@ void () T_MissileTouch = { }; void () W_FireRocket = { - newmis = spawn(); - newmis.owner = self; - newmis.movetype = MOVETYPE_FLYMISSILE; - newmis.solid = SOLID_BBOX; + entity proj = FOProj_Create(FPP_ROCKET); + proj.owner = self; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.solid = SOLID_BBOX; makevectors(self.v_angle); - newmis.velocity = v_forward * fpp_types[FPP_ROCKET].speed; - newmis.angles = vectoangles(newmis.velocity); + proj.velocity = v_forward * fpp_types[FPP_ROCKET].speed; + proj.angles = vectoangles(proj.velocity); - newmis.touch = T_MissileTouch; - newmis.voided = 0; + proj.touch = T_MissileTouch; + proj.voided = 0; - newmis.nextthink = time + 5; - newmis.think = SUB_Remove; + proj.nextthink = time + 5; + proj.think = SUB_Remove; - newmis.weapon = DMSG_ROCKETL; - newmis.classname = "proj_rocket"; - setorigin(newmis, self.origin + v_forward * 8 + '0 0 16'); + proj.weapon = DMSG_ROCKETL; + proj.classname = "proj_rocket"; + proj.origin = self.origin + v_forward * 8 + '0 0 16'; - FOProj_Init(FPP_ROCKET, newmis); + FOProj_Finalize(proj); self.ammo_rockets = self.ammo_rockets - 1; KickPlayer(-2, self); @@ -1325,19 +1325,19 @@ void () spike_touch; void () superspike_touch; entity (int fpp_type, vector offset) W_FireNail = { - newmis = spawn(); - newmis.voided = 0; - newmis.owner = self; - newmis.movetype = MOVETYPE_FLYMISSILE; - newmis.solid = SOLID_BBOX; + entity proj = FOProj_Create(fpp_type); + proj.voided = 0; + proj.owner = self; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.solid = SOLID_BBOX; - newmis.angles = vectoangles(aim(self, 1000)); - newmis.classname = "spike"; - newmis.think = SUB_Remove; - newmis.nextthink = time + 6; - setorigin(newmis, self.origin + offset + '0 0 16'); + proj.angles = vectoangles(aim(self, 1000)); + proj.classname = "spike"; + proj.think = SUB_Remove; + proj.nextthink = time + 6; + setorigin(proj, self.origin + offset + '0 0 16'); - newmis.velocity = aim(self, 1000) * fpp_types[fpp_type].speed; + proj.velocity = aim(self, 1000) * fpp_types[fpp_type].speed; if (fpp_type == FPP_NAIL) { newmis.weapon = DMSG_NAILGUN; @@ -1347,9 +1347,9 @@ entity (int fpp_type, vector offset) W_FireNail = { newmis.weapon = DMSG_SNAILGUN; } - FOProj_Init(fpp_type, newmis); + FOProj_Finalize(proj); - return newmis; + return proj; }; void (float ox) W_FireSpikes = { From a4bdb276e8d3c6892fb8375705b7c6e828e39740 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 02:11:19 -0800 Subject: [PATCH 1859/2474] Antilag trails Back-draw trails for antilagged projectiles --- csqc/weapon_predict.qc | 5 +++-- share/prediction.qc | 3 ++- ssqc/antilag.qc | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index d41ed133..ee7242dc 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -728,7 +728,6 @@ entity FPP_Init(int fpp_type, entity proj) { else setmodelindex(proj, desc->modelindex); - /* proj.p_time = proj.s_time + 1/77.0; */ proj.oldorigin = proj.s_origin; proj.traileffectnum = FPP_FindTrail(proj); @@ -1044,7 +1043,9 @@ void InitProjectileEnt() { } if (!has_predicted) { - self.oldorigin = self.origin; + // Back-track trail for entities without a local prediction. We use + // s_origin here as that's what we know antilag_ms to be relative to. + self.oldorigin = self.s_origin - self.antilag_ms/ 1000.0 * self.velocity; } } diff --git a/share/prediction.qc b/share/prediction.qc index f9743191..85376acf 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -4,6 +4,7 @@ // Below apply to both CSQC & SSQC ents .float fpp_index; // Projectile type +.int antilag_ms; #ifdef CSQC .vector s_origin; .float s_time; @@ -451,7 +452,7 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, velocity[2]); COMMO(Float, self.s_time, time); - + COMM(Byte, antilag_ms); } if (sendflags & FOPP_INIT) { diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 4c93fdde..f6de1b2e 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -41,6 +41,7 @@ void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { if (trace_fraction < 1) projected_origin = trace_endpos; + projectile.antilag_ms = time_offset; setorigin(projectile, projected_origin); } #define DEBUG_ANTILAG 0 From 3f241d93e8ff29379ca82c595cb6e89993473573 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 02:29:37 -0800 Subject: [PATCH 1860/2474] Disable weapon prediction when spectating In particular, we want to make sure that the engine weapon/etc is rendered. --- csqc/weapon_predict.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ee7242dc..18113dcc 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -78,6 +78,11 @@ static float CalcPredEnabled(float current_enable, return FALSE; } + if (is_spectator) { + *set_by = "[spectator]"; + return FALSE; + } + if (server_disable || client_value == 0) { *set_by = server_disable ? "[server disable]" : "[cvar disable]"; From 3ed484b305aa1bf546249976792c72041e176293 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 16:51:15 -0800 Subject: [PATCH 1861/2474] Fix NG/SNG not hitting Search and replace missed a spot. --- ssqc/weapons.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2d6d0c1e..30943818 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1340,11 +1340,11 @@ entity (int fpp_type, vector offset) W_FireNail = { proj.velocity = aim(self, 1000) * fpp_types[fpp_type].speed; if (fpp_type == FPP_NAIL) { - newmis.weapon = DMSG_NAILGUN; - newmis.touch = spike_touch; + proj.weapon = DMSG_NAILGUN; + proj.touch = spike_touch; } else { // fpp_type == FPP_SUPER_NAIL - newmis.touch = superspike_touch; - newmis.weapon = DMSG_SNAILGUN; + proj.weapon = DMSG_SNAILGUN; + proj.touch = superspike_touch; } FOProj_Finalize(proj); From 0bbf0529986c25e4aa1e436ad3e88606117c8ca1 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 16:56:10 -0800 Subject: [PATCH 1862/2474] Make sure we still static project with LAN pings Cutting out antilag projection was intentional, but this now also cuts out newmis forwarding. Restore. --- ssqc/antilag.qc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index f6de1b2e..a6e0917f 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -29,10 +29,8 @@ void AL_ProjectProjectile (entity projectile) { } void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { - if (NoLanProject()) - return; - - float max_credit = max_rewind_credit_ms(fpp_type) + dynamic_newmis_ms(); + float max_credit = NoLanProject() ? 0 : + max_rewind_credit_ms(fpp_type) + dynamic_newmis_ms(); float time_offset = min(self.client_ping, max_credit) + static_newmis_ms(fpp_type); vector projected_origin = projectile.origin + (projectile.velocity * (time_offset / 1000.0)); From ccdfcb4eb39ea01f5cb9f157518ecfec0aee410d Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 20:30:44 -0800 Subject: [PATCH 1863/2474] Unify projection offset calculation between client and server - Make rockets use 50ms of static projection for now, most RJs use 30-40, but for now just keep the behavior uniform. - Fix case where AC was getting static projection clientside but not server - Make LAN no projection cut off smoother. --- csqc/weapon_predict.qc | 37 +++++++++++++----------------- share/prediction.qc | 51 +++++++++++++++++++++++++++++++++++++----- ssqc/antilag.qc | 9 ++++---- 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 18113dcc..17949b2f 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -128,6 +128,8 @@ static float next_ping_update; void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; #define PRINT_CONFIG(_field) \ + printf(" ." #_field " = %d\n", fo_config.##_field) +#define PRINT_CONFIG_ACTIVE(_field) \ if (fo_config.##_field) printf(" ." #_field " = %d\n", fo_config.##_field) void WPP_Status() { string wp_source, pp_source; @@ -159,12 +161,12 @@ void WPP_Status() { PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); PRINT_CONFIG(wp_default_min_ping_ms); - PRINT_CONFIG(wp_global_enable); - PRINT_CONFIG(wp_global_disable); - PRINT_CONFIG(pp_global_enable); - PRINT_CONFIG(pp_global_disable); - PRINT_CONFIG(wpp_global_enable); - PRINT_CONFIG(wpp_global_disable); + PRINT_CONFIG_ACTIVE(wp_global_enable); + PRINT_CONFIG_ACTIVE(wp_global_disable); + PRINT_CONFIG_ACTIVE(pp_global_enable); + PRINT_CONFIG_ACTIVE(pp_global_disable); + PRINT_CONFIG_ACTIVE(wpp_global_enable); + PRINT_CONFIG_ACTIVE(wpp_global_disable); } #undef PRINT_CONFIG @@ -792,19 +794,6 @@ static vector PredProj_Pos(entity proj) { return proj.s_origin + offset * proj.velocity; } -// Predict the effective start time of something we fire right now, accounting -// for server side projection, ping fluctuation, etc. -float PP_StartOffset(int fpp_type) { - float max_credit = max_rewind_credit_ms(fpp_type); - // Server will credit full frame, average out to middle of prior. - const float frame_cor = 1.5 * 1/77.0; - - return (max(pstate_pred.client_ping - max_credit - dynamic_newmis_ms(), 0) - - static_newmis_ms(fpp_type)) / 1000.0 - frame_cor; -} - -static float PP_EPS = 0.05; - entity PP_CreateProjectile(int fpp_type, vector offset) { PredProj_Sound(fpp_type); @@ -825,9 +814,13 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { return __NULL__; #endif + ProjectResult push_t = + WeaponPred_ProjectOffset(fpp_type, pstate_pred.client_ping); + + float uncorrected_ms = pstate_pred.client_ping - push_t.dynamic_ms; // Note: We use true time here as created projectiles exist outside of pred. - proj.s_time = time + PP_StartOffset(fpp_type); - proj.starttime = max(time, proj.s_time); + proj.starttime = time + uncorrected_ms/1000.0; + proj.s_time = proj.starttime - push_t.static_ms/1000.0; proj.endtime = proj.starttime + pstate_pred.client_ping / 1000.0 + PP_EPS; proj.predraw = PP_PredrawPredicted; @@ -972,7 +965,7 @@ void WP_Attack() { // ** Not currently doing this because playing animation in advance is better // for understanding attack_finished as a player. ** float offset = - // max(PP_PredictStartOffset() - 2/77.0, 0); + // max(PP_PredictStartOffset() - 2*SERVER_FRAME_MS, 0); if (offset > 0) { if ((CVARF(wpp_debug) & 2) && pengine.is_effectframe) printf("held for %0.3f\n", offset); diff --git a/share/prediction.qc b/share/prediction.qc index 85376acf..169fd499 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -2,9 +2,12 @@ #define ENT_WEAPONPRED 101 #define ENT_PROJECTILE 102 +const float SERVER_FPS = 77; +const float SERVER_FRAME_MS = 1/SERVER_FPS * 1000.0; + // Below apply to both CSQC & SSQC ents .float fpp_index; // Projectile type -.int antilag_ms; +.float antilag_ms; #ifdef CSQC .vector s_origin; .float s_time; @@ -127,6 +130,7 @@ struct fo_projectile { string model; string trail; SoundIndex snd; + float fixed_project; // No dynamic proportioning of newmis projection // Automatically initialized below this line. float modelindex; @@ -134,9 +138,9 @@ struct fo_projectile { }; fo_projectile fpp_types[] = { - { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "", SND_RL }, + { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "", SND_RL, TRUE }, { FPP_GRENADE, 600, "grenade.mdl", "t_grenade", SND_GREN }, - { FPP_INCENDIARY, 800, "lavaball.mdl", "t_lavaball", SND_RL }, + { FPP_INCENDIARY, 800, "lavaball.mdl", "t_lavaball", SND_RL, TRUE }, { FPP_NAIL, 1500, "spike.mdl", "tr_spike", SND_NAIL }, { FPP_SUPER_NAIL, 1500, "s_spike.mdl", "tr_spike", SND_SNAIL }, { FPP_FLAMETHROWER, 600, "s_explod.spr", "explodesprite", SND_FLAMETHROWER }, @@ -186,15 +190,21 @@ float max_rewind_credit_ms(int fpp_type) { // NOTE: DO NOT USE NEWMIS FOR FO PROJECTILES. THE NEWMIS CORRECTION IS NOW // MADE EXPLICITLY RATHER THAN IMPLICITLY. [WE AUTOMATICALLY STRIP NEWMIS // FROM PROJECTILES PASSED TO US.] +static float NEWMIS_MS = 50; float static_newmis_ms(int fpp_type) { if (fpp_type == FPP_FLAMETHROWER || fpp_type == FPP_ASSAULT_CANNON) return 0; - return 50 - fo_config.dynamic_newmis_ms; + return NEWMIS_MS - fo_config.dynamic_newmis_ms; } + inline float dynamic_newmis_ms() { return fo_config.dynamic_newmis_ms; } + +inline float fixed_newmis_ms(int fpp_type) { + return NEWMIS_MS; +} .float wpp_aux; #ifdef SSQC @@ -523,7 +533,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_enable); CONFIG_UPDATE("wppge", wpp_global_disable); - CLAMP_UPDATE(dynamic_newmis_ms, 0, 50); + CLAMP_UPDATE(dynamic_newmis_ms, 0, NEWMIS_MS); CLAMP_UPDATE(max_rewind_ms, 0, 250); CLAMP_UPDATE(max_rewind_slow_projectile_ms, 0, fo_config.max_rewind_ms); CLAMP_UPDATE(max_rewind_fast_projectile_ms, 0, fo_config.max_rewind_ms); @@ -638,7 +648,6 @@ entity FOProj_Create(int fpp_type) { return prj; } - void FOProj_Finalize(entity mis) { int fpp_type = mis.fpp_index; // We explicitly do not use newmis. Newmis internally implements a fixed @@ -674,6 +683,36 @@ float get_shells() { return self.ammo_shells; } static inline vector get_origin() { return self.origin; } #endif +struct ProjectResult { + float static_ms; + float dynamic_ms; +}; + +ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { + float max_ping_credit = max_rewind_credit_ms(fpp_type); + float static_credit; + + if (fpp_types[fpp_type].fixed_project) { + static_credit = fixed_newmis_ms(fpp_type); + } else { + static_credit = static_newmis_ms(fpp_type); + max_ping_credit += dynamic_newmis_ms(); + } + + float frame_nudge = 0; +#ifdef SSQC + // On the server side, account for the fact that we won't do anything until + // the next frame. + frame_nudge = 1.5*SERVER_FRAME_MS; +#endif + float adj_ping = max(ping - frame_nudge, 0); + + ProjectResult result; + result.static_ms = static_credit; + result.dynamic_ms = min(adj_ping, max_ping_credit); + return result; +} + // Randomize by ammo index for consistency even if a packet/prediction misses. float hwguy_random_index; diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index a6e0917f..86cc7912 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -29,17 +29,16 @@ void AL_ProjectProjectile (entity projectile) { } void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { - float max_credit = NoLanProject() ? 0 : - max_rewind_credit_ms(fpp_type) + dynamic_newmis_ms(); - float time_offset = min(self.client_ping, max_credit) + static_newmis_ms(fpp_type); + ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, self.client_ping); + float offset_ms = offset.static_ms + offset.dynamic_ms; + vector projected_origin = projectile.origin + offset_ms / 1000.0 * projectile.velocity; - vector projected_origin = projectile.origin + (projectile.velocity * (time_offset / 1000.0)); traceline(projectile.origin, projected_origin, 0, self); if (trace_fraction < 1) projected_origin = trace_endpos; - projectile.antilag_ms = time_offset; + projectile.antilag_ms = offset_ms * trace_fraction; setorigin(projectile, projected_origin); } #define DEBUG_ANTILAG 0 From 32e47705ec606baae4d7ec25338ac9ca53941213 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 22:50:46 -0800 Subject: [PATCH 1864/2474] Fix server-side WEAPLAST bug Early return on WEAPLAST meant you couldn't WEAPLAST and fire in the same frame. This would previously generate a false projectile client-side as the server was blocked. --- csqc/weapon_predict.qc | 3 ++- ssqc/weapons.qc | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 17949b2f..5098626a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -320,6 +320,8 @@ float WP_CheckAmmo(FO_WeapInfo* wi) { return ammo > wi->ammo_per_shot; } +var float changed_weapon; + void WP_ChangeWeapon(Slot slot) { FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); if (!WP_CheckAmmo(wi)) @@ -624,7 +626,6 @@ void MP_SetSpeed() { } -float td; void WP_Frame() { MP_SetSpeed(); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 30943818..5ab58905 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2501,7 +2501,6 @@ void () W_WeaponFrame = { if (self.impulse == TF_WEAPLAST && self.is_undercover != 2) { W_ChangeWeaponLast(); self.impulse = 0; - return; } // +slot/-slot handle attack; we only need to swap back to last weapon. From 15733e177a17b72fe66b50eb0374a37928fd0f6b Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 9 Nov 2022 22:52:18 -0800 Subject: [PATCH 1865/2474] Block client-side reload in prematch --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 5098626a..3d737eae 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -484,7 +484,7 @@ string WP_GetClip() { void WP_Reload() { FO_WeapInfo* wi = WP_CurrentWeapon(); - if (!wi->needs_reload || WP_IsReloading()) + if (!wi->needs_reload || WP_IsReloading() || prematch) return; float clip_fired = *WP_ClipFired(); From 17c3ef7ee388751e5390f59dff192a3f6009a7cf Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 15 Nov 2022 21:30:44 -0800 Subject: [PATCH 1866/2474] Fix physics frame nudge to be client-side & optimize netcode This got wrapped the wrong way (ifdef SSQC) while splitting up patches. Update and move it to static nudge. Also, we don't need to transmit angles for our projectiles, it can be derived from velocity. --- csqc/weapon_predict.qc | 1 + share/prediction.qc | 20 +++++++++----------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 3d737eae..2858838d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1027,6 +1027,7 @@ void InitProjectileEnt() { FPP_Init(self.fpp_index, self); + self.angles = vectoangles(self.velocity); self.origin = self.s_origin + (time - self.s_time) * self.velocity; // We still check this with projectile prediction as there could be in diff --git a/share/prediction.qc b/share/prediction.qc index 169fd499..bc8bd412 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -462,15 +462,11 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, velocity[2]); COMMO(Float, self.s_time, time); - COMM(Byte, antilag_ms); } if (sendflags & FOPP_INIT) { COMM(Byte, fpp_index); - - COMM(Angle, angles[0]); - COMM(Angle, angles[1]); - COMM(Angle, angles[2]); + COMM(Byte, antilag_ms); } if (sendflags & FOPP_AUX) { @@ -700,15 +696,17 @@ ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { } float frame_nudge = 0; -#ifdef SSQC - // On the server side, account for the fact that we won't do anything until - // the next frame. - frame_nudge = 1.5*SERVER_FRAME_MS; +#ifdef CSQC + // Account for the fact that the server usually has a physics frame that's + // going to be credited to the new projectile. + frame_nudge = 1.5 * SERVER_FRAME_MS; #endif - float adj_ping = max(ping - frame_nudge, 0); + // Everything lower than SERVER_FRAME_MS falls into the next frame (and we + // have no resolution anyway), linearize beyond that. + float adj_ping = max(ping - SERVER_FRAME_MS, 0); ProjectResult result; - result.static_ms = static_credit; + result.static_ms = static_credit + frame_nudge; result.dynamic_ms = min(adj_ping, max_ping_credit); return result; } From b74a86ccbaee29aa27ec2e24ae7d2a5f8288c76c Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 16 Nov 2022 01:17:19 -0800 Subject: [PATCH 1867/2474] Fix Escape on Menus We were able to process escape twice from the same input leading to the menu simultaneously closing and opening. While here, clean up some legacy code such as MouseDown and a double new-frame check. --- csqc/csextradefs.qc | 6 ++++-- csqc/hud.qc | 2 -- csqc/input.qc | 24 ++++++++---------------- csqc/main.qc | 1 - csqc/menu.qc | 2 +- csqc/sui_sys.qc | 8 ++++++++ 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9c0c0c0f..24c6b098 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -361,7 +361,6 @@ typedef struct MouseStruct Mouse; MouseStruct PrevMouse; -float MouseDown; typedef struct { string filename; @@ -596,6 +595,8 @@ void HRC_SetActive(PanelID panel) { hud_render_cache.active_panel = panel; } +FO_Hud_Panel* getHudPanel(PanelID panelid); + // Returns true if HUD should be re-rendered this frame. float HRC_NewFrame() { // Rate limit even the more complicated enable checks. @@ -604,7 +605,8 @@ float HRC_NewFrame() { /* hud_render_cache.last_update = time; */ if (!CVARF(fo_hud_cache) || - fo_hud_menu_active || fo_hud_editor || showingscores) { + fo_hud_menu_active || fo_hud_editor || showingscores || + getHudPanel(HUDP_MAP_MENU)->Display) { // Either explicitly disabled, or rendering a more complicated scene // like the editor for which we'll just display in place. hud_render_cache.enabled = FALSE; diff --git a/csqc/hud.qc b/csqc/hud.qc index 9bae5d4d..6a53575e 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1103,8 +1103,6 @@ struct { } incremental_hud; void Hud_UpdateView(float width, float height, float menushown, float perf_sample) { - float hud_update = HRC_NewFrame(); - ScreenSize = [width, height, menushown]; if (HRC_NewFrame()) { float hts = perf_start_sample(&hud_timing, perf_sample); diff --git a/csqc/input.qc b/csqc/input.qc index 892640ff..81288a6d 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -7,6 +7,7 @@ static float HudInputEscape() { Menu_Cancel(); fo_hud_editor = FALSE; + printf("menu_close\n"); return TRUE; } @@ -20,19 +21,10 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; break; case IE_KEYDOWN: - switch (scanx) { - case K_ESCAPE: - if (HudInputEscape()) - return TRUE; - break; - case K_MOUSE1: - if(!fo_hud_editor && fo_hud_menu_active && - !(CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)) - break; + if (scanx == K_ESCAPE || scanx == K_MOUSE1) + return TRUE; - return TRUE; - } - if(fo_hud_menu_active) + if (fo_hud_menu_active) return fo_menu_process_input(CurrentMenu, scanx); break; case IE_MOUSEDELTA: @@ -44,6 +36,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } } else if(getHudPanel(HUDP_MAP_MENU)->Display) { sui_input_event(evtype, scanx, chary, devid); + switch (evtype) { case IE_MOUSEDELTA: return TRUE; @@ -52,7 +45,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { PrevMouse.y = Mouse.y; Mouse.x = scanx; Mouse.y = chary; - if (MouseDown) + if (sui_is_held(HUDP_MAP_MENU)) Hud_MapMenuPanel_Move(Mouse.x - PrevMouse.x, Mouse.y - PrevMouse.y); return TRUE; case IE_KEYDOWN: @@ -60,7 +53,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case K_ESCAPE: return TRUE; case K_MOUSE1: - MouseDown = TRUE; return TRUE; case K_UPARROW: vote_selected_index--; @@ -121,9 +113,8 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { showVoteMenu(FALSE); return TRUE; case K_MOUSE1: - MouseDown = FALSE; return TRUE; - } + } } } else { switch (evtype) @@ -132,6 +123,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { switch (scanx) { case K_ESCAPE: + printf("menu_open\n"); FO_Menu_Game(TRUE); return TRUE; } diff --git a/csqc/main.qc b/csqc/main.qc index d9e93539..b65ce9d3 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -114,7 +114,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_list_offset = 0; current_vote = world; vote_list_filter = ""; - MouseDown = 0; }; noref void() CSQC_WorldLoaded = { diff --git a/csqc/menu.qc b/csqc/menu.qc index 99472c7b..b2cd91f5 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -835,7 +835,7 @@ float fo_menu_process_input(fo_menu * menu, float scan) = { } void Menu_Cancel() = { - if(fo_hud_menu_active) { + if (fo_hud_menu_active) { setcursormode(FALSE); fo_hud_menu_active = FALSE; } diff --git a/csqc/sui_sys.qc b/csqc/sui_sys.qc index 6d0a4c6a..5818d610 100644 --- a/csqc/sui_sys.qc +++ b/csqc/sui_sys.qc @@ -285,6 +285,14 @@ float(PanelID id) sui_is_held = return _hold_action_count > 0 && _hold_actions[0] == id; }; +float sui_has_hold(PanelID id) { + for (float i = 0; i < _hold_action_count; i++) + if (_hold_actions[i] == id) + return TRUE; + + return FALSE; +} + // last clicked: is this the last action element that was clicked, good for focusing on input boxes for example float(PanelID id) sui_is_last_clicked = From 6508e1626535c9aca6abccfc8fe7b4870ada62c3 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 13 Oct 2022 13:18:05 -0700 Subject: [PATCH 1868/2474] Implement fixed-time physics in QC Re-implements FLY and BOUNCE physics in quakec. This is both necessary for us to be able to implement predicted grenade projectiles (which follow arcs) but also allows us to better align our client and server side predictions. We do this by moving physics to a fixed step (excess in the step is discarded) that can be aligned to ensure constant progression for a given time between client and server. The net-net is that this avoids small computational differences resulting in different bounces for client vs server side (since difference in time -> difference in acceleration -> difference in bounce/cutoff). One immediate benefit: antilag forwarding of grenades is now consistent with true grenade arc, as opposed to the linear projection prior. This is always used for client-side prediction and antilag projection. When "qc_physics 1" (or qcp) is set we also use it server side (as a customphysics) handler. --- csqc/csprogs.src | 1 + csqc/weapon_predict.qc | 64 ++++++++------- share/commondefs.qc | 1 + share/debug.qc | 16 +++- share/physics.qc | 182 +++++++++++++++++++++++++++++++++++++++++ share/prediction.qc | 84 +++++++++++++++---- ssqc/antilag.qc | 12 +-- ssqc/progs.src | 1 + 8 files changed, 306 insertions(+), 55 deletions(-) create mode 100644 share/physics.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 8c163ac6..747eeb02 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -14,6 +14,7 @@ csextradefs.qc ../share/commondefs.qc ../share/common_helpers.qc ../share/common_vote.qc +../share/physics.qc ../share/weapons.qc ../share/prediction.qc ../share/animate.qc diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2858838d..c3b693c0 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -155,6 +155,7 @@ void WPP_Status() { printf(" inst_ping = %d avg_ping = %d var = %d\n", ping, avg, variance); printf("Config:\n"); + PRINT_CONFIG(qc_physics); PRINT_CONFIG(dynamic_newmis_ms); PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); @@ -242,8 +243,6 @@ void Attack_Finished(float attack_time) { //////////////////////////////////////////////////////////////////////////////// /// Weapon models //////////////////////////////////////////////////////////////////////////////// -float animate_s_time; - static entity pred_sound_entity; static float last_pred_sound; @@ -726,7 +725,7 @@ int FPP_FindTrail(entity e) DEFCVAR_FLOAT(cl_r2g, 0); -entity FPP_Init(int fpp_type, entity proj) { +void FPP_Init(int fpp_type, entity proj) { fo_projectile* desc = &fpp_types[fpp_type]; proj.fpp_index = fpp_type; @@ -736,10 +735,12 @@ entity FPP_Init(int fpp_type, entity proj) { else setmodelindex(proj, desc->modelindex); - proj.oldorigin = proj.s_origin; - proj.traileffectnum = FPP_FindTrail(proj); + if (fpp_type == FPP_GRENADE) { + proj.avelocity = '300 300 300'; + } - return proj; + proj.traileffectnum = FPP_FindTrail(proj); + proj.movetype = desc->movetype; } DEFCVAR_FLOAT(r_rocketlight, 1); @@ -748,10 +749,7 @@ DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); .float trail_started; float PP_PredrawActive() { - float delta = time - self.s_time; - - self.origin = self.s_origin + (self.velocity * delta); - setorigin(self, self.origin); + CPhys_Update(self); // we need to space out the particles incase we're running at very high fps if (time > self.p_time) { @@ -790,11 +788,6 @@ float PP_PredrawPredicted() { static float PP_EPS = 0.05; -static vector PredProj_Pos(entity proj) { - float offset = time - proj.s_time; - return proj.s_origin + offset * proj.velocity; -} - entity PP_CreateProjectile(int fpp_type, vector offset) { PredProj_Sound(fpp_type); @@ -818,12 +811,14 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { ProjectResult push_t = WeaponPred_ProjectOffset(fpp_type, pstate_pred.client_ping); - float uncorrected_ms = pstate_pred.client_ping - push_t.dynamic_ms; + float uncorrected_dt = (pstate_pred.client_ping - push_t.dynamic_ms) / 1000.0; + float static_dt = push_t.static_ms / 1000.0; // Note: We use true time here as created projectiles exist outside of pred. - proj.starttime = time + uncorrected_ms/1000.0; - proj.s_time = proj.starttime - push_t.static_ms/1000.0; + proj.starttime = time + uncorrected_dt; + proj.s_time = proj.starttime - static_dt; proj.endtime = proj.starttime + pstate_pred.client_ping / 1000.0 + PP_EPS; + proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; @@ -831,12 +826,11 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.s_origin = pmove_org + offset; proj.s_origin[2] += 16; proj.velocity = v_forward * fpp_types[fpp_type].speed; + proj.angles = input_angles; proj.angles[0] *= -1; - proj.origin = PredProj_Pos(proj); + CPhys_Init(proj, proj.starttime, static_dt); proj.oldorigin = proj.origin; - proj.angles = input_angles; proj.angles[0] *= -1; - proj.pred_next = predicted_projectiles; if (predicted_projectiles) predicted_projectiles.pred_prev = proj; @@ -981,18 +975,21 @@ void WP_Attack() { float PredProjectile_MatchProjectile() { entity proj, match = __NULL__; - float best = 200; + float best = 64; for(proj = predicted_projectiles; proj != __NULL__; proj = proj.pred_next) { + if (proj == self) + error("???"); + if (proj.fpp_index != self.fpp_index || proj.wpp_aux != self.wpp_aux) continue; if (time > proj.endtime - 0.01) break; // Projectile list is time ordered - proj.origin = PredProj_Pos(proj); + CPhys_Sync(proj, max(time, self.phys_time)); float d = vlen(proj.origin - self.origin); - if (d < best) { + if (!best || d < best) { best = d; match = proj; } @@ -1004,12 +1001,14 @@ float PredProjectile_MatchProjectile() { self.trail_started = match.trail_started; if (CVARF(wpp_debug) & 1) { - string s = sprintf(" p_diff = %0.3f, t_e=%0.3f", + string s = sprintf(" p_diff = %0.1f, t_e=%0.3f t=%0.3f d_t=%0.3f", vlen(match.origin - self.origin), - vlen(match.origin - self.origin) / vlen(self.velocity)); - s = strcat(s, sprintf(" [c=%0.3f/%0.3f (s_t=%0.3f) s=%0.3f/%0.3f]\n", - vlen(match.origin - pmove_org),time, match.s_time, - vlen(self.origin - pmove_org),self.s_time)); + vlen(match.origin - self.origin) / vlen(self.velocity), + time, time - self.phys_time); + s = strcat(s, sprintf(" [c=%d/%0.3f s=%d/%0.3f,%0.3f] alms=%d\n", + vlen(match.origin - pmove_org), match.phys_time, + vlen(self.origin - pmove_org), self.s_time, self.phys_time, + self.antilag_ms)); print(s); } @@ -1024,11 +1023,12 @@ float PredProjectile_MatchProjectile() { void InitProjectileEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; + self.s_time = self.phys_time; FPP_Init(self.fpp_index, self); self.angles = vectoangles(self.velocity); - self.origin = self.s_origin + (time - self.s_time) * self.velocity; + CPhys_Init(self, max(time, self.phys_time), time - self.phys_time); // We still check this with projectile prediction as there could be in // flight projectiles on the transition. This is effectively a nop in the @@ -1049,6 +1049,10 @@ void InitProjectileEnt() { } } +void WP_SyncPhysProjectile() { + CPhys_Init(self, max(time, self.phys_time), time - self.phys_time); +} + DEFCVAR_FLOAT(r_drawviewmodel, 1); void WP_UpdateViewModel(entity pweap_ent) { diff --git a/share/commondefs.qc b/share/commondefs.qc index 4a1ba000..6d2ab3a3 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,4 +1,5 @@ var struct { + float qc_physics; float dynamic_newmis_ms; float max_rewind_ms; float max_rewind_slow_projectile_ms; diff --git a/share/debug.qc b/share/debug.qc index c94c4b1c..fb98f0ae 100644 --- a/share/debug.qc +++ b/share/debug.qc @@ -1,15 +1,29 @@ #ifdef SSQC +#define IS_CSQC 0 +#define IS_SSQC 1 + // printf that works in any context #define printf(...) bprint(PRINT_HIGH, sprintf(__VA_ARGS__)) #define printd(...) dprint(sprintf(__VA_ARGS__)) -#else +#elif defined(CSQC) + +#define IS_CSQC 1 +#define IS_SSQC 0 #define printf(...) print(sprintf(__VA_ARGS__)) #endif +inline string qc_prefix() { +#ifdef SSQC + return "SSQC"; +#else + return "CSQC"; +#endif +} + #define MSEC 0.001 #define SEC 1 diff --git a/share/physics.qc b/share/physics.qc new file mode 100644 index 00000000..faafb8af --- /dev/null +++ b/share/physics.qc @@ -0,0 +1,182 @@ +#define PHYS_DEBUG 0 + +static const float phys_tic = 0.005; + +.float phys_time; // Last physics time, 0 ==> s_time +.float phys_carry; // Carry from last partial tic +.float phys_t; // Total physics time accumulated + +#ifdef SSQC +static void Phys_Impact(entity e) { + if (trace_ent.solid == SOLID_NOT) + return; + + if (e.touch) { + entity held_self = self; + self = e; + other = trace_ent; + self.touch(); + self = held_self; + } +} +#else +.entity groundentity; +.vector s_origin; +.float is_removed; // The server code implements this to track entity removal + // for debug checks. But we can usefully piggy-back on it. + +static void Phys_Impact(entity e) { + if (trace_ent.solid == SOLID_NOT) + return; + + if (e.movetype == MOVETYPE_FLYMISSILE) { + e.is_removed = TRUE; + } +} + +float Phys_Advance(entity e, float delta); + +void CPhys_Sync(entity e, float target_time) { + if (target_time > e.phys_time) { + Phys_Advance(e, target_time - e.phys_time); + e.phys_time = target_time; + } +} + +void CPhys_Update(entity e) { + CPhys_Sync(e, time); +} + +void CPhys_Init(entity e, float target_time, float delta) { + e.origin = e.s_origin; + if (delta > 0) { + Phys_Advance(e, delta); + } else { + setorigin(e, e.origin); + } + e.phys_carry = 0; + e.phys_time = target_time; +} +#endif + +static inline float get_gravity() { return cvar("sv_gravity"); } + +#define dot(v1, v2) ((vector)v1 * (vector)v2) + +float Phys_Push(entity e, vector offset) { + float flags = 0; + + if (e.movetype == MOVETYPE_FLYMISSILE) + flags |= MOVE_MISSILE; + + traceline(e.origin, e.origin + offset, flags, e.owner); + e.origin = trace_endpos; + + if (trace_fraction < 1) { + setorigin(e, trace_endpos); + Phys_Impact(e); + return FALSE; + } + + return TRUE; +} + +static float epsilon = 0.1; // Matches ftesv +vector Phys_ClipVel(vector orig, vector normal, float overbounce) { + float backoff = -dot(orig, normal) * overbounce; + vector result = orig + backoff * normal; + + if (result[0] > -epsilon && result[0] < epsilon) result[0] = 0; + if (result[1] > -epsilon && result[1] < epsilon) result[1] = 0; + if (result[2] > -epsilon && result[2] < epsilon) result[2] = 0; + + return result; +} + +float Phys_Adv_Bounce(entity e, float dt) { + float g = get_gravity(); + + if (e.flags & FL_ONGROUND) { + if (-e.velocity_z >= 1.0/32.0) + e.flags &= ~FL_ONGROUND; + else // Consider falling through removed entity here at some point. + return 0; + } + + e.velocity_z -= 0.5 * dt * g; + + float move_time = dt, bounce; + if (Phys_Push(e, move_time * e.velocity)) { + e.velocity_z -= 0.5 * dt * g; + e.angles += dt * e.avelocity; + return dt; + } + + move_time *= min(1 - trace_fraction, 0); + e.angles += move_time * e.avelocity; + + float bounce_stop = 60 / 800 * g; + e.velocity = Phys_ClipVel(e.velocity, trace_plane_normal, 1.5); + + if (PHYS_DEBUG) + printf("%s v=%0.3f p=%v\n", qc_prefix(), e.velocity_z, e.origin); + + float bounce_speed = dot(trace_plane_normal, e.velocity); + if (trace_plane_normal.z > 0.7 && fabs(bounce_speed) < bounce_stop) { + e.flags |= FL_ONGROUND; + e.groundentity = trace_ent; + e.velocity = '0 0 0'; + e.avelocity = '0 0 0'; + } else { + e.velocity_z -= 0.5 * dt * g; + } + + return dt - move_time; +} + +float Phys_Adv_Linear(entity e, float dt) { + Phys_Push(e, dt * e.velocity); + + if (trace_fraction < 1) + dt *= trace_fraction; + + e.angles += dt * e.avelocity; + return dt; +} + +float Phys_Advance(entity e, float delta) { + if (delta < 0 || e.is_removed) + return 0; + + if (phys_tic * vlen(e.velocity) > 32) + error("phys_tic too big, needs adaptive scaling\n"); + + float total = 0, dt = 0; + delta += e.phys_carry; + while (delta > phys_tic) { + switch (e.movetype) { + case MOVETYPE_FLY: + case MOVETYPE_FLYMISSILE: + // Linear projectiles we can always simulate in a single step. + dt = Phys_Adv_Linear(e, delta); + delta = 0; + break; + case MOVETYPE_BOUNCE: + dt = Phys_Adv_Bounce(e, phys_tic); + delta -= phys_tic; + break; + default: + errorf("unsupported movetype %d\n", e.movetype); + + } + + total += dt; + } + e.phys_t += total; + + e.phys_carry = delta; + setorigin(e, e.origin); + return total; +} + +#undef dot diff --git a/share/prediction.qc b/share/prediction.qc index bc8bd412..45c98666 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -3,17 +3,17 @@ #define ENT_PROJECTILE 102 const float SERVER_FPS = 77; -const float SERVER_FRAME_MS = 1/SERVER_FPS * 1000.0; +const float SERVER_FRAME_DT = 1/SERVER_FPS; +const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; // Below apply to both CSQC & SSQC ents .float fpp_index; // Projectile type .float antilag_ms; #ifdef CSQC -.vector s_origin; .float s_time; #endif -string wp_version = "v0.2"; +string wp_version = "v0.3-phys"; enumflags { FOWP_CTIME, @@ -126,6 +126,7 @@ enum { struct fo_projectile { int id; + int movetype; float speed; string model; string trail; @@ -138,15 +139,24 @@ struct fo_projectile { }; fo_projectile fpp_types[] = { - { FPP_ROCKET, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "", SND_RL, TRUE }, - { FPP_GRENADE, 600, "grenade.mdl", "t_grenade", SND_GREN }, - { FPP_INCENDIARY, 800, "lavaball.mdl", "t_lavaball", SND_RL, TRUE }, - { FPP_NAIL, 1500, "spike.mdl", "tr_spike", SND_NAIL }, - { FPP_SUPER_NAIL, 1500, "s_spike.mdl", "tr_spike", SND_SNAIL }, - { FPP_FLAMETHROWER, 600, "s_explod.spr", "explodesprite", SND_FLAMETHROWER }, - { FPP_TRANQ, PC_SPY_TRANQSPEED, "spike.mdl", "tr_spike", SND_TRANQ }, - { FPP_RAILGUN, PC_ENGINEER_RAILSPEED, "e_spike1.mdl", "te_railtrail", SND_RAILGUN }, - { FPP_ASSAULT_CANNON, 3000, "proj_diam2.mdl", "tr_asscan", SND_NONE /* in anim */ }, + { FPP_ROCKET, MOVETYPE_FLYMISSILE, PC_SOLDIER_ROCKET_SPEED, + "missile.mdl", "", SND_RL, TRUE }, + { FPP_GRENADE, MOVETYPE_BOUNCE, 600, + "grenade.mdl", "t_grenade", SND_GREN }, + { FPP_INCENDIARY, MOVETYPE_FLYMISSILE, 800, + "lavaball.mdl", "t_lavaball", SND_RL, TRUE }, + { FPP_NAIL, MOVETYPE_FLYMISSILE, 1500, + "spike.mdl", "tr_spike", SND_NAIL }, + { FPP_SUPER_NAIL, MOVETYPE_FLYMISSILE, 1500, + "s_spike.mdl", "tr_spike", SND_SNAIL }, + { FPP_FLAMETHROWER, MOVETYPE_FLYMISSILE, 600, + "s_explod.spr", "explodesprite", SND_FLAMETHROWER }, + { FPP_TRANQ, MOVETYPE_FLYMISSILE, PC_SPY_TRANQSPEED, + "spike.mdl", "tr_spike", SND_TRANQ }, + { FPP_RAILGUN, MOVETYPE_FLYMISSILE, PC_ENGINEER_RAILSPEED, + "e_spike1.mdl", "te_railtrail", SND_RAILGUN }, + { FPP_ASSAULT_CANNON, MOVETYPE_FLYMISSILE, 3000, + "proj_diam2.mdl", "tr_asscan", SND_NONE /* in anim */ }, }; void InitFppProjectiles() { @@ -339,6 +349,7 @@ float WP_SendConfig(entity to_player, float sendflags) { #define COMM(_type, _field) fo_config.##_field = Read##_type() void EntUpdate_Config() { #endif + COMM(Float, qc_physics); COMM(Float, dynamic_newmis_ms); COMM(Float, max_rewind_ms); COMM(Float, max_rewind_slow_projectile_ms); @@ -435,7 +446,6 @@ void EntUpdate_WeaponPred(float isnew) { } #undef COMM - #ifdef SSQC #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.##_field) #define COMMD(_type, _dest, _field) COMM(_type, _field) @@ -444,6 +454,7 @@ float PP_SendEntity(entity to_player, float sendflags) { WriteByte(MSG_ENTITY, ENT_PROJECTILE); WriteByte(MSG_ENTITY, sendflags); #else +void WP_SyncPhysProjectile(); #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() #define COMMO(_type, _dest, _src) ##_dest = Read##_type() @@ -461,7 +472,8 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, velocity[1]); COMM(Coord, velocity[2]); - COMMO(Float, self.s_time, time); + COMM(Float, phys_time); + COMM(Float, phys_carry); } if (sendflags & FOPP_INIT) { @@ -480,6 +492,8 @@ void EntUpdate_Projectile(float isnew) { self.owner_entnum = readentitynum(); if (isnew) InitProjectileEnt(); + else + WP_SyncPhysProjectile(); #endif } #undef COMMD @@ -487,6 +501,7 @@ void EntUpdate_Projectile(float isnew) { #undef COMM void WeapPred_InitDefaultConfig() { + fo_config.qc_physics = 0; fo_config.dynamic_newmis_ms = 25; fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 100; @@ -516,6 +531,7 @@ static void WeaponPred_CheckConfigUpdate() { float update = FALSE; // Target is also the long form localinfo name. + CONFIG_UPDATE("qcp", qc_physics); CONFIG_UPDATE("dnm", dynamic_newmis_ms); CONFIG_UPDATE("mrt", max_rewind_ms); CONFIG_UPDATE("mrsp", max_rewind_slow_projectile_ms); @@ -578,6 +594,8 @@ void WeaponPred_InitPlayer(entity player) { "FortressOne: Weapon Prediction ", wp_version, "\n"); sprint(player, PRINT_HIGH, "FortressOne: CSQC projectiles ", fo_projectiles ? "enabled\n" : "disabled\n"); + sprint(player, PRINT_HIGH, "FortressOne: QC Physics ", + fo_config.qc_physics ? "enabled\n" : "disabled\n"); entity pe = spawn(); pe.owner = player; @@ -633,6 +651,31 @@ void PredProj_Sound(int proj_type, float vol = 1) { void WeaponPred_ProjectProjectile(int fpp_type, entity projectile); +void FO_Phys() { + float delta = time - self.phys_time; + if (delta > 0) { + Phys_Advance(self, delta); + self.phys_time = time; + } + + float held_time, thinktime; + // Once we lift physics, think execution comes with it. + do { + thinktime = self.nextthink; + if (thinktime <= 0 || thinktime > time) + return; + + held_time = time; + self.nextthink = 0; + time = thinktime; + self.think(); + time = held_time; + + if (self.is_removed || self.nextthink < thinktime /* no loop on rev */) + return; + } while (1); +} + entity FOProj_Create(int fpp_type) { entity prj = spawn(); @@ -658,6 +701,13 @@ void FOProj_Finalize(entity mis) { } PredProj_Sound(fpp_type); + + // We always need to init some of the state here (e.g. phys_time) as we + // always use the physics code client-side. + mis.phys_time = time; + if (fo_config.qc_physics) + mis.customphysics = FO_Phys; + WeaponPred_ProjectProjectile(mis.fpp_index, mis); // Below is conditional on using custom SendEntity. @@ -684,6 +734,10 @@ struct ProjectResult { float dynamic_ms; }; +#ifdef CSQC +DEFCVAR_FLOAT(wpp_phys_nudge, 2/3 * SERVER_FRAME_MS); +#endif + ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { float max_ping_credit = max_rewind_credit_ms(fpp_type); float static_credit; @@ -699,7 +753,7 @@ ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { #ifdef CSQC // Account for the fact that the server usually has a physics frame that's // going to be credited to the new projectile. - frame_nudge = 1.5 * SERVER_FRAME_MS; + frame_nudge = fo_config.qc_physics ? CVARF(wpp_phys_nudge) : 1.5 * SERVER_FRAME_MS; #endif // Everything lower than SERVER_FRAME_MS falls into the next frame (and we // have no resolution anyway), linearize beyond that. diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 86cc7912..00cc14ce 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -30,16 +30,10 @@ void AL_ProjectProjectile (entity projectile) { void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, self.client_ping); - float offset_ms = offset.static_ms + offset.dynamic_ms; - vector projected_origin = projectile.origin + offset_ms / 1000.0 * projectile.velocity; + float offset_dt = (offset.static_ms + offset.dynamic_ms) / 1000.0; - traceline(projectile.origin, projected_origin, 0, self); - - if (trace_fraction < 1) - projected_origin = trace_endpos; - - projectile.antilag_ms = offset_ms * trace_fraction; - setorigin(projectile, projected_origin); + float dt = Phys_Advance(projectile, offset_dt); + projectile.antilag_ms = dt * 1000; } #define DEBUG_ANTILAG 0 diff --git a/ssqc/progs.src b/ssqc/progs.src index f3346b56..35c57103 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -18,6 +18,7 @@ qw.qc debug.qc time.qc ../share/defs.h +../share/physics.qc ../share/weapons.qc ../share/prediction.qc ../share/animate.qc From aa93eafedd9f3fb362d6e14955c62314a98b16a4 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 16 Nov 2022 10:41:39 -0800 Subject: [PATCH 1869/2474] Remove debug prints Left over from fixing Escape --- csqc/input.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 81288a6d..0988d06b 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -7,7 +7,6 @@ static float HudInputEscape() { Menu_Cancel(); fo_hud_editor = FALSE; - printf("menu_close\n"); return TRUE; } @@ -123,7 +122,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { switch (scanx) { case K_ESCAPE: - printf("menu_open\n"); FO_Menu_Game(TRUE); return TRUE; } From 48d3819d354eb6b4b682f9455791097faef6072a Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 17 Nov 2022 11:18:10 -0800 Subject: [PATCH 1870/2474] Predict Grenade Launcher Connect all of the new physics code up to grenade launcher. --- csqc/weapon_predict.qc | 53 +++++++++++++++++++++++++++++---- share/defs.h | 2 +- share/prediction.qc | 45 ++++++++++++++++++++-------- share/weapons.qc | 4 +-- ssqc/client.qc | 4 +-- ssqc/weapons.qc | 67 +++++++++++++++++++++--------------------- 6 files changed, 117 insertions(+), 58 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c3b693c0..e1134cc3 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -793,6 +793,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { if (!PP_Enabled()) return __NULL__; + makevectors(input_angles); entity proj = spawn(); FPP_Init(fpp_type, proj); @@ -824,8 +825,20 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { setsize(proj, [0,0,0], [0,0,0]); proj.s_origin = pmove_org + offset; - proj.s_origin[2] += 16; - proj.velocity = v_forward * fpp_types[fpp_type].speed; + + if (fpp_type != FPP_GRENADE) { + proj.velocity = v_forward * fpp_types[fpp_type].speed; + proj.s_origin[2] += 16; + } else { + if (!input_angles_x) { + proj.velocity = v_forward * fpp_types[fpp_type].speed; + proj.velocity_z = 200; + } else { + proj.velocity = (v_forward * 600) + + (200 + shared_crandom(PRNG_WEAP) * 10) * v_up + + (shared_crandom(PRNG_WEAP) * 10 * v_right); + } + } proj.angles = input_angles; proj.angles[0] *= -1; CPhys_Init(proj, proj.starttime, static_dt); @@ -839,6 +852,26 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { return proj; } +static void FPP_ApplyGrenadeProperties(entity proj) { + if (proj.fpp_index != FPP_GRENADE) + return; + + switch (proj.wpp_aux) { + case GREN_RED: + proj.skin = 1; + break; + case GREN_PIPE: + proj.skin = 2; + break; + } +} + +void W_FireGrenade(int gren_type) { + entity proj = PP_CreateProjectile(FPP_GRENADE, '0 0 0'); + proj.wpp_aux = gren_type; + FPP_ApplyGrenadeProperties(proj); +} + void W_FireAssaultCannon() { FO_WeapInfo* wi = WP_CurrentWeapon(); WP_ConsumeAmmo(wi); @@ -930,12 +963,17 @@ void WP_Attack() { case WEAP_GRENADE_LAUNCHER: case WEAP_PIPE_LAUNCHER: - Pred_Sound(SND_GREN); break; + if (fo_config.qc_physics) + W_FireGrenade(wi->weapon == WEAP_GRENADE_LAUNCHER ? + GREN_RED : GREN_PIPE); + else + Pred_Sound(SND_GREN); + break; case WEAP_AXE: case WEAP_KNIFE: case WEAP_MEDIKIT: - melee_anim = shared_prng(PRNG_AXE) < 0.5 ? player_axeN : player_axebN; + melee_anim = shared_prng(PRNG_WEAP) < 0.5 ? player_axeN : player_axebN; // Fall through for sound. case WEAP_SPANNER: Pred_Sound(SND_AXE); break; @@ -1000,6 +1038,9 @@ float PredProjectile_MatchProjectile() { self.p_time = match.p_time; self.trail_started = match.trail_started; + if (self.fpp_index == FPP_GRENADE) + self.angles = match.angles; + if (CVARF(wpp_debug) & 1) { string s = sprintf(" p_diff = %0.1f, t_e=%0.3f t=%0.3f d_t=%0.3f", vlen(match.origin - self.origin), @@ -1024,10 +1065,11 @@ void InitProjectileEnt() { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; self.s_time = self.phys_time; + self.angles = vectoangles(self.velocity); FPP_Init(self.fpp_index, self); + FPP_ApplyGrenadeProperties(self); - self.angles = vectoangles(self.velocity); CPhys_Init(self, max(time, self.phys_time), time - self.phys_time); // We still check this with projectile prediction as there could be in @@ -1116,7 +1158,6 @@ float WP_ClientThink() { pstate_pred.buttons_up = old_input_buttons & (~input_buttons); pstate_pred.buttons_down = (~old_input_buttons) & input_buttons; - makevectors(input_angles); if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; diff --git a/share/defs.h b/share/defs.h index 026e3b1a..26dcc435 100644 --- a/share/defs.h +++ b/share/defs.h @@ -275,7 +275,7 @@ enumflags { #define TFSTATE_AC_FIRING (TFSTATE_AC_SPINUP|TFSTATE_AC_SPINNING) enum { - PRNG_AXE, + PRNG_WEAP, PRNG_HWGUY, PRNG_NUM_STATES, }; diff --git a/share/prediction.qc b/share/prediction.qc index 45c98666..bcca2e21 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -26,7 +26,8 @@ enumflags { FOWP_AF, FOWP_CLASS, FOWP_RELOAD, - FOWP_RNG, + FOWP_RNG0, + FOWP_RNG1, FOWP_PREDICT_FLAGS, }; @@ -63,7 +64,6 @@ struct predict_tf_state { float clip_fired[4]; int prng_base[PRNG_NUM_STATES]; - // Used for prediction, not actually communicated. Reset each frame. float ammo_used[AMMO_NUM_TYPES]; float buttons_down, buttons_up, buttons_held; @@ -142,7 +142,7 @@ fo_projectile fpp_types[] = { { FPP_ROCKET, MOVETYPE_FLYMISSILE, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "", SND_RL, TRUE }, { FPP_GRENADE, MOVETYPE_BOUNCE, 600, - "grenade.mdl", "t_grenade", SND_GREN }, + "grenade2.mdl", "t_grenade", SND_GREN, TRUE}, { FPP_INCENDIARY, MOVETYPE_FLYMISSILE, 800, "lavaball.mdl", "t_lavaball", SND_RL, TRUE }, { FPP_NAIL, MOVETYPE_FLYMISSILE, 1500, @@ -159,6 +159,12 @@ fo_projectile fpp_types[] = { "proj_diam2.mdl", "tr_asscan", SND_NONE /* in anim */ }, }; +// `wpp_aux` disambiguation for FPP_GRENADE projectiles. +enum { + GREN_RED, + GREN_PIPE, +}; + void InitFppProjectiles() { float i; static int once; @@ -269,6 +275,10 @@ float shared_prng(int type) { return (*prng_state(type) = lfsr_prng_raw(*prng_state(type))) / 65535.0; } +float shared_crandom(int type) { + return 2 * (shared_prng(type) - 0.5); +} + #ifdef SSQC #define OP1(_op, _f1) (player.predict_state.##_f1 _op player.##_f1) #define OP2(_op, _j, _f1, _f2) OP1(_op, _f2) _j OP1(_op, _f1) @@ -303,9 +313,10 @@ void WeaponPred_Update(entity player) { M1(FOWP_WF, weaponframe); M1(FOWP_AF, attack_finished); M2(FOWP_THINK, client_nextthink, client_thinkindex); - M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]) - M1(FOWP_RELOAD, reload_finished) - M2(FOWP_RNG, prng_base[0], prng_base[1]) + M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]); + M1(FOWP_RELOAD, reload_finished); + M1(FOWP_RNG0, prng_base[PRNG_WEAP]); + M1(FOWP_RNG1, prng_base[PRNG_HWGUY]) player.predict_entity.SendFlags = mask; } @@ -430,10 +441,10 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_RELOAD) COMM(Float, reload_finished); - if (sendflags & FOWP_RNG) { - COMM(Float, prng_base[0]); - COMM(Float, prng_base[1]); - } + if (sendflags & FOWP_RNG0) + COMM(Short, prng_base[0]); + if (sendflags & FOWP_RNG1) + COMM(Short, prng_base[1]); #ifdef SSQC return TRUE; @@ -502,7 +513,7 @@ void EntUpdate_Projectile(float isnew) { void WeapPred_InitDefaultConfig() { fo_config.qc_physics = 0; - fo_config.dynamic_newmis_ms = 25; + fo_config.dynamic_newmis_ms = 0; fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 100; fo_config.max_rewind_fast_projectile_ms = 100; @@ -702,16 +713,24 @@ void FOProj_Finalize(entity mis) { PredProj_Sound(fpp_type); + float csqc_networking = fo_projectiles; + // We always need to init some of the state here (e.g. phys_time) as we // always use the physics code client-side. mis.phys_time = time; - if (fo_config.qc_physics) + if (fo_config.qc_physics) { mis.customphysics = FO_Phys; + } else { + // If we don't have physics synchronized between client and server, use + // engine-side for both. + if (mis.fpp_index == FPP_GRENADE) + csqc_networking = FALSE; + } WeaponPred_ProjectProjectile(mis.fpp_index, mis); // Below is conditional on using custom SendEntity. - if (fo_projectiles) { + if (csqc_networking) { mis.SendEntity = PP_SendEntity; mis.SendFlags = FOPP_POS | FOPP_INIT; if (mis.wpp_aux) diff --git a/share/weapons.qc b/share/weapons.qc index cc0f2db2..a6ca0c78 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -115,8 +115,8 @@ FO_WeapInfo weapon_info[] = { { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, { WEAP_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.2, 0 }, { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 2, 0.2, 0 }, - { WEAP_GRENADE_LAUNCHER, PRED_MODEL, AMMO_ROCKETS, 6, 1, 0.6, 4 }, - { WEAP_PIPE_LAUNCHER, PRED_MODEL, AMMO_NONE, 0, 1, 0.6, 4 }, // Overlaps GL + { WEAP_GRENADE_LAUNCHER , PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, + { WEAP_PIPE_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, PRED_PROJ, AMMO_ROCKETS, 0, 3, -9, 0 }, diff --git a/ssqc/client.qc b/ssqc/client.qc index c4ecd392..111d93bf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2064,8 +2064,8 @@ void () PutClientInServer = { FO_InstantReloadAllWeapons(self); // Only need initial init here. - if (!self.prng_base[PRNG_AXE]) - self.prng_base[PRNG_AXE] = 65535 * random(); + if (!self.prng_base[PRNG_WEAP]) + self.prng_base[PRNG_WEAP] = 65535 * random(); // For hwguy we rotate the seed value, each seed generates many random nums. self.prng_base[PRNG_HWGUY] = 65535 * random(); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5ab58905..dfc7493b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1275,50 +1275,49 @@ void () W_FireGrenade = { self.ammo_rockets = self.ammo_rockets - 1; Pred_Sound(SND_GREN); KickPlayer(-2, self); - newmis = spawn(); - newmis.voided = 0; - newmis.owner = self; - newmis.movetype = 10; - newmis.solid = 2; + + entity proj = FOProj_Create(FPP_GRENADE); + proj.voided = 0; + proj.owner = self; + proj.movetype = MOVETYPE_BOUNCE; + proj.solid = SOLID_BBOX; if (FO_CurrentWeapon() == WEAP_GRENADE_LAUNCHER || cb_prematch) { - newmis.weapon = 5; - newmis.classname = "grenade"; - newmis.skin = 1; - newmis.touch = GrenadeTouch; - newmis.nextthink = time + 2.5; + proj.weapon = 5; + proj.classname = "grenade"; + proj.skin = 1; + proj.touch = GrenadeTouch; + proj.nextthink = time + 2.5; + proj.wpp_aux = GREN_RED; } else { if (old_pipecooldown) self.pipecooldown = time + 0.8; else self.pipecooldown = time + 0.5; ExplodeOldestPipebomb(); - newmis.classname = "pipebomb"; - newmis.skin = 2; - newmis.touch = PipebombTouch; - newmis.nextthink = time + 120; - newmis.weapon = 11; - newmis.team_no = self.team_no; + proj.classname = "pipebomb"; + proj.skin = 2; + proj.touch = PipebombTouch; + proj.nextthink = time + 120; + proj.weapon = 11; + proj.team_no = self.team_no; + proj.wpp_aux = GREN_PIPE; } makevectors(self.v_angle); if (self.v_angle_x) { - newmis.velocity = - (((v_forward * 600) + (v_up * 200)) + - ((crandom() * v_right) * 10)) + ((crandom() * v_up) * 10); + proj.velocity = (v_forward * 600) + + (200 + shared_crandom(PRNG_WEAP) * 10) * v_up + + (shared_crandom(PRNG_WEAP) * 10 * v_right); } else { - newmis.velocity = aim(self, 10000); - newmis.velocity = newmis.velocity * 600; - newmis.velocity_z = 200; + proj.velocity = aim(self, 10000); + proj.velocity = proj.velocity * 600; + proj.velocity_z = 200; } - newmis.avelocity = '300 300 300'; - newmis.angles = vectoangles(newmis.velocity); - newmis.think = GrenadeExplode; - FO_SetModel(newmis, "progs/grenade2.mdl"); - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, self.origin); + proj.avelocity = '300 300 300'; + proj.angles = vectoangles(proj.velocity); + proj.think = GrenadeExplode; + setorigin(proj, self.origin); - if (project_weapons) { - AL_ProjectProjectile(newmis); - } + FOProj_Finalize(proj); }; void () spike_touch; @@ -1630,13 +1629,13 @@ void () W_Attack = { if (ws.weapon == WEAP_AXE) { Pred_Sound(SND_AXE); - if (shared_prng(PRNG_AXE) < 0.5) + if (shared_prng(PRNG_WEAP) < 0.5) player_axe1(); else player_axeb1(); } else if (ws.weapon == WEAP_KNIFE) { Pred_Sound(SND_AXE); - if (shared_prng(PRNG_AXE) < 0.5) + if (shared_prng(PRNG_WEAP) < 0.5) player_knife1(); else player_knifeb1(); @@ -1712,7 +1711,7 @@ void () W_Attack = { } } else if (ws.weapon == WEAP_MEDIKIT) { Pred_Sound(SND_AXE); - if (shared_prng(PRNG_AXE) < 0.5) + if (shared_prng(PRNG_WEAP) < 0.5) player_medikit1(); else player_medikitb1(); From 7b6bb8425b8f993aca260e3af1f423768f949c07 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 18 Nov 2022 00:01:26 -0800 Subject: [PATCH 1871/2474] Refactor grenades round 1 Tableizes all the grenades and their various sundry parameters. Cleans up a lot of if-soup in preparation for client-side mirroring. There's still a bunch of legacy code using the old GR_TYPE macros, but this is easy to fix later. --- csqc/weapon_predict.qc | 12 +- share/prediction.qc | 13 +- share/weapons.qc | 120 ++++++++++++++++++ ssqc/demoman.qc | 2 +- ssqc/events.qc | 8 +- ssqc/qw.qc | 2 +- ssqc/scout.qc | 2 +- ssqc/tfort.qc | 267 +++++++++++------------------------------ ssqc/weapons.qc | 6 +- 9 files changed, 209 insertions(+), 223 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index e1134cc3..37a397fb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -856,14 +856,10 @@ static void FPP_ApplyGrenadeProperties(entity proj) { if (proj.fpp_index != FPP_GRENADE) return; - switch (proj.wpp_aux) { - case GREN_RED: - proj.skin = 1; - break; - case GREN_PIPE: - proj.skin = 2; - break; - } + FO_GrenInfo* gdesc = FO_GrenDesc(proj.wpp_aux); + + setmodelindex(proj, gdesc->modelindex); + proj.skin = gdesc->skin; } void W_FireGrenade(int gren_type) { diff --git a/share/prediction.qc b/share/prediction.qc index bcca2e21..2676b295 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -160,11 +160,6 @@ fo_projectile fpp_types[] = { }; // `wpp_aux` disambiguation for FPP_GRENADE projectiles. -enum { - GREN_RED, - GREN_PIPE, -}; - void InitFppProjectiles() { float i; static int once; @@ -711,6 +706,14 @@ void FOProj_Finalize(entity mis) { newmis = __NULL__; } + if (fpp_type == FPP_GRENADE) { + FO_GrenInfo* gdesc = FO_GrenDesc(mis.gren_type); + + setmodel(mis, gdesc->model); + mis.skin = gdesc->skin; + mis.wpp_aux = gdesc->id; + } + PredProj_Sound(fpp_type); float csqc_networking = fo_projectiles; diff --git a/share/weapons.qc b/share/weapons.qc index a6ca0c78..8694dccc 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -153,6 +153,106 @@ FO_ClassWeapons class_weapons[] = { { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; +enum { + GREN_FIRST = 100, + GREN_NORMAL = GREN_FIRST, + GREN_CONC, + GREN_BLAST, + GREN_NAIL, + GREN_SHOCK, + GREN_BURST, + GREN_MIRV, + GREN_NAPALM, + GREN_FLARE, // Not correctly predicted + GREN_GAS, + GREN_EMP, + GREN_FLASH, + GREN_CALTROP, + GREN_RED, + GREN_PIPE, + GREN_NONE, +}; + +// TODO: Just remove this legacy encoding. +int TF_GREN_conv(int tf_gren) { + switch (tf_gren) { + case GR_TYPE_NORMAL: return GREN_NORMAL; + case GR_TYPE_CONCUSSION: return GREN_CONC; + case GR_TYPE_BLAST: return GREN_BLAST; + case GR_TYPE_NAIL: return GREN_NAIL; + case GR_TYPE_SHOCK: return GREN_SHOCK; + case GR_TYPE_BURST: return GREN_BURST; + case GR_TYPE_MIRV: return GREN_MIRV; + case GR_TYPE_NAPALM: return GREN_NAPALM; + case GR_TYPE_FLARE: return GREN_FLARE; + case GR_TYPE_GAS: return GREN_GAS; + case GR_TYPE_EMP: return GREN_EMP; + case GR_TYPE_FLASH: return GREN_FLASH; + case GR_TYPE_CALTROP: return GREN_CALTROP; + }; + + error("unrecognized grenade type"); + return -1; +} + +struct FO_GrenInfo { + int id; + string name; + string model; + int skin; + vector avelocity; + + // Automatically initialized below this line. + float modelindex; + string logname; +}; + +FO_GrenInfo fo_grenades[] = { + { GREN_NORMAL, "Grenade", "hgren2.mdl", 0, '300 300 300',}, + { GREN_CONC, "Concussion", "hgren2.mdl", 1, '300 300 300'}, + { GREN_BLAST, "Blast", "blastgren.mdl", 1, '300 300 300'}, + { GREN_NAIL, "Nail", "biggren.mdl", 1, '0 300 0'}, + { GREN_SHOCK, "Shock", "biggren.mdl", 1, '0 300 0'}, + { GREN_BURST, "Burst", "biggren.mdl", 1, '0 300 0'}, + { GREN_MIRV, "Mirv", "biggren.mdl", 0, '0 300 0'}, + { GREN_NAPALM, "Napalm", "biggren.mdl", 2, '0 300 0'}, + { GREN_FLARE, "Flare", "flare.mdl", 1, '300 300 300'}, + { GREN_GAS, "Gas", "grenade2.mdl", 3, '300 300 300'}, + { GREN_EMP, "EMP", "grenade2.mdl", 4, '300 300 300'}, + { GREN_FLASH, "Flash", "flashgren.mdl", 0, '300 300 300'}, + { GREN_CALTROP, "Caltrop", "", 0, '300 300 300'}, + { GREN_RED, "Red", "grenade2.mdl", 1, '300 300 300'}, + { GREN_PIPE, "Pipe", "grenade2.mdl", 2, '300 300 300'}, +}; + +struct FO_ClassGrenades { + float id; + float gren[2]; +}; + +FO_ClassGrenades class_grenades[] = { + { PC_UNDEFINED, {GREN_NONE, GREN_NONE} }, + { PC_SCOUT, {GREN_FLASH, GREN_CONC} }, + { PC_SNIPER, {GREN_NORMAL, GREN_FLARE} }, + { PC_SOLDIER, {GREN_NORMAL, GREN_SHOCK} }, + { PC_DEMOMAN, {GREN_NORMAL, GREN_MIRV} }, + { PC_MEDIC, {GREN_NORMAL, GREN_CONC} }, + { PC_HVYWEAP, {GREN_NORMAL, GREN_MIRV} }, + { PC_PYRO, {GREN_NORMAL, GREN_NAPALM} }, + { PC_SPY, {GREN_NORMAL, GREN_GAS} }, + { PC_ENGINEER, {GREN_NORMAL, GREN_EMP} }, + { PC_RANDOM, {GREN_NONE, GREN_NONE} }, // TODO: Probably needs attention + { PC_CIVILIAN, {GREN_NONE, GREN_NONE} }, +}; + +inline FO_GrenInfo* FO_GrenDesc(int gren_type) { + return &fo_grenades[gren_type - GREN_FIRST]; +} + +FO_GrenInfo* FO_ClassGren(int playerclass, int type) { + return FO_GrenDesc(class_grenades[playerclass].gren[type]); +} + // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { @@ -682,5 +782,25 @@ void FO_Weapons_Init() { if (iw->weapons[j]) iw->slots[j] = WEAP_to_slot(iw->class, iw->weapons[j]); } + + for (i = 0; i < fo_grenades.length; i++) { + FO_GrenInfo* gdesc = &fo_grenades[i]; + ASSERTD_EQ(GREN_FIRST + i, gdesc->id); + + if (gdesc->name != "") { + gdesc->name = strcat(gdesc->name, " grenade"); + gdesc->logname = strcat(strtolower(gdesc->name), "grenade"); + } + + if (gdesc->model != "") { + gdesc->model = strcat("progs/", gdesc->model); + gdesc->modelindex = getmodelindex(gdesc->model); + } + } + + for (i = 0; i < class_grenades.length; i++) { + FO_ClassGrenades* cg = &class_grenades[i]; + ASSERTD_EQ(i, cg->id); + } } diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 346a2e99..7c48ea4a 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -100,7 +100,7 @@ void (vector org, entity shooter) MirvGrenadeLaunch = { newmis.solid = SOLID_BBOX; newmis.classname = "grenade"; - newmis.grenadename = "mirvsinglegrenade"; + newmis.gren_type = GREN_MIRV; newmis.weapon = DMSG_GREN_MIRV; newmis.touch = NormalGrenadeTouch; newmis.think = NormalGrenadeExplode; diff --git a/ssqc/events.qc b/ssqc/events.qc index fbeda3f9..485f8031 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -186,8 +186,8 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (damageKind == "damageTeam") return; } - else if ((inflictorId == "grenade") && (inflictor.grenadename != "")) - inflictorId = inflictor.grenadename; + else if (inflictorId == "grenade") + inflictorId = FO_GrenDesc(inflictor.gren_type)->logname; } @@ -285,8 +285,8 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { attackername = "world"; else if (inflictorId == "building_sentrygun") attackername = getEntityNameOrLogin(attacker.real_owner); - else if ((inflictorId == "grenade") && (inflictor.grenadename != "")) - inflictorId = inflictor.grenadename; + else if (inflictorId == "grenade") + inflictorId = FO_GrenDesc(inflictor.gren_type)->logname; } local string event; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 028baea7..05b5fc26 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -750,7 +750,7 @@ float gametime; string gametimestamp; float logfilehandle; float canlog; -.string grenadename; +.int gren_type; .float classtime; .float goalrunningtime; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 40fb8cf0..f40613d2 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -103,7 +103,7 @@ void () ScatterCaltrops = { while (num > 0) { e = spawn(); e.classname = "grenade"; - e.grenadename = "caltrop"; + e.gren_type = GREN_CALTROP; e.weapon = 10; e.owner = self.owner; e.team_no = self.owner.team_no; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c1761d1e..ed1e893d 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -772,6 +772,29 @@ void () TeamFortress_ShowTF = { } }; +void () NormalGrenadeTouch = { + if (other == self.owner) + return; + + FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; +}; + +void () NormalGrenadeExplode = { + deathmsg = DMSG_GREN_HAND; + T_RadiusDamage(self, self.owner, 180, world); + + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_EXPLOSION); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + + multicast(self.origin, MULTICAST_PHS); + dremove(self); +}; + void () GrenadeTimer = { self.heat = self.heat - 1; self.nextthink = time + 1; @@ -783,6 +806,28 @@ void () GrenadeTimer = { } }; +static struct stg_table_entry { + int id; + void() touch; + void() think; +}; + +stg_table_entry stg_table[] = { + { GREN_NORMAL, NormalGrenadeTouch, NormalGrenadeExplode}, + { GREN_CONC, ConcussionGrenadeTouch, ConcussionGrenadeExplode}, + { GREN_BLAST, BlastGrenadeTouch, BlastGrenadeExplode}, + { GREN_NAIL, NailGrenadeTouch, NailGrenadeExplode}, + { GREN_SHOCK, ShockGrenadeTouch, ShockGrenadeExplode}, + { GREN_BURST, BurstGrenadeTouch, BurstGrenadeExplode}, + { GREN_MIRV, MirvGrenadeTouch, MirvGrenadeExplode}, + { GREN_NAPALM, NapalmGrenadeTouch, NapalmGrenadeExplode1}, + { GREN_FLARE, FlareGrenadeTouch, FlareGrenadeExplode}, + { GREN_GAS, GasGrenadeTouch, GasGrenadeExplode1}, + { GREN_EMP, EMPGrenadeTouch, EMPGrenadeExplode}, + { GREN_FLASH, FlashGrenadeTouch, FlashGrenadeExplode}, + { GREN_CALTROP, CanisterTouch, ScatterCaltrops}, +}; + void (entity timer) FO_SpawnThrownGrenade = { local entity user = timer.owner; user.tfstate &= ~(TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING); @@ -818,99 +863,17 @@ void (entity timer) FO_SpawnThrownGrenade = { newmis.think = SUB_Null; newmis.nextthink = timer.heat; - if (timer.weapon == GR_TYPE_NORMAL) { - newmis.touch = NormalGrenadeTouch; - newmis.think = NormalGrenadeExplode; - newmis.grenadename = "normalgrenade"; - newmis.skin = 0; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } else if (timer.weapon == GR_TYPE_CONCUSSION) { - newmis.touch = ConcussionGrenadeTouch; - newmis.think = ConcussionGrenadeExplode; - newmis.grenadename = "concussiongrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } else if (timer.weapon == GR_TYPE_BLAST) { - newmis.touch = BlastGrenadeTouch; - newmis.think = BlastGrenadeExplode; - newmis.grenadename = "blastgrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/blastgren.mdl"); - } else if (timer.weapon == GR_TYPE_NAIL) { - newmis.touch = NailGrenadeTouch; - newmis.think = NailGrenadeExplode; - newmis.grenadename = "nailgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (timer.weapon == GR_TYPE_SHOCK) { - newmis.touch = ShockGrenadeTouch; - newmis.think = ShockGrenadeExplode; - newmis.grenadename = "shockgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (timer.weapon == GR_TYPE_BURST) { - newmis.touch = BurstGrenadeTouch; - newmis.think = BurstGrenadeExplode; - newmis.grenadename = "burstgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (timer.weapon == GR_TYPE_MIRV) { - newmis.touch = MirvGrenadeTouch; - newmis.think = MirvGrenadeExplode; - newmis.grenadename = "mirvgrenade"; - newmis.skin = 0; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (timer.weapon == GR_TYPE_NAPALM) { - newmis.touch = NapalmGrenadeTouch; - newmis.think = NapalmGrenadeExplode1; - newmis.grenadename = "napalmgrenade"; - newmis.skin = 2; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (timer.weapon == GR_TYPE_FLARE) { - newmis.touch = FlareGrenadeTouch; - newmis.weapon = timer.team_no; - newmis.think = FlareGrenadeExplode; - newmis.grenadename = "flaregrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - newmis.mdl = "flare"; - FO_SetModel(newmis, "progs/flare.mdl"); - } else if (timer.weapon == GR_TYPE_GAS) { - newmis.touch = GasGrenadeTouch; - newmis.think = GasGrenadeExplode1; - newmis.grenadename = "gasgrenade"; - newmis.skin = 3; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/grenade2.mdl"); - } else if (timer.weapon == GR_TYPE_EMP) { - newmis.touch = EMPGrenadeTouch; - newmis.think = EMPGrenadeExplode; - newmis.grenadename = "empgrenade"; - newmis.skin = 4; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/grenade2.mdl"); - } else if (timer.weapon == GR_TYPE_CALTROP) { - newmis.touch = CanisterTouch; - newmis.think = ScatterCaltrops; - newmis.grenadename = "caltropgrenade"; - newmis.skin = 0; - newmis.avelocity = '0 0 0'; - } else if (timer.weapon == GR_TYPE_FLASH) { - newmis.touch = FlashGrenadeTouch; - newmis.think = FlashGrenadeExplode; - newmis.grenadename = "flashgrenade"; - newmis.skin = 0; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/flashgren.mdl"); - } + int gtype = TF_GREN_conv(timer.weapon); + FO_GrenInfo* gdesc = FO_GrenDesc(gtype); + stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; + + newmis.gren_type = gtype; + newmis.skin = gdesc->skin; + FO_SetModel(newmis, gdesc->model); + newmis.avelocity = gdesc->avelocity; + newmis.touch = ste->touch; + newmis.think = ste->think; + setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, user.origin); } @@ -2786,65 +2749,8 @@ void () TeamFortress_ExplodePerson = { newmis.think = SUB_Null; newmis.nextthink = time + 0.1; // Server generated, no client time here. - if (self.weapon == GR_TYPE_NORMAL) { - newmis.touch = NormalGrenadeTouch; - newmis.think = NormalGrenadeExplode; - newmis.grenadename = "normalgrenade"; - newmis.skin = 0; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } else if (self.weapon == GR_TYPE_CONCUSSION) { - newmis.touch = ConcussionGrenadeTouch; - newmis.think = ConcussionGrenadeExplode; - newmis.grenadename = "concussiongrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/hgren2.mdl"); - } else if (self.weapon == GR_TYPE_BLAST) { - newmis.touch = BlastGrenadeTouch; - newmis.think = BlastGrenadeExplode; - newmis.grenadename = "blastgrenade"; - newmis.skin = 1; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/blastgren.mdl"); - } else if (self.weapon == GR_TYPE_NAIL) { - newmis.touch = NailGrenadeTouch; - newmis.think = NailGrenadeExplode; - newmis.grenadename = "nailgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_SHOCK) { - newmis.touch = ShockGrenadeTouch; - newmis.think = ShockGrenadeExplode; - newmis.grenadename = "shockgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_BURST) { - newmis.touch = BurstGrenadeTouch; - newmis.think = BurstGrenadeExplode; - newmis.grenadename = "burstgrenade"; - newmis.skin = 1; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_MIRV) { - newmis.touch = MirvGrenadeTouch; - newmis.think = MirvGrenadeExplode; - newmis.grenadename = "mirvgrenade"; - newmis.skin = 0; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_NAPALM) { - newmis.touch = NapalmGrenadeTouch; - newmis.think = NapalmGrenadeExplode1; - newmis.grenadename = "napalmgrenade"; - newmis.skin = 2; - newmis.avelocity = '0 300 0'; - FO_SetModel(newmis, "progs/biggren.mdl"); - } else if (self.weapon == GR_TYPE_FLARE) { + if (self.weapon == GR_TYPE_FLARE) { sprint(self.owner, PRINT_HIGH, "Flare lit\n"); - newmis.grenadename = "flaregrenade"; te = spawn(); te.touch = SUB_Null; te.think = RemoveFlare; @@ -2855,34 +2761,20 @@ void () TeamFortress_ExplodePerson = { dremove(self); dremove(newmis); return; - } else if (self.weapon == GR_TYPE_GAS) { - newmis.touch = GasGrenadeTouch; - newmis.think = GasGrenadeExplode1; - newmis.grenadename = "gasgrenade"; - newmis.skin = 2; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/grenade2.mdl"); - } else if (self.weapon == GR_TYPE_EMP) { - newmis.touch = EMPGrenadeTouch; - newmis.think = EMPGrenadeExplode; - newmis.grenadename = "empgrenade"; - newmis.skin = 4; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/grenade2.mdl"); - } else if (self.weapon == GR_TYPE_CALTROP) { - newmis.touch = CaltropTouch; - newmis.think = ScatterCaltrops; - newmis.grenadename = "caltropgrenade"; - } else if (self.weapon == GR_TYPE_FLASH) { - newmis.touch = FlashGrenadeTouch; - newmis.think = FlashGrenadeExplode; - newmis.grenadename = "flashgrenade"; - newmis.skin = 0; - newmis.avelocity = '300 300 300'; - FO_SetModel(newmis, "progs/flashgren.mdl"); } + + int gren_type = TF_GREN_conv(self.weapon); + FO_GrenInfo* gdesc = FO_GrenDesc(gren_type); + stg_table_entry* ste = &stg_table[gren_type - GREN_FIRST]; + + newmis.skin = gdesc->skin; + FO_SetModel(newmis, gdesc->model); + newmis.avelocity = gdesc->avelocity; + newmis.touch = ste->touch; + newmis.think = ste->think; setsize(newmis, '0 0 0', '0 0 0'); setorigin(newmis, self.owner.origin); + if ((self.owner.playerclass == PC_SCOUT) && (self.weapon != 10)) bprint(PRINT_MEDIUM, "No ", self.owner.netname, ", swallowing the grenade isn't very effective!\n"); @@ -2928,29 +2820,6 @@ void () TeamFortress_ExplodePerson = { dremove(self); }; -void () NormalGrenadeTouch = { - if (other == self.owner) - return; - - FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); - if (self.velocity == '0 0 0') - self.avelocity = '0 0 0'; -}; - -void () NormalGrenadeExplode = { - deathmsg = DMSG_GREN_HAND; - T_RadiusDamage(self, self.owner, 180, world); - - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - - multicast(self.origin, MULTICAST_PHS); - dremove(self); -}; - void () TeamFortress_DisplayDetectionItems = { local entity tfdet; local entity te; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index dfc7493b..ba383dc0 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1284,10 +1284,9 @@ void () W_FireGrenade = { if (FO_CurrentWeapon() == WEAP_GRENADE_LAUNCHER || cb_prematch) { proj.weapon = 5; proj.classname = "grenade"; - proj.skin = 1; proj.touch = GrenadeTouch; proj.nextthink = time + 2.5; - proj.wpp_aux = GREN_RED; + proj.gren_type = GREN_RED; } else { if (old_pipecooldown) self.pipecooldown = time + 0.8; @@ -1295,12 +1294,11 @@ void () W_FireGrenade = { self.pipecooldown = time + 0.5; ExplodeOldestPipebomb(); proj.classname = "pipebomb"; - proj.skin = 2; proj.touch = PipebombTouch; proj.nextthink = time + 120; proj.weapon = 11; proj.team_no = self.team_no; - proj.wpp_aux = GREN_PIPE; + proj.gren_type = GREN_PIPE; } makevectors(self.v_angle); if (self.v_angle_x) { From 36437fcb3f50673218f9fb6ca25b10ae912aa193 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 18 Nov 2022 01:36:09 -0800 Subject: [PATCH 1872/2474] Add client-side prediction for grenades No more delay on throwing grenades, the state is now all simulated. Grenades also now have antilag projection. Hooray. Some obvious remaining TODOs: - handle prime side as well so that there is no delay on timer start. - integrate with client side grenade timers, get rid of out of band messaging - locally spawn held grenades (and more importantly.. client physics!) --- csqc/weapon_predict.qc | 66 ++++++++++++++++++++++++++++++++++++++---- share/commondefs.qc | 1 + share/defs.h | 9 ++++-- share/physics.qc | 9 +++++- share/prediction.qc | 56 +++++++++++++++++++++++++---------- share/weapons.qc | 15 ++++++++-- ssqc/antilag.qc | 3 +- ssqc/qw.qc | 1 + ssqc/tfort.qc | 59 +++++++++++++++++++------------------ ssqc/tfortmap.qc | 32 ++++---------------- ssqc/time.qc | 4 +++ ssqc/tsoldier.qc | 4 ++- ssqc/weapons.qc | 1 - 13 files changed, 174 insertions(+), 86 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 37a397fb..270579a8 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -168,6 +168,7 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(pp_global_disable); PRINT_CONFIG_ACTIVE(wpp_global_enable); PRINT_CONFIG_ACTIVE(wpp_global_disable); + PRINT_CONFIG_ACTIVE(gren_beta_disable); } #undef PRINT_CONFIG @@ -382,6 +383,21 @@ static void WP_HandleHeavyInputs() { pstate_pred.impulse = 0; } +void W_ThrowGren(float is_throw); + +static void HandleButtonThrowgren(float index, float button) { + float b_down = pstate_pred.buttons_down & button; + float b_up = pstate_pred.buttons_up & button; + + if (IsHoldGrenades()) { + if (b_up) + W_ThrowGren(TRUE); + } else { + if ((pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) && b_down) + W_ThrowGren(TRUE); + } +} + void WP_Impulse() { // Note: We might have no impulse, but a queued slot here. WP_HandleHeavyInputs(); @@ -421,9 +437,17 @@ void WP_Impulse() { pstate_pred.playerclass, pstate_pred.current_slot, TRUE); break; + case TF_GRENADE_T: + W_ThrowGren(TRUE); + break; + default: match = FALSE; } + + HandleButtonThrowgren(1, BUTTON5); + HandleButtonThrowgren(2, BUTTON6); + if (match) pstate_pred.impulse = 0; @@ -635,6 +659,7 @@ void WP_Frame() { WP_CheckReloadFinished(); WP_Impulse(); + W_ThrowGren(FALSE); if ((input_buttons & BUTTON0) && !WP_IsReloading() && (pstate_pred.client_time >= pstate_pred.attack_finished)) @@ -735,10 +760,6 @@ void FPP_Init(int fpp_type, entity proj) { else setmodelindex(proj, desc->modelindex); - if (fpp_type == FPP_GRENADE) { - proj.avelocity = '300 300 300'; - } - proj.traileffectnum = FPP_FindTrail(proj); proj.movetype = desc->movetype; } @@ -796,6 +817,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { makevectors(input_angles); entity proj = spawn(); + proj.owner = edict_num(player_localentnum); FPP_Init(fpp_type, proj); #if 0 @@ -860,6 +882,7 @@ static void FPP_ApplyGrenadeProperties(entity proj) { setmodelindex(proj, gdesc->modelindex); proj.skin = gdesc->skin; + proj.avelocity = gdesc->avelocity; } void W_FireGrenade(int gren_type) { @@ -899,6 +922,38 @@ void (float ox) W_FireSpikes = { }; +DEFCVAR_FLOAT(wpp_disable_gren, 0) +static float PP_EnableGrenades() { + return fo_config.qc_physics && !fo_config.gren_beta_disable && + !CVARF(wpp_disable_gren); +} + +static void W_ThrowGren(float is_throw) { + if (!PP_EnableGrenades()) + return; + + if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED == 0) + return; + + if (is_throw) + pstate_pred.tfstate |= TFSTATE_GRENTHROWING; + else if (pstate_pred.tfstate & TFSTATE_GRENTHROWING == 0) + return; + + if (pstate_pred.client_time < pstate_pred.last_prime + 0.8) + return; // Not time to throw yet, THROWING set if necessary. + + if (IsEffectFrame()) { + entity gren = PP_CreateProjectile(FPP_GRENADE, '0 0 0'); + int index = (pstate_pred.tfstate & TFSTATE_GREN1_PRIMED) ? 0 : 1; + gren.wpp_aux = FO_ClassGren(pstate_pred.playerclass, index)->id; + FPP_ApplyGrenadeProperties(gren); + } + + pstate_pred.tfstate &= ~TFSTATE_GREN_MASK_ALL; +} + + void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { vector offset = org - pmove_org - '0 0 16'; entity proj = PP_CreateProjectile(FPP_ASSAULT_CANNON, offset); @@ -959,7 +1014,7 @@ void WP_Attack() { case WEAP_GRENADE_LAUNCHER: case WEAP_PIPE_LAUNCHER: - if (fo_config.qc_physics) + if (PP_EnableGrenades()) W_FireGrenade(wi->weapon == WEAP_GRENADE_LAUNCHER ? GREN_RED : GREN_PIPE); else @@ -1062,6 +1117,7 @@ void InitProjectileEnt() { self.predraw = PP_PredrawActive; self.s_time = self.phys_time; self.angles = vectoangles(self.velocity); + self.owner = edict_num(self.owner_entnum); FPP_Init(self.fpp_index, self); FPP_ApplyGrenadeProperties(self); diff --git a/share/commondefs.qc b/share/commondefs.qc index 6d2ab3a3..8b494776 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -13,6 +13,7 @@ var struct { float pp_global_disable; float wpp_global_enable; float wpp_global_disable; + float gren_beta_disable; } fo_config; #define MAX_FLAGINFO_LINES 10 diff --git a/share/defs.h b/share/defs.h index 26dcc435..c5d9d252 100644 --- a/share/defs.h +++ b/share/defs.h @@ -242,8 +242,10 @@ // TeamFortress State Flags enumflags { - TFSTATE_GRENPRIMED, // Whether the player has a primed grenade TFSTATE_RELOADING, // Whether the player is reloading + TFSTATE_GREN1_PRIMED, // Whether the player has a primed gren 1 + TFSTATE_GREN2_PRIMED, // Whether the player has a primed gren 2 + TFSTATE_GRENTHROWING, // is throwing a grenade TFSTATE_AIMING, // is using the laser sight or spinning TFSTATE_CANT_MOVE, TFSTATE_NO_WEAPON, // Weapon is disabled and not visible (e.g. detpack) @@ -261,7 +263,6 @@ enumflags { TFSTATE_QUAD, // Player has permanent Quad Damage (Usually by GoalItem) TFSTATE_RADSUIT, // Player has permanent Radsuit (Usually by GoalItem) TFSTATE_BURNING, // Is on fire - TFSTATE_GRENTHROWING, // is throwing a grenade TFSTATE_AIMING, // is using the laser sight or spinning cannon TFSTATE_RESPAWN_READY, // is waiting for respawn, and has pressed fire, // as sentry gun,indicate it needs to die @@ -271,6 +272,10 @@ enumflags { TFSTATE_RANDOMPC, }; + +#define TFSTATE_GREN_MASK_PRIMED (TFSTATE_GREN1_PRIMED|TFSTATE_GREN2_PRIMED) +#define TFSTATE_GREN_MASK_ALL (TFSTATE_GREN_MASK_PRIMED|TFSTATE_GRENTHROWING) + #define TFSTATE_AC_MASK (TFSTATE_AC_SPINUP|TFSTATE_AC_SPINNING|TFSTATE_AC_SPINDOWN) #define TFSTATE_AC_FIRING (TFSTATE_AC_SPINUP|TFSTATE_AC_SPINNING) diff --git a/share/physics.qc b/share/physics.qc index faafb8af..ca1b2367 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -7,6 +7,8 @@ static const float phys_tic = 0.005; .float phys_t; // Total physics time accumulated #ifdef SSQC +void Predict_UpdateHack(entity e); + static void Phys_Impact(entity e) { if (trace_ent.solid == SOLID_NOT) return; @@ -18,6 +20,9 @@ static void Phys_Impact(entity e) { self.touch(); self = held_self; } + + if (trace_ent.solid != SOLID_BSP) + Predict_UpdateHack(e); } #else .entity groundentity; @@ -69,7 +74,9 @@ float Phys_Push(entity e, vector offset) { if (e.movetype == MOVETYPE_FLYMISSILE) flags |= MOVE_MISSILE; - traceline(e.origin, e.origin + offset, flags, e.owner); + // Note: Networked entities don't currently intersect on CSQC instantiation + // of this, we fudge this in Phys_Impact from the server side. + traceline(e.origin, e.origin + offset, flags, e); e.origin = trace_endpos; if (trace_fraction < 1) { diff --git a/share/prediction.qc b/share/prediction.qc index 2676b295..42263841 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -13,15 +13,15 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; .float s_time; #endif -string wp_version = "v0.3-phys"; +string wp_version = "v0.4-phys"; enumflags { FOWP_CTIME, FOWP_IMPULSE, FOWP_TFSTATE, + FOWP_LASTPRIME, FOWP_CLIP, FOWP_THINK, - FOWP_TFSTATE, FOWP_WF, FOWP_AF, FOWP_CLASS, @@ -35,6 +35,8 @@ enumflags { FOPP_POS, FOPP_INIT, FOPP_AUX, + FOPP_ANGLES, + FOPP_MOVETYPE, }; #define FOWP_ALL 0xFFFF @@ -51,6 +53,7 @@ struct predict_tf_state { Slot current_slot, queue_slot, last_slot; float tfstate; + float last_prime; float client_time; float client_ping; @@ -305,6 +308,7 @@ void WeaponPred_Update(entity player) { M1(FOWP_CLASS, playerclass); M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); M1(FOWP_TFSTATE, tfstate); + M1(FOWP_LASTPRIME, last_prime); M1(FOWP_WF, weaponframe); M1(FOWP_AF, attack_finished); M2(FOWP_THINK, client_nextthink, client_thinkindex); @@ -330,6 +334,14 @@ void sprint_pred(entity client, float msglevel, string s) { return; // Message generated client-side. sprint(client, msglevel, s); } + +// Networked (non-csqc) entities don't appear to exist within the client-side +// CSQC world for our physics simulation. Until we either (a) migrate them +// there or (b) find a way to propagate them there, we cheat by sending an +// update to the client when such a collision occurs. +void Predict_UpdateHack(entity e) { + e.SendFlags |= FOPP_POS | FOPP_ANGLES; +} #endif #ifdef CSQC @@ -368,6 +380,7 @@ void EntUpdate_Config() { COMM(Float, pp_global_disable); COMM(Float, wpp_global_enable); COMM(Float, wpp_global_disable); + COMM(Float, gren_beta_disable); #ifdef SSQC return TRUE; @@ -413,6 +426,10 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Float, tfstate); } + if (sendflags & FOWP_LASTPRIME) { + COMM(Float, last_prime); + } + if (sendflags & FOWP_THINK) { COMM(Float, client_nextthink); COMM(Float, client_thinkindex); @@ -469,6 +486,11 @@ void WP_SyncPhysProjectile(); void EntUpdate_Projectile(float isnew) { float sendflags = readbyte(); #endif + if (sendflags & FOPP_INIT) { + COMM(Byte, fpp_index); + COMM(Byte, antilag_ms); + } + if (sendflags & FOPP_POS) { COMMD(Coord, s_origin[0], origin[0]); COMMD(Coord, s_origin[1], origin[1]); @@ -482,11 +504,15 @@ void EntUpdate_Projectile(float isnew) { COMM(Float, phys_carry); } - if (sendflags & FOPP_INIT) { - COMM(Byte, fpp_index); - COMM(Byte, antilag_ms); + if (sendflags & FOPP_ANGLES) { + COMM(Coord, angles[0]); + COMM(Coord, angles[1]); + COMM(Coord, angles[2]); } + if (sendflags & FOPP_MOVETYPE) + COMM(Byte, movetype); + if (sendflags & FOPP_AUX) { COMM(Short, wpp_aux); } @@ -550,6 +576,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("ppgd", pp_global_disable); CONFIG_UPDATE("wppge", wpp_global_enable); CONFIG_UPDATE("wppge", wpp_global_disable); + CONFIG_UPDATE("gbd", gren_beta_disable); CLAMP_UPDATE(dynamic_newmis_ms, 0, NEWMIS_MS); CLAMP_UPDATE(max_rewind_ms, 0, 250); @@ -705,30 +732,27 @@ void FOProj_Finalize(entity mis) { PRINT_ONCE("Error: fpp=%d used with newmis\n", (float)fpp_type); newmis = __NULL__; } + PredProj_Sound(fpp_type); + float csqc_networking = fo_projectiles; if (fpp_type == FPP_GRENADE) { FO_GrenInfo* gdesc = FO_GrenDesc(mis.gren_type); setmodel(mis, gdesc->model); + mis.avelocity = gdesc->avelocity; mis.skin = gdesc->skin; mis.wpp_aux = gdesc->id; - } - PredProj_Sound(fpp_type); - - float csqc_networking = fo_projectiles; + // If we don't have physics synchronized between client and server, use + // engine-side for both. + csqc_networking = (csqc_networking && fo_config.qc_physics); + } // We always need to init some of the state here (e.g. phys_time) as we // always use the physics code client-side. mis.phys_time = time; - if (fo_config.qc_physics) { + if (fo_config.qc_physics) mis.customphysics = FO_Phys; - } else { - // If we don't have physics synchronized between client and server, use - // engine-side for both. - if (mis.fpp_index == FPP_GRENADE) - csqc_networking = FALSE; - } WeaponPred_ProjectProjectile(mis.fpp_index, mis); diff --git a/share/weapons.qc b/share/weapons.qc index 8694dccc..d29f28d0 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -249,8 +249,8 @@ inline FO_GrenInfo* FO_GrenDesc(int gren_type) { return &fo_grenades[gren_type - GREN_FIRST]; } -FO_GrenInfo* FO_ClassGren(int playerclass, int type) { - return FO_GrenDesc(class_grenades[playerclass].gren[type]); +FO_GrenInfo* FO_ClassGren(int playerclass, int index) { + return FO_GrenDesc(class_grenades[playerclass].gren[index]); } // Indexed by WEAP_to_index(). We keep them out of the main table just to keep @@ -264,9 +264,14 @@ static string weapon_names[] = { }; string FO_GetWeapName(float weapon) { - return weapon_names[WEAP_to_index(weapon)]; + // Seeing a weird compiler bug here, passing WEAP_to_index directly to the + // array dereference will randomly cause OOB with length 13 limit, which is + // much smaller than `weapon_names`. + int index = WEAP_to_index(weapon); + return weapon_names[index]; } + struct FO_WeapModels { int weapon; string model; @@ -651,6 +656,10 @@ float IsUsingOldImpulses() { static float IsPyroSlotSwapped() { return csqc_get_user_setting("cfpi", "cf_pyro_impulses", "off"); } + +float IsHoldGrenades() { + return csqc_get_user_setting("hg", "hold_grens", "off"); +} #endif float InputHandlePyroSlotSwap(float input) { diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 00cc14ce..ca80072c 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -29,7 +29,8 @@ void AL_ProjectProjectile (entity projectile) { } void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { - ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, self.client_ping); + float ping = projectile.owner.client_ping; + ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); float offset_dt = (offset.static_ms + offset.dynamic_ms) / 1000.0; float dt = Phys_Advance(projectile, offset_dt); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 05b5fc26..9fc5abf3 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -772,6 +772,7 @@ float FO_FlashDimension; // precise grenades .entity grenade_timer; .float last_throw; +.float last_prime; // allow for default goal state .float default_group_no; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index ed1e893d..5ffe053b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -830,7 +830,7 @@ stg_table_entry stg_table[] = { void (entity timer) FO_SpawnThrownGrenade = { local entity user = timer.owner; - user.tfstate &= ~(TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING); + user.tfstate &= ~TFSTATE_GREN_MASK_ALL; user.last_throw = time; if (grentimers && infokeyf(user, INFOKEY_P_CSQCACTIVE)) { @@ -839,48 +839,45 @@ void (entity timer) FO_SpawnThrownGrenade = { FO_Sound(user, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); KickPlayer(-1, user); - newmis = spawn(); - newmis.owner = user; - newmis.movetype = 10; - newmis.solid = 2; - newmis.classname = "grenade"; + entity proj = FOProj_Create(FPP_GRENADE); + proj.owner = user; + proj.movetype = MOVETYPE_BOUNCE; + proj.solid = SOLID_BBOX; + proj.classname = "grenade"; makevectors(user.v_angle); if (user.deadflag) { if (timer.weapon == GR_TYPE_NORMAL) - newmis.velocity = '0 0 200'; + proj.velocity = '0 0 200'; else return; } else if (user.v_angle_x) { - newmis.velocity = + proj.velocity = v_forward * 600 + v_up * 200 + crandom() * v_right * 10 + crandom() * v_up * 10; } else { - newmis.velocity = aim(user, 10000); - newmis.velocity = newmis.velocity * 600; - newmis.velocity_z = 200; + proj.velocity = aim(user, 10000); + proj.velocity = proj.velocity * 600; + proj.velocity_z = 200; } - newmis.angles = vectoangles(newmis.velocity); - newmis.think = SUB_Null; - newmis.nextthink = timer.heat; + proj.angles = vectoangles(proj.velocity); + proj.think = SUB_Null; + proj.nextthink = timer.heat; int gtype = TF_GREN_conv(timer.weapon); FO_GrenInfo* gdesc = FO_GrenDesc(gtype); stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; - newmis.gren_type = gtype; - newmis.skin = gdesc->skin; - FO_SetModel(newmis, gdesc->model); - newmis.avelocity = gdesc->avelocity; - newmis.touch = ste->touch; - newmis.think = ste->think; + proj.gren_type = gtype; + proj.skin = gdesc->skin; + proj.touch = ste->touch; + proj.think = ste->think; - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, user.origin); + setorigin(proj, user.origin); + FOProj_Finalize(proj); } void (float inp) TeamFortress_PrimeThrowGrenade = { - if ((self.tfstate & TFSTATE_GRENPRIMED) || - (self.tfstate & TFSTATE_GRENTHROWING)) + if (self.tfstate & TFSTATE_GREN_MASK_PRIMED) TeamFortress_ThrowGrenade(); else { TeamFortress_PrimeGrenade(inp, TRUE); @@ -902,9 +899,9 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { local entity timer; gtype = 0; - if ((self.tfstate & TFSTATE_GRENPRIMED) || (self.tfstate & TFSTATE_GRENTHROWING)) + if (self.tfstate & TFSTATE_GREN_MASK_PRIMED) return; - + if (no_fire_mode) return; @@ -1048,7 +1045,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { return; } } - self.tfstate = self.tfstate | TFSTATE_GRENPRIMED; + self.tfstate |= (inp == 1) ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED; tGrenade = spawn(); tGrenade.owner = self; tGrenade.weapon = gtype; @@ -1058,7 +1055,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { else if (inp == 2) tGrenade.impulse = TF_GRENADE_2; - float time_base = remote_time(); + float time_base = max(remote_time(), self.last_throw); tGrenade.nextthink = time_base + 0.8; if (gtype == GR_TYPE_CALTROP) tGrenade.heat = time_base + 0.5 + 0.5; @@ -1087,6 +1084,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { tGrenade.think = FO_GrenadeThink; self.grenade_timer = tGrenade; + self.last_prime = global_to_client_time(time_base); }; @@ -1137,7 +1135,8 @@ void () FO_ThrowGrenade = { } void () TeamFortress_ThrowGrenade = { - if (!(self.tfstate & (TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING))) + if ((self.tfstate & TFSTATE_GREN_MASK_PRIMED == 0) || + (self.tfstate & TFSTATE_GRENTHROWING)) return; self.tfstate |= TFSTATE_GRENTHROWING; @@ -2735,7 +2734,7 @@ void () TeamFortress_AmmoboxTouch = { void () TeamFortress_ExplodePerson = { local entity te; - self.owner.tfstate &= ~(TFSTATE_GRENPRIMED | TFSTATE_GRENTHROWING); + self.owner.tfstate &= ~TFSTATE_GREN_MASK_ALL; KickPlayer(-2, self.owner); newmis = spawn(); diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 97292d68..925cfde2 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -888,27 +888,17 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (Player.ammo_detpack > Player.maxammo_detpack) { Player.ammo_detpack = Player.maxammo_detpack; } - if (Player.tfstate & TFSTATE_GRENPRIMED) { + if (Player.tfstate & TFSTATE_GREN_MASK_PRIMED) { te = find(world, classname, "primer"); while (te) { if (te.owner == Player) { if ((te.impulse == TF_GRENADE_2) && (Player.no_grenades_2 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); + Player.tfstate &= TFSTATE_GREN_MASK_ALL; dremove(te); } else if ((te.impulse == TF_GRENADE_1) && (Player.no_grenades_1 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); + Player.tfstate &= TFSTATE_GREN_MASK_ALL; dremove(te); } te = world; @@ -1162,27 +1152,17 @@ void (entity Goal, entity Player) RemoveResults = { if (Player.ammo_detpack > Player.maxammo_detpack) Player.ammo_detpack = Player.maxammo_detpack; - if (Player.tfstate & TFSTATE_GRENPRIMED) { + if (Player.tfstate & TFSTATE_GREN_MASK_PRIMED) { te = find(world, classname, "primer"); while (te) { if (te.owner == Player) { if ((te.impulse == TF_GRENADE_2) && (Player.no_grenades_2 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); + Player.tfstate &= ~TFSTATE_GREN_MASK_ALL; dremove(te); } else if ((te.impulse == TF_GRENADE_1) && (Player.no_grenades_1 <= 0)) { - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENPRIMED); - Player.tfstate = - Player.tfstate - - (Player.tfstate & TFSTATE_GRENTHROWING); + Player.tfstate &= ~TFSTATE_GREN_MASK_ALL; dremove(te); } te = world; diff --git a/ssqc/time.qc b/ssqc/time.qc index a5e33494..8d54d863 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -22,6 +22,10 @@ inline float client_to_global_time(float ctime) { return time + (ctime - self.client_time); } +inline float global_to_client_time(float gtime) { + return self.client_time + (gtime - time); +} + // Ping corrected `time`. float remote_time(float ct_type = CT_NOEXTERNALEFFECT) { return client_to_global_time(remote_client_time(ct_type)); diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 07395540..0edc2341 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -98,10 +98,10 @@ void () ShockGrenadeExplode = { if(solid_nailgren) { setsize(self, '-1 -1 -1', '1 1 1'); } - self.avelocity = '0 500 0'; self.nextthink = time + 0.7; self.playerclass = 0; self.think = NailGrenLaser; + self.SendFlags = FOPP_POS | FOPP_MOVETYPE; }; void () BurstGrenadeExplode = { @@ -191,6 +191,8 @@ void () NailGrenLaser = { //using self.playerclass to count thinks self.v_angle_x = 0; self.v_angle_z = 0; self.angles = self.v_angle; + self.SendFlags |= FOPP_ANGLES; + makevectors(self.v_angle); org = self.origin; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ba383dc0..a4c57b88 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1310,7 +1310,6 @@ void () W_FireGrenade = { proj.velocity = proj.velocity * 600; proj.velocity_z = 200; } - proj.avelocity = '300 300 300'; proj.angles = vectoangles(proj.velocity); proj.think = GrenadeExplode; setorigin(proj, self.origin); From 5425301d0251c1916c29371d6786cdc4236a4a8a Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 18 Nov 2022 16:35:29 -0800 Subject: [PATCH 1873/2474] Make newmis (static) nudge a tunable The old physics code would additionally apply an (inconsistent) outstanding physics frames to new projectiles. The new code is more consistent but add a tunable for extra nudge in case we want to restore some of the boost that this was previously providing. It's small enough that this might not matter. --- csqc/weapon_predict.qc | 1 + share/commondefs.qc | 1 + share/prediction.qc | 36 +++++++++++++++++++----------------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 270579a8..9b0eacb9 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -156,6 +156,7 @@ void WPP_Status() { printf("Config:\n"); PRINT_CONFIG(qc_physics); + PRINT_CONFIG(static_newmis_ms); PRINT_CONFIG(dynamic_newmis_ms); PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); diff --git a/share/commondefs.qc b/share/commondefs.qc index 8b494776..47a566cb 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,5 +1,6 @@ var struct { float qc_physics; + float static_newmis_ms; float dynamic_newmis_ms; float max_rewind_ms; float max_rewind_slow_projectile_ms; diff --git a/share/prediction.qc b/share/prediction.qc index 42263841..efa86aac 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -204,12 +204,11 @@ float max_rewind_credit_ms(int fpp_type) { // NOTE: DO NOT USE NEWMIS FOR FO PROJECTILES. THE NEWMIS CORRECTION IS NOW // MADE EXPLICITLY RATHER THAN IMPLICITLY. [WE AUTOMATICALLY STRIP NEWMIS // FROM PROJECTILES PASSED TO US.] -static float NEWMIS_MS = 50; float static_newmis_ms(int fpp_type) { if (fpp_type == FPP_FLAMETHROWER || fpp_type == FPP_ASSAULT_CANNON) return 0; - return NEWMIS_MS - fo_config.dynamic_newmis_ms; + return fo_config.static_newmis_ms - fo_config.dynamic_newmis_ms; } inline float dynamic_newmis_ms() { @@ -217,7 +216,7 @@ inline float dynamic_newmis_ms() { } inline float fixed_newmis_ms(int fpp_type) { - return NEWMIS_MS; + return fo_config.static_newmis_ms; } .float wpp_aux; @@ -367,20 +366,21 @@ float WP_SendConfig(entity to_player, float sendflags) { #define COMM(_type, _field) fo_config.##_field = Read##_type() void EntUpdate_Config() { #endif - COMM(Float, qc_physics); + COMM(Byte, qc_physics); + COMM(Float, static_newmis_ms); COMM(Float, dynamic_newmis_ms); - COMM(Float, max_rewind_ms); - COMM(Float, max_rewind_slow_projectile_ms); - COMM(Float, max_rewind_fast_projectile_ms); - COMM(Float, rewind_fast_projectile_thresh); - COMM(Float, wp_default_min_ping_ms); - COMM(Float, wp_global_enable); - COMM(Float, wp_global_disable); - COMM(Float, pp_global_enable); - COMM(Float, pp_global_disable); - COMM(Float, wpp_global_enable); - COMM(Float, wpp_global_disable); - COMM(Float, gren_beta_disable); + COMM(Byte, max_rewind_ms); + COMM(Byte, max_rewind_slow_projectile_ms); + COMM(Byte, max_rewind_fast_projectile_ms); + COMM(Byte, rewind_fast_projectile_thresh); + COMM(Byte, wp_default_min_ping_ms); + COMM(Byte, wp_global_enable); + COMM(Byte, wp_global_disable); + COMM(Byte, pp_global_enable); + COMM(Byte, pp_global_disable); + COMM(Byte, wpp_global_enable); + COMM(Byte, wpp_global_disable); + COMM(Byte, gren_beta_disable); #ifdef SSQC return TRUE; @@ -534,6 +534,7 @@ void EntUpdate_Projectile(float isnew) { void WeapPred_InitDefaultConfig() { fo_config.qc_physics = 0; + fo_config.static_newmis_ms = 50; fo_config.dynamic_newmis_ms = 0; fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 100; @@ -564,6 +565,7 @@ static void WeaponPred_CheckConfigUpdate() { // Target is also the long form localinfo name. CONFIG_UPDATE("qcp", qc_physics); + CONFIG_UPDATE("snm", static_newmis_ms); CONFIG_UPDATE("dnm", dynamic_newmis_ms); CONFIG_UPDATE("mrt", max_rewind_ms); CONFIG_UPDATE("mrsp", max_rewind_slow_projectile_ms); @@ -578,7 +580,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_disable); CONFIG_UPDATE("gbd", gren_beta_disable); - CLAMP_UPDATE(dynamic_newmis_ms, 0, NEWMIS_MS); + CLAMP_UPDATE(dynamic_newmis_ms, 0, fo_config.static_newmis_ms); CLAMP_UPDATE(max_rewind_ms, 0, 250); CLAMP_UPDATE(max_rewind_slow_projectile_ms, 0, fo_config.max_rewind_ms); CLAMP_UPDATE(max_rewind_fast_projectile_ms, 0, fo_config.max_rewind_ms); From 7f20ef39a031a2c9ae3f4a64ceb4f10dbabccfe0 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 18 Nov 2022 22:07:58 -0800 Subject: [PATCH 1874/2474] Track down OOB I suspect it's the logging code, but extra catches added just in case. --- csqc/weapon_predict.qc | 4 ++++ share/weapons.qc | 6 +++++- ssqc/events.qc | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 9b0eacb9..c495dba3 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -879,6 +879,10 @@ static void FPP_ApplyGrenadeProperties(entity proj) { if (proj.fpp_index != FPP_GRENADE) return; + if (proj.wpp_aux < GREN_FIRST) { + printf("proj missing gren_type, tell newby\n"); + proj.wpp_aux = GREN_FIRST; + } FO_GrenInfo* gdesc = FO_GrenDesc(proj.wpp_aux); setmodelindex(proj, gdesc->modelindex); diff --git a/share/weapons.qc b/share/weapons.qc index d29f28d0..016559ae 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -245,7 +245,11 @@ FO_ClassGrenades class_grenades[] = { { PC_CIVILIAN, {GREN_NONE, GREN_NONE} }, }; -inline FO_GrenInfo* FO_GrenDesc(int gren_type) { +FO_GrenInfo* FO_GrenDesc(int gren_type) { + if (gren_type < GREN_FIRST) { + printf("proj missing gren_type, tell newby\n"); + gren_type = GREN_FIRST; + } return &fo_grenades[gren_type - GREN_FIRST]; } diff --git a/ssqc/events.qc b/ssqc/events.qc index 485f8031..cd95d1c6 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -186,7 +186,7 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (damageKind == "damageTeam") return; } - else if (inflictorId == "grenade") + else if (inflictorId == "grenade" && inflictor.gren_type >= GREN_FIRST) inflictorId = FO_GrenDesc(inflictor.gren_type)->logname; } @@ -285,7 +285,7 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { attackername = "world"; else if (inflictorId == "building_sentrygun") attackername = getEntityNameOrLogin(attacker.real_owner); - else if (inflictorId == "grenade") + else if (inflictorId == "grenade" && inflictor.gren_type >= GREN_FIRST) inflictorId = FO_GrenDesc(inflictor.gren_type)->logname; } From c0c194e9821e1ac0d99e82863b9b14b2d6ebcf12 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 19 Nov 2022 14:06:38 -0800 Subject: [PATCH 1875/2474] Add more gren_type annotation Crash before was likely a held grenade which gets spawned as a child of the originally held grenade and wasn't copying the type over. --- csqc/weapon_predict.qc | 2 +- ssqc/tfort.qc | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c495dba3..2a8a5bdb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -880,7 +880,7 @@ static void FPP_ApplyGrenadeProperties(entity proj) { return; if (proj.wpp_aux < GREN_FIRST) { - printf("proj missing gren_type, tell newby\n"); + printf("proj (%s) missing gren_type, tell newby\n", proj.model); proj.wpp_aux = GREN_FIRST; } FO_GrenInfo* gdesc = FO_GrenDesc(proj.wpp_aux); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 5ffe053b..9ab4157b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -945,6 +945,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { newmis.movetype = 6; newmis.solid = 2; newmis.classname = "grenade"; + newmis.gren_type = GREN_FLARE; makevectors(self.v_angle); newmis.velocity = (v_forward * 600) + (v_up * 25); newmis.velocity = newmis.velocity * 700; @@ -1012,6 +1013,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { newmis.movetype = 6; newmis.solid = 2; newmis.classname = "grenade"; + newmis.gren_type = GREN_FLARE; makevectors(self.v_angle); if (self.v_angle_x) { newmis.velocity = v_forward * 1200 + v_up * 200; @@ -2738,8 +2740,8 @@ void () TeamFortress_ExplodePerson = { KickPlayer(-2, self.owner); newmis = spawn(); - newmis.movetype = 10; - newmis.solid = 2; + newmis.movetype = MOVETYPE_BOUNCE; + newmis.solid = SOLID_BBOX; newmis.classname = "grenade"; newmis.team_no = self.owner.team_no; newmis.owner = self.owner; @@ -2762,9 +2764,9 @@ void () TeamFortress_ExplodePerson = { return; } - int gren_type = TF_GREN_conv(self.weapon); - FO_GrenInfo* gdesc = FO_GrenDesc(gren_type); - stg_table_entry* ste = &stg_table[gren_type - GREN_FIRST]; + int gtype = TF_GREN_conv(self.weapon); + FO_GrenInfo* gdesc = FO_GrenDesc(gtype); + stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; newmis.skin = gdesc->skin; FO_SetModel(newmis, gdesc->model); From f7e5a9af5df7e384276fd1c96f9d042347f31eba Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 20 Nov 2022 12:31:42 -0800 Subject: [PATCH 1876/2474] Support MOVETYPE_NONE And make unsupported movetypes non-fatal so we can back out qcp without restarting server. --- share/physics.qc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/share/physics.qc b/share/physics.qc index ca1b2367..7d04573e 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -168,13 +168,22 @@ float Phys_Advance(entity e, float delta) { dt = Phys_Adv_Linear(e, delta); delta = 0; break; + case MOVETYPE_BOUNCE: dt = Phys_Adv_Bounce(e, phys_tic); delta -= phys_tic; break; - default: - errorf("unsupported movetype %d\n", e.movetype); + case MOVETYPE_NONE: + dt = delta; + delta = 0; + break; + + default: + printf("ERROR: %s unsupported movetype %d\n", e.model, e.movetype); + dt = delta; + delta = 0; + break; } total += dt; From 4d2a9b91fd7506c1fec3a8aa0142d5beb3327e77 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 21 Nov 2022 14:51:48 -0800 Subject: [PATCH 1877/2474] Disambiguate Grenades and Handgrenades While grenades and handgrenades share physics models, there are a few properties -- e.g. sound -- for which they are separate categories. Split them into FPP_GRENADE and FPP_HANDGRENADE. This fixes predicted sound for hand grenades, also fixes there being no sound in the case where we dont have the new grenade physics (and so can't send csqc projectiles, meaning we never triggered the missed predicted sound case when qcp_physics == 0). --- csqc/weapon_predict.qc | 19 +++++++++---------- share/prediction.qc | 22 ++++++++++++++++++++-- ssqc/tfort.qc | 3 +-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2a8a5bdb..4c3a42eb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -252,16 +252,13 @@ void Pred_Sound(SoundIndex snd, float vol = 1) { if (snd == SND_NONE || !IsEffectFrame() || pstate_pred.tfstate & TFSTATE_FLASHED) return; - ASSERTD_GE(snd, SND_FIRST); - snd -= SND_FIRST; last_pred_sound = time; setorigin(pred_sound_entity, pmove_org); - /* sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, vol, ATTN_NORM); */ - sound(pred_sound_entity, CHAN_WEAPON, snd_types[snd].sound, vol, ATTN_NORM); + sound(pred_sound_entity, CHAN_WEAPON, Snd_Get(snd)->sound, vol, ATTN_NORM); } void PredProj_Sound(int proj_type, float vol = 1) { - Pred_Sound(fpp_types[proj_type].snd, vol); + Pred_Sound(FPP_Get(proj_type)->snd, vol); } inline FO_WeapInfo* WP_CurrentWeapon() { @@ -737,7 +734,9 @@ DEFCVAR_FLOAT(r_grenadetrail, 1); int FPP_FindTrail(entity e) { float is_rocket = e.fpp_index == FPP_ROCKET; - float is_grenade = e.fpp_index == FPP_GRENADE; + float is_grenade = e.fpp_index == FPP_GRENADE; // Do not use IsGrenade + // here. This only applies + // to FPP_GRENADE. if (is_rocket || is_grenade) { float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; @@ -849,7 +848,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { setsize(proj, [0,0,0], [0,0,0]); proj.s_origin = pmove_org + offset; - if (fpp_type != FPP_GRENADE) { + if (!FPP_IsGrenade(fpp_type)) { proj.velocity = v_forward * fpp_types[fpp_type].speed; proj.s_origin[2] += 16; } else { @@ -876,7 +875,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { } static void FPP_ApplyGrenadeProperties(entity proj) { - if (proj.fpp_index != FPP_GRENADE) + if (!FPP_IsGrenade(proj.fpp_index)) return; if (proj.wpp_aux < GREN_FIRST) { @@ -949,7 +948,7 @@ static void W_ThrowGren(float is_throw) { return; // Not time to throw yet, THROWING set if necessary. if (IsEffectFrame()) { - entity gren = PP_CreateProjectile(FPP_GRENADE, '0 0 0'); + entity gren = PP_CreateProjectile(FPP_HANDGRENADE, '0 0 0'); int index = (pstate_pred.tfstate & TFSTATE_GREN1_PRIMED) ? 0 : 1; gren.wpp_aux = FO_ClassGren(pstate_pred.playerclass, index)->id; FPP_ApplyGrenadeProperties(gren); @@ -1094,7 +1093,7 @@ float PredProjectile_MatchProjectile() { self.p_time = match.p_time; self.trail_started = match.trail_started; - if (self.fpp_index == FPP_GRENADE) + if (FPP_IsGrenade(self.fpp_index)) self.angles = match.angles; if (CVARF(wpp_debug) & 1) { diff --git a/share/prediction.qc b/share/prediction.qc index efa86aac..ae50f6e2 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -82,6 +82,7 @@ enum SoundIndex:float { SND_SSG, SND_RL, SND_GREN, + SND_THROWGREN, SND_NAIL, SND_SNAIL, SND_FLAMETHROWER, @@ -104,6 +105,7 @@ fo_predsnd snd_types[] = { { SND_SSG, "shotgn2.wav" }, { SND_RL, "sgun1.wav" }, { SND_GREN, "grenade.wav" }, + { SND_THROWGREN, "ax1.wav" }, { SND_NAIL, "rocket1i.wav" }, { SND_SNAIL, "spike2.wav" }, { SND_FLAMETHROWER, "flmfire2.wav" }, @@ -117,7 +119,8 @@ fo_predsnd snd_types[] = { enum { FPP_ROCKET, - FPP_GRENADE, + FPP_GRENADE, // Grenade launcher + FPP_HANDGRENADE, // TF Grenade FPP_INCENDIARY, FPP_NAIL, FPP_SUPER_NAIL, @@ -146,6 +149,8 @@ fo_projectile fpp_types[] = { "missile.mdl", "", SND_RL, TRUE }, { FPP_GRENADE, MOVETYPE_BOUNCE, 600, "grenade2.mdl", "t_grenade", SND_GREN, TRUE}, + { FPP_HANDGRENADE, MOVETYPE_BOUNCE, 600, + "hgren2.mdl", "t_grenade", SND_THROWGREN}, { FPP_INCENDIARY, MOVETYPE_FLYMISSILE, 800, "lavaball.mdl", "t_lavaball", SND_RL, TRUE }, { FPP_NAIL, MOVETYPE_FLYMISSILE, 1500, @@ -162,6 +167,14 @@ fo_projectile fpp_types[] = { "proj_diam2.mdl", "tr_asscan", SND_NONE /* in anim */ }, }; +inline fo_projectile* FPP_Get(int fpp_type) { return &fpp_types[fpp_type]; } +inline fo_predsnd* Snd_Get(int snd_type) { return &snd_types[snd_type - SND_FIRST]; } +inline fo_predsnd* FPP_Sound(int fpp_type) { return Snd_Get(FPP_Get(fpp_type)->snd); } + +inline float FPP_IsGrenade(int fpp_type) { + return fpp_type == FPP_GRENADE || fpp_type == FPP_HANDGRENADE; +} + // `wpp_aux` disambiguation for FPP_GRENADE projectiles. void InitFppProjectiles() { float i; @@ -737,7 +750,7 @@ void FOProj_Finalize(entity mis) { PredProj_Sound(fpp_type); float csqc_networking = fo_projectiles; - if (fpp_type == FPP_GRENADE) { + if (FPP_IsGrenade(fpp_type)) { FO_GrenInfo* gdesc = FO_GrenDesc(mis.gren_type); setmodel(mis, gdesc->model); @@ -764,6 +777,11 @@ void FOProj_Finalize(entity mis) { mis.SendFlags = FOPP_POS | FOPP_INIT; if (mis.wpp_aux) mis.SendFlags |= FOPP_AUX; + } else if (fpp_type == FPP_HANDGRENADE) { + entity target = self; + if (target.classname != "player") + target = target.owner; // Handle call from timer on latched throw. + FO_Sound(target, CHAN_WEAPON, Snd_Get(SND_THROWGREN)->sound, 1, ATTN_NORM); } } #endif diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 9ab4157b..a0c45336 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -837,9 +837,8 @@ void (entity timer) FO_SpawnThrownGrenade = { UpdateClientGrenadeThrown(user); } - FO_Sound(user, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); KickPlayer(-1, user); - entity proj = FOProj_Create(FPP_GRENADE); + entity proj = FOProj_Create(FPP_HANDGRENADE); proj.owner = user; proj.movetype = MOVETYPE_BOUNCE; proj.solid = SOLID_BBOX; From 04facfce24ff9a36a146010f749e9e74961fec45 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 21 Nov 2022 15:20:42 -0800 Subject: [PATCH 1878/2474] Enable new physics by default No issues with pugs earlier today, can still be disabled via: `localinfo qcp 0`. Also temporarily disable forwarding of handgrenades (new nhfg=1). The problem here is that throws being made against the grenade timer which is already offset for ping. The right answer here is to actually do all grenades with rewind, e.g. no more timer offsets, backdate and replay the grenade throw when it lands on server, with appropriate forwarding. This will take a little more work though, so just disable forwarding in the mean time (there was non prior anyway). --- csqc/weapon_predict.qc | 1 + share/commondefs.qc | 1 + share/prediction.qc | 8 +++++++- ssqc/antilag.qc | 30 ------------------------------ 4 files changed, 9 insertions(+), 31 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 4c3a42eb..dd8f9c3f 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -163,6 +163,7 @@ void WPP_Status() { PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); PRINT_CONFIG(wp_default_min_ping_ms); + PRINT_CONFIG(no_forward_hg); PRINT_CONFIG_ACTIVE(wp_global_enable); PRINT_CONFIG_ACTIVE(wp_global_disable); PRINT_CONFIG_ACTIVE(pp_global_enable); diff --git a/share/commondefs.qc b/share/commondefs.qc index 47a566cb..7b8c2558 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -7,6 +7,7 @@ var struct { float max_rewind_fast_projectile_ms; float rewind_fast_projectile_thresh; float wp_default_min_ping_ms; + float no_forward_hg; float wp_global_enable; float wp_global_disable; diff --git a/share/prediction.qc b/share/prediction.qc index ae50f6e2..5d3a48d1 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -394,6 +394,7 @@ void EntUpdate_Config() { COMM(Byte, wpp_global_enable); COMM(Byte, wpp_global_disable); COMM(Byte, gren_beta_disable); + COMM(Byte, no_forward_hg); #ifdef SSQC return TRUE; @@ -546,7 +547,7 @@ void EntUpdate_Projectile(float isnew) { #undef COMM void WeapPred_InitDefaultConfig() { - fo_config.qc_physics = 0; + fo_config.qc_physics = 1; fo_config.static_newmis_ms = 50; fo_config.dynamic_newmis_ms = 0; fo_config.max_rewind_ms = 250; @@ -554,6 +555,7 @@ void WeapPred_InitDefaultConfig() { fo_config.max_rewind_fast_projectile_ms = 100; fo_config.rewind_fast_projectile_thresh = 1500; fo_config.wp_default_min_ping_ms = 40; + fo_config.no_forward_hg = 1; } #ifdef SSQC @@ -592,6 +594,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_enable); CONFIG_UPDATE("wppge", wpp_global_disable); CONFIG_UPDATE("gbd", gren_beta_disable); + CONFIG_UPDATE("nfhg", no_forward_hg); CLAMP_UPDATE(dynamic_newmis_ms, 0, fo_config.static_newmis_ms); CLAMP_UPDATE(max_rewind_ms, 0, 250); @@ -815,6 +818,9 @@ ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { max_ping_credit += dynamic_newmis_ms(); } + if (fpp_type == FPP_HANDGRENADE && fo_config.no_forward_hg) + max_ping_credit = 0; + float frame_nudge = 0; #ifdef CSQC // Account for the fact that the server usually has a physics frame that's diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index ca80072c..83b33cdd 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,33 +1,3 @@ -static float NoLanProject() { - if (self.client_ping <= 25) - return TRUE; - return FALSE; -} - -void AL_ProjectProjectile (entity projectile) { - if (NoLanProject()) - return; - - float time_offset = - min(self.client_ping, fo_config.max_rewind_slow_projectile_ms) / 1000.0; - - vector projected_origin = projectile.origin + (projectile.velocity * time_offset); - // Rewind projectile is preferable but unavailable. This would rewind and replay the projectile from origin - // to the projected origin. Since it isn't available, we will use a traceline, without MOVE_LAGGED - // because by tracing between old origin and projected origin we effectively have a single (last) frame - // rewind at the projected origin. The effect is high ping players are disadvantaged in close combat. - // This is preferable to unhappy low ping players. - // - // XXX This will updated to use rewind. - traceline(projectile.origin, projected_origin, 0, self); - - if (trace_fraction < 1) { - projected_origin = trace_endpos; - } - - setorigin(projectile, projected_origin); -} - void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { float ping = projectile.owner.client_ping; ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); From 3a4e4cd96266e18829c0159843528a4e90c2660b Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 21 Nov 2022 15:47:49 -0800 Subject: [PATCH 1879/2474] Clown mode The rules of physics were made to be broken. --- csqc/weapon_predict.qc | 10 ++++++++++ share/commondefs.qc | 11 +++++++++++ share/physics.qc | 15 +++++++++++---- share/prediction.qc | 7 +++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index dd8f9c3f..241af50e 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -171,6 +171,16 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(wpp_global_enable); PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); + + static string clown_desc[] = { "Rubber grenades", "Proj gravity" }; + if (fo_config.clown_settings) { + printf("Clown mode:\n"); + printf(" .clown gravity=%d\n", fo_config.clown_grav); + for (float i = 0; i < clown_desc.length; i++) + if (fo_config.clown_settings & (1 << i)) + printf(" .%s\n", clown_desc[i]); + + } } #undef PRINT_CONFIG diff --git a/share/commondefs.qc b/share/commondefs.qc index 7b8c2558..4cf558a2 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -8,6 +8,8 @@ var struct { float rewind_fast_projectile_thresh; float wp_default_min_ping_ms; float no_forward_hg; + float clown_settings; + float clown_grav; float wp_global_enable; float wp_global_disable; @@ -18,6 +20,15 @@ var struct { float gren_beta_disable; } fo_config; +enumflags { + CLOWN_RUBBERGREN, + CLOWN_PROJ_GRAVITY, +}; + +inline float IsClownMode(int setting) { + return fo_config.clown_settings & setting; +} + #define MAX_FLAGINFO_LINES 10 #define ENG_BUILDING_DISMANTLE_DISTANCE 100 #define ENG_BUILDING_MAINT_DISTANCE 80 diff --git a/share/physics.qc b/share/physics.qc index 7d04573e..336df81b 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -123,7 +123,8 @@ float Phys_Adv_Bounce(entity e, float dt) { e.angles += move_time * e.avelocity; float bounce_stop = 60 / 800 * g; - e.velocity = Phys_ClipVel(e.velocity, trace_plane_normal, 1.5); + float debounce = !IsClownMode(CLOWN_RUBBERGREN) ? 1.5 : 2.5; + e.velocity = Phys_ClipVel(e.velocity, trace_plane_normal, debounce); if (PHYS_DEBUG) printf("%s v=%0.3f p=%v\n", qc_prefix(), e.velocity_z, e.origin); @@ -156,7 +157,8 @@ float Phys_Advance(entity e, float delta) { return 0; if (phys_tic * vlen(e.velocity) > 32) - error("phys_tic too big, needs adaptive scaling\n"); + if (!fo_config.clown_settings) + error("phys_tic too big, needs adaptive scaling\n"); float total = 0, dt = 0; delta += e.phys_carry; @@ -164,9 +166,14 @@ float Phys_Advance(entity e, float delta) { switch (e.movetype) { case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: + float step = delta; + if (IsClownMode(CLOWN_PROJ_GRAVITY)) { + step = phys_tic; + e.velocity_z += -fo_config.clown_grav * step; + } // Linear projectiles we can always simulate in a single step. - dt = Phys_Adv_Linear(e, delta); - delta = 0; + dt = Phys_Adv_Linear(e, step); + delta -= step; break; case MOVETYPE_BOUNCE: diff --git a/share/prediction.qc b/share/prediction.qc index 5d3a48d1..cb6750c1 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -395,6 +395,8 @@ void EntUpdate_Config() { COMM(Byte, wpp_global_disable); COMM(Byte, gren_beta_disable); COMM(Byte, no_forward_hg); + COMM(Byte, clown_settings); + COMM(Float, clown_grav); #ifdef SSQC return TRUE; @@ -546,6 +548,7 @@ void EntUpdate_Projectile(float isnew) { #undef COMMO #undef COMM + void WeapPred_InitDefaultConfig() { fo_config.qc_physics = 1; fo_config.static_newmis_ms = 50; @@ -556,6 +559,8 @@ void WeapPred_InitDefaultConfig() { fo_config.rewind_fast_projectile_thresh = 1500; fo_config.wp_default_min_ping_ms = 40; fo_config.no_forward_hg = 1; + fo_config.clown_settings = 0; + fo_config.clown_grav = 400; } #ifdef SSQC @@ -595,6 +600,8 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_disable); CONFIG_UPDATE("gbd", gren_beta_disable); CONFIG_UPDATE("nfhg", no_forward_hg); + CONFIG_UPDATE("clown", clown_settings); + CONFIG_UPDATE("clown_grav", clown_grav); CLAMP_UPDATE(dynamic_newmis_ms, 0, fo_config.static_newmis_ms); CLAMP_UPDATE(max_rewind_ms, 0, 250); From 91c6c5c14b283b9f412b0eec8b324e8e1ce7d1d3 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 22 Nov 2022 01:58:41 -0800 Subject: [PATCH 1880/2474] Don't bounce down slopes by default Restore old behavior which ignored the plane normal and let you stick grenades (e.g. pipes) on slopes more easily. --- share/physics.qc | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/share/physics.qc b/share/physics.qc index 336df81b..21a1ffe4 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -6,6 +6,15 @@ static const float phys_tic = 0.005; .float phys_carry; // Carry from last partial tic .float phys_t; // Total physics time accumulated +enumflags { + PHYS_ENABLED, + PHYS_BOUNCE_DOWN_SLOPES, +}; + +static inline float PhysFlagEnabled(float flag) { + return fo_config.qc_physics & flag; +} + #ifdef SSQC void Predict_UpdateHack(entity e); @@ -119,6 +128,9 @@ float Phys_Adv_Bounce(entity e, float dt) { return dt; } + if (trace_allsolid) + trace_fraction = 0; + move_time *= min(1 - trace_fraction, 0); e.angles += move_time * e.avelocity; @@ -129,8 +141,13 @@ float Phys_Adv_Bounce(entity e, float dt) { if (PHYS_DEBUG) printf("%s v=%0.3f p=%v\n", qc_prefix(), e.velocity_z, e.origin); - float bounce_speed = dot(trace_plane_normal, e.velocity); - if (trace_plane_normal.z > 0.7 && fabs(bounce_speed) < bounce_stop) { + float bounce_speed; + if (PhysFlagEnabled(PHYS_BOUNCE_DOWN_SLOPES)) + bounce_speed = dot(trace_plane_normal, e.velocity); + else + bounce_speed = e.velocity_z; + + if (trace_plane_normal.z > 0.7 && bounce_speed < bounce_stop) { e.flags |= FL_ONGROUND; e.groundentity = trace_ent; e.velocity = '0 0 0'; From 9aaa19fd3fdb74ebbde69549f1d347d39f3a897b Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 22 Nov 2022 15:47:40 -0800 Subject: [PATCH 1881/2474] Physics Updates - Clean-up physics code now that it's ~stable. - Eliminate the notion of carry-time, just use an absolute timepoint. Calculate the right steps against this where necessary. - Add support for interpolating local physics slightly ahead - Fix bug which was misaligning client projectiles --- csqc/weapon_predict.qc | 58 ++++++++++++------- share/physics.qc | 128 ++++++++++++++++++++++------------------- share/prediction.qc | 31 +++++----- ssqc/antilag.qc | 2 +- 4 files changed, 119 insertions(+), 100 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 241af50e..60b87136 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -5,6 +5,9 @@ DEFCVAR_FLOAT(wpp_min_ping, -1); DEFCVAR_FLOAT(wpp_weap_predict, -1); DEFCVAR_FLOAT(wpp_proj_predict, -1); +DEFCVAR_FLOAT(wpp_phys_adv_ms, 0); +DEFCVAR_FLOAT(wpp_phys_local_adv_ms, SERVER_FRAME_MS); + float WP_MinPing() { if (CVARF(wpp_min_ping) == -1) return fo_config.wp_default_min_ping_ms; @@ -705,7 +708,19 @@ trail_table_entry trail_table[] = { {{"TE_RAILTRAIL"}}, }; -float nail_trail; +static inline float phys_adv_dt() { + float adj_ping = max(pstate_pred.client_ping, 0); + return min(CVARF(wpp_phys_adv_ms), adj_ping) / 1000.0; +} + +float get_phys_time(entity e) { + float ptime = time, adv_dt; + if (e.owner_entnum && e.owner_entnum != player_localentnum) + adv_dt = phys_adv_dt(); + else + adv_dt = CVARF(wpp_phys_local_adv_ms) / 1000.0; + return ptime + adv_dt; +} void FO_PP_Init() { // Entity we'll attach locally generated sound to. @@ -781,7 +796,7 @@ DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); .float trail_started; float PP_PredrawActive() { - CPhys_Update(self); + Phys_Advance(self, get_phys_time(self), 0); // we need to space out the particles incase we're running at very high fps if (time > self.p_time) { @@ -825,7 +840,6 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { if (!PP_Enabled()) return __NULL__; - makevectors(input_angles); entity proj = spawn(); proj.owner = edict_num(player_localentnum); @@ -857,11 +871,11 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.drawmask = MASK_PRED_PROJECTILE; setsize(proj, [0,0,0], [0,0,0]); - proj.s_origin = pmove_org + offset; + proj.origin = pmove_org + offset; if (!FPP_IsGrenade(fpp_type)) { proj.velocity = v_forward * fpp_types[fpp_type].speed; - proj.s_origin[2] += 16; + proj.origin[2] += 16; } else { if (!input_angles_x) { proj.velocity = v_forward * fpp_types[fpp_type].speed; @@ -874,7 +888,8 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { } proj.angles = input_angles; proj.angles[0] *= -1; - CPhys_Init(proj, proj.starttime, static_dt); + proj.s_origin = proj.origin; + Phys_Init(proj, proj.starttime, static_dt, PHYSF_CONSUME_ALL); proj.oldorigin = proj.origin; proj.pred_next = predicted_projectiles; @@ -1091,7 +1106,8 @@ float PredProjectile_MatchProjectile() { if (time > proj.endtime - 0.01) break; // Projectile list is time ordered - CPhys_Sync(proj, max(time, self.phys_time)); + Phys_Advance(proj, get_phys_time(proj), 0); + float d = vlen(proj.origin - self.origin); if (!best || d < best) { best = d; @@ -1108,13 +1124,12 @@ float PredProjectile_MatchProjectile() { self.angles = match.angles; if (CVARF(wpp_debug) & 1) { - string s = sprintf(" p_diff = %0.1f, t_e=%0.3f t=%0.3f d_t=%0.3f", + string s = sprintf(" p_diff: %0.1f [%0.3f] t=%0.3f p_t=c:%0.3f s:%0.3f [%0.3f]", vlen(match.origin - self.origin), vlen(match.origin - self.origin) / vlen(self.velocity), - time, time - self.phys_time); - s = strcat(s, sprintf(" [c=%d/%0.3f s=%d/%0.3f,%0.3f] alms=%d\n", - vlen(match.origin - pmove_org), match.phys_time, - vlen(self.origin - pmove_org), self.s_time, self.phys_time, + time, match.phys_time, self.phys_time, match.phys_time - self.phys_time); + s = strcat(s, sprintf(" [c=%d s=%d] al=%d\n", + vlen(match.origin - pmove_org), vlen(self.origin - pmove_org), self.antilag_ms)); print(s); } @@ -1127,17 +1142,21 @@ float PredProjectile_MatchProjectile() { } // Called on `self`. -void InitProjectileEnt() { +void InitProjectileEnt(float sendflags) { self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; - self.s_time = self.phys_time; - self.angles = vectoangles(self.velocity); + if (sendflags & FOPP_ANGLES == 0) + self.angles = vectoangles(self.velocity); self.owner = edict_num(self.owner_entnum); FPP_Init(self.fpp_index, self); FPP_ApplyGrenadeProperties(self); - CPhys_Init(self, max(time, self.phys_time), time - self.phys_time); + float ptime = get_phys_time(self); + if (ptime > self.phys_time /* from server */) + Phys_Advance(self, ptime, 0); + else + setorigin(self, self.origin); // We still check this with projectile prediction as there could be in // flight projectiles on the transition. This is effectively a nop in the @@ -1154,14 +1173,10 @@ void InitProjectileEnt() { if (!has_predicted) { // Back-track trail for entities without a local prediction. We use // s_origin here as that's what we know antilag_ms to be relative to. - self.oldorigin = self.s_origin - self.antilag_ms/ 1000.0 * self.velocity; + self.oldorigin = self.s_origin - self.antilag_ms/1000.0 * self.velocity; } } -void WP_SyncPhysProjectile() { - CPhys_Init(self, max(time, self.phys_time), time - self.phys_time); -} - DEFCVAR_FLOAT(r_drawviewmodel, 1); void WP_UpdateViewModel(entity pweap_ent) { @@ -1220,6 +1235,7 @@ float WP_ClientThink() { old_input_buttons = input_buttons; if (!getinputstate(pframe) || input_timelength <= 0) break; + makevectors(input_angles); pstate_pred.buttons_held = input_buttons; pstate_pred.buttons_up = old_input_buttons & (~input_buttons); diff --git a/share/physics.qc b/share/physics.qc index 21a1ffe4..cb7d8a23 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -2,13 +2,14 @@ static const float phys_tic = 0.005; -.float phys_time; // Last physics time, 0 ==> s_time -.float phys_carry; // Carry from last partial tic -.float phys_t; // Total physics time accumulated +.float phys_time; // Current physics time enumflags { - PHYS_ENABLED, - PHYS_BOUNCE_DOWN_SLOPES, + PHYSB_ENABLED, +}; + +enumflags { + PHYSF_CONSUME_ALL, }; static inline float PhysFlagEnabled(float flag) { @@ -18,7 +19,7 @@ static inline float PhysFlagEnabled(float flag) { #ifdef SSQC void Predict_UpdateHack(entity e); -static void Phys_Impact(entity e) { +static void Phys_Impact(entity e, float dt, float phys_flags) { if (trace_ent.solid == SOLID_NOT) return; @@ -30,46 +31,35 @@ static void Phys_Impact(entity e) { self = held_self; } +#if PHYS_DEBUG + printf("SPhys: Impact t=%0.3f pt=%0.3f [%0.3f]\n", + time, e.phys_time + dt, e.phys_time + frametime); + printf("Imp: e=%p e.o=%p te=%p\n", e, e.owner, other); +#endif + if (trace_ent.solid != SOLID_BSP) Predict_UpdateHack(e); } #else +DEFCVAR_FLOAT(fo_phys_debug, 0); + .entity groundentity; -.vector s_origin; .float is_removed; // The server code implements this to track entity removal // for debug checks. But we can usefully piggy-back on it. -static void Phys_Impact(entity e) { +float get_phys_time(entity); + +static void Phys_Impact(entity e, float dt, float phys_flags) { if (trace_ent.solid == SOLID_NOT) return; if (e.movetype == MOVETYPE_FLYMISSILE) { e.is_removed = TRUE; } -} - -float Phys_Advance(entity e, float delta); - -void CPhys_Sync(entity e, float target_time) { - if (target_time > e.phys_time) { - Phys_Advance(e, target_time - e.phys_time); - e.phys_time = target_time; - } -} -void CPhys_Update(entity e) { - CPhys_Sync(e, time); -} - -void CPhys_Init(entity e, float target_time, float delta) { - e.origin = e.s_origin; - if (delta > 0) { - Phys_Advance(e, delta); - } else { - setorigin(e, e.origin); - } - e.phys_carry = 0; - e.phys_time = target_time; + if (CVARF(fo_phys_debug) & 1) + printf("CPhys: Impact t=%0.3f pt=%0.3f [%0.3f]\n", time, e.phys_time + dt, + get_phys_time(e)); } #endif @@ -77,20 +67,20 @@ static inline float get_gravity() { return cvar("sv_gravity"); } #define dot(v1, v2) ((vector)v1 * (vector)v2) -float Phys_Push(entity e, vector offset) { - float flags = 0; +float Phys_Push(entity e, vector offset, float dt, float phys_flags) { + float trace_flags = 0; if (e.movetype == MOVETYPE_FLYMISSILE) - flags |= MOVE_MISSILE; + trace_flags |= MOVE_MISSILE; // Note: Networked entities don't currently intersect on CSQC instantiation // of this, we fudge this in Phys_Impact from the server side. - traceline(e.origin, e.origin + offset, flags, e); + traceline(e.origin, e.origin + offset, trace_flags, e); e.origin = trace_endpos; if (trace_fraction < 1) { setorigin(e, trace_endpos); - Phys_Impact(e); + Phys_Impact(e, trace_fraction * dt, phys_flags); return FALSE; } @@ -109,7 +99,7 @@ vector Phys_ClipVel(vector orig, vector normal, float overbounce) { return result; } -float Phys_Adv_Bounce(entity e, float dt) { +float Phys_Adv_Bounce(entity e, float dt, float phys_flags) { float g = get_gravity(); if (e.flags & FL_ONGROUND) { @@ -122,7 +112,7 @@ float Phys_Adv_Bounce(entity e, float dt) { e.velocity_z -= 0.5 * dt * g; float move_time = dt, bounce; - if (Phys_Push(e, move_time * e.velocity)) { + if (Phys_Push(e, move_time * e.velocity, move_time, phys_flags)) { e.velocity_z -= 0.5 * dt * g; e.angles += dt * e.avelocity; return dt; @@ -131,7 +121,7 @@ float Phys_Adv_Bounce(entity e, float dt) { if (trace_allsolid) trace_fraction = 0; - move_time *= min(1 - trace_fraction, 0); + move_time = (1 - trace_fraction) * dt; e.angles += move_time * e.avelocity; float bounce_stop = 60 / 800 * g; @@ -142,7 +132,7 @@ float Phys_Adv_Bounce(entity e, float dt) { printf("%s v=%0.3f p=%v\n", qc_prefix(), e.velocity_z, e.origin); float bounce_speed; - if (PhysFlagEnabled(PHYS_BOUNCE_DOWN_SLOPES)) + if (cvar("sv_gameplayfix_grenadebouncedownslopes")) bounce_speed = dot(trace_plane_normal, e.velocity); else bounce_speed = e.velocity_z; @@ -159,8 +149,8 @@ float Phys_Adv_Bounce(entity e, float dt) { return dt - move_time; } -float Phys_Adv_Linear(entity e, float dt) { - Phys_Push(e, dt * e.velocity); +float Phys_Adv_Linear(entity e, float dt, float phys_flags) { + Phys_Push(e, dt * e.velocity, dt, phys_flags); if (trace_fraction < 1) dt *= trace_fraction; @@ -169,54 +159,72 @@ float Phys_Adv_Linear(entity e, float dt) { return dt; } -float Phys_Advance(entity e, float delta) { - if (delta < 0 || e.is_removed) +float Phys_Advance(entity e, float target_time, float phys_flags) { + if (target_time < e.phys_time || e.is_removed) { + setorigin(e, e.origin); return 0; + } if (phys_tic * vlen(e.velocity) > 32) if (!fo_config.clown_settings) error("phys_tic too big, needs adaptive scaling\n"); - float total = 0, dt = 0; - delta += e.phys_carry; - while (delta > phys_tic) { + static float limit_eps = 0.0005; + float limit = (phys_flags & PHYSF_CONSUME_ALL) ? limit_eps : phys_tic; + float total = 0, dt = 0, step = 0, delta; + + while ((delta = target_time - e.phys_time) >= limit) { switch (e.movetype) { case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: - float step = delta; + // Linear projectiles we can always simulate in a single step. + if (limit > limit_eps) + step = floor(delta / limit) * limit; + else + step = delta; + + // Unless there's.... gravity if (IsClownMode(CLOWN_PROJ_GRAVITY)) { - step = phys_tic; + step = min(phys_tic, delta); e.velocity_z += -fo_config.clown_grav * step; } - // Linear projectiles we can always simulate in a single step. - dt = Phys_Adv_Linear(e, step); - delta -= step; + + dt = Phys_Adv_Linear(e, step, phys_flags); break; case MOVETYPE_BOUNCE: - dt = Phys_Adv_Bounce(e, phys_tic); - delta -= phys_tic; + step = min(phys_tic, delta); + dt = Phys_Adv_Bounce(e, step, phys_flags); break; case MOVETYPE_NONE: - dt = delta; - delta = 0; + step = dt = delta; break; default: printf("ERROR: %s unsupported movetype %d\n", e.model, e.movetype); - dt = delta; - delta = 0; + step = dt = delta; break; } + e.phys_time += step; + ASSERTF_LE(e.phys_time, target_time); total += dt; } - e.phys_t += total; - e.phys_carry = delta; setorigin(e, e.origin); return total; } +float Phys_Init(entity e, float target_time, float delta, float phys_flags) { + if (delta > 0) { + e.phys_time = target_time - delta; + return Phys_Advance(e, target_time, phys_flags); + } else { + e.phys_time = target_time; + setorigin(e, e.origin); + return 0; + } +} + #undef dot diff --git a/share/prediction.qc b/share/prediction.qc index cb6750c1..5f1860a1 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -10,6 +10,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; .float fpp_index; // Projectile type .float antilag_ms; #ifdef CSQC +.vector s_origin; .float s_time; #endif @@ -362,10 +363,11 @@ float() ReadShort = #362; float() ReadCoord = #364; float() ReadAngle = #365; float() ReadFloat = #367; +float() ReadEntity = #368; void InitWeapPredEnt(entity e); void WP_ServerUpdate(); -void InitProjectileEnt(); +void InitProjectileEnt(float sendflags); void WPP_UpdateEnable(float force); .float owner_entnum; @@ -493,8 +495,6 @@ float PP_SendEntity(entity to_player, float sendflags) { WriteByte(MSG_ENTITY, ENT_PROJECTILE); WriteByte(MSG_ENTITY, sendflags); #else -void WP_SyncPhysProjectile(); - #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() #define COMMO(_type, _dest, _src) ##_dest = Read##_type() #define COMM(_type, _field) COMMD(_type, _field, _field) @@ -505,19 +505,22 @@ void EntUpdate_Projectile(float isnew) { if (sendflags & FOPP_INIT) { COMM(Byte, fpp_index); COMM(Byte, antilag_ms); + COMMD(Entity, owner_entnum, owner); } if (sendflags & FOPP_POS) { - COMMD(Coord, s_origin[0], origin[0]); - COMMD(Coord, s_origin[1], origin[1]); - COMMD(Coord, s_origin[2], origin[2]); - + COMM(Coord, origin[0]); + COMM(Coord, origin[1]); + COMM(Coord, origin[2]); COMM(Coord, velocity[0]); COMM(Coord, velocity[1]); COMM(Coord, velocity[2]); COMM(Float, phys_time); - COMM(Float, phys_carry); +#ifdef CSQC + self.s_origin = self.origin; + self.s_time = self.phys_time; +#endif } if (sendflags & FOPP_ANGLES) { @@ -534,14 +537,10 @@ void EntUpdate_Projectile(float isnew) { } #ifdef SSQC - WriteEntity(MSG_ENTITY, self.owner); return TRUE; #else - self.owner_entnum = readentitynum(); if (isnew) - InitProjectileEnt(); - else - WP_SyncPhysProjectile(); + InitProjectileEnt(sendflags); #endif } #undef COMMD @@ -710,11 +709,7 @@ void PredProj_Sound(int proj_type, float vol = 1) { void WeaponPred_ProjectProjectile(int fpp_type, entity projectile); void FO_Phys() { - float delta = time - self.phys_time; - if (delta > 0) { - Phys_Advance(self, delta); - self.phys_time = time; - } + Phys_Advance(self, time, 0); float held_time, thinktime; // Once we lift physics, think execution comes with it. diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 83b33cdd..7ff56253 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -3,7 +3,7 @@ void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); float offset_dt = (offset.static_ms + offset.dynamic_ms) / 1000.0; - float dt = Phys_Advance(projectile, offset_dt); + float dt = Phys_Init(projectile, time, offset_dt, PHYSF_CONSUME_ALL); projectile.antilag_ms = dt * 1000; } #define DEBUG_ANTILAG 0 From fa0b08771468fa33ec06683c274d03ce849d8c76 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 21 Nov 2022 17:41:08 -0800 Subject: [PATCH 1882/2474] Update Rewind Clean up and rewrite some of the original rewind code in preparation for physics integration. Add interpolation between log points for more precise positions. Credit to reki/mvdsv for a bunch of this. Fixes a bug in detpipe rewind where some positions could be inconsistent. --- csqc/weapon_predict.qc | 23 ++- share/commondefs.qc | 7 +- share/physics.qc | 17 ++- share/prediction.qc | 13 +- ssqc/antilag.qc | 314 +++++++++++++++++------------------------ ssqc/combat.qc | 14 +- ssqc/defs.qc | 1 - ssqc/demoman.qc | 2 +- ssqc/qw.qc | 2 + ssqc/subs.qc | 6 - 10 files changed, 181 insertions(+), 218 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 60b87136..2ea9c204 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -161,12 +161,7 @@ void WPP_Status() { PRINT_CONFIG(qc_physics); PRINT_CONFIG(static_newmis_ms); PRINT_CONFIG(dynamic_newmis_ms); - PRINT_CONFIG(max_rewind_ms); - PRINT_CONFIG(max_rewind_slow_projectile_ms); - PRINT_CONFIG(max_rewind_fast_projectile_ms); - PRINT_CONFIG(rewind_fast_projectile_thresh); PRINT_CONFIG(wp_default_min_ping_ms); - PRINT_CONFIG(no_forward_hg); PRINT_CONFIG_ACTIVE(wp_global_enable); PRINT_CONFIG_ACTIVE(wp_global_disable); PRINT_CONFIG_ACTIVE(pp_global_enable); @@ -175,12 +170,26 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); + static string rewind_desc[] = { "rewind knockback" }; + printf("Rewind Settings:\n"); + if (fo_config.rewind_flags) { + for (float i = 0; i < rewind_desc.length; i++) + if (fo_config.rewind_flags & (1 << i)) + printf(" .%s\n", rewind_desc[i]); + + } + PRINT_CONFIG(no_forward_hg); + PRINT_CONFIG(max_rewind_ms); + PRINT_CONFIG(max_rewind_slow_projectile_ms); + PRINT_CONFIG(max_rewind_fast_projectile_ms); + PRINT_CONFIG(rewind_fast_projectile_thresh); + static string clown_desc[] = { "Rubber grenades", "Proj gravity" }; - if (fo_config.clown_settings) { + if (fo_config.clown_flags) { printf("Clown mode:\n"); printf(" .clown gravity=%d\n", fo_config.clown_grav); for (float i = 0; i < clown_desc.length; i++) - if (fo_config.clown_settings & (1 << i)) + if (fo_config.clown_flags & (1 << i)) printf(" .%s\n", clown_desc[i]); } diff --git a/share/commondefs.qc b/share/commondefs.qc index 4cf558a2..d4955f69 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -2,13 +2,14 @@ var struct { float qc_physics; float static_newmis_ms; float dynamic_newmis_ms; + float rewind_flags; float max_rewind_ms; float max_rewind_slow_projectile_ms; float max_rewind_fast_projectile_ms; float rewind_fast_projectile_thresh; float wp_default_min_ping_ms; float no_forward_hg; - float clown_settings; + float clown_flags; float clown_grav; float wp_global_enable; @@ -25,8 +26,8 @@ enumflags { CLOWN_PROJ_GRAVITY, }; -inline float IsClownMode(int setting) { - return fo_config.clown_settings & setting; +inline float IsClownMode(int flag) { + return fo_config.clown_flags & flag; } #define MAX_FLAGINFO_LINES 10 diff --git a/share/physics.qc b/share/physics.qc index cb7d8a23..2c320228 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -44,8 +44,7 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { DEFCVAR_FLOAT(fo_phys_debug, 0); .entity groundentity; -.float is_removed; // The server code implements this to track entity removal - // for debug checks. But we can usefully piggy-back on it. +.float voided; float get_phys_time(entity); @@ -53,9 +52,8 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { if (trace_ent.solid == SOLID_NOT) return; - if (e.movetype == MOVETYPE_FLYMISSILE) { - e.is_removed = TRUE; - } + if (e.movetype == MOVETYPE_FLYMISSILE) + e.voided = TRUE; if (CVARF(fo_phys_debug) & 1) printf("CPhys: Impact t=%0.3f pt=%0.3f [%0.3f]\n", time, e.phys_time + dt, @@ -160,13 +158,13 @@ float Phys_Adv_Linear(entity e, float dt, float phys_flags) { } float Phys_Advance(entity e, float target_time, float phys_flags) { - if (target_time < e.phys_time || e.is_removed) { + if (target_time < e.phys_time) { setorigin(e, e.origin); return 0; } if (phys_tic * vlen(e.velocity) > 32) - if (!fo_config.clown_settings) + if (!fo_config.clown_flags) error("phys_tic too big, needs adaptive scaling\n"); static float limit_eps = 0.0005; @@ -174,6 +172,11 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { float total = 0, dt = 0, step = 0, delta; while ((delta = target_time - e.phys_time) >= limit) { + if (e.voided) { + e.phys_time = target_time; + break; + } + switch (e.movetype) { case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: diff --git a/share/prediction.qc b/share/prediction.qc index 5f1860a1..29a5a64a 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -388,6 +388,10 @@ void EntUpdate_Config() { COMM(Byte, max_rewind_slow_projectile_ms); COMM(Byte, max_rewind_fast_projectile_ms); COMM(Byte, rewind_fast_projectile_thresh); + COMM(Byte, rewind_flags); + COMM(Byte, no_forward_hg); + COMM(Byte, clown_flags); + COMM(Float, clown_grav); COMM(Byte, wp_default_min_ping_ms); COMM(Byte, wp_global_enable); COMM(Byte, wp_global_disable); @@ -396,9 +400,6 @@ void EntUpdate_Config() { COMM(Byte, wpp_global_enable); COMM(Byte, wpp_global_disable); COMM(Byte, gren_beta_disable); - COMM(Byte, no_forward_hg); - COMM(Byte, clown_settings); - COMM(Float, clown_grav); #ifdef SSQC return TRUE; @@ -552,13 +553,14 @@ void WeapPred_InitDefaultConfig() { fo_config.qc_physics = 1; fo_config.static_newmis_ms = 50; fo_config.dynamic_newmis_ms = 0; + fo_config.rewind_flags = 0; fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 100; fo_config.max_rewind_fast_projectile_ms = 100; fo_config.rewind_fast_projectile_thresh = 1500; fo_config.wp_default_min_ping_ms = 40; fo_config.no_forward_hg = 1; - fo_config.clown_settings = 0; + fo_config.clown_flags = 0; fo_config.clown_grav = 400; } @@ -599,7 +601,8 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_disable); CONFIG_UPDATE("gbd", gren_beta_disable); CONFIG_UPDATE("nfhg", no_forward_hg); - CONFIG_UPDATE("clown", clown_settings); + CONFIG_UPDATE("rewind", rewind_flags); + CONFIG_UPDATE("clown", clown_flags); CONFIG_UPDATE("clown_grav", clown_grav); CLAMP_UPDATE(dynamic_newmis_ms, 0, fo_config.static_newmis_ms); diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 7ff56253..cd6dcdca 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -6,9 +6,19 @@ void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { float dt = Phys_Init(projectile, time, offset_dt, PHYSF_CONSUME_ALL); projectile.antilag_ms = dt * 1000; } + #define DEBUG_ANTILAG 0 -#ifndef DEBUG_ANTILAG +enumflags { + REWIND_KNOCKBACK, +}; + +float RewindFlagEnabled(float flag) { + return fo_config.rewind_flags & flag; +} + + +#if DEBUG_ANTILAG #define al_printf(...) printf(__VA_ARGS__) #define al_printd(...) dprint(__VA_ARGS__) #else @@ -17,7 +27,14 @@ void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { #endif #define AL_MAX_REWINDS 25 -#define AL_FRAME_LIMIT (1/77.0) + +inline int NextRewindIdx(int idx) { + return (idx + 1) % AL_MAX_REWINDS; +} + +inline int PrevRewindIdx(int idx) { + return (idx - 1 + AL_MAX_REWINDS) % AL_MAX_REWINDS; +} struct RewindSnapshot { float time; @@ -25,51 +42,47 @@ struct RewindSnapshot { vector velocity; }; +enum RewindStatus:float { + kPresent, + kRewound, +}; + struct RewindState { entity owner; RewindSnapshot snapshot[AL_MAX_REWINDS]; + int cur; - float rewound; - vector tmp_origin; - vector tmp_velocity; - RewindSnapshot* rewound_from; - - float cursor; - float cursor_limit; + RewindStatus rewound; + vector held_origin, held_velocity; - float allocated; RewindState* next; RewindState* prev; }; RewindState* rewind_players; -RewindState* AllocRewind(entity ent) { +static RewindState* AllocRewind(entity ent) { RewindState* state = memalloc(sizeof(RewindState)); - state.cursor = 0; - state.cursor_limit = time + AL_FRAME_LIMIT; + state.rewound = kPresent; state.owner = ent; return state; } -void FreeRewind(RewindState* h) { +static void FreeRewind(RewindState* h) { memfree(h); } - -void RL_Insert(RewindState** head, RewindState* node) { +static void RL_Insert(RewindState** head, RewindState* node) { if (!*head) { - node->next = node->prev = node; - *head = node; + node->next = node->prev = __NULL__; } else { node->next = *head; - node->prev = (*head)->prev; - - (node->next)->prev = (node->prev)->next = node; + (*head)->prev = node; } + *head = node; } -void RL_Remove(RewindState** head, RewindState* node) { +static void RL_Remove(RewindState** head, RewindState* node) { if (*head == node) { *head = __NULL__; } else { @@ -79,184 +92,126 @@ void RL_Remove(RewindState** head, RewindState* node) { } #define RL_FOR_EACH(_head, _var) \ - for (RewindState* _var = _head; _var;\ - _var = _var->next != head ? _var->next : __NULL__) - -RewindSnapshot* RewindLog(RewindState* target) { - if (target->owner != self) - error("Log mismatch\n"); - - if (time > target->cursor_limit) { - target->cursor = (target->cursor + 1) % AL_MAX_REWINDS; - target->cursor_limit = time + AL_FRAME_LIMIT; - } - - RewindSnapshot* snapshot = &target->snapshot[target->cursor]; - snapshot->time = time; - snapshot->origin = target->owner.origin; - snapshot->velocity = target->owner.velocity; - - return snapshot; -} + for (RewindState* _var = _head; _var; _var = _var->next) struct SeekResult { - RewindSnapshot *before; - RewindSnapshot *after; - RewindSnapshot *nearest; + RewindSnapshot* before; + RewindSnapshot* after; }; -inline float NextIndex(float pos) { return (pos + 1) % AL_MAX_REWINDS; } -inline float Index(float pos) { return (pos + AL_MAX_REWINDS) % AL_MAX_REWINDS; } -inline float PrevIndex(float pos) { return Index(pos - 1); } - -void DumpPos(RewindState* target, float pos) { - printd(" dump %d %0.2f\n", Index(pos), target->snapshot[Index(pos)].time); -} - -SeekResult SeekBasic(RewindState* target, float when) { +static SeekResult RewindSeek(RewindState* rstate, float rtime) { SeekResult r; - float before = 0, after = time, nearest = when + 1; - r.before = r.after = r.nearest = __NULL__; + r.before = r.after = __NULL__; + + int idx = rstate->cur; for (int i = 0; i < AL_MAX_REWINDS; i++) { - RewindSnapshot* s = &target->snapshot[i]; + RewindSnapshot* rs = &rstate->snapshot[idx]; - if (s->time && s->time > when && s->time < after) { - after = s->time; - r.after = s; - } - if (s->time && s->time < when && s->time > before) { - before = s->time; - r.before = s; + if (rs->time > rtime) { + r.after = rs; + } else { + if (rs->time) + r.before = rs; + break; } - } - if (fabs(when - before) < fabs(when - after)) - r.nearest = r.before; - else - r.nearest = r.after; + idx = PrevRewindIdx(idx); + } return r; } -#if 0 -void CompareSeek(SeekResult s1, SeekResult, s2) { - if (before != (r.before)->time) - errorf("before mismatch w=%f seek=%f check=%f\n", - when, (r.before)->time, before); - if (after != (r.after)->time) - errorf("after mismatch w=%f seek=%f check=%f\n", - when, (r.after)->time, after); - if (nearest != (r.nearest)->time) - errorf("nearest mismatch w=%f seek=%f check=%f\n", - when, (r.nearest)->time, nearest); -} - +RewindSnapshot* RewindLog(RewindState* target) { + if (target->owner != self) + error("Log mismatch\n"); -SeekResult SeekOpt(RewindState* target, float when) { - SeekResult r; - r.before = r.after = r.nearest = __NULL__; + RewindSnapshot* rs = &target->snapshot[target->cur]; + if (rs->time && rs->time > time + 0.001) { + target->cur = NextRewindIdx(target->cur); + rs = &target->snapshot[target->cur]; + } - float probe = floor((time - when) / AL_FRAME_LIMIT); - probe = max(probe - 3, 0); - printd(" probe = %d -> %d, %d\n", - probe, target->cursor, Index(target->cursor - probe)); + rs->time = time; + rs->origin = target->owner.origin; + rs->velocity = target->owner.velocity; - if (probe > AL_MAX_REWINDS || probe < 0) - return r; + return rs; +} - probe = 0; // Conservative/safe for now. - float tmp = Index(target->cursor - probe); - printd(" t = %d c = %f\n", tmp, target->cursor); - while (target->snapshot[tmp].time > when) { - RewindSnapshot* snap = &target->snapshot[tmp]; +static void RewindSave(RewindState* rs) { + rs->rewound = kRewound; + entity e = rs->owner; - r.after = &target->snapshot[tmp]; - printd(" %d >when %0.2f\n", tmp, (r.after)->time); - tmp = PrevIndex(tmp); - } - printd(" %d middle %0.2f\n", tmp, target->snapshot[tmp].time); + if (e.health <= 0) + return; + rs->held_origin = e.origin; + rs->held_velocity = e.velocity; +} - if (target->snapshot[tmp].time > 0) { - r.before = &target->snapshot[tmp]; - printd(" %d time); - } +static void RewindRestore(RewindState* rs, float type) { + ASSERTD_EQ(rs->rewound, kRewound); - DumpPos(target, tmp - 1); - DumpPos(target, tmp); - DumpPos(target, tmp + 1); + rs->rewound = type; + entity e = rs->owner; - r.nearest = r.after; - if (r.before && fabs((r.before)->time - when) < fabs((r.after)->time - when)) - r.nearest = r.before; - tmp = NextIndex(tmp); + if (e.health <= 0) + return; - SeekCheck(target, when, &r); - return r; + setorigin(e, rs->held_origin); + // We restore origin, but preserve changes to velocity. } -#endif -SeekResult Seek(RewindState* target, float when) { - SeekResult r; - r.before = r.after = r.nearest = __NULL__; +static void RL_StashPositions(RewindState* head) { + RL_FOR_EACH(head, rs) + RewindSave(rs); +} - return SeekBasic(target, when); +static void RL_RestorePositions(RewindState* head) { + RL_FOR_EACH(head, rs) + RewindRestore(rs, kPresent); } -// TODO: Filter out observers, but no harm immediately. -void RL_Rewind(RewindState* head, entity exclude, float when) { - float show_rewind_points = CF_GetSetting("rds", "rewind_debug_show", "off"); - - printd("REWIND START %p\n", head); - RL_FOR_EACH(head, rs) { - if (rs->owner == exclude || - when < rs->owner->spawn_time) { // Don't rewind to past life. - rs->rewound = 2; - printd("rewind skipped %s\n", exclude.netname); - continue; - } +static void RewindTo(RewindState* rstate, float rtime) { + ASSERTD_EQ(rstate->rewound, kRewound); - printd("start %s, %f -> %f %d\n", rs->owner.netname, time, when, - (time - when) / AL_FRAME_LIMIT); - SeekResult seek = Seek(rs, when); - RewindSnapshot* near = seek.nearest; - if (near) { - printd("trying to rewind %s to %f, found %f\n", rs->owner.netname, - when, near->time); - if (rs->rewound == 1) - error("ALREADY REWOUND"); - - rs->rewound = TRUE; - rs->tmp_origin = rs->owner.origin; - rs->tmp_velocity = rs->owner.velocity; - rs->owner.origin = near->origin; - rs->owner.velocity = near->velocity; - rs->rewound_from = near; - - if (show_rewind_points) - pointparticles(particleeffectnum("fo_airblast"), near->origin); - } + rtime = max(rtime, rstate->owner->spawn_time); + + SeekResult sr = RewindSeek(rstate, rtime); + RewindSnapshot* a = sr.after; + RewindSnapshot* b = sr.before; + + vector pos = a.origin; + if (b) { + float frac = (rtime - b->time) / (a->time - b->time); + vector diff = a->origin - b->origin; + + if (vlen(diff) > 48) + frac = 1; // Most likely teleport. + + pos = b->origin + frac * diff; } - printd("REWIND END\n"); + + setorigin(rstate->owner, pos); } -void RL_RestorePresent(RewindState* head) { - RL_FOR_EACH(head, rs) { - if (rs->rewound == 1) { - printd("restoring %s\n", rs->owner.netname); +// TODO: Filter out observers, but no harm immediately. +static void RL_RewindTo(RewindState* head, entity exclude, float rtime) { + float show_rewind_points = + CF_GetSetting("rds", "rewind_debug_show", DEBUG_ANTILAG ? "on" : "off"); - rs->owner.origin = rs->tmp_origin; - rs->owner.velocity = rs->tmp_velocity; - } else { - printd("restore skipped %s\n", rs->owner.netname); - } + RL_FOR_EACH(head, rstate) { + entity e = rstate->owner; + if (e == exclude || rtime < e->spawn_time) + continue; - rs->rewound = FALSE; - rs->rewound_from = __NULL__; + RewindTo(rstate, rtime); + + if (show_rewind_points) + pointparticles(particleeffectnum("fo_airblast"), e->origin); } } - class FOPlayer { RewindState* rewind_; @@ -267,11 +222,10 @@ class FOPlayer { virtual void() Destroy = { RL_Remove(&rewind_players, rewind_); - + FreeRewind(rewind_); }; nonvirtual void() Respawn = { - }; nonvirtual void() RewindUpdate = { @@ -279,28 +233,22 @@ class FOPlayer { }; void(float when) RewindExcept = { - RL_Rewind(rewind_players, this, when); + RL_StashPositions(rewind_players); + RL_RewindTo(rewind_players, this, when); }; static void (float when) RewindAll = { - RL_Rewind(rewind_players, world, when); + RL_StashPositions(rewind_players); + RL_RewindTo(rewind_players, world, when); }; static void() RestoreAll { - RL_RestorePresent(rewind_players); + RL_RestorePositions(rewind_players); }; - void() RestoreNow = { - if (rewind_->rewound == 1) { - this.origin = rewind_->tmp_origin; - this.velocity = rewind_->tmp_velocity; - rewind_->rewound = 2; - } - }; - - vector() TrueOrigin = { - if (rewind_->rewound == 1) { - return rewind_->tmp_origin; + vector() UnrewoundOrigin = { + if (rewind_->rewound == kRewound) { + return rewind_->held_origin; } else { return this->origin; } @@ -313,7 +261,7 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { if (!antilag_settings.rewind_detpipe) return FALSE; - float rewind_max_offset = ((AL_MAX_REWINDS - 1)* AL_FRAME_LIMIT); + float rewind_max_offset = (AL_MAX_REWINDS - 1) * SERVER_FRAME_DT; farthest_rewind_point = max(farthest_rewind_point, time - rewind_max_offset); @@ -321,7 +269,7 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { float rewind_to = max(farthest_rewind_point, remote_time()); // Ignore for LAN pings. - if (time - rewind_to < 0.013) + if (time - rewind_to < SERVER_FRAME_DT) return FALSE; FOPlayer fop = (FOPlayer)self; @@ -329,8 +277,4 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { return TRUE; } -void UnrewindPlayer(entity p) { - FOPlayer fop = (FOPlayer)p; - fop.RestoreNow(); -} diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 8969a187..1a8558ea 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -760,7 +760,10 @@ void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, FOPlayer fc = (FOPlayer)c; org[0] = c.origin + (c.mins + c.maxs) * 0.5; - org[1] = fc.TrueOrigin() + (c.mins + c.maxs) * 0.5; + if (RewindFlagEnabled(REWIND_KNOCKBACK)) + org[1] = org[0]; + else + org[1] = fc.UnrewoundOrigin() + (c.mins + c.maxs) * 0.5; for (int j = 0; j < 2; j++) { float points = 0.5 * vlen(inflictor.origin - org[j]); @@ -772,12 +775,17 @@ void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, dmg[j] = points; } - fc.RestoreNow(); // Use current location for knockback, etc. - dmg[1] = min(dmg[0], dmg[1]); // Limit Kerbal. + vector held_pos = c.origin; + if (!RewindFlagEnabled(REWIND_KNOCKBACK)) { + c.origin = fc.UnrewoundOrigin(); + dmg[1] = min(dmg[0], dmg[1]); // Limit Kerbal. + } if (dmg[0] > 0) TF_T_DamageKnock(c, inflictor, attacker, dmg[0], dmg[1], TF_TD_NOTTEAM, TF_TD_EXPLOSION); + + c.origin = held_pos; } } diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 66a6410a..700e8da4 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -340,7 +340,6 @@ void () SUB_Null; void (entity et, float f) SUB_Null_pain; void () SUB_UseTargets; void () SUB_Remove; -void (entity ent) RemoveDeferred; // // combat.qc diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 7c48ea4a..cfa1adaa 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -40,7 +40,7 @@ float (float force) TeamFortress_DetonatePipebombs = { pipes[i].voided = 1; RenderExplosion(pipes[i].origin); - RemoveDeferred(pipes[i]); + dremove(pipes[i]); } } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9fc5abf3..bde815a5 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -13,6 +13,8 @@ struct antilag_settings_t { float rewind_detpipe; } antilag_settings; +.vector antilag_origin; + .float client_time; // A stable/predictable client clock .float client_ping; // ping used for prediction .float last_remote_client_time; // For monoticity diff --git a/ssqc/subs.qc b/ssqc/subs.qc index 1d64b39e..d0bae51a 100644 --- a/ssqc/subs.qc +++ b/ssqc/subs.qc @@ -27,12 +27,6 @@ void () SUB_Remove = { dremove(self); }; - -void RemoveDeferred(entity e) { - e.nextthink = time; - e.think = SUB_Remove; -} - void () SetMovedir = { if (self.angles == '0 -1 0') self.movedir = '0 0 1'; From 7bffd91456cb4a0f29777aa812391fca35da3587 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 22 Nov 2022 16:24:30 -0800 Subject: [PATCH 1883/2474] Rewind Projectiles Implement 2 forms of rewind support for projectiles: 1) Rewind collision detection, when forwarding the projectile through time, use actual prior player positions, rather than teleporting in the present. 2) When rockets teleport (because antilag), the timing between the player firing and the explosion occurring relative to their movement is variable. Resolve this by delaying the self knockback calculation to account for relative movement. These are flag controlled and currently disabled by default. --- csqc/weapon_predict.qc | 3 +- share/physics.qc | 52 +++++++++++++++++------------ share/prediction.qc | 3 -- ssqc/antilag.qc | 76 ++++++++++++++++++++++++++++++++++++------ ssqc/combat.qc | 58 +++++++++++++++++--------------- ssqc/pyro.qc | 10 +++++- ssqc/weapons.qc | 47 +++++++++++++++++++++++--- 7 files changed, 181 insertions(+), 68 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2ea9c204..bfb14f00 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -170,7 +170,8 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); - static string rewind_desc[] = { "rewind knockback" }; + static string rewind_desc[] = { "rewind pipe knockback", "rewind proj hit", + "sync proj self knockback" }; printf("Rewind Settings:\n"); if (fo_config.rewind_flags) { for (float i = 0; i < rewind_desc.length; i++) diff --git a/share/physics.qc b/share/physics.qc index 2c320228..47ac6126 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -10,8 +10,12 @@ enumflags { enumflags { PHYSF_CONSUME_ALL, + PHYSF_REWIND_PLAYERS, + PHYSF_FORWARD_KNOCK, }; +const float FL_FORWARD_KNOCK = FL_GODMODE; + static inline float PhysFlagEnabled(float flag) { return fo_config.qc_physics & flag; } @@ -24,6 +28,9 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { return; if (e.touch) { + if (phys_flags & PHYSF_FORWARD_KNOCK) + e.flags |= FL_FORWARD_KNOCK; + entity held_self = self; self = e; other = trace_ent; @@ -123,7 +130,7 @@ float Phys_Adv_Bounce(entity e, float dt, float phys_flags) { e.angles += move_time * e.avelocity; float bounce_stop = 60 / 800 * g; - float debounce = !IsClownMode(CLOWN_RUBBERGREN) ? 1.5 : 2.5; + float debounce = !IsClownMode(CLOWN_RUBBERGREN) ? 1.5 : 2; e.velocity = Phys_ClipVel(e.velocity, trace_plane_normal, debounce); if (PHYS_DEBUG) @@ -157,16 +164,25 @@ float Phys_Adv_Linear(entity e, float dt, float phys_flags) { return dt; } +var void(entity e) RewindSyncTime; + +static void Phys_CapVel(entity e) { + static const float limit = 32 / phys_tic; + + if (vlen(e.velocity) > limit) { + if (!fo_config.clown_flags) + printf("%s v=%d too fast, consider adaptive scaling\n", + e.model, vlen(e.velocity)); + e.velocity = normalize(e.velocity) * limit; + } +} + float Phys_Advance(entity e, float target_time, float phys_flags) { if (target_time < e.phys_time) { setorigin(e, e.origin); return 0; } - if (phys_tic * vlen(e.velocity) > 32) - if (!fo_config.clown_flags) - error("phys_tic too big, needs adaptive scaling\n"); - static float limit_eps = 0.0005; float limit = (phys_flags & PHYSF_CONSUME_ALL) ? limit_eps : phys_tic; float total = 0, dt = 0, step = 0, delta; @@ -177,35 +193,27 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { break; } + if (phys_flags & PHYSF_REWIND_PLAYERS) + RewindSyncTime(e); + step = min(phys_tic, delta); + + if (IsClownMode(CLOWN_PROJ_GRAVITY)) + e.velocity_z += -fo_config.clown_grav * step; + Phys_CapVel(e); + switch (e.movetype) { case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: - // Linear projectiles we can always simulate in a single step. - if (limit > limit_eps) - step = floor(delta / limit) * limit; - else - step = delta; - - // Unless there's.... gravity - if (IsClownMode(CLOWN_PROJ_GRAVITY)) { - step = min(phys_tic, delta); - e.velocity_z += -fo_config.clown_grav * step; - } - dt = Phys_Adv_Linear(e, step, phys_flags); break; case MOVETYPE_BOUNCE: - step = min(phys_tic, delta); dt = Phys_Adv_Bounce(e, step, phys_flags); break; - case MOVETYPE_NONE: - step = dt = delta; - break; - default: printf("ERROR: %s unsupported movetype %d\n", e.model, e.movetype); + case MOVETYPE_NONE: step = dt = delta; break; } diff --git a/share/prediction.qc b/share/prediction.qc index 29a5a64a..f3762b17 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -9,10 +9,8 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; // Below apply to both CSQC & SSQC ents .float fpp_index; // Projectile type .float antilag_ms; -#ifdef CSQC .vector s_origin; .float s_time; -#endif string wp_version = "v0.4-phys"; @@ -773,7 +771,6 @@ void FOProj_Finalize(entity mis) { // We always need to init some of the state here (e.g. phys_time) as we // always use the physics code client-side. - mis.phys_time = time; if (fo_config.qc_physics) mis.customphysics = FO_Phys; diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index cd6dcdca..6b5ccf4b 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -1,23 +1,15 @@ -void WeaponPred_ProjectProjectile(int fpp_type, entity projectile) { - float ping = projectile.owner.client_ping; - ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); - float offset_dt = (offset.static_ms + offset.dynamic_ms) / 1000.0; - - float dt = Phys_Init(projectile, time, offset_dt, PHYSF_CONSUME_ALL); - projectile.antilag_ms = dt * 1000; -} - #define DEBUG_ANTILAG 0 enumflags { REWIND_KNOCKBACK, + REWIND_PROJ_HIT, + REWIND_PROJ_SELFKNOCK, }; float RewindFlagEnabled(float flag) { return fo_config.rewind_flags & flag; } - #if DEBUG_ANTILAG #define al_printf(...) printf(__VA_ARGS__) #define al_printd(...) dprint(__VA_ARGS__) @@ -175,6 +167,9 @@ static void RL_RestorePositions(RewindState* head) { static void RewindTo(RewindState* rstate, float rtime) { ASSERTD_EQ(rstate->rewound, kRewound); + if (rstate->owner.health <= 0) + return; + rtime = max(rtime, rstate->owner->spawn_time); SeekResult sr = RewindSeek(rstate, rtime); @@ -277,4 +272,65 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { return TRUE; } +void ProjRewind(entity e) { + RL_RewindTo(rewind_players, e.owner, e.phys_time); +} + +void WeaponPred_ProjectProjectileRewind(int fpp_type, entity proj) { + float ping = proj.owner.client_ping; + + ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); + float static_dt = offset.static_ms / 1000.0; + float dynamic_dt = offset.dynamic_ms / 1000.0; + float stime = time - dynamic_dt; + + float rewind_hit = RewindFlagEnabled(REWIND_PROJ_HIT); + float phys_flags = PHYSF_CONSUME_ALL; + if (rewind_hit) { + phys_flags |= PHYSF_REWIND_PLAYERS; + RL_StashPositions(rewind_players); + RL_RewindTo(rewind_players, proj.owner, stime); + } + + if (RewindFlagEnabled(REWIND_PROJ_SELFKNOCK)) + phys_flags |= PHYSF_FORWARD_KNOCK; + + // Static projection happens instantly. If rewind is active, we'll do it at + // the rewound point in time, but we don't advance time while stepping + // through it. + proj.s_origin = proj.origin; + proj.s_time = 0; + Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); + + // We initialize s_origin/s_time after Phys_Init, they are used when + // knockback forwarding is on to determine delay. + proj.s_origin = proj.origin; + proj.s_time = time; + + float dt = 0; + if (!proj.voided) { + RewindSyncTime = ProjRewind; + dt = Phys_Advance(proj, time, phys_flags); + } + + if (rewind_hit) + RL_RestorePositions(rewind_players); + + proj.antilag_ms = dt * 1000; +} + +void WeaponPred_ProjectProjectile(int fpp_type, entity proj) { + if (RewindFlagEnabled(REWIND_PROJ_HIT | REWIND_PROJ_SELFKNOCK)) { + WeaponPred_ProjectProjectileRewind(fpp_type, proj); + return; + } + + proj.s_origin = proj.origin; + float ping = proj.owner.client_ping; + ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); + float offset_dt = (offset.static_ms + offset.dynamic_ms) / 1000.0; + + float dt = Phys_Init(proj, time, offset_dt, PHYSF_CONSUME_ALL); + proj.antilag_ms = dt * 1000; +} diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 1a8558ea..305a1fa6 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -703,39 +703,43 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, } void (entity inflictor, entity attacker, float damage, - entity ignore) T_RadiusDamage = { + entity ignore1, entity ignore2 = __NULL__, entity only = __NULL__) + T_RadiusDamage = { local float points; local entity head; local vector org; - head = findradius(inflictor.origin, damage + 40); - while (head) { - if (head != ignore) { - if (head.takedamage) { - - org = head.origin + (head.mins + head.maxs) * 0.5; - points = 0.5 * vlen(inflictor.origin - org); - if (points < 0) - points = 0; - points = damage - points; - if (head == attacker) - points = points * 0.75; - - if (points > 0) { - if (CanDamage(head, inflictor)) { - // shambler takes half damage from all explosions - if (head.classname == "monster_shambler") - T_Damage(head, inflictor, attacker, - points * 0.5); - else - TF_T_DamageKnock(head, inflictor, attacker, points, - points, - TF_TD_NOTTEAM, TF_TD_EXPLOSION); - } - } + int count, i; + entity* rlist = findradius_list(inflictor.origin, damage + 40, count); + + for (i = 0; i < count; i ++) { + entity e = rlist[i]; + if ((only && e != only) || e == ignore1 || e == ignore2) + continue; + + if (!e.takedamage) + continue; + + org = e.origin + (e.mins + e.maxs) * 0.5; + points = 0.5 * vlen(inflictor.origin - org); + if (points < 0) + points = 0; + points = damage - points; + if (e == attacker) + points = points * 0.75; + + if (points > 0) { + if (CanDamage(e, inflictor)) { + // shambler takes half damage from all explosions + if (e.classname == "monster_shambler") + T_Damage(e, inflictor, attacker, + points * 0.5); + else + TF_T_DamageKnock(e, inflictor, attacker, points, + points, + TF_TD_NOTTEAM, TF_TD_EXPLOSION); } } - head = head.chain; } }; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 214bb9d5..2f4437ef 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -611,7 +611,10 @@ void () IncendiaryRadius_OZTF = { else damg = 92; deathmsg = 15; - T_RadiusDamage(self, self.owner, damg, other); + + entity ignore_self = AntilagKnock(self, damg) ? self.owner : __NULL__; + T_RadiusDamage(self, self.owner, damg, other, ignore_self); + self.origin = (self.origin - (8 * normalize (self.velocity))); WriteByte(4, 23); WriteByte(4, 3); @@ -628,6 +631,11 @@ void () T_IncendiaryTouch = { if (other == self.owner) { return; } + + if (self.voided) + return; + self.voided = 1; + if (pointcontents(self.origin) == CONTENT_SKY) { remove(self); return; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index a4c57b88..13f61edd 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1039,6 +1039,46 @@ void () BecomeExplosion = { dremove(self); }; +.float al_dmg; + +static void Antilag_Knock(entity e) { + T_RadiusDamage(e, e.owner, e.al_dmg, __NULL__, __NULL__, e.owner); + dremove(e); +} + +void T_Knock_Antilag() { + Antilag_Knock(self); +} + +float AntilagKnock(entity e, float dmg) { + if (!RewindFlagEnabled(REWIND_PROJ_SELFKNOCK) || e.s_time == 0) + return FALSE; + + entity knock_e = spawn(); + + setorigin(knock_e, e.origin); + knock_e.s_origin = e.s_origin; + knock_e.owner = e.owner; + knock_e.classname = e.classname; + knock_e.oldenemy = other; + knock_e.al_dmg = dmg; + + vector diff = e.origin - e.s_origin; + float ttime = vlen(diff) / vlen(e.velocity); + float dtime = time - e.s_time; + + float delay = ttime - dtime; + + if (delay > SERVER_FRAME_DT && dtime < 0.25) { + knock_e.think = T_Knock_Antilag; + knock_e.nextthink = time + delay; + } else { + Antilag_Knock(knock_e); + } + + return TRUE; +} + void () T_MissileTouch = { local float damg; @@ -1058,10 +1098,9 @@ void () T_MissileTouch = { TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_OTHER); - if (self.owner.classname == "building_sentrygun") - T_RadiusDamage(self, self.owner, 150, other); - else - T_RadiusDamage(self, self.owner, 92, other); + float dmg = (self.owner.classname == "building_sentrygun") ? 150 : 92; + entity ignore_self = AntilagKnock(self, dmg) ? self.owner : __NULL__; + T_RadiusDamage(self, self.owner, dmg, other, ignore_self); self.origin = self.origin - 8 * normalize(self.velocity); From 14dcdc642b62cf7e30cb4873ca060cfe349d09d9 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 23 Nov 2022 16:38:20 -0800 Subject: [PATCH 1884/2474] Improve projectile trails QW has a (normally) nice optimization where entities which are created and destroyed on the same frame don't send any data to the client. However, with things like antilag projection on rockets, this can mean that we get explosions with no trails, since bandwidth is cheap (especially since the new netcode uses much less than the old), make sure we always send the entity to generate a trail from. Also ensure trail rendering is more consistent around starting 50ms out. --- csqc/weapon_predict.qc | 10 ++++++++-- share/commondefs.qc | 7 +++++++ share/prediction.qc | 8 +------- ssqc/antilag.qc | 12 +++++++----- ssqc/debug.qc | 10 ++++++++++ ssqc/hwguy.qc | 13 ++++++------- ssqc/pyro.qc | 6 +++--- ssqc/spy.qc | 4 ++-- ssqc/weapons.qc | 36 +++++++++++++++++------------------- 9 files changed, 61 insertions(+), 45 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index bfb14f00..c828ce2f 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -899,8 +899,13 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.angles = input_angles; proj.angles[0] *= -1; proj.s_origin = proj.origin; - Phys_Init(proj, proj.starttime, static_dt, PHYSF_CONSUME_ALL); + + // Trail starts at 0.05, we, split physics calcs longer than this. + float sdt2 = max(static_dt - 0.05, 0) + Phys_Init(proj, proj.starttime - sdt2, static_dt - sdt2, PHYSF_CONSUME_ALL); proj.oldorigin = proj.origin; + if (sdt2 > 0) + Phys_Advance(proj, sdt2, PHYSF_CONSUME_ALL); proj.pred_next = predicted_projectiles; if (predicted_projectiles) @@ -1183,7 +1188,8 @@ void InitProjectileEnt(float sendflags) { if (!has_predicted) { // Back-track trail for entities without a local prediction. We use // s_origin here as that's what we know antilag_ms to be relative to. - self.oldorigin = self.s_origin - self.antilag_ms/1000.0 * self.velocity; + float trail_ms = (self.antilag_ms - 50) / 1000.0; + self.oldorigin = self.s_origin - trail_ms * self.velocity; } } diff --git a/share/commondefs.qc b/share/commondefs.qc index d4955f69..78c0c48f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -30,6 +30,13 @@ inline float IsClownMode(int flag) { return fo_config.clown_flags & flag; } +const float SERVER_FPS = 77; +const float SERVER_FRAME_DT = 1/SERVER_FPS; +const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; + +.vector s_origin; +.float s_time; + #define MAX_FLAGINFO_LINES 10 #define ENG_BUILDING_DISMANTLE_DISTANCE 100 #define ENG_BUILDING_MAINT_DISTANCE 80 diff --git a/share/prediction.qc b/share/prediction.qc index f3762b17..b4cbddef 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -2,15 +2,9 @@ #define ENT_WEAPONPRED 101 #define ENT_PROJECTILE 102 -const float SERVER_FPS = 77; -const float SERVER_FRAME_DT = 1/SERVER_FPS; -const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; - // Below apply to both CSQC & SSQC ents .float fpp_index; // Projectile type .float antilag_ms; -.vector s_origin; -.float s_time; string wp_version = "v0.4-phys"; @@ -503,7 +497,7 @@ void EntUpdate_Projectile(float isnew) { #endif if (sendflags & FOPP_INIT) { COMM(Byte, fpp_index); - COMM(Byte, antilag_ms); + COMM(Short, antilag_ms); COMMD(Entity, owner_entnum, owner); } diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 6b5ccf4b..36748165 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -299,8 +299,8 @@ void WeaponPred_ProjectProjectileRewind(int fpp_type, entity proj) { // the rewound point in time, but we don't advance time while stepping // through it. proj.s_origin = proj.origin; - proj.s_time = 0; - Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); + proj.s_time = time; + float st = Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); // We initialize s_origin/s_time after Phys_Init, they are used when // knockback forwarding is on to determine delay. @@ -316,7 +316,7 @@ void WeaponPred_ProjectProjectileRewind(int fpp_type, entity proj) { if (rewind_hit) RL_RestorePositions(rewind_players); - proj.antilag_ms = dt * 1000; + proj.antilag_ms = (st + dt) * 1000; } void WeaponPred_ProjectProjectile(int fpp_type, entity proj) { @@ -326,11 +326,13 @@ void WeaponPred_ProjectProjectile(int fpp_type, entity proj) { } proj.s_origin = proj.origin; + proj.s_time = time; float ping = proj.owner.client_ping; ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); - float offset_dt = (offset.static_ms + offset.dynamic_ms) / 1000.0; + float static_dt = offset.static_ms / 1000.0; + float dynamic_dt = offset.dynamic_ms / 1000.0; - float dt = Phys_Init(proj, time, offset_dt, PHYSF_CONSUME_ALL); + float dt = Phys_Init(proj, time, static_dt + dynamic_dt, PHYSF_CONSUME_ALL); proj.antilag_ms = dt * 1000; } diff --git a/ssqc/debug.qc b/ssqc/debug.qc index 2c6ff206..b9a49367 100644 --- a/ssqc/debug.qc +++ b/ssqc/debug.qc @@ -16,6 +16,16 @@ void (entity te) dremove = remove(te); }; +void dremove_sent(entity te) { + static const float epsilon = SERVER_FRAME_DT; + if (time > te.s_time + epsilon) { + dremove(self); + } else { + self.nextthink = time + 2 * epsilon; + self.think = SUB_Remove; + } +} + void () display_location = { local string st; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index d37780b4..6b4ada11 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -12,18 +12,17 @@ void AssCanBulletThink () void AssCanBulletTouch() { - if (self.voided) - return; // Marked for removal - + if (self.voided) + return; // Marked for removal self.voided = TRUE; - if (pointcontents(self.origin) == CONTENT_SKY) { + if (pointcontents(self.origin) == CONTENT_SKY) { dremove(self); return; } - if (other == self.owner) - return; // Touching self, do nothing + if (other == self.owner) + return; // Touching self, do nothing deathmsg = self.weapon; if (other.health) @@ -49,7 +48,7 @@ void AssCanBulletTouch() multicast(self.origin, MULTICAST_PVS); } - dremove(self); + dremove_sent(self); }; void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 2f4437ef..75188c09 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -601,7 +601,7 @@ void () IncendiaryRadius = { WriteCoord(MSG_MULTICAST, self.origin_y); WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); - dremove(self); + dremove_sent(self); }; void () IncendiaryRadius_OZTF = { @@ -622,7 +622,7 @@ void () IncendiaryRadius_OZTF = { WriteCoord(4, self.origin_y); WriteCoord(4, self.origin_z); multicast(self.origin, 1); - dremove(self); + dremove_sent(self); }; void () T_IncendiaryTouch = { @@ -637,7 +637,7 @@ void () T_IncendiaryTouch = { self.voided = 1; if (pointcontents(self.origin) == CONTENT_SKY) { - remove(self); + dremove_sent(self); return; } self.effects = self.effects | 4; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 9a93972a..a7072d3d 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1101,7 +1101,7 @@ void () T_TranqDartTouch = { return; if (pointcontents(self.origin) == CONTENT_SKY) { - dremove(self); + dremove_sent(self); return; } if (other.takedamage) { @@ -1151,7 +1151,7 @@ void () T_TranqDartTouch = { WriteCoord(4, self.origin_z); multicast(self.origin, 2); } - dremove(self); + dremove_sent(self); }; void () TranquiliserTimer = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 13f61edd..39278317 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1087,7 +1087,7 @@ void () T_MissileTouch = { self.voided = 1; if (pointcontents(self.origin) == CONTENT_SKY) { - dremove(self); + dremove_sent(self); return; } damg = 92 + random() * 20; @@ -1111,7 +1111,7 @@ void () T_MissileTouch = { WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); - dremove(self); + dremove_sent(self); }; void () W_FireRocket = { @@ -1465,7 +1465,7 @@ void () spike_touch = { return; if (pointcontents(self.origin) == CONTENT_SKY) { - dremove(self); + dremove_sent(self); return; } if (other.takedamage) { @@ -1478,9 +1478,8 @@ void () spike_touch = { TF_T_Damage(other, self, self.owner, ng_damage, TF_TD_NOTTEAM, TF_TD_NAIL); } - - dremove(self); - + + dremove_sent(self); } else { WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); if (self.classname == "wizspike") @@ -1493,17 +1492,16 @@ void () spike_touch = { WriteCoord(MSG_MULTICAST, self.origin_y); WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); - - if(other.classname == "worldspawn" && spurs_enabled > 0) - { - if(self.owner.playerclass == PC_SCOUT && spurs_scout == 1 || self.owner.playerclass == PC_SPY && spurs_spy == 1) - { - ConvertToSpurs(self); - return; - } - } - - dremove(self); + + if(other.classname == "worldspawn" && spurs_enabled > 0) { + if(self.owner.playerclass == PC_SCOUT && spurs_scout == 1 || + self.owner.playerclass == PC_SPY && spurs_spy == 1) { + ConvertToSpurs(self); + return; + } + } + + dremove_sent(self); } }; @@ -1521,7 +1519,7 @@ void () superspike_touch = { return; if (pointcontents(self.origin) == CONTENT_SKY) { - dremove(self); + dremove_sent(self); return; } if (other.takedamage) { @@ -1548,7 +1546,7 @@ void () superspike_touch = { WriteCoord(MSG_MULTICAST, self.origin_z); multicast(self.origin, MULTICAST_PHS); } - dremove(self); + dremove_sent(self); }; void W_UpdateWeaponModel(entity pl) { From 6b5469ffea011c8faf81ac6e75e06d2b7b62c649 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 23 Nov 2022 19:18:33 -0800 Subject: [PATCH 1885/2474] Customize Pyro Projectiles Adds r_pyrotrail (which allows the trail for incendiary rockets) and cl_p2r (which uses rocket models instead of lavaballs for incendiary rockets when set). --- csqc/weapon_predict.qc | 40 ++++++++++++++++++++++------------------ share/prediction.qc | 2 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c828ce2f..ee5dba6a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -764,26 +764,26 @@ void PP_Cleanup(entity proj) { remove(proj); } -DEFCVAR_FLOAT(r_rockettrail, 1); -DEFCVAR_FLOAT(r_grenadetrail, 1); +DEFCVAR_FLOAT(r_pyrotrail, 0); +DEFCVAR_FLOAT(r_rockettrail, 0); +DEFCVAR_FLOAT(r_grenadetrail, 0); -int FPP_FindTrail(entity e) -{ - float is_rocket = e.fpp_index == FPP_ROCKET; - float is_grenade = e.fpp_index == FPP_GRENADE; // Do not use IsGrenade - // here. This only applies - // to FPP_GRENADE. +int FPP_FindTrail(entity e) { + int idx = -1; int is_g = 0; - if (is_rocket || is_grenade) { - float idx = is_grenade ? CVARF(r_grenadetrail) : CVARF(r_rockettrail) - 1; - - if (idx >= 0 && idx < trail_table.length) - return trail_table[idx].trail[is_grenade]; + switch (e.fpp_index) { + case FPP_ROCKET: idx = CVARF(r_rockettrail) - 1; break; + case FPP_INCENDIARY: idx = CVARF(r_pyrotrail) - 1; break; + case FPP_GRENADE: idx = CVARF(r_grenadetrail) - 1; is_g = 1; break; } + if (idx >= 0 && idx < trail_table.length) + return trail_table[idx].trail[is_g]; + return fpp_types[e.fpp_index].trailindex; } +DEFCVAR_FLOAT(cl_p2r, 0); DEFCVAR_FLOAT(cl_r2g, 0); void FPP_Init(int fpp_type, entity proj) { @@ -791,10 +791,14 @@ void FPP_Init(int fpp_type, entity proj) { proj.fpp_index = fpp_type; - if (fpp_type == FPP_ROCKET && CVARF(cl_r2g) == 1) - setmodelindex(proj, fpp_types[FPP_GRENADE].modelindex); - else - setmodelindex(proj, desc->modelindex); + int render_type = fpp_type; + // If someone sets both p2r and r2g, we'll convert all the way. + if (render_type == FPP_INCENDIARY && CVARF(cl_p2r) == 1) + render_type = FPP_ROCKET; + if (render_type == FPP_ROCKET && CVARF(cl_r2g) == 1) + render_type = FPP_GRENADE; + + setmodelindex(proj, fpp_types[render_type].modelindex); proj.traileffectnum = FPP_FindTrail(proj); proj.movetype = desc->movetype; @@ -901,7 +905,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.s_origin = proj.origin; // Trail starts at 0.05, we, split physics calcs longer than this. - float sdt2 = max(static_dt - 0.05, 0) + float sdt2 = max(static_dt - 0.05, 0); Phys_Init(proj, proj.starttime - sdt2, static_dt - sdt2, PHYSF_CONSUME_ALL); proj.oldorigin = proj.origin; if (sdt2 > 0) diff --git a/share/prediction.qc b/share/prediction.qc index b4cbddef..dfadfddb 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -139,7 +139,7 @@ struct fo_projectile { fo_projectile fpp_types[] = { { FPP_ROCKET, MOVETYPE_FLYMISSILE, PC_SOLDIER_ROCKET_SPEED, - "missile.mdl", "", SND_RL, TRUE }, + "missile.mdl", "t_rocket", SND_RL, TRUE }, { FPP_GRENADE, MOVETYPE_BOUNCE, 600, "grenade2.mdl", "t_grenade", SND_GREN, TRUE}, { FPP_HANDGRENADE, MOVETYPE_BOUNCE, 600, From 2ed2867cf8e418bf85c84a7bb8098baa2710e98b Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 23 Nov 2022 19:23:12 -0800 Subject: [PATCH 1886/2474] Fix build menu stopping swings Build menu was capturing mouse inputs so you couldn't swing wrench once open. --- csqc/input.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 0988d06b..35602a3d 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -20,9 +20,10 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; break; case IE_KEYDOWN: - if (scanx == K_ESCAPE || scanx == K_MOUSE1) + if (scanx == K_ESCAPE) return TRUE; - + if (scanx == K_MOUSE1 && !menu_mouse) + return FALSE; if (fo_hud_menu_active) return fo_menu_process_input(CurrentMenu, scanx); break; From 7abcb9c1d306059507bba8732b04fc3067205b86 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 23 Nov 2022 22:38:23 -0800 Subject: [PATCH 1887/2474] Round of cleanup on client reloading code ReloadNext was being predicted differently to server, fix and generally clean things up. --- csqc/weapon_predict.qc | 193 +++++++++++++++++++++++++---------------- share/animate.qc | 9 +- share/weapons.qc | 20 ++--- ssqc/actions.qc | 21 ++--- ssqc/debug.qc | 4 +- 5 files changed, 140 insertions(+), 107 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ee5dba6a..737e92be 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -272,6 +272,15 @@ void Attack_Finished(float attack_time) { static entity pred_sound_entity; static float last_pred_sound; +static inline Slot CurrentSlot() { return pstate_pred.current_slot; } +static inline FO_WeapInfo* SlotWI(Slot slot) { + return FO_SlotWeapInfo(pstate_pred.playerclass, slot); +} + +inline FO_WeapInfo* WP_CurrentWeapon() { + return SlotWI(CurrentSlot()); +} + void Pred_Sound(SoundIndex snd, float vol = 1) { if (snd == SND_NONE || !IsEffectFrame() || pstate_pred.tfstate & TFSTATE_FLASHED) return; @@ -285,10 +294,6 @@ void PredProj_Sound(int proj_type, float vol = 1) { Pred_Sound(FPP_Get(proj_type)->snd, vol); } -inline FO_WeapInfo* WP_CurrentWeapon() { - return FO_SlotWeapInfo(pstate_pred.playerclass, pstate_pred.current_slot); -} - // Corrections for when we can recognize that we missed a packet. void WP_ServerUpdate() { if (pstate_server.attack_finished < pstate_server.client_time) @@ -335,18 +340,21 @@ float WP_CurrentAmmo() { float WP_CheckAmmo(FO_WeapInfo* wi) { - if (wi->ammo_type == AMMO_NONE || IsSlotMelee(pstate_pred.current_slot)) + if (wi->ammo_type == AMMO_NONE) return TRUE; + if (wi->weapon == WEAP_MEDIKIT || wi->weapon == WEAP_SPANNER) + return TRUE; + + if (wi->weapon == WEAP_ASSAULT_CANNON && WP_GetAmmo(AMMO_CELLS) < 7) + return FALSE; + int ammo = WP_GetAmmo(wi->ammo_type); return ammo > wi->ammo_per_shot; } -var float changed_weapon; - void WP_ChangeWeapon(Slot slot) { - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - if (!WP_CheckAmmo(wi)) + if (!WP_CheckAmmo(SlotWI(slot))) return; pstate_pred.last_slot = pstate_pred.current_slot; @@ -358,10 +366,7 @@ void WP_ChangeWeapon(Slot slot) { Slot WP_BestWeaponSlot() { for (float i = 1; i <= TF_NUM_SLOTS; i++) { Slot slot = MakeSlot(i); - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); - - if (wi->weapon == WEAP_ASSAULT_CANNON && WP_GetAmmo(AMMO_CELLS) < 7) - continue; + FO_WeapInfo* wi = SlotWI(slot); if (wi->weapon == WEAP_NONE || !WP_CheckAmmo(wi)) continue; @@ -376,8 +381,6 @@ void W_ChangeToBestWeapon() { WP_ChangeWeapon(WP_BestWeaponSlot()); } -void WP_Reload(); - float WP_LockedCannon() { if (!WP_Enabled()) return SBAR.LockedCannon; @@ -420,14 +423,43 @@ static void HandleButtonThrowgren(float index, float button) { } } +float WP_ReloadSlot(Slot slot); +void WP_ReloadNext(); + void WP_Impulse() { - // Note: We might have no impulse, but a queued slot here. WP_HandleHeavyInputs(); - float match = TRUE; + // Note: We might have no impulse, but a queued slot here. float quick_swap = FALSE; + // Impulses that are NOT held by attack_finished / reloading. + float match = TRUE; switch (pstate_pred.impulse) { + case TF_GRENADE_T: + W_ThrowGren(TRUE); + break; + + default: + match = FALSE; + break; + } + + HandleButtonThrowgren(1, BUTTON5); + HandleButtonThrowgren(2, BUTTON6); + + if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) + return; + + // Impulses that ARE held by attack_finished / reloading. + if (!match) switch (pstate_pred.impulse) { + case TF_RELOAD: + WP_ReloadSlot(CurrentSlot()); + break; + + case TF_RELOAD_NEXT: + WP_ReloadNext(); + break; + case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: pstate_pred.impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. quick_swap = TRUE; @@ -452,105 +484,94 @@ void WP_Impulse() { case TF_WEAPNEXT: pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( - pstate_pred.playerclass, pstate_pred.current_slot, FALSE); + pstate_pred.playerclass,CurrentSlot(), FALSE); break; case TF_WEAPPREV: pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( - pstate_pred.playerclass, pstate_pred.current_slot, TRUE); - break; - - case TF_GRENADE_T: - W_ThrowGren(TRUE); + pstate_pred.playerclass, CurrentSlot(), TRUE); break; default: match = FALSE; + break; } - HandleButtonThrowgren(1, BUTTON5); - HandleButtonThrowgren(2, BUTTON6); - - if (match) - pstate_pred.impulse = 0; - - if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) - return; - if (!IsSlotNull(pstate_pred.queue_slot)) { WP_ChangeWeapon(pstate_pred.queue_slot); pstate_pred.queue_slot = SlotNull; } - if (!pstate_pred.impulse) - return; - - float clear = FALSE; - if (pstate_pred.impulse == TF_RELOAD) { - WP_Reload(); - clear = TRUE; - } - - if (clear) + if (match) pstate_pred.impulse = 0; } -float* WP_ClipFired() { - float index = SlotIndex(pstate_pred.current_slot); - if (pstate_pred.playerclass == PC_DEMOMAN && - index == 1) +static float* WP_ClipFired(Slot slot) { + float index = SlotIndex(slot); + if (pstate_pred.playerclass == PC_DEMOMAN && index == 1) index = 0; // Special case: Pipebomb shares with Grenadel launcher. return &pstate_pred.clip_fired[index]; } +float WP_CurrentClipFired() { + return *WP_ClipFired(CurrentSlot()); +} + string WP_GetClip() { if (!WP_Enabled()) return SBAR.ClipSize; - Slot slot = pstate_pred.current_slot; - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, slot); + Slot slot = CurrentSlot(); + FO_WeapInfo* wi = SlotWI(slot); if (!wi->needs_reload || IsSlotNull(slot)) return ""; float capacity = wi->clip_size; float still_loading = 0; - float fired = *WP_ClipFired(); + float fired = *WP_ClipFired(slot); if (WP_IsReloading()) still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, - pstate_pred.reload_finished); + pstate_pred.reload_finished); float clip = capacity - fired - still_loading; return sprintf("%d/%d", clip, wi->clip_size); } -void WP_Reload() { - FO_WeapInfo* wi = WP_CurrentWeapon(); +float WP_CanReload(Slot slot, string* msg = __NULL__) { + FO_WeapInfo* wi = SlotWI(slot); if (!wi->needs_reload || WP_IsReloading() || prematch) - return; + return FALSE; - float clip_fired = *WP_ClipFired(); + float clip_fired = *WP_ClipFired(slot); float ammo_rem = WP_GetAmmo(wi->ammo_type); + return FO_CanReloadMsg(wi, ammo_rem, clip_fired, msg); +} - string msg; - if (!FO_CheckCanReload(wi, ammo_rem, clip_fired, msg)) { - if (IsEffectFrame()) +float WP_ReloadSlot(Slot slot) { + FO_WeapInfo* wi = SlotWI(slot); + + string msg = ""; + if (!WP_CanReload(slot, &msg)) { + if (IsEffectFrame() && msg != "") csqc_print(msg); - return; + return FALSE; } if (IsEffectFrame()) csqc_print(strcat("Reloading ", FO_GetWeapName(wi->weapon), "...\n")); pstate_pred.tfstate |= TFSTATE_RELOADING; - float amt = min(ammo_rem, clip_fired); - (*WP_ClipFired()) -= amt; + float amt = min(*WP_ClipFired(slot), WP_GetAmmo(wi->ammo_type)); + (*WP_ClipFired(slot)) -= amt; pstate_pred.reload_finished = pstate_pred.client_time + (amt / wi->clip_size) * wi->full_reload_time; + + return TRUE; } void WP_CheckReloadFinished() { @@ -562,25 +583,45 @@ void WP_CheckReloadFinished() { } } -float WP_ReloadIfNeeded(FO_WeapInfo* wi) { - if (!WP_CheckAmmo(wi) || wi->needs_reload) { - if (*WP_ClipFired() >= wi->clip_size) { - WP_Reload(); - return TRUE; +#define eprintf(...) if (IsEffectFrame()) printf(__VA_ARGS__) + +void WP_ReloadNext() { + Slot slot = CurrentSlot(); + + do { + slot = FO_FindPrevNextWeaponSlot(pstate_pred.playerclass, slot, FALSE); + + // We check this manually because we don't want to spam reload msgs. + if (WP_CanReload(slot)) { + if (WP_ReloadSlot(slot)) + return; } - } + } while (!IsSameSlot(slot, CurrentSlot())); + + if (IsEffectFrame()) + csqc_print("All clips full\n"); +} + +float WP_ReloadIfNeeded(Slot slot) { + FO_WeapInfo* wi = SlotWI(slot); + + if (*WP_ClipFired(slot) >= wi->clip_size) + return WP_ReloadSlot(slot); return FALSE; } -float WP_ConsumeAmmo(FO_WeapInfo* wi) { - if (WP_ReloadIfNeeded(wi)) +float WP_ReloadCurrentIfNeeded() { return WP_ReloadIfNeeded(CurrentSlot()); } + +float WP_ConsumeAmmo(Slot slot) { + if (WP_ReloadIfNeeded(slot)) return FALSE; + FO_WeapInfo* wi = SlotWI(slot); pstate_pred.ammo_used[wi->ammo_type] += wi->ammo_per_shot; - *WP_ClipFired() += wi->ammo_per_shot; + *WP_ClipFired(slot) += wi->ammo_per_shot; - WP_ReloadIfNeeded(wi); + WP_ReloadIfNeeded(slot); return TRUE; } @@ -941,8 +982,8 @@ void W_FireGrenade(int gren_type) { } void W_FireAssaultCannon() { - FO_WeapInfo* wi = WP_CurrentWeapon(); - WP_ConsumeAmmo(wi); + if (!WP_ConsumeAmmo(CurrentSlot())) + return; if (!IsEffectFrame() || !PP_Enabled()) return; @@ -958,7 +999,7 @@ void (float ox) W_FireSpikes = { return; } - WP_ConsumeAmmo(wi); + WP_ConsumeAmmo(CurrentSlot()); Attack_Finished(wi->attack_time); if (!IsEffectFrame()) @@ -1020,7 +1061,6 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { } void WP_Attack() { - Slot slot = pstate_pred.current_slot; FO_WeapInfo* wi = WP_CurrentWeapon(); if (wi->predict_type == NO_PREDICT) @@ -1032,7 +1072,7 @@ void WP_Attack() { wi->weapon == WEAP_SUPER_NAILGUN || wi->weapon == WEAP_ASSAULT_CANNON; - if ((in_anim && !WP_CheckAmmo(wi)) || (!in_anim && !WP_ConsumeAmmo(wi))) + if ((in_anim && !WP_CheckAmmo(wi)) || (!in_anim && !WP_ConsumeAmmo(CurrentSlot()))) return; // OK. We're ready to pew. @@ -1202,8 +1242,7 @@ DEFCVAR_FLOAT(r_drawviewmodel, 1); void WP_UpdateViewModel(entity pweap_ent) { float pmodelindex, pframe; - FO_WeapInfo* wi = FO_SlotWeapInfo(pstate_pred.playerclass, - pstate_pred.current_slot); + FO_WeapInfo* wi = WP_CurrentWeapon(); // Note, even if the predicted weapon model is not visible we might still be // using it to generated predicted projectiles. E.g. we need to keep diff --git a/share/animate.qc b/share/animate.qc index 34b8a134..21d70c11 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -156,8 +156,8 @@ static void SuperDamageSound() {} // TODO static inline vector get_velocity() { return pmove_vel; } static inline void set_weapon_frame(int f) { self.frame = f; } static inline void muzzleflash() {} -float* WP_ClipFired(); -static inline float get_clip_fired() { return *WP_ClipFired(); } +float WP_CurrentClipFired(); +static inline float get_clip_fired() { return WP_CurrentClipFired(); } void player_run() { pstate_pred.client_nextthink = 0; @@ -206,9 +206,8 @@ void player_assault_cannon() { } void Attack_Finished(float attack_time); -float WP_ReloadIfNeeded(FO_WeapInfo* wi); -FO_WeapInfo* WP_CurrentWeapon(); -static inline float FO_CheckForReload() { return WP_ReloadIfNeeded(WP_CurrentWeapon()); } +float WP_ReloadCurrentIfNeeded(); +static inline float FO_CheckForReload() { return WP_ReloadCurrentIfNeeded(); } #endif void W_FireSpikes(float ox); diff --git a/share/weapons.qc b/share/weapons.qc index 016559ae..2143de67 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -416,15 +416,15 @@ float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) return ceil((reload_finished - now) / tick) * wi->ammo_per_shot; } -float FO_CheckCanReload(FO_WeapInfo* wi, int ammo_remaining, int clip_fired, - __out string msg) { - if (clip_fired == 0) - msg = "Clip full\n"; - else if (ammo_remaining == 0) - msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); - else if (wi->clip_size - clip_fired == ammo_remaining) - msg = strcat("All ", AMMO_to_s[wi->ammo_type], " are in the clip\n"); - else +float FO_CanReloadMsg(FO_WeapInfo* wi, int ammo_remaining, int clip_fired, + string* msg = __NULL__) { + if (clip_fired == 0) { + if (msg) *msg = "Clip full\n"; + } else if (ammo_remaining == 0) { + if (msg) *msg = strcat("Out of ", AMMO_to_s[wi->ammo_type], "\n"); + } else if (wi->clip_size - clip_fired == ammo_remaining) { + if (msg) *msg = strcat("All ", AMMO_to_s[wi->ammo_type], " are in the clip\n"); + } else return TRUE; return FALSE; // msg filled in above. @@ -543,7 +543,7 @@ void FO_ReloadSlot(Slot slot, float force) { return; string msg; - if (!FO_CheckCanReload(wi, *ws->ammo_remaining, *ws->clip_fired, msg)) { + if (!FO_CanReloadMsg(wi, *ws->ammo_remaining, *ws->clip_fired, &msg)) { sprint_pred(self, PRINT_HIGH, msg); return; } diff --git a/ssqc/actions.qc b/ssqc/actions.qc index f318f57e..42655930 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -476,22 +476,17 @@ void () RestoreDefaultWeapon = { void () TeamFortress_ReloadNext = { Slot slot = self.current_slot; - if (!FO_CanReload(slot)) { - int base = SlotIndex(slot); + do { + slot = FO_FindPrevNextWeaponSlot(self.playerclass, slot, FALSE); - for (int i = 1; i < TF_NUM_SLOTS; i++) { - slot = MakeSlot(1 + ((base + 1) % TF_NUM_SLOTS)); - if (FO_CanReload(slot)) - break; + if (FO_CanReload(slot)) { + FO_ReloadSlot(slot, FALSE); + RestoreDefaultWeapon(); + return; } - } + } while (!IsSameSlot(slot, self.current_slot)); - if (FO_CanReload(slot)) { - FO_ReloadSlot(slot, FALSE); - RestoreDefaultWeapon(); - } else { - sprint(self, PRINT_HIGH, "All clips full\n"); - } + sprint_pred(self, PRINT_HIGH, "All clips full\n"); } entity TeamFortress_GetPracticeSpawn(entity e) = diff --git a/ssqc/debug.qc b/ssqc/debug.qc index b9a49367..2eaaad29 100644 --- a/ssqc/debug.qc +++ b/ssqc/debug.qc @@ -17,11 +17,11 @@ void (entity te) dremove = }; void dremove_sent(entity te) { - static const float epsilon = SERVER_FRAME_DT; + static const float epsilon = 2 * SERVER_FRAME_DT; if (time > te.s_time + epsilon) { dremove(self); } else { - self.nextthink = time + 2 * epsilon; + self.nextthink = time + epsilon; self.think = SUB_Remove; } } From 46d63319d9a223519f5b349850086c8068182917 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 23 Nov 2022 23:12:56 -0800 Subject: [PATCH 1888/2474] Don't predict pipes in prematch Only reds. --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 737e92be..6d8942c3 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1104,7 +1104,7 @@ void WP_Attack() { case WEAP_GRENADE_LAUNCHER: case WEAP_PIPE_LAUNCHER: if (PP_EnableGrenades()) - W_FireGrenade(wi->weapon == WEAP_GRENADE_LAUNCHER ? + W_FireGrenade(wi->weapon == WEAP_GRENADE_LAUNCHER || prematch ? GREN_RED : GREN_PIPE); else Pred_Sound(SND_GREN); From 3036d518bf4e3117e8c4d9e479b64c5a2bfc5834 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 24 Nov 2022 00:11:03 -0800 Subject: [PATCH 1889/2474] Fix impulse clearing Prior commit got this wrong. --- csqc/weapon_predict.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6d8942c3..818523fb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -444,6 +444,9 @@ void WP_Impulse() { break; } + if (match) + pstate_pred.impulse = 0; + HandleButtonThrowgren(1, BUTTON5); HandleButtonThrowgren(2, BUTTON6); @@ -451,7 +454,9 @@ void WP_Impulse() { return; // Impulses that ARE held by attack_finished / reloading. - if (!match) switch (pstate_pred.impulse) { + match = TRUE; + switch (pstate_pred.impulse) { + case 0: break; // Handled above. case TF_RELOAD: WP_ReloadSlot(CurrentSlot()); break; From 246855fb2d0eae9c5cf4c3fa7baf9b85338ea7f3 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 24 Nov 2022 00:13:07 -0800 Subject: [PATCH 1890/2474] Add missing brackets on ternary --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 818523fb..05c51ddb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1109,7 +1109,7 @@ void WP_Attack() { case WEAP_GRENADE_LAUNCHER: case WEAP_PIPE_LAUNCHER: if (PP_EnableGrenades()) - W_FireGrenade(wi->weapon == WEAP_GRENADE_LAUNCHER || prematch ? + W_FireGrenade((wi->weapon == WEAP_GRENADE_LAUNCHER || prematch) ? GREN_RED : GREN_PIPE); else Pred_Sound(SND_GREN); From 2be30e13b31cfff16f643a38ac1fe589b9b6ffe9 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 24 Nov 2022 03:18:56 -0800 Subject: [PATCH 1891/2474] Add checking for starting on solids We're getting the odd grenade bouncing in corners and not decelerating. This might be sufficient, but also cull these when they occur for now. --- share/physics.qc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/share/physics.qc b/share/physics.qc index 47ac6126..0affae89 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -12,6 +12,7 @@ enumflags { PHYSF_CONSUME_ALL, PHYSF_REWIND_PLAYERS, PHYSF_FORWARD_KNOCK, + PHYSF_FAIL_STARTSOLID }; const float FL_FORWARD_KNOCK = FL_GODMODE; @@ -81,11 +82,16 @@ float Phys_Push(entity e, vector offset, float dt, float phys_flags) { // Note: Networked entities don't currently intersect on CSQC instantiation // of this, we fudge this in Phys_Impact from the server side. traceline(e.origin, e.origin + offset, trace_flags, e); + + if ((phys_flags & PHYSF_FAIL_STARTSOLID) && trace_startsolid) { + return trace_fraction; + } + e.origin = trace_endpos; if (trace_fraction < 1) { - setorigin(e, trace_endpos); - Phys_Impact(e, trace_fraction * dt, phys_flags); + if ((e.flags & FL_ONGROUND == 0 || e.groundentity != trace_ent)) + Phys_Impact(e, trace_fraction * dt, phys_flags); return FALSE; } @@ -116,6 +122,7 @@ float Phys_Adv_Bounce(entity e, float dt, float phys_flags) { e.velocity_z -= 0.5 * dt * g; + phys_flags |= PHYSF_FAIL_STARTSOLID; float move_time = dt, bounce; if (Phys_Push(e, move_time * e.velocity, move_time, phys_flags)) { e.velocity_z -= 0.5 * dt * g; @@ -123,8 +130,6 @@ float Phys_Adv_Bounce(entity e, float dt, float phys_flags) { return dt; } - if (trace_allsolid) - trace_fraction = 0; move_time = (1 - trace_fraction) * dt; e.angles += move_time * e.avelocity; @@ -173,7 +178,8 @@ static void Phys_CapVel(entity e) { if (!fo_config.clown_flags) printf("%s v=%d too fast, consider adaptive scaling\n", e.model, vlen(e.velocity)); - e.velocity = normalize(e.velocity) * limit; + // normalize(e.velocity) * limit; + e.velocity = '0 0 0'; } } From 303a1aff973b55a48c0887c9ce2fe21cb2cb502a Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 24 Nov 2022 03:44:20 -0800 Subject: [PATCH 1892/2474] Rewind updates - Fix bug where log was being constantly overwritten - Smoothen interpolation and try harder to find the right pair/fix some cases where this could be off. - Extrapolate a tiny amount for very recent timestamps. --- share/physics.qc | 6 +++--- ssqc/antilag.qc | 56 ++++++++++++++++++++++++++++++++++-------------- ssqc/qw.qc | 1 + ssqc/time.qc | 1 + 4 files changed, 45 insertions(+), 19 deletions(-) diff --git a/share/physics.qc b/share/physics.qc index 0affae89..e9583e1a 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -169,7 +169,7 @@ float Phys_Adv_Linear(entity e, float dt, float phys_flags) { return dt; } -var void(entity e) RewindSyncTime; +var void(entity e, float step) RewindSyncTime; static void Phys_CapVel(entity e) { static const float limit = 32 / phys_tic; @@ -199,9 +199,9 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { break; } - if (phys_flags & PHYSF_REWIND_PLAYERS) - RewindSyncTime(e); step = min(phys_tic, delta); + if (phys_flags & PHYSF_REWIND_PLAYERS) + RewindSyncTime(e, step); if (IsClownMode(CLOWN_PROJ_GRAVITY)) e.velocity_z += -fo_config.clown_grav * step; diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index 36748165..af24fb82 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -100,7 +100,7 @@ static SeekResult RewindSeek(RewindState* rstate, float rtime) { for (int i = 0; i < AL_MAX_REWINDS; i++) { RewindSnapshot* rs = &rstate->snapshot[idx]; - if (rs->time > rtime) { + if (rs->time >= rtime) { r.after = rs; } else { if (rs->time) @@ -119,7 +119,7 @@ RewindSnapshot* RewindLog(RewindState* target) { error("Log mismatch\n"); RewindSnapshot* rs = &target->snapshot[target->cur]; - if (rs->time && rs->time > time + 0.001) { + if (rs->time && time > rs->time + 0.005) { target->cur = NextRewindIdx(target->cur); rs = &target->snapshot[target->cur]; } @@ -131,6 +131,12 @@ RewindSnapshot* RewindLog(RewindState* target) { return rs; } +void DumpLog(RewindState* rs) { + for (float i = 0; i < AL_MAX_REWINDS; i++) { + printf("%s%2d> t=%0.3f\n", i == rs->cur ? "*" : " ", i, rs->snapshot[i].time); + } +} + static void RewindSave(RewindState* rs) { rs->rewound = kRewound; entity e = rs->owner; @@ -166,25 +172,43 @@ static void RL_RestorePositions(RewindState* head) { static void RewindTo(RewindState* rstate, float rtime) { ASSERTD_EQ(rstate->rewound, kRewound); + entity e = rstate->owner; - if (rstate->owner.health <= 0) + if (e.health <= 0) return; - rtime = max(rtime, rstate->owner->spawn_time); + vector pos; - SeekResult sr = RewindSeek(rstate, rtime); - RewindSnapshot* a = sr.after; - RewindSnapshot* b = sr.before; + if (rtime < e.client_lastupdate) { + SeekResult sr = RewindSeek(rstate, rtime); + RewindSnapshot* a = sr.after; + RewindSnapshot* b = sr.before; - vector pos = a.origin; - if (b) { - float frac = (rtime - b->time) / (a->time - b->time); - vector diff = a->origin - b->origin; + float a_time; + vector a_origin; - if (vlen(diff) > 48) - frac = 1; // Most likely teleport. + if (!a) { + a_time = time; + a_origin = self.origin; + } else { + a_time = a->time; + a_origin = a->origin; + } - pos = b->origin + frac * diff; + if (!b) { + pos = a_origin; // Should never happen... + } else { + float frac = (rtime - b->time) / (a->time - b->time); + vector diff = a->origin - b->origin; + + if (vlen(diff) > 48) + frac = 1; // Most likely teleport. + + pos = b->origin + frac * diff; + } + } else { + float max_xerp = CF_GetSetting("rwmx", "rewind_max_xerp", "0.02"); + pos = e.origin + min(rtime - e.client_lastupdate, max_xerp) * e.velocity; } setorigin(rstate->owner, pos); @@ -272,8 +296,8 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { return TRUE; } -void ProjRewind(entity e) { - RL_RewindTo(rewind_players, e.owner, e.phys_time); +void ProjRewind(entity e, float step) { + RL_RewindTo(rewind_players, e.owner, e.phys_time + step / 2); } void WeaponPred_ProjectProjectileRewind(int fpp_type, entity proj) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index bde815a5..d2e7b06b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -18,6 +18,7 @@ struct antilag_settings_t { .float client_time; // A stable/predictable client clock .float client_ping; // ping used for prediction .float last_remote_client_time; // For monoticity +.float client_lastupdate; .void() client_think; // client-time relative think .float client_thinkindex; diff --git a/ssqc/time.qc b/ssqc/time.qc index 8d54d863..8d06dcce 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -45,6 +45,7 @@ void FO_CheckClientThink() { void FO_UpdateClientTime() { self.client_time += frametime; + self.client_lastupdate = time; self.client_ping = infokeyf(self, INFOKEY_P_PING); } From 574a02ac8af58d7bc6f65511b4cb3c288836d0ed Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 24 Nov 2022 04:13:33 -0800 Subject: [PATCH 1893/2474] Fix s_time for static projection For both forward knock and trails --- ssqc/antilag.qc | 5 ++--- ssqc/debug.qc | 10 +++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ssqc/antilag.qc b/ssqc/antilag.qc index af24fb82..774e20c7 100644 --- a/ssqc/antilag.qc +++ b/ssqc/antilag.qc @@ -320,10 +320,9 @@ void WeaponPred_ProjectProjectileRewind(int fpp_type, entity proj) { phys_flags |= PHYSF_FORWARD_KNOCK; // Static projection happens instantly. If rewind is active, we'll do it at - // the rewound point in time, but we don't advance time while stepping - // through it. + // a prior point in time, but we don't advance time while stepping. proj.s_origin = proj.origin; - proj.s_time = time; + proj.s_time = 0; float st = Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); // We initialize s_origin/s_time after Phys_Init, they are used when diff --git a/ssqc/debug.qc b/ssqc/debug.qc index 2eaaad29..a5d81b51 100644 --- a/ssqc/debug.qc +++ b/ssqc/debug.qc @@ -17,11 +17,15 @@ void (entity te) dremove = }; void dremove_sent(entity te) { - static const float epsilon = 2 * SERVER_FRAME_DT; - if (time > te.s_time + epsilon) { + static const float epsilon = 3*SERVER_FRAME_DT; + float stime = te.s_time; + if (!stime) + stime = time; + + if (time > stime + epsilon) { dremove(self); } else { - self.nextthink = time + epsilon; + self.nextthink = stime + epsilon; self.think = SUB_Remove; } } From 04d29a87b20fc9047712f873dbbbdf9345e16464 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 24 Nov 2022 11:53:23 -0800 Subject: [PATCH 1894/2474] Restore setorigin and skip void ents Radius searches on explosion need the earlier setorigin it seems. --- csqc/weapon_predict.qc | 3 +++ share/physics.qc | 8 ++++---- share/prediction.qc | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 05c51ddb..86c85be6 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -856,6 +856,9 @@ DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); .float trail_started; float PP_PredrawActive() { + if (self.voided) + return PREDRAW_NEXT; + Phys_Advance(self, get_phys_time(self), 0); // we need to space out the particles incase we're running at very high fps diff --git a/share/physics.qc b/share/physics.qc index e9583e1a..ce7b8dd0 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -83,14 +83,14 @@ float Phys_Push(entity e, vector offset, float dt, float phys_flags) { // of this, we fudge this in Phys_Impact from the server side. traceline(e.origin, e.origin + offset, trace_flags, e); - if ((phys_flags & PHYSF_FAIL_STARTSOLID) && trace_startsolid) { - return trace_fraction; - } + if ((phys_flags & PHYSF_FAIL_STARTSOLID) && trace_startsolid) + return FALSE; e.origin = trace_endpos; if (trace_fraction < 1) { - if ((e.flags & FL_ONGROUND == 0 || e.groundentity != trace_ent)) + setorigin(e, trace_endpos); + if ((e.flags & FL_ONGROUND == 0) || e.groundentity != trace_ent) Phys_Impact(e, trace_fraction * dt, phys_flags); return FALSE; } diff --git a/share/prediction.qc b/share/prediction.qc index dfadfddb..72a5fd59 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -704,7 +704,8 @@ void PredProj_Sound(int proj_type, float vol = 1) { void WeaponPred_ProjectProjectile(int fpp_type, entity projectile); void FO_Phys() { - Phys_Advance(self, time, 0); + if (!self.voided) + Phys_Advance(self, time, 0); float held_time, thinktime; // Once we lift physics, think execution comes with it. From 2810918e59269e5296ade83e6e41cc656465e9e2 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 25 Nov 2022 03:57:06 -0800 Subject: [PATCH 1895/2474] Reduce bandwidth used by ~25% Velocity was embedded into a stat field for speed display on the HUD. This is a non-optimal choice both because it changes incredibly quickly and a better (more up-to-date) copy is already available client side in the form of pmove. Reduces BW used from ~60k/s to 45k/s. Should also likely help with proxy overflows. --- csqc/csextradefs.qc | 1 - csqc/main.qc | 4 ---- csqc/status.qc | 2 +- share/defs.h | 13 +++++-------- ssqc/world.qc | 1 - 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 24c6b098..7b86dfaa 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -824,7 +824,6 @@ float is_observer; float oldhealth; float painfinished; vector thisorigin; -float speed; float jump_counter; float grentimer_waiting; float jumpsound_cooldown; diff --git a/csqc/main.qc b/csqc/main.qc index b65ce9d3..9a3337c6 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -492,10 +492,6 @@ void _Sync_ServerCommandFrame() { if (is_spectator) is_observer = FALSE; - vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), - getstatf(STAT_VELOCITY_Z)]; - speed = sqrt(vel.x * vel.x + vel.y * vel.y); - local float health = getstatf(STAT_HEALTH); if (health <= 0 || player_class != PC_SNIPER) { zoomed_in = 0; diff --git a/csqc/status.qc b/csqc/status.qc index ddbbe0db..045870db 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1103,7 +1103,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_GUN6, "gun6", "Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, {HUDP_GUN7, "gun7", "Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", speed) : "";}, 0, 4}, + {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", vlen(pmove_vel)) : "";}, 0, 4}, {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0,1, doNothing, {return "";}, 1}, }; diff --git a/share/defs.h b/share/defs.h index 026e3b1a..9d2c6b40 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1502,14 +1502,11 @@ enumflags { #define STAT_TEAMNO 33 #define STAT_FLAGS 34 #define STAT_CLASS 35 -#define STAT_VELOCITY_X 36 -#define STAT_VELOCITY_Y 37 -#define STAT_VELOCITY_Z 38 -#define STAT_NO_GREN1 39 -#define STAT_NO_GREN2 40 -#define STAT_TP_GREN1 41 -#define STAT_TP_GREN2 42 -#define STAT_PAUSED 43 +#define STAT_NO_GREN1 36 +#define STAT_NO_GREN2 37 +#define STAT_TP_GREN1 38 +#define STAT_TP_GREN2 39 +#define STAT_PAUSED 40 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/world.qc b/ssqc/world.qc index 1dbaaa86..ea81a8df 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -332,7 +332,6 @@ void () worldspawn = { clientstat(STAT_TEAMNO, EV_FLOAT, team_no); clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); clientstat(STAT_CLASS, EV_FLOAT, playerclass); - clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); clientstat(STAT_TP_GREN1, EV_FLOAT, tp_grenades_1); From d4803c2d3445d43c9d10128371d8aa4aa94d2ab9 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 25 Nov 2022 23:18:23 -0800 Subject: [PATCH 1896/2474] Fix Instakill Tranqs Delayed entity removal was allowing for multiple touches dependent on ping, angle, and newmis. But keep a clown mode that allows it. --- csqc/weapon_predict.qc | 2 +- share/commondefs.qc | 1 + ssqc/spy.qc | 10 ++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 86c85be6..c2bb8ab4 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -185,7 +185,7 @@ void WPP_Status() { PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); - static string clown_desc[] = { "Rubber grenades", "Proj gravity" }; + static string clown_desc[] = { "Rubber grenades", "Proj gravity", "Lethal tranq" }; if (fo_config.clown_flags) { printf("Clown mode:\n"); printf(" .clown gravity=%d\n", fo_config.clown_grav); diff --git a/share/commondefs.qc b/share/commondefs.qc index 78c0c48f..e8c69f64 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -24,6 +24,7 @@ var struct { enumflags { CLOWN_RUBBERGREN, CLOWN_PROJ_GRAVITY, + CLOWN_LETHAL_TRANQ, }; inline float IsClownMode(int flag) { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index a7072d3d..f176c394 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1097,9 +1097,13 @@ void () W_FireTranq = { void () T_TranqDartTouch = { local entity timer; - if (other.solid == 1) + if (other.solid == SOLID_TRIGGER) return; + if (self.voided) + return; + self.voided = 1; + if (pointcontents(self.origin) == CONTENT_SKY) { dremove_sent(self); return; @@ -1134,7 +1138,9 @@ void () T_TranqDartTouch = { } spawn_touchblood(9); deathmsg = 25; - TF_T_Damage(other, self, self.owner, 20, 2, 2); + + float dmg = IsClownMode(CLOWN_LETHAL_TRANQ) ? 999 : 20; + TF_T_Damage(other, self, self.owner, dmg, 2, 2); } else { WriteByte(4, 23); if (self.classname == "wizspike") { From 0388bfbaf920484c7a138d4d6526ae91c740f97a Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 00:48:56 -0800 Subject: [PATCH 1897/2474] Make fast projectiles their own clown setting --- csqc/weapon_predict.qc | 3 ++- share/commondefs.qc | 3 ++- share/prediction.qc | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c2bb8ab4..1d08f065 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -185,7 +185,8 @@ void WPP_Status() { PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); - static string clown_desc[] = { "Rubber grenades", "Proj gravity", "Lethal tranq" }; + static string clown_desc[] = { "Fast projectiles", "Rubber grenades", + "Proj gravity", "Lethal tranq" }; if (fo_config.clown_flags) { printf("Clown mode:\n"); printf(" .clown gravity=%d\n", fo_config.clown_grav); diff --git a/share/commondefs.qc b/share/commondefs.qc index e8c69f64..891d580f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -22,9 +22,10 @@ var struct { } fo_config; enumflags { + CLOWN_FAST_PROJECTILES, CLOWN_RUBBERGREN, - CLOWN_PROJ_GRAVITY, CLOWN_LETHAL_TRANQ, + CLOWN_PROJ_GRAVITY, }; inline float IsClownMode(int flag) { diff --git a/share/prediction.qc b/share/prediction.qc index 72a5fd59..21986f3a 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -815,6 +815,9 @@ ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { max_ping_credit += dynamic_newmis_ms(); } + if (IsClownMode(CLOWN_FAST_PROJECTILES) && !FPP_IsGrenade(fpp_type)) + static_credit = 9999; + if (fpp_type == FPP_HANDGRENADE && fo_config.no_forward_hg) max_ping_credit = 0; From dc75e7c5da24ab84dfc701cb0c61b0eec52eff3d Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 01:16:18 -0800 Subject: [PATCH 1898/2474] Automatically disable clown mode --- ssqc/clan.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 980a8cc7..cbbd8fad 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1077,6 +1077,7 @@ float () CheckAllPlayersReady = { bprint (2, "All players ready, match will start after ceasefire ends.\n"); } else { bprint (2, "All players ready, starting match\n"); + localcmd("localinfo clown 0"); // Disable any clown settings. StartTimer (); local float limit_quad_players = CF_GetSetting("lqp", "limit_quad_players", "off"); From e05bf9e4bd7d1c56c767d44c411d8a612e6d6829 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 02:08:27 -0800 Subject: [PATCH 1899/2474] Work-around initial SendFlags not respecting mask --- share/prediction.qc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/share/prediction.qc b/share/prediction.qc index 21986f3a..4c200364 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -407,6 +407,11 @@ float WP_SendEntity(entity to_player, float sendflags) { if (to_player != self.owner) return FALSE; + // Initial send doesn't respect the set mask. Maybe setsendneeded fixes + // this but that would need an sv binary upgrade. Work around for now. + if (sendflags == 0xFFFFFF) + sendflags = self.SendFlags; + WriteByte(MSG_ENTITY, ENT_WEAPONPRED); WriteFloat(MSG_ENTITY, sendflags); #else @@ -485,6 +490,10 @@ void EntUpdate_WeaponPred(float isnew) { #define COMMD(_type, _dest, _field) COMM(_type, _field) #define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) float PP_SendEntity(entity to_player, float sendflags) { + // Initial send doesn't respect the set mask. Maybe setsendneeded fixes + // this but that would need an sv binary upgrade. Work around for now. + if (sendflags == 0xFFFFFF) + sendflags = self.SendFlags; WriteByte(MSG_ENTITY, ENT_PROJECTILE); WriteByte(MSG_ENTITY, sendflags); #else From a54bca4140eee11418313f3cd7f49a7ac33d5be0 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 02:56:38 -0800 Subject: [PATCH 1900/2474] Bound both nudges by ping --- csqc/weapon_predict.qc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 1d08f065..6d303866 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -765,18 +765,17 @@ trail_table_entry trail_table[] = { {{"TE_RAILTRAIL"}}, }; -static inline float phys_adv_dt() { - float adj_ping = max(pstate_pred.client_ping, 0); - return min(CVARF(wpp_phys_adv_ms), adj_ping) / 1000.0; +float get_phys_time_nudge_dt(entity e) { + float nudge, adj_ping = max(pstate_pred.client_ping, 0); + if (e.owner_entnum != player_localentnum) + nudge = CVARF(wpp_phys_adv_ms); + else + nudge = CVARF(wpp_phys_local_adv_ms); + return min(nudge, adj_ping) / 1000.0; } -float get_phys_time(entity e) { - float ptime = time, adv_dt; - if (e.owner_entnum && e.owner_entnum != player_localentnum) - adv_dt = phys_adv_dt(); - else - adv_dt = CVARF(wpp_phys_local_adv_ms) / 1000.0; - return ptime + adv_dt; +inline float get_phys_time(entity e) { + return time + get_phys_time_nudge_dt(e); } void FO_PP_Init() { From 681c2a6a9ef1c26d078a85a2daef8b8d3938845f Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 13:47:17 -0800 Subject: [PATCH 1901/2474] Undo sendflags change Was occasionally undersending when mask is cleared and bogus mask came in. --- share/prediction.qc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/share/prediction.qc b/share/prediction.qc index 4c200364..21986f3a 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -407,11 +407,6 @@ float WP_SendEntity(entity to_player, float sendflags) { if (to_player != self.owner) return FALSE; - // Initial send doesn't respect the set mask. Maybe setsendneeded fixes - // this but that would need an sv binary upgrade. Work around for now. - if (sendflags == 0xFFFFFF) - sendflags = self.SendFlags; - WriteByte(MSG_ENTITY, ENT_WEAPONPRED); WriteFloat(MSG_ENTITY, sendflags); #else @@ -490,10 +485,6 @@ void EntUpdate_WeaponPred(float isnew) { #define COMMD(_type, _dest, _field) COMM(_type, _field) #define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) float PP_SendEntity(entity to_player, float sendflags) { - // Initial send doesn't respect the set mask. Maybe setsendneeded fixes - // this but that would need an sv binary upgrade. Work around for now. - if (sendflags == 0xFFFFFF) - sendflags = self.SendFlags; WriteByte(MSG_ENTITY, ENT_PROJECTILE); WriteByte(MSG_ENTITY, sendflags); #else From f8594e108e8ce82e627f446cb78146384ab22c57 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 09:43:36 -0800 Subject: [PATCH 1902/2474] Refactor and clean-up --- csqc/csprogs.src | 1 + csqc/main.qc | 2 +- csqc/weapon_predict.qc | 34 +++---- share/classes.qc | 79 ++++++++++++++++ share/commondefs.qc | 27 +++++- share/physics.qc | 26 +++++- share/prediction.qc | 166 +++++++-------------------------- ssqc/client.qc | 10 +- ssqc/demoman.qc | 2 +- ssqc/progs.src | 3 +- ssqc/{antilag.qc => rewind.qc} | 91 ++++++------------ ssqc/tsoldier.qc | 2 +- ssqc/world.qc | 2 +- 13 files changed, 224 insertions(+), 221 deletions(-) create mode 100644 share/classes.qc rename ssqc/{antilag.qc => rewind.qc} (79%) diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 747eeb02..d2b2db20 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -17,6 +17,7 @@ csextradefs.qc ../share/physics.qc ../share/weapons.qc ../share/prediction.qc +../share/classes.qc ../share/animate.qc weapon_predict.qc sui_sys.qc diff --git a/csqc/main.qc b/csqc/main.qc index f3e09928..a71ba829 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,7 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // } FO_Weapons_Init(); - WeapPred_InitDefaultConfig(); + Predict_InitDefaultConfig(); FO_PP_Init(); // Some of this is always used by custom projectiles. CsGrenTimer::Init(); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6d303866..38f84944 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -170,14 +170,11 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); - static string rewind_desc[] = { "rewind pipe knockback", "rewind proj hit", - "sync proj self knockback" }; - printf("Rewind Settings:\n"); - if (fo_config.rewind_flags) { - for (float i = 0; i < rewind_desc.length; i++) - if (fo_config.rewind_flags & (1 << i)) - printf(" .%s\n", rewind_desc[i]); - + printf("Rewind Settings [rewind_flags=%d]:\n", fo_config.rewind_flags); + for (float i = 0; i < REWIND_DESC.length; i++) { + float flag = 1 << i; + printf(" %2d [%-3s]: .%s\n", flag, + (fo_config.rewind_flags & flag) ? "on": "off", REWIND_DESC[i]); } PRINT_CONFIG(no_forward_hg); PRINT_CONFIG(max_rewind_ms); @@ -185,14 +182,17 @@ void WPP_Status() { PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); - static string clown_desc[] = { "Fast projectiles", "Rubber grenades", - "Proj gravity", "Lethal tranq" }; - if (fo_config.clown_flags) { - printf("Clown mode:\n"); - printf(" .clown gravity=%d\n", fo_config.clown_grav); - for (float i = 0; i < clown_desc.length; i++) - if (fo_config.clown_flags & (1 << i)) - printf(" .%s\n", clown_desc[i]); + if (!fo_config.clown_flags) + return; + + printf("Clown mode [clown_flags=%d]:\n", fo_config.clown_flags); + for (float i = 0; i < CLOWN_DESC.length; i++) { + float flag = 1 << i; + printf(" %2d [%-3s]: .%s", flag, + (fo_config.clown_flags & flag) ? "on": "off", CLOWN_DESC[i]); + if (flag == CLOWN_PROJ_GRAVITY) + printf(" (clown_grav=%d)", fo_config.clown_grav); + printf("\n"); } } @@ -920,7 +920,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { #endif ProjectResult push_t = - WeaponPred_ProjectOffset(fpp_type, pstate_pred.client_ping); + Forward_ProjectOffset(fpp_type, pstate_pred.client_ping); float uncorrected_dt = (pstate_pred.client_ping - push_t.dynamic_ms) / 1000.0; float static_dt = push_t.static_ms / 1000.0; diff --git a/share/classes.qc b/share/classes.qc new file mode 100644 index 00000000..f5817ab5 --- /dev/null +++ b/share/classes.qc @@ -0,0 +1,79 @@ +#ifdef SSQC +inline int* prng_state(int type) { return &self.prng_base[type]; } +#else +inline int* prng_state(int type) { return &pstate_pred.prng_base[type]; } +#endif + +int lfsr_prng_raw(int v) { // A 16-bit xor-shift LFSR. + v ^= (v >> 7); + v ^= (v << 9); + v &= 65535; + v ^= (v >> 13); + return v; +} + +float lsfr_prng(int prev) { + return lfsr_prng_raw(prev) / 65535.0; +} + +float shared_prng(int type) { + return (*prng_state(type) = lfsr_prng_raw(*prng_state(type))) / 65535.0; +} + +float shared_crandom(int type) { + return 2 * (shared_prng(type) - 0.5); +} + +#ifdef CSQC +float WP_GetAmmo(float ammo_type); +float get_shells() { return WP_GetAmmo(AMMO_SHELLS); } +static inline vector get_origin() { return pmove_org; } +#else +float get_shells() { return self.ammo_shells; } +static inline vector get_origin() { return self.origin; } +#endif + +// Randomize by ammo index for consistency even if a packet/prediction misses. +static float hwguy_random_index; + +void reset_hwguy_random() { + hwguy_random_index = (*prng_state(PRNG_HWGUY) + get_shells() * 211) & 65535; + if (hwguy_random_index == 0) + hwguy_random_index = (get_shells() + 1) * 211; +} + +float hwguy_random() { + float index = hwguy_random_index; + float r = (hwguy_random_index = lfsr_prng_raw(hwguy_random_index)) / 65535.0; + return r; +} + +float hwguy_crandom() { + return 2 * (hwguy_random() - 0.5); +} + +void FO_FireAssCanPellet(vector org, vector spread_dir, float var_speed, int index); + +void WeapPred_FireAssCan(vector vangle, float shotcount, + vector spread) { + vector bullet_dir, spread_dir, rand_dir, org; + float bullet_speed, var_speed; + + reset_hwguy_random(); + + makevectors(vangle); + + // In front of player model and down towards gun + bullet_speed = fpp_types[FPP_ASSAULT_CANNON].speed; + bullet_dir = v_forward; + + for (int i = 0; i < shotcount; i++) { + var_speed = hwguy_crandom()*10 + bullet_speed; // Slight speed variance + rand_dir = (hwguy_crandom()*spread_x) * v_right + + (hwguy_crandom()*spread_y) * v_up; + spread_dir = bullet_dir + rand_dir; + org = get_origin() + '0 0 10' + rand_dir; + + FO_FireAssCanPellet(org, spread_dir, var_speed, i); + } +} diff --git a/share/commondefs.qc b/share/commondefs.qc index 891d580f..891c95f4 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -21,11 +21,36 @@ var struct { float gren_beta_disable; } fo_config; +enumflags { + REWIND_KNOCKBACK, + REWIND_PROJ_HIT, + REWIND_PROJ_SELFKNOCK, +}; + +string REWIND_DESC[] = { + "rewind pipe knockback", + "rewind projectile hit", + "forward projectile self-knockback", +}; + +const float REWIND_DEFAULT_FLAGS = 0; + +float RewindFlagEnabled(float flag) { + return fo_config.rewind_flags & flag; +} + enumflags { CLOWN_FAST_PROJECTILES, CLOWN_RUBBERGREN, - CLOWN_LETHAL_TRANQ, CLOWN_PROJ_GRAVITY, + CLOWN_LETHAL_TRANQ, +}; + +string CLOWN_DESC[] = { + "fast projectiles", + "rubber grenades", + "projectile gravity", + "elephant tranq", }; inline float IsClownMode(int flag) { diff --git a/share/physics.qc b/share/physics.qc index ce7b8dd0..16cb67cc 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -22,8 +22,31 @@ static inline float PhysFlagEnabled(float flag) { } #ifdef SSQC -void Predict_UpdateHack(entity e); +float Phys_Advance(entity e, float target_time, float phys_flags); + +void FO_CustomPhysics() { + if (!self.voided) + Phys_Advance(self, time, 0); + + float held_time, thinktime; + // Once we lift physics, think execution comes with it. + do { + thinktime = self.nextthink; + if (thinktime <= 0 || thinktime > time) + return; + + held_time = time; + self.nextthink = 0; + time = thinktime; + self.think(); + time = held_time; + + if (self.is_removed || self.nextthink < thinktime /* no loop on rev */) + return; + } while (1); +} +void Predict_UpdateHack(entity e); static void Phys_Impact(entity e, float dt, float phys_flags) { if (trace_ent.solid == SOLID_NOT) return; @@ -243,5 +266,4 @@ float Phys_Init(entity e, float target_time, float delta, float phys_flags) { return 0; } } - #undef dot diff --git a/share/prediction.qc b/share/prediction.qc index 21986f3a..9c4da9f4 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -22,14 +22,16 @@ enumflags { FOWP_RNG0, FOWP_RNG1, FOWP_PREDICT_FLAGS, + FOWP_NEW, // We only use this for a new entity, which is FFF... anyway. }; enumflags { - FOPP_POS, FOPP_INIT, + FOPP_POS, FOPP_AUX, FOPP_ANGLES, FOPP_MOVETYPE, + FOPP_NEW, // We only use this for a new entity, which is FFF... anyway. }; #define FOWP_ALL 0xFFFF @@ -256,32 +258,6 @@ predict_tf_state pstate_pred, pstate_server; #endif -#ifdef SSQC -inline int* prng_state(int type) { return &self.prng_base[type]; } -#else -inline int* prng_state(int type) { return &pstate_pred.prng_base[type]; } -#endif - -int lfsr_prng_raw(int v) { // A 16-bit xor-shift LFSR. - v ^= (v >> 7); - v ^= (v << 9); - v &= 65535; - v ^= (v >> 13); - return v; -} - -float lsfr_prng(int prev) { - return lfsr_prng_raw(prev) / 65535.0; -} - -float shared_prng(int type) { - return (*prng_state(type) = lfsr_prng_raw(*prng_state(type))) / 65535.0; -} - -float shared_crandom(int type) { - return 2 * (shared_prng(type) - 0.5); -} - #ifdef SSQC #define OP1(_op, _f1) (player.predict_state.##_f1 _op player.##_f1) #define OP2(_op, _j, _f1, _f2) OP1(_op, _f2) _j OP1(_op, _f1) @@ -292,20 +268,19 @@ float shared_crandom(int type) { #define M3(_bit, _f1, _f2, _f3) if (OP3(!=, ||, _f1, _f2, _f3)) { mask |= _bit; OP3(=, ;, _f1, _f2, _f3); } #define M4(_bit, _f1, _f2, _f3, _f4) if (OP4(!=, ||, _f1, _f2, _f3, _f4)) { mask |= _bit; OP4(=, ;, _f1, _f2, _f3, _f4); } -predict_tf_state blank_state; .float last_full_predict_refresh; -void WeaponPred_Update(entity player) { - if (player.predict_entity == __NULL__) - return; +void Predict_Update() { + entity pe = self.predict_entity; + if (pe != __NULL__) + pe.SendFlags = 1; // Will compute what to send. +} +static float Prediction_ChangedMask(entity player) { float mask = FOWP_CTIME; - if (time - player.last_full_predict_refresh >= 1000 * MSEC) { - player.predict_state = blank_state; - player.last_full_predict_refresh = time; - mask = -1; - } + if (time - player.last_full_predict_refresh >= 1000 * MSEC) + return 0xFFFFFF; player.predict_state.client_time = player.client_time; player.predict_state.client_ping = player.client_ping; @@ -322,7 +297,7 @@ void WeaponPred_Update(entity player) { M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]) - player.predict_entity.SendFlags = mask; + return mask; } #undef OP1 @@ -403,10 +378,12 @@ void EntUpdate_Config() { #ifdef SSQC #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) -float WP_SendEntity(entity to_player, float sendflags) { +float WP_SendEntity(entity to_player, float ignored) { if (to_player != self.owner) return FALSE; + float sendflags = Prediction_ChangedMask(self.owner); + WriteByte(MSG_ENTITY, ENT_WEAPONPRED); WriteFloat(MSG_ENTITY, sendflags); #else @@ -415,11 +392,11 @@ void EntUpdate_WeaponPred(float isnew) { float sendflags = readfloat(); #endif if (sendflags & FOWP_PREDICT_FLAGS) - COMM(Float, predict_flags); + COMM(Byte, predict_flags); if (sendflags & FOWP_CTIME) { COMM(Float, client_time); - COMM(Float, client_ping); + COMM(Byte, client_ping); } if (sendflags & FOWP_CLASS) { @@ -485,6 +462,12 @@ void EntUpdate_WeaponPred(float isnew) { #define COMMD(_type, _dest, _field) COMM(_type, _field) #define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) float PP_SendEntity(entity to_player, float sendflags) { + if (sendflags & FOPP_NEW) { + sendflags = FOPP_INIT | FOPP_POS; + if (self.wpp_aux) + sendflags |= FOPP_AUX; + } + WriteByte(MSG_ENTITY, ENT_PROJECTILE); WriteByte(MSG_ENTITY, sendflags); #else @@ -509,6 +492,7 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, velocity[1]); COMM(Coord, velocity[2]); + COMM(Byte, movetype); COMM(Float, phys_time); #ifdef CSQC self.s_origin = self.origin; @@ -522,9 +506,6 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, angles[2]); } - if (sendflags & FOPP_MOVETYPE) - COMM(Byte, movetype); - if (sendflags & FOPP_AUX) { COMM(Short, wpp_aux); } @@ -541,11 +522,11 @@ void EntUpdate_Projectile(float isnew) { #undef COMM -void WeapPred_InitDefaultConfig() { +void Predict_InitDefaultConfig() { fo_config.qc_physics = 1; fo_config.static_newmis_ms = 50; fo_config.dynamic_newmis_ms = 0; - fo_config.rewind_flags = 0; + fo_config.rewind_flags = REWIND_DEFAULT_FLAGS; fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 100; fo_config.max_rewind_fast_projectile_ms = 100; @@ -615,8 +596,8 @@ static void WeaponPred_CheckConfigUpdate() { #undef CLAMP_UPDATE #undef CONFIG_UPDATE -void WeaponPred_Init() { - WeapPred_InitDefaultConfig(); +void Predict_Init() { + Predict_InitDefaultConfig(); config_entity = spawn(); @@ -629,7 +610,7 @@ void WeaponPred_Init() { } .float wpp_init; -void WeaponPred_InitPlayer(entity player) { +void Predict_InitPlayer(entity player) { // PutClientInServer is called every spawn. At some point we'll clean up // parameter decode so that it can happen earlier and this nonsense goes // away. @@ -660,7 +641,7 @@ void WeaponPred_InitPlayer(entity player) { player.predict_entity = pe; } -void WeaponPred_TearDown(entity player) { +void Predict_Destroy(entity player) { if (player.predict_entity != __NULL__) dremove(player.predict_entity); } @@ -701,29 +682,7 @@ void PredProj_Sound(int proj_type, float vol = 1) { Pred_Sound(fpp_types[proj_type].snd, vol); } -void WeaponPred_ProjectProjectile(int fpp_type, entity projectile); - -void FO_Phys() { - if (!self.voided) - Phys_Advance(self, time, 0); - - float held_time, thinktime; - // Once we lift physics, think execution comes with it. - do { - thinktime = self.nextthink; - if (thinktime <= 0 || thinktime > time) - return; - - held_time = time; - self.nextthink = 0; - time = thinktime; - self.think(); - time = held_time; - - if (self.is_removed || self.nextthink < thinktime /* no loop on rev */) - return; - } while (1); -} +void Forward_Projectile(int fpp_type, entity projectile); entity FOProj_Create(int fpp_type) { entity prj = spawn(); @@ -767,16 +726,14 @@ void FOProj_Finalize(entity mis) { // We always need to init some of the state here (e.g. phys_time) as we // always use the physics code client-side. if (fo_config.qc_physics) - mis.customphysics = FO_Phys; + mis.customphysics = FO_CustomPhysics; - WeaponPred_ProjectProjectile(mis.fpp_index, mis); + Forward_Projectile(mis.fpp_index, mis); // Below is conditional on using custom SendEntity. if (csqc_networking) { mis.SendEntity = PP_SendEntity; - mis.SendFlags = FOPP_POS | FOPP_INIT; - if (mis.wpp_aux) - mis.SendFlags |= FOPP_AUX; + mis.SendFlags = FOPP_NEW; } else if (fpp_type == FPP_HANDGRENADE) { entity target = self; if (target.classname != "player") @@ -786,15 +743,6 @@ void FOProj_Finalize(entity mis) { } #endif -#ifdef CSQC -float WP_GetAmmo(float ammo_type); -float get_shells() { return WP_GetAmmo(AMMO_SHELLS); } -static inline vector get_origin() { return pmove_org; } -#else -float get_shells() { return self.ammo_shells; } -static inline vector get_origin() { return self.origin; } -#endif - struct ProjectResult { float static_ms; float dynamic_ms; @@ -804,7 +752,7 @@ struct ProjectResult { DEFCVAR_FLOAT(wpp_phys_nudge, 2/3 * SERVER_FRAME_MS); #endif -ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { +ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { float max_ping_credit = max_rewind_credit_ms(fpp_type); float static_credit; @@ -837,47 +785,3 @@ ProjectResult WeaponPred_ProjectOffset(int fpp_type, float ping) { return result; } -// Randomize by ammo index for consistency even if a packet/prediction misses. -float hwguy_random_index; - -void reset_hwguy_random() { - hwguy_random_index = (*prng_state(PRNG_HWGUY) + get_shells() * 211) & 65535; - if (hwguy_random_index == 0) - hwguy_random_index = (get_shells() + 1) * 211; -} - -float hwguy_random() { - float index = hwguy_random_index; - float r = (hwguy_random_index = lfsr_prng_raw(hwguy_random_index)) / 65535.0; - return r; -} - -float hwguy_crandom() { - return 2 * (hwguy_random() - 0.5); -} - -void FO_FireAssCanPellet(vector org, vector spread_dir, float var_speed, int index); - -void WeapPred_FireAssCan(vector vangle, float shotcount, - vector spread) { - vector bullet_dir, spread_dir, rand_dir, org; - float bullet_speed, var_speed; - - reset_hwguy_random(); - - makevectors(vangle); - - // Infront of player model and down towards gun - bullet_speed = fpp_types[FPP_ASSAULT_CANNON].speed; - bullet_dir = v_forward; - - for (int i = 0; i < shotcount; i++) { - var_speed = hwguy_crandom()*10 + bullet_speed; // Slight speed variance - rand_dir = (hwguy_crandom()*spread_x) * v_right + - (hwguy_crandom()*spread_y) * v_up; - spread_dir = bullet_dir + rand_dir; - org = get_origin() + '0 0 10' + rand_dir; - - FO_FireAssCanPellet(org, spread_dir, var_speed, i); - } -} diff --git a/ssqc/client.qc b/ssqc/client.qc index 111d93bf..03cb76b2 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -72,8 +72,8 @@ void () NextLevel; void CSEv_SetPlayerImpulse_f(float n); void StopAssCan(); -void WeaponPred_InitPlayer(entity player); -void WeaponPred_TearDown(entity player); +void Predict_InitPlayer(entity player); +void Predict_Destroy(entity player); void (float n) CSEv_SetPlayerImpulse_f = { bprint(PRINT_HIGH, self.netname, "\n"); @@ -2097,7 +2097,7 @@ void () PutClientInServer = { DecodeLevelParms(); - WeaponPred_InitPlayer(self); + Predict_InitPlayer(self); if (self.playerclass != PC_CIVILIAN && TeamFortress_TeamIsCivilian(self.team_no)) { TeamFortress_ChangeClass(11); @@ -2922,7 +2922,7 @@ void () PlayerPostThink = { self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; - WeaponPred_Update(self); + Predict_Update(); if (self.view_ofs == '0 0 0') { return; @@ -3203,7 +3203,7 @@ void () ClientDisconnect = { UnvoteForMap(self); } - WeaponPred_TearDown(self); + Predict_Destroy(self); }; string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage = { diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index cfa1adaa..a10dda6e 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -27,7 +27,7 @@ float (float force) TeamFortress_DetonatePipebombs = { float rewound = FALSE; if (!force && count > 0) - rewound = AL_RewindPlayersExceptSelf(self.pipecooldown); + rewound = RewindPlayersExceptSelf(self.pipecooldown); for (float i = 0; i < count; i++) { if (pipes[i].owner == self) { diff --git a/ssqc/progs.src b/ssqc/progs.src index 35c57103..402c71f0 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -21,6 +21,7 @@ time.qc ../share/physics.qc ../share/weapons.qc ../share/prediction.qc +../share/classes.qc ../share/animate.qc events.qc roles.qc @@ -36,7 +37,7 @@ help.qc subs.qc items.qc locfiles.qc -antilag.qc +rewind.qc combat.qc weapons.qc world.qc diff --git a/ssqc/antilag.qc b/ssqc/rewind.qc similarity index 79% rename from ssqc/antilag.qc rename to ssqc/rewind.qc index 774e20c7..706a8721 100644 --- a/ssqc/antilag.qc +++ b/ssqc/rewind.qc @@ -1,31 +1,21 @@ -#define DEBUG_ANTILAG 0 +#define DEBUG_REWIND 0 -enumflags { - REWIND_KNOCKBACK, - REWIND_PROJ_HIT, - REWIND_PROJ_SELFKNOCK, -}; - -float RewindFlagEnabled(float flag) { - return fo_config.rewind_flags & flag; -} - -#if DEBUG_ANTILAG -#define al_printf(...) printf(__VA_ARGS__) -#define al_printd(...) dprint(__VA_ARGS__) +#if DEBUG_REWIND +#define rw_printf(...) printf(__VA_ARGS__) +#define rw_printd(...) dprint(__VA_ARGS__) #else -#define al_printf(...) -#define al_printd(...) +#define rw_printf(...) +#define rw_printd(...) #endif -#define AL_MAX_REWINDS 25 +#define MAX_SNAPSHOTS 25 inline int NextRewindIdx(int idx) { - return (idx + 1) % AL_MAX_REWINDS; + return (idx + 1) % MAX_SNAPSHOTS; } inline int PrevRewindIdx(int idx) { - return (idx - 1 + AL_MAX_REWINDS) % AL_MAX_REWINDS; + return (idx - 1 + MAX_SNAPSHOTS) % MAX_SNAPSHOTS; } struct RewindSnapshot { @@ -41,7 +31,7 @@ enum RewindStatus:float { struct RewindState { entity owner; - RewindSnapshot snapshot[AL_MAX_REWINDS]; + RewindSnapshot snapshot[MAX_SNAPSHOTS]; int cur; RewindStatus rewound; @@ -97,7 +87,7 @@ static SeekResult RewindSeek(RewindState* rstate, float rtime) { r.before = r.after = __NULL__; int idx = rstate->cur; - for (int i = 0; i < AL_MAX_REWINDS; i++) { + for (int i = 0; i < MAX_SNAPSHOTS; i++) { RewindSnapshot* rs = &rstate->snapshot[idx]; if (rs->time >= rtime) { @@ -132,7 +122,7 @@ RewindSnapshot* RewindLog(RewindState* target) { } void DumpLog(RewindState* rs) { - for (float i = 0; i < AL_MAX_REWINDS; i++) { + for (float i = 0; i < MAX_SNAPSHOTS; i++) { printf("%s%2d> t=%0.3f\n", i == rs->cur ? "*" : " ", i, rs->snapshot[i].time); } } @@ -217,7 +207,7 @@ static void RewindTo(RewindState* rstate, float rtime) { // TODO: Filter out observers, but no harm immediately. static void RL_RewindTo(RewindState* head, entity exclude, float rtime) { float show_rewind_points = - CF_GetSetting("rds", "rewind_debug_show", DEBUG_ANTILAG ? "on" : "off"); + CF_GetSetting("rds", "rewind_debug_show", DEBUG_REWIND ? "on" : "off"); RL_FOR_EACH(head, rstate) { entity e = rstate->owner; @@ -251,11 +241,19 @@ class FOPlayer { RewindLog(rewind_); }; - void(float when) RewindExcept = { + nonvirtual void(float when) RewindExcept = { RL_StashPositions(rewind_players); RL_RewindTo(rewind_players, this, when); }; + nonvirtual vector() UnrewoundOrigin = { + if (rewind_->rewound == kRewound) { + return rewind_->held_origin; + } else { + return this->origin; + } + }; + static void (float when) RewindAll = { RL_StashPositions(rewind_players); RL_RewindTo(rewind_players, world, when); @@ -264,23 +262,15 @@ class FOPlayer { static void() RestoreAll { RL_RestorePositions(rewind_players); }; - - vector() UnrewoundOrigin = { - if (rewind_->rewound == kRewound) { - return rewind_->held_origin; - } else { - return this->origin; - } - }; }; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; -float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { +float RewindPlayersExceptSelf(float farthest_rewind_point) { if (!antilag_settings.rewind_detpipe) return FALSE; - float rewind_max_offset = (AL_MAX_REWINDS - 1) * SERVER_FRAME_DT; + float rewind_max_offset = (MAX_SNAPSHOTS - 1) * SERVER_FRAME_DT; farthest_rewind_point = max(farthest_rewind_point, time - rewind_max_offset); @@ -296,14 +286,14 @@ float AL_RewindPlayersExceptSelf(float farthest_rewind_point) { return TRUE; } -void ProjRewind(entity e, float step) { +void ProjRewindForPhys(entity e, float step) { RL_RewindTo(rewind_players, e.owner, e.phys_time + step / 2); } -void WeaponPred_ProjectProjectileRewind(int fpp_type, entity proj) { +void Forward_Projectile(int fpp_type, entity proj) { float ping = proj.owner.client_ping; - ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); + ProjectResult offset = Forward_ProjectOffset(fpp_type, ping); float static_dt = offset.static_ms / 1000.0; float dynamic_dt = offset.dynamic_ms / 1000.0; float stime = time - dynamic_dt; @@ -323,39 +313,20 @@ void WeaponPred_ProjectProjectileRewind(int fpp_type, entity proj) { // a prior point in time, but we don't advance time while stepping. proj.s_origin = proj.origin; proj.s_time = 0; - float st = Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); + float ft = Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); // We initialize s_origin/s_time after Phys_Init, they are used when // knockback forwarding is on to determine delay. proj.s_origin = proj.origin; proj.s_time = time; - float dt = 0; if (!proj.voided) { - RewindSyncTime = ProjRewind; - dt = Phys_Advance(proj, time, phys_flags); + RewindSyncTime = ProjRewindForPhys; + ft += Phys_Advance(proj, time, phys_flags); } if (rewind_hit) RL_RestorePositions(rewind_players); - proj.antilag_ms = (st + dt) * 1000; + proj.antilag_ms = ft * 1000; } - -void WeaponPred_ProjectProjectile(int fpp_type, entity proj) { - if (RewindFlagEnabled(REWIND_PROJ_HIT | REWIND_PROJ_SELFKNOCK)) { - WeaponPred_ProjectProjectileRewind(fpp_type, proj); - return; - } - - proj.s_origin = proj.origin; - proj.s_time = time; - float ping = proj.owner.client_ping; - ProjectResult offset = WeaponPred_ProjectOffset(fpp_type, ping); - float static_dt = offset.static_ms / 1000.0; - float dynamic_dt = offset.dynamic_ms / 1000.0; - - float dt = Phys_Init(proj, time, static_dt + dynamic_dt, PHYSF_CONSUME_ALL); - proj.antilag_ms = dt * 1000; -} - diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 0edc2341..26abefb5 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -101,7 +101,7 @@ void () ShockGrenadeExplode = { self.nextthink = time + 0.7; self.playerclass = 0; self.think = NailGrenLaser; - self.SendFlags = FOPP_POS | FOPP_MOVETYPE; + self.SendFlags = FOPP_POS; }; void () BurstGrenadeExplode = { diff --git a/ssqc/world.qc b/ssqc/world.qc index 1bbde10e..569d5b46 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -374,7 +374,7 @@ void () worldspawn = { } dimension_send = DMN_NOFLASH; - WeaponPred_Init(); + Predict_Init(); settings_to_track = memalloc(sizeof(*settings_to_track)*settings_to_track_list.length); for (float i = 0; i < settings_to_track_list.length; i++) From d7ec0c361ca80f197494e67a6dd18b2482a0d5a6 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 09:44:33 -0800 Subject: [PATCH 1903/2474] Enable new rewind behaviors by default Several pugs with no issues. From e74cfefc1ffad53e1df4544230512a02c6ad9263 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 13:46:30 -0800 Subject: [PATCH 1904/2474] I'm rubber, you're glue --- share/commondefs.qc | 4 ++++ share/physics.qc | 35 +++++++++++++++++++++++++++++++---- share/prediction.qc | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 891c95f4..63c85c4b 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -44,6 +44,8 @@ enumflags { CLOWN_RUBBERGREN, CLOWN_PROJ_GRAVITY, CLOWN_LETHAL_TRANQ, + CLOWN_STICKY_GRENS, + CLOWN_STICKY_PIPES, }; string CLOWN_DESC[] = { @@ -51,6 +53,8 @@ string CLOWN_DESC[] = { "rubber grenades", "projectile gravity", "elephant tranq", + "sticky grenades", + "sticky pipes", }; inline float IsClownMode(int flag) { diff --git a/share/physics.qc b/share/physics.qc index 16cb67cc..1c24eeb1 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -21,6 +21,8 @@ static inline float PhysFlagEnabled(float flag) { return fo_config.qc_physics & flag; } +void AugmentGrenadeImpact(); + #ifdef SSQC float Phys_Advance(entity e, float target_time, float phys_flags); @@ -48,9 +50,11 @@ void FO_CustomPhysics() { void Predict_UpdateHack(entity e); static void Phys_Impact(entity e, float dt, float phys_flags) { - if (trace_ent.solid == SOLID_NOT) + other = trace_ent; + if (other.solid == SOLID_NOT) return; + if (e.touch) { if (phys_flags & PHYSF_FORWARD_KNOCK) e.flags |= FL_FORWARD_KNOCK; @@ -62,34 +66,48 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { self = held_self; } + AugmentGrenadeImpact(); + #if PHYS_DEBUG printf("SPhys: Impact t=%0.3f pt=%0.3f [%0.3f]\n", time, e.phys_time + dt, e.phys_time + frametime); printf("Imp: e=%p e.o=%p te=%p\n", e, e.owner, other); #endif +} - if (trace_ent.solid != SOLID_BSP) - Predict_UpdateHack(e); +static vector get_followed_origin() { + return self.aiment.origin; } #else DEFCVAR_FLOAT(fo_phys_debug, 0); .entity groundentity; +.float aiment_num; .float voided; float get_phys_time(entity); static void Phys_Impact(entity e, float dt, float phys_flags) { - if (trace_ent.solid == SOLID_NOT) + other = trace_ent; + if (other.solid == SOLID_NOT) return; if (e.movetype == MOVETYPE_FLYMISSILE) e.voided = TRUE; + AugmentGrenadeImpact(); + if (CVARF(fo_phys_debug) & 1) printf("CPhys: Impact t=%0.3f pt=%0.3f [%0.3f]\n", time, e.phys_time + dt, get_phys_time(e)); } + +static vector get_followed_origin() { + if (!(float)getentity(self.aiment_num, GE_ACTIVE)) + return self.origin; + else + return (vector)getentity(self.aiment_num, GE_ORIGIN); +} #endif static inline float get_gravity() { return cvar("sv_gravity"); } @@ -240,6 +258,15 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { dt = Phys_Adv_Bounce(e, step, phys_flags); break; + case MOVETYPE_FOLLOW: + vector org = get_followed_origin(); + target_time = e.phys_time; + step = target_time - e.phys_time; + dt = step > 0 ?: 0; + + e.origin = org + e.velocity; + break; + default: printf("ERROR: %s unsupported movetype %d\n", e.model, e.movetype); case MOVETYPE_NONE: diff --git a/share/prediction.qc b/share/prediction.qc index 9c4da9f4..0ab78de7 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -506,6 +506,12 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, angles[2]); } + if (sendflags & FOPP_MOVETYPE) { + COMM(Byte, movetype); + if (self.movetype == MOVETYPE_FOLLOW) + COMMD(Entity, aiment_num, aiment); + } + if (sendflags & FOPP_AUX) { COMM(Short, wpp_aux); } @@ -785,3 +791,31 @@ ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { return result; } +void AugmentGrenadeImpact() { + if (!FPP_IsGrenade(self.fpp_index) || self.voided || + self.wpp_aux == GREN_RED) + return; + + float old_move = self.movetype; + + if (IsClownMode(CLOWN_STICKY_PIPES) && other.solid == SOLID_BSP) + self.movetype = MOVETYPE_NONE; + + if (IsClownMode(CLOWN_STICKY_GRENS) && other.solid == SOLID_SLIDEBOX) { + self.movetype = MOVETYPE_FOLLOW; + self.velocity = self.origin - other.origin; +#ifdef SSQC + self.aiment = other; + self.SendFlags |= FOPP_POS; // Need velocity +#else + self.aiment_num = other.entnum; +#endif + } + +#ifdef SSQC + if (other.solid != SOLID_BSP) + Predict_UpdateHack(self); + if (self.movetype != old_move) + self.SendFlags |= FOPP_MOVETYPE; +#endif +} From ba35ecdfb9f3267564be2aaae82888894f34e10d Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 22:14:03 -0800 Subject: [PATCH 1905/2474] Enable new rewind behaviors by default Several pugs without issues (and prior tree got mangled) --- share/commondefs.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 63c85c4b..b917cbf4 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -33,7 +33,8 @@ string REWIND_DESC[] = { "forward projectile self-knockback", }; -const float REWIND_DEFAULT_FLAGS = 0; +const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_HIT | + REWIND_PROJ_SELFKNOCK; float RewindFlagEnabled(float flag) { return fo_config.rewind_flags & flag; From 96936a0fe66bf31b8e9a69cdde4a832196de5942 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 27 Nov 2022 00:06:51 -0800 Subject: [PATCH 1906/2474] Make sure we copy to predict_state and init last full refresh --- share/prediction.qc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/share/prediction.qc b/share/prediction.qc index 0ab78de7..6591ba4b 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -197,8 +197,8 @@ void InitFppProjectiles() { float max_rewind_credit_ms(int fpp_type) { return fpp_types[fpp_type].speed < fo_config.rewind_fast_projectile_thresh ? - fo_config.max_rewind_slow_projectile_ms : - fo_config.max_rewind_fast_projectile_ms; + fo_config.max_rewind_slow_projectile_ms : + fo_config.max_rewind_fast_projectile_ms; } @@ -279,9 +279,6 @@ void Predict_Update() { static float Prediction_ChangedMask(entity player) { float mask = FOWP_CTIME; - if (time - player.last_full_predict_refresh >= 1000 * MSEC) - return 0xFFFFFF; - player.predict_state.client_time = player.client_time; player.predict_state.client_ping = player.client_ping; @@ -297,6 +294,11 @@ static float Prediction_ChangedMask(entity player) { M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]) + if (time - player.last_full_predict_refresh >= 1000 * MSEC) { + player.last_full_predict_refresh = time; + return 0xFFFFFF; + } + return mask; } From b4a2e2c77d944b3bcb45fde5888be23f615ae913 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 27 Nov 2022 14:55:00 -0800 Subject: [PATCH 1907/2474] Finish owner -> owner_entnum conversion --- csqc/weapon_predict.qc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 38f84944..38e5dc88 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -155,7 +155,8 @@ void WPP_Status() { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); float avg, variance; fill_avg_ping(&avg, &variance); - printf(" inst_ping = %d avg_ping = %d var = %d\n", ping, avg, variance); + printf(" inst_ping = %d client_ping = %d avg_ping = %d var = %d\n", + ping, pstate_server.client_ping, avg, variance); printf("Config:\n"); PRINT_CONFIG(qc_physics); @@ -905,7 +906,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { return __NULL__; entity proj = spawn(); - proj.owner = edict_num(player_localentnum); + proj.owner_entnum = player_localentnum; FPP_Init(fpp_type, proj); #if 0 @@ -1214,7 +1215,6 @@ void InitProjectileEnt(float sendflags) { self.predraw = PP_PredrawActive; if (sendflags & FOPP_ANGLES == 0) self.angles = vectoangles(self.velocity); - self.owner = edict_num(self.owner_entnum); FPP_Init(self.fpp_index, self); FPP_ApplyGrenadeProperties(self); From 7d10561af35be25b02d692fd82e8acd787d954ba Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 27 Nov 2022 21:20:31 -0800 Subject: [PATCH 1908/2474] Refactor grenades Rework some of the grenade code so that we can query more properties about grenades (their explosion type and damage). --- share/weapons.qc | 40 +++++++++++++++++++++++++++ ssqc/demoman.qc | 72 +++++++++++++++++------------------------------- ssqc/scout.qc | 12 -------- ssqc/tfort.qc | 18 ++---------- ssqc/weapons.qc | 21 ++++++++++++++ 5 files changed, 89 insertions(+), 74 deletions(-) diff --git a/share/weapons.qc b/share/weapons.qc index 2143de67..5918fb6f 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -168,6 +168,7 @@ enum { GREN_EMP, GREN_FLASH, GREN_CALTROP, + GREN_MIRVLET, GREN_RED, GREN_PIPE, GREN_NONE, @@ -221,10 +222,49 @@ FO_GrenInfo fo_grenades[] = { { GREN_EMP, "EMP", "grenade2.mdl", 4, '300 300 300'}, { GREN_FLASH, "Flash", "flashgren.mdl", 0, '300 300 300'}, { GREN_CALTROP, "Caltrop", "", 0, '300 300 300'}, + { GREN_MIRVLET, "Mirvlet", "grenade2.mdl", 1, '250 300 400'}, { GREN_RED, "Red", "grenade2.mdl", 1, '300 300 300'}, { GREN_PIPE, "Pipe", "grenade2.mdl", 2, '300 300 300'}, }; +enum { + kRadiusDamage, + kRadiusBounce, +}; + +struct FO_GrenExp { + int type; + int dmg; + int deathmsg; + +}; + +float FO_GrenGetExp(int gren_type, __out FO_GrenExp exp) { + exp.type = kRadiusDamage; + switch (gren_type) { + case GREN_NORMAL: + exp.dmg = 180; + exp.deathmsg = DMSG_GREN_HAND; + break; + case GREN_MIRVLET: + exp.dmg = 180; + exp.deathmsg = DMSG_GREN_MIRV; + break; + case GREN_CONC: + exp.dmg = 240; + exp.type = kRadiusBounce; + break; + case GREN_MIRV: + exp.dmg = 100; + exp.deathmsg = DMSG_GREN_MIRV; + break; + default: + return FALSE; + } + + return TRUE; +} + struct FO_ClassGrenades { float id; float gren[2]; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index a10dda6e..4b4b3259 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -3,11 +3,9 @@ //======================================================== void () NormalGrenadeTouch; -void () NormalGrenadeExplode; void () MirvGrenadeTouch; void () MirvGrenadeExplode; -void (vector org, entity shooter) MirvGrenadeLaunch; void () TeamFortress_DetpackMenu; void () TeamFortress_DetpackStop; @@ -62,61 +60,43 @@ void () MirvGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () MirvGrenadeExplode = { - local float i; - - deathmsg = DMSG_GREN_MIRV; - T_RadiusDamage(self, self.owner, 100, world); +static void (vector org, entity shooter) MirvGrenadeLaunch = { + float xdir = 75 * crandom(); + float ydir = 75 * crandom(); + float zdir = 40 * random(); - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); + entity proj = FOProj_Create(FPP_HANDGRENADE); + proj.owner = shooter; + proj.movetype = MOVETYPE_BOUNCE; + proj.solid = SOLID_BBOX; - self.solid = SOLID_NOT; - i = 0; - while (i < 4) { - MirvGrenadeLaunch(self.origin + '0 0 -1', self.owner); - i = i + 1; - } - BecomeExplosion(); - -}; + proj.classname = "grenade"; + proj.touch = NormalGrenadeTouch; + proj.think = FO_T_GrenExplode; + proj.nextthink = time + 2 + random(); -void (vector org, entity shooter) MirvGrenadeLaunch = { - local float xdir; - local float ydir; - local float zdir; + proj.velocity = [xdir * 2, ydir * 2, zdir * 15]; - xdir = 150 * random() - 75; - ydir = 150 * random() - 75; - zdir = 40 * random(); + FO_GrenInfo* gdesc = FO_GrenDesc(GREN_MIRVLET); + proj.gren_type = GREN_MIRVLET; + proj.skin = gdesc->skin; - newmis = spawn(); - newmis.owner = shooter; - newmis.movetype = MOVETYPE_BOUNCE; - newmis.solid = SOLID_BBOX; + setorigin(proj, org); + FOProj_Finalize(proj); +}; - newmis.classname = "grenade"; - newmis.gren_type = GREN_MIRV; - newmis.weapon = DMSG_GREN_MIRV; - newmis.touch = NormalGrenadeTouch; - newmis.think = NormalGrenadeExplode; - newmis.nextthink = time + 2 + random(); +void () MirvGrenadeExplode = { + FO_GrenExplode(self); - newmis.velocity_x = xdir * 2; - newmis.velocity_y = ydir * 2; - newmis.velocity_z = zdir * 15; - newmis.avelocity = '250 300 400'; + self.solid = SOLID_NOT; + for (int i = 0; i < 4; i++) + MirvGrenadeLaunch(self.origin, self.owner); - FO_SetModel(newmis, "progs/grenade2.mdl"); + dremove(self); - setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); - setorigin(newmis, org); }; + void () TeamFortress_DetpackMenu = { local entity detpack; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index f40613d2..3cbf7f22 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -9,7 +9,6 @@ void () FlashGrenadeTouch; void () FlashTimer; void () FlashGrenadeExplode; void () ConcussionGrenadeTouch; -void () ConcussionGrenadeExplode; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; void (entity inflictor, entity attacker, float bounce, @@ -359,17 +358,6 @@ void () ConcussionGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () ConcussionGrenadeExplode = { - T_RadiusBounce(self, self.owner, 240, world); - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - multicast(self.origin, MULTICAST_PHS); - dremove(self); -}; - void () BlastGrenadeTouch = { FO_Sound(self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); if (self.velocity == '0 0 0') diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index a0c45336..63c2f2ed 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -781,20 +781,6 @@ void () NormalGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () NormalGrenadeExplode = { - deathmsg = DMSG_GREN_HAND; - T_RadiusDamage(self, self.owner, 180, world); - - WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); - WriteByte(MSG_MULTICAST, TE_EXPLOSION); - WriteCoord(MSG_MULTICAST, self.origin_x); - WriteCoord(MSG_MULTICAST, self.origin_y); - WriteCoord(MSG_MULTICAST, self.origin_z); - - multicast(self.origin, MULTICAST_PHS); - dremove(self); -}; - void () GrenadeTimer = { self.heat = self.heat - 1; self.nextthink = time + 1; @@ -813,8 +799,8 @@ static struct stg_table_entry { }; stg_table_entry stg_table[] = { - { GREN_NORMAL, NormalGrenadeTouch, NormalGrenadeExplode}, - { GREN_CONC, ConcussionGrenadeTouch, ConcussionGrenadeExplode}, + { GREN_NORMAL, NormalGrenadeTouch, FO_T_GrenExplode}, + { GREN_CONC, ConcussionGrenadeTouch, FO_T_GrenExplode}, { GREN_BLAST, BlastGrenadeTouch, BlastGrenadeExplode}, { GREN_NAIL, NailGrenadeTouch, NailGrenadeExplode}, { GREN_SHOCK, ShockGrenadeTouch, ShockGrenadeExplode}, diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 39278317..c57b6406 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1234,6 +1234,27 @@ void RenderExplosion(vector origin) { WriteCoord(MSG_MULTICAST, origin_z); multicast(origin, MULTICAST_PHS); } +void T_RadiusBounce(entity inflictor, entity attacker, float bounce, + entity ignore); + +// REQUIRES: e.gren_type is set and supported by FO_GrenGetExp +void FO_GrenExplode(entity e) { + FO_GrenExp exp; + ASSERTF_TRUE(FO_GrenGetExp(e.gren_type, exp)); + + deathmsg = exp.deathmsg; + if (exp.type == kRadiusDamage) + T_RadiusDamage(self, self.owner, exp.dmg, world); + else if (exp.type == kRadiusBounce) + T_RadiusBounce(self, self.owner, exp.dmg, world); + + RenderExplosion(e.origin); +} + +void FO_T_GrenExplode() { + FO_GrenExplode(self); + dremove(self); +} void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, entity ignore); From 39ee29d745f236a283d5b6b6dcd7311af4068136 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Nov 2022 15:21:55 -0800 Subject: [PATCH 1909/2474] Clean up FPP code - Unify accessors - Make invalid indexes findable - Get rid of wpp_aux name overloading --- csqc/weapon_predict.qc | 39 ++++++++++++++++---------------- share/classes.qc | 2 +- share/commondefs.qc | 12 ++++++++++ share/prediction.qc | 51 +++++++++++++++++++++--------------------- ssqc/demoman.qc | 2 +- ssqc/engineer.qc | 2 +- ssqc/events.qc | 8 +++---- ssqc/hwguy.qc | 2 +- ssqc/misc.qc | 5 +++-- ssqc/pyro.qc | 4 ++-- ssqc/qw.qc | 1 - ssqc/scout.qc | 2 +- ssqc/spy.qc | 2 +- ssqc/tfort.qc | 6 ++--- ssqc/weapons.qc | 10 ++++----- 15 files changed, 81 insertions(+), 67 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 38e5dc88..da448881 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -818,7 +818,7 @@ DEFCVAR_FLOAT(r_grenadetrail, 0); int FPP_FindTrail(entity e) { int idx = -1; int is_g = 0; - switch (e.fpp_index) { + switch (e.fpp.index) { case FPP_ROCKET: idx = CVARF(r_rockettrail) - 1; break; case FPP_INCENDIARY: idx = CVARF(r_pyrotrail) - 1; break; case FPP_GRENADE: idx = CVARF(r_grenadetrail) - 1; is_g = 1; break; @@ -827,16 +827,16 @@ int FPP_FindTrail(entity e) { if (idx >= 0 && idx < trail_table.length) return trail_table[idx].trail[is_g]; - return fpp_types[e.fpp_index].trailindex; + return FPP_Get(e.fpp.index)->trailindex; } DEFCVAR_FLOAT(cl_p2r, 0); DEFCVAR_FLOAT(cl_r2g, 0); void FPP_Init(int fpp_type, entity proj) { - fo_projectile* desc = &fpp_types[fpp_type]; + fo_projectile* desc = FPP_Get(fpp_type); - proj.fpp_index = fpp_type; + proj.fpp.index = fpp_type; int render_type = fpp_type; // If someone sets both p2r and r2g, we'll convert all the way. @@ -845,7 +845,7 @@ void FPP_Init(int fpp_type, entity proj) { if (render_type == FPP_ROCKET && CVARF(cl_r2g) == 1) render_type = FPP_GRENADE; - setmodelindex(proj, fpp_types[render_type].modelindex); + setmodelindex(proj, FPP_Get(render_type)->modelindex); proj.traileffectnum = FPP_FindTrail(proj); proj.movetype = desc->movetype; @@ -937,15 +937,16 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { setsize(proj, [0,0,0], [0,0,0]); proj.origin = pmove_org + offset; + float proj_speed = FPP_Get(fpp_type)->speed; if (!FPP_IsGrenade(fpp_type)) { - proj.velocity = v_forward * fpp_types[fpp_type].speed; + proj.velocity = v_forward * proj_speed; proj.origin[2] += 16; } else { if (!input_angles_x) { - proj.velocity = v_forward * fpp_types[fpp_type].speed; + proj.velocity = v_forward * proj_speed; proj.velocity_z = 200; } else { - proj.velocity = (v_forward * 600) + + proj.velocity = (v_forward * proj_speed) + (200 + shared_crandom(PRNG_WEAP) * 10) * v_up + (shared_crandom(PRNG_WEAP) * 10 * v_right); } @@ -970,14 +971,14 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { } static void FPP_ApplyGrenadeProperties(entity proj) { - if (!FPP_IsGrenade(proj.fpp_index)) + if (!FPP_IsGrenade(proj.fpp.index)) return; - if (proj.wpp_aux < GREN_FIRST) { + if (proj.fpp.gren_type < GREN_FIRST) { printf("proj (%s) missing gren_type, tell newby\n", proj.model); - proj.wpp_aux = GREN_FIRST; + proj.fpp.gren_type = GREN_FIRST; } - FO_GrenInfo* gdesc = FO_GrenDesc(proj.wpp_aux); + FO_GrenInfo* gdesc = FO_GrenDesc(proj.fpp.gren_type); setmodelindex(proj, gdesc->modelindex); proj.skin = gdesc->skin; @@ -986,7 +987,7 @@ static void FPP_ApplyGrenadeProperties(entity proj) { void W_FireGrenade(int gren_type) { entity proj = PP_CreateProjectile(FPP_GRENADE, '0 0 0'); - proj.wpp_aux = gren_type; + proj.fpp.gren_type = gren_type; FPP_ApplyGrenadeProperties(proj); } @@ -1045,7 +1046,7 @@ static void W_ThrowGren(float is_throw) { if (IsEffectFrame()) { entity gren = PP_CreateProjectile(FPP_HANDGRENADE, '0 0 0'); int index = (pstate_pred.tfstate & TFSTATE_GREN1_PRIMED) ? 0 : 1; - gren.wpp_aux = FO_ClassGren(pstate_pred.playerclass, index)->id; + gren.fpp.gren_type = FO_ClassGren(pstate_pred.playerclass, index)->id; FPP_ApplyGrenadeProperties(gren); } @@ -1066,7 +1067,7 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { proj.skin = 16 + hwguy_random() * 7; proj.velocity = dir * proj_speed; proj.angles = vectoangles(dir); - proj.wpp_aux = WP_GetAmmo(AMMO_SHELLS) * 100 + index; + proj.fpp.ammo_index = WP_GetAmmo(AMMO_SHELLS) * 100 + index; } void WP_Attack() { @@ -1168,7 +1169,7 @@ float PredProjectile_MatchProjectile() { if (proj == self) error("???"); - if (proj.fpp_index != self.fpp_index || proj.wpp_aux != self.wpp_aux) + if (proj.fpp.index != self.fpp.index || proj.fpp.aux != self.fpp.aux) continue; if (time > proj.endtime - 0.01) @@ -1188,7 +1189,7 @@ float PredProjectile_MatchProjectile() { self.p_time = match.p_time; self.trail_started = match.trail_started; - if (FPP_IsGrenade(self.fpp_index)) + if (FPP_IsGrenade(self.fpp.index)) self.angles = match.angles; if (CVARF(wpp_debug) & 1) { @@ -1216,7 +1217,7 @@ void InitProjectileEnt(float sendflags) { if (sendflags & FOPP_ANGLES == 0) self.angles = vectoangles(self.velocity); - FPP_Init(self.fpp_index, self); + FPP_Init(self.fpp.index, self); FPP_ApplyGrenadeProperties(self); float ptime = get_phys_time(self); @@ -1234,7 +1235,7 @@ void InitProjectileEnt(float sendflags) { if (WP_Enabled() && !has_predicted && self.s_time > last_pred_sound + PP_EPS/2) // Missing projectile implies we missed the local sound, patch it up. - PredProj_Sound(self.fpp_index); + PredProj_Sound(self.fpp.index); } if (!has_predicted) { diff --git a/share/classes.qc b/share/classes.qc index f5817ab5..10f0448e 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -64,7 +64,7 @@ void WeapPred_FireAssCan(vector vangle, float shotcount, makevectors(vangle); // In front of player model and down towards gun - bullet_speed = fpp_types[FPP_ASSAULT_CANNON].speed; + bullet_speed = FPP_Get(FPP_ASSAULT_CANNON)->speed; bullet_dir = v_forward; for (int i = 0; i < shotcount; i++) { diff --git a/share/commondefs.qc b/share/commondefs.qc index b917cbf4..565debb1 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,3 +1,15 @@ +struct FPPState { + int index; + + union { + int aux; + int gren_type; + int ammo_index; + }; +}; + +.FPPState fpp; + var struct { float qc_physics; float static_newmis_ms; diff --git a/share/prediction.qc b/share/prediction.qc index 6591ba4b..a7cf8077 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -3,7 +3,6 @@ #define ENT_PROJECTILE 102 // Below apply to both CSQC & SSQC ents -.float fpp_index; // Projectile type .float antilag_ms; string wp_version = "v0.4-phys"; @@ -94,7 +93,7 @@ struct fo_predsnd { string sound; }; -fo_predsnd snd_types[] = { +static fo_predsnd snd_types[] = { { SND_AXE, "ax1.wav" }, { SND_SG, "guncock.wav" }, { SND_SSG, "shotgn2.wav" }, @@ -113,7 +112,9 @@ fo_predsnd snd_types[] = { }; enum { - FPP_ROCKET, + FPP_NONE, + FPP_FIRST = 50, + FPP_ROCKET = FPP_FIRST, FPP_GRENADE, // Grenade launcher FPP_HANDGRENADE, // TF Grenade FPP_INCENDIARY, @@ -139,7 +140,7 @@ struct fo_projectile { float trailindex; }; -fo_projectile fpp_types[] = { +static fo_projectile fpp_types[] = { { FPP_ROCKET, MOVETYPE_FLYMISSILE, PC_SOLDIER_ROCKET_SPEED, "missile.mdl", "t_rocket", SND_RL, TRUE }, { FPP_GRENADE, MOVETYPE_BOUNCE, 600, @@ -162,7 +163,7 @@ fo_projectile fpp_types[] = { "proj_diam2.mdl", "tr_asscan", SND_NONE /* in anim */ }, }; -inline fo_projectile* FPP_Get(int fpp_type) { return &fpp_types[fpp_type]; } +inline fo_projectile* FPP_Get(int fpp_type) { return &fpp_types[fpp_type - FPP_FIRST]; } inline fo_predsnd* Snd_Get(int snd_type) { return &snd_types[snd_type - SND_FIRST]; } inline fo_predsnd* FPP_Sound(int fpp_type) { return Snd_Get(FPP_Get(fpp_type)->snd); } @@ -170,7 +171,6 @@ inline float FPP_IsGrenade(int fpp_type) { return fpp_type == FPP_GRENADE || fpp_type == FPP_HANDGRENADE; } -// `wpp_aux` disambiguation for FPP_GRENADE projectiles. void InitFppProjectiles() { float i; static int once; @@ -179,7 +179,7 @@ void InitFppProjectiles() { for (i = 0; i < fpp_types.length; i++) { fo_projectile* desc = &fpp_types[i]; - ASSERTD_EQ(i, desc->id); + ASSERTD_EQ(i + FPP_FIRST, desc->id); desc->model = strcat("progs/", desc->model); desc->modelindex = getmodelindex(desc->model); if (desc->trail != "") @@ -196,7 +196,7 @@ void InitFppProjectiles() { } float max_rewind_credit_ms(int fpp_type) { - return fpp_types[fpp_type].speed < fo_config.rewind_fast_projectile_thresh ? + return FPP_Get(fpp_type)->speed < fo_config.rewind_fast_projectile_thresh ? fo_config.max_rewind_slow_projectile_ms : fo_config.max_rewind_fast_projectile_ms; } @@ -226,7 +226,6 @@ inline float dynamic_newmis_ms() { inline float fixed_newmis_ms(int fpp_type) { return fo_config.static_newmis_ms; } -.float wpp_aux; #ifdef SSQC @@ -466,7 +465,7 @@ void EntUpdate_WeaponPred(float isnew) { float PP_SendEntity(entity to_player, float sendflags) { if (sendflags & FOPP_NEW) { sendflags = FOPP_INIT | FOPP_POS; - if (self.wpp_aux) + if (self.fpp.aux) sendflags |= FOPP_AUX; } @@ -481,11 +480,15 @@ void EntUpdate_Projectile(float isnew) { float sendflags = readbyte(); #endif if (sendflags & FOPP_INIT) { - COMM(Byte, fpp_index); + COMM(Byte, fpp.index); COMM(Short, antilag_ms); COMMD(Entity, owner_entnum, owner); } + if (sendflags & FOPP_AUX) { + COMM(Short, fpp.aux); + } + if (sendflags & FOPP_POS) { COMM(Coord, origin[0]); COMM(Coord, origin[1]); @@ -514,9 +517,6 @@ void EntUpdate_Projectile(float isnew) { COMMD(Entity, aiment_num, aiment); } - if (sendflags & FOPP_AUX) { - COMM(Short, wpp_aux); - } #ifdef SSQC return TRUE; @@ -687,7 +687,7 @@ void Pred_Sound(SoundIndex snd, float vol = 1) { } void PredProj_Sound(int proj_type, float vol = 1) { - Pred_Sound(fpp_types[proj_type].snd, vol); + Pred_Sound(FPP_Get(proj_type)->snd, vol); } void Forward_Projectile(int fpp_type, entity projectile); @@ -695,16 +695,16 @@ void Forward_Projectile(int fpp_type, entity projectile); entity FOProj_Create(int fpp_type) { entity prj = spawn(); - prj.fpp_index = fpp_type; + prj.fpp.index = fpp_type; prj.dimension_seen = DMN_NOFLASH; - setmodel(prj, fpp_types[fpp_type].model); + setmodel(prj, FPP_Get(fpp_type)->model); setsize(prj, '0 0 0', '0 0 0'); return prj; } void FOProj_Finalize(entity mis) { - int fpp_type = mis.fpp_index; + int fpp_type = mis.fpp.index; // We explicitly do not use newmis. Newmis internally implements a fixed // 50m forward of physics handling (equivalent to our projection below) // which cannot be nicely unwound or accounted for.ammo_shells @@ -719,12 +719,12 @@ void FOProj_Finalize(entity mis) { float csqc_networking = fo_projectiles; if (FPP_IsGrenade(fpp_type)) { - FO_GrenInfo* gdesc = FO_GrenDesc(mis.gren_type); + FO_GrenInfo* gdesc = FO_GrenDesc(mis.fpp.gren_type); setmodel(mis, gdesc->model); mis.avelocity = gdesc->avelocity; mis.skin = gdesc->skin; - mis.wpp_aux = gdesc->id; + mis.fpp.gren_type = gdesc->id; // If we don't have physics synchronized between client and server, use // engine-side for both. @@ -736,7 +736,7 @@ void FOProj_Finalize(entity mis) { if (fo_config.qc_physics) mis.customphysics = FO_CustomPhysics; - Forward_Projectile(mis.fpp_index, mis); + Forward_Projectile(mis.fpp.index, mis); // Below is conditional on using custom SendEntity. if (csqc_networking) { @@ -764,7 +764,7 @@ ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { float max_ping_credit = max_rewind_credit_ms(fpp_type); float static_credit; - if (fpp_types[fpp_type].fixed_project) { + if (FPP_Get(fpp_type)->fixed_project) { static_credit = fixed_newmis_ms(fpp_type); } else { static_credit = static_newmis_ms(fpp_type); @@ -794,13 +794,14 @@ ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { } void AugmentGrenadeImpact() { - if (!FPP_IsGrenade(self.fpp_index) || self.voided || - self.wpp_aux == GREN_RED) + if (!FPP_IsGrenade(self.fpp.index) || self.voided || + self.fpp.gren_type == GREN_RED) return; float old_move = self.movetype; - if (IsClownMode(CLOWN_STICKY_PIPES) && other.solid == SOLID_BSP) + if (IsClownMode(CLOWN_STICKY_PIPES) && self.fpp.gren_type == GREN_PIPE && + other.solid == SOLID_BSP) self.movetype = MOVETYPE_NONE; if (IsClownMode(CLOWN_STICKY_GRENS) && other.solid == SOLID_SLIDEBOX) { diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 4b4b3259..cb2b76eb 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -78,7 +78,7 @@ static void (vector org, entity shooter) MirvGrenadeLaunch = { proj.velocity = [xdir * 2, ydir * 2, zdir * 15]; FO_GrenInfo* gdesc = FO_GrenDesc(GREN_MIRVLET); - proj.gren_type = GREN_MIRVLET; + proj.fpp.gren_type = GREN_MIRVLET; proj.skin = gdesc->skin; setorigin(proj, org); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 705be172..1255aa27 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -95,7 +95,7 @@ void () W_FireRailgun = { proj.solid = SOLID_TRIGGER; - proj.velocity = vec * fpp_types[FPP_RAILGUN].speed; + proj.velocity = vec * FPP_Get(FPP_RAILGUN)->speed; proj.angles = vectoangles(proj.velocity); proj.nextthink = time + 5; diff --git a/ssqc/events.qc b/ssqc/events.qc index cd95d1c6..cf949a11 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -186,8 +186,8 @@ void (entity attacker, entity target, entity inflictor, float damage, float true if (damageKind == "damageTeam") return; } - else if (inflictorId == "grenade" && inflictor.gren_type >= GREN_FIRST) - inflictorId = FO_GrenDesc(inflictor.gren_type)->logname; + else if (inflictorId == "grenade" && inflictor.fpp.gren_type >= GREN_FIRST) + inflictorId = FO_GrenDesc(inflictor.fpp.gren_type)->logname; } @@ -285,8 +285,8 @@ void (entity attacker, entity target, entity inflictor) LogEventKill = { attackername = "world"; else if (inflictorId == "building_sentrygun") attackername = getEntityNameOrLogin(attacker.real_owner); - else if (inflictorId == "grenade" && inflictor.gren_type >= GREN_FIRST) - inflictorId = FO_GrenDesc(inflictor.gren_type)->logname; + else if (inflictorId == "grenade" && inflictor.fpp.gren_type >= GREN_FIRST) + inflictorId = FO_GrenDesc(inflictor.fpp.gren_type)->logname; } local string event; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index 6b4ada11..ae6caade 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -81,7 +81,7 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) proj.angles = vectoangles(dir); // Create direction angle setorigin (proj, org); // Move to starting position - proj.wpp_aux = self.ammo_shells * 100 + index; + proj.fpp.ammo_index = self.ammo_shells * 100 + index; FOProj_Finalize(proj); } diff --git a/ssqc/misc.qc b/ssqc/misc.qc index 13857a30..cd290ca2 100644 --- a/ssqc/misc.qc +++ b/ssqc/misc.qc @@ -314,11 +314,12 @@ void (vector org, vector dir) launch_spike = { newmis.classname = "spike"; newmis.think = SUB_Remove; newmis.nextthink = time + 6; - FO_SetModel(newmis, fpp_types[FPP_NAIL].model); + fo_projectile* fdesc = FPP_Get(FPP_NAIL); + FO_SetModel(newmis, fdesc->model); setsize(newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin(newmis, org); - newmis.velocity = dir * fpp_types[FPP_NAIL].speed; + newmis.velocity = dir * fdesc->speed; }; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 75188c09..3afd7537 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -556,7 +556,7 @@ void () W_FireFlame = { flame.velocity = aim(self, 10000); if (pyro_type == PYRO_FO) { - flame.velocity = flame.velocity * fpp_types[FPP_FLAMETHROWER].speed; + flame.velocity = flame.velocity * FPP_Get(FPP_FLAMETHROWER)->speed; flame.nextthink = time + 0.15; } else @@ -692,7 +692,7 @@ void () W_FireIncendiaryCannon = { } else { - proj.velocity = proj.velocity * fpp_types[FPP_INCENDIARY].speed; + proj.velocity = proj.velocity * FPP_Get(FPP_INCENDIARY)->speed; proj.think = IncendiaryRadius_OZTF; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index d2e7b06b..043e14f7 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -753,7 +753,6 @@ float gametime; string gametimestamp; float logfilehandle; float canlog; -.int gren_type; .float classtime; .float goalrunningtime; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 3cbf7f22..6857f80a 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -102,7 +102,7 @@ void () ScatterCaltrops = { while (num > 0) { e = spawn(); e.classname = "grenade"; - e.gren_type = GREN_CALTROP; + e.fpp.gren_type = GREN_CALTROP; e.weapon = 10; e.owner = self.owner; e.team_no = self.owner.team_no; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index f176c394..bb20c3a9 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1083,7 +1083,7 @@ void () W_FireTranq = { proj.solid = 2; makevectors(self.v_angle); proj.velocity = v_forward; - proj.velocity = proj.velocity * fpp_types[FPP_TRANQ].speed; + proj.velocity = proj.velocity * FPP_Get(FPP_TRANQ)->speed; proj.angles = vectoangles(proj.velocity); proj.touch = T_TranqDartTouch; proj.think = SUB_Remove; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 63c2f2ed..504bc539 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -852,7 +852,7 @@ void (entity timer) FO_SpawnThrownGrenade = { FO_GrenInfo* gdesc = FO_GrenDesc(gtype); stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; - proj.gren_type = gtype; + proj.fpp.gren_type = gtype; proj.skin = gdesc->skin; proj.touch = ste->touch; proj.think = ste->think; @@ -930,7 +930,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { newmis.movetype = 6; newmis.solid = 2; newmis.classname = "grenade"; - newmis.gren_type = GREN_FLARE; + newmis.fpp.gren_type = GREN_FLARE; makevectors(self.v_angle); newmis.velocity = (v_forward * 600) + (v_up * 25); newmis.velocity = newmis.velocity * 700; @@ -998,7 +998,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { newmis.movetype = 6; newmis.solid = 2; newmis.classname = "grenade"; - newmis.gren_type = GREN_FLARE; + newmis.fpp.gren_type = GREN_FLARE; makevectors(self.v_angle); if (self.v_angle_x) { newmis.velocity = v_forward * 1200 + v_up * 200; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index c57b6406..6544ae0a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1121,7 +1121,7 @@ void () W_FireRocket = { proj.solid = SOLID_BBOX; makevectors(self.v_angle); - proj.velocity = v_forward * fpp_types[FPP_ROCKET].speed; + proj.velocity = v_forward * FPP_Get(FPP_ROCKET)->speed; proj.angles = vectoangles(proj.velocity); proj.touch = T_MissileTouch; @@ -1240,7 +1240,7 @@ void T_RadiusBounce(entity inflictor, entity attacker, float bounce, // REQUIRES: e.gren_type is set and supported by FO_GrenGetExp void FO_GrenExplode(entity e) { FO_GrenExp exp; - ASSERTF_TRUE(FO_GrenGetExp(e.gren_type, exp)); + ASSERTF_TRUE(FO_GrenGetExp(e.fpp.gren_type, exp)); deathmsg = exp.deathmsg; if (exp.type == kRadiusDamage) @@ -1346,7 +1346,7 @@ void () W_FireGrenade = { proj.classname = "grenade"; proj.touch = GrenadeTouch; proj.nextthink = time + 2.5; - proj.gren_type = GREN_RED; + proj.fpp.gren_type = GREN_RED; } else { if (old_pipecooldown) self.pipecooldown = time + 0.8; @@ -1358,7 +1358,7 @@ void () W_FireGrenade = { proj.nextthink = time + 120; proj.weapon = 11; proj.team_no = self.team_no; - proj.gren_type = GREN_PIPE; + proj.fpp.gren_type = GREN_PIPE; } makevectors(self.v_angle); if (self.v_angle_x) { @@ -1393,7 +1393,7 @@ entity (int fpp_type, vector offset) W_FireNail = { proj.nextthink = time + 6; setorigin(proj, self.origin + offset + '0 0 16'); - proj.velocity = aim(self, 1000) * fpp_types[fpp_type].speed; + proj.velocity = aim(self, 1000) * FPP_Get(fpp_type)->speed; if (fpp_type == FPP_NAIL) { proj.weapon = DMSG_NAILGUN; From c52d1d5829364843616ee632bca6ac4362ceb586 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Nov 2022 16:49:20 -0800 Subject: [PATCH 1910/2474] Fix concussion speed bump Was tracelining to an arbitrary endpoint so actual intersection was dependent on BSP layout. --- ssqc/scout.qc | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 6857f80a..7bd62546 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -721,42 +721,25 @@ void () TeamFortress_Scan = { void CussSpeedBump() { - entity p; - p = self.owner; + entity p = self.owner; self.nextthink = time + .3; - if (!self.cnt2) - { + if (!self.cnt) { makevectors(p.v_angle); // if medic within x units of ground, slow - traceline(p.origin, (v_up * -1000), MOVE_NOMONSTERS, p); - - if (vlen(p.origin - trace_endpos) <= 100) - { - // near ground - self.cnt2 = 1; - } - } - - if (self.cnt2) - { - self.cnt = self.cnt + 1; + traceline(p.origin, p.origin - 100 * v_up, MOVE_NOMONSTERS, p); + if (trace_fraction < 1) // Found ground + self.cnt = TRUE; + } else { + self.cnt2++; if (vlen(p.velocity) > 1000) - { - if (self.cnt < 10) - { - p.velocity = p.velocity *.9; - } - } + p.velocity *= 0.9; } - - if (self.cnt >= 10) - { + if (self.cnt2 > 9) dremove(self); - } } void (entity inflictor, entity attacker, float bounce, From f147b4773d2c5cf106c8788e7b9adfcb1e3715b3 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Nov 2022 17:13:27 -0800 Subject: [PATCH 1911/2474] Fix rewind to super-present picking up wrong origin --- ssqc/rewind.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 706a8721..f201c59e 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -179,7 +179,7 @@ static void RewindTo(RewindState* rstate, float rtime) { if (!a) { a_time = time; - a_origin = self.origin; + a_origin = e.origin; } else { a_time = a->time; a_origin = a->origin; From a59c0fe90c21bd7124e882b444e863385fe92fab Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Nov 2022 17:13:27 -0800 Subject: [PATCH 1912/2474] Fix rewind to super-present picking up wrong origin --- csqc/weapon_predict.qc | 32 +++++++++++++++++++++++++++++++- share/physics.qc | 2 +- share/prediction.qc | 21 ++------------------- ssqc/rewind.qc | 2 +- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index da448881..f9730031 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -8,6 +8,24 @@ DEFCVAR_FLOAT(wpp_proj_predict, -1); DEFCVAR_FLOAT(wpp_phys_adv_ms, 0); DEFCVAR_FLOAT(wpp_phys_local_adv_ms, SERVER_FRAME_MS); +struct pengine_t { + float pp_enabled; + float wp_enabled; + float is_effectframe; + float last_effectframe; + + entity player_ent; + entity pweap_ent; + + // Must include MASK_PRED_VIEWMODEL or we lose updates. + // We only add/remove MASK_VIEWMODEL and MASK_PRED_PROJECTILE + float view_mask; +} pengine; + +inline float PP_Enabled() { return pengine.pp_enabled; } +inline float WP_Enabled() { return pengine.wp_enabled; } +inline float WPP_ViewModelMask() { return pengine.view_mask; } + float WP_MinPing() { if (CVARF(wpp_min_ping) == -1) return fo_config.wp_default_min_ping_ms; @@ -86,6 +104,11 @@ static float CalcPredEnabled(float current_enable, return FALSE; } + if (is_observer) { + *set_by = "[observer]"; + return FALSE; + } + if (server_disable || client_value == 0) { *set_by = server_disable ? "[server disable]" : "[cvar disable]"; @@ -231,6 +254,7 @@ void WPP_UpdateEnable(float force) { printf("FortressOne: Weapon prediction %s %s\n", wp_new ? "enabled" : "disabled", wp_source); pengine.wp_enabled = wp_new; + pengine.player_ent = edict_num(player_localentnum); } if (pp_new != pengine.pp_enabled || !once) { @@ -240,6 +264,7 @@ void WPP_UpdateEnable(float force) { } once = TRUE; + float wpp_status = (pengine.wp_enabled ? CSQC_WEAP_PRED : 0) + (pengine.pp_enabled ? CSQC_PROJ_PRED : 0); setlocaluserinfo(0, "fo_wpp_status", ftos(wpp_status)); @@ -907,6 +932,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { entity proj = spawn(); proj.owner_entnum = player_localentnum; + proj.owner = pengine.player_ent; FPP_Init(fpp_type, proj); #if 0 @@ -1220,6 +1246,9 @@ void InitProjectileEnt(float sendflags) { FPP_Init(self.fpp.index, self); FPP_ApplyGrenadeProperties(self); + if (self.owner_entnum == player_localentnum) + self.owner = pengine.player_ent; + float ptime = get_phys_time(self); if (ptime > self.phys_time /* from server */) Phys_Advance(self, ptime, 0); @@ -1343,6 +1372,7 @@ void InitWeapPredEnt(entity pe) { self.drawmask = MASK_PRED_VIEWMODEL; self.renderflags = RF_VIEWMODEL; - pengine.pweap_ent = self; + pe.owner = pengine.player_ent; + pengine.pweap_ent = pe; } diff --git a/share/physics.qc b/share/physics.qc index 1c24eeb1..3df323d4 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -122,7 +122,7 @@ float Phys_Push(entity e, vector offset, float dt, float phys_flags) { // Note: Networked entities don't currently intersect on CSQC instantiation // of this, we fudge this in Phys_Impact from the server side. - traceline(e.origin, e.origin + offset, trace_flags, e); + traceline(e.origin, e.origin + offset, trace_flags, e.owner); if ((phys_flags & PHYSF_FAIL_STARTSOLID) && trace_startsolid) return FALSE; diff --git a/share/prediction.qc b/share/prediction.qc index a7cf8077..6b69d970 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -234,23 +234,6 @@ inline float fixed_newmis_ms(int fpp_type) { #else -struct pengine_t { - float pp_enabled; - float wp_enabled; - float is_effectframe; - float last_effectframe; - - entity pweap_ent; - - // Must include MASK_PRED_VIEWMODEL or we lose updates. - // We only add/remove MASK_VIEWMODEL and MASK_PRED_PROJECTILE - float view_mask; -} pengine; - -inline float PP_Enabled() { return pengine.pp_enabled; } -inline float WP_Enabled() { return pengine.wp_enabled; } -inline float WPP_ViewModelMask() { return pengine.view_mask; } - predict_tf_state pstate_pred, pstate_server; #define MASK_PRED_VIEWMODEL 256 #define MASK_PRED_PROJECTILE 512 @@ -497,7 +480,6 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, velocity[1]); COMM(Coord, velocity[2]); - COMM(Byte, movetype); COMM(Float, phys_time); #ifdef CSQC self.s_origin = self.origin; @@ -809,7 +791,8 @@ void AugmentGrenadeImpact() { self.velocity = self.origin - other.origin; #ifdef SSQC self.aiment = other; - self.SendFlags |= FOPP_POS; // Need velocity + self.SendFlags |= FOPP_POS | FOPP_MOVETYPE; // Need velocity for + // offset #else self.aiment_num = other.entnum; #endif diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 706a8721..f201c59e 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -179,7 +179,7 @@ static void RewindTo(RewindState* rstate, float rtime) { if (!a) { a_time = time; - a_origin = self.origin; + a_origin = e.origin; } else { a_time = a->time; a_origin = a->origin; From 62729f7e4afccf2801bf6186589aacd4b658e106 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Nov 2022 23:15:26 -0800 Subject: [PATCH 1913/2474] More cleanup and tuning of weapon_pred --- csqc/csextradefs.qc | 1 + csqc/main.qc | 1 + csqc/weapon_predict.qc | 52 ++++++++++++++++++++++++++++++------------ share/prediction.qc | 7 ++---- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9047c3e4..1570fd29 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -576,6 +576,7 @@ float team_no; float is_spectator; float player_class; float is_observer; +float is_player; //float health; float oldhealth; float painfinished; diff --git a/csqc/main.qc b/csqc/main.qc index a71ba829..24d57653 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -486,6 +486,7 @@ void _Sync_ServerCommandFrame() { is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) is_observer = FALSE; + is_player = !is_spectator && !is_observer; vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), getstatf(STAT_VELOCITY_Z)]; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f9730031..f73723ae 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -6,7 +6,7 @@ DEFCVAR_FLOAT(wpp_weap_predict, -1); DEFCVAR_FLOAT(wpp_proj_predict, -1); DEFCVAR_FLOAT(wpp_phys_adv_ms, 0); -DEFCVAR_FLOAT(wpp_phys_local_adv_ms, SERVER_FRAME_MS); +DEFCVAR_FLOAT(wpp_phys_local_adv_ms, 0); struct pengine_t { float pp_enabled; @@ -14,6 +14,7 @@ struct pengine_t { float is_effectframe; float last_effectframe; + float player_entnum; // player_localentnum iff is_player == 1 entity player_ent; entity pweap_ent; @@ -254,7 +255,15 @@ void WPP_UpdateEnable(float force) { printf("FortressOne: Weapon prediction %s %s\n", wp_new ? "enabled" : "disabled", wp_source); pengine.wp_enabled = wp_new; - pengine.player_ent = edict_num(player_localentnum); + + if (wp_new) { + entity player = edict_num(player_localentnum); + pengine.player_entnum = player_localentnum; + pengine.player_ent = player; + pengine.pweap_ent.owner = player; + } else { + pengine.player_entnum = -1; + } } if (pp_new != pengine.pp_enabled || !once) { @@ -791,13 +800,28 @@ trail_table_entry trail_table[] = { {{"TE_RAILTRAIL"}}, }; +inline float interp_ms() { + return (clientcommandframe - servercommandframe) * SERVER_FRAME_MS; +} + +inline float interp_dt() { + return interp_ms() / 1000.0; +} + +inline float interp_time() { + return time + interp_dt(); +} + float get_phys_time_nudge_dt(entity e) { - float nudge, adj_ping = max(pstate_pred.client_ping, 0); - if (e.owner_entnum != player_localentnum) + if (!is_player) + return 0; + + float nudge; + if (e.owner_entnum != pengine.player_entnum) nudge = CVARF(wpp_phys_adv_ms); else nudge = CVARF(wpp_phys_local_adv_ms); - return min(nudge, adj_ping) / 1000.0; + return min(nudge, interp_ms()) / 1000.0; } inline float get_phys_time(entity e) { @@ -946,16 +970,17 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { return __NULL__; #endif - ProjectResult push_t = - Forward_ProjectOffset(fpp_type, pstate_pred.client_ping); + ProjectResult push_t = Forward_ProjectOffset(fpp_type, interp_ms()); - float uncorrected_dt = (pstate_pred.client_ping - push_t.dynamic_ms) / 1000.0; + // Using interp_ms() to predict which packet it will arrive in, while using + // client_ping to predict when that packet will arrive, seems to produce + // more consistent results, possibly due to batching. + float uncorrected_dt = (pstate_server.client_ping - push_t.dynamic_ms) / 1000.0; float static_dt = push_t.static_ms / 1000.0; // Note: We use true time here as created projectiles exist outside of pred. proj.starttime = time + uncorrected_dt; proj.s_time = proj.starttime - static_dt; - proj.endtime = proj.starttime + pstate_pred.client_ping / 1000.0 + PP_EPS; - + proj.endtime = proj.starttime + pstate_server.client_ping / 1000.0 + PP_EPS; proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; @@ -1201,7 +1226,7 @@ float PredProjectile_MatchProjectile() { if (time > proj.endtime - 0.01) break; // Projectile list is time ordered - Phys_Advance(proj, get_phys_time(proj), 0); + Phys_Advance(proj, get_phys_time(proj), PHYSF_CONSUME_ALL); float d = vlen(proj.origin - self.origin); if (!best || d < best) { @@ -1246,7 +1271,7 @@ void InitProjectileEnt(float sendflags) { FPP_Init(self.fpp.index, self); FPP_ApplyGrenadeProperties(self); - if (self.owner_entnum == player_localentnum) + if (self.owner_entnum == pengine.player_entnum) self.owner = pengine.player_ent; float ptime = get_phys_time(self); @@ -1259,7 +1284,7 @@ void InitProjectileEnt(float sendflags) { // flight projectiles on the transition. This is effectively a nop in the // off case since the projectile list will just be empty. float has_predicted = FALSE; - if (self.owner_entnum == player_localentnum) { + if (self.owner_entnum == pengine.player_entnum) { has_predicted = PredProjectile_MatchProjectile(); if (WP_Enabled() && !has_predicted && self.s_time > last_pred_sound + PP_EPS/2) @@ -1372,7 +1397,6 @@ void InitWeapPredEnt(entity pe) { self.drawmask = MASK_PRED_VIEWMODEL; self.renderflags = RF_VIEWMODEL; - pe.owner = pengine.player_ent; pengine.pweap_ent = pe; } diff --git a/share/prediction.qc b/share/prediction.qc index 6b69d970..5c7f66e1 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -738,10 +738,6 @@ struct ProjectResult { float dynamic_ms; }; -#ifdef CSQC -DEFCVAR_FLOAT(wpp_phys_nudge, 2/3 * SERVER_FRAME_MS); -#endif - ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { float max_ping_credit = max_rewind_credit_ms(fpp_type); float static_credit; @@ -763,7 +759,8 @@ ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { #ifdef CSQC // Account for the fact that the server usually has a physics frame that's // going to be credited to the new projectile. - frame_nudge = fo_config.qc_physics ? CVARF(wpp_phys_nudge) : 1.5 * SERVER_FRAME_MS; + if (!fo_config.qc_physics) + frame_nudge = SERVER_FRAME_MS * 1.5; #endif // Everything lower than SERVER_FRAME_MS falls into the next frame (and we // have no resolution anyway), linearize beyond that. From 1b2637261ebb75532e93fee9d82b09214830174a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Nov 2022 23:57:16 -0800 Subject: [PATCH 1914/2474] Add support for forwarding door opening by ping Opens doors in time (up to 150 ping) for remote clients to see them opening on server side and pmove not to stick on them. Requires `localinfo rfd=1` (must be set *before* map load) and `rewind & 4` to enable. --- share/commondefs.qc | 2 ++ share/prediction.qc | 15 +++++++++++++++ ssqc/client.qc | 1 + ssqc/rewind.qc | 16 ++++++++++++++++ ssqc/triggers.qc | 2 ++ 5 files changed, 36 insertions(+) diff --git a/share/commondefs.qc b/share/commondefs.qc index 565debb1..255c7fd7 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -36,12 +36,14 @@ var struct { enumflags { REWIND_KNOCKBACK, REWIND_PROJ_HIT, + REWIND_FORWARD_DOORS, REWIND_PROJ_SELFKNOCK, }; string REWIND_DESC[] = { "rewind pipe knockback", "rewind projectile hit", + "open doors earlier for hpbs [requires rfd=1]", "forward projectile self-knockback", }; diff --git a/share/prediction.qc b/share/prediction.qc index 5c7f66e1..62eff7e0 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -544,6 +544,18 @@ entity config_entity; update = TRUE; \ } } while (0) +float ForwardDoorsPossible() { + static float once; + static float possible; + + if (!once) { + possible = CF_GetSetting("rfd", "rewind_forward_doors", "off"); + once = TRUE; + } + + return possible; +} + static void WeaponPred_CheckConfigUpdate() { float update = FALSE; @@ -573,6 +585,9 @@ static void WeaponPred_CheckConfigUpdate() { CLAMP_UPDATE(max_rewind_slow_projectile_ms, 0, fo_config.max_rewind_ms); CLAMP_UPDATE(max_rewind_fast_projectile_ms, 0, fo_config.max_rewind_ms); + if (!ForwardDoorsPossible()) + fo_config.rewind_flags &= ~REWIND_FORWARD_DOORS; + static float last_force_refresh; if (time > last_force_refresh + 5) { update = TRUE; diff --git a/ssqc/client.qc b/ssqc/client.qc index 03cb76b2..da2e3ed8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2916,6 +2916,7 @@ void () PlayerPostThink = { UpdateScoreboardInfo(self); FOPlayer fop = (FOPlayer)self; fop.RewindUpdate(); + Forward_OpenDoors(self); FO_WeapState ws; FO_FillCurrentWeapState(&ws); diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index f201c59e..f8f1f920 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -330,3 +330,19 @@ void Forward_Projectile(int fpp_type, entity proj) { proj.antilag_ms = ft * 1000; } + +void Forward_OpenDoors(entity player) { + if (!RewindFlagEnabled(REWIND_FORWARD_DOORS)) + return; + + vector offset = max(player.client_ping, 150) / 1000.0 * player.velocity; + traceline(player.origin, player.origin + offset, MOVE_TRIGGERS, player); + + if (trace_fraction < 1 && trace_ent.solid == SOLID_TRIGGER) { + entity held_self = self; + other = player; + self = trace_ent; + trace_ent.touch(); + self = held_self; + } +} diff --git a/ssqc/triggers.qc b/ssqc/triggers.qc index 91b5a0b3..f056fc86 100644 --- a/ssqc/triggers.qc +++ b/ssqc/triggers.qc @@ -124,6 +124,8 @@ void () trigger_multiple = { self.solid = SOLID_BBOX; setorigin(self, self.origin); } else if (!(self.spawnflags & SPAWNFLAG_NOTOUCH)) { + if (ForwardDoorsPossible()) + self.flags |= FL_FINDABLE_NONSOLID; self.touch = multi_touch; } }; From 48a79d1df16798f6581210c798e7a9db14d7cec1 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 29 Nov 2022 00:04:56 -0800 Subject: [PATCH 1915/2474] Convert held grenades to use the new shared code also I was deferring this, but it's necessary since some of the default thinks have been replaced by the new stuff. --- ssqc/tfort.qc | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 504bc539..197666ce 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2724,16 +2724,16 @@ void () TeamFortress_ExplodePerson = { self.owner.tfstate &= ~TFSTATE_GREN_MASK_ALL; KickPlayer(-2, self.owner); - newmis = spawn(); - newmis.movetype = MOVETYPE_BOUNCE; - newmis.solid = SOLID_BBOX; - newmis.classname = "grenade"; - newmis.team_no = self.owner.team_no; - newmis.owner = self.owner; - newmis.velocity = '0 0 0'; - newmis.angles = vectoangles(newmis.velocity); - newmis.think = SUB_Null; - newmis.nextthink = time + 0.1; // Server generated, no client time here. + entity proj = FOProj_Create(FPP_HANDGRENADE); + proj.movetype = MOVETYPE_BOUNCE; + proj.solid = SOLID_BBOX; + proj.classname = "grenade"; + proj.team_no = self.owner.team_no; + proj.owner = self.owner; + proj.velocity = '0 0 0'; + proj.angles = vectoangles(proj.velocity); + proj.think = SUB_Null; + proj.nextthink = time + 0.1; // Server generated, no client time here. if (self.weapon == GR_TYPE_FLARE) { sprint(self.owner, PRINT_HIGH, "Flare lit\n"); @@ -2745,7 +2745,7 @@ void () TeamFortress_ExplodePerson = { te.solid = 0; self.owner.effects = self.owner.effects | EF_BRIGHTLIGHT; dremove(self); - dremove(newmis); + dremove(proj); return; } @@ -2753,13 +2753,13 @@ void () TeamFortress_ExplodePerson = { FO_GrenInfo* gdesc = FO_GrenDesc(gtype); stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; - newmis.skin = gdesc->skin; - FO_SetModel(newmis, gdesc->model); - newmis.avelocity = gdesc->avelocity; - newmis.touch = ste->touch; - newmis.think = ste->think; - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, self.owner.origin); + proj.fpp.gren_type = gtype; + proj.skin = gdesc->skin; + proj.avelocity = gdesc->avelocity; + proj.touch = ste->touch; + proj.think = ste->think; + setorigin(proj, self.owner.origin); + FOProj_Finalize(proj); if ((self.owner.playerclass == PC_SCOUT) && (self.weapon != 10)) bprint(PRINT_MEDIUM, "No ", self.owner.netname, From b9c42d9db508ebfdb3879bcfad12b273505ad9c8 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 29 Nov 2022 01:04:52 -0800 Subject: [PATCH 1916/2474] Cap the velocity we'll forward open a door at Limits how much extra steam you can carry in --- ssqc/rewind.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index f8f1f920..e2dceb2b 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -335,7 +335,8 @@ void Forward_OpenDoors(entity player) { if (!RewindFlagEnabled(REWIND_FORWARD_DOORS)) return; - vector offset = max(player.client_ping, 150) / 1000.0 * player.velocity; + vector offset = min(550, vlen(player.velocity)) * normalize(player.velocity); + offset *= max(player.client_ping, 150) / 1000.0; traceline(player.origin, player.origin + offset, MOVE_TRIGGERS, player); if (trace_fraction < 1 && trace_ent.solid == SOLID_TRIGGER) { From d80b646fb418bf16d79dab2e84f286b6291e762f Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 29 Nov 2022 16:18:43 -0800 Subject: [PATCH 1917/2474] Use more bits to transmit ping This was overflowing for Australia<->Europe cross-play. --- share/prediction.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/prediction.qc b/share/prediction.qc index 62eff7e0..a85edd5c 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -380,7 +380,7 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_CTIME) { COMM(Float, client_time); - COMM(Byte, client_ping); + COMM(Short, client_ping); } if (sendflags & FOWP_CLASS) { From bb9ba477541dc456b8ad14bc409e131c83117ed3 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 29 Nov 2022 23:25:55 -0800 Subject: [PATCH 1918/2474] Augment, don't override flags when popping up shock grenades We're seeing the occasional disconnect where a projectile is missing its type. But this should always be sent; seems to happen to HPBs. One guess is maybe the original packet is being lost on a shock grenade and then flags is being smashed by the movetype update? Ensure this doesn't happen by ORing (and make sure we actually pass back the movetype -- didn't matter since no vel). In the meantime, prevent it from crashing by giving it a (intentionally probably wrong) model. --- csqc/weapon_predict.qc | 5 +++++ ssqc/tsoldier.qc | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f73723ae..e36dee9c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1263,6 +1263,11 @@ float PredProjectile_MatchProjectile() { // Called on `self`. void InitProjectileEnt(float sendflags) { + if (self.fpp.index == FPP_NONE) { + printf("ERROR: Missing FPP flags=%d\n", sendflags); + self.fpp.index = FPP_RAILGUN; // Something people will notice. + } + self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; if (sendflags & FOPP_ANGLES == 0) diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index 26abefb5..a38043e2 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -101,7 +101,7 @@ void () ShockGrenadeExplode = { self.nextthink = time + 0.7; self.playerclass = 0; self.think = NailGrenLaser; - self.SendFlags = FOPP_POS; + self.SendFlags |= FOPP_POS | FOPP_MOVETYPE; }; void () BurstGrenadeExplode = { From 7de9e19ac13d614d1e7435354e15ba5499205743 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 30 Nov 2022 01:57:28 -0800 Subject: [PATCH 1919/2474] Use held origin when we need a now rewind point Just in case entity was already rewound to another point in time. Make sure that update spam can't drag an entry forwards indefinitely. Ensure last-update is aligned with log record. --- ssqc/rewind.qc | 36 ++++++++++++++++++++++-------------- ssqc/time.qc | 1 - 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index e2dceb2b..ccd411bb 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -108,13 +108,20 @@ RewindSnapshot* RewindLog(RewindState* target) { if (target->owner != self) error("Log mismatch\n"); + target->owner->client_lastupdate = time; + RewindSnapshot* rs = &target->snapshot[target->cur]; - if (rs->time && time > rs->time + 0.005) { - target->cur = NextRewindIdx(target->cur); - rs = &target->snapshot[target->cur]; + if (time > rs->time + 0.05) { + if (rs->time) { + target->cur = NextRewindIdx(target->cur); + rs = &target->snapshot[target->cur]; + } + // Only set timestamp when we start the rewind entry. Subsequent + // overlapped updates will update the position but not the time (so that + // we can't drag it arbitrarily far forwards). + rs->time = time; } - rs->time = time; rs->origin = target->owner.origin; rs->velocity = target->owner.velocity; @@ -164,7 +171,7 @@ static void RewindTo(RewindState* rstate, float rtime) { ASSERTD_EQ(rstate->rewound, kRewound); entity e = rstate->owner; - if (e.health <= 0) + if (e.health <= 0 || rtime < e->spawn_time) return; vector pos; @@ -177,19 +184,20 @@ static void RewindTo(RewindState* rstate, float rtime) { float a_time; vector a_origin; - if (!a) { - a_time = time; - a_origin = e.origin; - } else { + if (a) { a_time = a->time; a_origin = a->origin; + } else { + a_time = time; + a_origin = rstate->held_origin; } if (!b) { - pos = a_origin; // Should never happen... + pos = a_origin; // Should only happen if ran off the end of the + // array, this shouldn't occur at stock limits. } else { - float frac = (rtime - b->time) / (a->time - b->time); - vector diff = a->origin - b->origin; + float frac = (rtime - b->time) / (a_time - b->time); + vector diff = a_origin - b->origin; if (vlen(diff) > 48) frac = 1; // Most likely teleport. @@ -198,7 +206,7 @@ static void RewindTo(RewindState* rstate, float rtime) { } } else { float max_xerp = CF_GetSetting("rwmx", "rewind_max_xerp", "0.02"); - pos = e.origin + min(rtime - e.client_lastupdate, max_xerp) * e.velocity; + pos = rstate->held_origin + min(rtime - e.client_lastupdate, max_xerp) * e.velocity; } setorigin(rstate->owner, pos); @@ -211,7 +219,7 @@ static void RL_RewindTo(RewindState* head, entity exclude, float rtime) { RL_FOR_EACH(head, rstate) { entity e = rstate->owner; - if (e == exclude || rtime < e->spawn_time) + if (e == exclude) continue; RewindTo(rstate, rtime); diff --git a/ssqc/time.qc b/ssqc/time.qc index 8d06dcce..8d54d863 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -45,7 +45,6 @@ void FO_CheckClientThink() { void FO_UpdateClientTime() { self.client_time += frametime; - self.client_lastupdate = time; self.client_ping = infokeyf(self, INFOKEY_P_PING); } From ff8254e89b197b89f0a326bdfba0337c5eac3bc4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 2 Dec 2022 17:00:20 +1100 Subject: [PATCH 1920/2474] Fix incorrect water sound path --- csqc/events.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index a18430be..53caba44 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -454,8 +454,8 @@ float(float entnum, float channel, string soundname, float vol, float attenuatio case "player/land.wav": case "player/land2.wav": case "player/h2ojump.wav": - case "player/water1.wav": - case "player/water2.wav": + case "misc/water1.wav": + case "misc/water2.wav": case "player/inlava.wav": case "player/inh2o.wav": case "player/slimbrn2.wav": From f917eaa5bbb04e8033ff2a5df636dc9703bd44db Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 2 Dec 2022 17:01:10 +1100 Subject: [PATCH 1921/2474] fix incorrect water sound path --- csqc/main.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3b75ac71..34ac8efc 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -557,9 +557,9 @@ void PlayCSJumpSounds() { if (swimsound_cooldown < time) { swimsound_cooldown = time + 1; if (random() < 0.5) { - localsound("player/water1.wav", CHAN_BODY, 1); + localsound("misc/water1.wav", CHAN_BODY, 1); } else { - localsound("player/water2.wav", CHAN_BODY, 1); + localsound("misc/water2.wav", CHAN_BODY, 1); } } } else { From 825d73bd2d030882ac423c738de531ded869f583 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 1 Dec 2022 22:06:08 -0800 Subject: [PATCH 1922/2474] Refactor frame loop slightly - Add support for intercepting effect frames we skipped - Don't bother touching the last partial effect frame, this has the side effect of resolving super low ping issues. Might need to bring it back if we support extrap for pmove. - Move stuff around and prep for pmove. --- csqc/weapon_predict.qc | 44 ++++++++++++++++++++++++++++-------------- share/prediction.qc | 3 +++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 707ca224..013b7697 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -263,10 +263,11 @@ void WPP_UpdateEnable(float force) { WP_UpdateViewModel(pengine.pweap_ent); } -static float IsEffectFrame() { +float IsEffectFrame() { if (!pengine.is_effectframe) return FALSE; +#if 0 // At ultra-low latencies it's possible that we're only one frame in front // of the server. But this can mean that we get that frame back immediately // (and our input applies to the one after it). @@ -274,9 +275,20 @@ static float IsEffectFrame() { pengine.last_effectframe++; if (CVARF(wpp_debug) & 8) print("Effect bump!\n"); } +#endif return TRUE; } +// This covers frames that would have been effect frames, but were missed client +// side due to . It's too loose for things like lining up +// projectiles where we just take the miss, but for things like sound it's +// better to have minutely off than not play. +float IsEffectFrameMulti() { + return (pengine.is_effectframe || + (pstate_pred.seq > pengine.last_effectframe && + pstate_pred.seq < clientcommandframe)); +} + void Attack_Finished(float attack_time) { pstate_pred.attack_finished = pstate_pred.client_time + attack_time; } @@ -739,6 +751,16 @@ void WP_Frame() { return; } + while (pstate_pred.client_nextthink && + pstate_pred.client_time >= pstate_pred.client_nextthink) { + float held_client_time = pstate_pred.client_time; + + pstate_pred.client_time = pstate_pred.client_nextthink; + pstate_pred.client_nextthink = 0; + WP_AnimateModel(); + pstate_pred.client_time = held_client_time; + } + WP_CheckReloadFinished(); WP_Impulse(); W_ThrowGren(FALSE); @@ -779,7 +801,7 @@ trail_table_entry trail_table[] = { }; inline float interp_ms() { - return (clientcommandframe - servercommandframe) * SERVER_FRAME_MS; + return (pstate_pred.seq - pstate_server.seq) * SERVER_FRAME_MS; } inline float interp_dt() { @@ -1336,18 +1358,22 @@ float WP_ClientThink() { float old_input_buttons; int pframe = servercommandframe + 1; - int eframe = clientcommandframe; + int eframe = clientcommandframe - 1; + int effect_frame = clientcommandframe - 1; + + pstate_server.seq = servercommandframe; for(; pframe <= eframe; pframe++) { old_input_buttons = input_buttons; if (!getinputstate(pframe) || input_timelength <= 0) break; makevectors(input_angles); + pstate_pred.seq = pframe; pstate_pred.buttons_held = input_buttons; pstate_pred.buttons_up = old_input_buttons & (~input_buttons); pstate_pred.buttons_down = (~old_input_buttons) & input_buttons; - if (pframe == eframe - 1 && pframe > pengine.last_effectframe) { + if (pframe == effect_frame && pframe > pengine.last_effectframe) { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; } else { @@ -1358,16 +1384,6 @@ float WP_ClientThink() { if (input_impulse) pstate_pred.impulse = input_impulse; - while (pstate_pred.client_nextthink && - pstate_pred.client_time >= pstate_pred.client_nextthink) { - float held_client_time = pstate_pred.client_time; - - pstate_pred.client_time = pstate_pred.client_nextthink; - pstate_pred.client_nextthink = 0; - WP_AnimateModel(); - pstate_pred.client_time = held_client_time; - } - WP_Frame(); } diff --git a/share/prediction.qc b/share/prediction.qc index a85edd5c..8608d4a5 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -61,9 +61,12 @@ struct predict_tf_state { float clip_fired[4]; int prng_base[PRNG_NUM_STATES]; +#ifdef CSQC // Used for prediction, not actually communicated. Reset each frame. + int seq; float ammo_used[AMMO_NUM_TYPES]; float buttons_down, buttons_up, buttons_held; +#endif }; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; From fd8e1e2fb71efff5b847d28068b4ec37af8c7ef3 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 1 Dec 2022 15:53:08 -0800 Subject: [PATCH 1923/2474] Client-side jump sound prediction Rework jump prediction to be integrated into our predicted frame interpolation versus hanging off render. This lets us fix a bunch of nits and avoids the need for cooldowns (since we can actually track when there was a predicted jump). --- csqc/csextradefs.qc | 5 -- csqc/csprogs.src | 1 + csqc/events.qc | 5 +- csqc/main.qc | 113 ----------------------------------------- csqc/pmove.qc | 97 +++++++++++++++++++++++++++++++++++ csqc/weapon_predict.qc | 6 ++- ssqc/client.qc | 2 +- 7 files changed, 106 insertions(+), 123 deletions(-) create mode 100644 csqc/pmove.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 54aea251..8433df5c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -831,12 +831,7 @@ float painfinished; vector thisorigin; float jump_counter; float grentimer_waiting; -float jumpsound_cooldown; -float swimsound_cooldown; -float last_onground; -float last_vel_z; float last_death_time; -float last_waterlevel; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 024839ff..0ef4cb4f 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -21,6 +21,7 @@ profile.qc ../share/classes.qc ../share/animate.qc weapon_predict.qc +pmove.qc sui_sys.qc vote.qc status.qc diff --git a/csqc/events.qc b/csqc/events.qc index 150e51c8..0d0080ee 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -513,11 +513,10 @@ float(float ent_num, float channel, string soundname, float vol, float attenuati case "player/inh2o.wav": case "player/slimbrn2.wav": case "misc/outwater.wav": - if (CVARF(fo_csjumpsounds)) { + if (CSQC_JumpSounds_Active()) return 1; - } else { + else break; - } } return 0; diff --git a/csqc/main.qc b/csqc/main.qc index 1d0fa054..b1e0eec4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -143,8 +143,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Hud_UpdateView(width, height, menushown, fts); perf_finish_sample(&frame_timing, fts); - - PlayCSJumpSounds(); } noref float(string cmd) CSQC_ConsoleCommand = { @@ -557,114 +555,3 @@ void Perf_Status() { to_precision(avg, prec), variance, to_precision(minv, prec), to_precision(maxv, prec)); } - -float InFluid(vector point){ - local float cont = pointcontents(point); - - if (cont == CONTENT_WATER || cont == CONTENT_SLIME || cont == CONTENT_LAVA) { - return 1; - } else { - return 0; - } -} - -float CalculateWaterLevel() { - local vector point = pmove_org; - local float waterlevel = 0; - - point[2] = pmove_org[2] + PLAYER_MINS[2] + 1; // feet - if (!InFluid(point)) { - return waterlevel; - } else { - waterlevel++; - } - - point[2] = pmove_org[2] + (PLAYER_MINS[2] + PLAYER_MAXS[2]) * 0.5; // waist - if (!InFluid(point)) { - return waterlevel; - } else { - waterlevel++; - } - - point[2] = pmove_org[2] + PLAYER_MINS[2] + PLAYER_MAXS[2] + DEFAULT_VIEWHEIGHT; // eyes - if (!InFluid(point)) { - return waterlevel; - } else { - waterlevel++; - } - - return waterlevel; -} - -void PlayCSJumpSounds() { - if (!CVARF(fo_csjumpsounds)) { - return; - } - - if (getstatf(STAT_PAUSED)) { - return; - } - - local float waterlevel = CalculateWaterLevel(); - - if (getstatf(STAT_HEALTH) > 0) { - // jumping - if ((input_buttons & BUTTON2)) { - if (waterlevel >= 2) { - if (swimsound_cooldown < time) { - swimsound_cooldown = time + 1; - if (random() < 0.5) { - localsound("player/water1.wav", CHAN_BODY, 1); - } else { - localsound("player/water2.wav", CHAN_BODY, 1); - } - } - } else { - if (pmove_onground && pmove_vel_z < 180 /*not sliding*/ ) { - if (jumpsound_cooldown < time) { - jumpsound_cooldown = time + (2 / serverkeyfloat("maxfps")); - localsound("player/plyrjmp8.wav", CHAN_AUTO, cvar(FOCMD_JUMPVOLUME)); - } - } - } - } - - // landing - if (pmove_onground && !last_onground && last_vel_z < -300) { - if (pointcontents(pmove_org) == CONTENT_WATER) { - localsound("player/h2ojump.wav", CHAN_BODY, 1); - } else if (last_vel_z < -650) { - localsound("player/land2.wav", CHAN_VOICE, 1); - } else { - localsound("player/land.wav", CHAN_VOICE, 1); - } - } - - // entering water - if (waterlevel > 0 && last_waterlevel == 0) { - local vector feet = pmove_org; - feet[2] = pmove_org[2] + PLAYER_MINS[2] + 1; - - switch(pointcontents(feet)) { - case CONTENT_LAVA: - localsound("player/inlava.wav", CHAN_BODY, 1); - break; - case CONTENT_WATER: - localsound("player/inh2o.wav", CHAN_BODY, 1); - break; - case CONTENT_SLIME: - localsound("player/slimbrn2.wav", CHAN_BODY, 1); - break; - } - } - - // exiting water - if (waterlevel == 0 && last_waterlevel > 0) { - localsound("misc/outwater.wav", CHAN_BODY, 1); - } - } - - last_vel_z = pmove_vel_z; - last_onground = pmove_onground; - last_waterlevel = waterlevel; -}; diff --git a/csqc/pmove.qc b/csqc/pmove.qc new file mode 100644 index 00000000..dd3bdc8f --- /dev/null +++ b/csqc/pmove.qc @@ -0,0 +1,97 @@ +const vector PLAYER_MINS = [-16, -16, -24]; +const vector PLAYER_MAXS = [16, 16, 32]; + +inline float CSQC_JumpSounds_Active() { + return WP_Enabled() && CVARF(fo_csjumpsounds); +} + +// Sets *type to whatever is at the feet of `point`. +static float PM_GetWaterLevel(vector point, float* type) { + float waterlevel = 0; + float offsets[] = { PLAYER_MINS.z + 1, (PLAYER_MINS.z + PLAYER_MAXS.z) / 2, + DEFAULT_VIEWHEIGHT }; + for (int i = 0; i < 3; i++) { + float cont = pointcontents(point + offsets[i] * '0 0 1'); + if (i == 0) + *type = cont; + if (cont == CONTENT_WATER || cont == CONTENT_SLIME || cont == CONTENT_LAVA) + waterlevel++; + else + break; + } + return waterlevel; +} + +void PM_PredictJump() { + if (!CVARF(fo_csjumpsounds) || getstatf(STAT_PAUSED)) + return; + + static float last_onground, last_waterlevel, last_vel_z; + + float fluidtype; + float waterlevel = PM_GetWaterLevel(pmove_org, &fluidtype); + float jumping = input_buttons & BUTTON2; + float onground = pmove_onground; + float landing = onground && !last_onground; + float health = getstatf(STAT_HEALTH); + + if (health <= 0) { + last_onground = 1; + last_vel_z = 0; + last_waterlevel = 0; + return; + } + + if (!IsEffectFrameMulti()) + return; + + static float swimsound_next; + + string sound; + if (landing && last_vel_z < -300) { // Hard or water land. + if (fluidtype == CONTENT_WATER) + localsound("player/h2ojump.wav", CHAN_BODY, 1); + else if (last_vel_z < -650) // Will take damage. + localsound("player/land2.wav", CHAN_VOICE, 1); + else + localsound("player/land.wav", CHAN_VOICE, 1); + } + + // TODO: Model health above and not play jump when landing into death. + if (jumping) { + if (waterlevel >= 2 && time > swimsound_next) { + swimsound_next = time + 1; + sound = random() < 0.5 ? "player/water1.wav" : "player/water2.wav"; + localsound(sound, CHAN_BODY, 1); + } else if (last_onground && !onground && + pmove_vel_z > last_vel_z + 200) { + // The default pmove implementation and server behave slightly + // differently here in two important ways here: + // 1) Jump calculations run _prior_ to movement rather than post, + // meaning you can test for jumping and onground directly. We + // get around this by just using prior frame's onground. + // 2) Something (probably airstep) masks on-grounds that get + // skipped, which otherwise results in false jumps moving up + // stairs when combined with (1). We can test for this by + // watching to see whether we actually got a sufficiently large + // velocity increase. + localsound("player/plyrjmp8.wav", CHAN_AUTO, cvar(FOCMD_JUMPVOLUME)); + } + } + + if (waterlevel > 0 && last_waterlevel == 0) { // Water entry. + sound = ""; + switch(fluidtype) { + case CONTENT_LAVA: sound = "player/inlava.wav"; break; + case CONTENT_WATER: sound = "player/inh2o.wav"; break; + case CONTENT_SLIME: sound = "player/slimbrn2.wav"; break; + } + localsound(sound, CHAN_BODY, 1); + } else if (waterlevel == 0 && last_waterlevel > 0) { // Water exit. + localsound("misc/outwater.wav", CHAN_BODY, 1); + } + + last_vel_z = pmove_vel_z; + last_onground = pmove_onground; + last_waterlevel = waterlevel; +}; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 013b7697..d68a0ba1 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -12,7 +12,7 @@ struct pengine_t { float pp_enabled; float wp_enabled; float is_effectframe; - float last_effectframe; + float last_effectframe, last_effectframe2; float player_entnum; // player_localentnum iff is_player == 1 entity player_ent; @@ -1348,6 +1348,8 @@ void WP_UpdateViewModel(entity pweap_ent) { pweap_ent.lerpfrac = max(0, pweap_ent.lerpfrac - frametime * 10); } +void PM_PredictJump(); + float WP_ClientThink() { if (!WP_Enabled()) return PREDRAW_NEXT; @@ -1355,6 +1357,7 @@ float WP_ClientThink() { pstate_pred = pstate_server; getinputstate(servercommandframe); // Setup first read for old_buttons. + pengine.last_effectframe2 = pengine.last_effectframe; float old_input_buttons; int pframe = servercommandframe + 1; @@ -1384,6 +1387,7 @@ float WP_ClientThink() { if (input_impulse) pstate_pred.impulse = input_impulse; + PM_PredictJump(); WP_Frame(); } diff --git a/ssqc/client.qc b/ssqc/client.qc index 11c6b42a..ed63de34 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2948,7 +2948,7 @@ void () PlayerPostThink = { if (((self.jump_flag < -300) && (self.flags & FL_ONGROUND)) && (self.health > 0)) { - if (self.watertype == -3) { + if (self.watertype == CONTENT_WATER) { FO_Sound(self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM); } else { if (self.jump_flag < -650) { From 098efe336c0e446d21da2c99c7f758a86de1a981 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 26 Nov 2022 02:51:42 -0800 Subject: [PATCH 1924/2474] Add physics forward simulation Simulate a ~RTT ahead of client so that we can predict events for knockback. --- csqc/weapon_predict.qc | 9 +++++++- share/commondefs.qc | 1 + share/physics.qc | 52 +++++++++++++++++++++++++++++++++++++++--- share/prediction.qc | 9 +++++--- ssqc/tfort.qc | 1 + 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index d68a0ba1..f68710af 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -320,10 +320,15 @@ void PredProj_Sound(int proj_type, float vol = 1) { Pred_Sound(FPP_Get(proj_type)->snd, vol); } -// Corrections for when we can recognize that we missed a packet. void WP_ServerUpdate() { + // Force WF to zero, in case we missed a packet. if (pstate_server.attack_finished < pstate_server.client_time) pstate_server.weaponframe = 0; + + if (CVARF(fo_wpp_beta) == 2) + phys_sim_dt = (pstate_server.client_ping + 2 * SERVER_FRAME_MS) / 1000.0; + else + phys_sim_dt = -1; } static Slot InputToSlot(float input) { @@ -911,6 +916,7 @@ float PP_PredrawActive() { return PREDRAW_NEXT; Phys_Advance(self, get_phys_time(self), 0); + Phys_Sim(self); // we need to space out the particles incase we're running at very high fps if (time > self.p_time) { @@ -982,6 +988,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.starttime = time + uncorrected_dt; proj.s_time = proj.starttime - static_dt; proj.endtime = proj.starttime + pstate_server.client_ping / 1000.0 + PP_EPS; + proj.server_live_time = time + interp_dt(); proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; diff --git a/share/commondefs.qc b/share/commondefs.qc index 3c8e8624..e2047c8b 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -1,5 +1,6 @@ struct FPPState { int index; + float expires_at; union { int aux; diff --git a/share/physics.qc b/share/physics.qc index 3df323d4..e9087cc9 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -3,6 +3,8 @@ static const float phys_tic = 0.005; .float phys_time; // Current physics time +.float server_live_time; // When an entity can first appear on server. 0 for + // server-side ents. enumflags { PHYSB_ENABLED, @@ -12,7 +14,8 @@ enumflags { PHYSF_CONSUME_ALL, PHYSF_REWIND_PLAYERS, PHYSF_FORWARD_KNOCK, - PHYSF_FAIL_STARTSOLID + PHYSF_FAIL_STARTSOLID, + PHYSF_SIM, }; const float FL_FORWARD_KNOCK = FL_GODMODE; @@ -54,7 +57,6 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { if (other.solid == SOLID_NOT) return; - if (e.touch) { if (phys_flags & PHYSF_FORWARD_KNOCK) e.flags |= FL_FORWARD_KNOCK; @@ -98,10 +100,13 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { AugmentGrenadeImpact(); if (CVARF(fo_phys_debug) & 1) - printf("CPhys: Impact t=%0.3f pt=%0.3f [%0.3f]\n", time, e.phys_time + dt, + printf("CPhys: Impact t=%0.3f pt=%0.3f sim=%d [%0.3f]\n", time, e.phys_time + dt, + phys_flags & PHYSF_SIM, get_phys_time(e)); } +static void Phys_Expired(entity e, float phys_flags) {} + static vector get_followed_origin() { if (!(float)getentity(self.aiment_num, GE_ACTIVE)) return self.origin; @@ -230,6 +235,12 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { return 0; } + // If there's an expiry, make sure we get to the exact position. + if (e.fpp.expires_at && target_time > e.fpp.expires_at) { + target_time = e.fpp.expires_at; + phys_flags |= PHYSF_CONSUME_ALL; + } + static float limit_eps = 0.0005; float limit = (phys_flags & PHYSF_CONSUME_ALL) ? limit_eps : phys_tic; float total = 0, dt = 0, step = 0, delta; @@ -293,4 +304,39 @@ float Phys_Init(entity e, float target_time, float delta, float phys_flags) { return 0; } } + +#ifdef CSQC +.float phys_sim_last; +.float phys_sim_voided_at; +var float phys_sim_dt; + +void Phys_Sim(entity e) { + // TODO: Unvoid+undo if we make it past the void point. + if (phys_sim_dt < 0 || e.phys_sim_voided_at) + return; + + float ptime = time + phys_sim_dt; + if (ptime < self.phys_sim_last + SERVER_FRAME_MS) + return; + self.phys_sim_last = ptime; + + float held_phys_time = e.phys_time; + vector held_org = e.origin; + vector held_vel = e.velocity; + vector held_angles = e.angles; + float held_flags = e.flags; + + Phys_Advance(e, ptime, PHYSF_SIM | PHYSF_CONSUME_ALL); + + if (e.voided) { + e.phys_sim_voided_at = e.phys_time; + e.voided = 0; + } + e.phys_time = held_phys_time; + e.origin = held_org; + e.velocity = held_vel; + e.angles = held_angles; + e.flags = held_flags; +} +#endif #undef dot diff --git a/share/prediction.qc b/share/prediction.qc index 8608d4a5..175f9161 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -30,6 +30,7 @@ enumflags { FOPP_AUX, FOPP_ANGLES, FOPP_MOVETYPE, + FOPP_EXPIRY, FOPP_NEW, // We only use this for a new entity, which is FFF... anyway. }; @@ -453,6 +454,8 @@ float PP_SendEntity(entity to_player, float sendflags) { sendflags = FOPP_INIT | FOPP_POS; if (self.fpp.aux) sendflags |= FOPP_AUX; + if (self.fpp.expires_at) + sendflags |= FOPP_EXPIRY; } WriteByte(MSG_ENTITY, ENT_PROJECTILE); @@ -471,9 +474,10 @@ void EntUpdate_Projectile(float isnew) { COMMD(Entity, owner_entnum, owner); } - if (sendflags & FOPP_AUX) { + if (sendflags & FOPP_AUX) COMM(Short, fpp.aux); - } + if (sendflags & FOPP_EXPIRY) + COMM(Float, fpp.expires_at); if (sendflags & FOPP_POS) { COMM(Coord, origin[0]); @@ -502,7 +506,6 @@ void EntUpdate_Projectile(float isnew) { COMMD(Entity, aiment_num, aiment); } - #ifdef SSQC return TRUE; #else diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 197666ce..554c2881 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -853,6 +853,7 @@ void (entity timer) FO_SpawnThrownGrenade = { stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; proj.fpp.gren_type = gtype; + proj.fpp.expires_at = timer.heat; proj.skin = gdesc->skin; proj.touch = ste->touch; proj.think = ste->think; From 87cc6cd7bc72d5a55ee64653b065eca0db035df3 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 2 Dec 2022 14:31:20 -0800 Subject: [PATCH 1925/2474] Simplify remote_time Logic for what time point to use was lifted into physics/rewind/etc this now just wants to give us the furthest point which callers can constrain against. --- ssqc/qw.qc | 2 +- ssqc/time.qc | 18 +++++------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a3cbb227..ea9de505 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -31,7 +31,7 @@ struct antilag_settings_t { // at t1: remote_client_time() + o < at t2: lag_time() + o FOR t2 > t1 // E.g. That you never have to worry about the correction reordering events // that `time + o` would not. -float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT); +float remote_client_time(); //=========================================================================== // TEAMFORTRESS Defs diff --git a/ssqc/time.qc b/ssqc/time.qc index 8d54d863..1bf2c7b6 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -1,14 +1,6 @@ -float remote_client_time(float ct_type = CT_NOEXTERNALEFFECT) { - float offset = min(self.client_ping, fo_config.max_rewind_ms); - - switch (ct_type) { - case CT_SLOW_PROJECTILE: - offset = min(offset, fo_config.max_rewind_slow_projectile_ms); - break; - case CT_FAST_PROJECTILE: - offset = min(offset, fo_config.max_rewind_fast_projectile_ms); - break; - } +float remote_client_time() { + float adj_ping = max(self.client_ping - SERVER_FRAME_MS, 0); + float offset = min(adj_ping, fo_config.max_rewind_ms); float target = self.client_time - offset / 1000.0; target = max(target, self.last_remote_client_time); // prevent jitter @@ -27,8 +19,8 @@ inline float global_to_client_time(float gtime) { } // Ping corrected `time`. -float remote_time(float ct_type = CT_NOEXTERNALEFFECT) { - return client_to_global_time(remote_client_time(ct_type)); +float remote_time() { + return client_to_global_time(remote_client_time()); } void FO_CheckClientThink() { From 9ef71ada5499c504f78ce92f07ab0fc0a599a5d5 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 2 Dec 2022 01:19:20 -0800 Subject: [PATCH 1926/2474] Antilag for Handgrenades Now you don't need to adjust your throws for ping (when enabled.. up to limits..). Not yet default enabled. TL;DR: We rewind and time warp using our lockout window to to allow grenade throws to be fairly extensively ping corrected. --- csqc/events.qc | 10 +++++-- csqc/weapon_predict.qc | 18 ++++++++++-- share/commondefs.qc | 18 ++++++++++-- share/prediction.qc | 62 ++++++++++++++++++++++++++++++++++-------- ssqc/rewind.qc | 8 ++++-- ssqc/tfort.qc | 39 ++++++++++++++++++++------ ssqc/time.qc | 4 +++ ssqc/weapons.qc | 2 +- 8 files changed, 129 insertions(+), 32 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 0d0080ee..17f13ee5 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -344,9 +344,13 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, flags_ = timer_flags; if (this.flags_ & FL_GT_ADJPING) { - local float rtt = - getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; - expires_at_ -= rtt/2; + float rtt = pstate_pred.client_ping; + if (RewindFlagEnabled(REWIND_GRENADES)) + rtt = max(0, rtt - (100 + FO_RewindGrenMs(TF_GREN_conv(_grentype)))); + else + rtt /= 2; // Not actually right, but preserve buggy behavior for + // now as people are used to it. + expires_at_ -= rtt / 1000; } StartSound(); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f68710af..18e648da 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -179,11 +179,11 @@ void WPP_Status() { printf(" %2d [%-3s]: .%s\n", flag, (fo_config.rewind_flags & flag) ? "on": "off", REWIND_DESC[i]); } - PRINT_CONFIG(no_forward_hg); PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); + PRINT_CONFIG(max_rewind_grenade_ms); if (!fo_config.clown_flags) return; @@ -457,6 +457,7 @@ static void HandleButtonThrowgren(float index, float button) { float WP_ReloadSlot(Slot slot); void WP_ReloadNext(); +float interp_time(); void WP_Impulse() { WP_HandleHeavyInputs(); @@ -1102,10 +1103,21 @@ static void W_ThrowGren(float is_throw) { if (pstate_pred.client_time < pstate_pred.last_prime + 0.8) return; // Not time to throw yet, THROWING set if necessary. + int type_index = (pstate_pred.tfstate & TFSTATE_GREN1_PRIMED) ? 0 : 1; + int gren_type = FO_ClassGren(pstate_pred.playerclass, type_index)->id; + + float last_possible_throw = pstate_pred.last_prime + 3.7; + last_possible_throw -= FO_RewindGrenDt(gren_type); + + // We're conservative here, a missed predicted projectile throw into what's + // actually a held grenade is frustrating. Better to leave it up to the + // server when it's really tight. + if (pstate_pred.client_time > last_possible_throw - 1.5 * SERVER_FRAME_DT) + return; // Buckle up... probably. + if (IsEffectFrame()) { entity gren = PP_CreateProjectile(FPP_HANDGRENADE, '0 0 0'); - int index = (pstate_pred.tfstate & TFSTATE_GREN1_PRIMED) ? 0 : 1; - gren.fpp.gren_type = FO_ClassGren(pstate_pred.playerclass, index)->id; + gren.fpp.gren_type = gren_type; FPP_ApplyGrenadeProperties(gren); } diff --git a/share/commondefs.qc b/share/commondefs.qc index e2047c8b..6c25d6fe 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -2,6 +2,11 @@ struct FPPState { int index; float expires_at; +#ifdef SSQC + int flags; + float dynamic_dt; +#endif + union { int aux; int gren_type; @@ -11,6 +16,11 @@ struct FPPState { .FPPState fpp; +enumflags { + FPF_NO_REWIND, + FPF_FIXED_DYNAMIC, +}; + var struct { float qc_physics; float static_newmis_ms; @@ -19,9 +29,9 @@ var struct { float max_rewind_ms; float max_rewind_slow_projectile_ms; float max_rewind_fast_projectile_ms; + float max_rewind_grenade_ms; float rewind_fast_projectile_thresh; float wp_default_min_ping_ms; - float no_forward_hg; float clown_flags; float clown_grav; @@ -37,19 +47,21 @@ var struct { enumflags { REWIND_KNOCKBACK, REWIND_PROJ_HIT, + REWIND_GRENADES, REWIND_FORWARD_DOORS, - REWIND_PROJ_SELFKNOCK, + REWIND_FORWARD_PROJ_SELFKNOCK, }; string REWIND_DESC[] = { "rewind pipe knockback", "rewind projectile hit", + "rewind grenade throws", "open doors earlier for hpbs [requires rfd=1]", "forward projectile self-knockback", }; const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_HIT | - REWIND_PROJ_SELFKNOCK; + REWIND_FORWARD_PROJ_SELFKNOCK; float RewindFlagEnabled(float flag) { return fo_config.rewind_flags & flag; diff --git a/share/prediction.qc b/share/prediction.qc index 175f9161..3046c9a4 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -200,7 +200,7 @@ void InitFppProjectiles() { } float max_rewind_credit_ms(int fpp_type) { - return FPP_Get(fpp_type)->speed < fo_config.rewind_fast_projectile_thresh ? + return (FPP_Get(fpp_type)->speed < fo_config.rewind_fast_projectile_thresh) ? fo_config.max_rewind_slow_projectile_ms : fo_config.max_rewind_fast_projectile_ms; } @@ -216,7 +216,7 @@ float max_rewind_credit_ms(int fpp_type) { // NOTE: DO NOT USE NEWMIS FOR FO PROJECTILES. THE NEWMIS CORRECTION IS NOW // MADE EXPLICITLY RATHER THAN IMPLICITLY. [WE AUTOMATICALLY STRIP NEWMIS // FROM PROJECTILES PASSED TO US.] -float static_newmis_ms(int fpp_type) { +static float static_newmis_ms(int fpp_type) { if (fpp_type == FPP_FLAMETHROWER || fpp_type == FPP_ASSAULT_CANNON) return 0; @@ -231,6 +231,43 @@ inline float fixed_newmis_ms(int fpp_type) { return fo_config.static_newmis_ms; } +float FO_RewindGrenMs(int gren_type) { + if (!RewindFlagEnabled(REWIND_GRENADES)) + return 0; + + float result = fo_config.max_rewind_grenade_ms; + if (gren_type == GREN_CONC) + result += 25; + + return result; +} + +float FO_RewindGrenDt(int gren_type) { + if (!RewindFlagEnabled(REWIND_GRENADES)) + return 0; + + return FO_RewindGrenMs(gren_type) / 1000.0; +} + +float FO_RewindGrenWinDt(int gren_type) { + if (!RewindFlagEnabled(REWIND_GRENADES) || + fo_config.max_rewind_ms <= 50) + return 0; + + // There's no benefit to holding a conc grenade -- and it's beneficial to + // hold it late, so we open the window slightly further when needed. + return gren_type == GREN_CONC ? 0.05 : 0.025; +} + +float FO_MaxRewindGrenWinDt() { + if (!RewindFlagEnabled(REWIND_GRENADES) || + fo_config.max_rewind_ms <= 50) + return 0; + + // Large rewind possible, open up the window. + return 0.1; // An always correct value +} + #ifdef SSQC .predict_tf_state predict_state; @@ -342,9 +379,8 @@ void EntUpdate_Config() { COMM(Byte, max_rewind_ms); COMM(Byte, max_rewind_slow_projectile_ms); COMM(Byte, max_rewind_fast_projectile_ms); - COMM(Byte, rewind_fast_projectile_thresh); + COMM(Short, rewind_fast_projectile_thresh); COMM(Byte, rewind_flags); - COMM(Byte, no_forward_hg); COMM(Byte, clown_flags); COMM(Float, clown_grav); COMM(Byte, wp_default_min_ping_ms); @@ -524,11 +560,11 @@ void Predict_InitDefaultConfig() { fo_config.dynamic_newmis_ms = 0; fo_config.rewind_flags = REWIND_DEFAULT_FLAGS; fo_config.max_rewind_ms = 250; - fo_config.max_rewind_slow_projectile_ms = 100; - fo_config.max_rewind_fast_projectile_ms = 100; + fo_config.max_rewind_slow_projectile_ms = 150; + fo_config.max_rewind_fast_projectile_ms = 150; + fo_config.max_rewind_grenade_ms = 50; // Only affects REWIND_GREN fo_config.rewind_fast_projectile_thresh = 1500; fo_config.wp_default_min_ping_ms = 40; - fo_config.no_forward_hg = 1; fo_config.clown_flags = 0; fo_config.clown_grav = 400; } @@ -572,6 +608,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("mrt", max_rewind_ms); CONFIG_UPDATE("mrsp", max_rewind_slow_projectile_ms); CONFIG_UPDATE("mrfp", max_rewind_fast_projectile_ms); + CONFIG_UPDATE("mrg", max_rewind_grenade_ms); CONFIG_UPDATE("rfpt", rewind_fast_projectile_thresh); CONFIG_UPDATE("wpdmp", wp_default_min_ping_ms); CONFIG_UPDATE("wpge", wp_global_enable); @@ -581,7 +618,6 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_enable); CONFIG_UPDATE("wppge", wpp_global_disable); CONFIG_UPDATE("gbd", gren_beta_disable); - CONFIG_UPDATE("nfhg", no_forward_hg); CONFIG_UPDATE("rewind", rewind_flags); CONFIG_UPDATE("clown", clown_flags); CONFIG_UPDATE("clown_grav", clown_grav); @@ -590,6 +626,7 @@ static void WeaponPred_CheckConfigUpdate() { CLAMP_UPDATE(max_rewind_ms, 0, 250); CLAMP_UPDATE(max_rewind_slow_projectile_ms, 0, fo_config.max_rewind_ms); CLAMP_UPDATE(max_rewind_fast_projectile_ms, 0, fo_config.max_rewind_ms); + CLAMP_UPDATE(max_rewind_grenade_ms, 0, 125); if (!ForwardDoorsPossible()) fo_config.rewind_flags &= ~REWIND_FORWARD_DOORS; @@ -765,6 +802,12 @@ ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { if (FPP_Get(fpp_type)->fixed_project) { static_credit = fixed_newmis_ms(fpp_type); + } else if (fpp_type == FPP_HANDGRENADE) { + static_credit = static_newmis_ms(fpp_type); + if (RewindFlagEnabled(REWIND_GRENADES)) + max_ping_credit = fo_config.max_rewind_grenade_ms; + else + max_ping_credit = 0; } else { static_credit = static_newmis_ms(fpp_type); max_ping_credit += dynamic_newmis_ms(); @@ -773,9 +816,6 @@ ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { if (IsClownMode(CLOWN_FAST_PROJECTILES) && !FPP_IsGrenade(fpp_type)) static_credit = 9999; - if (fpp_type == FPP_HANDGRENADE && fo_config.no_forward_hg) - max_ping_credit = 0; - float frame_nudge = 0; #ifdef CSQC // Account for the fact that the server usually has a physics frame that's diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index ccd411bb..6b88c9b8 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -304,9 +304,13 @@ void Forward_Projectile(int fpp_type, entity proj) { ProjectResult offset = Forward_ProjectOffset(fpp_type, ping); float static_dt = offset.static_ms / 1000.0; float dynamic_dt = offset.dynamic_ms / 1000.0; + + if (proj.fpp.flags & FPF_FIXED_DYNAMIC) + dynamic_dt = proj.fpp.dynamic_dt; float stime = time - dynamic_dt; - float rewind_hit = RewindFlagEnabled(REWIND_PROJ_HIT); + float no_rewind = proj.fpp.flags & FPF_NO_REWIND; + float rewind_hit = !no_rewind && RewindFlagEnabled(REWIND_PROJ_HIT); float phys_flags = PHYSF_CONSUME_ALL; if (rewind_hit) { phys_flags |= PHYSF_REWIND_PLAYERS; @@ -314,7 +318,7 @@ void Forward_Projectile(int fpp_type, entity proj) { RL_RewindTo(rewind_players, proj.owner, stime); } - if (RewindFlagEnabled(REWIND_PROJ_SELFKNOCK)) + if (!no_rewind && RewindFlagEnabled(REWIND_FORWARD_PROJ_SELFKNOCK)) phys_flags |= PHYSF_FORWARD_KNOCK; // Static projection happens instantly. If rewind is active, we'll do it at diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 554c2881..e76cf4f6 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -848,7 +848,7 @@ void (entity timer) FO_SpawnThrownGrenade = { proj.think = SUB_Null; proj.nextthink = timer.heat; - int gtype = TF_GREN_conv(timer.weapon); + int gtype = timer.fpp.gren_type; FO_GrenInfo* gdesc = FO_GrenDesc(gtype); stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; @@ -1037,6 +1037,8 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { tGrenade = spawn(); tGrenade.owner = self; tGrenade.weapon = gtype; + tGrenade.fpp.gren_type = TF_GREN_conv(gtype); + tGrenade.classname = "primetimer"; if (inp == 1) tGrenade.impulse = TF_GRENADE_1; @@ -1096,8 +1098,13 @@ void () FO_GrenadeThink = { FO_SpawnThrownGrenade(self); dremove(self); } else { + // When REWIND_GRENADES is enabled, we slightly time-warp the + // spawned grenade to open up the timing window on being able to + // rewind a throw further. Total time is the same. + float expiry = self.heat + FO_RewindGrenWinDt(self.fpp.gren_type); + // If this fires, we never threw. - self.nextthink = self.heat; + self.nextthink = expiry; } } else { if (self.weapon != GR_TYPE_CALTROP) @@ -1107,9 +1114,15 @@ void () FO_GrenadeThink = { } void () FO_ThrowGrenade = { - local entity timer = self.grenade_timer; - if (timer.nextthink != timer.heat || timer.heat - time < 0.1) { - // We do not allow throwing within the first second, or the last 0.1. + entity timer = self.grenade_timer; + + float throwtime = time, lockout = 0.1; + if (RewindFlagEnabled(REWIND_GRENADES)) + throwtime = bounded_remote_time(FO_RewindGrenDt(timer.fpp.gren_type)); + + if (timer.nextthink - FO_MaxRewindGrenWinDt() > timer.heat || + throwtime > timer.heat - lockout) { + // We do not allow throwing within the 0.8s, or the last 0.1s. // The former is a priming time, the latter is so that client side // knockback will be able to reliably predict whether a grenade was held // (e.g. gren jump) or thrown up to ~200ms ping. @@ -2720,7 +2733,9 @@ void () TeamFortress_AmmoboxTouch = { }; void () TeamFortress_ExplodePerson = { - local entity te; + entity te; + int gtype = self.fpp.gren_type; + FO_GrenInfo* gdesc = FO_GrenDesc(gtype); self.owner.tfstate &= ~TFSTATE_GREN_MASK_ALL; KickPlayer(-2, self.owner); @@ -2734,7 +2749,14 @@ void () TeamFortress_ExplodePerson = { proj.velocity = '0 0 0'; proj.angles = vectoangles(proj.velocity); proj.think = SUB_Null; - proj.nextthink = time + 0.1; // Server generated, no client time here. + float expires = time + 0.1; // Server generated, no client time here. + float rw_dt = FO_RewindGrenWinDt(gtype); + if (rw_dt > 0) { + proj.fpp.flags |= FPF_FIXED_DYNAMIC; + proj.fpp.dynamic_dt = rw_dt; + expires -= rw_dt; + } + proj.nextthink = expires; if (self.weapon == GR_TYPE_FLARE) { sprint(self.owner, PRINT_HIGH, "Flare lit\n"); @@ -2750,11 +2772,10 @@ void () TeamFortress_ExplodePerson = { return; } - int gtype = TF_GREN_conv(self.weapon); - FO_GrenInfo* gdesc = FO_GrenDesc(gtype); stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; proj.fpp.gren_type = gtype; + proj.fpp.flags |= FPF_NO_REWIND; proj.skin = gdesc->skin; proj.avelocity = gdesc->avelocity; proj.touch = ste->touch; diff --git a/ssqc/time.qc b/ssqc/time.qc index 1bf2c7b6..7868a2d9 100644 --- a/ssqc/time.qc +++ b/ssqc/time.qc @@ -23,6 +23,10 @@ float remote_time() { return client_to_global_time(remote_client_time()); } +float bounded_remote_time(float dt) { + return max(time - dt, remote_time()); +} + void FO_CheckClientThink() { if (self.client_nextthink > 0 && self.client_time >= self.client_nextthink) { float held_client_time = self.client_time; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 6544ae0a..d28cb03f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1051,7 +1051,7 @@ void T_Knock_Antilag() { } float AntilagKnock(entity e, float dmg) { - if (!RewindFlagEnabled(REWIND_PROJ_SELFKNOCK) || e.s_time == 0) + if (!RewindFlagEnabled(REWIND_FORWARD_PROJ_SELFKNOCK) || e.s_time == 0) return FALSE; entity knock_e = spawn(); From 45ed6adf1cd1ac4940a0fb46db22d3fc42656fd0 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 3 Dec 2022 13:20:47 -0800 Subject: [PATCH 1927/2474] Simplify predict decision for handgrenades Remove and simplify some legacy bits from bringing up the new physics code. Now that grenades have their own independent rewind timing/enable (due to a bunch of properties specific to them), key on that for whether to generate a client side projectile (if not enabled, there's no rewind to project against). --- csqc/weapon_predict.qc | 12 ++++-------- share/prediction.qc | 1 + 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 18e648da..b7277a8d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -182,8 +182,8 @@ void WPP_Status() { PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); PRINT_CONFIG(max_rewind_fast_projectile_ms); - PRINT_CONFIG(rewind_fast_projectile_thresh); PRINT_CONFIG(max_rewind_grenade_ms); + PRINT_CONFIG(rewind_fast_projectile_thresh); if (!fo_config.clown_flags) return; @@ -1082,14 +1082,10 @@ void (float ox) W_FireSpikes = { }; -DEFCVAR_FLOAT(wpp_disable_gren, 0) -static float PP_EnableGrenades() { - return fo_config.qc_physics && !fo_config.gren_beta_disable && - !CVARF(wpp_disable_gren); -} +static float QcPhysics() { return fo_config.qc_physics; } static void W_ThrowGren(float is_throw) { - if (!PP_EnableGrenades()) + if (!QcPhysics() || !RewindFlagEnabled(REWIND_GRENADES)) return; if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED == 0) @@ -1184,7 +1180,7 @@ void WP_Attack() { case WEAP_GRENADE_LAUNCHER: case WEAP_PIPE_LAUNCHER: - if (PP_EnableGrenades()) + if (QcPhysics()) W_FireGrenade((wi->weapon == WEAP_GRENADE_LAUNCHER || prematch) ? GREN_RED : GREN_PIPE); else diff --git a/share/prediction.qc b/share/prediction.qc index 3046c9a4..f3c3bb86 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -379,6 +379,7 @@ void EntUpdate_Config() { COMM(Byte, max_rewind_ms); COMM(Byte, max_rewind_slow_projectile_ms); COMM(Byte, max_rewind_fast_projectile_ms); + COMM(Byte, max_rewind_grenade_ms); COMM(Short, rewind_fast_projectile_thresh); COMM(Byte, rewind_flags); COMM(Byte, clown_flags); From 96d0baad51507489a3d277f554e05b153820023c Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 5 Dec 2022 02:09:42 -0800 Subject: [PATCH 1928/2474] Hot fix for fast throwing, will fix rewind point later --- ssqc/tfort.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e76cf4f6..c00751da 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1120,8 +1120,7 @@ void () FO_ThrowGrenade = { if (RewindFlagEnabled(REWIND_GRENADES)) throwtime = bounded_remote_time(FO_RewindGrenDt(timer.fpp.gren_type)); - if (timer.nextthink - FO_MaxRewindGrenWinDt() > timer.heat || - throwtime > timer.heat - lockout) { + if (timer.nextthink != timer.heat || timer.heat - time < 0.1) { // We do not allow throwing within the 0.8s, or the last 0.1s. // The former is a priming time, the latter is so that client side // knockback will be able to reliably predict whether a grenade was held From 87aeaee9d3c2dca28d4a6b74adf93fb5743ce05d Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 5 Dec 2022 10:05:07 -0800 Subject: [PATCH 1929/2474] Physics updates - Make airblast work again (it was working before, but not updating local physics) - Make napalms/shock/gas not freeze when they reach expiry (part of more precise explosion locations for other types) - Minor clean-up to napalm code --- ssqc/pyro.qc | 139 ++++++++++++++++++++++++-------------------------- ssqc/tfort.qc | 10 ++-- 2 files changed, 72 insertions(+), 77 deletions(-) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 3afd7537..ff9c9817 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -729,85 +729,78 @@ void () UseAirBlast = { return; } - if (self.special_cooldown < time) - { - self.airblast_cooldown = 1; - self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; - entity timer = spawn(); - timer.owner = self; - timer.classname = "timer"; - timer.nextthink = time + PC_PYRO_AIRBLAST_COOLDOWN; - timer.think = AirBlastReloadFinished; + if (time < self.special_cooldown) + return; + + self.airblast_cooldown = 1; + self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; + entity timer = spawn(); + timer.owner = self; + timer.classname = "timer"; + timer.nextthink = time + PC_PYRO_AIRBLAST_COOLDOWN; + timer.think = AirBlastReloadFinished; - pointparticles(particleeffectnum("te_teleportsplash"), + pointparticles(particleeffectnum("te_teleportsplash"), self.origin + v_forward * PC_PYRO_AIRBLAST_RANGE / 4, v_forward); - FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); - makevectors(self.v_angle); - entity ent; + FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); + makevectors(self.v_angle); - ent = findradius(self.origin, PC_PYRO_AIRBLAST_RANGE); - while (ent) - { - if (ent.movetype != MOVETYPE_NONE && ent != self) - { - if (infront(ent)) - { - switch (ent.classname) - { - case "player": - case "pyro_rocket": - case "flamerflame": - case "proj_tranq": - case "proj_bullet": - case "proj_rocket": - case "grenade": - case "spike": - case "pipebomb": - vector targorg; - targorg = ent.origin; - float pushval = 1000; - if (ent == self) - { - pushval = 500; - traceline(self.origin, self.origin + v_forward * 200, MOVE_NOMONSTERS, self); - if (trace_fraction < 1) - { - targorg = self.origin - (v_forward * 200 * trace_fraction); - } - } - - vector delta = targorg - self.origin; - float dist = vlen(delta); - float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; + int count; + entity* list = findradius_list(self.origin, PC_PYRO_AIRBLAST_RANGE, count); + + for (int i = 0; i < count; i++) { + entity ent = list[i]; + + if (ent.movetype == MOVETYPE_NONE || ent == self || !infront(ent)) + continue; + + switch (ent.classname) { + case "player": + case "pyro_rocket": + case "flamerflame": + case "proj_tranq": + case "proj_bullet": + case "proj_rocket": + case "grenade": + case "spike": + case "pipebomb": + break; - if (ent.flags & FL_ONGROUND) - { - if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted - { - setorigin(ent, ent.origin + '0 0 1'); - } - } - - delta = normalize(delta); - delta = delta * percent * pushval; + default: + continue; // Next in list. + } - if (ent.movetype == MOVETYPE_FLYMISSILE) - { - float speed = vlen(ent.velocity); - ent.velocity = normalize(delta) * speed; - } - else - { - ent.velocity = ent.velocity + delta; - } - - break; - } - } - } - - ent = ent.chain; + vector targorg; + targorg = ent.origin; + float pushval = 1000; + if (ent == self) { + pushval = 500; + traceline(self.origin, self.origin + v_forward * 200, MOVE_NOMONSTERS, self); + if (trace_fraction < 1) + targorg = self.origin - (v_forward * 200 * trace_fraction); } + + vector delta = targorg - self.origin; + float dist = vlen(delta); + float percent = (PC_PYRO_AIRBLAST_RANGE - dist) / PC_PYRO_AIRBLAST_RANGE; + + if (ent.flags & FL_ONGROUND) { + if (ent.classname != "pipebomb" && ent != self) // leave them on ground, we don't want them blasted + setorigin(ent, ent.origin + '0 0 1'); + } + + delta = normalize(delta); + delta = delta * percent * pushval; + + if (ent.movetype == MOVETYPE_FLYMISSILE) { + float speed = vlen(ent.velocity); + ent.velocity = normalize(delta) * speed; + } else { + ent.velocity = ent.velocity + delta; + } + + if (ent.classname != "player") + ent.SendFlags |= FOPP_POS; } }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c00751da..11778104 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -796,6 +796,7 @@ static struct stg_table_entry { int id; void() touch; void() think; + float no_expiry; }; stg_table_entry stg_table[] = { @@ -803,12 +804,12 @@ stg_table_entry stg_table[] = { { GREN_CONC, ConcussionGrenadeTouch, FO_T_GrenExplode}, { GREN_BLAST, BlastGrenadeTouch, BlastGrenadeExplode}, { GREN_NAIL, NailGrenadeTouch, NailGrenadeExplode}, - { GREN_SHOCK, ShockGrenadeTouch, ShockGrenadeExplode}, + { GREN_SHOCK, ShockGrenadeTouch, ShockGrenadeExplode, TRUE}, { GREN_BURST, BurstGrenadeTouch, BurstGrenadeExplode}, { GREN_MIRV, MirvGrenadeTouch, MirvGrenadeExplode}, - { GREN_NAPALM, NapalmGrenadeTouch, NapalmGrenadeExplode1}, + { GREN_NAPALM, NapalmGrenadeTouch, NapalmGrenadeExplode1, TRUE}, { GREN_FLARE, FlareGrenadeTouch, FlareGrenadeExplode}, - { GREN_GAS, GasGrenadeTouch, GasGrenadeExplode1}, + { GREN_GAS, GasGrenadeTouch, GasGrenadeExplode1, TRUE}, { GREN_EMP, EMPGrenadeTouch, EMPGrenadeExplode}, { GREN_FLASH, FlashGrenadeTouch, FlashGrenadeExplode}, { GREN_CALTROP, CanisterTouch, ScatterCaltrops}, @@ -853,7 +854,8 @@ void (entity timer) FO_SpawnThrownGrenade = { stg_table_entry* ste = &stg_table[gtype - GREN_FIRST]; proj.fpp.gren_type = gtype; - proj.fpp.expires_at = timer.heat; + if (!ste->no_expiry) + proj.fpp.expires_at = timer.heat; proj.skin = gdesc->skin; proj.touch = ste->touch; proj.think = ste->think; From f166ebb37e1fe2934cdcd5d81b9b9dc27d8a7286 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 5 Dec 2022 15:36:01 -0800 Subject: [PATCH 1930/2474] Automatic minping Add Support for synchronizing clients to an automatic minping. Configured via `localinfo min_ping_ms x` (or mpm for short). Cooperating clients will automatically calibrate their delay-packets in a uniform fashion. --- csqc/main.qc | 5 +++ csqc/weapon_predict.qc | 70 ++++++++++++++++++++++++++++++++++++++++++ share/commondefs.qc | 2 ++ share/prediction.qc | 3 ++ 4 files changed, 80 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index b1e0eec4..456f8533 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -447,6 +447,9 @@ void CSQC_Shutdown() = { FO_WriteSettings(); } +// We can query, but not set via an autocvar. +DEFCVAR_FLOAT(cl_delay_packets, 0); + float last_servercommandframe; void _Sync_ServerCommandFrame() { // Server command frames are monotonically unique, we can skip processing @@ -479,6 +482,8 @@ void _Sync_ServerCommandFrame() { setviewprop(VF_AFOV, cvar("fov")); setsensitivityscaler(1); } + + UpdateMinPing(); } float last_clientcommandframe; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index b7277a8d..02a96c3c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -128,6 +128,7 @@ static float CalcPredEnabled(float current_enable, } #define ENABLE_CHECK_PERIOD 2 +static float client_delay_packets; static float next_wpp_enable_check; static float next_ping_update; void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; @@ -159,8 +160,11 @@ void WPP_Status() { fill_avg_ping(&avg, &variance); printf(" inst_ping = %d client_ping = %d avg_ping = %d var = %d\n", ping, pstate_server.client_ping, avg, variance); + if (fo_config.min_ping_ms) + printf(" client_delay_packets = %d\n", client_delay_packets); printf("Config:\n"); + PRINT_CONFIG(min_ping_ms); PRINT_CONFIG(qc_physics); PRINT_CONFIG(static_newmis_ms); PRINT_CONFIG(dynamic_newmis_ms); @@ -263,6 +267,72 @@ void WPP_UpdateEnable(float force) { WP_UpdateViewModel(pengine.pweap_ent); } +DEFCVAR_FLOAT(fo_minping_min, 0); // Can be used to set a lower-bound on + // what minping will be chosen. +DEFCVAR_FLOAT(cl_delay_packets, 0); // Can be used to query, but not set. + +void UpdateMinPing() { + static float next_update; + if (!fo_config.min_ping_ms || time < next_update) + return; + next_update = time + 1; + + const float PING_SAMPLES = 10; + static float num_samples; + static float ping_cache[PING_SAMPLES]; + static float once; + + if (CVARF(cl_delay_packets) != client_delay_packets) { + // We expect to see a one-time mismatch, but after this, clients are + // trying to change it on us. Make that noisy. + if (once) + localcmd(sprintf("say forced reset delay_packets %d -> %d\n", + CVARF(cl_delay_packets), client_delay_packets)); + once = TRUE; + + next_update = time + 0.1; + localcmd(sprintf("cl_delay_packets %d\n", client_delay_packets)); + return; + } + + float cache_index = (num_samples++) % ping_cache.length; + ping_cache[cache_index] = + max(0, getplayerkeyfloat(player_localnum, INFOKEY_P_PING)); + + if (num_samples < 10) + return; + + float ping = ping_cache[0]; + for (int i = 1; i < ping_cache.length; i++) + ping = min(ping, ping_cache[i]); + + ping = max(ping - client_delay_packets, SERVER_FRAME_MS); + float target = max(fo_config.min_ping_ms - ping, 0); + + if (CVARF(fo_minping_min) > 0) + target = max(target, CVARF(fo_minping_min)); + + if (!is_player) + target = 0; + + if (target == 0) { + client_delay_packets = 0; + } else { + float nv = (ceil((target - 0.1)/ 3)) * 3 + 1; + // Bound how much we'll step at once. + if (!client_delay_packets) + client_delay_packets = nv; + else + client_delay_packets = min(client_delay_packets + 5, nv); + } + + if (CVARF(cl_delay_packets) != client_delay_packets) { + localcmd(sprintf("cl_delay_packets %d\n", client_delay_packets)); + setlocaluserinfo(0, "client_delay_packets", ftos(client_delay_packets)); + num_samples = 0; + } +} + float IsEffectFrame() { if (!pengine.is_effectframe) return FALSE; diff --git a/share/commondefs.qc b/share/commondefs.qc index 6c25d6fe..cfb89528 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -22,6 +22,8 @@ enumflags { }; var struct { + float min_ping_ms; + float qc_physics; float static_newmis_ms; float dynamic_newmis_ms; diff --git a/share/prediction.qc b/share/prediction.qc index f3c3bb86..00e40a70 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -374,6 +374,7 @@ float WP_SendConfig(entity to_player, float sendflags) { void EntUpdate_Config() { #endif COMM(Byte, qc_physics); + COMM(Byte, min_ping_ms); COMM(Float, static_newmis_ms); COMM(Float, dynamic_newmis_ms); COMM(Byte, max_rewind_ms); @@ -556,6 +557,7 @@ void EntUpdate_Projectile(float isnew) { void Predict_InitDefaultConfig() { + fo_config.min_ping_ms = 0; fo_config.qc_physics = 1; fo_config.static_newmis_ms = 50; fo_config.dynamic_newmis_ms = 0; @@ -604,6 +606,7 @@ static void WeaponPred_CheckConfigUpdate() { // Target is also the long form localinfo name. CONFIG_UPDATE("qcp", qc_physics); + CONFIG_UPDATE("mpm", min_ping_ms); CONFIG_UPDATE("snm", static_newmis_ms); CONFIG_UPDATE("dnm", dynamic_newmis_ms); CONFIG_UPDATE("mrt", max_rewind_ms); From 8f231393e98d2950bb8f8519b31dd0b033b6266e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 5 Dec 2022 16:12:15 -0800 Subject: [PATCH 1931/2474] Clear delay-packets when minping cleared When we believe minping set delay_packets, ensure it's cleared when removed server-side. --- csqc/weapon_predict.qc | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 02a96c3c..819b8c18 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -271,9 +271,24 @@ DEFCVAR_FLOAT(fo_minping_min, 0); // Can be used to set a lower-bound on // what minping will be chosen. DEFCVAR_FLOAT(cl_delay_packets, 0); // Can be used to query, but not set. +static void set_minping_delay_packets() { + localcmd(sprintf("cl_delay_packets %d\n", client_delay_packets)); + setlocaluserinfo(0, "client_delay_packets", ftos(client_delay_packets)); +} + void UpdateMinPing() { static float next_update; - if (!fo_config.min_ping_ms || time < next_update) + + if (!fo_config.min_ping_ms) { + // Clear, if-and-only-if, we control the value. + if (client_delay_packets) { + client_delay_packets = 0; + set_minping_delay_packets(); + } + return; + } + + if (time < next_update) return; next_update = time + 1; @@ -291,7 +306,7 @@ void UpdateMinPing() { once = TRUE; next_update = time + 0.1; - localcmd(sprintf("cl_delay_packets %d\n", client_delay_packets)); + set_minping_delay_packets(); return; } @@ -323,11 +338,11 @@ void UpdateMinPing() { if (!client_delay_packets) client_delay_packets = nv; else - client_delay_packets = min(client_delay_packets + 5, nv); + client_delay_packets = min(client_delay_packets + 10, nv); } if (CVARF(cl_delay_packets) != client_delay_packets) { - localcmd(sprintf("cl_delay_packets %d\n", client_delay_packets)); + set_minping_delay_packets(); setlocaluserinfo(0, "client_delay_packets", ftos(client_delay_packets)); num_samples = 0; } From 3664c3e344b88a7ac339d130efca5e26da574c6e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 5 Dec 2022 16:18:48 -0800 Subject: [PATCH 1932/2474] Re-enable adjustment of throw-time when REWIND_GRENADES is enabled Grenade fountains no more. Also make sure that we freeze shock grenade when it pops up. --- csqc/weapon_predict.qc | 30 ++++++++++++++++++------------ share/commondefs.qc | 2 ++ ssqc/tfort.qc | 3 ++- ssqc/tsoldier.qc | 1 + 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 819b8c18..398221aa 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1169,6 +1169,22 @@ void (float ox) W_FireSpikes = { static float QcPhysics() { return fo_config.qc_physics; } +static float CanThrowGrenade(int gren_type) { + if (pstate_pred.client_time < pstate_pred.last_prime + 0.8) + return FALSE; // Not time to throw yet, THROWING set if necessary. + + float last_possible_throw = pstate_pred.last_prime + 3.7; + last_possible_throw -= FO_RewindGrenDt(gren_type); + + // We're conservative here, a missed predicted projectile throw into what's + // actually a held grenade is frustrating. Better to leave it up to the + // server when it's really tight. + if (pstate_pred.client_time > last_possible_throw - 1.5 * SERVER_FRAME_DT) + return FALSE; // Buckle up... probably. + + return TRUE; +} + static void W_ThrowGren(float is_throw) { if (!QcPhysics() || !RewindFlagEnabled(REWIND_GRENADES)) return; @@ -1181,20 +1197,10 @@ static void W_ThrowGren(float is_throw) { else if (pstate_pred.tfstate & TFSTATE_GRENTHROWING == 0) return; - if (pstate_pred.client_time < pstate_pred.last_prime + 0.8) - return; // Not time to throw yet, THROWING set if necessary. - int type_index = (pstate_pred.tfstate & TFSTATE_GREN1_PRIMED) ? 0 : 1; int gren_type = FO_ClassGren(pstate_pred.playerclass, type_index)->id; - - float last_possible_throw = pstate_pred.last_prime + 3.7; - last_possible_throw -= FO_RewindGrenDt(gren_type); - - // We're conservative here, a missed predicted projectile throw into what's - // actually a held grenade is frustrating. Better to leave it up to the - // server when it's really tight. - if (pstate_pred.client_time > last_possible_throw - 1.5 * SERVER_FRAME_DT) - return; // Buckle up... probably. + if (!CanThrowGrenade(gren_type) && !IsClownMode(CLOWN_SPAM_GRENADES)) + return; if (IsEffectFrame()) { entity gren = PP_CreateProjectile(FPP_HANDGRENADE, '0 0 0'); diff --git a/share/commondefs.qc b/share/commondefs.qc index cfb89528..1efc6b32 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -76,6 +76,7 @@ enumflags { CLOWN_LETHAL_TRANQ, CLOWN_STICKY_GRENS, CLOWN_STICKY_PIPES, + CLOWN_SPAM_GRENADES, }; string CLOWN_DESC[] = { @@ -85,6 +86,7 @@ string CLOWN_DESC[] = { "elephant tranq", "sticky grenades", "sticky pipes", + "no grenade prime-time", }; inline float IsClownMode(int flag) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 11778104..f83be9db 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1122,7 +1122,8 @@ void () FO_ThrowGrenade = { if (RewindFlagEnabled(REWIND_GRENADES)) throwtime = bounded_remote_time(FO_RewindGrenDt(timer.fpp.gren_type)); - if (timer.nextthink != timer.heat || timer.heat - time < 0.1) { + if ((timer.nextthink < timer.heat || throwtime > timer.heat - lockout) && + !IsClownMode(CLOWN_SPAM_GRENADES)) { // We do not allow throwing within the 0.8s, or the last 0.1s. // The former is a priming time, the latter is so that client side // knockback will be able to reliably predict whether a grenade was held diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index a38043e2..b32dbd7f 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -94,6 +94,7 @@ void () ShockGrenadeExplode = { } self.no_active_nail_grens = self.owner.no_active_nail_grens; self.movetype = MOVETYPE_FLY; + self.velocity = '0 0 0'; setorigin(self, self.origin + '0 0 32'); if(solid_nailgren) { setsize(self, '-1 -1 -1', '1 1 1'); From 7638e0e82fc757914da9f426029a320aa5ae87f6 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 6 Dec 2022 00:11:49 -0800 Subject: [PATCH 1933/2474] Move viewmodel to its own entity Also fix spectator not seeing viewmodel. --- csqc/main.qc | 5 ++++- csqc/weapon_predict.qc | 50 ++++++++++++++++++++++-------------------- share/prediction.qc | 2 +- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 456f8533..fa448df8 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -136,7 +136,10 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) setproperty(VF_DRAWENGINESBAR, 1); - addentities((intermission?0:WPP_ViewModelMask())|MASK_ENGINE); + float mask = MASK_ENGINE; + if (!intermission) + mask |= WPP_ViewModelMask(); + addentities(mask); renderscene(); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 398221aa..a15a28e1 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -17,6 +17,7 @@ struct pengine_t { float player_entnum; // player_localentnum iff is_player == 1 entity player_ent; entity pweap_ent; + entity viewmodel; // Must include MASK_PRED_VIEWMODEL or we lose updates. // We only add/remove MASK_VIEWMODEL and MASK_PRED_PROJECTILE @@ -34,7 +35,7 @@ float WP_MinPing() { return CVARF(wpp_min_ping); } -void WP_UpdateViewModel(entity pweap_ent); +void WP_UpdateViewModel(); #define csqc_print(...) \ do { if (CVARF(wpp_debug) & 4) { \ @@ -260,11 +261,11 @@ void WPP_UpdateEnable(float force) { (pengine.pp_enabled ? CSQC_PROJ_PRED : 0); setlocaluserinfo(0, "fo_wpp_status", ftos(wpp_status)); // We always need to "render" the view model to trigger predraw compute. - pengine.view_mask = MASK_PRED_VIEWMODEL | + pengine.view_mask = MASK_PRED_ENT | MASK_VIEWMODEL | (pp_new ? MASK_PRED_PROJECTILE : 0); - if (pengine.pweap_ent != __NULL__) - WP_UpdateViewModel(pengine.pweap_ent); + if (pengine.viewmodel != __NULL__) + WP_UpdateViewModel(); } DEFCVAR_FLOAT(fo_minping_min, 0); // Can be used to set a lower-bound on @@ -1414,17 +1415,15 @@ void InitProjectileEnt(float sendflags) { DEFCVAR_FLOAT(r_drawviewmodel, 1); -void WP_UpdateViewModel(entity pweap_ent) { +void WP_UpdateViewModel() { + entity viewmodel = pengine.viewmodel; float pmodelindex, pframe; FO_WeapInfo* wi = WP_CurrentWeapon(); - // Note, even if the predicted weapon model is not visible we might still be - // using it to generated predicted projectiles. E.g. we need to keep - // PRED_VIEWMODEL in the render mask. if (!WP_Enabled() || wi->predict_type == NO_PREDICT) { // Fall back to engine. - pweap_ent.modelindex = 0; + viewmodel.modelindex = 0; pengine.view_mask |= MASK_VIEWMODEL; return; } else { @@ -1433,25 +1432,25 @@ void WP_UpdateViewModel(entity pweap_ent) { static float no_weap_mask = TFSTATE_NO_WEAPON | TFSTATE_RELOADING | TFSTATE_FLASHED; if (pstate_pred.tfstate & no_weap_mask || CVARF(r_drawviewmodel) == 0) { - pweap_ent.modelindex = 0; + viewmodel.modelindex = 0; return; } - pweap_ent.alpha = CVARF(r_drawviewmodel); + viewmodel.alpha = CVARF(r_drawviewmodel); pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; - if (pweap_ent.modelindex != pmodelindex) { - pweap_ent.frame = pframe; - pweap_ent.modelindex = pmodelindex; - pweap_ent.lerpfrac = 0; - } else if (self.frame != pframe) { - pweap_ent.frame2 = self.frame; - pweap_ent.frame = pframe; - pweap_ent.lerpfrac = 1; + if (viewmodel.modelindex != pmodelindex) { + viewmodel.frame = pframe; + viewmodel.modelindex = pmodelindex; + viewmodel.lerpfrac = 0; + } else if (viewmodel.frame != pframe) { + viewmodel.frame2 = viewmodel.frame; + viewmodel.frame = pframe; + viewmodel.lerpfrac = 1; } - pweap_ent.lerpfrac = max(0, pweap_ent.lerpfrac - frametime * 10); + viewmodel.lerpfrac = max(0, viewmodel.lerpfrac - frametime * 10); } void PM_PredictJump(); @@ -1497,15 +1496,18 @@ float WP_ClientThink() { WP_Frame(); } - WP_UpdateViewModel(self); + WP_UpdateViewModel(); return PREDRAW_AUTOADD; } void InitWeapPredEnt(entity pe) { pe.predraw = WP_ClientThink; + pengine.pweap_ent = pe; + pe.drawmask = MASK_PRED_ENT; - self.drawmask = MASK_PRED_VIEWMODEL; - self.renderflags = RF_VIEWMODEL; + entity viewmodel = spawn(); + viewmodel.drawmask = MASK_PRED_ENT; + viewmodel.renderflags = RF_VIEWMODEL | RF_DEPTHHACK; + pengine.viewmodel = viewmodel; - pengine.pweap_ent = pe; } diff --git a/share/prediction.qc b/share/prediction.qc index 00e40a70..046ff783 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -276,7 +276,7 @@ float FO_MaxRewindGrenWinDt() { #else predict_tf_state pstate_pred, pstate_server; -#define MASK_PRED_VIEWMODEL 256 +#define MASK_PRED_ENT 256 #define MASK_PRED_PROJECTILE 512 #endif From e34551d3fcec10b0b5f96a4a700d9b6e6a3f5d61 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 6 Dec 2022 17:45:39 -0800 Subject: [PATCH 1934/2474] First TFX implementation A lot of dodgy hacks to get a first pass up and running, but supports: - Outlining players through walls - Outlining flags through walls (o can always see, d can only see when not carried) - Showing grenade timers Metered by whether you're spectating, offense, defense, etc. --- csqc/csextradefs.qc | 1 + csqc/csprogs.src | 1 + csqc/events.qc | 5 + csqc/main.qc | 5 + csqc/tfx.qc | 295 +++++++++++++++++++++++++++++++++++++++++ csqc/weapon_predict.qc | 17 ++- share/commondefs.qc | 36 +++++ share/defs.h | 1 + share/prediction.qc | 4 + ssqc/quadmode.qc | 1 + ssqc/qw.qc | 1 + ssqc/status.qc | 23 +++- ssqc/world.qc | 1 + 13 files changed, 387 insertions(+), 4 deletions(-) create mode 100644 csqc/tfx.qc diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 8433df5c..c4b6b285 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -67,6 +67,7 @@ const vector PLAYER_MAXS = [16, 16, 24]; #define MAP_MAX_CHARS 20 +.void() removefunc; .float owned_by; .string netname; .float playerid; diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 0ef4cb4f..48c655d4 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -22,6 +22,7 @@ profile.qc ../share/animate.qc weapon_predict.qc pmove.qc +tfx.qc sui_sys.qc vote.qc status.qc diff --git a/csqc/events.qc b/csqc/events.qc index 17f13ee5..d780caf8 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -113,6 +113,11 @@ void() CSQC_Parse_Event = { last_death_time = readfloat(); StopGrenTimers(); break; + case MSG_TFX_GRENTIMER: + float entnum = readentitynum(); + float explodes_at = readfloat(); + TFxGrenTimerUpdate(entnum, explodes_at); + break; case MSG_CLIENT_MENU: float menutype = readfloat(); switch (menutype) { diff --git a/csqc/main.qc b/csqc/main.qc index fa448df8..e278b2b5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -117,6 +117,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_list_offset = 0; current_vote = world; vote_list_filter = ""; + + TF_Init(); }; noref void() CSQC_WorldLoaded = { @@ -142,6 +144,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { addentities(mask); renderscene(); + TFxRenderGrenadeTimers(); Hud_UpdateView(width, height, menushown, fts); @@ -406,6 +409,8 @@ void(float isnew) CSQC_Ent_Update = { }; void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and will no longer be tracked... + if (self.removefunc) + self.removefunc(); remove(self); }; diff --git a/csqc/tfx.qc b/csqc/tfx.qc new file mode 100644 index 00000000..0e69aba5 --- /dev/null +++ b/csqc/tfx.qc @@ -0,0 +1,295 @@ +.entity outline; +.float grentimer_expires; // TODO: integrate this +.float teamno; +static entity local_player; +static float shader_team[2], shader_flag; + +enum { + TeamNone = 0, + TeamBlue = 1, + TeamRed = 2, +}; + + +static float FlagCarried() { // Just awful. + for (int i = 0; i < FlagInfoLines.length; i++) + if (FlagInfoLines[i].state == FLAGINFO_CARRIED) + return TRUE; + return FALSE; +} + +// Until we network player entities we need somewhere to stash things. +struct EntHash { + int entnum; + float grentimer_expires; +}; +static EntHash ent_hash[43]; + +static EntHash* EntGet(int ent_num) { + EntHash* he = __NULL__; + + for (int i = 0; i < ent_hash.length; i++) { + he = &ent_hash[(i + ent_num) % ent_hash.length]; + if (he->entnum == ent_num) + return he; + else if (!he->entnum) + break; + } + + he->entnum = ent_num; + return he; +} + +static float TeamNo(entity player) { + // This is horrific, but the most immediately accessible thing we seem to + // have. getentity() is just unreliable. + float pc = stof(infokey(player, INFOKEY_P_BOTTOMCOLOR)); + switch (pc) { + case 13: return TeamBlue; + case 4: return TeamRed; + } + return TeamNone; +} + +static inline float AttackingTeamNo() { return getstatf(STAT_TEAMNO_ATTACK); } + +static float IsAttacking(entity player) { + /* return TeamNo(player) == getstatf(STAT_TEAMNO_ATTACK); */ + return player.teamno == AttackingTeamNo(); +} + +static float ShowPlayerOutline(entity player) { + if (player.entnum == player_localentnum || player.teamno == TeamNone) + return FALSE; + + if (prematch && TFxEnabled(TFX_PREMATCH_OUTLINE)) + return TRUE; + + if (!is_player) + return TFxEnabled(TFX_SPEC_OUTLINE); + + if ((TFxEnabled(TFX_DEFENSE_OUTLINE) && !IsAttacking(player)) || + (TFxEnabled(TFX_OFFENSE_OUTLINE) && IsAttacking(player))) + return player.teamno == local_player.teamno; + + return FALSE; +} + +static void RemoveOutline() { + if (self.outline != __NULL__) + remove(self.outline); +} + +static void AddOutline(entity ent, string model) { + entity o = spawn(); + setmodel(o, model); + o.classname = "outline"; + o.fatness = 2; + setsize(o, PLAYER_MINS, PLAYER_MAXS); + + ent.outline = o; + ent.removefunc = RemoveOutline; +} + +static void UpdateOutline(entity player) { + entity o = player.outline; + if (!ShowPlayerOutline(player)) { + o.drawmask = 0; + return; + } + + o.forceshader = shader_team[TeamNo(player) - TeamBlue]; + o.drawmask = MASK_ENGINE; + o.frame = player.frame; + o.angles = player.angles; + if (player == local_player) + o.renderflags |= RF_EXTERNALMODEL; + setorigin(o, player.origin); + +} + +float UpdatePlayer(float isnew) { + if (isnew) { + if (self.entnum == player_localentnum && is_player) + local_player = self; + AddOutline(self, "progs/player.mdl"); + } + + if (self.entnum == player_localentnum) + self.renderflags |= RF_EXTERNALMODEL; + else + self.renderflags &= ~RF_EXTERNALMODEL; + + self.teamno = TeamNo(self); + + UpdateOutline(self); + return TRUE; +} + +static float ShowTeamGrenTimer(float team, float my_team) { + if (!is_player && TFxEnabled(TFX_SPEC_GRENTIMER)) + return TRUE; + + if (team == AttackingTeamNo()) { + if (TFxEnabled(TFX_OFFENSE_GRENTIMER) && team == my_team) + return TRUE; + } else { + if (TFxEnabled(TFX_DEFENSE_GRENTIMER) && team == my_team) + return TRUE; + } + + return FALSE; +} + +static entity gren_list[20]; +static int num_gren_list; +static float next_grenlist_update; + +static float RenderGrenTimer(entity p, float test_only) { + const float maxd = 1000, mind = 200; + vector po = p.origin + '0 0 40'; + vector o = pmove_org; + + if (p == local_player) + return FALSE; + + float diff = vlen(po - o); + if (diff > maxd) + return FALSE; + + traceline(o, po, 3, p); + if (trace_fraction < 1) + return FALSE; + + EntHash* he = EntGet(p.entnum); + float rem = he->grentimer_expires - time; + if (rem < 0) + return FALSE; + + if (test_only) + return TRUE; + + vector colors[] = { '1 0 0', '0.8 0.8 0.4', '0.8 0.5 0.5', '1 1 1'}; + vector c = project(po); + vector size = '8 8 8' * (maxd - max(diff, mind)) / (maxd - mind); + string str = ftos(ceil(rem)); + c.x -= stringwidth(str, FALSE, size) / 2; + drawstring(c, str, size, colors[floor(rem)], 1, 0); + + return TRUE; +} + +entity*(.__variant fld, __variant match, int type=EV_STRING, __out int count) find_list = #0:find_list; + +static void UpdateGrenList() { + if (time < next_grenlist_update) + return; + next_grenlist_update = time + 0.1; + num_gren_list = 0; + + float teams[] = {TeamRed, TeamBlue}; + + for (int i = 0; i < teams.length; i++) { + float team = teams[i]; + if (!ShowTeamGrenTimer(team, local_player.teamno)) + continue; + + int count; + entity* players = find_list(teamno, team, EV_FLOAT, count); + for (int j = 0; j < count; j++) { + entity p = players[j]; + + if (RenderGrenTimer(p, TRUE)) + gren_list[num_gren_list++] = p; + } + } +} + +void TFxRenderGrenadeTimers() { + UpdateGrenList(); + + for (int i = 0; i < num_gren_list; i++) { + entity p = gren_list[i]; + RenderGrenTimer(p, FALSE); + } +} + +static float ShowFlagOutline() { + if (!is_player && TFxEnabled(TFX_SPEC_SEEFLAG)) + return TRUE; + + if (TFxEnabled(TFX_OFFENSE_SEEFLAG) && IsAttacking(local_player)) + return TRUE; + + if (TFxEnabled(TFX_DEFENSE_SEEFLAG) && !IsAttacking(local_player) && + !FlagCarried()) + return TRUE; + + return FALSE; +} + +static void UpdateFlagOutline(entity flag) { + entity o = flag.outline; + if (!ShowFlagOutline()) { + o.drawmask = 0; + return; + } + + o.forceshader = shader_flag; + o.drawmask = MASK_ENGINE; + o.angles = flag.angles; + o.frame = flag.frame; + setorigin(o, flag.origin); +} + +float UpdateFlag(float isnew) { + if (isnew) + AddOutline(self, "progs/ff_flag.mdl"); + + UpdateFlagOutline(self); + + return TRUE; +} + +void TFxGrenTimerUpdate(float ent_num, float expiry) { + EntHash* he = EntGet(ent_num); + he->grentimer_expires = expiry; +} + +void TF_Init() { + precache_model("progs/player.mdl"); + deltalisten("progs/player.mdl", UpdatePlayer, 3); + deltalisten("progs/ff_flag.mdl", UpdateFlag, 0); + + shader_team[0] = shaderforname("blue_team", "{" + "sort nearest\n" + "{ map textures/sfx/quad.tga\n" + "rgbGen lightingDiffuse\n" + "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" + "tcgen environment\n" + "tcmod rotate 30\n" + "tcmod scroll 1.1\n" + "nodepthtest\n" + "}\n}"); + + shader_team[1] = shaderforname("red_team", "{" + "sort nearest\n" + "{ map textures/sfx/pent.tga\n" + "rgbGen lightingDiffuse\n" + "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" + "tcgen environment\n" + "tcmod rotate 30\n" + "tcmod scroll 1.1\n" + "nodepthtest\n" + "}\n}"); + + shader_flag = shaderforname("flag", "{" + "sort nearest\n" + "{ map textures/sfx/specular.tga\n" + "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" + "tcgen environment\n" + "tcmod scroll 1.1\n" + "nodepthtest\n" + "}\n}"); + +} diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index a15a28e1..c5899645 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -163,6 +163,17 @@ void WPP_Status() { ping, pstate_server.client_ping, avg, variance); if (fo_config.min_ping_ms) printf(" client_delay_packets = %d\n", client_delay_packets); + printf("\n"); + + if (fo_config.tfx_flags) { + printf("TFX [tfx_flags=%d]\n", fo_config.tfx_flags); + for (float i = 0; i < TFX_DESC.length; i++) { + float flag = 1 << i; + printf(" %2d [%-3s]: .%s\n", flag, TFxEnabled(flag) ? "on": "off", + TFX_DESC[i]); + } + printf("\n"); + } printf("Config:\n"); PRINT_CONFIG(min_ping_ms); @@ -177,18 +188,21 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(wpp_global_enable); PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); + printf("\n"); printf("Rewind Settings [rewind_flags=%d]:\n", fo_config.rewind_flags); for (float i = 0; i < REWIND_DESC.length; i++) { float flag = 1 << i; printf(" %2d [%-3s]: .%s\n", flag, - (fo_config.rewind_flags & flag) ? "on": "off", REWIND_DESC[i]); + RewindFlagEnabled(flag) ? "on": "off", REWIND_DESC[i]); } + PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(max_rewind_grenade_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); + printf("\n"); if (!fo_config.clown_flags) return; @@ -201,7 +215,6 @@ void WPP_Status() { if (flag == CLOWN_PROJ_GRAVITY) printf(" (clown_grav=%d)", fo_config.clown_grav); printf("\n"); - } } #undef PRINT_CONFIG diff --git a/share/commondefs.qc b/share/commondefs.qc index 1efc6b32..8f8e2e1e 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -37,6 +37,8 @@ var struct { float clown_flags; float clown_grav; + float tfx_flags; + float wp_global_enable; float wp_global_disable; float pp_global_enable; @@ -69,6 +71,38 @@ float RewindFlagEnabled(float flag) { return fo_config.rewind_flags & flag; } +enumflags { + TFX_SPEC_OUTLINE, + TFX_SPEC_SEEFLAG, + TFX_SPEC_GRENTIMER, + TFX_PREMATCH_OUTLINE, + TFX_OFFENSE_SEEFLAG, + TFX_DEFENSE_SEEFLAG, + TFX_OFFENSE_OUTLINE, + TFX_DEFENSE_OUTLINE, + TFX_OFFENSE_GRENTIMER, + TFX_DEFENSE_GRENTIMER, +}; + +string TFX_DESC[] = { + "Spectators see outlines", + "Spectators see flags", + "Spectators see grenade timers", + "Prematch see outlines", + "Offense sees flag (always)", + "Defense sees flag, when not carried", + "Offense sees grentimers", + "Defense sees grentimers", + "Offense sees outlines", + "Defense sees outlines", +}; + +float TFxEnabled(float flag) { + return fo_config.tfx_flags & flag; +} + +const float TFX_DEFAULT_FLAGS = TFX_SPEC_OUTLINE | TFX_SPEC_GRENTIMER | TFX_PREMATCH_OUTLINE; + enumflags { CLOWN_FAST_PROJECTILES, CLOWN_RUBBERGREN, @@ -137,6 +171,8 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_PAUSE 23 #define MSG_UNPAUSE 24 +#define MSG_TFX_GRENTIMER 25 + #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 #define FLAGINFO_DROPPED 3 diff --git a/share/defs.h b/share/defs.h index 90672a62..7c8392c2 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1512,6 +1512,7 @@ enumflags { #define STAT_TP_GREN1 38 #define STAT_TP_GREN2 39 #define STAT_PAUSED 40 +#define STAT_TEAMNO_ATTACK 41 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/share/prediction.qc b/share/prediction.qc index 046ff783..b2f0ea10 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -278,6 +278,7 @@ float FO_MaxRewindGrenWinDt() { predict_tf_state pstate_pred, pstate_server; #define MASK_PRED_ENT 256 #define MASK_PRED_PROJECTILE 512 +#define MASK_OUTLINE 1024 #endif @@ -383,6 +384,7 @@ void EntUpdate_Config() { COMM(Byte, max_rewind_grenade_ms); COMM(Short, rewind_fast_projectile_thresh); COMM(Byte, rewind_flags); + COMM(Short, tfx_flags); COMM(Byte, clown_flags); COMM(Float, clown_grav); COMM(Byte, wp_default_min_ping_ms); @@ -562,6 +564,7 @@ void Predict_InitDefaultConfig() { fo_config.static_newmis_ms = 50; fo_config.dynamic_newmis_ms = 0; fo_config.rewind_flags = REWIND_DEFAULT_FLAGS; + fo_config.tfx_flags = TFX_DEFAULT_FLAGS; fo_config.max_rewind_ms = 250; fo_config.max_rewind_slow_projectile_ms = 150; fo_config.max_rewind_fast_projectile_ms = 150; @@ -623,6 +626,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE("wppge", wpp_global_disable); CONFIG_UPDATE("gbd", gren_beta_disable); CONFIG_UPDATE("rewind", rewind_flags); + CONFIG_UPDATE("tfx", tfx_flags); CONFIG_UPDATE("clown", clown_flags); CONFIG_UPDATE("clown_grav", clown_grav); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 9bae1afc..2531a38e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -268,6 +268,7 @@ void () QuadRoundBegin = { round_over = 0; if(quad_roles) { + team_no_attack = 1 + (rounds % 2); //tfdet = find(world, classname, "info_tfdetect"); if(rounds % 2) { Team1_Role = &Role_Defence; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ea9de505..6f08dd1a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -192,6 +192,7 @@ float round_winner_team; entity round_winner; float round_winner_print_health; +float team_no_attack; .float team_no; // The team you belong to .float lives; // The number of lives you have left diff --git a/ssqc/status.qc b/ssqc/status.qc index cbd0a79f..3e6b60f1 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -763,6 +763,21 @@ string GetSBClassInfo(entity pl, float csqcactive) return st1; } +// Temporary until we network player ents. +static void TFxUpdateGrenadeTimer(entity player, float explodes_at) { + const float tfx_gren_mask = + TFX_SPEC_GRENTIMER | TFX_DEFENSE_GRENTIMER | TFX_OFFENSE_GRENTIMER; + + if (!TFxEnabled(tfx_gren_mask)) + return; + + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_TFX_GRENTIMER); + WriteEntity(MSG_MULTICAST, player); + WriteFloat(MSG_MULTICAST, explodes_at); + multicast('0 0 0', MULTICAST_ALL_R); +} + void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; @@ -773,15 +788,19 @@ void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { WriteFloat(MSG_MULTICAST, time); WriteFloat(MSG_MULTICAST, explodes_at); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); + + TFxUpdateGrenadeTimer(pl, explodes_at); } void UpdateClientGrenadeThrown(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENTHROWN); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); + + TFxUpdateGrenadeTimer(pl, 0); } void UpdateClientPlayerDie(entity pl) = { diff --git a/ssqc/world.qc b/ssqc/world.qc index 49949b8a..59a40248 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -338,6 +338,7 @@ void () worldspawn = { clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused"); + globalstat(STAT_TEAMNO_ATTACK, EV_FLOAT, "team_no_attack"); entity worldspawnent; worldspawnent = spawn(); From 026dd71f6ae35267cc0fd2ad392e181255a99be4 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 7 Dec 2022 17:22:56 -0800 Subject: [PATCH 1935/2474] Run jump prediction of leading client frame for now We can't recover prior pmove vals from getinputstate so until we're running pmove, just snoop the trailing edge of clientcommandframe. --- csqc/main.qc | 12 +----------- csqc/pmove.qc | 15 ++++++++++----- csqc/weapon_predict.qc | 3 --- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index e278b2b5..6fc90b4f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -494,22 +494,12 @@ void _Sync_ServerCommandFrame() { UpdateMinPing(); } -float last_clientcommandframe; -// REQUIRES: Must be called after _Sync_ServerCommandFrame. -void _Sync_ClientCommandFrame() { - // Client command frames are regenerated beyond the server frame, so we - // cannot check that we have not seen this client command frame alone. - if (last_servercommandframe == servercommandframe && - last_clientcommandframe == clientcommandframe) - return; - last_clientcommandframe = clientcommandframe; -} // Called for each {client, server} command frame, ensures globals are // synchronized with server and predicted state. void Sync_GameState() { _Sync_ServerCommandFrame(); - _Sync_ClientCommandFrame(); + PM_PredictJump(); } static string to_precision(float f, float p) { diff --git a/csqc/pmove.qc b/csqc/pmove.qc index dd3bdc8f..3b3099f0 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -2,7 +2,7 @@ const vector PLAYER_MINS = [-16, -16, -24]; const vector PLAYER_MAXS = [16, 16, 32]; inline float CSQC_JumpSounds_Active() { - return WP_Enabled() && CVARF(fo_csjumpsounds); + return CVARF(fo_csjumpsounds); } // Sets *type to whatever is at the feet of `point`. @@ -23,11 +23,19 @@ static float PM_GetWaterLevel(vector point, float* type) { } void PM_PredictJump() { - if (!CVARF(fo_csjumpsounds) || getstatf(STAT_PAUSED)) + if (!CSQC_JumpSounds_Active() || getstatf(STAT_PAUSED)) return; + static float last_clientframe; static float last_onground, last_waterlevel, last_vel_z; + if (!getinputstate(clientcommandframe) || input_timelength <= 0) + return; + + if (time <= last_clientframe) + return; + last_clientframe = time; + float fluidtype; float waterlevel = PM_GetWaterLevel(pmove_org, &fluidtype); float jumping = input_buttons & BUTTON2; @@ -42,9 +50,6 @@ void PM_PredictJump() { return; } - if (!IsEffectFrameMulti()) - return; - static float swimsound_next; string sound; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c5899645..7a049a90 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1466,8 +1466,6 @@ void WP_UpdateViewModel() { viewmodel.lerpfrac = max(0, viewmodel.lerpfrac - frametime * 10); } -void PM_PredictJump(); - float WP_ClientThink() { if (!WP_Enabled()) return PREDRAW_NEXT; @@ -1505,7 +1503,6 @@ float WP_ClientThink() { if (input_impulse) pstate_pred.impulse = input_impulse; - PM_PredictJump(); WP_Frame(); } From 3abb40445365fcc75dc0fe74296e41f657702d07 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 7 Dec 2022 18:29:17 -0800 Subject: [PATCH 1936/2474] Make outlines only outline Don't obscure player texture. Turn more stuff on for preview in prematch mode. --- csqc/main.qc | 2 +- csqc/tfx.qc | 24 +++++++++++++++++------- share/commondefs.qc | 8 +++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 6fc90b4f..b2e4d652 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -476,7 +476,7 @@ void _Sync_ServerCommandFrame() { is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) is_observer = FALSE; - is_player = !is_spectator && !is_observer; + is_player = (!is_spectator && !is_observer); local float health = getstatf(STAT_HEALTH); if (health <= 0 || player_class != PC_SNIPER) { diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 0e69aba5..e5230302 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -2,7 +2,7 @@ .float grentimer_expires; // TODO: integrate this .float teamno; static entity local_player; -static float shader_team[2], shader_flag; +static float shader_team[2], shader_flag, shader_over_outline; enum { TeamNone = 0, @@ -62,7 +62,7 @@ static float ShowPlayerOutline(entity player) { if (player.entnum == player_localentnum || player.teamno == TeamNone) return FALSE; - if (prematch && TFxEnabled(TFX_PREMATCH_OUTLINE)) + if (prematch && TFxEnabled(TFX_PREMATCH_EVERYTHING)) return TRUE; if (!is_player) @@ -84,7 +84,7 @@ static void AddOutline(entity ent, string model) { entity o = spawn(); setmodel(o, model); o.classname = "outline"; - o.fatness = 2; + o.fatness = 1; setsize(o, PLAYER_MINS, PLAYER_MAXS); ent.outline = o; @@ -113,6 +113,7 @@ float UpdatePlayer(float isnew) { if (self.entnum == player_localentnum && is_player) local_player = self; AddOutline(self, "progs/player.mdl"); + self.forceshader = shader_over_outline; } if (self.entnum == player_localentnum) @@ -130,6 +131,9 @@ static float ShowTeamGrenTimer(float team, float my_team) { if (!is_player && TFxEnabled(TFX_SPEC_GRENTIMER)) return TRUE; + if (prematch && TFxEnabled(TFX_PREMATCH_EVERYTHING)) + return TRUE; + if (team == AttackingTeamNo()) { if (TFxEnabled(TFX_OFFENSE_GRENTIMER) && team == my_team) return TRUE; @@ -218,6 +222,9 @@ static float ShowFlagOutline() { if (!is_player && TFxEnabled(TFX_SPEC_SEEFLAG)) return TRUE; + if (prematch && TFxEnabled(TFX_PREMATCH_EVERYTHING)) + return TRUE; + if (TFxEnabled(TFX_OFFENSE_SEEFLAG) && IsAttacking(local_player)) return TRUE; @@ -243,8 +250,10 @@ static void UpdateFlagOutline(entity flag) { } float UpdateFlag(float isnew) { - if (isnew) + if (isnew) { AddOutline(self, "progs/ff_flag.mdl"); + // Flags have their own shader already, just make them shiny for now. + } UpdateFlagOutline(self); @@ -262,7 +271,6 @@ void TF_Init() { deltalisten("progs/ff_flag.mdl", UpdateFlag, 0); shader_team[0] = shaderforname("blue_team", "{" - "sort nearest\n" "{ map textures/sfx/quad.tga\n" "rgbGen lightingDiffuse\n" "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" @@ -273,7 +281,6 @@ void TF_Init() { "}\n}"); shader_team[1] = shaderforname("red_team", "{" - "sort nearest\n" "{ map textures/sfx/pent.tga\n" "rgbGen lightingDiffuse\n" "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" @@ -283,8 +290,11 @@ void TF_Init() { "nodepthtest\n" "}\n}"); - shader_flag = shaderforname("flag", "{" + shader_over_outline = shaderforname("over_outline", "{" "sort nearest\n" + "}"); + + shader_flag = shaderforname("flag", "{" "{ map textures/sfx/specular.tga\n" "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" "tcgen environment\n" diff --git a/share/commondefs.qc b/share/commondefs.qc index 8f8e2e1e..b74b6d9b 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -72,10 +72,10 @@ float RewindFlagEnabled(float flag) { } enumflags { + TFX_PREMATCH_EVERYTHING, TFX_SPEC_OUTLINE, TFX_SPEC_SEEFLAG, TFX_SPEC_GRENTIMER, - TFX_PREMATCH_OUTLINE, TFX_OFFENSE_SEEFLAG, TFX_DEFENSE_SEEFLAG, TFX_OFFENSE_OUTLINE, @@ -85,10 +85,10 @@ enumflags { }; string TFX_DESC[] = { + "Prematch see everything", "Spectators see outlines", "Spectators see flags", "Spectators see grenade timers", - "Prematch see outlines", "Offense sees flag (always)", "Defense sees flag, when not carried", "Offense sees grentimers", @@ -101,7 +101,9 @@ float TFxEnabled(float flag) { return fo_config.tfx_flags & flag; } -const float TFX_DEFAULT_FLAGS = TFX_SPEC_OUTLINE | TFX_SPEC_GRENTIMER | TFX_PREMATCH_OUTLINE; +const float TFX_DEFAULT_FLAGS = + TFX_SPEC_OUTLINE | TFX_SPEC_GRENTIMER | TFX_SPEC_SEEFLAG | + TFX_PREMATCH_EVERYTHING; enumflags { CLOWN_FAST_PROJECTILES, From 1ae6b41bd8ce31145b13e055a263acc2b4704d07 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 8 Dec 2022 21:14:54 -0800 Subject: [PATCH 1937/2474] Fix autocvars around prior FOCMD defines This was generating compilable, but not correct code that would end up using FOCMD_... for cvar definitions. This was further masked by an incorrect use of cvar() sneaking back into the code that allowed it to pick up the legacy value on a client that had previously defined it (although it would be missing on a new install). While we're here, shoot another cvar() that's crept in around fov. --- csqc/csextradefs.qc | 7 ------- csqc/events.qc | 6 +++--- csqc/main.qc | 9 +++++---- csqc/pmove.qc | 4 +++- csqc/settings.qc | 45 +++++++++++++++++++++++++-------------------- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c4b6b285..2bd8dd45 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -810,13 +810,6 @@ string FO_ScoreBoardColumns[] = { "dmgt" }; -#define FOCMD_OLDSCOREBOARD "fo_oldscoreboard" -#define FOCMD_GRENTIMER "fo_grentimer" -#define FOCMD_GRENTIMERSOUND "fo_grentimersound" -#define FOCMD_GRENTIMERVOLUME "fo_grentimervolume" -#define FOCMD_JUMPVOLUME "fo_jumpvolume" -#define FOCMD_ADMIN_MENU_UPDATE_TIME "fo_adminrefresh" - DEFCVAR_FLOAT(fo_fte_hud, 0); DEFCVAR_FLOAT(fo_legacy_sbar, 0); DEFCVAR_FLOAT(fo_csjumpsounds, 1); diff --git a/csqc/events.qc b/csqc/events.qc index d780caf8..428f24b4 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -320,7 +320,7 @@ DEFCVAR_FLOAT(fo_grentimer_debug, 0); string cached_timer; string GetGrenTimerSound() { - string wav = CVARS(FOCMD_GRENTIMERSOUND); + string wav = CVARS(fo_grentimersound); if (cached_timer != wav) { precache_sound(wav); @@ -334,7 +334,7 @@ void CsGrenTimer::StartSound() { return; string wav = GetGrenTimerSound(); - float volume = CVARF(FOCMD_GRENTIMERVOLUME); + float volume = CVARF(fo_grentimervolume); // Note there's a bug where soundupdate returns false for a new sample, even // though it's started. @@ -381,7 +381,7 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { return; local float timer_flags = 0; - switch (CVARF(FOCMD_GRENTIMER)) { + switch (CVARF(fo_grentimer)) { case 0: break; case 1: timer_flags = FL_GT_SOUND; break; // 2 [and something sane for anything we don't recognize.] diff --git a/csqc/main.qc b/csqc/main.qc index b2e4d652..3a3ad333 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -229,7 +229,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { Menu_Cancel(); break; case "+fo_showscores": - if (CVARF(FOCMD_OLDSCOREBOARD) == 1) + if (CVARF(fo_oldscoreboard) == 1) { tokenize(findkeysforcommand(argv(0))); @@ -258,7 +258,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "+showscores": case "+showteamscores": showingscores = TRUE; - if (CVARF(FOCMD_OLDSCOREBOARD) != 1) + if (CVARF(fo_oldscoreboard) != 1) { tokenize(findkeysforcommand(argv(0))); @@ -457,6 +457,7 @@ void CSQC_Shutdown() = { // We can query, but not set via an autocvar. DEFCVAR_FLOAT(cl_delay_packets, 0); +DEFCVAR_FLOAT(fov, 90); float last_servercommandframe; void _Sync_ServerCommandFrame() { @@ -484,10 +485,10 @@ void _Sync_ServerCommandFrame() { } if (zoomed_in) { - setviewprop(VF_AFOV, cvar("fov")/3); + setviewprop(VF_AFOV, CVARF(fov))/3; setsensitivityscaler(1/3); } else { - setviewprop(VF_AFOV, cvar("fov")); + setviewprop(VF_AFOV, CVARF(fov)); setsensitivityscaler(1); } diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 3b3099f0..ed6192de 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -1,3 +1,5 @@ +DEFCVAR_FLOAT(fo_jumpvolume, 1); + const vector PLAYER_MINS = [-16, -16, -24]; const vector PLAYER_MAXS = [16, 16, 32]; @@ -80,7 +82,7 @@ void PM_PredictJump() { // stairs when combined with (1). We can test for this by // watching to see whether we actually got a sufficiently large // velocity increase. - localsound("player/plyrjmp8.wav", CHAN_AUTO, cvar(FOCMD_JUMPVOLUME)); + localsound("player/plyrjmp8.wav", CHAN_AUTO, CVARF(fo_jumpvolume)); } } diff --git a/csqc/settings.qc b/csqc/settings.qc index 88034d11..6e6c0e76 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -1,9 +1,8 @@ // Saved/Loaded/Restored by Settings funcs -DEFCVAR_FLOAT(FOCMD_GRENTIMER, 2); // Sound + Ping adjust -DEFCVAR_STRING(FOCMD_GRENTIMERSOUND, "grentimer.wav"); -DEFCVAR_FLOAT(FOCMD_GRENTIMERVOLUME, 1); -DEFCVAR_FLOAT(FOCMD_JUMPVOLUME, 1); -DEFCVAR_FLOAT(FOCMD_OLDSCOREBOARD, 0); +DEFCVAR_FLOAT(fo_grentimer, 2); // Sound + Ping adjust +DEFCVAR_STRING(fo_grentimersound, "grentimer.wav"); +DEFCVAR_FLOAT(fo_grentimervolume, 1); +DEFCVAR_FLOAT(fo_oldscoreboard, 0); // CVARS that just pass via regular config state. DEFCVAR_FLOAT(fo_hud_idle_alpha, 0.3); @@ -23,28 +22,34 @@ string FormatCfgVector(string line, string field, vector value) return line; } +const string FOCMD_OLDSCOREBOARD = "fo_oldscoreboard"; +const string FOCMD_GRENTIMER = "fo_grentimer"; +const string FOCMD_GRENTIMERSOUND = "fo_grentimersound"; +const string FOCMD_GRENTIMERVOLUME = "fo_grentimervolume"; +const string FOCMD_JUMPVOLUME = "fo_jumpvolume"; +const string FOCMD_ADMIN_MENU_UPDATE_TIME = "fo_adminrefresh"; void FO_WriteSettings() { // this overwrites float filehandle; filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(CVARF(FOCMD_GRENTIMER))); - line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, CVARS(FOCMD_GRENTIMERSOUND)); - line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, ftos(CVARF(FOCMD_GRENTIMERVOLUME))); - line = FormatCfgString(line, FOCMD_JUMPVOLUME, ftos(CVARF(FOCMD_JUMPVOLUME))); - line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(CVARF(FOCMD_OLDSCOREBOARD))); + string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(CVARF(fo_grentimer))); + line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, CVARS(fo_grentimersound)); + line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, ftos(CVARF(fo_grentimervolume))); + line = FormatCfgString(line, FOCMD_JUMPVOLUME, ftos(CVARF(fo_jumpvolume))); + line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(CVARF(fo_oldscoreboard))); fputs(filehandle, line); fclose(filehandle); } void FO_LoadDefaultSettings() { - CVARF(FOCMD_GRENTIMER) = 2; - CVARS(FOCMD_GRENTIMERSOUND) = "grentimer.wav"; - CVARF(FOCMD_GRENTIMERVOLUME) = 1; - CVARF(FOCMD_JUMPVOLUME) = 1; - CVARF(FOCMD_OLDSCOREBOARD) = 0; + CVARF(fo_grentimer) = 2; + CVARS(fo_grentimersound) = "grentimer.wav"; + CVARF(fo_grentimervolume) = 1; + CVARF(fo_jumpvolume) = 1; + CVARF(fo_oldscoreboard) = 0; } void FO_LoadSettings() @@ -74,19 +79,19 @@ void FO_LoadSettings() switch(field) { case FOCMD_GRENTIMER: - CVARF(FOCMD_GRENTIMER) = stof(val); + CVARF(fo_grentimer) = stof(val); break; case FOCMD_GRENTIMERSOUND: - CVARS(FOCMD_GRENTIMERSOUND) = val; + CVARS(fo_grentimersound) = val; break; case FOCMD_GRENTIMERVOLUME: - CVARF(FOCMD_GRENTIMERVOLUME) = stof(val); + CVARF(fo_grentimervolume) = stof(val); break; case FOCMD_JUMPVOLUME: - CVARF(FOCMD_JUMPVOLUME) = stof(val); + CVARF(fo_jumpvolume) = stof(val); break; case FOCMD_OLDSCOREBOARD: - CVARF(FOCMD_OLDSCOREBOARD) = stof(val); + CVARF(fo_oldscoreboard) = stof(val); break; } } From 3376096a64897f0795068b1f3a04adc66146d059 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Dec 2022 00:29:38 -0800 Subject: [PATCH 1938/2474] TFX: Some shader tuning --- csqc/tfx.qc | 68 ++++++++++++++++++++++-------------------- csqc/weapon_predict.qc | 1 - 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/csqc/tfx.qc b/csqc/tfx.qc index e5230302..1ebc4ca2 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -95,9 +95,11 @@ static void UpdateOutline(entity player) { entity o = player.outline; if (!ShowPlayerOutline(player)) { o.drawmask = 0; + self.forceshader = 0; return; } + self.forceshader = shader_over_outline; o.forceshader = shader_team[TeamNo(player) - TeamBlue]; o.drawmask = MASK_ENGINE; o.frame = player.frame; @@ -112,8 +114,8 @@ float UpdatePlayer(float isnew) { if (isnew) { if (self.entnum == player_localentnum && is_player) local_player = self; + AddOutline(self, "progs/player.mdl"); - self.forceshader = shader_over_outline; } if (self.entnum == player_localentnum) @@ -265,41 +267,41 @@ void TFxGrenTimerUpdate(float ent_num, float expiry) { he->grentimer_expires = expiry; } +static string OutlineShader(string texture) { + return sprintf( +"{\ + sort 6\ + {\ + map %s\ + rgbGen lightingDiffuse\ + blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\ + tcgen environment\ + tcmod rotate 30\ + tcmod scroll 1.1\ + nodepthtest\ + depthfunc greater\ + }\ +}", texture); +} + +static string rnds(string prefix) { +#if 0 + // Debugging convenience, concatenates a random string when enabled so that + // shaders don't get cached on-client between builds. + for (int i = 0; i < 5; i++) + prefix = strcat(prefix, chr2str('a' + floor(random() * 26))); +#endif + return prefix; +} + void TF_Init() { precache_model("progs/player.mdl"); - deltalisten("progs/player.mdl", UpdatePlayer, 3); + deltalisten("progs/player.mdl", UpdatePlayer, 0); deltalisten("progs/ff_flag.mdl", UpdateFlag, 0); - shader_team[0] = shaderforname("blue_team", "{" - "{ map textures/sfx/quad.tga\n" - "rgbGen lightingDiffuse\n" - "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" - "tcgen environment\n" - "tcmod rotate 30\n" - "tcmod scroll 1.1\n" - "nodepthtest\n" - "}\n}"); - - shader_team[1] = shaderforname("red_team", "{" - "{ map textures/sfx/pent.tga\n" - "rgbGen lightingDiffuse\n" - "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" - "tcgen environment\n" - "tcmod rotate 30\n" - "tcmod scroll 1.1\n" - "nodepthtest\n" - "}\n}"); - - shader_over_outline = shaderforname("over_outline", "{" - "sort nearest\n" - "}"); - - shader_flag = shaderforname("flag", "{" - "{ map textures/sfx/specular.tga\n" - "blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\n" - "tcgen environment\n" - "tcmod scroll 1.1\n" - "nodepthtest\n" - "}\n}"); + shader_team[0] = shaderforname(rnds("blue_team_outline"), OutlineShader("textures/sfx/quad.tga")); + shader_team[1] = shaderforname(rnds("red_team_outline"), OutlineShader("textures/sfx/pent.tga")); + shader_flag = shaderforname(rnds("flag_outline"), OutlineShader("textures/sfx/specular.tga")); + shader_over_outline = shaderforname(rnds("over_outline"), "{ sort 7 }"); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 7a049a90..085787d2 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1519,5 +1519,4 @@ void InitWeapPredEnt(entity pe) { viewmodel.drawmask = MASK_PRED_ENT; viewmodel.renderflags = RF_VIEWMODEL | RF_DEPTHHACK; pengine.viewmodel = viewmodel; - } From e7dd9856b3d0f475510db0d65ba3723cba328a80 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Dec 2022 15:34:45 -0800 Subject: [PATCH 1939/2474] Don't pull inputs in inputframe We need this in pmove, but while we're building the input frame we have to omit or we'll clobber the in-situ frame. --- csqc/pmove.qc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index ed6192de..88cfec09 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -28,16 +28,8 @@ void PM_PredictJump() { if (!CSQC_JumpSounds_Active() || getstatf(STAT_PAUSED)) return; - static float last_clientframe; static float last_onground, last_waterlevel, last_vel_z; - if (!getinputstate(clientcommandframe) || input_timelength <= 0) - return; - - if (time <= last_clientframe) - return; - last_clientframe = time; - float fluidtype; float waterlevel = PM_GetWaterLevel(pmove_org, &fluidtype); float jumping = input_buttons & BUTTON2; From f92471cd64d8beb493f4863f1a42975fba05c423 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 9 Dec 2022 22:43:45 -0800 Subject: [PATCH 1940/2474] Workaround FTE pmove_vel bug Some versions of FTE do not correctly update pmove_vel (although other state, e.g. pmove_org is). Until we're directly tied to pmove, we snoop on recent values when we think this is happening. This seems to be fixed on newer builds. --- csqc/main.qc | 3 +++ csqc/pmove.qc | 13 +++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3a3ad333..9e6f062c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -149,6 +149,9 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { Hud_UpdateView(width, height, menushown, fts); perf_finish_sample(&frame_timing, fts); + + // Work around bug in some versions of FTE. See pmove.qc + recent_pmove_vel_z = pmove_vel_z; } noref float(string cmd) CSQC_ConsoleCommand = { diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 88cfec09..fb593869 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -24,6 +24,11 @@ static float PM_GetWaterLevel(vector point, float* type) { return waterlevel; } +// Some versions of FTE do not correctly update pmove_vel (although other state, +// e.g. pmove_org is). Until we're directly tied to pmove, we snoop on recent +// values when we think this is happening. +float recent_pmove_vel_z; + void PM_PredictJump() { if (!CSQC_JumpSounds_Active() || getstatf(STAT_PAUSED)) return; @@ -36,6 +41,7 @@ void PM_PredictJump() { float onground = pmove_onground; float landing = onground && !last_onground; float health = getstatf(STAT_HEALTH); + float vel_z = pmove_vel_z ?: recent_pmove_vel_z; if (health <= 0) { last_onground = 1; @@ -62,8 +68,7 @@ void PM_PredictJump() { swimsound_next = time + 1; sound = random() < 0.5 ? "player/water1.wav" : "player/water2.wav"; localsound(sound, CHAN_BODY, 1); - } else if (last_onground && !onground && - pmove_vel_z > last_vel_z + 200) { + } else if (last_onground && !onground && vel_z > last_vel_z + 200) { // The default pmove implementation and server behave slightly // differently here in two important ways here: // 1) Jump calculations run _prior_ to movement rather than post, @@ -90,7 +95,7 @@ void PM_PredictJump() { localsound("misc/outwater.wav", CHAN_BODY, 1); } - last_vel_z = pmove_vel_z; - last_onground = pmove_onground; + last_vel_z = vel_z; + last_onground = onground; last_waterlevel = waterlevel; }; From 88b090878d8e2e5741eb340914e0b37a9e2cc46a Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 11 Dec 2022 21:45:11 -0800 Subject: [PATCH 1941/2474] Add wpp_setspeed which allows CSQC to implement speed updates rather than stuff This reduces lerping/prediction errors for locally implemented weapons as we do not need wait for the server to initiate TFSTATE_AIMING, etc. This also avoids the use of lower maxspeed values, which do not arrive in time for pmove -- resulting in large lerps on state transition. Also: - Remove legacy independent tracking of forward/back and sidespeed, which was always symmetric and mirrored into qwsv's maxspeed. - Some cleanup of wpp_status() that snuck in while refactoring. --- csqc/weapon_predict.qc | 120 ++++++++++++++++++++++++----------------- share/classes.qc | 16 ++++++ share/commondefs.qc | 22 +++++++- share/defs.h | 11 ---- share/prediction.qc | 13 +++-- ssqc/qw.qc | 3 +- ssqc/tfort.qc | 105 ++++++++++++------------------------ 7 files changed, 153 insertions(+), 137 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 085787d2..45a6440a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -8,6 +8,8 @@ DEFCVAR_FLOAT(wpp_proj_predict, -1); DEFCVAR_FLOAT(wpp_phys_adv_ms, 0); DEFCVAR_FLOAT(wpp_phys_local_adv_ms, 0); +DEFCVAR_FLOAT(wpp_setspeed, 1); + struct pengine_t { float pp_enabled; float wp_enabled; @@ -138,6 +140,21 @@ void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocal printf(" ." #_field " = %d\n", fo_config.##_field) #define PRINT_CONFIG_ACTIVE(_field) \ if (fo_config.##_field) printf(" ." #_field " = %d\n", fo_config.##_field) + +static void PrintFlagField(string desc, float bits, float nbits, + string* bit_desc) { + if (!bits) + return; + + printf(desc, bits); + for (float i = 0; i < nbits; i++) { + float flag = 1 << i; + string enabled = (bits & flag) ? "on" : "off"; + printf(" %3d [%-3s]: %s\n", flag, enabled, bit_desc[i]); + } + printf("\n"); +} + void WPP_Status() { string wp_source, pp_source; float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; @@ -163,18 +180,9 @@ void WPP_Status() { ping, pstate_server.client_ping, avg, variance); if (fo_config.min_ping_ms) printf(" client_delay_packets = %d\n", client_delay_packets); + printf(" maxspeed = %d\n", pstate_server.csqc_maxspeed); printf("\n"); - if (fo_config.tfx_flags) { - printf("TFX [tfx_flags=%d]\n", fo_config.tfx_flags); - for (float i = 0; i < TFX_DESC.length; i++) { - float flag = 1 << i; - printf(" %2d [%-3s]: .%s\n", flag, TFxEnabled(flag) ? "on": "off", - TFX_DESC[i]); - } - printf("\n"); - } - printf("Config:\n"); PRINT_CONFIG(min_ping_ms); PRINT_CONFIG(qc_physics); @@ -188,15 +196,6 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(wpp_global_enable); PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); - printf("\n"); - - printf("Rewind Settings [rewind_flags=%d]:\n", fo_config.rewind_flags); - for (float i = 0; i < REWIND_DESC.length; i++) { - float flag = 1 << i; - printf(" %2d [%-3s]: .%s\n", flag, - RewindFlagEnabled(flag) ? "on": "off", REWIND_DESC[i]); - } - PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); PRINT_CONFIG(max_rewind_fast_projectile_ms); @@ -204,18 +203,14 @@ void WPP_Status() { PRINT_CONFIG(rewind_fast_projectile_thresh); printf("\n"); - if (!fo_config.clown_flags) - return; + PrintFlagField("Rewind Settings [rewind_flags=%d]\n", + fo_config.rewind_flags, REWIND_DESC.length, REWIND_DESC); - printf("Clown mode [clown_flags=%d]:\n", fo_config.clown_flags); - for (float i = 0; i < CLOWN_DESC.length; i++) { - float flag = 1 << i; - printf(" %2d [%-3s]: .%s", flag, - (fo_config.clown_flags & flag) ? "on": "off", CLOWN_DESC[i]); - if (flag == CLOWN_PROJ_GRAVITY) - printf(" (clown_grav=%d)", fo_config.clown_grav); - printf("\n"); - } + PrintFlagField("TFX [tfx_flags=%d]:\n", fo_config.tfx_flags, + TFX_DESC.length, TFX_DESC); + + PrintFlagField("Clown mode [clown_flags=%d]\n", + fo_config.clown_flags, CLOWN_DESC.length, CLOWN_DESC); } #undef PRINT_CONFIG @@ -270,8 +265,15 @@ void WPP_UpdateEnable(float force) { once = TRUE; - float wpp_status = (pengine.wp_enabled ? CSQC_WEAP_PRED : 0) + - (pengine.pp_enabled ? CSQC_PROJ_PRED : 0); + float wpp_status = 0; + if (pengine.wp_enabled) { + wpp_status |= CSQC_WEAP_PRED; + if (pengine.pp_enabled) + wpp_status |= CSQC_PROJ_PRED; + if (CVARF(wpp_setspeed)) + wpp_status |= CSQC_SETSPEED; + } + setlocaluserinfo(0, "fo_wpp_status", ftos(wpp_status)); // We always need to "render" the view model to trigger predraw compute. pengine.view_mask = MASK_PRED_ENT | MASK_VIEWMODEL | @@ -824,33 +826,53 @@ void WPP_Dump() { void WP_Attack(); -void MP_SetSpeed() { -#if 0 - // This wants ping correction to not be a punishment... - static float prev_state; +DEFCVAR_FLOAT(cl_forwardspeed, 0); +DEFCVAR_FLOAT(cl_backspeed, 0); +DEFCVAR_FLOAT(cl_sidespeed, 0); - if (!IsEffectFrame()) +void MP_SetSpeed() { + if (!CVARF(wpp_setspeed)) return; - if (pstate_pred.tfstate & TFSTATE_AIMING == prev_state) - return; + const float speed_aiming = 80; + const float speed_aiming2dir = ceil(speed_aiming/sqrt(2)); + static float last_playerclass; + + float speed = pstate_pred.csqc_maxspeed, force = FALSE; - prev_state = pstate_pred.tfstate & TFSTATE_AIMING; + float fastest = + max(CVARF(cl_forwardspeed), CVARF(cl_backspeed), CVARF(cl_sidespeed)); + + if (pstate_pred.playerclass != last_playerclass) + force = TRUE; + last_playerclass = pstate_pred.playerclass; - string mspeed = "999"; if (pstate_pred.tfstate & TFSTATE_AIMING) - mspeed = "80"; + speed = min(pstate_pred.csqc_maxspeed, speed_aiming); + else if (fastest == speed_aiming || fastest == speed_aiming2dir) + force = TRUE; // This is an imperfect good heuristic that avoids + // issues on missed packets/transitions/etc. + + // Cap as maxspeed would, but client-side, when enabled. + if (RewindFlagEnabled(REWIND_SETSPEED) && speed < pstate_pred.csqc_maxspeed) { + if (input_movevalues.x && input_movevalues.y) + speed = speed_aiming2dir; + else if (fastest == speed_aiming2dir) + force = TRUE; // reset back to speed_aiming + } - localcmd("cl_forwardspeed ", mspeed, "\n"); - localcmd("cl_sidespeed ", mspeed, "\n"); - localcmd("cl_backspeed ", mspeed, "\n"); -#endif + // We check >speed, not =speed as it's still valid for clients to control to + // lower speeds. Except for transitions where the maxspeed is reset. + if (fastest > speed || force) { + string spd = ftos(speed); + localcmd("cl_forwardspeed ", spd, "; cl_backspeed ",spd, "; cl_sidespeed ", spd, "\n"); + CVARF(cl_forwardspeed) = CVARF(cl_backspeed) = CVARF(cl_sidespeed) = speed; + } } -void WP_Frame() { - MP_SetSpeed(); +void WP_Frame() { if (getstatf(STAT_HEALTH) < 0) { pstate_pred.current_slot = SlotNull; return; @@ -873,6 +895,8 @@ void WP_Frame() { if ((input_buttons & BUTTON0) && !WP_IsReloading() && (pstate_pred.client_time >= pstate_pred.attack_finished)) WP_Attack(); + + MP_SetSpeed(); } diff --git a/share/classes.qc b/share/classes.qc index 10f0448e..7f3703e1 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -77,3 +77,19 @@ void WeapPred_FireAssCan(vector vangle, float shotcount, FO_FireAssCanPellet(org, spread_dir, var_speed, i); } } + +float Class_MaxSpeed(float playerclass) { + switch (playerclass) { + case PC_SCOUT: return PC_SCOUT_MAXSPEED; + case PC_SNIPER: return PC_SNIPER_MAXSPEED; + case PC_SOLDIER: return PC_SOLDIER_MAXSPEED; + case PC_DEMOMAN: return PC_DEMOMAN_MAXSPEED; + case PC_MEDIC: return PC_MEDIC_MAXSPEED; + case PC_HVYWEAP: return PC_HVYWEAP_MAXSPEED; + case PC_PYRO: return PC_PYRO_MAXSPEED; + case PC_SPY: return PC_SPY_MAXSPEED; + case PC_ENGINEER: return PC_ENGINEER_MAXSPEED; + case PC_CIVILIAN: return PC_CIVILIAN_MAXSPEED; + default: return 0; + } +} diff --git a/share/commondefs.qc b/share/commondefs.qc index b74b6d9b..76595458 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -37,6 +37,7 @@ var struct { float clown_flags; float clown_grav; + float predict_flags; float tfx_flags; float wp_global_enable; @@ -54,18 +55,21 @@ enumflags { REWIND_GRENADES, REWIND_FORWARD_DOORS, REWIND_FORWARD_PROJ_SELFKNOCK, + REWIND_SETSPEED, }; string REWIND_DESC[] = { "rewind pipe knockback", "rewind projectile hit", "rewind grenade throws", - "open doors earlier for hpbs [requires rfd=1]", "forward projectile self-knockback", + "open doors earlier for hpbs [requires rfd=1]", + "allow csqc to handle maxspeed" }; const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_HIT | - REWIND_FORWARD_PROJ_SELFKNOCK; + REWIND_FORWARD_PROJ_SELFKNOCK | + REWIND_SETSPEED; float RewindFlagEnabled(float flag) { return fo_config.rewind_flags & flag; @@ -105,6 +109,20 @@ const float TFX_DEFAULT_FLAGS = TFX_SPEC_OUTLINE | TFX_SPEC_GRENTIMER | TFX_SPEC_SEEFLAG | TFX_PREMATCH_EVERYTHING; +enum CSQCFlags { + PREDICT_CSQC_SETSPEED, +}; + +string PREDICTF_DESC[] = { + "allow csqc to handle maxspeed" +}; + +inline float PredictEnabled(float flag) { + return fo_config.predict_flags & flag; +}; + +const float PREDICT_FLAGS_DEFAULT = 0; + enumflags { CLOWN_FAST_PROJECTILES, CLOWN_RUBBERGREN, diff --git a/share/defs.h b/share/defs.h index 7c8392c2..84a8775a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -890,7 +890,6 @@ enumflags { #define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. #define PC_SCOUT_MAXHEALTH 100 // Maximum Health Level #define PC_SCOUT_MAXSPEED 450 // Maximum movement speed -#define PC_SCOUT_MAXSTRAFESPEED 450 // Maximum strafing movement speed #define PC_SCOUT_MAXARMOR 25 // Maximum Armor Level, of any armor class #define PC_SCOUT_INITARMOR 0 // Armor level when respawned #define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption @@ -920,7 +919,6 @@ enumflags { #define PC_SNIPER_SKIN 5 #define PC_SNIPER_MAXHEALTH 100 #define PC_SNIPER_MAXSPEED 300 -#define PC_SNIPER_MAXSTRAFESPEED 300 #define PC_SNIPER_MAXARMOR 40 #define PC_SNIPER_INITARMOR 0 #define PC_SNIPER_MAXARMORTYPE 0.3 @@ -947,7 +945,6 @@ enumflags { #define PC_SOLDIER_SKIN 6 #define PC_SOLDIER_MAXHEALTH 100 #define PC_SOLDIER_MAXSPEED 240 -#define PC_SOLDIER_MAXSTRAFESPEED 240 #define PC_SOLDIER_MAXARMOR 200 #define PC_SOLDIER_INITARMOR 100 #define PC_SOLDIER_MAXARMORTYPE 0.8 @@ -975,7 +972,6 @@ enumflags { #define PC_DEMOMAN_SKIN 1 #define PC_DEMOMAN_MAXHEALTH 100 #define PC_DEMOMAN_MAXSPEED 280 -#define PC_DEMOMAN_MAXSTRAFESPEED 280 #define PC_DEMOMAN_MAXARMOR 110 #define PC_DEMOMAN_INITARMOR 40 #define PC_DEMOMAN_MAXARMORTYPE 0.6 @@ -1004,9 +1000,7 @@ enumflags { #define PC_MEDIC_SKIN 3 #define PC_MEDIC_MAXHEALTH 100 #define PC_MEDIC_MAXSPEED 320 -#define PC_MEDIC_MAXSTRAFESPEED 320 #define PC_BLASTMEDIC_MAXSPEED 280 -#define PC_BLASTMEDIC_MAXSTRAFESPEED 280 #define PC_MEDIC_MAXARMOR 90 #define PC_MEDIC_INITARMOR 40 #define PC_MEDIC_MAXARMORTYPE 0.6 @@ -1047,7 +1041,6 @@ enumflags { #define PC_HVYWEAP_SKIN 2 #define PC_HVYWEAP_MAXHEALTH 100 #define PC_HVYWEAP_MAXSPEED 230 -#define PC_HVYWEAP_MAXSTRAFESPEED 230 #define PC_HVYWEAP_MAXARMOR 300 #define PC_HVYWEAP_INITARMOR 150 #define PC_HVYWEAP_MAXARMORTYPE 0.8 @@ -1075,7 +1068,6 @@ enumflags { #define PC_PYRO_SKIN 21 #define PC_PYRO_MAXHEALTH 100 #define PC_PYRO_MAXSPEED 300 -#define PC_PYRO_MAXSTRAFESPEED 300 #define PC_PYRO_MAXARMOR 150 #define PC_PYRO_INITARMOR 50 #define PC_PYRO_MAXARMORTYPE 0.6 @@ -1126,7 +1118,6 @@ enumflags { #define PC_SPY_SKIN 22 #define PC_SPY_MAXHEALTH 100 #define PC_SPY_MAXSPEED 300 -#define PC_SPY_MAXSTRAFESPEED 300 #define PC_SPY_MAXARMOR 90 #define PC_SPY_INITARMOR 15 #define PC_SPY_MAXARMORTYPE 0.6 @@ -1158,7 +1149,6 @@ enumflags { #define PC_ENGINEER_SKIN 22 // Not used anymore #define PC_ENGINEER_MAXHEALTH 100 #define PC_ENGINEER_MAXSPEED 300 -#define PC_ENGINEER_MAXSTRAFESPEED 300 #define PC_ENGINEER_MAXARMOR 30 #define PC_ENGINEER_INITARMOR 5 #define PC_ENGINEER_MAXARMORTYPE 0.6 @@ -1187,7 +1177,6 @@ enumflags { #define PC_CIVILIAN_SKIN 22 #define PC_CIVILIAN_MAXHEALTH 50 #define PC_CIVILIAN_MAXSPEED 240 -#define PC_CIVILIAN_MAXSTRAFESPEED 240 #define PC_CIVILIAN_MAXARMOR 0 #define PC_CIVILIAN_INITARMOR 0 #define PC_CIVILIAN_MAXARMORTYPE 0 diff --git a/share/prediction.qc b/share/prediction.qc index b2f0ea10..9de1db5c 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -39,6 +39,7 @@ enumflags { enumflags { CSQC_WEAP_PRED, CSQC_PROJ_PRED, + CSQC_SETSPEED, }; struct predict_tf_state { @@ -49,6 +50,7 @@ struct predict_tf_state { float tfstate; float last_prime; + float csqc_maxspeed; float client_time; float client_ping; @@ -273,6 +275,10 @@ float FO_MaxRewindGrenWinDt() { .predict_tf_state predict_state; .entity predict_entity; +inline float ClientPred_Enabled(entity client, float pred_flag) { + return infokeyf(client, "fo_wpp_status") & pred_flag; +} + #else predict_tf_state pstate_pred, pstate_server; @@ -308,7 +314,7 @@ static float Prediction_ChangedMask(entity player) { M1(FOWP_CLASS, playerclass); M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); - M1(FOWP_TFSTATE, tfstate); + M2(FOWP_TFSTATE, tfstate, csqc_maxspeed); M1(FOWP_LASTPRIME, last_prime); M1(FOWP_WF, weaponframe); M1(FOWP_AF, attack_finished); @@ -336,7 +342,7 @@ static float Prediction_ChangedMask(entity player) { #undef M4 void sprint_pred(entity client, float msglevel, string s) { - if (infokeyf(client, "fo_wpp_status") & CSQC_WEAP_PRED) + if (ClientPred_Enabled(client, CSQC_WEAP_PRED)) return; // Message generated client-side. sprint(client, msglevel, s); } @@ -440,6 +446,7 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_TFSTATE) { COMM(Float, tfstate); + COMM(Short, csqc_maxspeed); } if (sendflags & FOWP_LASTPRIME) { @@ -726,7 +733,7 @@ void Pred_Sound(SoundIndex snd, float vol = 1) { entity target = self; string wav = snd_types[snd].sound; - if (infokeyf(self, "fo_wpp_status") & CSQC_WEAP_PRED == 1) { + if (ClientPred_Enabled(self, CSQC_WEAP_PRED)) { target = self.predict_entity; setorigin(target, self.origin); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 6f08dd1a..0f2c876e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -138,8 +138,7 @@ float remote_client_time(); .float items_allowed; .float armor_allowed; .float maxarmor; -.float maxfbspeed; // Maximum forward/back speed -.float maxstrafespeed; // Maximum side speed +.float csqc_maxspeed; .float is_disarming; .float motd; // Used to display MOTD diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f83be9db..685844a4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1245,9 +1245,9 @@ float (float pc) IsLegalClass = { }; void (entity p) TeamFortress_SetSpeed = { - local string sp; - local float tf; - local entity te; + string sp; + float tf; + entity te; stuffcmd(p, "cl_movespeedkey 1\n"); if (p.tfstate & TFSTATE_CANT_MOVE) { @@ -1268,84 +1268,47 @@ void (entity p) TeamFortress_SetSpeed = { stuffcmd(p, "m_side 0.8\n"); } #endif - if (p.playerclass == PC_SCOUT) { - p.maxfbspeed = PC_SCOUT_MAXSPEED; - p.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED; - } else if (p.playerclass == PC_SNIPER) { - p.maxfbspeed = PC_SNIPER_MAXSPEED; - p.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED; - } else if (p.playerclass == PC_SOLDIER) { - p.maxfbspeed = PC_SOLDIER_MAXSPEED; - p.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED; - } else if (p.playerclass == PC_DEMOMAN) { - p.maxfbspeed = PC_DEMOMAN_MAXSPEED; - p.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED; - } else if (p.playerclass == PC_MEDIC) { - if (medic_type == MEDIC_TYPE_BLAST) { - p.maxfbspeed = PC_BLASTMEDIC_MAXSPEED; - p.maxstrafespeed = PC_BLASTMEDIC_MAXSTRAFESPEED; - } else { - p.maxfbspeed = PC_MEDIC_MAXSPEED; - p.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED; - } - } else if (p.playerclass == PC_HVYWEAP) { - p.maxfbspeed = PC_HVYWEAP_MAXSPEED; - p.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED; - } else if (p.playerclass == PC_PYRO) { - p.maxfbspeed = PC_PYRO_MAXSPEED; - p.maxstrafespeed = PC_PYRO_MAXSTRAFESPEED; - } else if (p.playerclass == PC_CIVILIAN || votemode) { - p.maxfbspeed = PC_CIVILIAN_MAXSPEED; - p.maxstrafespeed = PC_CIVILIAN_MAXSTRAFESPEED; - } else if (p.playerclass == PC_SPY) { - p.maxfbspeed = PC_SPY_MAXSPEED; - p.maxstrafespeed = PC_SPY_MAXSTRAFESPEED; - } else if (p.playerclass == PC_ENGINEER) { - p.maxfbspeed = PC_ENGINEER_MAXSPEED; - p.maxstrafespeed = PC_ENGINEER_MAXSTRAFESPEED; - } else if (p.playerclass == PC_UNDEFINED) { - // p.maxfbspeed = 320; - // p.maxstrafespeed = 320; - p.maxfbspeed = 0; - p.maxstrafespeed = 0; - p.maxspeed = 0; - return; - } + float new_max = Class_MaxSpeed(p.playerclass); + tf = 0; te = find(world, classname, "item_tfgoal"); while ((te != world) && (tf == 0)) { if (te.owner == p) { if (te.goal_activation & TFGI_SLOW) { tf = 1; - p.maxfbspeed = p.maxfbspeed / 2; - p.maxstrafespeed = p.maxstrafespeed / 2; + new_max /= 2; } } te = find(te, classname, "item_tfgoal"); } - if (p.tfstate & TFSTATE_TRANQUILISED) { - p.maxfbspeed = p.maxfbspeed / 2; - p.maxstrafespeed = p.maxstrafespeed / 2; - } - if (p.leg_damage) { - if (p.leg_damage > 6) { - p.leg_damage = 6; - } - p.maxfbspeed = p.maxfbspeed * (10 - p.leg_damage) / 10; - p.maxstrafespeed = p.maxstrafespeed * (10 - p.leg_damage) / 10; - } - if (p.tfstate & TFSTATE_AIMING) { - if (p.maxfbspeed > 80) { - p.maxfbspeed = 80; - } - if (p.maxstrafespeed > 80) { - p.maxstrafespeed = 80; - } + + if (p.tfstate & TFSTATE_TRANQUILISED) + new_max /= 2; + + if (p.leg_damage) + new_max *= (10 - min(p.leg_damage, 6)) / 10; + + float client_enable = ClientPred_Enabled(p, CSQC_SETSPEED); + + // When the client is co-operating (and enabled), allow it to handle + // TFSTATE_AIMING transitions due to the frequent edges here and negative + // maxspeed/pmove interaction (bounds client prediction until maxspeed makes + // it to client, even though released on unpredicted earlier frame, leading + // to lots of skipping). + if (!RewindFlagEnabled(REWIND_SETSPEED) || !client_enable) + if (p.tfstate & TFSTATE_AIMING) + new_max = min(new_max, 80); + + if (!client_enable) { + // It's possible to set the client-enable without REWIND_SETSPEED, + // they'll just skip more. + sp = ftos(new_max); + stuffcmd(p, "cl_backspeed ", sp, "; cl_forwardspeed ", sp, + "; cl_sidespeed ", sp, "\n"); } - sp = ftos(p.maxfbspeed); - stuffcmd(p, "cl_backspeed ", sp, "; cl_forwardspeed ", sp, - "; cl_sidespeed ", sp, "\n"); - p.maxspeed = p.maxfbspeed; + + p.maxspeed = new_max; + p.csqc_maxspeed = new_max; // Always set, need populated on transition. }; void () TeamFortress_SetHealth = { @@ -2941,7 +2904,7 @@ void () TeamFortress_CheckforCheats = { vf_z = 0; vf = normalize(vf); tf = vplf_x * vf_x + vplf_y * vf_y; - pf = self.owner.maxfbspeed + 100; + pf = self.owner.maxspeed + 100; if ((self.owner.tfstate & TFSTATE_CANT_MOVE) && (tf > 20)) { self.nextthink = time + 0.5; From 56858dfc1076c62481af478869cbdc66edcd53ed Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 11 Dec 2022 16:01:07 -0800 Subject: [PATCH 1942/2474] Client-side sniper rifle - Client side dot - Client-side movement transitions on aiming/!aiming - Client side sbar damage side calculation - Some implfication of damage_full/etc --- csqc/csextradefs.qc | 3 +- csqc/events.qc | 1 - csqc/hud.qc | 8 +-- csqc/pmove.qc | 3 -- csqc/weapon_predict.qc | 117 +++++++++++++++++++++++++++++++++++------ share/defs.h | 2 + share/prediction.qc | 4 +- share/weapons.qc | 2 +- ssqc/client.qc | 4 +- ssqc/qw.qc | 1 - ssqc/sniper.qc | 9 ++++ ssqc/status.qc | 14 ++--- ssqc/tfort.qc | 1 + ssqc/weapons.qc | 11 ++-- 14 files changed, 131 insertions(+), 49 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 2bd8dd45..6a3f5835 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -43,7 +43,7 @@ vector TEXT_TEAM_COLOUR[] = { const float DEFAULT_VIEWHEIGHT = 22; const vector PLAYER_MINS = [-16, -16, -24]; -const vector PLAYER_MAXS = [16, 16, 24]; +const vector PLAYER_MAXS = [16, 16, 32]; #define FO_MENU_FLAG_USE_MOUSE 1 #define FO_MENU_FLAG_CENTER 2 @@ -290,7 +290,6 @@ typedef struct { float ScannerTFItemsFlags; // sniper float SniperDam; - float SniperMax; // demoman float IsDetpacking; float DetpackLeft; diff --git a/csqc/events.qc b/csqc/events.qc index 428f24b4..21ca8ad6 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -430,7 +430,6 @@ void ParseSBAR() break; case PC_SNIPER: SBAR.SniperDam = readfloat(); - SBAR.SniperMax = readfloat(); break; case PC_DEMOMAN: SBAR.IsDetpacking = readfloat(); diff --git a/csqc/hud.qc b/csqc/hud.qc index 6a53575e..e411785c 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -828,16 +828,16 @@ void Hud_DrawClassInfoPanel(float playerclass) } break; case PC_SNIPER: - if (SBAR.SniperDam) + float sniper_dam = WP_SniperCharge(); + if (sniper_dam) { icon = ICON_SNIPER; //HudIcons[playerclass+6].icon; HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = strcat("Dam: ", ftos(SBAR.SniperDam)); + msg = strcat("Dam: ", ftos(sniper_dam)); pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - if (SBAR.SniperMax) - { + if (sniper_dam == PC_SNIPER_MAXDAM) { msg = "(100%)"; colour = '1 0 0'; HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); diff --git a/csqc/pmove.qc b/csqc/pmove.qc index fb593869..f0de8c47 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -1,8 +1,5 @@ DEFCVAR_FLOAT(fo_jumpvolume, 1); -const vector PLAYER_MINS = [-16, -16, -24]; -const vector PLAYER_MAXS = [16, 16, 32]; - inline float CSQC_JumpSounds_Active() { return CVARF(fo_csjumpsounds); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 45a6440a..8ad03ea2 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,13 +1,14 @@ DEFCVAR_FLOAT(wpp_debug, 0); DEFCVAR_FLOAT(fo_wpp_beta, 0); +DEFCVAR_FLOAT(fo_client_sniper_sight, 1); + DEFCVAR_FLOAT(wpp_min_ping, -1); DEFCVAR_FLOAT(wpp_weap_predict, -1); DEFCVAR_FLOAT(wpp_proj_predict, -1); DEFCVAR_FLOAT(wpp_phys_adv_ms, 0); DEFCVAR_FLOAT(wpp_phys_local_adv_ms, 0); - DEFCVAR_FLOAT(wpp_setspeed, 1); struct pengine_t { @@ -39,6 +40,18 @@ float WP_MinPing() { void WP_UpdateViewModel(); +inline float interp_ms() { + return (pstate_pred.seq - pstate_server.seq) * SERVER_FRAME_MS; +} + +inline float interp_dt() { + return interp_ms() / 1000.0; +} + +inline float interp_time() { + return time + interp_dt(); +} + #define csqc_print(...) \ do { if (CVARF(wpp_debug) & 4) { \ print("CSQC: ", __VA_ARGS__); \ @@ -264,7 +277,6 @@ void WPP_UpdateEnable(float force) { } once = TRUE; - float wpp_status = 0; if (pengine.wp_enabled) { wpp_status |= CSQC_WEAP_PRED; @@ -272,6 +284,8 @@ void WPP_UpdateEnable(float force) { wpp_status |= CSQC_PROJ_PRED; if (CVARF(wpp_setspeed)) wpp_status |= CSQC_SETSPEED; + if (CVARF(fo_client_sniper_sight)) + wpp_status |= CSQC_SNIPER_SIGHT; } setlocaluserinfo(0, "fo_wpp_status", ftos(wpp_status)); @@ -540,6 +554,75 @@ static void WP_HandleHeavyInputs() { pstate_pred.impulse = 0; } +struct { + float start_seq; + entity sight; + float sight_modelindex; +} SniperState; + +static void WP_InitSniper() { + entity sight = spawn(); + sight.solid = SOLID_NOT; + sight.drawmask = 0; + float index = getmodelindex("progs/sight.spr"); + setmodelindex(sight, index); + + SniperState.sight = sight; +} + +float WP_SniperCharge() { + if (!WP_Enabled()) + return SBAR.SniperDam; + + if (!SniperState.start_seq) + return 0; + + float heat = 50 + (pstate_pred.seq - SniperState.start_seq) * 3; + return min(PC_SNIPER_MAXDAM, heat); +} + +static void WP_Sniper_UpdateSight() { + if (pstate_pred.playerclass != PC_SNIPER || !CVARF(fo_client_sniper_sight) || + (pstate_pred.tfstate & TFSTATE_AIMING == 0)) { + SniperState.sight.drawmask = 0; + return; + } + + SniperState.sight.drawmask = MASK_ENGINE; + vector org = pmove_org + v_forward * 10; + org.z += PLAYER_MINS.z - 1 + (PLAYER_MAXS.z - PLAYER_MINS.z) * 0.7; + traceline(org, org + v_forward * 9192, MOVE_NORMAL, 0); + setorigin(SniperState.sight, trace_endpos); +} + +static float WP_Sniper_IsAttack() { + float aiming = pstate_pred.tfstate & TFSTATE_AIMING; + + // Just box these out up front + if (pstate_pred.client_time < pstate_pred.attack_finished || + !WP_GetAmmo(AMMO_SHELLS)) + return FALSE; + + if (pstate_pred.buttons_held & BUTTON0) { + // Start charging when possible/necessary. + if (!aiming && pmove_onground && vlen(pmove_vel) <= 50) { + pstate_pred.tfstate |= TFSTATE_AIMING; + SniperState.start_seq = pstate_pred.seq; + } + return FALSE; + } else if (pstate_pred.buttons_up & BUTTON0) { + pstate_pred.tfstate &= ~TFSTATE_AIMING; + SniperState.start_seq = 0; + + if (aiming && pmove_onground && IsEffectFrame()) + printf("C attack at it=%0.3f t=%0.3f\n", interp_time(), time); + // Can fire iff already aiming and on ground + return (aiming && pmove_onground); + } else { + return FALSE; + } +} + void W_ThrowGren(float is_throw); static void HandleButtonThrowgren(float index, float button) { @@ -558,7 +641,6 @@ static void HandleButtonThrowgren(float index, float button) { float WP_ReloadSlot(Slot slot); void WP_ReloadNext(); -float interp_time(); void WP_Impulse() { WP_HandleHeavyInputs(); @@ -783,6 +865,7 @@ void WP_AnimateModel() { case WEAP_RAILGUN: case WEAP_SHOTGUN: case WEAP_SUPER_SHOTGUN: + case WEAP_SNIPER_RIFLE: player_shotN(); break; case WEAP_FLAMETHROWER: @@ -892,10 +975,19 @@ void WP_Frame() { WP_Impulse(); W_ThrowGren(FALSE); - if ((input_buttons & BUTTON0) && !WP_IsReloading() && - (pstate_pred.client_time >= pstate_pred.attack_finished)) + float is_attack = 0; + + if (pstate_pred.playerclass != PC_SNIPER) + is_attack = ((input_buttons & BUTTON0) && + (pstate_pred.client_time >= pstate_pred.attack_finished) && + !WP_IsReloading()); + else + is_attack = WP_Sniper_IsAttack(); + + if (is_attack) WP_Attack(); + WP_Sniper_UpdateSight(); MP_SetSpeed(); } @@ -929,18 +1021,6 @@ trail_table_entry trail_table[] = { {{"TE_RAILTRAIL"}}, }; -inline float interp_ms() { - return (pstate_pred.seq - pstate_server.seq) * SERVER_FRAME_MS; -} - -inline float interp_dt() { - return interp_ms() / 1000.0; -} - -inline float interp_time() { - return time + interp_dt(); -} - float get_phys_time_nudge_dt(entity e) { if (!is_player) return 0; @@ -1326,6 +1406,7 @@ void WP_Attack() { case WEAP_SHOTGUN: Pred_Sound(SND_SG); break; case WEAP_SUPER_SHOTGUN: Pred_Sound(SND_SSG); break; + case WEAP_SNIPER_RIFLE: Pred_Sound(SND_SNIPER_RIFLE); break; } } @@ -1535,6 +1616,8 @@ float WP_ClientThink() { } void InitWeapPredEnt(entity pe) { + WP_InitSniper(); + pe.predraw = WP_ClientThink; pengine.pweap_ent = pe; pe.drawmask = MASK_PRED_ENT; diff --git a/share/defs.h b/share/defs.h index 84a8775a..4adaf9f2 100644 --- a/share/defs.h +++ b/share/defs.h @@ -941,6 +941,8 @@ enumflags { #define PC_SNIPER_GRENADE_MAX_2 4 #define PC_SNIPER_TF_ITEMS 0 +#define PC_SNIPER_MAXDAM 401 + // Class Details for SOLDIER #define PC_SOLDIER_SKIN 6 #define PC_SOLDIER_MAXHEALTH 100 diff --git a/share/prediction.qc b/share/prediction.qc index 9de1db5c..7ac474fb 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -40,6 +40,7 @@ enumflags { CSQC_WEAP_PRED, CSQC_PROJ_PRED, CSQC_SETSPEED, + CSQC_SNIPER_SIGHT, }; struct predict_tf_state { @@ -88,6 +89,7 @@ enum SoundIndex:float { SND_FLAMETHROWER, SND_RAILGUN, SND_TRANQ, + SND_SNIPER_RIFLE, SND_ASSCAN_UP, SND_ASSCAN_FIRE, SND_ASSCAN_DOWN, @@ -111,6 +113,7 @@ static fo_predsnd snd_types[] = { { SND_FLAMETHROWER, "flmfire2.wav" }, { SND_RAILGUN, "railgun.wav" }, { SND_TRANQ, "dartgun.wav" }, + { SND_SNIPER_RIFLE, "sniper.wav" }, { SND_ASSCAN_UP, "asscan1.wav" }, { SND_ASSCAN_FIRE, "asscan2.wav" }, { SND_ASSCAN_DOWN, "asscan3.wav" }, @@ -278,7 +281,6 @@ float FO_MaxRewindGrenWinDt() { inline float ClientPred_Enabled(entity client, float pred_flag) { return infokeyf(client, "fo_wpp_status") & pred_flag; } - #else predict_tf_state pstate_pred, pstate_server; diff --git a/share/weapons.qc b/share/weapons.qc index 5918fb6f..725d9992 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -109,7 +109,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_MEDIKIT, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, { WEAP_SPANNER, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, { WEAP_AXE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, - { WEAP_SNIPER_RIFLE, NO_PREDICT, AMMO_SHELLS, -9, 1, 1.5, 4 }, + { WEAP_SNIPER_RIFLE, PRED_MODEL, AMMO_SHELLS, -9, 1, 1.5, 4 }, { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0 }, { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, diff --git a/ssqc/client.qc b/ssqc/client.qc index ed63de34..27f96299 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -545,8 +545,8 @@ void () DecodeLevelParms = { // allow scout dash [on] scoutdash = CF_GetSetting("sd", "scoutdash", "on"); - // enable sniper rifle reload [on] - sniperreload = CF_GetSetting("sr", "sniperreload", "on"); + // enable sniper rifle reload [off] + sniperreload = CF_GetSetting("sr", "sniperreload", "off"); // spawn with full ammo/armor [off] spawnfull = CF_GetSetting("sf", "spawnfull", "off"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 0f2c876e..ef09dce4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -102,7 +102,6 @@ float remote_client_time(); .float dash_cooldown; // Cooldown for Scout dash .float undercover_timer; // Seconds left until disguised .float power_time; // The time when sniper power in status bar was last updated -.float power_full; // Whether sniper power has reached full power or not .float sentry_ticks; // Used to indicate when engineer's sentry gun is finished building .float dispenser_ticks; // Used to indicate when engineer's dispenser is finished building .float building_percentage; // The building percentage shown in status bar diff --git a/ssqc/sniper.qc b/ssqc/sniper.qc index 1c35db55..7c686afe 100644 --- a/ssqc/sniper.qc +++ b/ssqc/sniper.qc @@ -142,6 +142,13 @@ void () SniperSight_Update = { self.nextthink = time + 0.1; }; +static float sight_send_filter() { + if (other == self.owner) + return FALSE; + + return TRUE; +} + void () SniperSight_Create = { local entity sight; @@ -163,4 +170,6 @@ void () SniperSight_Create = { sight.think = SniperSight_Update; sight.nextthink = time + 0.05; + if (ClientPred_Enabled(self, CSQC_SNIPER_SIGHT)) + sight.customizeentityforclient = sight_send_filter; }; diff --git a/ssqc/status.qc b/ssqc/status.qc index 3e6b60f1..69141d9c 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -874,17 +874,12 @@ void UpdateClientStatusBar(entity pl) } break; case PC_SNIPER: - float dam, max; + float dam; dam = 0; - max = FALSE; if (sniperpower) - { dam = pl.heat; - max = pl.power_full; - } - + WriteFloat(MSG_MULTICAST, dam); - WriteFloat(MSG_MULTICAST, max); break; case PC_DEMOMAN: WriteFloat(MSG_MULTICAST, pl.is_detpacking); @@ -988,7 +983,7 @@ void UpdateClientStatusBar(entity pl) { WriteFloat(MSG_MULTICAST, disp.health); } - disp = find(disp, classname, "building_dispenser"); + disp = find(disp, classname, "building_d0; //ispenser"); } } break; @@ -1404,9 +1399,8 @@ string(entity pl) SniperPowerToString = st = Q"\spower\s: "; st = strcat(st, ftos(pl.heat)); st = strcat(st, " dmg"); - if (pl.power_full) { + if (pl.heat == PC_SNIPER_MAXDAM) st = strcat(st, " (max)"); - } } return st; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 685844a4..b66391c0 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1249,6 +1249,7 @@ void (entity p) TeamFortress_SetSpeed = { float tf; entity te; + float oldmax = self.maxspeed; stuffcmd(p, "cl_movespeedkey 1\n"); if (p.tfstate & TFSTATE_CANT_MOVE) { #ifdef STOP_MOUSE_MOVEMENT diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d28cb03f..ba051b4b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -843,7 +843,7 @@ void () W_FireSniperRifle = { local vector h; dir = '0 0 0'; - FO_Sound(self, CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM); + Pred_Sound(SND_SNIPER_RIFLE); KickPlayer(-2, self); self.ammo_shells = self.ammo_shells - 1; @@ -2698,15 +2698,12 @@ void () W_WeaponFrame = { if (self.button0) { if (FO_CurrentWeapon() == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { - if (self.heat < 400) { - self.heat = self.heat + 3; + if (self.heat < PC_SNIPER_MAXDAM) { + self.heat = max(self.heat + 3, PC_SNIPER_MAXDAM); if ((sniperpower) && (self.power_time < (time - 0.3))) { self.power_time = time; Status_Refresh(self); } - } else if ((sniperpower) && (!self.power_full)) { - self.power_full = 1; - Status_Refresh(self); } } else { local vector tv = self.velocity; @@ -2715,7 +2712,6 @@ void () W_WeaponFrame = { SniperSight_Create(); self.heat = 50; self.tfstate |= TFSTATE_AIMING; - self.power_full = 0; } } } else if (FO_CurrentWeapon() == WEAP_ASSAULT_CANNON) { @@ -2734,6 +2730,7 @@ void () W_WeaponFrame = { W_Attack(); self.tfstate &= ~TFSTATE_AIMING; self.heat = 0; + printf("S attack at %0.3f\n", time); } }; From 797face848ffd9463c1e6400924b736ff9ef3fcb Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 13 Dec 2022 00:50:47 -0800 Subject: [PATCH 1943/2474] Fix lint that escaped --- csqc/weapon_predict.qc | 3 --- ssqc/status.qc | 2 +- ssqc/tfort.qc | 1 - ssqc/weapons.qc | 1 - 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 8ad03ea2..4ef4287a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -613,9 +613,6 @@ static float WP_Sniper_IsAttack() { } else if (pstate_pred.buttons_up & BUTTON0) { pstate_pred.tfstate &= ~TFSTATE_AIMING; SniperState.start_seq = 0; - - if (aiming && pmove_onground && IsEffectFrame()) - printf("C attack at it=%0.3f t=%0.3f\n", interp_time(), time); // Can fire iff already aiming and on ground return (aiming && pmove_onground); } else { diff --git a/ssqc/status.qc b/ssqc/status.qc index 69141d9c..f692dd08 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -983,7 +983,7 @@ void UpdateClientStatusBar(entity pl) { WriteFloat(MSG_MULTICAST, disp.health); } - disp = find(disp, classname, "building_d0; //ispenser"); + disp = find(disp, classname, "building_dispenser"); } } break; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b66391c0..685844a4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1249,7 +1249,6 @@ void (entity p) TeamFortress_SetSpeed = { float tf; entity te; - float oldmax = self.maxspeed; stuffcmd(p, "cl_movespeedkey 1\n"); if (p.tfstate & TFSTATE_CANT_MOVE) { #ifdef STOP_MOUSE_MOVEMENT diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index ba051b4b..bb25bb3d 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2730,7 +2730,6 @@ void () W_WeaponFrame = { W_Attack(); self.tfstate &= ~TFSTATE_AIMING; self.heat = 0; - printf("S attack at %0.3f\n", time); } }; From 04ecbeda5e27dde38bdbf86f5c2bc998271bb2a2 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 13 Dec 2022 18:40:58 -0800 Subject: [PATCH 1944/2474] Add more convenient flags field format Our new options support several bitmasks for controlling behavior. This adds a simpler syntax for specifying them rather than computing the OR manually. Now, either `val` or `val1,val2,val3,...` can be specified. In the latter case, they will be OR'd together. E.g. `rcon localinfo rewind 1,2,4` or `rcon localinfo rewind 7` are now equivalent. --- share/commondefs.qc | 10 +++---- share/prediction.qc | 68 +++++++++++++++++++++++++++------------------ ssqc/client.qc | 21 ++++++++++---- 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 76595458..e53afc7b 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -50,21 +50,21 @@ var struct { } fo_config; enumflags { - REWIND_KNOCKBACK, REWIND_PROJ_HIT, + REWIND_KNOCKBACK, + REWIND_SETSPEED, REWIND_GRENADES, - REWIND_FORWARD_DOORS, REWIND_FORWARD_PROJ_SELFKNOCK, - REWIND_SETSPEED, + REWIND_FORWARD_DOORS, }; string REWIND_DESC[] = { - "rewind pipe knockback", "rewind projectile hit", + "rewind pipe knockback", + "allow csqc to handle maxspeed" "rewind grenade throws", "forward projectile self-knockback", "open doors earlier for hpbs [requires rfd=1]", - "allow csqc to handle maxspeed" }; const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_HIT | diff --git a/share/prediction.qc b/share/prediction.qc index 7ac474fb..4e3a4ae5 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -73,7 +73,8 @@ struct predict_tf_state { #endif }; -float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +string CF_GetSettingRaw(string ps_short, string ps_setting, string ps_default); +float CF_GetSetting(string ps_short, string ps_setting, string ps_default); enum SoundIndex:float { SND_NONE = 0, @@ -588,12 +589,16 @@ void Predict_InitDefaultConfig() { entity config_entity; -#define CONFIG_UPDATE(_ps_short, _field) \ +#define CONFIG_UPDATE(_flag, _ps_short, _field) \ do { string _cur = ftos(fo_config.##_field); \ - float _val = CF_GetSetting(_ps_short, #_field, _cur); \ - if (_val != fo_config.##_field) { \ - fo_config.##_field = _val; update = TRUE; \ - } \ + float _val; \ + if (_flag) \ + _val = ParseFlags(CF_GetSettingRaw(_ps_short, #_field, _cur)); \ + else \ + _val = CF_GetSetting(_ps_short, #_field, _cur); \ + if (_val != fo_config.##_field) { \ + fo_config.##_field = _val; update = TRUE; \ + } \ } while (0) #define CLAMP_UPDATE(_field, _clamp_low, _clamp_high) \ do { if (fo_config.##_field < _clamp_low || fo_config.##_field > _clamp_high) { \ @@ -613,31 +618,40 @@ float ForwardDoorsPossible() { return possible; } +// Equivalent to stof(str) when not splittable (e.g. single OR'd val). +static float ParseFlags(string str) { + float n = tokenize(str); + float result = 0; + for (int i = 0; i < n; i++) + result |= stof(argv(i)); + return result; +} + static void WeaponPred_CheckConfigUpdate() { float update = FALSE; // Target is also the long form localinfo name. - CONFIG_UPDATE("qcp", qc_physics); - CONFIG_UPDATE("mpm", min_ping_ms); - CONFIG_UPDATE("snm", static_newmis_ms); - CONFIG_UPDATE("dnm", dynamic_newmis_ms); - CONFIG_UPDATE("mrt", max_rewind_ms); - CONFIG_UPDATE("mrsp", max_rewind_slow_projectile_ms); - CONFIG_UPDATE("mrfp", max_rewind_fast_projectile_ms); - CONFIG_UPDATE("mrg", max_rewind_grenade_ms); - CONFIG_UPDATE("rfpt", rewind_fast_projectile_thresh); - CONFIG_UPDATE("wpdmp", wp_default_min_ping_ms); - CONFIG_UPDATE("wpge", wp_global_enable); - CONFIG_UPDATE("wpgd", wp_global_disable); - CONFIG_UPDATE("ppge", pp_global_enable); - CONFIG_UPDATE("ppgd", pp_global_disable); - CONFIG_UPDATE("wppge", wpp_global_enable); - CONFIG_UPDATE("wppge", wpp_global_disable); - CONFIG_UPDATE("gbd", gren_beta_disable); - CONFIG_UPDATE("rewind", rewind_flags); - CONFIG_UPDATE("tfx", tfx_flags); - CONFIG_UPDATE("clown", clown_flags); - CONFIG_UPDATE("clown_grav", clown_grav); + CONFIG_UPDATE(FALSE, "qcp", qc_physics); + CONFIG_UPDATE(FALSE, "mpm", min_ping_ms); + CONFIG_UPDATE(FALSE, "snm", static_newmis_ms); + CONFIG_UPDATE(FALSE, "dnm", dynamic_newmis_ms); + CONFIG_UPDATE(FALSE, "mrt", max_rewind_ms); + CONFIG_UPDATE(FALSE, "mrsp", max_rewind_slow_projectile_ms); + CONFIG_UPDATE(FALSE, "mrfp", max_rewind_fast_projectile_ms); + CONFIG_UPDATE(FALSE, "mrg", max_rewind_grenade_ms); + CONFIG_UPDATE(FALSE, "rfpt", rewind_fast_projectile_thresh); + CONFIG_UPDATE(FALSE, "wpdmp", wp_default_min_ping_ms); + CONFIG_UPDATE(FALSE, "wpge", wp_global_enable); + CONFIG_UPDATE(FALSE, "wpgd", wp_global_disable); + CONFIG_UPDATE(FALSE, "ppge", pp_global_enable); + CONFIG_UPDATE(FALSE, "ppgd", pp_global_disable); + CONFIG_UPDATE(FALSE, "wppge", wpp_global_enable); + CONFIG_UPDATE(FALSE, "wppge", wpp_global_disable); + CONFIG_UPDATE(FALSE, "gbd", gren_beta_disable); + CONFIG_UPDATE(TRUE, "rewind", rewind_flags); + CONFIG_UPDATE(TRUE, "tfx", tfx_flags); + CONFIG_UPDATE(TRUE, "clown", clown_flags); + CONFIG_UPDATE(FALSE, "clown_grav", clown_grav); CLAMP_UPDATE(dynamic_newmis_ms, 0, fo_config.static_newmis_ms); CLAMP_UPDATE(max_rewind_ms, 0, 250); diff --git a/ssqc/client.qc b/ssqc/client.qc index 27f96299..1cfb611c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -173,17 +173,23 @@ string (entity ent, string ps_short, string ps_setting, string ps_default) FO_Ge return st; }; -//if ent is world, return serverinfo, if ent is a player, return that client's setinfo key -float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting = { - local string st; - st = infokey(ent, ps_short); +string FO_GetUserSettingRaw(entity ent, string ps_short, string ps_setting, + string ps_default) { + string st = infokey(ent, ps_short); if (st == string_null) { st = infokey(ent, ps_setting); if (st == string_null) { st = ps_default; } } + return st; +} + +//if ent is world, return serverinfo, if ent is a player, return that client's setinfo key +float FO_GetUserSetting(entity ent, string ps_short, string ps_setting, + string ps_default) { + string st = FO_GetUserSettingRaw(ent, ps_short, ps_setting, ps_default); switch (st) { @@ -196,7 +202,12 @@ float (entity ent, string ps_short, string ps_setting, string ps_default) FO_Get } }; -float (string ps_short, string ps_setting, string ps_default) CF_GetSetting = { +string CF_GetSettingRaw(string ps_short, string ps_setting, + string ps_default) { + return FO_GetUserSettingRaw(world, ps_short, ps_setting, ps_default); +}; + +float CF_GetSetting(string ps_short, string ps_setting, string ps_default) { return FO_GetUserSetting(world, ps_short, ps_setting, ps_default); }; From be7e191980c658e7cce60c64e47efe1898d454d5 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 13 Dec 2022 22:53:34 -0800 Subject: [PATCH 1945/2474] Prune pyro_types The pyro code is overcomplicated due to the support of multiple legacy types and some alternate features that didn't make it. It's also resulted in a nasty bug for pyro rockets where directs do less damage than splash. Before we make any balance changes, first clean up everything. There is now only the fone-pyro, with no speciation. --- README.md | 1 - share/defs.h | 22 +--- share/weapons.qc | 12 +- ssqc/client.qc | 23 ---- ssqc/combat.qc | 12 +- ssqc/pyro.qc | 286 ++++++----------------------------------------- ssqc/qw.qc | 8 -- ssqc/weapons.qc | 2 - 8 files changed, 43 insertions(+), 323 deletions(-) diff --git a/README.md b/README.md index 8ad78ce9..02b1cad0 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,6 @@ New features * Allow team changing. * Any non-valid impulse now closes the active menu. * Option to allow a demoman to place a detpack while reloading his weapon `localinfo detreload on` -* Pyro types - `localinfo pyro_type val` - 0 = original tf2.9, 1 = oztf pyro style, 2 = FO pyro style * localinfo server_sbflaginfo : 0 - disables sbar flaginfo, 1 enables it [default: 1] * localinfo reverse_cap : 0 - normal gameplay, 1: you have to take your flag and capture in the enemy base [default: 0] * localinfo engineer_move / em : 0 - normal gameplay, 1: engineers can move while building [default: 1] diff --git a/share/defs.h b/share/defs.h index 4adaf9f2..053a278e 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1097,24 +1097,12 @@ enumflags { #define PC_PYRO_AIRBLASTJUMP_CELLS 75 #define PC_PYRO_LAVA_LIFETIME 3 #define PC_PYRO_LAVA_RETICK 1.2 -#define PC_PYRO_FLAMETHROWER_DAM_FO 15 -#define PC_PYRO_FLAMETHROWER_DAM_ORIG 10 -#define PC_PYRO_NAPALM_INIT_DAM_ORIG 20 -#define PC_PYRO_NAPALM_INIT_DAM_FO 40 -#define PC_PYRO_NAPALM_MAX_EXPLOSIONS_ORIG 8 -#define PC_PYRO_NAPALM_MAX_EXPLOSIONS_FO 4 -#define PC_PYRO_INIT_BURN_DAM_ORIG 6 -#define PC_PYRO_INIT_BURN_DAM_FO 12 -#define PC_PYRO_BURN_MULTIPLIER_ORIG .3 -#define PC_PYRO_BURN_MULTIPLIER_FO 1 +#define PC_PYRO_FLAMETHROWER_DAM 15 +#define PC_PYRO_NAPALM_INIT_DAM 40 +#define PC_PYRO_NAPALM_MAX_EXPLOSIONS 4 +#define PC_PYRO_INIT_BURN_DAM 12 +#define PC_PYRO_BURN_MULTIPLIER 1 #define PC_PYRO_BURN_DAMAGE_AMP 1.2 -#define PC_PYRO_OLD_PROJSPEED 600 -#define PC_PYRO_NEW_PROJSPEED 800 - -// pyro types -#define PYRO_ORIGINAL 0 -#define PYRO_OZTF 1 -#define PYRO_FO 2 // Class Details for SPY #define PC_SPY_SKIN 22 diff --git a/share/weapons.qc b/share/weapons.qc index 725d9992..7d4d2890 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -13,7 +13,6 @@ .float ammo_cells; float sniperreload = FALSE; -float pyro_type = PYRO_FO; #endif // Some preprocessor bug is making __LINE__ not substitute right here most of @@ -119,7 +118,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_PIPE_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0 }, { WEAP_ROCKET_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 4, 1, 0.8, 5 }, - { WEAP_INCENDIARY, PRED_PROJ, AMMO_ROCKETS, 0, 3, -9, 0 }, + { WEAP_INCENDIARY, PRED_PROJ, AMMO_ROCKETS, 0, 3, 0.9, 0 }, { WEAP_ASSAULT_CANNON, PRED_PROJ, AMMO_SHELLS, 100, 1, 0.2, 4 }, { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, @@ -772,15 +771,6 @@ void FO_Weapons_Init() { FO_WeapInfo* WI_sr = FO_GetWeapInfo(WEAP_SNIPER_RIFLE); WI_sr->clip_size = sniperreload ? 1 : 0; - FO_WeapInfo* WI_ir = FO_GetWeapInfo(WEAP_INCENDIARY); - switch (pyro_type) { - case PYRO_ORIGINAL: WI_ir->attack_time = 1.2; break; - case PYRO_OZTF: - case PYRO_FO: - default: - WI_ir->attack_time = 0.9; break; - } - for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; ASSERTD_EQ(WEAP_to_index(wi->weapon), i); diff --git a/ssqc/client.qc b/ssqc/client.qc index 1cfb611c..5ee60985 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -538,15 +538,6 @@ void () DecodeLevelParms = { asscanrange = CF_GetSetting("acr", "asscanrange", "0"); asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); - // Pyro Airblast pushval min and max - airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); - airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "470"); - airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "600"); - airblastjump = CF_GetSetting("abj", "airblastjump", "off"); - airblastsize = CF_GetSetting("abs", "airblastsize", "150"); - airblastcells = CF_GetSetting("abc", "airblastcells", ftos(PC_PYRO_AIRBLAST_CELLS)); - airblastjumpcells = CF_GetSetting("abjc", "airblastjumpcells", ftos(PC_PYRO_AIRBLASTJUMP_CELLS)); - // force reload [on] force_reload = CF_GetSetting("fr", "forcereload", "on"); @@ -605,11 +596,6 @@ void () DecodeLevelParms = { asscanrange = CF_GetSetting("acr", "asscanrange", "0"); asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); - // Pyro Airblast pushval min and max - airblastv2 = CF_GetSetting("abv2", "airblastv2", "off"); - airblastpushmin = CF_GetSetting("abpmin", "airblastpushmin", "500"); - airblastpushmax = CF_GetSetting("abpmax", "airblastpushmax", "800"); - // remote_client_time max delta antilag_settings.rewind_detpipe = CF_GetSetting("alrd", "al_rewind_detpipe", "on"); @@ -665,9 +651,6 @@ void () DecodeLevelParms = { // whitelists detpack impulses on the list of commands that you're allowed to use while reloading [off] detpack_when_reloading = CF_GetSetting("detreload", "detpack_while_reloading", "off"); - // pyro class type - 0:default; 1:OzTF like; 2:plasmaclass - pyro_type = CF_GetSetting("pyrotype", "pyro_type", "2"); - // ceasefire type - 0: default; 1: pause ceasefire_type = CF_GetSetting("ceasefiretype", "cft", "1"); @@ -876,7 +859,6 @@ void () DecodeLevelParms = { superspanner = FALSE; superknife = TRUE; superknife_multihit = FALSE; - pyro_type = PYRO_OZTF; Role_None.gren1_limits[1] = PC_SCOUT_GRENADE_MAX_1; Role_None.gren1_limits[2] = PC_SNIPER_GRENADE_MAX_1; Role_None.gren1_limits[3] = PC_SOLDIER_GRENADE_MAX_1; @@ -899,9 +881,6 @@ void () DecodeLevelParms = { walls_block_emp = FALSE; solid_nailgren = FALSE; scoutscanspike = TRUE; - airblastpushmin = 470; - airblastpushmax = 600; - airblastsize = 150; } st = infokey(world, "faithful"); @@ -952,7 +931,6 @@ void () DecodeLevelParms = { superspanner = FALSE; superknife = FALSE; superknife_multihit = FALSE; - pyro_type = PYRO_ORIGINAL; Role_None.gren1_limits[1] = 4; Role_None.gren1_limits[2] = 4; Role_None.gren1_limits[3] = 4; @@ -999,7 +977,6 @@ void () DecodeLevelParms = { medicnocuss = FALSE; project_weapons = FALSE; distance_based_cuss_duration = FALSE; - pyro_type = 1; drop_grenades = FALSE; drop_grenpack = FALSE; drop_gren1 = 0; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 305a1fa6..1110c378 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -424,8 +424,8 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, no_damage = 0; - if (pyro_type == PYRO_FO && (targ.tfstate & TFSTATE_BURNING)) - damage = damage * PC_PYRO_BURN_DAMAGE_AMP; + if (targ.tfstate & TFSTATE_BURNING) + damage *= PC_PYRO_BURN_DAMAGE_AMP; if (attacker.classname == "player") { @@ -538,14 +538,6 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, dir = normalize(dir); moment = knock_damage; - if (inflictor.classname == "pyro_rocket" && pyro_type == 1) { - if (attacker == targ) { - moment *= 1.5; - } else { - moment *= 1.25; - } - } - if (targ.playerclass == PC_HVYWEAP) { moment = moment / 4; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index ff9c9817..bb320f07 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -12,14 +12,9 @@ void (entity ent, float num) SetFlameCount = { ent.numflames = num; if (num == 0) - { - ent.tfstate = ent.tfstate - (ent.tfstate & TFSTATE_BURNING); - } + ent.tfstate &= ~TFSTATE_BURNING; else - { - ent.tfstate = ent.tfstate | TFSTATE_BURNING; - } - + ent.tfstate |= TFSTATE_BURNING; }; entity(string type, entity p_owner) FlameSpawn = @@ -157,17 +152,8 @@ void () NapalmGrenadeExplode2 = { // TODO - make a settings struct and put these in on world spawn float explodeDam = 0; float maxExplosions = 0; - switch (pyro_type) - { - case PYRO_FO: - explodeDam = PC_PYRO_NAPALM_INIT_DAM_FO; - maxExplosions = PC_PYRO_NAPALM_MAX_EXPLOSIONS_FO; - break; - default: - explodeDam = PC_PYRO_NAPALM_INIT_DAM_ORIG; - maxExplosions = PC_PYRO_NAPALM_MAX_EXPLOSIONS_ORIG; - break; - } + explodeDam = PC_PYRO_NAPALM_INIT_DAM; + maxExplosions = PC_PYRO_NAPALM_MAX_EXPLOSIONS; self.nextthink = time + 1; makevectors(self.v_angle); @@ -310,20 +296,7 @@ void () FlameFollow = { } self.nextthink = time + 0.1; if ((self.effects == 8) && (self.heat >= 3)) { - damage = 0; - switch (pyro_type) - { - case PYRO_FO: - damage = self.enemy.numflames * PC_PYRO_BURN_MULTIPLIER_FO * 3; - break; - default: - damage = self.enemy.numflames * PC_PYRO_BURN_MULTIPLIER_ORIG * 3; - break; - } - - if (damage < 1) { - damage = 1; - } + damage = min(self.enemy.numflames * PC_PYRO_BURN_MULTIPLIER * 3, 1); self.heat = 1; deathmsg = 15; TF_T_Damage(self.enemy, self, self.owner, damage, TF_TD_NOTTEAM, @@ -435,14 +408,8 @@ void () Flamer_stream_touch = { } } - if (pyro_type == PYRO_FO) - { - TF_T_Damage(other, self, self.owner, PC_PYRO_FLAMETHROWER_DAM_FO, TF_TD_NOTTEAM, TF_TD_FIRE); - } - else - { - TF_T_Damage(other, self, self.owner, PC_PYRO_FLAMETHROWER_DAM_ORIG, TF_TD_NOTTEAM, TF_TD_FIRE); - } + TF_T_Damage(other, self, self.owner, PC_PYRO_FLAMETHROWER_DAM, + TF_TD_NOTTEAM, TF_TD_FIRE); float flamehealth = 45; SetOnFire(other, self.owner, self.origin, flamehealth); @@ -450,7 +417,7 @@ void () Flamer_stream_touch = { } } else { if ((random() < 0.3) || - (pointcontents((self.origin + '0 0 1')) != -1)) { + (pointcontents((self.origin + '0 0 1')) != CONTENT_EMPTY)) { remove(self); return; } @@ -476,16 +443,8 @@ void () Napalm_touch = { } if (other != world) { if ((other.takedamage == 2) && (other.health > 0)) { - float dam = 0; - switch (pyro_type) - { - case PYRO_FO: - dam = PC_PYRO_INIT_BURN_DAM_FO; - break; - default: - dam = PC_PYRO_INIT_BURN_DAM_ORIG; - break; - } + float dam = PC_PYRO_INIT_BURN_DAM; + deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, dam, TF_TD_NOTTEAM, TF_TD_FIRE); @@ -553,21 +512,12 @@ void () W_FireFlame = { flame.solid = SOLID_BBOX; flame.classname = "flamerflame"; makevectors(self.v_angle); - flame.velocity = aim(self, 10000); - if (pyro_type == PYRO_FO) - { - flame.velocity = flame.velocity * FPP_Get(FPP_FLAMETHROWER)->speed; - flame.nextthink = time + 0.15; - } - else - { - flame.velocity = flame.velocity * 600; - flame.nextthink = time + 0.15; - } - + flame.velocity = aim(self, 10000) * FPP_Get(FPP_FLAMETHROWER)->speed; + flame.nextthink = time + 0.15; + flame.touch = Flamer_stream_touch; flame.think = s_explode1; - + setorigin(flame, self.origin + v_forward * 16 + '0 0 16'); FOProj_Finalize(flame); @@ -604,27 +554,6 @@ void () IncendiaryRadius = { dremove_sent(self); }; -void () IncendiaryRadius_OZTF = { - local float damg; - if (pyro_type == 1) - damg = 68; - else - damg = 92; - deathmsg = 15; - - entity ignore_self = AntilagKnock(self, damg) ? self.owner : __NULL__; - T_RadiusDamage(self, self.owner, damg, other, ignore_self); - - self.origin = (self.origin - (8 * normalize (self.velocity))); - WriteByte(4, 23); - WriteByte(4, 3); - WriteCoord(4, self.origin_x); - WriteCoord(4, self.origin_y); - WriteCoord(4, self.origin_z); - multicast(self.origin, 1); - dremove_sent(self); -}; - void () T_IncendiaryTouch = { local float damg; @@ -641,36 +570,28 @@ void () T_IncendiaryTouch = { return; } self.effects = self.effects | 4; - if (pyro_type == PYRO_ORIGINAL) - { - damg = 30 + random() * 20; - } - else - { - if (pyro_type == 1) - damg = 68 + random() * 20; - else - damg = 42 + random() * 20; - } - + damg = 42 + random() * 20; + if (other.health) { deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_FIRE); } - switch (pyro_type) - { - case PYRO_ORIGINAL: - IncendiaryRadius(); - break; - case PYRO_OZTF: - IncendiaryRadius_OZTF(); - break; - case PYRO_FO: - IncendiaryRadius_OZTF(); - break; - } + damg = 92; + deathmsg = 15; + + entity ignore_self = AntilagKnock(self, damg) ? self.owner : __NULL__; + T_RadiusDamage(self, self.owner, damg, other, ignore_self); + + self.origin = (self.origin - (8 * normalize (self.velocity))); + WriteByte(4, 23); + WriteByte(4, 3); + WriteCoord(4, self.origin_x); + WriteCoord(4, self.origin_y); + WriteCoord(4, self.origin_z); + multicast(self.origin, 1); + dremove_sent(self); }; void () W_FireIncendiaryCannon = { @@ -683,21 +604,12 @@ void () W_FireIncendiaryCannon = { proj.owner = self; proj.movetype = MOVETYPE_FLYMISSILE; proj.solid = SOLID_BBOX; + makevectors(self.v_angle); - proj.velocity = aim(self, 1000); - if (pyro_type == PYRO_ORIGINAL) - { - proj.velocity = proj.velocity * 600; - proj.think = SUB_Remove; - } - else - { - proj.velocity = proj.velocity * FPP_Get(FPP_INCENDIARY)->speed; - proj.think = IncendiaryRadius_OZTF; - } - + proj.velocity = aim(self, 1000) * FPP_Get(FPP_INCENDIARY)->speed; proj.angles = vectoangles(proj.velocity); proj.touch = T_IncendiaryTouch; + proj.think = SUB_Remove; proj.nextthink = time + 5; proj.weapon = DMSG_INCENDIARY; proj.classname = "pyro_rocket"; @@ -714,21 +626,11 @@ void () AirBlastReloadFinished = { }; void FO_Airblast() = { - if (pyro_type == PYRO_FO) - if (airblastv2) { - UseAirBlastV2(); - } else { - UseAirBlast(); - } - Status_Refresh(self); -} - -void () UseAirBlast = { if(no_fire_mode) { sprint(self, PRINT_MEDIUM, "You cannot blast air right now\n"); return; } - + if (time < self.special_cooldown) return; @@ -802,123 +704,5 @@ void () UseAirBlast = { if (ent.classname != "player") ent.SendFlags |= FOPP_POS; } -}; - -void () UseAirBlastV2 = { - if(no_fire_mode) { - sprint(self, PRINT_MEDIUM, "You cannot blast air right now\n"); - return; - } - - float isabjump = airblastjump && self.v_angle_x > 60; - - if (self.ammo_cells < airblastcells) - { - sprint(self, PRINT_HIGH, "Not enough cells to Airblast\n"); - } - else if (isabjump && airblastcells > 0 && self.ammo_cells < airblastjumpcells) - { - sprint(self, PRINT_HIGH, "Not enough cells to Airblast jump\n"); - } - else if (self.special_cooldown < time) - { - float cellcost = airblastcells; - - self.airblast_cooldown = 1; - self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; - entity timer = spawn(); - timer.owner = self; - timer.classname = "timer"; - timer.nextthink = time + PC_PYRO_AIRBLAST_COOLDOWN; - timer.think = AirBlastReloadFinished; - - FO_Sound(self, CHAN_WEAPON, "weapons/airblastshoot.wav", 1, ATTN_NORM); - makevectors(self.v_angle); - entity ent; - - float abrange = PC_PYRO_AIRBLAST_RANGE / 2; - vector ab_start = self.origin + v_up * 20 + v_forward * 8; - vector ab_origin = ab_start + aim(self,1000) * (abrange / 2); - vector ab_diameter = ab_start + aim(self,1000) * abrange; - - pointparticles(particleeffectnum("fo_airblast"), ab_origin, v_forward); - - if (isabjump) - { - if (airblastcells > 0 && airblastjumpcells > airblastcells) - { - cellcost = cellcost + airblastjumpcells - airblastcells; - } - - if ((airblastjump == 1 || airblastjump == 3) && self.flags & FL_ONGROUND) - self.velocity_z = 490; - else if (airblastjump == 1 || airblastjump == 2) - { - self.velocity_z = self.velocity_z + 260; - } - } - - self.ammo_cells = self.ammo_cells - cellcost; - - ent = findradius(ab_origin, abrange); - while (ent) - { - if (ent.movetype != MOVETYPE_NONE && ent != self && CanDamage(ent,self)) - { - vector diameter_pos = ab_start + aim(self,500) * vlen(ent.origin - ab_start); - float distfromdiameter = vlen(ent.origin - diameter_pos); - - if (distfromdiameter <= airblastsize / 2 && ent != self) - { - switch (ent.classname) - { - case "player": - case "pyro_rocket": - case "flamerflame": - case "proj_tranq": - case "proj_bullet": - case "proj_rocket": - case "grenade": - case "spike": - case "pipebomb": - vector targorg = ent.origin; - float pushval = airblastpushmax; - vector delta = targorg - ab_start; - float dist = vlen(delta); - float scale = airblastpushmax - airblastpushmin; - float percent = (abrange - dist) / abrange; - - if (ent.movetype != MOVETYPE_FLY && ent.classname != "pipebomb" && ent.velocity == '0 0 0') // Airblast non-moving ents, except for pipebombs - { - setorigin(ent, ent.origin + '0 0 1'); - ent.velocity = '0 0 150' + normalize(ent.origin - (self.origin - v_up * 28 )) * 400; - } - else if (ent.movetype == MOVETYPE_FLYMISSILE) // return missle at same speed in where aiming - { - ent.velocity = vlen(ent.velocity) * aim(self,1000); - } - else // All other trajectory is based on ab -> ent and velocity via pushval - { - if (percent <= 0.05) { pushval = airblastpushmin; } - else if (percent >= 0.50) { pushval = airblastpushmax; } - else { pushval = airblastpushmin + scale * percent; } - - if (ent.owner != self) - { - ent.velocity = '0 0 0'; - } - //self.origin used to avoid downward trajectory - ent.velocity = ent.velocity + pushval * normalize(ent.origin - self.origin); - } - - break; - - } - } - } - - ent = ent.chain; - } - - } + Status_Refresh(self); }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ef09dce4..e05327d6 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -593,13 +593,6 @@ float server_huetf; float scoutscanspike; float asscanrange; float asscanrangedie; -float airblastv2; -float airblastpushmin; -float airblastpushmax; -float airblastjump; -float airblastsize; -float airblastcells; -float airblastjumpcells; float force_reload; float old_spanner; @@ -619,7 +612,6 @@ float superknife; float superknife_multihit; float impulse_queue; float detpack_when_reloading; -float pyro_type; float flag_follow; float ceasefire_type; float cs_paused; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index bb25bb3d..8d083205 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -50,8 +50,6 @@ void () TeamFortress_DetpackMenu; void () CF_Medic_AuraToggle; void () FO_LockToggle; void () FO_Airblast; -void () UseAirBlast; -void () UseAirBlastV2; void () TeamFortress_EngineerBuild; void () TeamFortress_EngineerBuildStop; void () TeamFortress_Scan; From a6062c08961007ce2eb3459ecfc8d18cf15ebd04 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 14 Dec 2022 01:06:17 -0800 Subject: [PATCH 1946/2474] Add flame to incendiary direct Due to an unintended interaction between all the pyro types code, direct incendiaries were doing less damage than splash. We have to buff the direct a little bit, but how? This is a first pass, it adds a flame effect to (only) direct incendiaries which push the (total) damage from 42+random(20) to ~72+random(20). Additionally, the flame dot will result in the target receiving additional damage from future sources while alight. In particular, this should also make pyro much better against relatively static defense such as sentries and hwguys and that feels like a step in the right direction. --- ssqc/pyro.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index bb320f07..54708901 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -573,6 +573,9 @@ void () T_IncendiaryTouch = { damg = 42 + random() * 20; if (other.health) { + if (CF_GetSetting("pdf", "pyro_direct_fix", "on") && + other.solid != SOLID_BSP) + SetOnFire(other, self.owner, self.origin, 30); deathmsg = DMSG_FLAME; TF_T_Damage(other, self, self.owner, damg, TF_TD_NOTTEAM, TF_TD_FIRE); From c293f1e19f2ee99439d06fcefd9ab1cb88890e56 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 15 Dec 2022 00:06:22 -0800 Subject: [PATCH 1947/2474] Handle TFSTATE_CANT_MOVE in REWIND_SETSPEED This was out-of-line and not properly handled, fixed. Also simplify/improve the logic on when the ceiling needs to be raised for CSQC-managed. --- csqc/weapon_predict.qc | 36 +++++++++++++++++------------------- share/commondefs.qc | 3 +-- ssqc/tfort.qc | 22 +++++++++++++++------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 4ef4287a..6d865b8e 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -914,39 +914,37 @@ void MP_SetSpeed() { if (!CVARF(wpp_setspeed)) return; - const float speed_aiming = 80; - const float speed_aiming2dir = ceil(speed_aiming/sqrt(2)); - static float last_playerclass; + static float last_playerclass, last_set; - float speed = pstate_pred.csqc_maxspeed, force = FALSE; - - float fastest = - max(CVARF(cl_forwardspeed), CVARF(cl_backspeed), CVARF(cl_sidespeed)); + float speed = pstate_pred.csqc_maxspeed; if (pstate_pred.playerclass != last_playerclass) - force = TRUE; + last_set = -1; // Force update. last_playerclass = pstate_pred.playerclass; - if (pstate_pred.tfstate & TFSTATE_AIMING) + const float speed_aiming = 80; + const float speed_aiming2dir = ceil(speed_aiming/sqrt(2)); + + if (pstate_pred.tfstate & TFSTATE_AIMING) { speed = min(pstate_pred.csqc_maxspeed, speed_aiming); - else if (fastest == speed_aiming || fastest == speed_aiming2dir) - force = TRUE; // This is an imperfect good heuristic that avoids - // issues on missed packets/transitions/etc. - // Cap as maxspeed would, but client-side, when enabled. - if (RewindFlagEnabled(REWIND_SETSPEED) && speed < pstate_pred.csqc_maxspeed) { + // Cap as maxspeed would, but client-side, when enabled. + if (RewindFlagEnabled(REWIND_SETSPEED)) if (input_movevalues.x && input_movevalues.y) - speed = speed_aiming2dir; - else if (fastest == speed_aiming2dir) - force = TRUE; // reset back to speed_aiming + speed = min(speed, speed_aiming2dir); } + float fastest = + max(CVARF(cl_forwardspeed), CVARF(cl_backspeed), CVARF(cl_sidespeed)); + // We check >speed, not =speed as it's still valid for clients to control to // lower speeds. Except for transitions where the maxspeed is reset. - if (fastest > speed || force) { + if (speed > last_set || fastest > speed) { + last_set = speed; + CVARF(cl_forwardspeed) = CVARF(cl_backspeed) = CVARF(cl_sidespeed) = speed; + string spd = ftos(speed); localcmd("cl_forwardspeed ", spd, "; cl_backspeed ",spd, "; cl_sidespeed ", spd, "\n"); - CVARF(cl_forwardspeed) = CVARF(cl_backspeed) = CVARF(cl_sidespeed) = speed; } } diff --git a/share/commondefs.qc b/share/commondefs.qc index e53afc7b..e203b432 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -68,8 +68,7 @@ string REWIND_DESC[] = { }; const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_HIT | - REWIND_FORWARD_PROJ_SELFKNOCK | - REWIND_SETSPEED; + REWIND_FORWARD_PROJ_SELFKNOCK; float RewindFlagEnabled(float flag) { return fo_config.rewind_flags & flag; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 685844a4..fca555be 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1256,9 +1256,13 @@ void (entity p) TeamFortress_SetSpeed = { stuffcmd(p, "m_side 0\n"); #endif p.velocity = '0 0 0'; - stuffcmd(p, "cl_backspeed 0\n"); - stuffcmd(p, "cl_forwardspeed 0\n"); - stuffcmd(p, "cl_sidespeed 0\n"); + if (!RewindFlagEnabled(REWIND_SETSPEED)) { + // maxspeed suffices for any modern client, delete these once + // tested in a few pugs. + stuffcmd(p, "cl_backspeed 0\n"); + stuffcmd(p, "cl_forwardspeed 0\n"); + stuffcmd(p, "cl_sidespeed 0\n"); + } p.maxspeed = 0; return; } @@ -1268,6 +1272,13 @@ void (entity p) TeamFortress_SetSpeed = { stuffcmd(p, "m_side 0.8\n"); } #endif + if (p.playerclass == PC_UNDEFINED) { + // Typically this hits spectators and then spec movetype --> maxspeed + // actually ignored. + p.maxspeed = 0; + return; + } + float new_max = Class_MaxSpeed(p.playerclass); tf = 0; @@ -1295,13 +1306,10 @@ void (entity p) TeamFortress_SetSpeed = { // maxspeed/pmove interaction (bounds client prediction until maxspeed makes // it to client, even though released on unpredicted earlier frame, leading // to lots of skipping). - if (!RewindFlagEnabled(REWIND_SETSPEED) || !client_enable) + if (!RewindFlagEnabled(REWIND_SETSPEED) || !client_enable) { if (p.tfstate & TFSTATE_AIMING) new_max = min(new_max, 80); - if (!client_enable) { - // It's possible to set the client-enable without REWIND_SETSPEED, - // they'll just skip more. sp = ftos(new_max); stuffcmd(p, "cl_backspeed ", sp, "; cl_forwardspeed ", sp, "; cl_sidespeed ", sp, "\n"); From 23468ca958e39039b67edec2d9bef4396f748f42 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 15 Dec 2022 01:10:17 -0800 Subject: [PATCH 1948/2474] TFX: Updates - Temporarily disable due to deltalisten smashing shaders when not in use - Turn off in prematch - Visibility for tf_flag model - Simplify outline selection --- csqc/tfx.qc | 17 +++++++++++------ share/commondefs.qc | 3 +-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 1ebc4ca2..947e6667 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -80,9 +80,9 @@ static void RemoveOutline() { remove(self.outline); } -static void AddOutline(entity ent, string model) { +static void AddOutline(entity ent) { entity o = spawn(); - setmodel(o, model); + setmodelindex(o, ent.modelindex); o.classname = "outline"; o.fatness = 1; setsize(o, PLAYER_MINS, PLAYER_MAXS); @@ -115,7 +115,7 @@ float UpdatePlayer(float isnew) { if (self.entnum == player_localentnum && is_player) local_player = self; - AddOutline(self, "progs/player.mdl"); + AddOutline(self); } if (self.entnum == player_localentnum) @@ -253,7 +253,8 @@ static void UpdateFlagOutline(entity flag) { float UpdateFlag(float isnew) { if (isnew) { - AddOutline(self, "progs/ff_flag.mdl"); + float mindex = self.modelindex; + AddOutline(self); // Flags have their own shader already, just make them shiny for now. } @@ -277,7 +278,6 @@ static string OutlineShader(string texture) { blendfunc GL_ONE GL_ONE_MINUS_SRC_COLOR\ tcgen environment\ tcmod rotate 30\ - tcmod scroll 1.1\ nodepthtest\ depthfunc greater\ }\ @@ -295,13 +295,18 @@ static string rnds(string prefix) { } void TF_Init() { - precache_model("progs/player.mdl"); +#if 0 + Deltalisten breaks some default shaders even without a forceoverride. Quick + fix to unblock. + deltalisten("progs/player.mdl", UpdatePlayer, 0); deltalisten("progs/ff_flag.mdl", UpdateFlag, 0); + deltalisten("progs/tf_flag.mdl", UpdateFlag, 0); shader_team[0] = shaderforname(rnds("blue_team_outline"), OutlineShader("textures/sfx/quad.tga")); shader_team[1] = shaderforname(rnds("red_team_outline"), OutlineShader("textures/sfx/pent.tga")); shader_flag = shaderforname(rnds("flag_outline"), OutlineShader("textures/sfx/specular.tga")); shader_over_outline = shaderforname(rnds("over_outline"), "{ sort 7 }"); +#endif } diff --git a/share/commondefs.qc b/share/commondefs.qc index e203b432..e8907d1f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -105,8 +105,7 @@ float TFxEnabled(float flag) { } const float TFX_DEFAULT_FLAGS = - TFX_SPEC_OUTLINE | TFX_SPEC_GRENTIMER | TFX_SPEC_SEEFLAG | - TFX_PREMATCH_EVERYTHING; + TFX_SPEC_OUTLINE | TFX_SPEC_GRENTIMER | TFX_SPEC_SEEFLAG; enum CSQCFlags { PREDICT_CSQC_SETSPEED, From 7ee5325b3e03a1ba9e0f16ba9876580dbe068192 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 19 Dec 2022 15:57:42 -0800 Subject: [PATCH 1949/2474] Nits / settings updates --- share/commondefs.qc | 6 ++++-- ssqc/rewind.qc | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index e8907d1f..f7ea341f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -61,14 +61,16 @@ enumflags { string REWIND_DESC[] = { "rewind projectile hit", "rewind pipe knockback", - "allow csqc to handle maxspeed" + "allow csqc to handle maxspeed", "rewind grenade throws", "forward projectile self-knockback", "open doors earlier for hpbs [requires rfd=1]", }; const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_HIT | - REWIND_FORWARD_PROJ_SELFKNOCK; + REWIND_FORWARD_PROJ_SELFKNOCK | + REWIND_SETSPEED; + float RewindFlagEnabled(float flag) { return fo_config.rewind_flags & flag; diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 6b88c9b8..e2b63d54 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -205,8 +205,10 @@ static void RewindTo(RewindState* rstate, float rtime) { pos = b->origin + frac * diff; } } else { - float max_xerp = CF_GetSetting("rwmx", "rewind_max_xerp", "0.02"); - pos = rstate->held_origin + min(rtime - e.client_lastupdate, max_xerp) * e.velocity; + pos = rstate->held_origin; + float max_xerp = CF_GetSetting("rwmx", "rewind_max_xerp", "0"); + if (max_xerp > 0) + pos += min(rtime - e.client_lastupdate, max_xerp) * rstate->held_velocity; } setorigin(rstate->owner, pos); From 2cb0b88636f19e7873785bddfbd31bd945344b89 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 20 Dec 2022 18:06:54 -0800 Subject: [PATCH 1950/2474] Better matching of melee animations Eliminate 2 sources of mismatch between client and server animation: 1) Turns out to be a general fix, readshort is signed (and writeshort will just pass through unsigned) and we were clipping the range on our base. Leading to client and server using different prng bases for some value. 2) It's possible also to just mispredict/miss/etc. We can filter these out by having the server animation follow the client's choice in the case we got it wrong. --- csqc/weapon_predict.qc | 10 ++++++++++ share/prediction.qc | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6d865b8e..fec0bf77 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -440,6 +440,16 @@ void WP_ServerUpdate() { if (pstate_server.attack_finished < pstate_server.client_time) pstate_server.weaponframe = 0; + // Match up melee animations when they don't match. The easiest way for + // this to happen is effectframe miss. + if (pstate_server.weaponframe >= 1 && pstate_server.weaponframe < 8 && + pstate_pred.weaponframe >= 1 && pstate_pred.weaponframe < 8) { + pstate_server.weaponframe = (pstate_server.weaponframe - 1) % 4; + if (pstate_pred.weaponframe >= 4) + pstate_server.weaponframe += 4; + pstate_server.weaponframe += 1; + } + if (CVARF(fo_wpp_beta) == 2) phys_sim_dt = (pstate_server.client_ping + 2 * SERVER_FRAME_MS) / 1000.0; else diff --git a/share/prediction.qc b/share/prediction.qc index 4e3a4ae5..bf2aeb2c 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -366,6 +366,7 @@ float() ReadCoord = #364; float() ReadAngle = #365; float() ReadFloat = #367; float() ReadEntity = #368; +int() ReadInt = #0:readint; void InitWeapPredEnt(entity e); void WP_ServerUpdate(); @@ -480,9 +481,9 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Float, reload_finished); if (sendflags & FOWP_RNG0) - COMM(Short, prng_base[0]); + COMM(Int, prng_base[PRNG_WEAP]); if (sendflags & FOWP_RNG1) - COMM(Short, prng_base[1]); + COMM(Int, prng_base[PRNG_HWGUY]); #ifdef SSQC return TRUE; From f6940f4fadf7735487922999f304f684580b7f28 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 20 Dec 2022 21:21:41 -0800 Subject: [PATCH 1951/2474] Animation tweaks - Make sure we only frame match on melee slots (external animation frames are unique, weapon model frames aren ot) - Make sure we don't emit projectiles for not-in-animation cases when we have no ammo. --- csqc/weapon_predict.qc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index fec0bf77..ac307bbd 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -442,7 +442,8 @@ void WP_ServerUpdate() { // Match up melee animations when they don't match. The easiest way for // this to happen is effectframe miss. - if (pstate_server.weaponframe >= 1 && pstate_server.weaponframe < 8 && + if (IsSlotMelee(pstate_server.current_slot) && + pstate_server.weaponframe >= 1 && pstate_server.weaponframe < 8 && pstate_pred.weaponframe >= 1 && pstate_pred.weaponframe < 8) { pstate_server.weaponframe = (pstate_server.weaponframe - 1) % 4; if (pstate_pred.weaponframe >= 4) @@ -1357,13 +1358,16 @@ void WP_Attack() { if (wi->predict_type == NO_PREDICT) return; + if (!WP_CheckAmmo(wi)) + return; + // Whether firing occurs here, or is embedded in the frame animation code // (because continuous fire). int in_anim = wi->weapon == WEAP_NAILGUN || wi->weapon == WEAP_SUPER_NAILGUN || wi->weapon == WEAP_ASSAULT_CANNON; - if ((in_anim && !WP_CheckAmmo(wi)) || (!in_anim && !WP_ConsumeAmmo(CurrentSlot()))) + if (!in_anim && !WP_ConsumeAmmo(CurrentSlot())) return; // OK. We're ready to pew. From 5b75c2eb1d13f6de7eb2395ba73b08e5942274e1 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 20 Dec 2022 23:16:20 -0800 Subject: [PATCH 1952/2474] Fix scoreboard flickering It turns out this only ever worked by luck before (happening to get the right trash on stack). Flickering was due to inconsistent trash on stack. --- csqc/status.qc | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 045870db..cd32dd4b 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -654,19 +654,8 @@ string (float val) AbbreviateNumberToString = { }; void (vector position, vector size, string val, vector textcolour, float alpha - , float flags, string colname, optional float padright = FALSE) drawShowScoresColumnVal = { - float valwidth, colwidth; - - colwidth = strlen(colname); - if (padright == TRUE) - { - val = strpad(colwidth, val); - } - else - { - val = strpad(colwidth * -1, val); - } - + , float flags, string colname) drawShowScoresColumnVal = { + val = strpad(strlen(colname) * -1, val); sui_text(position, size, val, textcolour, 1, 0); }; From 0f95708b1441dc6ce7eaffed0ae008314c5000dc Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Dec 2022 00:01:10 -0800 Subject: [PATCH 1953/2474] Restore shock grenade rotation during their interstitial pop-up. --- share/prediction.qc | 7 +++++++ ssqc/tsoldier.qc | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/share/prediction.qc b/share/prediction.qc index bf2aeb2c..64fa2653 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -29,6 +29,7 @@ enumflags { FOPP_POS, FOPP_AUX, FOPP_ANGLES, + FOPP_AVEL, FOPP_MOVETYPE, FOPP_EXPIRY, FOPP_NEW, // We only use this for a new entity, which is FFF... anyway. @@ -551,6 +552,12 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, angles[2]); } + if (sendflags & FOPP_AVEL) { + COMM(Coord, avelocity[0]); + COMM(Coord, avelocity[1]); + COMM(Coord, avelocity[2]); + } + if (sendflags & FOPP_MOVETYPE) { COMM(Byte, movetype); if (self.movetype == MOVETYPE_FOLLOW) diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index b32dbd7f..aa3747c6 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -95,6 +95,7 @@ void () ShockGrenadeExplode = { self.no_active_nail_grens = self.owner.no_active_nail_grens; self.movetype = MOVETYPE_FLY; self.velocity = '0 0 0'; + self.avelocity = '0 500 0'; setorigin(self, self.origin + '0 0 32'); if(solid_nailgren) { setsize(self, '-1 -1 -1', '1 1 1'); @@ -102,7 +103,7 @@ void () ShockGrenadeExplode = { self.nextthink = time + 0.7; self.playerclass = 0; self.think = NailGrenLaser; - self.SendFlags |= FOPP_POS | FOPP_MOVETYPE; + self.SendFlags |= FOPP_POS | FOPP_MOVETYPE | FOPP_AVEL; }; void () BurstGrenadeExplode = { From c24c561bfb7e4c901ccf9677d9555c94a5ef3b39 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 24 Dec 2022 01:26:48 -0800 Subject: [PATCH 1954/2474] Emulate MOVETYPE_PUSH The CSQC reflected entities don't get fully propagated for platforms such as lifts etc. Handle this by just blasting updates from server side when on pusher that's in motion. It's not perfect but handles the worst of it. --- share/physics.qc | 25 ---------------------- share/prediction.qc | 51 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/share/physics.qc b/share/physics.qc index e9087cc9..ae4c9753 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -23,35 +23,10 @@ const float FL_FORWARD_KNOCK = FL_GODMODE; static inline float PhysFlagEnabled(float flag) { return fo_config.qc_physics & flag; } - void AugmentGrenadeImpact(); #ifdef SSQC -float Phys_Advance(entity e, float target_time, float phys_flags); - -void FO_CustomPhysics() { - if (!self.voided) - Phys_Advance(self, time, 0); - - float held_time, thinktime; - // Once we lift physics, think execution comes with it. - do { - thinktime = self.nextthink; - if (thinktime <= 0 || thinktime > time) - return; - - held_time = time; - self.nextthink = 0; - time = thinktime; - self.think(); - time = held_time; - - if (self.is_removed || self.nextthink < thinktime /* no loop on rev */) - return; - } while (1); -} -void Predict_UpdateHack(entity e); static void Phys_Impact(entity e, float dt, float phys_flags) { other = trace_ent; if (other.solid == SOLID_NOT) diff --git a/share/prediction.qc b/share/prediction.qc index 64fa2653..ed55730c 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -350,14 +350,6 @@ void sprint_pred(entity client, float msglevel, string s) { return; // Message generated client-side. sprint(client, msglevel, s); } - -// Networked (non-csqc) entities don't appear to exist within the client-side -// CSQC world for our physics simulation. Until we either (a) migrate them -// there or (b) find a way to propagate them there, we cheat by sending an -// update to the client when such a collision occurs. -void Predict_UpdateHack(entity e) { - e.SendFlags |= FOPP_POS | FOPP_ANGLES; -} #endif #ifdef CSQC @@ -745,6 +737,38 @@ void WeaponPred_DoServerClientThink() { } } +void FO_CustomPhysics() { + if (!self.voided) { + Phys_Advance(self, time, 0); + + // Moving platforms don't get properly reflected into the entities CSQC + // sees so just blast the client with updates when on one (in motion). + // Basically what the stock netcode does anyway. It's not perfect but, + // better than nothing. + entity ground = self.groundentity; + if ((self.flags & FL_ONGROUND) && (ground.movetype == MOVETYPE_PUSH) && + (vlen(ground.velocity) > 0)) + self.SendFlags |= FOPP_POS; + } + + float held_time, thinktime; + // Once we lift physics, think execution comes with it. + do { + thinktime = self.nextthink; + if (thinktime <= 0 || thinktime > time) + return; + + held_time = time; + self.nextthink = 0; + time = thinktime; + self.think(); + time = held_time; + + if (self.is_removed || self.nextthink < thinktime /* no loop on rev */) + return; + } while (1); +} + void FO_Sound(entity e, float chan, string samp, float vol, float atten); void Pred_Sound(SoundIndex snd, float vol = 1) { @@ -896,9 +920,16 @@ void AugmentGrenadeImpact() { } #ifdef SSQC - if (other.solid != SOLID_BSP) - Predict_UpdateHack(self); + if (other.solid != SOLID_BSP) { + // Networked (non-csqc) entities don't appear to exist within the + // client-side CSQC world for our physics simulation. Until we either + // (a) migrate them there or (b) find a way to propagate them there, we + // cheat by sending an update to the client when such a collision + // occurs. + self.SendFlags |= FOPP_POS | FOPP_ANGLES; + } if (self.movetype != old_move) self.SendFlags |= FOPP_MOVETYPE; #endif } + From 19c9fa83b5c11375ace4f41f2ae61498fab07597 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 23 Dec 2022 23:24:27 -0800 Subject: [PATCH 1955/2474] Input/State cleanup - Unify is-alive checks (e.g. jump, pweap, etc) under is_alive - Fix +button3 sniper zoom - Move more stuff out of CSQC_Input_Frame --- csqc/csextradefs.qc | 1 + csqc/main.qc | 58 +++++++++++++++++++----------------------- csqc/pmove.qc | 3 +-- csqc/weapon_predict.qc | 7 ++++- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6a3f5835..5f0e5248 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -818,6 +818,7 @@ float is_spectator; float player_class; float is_observer; float is_player; +float is_alive; //float health; float oldhealth; float painfinished; diff --git a/csqc/main.qc b/csqc/main.qc index 9e6f062c..f69527c5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -128,12 +128,17 @@ noref void() CSQC_WorldLoaded = { void Hud_UpdateView(float width, float height, float menushown, float perf_sample); +DEFCVAR_FLOAT(fov, 90); + noref void(float width, float height, float menushown) CSQC_UpdateView = { float fts = perf_start_sample(&frame_timing); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + if (zoomed_in) + setviewprop(VF_AFOV, CVARF(fov)/3); + // Draw original sbar, viewsize honoured automatically. if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) setproperty(VF_DRAWENGINESBAR, 1); @@ -417,8 +422,6 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; -void WPP_Dump(); - noref void CSQC_Input_Frame() { local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; @@ -426,31 +429,30 @@ noref void CSQC_Input_Frame() { local float keydowns = changed_buttons & input_buttons; local float keyups = changed_buttons & ~input_buttons; + Sync_GameState(); + // Intercept rocket jump; - if ((player_class == PC_SOLDIER || player_class == PC_PYRO) && input_buttons & BUTTON4) { - input_buttons |= BUTTON0 + BUTTON2; - } + if ((player_class == PC_SOLDIER || player_class == PC_PYRO) && + (input_buttons & BUTTON4)) + input_buttons |= BUTTON0 | BUTTON2; + + // Handle zoom + float prev_zoomed_in = zoomed_in; + if (player_class == PC_SNIPER && is_alive) + zoomed_in = input_buttons & BUTTON3; + else + zoomed_in = 0; - // Intercept zoom - if (player_class == PC_SNIPER && keydowns & BUTTON3) { - zoomed_in = !zoomed_in; - } - - if (input_impulse == TF_DEBUG_CSQC) { - WPP_Dump(); - input_impulse = 0; - } + if (prev_zoomed_in != zoomed_in) + setsensitivityscaler(zoomed_in ? 1/3 : 1); WPP_UpdateEnable(FALSE); - Sync_GameState(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { - local float health = getstatf(STAT_HEALTH); - //pain face is 0.2 long - if(oldhealth > health) { + if (take > 0) painfinished = time + 0.2; - } + return 0; } @@ -476,24 +478,16 @@ void _Sync_ServerCommandFrame() { is_observer = TRUE; player_class = getstatf(STAT_CLASS); SBAR.ReadyStatus = getstatf(STAT_FLAGS); - oldhealth = getstatf(STAT_HEALTH); + is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) is_observer = FALSE; is_player = (!is_spectator && !is_observer); - local float health = getstatf(STAT_HEALTH); - if (health <= 0 || player_class != PC_SNIPER) { - zoomed_in = 0; - } - - if (zoomed_in) { - setviewprop(VF_AFOV, CVARF(fov))/3; - setsensitivityscaler(1/3); - } else { - setviewprop(VF_AFOV, CVARF(fov)); - setsensitivityscaler(1); - } + if (!is_player || getstatf(STAT_HEALTH) <= 0) + is_alive = 0; + else + is_alive = 1; UpdateMinPing(); } diff --git a/csqc/pmove.qc b/csqc/pmove.qc index f0de8c47..84428a3e 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -37,10 +37,9 @@ void PM_PredictJump() { float jumping = input_buttons & BUTTON2; float onground = pmove_onground; float landing = onground && !last_onground; - float health = getstatf(STAT_HEALTH); float vel_z = pmove_vel_z ?: recent_pmove_vel_z; - if (health <= 0) { + if (!is_alive) { last_onground = 1; last_vel_z = 0; last_waterlevel = 0; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ac307bbd..35c13666 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -648,6 +648,7 @@ static void HandleButtonThrowgren(float index, float button) { float WP_ReloadSlot(Slot slot); void WP_ReloadNext(); +void WPP_Dump(); void WP_Impulse() { WP_HandleHeavyInputs(); @@ -662,6 +663,10 @@ void WP_Impulse() { W_ThrowGren(TRUE); break; + case TF_DEBUG_CSQC: + WPP_Dump(); + break; + default: match = FALSE; break; @@ -962,7 +967,7 @@ void MP_SetSpeed() { void WP_Frame() { - if (getstatf(STAT_HEALTH) < 0) { + if (!is_alive) { pstate_pred.current_slot = SlotNull; return; } From bf0ee5d4743ea822cf8a6bddae5d1c6c31cac3da Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Dec 2022 01:49:09 +1100 Subject: [PATCH 1956/2474] Hacky fix the gameclock bug in fo_fte_hud, needs rewrite --- csqc/csextradefs.qc | 2 +- csqc/events.qc | 5 ++++- csqc/status.qc | 14 ++++++-------- share/commondefs.qc | 1 + ssqc/csmenu.qc | 13 +++++++++++-- ssqc/quadmode.qc | 12 +++++++++++- 6 files changed, 34 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1c5e9550..c360c26f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -90,7 +90,7 @@ float quad_rounds_total; float prematch; float round_active; float round_over; -float round_time_remaining; +float round_ending; float showingscores; float mapvote_expiry; float num_mapvotes; diff --git a/csqc/events.qc b/csqc/events.qc index b68a0390..e1b17ff0 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -268,9 +268,12 @@ void() CSQC_Parse_Event = { //game_started = readbyte(); local float rtr = readfloat(); if(rtr) { - round_time_remaining = time + rtr; + round_ending = time + rtr; } break; + case MSG_QUAD_ROUND_BEGIN: + round_ending = readfloat() * 60 + time + 1; + break; case MSG_TEAM_SCORES: TeamScore[0] = readfloat(); TeamScore[1] = readfloat(); diff --git a/csqc/status.qc b/csqc/status.qc index b099dc3e..9be48dca 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -329,9 +329,9 @@ string gameClockString() { float minutes = 0; float seconds = 0; float timelimit = stof(serverkey("timelimit")); - - if(round_time_remaining) { - float t = round_time_remaining - time; + + if(round_ending) { + float t = round_ending - time; if(t < 0) t = t * -1; minutes = floor(t/60); seconds = floor(t - (minutes*60)); @@ -345,14 +345,12 @@ string gameClockString() { minutes = floor(time/60); seconds = floor(time - (minutes*60)); } - + string sm = strcat((minutes<10?"0":""),ftos(minutes)); string ss = strcat((seconds<10?"0":""),ftos(seconds)); - + string tmp = strcat(sm,":",ss); - //if(round_time_remaining) tmp = ftos(floor(round_time_remaining - time)); - - return tmp; + return tmp; }; void(string panelid, float display, string text) doNothing = {}; diff --git a/share/commondefs.qc b/share/commondefs.qc index 71bd23ff..7fd07c5a 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -32,6 +32,7 @@ #define MSG_VOTE_MAP_ADD 20 #define MSG_VOTE_MAP_DELETE 21 #define MSG_PLAYERDIE 22 +#define MSG_QUAD_ROUND_BEGIN 23 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 5cf036cf..5ca67ef4 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -269,6 +269,17 @@ void UpdateClientTeamScores(entity e) = { multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); } +void UpdateClientQuadRoundBegin(entity pl, float round_time) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_QUAD_ROUND_BEGIN); + WriteFloat(MSG_MULTICAST, round_time); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientPrematch(entity pl, float countdownstarted) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; @@ -285,12 +296,10 @@ void UpdateClientPrematch(entity pl, float countdownstarted) = { local entity t = find(world, classname, "match"); if (t != world) { timeleft = t.cnt2; - } t = find(world, classname, "prematch"); if (t != world) { timeleft = t.cnt2; - } t = find(world, classname, "round"); if (t != world) { diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 0e59bb2c..e9c6cc04 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -255,7 +255,8 @@ void () QuadRoundBegin = { //local entity tfdet; local float counter; - localcmd(strcat(strcat("timelimit ", ftos(stof(infokey(world, "round_time")))), "\n")); + local float round_time = stof(infokey(world, "round_time")); + localcmd(strcat(strcat("timelimit ", ftos(round_time)), "\n")); te = find(world, classname, "func_breakable"); while (te) { @@ -308,6 +309,15 @@ void () QuadRoundBegin = { } bprint(2, "QUAD ROUND BEGINS NOW\n"); + + te = find(world, classname, "player"); + while (te) { + if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { + UpdateClientQuadRoundBegin(te, round_time); + } + te = find(te, classname, "player"); + } + if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; self.cnt2 = 60; From 87c762420df020c0c9a2a20694fd0897892d4b21 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 25 Dec 2022 17:03:18 -0800 Subject: [PATCH 1957/2474] Use thinkindex to reset hit_in_current_animation The starting weapon-frame is variable depending on whether the a, or b, swing animation is being used. This could result in the multi-frame hit counter not being reset on b-swings after a-swings. Use thinkindex() instead which is uniform across the two animations. --- share/animate.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/animate.qc b/share/animate.qc index 5403b9f2..4fb0c12f 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -93,7 +93,7 @@ static void axe_extra() { break; } - if (self.weaponframe == 1) + if (*thinkindex() == 2) // 1-index and already incremented. self.hit_in_current_animation = FALSE; if ((*flag && !self.hit_in_current_animation) || From 303c23bbde04c477c1bae0afa1137bfe01f63936 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 8 Jan 2023 23:09:24 +1100 Subject: [PATCH 1958/2474] WIP --- README.md | 2 ++ ssqc/client.qc | 5 ++- ssqc/login.qc | 12 +++++++ ssqc/quadmode.qc | 85 ++++++++++++++++++++++++++++++++++++++++++++++-- ssqc/qw.qc | 3 ++ 5 files changed, 104 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8ad78ce9..5351df25 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ FortressOne Server New features ------ +* website backend for match results, stats. Login with discord at https://www.fortressone.org, and set `_fo_token`. +* `localinfo discord_channel_id n` to specify discord_channel. Required for autoreporting. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/client.qc b/ssqc/client.qc index c8f84dc5..db12ec08 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -810,7 +810,10 @@ void () DecodeLevelParms = { // allow clients to place a personal practice spawn [off] allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); - + + // specify discord channel for auto-reporting [""] + discord_channel_id = infokey(world, "discord_channel_id"); + // split backpack.mdl into deathbag.mdl and discard.mdl [on] (visual change only) splitbackpackmodels = CF_GetSetting("sbm", "splitbackpackmodels", "on"); diff --git a/ssqc/login.qc b/ssqc/login.qc index a83f979d..222beac0 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -14,6 +14,18 @@ void (entity player, string login, string secret) performLogin = { } void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback = { + switch(reqid) + { + case 11: + bprint(PRINT_HIGH, "=================\n"); + bprint(PRINT_HIGH, "=================\n"); + bprint(PRINT_HIGH, "responsecode: ", ftos(responsecode), "\n"); + bprint(PRINT_HIGH, "resourcebody: ", resourcebody, "\n"); + bprint(PRINT_HIGH, "=================\n"); + bprint(PRINT_HIGH, "=================\n"); + return; + } + local float got_one = 0; self.login_in_progress = 0; local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 0e59bb2c..b696fa5d 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -249,7 +249,6 @@ void () QuadRoundThink = { }; void () QuadRoundBegin = { - local entity te; local entity oldself; //local entity tfdet; @@ -298,7 +297,7 @@ void () QuadRoundBegin = { self = oldself; te = find (te, classname, "player"); } -// lightstyle (0, "m"); + // lightstyle (0, "m"); te = find(world, classname, "observer"); while (te) { if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { @@ -307,6 +306,57 @@ void () QuadRoundBegin = { te = find(te, classname, "observer"); } + local string data = ""; + + data = strcat(data, "{\n"); + data = strcat(data, " \"match\": {\n"); + data = strcat(data, " \"map\": \"", mapname, "\",\n"); + data = strcat(data, " \"discord_channel\": {\n"); + data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); + data = strcat(data, " },\n"); + data = strcat(data, " \"teams\": {\n"); + + local float prefix_comma; + local string token; + local entity p; + local float tn; + + for (tn = 1; tn <= number_of_teams; ++tn) { + if (tn > 1) + data = strcat(data, ","); + + data = strcat(data, " \"", ftos(tn), "\": {\n"); + data = strcat(data, " \"players\": [\n"); + + prefix_comma = FALSE; + + p = find(world, classname, "player"); + while (p != world) { + if(p.team_no == tn) { + if (prefix_comma) + data = strcat(data, ","); + + token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); + data = strcat(data, "{ \"auth_token\": \"", token, "\" }\n"); + prefix_comma = TRUE; + } + + p = find(p, classname, "player"); + } + + data = strcat(data, " ]\n"); + data = strcat(data, " }\n"); + } + + data = strcat(data, " }\n"); + data = strcat(data, " }\n"); + data = strcat(data, "}\n"); + + // make url configurable + bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); + bprint(PRINT_HIGH, "data: ", data, "\n"); + uri_post("http://host.docker.internal:3000/results/api/v1/matches", 11, "application/json", data); + bprint(2, "QUAD ROUND BEGINS NOW\n"); if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; @@ -421,6 +471,33 @@ void () StartQuadRound = round_over = 1; if (rounds == 1) { + local float i = 0; + local string data = ""; + p = find(world, classname, "player"); + while (p != world) { + if(i > 0) + data = strcat("&", data); + + data = strcat("fo_token[", ftos(i), "]=", p.fo_token); + i++; + + p = find(p, classname, "player"); + } + + // make url configurable + /* bprint(PRINT_HIGH, "===sending StartQuadRound request===\n"); */ + /* bprint(PRINT_HIGH, data, "\n"); */ + /* uri_get("http://host.docker.internal:3000/foos", 11, "application/x-www-form-urlencoded", data); */ + + while (p != world) { + if (p.netname != "" && p.team_no && p.playerclass) { + } + if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(p, TRUE); + } + p = find(p, classname, "player"); + } + quad_winner = CheckWinningTeam(); if (quad_winner == 0) bprint (2, "Round Drawn!\n"); @@ -433,6 +510,10 @@ void () StartQuadRound = else if (quad_winner == 4) bprint(2, "Green Team Wins!\n"); p = find (world, classname, "player"); + + // send result to server + + while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { p.takedamage = DAMAGE_NO; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 269b0b3b..50a36e3e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -634,6 +634,7 @@ float noreturn; float nohitsounds; float nokeepcells; float allowpracspawns; +string discord_channel_id; float splitbackpackmodels; float standardizedeathammo; float deathammo_shells; @@ -737,6 +738,8 @@ string webpageUrl; .string login; .float login_in_progress; +.string fo_token; + //Logging fields float gametime; string gametimestamp; From 261affc73af9ec70bf3d5b9951656d2d2e91aafa Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Jan 2023 00:44:00 +1100 Subject: [PATCH 1959/2474] Save match_id / refactor --- share/defs.h | 4 ++ ssqc/login.qc | 115 +++++++++++++++++++++++------------------------ ssqc/quadmode.qc | 107 ++++++++++++++++++++++--------------------- ssqc/qw.qc | 3 ++ 4 files changed, 120 insertions(+), 109 deletions(-) diff --git a/share/defs.h b/share/defs.h index 89e3a0c3..756bfd33 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1523,3 +1523,7 @@ #define TEAM_RED 2 #define TEAM_YELL 3 #define TEAM_GREN 4 + +// web request index +#define FO_MATCH_STARTED_REQUEST 1 +#define BR_LOGIN_REQUEST 2 diff --git a/ssqc/login.qc b/ssqc/login.qc index 222beac0..199d4701 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -2,7 +2,7 @@ void (entity player, string login, string secret) performLogin = { string data = strcat("login=", login); data = strcat(data,"&secret="); data = strcat(data,secret); - uri_get(loginUrl, 10, "application/x-www-form-urlencoded", data); + uri_get(loginUrl, BR_LOGIN_REQUEST, "application/x-www-form-urlencoded", data); self.login_in_progress = 1; dprint(infokey(self,"name")); dprint(" ["); @@ -14,67 +14,64 @@ void (entity player, string login, string secret) performLogin = { } void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback = { - switch(reqid) - { - case 11: + switch(reqid) { + case FO_MATCH_STARTED_REQUEST: + match_id = resourcebody; bprint(PRINT_HIGH, "=================\n"); + bprint(PRINT_HIGH, "Match ID: ", match_id, "\n"); bprint(PRINT_HIGH, "=================\n"); - bprint(PRINT_HIGH, "responsecode: ", ftos(responsecode), "\n"); - bprint(PRINT_HIGH, "resourcebody: ", resourcebody, "\n"); - bprint(PRINT_HIGH, "=================\n"); - bprint(PRINT_HIGH, "=================\n"); - return; - } - - local float got_one = 0; - self.login_in_progress = 0; - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if (!responsecode) { - float num_args = tokenizebyseparator(resourcebody,";"); - self.login = argv(0); - forceinfokey(self,"*login", self.login); - bprint(2, infokey(self,"name")); - bprint(2, " has logged in as \s"); - bprint(2, self.login); - bprint(2, "\s\n"); - dprint(infokey(self,"name")); - dprint(" logged in as "); - dprint(self.login); - dprint("\n"); - CenterPrint3(self, "You have logged in as ", self.login, "\n"); - if (num_args > 1) { - if (argv(1) == "true") { - self.is_admin = TRUE; - forceinfokey(self,"*admin", ftos(self.is_admin)); - Admin_Aliases (); - bprint(2, self.netname, " \sgains full admin status!\s\n"); -// bprint (3, "\n"); - sprint(self, 2, "Type \scommands\s for admin commands.\n"); - } - } - if(self.team_no == 0 && !intermission_running) { - if (clanbattle && (self.has_disconnected != 1)) { - if (self.tf_id != 0) { - got_one = RejoinWithTfId(); - ResetAndRespawnPlayer(self); + break; + case BR_LOGIN_REQUEST: + local float got_one = 0; + self.login_in_progress = 0; + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (!responsecode) { + float num_args = tokenizebyseparator(resourcebody,";"); + self.login = argv(0); + forceinfokey(self,"*login", self.login); + bprint(2, infokey(self,"name")); + bprint(2, " has logged in as \s"); + bprint(2, self.login); + bprint(2, "\s\n"); + dprint(infokey(self,"name")); + dprint(" logged in as "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, "You have logged in as ", self.login, "\n"); + if (num_args > 1) { + if (argv(1) == "true") { + self.is_admin = TRUE; + forceinfokey(self,"*admin", ftos(self.is_admin)); + Admin_Aliases (); + bprint(2, self.netname, " \sgains full admin status!\s\n"); + // bprint (3, "\n"); + sprint(self, 2, "Type \scommands\s for admin commands.\n"); + } } - if (!got_one) { - CreateTfIdAndJoin(); - } - } - if (!got_one) { - if (csqcactive) - Menu_Team(0); - else - Menu_Team(1); + if(self.team_no == 0 && !intermission_running) { + if (clanbattle && (self.has_disconnected != 1)) { + if (self.tf_id != 0) { + got_one = RejoinWithTfId(); + ResetAndRespawnPlayer(self); + } + if (!got_one) { + CreateTfIdAndJoin(); + } + } + if (!got_one) { + if (csqcactive) + Menu_Team(0); + else + Menu_Team(1); + } + } + } else { + dprint(infokey(self,"name")); + dprint(" login failed: "); + dprint(self.login); + dprint("\n"); + CenterPrint3(self, ftos(responsecode), " - Login FAILED, invalid Login/Secret", "\n"); } - } - } - else { - dprint(infokey(self,"name")); - dprint(" login failed: "); - dprint(self.login); - dprint("\n"); - CenterPrint3(self, ftos(responsecode), " - Login FAILED, invalid Login/Secret", "\n"); + break; } } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index b696fa5d..8d39830d 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -1,5 +1,61 @@ void () info_player_teamspawn; +void () PostFOMatchStarted = { + local string data = ""; + + data = strcat(data, "{\n"); + data = strcat(data, " \"match\": {\n"); + data = strcat(data, " \"map\": \"", mapname, "\",\n"); + data = strcat(data, " \"discord_channel\": {\n"); + data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); + data = strcat(data, " },\n"); + data = strcat(data, " \"teams\": {\n"); + + local float tn; + local float prefix_comma; + local entity p; + local string token; + + for (tn = 1; tn <= number_of_teams; ++tn) { + if (TeamFortress_TeamGetNoPlayers(tn) == 0) + continue; + + if (tn > 1) + data = strcat(data, ","); + + data = strcat(data, " \"", ftos(tn), "\": {\n"); + data = strcat(data, " \"players\": [\n"); + + prefix_comma = FALSE; + + p = find(world, classname, "player"); + while (p != world) { + if(p.team_no == tn) { + if (prefix_comma) + data = strcat(data, ","); + + token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); + data = strcat(data, "{ \"auth_token\": \"", token, "\" }\n"); + prefix_comma = TRUE; + } + + p = find(p, classname, "player"); + } + + data = strcat(data, " ]\n"); + data = strcat(data, " }\n"); + } + + data = strcat(data, " }\n"); + data = strcat(data, " }\n"); + data = strcat(data, "}\n"); + + // make url configurable + uri_post("http://host.docker.internal:3000/results/api/v1/matches", FO_MATCH_STARTED_REQUEST, "application/json", data); + bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); + bprint(PRINT_HIGH, "data: ", data, "\n"); +}; + float () CheckWinningTeam = { local float win_score = 0; local float winning_team = 0; @@ -306,56 +362,7 @@ void () QuadRoundBegin = { te = find(te, classname, "observer"); } - local string data = ""; - - data = strcat(data, "{\n"); - data = strcat(data, " \"match\": {\n"); - data = strcat(data, " \"map\": \"", mapname, "\",\n"); - data = strcat(data, " \"discord_channel\": {\n"); - data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); - data = strcat(data, " },\n"); - data = strcat(data, " \"teams\": {\n"); - - local float prefix_comma; - local string token; - local entity p; - local float tn; - - for (tn = 1; tn <= number_of_teams; ++tn) { - if (tn > 1) - data = strcat(data, ","); - - data = strcat(data, " \"", ftos(tn), "\": {\n"); - data = strcat(data, " \"players\": [\n"); - - prefix_comma = FALSE; - - p = find(world, classname, "player"); - while (p != world) { - if(p.team_no == tn) { - if (prefix_comma) - data = strcat(data, ","); - - token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); - data = strcat(data, "{ \"auth_token\": \"", token, "\" }\n"); - prefix_comma = TRUE; - } - - p = find(p, classname, "player"); - } - - data = strcat(data, " ]\n"); - data = strcat(data, " }\n"); - } - - data = strcat(data, " }\n"); - data = strcat(data, " }\n"); - data = strcat(data, "}\n"); - - // make url configurable - bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); - bprint(PRINT_HIGH, "data: ", data, "\n"); - uri_post("http://host.docker.internal:3000/results/api/v1/matches", 11, "application/json", data); + PostFOMatchStarted(); bprint(2, "QUAD ROUND BEGINS NOW\n"); if (!self.cnt) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 50a36e3e..62047f5b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -786,6 +786,9 @@ string goal_class_names[7] = { .float airblast_cooldown; +// backend +string match_id; + // people complain about settings, let's track them string settings_to_track_list[2] = { From f5d041b99dfd40c54178b4862881c8a152d9aa27 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Jan 2023 01:28:12 +1100 Subject: [PATCH 1960/2474] Refactor --- ssqc/quadmode.qc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 8d39830d..a4dd3cd2 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -17,12 +17,6 @@ void () PostFOMatchStarted = { local string token; for (tn = 1; tn <= number_of_teams; ++tn) { - if (TeamFortress_TeamGetNoPlayers(tn) == 0) - continue; - - if (tn > 1) - data = strcat(data, ","); - data = strcat(data, " \"", ftos(tn), "\": {\n"); data = strcat(data, " \"players\": [\n"); @@ -35,7 +29,7 @@ void () PostFOMatchStarted = { data = strcat(data, ","); token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); - data = strcat(data, "{ \"auth_token\": \"", token, "\" }\n"); + data = strcat(data, " { \"auth_token\": \"", token, "\" }\n"); prefix_comma = TRUE; } @@ -43,7 +37,12 @@ void () PostFOMatchStarted = { } data = strcat(data, " ]\n"); - data = strcat(data, " }\n"); + data = strcat(data, " }"); + + if (tn < number_of_teams) + data = strcat(data, ","); + + data = strcat(data, " \n"); } data = strcat(data, " }\n"); From 2b8c69be9c09a667ddc052f50c973e4a8ca4f0e4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Jan 2023 01:39:22 +1100 Subject: [PATCH 1961/2474] Make backend uri configurable --- README.md | 3 ++- ssqc/client.qc | 3 +++ ssqc/quadmode.qc | 2 +- ssqc/qw.qc | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5351df25..908f9dd2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ New features ------ * website backend for match results, stats. Login with discord at https://www.fortressone.org, and set `_fo_token`. -* `localinfo discord_channel_id n` to specify discord_channel. Required for autoreporting. +* `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. +* `localinfo backend_uri ` to specify backend API endpoint, i.e. https://www.fortressone.org/ in prod * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/client.qc b/ssqc/client.qc index db12ec08..7b629a80 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -814,6 +814,9 @@ void () DecodeLevelParms = { // specify discord channel for auto-reporting [""] discord_channel_id = infokey(world, "discord_channel_id"); + // specify discord channel for auto-reporting [""] + backend_uri = infokey(world, "backend_uri", "https://www.fortressone.org"); + // split backpack.mdl into deathbag.mdl and discard.mdl [on] (visual change only) splitbackpackmodels = CF_GetSetting("sbm", "splitbackpackmodels", "on"); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index a4dd3cd2..cc64a55f 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -50,7 +50,7 @@ void () PostFOMatchStarted = { data = strcat(data, "}\n"); // make url configurable - uri_post("http://host.docker.internal:3000/results/api/v1/matches", FO_MATCH_STARTED_REQUEST, "application/json", data); + uri_post(sprintf("%s/results/api/v1/matches", backend_uri), FO_MATCH_STARTED_REQUEST, "application/json", data); bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); bprint(PRINT_HIGH, "data: ", data, "\n"); }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 62047f5b..88c31116 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -635,6 +635,7 @@ float nohitsounds; float nokeepcells; float allowpracspawns; string discord_channel_id; +string backend_uri; float splitbackpackmodels; float standardizedeathammo; float deathammo_shells; From e38a46ca0f903193defcdd6252e996be3916c23a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 10 Jan 2023 03:01:44 +1100 Subject: [PATCH 1962/2474] Add result reporting --- README.md | 2 +- ssqc/client.qc | 6 +++--- ssqc/quadmode.qc | 24 ++++++++++++++++++++---- ssqc/qw.qc | 2 +- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 908f9dd2..8f693c13 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ New features * website backend for match results, stats. Login with discord at https://www.fortressone.org, and set `_fo_token`. * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. -* `localinfo backend_uri ` to specify backend API endpoint, i.e. https://www.fortressone.org/ in prod +* `localinfo backend_host ` to specify backend API endpoint. Default: https://www.fortressone.org/ * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/client.qc b/ssqc/client.qc index 7b629a80..3d36c7aa 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -811,11 +811,11 @@ void () DecodeLevelParms = { // allow clients to place a personal practice spawn [off] allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); - // specify discord channel for auto-reporting [""] + // specify discord channel for results auto-reporting [""] discord_channel_id = infokey(world, "discord_channel_id"); - // specify discord channel for auto-reporting [""] - backend_uri = infokey(world, "backend_uri", "https://www.fortressone.org"); + // specify API host for backend [""] + backend_host = infokey(world, "backend_host", "https://www.fortressone.org"); // split backpack.mdl into deathbag.mdl and discard.mdl [on] (visual change only) splitbackpackmodels = CF_GetSetting("sbm", "splitbackpackmodels", "on"); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index cc64a55f..97634bf8 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -49,12 +49,28 @@ void () PostFOMatchStarted = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); - // make url configurable - uri_post(sprintf("%s/results/api/v1/matches", backend_uri), FO_MATCH_STARTED_REQUEST, "application/json", data); + local string uri = sprintf("%s/results/api/v1/matches", backend_host); + uri_post(uri, FO_MATCH_STARTED_REQUEST, "application/json", data); bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); bprint(PRINT_HIGH, "data: ", data, "\n"); }; +void (float winner) PostFOMatchFinished = { + local string data = ""; + + data = strcat(data, "{\n"); + data = strcat(data, " \"match\": {\n"); + data = strcat(data, " \"id\": \"", match_id, "\",\n"); + data = strcat(data, " \"winner\": \"", ftos(winner), "\"\n"); + data = strcat(data, " }\n"); + data = strcat(data, "}\n"); + + local string uri = sprintf("%s/results/api/v1/matches/%s", backend_host, match_id); + uri_post(uri, FO_MATCH_STARTED_REQUEST, "application/json", data); + bprint(PRINT_HIGH, "===sending QuadRoundFinished request===\n"); + bprint(PRINT_HIGH, "data: ", data, "\n"); +}; + float () CheckWinningTeam = { local float win_score = 0; local float winning_team = 0; @@ -361,9 +377,9 @@ void () QuadRoundBegin = { te = find(te, classname, "observer"); } + bprint(2, "QUAD ROUND BEGINS NOW\n"); PostFOMatchStarted(); - bprint(2, "QUAD ROUND BEGINS NOW\n"); if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; self.cnt2 = 60; @@ -518,7 +534,7 @@ void () StartQuadRound = p = find (world, classname, "player"); // send result to server - + PostFOMatchFinished(quad_winner); while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 88c31116..8371706a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -635,7 +635,7 @@ float nohitsounds; float nokeepcells; float allowpracspawns; string discord_channel_id; -string backend_uri; +string backend_host; float splitbackpackmodels; float standardizedeathammo; float deathammo_shells; From 255199907e4fbc8abbf85f27a8c0ca2e958edce5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 10 Jan 2023 23:45:30 +1100 Subject: [PATCH 1963/2474] All time attack and defence options --- csqc/events.qc | 6 ++++ csqc/menu.qc | 5 +++- share/defs.h | 5 ++++ ssqc/commands.qc | 16 ++++++++++- ssqc/quadmode.qc | 74 ++++++++++++++++++++---------------------------- ssqc/qw.qc | 2 ++ ssqc/weapons.qc | 1 - 7 files changed, 63 insertions(+), 46 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index b68a0390..0e859490 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -131,6 +131,12 @@ void() CSQC_Parse_Event = { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; } } + + if(!(SBAR.GameMode & GAMEMODE_QUAD)) { + FO_MENU_TEAM.options[6].state = FO_MENU_STATE_DISABLED; + FO_MENU_TEAM.options[7].state = FO_MENU_STATE_DISABLED; + } + FO_Menu_Team(2); break; case CLIENT_MENU_CLASS: diff --git a/csqc/menu.qc b/csqc/menu.qc index 46adcd35..c70a55c4 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -98,6 +98,7 @@ var fo_menu FO_MENU_SPECTATOR_TRACK = { void teamChosen(string team) = { localcmd("cmd changeteam ", team, "\n"); + if(player_class) { Menu_Cancel(); } else { @@ -113,9 +114,11 @@ var fo_menu FO_MENU_TEAM = { {"4","Green team","","Also okay",FO_MENU_STATE_NORMAL,{teamChosen("4");},MENU_TEXT_GREEN_FO}, MenuSpacer, {"5","Auto-assign team","","",FO_MENU_STATE_NORMAL,{teamChosen("auto");},MENU_BUTTON}, + {"6","All time attack","","Always on the attacking team",FO_MENU_STATE_NORMAL,{teamChosen("attack");},MENU_BUTTON}, + {"7","All time defence","","Always on the defending team",FO_MENU_STATE_NORMAL,{teamChosen("defence");},MENU_BUTTON}, MenuSpacer, {"0","Spectate","","",FO_MENU_STATE_NORMAL,{localcmd("observe\n");Menu_Cancel();},MENU_BUTTON}, - }, 8, TRUE, { + }, 10, TRUE, { if(intermission) { Menu_Cancel(); } diff --git a/share/defs.h b/share/defs.h index 756bfd33..13973402 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1524,6 +1524,11 @@ #define TEAM_YELL 3 #define TEAM_GREN 4 +// all time teams +#define ALL_TIME_COLOUR 0 +#define ALL_TIME_ATTACK 1 +#define ALL_TIME_DEFENCE 2 + // web request index #define FO_MATCH_STARTED_REQUEST 1 #define BR_LOGIN_REQUEST 2 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a40dec71..60eda5a6 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -387,6 +387,19 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } if (arg2) { + local float final_round = (rounds == 1); + + switch(arg2) { + case "attack": + self.all_time = ALL_TIME_ATTACK; + arg2 = final_round ? "2" : "1"; + break; + case "defence": + self.all_time = ALL_TIME_DEFENCE; + arg2 = final_round ? "1" : "2"; + break; + } + if(arg2 == "auto") { if(self.team_no == 0) { TeamFortress_TeamPutPlayerInTeam(); @@ -398,6 +411,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } } + if(arg2 == "1" || arg2 == "2" || arg2 == "3" || arg2 == "4") { float newteam = stof(arg2), oldteam = self.team_no; if(number_of_teams == 0 || newteam <= number_of_teams) { @@ -884,7 +898,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "cmd showvotes\b: List current voting summary\b\n"); sprint(self, PRINT_HIGH, "cmd break\b: Cancel current vote\b\n"); } else { - sprint(self, PRINT_HIGH, "cmd changeteam [#|auto]\n"); + sprint(self, PRINT_HIGH, "cmd changeteam [#|auto|attack|defence]\n"); sprint(self, PRINT_HIGH, "cmd changeclass [#]\n"); sprint(self, PRINT_HIGH, "cmd dropammo [1-4] [amount]\n"); sprint(self, PRINT_HIGH, "cmd disguise [last|none|skin #|team #]\n"); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 97634bf8..8a38e455 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -1,6 +1,6 @@ void () info_player_teamspawn; -void () PostFOMatchStarted = { +void () PostFOQuadStarted = { local string data = ""; data = strcat(data, "{\n"); @@ -24,7 +24,7 @@ void () PostFOMatchStarted = { p = find(world, classname, "player"); while (p != world) { - if(p.team_no == tn) { + if(p.team_no == tn && p.all_time == ALL_TIME_COLOUR) { if (prefix_comma) data = strcat(data, ","); @@ -55,7 +55,7 @@ void () PostFOMatchStarted = { bprint(PRINT_HIGH, "data: ", data, "\n"); }; -void (float winner) PostFOMatchFinished = { +void (float winner) PostFOQuadFinished = { local string data = ""; data = strcat(data, "{\n"); @@ -378,7 +378,6 @@ void () QuadRoundBegin = { } bprint(2, "QUAD ROUND BEGINS NOW\n"); - PostFOMatchStarted(); if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; @@ -493,24 +492,6 @@ void () StartQuadRound = round_over = 1; if (rounds == 1) { - local float i = 0; - local string data = ""; - p = find(world, classname, "player"); - while (p != world) { - if(i > 0) - data = strcat("&", data); - - data = strcat("fo_token[", ftos(i), "]=", p.fo_token); - i++; - - p = find(p, classname, "player"); - } - - // make url configurable - /* bprint(PRINT_HIGH, "===sending StartQuadRound request===\n"); */ - /* bprint(PRINT_HIGH, data, "\n"); */ - /* uri_get("http://host.docker.internal:3000/foos", 11, "application/x-www-form-urlencoded", data); */ - while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { } @@ -534,7 +515,7 @@ void () StartQuadRound = p = find (world, classname, "player"); // send result to server - PostFOMatchFinished(quad_winner); + PostFOQuadFinished(quad_winner); while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { @@ -568,8 +549,34 @@ void () StartQuadRound = localcmd("stop\n"); return; } - if (rounds > 1) + + if (rounds > 1){ rounds = (rounds - 1); + + if (rounds == 2) + PostFOQuadStarted(); + + if (rounds == 1 /* final round */) { + te = find(world, classname, "player"); + while (te != world) { + if (te.all_time != ALL_TIME_COLOUR) { + sprint(te, PRINT_HIGH, "Swapping teams.\n"); + + switch(te.all_time) { + case ALL_TIME_ATTACK: + stuffcmd(te, "cmd changeteam attack\n"); + break; + case ALL_TIME_DEFENCE: + stuffcmd(te, "cmd changeteam defence\n"); + break; + } + } + + te = find(te, classname, "player"); + } + } + } + if (intermission_running) return; @@ -669,22 +676,3 @@ void () StartQuadRound = te.nextthink = (time + 1); } }; - -void () EndQuadRound = { - if (infokey(world, "quadmode") == "on") { - if (infokey(world,"status") != "Countdown" && infokey(world,"status") != "Standby") { - if (rounds > 1) { - local string st; - st = ftos(round_delay_time); - bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); - lightstyle (0, "e"); - self.think = QuadRoundOver; - self.nextthink = (time + 0.1); - } - else if (rounds == 1) { - StartQuadRound(); - } - } - } -}; - diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 8371706a..614aa511 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -165,8 +165,10 @@ entity round_winner; float round_winner_print_health; .float team_no; // The team you belong to +.float all_time; // Automatically join attacking/defending team during quads .float lives; // The number of lives you have left + .float infection_team_no; // The team_no of the person who infected you // CTF stuff diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 544eccd2..64c66ab3 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -121,7 +121,6 @@ void () TranquiliserTimer; void () TeamFortress_CTF_FlagInfo; void () ClanMode; void () QuadMode; -void () EndQuadRound; void () PlayerReady; void () PlayerNotReady; void () Broadcast_Players_NotReady; From 5ed6554022d507ef23978e5036de5b40116d6aab Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 11 Jan 2023 01:39:52 +1100 Subject: [PATCH 1964/2474] Only show all time options when appropriate --- csqc/csextradefs.qc | 1 + csqc/events.qc | 21 ++++++++++++++++++--- csqc/main.qc | 1 + csqc/menu.qc | 6 ------ share/defs.h | 1 + ssqc/commands.qc | 4 ++++ ssqc/world.qc | 1 + 7 files changed, 26 insertions(+), 9 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c360c26f..ce530007 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -529,6 +529,7 @@ DEFCVAR_FLOAT(fo_legacy_sbar, 0); DEFCVAR_FLOAT(fo_csjumpsounds, 1); float team_no; +float all_time; float is_spectator; float player_class; float is_observer; diff --git a/csqc/events.qc b/csqc/events.qc index 352b17b7..a0d19166 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -122,7 +122,7 @@ void() CSQC_Parse_Event = { for(float i = 0; i < 4; i++) { if(i < number_of_teams) { FO_MENU_TEAM.options[i].value = ftos(readbyte()); - if((i + 1) != team_no) { + if(((i + 1) != team_no) || (all_time != ALL_TIME_COLOUR)) { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_NORMAL; } else { FO_MENU_TEAM.options[i].state = FO_MENU_STATE_DISABLED; @@ -132,7 +132,22 @@ void() CSQC_Parse_Event = { } } - if(!(SBAR.GameMode & GAMEMODE_QUAD)) { + if(SBAR.GameMode & GAMEMODE_QUAD) { + switch (all_time) { + case ALL_TIME_COLOUR: + FO_MENU_TEAM.options[6].state = FO_MENU_STATE_NORMAL; + FO_MENU_TEAM.options[7].state = FO_MENU_STATE_NORMAL; + break; + case ALL_TIME_ATTACK: + FO_MENU_TEAM.options[6].state = FO_MENU_STATE_DISABLED; + FO_MENU_TEAM.options[7].state = FO_MENU_STATE_NORMAL; + break; + case ALL_TIME_DEFENCE: + FO_MENU_TEAM.options[6].state = FO_MENU_STATE_NORMAL; + FO_MENU_TEAM.options[7].state = FO_MENU_STATE_DISABLED; + break; + } + } else { FO_MENU_TEAM.options[6].state = FO_MENU_STATE_DISABLED; FO_MENU_TEAM.options[7].state = FO_MENU_STATE_DISABLED; } @@ -148,7 +163,7 @@ void() CSQC_Parse_Event = { case CLIENT_MENU_SCOUT: float scanner_on = readbyte(); float scanner_flags = readfloat(); - + FO_Menu_Scout(2, scanner_on, scanner_flags); break; case CLIENT_MENU_SPY: diff --git a/csqc/main.qc b/csqc/main.qc index f76a10c1..694e6c3f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -480,6 +480,7 @@ void _Sync_ServerCommandFrame() { last_servercommandframe = servercommandframe; team_no = getstatf(STAT_TEAMNO); + all_time = getstatf(STAT_ALL_TIME); is_observer = FALSE; if (team_no == 0) is_observer = TRUE; diff --git a/csqc/menu.qc b/csqc/menu.qc index c70a55c4..20a6866a 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -904,14 +904,8 @@ void FO_Menu_Team(float force) = { if(number_of_teams < 2) { return; } - //Hide autoteam option - //FO_MENU_TEAM.num_opts = number_of_teams; - //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_HIDDEN; FO_MENU_TEAM.options[5].state = FO_MENU_STATE_DISABLED; } else { - //Show autoteam option - //FO_MENU_TEAM.num_opts = 8; - //FO_MENU_TEAM.options[4].state = FO_MENU_STATE_NORMAL; FO_MENU_TEAM.options[5].state = FO_MENU_STATE_NORMAL; } for(float i = 0; i < 4; i++) { diff --git a/share/defs.h b/share/defs.h index 13973402..8b581afe 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1494,6 +1494,7 @@ #define STAT_TP_GREN1 41 #define STAT_TP_GREN2 42 #define STAT_PAUSED 43 +#define STAT_ALL_TIME 44 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 60eda5a6..75a2ffb3 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -393,11 +393,15 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "attack": self.all_time = ALL_TIME_ATTACK; arg2 = final_round ? "2" : "1"; + sprint(self, PRINT_HIGH, "You will always be on the attacking team\n"); break; case "defence": self.all_time = ALL_TIME_DEFENCE; arg2 = final_round ? "1" : "2"; + sprint(self, PRINT_HIGH, "You will always be on the defending team\n"); break; + default: + self.all_time = ALL_TIME_COLOUR; } if(arg2 == "auto") { diff --git a/ssqc/world.qc b/ssqc/world.qc index b4a0cbe9..3085f254 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -329,6 +329,7 @@ void () worldspawn = { lightstyle(63, "a"); clientstat(STAT_TEAMNO, EV_FLOAT, team_no); + clientstat(STAT_ALL_TIME, EV_FLOAT, all_time); clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_VELOCITY_X, EV_VECTOR, velocity); //STAT_VELOCITY_Y and Z are automaticaly defined with this too, because vector From 1970f4197b73ad56d7e69c7fa270967c5433c77f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 11 Jan 2023 02:45:51 +1100 Subject: [PATCH 1965/2474] Clean up --- README.md | 3 ++- share/defs.h | 5 +++-- ssqc/login.qc | 14 ++++++++++---- ssqc/quadmode.qc | 12 ++++++------ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8f693c13..ccee57bf 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,10 @@ FortressOne Server New features ------ -* website backend for match results, stats. Login with discord at https://www.fortressone.org, and set `_fo_token`. +* Website backend for match results, stats. Login with discord at https://www.fortressone.org, and `setinfo _fo_token `. * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. * `localinfo backend_host ` to specify backend API endpoint. Default: https://www.fortressone.org/ +* All-time attack and all-time defence team options. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/share/defs.h b/share/defs.h index 8b581afe..9ca499e4 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1531,5 +1531,6 @@ #define ALL_TIME_DEFENCE 2 // web request index -#define FO_MATCH_STARTED_REQUEST 1 -#define BR_LOGIN_REQUEST 2 +#define BR_LOGIN_REQUEST 1 +#define FO_QUAD_STARTED_REQUEST 2 +#define FO_QUAD_FINISHED_REQUEST 3 diff --git a/ssqc/login.qc b/ssqc/login.qc index 199d4701..92eca0cf 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -15,11 +15,17 @@ void (entity player, string login, string secret) performLogin = { void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback = { switch(reqid) { - case FO_MATCH_STARTED_REQUEST: + case FO_QUAD_STARTED_REQUEST: + bprint(PRINT_HIGH, "response code: ", ftos(responsecode), "\n"); match_id = resourcebody; - bprint(PRINT_HIGH, "=================\n"); - bprint(PRINT_HIGH, "Match ID: ", match_id, "\n"); - bprint(PRINT_HIGH, "=================\n"); + bprint(PRINT_HIGH, "Match logged ID: ", match_id, "\n"); + break; + case FO_QUAD_FINISHED_REQUEST: + match_id = resourcebody; + bprint(PRINT_HIGH, "response code: ", ftos(responsecode), "\n"); + bprint(PRINT_HIGH, "body: ", resourcebody, "\n"); + /* bprint(PRINT_HIGH, "Match ID: ", match_id, "\n"); */ + /* bprint(PRINT_HIGH, "=================\n"); */ break; case BR_LOGIN_REQUEST: local float got_one = 0; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 1e6db3da..8b3c7f17 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -50,9 +50,9 @@ void () PostFOQuadStarted = { data = strcat(data, "}\n"); local string uri = sprintf("%s/results/api/v1/matches", backend_host); - uri_post(uri, FO_MATCH_STARTED_REQUEST, "application/json", data); - bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); - bprint(PRINT_HIGH, "data: ", data, "\n"); + uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); + /* bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); */ + /* bprint(PRINT_HIGH, "data: ", data, "\n"); */ }; void (float winner) PostFOQuadFinished = { @@ -66,9 +66,9 @@ void (float winner) PostFOQuadFinished = { data = strcat(data, "}\n"); local string uri = sprintf("%s/results/api/v1/matches/%s", backend_host, match_id); - uri_post(uri, FO_MATCH_STARTED_REQUEST, "application/json", data); - bprint(PRINT_HIGH, "===sending QuadRoundFinished request===\n"); - bprint(PRINT_HIGH, "data: ", data, "\n"); + uri_post(uri, FO_QUAD_FINISHED_REQUEST, "application/json", data); + /* bprint(PRINT_HIGH, "===sending QuadRoundFinished request===\n"); */ + /* bprint(PRINT_HIGH, "data: ", data, "\n"); */ }; float () CheckWinningTeam = { From 833cfb5ea53cb197444426bdab5c8e6539f40d39 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 11 Jan 2023 20:55:36 +1100 Subject: [PATCH 1966/2474] Send server address information --- ssqc/quadmode.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 8b3c7f17..29199c73 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -6,6 +6,10 @@ void () PostFOQuadStarted = { data = strcat(data, "{\n"); data = strcat(data, " \"match\": {\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); + data = strcat(data, " \"server\": {\n"); + data = strcat(data, " \"name\": \"", infokey(world, "hostname"), "\",\n"); + data = strcat(data, " \"host\": \"", cvar_string("sv_serverip"), "\"\n"); + data = strcat(data, " },\n"); data = strcat(data, " \"discord_channel\": {\n"); data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); data = strcat(data, " },\n"); From 7121f2a63c41ae790191af81b62b1b11006bb1e8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 11 Jan 2023 22:40:55 +1100 Subject: [PATCH 1967/2474] Terser --- ssqc/commands.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 75a2ffb3..37c32941 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -393,12 +393,12 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "attack": self.all_time = ALL_TIME_ATTACK; arg2 = final_round ? "2" : "1"; - sprint(self, PRINT_HIGH, "You will always be on the attacking team\n"); + sprint(self, PRINT_HIGH, "Always on the attacking team\n"); break; case "defence": self.all_time = ALL_TIME_DEFENCE; arg2 = final_round ? "1" : "2"; - sprint(self, PRINT_HIGH, "You will always be on the defending team\n"); + sprint(self, PRINT_HIGH, "Always on the defending team\n"); break; default: self.all_time = ALL_TIME_COLOUR; From a87b4c618bada794ed40cf00704323bd82cef75f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 13 Jan 2023 01:59:11 +1100 Subject: [PATCH 1968/2474] Prevent readying up, joining team during play for unauthed players --- share/defs.h | 1 + ssqc/clan.qc | 5 ++++ ssqc/client.qc | 23 ++++++++++++------ ssqc/commands.qc | 15 +++++++++--- ssqc/login.qc | 61 +++++++++++++++++++++++++++++++++++++++++------- ssqc/quadmode.qc | 2 -- ssqc/qw.qc | 6 +++-- ssqc/tforttm.qc | 5 ++++ 8 files changed, 96 insertions(+), 22 deletions(-) diff --git a/share/defs.h b/share/defs.h index 9ca499e4..7abe179b 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1534,3 +1534,4 @@ #define BR_LOGIN_REQUEST 1 #define FO_QUAD_STARTED_REQUEST 2 #define FO_QUAD_FINISHED_REQUEST 3 +#define FO_LOGIN_REQUEST 4 diff --git a/ssqc/clan.qc b/ssqc/clan.qc index af8f345b..57536b2e 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1086,6 +1086,11 @@ float () CheckAllPlayersReady = { } void () PlayerReady = { + if (!self.fo_login && foLoginRequired) { + sprint(self, PRINT_HIGH, "You need to log in to ready up. See ", backend_host, "\n"); + return; + } + if (is_countdown) { sprint(self, 2, "You cannot do this after countdown has started.\n"); return; diff --git a/ssqc/client.qc b/ssqc/client.qc index 3d36c7aa..219162ac 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -779,6 +779,15 @@ void () DecodeLevelParms = { loginRequired = 0; } + // specify API host for backend [""] + backend_host = FO_GetUserSettingString(world, "backend_host", "bh", "https://www.fortressone.org"); + + // enforces API login + foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "0"); + + // specify discord channel [""] + discord_channel_id = infokey(world, "discord_channel_id"); + // fortress one flash time in seconds fo_flashtime = CF_GetSetting("ff", "fo_flashtime", "2"); @@ -811,12 +820,6 @@ void () DecodeLevelParms = { // allow clients to place a personal practice spawn [off] allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); - // specify discord channel for results auto-reporting [""] - discord_channel_id = infokey(world, "discord_channel_id"); - - // specify API host for backend [""] - backend_host = infokey(world, "backend_host", "https://www.fortressone.org"); - // split backpack.mdl into deathbag.mdl and discard.mdl [on] (visual change only) splitbackpackmodels = CF_GetSetting("sbm", "splitbackpackmodels", "on"); @@ -3059,11 +3062,17 @@ void () ClientConnect = { if (self.netname == string_null) KickCheater(self); + if (FO_GetUserSettingString(self, "_fo_token", "fo_token", FALSE)) { + stuffcmd(self, "cmd fo-login\n"); + } else if (foLoginRequired) { + sprint(self, PRINT_HIGH, "You need to log in to ready up. Update setinfo _fo_token. See ", backend_host, "\n"); + } + if (infokey(self,"*login")) self.login = infokey(self,"*login"); if (infokey(self,"*admin")) self.is_admin = stof(infokey(self, "*admin")); - if (self.login == string_null) + if (loginRequired && self.login == string_null) sprint(self,2, "Login required, please use \"cmd login \" \nbefore joining the game\n"); TeamFortress_Alias("id", TF_ID, 0); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 37c32941..0265346f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -935,6 +935,15 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint (self, PRINT_HIGH, "Missing username/password\n"); } break; + case "fo-login": + processedCmd = TRUE; + if (self.fo_login != string_null) { + sprint (self, PRINT_HIGH, "You are already logged in\n"); + } + else { + performFoLogin(self); + } + break; case "login-silent" : processedCmd = TRUE; if (arg3 != string_null) { @@ -955,7 +964,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; } - + if (self.is_admin) { switch (arg1) @@ -1298,7 +1307,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } } - + return processedCmd; } @@ -1307,7 +1316,7 @@ void (string cmd) SV_ParseClientCommand = { tokenize(cmd); isProcessed = ParseCmds(argv(0), argv(1), argv(2)); - + if (!isProcessed) { clientcommand(self, cmd); diff --git a/ssqc/login.qc b/ssqc/login.qc index 92eca0cf..7a3a5670 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -13,19 +13,64 @@ void (entity player, string login, string secret) performLogin = { dprint("\n"); } +void (entity player) performFoLogin = { + local string uri = sprintf("%s/results/api/v1/fo_login", backend_host); + local string token = FO_GetUserSettingString(player, "_fo_token", "fo_token", ""); + uri_get(uri, FO_LOGIN_REQUEST, "application/json", sprintf("{ \"auth_token\": \"%s\" }", token)); + player.login_in_progress = 1; + dprint(sprintf("%s [%s] logging in\n", infokey(player, "name"), infokey(player, "ip"))); +} + void(float reqid, float responsecode, string resourcebody, int resourcebytes) URI_Get_Callback = { + local float success = !responsecode; + switch(reqid) { case FO_QUAD_STARTED_REQUEST: - bprint(PRINT_HIGH, "response code: ", ftos(responsecode), "\n"); - match_id = resourcebody; - bprint(PRINT_HIGH, "Match logged ID: ", match_id, "\n"); + local string msg; + + if (success && resourcebody) { + match_id = resourcebody; + msg = sprintf("Quad start successfully logged. ID: %s\n", match_id); + bprint(PRINT_HIGH, msg); + dprint(msg); + } else { + msg = sprintf("Quad start failed to log. Response code: %d\n", responsecode); + bprint(PRINT_HIGH, msg); + dprint(msg); + } + break; case FO_QUAD_FINISHED_REQUEST: - match_id = resourcebody; - bprint(PRINT_HIGH, "response code: ", ftos(responsecode), "\n"); - bprint(PRINT_HIGH, "body: ", resourcebody, "\n"); - /* bprint(PRINT_HIGH, "Match ID: ", match_id, "\n"); */ - /* bprint(PRINT_HIGH, "=================\n"); */ + local string msg; + + if (success && resourcebody == match_id) { + msg = sprintf("Quad result successfully logged. ID: %s\n", match_id); + bprint(PRINT_HIGH, msg); + dprint(msg); + } else { + msg = sprintf("Quad result failed to log. Response code: %d\n", responsecode); + bprint(PRINT_HIGH, msg); + dprint(msg); + } + + break; + case FO_LOGIN_REQUEST: + self.login_in_progress = 0; + local string msg; + + if (!responsecode) { + self.fo_login = resourcebody; + CenterPrint(self, sprintf("You have logged in as %s\n", self.fo_login)); + msg = sprintf("%s has logged in as %s\n", infokey(self, "name"), self.fo_login); + bprint(PRINT_HIGH, msg); + dprint(msg); + } else { + CenterPrint(self, "Login failed\n"); + msg = (sprintf("%s login failed. Response code: %d\n", infokey(self, "name"), responsecode)); + sprint(self, PRINT_HIGH, msg); + dprint(msg); + } + break; case BR_LOGIN_REQUEST: local float got_one = 0; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 29199c73..fa612515 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -71,8 +71,6 @@ void (float winner) PostFOQuadFinished = { local string uri = sprintf("%s/results/api/v1/matches/%s", backend_host, match_id); uri_post(uri, FO_QUAD_FINISHED_REQUEST, "application/json", data); - /* bprint(PRINT_HIGH, "===sending QuadRoundFinished request===\n"); */ - /* bprint(PRINT_HIGH, "data: ", data, "\n"); */ }; float () CheckWinningTeam = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 614aa511..a30449fe 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -734,6 +734,10 @@ string (string s, float width) strpadr = float captainmode; .float captain; +// fortressone.org API +float foLoginRequired; +.string fo_login; + //Player ID float loginRequired; string loginUrl; @@ -741,8 +745,6 @@ string webpageUrl; .string login; .float login_in_progress; -.string fo_token; - //Logging fields float gametime; string gametimestamp; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index cbc7d017..49e9570b 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -295,6 +295,11 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options }; float (float tno) TeamFortress_TeamSet = { + if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login) { + sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or log in at ", backend_host, "\n"); + return 0; + } + local float tftso = TeamFortress_TeamSet_Options(self, tno, FALSE); SetDimensions(TRUE); UpdateAllClientsTeamScores(); From e455edfa4d36a913d2b213e1fdcac68a4d24b336 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 13 Jan 2023 19:37:22 +1100 Subject: [PATCH 1969/2474] Report scores, timeleft and server info --- ssqc/login.qc | 2 +- ssqc/quadmode.qc | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/ssqc/login.qc b/ssqc/login.qc index 7a3a5670..dc3bc05f 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -61,7 +61,7 @@ void(float reqid, float responsecode, string resourcebody, int resourcebytes) UR if (!responsecode) { self.fo_login = resourcebody; CenterPrint(self, sprintf("You have logged in as %s\n", self.fo_login)); - msg = sprintf("%s has logged in as %s\n", infokey(self, "name"), self.fo_login); + msg = sprintf("%s logged in as %s\n", infokey(self, "name"), self.fo_login); bprint(PRINT_HIGH, msg); dprint(msg); } else { diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index fa612515..b83684e0 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -8,7 +8,7 @@ void () PostFOQuadStarted = { data = strcat(data, " \"map\": \"", mapname, "\",\n"); data = strcat(data, " \"server\": {\n"); data = strcat(data, " \"name\": \"", infokey(world, "hostname"), "\",\n"); - data = strcat(data, " \"host\": \"", cvar_string("sv_serverip"), "\"\n"); + data = strcat(data, " \"address\": \"", cvar_string("sv_serverip"), "\"\n"); data = strcat(data, " },\n"); data = strcat(data, " \"discord_channel\": {\n"); data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); @@ -61,11 +61,36 @@ void () PostFOQuadStarted = { void (float winner) PostFOQuadFinished = { local string data = ""; + local entity t = find(world, classname, "round"); + local float timeleft; + if (t != world) { + timeleft = t.cnt * 60 + t.cnt2; + } data = strcat(data, "{\n"); data = strcat(data, " \"match\": {\n"); data = strcat(data, " \"id\": \"", match_id, "\",\n"); - data = strcat(data, " \"winner\": \"", ftos(winner), "\"\n"); + data = strcat(data, " \"winner\": \"", ftos(winner), "\",\n"); + data = strcat(data, " \"timeleft\": \"", ftos(timeleft), "\",\n"); + data = strcat(data, " \"teams\": {\n"); + + local float tn; + local float prefix_comma; + local entity p; + local string token; + + for (tn = 1; tn <= number_of_teams; ++tn) { + local float score = TeamFortress_TeamGetScore(tn); + + data = strcat(data, " \"", ftos(tn), "\": {\n"); + data = strcat(data, " \"score\": \"", ftos(score), "\""); + data = strcat(data, " }"); + + if (tn < number_of_teams) + data = strcat(data, ","); + } + + data = strcat(data, " }\n"); data = strcat(data, " }\n"); data = strcat(data, "}\n"); From 5b8bcdc938d42c1a2122d1afc6941d4516ee685d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 14 Jan 2023 00:11:12 +1100 Subject: [PATCH 1970/2474] Send demo filename to backend --- README.md | 2 +- ssqc/clan.qc | 3 ++- ssqc/client.qc | 7 +++++-- ssqc/login.qc | 2 +- ssqc/quadmode.qc | 9 +++++++-- ssqc/qw.qc | 4 +++- ssqc/tforttm.qc | 2 +- 7 files changed, 20 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ccee57bf..8f584fbf 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ New features * Website backend for match results, stats. Login with discord at https://www.fortressone.org, and `setinfo _fo_token `. * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. -* `localinfo backend_host ` to specify backend API endpoint. Default: https://www.fortressone.org/ +* `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ * All-time attack and all-time defence team options. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 57536b2e..e284cd61 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -318,6 +318,7 @@ void () PreMatch_Think = { localcmd("record \""); str = strzone(GetGameFileName()); + demo_filename = str; localcmd(strzone(str)); localcmd("\"\n"); @@ -1087,7 +1088,7 @@ float () CheckAllPlayersReady = { void () PlayerReady = { if (!self.fo_login && foLoginRequired) { - sprint(self, PRINT_HIGH, "You need to log in to ready up. See ", backend_host, "\n"); + sprint(self, PRINT_HIGH, "You need to log in to ready up. See ", backend_address, "\n"); return; } diff --git a/ssqc/client.qc b/ssqc/client.qc index 219162ac..ae163bd5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -780,7 +780,10 @@ void () DecodeLevelParms = { } // specify API host for backend [""] - backend_host = FO_GetUserSettingString(world, "backend_host", "bh", "https://www.fortressone.org"); + backend_address = FO_GetUserSettingString(world, "backend_address", "backaddy", "https://www.fortressone.org/"); + + // specify demo filehost address e.g. https://fortressone-demos.s3.amazonaws.com/sydney/staging/ + demo_files_address = FO_GetUserSettingString(world, "demo_files_address", "demofileaddy", ""); // enforces API login foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "0"); @@ -3065,7 +3068,7 @@ void () ClientConnect = { if (FO_GetUserSettingString(self, "_fo_token", "fo_token", FALSE)) { stuffcmd(self, "cmd fo-login\n"); } else if (foLoginRequired) { - sprint(self, PRINT_HIGH, "You need to log in to ready up. Update setinfo _fo_token. See ", backend_host, "\n"); + sprint(self, PRINT_HIGH, "You need to log in to ready up. Update setinfo _fo_token. See ", backend_address, "\n"); } if (infokey(self,"*login")) diff --git a/ssqc/login.qc b/ssqc/login.qc index dc3bc05f..fd25cac5 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -14,7 +14,7 @@ void (entity player, string login, string secret) performLogin = { } void (entity player) performFoLogin = { - local string uri = sprintf("%s/results/api/v1/fo_login", backend_host); + local string uri = sprintf("%s/results/api/v1/fo_login", backend_address); local string token = FO_GetUserSettingString(player, "_fo_token", "fo_token", ""); uri_get(uri, FO_LOGIN_REQUEST, "application/json", sprintf("{ \"auth_token\": \"%s\" }", token)); player.login_in_progress = 1; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index b83684e0..604af90e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -6,6 +6,10 @@ void () PostFOQuadStarted = { data = strcat(data, "{\n"); data = strcat(data, " \"match\": {\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); + + local string demo_uri = strcat(demo_files_address, demo_filename); + data = strcat(data, " \"demo_uri\": \"", demo_uri, "\",\n"); + data = strcat(data, " \"server\": {\n"); data = strcat(data, " \"name\": \"", infokey(world, "hostname"), "\",\n"); data = strcat(data, " \"address\": \"", cvar_string("sv_serverip"), "\"\n"); @@ -53,7 +57,7 @@ void () PostFOQuadStarted = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); - local string uri = sprintf("%s/results/api/v1/matches", backend_host); + local string uri = sprintf("%s/results/api/v1/matches", backend_address); uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); /* bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); */ /* bprint(PRINT_HIGH, "data: ", data, "\n"); */ @@ -61,6 +65,7 @@ void () PostFOQuadStarted = { void (float winner) PostFOQuadFinished = { local string data = ""; + local entity t = find(world, classname, "round"); local float timeleft; if (t != world) { @@ -94,7 +99,7 @@ void (float winner) PostFOQuadFinished = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); - local string uri = sprintf("%s/results/api/v1/matches/%s", backend_host, match_id); + local string uri = sprintf("%s/results/api/v1/matches/%s", backend_address, match_id); uri_post(uri, FO_QUAD_FINISHED_REQUEST, "application/json", data); }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a30449fe..9aa12378 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -480,6 +480,7 @@ float vote_anarchy_mode; float vote_total_votes; float vote_style; float vote_threshold; +string demo_filename; .float tf_id; @@ -637,7 +638,8 @@ float nohitsounds; float nokeepcells; float allowpracspawns; string discord_channel_id; -string backend_host; +string backend_address; +string demo_files_address; float splitbackpackmodels; float standardizedeathammo; float deathammo_shells; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 49e9570b..597b02a2 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -296,7 +296,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options float (float tno) TeamFortress_TeamSet = { if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login) { - sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or log in at ", backend_host, "\n"); + sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or log in at ", backend_address, "\n"); return 0; } From ffcec94b99b96e02abaab6ae4c7e6136c8d6c664 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 14 Jan 2023 02:25:37 +1100 Subject: [PATCH 1971/2474] Fix demo link, add stats link --- ssqc/clan.qc | 2 +- ssqc/client.qc | 3 +++ ssqc/quadmode.qc | 5 ++++- ssqc/qw.qc | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index e284cd61..297141b9 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -318,7 +318,7 @@ void () PreMatch_Think = { localcmd("record \""); str = strzone(GetGameFileName()); - demo_filename = str; + game_filename = str; localcmd(strzone(str)); localcmd("\"\n"); diff --git a/ssqc/client.qc b/ssqc/client.qc index ae163bd5..b43109e9 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -785,6 +785,9 @@ void () DecodeLevelParms = { // specify demo filehost address e.g. https://fortressone-demos.s3.amazonaws.com/sydney/staging/ demo_files_address = FO_GetUserSettingString(world, "demo_files_address", "demofileaddy", ""); + // specify stats filehost address e.g. http://fortressone-stats.s3-ap-southeast-2.amazonaws.com/sydney/staging/ + stats_files_address = FO_GetUserSettingString(world, "stats_files_address", "statsfileaddy", ""); + // enforces API login foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "0"); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 604af90e..7fcb0c6e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -7,9 +7,12 @@ void () PostFOQuadStarted = { data = strcat(data, " \"match\": {\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); - local string demo_uri = strcat(demo_files_address, demo_filename); + local string demo_uri = strcat(demo_files_address, game_filename, ".mvd"); data = strcat(data, " \"demo_uri\": \"", demo_uri, "\",\n"); + local string stats_uri = strcat(stats_files_address, game_filename, ".json"); + data = strcat(data, " \"stats_uri\": \"", stats_uri, "\",\n"); + data = strcat(data, " \"server\": {\n"); data = strcat(data, " \"name\": \"", infokey(world, "hostname"), "\",\n"); data = strcat(data, " \"address\": \"", cvar_string("sv_serverip"), "\"\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9aa12378..b0a80b04 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -480,7 +480,8 @@ float vote_anarchy_mode; float vote_total_votes; float vote_style; float vote_threshold; -string demo_filename; +string game_filename; +string stats_filename; .float tf_id; @@ -640,6 +641,7 @@ float allowpracspawns; string discord_channel_id; string backend_address; string demo_files_address; +string stats_files_address; float splitbackpackmodels; float standardizedeathammo; float deathammo_shells; From afbbbae4a4e8bffebca745d08eb8d775d236d2f2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Jan 2023 16:28:20 +1100 Subject: [PATCH 1972/2474] Add login command, default to require login --- csqc/main.qc | 23 +++++++++++++++++++++++ share/defs.h | 1 + ssqc/client.qc | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 694e6c3f..c902785f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -28,6 +28,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { // precache_pic(HudIcons[i].icon); // } + registercommand("login"); registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); registercommand("fo_hud_reset"); @@ -170,6 +171,28 @@ noref float(string cmd) CSQC_ConsoleCommand = { local float grentype; switch(argv(0)) { + case "login": + local string token = argv(1); + local float filehandle; + + if(token == "") { + filehandle = fopen(FO_TOKEN_PATH, FILE_READ); + + if (filehandle == -1) { + print("You need to provide your token\n"); + break; + } else { + token = fgets(filehandle); + } + } else { + filehandle = fopen(FO_TOKEN_PATH, FILE_WRITE); + fputs(filehandle, token); + fclose(filehandle); + } + + localcmd("setinfo _fo_token ", token, "\n"); + localcmd("cmd fo-login\n"); + break; case "fo_hud_editor": FO_Hud_Editor(); break; diff --git a/share/defs.h b/share/defs.h index 7abe179b..da12c301 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1404,6 +1404,7 @@ #define FO_HUD_CONFIG_PATH "fortressone_hud.cfg" #define FO_CONFIG_PATH "fortressone_csqc.cfg" +#define FO_TOKEN_PATH "fortressone_token.cfg" #define HUD_ICON_SIZE_X 24 #define HUD_ICON_SIZE_Y 24 diff --git a/ssqc/client.qc b/ssqc/client.qc index b43109e9..2c362681 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -789,7 +789,7 @@ void () DecodeLevelParms = { stats_files_address = FO_GetUserSettingString(world, "stats_files_address", "statsfileaddy", ""); // enforces API login - foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "0"); + foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "1"); // specify discord channel [""] discord_channel_id = infokey(world, "discord_channel_id"); From 7133f65529f7c87ef3d0927ac44f84c663e460d7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Jan 2023 00:17:59 +1100 Subject: [PATCH 1973/2474] Add client side login logic --- csqc/events.qc | 9 +++++ csqc/main.qc | 95 +++++++++++++++++++++++---------------------- share/commondefs.qc | 1 + ssqc/clan.qc | 2 +- ssqc/client.qc | 7 +--- ssqc/commands.qc | 2 +- ssqc/csmenu.qc | 10 +++++ ssqc/login.qc | 2 +- ssqc/tforttm.qc | 2 +- 9 files changed, 74 insertions(+), 56 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index a0d19166..b53d13c6 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -326,6 +326,15 @@ void() CSQC_Parse_Event = { case MSG_VOTE_MAP_DELETE: RemoveVoteMap(readstring(), FALSE); break; + case MSG_LOGIN: + local float filehandle = fopen(FO_TOKEN_PATH, FILE_READ); + if (filehandle != -1) { + localcmd("setinfo _fo_token ", fgets(filehandle), "\n"); + localcmd("cmd fo-login\n"); + } else { + print("You are not logged in\n"); + } + break; } } diff --git a/csqc/main.qc b/csqc/main.qc index c902785f..e3d4142d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -14,6 +14,7 @@ void ApplyTransparencyToGrenTimer(); void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); +void FoLogin(string token); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -172,26 +173,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { switch(argv(0)) { case "login": - local string token = argv(1); - local float filehandle; - - if(token == "") { - filehandle = fopen(FO_TOKEN_PATH, FILE_READ); - - if (filehandle == -1) { - print("You need to provide your token\n"); - break; - } else { - token = fgets(filehandle); - } - } else { - filehandle = fopen(FO_TOKEN_PATH, FILE_WRITE); - fputs(filehandle, token); - fclose(filehandle); - } - - localcmd("setinfo _fo_token ", token, "\n"); - localcmd("cmd fo-login\n"); + FoLogin(argv(1)); break; case "fo_hud_editor": FO_Hud_Editor(); @@ -374,30 +356,30 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-dropflag": localcmd("-button7\n"); break; - // case "+quick1": - // localcmd("+button8\n"); - // break; - // case "-quick1": - // localcmd("-button8\n"); - // break; - // case "+quick2": - // localcmd("+button9\n"); - // break; - // case "-quick2": - // localcmd("-button9\n"); - // break; - // case "+quick3": - // localcmd("+button10\n"); - // break; - // case "-quick3": - // localcmd("-button10\n"); - // break; - // case "+quick4": - // localcmd("+button11\n"); - // break; - // case "-quick4": - // localcmd("-button11\n"); - // break; + // case "+quick1": + // localcmd("+button8\n"); + // break; + // case "-quick1": + // localcmd("-button8\n"); + // break; + // case "+quick2": + // localcmd("+button9\n"); + // break; + // case "-quick2": + // localcmd("-button9\n"); + // break; + // case "+quick3": + // localcmd("+button10\n"); + // break; + // case "-quick3": + // localcmd("-button10\n"); + // break; + // case "+quick4": + // localcmd("+button11\n"); + // break; + // case "-quick4": + // localcmd("-button11\n"); + // break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { localcmd("+button4\n"); @@ -515,7 +497,7 @@ void _Sync_ServerCommandFrame() { is_observer = FALSE; vector vel = [getstatf(STAT_VELOCITY_X), getstatf(STAT_VELOCITY_Y), - getstatf(STAT_VELOCITY_Z)]; + getstatf(STAT_VELOCITY_Z)]; speed = sqrt(vel.x * vel.x + vel.y * vel.y); local float health = getstatf(STAT_HEALTH); @@ -540,7 +522,7 @@ void _Sync_ClientCommandFrame() { // Client command frames are regenerated beyond the server frame, so we // cannot check that we have not seen this client command frame alone. if (last_servercommandframe == servercommandframe && - last_clientcommandframe == clientcommandframe) + last_clientcommandframe == clientcommandframe) return; last_clientcommandframe = clientcommandframe; } @@ -551,3 +533,24 @@ void Sync_GameState() { _Sync_ServerCommandFrame(); _Sync_ClientCommandFrame(); } + +void FoLogin(string token) { + local float filehandle; + + if (token != "") { + filehandle = fopen(FO_TOKEN_PATH, FILE_WRITE); + fputs(filehandle, token); + fclose(filehandle); + } else { + filehandle = fopen(FO_TOKEN_PATH, FILE_READ); + if (filehandle == -1) { + print("Can't login without valid token\n"); + return; + } else { + token = fgets(filehandle); + } + } + + localcmd("setinfo _fo_token ", token, "\n"); + localcmd("cmd fo-login\n"); +} diff --git a/share/commondefs.qc b/share/commondefs.qc index 7fd07c5a..059afb00 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -33,6 +33,7 @@ #define MSG_VOTE_MAP_DELETE 21 #define MSG_PLAYERDIE 22 #define MSG_QUAD_ROUND_BEGIN 23 +#define MSG_LOGIN 24 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 297141b9..42fde255 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1088,7 +1088,7 @@ float () CheckAllPlayersReady = { void () PlayerReady = { if (!self.fo_login && foLoginRequired) { - sprint(self, PRINT_HIGH, "You need to log in to ready up. See ", backend_address, "\n"); + sprint(self, PRINT_HIGH, "You need to log in to ready up. See fortressone.org\n"); return; } diff --git a/ssqc/client.qc b/ssqc/client.qc index 2c362681..1d22b71a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3068,12 +3068,6 @@ void () ClientConnect = { if (self.netname == string_null) KickCheater(self); - if (FO_GetUserSettingString(self, "_fo_token", "fo_token", FALSE)) { - stuffcmd(self, "cmd fo-login\n"); - } else if (foLoginRequired) { - sprint(self, PRINT_HIGH, "You need to log in to ready up. Update setinfo _fo_token. See ", backend_address, "\n"); - } - if (infokey(self,"*login")) self.login = infokey(self,"*login"); if (infokey(self,"*admin")) @@ -3123,6 +3117,7 @@ void () ClientConnect = { //if(quadmode) UpdateClientPrematch(self, !cb_prematch); UpdateClient_VoteMap_AddAll(self); + UpdateClient_Login(self); } if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 0265346f..9b2fb0d2 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -938,7 +938,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "fo-login": processedCmd = TRUE; if (self.fo_login != string_null) { - sprint (self, PRINT_HIGH, "You are already logged in\n"); + sprint (self, PRINT_HIGH, "You are logged in\n"); } else { performFoLogin(self); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 5ca67ef4..5397157e 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -363,6 +363,16 @@ void UpdateClient_VoteMap_Add(entity pl, entity map_candidate) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClient_Login(entity pl) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_LOGIN); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void() votemap_sender_think = { if (self.owner.vote_map_send) { UpdateClient_VoteMap_Add(self.owner, self.owner.vote_map_send); diff --git a/ssqc/login.qc b/ssqc/login.qc index fd25cac5..5633c330 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -14,10 +14,10 @@ void (entity player, string login, string secret) performLogin = { } void (entity player) performFoLogin = { + player.login_in_progress = 1; local string uri = sprintf("%s/results/api/v1/fo_login", backend_address); local string token = FO_GetUserSettingString(player, "_fo_token", "fo_token", ""); uri_get(uri, FO_LOGIN_REQUEST, "application/json", sprintf("{ \"auth_token\": \"%s\" }", token)); - player.login_in_progress = 1; dprint(sprintf("%s [%s] logging in\n", infokey(player, "name"), infokey(player, "ip"))); } diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 597b02a2..5f0a93e6 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -296,7 +296,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options float (float tno) TeamFortress_TeamSet = { if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login) { - sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or log in at ", backend_address, "\n"); + sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or see fortressone.org\n"); return 0; } From c66e1416a7686085793d89eb4227098e68309db2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Jan 2023 00:27:23 +1100 Subject: [PATCH 1974/2474] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f584fbf..220ad95a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server New features ------ -* Website backend for match results, stats. Login with discord at https://www.fortressone.org, and `setinfo _fo_token `. +* Website backend for match results, stats. Get a token at fortressone.org, connect to a FortressOne server, and `login `. * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ * All-time attack and all-time defence team options. From c429c2a1bc0e5799c22bd8feeab255e5206073a2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Jan 2023 00:31:39 +1100 Subject: [PATCH 1975/2474] Warnings begone --- csqc/events.qc | 7 +++---- ssqc/quadmode.qc | 2 +- ssqc/qw.qc | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index b53d13c6..67770847 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -134,10 +134,6 @@ void() CSQC_Parse_Event = { if(SBAR.GameMode & GAMEMODE_QUAD) { switch (all_time) { - case ALL_TIME_COLOUR: - FO_MENU_TEAM.options[6].state = FO_MENU_STATE_NORMAL; - FO_MENU_TEAM.options[7].state = FO_MENU_STATE_NORMAL; - break; case ALL_TIME_ATTACK: FO_MENU_TEAM.options[6].state = FO_MENU_STATE_DISABLED; FO_MENU_TEAM.options[7].state = FO_MENU_STATE_NORMAL; @@ -146,6 +142,9 @@ void() CSQC_Parse_Event = { FO_MENU_TEAM.options[6].state = FO_MENU_STATE_NORMAL; FO_MENU_TEAM.options[7].state = FO_MENU_STATE_DISABLED; break; + default: + FO_MENU_TEAM.options[6].state = FO_MENU_STATE_NORMAL; + FO_MENU_TEAM.options[7].state = FO_MENU_STATE_NORMAL; } } else { FO_MENU_TEAM.options[6].state = FO_MENU_STATE_DISABLED; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 7fcb0c6e..a6997125 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -70,7 +70,7 @@ void (float winner) PostFOQuadFinished = { local string data = ""; local entity t = find(world, classname, "round"); - local float timeleft; + local float timeleft = 0; if (t != world) { timeleft = t.cnt * 60 + t.cnt2; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index b0a80b04..6b6a96ac 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -481,7 +481,6 @@ float vote_total_votes; float vote_style; float vote_threshold; string game_filename; -string stats_filename; .float tf_id; From fb9298f72b1aade5baaaff399db7a1733e11a3f8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 17 Jan 2023 15:46:28 +1100 Subject: [PATCH 1976/2474] Don't report matches with only one player --- ssqc/quadmode.qc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index a6997125..d7f05ded 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -67,6 +67,9 @@ void () PostFOQuadStarted = { }; void (float winner) PostFOQuadFinished = { + if (!match_id) + return; + local string data = ""; local entity t = find(world, classname, "round"); @@ -597,7 +600,18 @@ void () StartQuadRound = if (rounds > 1){ rounds = (rounds - 1); - if (rounds == 2) + + p = find (world, classname, "player"); + + local float legit_players = 0; + while (p != world) { + if (p.team_no && p.playerclass) + legit_players++; + + p = find(p, classname, "player"); + } + + if (rounds == 2 && legit_players > 1) PostFOQuadStarted(); if (rounds == 1 /* final round */) { From 24f4562314bbcd3111de321a433fccb6a6d27868 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 18 Jan 2023 01:40:49 +1100 Subject: [PATCH 1977/2474] Fix issue with backend_address global not yet being defined when needed after admin menu > map end --- ssqc/client.qc | 5 ++++- ssqc/login.qc | 1 + ssqc/quadmode.qc | 9 ++++++--- ssqc/qw.qc | 1 - 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 1d22b71a..5a990e6e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -780,7 +780,10 @@ void () DecodeLevelParms = { } // specify API host for backend [""] - backend_address = FO_GetUserSettingString(world, "backend_address", "backaddy", "https://www.fortressone.org/"); + // I don't actually call this because it's value is sometimes needed before this code is called. + // Use admin menu to 'end map', DecodeLevelParms() doesn't get called until later. These setting + // globals should probably moved earlier. + /* backend_address = FO_GetUserSettingString(world, "backend_address", "backaddy", "https://www.fortressone.org/"); */ // specify demo filehost address e.g. https://fortressone-demos.s3.amazonaws.com/sydney/staging/ demo_files_address = FO_GetUserSettingString(world, "demo_files_address", "demofileaddy", ""); diff --git a/ssqc/login.qc b/ssqc/login.qc index 5633c330..2607e809 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -15,6 +15,7 @@ void (entity player, string login, string secret) performLogin = { void (entity player) performFoLogin = { player.login_in_progress = 1; + local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/fo_login", backend_address); local string token = FO_GetUserSettingString(player, "_fo_token", "fo_token", ""); uri_get(uri, FO_LOGIN_REQUEST, "application/json", sprintf("{ \"auth_token\": \"%s\" }", token)); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index d7f05ded..3a9f75ce 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -60,6 +60,7 @@ void () PostFOQuadStarted = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); + local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/matches", backend_address); uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); /* bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); */ @@ -105,6 +106,7 @@ void (float winner) PostFOQuadFinished = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); + local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/matches/%s", backend_address, match_id); uri_post(uri, FO_QUAD_FINISHED_REQUEST, "application/json", data); }; @@ -541,10 +543,11 @@ void () StartQuadRound = if (rounds == 1) { while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { + if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { + UpdateClientPrematch(p, TRUE); + } } - if(infokeyf(p, INFOKEY_P_CSQCACTIVE)) { - UpdateClientPrematch(p, TRUE); - } + p = find(p, classname, "player"); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 6b6a96ac..eb43b7fc 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -638,7 +638,6 @@ float nohitsounds; float nokeepcells; float allowpracspawns; string discord_channel_id; -string backend_address; string demo_files_address; string stats_files_address; float splitbackpackmodels; From 1955eaddb59b92ae5d6d585f8f1b52fcea78a449 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 20 Jan 2023 18:13:19 +1100 Subject: [PATCH 1978/2474] zut csqc hitsound/text nfi what im doing --- csqc/csprogs.src | 2 + csqc/events.qc | 120 ++++++++++++++++++++++++++++++++++++++++ csqc/hitfeedback.qc | 68 +++++++++++++++++++++++ csqc/main.qc | 3 +- csqc/settings.qc | 132 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 csqc/hitfeedback.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index 48c655d4..fcf7f83b 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -20,6 +20,7 @@ profile.qc ../share/prediction.qc ../share/classes.qc ../share/animate.qc +../share/mcp_precache.qc weapon_predict.qc pmove.qc tfx.qc @@ -30,6 +31,7 @@ settings.qc menu.qc main.qc events.qc +hitfeedback.qc hud_helpers.qc hud.qc input.qc diff --git a/csqc/events.qc b/csqc/events.qc index c0d7c838..67bdfb1b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,5 +1,6 @@ void ParseSBAR(); void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); +void ParseHitFlag(vector hf_pos, float hf_dmg, float hf); float StartGrenTimer(float primed_at, float expires_at, float grentype, float play_sound); void() CSQC_Parse_Event = { @@ -118,6 +119,15 @@ void() CSQC_Parse_Event = { float explodes_at = readfloat(); TFxGrenTimerUpdate(entnum, explodes_at); break; + case MSG_HITFLAG: + local vector hf_pos = '0 0 0'; + hf_pos_x = readcoord(); + hf_pos_y = readcoord(); + hf_pos_z = readcoord(); + local float hf_dmg = readshort(); + local float hf = readshort(); + ParseHitFlag(hf_pos, hf_dmg, hf); + break; case MSG_CLIENT_MENU: float menutype = readfloat(); switch (menutype) { @@ -436,7 +446,117 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { primed_at, explodes_at, explodes_at - primed_at)); } } +float HitflagThink() = +{ + local float speed = self.min_val * frametime; + local vector htvect = '0 0 0'; + htvect.z = speed; + setorigin(self, self.origin + htvect); + + if(time > self.max_val) + remove(self); + return FALSE; +} +void ParseHitFlag(vector hf_pos, float hf_dmg, float hf) = +{ + local float hittext_allowed = 1; + if(Bitfield_Contains(hf, HITFLAG_NOTEXT) || CVARF(fo_hittext_enabled) == 0) + hittext_allowed = 0; + + local float hitaudio_allowed = 1; + if(Bitfield_Contains(hf, HITFLAG_NOAUDIO) || CVARF(fo_hitaudio_enabled) == 0) + hitaudio_allowed = 0; + + local float hurtself = 0; + local float friendly = 0; + local float killingblow = 0; + local float meatshot = 0; + local float noarmour = 0; + local float headshot = 0; + local float feignedenemy = 0; + + if(Bitfield_Contains(hf, HITFLAG_NOARMOUR)) + noarmour = 1; + + if(Bitfield_Contains(hf, HITFLAG_KILLINGBLOW)) + killingblow = 1; + + if(Bitfield_Contains(hf, HITFLAG_MEATSHOT)) + meatshot = 1; + + if(Bitfield_Contains(hf, HITFLAG_HEADSHOT)) + headshot = 1; + + if(Bitfield_Contains(hf, HITFLAG_SELF)) + hurtself = 1; + + if(Bitfield_Contains(hf, HITFLAG_FRIENDLY)) + friendly = 1; + + if(Bitfield_Contains(hf, HITFLAG_FEIGNEDENEMY)) + feignedenemy = 1; + + if(hitaudio_allowed) + { + //hitsound + if(friendly && !hurtself && !feignedenemy) + localsound(SND_HURTTEAM, CHAN_AUTO, 1); + + else if(hurtself) + localsound(SND_HURTSELF, CHAN_AUTO, 1); + + else + if(!feignedenemy) + meatshot ? localsound(SND_HURTENEMY_MEATSHOT, CHAN_AUTO, 1) : localsound(SND_HURTENEMY, CHAN_AUTO, 1); + + //killsound + if(killingblow) + { + if(friendly && !hurtself) + localsound(SND_KILLTEAM, CHAN_AUTO, 1); + else if(hurtself) + localsound(SND_KILLSELF, CHAN_AUTO, 1); + else + localsound(SND_KILLENEMY, CHAN_AUTO, 1); + + } + } + + if(headshot && !friendly && !feignedenemy) + localsound(SND_HEADSHOT, CHAN_AUTO, 1); + + if(noarmour && !friendly && !feignedenemy) + localsound(SND_NOARMOUR, CHAN_AUTO, 1); + + if(hittext_allowed && !friendly) + { + + + if(feignedenemy && !killingblow) + { + return; + } + else + { + local vector offs = '0 0 0'; + offs_z = CVARF(fo_hittext_offset); + local entity te = spawn(); + local vector pos = '0 0 0'; + pos.x = hf_pos_x; + pos.y = hf_pos_y; + pos.z = hf_pos_z; + setorigin(te, pos + offs); + te.drawmask = MASK_ENGINE; + te.classname = CN_HITTEXT; + te.predraw = HitflagThink; + te.max_val = time + CVARF(fo_hittext_duration); + te.min_val = CVARF(fo_hittext_speed); + te.votecount = hf_dmg; + te.localmap = noarmour; + } + } +}; void ParseSBAR() { SBAR.ClipSize = readstring(); diff --git a/csqc/hitfeedback.qc b/csqc/hitfeedback.qc new file mode 100644 index 00000000..f16b5671 --- /dev/null +++ b/csqc/hitfeedback.qc @@ -0,0 +1,68 @@ +// +static entity hittext_list[40]; // make sure to change # in updatehittextlist count +static int num_hittext_list; +static float next_hittextlist_update; + +static float RenderHitText(entity p) { + const float maxd = 1500, mind = 200; + vector po = p.origin; + vector o = pmove_org; + + //if (p == local_player) + // return FALSE; + + float diff = vlen(po - o); + if (diff > maxd) + return FALSE; + + traceline(o, po, 3, p); + if (trace_fraction < 1) + return FALSE; + + + vector clr = stov(CVARS(fo_hittext_colour)); + if(CVARF(fo_hittext_style) == 2 && p.localmap == 1) + clr = stov(CVARS(fo_hittext_colour2)); + + vector c = project(po); + + + vector size = '0 0 0'; + size_z = CVARF(fo_hittext_size); + size_x = CVARF(fo_hittext_size); + size_y = CVARF(fo_hittext_size); + size = size * (maxd - max(diff, mind)) / (maxd - mind); + string str = ftos(p.votecount); + c.x -= stringwidth(str, FALSE, size) / 2; + drawstring(c, str, size, clr, 1, 0); + + return TRUE; +} + +static void UpdateHitTextList() { + if (time < next_hittextlist_update) + return; + next_hittextlist_update = time + 0.1; + num_hittext_list = 0; + + int count; + entity* hittexts = find_list(classname, CN_HITTEXT, EV_FLOAT, count); + if(count > 40) + count = 40; + for (int j = 0; j < count; j++) + { + entity p = hittexts[j]; + if (RenderHitText(p)) + hittext_list[num_hittext_list++] = p; + } + +} + +void RenderHitTexts() { + UpdateHitTextList(); + + for (int i = 0; i < num_hittext_list; i++) { + entity p = hittext_list[i]; + RenderHitText(p); + } +} diff --git a/csqc/main.qc b/csqc/main.qc index 9ecb4a53..4d296234 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -18,6 +18,7 @@ void FO_Hud_Init(); float InFluid(vector point); float CalculateWaterLevel(); void PlayCSJumpSounds(); +void RenderHitTexts(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -152,7 +153,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); TFxRenderGrenadeTimers(); - + RenderHitTexts(); Hud_UpdateView(width, height, menushown, fts); perf_finish_sample(&frame_timing, fts); diff --git a/csqc/settings.qc b/csqc/settings.qc index 6e6c0e76..8dc214db 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -4,6 +4,24 @@ DEFCVAR_STRING(fo_grentimersound, "grentimer.wav"); DEFCVAR_FLOAT(fo_grentimervolume, 1); DEFCVAR_FLOAT(fo_oldscoreboard, 0); +DEFCVAR_FLOAT(fo_hitaudio_enabled, 1); +DEFCVAR_FLOAT(fo_hitaudio_hurtself, 0); +DEFCVAR_FLOAT(fo_hitaudio_hurtteam, 1); +DEFCVAR_FLOAT(fo_hitaudio_hurtenemy, 1); +DEFCVAR_FLOAT(fo_hitaudio_killself, 1); +DEFCVAR_FLOAT(fo_hitaudio_killteam, 1); +DEFCVAR_FLOAT(fo_hitaudio_killenemy, 1); +DEFCVAR_FLOAT(fo_hitaudio_noarmour, 0); + +DEFCVAR_FLOAT(fo_hittext_enabled, 1); +DEFCVAR_FLOAT(fo_hittext_size, 16); +DEFCVAR_FLOAT(fo_hittext_speed, 96); +DEFCVAR_FLOAT(fo_hittext_duration, 2); +DEFCVAR_FLOAT(fo_hittext_alpha, 1); +DEFCVAR_FLOAT(fo_hittext_style, 1); +DEFCVAR_FLOAT(fo_hittext_offset, 32); +DEFCVAR_STRING(fo_hittext_colour, "1 1 1"); +DEFCVAR_STRING(fo_hittext_colour2, "1 0 1"); // CVARS that just pass via regular config state. DEFCVAR_FLOAT(fo_hud_idle_alpha, 0.3); DEFCVAR_FLOAT(FOCMD_ADMIN_MENU_UPDATE_TIME, 2); @@ -29,6 +47,24 @@ const string FOCMD_GRENTIMERVOLUME = "fo_grentimervolume"; const string FOCMD_JUMPVOLUME = "fo_jumpvolume"; const string FOCMD_ADMIN_MENU_UPDATE_TIME = "fo_adminrefresh"; +const string FOCMD_HITAUDIO_ENABLED = "fo_hitaudio_enabled"; +const string FOCMD_HITAUDIO_HURTSELF = "fo_hitaudio_hurtself"; +const string FOCMD_HITAUDIO_HURTTEAM = "fo_hitaudio_hurtteam"; +const string FOCMD_HITAUDIO_HURTENEMY = "fo_hitaudio_hurtenemy"; +const string FOCMD_HITAUDIO_KILLSELF = "fo_hitaudio_killself"; +const string FOCMD_HITAUDIO_KILLTEAM = "fo_hitaudio_killteam"; +const string FOCMD_HITAUDIO_KILLENEMY = "fo_hitaudio_killenemy"; +const string FOCMD_HITAUDIO_NOARMOUR = "fo_hitaudio_noarmour"; + +const string FOCMD_HITTEXT_ENABLED = "fo_hittext_enabled"; +const string FOCMD_HITTEXT_SIZE = "fo_hittext_size"; +const string FOCMD_HITTEXT_SPEED = "fo_hittext_speed"; +const string FOCMD_HITTEXT_ALPHA = "fo_hittext_alpha"; +const string FOCMD_HITTEXT_DURATION = "fo_hittext_duration"; +const string FOCMD_HITTEXT_STYLE = "fo_hittext_style"; +const string FOCMD_HITTEXT_OFFSET = "fo_hittext_offset"; +const string FOCMD_HITTEXT_COLOUR = "fo_hittext_colour"; +const string FOCMD_HITTEXT_COLOUR2 = "fo_hittext_colour2"; void FO_WriteSettings() { // this overwrites @@ -39,6 +75,25 @@ void FO_WriteSettings() line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, ftos(CVARF(fo_grentimervolume))); line = FormatCfgString(line, FOCMD_JUMPVOLUME, ftos(CVARF(fo_jumpvolume))); line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(CVARF(fo_oldscoreboard))); + + line = FormatCfgString(line, FOCMD_HITAUDIO_ENABLED, ftos(CVARF(fo_hitaudio_enabled))); + line = FormatCfgString(line, FOCMD_HITAUDIO_HURTSELF, ftos(CVARF(fo_hitaudio_hurtself))); + line = FormatCfgString(line, FOCMD_HITAUDIO_HURTTEAM, ftos(CVARF(fo_hitaudio_hurtteam))); + line = FormatCfgString(line, FOCMD_HITAUDIO_HURTENEMY, ftos(CVARF(fo_hitaudio_hurtenemy))); + line = FormatCfgString(line, FOCMD_HITAUDIO_KILLSELF, ftos(CVARF(fo_hitaudio_killself))); + line = FormatCfgString(line, FOCMD_HITAUDIO_KILLTEAM, ftos(CVARF(fo_hitaudio_killteam))); + line = FormatCfgString(line, FOCMD_HITAUDIO_KILLENEMY, ftos(CVARF(fo_hitaudio_killenemy))); + line = FormatCfgString(line, FOCMD_HITAUDIO_NOARMOUR, ftos(CVARF(fo_hitaudio_noarmour))); + + line = FormatCfgString(line, FOCMD_HITTEXT_ENABLED, ftos(CVARF(fo_hittext_enabled))); + line = FormatCfgString(line, FOCMD_HITTEXT_SIZE, ftos(CVARF(fo_hittext_size))); + line = FormatCfgString(line, FOCMD_HITTEXT_SPEED, ftos(CVARF(fo_hittext_speed))); + line = FormatCfgString(line, FOCMD_HITTEXT_DURATION, ftos(CVARF(fo_hittext_duration))); + line = FormatCfgString(line, FOCMD_HITTEXT_ALPHA, ftos(CVARF(fo_hittext_alpha))); + line = FormatCfgString(line, FOCMD_HITTEXT_STYLE, ftos(CVARF(fo_hittext_style))); + line = FormatCfgString(line, FOCMD_HITTEXT_OFFSET, ftos(CVARF(fo_hittext_offset))); + line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR, CVARS(fo_hittext_colour)); + line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR2, CVARS(fo_hittext_colour2)); fputs(filehandle, line); fclose(filehandle); } @@ -50,6 +105,24 @@ void FO_LoadDefaultSettings() CVARF(fo_grentimervolume) = 1; CVARF(fo_jumpvolume) = 1; CVARF(fo_oldscoreboard) = 0; + CVARF(fo_hitaudio_enabled) = 1; + CVARF(fo_hitaudio_hurtself) = 0; + CVARF(fo_hitaudio_hurtteam) = 1; + CVARF(fo_hitaudio_hurtenemy) = 1; + CVARF(fo_hitaudio_killself) = 1; + CVARF(fo_hitaudio_killteam) = 1; + CVARF(fo_hitaudio_killenemy) = 1; + CVARF(fo_hitaudio_noarmour) = 0; + + CVARF(fo_hittext_enabled) = 1; + CVARF(fo_hittext_size) = 16; + CVARF(fo_hittext_speed) = 96; + CVARF(fo_hittext_alpha) = 1; + CVARF(fo_hittext_duration) = 2; + CVARF(fo_hittext_style) = 1; + CVARF(fo_hittext_offset) = 32; + CVARS(fo_hittext_colour) = "1 1 1"; + CVARS(fo_hittext_colour2) = "1 0 1"; } void FO_LoadSettings() @@ -93,6 +166,65 @@ void FO_LoadSettings() case FOCMD_OLDSCOREBOARD: CVARF(fo_oldscoreboard) = stof(val); break; + case FOCMD_HITAUDIO_ENABLED: + CVARF(fo_hitaudio_enabled) = stof(val); + break; + case FOCMD_HITAUDIO_HURTSELF: + CVARF(fo_hitaudio_hurtself) = stof(val); + break; + case FOCMD_HITAUDIO_HURTTEAM: + CVARF(fo_hitaudio_hurtteam) = stof(val); + break; + case FOCMD_HITAUDIO_HURTENEMY: + CVARF(fo_hitaudio_hurtenemy) = stof(val); + break; + case FOCMD_HITAUDIO_KILLSELF: + CVARF(fo_hitaudio_killself) = stof(val); + break; + case FOCMD_HITAUDIO_KILLTEAM: + CVARF(fo_hitaudio_killteam) = stof(val); + break; + case FOCMD_HITAUDIO_KILLENEMY: + CVARF(fo_hitaudio_killenemy) = stof(val); + break; + case FOCMD_HITAUDIO_NOARMOUR: + CVARF(fo_hitaudio_noarmour) = stof(val); + break; + + case FOCMD_HITTEXT_ENABLED: + CVARF(fo_hittext_enabled) = stof(val); + break; + + case FOCMD_HITTEXT_SIZE: + CVARF(fo_hittext_size) = stof(val); + break; + + case FOCMD_HITTEXT_SPEED: + CVARF(fo_hittext_speed) = stof(val); + break; + + case FOCMD_HITTEXT_ALPHA: + CVARF(fo_hittext_alpha) = stof(val); + break; + + case FOCMD_HITTEXT_DURATION: + CVARF(fo_hittext_duration) = stof(val); + break; + + case FOCMD_HITTEXT_STYLE: + CVARF(fo_hittext_style) = stof(val); + break; + + case FOCMD_HITTEXT_OFFSET: + CVARF(fo_hittext_offset) = stof(val); + break; + + case FOCMD_HITTEXT_COLOUR: + CVARS(fo_hittext_colour) = val; + break; + + case FOCMD_HITTEXT_COLOUR2: + CVARS(fo_hittext_colour2) = val; } } ln = fgets(filehandle); From ffea1eb988cc03dfbd138fec5505881baa8ec0c7 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 20 Jan 2023 18:14:44 +1100 Subject: [PATCH 1979/2474] zut csqc hitsound/hittext nfi what im doing --- share/common_helpers.qc | 22 +++++++++++++++++++++- share/commondefs.qc | 12 +++++++++++- share/mcp_precache.qc | 27 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 share/mcp_precache.qc diff --git a/share/common_helpers.qc b/share/common_helpers.qc index 33ac352f..c0ca9ebf 100644 --- a/share/common_helpers.qc +++ b/share/common_helpers.qc @@ -22,4 +22,24 @@ string TeamToString(float num) if (num == 3) return "Yellow"; if (num == 4) return "Green"; return " "; -} \ No newline at end of file +} +float Bitfield_Add (float bf, float b) = +{ + bf = bf | b; + return bf; +}; + +float Bitfield_Remove (float bf, float b) = +{ + bf = bf - (bf & b); + return bf; +}; + +float Bitfield_Contains (float bf, float b) = +{ + if (bf & b) + return 1; + else + return 0; + +}; \ No newline at end of file diff --git a/share/commondefs.qc b/share/commondefs.qc index 79165c5f..734349ff 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -193,7 +193,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_TFX_GRENTIMER 25 #define MSG_QUAD_ROUND_BEGIN 26 #define MSG_LOGIN 27 - +#define MSG_HITFLAG 28 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 #define FLAGINFO_DROPPED 3 @@ -251,3 +251,13 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; // #define BUTTON15 131072 // #define BUTTON16 262144 +#define HITFLAG_NOARMOUR 1 +#define HITFLAG_KILLINGBLOW 2 +#define HITFLAG_MEATSHOT 4 +#define HITFLAG_HEADSHOT 8 +#define HITFLAG_SELF 16 +#define HITFLAG_FRIENDLY 32 +#define HITFLAG_CUSS 64 +#define HITFLAG_FEIGNEDENEMY 128 +#define HITFLAG_NOAUDIO 256 +#define HITFLAG_NOTEXT 512 \ No newline at end of file diff --git a/share/mcp_precache.qc b/share/mcp_precache.qc new file mode 100644 index 00000000..aced0722 --- /dev/null +++ b/share/mcp_precache.qc @@ -0,0 +1,27 @@ +void mcp_Precache() = +{ +#define CN_HITTEXT "hittext" + +#define SND_HURTTEAM "hitaudio/hurtteam.wav" +#define SND_HURTSELF "hitaudio/hurtself.wav" +#define SND_HURTENEMY "hitaudio/hurtenemy.wav" +#define SND_HURTENEMY_MEATSHOT "hitaudio/hurtenemy_meatshot.wav" +precache_sound(SND_HURTTEAM); +precache_sound(SND_HURTSELF); +precache_sound(SND_HURTENEMY); +precache_sound(SND_HURTENEMY_MEATSHOT); + +#define SND_NOARMOUR "hitaudio/noarmour.wav" +precache_sound(SND_NOARMOUR); + +#define SND_KILLTEAM "hitaudio/killteam.wav" +#define SND_KILLSELF "hitaudio/killself.wav" +#define SND_KILLENEMY "hitaudio/killenemy.wav" +precache_sound(SND_KILLTEAM); +precache_sound(SND_KILLSELF); +precache_sound(SND_KILLENEMY); + + +#define SND_HEADSHOT "announcer/headshot.wav" +precache_sound(SND_HEADSHOT); +} \ No newline at end of file From 8de081213cd035106ef287b1f3fcb4edf709b519 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Fri, 20 Jan 2023 18:15:46 +1100 Subject: [PATCH 1980/2474] zut csqc hitsounds/hittext still nfi what im doing --- ssqc/client.qc | 7 ++++ ssqc/combat.qc | 89 ++++++++++++++++++++++++++++++++++++++++++++++++-- ssqc/progs.src | 1 + ssqc/qw.qc | 2 ++ ssqc/world.qc | 1 + 5 files changed, 97 insertions(+), 3 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 35f8bcaa..4c2f0c07 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -796,6 +796,11 @@ void () DecodeLevelParms = { // disable hit sounds [off] nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); + //test zutmode for testing stuff [off] + zutmode = CF_GetSetting("zm", "zutmode", "0"); + + // disable hit text [off] + nohittext = CF_GetSetting("nht", "nohittext", 0); // disable setinfo keepcells [off] nokeepcells = CF_GetSetting("nkc", "nokeepcells", "0"); @@ -1006,6 +1011,8 @@ void () DecodeLevelParms = { stock_reload = FALSE; classtips = FALSE; nohitsounds = TRUE; + nohittext = TRUE; //damned luddites + zutmode = FALSE; detpack_when_reloading = TRUE; old_hp_armor = TRUE; //server_sbflaginfo = FALSE; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 1110c378..6d822134 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -147,10 +147,13 @@ void (entity targ, entity attacker) Killed = { }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { - if(nohitsounds) { + if(nohitsounds) return; - } - + + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + + if(csqcactive && zutmode) + return; if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) @@ -222,6 +225,9 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { void (entity targ, entity attacker) KillSound = { + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if(csqcactive && zutmode) + return; if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) { @@ -268,6 +274,81 @@ void (entity targ, entity attacker) KillSound = { } }; +void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float original_damage, float actual_damage) = +{ + local float hitflag = 0; + local entity trueattacker = attacker; + if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) + { + if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) + { + if (attacker.classname == "building_sentrygun") + trueattacker = attacker.real_owner; + } + } + + local float csqcactive = infokeyf(trueattacker, INFOKEY_P_CSQCACTIVE); + if(!csqcactive) + return; + + + //server allowances -- just baking in hitflag coz im a lazy as + if(nohitsounds) + hitflag = Bitfield_Add(hitflag, HITFLAG_NOAUDIO); + if(nohittext) + hitflag = Bitfield_Add(hitflag, HITFLAG_NOTEXT); + + //no armour left on target -- other games call it "screaming" "cracked" "one shot" etc + if(targ.armorvalue <= 0) + hitflag = Bitfield_Add(hitflag, HITFLAG_NOARMOUR); + + if(targ.health <= 0) + hitflag = Bitfield_Add(hitflag, HITFLAG_KILLINGBLOW); + + //meatshot -- this is very lazy, should do t_missile etc + if( + ((inflictor.weapon == DMSG_ROCKETL) && (original_damage >= 80)) || + ((inflictor.weapon == DMSG_SSHOTGUN) && (original_damage >= 40)) || + ((inflictor.weapon == DMSG_GRENADEL) && (original_damage >= 85)) || + ((inflictor.weapon == DMSG_INCENDIARY) && (original_damage >= 40)) + ) + hitflag = Bitfield_Add(hitflag, HITFLAG_MEATSHOT); + + //headshot + if (deathmsg == DMSG_SNIPERHEADSHOT) + hitflag = Bitfield_Add(hitflag, HITFLAG_HEADSHOT); + + //self + if(trueattacker == targ) + hitflag = Bitfield_Add(hitflag, HITFLAG_SELF); + + //friendly + local float frnd = 0; + if(targ.team_no == trueattacker.team_no) + frnd = 1; + if(targ.undercover_team != 0 && targ.playerclass == PC_SPY && targ.team_no != trueattacker.team_no) + frnd = 1; + + if(frnd) + hitflag = Bitfield_Add(hitflag, HITFLAG_FRIENDLY); + + + //feign + if (targ.playerclass == PC_SPY && targ.is_feigning && targ.team_no != trueattacker.team_no) + hitflag = Bitfield_Add(hitflag, HITFLAG_FEIGNEDENEMY); + + //TODO: cuss - done elsewhere + + msg_entity = trueattacker; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_HITFLAG); + WriteCoord(MSG_MULTICAST, targ.origin.x); + WriteCoord(MSG_MULTICAST, targ.origin.y); + WriteCoord(MSG_MULTICAST, targ.origin.z); + WriteShort(MSG_MULTICAST, actual_damage); + WriteShort(MSG_MULTICAST, hitflag); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); +}; void (entity targ, entity inflictor, entity attacker, float damage, float knock_damage) T_DamageKnock = { local vector dir; @@ -661,6 +742,8 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, targ.armorvalue = 0; } + if(zutmode) + BroadcastHitFlag(targ, inflictor, attacker, original_damage, damh); if (targ.health <= 0) { if ((inflictor.classname == "detpack") diff --git a/ssqc/progs.src b/ssqc/progs.src index 402c71f0..3dddb10f 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -23,6 +23,7 @@ time.qc ../share/prediction.qc ../share/classes.qc ../share/animate.qc +../share/mcp_precache.qc events.qc roles.qc q3defs.qc diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 7a3b8bfd..ab9606cd 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -634,6 +634,8 @@ float fo_repair_ratio; float solid_nailgren; float noreturn; float nohitsounds; +float nohittext; +float zutmode; float nokeepcells; float allowpracspawns; string discord_channel_id; diff --git a/ssqc/world.qc b/ssqc/world.qc index dec019eb..838fcba3 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -147,6 +147,7 @@ void () worldspawn = { Vote_Reset(); W_Precache(); + mcp_Precache(); precache_sound("edge/backpack.wav"); precache_sound("demon/dland2.wav"); precache_sound("misc/h2ohit1.wav"); From 00de67407e4754d5673ced49df990ae28905af73 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sat, 21 Jan 2023 17:41:40 +1100 Subject: [PATCH 1981/2474] csqc hitaudio/hittext nfi --- csqc/csextradefs.qc | 5 +++ csqc/events.qc | 86 +++++++++++++++++++++++++-------------------- csqc/hitfeedback.qc | 29 +++++++++------ csqc/settings.qc | 22 ++++++++---- 4 files changed, 86 insertions(+), 56 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 2cc8d2b9..352fb202 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -117,6 +117,11 @@ float zoomed_in; .float max_val; .float votecount; .float localmap; +.float zut1; //using for random stuff +.float zut2; //using for random stuff +.float zut3; //using for random stuff +.float zut4; //using for random stuff +.float zut5; //using for random stuff void () SUB_Null = { }; diff --git a/csqc/events.qc b/csqc/events.qc index 67bdfb1b..97fd236e 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,6 +1,6 @@ void ParseSBAR(); void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); -void ParseHitFlag(vector hf_pos, float hf_dmg, float hf); +void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag); float StartGrenTimer(float primed_at, float expires_at, float grentype, float play_sound); void() CSQC_Parse_Event = { @@ -119,15 +119,16 @@ void() CSQC_Parse_Event = { float explodes_at = readfloat(); TFxGrenTimerUpdate(entnum, explodes_at); break; - case MSG_HITFLAG: - local vector hf_pos = '0 0 0'; - hf_pos_x = readcoord(); - hf_pos_y = readcoord(); - hf_pos_z = readcoord(); - local float hf_dmg = readshort(); - local float hf = readshort(); - ParseHitFlag(hf_pos, hf_dmg, hf); - break; + case MSG_HITFLAG: + local vector targpos = '0 0 0'; + targpos_x = readcoord(); + targpos_y = readcoord(); + targpos_z = readcoord(); + local float mitdmg = readshort(); + local float rawdmg = readshort(); + local float hitflag = readshort(); + ParseHitFlag(targpos, mitdmg, rawdmg, hitflag); + break; case MSG_CLIENT_MENU: float menutype = readfloat(); switch (menutype) { @@ -448,54 +449,63 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { } float HitflagThink() = { - local float speed = self.min_val * frametime; + local float speed = self.zut4 * frametime; local vector htvect = '0 0 0'; htvect.z = speed; setorigin(self, self.origin + htvect); - if(time > self.max_val) + if(time > self.zut3) remove(self); return FALSE; } -void ParseHitFlag(vector hf_pos, float hf_dmg, float hf) = +void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = { local float hittext_allowed = 1; - if(Bitfield_Contains(hf, HITFLAG_NOTEXT) || CVARF(fo_hittext_enabled) == 0) + if(Bitfield_Contains(hitflag, HITFLAG_NOTEXT) || CVARF(fo_hittext_enabled) == 0) hittext_allowed = 0; local float hitaudio_allowed = 1; - if(Bitfield_Contains(hf, HITFLAG_NOAUDIO) || CVARF(fo_hitaudio_enabled) == 0) + if(Bitfield_Contains(hitflag, HITFLAG_NOAUDIO) || CVARF(fo_hitaudio_enabled) == 0) hitaudio_allowed = 0; local float hurtself = 0; + local float flashed = 0; local float friendly = 0; local float killingblow = 0; local float meatshot = 0; - local float noarmour = 0; + local float noarmourontarg = 0; local float headshot = 0; local float feignedenemy = 0; + local float wantsnoarmoursound = CVARF(fo_hitaudio_noarmour); + local float wantsrawdmg = CVARF(fo_hittext_rawdamage); - if(Bitfield_Contains(hf, HITFLAG_NOARMOUR)) - noarmour = 1; + if(Bitfield_Contains(hitflag, HITFLAG_NOARMOUR)) + noarmourontarg = 1; - if(Bitfield_Contains(hf, HITFLAG_KILLINGBLOW)) + if(Bitfield_Contains(hitflag, HITFLAG_KILLINGBLOW)) killingblow = 1; - if(Bitfield_Contains(hf, HITFLAG_MEATSHOT)) + if(Bitfield_Contains(hitflag, HITFLAG_MEATSHOT)) meatshot = 1; - if(Bitfield_Contains(hf, HITFLAG_HEADSHOT)) + if(Bitfield_Contains(hitflag, HITFLAG_HEADSHOT)) headshot = 1; - if(Bitfield_Contains(hf, HITFLAG_SELF)) + if(Bitfield_Contains(hitflag, HITFLAG_SELF)) hurtself = 1; - if(Bitfield_Contains(hf, HITFLAG_FRIENDLY)) + if(Bitfield_Contains(hitflag, HITFLAG_FRIENDLY)) friendly = 1; - if(Bitfield_Contains(hf, HITFLAG_FEIGNEDENEMY)) + if(Bitfield_Contains(hitflag, HITFLAG_FEIGNEDENEMY)) feignedenemy = 1; + + if(Bitfield_Contains(hitflag, HITFLAG_IMFLASHED)) + flashed = 1; + + if(flashed) + return; if(hitaudio_allowed) { @@ -519,15 +529,14 @@ void ParseHitFlag(vector hf_pos, float hf_dmg, float hf) = localsound(SND_KILLSELF, CHAN_AUTO, 1); else localsound(SND_KILLENEMY, CHAN_AUTO, 1); - } - } - - if(headshot && !friendly && !feignedenemy) - localsound(SND_HEADSHOT, CHAN_AUTO, 1); + + if(headshot && !friendly && !feignedenemy) + localsound(SND_HEADSHOT, CHAN_AUTO, 1); - if(noarmour && !friendly && !feignedenemy) - localsound(SND_NOARMOUR, CHAN_AUTO, 1); + if(noarmourontarg && !friendly && !feignedenemy && wantsnoarmoursound) + localsound(SND_NOARMOUR, CHAN_AUTO, 1); + } if(hittext_allowed && !friendly) { @@ -543,17 +552,18 @@ void ParseHitFlag(vector hf_pos, float hf_dmg, float hf) = offs_z = CVARF(fo_hittext_offset); local entity te = spawn(); local vector pos = '0 0 0'; - pos.x = hf_pos_x; - pos.y = hf_pos_y; - pos.z = hf_pos_z; + pos.x = targpos_x; + pos.y = targpos_y; + pos.z = targpos_z; setorigin(te, pos + offs); te.drawmask = MASK_ENGINE; te.classname = CN_HITTEXT; te.predraw = HitflagThink; - te.max_val = time + CVARF(fo_hittext_duration); - te.min_val = CVARF(fo_hittext_speed); - te.votecount = hf_dmg; - te.localmap = noarmour; + CVARF(fo_hittext_rawdamage) ? te.zut1 = rawdmg : te.zut1 = mitdmg; + te.zut2 = noarmourontarg; + te.zut3 = time + CVARF(fo_hittext_duration); + te.zut4 = CVARF(fo_hittext_speed); + te.zut5 = CVARF(fo_hittext_alpha); } } }; diff --git a/csqc/hitfeedback.qc b/csqc/hitfeedback.qc index f16b5671..a923b3ab 100644 --- a/csqc/hitfeedback.qc +++ b/csqc/hitfeedback.qc @@ -1,40 +1,48 @@ -// static entity hittext_list[40]; // make sure to change # in updatehittextlist count static int num_hittext_list; static float next_hittextlist_update; static float RenderHitText(entity p) { - const float maxd = 1500, mind = 200; + const float maxd = 1500, mind = 0; vector po = p.origin; vector o = pmove_org; - - //if (p == local_player) - // return FALSE; + + vector direc = normalize(po - pmove_org); + makevectors(getviewprop(VF_ANGLES)); + + #define dot(v1, v2) ((vector)v1 * (vector)v2) + float d = dot(v_forward, direc); + #undef dot + + if(d <= 0) + return FALSE; + + if (p == self) + return FALSE; float diff = vlen(po - o); if (diff > maxd) return FALSE; traceline(o, po, 3, p); + if (trace_fraction < 1) return FALSE; - vector clr = stov(CVARS(fo_hittext_colour)); - if(CVARF(fo_hittext_style) == 2 && p.localmap == 1) + if(CVARF(fo_hittext_noarmour) == 2 && p.zut2 == 1) clr = stov(CVARS(fo_hittext_colour2)); vector c = project(po); - vector size = '0 0 0'; size_z = CVARF(fo_hittext_size); size_x = CVARF(fo_hittext_size); size_y = CVARF(fo_hittext_size); size = size * (maxd - max(diff, mind)) / (maxd - mind); - string str = ftos(p.votecount); + string str = ftos(p.zut1); c.x -= stringwidth(str, FALSE, size) / 2; - drawstring(c, str, size, clr, 1, 0); + drawstring(c, str, size, clr, p.zut5, 0); return TRUE; } @@ -55,7 +63,6 @@ static void UpdateHitTextList() { if (RenderHitText(p)) hittext_list[num_hittext_list++] = p; } - } void RenderHitTexts() { diff --git a/csqc/settings.qc b/csqc/settings.qc index 8dc214db..27830cd8 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -18,7 +18,8 @@ DEFCVAR_FLOAT(fo_hittext_size, 16); DEFCVAR_FLOAT(fo_hittext_speed, 96); DEFCVAR_FLOAT(fo_hittext_duration, 2); DEFCVAR_FLOAT(fo_hittext_alpha, 1); -DEFCVAR_FLOAT(fo_hittext_style, 1); +DEFCVAR_FLOAT(fo_hittext_rawdamage, 1); +DEFCVAR_FLOAT(fo_hittext_noarmour, 1); DEFCVAR_FLOAT(fo_hittext_offset, 32); DEFCVAR_STRING(fo_hittext_colour, "1 1 1"); DEFCVAR_STRING(fo_hittext_colour2, "1 0 1"); @@ -54,14 +55,15 @@ const string FOCMD_HITAUDIO_HURTENEMY = "fo_hitaudio_hurtenemy"; const string FOCMD_HITAUDIO_KILLSELF = "fo_hitaudio_killself"; const string FOCMD_HITAUDIO_KILLTEAM = "fo_hitaudio_killteam"; const string FOCMD_HITAUDIO_KILLENEMY = "fo_hitaudio_killenemy"; -const string FOCMD_HITAUDIO_NOARMOUR = "fo_hitaudio_noarmour"; +const string FOCMD_HITAUDIO_NOARMOUR = "fo_hitaudio_noarmour"; const string FOCMD_HITTEXT_ENABLED = "fo_hittext_enabled"; const string FOCMD_HITTEXT_SIZE = "fo_hittext_size"; const string FOCMD_HITTEXT_SPEED = "fo_hittext_speed"; const string FOCMD_HITTEXT_ALPHA = "fo_hittext_alpha"; const string FOCMD_HITTEXT_DURATION = "fo_hittext_duration"; -const string FOCMD_HITTEXT_STYLE = "fo_hittext_style"; +const string FOCMD_HITTEXT_RAWDAMAGE = "fo_hittext_rawdamage"; +const string FOCMD_HITTEXT_NOARMOUR = "fo_hittext_noarmour"; const string FOCMD_HITTEXT_OFFSET = "fo_hittext_offset"; const string FOCMD_HITTEXT_COLOUR = "fo_hittext_colour"; const string FOCMD_HITTEXT_COLOUR2 = "fo_hittext_colour2"; @@ -90,7 +92,8 @@ void FO_WriteSettings() line = FormatCfgString(line, FOCMD_HITTEXT_SPEED, ftos(CVARF(fo_hittext_speed))); line = FormatCfgString(line, FOCMD_HITTEXT_DURATION, ftos(CVARF(fo_hittext_duration))); line = FormatCfgString(line, FOCMD_HITTEXT_ALPHA, ftos(CVARF(fo_hittext_alpha))); - line = FormatCfgString(line, FOCMD_HITTEXT_STYLE, ftos(CVARF(fo_hittext_style))); + line = FormatCfgString(line, FOCMD_HITTEXT_RAWDAMAGE, ftos(CVARF(fo_hittext_rawdamage))); + line = FormatCfgString(line, FOCMD_HITTEXT_NOARMOUR, ftos(CVARF(fo_hittext_noarmour))); line = FormatCfgString(line, FOCMD_HITTEXT_OFFSET, ftos(CVARF(fo_hittext_offset))); line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR, CVARS(fo_hittext_colour)); line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR2, CVARS(fo_hittext_colour2)); @@ -119,7 +122,8 @@ void FO_LoadDefaultSettings() CVARF(fo_hittext_speed) = 96; CVARF(fo_hittext_alpha) = 1; CVARF(fo_hittext_duration) = 2; - CVARF(fo_hittext_style) = 1; + CVARF(fo_hittext_rawdamage) = 1; + CVARF(fo_hittext_noarmour) = 1; CVARF(fo_hittext_offset) = 32; CVARS(fo_hittext_colour) = "1 1 1"; CVARS(fo_hittext_colour2) = "1 0 1"; @@ -211,8 +215,12 @@ void FO_LoadSettings() CVARF(fo_hittext_duration) = stof(val); break; - case FOCMD_HITTEXT_STYLE: - CVARF(fo_hittext_style) = stof(val); + case FOCMD_HITTEXT_RAWDAMAGE: + CVARF(fo_hittext_rawdamage) = stof(val); + break; + + case FOCMD_HITTEXT_NOARMOUR: + CVARF(fo_hittext_noarmour) = stof(val); break; case FOCMD_HITTEXT_OFFSET: From 478843e30fb252e4a4b632ab4601d142f1e09c0d Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sat, 21 Jan 2023 17:42:34 +1100 Subject: [PATCH 1982/2474] csqc hitaudio/hittext nfi --- ssqc/combat.qc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 6d822134..8ceab7de 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -278,19 +278,28 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float orig { local float hitflag = 0; local entity trueattacker = attacker; + local float validtarg = 0; + if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) { + validtarg = 1; + if (attacker.classname == "building_sentrygun") trueattacker = attacker.real_owner; } } + + if(!validtarg) + return; local float csqcactive = infokeyf(trueattacker, INFOKEY_P_CSQCACTIVE); if(!csqcactive) return; - + + if(trueattacker.FlashTime > 0) + return; //server allowances -- just baking in hitflag coz im a lazy as if(nohitsounds) @@ -299,7 +308,7 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float orig hitflag = Bitfield_Add(hitflag, HITFLAG_NOTEXT); //no armour left on target -- other games call it "screaming" "cracked" "one shot" etc - if(targ.armorvalue <= 0) + if(targ.armorvalue <= 0 && targ.classname == "player") hitflag = Bitfield_Add(hitflag, HITFLAG_NOARMOUR); if(targ.health <= 0) @@ -338,6 +347,7 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float orig hitflag = Bitfield_Add(hitflag, HITFLAG_FEIGNEDENEMY); //TODO: cuss - done elsewhere + msg_entity = trueattacker; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); @@ -346,6 +356,7 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float orig WriteCoord(MSG_MULTICAST, targ.origin.y); WriteCoord(MSG_MULTICAST, targ.origin.z); WriteShort(MSG_MULTICAST, actual_damage); + WriteShort(MSG_MULTICAST, original_damage); WriteShort(MSG_MULTICAST, hitflag); multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); }; From c6d056356dd3081fcd46c0ccb82959e510c76d4a Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sat, 21 Jan 2023 17:43:17 +1100 Subject: [PATCH 1983/2474] csqc hitaudio/hittext nfi --- share/commondefs.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 734349ff..811e24d3 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -258,6 +258,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define HITFLAG_SELF 16 #define HITFLAG_FRIENDLY 32 #define HITFLAG_CUSS 64 -#define HITFLAG_FEIGNEDENEMY 128 +#define HITFLAG_FEIGNEDENEMY 128 #define HITFLAG_NOAUDIO 256 -#define HITFLAG_NOTEXT 512 \ No newline at end of file +#define HITFLAG_NOTEXT 512 +#define HITFLAG_IMFLASHED 1024 \ No newline at end of file From bea656f2e48f0b17146ecb7b78450e5822f3e71a Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sat, 21 Jan 2023 18:26:15 +1100 Subject: [PATCH 1984/2474] csqc hitaudio/hittext nfi --- README.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cf53af1..85a7b848 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,35 @@ FortressOne Server New features ------ - +* Added in csqc hitaudio and hittext for testing `localinfo zutmode 1` on server to enable. + + Client commands, default shown: + + === Audio === + `fo_hitaudio_enabled 1' - toggle on/off + `fo_hitaudio_hurtself 0' - play a sound when you hurt yourself + `fo_hitaudio_team 1' - play a sound when you hurt a teammate + `fo_hitaudio_enemy 1' - play a sound when you hurt an enemy + `fo_hitaudio_killself 1` - play a sound when you kill yourself + `fo_hitaudio_killteam 1` - play a sound when you kill a teammate + `fo_hitaudio_killenemy 1` - play a sound when you kill an enemy + `fo_hitaudio_noarmour 0` - play an extra sound if you hurt an enemy with no armour + + also added a headshot sound for snipers, only plays for the client + sounds files are found in `fortress/sound/hitaudio/` and `fortress/sound/announcer/` + + === Text === + 'fo_hittext_enabled 1` - toggle on/off + 'fo_hittext_size 32` - size of text + 'fo_hittext_speed 96` - how fast it scrolls up + 'fo_hittext_alpha 1` - alpha + 'fo_hittext_duration 2` - how long before text disappears + 'fo_hittext_rawdamage 1` - setting to 0 shows damage AFTER armour mitigation + 'fo_hittext_noarmour 1` - changes colour of text if enemy has no armour, see 'fo_hittext_colour2' to set + 'fo_hittext_offset 32` - how high text appears above target + 'fo_hittext_colour "1 1 1"` - default colour of text (rgb 0-1) + 'fo_hittext_colour2 "1 0 1"` - overrides default colour of text if `fo_hittext_noarmour 1` is set and target has no armour + * Website backend for match results, stats. Get a token at fortressone.org, connect to a FortressOne server, and `login `. * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ From 9840b622f6b655a6a9eb05bcce7ff346db7e84cd Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sat, 21 Jan 2023 18:30:55 +1100 Subject: [PATCH 1985/2474] csqc hittext/hitaudio nfi --- README.md | 53 +++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 85a7b848..ff0613d5 100644 --- a/README.md +++ b/README.md @@ -3,35 +3,40 @@ FortressOne Server New features ------ + +--------------------------------- + * Added in csqc hitaudio and hittext for testing `localinfo zutmode 1` on server to enable. - Client commands, default shown: - - === Audio === - `fo_hitaudio_enabled 1' - toggle on/off - `fo_hitaudio_hurtself 0' - play a sound when you hurt yourself - `fo_hitaudio_team 1' - play a sound when you hurt a teammate - `fo_hitaudio_enemy 1' - play a sound when you hurt an enemy - `fo_hitaudio_killself 1` - play a sound when you kill yourself - `fo_hitaudio_killteam 1` - play a sound when you kill a teammate - `fo_hitaudio_killenemy 1` - play a sound when you kill an enemy - `fo_hitaudio_noarmour 0` - play an extra sound if you hurt an enemy with no armour +Client commands, default shown: - also added a headshot sound for snipers, only plays for the client - sounds files are found in `fortress/sound/hitaudio/` and `fortress/sound/announcer/` +=== Audio === +* `fo_hitaudio_enabled 1` - toggle on/off +* `fo_hitaudio_hurtself 0` - play a sound when you hurt yourself +* `fo_hitaudio_team 1` - play a sound when you hurt a teammate +* `fo_hitaudio_enemy 1` - play a sound when you hurt an enemy +* `fo_hitaudio_killself 1` - play a sound when you kill yourself +* `fo_hitaudio_killteam 1` - play a sound when you kill a teammate +* `fo_hitaudio_killenemy 1` - play a sound when you kill an enemy +* `fo_hitaudio_noarmour 0` - play an extra sound if you hurt an enemy with no armour - === Text === - 'fo_hittext_enabled 1` - toggle on/off - 'fo_hittext_size 32` - size of text - 'fo_hittext_speed 96` - how fast it scrolls up - 'fo_hittext_alpha 1` - alpha - 'fo_hittext_duration 2` - how long before text disappears - 'fo_hittext_rawdamage 1` - setting to 0 shows damage AFTER armour mitigation - 'fo_hittext_noarmour 1` - changes colour of text if enemy has no armour, see 'fo_hittext_colour2' to set - 'fo_hittext_offset 32` - how high text appears above target - 'fo_hittext_colour "1 1 1"` - default colour of text (rgb 0-1) - 'fo_hittext_colour2 "1 0 1"` - overrides default colour of text if `fo_hittext_noarmour 1` is set and target has no armour +also added a headshot sound for snipers, only plays for the client +sounds files are found in `fortress/sound/hitaudio/` and `fortress/sound/announcer/` +=== Text === +* `fo_hittext_enabled 1` - toggle on/off +* `fo_hittext_size 32` - size of text +* `fo_hittext_speed 96` - how fast it scrolls up +* `fo_hittext_alpha 1` - alpha +* `fo_hittext_duration 2` - how long before text disappears +* `fo_hittext_rawdamage 1` - setting to 0 shows damage AFTER armour mitigation +* `fo_hittext_noarmour 1` - changes colour of text if enemy has no armour, see 'fo_hittext_colour2' to set +* `fo_hittext_offset 32` - how high text appears above target +* `fo_hittext_colour "1 1 1"` - default colour of text (rgb 0-1) +* `fo_hittext_colour2 "1 0 1"` - overrides default colour of text if `fo_hittext_noarmour 1` is set and target has no armour + +------------------------------- + * Website backend for match results, stats. Get a token at fortressone.org, connect to a FortressOne server, and `login `. * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ From 9b4073133bf6b2012fc252a48fe6b298e8538ad1 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sat, 21 Jan 2023 18:35:59 +1100 Subject: [PATCH 1986/2474] csqc hitaudio/hittext nfi --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ff0613d5..0d4eb50f 100644 --- a/README.md +++ b/README.md @@ -13,27 +13,27 @@ Client commands, default shown: === Audio === * `fo_hitaudio_enabled 1` - toggle on/off * `fo_hitaudio_hurtself 0` - play a sound when you hurt yourself -* `fo_hitaudio_team 1` - play a sound when you hurt a teammate -* `fo_hitaudio_enemy 1` - play a sound when you hurt an enemy +* `fo_hitaudio_hurtteam 1` - play a sound when you hurt a teammate +* `fo_hitaudio_hurtenemy 1` - play a sound when you hurt an enemy * `fo_hitaudio_killself 1` - play a sound when you kill yourself * `fo_hitaudio_killteam 1` - play a sound when you kill a teammate * `fo_hitaudio_killenemy 1` - play a sound when you kill an enemy * `fo_hitaudio_noarmour 0` - play an extra sound if you hurt an enemy with no armour also added a headshot sound for snipers, only plays for the client -sounds files are found in `fortress/sound/hitaudio/` and `fortress/sound/announcer/` +sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announcer/` === Text === * `fo_hittext_enabled 1` - toggle on/off * `fo_hittext_size 32` - size of text -* `fo_hittext_speed 96` - how fast it scrolls up +* `fo_hittext_speed 96` - how fast text scrolls up * `fo_hittext_alpha 1` - alpha * `fo_hittext_duration 2` - how long before text disappears * `fo_hittext_rawdamage 1` - setting to 0 shows damage AFTER armour mitigation -* `fo_hittext_noarmour 1` - changes colour of text if enemy has no armour, see 'fo_hittext_colour2' to set +* `fo_hittext_noarmour 1` - changes colour of text if enemy has no armour, see `fo_hittext_colour2` to set * `fo_hittext_offset 32` - how high text appears above target * `fo_hittext_colour "1 1 1"` - default colour of text (rgb 0-1) -* `fo_hittext_colour2 "1 0 1"` - overrides default colour of text if `fo_hittext_noarmour 1` is set and target has no armour +* `fo_hittext_colour2 "1 0 1"` - overrides default colour of text if `fo_hittext_noarmour 1` is set and target has no armour (rgb 0-1) ------------------------------- From a3ed8cef40fb46686b11d17e248dfcaf16a97fcb Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Sat, 21 Jan 2023 18:55:56 +1100 Subject: [PATCH 1987/2474] csqc hitaudio/hittext nfi --- csqc/hitfeedback.qc | 2 +- csqc/settings.qc | 74 ++++++++++++++++++++------------------------- 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/csqc/hitfeedback.qc b/csqc/hitfeedback.qc index a923b3ab..b7304144 100644 --- a/csqc/hitfeedback.qc +++ b/csqc/hitfeedback.qc @@ -30,7 +30,7 @@ static float RenderHitText(entity p) { return FALSE; vector clr = stov(CVARS(fo_hittext_colour)); - if(CVARF(fo_hittext_noarmour) == 2 && p.zut2 == 1) + if(CVARF(fo_hittext_noarmour) == 1 && p.zut2 == 1) clr = stov(CVARS(fo_hittext_colour2)); vector c = project(po); diff --git a/csqc/settings.qc b/csqc/settings.qc index 27830cd8..480f89e7 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -170,7 +170,7 @@ void FO_LoadSettings() case FOCMD_OLDSCOREBOARD: CVARF(fo_oldscoreboard) = stof(val); break; - case FOCMD_HITAUDIO_ENABLED: + case FOCMD_HITAUDIO_ENABLED: CVARF(fo_hitaudio_enabled) = stof(val); break; case FOCMD_HITAUDIO_HURTSELF: @@ -192,47 +192,37 @@ void FO_LoadSettings() CVARF(fo_hitaudio_killenemy) = stof(val); break; case FOCMD_HITAUDIO_NOARMOUR: - CVARF(fo_hitaudio_noarmour) = stof(val); - break; - - case FOCMD_HITTEXT_ENABLED: - CVARF(fo_hittext_enabled) = stof(val); - break; - - case FOCMD_HITTEXT_SIZE: - CVARF(fo_hittext_size) = stof(val); - break; - - case FOCMD_HITTEXT_SPEED: - CVARF(fo_hittext_speed) = stof(val); - break; - - case FOCMD_HITTEXT_ALPHA: - CVARF(fo_hittext_alpha) = stof(val); - break; - - case FOCMD_HITTEXT_DURATION: - CVARF(fo_hittext_duration) = stof(val); - break; - - case FOCMD_HITTEXT_RAWDAMAGE: - CVARF(fo_hittext_rawdamage) = stof(val); - break; - - case FOCMD_HITTEXT_NOARMOUR: - CVARF(fo_hittext_noarmour) = stof(val); - break; - - case FOCMD_HITTEXT_OFFSET: - CVARF(fo_hittext_offset) = stof(val); - break; - - case FOCMD_HITTEXT_COLOUR: - CVARS(fo_hittext_colour) = val; - break; - - case FOCMD_HITTEXT_COLOUR2: - CVARS(fo_hittext_colour2) = val; + CVARF(fo_hitaudio_noarmour) = stof(val); + break; + case FOCMD_HITTEXT_ENABLED: + CVARF(fo_hittext_enabled) = stof(val); + break; + case FOCMD_HITTEXT_SIZE: + CVARF(fo_hittext_size) = stof(val); + break; + case FOCMD_HITTEXT_SPEED: + CVARF(fo_hittext_speed) = stof(val); + break; + case FOCMD_HITTEXT_ALPHA: + CVARF(fo_hittext_alpha) = stof(val); + break; + case FOCMD_HITTEXT_DURATION: + CVARF(fo_hittext_duration) = stof(val); + break; + case FOCMD_HITTEXT_RAWDAMAGE: + CVARF(fo_hittext_rawdamage) = stof(val); + break; + case FOCMD_HITTEXT_NOARMOUR: + CVARF(fo_hittext_noarmour) = stof(val); + break; + case FOCMD_HITTEXT_OFFSET: + CVARF(fo_hittext_offset) = stof(val); + break; + case FOCMD_HITTEXT_COLOUR: + CVARS(fo_hittext_colour) = val; + break; + case FOCMD_HITTEXT_COLOUR2: + CVARS(fo_hittext_colour2) = val; } } ln = fgets(filehandle); From 4c0d0ea8054b624990ead0c20aab526f0a0484f1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 23 Jan 2023 00:48:17 +1100 Subject: [PATCH 1988/2474] WIP send playerclass --- ssqc/quadmode.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 3a9f75ce..7f614407 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -5,6 +5,7 @@ void () PostFOQuadStarted = { data = strcat(data, "{\n"); data = strcat(data, " \"match\": {\n"); + data = strcat(data, " \"round\": \"1\",\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); local string demo_uri = strcat(demo_files_address, game_filename, ".mvd"); @@ -40,7 +41,10 @@ void () PostFOQuadStarted = { data = strcat(data, ","); token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); - data = strcat(data, " { \"auth_token\": \"", token, "\" }\n"); + data = strcat(data, " {\n"); + data = strcat(data, " \"auth_token\": \"", token, "\",\n"); + data = strcat(data, " \"playerclass\": \"", ftos(p.playerclass), "\"\n"); + data = strcat(data, " }\n"); prefix_comma = TRUE; } From 7d477f8c3596405368206792c621e1c45352fbb5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 23 Jan 2023 01:35:06 +1100 Subject: [PATCH 1989/2474] Add some names to some variables --- csqc/csextradefs.qc | 10 +++++----- csqc/events.qc | 14 +++++++------- csqc/hitfeedback.qc | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 352fb202..d0a46041 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -117,11 +117,11 @@ float zoomed_in; .float max_val; .float votecount; .float localmap; -.float zut1; //using for random stuff -.float zut2; //using for random stuff -.float zut3; //using for random stuff -.float zut4; //using for random stuff -.float zut5; //using for random stuff +.float hittext_damage; //using for random stuff +.float target_armourless; +.float hittext_duration; +.float hittext_speed; +.float hittext_alpha; void () SUB_Null = { }; diff --git a/csqc/events.qc b/csqc/events.qc index 97fd236e..f64e089f 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -449,12 +449,12 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { } float HitflagThink() = { - local float speed = self.zut4 * frametime; + local float speed = self.hittext_speed * frametime; local vector htvect = '0 0 0'; htvect.z = speed; setorigin(self, self.origin + htvect); - if(time > self.zut3) + if(time > self.hittext_duration) remove(self); return FALSE; } @@ -559,11 +559,11 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = te.drawmask = MASK_ENGINE; te.classname = CN_HITTEXT; te.predraw = HitflagThink; - CVARF(fo_hittext_rawdamage) ? te.zut1 = rawdmg : te.zut1 = mitdmg; - te.zut2 = noarmourontarg; - te.zut3 = time + CVARF(fo_hittext_duration); - te.zut4 = CVARF(fo_hittext_speed); - te.zut5 = CVARF(fo_hittext_alpha); + CVARF(fo_hittext_rawdamage) ? te.hittext_damage = rawdmg : te.hittext_damage = mitdmg; + te.target_armourless = noarmourontarg; + te.hittext_duration = time + CVARF(fo_hittext_duration); + te.hittext_speed = CVARF(fo_hittext_speed); + te.hittext_alpha = CVARF(fo_hittext_alpha); } } }; diff --git a/csqc/hitfeedback.qc b/csqc/hitfeedback.qc index b7304144..cf74774f 100644 --- a/csqc/hitfeedback.qc +++ b/csqc/hitfeedback.qc @@ -30,7 +30,7 @@ static float RenderHitText(entity p) { return FALSE; vector clr = stov(CVARS(fo_hittext_colour)); - if(CVARF(fo_hittext_noarmour) == 1 && p.zut2 == 1) + if(CVARF(fo_hittext_noarmour) == 1 && p.target_armourless == 1) clr = stov(CVARS(fo_hittext_colour2)); vector c = project(po); @@ -40,9 +40,9 @@ static float RenderHitText(entity p) { size_x = CVARF(fo_hittext_size); size_y = CVARF(fo_hittext_size); size = size * (maxd - max(diff, mind)) / (maxd - mind); - string str = ftos(p.zut1); + string str = ftos(p.hittext_damage); c.x -= stringwidth(str, FALSE, size) / 2; - drawstring(c, str, size, clr, p.zut5, 0); + drawstring(c, str, size, clr, p.hittext_alpha, 0); return TRUE; } From f192d8b06eb283d5e50c2f42fe80a01837a33e39 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 23 Jan 2023 01:40:42 +1100 Subject: [PATCH 1990/2474] whitespace --- ssqc/client.qc | 12 ++--- ssqc/combat.qc | 123 +++++++++++++++++++++++++------------------------ 2 files changed, 68 insertions(+), 67 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 4c2f0c07..fc787dea 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -795,15 +795,15 @@ void () DecodeLevelParms = { // disable hit sounds [off] nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); - - //test zutmode for testing stuff [off] + + //test zutmode for testing stuff [off] zutmode = CF_GetSetting("zm", "zutmode", "0"); - + // disable hit text [off] nohittext = CF_GetSetting("nht", "nohittext", 0); // disable setinfo keepcells [off] nokeepcells = CF_GetSetting("nkc", "nokeepcells", "0"); - + // allow clients to place a personal practice spawn [off] allowpracspawns = CF_GetSetting("aps", "allowpracspawns", "0"); @@ -1011,8 +1011,8 @@ void () DecodeLevelParms = { stock_reload = FALSE; classtips = FALSE; nohitsounds = TRUE; - nohittext = TRUE; //damned luddites - zutmode = FALSE; + nohittext = TRUE; //damned luddites + zutmode = FALSE; detpack_when_reloading = TRUE; old_hp_armor = TRUE; //server_sbflaginfo = FALSE; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 8ceab7de..9995dca0 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -142,24 +142,23 @@ void (entity targ, entity attacker) Killed = { if(vote_anarchy_mode) { UnvoteForMap(targ); } - - }; void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { if(nohitsounds) return; - - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - - if(csqcactive && zutmode) - return; - if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) + + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + + if(csqcactive && zutmode) + return; + + if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) { local entity trueattacker; - + if (attacker.classname == "building_sentrygun") { // work out correct attacker trueattacker = attacker.real_owner; @@ -168,7 +167,7 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { { trueattacker = attacker; } - + if (trueattacker == targ) { return; @@ -176,7 +175,7 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { local string hitsound; hitsound = infokey(trueattacker, "hitsound"); - + if (hitsound == "1" || hitsound == "2") { local float crit = 0; @@ -204,7 +203,7 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { float targteam; targteam = (targ.undercover_team == 0) ? targ.team_no : targ.undercover_team; - + if (targteam != attacker.team_no) { if (crit == 1){ stuffcmd(trueattacker, "play misc/hitsoundcrit.wav\n"); //sounds precached in weapons.qc @@ -219,59 +218,60 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { } } } - } - } + } + } }; void (entity targ, entity attacker) KillSound = { + local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if(csqcactive && zutmode) - return; - if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { - if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) { - - local entity trueattacker; - if (attacker.classname == "building_sentrygun") { - trueattacker = attacker.real_owner; - } - else { - trueattacker = attacker; - } + if(csqcactive && zutmode) + return; - local string killsound = infokey(trueattacker, "killsound"); + if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { + if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) { - if (killsound == "1" || killsound == "2" || killsound == "3"){ - - if (targ.team_no != trueattacker.team_no) { - stuffcmd(trueattacker, "play misc/killsound.wav\n"); - return; - } - else { - - if (trueattacker == targ) { - if(killsound == "3") { - stuffcmd(trueattacker, "play misc/killsoundteam.wav\n"); - } - return; - } - - if (killsound == "2" || killsound == "3") { - stuffcmd(trueattacker, "play misc/killsoundteam.wav\n"); - } - - } - } - } - } - else { - if (targ.classname == "player") { - local string targkillsound = infokey(targ, "killsound"); - if (targkillsound == "3") { - stuffcmd(targ, "play misc/killsoundteam.wav\n"); - } - } - } + local entity trueattacker; + if (attacker.classname == "building_sentrygun") { + trueattacker = attacker.real_owner; + } + else { + trueattacker = attacker; + } + + local string killsound = infokey(trueattacker, "killsound"); + + if (killsound == "1" || killsound == "2" || killsound == "3"){ + + if (targ.team_no != trueattacker.team_no) { + stuffcmd(trueattacker, "play misc/killsound.wav\n"); + return; + } + else { + + if (trueattacker == targ) { + if(killsound == "3") { + stuffcmd(trueattacker, "play misc/killsoundteam.wav\n"); + } + return; + } + + if (killsound == "2" || killsound == "3") { + stuffcmd(trueattacker, "play misc/killsoundteam.wav\n"); + } + + } + } + } + } + else { + if (targ.classname == "player") { + local string targkillsound = infokey(targ, "killsound"); + if (targkillsound == "3") { + stuffcmd(targ, "play misc/killsoundteam.wav\n"); + } + } + } }; void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float original_damage, float actual_damage) = @@ -753,8 +753,9 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, targ.armorvalue = 0; } - if(zutmode) - BroadcastHitFlag(targ, inflictor, attacker, original_damage, damh); + if(zutmode) + BroadcastHitFlag(targ, inflictor, attacker, original_damage, damh); + if (targ.health <= 0) { if ((inflictor.classname == "detpack") From daa0a450b4eb5b98ce5d7cbfec621cfef6173c8b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 23 Jan 2023 12:47:01 +1100 Subject: [PATCH 1991/2474] Default zutmode on --- ssqc/client.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index fc787dea..6c5730c4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -797,10 +797,11 @@ void () DecodeLevelParms = { nohitsounds = CF_GetSetting("nhs", "nohitsounds", "0"); //test zutmode for testing stuff [off] - zutmode = CF_GetSetting("zm", "zutmode", "0"); + zutmode = CF_GetSetting("zm", "zutmode", "1"); // disable hit text [off] - nohittext = CF_GetSetting("nht", "nohittext", 0); + nohittext = CF_GetSetting("nht", "nohittext", "0"); + // disable setinfo keepcells [off] nokeepcells = CF_GetSetting("nkc", "nokeepcells", "0"); From b260046d8b867d51a261dfa2566dd4c8444cc2af Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 23 Jan 2023 22:58:39 +1100 Subject: [PATCH 1992/2474] hitaudio cvar fix fo_hitaudio_* should work now --- csqc/events.qc | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index f64e089f..38233c75 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -477,9 +477,17 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = local float noarmourontarg = 0; local float headshot = 0; local float feignedenemy = 0; - local float wantsnoarmoursound = CVARF(fo_hitaudio_noarmour); local float wantsrawdmg = CVARF(fo_hittext_rawdamage); + local float wantsnoarmoursound = CVARF(fo_hitaudio_noarmour); + local float wantshurtselfsound = CVARF(fo_hitaudio_hurtself); + local float wantshurtenemysound = CVARF(fo_hitaudio_hurtenemy); + local float wantshurtteamsound = CVARF(fo_hitaudio_hurtteam); + + local float wantskillselfsound = CVARF(fo_hitaudio_killself); + local float wantskillenemysound = CVARF(fo_hitaudio_killenemy); + local float wantskillteamsound = CVARF(fo_hitaudio_killteam); + if(Bitfield_Contains(hitflag, HITFLAG_NOARMOUR)) noarmourontarg = 1; @@ -510,25 +518,32 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = if(hitaudio_allowed) { //hitsound - if(friendly && !hurtself && !feignedenemy) + if(friendly && !hurtself && !feignedenemy && wantshurtteamsound) localsound(SND_HURTTEAM, CHAN_AUTO, 1); - else if(hurtself) + else if(hurtself && wantshurtselfsound) localsound(SND_HURTSELF, CHAN_AUTO, 1); else - if(!feignedenemy) + if(!feignedenemy && wantshurtenemysound) meatshot ? localsound(SND_HURTENEMY_MEATSHOT, CHAN_AUTO, 1) : localsound(SND_HURTENEMY, CHAN_AUTO, 1); //killsound if(killingblow) { - if(friendly && !hurtself) + if(friendly && !hurtself && wantskillteamsound) + { localsound(SND_KILLTEAM, CHAN_AUTO, 1); - else if(hurtself) + } + else if(hurtself && wantskillselfsound) + { localsound(SND_KILLSELF, CHAN_AUTO, 1); + } else - localsound(SND_KILLENEMY, CHAN_AUTO, 1); + { + if(wantskillenemysound) + localsound(SND_KILLENEMY, CHAN_AUTO, 1); + } } if(headshot && !friendly && !feignedenemy) @@ -540,8 +555,6 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = if(hittext_allowed && !friendly) { - - if(feignedenemy && !killingblow) { return; From 479be827480706a97a647a4861e9151526e61944 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 23 Jan 2023 23:38:44 +1100 Subject: [PATCH 1993/2474] wrong audio killing disguised spy fix wrong audio killing disguised spy fix --- ssqc/combat.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 9995dca0..41de3586 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -312,7 +312,11 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float orig hitflag = Bitfield_Add(hitflag, HITFLAG_NOARMOUR); if(targ.health <= 0) + { hitflag = Bitfield_Add(hitflag, HITFLAG_KILLINGBLOW); + if(targ.undercover_team != 0 && targ.playerclass == PC_SPY && targ.team_no != trueattacker.team_no) + hitflag = Bitfield_Add(hitflag, HITFLAG_KILLEDUNDERCOVERSPY); + } //meatshot -- this is very lazy, should do t_missile etc if( From 5769c7ce9743b5fec622a4a691e72e2b14da45a6 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 23 Jan 2023 23:39:26 +1100 Subject: [PATCH 1994/2474] wrong audio killing disguised spy fix wrong audio killing disguised spy fix --- csqc/events.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index 38233c75..e6602c08 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -478,6 +478,7 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = local float headshot = 0; local float feignedenemy = 0; local float wantsrawdmg = CVARF(fo_hittext_rawdamage); + local float killedundercover = Bitfield_Contains(hitflag, HITFLAG_KILLEDUNDERCOVERSPY); local float wantsnoarmoursound = CVARF(fo_hitaudio_noarmour); local float wantshurtselfsound = CVARF(fo_hitaudio_hurtself); @@ -525,13 +526,15 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = localsound(SND_HURTSELF, CHAN_AUTO, 1); else + { if(!feignedenemy && wantshurtenemysound) meatshot ? localsound(SND_HURTENEMY_MEATSHOT, CHAN_AUTO, 1) : localsound(SND_HURTENEMY, CHAN_AUTO, 1); + } //killsound if(killingblow) { - if(friendly && !hurtself && wantskillteamsound) + if(friendly && !hurtself && wantskillteamsound && !killedundercover) { localsound(SND_KILLTEAM, CHAN_AUTO, 1); } From 3a7464de0a6138fa9523b9ee9583a3dd1fbab948 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Mon, 23 Jan 2023 23:39:56 +1100 Subject: [PATCH 1995/2474] wrong audio killing disguised spy fix wrong audio killing disguised spy fix --- share/commondefs.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 811e24d3..f1d9721f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -261,4 +261,6 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define HITFLAG_FEIGNEDENEMY 128 #define HITFLAG_NOAUDIO 256 #define HITFLAG_NOTEXT 512 -#define HITFLAG_IMFLASHED 1024 \ No newline at end of file +#define HITFLAG_IMFLASHED 1024 +#define HITFLAG_KILLEDUNDERCOVERSPY 2048 + \ No newline at end of file From e56d081511af9dcb7140432e0c4e5f0edd2afea6 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Tue, 24 Jan 2023 08:44:02 +1100 Subject: [PATCH 1996/2474] more hitaudio/text fixes more hitaudio/text fixes From 1cf0884333ba4807cdfff350980be44a824e3e1d Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Tue, 24 Jan 2023 08:44:47 +1100 Subject: [PATCH 1997/2474] more hitaudio/text fixes more hitaudio/text fixes --- ssqc/combat.qc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 41de3586..78b48643 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -147,12 +147,7 @@ void (entity targ, entity attacker) Killed = { void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { if(nohitsounds) return; - - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - - if(csqcactive && zutmode) - return; - + if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) @@ -168,10 +163,13 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { trueattacker = attacker; } + local float csqcactive = infokeyf(trueattacker, INFOKEY_P_CSQCACTIVE); + + if(zutmode && csqcactive) + return; + if (trueattacker == targ) - { return; - } local string hitsound; hitsound = infokey(trueattacker, "hitsound"); @@ -223,10 +221,7 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { }; void (entity targ, entity attacker) KillSound = { - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if(csqcactive && zutmode) - return; if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) { if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) { @@ -238,7 +233,11 @@ void (entity targ, entity attacker) KillSound = { else { trueattacker = attacker; } - + + local float csqcactive = infokeyf(trueattacker, INFOKEY_P_CSQCACTIVE); + if(csqcactive && zutmode) + return; + local string killsound = infokey(trueattacker, "killsound"); if (killsound == "1" || killsound == "2" || killsound == "3"){ @@ -362,7 +361,8 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float orig WriteShort(MSG_MULTICAST, actual_damage); WriteShort(MSG_MULTICAST, original_damage); WriteShort(MSG_MULTICAST, hitflag); - multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); + //WriteEntity(MSG_MULTICAST, targ); + multicast('0 0 0', MULTICAST_ONE_R); }; void (entity targ, entity inflictor, entity attacker, float damage, float knock_damage) T_DamageKnock = { From 0b77ac670f0cd12e56adb495321148ea9be86a12 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Tue, 24 Jan 2023 08:46:45 +1100 Subject: [PATCH 1998/2474] more hitaudio/text fixes more hitaudio/text fixes --- csqc/csextradefs.qc | 3 +- csqc/events.qc | 67 +++++++++++++++++++++++++++++++++++---------- csqc/hitfeedback.qc | 17 +++++++++--- csqc/settings.qc | 32 ++++++++++++++++------ 4 files changed, 91 insertions(+), 28 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index d0a46041..9aa18807 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -117,8 +117,9 @@ float zoomed_in; .float max_val; .float votecount; .float localmap; -.float hittext_damage; //using for random stuff +.float hittext_damage; .float target_armourless; +.float target_friendly; .float hittext_duration; .float hittext_speed; .float hittext_alpha; diff --git a/csqc/events.qc b/csqc/events.qc index e6602c08..645e914d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -495,9 +495,10 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = if(Bitfield_Contains(hitflag, HITFLAG_KILLINGBLOW)) killingblow = 1; - if(Bitfield_Contains(hitflag, HITFLAG_MEATSHOT)) + if(Bitfield_Contains(hitflag, HITFLAG_MEATSHOT)) + { meatshot = 1; - + } if(Bitfield_Contains(hitflag, HITFLAG_HEADSHOT)) headshot = 1; @@ -519,33 +520,62 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = if(hitaudio_allowed) { //hitsound - if(friendly && !hurtself && !feignedenemy && wantshurtteamsound) - localsound(SND_HURTTEAM, CHAN_AUTO, 1); - - else if(hurtself && wantshurtselfsound) - localsound(SND_HURTSELF, CHAN_AUTO, 1); - + + if(friendly && !hurtself && !feignedenemy) + { + if(wantshurtteamsound) + { + localsound(SND_HURTTEAM, CHAN_AUTO, 1); + } + } + + else if(hurtself) + { + if(wantshurtselfsound) + { + localsound(SND_HURTSELF, CHAN_AUTO, 1); + } + } + + else if(feignedenemy) + { + feignedenemy = feignedenemy; //do nothing i guess + } + else if(wantshurtenemysound) + { + if(meatshot) + { + localsound(SND_HURTENEMY_MEATSHOT, CHAN_AUTO, 1); + } + else + { + localsound(SND_HURTENEMY, CHAN_AUTO, 1); + } + } else { - if(!feignedenemy && wantshurtenemysound) - meatshot ? localsound(SND_HURTENEMY_MEATSHOT, CHAN_AUTO, 1) : localsound(SND_HURTENEMY, CHAN_AUTO, 1); + feignedenemy = feignedenemy; //do nothing i guess } //killsound if(killingblow) { - if(friendly && !hurtself && wantskillteamsound && !killedundercover) + if(friendly && !hurtself && !killedundercover) { - localsound(SND_KILLTEAM, CHAN_AUTO, 1); + if(wantskillteamsound) + localsound(SND_KILLTEAM, CHAN_AUTO, 1); } - else if(hurtself && wantskillselfsound) + else if(hurtself) { - localsound(SND_KILLSELF, CHAN_AUTO, 1); + if(wantskillselfsound) + localsound(SND_KILLSELF, CHAN_AUTO, 1); } else { if(wantskillenemysound) + { localsound(SND_KILLENEMY, CHAN_AUTO, 1); + } } } @@ -556,7 +586,7 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = localsound(SND_NOARMOUR, CHAN_AUTO, 1); } - if(hittext_allowed && !friendly) + if(hittext_allowed) { if(feignedenemy && !killingblow) { @@ -564,6 +594,9 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = } else { + if(friendly && !CVARF(fo_hittext_friendly) && !feignedenemy) + return; + local vector offs = '0 0 0'; offs_z = CVARF(fo_hittext_offset); local entity te = spawn(); @@ -580,6 +613,10 @@ void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = te.hittext_duration = time + CVARF(fo_hittext_duration); te.hittext_speed = CVARF(fo_hittext_speed); te.hittext_alpha = CVARF(fo_hittext_alpha); + if(feignedenemy) + te.target_friendly = 0; + else + te.target_friendly = friendly; } } }; diff --git a/csqc/hitfeedback.qc b/csqc/hitfeedback.qc index cf74774f..ae5200a6 100644 --- a/csqc/hitfeedback.qc +++ b/csqc/hitfeedback.qc @@ -28,10 +28,19 @@ static float RenderHitText(entity p) { if (trace_fraction < 1) return FALSE; - - vector clr = stov(CVARS(fo_hittext_colour)); - if(CVARF(fo_hittext_noarmour) == 1 && p.target_armourless == 1) - clr = stov(CVARS(fo_hittext_colour2)); + + vector clr = '0 0 0'; + + if(!p.target_friendly) + { + if(CVARF(fo_hittext_noarmour) == 1 && p.target_armourless == 1) + clr = stov(CVARS(fo_hittext_colour2)); + else + clr = stov(CVARS(fo_hittext_colour)); + } + + if(p.target_friendly) + clr = stov(CVARS(fo_hittext_colour3)); vector c = project(po); diff --git a/csqc/settings.qc b/csqc/settings.qc index 480f89e7..8aff3997 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -5,13 +5,13 @@ DEFCVAR_FLOAT(fo_grentimervolume, 1); DEFCVAR_FLOAT(fo_oldscoreboard, 0); DEFCVAR_FLOAT(fo_hitaudio_enabled, 1); -DEFCVAR_FLOAT(fo_hitaudio_hurtself, 0); +DEFCVAR_FLOAT(fo_hitaudio_hurtself, 1); DEFCVAR_FLOAT(fo_hitaudio_hurtteam, 1); DEFCVAR_FLOAT(fo_hitaudio_hurtenemy, 1); DEFCVAR_FLOAT(fo_hitaudio_killself, 1); DEFCVAR_FLOAT(fo_hitaudio_killteam, 1); DEFCVAR_FLOAT(fo_hitaudio_killenemy, 1); -DEFCVAR_FLOAT(fo_hitaudio_noarmour, 0); +DEFCVAR_FLOAT(fo_hitaudio_noarmour, 1); DEFCVAR_FLOAT(fo_hittext_enabled, 1); DEFCVAR_FLOAT(fo_hittext_size, 16); @@ -21,8 +21,10 @@ DEFCVAR_FLOAT(fo_hittext_alpha, 1); DEFCVAR_FLOAT(fo_hittext_rawdamage, 1); DEFCVAR_FLOAT(fo_hittext_noarmour, 1); DEFCVAR_FLOAT(fo_hittext_offset, 32); +DEFCVAR_FLOAT(fo_hittext_friendly, 0); DEFCVAR_STRING(fo_hittext_colour, "1 1 1"); -DEFCVAR_STRING(fo_hittext_colour2, "1 0 1"); +DEFCVAR_STRING(fo_hittext_colour2, "1 0 1"); +DEFCVAR_STRING(fo_hittext_colour3, "1 0 0"); // CVARS that just pass via regular config state. DEFCVAR_FLOAT(fo_hud_idle_alpha, 0.3); DEFCVAR_FLOAT(FOCMD_ADMIN_MENU_UPDATE_TIME, 2); @@ -65,8 +67,11 @@ const string FOCMD_HITTEXT_DURATION = "fo_hittext_duration"; const string FOCMD_HITTEXT_RAWDAMAGE = "fo_hittext_rawdamage"; const string FOCMD_HITTEXT_NOARMOUR = "fo_hittext_noarmour"; const string FOCMD_HITTEXT_OFFSET = "fo_hittext_offset"; +const string FOCMD_HITTEXT_FRIENDLY = "fo_hittext_fiendly"; const string FOCMD_HITTEXT_COLOUR = "fo_hittext_colour"; -const string FOCMD_HITTEXT_COLOUR2 = "fo_hittext_colour2"; +const string FOCMD_HITTEXT_COLOUR2 = "fo_hittext_colour2"; +const string FOCMD_HITTEXT_COLOUR3 = "fo_hittext_colour3"; + void FO_WriteSettings() { // this overwrites @@ -95,8 +100,10 @@ void FO_WriteSettings() line = FormatCfgString(line, FOCMD_HITTEXT_RAWDAMAGE, ftos(CVARF(fo_hittext_rawdamage))); line = FormatCfgString(line, FOCMD_HITTEXT_NOARMOUR, ftos(CVARF(fo_hittext_noarmour))); line = FormatCfgString(line, FOCMD_HITTEXT_OFFSET, ftos(CVARF(fo_hittext_offset))); + line = FormatCfgString(line, FOCMD_HITTEXT_FRIENDLY, ftos(CVARF(fo_hittext_friendly))); line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR, CVARS(fo_hittext_colour)); line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR2, CVARS(fo_hittext_colour2)); + line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR2, CVARS(fo_hittext_colour3)); fputs(filehandle, line); fclose(filehandle); } @@ -109,13 +116,13 @@ void FO_LoadDefaultSettings() CVARF(fo_jumpvolume) = 1; CVARF(fo_oldscoreboard) = 0; CVARF(fo_hitaudio_enabled) = 1; - CVARF(fo_hitaudio_hurtself) = 0; + CVARF(fo_hitaudio_hurtself) = 1; CVARF(fo_hitaudio_hurtteam) = 1; CVARF(fo_hitaudio_hurtenemy) = 1; CVARF(fo_hitaudio_killself) = 1; CVARF(fo_hitaudio_killteam) = 1; CVARF(fo_hitaudio_killenemy) = 1; - CVARF(fo_hitaudio_noarmour) = 0; + CVARF(fo_hitaudio_noarmour) = 1; CVARF(fo_hittext_enabled) = 1; CVARF(fo_hittext_size) = 16; @@ -125,8 +132,10 @@ void FO_LoadDefaultSettings() CVARF(fo_hittext_rawdamage) = 1; CVARF(fo_hittext_noarmour) = 1; CVARF(fo_hittext_offset) = 32; + CVARF(fo_hittext_friendly) = 0; CVARS(fo_hittext_colour) = "1 1 1"; - CVARS(fo_hittext_colour2) = "1 0 1"; + CVARS(fo_hittext_colour2) = "1 0 1"; + CVARS(fo_hittext_colour3) = "1 0 0"; } void FO_LoadSettings() @@ -217,12 +226,19 @@ void FO_LoadSettings() break; case FOCMD_HITTEXT_OFFSET: CVARF(fo_hittext_offset) = stof(val); - break; + break; + case FOCMD_HITTEXT_FRIENDLY: + CVARF(fo_hittext_friendly) = stof(val); + break; case FOCMD_HITTEXT_COLOUR: CVARS(fo_hittext_colour) = val; break; case FOCMD_HITTEXT_COLOUR2: CVARS(fo_hittext_colour2) = val; + break; + case FOCMD_HITTEXT_COLOUR2: + CVARS(fo_hittext_colour3) = val; + break; } } ln = fgets(filehandle); From 25aa552af9d7a4b3d78fd22f307f952f975be982 Mon Sep 17 00:00:00 2001 From: evilantAU <47465476+evilantAU@users.noreply.github.com> Date: Tue, 24 Jan 2023 08:55:21 +1100 Subject: [PATCH 1999/2474] more hitaudio/hittext fixes --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0d4eb50f..e82637fb 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ New features ------ --------------------------------- +* Added in `fo_hittext_friendly 0` - setting to 1 shows text when damaging friendlys +* Added in `fo_hittext_colour3 "1 0 0"` - colour of friendly hittext if fo_hittext_friendly is set to 1 (rgb 0-1) * Added in csqc hitaudio and hittext for testing `localinfo zutmode 1` on server to enable. @@ -12,13 +14,13 @@ Client commands, default shown: === Audio === * `fo_hitaudio_enabled 1` - toggle on/off -* `fo_hitaudio_hurtself 0` - play a sound when you hurt yourself +* `fo_hitaudio_hurtself 1` - play a sound when you hurt yourself * `fo_hitaudio_hurtteam 1` - play a sound when you hurt a teammate * `fo_hitaudio_hurtenemy 1` - play a sound when you hurt an enemy * `fo_hitaudio_killself 1` - play a sound when you kill yourself * `fo_hitaudio_killteam 1` - play a sound when you kill a teammate * `fo_hitaudio_killenemy 1` - play a sound when you kill an enemy -* `fo_hitaudio_noarmour 0` - play an extra sound if you hurt an enemy with no armour +* `fo_hitaudio_noarmour 1` - play an extra sound if you hurt an enemy with no armour also added a headshot sound for snipers, only plays for the client sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announcer/` @@ -32,9 +34,10 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * `fo_hittext_rawdamage 1` - setting to 0 shows damage AFTER armour mitigation * `fo_hittext_noarmour 1` - changes colour of text if enemy has no armour, see `fo_hittext_colour2` to set * `fo_hittext_offset 32` - how high text appears above target -* `fo_hittext_colour "1 1 1"` - default colour of text (rgb 0-1) -* `fo_hittext_colour2 "1 0 1"` - overrides default colour of text if `fo_hittext_noarmour 1` is set and target has no armour (rgb 0-1) - +* `fo_hittext_friendly 0` - toggles text above friendlys if you damage them +* `fo_hittext_colour "1 1 1"` - default colour of enemy text (rgb 0-1) +* `fo_hittext_colour2 "1 0 1"` - overrides default colour of enemy text if `fo_hittext_noarmour 1` is set and target has no armour (rgb 0-1) +* `fo_hittext_colour3 "1 0 0"` - colour of friendly hittext if fo_hittext_friendly is set to 1 (rgb 0-1) ------------------------------- * Website backend for match results, stats. Get a token at fortressone.org, connect to a FortressOne server, and `login `. From 26883eab8a63d0affa4414ade28b4837cf119a4d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 27 Jan 2023 15:43:59 +1100 Subject: [PATCH 2000/2474] WIP: Add half time score update --- ssqc/quadmode.qc | 60 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 7f614407..3fb62e2d 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -67,8 +67,61 @@ void () PostFOQuadStarted = { local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/matches", backend_address); uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); - /* bprint(PRINT_HIGH, "===sending QuadRoundBegin request===\n"); */ - /* bprint(PRINT_HIGH, "data: ", data, "\n"); */ +}; + +void () PostFOQuadFinalRoundStarted = { + local string data = ""; + + data = strcat(data, "{\n"); + data = strcat(data, " \"match\": {\n"); + data = strcat(data, " \"id\": \"", match_id, "\",\n"); + data = strcat(data, " \"round\": \"2\",\n"); + data = strcat(data, " \"teams\": {\n"); + + local float tn; + local float prefix_comma; + local entity p; + local string token; + + for (tn = 1; tn <= number_of_teams; ++tn) { + data = strcat(data, " \"", ftos(tn), "\": {\n"); + data = strcat(data, " \"players\": [\n"); + + prefix_comma = FALSE; + + p = find(world, classname, "player"); + while (p != world) { + if(p.team_no == tn && p.all_time == ALL_TIME_COLOUR) { + if (prefix_comma) + data = strcat(data, ","); + + token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); + data = strcat(data, " {\n"); + data = strcat(data, " \"auth_token\": \"", token, "\",\n"); + data = strcat(data, " \"playerclass\": \"", ftos(p.playerclass), "\"\n"); + data = strcat(data, " }\n"); + prefix_comma = TRUE; + } + + p = find(p, classname, "player"); + } + + data = strcat(data, " ]\n"); + data = strcat(data, " }"); + + if (tn < number_of_teams) + data = strcat(data, ","); + + data = strcat(data, " \n"); + } + + data = strcat(data, " }\n"); + data = strcat(data, " }\n"); + data = strcat(data, "}\n"); + + local string backend_address = infokey(world, "backend_address"); + local string uri = sprintf("%s/results/api/v1/matches/%s", backend_address, match_id); + uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); }; void (float winner) PostFOQuadFinished = { @@ -424,6 +477,9 @@ void () QuadRoundBegin = { bprint(2, "QUAD ROUND BEGINS NOW\n"); + if (rounds == 1) + PostFOQuadFinalRoundStarted(); + te = find(world, classname, "player"); while (te) { if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { From 65f29567ff923989235f6afdd24c2e4bdd5b5ca8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 27 Jan 2023 15:59:33 +1100 Subject: [PATCH 2001/2474] Don't send login beacon if not required --- ssqc/client.qc | 4 ++-- ssqc/csmenu.qc | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5a990e6e..eb252304 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -802,13 +802,13 @@ void () DecodeLevelParms = { // health repair fo_repair_ratio = CF_GetSetting("forep", "fo_repair_ratio", "2"); - + // keep teams on map change [off] cb_keepteams = CF_GetSetting("kt", "keep_teams", "0"); // use att/def roles in quad mode [off] quad_roles = CF_GetSetting("qr", "quad_roles", "0"); - + LoadRole(&Role_Attack); LoadRole(&Role_Defence); InitTeamRoles(); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 5397157e..25b365b2 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -367,6 +367,9 @@ void UpdateClient_Login(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; + if(!foLoginRequired) + return; + msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_LOGIN); From 5d7700f224ef3da3fd9ec33c6b78fa251375d735 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 31 Jan 2023 01:08:57 +1100 Subject: [PATCH 2002/2474] Send round data --- ssqc/quadmode.qc | 7 +++++-- ssqc/tforttm.qc | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 3fb62e2d..584d86b8 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -5,7 +5,7 @@ void () PostFOQuadStarted = { data = strcat(data, "{\n"); data = strcat(data, " \"match\": {\n"); - data = strcat(data, " \"round\": \"1\",\n"); + data = strcat(data, " \"round\": \"", ftos(rounds), "\",\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); local string demo_uri = strcat(demo_files_address, game_filename, ".mvd"); @@ -75,7 +75,7 @@ void () PostFOQuadFinalRoundStarted = { data = strcat(data, "{\n"); data = strcat(data, " \"match\": {\n"); data = strcat(data, " \"id\": \"", match_id, "\",\n"); - data = strcat(data, " \"round\": \"2\",\n"); + data = strcat(data, " \"round\": \"", ftos(rounds), "\",\n"); data = strcat(data, " \"teams\": {\n"); local float tn; @@ -84,7 +84,10 @@ void () PostFOQuadFinalRoundStarted = { local string token; for (tn = 1; tn <= number_of_teams; ++tn) { + local float score = TeamFortress_TeamGetScore(tn); + data = strcat(data, " \"", ftos(tn), "\": {\n"); + data = strcat(data, " \"score\": \"", ftos(score), "\","); data = strcat(data, " \"players\": [\n"); prefix_comma = FALSE; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 5f0a93e6..65543a21 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -241,6 +241,8 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options stuffcmd(pe, st); stuffcmd(pe, "\n"); + UpdateClient_Login(pe); + if(!skipclasscheck) { if(pe.playerclass == PC_CIVILIAN) { if (TeamFortress_TeamIsCivilian(tno)) { From 210036f0871d204b0a1b3bf7b0dc6dc55668ff0b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 2 Feb 2023 23:44:31 +1100 Subject: [PATCH 2003/2474] Complain if teams have uneven number of players --- ssqc/clan.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 42fde255..b7e8ef6b 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1075,14 +1075,18 @@ float () CheckAllPlayersReady = { bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); if (v_ready == f1 && v_ready > 0) { - if(cease_fire) { + if (TeamFortress_TeamGetNoPlayers(1) != TeamFortress_TeamGetNoPlayers(2)) { + bprint (2, "Teams have uneven number of players, is someone supposed to be all-time attack?\n"); + } else if(cease_fire) { bprint (2, "All players ready, match will start after ceasefire ends.\n"); } else { bprint (2, "All players ready, starting match\n"); StartTimer (); } + return 1; } + return 0; } From 144ca6cd55f12a472b6555ed7a0b1d54b1761d57 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 5 Feb 2023 22:46:46 +1100 Subject: [PATCH 2004/2474] Move login to top of PutClientInServer() --- csqc/events.qc | 2 +- csqc/main.qc | 2 +- ssqc/clan.qc | 4 ++-- ssqc/client.qc | 16 +++++++++++----- ssqc/commands.qc | 18 ++++++++++++------ ssqc/login.qc | 2 -- ssqc/tfort.qc | 1 + ssqc/tforttm.qc | 33 ++++++++++++++++++++------------- 8 files changed, 48 insertions(+), 30 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 67770847..24a45ac8 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -329,7 +329,7 @@ void() CSQC_Parse_Event = { local float filehandle = fopen(FO_TOKEN_PATH, FILE_READ); if (filehandle != -1) { localcmd("setinfo _fo_token ", fgets(filehandle), "\n"); - localcmd("cmd fo-login\n"); + localcmd("cmd fo-login-silent\n"); } else { print("You are not logged in\n"); } diff --git a/csqc/main.qc b/csqc/main.qc index e3d4142d..f871052e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -552,5 +552,5 @@ void FoLogin(string token) { } localcmd("setinfo _fo_token ", token, "\n"); - localcmd("cmd fo-login\n"); + localcmd("cmd fo-login-silent\n"); } diff --git a/ssqc/clan.qc b/ssqc/clan.qc index b7e8ef6b..cedbad1e 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1075,7 +1075,7 @@ float () CheckAllPlayersReady = { bprint (PRINT_HIGH, "Total players ready - ",ftos(v_ready),"/",ftos(f1),".\n"); if (v_ready == f1 && v_ready > 0) { - if (TeamFortress_TeamGetNoPlayers(1) != TeamFortress_TeamGetNoPlayers(2)) { + if (TeamFortress_TeamGetNoPlayersExcludingAllTime(1) != TeamFortress_TeamGetNoPlayersExcludingAllTime(2)) { bprint (2, "Teams have uneven number of players, is someone supposed to be all-time attack?\n"); } else if(cease_fire) { bprint (2, "All players ready, match will start after ceasefire ends.\n"); @@ -1091,7 +1091,7 @@ float () CheckAllPlayersReady = { } void () PlayerReady = { - if (!self.fo_login && foLoginRequired) { + if (self.fo_login == string_null && foLoginRequired) { sprint(self, PRINT_HIGH, "You need to log in to ready up. See fortressone.org\n"); return; } diff --git a/ssqc/client.qc b/ssqc/client.qc index 5a990e6e..bb9da4d5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1987,6 +1987,7 @@ void (entity p) SetVoteParams = { p.ammo_rockets = 0; p.ammo_cells = 0; p.armortype = 0; + // why? p.team_no = 0; p.playerclass = 0; p.flags |= FL_ONGROUND; @@ -2077,6 +2078,11 @@ void (float all_dimensions) SetDimensions = { }; void () PutClientInServer = { + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { + if (self.fo_login == string_null && foLoginRequired) + UpdateClient_Login(self); + } + local float oldclass; local entity spot; local entity te; @@ -2129,10 +2135,10 @@ void () PutClientInServer = { setmodel(self, "progs/player.mdl"); modelindex_player = self.modelindex; - if(votemode) { - SetVoteParams(self); - return; - } + // TODO: There's a bug here where self.team_no is set to 0 immediately after joining team + /* if(votemode) { */ + /* SetVoteParams(self); */ + /* } */ if(no_fire_mode) { return; @@ -3120,8 +3126,8 @@ void () ClientConnect = { //if(quadmode) UpdateClientPrematch(self, !cb_prematch); UpdateClient_VoteMap_AddAll(self); - UpdateClient_Login(self); } + if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); }; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 9b2fb0d2..ec8108d0 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -386,6 +386,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; } + if (arg2) { local float final_round = (rounds == 1); @@ -432,6 +433,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { //UpdateClientMenu_Team(self); Menu_Team(0); } + break; case "changeclass": processedCmd = TRUE; @@ -935,20 +937,24 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint (self, PRINT_HIGH, "Missing username/password\n"); } break; + case "login-silent" : + processedCmd = TRUE; + if (arg3 != string_null) { + performLogin(self,arg2,arg3); + } + break; case "fo-login": processedCmd = TRUE; if (self.fo_login != string_null) { sprint (self, PRINT_HIGH, "You are logged in\n"); - } - else { + } else { performFoLogin(self); } break; - case "login-silent" : + case "fo-login-silent": processedCmd = TRUE; - if (arg3 != string_null) { - performLogin(self,arg2,arg3); - } + if (self.fo_login == string_null) + performFoLogin(self); break; case "who": processedCmd = TRUE; diff --git a/ssqc/login.qc b/ssqc/login.qc index 2607e809..e061e425 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -14,7 +14,6 @@ void (entity player, string login, string secret) performLogin = { } void (entity player) performFoLogin = { - player.login_in_progress = 1; local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/fo_login", backend_address); local string token = FO_GetUserSettingString(player, "_fo_token", "fo_token", ""); @@ -56,7 +55,6 @@ void(float reqid, float responsecode, string resourcebody, int resourcebytes) UR break; case FO_LOGIN_REQUEST: - self.login_in_progress = 0; local string msg; if (!responsecode) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 63b2ee6a..853da01d 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -233,6 +233,7 @@ void (float inp) TeamFortress_ChangeClass = { self.immune_to_check = time + 10; return; } + if (teamplay && (self.team_no == 0)) { if (toggleflags & TFLAG_AUTOTEAM) { if (TeamFortress_TeamPutPlayerInTeam() == 0) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 65543a21..08dc6aaf 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -241,8 +241,6 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options stuffcmd(pe, st); stuffcmd(pe, "\n"); - UpdateClient_Login(pe); - if(!skipclasscheck) { if(pe.playerclass == PC_CIVILIAN) { if (TeamFortress_TeamIsCivilian(tno)) { @@ -303,6 +301,7 @@ float (float tno) TeamFortress_TeamSet = { } local float tftso = TeamFortress_TeamSet_Options(self, tno, FALSE); + SetDimensions(TRUE); UpdateAllClientsTeamScores(); UpdateReadyStatus(); @@ -461,24 +460,32 @@ float (float tno) TeamFortress_TeamGetLives = { }; float (float tno) TeamFortress_TeamGetNoPlayers = { - local float size_team; local entity search; - size_team = 0; + local string cn = tno == 0 ? "observer" : "player"; + local float size_team = 0; - search = find(world, classname, "player"); + search = find(world, classname, cn); while (search != world) { if (search.team_no == tno) size_team = size_team + 1; - search = find(search, classname, "player"); + search = find(search, classname, cn); } - if (tno == 0) { - search = find(world, classname, "observer"); - while ((search != world)) { - if (search.team_no == tno) - size_team = size_team + 1; - search = find(search, classname, "observer"); - } + + return (size_team); +}; + +float (float tno) TeamFortress_TeamGetNoPlayersExcludingAllTime = { + local entity search; + local string cn = tno == 0 ? "observer" : "player"; + local float size_team = 0; + + search = find(world, classname, cn); + while (search != world) { + if (search.team_no == tno && search.all_time == ALL_TIME_COLOUR) + size_team = size_team + 1; + search = find(search, classname, cn); } + return (size_team); }; From 55361976a89d307f8d4dfd744147386d95f0e5cc Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 5 Feb 2023 23:36:35 +1100 Subject: [PATCH 2005/2474] Send login beacon at beginning of put client in server --- ssqc/client.qc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index bb9da4d5..8a280ec8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -779,11 +779,15 @@ void () DecodeLevelParms = { loginRequired = 0; } - // specify API host for backend [""] - // I don't actually call this because it's value is sometimes needed before this code is called. + // I don't actually define these because their values are sometimes needed before this code is called. // Use admin menu to 'end map', DecodeLevelParms() doesn't get called until later. These setting // globals should probably moved earlier. - /* backend_address = FO_GetUserSettingString(world, "backend_address", "backaddy", "https://www.fortressone.org/"); */ + + // specify API host for backend [""] + // backend_address = FO_GetUserSettingString(world, "backend_address", "https://www.fortressone.org/"); + + // enforce API login [""] + // foLoginRequired = CF_GetSetting("fologinrequired", "1"); // specify demo filehost address e.g. https://fortressone-demos.s3.amazonaws.com/sydney/staging/ demo_files_address = FO_GetUserSettingString(world, "demo_files_address", "demofileaddy", ""); @@ -791,9 +795,6 @@ void () DecodeLevelParms = { // specify stats filehost address e.g. http://fortressone-stats.s3-ap-southeast-2.amazonaws.com/sydney/staging/ stats_files_address = FO_GetUserSettingString(world, "stats_files_address", "statsfileaddy", ""); - // enforces API login - foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "1"); - // specify discord channel [""] discord_channel_id = infokey(world, "discord_channel_id"); @@ -2078,8 +2079,10 @@ void (float all_dimensions) SetDimensions = { }; void () PutClientInServer = { - if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - if (self.fo_login == string_null && foLoginRequired) + if (self.fo_login == string_null) { + foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "1"); + + if (foLoginRequired) UpdateClient_Login(self); } From bb918e672b7a2e56dbe519a83261ebcde56973b7 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 11 Feb 2023 15:02:50 -0800 Subject: [PATCH 2006/2474] grentimers: add full-rt correction Experimentally on fo_grentimer 3, will replace default fo_grentimer 2 after testing. --- csqc/csextradefs.qc | 3 ++- csqc/events.qc | 13 ++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9aa18807..c7ccb07d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -521,7 +521,8 @@ FO_Hud_Settings HudSettings; enumflags { FL_GT_SOUND, FL_GT_THROWN, - FL_GT_ADJPING + FL_GT_ADJPING, + FL_GT_FULL_RTT, }; void(string identify) Hud_DrawIdentifyPanel; diff --git a/csqc/events.qc b/csqc/events.qc index 0cd2b5c7..5ca8dc6b 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -395,7 +395,7 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, float rtt = pstate_pred.client_ping; if (RewindFlagEnabled(REWIND_GRENADES)) rtt = max(0, rtt - (100 + FO_RewindGrenMs(TF_GREN_conv(_grentype)))); - else + else if ((this.flags_ & FL_GT_FULL_RTT) == 0) rtt /= 2; // Not actually right, but preserve buggy behavior for // now as people are used to it. expires_at_ -= rtt / 1000; @@ -427,8 +427,9 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { switch (CVARF(fo_grentimer)) { case 0: break; case 1: timer_flags = FL_GT_SOUND; break; + case 3: timer_flags = FL_GT_FULL_RTT; // Intentional fall-through. // 2 [and something sane for anything we don't recognize.] - default: timer_flags = FL_GT_SOUND | FL_GT_ADJPING; break; + default: timer_flags |= FL_GT_SOUND | FL_GT_ADJPING; break; } float debug_print_state = CVARF(fo_grentimer_debug) & 1; @@ -439,12 +440,10 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (debug_print_state) { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; - float expires_old = time + 3.8 - ping; - float expires_new = timer.expiry(); - float expires_ideal = explodes_at - ping/2; + float expires_at = timer.expiry(); - print(sprintf("primed_at=%0.2f explodes_at=%0.2f fuse=%0.2f\n", - primed_at, explodes_at, explodes_at - primed_at)); + print(sprintf("primed_at=%0.2f expires_at=%0.2f explodes_at=%0.2f tfuse=%0.2f\n", + primed_at, expires_at, explodes_at, expires_at - primed_at)); } } float HitflagThink() = From ed45ad169f006fa4f62a9d6a2a308077d3363356 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 11 Feb 2023 15:28:22 -0800 Subject: [PATCH 2007/2474] grentimers: add fo_grentimer_nostack Add new grenade timer setting to only play sound for the soonest grenade --- csqc/csextradefs.qc | 25 +++++++++++++++++++++++-- csqc/events.qc | 7 ++++++- csqc/main.qc | 1 + 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c7ccb07d..32462f02 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -708,6 +708,9 @@ void HRC_Render() { drawfill(args->pos, args->size, args->rgb, args->alpha, args->drawflag); } } + +DEFCVAR_FLOAT(fo_grentimer_nostack, 0); + class CsGrenTimer; CsGrenTimer grentimers[NUM_GREN_TIMERS]; @@ -717,6 +720,7 @@ class CsGrenTimer { float expires_at_; float flags_; float grentype_; + float playing_; nonvirtual float() index { return index_; }; nonvirtual float() active { return expires_at_ > time; }; @@ -734,6 +738,7 @@ class CsGrenTimer { nonvirtual void() Stop; nonvirtual void() PauseSound { + playing_ = FALSE; if (flags_ & FL_GT_SOUND) // -volume => stop. soundupdate(this, CHAN_VOICE, "", -1, 0, 0, 0, 0); }; @@ -761,17 +766,33 @@ class CsGrenTimer { static void() SyncPause { // Time froze, but sound kept running, realign. for (float i = 0; i < grentimers.length; i++) - if (grentimers[i].active) + if (grentimers[i].active()) grentimers[i].PauseSound(); }; static void() SyncUnpause { // Time froze, but sound kept running, realign. for (float i = 0; i < grentimers.length; i++) - if (grentimers[i].active) + if (grentimers[i].active()) grentimers[i].StartSound(); }; + static void() UpdateSoundStack { + if (!CVARF(fo_grentimer_nostack)) + return; + + CsGrenTimer best = __NULL__; + + for (float i = 0; i < grentimers.length; i++) { + CsGrenTimer c = grentimers[i]; + if (c.active() && (best == __NULL__ || c.expiry() < best.expiry())) + best = c; + } + + if (best != __NULL__ && !best.playing_) + best.StartSound(); + }; + static CsGrenTimer() GetLast { return last_; }; }; diff --git a/csqc/events.qc b/csqc/events.qc index 5ca8dc6b..d1522184 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -382,6 +382,7 @@ void CsGrenTimer::StartSound() { // Note there's a bug where soundupdate returns false for a new sample, even // though it's started. soundupdate(this, CHAN_VOICE, wav, volume, 0, 0, 0, sound_offset()); + this.playing_ = TRUE; } void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, @@ -390,6 +391,7 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, primed_at_ = primed_at; expires_at_ = expires_at; flags_ = timer_flags; + playing_ = FALSE; if (this.flags_ & FL_GT_ADJPING) { float rtt = pstate_pred.client_ping; @@ -401,7 +403,10 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, expires_at_ -= rtt / 1000; } - StartSound(); + if (!CVARF(fo_grentimer_nostack)) + StartSound(); + else + UpdateSoundStack(); } void CsGrenTimer::Stop() { diff --git a/csqc/main.qc b/csqc/main.qc index 933a016f..668eae4d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -497,6 +497,7 @@ void _Sync_ServerCommandFrame() { is_alive = 1; UpdateMinPing(); + CsGrenTimer::UpdateSoundStack(); } From b2c33405a6cb7fc3b77bd38d0c3560d505c9f1a0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 14 Feb 2023 18:19:15 +1100 Subject: [PATCH 2008/2474] Haze stats are html, not json --- ssqc/quadmode.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 584d86b8..38946462 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -11,7 +11,7 @@ void () PostFOQuadStarted = { local string demo_uri = strcat(demo_files_address, game_filename, ".mvd"); data = strcat(data, " \"demo_uri\": \"", demo_uri, "\",\n"); - local string stats_uri = strcat(stats_files_address, game_filename, ".json"); + local string stats_uri = strcat(stats_files_address, game_filename, ".html"); data = strcat(data, " \"stats_uri\": \"", stats_uri, "\",\n"); data = strcat(data, " \"server\": {\n"); From 6835f2c4f711e3dc8ea8b052d9d8ddeb60a9aa53 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 15 Feb 2023 03:41:12 -0800 Subject: [PATCH 2009/2474] hittext: update and rework - refactor/simplify all of the hittext code - make hittexts appear instantly rather than waiting for next poll - improve performance by a few hundred fps (various: rendering, tracking, etc) - simplify logic in handling of feigned/friendly/etc - fix bugs and create new bugs --- csqc/csextradefs.qc | 10 +- csqc/events.qc | 263 +++++++++++++--------------------------- csqc/hitfeedback.qc | 193 ++++++++++++++++------------- csqc/main.qc | 4 +- csqc/settings.qc | 2 +- share/common_helpers.qc | 20 --- share/commondefs.qc | 28 +++-- ssqc/combat.qc | 177 +++++++++++++-------------- 8 files changed, 299 insertions(+), 398 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 32462f02..63a8974a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -117,12 +117,10 @@ float zoomed_in; .float max_val; .float votecount; .float localmap; -.float hittext_damage; -.float target_armourless; -.float target_friendly; -.float hittext_duration; -.float hittext_speed; -.float hittext_alpha; + +.string hittext_str; +.float hittext_hitflags; +.float hittext_expires; void () SUB_Null = { }; diff --git a/csqc/events.qc b/csqc/events.qc index d1522184..b256476d 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -119,16 +119,16 @@ void() CSQC_Parse_Event = { float explodes_at = readfloat(); TFxGrenTimerUpdate(entnum, explodes_at); break; - case MSG_HITFLAG: - local vector targpos = '0 0 0'; - targpos_x = readcoord(); - targpos_y = readcoord(); + case MSG_HITFLAG: + vector targpos; + targpos_x = readcoord(); + targpos_y = readcoord(); targpos_z = readcoord(); - local float mitdmg = readshort(); - local float rawdmg = readshort(); - local float hitflag = readshort(); - ParseHitFlag(targpos, mitdmg, rawdmg, hitflag); - break; + float mitdmg = readshort(); + float rawdmg = readshort(); + float hitflag = readshort(); + ParseHitFlag(targpos, mitdmg, rawdmg, hitflag); + break; case MSG_CLIENT_MENU: float menutype = readfloat(); switch (menutype) { @@ -451,179 +451,82 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { primed_at, expires_at, explodes_at, expires_at - primed_at)); } } -float HitflagThink() = -{ - local float speed = self.hittext_speed * frametime; - local vector htvect = '0 0 0'; - htvect.z = speed; - setorigin(self, self.origin + htvect); - - if(time > self.hittext_duration) - remove(self); - return FALSE; +#define HITFLAG(_fl_name) (hitflags & (HITFLAG_##_fl_name)) + +static void PlayHitSound(float hitflags) { + float wantsnoarmoursound = CVARF(fo_hitaudio_noarmour); + float wantshurtselfsound = CVARF(fo_hitaudio_hurtself); + float wantshurtenemysound = CVARF(fo_hitaudio_hurtenemy); + float wantshurtteamsound = CVARF(fo_hitaudio_hurtteam); + + float wantskillselfsound = CVARF(fo_hitaudio_killself); + float wantskillenemysound = CVARF(fo_hitaudio_killenemy); + float wantskillteamsound = CVARF(fo_hitaudio_killteam); + + string snd = "", snd2 = ""; + + if (HITFLAG(SELF)) { + if (wantshurtselfsound) + snd = SND_HURTSELF; + if (wantskillselfsound && HITFLAG(KILLINGBLOW)) + snd2 = SND_KILLSELF; + } else if (HITFLAG(FRIENDLY)) { + if (wantshurtteamsound) + snd = SND_HURTTEAM; + if (wantskillteamsound && HITFLAG(KILLINGBLOW)) + snd2 = SND_KILLTEAM; + } else { + if (wantshurtenemysound) + snd = HITFLAG(MEATSHOT) ? SND_HURTENEMY_MEATSHOT : SND_HURTENEMY; + if (wantskillenemysound && HITFLAG(KILLINGBLOW)) + snd2 = SND_KILLENEMY; + + if (HITFLAG(HEADSHOT)) + localsound(SND_HEADSHOT, CHAN_AUTO, 1); + if (HITFLAG(NOARMOUR) && wantsnoarmoursound) + localsound(SND_HEADSHOT, CHAN_AUTO, 1); + } + + if (snd != "") + localsound(snd, CHAN_AUTO, 1); + if (snd2 != "") + localsound(snd2, CHAN_AUTO, 1); } -void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag) = -{ - local float hittext_allowed = 1; - if(Bitfield_Contains(hitflag, HITFLAG_NOTEXT) || CVARF(fo_hittext_enabled) == 0) - hittext_allowed = 0; - - local float hitaudio_allowed = 1; - if(Bitfield_Contains(hitflag, HITFLAG_NOAUDIO) || CVARF(fo_hitaudio_enabled) == 0) - hitaudio_allowed = 0; - - local float hurtself = 0; - local float flashed = 0; - local float friendly = 0; - local float killingblow = 0; - local float meatshot = 0; - local float noarmourontarg = 0; - local float headshot = 0; - local float feignedenemy = 0; - local float wantsrawdmg = CVARF(fo_hittext_rawdamage); - local float killedundercover = Bitfield_Contains(hitflag, HITFLAG_KILLEDUNDERCOVERSPY); - - local float wantsnoarmoursound = CVARF(fo_hitaudio_noarmour); - local float wantshurtselfsound = CVARF(fo_hitaudio_hurtself); - local float wantshurtenemysound = CVARF(fo_hitaudio_hurtenemy); - local float wantshurtteamsound = CVARF(fo_hitaudio_hurtteam); - - local float wantskillselfsound = CVARF(fo_hitaudio_killself); - local float wantskillenemysound = CVARF(fo_hitaudio_killenemy); - local float wantskillteamsound = CVARF(fo_hitaudio_killteam); - - if(Bitfield_Contains(hitflag, HITFLAG_NOARMOUR)) - noarmourontarg = 1; - - if(Bitfield_Contains(hitflag, HITFLAG_KILLINGBLOW)) - killingblow = 1; - - if(Bitfield_Contains(hitflag, HITFLAG_MEATSHOT)) - { - meatshot = 1; - } - if(Bitfield_Contains(hitflag, HITFLAG_HEADSHOT)) - headshot = 1; - - if(Bitfield_Contains(hitflag, HITFLAG_SELF)) - hurtself = 1; - - if(Bitfield_Contains(hitflag, HITFLAG_FRIENDLY)) - friendly = 1; - - if(Bitfield_Contains(hitflag, HITFLAG_FEIGNEDENEMY)) - feignedenemy = 1; - - if(Bitfield_Contains(hitflag, HITFLAG_IMFLASHED)) - flashed = 1; - - if(flashed) - return; - - if(hitaudio_allowed) - { - //hitsound - - if(friendly && !hurtself && !feignedenemy) - { - if(wantshurtteamsound) - { - localsound(SND_HURTTEAM, CHAN_AUTO, 1); - } - } - - else if(hurtself) - { - if(wantshurtselfsound) - { - localsound(SND_HURTSELF, CHAN_AUTO, 1); - } - } - - else if(feignedenemy) - { - feignedenemy = feignedenemy; //do nothing i guess - } - else if(wantshurtenemysound) - { - if(meatshot) - { - localsound(SND_HURTENEMY_MEATSHOT, CHAN_AUTO, 1); - } - else - { - localsound(SND_HURTENEMY, CHAN_AUTO, 1); - } - } - else - { - feignedenemy = feignedenemy; //do nothing i guess - } - - //killsound - if(killingblow) - { - if(friendly && !hurtself && !killedundercover) - { - if(wantskillteamsound) - localsound(SND_KILLTEAM, CHAN_AUTO, 1); - } - else if(hurtself) - { - if(wantskillselfsound) - localsound(SND_KILLSELF, CHAN_AUTO, 1); - } - else - { - if(wantskillenemysound) - { - localsound(SND_KILLENEMY, CHAN_AUTO, 1); - } - } - } - - if(headshot && !friendly && !feignedenemy) - localsound(SND_HEADSHOT, CHAN_AUTO, 1); - - if(noarmourontarg && !friendly && !feignedenemy && wantsnoarmoursound) - localsound(SND_NOARMOUR, CHAN_AUTO, 1); - } - - if(hittext_allowed) - { - if(feignedenemy && !killingblow) - { - return; - } - else - { - if(friendly && !CVARF(fo_hittext_friendly) && !feignedenemy) - return; - - local vector offs = '0 0 0'; - offs_z = CVARF(fo_hittext_offset); - local entity te = spawn(); - local vector pos = '0 0 0'; - pos.x = targpos_x; - pos.y = targpos_y; - pos.z = targpos_z; - setorigin(te, pos + offs); - te.drawmask = MASK_ENGINE; - te.classname = CN_HITTEXT; - te.predraw = HitflagThink; - CVARF(fo_hittext_rawdamage) ? te.hittext_damage = rawdmg : te.hittext_damage = mitdmg; - te.target_armourless = noarmourontarg; - te.hittext_duration = time + CVARF(fo_hittext_duration); - te.hittext_speed = CVARF(fo_hittext_speed); - te.hittext_alpha = CVARF(fo_hittext_alpha); - if(feignedenemy) - te.target_friendly = 0; - else - te.target_friendly = friendly; - } - } -}; +void NewHittext(entity hittext); + +void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflags) { + if (HITFLAG(IMFLASHED)) + return; + + float want_hittext = CVARF(fo_hittext_enabled) && !HITFLAG(NOTEXT); + float want_hitsound = CVARF(fo_hitaudio_enabled) && !HITFLAG(NOAUDIO); + + if (want_hitsound) + PlayHitSound(hitflags); + + if (!want_hittext) + return; + + if (HITFLAG(SELF) || + (HITFLAG(FRIENDLY) && !CVARF(fo_hittext_friendly))) + return; + + entity te = spawn(); + + te.hittext_str = ftos((CVARF(fo_hittext_rawdamage)) ? rawdmg : mitdmg); + te.classname = CN_HITTEXT; + te.hittext_expires = time + CVARF(fo_hittext_duration); + te.hittext_hitflags = hitflags; + + setorigin(te, + [targpos_x, targpos_y, targpos_z + CVARF(fo_hittext_offset)]); + + NewHittext(te); +}; + +#undef HITFLAG + void ParseSBAR() { SBAR.ClipSize = readstring(); diff --git a/csqc/hitfeedback.qc b/csqc/hitfeedback.qc index ae5200a6..760de154 100644 --- a/csqc/hitfeedback.qc +++ b/csqc/hitfeedback.qc @@ -1,84 +1,109 @@ -static entity hittext_list[40]; // make sure to change # in updatehittextlist count -static int num_hittext_list; -static float next_hittextlist_update; - -static float RenderHitText(entity p) { - const float maxd = 1500, mind = 0; - vector po = p.origin; - vector o = pmove_org; - - vector direc = normalize(po - pmove_org); - makevectors(getviewprop(VF_ANGLES)); - - #define dot(v1, v2) ((vector)v1 * (vector)v2) - float d = dot(v_forward, direc); - #undef dot - - if(d <= 0) - return FALSE; - - if (p == self) - return FALSE; - - float diff = vlen(po - o); - if (diff > maxd) - return FALSE; - - traceline(o, po, 3, p); - - if (trace_fraction < 1) - return FALSE; - - vector clr = '0 0 0'; - - if(!p.target_friendly) - { - if(CVARF(fo_hittext_noarmour) == 1 && p.target_armourless == 1) - clr = stov(CVARS(fo_hittext_colour2)); - else - clr = stov(CVARS(fo_hittext_colour)); - } - - if(p.target_friendly) - clr = stov(CVARS(fo_hittext_colour3)); - - vector c = project(po); - - vector size = '0 0 0'; - size_z = CVARF(fo_hittext_size); - size_x = CVARF(fo_hittext_size); - size_y = CVARF(fo_hittext_size); - size = size * (maxd - max(diff, mind)) / (maxd - mind); - string str = ftos(p.hittext_damage); - c.x -= stringwidth(str, FALSE, size) / 2; - drawstring(c, str, size, clr, p.hittext_alpha, 0); - - return TRUE; -} - -static void UpdateHitTextList() { - if (time < next_hittextlist_update) - return; - next_hittextlist_update = time + 0.1; - num_hittext_list = 0; - - int count; - entity* hittexts = find_list(classname, CN_HITTEXT, EV_FLOAT, count); - if(count > 40) - count = 40; - for (int j = 0; j < count; j++) - { - entity p = hittexts[j]; - if (RenderHitText(p)) - hittext_list[num_hittext_list++] = p; - } -} - -void RenderHitTexts() { - UpdateHitTextList(); - - for (int i = 0; i < num_hittext_list; i++) { - entity p = hittext_list[i]; - RenderHitText(p); - } -} +static entity render_hittexts[40]; +static float num_hittexts, num_render; +static float next_render_update; + +static vector clr_noarmour, clr_reg, clr_friendly; + +static void AddRenderableHittext(entity hittext) { + if (num_render < render_hittexts.length) + render_hittexts[num_render++] = hittext; +} + +void NewHittext(entity hittext) { + num_hittexts++; + AddRenderableHittext(hittext); +} + +static void RenderHitText(entity p) { + const float maxd = 1500, mind = 0; + vector po = p.origin; + vector o = pmove_org; + + float rem = p.hittext_expires - time; + po.z += (CVARF(fo_hittext_duration) - rem) * CVARF(fo_hittext_speed); + vector direc = normalize(po - pmove_org); + makevectors(getviewprop(VF_ANGLES)); + + float d = v_forward * direc; + + if(d <= 0 || rem <= 0) + return; + + float diff = vlen(po - o); + if (diff > maxd) + return; + + traceline(o, po, MOVE_NOMONSTERS, p); + if (trace_fraction < 1) + return; + + vector clr; + + if (p.hittext_hitflags & HITFLAG_FRIENDLY) { + clr = clr_friendly; + } else { + if (CVARF(fo_hittext_noarmour) && + (p.hittext_hitflags & HITFLAG_NOARMOUR)) + clr = clr_noarmour; + else + clr = clr_reg; + } + + vector c = project(po); + + vector size = '1 1 1' * CVARF(fo_hittext_size); + size *= (maxd - max(diff, mind)) / (maxd - mind); + + string str = p.hittext_str; + // stringwidth() is technically more correct here, but there's a bunch of + // these and we have to draw them every frame so exploit fixed size font to + // compute inline. + c.x -= strlen(str) * size_x / 2; + + // Fade out + float alpha = CVARF(fo_hittext_alpha); + + float fade_time = max(0.5, CVARF(fo_hittext_alpha) * 0.2); + if (rem < fade_time) + alpha = rem/fade_time * CVARF(fo_hittext_alpha); + + drawstring(c, str, size, clr, alpha, 0); +} + +static void UpdateHitTextList() { + if (time < next_render_update) + return; + + // Convert these periodically + clr_reg = stov(CVARS(fo_hittext_colour)); + clr_noarmour = stov(CVARS(fo_hittext_colour2)); + clr_friendly = stov(CVARS(fo_hittext_colour3)); + + next_render_update = time + 0.1; + num_render = 0; + + int count; + entity* hittexts = find_list(classname, CN_HITTEXT, EV_STRING, count); + + num_hittexts = 0; + for (int i = 0; i < count; i++) { + entity ht = hittexts[i]; + if (time > ht.hittext_expires) { + remove(ht); + continue; + } + + num_hittexts++; + AddRenderableHittext(ht); + } +} + +void RenderHitTexts() { + if (num_hittexts) + UpdateHitTextList(); + + if (CVARF(fo_hittext_enabled)) { + for (int i = 0; i < num_render; i++) + RenderHitText(render_hittexts[i]); + } +} diff --git a/csqc/main.qc b/csqc/main.qc index 668eae4d..a7e42644 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -18,7 +18,7 @@ void FO_Hud_Init(); float InFluid(vector point); float CalculateWaterLevel(); void PlayCSJumpSounds(); -void RenderHitTexts(); +void RenderHitTexts(); void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -153,7 +153,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); TFxRenderGrenadeTimers(); - RenderHitTexts(); + RenderHitTexts(); Hud_UpdateView(width, height, menushown, fts); perf_finish_sample(&frame_timing, fts); diff --git a/csqc/settings.qc b/csqc/settings.qc index 8aff3997..1de98b40 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -135,7 +135,7 @@ void FO_LoadDefaultSettings() CVARF(fo_hittext_friendly) = 0; CVARS(fo_hittext_colour) = "1 1 1"; CVARS(fo_hittext_colour2) = "1 0 1"; - CVARS(fo_hittext_colour3) = "1 0 0"; + CVARS(fo_hittext_colour3) = "1 0 0"; } void FO_LoadSettings() diff --git a/share/common_helpers.qc b/share/common_helpers.qc index c0ca9ebf..66a063a3 100644 --- a/share/common_helpers.qc +++ b/share/common_helpers.qc @@ -23,23 +23,3 @@ string TeamToString(float num) if (num == 4) return "Green"; return " "; } -float Bitfield_Add (float bf, float b) = -{ - bf = bf | b; - return bf; -}; - -float Bitfield_Remove (float bf, float b) = -{ - bf = bf - (bf & b); - return bf; -}; - -float Bitfield_Contains (float bf, float b) = -{ - if (bf & b) - return 1; - else - return 0; - -}; \ No newline at end of file diff --git a/share/commondefs.qc b/share/commondefs.qc index f1d9721f..d50533ec 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -251,16 +251,18 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; // #define BUTTON15 131072 // #define BUTTON16 262144 -#define HITFLAG_NOARMOUR 1 -#define HITFLAG_KILLINGBLOW 2 -#define HITFLAG_MEATSHOT 4 -#define HITFLAG_HEADSHOT 8 -#define HITFLAG_SELF 16 -#define HITFLAG_FRIENDLY 32 -#define HITFLAG_CUSS 64 -#define HITFLAG_FEIGNEDENEMY 128 -#define HITFLAG_NOAUDIO 256 -#define HITFLAG_NOTEXT 512 -#define HITFLAG_IMFLASHED 1024 -#define HITFLAG_KILLEDUNDERCOVERSPY 2048 - \ No newline at end of file +enumflags { + HITFLAG_NOARMOUR, + HITFLAG_KILLINGBLOW, + HITFLAG_MEATSHOT, + HITFLAG_HEADSHOT, + HITFLAG_SELF, + HITFLAG_FRIENDLY, + HITFLAG_CUSS, + HITFLAG_FEIGNEDENEMY, + HITFLAG_NOAUDIO, + HITFLAG_NOTEXT, + HITFLAG_IMFLASHED, + HITFLAG_KILLEDUNDERCOVERSPY, +}; + diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 78b48643..ab46a718 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -273,97 +273,90 @@ void (entity targ, entity attacker) KillSound = { } }; -void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, float original_damage, float actual_damage) = -{ - local float hitflag = 0; - local entity trueattacker = attacker; - local float validtarg = 0; - - if ((attacker.classname == "player") || (attacker.classname == "building_sentrygun") || (attacker.classname == "building_dispenser")) - { - if ((targ.classname == "player") || (targ.classname == "building_sentrygun") || (targ.classname == "building_dispenser")) - { - validtarg = 1; - - if (attacker.classname == "building_sentrygun") - trueattacker = attacker.real_owner; - } - } - - if(!validtarg) - return; - - local float csqcactive = infokeyf(trueattacker, INFOKEY_P_CSQCACTIVE); - if(!csqcactive) - return; - - if(trueattacker.FlashTime > 0) - return; - - //server allowances -- just baking in hitflag coz im a lazy as - if(nohitsounds) - hitflag = Bitfield_Add(hitflag, HITFLAG_NOAUDIO); - if(nohittext) - hitflag = Bitfield_Add(hitflag, HITFLAG_NOTEXT); - - //no armour left on target -- other games call it "screaming" "cracked" "one shot" etc - if(targ.armorvalue <= 0 && targ.classname == "player") - hitflag = Bitfield_Add(hitflag, HITFLAG_NOARMOUR); - - if(targ.health <= 0) - { - hitflag = Bitfield_Add(hitflag, HITFLAG_KILLINGBLOW); - if(targ.undercover_team != 0 && targ.playerclass == PC_SPY && targ.team_no != trueattacker.team_no) - hitflag = Bitfield_Add(hitflag, HITFLAG_KILLEDUNDERCOVERSPY); - } - - //meatshot -- this is very lazy, should do t_missile etc - if( - ((inflictor.weapon == DMSG_ROCKETL) && (original_damage >= 80)) || - ((inflictor.weapon == DMSG_SSHOTGUN) && (original_damage >= 40)) || - ((inflictor.weapon == DMSG_GRENADEL) && (original_damage >= 85)) || - ((inflictor.weapon == DMSG_INCENDIARY) && (original_damage >= 40)) - ) - hitflag = Bitfield_Add(hitflag, HITFLAG_MEATSHOT); - - //headshot - if (deathmsg == DMSG_SNIPERHEADSHOT) - hitflag = Bitfield_Add(hitflag, HITFLAG_HEADSHOT); - - //self - if(trueattacker == targ) - hitflag = Bitfield_Add(hitflag, HITFLAG_SELF); - - //friendly - local float frnd = 0; - if(targ.team_no == trueattacker.team_no) - frnd = 1; - if(targ.undercover_team != 0 && targ.playerclass == PC_SPY && targ.team_no != trueattacker.team_no) - frnd = 1; - - if(frnd) - hitflag = Bitfield_Add(hitflag, HITFLAG_FRIENDLY); - - - //feign - if (targ.playerclass == PC_SPY && targ.is_feigning && targ.team_no != trueattacker.team_no) - hitflag = Bitfield_Add(hitflag, HITFLAG_FEIGNEDENEMY); - - //TODO: cuss - done elsewhere +static inline float valid_hitflag_target(string name) { + return (name == "player" || name == "building_sentrygun" || + name == "building_dispenser"); +} + +void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, + float original_damage, float actual_damage) { + float hitflag = 0; + + if (!valid_hitflag_target(attacker.classname) || + !valid_hitflag_target(targ.classname)) + return; + + if (attacker.classname != "player") + attacker = attacker.real_owner; + + if (!infokeyf(attacker, INFOKEY_P_CSQCACTIVE) || (attacker.tfstate & TFSTATE_FLASHED)) + return; + + // Feigned spies act as corpses unless they're a teammate + if (targ.playerclass == PC_SPY && targ.is_feigning && targ.health > 0 && + targ.team_no != attacker.team_no) + return; + + // server allowances -- just baking in hitflag coz im a lazy as + if(nohitsounds) + hitflag |= HITFLAG_NOAUDIO; + if(nohittext) + hitflag |= HITFLAG_NOTEXT; + + // no armour left on target -- other games call it "screaming" "cracked" "one shot" etc + if(targ.armorvalue <= 0 && targ.classname == "player") + hitflag |= HITFLAG_NOARMOUR; + + // friendly + if ((targ.team_no == attacker.team_no) || + (targ.playerclass == PC_SPY && targ.undercover_team == attacker.team_no)) + hitflag |= HITFLAG_FRIENDLY; + + // kill + if(targ.health <= 0) { + hitflag |= HITFLAG_KILLINGBLOW; + + if (targ.playerclass == PC_SPY) { + if (targ.undercover_team != 0 && targ.team_no != attacker.team_no) { + hitflag |= HITFLAG_KILLEDUNDERCOVERSPY; + hitflag &= ~HITFLAG_FRIENDLY; + } + if (targ.is_feigning) + hitflag |= HITFLAG_FEIGNEDENEMY; + } + } + + // meatshot -- this is very lazy, should do t_missile etc + if (((inflictor.weapon == DMSG_ROCKETL) && (original_damage >= 80)) || + ((inflictor.weapon == DMSG_SSHOTGUN) && (original_damage >= 40)) || + ((inflictor.weapon == DMSG_GRENADEL) && (original_damage >= 85)) || + ((inflictor.weapon == DMSG_INCENDIARY) && (original_damage >= 40))) + hitflag |= HITFLAG_MEATSHOT; + + // headshot + if (deathmsg == DMSG_SNIPERHEADSHOT) + hitflag |= HITFLAG_HEADSHOT; + + // self + if (attacker == targ) + hitflag |= HITFLAG_SELF; + + // TODO: cuss - done elsewhere + + msg_entity = attacker; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_HITFLAG); + WriteCoord(MSG_MULTICAST, targ.origin.x); + WriteCoord(MSG_MULTICAST, targ.origin.y); + WriteCoord(MSG_MULTICAST, targ.origin.z); + WriteShort(MSG_MULTICAST, actual_damage); + WriteShort(MSG_MULTICAST, original_damage); + WriteShort(MSG_MULTICAST, hitflag); + + // TODO: Supporting spectators (requires no ezquake) + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); +}; - - msg_entity = trueattacker; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_HITFLAG); - WriteCoord(MSG_MULTICAST, targ.origin.x); - WriteCoord(MSG_MULTICAST, targ.origin.y); - WriteCoord(MSG_MULTICAST, targ.origin.z); - WriteShort(MSG_MULTICAST, actual_damage); - WriteShort(MSG_MULTICAST, original_damage); - WriteShort(MSG_MULTICAST, hitflag); - //WriteEntity(MSG_MULTICAST, targ); - multicast('0 0 0', MULTICAST_ONE_R); -}; void (entity targ, entity inflictor, entity attacker, float damage, float knock_damage) T_DamageKnock = { local vector dir; @@ -757,8 +750,8 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, targ.armorvalue = 0; } - if(zutmode) - BroadcastHitFlag(targ, inflictor, attacker, original_damage, damh); + if (zutmode) + BroadcastHitFlag(targ, inflictor, attacker, original_damage, damh); if (targ.health <= 0) { From 4eda54a9d7db5c038e8c8869732b88f94ce53f22 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 16 Feb 2023 02:24:34 -0800 Subject: [PATCH 2010/2474] hitsounds: fix noarmour sound no more HEADSHOTS --- csqc/events.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index b256476d..43988883 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -484,7 +484,7 @@ static void PlayHitSound(float hitflags) { if (HITFLAG(HEADSHOT)) localsound(SND_HEADSHOT, CHAN_AUTO, 1); if (HITFLAG(NOARMOUR) && wantsnoarmoursound) - localsound(SND_HEADSHOT, CHAN_AUTO, 1); + localsound(SND_NOARMOUR, CHAN_AUTO, 1); } if (snd != "") From 3a76a382c12fae435cf99f1d40d2d72a2fc17281 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 15 Feb 2023 11:28:43 -0800 Subject: [PATCH 2011/2474] config: get rid of unneccessary settings save/restore fte handles this for autocvars (and no fte means no csqc to have these cvars) --- csqc/hud_helpers.qc | 12 +++ csqc/main.qc | 6 +- csqc/menu.qc | 2 +- csqc/settings.qc | 229 +------------------------------------------- 4 files changed, 18 insertions(+), 231 deletions(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index c26267e2..3d71c574 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -219,6 +219,18 @@ void Hud_DrawStringLMPThreshold(vector pos, string value, float size, float thre } } +static string FormatCfgString(string line, string field, string value) { + line = strcat(line, "\n", field, ":", value); + return line; +} + +static string FormatCfgVector(string line, string field, vector value) +{ + line = strcat(line, "\n", field, ":", strcat(ftos(value_x), ",", ftos(value_y))); + + return line; +} + string GetPanelString(string line, FO_Hud_Panel* panel) { string sn = panel->SaveName; diff --git a/csqc/main.qc b/csqc/main.qc index a7e42644..99c53550 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -6,8 +6,6 @@ void FO_Hud_Editor_List_Panels(); void FO_Hud_Editor_Print_Panel_Setting(string, string setting); void FO_Hud_Editor_Set_Panel_Setting(string, string setting, string value); void Hud_WriteCfg(string path); -void FO_LoadSettings(); -void FO_WriteSettings(); void AddGrenTimer(float grentype, float offset); void StopGrenTimers(); float IsValidToUseGrenades(); @@ -104,7 +102,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercvar("fo_menu_option_+", "="); FO_Hud_Editor_LoadSettings(FO_HUD_CONFIG_PATH); - FO_LoadSettings(); MenuPanel = getHudPanel(HUDP_MENU); @@ -462,8 +459,7 @@ float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { return 0; } -void CSQC_Shutdown() = { - FO_WriteSettings(); +void CSQC_Shutdown() { } // We can query, but not set via an autocvar. diff --git a/csqc/menu.qc b/csqc/menu.qc index 9eced4f0..a55fb7f8 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -379,7 +379,7 @@ var fo_menu FO_MENU_DISPENSER_USE = { void updateAdminMenuInfo() = { if(admin_menu_next_update < time) { localcmd("cmd adminrefresh\n"); - admin_menu_next_update = time + CVARF(FOCMD_ADMIN_MENU_UPDATE_TIME); + admin_menu_next_update = time + CVARF(fo_adminrefresh); } } diff --git a/csqc/settings.qc b/csqc/settings.qc index 1de98b40..3ede6f17 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -1,4 +1,3 @@ -// Saved/Loaded/Restored by Settings funcs DEFCVAR_FLOAT(fo_grentimer, 2); // Sound + Ping adjust DEFCVAR_STRING(fo_grentimersound, "grentimer.wav"); DEFCVAR_FLOAT(fo_grentimervolume, 1); @@ -24,230 +23,10 @@ DEFCVAR_FLOAT(fo_hittext_offset, 32); DEFCVAR_FLOAT(fo_hittext_friendly, 0); DEFCVAR_STRING(fo_hittext_colour, "1 1 1"); DEFCVAR_STRING(fo_hittext_colour2, "1 0 1"); -DEFCVAR_STRING(fo_hittext_colour3, "1 0 0"); -// CVARS that just pass via regular config state. -DEFCVAR_FLOAT(fo_hud_idle_alpha, 0.3); -DEFCVAR_FLOAT(FOCMD_ADMIN_MENU_UPDATE_TIME, 2); - -string FormatCfgString(string line, string field, string value) -{ - line = strcat(line, "\n", field, ":", value); - - return line; -} - -string FormatCfgVector(string line, string field, vector value) -{ - line = strcat(line, "\n", field, ":", strcat(ftos(value_x), ",", ftos(value_y))); - - return line; -} +DEFCVAR_STRING(fo_hittext_colour3, "1 0 0"); -const string FOCMD_OLDSCOREBOARD = "fo_oldscoreboard"; -const string FOCMD_GRENTIMER = "fo_grentimer"; -const string FOCMD_GRENTIMERSOUND = "fo_grentimersound"; -const string FOCMD_GRENTIMERVOLUME = "fo_grentimervolume"; -const string FOCMD_JUMPVOLUME = "fo_jumpvolume"; -const string FOCMD_ADMIN_MENU_UPDATE_TIME = "fo_adminrefresh"; - -const string FOCMD_HITAUDIO_ENABLED = "fo_hitaudio_enabled"; -const string FOCMD_HITAUDIO_HURTSELF = "fo_hitaudio_hurtself"; -const string FOCMD_HITAUDIO_HURTTEAM = "fo_hitaudio_hurtteam"; -const string FOCMD_HITAUDIO_HURTENEMY = "fo_hitaudio_hurtenemy"; -const string FOCMD_HITAUDIO_KILLSELF = "fo_hitaudio_killself"; -const string FOCMD_HITAUDIO_KILLTEAM = "fo_hitaudio_killteam"; -const string FOCMD_HITAUDIO_KILLENEMY = "fo_hitaudio_killenemy"; -const string FOCMD_HITAUDIO_NOARMOUR = "fo_hitaudio_noarmour"; - -const string FOCMD_HITTEXT_ENABLED = "fo_hittext_enabled"; -const string FOCMD_HITTEXT_SIZE = "fo_hittext_size"; -const string FOCMD_HITTEXT_SPEED = "fo_hittext_speed"; -const string FOCMD_HITTEXT_ALPHA = "fo_hittext_alpha"; -const string FOCMD_HITTEXT_DURATION = "fo_hittext_duration"; -const string FOCMD_HITTEXT_RAWDAMAGE = "fo_hittext_rawdamage"; -const string FOCMD_HITTEXT_NOARMOUR = "fo_hittext_noarmour"; -const string FOCMD_HITTEXT_OFFSET = "fo_hittext_offset"; -const string FOCMD_HITTEXT_FRIENDLY = "fo_hittext_fiendly"; -const string FOCMD_HITTEXT_COLOUR = "fo_hittext_colour"; -const string FOCMD_HITTEXT_COLOUR2 = "fo_hittext_colour2"; -const string FOCMD_HITTEXT_COLOUR3 = "fo_hittext_colour3"; - -void FO_WriteSettings() -{ - // this overwrites - float filehandle; - filehandle = fopen(FO_CONFIG_PATH, FILE_WRITE); - string line = FormatCfgString("", FOCMD_GRENTIMER, ftos(CVARF(fo_grentimer))); - line = FormatCfgString(line, FOCMD_GRENTIMERSOUND, CVARS(fo_grentimersound)); - line = FormatCfgString(line, FOCMD_GRENTIMERVOLUME, ftos(CVARF(fo_grentimervolume))); - line = FormatCfgString(line, FOCMD_JUMPVOLUME, ftos(CVARF(fo_jumpvolume))); - line = FormatCfgString(line, FOCMD_OLDSCOREBOARD, ftos(CVARF(fo_oldscoreboard))); - - line = FormatCfgString(line, FOCMD_HITAUDIO_ENABLED, ftos(CVARF(fo_hitaudio_enabled))); - line = FormatCfgString(line, FOCMD_HITAUDIO_HURTSELF, ftos(CVARF(fo_hitaudio_hurtself))); - line = FormatCfgString(line, FOCMD_HITAUDIO_HURTTEAM, ftos(CVARF(fo_hitaudio_hurtteam))); - line = FormatCfgString(line, FOCMD_HITAUDIO_HURTENEMY, ftos(CVARF(fo_hitaudio_hurtenemy))); - line = FormatCfgString(line, FOCMD_HITAUDIO_KILLSELF, ftos(CVARF(fo_hitaudio_killself))); - line = FormatCfgString(line, FOCMD_HITAUDIO_KILLTEAM, ftos(CVARF(fo_hitaudio_killteam))); - line = FormatCfgString(line, FOCMD_HITAUDIO_KILLENEMY, ftos(CVARF(fo_hitaudio_killenemy))); - line = FormatCfgString(line, FOCMD_HITAUDIO_NOARMOUR, ftos(CVARF(fo_hitaudio_noarmour))); - - line = FormatCfgString(line, FOCMD_HITTEXT_ENABLED, ftos(CVARF(fo_hittext_enabled))); - line = FormatCfgString(line, FOCMD_HITTEXT_SIZE, ftos(CVARF(fo_hittext_size))); - line = FormatCfgString(line, FOCMD_HITTEXT_SPEED, ftos(CVARF(fo_hittext_speed))); - line = FormatCfgString(line, FOCMD_HITTEXT_DURATION, ftos(CVARF(fo_hittext_duration))); - line = FormatCfgString(line, FOCMD_HITTEXT_ALPHA, ftos(CVARF(fo_hittext_alpha))); - line = FormatCfgString(line, FOCMD_HITTEXT_RAWDAMAGE, ftos(CVARF(fo_hittext_rawdamage))); - line = FormatCfgString(line, FOCMD_HITTEXT_NOARMOUR, ftos(CVARF(fo_hittext_noarmour))); - line = FormatCfgString(line, FOCMD_HITTEXT_OFFSET, ftos(CVARF(fo_hittext_offset))); - line = FormatCfgString(line, FOCMD_HITTEXT_FRIENDLY, ftos(CVARF(fo_hittext_friendly))); - line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR, CVARS(fo_hittext_colour)); - line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR2, CVARS(fo_hittext_colour2)); - line = FormatCfgString(line, FOCMD_HITTEXT_COLOUR2, CVARS(fo_hittext_colour3)); - fputs(filehandle, line); - fclose(filehandle); -} - -void FO_LoadDefaultSettings() -{ - CVARF(fo_grentimer) = 2; - CVARS(fo_grentimersound) = "grentimer.wav"; - CVARF(fo_grentimervolume) = 1; - CVARF(fo_jumpvolume) = 1; - CVARF(fo_oldscoreboard) = 0; - CVARF(fo_hitaudio_enabled) = 1; - CVARF(fo_hitaudio_hurtself) = 1; - CVARF(fo_hitaudio_hurtteam) = 1; - CVARF(fo_hitaudio_hurtenemy) = 1; - CVARF(fo_hitaudio_killself) = 1; - CVARF(fo_hitaudio_killteam) = 1; - CVARF(fo_hitaudio_killenemy) = 1; - CVARF(fo_hitaudio_noarmour) = 1; - - CVARF(fo_hittext_enabled) = 1; - CVARF(fo_hittext_size) = 16; - CVARF(fo_hittext_speed) = 96; - CVARF(fo_hittext_alpha) = 1; - CVARF(fo_hittext_duration) = 2; - CVARF(fo_hittext_rawdamage) = 1; - CVARF(fo_hittext_noarmour) = 1; - CVARF(fo_hittext_offset) = 32; - CVARF(fo_hittext_friendly) = 0; - CVARS(fo_hittext_colour) = "1 1 1"; - CVARS(fo_hittext_colour2) = "1 0 1"; - CVARS(fo_hittext_colour3) = "1 0 0"; -} - -void FO_LoadSettings() -{ - FO_LoadDefaultSettings(); - - float filehandle; - filehandle = fopen(FO_CONFIG_PATH, FILE_READ); - if (filehandle >= 0) { - // get number of lines - string ln; - ln = fgets(filehandle); - while (ln) - { - if (strlen(ln) > 0) - { - ln = strreplace("\n", "", ln); - string val, field; +DEFCVAR_FLOAT(fo_hud_idle_alpha, 0.3); +DEFCVAR_FLOAT(fo_adminrefresh, 2); - float x = 0, y = 0; - float count = tokenizebyseparator(ln, ":"); - field = argv(0); - field = strtrim(field); - val = argv(1); - val = strtrim(val); +static float __unused; // Needed to avoid a spurious compiler error. - switch(field) - { - case FOCMD_GRENTIMER: - CVARF(fo_grentimer) = stof(val); - break; - case FOCMD_GRENTIMERSOUND: - CVARS(fo_grentimersound) = val; - break; - case FOCMD_GRENTIMERVOLUME: - CVARF(fo_grentimervolume) = stof(val); - break; - case FOCMD_JUMPVOLUME: - CVARF(fo_jumpvolume) = stof(val); - break; - case FOCMD_OLDSCOREBOARD: - CVARF(fo_oldscoreboard) = stof(val); - break; - case FOCMD_HITAUDIO_ENABLED: - CVARF(fo_hitaudio_enabled) = stof(val); - break; - case FOCMD_HITAUDIO_HURTSELF: - CVARF(fo_hitaudio_hurtself) = stof(val); - break; - case FOCMD_HITAUDIO_HURTTEAM: - CVARF(fo_hitaudio_hurtteam) = stof(val); - break; - case FOCMD_HITAUDIO_HURTENEMY: - CVARF(fo_hitaudio_hurtenemy) = stof(val); - break; - case FOCMD_HITAUDIO_KILLSELF: - CVARF(fo_hitaudio_killself) = stof(val); - break; - case FOCMD_HITAUDIO_KILLTEAM: - CVARF(fo_hitaudio_killteam) = stof(val); - break; - case FOCMD_HITAUDIO_KILLENEMY: - CVARF(fo_hitaudio_killenemy) = stof(val); - break; - case FOCMD_HITAUDIO_NOARMOUR: - CVARF(fo_hitaudio_noarmour) = stof(val); - break; - case FOCMD_HITTEXT_ENABLED: - CVARF(fo_hittext_enabled) = stof(val); - break; - case FOCMD_HITTEXT_SIZE: - CVARF(fo_hittext_size) = stof(val); - break; - case FOCMD_HITTEXT_SPEED: - CVARF(fo_hittext_speed) = stof(val); - break; - case FOCMD_HITTEXT_ALPHA: - CVARF(fo_hittext_alpha) = stof(val); - break; - case FOCMD_HITTEXT_DURATION: - CVARF(fo_hittext_duration) = stof(val); - break; - case FOCMD_HITTEXT_RAWDAMAGE: - CVARF(fo_hittext_rawdamage) = stof(val); - break; - case FOCMD_HITTEXT_NOARMOUR: - CVARF(fo_hittext_noarmour) = stof(val); - break; - case FOCMD_HITTEXT_OFFSET: - CVARF(fo_hittext_offset) = stof(val); - break; - case FOCMD_HITTEXT_FRIENDLY: - CVARF(fo_hittext_friendly) = stof(val); - break; - case FOCMD_HITTEXT_COLOUR: - CVARS(fo_hittext_colour) = val; - break; - case FOCMD_HITTEXT_COLOUR2: - CVARS(fo_hittext_colour2) = val; - break; - case FOCMD_HITTEXT_COLOUR2: - CVARS(fo_hittext_colour3) = val; - break; - } - } - ln = fgets(filehandle); - } - fclose(filehandle); - } - else - { - // write a new file - FO_WriteSettings(); - } -} From 91182a0844f5b4d811030a29f3d5ec62862936bb Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 16 Feb 2023 02:48:05 -0800 Subject: [PATCH 2012/2474] weapons: fix mashing +slot mashing +slot on top of +slot creates confusion since we couldn't actually process the prior weapon change from -slot even though a new +slot is queuing and overloading it. This resulted in the state-machine valid, but confusing behavior that if you +slot before a prior -slot attack finished, then it might consider the weapon to swap back to on the second +slot as the original. Make this more intuitive by making sure we forward the prior -slot to last-weapon before this. probably worth improving impulse behavior immediately after this by using queue_slot to eliminate a bunch of cases for these held impulses that can be clobbered. --- csqc/weapon_predict.qc | 15 ++++++++++----- ssqc/weapons.qc | 6 +++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 35c13666..ce052c20 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -650,6 +650,13 @@ float WP_ReloadSlot(Slot slot); void WP_ReloadNext(); void WPP_Dump(); +static void WP_ChangeIfQueued() { + if (!IsSlotNull(pstate_pred.queue_slot)) { + WP_ChangeWeapon(pstate_pred.queue_slot); + pstate_pred.queue_slot = SlotNull; + } +} + void WP_Impulse() { WP_HandleHeavyInputs(); @@ -681,6 +688,8 @@ void WP_Impulse() { if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) return; + WP_ChangeIfQueued(); // Might have something previously buffered. + // Impulses that ARE held by attack_finished / reloading. match = TRUE; switch (pstate_pred.impulse) { @@ -729,11 +738,7 @@ void WP_Impulse() { break; } - if (!IsSlotNull(pstate_pred.queue_slot)) { - WP_ChangeWeapon(pstate_pred.queue_slot); - pstate_pred.queue_slot = SlotNull; - } - + WP_ChangeIfQueued(); // Might have something newly buffered. if (match) pstate_pred.impulse = 0; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index c3f2a8d6..28fcc026 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2569,6 +2569,9 @@ void () W_WeaponFrame = { float can_change_weapon = WeaponReady(); // TODO: Open up queueing by moving queue can_change to ChangeWeapon? + if (!IsSlotNull(self.queue_slot) && can_change_weapon) + W_ChangeWeaponSlot(self.queue_slot); + if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() && can_change_weapon) { // slot 1-4 (or 1-7) binds @@ -2586,9 +2589,6 @@ void () W_WeaponFrame = { W_ChangeWeaponSlot(slot); } self.impulse = 0; - } else if (!IsSlotNull(self.queue_slot) && can_change_weapon) { - // change slot if queue_slot has been set - W_ChangeWeaponSlot(self.queue_slot); } if (self.impulse == TF_CHANGETEAM) { From 4b72bc4eea2f70793de3bea988587b6145c4e924 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 16 Feb 2023 21:56:15 -0800 Subject: [PATCH 2013/2474] compiler: support most recent fteqcc - (new compiler buglet) can't handle newline in preprocessor macro with tokens, just remove the newline - fix some (valid) new uninitialized varaible warnings - remove some straggler cases that have crept in (unused variables, warning for customizeentity even though it's better fit than csqc in that case) --- csqc/csextradefs.qc | 2 -- csqc/hud_helpers.qc | 3 ++- menusys/mitem_tabs.qc | 2 +- share/debug.qc | 10 ++++------ ssqc/qw.qc | 2 +- ssqc/sniper.qc | 2 ++ 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 63a8974a..63e4e499 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -846,8 +846,6 @@ float player_class; float is_observer; float is_player; float is_alive; -//float health; -float oldhealth; float painfinished; vector thisorigin; float jump_counter; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 3d71c574..1d35a64e 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -381,11 +381,12 @@ void FO_Hud_Editor_LoadSettings(string filename) FO_Hud_InitSystemPanels(); } +static FO_Hud_Panel zero_panel; // Inherits active render cache id void GetNewPanel(vector pos, vector fillSize, float scale, float display, float orientation, string name) { - FO_Hud_Panel pnl; + FO_Hud_Panel pnl = zero_panel; pnl.Position = pos; pnl.FillSize = fillSize; diff --git a/menusys/mitem_tabs.qc b/menusys/mitem_tabs.qc index 47ef7e66..acd684eb 100644 --- a/menusys/mitem_tabs.qc +++ b/menusys/mitem_tabs.qc @@ -96,7 +96,7 @@ float(vector pos, float scan, float char, float down) mitem_tabs::item_keypress { local mitem ch; local vector tpos = pos; - local vector sz; + local vector sz = '0 0 0'; local float result; if (down && (scan == K_MOUSE1 || scan == K_MOUSE2 || scan == K_MOUSE3)) diff --git a/share/debug.qc b/share/debug.qc index fb98f0ae..2093491e 100644 --- a/share/debug.qc +++ b/share/debug.qc @@ -30,15 +30,13 @@ inline string qc_prefix() { #define errors(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__)) #define errorf(fmt, ...) error(sprintf("%s:%d Error> " fmt, __FILE__, __LINE__, __VA_ARGS__)) -#define _ASSERT_OP(_op, _invop, _fmt, _v1, _v2) \ - if (!((_v1) _op (_v2))) \ - errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ - #_v1, #_v2, _v1, _v2) +#define _ASSERT_OP(_op, _invop, _fmt, _val1, _v2) \ + if (!((_val1) _op (_v2))) \ + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", #_val1, #_v2, _val1, _v2) #define __ASSERT_OP(_op, _invop, _fmt, _v1, _v2, __v1, __v2) \ if (!((__v1) _op (__v2))) \ - errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", \ - #_v1, #_v2, __v1, __v2) + errorf("Expected: %s " #_op " %s, but: " #_fmt " " #_invop " " #_fmt "\n", #_v1, #_v2, __v1, __v2) #define ASSERTF_EQ(_v1, _v2) _ASSERT_OP(==, !=, %0.2f, _v1, _v2) #define ASSERTF_NE(_v1, _v2) _ASSERT_OP(!=, ==, %0.2f, _v1, _v2) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ab9606cd..ae15e338 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -809,7 +809,7 @@ string settings_to_track_list[4] = { "al_max_remote_client_time_offset", }; -typedef struct setting_t { +struct setting_t { string setting_name; string value; }; diff --git a/ssqc/sniper.qc b/ssqc/sniper.qc index 7c686afe..e7d1ab7d 100644 --- a/ssqc/sniper.qc +++ b/ssqc/sniper.qc @@ -170,6 +170,8 @@ void () SniperSight_Create = { sight.think = SniperSight_Update; sight.nextthink = time + 0.05; +#pragma warning disable F326 if (ClientPred_Enabled(self, CSQC_SNIPER_SIGHT)) sight.customizeentityforclient = sight_send_filter; +#pragma warning enable F326 }; From f792c11d7efa42face75aa9b019c73cc3fa335da Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 16 Feb 2023 22:09:24 -0800 Subject: [PATCH 2014/2474] impulses: remove impulse TF_CLASSMENU No longer used (implemented via `cmd` now) and was leading to bogus input collisions in the weapon table space when old_weapon_impulses was used. --- share/defs.h | 2 +- ssqc/tforthlp.qc | 3 +-- ssqc/weapons.qc | 14 -------------- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/share/defs.h b/share/defs.h index f025cc52..6b7a8539 100644 --- a/share/defs.h +++ b/share/defs.h @@ -403,7 +403,7 @@ typedef struct { int id; } Slot; #define TF_IMPULSE_SLOT4 4 // Changes weapon to slot 4 (melee weapon) #define TF_NUM_SLOTS 4 -#define TF_CLASSMENU 5 // Brings up class menu +// unused 5 // unused 6 // unused 7 // unused 8 diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 44368883..bc133a45 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -79,8 +79,7 @@ void () TeamFortress_MOTD = { return; } - //TeamFortress_Alias("menu", TF_CLASSMENU, 0); - if(csqcactive) { + if (csqcactive) { TeamFortress_AliasString("menu", "fo_menu_special"); } else { TeamFortress_AliasString("menu", "cmd menu"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 28fcc026..f4be2533 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2527,20 +2527,6 @@ void () W_WeaponFrame = { } } - if (self.impulse == TF_CLASSMENU && self.playerclass != PC_MEDIC) { - if (self.playerclass == PC_ENGINEER) - Menu_Engineer(self); - else if (self.playerclass == PC_SCOUT) - Menu_Scout(); - else if (self.playerclass == PC_SPY) - Menu_Spy(self); - else if (self.playerclass == PC_DEMOMAN) - TeamFortress_DetpackMenu(); - - self.impulse = 0; - return; - } - if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && From 27a2695fb72e90a49a659112fd55af47e6e0a761 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 16 Feb 2023 22:11:38 -0800 Subject: [PATCH 2015/2474] weapons: put flamethrower/incendiary on right impulse under old_weapon_impulses flamethrower and incendiary were previously off-by-one (5 & 6 instead of 6 & 7) under owi. This was both wrong and resulting in flamethrower getting locked out by collision with (now removed) TF_CLASSMENU impulse. Move them to the right impulse. --- share/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/weapons.qc b/share/weapons.qc index 7d4d2890..9010a06b 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -654,7 +654,7 @@ ImpulseWeapon impulse_weapons[] = { { PC_HVYWEAP, { WEAP_AXE, WEAP_SHOTGUN, WEAP_SUPER_SHOTGUN, 0, 0, 0, WEAP_ASSAULT_CANNON } }, { PC_PYRO, - { WEAP_AXE, WEAP_SHOTGUN, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, + { WEAP_AXE, WEAP_SHOTGUN, 0, 0, 0, WEAP_FLAMETHROWER, WEAP_INCENDIARY } }, { PC_SPY, { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, { PC_ENGINEER, From cab825789d1c4c9a830615fb467da19e48c835da Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 16 Feb 2023 23:08:37 -0800 Subject: [PATCH 2016/2474] weapons: fix client-side weapons under owi Some incorrect playerclass references meant that weapon prediction under old_weapon_impulses wasn't working properly. Fix this and remove some of our older slot debugging code. --- csqc/weapon_predict.qc | 2 +- share/defs.h | 2 +- share/weapons.qc | 44 ++++++++++++++---------------------------- ssqc/progs.src | 1 - ssqc/weapons.qc | 7 ++++--- 5 files changed, 20 insertions(+), 36 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ce052c20..bdfc921a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -458,7 +458,7 @@ void WP_ServerUpdate() { } static Slot InputToSlot(float input) { - Slot result = FO_SlotByInput(input); + Slot result = FO_SlotByInput(pstate_pred.playerclass, input); return result; } diff --git a/share/defs.h b/share/defs.h index 6b7a8539..a20a6693 100644 --- a/share/defs.h +++ b/share/defs.h @@ -320,7 +320,7 @@ enum { /*======================================================*/ // Opaque token that encapsulates slots for correctness. -typedef struct { int id; } Slot; +struct Slot { int id; }; // Some of the toggleflags aren't used anymore, but the bits are still // there to provide compatability with old maps diff --git a/share/weapons.qc b/share/weapons.qc index 9010a06b..ed732160 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -5,7 +5,6 @@ * but it gets us started. */ .float waterlevel; -.float playerclass; .float ammo_shells; .float ammo_nails; @@ -15,22 +14,8 @@ float sniperreload = FALSE; #endif -// Some preprocessor bug is making __LINE__ not substitute right here most of -// the time. Oh well, even if we just get file it's good enough to narrow. -#define CheckSlot(slot_num) _CheckSlot(__FILE__, __LINE__, slot_num) -float _CheckSlot(string file, float line, float slot_num) { - if (slot_num < 1 || slot_num > TF_NUM_SLOTS) { - printf("%s:%d: Invalid slot (%d). Continuing.\n", - file, line, slot_num); - return 4; - } - return slot_num; -} - -#define MakeSlot(slot_num) _MakeSlot(CheckSlot(slot_num)) -// Careful: Slots are not 0-indexed they start from 1. // Use SlotIndex() to convert a slot if you're indexing an array. -Slot _MakeSlot(float slot_num) { +Slot MakeSlot(float slot_num) { if (slot_num < 1 || slot_num > TF_NUM_SLOTS) errorf("invalid slot %d\n", slot_num); @@ -424,11 +409,6 @@ float FO_ClassWeaponBySlot(float class, Slot slot) { return wi->weapon; } -float FO_WeaponSlot(Slot slot) { - return FO_ClassWeaponBySlot(self.playerclass, slot); -} - - float FO_ClassWeapItemMask(float class) { float result = 0; for (int i = 1; i <= TF_NUM_SLOTS; i++) { @@ -439,6 +419,7 @@ float FO_ClassWeapItemMask(float class) { return result; } +#ifndef CSQC float FO_WeaponsMask(entity player) { float mask = 0; for (float i = 1; i <= TF_NUM_SLOTS; i++) { @@ -448,6 +429,7 @@ float FO_WeaponsMask(entity player) { } return mask; } +#endif // Slightly awkward construction, but convenient for calling from CSQC and SSQC. float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) { @@ -659,12 +641,14 @@ ImpulseWeapon impulse_weapons[] = { { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, { PC_ENGINEER, { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, + { PC_RANDOM, { WEAP_AXE } }, // Never instantiated { PC_CIVILIAN, { WEAP_AXE } }, }; -Slot FO_ImpulseToSlot(float impulse) { +Slot FO_ImpulseToSlot(float playerclass, float impulse) { if (impulse < 1 || impulse > 7) return SlotNull; - return impulse_weapons[self.playerclass].slots[impulse - 1]; + Slot r = impulse_weapons[playerclass].slots[impulse - 1]; + return r; } #ifdef SSQC @@ -705,18 +689,18 @@ float IsHoldGrenades() { } #endif -float InputHandlePyroSlotSwap(float input) { +float InputHandlePyroSlotSwap(float playerclass, float input) { float cf_pyro_impulses = IsPyroSlotSwapped(); - if (self.playerclass == PC_PYRO && cf_pyro_impulses && (input == 1 || input == 2)) + if (playerclass == PC_PYRO && cf_pyro_impulses && (input == 1 || input == 2)) input = 3 - input; return input; } -Slot FO_SlotByInput(float input) { +Slot FO_SlotByInput(float playerclass, float input) { if (IsUsingOldImpulses()) { - return FO_ImpulseToSlot(input); + return FO_ImpulseToSlot(playerclass, input); } else { - input = InputHandlePyroSlotSwap(input); + input = InputHandlePyroSlotSwap(playerclass, input); if (input >= 1 && input <= TF_NUM_SLOTS) return MakeSlot(input); else @@ -752,12 +736,12 @@ Slot FO_FindPrevNextWeaponSlot(float playerclass, Slot slot, float is_prev) { // This is a little subtle, we need to transform the index both before // and after the walk so that we don't walk back into ourselves. - i = InputHandlePyroSlotSwap(SlotIndex(slot) + 1) - 1; + i = InputHandlePyroSlotSwap(playerclass, SlotIndex(slot) + 1) - 1; do { i = (i + direction + len) % len; } while (slot_weaps[i] == 0); - i = InputHandlePyroSlotSwap(i + 1); + i = InputHandlePyroSlotSwap(playerclass, i + 1); return MakeSlot(i); } } diff --git a/ssqc/progs.src b/ssqc/progs.src index 3dddb10f..9d483a10 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -17,7 +17,6 @@ defs.qc qw.qc debug.qc time.qc -../share/defs.h ../share/physics.qc ../share/weapons.qc ../share/prediction.qc diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f4be2533..a08ef568 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1898,7 +1898,7 @@ void W_ChangeWeaponByInput(float input) { if (input < 1 || input > GetMaxWeaponInput()) return; - Slot slot = FO_SlotByInput(input); + Slot slot = FO_SlotByInput(self.playerclass, input); if (IsSlotNull(slot)) return; @@ -2350,7 +2350,7 @@ void () ButtonFrame = { local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); if (default_weapon >= 1 && default_weapon <= 4) { - self.impulse = InputHandlePyroSlotSwap(default_weapon); + self.impulse = InputHandlePyroSlotSwap(self.playerclass, default_weapon); } } @@ -2565,7 +2565,8 @@ void () W_WeaponFrame = { self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - float input = InputHandlePyroSlotSwap(self.impulse - TF_QUICKSLOT1 + 1); + float input = InputHandlePyroSlotSwap(self.playerclass, + self.impulse - TF_QUICKSLOT1 + 1); Slot slot = MakeSlot(input); if (IsSameSlot(slot, self.current_slot)) { From 6fd6b496341f011b406ee771d3fe56731d1f2441 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 17 Feb 2023 11:31:22 -0800 Subject: [PATCH 2017/2474] prediction: use localsound and tie to projectile Use localsound to avoid attenuation that was occurring with predicted location. Now that we have projectile prediction for everything tie tracking of predicted sounds to the projectile instead of a heuristic. We're not doing this for hitscan weapons, but technically we werent before anyway since they had no projectile to trigger the missed sound check. --- csqc/weapon_predict.qc | 25 +++++++++++++++---------- share/prediction.qc | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index bdfc921a..86e37b6d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -422,13 +422,16 @@ inline FO_WeapInfo* WP_CurrentWeapon() { return SlotWI(CurrentSlot()); } -void Pred_Sound(SoundIndex snd, float vol = 1) { - if (snd == SND_NONE || !IsEffectFrame() || pstate_pred.tfstate & TFSTATE_FLASHED) +void RawPred_Sound(SoundIndex snd, float vol = 1) { + if (snd == SND_NONE || pstate_pred.tfstate & TFSTATE_FLASHED) return; - last_pred_sound = time; - setorigin(pred_sound_entity, pmove_org); - sound(pred_sound_entity, CHAN_WEAPON, Snd_Get(snd)->sound, vol, ATTN_NORM); + localsound(Snd_Get(snd)->sound, CHAN_WEAPON, vol); +} + +void Pred_Sound(SoundIndex snd, float vol = 1) { + if (IsEffectFrame()) + RawPred_Sound(snd, vol); } void PredProj_Sound(int proj_type, float vol = 1) { @@ -1534,12 +1537,14 @@ void InitProjectileEnt(float sendflags) { // flight projectiles on the transition. This is effectively a nop in the // off case since the projectile list will just be empty. float has_predicted = FALSE; - if (self.owner_entnum == pengine.player_entnum) { + if (PP_Enabled() && self.owner_entnum == pengine.player_entnum) { has_predicted = PredProjectile_MatchProjectile(); - if (WP_Enabled() && !has_predicted && - self.s_time > last_pred_sound + PP_EPS/2) - // Missing projectile implies we missed the local sound, patch it up. - PredProj_Sound(self.fpp.index); + + // Either missed prediction, or not active. We don't want to condition + // on effect frames here as this isn't predicted; stronger: if we missed + // the sound we probably missed an effect frame! + if (!has_predicted) + RawPred_Sound(FPP_Get(self.fpp.index)->snd); } if (!has_predicted) { diff --git a/share/prediction.qc b/share/prediction.qc index ed55730c..b28f296e 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -781,7 +781,7 @@ void Pred_Sound(SoundIndex snd, float vol = 1) { entity target = self; string wav = snd_types[snd].sound; - if (ClientPred_Enabled(self, CSQC_WEAP_PRED)) { + if (ClientPred_Enabled(self, CSQC_PROJ_PRED)) { target = self.predict_entity; setorigin(target, self.origin); } From 3599c3c08dc7a78da56c328c29a3adc0de486232 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 17 Feb 2023 11:57:06 -0800 Subject: [PATCH 2018/2474] prediction: don't emit projectiles during no_fire_mode Prevent ghost projectiles during e.g. duel lockout or ceasefire --- csqc/weapon_predict.qc | 5 ++++- share/defs.h | 5 +++-- ssqc/world.qc | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 86e37b6d..671d73b0 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1323,7 +1323,7 @@ static float CanThrowGrenade(int gren_type) { } static void W_ThrowGren(float is_throw) { - if (!QcPhysics() || !RewindFlagEnabled(REWIND_GRENADES)) + if (!QcPhysics() || !RewindFlagEnabled(REWIND_GRENADES) || getstatf(STAT_NOFIRE)) return; if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED == 0) @@ -1366,6 +1366,9 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { } void WP_Attack() { + if (getstatf(STAT_NOFIRE)) + return; + FO_WeapInfo* wi = WP_CurrentWeapon(); if (wi->predict_type == NO_PREDICT) diff --git a/share/defs.h b/share/defs.h index a20a6693..63f93a3f 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1492,8 +1492,9 @@ enumflags { #define STAT_TP_GREN1 38 #define STAT_TP_GREN2 39 #define STAT_PAUSED 40 -#define STAT_TEAMNO_ATTACK 41 -#define STAT_ALL_TIME 42 +#define STAT_NOFIRE 41 +#define STAT_TEAMNO_ATTACK 42 +#define STAT_ALL_TIME 43 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/world.qc b/ssqc/world.qc index 838fcba3..52ad050e 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -340,6 +340,7 @@ void () worldspawn = { clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused"); + globalstat(STAT_NOFIRE, EV_FLOAT, "no_fire_mode"); globalstat(STAT_TEAMNO_ATTACK, EV_FLOAT, "team_no_attack"); entity worldspawnent; From df61a3233f082739d5c7d33f631cec820991c930 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 20 Feb 2023 16:05:49 -0800 Subject: [PATCH 2019/2474] impulses: restore TF_CLASSMENU While internal usage has migrated to `cmd menu`; there's still external use via legacy impulse 5 bind which this hits. Just bringing it back is simplest. --- share/defs.h | 2 +- ssqc/tforthlp.qc | 1 + ssqc/weapons.qc | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 63f93a3f..61aa3433 100644 --- a/share/defs.h +++ b/share/defs.h @@ -403,7 +403,7 @@ struct Slot { int id; }; #define TF_IMPULSE_SLOT4 4 // Changes weapon to slot 4 (melee weapon) #define TF_NUM_SLOTS 4 -// unused 5 +#define TF_CLASSMENU 5 // Brings up class menu // unused 6 // unused 7 // unused 8 diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index bc133a45..089aef5f 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -84,6 +84,7 @@ void () TeamFortress_MOTD = { } else { TeamFortress_AliasString("menu", "cmd menu"); } + TeamFortress_Alias("slot1", TF_IMPULSE_SLOT1, 0); TeamFortress_Alias("slot2", TF_IMPULSE_SLOT2, 0); TeamFortress_Alias("slot3", TF_IMPULSE_SLOT3, 0); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index a08ef568..23e3313b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2527,6 +2527,18 @@ void () W_WeaponFrame = { } } + if (self.impulse == TF_CLASSMENU && self.playerclass != PC_MEDIC) { + switch (self.playerclass) { + case PC_ENGINEER: Menu_Engineer(self); break; + case PC_SCOUT: Menu_Scout(); break; + case PC_SPY: Menu_Spy(self); break; + case PC_DEMOMAN: TeamFortress_DetpackMenu(); break; + } + + self.impulse = 0; + return; + } + if ((self.is_feigning) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && From 0f9cb5b00dc75eaea051481ce04cef0eb522a3bd Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 20 Feb 2023 16:32:39 -0800 Subject: [PATCH 2020/2474] movement: further simplify setspeed / make specs fast Remove more stuffs; trying to get to the bottom of unfeigning spies that can't move. Make specs consistently fast. --- csqc/weapon_predict.qc | 1 - ssqc/tfort.qc | 20 ++------------------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 671d73b0..2f971ed8 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -965,7 +965,6 @@ void MP_SetSpeed() { // lower speeds. Except for transitions where the maxspeed is reset. if (speed > last_set || fastest > speed) { last_set = speed; - CVARF(cl_forwardspeed) = CVARF(cl_backspeed) = CVARF(cl_sidespeed) = speed; string spd = ftos(speed); localcmd("cl_forwardspeed ", spd, "; cl_backspeed ",spd, "; cl_sidespeed ", spd, "\n"); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2087fe83..f8e04e17 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1250,33 +1250,17 @@ void (entity p) TeamFortress_SetSpeed = { float tf; entity te; - stuffcmd(p, "cl_movespeedkey 1\n"); if (p.tfstate & TFSTATE_CANT_MOVE) { -#ifdef STOP_MOUSE_MOVEMENT - stuffcmd(p, "m_forward 0\n"); - stuffcmd(p, "m_side 0\n"); -#endif p.velocity = '0 0 0'; - if (!RewindFlagEnabled(REWIND_SETSPEED)) { - // maxspeed suffices for any modern client, delete these once - // tested in a few pugs. - stuffcmd(p, "cl_backspeed 0\n"); - stuffcmd(p, "cl_forwardspeed 0\n"); - stuffcmd(p, "cl_sidespeed 0\n"); - } p.maxspeed = 0; return; } -#ifdef STOP_MOUSE_MOVEMENT - else { - stuffcmd(p, "m_forward 1\n"); - stuffcmd(p, "m_side 0.8\n"); - } -#endif + if (p.playerclass == PC_UNDEFINED) { // Typically this hits spectators and then spec movetype --> maxspeed // actually ignored. p.maxspeed = 0; + stuffcmd(p, "cl_backspeed 500; cl_forwardspeed 500; cl_sidespeed 500\n"); return; } From cc3c047868b1e1c5f091bd672318b3afae728242 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 20 Feb 2023 17:13:48 -0800 Subject: [PATCH 2021/2474] hud: extend caching to scoreboard Now that the unrelated flicker bug is fixed, extend hud_cache support to the scoreboard. This reduces the fps hit from ~400+ to under 100. Add some specific handling to move it to the front of the redraw list on toggle so that it still feels nice and snappy. --- csqc/csextradefs.qc | 3 +-- csqc/hud.qc | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 63e4e499..2733f6d1 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -614,7 +614,7 @@ float HRC_NewFrame() { /* hud_render_cache.last_update = time; */ if (!CVARF(fo_hud_cache) || - fo_hud_menu_active || fo_hud_editor || showingscores || + fo_hud_menu_active || fo_hud_editor || getHudPanel(HUDP_MAP_MENU)->Display) { // Either explicitly disabled, or rendering a more complicated scene // like the editor for which we'll just display in place. @@ -626,7 +626,6 @@ float HRC_NewFrame() { return FALSE; } - static Draw_Args* next_args() { float idx; if (hud_render_cache.free_count) diff --git a/csqc/hud.qc b/csqc/hud.qc index e411785c..57d1b804 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1104,6 +1104,7 @@ struct { void Hud_UpdateView(float width, float height, float menushown, float perf_sample) { ScreenSize = [width, height, menushown]; + if (HRC_NewFrame()) { float hts = perf_start_sample(&hud_timing, perf_sample); sui_begin(width, height); @@ -1117,6 +1118,19 @@ void Hud_UpdateView(float width, float height, float menushown, float perf_sampl if (!hud_render_cache.enabled) return; + // Handle appearance/removal of scoreboard. Invalidate if it's disappearing + // and render it immediately for responsiveness if it's been brought up. + static float last_showingscores; + if (last_showingscores != showingscores) { + if (last_showingscores) { + HRC_Invalidate(HUDP_SHOWSCORES); + } else { + incremental_hud.idx = HUDP_SHOWSCORES - HUDP_FIRST; + incremental_hud.last_draw[incremental_hud.idx] = 0; + } + last_showingscores = showingscores; + } + // Skip any not-displayed elements. float i = 0, idx = incremental_hud.idx; while (!getHudPanel(HUDP_FIRST + idx)->Display && From 29b94e0d2aac7382cf3d71fc89f69e8cad12e578 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 20 Feb 2023 17:39:44 -0800 Subject: [PATCH 2022/2474] Add fo_settings_check Adds an fo_settings_check command that validates client settings and recommends when better options are available. Currently checks: worker_count/r_temporalscenecache/fo_grentimer It would be nice to automatically correct things like worker_count, but security disallows csqc/server setting these. --- csqc/main.qc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index 99c53550..34b344e7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -26,6 +26,8 @@ DECLARE_PERF_SAMPLER(frame_timing, 60, 0.1); DECLARE_PERF_SAMPLER(hud_timing, 60, 0.1); DECLARE_PERF_SAMPLER(hud_partial_timing, 60, 0.1); +void ClientSettings_Check(); + noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); @@ -90,6 +92,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("tracktarget"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); + registercommand("fo_settings_check"); registercommand("vote_addmap"); registercommand("vote_removemap"); @@ -123,6 +126,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { noref void() CSQC_WorldLoaded = { print("CSQC World Loaded\n"); + ClientSettings_Check(); localcmd("menu_restart\n"); } @@ -239,6 +243,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_cancel": Menu_Cancel(); break; + case "fo_settings_check": + ClientSettings_Check(); + break; case "+fo_showscores": if (CVARF(fo_oldscoreboard) == 1) { @@ -581,3 +588,15 @@ void Perf_Status() { to_precision(avg, prec), variance, to_precision(minv, prec), to_precision(maxv, prec)); } + +void ClientSettings_Check() { + localcmd("cl_movespeedkey 1"); + if (cvar("worker_count") == 0) + printf("ERROR: Please set `worker_count 4` to reduce stuttering!\n"); + + if (cvar("r_temporalscenecache") == 0) + printf("RECOMMENDED: Please set `r_temporalscenecache 1` to reduce stuttering!\n"); + if (cvar("fo_grentimer") != 2) + printf("RECOMMEND: Setting `fo_grentimer 2` for ping correction.\n"); + printf("Finished checking settings...\n"); +} From 314de7e954680d262f2451fedd11971b880200ba Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 20 Feb 2023 19:09:10 -0800 Subject: [PATCH 2023/2474] grentimers: default fo_grentimer 2 to full rtt correction Due to the world being interpolated an additional 1/2 rtt, our prior ping correction was slightly off. Change the default correction to a full rtt, but also introduce `fo_grentimer_ping_frac` to control the total latency corrected. A value of `fo_grentimer_ping_frac 0.5` will restore the behavior prior to this change. --- csqc/csextradefs.qc | 4 ++-- csqc/events.qc | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 2733f6d1..6175ab0d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -520,7 +520,6 @@ enumflags { FL_GT_SOUND, FL_GT_THROWN, FL_GT_ADJPING, - FL_GT_FULL_RTT, }; void(string identify) Hud_DrawIdentifyPanel; @@ -706,7 +705,8 @@ void HRC_Render() { } } -DEFCVAR_FLOAT(fo_grentimer_nostack, 0); +DEFCVAR_FLOAT(fo_grentimer_ping_frac, 1); // Fraction of ping to correct for. +DEFCVAR_FLOAT(fo_grentimer_nostack, 0); // When set, only play soonest timer. class CsGrenTimer; CsGrenTimer grentimers[NUM_GREN_TIMERS]; diff --git a/csqc/events.qc b/csqc/events.qc index 43988883..d19d5965 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -394,12 +394,9 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, playing_ = FALSE; if (this.flags_ & FL_GT_ADJPING) { - float rtt = pstate_pred.client_ping; + float rtt = pstate_pred.client_ping * CVARF(fo_grentimer_ping_frac); if (RewindFlagEnabled(REWIND_GRENADES)) rtt = max(0, rtt - (100 + FO_RewindGrenMs(TF_GREN_conv(_grentype)))); - else if ((this.flags_ & FL_GT_FULL_RTT) == 0) - rtt /= 2; // Not actually right, but preserve buggy behavior for - // now as people are used to it. expires_at_ -= rtt / 1000; } @@ -432,7 +429,6 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { switch (CVARF(fo_grentimer)) { case 0: break; case 1: timer_flags = FL_GT_SOUND; break; - case 3: timer_flags = FL_GT_FULL_RTT; // Intentional fall-through. // 2 [and something sane for anything we don't recognize.] default: timer_flags |= FL_GT_SOUND | FL_GT_ADJPING; break; } From 82d962ba1ff610798d09ffdae8107cbdb8fcda2f Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 20 Feb 2023 19:20:26 -0800 Subject: [PATCH 2024/2474] settings check: add fo_hud_cache Test for fo_hud_cache 1 --- csqc/main.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 34b344e7..bdc432f4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -593,10 +593,11 @@ void ClientSettings_Check() { localcmd("cl_movespeedkey 1"); if (cvar("worker_count") == 0) printf("ERROR: Please set `worker_count 4` to reduce stuttering!\n"); - if (cvar("r_temporalscenecache") == 0) printf("RECOMMENDED: Please set `r_temporalscenecache 1` to reduce stuttering!\n"); if (cvar("fo_grentimer") != 2) printf("RECOMMEND: Setting `fo_grentimer 2` for ping correction.\n"); + if (cvar("fo_hud_cache") != 1) + printf("ERROR: Please set `fo_hud_cache 1` to improve fps.\n"); printf("Finished checking settings...\n"); } From eac33224d7db21bf6080d5b81eaeb888509d2e64 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 20 Feb 2023 19:24:09 -0800 Subject: [PATCH 2025/2474] spy: default feign rate limit off Now that we're not doing pub nights, default the rate limit to 0 again. Should probably apply to just the death message if we bring it back anyway. --- ssqc/client.qc | 2 +- ssqc/spy.qc | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c01f067e..8a582f5c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -526,7 +526,7 @@ void () DecodeLevelParms = { feign_msg = CF_GetSetting("fm", "feign_msg", "on"); // rate limit on feign - feign_rate_limit = CF_GetSetting("frl", "feign_rate_limit", "5"); + feign_rate_limit = CF_GetSetting("frl", "feign_rate_limit", "0"); // turn off spy [off] spy_off = CF_GetSetting("spy", "spy", "off"); diff --git a/ssqc/spy.qc b/ssqc/spy.qc index bb20c3a9..0ddc8170 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -166,7 +166,10 @@ void (float issilent, float force) FO_Spy_Feign = { } // Success. We will feign. - self.next_feign_time = time + feign_rate_limit; + if (feign_rate_limit) + self.next_feign_time = time + feign_rate_limit; + else + self.next_feign_time = 0; // don't check for team color cheat for 5 seconds self.immune_to_check = time + 5; From e9818a86f95bc86f33bea69e9580f047f53ad3fb Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 21 Feb 2023 19:13:32 -0800 Subject: [PATCH 2026/2474] scoreboard: refactor - Refactor scoreboard to simplify/remove some repetition, small performance improvements - Better truncation handling for coloured names - Cache on startup whether or not we have icons for ready/chat/afk --- csqc/csextradefs.qc | 10 +- csqc/menu.qc | 15 ++ csqc/status.qc | 325 +++++++++++++++++++------------------------- 3 files changed, 161 insertions(+), 189 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6175ab0d..6a9314f9 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -794,7 +794,7 @@ class CsGrenTimer { }; // scoreboard stuff -typedef struct { +struct FO_ScoreBoardLine{ float ping; float pl; string classtext; @@ -812,7 +812,7 @@ typedef struct { float damagetaken; float ready; float chat; -} FO_ScoreBoardLine; +}; // fte maxclients is 255, right? #define FO_SCOREBOARDLINES_LENGTH 32 @@ -834,6 +834,12 @@ string FO_ScoreBoardColumns[] = { "dmgt" }; +struct { + string icon_ready; + string icon_chat; + string icon_afk; +} FO_ScoreBoardAssets; + DEFCVAR_FLOAT(fo_fte_hud, 0); DEFCVAR_FLOAT(fo_legacy_sbar, 0); DEFCVAR_FLOAT(fo_csjumpsounds, 1); diff --git a/csqc/menu.qc b/csqc/menu.qc index a55fb7f8..3db39711 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -1321,6 +1321,17 @@ void (float show) showVoteMenu = { _target.options[i].id = ++next_id; \ } while (0) + +// Returns path if it exists, empty string otherwise. +static string InitIfFileExists(string path) { + float filehandle = fopen(path, FILE_READ); + if (filehandle >= 0) { + fclose(filehandle); + return path; + } + return ""; +} + void FO_Hud_Init() { float i; ASSERTD_EQ(Hud_Panels.length, HUDP_LAST - HUDP_FIRST + 1); @@ -1355,5 +1366,9 @@ void FO_Hud_Init() { INIT_MENU_IDS(FO_MENU_ADMIN_TIMELIMIT); INIT_MENU_IDS(FO_MENU_ADMIN_FRAGLIMIT); INIT_MENU_IDS(FO_MENU_VOTE); + + FO_ScoreBoardAssets.icon_ready = InitIfFileExists("textures/wad/icon_ready.png"); + FO_ScoreBoardAssets.icon_chat = InitIfFileExists("textures/wad/icon_chat.png"); + FO_ScoreBoardAssets.icon_afk = InitIfFileExists("textures/wad/icon_afk.png"); } #undef INIT_MENU_IDS diff --git a/csqc/status.qc b/csqc/status.qc index 8a6c1c63..0c06ede4 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -677,13 +677,10 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel float classspace = strlen("class") * smalltext.x; - for (float i = 0; i < FO_ScoreBoardColumns.length; i++) - { + for (float i = 0; i < FO_ScoreBoardColumns.length; i++) { string colname = FO_ScoreBoardColumns[i]; - if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) - { - switch (colname) - { + if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) { + switch (colname) { case "class": colname = "type"; case "ping": @@ -692,27 +689,20 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel sui_text(position, smalltext, colname, columnColour, .7, 0); break; } - } - else - { + } else { sui_text(position, smalltext, colname, columnColour, .7, 0); } - + txtlength = strlen(colname) * smalltext.x; if (colname == "name") - { position_x += namespace; - } else - { position_x += txtlength + padding; - } } position = [0, smalltext.y]; float lineCount = 1; - for (float i = 0; i < FO_SCOREBOARDLINES_LENGTH; i++) - { + for (float i = 0; i < FO_SCOREBOARDLINES_LENGTH; i++) { string name = lines[i].name; if (!name) continue; @@ -720,14 +710,10 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel lineCount++; float trans = 1; if (lineCount % 2 == 0) - { trans = .7; - } else - { trans = .3; - } - + sui_fill(position, size, columnColour, trans, 0); textcolour = MENU_TEXT_1; @@ -736,18 +722,13 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel } else if(lines[i].name == getplayerkeyvalue(player_localentnum - 1, "name")) { textcolour = '0.8 0 0.8'; } else { - if (prematch && lines[i].team_no && !SBAR.CountdownStarted - && lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) - { + if (prematch && lines[i].team_no && !SBAR.CountdownStarted + && lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { float ready = lines[i].ready; if (ready) - { textcolour = MENU_TEXT_GREEN_FO; - } else - { textcolour = MENU_TEXT_RED_FO; - } } } @@ -761,59 +742,50 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; if (team_no == lines[i].team_no || lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER - || is_spectator || is_observer) - { + || is_spectator || is_observer) { string c = lines[i].classtext; - if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) - { + if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { float cspace = strlen(c) * smalltext.x; - if (cspace > classspace) - { + if (cspace > classspace) { float max = classspace / smalltext.x; // TODO - maybe make this ok with non fixed width fonts one day... we're 90% of the way there c = substring(c, 0, max); } } - + sui_text(position, smalltext, c, textcolour, 1, 0); } - + position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; - if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) - { + if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { val = AbbreviateNumberToString(lines[i].score); drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); } position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; string n = lines[i].name; - if (strlen(n) * smalltext.x >= (namespace - padding)) - { - float diff = (namespace - padding) / smalltext.x; - n = substring(n, 0, diff); + if (stringwidth(n, TRUE, smalltext) >= namespace - padding) { + n = strdecolorize(n); + n = substring(n, 0, floor(namespace - padding) / smalltext.x); } sui_text(position, smalltext, n, textcolour, 1, 0); position_x += namespace; - vector iconpos = [size_x, position_y]; + vector iconpos = [size_x, position_y]; //check for icon files existing, otherwise use fallbacks float filehandle; if(lines[i].ready) { - filehandle = fopen(strcat("textures/wad/icon_ready.png"), FILE_READ); - if (filehandle >= 0) { - fclose(filehandle); - sui_pic(iconpos, smalltext, "textures/wad/icon_ready.png", '1 1 1', alpha, flags); - } else { + if (FO_ScoreBoardAssets.icon_ready != "") + sui_pic(iconpos, smalltext, FO_ScoreBoardAssets.icon_ready, '1 1 1', alpha, flags); + else sui_text(iconpos, smalltext, "R", MENU_TEXT_GREEN_FO, 1, 0); - } iconpos_x += smalltext.x; } + if(lines[i].chat & 1) { - filehandle = fopen(strcat("textures/wad/icon_chat.png"), FILE_READ); - if (filehandle >= 0) { - fclose(filehandle); - sui_pic(iconpos, smalltext, "textures/wad/icon_chat.png", '1 1 1', alpha, flags); + if (FO_ScoreBoardAssets.icon_chat != "") { + sui_pic(iconpos, smalltext, FO_ScoreBoardAssets.icon_chat, '1 1 1', alpha, flags); } else { //use ezquake chaticons image. Couldn't get drawsubpic to work, so now we get this instead drawsetcliparea(iconpos_x + panel.Position.x, iconpos_y + panel.Position.y + 20, smalltext.x, smalltext.y); @@ -822,11 +794,10 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel } iconpos_x += smalltext.x; } + if(lines[i].chat & 2) { - filehandle = fopen(strcat("textures/wad/icon_afk.png"), FILE_READ); - if (filehandle >= 0) { - fclose(filehandle); - sui_pic(iconpos, smalltext, "textures/wad/icon_afk.png", '1 1 1', alpha, flags); + if (FO_ScoreBoardAssets.icon_afk != "") { + sui_pic(iconpos, smalltext, FO_ScoreBoardAssets.icon_afk, '1 1 1', alpha, flags); } else { drawsetcliparea(iconpos_x + panel.Position.x, iconpos_y + panel.Position.y + 20, smalltext.x, smalltext.y); sui_pic(iconpos - [smalltext_x,0], [smalltext_x * 4,smalltext_y * 256 / 56 ], "textures/chaticons.png", '1 1 1', alpha, flags); @@ -835,8 +806,7 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel iconpos_x += smalltext.x; } - if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) - { + if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) { position_y += smalltext_y; position_x = 0; continue; @@ -881,15 +851,38 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel position_x = 0; position_y += smalltext_y; } - + size_y = smalltext.y * lineCount; sui_border_box([0, 0], size, 1, MENU_BORDER, FO_MENU_TRANSPARENCY, 0); return position; }; -void(PanelID panelid, string text) drawShowScoresPanel = { +enum { + SC_BLUE, + SC_RED, + SC_YELLOW, + SC_GREEN, + SC_SPECS, + NUM_SC = SC_SPECS, +}; + +struct FO_ScoreBoardTeam { + FO_ScoreBoardLine lines[FO_SCOREBOARDLINES_LENGTH]; + int count; +}; + +struct FO_ScoreBoard { + FO_ScoreBoardTeam team[NUM_SC]; +}; + +static FO_ScoreBoard score_board; + +void drawShowScoresPanel(PanelID panelid, string text) { FO_Hud_Panel* panel = getHudPanel(panelid); - + + if (!panel.Display && !fo_hud_editor) + return; + vector position = getPanelPosition(panel); vector size = getPanelFillSize(panel); vector mediumtext = MENU_TEXT_SMALL * panel.Scale * 2; @@ -900,138 +893,96 @@ void(PanelID panelid, string text) drawShowScoresPanel = { if (hud_panel(panelid, position, size, 0.3, panel.Display)) { // click event } - } else { - if(!panel.Display) { - return; - } - - FO_ScoreBoardLine FO_ScoreBoardLines_Blue[FO_SCOREBOARDLINES_LENGTH]; - FO_ScoreBoardLine FO_ScoreBoardLines_Red[FO_SCOREBOARDLINES_LENGTH]; - FO_ScoreBoardLine FO_ScoreBoardLines_Yellow[FO_SCOREBOARDLINES_LENGTH]; - FO_ScoreBoardLine FO_ScoreBoardLines_Green[FO_SCOREBOARDLINES_LENGTH]; - FO_ScoreBoardLine FO_ScoreBoardLines_Specs[FO_SCOREBOARDLINES_LENGTH]; - - sui_push_frame(position, [size.x, 1]); - sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); - position = [0,0]; - sui_text(position, mediumtext, "Scoreboard", textcolour, 1, 0); - - float bluecount = 0, redcount = 0, yellowcount = 0, greencount = 0, speccount = 0; - for (float i = 0; i < FO_SCOREBOARDLINES_LENGTH; i++) - { - FO_ScoreBoardLine sbl; - sbl.ping = getplayerkeyfloat(i, INFOKEY_P_PING); - if (!sbl.ping) - { - continue; - } - sbl.pl = getplayerkeyfloat(i, INFOKEY_P_PACKETLOSS); - float class = getplayerkeyfloat(i, "playerclass"); - sbl.classtext = ClassToString(class); - sbl.name = getplayerkeyvalue(i, INFOKEY_P_NAME); - sbl.score = getplayerkeyfloat(i, INFOKEY_P_FRAGS); - sbl.caps = getplayerkeyfloat(i, "caps"); - sbl.touches = getplayerkeyfloat(i, "touches"); - sbl.kills = getplayerkeyfloat(i, "kills"); - sbl.teamkills = getplayerkeyfloat(i, "teamkills"); - sbl.deaths = getplayerkeyfloat(i, "deaths"); - sbl.afflicted = getplayerkeyfloat(i, "afflicted"); - sbl.teamafflicted = getplayerkeyfloat(i, "teamafflicted"); - sbl.damagegiven = getplayerkeyfloat(i, "damagegiven"); - sbl.damagetaken = getplayerkeyfloat(i, "damagetaken"); - sbl.team_no = getplayerkeyfloat(i, "team_no"); - sbl.ready = getplayerkeyfloat(i, "ready"); - sbl.chat = getplayerkeyfloat(i, "chat"); - - switch (sbl.team_no) - { - case 1: - FO_ScoreBoardLines_Blue[bluecount++] = sbl; - break; - case 2: - FO_ScoreBoardLines_Red[redcount++] = sbl; - break; - case 3: - FO_ScoreBoardLines_Yellow[yellowcount++] = sbl; - break; - case 4: - FO_ScoreBoardLines_Green[greencount++] = sbl; - break; - default: - float spec = getplayerkeyfloat(i, "*spectator"); - sbl.team_no = (spec == 1) ? TEAM_SPECTATOR : TEAM_OBSERVER; - sbl.classtext = (spec == 1) ? "Spectator" : "Observer"; - FO_ScoreBoardLines_Specs[speccount++] = sbl; - break; - } - } + return; + } - float sbCount = 0; + float i; - vector smalltext = MENU_TEXT_SMALL * panel.Scale; - vector yspacer = [0, 20]; - size_y = smalltext_y; - - if (FO_ScoreBoardLines_Blue[0].name) - { - position += yspacer; - sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Blue, panel, padding, MENU_TEXT_BLUE_FO); - sbCount++; - } - - if (FO_ScoreBoardLines_Red[0].name) - { - position += yspacer; - sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Red, panel, padding, MENU_TEXT_RED_FO); - sbCount++; - } - - if (FO_ScoreBoardLines_Yellow[0].name) - { - position += yspacer; - sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Yellow, panel, padding, MENU_TEXT_YELLOW_FO); - sbCount++; - } - - if (FO_ScoreBoardLines_Green[0].name) - { - position += yspacer; - sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Green, panel, padding, MENU_TEXT_GREEN_FO); - sbCount++; - } + for (i = 0; i < NUM_SC; i++) + score_board.team[i].count = 0; - if (FO_ScoreBoardLines_Specs[0].name) - { - position += yspacer; - sui_push_frame(position, size); - position = drawShowScoresTeamPanel(FO_ScoreBoardLines_Specs, panel, padding, MENU_TEXT_SPEC_FO); - sbCount++; + sui_push_frame(position, [size.x, 1]); + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); + position = [0,0]; + sui_text(position, mediumtext, "Scoreboard", textcolour, 1, 0); + + for (i = 0; i < FO_SCOREBOARDLINES_LENGTH; i++) { + float ping = getplayerkeyfloat(i, INFOKEY_P_PING); + if (!ping) + continue; + + int sbl_team_no = getplayerkeyfloat(i, "team_no"); + switch (sbl_team_no) { + case 1: case 2: case 3: case 4: + sbl_team_no -= 1; // Maps to SC enum + break; + default: + sbl_team_no = SC_SPECS; + break; } - - /* - // FIXME - maybe some colours on some columns to help differentiate them - If possible, have AFK/msg indicators - Reset between rounds - Make a summary one for end of game too - show who you are on scoreboard - show who you are speccing - when player comes in after caps occur, they aren't getting team score - - */ - - for (float i = 0; i < sbCount; i++) - { - sui_pop_frame(); + FO_ScoreBoardTeam* team = &score_board.team[sbl_team_no]; + FO_ScoreBoardLine* sbl = &team->lines[team->count++]; + + sbl->ping = ping; + sbl->pl = getplayerkeyfloat(i, INFOKEY_P_PACKETLOSS); + float class = getplayerkeyfloat(i, "playerclass"); + sbl->classtext = ClassToString(class); + sbl->name = getplayerkeyvalue(i, INFOKEY_P_NAME); + sbl->score = getplayerkeyfloat(i, INFOKEY_P_FRAGS); + sbl->caps = getplayerkeyfloat(i, "caps"); + sbl->touches = getplayerkeyfloat(i, "touches"); + sbl->kills = getplayerkeyfloat(i, "kills"); + sbl->teamkills = getplayerkeyfloat(i, "teamkills"); + sbl->deaths = getplayerkeyfloat(i, "deaths"); + sbl->afflicted = getplayerkeyfloat(i, "afflicted"); + sbl->teamafflicted = getplayerkeyfloat(i, "teamafflicted"); + sbl->damagegiven = getplayerkeyfloat(i, "damagegiven"); + sbl->damagetaken = getplayerkeyfloat(i, "damagetaken"); + sbl->team_no = getplayerkeyfloat(i, "team_no"); + sbl->ready = getplayerkeyfloat(i, "ready"); + sbl->chat = getplayerkeyfloat(i, "chat"); + + if (sbl_team_no == SC_SPECS) { + float spec = getplayerkeyfloat(i, "*spectator"); + sbl->team_no = (spec == 1) ? TEAM_SPECTATOR : TEAM_OBSERVER; + sbl->classtext = (spec == 1) ? "Spectator" : "Observer"; } - - sui_pop_frame(); } + + float sbCount = 0; + + vector smalltext = MENU_TEXT_SMALL * panel.Scale; + vector yspacer = [0, 20]; + size_y = smalltext_y; + + for (i = 0; i < NUM_SC; i++) { + FO_ScoreBoardTeam* team = &score_board.team[i]; + if (!team->count) + continue; + + position += yspacer; + sui_push_frame(position, size); + position = drawShowScoresTeamPanel(&team->lines, panel, + padding, TEXT_TEAM_COLOUR[i]); + sbCount++; + } + + /* + // FIXME + maybe some colours on some columns to help differentiate them + If possible, have AFK/msg indicators + Reset between rounds + Make a summary one for end of game too + show who you are on scoreboard + show who you are speccing + when player comes in after caps occur, they aren't getting team score + +*/ + + for (float i = 0; i < sbCount; i++) + sui_pop_frame(); + sui_pop_frame(); } void (float show) FO_Show_Scores = { From 31b74aa67133879f1656cf8b089b98498c4b8e21 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Feb 2023 11:36:37 -0800 Subject: [PATCH 2027/2474] weapons: prevent recursive detpipe When a demoman dies, his pipebombs detonate. When a demoman detonates his pipebombs and kills themself... ... their pipebombs... detonate. You start to see the problem. Re-entrancy in death handling on self-detpipe would result in nested detpipe call, however, both the parent and child calls are working on the same pipe lists and so subsequent parent execution will result in a duplicate detonation for anything handled by the child. Resulting in spurious explosions at (0,0,0) when the removed ent is redetonated. Fix by preventing detpipe nesting; the second case will no longer trigger a second detpipe. --- ssqc/demoman.qc | 8 ++++++++ ssqc/qw.qc | 1 + 2 files changed, 9 insertions(+) diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index cb2b76eb..58584394 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -20,6 +20,12 @@ float (float force) TeamFortress_DetonatePipebombs = { if (time < self.pipecooldown && !force) return impulse_queue ? FALSE : TRUE; + if (self.detpipe_nesting > 0) + return TRUE; + // It's possible that we'll kill ourselves when we detonate pipebombs and + // initiate a nested det; exclude this to avoid iterating removed ents. + self.detpipe_nesting++; + int count; entity* pipes = find_list(classname, "pipebomb", EV_STRING, count); @@ -42,9 +48,11 @@ float (float force) TeamFortress_DetonatePipebombs = { } } + // NOTE: nested death-dets would not trigger double unwind due to `force==1` if (rewound) FOPlayer::RestoreAll(); + self.detpipe_nesting--; return TRUE; }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index ae15e338..482a81a4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -85,6 +85,7 @@ float remote_client_time(); .float vote_close; // TRUE if player has closed the map vote, resets on spawn .float detpack_left; // Seconds left to detpack explosion .float pipecooldown; // Time when detpipe command can be issued +.float detpipe_nesting; // Used to avoid recursive detpipes when detting self .float disguise_skin; // The skin the spy is changing to .float queue_skin; // The skin the spy will change to after team disguise is finished .float last_selected_skin; // The last skin the spy selected to disguise as From f1be2d246295c281898eca17aa429ee2a82d0ce6 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Feb 2023 11:49:23 -0800 Subject: [PATCH 2028/2474] weapons: add dynamic lights for rockets Restores dynamic light for soldier and pyro rockets. Can be enabled/disabled via `r_rocketlight 0/1` Appearance (color) can be controlled via `r_rocketlight_color`. [ Note: We ignore the radius specifier that can be embedded into color. ] --- csqc/weapon_predict.qc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2f971ed8..1cdacf85 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1130,7 +1130,13 @@ void FPP_Init(int fpp_type, entity proj) { DEFCVAR_FLOAT(r_rocketlight, 1); DEFCVAR_FLOAT(r_rocketlight, 1); -DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); +DEFCVAR_STRING(r_rocketlight_color, "2.0 1.0 0.25 200"); // Radius ignored. + +static float HasLight(int fpp_type) { + if (!CVARF(r_rocketlight)) + return FALSE; + return fpp_type == FPP_ROCKET || fpp_type == FPP_INCENDIARY; +} .float trail_started; float PP_PredrawActive() { @@ -1156,11 +1162,8 @@ float PP_PredrawActive() { self.oldorigin = self.origin; } -#if 0 // TODO - if (self.modelflags & MF_ROCKET && CVARF(r_rocketlight)) { - dynamiclight_add(self.origin, 200, CVARS(r_rocketlight_color), 0); - } -#endif + if (HasLight(self.fpp.index)) + dynamiclight_add(self.origin, 200, stov(CVARS(r_rocketlight_color))); return PREDRAW_AUTOADD; } From 446f8a64bc2448904a8aa46ec5bec7135acd020f Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Feb 2023 12:51:23 -0800 Subject: [PATCH 2029/2474] scoreboard: fix array length array for teams list was off-by-1 --- csqc/status.qc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 0c06ede4..c3345bac 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -858,12 +858,12 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel }; enum { - SC_BLUE, - SC_RED, - SC_YELLOW, - SC_GREEN, - SC_SPECS, - NUM_SC = SC_SPECS, + SCT_BLUE, + SCT_RED, + SCT_YELLOW, + SCT_GREEN, + SCT_SPECS, + NUM_SCT, }; struct FO_ScoreBoardTeam { @@ -872,7 +872,7 @@ struct FO_ScoreBoardTeam { }; struct FO_ScoreBoard { - FO_ScoreBoardTeam team[NUM_SC]; + FO_ScoreBoardTeam team[NUM_SCT]; }; static FO_ScoreBoard score_board; @@ -898,7 +898,7 @@ void drawShowScoresPanel(PanelID panelid, string text) { float i; - for (i = 0; i < NUM_SC; i++) + for (i = 0; i < NUM_SCT; i++) score_board.team[i].count = 0; sui_push_frame(position, [size.x, 1]); @@ -917,7 +917,7 @@ void drawShowScoresPanel(PanelID panelid, string text) { sbl_team_no -= 1; // Maps to SC enum break; default: - sbl_team_no = SC_SPECS; + sbl_team_no = SCT_SPECS; break; } @@ -943,7 +943,7 @@ void drawShowScoresPanel(PanelID panelid, string text) { sbl->ready = getplayerkeyfloat(i, "ready"); sbl->chat = getplayerkeyfloat(i, "chat"); - if (sbl_team_no == SC_SPECS) { + if (sbl_team_no == SCT_SPECS) { float spec = getplayerkeyfloat(i, "*spectator"); sbl->team_no = (spec == 1) ? TEAM_SPECTATOR : TEAM_OBSERVER; sbl->classtext = (spec == 1) ? "Spectator" : "Observer"; @@ -956,7 +956,7 @@ void drawShowScoresPanel(PanelID panelid, string text) { vector yspacer = [0, 20]; size_y = smalltext_y; - for (i = 0; i < NUM_SC; i++) { + for (i = 0; i < NUM_SCT; i++) { FO_ScoreBoardTeam* team = &score_board.team[i]; if (!team->count) continue; From ae8993ab51a868c673a3321d02eee50c8fd51594 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Feb 2023 14:12:40 -0800 Subject: [PATCH 2030/2474] scoreboard: fix second array length text_team_colour also needed extended for the spec team --- csqc/csextradefs.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6a9314f9..cab197df 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -38,7 +38,8 @@ vector TEXT_TEAM_COLOUR[] = { MENU_TEXT_BLUE_FO, MENU_TEXT_RED_FO, MENU_TEXT_YELLOW_FO, - MENU_TEXT_GREEN_FO + MENU_TEXT_GREEN_FO, + MENU_TEXT_SPEC_FO, }; const float DEFAULT_VIEWHEIGHT = 22; From d013e231489d0bd84f1f2d59260167f55dd668d6 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Feb 2023 21:16:16 -0800 Subject: [PATCH 2031/2474] scoreboard: bound iteration The scoreboard was previously trying to print every possible line for every team, this both added overhead and allowed for potential position reuse (since it could examine previously used slots and try to render them). Fix this by just using the count we already have. --- csqc/status.qc | 52 ++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index c3345bac..3149ba76 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -657,14 +657,34 @@ void (vector position, vector size, string val, vector textcolour, float alpha sui_text(position, size, val, textcolour, 1, 0); }; -vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel - , float padding, vector columnColour) drawShowScoresTeamPanel = { +enum { + SCT_BLUE, + SCT_RED, + SCT_YELLOW, + SCT_GREEN, + SCT_SPECS, + NUM_SCT, +}; + +struct FO_ScoreBoardTeam { + FO_ScoreBoardLine lines[FO_SCOREBOARDLINES_LENGTH]; + int count; +}; + +struct FO_ScoreBoard { + FO_ScoreBoardTeam team[NUM_SCT]; +}; + +static FO_ScoreBoard score_board; + +vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, + float padding, vector columnColour) { vector textcolour = MENU_TEXT_1; vector smalltext = MENU_TEXT_SMALL * panel.Scale; vector yspacer = [0, 20]; vector position = [0, 0]; vector size = getPanelFillSize(panel); - + position = [0,0]; sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); size = [size_x, smalltext_y]; @@ -677,7 +697,8 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel float classspace = strlen("class") * smalltext.x; - for (float i = 0; i < FO_ScoreBoardColumns.length; i++) { + FO_ScoreBoardLine* lines = &team->lines; + for (float i = 0; i < team->count; i++) { string colname = FO_ScoreBoardColumns[i]; if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) { switch (colname) { @@ -857,25 +878,6 @@ vector (FO_ScoreBoardLine *lines, FO_Hud_Panel *panel return position; }; -enum { - SCT_BLUE, - SCT_RED, - SCT_YELLOW, - SCT_GREEN, - SCT_SPECS, - NUM_SCT, -}; - -struct FO_ScoreBoardTeam { - FO_ScoreBoardLine lines[FO_SCOREBOARDLINES_LENGTH]; - int count; -}; - -struct FO_ScoreBoard { - FO_ScoreBoardTeam team[NUM_SCT]; -}; - -static FO_ScoreBoard score_board; void drawShowScoresPanel(PanelID panelid, string text) { FO_Hud_Panel* panel = getHudPanel(panelid); @@ -963,8 +965,8 @@ void drawShowScoresPanel(PanelID panelid, string text) { position += yspacer; sui_push_frame(position, size); - position = drawShowScoresTeamPanel(&team->lines, panel, - padding, TEXT_TEAM_COLOUR[i]); + position = drawShowScoresTeamPanel(panel, team, padding, + TEXT_TEAM_COLOUR[i]); sbCount++; } From f14833a8b9c32fe6b11d9d774b6083350464f5e6 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Feb 2023 21:28:08 -0800 Subject: [PATCH 2032/2474] events: clean up file newlines, misc brackets, indentation, etc --- ssqc/events.qc | 880 ++++++++++++++++++++++++------------------------- 1 file changed, 424 insertions(+), 456 deletions(-) diff --git a/ssqc/events.qc b/ssqc/events.qc index cf949a11..54ae3f70 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -1,456 +1,424 @@ -string (string text) clearString; -string (float tno) GetTeamName; - -float (entity player) isPlayerValid = { - if (player.has_disconnected == 1 - || !infokey(player, INFOKEY_P_USERID) - || infokey(player, INFOKEY_P_USERID) == "" - || !infokey(player, INFOKEY_P_NAME) - || infokey(player, INFOKEY_P_NAME) == "") { - return 0; - } - return 1; -} - -string () ISOTimemillis = { - local string padding = string_null; - local string timeuse = strftime(0,"%Y-%m-%dT%H:%M:%S."); - local float randmillis = rint((random()*1000*random())); - if (randmillis < 10) - padding = "00"; - else if (randmillis < 100) - padding = "0"; - local string padded = strcat(padding, ftos(randmillis)); - timeuse = strcat(timeuse, padded); - timeuse = strcat(timeuse, "Z"); - return timeuse; -} - -string (entity pl) getEntityNameOrLogin = { - if (loginRequired) - return pl.login; - else - return clearString(pl.netname); -} - -void (string evt) logevent = { - local string st = infokey (world, "event_debug"); - if (stof(st) > 0) { - bprint(PRINT_HIGH, evt, "\n"); - } - fputs(logfilehandle, evt); -} - -void (entity player) LogEventPlayerStart = { - if (canlog == 0) - return; - if (isPlayerValid(player) == FALSE) - return; - - local string event; - event = sprintf(",\n{\"type\": \"playerStart\", \"player\": \"%s\", \"classtime\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(player), ftos(player.classtime), ftos(gametime), gametimestamp); - logevent(event); -} - -void () LogEventGameStart = { - gametimestamp = ISOTimemillis(); - if (canlog == 0) - return; - local string event; - local entity player; - local float numplayers = 0; - player = find (world, classname, "player"); - - while (player) - { - if (isPlayerValid(player) == TRUE) - numplayers++; - player = find (player, classname, "player"); - } - - event = sprintf("{\"type\": \"gameStart\", \"map\": \"%s\", \"numPlayers\": %s, \"numTeams\": %s, \"time\": %s, \"demo\": \"%s\", \"gameTimeStamp\": \"%s\"}", mapname, ftos(numplayers), ftos(number_of_teams), ftos(gametime), cvar_string("serverdemo"), gametimestamp); - logevent(event); -} - -void (entity player, float previous, float next, float timeplayed) LogEventChangeClass = { - if (canlog == 0) - return; - if (isPlayerValid(player) == FALSE) - return; - if (previous == 0) { - return; - } - - local string event; - event = sprintf(",\n{\"type\": \"changeClass\", \"player\": \"%s\", \"playerClass\": %s, \"nextClass\": %s, \"team\": %s, \"timePlayed\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", - getEntityNameOrLogin(player), - ftos(previous), - ftos(next), - ftos(player.team_no), - ftos(timeplayed), - ftos(gametime), - gametimestamp - ); - logevent(event); -} - -string (float weapon) GetWeaponName = { - if (weapon >= 1 && weapon <= WEAP_LAST) { - string name = FO_GetWeapName(weapon); - name = strtolower(name); - name = strreplace(name, " ", ""); - return name; - } - - return "undefined"; -} - -void (entity attacker, entity target, string afflictionType) LogAffliction = { - if (attacker.classname == "player" && target.classname == "player") - { - if (attacker.team_no == target.team_no) - { - attacker.afflicted = attacker.afflicted + 1; - } - else - { - attacker.teamafflicted = attacker.teamafflicted + 1; - } - } -} - -void (entity attacker, entity target, entity inflictor, float damage, float truedam) LogEventDamage = { - if (!cb_prematch) - { - entity realattacker = attacker; - if (attacker.classname == "building_sentrygun" || attacker.classname == "building_dispenser") - { - realattacker = attacker.real_owner; - } - - if (realattacker.team_no != target.team_no) - { - if (realattacker != target && realattacker != target.real_owner) - { - if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) - { - realattacker.damagegiven = realattacker.damagegiven + truedam; - } - - if (target.classname == "player") - { - target.damagetaken = target.damagetaken + truedam; - } - } - } - } - - if (canlog == 0) - return; - - local string event; - local string attackEvent; - local string targetEvent; - local string part1attack; - local string part1target; - local string part2; - local string damageKind; - local string attackername; - local string targetname; - local string inflictorId; - - attackername = getEntityNameOrLogin(attacker); - targetname = getEntityNameOrLogin(target); - if (attacker == target) - damageKind = "self"; - else if (attacker.team_no == target.team_no) - damageKind = "team"; - else - damageKind = "enemy"; - - - if (inflictor.classname == "player") - inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); - else { - inflictorId = inflictor.classname; - if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { - inflictorId = "nailgrenspike"; - } - else if ((inflictor.classname == "spike") && (attacker.playerclass == 5)) { - inflictorId = "superspike"; - } - if (inflictorId == "worldspawn") - attackername = "world"; - else if (inflictorId == "building_sentrygun") { - attackername = getEntityNameOrLogin(attacker.real_owner); - if (damageKind == "damageTeam") - return; - } - else if (inflictorId == "grenade" && inflictor.fpp.gren_type >= GREN_FIRST) - inflictorId = FO_GrenDesc(inflictor.fpp.gren_type)->logname; - } - - - if (getEntityNameOrLogin(target) != "") { - part1attack = sprintf(",\n{\"type\": \"damageDone\", \"kind\": \"%s\", \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, \"target\": \"%s\", \"targetClass\": %s, \"targetTeam\": %s, ", - damageKind, - attackername, - ftos(attacker.playerclass), - ftos(attacker.team_no), - getEntityNameOrLogin(target), - ftos(target.playerclass), - ftos(target.team_no)); - part1target = sprintf(",\n{\"type\": \"damageTaken\", \"kind\": \"%s\", \"attacker\": \"%s\", \"attackerClass\": %s, \"attackerTeam\": %s, \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, ", - damageKind, - attackername, - ftos(attacker.playerclass), - ftos(attacker.team_no), - getEntityNameOrLogin(target), - ftos(target.playerclass), - ftos(target.team_no)); - - - part2 = sprintf("\"inflictor\": \"%s\", \"damage\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", - inflictorId, - ftos(damage), - ftos(gametime), - gametimestamp - ); - - attackEvent = strcat(part1attack, part2); - targetEvent = strcat(part1target, part2); - event = strcat(attackEvent, targetEvent); - logevent(event); - } -} - -void (entity attacker, entity target, entity inflictor) LogEventKill = { - if (!cb_prematch) - { - entity realattacker = attacker; - if (attacker.classname == "building_sentrygun" || attacker.classname == "building_dispenser") - { - realattacker = attacker.real_owner; - } - - if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) - { - if (realattacker != target && realattacker != target.real_owner) - { - if (realattacker.team_no == target.team_no) - { - realattacker.sbteamkills = realattacker.sbteamkills + 1; - } - else - { - realattacker.kills = realattacker.kills + 1; - } - } - - target.deaths = target.deaths + 1; - } - } - - if (canlog == 0) - return; - - if ((target.classname != "player") && (target.classname != "building_sentrygun")) - return; - - local string killKind; - local string attackername; - local string targetname; - local string inflictorId; - - attackername = getEntityNameOrLogin(attacker); - targetname = getEntityNameOrLogin(target); - if (attacker == target) - killKind = "self"; - else if (attacker.team_no == target.team_no) - killKind = "team"; - else - killKind = "enemy"; - - if (inflictor.classname == "player") - inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); - else { - inflictorId = inflictor.classname; - if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { - inflictorId = "nailgrenspike"; - } - else if ((inflictor.classname == "spike") && (attacker.playerclass == 5)) { - inflictorId = "superspike"; - } - if (inflictorId == "worldspawn") - attackername = "world"; - else if (inflictorId == "building_sentrygun") - attackername = getEntityNameOrLogin(attacker.real_owner); - else if (inflictorId == "grenade" && inflictor.fpp.gren_type >= GREN_FIRST) - inflictorId = FO_GrenDesc(inflictor.fpp.gren_type)->logname; - } - - local string event; - local string attackEvent; - local string targetEvent; - local string part1attack; - local string part1target; - local string part2; - - part1attack = sprintf(",\n{\"type\": \"kill\", \"kind\": \"%s\", \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, \"target\": \"%s\", \"targetClass\": %s, \"targetTeam\": %s, ", - killKind, - attackername, - ftos(attacker.playerclass), - ftos(attacker.team_no), - targetname, - ftos(target.playerclass), - ftos(target.team_no)); - part1target = sprintf(",\n{\"type\": \"death\", \"kind\": \"%s\", \"attacker\": \"%s\", \"attackerClass\": %s, \"attackerTeam\": %s, \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, ", - killKind, - attackername, - ftos(attacker.playerclass), - ftos(attacker.team_no), - targetname, - ftos(target.playerclass), - ftos(target.team_no)); - part2 = sprintf("\"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", - inflictorId, - ftos(gametime), - gametimestamp - ); - attackEvent = strcat(part1attack, part2); - targetEvent = strcat(part1target, part2); - event = strcat(attackEvent, targetEvent); - logevent(event); -} - -void (entity attacker, entity target, float tfstate) LogEventAffliction = { - if (attacker != target) - { - if (attacker.team_no == target.team_no) - { - attacker.teamafflicted = attacker.teamafflicted + 1; - } - else - { - attacker.afflicted = attacker.afflicted + 1; - } - } -}; - -void (entity player) LogEventGoal = { - if(player == world) - return; - player.caps = player.caps + 1; - if (canlog == 0) - return; - local string event; - event = sprintf(",\n{\"type\": \"goal\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", - ftos(player.team_no), - getEntityNameOrLogin(player), - ftos(player.playerclass), - ftos(gametime), - gametimestamp); - logevent(event); -} - - -void (entity player) LogEventPickupGoal = { - player.touches = player.touches + 1; - if (canlog == 0) - return; - local string event; - event = sprintf(",\n{\"type\": \"pickup\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", - ftos(player.team_no), - getEntityNameOrLogin(player), - ftos(player.playerclass), - ftos(gametime), - gametimestamp); - logevent(event); -} - -void (entity player, float timecarried) LogEventFumble = { - if (canlog == 0) - return; - local string event; - event = sprintf(",\n{\"type\": \"fumble\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"timeCarried\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", - ftos(player.team_no), - getEntityNameOrLogin(player), - ftos(player.playerclass), - ftos(timecarried), - ftos(gametime), - gametimestamp); - logevent(event); -} - -void (entity attacker) LogEventAttack = { - if (canlog == 0) - return; - local string event; - event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(FO_PlayerCurrentWeapon(attacker)), ftos(gametime), gametimestamp); - logevent(event); -} - -void () LogEventGameEnd = { - if (canlog == 0) - return; - local string event; - event = sprintf(",\n{\"type\": \"gameEnd\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", ftos(gametime), gametimestamp); - logevent(event); -} - -void () LogEventTeamScores = { - local float win_score = 0; - local float winning_team = 0; - - if (team1score > win_score) { - win_score = team1score; - winning_team = 1; - } - - if (team2score > win_score) { - win_score = team2score; - winning_team = 2; - } - else if (team2score == win_score) { - winning_team = 0; - } - - - if (team3score > win_score) { - win_score = team3score; - winning_team = 3; - } - else if (team3score == win_score) { - winning_team = 0; - } - - if (team4score > win_score) { - win_score = team4score; - winning_team = 4; - } - else if (team4score == win_score) { - winning_team = 0; - } - - local string teamscores; - teamscores = sprintf("\"team1Score\": %s", ftos(team1score)); - if (number_of_teams > 1) - teamscores = strcat(teamscores, sprintf(", \"team2Score\": %s", ftos(team2score))); - if (number_of_teams > 2) - teamscores = strcat(teamscores, sprintf(", \"team3Score\": %s", ftos(team3score))); - if (number_of_teams > 3) - teamscores = strcat(teamscores, sprintf(", \"team4Score\": %s", ftos(team4score))); - - local string teamnames; - teamnames = sprintf("\"team1Name\": \"%s\"", GetTeamName(1)); - if (number_of_teams > 1) - teamnames = strcat(teamnames, sprintf(", \"team2Name\": \"%s\"", GetTeamName(2))); - if (number_of_teams > 2) - teamnames = strcat(teamnames, sprintf(", \"team3Name\": \"%s\"", GetTeamName(3))); - if (number_of_teams > 3) - teamnames = strcat(teamnames, sprintf(", \"team4Name\": \"%s\"", GetTeamName(4))); - - local string event; - event = sprintf(",\n{\"type\": \"teamScores\", %s, %s, \"winningTeam\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", teamscores, teamnames, ftos(winning_team), ftos(gametime), gametimestamp); - logevent(event); -} +string (string text) clearString; +string (float tno) GetTeamName; + +float (entity player) isPlayerValid = { + if (player.has_disconnected == 1 + || !infokey(player, INFOKEY_P_USERID) + || infokey(player, INFOKEY_P_USERID) == "" + || !infokey(player, INFOKEY_P_NAME) + || infokey(player, INFOKEY_P_NAME) == "") { + return 0; + } + return 1; +} + +string () ISOTimemillis = { + string padding = string_null; + string timeuse = strftime(0,"%Y-%m-%dT%H:%M:%S."); + float randmillis = rint((random()*1000*random())); + if (randmillis < 10) + padding = "00"; + else if (randmillis < 100) + padding = "0"; + string padded = strcat(padding, ftos(randmillis)); + timeuse = strcat(timeuse, padded); + timeuse = strcat(timeuse, "Z"); + return timeuse; +} + +string (entity pl) getEntityNameOrLogin = { + if (loginRequired) + return pl.login; + else + return clearString(pl.netname); +} + +void (string evt) logevent = { + string st = infokey (world, "event_debug"); + if (stof(st) > 0) + bprint(PRINT_HIGH, evt, "\n"); + fputs(logfilehandle, evt); +} + +void (entity player) LogEventPlayerStart = { + if (canlog == 0) + return; + if (isPlayerValid(player) == FALSE) + return; + + string event; + event = sprintf(",\n{\"type\": \"playerStart\", \"player\": \"%s\", \"classtime\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(player), ftos(player.classtime), ftos(gametime), gametimestamp); + logevent(event); +} + +void () LogEventGameStart = { + gametimestamp = ISOTimemillis(); + if (canlog == 0) + return; + string event; + entity player; + float numplayers = 0; + player = find (world, classname, "player"); + + while (player) { + if (isPlayerValid(player) == TRUE) + numplayers++; + player = find (player, classname, "player"); + } + + event = sprintf("{\"type\": \"gameStart\", \"map\": \"%s\", \"numPlayers\": %s, \"numTeams\": %s, \"time\": %s, \"demo\": \"%s\", \"gameTimeStamp\": \"%s\"}", mapname, ftos(numplayers), ftos(number_of_teams), ftos(gametime), cvar_string("serverdemo"), gametimestamp); + logevent(event); +} + +void (entity player, float previous, float next, float timeplayed) LogEventChangeClass = { + if (canlog == 0) + return; + if (isPlayerValid(player) == FALSE) + return; + if (previous == 0) + return; + + string event; + event = sprintf(",\n{\"type\": \"changeClass\", \"player\": \"%s\", \"playerClass\": %s, \"nextClass\": %s, \"team\": %s, \"timePlayed\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", + getEntityNameOrLogin(player), + ftos(previous), + ftos(next), + ftos(player.team_no), + ftos(timeplayed), + ftos(gametime), + gametimestamp + ); + logevent(event); +} + +string (float weapon) GetWeaponName = { + if (weapon >= 1 && weapon <= WEAP_LAST) { + string name = FO_GetWeapName(weapon); + name = strtolower(name); + name = strreplace(name, " ", ""); + return name; + } + + return "undefined"; +} + +void (entity attacker, entity target, string afflictionType) LogAffliction = { + if (attacker.classname == "player" && target.classname == "player") { + if (attacker.team_no == target.team_no) + attacker.afflicted = attacker.afflicted + 1; + else + attacker.teamafflicted = attacker.teamafflicted + 1; + } +} + +void (entity attacker, entity target, entity inflictor, float damage, float truedam) LogEventDamage = { + if (!cb_prematch) { + entity realattacker = attacker; + if (attacker.classname == "building_sentrygun" || attacker.classname == "building_dispenser") + realattacker = attacker.real_owner; + + if (realattacker.team_no != target.team_no) { + if (realattacker != target && realattacker != target.real_owner) { + if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) + realattacker.damagegiven = realattacker.damagegiven + truedam; + + if (target.classname == "player") + target.damagetaken = target.damagetaken + truedam; + } + } + } + + if (canlog == 0) + return; + + string event; + string attackEvent; + string targetEvent; + string part1attack; + string part1target; + string part2; + string damageKind; + string attackername; + string targetname; + string inflictorId; + + attackername = getEntityNameOrLogin(attacker); + targetname = getEntityNameOrLogin(target); + if (attacker == target) + damageKind = "self"; + else if (attacker.team_no == target.team_no) + damageKind = "team"; + else + damageKind = "enemy"; + + + if (inflictor.classname == "player") { + inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); + } else { + inflictorId = inflictor.classname; + if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) + inflictorId = "nailgrenspike"; + else if ((inflictor.classname == "spike") && (attacker.playerclass == 5)) + inflictorId = "superspike"; + + if (inflictorId == "worldspawn") { + attackername = "world"; + } else if (inflictorId == "building_sentrygun") { + attackername = getEntityNameOrLogin(attacker.real_owner); + if (damageKind == "damageTeam") + return; + } + else if (inflictorId == "grenade" && inflictor.fpp.gren_type >= GREN_FIRST) + inflictorId = FO_GrenDesc(inflictor.fpp.gren_type)->logname; + } + + if (getEntityNameOrLogin(target) != "") { + part1attack = sprintf(",\n{\"type\": \"damageDone\", \"kind\": \"%s\", \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, \"target\": \"%s\", \"targetClass\": %s, \"targetTeam\": %s, ", + damageKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + getEntityNameOrLogin(target), + ftos(target.playerclass), + ftos(target.team_no)); + part1target = sprintf(",\n{\"type\": \"damageTaken\", \"kind\": \"%s\", \"attacker\": \"%s\", \"attackerClass\": %s, \"attackerTeam\": %s, \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, ", + damageKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + getEntityNameOrLogin(target), + ftos(target.playerclass), + ftos(target.team_no)); + + + part2 = sprintf("\"inflictor\": \"%s\", \"damage\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", + inflictorId, + ftos(damage), + ftos(gametime), + gametimestamp + ); + + attackEvent = strcat(part1attack, part2); + targetEvent = strcat(part1target, part2); + event = strcat(attackEvent, targetEvent); + logevent(event); + } +} + +void (entity attacker, entity target, entity inflictor) LogEventKill = { + if (!cb_prematch) { + entity realattacker = attacker; + if (attacker.classname == "building_sentrygun" || attacker.classname == "building_dispenser") + realattacker = attacker.real_owner; + + if (realattacker.classname == "player" && (target.classname == "player" || target.classname == "building_sentrygun")) { + if (realattacker != target && realattacker != target.real_owner) + { + if (realattacker.team_no == target.team_no) + realattacker.sbteamkills = realattacker.sbteamkills + 1; + else + realattacker.kills = realattacker.kills + 1; + } + + target.deaths = target.deaths + 1; + } + } + + if (canlog == 0) + return; + + if ((target.classname != "player") && (target.classname != "building_sentrygun")) + return; + + string killKind; + string attackername; + string targetname; + string inflictorId; + + attackername = getEntityNameOrLogin(attacker); + targetname = getEntityNameOrLogin(target); + if (attacker == target) + killKind = "self"; + else if (attacker.team_no == target.team_no) + killKind = "team"; + else + killKind = "enemy"; + + if (inflictor.classname == "player") { + inflictorId = GetWeaponName(FO_PlayerCurrentWeapon(attacker)); + } else { + inflictorId = inflictor.classname; + if ((inflictor.classname == "spike") && (attacker.playerclass == 3)) { + inflictorId = "nailgrenspike"; + } + else if ((inflictor.classname == "spike") && (attacker.playerclass == 5)) { + inflictorId = "superspike"; + } + + if (inflictorId == "worldspawn") + attackername = "world"; + else if (inflictorId == "building_sentrygun") + attackername = getEntityNameOrLogin(attacker.real_owner); + else if (inflictorId == "grenade" && inflictor.fpp.gren_type >= GREN_FIRST) + inflictorId = FO_GrenDesc(inflictor.fpp.gren_type)->logname; + } + + string event; + string attackEvent; + string targetEvent; + string part1attack; + string part1target; + string part2; + + part1attack = sprintf(",\n{\"type\": \"kill\", \"kind\": \"%s\", \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, \"target\": \"%s\", \"targetClass\": %s, \"targetTeam\": %s, ", + killKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + targetname, + ftos(target.playerclass), + ftos(target.team_no)); + part1target = sprintf(",\n{\"type\": \"death\", \"kind\": \"%s\", \"attacker\": \"%s\", \"attackerClass\": %s, \"attackerTeam\": %s, \"player\": \"%s\", \"playerClass\": %s, \"playerTeam\": %s, ", + killKind, + attackername, + ftos(attacker.playerclass), + ftos(attacker.team_no), + targetname, + ftos(target.playerclass), + ftos(target.team_no)); + part2 = sprintf("\"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", + inflictorId, + ftos(gametime), + gametimestamp + ); + attackEvent = strcat(part1attack, part2); + targetEvent = strcat(part1target, part2); + event = strcat(attackEvent, targetEvent); + logevent(event); +} + +void (entity attacker, entity target, float tfstate) LogEventAffliction = { + if (attacker != target) { + if (attacker.team_no == target.team_no) + attacker.teamafflicted = attacker.teamafflicted + 1; + else + attacker.afflicted = attacker.afflicted + 1; + } +}; + +void (entity player) LogEventGoal = { + if(player == world) + return; + + player.caps = player.caps + 1; + if (canlog == 0) + return; + + string event; + event = sprintf(",\n{\"type\": \"goal\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", + ftos(player.team_no), + getEntityNameOrLogin(player), + ftos(player.playerclass), + ftos(gametime), + gametimestamp); + logevent(event); +} + + +void (entity player) LogEventPickupGoal = { + player.touches = player.touches + 1; + if (canlog == 0) + return; + + string event; + event = sprintf(",\n{\"type\": \"pickup\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", + ftos(player.team_no), + getEntityNameOrLogin(player), + ftos(player.playerclass), + ftos(gametime), + gametimestamp); + logevent(event); +} + +void (entity player, float timecarried) LogEventFumble = { + if (canlog == 0) + return; + string event; + event = sprintf(",\n{\"type\": \"fumble\", \"team\": %s, \"player\": \"%s\", \"playerClass\": \"%s\", \"timeCarried\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", + ftos(player.team_no), + getEntityNameOrLogin(player), + ftos(player.playerclass), + ftos(timecarried), + ftos(gametime), + gametimestamp); + logevent(event); +} + +void (entity attacker) LogEventAttack = { + if (canlog == 0) + return; + string event; + event = sprintf(",\n{\"type\": \"attack\", \"player\": \"%s\", \"playerClass\": \"%s\", \"inflictor\": \"%s\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", getEntityNameOrLogin(attacker), ftos(attacker.playerclass), GetWeaponName(FO_PlayerCurrentWeapon(attacker)), ftos(gametime), gametimestamp); + logevent(event); +} + +void () LogEventGameEnd = { + if (canlog == 0) + return; + string event; + event = sprintf(",\n{\"type\": \"gameEnd\", \"time\": %s, \"gameTimeStamp\": \"%s\"}", ftos(gametime), gametimestamp); + logevent(event); +} + +void () LogEventTeamScores = { + float win_score = 0; + float winning_team = 0; + + if (team1score > win_score) { + win_score = team1score; + winning_team = 1; + } + + if (team2score > win_score) { + win_score = team2score; + winning_team = 2; + } else if (team2score == win_score) { + winning_team = 0; + } + + if (team3score > win_score) { + win_score = team3score; + winning_team = 3; + } else if (team3score == win_score) { + winning_team = 0; + } + + if (team4score > win_score) { + win_score = team4score; + winning_team = 4; + } else if (team4score == win_score) { + winning_team = 0; + } + + string teamscores; + teamscores = sprintf("\"team1Score\": %s", ftos(team1score)); + if (number_of_teams > 1) + teamscores = strcat(teamscores, sprintf(", \"team2Score\": %s", ftos(team2score))); + if (number_of_teams > 2) + teamscores = strcat(teamscores, sprintf(", \"team3Score\": %s", ftos(team3score))); + if (number_of_teams > 3) + teamscores = strcat(teamscores, sprintf(", \"team4Score\": %s", ftos(team4score))); + + string teamnames; + teamnames = sprintf("\"team1Name\": \"%s\"", GetTeamName(1)); + if (number_of_teams > 1) + teamnames = strcat(teamnames, sprintf(", \"team2Name\": \"%s\"", GetTeamName(2))); + if (number_of_teams > 2) + teamnames = strcat(teamnames, sprintf(", \"team3Name\": \"%s\"", GetTeamName(3))); + if (number_of_teams > 3) + teamnames = strcat(teamnames, sprintf(", \"team4Name\": \"%s\"", GetTeamName(4))); + + string event; + event = sprintf(",\n{\"type\": \"teamScores\", %s, %s, \"winningTeam\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", teamscores, teamnames, ftos(winning_team), ftos(gametime), gametimestamp); + logevent(event); +} From 1a8a0ba451404c1f7f9df47d5aedbab290a74d76 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Feb 2023 21:59:27 -0800 Subject: [PATCH 2033/2474] events: fix inflictors - Misordered args on string substitution were leading hitscan weapons to report null names. - Grenades were getting extra ' grenade' concatenation --- share/weapons.qc | 41 +++++++++++++++++++---------------------- ssqc/events.qc | 2 +- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/share/weapons.qc b/share/weapons.qc index ed732160..ff0c52ed 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -182,33 +182,32 @@ int TF_GREN_conv(int tf_gren) { struct FO_GrenInfo { int id; - string name; + string logname; string model; int skin; vector avelocity; // Automatically initialized below this line. float modelindex; - string logname; }; FO_GrenInfo fo_grenades[] = { - { GREN_NORMAL, "Grenade", "hgren2.mdl", 0, '300 300 300',}, - { GREN_CONC, "Concussion", "hgren2.mdl", 1, '300 300 300'}, - { GREN_BLAST, "Blast", "blastgren.mdl", 1, '300 300 300'}, - { GREN_NAIL, "Nail", "biggren.mdl", 1, '0 300 0'}, - { GREN_SHOCK, "Shock", "biggren.mdl", 1, '0 300 0'}, - { GREN_BURST, "Burst", "biggren.mdl", 1, '0 300 0'}, - { GREN_MIRV, "Mirv", "biggren.mdl", 0, '0 300 0'}, - { GREN_NAPALM, "Napalm", "biggren.mdl", 2, '0 300 0'}, - { GREN_FLARE, "Flare", "flare.mdl", 1, '300 300 300'}, - { GREN_GAS, "Gas", "grenade2.mdl", 3, '300 300 300'}, - { GREN_EMP, "EMP", "grenade2.mdl", 4, '300 300 300'}, - { GREN_FLASH, "Flash", "flashgren.mdl", 0, '300 300 300'}, - { GREN_CALTROP, "Caltrop", "", 0, '300 300 300'}, - { GREN_MIRVLET, "Mirvlet", "grenade2.mdl", 1, '250 300 400'}, - { GREN_RED, "Red", "grenade2.mdl", 1, '300 300 300'}, - { GREN_PIPE, "Pipe", "grenade2.mdl", 2, '300 300 300'}, + { GREN_NORMAL, "normal", "hgren2.mdl", 0, '300 300 300',}, + { GREN_CONC, "concussion", "hgren2.mdl", 1, '300 300 300'}, + { GREN_BLAST, "blast", "blastgren.mdl", 1, '300 300 300'}, + { GREN_NAIL, "nail", "biggren.mdl", 1, '0 300 0'}, + { GREN_SHOCK, "shock", "biggren.mdl", 1, '0 300 0'}, + { GREN_BURST, "burst", "biggren.mdl", 1, '0 300 0'}, + { GREN_MIRV, "mirv", "biggren.mdl", 0, '0 300 0'}, + { GREN_NAPALM, "napalm", "biggren.mdl", 2, '0 300 0'}, + { GREN_FLARE, "flare", "flare.mdl", 1, '300 300 300'}, + { GREN_GAS, "gas", "grenade2.mdl", 3, '300 300 300'}, + { GREN_EMP, "emp", "grenade2.mdl", 4, '300 300 300'}, + { GREN_FLASH, "flash", "flashgren.mdl", 0, '300 300 300'}, + { GREN_CALTROP, "caltrop", "", 0, '300 300 300'}, + { GREN_MIRVLET, "mirv", "grenade2.mdl", 1, '250 300 400'}, + { GREN_RED, "gl", "grenade2.mdl", 1, '300 300 300'}, + { GREN_PIPE, "pipe", "grenade2.mdl", 2, '300 300 300'}, }; enum { @@ -814,10 +813,8 @@ void FO_Weapons_Init() { FO_GrenInfo* gdesc = &fo_grenades[i]; ASSERTD_EQ(GREN_FIRST + i, gdesc->id); - if (gdesc->name != "") { - gdesc->name = strcat(gdesc->name, " grenade"); - gdesc->logname = strcat(strtolower(gdesc->name), "grenade"); - } + if (i < GREN_RED) + gdesc->logname = strcat(strtolower(gdesc->logname), "grenade"); if (gdesc->model != "") { gdesc->model = strcat("progs/", gdesc->model); diff --git a/ssqc/events.qc b/ssqc/events.qc index 54ae3f70..404470ec 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -95,7 +95,7 @@ string (float weapon) GetWeaponName = { if (weapon >= 1 && weapon <= WEAP_LAST) { string name = FO_GetWeapName(weapon); name = strtolower(name); - name = strreplace(name, " ", ""); + name = strreplace(" ", "", name); return name; } From ae75ff1b6fab3a886ba6e4e13e83a1fc674c88d2 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 23 Feb 2023 03:54:37 -0800 Subject: [PATCH 2034/2474] scoreboard: actually do what the last commit was supposed to do --- csqc/status.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 3149ba76..f0e70ec0 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -698,7 +698,7 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, float classspace = strlen("class") * smalltext.x; FO_ScoreBoardLine* lines = &team->lines; - for (float i = 0; i < team->count; i++) { + for (float i = 0; i < FO_ScoreBoardColumns.length; i++) { string colname = FO_ScoreBoardColumns[i]; if (lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER) { switch (colname) { @@ -723,7 +723,7 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, position = [0, smalltext.y]; float lineCount = 1; - for (float i = 0; i < FO_SCOREBOARDLINES_LENGTH; i++) { + for (float i = 0; i < team->count; i++) { string name = lines[i].name; if (!name) continue; From 5e44ee80ff5f34f87f7a861d828deb6f7a451e93 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 23 Feb 2023 16:45:34 -0800 Subject: [PATCH 2035/2474] hud render cache: bump size Now that we're rendering the scoreboard, there are potentially many more individual elements going into the cache; bump the capacity in case we're pushing near it. --- csqc/csextradefs.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index cab197df..c2f53ab6 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -556,9 +556,9 @@ struct { PanelID active_panel; float last_update; int draw_direct; - Draw_Args draw_cache[255]; + Draw_Args draw_cache[1000]; int draw_count; - float free_cache[255]; + float free_cache[1000]; int free_count; } hud_render_cache; From fb21b52b037cfdc2a3145f025267da8ebc434359 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 25 Feb 2023 15:58:41 +1100 Subject: [PATCH 2036/2474] WIP --- csqc/csextradefs.qc | 11 +++++++++ csqc/main.qc | 59 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 63a8974a..a7365a29 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -67,6 +67,11 @@ const vector PLAYER_MAXS = [16, 16, 32]; #define MAP_MAX_CHARS 20 +#define SLOT1 1 +#define SLOT2 2 +#define SLOT3 4 +#define SLOT4 8 + .void() removefunc; .float owned_by; .string netname; @@ -107,6 +112,8 @@ entity current_vote; string vote_list_filter; float oldbuttons; float zoomed_in; +float input_slots; +float oldslots; .string name; .string description; @@ -794,6 +801,10 @@ class CsGrenTimer { static CsGrenTimer() GetLast { return last_; }; }; + +// slot selection history +float slot_selection_history[10]; + // scoreboard stuff typedef struct { float ping; diff --git a/csqc/main.qc b/csqc/main.qc index 99c53550..7bb0eeef 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -45,6 +45,15 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_PP_Init(); // Some of this is always used by custom projectiles. CsGrenTimer::Init(); + registercommand("+zel1"); + registercommand("-zel1"); + registercommand("+zel2"); + registercommand("-zel2"); + registercommand("+zel3"); + registercommand("-zel3"); + registercommand("+zel4"); + registercommand("-zel4"); + registercommand("login"); registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); @@ -166,6 +175,30 @@ noref float(string cmd) CSQC_ConsoleCommand = { local float grentype; switch(argv(0)) { + case "+zel1": + input_slots |= SLOT1; + break; + case "-zel1": + input_slots &= ~SLOT1; + break; + case "+zel2": + input_slots |= SLOT2; + break; + case "-zel2": + input_slots &= ~SLOT2; + break; + case "+zel3": + input_slots |= SLOT3; + break; + case "-zel3": + input_slots &= ~SLOT3; + break; + case "+zel4": + input_slots |= SLOT4; + break; + case "-zel4": + input_slots &= ~SLOT4; + break; case "login": FoLogin(argv(1)); break; @@ -426,6 +459,32 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; noref void CSQC_Input_Frame() { + local float changed_slots = input_slots ^ oldslots; + oldslots = input_slots; + + local float slotdowns = changed_slots & input_buttons; + local float slotups = changed_slots & ~input_buttons; + + if (input_slots) + input_buttons |= BUTTON0; + + if (changed_slots & SLOT1) { + if (input_slots & SLOT1) + input_impulse = 1; + else + + if ((changed_slots & SLOT2) && (input_slots & SLOT2)) + input_impulse = 2; + if ((changed_slots & SLOT3) && (input_slots & SLOT3)) + input_impulse = 3; + if ((changed_slots & SLOT4) && (input_slots & SLOT4)) + input_impulse = 4; + + /* if ((changed_slots & SLOT1) && !(input_buttons & SLOT1)) */ + /* if ((changed_slots & SLOT2) && !(input_buttons & SLOT2)) */ + /* if ((changed_slots & SLOT3) && !(input_buttons & SLOT3)) */ + /* if ((changed_slots & SLOT4) && !(input_buttons & SLOT4)) */ + local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; From e255265432ed4b31755a42b868442284018c3281 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 25 Feb 2023 23:37:10 +1100 Subject: [PATCH 2037/2474] Update readme with new commands --- README.md | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e82637fb..8f773e5f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,33 @@ FortressOne Server ================== -New features ------- +New commands +------------ + +* `fo_hud_cache 1` less resource intensive hud +* `fo_hud_fps 60` set hud refresh rate +* `fo_grentimer_ping_frac 1` fraction of ping to correct for +* `fo_grentimer_nostack 0` when set, only play the oldest timer +* `fo_fte_hud 0` completely replace Quake engine hud with FO hud +* `fo_legacy_sbar 0` use oldschool Team Fortress status bar +* `fo_oldscoreboard 0` use oldschool Quake scoreboard +* `fo_adminrefresh 2` time in seconds for admin menu to refresh +* `fo_wpp_beta 0` client side weapon/projectile prediction +* `wpp_min_ping -1` minimum ping before `fo_wpp_beta` is enabled. -1 defaults to 40. +* `wpp_weap_predict -1` weapon prediction. 1 force on, 0 force off, -1 use fo_wpp_beta / server settings +* `wpp_proj_predict -1` projectile prediction. 1 force on, 0 force off, -1 use fo_wpp_beta / server settings +* `fo_client_sniper_sight 1` client side sniper dot +* `cl_p2r` for old weapon impulses +* `cl_r2g` for old weapon impulses +* `r_pyrotrail 0` +* `r_rockettrail 0` +* `r_grenadetrail 0` +* `wpp_phys_adv_ms 0` +* `wpp_phys_local_adv_ms 0` +* `wpp_setspeed 1` +* `wpp_debug 1` bitfield 0,1,2,4,8 for debugging +* `fo_phys_debug 1` bitfield 0,1 for debugging ---------------------------------- * Added in `fo_hittext_friendly 0` - setting to 1 shows text when damaging friendlys * Added in `fo_hittext_colour3 "1 0 0"` - colour of friendly hittext if fo_hittext_friendly is set to 1 (rgb 0-1) @@ -105,12 +128,12 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * CSQC - fo_menu_game in-game menu * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press * CSQC - fo_grentimersound grentimer.wav -* CSQC - fo_grentimervolume -* CSQC - fo_jumpvolume +* CSQC - fo_grentimervolume 1 +* CSQC - fo_jumpvolume 1 * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration * CSQC - fo_hud_editor to move panels and save to config -* CSQC - fo_csjumpsounds +* CSQC - fo_csjumpsounds 1 for client side jump sounds (not delayed by ping) * `info_empblock` has a new field `goal_effects`. Setting it to 16 will prevent it from blocking emps if there is a wall between it and the explosion. * New map point entity `info_empblock` with `t_length` field that specifies its radius of effect. An EMP explosion within a range of one will not go through walls. * Server option for duelmode to allow draws on a double-ko `localinfo duel_allow_draw 1`/`localinfo dad 1` (default 1) From 3a99ab8226d6468b85dce6483f1bc10181fe4c27 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Feb 2023 18:31:52 +1100 Subject: [PATCH 2038/2474] Refactor --- csqc/csextradefs.qc | 6 ++-- csqc/main.qc | 67 +++++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index a7365a29..20712a24 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -71,6 +71,7 @@ const vector PLAYER_MAXS = [16, 16, 32]; #define SLOT2 2 #define SLOT3 4 #define SLOT4 8 +#define MAX_SLOT_SELECTION_HISTORY_SIZE 10 .void() removefunc; .float owned_by; @@ -114,6 +115,8 @@ float oldbuttons; float zoomed_in; float input_slots; float oldslots; +float slot_selection_history[MAX_SLOT_SELECTION_HISTORY_SIZE]; +float slot_selection_history_top; .string name; .string description; @@ -802,9 +805,6 @@ class CsGrenTimer { }; -// slot selection history -float slot_selection_history[10]; - // scoreboard stuff typedef struct { float ping; diff --git a/csqc/main.qc b/csqc/main.qc index 7bb0eeef..d76a1fd2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -45,6 +45,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_PP_Init(); // Some of this is always used by custom projectiles. CsGrenTimer::Init(); + slot_selection_history_top = -1; + registercommand("+zel1"); registercommand("-zel1"); registercommand("+zel2"); @@ -458,6 +460,48 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; +void PushSlotSelection(float value) { + if (slot_selection_history_top == MAX_SLOT_SELECTION_HISTORY_SIZE) { + // Stack is full + return; + } + + slot_selection_history_top += 1; + slot_selection_history[slot_selection_history_top] = value; +} + +float PopSlotSelectionHistoryIf(float slot) { + if (slot_selection_history_top == -1) { + // Stack is empty + return -1; + } + + for (float i = slot_selection_history_top; i >= 0; i--) { + if (slot_selection_history[i] == slot) { + for (float j = i+1; j < MAX_SLOT_SELECTION_HISTORY_SIZE; j++) { + slot_selection_history[j-1] = slot_selection_history[j]; + } + + slot_selection_history_top--; + break; + } + } +} + +void Handle_Slot_Key(float slot, float impulse) { + if (input_slots & slot) { // slot keydown + PushSlotSelection(impulse); + input_impulse = impulse; + } else { // slot keyup + PopSlotSelectionHistoryIf(impulse); + if(slot_selection_history_top >= 0) { + input_impulse = slot_selection_history[slot_selection_history_top]; + } else { + input_impulse = default_weapon; + } + } +} + noref void CSQC_Input_Frame() { local float changed_slots = input_slots ^ oldslots; oldslots = input_slots; @@ -465,25 +509,14 @@ noref void CSQC_Input_Frame() { local float slotdowns = changed_slots & input_buttons; local float slotups = changed_slots & ~input_buttons; - if (input_slots) + if (input_slots) { // if using slots, you definitely should be shooting input_buttons |= BUTTON0; + } - if (changed_slots & SLOT1) { - if (input_slots & SLOT1) - input_impulse = 1; - else - - if ((changed_slots & SLOT2) && (input_slots & SLOT2)) - input_impulse = 2; - if ((changed_slots & SLOT3) && (input_slots & SLOT3)) - input_impulse = 3; - if ((changed_slots & SLOT4) && (input_slots & SLOT4)) - input_impulse = 4; - - /* if ((changed_slots & SLOT1) && !(input_buttons & SLOT1)) */ - /* if ((changed_slots & SLOT2) && !(input_buttons & SLOT2)) */ - /* if ((changed_slots & SLOT3) && !(input_buttons & SLOT3)) */ - /* if ((changed_slots & SLOT4) && !(input_buttons & SLOT4)) */ + if (changed_slots & SLOT1) { Handle_Slot_Key(SLOT1, 1); } + if (changed_slots & SLOT2) { Handle_Slot_Key(SLOT2, 2); } + if (changed_slots & SLOT3) { Handle_Slot_Key(SLOT3, 3); } + if (changed_slots & SLOT4) { Handle_Slot_Key(SLOT4, 4); } local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; From 4787e2c2e891d435da69e249a5ea27ba379e8b6b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Feb 2023 18:35:32 +1100 Subject: [PATCH 2039/2474] Refactor --- csqc/csextradefs.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1aa162ec..2c0e45e8 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -804,7 +804,6 @@ class CsGrenTimer { static CsGrenTimer() GetLast { return last_; }; }; - // scoreboard stuff struct FO_ScoreBoardLine{ float ping; From c75a7d61078bc5df9d457a8498339175ff84e050 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Feb 2023 18:54:30 +1100 Subject: [PATCH 2040/2474] Clean up default weapon stuff --- README.md | 2 +- csqc/main.qc | 6 ++++-- csqc/settings.qc | 1 + csqc/weapon_predict.qc | 5 ----- share/weapons.qc | 2 -- ssqc/actions.qc | 8 -------- ssqc/qw.qc | 1 - ssqc/tforthlp.qc | 2 -- ssqc/weapons.qc | 9 --------- 9 files changed, 6 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 8f773e5f..0f491b4c 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New commands ------------ +* `fo_default_weapon 0` default weapon when using +zelx binds * `fo_hud_cache 1` less resource intensive hud * `fo_hud_fps 60` set hud refresh rate * `fo_grentimer_ping_frac 1` fraction of ping to correct for @@ -178,7 +179,6 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * Prime/throw grenades with one button (/gren1 and /gren2). * Weapon slots (1-4) where 1 is always primary and 4 is always melee. * Quick attack aliases (+quick1-4 will switch weapon and fire). -* Set default weapon to select after firing (e.g. `setinfo default_weapon 1`). * Next/previous weapon (/weapprev and /weapnext). * Last weapon (/weaplast). * Remember current weapon and last weapon after dying. diff --git a/csqc/main.qc b/csqc/main.qc index 58341d25..b3302860 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -501,10 +501,12 @@ void Handle_Slot_Key(float slot, float impulse) { input_impulse = impulse; } else { // slot keyup PopSlotSelectionHistoryIf(impulse); - if(slot_selection_history_top >= 0) { + if (slot_selection_history_top >= 0) { input_impulse = slot_selection_history[slot_selection_history_top]; } else { - input_impulse = default_weapon; + if (CVARF(fo_default_weapon)) { + input_impulse = CVARF(fo_default_weapon); + } } } } diff --git a/csqc/settings.qc b/csqc/settings.qc index 3ede6f17..56a628ce 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -2,6 +2,7 @@ DEFCVAR_FLOAT(fo_grentimer, 2); // Sound + Ping adjust DEFCVAR_STRING(fo_grentimersound, "grentimer.wav"); DEFCVAR_FLOAT(fo_grentimervolume, 1); DEFCVAR_FLOAT(fo_oldscoreboard, 0); +DEFCVAR_FLOAT(fo_default_weapon, 0); DEFCVAR_FLOAT(fo_hitaudio_enabled, 1); DEFCVAR_FLOAT(fo_hitaudio_hurtself, 1); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 1cdacf85..f521a202 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -82,11 +82,6 @@ static float CalcPredEnabled(float current_enable, float server_disable, float server_enable, float client_value, float dependent_enabled, string* set_by) { - if (csqc_get_user_setting("dw", "default_weapon", "0")) { - *set_by = "[default_weapon unsupported, talk to newby to fix your " \ - "config to not need it]"; - return FALSE; - } if (!dependent_enabled) { // PP depends on WP, so !WP => !PP diff --git a/share/weapons.qc b/share/weapons.qc index ff0c52ed..23cb62d4 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -549,9 +549,7 @@ float FO_CanReload(Slot slot) { return FALSE; } -void () RestoreDefaultWeapon; void FO_ReloadSlot(Slot slot, float force) { - RestoreDefaultWeapon(); if (self.tfstate & TFSTATE_RELOADING || IsSlotNull(slot)) return; diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 42655930..5c58978d 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -466,13 +466,6 @@ void (entity pe_player, float f_type) CF_Identify = { } }; -void () RestoreDefaultWeapon = { - float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); - if (default_weapon >= 1 && default_weapon <= TF_NUM_SLOTS) { - W_ChangeWeaponSlot(MakeSlot(default_weapon)); - } -}; - void () TeamFortress_ReloadNext = { Slot slot = self.current_slot; @@ -481,7 +474,6 @@ void () TeamFortress_ReloadNext = { if (FO_CanReload(slot)) { FO_ReloadSlot(slot, FALSE); - RestoreDefaultWeapon(); return; } } while (!IsSameSlot(slot, self.current_slot)); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 482a81a4..65f57470 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -108,7 +108,6 @@ float remote_client_time(); .float building_percentage; // The building percentage shown in status bar .float fragstreak; // Frag streak .float caps; // Caps during this game -.float default_weapon; // Weapon to select when not firing .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 089aef5f..a869d546 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -90,8 +90,6 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("slot3", TF_IMPULSE_SLOT3, 0); TeamFortress_Alias("slot4", TF_IMPULSE_SLOT4, 0); - // you shouldn't use these in fte, use setinfo default_weapon and +quick instead - // leaving in to prevent breaking change TeamFortress_AliasString("+slot1", "impulse 20;+attack"); TeamFortress_AliasString("-slot1", "-attack;impulse 24"); TeamFortress_AliasString("+slot2", "impulse 21;+attack"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 23e3313b..422768e4 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2345,15 +2345,6 @@ void () ButtonFrame = { local float keydowns = changed_buttons & input_buttons; local float keyups = changed_buttons & ~input_buttons; - // +attack keyup - if (keyups & BUTTON0) { - local float default_weapon = FO_GetUserSetting(self, "default_weapon", "dw", "0"); - - if (default_weapon >= 1 && default_weapon <= 4) { - self.impulse = InputHandlePyroSlotSwap(self.playerclass, default_weapon); - } - } - // +special every frame if (input_buttons & BUTTON3) { if (!cb_prematch && !cease_fire) { From 2996dbe8969aed25b26bd9dc9177ff76934a0b14 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 26 Feb 2023 19:15:13 +1100 Subject: [PATCH 2041/2474] Unset last element of array when popping --- csqc/main.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/main.qc b/csqc/main.qc index b3302860..5108622f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -489,6 +489,7 @@ float PopSlotSelectionHistoryIf(float slot) { slot_selection_history[j-1] = slot_selection_history[j]; } + slot_selection_history[MAX_SLOT_SELECTION_HISTORY_SIZE-1] = 0; slot_selection_history_top--; break; } From 261727102482535d6f12fb75767cd97aa3611c73 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 27 Feb 2023 00:46:34 +1100 Subject: [PATCH 2042/2474] Refactor --- README.md | 3 +- csqc/csextradefs.qc | 7 -- csqc/main.qc | 151 ++++++++++++++++---------------------------- 3 files changed, 57 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index 0f491b4c..9da002d3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ FortressOne Server New commands ------------ -* `fo_default_weapon 0` default weapon when using +zelx binds +* `+slot n` bind. fires nth weapon +* `fo_default_weapon 0` default weapon when using `+slot` binds * `fo_hud_cache 1` less resource intensive hud * `fo_hud_fps 60` set hud refresh rate * `fo_grentimer_ping_frac 1` fraction of ping to correct for diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 2c0e45e8..6afefd74 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -68,10 +68,6 @@ const vector PLAYER_MAXS = [16, 16, 32]; #define MAP_MAX_CHARS 20 -#define SLOT1 1 -#define SLOT2 2 -#define SLOT3 4 -#define SLOT4 8 #define MAX_SLOT_SELECTION_HISTORY_SIZE 10 .void() removefunc; @@ -112,10 +108,7 @@ float vote_selected_index; float vote_list_offset; entity current_vote; string vote_list_filter; -float oldbuttons; float zoomed_in; -float input_slots; -float oldslots; float slot_selection_history[MAX_SLOT_SELECTION_HISTORY_SIZE]; float slot_selection_history_top; diff --git a/csqc/main.qc b/csqc/main.qc index 5108622f..a8885f3c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -22,6 +22,37 @@ void GetSelf() = { self = findfloat(world, entnum, player_localentnum); } +void PushToSlotSelectionHistory(float value) { + if (slot_selection_history_top >= MAX_SLOT_SELECTION_HISTORY_SIZE) { + // Stack is full + return; + } + + slot_selection_history_top += 1; + print(sprintf("slot_selection_history_top: %f\n", slot_selection_history_top)); + slot_selection_history[slot_selection_history_top] = value; +} + +float RemoveSlotFromSelectionHistory(float slot) { + if (slot_selection_history_top == -1) { + // Stack is empty + return -1; + } + + for (float i = slot_selection_history_top; i >= 0; i--) { + if (slot_selection_history[i] == slot) { + for (float j = i+1; j < MAX_SLOT_SELECTION_HISTORY_SIZE; j++) { + slot_selection_history[j-1] = slot_selection_history[j]; + } + + slot_selection_history[MAX_SLOT_SELECTION_HISTORY_SIZE-1] = 0; + slot_selection_history_top--; + break; + } + } +} + + DECLARE_PERF_SAMPLER(frame_timing, 60, 0.1); DECLARE_PERF_SAMPLER(hud_timing, 60, 0.1); DECLARE_PERF_SAMPLER(hud_partial_timing, 60, 0.1); @@ -49,14 +80,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { slot_selection_history_top = -1; - registercommand("+zel1"); - registercommand("-zel1"); - registercommand("+zel2"); - registercommand("-zel2"); - registercommand("+zel3"); - registercommand("-zel3"); - registercommand("+zel4"); - registercommand("-zel4"); + registercommand("+slot"); + registercommand("-slot"); registercommand("login"); registercommand("fo_hud_editor"); @@ -174,6 +199,24 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { recent_pmove_vel_z = pmove_vel_z; } +void Slot_Keydown(float slot) { + PushToSlotSelectionHistory(slot); + localcmd(sprintf("impulse %f\n", slot)); + localcmd("+attack\n"); +} + +void Slot_Keyup(float slot) { + RemoveSlotFromSelectionHistory(slot); + if (slot_selection_history_top >= 0) { + localcmd(sprintf("impulse %f\n", slot_selection_history[slot_selection_history_top])); + } else { + if (CVARF(fo_default_weapon)) { + localcmd(sprintf("impulse %f\n", CVARF(fo_default_weapon))); + } + localcmd("-attack\n"); + } +} + noref float(string cmd) CSQC_ConsoleCommand = { tokenize_console(cmd); float val; @@ -181,29 +224,11 @@ noref float(string cmd) CSQC_ConsoleCommand = { local float grentype; switch(argv(0)) { - case "+zel1": - input_slots |= SLOT1; - break; - case "-zel1": - input_slots &= ~SLOT1; - break; - case "+zel2": - input_slots |= SLOT2; - break; - case "-zel2": - input_slots &= ~SLOT2; - break; - case "+zel3": - input_slots |= SLOT3; - break; - case "-zel3": - input_slots &= ~SLOT3; - break; - case "+zel4": - input_slots |= SLOT4; + case "+slot": + Slot_Keydown(stof(argv(1))); break; - case "-zel4": - input_slots &= ~SLOT4; + case "-slot": + Slot_Keyup(stof(argv(1))); break; case "login": FoLogin(argv(1)); @@ -467,73 +492,7 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; -void PushSlotSelection(float value) { - if (slot_selection_history_top == MAX_SLOT_SELECTION_HISTORY_SIZE) { - // Stack is full - return; - } - - slot_selection_history_top += 1; - slot_selection_history[slot_selection_history_top] = value; -} - -float PopSlotSelectionHistoryIf(float slot) { - if (slot_selection_history_top == -1) { - // Stack is empty - return -1; - } - - for (float i = slot_selection_history_top; i >= 0; i--) { - if (slot_selection_history[i] == slot) { - for (float j = i+1; j < MAX_SLOT_SELECTION_HISTORY_SIZE; j++) { - slot_selection_history[j-1] = slot_selection_history[j]; - } - - slot_selection_history[MAX_SLOT_SELECTION_HISTORY_SIZE-1] = 0; - slot_selection_history_top--; - break; - } - } -} - -void Handle_Slot_Key(float slot, float impulse) { - if (input_slots & slot) { // slot keydown - PushSlotSelection(impulse); - input_impulse = impulse; - } else { // slot keyup - PopSlotSelectionHistoryIf(impulse); - if (slot_selection_history_top >= 0) { - input_impulse = slot_selection_history[slot_selection_history_top]; - } else { - if (CVARF(fo_default_weapon)) { - input_impulse = CVARF(fo_default_weapon); - } - } - } -} - noref void CSQC_Input_Frame() { - local float changed_slots = input_slots ^ oldslots; - oldslots = input_slots; - - local float slotdowns = changed_slots & input_buttons; - local float slotups = changed_slots & ~input_buttons; - - if (input_slots) { // if using slots, you definitely should be shooting - input_buttons |= BUTTON0; - } - - if (changed_slots & SLOT1) { Handle_Slot_Key(SLOT1, 1); } - if (changed_slots & SLOT2) { Handle_Slot_Key(SLOT2, 2); } - if (changed_slots & SLOT3) { Handle_Slot_Key(SLOT3, 3); } - if (changed_slots & SLOT4) { Handle_Slot_Key(SLOT4, 4); } - - local float changed_buttons = input_buttons ^ oldbuttons; - oldbuttons = input_buttons; - - local float keydowns = changed_buttons & input_buttons; - local float keyups = changed_buttons & ~input_buttons; - Sync_GameState(); // Intercept rocket jump; From 5b60c3b34b4868aff7863201462aeff7eee394e7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 27 Feb 2023 00:49:11 +1100 Subject: [PATCH 2043/2474] remove debug statement --- csqc/main.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index a8885f3c..4352c176 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -29,7 +29,6 @@ void PushToSlotSelectionHistory(float value) { } slot_selection_history_top += 1; - print(sprintf("slot_selection_history_top: %f\n", slot_selection_history_top)); slot_selection_history[slot_selection_history_top] = value; } @@ -207,7 +206,7 @@ void Slot_Keydown(float slot) { void Slot_Keyup(float slot) { RemoveSlotFromSelectionHistory(slot); - if (slot_selection_history_top >= 0) { + if (slot_selection_history_top >= 0) { // still holding another +slot bind localcmd(sprintf("impulse %f\n", slot_selection_history[slot_selection_history_top])); } else { if (CVARF(fo_default_weapon)) { From 7740478824af783234c21f4ee559d69acf222b10 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 27 Feb 2023 01:04:20 +1100 Subject: [PATCH 2044/2474] Less verbose --- csqc/csextradefs.qc | 6 +++--- csqc/main.qc | 34 +++++++++++++++++----------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6afefd74..24505443 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -68,7 +68,7 @@ const vector PLAYER_MAXS = [16, 16, 32]; #define MAP_MAX_CHARS 20 -#define MAX_SLOT_SELECTION_HISTORY_SIZE 10 +#define MAX_SLOT_HISTORY_SIZE 10 .void() removefunc; .float owned_by; @@ -109,8 +109,8 @@ float vote_list_offset; entity current_vote; string vote_list_filter; float zoomed_in; -float slot_selection_history[MAX_SLOT_SELECTION_HISTORY_SIZE]; -float slot_selection_history_top; +float slot_history[MAX_SLOT_HISTORY_SIZE]; +float slot_history_top; .string name; .string description; diff --git a/csqc/main.qc b/csqc/main.qc index 4352c176..e124cf9a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -22,30 +22,30 @@ void GetSelf() = { self = findfloat(world, entnum, player_localentnum); } -void PushToSlotSelectionHistory(float value) { - if (slot_selection_history_top >= MAX_SLOT_SELECTION_HISTORY_SIZE) { +void PushToSlotHistory(float value) { + if (slot_history_top >= MAX_SLOT_HISTORY_SIZE) { // Stack is full return; } - slot_selection_history_top += 1; - slot_selection_history[slot_selection_history_top] = value; + slot_history_top += 1; + slot_history[slot_history_top] = value; } -float RemoveSlotFromSelectionHistory(float slot) { - if (slot_selection_history_top == -1) { +float RemoveFromSlotHistory(float slot) { + if (slot_history_top == -1) { // Stack is empty return -1; } - for (float i = slot_selection_history_top; i >= 0; i--) { - if (slot_selection_history[i] == slot) { - for (float j = i+1; j < MAX_SLOT_SELECTION_HISTORY_SIZE; j++) { - slot_selection_history[j-1] = slot_selection_history[j]; + for (float i = slot_history_top; i >= 0; i--) { + if (slot_history[i] == slot) { + for (float j = i+1; j < MAX_SLOT_HISTORY_SIZE; j++) { + slot_history[j-1] = slot_history[j]; } - slot_selection_history[MAX_SLOT_SELECTION_HISTORY_SIZE-1] = 0; - slot_selection_history_top--; + slot_history[MAX_SLOT_HISTORY_SIZE-1] = 0; + slot_history_top--; break; } } @@ -77,7 +77,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_PP_Init(); // Some of this is always used by custom projectiles. CsGrenTimer::Init(); - slot_selection_history_top = -1; + slot_history_top = -1; registercommand("+slot"); registercommand("-slot"); @@ -199,15 +199,15 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } void Slot_Keydown(float slot) { - PushToSlotSelectionHistory(slot); + PushToSlotHistory(slot); localcmd(sprintf("impulse %f\n", slot)); localcmd("+attack\n"); } void Slot_Keyup(float slot) { - RemoveSlotFromSelectionHistory(slot); - if (slot_selection_history_top >= 0) { // still holding another +slot bind - localcmd(sprintf("impulse %f\n", slot_selection_history[slot_selection_history_top])); + RemoveFromSlotHistory(slot); + if (slot_history_top >= 0) { // still holding another +slot bind + localcmd(sprintf("impulse %f\n", slot_history[slot_history_top])); } else { if (CVARF(fo_default_weapon)) { localcmd(sprintf("impulse %f\n", CVARF(fo_default_weapon))); From f19656fbbbb0e3bbdf52b072fd4fccd4402dd29f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 1 Mar 2023 21:21:53 +1100 Subject: [PATCH 2045/2474] Make sure login is required before rejecting a reconnected --- ssqc/tforttm.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 08dc6aaf..20bc27c2 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -295,7 +295,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options }; float (float tno) TeamFortress_TeamSet = { - if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login) { + if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login && foLoginRequired) { sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or see fortressone.org\n"); return 0; } From f7c79de294f53b2b9b51891dbe66265a30cfa5fa Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 8 Mar 2023 23:38:49 -0800 Subject: [PATCH 2046/2474] impulse: remove legacy QUICKSLOT/QUICKSTOP This was a rat's nest of a state machine which required a bunch of unpleasant translation, state tracking, and handling. Replace with direct invocation of the native slot and weaplast, which gets rid of all special handling of +slot on client and server. --- csqc/weapon_predict.qc | 25 ------------------------- share/defs.h | 11 +++++------ ssqc/tforthlp.qc | 16 ++++++++-------- ssqc/weapons.qc | 25 ------------------------- 4 files changed, 13 insertions(+), 64 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f521a202..e91e0e78 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -658,9 +658,6 @@ static void WP_ChangeIfQueued() { void WP_Impulse() { WP_HandleHeavyInputs(); - // Note: We might have no impulse, but a queued slot here. - float quick_swap = FALSE; - // Impulses that are NOT held by attack_finished / reloading. float match = TRUE; switch (pstate_pred.impulse) { @@ -700,25 +697,14 @@ void WP_Impulse() { WP_ReloadNext(); break; - case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: - pstate_pred.impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. - quick_swap = TRUE; case 1: case 2: case 3: case 4: case 5: case 6: case 7: { Slot slot = InputToSlot(pstate_pred.impulse); if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) { - if (quick_swap) - pstate_pred.tfstate |= TFSTATE_QUICKSLOT; pstate_pred.queue_slot = slot; } break; } - case TF_QUICKSTOP: - if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) { - pstate_pred.impulse = 0; - break; - } - pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. case TF_WEAPLAST: pstate_pred.queue_slot = pstate_pred.last_slot; break; @@ -1186,17 +1172,6 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.owner = pengine.player_ent; FPP_Init(fpp_type, proj); -#if 0 - // Packet loss doesnt guarantee the server will actually register quickslot - // since it's a separate command from the attack. We can improve this in the - // future via either a button or just combining them on an impulse. But for - // now just dont create the projectile, it's usually swapping to a hitscan - // weapon anyway. - if (pstate_pred.tfstate & TFSTATE_QUICKSLOT && - !(pstate_server.tfstate & TFSTATE_QUICKSLOT)) - return __NULL__; -#endif - ProjectResult push_t = Forward_ProjectOffset(fpp_type, interp_ms()); // Using interp_ms() to predict which packet it will arrive in, while using diff --git a/share/defs.h b/share/defs.h index 61aa3433..275925ee 100644 --- a/share/defs.h +++ b/share/defs.h @@ -252,7 +252,6 @@ enumflags { // (Note: We don't use NO_WEAPON for reloading // as it could result in stacked no-weapon states.) TFSTATE_FLASHED, - TFSTATE_QUICKSLOT, // QUICKSTOP should change to last weapon. TFSTATE_AC_SPINUP, // These cover the 3 assault cannon states. TFSTATE_AC_SPINNING, TFSTATE_AC_SPINDOWN, @@ -418,11 +417,11 @@ struct Slot { int id; }; #define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) #define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) #define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 -#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon -#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon -#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon -#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon -#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped +// unused 20 +// unused 21 +// unused 22 +// unused 23 +// unused 24 #define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 #define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 #define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index a869d546..01b8e563 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -90,14 +90,14 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("slot3", TF_IMPULSE_SLOT3, 0); TeamFortress_Alias("slot4", TF_IMPULSE_SLOT4, 0); - TeamFortress_AliasString("+slot1", "impulse 20;+attack"); - TeamFortress_AliasString("-slot1", "-attack;impulse 24"); - TeamFortress_AliasString("+slot2", "impulse 21;+attack"); - TeamFortress_AliasString("-slot2", "-attack;impulse 24"); - TeamFortress_AliasString("+slot3", "impulse 22;+attack"); - TeamFortress_AliasString("-slot3", "-attack;impulse 24"); - TeamFortress_AliasString("+slot4", "impulse 23;+attack"); - TeamFortress_AliasString("-slot4", "-attack;impulse 24"); + TeamFortress_AliasString("+slot1", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT1)); + TeamFortress_AliasString("-slot1", sprintf("-attack;impulse %d", TF_WEAPLAST)); + TeamFortress_AliasString("+slot2", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT2)); + TeamFortress_AliasString("-slot2", sprintf("-attack;impulse %d", TF_WEAPLAST)); + TeamFortress_AliasString("+slot3", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT3)); + TeamFortress_AliasString("-slot3", sprintf("-attack;impulse %d", TF_WEAPLAST)); + TeamFortress_AliasString("+slot4", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT4)); + TeamFortress_AliasString("-slot4", sprintf("-attack;impulse %d", TF_WEAPLAST)); } else if (self.motd == 30) { if(csqcactive) { TeamFortress_AliasString("changeteam", "fo_menu_team"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 422768e4..f32675fe 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2543,18 +2543,6 @@ void () W_WeaponFrame = { self.impulse = 0; } - // +slot/-slot handle attack; we only need to swap back to last weapon. - // Let's see if we can get away with just treating this as last weapon; - // there were already so many edge cases in the old code such as swapping on - // an empty weapon. - if (self.impulse == TF_QUICKSTOP) { - if (self.tfstate & TFSTATE_QUICKSLOT) - self.impulse = TF_WEAPLAST; - else - self.impulse = 0; - self.tfstate &= ~TFSTATE_QUICKSLOT; - } - float can_change_weapon = WeaponReady(); // TODO: Open up queueing by moving queue can_change to ChangeWeapon? @@ -2566,19 +2554,6 @@ void () W_WeaponFrame = { // slot 1-4 (or 1-7) binds W_ChangeWeaponByInput(self.impulse); self.impulse = 0; - } else if (self.impulse >= TF_QUICKSLOT1 && - self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { - float input = InputHandlePyroSlotSwap(self.playerclass, - self.impulse - TF_QUICKSLOT1 + 1); - Slot slot = MakeSlot(input); - - if (IsSameSlot(slot, self.current_slot)) { - self.tfstate &= ~TFSTATE_QUICKSLOT; - } else { - self.tfstate |= TFSTATE_QUICKSLOT; - W_ChangeWeaponSlot(slot); - } - self.impulse = 0; } if (self.impulse == TF_CHANGETEAM) { From 29e2dc40172692bbe52d749986dcdd62c720b4d1 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 10 Mar 2023 16:16:30 -0800 Subject: [PATCH 2047/2474] Revert "impulse: remove legacy QUICKSLOT/QUICKSTOP" People still depend on the +slot specific weaplast behavior This reverts commit f7c79de294f53b2b9b51891dbe66265a30cfa5fa. --- csqc/weapon_predict.qc | 25 +++++++++++++++++++++++++ share/defs.h | 11 ++++++----- ssqc/tforthlp.qc | 16 ++++++++-------- ssqc/weapons.qc | 25 +++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index e91e0e78..f521a202 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -658,6 +658,9 @@ static void WP_ChangeIfQueued() { void WP_Impulse() { WP_HandleHeavyInputs(); + // Note: We might have no impulse, but a queued slot here. + float quick_swap = FALSE; + // Impulses that are NOT held by attack_finished / reloading. float match = TRUE; switch (pstate_pred.impulse) { @@ -697,14 +700,25 @@ void WP_Impulse() { WP_ReloadNext(); break; + case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: + pstate_pred.impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. + quick_swap = TRUE; case 1: case 2: case 3: case 4: case 5: case 6: case 7: { Slot slot = InputToSlot(pstate_pred.impulse); if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) { + if (quick_swap) + pstate_pred.tfstate |= TFSTATE_QUICKSLOT; pstate_pred.queue_slot = slot; } break; } + case TF_QUICKSTOP: + if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) { + pstate_pred.impulse = 0; + break; + } + pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. case TF_WEAPLAST: pstate_pred.queue_slot = pstate_pred.last_slot; break; @@ -1172,6 +1186,17 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.owner = pengine.player_ent; FPP_Init(fpp_type, proj); +#if 0 + // Packet loss doesnt guarantee the server will actually register quickslot + // since it's a separate command from the attack. We can improve this in the + // future via either a button or just combining them on an impulse. But for + // now just dont create the projectile, it's usually swapping to a hitscan + // weapon anyway. + if (pstate_pred.tfstate & TFSTATE_QUICKSLOT && + !(pstate_server.tfstate & TFSTATE_QUICKSLOT)) + return __NULL__; +#endif + ProjectResult push_t = Forward_ProjectOffset(fpp_type, interp_ms()); // Using interp_ms() to predict which packet it will arrive in, while using diff --git a/share/defs.h b/share/defs.h index 275925ee..61aa3433 100644 --- a/share/defs.h +++ b/share/defs.h @@ -252,6 +252,7 @@ enumflags { // (Note: We don't use NO_WEAPON for reloading // as it could result in stacked no-weapon states.) TFSTATE_FLASHED, + TFSTATE_QUICKSLOT, // QUICKSTOP should change to last weapon. TFSTATE_AC_SPINUP, // These cover the 3 assault cannon states. TFSTATE_AC_SPINNING, TFSTATE_AC_SPINDOWN, @@ -417,11 +418,11 @@ struct Slot { int id; }; #define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) #define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) #define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 -// unused 20 -// unused 21 -// unused 22 -// unused 23 -// unused 24 +#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon +#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon +#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon +#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon +#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped #define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 #define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 #define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index 01b8e563..a869d546 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -90,14 +90,14 @@ void () TeamFortress_MOTD = { TeamFortress_Alias("slot3", TF_IMPULSE_SLOT3, 0); TeamFortress_Alias("slot4", TF_IMPULSE_SLOT4, 0); - TeamFortress_AliasString("+slot1", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT1)); - TeamFortress_AliasString("-slot1", sprintf("-attack;impulse %d", TF_WEAPLAST)); - TeamFortress_AliasString("+slot2", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT2)); - TeamFortress_AliasString("-slot2", sprintf("-attack;impulse %d", TF_WEAPLAST)); - TeamFortress_AliasString("+slot3", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT3)); - TeamFortress_AliasString("-slot3", sprintf("-attack;impulse %d", TF_WEAPLAST)); - TeamFortress_AliasString("+slot4", sprintf("impulse %d;+attack", TF_IMPULSE_SLOT4)); - TeamFortress_AliasString("-slot4", sprintf("-attack;impulse %d", TF_WEAPLAST)); + TeamFortress_AliasString("+slot1", "impulse 20;+attack"); + TeamFortress_AliasString("-slot1", "-attack;impulse 24"); + TeamFortress_AliasString("+slot2", "impulse 21;+attack"); + TeamFortress_AliasString("-slot2", "-attack;impulse 24"); + TeamFortress_AliasString("+slot3", "impulse 22;+attack"); + TeamFortress_AliasString("-slot3", "-attack;impulse 24"); + TeamFortress_AliasString("+slot4", "impulse 23;+attack"); + TeamFortress_AliasString("-slot4", "-attack;impulse 24"); } else if (self.motd == 30) { if(csqcactive) { TeamFortress_AliasString("changeteam", "fo_menu_team"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f32675fe..422768e4 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2543,6 +2543,18 @@ void () W_WeaponFrame = { self.impulse = 0; } + // +slot/-slot handle attack; we only need to swap back to last weapon. + // Let's see if we can get away with just treating this as last weapon; + // there were already so many edge cases in the old code such as swapping on + // an empty weapon. + if (self.impulse == TF_QUICKSTOP) { + if (self.tfstate & TFSTATE_QUICKSLOT) + self.impulse = TF_WEAPLAST; + else + self.impulse = 0; + self.tfstate &= ~TFSTATE_QUICKSLOT; + } + float can_change_weapon = WeaponReady(); // TODO: Open up queueing by moving queue can_change to ChangeWeapon? @@ -2554,6 +2566,19 @@ void () W_WeaponFrame = { // slot 1-4 (or 1-7) binds W_ChangeWeaponByInput(self.impulse); self.impulse = 0; + } else if (self.impulse >= TF_QUICKSLOT1 && + self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { + float input = InputHandlePyroSlotSwap(self.playerclass, + self.impulse - TF_QUICKSLOT1 + 1); + Slot slot = MakeSlot(input); + + if (IsSameSlot(slot, self.current_slot)) { + self.tfstate &= ~TFSTATE_QUICKSLOT; + } else { + self.tfstate |= TFSTATE_QUICKSLOT; + W_ChangeWeaponSlot(slot); + } + self.impulse = 0; } if (self.impulse == TF_CHANGETEAM) { From 556776f331d0dd70fddf8caf67b160cc28edeed0 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 10 Mar 2023 16:15:54 -0800 Subject: [PATCH 2048/2474] HUD: Add a speedbar - Adds support for a speedbar (similar to ezhud) to the native FO hud. - Fix the text-only FTE speed display to not count zvel --- csqc/csextradefs.qc | 1 + csqc/hud.qc | 5 +++ csqc/status.qc | 81 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 24505443..53379895 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -456,6 +456,7 @@ enum PanelID:float { HUDP_GUN7, HUDP_GUN8, HUDP_SPEED, + HUDP_SPEEDBAR, HUDP_OPTIONS, // Should be the last HUD element so that it's always on top. HUDP_LAST = HUDP_OPTIONS, diff --git a/csqc/hud.qc b/csqc/hud.qc index 57d1b804..d0e685a0 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -50,6 +50,11 @@ void FO_Hud_Editor_LoadDefaultSettings() getHudPanel(HUDP_MAP_MENU)->Position = [(width / 2) - (getHudPanel(HUDP_MAP_MENU)->FillSize.x / 2), 30]; getHudPanel(HUDP_MAP_MENU)->Scale = 1.00; getHudPanel(HUDP_MAP_MENU)->Display = 0; + + getHudPanel(HUDP_SPEEDBAR)->Display = 0; + getHudPanel(HUDP_SPEEDBAR)->Scale = 1.00; + getHudPanel(HUDP_SPEEDBAR)->Snap = HUD_SNAP_CENTER; + getHudPanel(HUDP_SPEEDBAR)->Position = [0, 30]; } void FO_Hud_Editor_List_Panels() = { diff --git a/csqc/status.qc b/csqc/status.qc index f0e70ec0..769f0961 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -992,6 +992,84 @@ void (float show) FO_Show_Scores = { getHudPanel(HUDP_SHOWSCORES)->Display = show; }; +struct SpeedBarColors { + float max_speed; + float frac; + vector color; +}; + +const float SPEEDBAR_MAX = 3000; +static SpeedBarColors speedbar_colors[] = { + { 300, 0.40, '0.6 0.2 0.2'}, + { 400, 0.10, '0.7 0.2 0.2'}, + { 500, 0.25, '0.7 0.4 0.2'}, + { 750, 0.1225, '0.7 0.7 0.3'}, + {1000, 0.1225, '0.1 0.5 0.1'}, + {SPEEDBAR_MAX, 1, '0.1 0.7 0.1'}, +}; + +static float PlanarSpeed() { + return vlen([pmove_vel.x, pmove_vel.y, 0]); +} + +void drawSpeedBar(PanelID panelid, string text) { + FO_Hud_Panel* panel = getHudPanel(HUDP_SPEEDBAR); + vector fillsize = panel.FillSize * panel.Scale; + float alpha = fo_hud_editor ? 0.2:0.9; + vector position = getPanelPosition(panel); + + if (hud_panel(panel->id, position, fillsize, alpha, panel.Display)) { + // click event + } + + if (fo_hud_editor) + return; + + HRC_drawfill(position, fillsize, '0.5 0.5 0.5'); + + position += '1 1 0'; + fillsize -= '1 2 0'; + float frac_start, frac_end = 1; + + float tspeed = PlanarSpeed(); + float rspeed = min(tspeed, SPEEDBAR_MAX); + + float last_max = 0; + for (int i = 0; i < speedbar_colors.length; i++) { + SpeedBarColors* cur = &speedbar_colors[i]; + + if (frac_end > 0.99) { + frac_start = 0; + frac_end = cur.frac; + } else { + frac_start = frac_end; + frac_end = min(frac_start + cur.frac, 1); + } + + float pos; + if (rspeed > cur.max_speed) { + pos = frac_end; + // When we know we're going to wrap, fill the prior color. + if (frac_end > 0.99) + frac_start = 0; + } else { + pos = (rspeed - last_max) / (cur.max_speed - last_max) * + (frac_end - frac_start) + frac_start; + } + + vector start = position, fill = fillsize; + start.x += frac_start * fill.x; + fill.x *= pos - frac_start; + HRC_drawfill(start, fill, cur.color); + + last_max = cur.max_speed; + if (rspeed < last_max) + break; + } + + HRC_drawstring(position + '3 0 0', ftos((int)tspeed), '9 9 0', '1 1 1'); +} + var FO_Hud_Panel Hud_Panels[] = { // id, Name, Position, FillSize, Scale, TextScale, Display, Orientation, // void drawPanel(PanelID panelid, string text, string icon), @@ -1043,7 +1121,8 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_GUN6, "gun6", "Grenade Launcher", '-4 -90', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_GRENADE_LAUNCHER);}, 0, 36}, {HUDP_GUN7, "gun7", "Rocket Launcher", '-4 -70', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_ROCKET_LAUNCHER);}, 0, 36}, {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, - {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? sprintf("%3.1f UPS", vlen(pmove_vel)) : "";}, 0, 4}, + {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? ftos((int)PlanarSpeed()) : "";}, 0, 4}, + {HUDP_SPEEDBAR, "speedbar", "Speed Bar", '4 30', '150 10', 1,1.4,0,0,0, drawSpeedBar, {return "";}, 0, 4}, {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0,1, doNothing, {return "";}, 1}, }; From 54e6dcd2e8bea649c923f8131abd45776e87d51a Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 10 Mar 2023 16:46:26 -0800 Subject: [PATCH 2049/2474] HUD: fix escape handling and input capture - Input is no longer passed through when the hud editor is open - Escape now consistently opens the FO menu, or closes an open menu .. but does not open the system menu (0 from the FO menu does this) - Escape now properly exits the hud editor (without a save as before, although this is still a little sketch as there are other ways to trigger it, oh well) --- csqc/hud_helpers.qc | 14 +++++----- csqc/input.qc | 62 ++++++++++----------------------------------- 2 files changed, 22 insertions(+), 54 deletions(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 1d35a64e..16345ca8 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -1,12 +1,14 @@ void Hud_WriteCfg(string path); void FO_Hud_InitSystemPanels(); -void FO_Hud_Editor() -{ - if (fo_hud_editor) - { - fo_hud_editor = FALSE; - setcursormode(FALSE); +void FO_Hud_Editor_Cancel() { + fo_hud_editor = FALSE; + setcursormode(FALSE); +} + +void FO_Hud_Editor() { + if (fo_hud_editor) { + FO_Hud_Editor_Cancel(); FO_Hud_InitSystemPanels(); Hud_WriteCfg(FO_HUD_CONFIG_PATH); diff --git a/csqc/input.qc b/csqc/input.qc index 35602a3d..3bc0ef96 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -1,39 +1,30 @@ void Menu_Cancel(); void FO_Menu_Game(float); -static float HudInputEscape() { - if (!fo_hud_menu_active && !fo_hud_editor) - return FALSE; - - Menu_Cancel(); - fo_hud_editor = FALSE; - return TRUE; -} - +// TRUE --> capture input +// FALSE --> pass input on float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { if (fo_hud_editor || fo_hud_menu_active) { sui_input_event(evtype, scanx, chary, devid); float menu_mouse = (fo_hud_menu_active && (CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)); + switch (evtype) { - case IE_KEYUP: - if (scanx == K_ESCAPE && HudInputEscape()) - return TRUE; - break; case IE_KEYDOWN: - if (scanx == K_ESCAPE) - return TRUE; - if (scanx == K_MOUSE1 && !menu_mouse) - return FALSE; if (fo_hud_menu_active) - return fo_menu_process_input(CurrentMenu, scanx); + fo_menu_process_input(CurrentMenu, scanx); + if (scanx == K_ESCAPE) { + Menu_Cancel(); + FO_Hud_Editor_Cancel(); + return TRUE; // Always capture escape + } break; - case IE_MOUSEDELTA: - return (fo_hud_editor || menu_mouse); case IE_MOUSEABS: Mouse.x = scanx; Mouse.y = chary; - return (fo_hud_editor || menu_mouse); + break; } + + return fo_hud_editor; // capture iff hud-editor } else if(getHudPanel(HUDP_MAP_MENU)->Display) { sui_input_event(evtype, scanx, chary, devid); @@ -119,42 +110,17 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } else { switch (evtype) { - case IE_KEYUP: - switch (scanx) - { - case K_ESCAPE: - FO_Menu_Game(TRUE); - return TRUE; - } - break; case IE_KEYDOWN: switch (scanx) { case K_ESCAPE: + FO_Menu_Game(TRUE); return TRUE; } break; default: } } -/* - * better not - if(evtype == IE_KEYUP) { - tokenize(findkeysforcommand("impulse 5")); - float imp5_1 = stof(argv(0)); - float imp5_2 = stof(argv(1)); - tokenize(findkeysforcommand("menu")); - float menucmd_1 = stof(argv(0)); - float menucmd_2 = stof(argv(1)); - switch (scanx) { - case imp5_1: - case imp5_2: - case menucmd_1: - case menucmd_2: - FO_Menu_Special(TRUE); - return TRUE; - } - } -*/ + return FALSE; } From f3d810d0d121b46032b55c13c402eb013ff38aed Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 10 Mar 2023 20:30:37 -0800 Subject: [PATCH 2050/2474] hud: add a ping panel Simlar to ezhud's support. Unfortunately, the data granularity is a little worse due to infokey clipping to server frames; but good enough. --- csqc/csextradefs.qc | 1 + csqc/hud.qc | 4 ++++ csqc/status.qc | 3 +++ csqc/weapon_predict.qc | 10 ++++++++++ 4 files changed, 18 insertions(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 53379895..f9ece130 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -457,6 +457,7 @@ enum PanelID:float { HUDP_GUN8, HUDP_SPEED, HUDP_SPEEDBAR, + HUDP_PING, HUDP_OPTIONS, // Should be the last HUD element so that it's always on top. HUDP_LAST = HUDP_OPTIONS, diff --git a/csqc/hud.qc b/csqc/hud.qc index d0e685a0..454160cc 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -55,6 +55,10 @@ void FO_Hud_Editor_LoadDefaultSettings() getHudPanel(HUDP_SPEEDBAR)->Scale = 1.00; getHudPanel(HUDP_SPEEDBAR)->Snap = HUD_SNAP_CENTER; getHudPanel(HUDP_SPEEDBAR)->Position = [0, 30]; + + getHudPanel(HUDP_PING)->Display = 0; + getHudPanel(HUDP_PING)->Snap = HUD_SNAP_TOP_RIGHT; + getHudPanel(HUDP_PING)->Scale = 1.00; } void FO_Hud_Editor_List_Panels() = { diff --git a/csqc/status.qc b/csqc/status.qc index 769f0961..c7eb03e7 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1070,6 +1070,8 @@ void drawSpeedBar(PanelID panelid, string text) { HRC_drawstring(position + '3 0 0', ftos((int)tspeed), '9 9 0', '1 1 1'); } +string getPingPanelText(); + var FO_Hud_Panel Hud_Panels[] = { // id, Name, Position, FillSize, Scale, TextScale, Display, Orientation, // void drawPanel(PanelID panelid, string text, string icon), @@ -1123,6 +1125,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? ftos((int)PlanarSpeed()) : "";}, 0, 4}, {HUDP_SPEEDBAR, "speedbar", "Speed Bar", '4 30', '150 10', 1,1.4,0,0,0, drawSpeedBar, {return "";}, 0, 4}, + {HUDP_PING, "ping", "Ping", '4 15', '120 12', 1,1.4,0,0,0, drawTextPanel, getPingPanelText, 0, 4}, {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0,1, doNothing, {return "";}, 1}, }; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f521a202..88421f3f 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -59,6 +59,16 @@ inline float interp_time() { DECLARE_MOVING_AVG(avg_ping, 20); +string getPingPanelText() { + float minv, maxv, avg, varr; + + read_online_avg(&avg_ping, &avg, &varr); + compute_maxmin(&avg_ping.samples, &minv, &maxv); + float pl = getplayerkeyfloat(player_localnum, INFOKEY_P_PACKETLOSS); + + return sprintf("^7%d^1/^7%d^1/^7%d ^8ms ^7%d^8%%\n", minv, avg, maxv, pl); +} + static void update_avg_ping() { // We use a fairly low clamp here because: // a) We want to limit the effect of momentary total loss From 99959e9a52cc8181b967849026af1331a44e0631 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 11 Mar 2023 15:18:49 -0800 Subject: [PATCH 2051/2474] hud: strip name colors from id, add option for scoreboard - strip colored names from id - adds `fo_simple_names` which will strip name colors from the scoreboard also --- csqc/status.qc | 5 +++++ ssqc/actions.qc | 2 ++ 2 files changed, 7 insertions(+) diff --git a/csqc/status.qc b/csqc/status.qc index c7eb03e7..5641e9f1 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -677,6 +677,8 @@ struct FO_ScoreBoard { static FO_ScoreBoard score_board; +DEFCVAR_FLOAT(fo_simple_names, 0); + vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, float padding, vector columnColour) { vector textcolour = MENU_TEXT_1; @@ -786,6 +788,9 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; string n = lines[i].name; + if (CVARF(fo_simple_names)) + n = strdecolorize(n); + if (stringwidth(n, TRUE, smalltext) >= namespace - padding) { n = strdecolorize(n); n = substring(n, 0, floor(namespace - padding) / smalltext.x); diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 5c58978d..d9d9bc24 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -392,6 +392,8 @@ void (entity pe_player, float f_type) CF_Identify = { return; } + s_name = strdecolorize(s_name); + // set name + health (if medic) if (f_maxhealth && (f_friendly || f_fakefriendly)) { s_id_string = strcat(s_name, "\n"); From eb744789a0478279bddcf32666f1b5378b3bfe5c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 16 Mar 2023 00:01:52 +1100 Subject: [PATCH 2052/2474] Create a file to indicate ready for updater to run --- ssqc/quadmode.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 04d2d14b..b6b588f1 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -662,6 +662,12 @@ void () StartQuadRound = } localcmd("stop\n"); + + // tell updater script to run + float filehandle; + filehandle = fopen("upload_ready", FILE_WRITE); + fclose(filehandle); + return; } From c16b365b4f0dc3d952723bcefc1f4e9134548b9d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 16 Mar 2023 01:07:25 +1100 Subject: [PATCH 2053/2474] Add admin menu option to pull updates --- README.md | 1 + csqc/menu.qc | 2 +- ssqc/admin.qc | 8 ++++++++ ssqc/commands.qc | 4 ++++ ssqc/menu.qc | 4 ++++ ssqc/quadmode.qc | 6 +----- ssqc/weapons.qc | 1 + 7 files changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8f773e5f..fba5a0fb 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New commands ------------ +* `cmd updateserver` tell server to pull latest progs and maps * `fo_hud_cache 1` less resource intensive hud * `fo_hud_fps 60` set hud refresh rate * `fo_grentimer_ping_frac 1` fraction of ping to correct for diff --git a/csqc/menu.qc b/csqc/menu.qc index 3db39711..f8db837b 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -392,7 +392,7 @@ var fo_menu FO_MENU_ADMIN_MAIN = { {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd randomise\n");},MENU_BORDER_WARNING}, {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd restart\n"); Menu_Cancel();},MENU_BORDER_WARNING}, {"8","End Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcebreak\n"); Menu_Cancel();},MENU_BORDER_WARNING}, - MenuSpacer, + {"9","Update Server","","",FO_MENU_STATE_NORMAL,{localcmd("cmd updateserver\n"); Menu_Cancel();},MENU_BORDER_WARNING}, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, MenuSpacer, {"+","Next - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, diff --git a/ssqc/admin.qc b/ssqc/admin.qc index 40e32697..c8b278e2 100644 --- a/ssqc/admin.qc +++ b/ssqc/admin.qc @@ -185,6 +185,14 @@ void () Admin_CeaseFire = { } }; +void () Admin_UpdateServer = { + bprint(PRINT_HIGH, "Server updating...\n"); + + float filehandle; + filehandle = fopen("upload_ready", FILE_WRITE); + fclose(filehandle); +}; + void NotifyPauseUnpause(float is_pause) { int count; entity* p = find_list(classname, "player", EV_STRING, count); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 31defcea..5dfc5c81 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1173,6 +1173,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { Admin_CeaseFire(); processedCmd = TRUE; break; + case "updateserver": + Admin_UpdateServer(); + processedCmd = TRUE; + break; case "map": processedCmd = TRUE; if (arg_num == 2) { diff --git a/ssqc/menu.qc b/ssqc/menu.qc index a865ef1f..89c301c5 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -1211,6 +1211,7 @@ void () QuadMode; void () PubMode; void () DuelMode; void () RestartMap; +void () Admin_UpdateServer; void () Menu_Admin = { if(self.is_admin && infokeyf(self, INFOKEY_P_CSQCACTIVE)) { @@ -1576,6 +1577,9 @@ void (float inp) Menu_Admin_Input = case 7: // Restart Current Map Option RestartMap(); break; + case 9: + Admin_UpdateServer(); + break; } } else if (self.current_menu_page == 2) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index b6b588f1..268257c9 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -662,11 +662,7 @@ void () StartQuadRound = } localcmd("stop\n"); - - // tell updater script to run - float filehandle; - filehandle = fopen("upload_ready", FILE_WRITE); - fclose(filehandle); + Admin_UpdateServer(); return; } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 23e3313b..6104ca9a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -80,6 +80,7 @@ void () Admin_CycleDeal; void () Admin_DoKick; void () Admin_DoBan; void () Admin_CeaseFire; +void () Admin_UpdateServer; void () Admin_ListIPs; void () fadetoblack; From 5dd33294f0d471912a3728c4720fab947f3bcc00 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Mar 2023 17:08:02 -0700 Subject: [PATCH 2054/2474] hud: fix scoreboard colours Scoreboard fields were being rendered with menu associated colours, which ended up in blending / channels being flattened when combined with coloured names. Fix this and generally make the scoreboard a little easier to read. --- csqc/csextradefs.qc | 5 ++++ csqc/status.qc | 63 +++++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f9ece130..1a6f823f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -23,6 +23,11 @@ vector MENU_TEXT_WARNING = '0.8 0 0'; vector MENU_TEXT_GREEN = '0 0.8 0'; vector MENU_DARKEN = '1 1 1'; +vector SCOREB_HEADER = '0.7 0.7 0.7'; +vector SCOREB_NAME = '1 1 1'; +vector SCOREB_FIELD = '0.9 0.9 0.9'; +vector SCOREB_SELF_BG = '0.8 0.8 0.8'; + vector MENU_TEXT_SMALL = '8 8 0'; vector MENU_TEXT_MEDIUM = '16 16 0'; vector MENU_TEXT_LARGE = '24 24 0'; diff --git a/csqc/status.qc b/csqc/status.qc index 5641e9f1..4cc2777c 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -680,8 +680,7 @@ static FO_ScoreBoard score_board; DEFCVAR_FLOAT(fo_simple_names, 0); vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, - float padding, vector columnColour) { - vector textcolour = MENU_TEXT_1; + float padding, vector team_colour) { vector smalltext = MENU_TEXT_SMALL * panel.Scale; vector yspacer = [0, 20]; vector position = [0, 0]; @@ -709,11 +708,11 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, case "ping": case "pl": case "name": - sui_text(position, smalltext, colname, columnColour, .7, 0); + sui_text(position, smalltext, colname, SCOREB_HEADER, .7, 0); break; } } else { - sui_text(position, smalltext, colname, columnColour, .7, 0); + sui_text(position, smalltext, colname, SCOREB_HEADER, .7, 0); } txtlength = strlen(colname) * smalltext.x; @@ -731,37 +730,27 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, continue; lineCount++; - float trans = 1; + float alpha = 1; if (lineCount % 2 == 0) - trans = .7; + alpha = .7; else - trans = .3; - - sui_fill(position, size, columnColour, trans, 0); + alpha = .3; - textcolour = MENU_TEXT_1; - if(lines[i].name == getplayerkeyvalue(player_localnum, "name")) { - textcolour = MENU_TEXT_4; - } else if(lines[i].name == getplayerkeyvalue(player_localentnum - 1, "name")) { - textcolour = '0.8 0 0.8'; - } else { - if (prematch && lines[i].team_no && !SBAR.CountdownStarted - && lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { - float ready = lines[i].ready; - if (ready) - textcolour = MENU_TEXT_GREEN_FO; - else - textcolour = MENU_TEXT_RED_FO; - } + vector fill_colour = team_colour; + if (lines[i].name == getplayerkeyvalue(player_localnum, "name")) { + alpha = 0.5; + fill_colour = SCOREB_SELF_BG; } + sui_fill(position, size, fill_colour, alpha, 0); + float col = 0, alpha = 1, flags = 0; string val = AbbreviateNumberToString(lines[i].ping); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].pl); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; if (team_no == lines[i].team_no || lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER @@ -776,14 +765,14 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, } } - sui_text(position, smalltext, c, textcolour, 1, 0); + sui_text(position, smalltext, c, SCOREB_FIELD, 1, 0); } position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { val = AbbreviateNumberToString(lines[i].score); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); } position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; @@ -795,7 +784,7 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, n = strdecolorize(n); n = substring(n, 0, floor(namespace - padding) / smalltext.x); } - sui_text(position, smalltext, n, textcolour, 1, 0); + sui_text(position, smalltext, n, SCOREB_NAME, 1, 0); position_x += namespace; vector iconpos = [size_x, position_y]; @@ -839,39 +828,39 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, } val = AbbreviateNumberToString(lines[i].caps); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].touches); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].kills); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].teamkills); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].deaths); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].afflicted); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].teamafflicted); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].damagegiven); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; val = AbbreviateNumberToString(lines[i].damagetaken); - drawShowScoresColumnVal(position, smalltext, val, textcolour, alpha, flags, FO_ScoreBoardColumns[col]); + drawShowScoresColumnVal(position, smalltext, val, SCOREB_FIELD, alpha, flags, FO_ScoreBoardColumns[col]); position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; position_x = 0; From 7f0b899868ac75a889d42dc42b3b21dbb09f7871 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 22 Mar 2023 17:15:51 -0700 Subject: [PATCH 2055/2474] hud: highlight spectated player on scoreboard render the background of the currently spectated player (if any) in yellow --- csqc/csextradefs.qc | 1 + csqc/status.qc | 3 +++ 2 files changed, 4 insertions(+) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1a6f823f..9b8691d6 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -27,6 +27,7 @@ vector SCOREB_HEADER = '0.7 0.7 0.7'; vector SCOREB_NAME = '1 1 1'; vector SCOREB_FIELD = '0.9 0.9 0.9'; vector SCOREB_SELF_BG = '0.8 0.8 0.8'; +vector SCOREB_SPECTATED_BG = '0.8 0.8 0.2'; vector MENU_TEXT_SMALL = '8 8 0'; vector MENU_TEXT_MEDIUM = '16 16 0'; diff --git a/csqc/status.qc b/csqc/status.qc index 4cc2777c..59ad5318 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -740,6 +740,9 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, if (lines[i].name == getplayerkeyvalue(player_localnum, "name")) { alpha = 0.5; fill_colour = SCOREB_SELF_BG; + } else if (lines[i].name == getplayerkeyvalue(player_localentnum - 1, "name")) { + alpha = 0.5; + fill_colour = SCOREB_SPECTATED_BG; } sui_fill(position, size, fill_colour, alpha, 0); From a3fe9f778247749047cc78fa7d566844475a8eb4 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 25 Mar 2023 23:24:38 -0700 Subject: [PATCH 2056/2474] wp: update ping tracking - Filter out ping samples when client is unfocused (unreliable) - Use much smaller convergence interval - Move enable check to 1hz, immediate check on cvar change, 10s back off on flip --- csqc/weapon_predict.qc | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 88421f3f..06504baa 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -74,7 +74,7 @@ static void update_avg_ping() { // a) We want to limit the effect of momentary total loss // b) We actually want high pings to have low effective variance and // trigger it on consistently. - float newv = min(getplayerkeyfloat(player_localnum, INFOKEY_P_PING), 200); + float newv = min(getplayerkeyfloat(player_localnum, INFOKEY_P_PING), 300); update_online_avg(&avg_ping, newv); } @@ -144,14 +144,11 @@ static float CalcPredEnabled(float current_enable, } } - *set_by = "[default]"; + *set_by = "[disabled]"; return FALSE; } -#define ENABLE_CHECK_PERIOD 2 static float client_delay_packets; -static float next_wpp_enable_check; -static float next_ping_update; void(float seat, string keyname, string newvalue) setlocaluserinfo = #0:setlocaluserinfo; #define PRINT_CONFIG(_field) \ @@ -233,9 +230,25 @@ void WPP_Status() { #undef PRINT_CONFIG void WPP_UpdateEnable(float force) { + static float next_ping_update; + static float PING_PERIOD = 0.250; + if (time > next_ping_update) { - update_avg_ping(); - next_ping_update = time + ENABLE_CHECK_PERIOD / avg_ping.samples.max_count; + // Use an undocumented ezquake compat feature to figure out whether we + // have focus or not, drop samples in this case due to lowered network + // fps. + float is_unfocused = getplayerkeyfloat(player_localnum, "chat") & 2; + if (!is_unfocused) + update_avg_ping(); + next_ping_update = time + PING_PERIOD / avg_ping.samples.max_count; + } + + // Immediate updates any time there's a cvar change. + static float next_wpp_enable_check; + static float last_fo_wpp_beta; + if (CVARF(fo_wpp_beta) != last_fo_wpp_beta) { + next_wpp_enable_check = 0; + last_fo_wpp_beta = CVARF(fo_wpp_beta); } if (avg_ping.samples.count < 5) @@ -243,7 +256,7 @@ void WPP_UpdateEnable(float force) { if (!force && time < next_wpp_enable_check) return; - next_wpp_enable_check = time + ENABLE_CHECK_PERIOD; + next_wpp_enable_check = time + 1; // For wpp_weap_predict and wpp_proj_predict we use a tristate: // 1 => force on, 0 => force off, -1 => up to min_ping/server @@ -279,6 +292,8 @@ void WPP_UpdateEnable(float force) { printf("FortressOne: Projectile prediction %s %s\n", pp_new ? "enabled" : "disabled", pp_source); pengine.pp_enabled = pp_new; + + next_wpp_enable_check += 9; } once = TRUE; From 2f26d799ee82be7ed761e14a19cee31b5b8c50d4 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 26 Mar 2023 01:32:58 -0700 Subject: [PATCH 2057/2474] minping: add fo_min_ping Improve min ping support in several ways: - add a new client-side, fo_min_ping to be specified which syncs to a target ping - both client-side and global min-pings can now be used, the highest will take precedent. This allows specific clients to set a higher ping (e.g. when there's a min ping that works for everyone except one person who needs a match). - cl_delay_packets can also now be used for the scenario above, provided it is larger than the required minimum - Simplify/rewrite the loops for convergence; ignore ping when unfocused. --- csqc/main.qc | 16 ++++- csqc/weapon_predict.qc | 146 +++++++++++++++++++++++++---------------- 2 files changed, 101 insertions(+), 61 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index e124cf9a..58267c53 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -102,6 +102,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("fo_menu_dropammo"); registercommand("fo_menu_cancel"); + registercommand("fo_min_ping"); + registercommand("+aux_jump"); registercommand("-aux_jump"); registercommand("+special"); @@ -302,6 +304,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "fo_menu_cancel": Menu_Cancel(); break; + case "fo_min_ping": + UpdateFoMinPing(argv(1)); + break; case "fo_settings_check": ClientSettings_Check(); break; @@ -508,8 +513,6 @@ noref void CSQC_Input_Frame() { if (prev_zoomed_in != zoomed_in) setsensitivityscaler(zoomed_in ? 1/3 : 1); - - WPP_UpdateEnable(FALSE); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { @@ -552,7 +555,14 @@ void _Sync_ServerCommandFrame() { else is_alive = 1; - UpdateMinPing(); + // Use an undocumented ezquake compat feature to figure out whether we + // have focus or not, skip updates in this case due to lowered network fps. + float is_unfocused = getplayerkeyfloat(player_localnum, "chat") & 2; + if (!is_unfocused) { + UpdateMinPing(); + WPP_UpdateEnable(FALSE); + } + CsGrenTimer::UpdateSoundStack(); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 06504baa..5a176212 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -234,12 +234,7 @@ void WPP_UpdateEnable(float force) { static float PING_PERIOD = 0.250; if (time > next_ping_update) { - // Use an undocumented ezquake compat feature to figure out whether we - // have focus or not, drop samples in this case due to lowered network - // fps. - float is_unfocused = getplayerkeyfloat(player_localnum, "chat") & 2; - if (!is_unfocused) - update_avg_ping(); + update_avg_ping(); next_ping_update = time + PING_PERIOD / avg_ping.samples.max_count; } @@ -326,76 +321,111 @@ static void set_minping_delay_packets() { setlocaluserinfo(0, "client_delay_packets", ftos(client_delay_packets)); } -void UpdateMinPing() { - static float next_update; +struct { + float last_val; + float minv, user_controlled; + float fo_min_ping; +} DelayPacketState; + +static void UpdateDelayPackets(float val, float user) { + string sv = sprintf("%d", val); + setlocaluserinfo(0, "csqc_dp", user ? "0" : "1"); + setlocaluserinfo(0, "client_delay_packets", sv); + + DelayPacketState.user_controlled = user; + DelayPacketState.last_val = val; + + if (val != CVARF(cl_delay_packets)) { + CVARF(cl_delay_packets) = val; + localcmd("cl_delay_packets ", sv, "\n"); + } +} - if (!fo_config.min_ping_ms) { - // Clear, if-and-only-if, we control the value. - if (client_delay_packets) { - client_delay_packets = 0; - set_minping_delay_packets(); - } - return; +void UpdateFoMinPing(string arg) { + float fmp = DelayPacketState.fo_min_ping; + + if (arg != "") { + float nv = stoi(arg); + + // Don't bother posting if we'll ignore it. + if (nv != fmp && nv > fo_config.min_ping_ms) + localcmd(sprintf("say SET: fo_min_ping %d\n", nv)); + + DelayPacketState.fo_min_ping = fmp = nv; + DelayPacketState.user_controlled = FALSE; } - if (time < next_update) - return; - next_update = time + 1; + float min_ping = max(fo_config.min_ping_ms, fmp); + printf("Min ping is: %d [%s specified]\n", min_ping, + min_ping == fmp ? "client" : "server"); +} - const float PING_SAMPLES = 10; - static float num_samples; - static float ping_cache[PING_SAMPLES]; +string(float seat, string keyname) getlocaluserinfo = #0:getlocaluserinfo; +void ModulateDelayPackets() { static float once; - if (CVARF(cl_delay_packets) != client_delay_packets) { - // We expect to see a one-time mismatch, but after this, clients are - // trying to change it on us. Make that noisy. - if (once) - localcmd(sprintf("say forced reset delay_packets %d -> %d\n", - CVARF(cl_delay_packets), client_delay_packets)); + float dp = CVARF(cl_delay_packets), nv; + + if (!once) { + if (getlocaluserinfo(0, "csqc_dp") == "1") { + // Set from a previous game, clear. + UpdateDelayPackets(0, TRUE); + return; + } + + DelayPacketState.last_val = dp; + DelayPacketState.user_controlled = TRUE; once = TRUE; + } - next_update = time + 0.1; - set_minping_delay_packets(); - return; + if (dp != DelayPacketState.last_val && dp > DelayPacketState.minv) { + UpdateDelayPackets(dp, TRUE); + localcmd(sprintf("say SET: cl_delay_packets %d\n", dp)); + } else if (dp < DelayPacketState.minv || + (dp > DelayPacketState.minv && !DelayPacketState.user_controlled)) { + + if (dp != DelayPacketState.last_val) + localcmd(sprintf("say IGNORED: cl_delay_packets %d [< min of %d]\n", + dp, DelayPacketState.minv)); + UpdateDelayPackets(DelayPacketState.minv, FALSE); } +} - float cache_index = (num_samples++) % ping_cache.length; - ping_cache[cache_index] = - max(0, getplayerkeyfloat(player_localnum, INFOKEY_P_PING)); - if (num_samples < 10) +void UpdateMinPing() { + static float next_update; + + ModulateDelayPackets(); + + float min_ping = max(fo_config.min_ping_ms, DelayPacketState.fo_min_ping); + + if (!min_ping) { + DelayPacketState.minv = 0; return; + } - float ping = ping_cache[0]; - for (int i = 1; i < ping_cache.length; i++) - ping = min(ping, ping_cache[i]); + if (time < next_update || !is_player) + return; + next_update = time + 5; - ping = max(ping - client_delay_packets, SERVER_FRAME_MS); - float target = max(fo_config.min_ping_ms - ping, 0); + const float PING_SAMPLES = 10; + static float num_samples; + static float ping_cache[PING_SAMPLES]; + float cache_index = (num_samples++) % ping_cache.length; - if (CVARF(fo_minping_min) > 0) - target = max(target, CVARF(fo_minping_min)); + float cping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); + ping_cache[cache_index] = max(0, cping - DelayPacketState.last_val); - if (!is_player) - target = 0; + float true_avg = 0; + float N = min(num_samples, PING_SAMPLES); + for (int i = 0; i < N; i++) + true_avg += ping_cache[i]; + true_avg /= N; - if (target == 0) { - client_delay_packets = 0; - } else { - float nv = (ceil((target - 0.1)/ 3)) * 3 + 1; - // Bound how much we'll step at once. - if (!client_delay_packets) - client_delay_packets = nv; - else - client_delay_packets = min(client_delay_packets + 10, nv); - } + float target = max(ceil(min_ping - true_avg), 0); - if (CVARF(cl_delay_packets) != client_delay_packets) { - set_minping_delay_packets(); - setlocaluserinfo(0, "client_delay_packets", ftos(client_delay_packets)); - num_samples = 0; - } + // Bound convergence steps + DelayPacketState.minv = min(DelayPacketState.minv + 25, target); } float IsEffectFrame() { From a7f039a580668d88df6945763a9c556c290ff538 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 26 Mar 2023 02:08:23 -0700 Subject: [PATCH 2058/2474] wpp: match projectile prediction to player prediction Currently projectiles and players are interpolated on separate clocks, which can lead to frustrating hit registration. Introduce support to calculate how much player prediction is occurring, then synchronize projectiles fired by the current client against that. Not yet enabled by default. Enabled by including a 2 bit in fo_wpp_beta. Renames/adds two new cvars: wpp_adv_selfp_ms (extra nudge to add to our own projectiles, up to ping) wpp_adv_remotep_ms (extra nudge to add to others' projectiles, up to ping) --- csqc/main.qc | 8 +-- csqc/weapon_predict.qc | 153 +++++++++++++++++++++++++++-------------- 2 files changed, 105 insertions(+), 56 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 58267c53..c07eab3b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -529,6 +529,8 @@ void CSQC_Shutdown() { DEFCVAR_FLOAT(cl_delay_packets, 0); DEFCVAR_FLOAT(fov, 90); +void WP_UpdatePings(); + float last_servercommandframe; void _Sync_ServerCommandFrame() { // Server command frames are monotonically unique, we can skip processing @@ -558,10 +560,8 @@ void _Sync_ServerCommandFrame() { // Use an undocumented ezquake compat feature to figure out whether we // have focus or not, skip updates in this case due to lowered network fps. float is_unfocused = getplayerkeyfloat(player_localnum, "chat") & 2; - if (!is_unfocused) { - UpdateMinPing(); - WPP_UpdateEnable(FALSE); - } + if (!is_unfocused) + WP_UpdatePings(); CsGrenTimer::UpdateSoundStack(); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 5a176212..205ed522 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -7,8 +7,8 @@ DEFCVAR_FLOAT(wpp_min_ping, -1); DEFCVAR_FLOAT(wpp_weap_predict, -1); DEFCVAR_FLOAT(wpp_proj_predict, -1); -DEFCVAR_FLOAT(wpp_phys_adv_ms, 0); -DEFCVAR_FLOAT(wpp_phys_local_adv_ms, 0); +DEFCVAR_FLOAT(wpp_adv_selfp_ms, 0); +DEFCVAR_FLOAT(wpp_adv_otherp_ms, 0); DEFCVAR_FLOAT(wpp_setspeed, 1); struct pengine_t { @@ -27,6 +27,9 @@ struct pengine_t { float view_mask; } pengine; +static float inst_ping_ms; +static float inst_ping_t; + inline float PP_Enabled() { return pengine.pp_enabled; } inline float WP_Enabled() { return pengine.wp_enabled; } inline float WPP_ViewModelMask() { return pengine.view_mask; } @@ -40,18 +43,56 @@ float WP_MinPing() { void WP_UpdateViewModel(); -inline float interp_ms() { +inline float server_time_ms() { return (pstate_pred.seq - pstate_server.seq) * SERVER_FRAME_MS; } -inline float interp_dt() { - return interp_ms() / 1000.0; +inline float server_time_dt() { + return server_time_ms() / 1000.0; } -inline float interp_time() { - return time + interp_dt(); +inline float server_time() { + return time + server_time_dt(); } +DEFCVAR_FLOAT(cl_predict_players, 1); +DEFCVAR_FLOAT(cl_predict_players_latency, 0.9); +DEFCVAR_FLOAT(cl_predict_players_nudge, 0.02); +DEFCVAR_FLOAT(cl_predict_players_frac, 0.9); + +static float pred_time_dt; // delta-time that the world predicted forward by + +// Match up local interpolation of projectile position with that of players. +static void update_interp_time_dt() { + if (CVARF(fo_wpp_beta) & 2 == 0) // Temporary gate bit. + return; + + if (!CVARF(cl_predict_players)) { + pred_time_dt = 0; + return; + } + + // Maybe prefer smoothed value here? + pred_time_dt = inst_ping_t; + + if (CVARF(cl_predict_players_latency) < 1) + pred_time_dt *= 1 - CVARF(cl_predict_players_latency); + pred_time_dt *= CVARF(cl_predict_players_frac); + + pred_time_dt += CVARF(wpp_adv_selfp_ms) + CVARF(cl_predict_players_nudge); + pred_time_dt = min(pred_time_dt, inst_ping_t); +} + +// Unlike server_time(), interp_time() is continuous and reflects how much we've +// projected the local copy of the world forward. Monotonic. +static float interp_time() { + static float last_interp_time = 0; + + last_interp_time = max(last_interp_time, time + pred_time_dt); + return last_interp_time; +} + + #define csqc_print(...) \ do { if (CVARF(wpp_debug) & 4) { \ print("CSQC: ", __VA_ARGS__); \ @@ -74,7 +115,7 @@ static void update_avg_ping() { // a) We want to limit the effect of momentary total loss // b) We actually want high pings to have low effective variance and // trigger it on consistently. - float newv = min(getplayerkeyfloat(player_localnum, INFOKEY_P_PING), 300); + float newv = min(inst_ping_ms, 300); update_online_avg(&avg_ping, newv); } @@ -188,11 +229,10 @@ void WPP_Status() { printf(" Projectile prediction %s %s\n", pp_enabled ? "enabled" : "disabled", pp_source); - float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); float avg, variance; fill_avg_ping(&avg, &variance); printf(" inst_ping = %d client_ping = %d avg_ping = %d var = %d\n", - ping, pstate_server.client_ping, avg, variance); + inst_ping_ms, pstate_server.client_ping, avg, variance); if (fo_config.min_ping_ms) printf(" client_delay_packets = %d\n", client_delay_packets); printf(" maxspeed = %d\n", pstate_server.csqc_maxspeed); @@ -235,6 +275,7 @@ void WPP_UpdateEnable(float force) { if (time > next_ping_update) { update_avg_ping(); + update_interp_time_dt(); next_ping_update = time + PING_PERIOD / avg_ping.samples.max_count; } @@ -413,7 +454,7 @@ void UpdateMinPing() { static float ping_cache[PING_SAMPLES]; float cache_index = (num_samples++) % ping_cache.length; - float cping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); + float cping = inst_ping_ms; ping_cache[cache_index] = max(0, cping - DelayPacketState.last_val); float true_avg = 0; @@ -428,6 +469,15 @@ void UpdateMinPing() { DelayPacketState.minv = min(DelayPacketState.minv + 25, target); } +void WP_UpdatePings() { + inst_ping_ms = getplayerkeyfloat(player_localnum, INFOKEY_P_PING); + inst_ping_t = inst_ping_ms / 1000.0; + + update_interp_time_dt(); + UpdateMinPing(); + WPP_UpdateEnable(FALSE); +} + float IsEffectFrame() { if (!pengine.is_effectframe) return FALSE; @@ -504,7 +554,7 @@ void WP_ServerUpdate() { pstate_server.weaponframe += 1; } - if (CVARF(fo_wpp_beta) == 2) + if (CVARF(fo_wpp_beta) & 4) phys_sim_dt = (pstate_server.client_ping + 2 * SERVER_FRAME_MS) / 1000.0; else phys_sim_dt = -1; @@ -1089,20 +1139,21 @@ trail_table_entry trail_table[] = { {{"TE_RAILTRAIL"}}, }; -float get_phys_time_nudge_dt(entity e) { - if (!is_player) - return 0; - - float nudge; - if (e.owner_entnum != pengine.player_entnum) - nudge = CVARF(wpp_phys_adv_ms); - else - nudge = CVARF(wpp_phys_local_adv_ms); - return min(nudge, interp_ms()) / 1000.0; -} - inline float get_phys_time(entity e) { - return time + get_phys_time_nudge_dt(e); + if (e.owner_entnum == pengine.player_entnum) { + // We want to align our own entities with remote player interp so that + // collisions feel correct. + return interp_time(); + } else { + // Entities from other players.. we have choice. For now, advance them + // up to wpp_adv_otherp_ms (bounded at ping, which is true position for + // hitting the client.. what they likely care about most... although + // this will offset explosions in the short term). + static float last_self_time; + float dt = min(inst_ping_ms, CVARF(wpp_adv_otherp_ms)) / 1000.0; + last_self_time = max(last_self_time, time + dt); + return last_self_time; + } } void FO_PP_Init() { @@ -1241,29 +1292,17 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.owner = pengine.player_ent; FPP_Init(fpp_type, proj); -#if 0 - // Packet loss doesnt guarantee the server will actually register quickslot - // since it's a separate command from the attack. We can improve this in the - // future via either a button or just combining them on an impulse. But for - // now just dont create the projectile, it's usually swapping to a hitscan - // weapon anyway. - if (pstate_pred.tfstate & TFSTATE_QUICKSLOT && - !(pstate_server.tfstate & TFSTATE_QUICKSLOT)) - return __NULL__; -#endif - - ProjectResult push_t = Forward_ProjectOffset(fpp_type, interp_ms()); + float ms_ahead = server_time_ms(); + ProjectResult push_t = Forward_ProjectOffset(fpp_type, ms_ahead); - // Using interp_ms() to predict which packet it will arrive in, while using - // client_ping to predict when that packet will arrive, seems to produce - // more consistent results, possibly due to batching. - float uncorrected_dt = (pstate_server.client_ping - push_t.dynamic_ms) / 1000.0; + float uncorrected_dt = max(ms_ahead - push_t.dynamic_ms, 0) / 1000.0; float static_dt = push_t.static_ms / 1000.0; + // Note: We use true time here as created projectiles exist outside of pred. proj.starttime = time + uncorrected_dt; proj.s_time = proj.starttime - static_dt; proj.endtime = proj.starttime + pstate_server.client_ping / 1000.0 + PP_EPS; - proj.server_live_time = time + interp_dt(); + proj.server_live_time = server_time(); proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; @@ -1515,6 +1554,24 @@ void WP_Attack() { WP_AnimateModel(); } + +void PredProjectile_DebugMatch(entity cprj, entity sprj) { + string sgn = + vlen(cprj.origin - pmove_org) > vlen(sprj.origin- pmove_org) ? "+" : "-"; + + string s = sprintf(" p_diff: %s%-2.1f [%0.3f] ", sgn, + vlen(cprj.origin - sprj.origin), + vlen(cprj.origin - sprj.origin) / vlen(cprj.velocity)); + s = strcat(s, sprintf("t=%0.3f / %0.3f p_t=[c:%0.3f s:%0.3f d=%0.3f]", + time, sprj.t_time, cprj.phys_time, sprj.phys_time, + sprj.phys_time - cprj.phys_time)); + + s = strcat(s, sprintf(" [c=%d s=%d] al=%d\n", + vlen(cprj.origin - pmove_org), vlen(sprj.origin - pmove_org), + self.antilag_ms)); + print(s); +} + float PredProjectile_MatchProjectile() { entity proj, match = __NULL__; float best = 64; @@ -1546,16 +1603,8 @@ float PredProjectile_MatchProjectile() { if (FPP_IsGrenade(self.fpp.index)) self.angles = match.angles; - if (CVARF(wpp_debug) & 1) { - string s = sprintf(" p_diff: %0.1f [%0.3f] t=%0.3f p_t=c:%0.3f s:%0.3f [%0.3f]", - vlen(match.origin - self.origin), - vlen(match.origin - self.origin) / vlen(self.velocity), - time, match.phys_time, self.phys_time, match.phys_time - self.phys_time); - s = strcat(s, sprintf(" [c=%d s=%d] al=%d\n", - vlen(match.origin - pmove_org), vlen(self.origin - pmove_org), - self.antilag_ms)); - print(s); - } + if (CVARF(wpp_debug) & 1) + PredProjectile_DebugMatch(match, self); PP_Cleanup(match); return TRUE; From 07fa5a353dcea03b168317529cd5afbbe36bdbdb Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 26 Mar 2023 02:13:29 -0700 Subject: [PATCH 2059/2474] Fix missing hunk from prior commit. --- csqc/weapon_predict.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 205ed522..6b67a32a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1562,8 +1562,8 @@ void PredProjectile_DebugMatch(entity cprj, entity sprj) { string s = sprintf(" p_diff: %s%-2.1f [%0.3f] ", sgn, vlen(cprj.origin - sprj.origin), vlen(cprj.origin - sprj.origin) / vlen(cprj.velocity)); - s = strcat(s, sprintf("t=%0.3f / %0.3f p_t=[c:%0.3f s:%0.3f d=%0.3f]", - time, sprj.t_time, cprj.phys_time, sprj.phys_time, + s = strcat(s, sprintf("t=%0.3f p_t=[c:%0.3f s:%0.3f d=%0.3f]", + time, cprj.phys_time, sprj.phys_time, sprj.phys_time - cprj.phys_time)); s = strcat(s, sprintf(" [c=%d s=%d] al=%d\n", From 504c7dd9ea5501a257c1aabd070f581af027d154 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 29 Mar 2023 15:56:40 -0700 Subject: [PATCH 2060/2474] hud: make sure we capture inputs on in game menus We cleaned up a bunch of the input capture code, one escape that was some of the in game menus such as the engineer build menu were now correctly passing through e.g. WASD consistently, however, they weren't consuming the inputs that definitely applied to them. --- csqc/input.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 3bc0ef96..92161688 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -10,13 +10,12 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { switch (evtype) { case IE_KEYDOWN: - if (fo_hud_menu_active) - fo_menu_process_input(CurrentMenu, scanx); if (scanx == K_ESCAPE) { Menu_Cancel(); FO_Hud_Editor_Cancel(); return TRUE; // Always capture escape - } + } else if (fo_hud_menu_active) + return fo_menu_process_input(CurrentMenu, scanx); break; case IE_MOUSEABS: Mouse.x = scanx; From d2845c75405b9418aa5ee9b63eb1426b82b0e79b Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 26 Mar 2023 15:30:15 -0700 Subject: [PATCH 2061/2474] hud: fix flickering ammo/clip when dead Bit of a hack hiding some other issues in the hud code but quick temp fix. --- csqc/status.qc | 2 +- csqc/weapon_predict.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 59ad5318..06c3bf5f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -9,7 +9,7 @@ void FO_Hud_HidePanel(PanelID id); void FO_Hud_ShowPanel(PanelID id); void(PanelID ignored, string text) drawClipSize = { - if (SBAR.ClipSize != "" || fo_hud_editor) + if (is_alive || fo_hud_editor) Hud_DrawPanelLMP(getHudPanel(HUDP_CLIPSIZE), text, ICON_CLIPSIZE, 1); }; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6b67a32a..54c58433 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -580,7 +580,7 @@ static float AmmoToStat(float ammo_type) { } float WP_GetAmmo(float ammo_type) { - if (!WP_Enabled()) + if (!WP_Enabled() || !is_alive) return getstatf(AmmoToStat(ammo_type)); if (ammo_type == AMMO_NONE) From 85d47ac826d1e558b667944d92a0c99f0828380a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Apr 2023 13:07:47 -0700 Subject: [PATCH 2062/2474] weapons: restore old ng rof Restore ongrof parameter (also brought in by huetf). Make sure that both client and server side prediction handle it properly. --- csqc/weapon_predict.qc | 1 + share/animate.qc | 6 ++++-- share/commondefs.qc | 2 ++ share/prediction.qc | 11 +++++++++++ share/weapons.qc | 11 +++++++++++ ssqc/client.qc | 2 ++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 54c58433..fc410dac 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -251,6 +251,7 @@ void WPP_Status() { PRINT_CONFIG_ACTIVE(wpp_global_enable); PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); + PRINT_CONFIG_ACTIVE(old_ng_rof); PRINT_CONFIG(max_rewind_ms); PRINT_CONFIG(max_rewind_slow_projectile_ms); PRINT_CONFIG(max_rewind_fast_projectile_ms); diff --git a/share/animate.qc b/share/animate.qc index 4fb0c12f..ab40bbe5 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -219,8 +219,10 @@ void nail_extra_csqc_ssqc() { } float tidx = *thinkindex() % 2; // 1 based, and incremented. - SuperDamageSound(); - W_FireSpikes(tidx ? 4 : -4); + if (tidx == 0 || !OldNgRof()) { + SuperDamageSound(); + W_FireSpikes(tidx ? 4 : -4); + } } void player_asscan_down1(); diff --git a/share/commondefs.qc b/share/commondefs.qc index d50533ec..c6d2a020 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -37,6 +37,8 @@ var struct { float clown_flags; float clown_grav; + float old_ng_rof; + float predict_flags; float tfx_flags; diff --git a/share/prediction.qc b/share/prediction.qc index b28f296e..db10ce4c 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -398,6 +398,7 @@ void EntUpdate_Config() { COMM(Byte, wpp_global_enable); COMM(Byte, wpp_global_disable); COMM(Byte, gren_beta_disable); + COMM(Byte, old_ng_rof); #ifdef SSQC return TRUE; @@ -648,6 +649,16 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE(FALSE, "wppge", wpp_global_enable); CONFIG_UPDATE(FALSE, "wppge", wpp_global_disable); CONFIG_UPDATE(FALSE, "gbd", gren_beta_disable); + + // Not dynamically updatable. + static float read_rof_once = FALSE; + if (!read_rof_once) { + if (!fo_config.old_ng_rof) // Don't overwrite huetf setting this. + CONFIG_UPDATE(FALSE, "ongrof", old_ng_rof); + printf("reading ROF %d\n", fo_config.old_ng_rof); + read_rof_once = TRUE; + } + CONFIG_UPDATE(TRUE, "rewind", rewind_flags); CONFIG_UPDATE(TRUE, "tfx", tfx_flags); CONFIG_UPDATE(TRUE, "clown", clown_flags); diff --git a/share/weapons.qc b/share/weapons.qc index 23cb62d4..23059a3d 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -430,6 +430,10 @@ float FO_WeaponsMask(entity player) { } #endif +float OldNgRof() { + return fo_config.old_ng_rof; +} + // Slightly awkward construction, but convenient for calling from CSQC and SSQC. float FO_NumClipStillLoading(FO_WeapInfo* wi, float now, float reload_finished) { float tick = (wi->ammo_per_shot / wi->clip_size) * wi->full_reload_time; @@ -788,6 +792,13 @@ void FO_Weapons_Init() { } } + if (OldNgRof()) { + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_NAILGUN); + wi->ammo_per_shot = 2; + FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_SUPER_NAILGUN); + wi->ammo_per_shot = 4; + } + for (i = 0; i < class_weapons.length; i++) { for (j = 0; j < 4; j++) { FO_ClassWeapons* cw = &class_weapons[i]; diff --git a/ssqc/client.qc b/ssqc/client.qc index 8a582f5c..51ea02ef 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -978,6 +978,7 @@ void () DecodeLevelParms = { walls_block_emp = FALSE; solid_nailgren = TRUE; scoutscanspike = FALSE; + fo_config.old_ng_rof = TRUE; } st = infokey(world, "huetf"); @@ -1029,6 +1030,7 @@ void () DecodeLevelParms = { Role_None.gren2_limits[8] = 3; max_active_gren2_soldier = 1; round_delay_time = 10; + fo_config.old_ng_rof = TRUE; } // Must be after we've set up conditional options (e.g. hwguy reload). From 2b0ccd240920ba17be665fd69669d085a1edf97c Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Apr 2023 13:53:03 -0700 Subject: [PATCH 2063/2474] weapons: fix sniper rifle - fix damage for both headshots and body shots - clean up weapon code (removing not understood case for firing inside an ent can restore if it's somehow needed) - remove partially supported reload bits --- csqc/weapon_predict.qc | 2 +- share/weapons.qc | 3 - ssqc/client.qc | 10 ---- ssqc/qw.qc | 2 - ssqc/tfort.qc | 2 - ssqc/weapons.qc | 124 +++++++++++++++++------------------------ 6 files changed, 53 insertions(+), 90 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index fc410dac..9ce20402 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -693,7 +693,7 @@ float WP_SniperCharge() { return 0; float heat = 50 + (pstate_pred.seq - SniperState.start_seq) * 3; - return min(PC_SNIPER_MAXDAM, heat); + return min(heat, PC_SNIPER_MAXDAM); } static void WP_Sniper_UpdateSight() { diff --git a/share/weapons.qc b/share/weapons.qc index 23059a3d..e357900d 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -10,8 +10,6 @@ .float ammo_nails; .float ammo_rockets; .float ammo_cells; - -float sniperreload = FALSE; #endif // Use SlotIndex() to convert a slot if you're indexing an array. @@ -754,7 +752,6 @@ void FO_Weapons_Init() { ASSERTD_EQ(weapon_names.length, weapon_info.length); FO_WeapInfo* WI_sr = FO_GetWeapInfo(WEAP_SNIPER_RIFLE); - WI_sr->clip_size = sniperreload ? 1 : 0; for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; diff --git a/ssqc/client.qc b/ssqc/client.qc index 51ea02ef..c49040fe 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -547,9 +547,6 @@ void () DecodeLevelParms = { // allow scout dash [on] scoutdash = CF_GetSetting("sd", "scoutdash", "on"); - // enable sniper rifle reload [off] - sniperreload = CF_GetSetting("sr", "sniperreload", "off"); - // spawn with full ammo/armor [off] spawnfull = CF_GetSetting("sf", "spawnfull", "off"); @@ -577,9 +574,6 @@ void () DecodeLevelParms = { // display sniper rifle power in status bar [on] sniperpower = CF_GetSetting("sp", "sniperpower", "on"); - // display sniper rifle reload percentage in status bar [on] - sniperreloadpercent = CF_GetSetting("rp", "sniperreloadpercent", "on"); - // display build status in status bar [on] buildstatus = CF_GetSetting("bs", "buildstatus", "on"); @@ -850,7 +844,6 @@ void () DecodeLevelParms = { discammo_pickup = FALSE; old_dropflag = FALSE; scoutdash = TRUE; - sniperreload = TRUE; old_sniperrange = FALSE; Role_None.detpipe_limit = 6; detpipe_limit_world = -1; @@ -876,7 +869,6 @@ void () DecodeLevelParms = { stock_reload = TRUE; classtips = TRUE; sniperpower = TRUE; - sniperreloadpercent = TRUE; buildstatus = TRUE; old_hp_armor = FALSE; superaxe = TRUE; @@ -922,7 +914,6 @@ void () DecodeLevelParms = { discammo_pickup = TRUE; old_dropflag = TRUE; scoutdash = FALSE; - sniperreload = FALSE; old_sniperrange = TRUE; Role_None.detpipe_limit = 7; detpipe_limit_world = 7; @@ -948,7 +939,6 @@ void () DecodeLevelParms = { stock_reload = FALSE; classtips = FALSE; sniperpower = FALSE; - sniperreloadpercent = FALSE; buildstatus = FALSE; old_hp_armor = TRUE; superaxe = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 65f57470..7c5b061d 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -578,7 +578,6 @@ float feign_pack; float feign_msg; float feign_rate_limit; float scoutdash; -float sniperreload; float spawnfull; float stockfull; float stock_on_cap; @@ -588,7 +587,6 @@ float cussgrentime; float medicnocuss; float distance_based_cuss_duration; float sniperpower; -float sniperreloadpercent; float buildstatus; float server_default; float server_faithful; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f8e04e17..30d403c5 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -702,10 +702,8 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Scout dash ability", scoutdash, "", 1); sprint(self, PRINT_HIGH, "\n== Sniper ==\n"); - CF_PrintSetting("Sniper reload", sniperreload, "", 1); CF_PrintSetting("Old sniper rifle range", old_sniperrange, "", 1); CF_PrintSetting("Sniper Rifle power in status bar", sniperpower, "", 1); - CF_PrintSetting("Reload percentage in status bar", sniperreloadpercent, "", 1); sprint(self, PRINT_HIGH, "\n== Medic ==\n"); CF_PrintSetting("Medic immune to concussion grenade", medicnocuss, "", 1); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index a9662135..3dacf031 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -849,93 +849,76 @@ void () W_FireSniperRifle = { src = self.origin + v_forward * 10; src_z = self.absmin_z + self.size_z * 0.7; - use_this = FALSE; - - if (old_sniperrange) - traceline(src, src + dir * 8092, MOVE_LAGGED, self); - else - traceline(src, src + dir * 9192, MOVE_LAGGED, self); - if (trace_fraction != 1) - if (trace_ent != world) - if (trace_ent.classname == "player") - use_this = TRUE; - KickPlayer(-4, self); - if (!use_this) { - dir = aim(self, 10000); - if (old_sniperrange) - traceline(src, src + dir * 3072, MOVE_LAGGED, self); - else - traceline(src, src + dir * 9192, MOVE_LAGGED, self); - } + dir = aim(self, 10000); + float range = old_sniperrange ? 3072 : 9192; // Super arbitrary but ok. + traceline(src, src + dir * range, MOVE_LAGGED, self); + deathmsg = DMSG_SNIPERRIFLE; dam_mult = 1; - if (trace_ent) { - if (trace_ent.classname == "player") { - - f = trace_endpos - src; + if (trace_fraction < 1 && trace_ent && trace_ent.classname == "player") { + f = trace_endpos - src; - g_x = trace_endpos_x; - g_y = trace_endpos_y; - g_z = 0; + g_x = trace_endpos_x; + g_y = trace_endpos_y; + g_z = 0; - h_x = trace_ent.origin_x; - h_y = trace_ent.origin_y; - h_z = 0; + h_x = trace_ent.origin_x; + h_y = trace_ent.origin_y; + h_z = 0; - x = vlen(g - h); - f = (normalize(f) * x) + trace_endpos; + x = vlen(g - h); + f = (normalize(f) * x) + trace_endpos; - zdif = f_z - trace_ent.origin_z; - deathmsg = DMSG_SNIPERRIFLE; + zdif = f_z - trace_ent.origin_z; + deathmsg = DMSG_SNIPERRIFLE; - trace_ent.head_shot_vector = '0 0 0'; - if (zdif < 0) { + trace_ent.head_shot_vector = '0 0 0'; + if (zdif < 0) { - dam_mult = 0.5; - trace_ent.leg_damage = trace_ent.leg_damage + 1; - TeamFortress_SetSpeed(trace_ent); - deathmsg = DMSG_SNIPERLEGSHOT; - TF_T_Damage(trace_ent, self, self, self.heat * dam_mult, 2, - 1); + dam_mult = 0.5; + trace_ent.leg_damage = trace_ent.leg_damage + 1; + TeamFortress_SetSpeed(trace_ent); + deathmsg = DMSG_SNIPERLEGSHOT; + TF_T_Damage(trace_ent, self, self, self.heat * dam_mult, TF_TD_NOTTEAM, + TF_TD_SHOT); - if (trace_ent.health > 0) { - sprint(trace_ent, PRINT_LOW, "Leg injury!\n"); - sprint(self, PRINT_MEDIUM, - "Leg shot - that'll slow him down!\n"); - } - return; + if (trace_ent.health > 0) { + sprint(trace_ent, PRINT_LOW, "Leg injury!\n"); + sprint(self, PRINT_MEDIUM, + "Leg shot - that'll slow him down!\n"); + } + return; - } else if (zdif > 20) { + } else if (zdif > 20) { - dam_mult = 2; - stuffcmd(trace_ent, "bf\n"); - trace_ent.head_shot_vector = - trace_ent.origin - self.origin; - deathmsg = DMSG_SNIPERHEADSHOT; - TF_T_Damage(trace_ent, self, self, (self.heat * dam_mult), - 2, 1); + dam_mult = 2; + stuffcmd(trace_ent, "bf\n"); + trace_ent.head_shot_vector = + trace_ent.origin - self.origin; + deathmsg = DMSG_SNIPERHEADSHOT; + TF_T_Damage(trace_ent, self, self, (self.heat * dam_mult), + TF_TD_NOTTEAM, TF_TD_SHOT); - if (trace_ent.health > 0) { - sprint(trace_ent, PRINT_LOW, "Head injury!\n"); - sprint(self, PRINT_MEDIUM, - "Head shot - that's gotta hurt!\n"); - } - return; + if (trace_ent.health > 0) { + sprint(trace_ent, PRINT_LOW, "Head injury!\n"); + sprint(self, PRINT_MEDIUM, + "Head shot - that's gotta hurt!\n"); + } - } else - deathmsg = DMSG_SNIPERRIFLE; + } else { + deathmsg = DMSG_SNIPERRIFLE; } } - ClearMultiDamage(); - if (trace_fraction != 1) + if (trace_fraction < 1) { + ClearMultiDamage(); TraceAttack(self.heat * dam_mult, dir); - - FireBullets(1, dir, '0 0 0'); - - ApplyMultiDamage(); + ApplyMultiDamage(); + } else { + FireBullets(1, dir, '0 0 0'); + } }; void () W_FireAutoRifle = { @@ -1726,9 +1709,6 @@ void () W_Attack = { if (self.flags & FL_ONGROUND) { player_shot1(); W_FireSniperRifle(); - if (sniperreload) { - Status_Refresh(self); - } } } else if (ws.weapon == WEAP_AUTO_RIFLE) { player_autorifle1(); @@ -2687,7 +2667,7 @@ void () W_WeaponFrame = { if (FO_CurrentWeapon() == WEAP_SNIPER_RIFLE) { if (self.tfstate & TFSTATE_AIMING) { if (self.heat < PC_SNIPER_MAXDAM) { - self.heat = max(self.heat + 3, PC_SNIPER_MAXDAM); + self.heat = min(self.heat + 3, PC_SNIPER_MAXDAM); if ((sniperpower) && (self.power_time < (time - 0.3))) { self.power_time = time; Status_Refresh(self); From c56b732a762ab7b375e26b65ce2d4068bfdd95f8 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Apr 2023 14:03:35 -0700 Subject: [PATCH 2064/2474] weapon prediction: remove all the beta global disable/enable bits now only a single global disable --- csqc/weapon_predict.qc | 17 ++++++----------- share/commondefs.qc | 5 ----- share/prediction.qc | 10 ---------- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 9ce20402..4d544895 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -130,7 +130,7 @@ float csqc_get_user_setting(string s_short, string s_long, string def); // server disable, client enable/disable, server/ping enable static float CalcPredEnabled(float current_enable, float unspec_default /* meaning of '-1' */, - float server_disable, float server_enable, + float server_disable, float client_value, float dependent_enabled, string* set_by) { @@ -174,7 +174,7 @@ static float CalcPredEnabled(float current_enable, return current_enable; // variance too high, don't change anything. - if (unspec_default || server_enable) { + if (unspec_default) { if (ping_enable) { *set_by = sprintf("[ping >%d] (avg=%0.0f var=%0.0f)", WP_MinPing(), avg, variance); @@ -216,11 +216,11 @@ void WPP_Status() { float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; CalcPredEnabled(wp_enabled, CVARF(fo_wpp_beta), - fo_config.wp_global_disable, fo_config.wp_global_enable, + fo_config.wp_global_disable, CVARF(wpp_weap_predict), TRUE, &wp_source); CalcPredEnabled(pp_enabled, CVARF(fo_wpp_beta), - fo_config.pp_global_disable, fo_config.pp_global_enable, + fo_config.wp_global_disable, CVARF(wpp_proj_predict), wp_enabled, &pp_source); printf("Prediction Status:\n"); @@ -244,12 +244,7 @@ void WPP_Status() { PRINT_CONFIG(static_newmis_ms); PRINT_CONFIG(dynamic_newmis_ms); PRINT_CONFIG(wp_default_min_ping_ms); - PRINT_CONFIG_ACTIVE(wp_global_enable); PRINT_CONFIG_ACTIVE(wp_global_disable); - PRINT_CONFIG_ACTIVE(pp_global_enable); - PRINT_CONFIG_ACTIVE(pp_global_disable); - PRINT_CONFIG_ACTIVE(wpp_global_enable); - PRINT_CONFIG_ACTIVE(wpp_global_disable); PRINT_CONFIG_ACTIVE(gren_beta_disable); PRINT_CONFIG_ACTIVE(old_ng_rof); PRINT_CONFIG(max_rewind_ms); @@ -302,11 +297,11 @@ void WPP_UpdateEnable(float force) { string wp_source, pp_source; wp_new = CalcPredEnabled(wp_enabled, CVARF(fo_wpp_beta), - fo_config.wp_global_disable, fo_config.wp_global_enable, + fo_config.wp_global_disable, CVARF(wpp_weap_predict), TRUE, &wp_source); pp_new = CalcPredEnabled(pp_enabled, CVARF(fo_wpp_beta), - fo_config.pp_global_disable, fo_config.pp_global_enable, + fo_config.wp_global_disable, CVARF(wpp_proj_predict), wp_new, &pp_source); static float once; diff --git a/share/commondefs.qc b/share/commondefs.qc index c6d2a020..974ec757 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -42,12 +42,7 @@ var struct { float predict_flags; float tfx_flags; - float wp_global_enable; float wp_global_disable; - float pp_global_enable; - float pp_global_disable; - float wpp_global_enable; - float wpp_global_disable; float gren_beta_disable; } fo_config; diff --git a/share/prediction.qc b/share/prediction.qc index db10ce4c..f5ded67e 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -391,12 +391,7 @@ void EntUpdate_Config() { COMM(Byte, clown_flags); COMM(Float, clown_grav); COMM(Byte, wp_default_min_ping_ms); - COMM(Byte, wp_global_enable); COMM(Byte, wp_global_disable); - COMM(Byte, pp_global_enable); - COMM(Byte, pp_global_disable); - COMM(Byte, wpp_global_enable); - COMM(Byte, wpp_global_disable); COMM(Byte, gren_beta_disable); COMM(Byte, old_ng_rof); @@ -642,12 +637,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE(FALSE, "mrg", max_rewind_grenade_ms); CONFIG_UPDATE(FALSE, "rfpt", rewind_fast_projectile_thresh); CONFIG_UPDATE(FALSE, "wpdmp", wp_default_min_ping_ms); - CONFIG_UPDATE(FALSE, "wpge", wp_global_enable); CONFIG_UPDATE(FALSE, "wpgd", wp_global_disable); - CONFIG_UPDATE(FALSE, "ppge", pp_global_enable); - CONFIG_UPDATE(FALSE, "ppgd", pp_global_disable); - CONFIG_UPDATE(FALSE, "wppge", wpp_global_enable); - CONFIG_UPDATE(FALSE, "wppge", wpp_global_disable); CONFIG_UPDATE(FALSE, "gbd", gren_beta_disable); // Not dynamically updatable. From 171259199750e982028ab1081094a616f1691534 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Apr 2023 14:48:36 -0700 Subject: [PATCH 2065/2474] minping: update convergence loop Saw some negative feedback on the last implementation. --- csqc/weapon_predict.qc | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 4d544895..e5b6915a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -430,7 +430,7 @@ void ModulateDelayPackets() { void UpdateMinPing() { - static float next_update; + static float next_ping_update, next_minv_update; ModulateDelayPackets(); @@ -441,13 +441,16 @@ void UpdateMinPing() { return; } - if (time < next_update || !is_player) - return; - next_update = time + 5; - - const float PING_SAMPLES = 10; + // Ideally we want to span more than one update here to better handle + // averaging of clamping to server frames. + const float PING_SAMPLES = 50; static float num_samples; static float ping_cache[PING_SAMPLES]; + + if (time < next_ping_update || !is_player) + return; + next_ping_update = time + 0.2; + float cache_index = (num_samples++) % ping_cache.length; float cping = inst_ping_ms; @@ -459,10 +462,28 @@ void UpdateMinPing() { true_avg += ping_cache[i]; true_avg /= N; + // Accuracy limitations hurt us here. + true_avg = max(true_avg, SERVER_FRAME_MS - 1); + + if (time < next_minv_update) + return; + + float old = DelayPacketState.minv; float target = max(ceil(min_ping - true_avg), 0); - // Bound convergence steps - DelayPacketState.minv = min(DelayPacketState.minv + 25, target); + if (target > 0) + target += 1; // Slightly bias up for stability and better equalization. + + if (fabs(target - old) >= 25) { + target = floor(target * 0.975); // Take big steps conservatively + next_ping_update = time + 3; // Time to reconverge + } else { + target = max(min(target, old + 3), old - 3); // Bound smaller updates. + next_ping_update = time + 3; // Time to reconverge + } + + DelayPacketState.minv = target; + next_minv_update = next_ping_update + 1; // Limit modulation } void WP_UpdatePings() { From 709606b7bbe60bfd37ad0dd1f2fdd7222e048ec7 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Apr 2023 16:38:41 -0700 Subject: [PATCH 2066/2474] weapon prediction: default on Now controlled by: fo_predict_weapons [default 1] fo_predict_projectiles [default 1] Also default enable tuning to match projectile prediction with player prediction. --- README.md | 7 +++---- csqc/main.qc | 4 ++++ csqc/weapon_predict.qc | 45 ++++++++++++++++++------------------------ share/prediction.qc | 2 +- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 5513657b..9d3cd6f2 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,9 @@ New commands * `fo_legacy_sbar 0` use oldschool Team Fortress status bar * `fo_oldscoreboard 0` use oldschool Quake scoreboard * `fo_adminrefresh 2` time in seconds for admin menu to refresh -* `fo_wpp_beta 0` client side weapon/projectile prediction -* `wpp_min_ping -1` minimum ping before `fo_wpp_beta` is enabled. -1 defaults to 40. -* `wpp_weap_predict -1` weapon prediction. 1 force on, 0 force off, -1 use fo_wpp_beta / server settings -* `wpp_proj_predict -1` projectile prediction. 1 force on, 0 force off, -1 use fo_wpp_beta / server settings +* `fo_predict_weapons 1` client-side weapon prediction +* `fo_predict_projectiles 1` client-side projectile prediction +* `wpp_min_ping -1` minimum ping before `fo_wpp_beta` is enabled. * `fo_client_sniper_sight 1` client side sniper dot * `cl_p2r` for old weapon impulses * `cl_r2g` for old weapon impulses diff --git a/csqc/main.qc b/csqc/main.qc index c07eab3b..8d026ced 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -662,5 +662,9 @@ void ClientSettings_Check() { printf("RECOMMEND: Setting `fo_grentimer 2` for ping correction.\n"); if (cvar("fo_hud_cache") != 1) printf("ERROR: Please set `fo_hud_cache 1` to improve fps.\n"); + if (cvar("fo_predict_weapons") != 1) + printf("WARNING: client-side weapon prediction disabled [fo_predict_weapons 0]\n"); + if (cvar("fo_predict_projectiles") != 1) + printf("WARNING: client-side projectile prediction disabled [fo_predict_projectiles 0]\n"); printf("Finished checking settings...\n"); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index e5b6915a..7606a3e0 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1,11 +1,12 @@ DEFCVAR_FLOAT(wpp_debug, 0); DEFCVAR_FLOAT(fo_wpp_beta, 0); +DEFCVAR_FLOAT(fo_predict_weapons, 1); +DEFCVAR_FLOAT(fo_predict_projectiles, 1); + DEFCVAR_FLOAT(fo_client_sniper_sight, 1); DEFCVAR_FLOAT(wpp_min_ping, -1); -DEFCVAR_FLOAT(wpp_weap_predict, -1); -DEFCVAR_FLOAT(wpp_proj_predict, -1); DEFCVAR_FLOAT(wpp_adv_selfp_ms, 0); DEFCVAR_FLOAT(wpp_adv_otherp_ms, 0); @@ -64,9 +65,6 @@ static float pred_time_dt; // delta-time that the world predicted forward by // Match up local interpolation of projectile position with that of players. static void update_interp_time_dt() { - if (CVARF(fo_wpp_beta) & 2 == 0) // Temporary gate bit. - return; - if (!CVARF(cl_predict_players)) { pred_time_dt = 0; return; @@ -131,7 +129,6 @@ float csqc_get_user_setting(string s_short, string s_long, string def); static float CalcPredEnabled(float current_enable, float unspec_default /* meaning of '-1' */, float server_disable, - float client_value, float dependent_enabled, string* set_by) { if (!dependent_enabled) { @@ -150,15 +147,10 @@ static float CalcPredEnabled(float current_enable, return FALSE; } - if (server_disable || client_value == 0) { - *set_by = server_disable ? "[server disable]" : "[cvar disable]"; - + if (server_disable) { + *set_by = "[server disable]"; return FALSE; } - if (client_value == 1) { - *set_by = sprintf("[cvar enable]"); - return TRUE; - } if (WP_MinPing() == 0) return current_enable; @@ -215,13 +207,13 @@ void WPP_Status() { string wp_source, pp_source; float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; - CalcPredEnabled(wp_enabled, CVARF(fo_wpp_beta), + CalcPredEnabled(wp_enabled, CVARF(fo_predict_weapons), fo_config.wp_global_disable, - CVARF(wpp_weap_predict), TRUE, &wp_source); + TRUE, &wp_source); - CalcPredEnabled(pp_enabled, CVARF(fo_wpp_beta), + CalcPredEnabled(pp_enabled, CVARF(fo_predict_projectiles), fo_config.wp_global_disable, - CVARF(wpp_proj_predict), wp_enabled, &pp_source); + wp_enabled, &pp_source); printf("Prediction Status:\n"); printf(" Weapon prediction %s %s\n", @@ -277,10 +269,13 @@ void WPP_UpdateEnable(float force) { // Immediate updates any time there's a cvar change. static float next_wpp_enable_check; - static float last_fo_wpp_beta; - if (CVARF(fo_wpp_beta) != last_fo_wpp_beta) { + static float last_fo_predict_weapons, last_fo_predict_projectiles; + + if (CVARF(fo_predict_weapons) != last_fo_predict_weapons || + CVARF(fo_predict_projectiles) != last_fo_predict_projectiles) { next_wpp_enable_check = 0; - last_fo_wpp_beta = CVARF(fo_wpp_beta); + last_fo_predict_weapons = CVARF(fo_predict_weapons); + last_fo_predict_projectiles = CVARF(fo_predict_projectiles); } if (avg_ping.samples.count < 5) @@ -290,19 +285,17 @@ void WPP_UpdateEnable(float force) { return; next_wpp_enable_check = time + 1; - // For wpp_weap_predict and wpp_proj_predict we use a tristate: - // 1 => force on, 0 => force off, -1 => up to min_ping/server float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; float wp_new = -1, pp_new = -1; string wp_source, pp_source; - wp_new = CalcPredEnabled(wp_enabled, CVARF(fo_wpp_beta), + wp_new = CalcPredEnabled(wp_enabled, CVARF(fo_predict_weapons), fo_config.wp_global_disable, - CVARF(wpp_weap_predict), TRUE, &wp_source); + TRUE, &wp_source); - pp_new = CalcPredEnabled(pp_enabled, CVARF(fo_wpp_beta), + pp_new = CalcPredEnabled(pp_enabled, CVARF(fo_predict_projectiles), fo_config.wp_global_disable, - CVARF(wpp_proj_predict), wp_new, &pp_source); + wp_new, &pp_source); static float once; if (wp_new != pengine.wp_enabled || !once) { diff --git a/share/prediction.qc b/share/prediction.qc index f5ded67e..298a6e47 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -576,7 +576,7 @@ void Predict_InitDefaultConfig() { fo_config.max_rewind_fast_projectile_ms = 150; fo_config.max_rewind_grenade_ms = 50; // Only affects REWIND_GREN fo_config.rewind_fast_projectile_thresh = 1500; - fo_config.wp_default_min_ping_ms = 40; + fo_config.wp_default_min_ping_ms = 25; fo_config.clown_flags = 0; fo_config.clown_grav = 400; } From cc6eb82c0268fa7c3c31d13aaaf7520f164e2105 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Apr 2023 16:38:54 -0700 Subject: [PATCH 2067/2474] readme: fix nits --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9d3cd6f2..b6a7f34f 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,11 @@ New commands * `fo_predict_projectiles 1` client-side projectile prediction * `wpp_min_ping -1` minimum ping before `fo_wpp_beta` is enabled. * `fo_client_sniper_sight 1` client side sniper dot -* `cl_p2r` for old weapon impulses -* `cl_r2g` for old weapon impulses -* `r_pyrotrail 0` -* `r_rockettrail 0` -* `r_grenadetrail 0` +* `cl_p2r` use rocket model for incendiary launcher +* `cl_r2g` use grenade model for rockets +* `r_pyrotrail 0` ezquake-compatible trail selection for incendiary launcher +* `r_rockettrail 0` ezquake-compatible trail selection for rocket launcher +* `r_grenadetrail 0` ezquake-compatible trail selection for grenade launcher * `wpp_phys_adv_ms 0` * `wpp_phys_local_adv_ms 0` * `wpp_setspeed 1` From fb35aa535a4b06bad706f8be18d44eb9f2d4d782 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 10 Apr 2023 23:29:20 -0700 Subject: [PATCH 2068/2474] weapon prediction: fix interp calculation inversion needs <= not < --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 7606a3e0..8eb27931 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -73,7 +73,7 @@ static void update_interp_time_dt() { // Maybe prefer smoothed value here? pred_time_dt = inst_ping_t; - if (CVARF(cl_predict_players_latency) < 1) + if (CVARF(cl_predict_players_latency) <= 1) pred_time_dt *= 1 - CVARF(cl_predict_players_latency); pred_time_dt *= CVARF(cl_predict_players_frac); From feb9bb30c3234e7b9e10e085cd570534ebb09456 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 14 Apr 2023 00:20:39 -0700 Subject: [PATCH 2069/2474] bodyqueue: rewrite the bodyqueue to actually work Currently guarantees each player leaves a body behind that lasts for 15s. We may end up wanting to limit the number of bodies that can exist at one time more aggressively (or reduce the timeout), but start by making bodies exist again. --- ssqc/clan.qc | 2 + ssqc/client.qc | 7 +-- ssqc/world.qc | 140 +++++++++++++++++++++++++++++++++++-------------- 3 files changed, 108 insertions(+), 41 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 3f773be1..34a3e3cd 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -168,6 +168,8 @@ void () StartMatch = //ResetPlayers(); CountMatchPlayersAndReset(); } + + FilterBodyQueue(TRUE); }; float () GetPlayerCount diff --git a/ssqc/client.qc b/ssqc/client.qc index c49040fe..7b1f46fb 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1322,11 +1322,11 @@ void () respawn = { } if (coop) { - CopyToBodyQue(self); + AddToBodyQueue(self); setspawnparms(self); PutClientInServer(); } else if (deathmatch) { - CopyToBodyQue(self); + AddToBodyQueue(self); SetNewParms(); PutClientInServer(); } else @@ -1425,7 +1425,8 @@ void () RemovePlayerOwnedEnts = { if (self.tfstate & TFSTATE_RANDOMPC) { te.tfstate = TFSTATE_RANDOMPC; } - } + } + RemoveDeadBody(self); } void (string cn) RemoveAllEntsByClassname = { diff --git a/ssqc/world.qc b/ssqc/world.qc index 52ad050e..cc57e9c2 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -1,4 +1,3 @@ -void () InitBodyQue; void () CheckTrackedSettings; void () TerminateStaleServer; @@ -99,7 +98,6 @@ void () worldspawn = { lastspawn = world; number_of_teams = 0; - InitBodyQue(); if (self.model == "maps/e1m8.bsp") cvar_set("sv_gravity", "100"); else @@ -388,6 +386,103 @@ void () worldspawn = { } }; +#if 0 +// Alternate implementation, drop if simple version is sufficient. +static const float BODYQUEUE_MAX = 32; + +static struct { + entity queue[BODYQUEUE_MAX]; + float num; +} bodies; + + +void ClearBodyQueue() { + for (float i = 0; i < bodies.nun; i++) + remove(bodies.queue[i]); + bodies.num = 0; +} + + +void FilterBodyQueue(entity filter) { + float i = 0, j = 0, num = 0; + + while (j < bodies.num) { + while (j < bodies.num && (bodies[j].heat > time || bodies[j].owner == filter)) + j++; + if (j >= bodies.num) + break; + + if (i != j) { + remove(bodies[i]); + bodies[i] = bodies[j]; + } + num++; + i++; + j++; + } + + bodies.num = num; +} +#endif + +static const float BODYQUEUE_TIMEOUT = 15; +.entity bodyqueue; + +void RemoveDeadBody(entity ent) { + if (ent.bodyqueue == __NULL__) + return; + + printf("removing body\n"); + remove(ent.bodyqueue); + ent.bodyqueue = __NULL__; +} + +void FilterBodyQueue(float clear) { + int count, i; + entity* bodies = find_list(classname, "bodyqueue", EV_STRING, count); + for (i = 0; i < count; i++) + if (time > bodies[i].heat || clear) { + printf("FILTER %d %s h=%0.3f t=%0.3f\n", clear, bodies[i].owner.netname, + bodies[i].heat, time); + RemoveDeadBody(bodies[i].owner); + } +} + +void AddToBodyQueue(entity ent) { + if (cb_prematch) + return; + + if (ent.model != "progs/player.mdl") + return; // in particular, filters out suicides + + if (ent.bodyqueue) + RemoveDeadBody(ent); + + printf("ADDING %s to queue f=%d m=%s/%d\n", ent.netname, ent.frame, + ent.model, ent.modelindex); + + entity nb = spawn(); + nb.owner = ent; + nb.heat = time + BODYQUEUE_TIMEOUT; + nb.classname = "bodyqueue"; + + nb.angles = ent.angles; + nb.model = ent.model; + nb.skin = ent.skin; + nb.modelindex = ent.modelindex; + nb.frame = ent.frame; + nb.colormap = ent.colormap; + nb.movetype = ent.movetype; + nb.velocity = ent.velocity; + nb.flags = 0; + setorigin(nb, ent.origin); + setsize(nb, ent.mins, ent.maxs); + + nb.dimension_seen = DMN_NOFLASH; + + ent.bodyqueue = nb; +}; + void () StartFrame = { teamplay = cvar("teamplay"); timelimit = cvar("timelimit") * 60; @@ -399,45 +494,14 @@ void () StartFrame = { CheckTrackedSettings(); TerminateStaleServer(); } -}; -entity bodyque_head; - -void () bodyque = { -}; - -void () InitBodyQue = { - bodyque_head = spawn(); - bodyque_head.classname = "bodyque"; - bodyque_head.owner = spawn(); - bodyque_head.owner.classname = "bodyque"; - bodyque_head.owner.owner = spawn(); - bodyque_head.owner.owner.classname = "bodyque"; - bodyque_head.owner.owner.owner = spawn(); - bodyque_head.owner.owner.owner.classname = "bodyque"; - bodyque_head.owner.owner.owner.owner = bodyque_head; - -}; - -void (entity ent) CopyToBodyQue = { - if (cb_prematch) - return; - - bodyque_head.angles = ent.angles; - bodyque_head.model = ent.model; - bodyque_head.skin = ent.skin; - bodyque_head.modelindex = ent.modelindex; - bodyque_head.frame = ent.frame; - bodyque_head.colormap = ent.colormap; - bodyque_head.movetype = ent.movetype; - bodyque_head.velocity = ent.velocity; - bodyque_head.flags = 0; - setorigin(bodyque_head, ent.origin); - setsize(bodyque_head, ent.mins, ent.maxs); - bodyque_head = bodyque_head.owner; + static float next_filter_bodyqueue; + if (time > next_filter_bodyqueue) { + FilterBodyQueue(FALSE); + next_filter_bodyqueue = time + 0.5; + } }; - // this is used for spawning world objects on map load.. not player, projectiles etc - also disables the engine's conditional spawning based on spawnflags, you're expected to do that part yourself void(void() fnc)CheckSpawn = { if(fnc) From 83d09be0d534b6174f9e7cd64f18e7f745a69e36 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 14 Apr 2023 00:27:14 -0700 Subject: [PATCH 2070/2474] misc: world loop clean-up - Remove unmaintained (and not really working) tracked settings code. The new settings are all client reported via wpp_status anyway. We can make changes to them noisy if it's ever an issue (they aren't now). - change stale server check to be once a minute instead of once a second and timeout to be 6 hours so we cycle progs through faster / keep servers fresher. --- ssqc/commands.qc | 12 ------------ ssqc/defs.qc | 1 - ssqc/qw.qc | 16 ---------------- ssqc/world.qc | 35 +++++++---------------------------- 4 files changed, 7 insertions(+), 57 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5dfc5c81..629de952 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -300,15 +300,6 @@ void (entity pl) PrintWho = { strunzone(msg); } -void () OutputTrackedSettings = { - bprint(PRINT_HIGH, self.netname, " called for a settings check (fo_settings_status)\n"); - for (float i = 0; i < settings_to_track_list.length; i++) - { - setting_t* s = &settings_to_track[i]; - bprint(PRINT_HIGH, "Setting ", s.setting_name, " is currently ", s.value, "\n"); - } -} - float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; @@ -328,9 +319,6 @@ float (string arg1, string arg2, string arg3) ParseCmds = { self.impulse = stof(arg2); } break; - case "fo_settings_status": - OutputTrackedSettings(); - break; case "progsversion": // yy.mm.dd.incremented vers sprint(self, PRINT_HIGH, "sv progs version: 22.02.13.1\n"); diff --git a/ssqc/defs.qc b/ssqc/defs.qc index 700e8da4..2ee18387 100644 --- a/ssqc/defs.qc +++ b/ssqc/defs.qc @@ -190,7 +190,6 @@ string string_null; // null string, nothing should be held here entity activator; // the entity that activated a trigger or brush entity damage_attacker; // set by T_Damage -float framecount; // cvars checked each frame float skill; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 7c5b061d..52bd379f 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -797,19 +797,3 @@ string goal_class_names[7] = { // backend string match_id; - -// people complain about settings, let's track them - -string settings_to_track_list[4] = { - "sv_antilag", - "project_weapons", - "al_rewind_detpipe", - "al_max_remote_client_time_offset", -}; - -struct setting_t { - string setting_name; - string value; -}; - -setting_t *settings_to_track; diff --git a/ssqc/world.qc b/ssqc/world.qc index cc57e9c2..b7926631 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -1,4 +1,3 @@ -void () CheckTrackedSettings; void () TerminateStaleServer; string (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSettingString; @@ -375,15 +374,6 @@ void () worldspawn = { dimension_send = DMN_NOFLASH; Predict_Init(); - - settings_to_track = memalloc(sizeof(*settings_to_track)*settings_to_track_list.length); - for (float i = 0; i < settings_to_track_list.length; i++) - { - settings_to_track[i].setting_name = settings_to_track_list[i]; - string val = infokey(world, settings_to_track_list[i]); - val = (val != "") ? val : "unset"; - settings_to_track[i].value = val; - } }; #if 0 @@ -488,11 +478,11 @@ void () StartFrame = { timelimit = cvar("timelimit") * 60; fraglimit = cvar("fraglimit"); deathmatch = cvar("deathmatch"); - framecount = framecount + 1; - if (framecount % 77 == 0) { - CheckTrackedSettings(); + static float next_stale_check; + if (time > next_stale_check) { TerminateStaleServer(); + next_stale_check = time + 60; } static float next_filter_bodyqueue; @@ -517,21 +507,9 @@ void(void() fnc)CheckSpawn = { } }; -void () CheckTrackedSettings = { - for (float i = 0; i < settings_to_track_list.length; i++) - { - setting_t* s = &settings_to_track[i]; - string new_val = infokey(world, s.setting_name); - if (new_val != s.value) - { - bprint(PRINT_HIGH, "Setting ", s.setting_name, " has been changed from ", s.value, " to ", new_val, "\n"); - s.value = new_val; - } - } -} - +static const float STALE_TIME_HOURS = 6; void () TerminateStaleServer = { - if (gettime() < 86400) + if (gettime() < STALE_TIME_HOURS * 3600) return; for (entity e = world; (e = find(e, classname, "player")); ) { @@ -539,6 +517,7 @@ void () TerminateStaleServer = { return; //someone is around } - dprint("Terminating empty server with more than 24 hours uptime\n"); + dprint(sprintf("Terminating empty server with more than %d hours uptime\n", + STALE_TIME_HOURS)); localcmd("quit\n"); } From e4d998d4a736b9dc72853af2e0bf4665379a03dd Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 14 Apr 2023 00:31:50 -0700 Subject: [PATCH 2071/2474] bodyqueue: remove debug prints derp --- ssqc/world.qc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/ssqc/world.qc b/ssqc/world.qc index b7926631..ef7a4404 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -422,7 +422,6 @@ void RemoveDeadBody(entity ent) { if (ent.bodyqueue == __NULL__) return; - printf("removing body\n"); remove(ent.bodyqueue); ent.bodyqueue = __NULL__; } @@ -431,11 +430,8 @@ void FilterBodyQueue(float clear) { int count, i; entity* bodies = find_list(classname, "bodyqueue", EV_STRING, count); for (i = 0; i < count; i++) - if (time > bodies[i].heat || clear) { - printf("FILTER %d %s h=%0.3f t=%0.3f\n", clear, bodies[i].owner.netname, - bodies[i].heat, time); + if (time > bodies[i].heat || clear) RemoveDeadBody(bodies[i].owner); - } } void AddToBodyQueue(entity ent) { @@ -448,9 +444,6 @@ void AddToBodyQueue(entity ent) { if (ent.bodyqueue) RemoveDeadBody(ent); - printf("ADDING %s to queue f=%d m=%s/%d\n", ent.netname, ent.frame, - ent.model, ent.modelindex); - entity nb = spawn(); nb.owner = ent; nb.heat = time + BODYQUEUE_TIMEOUT; From c617ca541eab6b731eb70a08151bddc024fc3152 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 03:26:05 -0700 Subject: [PATCH 2072/2474] weapons: experimental new concussion grenade affects aim rather than movement Aim and crosshair traces a figure 8 which player must correct for, movement also subtly trends in that direction. Variety of flags for some initial tuning, but the most basic is enabled via `localinfo foc 1` --- csqc/events.qc | 5 +++ csqc/main.qc | 80 ++++++++++++++++++++++++++++++++++++++++++ csqc/weapon_predict.qc | 1 + share/commondefs.qc | 3 +- ssqc/client.qc | 9 +++++ ssqc/qw.qc | 9 +++++ ssqc/scout.qc | 7 ++++ ssqc/status.qc | 20 +++++++++++ 8 files changed, 133 insertions(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index d19d5965..bc3251bd 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -356,6 +356,11 @@ void() CSQC_Parse_Event = { case MSG_UNPAUSE: CsGrenTimer::SyncUnpause(); break; + case MSG_CONCUSSED: + cuss_state.amp = readbyte(); + cuss_state.end_time = readfloat(); + break; + } } diff --git a/csqc/main.qc b/csqc/main.qc index 8d026ced..d42527d9 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -167,6 +167,7 @@ noref void() CSQC_WorldLoaded = { localcmd("menu_restart\n"); } +void FO_CussCrosshair(float width, float height); void Hud_UpdateView(float width, float height, float menushown, float perf_sample); DEFCVAR_FLOAT(fov, 90); @@ -194,6 +195,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { RenderHitTexts(); Hud_UpdateView(width, height, menushown, fts); + FO_CussCrosshair(width, height); perf_finish_sample(&frame_timing, fts); // Work around bug in some versions of FTE. See pmove.qc @@ -496,6 +498,82 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; +struct { + float old_x, old_y; + float cussed; + float end_time; + float amp; +} cuss_state; + +vector FO_Conc_Offset() { + const float P = 4; + + float rem = cuss_state.end_time - time; + if (rem < 0) + return '0 0 0'; + + float a = ((rem % P) / P) * 2 * M_PI; + float amp = 2 + cuss_state.amp * min(8, rem)/8; + + float x = amp * sin(a), y = amp * sin(a) * cos(a); + return [x, y, 0]; +} + + +vector FO_ConcAim() { + vector o = FO_Conc_Offset(); + + vector r = v_forward * 200 + o.x * v_right + o.y * v_up; + return normalize(r); +} + +DEFCVAR_FLOAT(cl_crossx, 0); +DEFCVAR_FLOAT(cl_crossy, 0); + +void FO_CussCrosshair(float width, float height) { + // Limit the rendering speed to reduce blur + static float next_update; + if (time < next_update) + return; + next_update += 0.025; + + + if (time >= cuss_state.end_time) { + if (cuss_state.cussed) { + // Make sure we restore crosshairs + localcmd(sprintf("cl_crossx %d; cl_crossy %d;\n", + cuss_state.old_x, cuss_state.old_y)); + cuss_state.cussed = FALSE; + } + return; + } + + if (!cuss_state.cussed) { + /* cuss_state.old_x = CVARF(cl_crossx); */ + /* cuss_state.old_y = CVARF(cl_crossy); */ + cuss_state.old_x = 0; // TODO: properly save and restore these + cuss_state.old_y = 0; + cuss_state.cussed = TRUE; + } + + makevectors(input_angles); // updated by input_frame + vector p = project(pmove_org + 8000 * v_forward); + + localcmd(sprintf("cl_crossx %d; cl_crossy %d;\n", + cuss_state.old_x + p_x - width / 2, + cuss_state.old_y + p_y - height / 2)); +} + +void FO_UpdateCuss() { + if (time < cuss_state.end_time) { + makevectors(input_angles); + input_angles = vectoangles(FO_ConcAim()); + makevectors(input_angles); + input_angles_x *= -1; + } + +} + noref void CSQC_Input_Frame() { Sync_GameState(); @@ -513,6 +591,8 @@ noref void CSQC_Input_Frame() { if (prev_zoomed_in != zoomed_in) setsensitivityscaler(zoomed_in ? 1/3 : 1); + + FO_UpdateCuss(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 8eb27931..52c96197 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1082,6 +1082,7 @@ void MP_SetSpeed() { } +DEFCVAR_FLOAT(cl_crossx, 0); void WP_Frame() { if (!is_alive) { diff --git a/share/commondefs.qc b/share/commondefs.qc index 974ec757..4f6ebaf9 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -190,7 +190,8 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_TFX_GRENTIMER 25 #define MSG_QUAD_ROUND_BEGIN 26 #define MSG_LOGIN 27 -#define MSG_HITFLAG 28 +#define MSG_HITFLAG 28 +#define MSG_CONCUSSED 29 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 #define FLAGINFO_DROPPED 3 diff --git a/ssqc/client.qc b/ssqc/client.qc index 7b1f46fb..a1a9732e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -571,6 +571,15 @@ void () DecodeLevelParms = { // medic immune to concussion grenade effects [on] medicnocuss = CF_GetSetting("mnc", "medicnocuss", "on"); + // aim based concussion grenade effect + fo_concuss = CF_GetSetting("foc", "fo_cuss", "0"); + + // Tie some of these other options together for convenience / other + if (fo_concuss & FOC_DISTANCE) + distance_based_cuss_duration = TRUE; + if (fo_concuss & FOC_AFF_MED) + medicnocuss = FALSE; + // display sniper rifle power in status bar [on] sniperpower = CF_GetSetting("sp", "sniperpower", "on"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 52bd379f..1a8a64d0 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -651,6 +651,15 @@ float engineer_move; float fo_projectiles; +enumflags { + FOC_ON, + FOC_DISTANCE, + FOC_AFF_MED, + FOC_RED_MED, + FOC_RED_HVY, +}; +float fo_concuss; + float numlocs; typedef struct {vector pos; string desc;} loc_t; loc_t *locs; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 7bd62546..136c192b 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -841,6 +841,13 @@ void (entity inflictor, entity attacker, float bounce, speedbump.owner = head; } + if (fo_concuss & FOC_ON) { + UpdateClientConcussion(head, actual_cuss_time); + + head = head.chain; + continue; + } + te = find(world, classname, "timer"); if (old_grens == TRUE) while (((te.owner != head) || diff --git a/ssqc/status.qc b/ssqc/status.qc index f692dd08..b7df13f1 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -614,6 +614,26 @@ void (entity Player) InitAllStatuses = { } }; +void UpdateClientConcussion(entity player, float duration) { + msg_entity = player; + + float amp = 50; + + if ((player.playerclass == PC_HVYWEAP) && (fo_concuss & FOC_RED_HVY)) { + amp /= 2; + } + + if ((player.playerclass == PC_MEDIC) && (fo_concuss & FOC_RED_MED)) { + duration /= 2; + } + + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_CONCUSSED); + WriteByte(MSG_MULTICAST, amp); + WriteFloat(MSG_MULTICAST, time + duration); + multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); +} + float laststate; void (entity Player, entity Goal) UpdateClientButtonStatus = { if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) From 55909c780ca5f52f23adcc025d7ce49ca09dabbc Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 11:51:42 -0700 Subject: [PATCH 2073/2474] weapon prediction: reduce hysteresis/logging Stop prediction flipping between off and on at boundary ping values by sliding the ping we enable at down as we're crossing for stability. Also reduce how verbose the logging is. Finally increment version number. --- csqc/weapon_predict.qc | 53 +++++++++++++++++++++++++----------------- share/prediction.qc | 6 +---- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 52c96197..a9e80c18 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -126,8 +126,7 @@ float csqc_get_user_setting(string s_short, string s_long, string def); // Order of preference: // server disable, client enable/disable, server/ping enable -static float CalcPredEnabled(float current_enable, - float unspec_default /* meaning of '-1' */, +static float CalcPredEnabled(float current_enable, float cvar, float server_disable, float dependent_enabled, string* set_by) { @@ -152,29 +151,39 @@ static float CalcPredEnabled(float current_enable, return FALSE; } + if (!cvar) { + *set_by = "[disabled]"; + return FALSE; + } + if (WP_MinPing() == 0) return current_enable; float ping_enable, avg, variance; fill_avg_ping(&avg, &variance); - // We wait until 5ms over target (or 5 ms under target) when flipping, to - // avoid flip flopping when ping is right at target. - if (variance < sq(15)) - ping_enable = avg > WP_MinPing() + (current_enable ? -5 : 5); - else - return current_enable; // variance too high, don't change anything. + if (variance > sq(15)) { + *set_by = "[ping not yet stable]"; + return current_enable; // variance too high, wait. + } - if (unspec_default) { - if (ping_enable) { - *set_by = sprintf("[ping >%d] (avg=%0.0f var=%0.0f)", - WP_MinPing(), avg, variance); - return TRUE; - } else { - *set_by = sprintf("[lan mode <%d]", WP_MinPing()); - return FALSE; - } + static float hyst = 0; + ping_enable = avg > WP_MinPing() - hyst; + if (ping_enable != current_enable) { + if (!hyst) // avoid flip-flopping on boundary values. + hyst = 10; + else + hyst += 5; + } + + if (ping_enable) { + *set_by = sprintf("[ping >%d] (avg=%0.0f var=%0.0f)", + WP_MinPing(), avg, variance); + return TRUE; + } else { + *set_by = sprintf("[lan mode <%d]", WP_MinPing()); + return FALSE; } *set_by = "[disabled]"; @@ -299,8 +308,9 @@ void WPP_UpdateEnable(float force) { static float once; if (wp_new != pengine.wp_enabled || !once) { - printf("FortressOne: Weapon prediction %s %s\n", - wp_new ? "enabled" : "disabled", wp_source); + if (!CVARF(fo_predict_projectiles) && is_player) + printf("FortressOne: Weapon prediction (no projectiles) %s %s\n", + wp_new ? "enabled" : "disabled", wp_source); pengine.wp_enabled = wp_new; if (wp_new) { @@ -314,8 +324,9 @@ void WPP_UpdateEnable(float force) { } if (pp_new != pengine.pp_enabled || !once) { - printf("FortressOne: Projectile prediction %s %s\n", - pp_new ? "enabled" : "disabled", pp_source); + if (is_player) + printf("FortressOne: Weapon/Projectile prediction %s %s\n", + pp_new ? "enabled" : "disabled", pp_source); pengine.pp_enabled = pp_new; next_wpp_enable_check += 9; diff --git a/share/prediction.qc b/share/prediction.qc index 298a6e47..9aef84c6 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -5,7 +5,7 @@ // Below apply to both CSQC & SSQC ents .float antilag_ms; -string wp_version = "v0.4-phys"; +string wp_version = "v1.0"; enumflags { FOWP_CTIME, @@ -705,10 +705,6 @@ void Predict_InitPlayer(entity player) { sprint(player, PRINT_HIGH, "FortressOne: Weapon Prediction ", wp_version, "\n"); - sprint(player, PRINT_HIGH, "FortressOne: CSQC projectiles ", - fo_projectiles ? "enabled\n" : "disabled\n"); - sprint(player, PRINT_HIGH, "FortressOne: QC Physics ", - fo_config.qc_physics ? "enabled\n" : "disabled\n"); entity pe = spawn(); pe.owner = player; From 0a836cbf66319f25bafd2c4141b61851b6e5a110 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 12:42:44 -0700 Subject: [PATCH 2074/2474] prediction: move conc state into tfstate and predict make concussion state a property of tfstate rather than a stand-alone. This allows prediction around the various types as well as behaviors such as clear-on-respawn and heal to be standardized. --- csqc/events.qc | 5 ----- csqc/main.qc | 26 +++++++++++--------------- csqc/weapon_predict.qc | 30 +++++++++++++++++++++++++++--- share/commondefs.qc | 1 - share/defs.h | 1 + share/prediction.qc | 10 ++++++++++ ssqc/qw.qc | 3 ++- ssqc/scout.qc | 13 ++++++++----- ssqc/status.qc | 9 ++++----- ssqc/tfort.qc | 3 +-- ssqc/weapons.qc | 1 + 11 files changed, 65 insertions(+), 37 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index bc3251bd..d19d5965 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -356,11 +356,6 @@ void() CSQC_Parse_Event = { case MSG_UNPAUSE: CsGrenTimer::SyncUnpause(); break; - case MSG_CONCUSSED: - cuss_state.amp = readbyte(); - cuss_state.end_time = readfloat(); - break; - } } diff --git a/csqc/main.qc b/csqc/main.qc index d42527d9..abef208d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -498,12 +498,9 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; -struct { - float old_x, old_y; - float cussed; - float end_time; - float amp; -} cuss_state; +static float IsConced() { + return pstate_pred.tfstate & TFSTATE_CONC; +} vector FO_Conc_Offset() { const float P = 4; @@ -513,7 +510,7 @@ vector FO_Conc_Offset() { return '0 0 0'; float a = ((rem % P) / P) * 2 * M_PI; - float amp = 2 + cuss_state.amp * min(8, rem)/8; + float amp = 2 + pstate_server.conc_amp * min(8, rem)/8; float x = amp * sin(a), y = amp * sin(a) * cos(a); return [x, y, 0]; @@ -537,8 +534,7 @@ void FO_CussCrosshair(float width, float height) { return; next_update += 0.025; - - if (time >= cuss_state.end_time) { + if (!IsConced()) { if (cuss_state.cussed) { // Make sure we restore crosshairs localcmd(sprintf("cl_crossx %d; cl_crossy %d;\n", @@ -565,13 +561,13 @@ void FO_CussCrosshair(float width, float height) { } void FO_UpdateCuss() { - if (time < cuss_state.end_time) { - makevectors(input_angles); - input_angles = vectoangles(FO_ConcAim()); - makevectors(input_angles); - input_angles_x *= -1; - } + if (!IsConced()) + return; + makevectors(input_angles); + input_angles = vectoangles(FO_ConcAim()); + makevectors(input_angles); + input_angles_x *= -1; } noref void CSQC_Input_Frame() { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index a9e80c18..ebd9dbc5 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -83,7 +83,7 @@ static void update_interp_time_dt() { // Unlike server_time(), interp_time() is continuous and reflects how much we've // projected the local copy of the world forward. Monotonic. -static float interp_time() { +float interp_time() { static float last_interp_time = 0; last_interp_time = max(last_interp_time, time + pred_time_dt); @@ -1721,12 +1721,36 @@ void WP_UpdateViewModel() { viewmodel.lerpfrac = max(0, viewmodel.lerpfrac - frametime * 10); } +struct { + float old_x, old_y; + float cussed; + + float end_time; +} cuss_state; + +void PredictConc() { + if (pstate_server.tfstate & TFSTATE_CONC == 0) + return; + + static float last_conc_finished; + if (pstate_server.conc_finished != last_conc_finished) { + // New conc, use a single fixed local finish time. + last_conc_finished = pstate_server.conc_finished; + cuss_state.end_time = pstate_server.conc_finished - server_time_dt(); + } + + if (time > cuss_state.end_time) { + pstate_pred.tfstate &= ~TFSTATE_CONC; + } +} + float WP_ClientThink() { + pstate_pred = pstate_server; + PredictConc(); + if (!WP_Enabled()) return PREDRAW_NEXT; - pstate_pred = pstate_server; - getinputstate(servercommandframe); // Setup first read for old_buttons. pengine.last_effectframe2 = pengine.last_effectframe; diff --git a/share/commondefs.qc b/share/commondefs.qc index 4f6ebaf9..bb0ec128 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -191,7 +191,6 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_QUAD_ROUND_BEGIN 26 #define MSG_LOGIN 27 #define MSG_HITFLAG 28 -#define MSG_CONCUSSED 29 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 #define FLAGINFO_DROPPED 3 diff --git a/share/defs.h b/share/defs.h index 61aa3433..51d1b1b8 100644 --- a/share/defs.h +++ b/share/defs.h @@ -248,6 +248,7 @@ enumflags { TFSTATE_GRENTHROWING, // is throwing a grenade TFSTATE_AIMING, // is using the laser sight or spinning TFSTATE_CANT_MOVE, + TFSTATE_CONC, TFSTATE_NO_WEAPON, // Weapon is disabled and not visible (e.g. detpack) // (Note: We don't use NO_WEAPON for reloading // as it could result in stacked no-weapon states.) diff --git a/share/prediction.qc b/share/prediction.qc index 9aef84c6..56570dec 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -12,6 +12,7 @@ enumflags { FOWP_IMPULSE, FOWP_TFSTATE, FOWP_LASTPRIME, + FOWP_CONCFINISH, FOWP_CLIP, FOWP_THINK, FOWP_WF, @@ -54,6 +55,9 @@ struct predict_tf_state { float last_prime; float csqc_maxspeed; + float conc_amp; + float conc_finished; + float client_time; float client_ping; float weaponframe; @@ -320,6 +324,7 @@ static float Prediction_ChangedMask(entity player) { M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); M2(FOWP_TFSTATE, tfstate, csqc_maxspeed); M1(FOWP_LASTPRIME, last_prime); + M2(FOWP_CONCFINISH, conc_finished, conc_amp); M1(FOWP_WF, weaponframe); M1(FOWP_AF, attack_finished); M2(FOWP_THINK, client_nextthink, client_thinkindex); @@ -446,6 +451,11 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Float, last_prime); } + if (sendflags & FOWP_CONCFINISH) { + COMM(Byte, conc_amp); + COMM(Float, conc_finished); + } + if (sendflags & FOWP_THINK) { COMM(Float, client_nextthink); COMM(Float, client_thinkindex); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 1a8a64d0..acd3b71b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -60,7 +60,6 @@ float remote_client_time(); .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage .float is_unabletospy; // TRUE for a SPY if they can't go undercover .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in -.float is_concussed; // TRUE for a player who is affected by concussion grenade .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team .float has_changedclass; // TRUE for a player that has changed class @@ -784,6 +783,8 @@ float FO_FlashDimension; .entity grenade_timer; .float last_throw; .float last_prime; +.float conc_amp; +.float conc_finished; // allow for default goal state .float default_group_no; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 136c192b..a37fd281 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -417,8 +417,10 @@ void () OldConcussionGrenadeTimer = { stuffcmd(self.owner, "fov "); stuffcmd(self.owner, st); stuffcmd(self.owner, "\n"); - if (self.health == 0) + if (self.health == 0) { + self.tfstate &= ~TFSTATE_CONC; dremove(self); + } }; void () ConcussionGrenadeTimer = { @@ -430,7 +432,7 @@ void () ConcussionGrenadeTimer = { if (self.owner.invincible_finished > time) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); self.owner.fixangle = 0; - self.owner.is_concussed = 0; + self.owner.tfstate &= ~TFSTATE_CONC; dremove(self); return; } @@ -494,7 +496,7 @@ void () ConcussionGrenadeTimer = { } if (self.health <= 0) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); - self.owner.is_concussed = 0; + self.owner.tfstate &= ~TFSTATE_CONC; dremove(self); } }; @@ -832,7 +834,9 @@ void (entity inflictor, entity attacker, float bounce, } } - if (distance_based_cuss_duration + head.tfstate |= TFSTATE_CONC; + + if (distance_based_cuss_duration && ((head.playerclass == PC_MEDIC) || (head.playerclass == PC_SCOUT))) { entity speedbump; speedbump = spawn(); @@ -892,7 +896,6 @@ void (entity inflictor, entity attacker, float bounce, te.classname = "timer"; te.owner = head; te.health = 40 * actual_cuss_time; - self.owner.is_concussed = 1; } } } diff --git a/ssqc/status.qc b/ssqc/status.qc index b7df13f1..05821b91 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -617,6 +617,7 @@ void (entity Player) InitAllStatuses = { void UpdateClientConcussion(entity player, float duration) { msg_entity = player; + // TODO: obviously doesn't need to be server side float amp = 50; if ((player.playerclass == PC_HVYWEAP) && (fo_concuss & FOC_RED_HVY)) { @@ -627,11 +628,9 @@ void UpdateClientConcussion(entity player, float duration) { duration /= 2; } - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_CONCUSSED); - WriteByte(MSG_MULTICAST, amp); - WriteFloat(MSG_MULTICAST, time + duration); - multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); + // networked via prediction ent + player.conc_amp = amp; + player.conc_finished = time + duration; } float laststate; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 30d403c5..43401712 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1508,7 +1508,6 @@ void () TeamFortress_SetEquipment = { self.is_feigning = 0; self.next_feign_time = 0; self.is_unabletospy = 0; - self.is_concussed = 0; self.disguise_skin = 0; self.disguise_team = 0; self.detpack_left = 0; @@ -2256,7 +2255,7 @@ void () TeamFortress_RemoveTimers = { local entity te; self.leg_damage = 0; - self.is_concussed = 0; + self.tfstate &= ~TFSTATE_CONC; self.is_undercover = 0; if (self.is_building && engineer_move) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 3dacf031..299242d3 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -434,6 +434,7 @@ int () W_FireMedikit = { if (te.team_no != self.team_no) TF_AddFrags(self, 1); + trace_ent.tfstate &= ~TFSTATE_CONC; dremove(te); } if (trace_ent.tfstate & TFSTATE_HALLUCINATING) { From e736e06f2398c8a3926f467fc4737447c0ab08d4 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 11:35:03 -0700 Subject: [PATCH 2075/2474] experiment: tuning for new concussion effect - add some head bob - with prior patch, now healable, clears on respawn, etc - blended curve to ramp down conc effect first 4s: full conc 6s-2s: blend down to 50% 2s-0s: blend down to 0% - scouts get double effect --- csqc/main.qc | 30 +++++++++++++++++++++++++++++- csqc/weapon_predict.qc | 2 ++ ssqc/status.qc | 5 ++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index abef208d..af663dae 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -167,6 +167,7 @@ noref void() CSQC_WorldLoaded = { localcmd("menu_restart\n"); } +void FO_CussView(); void FO_CussCrosshair(float width, float height); void Hud_UpdateView(float width, float height, float menushown, float perf_sample); @@ -177,6 +178,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + // + FO_CussView(); if (zoomed_in) setviewprop(VF_AFOV, CVARF(fov)/3); @@ -191,11 +194,12 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { addentities(mask); renderscene(); + + FO_CussCrosshair(width, height); TFxRenderGrenadeTimers(); RenderHitTexts(); Hud_UpdateView(width, height, menushown, fts); - FO_CussCrosshair(width, height); perf_finish_sample(&frame_timing, fts); // Work around bug in some versions of FTE. See pmove.qc @@ -502,6 +506,11 @@ static float IsConced() { return pstate_pred.tfstate & TFSTATE_CONC; } + +static float BlendAmp(float start, float end, float rem, float D) { + return rem/D * end + (D-rem)/D * start; +} + vector FO_Conc_Offset() { const float P = 4; @@ -510,6 +519,16 @@ vector FO_Conc_Offset() { return '0 0 0'; float a = ((rem % P) / P) * 2 * M_PI; + + float amp = pstate_server.conc_amp; + if (rem >= 6) + amp *= 1; + else if (rem >= 2) + amp *= BlendAmp(1.0, 0.5, rem - 2, 6 - 2); + else + amp *= BlendAmp(0.5, 0, rem, 2); + + float amp = 2 + pstate_server.conc_amp * min(8, rem)/8; float x = amp * sin(a), y = amp * sin(a) * cos(a); @@ -521,12 +540,21 @@ vector FO_ConcAim() { vector o = FO_Conc_Offset(); vector r = v_forward * 200 + o.x * v_right + o.y * v_up; + + cuss_state.view = vectoangles(v_forward * 200 + o.x/4 * v_right + o.y/4 * v_up); + cuss_state.view[0] *= -1; + return normalize(r); } DEFCVAR_FLOAT(cl_crossx, 0); DEFCVAR_FLOAT(cl_crossy, 0); +void FO_CussView() { + if (cuss_state.cussed) + setproperty(VF_ANGLES, cuss_state.view); +}; + void FO_CussCrosshair(float width, float height) { // Limit the rendering speed to reduce blur static float next_update; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ebd9dbc5..530ee8e5 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1726,6 +1726,8 @@ struct { float cussed; float end_time; + + vector view; } cuss_state; void PredictConc() { diff --git a/ssqc/status.qc b/ssqc/status.qc index 05821b91..02315059 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -618,7 +618,7 @@ void UpdateClientConcussion(entity player, float duration) { msg_entity = player; // TODO: obviously doesn't need to be server side - float amp = 50; + float amp = 100; if ((player.playerclass == PC_HVYWEAP) && (fo_concuss & FOC_RED_HVY)) { amp /= 2; @@ -628,6 +628,9 @@ void UpdateClientConcussion(entity player, float duration) { duration /= 2; } + if (player.playerclass == PC_SCOUT) + amp *= 2; + // networked via prediction ent player.conc_amp = amp; player.conc_finished = time + duration; From 8d8a81a25daa18ace90ed629a91638979bd40572 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 13:36:28 -0700 Subject: [PATCH 2076/2474] experimental: make some cuss parameters tunable foca -- base amplitude [default 100] focs -- scout multiplier [default 1.5] focs -- medic multiplier (when affected) [default 0.5] foch -- heavy multiplier [default 0.75] --- ssqc/qw.qc | 1 - ssqc/status.qc | 27 +++++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index acd3b71b..2e3a9c70 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -655,7 +655,6 @@ enumflags { FOC_DISTANCE, FOC_AFF_MED, FOC_RED_MED, - FOC_RED_HVY, }; float fo_concuss; diff --git a/ssqc/status.qc b/ssqc/status.qc index 02315059..dc117e4e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -617,20 +617,27 @@ void (entity Player) InitAllStatuses = { void UpdateClientConcussion(entity player, float duration) { msg_entity = player; - // TODO: obviously doesn't need to be server side + static float scout_mult = 1.5; + static float medic_mult = 0.5; + static float heavy_mult = 0.5; float amp = 100; - if ((player.playerclass == PC_HVYWEAP) && (fo_concuss & FOC_RED_HVY)) { - amp /= 2; + // Once non debug, these should be once per map. + amp = CF_GetSetting("foca", "fo_cuss_amp", "100"); + scout_mult = CF_GetSetting("focs", "fo_cuss_scout", "1.5"); + medic_mult = CF_GetSetting("focm", "fo_cuss_medic", "0.5"); + heavy_mult = CF_GetSetting("foch", "fo_cuss_heavy", "0.75"); + + if (player.playerclass == PC_HVYWEAP) { + amp *= heavy_mult; + } else if (player.playerclass == PC_SCOUT) { + amp *= scout_mult; + } else if (player.playerclass == PC_MEDIC) { + if (fo_concuss & FOC_RED_MED) + duration /= 2; + amp *= medic_mult; } - if ((player.playerclass == PC_MEDIC) && (fo_concuss & FOC_RED_MED)) { - duration /= 2; - } - - if (player.playerclass == PC_SCOUT) - amp *= 2; - // networked via prediction ent player.conc_amp = amp; player.conc_finished = time + duration; From 0d4b92fdb8b9620269bcffc656ebf66b500e1bae Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 13:45:30 -0700 Subject: [PATCH 2077/2474] clown: add a perma conc clown flag --- csqc/main.qc | 4 ++-- csqc/weapon_predict.qc | 9 +++++++++ share/commondefs.qc | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index af663dae..31f4f947 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -520,7 +520,7 @@ vector FO_Conc_Offset() { float a = ((rem % P) / P) * 2 * M_PI; - float amp = pstate_server.conc_amp; + float amp = pstate_pred.conc_amp; if (rem >= 6) amp *= 1; else if (rem >= 2) @@ -529,7 +529,7 @@ vector FO_Conc_Offset() { amp *= BlendAmp(0.5, 0, rem, 2); - float amp = 2 + pstate_server.conc_amp * min(8, rem)/8; + float amp = 2 + pstate_pred.conc_amp * min(8, rem)/8; float x = amp * sin(a), y = amp * sin(a) * cos(a); return [x, y, 0]; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 530ee8e5..ebb4295e 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1731,6 +1731,15 @@ struct { } cuss_state; void PredictConc() { + if (fo_config.clown_flags & CLOWN_CONC) { + if (cuss_state.end_time < time + 6) + cuss_state.end_time += 4; // Must align with period. + + pstate_pred.conc_amp = 100; + pstate_pred.tfstate |= TFSTATE_CONC; + return; + } + if (pstate_server.tfstate & TFSTATE_CONC == 0) return; diff --git a/share/commondefs.qc b/share/commondefs.qc index bb0ec128..39f5d80c 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -125,6 +125,7 @@ enumflags { CLOWN_RUBBERGREN, CLOWN_PROJ_GRAVITY, CLOWN_LETHAL_TRANQ, + CLOWN_CONC, CLOWN_STICKY_GRENS, CLOWN_STICKY_PIPES, CLOWN_SPAM_GRENADES, @@ -135,6 +136,7 @@ string CLOWN_DESC[] = { "rubber grenades", "projectile gravity", "elephant tranq", + "perma conc", "sticky grenades", "sticky pipes", "no grenade prime-time", From 8b8ff3bd03bde834dfc18ffd440b3ae8a4bebd30 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 14:40:15 -0700 Subject: [PATCH 2078/2474] experimental: conc reduce blur and fix blend curve blending was linear vs intended curve, try to reduce motion blur from viewport changes --- csqc/main.qc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 31f4f947..39da20a2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -508,7 +508,7 @@ static float IsConced() { static float BlendAmp(float start, float end, float rem, float D) { - return rem/D * end + (D-rem)/D * start; + return rem/D * start + (D-rem)/D * end; } vector FO_Conc_Offset() { @@ -521,16 +521,13 @@ vector FO_Conc_Offset() { float a = ((rem % P) / P) * 2 * M_PI; float amp = pstate_pred.conc_amp; - if (rem >= 6) + if (rem >= 8) amp *= 1; else if (rem >= 2) - amp *= BlendAmp(1.0, 0.5, rem - 2, 6 - 2); + amp *= BlendAmp(1.0, 0.5, rem - 2, 8 - 2); else amp *= BlendAmp(0.5, 0, rem, 2); - - float amp = 2 + pstate_pred.conc_amp * min(8, rem)/8; - float x = amp * sin(a), y = amp * sin(a) * cos(a); return [x, y, 0]; } @@ -556,11 +553,12 @@ void FO_CussView() { }; void FO_CussCrosshair(float width, float height) { + const float conc_fps = 144; // Limit the rendering speed to reduce blur static float next_update; if (time < next_update) return; - next_update += 0.025; + next_update = time + 1.0/conc_fps; if (!IsConced()) { if (cuss_state.cussed) { From 2d48206974f8a6488683639c034596a52b5ed331 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 15:46:05 -0700 Subject: [PATCH 2079/2474] experimental: restore air control / strafing Air control with the new conc was harder due to the way it was perturbing forward (and strafe moves perpendicular from this). A nice compromise is that we only need to perturb the vector while firing; this might look a little weird while spectating (we can improve this later) but we can only apply the effect while firing, which allows regular air control while conc jumping (and not firing). Setting fo_concuss 1 will now enable the following defaults: air control, affects medic Also add more aggressive resets to make sure we clear crosshair when not conced, add `fo_crossy` for people who want to set cl_crossy now that we're overriding it. --- csqc/main.qc | 57 +++++++++++++++++++++++------------------- csqc/weapon_predict.qc | 9 ++++--- share/commondefs.qc | 24 ++++++++++++++++++ share/prediction.qc | 8 +++++- ssqc/client.qc | 2 ++ ssqc/qw.qc | 6 ----- ssqc/scout.qc | 2 +- 7 files changed, 70 insertions(+), 38 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 39da20a2..65fcc7e6 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -511,7 +511,7 @@ static float BlendAmp(float start, float end, float rem, float D) { return rem/D * start + (D-rem)/D * end; } -vector FO_Conc_Offset() { +static vector FO_Conc_Offset() { const float P = 4; float rem = cuss_state.end_time - time; @@ -533,26 +533,28 @@ vector FO_Conc_Offset() { } -vector FO_ConcAim() { +static void FO_UpdateConcAim() { + makevectors(input_angles); vector o = FO_Conc_Offset(); vector r = v_forward * 200 + o.x * v_right + o.y * v_up; - cuss_state.view = vectoangles(v_forward * 200 + o.x/4 * v_right + o.y/4 * v_up); - cuss_state.view[0] *= -1; + cuss_state.c_view = vectoangles(v_forward * 200 + o.x/4 * v_right + o.y/4 * v_up); + cuss_state.c_view[0] *= -1; - return normalize(r); + cuss_state.c_forward = normalize(r); } +DEFCVAR_FLOAT(fo_crossy, 0); // For people who want to use crossy DEFCVAR_FLOAT(cl_crossx, 0); DEFCVAR_FLOAT(cl_crossy, 0); -void FO_CussView() { +static void FO_CussView() { if (cuss_state.cussed) - setproperty(VF_ANGLES, cuss_state.view); + setproperty(VF_ANGLES, cuss_state.c_view); }; -void FO_CussCrosshair(float width, float height) { +static void FO_CussCrosshair(float width, float height) { const float conc_fps = 144; // Limit the rendering speed to reduce blur static float next_update; @@ -561,39 +563,42 @@ void FO_CussCrosshair(float width, float height) { next_update = time + 1.0/conc_fps; if (!IsConced()) { - if (cuss_state.cussed) { + if (cuss_state.cussed || CVARF(cl_crossx) != 0 || + CVARF(cl_crossy) != CVARF(fo_crossy)) { // Make sure we restore crosshairs - localcmd(sprintf("cl_crossx %d; cl_crossy %d;\n", - cuss_state.old_x, cuss_state.old_y)); + localcmd(sprintf("cl_crossx %d; cl_crossy %d;\n", 0, CVARF(fo_crossy))); + CVARF(cl_crossx) = 0; + CVARF(cl_crossy) = CVARF(fo_crossy); cuss_state.cussed = FALSE; } return; } - if (!cuss_state.cussed) { - /* cuss_state.old_x = CVARF(cl_crossx); */ - /* cuss_state.old_y = CVARF(cl_crossy); */ - cuss_state.old_x = 0; // TODO: properly save and restore these - cuss_state.old_y = 0; - cuss_state.cussed = TRUE; - } - + cuss_state.cussed = TRUE; makevectors(input_angles); // updated by input_frame - vector p = project(pmove_org + 8000 * v_forward); + vector p = project(pmove_org + 8000 * cuss_state.c_forward); localcmd(sprintf("cl_crossx %d; cl_crossy %d;\n", - cuss_state.old_x + p_x - width / 2, - cuss_state.old_y + p_y - height / 2)); + p_x - width / 2, CVARF(fo_crossy) + p_y - height / 2)); } void FO_UpdateCuss() { if (!IsConced()) return; - makevectors(input_angles); - input_angles = vectoangles(FO_ConcAim()); - makevectors(input_angles); - input_angles_x *= -1; + FO_UpdateConcAim(); + + float modify_forward = TRUE; + + if ((!pmove_onground && (fo_config.fo_concuss & FOC_EASY_AIR)) || + (pmove_onground && (fo_config.fo_concuss & FOC_EASY_GROUND))) + modify_forward = input_buttons & BUTTON0; + + if (modify_forward) { + input_angles = vectoangles(cuss_state.c_forward); + input_angles_x *= -1; + makevectors(input_angles); + } } noref void CSQC_Input_Frame() { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ebb4295e..2c3fa5a5 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -263,6 +263,9 @@ void WPP_Status() { PrintFlagField("Clown mode [clown_flags=%d]\n", fo_config.clown_flags, CLOWN_DESC.length, CLOWN_DESC); + + PrintFlagField("Concs [fo_concuss=%d]\n", + fo_config.fo_concuss, FO_CONC.length, FO_CONC); } #undef PRINT_CONFIG @@ -1722,12 +1725,10 @@ void WP_UpdateViewModel() { } struct { - float old_x, old_y; float cussed; - float end_time; - - vector view; + vector c_view; + vector c_forward; } cuss_state; void PredictConc() { diff --git a/share/commondefs.qc b/share/commondefs.qc index 39f5d80c..9170e333 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -44,6 +44,8 @@ var struct { float wp_global_disable; float gren_beta_disable; + + float fo_concuss; } fo_config; enumflags { @@ -120,6 +122,28 @@ inline float PredictEnabled(float flag) { const float PREDICT_FLAGS_DEFAULT = 0; +enumflags { + FOC_ON_DEF, // apply foc_defaults + FOC_ON_NODEF, + FOC_AFF_MED, + FOC_EASY_AIR, + FOC_EASY_GROUND, + FOC_DISTANCE, + FOC_RED_MED, +}; + +const float foc_defaults = FOC_AFF_MED | FOC_EASY_AIR; + +string FO_CONC[] = { + "on (w/ defaults)", + "on (no defaults)", + "affects medic", + "easy air control", + "easy ground control", + "distance based", + "reduce medic effect", +}; + enumflags { CLOWN_FAST_PROJECTILES, CLOWN_RUBBERGREN, diff --git a/share/prediction.qc b/share/prediction.qc index 56570dec..b38d138b 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -399,6 +399,7 @@ void EntUpdate_Config() { COMM(Byte, wp_global_disable); COMM(Byte, gren_beta_disable); COMM(Byte, old_ng_rof); + COMM(Short, fo_concuss); #ifdef SSQC return TRUE; @@ -589,6 +590,7 @@ void Predict_InitDefaultConfig() { fo_config.wp_default_min_ping_ms = 25; fo_config.clown_flags = 0; fo_config.clown_grav = 400; + fo_config.fo_concuss = 0; } #ifdef SSQC @@ -655,10 +657,14 @@ static void WeaponPred_CheckConfigUpdate() { if (!read_rof_once) { if (!fo_config.old_ng_rof) // Don't overwrite huetf setting this. CONFIG_UPDATE(FALSE, "ongrof", old_ng_rof); - printf("reading ROF %d\n", fo_config.old_ng_rof); read_rof_once = TRUE; } + if (fo_concuss != fo_config.fo_concuss) { + fo_config.fo_concuss = fo_concuss; + update = TRUE; + } + CONFIG_UPDATE(TRUE, "rewind", rewind_flags); CONFIG_UPDATE(TRUE, "tfx", tfx_flags); CONFIG_UPDATE(TRUE, "clown", clown_flags); diff --git a/ssqc/client.qc b/ssqc/client.qc index a1a9732e..ce0a8833 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -573,6 +573,8 @@ void () DecodeLevelParms = { // aim based concussion grenade effect fo_concuss = CF_GetSetting("foc", "fo_cuss", "0"); + if (fo_concuss & FOC_ON_DEF) + fo_concuss |= foc_defaults; // Tie some of these other options together for convenience / other if (fo_concuss & FOC_DISTANCE) diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 2e3a9c70..fc101edd 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -650,12 +650,6 @@ float engineer_move; float fo_projectiles; -enumflags { - FOC_ON, - FOC_DISTANCE, - FOC_AFF_MED, - FOC_RED_MED, -}; float fo_concuss; float numlocs; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index a37fd281..d9a1c533 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -845,7 +845,7 @@ void (entity inflictor, entity attacker, float bounce, speedbump.owner = head; } - if (fo_concuss & FOC_ON) { + if (fo_concuss) { UpdateClientConcussion(head, actual_cuss_time); head = head.chain; From 5dfb7f732129df541d407ff88b1fd036dff3235e Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 16:37:59 -0700 Subject: [PATCH 2080/2474] experimental: cleanup conc - print your head is better message - make sure effect is removed on cap - make it a little less brutal for heavy by default - clean up some stuff that allows live edits --- csqc/weapon_predict.qc | 14 ++++++++++---- ssqc/status.qc | 8 ++++---- ssqc/tfortmap.qc | 1 + 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2c3fa5a5..68670cf0 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -185,9 +185,6 @@ static float CalcPredEnabled(float current_enable, float cvar, *set_by = sprintf("[lan mode <%d]", WP_MinPing()); return FALSE; } - - *set_by = "[disabled]"; - return FALSE; } static float client_delay_packets; @@ -1741,18 +1738,27 @@ void PredictConc() { return; } + if (!fo_config.fo_concuss) + return; // Not enabled. + if (pstate_server.tfstate & TFSTATE_CONC == 0) return; - static float last_conc_finished; + static float last_conc_finished, last_conc_printed = TRUE; if (pstate_server.conc_finished != last_conc_finished) { // New conc, use a single fixed local finish time. last_conc_finished = pstate_server.conc_finished; cuss_state.end_time = pstate_server.conc_finished - server_time_dt(); + last_conc_printed = FALSE; } if (time > cuss_state.end_time) { pstate_pred.tfstate &= ~TFSTATE_CONC; + + if (!last_conc_printed) { + print("Your head feels better now\n"); + last_conc_printed = TRUE; + } } } diff --git a/ssqc/status.qc b/ssqc/status.qc index dc117e4e..3182111e 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -617,16 +617,16 @@ void (entity Player) InitAllStatuses = { void UpdateClientConcussion(entity player, float duration) { msg_entity = player; - static float scout_mult = 1.5; - static float medic_mult = 0.5; - static float heavy_mult = 0.5; + static float scout_mult; + static float medic_mult; + static float heavy_mult; float amp = 100; // Once non debug, these should be once per map. amp = CF_GetSetting("foca", "fo_cuss_amp", "100"); scout_mult = CF_GetSetting("focs", "fo_cuss_scout", "1.5"); medic_mult = CF_GetSetting("focm", "fo_cuss_medic", "0.5"); - heavy_mult = CF_GetSetting("foch", "fo_cuss_heavy", "0.75"); + heavy_mult = CF_GetSetting("foch", "fo_cuss_heavy", "0.25"); if (player.playerclass == PC_HVYWEAP) { amp *= heavy_mult; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 925cfde2..45fb01cf 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -979,6 +979,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } dremove(te); } + Player.tfstate &= ~TFSTATE_CONC; if (Player.tfstate & TFSTATE_HALLUCINATING) { if (te.think == HallucinationTimer) { From b7f08931844d716ba316181c5da33e4462217ff4 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 18 Apr 2023 19:05:10 -0700 Subject: [PATCH 2081/2474] experimental: make sure new cuss doesn't bleed through no effect when not enabled --- csqc/main.qc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 65fcc7e6..ec179c0f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -502,7 +502,10 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and remove(self); }; -static float IsConced() { +static float IsFoConced() { + if (!fo_config.fo_concuss) + return FALSE; + return pstate_pred.tfstate & TFSTATE_CONC; } @@ -562,7 +565,7 @@ static void FO_CussCrosshair(float width, float height) { return; next_update = time + 1.0/conc_fps; - if (!IsConced()) { + if (!IsFoConced()) { if (cuss_state.cussed || CVARF(cl_crossx) != 0 || CVARF(cl_crossy) != CVARF(fo_crossy)) { // Make sure we restore crosshairs @@ -583,7 +586,7 @@ static void FO_CussCrosshair(float width, float height) { } void FO_UpdateCuss() { - if (!IsConced()) + if (!IsFoConced()) return; FO_UpdateConcAim(); From 06138cf6e39ab23f9620268c13571bd025695b66 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 19 Apr 2023 01:39:28 -0700 Subject: [PATCH 2082/2474] experimental: minor fixes - v_forward was getting reversed - lower conc-render fps to reduce blur - fix clown conc --- csqc/main.qc | 11 ++++++----- csqc/weapon_predict.qc | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index ec179c0f..41f80d81 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -503,6 +503,9 @@ void() CSQC_Ent_Remove = { //the entity in question left the player's pvs, and }; static float IsFoConced() { + if (IsClownMode(CLOWN_CONC)) + return TRUE; + if (!fo_config.fo_concuss) return FALSE; @@ -540,12 +543,10 @@ static void FO_UpdateConcAim() { makevectors(input_angles); vector o = FO_Conc_Offset(); - vector r = v_forward * 200 + o.x * v_right + o.y * v_up; - cuss_state.c_view = vectoangles(v_forward * 200 + o.x/4 * v_right + o.y/4 * v_up); cuss_state.c_view[0] *= -1; - cuss_state.c_forward = normalize(r); + cuss_state.c_forward = normalize(v_forward * 200 + o.x * v_right + o.y * v_up); } DEFCVAR_FLOAT(fo_crossy, 0); // For people who want to use crossy @@ -558,7 +559,7 @@ static void FO_CussView() { }; static void FO_CussCrosshair(float width, float height) { - const float conc_fps = 144; + const float conc_fps = 77; // Limit the rendering speed to reduce blur static float next_update; if (time < next_update) @@ -599,8 +600,8 @@ void FO_UpdateCuss() { if (modify_forward) { input_angles = vectoangles(cuss_state.c_forward); - input_angles_x *= -1; makevectors(input_angles); + input_angles_x *= -1; } } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 68670cf0..bbb76b99 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1729,7 +1729,7 @@ struct { } cuss_state; void PredictConc() { - if (fo_config.clown_flags & CLOWN_CONC) { + if (IsClownMode(CLOWN_CONC)) { if (cuss_state.end_time < time + 6) cuss_state.end_time += 4; // Must align with period. From 86f76c6318e36917950395198b2904e971428cdf Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 19 Apr 2023 22:23:36 +1000 Subject: [PATCH 2083/2474] Temp fix for heavy cannon skipping as hpb --- share/animate.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/animate.qc b/share/animate.qc index 4fb0c12f..b9e1bb57 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -265,7 +265,7 @@ void asscan_fire_extra() { FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (vlen(get_velocity()) <= 90 && !(*tf_state () & TFSTATE_LOCK)) { + if (vlen(get_velocity()) <= 100 && !(*tf_state () & TFSTATE_LOCK)) { if (tidx % 2 == 1) { // 1-based muzzleflash(); Pred_Sound(SND_ASSCAN_FIRE); From b0b232bd44d466a74b908c52bb49b57588793066 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 19 Apr 2023 11:15:53 -0700 Subject: [PATCH 2084/2474] experimental: improve (fix?) motion blur The viewport calculation was only getting updates in input_frames then consumed in rendering, reverse this -- calculate our vectors in rendering and use them in input_frames so that the viewport doesn't get an effective fps drop (rendered remains high, but effective drops with view calc). --- csqc/main.qc | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 41f80d81..c799de2c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -538,15 +538,14 @@ static vector FO_Conc_Offset() { return [x, y, 0]; } - static void FO_UpdateConcAim() { makevectors(input_angles); vector o = FO_Conc_Offset(); + cuss_state.c_forward = normalize(v_forward * 200 + o.x * v_right + o.y * v_up); + cuss_state.c_view = vectoangles(v_forward * 200 + o.x/4 * v_right + o.y/4 * v_up); cuss_state.c_view[0] *= -1; - - cuss_state.c_forward = normalize(v_forward * 200 + o.x * v_right + o.y * v_up); } DEFCVAR_FLOAT(fo_crossy, 0); // For people who want to use crossy @@ -554,17 +553,18 @@ DEFCVAR_FLOAT(cl_crossx, 0); DEFCVAR_FLOAT(cl_crossy, 0); static void FO_CussView() { - if (cuss_state.cussed) + if (cuss_state.cussed) { + FO_UpdateConcAim(); setproperty(VF_ANGLES, cuss_state.c_view); + } }; static void FO_CussCrosshair(float width, float height) { - const float conc_fps = 77; - // Limit the rendering speed to reduce blur + const float crosshair_hz = 200; static float next_update; if (time < next_update) return; - next_update = time + 1.0/conc_fps; + next_update = time + 1.0/crosshair_hz; if (!IsFoConced()) { if (cuss_state.cussed || CVARF(cl_crossx) != 0 || @@ -586,12 +586,10 @@ static void FO_CussCrosshair(float width, float height) { p_x - width / 2, CVARF(fo_crossy) + p_y - height / 2)); } -void FO_UpdateCuss() { +void FO_ApplyCussInput() { if (!IsFoConced()) return; - FO_UpdateConcAim(); - float modify_forward = TRUE; if ((!pmove_onground && (fo_config.fo_concuss & FOC_EASY_AIR)) || @@ -623,7 +621,7 @@ noref void CSQC_Input_Frame() { if (prev_zoomed_in != zoomed_in) setsensitivityscaler(zoomed_in ? 1/3 : 1); - FO_UpdateCuss(); + FO_ApplyCussInput(); } float(float save, float take, vector inflictororg) CSQC_Parse_Damage = { From 10c6d4624d31de54214006a86e4d02065e203cef Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 19 Apr 2023 12:13:12 -0700 Subject: [PATCH 2085/2474] Revert "Temp fix for heavy cannon skipping as hpb" Just say no to heavy buffs. This reverts commit 86f76c6318e36917950395198b2904e971428cdf. --- share/animate.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/animate.qc b/share/animate.qc index 054debb0..ab40bbe5 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -267,7 +267,7 @@ void asscan_fire_extra() { FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (vlen(get_velocity()) <= 100 && !(*tf_state () & TFSTATE_LOCK)) { + if (vlen(get_velocity()) <= 90 && !(*tf_state () & TFSTATE_LOCK)) { if (tidx % 2 == 1) { // 1-based muzzleflash(); Pred_Sound(SND_ASSCAN_FIRE); From 35c9364bfcfbe023dd2228e82dfadd3d9aa49982 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 19 Apr 2023 12:18:37 -0700 Subject: [PATCH 2086/2474] weapon pred: use input_movevalues instead of cl_forwardspeed et al Beyond being much cleaner in terms of application and reversion, the instant response means that the values aren't pushed to the next input frame resulting in behavior that appears equivalent to server specified maxspeed. Neither will generate skips from any directional strafing alone. It's possible in both cases to generate skips (from legitimately going too fast) from the extra acceleration you can generate from viewangles, but you're just legitimately going too fast in both cases, behavior is the same). --- csqc/main.qc | 3 +++ csqc/weapon_predict.qc | 43 +++++------------------------------------- 2 files changed, 8 insertions(+), 38 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index c799de2c..5f646553 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -603,6 +603,8 @@ void FO_ApplyCussInput() { } } +void FO_ApplyMaxSpeed(); + noref void CSQC_Input_Frame() { Sync_GameState(); @@ -621,6 +623,7 @@ noref void CSQC_Input_Frame() { if (prev_zoomed_in != zoomed_in) setsensitivityscaler(zoomed_in ? 1/3 : 1); + FO_ApplyMaxSpeed(); FO_ApplyCussInput(); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index bbb76b99..602ec03a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1051,48 +1051,16 @@ void WPP_Dump() { void WP_Attack(); -DEFCVAR_FLOAT(cl_forwardspeed, 0); -DEFCVAR_FLOAT(cl_backspeed, 0); -DEFCVAR_FLOAT(cl_sidespeed, 0); - -void MP_SetSpeed() { - if (!CVARF(wpp_setspeed)) +void FO_ApplyMaxSpeed() { + if (!WP_Enabled() || !CVARF(wpp_setspeed) || !RewindFlagEnabled(REWIND_SETSPEED)) return; - static float last_playerclass, last_set; - - float speed = pstate_pred.csqc_maxspeed; - - if (pstate_pred.playerclass != last_playerclass) - last_set = -1; // Force update. - last_playerclass = pstate_pred.playerclass; - - const float speed_aiming = 80; - const float speed_aiming2dir = ceil(speed_aiming/sqrt(2)); - - if (pstate_pred.tfstate & TFSTATE_AIMING) { - speed = min(pstate_pred.csqc_maxspeed, speed_aiming); - - // Cap as maxspeed would, but client-side, when enabled. - if (RewindFlagEnabled(REWIND_SETSPEED)) - if (input_movevalues.x && input_movevalues.y) - speed = min(speed, speed_aiming2dir); - } - - float fastest = - max(CVARF(cl_forwardspeed), CVARF(cl_backspeed), CVARF(cl_sidespeed)); - - // We check >speed, not =speed as it's still valid for clients to control to - // lower speeds. Except for transitions where the maxspeed is reset. - if (speed > last_set || fastest > speed) { - last_set = speed; + if (pstate_pred.tfstate & TFSTATE_AIMING == 0) + return; - string spd = ftos(speed); - localcmd("cl_forwardspeed ", spd, "; cl_backspeed ",spd, "; cl_sidespeed ", spd, "\n"); - } + input_movevalues = normalize(input_movevalues) * 80; } - DEFCVAR_FLOAT(cl_crossx, 0); void WP_Frame() { @@ -1128,7 +1096,6 @@ void WP_Frame() { WP_Attack(); WP_Sniper_UpdateSight(); - MP_SetSpeed(); } From e04addeec0dbf18c1868b0cfcd4605db1207fbf5 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 19 Apr 2023 23:48:33 -0700 Subject: [PATCH 2087/2474] conc: massive cleanup Now that we have so many implementations floating around, all of the state around how we heal, do timers, clear on cap, etc is a giant mess. Even figuring out what the conc type is requires a multi-way eval. Refactor all of this so it goes through a few common functions. All so we can have bubbles on the new conc. The long form name enable name is also now fixed to be `fo_concuss`. --- csqc/weapon_predict.qc | 11 +--- ssqc/client.qc | 46 +++++++------ ssqc/scout.qc | 144 +++++++++++++++++++++++++---------------- ssqc/tfort.qc | 3 +- ssqc/tfortmap.qc | 8 +-- ssqc/weapons.qc | 24 ++----- 6 files changed, 129 insertions(+), 107 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index bbb76b99..bf2c8692 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1744,22 +1744,15 @@ void PredictConc() { if (pstate_server.tfstate & TFSTATE_CONC == 0) return; - static float last_conc_finished, last_conc_printed = TRUE; + static float last_conc_finished; if (pstate_server.conc_finished != last_conc_finished) { // New conc, use a single fixed local finish time. last_conc_finished = pstate_server.conc_finished; cuss_state.end_time = pstate_server.conc_finished - server_time_dt(); - last_conc_printed = FALSE; } - if (time > cuss_state.end_time) { + if (time > cuss_state.end_time) pstate_pred.tfstate &= ~TFSTATE_CONC; - - if (!last_conc_printed) { - print("Your head feels better now\n"); - last_conc_printed = TRUE; - } - } } float WP_ClientThink() { diff --git a/ssqc/client.qc b/ssqc/client.qc index ce0a8833..a60d9dde 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -563,7 +563,7 @@ void () DecodeLevelParms = { classtips = CF_GetSetting("ct", "classtips", "on"); // concussion grenade effect time [19] - cussgrentime = CF_GetSetting("cgt", "cussgrentime", "19"); + cussgrentime = CF_GetSetting("cgt", "cussgrentime", "10"); // concussion grenade effect time proportional to distance from explosion distance_based_cuss_duration = CF_GetSetting("dbcd", "distance_based_cuss_duration", "off"); @@ -572,7 +572,7 @@ void () DecodeLevelParms = { medicnocuss = CF_GetSetting("mnc", "medicnocuss", "on"); // aim based concussion grenade effect - fo_concuss = CF_GetSetting("foc", "fo_cuss", "0"); + fo_concuss = CF_GetSetting("foc", "fo_concuss", "0"); if (fo_concuss & FOC_ON_DEF) fo_concuss |= foc_defaults; @@ -2498,6 +2498,23 @@ void () PlayerDeathThink = { void player_asscan_down1(); +enum ConcMode { + CONC_IDLESCALE, + CONC_CLASSIC, + CONC_AIM, +}; + +ConcMode GetConcMode() { + if (old_grens) + return CONC_IDLESCALE; + else if (fo_concuss) + return CONC_AIM; + else + return CONC_CLASSIC; +} + +entity FindConcTimer(entity player); + void () PlayerJump = { local entity te; local float stumble; @@ -2548,22 +2565,15 @@ void () PlayerJump = { StopAssCan(); } - if (old_grens != 1) { - te = find(world, classname, "timer"); - while (((te.owner != self) || (te.think != ConcussionGrenadeTimer)) - && (te != world)) - te = find(te, classname, "timer"); - - if ((te != world) && (te != self)) { - crandom(); - stumble = crandom() * (te.health / 100); - if (crandom() < 0) { - self.velocity_x = self.velocity_y + stumble; - self.velocity_y = self.velocity_x + stumble; - } else { - self.velocity_x = (-1 * self.velocity_y) + stumble; - self.velocity_y = (-1 * self.velocity_x) + stumble; - } + if (GetConcMode() == CONC_CLASSIC && (self.tfstate & TFSTATE_CONC)) { + entity te = FindConcTimer(self); + stumble = crandom() * (te.health / 100); + if (crandom() < 0) { + self.velocity_x = self.velocity_y + stumble; + self.velocity_y = self.velocity_x + stumble; + } else { + self.velocity_x = (-1 * self.velocity_y) + stumble; + self.velocity_y = (-1 * self.velocity_x) + stumble; } } }; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index d9a1c533..8a1944e9 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -18,6 +18,46 @@ void (entity inflictor, entity attacker, float bounce, entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; +void ClassicConcussionGrenadeTimer(); +void OldConcussionGrenadeTimer(); +void FoConcussionGrenadeTimer(); + +void ConcThink() { + switch (GetConcMode()) { + case CONC_IDLESCALE: return OldConcussionGrenadeTimer(); + case CONC_CLASSIC: return ClassicConcussionGrenadeTimer(); + case CONC_AIM: return FoConcussionGrenadeTimer(); + } +} + +entity FindConcTimer(entity player) { + int count; + entity* timers = find_list(classname, "timer", EV_STRING, count); + + for (int i = 0; i < count; i++) + if (timers[i].owner == player && timers[i].think == ConcThink) + return timers[i]; + + return __NULL__; +} + +void RemoveConc(entity player, float remove_timer = TRUE) { + if (player.tfstate & TFSTATE_CONC == 0) + return; + + player.tfstate &= ~TFSTATE_CONC; + player.conc_finished = 0; + + if (GetConcMode() == CONC_IDLESCALE) + stuffcmd(player, "v_idlescale 0\nfov 90\n"); + + if (remove_timer) { + entity timer = FindConcTimer(player); + if (timer != __NULL__) + dremove(timer); + } +} + void () CF_Scout_Dash = { if (self.playerclass != PC_SCOUT) return; @@ -418,54 +458,50 @@ void () OldConcussionGrenadeTimer = { stuffcmd(self.owner, st); stuffcmd(self.owner, "\n"); if (self.health == 0) { - self.tfstate &= ~TFSTATE_CONC; + RemoveConc(self.owner, FALSE); dremove(self); } }; -void () ConcussionGrenadeTimer = { +static void SpawnBubble(vector origin) { + newmis = spawn(); + FO_SetModel(newmis, "progs/s_bubble.spr"); + setorigin(newmis, origin); + newmis.movetype = MOVETYPE_NOCLIP; + newmis.solid = SOLID_NOT; + newmis.velocity = '0 0 15'; + newmis.nextthink = time + 0.5; + newmis.think = bubble_bob; + newmis.touch = bubble_remove; + newmis.classname = "bubble"; + newmis.frame = 0; + newmis.cnt = 0; + setsize(newmis, '-8 -8 -8', '8 8 8'); +} + +void () ClassicConcussionGrenadeTimer = { local vector src; local float pos; - local float concadjust; local float stumble; if (self.owner.invincible_finished > time) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); - self.owner.fixangle = 0; - self.owner.tfstate &= ~TFSTATE_CONC; + RemoveConc(self.owner, FALSE); dremove(self); return; } - if ((self.health == 200) || (self.health == 400) || - (self.health == 600) - || (self.health == 800) || (self.health == 1000)) { - newmis = spawn(); - FO_SetModel(newmis, "progs/s_bubble.spr"); - setorigin(newmis, self.owner.origin); - newmis.movetype = MOVETYPE_NOCLIP; - newmis.solid = SOLID_NOT; - newmis.velocity = '0 0 15'; - newmis.nextthink = time + 0.5; - newmis.think = bubble_bob; - newmis.touch = bubble_remove; - newmis.classname = "bubble"; - newmis.frame = 0; - newmis.cnt = 0; - setsize(newmis, '-8 -8 -8', '8 8 8'); - } + if (self.health > 0 && self.health % 200 == 0) + SpawnBubble(self.owner.origin); + self.health = self.health - 10; - if (self.owner.playerclass == 5) + if (self.owner.playerclass == PC_MEDIC) self.health = self.health - 10; if (self.health < 0) self.health = 0; - concadjust = 1; - self.nextthink = time + 0.25 * concadjust; - - if (concadjust > 1) - self.health = self.health - concadjust; + self.nextthink = time + 0.25; pos = pointcontents(self.owner.origin); src_x = self.owner.origin_x + self.owner.maxs_x + 2; @@ -496,11 +532,26 @@ void () ConcussionGrenadeTimer = { } if (self.health <= 0) { sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); - self.owner.tfstate &= ~TFSTATE_CONC; + RemoveConc(self.owner, FALSE); dremove(self); } }; +void FoConcussionGrenadeTimer() { + const float bubble_int = 1; + float finished = self.owner.conc_finished; + + self.nextthink = min(time + bubble_int, finished); + + if (time < finished) { + SpawnBubble(self.owner.origin); + } else { + sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); + RemoveConc(self.owner, FALSE); + dremove(self); + } +} + void () ScannerSwitch = { local entity te; @@ -780,7 +831,7 @@ void (entity inflictor, entity attacker, float bounce, void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce = { local float actual_cuss_time = cussgrentime; - local float distance; + local float distance; local float points; local entity head; local entity te; @@ -834,8 +885,6 @@ void (entity inflictor, entity attacker, float bounce, } } - head.tfstate |= TFSTATE_CONC; - if (distance_based_cuss_duration && ((head.playerclass == PC_MEDIC) || (head.playerclass == PC_SCOUT))) { entity speedbump; @@ -845,28 +894,15 @@ void (entity inflictor, entity attacker, float bounce, speedbump.owner = head; } - if (fo_concuss) { + head.tfstate |= TFSTATE_CONC; + if (fo_concuss) UpdateClientConcussion(head, actual_cuss_time); + else // not used currently, but populate anyway + head.conc_finished = time + actual_cuss_time; - head = head.chain; - continue; - } - - te = find(world, classname, "timer"); - if (old_grens == TRUE) - while (((te.owner != head) || - (te.think != - OldConcussionGrenadeTimer)) - && (te != world)) - te = find(te, classname, "timer"); - else - while (((te.owner != head) || - (te.think != ConcussionGrenadeTimer)) - && (te != world)) - te = find(te, classname, "timer"); - + entity te = FindConcTimer(head); if (te != world) { - if (old_grens == TRUE) { + if (GetConcMode() == CONC_IDLESCALE) { stuffcmd(head, "v_idlescale 100\n"); stuffcmd(head, "fov 130\n"); te.health = 100; @@ -877,13 +913,13 @@ void (entity inflictor, entity attacker, float bounce, } } else { // LogEventAffliction(attacker, head, TFSTATE_CONCUSSED); - if (old_grens == TRUE) { + if (GetConcMode() == CONC_IDLESCALE) { stuffcmd(head, "v_idlescale 100\n"); stuffcmd(head, "fov 130\n"); stuffcmd(head, "bf\n"); te = spawn(); te.nextthink = time + 5; - te.think = OldConcussionGrenadeTimer; + te.think = ConcThink; te.team_no = attacker.team_no; te.classname = "timer"; te.owner = head; @@ -891,7 +927,7 @@ void (entity inflictor, entity attacker, float bounce, } else { te = spawn(); te.nextthink = time + 0.25; - te.think = ConcussionGrenadeTimer; + te.think = ConcThink; te.team_no = attacker.team_no; te.classname = "timer"; te.owner = head; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 43401712..5ebca7c2 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2255,8 +2255,8 @@ void () TeamFortress_RemoveTimers = { local entity te; self.leg_damage = 0; - self.tfstate &= ~TFSTATE_CONC; self.is_undercover = 0; + RemoveConc(self); if (self.is_building && engineer_move) { TeamFortress_EngineerBuildStop(); @@ -2328,7 +2328,6 @@ void () TeamFortress_RemoveTimers = { } } if (old_grens == 1) { - stuffcmd(self, "v_idlescale 0\n"); stuffcmd(self, "v_cshift; wait; bf\n"); self.FlashTime = 0; } diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 45fb01cf..5cca8391 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -973,13 +973,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { te = find(Player, classname, "timer"); - if (te.think == ConcussionGrenadeTimer || te.think == OldConcussionGrenadeTimer) { - if (old_grens == TRUE) { - stuffcmd(Player, "v_idlescale 0\nfov 90\n"); - } - dremove(te); - } - Player.tfstate &= ~TFSTATE_CONC; + RemoveConc(Player); if (Player.tfstate & TFSTATE_HALLUCINATING) { if (te.think == HallucinationTimer) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 299242d3..dfca2c2f 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -7,9 +7,6 @@ void (vector org, float damage) SpawnBlood; void () SuperDamageSound; -void () ConcussionGrenadeTimer; -void () OldConcussionGrenadeTimer; - void (Slot slot) W_ChangeWeaponSlot; void () W_ChangeToBestWeapon; void () W_PrintWeaponMessage; @@ -392,6 +389,9 @@ int () W_FireSpanner = { } }; +void RemoveConc(entity player, float remove_timer = TRUE); +entity FindConcTimer(entity player); + int () W_FireMedikit = { local vector source; local vector org; @@ -414,29 +414,19 @@ int () W_FireMedikit = { (self.team_no != 0)) || coop) { healam = 200; - te = find(world, classname, "timer"); - while (((te.owner != trace_ent) - || ((te.think != ConcussionGrenadeTimer) - && (te.think != OldConcussionGrenadeTimer))) - && (te != world)) - te = find(te, classname, "timer"); - - if (te != world) { - - if (old_grens == TRUE) - stuffcmd(trace_ent, "v_idlescale 0\nfov 90\n"); - + if (trace_ent.tfstate & TFSTATE_CONC) { SpawnBlood(org, 20); bprint(PRINT_MEDIUM, self.netname, " cured ", trace_ent.netname, "'s concussion\n"); + entity te = FindConcTimer(trace_ent); if (te.team_no != self.team_no) TF_AddFrags(self, 1); - trace_ent.tfstate &= ~TFSTATE_CONC; - dremove(te); + RemoveConc(trace_ent); } + if (trace_ent.tfstate & TFSTATE_HALLUCINATING) { te = find(world, classname, "timer"); From bf8b3df4692b56db76b9d21d8bdccc96d6c75651 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 20 Apr 2023 16:55:53 -0700 Subject: [PATCH 2088/2474] mp: remove stuffs We really don't need to do much with client movespeeds anymore, our maxspeed handling does the work. Remove some stuffs for legacy clients that could have led to sticky speeds; we now only stuff reasonable (fast) defaults to a spec. --- csqc/weapon_predict.qc | 6 ++---- ssqc/tfort.qc | 10 ++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 912280ee..4e7afede 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1055,10 +1055,8 @@ void FO_ApplyMaxSpeed() { if (!WP_Enabled() || !CVARF(wpp_setspeed) || !RewindFlagEnabled(REWIND_SETSPEED)) return; - if (pstate_pred.tfstate & TFSTATE_AIMING == 0) - return; - - input_movevalues = normalize(input_movevalues) * 80; + if (pstate_pred.tfstate & TFSTATE_AIMING) + input_movevalues = normalize(input_movevalues) * 80; } DEFCVAR_FLOAT(cl_crossx, 0); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 5ebca7c2..b98d35ac 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1258,7 +1258,7 @@ void (entity p) TeamFortress_SetSpeed = { // Typically this hits spectators and then spec movetype --> maxspeed // actually ignored. p.maxspeed = 0; - stuffcmd(p, "cl_backspeed 500; cl_forwardspeed 500; cl_sidespeed 500\n"); + stuffcmd(p, "cl_movespeedkey 1;cl_backspeed 500; cl_forwardspeed 500; cl_sidespeed 500;\n"); return; } @@ -1292,14 +1292,12 @@ void (entity p) TeamFortress_SetSpeed = { if (!RewindFlagEnabled(REWIND_SETSPEED) || !client_enable) { if (p.tfstate & TFSTATE_AIMING) new_max = min(new_max, 80); - - sp = ftos(new_max); - stuffcmd(p, "cl_backspeed ", sp, "; cl_forwardspeed ", sp, - "; cl_sidespeed ", sp, "\n"); } p.maxspeed = new_max; - p.csqc_maxspeed = new_max; // Always set, need populated on transition. + p.csqc_maxspeed = new_max; // Note: with new input_movevalues construction + // this isn't technically needed until we do + // something like client-side tranq pred. }; void () TeamFortress_SetHealth = { From cf93123448a9b9d7b3afb72bcb07241a2978ad3e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 24 Apr 2023 17:27:54 -0700 Subject: [PATCH 2089/2474] experimental: tune new conc - Some Brazilian feedback is that it still felt a little too easy to hit right after conc affect so do some things to make the curve more parameterizable. Particularly, reducing the period of initial rotations (to accelerate how fast aim is moving) for the first few seconds before falling off. - Slightly increase base amplitude, period is no longer fixed per above - Remove sync on now redundant period - Reduce effect for medic by default - Increase effect for heavy by default - More run-time tunables to shape the curve a --- csqc/main.qc | 60 +++++++++++++++++++++++++++++++++--------- csqc/weapon_predict.qc | 9 +++++-- share/prediction.qc | 10 +++---- ssqc/scout.qc | 51 +++++++++++++++++++++++++++++++++++ ssqc/status.qc | 29 -------------------- 5 files changed, 110 insertions(+), 49 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index c799de2c..32effac6 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -512,30 +512,64 @@ static float IsFoConced() { return pstate_pred.tfstate & TFSTATE_CONC; } +struct ConcCurve { + float duration; + float cycles; + float amp_end; + float offset; +}; + +ConcCurve conc_curve[] = { + {1, 0.5, 0.0, 0.5}, + {6, 4, 0.2, 0.5}, + {2, 1.5, 0.75}, + {1, 1, 1}, + {0, 0, 1}, // Terminator +}; -static float BlendAmp(float start, float end, float rem, float D) { +ConcCurve clown_curve[] = { + {10, 4, 0.75}, + {0, 0, 0.75}, // Terminator +}; + +float ClownConcPeriod() { return clown_curve[0].duration; } + +static float Blend(float start, float end, float rem, float D) { return rem/D * start + (D-rem)/D * end; } static vector FO_Conc_Offset() { - const float P = 4; - + static float last_rem; float rem = cuss_state.end_time - time; if (rem < 0) return '0 0 0'; - float a = ((rem % P) / P) * 2 * M_PI; + ConcCurve* table; + float len; + ConcCurve* cur = __NULL__; + float i, rot = 0; - float amp = pstate_pred.conc_amp; - if (rem >= 8) - amp *= 1; - else if (rem >= 2) - amp *= BlendAmp(1.0, 0.5, rem - 2, 8 - 2); - else - amp *= BlendAmp(0.5, 0, rem, 2); + if (!IsClownMode(CLOWN_CONC)) { + table = conc_curve; + len = conc_curve.length; + } else { + table = clown_curve; + len = clown_curve.length; + } + + for (i = 0; i < len - 1; i++) { + cur = &table[i]; + if (rem <= cur->duration) + break; + rem -= cur->duration; + } + + float amp = Blend(table[i+1].amp_end, cur->amp_end, rem, cur->duration); + amp *= pstate_pred.conc_amp; + float a = (cur->duration - rem) / cur->duration * cur->cycles * 2 * M_PI; + a += cur->offset * 2 * M_PI; - float x = amp * sin(a), y = amp * sin(a) * cos(a); - return [x, y, 0]; + return [amp * sin(a), amp * sin(a) * cos(a), 0]; } static void FO_UpdateConcAim() { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index bf2c8692..7889c29d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1726,12 +1726,16 @@ struct { float end_time; vector c_view; vector c_forward; + + float last_a; } cuss_state; +float ClownConcPeriod(); + void PredictConc() { if (IsClownMode(CLOWN_CONC)) { - if (cuss_state.end_time < time + 6) - cuss_state.end_time += 4; // Must align with period. + if (cuss_state.end_time < time) + cuss_state.end_time = time + ClownConcPeriod(); pstate_pred.conc_amp = 100; pstate_pred.tfstate |= TFSTATE_CONC; @@ -1749,6 +1753,7 @@ void PredictConc() { // New conc, use a single fixed local finish time. last_conc_finished = pstate_server.conc_finished; cuss_state.end_time = pstate_server.conc_finished - server_time_dt(); + cuss_state.last_a = 0; } if (time > cuss_state.end_time) diff --git a/share/prediction.qc b/share/prediction.qc index b38d138b..6f4b1d6b 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -652,6 +652,11 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE(FALSE, "wpgd", wp_global_disable); CONFIG_UPDATE(FALSE, "gbd", gren_beta_disable); + if (fo_concuss != fo_config.fo_concuss) { + fo_config.fo_concuss = fo_concuss; + update = TRUE; + } + // Not dynamically updatable. static float read_rof_once = FALSE; if (!read_rof_once) { @@ -660,11 +665,6 @@ static void WeaponPred_CheckConfigUpdate() { read_rof_once = TRUE; } - if (fo_concuss != fo_config.fo_concuss) { - fo_config.fo_concuss = fo_concuss; - update = TRUE; - } - CONFIG_UPDATE(TRUE, "rewind", rewind_flags); CONFIG_UPDATE(TRUE, "tfx", tfx_flags); CONFIG_UPDATE(TRUE, "clown", clown_flags); diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 8a1944e9..4ae95289 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -828,6 +828,57 @@ void (entity inflictor, entity attacker, float bounce, } }; + +struct ClassConc { + float amp_mult; + float duration_mult; +}; + +static ClassConc class_mod[] = { + { 1.0, 1.0 }, // observer + { 1.5, 1.0 }, // scout + { 1.0, 1.0 }, // sniper + { 1.0, 1.0 }, // soldier + { 1.0, 1.0 }, // demoman + { 1.0, 0.5 }, // medic + { 0.75, 1.0 }, // hwguy + { 1.0, 1.0 }, // pyro + { 1.0, 1.0 }, // spy + { 1.0, 1.0 }, // engineer + { 1.0, 1.0 }, // randompc + { 1.0, 1.0 }, // civilian +}; + +static ClassConc get_class_mod(float playerclass) { + string short_a = sprintf("foc_a%d", playerclass); + string long_a = sprintf("fo_concuss_amp%d", playerclass); + string short_d = sprintf("foc_d%d", playerclass); + string long_d = sprintf("fo_concuss_dur%d", playerclass); + + ClassConc r = class_mod[playerclass]; + + float amp_m = CF_GetSetting(short_a, long_a, "off"); + if (amp_m) + r.amp_mult = amp_m; + + float dur = CF_GetSetting(short_d, long_d, "off"); + if (dur) + r.duration_mult = dur; + + return r; +} + +static void UpdateClientConcussion(entity player, float duration) { + float base_amp = CF_GetSetting("foca", "foc_amp", "110"); + + // Once non debug, these should be once per map. + ClassConc r = get_class_mod(player.playerclass); + + // networked via prediction ent + player.conc_amp = base_amp * r.amp_mult; + player.conc_finished = time + duration * r.duration_mult; +} + void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce = { local float actual_cuss_time = cussgrentime; diff --git a/ssqc/status.qc b/ssqc/status.qc index 3182111e..f692dd08 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -614,35 +614,6 @@ void (entity Player) InitAllStatuses = { } }; -void UpdateClientConcussion(entity player, float duration) { - msg_entity = player; - - static float scout_mult; - static float medic_mult; - static float heavy_mult; - float amp = 100; - - // Once non debug, these should be once per map. - amp = CF_GetSetting("foca", "fo_cuss_amp", "100"); - scout_mult = CF_GetSetting("focs", "fo_cuss_scout", "1.5"); - medic_mult = CF_GetSetting("focm", "fo_cuss_medic", "0.5"); - heavy_mult = CF_GetSetting("foch", "fo_cuss_heavy", "0.25"); - - if (player.playerclass == PC_HVYWEAP) { - amp *= heavy_mult; - } else if (player.playerclass == PC_SCOUT) { - amp *= scout_mult; - } else if (player.playerclass == PC_MEDIC) { - if (fo_concuss & FOC_RED_MED) - duration /= 2; - amp *= medic_mult; - } - - // networked via prediction ent - player.conc_amp = amp; - player.conc_finished = time + duration; -} - float laststate; void (entity Player, entity Goal) UpdateClientButtonStatus = { if(!infokeyf(Player, INFOKEY_P_CSQCACTIVE)) From c5be0ce2ab2e9500a020005fb42381b18a35cf5f Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 25 Apr 2023 13:36:30 -0700 Subject: [PATCH 2090/2474] experimental: bound view bob Put a bound on view bob beyond it just being a reduced function of amplitude so that scout is a little more controllable / less nauseating. --- csqc/main.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 32effac6..fcd1511f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -565,20 +565,20 @@ static vector FO_Conc_Offset() { } float amp = Blend(table[i+1].amp_end, cur->amp_end, rem, cur->duration); - amp *= pstate_pred.conc_amp; float a = (cur->duration - rem) / cur->duration * cur->cycles * 2 * M_PI; a += cur->offset * 2 * M_PI; - return [amp * sin(a), amp * sin(a) * cos(a), 0]; + return [sin(a), sin(a) * cos(a), amp * pstate_pred.conc_amp]; } static void FO_UpdateConcAim() { makevectors(input_angles); vector o = FO_Conc_Offset(); - cuss_state.c_forward = normalize(v_forward * 200 + o.x * v_right + o.y * v_up); + cuss_state.c_forward = normalize(v_forward * 200 + o.x * o.z * v_right + o.y * o.z * v_up); - cuss_state.c_view = vectoangles(v_forward * 200 + o.x/4 * v_right + o.y/4 * v_up); + vector vv = o * min(o.z / 4, 20); + cuss_state.c_view = vectoangles(v_forward * 200 + vv.x * v_right + vv.y * v_up); cuss_state.c_view[0] *= -1; } From 9d68949f8e91f06b5da943f60391b78ddf010f19 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 1 May 2023 01:31:13 -0700 Subject: [PATCH 2091/2474] weapons: fix heavy cell consumption + minor tweaks - AC was costing -7 cells to fire, fix this and move it to a def. - Make weapon prediction account for usable cells in predicting spin-up - Add some helpers and cleanup around conditional firing of hwguy (and more generally ammo interactions). - Fix weapon prediction predicting out of ammo when there was exactly ammo_per_shot ammo left (> vs >=) --- csqc/weapon_predict.qc | 18 +++++++++++++++--- share/defs.h | 1 + share/weapons.qc | 17 +++-------------- ssqc/hwguy.qc | 20 ++++++++++++++++++++ ssqc/weapons.qc | 39 +++++++++++++++++++++++++++------------ 5 files changed, 66 insertions(+), 29 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 7889c29d..f46570d9 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -631,7 +631,7 @@ float WP_CheckAmmo(FO_WeapInfo* wi) { return FALSE; int ammo = WP_GetAmmo(wi->ammo_type); - return ammo > wi->ammo_per_shot; + return ammo >= wi->ammo_per_shot; } void WP_ChangeWeapon(Slot slot) { @@ -988,6 +988,14 @@ float WP_ConsumeAmmo(Slot slot) { return TRUE; } +float W_ConsumeAmmoIfPossible(float ammo_type, float amount) { + if (WP_GetAmmo(ammo_type) < amount) + return FALSE; + + pstate_pred.ammo_used[ammo_type] += amount; + return TRUE; +} + var void() melee_anim = player_axeN; void WP_AnimateModel() { @@ -1553,8 +1561,12 @@ void WP_Attack() { // Start the AC state machine when necessary. if (wi->weapon == WEAP_ASSAULT_CANNON && - (pstate_pred.tfstate & TFSTATE_AC_MASK) == 0) - pstate_pred.tfstate |= TFSTATE_AC_SPINUP; + (pstate_pred.tfstate & TFSTATE_AC_MASK) == 0) { + if (W_ConsumeAmmoIfPossible(AMMO_CELLS, PC_HVYWEAP_CELL_FIRE)) + pstate_pred.tfstate |= TFSTATE_AC_SPINUP; + else + pstate_pred.client_thinkindex = 0; // Just kidding, no cells. + } #if 0 // If our latency is higher than forward projection, synchronize animation // with when it will actually start/finish. The projectile internally diff --git a/share/defs.h b/share/defs.h index 51d1b1b8..e30d08bd 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1065,6 +1065,7 @@ enumflags { #define PC_HVYWEAP_GRENADE_MAX_1 4 #define PC_HVYWEAP_GRENADE_MAX_2 1 #define PC_HVYWEAP_TF_ITEMS 0 +#define PC_HVYWEAP_CELL_FIRE 7 // Class Details for PYRO diff --git a/share/weapons.qc b/share/weapons.qc index e357900d..f62e431e 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -335,19 +335,6 @@ static FO_WeapModels weapon_models[] = { // REQUIRES: Order must match above. static string AMMO_to_s[] = {"none", "shells", "nails", "cells", "rockets"}; -static float* AMMO_to_p(entity player, AmmoType ammo_type) { - switch (ammo_type) { - case AMMO_SHELLS: return &player.ammo_shells; - case AMMO_CELLS: return &player.ammo_cells; - case AMMO_NAILS: return &player.ammo_nails; - case AMMO_ROCKETS: return &player.ammo_rockets; - default: - case AMMO_NONE: - return __NULL__; - } - return __NULL__; -} - Slot WEAP_to_slot(float playerclass, float weapon) { for (float i = 0; i < TF_NUM_SLOTS; i++) { if (class_weapons[playerclass].slots[i] == weapon) @@ -466,6 +453,8 @@ struct FO_WeapState { }; +float* W_ammo_to_p(entity player, AmmoType ammo_type); + void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, slot); @@ -473,7 +462,7 @@ void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { result->slot = slot; result->wi = wi; - result->ammo_remaining = AMMO_to_p(player, wi->ammo_type); + result->ammo_remaining = W_ammo_to_p(player, wi->ammo_type); if (!IsSlotNull(slot)) result->clip_fired = &player.clip_fired[SlotIndex(slot)]; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index ae6caade..daac67e2 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -98,3 +98,23 @@ void FO_LockToggle () { /* this shouldn't be here, I think we just need to allow this impulse while shooting */ /* worth checking detpipes for this too */ } + +float AssCanTryBeginFire() { + if (get_shells() < 1) + return FALSE; + + if (FO_CheckForReload()) + return FALSE; + + if (!W_ConsumeAmmoIfPossible(AMMO_CELLS, PC_HVYWEAP_CELL_FIRE)) { + // Not worth optimizing w/ client side. + if (time >= self.antispam_assault_cannon) { + sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); + self.antispam_assault_cannon = time + 3; + } + return FALSE; + } + + player_asscan_up1(); + return TRUE; +} diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index dfca2c2f..99380711 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -190,6 +190,29 @@ void (float att_delay) Attack_Finished = { self.attack_finished = self.client_time + att_delay; }; +float* W_ammo_to_p(entity player, AmmoType ammo_type) { + switch (ammo_type) { + case AMMO_SHELLS: return &player.ammo_shells; + case AMMO_CELLS: return &player.ammo_cells; + case AMMO_NAILS: return &player.ammo_nails; + case AMMO_ROCKETS: return &player.ammo_rockets; + default: + case AMMO_NONE: + return __NULL__; + } + return __NULL__; +} + +float W_ConsumeAmmoIfPossible(float ammo_type, float amount) { + float *ammo = W_ammo_to_p(self, ammo_type); + + if (*ammo < amount) + return FALSE; + *ammo -= amount; + return TRUE; +} + + int () W_FireAxe = { local vector source; local vector org; @@ -1621,6 +1644,8 @@ void () player_asscan_up1; void () player_medikit1; void () player_medikitb1; +float AssCanTryBeginFire(); + void () W_Attack = { FO_WeapState ws; FO_FillCurrentWeapState(&ws); @@ -1705,19 +1730,9 @@ void () W_Attack = { player_autorifle1(); W_FireAutoRifle(); } else if (ws.weapon == WEAP_ASSAULT_CANNON) { - if (self.ammo_cells < 7) { - if (time >= self.antispam_assault_cannon) { - sprint(self, PRINT_MEDIUM, "Not enough cells to power up the Assault Cannon\n"); - self.antispam_assault_cannon = time + 3; - } + self.immune_to_check = time + 5; + if (!AssCanTryBeginFire()) W_ChangeToBestWeapon(); - } else { - self.ammo_cells -= - 7; - self.count = 0; - self.immune_to_check = time + 5; - self.tfstate |= TFSTATE_AIMING; - player_asscan_up1(); - } } else if (ws.weapon == WEAP_FLAMETHROWER) { player_flamethrower1(); W_FireFlame(); From d2857492a5786810eb3a29da51b02c1e7bcc546c Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 1 May 2023 01:31:21 -0700 Subject: [PATCH 2092/2474] hud: unify lmp lookup and render partial clips - slightly unify the awful char->wad lookup used by a few of the hud functions - add a hacky way to emit red text with markup - use said hack to render clips constrained by available ammo rather than loaded clip in red - add `fo_hud_noclipicon` for just clip text with no icon (off by default) --- csqc/hud_helpers.qc | 88 +++++++++++++++++------------------------- csqc/status.qc | 5 ++- csqc/weapon_predict.qc | 10 ++++- 3 files changed, 48 insertions(+), 55 deletions(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 16345ca8..094b0e13 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -113,6 +113,26 @@ float(PanelID id, vector pos, vector size, float alpha, float enabled) hud_panel return sui_is_clicked(id); }; +static string lmp_lookup(float c, float use_red) { + string lmp = ""; + switch (c) { + case ' ': return ""; + case '*': return "use_red"; // Caller must handle + case '-': lmp = "num_minus"; break; + case '/': lmp = "num_slash"; break; + case ':': lmp = "num_colon"; break; + default: { + if (c >= '0' && c <= '9') + lmp = sprintf("num_%g", c-'0'); + else + return "sb_quad"; // Unrecognized. + } + } + if (use_red) + lmp = strcat("a", lmp); + return lmp; +} + // this draws backwards, haven't bothered to change as we don't use it void Hud_DrawLargeValue(vector pos, float value, float threshhold, float size) { @@ -143,39 +163,31 @@ void Hud_DrawLargeValue(vector pos, float value, float threshhold, float size) void Hud_DrawStringLMP(vector pos, string value, float size) { - float c; - float len, i; + float len, i, j; string s; if (!size) size = 24; vector vsize = [size, size, 0]; s = value; len = strlen(s); - i = 0; + float use_red = FALSE; - while(iclip_size); + float rem = WP_GetAmmo(wi->ammo_type); + + // It's possible for the amount in clip to exceed remaining ammo (this + // occurs because we load before we drop for example). Render a clipped + // clip when this occurs, with a visual indicator. + if (clip > rem) + return sprintf("*%d*/%d", rem, wi->clip_size); + else + return sprintf("%d/%d", clip, wi->clip_size); } float WP_CanReload(Slot slot, string* msg = __NULL__) { From 802db0682acdc9e92dfb7279dced3bb9c522a62f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 2 May 2023 00:10:47 +1000 Subject: [PATCH 2093/2474] Prevent server crashing when reloadnext issued without playerclass --- ssqc/actions.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index d9d9bc24..9e08a6fd 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -469,6 +469,9 @@ void (entity pe_player, float f_type) CF_Identify = { }; void () TeamFortress_ReloadNext = { + if (self.playerclass < 1 || self.playerclass > 9) + return; + Slot slot = self.current_slot; do { From 365808b77800630c9a8d60eab24f249610ffc8cf Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 1 May 2023 13:15:20 -0700 Subject: [PATCH 2094/2474] hud: fix spacing on updated text rendering funcs - effective pre-increment was inserting a space on rendered elements - also just update the threshold equivalent to support use_red markup, even though it's not currently used --- csqc/hud_helpers.qc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 094b0e13..352a3b17 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -178,28 +178,32 @@ void Hud_DrawStringLMP(vector pos, string value, float size) continue; } - j++; if (lmp != "") HRC_drawpic(pos + [j * size, 0, 0], lmp, vsize, '1 1 1', 1, 0); + j++; } } void Hud_DrawStringLMPThreshold(vector pos, string value, float size, float threshold) { - float len, i, intval; + float len, i, j, intval, use_red = FALSE; string s, lmp; if (!size) size = 24; vector vsize = [size, size, 0]; s = value; intval = stof(value); len = strlen(s); - i = 0; - while(i Date: Mon, 1 May 2023 14:28:01 -0700 Subject: [PATCH 2095/2474] hud: improve scoreboard precision Clipping scoreboard units to kilos hides a lot of information. Impove behavior by more densely filling up to 4 digits: - <10000 now prints precisely - <100 % 1000 now prints with an additional decimal and unit - >100 % 1000 now prints as before --- csqc/status.qc | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 32ae043d..f060842f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -621,37 +621,25 @@ void(PanelID panelid, string text) drawReadyPanel = { } } -float (float val) AbbreviateNumber = { - val = val / 1000; - val = rint(val); - return val; -}; - string (float val) AbbreviateNumberToString = { - string abbr = ""; + val = rint(val); + if (val < 10000) + return ftos(rint(val)); - int count = 0; - while (val >= 1000) - { - val = AbbreviateNumber(val); + float count = 0; + while (val >= 1000) { + val /= 1000; count++; } - switch (count) - { - case 1: - abbr = "k"; - break; - case 2: - abbr = "m"; - break; - case 3: - abbr = "b"; - break; - } - - string s = strcat(ftos(val), abbr); - return s; + // Try to (with max density) use up to 4 characters. + const string abbr = "kmb"; + if (count == 0) + return ftos(val); + else if (val < 100) + return sprintf("%0.1f%c", val, abbr[min(count - 1, 2)]); + else + return sprintf("%d%c", val, abbr[min(count - 1, 2)]); }; void (vector position, vector size, string val, vector textcolour, float alpha From 6b5ae6be98d3a81688c9a936146a8f0a9254b5c6 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 1 May 2023 14:29:16 -0700 Subject: [PATCH 2096/2474] spy: set frl to something sane 0 just allows instant spam --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index a60d9dde..b4dd98d1 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -526,7 +526,7 @@ void () DecodeLevelParms = { feign_msg = CF_GetSetting("fm", "feign_msg", "on"); // rate limit on feign - feign_rate_limit = CF_GetSetting("frl", "feign_rate_limit", "0"); + feign_rate_limit = CF_GetSetting("frl", "feign_rate_limit", "0.5"); // turn off spy [off] spy_off = CF_GetSetting("spy", "spy", "off"); From 625325fc5c2107e8df8e0cf8febe966b9dadd87e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 1 May 2023 17:12:24 -0700 Subject: [PATCH 2097/2474] hud: render at right position DrawStringLMPThreshold was maintaining the offset in rendered space but still using the offset in strong. Doesn't affect anything in practice since use_red markup is not being used currently with this function. --- csqc/hud_helpers.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 352a3b17..7f7afc23 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -202,7 +202,7 @@ void Hud_DrawStringLMPThreshold(vector pos, string value, float size, float thre } if (lmp != "") - HRC_drawpic(pos + [i * size, 0, 0], lmp, vsize, '1 1 1', 1, 0); + HRC_drawpic(pos + [j * size, 0, 0], lmp, vsize, '1 1 1', 1, 0); j++; } } From 98ff9e30bf0b07c53d585e030cdaa8fa8d170258 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 1 May 2023 17:15:19 -0700 Subject: [PATCH 2098/2474] cleanup: remove deprecated project_weapons_* settings TODO: update documentation --- ssqc/client.qc | 7 ------- ssqc/qw.qc | 3 --- 2 files changed, 10 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index b4dd98d1..72049bc4 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -608,12 +608,6 @@ void () DecodeLevelParms = { // CSQC projectiles fo_projectiles = CF_GetSetting("focp", "fo_csqc_projectiles", "on"); - // project projectile weapons by player ping - project_weapons = CF_GetSetting("pw", "project_weapons", "off"); - - // max projectile projection latency (default 100ms) - project_weapons_max_latency = CF_GetSetting("pwml", "project_weapons_max_latency", ftos(0.1)); - // delay respawning by this many seconds [0] Role_None.respawn_delay_time = CF_GetSetting("rd", "respawn_delay", "0"); if (Role_None.respawn_delay_time) { @@ -1002,7 +996,6 @@ void () DecodeLevelParms = { detpipe_limit_world = 7; medicaura = FALSE; medicnocuss = FALSE; - project_weapons = FALSE; distance_based_cuss_duration = FALSE; drop_grenades = FALSE; drop_grenpack = FALSE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index fc101edd..95c5bfdf 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -600,9 +600,6 @@ float old_dispenser; float old_hp_armor; float max_armor_hwguy; -float project_weapons; -float project_weapons_max_latency; - float ng_damage; float sng_damage; float superaxe; From f6aa9bf4bb00710eb3aec7d2f16806998ef3fdc9 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 3 May 2023 11:33:02 -0700 Subject: [PATCH 2099/2474] hud: fix built-in pad bug strpad of negative length (for right align) on strings that are already the right length, sends them to the moon. Avoid this. Spacing on scoreboard generally needs a little bit of attention, but at least show a squished number rather than blank.. --- csqc/status.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csqc/status.qc b/csqc/status.qc index f060842f..16e09dd0 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -644,7 +644,8 @@ string (float val) AbbreviateNumberToString = { void (vector position, vector size, string val, vector textcolour, float alpha , float flags, string colname) drawShowScoresColumnVal = { - val = strpad(strlen(colname) * -1, val); + if (strlen(val) < strlen(colname)) + val = strpad(strlen(colname) * -1, val); sui_text(position, size, val, textcolour, 1, 0); }; From a03cab88a8872f4dfb2700532a54d3241bfb9467 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 5 May 2023 01:12:57 -0700 Subject: [PATCH 2100/2474] login: fix file-handle leaks and refactor The current login code is leaking file handles in two places which leads to login failures when we run out of handles and it's unable to read the token. Fix this but also just refactor so we're not duplicating the read/send path between client and server initiated. Add instructions for people who dont have a token to visit the FO website to get one. --- csqc/events.qc | 8 ++------ csqc/main.qc | 34 ++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index d19d5965..55f2a73a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -2,6 +2,7 @@ void ParseSBAR(); void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag); float StartGrenTimer(float primed_at, float expires_at, float grentype, float play_sound); +float FoLogin(string token, float print_error); void() CSQC_Parse_Event = { float msgtype = readbyte(); @@ -342,13 +343,8 @@ void() CSQC_Parse_Event = { RemoveVoteMap(readstring(), FALSE); break; case MSG_LOGIN: - local float filehandle = fopen(FO_TOKEN_PATH, FILE_READ); - if (filehandle != -1) { - localcmd("setinfo _fo_token ", fgets(filehandle), "\n"); - localcmd("cmd fo-login-silent\n"); - } else { + if (!FoLogin("", FALSE)) print("You are not logged in\n"); - } break; case MSG_PAUSE: CsGrenTimer::SyncPause(); diff --git a/csqc/main.qc b/csqc/main.qc index d3ba3082..bdabaa02 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,7 +10,7 @@ void AddGrenTimer(float grentype, float offset); void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); -void FoLogin(string token); +float FoLogin(string token, float print_error); void Perf_Status(); void FO_Hud_Init(); float InFluid(vector point); @@ -238,7 +238,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { Slot_Keyup(stof(argv(1))); break; case "login": - FoLogin(argv(1)); + FoLogin(argv(1), TRUE); break; case "fo_hud_editor": FO_Hud_Editor(); @@ -720,25 +720,35 @@ void Sync_GameState() { PM_PredictJump(); } -void FoLogin(string token) { - local float filehandle; +static string FoLogin_GetToken() { + float filehandle = fopen(FO_TOKEN_PATH, FILE_READ); + if (filehandle == -1) + return ""; + string token = fgets(filehandle); + fclose(filehandle); + return token; +} + +// Doesn't actually return success, just whether it sent a token. +float FoLogin(string token, float print_error) { if (token != "") { - filehandle = fopen(FO_TOKEN_PATH, FILE_WRITE); + float filehandle = fopen(FO_TOKEN_PATH, FILE_WRITE); fputs(filehandle, token); fclose(filehandle); } else { - filehandle = fopen(FO_TOKEN_PATH, FILE_READ); - if (filehandle == -1) { - print("Can't login without valid token\n"); - return; - } else { - token = fgets(filehandle); - } + token = FoLogin_GetToken(); + } + + if (token == "") { + if (print_error) + print("Token required: Please sign-up at FortressOne.org and follow the instructions to generate your login token.\n"); + return FALSE; } localcmd("setinfo _fo_token ", token, "\n"); localcmd("cmd fo-login-silent\n"); + return TRUE; } static string to_precision(float f, float p) { From 3500e373fb3e7a5eadcc5c8ba18a59c0a6f02315 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 5 May 2023 01:12:57 -0700 Subject: [PATCH 2101/2474] login: fix file-handle leaks and refactor The current login code is leaking file handles in two places which leads to login failures when we run out of handles and it's unable to read the token. Fix this but also just refactor so we're not duplicating the read/send path between client and server initiated. Add instructions for people who dont have a token to visit the FO website to get one. --- csqc/events.qc | 8 ++------ csqc/main.qc | 34 ++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index d19d5965..55f2a73a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -2,6 +2,7 @@ void ParseSBAR(); void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag); float StartGrenTimer(float primed_at, float expires_at, float grentype, float play_sound); +float FoLogin(string token, float print_error); void() CSQC_Parse_Event = { float msgtype = readbyte(); @@ -342,13 +343,8 @@ void() CSQC_Parse_Event = { RemoveVoteMap(readstring(), FALSE); break; case MSG_LOGIN: - local float filehandle = fopen(FO_TOKEN_PATH, FILE_READ); - if (filehandle != -1) { - localcmd("setinfo _fo_token ", fgets(filehandle), "\n"); - localcmd("cmd fo-login-silent\n"); - } else { + if (!FoLogin("", FALSE)) print("You are not logged in\n"); - } break; case MSG_PAUSE: CsGrenTimer::SyncPause(); diff --git a/csqc/main.qc b/csqc/main.qc index 825cde1a..95c820df 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -10,7 +10,7 @@ void AddGrenTimer(float grentype, float offset); void StopGrenTimers(); float IsValidToUseGrenades(); void Sync_GameState(); -void FoLogin(string token); +float FoLogin(string token, float print_error); void Perf_Status(); void FO_Hud_Init(); float InFluid(vector point); @@ -238,7 +238,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { Slot_Keyup(stof(argv(1))); break; case "login": - FoLogin(argv(1)); + FoLogin(argv(1), TRUE); break; case "fo_hud_editor": FO_Hud_Editor(); @@ -720,25 +720,35 @@ void Sync_GameState() { PM_PredictJump(); } -void FoLogin(string token) { - local float filehandle; +static string FoLogin_GetToken() { + float filehandle = fopen(FO_TOKEN_PATH, FILE_READ); + if (filehandle == -1) + return ""; + string token = fgets(filehandle); + fclose(filehandle); + return token; +} + +// Doesn't actually return success, just whether it sent a token. +float FoLogin(string token, float print_error) { if (token != "") { - filehandle = fopen(FO_TOKEN_PATH, FILE_WRITE); + float filehandle = fopen(FO_TOKEN_PATH, FILE_WRITE); fputs(filehandle, token); fclose(filehandle); } else { - filehandle = fopen(FO_TOKEN_PATH, FILE_READ); - if (filehandle == -1) { - print("Can't login without valid token\n"); - return; - } else { - token = fgets(filehandle); - } + token = FoLogin_GetToken(); + } + + if (token == "") { + if (print_error) + print("Token required: Please sign-up at FortressOne.org and follow the instructions to generate your login token.\n"); + return FALSE; } localcmd("setinfo _fo_token ", token, "\n"); localcmd("cmd fo-login-silent\n"); + return TRUE; } static string to_precision(float f, float p) { From 4ea7a3dab6c028f61102c520e3b546c49ca816de Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 6 May 2023 20:55:50 +1000 Subject: [PATCH 2102/2474] Don't both with logins if backend_address isn't configured --- csqc/main.qc | 2 +- ssqc/clan.qc | 2 +- ssqc/client.qc | 4 +--- ssqc/csmenu.qc | 2 +- ssqc/functions.qc | 58 +++++++++++++++++++++++++++-------------------- ssqc/qw.qc | 1 - ssqc/tforttm.qc | 2 +- 7 files changed, 39 insertions(+), 32 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 95c820df..ee2bc23a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -742,7 +742,7 @@ float FoLogin(string token, float print_error) { if (token == "") { if (print_error) - print("Token required: Please sign-up at FortressOne.org and follow the instructions to generate your login token.\n"); + print("Token required: Please sign-up at fortressone.org and follow the instructions to generate your login token.\n"); return FALSE; } diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 34a3e3cd..1179c4ea 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1094,7 +1094,7 @@ float () CheckAllPlayersReady = { } void () PlayerReady = { - if (self.fo_login == string_null && foLoginRequired) { + if (self.fo_login == string_null && foLoginRequired()) { sprint(self, PRINT_HIGH, "You need to log in to ready up. See fortressone.org\n"); return; } diff --git a/ssqc/client.qc b/ssqc/client.qc index a60d9dde..c574c409 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2052,9 +2052,7 @@ void (float all_dimensions) SetDimensions = { void () PutClientInServer = { if (self.fo_login == string_null) { - foLoginRequired = CF_GetSetting("fologinrequired", "fologreq", "1"); - - if (foLoginRequired) + if (foLoginRequired()) UpdateClient_Login(self); } diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 25b365b2..a7fa491a 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -367,7 +367,7 @@ void UpdateClient_Login(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; - if(!foLoginRequired) + if(!foLoginRequired()) return; msg_entity = pl; diff --git a/ssqc/functions.qc b/ssqc/functions.qc index dceb8079..060288fa 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -67,20 +67,20 @@ void () randomizeCaptains = { local float teamno = 0; local float capteam[4] = {0, 0, 0, 0}; - te = find(world, classname, "player"); - while (te != world) { - if (te.captain == 9 && tmp < number_of_teams) { + te = find(world, classname, "player"); + while (te != world) { + if (te.captain == 9 && tmp < number_of_teams) { do { teamno = floor((random() * number_of_teams)); } while (capteam[teamno] == 1); capteam[teamno] = 1; - te.captain = teamno + 1; + te.captain = teamno + 1; if (te.captain == 1) stuffcmd(te, "reload\n"); tmp = tmp + 1; } - te = find(te, classname, "player"); - } + te = find(te, classname, "player"); + } }; void () randomizeTeams = { @@ -89,8 +89,8 @@ void () randomizeTeams = { local float teamno = 0; local float randteam[4] = {0, 0, 0, 0}; - te = find(world, classname, "player"); - while (te != world) { + te = find(world, classname, "player"); + while (te != world) { if (tmp >= number_of_teams) { tmp = 0; randteam[0] = 0; @@ -98,7 +98,7 @@ void () randomizeTeams = { randteam[2] = 0; randteam[3] = 0; } - if (tmp < number_of_teams) { + if (tmp < number_of_teams) { do { teamno = floor((random() * number_of_teams)); } while (randteam[teamno] == 1); @@ -110,8 +110,8 @@ void () randomizeTeams = { self = temp; tmp = tmp + 1; } - te = find(te, classname, "player"); - } + te = find(te, classname, "player"); + } }; string (string text) clearString = { @@ -133,15 +133,15 @@ void () PrintLoginMessage = { void () EndGameThink = { local string m = mapname; - if(vote_result != string_null && vote_result != "") { - m = vote_result; - } else if(nextmap != string_null && nextmap != "") { - m = nextmap; - } - localcmd("changelevel "); - localcmd(m); - localcmd("\n"); - dremove(self); + if(vote_result != string_null && vote_result != "") { + m = vote_result; + } else if(nextmap != string_null && nextmap != "") { + m = nextmap; + } + localcmd("changelevel "); + localcmd(m); + localcmd("\n"); + dremove(self); } void () MapEndSequence = { @@ -164,8 +164,18 @@ void () MapEndSequence = { canlog = 0; maprestarttimer = spawn(); - maprestarttimer.classname = "timer"; - maprestarttimer.netname = "maprestarttimer"; - maprestarttimer.think = EndGameThink; - maprestarttimer.nextthink = time + map_restart_time; + maprestarttimer.classname = "timer"; + maprestarttimer.netname = "maprestarttimer"; + maprestarttimer.think = EndGameThink; + maprestarttimer.nextthink = time + map_restart_time; +} + +float () foLoginRequired = { + if (!CF_GetSetting("fologreq", "fologinrequired", "1")) + return 0; + + if (CF_GetSettingRaw("ba", "backend_address", "") == "") + return 0; + + return 1; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index fc101edd..9a5c0b39 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -739,7 +739,6 @@ float captainmode; .float captain; // fortressone.org API -float foLoginRequired; .string fo_login; //Player ID diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 20bc27c2..d4a4d019 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -295,7 +295,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options }; float (float tno) TeamFortress_TeamSet = { - if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login && foLoginRequired) { + if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login && foLoginRequired()) { sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or see fortressone.org\n"); return 0; } From 83dd3f26d2be6feddefd5db87e3b4974fc9162c4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 8 May 2023 01:52:02 +1000 Subject: [PATCH 2103/2474] Cache login status --- ssqc/clan.qc | 2 +- ssqc/client.qc | 16 ++-------------- ssqc/csmenu.qc | 2 +- ssqc/functions.qc | 10 ---------- ssqc/login.qc | 1 - ssqc/quadmode.qc | 3 --- ssqc/qw.qc | 3 ++- ssqc/tforttm.qc | 2 +- ssqc/world.qc | 5 +++++ 9 files changed, 12 insertions(+), 32 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index 1179c4ea..de247a11 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1094,7 +1094,7 @@ float () CheckAllPlayersReady = { } void () PlayerReady = { - if (self.fo_login == string_null && foLoginRequired()) { + if (fo_login_required && self.fo_login == string_null) { sprint(self, PRINT_HIGH, "You need to log in to ready up. See fortressone.org\n"); return; } diff --git a/ssqc/client.qc b/ssqc/client.qc index c574c409..852d6a06 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -757,16 +757,6 @@ void () DecodeLevelParms = { loginRequired = 0; } - // I don't actually define these because their values are sometimes needed before this code is called. - // Use admin menu to 'end map', DecodeLevelParms() doesn't get called until later. These setting - // globals should probably moved earlier. - - // specify API host for backend [""] - // backend_address = FO_GetUserSettingString(world, "backend_address", "https://www.fortressone.org/"); - - // enforce API login [""] - // foLoginRequired = CF_GetSetting("fologinrequired", "1"); - // specify demo filehost address e.g. https://fortressone-demos.s3.amazonaws.com/sydney/staging/ demo_files_address = FO_GetUserSettingString(world, "demo_files_address", "demofileaddy", ""); @@ -2051,10 +2041,8 @@ void (float all_dimensions) SetDimensions = { }; void () PutClientInServer = { - if (self.fo_login == string_null) { - if (foLoginRequired()) - UpdateClient_Login(self); - } + if (fo_login_required && self.fo_login == string_null) + UpdateClient_Login(self); local float oldclass; local entity spot; diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index a7fa491a..6ab2d45c 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -367,7 +367,7 @@ void UpdateClient_Login(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; - if(!foLoginRequired()) + if(!fo_login_required) return; msg_entity = pl; diff --git a/ssqc/functions.qc b/ssqc/functions.qc index 060288fa..5e7f5b65 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -169,13 +169,3 @@ void () MapEndSequence = { maprestarttimer.think = EndGameThink; maprestarttimer.nextthink = time + map_restart_time; } - -float () foLoginRequired = { - if (!CF_GetSetting("fologreq", "fologinrequired", "1")) - return 0; - - if (CF_GetSettingRaw("ba", "backend_address", "") == "") - return 0; - - return 1; -} diff --git a/ssqc/login.qc b/ssqc/login.qc index e061e425..2e2f472f 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -14,7 +14,6 @@ void (entity player, string login, string secret) performLogin = { } void (entity player) performFoLogin = { - local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/fo_login", backend_address); local string token = FO_GetUserSettingString(player, "_fo_token", "fo_token", ""); uri_get(uri, FO_LOGIN_REQUEST, "application/json", sprintf("{ \"auth_token\": \"%s\" }", token)); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 268257c9..f90e6663 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -64,7 +64,6 @@ void () PostFOQuadStarted = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); - local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/matches", backend_address); uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); }; @@ -122,7 +121,6 @@ void () PostFOQuadFinalRoundStarted = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); - local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/matches/%s", backend_address, match_id); uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); }; @@ -166,7 +164,6 @@ void (float winner) PostFOQuadFinished = { data = strcat(data, " }\n"); data = strcat(data, "}\n"); - local string backend_address = infokey(world, "backend_address"); local string uri = sprintf("%s/results/api/v1/matches/%s", backend_address, match_id); uri_post(uri, FO_QUAD_FINISHED_REQUEST, "application/json", data); }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9a5c0b39..fed85c31 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -796,6 +796,7 @@ string goal_class_names[7] = { .float special_cooldown; .float airblast_cooldown; - // backend string match_id; +string backend_address; +float fo_login_required; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index d4a4d019..f0f08ab3 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -295,7 +295,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options }; float (float tno) TeamFortress_TeamSet = { - if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login && foLoginRequired()) { + if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login && fo_login_required) { sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or see fortressone.org\n"); return 0; } diff --git a/ssqc/world.qc b/ssqc/world.qc index ef7a4404..c7cc99f1 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -340,6 +340,11 @@ void () worldspawn = { globalstat(STAT_NOFIRE, EV_FLOAT, "no_fire_mode"); globalstat(STAT_TEAMNO_ATTACK, EV_FLOAT, "team_no_attack"); + // login required cache + local float flr = CF_GetSetting("flr", "fologinrequired", "1"); + backend_address = CF_GetSettingRaw("ba", "backend_address", ""); + fo_login_required = (flr && (backend_address != "")); + entity worldspawnent; worldspawnent = spawn(); worldspawnent.think = WorldSpawnPost; From 69dccc621c89dc6da1d7a9461c9ac74e2cecbd81 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 10 May 2023 01:46:49 +1000 Subject: [PATCH 2104/2474] Remove pointless type from function fixing compile warning --- csqc/main.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index ee2bc23a..c3319ff2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -32,10 +32,10 @@ void PushToSlotHistory(float value) { slot_history[slot_history_top] = value; } -float RemoveFromSlotHistory(float slot) { +void RemoveFromSlotHistory(float slot) { if (slot_history_top == -1) { // Stack is empty - return -1; + return; } for (float i = slot_history_top; i >= 0; i--) { @@ -214,6 +214,7 @@ void Slot_Keydown(float slot) { void Slot_Keyup(float slot) { RemoveFromSlotHistory(slot); + if (slot_history_top >= 0) { // still holding another +slot bind localcmd(sprintf("impulse %f\n", slot_history[slot_history_top])); } else { From 6b3f16c96c5797ebd0cb849e09703808654ad859 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 12 May 2023 04:22:13 +1000 Subject: [PATCH 2105/2474] Prevent joining team without login. This effectively enforces login. But also prevents random players from joining during prematch, requiring them to be kicked (often repeatedly) --- ssqc/tforttm.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index f0f08ab3..49532513 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -295,8 +295,8 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options }; float (float tno) TeamFortress_TeamSet = { - if (quadmode && !cb_prematch && tno >=1 && tno <=4 && !self.fo_login && fo_login_required) { - sprint(self, PRINT_HIGH, "Cannot join game in progress if not logged in. Spectate or see fortressone.org\n"); + if (quadmode && tno >=1 && tno <=4 && !self.fo_login && fo_login_required) { + sprint(self, PRINT_HIGH, "You need to sign in first. Get your login token at www.fortressone.org\n"); return 0; } From 187f9e6ada2c4cc0afe8a4f9099fd58230053036 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 12 May 2023 05:03:08 +1000 Subject: [PATCH 2106/2474] Formatting --- ssqc/tforttm.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 49532513..7de4e16e 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -295,7 +295,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options }; float (float tno) TeamFortress_TeamSet = { - if (quadmode && tno >=1 && tno <=4 && !self.fo_login && fo_login_required) { + if (quadmode && tno >= 1 && tno <= 4 && !self.fo_login && fo_login_required) { sprint(self, PRINT_HIGH, "You need to sign in first. Get your login token at www.fortressone.org\n"); return 0; } From 4b378809721d193ae1beaa088a46cde572549ac9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 13 May 2023 20:36:24 +1000 Subject: [PATCH 2107/2474] Handle compressed gz demo filenames --- ssqc/quadmode.qc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index f90e6663..2ab6e3cc 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -8,7 +8,15 @@ void () PostFOQuadStarted = { data = strcat(data, " \"round\": \"", ftos(rounds), "\",\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); - local string demo_uri = strcat(demo_files_address, game_filename, ".mvd"); + local float game_filename_extension; + + if (cvar("sv_demoAutoCompress"))) { + game_filename_extension = ".mvd.gz"; + } else { + game_filename_extension = ".mvd"; + } + + local string demo_uri = strcat(demo_files_address, game_filename, game_filename_extension); data = strcat(data, " \"demo_uri\": \"", demo_uri, "\",\n"); local string stats_uri = strcat(stats_files_address, game_filename, ".html"); From 7c89ea02d32e6f2fcc7691dee21cc45f6e832340 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 13 May 2023 20:38:15 +1000 Subject: [PATCH 2108/2474] Fix type error --- ssqc/quadmode.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 2ab6e3cc..f37fad3f 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -8,9 +8,8 @@ void () PostFOQuadStarted = { data = strcat(data, " \"round\": \"", ftos(rounds), "\",\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); - local float game_filename_extension; - - if (cvar("sv_demoAutoCompress"))) { + local string game_filename_extension; + if (cvar("sv_demoAutoCompress")) { game_filename_extension = ".mvd.gz"; } else { game_filename_extension = ".mvd"; From ab3baeea841cbaec84b5b9063ecd86bd63500b9e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 16 May 2023 20:11:13 +1000 Subject: [PATCH 2109/2474] Don't attempt to send match results if login isn't required --- ssqc/quadmode.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index f90e6663..bb079624 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -478,7 +478,7 @@ void () QuadRoundBegin = { bprint(2, "QUAD ROUND BEGINS NOW\n"); - if (rounds == 1) + if (rounds == 1 && fo_login_required) PostFOQuadFinalRoundStarted(); te = find(world, classname, "player"); @@ -626,7 +626,8 @@ void () StartQuadRound = p = find (world, classname, "player"); // send result to server - PostFOQuadFinished(quad_winner); + if (fo_login_required) + PostFOQuadFinished(quad_winner); while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { @@ -678,7 +679,7 @@ void () StartQuadRound = p = find(p, classname, "player"); } - if (rounds == 2 && legit_players > 1) + if (rounds == 2 && legit_players > 1 && fo_login_required) PostFOQuadStarted(); if (rounds == 1 /* final round */) { From 35826c1b029925c22d94c33823a5f6e235b7e888 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 22 May 2023 20:06:16 +1000 Subject: [PATCH 2110/2474] Don't send match results if teams uneven, don't allow forcestart when logins enabled --- ssqc/clan.qc | 2 +- ssqc/commands.qc | 5 +++++ ssqc/quadmode.qc | 22 ++++++++++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ssqc/clan.qc b/ssqc/clan.qc index de247a11..d3448929 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -1095,7 +1095,7 @@ float () CheckAllPlayersReady = { void () PlayerReady = { if (fo_login_required && self.fo_login == string_null) { - sprint(self, PRINT_HIGH, "You need to log in to ready up. See fortressone.org\n"); + sprint(self, PRINT_HIGH, "You need to sign in first. Get your login token at www.fortressone.org\n"); return; } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 629de952..5e6f58e3 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -27,6 +27,11 @@ void () RestartMap = { } void () ForceStartMatch = { + if (fo_login_required) { + bprint(PRINT_HIGH, "Can't forcestart while logins enabled.\n"); + return; + } + if (clanbattle == 1 && cb_prematch == 1) { bprint(PRINT_HIGH, self.netname); bprint(PRINT_HIGH, " has forced the match start.\n"); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index bb079624..04c8912e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -1,6 +1,15 @@ void () info_player_teamspawn; void () PostFOQuadStarted = { + if (!fo_login_required) + return; + + if !(TeamFortress_TeamGetNoPlayersExcludingAllTime(1) == TeamFortress_TeamGetNoPlayersExcludingAllTime(2)) { + bprint(PRINT_HIGH, "Uneven teams, match can't be recorded\n"); + fo_login_required = FALSE; + return; + } + local string data = ""; data = strcat(data, "{\n"); @@ -69,6 +78,9 @@ void () PostFOQuadStarted = { }; void () PostFOQuadFinalRoundStarted = { + if (!fo_login_required) + return; + local string data = ""; data = strcat(data, "{\n"); @@ -126,6 +138,9 @@ void () PostFOQuadFinalRoundStarted = { }; void (float winner) PostFOQuadFinished = { + if (!fo_login_required) + return; + if (!match_id) return; @@ -478,7 +493,7 @@ void () QuadRoundBegin = { bprint(2, "QUAD ROUND BEGINS NOW\n"); - if (rounds == 1 && fo_login_required) + if (rounds == 1) PostFOQuadFinalRoundStarted(); te = find(world, classname, "player"); @@ -626,8 +641,7 @@ void () StartQuadRound = p = find (world, classname, "player"); // send result to server - if (fo_login_required) - PostFOQuadFinished(quad_winner); + PostFOQuadFinished(quad_winner); while (p != world) { if (p.netname != "" && p.team_no && p.playerclass) { @@ -679,7 +693,7 @@ void () StartQuadRound = p = find(p, classname, "player"); } - if (rounds == 2 && legit_players > 1 && fo_login_required) + if (rounds == 2 && legit_players > 1) PostFOQuadStarted(); if (rounds == 1 /* final round */) { From 98a0b9f7d24d989058a266311a0756aa081ec475 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 16 Jul 2023 13:59:03 +1000 Subject: [PATCH 2111/2474] Ensure feign next damage is disabled on respawn --- ssqc/client.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 852d6a06..ba8f15aa 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2073,6 +2073,7 @@ void () PutClientInServer = { self.saveme_time = 0; self.display_tip = 0; self.tip_type = 0; + self.feign_next_damage = 0; FO_InstantReloadAllWeapons(self); @@ -2204,7 +2205,7 @@ void () PutClientInServer = { if ((spot.classname == "info_player_teamspawn") && (!cb_prematch)) { - + if (spot.items != 0) { te = Finditem(spot.items); if (te) @@ -2229,7 +2230,7 @@ void () PutClientInServer = { spot.think = SUB_Remove; } } - + setmodel(self, string_null); modelindex_null = self.modelindex; @@ -2243,6 +2244,7 @@ void () PutClientInServer = { self.modelindex = modelindex_null; self.menu_input = nil; } + setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); self.view_ofs = '0 0 22'; self.velocity = '0 0 0'; From feb2c7aead9421374ef5b52655e3df3367866154 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 25 Jul 2023 12:08:33 -0700 Subject: [PATCH 2112/2474] client: work-around for missing models issue flush post world-load to resolve race conditions where models appended into the map package do not resolve correctly. --- csqc/main.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index b4efe67f..b489c7d7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -165,6 +165,9 @@ noref void() CSQC_WorldLoaded = { print("CSQC World Loaded\n"); ClientSettings_Check(); localcmd("menu_restart\n"); + // Resolve race condition where models packed into map package sometimes do + // not resolve correctly. + localcmd("flush\n"); } void FO_CussView(); From 301b252f6b0e94a4e8809425fb878f6f3c5317e0 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 25 Jul 2023 12:28:36 -0700 Subject: [PATCH 2113/2474] medic: activate aura by default when changing class to medic and off The most common reason for this being off is.. forgetting to turn it on. Flip this to be on by default when you change class to medic. If you turn it off, it will stay off (unless you again change classes), but the default is now on. --- ssqc/client.qc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ssqc/client.qc b/ssqc/client.qc index e11872d5..2666d040 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2113,6 +2113,8 @@ void () PutClientInServer = { TeamFortress_ChangeClass(11); } + int prev_playerclass = self.playerclass; + if (deathmatch == 3) { if(self.nextpc != self.playerclass) { if (self.playerclass != 0) { @@ -2293,6 +2295,11 @@ void () PutClientInServer = { self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY; } + // Activate medic aura by default when changing to class and off + if (self.playerclass == PC_MEDIC && prev_playerclass != PC_MEDIC && + !self.aura_active) + CF_Medic_AuraToggle(); + UpdateReadyStatus(); }; From 335c815779da162ee2a5a6bbb5d269eff2f82d58 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 31 Jul 2023 02:43:20 +1000 Subject: [PATCH 2114/2474] Hide flag to carrier --- ssqc/tfortmap.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 5cca8391..17a21fd7 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2199,6 +2199,7 @@ void () item_tfgoal_touch = { newmis.movetype = MOVETYPE_FOLLOW; newmis.aiment = other; newmis.view_ofs = newmis.origin - other.origin; + newmis.nodrawtoclient = other; } }; From a9be1465a5f426e51924c53d116a3078fe1314a5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 31 Jul 2023 03:07:56 +1000 Subject: [PATCH 2115/2474] Auto update server when stale --- ssqc/world.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/world.qc b/ssqc/world.qc index c7cc99f1..a4483e47 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -515,6 +515,8 @@ void () TerminateStaleServer = { return; //someone is around } + Admin_UpdateServer(); + dprint(sprintf("Terminating empty server with more than %d hours uptime\n", STALE_TIME_HOURS)); localcmd("quit\n"); From e490dba01d480071d6a439e92c3f46e0dd521749 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 31 Jul 2023 03:12:02 +1000 Subject: [PATCH 2116/2474] Auto update stale server --- ssqc/world.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/world.qc b/ssqc/world.qc index c7cc99f1..a4483e47 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -515,6 +515,8 @@ void () TerminateStaleServer = { return; //someone is around } + Admin_UpdateServer(); + dprint(sprintf("Terminating empty server with more than %d hours uptime\n", STALE_TIME_HOURS)); localcmd("quit\n"); From 3f2c294daebf0e93ebc337766084c1b9cb75f41a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 31 Jul 2023 16:31:56 -0700 Subject: [PATCH 2117/2474] hwguy: fix locked weaponframe selection CSQC side was filling in wrong field --- share/animate.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/animate.qc b/share/animate.qc index ab40bbe5..6d0db327 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -154,7 +154,7 @@ static inline float is_attacking() { return input_buttons & BUTTON0; } static inline float is_intermission() { return intermission; } static void SuperDamageSound() {} // TODO static inline vector get_velocity() { return pmove_vel; } -static inline void set_weapon_frame(int f) { self.frame = f; } +static inline void set_weapon_frame(float f) { pstate_pred.weaponframe = f; } static inline void muzzleflash() {} float WP_CurrentClipFired(); static inline float get_clip_fired() { return WP_CurrentClipFired(); } From 65566b778dd7c7219fecc42ed16bbf1dc9c0b111 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 11 Aug 2023 15:20:58 -0700 Subject: [PATCH 2118/2474] client: add slot_a for alternating slot selection pecan was dependent using bugs in the old +slot implementation so that he could switch between reds/yellows while using a +slot bind. Add a new client command to do what he really wants: to be able to swap between reds/yellows, swapping to reds if neither active We implement a more generic form of this, "slot_a ". This lets you bind it with 2 passed slots, when activated, it will switch to slot_a if neither is selected, otherwise it will alternate between them. pecan's use case becomes: bind key slot_a 1 2 --- csqc/main.qc | 8 ++++++++ csqc/weapon_predict.qc | 17 +++++++++++++++++ share/weapons.qc | 3 ++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index b489c7d7..a3a770f3 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -118,6 +118,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); + + registercommand("slot_a"); + // registercommand("+quick1"); // registercommand("-quick1"); // registercommand("+quick2"); @@ -228,6 +231,8 @@ void Slot_Keyup(float slot) { } } +void W_ChangeToSlotAlternate(string opt1, string opt2); + noref float(string cmd) CSQC_ConsoleCommand = { tokenize_console(cmd); float val; @@ -477,6 +482,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "vote_removemap": RemoveVoteMap(argv(1), TRUE); break; + case "slot_a": // Alternate between passed options + W_ChangeToSlotAlternate(argv(1), argv(2)); + break; } return FALSE; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 1e4046ab..1cec49c7 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -644,6 +644,23 @@ void WP_ChangeWeapon(Slot slot) { // UpdateViewModel will propagate. } +// Alternate between opt1/opt2, activating opt1 if neither is active. +// Useful for demoman to have red/yellows bound to 1 key. +void W_ChangeToSlotAlternate(string opt1, string opt2) { + float v1 = strlen(opt1) > 0 ? stof(opt1) : 0; + float v2 = strlen(opt2) > 0 ? stof(opt2) : v1; + + if ((v1 < 1 || v1 > TF_NUM_SLOTS) || (v2 < 1 || v2 > TF_NUM_SLOTS)) + return; + + // The OWI/slot mess rears its head again here. We convert to a slot for + // comparison but use the naked input value which will then be converted per + // OWI if active. + Slot slot = FO_SlotByInput(pstate_pred.playerclass, v1); + float imp = IsSameSlot(pstate_pred.current_slot, slot) ? v2 : v1; + localcmd(sprintf("impulse %d\n", imp)); +} + Slot WP_BestWeaponSlot() { for (float i = 1; i <= TF_NUM_SLOTS; i++) { Slot slot = MakeSlot(i); diff --git a/share/weapons.qc b/share/weapons.qc index f62e431e..a0ed2d8b 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -34,7 +34,8 @@ float SlotIndex(Slot slot) { printf("ERROR: OOB slot id (%d) found. Continuing.\n", (float)slot.id); return TF_NUM_SLOTS - 1; } - return slot.id - 1; } + return slot.id - 1; +} // Convert a weapon-bit to a linear index. static float WEAP_to_index(float weapon) { From 92176ad0b3f74f175520bf097062c0fb4a1182c6 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 13 Aug 2023 16:11:36 -0700 Subject: [PATCH 2119/2474] init: no more stuff If you've ever noticed that first connect seems to take a long time compared to subsequent ones it turns out that hundreds of mod aliases (many of which we no longer really use) are being stuffed (with a rate limit) for binding. Eliminate this by performing client binds directly in CSQC, with no server-side stuffs. --- csqc/main.qc | 23 +++- share/defs.h | 158 ++++++++++++++++++++++++- ssqc/client.qc | 5 +- ssqc/qw.qc | 1 - ssqc/spect.qc | 5 - ssqc/tforthlp.qc | 296 +++++++---------------------------------------- ssqc/weapons.qc | 5 - 7 files changed, 226 insertions(+), 267 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index a3a770f3..01877e6b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -52,6 +52,23 @@ void RemoveFromSlotHistory(float slot) { } +static void BindAlias(TFAlias* tfa) { + if (tfa->impulse == 0 && tfa->cmd == "") // Some aliases are !csqc-only + return; + + if (tfa->impulse) + localcmd(sprintf("alias %s impulse %d\n", tfa->alias, tfa->impulse)); + else + localcmd(strcat("alias ", tfa->alias, " \"", tfa->cmd, "\"\n")); +} + +static void SetupAliases() { + for (float i = 0; i < client_aliases.length; i++) + BindAlias(&client_aliases[i]); + + print("Aliases set\n"); +} + DECLARE_PERF_SAMPLER(frame_timing, 60, 0.1); DECLARE_PERF_SAMPLER(hud_timing, 60, 0.1); DECLARE_PERF_SAMPLER(hud_partial_timing, 60, 0.1); @@ -162,11 +179,13 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { vote_list_filter = ""; TF_Init(); + + ClientSettings_Check(); + SetupAliases(); + print("CSQC initialization finished\n"); }; noref void() CSQC_WorldLoaded = { - print("CSQC World Loaded\n"); - ClientSettings_Check(); localcmd("menu_restart\n"); // Resolve race condition where models packed into map package sometimes do // not resolve correctly. diff --git a/share/defs.h b/share/defs.h index e30d08bd..3a1a5ae9 100644 --- a/share/defs.h +++ b/share/defs.h @@ -509,7 +509,7 @@ struct Slot { int id; }; #define TF_SHOWTF 107 // Displays server settings and mod version #define TF_SHOWLEGALCLASSES 108 // Show what classes are allowed by current map #define TF_SHOW_IDS 109 // Show ids of connected players -#define TF_ALIAS_CHECK 110 // Check if client has gotten all the aliases +// unused 110 #define TF_CHANGECLASS 111 // Bring up class selection menu #define TF_CHANGEPC_SCOUT 112 // Change class to Scout #define TF_CHANGEPC_SNIPER 113 // Change class to Sniper @@ -1537,3 +1537,159 @@ enumflags { #define FO_QUAD_STARTED_REQUEST 2 #define FO_QUAD_FINISHED_REQUEST 3 #define FO_LOGIN_REQUEST 4 + +struct TFAlias { + string alias; + float impulse; + string cmd; + float nocsqc_impulse; + string nocsqc_cmd; +}; + +TFAlias client_aliases[] = { + {"slot1", TF_IMPULSE_SLOT1}, + {"slot2", TF_IMPULSE_SLOT2}, + {"slot3", TF_IMPULSE_SLOT3}, + {"slot4", TF_IMPULSE_SLOT4}, + {"+slot1", 0, "impulse 20;+attack"}, + {"-slot1", 0, "-attack;impulse 24"}, + {"+slot2", 0, "impulse 21;+attack"}, + {"-slot2", 0, "-attack;impulse 24"}, + {"+slot3", 0, "impulse 22;+attack"}, + {"-slot3", 0, "-attack;impulse 24"}, + {"+slot4", 0, "impulse 23;+attack"}, + {"-slot4", 0, "-attack;impulse 24"}, + {"+quick1", 0, "impulse 1;+attack"}, + {"-quick1", 0, "-attack"}, + {"+quick2", 0, "impulse 2;+attack"}, + {"-quick2", 0, "-attack"}, + {"+quick3", 0, "impulse 3;+attack"}, + {"-quick3", 0, "-attack"}, + {"+quick4", 0, "impulse 4;+attack"}, + {"-quick4", 0, "-attack"}, + {"menu", 0, "fo_menu_special", 0, "cmd menu"}, + {"changeteam", 0, "fo_menu_team", TF_CHANGETEAM}, + {"teamblue", 0, "cmd changeteam 1", TF_TEAM_1}, + {"teamred", 0, "cmd changeteam 2", TF_TEAM_2}, + {"teamyellow", 0, "cmd changeteam 3", TF_TEAM_3}, + {"teamgreen", 0, "cmd changeteam 4", TF_TEAM_4}, + {"changeclass", 0, "fo_menu_class", TF_CHANGECLASS}, + {"scout", 0, "cmd changeclass 1", TF_CHANGEPC_SCOUT}, + {"sniper", 0, "cmd changeclass 2", TF_CHANGEPC_SNIPER}, + {"soldier", 0, "cmd changeclass 3", TF_CHANGEPC_SOLDIER}, + {"demoman", 0, "cmd changeclass 4", TF_CHANGEPC_DEMOMAN}, + {"medic", 0, "cmd changeclass 5", TF_CHANGEPC_MEDIC}, + {"hwguy", 0, "cmd changeclass 6", TF_CHANGEPC_HVYWEAP}, + {"pyro", 0, "cmd changeclass 7", TF_CHANGEPC_PYRO}, + {"spy", 0, "cmd changeclass 8", TF_CHANGEPC_SPY}, + {"engineer", 0, "cmd changeclass 9", TF_CHANGEPC_ENGINEER}, + {"randompc", 0, "cmd changeclass 10", TF_CHANGEPC_RANDOM}, + {"showclasses", TF_TEAM_CLASSES}, + {"legalclasses", TF_SHOWLEGALCLASSES}, + {"classhelp", TF_CLASSHELP}, + {"query", TF_STATUS_QUERY}, + {"inv", TF_INVENTORY}, + {"showtf", TF_SHOWTF}, + {"showscores", TF_TEAM_SCORES}, + {"flaginfo", FLAG_INFO}, + {"maphelp", TF_HELP_MAP}, + {"showids", TF_SHOW_IDS}, + {"id", TF_ID}, + {"idteam", TF_ID_TEAM}, + {"idenemy", TF_ID_ENEMY}, + {"nexttip", TF_NEXTTIP}, + {"votenext", TF_VOTENEXT}, + {"votetrick", TF_VOTETRICK}, + {"voterace", TF_VOTERACE}, + {"forcenext", TF_FORCENEXT}, + {"togglevote", TF_TOGGLEVOTE}, + {"dropkey", TF_DROPKEY}, + {"dropammo", 0, "fo_menu_dropammo", TF_DROP_AMMO}, + {"dropflag", TF_DROPFLAG}, + {"dropitems", TF_DROPFLAG}, + {"showloc", TF_DISPLAYLOCATION}, + {"special", TF_SPECIAL_SKILL}, + {"special2", TF_SPECIAL_SKILL_2}, + {"saveme", TF_MEDIC_HELPME}, + {"discard", TF_DISCARD}, + {"discard_drop_ammo", TF_DISCARD_DROP_AMMO}, + {"weapnext", TF_WEAPNEXT}, + {"weapprev", TF_WEAPPREV}, + {"weaplast", TF_WEAPLAST}, + {"reload", TF_RELOAD}, + {"reload1", TF_RELOAD_SLOT1}, + {"reload2", TF_RELOAD_SLOT2}, + {"reload3", TF_RELOAD_SLOT3}, + {"reloadnext", TF_RELOAD_NEXT}, + {"grenswitch", TF_GRENADE_SWITCH}, + {"throwgren", TF_GRENADE_T}, + {"primeone", TF_GRENADE_1}, + {"primetwo", TF_GRENADE_2}, + {"+gren1", TF_GRENADE_1}, + {"-gren1", TF_GRENADE_T}, + {"+gren2", TF_GRENADE_2}, + {"-gren2", TF_GRENADE_T}, + {"gren1", TF_GRENADE_PT_1}, + {"gren2", TF_GRENADE_PT_2}, + {"dash", TF_DASH}, + {"autoscan", TF_SCAN}, + {"scansound", TF_SCAN_SOUND}, + {"scanf", TF_SCAN_FRIENDLY}, + {"scane", TF_SCAN_ENEMY}, + {"zoomtoggle", TF_ZOOMTOGGLE}, + {"zoomin", TF_ZOOMIN}, + {"zoomout", TF_ZOOMOUT}, + {"detpipe", TF_PB_DETONATE}, + {"+det5", TF_DETPACK_5}, + {"-det5", TF_DETPACK_STOP}, + {"+det20", TF_DETPACK_20}, + {"-det20", TF_DETPACK_STOP}, + {"+det50", TF_DETPACK_50}, + {"-det50", TF_DETPACK_STOP}, + {"+det255", TF_DETPACK}, + {"-det255", TF_DETPACK_STOP}, + {"aura", TF_MEDIC_AURA_TOGGLE}, + {"locktoggle", TF_HVYWEAP_LOCK_TOGGLE}, + {"lock", TF_LOCKON}, + {"unlock", TF_LOCKOFF}, + {"+lock", TF_LOCKON}, + {"-lock", TF_LOCKOFF}, + {"airblast", TF_AIRBLAST}, + {"disguise", 0, "fo_menu_disguise", TF_SPY_SPY}, + {"+feign", TF_SPY_DIE_ON}, + {"-feign", TF_SPY_DIE_OFF}, + {"feign", TF_SPY_DIE}, + {"sfeign", TF_SPY_SILENT_DIE}, + {"dreset", TF_DISGUISE_RESET}, + {"dscout", TF_DISGUISE_SCOUT}, + {"dsniper", TF_DISGUISE_SNIPER}, + {"dsoldier", TF_DISGUISE_SOLDIER}, + {"ddemoman", TF_DISGUISE_DEMOMAN}, + {"dmedic", TF_DISGUISE_MEDIC}, + {"dhwguy", TF_DISGUISE_HWGUY}, + {"dpyro", TF_DISGUISE_PYRO}, + {"dengineer", TF_DISGUISE_ENGINEER}, + {"dblue", TF_DISGUISE_BLUE}, + {"dred", TF_DISGUISE_RED}, + {"dyellow", TF_DISGUISE_YELLOW}, + {"dgreen", TF_DISGUISE_GREEN}, + {"denemy", TF_DISGUISE_ENEMY}, + {"dlast", TF_DISGUISE_LAST}, + {"dlastspawn", TF_DISGUISE_LAST_SPAWNED}, + {"build", 0, "fo_menu_build", TF_ENGINEER_BUILD}, + {"detsentry", TF_ENGINEER_DETSENTRY}, + {"detdispenser", TF_ENGINEER_DETDISP}, + {"toggledispenser", TF_ENGINEER_TOGGLEDISPENSER}, + {"togglesentry", TF_ENGINEER_TOGGLESENTRY}, + {"ready", TF_PLAYER_READY}, + {"notready", TF_PLAYER_NOT_READY}, + {"nginfo", TF_NAILGREN_INFO}, + {"break", 0, "cmd break"}, + {"voteyes", 0, "cmd voteyes"}, + {"yes", 0, "cmd voteyes"}, + {"fo_settings_status", 0, "cmd fo_settings_status"}, + {"placepracspawn", TF_PRACSPAWN_PLACE}, + {"removepracspawn", TF_PRACSPAWN_REMOVE}, + {"tracktarget", 0, "", 0, "cmd track target"}, +}; + diff --git a/ssqc/client.qc b/ssqc/client.qc index 2666d040..11b0e972 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2942,6 +2942,8 @@ void FO_HandleTFStateUpdate() { self.last_tfstate = self.tfstate; } +void TeamFortress_MOTD(); + void () PlayerPostThink = { FO_CheckClientThink(); UpdateScoreboardInfo(self); @@ -3005,7 +3007,7 @@ void () PlayerPostThink = { FO_ReloadFrame(); ButtonFrame(); W_WeaponFrame(); - if (self.motd <= 400) { + if (self.motd >= 0) { TeamFortress_MOTD(); } else { if (self.cheat_check == 0) { @@ -3049,7 +3051,6 @@ void () ClientConnect = { bprint(PRINT_HIGH, self.netname, " entered the game\n"); self.motd = 0; - self.got_aliases = 0; if (self.netname == string_null) KickCheater(self); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 10109581..c8450756 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -49,7 +49,6 @@ float remote_client_time(); .float tp_grenades_2; // 2nd type of grenades being carried .float tp_grenade_switch; // Set to 1 if +gren1 and +gren2 switch places .float hook_out; // Dummy field for hook to silence error messages -.float got_aliases; // TRUE if the player has TeamFortress aliases .float cheat_check; // Time when we'll next check for team cheats .float is_removed; // TRUE if the entity has been removed .float is_undercover; // TRUE for a SPY if they're undercover diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 2b045ce2..24367707 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -12,7 +12,6 @@ void () SpectatorDisconnect; void () SpectatorImpulseCommand; void () SpectatorThink; -void () Quick_Aliases; void () Admin_Aliases; void () SpectatorConnect = { @@ -29,8 +28,6 @@ void () SpectatorConnect = { if (infokey(self,"*admin")) self.is_admin = stof(infokey(self, "*admin")); - Quick_Aliases(); - st = infokey(self, "apw"); if (st == string_null) st = infokey(self, "adminpwd"); @@ -160,8 +157,6 @@ void () SpectatorThink = { if (self.impulse) SpectatorImpulseCommand(); - //if (self.motd <= 400) - // TeamFortress_MOTD(); if (time >= self.StatusRefreshTime) { RefreshStatusBar(self); } diff --git a/ssqc/tforthlp.qc b/ssqc/tforthlp.qc index a869d546..ab35927d 100644 --- a/ssqc/tforthlp.qc +++ b/ssqc/tforthlp.qc @@ -8,272 +8,66 @@ void (float inp) MOTD_Input = { Menu_Team_Input(inp); }; -void () Quick_Aliases = -{ - TeamFortress_AliasString("+quick1", "impulse 1;+attack"); - TeamFortress_AliasString("-quick1", "-attack"); - TeamFortress_AliasString("+quick2", "impulse 2;+attack"); - TeamFortress_AliasString("-quick2", "-attack"); - TeamFortress_AliasString("+quick3", "impulse 3;+attack"); - TeamFortress_AliasString("-quick3", "-attack"); - TeamFortress_AliasString("+quick4", "impulse 4;+attack"); - TeamFortress_AliasString("-quick4", "-attack"); -}; - -void () TeamFortress_MOTD = { - if (votemode) { +void TeamFortress_MOTD() { + if (votemode) return; - } - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if (self.classname == "observer") { - if(!csqcactive) { - TeamFortress_AliasString("tracktarget", "cmd tracktarget"); - } + + if (loginRequired && !self.login) + Menu_Login(); + else + Menu_Team(0); + + float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); + if (csqcactive) { + self.motd = -1; return; } + // Below is not really tested, it's an attempt at preserving for posterity. + // Expect potential bugs if we ever reintroduce !CSQC support. + const float ALIAS_OFFSET = 100; - local string st1; - local string st2; - local string ya; - - if (self.motd == 5) { - if(csqcactive) { - if(self.team_no == 0 && !intermission_running ) { - if (loginRequired && !self.login) - Menu_Login(); - else - Menu_Team(0); - } - } else { - sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); + if (self.motd == 0) { + if ((teamplay != 0) && (self.team_no == 0)) + stuffcmd(self, "color 0\n"); - st1 = infokey(world, "motd1"); - if (st1 != string_null) { - st2 = infokey(world, "motd2"); - if (st2 != string_null) { - st1 = strcat(strcat(st1, "\n"), st2); - } - } else { - st1 = "Welcome to FortressOne\n==================================\nwww.github.com/FortressOne"; - } + sprint(self, PRINT_HIGH, "\nFortressOne ", VER, "\n\n"); - sprint(self, PRINT_HIGH, st1); - sprint(self, PRINT_HIGH, "\n\n\n"); - if(self.team_no == 0 && !intermission_running) { - Status_Menu(self, MOTD_Input, st1); + string st1, st2; + st1 = infokey(world, "motd1"); + if (st1 != string_null) { + st2 = infokey(world, "motd2"); + if (st2 != string_null) { + st1 = strcat(strcat(st1, "\n"), st2); } - } - } - - if (self.motd == 20) { - if ((teamplay != 0) && (self.team_no == 0)) { - stuffcmd(self, "color "); - ya = ftos(0); - stuffcmd(self, ya); - stuffcmd(self, "\n"); + } else { + st1 = "Welcome to FortressOne\n==================================\nwww.github.com/FortressOne"; } - // will also skip motd - if (self.got_aliases == TRUE) { - self.motd = 400; - return; - } + sprint(self, PRINT_HIGH, strcat(st1, "\n\n\n")); + if(self.team_no == 0 && !intermission_running) + Status_Menu(self, MOTD_Input, st1); - if (csqcactive) { - TeamFortress_AliasString("menu", "fo_menu_special"); - } else { - TeamFortress_AliasString("menu", "cmd menu"); - } + self.motd = ALIAS_OFFSET; + } - TeamFortress_Alias("slot1", TF_IMPULSE_SLOT1, 0); - TeamFortress_Alias("slot2", TF_IMPULSE_SLOT2, 0); - TeamFortress_Alias("slot3", TF_IMPULSE_SLOT3, 0); - TeamFortress_Alias("slot4", TF_IMPULSE_SLOT4, 0); + float idx = self.motd - ALIAS_OFFSET; + if (idx >= 0 && idx < client_aliases.length) { + TFAlias* alias = &client_aliases[idx]; - TeamFortress_AliasString("+slot1", "impulse 20;+attack"); - TeamFortress_AliasString("-slot1", "-attack;impulse 24"); - TeamFortress_AliasString("+slot2", "impulse 21;+attack"); - TeamFortress_AliasString("-slot2", "-attack;impulse 24"); - TeamFortress_AliasString("+slot3", "impulse 22;+attack"); - TeamFortress_AliasString("-slot3", "-attack;impulse 24"); - TeamFortress_AliasString("+slot4", "impulse 23;+attack"); - TeamFortress_AliasString("-slot4", "-attack;impulse 24"); - } else if (self.motd == 30) { - if(csqcactive) { - TeamFortress_AliasString("changeteam", "fo_menu_team"); - TeamFortress_AliasString("teamblue", "cmd changeteam 1"); - TeamFortress_AliasString("teamred", "cmd changeteam 2"); - TeamFortress_AliasString("teamyellow", "cmd changeteam 3"); - TeamFortress_AliasString("teamgreen", "cmd changeteam 4"); - TeamFortress_AliasString("changeclass", "fo_menu_class"); - TeamFortress_AliasString("scout", "cmd changeclass 1"); - TeamFortress_AliasString("sniper", "cmd changeclass 2"); - TeamFortress_AliasString("soldier", "cmd changeclass 3"); - TeamFortress_AliasString("demoman", "cmd changeclass 4"); - TeamFortress_AliasString("medic", "cmd changeclass 5"); - TeamFortress_AliasString("hwguy", "cmd changeclass 6"); - TeamFortress_AliasString("pyro", "cmd changeclass 7"); - TeamFortress_AliasString("spy", "cmd changeclass 8"); - TeamFortress_AliasString("engineer", "cmd changeclass 9"); - TeamFortress_AliasString("randompc", "cmd changeclass 10"); - } else { - TeamFortress_Alias("changeteam", TF_CHANGETEAM, 0); - TeamFortress_Alias("teamblue", TF_TEAM_1, 0); - TeamFortress_Alias("teamred", TF_TEAM_2, 0); - TeamFortress_Alias("teamyellow", TF_TEAM_3, 0); - TeamFortress_Alias("teamgreen", TF_TEAM_4, 0); - TeamFortress_Alias("changeclass", TF_CHANGECLASS, 0); - TeamFortress_Alias("scout", TF_CHANGEPC_SCOUT, 0); - TeamFortress_Alias("sniper", TF_CHANGEPC_SNIPER, 0); - TeamFortress_Alias("soldier", TF_CHANGEPC_SOLDIER, 0); - TeamFortress_Alias("demoman", TF_CHANGEPC_DEMOMAN, 0); - TeamFortress_Alias("medic", TF_CHANGEPC_MEDIC, 0); - TeamFortress_Alias("hwguy", TF_CHANGEPC_HVYWEAP, 0); - TeamFortress_Alias("pyro", TF_CHANGEPC_PYRO, 0); - TeamFortress_Alias("spy", TF_CHANGEPC_SPY, 0); - TeamFortress_Alias("engineer", TF_CHANGEPC_ENGINEER, 0); - TeamFortress_Alias("randompc", TF_CHANGEPC_RANDOM, 0); - } - TeamFortress_Alias("showclasses", TF_TEAM_CLASSES, 0); - TeamFortress_Alias("legalclasses", TF_SHOWLEGALCLASSES, 0); - TeamFortress_Alias("classhelp", TF_CLASSHELP, 0); - } else if (self.motd == 40) { - TeamFortress_Alias("query", TF_STATUS_QUERY, 0); - TeamFortress_Alias("inv", TF_INVENTORY, 0); - TeamFortress_Alias("showtf", TF_SHOWTF, 0); - TeamFortress_Alias("showscores", TF_TEAM_SCORES, 0); - TeamFortress_Alias("flaginfo", FLAG_INFO, 0); - TeamFortress_Alias("maphelp", TF_HELP_MAP, 0); - TeamFortress_Alias("showids", TF_SHOW_IDS, 0); - TeamFortress_Alias("id", TF_ID, 0); - TeamFortress_Alias("idteam", TF_ID_TEAM, 0); - TeamFortress_Alias("idenemy", TF_ID_ENEMY, 0); - TeamFortress_Alias("is_aliased", TF_ALIAS_CHECK, 0); - } else if (self.motd == 50) { - TeamFortress_Alias("nexttip", TF_NEXTTIP, 0); - TeamFortress_Alias("votenext", TF_VOTENEXT, 0); - TeamFortress_Alias("votetrick", TF_VOTETRICK, 0); - TeamFortress_Alias("voterace", TF_VOTERACE, 0); - TeamFortress_Alias("forcenext", TF_FORCENEXT, 0); - TeamFortress_Alias("togglevote", TF_TOGGLEVOTE, 0); - TeamFortress_Alias("dropkey", TF_DROPKEY, 0); - if(csqcactive) { - TeamFortress_AliasString("dropammo", "fo_menu_dropammo"); - } else { - TeamFortress_Alias("dropammo", TF_DROP_AMMO, 0); - } - TeamFortress_Alias("dropflag", TF_DROPFLAG, 0); - TeamFortress_Alias("dropitems", TF_DROPFLAG, 0); - TeamFortress_Alias("showloc", TF_DISPLAYLOCATION, 0); - TeamFortress_Alias("special", TF_SPECIAL_SKILL, 0); - TeamFortress_Alias("special2", TF_SPECIAL_SKILL_2, 0); - TeamFortress_Alias("saveme", TF_MEDIC_HELPME, 0); - TeamFortress_Alias("discard", TF_DISCARD, 0); - TeamFortress_Alias("discard_drop_ammo", TF_DISCARD_DROP_AMMO, 0); - } else if (self.motd == 60) { - TeamFortress_Alias("weapnext", TF_WEAPNEXT, 0); - TeamFortress_Alias("weapprev", TF_WEAPPREV, 0); - TeamFortress_Alias("weaplast", TF_WEAPLAST, 0); - TeamFortress_Alias("reload", TF_RELOAD, 0); - TeamFortress_Alias("reload1", TF_RELOAD_SLOT1, 0); - TeamFortress_Alias("reload2", TF_RELOAD_SLOT2, 0); - TeamFortress_Alias("reload3", TF_RELOAD_SLOT3, 0); - TeamFortress_Alias("reloadnext", TF_RELOAD_NEXT, 0); - } else if (self.motd == 70) { - TeamFortress_Alias("grenswitch", TF_GRENADE_SWITCH, 0); - TeamFortress_Alias("-gren1", TF_GRENADE_T, 0); - TeamFortress_Alias("-gren2", TF_GRENADE_T, 0); - TeamFortress_Alias("throwgren", TF_GRENADE_T, 0); - TeamFortress_Alias("primeone", TF_GRENADE_1, 0); - TeamFortress_Alias("primetwo", TF_GRENADE_2, 0); - TeamFortress_Alias("+gren1", TF_GRENADE_1, 0); - TeamFortress_Alias("+gren2", TF_GRENADE_2, 0); - TeamFortress_Alias("gren1", TF_GRENADE_PT_1, 0); - TeamFortress_Alias("gren2", TF_GRENADE_PT_2, 0); - } else if (self.motd == 80) { - TeamFortress_Alias("dash", TF_DASH, 0); - TeamFortress_Alias("autoscan", TF_SCAN, 0); - TeamFortress_Alias("scansound", TF_SCAN_SOUND, 0); - TeamFortress_Alias("scanf", TF_SCAN_FRIENDLY, 0); - TeamFortress_Alias("scane", TF_SCAN_ENEMY, 0); - TeamFortress_Alias("zoomtoggle", TF_ZOOMTOGGLE, 0); - TeamFortress_Alias("zoomin", TF_ZOOMIN, 0); - TeamFortress_Alias("zoomout", TF_ZOOMOUT, 0); - } else if (self.motd == 90) { - TeamFortress_Alias("detpipe", TF_PB_DETONATE, 0); - TeamFortress_Alias("+det5", TF_DETPACK_5, 0); - TeamFortress_Alias("-det5", TF_DETPACK_STOP, 0); - TeamFortress_Alias("+det20", TF_DETPACK_20, 0); - TeamFortress_Alias("-det20", TF_DETPACK_STOP, 0); - TeamFortress_Alias("+det50", TF_DETPACK_50, 0); - TeamFortress_Alias("-det50", TF_DETPACK_STOP, 0); - TeamFortress_Alias("+det255", TF_DETPACK, 255); - TeamFortress_Alias("-det255", TF_DETPACK_STOP, 0); - } else if (self.motd == 100) { - TeamFortress_Alias("aura", TF_MEDIC_AURA_TOGGLE, 0); - TeamFortress_Alias("locktoggle", TF_HVYWEAP_LOCK_TOGGLE, 0); - TeamFortress_Alias("lock", TF_LOCKON, 0); - TeamFortress_Alias("unlock", TF_LOCKOFF, 0); - TeamFortress_Alias("+lock", TF_LOCKON, 0); - TeamFortress_Alias("-lock", TF_LOCKOFF, 0); - TeamFortress_Alias("airblast", TF_AIRBLAST, 0); - if(csqcactive) { - TeamFortress_AliasString("disguise", "fo_menu_disguise"); - } else { - TeamFortress_Alias("disguise", TF_SPY_SPY, 0); - } - TeamFortress_Alias("+feign", TF_SPY_DIE_ON, 0); - TeamFortress_Alias("-feign", TF_SPY_DIE_OFF, 0); - TeamFortress_Alias("feign", TF_SPY_DIE, 0); - TeamFortress_Alias("sfeign", TF_SPY_SILENT_DIE, 0); - } else if (self.motd == 110) { - TeamFortress_Alias("dreset", TF_DISGUISE_RESET, 0); - TeamFortress_Alias("dscout", TF_DISGUISE_SCOUT, 0); - TeamFortress_Alias("dsniper", TF_DISGUISE_SNIPER, 0); - TeamFortress_Alias("dsoldier", TF_DISGUISE_SOLDIER, 0); - TeamFortress_Alias("ddemoman", TF_DISGUISE_DEMOMAN, 0); - TeamFortress_Alias("dmedic", TF_DISGUISE_MEDIC, 0); - TeamFortress_Alias("dhwguy", TF_DISGUISE_HWGUY, 0); - TeamFortress_Alias("dpyro", TF_DISGUISE_PYRO, 0); - } else if (self.motd == 120) { - TeamFortress_Alias("dengineer", TF_DISGUISE_ENGINEER, 0); - TeamFortress_Alias("dblue", TF_DISGUISE_BLUE, 0); - TeamFortress_Alias("dred", TF_DISGUISE_RED, 0); - TeamFortress_Alias("dyellow", TF_DISGUISE_YELLOW, 0); - TeamFortress_Alias("dgreen", TF_DISGUISE_GREEN, 0); - TeamFortress_Alias("denemy", TF_DISGUISE_ENEMY, 0); - TeamFortress_Alias("dlast", TF_DISGUISE_LAST, 0); - TeamFortress_Alias("dlastspawn", TF_DISGUISE_LAST_SPAWNED, 0); - if(csqcactive) { - TeamFortress_AliasString("build", "fo_menu_build"); - } else { - TeamFortress_Alias("build", TF_ENGINEER_BUILD, 0); - } - TeamFortress_Alias("detsentry", TF_ENGINEER_DETSENTRY, 0); - TeamFortress_Alias("detdispenser", TF_ENGINEER_DETDISP, 0); - TeamFortress_Alias("toggledispenser", TF_ENGINEER_TOGGLEDISPENSER, 0); - TeamFortress_Alias("togglesentry", TF_ENGINEER_TOGGLESENTRY, 0); - } else if (self.motd == 130) { - stuffcmd(self, "is_aliased\n"); - TeamFortress_Alias ("ready", TF_PLAYER_READY, 0); - TeamFortress_Alias ("notready", TF_PLAYER_NOT_READY, 0); - TeamFortress_Alias ("nginfo", TF_NAILGREN_INFO, 0); //nailgreninfo - TeamFortress_AliasString("break", "cmd break"); - TeamFortress_AliasString("voteyes", "cmd voteyes"); - TeamFortress_AliasString("yes", "cmd voteyes"); - TeamFortress_AliasString("fo_settings_status", "cmd fo_settings_status"); - TeamFortress_Alias("placepracspawn", TF_PRACSPAWN_PLACE, 0); - TeamFortress_Alias("removepracspawn", TF_PRACSPAWN_REMOVE, 0); - } else if (self.motd == 140) { - Quick_Aliases(); - } else if (self.motd == 400 && self.team_no == 0 && !csqcactive) { - if (loginRequired && !self.login) - Menu_Login(); + if (alias->nocsqc_cmd) + TeamFortress_AliasString(alias->alias, alias->nocsqc_cmd); + else if (alias->nocsqc_impulse) + TeamFortress_Alias(alias->alias, alias->nocsqc_impulse, 0); + else if (alias->impulse) + TeamFortress_Alias(alias->alias, alias->impulse, 0); else - Menu_Team(1); + TeamFortress_AliasString(alias->alias, alias->cmd); } - self.motd = self.motd + 1; + if (idx < client_aliases.length) + self.motd += 1; + else + self.motd = -1; }; void () TeamFortress_HelpMap = { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 99380711..b5e199e3 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -88,7 +88,6 @@ void () fadefromwhite; void (entity disp) Engineer_UseDispenser; void (entity gun) Engineer_UseSentryGun; -void () TeamFortress_MOTD; void () TeamFortress_HelpMap; void () TeamFortress_NailGrenInfo; @@ -2294,10 +2293,6 @@ void () DeadImpulses = { } } Status_Refresh(self); - } else if (self.impulse == TF_ALIAS_CHECK) { - sprint(self, PRINT_HIGH, "Aliases checked\n"); - self.got_aliases = 1; - self.impulse = 0; } if (self.impulse == TF_PLAYER_READY) { if (clanbattle == 1) { From 18ba2c0405afd5397a7c7d20260e3c47a7a858fa Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 14 Aug 2023 18:41:16 +1000 Subject: [PATCH 2120/2474] Use fo_login for stats --- ssqc/events.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/events.qc b/ssqc/events.qc index 404470ec..4090fec9 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -29,6 +29,8 @@ string () ISOTimemillis = { string (entity pl) getEntityNameOrLogin = { if (loginRequired) return pl.login; + else if (fo_login_required) + return pl.fo_login; else return clearString(pl.netname); } From efa6ee3078b85bbc61f227f82819e7992591bdf1 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 14 Aug 2023 20:05:34 -0700 Subject: [PATCH 2121/2474] client: bind csqc buttons directly Currently we interpose on a variety of alias-like commands (e.g. +grenade1) only to directly translate them back to a command. Just replace these with a direct bind and save the round-trips into CSQC. --- csqc/main.qc | 83 ++++------------------------------------------------ share/defs.h | 14 ++++++++- 2 files changed, 19 insertions(+), 78 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 01877e6b..f0568585 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -63,9 +63,14 @@ static void BindAlias(TFAlias* tfa) { } static void SetupAliases() { - for (float i = 0; i < client_aliases.length; i++) + float i; + + for (i = 0; i < client_aliases.length; i++) BindAlias(&client_aliases[i]); + for (i = 0; i < csqc_aliases.length; i++) + BindAlias(&csqc_aliases[i]); + print("Aliases set\n"); } @@ -123,30 +128,11 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("+aux_jump"); registercommand("-aux_jump"); - registercommand("+special"); - registercommand("-special"); - registercommand("+special2"); - registercommand("-special2"); - registercommand("+grenade1"); - registercommand("-grenade1"); - registercommand("+grenade2"); - registercommand("-grenade2"); - registercommand("+dropflag"); - registercommand("-dropflag"); registercommand("+rj"); registercommand("-rj"); registercommand("slot_a"); - // registercommand("+quick1"); - // registercommand("-quick1"); - // registercommand("+quick2"); - // registercommand("-quick2"); - // registercommand("+quick3"); - // registercommand("-quick3"); - // registercommand("+quick4"); - // registercommand("-quick4"); - registercommand("tracktarget"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); registercommand("fo_settings_check"); @@ -406,9 +392,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Show_Scores(FALSE); } break; - case "tracktarget": - localcmd("cmd tracktarget\n"); - break; case "+aux_jump": jump_counter++; localcmd("+jump\n"); @@ -425,60 +408,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { } break; - case "+special": - localcmd("+button3\n"); - break; - case "-special": - localcmd("-button3\n"); - break; - case "+special2": - localcmd("+button4\n"); - break; - case "-special2": - localcmd("-button4\n"); - break; - case "+grenade1": - localcmd("+button5\n"); - break; - case "-grenade1": - localcmd("-button5\n"); - break; - case "+grenade2": - localcmd("+button6\n"); - break; - case "-grenade2": - localcmd("-button6\n"); - break; - case "+dropflag": - localcmd("+button7\n"); - break; - case "-dropflag": - localcmd("-button7\n"); - break; - // case "+quick1": - // localcmd("+button8\n"); - // break; - // case "-quick1": - // localcmd("-button8\n"); - // break; - // case "+quick2": - // localcmd("+button9\n"); - // break; - // case "-quick2": - // localcmd("-button9\n"); - // break; - // case "+quick3": - // localcmd("+button10\n"); - // break; - // case "-quick3": - // localcmd("-button10\n"); - // break; - // case "+quick4": - // localcmd("+button11\n"); - // break; - // case "-quick4": - // localcmd("-button11\n"); - // break; case "+rj": if (player_class == PC_SOLDIER || player_class == PC_PYRO) { localcmd("+button4\n"); diff --git a/share/defs.h b/share/defs.h index 3a1a5ae9..d2d45042 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1690,6 +1690,18 @@ TFAlias client_aliases[] = { {"fo_settings_status", 0, "cmd fo_settings_status"}, {"placepracspawn", TF_PRACSPAWN_PLACE}, {"removepracspawn", TF_PRACSPAWN_REMOVE}, - {"tracktarget", 0, "", 0, "cmd track target"}, + {"tracktarget", 0, "cmd tracktarget", 0, "cmd track target"}, }; +TFAlias csqc_aliases[] = { + {"+special", 0, "+button3"}, + {"-special", 0, "-button3"}, + {"+special2", 0, "+button4"}, + {"-special2", 0, "-button4"}, + {"+grenade1", 0, "+button5"}, + {"-grenade1", 0, "-button5"}, + {"+grenade2", 0, "+button6"}, + {"-grenade2", 0, "-button6"}, + {"+dropflag", 0, "+button7"}, + {"-dropflag", 0, "-button7"}, +}; From 3aece0b70dc26d9c56e6f6d034f7d03c4c045b71 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 15 Aug 2023 21:22:55 -0700 Subject: [PATCH 2122/2474] init: fix missing new line The first client_alias bind was being swallowed because there was an partially constructed command in the buffer it was being appended to. --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index f0568585..3df8cadc 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -769,7 +769,7 @@ void Perf_Status() { } void ClientSettings_Check() { - localcmd("cl_movespeedkey 1"); + localcmd("cl_movespeedkey 1\n"); if (cvar("worker_count") == 0) printf("ERROR: Please set `worker_count 4` to reduce stuttering!\n"); if (cvar("r_temporalscenecache") == 0) From b300e1acff1e87043be957ea2fc44cf773b795cf Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 18 Aug 2023 00:22:04 +1000 Subject: [PATCH 2123/2474] Add -Ono-cf compile flag --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 7c49e420..7f63a520 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +# New variable for compile flags +CFLAGS := -Ono-cf + ifndef VER VER := $(shell ./version.sh --version) endif @@ -7,9 +10,9 @@ ifndef REV endif all: - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./ssqc/progs.src - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./csqc/csprogs.src - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./menu/menu.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" $(CFLAGS) ./ssqc/progs.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" $(CFLAGS) ./csqc/csprogs.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" $(CFLAGS) ./menu/menu.src clean: rm -f $(TARGET) qwprogs.lno files.dat progdefs.h From c543e02d145f381d396ee453fbc0b65fd382b115 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Aug 2023 23:24:46 +1000 Subject: [PATCH 2124/2474] Better team color crosshair --- menu/options_audio.qc | 15 +++++++------ menu/options_basic.qc | 3 --- ssqc/spect.qc | 3 +++ ssqc/tforttm.qc | 52 +++++++++++++++++-------------------------- 4 files changed, 32 insertions(+), 41 deletions(-) diff --git a/menu/options_audio.qc b/menu/options_audio.qc index cfd7dcee..02a6e969 100644 --- a/menu/options_audio.qc +++ b/menu/options_audio.qc @@ -22,13 +22,14 @@ nonstatic void(mitem_desktop desktop) M_Options_Audio = //add the options fr.add(spawn(mitem_text, item_text:_("Restart Sound"), item_command:"snd_restart", item_scale:8, item_flags:IF_RIGHTALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [0, pos], [-8, 8]); pos += 8; pos += 8; - fr.add(menuitemcombo_spawn(_("Sound Device"), "s_device", '280 8', cvar_string("_s_device_opts")), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Master Volume"), "volume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Ambient Volume"),"ambient_level", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Self Volume"), "s_localvolume", '0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Music Volume"), "bgmvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn(_("Sound Device"), "s_device", '280 8', cvar_string("_s_device_opts")), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Master Volume"), "volume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Jump Volume"), "fo_jumpvolume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Ambient Volume"),"ambient_level", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Self Volume"), "s_localvolume", '0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Music Volume"), "bgmvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Channels"), "s_numspeakers", '1 6 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcombo_spawn(_("Audio Quality"), "s_khz", '280 8', _( + fr.add(menuitemcombo_spawn(_("Audio Quality"), "s_khz", '280 8', _( "11025 \"11025hz (vanilla quake)\" " "22050 \"22050hz\" " "44100 \"44100hz (cd quality)\" " @@ -71,4 +72,4 @@ nonstatic void(mitem_desktop desktop) M_Options_Audio = fr.add(menuitemslider_spawn(_("Opus bitrate"), "cl_voip_bitrate", '0.5 128 0.5','280 8'), fl, [0, pos], [0, 8]); pos += 8; addmenuback(m); -}; \ No newline at end of file +}; diff --git a/menu/options_basic.qc b/menu/options_basic.qc index b4c2c6f1..597381f1 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -191,9 +191,6 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ - fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; /* fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( */ /* "0 \"None\" " */ diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 24367707..164454af 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -15,6 +15,9 @@ void () SpectatorThink; void () Admin_Aliases; void () SpectatorConnect = { + if (FO_GetUserSetting(self, "team_color_crosshair", "tcc", "off")) + stuffcmd(self, "crosshaircolor 0xffffff\n"); + SetDimensions(TRUE); local string st; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 7de4e16e..a9f87813 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -180,37 +180,6 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options return 0; } - if (TeamFortress_TeamGetColor(tno) == 0 && !teamplay) { - TeamFortress_TeamSetColor(tno); - if (TeamFortress_TeamGetColor(tno) == 0) { - sprint(pe, PRINT_HIGH, - "You cannot start a new team with your color, since another "); - sprint(pe, PRINT_HIGH, - "already using that color. Change your pants color, then try again.\n"); - return (0); - } - bprint(PRINT_HIGH, pe.netname, " has started the "); - bprint(PRINT_HIGH, team, "\n"); - pe.immune_to_check = time + 10; - if ((toggleflags & TFLAG_TEAMFRAGS) || - (toggleflags & TFLAG_FULLTEAMSCORE)) { - pe.frags = TeamFortress_TeamGetScore(tno); - } - stuffcmd(pe, "color "); - tc = TeamFortress_TeamGetColor(tno) - 1; - st = ftos(tc); - stuffcmd(pe, st); - stuffcmd(pe, "\n"); - pe.team_no = tno; - pe.lives = TeamFortress_TeamGetLives(tno); - SetTeamName(pe); - if (pe.playerclass == 0) { - if (TeamFortress_TeamIsCivilian(pe.team_no)) { - TeamFortress_ChangeClass(11); - } - } - return (1); - } if (!pe.deadflag) { if (pe.health == pe.max_health && (pe.spawn_time + 10) > time && CloseToSpawnPoint() && pe.suicide_time <= time) { pe.has_changedteam = 1; @@ -291,6 +260,27 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options forceinfokey(pe, "team_no", ftos(tno)); UpdateReadyStatus(); + if (FO_GetUserSetting(pe, "team_color_crosshair", "tcc", "off")) { + string team_color = "0xffffff"; + + switch (tno) { + case 1: + team_color = "0x0066ff"; + break; + case 2: + team_color = "0xff0000"; + break; + case 3: + team_color = "0xffff00"; + break; + case 4: + team_color = "0x00ff00"; + break; + } + + stuffcmd(pe, "crosshaircolor ", team_color, "\n"); + } + return (1); }; From 9722bef7db88403268d3e6f4c4137cd7d5cea081 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 19 Aug 2023 23:33:37 +1000 Subject: [PATCH 2125/2474] Update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b6a7f34f..da2f9583 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FortressOne Server New commands ------------ +* `team_color_crosshair` change crosshair to team colour * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon * `fo_default_weapon 0` default weapon when using `+slot` binds From 38ecc1c4be7820edb22e56f9aa8a0142e1784db0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 20 Aug 2023 17:12:40 +1000 Subject: [PATCH 2126/2474] Use pragma instead of command line for optimisation flags --- Makefile | 9 +++------ ssqc/progs.src | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7f63a520..7c49e420 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,3 @@ -# New variable for compile flags -CFLAGS := -Ono-cf - ifndef VER VER := $(shell ./version.sh --version) endif @@ -10,9 +7,9 @@ ifndef REV endif all: - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" $(CFLAGS) ./ssqc/progs.src - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" $(CFLAGS) ./csqc/csprogs.src - fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" $(CFLAGS) ./menu/menu.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./ssqc/progs.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./csqc/csprogs.src + fteqcc64 -DVER=\"$(VER)\" -DREV=\"$(REV)\" ./menu/menu.src clean: rm -f $(TARGET) qwprogs.lno files.dat progdefs.h diff --git a/ssqc/progs.src b/ssqc/progs.src index 9d483a10..9c02b67f 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -1,4 +1,5 @@ #pragma target fte_5768 +#pragma optimise no-cf #pragma optimise 3 #pragma flag enable subscope #pragma flag enable iffloat From 37fdedc926f6ba66404f6c4367973ff192b36a6c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 21 Aug 2023 01:55:39 +1000 Subject: [PATCH 2127/2474] Give indication of relaoding --- README.md | 4 ++++ share/common_helpers.qc | 2 ++ share/prediction.qc | 2 -- share/weapons.qc | 8 ++++++-- ssqc/weapons.qc | 19 ++++++++++++++++--- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b6a7f34f..4e117c2a 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ FortressOne Server New commands ------------ +* `setinfo reloadvolume 0` volume for reloading sounds +* `cmd updateserver` tell server to pull latest progs and maps +* `cmd updateserver` tell server to pull latest progs and maps +* `cmd updateserver` tell server to pull latest progs and maps * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon * `fo_default_weapon 0` default weapon when using `+slot` binds diff --git a/share/common_helpers.qc b/share/common_helpers.qc index 66a063a3..50d60c87 100644 --- a/share/common_helpers.qc +++ b/share/common_helpers.qc @@ -23,3 +23,5 @@ string TeamToString(float num) if (num == 4) return "Green"; return " "; } + +void FO_Sound(entity e, float chan, string samp, float vol, float atten); diff --git a/share/prediction.qc b/share/prediction.qc index 6f4b1d6b..eca3a120 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -782,8 +782,6 @@ void FO_CustomPhysics() { } while (1); } -void FO_Sound(entity e, float chan, string samp, float vol, float atten); - void Pred_Sound(SoundIndex snd, float vol = 1) { if (snd == SND_NONE) return; diff --git a/share/weapons.qc b/share/weapons.qc index a0ed2d8b..ca878331 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -497,6 +497,8 @@ void (float att_delay) Attack_Finished; void W_UpdateCurrentWeapon(entity pl); void sprint_pred(entity client, float msglevel, string s); +float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; + void FO_ReloadFrame() { if (self.tfstate & TFSTATE_RELOADING == 0) return; @@ -504,11 +506,13 @@ void FO_ReloadFrame() { FO_WeapState ws; FO_FillWeapState(self, self.current_slot, &ws); FO_WeapInfo* wi = ws.wi; + local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); - if (self.client_time >= self.reload_finished) { + if (self.reload_finished && (self.client_time >= self.reload_finished)) { self.tfstate &= ~TFSTATE_RELOADING; W_UpdateCurrentWeapon(self); self.last_still_loading = 0; + FO_Sound(self, CHAN_WEAPON, "weapons/pkup.wav", reloadvolume, ATTN_NORM); Status_Refresh(self); sprint_pred(self, PRINT_HIGH, "Finished reloading\n"); @@ -522,6 +526,7 @@ void FO_ReloadFrame() { self.reload_finished); if (self.last_still_loading != still_loading) { self.last_still_loading = still_loading; + FO_Sound(self, CHAN_WEAPON, "weapons/pkup.wav", reloadvolume, ATTN_NORM); Status_Refresh(self); } } @@ -643,7 +648,6 @@ Slot FO_ImpulseToSlot(float playerclass, float impulse) { #ifdef SSQC float IsUsingOldImpulses(); -float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; static float IsPyroSlotSwapped() { return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index b5e199e3..1cede42a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1569,10 +1569,23 @@ void W_UpdateWeaponModel(entity pl) { FO_FillWeapState(pl, pl.current_slot, &ws); FO_WeapInfo* wi = ws.wi; - if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) + local float ra = FO_GetUserSetting(pl, "reloadalpha", "ra", "0"); + + if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) { pl.weaponmodel = (wi->models)->model; - else - pl.weaponmodel = ""; + + if (ra) { + local float ra_ready = FO_GetUserSetting(pl, "reloadalphaready", "rard", "1"); + stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_ready)); + } + } else { + if (ra) { + local float ra_reloading = FO_GetUserSetting(pl, "reloadalphareloading", "rarl", "0.3"); + stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_reloading)); + } else { + pl.weaponmodel = ""; + } + } } void (entity pl) W_UpdateCurrentWeapon = { From 3e7cee87715d95148696e328047fa63fa4d80807 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 21 Aug 2023 02:12:20 +1000 Subject: [PATCH 2128/2474] Add reload indicator options to menu --- menu/options_audio.qc | 3 ++- menu/options_basic.qc | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/menu/options_audio.qc b/menu/options_audio.qc index cfd7dcee..6fd5018e 100644 --- a/menu/options_audio.qc +++ b/menu/options_audio.qc @@ -24,6 +24,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Audio = pos += 8; fr.add(menuitemcombo_spawn(_("Sound Device"), "s_device", '280 8', cvar_string("_s_device_opts")), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Master Volume"), "volume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Reload Volume"), "reloadvolume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Ambient Volume"),"ambient_level", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Self Volume"), "s_localvolume", '0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Music Volume"), "bgmvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; @@ -71,4 +72,4 @@ nonstatic void(mitem_desktop desktop) M_Options_Audio = fr.add(menuitemslider_spawn(_("Opus bitrate"), "cl_voip_bitrate", '0.5 128 0.5','280 8'), fl, [0, pos], [0, 8]); pos += 8; addmenuback(m); -}; \ No newline at end of file +}; diff --git a/menu/options_basic.qc b/menu/options_basic.qc index b4c2c6f1..ec750a83 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -116,11 +116,13 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = //fr.add(menuitemcolour_spawn(_("Upper Colour"), "topcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; //fr.add(menuitemcolour_spawn(_("Lower Colour"), "bottomcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; /*aka: arse colour*/ pos += 8; - fr.add(menuitemcheck_spawn (_("Always Run"), "cl_run", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + /* fr.add(menuitemcheck_spawn (_("Always Run"), "cl_run", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ fr.add(menuitemcheck_spawn (_("Invert Mouse"), "m_pitchsign", '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Sensitivity"), "sensitivity", '3 20 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Fov"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Viewmodel Fov"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("FOV"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Weapon FOV"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Weapon Alpha"), "reloadalphaready", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Reloading Alpha"), "reloadalphareloading", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'-0.2 0.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; From c9b25197a351d15520a138474548192cfec63bc0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 21 Aug 2023 02:24:41 +1000 Subject: [PATCH 2129/2474] Fix readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4e117c2a..e3cad2f9 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ FortressOne Server New commands ------------ -* `setinfo reloadvolume 0` volume for reloading sounds -* `cmd updateserver` tell server to pull latest progs and maps -* `cmd updateserver` tell server to pull latest progs and maps -* `cmd updateserver` tell server to pull latest progs and maps +* `setinfo reloadvolume 0` 0 - 1 volume for reloading sounds +* `setinfo reloadalpha 0` enable visible view weapon while reloading +* `setinfo reloadalphaready 1` view weapon alpha when not reloading +* `setinfo reloadalphareloading 0.3` view weapon alpha when reloading * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon * `fo_default_weapon 0` default weapon when using `+slot` binds From 253e41a78af557cbdb1fb4ab1ae912c0b34ac66b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 23 Aug 2023 00:09:20 +1000 Subject: [PATCH 2130/2474] Support weapon predicition in for reload sounds / alpha --- csqc/weapon_predict.qc | 44 +++++++++++++++++++++++++++++++++-------- share/common_helpers.qc | 8 ++++++++ share/commondefs.qc | 6 ++++++ share/prediction.qc | 5 ++--- share/weapons.qc | 15 +++++++++++--- ssqc/weapons.qc | 5 +++-- 6 files changed, 67 insertions(+), 16 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 1cec49c7..7725e739 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -12,6 +12,12 @@ DEFCVAR_FLOAT(wpp_adv_selfp_ms, 0); DEFCVAR_FLOAT(wpp_adv_otherp_ms, 0); DEFCVAR_FLOAT(wpp_setspeed, 1); +DEFCVAR_FLOAT(r_drawviewmodel, 1); +DEFCVAR_FLOAT(reloadalpha, 0); +DEFCVAR_FLOAT(reloadalphaready, 1); +DEFCVAR_FLOAT(reloadalphareloading, 0.3); +DEFCVAR_FLOAT(reloadvolume, 1); + struct pengine_t { float pp_enabled; float wp_enabled; @@ -30,6 +36,7 @@ struct pengine_t { static float inst_ping_ms; static float inst_ping_t; +static float last_still_loading; inline float PP_Enabled() { return pengine.pp_enabled; } inline float WP_Enabled() { return pengine.wp_enabled; } @@ -543,16 +550,16 @@ inline FO_WeapInfo* WP_CurrentWeapon() { return SlotWI(CurrentSlot()); } -void RawPred_Sound(SoundIndex snd, float vol = 1) { +void RawPred_Sound(SoundIndex snd, float channel, float vol = 1) { if (snd == SND_NONE || pstate_pred.tfstate & TFSTATE_FLASHED) return; - localsound(Snd_Get(snd)->sound, CHAN_WEAPON, vol); + localsound(Snd_Get(snd)->sound, channel, vol); } void Pred_Sound(SoundIndex snd, float vol = 1) { if (IsEffectFrame()) - RawPred_Sound(snd, vol); + RawPred_Sound(snd, CHAN_WEAPON, vol); } void PredProj_Sound(int proj_type, float vol = 1) { @@ -826,6 +833,7 @@ void WP_Impulse() { HandleButtonThrowgren(1, BUTTON5); HandleButtonThrowgren(2, BUTTON6); + // TODO: is this blocking a /ready while reloading? if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) return; @@ -915,6 +923,14 @@ string WP_GetClip() { still_loading = FO_NumClipStillLoading(wi, pstate_pred.client_time, pstate_pred.reload_finished); + if (last_still_loading != still_loading) { + last_still_loading = still_loading; + + if (still_loading) { + RawPred_Sound(SND_RELOAD, CHAN_AUTO, CVARF(reloadvolume)); + } + } + float clip = capacity - fired - still_loading; float rem = WP_GetAmmo(wi->ammo_type); @@ -1672,7 +1688,7 @@ void InitProjectileEnt(float sendflags) { // on effect frames here as this isn't predicted; stronger: if we missed // the sound we probably missed an effect frame! if (!has_predicted) - RawPred_Sound(FPP_Get(self.fpp.index)->snd); + RawPred_Sound(FPP_Get(self.fpp.index)->snd, CHAN_WEAPON); } if (!has_predicted) { @@ -1683,8 +1699,6 @@ void InitProjectileEnt(float sendflags) { } } -DEFCVAR_FLOAT(r_drawviewmodel, 1); - void WP_UpdateViewModel() { entity viewmodel = pengine.viewmodel; float pmodelindex, pframe; @@ -1700,13 +1714,27 @@ void WP_UpdateViewModel() { pengine.view_mask &= ~MASK_VIEWMODEL; } - static float no_weap_mask = TFSTATE_NO_WEAPON | TFSTATE_RELOADING | TFSTATE_FLASHED; + static float no_weap_mask = TFSTATE_NO_WEAPON | TFSTATE_FLASHED; if (pstate_pred.tfstate & no_weap_mask || CVARF(r_drawviewmodel) == 0) { viewmodel.modelindex = 0; return; } - viewmodel.alpha = CVARF(r_drawviewmodel); + if (pstate_pred.tfstate & TFSTATE_RELOADING) { + if (CVARF(reloadalpha)) { + viewmodel.alpha = CVARF(reloadalphareloading); + } else { + viewmodel.modelindex = 0; + } + return; + } + + if (CVARF(reloadalpha)) { + viewmodel.alpha = CVARF(reloadalphaready); + } else { + viewmodel.alpha = CVARF(r_drawviewmodel); + } + pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; diff --git a/share/common_helpers.qc b/share/common_helpers.qc index 50d60c87..b2d0b55e 100644 --- a/share/common_helpers.qc +++ b/share/common_helpers.qc @@ -25,3 +25,11 @@ string TeamToString(float num) } void FO_Sound(entity e, float chan, string samp, float vol, float atten); + +#ifdef SSQC + +inline float ClientPred_Enabled(entity client, float pred_flag) { + return infokeyf(client, "fo_wpp_status") & pred_flag; +} + +#endif diff --git a/share/commondefs.qc b/share/commondefs.qc index 9170e333..2328283f 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -289,3 +289,9 @@ enumflags { HITFLAG_KILLEDUNDERCOVERSPY, }; +enumflags { + CSQC_WEAP_PRED, + CSQC_PROJ_PRED, + CSQC_SETSPEED, + CSQC_SNIPER_SIGHT, +}; diff --git a/share/prediction.qc b/share/prediction.qc index eca3a120..c2fd12c7 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -100,6 +100,7 @@ enum SoundIndex:float { SND_ASSCAN_FIRE, SND_ASSCAN_DOWN, SND_ASSCAN_SPIN, + SND_RELOAD }; struct fo_predsnd { @@ -124,6 +125,7 @@ static fo_predsnd snd_types[] = { { SND_ASSCAN_FIRE, "asscan2.wav" }, { SND_ASSCAN_DOWN, "asscan3.wav" }, { SND_ASSCAN_SPIN, "asscan4.wav" }, + { SND_RELOAD, "pkup.wav" } }; enum { @@ -284,9 +286,6 @@ float FO_MaxRewindGrenWinDt() { .predict_tf_state predict_state; .entity predict_entity; -inline float ClientPred_Enabled(entity client, float pred_flag) { - return infokeyf(client, "fo_wpp_status") & pred_flag; -} #else predict_tf_state pstate_pred, pstate_server; diff --git a/share/weapons.qc b/share/weapons.qc index ca878331..0ff0419a 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -506,13 +506,11 @@ void FO_ReloadFrame() { FO_WeapState ws; FO_FillWeapState(self, self.current_slot, &ws); FO_WeapInfo* wi = ws.wi; - local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); if (self.reload_finished && (self.client_time >= self.reload_finished)) { self.tfstate &= ~TFSTATE_RELOADING; W_UpdateCurrentWeapon(self); self.last_still_loading = 0; - FO_Sound(self, CHAN_WEAPON, "weapons/pkup.wav", reloadvolume, ATTN_NORM); Status_Refresh(self); sprint_pred(self, PRINT_HIGH, "Finished reloading\n"); @@ -524,9 +522,15 @@ void FO_ReloadFrame() { float still_loading = FO_NumClipStillLoading(wi, self.client_time, self.reload_finished); + if (self.last_still_loading != still_loading) { self.last_still_loading = still_loading; - FO_Sound(self, CHAN_WEAPON, "weapons/pkup.wav", reloadvolume, ATTN_NORM); + + if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) { + local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); + FO_Sound(self, CHAN_AUTO, "weapons/pkup.wav", reloadvolume, ATTN_NORM); + } + Status_Refresh(self); } } @@ -566,6 +570,11 @@ void FO_ReloadSlot(Slot slot, float force) { sprint_pred(self, PRINT_HIGH, strcat("Reloading ", FO_GetWeapName(ws->weapon), "...\n")); + if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) { + local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); + FO_Sound(self, CHAN_AUTO, "weapons/pkup.wav", reloadvolume, ATTN_NORM); + } + Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. self.tfstate |= TFSTATE_RELOADING; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1cede42a..b97d2fad 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1570,16 +1570,17 @@ void W_UpdateWeaponModel(entity pl) { FO_WeapInfo* wi = ws.wi; local float ra = FO_GetUserSetting(pl, "reloadalpha", "ra", "0"); + local float wp_enabled = ClientPred_Enabled(pl, CSQC_WEAP_PRED); if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) { pl.weaponmodel = (wi->models)->model; - if (ra) { + if (ra && !wp_enabled) { local float ra_ready = FO_GetUserSetting(pl, "reloadalphaready", "rard", "1"); stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_ready)); } } else { - if (ra) { + if (ra && !wp_enabled) { local float ra_reloading = FO_GetUserSetting(pl, "reloadalphareloading", "rarl", "0.3"); stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_reloading)); } else { From 15e4c77dd8ec4d757eb8b0c6f52de9f3e79f6452 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 23 Aug 2023 00:14:24 +1000 Subject: [PATCH 2131/2474] off is more idiomatic than 0 for binary options --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index b97d2fad..f8e8d214 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1569,7 +1569,7 @@ void W_UpdateWeaponModel(entity pl) { FO_FillWeapState(pl, pl.current_slot, &ws); FO_WeapInfo* wi = ws.wi; - local float ra = FO_GetUserSetting(pl, "reloadalpha", "ra", "0"); + local float ra = FO_GetUserSetting(pl, "reloadalpha", "ra", "off"); local float wp_enabled = ClientPred_Enabled(pl, CSQC_WEAP_PRED); if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) { From 2944bfe03e717ee8721e4b58e42374bf54993da1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 25 Aug 2023 01:16:34 +1000 Subject: [PATCH 2132/2474] Do team_color_crosshair on client side --- csqc/csextradefs.qc | 1 + csqc/main.qc | 29 ++++++++++++++++++++++++++++- csqc/settings.qc | 1 + ssqc/spect.qc | 3 --- ssqc/tforttm.qc | 22 ---------------------- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9b8691d6..aea94556 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -857,6 +857,7 @@ DEFCVAR_FLOAT(fo_legacy_sbar, 0); DEFCVAR_FLOAT(fo_csjumpsounds, 1); float team_no; +float crosshair_team_no; float all_time; float is_spectator; float player_class; diff --git a/csqc/main.qc b/csqc/main.qc index 3df8cadc..49256ae4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -181,6 +181,7 @@ noref void() CSQC_WorldLoaded = { void FO_CussView(); void FO_CussCrosshair(float width, float height); void Hud_UpdateView(float width, float height, float menushown, float perf_sample); +void UpdateTeamColorCrosshair(); DEFCVAR_FLOAT(fov, 90); @@ -207,6 +208,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); FO_CussCrosshair(width, height); + UpdateTeamColorCrosshair(); + TFxRenderGrenadeTimers(); RenderHitTexts(); Hud_UpdateView(width, height, menushown, fts); @@ -580,6 +583,31 @@ static void FO_CussCrosshair(float width, float height) { p_x - width / 2, CVARF(fo_crossy) + p_y - height / 2)); } +static void UpdateTeamColorCrosshair() { + if (!CVARF(team_color_crosshair)) + return; + + if (crosshair_team_no == team_no) + return; + + string crosshair_color = "0xffffff"; + switch (team_no) { + case 1: + crosshair_color = "0x0066ff"; + break; + case 2: + crosshair_color = "0xff0000"; + break; + case 3: + crosshair_color = "0xffff00"; + break; + case 4: + crosshair_color = "0x00ff00"; + } + localcmd("crosshaircolor ", crosshair_color, "\n"); + crosshair_team_no = team_no; +} + void FO_ApplyCussInput() { if (!IsFoConced()) return; @@ -657,7 +685,6 @@ void _Sync_ServerCommandFrame() { if (is_spectator) is_observer = FALSE; is_player = (!is_spectator && !is_observer); - if (!is_player || getstatf(STAT_HEALTH) <= 0) is_alive = 0; else diff --git a/csqc/settings.qc b/csqc/settings.qc index 56a628ce..68697827 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,6 +3,7 @@ DEFCVAR_STRING(fo_grentimersound, "grentimer.wav"); DEFCVAR_FLOAT(fo_grentimervolume, 1); DEFCVAR_FLOAT(fo_oldscoreboard, 0); DEFCVAR_FLOAT(fo_default_weapon, 0); +DEFCVAR_FLOAT(team_color_crosshair, 0); DEFCVAR_FLOAT(fo_hitaudio_enabled, 1); DEFCVAR_FLOAT(fo_hitaudio_hurtself, 1); diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 164454af..24367707 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -15,9 +15,6 @@ void () SpectatorThink; void () Admin_Aliases; void () SpectatorConnect = { - if (FO_GetUserSetting(self, "team_color_crosshair", "tcc", "off")) - stuffcmd(self, "crosshaircolor 0xffffff\n"); - SetDimensions(TRUE); local string st; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index a9f87813..b73e83cd 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -259,28 +259,6 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options forceinfokey(pe, "team_no", ftos(tno)); UpdateReadyStatus(); - - if (FO_GetUserSetting(pe, "team_color_crosshair", "tcc", "off")) { - string team_color = "0xffffff"; - - switch (tno) { - case 1: - team_color = "0x0066ff"; - break; - case 2: - team_color = "0xff0000"; - break; - case 3: - team_color = "0xffff00"; - break; - case 4: - team_color = "0x00ff00"; - break; - } - - stuffcmd(pe, "crosshaircolor ", team_color, "\n"); - } - return (1); }; From 3f7f0745c8f5d632e91518efcd984272d30a232b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 25 Aug 2023 01:55:16 +1000 Subject: [PATCH 2133/2474] Default reloadvolume to 0 --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 7725e739..094d0f2e 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -16,7 +16,7 @@ DEFCVAR_FLOAT(r_drawviewmodel, 1); DEFCVAR_FLOAT(reloadalpha, 0); DEFCVAR_FLOAT(reloadalphaready, 1); DEFCVAR_FLOAT(reloadalphareloading, 0.3); -DEFCVAR_FLOAT(reloadvolume, 1); +DEFCVAR_FLOAT(reloadvolume, 0); struct pengine_t { float pp_enabled; From 723b3df6ca3bf97f2beb58bd51f3a9fdba83f1d1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 25 Aug 2023 02:21:50 +1000 Subject: [PATCH 2134/2474] reloadvolume userinfo and autocvars aren't synced unless set reloadvolume in config --- csqc/weapon_predict.qc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 094d0f2e..cae85562 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -16,7 +16,7 @@ DEFCVAR_FLOAT(r_drawviewmodel, 1); DEFCVAR_FLOAT(reloadalpha, 0); DEFCVAR_FLOAT(reloadalphaready, 1); DEFCVAR_FLOAT(reloadalphareloading, 0.3); -DEFCVAR_FLOAT(reloadvolume, 0); +/* DEFCVAR_FLOAT(reloadvolume, 0); */ struct pengine_t { float pp_enabled; @@ -927,7 +927,8 @@ string WP_GetClip() { last_still_loading = still_loading; if (still_loading) { - RawPred_Sound(SND_RELOAD, CHAN_AUTO, CVARF(reloadvolume)); + local float reloadvolume = getplayerkeyfloat(player_localnum, "reloadvolume", 0); + RawPred_Sound(SND_RELOAD, CHAN_AUTO, reloadvolume); } } From ad16e04fb82ea20b3375b68f51a5bdc62480e3ba Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 25 Aug 2023 03:49:49 +1000 Subject: [PATCH 2135/2474] Only run UpdateTeamColorCrosshair when new server frame received --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 49256ae4..890b8f15 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -208,7 +208,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { renderscene(); FO_CussCrosshair(width, height); - UpdateTeamColorCrosshair(); TFxRenderGrenadeTimers(); RenderHitTexts(); @@ -697,6 +696,7 @@ void _Sync_ServerCommandFrame() { WP_UpdatePings(); CsGrenTimer::UpdateSoundStack(); + UpdateTeamColorCrosshair(); } From 8a61e2ce1e60cb08e22a2b2c44c793467eaebc63 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 26 Aug 2023 22:28:37 +1000 Subject: [PATCH 2136/2474] Weapon specific reload sounds - client side --- csqc/weapon_predict.qc | 20 +++++++++++++++++++- share/prediction.qc | 12 ++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index cae85562..14461f54 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -928,7 +928,25 @@ string WP_GetClip() { if (still_loading) { local float reloadvolume = getplayerkeyfloat(player_localnum, "reloadvolume", 0); - RawPred_Sound(SND_RELOAD, CHAN_AUTO, reloadvolume); + local float sample; + switch (WP_CurrentWeapon()->weapon) { + case WEAP_ROCKET_LAUNCHER: + sample = SND_RELOAD_ROCKET; + break; + case WEAP_GRENADE_LAUNCHER: + case WEAP_PIPE_LAUNCHER: + sample = SND_RELOAD_GREN; + break; + case WEAP_SHOTGUN: + sample = SND_RELOAD_SHOTGUN; + break; + case WEAP_SUPER_SHOTGUN: + sample = SND_RELOAD_SUPER_SHOTGUN; + break; + case WEAP_ASSAULT_CANNON: + sample = SND_RELOAD_ASSAULT_CANNON; + } + RawPred_Sound(sample, CHAN_AUTO, reloadvolume); } } diff --git a/share/prediction.qc b/share/prediction.qc index c2fd12c7..8a5e6d8e 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -100,7 +100,11 @@ enum SoundIndex:float { SND_ASSCAN_FIRE, SND_ASSCAN_DOWN, SND_ASSCAN_SPIN, - SND_RELOAD + SND_RELOAD_GREN, + SND_RELOAD_ROCKET, + SND_RELOAD_SHOTGUN, + SND_RELOAD_SUPER_SHOTGUN, + SND_RELOAD_ASSAULT_CANNON }; struct fo_predsnd { @@ -125,7 +129,11 @@ static fo_predsnd snd_types[] = { { SND_ASSCAN_FIRE, "asscan2.wav" }, { SND_ASSCAN_DOWN, "asscan3.wav" }, { SND_ASSCAN_SPIN, "asscan4.wav" }, - { SND_RELOAD, "pkup.wav" } + { SND_RELOAD_GREN, "reload_gren.wav" }, + { SND_RELOAD_ROCKET, "reload_rocket.wav" }, + { SND_RELOAD_SHOTGUN, "reload_shotgun.wav" }, + { SND_RELOAD_SUPER_SHOTGUN, "reload_super_shotgun.wav" }, + { SND_RELOAD_ASSAULT_CANNON, "reload_assault_cannon.wav" }, }; enum { From 66c548f03d451a92dd30634e57e517a14453fba1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 26 Aug 2023 22:51:34 +1000 Subject: [PATCH 2137/2474] Weapon specific reload sounds - server side --- share/weapons.qc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/share/weapons.qc b/share/weapons.qc index 0ff0419a..285cf1f8 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -528,7 +528,26 @@ void FO_ReloadFrame() { if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) { local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); - FO_Sound(self, CHAN_AUTO, "weapons/pkup.wav", reloadvolume, ATTN_NORM); + local string sample; + + switch (FO_CurrentWeapon()) { + case WEAP_ROCKET_LAUNCHER: + sample = "weapons/reload_rocket.wav"; + break; + case WEAP_GRENADE_LAUNCHER: + case WEAP_PIPE_LAUNCHER: + sample = "weapons/reload_gren.wav"; + break; + case WEAP_SHOTGUN: + sample = "weapons/reload_shotgun.wav"; + break; + case WEAP_SUPER_SHOTGUN: + sample = "weapons/reload_super_shotgun.wav"; + break; + case WEAP_ASSAULT_CANNON: + sample = "weapons/reload_assault_cannon.wav"; + } + FO_Sound(self, CHAN_AUTO, sample, reloadvolume, ATTN_NORM); } Status_Refresh(self); From 0dfa5997c97ae95f7acfd41046c25a15781d79c7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 27 Aug 2023 00:14:48 +1000 Subject: [PATCH 2138/2474] Refactor --- share/weapons.qc | 55 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/share/weapons.qc b/share/weapons.qc index 285cf1f8..1d37954f 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -499,6 +499,30 @@ void sprint_pred(entity client, float msglevel, string s); float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; +void FO_ReloadSound() { + local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); + local string sample; + + switch (FO_CurrentWeapon()) { + case WEAP_ROCKET_LAUNCHER: + sample = "weapons/reload_rocket.wav"; + break; + case WEAP_GRENADE_LAUNCHER: + case WEAP_PIPE_LAUNCHER: + sample = "weapons/reload_gren.wav"; + break; + case WEAP_SHOTGUN: + sample = "weapons/reload_shotgun.wav"; + break; + case WEAP_SUPER_SHOTGUN: + sample = "weapons/reload_super_shotgun.wav"; + break; + case WEAP_ASSAULT_CANNON: + sample = "weapons/reload_assault_cannon.wav"; + } + FO_Sound(self, CHAN_AUTO, sample, reloadvolume, ATTN_NORM); +} + void FO_ReloadFrame() { if (self.tfstate & TFSTATE_RELOADING == 0) return; @@ -526,29 +550,8 @@ void FO_ReloadFrame() { if (self.last_still_loading != still_loading) { self.last_still_loading = still_loading; - if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) { - local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); - local string sample; - - switch (FO_CurrentWeapon()) { - case WEAP_ROCKET_LAUNCHER: - sample = "weapons/reload_rocket.wav"; - break; - case WEAP_GRENADE_LAUNCHER: - case WEAP_PIPE_LAUNCHER: - sample = "weapons/reload_gren.wav"; - break; - case WEAP_SHOTGUN: - sample = "weapons/reload_shotgun.wav"; - break; - case WEAP_SUPER_SHOTGUN: - sample = "weapons/reload_super_shotgun.wav"; - break; - case WEAP_ASSAULT_CANNON: - sample = "weapons/reload_assault_cannon.wav"; - } - FO_Sound(self, CHAN_AUTO, sample, reloadvolume, ATTN_NORM); - } + if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) + FO_ReloadSound(); Status_Refresh(self); } @@ -589,10 +592,8 @@ void FO_ReloadSlot(Slot slot, float force) { sprint_pred(self, PRINT_HIGH, strcat("Reloading ", FO_GetWeapName(ws->weapon), "...\n")); - if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) { - local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); - FO_Sound(self, CHAN_AUTO, "weapons/pkup.wav", reloadvolume, ATTN_NORM); - } + if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) + FO_ReloadSound(); Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. From 85d262f006bc3c88c948e10a3054a654bf1f797b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 27 Aug 2023 01:27:09 +1000 Subject: [PATCH 2139/2474] Allow readying while reloading --- ssqc/weapons.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index b5e199e3..6c2b0d72 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2635,6 +2635,8 @@ void () W_WeaponFrame = { case TF_SPY_DIE_ON: case TF_SPY_DIE_OFF: case TF_SPY_SILENT_DIE: + case TF_PLAYER_READY: + case TF_PLAYER_NOT_READY: ImpulseCommands(); return; // allows setting detpack while reloading on toggle, defaults to off From 4f8c64e752e6263581d162f6b2523e3500b406b9 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 28 Aug 2023 13:27:16 +1000 Subject: [PATCH 2140/2474] Update progs.src don't have level 3 optimise write over our no-cf directive --- ssqc/progs.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/progs.src b/ssqc/progs.src index 9c02b67f..33cf1839 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -1,6 +1,6 @@ #pragma target fte_5768 -#pragma optimise no-cf #pragma optimise 3 +#pragma optimise no-cf #pragma flag enable subscope #pragma flag enable iffloat #pragma flag enable lo From fd26cfaccca01eb3eb76b9e9363519db22243f7d Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Aug 2023 11:18:58 -0700 Subject: [PATCH 2141/2474] wp: converge to fo_reloadalpha There was an explosion of reloadalpha variables that was slightly confusing and collided with existing features (e.g. fractional r_drawviewmodel fov). Replace these {reloadalpha, reloadalphareloading, reloadalphaready} with a single cvar, fo_reloadalpha which only controls alpha when reloading and is purely client-side. Remove server-side bits. --- README.md | 4 +- csqc/weapon_predict.qc | 16 +- menu/options_basic.qc | 460 ++++++++++++++++++++--------------------- ssqc/weapons.qc | 20 +- 4 files changed, 239 insertions(+), 261 deletions(-) diff --git a/README.md b/README.md index 68646749..08459978 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,7 @@ New commands * `team_color_crosshair` change crosshair to team colour * `setinfo reloadvolume 0` 0 - 1 volume for reloading sounds -* `setinfo reloadalpha 0` enable visible view weapon while reloading -* `setinfo reloadalphaready 1` view weapon alpha when not reloading -* `setinfo reloadalphareloading 0.3` view weapon alpha when reloading +* `fo_reloadalpha x` alpha of viewmodel when reloading, 0 for invisible * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon * `fo_default_weapon 0` default weapon when using `+slot` binds diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 14461f54..d0b4f16c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -13,9 +13,7 @@ DEFCVAR_FLOAT(wpp_adv_otherp_ms, 0); DEFCVAR_FLOAT(wpp_setspeed, 1); DEFCVAR_FLOAT(r_drawviewmodel, 1); -DEFCVAR_FLOAT(reloadalpha, 0); -DEFCVAR_FLOAT(reloadalphaready, 1); -DEFCVAR_FLOAT(reloadalphareloading, 0.3); +DEFCVAR_FLOAT(fo_reloadalpha, 0); /* DEFCVAR_FLOAT(reloadvolume, 0); */ struct pengine_t { @@ -1740,16 +1738,12 @@ void WP_UpdateViewModel() { } if (pstate_pred.tfstate & TFSTATE_RELOADING) { - if (CVARF(reloadalpha)) { - viewmodel.alpha = CVARF(reloadalphareloading); - } else { + float ra = CVARF(fo_reloadalpha); + if (ra > 0) + viewmodel.alpha = ra; + else viewmodel.modelindex = 0; - } return; - } - - if (CVARF(reloadalpha)) { - viewmodel.alpha = CVARF(reloadalphaready); } else { viewmodel.alpha = CVARF(r_drawviewmodel); } diff --git a/menu/options_basic.qc b/menu/options_basic.qc index f4ac5d64..bd2741ca 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -1,230 +1,230 @@ -class mitem_playerpreview : mitem_spinnymodel -{ -#if 1//defined(FTE_QC_CUSTOMSKINS) - virtual void(vector pos) item_draw = - { - //if you wanted to get more advanced, you could use q3 skins here. - if (cvar("noskins")) - setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\n\n", cvar_string("topcolor"), cvar_string("bottomcolor"))); - else if (cvar_string("cl_teamskin") != "") - setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("cl_teamskin"))); - else - setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("skin"))); - - super::item_draw(pos); - }; -#endif -}; - -static string() skinopts = -{ - string opts = ""; - float s = search_begin("skins/*.pcx", TRUE, TRUE); - if (s < 0) - return opts; - float n = search_getsize(s); - for (float i = 0; i < n; i++) - { - string f = substring(search_getfilename(s, i), 6, -5); - opts = strcat(opts, "\"", f, "\" \"", f, "\" "); - } - return opts; -}; - -var float autocvar_m_pitch = 0.022; -class options_basic : mitem_exmenu -{ - virtual float(string key) isvalid = - { - if (key == "m_pitchsign") - return TRUE; - if (key == "cl_run") - return TRUE; - return super::isvalid(key); - }; - virtual string(string key) get = - { - if (key == "m_pitchsign") - return (autocvar_m_pitch<0)?"1":"0"; - if (key == "cl_run") - return (stof(super::get("cl_forwardspeed")) > 200)?"1":"0"; - //if (key == "fo_grentimer") - // return getplayerkeyvalue(player_localnum, "nt"); - return super::get(key); - }; - virtual void(string key, string newval) set = - { - if (key == "m_pitchsign") - { - float invert; - if (stof(newval)) - invert = autocvar_m_pitch > 0; - else - invert = autocvar_m_pitch < 0; - if (invert) - cvar_set("m_pitch", ftos(-autocvar_m_pitch)); - } - else if (key == "cl_run") - { - float setbackspeed = (super::get("cl_backspeed") != ""); - if (stof(newval)) - { - super::set("cl_forwardspeed", "400"); - super::set("cl_sidespeed", "400"); - if (setbackspeed) - super::set("cl_backspeed", "400"); - super::set("cl_movespeedkey", "0.5"); //makes +speed act like +walk - } - else - { - //these are the defaults from winquake. - super::set("cl_forwardspeed", "200"); - super::set("cl_sidespeed", "350"); - if (setbackspeed) - super::set("cl_backspeed", "200"); - super::set("cl_movespeedkey", "2.0"); - } - } - else - super::set(key, newval); - }; -}; -nonstatic void(mitem_desktop desktop) M_Options_Basic = -{ - mitem_exmenu m; - m = spawn(options_basic, item_text:_("Basic Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); - desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); - desktop.item_focuschange(m, IF_KFOCUSED); - m.totop(); - - float h = 200 * 0.5; - //draw title art above the options - mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-160-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); - //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. - mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); - m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); - float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; - float pos = 0; - - - fr.add(menuitemeditt_spawn(_("Player Name"), dp("_cl_name", "name"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemeditt_spawn(_("Player Team"), "team", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemcombo_spawn(_("Player Skin"), "skin", '280 8', skinopts()), fl, [0, pos], [0, 8]); pos += 8; - - - //fr.add(menuitemcolour_spawn(_("Upper Colour"), "topcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemcolour_spawn(_("Lower Colour"), "bottomcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; /*aka: arse colour*/ - pos += 8; - /* fr.add(menuitemcheck_spawn (_("Always Run"), "cl_run", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ - fr.add(menuitemcheck_spawn (_("Invert Mouse"), "m_pitchsign", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Sensitivity"), "sensitivity", '3 20 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("FOV"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Weapon FOV"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Weapon Alpha"), "reloadalphaready", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Reloading Alpha"), "reloadalphareloading", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'-0.2 0.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - pos += 8; - fr.add( - spawn( - mitem_text, - item_text:strcat("^{e080} ^a","Crosshair","^d ^{e082}"), - item_command:"", - item_scale:8, - item_flags:IF_CENTERALIGN - ), - RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, - [0, pos], - [0, 8] - ); pos += 8; - pos += 8; - fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - pos += 8; - fr.add( - spawn( - mitem_text, - item_text:strcat("^{e080} ^a","Grenades","^d ^{e082}"), - item_command:"", - item_scale:8, - item_flags:IF_CENTERALIGN - ), - RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, - [0, pos], - [0, 8] - ); pos += 8; - pos += 8; - fr.add(menuitemcombo_spawn (_("Timer"), "fo_grentimer", '280 8', _( - "2 \"On\" " - "0 \"Silent\" " - )), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcombo_spawn (_("Sound"), "fo_grentimersound", '280 8', _( - "grentimer.wav \"Default\" " - "mcp_grentimer1.wav \"1\" " - "mcp_grentimer2.wav \"2\" " - "mcp_grentimer3.wav \"3\" " - "mcp_grentimer4.wav \"4\" " - "mcp_grentimer5.wav \"5\" " - "mcp_grentimer6.wav \"6\" " - "mcp_grentimer7.wav \"7\" " - "mcp_grentimer8.wav \"8\" " - "mcp_grentimer9.wav \"9\" " - "mcp_grentimer10.wav \"10\" " - "mcp_grentimer11.wav \"11\" " - "mcp_grentimer12.wav \"12\" " - "mcp_grentimer13.wav \"13\" " - "mcp_grentimer14.wav \"14\" " - "mcp_grentimer15.wav \"15\" " - "mcp_grentimer16.wav \"16\" " - "mcp_grentimer17.wav \"17\" " - "mcp_grentimer18.wav \"18\" " - "mcp_grentimer19.wav \"19\" " - "mcp_grentimer20.wav \"20\" " - "mcp_grentimer21.wav \"21\" " - "mcp_grentimer22.wav \"22\" " - "mcp_grentimer23.wav \"23\" " - "mcp_grentimer24.wav \"24\" " - "mcp_grentimer25.wav \"25\" " - "mcp_grentimer26.wav \"26\" " - )), fl, [0, pos], [0, 8]); pos += 8; - - - /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ - //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - /* fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( */ - /* "0 \"None\" " */ - /* "1 \"Server\" " */ - /* "2 \"Immediate\" " */ - /* )), fl, [0, pos], [0, 8]); pos += 8; */ - //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - - local string skin = "tf_sold"; - local float r = random(); - if(r > 0.89) - skin = "tf_scout"; - else if(r > 0.78) - skin = "tf_snipe"; - else if(r > 0.67) - skin = "tf_demo"; - else if(r > 0.56) - skin = "tf_medic"; - else if(r > 0.45) - skin = "tf_hwguy"; - else if(r > 0.34) - skin = "tf_pyro"; - else if(r > 0.23) - skin = "tf_spy"; - else if(r > 0.12) - skin = "tf_eng"; - - - //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); - m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', customskin:skin, rotatespeed:10, topcolour:0, bottomcolour:0), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); -// m.add(spawn (mitem_playerpreview, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 12*-16/2], [-40, 12*16/2]); - - addmenuback(m); -}; +class mitem_playerpreview : mitem_spinnymodel +{ +#if 1//defined(FTE_QC_CUSTOMSKINS) + virtual void(vector pos) item_draw = + { + //if you wanted to get more advanced, you could use q3 skins here. + if (cvar("noskins")) + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\n\n", cvar_string("topcolor"), cvar_string("bottomcolor"))); + else if (cvar_string("cl_teamskin") != "") + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("cl_teamskin"))); + else + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("skin"))); + + super::item_draw(pos); + }; +#endif +}; + +static string() skinopts = +{ + string opts = ""; + float s = search_begin("skins/*.pcx", TRUE, TRUE); + if (s < 0) + return opts; + float n = search_getsize(s); + for (float i = 0; i < n; i++) + { + string f = substring(search_getfilename(s, i), 6, -5); + opts = strcat(opts, "\"", f, "\" \"", f, "\" "); + } + return opts; +}; + +var float autocvar_m_pitch = 0.022; +class options_basic : mitem_exmenu +{ + virtual float(string key) isvalid = + { + if (key == "m_pitchsign") + return TRUE; + if (key == "cl_run") + return TRUE; + return super::isvalid(key); + }; + virtual string(string key) get = + { + if (key == "m_pitchsign") + return (autocvar_m_pitch<0)?"1":"0"; + if (key == "cl_run") + return (stof(super::get("cl_forwardspeed")) > 200)?"1":"0"; + //if (key == "fo_grentimer") + // return getplayerkeyvalue(player_localnum, "nt"); + return super::get(key); + }; + virtual void(string key, string newval) set = + { + if (key == "m_pitchsign") + { + float invert; + if (stof(newval)) + invert = autocvar_m_pitch > 0; + else + invert = autocvar_m_pitch < 0; + if (invert) + cvar_set("m_pitch", ftos(-autocvar_m_pitch)); + } + else if (key == "cl_run") + { + float setbackspeed = (super::get("cl_backspeed") != ""); + if (stof(newval)) + { + super::set("cl_forwardspeed", "400"); + super::set("cl_sidespeed", "400"); + if (setbackspeed) + super::set("cl_backspeed", "400"); + super::set("cl_movespeedkey", "0.5"); //makes +speed act like +walk + } + else + { + //these are the defaults from winquake. + super::set("cl_forwardspeed", "200"); + super::set("cl_sidespeed", "350"); + if (setbackspeed) + super::set("cl_backspeed", "200"); + super::set("cl_movespeedkey", "2.0"); + } + } + else + super::set(key, newval); + }; +}; +nonstatic void(mitem_desktop desktop) M_Options_Basic = +{ + mitem_exmenu m; + m = spawn(options_basic, item_text:_("Basic Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-160-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + float pos = 0; + + + fr.add(menuitemeditt_spawn(_("Player Name"), dp("_cl_name", "name"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemeditt_spawn(_("Player Team"), "team", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemcombo_spawn(_("Player Skin"), "skin", '280 8', skinopts()), fl, [0, pos], [0, 8]); pos += 8; + + + //fr.add(menuitemcolour_spawn(_("Upper Colour"), "topcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemcolour_spawn(_("Lower Colour"), "bottomcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; /*aka: arse colour*/ + pos += 8; + /* fr.add(menuitemcheck_spawn (_("Always Run"), "cl_run", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ + fr.add(menuitemcheck_spawn (_("Invert Mouse"), "m_pitchsign", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Sensitivity"), "sensitivity", '3 20 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("FOV"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Weapon FOV"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Weapon Alpha"), "r_drawviewmodel", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Reloading Alpha"), "fo_reloadalpha", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'-0.2 0.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + pos += 8; + fr.add( + spawn( + mitem_text, + item_text:strcat("^{e080} ^a","Crosshair","^d ^{e082}"), + item_command:"", + item_scale:8, + item_flags:IF_CENTERALIGN + ), + RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, + [0, pos], + [0, 8] + ); pos += 8; + pos += 8; + fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + pos += 8; + fr.add( + spawn( + mitem_text, + item_text:strcat("^{e080} ^a","Grenades","^d ^{e082}"), + item_command:"", + item_scale:8, + item_flags:IF_CENTERALIGN + ), + RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, + [0, pos], + [0, 8] + ); pos += 8; + pos += 8; + fr.add(menuitemcombo_spawn (_("Timer"), "fo_grentimer", '280 8', _( + "2 \"On\" " + "0 \"Silent\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn (_("Sound"), "fo_grentimersound", '280 8', _( + "grentimer.wav \"Default\" " + "mcp_grentimer1.wav \"1\" " + "mcp_grentimer2.wav \"2\" " + "mcp_grentimer3.wav \"3\" " + "mcp_grentimer4.wav \"4\" " + "mcp_grentimer5.wav \"5\" " + "mcp_grentimer6.wav \"6\" " + "mcp_grentimer7.wav \"7\" " + "mcp_grentimer8.wav \"8\" " + "mcp_grentimer9.wav \"9\" " + "mcp_grentimer10.wav \"10\" " + "mcp_grentimer11.wav \"11\" " + "mcp_grentimer12.wav \"12\" " + "mcp_grentimer13.wav \"13\" " + "mcp_grentimer14.wav \"14\" " + "mcp_grentimer15.wav \"15\" " + "mcp_grentimer16.wav \"16\" " + "mcp_grentimer17.wav \"17\" " + "mcp_grentimer18.wav \"18\" " + "mcp_grentimer19.wav \"19\" " + "mcp_grentimer20.wav \"20\" " + "mcp_grentimer21.wav \"21\" " + "mcp_grentimer22.wav \"22\" " + "mcp_grentimer23.wav \"23\" " + "mcp_grentimer24.wav \"24\" " + "mcp_grentimer25.wav \"25\" " + "mcp_grentimer26.wav \"26\" " + )), fl, [0, pos], [0, 8]); pos += 8; + + + /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ + //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + /* fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( */ + /* "0 \"None\" " */ + /* "1 \"Server\" " */ + /* "2 \"Immediate\" " */ + /* )), fl, [0, pos], [0, 8]); pos += 8; */ + //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + + local string skin = "tf_sold"; + local float r = random(); + if(r > 0.89) + skin = "tf_scout"; + else if(r > 0.78) + skin = "tf_snipe"; + else if(r > 0.67) + skin = "tf_demo"; + else if(r > 0.56) + skin = "tf_medic"; + else if(r > 0.45) + skin = "tf_hwguy"; + else if(r > 0.34) + skin = "tf_pyro"; + else if(r > 0.23) + skin = "tf_spy"; + else if(r > 0.12) + skin = "tf_eng"; + + + //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); + m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', customskin:skin, rotatespeed:10, topcolour:0, bottomcolour:0), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); +// m.add(spawn (mitem_playerpreview, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 12*-16/2], [-40, 12*16/2]); + + addmenuback(m); +}; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 98b21102..6c2b0d72 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1569,24 +1569,10 @@ void W_UpdateWeaponModel(entity pl) { FO_FillWeapState(pl, pl.current_slot, &ws); FO_WeapInfo* wi = ws.wi; - local float ra = FO_GetUserSetting(pl, "reloadalpha", "ra", "off"); - local float wp_enabled = ClientPred_Enabled(pl, CSQC_WEAP_PRED); - - if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) { + if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) pl.weaponmodel = (wi->models)->model; - - if (ra && !wp_enabled) { - local float ra_ready = FO_GetUserSetting(pl, "reloadalphaready", "rard", "1"); - stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_ready)); - } - } else { - if (ra && !wp_enabled) { - local float ra_reloading = FO_GetUserSetting(pl, "reloadalphareloading", "rarl", "0.3"); - stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_reloading)); - } else { - pl.weaponmodel = ""; - } - } + else + pl.weaponmodel = ""; } void (entity pl) W_UpdateCurrentWeapon = { From 4fd279c2c37922aa0fd6b8fb28ab771ae1b04073 Mon Sep 17 00:00:00 2001 From: lordee Date: Mon, 28 Aug 2023 13:27:16 +1000 Subject: [PATCH 2142/2474] Update progs.src don't have level 3 optimise write over our no-cf directive --- ssqc/progs.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/progs.src b/ssqc/progs.src index 9c02b67f..33cf1839 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -1,6 +1,6 @@ #pragma target fte_5768 -#pragma optimise no-cf #pragma optimise 3 +#pragma optimise no-cf #pragma flag enable subscope #pragma flag enable iffloat #pragma flag enable lo From ff41b7ad7d5beff12036c8748f9bbc0dbcc14eb9 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Aug 2023 11:18:58 -0700 Subject: [PATCH 2143/2474] wp: converge to fo_reloadalpha There was an explosion of reloadalpha variables that was slightly confusing and collided with existing features (e.g. fractional r_drawviewmodel fov). Replace these {reloadalpha, reloadalphareloading, reloadalphaready} with a single cvar, fo_reloadalpha which only controls alpha when reloading and is purely client-side. Remove server-side bits. --- README.md | 4 +- csqc/weapon_predict.qc | 16 +- menu/options_basic.qc | 463 ++++++++++++++++++++--------------------- ssqc/weapons.qc | 20 +- 4 files changed, 239 insertions(+), 264 deletions(-) diff --git a/README.md b/README.md index e3cad2f9..89d84092 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,7 @@ New commands ------------ * `setinfo reloadvolume 0` 0 - 1 volume for reloading sounds -* `setinfo reloadalpha 0` enable visible view weapon while reloading -* `setinfo reloadalphaready 1` view weapon alpha when not reloading -* `setinfo reloadalphareloading 0.3` view weapon alpha when reloading +* `fo_reloadalpha x` alpha of viewmodel when reloading, 0 for invisible * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon * `fo_default_weapon 0` default weapon when using `+slot` binds diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 14461f54..d0b4f16c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -13,9 +13,7 @@ DEFCVAR_FLOAT(wpp_adv_otherp_ms, 0); DEFCVAR_FLOAT(wpp_setspeed, 1); DEFCVAR_FLOAT(r_drawviewmodel, 1); -DEFCVAR_FLOAT(reloadalpha, 0); -DEFCVAR_FLOAT(reloadalphaready, 1); -DEFCVAR_FLOAT(reloadalphareloading, 0.3); +DEFCVAR_FLOAT(fo_reloadalpha, 0); /* DEFCVAR_FLOAT(reloadvolume, 0); */ struct pengine_t { @@ -1740,16 +1738,12 @@ void WP_UpdateViewModel() { } if (pstate_pred.tfstate & TFSTATE_RELOADING) { - if (CVARF(reloadalpha)) { - viewmodel.alpha = CVARF(reloadalphareloading); - } else { + float ra = CVARF(fo_reloadalpha); + if (ra > 0) + viewmodel.alpha = ra; + else viewmodel.modelindex = 0; - } return; - } - - if (CVARF(reloadalpha)) { - viewmodel.alpha = CVARF(reloadalphaready); } else { viewmodel.alpha = CVARF(r_drawviewmodel); } diff --git a/menu/options_basic.qc b/menu/options_basic.qc index ec750a83..bd2741ca 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -1,233 +1,230 @@ -class mitem_playerpreview : mitem_spinnymodel -{ -#if 1//defined(FTE_QC_CUSTOMSKINS) - virtual void(vector pos) item_draw = - { - //if you wanted to get more advanced, you could use q3 skins here. - if (cvar("noskins")) - setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\n\n", cvar_string("topcolor"), cvar_string("bottomcolor"))); - else if (cvar_string("cl_teamskin") != "") - setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("cl_teamskin"))); - else - setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("skin"))); - - super::item_draw(pos); - }; -#endif -}; - -static string() skinopts = -{ - string opts = ""; - float s = search_begin("skins/*.pcx", TRUE, TRUE); - if (s < 0) - return opts; - float n = search_getsize(s); - for (float i = 0; i < n; i++) - { - string f = substring(search_getfilename(s, i), 6, -5); - opts = strcat(opts, "\"", f, "\" \"", f, "\" "); - } - return opts; -}; - -var float autocvar_m_pitch = 0.022; -class options_basic : mitem_exmenu -{ - virtual float(string key) isvalid = - { - if (key == "m_pitchsign") - return TRUE; - if (key == "cl_run") - return TRUE; - return super::isvalid(key); - }; - virtual string(string key) get = - { - if (key == "m_pitchsign") - return (autocvar_m_pitch<0)?"1":"0"; - if (key == "cl_run") - return (stof(super::get("cl_forwardspeed")) > 200)?"1":"0"; - //if (key == "fo_grentimer") - // return getplayerkeyvalue(player_localnum, "nt"); - return super::get(key); - }; - virtual void(string key, string newval) set = - { - if (key == "m_pitchsign") - { - float invert; - if (stof(newval)) - invert = autocvar_m_pitch > 0; - else - invert = autocvar_m_pitch < 0; - if (invert) - cvar_set("m_pitch", ftos(-autocvar_m_pitch)); - } - else if (key == "cl_run") - { - float setbackspeed = (super::get("cl_backspeed") != ""); - if (stof(newval)) - { - super::set("cl_forwardspeed", "400"); - super::set("cl_sidespeed", "400"); - if (setbackspeed) - super::set("cl_backspeed", "400"); - super::set("cl_movespeedkey", "0.5"); //makes +speed act like +walk - } - else - { - //these are the defaults from winquake. - super::set("cl_forwardspeed", "200"); - super::set("cl_sidespeed", "350"); - if (setbackspeed) - super::set("cl_backspeed", "200"); - super::set("cl_movespeedkey", "2.0"); - } - } - else - super::set(key, newval); - }; -}; -nonstatic void(mitem_desktop desktop) M_Options_Basic = -{ - mitem_exmenu m; - m = spawn(options_basic, item_text:_("Basic Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); - desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); - desktop.item_focuschange(m, IF_KFOCUSED); - m.totop(); - - float h = 200 * 0.5; - //draw title art above the options - mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); - m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-160-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); - //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. - mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); - m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); - float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; - float pos = 0; - - - fr.add(menuitemeditt_spawn(_("Player Name"), dp("_cl_name", "name"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemeditt_spawn(_("Player Team"), "team", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemcombo_spawn(_("Player Skin"), "skin", '280 8', skinopts()), fl, [0, pos], [0, 8]); pos += 8; - - - //fr.add(menuitemcolour_spawn(_("Upper Colour"), "topcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemcolour_spawn(_("Lower Colour"), "bottomcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; /*aka: arse colour*/ - pos += 8; - /* fr.add(menuitemcheck_spawn (_("Always Run"), "cl_run", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ - fr.add(menuitemcheck_spawn (_("Invert Mouse"), "m_pitchsign", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Sensitivity"), "sensitivity", '3 20 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("FOV"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Weapon FOV"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Weapon Alpha"), "reloadalphaready", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Reloading Alpha"), "reloadalphareloading", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'-0.2 0.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - pos += 8; - fr.add( - spawn( - mitem_text, - item_text:strcat("^{e080} ^a","Crosshair","^d ^{e082}"), - item_command:"", - item_scale:8, - item_flags:IF_CENTERALIGN - ), - RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, - [0, pos], - [0, 8] - ); pos += 8; - pos += 8; - fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - pos += 8; - fr.add( - spawn( - mitem_text, - item_text:strcat("^{e080} ^a","Grenades","^d ^{e082}"), - item_command:"", - item_scale:8, - item_flags:IF_CENTERALIGN - ), - RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, - [0, pos], - [0, 8] - ); pos += 8; - pos += 8; - fr.add(menuitemcombo_spawn (_("Timer"), "fo_grentimer", '280 8', _( - "2 \"On\" " - "0 \"Silent\" " - )), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcombo_spawn (_("Sound"), "fo_grentimersound", '280 8', _( - "grentimer.wav \"Default\" " - "mcp_grentimer1.wav \"1\" " - "mcp_grentimer2.wav \"2\" " - "mcp_grentimer3.wav \"3\" " - "mcp_grentimer4.wav \"4\" " - "mcp_grentimer5.wav \"5\" " - "mcp_grentimer6.wav \"6\" " - "mcp_grentimer7.wav \"7\" " - "mcp_grentimer8.wav \"8\" " - "mcp_grentimer9.wav \"9\" " - "mcp_grentimer10.wav \"10\" " - "mcp_grentimer11.wav \"11\" " - "mcp_grentimer12.wav \"12\" " - "mcp_grentimer13.wav \"13\" " - "mcp_grentimer14.wav \"14\" " - "mcp_grentimer15.wav \"15\" " - "mcp_grentimer16.wav \"16\" " - "mcp_grentimer17.wav \"17\" " - "mcp_grentimer18.wav \"18\" " - "mcp_grentimer19.wav \"19\" " - "mcp_grentimer20.wav \"20\" " - "mcp_grentimer21.wav \"21\" " - "mcp_grentimer22.wav \"22\" " - "mcp_grentimer23.wav \"23\" " - "mcp_grentimer24.wav \"24\" " - "mcp_grentimer25.wav \"25\" " - "mcp_grentimer26.wav \"26\" " - )), fl, [0, pos], [0, 8]); pos += 8; - - - /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ - fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - /* fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( */ - /* "0 \"None\" " */ - /* "1 \"Server\" " */ - /* "2 \"Immediate\" " */ - /* )), fl, [0, pos], [0, 8]); pos += 8; */ - //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - - local string skin = "tf_sold"; - local float r = random(); - if(r > 0.89) - skin = "tf_scout"; - else if(r > 0.78) - skin = "tf_snipe"; - else if(r > 0.67) - skin = "tf_demo"; - else if(r > 0.56) - skin = "tf_medic"; - else if(r > 0.45) - skin = "tf_hwguy"; - else if(r > 0.34) - skin = "tf_pyro"; - else if(r > 0.23) - skin = "tf_spy"; - else if(r > 0.12) - skin = "tf_eng"; - - - //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); - m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', customskin:skin, rotatespeed:10, topcolour:0, bottomcolour:0), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); -// m.add(spawn (mitem_playerpreview, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 12*-16/2], [-40, 12*16/2]); - - addmenuback(m); -}; +class mitem_playerpreview : mitem_spinnymodel +{ +#if 1//defined(FTE_QC_CUSTOMSKINS) + virtual void(vector pos) item_draw = + { + //if you wanted to get more advanced, you could use q3 skins here. + if (cvar("noskins")) + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\n\n", cvar_string("topcolor"), cvar_string("bottomcolor"))); + else if (cvar_string("cl_teamskin") != "") + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("cl_teamskin"))); + else + setcustomskin(self, "", sprintf("q1upper \"%s\"\nq1lower \"%s\"\nqwskin \"%s\"\n", cvar_string("topcolor"), cvar_string("bottomcolor"), cvar_string("skin"))); + + super::item_draw(pos); + }; +#endif +}; + +static string() skinopts = +{ + string opts = ""; + float s = search_begin("skins/*.pcx", TRUE, TRUE); + if (s < 0) + return opts; + float n = search_getsize(s); + for (float i = 0; i < n; i++) + { + string f = substring(search_getfilename(s, i), 6, -5); + opts = strcat(opts, "\"", f, "\" \"", f, "\" "); + } + return opts; +}; + +var float autocvar_m_pitch = 0.022; +class options_basic : mitem_exmenu +{ + virtual float(string key) isvalid = + { + if (key == "m_pitchsign") + return TRUE; + if (key == "cl_run") + return TRUE; + return super::isvalid(key); + }; + virtual string(string key) get = + { + if (key == "m_pitchsign") + return (autocvar_m_pitch<0)?"1":"0"; + if (key == "cl_run") + return (stof(super::get("cl_forwardspeed")) > 200)?"1":"0"; + //if (key == "fo_grentimer") + // return getplayerkeyvalue(player_localnum, "nt"); + return super::get(key); + }; + virtual void(string key, string newval) set = + { + if (key == "m_pitchsign") + { + float invert; + if (stof(newval)) + invert = autocvar_m_pitch > 0; + else + invert = autocvar_m_pitch < 0; + if (invert) + cvar_set("m_pitch", ftos(-autocvar_m_pitch)); + } + else if (key == "cl_run") + { + float setbackspeed = (super::get("cl_backspeed") != ""); + if (stof(newval)) + { + super::set("cl_forwardspeed", "400"); + super::set("cl_sidespeed", "400"); + if (setbackspeed) + super::set("cl_backspeed", "400"); + super::set("cl_movespeedkey", "0.5"); //makes +speed act like +walk + } + else + { + //these are the defaults from winquake. + super::set("cl_forwardspeed", "200"); + super::set("cl_sidespeed", "350"); + if (setbackspeed) + super::set("cl_backspeed", "200"); + super::set("cl_movespeedkey", "2.0"); + } + } + else + super::set(key, newval); + }; +}; +nonstatic void(mitem_desktop desktop) M_Options_Basic = +{ + mitem_exmenu m; + m = spawn(options_basic, item_text:_("Basic Options"), item_flags:IF_SELECTABLE, item_command:"m_options"); + desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0'); + desktop.item_focuschange(m, IF_KFOCUSED); + m.totop(); + + float h = 200 * 0.5; + //draw title art above the options + mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN); + m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [(160-160-banner.item_size_x)*0.5, -h-32], [banner.item_size_x, -h-8]); + //spawn a container frame for the actual options. this provides a scrollbar if we have too many items. + mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE); + m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, -h], [160, h*2]); + float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN; + float pos = 0; + + + fr.add(menuitemeditt_spawn(_("Player Name"), dp("_cl_name", "name"), '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemeditt_spawn(_("Player Team"), "team", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemcombo_spawn(_("Player Skin"), "skin", '280 8', skinopts()), fl, [0, pos], [0, 8]); pos += 8; + + + //fr.add(menuitemcolour_spawn(_("Upper Colour"), "topcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemcolour_spawn(_("Lower Colour"), "bottomcolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; /*aka: arse colour*/ + pos += 8; + /* fr.add(menuitemcheck_spawn (_("Always Run"), "cl_run", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ + fr.add(menuitemcheck_spawn (_("Invert Mouse"), "m_pitchsign", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Sensitivity"), "sensitivity", '3 20 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("FOV"), "fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Weapon FOV"), "r_viewmodel_fov", '80 130 5', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Weapon Alpha"), "r_drawviewmodel", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Reloading Alpha"), "fo_reloadalpha", '0 1 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Gamma"), dp("v_gamma", "gamma"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Contrast"), dp("v_contrast", "contrast"), '0.8 1.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Brightness"), dp("v_brightness", "brightness"),'-0.2 0.2 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + pos += 8; + fr.add( + spawn( + mitem_text, + item_text:strcat("^{e080} ^a","Crosshair","^d ^{e082}"), + item_command:"", + item_scale:8, + item_flags:IF_CENTERALIGN + ), + RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, + [0, pos], + [0, 8] + ); pos += 8; + pos += 8; + fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + pos += 8; + fr.add( + spawn( + mitem_text, + item_text:strcat("^{e080} ^a","Grenades","^d ^{e082}"), + item_command:"", + item_scale:8, + item_flags:IF_CENTERALIGN + ), + RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, + [0, pos], + [0, 8] + ); pos += 8; + pos += 8; + fr.add(menuitemcombo_spawn (_("Timer"), "fo_grentimer", '280 8', _( + "2 \"On\" " + "0 \"Silent\" " + )), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcombo_spawn (_("Sound"), "fo_grentimersound", '280 8', _( + "grentimer.wav \"Default\" " + "mcp_grentimer1.wav \"1\" " + "mcp_grentimer2.wav \"2\" " + "mcp_grentimer3.wav \"3\" " + "mcp_grentimer4.wav \"4\" " + "mcp_grentimer5.wav \"5\" " + "mcp_grentimer6.wav \"6\" " + "mcp_grentimer7.wav \"7\" " + "mcp_grentimer8.wav \"8\" " + "mcp_grentimer9.wav \"9\" " + "mcp_grentimer10.wav \"10\" " + "mcp_grentimer11.wav \"11\" " + "mcp_grentimer12.wav \"12\" " + "mcp_grentimer13.wav \"13\" " + "mcp_grentimer14.wav \"14\" " + "mcp_grentimer15.wav \"15\" " + "mcp_grentimer16.wav \"16\" " + "mcp_grentimer17.wav \"17\" " + "mcp_grentimer18.wav \"18\" " + "mcp_grentimer19.wav \"19\" " + "mcp_grentimer20.wav \"20\" " + "mcp_grentimer21.wav \"21\" " + "mcp_grentimer22.wav \"22\" " + "mcp_grentimer23.wav \"23\" " + "mcp_grentimer24.wav \"24\" " + "mcp_grentimer25.wav \"25\" " + "mcp_grentimer26.wav \"26\" " + )), fl, [0, pos], [0, 8]); pos += 8; + + + /* fr.add(menuitemcheck_spawn (_("Simple Bunnyhop"), "fo_autohop", '280 8'), fl, [0, pos], [0, 8]); pos += 8; */ + //fr.add(menuitemcheck_spawn (_("Grenade Timer"), "fo_grentimer", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + /* fr.add(menuitemcombo_spawn (_("Grenade Timer"), "fo_grentimer", '280 8', _( */ + /* "0 \"None\" " */ + /* "1 \"Server\" " */ + /* "2 \"Immediate\" " */ + /* )), fl, [0, pos], [0, 8]); pos += 8; */ + //fr.add(menuitemslider_spawn(_("TF Status Bar"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + //fr.add(menuitemslider_spawn(_("TF Flag Info"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + + local string skin = "tf_sold"; + local float r = random(); + if(r > 0.89) + skin = "tf_scout"; + else if(r > 0.78) + skin = "tf_snipe"; + else if(r > 0.67) + skin = "tf_demo"; + else if(r > 0.56) + skin = "tf_medic"; + else if(r > 0.45) + skin = "tf_hwguy"; + else if(r > 0.34) + skin = "tf_pyro"; + else if(r > 0.23) + skin = "tf_spy"; + else if(r > 0.12) + skin = "tf_eng"; + + + //m.add(spawn (mitem_spinnymodel, item_text: it), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, 12*-16/2], [0, 12*16/2]); + m.add(spawn (mitem_spinnymodel, item_text: "progs/player.mdl", firstframe:12, framecount:5, shootframe:119, shootframes:6, dontrotate:1, startangle:'0 155 0', customskin:skin, rotatespeed:10, topcolour:0, bottomcolour:0), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-300, 16*-16/2], [-40, 16*16/2]); +// m.add(spawn (mitem_playerpreview, item_text: "progs/player.mdl", firstframe:0, framecount:6, shootframe:119, shootframes:6), RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-200, 12*-16/2], [-40, 12*16/2]); + + addmenuback(m); +}; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f8e8d214..b5e199e3 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1569,24 +1569,10 @@ void W_UpdateWeaponModel(entity pl) { FO_FillWeapState(pl, pl.current_slot, &ws); FO_WeapInfo* wi = ws.wi; - local float ra = FO_GetUserSetting(pl, "reloadalpha", "ra", "off"); - local float wp_enabled = ClientPred_Enabled(pl, CSQC_WEAP_PRED); - - if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) { + if (pl.tfstate & (TFSTATE_RELOADING | TFSTATE_NO_WEAPON) == 0) pl.weaponmodel = (wi->models)->model; - - if (ra && !wp_enabled) { - local float ra_ready = FO_GetUserSetting(pl, "reloadalphaready", "rard", "1"); - stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_ready)); - } - } else { - if (ra && !wp_enabled) { - local float ra_reloading = FO_GetUserSetting(pl, "reloadalphareloading", "rarl", "0.3"); - stuffcmd(pl, sprintf("r_drawviewmodel %f\n", ra_reloading)); - } else { - pl.weaponmodel = ""; - } - } + else + pl.weaponmodel = ""; } void (entity pl) W_UpdateCurrentWeapon = { From eb9e366d67c5af85f9b4a404109b281f34c45d55 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 30 Aug 2023 00:44:34 +1000 Subject: [PATCH 2144/2474] Don't have reload sounds in the world, remove setinfo --- README.md | 2 +- csqc/events.qc | 4 ++++ csqc/weapon_predict.qc | 53 ++++++++++++++++++++++++------------------ share/commondefs.qc | 3 ++- share/weapons.qc | 34 +++++---------------------- ssqc/status.qc | 11 +++++++++ 6 files changed, 54 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 89d84092..ac6a65d5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server New commands ------------ -* `setinfo reloadvolume 0` 0 - 1 volume for reloading sounds +* `reloadvolume 0` 0 - 1 volume for reloading sounds * `fo_reloadalpha x` alpha of viewmodel when reloading, 0 for invisible * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon diff --git a/csqc/events.qc b/csqc/events.qc index 55f2a73a..f345bfa1 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -352,6 +352,10 @@ void() CSQC_Parse_Event = { case MSG_UNPAUSE: CsGrenTimer::SyncUnpause(); break; + case MSG_RELOADSOUND: + local float weapon = readfloat(); + FO_ReloadSound(weapon); + break; } } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index d0b4f16c..43cb7061 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -14,7 +14,7 @@ DEFCVAR_FLOAT(wpp_setspeed, 1); DEFCVAR_FLOAT(r_drawviewmodel, 1); DEFCVAR_FLOAT(fo_reloadalpha, 0); -/* DEFCVAR_FLOAT(reloadvolume, 0); */ +DEFCVAR_FLOAT(reloadvolume, 0); struct pengine_t { float pp_enabled; @@ -591,6 +591,33 @@ static Slot InputToSlot(float input) { return result; } +void FO_ReloadSound(float weapon) { + local float reloadvolume = CVARF(reloadvolume); + + if (reloadvolume == 0) + return; + + local float sample = 0; + switch (WP_CurrentWeapon()->weapon) { + case WEAP_ROCKET_LAUNCHER: + sample = SND_RELOAD_ROCKET; + break; + case WEAP_GRENADE_LAUNCHER: + case WEAP_PIPE_LAUNCHER: + sample = SND_RELOAD_GREN; + break; + case WEAP_SHOTGUN: + sample = SND_RELOAD_SHOTGUN; + break; + case WEAP_SUPER_SHOTGUN: + sample = SND_RELOAD_SUPER_SHOTGUN; + break; + case WEAP_ASSAULT_CANNON: + sample = SND_RELOAD_ASSAULT_CANNON; + } + RawPred_Sound(sample, CHAN_AUTO, reloadvolume); +}; + inline float WP_IsReloading() { return pstate_pred.tfstate & TFSTATE_RELOADING; } @@ -924,28 +951,8 @@ string WP_GetClip() { if (last_still_loading != still_loading) { last_still_loading = still_loading; - if (still_loading) { - local float reloadvolume = getplayerkeyfloat(player_localnum, "reloadvolume", 0); - local float sample; - switch (WP_CurrentWeapon()->weapon) { - case WEAP_ROCKET_LAUNCHER: - sample = SND_RELOAD_ROCKET; - break; - case WEAP_GRENADE_LAUNCHER: - case WEAP_PIPE_LAUNCHER: - sample = SND_RELOAD_GREN; - break; - case WEAP_SHOTGUN: - sample = SND_RELOAD_SHOTGUN; - break; - case WEAP_SUPER_SHOTGUN: - sample = SND_RELOAD_SUPER_SHOTGUN; - break; - case WEAP_ASSAULT_CANNON: - sample = SND_RELOAD_ASSAULT_CANNON; - } - RawPred_Sound(sample, CHAN_AUTO, reloadvolume); - } + if (still_loading) + FO_ReloadSound(WP_CurrentWeapon()->weapon); } float clip = capacity - fired - still_loading; diff --git a/share/commondefs.qc b/share/commondefs.qc index 2328283f..32a85513 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -193,7 +193,6 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_SBAR 4 #define MSG_GRENPRIMED 5 - #define MSG_CLIENT_MENU 6 #define MSG_TEAMS_UPDATE 7 #define MSG_CLASSES_UPDATE 8 @@ -217,6 +216,8 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_QUAD_ROUND_BEGIN 26 #define MSG_LOGIN 27 #define MSG_HITFLAG 28 +#define MSG_RELOADSOUND 29 + #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 #define FLAGINFO_DROPPED 3 diff --git a/share/weapons.qc b/share/weapons.qc index 1d37954f..297fa049 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -498,29 +498,11 @@ void W_UpdateCurrentWeapon(entity pl); void sprint_pred(entity client, float msglevel, string s); float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; +void (entity pl, float weapon) UpdateClientReloadSound; void FO_ReloadSound() { - local float reloadvolume = FO_GetUserSetting(self, "reloadvolume", "rv", "0"); - local string sample; - - switch (FO_CurrentWeapon()) { - case WEAP_ROCKET_LAUNCHER: - sample = "weapons/reload_rocket.wav"; - break; - case WEAP_GRENADE_LAUNCHER: - case WEAP_PIPE_LAUNCHER: - sample = "weapons/reload_gren.wav"; - break; - case WEAP_SHOTGUN: - sample = "weapons/reload_shotgun.wav"; - break; - case WEAP_SUPER_SHOTGUN: - sample = "weapons/reload_super_shotgun.wav"; - break; - case WEAP_ASSAULT_CANNON: - sample = "weapons/reload_assault_cannon.wav"; - } - FO_Sound(self, CHAN_AUTO, sample, reloadvolume, ATTN_NORM); + if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) + UpdateClientReloadSound(self, FO_CurrentWeapon()); } void FO_ReloadFrame() { @@ -549,10 +531,7 @@ void FO_ReloadFrame() { if (self.last_still_loading != still_loading) { self.last_still_loading = still_loading; - - if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) - FO_ReloadSound(); - + FO_ReloadSound(); Status_Refresh(self); } } @@ -592,11 +571,10 @@ void FO_ReloadSlot(Slot slot, float force) { sprint_pred(self, PRINT_HIGH, strcat("Reloading ", FO_GetWeapName(ws->weapon), "...\n")); - if (!ClientPred_Enabled(self, CSQC_WEAP_PRED)) - FO_ReloadSound(); - Attack_Finished(wi->attack_time); // Carried.. but not sure it's necessary. + FO_ReloadSound(); + self.tfstate |= TFSTATE_RELOADING; Status_Refresh(self); diff --git a/ssqc/status.qc b/ssqc/status.qc index f692dd08..44fc6bee 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -778,6 +778,17 @@ static void TFxUpdateGrenadeTimer(entity player, float explodes_at) { multicast('0 0 0', MULTICAST_ALL_R); } +void UpdateClientReloadSound(entity pl, float weapon) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_RELOADSOUND); + WriteFloat(MSG_MULTICAST, weapon); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From aa6256be6b69be283d0585afc936df45e203dfd4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 30 Aug 2023 01:22:26 +1000 Subject: [PATCH 2145/2474] Rename reloadvolume command to fo_reloadvolume --- README.md | 3 ++- csqc/weapon_predict.qc | 4 ++-- menu/options_audio.qc | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ac6a65d5..b3727488 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ FortressOne Server New commands ------------ -* `reloadvolume 0` 0 - 1 volume for reloading sounds +* `team_color_crosshair` change crosshair to team colour +* `fo_reloadvolume 0` 0 - 1 volume for reloading sounds * `fo_reloadalpha x` alpha of viewmodel when reloading, 0 for invisible * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 43cb7061..b0967e4a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -14,7 +14,7 @@ DEFCVAR_FLOAT(wpp_setspeed, 1); DEFCVAR_FLOAT(r_drawviewmodel, 1); DEFCVAR_FLOAT(fo_reloadalpha, 0); -DEFCVAR_FLOAT(reloadvolume, 0); +DEFCVAR_FLOAT(fo_reloadvolume, 0); struct pengine_t { float pp_enabled; @@ -592,7 +592,7 @@ static Slot InputToSlot(float input) { } void FO_ReloadSound(float weapon) { - local float reloadvolume = CVARF(reloadvolume); + local float reloadvolume = CVARF(fo_reloadvolume); if (reloadvolume == 0) return; diff --git a/menu/options_audio.qc b/menu/options_audio.qc index 6fd5018e..bc69ee8e 100644 --- a/menu/options_audio.qc +++ b/menu/options_audio.qc @@ -24,7 +24,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Audio = pos += 8; fr.add(menuitemcombo_spawn(_("Sound Device"), "s_device", '280 8', cvar_string("_s_device_opts")), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Master Volume"), "volume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemslider_spawn(_("Reload Volume"), "reloadvolume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemslider_spawn(_("Reload Volume"), "fo_reloadvolume", '0.0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Ambient Volume"),"ambient_level", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Self Volume"), "s_localvolume", '0 1 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemslider_spawn(_("Music Volume"), "bgmvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8; From 435c906ce56c346b04728510c12252017931188d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 30 Aug 2023 01:26:31 +1000 Subject: [PATCH 2146/2474] Rename team_color_crosshair command to fo_team_color_crosshair --- README.md | 2 +- csqc/settings.qc | 2 +- menu/options_basic.qc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index da2f9583..94f078b5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FortressOne Server New commands ------------ -* `team_color_crosshair` change crosshair to team colour +* `fo_team_color_crosshair` change crosshair to team colour * `cmd updateserver` tell server to pull latest progs and maps * `+slot n` bind. fires nth weapon * `fo_default_weapon 0` default weapon when using `+slot` binds diff --git a/csqc/settings.qc b/csqc/settings.qc index 68697827..6f029b2c 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -3,7 +3,7 @@ DEFCVAR_STRING(fo_grentimersound, "grentimer.wav"); DEFCVAR_FLOAT(fo_grentimervolume, 1); DEFCVAR_FLOAT(fo_oldscoreboard, 0); DEFCVAR_FLOAT(fo_default_weapon, 0); -DEFCVAR_FLOAT(team_color_crosshair, 0); +DEFCVAR_FLOAT(fo_team_color_crosshair, 0); DEFCVAR_FLOAT(fo_hitaudio_enabled, 1); DEFCVAR_FLOAT(fo_hitaudio_hurtself, 1); diff --git a/menu/options_basic.qc b/menu/options_basic.qc index 597381f1..5bd5cd52 100644 --- a/menu/options_basic.qc +++ b/menu/options_basic.qc @@ -140,7 +140,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Basic = pos += 8; fr.add(menuitemslider_spawn(_("Type"), "crosshair", '0.0 19 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8; fr.add(menuitemcolour_spawn(_("Color"), "crosshaircolor", '280 8'), fl, [0, pos], [0, 8]); pos += 8; - fr.add(menuitemcheck_spawn (_("Use Team Color"), "team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; + fr.add(menuitemcheck_spawn (_("Use Team Color"), "fo_team_color_crosshair", '280 8'), fl, [0, pos], [0, 8]); pos += 8; pos += 8; fr.add( spawn( From 64fd4dfd828eb911ee1d6cae822bcf409ea27892 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Sep 2023 01:24:35 +1000 Subject: [PATCH 2147/2474] Fix 'Finished reloading' spam, allow weapon animation during reload --- csqc/weapon_predict.qc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index b0967e4a..57ffbfbc 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -858,7 +858,6 @@ void WP_Impulse() { HandleButtonThrowgren(1, BUTTON5); HandleButtonThrowgren(2, BUTTON6); - // TODO: is this blocking a /ready while reloading? if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) return; @@ -1002,7 +1001,7 @@ float WP_ReloadSlot(Slot slot) { } void WP_CheckReloadFinished() { - if (WP_IsReloading() && pstate_pred.client_time >= pstate_pred.reload_finished) { + if (WP_IsReloading() && pstate_pred.reload_finished && pstate_pred.client_time >= pstate_pred.reload_finished) { pstate_pred.tfstate &= ~TFSTATE_RELOADING; if (IsEffectFrame()) @@ -1739,7 +1738,7 @@ void WP_UpdateViewModel() { } static float no_weap_mask = TFSTATE_NO_WEAPON | TFSTATE_FLASHED; - if (pstate_pred.tfstate & no_weap_mask || CVARF(r_drawviewmodel) == 0) { + if (pstate_pred.tfstate & no_weap_mask) { viewmodel.modelindex = 0; return; } @@ -1750,7 +1749,6 @@ void WP_UpdateViewModel() { viewmodel.alpha = ra; else viewmodel.modelindex = 0; - return; } else { viewmodel.alpha = CVARF(r_drawviewmodel); } From 6d4cf0e5cf737daca28ae5e3a57c4b68122da662 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Sep 2023 01:34:16 +1000 Subject: [PATCH 2148/2474] Fix bad cvar name --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 890b8f15..ba9a08bb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -583,7 +583,7 @@ static void FO_CussCrosshair(float width, float height) { } static void UpdateTeamColorCrosshair() { - if (!CVARF(team_color_crosshair)) + if (!CVARF(fo_team_color_crosshair)) return; if (crosshair_team_no == team_no) From 45e4e7ba8118594ba2bab4b0488fdf30323b0573 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Sep 2023 01:37:03 +1000 Subject: [PATCH 2149/2474] Remove git merge artifact from README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 101db418..78cfb635 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ FortressOne Server New commands ------------ -<<<<<<< HEAD * `fo_reloadvolume 0` 0 - 1 volume for reloading sounds * `fo_reloadalpha x` alpha of viewmodel when reloading, 0 for invisible * `fo_team_color_crosshair` change crosshair to team colour From 96d0c1089573ec1b95afc3082a3e7269b51b1acb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Sep 2023 08:49:36 +1000 Subject: [PATCH 2150/2474] Fix reloadalpha 0 behaving like reloadalpha 1 --- csqc/weapon_predict.qc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 57ffbfbc..22c17d42 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1744,11 +1744,12 @@ void WP_UpdateViewModel() { } if (pstate_pred.tfstate & TFSTATE_RELOADING) { - float ra = CVARF(fo_reloadalpha); - if (ra > 0) - viewmodel.alpha = ra; + float ra; + if (CVARF(fo_reloadalpha)) + ra = CVARF(fo_reloadalpha); else - viewmodel.modelindex = 0; + ra = 0.0001; // 0 is same as 1 for compatability reasons + viewmodel.alpha = ra; } else { viewmodel.alpha = CVARF(r_drawviewmodel); } From 24ead813fca8cf5b714e4f3e8ee7d59cdbe4b831 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Sep 2023 09:15:14 +1000 Subject: [PATCH 2151/2474] Revert "Fix reloadalpha 0 behaving like reloadalpha 1" This reverts commit 96d0c1089573ec1b95afc3082a3e7269b51b1acb. --- csqc/weapon_predict.qc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 22c17d42..57ffbfbc 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1744,12 +1744,11 @@ void WP_UpdateViewModel() { } if (pstate_pred.tfstate & TFSTATE_RELOADING) { - float ra; - if (CVARF(fo_reloadalpha)) - ra = CVARF(fo_reloadalpha); + float ra = CVARF(fo_reloadalpha); + if (ra > 0) + viewmodel.alpha = ra; else - ra = 0.0001; // 0 is same as 1 for compatability reasons - viewmodel.alpha = ra; + viewmodel.modelindex = 0; } else { viewmodel.alpha = CVARF(r_drawviewmodel); } From d169179e801b540f0a07db548889675a3dd483a2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 1 Sep 2023 09:21:54 +1000 Subject: [PATCH 2152/2474] No need to do any weapon frame predictions while reloading if fo_reloadalpha is 0 --- csqc/weapon_predict.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 57ffbfbc..89c8f9d9 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1745,10 +1745,12 @@ void WP_UpdateViewModel() { if (pstate_pred.tfstate & TFSTATE_RELOADING) { float ra = CVARF(fo_reloadalpha); - if (ra > 0) + if (ra > 0) { viewmodel.alpha = ra; - else + } else { viewmodel.modelindex = 0; + return; + } } else { viewmodel.alpha = CVARF(r_drawviewmodel); } From e1d33a9d179a16a1e10d15287ab971cbf667b660 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 7 Sep 2023 02:57:01 +1000 Subject: [PATCH 2153/2474] Add login required option to admin menu, fix inconsistent menu spacers --- csqc/csextradefs.qc | 1 + csqc/events.qc | 1 + csqc/menu.qc | 40 ++++++++++++++++++++++++++++------------ ssqc/commands.qc | 13 +++++++++++++ ssqc/csmenu.qc | 4 +++- 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index aea94556..c9ed8768 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -347,6 +347,7 @@ typedef struct { float duelmode; float quad_rounds; float quad_round_time; + float fo_login_required; float captainmode; float timelimit; float fraglimit; diff --git a/csqc/events.qc b/csqc/events.qc index f345bfa1..4c705875 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -269,6 +269,7 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.ceasefire = readbyte(); SERVER_ADMIN.quad_rounds = readfloat(); SERVER_ADMIN.quad_round_time = readfloat(); + SERVER_ADMIN.fo_login_required = readfloat(); SERVER_ADMIN.timelimit = readfloat(); SERVER_ADMIN.fraglimit = readfloat(); SERVER_ADMIN.clanmode = readfloat(); diff --git a/csqc/menu.qc b/csqc/menu.qc index f8db837b..6a2fb9cf 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -6,6 +6,7 @@ void (float force) FO_Menu_Admin_Rounds; void (float force) FO_Menu_Admin_Timelimit; void (float force) FO_Menu_Admin_Fraglimit; void (float force) FO_Menu_Admin_QuadTimelimit; +void (float force) FO_Menu_Admin_FoLoginRequired; void (float force) FO_Menu_Spy; void (float force) FO_Menu_Spy_Skin; void (float force) FO_Menu_Spy_Team; @@ -389,12 +390,12 @@ var fo_menu FO_MENU_ADMIN_MAIN = { {"2","Kick...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_KICK, 0);},MENU_BORDER_WARNING}, {"3","Ban...","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_BAN, 0);},MENU_BORDER_WARNING}, {"4","Force Spectate...","","Force someone to be a spectator",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_ADMIN_FORCE_SPEC, 0);},MENU_BORDER_WARNING}, - {"6","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd randomise\n");},MENU_BORDER_WARNING}, - {"7","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd restart\n"); Menu_Cancel();},MENU_BORDER_WARNING}, - {"8","End Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcebreak\n"); Menu_Cancel();},MENU_BORDER_WARNING}, - {"9","Update Server","","",FO_MENU_STATE_NORMAL,{localcmd("cmd updateserver\n"); Menu_Cancel();},MENU_BORDER_WARNING}, - {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, + {"5","Randomize Teams","","",FO_MENU_STATE_NORMAL,{localcmd("cmd randomise\n");},MENU_BORDER_WARNING}, + {"6","Restart Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd restart\n"); Menu_Cancel();},MENU_BORDER_WARNING}, + {"7","End Current Map","","",FO_MENU_STATE_NORMAL,{localcmd("cmd forcebreak\n"); Menu_Cancel();},MENU_BORDER_WARNING}, + {"8","Update Server","","",FO_MENU_STATE_NORMAL,{localcmd("cmd updateserver\n"); Menu_Cancel();},MENU_BORDER_WARNING}, MenuSpacer, + {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, {"+","Next - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, {"-","Prev - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, }, 12, TRUE, { @@ -427,14 +428,14 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"4","Duel Mode","","Simplifies 1 on 1 action",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, {"5","Quad Rounds...","","Number of rounds in Quad mode. Usually 2",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, {"6","Quad Round Time...","","Round time for each quad round",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, - {"7","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BG_DARK}, - {"8","Force Start","","Skip prematch and start the game\nPlease use sparingly",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, + {"7","Login Required","","Require players to log in",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_FoLoginRequired(TRUE);},MENU_BORDER_WARNING}, + {"8","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BG_DARK}, + {"9","Force Start","","Skip prematch and start the game\nPlease use sparingly",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - MenuSpacer, {"+","Next - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, {"-","Prev - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, - }, 13, TRUE, { + }, 14, TRUE, { updateAdminMenuInfo(); FO_MENU_ADMIN_MODES.options[0].value = modeStatus(SERVER_ADMIN.pubmode); FO_MENU_ADMIN_MODES.options[1].value = modeStatus(SERVER_ADMIN.clanmode); @@ -442,7 +443,8 @@ var fo_menu FO_MENU_ADMIN_MODES = { FO_MENU_ADMIN_MODES.options[3].value = modeStatus(SERVER_ADMIN.duelmode); FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); - FO_MENU_ADMIN_MODES.options[6].value = SERVER_ADMIN.captainmode?"on":"off"; + FO_MENU_ADMIN_MODES.options[6].value = modeStatus(SERVER_ADMIN.fo_login_required); + FO_MENU_ADMIN_MODES.options[7].value = SERVER_ADMIN.captainmode?"on":"off"; } }; var fo_menu FO_MENU_ADMIN_SETTINGS = { @@ -455,10 +457,9 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { // {"6","Spur Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - MenuSpacer, {"+","Next - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, {"-","Prev - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, - }, 7, TRUE, { + }, 6, TRUE, { updateAdminMenuInfo(); FO_MENU_ADMIN_SETTINGS.options[0].value = ftos(SERVER_ADMIN.timelimit); FO_MENU_ADMIN_SETTINGS.options[1].value = ftos(SERVER_ADMIN.fraglimit); @@ -605,6 +606,14 @@ var fo_menu FO_MENU_ADMIN_QUAD_TIMELIMIT = { {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, }, 11, TRUE }; +var fo_menu FO_MENU_ADMIN_FO_LOGIN_REQUIRED = { + [0,0], [300,200], "Login Required?", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { + {"1","On","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fologinrequired 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"2","Off (Match Not Reported)","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fologinrequired 0\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, + }, 4, TRUE +}; var fo_menu FO_MENU_ADMIN_TIMELIMIT = { [0,0], [300,200], "Set Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","0 (infinite)","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 0\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, @@ -1182,6 +1191,12 @@ void FO_Menu_Admin_QuadTimelimit(float force) = { CurrentMenu = &FO_MENU_ADMIN_QUAD_TIMELIMIT; fo_hud_menu_active = TRUE; } +void FO_Menu_Admin_FoLoginRequired(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_FO_LOGIN_REQUIRED; + fo_hud_menu_active = TRUE; +} void FO_Menu_Admin_Timelimit(float force) = { if(fo_hud_menu_active && !force) return; @@ -1363,6 +1378,7 @@ void FO_Hud_Init() { INIT_MENU_IDS(FO_MENU_ADMIN_PLAYERS); INIT_MENU_IDS(FO_MENU_ADMIN_ROUNDS); INIT_MENU_IDS(FO_MENU_ADMIN_QUAD_TIMELIMIT); + INIT_MENU_IDS(FO_MENU_ADMIN_FO_LOGIN_REQUIRED); INIT_MENU_IDS(FO_MENU_ADMIN_TIMELIMIT); INIT_MENU_IDS(FO_MENU_ADMIN_FRAGLIMIT); INIT_MENU_IDS(FO_MENU_VOTE); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5e6f58e3..1b7e0b83 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1249,6 +1249,19 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } } break; + case "fologinrequired": + processedCmd = TRUE; + if(arg2) { + localcmd ("localinfo fologinrequired ",arg2,"\n"); + if (stof(arg2)) { + bprint(PRINT_HIGH, "Logins will be required. Matches can be reported\n"); + } else { + bprint(PRINT_HIGH, "Allow unregistered players. Matches won't be reported\n"); + } + bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); + UpdateAllAdmins(); + } + break; case "captainmode": processedCmd = TRUE; if(arg2 && arg3) { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 6ab2d45c..7c22eaae 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -170,12 +170,14 @@ void Update_ServerAdminInfo(entity pl) = { msg_entity = pl; local float cm = CF_GetSetting("c", "clan", "off"), qm = CF_GetSetting("quadmode", "quadmode", "off"), - dm = CF_GetSetting("duelmode", "duelmode", "off"); + dm = CF_GetSetting("duelmode", "duelmode", "off"), + flr = CF_GetSetting("flr", "fologinrequired", "off"); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SERVER_ADMIN_INFO); WriteByte(MSG_MULTICAST, is_paused || cease_fire); WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); WriteFloat(MSG_MULTICAST, infokeyf(world, "round_time")); + WriteFloat(MSG_MULTICAST, (fo_login_required?1:0) + (flr?2:0)); WriteFloat(MSG_MULTICAST, infokeyf(world, "timelimit")); WriteFloat(MSG_MULTICAST, infokeyf(world, "fraglimit")); WriteFloat(MSG_MULTICAST, (clanbattle?1:0) + (cm?2:0)); From b03eca8ff656044b4ef4a8ec14b3bfcdcf9a36e0 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 6 Sep 2023 20:24:05 -0700 Subject: [PATCH 2154/2474] wp: restore zero check on r_drawviewmodel This also needs to be put back where it was, otherwise it breaks `r_drawviewmodel 0` to hide the viewmodel. --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 89c8f9d9..889d4932 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1738,7 +1738,7 @@ void WP_UpdateViewModel() { } static float no_weap_mask = TFSTATE_NO_WEAPON | TFSTATE_FLASHED; - if (pstate_pred.tfstate & no_weap_mask) { + if (pstate_pred.tfstate & no_weap_mask || CVARF(r_drawviewmodel) == 0) { viewmodel.modelindex = 0; return; } From d14385268dbb70e1ba6aa865357e817fd1e80d16 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 7 Sep 2023 17:21:02 -0700 Subject: [PATCH 2155/2474] wp: handle pvs/retransmits more cleanly Engine instantiated new entities have a ~0 changed-mask for full-transmit which could have some unintended interactions with the client-side instantiation. A notable example of this is PVS interactions. Handle this case explicitly. This should also fix phantom duplicate weapon firing sounds that some people were experiencing (one of the unintended interactions above). --- csqc/weapon_predict.qc | 6 ++++++ share/prediction.qc | 23 +++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 889d4932..f6b4269d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1700,6 +1700,12 @@ void InitProjectileEnt(float sendflags) { else setorigin(self, self.origin); + if (sendflags & FOPP_NEW == 0) { + // Retransmit. Patch up trail, but no predicted / sound / etc. + self.oldorigin = self.s_origin; + return; + } + // We still check this with projectile prediction as there could be in // flight projectiles on the transition. This is effectively a nop in the // off case since the projectile list will just be empty. diff --git a/share/prediction.qc b/share/prediction.qc index 8a5e6d8e..74a833da 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -22,10 +22,10 @@ enumflags { FOWP_RNG0, FOWP_RNG1, FOWP_PREDICT_FLAGS, - FOWP_NEW, // We only use this for a new entity, which is FFF... anyway. }; enumflags { + FOPP_NEW, FOPP_INIT, FOPP_POS, FOPP_AUX, @@ -33,10 +33,8 @@ enumflags { FOPP_AVEL, FOPP_MOVETYPE, FOPP_EXPIRY, - FOPP_NEW, // We only use this for a new entity, which is FFF... anyway. }; -#define FOWP_ALL 0xFFFF enumflags { CSQC_WEAP_PRED, @@ -507,24 +505,33 @@ void EntUpdate_WeaponPred(float isnew) { #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.##_field) #define COMMD(_type, _dest, _field) COMM(_type, _field) #define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) -float PP_SendEntity(entity to_player, float sendflags) { - if (sendflags & FOPP_NEW) { - sendflags = FOPP_INIT | FOPP_POS; +float PP_SendEntity(entity to_player, float sendmask) { + float sendflags = self.SendFlags & sendmask; + + if (sendflags & FOPP_NEW || sendflags == 0 /* retransmit */) { + sendflags |= FOPP_INIT | FOPP_POS; if (self.fpp.aux) sendflags |= FOPP_AUX; if (self.fpp.expires_at) sendflags |= FOPP_EXPIRY; + + // Make sure we carry all the state on a retransmit (normally PVS). + if (sendflags & FOPP_NEW == 0) { + sendflags |= FOPP_ANGLES | FOPP_MOVETYPE; + if (vlen(self.avelocity) > 0) + sendflags |= FOPP_AVEL; + } } WriteByte(MSG_ENTITY, ENT_PROJECTILE); - WriteByte(MSG_ENTITY, sendflags); + WriteShort(MSG_ENTITY, sendflags); #else #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() #define COMMO(_type, _dest, _src) ##_dest = Read##_type() #define COMM(_type, _field) COMMD(_type, _field, _field) void EntUpdate_Projectile(float isnew) { - float sendflags = readbyte(); + float sendflags = readshort(); #endif if (sendflags & FOPP_INIT) { COMM(Byte, fpp.index); From 19e7febc02626e918d014495b9c0e12ff077ba2c Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Aug 2023 15:53:04 -0700 Subject: [PATCH 2156/2474] projectiles: unify skybox removal Several projectile types were missing handling for skybox collision, which ends up cascading into PVS events. Unify coverage/removal inside the physics code handling the original movement into/intersection with skybox so that we don't have to carry it across every touch(). (If we ever did want something else here we can always re-introduce it as a unified helper rather than the copy-and-paste job this removes.) --- share/physics.qc | 5 +++++ ssqc/hwguy.qc | 5 ----- ssqc/pyro.qc | 6 +----- ssqc/spy.qc | 4 ---- ssqc/weapons.qc | 12 ------------ 5 files changed, 6 insertions(+), 26 deletions(-) diff --git a/share/physics.qc b/share/physics.qc index ae4c9753..ce15c501 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -32,6 +32,11 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { if (other.solid == SOLID_NOT) return; + if (pointcontents(self.origin) == CONTENT_SKY) { + dremove_sent(self); + return; + } + if (e.touch) { if (phys_flags & PHYSF_FORWARD_KNOCK) e.flags |= FL_FORWARD_KNOCK; diff --git a/ssqc/hwguy.qc b/ssqc/hwguy.qc index daac67e2..d27ace81 100644 --- a/ssqc/hwguy.qc +++ b/ssqc/hwguy.qc @@ -16,11 +16,6 @@ void AssCanBulletTouch() return; // Marked for removal self.voided = TRUE; - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove(self); - return; - } - if (other == self.owner) return; // Touching self, do nothing diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 54708901..ddcdd274 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -565,11 +565,7 @@ void () T_IncendiaryTouch = { return; self.voided = 1; - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove_sent(self); - return; - } - self.effects = self.effects | 4; + self.effects |= EF_BRIGHTLIGHT; damg = 42 + random() * 20; if (other.health) { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 0ddc8170..78aab175 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -1107,10 +1107,6 @@ void () T_TranqDartTouch = { return; self.voided = 1; - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove_sent(self); - return; - } if (other.takedamage) { if ((other.classname == "player") && !((other.team_no == self.owner.team_no) && diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 6c2b0d72..d843fe6a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1080,10 +1080,6 @@ void () T_MissileTouch = { return; self.voided = 1; - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove_sent(self); - return; - } damg = 92 + random() * 20; deathmsg = self.weapon; @@ -1479,10 +1475,6 @@ void () spike_touch = { if (other.solid == SOLID_TRIGGER) return; - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove_sent(self); - return; - } if (other.takedamage) { spawn_touchblood(9); deathmsg = self.weapon; @@ -1533,10 +1525,6 @@ void () superspike_touch = { if (other.solid == SOLID_TRIGGER) return; - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove_sent(self); - return; - } if (other.takedamage) { spawn_touchblood(18); deathmsg = self.weapon; From 8a15749f831857260263d707e99c6bb369aea121 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 28 Aug 2023 11:40:36 -0700 Subject: [PATCH 2157/2474] wp: always enable weapon + projectile prediction by default Make client side prediction always active by default. Use of client versus server rendering no longer depends on ping. Disabling (e.g. `fo_predict_weapons 0`, `fo_predict_projectiles 0`) is unchanged. (Although will be subsequently weakened to only apply to the prediction part as we admit higher dependency on client-side handling.) --- csqc/weapon_predict.qc | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f6b4269d..653951a4 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -42,7 +42,7 @@ inline float WPP_ViewModelMask() { return pengine.view_mask; } float WP_MinPing() { if (CVARF(wpp_min_ping) == -1) - return fo_config.wp_default_min_ping_ms; + return fo_config.wp_default_min_ping_ms; else return CVARF(wpp_min_ping); } @@ -132,8 +132,8 @@ float csqc_get_user_setting(string s_short, string s_long, string def); // Order of preference: // server disable, client enable/disable, server/ping enable static float CalcPredEnabled(float current_enable, float cvar, - float server_disable, - float dependent_enabled, string* set_by) { + float server_disable, float dependent_enabled, + string* set_by) { if (!dependent_enabled) { // PP depends on WP, so !WP => !PP @@ -161,6 +161,11 @@ static float CalcPredEnabled(float current_enable, float cvar, return FALSE; } + *set_by = "[default]"; + return TRUE; + +#if 0 + if (WP_MinPing() == 0) return current_enable; @@ -190,6 +195,7 @@ static float CalcPredEnabled(float current_enable, float cvar, *set_by = sprintf("[lan mode <%d]", WP_MinPing()); return FALSE; } +#endif } static float client_delay_packets; @@ -219,12 +225,10 @@ void WPP_Status() { float wp_enabled = pengine.wp_enabled, pp_enabled = pengine.pp_enabled; CalcPredEnabled(wp_enabled, CVARF(fo_predict_weapons), - fo_config.wp_global_disable, - TRUE, &wp_source); + fo_config.wp_global_disable, TRUE, &wp_source); CalcPredEnabled(pp_enabled, CVARF(fo_predict_projectiles), - fo_config.wp_global_disable, - wp_enabled, &pp_source); + fo_config.wp_global_disable, wp_enabled, &pp_source); printf("Prediction Status:\n"); printf(" Weapon prediction %s %s\n", @@ -304,12 +308,10 @@ void WPP_UpdateEnable(float force) { string wp_source, pp_source; wp_new = CalcPredEnabled(wp_enabled, CVARF(fo_predict_weapons), - fo_config.wp_global_disable, - TRUE, &wp_source); + fo_config.wp_global_disable, TRUE, &wp_source); pp_new = CalcPredEnabled(pp_enabled, CVARF(fo_predict_projectiles), - fo_config.wp_global_disable, - wp_new, &pp_source); + fo_config.wp_global_disable, wp_new, &pp_source); static float once; if (wp_new != pengine.wp_enabled || !once) { From babb7e7fb0e6578a3e664bee03610c9ff2dbccb8 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 7 Sep 2023 17:58:30 -0700 Subject: [PATCH 2158/2474] wp: update enable state on player transitions More quickly update enable state on player/state transitions. Also no longer wait for stable ping since we're transitioning away from ping toggle. --- csqc/main.qc | 8 ++++++++ csqc/weapon_predict.qc | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index ba9a08bb..3699ddfa 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -683,7 +683,15 @@ void _Sync_ServerCommandFrame() { is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); if (is_spectator) is_observer = FALSE; + + static float last_is_player; + + last_is_player = is_player; is_player = (!is_spectator && !is_observer); + + if (last_is_player != is_player) + WP_PlayerTransition(); + if (!is_player || getstatf(STAT_HEALTH) <= 0) is_alive = 0; else diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 653951a4..d32cee94 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -296,8 +296,10 @@ void WPP_UpdateEnable(float force) { last_fo_predict_projectiles = CVARF(fo_predict_projectiles); } +#ifdef 0 if (avg_ping.samples.count < 5) return; // Skip until we have a useful number of samples. +#endif if (!force && time < next_wpp_enable_check) return; @@ -360,6 +362,10 @@ void WPP_UpdateEnable(float force) { WP_UpdateViewModel(); } +void WP_PlayerTransition() { + WPP_UpdateEnable(TRUE); +} + DEFCVAR_FLOAT(fo_minping_min, 0); // Can be used to set a lower-bound on // what minping will be chosen. DEFCVAR_FLOAT(cl_delay_packets, 0); // Can be used to query, but not set. From 0a99616f114a0b59bb3bee67c9c0532e863fa48e Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 7 Sep 2023 19:46:17 -0700 Subject: [PATCH 2159/2474] wp: make sure that we've received prediction ent Since we no longer wait for ping to stabilize it's possible to race with receiving the prediction entity from the server; ensure we synchronize on this. From e5281f39488ac6c6fddc541db801b26bd2e029e7 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 7 Sep 2023 19:52:06 -0700 Subject: [PATCH 2160/2474] wp: make sure that we've received prediction ent (reupload) Since we no longer wait for ping to stabilize it's possible to race with receiving the prediction entity from the server; ensure we synchronize on this. --- csqc/weapon_predict.qc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index d32cee94..aaaf41d2 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -16,6 +16,8 @@ DEFCVAR_FLOAT(r_drawviewmodel, 1); DEFCVAR_FLOAT(fo_reloadalpha, 0); DEFCVAR_FLOAT(fo_reloadvolume, 0); +static float wp_ready; + struct pengine_t { float pp_enabled; float wp_enabled; @@ -285,6 +287,9 @@ void WPP_UpdateEnable(float force) { next_ping_update = time + PING_PERIOD / avg_ping.samples.max_count; } + if (!wp_ready) + return; + // Immediate updates any time there's a cvar change. static float next_wpp_enable_check; static float last_fo_predict_weapons, last_fo_predict_projectiles; @@ -1880,4 +1885,6 @@ void InitWeapPredEnt(entity pe) { viewmodel.drawmask = MASK_PRED_ENT; viewmodel.renderflags = RF_VIEWMODEL | RF_DEPTHHACK; pengine.viewmodel = viewmodel; + + wp_ready = TRUE; } From eb2286613c8e4056d8f9817952a9129db067c8b6 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 8 Sep 2023 10:01:09 -0700 Subject: [PATCH 2161/2474] hud: add a visual indicator of reload progress Add a hud indicator describing reload progress/completion. Only displayed when reloading. --- csqc/csextradefs.qc | 1 + csqc/hud.qc | 6 +++--- csqc/status.qc | 29 ++++++++++++++++++++++++++++- csqc/weapon_predict.qc | 9 +++++++++ share/prediction.qc | 7 +++++-- share/weapons.qc | 1 + ssqc/qw.qc | 1 + ssqc/tfort.qc | 1 - 8 files changed, 48 insertions(+), 7 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c9ed8768..c629e398 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -423,6 +423,7 @@ enum PanelID:float { HUDP_MENU, HUDP_MENU_HINT, HUDP_CLIPSIZE, + HUDP_RELOADPROGRESS, HUDP_FRAGSTREAK, HUDP_CAPS, HUDP_GREN1, diff --git a/csqc/hud.qc b/csqc/hud.qc index 454160cc..56249351 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -56,9 +56,9 @@ void FO_Hud_Editor_LoadDefaultSettings() getHudPanel(HUDP_SPEEDBAR)->Snap = HUD_SNAP_CENTER; getHudPanel(HUDP_SPEEDBAR)->Position = [0, 30]; - getHudPanel(HUDP_PING)->Display = 0; - getHudPanel(HUDP_PING)->Snap = HUD_SNAP_TOP_RIGHT; - getHudPanel(HUDP_PING)->Scale = 1.00; + getHudPanel(HUDP_RELOADPROGRESS)->Display = 1; + getHudPanel(HUDP_RELOADPROGRESS)->Snap = HUD_SNAP_CENTER; + getHudPanel(HUDP_RELOADPROGRESS)->Position = [0, yoffset - 30]; } void FO_Hud_Editor_List_Panels() = { diff --git a/csqc/status.qc b/csqc/status.qc index 16e09dd0..a5e97f69 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1059,6 +1059,32 @@ void drawSpeedBar(PanelID panelid, string text) { HRC_drawstring(position + '3 0 0', ftos((int)tspeed), '9 9 0', '1 1 1'); } +void drawReloadProgress(PanelID panelid, string text) { + FO_Hud_Panel* panel = getHudPanel(HUDP_RELOADPROGRESS); + vector fillsize = panel.FillSize * panel.Scale; + vector position = getPanelPosition(panel); + + if (fo_hud_editor && + hud_panel(panel->id, position, fillsize, 0.2, panel.Display)) { + // click event + } + + float per = WP_ReloadPercent(); + if (per == 1) + return; + + HRC_drawfill(position, fillsize, '0.5 0.5 0.5'); + vector progress = fillsize; + progress.x *= per; + + position += '1 1 0'; + HRC_drawfill(position, progress - '1 2 0', '0.9 0.9 0.9'); + const string text = "Reloading"; + const vector fontsize = '8 8 0'; + position.x += (fillsize.x - stringwidth(text, 0, fontsize)) / 2; + HRC_drawstring(position, text, fontsize, '1 0.4 0.4'); +} + string getPingPanelText(); var FO_Hud_Panel Hud_Panels[] = { @@ -1073,6 +1099,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_MENU, "menu", "Menu", '10 110', '300 200',1,0,1,0,1, drawSimplePanel, {return "";}}, {HUDP_MENU_HINT, "menuhint", FO_HUD_MENU_HINT_NAME, '100 300', '300 24', 1,0,1,0,1, drawTextPanel, {return SBAR.Hint;}}, {HUDP_CLIPSIZE, "clipsize", FO_HUD_CLIPSIZE_NAME, '464 455', '26 26', 0.75,0,1,0,0, drawClipSize, { return WP_GetClip(); }}, + {HUDP_RELOADPROGRESS, "reload_progress", "Reload Progress", '0 0', '100 10', 1,1,1,0,0, drawReloadProgress, {return "";}, 0, HUD_SNAP_CENTER}, {HUDP_FRAGSTREAK, "fragstreak", FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, @@ -1114,7 +1141,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_GUN8, "gun8", "Lighning Gun", '-4 -50', '36 24', 0.8,1.4,1,0,0, drawInvIconPanel, {return getGunIcon(IT_LIGHTNING);}, 0, 36}, {HUDP_SPEED, "speed", "Speed", '4 15', '26 26', 1,1.4,0,0,0, drawTextPanel, {return CVARF(fo_fte_hud) ? ftos((int)PlanarSpeed()) : "";}, 0, 4}, {HUDP_SPEEDBAR, "speedbar", "Speed Bar", '4 30', '150 10', 1,1.4,0,0,0, drawSpeedBar, {return "";}, 0, 4}, - {HUDP_PING, "ping", "Ping", '4 15', '120 12', 1,1.4,0,0,0, drawTextPanel, getPingPanelText, 0, 4}, + {HUDP_PING, "ping", "Ping", '4 15', '120 12', 1,1.4,0,0,0, drawTextPanel, getPingPanelText, 0, HUD_SNAP_TOP_RIGHT}, {HUDP_OPTIONS, "hudoptions", FO_HUD_OPTIONS_NAME, '10 10', '150 182',1, 0,1,0,1, doNothing, {return "";}, 1}, }; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index aaaf41d2..14f56135 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -942,6 +942,14 @@ float WP_CurrentClipFired() { return *WP_ClipFired(CurrentSlot()); } +float WP_ReloadPercent() { + if (!WP_IsReloading()) + return 1; + + return (pstate_pred.client_time - pstate_pred.reload_started) / + (pstate_pred.reload_finished - pstate_pred.reload_started); +} + string WP_GetClip() { if (!WP_Enabled()) return SBAR.ClipSize; @@ -1007,6 +1015,7 @@ float WP_ReloadSlot(Slot slot) { float amt = min(*WP_ClipFired(slot), WP_GetAmmo(wi->ammo_type)); (*WP_ClipFired(slot)) -= amt; + pstate_pred.reload_started = pstate_pred.client_time; pstate_pred.reload_finished = pstate_pred.client_time + (amt / wi->clip_size) * wi->full_reload_time; diff --git a/share/prediction.qc b/share/prediction.qc index 74a833da..9f167982 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -64,6 +64,7 @@ struct predict_tf_state { float client_nextthink; float client_thinkindex; + float reload_started; float reload_finished; float clip_fired[4]; int prng_base[PRNG_NUM_STATES]; @@ -334,7 +335,7 @@ static float Prediction_ChangedMask(entity player) { M1(FOWP_AF, attack_finished); M2(FOWP_THINK, client_nextthink, client_thinkindex); M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]); - M1(FOWP_RELOAD, reload_finished); + M2(FOWP_RELOAD, reload_started, reload_finished); M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]) @@ -482,8 +483,10 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Byte, clip_fired[3]); } - if (sendflags & FOWP_RELOAD) + if (sendflags & FOWP_RELOAD) { + COMM(Float, reload_started); COMM(Float, reload_finished); + } if (sendflags & FOWP_RNG0) COMM(Int, prng_base[PRNG_WEAP]); diff --git a/share/weapons.qc b/share/weapons.qc index 297fa049..09cef9de 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -587,6 +587,7 @@ void FO_ReloadSlot(Slot slot, float force) { (*ws->clip_fired) -= reload_count; self.last_still_loading = reload_count; + self.reload_started = self.client_time; self.reload_finished = self.client_time + reload_duration; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index c8450756..dae19a25 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -227,6 +227,7 @@ float coop; .float noammo; // used for no ammo error messages // variables used for reloading +.float reload_started; // when the reload started .float reload_finished; // when the reload will finish // Only use below for map ent compatibility. diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b98d35ac..17057224 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2123,7 +2123,6 @@ void () TeamFortress_SetEquipment = { self.modelindex = 0; self.weaponmodel = string_null; modelindex_player = 0; - self.tfstate = self.tfstate | TFSTATE_RELOADING; setmodel(self, string_null); } From 7609b1b55fe0119e873749bff2f27e011627cc50 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 9 Sep 2023 02:45:29 -0700 Subject: [PATCH 2162/2474] spec: fix ident string spam (maybe fix spectate w/ proxy?) Early return when spectator/observer was preventing the last sbar update from being cached, resulting in spectators getting absolutely reamed by messages, in particular ident. Further improve this by only sending ident updates when there is an actual change, rather than constantly. This could well explain the proxy overflows we see when spectating. --- csqc/events.qc | 5 +++-- ssqc/actions.qc | 6 +----- ssqc/status.qc | 21 ++++++++++----------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 4c705875..14132ee4 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -426,8 +426,9 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (primed_at < last_death_time) return; - local float timer_flags = 0; - switch (CVARF(fo_grentimer)) { + float timer_flags = 0; + float timer_mode = is_player ? CVARF(fo_grentimer) : 1; + switch (timer_mode) { case 0: break; case 1: timer_flags = FL_GT_SOUND; break; // 2 [and something sane for anything we don't recognize.] diff --git a/ssqc/actions.qc b/ssqc/actions.qc index 9e08a6fd..e72376af 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -261,11 +261,7 @@ void (entity pe_player) FO_Spectator_Identify = { pe_player.ident_time = time + 0.5; if(pe_player.ident_string != s_id_string) { pe_player.ident_string = s_id_string; - //if(infokeyf(pe_player, INFOKEY_P_CSQCACTIVE)) { - UpdateClientIDString(pe_player); - //} else { - // Status_Refresh(pe_player); - //} + UpdateClientIDString(pe_player); } } } diff --git a/ssqc/status.qc b/ssqc/status.qc index 44fc6bee..be19a8b8 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -827,20 +827,18 @@ void UpdateClientPlayerDie(entity pl) = { void UpdateClientIDString(entity pl) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; + + string ident = time < pl.ident_time ? pl.ident_string : ""; // only send updates - //if(time < pl.ident_time && pl.ident_string == pl.last_ident_string) - // return; + if (ident == pl.last_ident_string) + return; + pl.last_ident_string = ident; + msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_ID); - // identify - if (pl.ident_string && time < pl.ident_time) { - WriteString(MSG_MULTICAST, pl.ident_string); - } else { - WriteString(MSG_MULTICAST, ""); - } + WriteString(MSG_MULTICAST, ident); multicast('0 0 0', MULTICAST_ONE_NOSPECS); - pl.last_ident_string = pl.ident_string; } void UpdateClientStatusBar(entity pl) @@ -1035,6 +1033,8 @@ void (entity pl) RefreshStatusBar = { height = 300; height = height - pl.StatusStringLines - 13; + pl.StatusRefreshTime = time + 1.5; + csqcactive = infokeyf(pl, INFOKEY_P_CSQCACTIVE); if(pl.classname == "observer" && csqcactive) { if (tfdet) @@ -1285,7 +1285,6 @@ void (entity pl) RefreshStatusBar = { } } centerprint(pl, pl.StatusString, pad, ident, ct, s1, s2, s3); - pl.StatusRefreshTime = time + 1.5; strunzone(pad); strunzone(ct); strunzone(s1); strunzone(s2); strunzone(s3); }; From 583dcc2d142a600a19ff15fa036dc1b7885434d7 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 9 Sep 2023 02:50:45 -0700 Subject: [PATCH 2163/2474] tfx: clear enable mask Some of these will be reintroduced, but we disabled elsewhere as a bit of hack around ezq issues so clear the mask then reintroduce with removal of that. --- share/commondefs.qc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 32a85513..f5716ebf 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -105,8 +105,7 @@ float TFxEnabled(float flag) { return fo_config.tfx_flags & flag; } -const float TFX_DEFAULT_FLAGS = - TFX_SPEC_OUTLINE | TFX_SPEC_GRENTIMER | TFX_SPEC_SEEFLAG; +const float TFX_DEFAULT_FLAGS = 0; enum CSQCFlags { PREDICT_CSQC_SETSPEED, From 5d62d3ef54356c570c89cf3e4f568e46f06f4a6e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 11 Sep 2023 18:04:35 -0700 Subject: [PATCH 2164/2474] wp: add support for local grenade priming Make grenades more responsive by responding to the prime immediately and starting the grenade timer client-side without waiting for it to come back from the server. At higher pings, this will result in less of the grenade wav being truncated. Currently behind `fo_beta_local_grenade` for testing. --- csqc/csextradefs.qc | 8 +++++ csqc/events.qc | 14 ++++++++ csqc/weapon_predict.qc | 74 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 90 insertions(+), 6 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c629e398..9f666da9 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -755,6 +755,14 @@ class CsGrenTimer { }; nonvirtual void() StartSound; + nonvirtual void(float offset) adj_sync { + if (!playing_) + return; + + expires_at_ += offset; + StartSound(); + }; + static float next_index_; static CsGrenTimer last_; diff --git a/csqc/events.qc b/csqc/events.qc index 14132ee4..3b6959b1 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -426,6 +426,20 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (primed_at < last_death_time) return; + // Very rough (but good enough for now) filter to disambiguate local + // predicted primes versus matched server primes. + static float last_explodes_at; + float delta = explodes_at - last_explodes_at; + if (fabs(delta) < 50 * MSEC) { + // Experimental patch up if prediction too far off. + if (CVARF(fo_beta_local_grenade) == 2 && delta > 10 * MSEC) { + CsGrenTimer last = CsGrenTimer::GetLast(); + last.adj_sync(delta); + } + return; + } + last_explodes_at = explodes_at; + float timer_flags = 0; float timer_mode = is_player ? CVARF(fo_grentimer) : 1; switch (timer_mode) { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 14f56135..c9639f5e 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -97,6 +97,11 @@ float interp_time() { return last_interp_time; } +// The server time of the current predicted clientcomandframe +inline float cpredict_time() { + return time + pstate_pred.client_time - pstate_server.client_time; +} + #define csqc_print(...) \ do { if (CVARF(wpp_debug) & 4) { \ @@ -818,17 +823,22 @@ static float WP_Sniper_IsAttack() { } void W_ThrowGren(float is_throw); +void W_PrimeGren(float index); static void HandleButtonThrowgren(float index, float button) { float b_down = pstate_pred.buttons_down & button; float b_up = pstate_pred.buttons_up & button; if (IsHoldGrenades()) { - if (b_up) + if (b_down) + W_PrimeGren(index); + else if (b_up) W_ThrowGren(TRUE); - } else { - if ((pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) && b_down) + } else if (b_down) { + if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) W_ThrowGren(TRUE); + else + W_PrimeGren(index); } } @@ -843,7 +853,45 @@ static void WP_ChangeIfQueued() { } } + +DEFCVAR_FLOAT(fo_beta_local_grenade, 0); + +void WP_HandleGrenadeInputs() { + if (!CVARF(fo_beta_local_grenade)) + return; + + float clear_impulse = TRUE; + + switch (pstate_pred.impulse) { + case TF_GRENADE_1: W_PrimeGren(1); break; + case TF_GRENADE_2: W_PrimeGren(2); break; + case TF_GRENADE_T: W_ThrowGren(TRUE); break; + + case TF_GRENADE_PT_1: + if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) + W_ThrowGren(TRUE); + else + W_PrimeGren(1); + break; + case TF_GRENADE_PT_2: + if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) + W_ThrowGren(TRUE); + else + W_PrimeGren(2); + break; + + default: clear_impulse = FALSE; break; + } + + HandleButtonThrowgren(1, BUTTON5); + HandleButtonThrowgren(2, BUTTON6); + + if (clear_impulse) + pstate_pred.impulse = 0; +} + void WP_Impulse() { + WP_HandleGrenadeInputs(); WP_HandleHeavyInputs(); // Note: We might have no impulse, but a queued slot here. @@ -868,9 +916,6 @@ void WP_Impulse() { if (match) pstate_pred.impulse = 0; - HandleButtonThrowgren(1, BUTTON5); - HandleButtonThrowgren(2, BUTTON6); - if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) return; @@ -1494,6 +1539,23 @@ static float CanThrowGrenade(int gren_type) { return TRUE; } +void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); + +static void W_PrimeGren(float index) { + if (!is_alive || getstatf(STAT_NOFIRE)) + return; + + if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) + return; + + index -= 1; + float gren = FO_ClassGren(pstate_pred.playerclass, index)->id; + + pstate_pred.tfstate |= (index ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED); + if (IsEffectFrame()) + ParseGrenPrimed(gren - GREN_FIRST + 1, time, time + 3.8); +} + static void W_ThrowGren(float is_throw) { if (!QcPhysics() || !RewindFlagEnabled(REWIND_GRENADES) || getstatf(STAT_NOFIRE)) return; From 122edede01c3e3d4501f64ecf42c8ee27238a505 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 11 Sep 2023 19:48:02 -0700 Subject: [PATCH 2165/2474] wp: unify server-frame states Introduce game_state which unifies a bunch of individual variables we had for tracking this before. Some minor clean-ups in updating callers. --- csqc/csextradefs.qc | 14 ++++++++++---- csqc/events.qc | 4 ++-- csqc/main.qc | 36 +++++++++++++++++++----------------- csqc/menu.qc | 4 ++-- csqc/pmove.qc | 2 +- csqc/status.qc | 7 ++++--- csqc/tfx.qc | 8 ++++---- csqc/weapon_predict.qc | 27 +++++++++++++++------------ ssqc/tfort.qc | 2 +- 9 files changed, 58 insertions(+), 46 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9f666da9..8ec91e26 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -866,14 +866,20 @@ DEFCVAR_FLOAT(fo_fte_hud, 0); DEFCVAR_FLOAT(fo_legacy_sbar, 0); DEFCVAR_FLOAT(fo_csjumpsounds, 1); +struct GameState { + float localentnum; + float is_player; + float is_alive; + float is_observer; + float is_spectator; +}; + +GameState game_state, prev_game_state; + float team_no; float crosshair_team_no; float all_time; -float is_spectator; float player_class; -float is_observer; -float is_player; -float is_alive; float painfinished; vector thisorigin; float jump_counter; diff --git a/csqc/events.qc b/csqc/events.qc index 3b6959b1..3b7ea1d2 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -441,7 +441,7 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { last_explodes_at = explodes_at; float timer_flags = 0; - float timer_mode = is_player ? CVARF(fo_grentimer) : 1; + float timer_mode = game_state.is_player ? CVARF(fo_grentimer) : 1; switch (timer_mode) { case 0: break; case 1: timer_flags = FL_GT_SOUND; break; @@ -640,7 +640,7 @@ float(float ent_num, float channel, string soundname, float vol, float attenuati return 1; // Sounds from remote entities are not local and we should always play. - if (ent_num != player_localentnum || is_spectator || is_observer) + if (ent_num != player_localentnum || !game_state.is_player) return 0; // Sounds below this line are conditionally filtered. diff --git a/csqc/main.qc b/csqc/main.qc index 3699ddfa..72c644ee 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -636,7 +636,7 @@ noref void CSQC_Input_Frame() { // Handle zoom float prev_zoomed_in = zoomed_in; - if (player_class == PC_SNIPER && is_alive) + if (player_class == PC_SNIPER) zoomed_in = input_buttons & BUTTON3; else zoomed_in = 0; @@ -672,30 +672,32 @@ void _Sync_ServerCommandFrame() { return; last_servercommandframe = servercommandframe; + prev_game_state = game_state; + team_no = getstatf(STAT_TEAMNO); all_time = getstatf(STAT_ALL_TIME); - is_observer = FALSE; - if (team_no == 0) - is_observer = TRUE; + game_state.is_observer = team_no == 0; player_class = getstatf(STAT_CLASS); SBAR.ReadyStatus = getstatf(STAT_FLAGS); - is_spectator = stof(getplayerkeyvalue(player_localnum, "*spectator")); - if (is_spectator) - is_observer = FALSE; - - static float last_is_player; + game_state.localentnum = player_localentnum; - last_is_player = is_player; - is_player = (!is_spectator && !is_observer); + if (game_state.is_observer) { + game_state.is_player = 0; + if (stof(getplayerkeyvalue(player_localnum, "*spectator"))) { + game_state.is_spectator = 1; + game_state.is_observer = 0; + } else { + game_state.is_spectator = 0; + } + } else { + game_state.is_player = 1; + } - if (last_is_player != is_player) - WP_PlayerTransition(); + // Note: When spectating someone, refers to them. + game_state.is_alive = getstatf(STAT_HEALTH) >= 0; - if (!is_player || getstatf(STAT_HEALTH) <= 0) - is_alive = 0; - else - is_alive = 1; + WP_ServerFrame(); // Use an undocumented ezquake compat feature to figure out whether we // have focus or not, skip updates in this case due to lowered network fps. diff --git a/csqc/menu.qc b/csqc/menu.qc index 6a2fb9cf..84977a2a 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -870,7 +870,7 @@ void FO_Menu_Game(float force) = { } if(fo_hud_menu_active && !force) return; - if(is_spectator) { + if(game_state.is_spectator) { //print(getplayerkeyvalue(player_localnum, "name"), " is a spectator!\n"); //FO_MENU_GAME_SPECTATOR.num_opts = 3; FO_MENU_GAME_SPECTATOR.options[2].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_DISABLED; @@ -890,7 +890,7 @@ void FO_Menu_Game(float force) = { } void FO_Menu_Track() = { - if(!is_spectator) + if(!game_state.is_spectator) return; local float i = 0; diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 84428a3e..c6f68cb3 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -39,7 +39,7 @@ void PM_PredictJump() { float landing = onground && !last_onground; float vel_z = pmove_vel_z ?: recent_pmove_vel_z; - if (!is_alive) { + if (!game_state.is_alive) { last_onground = 1; last_vel_z = 0; last_waterlevel = 0; diff --git a/csqc/status.qc b/csqc/status.qc index a5e97f69..c1487231 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -12,7 +12,7 @@ DEFCVAR_FLOAT(fo_hud_noclipicon, 0); void(PanelID ignored, string text) drawClipSize = { string icon = CVARF(fo_hud_noclipicon) ? "" : ICON_CLIPSIZE; - if (is_alive || fo_hud_editor) + if (game_state.is_alive || fo_hud_editor) Hud_DrawPanelLMP(getHudPanel(HUDP_CLIPSIZE), text, icon, 1); }; @@ -534,7 +534,8 @@ void(PanelID panelid, string text) drawReadyPanel = { if(showingscores || !panel.Display) { return; } - if(prematch && team_no && player_class && !SBAR.CountdownStarted && !is_spectator) { + if (prematch && team_no && player_class && !SBAR.CountdownStarted && + game_state.is_player) { if(SBAR.ReadyStatus & PLAYER_READY) { message = "Ready"; textcolour = MENU_TEXT_GREEN; @@ -749,7 +750,7 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; if (team_no == lines[i].team_no || lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER - || is_spectator || is_observer) { + || !game_state.is_player) { string c = lines[i].classtext; if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { float cspace = strlen(c) * smalltext.x; diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 947e6667..28c93834 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -65,7 +65,7 @@ static float ShowPlayerOutline(entity player) { if (prematch && TFxEnabled(TFX_PREMATCH_EVERYTHING)) return TRUE; - if (!is_player) + if (!game_state.is_player) return TFxEnabled(TFX_SPEC_OUTLINE); if ((TFxEnabled(TFX_DEFENSE_OUTLINE) && !IsAttacking(player)) || @@ -112,7 +112,7 @@ static void UpdateOutline(entity player) { float UpdatePlayer(float isnew) { if (isnew) { - if (self.entnum == player_localentnum && is_player) + if (self.entnum == player_localentnum && game_state.is_player) local_player = self; AddOutline(self); @@ -130,7 +130,7 @@ float UpdatePlayer(float isnew) { } static float ShowTeamGrenTimer(float team, float my_team) { - if (!is_player && TFxEnabled(TFX_SPEC_GRENTIMER)) + if (!game_state.is_player && TFxEnabled(TFX_SPEC_GRENTIMER)) return TRUE; if (prematch && TFxEnabled(TFX_PREMATCH_EVERYTHING)) @@ -221,7 +221,7 @@ void TFxRenderGrenadeTimers() { } static float ShowFlagOutline() { - if (!is_player && TFxEnabled(TFX_SPEC_SEEFLAG)) + if (!game_state.is_player && TFxEnabled(TFX_SPEC_SEEFLAG)) return TRUE; if (prematch && TFxEnabled(TFX_PREMATCH_EVERYTHING)) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c9639f5e..26707f57 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -148,12 +148,12 @@ static float CalcPredEnabled(float current_enable, float cvar, return FALSE; } - if (is_spectator) { + if (game_state.is_spectator) { *set_by = "[spectator]"; return FALSE; } - if (is_observer) { + if (game_state.is_observer) { *set_by = "[observer]"; return FALSE; } @@ -327,7 +327,7 @@ void WPP_UpdateEnable(float force) { static float once; if (wp_new != pengine.wp_enabled || !once) { - if (!CVARF(fo_predict_projectiles) && is_player) + if (!CVARF(fo_predict_projectiles) && game_state.is_player) printf("FortressOne: Weapon prediction (no projectiles) %s %s\n", wp_new ? "enabled" : "disabled", wp_source); pengine.wp_enabled = wp_new; @@ -343,7 +343,7 @@ void WPP_UpdateEnable(float force) { } if (pp_new != pengine.pp_enabled || !once) { - if (is_player) + if (game_state.is_player) printf("FortressOne: Weapon/Projectile prediction %s %s\n", pp_new ? "enabled" : "disabled", pp_source); pengine.pp_enabled = pp_new; @@ -372,10 +372,6 @@ void WPP_UpdateEnable(float force) { WP_UpdateViewModel(); } -void WP_PlayerTransition() { - WPP_UpdateEnable(TRUE); -} - DEFCVAR_FLOAT(fo_minping_min, 0); // Can be used to set a lower-bound on // what minping will be chosen. DEFCVAR_FLOAT(cl_delay_packets, 0); // Can be used to query, but not set. @@ -474,7 +470,7 @@ void UpdateMinPing() { static float num_samples; static float ping_cache[PING_SAMPLES]; - if (time < next_ping_update || !is_player) + if (time < next_ping_update || !game_state.is_player) return; next_ping_update = time + 0.2; @@ -651,7 +647,7 @@ static float AmmoToStat(float ammo_type) { } float WP_GetAmmo(float ammo_type) { - if (!WP_Enabled() || !is_alive) + if (!WP_Enabled() || !game_state.is_alive) return getstatf(AmmoToStat(ammo_type)); if (ammo_type == AMMO_NONE) @@ -1201,7 +1197,7 @@ void FO_ApplyMaxSpeed() { DEFCVAR_FLOAT(cl_crossx, 0); void WP_Frame() { - if (!is_alive) { + if (!game_state.is_alive) { pstate_pred.current_slot = SlotNull; return; } @@ -1542,7 +1538,7 @@ static float CanThrowGrenade(int gren_type) { void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); static void W_PrimeGren(float index) { - if (!is_alive || getstatf(STAT_NOFIRE)) + if (!game_state.is_alive || getstatf(STAT_NOFIRE)) return; if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) @@ -1959,3 +1955,10 @@ void InitWeapPredEnt(entity pe) { wp_ready = TRUE; } + +void WP_ServerFrame() { + if (game_state.is_player != prev_game_state.is_player) + WPP_UpdateEnable(TRUE); + +} + diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 17057224..c0c90896 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1352,7 +1352,7 @@ void () TeamFortress_SetHealth = { else self.max_health = PC_ENGINEER_MAXHEALTH; } else { - self.max_health = 1; + self.max_health = 0; self.takedamage = DAMAGE_NO; } self.health = self.max_health; From 1dfe655112810a5594e86093b837b3fb34dce771 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 11 Sep 2023 16:47:14 -0700 Subject: [PATCH 2166/2474] stat: add a counter for spawn generation Add a generation counter for alive/death states. Works with things like suicide which can occur in single frame. Also a tiny bit of deadflags cleanup. --- csqc/csextradefs.qc | 1 + csqc/main.qc | 1 + csqc/weapon_predict.qc | 2 -- share/defs.h | 1 + ssqc/client.qc | 9 +++++---- ssqc/player.qc | 5 +++-- ssqc/qw.qc | 2 ++ ssqc/spy.qc | 2 +- ssqc/world.qc | 1 + 9 files changed, 15 insertions(+), 9 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 8ec91e26..fb42045d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -872,6 +872,7 @@ struct GameState { float is_alive; float is_observer; float is_spectator; + float spawn_gen; }; GameState game_state, prev_game_state; diff --git a/csqc/main.qc b/csqc/main.qc index 72c644ee..0f9c0764 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -696,6 +696,7 @@ void _Sync_ServerCommandFrame() { // Note: When spectating someone, refers to them. game_state.is_alive = getstatf(STAT_HEALTH) >= 0; + game_state.spawn_gen = getstatf(STAT_SPAWN_GEN); WP_ServerFrame(); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 26707f57..7ab59668 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1959,6 +1959,4 @@ void InitWeapPredEnt(entity pe) { void WP_ServerFrame() { if (game_state.is_player != prev_game_state.is_player) WPP_UpdateEnable(TRUE); - } - diff --git a/share/defs.h b/share/defs.h index d2d45042..5419a21d 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1497,6 +1497,7 @@ enumflags { #define STAT_NOFIRE 41 #define STAT_TEAMNO_ATTACK 42 #define STAT_ALL_TIME 43 +#define STAT_SPAWN_GEN 44 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/client.qc b/ssqc/client.qc index f2fcb96d..74351237 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2041,6 +2041,8 @@ void () PutClientInServer = { local entity spot; local entity te; + self.spawn_gen += 1; + self.touch = player_touch; self.classname = "player"; self.health = 100; @@ -2458,8 +2460,7 @@ void () PlayerDeathThink = { if (self.button2 || self.button1 || self.button0) return; self.deadflag = DEAD_RESPAWNABLE; - self.tfstate = - self.tfstate - (self.tfstate & TFSTATE_RESPAWN_READY); + self.tfstate &= ~TFSTATE_RESPAWN_READY; return; } if ((!self.button2 && !self.button1) && !self.button0) { @@ -2705,7 +2706,7 @@ void () PlayerPreThink = { WaterMove(); } - if (self.deadflag >= 2) { + if (self.deadflag >= DEAD_DEAD) { PlayerDeathThink(); return; } @@ -2717,7 +2718,7 @@ void () PlayerPreThink = { Spy_RemoveDisguise(self); } } - if (self.deadflag == 1) { + if (self.deadflag == DEAD_DYING) { return; } diff --git a/ssqc/player.qc b/ssqc/player.qc index ab06442d..dfa1d07e 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -402,7 +402,7 @@ void (string gibname) HeadShotThrowHead = { }; void () KillPlayer = { - self.owner.deadflag = 2; + self.owner.deadflag = DEAD_DEAD; dremove(self); }; @@ -417,7 +417,7 @@ void () GibPlayer = { newmis.think = KillPlayer; newmis.nextthink = time + 1; } else { - self.deadflag = 2; + self.deadflag = DEAD_DEAD; } TeamFortress_SetupRespawn(0); if (damage_attacker.classname == "teledeath") { @@ -438,6 +438,7 @@ void () GibPlayer = { }; void () PlayerDie = { + self.spawn_gen += 1; UpdateClientPlayerDie(self); local float i; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index dae19a25..cc9cbee3 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -684,6 +684,8 @@ float intermission_exittime; .entity last_spawn_spot; .float spawn_at_last_spawn_spot; +.float spawn_gen; + .float max_grenades_1; .float max_grenades_2; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 78aab175..96c3dd00 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -92,7 +92,7 @@ void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch = { void () CF_Spy_AirThink = { local float area_check = 0; - if(self.owner.deadflag >= 2) { + if(self.owner.deadflag >= DEAD_DEAD) { // reset the movetype just in case you die while in the TOSS or the WALK states (eg mbasesr lift squish) self.owner.movetype = MOVETYPE_NONE; self.owner.tfstate |= TFSTATE_CANT_MOVE; diff --git a/ssqc/world.qc b/ssqc/world.qc index a4483e47..2c60fd4e 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -335,6 +335,7 @@ void () worldspawn = { clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); clientstat(STAT_TP_GREN1, EV_FLOAT, tp_grenades_1); clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); + clientstat(STAT_SPAWN_GEN,EV_FLOAT, spawn_gen); globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused"); globalstat(STAT_NOFIRE, EV_FLOAT, "no_fire_mode"); From a075101d66041b521803c87706f1faee154b35e6 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 12 Sep 2023 11:12:21 -0700 Subject: [PATCH 2167/2474] wp: don't predict primes when out of grenades Check local grenade counts before doing local prime prediction. --- csqc/weapon_predict.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 7ab59668..38d914bd 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1544,7 +1544,11 @@ static void W_PrimeGren(float index) { if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED) return; - index -= 1; + index -= 1; // We work with zero-based index here. + float stat = index == 0 ? STAT_NO_GREN1 : STAT_NO_GREN2; + if (getstatf(stat) < 1) + return; // No grenades left + float gren = FO_ClassGren(pstate_pred.playerclass, index)->id; pstate_pred.tfstate |= (index ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED); From 22868e3f857651faf9a5c52e64a026d2da3f700f Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 9 Sep 2023 02:29:37 -0700 Subject: [PATCH 2168/2474] spec: render grenade timer and play sounds Deliver grenade information to spectators* so that the hud grenade timers are synchronized with the watched player. *: technically removing _NOSPEC should have gone a lot of the way with the prior implementation, however these don't seem to work correctly for unknown reasons. We want this for TFX stuff anyway so just try the broadcast approach. We should be able to avoid need for reliable transmit with local gren timers also. --- csqc/csextradefs.qc | 1 - csqc/events.qc | 16 +++++++++------- csqc/weapon_predict.qc | 6 ++++++ share/commondefs.qc | 15 +++++++-------- ssqc/player.qc | 1 - ssqc/status.qc | 22 ++++++---------------- 6 files changed, 28 insertions(+), 33 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index fb42045d..5bdd5062 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -885,7 +885,6 @@ float painfinished; vector thisorigin; float jump_counter; float grentimer_waiting; -float last_death_time; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/events.qc b/csqc/events.qc index 3b7ea1d2..2ff70c41 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -102,19 +102,24 @@ void() CSQC_Parse_Event = { SBAR.Identify = readstring(); break; case MSG_GRENPRIMED: + float entno = readentitynum(); float grentype = readbyte(); float primed_at = readfloat(); float explodes_at = readfloat(); + + if (entno != player_localentnum) + return; + ParseGrenPrimed(grentype, primed_at, explodes_at); break; case MSG_GRENTHROWN: + float entno = readentitynum(); + if (entno != player_localentnum) + return; + CsGrenTimer last = CsGrenTimer::GetLast(); last.set_thrown(); break; - case MSG_PLAYERDIE: - last_death_time = readfloat(); - StopGrenTimers(); - break; case MSG_TFX_GRENTIMER: float entnum = readentitynum(); float explodes_at = readfloat(); @@ -423,9 +428,6 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) return; - if (primed_at < last_death_time) - return; - // Very rough (but good enough for now) filter to disambiguate local // predicted primes versus matched server primes. static float last_explodes_at; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 38d914bd..a371f3ab 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1960,7 +1960,13 @@ void InitWeapPredEnt(entity pe) { wp_ready = TRUE; } +void StopGrenTimers(); + void WP_ServerFrame() { if (game_state.is_player != prev_game_state.is_player) WPP_UpdateEnable(TRUE); + + if (game_state.spawn_gen != prev_game_state.spawn_gen && + game_state.is_alive) + StopGrenTimers(); } diff --git a/share/commondefs.qc b/share/commondefs.qc index f5716ebf..2565f8a3 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -208,14 +208,13 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_VOTE_UPDATE 19 #define MSG_VOTE_MAP_ADD 20 #define MSG_VOTE_MAP_DELETE 21 -#define MSG_PLAYERDIE 22 -#define MSG_PAUSE 23 -#define MSG_UNPAUSE 24 -#define MSG_TFX_GRENTIMER 25 -#define MSG_QUAD_ROUND_BEGIN 26 -#define MSG_LOGIN 27 -#define MSG_HITFLAG 28 -#define MSG_RELOADSOUND 29 +#define MSG_PAUSE 22 +#define MSG_UNPAUSE 23 +#define MSG_TFX_GRENTIMER 24 +#define MSG_QUAD_ROUND_BEGIN 25 +#define MSG_LOGIN 26 +#define MSG_HITFLAG 27 +#define MSG_RELOADSOUND 28 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/player.qc b/ssqc/player.qc index dfa1d07e..1abfe018 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -439,7 +439,6 @@ void () GibPlayer = { void () PlayerDie = { self.spawn_gen += 1; - UpdateClientPlayerDie(self); local float i; local entity te; diff --git a/ssqc/status.qc b/ssqc/status.qc index be19a8b8..7a046df5 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -790,40 +790,30 @@ void UpdateClientReloadSound(entity pl, float weapon) { } void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); + WriteEntity(MSG_MULTICAST, pl); WriteByte(MSG_MULTICAST, grentype); WriteFloat(MSG_MULTICAST, time); WriteFloat(MSG_MULTICAST, explodes_at); - multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); + + // Let's see if we can get away with avoiding _R here. + multicast('0 0 0', MULTICAST_ALL); TFxUpdateGrenadeTimer(pl, explodes_at); } void UpdateClientGrenadeThrown(entity pl) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENTHROWN); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + WriteEntity(MSG_MULTICAST, pl); + multicast('0 0 0', MULTICAST_ALL); TFxUpdateGrenadeTimer(pl, 0); } -void UpdateClientPlayerDie(entity pl) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_PLAYERDIE); - WriteFloat(MSG_MULTICAST, time); - multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); -} - void UpdateClientIDString(entity pl) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From 4c71f0e31c2a843fa38a2d4eac6d6a107a6c57b0 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 12 Sep 2023 11:45:09 -0700 Subject: [PATCH 2169/2474] wp: make sure we start with rendering engine models There appears to be some latent lurking non-csqc issue where the first player into a server isnt getting something set right here but any action (spawn/change weapon/reload/etc) clears this up. --- csqc/main.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index 0f9c0764..fb479a63 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -168,6 +168,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { ClientSettings_Check(); SetupAliases(); + + pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. print("CSQC initialization finished\n"); }; From ea187ab1018a4e1c354c534865945aa50e2a16f0 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 12 Sep 2023 13:07:56 -0700 Subject: [PATCH 2170/2474] rewind: use rewind positions during physics updates The QW protocol is fairly asynchronous in its event ordering; with much being driven off new player packets rather than constant time boundaries. Try using rewind positions in projectile travel to improve/make registration more consistent. --- share/commondefs.qc | 9 ++++++--- share/physics.qc | 4 ++-- share/prediction.qc | 22 +++++++++++++++++++++- ssqc/rewind.qc | 29 ++++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 2565f8a3..49f084aa 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -49,7 +49,8 @@ var struct { } fo_config; enumflags { - REWIND_PROJ_HIT, + REWIND_PROJ_FIRE, + REWIND_PROJ_TRAVEL, REWIND_KNOCKBACK, REWIND_SETSPEED, REWIND_GRENADES, @@ -58,7 +59,8 @@ enumflags { }; string REWIND_DESC[] = { - "rewind projectile hit", + "rewind projectile on firing", + "rewind on projectile travel", "rewind pipe knockback", "allow csqc to handle maxspeed", "rewind grenade throws", @@ -66,7 +68,8 @@ string REWIND_DESC[] = { "open doors earlier for hpbs [requires rfd=1]", }; -const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_HIT | +const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_FIRE | + REWIND_PROJ_TRAVEL | REWIND_FORWARD_PROJ_SELFKNOCK | REWIND_SETSPEED; diff --git a/share/physics.qc b/share/physics.qc index ce15c501..6d151403 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -195,7 +195,7 @@ float Phys_Adv_Linear(entity e, float dt, float phys_flags) { return dt; } -var void(entity e, float step) RewindSyncTime; +var void(entity e, float target_time) RewindSyncTime; static void Phys_CapVel(entity e) { static const float limit = 32 / phys_tic; @@ -233,7 +233,7 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { step = min(phys_tic, delta); if (phys_flags & PHYSF_REWIND_PLAYERS) - RewindSyncTime(e, step); + RewindSyncTime(e, e.phys_time + step/2); if (IsClownMode(CLOWN_PROJ_GRAVITY)) e.velocity_z += -fo_config.clown_grav * step; diff --git a/share/prediction.qc b/share/prediction.qc index 9f167982..384ba8c8 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -767,9 +767,29 @@ void WeaponPred_DoServerClientThink() { } } +void ProjRewindForTravel(entity e, float target_time); +void NoRewindSyncFn(entity e, float target_time); +void RW_StashAll(); +void RW_RestoreAll(); + void FO_CustomPhysics() { if (!self.voided) { - Phys_Advance(self, time, 0); + float physf = 0; + if (RewindFlagEnabled(REWIND_PROJ_TRAVEL)) { + // This is a little inside out, it would be nice to do this by time + // then by projectile/player, but structure makes that difficult + // without more aggressive change. + RW_StashAll(); + physf = PHYSF_REWIND_PLAYERS; + RewindSyncTime = ProjRewindForTravel; + } + + Phys_Advance(self, time, physf); + + if (RewindFlagEnabled(REWIND_PROJ_TRAVEL)) { + RewindSyncTime = NoRewindSyncFn; + RW_RestoreAll(); + } // Moving platforms don't get properly reflected into the entities CSQC // sees so just blast the client with updates when on one (in motion). diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index e2b63d54..1e7db4a7 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -274,6 +274,20 @@ class FOPlayer { }; }; +// TODO: untangle and decide whether the class stuff is adding any value +void RW_RewindAll(float when) { + FOPlayer::RewindAll(when); +} + +void RW_StashAll() { + RL_StashPositions(rewind_players); +} + +void RW_RestoreAll() { + FOPlayer::RestoreAll(); + +} + float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float RewindPlayersExceptSelf(float farthest_rewind_point) { @@ -296,8 +310,16 @@ float RewindPlayersExceptSelf(float farthest_rewind_point) { return TRUE; } -void ProjRewindForPhys(entity e, float step) { - RL_RewindTo(rewind_players, e.owner, e.phys_time + step / 2); +void ProjRewindForTravel(entity e, float target_time) { + RL_RewindTo(rewind_players, world, target_time); +} + +void ProjRewindForPhys(entity e, float target_time) { + RL_RewindTo(rewind_players, e.owner, target_time); +} + +void NoRewindSyncFn(entity e, float target_time) { + error("not set\n"); } void Forward_Projectile(int fpp_type, entity proj) { @@ -312,7 +334,7 @@ void Forward_Projectile(int fpp_type, entity proj) { float stime = time - dynamic_dt; float no_rewind = proj.fpp.flags & FPF_NO_REWIND; - float rewind_hit = !no_rewind && RewindFlagEnabled(REWIND_PROJ_HIT); + float rewind_hit = !no_rewind && RewindFlagEnabled(REWIND_PROJ_FIRE); float phys_flags = PHYSF_CONSUME_ALL; if (rewind_hit) { phys_flags |= PHYSF_REWIND_PLAYERS; @@ -337,6 +359,7 @@ void Forward_Projectile(int fpp_type, entity proj) { if (!proj.voided) { RewindSyncTime = ProjRewindForPhys; ft += Phys_Advance(proj, time, phys_flags); + RewindSyncTime = NoRewindSyncFn; } if (rewind_hit) From 7aef0434c5ee196713940ebd0b01898130258be1 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 12 Sep 2023 14:20:07 -0700 Subject: [PATCH 2171/2474] spec: handle throw without prime When spectating an already primed player, off a fresh connect, it's possible to get a throw message with no prime, meaning there's no last grenade timer to set thrown on. --- csqc/events.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/csqc/events.qc b/csqc/events.qc index 2ff70c41..f4fdd1bb 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -118,7 +118,10 @@ void() CSQC_Parse_Event = { return; CsGrenTimer last = CsGrenTimer::GetLast(); - last.set_thrown(); + // It's possible to get THROWN without PRIMED when spectating a + // player that primed before you started watching them. + if (last != world && last.active()) + last.set_thrown(); break; case MSG_TFX_GRENTIMER: float entnum = readentitynum(); From 58dac0544bf3af82e009ae980e9c0330cbae2dde Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 12 Sep 2023 14:48:01 -0700 Subject: [PATCH 2172/2474] csqc: unify is_player and is_observer No reason that I can tell for them to be separate and simplifies the code. --- csqc/csextradefs.qc | 1 - csqc/events.qc | 2 +- csqc/main.qc | 11 +++-------- csqc/status.qc | 2 +- csqc/weapon_predict.qc | 5 ----- 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 5bdd5062..8317b5e4 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -870,7 +870,6 @@ struct GameState { float localentnum; float is_player; float is_alive; - float is_observer; float is_spectator; float spawn_gen; }; diff --git a/csqc/events.qc b/csqc/events.qc index f4fdd1bb..6c01fd61 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -645,7 +645,7 @@ float(float ent_num, float channel, string soundname, float vol, float attenuati return 1; // Sounds from remote entities are not local and we should always play. - if (ent_num != player_localentnum || !game_state.is_player) + if (ent_num != player_localentnum || game_state.is_spectator) return 0; // Sounds below this line are conditionally filtered. diff --git a/csqc/main.qc b/csqc/main.qc index fb479a63..28988950 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -678,21 +678,16 @@ void _Sync_ServerCommandFrame() { team_no = getstatf(STAT_TEAMNO); all_time = getstatf(STAT_ALL_TIME); - game_state.is_observer = team_no == 0; player_class = getstatf(STAT_CLASS); SBAR.ReadyStatus = getstatf(STAT_FLAGS); game_state.localentnum = player_localentnum; - if (game_state.is_observer) { + if (team_no == 0 ||stof(getplayerkeyvalue(player_localnum, "*spectator"))) { + game_state.is_spectator = 1; game_state.is_player = 0; - if (stof(getplayerkeyvalue(player_localnum, "*spectator"))) { - game_state.is_spectator = 1; - game_state.is_observer = 0; - } else { - game_state.is_spectator = 0; - } } else { + game_state.is_spectator = 0; game_state.is_player = 1; } diff --git a/csqc/status.qc b/csqc/status.qc index c1487231..375da85a 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -750,7 +750,7 @@ vector drawShowScoresTeamPanel (FO_Hud_Panel *panel, FO_ScoreBoardTeam* team, position_x += strlen(FO_ScoreBoardColumns[col++]) * smalltext.x + padding; if (team_no == lines[i].team_no || lines[i].team_no == TEAM_SPECTATOR || lines[i].team_no == TEAM_OBSERVER - || !game_state.is_player) { + || game_state.is_spectator) { string c = lines[i].classtext; if (lines[i].team_no != TEAM_SPECTATOR && lines[i].team_no != TEAM_OBSERVER) { float cspace = strlen(c) * smalltext.x; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index a371f3ab..399a2c19 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -153,11 +153,6 @@ static float CalcPredEnabled(float current_enable, float cvar, return FALSE; } - if (game_state.is_observer) { - *set_by = "[observer]"; - return FALSE; - } - if (server_disable) { *set_by = "[server disable]"; return FALSE; From 66595794a732a5b68963af1e2255bf133651b93a Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 13 Sep 2023 16:17:15 -0700 Subject: [PATCH 2173/2474] quad: fix gameclock quad mode needs a bit of a rewrite quick and dirty update to make gameclock use a global stat field rather than messages which should keep it in much tighter sync. --- csqc/csextradefs.qc | 1 - csqc/events.qc | 1 - csqc/main.qc | 1 - csqc/status.qc | 29 ++++++++++++----------------- share/defs.h | 1 + ssqc/clan.qc | 1 + ssqc/csmenu.qc | 7 +------ ssqc/quadmode.qc | 10 +++------- ssqc/qw.qc | 1 + ssqc/world.qc | 3 +++ 10 files changed, 22 insertions(+), 33 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 8317b5e4..c43ee84c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -883,7 +883,6 @@ float player_class; float painfinished; vector thisorigin; float jump_counter; -float grentimer_waiting; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/events.qc b/csqc/events.qc index 6c01fd61..96fb22d5 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -318,7 +318,6 @@ void() CSQC_Parse_Event = { FO_Hud_ShowPanel(HUDP_MOTD); break; case MSG_QUAD_ROUND_BEGIN: - round_ending = readfloat() * 60 + time + 1; break; case MSG_TEAM_SCORES: TeamScore[0] = readfloat(); diff --git a/csqc/main.qc b/csqc/main.qc index 28988950..f80ab5f6 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -154,7 +154,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { CurrentMenu = &FO_MENU_TEAM; player_menu_type = 0; is_admin = FALSE; - grentimer_waiting = FALSE; jump_counter = 0; num_mapvotes = 0; diff --git a/csqc/status.qc b/csqc/status.qc index 375da85a..2f3e635d 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -302,27 +302,22 @@ string gameClockString() { float seconds = 0; float timelimit = stof(serverkey("timelimit")); - if(round_ending) { - float t = round_ending - time; - if(t < 0) t = t * -1; - minutes = floor(t/60); - seconds = floor(t - (minutes*60)); - } else if(timelimit) { - minutes = floor(time/60); - seconds = 60 - floor(time - (minutes*60)); - minutes = timelimit - ceil(time/60); - if(minutes < 0) minutes = minutes * -1; - if(seconds < 0) seconds = seconds * -1; + float end = getstatf(STAT_ROUND_END); + if (!end) + end = timelimit * 60; + + if (end) { + minutes = (end - time)/60; + seconds = (end - time)%60; } else { - minutes = floor(time/60); - seconds = floor(time - (minutes*60)); + minutes = time/60; + seconds = time%60; } - string sm = strcat((minutes<10?"0":""),ftos(minutes)); - string ss = strcat((seconds<10?"0":""),ftos(seconds)); + string sm = strcat((minutes<10?"0":""),ftos(floor(minutes))); + string ss = strcat((seconds<10?"0":""),ftos(floor(seconds))); - string tmp = strcat(sm,":",ss); - return tmp; + return strcat(sm,":",ss); }; static void(PanelID panelid, string text) doNothing = {}; diff --git a/share/defs.h b/share/defs.h index 5419a21d..a726a5d6 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1498,6 +1498,7 @@ enumflags { #define STAT_TEAMNO_ATTACK 42 #define STAT_ALL_TIME 43 #define STAT_SPAWN_GEN 44 +#define STAT_ROUND_END 45 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/clan.qc b/ssqc/clan.qc index d3448929..ce5140c1 100644 --- a/ssqc/clan.qc +++ b/ssqc/clan.qc @@ -434,6 +434,7 @@ void () StartTimer = if (timer.cnt2 < 1) { //By default, 10 seconds of countdown timer.cnt2 = 10; + round_end_time = time + 11; } timer.cnt2 = (timer.cnt2 + 1); timer.nextthink = (time + 0.1); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 7c22eaae..645dfbc1 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -272,14 +272,9 @@ void UpdateClientTeamScores(entity e) = { } void UpdateClientQuadRoundBegin(entity pl, float round_time) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - - msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_QUAD_ROUND_BEGIN); - WriteFloat(MSG_MULTICAST, round_time); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + multicast('0 0 0', MULTICAST_ALL_R); } void UpdateClientPrematch(entity pl, float countdownstarted) = { diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 7112320a..71b8e6e5 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -416,6 +416,7 @@ void () QuadRoundThink = { { local string st; st = ftos(round_delay_time); + round_end_time = time + round_delay_time + 1; bprint(2, "ROUND TIME OVER\nNext round begins in ", st, " seconds\n"); } @@ -503,13 +504,8 @@ void () QuadRoundBegin = { if (rounds == 1) PostFOQuadFinalRoundStarted(); - te = find(world, classname, "player"); - while (te) { - if(infokeyf(te, INFOKEY_P_CSQCACTIVE)) { - UpdateClientQuadRoundBegin(te, round_time); - } - te = find(te, classname, "player"); - } + round_end_time = time + round_time * 60 + 1; + UpdateClientQuadRoundBegin(te, round_time); if (!self.cnt) { self.cnt = stof(infokey (world, "round_time")) - 1; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index cc9cbee3..5d280f26 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -469,6 +469,7 @@ float rounds; float round_active; float round_over; float round_delay_time; +float round_end_time; float map_restart_time; float gametime; float is_countdown; diff --git a/ssqc/world.qc b/ssqc/world.qc index 2c60fd4e..89aef213 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -91,6 +91,8 @@ void () worldspawn = { WriteByte(MSG_INIT, 9/*svc_stufftext*/); WriteString(MSG_INIT, "set fo_serverscripts 1\n"); + round_end_time = 0; + vote_started = -1; local string st; @@ -337,6 +339,7 @@ void () worldspawn = { clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); clientstat(STAT_SPAWN_GEN,EV_FLOAT, spawn_gen); + globalstat(STAT_ROUND_END, EV_FLOAT, "round_end_time"); globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused"); globalstat(STAT_NOFIRE, EV_FLOAT, "no_fire_mode"); globalstat(STAT_TEAMNO_ATTACK, EV_FLOAT, "team_no_attack"); From 0743777101992c53d0834f0d98fca236a24b3650 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 13 Sep 2023 16:20:22 -0700 Subject: [PATCH 2174/2474] hud: expire ident string clientside Expire ident after 5s, don't depend on a new null string from server. --- csqc/csextradefs.qc | 1 + csqc/events.qc | 1 + csqc/status.qc | 3 +++ ssqc/status.qc | 12 ++++++------ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c43ee84c..bdee9a62 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -883,6 +883,7 @@ float player_class; float painfinished; vector thisorigin; float jump_counter; +float last_id_time; vector FO_Hud_Icon_Size = [24, 24, 0]; vector FO_Hud_Icon_Font_Size = [8, 8, 0]; diff --git a/csqc/events.qc b/csqc/events.qc index 96fb22d5..eb78eeb5 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -99,6 +99,7 @@ void() CSQC_Parse_Event = { ParseSBAR(); break; case MSG_ID: + last_id_time = time; SBAR.Identify = readstring(); break; case MSG_GRENPRIMED: diff --git a/csqc/status.qc b/csqc/status.qc index 2f3e635d..6d752dd9 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -17,6 +17,9 @@ void(PanelID ignored, string text) drawClipSize = { }; void(PanelID ignored, string text) drawIdentify = { + if (time > last_id_time + 5) + return; + if (strlen(text) > 0 || fo_hud_editor) Hud_DrawIdentifyPanel(text); }; diff --git a/ssqc/status.qc b/ssqc/status.qc index 7a046df5..81f65102 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -815,20 +815,20 @@ void UpdateClientGrenadeThrown(entity pl) = { } void UpdateClientIDString(entity pl) { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - string ident = time < pl.ident_time ? pl.ident_string : ""; - // only send updates - if (ident == pl.last_ident_string) + + if (ident == pl.last_ident_string) // only send updates return; pl.last_ident_string = ident; + if (ident == "") // No need to send null, we'll expire clientside. + return; + msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_ID); WriteString(MSG_MULTICAST, ident); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); + multicast('0 0 0', MULTICAST_ONE); } void UpdateClientStatusBar(entity pl) From 5fb6eac8a1377212ce75c10ce867f0bd0c5efa51 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 13 Sep 2023 16:28:23 -0700 Subject: [PATCH 2175/2474] quad: send 2v2 to scrim results for now Miami doesn't have the right ports and people are inconsistent so just do it automagically for 2v2 (or 1v1 which has also happened). --- ssqc/quadmode.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 71b8e6e5..787807b2 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -10,6 +10,11 @@ void () PostFOQuadStarted = { return; } + // Override 2v2 to go to scrim results for now. + string channel_id = discord_channel_id; + if (TeamFortress_TeamGetNoPlayersExcludingAllTime(1) <= 2) + channel_id = "1147341454851719219"; + local string data = ""; data = strcat(data, "{\n"); @@ -35,7 +40,7 @@ void () PostFOQuadStarted = { data = strcat(data, " \"address\": \"", cvar_string("sv_serverip"), "\"\n"); data = strcat(data, " },\n"); data = strcat(data, " \"discord_channel\": {\n"); - data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); + data = strcat(data, " \"channel_id\": \"", channel_id, "\"\n"); data = strcat(data, " },\n"); data = strcat(data, " \"teams\": {\n"); From 1c44f1845aa80f2ff71755e3952f363e19994d53 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 13 Sep 2023 21:55:00 -0700 Subject: [PATCH 2176/2474] wp: fix is_alive to be health>0 Refactoring accidentally had this as >= 0 --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index f80ab5f6..f43946cc 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -691,7 +691,7 @@ void _Sync_ServerCommandFrame() { } // Note: When spectating someone, refers to them. - game_state.is_alive = getstatf(STAT_HEALTH) >= 0; + game_state.is_alive = getstatf(STAT_HEALTH) > 0; game_state.spawn_gen = getstatf(STAT_SPAWN_GEN); WP_ServerFrame(); From 0d9a732a59224bcdbe95763f6749463cfdeaf89a Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 12 Sep 2023 17:23:51 -0700 Subject: [PATCH 2177/2474] grenades: deprecate legacy GR_GREN defines unify on GREN_ enum, update old call sites, remove conversions deprecate legacy grenade switch functionality remove STAT_ communication of grenade types --- csqc/csextradefs.qc | 17 ---- csqc/events.qc | 4 +- csqc/status.qc | 16 ++-- csqc/weapon_predict.qc | 2 +- share/defs.h | 65 ++++++--------- share/weapons.qc | 59 +++++--------- ssqc/items.qc | 36 +-------- ssqc/tfort.qc | 174 +++++++++++++---------------------------- ssqc/weapons.qc | 5 +- ssqc/world.qc | 2 - 10 files changed, 111 insertions(+), 269 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index bdee9a62..1b7e6c0a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -233,23 +233,6 @@ FO_Hud_Icons HudIcons2[39] = { {"textures/wad/anum_percent"} }; -FO_Hud_Icons GrenadeIcons[14] = { - {ICON_GREN_NONE}, - {ICON_GREN_NORMAL}, - {ICON_GREN_CONCUSSION}, - {ICON_GREN_NAIL}, - {ICON_GREN_MIRV}, - {ICON_GREN_NAPALM}, - {ICON_GREN_FLARE}, - {ICON_GREN_GAS}, - {ICON_GREN_EMP}, - {ICON_GREN_FLASH}, - {ICON_GREN_CALTROP}, - {ICON_GREN_BLAST}, - {ICON_GREN_SHOCK}, - {ICON_GREN_BURST}, -}; - FO_Hud_Icons FaceIcons[] = { //normal {"textures/wad/face1"}, diff --git a/csqc/events.qc b/csqc/events.qc index eb78eeb5..39a9c888 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -405,7 +405,7 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, if (this.flags_ & FL_GT_ADJPING) { float rtt = pstate_pred.client_ping * CVARF(fo_grentimer_ping_frac); if (RewindFlagEnabled(REWIND_GRENADES)) - rtt = max(0, rtt - (100 + FO_RewindGrenMs(TF_GREN_conv(_grentype)))); + rtt = max(0, rtt - (100 + FO_RewindGrenMs(_grentype))); expires_at_ -= rtt / 1000; } @@ -428,7 +428,7 @@ void StopGrenTimers() { } void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { - if (grentype == GR_TYPE_FLARE || grentype == GR_TYPE_CALTROP) + if (grentype == GREN_FLARE || grentype == GREN_CALTROP) return; // Very rough (but good enough for now) filter to disambiguate local diff --git a/csqc/status.qc b/csqc/status.qc index 6d752dd9..abd07a2e 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -49,26 +49,22 @@ void(PanelID ignored, string text) drawCapsPanel = { }; void(PanelID panelid, string text) drawGren1Panel = { - local float playerclass = SBAR.PlayerClass; + float playerclass = SBAR.PlayerClass; if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) return; - local float gren_type = getstatf(STAT_TP_GREN1); - local string icon = GrenadeIcons[gren_type].icon; - + string icon = FO_ClassGren(playerclass, 0)->icon; drawIconPanel(HUDP_GREN1, text, icon); }; void(PanelID ignored, string text) drawGren2Panel = { - local float playerclass = SBAR.PlayerClass; + float playerclass = SBAR.PlayerClass; if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) return; - local float gren_type = getstatf(STAT_TP_GREN2); - local string icon = GrenadeIcons[gren_type].icon; - + string icon = FO_ClassGren(playerclass, 1)->icon; drawIconPanel(HUDP_GREN2, text, icon); }; @@ -114,8 +110,8 @@ void(PanelID panelid, string text) drawGrenTimerPanel = { // grenade primed, we can obscure this by always considering // grenades after the first as primed. float alpha = (gt.is_thrown() || timercount) ? 0.3 : 1.0; - Hud_DrawPanelLMP(&panel2, ftos(timeleft), - GrenadeIcons[gt.grentype()].icon, alpha); + string icon = FO_GrenDesc(gt.grentype())->icon; + Hud_DrawPanelLMP(&panel2, ftos(timeleft), icon, alpha); panel2.Position = panel2.Position + [0, panel2.FillSize.y * panel2.Scale]; timercount++; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 399a2c19..73d70eff 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1548,7 +1548,7 @@ static void W_PrimeGren(float index) { pstate_pred.tfstate |= (index ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED); if (IsEffectFrame()) - ParseGrenPrimed(gren - GREN_FIRST + 1, time, time + 3.8); + ParseGrenPrimed(gren, time, time + 3.8); } static void W_ThrowGren(float is_throw) { diff --git a/share/defs.h b/share/defs.h index a726a5d6..4af5458a 100644 --- a/share/defs.h +++ b/share/defs.h @@ -418,7 +418,7 @@ struct Slot { int id; }; #define TF_GRENADE_T 16 // Throw primed grenade #define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) #define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) -#define TF_GRENADE_SWITCH 19 // Switch grenade mode 1/2 +// unused #define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon #define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon #define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon @@ -796,24 +796,6 @@ enumflags { // Tranquiliser Gun #define TRANQ_TIME 15 -// Grenades -#define GR_PRIMETIME 3 - -#define GR_TYPE_NONE 0 -#define GR_TYPE_NORMAL 1 -#define GR_TYPE_CONCUSSION 2 -#define GR_TYPE_NAIL 3 -#define GR_TYPE_MIRV 4 -#define GR_TYPE_NAPALM 5 -#define GR_TYPE_FLARE 6 -#define GR_TYPE_GAS 7 -#define GR_TYPE_EMP 8 -#define GR_TYPE_FLASH 9 -#define GR_TYPE_CALTROP 10 -#define GR_TYPE_BLAST 11 -#define GR_TYPE_SHOCK 12 -#define GR_TYPE_BURST 13 - // Defines for NailGren Types #define NGR_TYPE_NAIL 0 #define NGR_TYPE_LASER 1 @@ -906,7 +888,7 @@ enumflags { #define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned #define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned /* #define PC_SCOUT_GRENADE_TYPE_1 // Configured in TeamFortress_SetEquipment() */ -#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has +#define PC_SCOUT_GRENADE_TYPE_2 GREN_CONC // <- 2nd Type of Grenade this class has #define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned #define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned #define PC_SCOUT_GRENADE_MAX_1 3 @@ -934,8 +916,8 @@ enumflags { #define PC_SNIPER_INITAMMO_NAIL 50 #define PC_SNIPER_INITAMMO_CELL 0 #define PC_SNIPER_INITAMMO_ROCKET 0 -#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_FLARE +#define PC_SNIPER_GRENADE_TYPE_1 GREN_NORMAL +#define PC_SNIPER_GRENADE_TYPE_2 GREN_FLARE #define PC_SNIPER_GRENADE_INIT_1 2 #define PC_SNIPER_GRENADE_INIT_2 3 #define PC_SNIPER_GRENADE_MAX_1 4 @@ -962,7 +944,7 @@ enumflags { #define PC_SOLDIER_INITAMMO_NAIL 0 #define PC_SOLDIER_INITAMMO_CELL 0 #define PC_SOLDIER_INITAMMO_ROCKET 10 -#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SOLDIER_GRENADE_TYPE_1 GREN_NORMAL /* #define PC_SOLDIER_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_SOLDIER_GRENADE_INIT_1 4 #define PC_SOLDIER_GRENADE_INIT_2 1 @@ -991,8 +973,8 @@ enumflags { #define PC_DEMOMAN_INITAMMO_CELL 0 #define PC_DEMOMAN_INITAMMO_ROCKET 20 #define PC_DEMOMAN_INITAMMO_DETPACK 1 -#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_DEMOMAN_GRENADE_TYPE_1 GREN_NORMAL +#define PC_DEMOMAN_GRENADE_TYPE_2 GREN_MIRV #define PC_DEMOMAN_GRENADE_INIT_1 4 #define PC_DEMOMAN_GRENADE_INIT_2 4 #define PC_DEMOMAN_GRENADE_MAX_1 4 @@ -1020,7 +1002,7 @@ enumflags { #define PC_MEDIC_INITAMMO_CELL 0 #define PC_MEDIC_INITAMMO_ROCKET 0 #define PC_MEDIC_INITAMMO_MEDIKIT 50 -#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_MEDIC_GRENADE_TYPE_1 GREN_NORMAL /* #define PC_MEDIC_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_MEDIC_GRENADE_INIT_1 3 #define PC_MEDIC_GRENADE_INIT_2 3 @@ -1058,8 +1040,8 @@ enumflags { #define PC_HVYWEAP_INITAMMO_NAIL 0 #define PC_HVYWEAP_INITAMMO_CELL 30 #define PC_HVYWEAP_INITAMMO_ROCKET 0 -#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_HVYWEAP_GRENADE_TYPE_1 GREN_NORMAL +#define PC_HVYWEAP_GRENADE_TYPE_2 GREN_MIRV #define PC_HVYWEAP_GRENADE_INIT_1 4 #define PC_HVYWEAP_GRENADE_INIT_2 1 #define PC_HVYWEAP_GRENADE_MAX_1 4 @@ -1086,8 +1068,8 @@ enumflags { #define PC_PYRO_INITAMMO_NAIL 0 #define PC_PYRO_INITAMMO_CELL 120 #define PC_PYRO_INITAMMO_ROCKET 15 -#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM +#define PC_PYRO_GRENADE_TYPE_1 GREN_NORMAL +#define PC_PYRO_GRENADE_TYPE_2 GREN_NAPALM #define PC_PYRO_GRENADE_INIT_1 1 #define PC_PYRO_GRENADE_INIT_2 4 #define PC_PYRO_GRENADE_MAX_1 4 @@ -1124,8 +1106,8 @@ enumflags { #define PC_SPY_INITAMMO_NAIL 50 #define PC_SPY_INITAMMO_CELL 10 #define PC_SPY_INITAMMO_ROCKET 0 -#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS +#define PC_SPY_GRENADE_TYPE_1 GREN_NORMAL +#define PC_SPY_GRENADE_TYPE_2 GREN_GAS #define PC_SPY_GRENADE_INIT_1 2 #define PC_SPY_GRENADE_INIT_2 2 #define PC_SPY_GRENADE_MAX_1 4 @@ -1155,8 +1137,8 @@ enumflags { #define PC_ENGINEER_INITAMMO_NAIL 25 #define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal #define PC_ENGINEER_INITAMMO_ROCKET 0 -#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP +#define PC_ENGINEER_GRENADE_TYPE_1 GREN_NORMAL +#define PC_ENGINEER_GRENADE_TYPE_2 GREN_EMP #define PC_ENGINEER_GRENADE_INIT_1 2 #define PC_ENGINEER_GRENADE_INIT_2 2 #define PC_ENGINEER_GRENADE_MAX_1 4 @@ -1491,14 +1473,12 @@ enumflags { #define STAT_CLASS 35 #define STAT_NO_GREN1 36 #define STAT_NO_GREN2 37 -#define STAT_TP_GREN1 38 -#define STAT_TP_GREN2 39 -#define STAT_PAUSED 40 -#define STAT_NOFIRE 41 -#define STAT_TEAMNO_ATTACK 42 -#define STAT_ALL_TIME 43 -#define STAT_SPAWN_GEN 44 -#define STAT_ROUND_END 45 +#define STAT_PAUSED 38 +#define STAT_NOFIRE 39 +#define STAT_TEAMNO_ATTACK 40 +#define STAT_ALL_TIME 41 +#define STAT_SPAWN_GEN 42 +#define STAT_ROUND_END 43 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this @@ -1623,7 +1603,6 @@ TFAlias client_aliases[] = { {"reload2", TF_RELOAD_SLOT2}, {"reload3", TF_RELOAD_SLOT3}, {"reloadnext", TF_RELOAD_NEXT}, - {"grenswitch", TF_GRENADE_SWITCH}, {"throwgren", TF_GRENADE_T}, {"primeone", TF_GRENADE_1}, {"primetwo", TF_GRENADE_2}, diff --git a/share/weapons.qc b/share/weapons.qc index 09cef9de..eacd27b6 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -157,33 +157,12 @@ enum { GREN_NONE, }; -// TODO: Just remove this legacy encoding. -int TF_GREN_conv(int tf_gren) { - switch (tf_gren) { - case GR_TYPE_NORMAL: return GREN_NORMAL; - case GR_TYPE_CONCUSSION: return GREN_CONC; - case GR_TYPE_BLAST: return GREN_BLAST; - case GR_TYPE_NAIL: return GREN_NAIL; - case GR_TYPE_SHOCK: return GREN_SHOCK; - case GR_TYPE_BURST: return GREN_BURST; - case GR_TYPE_MIRV: return GREN_MIRV; - case GR_TYPE_NAPALM: return GREN_NAPALM; - case GR_TYPE_FLARE: return GREN_FLARE; - case GR_TYPE_GAS: return GREN_GAS; - case GR_TYPE_EMP: return GREN_EMP; - case GR_TYPE_FLASH: return GREN_FLASH; - case GR_TYPE_CALTROP: return GREN_CALTROP; - }; - - error("unrecognized grenade type"); - return -1; -} - struct FO_GrenInfo { int id; string logname; string model; int skin; + string icon; vector avelocity; // Automatically initialized below this line. @@ -191,22 +170,22 @@ struct FO_GrenInfo { }; FO_GrenInfo fo_grenades[] = { - { GREN_NORMAL, "normal", "hgren2.mdl", 0, '300 300 300',}, - { GREN_CONC, "concussion", "hgren2.mdl", 1, '300 300 300'}, - { GREN_BLAST, "blast", "blastgren.mdl", 1, '300 300 300'}, - { GREN_NAIL, "nail", "biggren.mdl", 1, '0 300 0'}, - { GREN_SHOCK, "shock", "biggren.mdl", 1, '0 300 0'}, - { GREN_BURST, "burst", "biggren.mdl", 1, '0 300 0'}, - { GREN_MIRV, "mirv", "biggren.mdl", 0, '0 300 0'}, - { GREN_NAPALM, "napalm", "biggren.mdl", 2, '0 300 0'}, - { GREN_FLARE, "flare", "flare.mdl", 1, '300 300 300'}, - { GREN_GAS, "gas", "grenade2.mdl", 3, '300 300 300'}, - { GREN_EMP, "emp", "grenade2.mdl", 4, '300 300 300'}, - { GREN_FLASH, "flash", "flashgren.mdl", 0, '300 300 300'}, - { GREN_CALTROP, "caltrop", "", 0, '300 300 300'}, - { GREN_MIRVLET, "mirv", "grenade2.mdl", 1, '250 300 400'}, - { GREN_RED, "gl", "grenade2.mdl", 1, '300 300 300'}, - { GREN_PIPE, "pipe", "grenade2.mdl", 2, '300 300 300'}, + { GREN_NORMAL, "normal", "hgren2.mdl", 0, ICON_GREN_NORMAL, '300 300 300',}, + { GREN_CONC, "concussion", "hgren2.mdl", 1, ICON_GREN_CONCUSSION, '300 300 300'}, + { GREN_BLAST, "blast", "blastgren.mdl", 1, ICON_GREN_NAIL, '300 300 300'}, + { GREN_NAIL, "nail", "biggren.mdl", 1, ICON_GREN_NAIL, '0 300 0'}, + { GREN_SHOCK, "shock", "biggren.mdl", 1, ICON_GREN_NAIL, '0 300 0'}, + { GREN_BURST, "burst", "biggren.mdl", 1, ICON_GREN_NAIL, '0 300 0'}, + { GREN_MIRV, "mirv", "biggren.mdl", 0, ICON_GREN_MIRV, '0 300 0'}, + { GREN_NAPALM, "napalm", "biggren.mdl", 2, ICON_GREN_NAPALM, '0 300 0'}, + { GREN_FLARE, "flare", "flare.mdl", 1, ICON_GREN_FLARE, '300 300 300'}, + { GREN_GAS, "gas", "grenade2.mdl", 3, ICON_GREN_GAS, '300 300 300'}, + { GREN_EMP, "emp", "grenade2.mdl", 4, ICON_GREN_EMP, '300 300 300'}, + { GREN_FLASH, "flash", "flashgren.mdl", 0, ICON_GREN_FLASH, '300 300 300'}, + { GREN_CALTROP, "caltrop", "", 0, ICON_GREN_CALTROP, '300 300 300'}, + { GREN_MIRVLET, "mirv", "grenade2.mdl", 1, ICON_GREN_NONE, '250 300 400'}, + { GREN_RED, "gl", "grenade2.mdl", 1, ICON_GREN_NONE, '300 300 300'}, + { GREN_PIPE, "pipe", "grenade2.mdl", 2, ICON_GREN_NONE, '300 300 300'}, }; enum { @@ -267,9 +246,9 @@ FO_ClassGrenades class_grenades[] = { { PC_CIVILIAN, {GREN_NONE, GREN_NONE} }, }; -FO_GrenInfo* FO_GrenDesc(int gren_type) { +FO_GrenInfo* FO_GrenDesc(float gren_type) { if (gren_type < GREN_FIRST) { - printf("proj missing gren_type, tell newby\n"); + printf("proj missing gren_type [%d], tell newby\n", gren_type); gren_type = GREN_FIRST; } return &fo_grenades[gren_type - GREN_FIRST]; diff --git a/ssqc/items.qc b/ssqc/items.qc index 8cea4a1a..42787ca1 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -712,37 +712,9 @@ void () weapon_lightning = { StartItem(); }; -void (entity pl, float typ) PrintGrenadeType = { - local string st; - st = ""; - - if (typ == GR_TYPE_NORMAL) { - st = "normal"; - } else if (typ == GR_TYPE_CONCUSSION) { - st = "concussion"; - } else if (typ == GR_TYPE_NAIL) { - st = "nail"; - } else if (typ == GR_TYPE_MIRV) { - st = "mirv"; - } else if (typ == GR_TYPE_NAPALM) { - st = "napalm"; - } else if (typ == GR_TYPE_FLARE) { - st = "flare"; - } else if (typ == GR_TYPE_GAS) { - st = "gas"; - } else if (typ == GR_TYPE_EMP) { - st = "EMP"; - } else if (typ == GR_TYPE_CALTROP) { - st = "caltrop"; - } else if (typ == GR_TYPE_FLASH) { - st = "flash"; - } else if (typ == GR_TYPE_BLAST) { - st = "blast"; - } else if (typ == GR_TYPE_SHOCK) { - st = "shock"; - } else if (typ == GR_TYPE_BURST) { - st = "burst"; - } +void (entity pl, float type) PrintGrenadeType = { + // TODO: this is still awful + string st = FO_GrenDesc(type)->logname; sprint(pl, PRINT_HIGH, st); }; @@ -756,7 +728,7 @@ void (entity pe_player, float pf_grenade_type, float pf_grenade_count) PrintFoun else sprint(pe_player, PRINT_HIGH, "a "); PrintGrenadeType(pe_player, pf_grenade_type); - if (pf_grenade_type == GR_TYPE_CALTROP) + if (pf_grenade_type == GREN_CALTROP) sprint(pe_player, PRINT_HIGH, " canister"); else sprint(pe_player, PRINT_HIGH, " grenade"); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c0c90896..b2bf2755 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -452,46 +452,46 @@ string GetGrenName(float type) string s = ""; switch (type) { - case GR_TYPE_NORMAL: + case GREN_NORMAL: s = "normal grenade"; break; - case GR_TYPE_NAIL: + case GREN_NAIL: s = "nail grenade"; break; - case GR_TYPE_MIRV: + case GREN_MIRV: s = "mirv grenade"; break; - case GR_TYPE_NAPALM: + case GREN_NAPALM: s = "napalm grenade"; break; - case GR_TYPE_FLARE: + case GREN_FLARE: s = "flare"; break; - case GR_TYPE_GAS: + case GREN_GAS: s = "hallucinogenic grenade"; break; - case GR_TYPE_EMP: + case GREN_EMP: s = "EMP grenade"; break; - case GR_TYPE_CALTROP: + case GREN_CALTROP: s = "caltrop canister"; break; - case GR_TYPE_FLASH: + case GREN_FLASH: s = "flash grenade"; break; - case GR_TYPE_CONCUSSION: + case GREN_CONC: s = "concussion grenade"; break; - case GR_TYPE_BLAST: + case GREN_BLAST: s = "blast grenade"; break; - case GR_TYPE_SHOCK: + case GREN_SHOCK: s = "shock grenade"; break; - case GR_TYPE_BURST: + case GREN_BURST: s = "burst grenade"; break; - case GR_TYPE_NONE: + case GREN_NONE: s = "no grenade"; break; } @@ -831,7 +831,7 @@ void (entity timer) FO_SpawnThrownGrenade = { proj.classname = "grenade"; makevectors(user.v_angle); if (user.deadflag) { - if (timer.weapon == GR_TYPE_NORMAL) + if (timer.weapon == GREN_NORMAL) proj.velocity = '0 0 200'; else return; @@ -870,7 +870,7 @@ void (float inp) TeamFortress_PrimeThrowGrenade = { TeamFortress_PrimeGrenade(inp, TRUE); if ( ((inp == 1 && self.tp_grenade_switch != 1) || (inp == 2 && self.tp_grenade_switch == 1)) - && self.tp_grenades_1 == GR_TYPE_CALTROP) + && self.tp_grenades_1 == GREN_CALTROP) TeamFortress_ThrowGrenade(); } }; @@ -896,29 +896,29 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { gtype = self.tp_grenades_1; - if (gtype == GR_TYPE_CONCUSSION) + if (gtype == GREN_CONC) gs = "Concussion grenade"; - else if (gtype == GR_TYPE_NAIL) { + else if (gtype == GREN_NAIL) { gs = "Nail grenade"; - } else if (gtype == GR_TYPE_MIRV) + } else if (gtype == GREN_MIRV) gs = "Mirv grenade"; - else if (gtype == GR_TYPE_NAPALM) + else if (gtype == GREN_NAPALM) gs = "Napalm grenade"; - else if (gtype == GR_TYPE_FLARE) + else if (gtype == GREN_FLARE) gs = "Flare"; - else if (gtype == GR_TYPE_GAS) + else if (gtype == GREN_GAS) gs = "Gas grenade"; - else if (gtype == GR_TYPE_EMP) + else if (gtype == GREN_EMP) gs = "EMP grenade"; - else if (gtype == GR_TYPE_FLASH) + else if (gtype == GREN_FLASH) gs = "Flash grenade"; - else if (gtype == GR_TYPE_CALTROP) + else if (gtype == GREN_CALTROP) gs = "Caltrop canister"; - else if (gtype == GR_TYPE_BLAST) + else if (gtype == GREN_BLAST) gs = "Blast grenade"; - else if (gtype == GR_TYPE_SHOCK) + else if (gtype == GREN_SHOCK) gs = "Shock grenade"; - else if (gtype == GR_TYPE_BURST) + else if (gtype == GREN_BURST) gs = "Burst grenade"; else gs = "Grenade"; @@ -926,7 +926,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { if (self.no_grenades_1 > 0) { self.has_throwngren = TRUE; self.no_grenades_1 = self.no_grenades_1 - 1; - if (gtype == GR_TYPE_FLARE) { + if (gtype == GREN_FLARE) { newmis = spawn(); newmis.owner = self; newmis.movetype = 6; @@ -948,7 +948,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { setorigin(newmis, self.origin); return; } - if (gtype == GR_TYPE_CALTROP) { + if (gtype == GREN_CALTROP) { ptime = ftos(0.5); sprint(self, PRINT_HIGH, "Opening ", gs, "...\n"); } else { @@ -966,27 +966,27 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { gtype = self.tp_grenades_2; - if (gtype == GR_TYPE_CONCUSSION) + if (gtype == GREN_CONC) gs = "Concussion grenade"; - else if (gtype == GR_TYPE_NAIL) + else if (gtype == GREN_NAIL) gs = "Nail grenade"; - else if (gtype == GR_TYPE_MIRV) + else if (gtype == GREN_MIRV) gs = "Mirv grenade"; - else if (gtype == GR_TYPE_NAPALM) + else if (gtype == GREN_NAPALM) gs = "Napalm grenade"; - else if (gtype == GR_TYPE_FLARE) + else if (gtype == GREN_FLARE) gs = "Flare"; - else if (gtype == GR_TYPE_GAS) + else if (gtype == GREN_GAS) gs = "Gas grenade"; - else if (gtype == GR_TYPE_EMP) + else if (gtype == GREN_EMP) gs = "EMP grenade"; - else if (gtype == GR_TYPE_FLASH) + else if (gtype == GREN_FLASH) gs = "Flash grenade"; - else if (gtype == GR_TYPE_BLAST) + else if (gtype == GREN_BLAST) gs = "Blast grenade"; - else if (gtype == GR_TYPE_SHOCK) + else if (gtype == GREN_SHOCK) gs = "Shock grenade"; - else if (gtype == GR_TYPE_BURST) + else if (gtype == GREN_BURST) gs = "Burst grenade"; else gs = "Grenade"; @@ -994,7 +994,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { if (self.no_grenades_2 > 0) { self.has_throwngren = TRUE; self.no_grenades_2 = self.no_grenades_2 - 1; - if (gtype == GR_TYPE_FLARE) { + if (gtype == GREN_FLARE) { newmis = spawn(); newmis.owner = self; newmis.movetype = 6; @@ -1021,7 +1021,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { setorigin(newmis, self.origin); return; } - if (gtype == GR_TYPE_CALTROP) { + if (gtype == GREN_CALTROP) { ptime = ftos(0.5); sprint(self, PRINT_HIGH, "Opening ", gs, "...\n"); } else { @@ -1038,7 +1038,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { tGrenade = spawn(); tGrenade.owner = self; tGrenade.weapon = gtype; - tGrenade.fpp.gren_type = TF_GREN_conv(gtype); + tGrenade.fpp.gren_type = gtype; tGrenade.classname = "primetimer"; if (inp == 1) @@ -1048,7 +1048,7 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { float time_base = max(remote_time(), self.last_throw); tGrenade.nextthink = time_base + 0.8; - if (gtype == GR_TYPE_CALTROP) + if (gtype == GREN_CALTROP) tGrenade.heat = time_base + 0.5 + 0.5; else { tGrenade.heat = time_base + 3 + 0.8; @@ -1108,7 +1108,7 @@ void () FO_GrenadeThink = { self.nextthink = expiry; } } else { - if (self.weapon != GR_TYPE_CALTROP) + if (self.weapon != GREN_CALTROP) TeamFortress_ExplodePerson(); dremove(self); } @@ -1145,68 +1145,6 @@ void () TeamFortress_ThrowGrenade = { FO_ThrowGrenade(); }; -void () TeamFortress_GrenadeSwitch = { - local string gs; - - if (self.tp_grenade_switch == 1) { - self.tp_grenade_switch = 0; - if (self.tp_grenades_1 == 2) - gs = "Concussion grenade"; - else if (self.tp_grenades_1 == 3) { - gs = "Nail grenade"; - } else if (self.tp_grenades_1 == 4) - gs = "Mirv grenade"; - else if (self.tp_grenades_1 == 5) - gs = "Napalm grenade"; - else if (self.tp_grenades_1 == 6) - gs = "Flare"; - else if (self.tp_grenades_1 == 7) - gs = "Gas grenade"; - else if (self.tp_grenades_1 == 8) - gs = "EMP grenade"; - else if (self.tp_grenades_1 == 11) - gs = "Blast grenade"; - else if (self.tp_grenades_1 == 12) - gs = "Shock grenade"; - else if (self.tp_grenades_1 == 13) - gs = "Burst grenade"; - else - gs = "Grenade"; - } else { - self.tp_grenade_switch = 1; - if (self.tp_grenades_2 == 2) - gs = "Concussion grenade"; - else if (self.tp_grenades_2 == 3) { - gs = "Nail grenade"; - } else if (self.tp_grenades_2 == 4) - gs = "Mirv grenade"; - else if (self.tp_grenades_2 == 5) - gs = "Napalm grenade"; - else if (self.tp_grenades_2 == 6) - gs = "Flare"; - else if (self.tp_grenades_2 == 7) - gs = "Gas grenade"; - else if (self.tp_grenades_2 == 8) - gs = "EMP grenade"; - else if (self.tp_grenades_2 == 9) - gs = "Flash grenade"; - else if (self.tp_grenades_2 == 10) - gs = "Caltrop canister"; - else if (self.tp_grenades_2 == 11) - gs = "Blast grenade"; - else if (self.tp_grenades_2 == 12) - gs = "Shock grenade"; - else if (self.tp_grenades_2 == 13) - gs = "Burst grenade"; - else - gs = "Grenade"; - } - if (gs == "Caltrop canister" || gs == "Flare") - sprint(self, PRINT_HIGH, gs, " is now the primary throwable item\n"); - else - sprint(self, PRINT_HIGH, gs, " is now the primary grenade\n"); -}; - float (float pc) IsLegalClass = { local float bit; bit = 0; @@ -1568,11 +1506,11 @@ void () TeamFortress_SetEquipment = { self.max_grenades_2 = role.gren2_limits[1]; if (old_grens == 1 || fo_flash == TRUE) - self.tp_grenades_1 = GR_TYPE_FLASH; + self.tp_grenades_1 = GREN_FLASH; else - self.tp_grenades_1 = GR_TYPE_CALTROP; + self.tp_grenades_1 = GREN_CALTROP; - self.tp_grenades_2 = GR_TYPE_CONCUSSION; + self.tp_grenades_2 = GREN_CONC; self.tf_items = PC_SCOUT_TF_ITEMS; @@ -1679,13 +1617,13 @@ void () TeamFortress_SetEquipment = { switch (nailgren_type) { case NGR_TYPE_NAIL: - self.tp_grenades_2 = GR_TYPE_NAIL; + self.tp_grenades_2 = GREN_NAIL; break; case NGR_TYPE_LASER: - self.tp_grenades_2 = GR_TYPE_SHOCK; + self.tp_grenades_2 = GREN_SHOCK; break; case NGR_TYPE_BURST: - self.tp_grenades_2 = GR_TYPE_BURST; + self.tp_grenades_2 = GREN_BURST; break; } @@ -1792,9 +1730,9 @@ void () TeamFortress_SetEquipment = { self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1; if(medic_type == MEDIC_TYPE_BLAST) { - self.tp_grenades_2 = GR_TYPE_BLAST; + self.tp_grenades_2 = GREN_BLAST; } else { - self.tp_grenades_2 = GR_TYPE_CONCUSSION; + self.tp_grenades_2 = GREN_CONC; } self.tf_items = PC_MEDIC_TF_ITEMS; @@ -2709,7 +2647,7 @@ void () TeamFortress_ExplodePerson = { } proj.nextthink = expires; - if (self.weapon == GR_TYPE_FLARE) { + if (self.weapon == GREN_FLARE) { sprint(self.owner, PRINT_HIGH, "Flare lit\n"); te = spawn(); te.touch = SUB_Null; @@ -2747,7 +2685,7 @@ void () TeamFortress_ExplodePerson = { bprint(PRINT_MEDIUM, "Ack! ", self.owner.netname, "! The grenade is your friend for another reason!\n"); else if (self.owner.playerclass == PC_MEDIC) { - if (self.weapon == GR_TYPE_BLAST) { + if (self.weapon == GREN_BLAST) { if (medic_type == MEDIC_TYPE_BLAST) { bprint(PRINT_MEDIUM, "Nice one ", self.owner.netname, ", you forgot to throw your blast grenade!\n"); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d843fe6a..d9591cef 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -25,7 +25,6 @@ void () TeamFortress_ShowTF; void (float inp, float is_player) TeamFortress_PrimeGrenade; void () TeamFortress_ThrowGrenade; void (float inp) TeamFortress_PrimeThrowGrenade; -void () TeamFortress_GrenadeSwitch; void () PipebombTouch; @@ -2024,8 +2023,6 @@ void () ImpulseCommands = { TeamFortress_SaveMe(); else if (self.impulse == TF_GRENADE_T) TeamFortress_ThrowGrenade(); - else if (self.impulse == TF_GRENADE_SWITCH) - TeamFortress_GrenadeSwitch(); else if (self.impulse == TF_ID) CF_Identify(self, 1); else if (self.impulse == TF_ID_TEAM) @@ -2641,7 +2638,7 @@ void () W_WeaponFrame = { } // grenade impulses always possible - if ((self.impulse >= TF_GRENADE_1 && self.impulse <= TF_GRENADE_SWITCH)) { + if ((self.impulse >= TF_GRENADE_1 && self.impulse <= TF_GRENADE_PT_2)) { ImpulseCommands(); return; } diff --git a/ssqc/world.qc b/ssqc/world.qc index 89aef213..342a8d0a 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -335,8 +335,6 @@ void () worldspawn = { clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); - clientstat(STAT_TP_GREN1, EV_FLOAT, tp_grenades_1); - clientstat(STAT_TP_GREN2, EV_FLOAT, tp_grenades_2); clientstat(STAT_SPAWN_GEN,EV_FLOAT, spawn_gen); globalstat(STAT_ROUND_END, EV_FLOAT, "round_end_time"); From db4fa944a917c2ebcf618773e7afe01ede40ca82 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 14 Sep 2023 22:19:21 -0700 Subject: [PATCH 2178/2474] menus: fix join game This turns out to be one place that we need to disambiguate being truly connected as a spectator versus observer. Check it explicitly. --- csqc/menu.qc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index 84977a2a..fb20ff21 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -870,7 +870,11 @@ void FO_Menu_Game(float force) = { } if(fo_hud_menu_active && !force) return; - if(game_state.is_spectator) { + + // Here we care about distinguishing connecting as spectator vs observer, so + // query it rather than using game_state which mixes. + float true_spec = stof(getplayerkeyvalue(player_localnum, "*spectator")); + if (true_spec) { //print(getplayerkeyvalue(player_localnum, "name"), " is a spectator!\n"); //FO_MENU_GAME_SPECTATOR.num_opts = 3; FO_MENU_GAME_SPECTATOR.options[2].state = is_admin?FO_MENU_STATE_NORMAL:FO_MENU_STATE_DISABLED; @@ -890,7 +894,7 @@ void FO_Menu_Game(float force) = { } void FO_Menu_Track() = { - if(!game_state.is_spectator) + if (!game_state.is_spectator) return; local float i = 0; From 68d4e66d9545e07ff00f373349a373265e986151 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 14 Sep 2023 21:34:54 -0700 Subject: [PATCH 2179/2474] csqc: require always on Formalize that CSQC is now always required by rejecting clients that do not support it with an error message. Immediately initialize prediction state entity so that we can unify passing state back to clients. --- ssqc/client.qc | 40 ++++++++++++++++++---------------------- ssqc/rewind.qc | 3 ++- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 74351237..a91a2d65 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3046,13 +3046,17 @@ void () UpdateAllClientsTeamScores = { //do not rely on csqcactive - it may misbehave when using `join` from spectator void () ClientConnect = { - local float csqc_active = infokeyf(self, INFOKEY_P_CSQCACTIVE); - local string st; - local float got_one; + if (!infokeyf(self,INFOKEY_P_CSQCACTIVE)) { + sprint(self, PRINT_HIGH, "FTE/CSQC is required for this server, please download the latest client package at www.fortressone.org\n"); + dropclient(self); + return; + } - spawnfunc_FOPlayer(); bprint(PRINT_HIGH, self.netname, " entered the game\n"); + spawnfunc_FOPlayer(); + Predict_InitPlayer(self); + self.motd = 0; if (self.netname == string_null) @@ -3065,8 +3069,6 @@ void () ClientConnect = { if (loginRequired && self.login == string_null) sprint(self,2, "Login required, please use \"cmd login \" \nbefore joining the game\n"); - TeamFortress_Alias("id", TF_ID, 0); - TeamFortress_ExecMapScript(self); self.has_disconnected = 0; @@ -3075,39 +3077,33 @@ void () ClientConnect = { GotoNextMap(); } - st = infokey(self, "apw"); + string st = infokey(self, "apw"); if (st == string_null) st = infokey(self, "adminpwd"); if (st) { Admin_Check(st); - if (self.is_admin) + if (self.is_admin) Admin_Aliases(); else self.is_admin = FALSE; } if (clanbattle && (self.has_disconnected != 1)) { - got_one = 0; st = infokey(self, "tf_id"); self.tf_id = stof(st); if (!loginRequired) { - if ((st != string_null) && (self.tf_id != 0)) { - got_one = RejoinWithTfId(); - } - if (!got_one) { + if ((st != string_null) && (self.tf_id != 0)) + RejoinWithTfId(); + else CreateTfIdAndJoin(); - } } } - if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { - InitAllStatuses(self); - UpdateClientMOTD(self); - UpdateClientTeamScores(self); - //if(quadmode) - UpdateClientPrematch(self, !cb_prematch); - UpdateClient_VoteMap_AddAll(self); - } + InitAllStatuses(self); + UpdateClientMOTD(self); + UpdateClientTeamScores(self); + UpdateClientPrematch(self, !cb_prematch); + UpdateClient_VoteMap_AddAll(self); if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 1e7db4a7..0f31b716 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -248,7 +248,8 @@ class FOPlayer { }; nonvirtual void() RewindUpdate = { - RewindLog(rewind_); + if (rewind_) + RewindLog(rewind_); }; nonvirtual void(float when) RewindExcept = { From a15effa0fd0b32203a39d844987c11271bad44d0 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 14 Sep 2023 22:13:41 -0700 Subject: [PATCH 2180/2474] hud: make prediction entity track spectated player By having the prediction state track the spectated player (and handling the initialization and updates for this properly) we start to see a lot more as a spectator. Elements such as clip and reload now work correctly. --- csqc/weapon_predict.qc | 3 --- share/prediction.qc | 61 ++++++++++++++++++++++-------------------- ssqc/client.qc | 1 - ssqc/spect.qc | 2 ++ 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 73d70eff..ba511874 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -987,9 +987,6 @@ float WP_ReloadPercent() { } string WP_GetClip() { - if (!WP_Enabled()) - return SBAR.ClipSize; - Slot slot = CurrentSlot(); FO_WeapInfo* wi = SlotWI(slot); diff --git a/share/prediction.qc b/share/prediction.qc index 384ba8c8..5e4e540f 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -5,7 +5,7 @@ // Below apply to both CSQC & SSQC ents .float antilag_ms; -string wp_version = "v1.0"; +string wp_version = "v1.1"; enumflags { FOWP_CTIME, @@ -22,6 +22,7 @@ enumflags { FOWP_RNG0, FOWP_RNG1, FOWP_PREDICT_FLAGS, + FOWP_LAST, }; enumflags { @@ -303,7 +304,7 @@ predict_tf_state pstate_pred, pstate_server; #endif #ifdef SSQC -#define OP1(_op, _f1) (player.predict_state.##_f1 _op player.##_f1) +#define OP1(_op, _f1) (player.predict_state.##_f1 _op src.##_f1) #define OP2(_op, _j, _f1, _f2) OP1(_op, _f2) _j OP1(_op, _f1) #define OP3(_op, _j, _f1, _f2, _f3) OP2(_op, _j, _f2, _f3) _j OP1(_op, _f1) #define OP4(_op, _j, _f1, _f2, _f3, _f4) OP3(_op, _j, _f2, _f3, _f4) _j OP1(_op, _f1) @@ -312,19 +313,14 @@ predict_tf_state pstate_pred, pstate_server; #define M3(_bit, _f1, _f2, _f3) if (OP3(!=, ||, _f1, _f2, _f3)) { mask |= _bit; OP3(=, ;, _f1, _f2, _f3); } #define M4(_bit, _f1, _f2, _f3, _f4) if (OP4(!=, ||, _f1, _f2, _f3, _f4)) { mask |= _bit; OP4(=, ;, _f1, _f2, _f3, _f4); } -.float last_full_predict_refresh; +.float pred_lastforce; +.float pred_forcebit; -void Predict_Update() { - entity pe = self.predict_entity; - if (pe != __NULL__) - pe.SendFlags = 1; // Will compute what to send. -} - -static float Prediction_ChangedMask(entity player) { +static float Prediction_ChangedMask(entity player, entity src) { float mask = FOWP_CTIME; - player.predict_state.client_time = player.client_time; - player.predict_state.client_ping = player.client_ping; + player.predict_state.client_time = src.client_time; + player.predict_state.client_ping = src.client_ping; M1(FOWP_CLASS, playerclass); M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); @@ -339,14 +335,32 @@ static float Prediction_ChangedMask(entity player) { M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]) - if (time - player.last_full_predict_refresh >= 1000 * MSEC) { - player.last_full_predict_refresh = time; - return 0xFFFFFF; + // Rotate through forced update fields. + if (time - player.pred_lastforce >= 100 * MSEC) { + player.pred_lastforce = time; + + player.pred_forcebit <<= 1; + if (player.pred_forcebit >= FOWP_LAST) + player.pred_forcebit = 1; + + mask |= player.pred_forcebit; } return mask; } +void Predict_InitPlayer(entity player); +void Predict_Update() { + Predict_InitPlayer(self); + + // When spectating, goalentity is our target. + entity src = self.goalentity; + if (!src) + src = self; + + self.predict_entity.SendFlags |= Prediction_ChangedMask(self, src); +} + #undef OP1 #undef OP2 #undef OP3 @@ -417,12 +431,10 @@ void EntUpdate_Config() { #ifdef SSQC #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) -float WP_SendEntity(entity to_player, float ignored) { +float WP_SendEntity(entity to_player, float sendflags) { if (to_player != self.owner) return FALSE; - float sendflags = Prediction_ChangedMask(self.owner); - WriteByte(MSG_ENTITY, ENT_WEAPONPRED); WriteFloat(MSG_ENTITY, sendflags); #else @@ -722,19 +734,9 @@ void Predict_Init() { config_entity.nextthink = time + 0.5; } -.float wpp_init; void Predict_InitPlayer(entity player) { - // PutClientInServer is called every spawn. At some point we'll clean up - // parameter decode so that it can happen earlier and this nonsense goes - // away. - if (player.wpp_init) + if (player.predict_entity) return; - player.wpp_init = TRUE; - - if (!infokeyf(player, INFOKEY_P_CSQCACTIVE)) { - bprint(PRINT_HIGH, player.netname, " is using a legacy non-CSQC client.\n"); - return; - } sprint(player, PRINT_HIGH, "FortressOne: Weapon Prediction ", wp_version, "\n"); @@ -747,6 +749,7 @@ void Predict_InitPlayer(entity player) { pe.SendEntity = WP_SendEntity; setorigin(pe, [0, 0, 0]); + player.pred_forcebit = 1; player.predict_entity = pe; } diff --git a/ssqc/client.qc b/ssqc/client.qc index a91a2d65..5ec4c5d8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3055,7 +3055,6 @@ void () ClientConnect = { bprint(PRINT_HIGH, self.netname, " entered the game\n"); spawnfunc_FOPlayer(); - Predict_InitPlayer(self); self.motd = 0; diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 24367707..e1552e94 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -160,4 +160,6 @@ void () SpectatorThink = { if (time >= self.StatusRefreshTime) { RefreshStatusBar(self); } + + Predict_Update(); }; From 4a4037bc396ef7be81d52c0d5ee0d310fb887cbb Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Sep 2023 10:14:48 -0700 Subject: [PATCH 2181/2474] grenades: massive clean-up and refactoring pass Massive clean up and refactoring of old grenade code. There's still a lot of spaghetti but it's greatly reduced, a bunch of the defines are dead, fields like tp_grenade are gone. Counts and other synchronization moved into prediction entity. --- csqc/status.qc | 4 +- csqc/weapon_predict.qc | 10 +- share/defs.h | 22 --- share/prediction.qc | 12 +- share/weapons.qc | 24 +++ ssqc/client.qc | 10 -- ssqc/items.qc | 40 +++-- ssqc/qw.qc | 5 +- ssqc/tfort.qc | 350 ++++++----------------------------------- ssqc/weapons.qc | 2 +- ssqc/world.qc | 2 - 11 files changed, 116 insertions(+), 365 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index abd07a2e..f722a884 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1097,8 +1097,8 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_RELOADPROGRESS, "reload_progress", "Reload Progress", '0 0', '100 10', 1,1,1,0,0, drawReloadProgress, {return "";}, 0, HUD_SNAP_CENTER}, {HUDP_FRAGSTREAK, "fragstreak", FO_HUD_FRAGSTREAK_NAME, '10 50', '26 26', 1,0,1,0,0, drawFragStreakPanel, {return ftos(SBAR.FragStreak);}}, {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, - {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0,0, drawGren1Panel, {return ftos(getstatf(STAT_NO_GREN1));}}, - {HUDP_GREN2, "gren2", FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0,0, drawGren2Panel, {return ftos(getstatf(STAT_NO_GREN2));}}, + {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0,0, drawGren1Panel, {return ftos(WP_GrenCount(1));}}, + {HUDP_GREN2, "gren2", FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0,0, drawGren2Panel, {return ftos(WP_GrenCount(2));}}, {HUDP_SPECIAL, "playerclass", FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, {HUDP_IDENTIFY, "identify", FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, 0, drawIdentify, {return SBAR.Identify;}}, {HUDP_FLAGINFO, "flaginfo", FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0,0, drawFlagInfo, {return "";}}, diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ba511874..05f5191f 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1529,6 +1529,10 @@ static float CanThrowGrenade(int gren_type) { void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); +float WP_GrenCount(float index) { + return index == 1 ? pstate_pred.no_grenades_1 : pstate_pred.no_grenades_2; +} + static void W_PrimeGren(float index) { if (!game_state.is_alive || getstatf(STAT_NOFIRE)) return; @@ -1537,13 +1541,15 @@ static void W_PrimeGren(float index) { return; index -= 1; // We work with zero-based index here. - float stat = index == 0 ? STAT_NO_GREN1 : STAT_NO_GREN2; - if (getstatf(stat) < 1) + float* gc = index == 0 ? &pstate_pred.no_grenades_1 : + &pstate_pred.no_grenades_2; + if (*gc < 1) return; // No grenades left float gren = FO_ClassGren(pstate_pred.playerclass, index)->id; pstate_pred.tfstate |= (index ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED); + *gc -= 1; if (IsEffectFrame()) ParseGrenPrimed(gren, time, time + 3.8); } diff --git a/share/defs.h b/share/defs.h index 4af5458a..01de5f0f 100644 --- a/share/defs.h +++ b/share/defs.h @@ -887,8 +887,6 @@ enumflags { #define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned #define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned #define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned -/* #define PC_SCOUT_GRENADE_TYPE_1 // Configured in TeamFortress_SetEquipment() */ -#define PC_SCOUT_GRENADE_TYPE_2 GREN_CONC // <- 2nd Type of Grenade this class has #define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned #define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned #define PC_SCOUT_GRENADE_MAX_1 3 @@ -916,8 +914,6 @@ enumflags { #define PC_SNIPER_INITAMMO_NAIL 50 #define PC_SNIPER_INITAMMO_CELL 0 #define PC_SNIPER_INITAMMO_ROCKET 0 -#define PC_SNIPER_GRENADE_TYPE_1 GREN_NORMAL -#define PC_SNIPER_GRENADE_TYPE_2 GREN_FLARE #define PC_SNIPER_GRENADE_INIT_1 2 #define PC_SNIPER_GRENADE_INIT_2 3 #define PC_SNIPER_GRENADE_MAX_1 4 @@ -944,8 +940,6 @@ enumflags { #define PC_SOLDIER_INITAMMO_NAIL 0 #define PC_SOLDIER_INITAMMO_CELL 0 #define PC_SOLDIER_INITAMMO_ROCKET 10 -#define PC_SOLDIER_GRENADE_TYPE_1 GREN_NORMAL -/* #define PC_SOLDIER_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_SOLDIER_GRENADE_INIT_1 4 #define PC_SOLDIER_GRENADE_INIT_2 1 #define PC_SOLDIER_GRENADE_MAX_1 4 @@ -973,8 +967,6 @@ enumflags { #define PC_DEMOMAN_INITAMMO_CELL 0 #define PC_DEMOMAN_INITAMMO_ROCKET 20 #define PC_DEMOMAN_INITAMMO_DETPACK 1 -#define PC_DEMOMAN_GRENADE_TYPE_1 GREN_NORMAL -#define PC_DEMOMAN_GRENADE_TYPE_2 GREN_MIRV #define PC_DEMOMAN_GRENADE_INIT_1 4 #define PC_DEMOMAN_GRENADE_INIT_2 4 #define PC_DEMOMAN_GRENADE_MAX_1 4 @@ -1002,8 +994,6 @@ enumflags { #define PC_MEDIC_INITAMMO_CELL 0 #define PC_MEDIC_INITAMMO_ROCKET 0 #define PC_MEDIC_INITAMMO_MEDIKIT 50 -#define PC_MEDIC_GRENADE_TYPE_1 GREN_NORMAL -/* #define PC_MEDIC_GRENADE_TYPE_2 // Configured in TeamFortress_SetEquipment() */ #define PC_MEDIC_GRENADE_INIT_1 3 #define PC_MEDIC_GRENADE_INIT_2 3 #define PC_MEDIC_GRENADE_MAX_1 4 @@ -1040,8 +1030,6 @@ enumflags { #define PC_HVYWEAP_INITAMMO_NAIL 0 #define PC_HVYWEAP_INITAMMO_CELL 30 #define PC_HVYWEAP_INITAMMO_ROCKET 0 -#define PC_HVYWEAP_GRENADE_TYPE_1 GREN_NORMAL -#define PC_HVYWEAP_GRENADE_TYPE_2 GREN_MIRV #define PC_HVYWEAP_GRENADE_INIT_1 4 #define PC_HVYWEAP_GRENADE_INIT_2 1 #define PC_HVYWEAP_GRENADE_MAX_1 4 @@ -1068,8 +1056,6 @@ enumflags { #define PC_PYRO_INITAMMO_NAIL 0 #define PC_PYRO_INITAMMO_CELL 120 #define PC_PYRO_INITAMMO_ROCKET 15 -#define PC_PYRO_GRENADE_TYPE_1 GREN_NORMAL -#define PC_PYRO_GRENADE_TYPE_2 GREN_NAPALM #define PC_PYRO_GRENADE_INIT_1 1 #define PC_PYRO_GRENADE_INIT_2 4 #define PC_PYRO_GRENADE_MAX_1 4 @@ -1106,8 +1092,6 @@ enumflags { #define PC_SPY_INITAMMO_NAIL 50 #define PC_SPY_INITAMMO_CELL 10 #define PC_SPY_INITAMMO_ROCKET 0 -#define PC_SPY_GRENADE_TYPE_1 GREN_NORMAL -#define PC_SPY_GRENADE_TYPE_2 GREN_GAS #define PC_SPY_GRENADE_INIT_1 2 #define PC_SPY_GRENADE_INIT_2 2 #define PC_SPY_GRENADE_MAX_1 4 @@ -1137,8 +1121,6 @@ enumflags { #define PC_ENGINEER_INITAMMO_NAIL 25 #define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal #define PC_ENGINEER_INITAMMO_ROCKET 0 -#define PC_ENGINEER_GRENADE_TYPE_1 GREN_NORMAL -#define PC_ENGINEER_GRENADE_TYPE_2 GREN_EMP #define PC_ENGINEER_GRENADE_INIT_1 2 #define PC_ENGINEER_GRENADE_INIT_2 2 #define PC_ENGINEER_GRENADE_MAX_1 4 @@ -1165,8 +1147,6 @@ enumflags { #define PC_CIVILIAN_INITAMMO_NAIL 0 #define PC_CIVILIAN_INITAMMO_CELL 0 #define PC_CIVILIAN_INITAMMO_ROCKET 0 -#define PC_CIVILIAN_GRENADE_TYPE_1 0 -#define PC_CIVILIAN_GRENADE_TYPE_2 0 #define PC_CIVILIAN_GRENADE_INIT_1 0 #define PC_CIVILIAN_GRENADE_INIT_2 0 #define PC_CIVILIAN_GRENADE_MAX_1 0 @@ -1471,8 +1451,6 @@ enumflags { #define STAT_TEAMNO 33 #define STAT_FLAGS 34 #define STAT_CLASS 35 -#define STAT_NO_GREN1 36 -#define STAT_NO_GREN2 37 #define STAT_PAUSED 38 #define STAT_NOFIRE 39 #define STAT_TEAMNO_ATTACK 40 diff --git a/share/prediction.qc b/share/prediction.qc index 5e4e540f..f2e54cda 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -14,6 +14,7 @@ enumflags { FOWP_LASTPRIME, FOWP_CONCFINISH, FOWP_CLIP, + FOWP_GREN, FOWP_THINK, FOWP_WF, FOWP_AF, @@ -70,6 +71,8 @@ struct predict_tf_state { float clip_fired[4]; int prng_base[PRNG_NUM_STATES]; + float no_grenades_1, no_grenades_2, gren_exp; + #ifdef CSQC // Used for prediction, not actually communicated. Reset each frame. int seq; @@ -333,7 +336,8 @@ static float Prediction_ChangedMask(entity player, entity src) { M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]); M2(FOWP_RELOAD, reload_started, reload_finished); M1(FOWP_RNG0, prng_base[PRNG_WEAP]); - M1(FOWP_RNG1, prng_base[PRNG_HWGUY]) + M1(FOWP_RNG1, prng_base[PRNG_HWGUY]); + M3(FOWP_GREN, no_grenades_1, no_grenades_2, gren_exp) // Rotate through forced update fields. if (time - player.pred_lastforce >= 100 * MSEC) { @@ -505,6 +509,12 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_RNG1) COMM(Int, prng_base[PRNG_HWGUY]); + if (sendflags & FOWP_GREN) { + COMM(Short, no_grenades_1); + COMM(Short, no_grenades_2); + COMM(Float, gren_exp); + } + #ifdef SSQC return TRUE; #else diff --git a/share/weapons.qc b/share/weapons.qc index eacd27b6..2b98b2d1 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -188,6 +188,24 @@ FO_GrenInfo fo_grenades[] = { { GREN_PIPE, "pipe", "grenade2.mdl", 2, ICON_GREN_NONE, '300 300 300'}, }; +string FO_GrenName(float gtype) { + switch (gtype) { + case GREN_CONC: return "Concussion grenade"; + case GREN_NAIL: return "Nail grenade"; + case GREN_MIRV: return "Mirv grenade"; + case GREN_NAPALM: return "Napalm grenade"; + case GREN_FLARE: return "Flare"; + case GREN_GAS: return "Gas grenade"; + case GREN_EMP: return "EMP grenade"; + case GREN_FLASH: return "Flash grenade"; + case GREN_CALTROP: return "Caltrop canister"; + case GREN_BLAST: return "Blast grenade"; + case GREN_SHOCK: return "Shock grenade"; + case GREN_BURST: return "Burst grenade"; + default: return "Grenade"; + } +} + enum { kRadiusDamage, kRadiusBounce, @@ -258,6 +276,12 @@ FO_GrenInfo* FO_ClassGren(int playerclass, int index) { return FO_GrenDesc(class_grenades[playerclass].gren[index]); } +#ifdef SSQC +FO_GrenInfo* FO_PlayerGren(entity player, int index) { + return FO_ClassGren(player.playerclass, index); +} +#endif + // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { diff --git a/ssqc/client.qc b/ssqc/client.qc index 5ec4c5d8..87298e02 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -20,7 +20,6 @@ float (float pc) IsLegalClass; void () SetupTeamEqualiser; void () CeaseFire_think; -void () RemoveGrenadeTimers; void () RemovePrimeTimers; void () RemoveGasTimers; void () RemoveGrenades; @@ -450,9 +449,6 @@ void () DecodeLevelParms = { // maximum grenades type 2 to drop in backpack [0] drop_gren2 = CF_GetSetting("dg2", "drop_gren2", "0"); - // display grenade timer in status bar [on] - grentimers = CF_GetSetting("gt", "grentimers", "on"); - // show sentry gun health + misc extras in id string [on] id_extended = CF_GetSetting("ie", "id_extended", "on"); @@ -833,7 +829,6 @@ void () DecodeLevelParms = { drop_grenpack = TRUE; drop_gren1 = 1; drop_gren2 = 0; - grentimers = TRUE; id_extended = TRUE; remember_weapon = TRUE; discammo_pickup = FALSE; @@ -903,7 +898,6 @@ void () DecodeLevelParms = { drop_grenpack = FALSE; drop_gren1 = 0; drop_gren2 = 0; - grentimers = FALSE; id_extended = FALSE; remember_weapon = FALSE; discammo_pickup = TRUE; @@ -1006,7 +1000,6 @@ void () DecodeLevelParms = { localcmd("localinfo server_sbflaginfo 0\n"); solid_detpack = TRUE; walls_block_emp = FALSE; - grentimers = FALSE; Role_None.gren2_limits[1] = 3; Role_None.gren2_limits[3] = 2; Role_None.gren2_limits[4] = 4; @@ -1486,7 +1479,6 @@ void () StartSpawnGuard = { void () DuelFinish = { FO_Sound(world, CHAN_AUTO, "boss1/sight1.wav", 1, ATTN_NONE); NextLevel(); - RemoveGrenadeTimers(); RemovePrimeTimers(); RemoveGrenades(); }; @@ -2431,7 +2423,6 @@ void () CheckRules = { if ((timelimit && (time >= timelimit))) { NextLevel(); - RemoveGrenadeTimers(); RemovePrimeTimers(); RemoveGrenades(); } @@ -2439,7 +2430,6 @@ void () CheckRules = { if ((fraglimit && (self.frags >= fraglimit))) { NextLevel(); - RemoveGrenadeTimers(); RemovePrimeTimers(); RemoveGrenades(); } diff --git a/ssqc/items.qc b/ssqc/items.qc index 42787ca1..d49041a6 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -738,28 +738,24 @@ void (entity pe_player, float pf_grenade_type, float pf_grenade_count) PrintFoun }; float () GetGrenadePossibility = { - local float maxg; + if (random() < 0.500) + return 0; - if (random() < 0.500) { + float index = random() < 0.5 ? 0 : 1; + FO_GrenInfo* gt = FO_PlayerGren(other, index); + if (gt->id == GREN_NONE) return 0; - } - if (random() < 0.500) { - maxg = other.max_grenades_1; - if ((other.tp_grenades_1 != 0) && (other.no_grenades_1 < maxg)) { - other.no_grenades_1 = other.no_grenades_1 + 1; - PrintFoundGrenade(other, other.tp_grenades_1, 1); - return 1; - } - } else { - maxg = other.max_grenades_2; - if ((other.tp_grenades_2 != 0) && (other.no_grenades_2 < maxg)) { - other.no_grenades_2 = other.no_grenades_2 + 1; - PrintFoundGrenade(other, other.tp_grenades_2, 1); - return 1; - } - } - return 0; -}; + + if (index == 0 && other.no_grenades_1 < other.max_grenades_1) + other.no_grenades_1 += 1; + else if (index == 1 && other.no_grenades_2 < other.max_grenades_2) + other.no_grenades_2 += 1; + else + return 0; + + PrintFoundGrenade(other, gt->id, 1); + return 1; +} void () ammo_touch = { local float gotgren; @@ -1242,7 +1238,7 @@ void () BackpackTouch = { else giveg = self.no_grenades_1; other.no_grenades_1 = other.no_grenades_1 + giveg; - PrintFoundGrenade(other, other.tp_grenades_1, giveg); + PrintFoundGrenade(other, FO_PlayerGren(other, 0)->id, giveg); // give grenade type 2 maxg = other.max_grenades_2; @@ -1251,7 +1247,7 @@ void () BackpackTouch = { else giveg = self.no_grenades_2; other.no_grenades_2 = other.no_grenades_2 + giveg; - PrintFoundGrenade(other, other.tp_grenades_2, giveg); + PrintFoundGrenade(other, FO_PlayerGren(other, 1)->id, giveg); } bound_other_ammo(other); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 5d280f26..c8ba27e3 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -43,11 +43,9 @@ float remote_client_time(); .float armorclass; // Type of armor being worn .float tf_items; // Another flag for player items .float tf_items_flags; // Flags for the player items +.float gren_exp; // Expiry of last primed grenade .float no_grenades_1; // Number of grenades of type 1 being carried .float no_grenades_2; // Number of grenades of type 2 being carried -.float tp_grenades_1; // 1st type of grenades being carried -.float tp_grenades_2; // 2nd type of grenades being carried -.float tp_grenade_switch; // Set to 1 if +gren1 and +gren2 switch places .float hook_out; // Dummy field for hook to silence error messages .float cheat_check; // Time when we'll next check for team cheats .float is_removed; // TRUE if the entity has been removed @@ -554,7 +552,6 @@ float max_gren2_spy; float max_gren2_engineer; */ float max_active_gren2_soldier; -float grentimers; float id_extended; float remember_weapon; float discammo_pickup; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b2bf2755..d58ca5dc 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -133,15 +133,6 @@ void () RemoveAutoIdTimer = { } }; -void () RemoveGrenadeTimers = { - local entity te = find(world, classname, "gtimer"); - while (te != world) { - if (te.owner == self) - dremove(te); - te = find(te, classname, "gtimer"); - } -}; - void () RemovePrimeTimers = { if (!drop_grenades) { local entity te = find(world, classname, "primetimer"); @@ -447,58 +438,6 @@ void () TeamFortress_DisplayLegalClasses = { sprint(self, PRINT_HIGH, "\n"); }; -string GetGrenName(float type) -{ - string s = ""; - switch (type) - { - case GREN_NORMAL: - s = "normal grenade"; - break; - case GREN_NAIL: - s = "nail grenade"; - break; - case GREN_MIRV: - s = "mirv grenade"; - break; - case GREN_NAPALM: - s = "napalm grenade"; - break; - case GREN_FLARE: - s = "flare"; - break; - case GREN_GAS: - s = "hallucinogenic grenade"; - break; - case GREN_EMP: - s = "EMP grenade"; - break; - case GREN_CALTROP: - s = "caltrop canister"; - break; - case GREN_FLASH: - s = "flash grenade"; - break; - case GREN_CONC: - s = "concussion grenade"; - break; - case GREN_BLAST: - s = "blast grenade"; - break; - case GREN_SHOCK: - s = "shock grenade"; - break; - case GREN_BURST: - s = "burst grenade"; - break; - case GREN_NONE: - s = "no grenade"; - break; - } - - return s; -} - void () TeamFortress_Inventory = { local entity en; local string st; @@ -523,7 +462,7 @@ void () TeamFortress_Inventory = { fl = self.no_grenades_1; if (fl > 0) { - string g1 = strcat(ftos(fl), " ", GetGrenName(self.tp_grenades_1)); + string g1 = strcat(ftos(fl), " ", FO_GrenName(FO_ClassGren(self.playerclass, 0)->id)); if (fl > 1) g1 = strcat(g1, "s"); @@ -533,7 +472,7 @@ void () TeamFortress_Inventory = { fl = self.no_grenades_2; if (fl > 0) { - string g2 = strcat(ftos(fl), " ", GetGrenName(self.tp_grenades_2)); + string g2 = strcat(ftos(fl), " ", FO_GrenName(FO_ClassGren(self.playerclass, 1)->id)); if (fl > 1) g2 = strcat(g2, "s"); @@ -672,7 +611,6 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("- Grenades type 1", drop_gren1, "", 0); CF_PrintSetting("- Grenades type 2", drop_gren2, "", 0); } - CF_PrintSetting("Grenade timers", grentimers, "", 1); CF_PrintSetting("Scout max grenades type 1 (caltrops)", Role_None.gren1_limits[1], "", PC_SCOUT_GRENADE_MAX_1); CF_PrintSetting("Sniper max grenades type 1 (normal)", Role_None.gren1_limits[2], "", PC_SNIPER_GRENADE_MAX_1); @@ -780,17 +718,6 @@ void () NormalGrenadeTouch = { self.avelocity = '0 0 0'; }; -void () GrenadeTimer = { - self.heat = self.heat - 1; - self.nextthink = time + 1; - self.owner.StatusGrenTime = self.heat; - Status_Refresh(self.owner); - - if (!self.heat) { - dremove(self); - } -}; - static struct stg_table_entry { int id; void() touch; @@ -819,9 +746,7 @@ void (entity timer) FO_SpawnThrownGrenade = { user.tfstate &= ~TFSTATE_GREN_MASK_ALL; user.last_throw = time; - if (grentimers && infokeyf(user, INFOKEY_P_CSQCACTIVE)) { - UpdateClientGrenadeThrown(user); - } + UpdateClientGrenadeThrown(user); KickPlayer(-1, user); entity proj = FOProj_Create(FPP_HANDGRENADE); @@ -866,179 +791,71 @@ void (entity timer) FO_SpawnThrownGrenade = { void (float inp) TeamFortress_PrimeThrowGrenade = { if (self.tfstate & TFSTATE_GREN_MASK_PRIMED) TeamFortress_ThrowGrenade(); - else { + else TeamFortress_PrimeGrenade(inp, TRUE); - if ( ((inp == 1 && self.tp_grenade_switch != 1) || (inp == 2 && self.tp_grenade_switch == 1)) - && self.tp_grenades_1 == GREN_CALTROP) + if (FO_ClassGren(self.playerclass, inp - 1)->id == GREN_CALTROP) TeamFortress_ThrowGrenade(); - } -}; +} void () FO_GrenadeThink; // is_player defines whether this originated from the player or server. -void (float inp, float is_player) TeamFortress_PrimeGrenade = { - local float gtype; - local string gs; - local string ptime; - local entity tGrenade; - local entity timer; - gtype = 0; - +void TeamFortress_PrimeGrenade(float inp, float is_player) { if (self.tfstate & TFSTATE_GREN_MASK_PRIMED) return; if (no_fire_mode) return; - if ((inp == 1 && self.tp_grenade_switch != 1) || (inp == 2 && self.tp_grenade_switch == 1)) { - - gtype = self.tp_grenades_1; - - if (gtype == GREN_CONC) - gs = "Concussion grenade"; - else if (gtype == GREN_NAIL) { - gs = "Nail grenade"; - } else if (gtype == GREN_MIRV) - gs = "Mirv grenade"; - else if (gtype == GREN_NAPALM) - gs = "Napalm grenade"; - else if (gtype == GREN_FLARE) - gs = "Flare"; - else if (gtype == GREN_GAS) - gs = "Gas grenade"; - else if (gtype == GREN_EMP) - gs = "EMP grenade"; - else if (gtype == GREN_FLASH) - gs = "Flash grenade"; - else if (gtype == GREN_CALTROP) - gs = "Caltrop canister"; - else if (gtype == GREN_BLAST) - gs = "Blast grenade"; - else if (gtype == GREN_SHOCK) - gs = "Shock grenade"; - else if (gtype == GREN_BURST) - gs = "Burst grenade"; - else - gs = "Grenade"; - - if (self.no_grenades_1 > 0) { - self.has_throwngren = TRUE; - self.no_grenades_1 = self.no_grenades_1 - 1; - if (gtype == GREN_FLARE) { - newmis = spawn(); - newmis.owner = self; - newmis.movetype = 6; - newmis.solid = 2; - newmis.classname = "grenade"; - newmis.fpp.gren_type = GREN_FLARE; - makevectors(self.v_angle); - newmis.velocity = (v_forward * 600) + (v_up * 25); - newmis.velocity = newmis.velocity * 700; - newmis.angles = vectoangles(newmis.velocity); - newmis.weapon = self.team_no; - newmis.think = FlareGrenadeExplode; - newmis.nextthink = time + 0.8; - newmis.touch = FlareGrenadeTouch; - newmis.skin = 1; - newmis.mdl = "flare"; - FO_SetModel(newmis, "progs/flare.mdl"); - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, self.origin); - return; - } - if (gtype == GREN_CALTROP) { - ptime = ftos(0.5); - sprint(self, PRINT_HIGH, "Opening ", gs, "...\n"); + FO_GrenInfo* gdesc = FO_PlayerGren(self, inp - 1); + float *numg = (inp == 1) ? &self.no_grenades_1 : &self.no_grenades_2; + string gs = FO_GrenName(gdesc->id); + + if (*numg > 0) { + self.has_throwngren = TRUE; + *numg -= 1; + if (gdesc->id == GREN_FLARE) { + newmis = spawn(); + newmis.owner = self; + newmis.movetype = MOVETYPE_TOSS; + newmis.solid = SOLID_BBOX; + newmis.classname = "grenade"; + newmis.fpp.gren_type = GREN_FLARE; + makevectors(self.v_angle); + if (self.v_angle_x) { + newmis.velocity = v_forward * 1200 + v_up * 200; } else { - ptime = ftos(3); - sprint(self, PRINT_HIGH, gs, " primed, ", ptime, - " seconds...\n"); + newmis.velocity = aim(self, 10000); + newmis.velocity = newmis.velocity * 1200; + newmis.velocity_z = 75; } - } else { - sprint(self, PRINT_HIGH, "No ", gs, "s left\n"); + newmis.angles = vectoangles(newmis.velocity); + newmis.weapon = self.team_no; + newmis.think = FlareGrenadeExplode; + newmis.nextthink = time + 0.8; + newmis.touch = FlareGrenadeTouch; + newmis.skin = 1; + newmis.mdl = "flare"; + FO_SetModel(newmis, "progs/flare.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); + setorigin(newmis, self.origin); return; - } - } - - if ( (inp == 2 && self.tp_grenade_switch != 1) || (inp == 1 && self.tp_grenade_switch == 1)) { - - gtype = self.tp_grenades_2; - - if (gtype == GREN_CONC) - gs = "Concussion grenade"; - else if (gtype == GREN_NAIL) - gs = "Nail grenade"; - else if (gtype == GREN_MIRV) - gs = "Mirv grenade"; - else if (gtype == GREN_NAPALM) - gs = "Napalm grenade"; - else if (gtype == GREN_FLARE) - gs = "Flare"; - else if (gtype == GREN_GAS) - gs = "Gas grenade"; - else if (gtype == GREN_EMP) - gs = "EMP grenade"; - else if (gtype == GREN_FLASH) - gs = "Flash grenade"; - else if (gtype == GREN_BLAST) - gs = "Blast grenade"; - else if (gtype == GREN_SHOCK) - gs = "Shock grenade"; - else if (gtype == GREN_BURST) - gs = "Burst grenade"; - else - gs = "Grenade"; - - if (self.no_grenades_2 > 0) { - self.has_throwngren = TRUE; - self.no_grenades_2 = self.no_grenades_2 - 1; - if (gtype == GREN_FLARE) { - newmis = spawn(); - newmis.owner = self; - newmis.movetype = 6; - newmis.solid = 2; - newmis.classname = "grenade"; - newmis.fpp.gren_type = GREN_FLARE; - makevectors(self.v_angle); - if (self.v_angle_x) { - newmis.velocity = v_forward * 1200 + v_up * 200; - } else { - newmis.velocity = aim(self, 10000); - newmis.velocity = newmis.velocity * 1200; - newmis.velocity_z = 75; - } - newmis.angles = vectoangles(newmis.velocity); - newmis.weapon = self.team_no; - newmis.think = FlareGrenadeExplode; - newmis.nextthink = time + 0.8; - newmis.touch = FlareGrenadeTouch; - newmis.skin = 1; - newmis.mdl = "flare"; - FO_SetModel(newmis, "progs/flare.mdl"); - setsize(newmis, '0 0 0', '0 0 0'); - setorigin(newmis, self.origin); - return; - } - if (gtype == GREN_CALTROP) { - ptime = ftos(0.5); - sprint(self, PRINT_HIGH, "Opening ", gs, "...\n"); - } else { - ptime = ftos(3); - sprint(self, PRINT_HIGH, gs, " primed, ", ptime, - " seconds...\n"); - } + } if (gdesc->id == GREN_CALTROP) { + sprint(self, PRINT_HIGH, "Opening ", gs, "...\n"); } else { - sprint(self, PRINT_HIGH, "No ", gs, "s left\n"); - return; + sprint(self, PRINT_HIGH, gs, " primed, 3 seconds...\n"); } + } else { + sprint(self, PRINT_HIGH, "No ", gs, "s left\n"); + return; } + self.tfstate |= (inp == 1) ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED; - tGrenade = spawn(); + entity tGrenade = spawn(); tGrenade.owner = self; - tGrenade.weapon = gtype; - tGrenade.fpp.gren_type = gtype; + tGrenade.weapon = gdesc->id; + tGrenade.fpp.gren_type = gdesc->id; tGrenade.classname = "primetimer"; if (inp == 1) @@ -1048,36 +865,18 @@ void (float inp, float is_player) TeamFortress_PrimeGrenade = { float time_base = max(remote_time(), self.last_throw); tGrenade.nextthink = time_base + 0.8; - if (gtype == GREN_CALTROP) + if (gdesc->id == GREN_CALTROP) tGrenade.heat = time_base + 0.5 + 0.5; else { tGrenade.heat = time_base + 3 + 0.8; - RemoveGrenadeTimers(); - - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - local float notimers = stof(infokey(self, "nt")); - if (grentimers && notimers != 1) { - timer = spawn(); - timer.nextthink = time_base + 0.8; - timer.think = GrenadeTimer; - timer.heat = 4; - timer.owner = self; - timer.classname = "gtimer"; - if (!notimers && !csqcactive) { - stuffcmd(self, "play grentimer\n"); - } - } - if (grentimers && csqcactive) { - UpdateClientGrenadePrimed(self, gtype, tGrenade.heat); - } + UpdateClientGrenadePrimed(self, gdesc->id, tGrenade.heat); } tGrenade.think = FO_GrenadeThink; self.grenade_timer = tGrenade; self.last_prime = global_to_client_time(time_base); -}; - +} void () FO_GrenadeThink = { local entity user = self.owner; @@ -1505,13 +1304,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[1]; self.max_grenades_2 = role.gren2_limits[1]; - if (old_grens == 1 || fo_flash == TRUE) - self.tp_grenades_1 = GREN_FLASH; - else - self.tp_grenades_1 = GREN_CALTROP; - - self.tp_grenades_2 = GREN_CONC; - self.tf_items = PC_SCOUT_TF_ITEMS; if (self.tf_items_flags <= 0) @@ -1562,9 +1354,7 @@ void () TeamFortress_SetEquipment = { self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL; self.max_grenades_1 = role.gren1_limits[2]; self.max_grenades_2 = role.gren2_limits[2]; - - self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2; + self.tf_items = PC_SNIPER_TF_ITEMS; self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS; @@ -1613,20 +1403,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[3]; self.max_grenades_2 = role.gren2_limits[3]; - self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1; - - switch (nailgren_type) { - case NGR_TYPE_NAIL: - self.tp_grenades_2 = GREN_NAIL; - break; - case NGR_TYPE_LASER: - self.tp_grenades_2 = GREN_SHOCK; - break; - case NGR_TYPE_BURST: - self.tp_grenades_2 = GREN_BURST; - break; - } - self.tf_items = PC_SOLDIER_TF_ITEMS; self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS; @@ -1675,8 +1451,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[4]; self.max_grenades_2 = role.gren2_limits[4]; - self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2; self.tf_items = PC_DEMOMAN_TF_ITEMS; self.ammo_detpack = PC_DEMOMAN_INITAMMO_DETPACK; @@ -1728,13 +1502,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[5]; self.max_grenades_2 = role.gren2_limits[5]; - self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1; - if(medic_type == MEDIC_TYPE_BLAST) { - self.tp_grenades_2 = GREN_BLAST; - } else { - self.tp_grenades_2 = GREN_CONC; - } - self.tf_items = PC_MEDIC_TF_ITEMS; self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS; @@ -1808,9 +1575,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[6]; self.max_grenades_2 = role.gren2_limits[6]; - self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2; - self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS; self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE; @@ -1860,9 +1624,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[7]; self.max_grenades_2 = role.gren2_limits[7]; - self.tp_grenades_1 = PC_PYRO_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_PYRO_GRENADE_TYPE_2; - self.armorclass = self.armorclass | PC_PYRO_INITARMORCLASS; self.armor_allowed = PC_PYRO_MAXARMORTYPE; if (old_hp_armor) @@ -1909,8 +1670,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = PC_CIVILIAN_GRENADE_MAX_1; self.max_grenades_2 = PC_CIVILIAN_GRENADE_MAX_2; - self.tp_grenades_1 = PC_CIVILIAN_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_CIVILIAN_GRENADE_TYPE_2; self.tf_items = PC_CIVILIAN_TF_ITEMS; self.armorclass = self.armorclass | PC_CIVILIAN_INITARMORCLASS; @@ -1961,8 +1720,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[8]; self.max_grenades_2 = role.gren2_limits[8]; - self.tp_grenades_1 = PC_SPY_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_SPY_GRENADE_TYPE_2; self.tf_items = PC_SPY_TF_ITEMS; self.armorclass = self.armorclass | PC_SPY_INITARMORCLASS; @@ -2020,8 +1777,6 @@ void () TeamFortress_SetEquipment = { self.max_grenades_1 = role.gren1_limits[9]; self.max_grenades_2 = role.gren2_limits[9]; - self.tp_grenades_1 = PC_ENGINEER_GRENADE_TYPE_1; - self.tp_grenades_2 = PC_ENGINEER_GRENADE_TYPE_2; self.tf_items = PC_ENGINEER_TF_ITEMS; self.armorclass = self.armorclass | PC_ENGINEER_INITARMORCLASS; @@ -2039,8 +1794,6 @@ void () TeamFortress_SetEquipment = { self.no_grenades_1 = 0; self.no_grenades_2 = 0; - self.tp_grenades_1 = 0; - self.tp_grenades_2 = 0; self.max_grenades_1 = 0; self.max_grenades_2 = 0; @@ -2219,7 +1972,6 @@ void () TeamFortress_RemoveTimers = { } RemoveAutoIdTimer(); - RemoveGrenadeTimers(); RemovePrimeTimers(); self.StatusGrenTime = 0; Status_Refresh(self); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index d9591cef..718a2707 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -22,7 +22,7 @@ void () TeamFortress_DisplayLegalClasses; void () TeamFortress_ShowIDs; void () TeamFortress_ShowTF; -void (float inp, float is_player) TeamFortress_PrimeGrenade; +void TeamFortress_PrimeGrenade(float inp, float is_player); void () TeamFortress_ThrowGrenade; void (float inp) TeamFortress_PrimeThrowGrenade; diff --git a/ssqc/world.qc b/ssqc/world.qc index 342a8d0a..b13cc027 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -333,8 +333,6 @@ void () worldspawn = { clientstat(STAT_ALL_TIME, EV_FLOAT, all_time); clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); clientstat(STAT_CLASS, EV_FLOAT, playerclass); - clientstat(STAT_NO_GREN1, EV_FLOAT, no_grenades_1); - clientstat(STAT_NO_GREN2, EV_FLOAT, no_grenades_2); clientstat(STAT_SPAWN_GEN,EV_FLOAT, spawn_gen); globalstat(STAT_ROUND_END, EV_FLOAT, "round_end_time"); From 43466b9f599a25674f9cbe912f8bfc1ccec0f64b Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Sep 2023 11:38:13 -0700 Subject: [PATCH 2182/2474] wp: unify playerclass sbar --- csqc/csextradefs.qc | 1 - csqc/events.qc | 4 +- csqc/hud.qc | 389 +++++++++++++++++++++-------------------- csqc/main.qc | 7 +- csqc/menu.qc | 6 +- csqc/status.qc | 14 +- csqc/weapon_predict.qc | 4 + share/defs.h | 13 +- ssqc/world.qc | 1 - 9 files changed, 218 insertions(+), 221 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1b7e6c0a..f2ca4954 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -272,7 +272,6 @@ typedef struct { float FragStreak; float Caps; string Identify; - float PlayerClass; string MOTD; string Hint; //1 = Clanmode, 2 = Quadmode, 4 = Duelmode, 8 = Prematch diff --git a/csqc/events.qc b/csqc/events.qc index 39a9c888..6ba27e30 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -549,9 +549,9 @@ void ParseSBAR() SBAR.ClipSize = readstring(); SBAR.FragStreak = readfloat(); SBAR.Caps = readfloat(); - SBAR.PlayerClass = readfloat(); + float class_info = readfloat(); - switch (SBAR.PlayerClass) + switch (class_info) { case PC_SCOUT: SBAR.ScannerOn = readfloat(); diff --git a/csqc/hud.qc b/csqc/hud.qc index 56249351..0ab8b15f 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -791,244 +791,245 @@ void Hud_DrawClassInfoPanel(float playerclass) if (!fo_hud_editor && !panel->Display) return; - switch (SBAR.PlayerClass) { + switch (WP_PlayerClass()) { case PC_SOLDIER: return; } - if (SBAR.PlayerClass) { - if (hud_panel(id, pos, panel->FillSize * panel->Scale, 0, panel->Display)) { - // click event - } + if (!WP_PlayerClass() || WP_PlayerClass() == PC_SOLDIER) + return; - float val; - vector size = FO_Hud_Icon_Size * panel->Scale; - vector fontSize = FO_Hud_Icon_Font_Size * (panel->TextScale ? panel->TextScale : panel->Scale); - pos = [pos_x + 2, pos_y + 2, 0]; - vector basepos = pos; - vector colour = '1 1 1'; - string icon = ""; - string msg = ""; + if (hud_panel(id, pos, panel->FillSize * panel->Scale, 0, panel->Display)) { + // click event + } - //icon = HudIcons[playerclass-1].icon; - /* icon = HudIcons[playerclass+6].icon; */ - /* HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); */ + float val; + vector size = FO_Hud_Icon_Size * panel->Scale; + vector fontSize = FO_Hud_Icon_Font_Size * (panel->TextScale ? panel->TextScale : panel->Scale); + pos = [pos_x + 2, pos_y + 2, 0]; + vector basepos = pos; + vector colour = '1 1 1'; + string icon = ""; + string msg = ""; - float len = 0, offset = 0; + //icon = HudIcons[playerclass-1].icon; + /* icon = HudIcons[playerclass+6].icon; */ + /* HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); */ - switch (playerclass) - { - case PC_SCOUT: - icon = ICON_SCOUT; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + float len = 0, offset = 0; - msg = SBAR.ScannerOn ? "Scanning" : "Offline"; - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - if (SBAR.ScannerOn) - { - msg = SBAR.ScannerRange ? strcat("Dist: ", ftos(SBAR.ScannerRange)) : "No targets"; - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); - if (SBAR.ScannerRange) - { - msg = (SBAR.ScannerTeamNo == team_no) ? "Friendly" : "Enemy"; - msg = strcat(msg, " ", ClassToString(SBAR.ScannerPlayerClass)); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); - } - } - break; - case PC_SNIPER: - float sniper_dam = WP_SniperCharge(); - if (sniper_dam) - { - icon = ICON_SNIPER; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + switch (playerclass) + { + case PC_SCOUT: + icon = ICON_SCOUT; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = strcat("Dam: ", ftos(sniper_dam)); - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - - if (sniper_dam == PC_SNIPER_MAXDAM) { - msg = "(100%)"; - colour = '1 0 0'; - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); - } - } - break; - case PC_DEMOMAN: - if (SBAR.IsDetpacking) + msg = SBAR.ScannerOn ? "Scanning" : "Offline"; + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + if (SBAR.ScannerOn) + { + msg = SBAR.ScannerRange ? strcat("Dist: ", ftos(SBAR.ScannerRange)) : "No targets"; + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + if (SBAR.ScannerRange) { - icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - - msg = "Setting"; - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - - msg = strcat(ftos(SBAR.DetpackLeft), " (", ftos(SBAR.IsDetpacking), ") secs left"); + msg = (SBAR.ScannerTeamNo == team_no) ? "Friendly" : "Enemy"; + msg = strcat(msg, " ", ClassToString(SBAR.ScannerPlayerClass)); HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } - else if (SBAR.DetpackLeft) - { - icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + } + break; + case PC_SNIPER: + float sniper_dam = WP_SniperCharge(); + if (sniper_dam) + { + icon = ICON_SNIPER; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = strcat(ftos(SBAR.DetpackLeft), " secs left"); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + msg = strcat("Dam: ", ftos(sniper_dam)); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + + if (sniper_dam == PC_SNIPER_MAXDAM) { + msg = "(100%)"; + colour = '1 0 0'; + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } - break; - case PC_MEDIC: - icon = ICON_MEDIC; //HudIcons[playerclass+6].icon; + } + break; + case PC_DEMOMAN: + if (SBAR.IsDetpacking) + { + icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = SBAR.AuraActive ? "On" : "Off"; + msg = "Setting"; pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - if (SBAR.AuraActive) + + msg = strcat(ftos(SBAR.DetpackLeft), " (", ftos(SBAR.IsDetpacking), ") secs left"); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + } + else if (SBAR.DetpackLeft) + { + icon = ICON_DEMOMAN; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + + msg = strcat(ftos(SBAR.DetpackLeft), " secs left"); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + } + break; + case PC_MEDIC: + icon = ICON_MEDIC; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + + msg = SBAR.AuraActive ? "On" : "Off"; + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + if (SBAR.AuraActive) + { + if (SBAR.HealCount) { - if (SBAR.HealCount) - { - msg = strcat(ftos(SBAR.HealCount), " players healed"); - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + msg = strcat(ftos(SBAR.HealCount), " players healed"); + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); - msg = strcat("for ", ftos(SBAR.HealAmount), " hp"); + msg = strcat("for ", ftos(SBAR.HealAmount), " hp"); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + } + else + { + if (SBAR.AuraStatus == PC_MEDIC_AURA_OUTOFPOWER) + { + msg = "Out of power"; HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } - else + else if (SBAR.AuraStatus == PC_MEDIC_AURA_RECHARGING) { - if (SBAR.AuraStatus == PC_MEDIC_AURA_OUTOFPOWER) - { - msg = "Out of power"; - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); - } - else if (SBAR.AuraStatus == PC_MEDIC_AURA_RECHARGING) - { - msg = "Recharging"; - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); - } + msg = "Recharging"; + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } } - break; - case PC_HVYWEAP: - if (WP_LockedCannon()) - { - icon = ICON_HWGUY; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + } + break; + case PC_HVYWEAP: + if (WP_LockedCannon()) + { + icon = ICON_HWGUY; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = "Assault Cannon Locked"; - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - } - break; - case PC_PYRO: - if (SBAR.AirBlast) - { - icon = ICON_PYRO; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = "Assault Cannon Locked"; + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + } + break; + case PC_PYRO: + if (SBAR.AirBlast) + { + icon = ICON_PYRO; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + + msg = "Airblast Cooling Down"; + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + } + else if (!SBAR.AirBlast) + { + icon = ICON_PYRO; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + + msg = "Airblast Ready"; + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + } + break; + case PC_SPY: + if (SBAR.IsUndercover == 1) + { + icon = ICON_SPY; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = "Airblast Cooling Down"; - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + if (SBAR.InvisOnly) + { + msg = "Invisible"; + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); } - else if (!SBAR.AirBlast) + else { - icon = ICON_PYRO; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = "Undercover"; + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + msg = strcat(TeamToString(SBAR.UndercoverTeam), " ", ClassToString(SBAR.UndercoverSkin)); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + } + } + else if (SBAR.IsUndercover == 2) + { + icon = ICON_SPY; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = "Airblast Ready"; - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + if (SBAR.InvisOnly) + { + msg = "Invisible"; + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + msg = strcat("In ", ftos(SBAR.UndercoverTimer), " secs"); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } - break; - case PC_SPY: - if (SBAR.IsUndercover == 1) + else { - icon = ICON_SPY; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - - if (SBAR.InvisOnly) + msg = "Disguising"; + pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + if (SBAR.DisguiseTeam) { - msg = "Invisible"; - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + msg = strcat("(", TeamToString(SBAR.DisguiseTeam), SBAR.QueueSkin ? "" : ") "); } - else + else if (SBAR.QueueTeam) { - msg = "Undercover"; - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - msg = strcat(TeamToString(SBAR.UndercoverTeam), " ", ClassToString(SBAR.UndercoverSkin)); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + msg = strcat("(", TeamToString(SBAR.QueueTeam), " "); } - } - else if (SBAR.IsUndercover == 2) - { - icon = ICON_SPY; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - - if (SBAR.InvisOnly) + else if (SBAR.UndercoverTeam) { - msg = "Invisible"; - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - msg = strcat("In ", ftos(SBAR.UndercoverTimer), " secs"); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + msg = strcat(TeamToString(SBAR.UndercoverTeam), " "); } - else + string msg2 = ""; + if (SBAR.DisguiseSkin) { - msg = "Disguising"; - pos = HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - if (SBAR.DisguiseTeam) - { - msg = strcat("(", TeamToString(SBAR.DisguiseTeam), SBAR.QueueSkin ? "" : ") "); - } - else if (SBAR.QueueTeam) - { - msg = strcat("(", TeamToString(SBAR.QueueTeam), " "); - } - else if (SBAR.UndercoverTeam) - { - msg = strcat(TeamToString(SBAR.UndercoverTeam), " "); - } - string msg2 = ""; - if (SBAR.DisguiseSkin) - { - msg2 = strcat(SBAR.QueueTeam ? "" : "(", ClassToString(SBAR.DisguiseSkin), ")"); - } - else if (SBAR.QueueSkin) - { - msg2 = strcat(" ", ClassToString(SBAR.QueueSkin), ")"); - } - else if (SBAR.UndercoverSkin) - { - msg2 = strcat(ClassToString(SBAR.UndercoverSkin)); - } - msg = strcat(msg, msg2); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); + msg2 = strcat(SBAR.QueueTeam ? "" : "(", ClassToString(SBAR.DisguiseSkin), ")"); + } + else if (SBAR.QueueSkin) + { + msg2 = strcat(" ", ClassToString(SBAR.QueueSkin), ")"); } + else if (SBAR.UndercoverSkin) + { + msg2 = strcat(ClassToString(SBAR.UndercoverSkin)); + } + msg = strcat(msg, msg2); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, TRUE, colour); } - break; - case PC_ENGINEER: - if (SBAR.HasSentry) - { - icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + } + break; + case PC_ENGINEER: + if (SBAR.HasSentry) + { + icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(rint(SBAR.SentryHealth)), " S: ", ftos(rint(SBAR.SentryAmmoShells)), " R: ", ftos(rint(SBAR.SentryAmmoRockets))); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - } - else if (SBAR.IsBuilding) - { - icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = strcat("L: ", ftos(SBAR.SentryLevel), " H: ", ftos(rint(SBAR.SentryHealth)), " S: ", ftos(rint(SBAR.SentryAmmoShells)), " R: ", ftos(rint(SBAR.SentryAmmoRockets))); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + } + else if (SBAR.IsBuilding) + { + icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); - msg = strcat(ftos(SBAR.BuildingPercentage), "%"); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - } - - // disp - pos = [pos_x, pos_y + size_y + 2]; - basepos = pos; - if (SBAR.HasDispenser) - { - icon = ICON_ENGINEER_DISP; //HudIcons[playerclass + 7].icon; - HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + msg = strcat(ftos(SBAR.BuildingPercentage), "%"); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + } - msg = strcat("H: ", ftos(rint(SBAR.DispenserHealth))); - HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); - } - break; - } + // disp + pos = [pos_x, pos_y + size_y + 2]; + basepos = pos; + if (SBAR.HasDispenser) + { + icon = ICON_ENGINEER_DISP; //HudIcons[playerclass + 7].icon; + HRC_drawpic(pos, icon, size, '1 1 1', 1, 0); + + msg = strcat("H: ", ftos(rint(SBAR.DispenserHealth))); + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, pos, basepos, FALSE, colour); + } + break; } } diff --git a/csqc/main.qc b/csqc/main.qc index f43946cc..04c3ea4b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -412,14 +412,12 @@ noref float(string cmd) CSQC_ConsoleCommand = { break; case "+rj": - if (player_class == PC_SOLDIER || player_class == PC_PYRO) { + if (WP_PlayerClass() == PC_SOLDIER || WP_PlayerClass() == PC_PYRO) localcmd("+button4\n"); - } break; case "-rj": - if (player_class == PC_SOLDIER || player_class == PC_PYRO) { + if (WP_PlayerClass() == PC_SOLDIER || WP_PlayerClass() == PC_PYRO) localcmd("-button4\n"); - } break; case "wpp_status": WPP_Status(); @@ -677,7 +675,6 @@ void _Sync_ServerCommandFrame() { team_no = getstatf(STAT_TEAMNO); all_time = getstatf(STAT_ALL_TIME); - player_class = getstatf(STAT_CLASS); SBAR.ReadyStatus = getstatf(STAT_FLAGS); game_state.localentnum = player_localentnum; diff --git a/csqc/menu.qc b/csqc/menu.qc index fb20ff21..58235ab3 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -1273,8 +1273,7 @@ void FO_Menu_Special(float force) = { return; fo_menu* NewMenu = __NULL__; - //void(float) nm; - switch (SBAR.PlayerClass) { + switch (WP_PlayerClass()) { case PC_SCOUT: NewMenu = &FO_MENU_SCOUT; //nm = FO_Menu_Scout; @@ -1300,8 +1299,7 @@ void FO_Menu_Special(float force) = { Menu_Cancel(); return; } - //CurrentMenu = NewMenu; - switch (SBAR.PlayerClass) { + switch (WP_PlayerClass()) { case PC_SCOUT: FO_Menu_Scout(force, FALSE, FALSE); //TODO: fix scanner settings break; diff --git a/csqc/status.qc b/csqc/status.qc index f722a884..4d82e3ac 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -49,7 +49,7 @@ void(PanelID ignored, string text) drawCapsPanel = { }; void(PanelID panelid, string text) drawGren1Panel = { - float playerclass = SBAR.PlayerClass; + float playerclass = WP_PlayerClass(); if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) return; @@ -59,7 +59,7 @@ void(PanelID panelid, string text) drawGren1Panel = { }; void(PanelID ignored, string text) drawGren2Panel = { - float playerclass = SBAR.PlayerClass; + float playerclass = WP_PlayerClass(); if (playerclass < PC_SCOUT || playerclass > PC_ENGINEER) return; @@ -69,8 +69,8 @@ void(PanelID ignored, string text) drawGren2Panel = { }; void(PanelID ignored, string text) drawSpecial = { - if (SBAR.PlayerClass || fo_hud_editor) - Hud_DrawClassInfoPanel(SBAR.PlayerClass); + if (WP_PlayerClass() || fo_hud_editor) + Hud_DrawClassInfoPanel(WP_PlayerClass()); }; void(PanelID panelid, string text) drawGrenTimerPanel = { @@ -125,7 +125,7 @@ void(PanelID panelid, string text) drawFacePanel = { if (!CVARF(fo_fte_hud)) return; - local float playerclass = SBAR.PlayerClass; //we could add different faces per class? + local float playerclass = WP_PlayerClass(); //we could add different faces per class? local string icon = FaceInvisibleInvulnerableIcon.icon; @@ -164,7 +164,7 @@ void(PanelID panelid, string text) drawArmourPanel = { if(!CVARF(fo_fte_hud)) return; - local float playerclass = SBAR.PlayerClass; + local float playerclass = WP_PlayerClass(); local string icon = fo_hud_editor?ArmourIcons[1].icon:""; @@ -1099,7 +1099,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_CAPS, "caps", FO_HUD_CAPS_NAME, '10 80', '26 26', 1,0,1,0,0, drawCapsPanel, {return ftos(SBAR.Caps);}}, {HUDP_GREN1, "gren1", FO_HUD_GREN1_NAME, '10 110', '26 26', 1,0,1,0,0, drawGren1Panel, {return ftos(WP_GrenCount(1));}}, {HUDP_GREN2, "gren2", FO_HUD_GREN2_NAME, '10 140', '26 26', 1,0,1,0,0, drawGren2Panel, {return ftos(WP_GrenCount(2));}}, - {HUDP_SPECIAL, "playerclass", FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0,0, drawSpecial, {return ftos(SBAR.PlayerClass);}}, + {HUDP_SPECIAL, "playerclass", FO_HUD_SPECIAL_NAME, '10 170', '50 26', 1,0,1,0,0, drawSpecial, {return ftos(WP_PlayerClass());}}, {HUDP_IDENTIFY, "identify", FO_HUD_IDENTIFY_NAME, '10 200', '50 26', 1,0,1,FO_HUD_INSERT_MIDDLE, 0, drawIdentify, {return SBAR.Identify;}}, {HUDP_FLAGINFO, "flaginfo", FO_HUD_FLAGINFO_NAME, '10 230', '26 260', 1,0,1,0,0, drawFlagInfo, {return "";}}, {HUDP_GRENTIMER, "grentimer", FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0,0, drawGrenTimerPanel, {return "";}}, diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 05f5191f..f57d1875 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -42,6 +42,10 @@ inline float PP_Enabled() { return pengine.pp_enabled; } inline float WP_Enabled() { return pengine.wp_enabled; } inline float WPP_ViewModelMask() { return pengine.view_mask; } +float WP_PlayerClass() { + return pstate_server.playerclass; +} + float WP_MinPing() { if (CVARF(wpp_min_ping) == -1) return fo_config.wp_default_min_ping_ms; diff --git a/share/defs.h b/share/defs.h index 01de5f0f..906e2bf7 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1450,13 +1450,12 @@ enumflags { // first 32 are reserved #define STAT_TEAMNO 33 #define STAT_FLAGS 34 -#define STAT_CLASS 35 -#define STAT_PAUSED 38 -#define STAT_NOFIRE 39 -#define STAT_TEAMNO_ATTACK 40 -#define STAT_ALL_TIME 41 -#define STAT_SPAWN_GEN 42 -#define STAT_ROUND_END 43 +#define STAT_PAUSED 35 +#define STAT_NOFIRE 36 +#define STAT_TEAMNO_ATTACK 37 +#define STAT_ALL_TIME 38 +#define STAT_SPAWN_GEN 39 +#define STAT_ROUND_END 40 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/world.qc b/ssqc/world.qc index b13cc027..ab5f5dd4 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -332,7 +332,6 @@ void () worldspawn = { clientstat(STAT_TEAMNO, EV_FLOAT, team_no); clientstat(STAT_ALL_TIME, EV_FLOAT, all_time); clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); - clientstat(STAT_CLASS, EV_FLOAT, playerclass); clientstat(STAT_SPAWN_GEN,EV_FLOAT, spawn_gen); globalstat(STAT_ROUND_END, EV_FLOAT, "round_end_time"); From 153f20f634f29932daddf3870401e1d8d404807e Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Sep 2023 13:26:06 -0700 Subject: [PATCH 2183/2474] wp: refactor and improve performance Improve prediction performance by not recomputing predictions for the same server/client frame pair. --- csqc/weapon_predict.qc | 27 +++++++++++++++++---------- share/physics.qc | 3 ++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f57d1875..6906a71a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -22,7 +22,7 @@ struct pengine_t { float pp_enabled; float wp_enabled; float is_effectframe; - float last_effectframe, last_effectframe2; + float last_effectframe; float player_entnum; // player_localentnum iff is_player == 1 entity player_ent; @@ -1902,15 +1902,9 @@ void PredictConc() { pstate_pred.tfstate &= ~TFSTATE_CONC; } -float WP_ClientThink() { - pstate_pred = pstate_server; - PredictConc(); - - if (!WP_Enabled()) - return PREDRAW_NEXT; - +static void WP_UpdatePredict() { + PredictConc(); // Looks like this is missing time/prediction interp getinputstate(servercommandframe); // Setup first read for old_buttons. - pengine.last_effectframe2 = pengine.last_effectframe; float old_input_buttons; int pframe = servercommandframe + 1; @@ -1944,7 +1938,20 @@ float WP_ClientThink() { } WP_UpdateViewModel(); - return PREDRAW_AUTOADD; +} + +DEFCVAR_FLOAT(fo_beta_noskip_predict, 0); +float WP_ClientThink() { + static float lsf, lcf; + if (lsf == servercommandframe && lcf == clientcommandframe && + !CVARF(fo_beta_noskip_predict)) + return PREDRAW_NEXT; + + pstate_pred = pstate_server; + + if (WP_Enabled()) + WP_UpdatePredict(); + return PREDRAW_NEXT; } void InitWeapPredEnt(entity pe) { diff --git a/share/physics.qc b/share/physics.qc index 6d151403..8b46c592 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -270,7 +270,8 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { total += dt; } - setorigin(e, e.origin); + if (step > 0) // Origin can have moved. + setorigin(e, e.origin); return total; } From 2c87edf252c6a824c8b103d1acb9944cf63735b5 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 16 Sep 2023 18:28:05 -0700 Subject: [PATCH 2184/2474] wp: remove some trailing references to player_class These missed migration to prediction ent; was breaking rj, ready notice, etc --- csqc/csextradefs.qc | 1 - csqc/main.qc | 4 ++-- csqc/menu.qc | 4 ++-- csqc/status.qc | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f2ca4954..dd26aa7f 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -861,7 +861,6 @@ GameState game_state, prev_game_state; float team_no; float crosshair_team_no; float all_time; -float player_class; float painfinished; vector thisorigin; float jump_counter; diff --git a/csqc/main.qc b/csqc/main.qc index 04c3ea4b..1e3d1c81 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -629,13 +629,13 @@ noref void CSQC_Input_Frame() { Sync_GameState(); // Intercept rocket jump; - if ((player_class == PC_SOLDIER || player_class == PC_PYRO) && + if ((WP_PlayerClass() == PC_SOLDIER || WP_PlayerClass() == PC_PYRO) && (input_buttons & BUTTON4)) input_buttons |= BUTTON0 | BUTTON2; // Handle zoom float prev_zoomed_in = zoomed_in; - if (player_class == PC_SNIPER) + if (WP_PlayerClass() == PC_SNIPER) zoomed_in = input_buttons & BUTTON3; else zoomed_in = 0; diff --git a/csqc/menu.qc b/csqc/menu.qc index 58235ab3..bfb7152d 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -105,7 +105,7 @@ var fo_menu FO_MENU_SPECTATOR_TRACK = { void teamChosen(string team) = { localcmd("cmd changeteam ", team, "\n"); - if(player_class) { + if(WP_PlayerClass()) { Menu_Cancel(); } else { FO_Menu_Class(TRUE); @@ -1000,7 +1000,7 @@ void FO_Menu_DropAmmo(float force) { } return; } - if (player_class == PC_ENGINEER) { + if (WP_PlayerClass() == PC_ENGINEER) { FO_MENU_DROPAMMO.title = "Drop or Make Ammo"; if ((getstatf(STAT_SHELLS) < DROP_SHELLS) && ((getstatf(STAT_CELLS) / AMMO_COST_SHELLS) > (DROP_SHELLS - getstatf(STAT_SHELLS)))) { FO_MENU_DROPAMMO.options[0].value = "(make)"; diff --git a/csqc/status.qc b/csqc/status.qc index 4d82e3ac..9113e36b 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -528,7 +528,7 @@ void(PanelID panelid, string text) drawReadyPanel = { if(showingscores || !panel.Display) { return; } - if (prematch && team_no && player_class && !SBAR.CountdownStarted && + if (prematch && team_no && WP_PlayerClass() && !SBAR.CountdownStarted && game_state.is_player) { if(SBAR.ReadyStatus & PLAYER_READY) { message = "Ready"; From 88083c46afc57c696594af09687d1e9447f2d013 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 03:14:05 -0700 Subject: [PATCH 2185/2474] weapons: make weapon changing more reliable and add new features When queued on attack_finished we leave other impulses like weapon changes on the line until it is finished, making it possible for them to be overwritten when more than one impulse is sent. Improve this by moving weapon impulses (except quickslot because it's difficult to do the right thing there) to immediately queue rather than stay pending so that we can process them more reliably. Also add two new client options: `fo_nofirealpha` (default: -1) when set (e.g. not -1) controls alpha when you can't fire `fo_hue_weaponswap` (default: 0) when set, allows you to visually swap weapons prior to attack finished. Note that these can be combined. --- csqc/weapon_predict.qc | 100 +++++++++++++++++++++++++++-------------- ssqc/weapons.qc | 18 ++++---- 2 files changed, 76 insertions(+), 42 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6906a71a..ac42989d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -16,6 +16,14 @@ DEFCVAR_FLOAT(r_drawviewmodel, 1); DEFCVAR_FLOAT(fo_reloadalpha, 0); DEFCVAR_FLOAT(fo_reloadvolume, 0); +// Alpha of weapon when unable to attck (e.g. time < attack_finished). +// Default: -1 means no change to alpha when in this state. +DEFCVAR_FLOAT(fo_nofirealpha, -1); + +// HueTF style -- does not wait for attack finished to render the queued weapon; +// purely visual, still have to wait for attack_finished. +DEFCVAR_FLOAT(fo_hue_weaponswap, 0); + static float wp_ready; struct pengine_t { @@ -841,6 +849,12 @@ float WP_ReloadSlot(Slot slot); void WP_ReloadNext(); void WPP_Dump(); +float WP_WeaponReady() { + const float not_ready_mask = TFSTATE_RELOADING | TFSTATE_NO_WEAPON; + return pstate_pred.client_time >= pstate_pred.attack_finished && + (pstate_pred.tfstate & not_ready_mask) == 0; +} + static void WP_ChangeIfQueued() { if (!IsSlotNull(pstate_pred.queue_slot)) { WP_ChangeWeapon(pstate_pred.queue_slot); @@ -886,40 +900,29 @@ void WP_HandleGrenadeInputs() { } void WP_Impulse() { + float match; + WP_HandleGrenadeInputs(); WP_HandleHeavyInputs(); // Note: We might have no impulse, but a queued slot here. float quick_swap = FALSE; + if (pstate_pred.impulse >= TF_QUICKSLOT1 && pstate_pred.impulse <= TF_QUICKSTOP && + !WP_WeaponReady()) { + // Filter these out because of potential double queuing pain; should + // probably try and deprecate. + return; + } + // Impulses that are NOT held by attack_finished / reloading. - float match = TRUE; + // * with a hacky exception for TF_QUICKSLOTs + match = TRUE; switch (pstate_pred.impulse) { - case TF_GRENADE_T: - W_ThrowGren(TRUE); - break; - case TF_DEBUG_CSQC: WPP_Dump(); break; - default: - match = FALSE; - break; - } - - if (match) - pstate_pred.impulse = 0; - - if (pstate_pred.client_time < pstate_pred.attack_finished || WP_IsReloading()) - return; - - WP_ChangeIfQueued(); // Might have something previously buffered. - - // Impulses that ARE held by attack_finished / reloading. - match = TRUE; - switch (pstate_pred.impulse) { - case 0: break; // Handled above. case TF_RELOAD: WP_ReloadSlot(CurrentSlot()); break; @@ -959,15 +962,37 @@ void WP_Impulse() { pstate_pred.playerclass, CurrentSlot(), TRUE); break; + case TF_GRENADE_T: + W_ThrowGren(TRUE); + break; + default: match = FALSE; break; } - WP_ChangeIfQueued(); // Might have something newly buffered. + // Impulse below this line depend on ready weapon. + if (!WP_WeaponReady()) + return; + + WP_ChangeIfQueued(); if (match) - pstate_pred.impulse = 0; + return; + + match = TRUE; + switch (pstate_pred.impulse) { + case TF_RELOAD: + WP_ReloadSlot(CurrentSlot()); + break; + + case TF_RELOAD_NEXT: + WP_ReloadNext(); + break; + default: + match = FALSE; + break; + } } static float* WP_ClipFired(Slot slot) { @@ -1835,20 +1860,29 @@ void WP_UpdateViewModel() { return; } + float alph; if (pstate_pred.tfstate & TFSTATE_RELOADING) { - float ra = CVARF(fo_reloadalpha); - if (ra > 0) { - viewmodel.alpha = ra; - } else { - viewmodel.modelindex = 0; - return; - } + alph = CVARF(fo_reloadalpha); } else { - viewmodel.alpha = CVARF(r_drawviewmodel); + alph = CVARF(r_drawviewmodel); + if (!WP_WeaponReady() && CVARF(fo_nofirealpha) != -1) + alph = CVARF(fo_nofirealpha); + } + + if (alph > 0) { + viewmodel.alpha = alph; + } else { + viewmodel.modelindex = 0; + return; } - pmodelindex = (wi->models)->modelindex; pframe = pstate_pred.weaponframe; + if (CVARF(fo_hue_weaponswap) && !IsSlotNull(pstate_pred.queue_slot)) { + wi = SlotWI(pstate_pred.queue_slot); + pframe = 0; + } + + pmodelindex = (wi->models)->modelindex; if (viewmodel.modelindex != pmodelindex) { viewmodel.frame = pframe; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 718a2707..f9e249ab 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1917,6 +1917,11 @@ void W_ChangeWeaponSlot(Slot slot) { Status_Refresh(self); }; +void W_ChangeQueuedWeaponIfReady() { + if (!IsSlotNull(self.queue_slot) && WeaponReady()) + W_ChangeWeaponSlot(self.queue_slot); +} + void W_ChangeWeaponLast() { if (!IsSlotNull(self.last_slot)) W_ChangeWeaponSlot(self.last_slot); @@ -2522,19 +2527,12 @@ void () W_WeaponFrame = { self.tfstate &= ~TFSTATE_QUICKSLOT; } - float can_change_weapon = WeaponReady(); - - // TODO: Open up queueing by moving queue can_change to ChangeWeapon? - if (!IsSlotNull(self.queue_slot) && can_change_weapon) - W_ChangeWeaponSlot(self.queue_slot); - - if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() && - can_change_weapon) { + if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput()) { // slot 1-4 (or 1-7) binds W_ChangeWeaponByInput(self.impulse); self.impulse = 0; } else if (self.impulse >= TF_QUICKSLOT1 && - self.impulse <= TF_QUICKSLOT4 && can_change_weapon) { + self.impulse <= TF_QUICKSLOT4 && WeaponReady()) { float input = InputHandlePyroSlotSwap(self.playerclass, self.impulse - TF_QUICKSLOT1 + 1); Slot slot = MakeSlot(input); @@ -2548,6 +2546,8 @@ void () W_WeaponFrame = { self.impulse = 0; } + W_ChangeQueuedWeaponIfReady(); + if (self.impulse == TF_CHANGETEAM) { Menu_Team(0); self.impulse = 0; From bcfab670eb77846595f71deb6e4b250bf27af1dd Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 03:35:03 -0700 Subject: [PATCH 2186/2474] wp: restore impulse clear Slightly simplify. --- csqc/weapon_predict.qc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ac42989d..343fb582 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -900,7 +900,7 @@ void WP_HandleGrenadeInputs() { } void WP_Impulse() { - float match; + float local_impulse; WP_HandleGrenadeInputs(); WP_HandleHeavyInputs(); @@ -917,8 +917,9 @@ void WP_Impulse() { // Impulses that are NOT held by attack_finished / reloading. // * with a hacky exception for TF_QUICKSLOTs - match = TRUE; - switch (pstate_pred.impulse) { + local_impulse = pstate_pred.impulse; + pstate_pred.impulse = 0; + switch (local_impulse) { case TF_DEBUG_CSQC: WPP_Dump(); break; @@ -932,10 +933,10 @@ void WP_Impulse() { break; case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: - pstate_pred.impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. + local_impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. quick_swap = TRUE; case 1: case 2: case 3: case 4: case 5: case 6: case 7: { - Slot slot = InputToSlot(pstate_pred.impulse); + Slot slot = InputToSlot(local_impulse); if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) { if (quick_swap) pstate_pred.tfstate |= TFSTATE_QUICKSLOT; @@ -945,14 +946,12 @@ void WP_Impulse() { } case TF_QUICKSTOP: - if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) { - pstate_pred.impulse = 0; + if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) break; - } pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. case TF_WEAPLAST: - pstate_pred.queue_slot = pstate_pred.last_slot; break; - + pstate_pred.queue_slot = pstate_pred.last_slot; + break; case TF_WEAPNEXT: pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( pstate_pred.playerclass,CurrentSlot(), FALSE); @@ -967,21 +966,22 @@ void WP_Impulse() { break; default: - match = FALSE; + pstate_pred.impulse = local_impulse; break; } - // Impulse below this line depend on ready weapon. + // Impulses below this line depend on ready weapon. if (!WP_WeaponReady()) return; WP_ChangeIfQueued(); - if (match) + if (!pstate_pred.impulse) // Handled above. return; - match = TRUE; - switch (pstate_pred.impulse) { + local_impulse = pstate_pred.impulse; + pstate_pred.impulse = 0; + switch (local_impulse) { case TF_RELOAD: WP_ReloadSlot(CurrentSlot()); break; @@ -990,7 +990,7 @@ void WP_Impulse() { WP_ReloadNext(); break; default: - match = FALSE; + pstate_pred.impulse = local_impulse; break; } } From 1cd97692c0f6682665890816b2b8ced42ad91bac Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 11:28:41 -0700 Subject: [PATCH 2187/2474] weapons: move +slotX to local and integrate weaplast with queueing Migrate all +slotX aliases to use the local +slot system so that we can delete the messy server side implementation (which doesnt play well with the new weapon queuing). Teach WEAPLAST about the new queuing (e.g. that when appropriate it should cancel a queued slot with no swap). --- csqc/weapon_predict.qc | 6 +++++- share/defs.h | 16 ++++++++-------- ssqc/weapons.qc | 5 ++++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 343fb582..86e19484 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -950,7 +950,11 @@ void WP_Impulse() { break; pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. case TF_WEAPLAST: - pstate_pred.queue_slot = pstate_pred.last_slot; + // Clearing queued counts as swap to whatever was pre-queued. + if (!IsSlotNull(pstate_pred.queue_slot)) + pstate_pred.queue_slot = SlotNull; + else + pstate_pred.queue_slot = pstate_pred.last_slot; break; case TF_WEAPNEXT: pstate_pred.queue_slot = FO_FindPrevNextWeaponSlot( diff --git a/share/defs.h b/share/defs.h index 906e2bf7..0a555d00 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1510,14 +1510,14 @@ TFAlias client_aliases[] = { {"slot2", TF_IMPULSE_SLOT2}, {"slot3", TF_IMPULSE_SLOT3}, {"slot4", TF_IMPULSE_SLOT4}, - {"+slot1", 0, "impulse 20;+attack"}, - {"-slot1", 0, "-attack;impulse 24"}, - {"+slot2", 0, "impulse 21;+attack"}, - {"-slot2", 0, "-attack;impulse 24"}, - {"+slot3", 0, "impulse 22;+attack"}, - {"-slot3", 0, "-attack;impulse 24"}, - {"+slot4", 0, "impulse 23;+attack"}, - {"-slot4", 0, "-attack;impulse 24"}, + {"+slot1", 0, "+slot 1"}, + {"-slot1", 0, "-slot 1"}, + {"+slot2", 0, "+slot 2"}, + {"-slot2", 0, "-slot 2"}, + {"+slot3", 0, "+slot 3"}, + {"-slot3", 0, "-slot 3"}, + {"+slot4", 0, "+slot 4"}, + {"-slot4", 0, "-slot 4"}, {"+quick1", 0, "impulse 1;+attack"}, {"-quick1", 0, "-attack"}, {"+quick2", 0, "impulse 2;+attack"}, diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index f9e249ab..be3e0cc1 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1923,7 +1923,10 @@ void W_ChangeQueuedWeaponIfReady() { } void W_ChangeWeaponLast() { - if (!IsSlotNull(self.last_slot)) + // Clearing queued counts as swap to whatever was pre-queued. + if (!IsSlotNull(self.queue_slot)) + self.queue_slot = SlotNull; + else if (!IsSlotNull(self.last_slot)) W_ChangeWeaponSlot(self.last_slot); }; From ebfe984ae716e86f9020db682c133eb6b9d6ee7e Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 11:57:56 -0700 Subject: [PATCH 2188/2474] wp: free duplicate entities, force refresh on swap Clients transition between entities on entering/leaving the game, which allows for weapon prediction to be initialized more than once now that we also use it for spectators. Free old initializations when this occurs. Also force aggressve refresh when spectating a new player. --- csqc/main.qc | 2 +- csqc/weapon_predict.qc | 20 ++++++++++++-------- share/prediction.qc | 10 +++++++--- ssqc/client.qc | 1 + 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1e3d1c81..ca69b095 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -96,7 +96,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Hud_Init(); FO_Weapons_Init(); Predict_InitDefaultConfig(); - FO_PP_Init(); // Some of this is always used by custom projectiles. + FO_Predict_Init(); CsGrenTimer::Init(); slot_history_top = -1; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 86e19484..d867a3e1 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1303,7 +1303,14 @@ inline float get_phys_time(entity e) { } } -void FO_PP_Init() { +void FO_Predict_Init() { + entity viewmodel = spawn(); + viewmodel.drawmask = MASK_PRED_ENT; + viewmodel.renderflags = RF_VIEWMODEL | RF_DEPTHHACK; + pengine.viewmodel = viewmodel; + + WP_InitSniper(); + // Entity we'll attach locally generated sound to. pred_sound_entity = spawn(); @@ -1993,16 +2000,13 @@ float WP_ClientThink() { } void InitWeapPredEnt(entity pe) { - WP_InitSniper(); + if (pengine.pweap_ent != world) { + remove(pengine.pweap_ent); + } pe.predraw = WP_ClientThink; - pengine.pweap_ent = pe; pe.drawmask = MASK_PRED_ENT; - - entity viewmodel = spawn(); - viewmodel.drawmask = MASK_PRED_ENT; - viewmodel.renderflags = RF_VIEWMODEL | RF_DEPTHHACK; - pengine.viewmodel = viewmodel; + pengine.pweap_ent = pe; wp_ready = TRUE; } diff --git a/share/prediction.qc b/share/prediction.qc index f2e54cda..d24b28fc 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -25,6 +25,7 @@ enumflags { FOWP_PREDICT_FLAGS, FOWP_LAST, }; +const float FOWP_ALL = FOWP_LAST - 1; enumflags { FOPP_NEW, @@ -318,8 +319,14 @@ predict_tf_state pstate_pred, pstate_server; .float pred_lastforce; .float pred_forcebit; +.entity last_pred_src; static float Prediction_ChangedMask(entity player, entity src) { + if (src != player.last_pred_src) { + player.last_pred_src = src; + return FOWP_ALL; + } + float mask = FOWP_CTIME; player.predict_state.client_time = src.client_time; @@ -748,9 +755,6 @@ void Predict_InitPlayer(entity player) { if (player.predict_entity) return; - sprint(player, PRINT_HIGH, - "FortressOne: Weapon Prediction ", wp_version, "\n"); - entity pe = spawn(); pe.owner = player; pe.classname = "WeaponPred"; diff --git a/ssqc/client.qc b/ssqc/client.qc index 87298e02..7e049eba 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3043,6 +3043,7 @@ void () ClientConnect = { } bprint(PRINT_HIGH, self.netname, " entered the game\n"); + sprint(self, PRINT_HIGH, "FortressOne: Weapon Prediction ", wp_version, "\n"); spawnfunc_FOPlayer(); From 4239469d9bd341d07378b4da04ad6d6022fcbed7 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Sep 2023 12:29:13 -0700 Subject: [PATCH 2189/2474] wp: handle all owned grenade timers by prediction ent No longer use CSQC messages to pass state on primed grenades for either the active or spectated player. Now communicated entirely with prediction ent. Introduces (not yet enabled by default) support for starting the grenade timer using a predicted local time which eliminates the delay around timer-start at any ping. Controlled by `fo_beta_local_grenades 1` --- csqc/csextradefs.qc | 37 +++++++++++++++++----- csqc/events.qc | 50 +++++++++++------------------ csqc/status.qc | 2 +- csqc/weapon_predict.qc | 72 ++++++++++++++++++++++++++++++++++-------- share/prediction.qc | 8 +++-- ssqc/client.qc | 1 + ssqc/qw.qc | 3 +- ssqc/status.qc | 20 ------------ ssqc/tfort.qc | 3 ++ 9 files changed, 117 insertions(+), 79 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index dd26aa7f..c7b4a35c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -516,6 +516,7 @@ enumflags { FL_GT_SOUND, FL_GT_THROWN, FL_GT_ADJPING, + FL_GT_LOCAL, }; void(string identify) Hud_DrawIdentifyPanel; @@ -709,8 +710,8 @@ CsGrenTimer grentimers[NUM_GREN_TIMERS]; class CsGrenTimer { float index_; - float primed_at_; float expires_at_; + float raw_expires_at_; float flags_; float grentype_; float playing_; @@ -718,16 +719,19 @@ class CsGrenTimer { nonvirtual float() index { return index_; }; nonvirtual float() active { return expires_at_ > time; }; nonvirtual float() expiry { return expires_at_; }; + nonvirtual float() raw_expiry { return raw_expires_at_; }; nonvirtual float() grentype { return grentype_; }; - nonvirtual void() set_thrown { flags_ |= FL_GT_THROWN; }; - nonvirtual float() is_thrown { return flags_ & FL_GT_THROWN; }; + + nonvirtual float(float flag) test_flag { return flags_ & flag; }; + nonvirtual void(float flag) set_flag { flags_ |= flag; }; + nonvirtual void(float flag) clear_flag { flags_ &= ~flag; }; + nonvirtual float() sound_offset { float offset = max(3.8 - (expires_at_ - time), 0); return offset; }; - nonvirtual void(float primed_at, float expires_at, - float grentype, float timer_flags) Set; + nonvirtual void(float expires_at, float grentype, float timer_flags) Set; nonvirtual void() Stop; nonvirtual void() PauseSound { @@ -737,12 +741,15 @@ class CsGrenTimer { }; nonvirtual void() StartSound; - nonvirtual void(float offset) adj_sync { + nonvirtual void(float offset, float adj_sound) adj_sync { if (!playing_) return; - expires_at_ += offset; - StartSound(); + raw_expires_at_ += offset; + if (adj_sound) { // Not yet working well + expires_at_ += offset; + StartSound(); + } }; static float next_index_; @@ -764,6 +771,20 @@ class CsGrenTimer { return last_; }; + static CsGrenTimer(float exp, float eps) Match { + CsGrenTimer result = world; + float best = eps; + + for (float i = 0; i < grentimers.length; i++) { + float d = fabs(exp - grentimers[i].raw_expiry()); + if (d < best) { + best = d; + result = grentimers[i]; + } + } + return result; + }; + static void() SyncPause { // Time froze, but sound kept running, realign. for (float i = 0; i < grentimers.length; i++) diff --git a/csqc/events.qc b/csqc/events.qc index 6ba27e30..72e843a8 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -1,5 +1,6 @@ void ParseSBAR(); -void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); +CsGrenTimer ParseGrenPrimed(float grentype, float explodes_at, + float timer_flags = 0); void ParseHitFlag(vector targpos, float mitdmg, float rawdmg, float hitflag); float StartGrenTimer(float primed_at, float expires_at, float grentype, float play_sound); float FoLogin(string token, float print_error); @@ -105,24 +106,25 @@ void() CSQC_Parse_Event = { case MSG_GRENPRIMED: float entno = readentitynum(); float grentype = readbyte(); - float primed_at = readfloat(); float explodes_at = readfloat(); - if (entno != player_localentnum) + // The current player (inc spectated) handled via prediction ent. + if (game_state.is_player || entno == player_localentnum) return; - ParseGrenPrimed(grentype, primed_at, explodes_at); + ParseGrenPrimed(grentype, explodes_at); break; case MSG_GRENTHROWN: float entno = readentitynum(); - if (entno != player_localentnum) + // Current player (or spectated) handled via prediction ent. + if (game_state.is_player || entno == player_localentnum) return; CsGrenTimer last = CsGrenTimer::GetLast(); // It's possible to get THROWN without PRIMED when spectating a // player that primed before you started watching them. if (last != world && last.active()) - last.set_thrown(); + last.set_flag(FL_GT_THROWN); break; case MSG_TFX_GRENTIMER: float entnum = readentitynum(); @@ -368,8 +370,6 @@ void() CSQC_Parse_Event = { } } -DEFCVAR_FLOAT(fo_grentimer_debug, 0); - string cached_timer; string GetGrenTimerSound() { string wav = CVARS(fo_grentimersound); @@ -394,11 +394,9 @@ void CsGrenTimer::StartSound() { this.playing_ = TRUE; } -void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, - float timer_flags) { +void CsGrenTimer::Set(float expires_at, float _grentype, float timer_flags) { grentype_ = _grentype; - primed_at_ = primed_at; - expires_at_ = expires_at; + raw_expires_at_ = expires_at_ = expires_at; flags_ = timer_flags; playing_ = FALSE; @@ -416,6 +414,7 @@ void CsGrenTimer::Set(float primed_at, float expires_at, float _grentype, } void CsGrenTimer::Stop() { + raw_expires_at_ = -1; expires_at_ = -1; PauseSound(); // Pause is really stop. flags_ = 0; @@ -427,25 +426,11 @@ void StopGrenTimers() { grentimers[i].Stop(); } -void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { +CsGrenTimer ParseGrenPrimed(float grentype, float explodes_at, + float timer_flags = 0) { if (grentype == GREN_FLARE || grentype == GREN_CALTROP) - return; + return world; - // Very rough (but good enough for now) filter to disambiguate local - // predicted primes versus matched server primes. - static float last_explodes_at; - float delta = explodes_at - last_explodes_at; - if (fabs(delta) < 50 * MSEC) { - // Experimental patch up if prediction too far off. - if (CVARF(fo_beta_local_grenade) == 2 && delta > 10 * MSEC) { - CsGrenTimer last = CsGrenTimer::GetLast(); - last.adj_sync(delta); - } - return; - } - last_explodes_at = explodes_at; - - float timer_flags = 0; float timer_mode = game_state.is_player ? CVARF(fo_grentimer) : 1; switch (timer_mode) { case 0: break; @@ -457,16 +442,17 @@ void ParseGrenPrimed(float grentype, float primed_at, float explodes_at) { float debug_print_state = CVARF(fo_grentimer_debug) & 1; CsGrenTimer timer = CsGrenTimer::GetNext(); - timer.Set(primed_at, explodes_at, grentype, timer_flags); + timer.Set(explodes_at, grentype, timer_flags); if (debug_print_state) { float ping = getplayerkeyfloat(player_localnum, INFOKEY_P_PING) / 1000; float expires_at = timer.expiry(); - print(sprintf("primed_at=%0.2f expires_at=%0.2f explodes_at=%0.2f tfuse=%0.2f\n", - primed_at, expires_at, explodes_at, expires_at - primed_at)); + print(sprintf("expires_at=%0.2f explodes_at=%0.2f\n", expires_at, explodes_at)); } + + return timer; } #define HITFLAG(_fl_name) (hitflags & (HITFLAG_##_fl_name)) diff --git a/csqc/status.qc b/csqc/status.qc index 9113e36b..0cae022b 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -109,7 +109,7 @@ void(PanelID panelid, string text) drawGrenTimerPanel = { // if things get reordered, but since we can only ever have one // grenade primed, we can obscure this by always considering // grenades after the first as primed. - float alpha = (gt.is_thrown() || timercount) ? 0.3 : 1.0; + float alpha = (gt.test_flag(FL_GT_THROWN) || timercount) ? 0.3 : 1.0; string icon = FO_GrenDesc(gt.grentype())->icon; Hud_DrawPanelLMP(&panel2, ftos(timeleft), icon, alpha); panel2.Position = panel2.Position + diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index d867a3e1..a7510f61 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1567,12 +1567,13 @@ static float CanThrowGrenade(int gren_type) { return TRUE; } -void ParseGrenPrimed(float grentype, float primed_at, float explodes_at); - float WP_GrenCount(float index) { return index == 1 ? pstate_pred.no_grenades_1 : pstate_pred.no_grenades_2; } +CsGrenTimer ParseGrenPrimed(float grentype, float explodes_at, + float timer_flags = 0); + static void W_PrimeGren(float index) { if (!game_state.is_alive || getstatf(STAT_NOFIRE)) return; @@ -1586,12 +1587,17 @@ static void W_PrimeGren(float index) { if (*gc < 1) return; // No grenades left - float gren = FO_ClassGren(pstate_pred.playerclass, index)->id; - - pstate_pred.tfstate |= (index ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED); *gc -= 1; - if (IsEffectFrame()) - ParseGrenPrimed(gren, time, time + 3.8); + pstate_pred.tfstate |= index ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED; + + pstate_pred.primed_gren_type = FO_ClassGren(pstate_pred.playerclass, index)->id; + + static float held_gren_exp; + if (IsEffectFrame()) { + held_gren_exp = time + 3.8 + input_timelength / 2; + ParseGrenPrimed(pstate_pred.primed_gren_type, held_gren_exp, FL_GT_LOCAL); + } + pstate_pred.primed_gren_exp = held_gren_exp; } static void W_ThrowGren(float is_throw) { @@ -1918,8 +1924,48 @@ struct { } cuss_state; float ClownConcPeriod(); +void StopGrenTimers(); + +DEFCVAR_FLOAT(fo_grentimer_debug, 0); + +static void WP_GrenadeTimers() { + static float last_gen; + static float last_server_exp; + + // New life or player, reset and resync. + if (game_state.spawn_gen != last_gen) { + last_gen = game_state.spawn_gen; + StopGrenTimers(); + last_server_exp = 0; + } -void PredictConc() { + float server_exp = pstate_server.primed_gren_exp; + CsGrenTimer srv = CsGrenTimer::Match(server_exp, 25*MSEC); + + if (server_exp != last_server_exp) { + last_server_exp = server_exp; + + if (srv == world) { + srv = ParseGrenPrimed(pstate_server.primed_gren_type, server_exp); + } else { + if (CVARF(fo_grentimer_debug) & 2) + printf("gt update local: delta=%0.3f\n", server_exp - srv.raw_expiry()); + + // Previous local + if (!srv.test_flag(FL_GT_LOCAL)) + printf("Warning: local grenade mismatch! %0.3f %0.3f\n", server_exp, srv.raw_expiry()); + srv.clear_flag(FL_GT_LOCAL); + // Sound sync below not yet working well. + srv.adj_sync(server_exp - srv.raw_expiry(), + CVARF(fo_beta_local_grenade) == 2); + } + } + + if (srv != world && (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED == 0)) + srv.set_flag(FL_GT_THROWN); +} + +static void PredictConc() { if (IsClownMode(CLOWN_CONC)) { if (cuss_state.end_time < time) cuss_state.end_time = time + ClownConcPeriod(); @@ -1957,6 +2003,7 @@ static void WP_UpdatePredict() { int effect_frame = clientcommandframe - 1; pstate_server.seq = servercommandframe; + pstate_server.server_time = time; for(; pframe <= eframe; pframe++) { old_input_buttons = input_buttons; if (!getinputstate(pframe) || input_timelength <= 0) @@ -1976,6 +2023,7 @@ static void WP_UpdatePredict() { } pstate_pred.client_time += input_timelength; + pstate_pred.server_time += input_timelength; if (input_impulse) pstate_pred.impulse = input_impulse; @@ -1996,6 +2044,8 @@ float WP_ClientThink() { if (WP_Enabled()) WP_UpdatePredict(); + + WP_GrenadeTimers(); return PREDRAW_NEXT; } @@ -2011,13 +2061,7 @@ void InitWeapPredEnt(entity pe) { wp_ready = TRUE; } -void StopGrenTimers(); - void WP_ServerFrame() { if (game_state.is_player != prev_game_state.is_player) WPP_UpdateEnable(TRUE); - - if (game_state.spawn_gen != prev_game_state.spawn_gen && - game_state.is_alive) - StopGrenTimers(); } diff --git a/share/prediction.qc b/share/prediction.qc index d24b28fc..b412ee81 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -72,13 +72,14 @@ struct predict_tf_state { float clip_fired[4]; int prng_base[PRNG_NUM_STATES]; - float no_grenades_1, no_grenades_2, gren_exp; + float no_grenades_1, no_grenades_2, primed_gren_type, primed_gren_exp; #ifdef CSQC // Used for prediction, not actually communicated. Reset each frame. int seq; float ammo_used[AMMO_NUM_TYPES]; float buttons_down, buttons_up, buttons_held; + float server_time; #endif }; @@ -344,7 +345,7 @@ static float Prediction_ChangedMask(entity player, entity src) { M2(FOWP_RELOAD, reload_started, reload_finished); M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]); - M3(FOWP_GREN, no_grenades_1, no_grenades_2, gren_exp) + M4(FOWP_GREN, no_grenades_1, no_grenades_2, primed_gren_type, primed_gren_exp) // Rotate through forced update fields. if (time - player.pred_lastforce >= 100 * MSEC) { @@ -519,7 +520,8 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_GREN) { COMM(Short, no_grenades_1); COMM(Short, no_grenades_2); - COMM(Float, gren_exp); + COMM(Byte, primed_gren_type); + COMM(Float, primed_gren_exp); } #ifdef SSQC diff --git a/ssqc/client.qc b/ssqc/client.qc index 7e049eba..ea564ad8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2069,6 +2069,7 @@ void () PutClientInServer = { self.prng_base[PRNG_WEAP] = 65535 * random(); // For hwguy we rotate the seed value, each seed generates many random nums. self.prng_base[PRNG_HWGUY] = 65535 * random(); + self.primed_gren_exp = 0; self.immune_to_check = time + 10; SetDimensions(TRUE); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index c8ba27e3..a517f3da 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -43,7 +43,8 @@ float remote_client_time(); .float armorclass; // Type of armor being worn .float tf_items; // Another flag for player items .float tf_items_flags; // Flags for the player items -.float gren_exp; // Expiry of last primed grenade +.float primed_gren_type; // Type of (last) primed grenate +.float primed_gren_exp; // Expiry of (last) primed grenade .float no_grenades_1; // Number of grenades of type 1 being carried .float no_grenades_2; // Number of grenades of type 2 being carried .float hook_out; // Dummy field for hook to silence error messages diff --git a/ssqc/status.qc b/ssqc/status.qc index 81f65102..e36c2783 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -763,21 +763,6 @@ string GetSBClassInfo(entity pl, float csqcactive) return st1; } -// Temporary until we network player ents. -static void TFxUpdateGrenadeTimer(entity player, float explodes_at) { - const float tfx_gren_mask = - TFX_SPEC_GRENTIMER | TFX_DEFENSE_GRENTIMER | TFX_OFFENSE_GRENTIMER; - - if (!TFxEnabled(tfx_gren_mask)) - return; - - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_TFX_GRENTIMER); - WriteEntity(MSG_MULTICAST, player); - WriteFloat(MSG_MULTICAST, explodes_at); - multicast('0 0 0', MULTICAST_ALL_R); -} - void UpdateClientReloadSound(entity pl, float weapon) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; @@ -795,13 +780,10 @@ void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); WriteEntity(MSG_MULTICAST, pl); WriteByte(MSG_MULTICAST, grentype); - WriteFloat(MSG_MULTICAST, time); WriteFloat(MSG_MULTICAST, explodes_at); // Let's see if we can get away with avoiding _R here. multicast('0 0 0', MULTICAST_ALL); - - TFxUpdateGrenadeTimer(pl, explodes_at); } void UpdateClientGrenadeThrown(entity pl) = { @@ -810,8 +792,6 @@ void UpdateClientGrenadeThrown(entity pl) = { WriteByte(MSG_MULTICAST, MSG_GRENTHROWN); WriteEntity(MSG_MULTICAST, pl); multicast('0 0 0', MULTICAST_ALL); - - TFxUpdateGrenadeTimer(pl, 0); } void UpdateClientIDString(entity pl) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index d58ca5dc..cdcc7390 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -852,6 +852,7 @@ void TeamFortress_PrimeGrenade(float inp, float is_player) { } self.tfstate |= (inp == 1) ? TFSTATE_GREN1_PRIMED : TFSTATE_GREN2_PRIMED; + entity tGrenade = spawn(); tGrenade.owner = self; tGrenade.weapon = gdesc->id; @@ -870,6 +871,8 @@ void TeamFortress_PrimeGrenade(float inp, float is_player) { else { tGrenade.heat = time_base + 3 + 0.8; + self.primed_gren_type = gdesc->id; + self.primed_gren_exp = tGrenade.heat; UpdateClientGrenadePrimed(self, gdesc->id, tGrenade.heat); } From 6e284dafef2938583be7f2ecd7048eff875b0956 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 20:12:39 -0700 Subject: [PATCH 2190/2474] client: make "+slot x" handle owi The client-side `+slot x` blindly pass impulse x which is incorrect when OWI is active. Perform the reverse slot-to-impulse conversion. --- csqc/main.qc | 11 +++++++---- share/weapons.qc | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index ca69b095..2df5d793 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -222,18 +222,21 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { void Slot_Keydown(float slot) { PushToSlotHistory(slot); - localcmd(sprintf("impulse %f\n", slot)); - localcmd("+attack\n"); + + float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(slot)); + localcmd(sprintf("impulse %d\n+attack\n", impulse)); } void Slot_Keyup(float slot) { RemoveFromSlotHistory(slot); if (slot_history_top >= 0) { // still holding another +slot bind - localcmd(sprintf("impulse %f\n", slot_history[slot_history_top])); + float impulse = FO_SlotToImpulse(WP_PlayerClass(), + MakeSlot(slot_history[slot_history_top])); + localcmd(sprintf("impulse %d\n", impulse)); } else { if (CVARF(fo_default_weapon)) { - localcmd(sprintf("impulse %f\n", CVARF(fo_default_weapon))); + localcmd(sprintf("impulse %d\n", CVARF(fo_default_weapon))); } localcmd("-attack\n"); } diff --git a/share/weapons.qc b/share/weapons.qc index 2b98b2d1..befbcc17 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -34,7 +34,7 @@ float SlotIndex(Slot slot) { printf("ERROR: OOB slot id (%d) found. Continuing.\n", (float)slot.id); return TF_NUM_SLOTS - 1; } - return slot.id - 1; + return slot.id - 1; } // Convert a weapon-bit to a linear index. @@ -700,6 +700,19 @@ float InputHandlePyroSlotSwap(float playerclass, float input) { return input; } +float FO_SlotToImpulse(float playerclass, Slot slot) { + if (!IsUsingOldImpulses()) + return SlotIndex(slot) + 1; + + float weap = FO_SlotWeapInfo(playerclass, slot)->weapon; + if (weap != WEAP_NONE) + for (float i = 0; i < impulse_weapons[playerclass].weapons.length; i++) + if (impulse_weapons[playerclass].weapons[i] == weap) + return i + 1; + + return -1; +} + Slot FO_SlotByInput(float playerclass, float input) { if (IsUsingOldImpulses()) { return FO_ImpulseToSlot(playerclass, input); From ea8c3f703c26fceea0e19c03bb0d0202830ca8b7 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 22:53:14 -0700 Subject: [PATCH 2191/2474] wp: fix 'reloading' spam Didn't delete old case when moving. --- csqc/weapon_predict.qc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index a7510f61..771bfc23 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -924,14 +924,6 @@ void WP_Impulse() { WPP_Dump(); break; - case TF_RELOAD: - WP_ReloadSlot(CurrentSlot()); - break; - - case TF_RELOAD_NEXT: - WP_ReloadNext(); - break; - case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: local_impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. quick_swap = TRUE; @@ -989,10 +981,10 @@ void WP_Impulse() { case TF_RELOAD: WP_ReloadSlot(CurrentSlot()); break; - case TF_RELOAD_NEXT: WP_ReloadNext(); break; + default: pstate_pred.impulse = local_impulse; break; From b3ea29f0fd25fe6fd9482044667a8e0e3b0cca7b Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 22:52:15 -0700 Subject: [PATCH 2192/2474] client: make -slot swap to prev weap The new +slot binds were missing the prior behavior of returning to the last weapon fired when `fo_default_weapon` was not set. Implement this. Move stack to 0-index instead of 1-index, simpler and fixes latent overflow bug. --- csqc/csextradefs.qc | 3 ++- csqc/main.qc | 43 ++++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c7b4a35c..34178cb6 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -115,8 +115,9 @@ float vote_list_offset; entity current_vote; string vote_list_filter; float zoomed_in; + float slot_history[MAX_SLOT_HISTORY_SIZE]; -float slot_history_top; +float slot_history_top, slot_under_stack; .string name; .string description; diff --git a/csqc/main.qc b/csqc/main.qc index 2df5d793..514fdb26 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -27,18 +27,17 @@ void PushToSlotHistory(float value) { // Stack is full return; } - - slot_history_top += 1; slot_history[slot_history_top] = value; -} - -void RemoveFromSlotHistory(float slot) { - if (slot_history_top == -1) { - // Stack is empty - return; + if (slot_history_top == 0) { + Slot slot = !IsSlotNull(pstate_pred.queue_slot) ? + pstate_pred.queue_slot : pstate_pred.current_slot; + slot_under_stack = SlotIndex(slot) + 1; } + slot_history_top += 1; +} - for (float i = slot_history_top; i >= 0; i--) { +float RemoveFromSlotHistory(float slot) { + for (float i = slot_history_top - 1; i >= 0; i--) { if (slot_history[i] == slot) { for (float j = i+1; j < MAX_SLOT_HISTORY_SIZE; j++) { slot_history[j-1] = slot_history[j]; @@ -49,6 +48,15 @@ void RemoveFromSlotHistory(float slot) { break; } } + + if (slot_history_top > 0) { + return slot_history[slot_history_top - 1]; + } else { + if (CVARF(fo_default_weapon)) + return CVARF(fo_default_weapon); + else + return slot_under_stack; + } } @@ -99,8 +107,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Predict_Init(); CsGrenTimer::Init(); - slot_history_top = -1; - registercommand("+slot"); registercommand("-slot"); @@ -228,18 +234,13 @@ void Slot_Keydown(float slot) { } void Slot_Keyup(float slot) { - RemoveFromSlotHistory(slot); + float prev = RemoveFromSlotHistory(slot); + float still_attack = slot_history_top > 0; // Empty stack check - if (slot_history_top >= 0) { // still holding another +slot bind - float impulse = FO_SlotToImpulse(WP_PlayerClass(), - MakeSlot(slot_history[slot_history_top])); - localcmd(sprintf("impulse %d\n", impulse)); - } else { - if (CVARF(fo_default_weapon)) { - localcmd(sprintf("impulse %d\n", CVARF(fo_default_weapon))); - } + float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(prev)); + localcmd(sprintf("impulse %d\n", impulse)); + if (!still_attack) localcmd("-attack\n"); - } } void W_ChangeToSlotAlternate(string opt1, string opt2); From 5d78f5516efc7b6e11e2a85cc72027966e4a967c Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 17 Sep 2023 23:53:44 -0700 Subject: [PATCH 2193/2474] client: make sure always return a usable slot Sometimes we're seeing zeros sneak in here. --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 514fdb26..25943387 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -237,7 +237,7 @@ void Slot_Keyup(float slot) { float prev = RemoveFromSlotHistory(slot); float still_attack = slot_history_top > 0; // Empty stack check - float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(prev)); + float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(prev ?: 1)); localcmd(sprintf("impulse %d\n", impulse)); if (!still_attack) localcmd("-attack\n"); From 4471a802f43071e38f171d619b2abbc037c6c235 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Sep 2023 09:00:54 -0700 Subject: [PATCH 2194/2474] spec: add fo_spec_grentimervolume Adds a new `fo_spec_grentimervolume` control that, when set (e.g. != -1), supercedes the regular grenade timer volume when speccing. Default value is -1 which means that the regular fo_grentimervolume is consumed. --- README.md | 1 + csqc/events.qc | 9 +++++++-- csqc/settings.qc | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 78cfb635..75d1d0a3 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * CSQC - fo_grentimer 0 - none, 1 - starts on server prime message, 2 - starts on prime button press * CSQC - fo_grentimersound grentimer.wav * CSQC - fo_grentimervolume 1 +* CSQC - fo_specgrentimervolume -1 [ignored when -1] * CSQC - fo_jumpvolume 1 * CSQC - fo_hud_reset resets HUD to defaults * CSQC - fo_hud_reload reloads last-saved hud configuration diff --git a/csqc/events.qc b/csqc/events.qc index 72e843a8..8f522e24 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -381,16 +381,21 @@ string GetGrenTimerSound() { return wav; } +static float GrenTimerVolume() { + if (game_state.is_spectator && CVARF(fo_spec_grentimervolume) != -1) + return CVARF(fo_spec_grentimervolume); + return CVARF(fo_grentimervolume); +} + void CsGrenTimer::StartSound() { if !(this.flags_ & FL_GT_SOUND) return; string wav = GetGrenTimerSound(); - float volume = CVARF(fo_grentimervolume); // Note there's a bug where soundupdate returns false for a new sample, even // though it's started. - soundupdate(this, CHAN_VOICE, wav, volume, 0, 0, 0, sound_offset()); + soundupdate(this, CHAN_VOICE, wav, GrenTimerVolume(), 0, 0, 0, sound_offset()); this.playing_ = TRUE; } diff --git a/csqc/settings.qc b/csqc/settings.qc index 6f029b2c..f52544d4 100644 --- a/csqc/settings.qc +++ b/csqc/settings.qc @@ -1,6 +1,10 @@ DEFCVAR_FLOAT(fo_grentimer, 2); // Sound + Ping adjust DEFCVAR_STRING(fo_grentimersound, "grentimer.wav"); DEFCVAR_FLOAT(fo_grentimervolume, 1); + +// When set (not -1) and spectating, supercedes fo_grentimervolume. +DEFCVAR_FLOAT(fo_spec_grentimervolume, -1); + DEFCVAR_FLOAT(fo_oldscoreboard, 0); DEFCVAR_FLOAT(fo_default_weapon, 0); DEFCVAR_FLOAT(fo_team_color_crosshair, 0); From fbf7b056205debb7a90a63efac7d004523143089 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Sep 2023 09:03:09 -0700 Subject: [PATCH 2195/2474] slots: do nothing on 0-prev Rather than converting it to a slot they may never have pressed or been on, just do nothing. --- csqc/main.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 25943387..6406ee24 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -237,8 +237,10 @@ void Slot_Keyup(float slot) { float prev = RemoveFromSlotHistory(slot); float still_attack = slot_history_top > 0; // Empty stack check - float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(prev ?: 1)); - localcmd(sprintf("impulse %d\n", impulse)); + if (prev) { + float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(prev)); + localcmd(sprintf("impulse %d\n", impulse)); + } if (!still_attack) localcmd("-attack\n"); } From b82ac9d9262ec6499fef9a9c656c9fd25f8fee0e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Sep 2023 12:03:36 -0700 Subject: [PATCH 2196/2474] antilag: rewind for death projectiles It's possible to die in between the time that you fire and the server receives you firing. This is particularly frustrating since you can often see the client side projectile disappear as a result of the server processing your death first. Handle this by introducing limited reconciliation that can emit projectiles in this window. Needs more integration with rewind and hitscan but good enough for a first try. --- csqc/weapon_predict.qc | 13 ++++++++++ share/commondefs.qc | 4 ++- share/prediction.qc | 6 ++--- ssqc/client.qc | 7 ----- ssqc/player.qc | 1 + ssqc/pyro.qc | 9 +++---- ssqc/qw.qc | 2 ++ ssqc/rewind.qc | 8 +++++- ssqc/weapons.qc | 59 +++++++++++++++++++++++++++++++----------- 9 files changed, 77 insertions(+), 32 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 771bfc23..e062eab8 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1662,12 +1662,15 @@ void WP_Attack() { pstate_pred.client_thinkindex = 1; if (IsEffectFrame() && !in_anim) { + float send_event = FALSE; switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: PP_CreateProjectile(FPP_ROCKET, v_forward * 8); + send_event = TRUE; break; case WEAP_INCENDIARY: PP_CreateProjectile(FPP_INCENDIARY, v_forward * 8); + send_event = TRUE; break; case WEAP_FLAMETHROWER: PP_CreateProjectile(FPP_FLAMETHROWER, v_forward * 16); @@ -1683,6 +1686,7 @@ void WP_Attack() { break; case WEAP_GRENADE_LAUNCHER: + send_event = TRUE; case WEAP_PIPE_LAUNCHER: if (QcPhysics()) W_FireGrenade((wi->weapon == WEAP_GRENADE_LAUNCHER || prematch) ? @@ -1703,6 +1707,15 @@ void WP_Attack() { case WEAP_SUPER_SHOTGUN: Pred_Sound(SND_SSG); break; case WEAP_SNIPER_RIFLE: Pred_Sound(SND_SNIPER_RIFLE); break; } + + if (send_event && RewindFlagEnabled(REWIND_SENDEVENT)) { + // It's slightly confusing that we pass server and not pred here, + // but this includes the ping adjustment that would occur at pred. + // Tested both ways and this seems to be more stable. + sendevent("Attack", "ifvv", + (float)wi->weapon, pstate_server.client_time, + pmove_org, input_angles); + } } if (!in_anim) diff --git a/share/commondefs.qc b/share/commondefs.qc index 49f084aa..8f989097 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -54,6 +54,7 @@ enumflags { REWIND_KNOCKBACK, REWIND_SETSPEED, REWIND_GRENADES, + REWIND_SENDEVENT, REWIND_FORWARD_PROJ_SELFKNOCK, REWIND_FORWARD_DOORS, }; @@ -64,6 +65,7 @@ string REWIND_DESC[] = { "rewind pipe knockback", "allow csqc to handle maxspeed", "rewind grenade throws", + "use sendevent augmentation (allows race w/ death rewind)", "forward projectile self-knockback", "open doors earlier for hpbs [requires rfd=1]", }; @@ -71,7 +73,7 @@ string REWIND_DESC[] = { const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_FIRE | REWIND_PROJ_TRAVEL | REWIND_FORWARD_PROJ_SELFKNOCK | - REWIND_SETSPEED; + REWIND_SETSPEED | REWIND_SENDEVENT; float RewindFlagEnabled(float flag) { diff --git a/share/prediction.qc b/share/prediction.qc index b412ee81..85e715c2 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -860,7 +860,7 @@ void PredProj_Sound(int proj_type, float vol = 1) { Pred_Sound(FPP_Get(proj_type)->snd, vol); } -void Forward_Projectile(int fpp_type, entity projectile); +void Forward_Projectile(int fpp_type, entity projectile, float use_ctime=0); entity FOProj_Create(int fpp_type) { entity prj = spawn(); @@ -873,7 +873,7 @@ entity FOProj_Create(int fpp_type) { return prj; } -void FOProj_Finalize(entity mis) { +void FOProj_Finalize(entity mis, float use_ctime=0) { int fpp_type = mis.fpp.index; // We explicitly do not use newmis. Newmis internally implements a fixed // 50m forward of physics handling (equivalent to our projection below) @@ -906,7 +906,7 @@ void FOProj_Finalize(entity mis) { if (fo_config.qc_physics) mis.customphysics = FO_CustomPhysics; - Forward_Projectile(mis.fpp.index, mis); + Forward_Projectile(mis.fpp.index, mis, use_ctime); // Below is conditional on using custom SendEntity. if (csqc_networking) { diff --git a/ssqc/client.qc b/ssqc/client.qc index ea564ad8..6ce27fdf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -68,18 +68,11 @@ float () RejoinWithTfId; void () CreateTfIdAndJoin; entity (entity e)TeamFortress_GetPracticeSpawn; void () NextLevel; -void CSEv_SetPlayerImpulse_f(float n); void StopAssCan(); void Predict_InitPlayer(entity player); void Predict_Destroy(entity player); -void (float n) CSEv_SetPlayerImpulse_f = { - bprint(PRINT_HIGH, self.netname, "\n"); - bprint(PRINT_HIGH, "setting impulse ", ftos(n), "\n"); - self.impulse = n; -}; - void () info_intermission = { if (CheckExistence() == 0) { diff --git a/ssqc/player.qc b/ssqc/player.qc index 1abfe018..b07ce126 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -439,6 +439,7 @@ void () GibPlayer = { void () PlayerDie = { self.spawn_gen += 1; + self.last_death_ctime = self.client_time; local float i; local entity te; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index ddcdd274..7be18786 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -593,18 +593,17 @@ void () T_IncendiaryTouch = { dremove_sent(self); }; -void () W_FireIncendiaryCannon = { +void W_FireIncendiaryCannon(vector org, vector v_ang, float use_ctime=0) { if (self.ammo_rockets < 3) { return; } - self.ammo_rockets = self.ammo_rockets - 3; KickPlayer(-3, self); entity proj = FOProj_Create(FPP_INCENDIARY); proj.owner = self; proj.movetype = MOVETYPE_FLYMISSILE; proj.solid = SOLID_BBOX; - makevectors(self.v_angle); + makevectors(v_ang); proj.velocity = aim(self, 1000) * FPP_Get(FPP_INCENDIARY)->speed; proj.angles = vectoangles(proj.velocity); proj.touch = T_IncendiaryTouch; @@ -612,9 +611,9 @@ void () W_FireIncendiaryCannon = { proj.nextthink = time + 5; proj.weapon = DMSG_INCENDIARY; proj.classname = "pyro_rocket"; - setorigin(proj, self.origin + v_forward * 8 + '0 0 16'); + setorigin(proj, org + v_forward * 8 + '0 0 16'); - FOProj_Finalize(proj); + FOProj_Finalize(proj, use_ctime); }; void () AirBlastReloadFinished = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a517f3da..0fb41138 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -14,6 +14,8 @@ struct antilag_settings_t { } antilag_settings; .vector antilag_origin; +.float last_death_ctime; +.float last_attack_ctime; .float client_time; // A stable/predictable client clock .float client_ping; // ping used for prediction diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 0f31b716..58d4ea1b 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -323,8 +323,14 @@ void NoRewindSyncFn(entity e, float target_time) { error("not set\n"); } -void Forward_Projectile(int fpp_type, entity proj) { +void Forward_Projectile(int fpp_type, entity proj, float use_ctime) { float ping = proj.owner.client_ping; + if (use_ctime) { + // These can be pretty late with sendevent latency on top so let's be + // conservative. + ping = min((proj.owner.client_time - use_ctime) * 1000, + fo_config.max_rewind_ms - 25); + } ProjectResult offset = Forward_ProjectOffset(fpp_type, ping); float static_dt = offset.static_ms / 1000.0; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index be3e0cc1..e4f49092 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -96,7 +96,7 @@ void () BioInfection_MonsterDecay; float (float weap) W_GetSlot; float (float weap) W_OldGetSlot; void () W_FireFlame; -void () W_FireIncendiaryCannon; +void W_FireIncendiaryCannon(vector org, vector angles, float use_ctime=0); void () W_FireTranq; void () W_FireRailgun; @@ -186,6 +186,7 @@ void (float att_delay) Attack_Finished = { att_delay *= 2; self.attack_finished = self.client_time + att_delay; + self.last_attack_ctime = self.client_time; }; float* W_ammo_to_p(entity player, AmmoType ammo_type) { @@ -1103,13 +1104,13 @@ void () T_MissileTouch = { dremove_sent(self); }; -void () W_FireRocket = { +void W_FireRocket(vector org, vector v_ang, float use_ctime=0) = { entity proj = FOProj_Create(FPP_ROCKET); proj.owner = self; proj.movetype = MOVETYPE_FLYMISSILE; proj.solid = SOLID_BBOX; - makevectors(self.v_angle); + makevectors(v_ang); proj.velocity = v_forward * FPP_Get(FPP_ROCKET)->speed; proj.angles = vectoangles(proj.velocity); @@ -1121,11 +1122,10 @@ void () W_FireRocket = { proj.weapon = DMSG_ROCKETL; proj.classname = "proj_rocket"; - proj.origin = self.origin + v_forward * 8 + '0 0 16'; + proj.origin = org + v_forward * 8 + '0 0 16'; - FOProj_Finalize(proj); + FOProj_Finalize(proj, use_ctime); - self.ammo_rockets = self.ammo_rockets - 1; KickPlayer(-2, self); }; @@ -1320,8 +1320,7 @@ void () ExplodeOldestPipebomb = { } }; -void () W_FireGrenade = { - self.ammo_rockets = self.ammo_rockets - 1; +void W_FireGrenade(vector org, vector v_ang, float use_ctime=0) { Pred_Sound(SND_GREN); KickPlayer(-2, self); @@ -1349,7 +1348,7 @@ void () W_FireGrenade = { proj.team_no = self.team_no; proj.fpp.gren_type = GREN_PIPE; } - makevectors(self.v_angle); + makevectors(v_ang); if (self.v_angle_x) { proj.velocity = (v_forward * 600) + (200 + shared_crandom(PRNG_WEAP) * 10) * v_up + @@ -1361,9 +1360,9 @@ void () W_FireGrenade = { } proj.angles = vectoangles(proj.velocity); proj.think = GrenadeExplode; - setorigin(proj, self.origin); + setorigin(proj, org); - FOProj_Finalize(proj); + FOProj_Finalize(proj, use_ctime); }; void () spike_touch; @@ -1694,15 +1693,18 @@ void () W_Attack = { player_nail1(); } else if (ws.weapon == WEAP_GRENADE_LAUNCHER) { player_rocket1(); - W_FireGrenade(); + self.ammo_rockets = self.ammo_rockets - 1; + W_FireGrenade(self.origin, self.v_angle); Status_Refresh(self); } else if (ws.weapon == WEAP_PIPE_LAUNCHER) { player_rocket1(); - W_FireGrenade(); + self.ammo_rockets = self.ammo_rockets - 1; + W_FireGrenade(self.origin, self.v_angle); Status_Refresh(self); } else if (ws.weapon == WEAP_ROCKET_LAUNCHER) { player_rocket1(); - W_FireRocket(); + self.ammo_rockets = self.ammo_rockets - 1; + W_FireRocket(self.origin, self.v_angle); Status_Refresh(self); } else if (ws.weapon == WEAP_LIGHTNING) { player_light1(); @@ -1729,7 +1731,8 @@ void () W_Attack = { } else if (ws.weapon == WEAP_INCENDIARY) { if (self.ammo_rockets >= 3) { player_rocket1(); - W_FireIncendiaryCannon(); + self.ammo_rockets = self.ammo_rockets - 3; + W_FireIncendiaryCannon(self.origin, self.v_angle); } else if (time >= self.antispam_incendiary_cannon) { sprint(self, PRINT_HIGH, "Not enough ammo\n"); self.antispam_incendiary_cannon = time + 3; @@ -2716,3 +2719,29 @@ void () ToggleInvincibility = { self.invincible_finished = time + 666; } }; + +// TODO: trust the client less, validate more. +// TODO: Could support hitscan (e.g. sg/ssg) +void (float weap, float ctime, vector pos, vector angles) CSEv_Attack_ifvv = { + if (!RewindFlagEnabled(REWIND_SENDEVENT)) + return; + + // Only applies to attacks before the last death. We can't use + // attack_finished here as there's an 0.3s lockout on spawn that obscures. + float lockout = 15*MSEC; // Be a tiny bit conservative + if (ctime >= self.last_death_ctime - lockout || + ctime < self.last_attack_ctime - lockout) + return; + + switch (weap) { + case WEAP_ROCKET_LAUNCHER: + W_FireRocket(pos, angles, ctime); + break; + case WEAP_INCENDIARY: + W_FireIncendiaryCannon(pos, angles, ctime); + break; + case WEAP_GRENADE_LAUNCHER: + W_FireGrenade(pos, angles, ctime); + break; + } +}; From a005cd2dc331e2c20875969cd4b35e84e8415c1d Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Sep 2023 19:18:41 -0700 Subject: [PATCH 2197/2474] wp: fix state tear When we refactored how the prediction update calculation occurred it could miss elements in think, allowing a handled impulse to propagate to the next frame. This ended up being typically invisible because it wouldn't be an effect-frame, but with very low pings it was possible for this to occur; resulting in effects like some double prints and double projectiles. --- ssqc/client.qc | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 6ce27fdf..03a12388 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2931,33 +2931,14 @@ void FO_HandleTFStateUpdate() { void TeamFortress_MOTD(); -void () PlayerPostThink = { - FO_CheckClientThink(); - UpdateScoreboardInfo(self); - FOPlayer fop = (FOPlayer)self; - fop.RewindUpdate(); - Forward_OpenDoors(self); +static void PlayerPostThinkAlive() { + float fdmg; FO_WeapState ws; FO_FillCurrentWeapState(&ws); self.currentammo = (ws->wi)->ammo_type != AMMO_NONE ? *ws->ammo_remaining : 0; - Predict_Update(); - - if (self.view_ofs == '0 0 0') { - return; - } - - if (self.deadflag) { - DeadImpulses(); - self.impulse = 0; - return; - } - - local float fdmg; - local float csqcactive = infokeyf(self, INFOKEY_P_CSQCACTIVE); - if (((self.jump_flag < -300) && (self.flags & FL_ONGROUND)) && (self.health > 0)) { if (self.watertype == CONTENT_WATER) { @@ -2984,6 +2965,8 @@ void () PlayerPostThink = { } self.jump_flag = self.velocity_z; + Forward_OpenDoors(self); + if(votemode) { CheckPowerups(); FO_ReloadFrame(); @@ -3010,6 +2993,22 @@ void () PlayerPostThink = { FO_HandleTFStateUpdate(); if (time >= self.StatusRefreshTime) RefreshStatusBar(self); +} + +void () PlayerPostThink = { + FO_CheckClientThink(); + UpdateScoreboardInfo(self); + + if (self.deadflag) { + DeadImpulses(); + self.impulse = 0; + } else { + PlayerPostThinkAlive(); + } + + FOPlayer fop = (FOPlayer)self; + fop.RewindUpdate(); + Predict_Update(); }; void () UpdateAllClientsTeamScores = { @@ -3028,7 +3027,6 @@ void () UpdateAllClientsTeamScores = { } } -//do not rely on csqcactive - it may misbehave when using `join` from spectator void () ClientConnect = { if (!infokeyf(self,INFOKEY_P_CSQCACTIVE)) { sprint(self, PRINT_HIGH, "FTE/CSQC is required for this server, please download the latest client package at www.fortressone.org\n"); From 287be8554ee8521b23c5d7517f5d7c68479690d9 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 19 Sep 2023 09:18:45 -0700 Subject: [PATCH 2198/2474] grentimers: misc spec fixes - Make sure we only play the timer for the selected player (or none) - Make sure we obey FL_GT_SOUND when spectating - Disable broadcast until we re-enable TFX --- csqc/events.qc | 20 ++++---------------- ssqc/status.qc | 7 +++++-- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 8f522e24..5bb00d0c 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -107,24 +107,9 @@ void() CSQC_Parse_Event = { float entno = readentitynum(); float grentype = readbyte(); float explodes_at = readfloat(); - - // The current player (inc spectated) handled via prediction ent. - if (game_state.is_player || entno == player_localentnum) - return; - - ParseGrenPrimed(grentype, explodes_at); break; case MSG_GRENTHROWN: float entno = readentitynum(); - // Current player (or spectated) handled via prediction ent. - if (game_state.is_player || entno == player_localentnum) - return; - - CsGrenTimer last = CsGrenTimer::GetLast(); - // It's possible to get THROWN without PRIMED when spectating a - // player that primed before you started watching them. - if (last != world && last.active()) - last.set_flag(FL_GT_THROWN); break; case MSG_TFX_GRENTIMER: float entnum = readentitynum(); @@ -436,7 +421,7 @@ CsGrenTimer ParseGrenPrimed(float grentype, float explodes_at, if (grentype == GREN_FLARE || grentype == GREN_CALTROP) return world; - float timer_mode = game_state.is_player ? CVARF(fo_grentimer) : 1; + float timer_mode = CVARF(fo_grentimer); switch (timer_mode) { case 0: break; case 1: timer_flags = FL_GT_SOUND; break; @@ -444,6 +429,9 @@ CsGrenTimer ParseGrenPrimed(float grentype, float explodes_at, default: timer_flags |= FL_GT_SOUND | FL_GT_ADJPING; break; } + if (game_state.is_spectator) + timer_flags &= ~FL_GT_ADJPING; + float debug_print_state = CVARF(fo_grentimer_debug) & 1; CsGrenTimer timer = CsGrenTimer::GetNext(); diff --git a/ssqc/status.qc b/ssqc/status.qc index e36c2783..ad3d9d36 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -775,6 +775,8 @@ void UpdateClientReloadSound(entity pl, float weapon) { } void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { + return; // Not needed until we re-enable TFX. + msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); @@ -782,11 +784,12 @@ void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { WriteByte(MSG_MULTICAST, grentype); WriteFloat(MSG_MULTICAST, explodes_at); - // Let's see if we can get away with avoiding _R here. - multicast('0 0 0', MULTICAST_ALL); + multicast('0 0 0', MULTICAST_ALL); // Actual primer has reliable transport. } void UpdateClientGrenadeThrown(entity pl) = { + return; // Not needed until we re-enable TFX. + msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENTHROWN); From 9abdc2fea4cd2de141dcaa36e928ab3a5d9892b2 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 19 Sep 2023 09:38:27 -0700 Subject: [PATCH 2199/2474] grens: add disable_resup_gren and enable in 2v2 Add a new localinfo {`drg`, `disable_resup_gren`} that allows disabling pack resupply of grenade1 (controlled by 1-bit) and grenade2 (controlled by 2-bit) e.g. `rcon localinfo drg 1` -- disable picking up gren1s `rcon localinfo drg 3` -- disable picking up gren1s and gren2s Does not affect backpack grenade pickup. Automatically enabled (=3) for 2v2 quads. --- ssqc/client.qc | 3 +++ ssqc/quadmode.qc | 11 ++++++++++- ssqc/qw.qc | 1 + ssqc/tfortmap.qc | 19 +++++++------------ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 03a12388..28065262 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -682,6 +682,9 @@ void () DecodeLevelParms = { Role_None.gren2_limits[8] = CF_GetSetting("mg2_8", "max_gren2_spy", ftos(PC_SPY_GRENADE_MAX_2)); Role_None.gren2_limits[9] = CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(PC_ENGINEER_GRENADE_MAX_2)); + // disable resupply giving grenades (1-bit for gren1, 2-bit for gren2) + disable_resup_gren = CF_GetSetting("drg", "disable_resup_gren", "0"); + // solid detpack toggle [0] solid_detpack = CF_GetSetting("sdp", "solid_detpack", "0"); // All Walls Block EMP [0] diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 787807b2..1aea5d3e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -1,5 +1,7 @@ void () info_player_teamspawn; +void Activate2v2_Ruleset(); + void () PostFOQuadStarted = { if (!fo_login_required) return; @@ -701,8 +703,11 @@ void () StartQuadRound = p = find(p, classname, "player"); } - if (rounds == 2 && legit_players > 1) + if (rounds == 2 && legit_players > 1) { PostFOQuadStarted(); + if (legit_players == 4) + Activate2v2_Ruleset(); + } if (rounds == 1 /* final round */) { te = find(world, classname, "player"); @@ -824,3 +829,7 @@ void () StartQuadRound = te.nextthink = (time + 1); } }; + +void Activate2v2_Ruleset() { + disable_resup_gren = 3; // Disable gren1 and gren2 pickups +} diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 0fb41138..78502305 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -795,6 +795,7 @@ string goal_class_names[7] = { .float special_cooldown; .float airblast_cooldown; +float disable_resup_gren; // backend string match_id; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 17a21fd7..c04d2b6e 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -871,20 +871,15 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.tfstate &= ~TFSTATE_RELOADING; *ws->clip_fired = max(*ws->clip_fired - Goal.ammo_rockets, 0); } - - } - Player.no_grenades_1 = - Player.no_grenades_1 + Goal.no_grenades_1; - Player.no_grenades_2 = - Player.no_grenades_2 + Goal.no_grenades_2; - - if (Player.no_grenades_1 > Player.max_grenades_1) { - Player.no_grenades_1 = Player.max_grenades_1; - } - if (Player.no_grenades_2 > Player.max_grenades_2) { - Player.no_grenades_2 = Player.max_grenades_2; } + if (disable_resup_gren & 1 == 0) + Player.no_grenades_1 = min(Player.no_grenades_1 + 1, + Player.max_grenades_1); + if (disable_resup_gren & 2 == 0) + Player.no_grenades_2 = min(Player.no_grenades_2 + 1, + Player.max_grenades_2); + if (Player.ammo_detpack > Player.maxammo_detpack) { Player.ammo_detpack = Player.maxammo_detpack; } From 145f1025c7cdef9c06c2507aa5bae7cd05a16ebd Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Sep 2023 14:18:43 -0700 Subject: [PATCH 2200/2474] impulses: remove TF_QUICKSLOT etc Remove server side implementation/complexity now that we are using client-side implementation. --- csqc/weapon_predict.qc | 24 +----------------------- share/defs.h | 6 ------ ssqc/weapons.qc | 26 -------------------------- 3 files changed, 1 insertion(+), 55 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index e062eab8..c7eb511d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -905,18 +905,6 @@ void WP_Impulse() { WP_HandleGrenadeInputs(); WP_HandleHeavyInputs(); - // Note: We might have no impulse, but a queued slot here. - float quick_swap = FALSE; - - if (pstate_pred.impulse >= TF_QUICKSLOT1 && pstate_pred.impulse <= TF_QUICKSTOP && - !WP_WeaponReady()) { - // Filter these out because of potential double queuing pain; should - // probably try and deprecate. - return; - } - - // Impulses that are NOT held by attack_finished / reloading. - // * with a hacky exception for TF_QUICKSLOTs local_impulse = pstate_pred.impulse; pstate_pred.impulse = 0; switch (local_impulse) { @@ -924,23 +912,13 @@ void WP_Impulse() { WPP_Dump(); break; - case TF_QUICKSLOT1: case TF_QUICKSLOT2: case TF_QUICKSLOT3: case TF_QUICKSLOT4: - local_impulse -= TF_QUICKSLOT1 - 1; // Intentional fall-through. - quick_swap = TRUE; case 1: case 2: case 3: case 4: case 5: case 6: case 7: { Slot slot = InputToSlot(local_impulse); - if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) { - if (quick_swap) - pstate_pred.tfstate |= TFSTATE_QUICKSLOT; + if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) pstate_pred.queue_slot = slot; - } break; } - case TF_QUICKSTOP: - if (pstate_pred.tfstate & TFSTATE_QUICKSLOT == 0) - break; - pstate_pred.tfstate &= ~TFSTATE_QUICKSLOT; // Intentional fall-through. case TF_WEAPLAST: // Clearing queued counts as swap to whatever was pre-queued. if (!IsSlotNull(pstate_pred.queue_slot)) diff --git a/share/defs.h b/share/defs.h index 0a555d00..62859c30 100644 --- a/share/defs.h +++ b/share/defs.h @@ -253,7 +253,6 @@ enumflags { // (Note: We don't use NO_WEAPON for reloading // as it could result in stacked no-weapon states.) TFSTATE_FLASHED, - TFSTATE_QUICKSLOT, // QUICKSTOP should change to last weapon. TFSTATE_AC_SPINUP, // These cover the 3 assault cannon states. TFSTATE_AC_SPINNING, TFSTATE_AC_SPINDOWN, @@ -419,11 +418,6 @@ struct Slot { int id; }; #define TF_GRENADE_PT_1 17 // Prime and throw grenade type 1 (two clicks) #define TF_GRENADE_PT_2 18 // Prime and throw grenade type 2 (two clicks) // unused -#define TF_QUICKSLOT1 20 // Fire weapon slot 1 and then switch back to current weapon -#define TF_QUICKSLOT2 21 // Fire weapon slot 2 and then switch back to current weapon -#define TF_QUICKSLOT3 22 // Fire weapon slot 3 and then switch back to current weapon -#define TF_QUICKSLOT4 23 // Fire weapon slot 4 and then switch back to current weapon -#define TF_QUICKSTOP 24 // Used to tell server that quick firing has stopped #define TF_RELOAD_SLOT1 25 // Reload weapon slot 1 #define TF_RELOAD_SLOT2 26 // Reload weapon slot 2 #define TF_RELOAD_SLOT3 27 // Reload weapon slot 3 diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e4f49092..3c2167bb 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2521,37 +2521,11 @@ void () W_WeaponFrame = { self.impulse = 0; } - // +slot/-slot handle attack; we only need to swap back to last weapon. - // Let's see if we can get away with just treating this as last weapon; - // there were already so many edge cases in the old code such as swapping on - // an empty weapon. - if (self.impulse == TF_QUICKSTOP) { - if (self.tfstate & TFSTATE_QUICKSLOT) - self.impulse = TF_WEAPLAST; - else - self.impulse = 0; - self.tfstate &= ~TFSTATE_QUICKSLOT; - } - if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput()) { // slot 1-4 (or 1-7) binds W_ChangeWeaponByInput(self.impulse); self.impulse = 0; - } else if (self.impulse >= TF_QUICKSLOT1 && - self.impulse <= TF_QUICKSLOT4 && WeaponReady()) { - float input = InputHandlePyroSlotSwap(self.playerclass, - self.impulse - TF_QUICKSLOT1 + 1); - Slot slot = MakeSlot(input); - - if (IsSameSlot(slot, self.current_slot)) { - self.tfstate &= ~TFSTATE_QUICKSLOT; - } else { - self.tfstate |= TFSTATE_QUICKSLOT; - W_ChangeWeaponSlot(slot); - } - self.impulse = 0; } - W_ChangeQueuedWeaponIfReady(); if (self.impulse == TF_CHANGETEAM) { From 4d6fc3f1f1f53b8ebeb8a9d5600e0f72256d716a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Sep 2023 14:45:05 -0700 Subject: [PATCH 2201/2474] slots: add precise slots and clean-up/simplify There's a lot of pain due to the fact that slots were introduced on overlapping impulses to the original weapons. Resolve this where we need explicit identification (e.g. +slot, +quick, etc) by introducing new precise slot impulses that resolve this. Take a general clean-up pass through most of the callsites; simplify handling of pyro slot swapping and reduce code duplication. --- csqc/main.qc | 9 +-- csqc/weapon_predict.qc | 8 +- share/defs.h | 28 ++++--- share/weapons.qc | 163 ++++++++++++++++++----------------------- ssqc/weapons.qc | 26 +++---- 5 files changed, 100 insertions(+), 134 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 6406ee24..25908f9e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -229,18 +229,15 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { void Slot_Keydown(float slot) { PushToSlotHistory(slot); - float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(slot)); - localcmd(sprintf("impulse %d\n+attack\n", impulse)); + localcmd(sprintf("impulse %d\n+attack\n", TF_SLOT1 + slot - 1)); } void Slot_Keyup(float slot) { float prev = RemoveFromSlotHistory(slot); float still_attack = slot_history_top > 0; // Empty stack check - if (prev) { - float impulse = FO_SlotToImpulse(WP_PlayerClass(), MakeSlot(prev)); - localcmd(sprintf("impulse %d\n", impulse)); - } + if (prev) + localcmd(sprintf("impulse %d\n", TF_SLOT1 + prev - 1)); if (!still_attack) localcmd("-attack\n"); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index c7eb511d..2792076e 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -607,11 +607,6 @@ void WP_ServerUpdate() { phys_sim_dt = -1; } -static Slot InputToSlot(float input) { - Slot result = FO_SlotByInput(pstate_pred.playerclass, input); - return result; -} - void FO_ReloadSound(float weapon) { local float reloadvolume = CVARF(fo_reloadvolume); @@ -912,8 +907,9 @@ void WP_Impulse() { WPP_Dump(); break; + case TF_SLOT1: case TF_SLOT2: case TF_SLOT3: case TF_SLOT4: case 1: case 2: case 3: case 4: case 5: case 6: case 7: { - Slot slot = InputToSlot(local_impulse); + Slot slot = FO_SlotByInput(pstate_pred.playerclass, local_impulse); if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) pstate_pred.queue_slot = slot; break; diff --git a/share/defs.h b/share/defs.h index 62859c30..b1da5c56 100644 --- a/share/defs.h +++ b/share/defs.h @@ -397,10 +397,10 @@ struct Slot { int id; }; /*======================================================*/ /* Impulse Defines */ /*======================================================*/ -#define TF_IMPULSE_SLOT1 1 // Changes weapon to slot 1 (primary weapon) -#define TF_IMPULSE_SLOT2 2 // Changes weapon to slot 2 (secondary weapon) -#define TF_IMPULSE_SLOT3 3 // Changes weapon to slot 3 (tertiary weapon) -#define TF_IMPULSE_SLOT4 4 // Changes weapon to slot 4 (melee weapon) +#define TF_IMPULSE1 1 // Ambiguous impulses that can be either +#define TF_IMPULSE2 2 // slots or classical weapons. Prefer +#define TF_IMPULSE3 3 // TF_SLOT1 .. TF_SLOT4 +#define TF_IMPULSE4 4 #define TF_NUM_SLOTS 4 #define TF_CLASSMENU 5 // Brings up class menu @@ -593,6 +593,10 @@ struct Slot { int id; }; // unused 197 // unused 198 #define TF_ADMIN_LISTIPS 199 +#define TF_SLOT1 200 // Changes weapon to slot 1 (primary weapon) +#define TF_SLOT2 201 // Changes weapon to slot 2 (secondary weapon) +#define TF_SLOT3 202 // Changes weapon to slot 3 (tertiary weapon) +#define TF_SLOT4 203 // Changes weapon to slot 4 (melee weapon) // unused 200 // unused 201 // unused 202 @@ -1500,10 +1504,10 @@ struct TFAlias { }; TFAlias client_aliases[] = { - {"slot1", TF_IMPULSE_SLOT1}, - {"slot2", TF_IMPULSE_SLOT2}, - {"slot3", TF_IMPULSE_SLOT3}, - {"slot4", TF_IMPULSE_SLOT4}, + {"slot1", TF_SLOT1}, + {"slot2", TF_SLOT2}, + {"slot3", TF_SLOT3}, + {"slot4", TF_SLOT4}, {"+slot1", 0, "+slot 1"}, {"-slot1", 0, "-slot 1"}, {"+slot2", 0, "+slot 2"}, @@ -1512,13 +1516,13 @@ TFAlias client_aliases[] = { {"-slot3", 0, "-slot 3"}, {"+slot4", 0, "+slot 4"}, {"-slot4", 0, "-slot 4"}, - {"+quick1", 0, "impulse 1;+attack"}, + {"+quick1", 0, "slot1;+attack"}, {"-quick1", 0, "-attack"}, - {"+quick2", 0, "impulse 2;+attack"}, + {"+quick2", 0, "slot2;+attack"}, {"-quick2", 0, "-attack"}, - {"+quick3", 0, "impulse 3;+attack"}, + {"+quick3", 0, "slot3;+attack"}, {"-quick3", 0, "-attack"}, - {"+quick4", 0, "impulse 4;+attack"}, + {"+quick4", 0, "slot4;+attack"}, {"-quick4", 0, "-attack"}, {"menu", 0, "fo_menu_special", 0, "cmd menu"}, {"changeteam", 0, "fo_menu_team", TF_CHANGETEAM}, diff --git a/share/weapons.qc b/share/weapons.qc index befbcc17..54492178 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -277,11 +277,46 @@ FO_GrenInfo* FO_ClassGren(int playerclass, int index) { } #ifdef SSQC +float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; +float IsUsingOldImpulses(); + +static float IsPyroSlotSwapped() { + return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); +} + FO_GrenInfo* FO_PlayerGren(entity player, int index) { return FO_ClassGren(player.playerclass, index); } -#endif +#else +string(entity e, string key) infokey = #80; + +float csqc_get_user_setting(string s_short, string s_long, string def) { + string s = getplayerkeyvalue(player_localnum, s_short); + if (s == "") { + s = getplayerkeyvalue(player_localnum, s_long); + if (s == "") + s = def; + } + + switch (s) { + case "on": return TRUE; + case "off": return FALSE; + default: return stof(s); + } +} +float IsUsingOldImpulses() { + return csqc_get_user_setting("owi", "old_weapon_impulses", "off"); +} + +static float IsPyroSlotSwapped() { + return csqc_get_user_setting("cfpi", "cf_pyro_impulses", "off"); +} + +float IsHoldGrenades() { + return csqc_get_user_setting("hg", "hold_grens", "off"); +} +#endif // Indexed by WEAP_to_index(). We keep them out of the main table just to keep // things a little more wieldly/readable. static string weapon_names[] = { @@ -380,21 +415,17 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_RAILGUN, IT_SHOTGUN}, }; -FO_WeapInfo* FO_SlotWeapInfo(float class, Slot slot) { +FO_WeapInfo* FO_SlotWeapInfo(float playerclass, Slot slot) { if (IsSlotNull(slot)) return FO_GetWeapInfo(WEAP_NONE); - FO_ClassWeapons* cw = &class_weapons[class]; - return cw->info[SlotIndex(slot)] ? cw->info[SlotIndex(slot)] : - FO_GetWeapInfo(WEAP_NONE); -} - -float FO_ClassWeaponBySlot(float class, Slot slot) { - FO_WeapInfo* wi = FO_SlotWeapInfo(class, slot); - if (!wi) - return WEAP_NONE; + float idx = SlotIndex(slot); + float cf_pyro_impulses = IsPyroSlotSwapped(); + float si = SlotIndex(slot); + if (playerclass == PC_PYRO && cf_pyro_impulses && (idx == 0 || idx == 1)) + idx = 1 - idx; - return wi->weapon; + return class_weapons[playerclass]->info[idx] ?: FO_GetWeapInfo(WEAP_NONE); } float FO_ClassWeapItemMask(float class) { @@ -478,14 +509,16 @@ void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { result->clip_fired = &player.clip_fired[0]; } -float FO_ClassWeaponBySlot(float class, Slot slot); -inline float FO_CurrentWeapon() { - return FO_ClassWeaponBySlot(self.playerclass, self.current_slot); +float FO_PlayerCurrentWeapon(entity player) { + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, player.current_slot); + if (!wi) + return WEAP_NONE; + return wi->weapon; } -inline float FO_PlayerCurrentWeapon(entity player) { - return FO_ClassWeaponBySlot(player.playerclass, player.current_slot); +inline float FO_CurrentWeapon() { + return FO_PlayerCurrentWeapon(self); } inline void FO_FillCurrentWeapState(FO_WeapState* result) { @@ -500,7 +533,6 @@ void (float att_delay) Attack_Finished; void W_UpdateCurrentWeapon(entity pl); void sprint_pred(entity client, float msglevel, string s); -float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; void (entity pl, float weapon) UpdateClientReloadSound; void FO_ReloadSound() { @@ -656,72 +688,15 @@ Slot FO_ImpulseToSlot(float playerclass, float impulse) { return r; } -#ifdef SSQC -float IsUsingOldImpulses(); - -static float IsPyroSlotSwapped() { - return FO_GetUserSetting(self, "cf_pyro_impulses", "cfpi", "off"); -} -#else -string(entity e, string key) infokey = #80; - -float csqc_get_user_setting(string s_short, string s_long, string def) { - string s = getplayerkeyvalue(player_localnum, s_short); - if (s == "") { - s = getplayerkeyvalue(player_localnum, s_long); - if (s == "") - s = def; - } - - switch (s) { - case "on": return TRUE; - case "off": return FALSE; - default: return stof(s); - } -} - -float IsUsingOldImpulses() { - return csqc_get_user_setting("owi", "old_weapon_impulses", "off"); -} - -static float IsPyroSlotSwapped() { - return csqc_get_user_setting("cfpi", "cf_pyro_impulses", "off"); -} - -float IsHoldGrenades() { - return csqc_get_user_setting("hg", "hold_grens", "off"); -} -#endif - -float InputHandlePyroSlotSwap(float playerclass, float input) { - float cf_pyro_impulses = IsPyroSlotSwapped(); - if (playerclass == PC_PYRO && cf_pyro_impulses && (input == 1 || input == 2)) - input = 3 - input; - return input; -} - -float FO_SlotToImpulse(float playerclass, Slot slot) { - if (!IsUsingOldImpulses()) - return SlotIndex(slot) + 1; - - float weap = FO_SlotWeapInfo(playerclass, slot)->weapon; - if (weap != WEAP_NONE) - for (float i = 0; i < impulse_weapons[playerclass].weapons.length; i++) - if (impulse_weapons[playerclass].weapons[i] == weap) - return i + 1; - - return -1; -} - Slot FO_SlotByInput(float playerclass, float input) { - if (IsUsingOldImpulses()) { - return FO_ImpulseToSlot(playerclass, input); + if (input >= TF_SLOT1 && input <= TF_SLOT4) + return MakeSlot(input - TF_SLOT1 + 1); + else if (IsUsingOldImpulses() && (input >= 1 && input <= 7)) { + return impulse_weapons[playerclass].slots[input - 1]; + } else if (input >= 1 && input <= TF_NUM_SLOTS) { + return MakeSlot(input - 1); } else { - input = InputHandlePyroSlotSwap(playerclass, input); - if (input >= 1 && input <= TF_NUM_SLOTS) - return MakeSlot(input); - else - return SlotNull; + return SlotNull; } } @@ -735,6 +710,7 @@ Slot FO_FindPrevNextWeaponSlot(float playerclass, Slot slot, float is_prev) { // impulse_table[offset] return junk so we use a pointer cursor. Slot* cur; len = 7; + direction = (direction + len) % len; for (i = 0; i < len; i++) { cur = &impulse_table[i]; @@ -742,24 +718,25 @@ Slot FO_FindPrevNextWeaponSlot(float playerclass, Slot slot, float is_prev) { break; } do { - i = (i + direction + len) % len; + i = (i + direction) % len; cur = &impulse_table[i]; } while (IsSlotNull(*cur)); + // Technically this will flip OWI+CFPI, but this is a nonsense combo. return *cur; } else { - float* slot_weaps = class_weapons[playerclass].slots; len = 4; + direction = (direction + len) % len; + float idx = SlotIndex(slot); + for (i = 0; i < len - 1; i++) { + idx += direction; + Slot c = MakeSlot(1 + (idx % len)); + FO_WeapInfo* wi = FO_SlotWeapInfo(playerclass, c); + if (wi->weapon != WEAP_NONE) + return c; + } - // This is a little subtle, we need to transform the index both before - // and after the walk so that we don't walk back into ourselves. - i = InputHandlePyroSlotSwap(playerclass, SlotIndex(slot) + 1) - 1; - do { - i = (i + direction + len) % len; - } while (slot_weaps[i] == 0); - - i = InputHandlePyroSlotSwap(playerclass, i + 1); - return MakeSlot(i); + return slot; } } diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 3c2167bb..4f33d123 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1870,17 +1870,6 @@ static void W_AmmoError() { } } -void W_ChangeWeaponByInput(float input) { - if (input < 1 || input > GetMaxWeaponInput()) - return; - - Slot slot = FO_SlotByInput(self.playerclass, input); - if (IsSlotNull(slot)) - return; - - W_ChangeWeaponSlot(slot); -} - void W_ChangeWeaponSlot(Slot slot) { if (self.playerclass == 0) return; @@ -2373,14 +2362,14 @@ void () ButtonFrame = { if (input_buttons & BUTTON4) { switch (self.playerclass) { case PC_SOLDIER: - self.impulse = TF_IMPULSE_SLOT1; + self.impulse = TF_SLOT1; // Intercepted by InterceptRocketJump() break; case PC_PYRO: if (IsUsingCFImpulses()) { - self.impulse = TF_IMPULSE_SLOT2; + self.impulse = TF_SLOT2; } else { - self.impulse = TF_IMPULSE_SLOT1; + self.impulse = TF_SLOT1; } // Intercepted by InterceptRocketJump() break; @@ -2521,9 +2510,12 @@ void () W_WeaponFrame = { self.impulse = 0; } - if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput()) { - // slot 1-4 (or 1-7) binds - W_ChangeWeaponByInput(self.impulse); + // slot 1-4 (or 1-7) binds + if (self.impulse >= 1 && self.impulse <= GetMaxWeaponInput() || + self.impulse >= TF_SLOT1 && self.impulse <= TF_SLOT4) { + Slot slot = FO_SlotByInput(self.playerclass, self.impulse); + if (!IsSlotNull(slot)) + W_ChangeWeaponSlot(slot); self.impulse = 0; } W_ChangeQueuedWeaponIfReady(); From b52575f4004b7b8ebbf949d86ced77b60519e448 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 20 Sep 2023 02:42:29 -0700 Subject: [PATCH 2202/2474] slots: fix off by 1 Classic impulses were off by 1 after refactoring. --- share/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/weapons.qc b/share/weapons.qc index 54492178..abbd757f 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -694,7 +694,7 @@ Slot FO_SlotByInput(float playerclass, float input) { else if (IsUsingOldImpulses() && (input >= 1 && input <= 7)) { return impulse_weapons[playerclass].slots[input - 1]; } else if (input >= 1 && input <= TF_NUM_SLOTS) { - return MakeSlot(input - 1); + return MakeSlot(input); } else { return SlotNull; } From 9b64826bf2bb621fef0bf821825441637b238b21 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 25 Sep 2023 19:23:12 -0700 Subject: [PATCH 2203/2474] hud: fix reload-bar overflow Clamp it generally, but also just don't render it in the dead case where tfstate isn't cleared until respawn. --- csqc/status.qc | 3 +++ csqc/weapon_predict.qc | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 0cae022b..868a006f 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -1064,6 +1064,9 @@ void drawReloadProgress(PanelID panelid, string text) { // click event } + if (!game_state.is_alive) + return; + float per = WP_ReloadPercent(); if (per == 1) return; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 2792076e..a88cea97 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -981,8 +981,8 @@ float WP_ReloadPercent() { if (!WP_IsReloading()) return 1; - return (pstate_pred.client_time - pstate_pred.reload_started) / - (pstate_pred.reload_finished - pstate_pred.reload_started); + return min(1, (pstate_pred.client_time - pstate_pred.reload_started) / + (pstate_pred.reload_finished - pstate_pred.reload_started)); } string WP_GetClip() { From d3ed98d1f9c693f9cceba2fc53fe822ecb938abc Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 26 Sep 2023 09:13:45 -0700 Subject: [PATCH 2204/2474] spec: menu clean up and crash fix - Pop up join team menu on connect - Treat observers like dead players and dont pass through all impulses (crash bug) - Skip needing to "join the game" before joining a team --- csqc/main.qc | 4 ++-- ssqc/client.qc | 5 ++++- ssqc/commands.qc | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 25908f9e..a23d09ac 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -157,8 +157,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { MenuPanel = getHudPanel(HUDP_MENU); - CurrentMenu = &FO_MENU_TEAM; - player_menu_type = 0; is_admin = FALSE; jump_counter = 0; @@ -176,6 +174,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. print("CSQC initialization finished\n"); + + FO_Menu_Game(TRUE); }; noref void() CSQC_WorldLoaded = { diff --git a/ssqc/client.qc b/ssqc/client.qc index 28065262..750cf5ff 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3002,7 +3002,10 @@ void () PlayerPostThink = { FO_CheckClientThink(); UpdateScoreboardInfo(self); - if (self.deadflag) { + if (self.motd >= 0) + TeamFortress_MOTD(); + + if (self.deadflag || self.playerclass == 0) { DeadImpulses(); self.impulse = 0; } else { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1b7e0b83..c6a753d9 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -363,9 +363,13 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "changeteam": processedCmd = TRUE; - if(self.classname == "observer") { + if (self.classname == "observer") { +#if 0 sprint(self, PRINT_HIGH, "You can't join a team while spectating! Join the game first.\n"); break; +#else + clientcommand(self, "join"); +#endif } if(teamplay == 0) { sprint(self, PRINT_HIGH, "You can't join a team when teamplay is disabled!\n"); From b323cf374d08b253e251998119b82431a31cb3e8 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 26 Sep 2023 14:48:04 -0700 Subject: [PATCH 2205/2474] wp: better handling of retransmits pt 2 --- csqc/weapon_predict.qc | 2 +- share/prediction.qc | 35 ++++++++++++++--------------------- ssqc/tsoldier.qc | 2 +- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index a88cea97..9bb25d8f 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1807,7 +1807,7 @@ void InitProjectileEnt(float sendflags) { else setorigin(self, self.origin); - if (sendflags & FOPP_NEW == 0) { + if (self.created_at > time + 0.05) { // Retransmit. Patch up trail, but no predicted / sound / etc. self.oldorigin = self.s_origin; return; diff --git a/share/prediction.qc b/share/prediction.qc index 85e715c2..001441da 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -4,6 +4,7 @@ // Below apply to both CSQC & SSQC ents .float antilag_ms; +.float created_at; string wp_version = "v1.1"; @@ -28,12 +29,10 @@ enumflags { const float FOWP_ALL = FOWP_LAST - 1; enumflags { - FOPP_NEW, FOPP_INIT, FOPP_POS, FOPP_AUX, FOPP_ANGLES, - FOPP_AVEL, FOPP_MOVETYPE, FOPP_EXPIRY, }; @@ -540,36 +539,32 @@ void EntUpdate_WeaponPred(float isnew) { #define COMMD(_type, _dest, _field) COMM(_type, _field) #define COMMO(_type, _dest, _src) Write##_type(MSG_ENTITY, _src) float PP_SendEntity(entity to_player, float sendmask) { - float sendflags = self.SendFlags & sendmask; + float sendflags = sendmask; - if (sendflags & FOPP_NEW || sendflags == 0 /* retransmit */) { - sendflags |= FOPP_INIT | FOPP_POS; + if (sendflags & FOPP_INIT) { + sendflags = FOPP_INIT | FOPP_POS; // Note: replaces sendmask if (self.fpp.aux) sendflags |= FOPP_AUX; if (self.fpp.expires_at) sendflags |= FOPP_EXPIRY; - - // Make sure we carry all the state on a retransmit (normally PVS). - if (sendflags & FOPP_NEW == 0) { - sendflags |= FOPP_ANGLES | FOPP_MOVETYPE; - if (vlen(self.avelocity) > 0) - sendflags |= FOPP_AVEL; - } + if (FPP_Get(self.fpp.index)->movetype != self.movetype) + sendflags |= FOPP_MOVETYPE; } WriteByte(MSG_ENTITY, ENT_PROJECTILE); - WriteShort(MSG_ENTITY, sendflags); + WriteByte(MSG_ENTITY, sendflags); #else #define COMMD(_type, _dest, _field) self.##_dest = Read##_type() #define COMMO(_type, _dest, _src) ##_dest = Read##_type() #define COMM(_type, _field) COMMD(_type, _field, _field) void EntUpdate_Projectile(float isnew) { - float sendflags = readshort(); + float sendflags = readbyte(); #endif if (sendflags & FOPP_INIT) { COMM(Byte, fpp.index); COMM(Short, antilag_ms); + COMM(Float, created_at); COMMD(Entity, owner_entnum, owner); } @@ -597,12 +592,9 @@ void EntUpdate_Projectile(float isnew) { COMM(Coord, angles[0]); COMM(Coord, angles[1]); COMM(Coord, angles[2]); - } - - if (sendflags & FOPP_AVEL) { - COMM(Coord, avelocity[0]); - COMM(Coord, avelocity[1]); - COMM(Coord, avelocity[2]); + COMM(Short, avelocity[0]); + COMM(Short, avelocity[1]); + COMM(Short, avelocity[2]); } if (sendflags & FOPP_MOVETYPE) { @@ -867,6 +859,7 @@ entity FOProj_Create(int fpp_type) { prj.fpp.index = fpp_type; prj.dimension_seen = DMN_NOFLASH; + prj.created_at = time; setmodel(prj, FPP_Get(fpp_type)->model); setsize(prj, '0 0 0', '0 0 0'); @@ -911,7 +904,7 @@ void FOProj_Finalize(entity mis, float use_ctime=0) { // Below is conditional on using custom SendEntity. if (csqc_networking) { mis.SendEntity = PP_SendEntity; - mis.SendFlags = FOPP_NEW; + mis.SendFlags = FOPP_INIT; } else if (fpp_type == FPP_HANDGRENADE) { entity target = self; if (target.classname != "player") diff --git a/ssqc/tsoldier.qc b/ssqc/tsoldier.qc index aa3747c6..05d46c60 100644 --- a/ssqc/tsoldier.qc +++ b/ssqc/tsoldier.qc @@ -103,7 +103,7 @@ void () ShockGrenadeExplode = { self.nextthink = time + 0.7; self.playerclass = 0; self.think = NailGrenLaser; - self.SendFlags |= FOPP_POS | FOPP_MOVETYPE | FOPP_AVEL; + self.SendFlags |= FOPP_POS | FOPP_MOVETYPE | FOPP_ANGLES; }; void () BurstGrenadeExplode = { From f193ef7190ec45d1e6ee2109186c8466b76edec1 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 26 Sep 2023 15:47:59 -0700 Subject: [PATCH 2206/2474] wp: make sure requeueing the current slot clears the queued slot If we re-select the weapon we have queued, it should override any queued weapon. This was resulting in quick-fire aliases occasionally generating ghost projectiles. --- csqc/weapon_predict.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 9bb25d8f..6fbd2715 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -910,8 +910,10 @@ void WP_Impulse() { case TF_SLOT1: case TF_SLOT2: case TF_SLOT3: case TF_SLOT4: case 1: case 2: case 3: case 4: case 5: case 6: case 7: { Slot slot = FO_SlotByInput(pstate_pred.playerclass, local_impulse); - if (!IsSlotNull(slot) && !IsSameSlot(pstate_pred.current_slot, slot)) - pstate_pred.queue_slot = slot; + if (IsSameSlot(pstate_pred.current_slot, slot)) + pstate_pred.queue_slot = SlotNull; + else if (!IsSlotNull(slot)) + pstate_pred.queue_slot = slot; break; } From ed361e6dd330a590941aa3f77cbc26f8bc180d3c Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 14:37:28 -0700 Subject: [PATCH 2207/2474] pmove: infrastructure and bare implementation Introduces a full integration for CSQC side movement prediction. I'd originally intended to break this up into more granular commits but some of the refactoring became too painful. A lot of the base structure is based on the excellent CSQC reference, but with many bugs and a first pass at refinements. Does some useful things such as computation caching and error smoothing. Many things are still missing, including some basics such as correct spectator and probably water movement. Extremely off by default with no controls to turn it on by default. To toggle for current connection use `fo_beta_pmove 0/1`. --- csqc/csextradefs.qc | 4 + csqc/hitfeedback.qc | 4 +- csqc/main.qc | 28 ++- csqc/pmove.qc | 464 +++++++++++++++++++++++++++++++++++++---- csqc/status.qc | 4 +- csqc/tfx.qc | 2 +- csqc/weapon_predict.qc | 35 +++- share/animate.qc | 2 +- share/classes.qc | 2 +- share/prediction.qc | 32 ++- ssqc/client.qc | 46 ++++ 11 files changed, 561 insertions(+), 62 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 34178cb6..c0309ad4 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -907,3 +907,7 @@ float(float playernum, string keyname, optional float assumevalue) getplayerkeyf Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings. */ float(string key, optional float assumevalue) serverkeyfloat = #0:serverkeyfloat; /* Version of serverkey that returns the value as a float (which avoids tempstrings). */ + + +vector PM_Org(); +vector PM_Vel(); diff --git a/csqc/hitfeedback.qc b/csqc/hitfeedback.qc index 760de154..290c7266 100644 --- a/csqc/hitfeedback.qc +++ b/csqc/hitfeedback.qc @@ -17,11 +17,11 @@ void NewHittext(entity hittext) { static void RenderHitText(entity p) { const float maxd = 1500, mind = 0; vector po = p.origin; - vector o = pmove_org; + vector o = PM_Org(); float rem = p.hittext_expires - time; po.z += (CVARF(fo_hittext_duration) - rem) * CVARF(fo_hittext_speed); - vector direc = normalize(po - pmove_org); + vector direc = normalize(po - PM_Org()); makevectors(getviewprop(VF_ANGLES)); float d = v_forward * direc; diff --git a/csqc/main.qc b/csqc/main.qc index a23d09ac..1245eaf4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -15,7 +15,6 @@ void Perf_Status(); void FO_Hud_Init(); float InFluid(vector point); float CalculateWaterLevel(); -void PlayCSJumpSounds(); void RenderHitTexts(); void GetSelf() = { @@ -110,6 +109,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("+slot"); registercommand("-slot"); + registercommand("fo_beta_pmove"); + registercommand("fopm_cmd"); + registercommand("login"); registercommand("fo_hud_editor"); registercommand("fo_hud_reload"); @@ -167,6 +169,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { current_vote = world; vote_list_filter = ""; + PM_Init(); TF_Init(); ClientSettings_Check(); @@ -189,6 +192,7 @@ void FO_CussView(); void FO_CussCrosshair(float width, float height); void Hud_UpdateView(float width, float height, float menushown, float perf_sample); void UpdateTeamColorCrosshair(); +void PMD_DrawGraphs(float width); DEFCVAR_FLOAT(fov, 90); @@ -197,7 +201,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! - // FO_CussView(); if (zoomed_in) @@ -212,6 +215,9 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { mask |= WPP_ViewModelMask(); addentities(mask); + if (PM_Enabled()) + PM_UpdateView(); + renderscene(); FO_CussCrosshair(width, height); @@ -219,6 +225,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { TFxRenderGrenadeTimers(); RenderHitTexts(); Hud_UpdateView(width, height, menushown, fts); + PMD_DrawGraphs(width); perf_finish_sample(&frame_timing, fts); @@ -257,6 +264,15 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "-slot": Slot_Keyup(stof(argv(1))); break; + + case "fopm_cmd": + PM_PmCmd(stof(argv(1))); + break; + + case "fo_beta_pmove": + PM_PmCmd(!!stof(argv(1))); + break; + case "login": FoLogin(argv(1), TRUE); break; @@ -578,7 +594,7 @@ static void FO_CussCrosshair(float width, float height) { cuss_state.cussed = TRUE; makevectors(input_angles); // updated by input_frame - vector p = project(pmove_org + 8000 * cuss_state.c_forward); + vector p = project(PM_Org() + 8000 * cuss_state.c_forward); localcmd(sprintf("cl_crossx %d; cl_crossy %d;\n", p_x - width / 2, CVARF(fo_crossy) + p_y - height / 2)); @@ -626,7 +642,7 @@ void FO_ApplyCussInput() { } } -void FO_ApplyMaxSpeed(); +void FO_ApplyMaxSpeed(float force); noref void CSQC_Input_Frame() { Sync_GameState(); @@ -646,7 +662,7 @@ noref void CSQC_Input_Frame() { if (prev_zoomed_in != zoomed_in) setsensitivityscaler(zoomed_in ? 1/3 : 1); - FO_ApplyMaxSpeed(); + FO_ApplyMaxSpeed(FALSE); FO_ApplyCussInput(); } @@ -711,7 +727,7 @@ void _Sync_ServerCommandFrame() { // synchronized with server and predicted state. void Sync_GameState() { _Sync_ServerCommandFrame(); - PM_PredictJump(); + PM_PredictJump_Engine(); } static string FoLogin_GetToken() { diff --git a/csqc/pmove.qc b/csqc/pmove.qc index c6f68cb3..9eebf07a 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -1,9 +1,47 @@ DEFCVAR_FLOAT(fo_jumpvolume, 1); -inline float CSQC_JumpSounds_Active() { - return CVARF(fo_csjumpsounds); +static float pm_enabled; +inline float PM_Enabled() { return pm_enabled; } + +#define ERRORTIME 0.05 +#define STEPTIME 8 + +enumflags { + PMF_JUMP_HELD, +}; + +// `seq` is the start of the first frame after which all input_*s are handled. +// Running to `seq` will result in being on frame `seq + 1` in the resultant +// state. In the case that `seq == commandclientframe` this could only be +// partially true since the input_*s (in particular, timelength) are not +// constant for this frame. +struct PMS_Data { + vector org, vel; + float seq; +} pm_s, pm_so, pm_c; + +struct { + entity ent; + float seq; + + vector error; + float errortime; + + float step, steptime, step_oldz; + + vector vieworg; +} pm; + +void PM_PmCmd(float arg) { + sendevent("PmCmd", "f", arg); } +vector PM_Org() { return PM_Enabled() ? pm.ent.origin : pmove_org; } +vector PM_Vel() { return PM_Enabled() ? pm.ent.velocity : pmove_vel; } +inline entity PM_Ent() { return pm.ent; } + +inline float CSQC_JumpSounds_Active() { return CVARF(fo_csjumpsounds); } + // Sets *type to whatever is at the feet of `point`. static float PM_GetWaterLevel(vector point, float* type) { float waterlevel = 0; @@ -21,35 +59,14 @@ static float PM_GetWaterLevel(vector point, float* type) { return waterlevel; } -// Some versions of FTE do not correctly update pmove_vel (although other state, -// e.g. pmove_org is). Until we're directly tied to pmove, we snoop on recent -// values when we think this is happening. -float recent_pmove_vel_z; - -void PM_PredictJump() { - if (!CSQC_JumpSounds_Active() || getstatf(STAT_PAUSED)) - return; - - static float last_onground, last_waterlevel, last_vel_z; - +static void PM_Sounds(float is_jumping, float is_jumpframe, + float is_landing, + float last_vel_z) { float fluidtype; - float waterlevel = PM_GetWaterLevel(pmove_org, &fluidtype); - float jumping = input_buttons & BUTTON2; - float onground = pmove_onground; - float landing = onground && !last_onground; - float vel_z = pmove_vel_z ?: recent_pmove_vel_z; + static float last_waterlevel; // Hacky ... + float waterlevel = PM_GetWaterLevel(PM_Org(), &fluidtype); - if (!game_state.is_alive) { - last_onground = 1; - last_vel_z = 0; - last_waterlevel = 0; - return; - } - - static float swimsound_next; - - string sound; - if (landing && last_vel_z < -300) { // Hard or water land. + if (is_landing && last_vel_z < -300) { // Hard or water land. if (fluidtype == CONTENT_WATER) localsound("player/h2ojump.wav", CHAN_BODY, 1); else if (last_vel_z < -650) // Will take damage. @@ -59,12 +76,15 @@ void PM_PredictJump() { } // TODO: Model health above and not play jump when landing into death. - if (jumping) { - if (waterlevel >= 2 && time > swimsound_next) { - swimsound_next = time + 1; - sound = random() < 0.5 ? "player/water1.wav" : "player/water2.wav"; - localsound(sound, CHAN_BODY, 1); - } else if (last_onground && !onground && vel_z > last_vel_z + 200) { + if (is_jumping) { + static float swimsound_next; + if (waterlevel >= 2) { + if (time > swimsound_next) { + swimsound_next = time + 1; + localsound(random() < 0.5 ? "player/water1.wav" : "player/water2.wav", + CHAN_BODY, 1); + } + } else if (is_jumpframe) { // The default pmove implementation and server behave slightly // differently here in two important ways here: // 1) Jump calculations run _prior_ to movement rather than post, @@ -80,7 +100,7 @@ void PM_PredictJump() { } if (waterlevel > 0 && last_waterlevel == 0) { // Water entry. - sound = ""; + string sound = ""; switch(fluidtype) { case CONTENT_LAVA: sound = "player/inlava.wav"; break; case CONTENT_WATER: sound = "player/inh2o.wav"; break; @@ -91,7 +111,377 @@ void PM_PredictJump() { localsound("misc/outwater.wav", CHAN_BODY, 1); } + last_waterlevel = waterlevel; +} + +// Some versions of FTE do not correctly update pmove_vel (although other state, +// e.g. PM_Org() is). Until we're directly tied to pmove, we snoop on recent +// values when we think this is happening. +float recent_pmove_vel_z; + +void PM_PredictJump_Engine() { + if (!CSQC_JumpSounds_Active() || getstatf(STAT_PAUSED)) + return; + + if (PM_Enabled()) // Handled by PredictJump_Pmove + return; + + static float last_onground, last_vel_z; + + float jumping = input_buttons & BUTTON2; + float onground = pmove_onground; //pmove_onground; + float landing = (onground && !last_onground); + float vel_z = pmove_vel_z ?: recent_pmove_vel_z; + + if (!game_state.is_alive) { + last_onground = 1; + last_vel_z = 0; + return; + } + + float is_jump = last_onground && !onground && vel_z > last_vel_z + 200; + + PM_Sounds(jumping, is_jump, landing, last_vel_z); + last_vel_z = vel_z; last_onground = onground; - last_waterlevel = waterlevel; }; + +//////////////////////////////////////////////////////////////////////////////// +// Pmove +//////////////////////////////////////////////////////////////////////////////// + +enum { + SERVER, + PMOVE, + VIEW, + NUM_DBG_GRAPH_TYPES, +}; + +DEFCVAR_FLOAT(fopmd_graph_x, -10); +DEFCVAR_FLOAT(fopmd_graph_y, 100); +DEFCVAR_FLOAT(fopmd_graph_w, 200); +DEFCVAR_FLOAT(fopmd_graph_h, 100); + +DEFCVAR_FLOAT(fopm_noerror, 0); +DEFCVAR_FLOAT(fopm_nocache, 0); +DEFCVAR_FLOAT(fopm_nostep, 0); + +DEFCVAR_FLOAT(v_viewheight, 0); + +enumflags { + PMDG_ON, + PMDG_NO_ALIGN_INTERP, +}; +DEFCVAR_FLOAT(fopmd_graph, 0); + +void PM_Init() { + pm.ent = spawn(); + pm.ent.solid = SOLID_NOT; + pm.ent.movetype = MOVETYPE_WALK; + setsize(pm.ent, '-16 -16 -24', '16 16 32'); +} + +// Should be invoked immediately after RunMovement() to ensure correctness of +// `seq` versus state. On server packets we manually set `seq` to sf + 1. +static inline void PM_SavePMS(PMS_Data *pms) { + entity ent = pm.ent; + pms->org = ent.origin; + pms->vel = ent.velocity; + pms->seq = pm.seq; +} + +static inline void PM_ActivatePMS(PMS_Data *pms) { + entity ent = pm.ent; + ent.origin = pms->org; + ent.velocity = pms->vel; + pm.seq = pms->seq; +}; + +static void PM_RunMovement(float endframe) { + entity ent = pm.ent; + if (servercommandframe >= pm_s.seq + 63) { + // We're meant to be updating the player faster than this + // hopefully its just that we're throttled... + // Uncommenting this block will result in the player continuing to be + // predicted rather than frozen. + pm_s.seq = servercommandframe - 63; + return; + } + + if (endframe < pm.seq) { + if (endframe >= pm_c.seq && !CVARF(fopm_nocache)) + PM_ActivatePMS(&pm_c); + else + PM_ActivatePMS(&pm_s); + } + + + if (!game_state.is_alive) { + pm.seq = clientcommandframe; + //just update the angles + if (!getinputstate(pm.seq-1)) { } + return; + } + + if (pm.seq < clientcommandframe - 128) + pm.seq = clientcommandframe - 128; + + while (pm.seq <= endframe) { + if (!getinputstate(pm.seq)) + break; + + // We have to apply this on the leading edge since INPUT_FRAME + // modifications do not occur until the frame is finalized. + if (pm.seq == clientcommandframe) + FO_ApplyMaxSpeed(TRUE); + + pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing + runstandardplayerphysics(ent); + + pm.seq++; + } + + // Add in anything that was applied after (for low packet rate protocols) + input_angles = view_angles; +}; + +static void PM_SetEnabled(float enabled) { + pm_enabled = enabled; + pm.ent.solid = enabled ? SOLID_SLIDEBOX : SOLID_NOT; + + if (!enabled) + return; + + pm.errortime = 0; + pm.steptime = 0; + pm.step_oldz = pm.ent.origin_z; +} + +static void PM_UpdateError() { + entity ent = pm.ent; + + if (CVARF(fopm_noerror)) { + pm.error = '0 0 0'; + pm.errortime = 0; + return; + } + + // Run prior prediction to present. + PM_ActivatePMS(&pm_so); + PM_RunMovement(clientcommandframe); + vector err = ent.origin; + + // Repeat with updated state. + PM_ActivatePMS(&pm_s); + PM_RunMovement(clientcommandframe); + + err -= ent.origin; + float nerr = vlen(err); + if (nerr > 128) { // teleport + pm.error = '0 0 0'; + pm.errortime = 0; + } else { // figure out the error amount, and add it to accumulated lerp + pm.error *= max(pm.errortime - time, 0) / ERRORTIME; + pm.error += err; + pm.errortime = vlen(pm.error) > 1 ? time + ERRORTIME : 0; + } +} + +static void PM_UpdateLocalMovement() { + entity ent = pm.ent; + + /* PM_ActivatePMS(&pm_c); */ + PM_RunMovement(clientcommandframe); + vector org = pm.ent.origin; + + + // Smooth stair stepping + if (org_z > pm.step_oldz + 8 && org_z < pm.step_oldz + 24 && + ent.velocity_z == 0) { // Evaluate out the remaining old step + if (pm.steptime - time > 0) + pm.step = (pm.steptime - time) * STEPTIME * pm.step; + else + pm.step = 0; + + // Work out the new step + pm.step += (pm.step_oldz - org_z); + pm.steptime = time + 1 / STEPTIME; + } + pm.step_oldz = org_z; + + float viewheight = CVARF(v_viewheight); + if (viewheight < -7) + viewheight = -7; + else if (viewheight > 7) + viewheight = 7; + + pm.vieworg = org; + pm.vieworg.z += getstatf(STAT_VIEWHEIGHT) + viewheight; + + // Correct view position over ERRORTIME + if (pm.errortime - time > 0) + pm.vieworg += (pm.errortime - time) * (1 / ERRORTIME) * pm.error; + + if (!CVARF(fopm_nostep)) + if (pm.steptime - time > 0) + pm.vieworg.z += (pm.steptime - time) * STEPTIME * pm.step; +} + +void PMD_UpdateImpulse(int seq); + +void PM_SyncTo(float seq) { + if (!PM_Enabled()) + return; + + entity ent = pm.ent; + + PM_RunMovement(seq - 1); + float of = ent.flags; + float last_vel_z = ent.velocity_z; + + PM_RunMovement(seq); + float nf = ent.flags; + + if (!CSQC_JumpSounds_Active()) + return; + + // Note: ~FL_ONGROUND and jump occur in same frame, produces JUMP_HELD + float jumping = input_buttons & BUTTON2; + float landing = (!(of & FL_ONGROUND) && (nf & FL_ONGROUND)); + float jump_frame = ent.pmove_flags & PMF_JUMP_HELD; + + PM_Sounds(jumping, jump_frame, landing, last_vel_z); +} + +void PM_Update(float sendflags) { + float was_enabled = PM_Enabled(); + float enabled = ((pstate_server.predict_flags & PF_PMOVE) && + (game_state.is_player)); + + if (enabled != was_enabled) + PM_SetEnabled(enabled); + + if (sendflags & FOWP_PMOVE == 0) + return; + + pm_so = pm_s; + pm.seq = servercommandframe + 1; // server state includes move + PM_SavePMS(&pm_s); + + // Pre-compute predicted movement for all locked frames (e.g. seq < + // clientcommandframe) so that we can accelerate the common case of + // computation at clientcommandframe (which does require constant + // re-evaluation). In the case there's no separation (e.g. lan pings) then + // the server frame is directly used as the cache frame. + if (clientcommandframe > servercommandframe + 1) + PM_RunMovement(clientcommandframe - 1); + PM_SavePMS(&pm_c); + + if (enabled && was_enabled) + PM_UpdateError(); + + PMD_UpdateImpulse(servercommandframe); +} + +void PM_UpdateView() { + PM_UpdateLocalMovement(); + setviewprop(VF_ORIGIN, pm.vieworg); + setviewprop(VF_ANGLES, view_angles); + + makevectors(view_angles); + SetListener(pm.vieworg, v_forward, v_right, v_up); +} + +//////////////////////////////////////////////////////////////////////////////// +// Debug +//////////////////////////////////////////////////////////////////////////////// + +static const float NIMP = 300; +struct PmoveDebug { + float points[NIMP]; + int nimp; +}; + +static PmoveDebug pmd[NUM_DBG_GRAPH_TYPES]; + +static void PMD_AddPoint(int ptype, float val) { + PmoveDebug* pd = &pmd[ptype]; + + pd->points[pd->nimp++ % NIMP] = val; +} + +static void PMD_UpdateImpulse(int seq) { + if (!CVARF(fopmd_graph)) + return; + + static int old_seq; + if (old_seq == seq) + return; + old_seq = seq; + + if (PM_Enabled()) + PM_RunMovement(clientcommandframe); + + vector sv = pm_s.vel; + vector pv = PM_Vel(); + + if (!vlen(pv) && !vlen(sv)) + return; + + PMD_AddPoint(SERVER, vlen(sv)); + PMD_AddPoint(PMOVE, vlen(pv)); + PMD_AddPoint(VIEW, vlen(pm.error) / 128 * 1200); +} + +static void PMD_Graph(int type, int offset, vector c1, vector c2, vector rgb) { + PmoveDebug* pd = &pmd[type]; + float wx = c2.x - c1.x, wy = c2.y - c1.y; + + float maxv = pd->points[0], minv = pd->points[0]; + for (int i = 1; i < NIMP; i++) { + maxv = max(maxv, pd->points[i]); + minv = min(minv, pd->points[i]); + } + + float h = max(maxv - minv, 1200); + + float px = wx / NIMP, py = (wy - 2) / h; + vector lend = c1 + [0, wy, 0]; + + vector m1 = [0, wy - maxv * py, 0]; + drawline(1, c1 + m1, c1 + m1 + [wx, 0, 0], '50 150 150', 1); + + for (int i = offset; i < NIMP; i++) { + int idx = (pd->nimp + i) % NIMP; + vector sx = + [c1.x + (i - offset) * px, c2.y - (pd->points[idx]) * py + 1, 0]; + vector sy = [sx.x + px, sx.y, 0]; + + drawline(1, sx, sy, rgb, 1); + drawline(1, lend, sx, rgb, 1); + lend = sy; + } +} + +void PMD_DrawGraphs(float width) { + if (!CVARF(fopmd_graph)) + return; + + vector c1 = [CVARF(fopmd_graph_x), CVARF(fopmd_graph_y), 0]; + if (c1.x < 0) + c1.x += width - CVARF(fopmd_graph_w); + vector w = [CVARF(fopmd_graph_w), CVARF(fopmd_graph_h), 0]; + vector c2 = c1 + w; + + drawfill(c1, w, '0.2 0.2 0.2', 1); + drawfill(c2, '5 5 5', '1 0 0', 1); + + float offset = (CVARF(fopmd_graph) & PMDG_NO_ALIGN_INTERP) ? 0 : + clientcommandframe - servercommandframe; + + offset = max(0, offset); + PMD_Graph(PMOVE, 0, c1, c2, '0 0 1'); + PMD_Graph(VIEW, 0, c1, c2, '0 1 0'); + PMD_Graph(SERVER, offset, c1, c2, '1 0 0'); +} diff --git a/csqc/status.qc b/csqc/status.qc index 868a006f..16752c7e 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -993,7 +993,9 @@ static SpeedBarColors speedbar_colors[] = { }; static float PlanarSpeed() { - return vlen([pmove_vel.x, pmove_vel.y, 0]); + vector pvel = PM_Vel(); + pvel.z = 0; // compiler bug: pvel becomes [1 0 0] if this is inlined + return vlen(pvel); } void drawSpeedBar(PanelID panelid, string text) { diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 28c93834..1de72c02 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -154,7 +154,7 @@ static float next_grenlist_update; static float RenderGrenTimer(entity p, float test_only) { const float maxd = 1000, mind = 200; vector po = p.origin + '0 0 40'; - vector o = pmove_org; + vector o = PM_Org(); if (p == local_player) return FALSE; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6fbd2715..ea1c42e1 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -585,7 +585,9 @@ void PredProj_Sound(int proj_type, float vol = 1) { Pred_Sound(FPP_Get(proj_type)->snd, vol); } -void WP_ServerUpdate() { +void PM_Update(float sendflags); + +void WP_ServerUpdate(float sendflags) { // Force WF to zero, in case we missed a packet. if (pstate_server.attack_finished < pstate_server.client_time) pstate_server.weaponframe = 0; @@ -605,6 +607,8 @@ void WP_ServerUpdate() { phys_sim_dt = (pstate_server.client_ping + 2 * SERVER_FRAME_MS) / 1000.0; else phys_sim_dt = -1; + + PM_Update(sendflags); } void FO_ReloadSound(float weapon) { @@ -789,7 +793,7 @@ static void WP_Sniper_UpdateSight() { } SniperState.sight.drawmask = MASK_ENGINE; - vector org = pmove_org + v_forward * 10; + vector org = PM_Org() + v_forward * 10; org.z += PLAYER_MINS.z - 1 + (PLAYER_MAXS.z - PLAYER_MINS.z) * 0.7; traceline(org, org + v_forward * 9192, MOVE_NORMAL, 0); setorigin(SniperState.sight, trace_endpos); @@ -1179,12 +1183,16 @@ void WPP_Dump() { void WP_Attack(); -void FO_ApplyMaxSpeed() { - if (!WP_Enabled() || !CVARF(wpp_setspeed) || !RewindFlagEnabled(REWIND_SETSPEED)) +void FO_ApplyMaxSpeed(float force) { + if (!force && + (!WP_Enabled() || !CVARF(wpp_setspeed) || !RewindFlagEnabled(REWIND_SETSPEED))) return; + float max_speed = pstate_pred.csqc_maxspeed; if (pstate_pred.tfstate & TFSTATE_AIMING) - input_movevalues = normalize(input_movevalues) * 80; + max_speed = 80; + if (vlen(input_movevalues) > max_speed) + input_movevalues = normalize(input_movevalues) * max_speed; } DEFCVAR_FLOAT(cl_crossx, 0); @@ -1430,7 +1438,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.drawmask = MASK_PRED_PROJECTILE; setsize(proj, [0,0,0], [0,0,0]); - proj.origin = pmove_org + offset; + proj.origin = PM_Org() + offset; float proj_speed = FPP_Get(fpp_type)->speed; if (!FPP_IsGrenade(fpp_type)) { @@ -1596,7 +1604,7 @@ static void W_ThrowGren(float is_throw) { void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { - vector offset = org - pmove_org - '0 0 16'; + vector offset = org - PM_Org() - '0 0 16'; entity proj = PP_CreateProjectile(FPP_ASSAULT_CANNON, offset); if (proj == __NULL__) @@ -1690,7 +1698,7 @@ void WP_Attack() { // Tested both ways and this seems to be more stable. sendevent("Attack", "ifvv", (float)wi->weapon, pstate_server.client_time, - pmove_org, input_angles); + PM_Org(), input_angles); } } @@ -1729,7 +1737,7 @@ void WP_Attack() { void PredProjectile_DebugMatch(entity cprj, entity sprj) { string sgn = - vlen(cprj.origin - pmove_org) > vlen(sprj.origin- pmove_org) ? "+" : "-"; + vlen(cprj.origin - PM_Org()) > vlen(sprj.origin- PM_Org()) ? "+" : "-"; string s = sprintf(" p_diff: %s%-2.1f [%0.3f] ", sgn, vlen(cprj.origin - sprj.origin), @@ -1739,7 +1747,7 @@ void PredProjectile_DebugMatch(entity cprj, entity sprj) { sprj.phys_time - cprj.phys_time)); s = strcat(s, sprintf(" [c=%d s=%d] al=%d\n", - vlen(cprj.origin - pmove_org), vlen(sprj.origin - pmove_org), + vlen(cprj.origin - PM_Org()), vlen(sprj.origin - PM_Org()), self.antilag_ms)); print(s); } @@ -1974,6 +1982,9 @@ static void PredictConc() { pstate_pred.tfstate &= ~TFSTATE_CONC; } +void PM_SyncTo(float seq); +void PM_TestJump(); + static void WP_UpdatePredict() { PredictConc(); // Looks like this is missing time/prediction interp getinputstate(servercommandframe); // Setup first read for old_buttons. @@ -1999,6 +2010,7 @@ static void WP_UpdatePredict() { if (pframe == effect_frame && pframe > pengine.last_effectframe) { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; + PM_SyncTo(pframe); } else { pengine.is_effectframe = FALSE; } @@ -2030,9 +2042,12 @@ float WP_ClientThink() { return PREDRAW_NEXT; } +entity WP_pmove_ent(); + void InitWeapPredEnt(entity pe) { if (pengine.pweap_ent != world) { remove(pengine.pweap_ent); + pengine.pweap_ent = world; } pe.predraw = WP_ClientThink; diff --git a/share/animate.qc b/share/animate.qc index 6d0db327..a05ec931 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -153,7 +153,7 @@ static inline float *tf_state() { return &pstate_pred.tfstate; } static inline float is_attacking() { return input_buttons & BUTTON0; } static inline float is_intermission() { return intermission; } static void SuperDamageSound() {} // TODO -static inline vector get_velocity() { return pmove_vel; } +static inline vector get_velocity() { return PM_Vel(); } static inline void set_weapon_frame(float f) { pstate_pred.weaponframe = f; } static inline void muzzleflash() {} float WP_CurrentClipFired(); diff --git a/share/classes.qc b/share/classes.qc index 7f3703e1..535a75b0 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -27,7 +27,7 @@ float shared_crandom(int type) { #ifdef CSQC float WP_GetAmmo(float ammo_type); float get_shells() { return WP_GetAmmo(AMMO_SHELLS); } -static inline vector get_origin() { return pmove_org; } +static inline vector get_origin() { return PM_Org(); } #else float get_shells() { return self.ammo_shells; } static inline vector get_origin() { return self.origin; } diff --git a/share/prediction.qc b/share/prediction.qc index 001441da..2b106b97 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -10,6 +10,7 @@ string wp_version = "v1.1"; enumflags { FOWP_CTIME, + FOWP_PMOVE, FOWP_IMPULSE, FOWP_TFSTATE, FOWP_LASTPRIME, @@ -45,6 +46,12 @@ enumflags { CSQC_SNIPER_SIGHT, }; +enumflags { + PF_PMOVE, + PF_POS, + PF_PMOVE_ACTIVATING, +}; + struct predict_tf_state { int playerclass; int predict_flags; @@ -320,6 +327,7 @@ predict_tf_state pstate_pred, pstate_server; .float pred_lastforce; .float pred_forcebit; .entity last_pred_src; +.float predict_flags; static float Prediction_ChangedMask(entity player, entity src) { if (src != player.last_pred_src) { @@ -332,6 +340,9 @@ static float Prediction_ChangedMask(entity player, entity src) { player.predict_state.client_time = src.client_time; player.predict_state.client_ping = src.client_ping; + if (player.predict_flags & PF_POS) + mask |= FOWP_PMOVE; + M1(FOWP_CLASS, playerclass); M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); M2(FOWP_TFSTATE, tfstate, csqc_maxspeed); @@ -344,6 +355,7 @@ static float Prediction_ChangedMask(entity player, entity src) { M2(FOWP_RELOAD, reload_started, reload_finished); M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]); + M1(FOWP_PREDICT_FLAGS, predict_flags); M4(FOWP_GREN, no_grenades_1, no_grenades_2, primed_gren_type, primed_gren_exp) // Rotate through forced update fields. @@ -354,7 +366,8 @@ static float Prediction_ChangedMask(entity player, entity src) { if (player.pred_forcebit >= FOWP_LAST) player.pred_forcebit = 1; - mask |= player.pred_forcebit; + if (player.pred_forcebit != FOWP_PMOVE) + mask |= player.pred_forcebit; } return mask; @@ -398,7 +411,7 @@ float() ReadEntity = #368; int() ReadInt = #0:readint; void InitWeapPredEnt(entity e); -void WP_ServerUpdate(); +void WP_ServerUpdate(float sendflags); void InitProjectileEnt(float sendflags); void WPP_UpdateEnable(float force); @@ -442,6 +455,7 @@ void EntUpdate_Config() { #ifdef SSQC #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) +#define COMM_PM(_type, _field) Write##_type(MSG_ENTITY, self.owner.##_field) float WP_SendEntity(entity to_player, float sendflags) { if (to_player != self.owner) return FALSE; @@ -449,7 +463,10 @@ float WP_SendEntity(entity to_player, float sendflags) { WriteByte(MSG_ENTITY, ENT_WEAPONPRED); WriteFloat(MSG_ENTITY, sendflags); #else +entity PM_Ent(); #define COMM(_type, _field) pstate_server.##_field = Read##_type() +#define COMM_PM(_type, _field) PM_Ent().##_field = Read##_type() + void EntUpdate_WeaponPred(float isnew) { float sendflags = readfloat(); #endif @@ -461,6 +478,15 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Short, client_ping); } + if (sendflags & FOWP_PMOVE) { + COMM_PM(Coord, origin[0]); + COMM_PM(Coord, origin[1]); + COMM_PM(Coord, origin[2]); + COMM_PM(Short, velocity[0]); + COMM_PM(Short, velocity[1]); + COMM_PM(Short, velocity[2]); + } + if (sendflags & FOWP_CLASS) { COMM(Byte, playerclass); } @@ -529,7 +555,7 @@ void EntUpdate_WeaponPred(float isnew) { if (isnew) InitWeapPredEnt(self); else - WP_ServerUpdate(); + WP_ServerUpdate(sendflags); #endif } #undef COMM diff --git a/ssqc/client.qc b/ssqc/client.qc index 750cf5ff..b20c3c15 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3890,3 +3890,49 @@ void() SV_RunClientCommand = { self.jump_flag = self.velocity_z; } */ + +static void DeferredPmoveAction() { + entity player = self.owner; + player.predict_flags &= ~PF_PMOVE_ACTIVATING; + + if (self.heat) { + sprint(player, PRINT_HIGH, "*** PMOVE ACTIVATED\n"); + player.nodrawtoclient = player; + player.predict_flags |= PF_PMOVE; + } else { + sprint(self, PRINT_HIGH, "*** PMOVE INACTIVE\n"); + player.predict_flags &= ~PF_PMOVE; + } + remove(self); +} + +void (float active) CSEv_PmCmd_f = { + sprint(self, PRINT_HIGH, sprintf("*** PMCMD %d\n", active)); + if (self.predict_flags & PF_PMOVE_ACTIVATING) { + sprint(self, PRINT_HIGH, "Please wait for prior activation to complete...\n"); + return; + } + + if (active & PF_PMOVE) + active |= PF_POS; + + self.predict_flags &= ~PF_POS; + self.predict_flags |= (active & PF_POS); + + if ((active & PF_PMOVE) == (self.predict_flags & PF_PMOVE)) + return; + + float enable = active & PF_PMOVE; + if (enable) { + self.maxspeed = PC_SCOUT_MAXSPEED; // Handled clientside. + } else { + self.nodrawtoclient = world; + } + + self.predict_flags |= PF_PMOVE_ACTIVATING; + entity defer = spawn(); + defer.owner = self; + defer.think = DeferredPmoveAction; + defer.heat = enable; + defer.nextthink = time + 0.1; +} From 5a5f9f9fdd2fbadc639eeb929648926697e46d9c Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 19:31:49 -0700 Subject: [PATCH 2208/2474] pmove: make sure prediction ent is owned by player Unlike networked player entities, our pmove ent is actually visible and can generate false local grenade collisions. Make sure that it's owned by the player to exclude this. --- csqc/pmove.qc | 22 ++++++++++++++++++++-- csqc/weapon_predict.qc | 5 +++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 9eebf07a..1862b6be 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -178,7 +178,6 @@ DEFCVAR_FLOAT(fopmd_graph, 0); void PM_Init() { pm.ent = spawn(); pm.ent.solid = SOLID_NOT; - pm.ent.movetype = MOVETYPE_WALK; setsize(pm.ent, '-16 -16 -24', '16 16 32'); } @@ -248,7 +247,8 @@ static void PM_RunMovement(float endframe) { static void PM_SetEnabled(float enabled) { pm_enabled = enabled; - pm.ent.solid = enabled ? SOLID_SLIDEBOX : SOLID_NOT; + + PM_Refresh(); if (!enabled) return; @@ -261,6 +261,7 @@ static void PM_SetEnabled(float enabled) { static void PM_UpdateError() { entity ent = pm.ent; + ent.owner = edict_num(player_localentnum); if (CVARF(fopm_noerror)) { pm.error = '0 0 0'; pm.errortime = 0; @@ -393,6 +394,23 @@ void PM_UpdateView() { SetListener(pm.vieworg, v_forward, v_right, v_up); } +void PM_Refresh() { + if (!PM_Enabled()) + return; + + entity ent = pm.ent; + setorigin(ent, ent.origin); + if (game_state.is_player) { + ent.owner = edict_num(player_localentnum); + ent.movetype = MOVETYPE_WALK; + ent.solid = SOLID_SLIDEBOX; + } else { + ent.owner = world; // Needs more than this for spec.. + ent.movetype = MOVETYPE_FLY; + ent.solid = SOLID_NOT; + } +} + //////////////////////////////////////////////////////////////////////////////// // Debug //////////////////////////////////////////////////////////////////////////////// diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ea1c42e1..b98bce2c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -2057,7 +2057,12 @@ void InitWeapPredEnt(entity pe) { wp_ready = TRUE; } +void PM_Refresh(); + void WP_ServerFrame() { if (game_state.is_player != prev_game_state.is_player) WPP_UpdateEnable(TRUE); + + if (game_state.spawn_gen != prev_game_state.spawn_gen) + PM_Refresh(); } From 9d758fe10fbe05403727065ba0052ff39f464f9b Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 19:35:23 -0700 Subject: [PATCH 2209/2474] pmove: set/clear cl_smartjump automatically Misses lots of edge cases but good enough until we (very shortly) replace smartjump. --- csqc/pmove.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 1862b6be..afabe934 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -33,6 +33,7 @@ struct { } pm; void PM_PmCmd(float arg) { + localcmd(sprintf("cl_smartjump %d\n", (arg & 1) ? 0 : 1)); sendevent("PmCmd", "f", arg); } From 8bdaefb1dc909ed89e1f922f0f17dbce02326a69 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 21:27:49 -0700 Subject: [PATCH 2210/2474] pmove: render effects locally Since we obscure the networked player, effects such as flag glow were not being rendered correctly. Reproduce these when clientside pmove is used. --- csqc/csextradefs.qc | 13 +++++++++ csqc/pmove.qc | 68 ++++++++++++++++++++++++++++++++++++++------- share/prediction.qc | 8 ++++-- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index c0309ad4..3ae49762 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -911,3 +911,16 @@ float(string key, optional float assumevalue) serverkeyfloat = #0:serverkeyfloat vector PM_Org(); vector PM_Vel(); + +struct veci { + vector v; + float i; +}; + +void cvar_parse4(string s, __out veci target) { + tokenize(s); + target.v[0] = stof(argv(0)); + target.v[1] = stof(argv(1)); + target.v[2] = stof(argv(2)); + target.i = stof(argv(3)); +} diff --git a/csqc/pmove.qc b/csqc/pmove.qc index afabe934..1cd16308 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -386,21 +386,11 @@ void PM_Update(float sendflags) { PMD_UpdateImpulse(servercommandframe); } -void PM_UpdateView() { - PM_UpdateLocalMovement(); - setviewprop(VF_ORIGIN, pm.vieworg); - setviewprop(VF_ANGLES, view_angles); - - makevectors(view_angles); - SetListener(pm.vieworg, v_forward, v_right, v_up); -} - void PM_Refresh() { if (!PM_Enabled()) return; entity ent = pm.ent; - setorigin(ent, ent.origin); if (game_state.is_player) { ent.owner = edict_num(player_localentnum); ent.movetype = MOVETYPE_WALK; @@ -412,6 +402,64 @@ void PM_Refresh() { } } +//////////////////////////////////////////////////////////////////////////////// +// View/Render +//////////////////////////////////////////////////////////////////////////////// + +DEFCVAR_STRING(r_brightlight_colour, "2.0 1.0 0.5 400"); +DEFCVAR_STRING(r_dimlight_colour, "2.0 1.0 0.5 200"); +DEFCVAR_STRING(r_redlight_colour, "3.0 0.5 0.5 200"); +DEFCVAR_STRING(r_bluelight_colour, "0.5 0.5 3.0 200"); +veci brightlight_l, dimlight_l, redlight_l, bluelight_l; + +static void ParseCvars() { + static float next_refresh; + + if (time < next_refresh) + return; + next_refresh = time + 0.5; + + cvar_parse4(CVARS(r_brightlight_colour), brightlight_l); + cvar_parse4(CVARS(r_dimlight_colour), dimlight_l); + cvar_parse4(CVARS(r_redlight_colour), redlight_l); + cvar_parse4(CVARS(r_bluelight_colour), bluelight_l); +} + +#define MUX_IN(ef, bit, src) \ + do { if ((ef) & (bit)) { rad = max(rad, src.i); col += src.v; } } while (0) +static void LocalEffects() { + float effects = pstate_server.effects; + float rad = 0; + vector col = '0 0 0'; + + const float MASK_ALL = EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE; + + if (effects & MASK_ALL == 0) + return; + + ParseCvars(); + + MUX_IN(effects, EF_BRIGHTLIGHT, brightlight_l); + MUX_IN(effects, EF_DIMLIGHT, dimlight_l); + MUX_IN(effects, EF_RED, redlight_l); + MUX_IN(effects, EF_BLUE, bluelight_l); + + rad = min(rad, 400); + dynamiclight_add(pm.vieworg, rad, col); +} +#undef MUX_IN + +void PM_UpdateView() { + PM_UpdateLocalMovement(); + setviewprop(VF_ORIGIN, pm.vieworg); + setviewprop(VF_ANGLES, view_angles); + + makevectors(view_angles); + SetListener(pm.vieworg, v_forward, v_right, v_up); + + LocalEffects(); +} + //////////////////////////////////////////////////////////////////////////////// // Debug //////////////////////////////////////////////////////////////////////////////// diff --git a/share/prediction.qc b/share/prediction.qc index 2b106b97..a94ed9b5 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -54,7 +54,7 @@ enumflags { struct predict_tf_state { int playerclass; - int predict_flags; + int predict_flags, effects; int impulse; Slot current_slot, queue_slot, last_slot; @@ -355,7 +355,7 @@ static float Prediction_ChangedMask(entity player, entity src) { M2(FOWP_RELOAD, reload_started, reload_finished); M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]); - M1(FOWP_PREDICT_FLAGS, predict_flags); + M2(FOWP_PREDICT_FLAGS, predict_flags, effects); M4(FOWP_GREN, no_grenades_1, no_grenades_2, primed_gren_type, primed_gren_exp) // Rotate through forced update fields. @@ -470,8 +470,10 @@ entity PM_Ent(); void EntUpdate_WeaponPred(float isnew) { float sendflags = readfloat(); #endif - if (sendflags & FOWP_PREDICT_FLAGS) + if (sendflags & FOWP_PREDICT_FLAGS) { COMM(Byte, predict_flags); + COMM(Short, effects); + } if (sendflags & FOWP_CTIME) { COMM(Float, client_time); From 19a9fa387d5f713400be5b3567ee4e3fc474db19 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 22:27:38 -0700 Subject: [PATCH 2211/2474] pmove: implement spectator support Minor tweaks to be able to predict correctly as a spec. --- csqc/pmove.qc | 7 +++---- ssqc/client.qc | 7 ++++++- ssqc/tfort.qc | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 1cd16308..5bc661a7 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -217,7 +217,7 @@ static void PM_RunMovement(float endframe) { } - if (!game_state.is_alive) { + if (!game_state.is_spectator && !game_state.is_alive) { pm.seq = clientcommandframe; //just update the angles if (!getinputstate(pm.seq-1)) { } @@ -358,8 +358,7 @@ void PM_SyncTo(float seq) { void PM_Update(float sendflags) { float was_enabled = PM_Enabled(); - float enabled = ((pstate_server.predict_flags & PF_PMOVE) && - (game_state.is_player)); + float enabled = pstate_server.predict_flags & PF_PMOVE; if (enabled != was_enabled) PM_SetEnabled(enabled); @@ -397,7 +396,7 @@ void PM_Refresh() { ent.solid = SOLID_SLIDEBOX; } else { ent.owner = world; // Needs more than this for spec.. - ent.movetype = MOVETYPE_FLY; + ent.movetype = MOVETYPE_NOCLIP; ent.solid = SOLID_NOT; } } diff --git a/ssqc/client.qc b/ssqc/client.qc index b20c3c15..107933c3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3899,6 +3899,7 @@ static void DeferredPmoveAction() { sprint(player, PRINT_HIGH, "*** PMOVE ACTIVATED\n"); player.nodrawtoclient = player; player.predict_flags |= PF_PMOVE; + TeamFortress_SetSpeed(player); } else { sprint(self, PRINT_HIGH, "*** PMOVE INACTIVE\n"); player.predict_flags &= ~PF_PMOVE; @@ -3924,7 +3925,11 @@ void (float active) CSEv_PmCmd_f = { float enable = active & PF_PMOVE; if (enable) { - self.maxspeed = PC_SCOUT_MAXSPEED; // Handled clientside. + // This is messy; maxspeed exists only in hidden inband communication + // with the client. We need to push a high value to the client before + // we obscure the client since it won't see further updates (which might + // increase when changing classes). + self.maxspeed = 1000; } else { self.nodrawtoclient = world; } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index cdcc7390..c0ff4439 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -997,7 +997,7 @@ void (entity p) TeamFortress_SetSpeed = { if (p.playerclass == PC_UNDEFINED) { // Typically this hits spectators and then spec movetype --> maxspeed // actually ignored. - p.maxspeed = 0; + p.csqc_maxspeed = p.maxspeed = 1000; stuffcmd(p, "cl_movespeedkey 1;cl_backspeed 500; cl_forwardspeed 500; cl_sidespeed 500;\n"); return; } From 0ae26286bc24159cfa0f73ef7a9cd5156aadbed9 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 30 Sep 2023 02:59:43 -0700 Subject: [PATCH 2212/2474] pmove: introduce fo_smartjump replaces cl_smartjump but works properly with fo; with and without movement prediciton. We probably want to just remove the whole moveup no sound gimmick and simplify this, but parity for now --- csqc/main.qc | 5 +++-- csqc/pmove.qc | 41 ++++++++++++++++++++++++++++++++++++----- csqc/weapon_predict.qc | 14 -------------- share/classes.qc | 1 + share/commondefs.qc | 4 +--- share/defs.h | 2 ++ ssqc/client.qc | 5 ++--- ssqc/spect.qc | 1 + ssqc/tfort.qc | 26 ++++++++++---------------- 9 files changed, 56 insertions(+), 43 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1245eaf4..2b5e4d89 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -186,6 +186,7 @@ noref void() CSQC_WorldLoaded = { // Resolve race condition where models packed into map package sometimes do // not resolve correctly. localcmd("flush\n"); + localcmd("cl_smartjump 0\n"); // replaced by fo_smartjump } void FO_CussView(); @@ -642,7 +643,7 @@ void FO_ApplyCussInput() { } } -void FO_ApplyMaxSpeed(float force); +void PM_InputFrame(); noref void CSQC_Input_Frame() { Sync_GameState(); @@ -662,7 +663,7 @@ noref void CSQC_Input_Frame() { if (prev_zoomed_in != zoomed_in) setsensitivityscaler(zoomed_in ? 1/3 : 1); - FO_ApplyMaxSpeed(FALSE); + PM_InputFrame(); FO_ApplyCussInput(); } diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 5bc661a7..72f1d8da 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -159,15 +159,17 @@ enum { NUM_DBG_GRAPH_TYPES, }; -DEFCVAR_FLOAT(fopmd_graph_x, -10); -DEFCVAR_FLOAT(fopmd_graph_y, 100); -DEFCVAR_FLOAT(fopmd_graph_w, 200); -DEFCVAR_FLOAT(fopmd_graph_h, 100); +DEFCVAR_FLOAT(fo_smartjump, 1); DEFCVAR_FLOAT(fopm_noerror, 0); DEFCVAR_FLOAT(fopm_nocache, 0); DEFCVAR_FLOAT(fopm_nostep, 0); +DEFCVAR_FLOAT(fopmd_graph_x, -10); +DEFCVAR_FLOAT(fopmd_graph_y, 100); +DEFCVAR_FLOAT(fopmd_graph_w, 200); +DEFCVAR_FLOAT(fopmd_graph_h, 100); + DEFCVAR_FLOAT(v_viewheight, 0); enumflags { @@ -198,6 +200,8 @@ static inline void PM_ActivatePMS(PMS_Data *pms) { pm.seq = pms->seq; }; +void PM_InputFrame(); + static void PM_RunMovement(float endframe) { entity ent = pm.ent; if (servercommandframe >= pm_s.seq + 63) { @@ -234,7 +238,7 @@ static void PM_RunMovement(float endframe) { // We have to apply this on the leading edge since INPUT_FRAME // modifications do not occur until the frame is finalized. if (pm.seq == clientcommandframe) - FO_ApplyMaxSpeed(TRUE); + PM_InputFrame(); pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing runstandardplayerphysics(ent); @@ -401,6 +405,33 @@ void PM_Refresh() { } } +DEFCVAR_FLOAT(cl_upspeed, 400); +void PM_InputFrame() { + float iz = input_movevalues.z; + input_movevalues.z = 0; + float max_speed = pstate_pred.csqc_maxspeed; + + // cl_smartjump replacement + float type; + if (input_buttons & BUTTON2) { + if ((game_state.is_player && CVARF(fo_smartjump) && + (PM_GetWaterLevel(PM_Org(), &type) >= 2)) + || game_state.is_spectator) { + input_buttons &= ~BUTTON2; + iz = min(CVARF(cl_upspeed), Class_MaxSpeed(WP_PlayerClass())); + } + } + + // Technically the sync with pstate_pred being on the right frame is loose.. + if (pstate_pred.tfstate & TFSTATE_AIMING) + max_speed = 80; + + if (vlen(input_movevalues) > max_speed) + input_movevalues = normalize(input_movevalues) * max_speed; + if (iz) + input_movevalues.z = min(max_speed, input_movevalues.z + iz); +} + //////////////////////////////////////////////////////////////////////////////// // View/Render //////////////////////////////////////////////////////////////////////////////// diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index b98bce2c..3e6a3349 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -364,8 +364,6 @@ void WPP_UpdateEnable(float force) { wpp_status |= CSQC_WEAP_PRED; if (pengine.pp_enabled) wpp_status |= CSQC_PROJ_PRED; - if (CVARF(wpp_setspeed)) - wpp_status |= CSQC_SETSPEED; if (CVARF(fo_client_sniper_sight)) wpp_status |= CSQC_SNIPER_SIGHT; } @@ -1183,18 +1181,6 @@ void WPP_Dump() { void WP_Attack(); -void FO_ApplyMaxSpeed(float force) { - if (!force && - (!WP_Enabled() || !CVARF(wpp_setspeed) || !RewindFlagEnabled(REWIND_SETSPEED))) - return; - - float max_speed = pstate_pred.csqc_maxspeed; - if (pstate_pred.tfstate & TFSTATE_AIMING) - max_speed = 80; - if (vlen(input_movevalues) > max_speed) - input_movevalues = normalize(input_movevalues) * max_speed; -} - DEFCVAR_FLOAT(cl_crossx, 0); void WP_Frame() { diff --git a/share/classes.qc b/share/classes.qc index 535a75b0..89ea4d50 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -80,6 +80,7 @@ void WeapPred_FireAssCan(vector vangle, float shotcount, float Class_MaxSpeed(float playerclass) { switch (playerclass) { + case PC_UNDEFINED: return SPEC_MAXSPEED; case PC_SCOUT: return PC_SCOUT_MAXSPEED; case PC_SNIPER: return PC_SNIPER_MAXSPEED; case PC_SOLDIER: return PC_SOLDIER_MAXSPEED; diff --git a/share/commondefs.qc b/share/commondefs.qc index 8f989097..2aa65bfe 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -52,7 +52,6 @@ enumflags { REWIND_PROJ_FIRE, REWIND_PROJ_TRAVEL, REWIND_KNOCKBACK, - REWIND_SETSPEED, REWIND_GRENADES, REWIND_SENDEVENT, REWIND_FORWARD_PROJ_SELFKNOCK, @@ -63,7 +62,6 @@ string REWIND_DESC[] = { "rewind projectile on firing", "rewind on projectile travel", "rewind pipe knockback", - "allow csqc to handle maxspeed", "rewind grenade throws", "use sendevent augmentation (allows race w/ death rewind)", "forward projectile self-knockback", @@ -73,7 +71,7 @@ string REWIND_DESC[] = { const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_FIRE | REWIND_PROJ_TRAVEL | REWIND_FORWARD_PROJ_SELFKNOCK | - REWIND_SETSPEED | REWIND_SENDEVENT; + REWIND_SENDEVENT; float RewindFlagEnabled(float flag) { diff --git a/share/defs.h b/share/defs.h index b1da5c56..bb0a4fae 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1495,6 +1495,8 @@ enumflags { #define FO_QUAD_FINISHED_REQUEST 3 #define FO_LOGIN_REQUEST 4 +#define SPEC_MAXSPEED 1000 + struct TFAlias { string alias; float impulse; diff --git a/ssqc/client.qc b/ssqc/client.qc index 107933c3..1f3416f7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3901,14 +3901,13 @@ static void DeferredPmoveAction() { player.predict_flags |= PF_PMOVE; TeamFortress_SetSpeed(player); } else { - sprint(self, PRINT_HIGH, "*** PMOVE INACTIVE\n"); + sprint(player, PRINT_HIGH, "*** PMOVE INACTIVE\n"); player.predict_flags &= ~PF_PMOVE; } remove(self); } void (float active) CSEv_PmCmd_f = { - sprint(self, PRINT_HIGH, sprintf("*** PMCMD %d\n", active)); if (self.predict_flags & PF_PMOVE_ACTIVATING) { sprint(self, PRINT_HIGH, "Please wait for prior activation to complete...\n"); return; @@ -3929,7 +3928,7 @@ void (float active) CSEv_PmCmd_f = { // with the client. We need to push a high value to the client before // we obscure the client since it won't see further updates (which might // increase when changing classes). - self.maxspeed = 1000; + self.maxspeed = SPEC_MAXSPEED; } else { self.nodrawtoclient = world; } diff --git a/ssqc/spect.qc b/ssqc/spect.qc index e1552e94..8fa05197 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -61,6 +61,7 @@ void () SpectatorConnect = { TeamFortress_StartTimers(); TeamFortress_RemovePracticeSpawn(self); + TeamFortress_SetSpeed(self); }; void () SpectatorDisconnect = { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c0ff4439..c5215d07 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -990,15 +990,15 @@ void (entity p) TeamFortress_SetSpeed = { if (p.tfstate & TFSTATE_CANT_MOVE) { p.velocity = '0 0 0'; - p.maxspeed = 0; + p.csqc_maxspeed = p.maxspeed = 0; return; } if (p.playerclass == PC_UNDEFINED) { // Typically this hits spectators and then spec movetype --> maxspeed // actually ignored. - p.csqc_maxspeed = p.maxspeed = 1000; - stuffcmd(p, "cl_movespeedkey 1;cl_backspeed 500; cl_forwardspeed 500; cl_sidespeed 500;\n"); + p.csqc_maxspeed = p.maxspeed = SPEC_MAXSPEED; + stuffcmd(p, "cl_movespeedkey 1;cl_backspeed 500; cl_forwardspeed 500; cl_sidespeed 500;cl_upspeed 500;\n"); return; } @@ -1022,22 +1022,16 @@ void (entity p) TeamFortress_SetSpeed = { if (p.leg_damage) new_max *= (10 - min(p.leg_damage, 6)) / 10; - float client_enable = ClientPred_Enabled(p, CSQC_SETSPEED); - - // When the client is co-operating (and enabled), allow it to handle - // TFSTATE_AIMING transitions due to the frequent edges here and negative - // maxspeed/pmove interaction (bounds client prediction until maxspeed makes - // it to client, even though released on unpredicted earlier frame, leading - // to lots of skipping). - if (!RewindFlagEnabled(REWIND_SETSPEED) || !client_enable) { +#if 0 + // Clients cooperate to handle TFSTATE_AIMING transitions locally due to the + // frequent edges here and negative maxspeed/pmove interaction (bounds + // client prediction until maxspeed makes it to client, even though released + // on unpredicted earlier frame, leading to lots of skipping). if (p.tfstate & TFSTATE_AIMING) new_max = min(new_max, 80); - } +#endif - p.maxspeed = new_max; - p.csqc_maxspeed = new_max; // Note: with new input_movevalues construction - // this isn't technically needed until we do - // something like client-side tranq pred. + p.maxspeed = p.csqc_maxspeed = new_max; }; void () TeamFortress_SetHealth = { From fd2b5efbd79ea04d6f643ba29e2870a374c5e28a Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 15:57:08 -0700 Subject: [PATCH 2213/2474] tfstate: migrated feigned to tfstate Migrate feigned to tfstate in preparation for conc predict. Fix rate limit to value that limits glitches relative to animation time. --- share/defs.h | 1 + ssqc/actions.qc | 2 +- ssqc/client.qc | 4 ++-- ssqc/combat.qc | 14 ++++-------- ssqc/items.qc | 56 ++++++++++++++++++------------------------------ ssqc/menu.qc | 4 ++-- ssqc/player.qc | 4 ++-- ssqc/qw.qc | 1 - ssqc/roles.qc | 3 ++- ssqc/scout.qc | 9 ++++---- ssqc/sentry.qc | 22 +++++++++---------- ssqc/spy.qc | 28 +++++++++++++----------- ssqc/tfort.qc | 3 +-- ssqc/tfortmap.qc | 2 +- ssqc/weapons.qc | 4 ++-- 15 files changed, 68 insertions(+), 89 deletions(-) diff --git a/share/defs.h b/share/defs.h index bb0a4fae..d6d4e996 100644 --- a/share/defs.h +++ b/share/defs.h @@ -263,6 +263,7 @@ enumflags { TFSTATE_QUAD, // Player has permanent Quad Damage (Usually by GoalItem) TFSTATE_RADSUIT, // Player has permanent Radsuit (Usually by GoalItem) TFSTATE_BURNING, // Is on fire + TFSTATE_FEIGNED, // Is feigned TFSTATE_AIMING, // is using the laser sight or spinning cannon TFSTATE_RESPAWN_READY, // is waiting for respawn, and has pressed fire, // as sentry gun,indicate it needs to die diff --git a/ssqc/actions.qc b/ssqc/actions.qc index e72376af..d4c4be55 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -346,7 +346,7 @@ void (entity pe_player, float f_type) CF_Identify = { if (trace_ent.playerclass == PC_SPY && !f_friendly) { // don't identify feigning enemy spies - if (trace_ent.is_feigning) + if (IsFeigned(trace_ent)) return; // use undercover name if available diff --git a/ssqc/client.qc b/ssqc/client.qc index 1f3416f7..294cd325 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -515,7 +515,7 @@ void () DecodeLevelParms = { feign_msg = CF_GetSetting("fm", "feign_msg", "on"); // rate limit on feign - feign_rate_limit = CF_GetSetting("frl", "feign_rate_limit", "0.5"); + feign_rate_limit = CF_GetSetting("frl", "feign_rate_limit", "1"); // turn off spy [off] spy_off = CF_GetSetting("spy", "spy", "off"); @@ -2709,7 +2709,7 @@ void () PlayerPreThink = { return; } - if (self.is_feigning) { + if (IsFeigned(self)) { if (self.flags & FL_ONGROUND) { // check area for entities - if found, bounce player forward if (!self.feign_areachecked) { diff --git a/ssqc/combat.qc b/ssqc/combat.qc index ab46a718..1dfc8cf9 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -191,13 +191,8 @@ void (entity targ, entity inflictor, entity attacker, float damage) HitSound = { crit = 1; } - if (targ.playerclass == PC_SPY) - { - if (targ.is_feigning) - { + if (targ.playerclass == PC_SPY && IsFeigned(targ)) return; - } - } float targteam; targteam = (targ.undercover_team == 0) ? targ.team_no : targ.undercover_team; @@ -293,7 +288,7 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, return; // Feigned spies act as corpses unless they're a teammate - if (targ.playerclass == PC_SPY && targ.is_feigning && targ.health > 0 && + if (targ.playerclass == PC_SPY && IsFeigned(targ) && targ.health > 0 && targ.team_no != attacker.team_no) return; @@ -321,7 +316,7 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, hitflag |= HITFLAG_KILLEDUNDERCOVERSPY; hitflag &= ~HITFLAG_FRIENDLY; } - if (targ.is_feigning) + if (IsFeigned(targ)) hitflag |= HITFLAG_FEIGNEDENEMY; } } @@ -773,9 +768,8 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, } } - if (self.feign_next_damage && !self.is_feigning){ + if (self.feign_next_damage && !IsFeigned(self)) FO_Spy_Feign(0, /* ignore rate-limit */ 1); - } self = oldself; }; diff --git a/ssqc/items.qc b/ssqc/items.qc index d49041a6..ed1875cb 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -1,6 +1,7 @@ float (entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo; float (entity Retriever, float WeaponType) TeamFortress_CanGetWeapon; void (entity Retriever, entity Items) TeamFortress_AddBackpackItems; +float IsFeigned(entity ent); void (entity p) TeamFortress_SetSpeed; @@ -217,18 +218,14 @@ void () health_touch = { local float medi; local string s; - if (other.classname != "player") { + if (other.classname != "player") return; - } - if (other.is_feigning) { + if (IsFeigned(other)) return; - } - if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) { + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; - } - if (cb_prematch == 1) { + if (cb_prematch == 1) return; - } medi = 0; if (self.healtype == 2) { if (!(other.tfstate & 16)) { @@ -318,21 +315,16 @@ void () armor_touch = { local float bit; local string s; - if (other.health <= 0) { + if (other.health <= 0) return; - } - if (other.classname != "player") { + if (other.classname != "player") return; - } - if (other.is_feigning) { + if (IsFeigned(other)) return; - } - if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) { + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; - } - if (cb_prematch == 1) { + if (cb_prematch == 1) return; - } if (self.classname == "item_armor1") { type = 0.300; value = 100; @@ -419,7 +411,7 @@ void () armor_touch = { stuffcmd(other, "bf\n"); activator = other; SUB_UseTargets(); -}; +} void () item_armor1 = { if (CheckExistence() == FALSE) { @@ -534,7 +526,7 @@ void () weapon_touch = { if (!(other.flags & 8)) return; - if (other.is_feigning) + if (IsFeigned(other)) return; if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; @@ -954,24 +946,18 @@ void () item_weapon = { }; void () key_touch = { - if (other.classname != "player") { + if (other.classname != "player") return; - } - if (other.health <= 0) { + if (other.health <= 0) return; - } - if (other.items & self.items) { + if (other.items & self.items) return; - } - if (other.is_feigning) { + if (IsFeigned(other)) return; - } - if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) { + if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; - } - if (cb_prematch == 1) { + if (cb_prematch == 1) return; - } sprint(other, PRINT_LOW, "You got the ", self.netname, "\n"); FO_Sound(other, CHAN_ITEM, self.noise, 1, 1); stuffcmd(other, "bf\n"); @@ -1065,7 +1051,7 @@ void () sigil_touch = { return; if (other.health <= 0) return; - if (other.is_feigning) + if (IsFeigned(other)) return; if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; @@ -1087,7 +1073,7 @@ void () powerup_touch = { return; if (other.health <= 0) return; - if (other.is_feigning) + if (IsFeigned(other)) return; if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; @@ -1218,7 +1204,7 @@ void () BackpackTouch = { local string s; local float maxg, giveg; - if (other.classname != "player" || other.is_feigning) + if (other.classname != "player" || IsFeigned(other)) return; if (other.health <= 0) return; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 89c301c5..9b0429fd 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -583,7 +583,7 @@ void (float inp) Menu_Spy_Input = { FO_Spy_DisguiseLast(self, TRUE); } else if (inp == 3) { FO_Spy_Feign(1, 0); - if (self.is_feigning) { + if (IsFeigned(self)) { Menu_Spy(self); } } else if (inp == 4) { @@ -622,7 +622,7 @@ void (entity pe_player) Menu_Spy = { if ((!pe_player.last_selected_skin && !pe_player.last_team) || invis_only) s_last = "\n"; - if (pe_player.is_feigning) + if (IsFeigned(pe_player)) s_feign = Q"\s[3]\s Stop feigning \n"; else s_feign = Q"\s[3]\s Start feigning (silent)\n"; diff --git a/ssqc/player.qc b/ssqc/player.qc index b07ce126..1757e6bb 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -235,7 +235,7 @@ void (entity et, float f) player_pain = { if (self.invisible_finished > time) return; - if (self.is_feigning) { + if (IsFeigned(self)) { PainSound(); return; } @@ -297,7 +297,7 @@ void () DeathSound = { local float rs; if (self.waterlevel == 3) { - if (self.is_feigning) + if (IsFeigned(self)) DeathBubbles(2); else DeathBubbles(10); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 78502305..adac4f5e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -55,7 +55,6 @@ float remote_client_time(); .float is_undercover; // TRUE for a SPY if they're undercover .float is_building; // TRUE for an ENGINEER if they're building something .float is_detpacking; // TRUE for a DEMOMAN if they're setting a detpack -.float is_feigning; // TRUE for a SPY if they're feigning death .float is_button_feigning; // TRUE for a SPY if they're feigning death with +feign or +special .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage .float is_unabletospy; // TRUE for a SPY if they can't go undercover diff --git a/ssqc/roles.qc b/ssqc/roles.qc index 2416b706..3dcff6a4 100644 --- a/ssqc/roles.qc +++ b/ssqc/roles.qc @@ -4,6 +4,7 @@ float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; string(float tno) GetTeamName; void () item_tfgoal_touch; void CenterPrint(entity, string); +float IsFeigned(entity ent); float quad_roles; @@ -125,7 +126,7 @@ void () item_tfgoal_hidden_touch = { return; if (cb_prematch) return; - if (other.is_feigning) + if (IsFeigned(other)) return; if (other == self.owner) return; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 4ae95289..e9baa688 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -10,6 +10,7 @@ void () FlashTimer; void () FlashGrenadeExplode; void () ConcussionGrenadeTouch; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; +float IsFeigned(entity ent); void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce; @@ -510,7 +511,7 @@ void () ClassicConcussionGrenadeTimer = { pos = pointcontents(src); if ((self.owner.flags & 512) || (self.owner.flags & 16)) { - if (!self.owner.is_feigning && + if (!IsFeigned(self.owner) && !(FO_PlayerCurrentWeapon(self.owner) == WEAP_ASSAULT_CANNON && !cannon_conc && self.owner.button0)) { makevectors(self.owner.v_angle); @@ -1018,8 +1019,7 @@ entity(entity scanner, float scanrange, float enemies, (scanner.team_no > 0)) { if ((head.playerclass == 8) && (head.team_no != scanner.team_no)) { - if ((head.is_feigning != 1) && - (invis_only != 1)) { + if (!IsFeigned(head) && (invis_only != 1)) { if (head.undercover_team == scanner.team_no) { return (head); @@ -1033,8 +1033,7 @@ entity(entity scanner, float scanrange, float enemies, (scanner.team_no > 0)) { if ((head.playerclass == 8) && (head.team_no != scanner.team_no)) { - if ((head.is_feigning != 1) && - (invis_only != 1)) { + if (!IsFeigned(head) && (invis_only != 1)) { if (head.undercover_team != scanner.team_no) { return (head); diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 201151ec..78305792 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -28,7 +28,7 @@ void () lvl1_sentry_stand =[0, lvl1_sentry_stand] { void () lvl1_sentry_atk1 =[1, lvl1_sentry_atk3] { ai_face(); - if ((self.enemy == world) || self.enemy.is_feigning || + if ((self.enemy == world) || IsFeigned(self.enemy) || (self.enemy.health <= 0) || !visible(self.enemy) || (self.enemy.has_disconnected == 1)) @@ -57,13 +57,11 @@ void () lvl2_sentry_stand =[3, lvl2_sentry_stand] { void () lvl2_sentry_atk1 =[4, lvl2_sentry_atk2] { ai_face(); - if (((((self.enemy == world) || self.enemy.is_feigning) || + if (((((self.enemy == world) || IsFeigned(self.enemy)) || (self.enemy.health <= 0)) || !visible(self.enemy)) || - (self.enemy.has_disconnected == 1)) - + (self.enemy.has_disconnected == 1)) lvl2_sentry_stand(); - - else if (self.ammo_shells <= 0) +else if (self.ammo_shells <= 0) lvl2_sentry_stand(); else if (Sentry_Fire() == 0) lvl2_sentry_atk3(); @@ -88,7 +86,7 @@ void () lvl3_sentry_stand =[6, lvl3_sentry_stand] { void () lvl3_sentry_atk1 =[7, lvl3_sentry_atk2] { ai_face(); - if (((((self.enemy == world) || self.enemy.is_feigning) || + if (((((self.enemy == world) || IsFeigned(self.enemy)) || (self.enemy.health <= 0)) || !visible(self.enemy)) || (self.enemy.has_disconnected == 1)) @@ -138,7 +136,7 @@ float () Sentry_FindTarget = { (self.team_no != 0)) gotone = 0; } - if (client.is_feigning) + if (IsFeigned(client)) gotone = 0; if ((client.flags & FL_NOTARGET) || (client.items & IT_INVISIBILITY)) @@ -187,7 +185,7 @@ float (entity p) FO_Sentry_ValidTarget = { (self.team_no != 0)) valid = FALSE; } - if (p.is_feigning) + if (IsFeigned(p)) valid = FALSE; if ((p.flags & FL_NOTARGET) || (p.items & IT_INVISIBILITY)) @@ -397,10 +395,10 @@ float () Sentry_Fire = { if (((self.ideal_yaw - anglemod(self.angles_y)) < -10) || ((self.ideal_yaw - anglemod(self.angles_y)) > 10)) - return (0); + return 0; - if (self.enemy.is_feigning == 1) - return (0); + if (IsFeigned(self.enemy)) + return 0; if ((self.weapon == 3) && (self.ammo_rockets > 0) && (self.super_damage_finished < time)) { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 96c3dd00..f26e2205 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -5,6 +5,10 @@ void () T_TranqDartTouch; void () Spy_DropBackpack; void (entity targ, entity attacker) KillSound; +float IsFeigned(entity ent) { + return ent.tfstate & TFSTATE_FEIGNED; +} + anim_t anim_spy_diea1 = { 11, 1, {50}, {0}, FALSE, FALSE, TRUE }; void spy_dieaN() { client_anim_frames(spy_dieaN, think_nop, &anim_spy_diea1); } void spy_diea1() { *thinkindex() = 1; spy_dieaN(); } @@ -66,9 +70,9 @@ float (entity pe_player) Spy_CheckArea = { || at_spot.mdl == "progs/disp.mdl") return 1; else if (at_spot.classname == "player" && pe_player != at_spot) { - if (!at_spot.is_feigning && at_spot.deadflag == 0) + if (!IsFeigned(at_spot) && at_spot.deadflag == 0) return 2; - else if (at_spot.is_feigning) + else if (IsFeigned(at_spot)) return 3; } at_spot = at_spot.chain; @@ -78,7 +82,7 @@ float (entity pe_player) Spy_CheckArea = { void (entity pe_player, float dontstopdead) Spy_CheckForFuncTouch = { if (pe_player.classname == "player" && pe_player.playerclass == PC_SPY) { - if(pe_player.is_feigning) { + if (IsFeigned(pe_player)) { pe_player.velocity_x = 0; pe_player.velocity_y = 0; pe_player.movetype = MOVETYPE_TOSS; @@ -100,7 +104,7 @@ void () CF_Spy_AirThink = { return; } - if ((self.owner.playerclass != PC_SPY) || (!self.owner.is_feigning)) { + if ((self.owner.playerclass != PC_SPY) || (!IsFeigned(self.owner))) { dremove(self); return; } @@ -134,7 +138,7 @@ void () CF_Spy_AirThink = { }; void (float issilent) FO_Spy_ToggleFeign = { - if (self.is_feigning || self.feign_next_damage) { + if (IsFeigned(self) || self.feign_next_damage) { FO_Spy_Unfeign(); } else { FO_Spy_FeignOnNextDamage(); @@ -142,13 +146,12 @@ void (float issilent) FO_Spy_ToggleFeign = { } void (float issilent, float force) FO_Spy_Feign = { - if (self.is_feigning) { + if (IsFeigned(self)) return; - } if (!force && time <= self.next_feign_time) { sprint(self, PRINT_HIGH, sprintf( - "%0.1f seconds until you have enough fake-blood to feign again!\n", + "%0.1f seconds until you can feign again!\n", self.next_feign_time - time)); return; } @@ -187,7 +190,7 @@ void (float issilent, float force) FO_Spy_Feign = { spy.nextthink = time + 0.1; // set spy feign variables - self.is_feigning = 1; + self.tfstate |= TFSTATE_FEIGNED; self.is_button_feigning = 1; Attack_Finished(0.8); @@ -276,9 +279,8 @@ void () FO_Spy_Unfeign = { sprint(self, PRINT_HIGH, "Feign cancelled\n"); } - if (!self.is_feigning) { + if (!IsFeigned(self)) return; - } if (!self.is_button_feigning) { return; @@ -298,7 +300,7 @@ void () FO_Spy_Unfeign = { self.view_ofs = '0 0 22'; // unset feign variables - self.is_feigning = 0; + self.tfstate &= ~TFSTATE_FEIGNED; self.is_button_feigning = 0; self.feign_areachecked = 0; @@ -325,7 +327,7 @@ void () FO_Spy_Unfeign = { } void (float issilent) FO_Spy_FeignCmd = { - if (self.is_feigning) + if (IsFeigned(self)) FO_Spy_Unfeign(); else FO_Spy_Feign(issilent, 0); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c5215d07..1192be16 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1237,7 +1237,6 @@ void () TeamFortress_SetEquipment = { self.is_detpacking = 0; self.airblast_cooldown = 0; self.is_undercover = 0; - self.is_feigning = 0; self.next_feign_time = 0; self.is_unabletospy = 0; self.disguise_skin = 0; @@ -1255,7 +1254,7 @@ void () TeamFortress_SetEquipment = { self.maxarmor = 0; self.respawn_time = 0; self.heat = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RELOADING); + self.tfstate &= (TFSTATE_RELOADING | TFSTATE_FEIGNED); if (self.team_no == 0) self.lives = -1; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index c04d2b6e..67dd632c 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2087,7 +2087,7 @@ void () item_tfgoal_touch = { return; if (cb_prematch) return; - if (other.is_feigning) + if (IsFeigned(other)) return; if (other == self.owner) return; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 4f33d123..5a7c13fa 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1942,7 +1942,7 @@ void () ImpulseCommands = { if ((self.last_impulse == TF_DETPACK) && self.impulse) TeamFortress_SetDetpack(self.impulse); - if (!self.is_feigning) { + if (!IsFeigned(self)) { if (self.impulse == TF_GRENADE_1) TeamFortress_PrimeGrenade(1, TRUE); else if (self.impulse == TF_GRENADE_2) @@ -2497,7 +2497,7 @@ void () W_WeaponFrame = { return; } - if ((self.is_feigning) && + if (IsFeigned(self) && (self.impulse != TF_SPECIAL_SKILL) && (self.impulse != TF_SPECIAL_SKILL_2) && (self.impulse != TF_MEDIC_HELPME) && From 4d41ca5b34064582d493ed4dc0f3f3d3df01fc21 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 16:05:12 -0700 Subject: [PATCH 2214/2474] hwguy: remove cannon_conc toggle A legacy option allowed concing a hwguy to be disabled. While it would be a beautiful troll to play with this set, just remove it to simplify the implementation of client-side concs. --- ssqc/client.qc | 5 ----- ssqc/qw.qc | 1 - ssqc/scout.qc | 32 ++++++++++++++------------------ ssqc/tfort.qc | 1 - 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 294cd325..e5bc03bf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -499,9 +499,6 @@ void () DecodeLevelParms = { cannon_move = TRUE; // required for this to work } - // make hwguy susceptible to concussion grenade while firing assault cannon [on] - cannon_conc = CF_GetSetting("cc", "cannon_conc", "on"); - // assault cannon accuracy (0 = cf, 1 = tf 2.8, 2 = tf 2.9) [0] cannon_accuracy = CF_GetSetting("cac", "cannon_accuracy", "0"); @@ -840,7 +837,6 @@ void () DecodeLevelParms = { cannon_air = TRUE; cannon_move = TRUE; cannon_movespin = FALSE; - cannon_conc = TRUE; cannon_accuracy = 0; flame_knockback = TRUE; old_spanner = FALSE; @@ -909,7 +905,6 @@ void () DecodeLevelParms = { cannon_air = TRUE; cannon_move = TRUE; cannon_movespin = TRUE; - cannon_conc = TRUE; cannon_accuracy = 1; flame_knockback = FALSE; old_spanner = TRUE; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index adac4f5e..f09b2e5e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -570,7 +570,6 @@ float cannon_lock; float cannon_air; float cannon_move; float cannon_movespin; -float cannon_conc; float cannon_accuracy; float feign_air; float feign_pack; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index e9baa688..f37c0a7d 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -510,24 +510,20 @@ void () ClassicConcussionGrenadeTimer = { src_z = self.owner.origin_z; pos = pointcontents(src); - if ((self.owner.flags & 512) || (self.owner.flags & 16)) { - if (!IsFeigned(self.owner) && - !(FO_PlayerCurrentWeapon(self.owner) == WEAP_ASSAULT_CANNON && - !cannon_conc && self.owner.button0)) { - makevectors(self.owner.v_angle); - stumble = crandom() * self.health; - if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { - if ((crandom() < 0)) { - self.owner.velocity_x = - self.owner.velocity_y + stumble; - self.owner.velocity_y = - self.owner.velocity_x + stumble; - } else { - self.owner.velocity_x = - -1 * self.owner.velocity_y + stumble; - self.owner.velocity_y = - -1 * self.owner.velocity_x + stumble; - } + if ((self.owner.flags & (FL_INWATER | FL_ONGROUND)) && !IsFeigned(self.owner)) { + makevectors(self.owner.v_angle); + stumble = crandom() * self.health; + if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { + if ((crandom() < 0)) { + self.owner.velocity_x = + self.owner.velocity_y + stumble; + self.owner.velocity_y = + self.owner.velocity_x + stumble; + } else { + self.owner.velocity_x = + -1 * self.owner.velocity_y + stumble; + self.owner.velocity_y = + -1 * self.owner.velocity_x + stumble; } } } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 1192be16..4a01987c 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -674,7 +674,6 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Allow Assault Cannon while moving", cannon_move, "", 1); } CF_PrintSetting("Spin Assault Cannon while moving", cannon_movespin, "", 1); - CF_PrintSetting("Allow Assault Cannon concussion", cannon_conc, "", 1); if (cannon_movespin == 0) { sprint(self, PRINT_HIGH, "Assault Cannon accuracy: CF style\n"); } else if (cannon_movespin == 1) { From 6765e85ff8120974e7ffbbd9f3f0d9c1065e158d Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 30 Sep 2023 11:15:11 -0700 Subject: [PATCH 2215/2474] pmove: no longer need to set smartjump --- csqc/pmove.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 72f1d8da..b83c5a1c 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -33,7 +33,6 @@ struct { } pm; void PM_PmCmd(float arg) { - localcmd(sprintf("cl_smartjump %d\n", (arg & 1) ? 0 : 1)); sendevent("PmCmd", "f", arg); } From 33db20b9f45be5815fb9a68784dec05157ffaa6b Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 30 Sep 2023 17:09:54 -0700 Subject: [PATCH 2216/2474] pmove: track interpolated time in pmove --- csqc/pmove.qc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index b83c5a1c..2c5e47fb 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -4,7 +4,7 @@ static float pm_enabled; inline float PM_Enabled() { return pm_enabled; } #define ERRORTIME 0.05 -#define STEPTIME 8 +#define STEPTIME 0.125 enumflags { PMF_JUMP_HELD, @@ -18,11 +18,13 @@ enumflags { struct PMS_Data { vector org, vel; float seq; + float interp_t; } pm_s, pm_so, pm_c; struct { entity ent; float seq; + float interp_t; vector error; float errortime; @@ -189,7 +191,9 @@ static inline void PM_SavePMS(PMS_Data *pms) { entity ent = pm.ent; pms->org = ent.origin; pms->vel = ent.velocity; + pms->seq = pm.seq; + pms->interp_t = pm.interp_t; } static inline void PM_ActivatePMS(PMS_Data *pms) { @@ -197,6 +201,7 @@ static inline void PM_ActivatePMS(PMS_Data *pms) { ent.origin = pms->org; ent.velocity = pms->vel; pm.seq = pms->seq; + pm.interp_t = pms->interp_t; }; void PM_InputFrame(); @@ -243,6 +248,7 @@ static void PM_RunMovement(float endframe) { runstandardplayerphysics(ent); pm.seq++; + pm.interp_t += input_timelength; } // Add in anything that was applied after (for low packet rate protocols) @@ -257,8 +263,7 @@ static void PM_SetEnabled(float enabled) { if (!enabled) return; - pm.errortime = 0; - pm.steptime = 0; + pm.errortime = pm.steptime = 0; pm.step_oldz = pm.ent.origin_z; } @@ -305,13 +310,13 @@ static void PM_UpdateLocalMovement() { if (org_z > pm.step_oldz + 8 && org_z < pm.step_oldz + 24 && ent.velocity_z == 0) { // Evaluate out the remaining old step if (pm.steptime - time > 0) - pm.step = (pm.steptime - time) * STEPTIME * pm.step; + pm.step = (pm.steptime - time) * (1 / STEPTIME) * pm.step; else pm.step = 0; // Work out the new step pm.step += (pm.step_oldz - org_z); - pm.steptime = time + 1 / STEPTIME; + pm.steptime = time + STEPTIME; } pm.step_oldz = org_z; @@ -371,6 +376,7 @@ void PM_Update(float sendflags) { pm_so = pm_s; pm.seq = servercommandframe + 1; // server state includes move + pm.interp_t = time; PM_SavePMS(&pm_s); // Pre-compute predicted movement for all locked frames (e.g. seq < From 72ba6f1ea3e1e9201cef2ea6b663b8d3a6e4f457 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 2 Oct 2023 01:18:13 -0700 Subject: [PATCH 2217/2474] wp: refinements to wp loop --- csqc/weapon_predict.qc | 36 +++++++++++++++++++----------------- share/prediction.qc | 9 +-------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 3e6a3349..8776cc0d 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -10,7 +10,6 @@ DEFCVAR_FLOAT(wpp_min_ping, -1); DEFCVAR_FLOAT(wpp_adv_selfp_ms, 0); DEFCVAR_FLOAT(wpp_adv_otherp_ms, 0); -DEFCVAR_FLOAT(wpp_setspeed, 1); DEFCVAR_FLOAT(r_drawviewmodel, 1); DEFCVAR_FLOAT(fo_reloadalpha, 0); @@ -109,12 +108,6 @@ float interp_time() { return last_interp_time; } -// The server time of the current predicted clientcomandframe -inline float cpredict_time() { - return time + pstate_pred.client_time - pstate_server.client_time; -} - - #define csqc_print(...) \ do { if (CVARF(wpp_debug) & 4) { \ print("CSQC: ", __VA_ARGS__); \ @@ -586,6 +579,8 @@ void PredProj_Sound(int proj_type, float vol = 1) { void PM_Update(float sendflags); void WP_ServerUpdate(float sendflags) { + pstate_server.seq = servercommandframe; + // Force WF to zero, in case we missed a packet. if (pstate_server.attack_finished < pstate_server.client_time) pstate_server.weaponframe = 0; @@ -1408,7 +1403,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.owner = pengine.player_ent; FPP_Init(fpp_type, proj); - float ms_ahead = server_time_ms(); + float ms_ahead = pstate_server.client_ping; ProjectResult push_t = Forward_ProjectOffset(fpp_type, ms_ahead); float uncorrected_dt = max(ms_ahead - push_t.dynamic_ms, 0) / 1000.0; @@ -1722,8 +1717,16 @@ void WP_Attack() { void PredProjectile_DebugMatch(entity cprj, entity sprj) { + static float S = 0, N = 0; + + S += vlen(cprj.origin - sprj.origin); N++; + if (N > 1000) { + S /= 1000; + N /= 1000; + } + string sgn = - vlen(cprj.origin - PM_Org()) > vlen(sprj.origin- PM_Org()) ? "+" : "-"; + vlen(cprj.origin - PM_Org()) > vlen(sprj.origin - PM_Org()) ? "+" : "-"; string s = sprintf(" p_diff: %s%-2.1f [%0.3f] ", sgn, vlen(cprj.origin - sprj.origin), @@ -1732,9 +1735,9 @@ void PredProjectile_DebugMatch(entity cprj, entity sprj) { time, cprj.phys_time, sprj.phys_time, sprj.phys_time - cprj.phys_time)); - s = strcat(s, sprintf(" [c=%d s=%d] al=%d\n", + s = strcat(s, sprintf(" [c=%d s=%d] err=%0.3f al=%d\n", vlen(cprj.origin - PM_Org()), vlen(sprj.origin - PM_Org()), - self.antilag_ms)); + S/N, self.antilag_ms)); print(s); } @@ -1752,7 +1755,7 @@ float PredProjectile_MatchProjectile() { if (time > proj.endtime - 0.01) break; // Projectile list is time ordered - Phys_Advance(proj, get_phys_time(proj), PHYSF_CONSUME_ALL); + Phys_Advance(proj, get_phys_time(self), PHYSF_CONSUME_ALL); float d = vlen(proj.origin - self.origin); if (!best || d < best) { @@ -1799,7 +1802,7 @@ void InitProjectileEnt(float sendflags) { float ptime = get_phys_time(self); if (ptime > self.phys_time /* from server */) - Phys_Advance(self, ptime, 0); + Phys_Advance(self, ptime, PHYSF_CONSUME_ALL); else setorigin(self, self.origin); @@ -1980,8 +1983,6 @@ static void WP_UpdatePredict() { int eframe = clientcommandframe - 1; int effect_frame = clientcommandframe - 1; - pstate_server.seq = servercommandframe; - pstate_server.server_time = time; for(; pframe <= eframe; pframe++) { old_input_buttons = input_buttons; if (!getinputstate(pframe) || input_timelength <= 0) @@ -1989,6 +1990,9 @@ static void WP_UpdatePredict() { makevectors(input_angles); pstate_pred.seq = pframe; + pstate_pred.client_time += input_timelength; + pstate_pred.server_time += input_timelength; + pstate_pred.buttons_held = input_buttons; pstate_pred.buttons_up = old_input_buttons & (~input_buttons); pstate_pred.buttons_down = (~old_input_buttons) & input_buttons; @@ -2001,8 +2005,6 @@ static void WP_UpdatePredict() { pengine.is_effectframe = FALSE; } - pstate_pred.client_time += input_timelength; - pstate_pred.server_time += input_timelength; if (input_impulse) pstate_pred.impulse = input_impulse; diff --git a/share/prediction.qc b/share/prediction.qc index a94ed9b5..5e075a34 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -967,19 +967,12 @@ ProjectResult Forward_ProjectOffset(int fpp_type, float ping) { if (IsClownMode(CLOWN_FAST_PROJECTILES) && !FPP_IsGrenade(fpp_type)) static_credit = 9999; - float frame_nudge = 0; -#ifdef CSQC - // Account for the fact that the server usually has a physics frame that's - // going to be credited to the new projectile. - if (!fo_config.qc_physics) - frame_nudge = SERVER_FRAME_MS * 1.5; -#endif // Everything lower than SERVER_FRAME_MS falls into the next frame (and we // have no resolution anyway), linearize beyond that. float adj_ping = max(ping - SERVER_FRAME_MS, 0); ProjectResult result; - result.static_ms = static_credit + frame_nudge; + result.static_ms = static_credit; result.dynamic_ms = min(adj_ping, max_ping_credit); return result; } From eddf7f631cdd8508e443fd88c68f43fb7c57cec9 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 2 Oct 2023 03:23:56 -0700 Subject: [PATCH 2218/2474] pmove: always enable jump predict with pmove pmove jump prediction is accurate enough to never not want it --- csqc/pmove.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 2c5e47fb..be165433 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -42,7 +42,11 @@ vector PM_Org() { return PM_Enabled() ? pm.ent.origin : pmove_org; } vector PM_Vel() { return PM_Enabled() ? pm.ent.velocity : pmove_vel; } inline entity PM_Ent() { return pm.ent; } -inline float CSQC_JumpSounds_Active() { return CVARF(fo_csjumpsounds); } +float CSQC_JumpSounds_Active() { + if (PM_Enabled()) + return TRUE; // PM sounds are accurate. + return CVARF(fo_csjumpsounds); +} // Sets *type to whatever is at the feet of `point`. static float PM_GetWaterLevel(vector point, float* type) { From a43df7cd3be1d377cab316f028bda85ff9a6bd9a Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Sep 2023 15:37:09 -0700 Subject: [PATCH 2219/2474] pmove: predict concussion effect Full client side prediction of concussion effect (e.g. concussion at 200 ping feels like concussion at 13 ping). --- csqc/pmove.qc | 74 +++++++++++++++++++++- csqc/weapon_predict.qc | 1 + share/animate.qc | 12 ++-- share/classes.qc | 64 +++++++++++++++++++ share/commondefs.qc | 6 ++ share/defs.h | 1 + share/prediction.qc | 24 ++++++- ssqc/client.qc | 7 ++- ssqc/scout.qc | 139 ++++++++++++++--------------------------- 9 files changed, 219 insertions(+), 109 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index be165433..8198811d 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -169,6 +169,7 @@ DEFCVAR_FLOAT(fo_smartjump, 1); DEFCVAR_FLOAT(fopm_noerror, 0); DEFCVAR_FLOAT(fopm_nocache, 0); DEFCVAR_FLOAT(fopm_nostep, 0); +DEFCVAR_FLOAT(fopm_nonudge, 0); DEFCVAR_FLOAT(fopmd_graph_x, -10); DEFCVAR_FLOAT(fopmd_graph_y, 100); @@ -210,6 +211,53 @@ static inline void PM_ActivatePMS(PMS_Data *pms) { void PM_InputFrame(); +enum { + NT_CONC, +}; + +struct PM_Nudge { + float itime, type; + vector nudge; +}; + +static PM_Nudge nudges[10]; +static float num_nudges; + +void PM_AddConcNudge(float itime, float mag, float flip) { + // This is kind of painful but not much easier.. + static float filter_itime; + if (itime <= filter_itime) + return; + filter_itime = itime; + + PM_Nudge* n = &nudges[(num_nudges++) % nudges.length]; + + n->type = NT_CONC; + n->itime = itime; + n->nudge.x = mag; + n->nudge.y = flip; +} + +static void PM_NudgeConc(PM_Nudge* nudge, entity ent) { + if (pointcontents(ent.origin) == CONTENT_WATER) + ent.flags |= FL_INWATER; // pmove doesn't usually maintain this. + Conc_Stumble(ent, nudge->nudge.x, nudge->nudge.y); +} + +// TODO: This obviously wants to be smarter +static void PM_ApplyNudges(entity ent, float sitime, float eitime) { + for (float i = 0; i < nudges.length; i++) { + PM_Nudge* n = &nudges[i]; + if (n->itime >= sitime && n->itime < eitime) { + switch (n->type) { + case NT_CONC: + PM_NudgeConc(n, ent); + break; + } + } + } +} + static void PM_RunMovement(float endframe) { entity ent = pm.ent; if (servercommandframe >= pm_s.seq + 63) { @@ -248,6 +296,9 @@ static void PM_RunMovement(float endframe) { if (pm.seq == clientcommandframe) PM_InputFrame(); + if (!CVARF(fopm_nonudge)) + PM_ApplyNudges(ent, pm.interp_t, pm.interp_t + input_timelength); + pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing runstandardplayerphysics(ent); @@ -257,7 +308,7 @@ static void PM_RunMovement(float endframe) { // Add in anything that was applied after (for low packet rate protocols) input_angles = view_angles; -}; +} static void PM_SetEnabled(float enabled) { pm_enabled = enabled; @@ -305,7 +356,6 @@ static void PM_UpdateError() { static void PM_UpdateLocalMovement() { entity ent = pm.ent; - /* PM_ActivatePMS(&pm_c); */ PM_RunMovement(clientcommandframe); vector org = pm.ent.origin; @@ -380,7 +430,7 @@ void PM_Update(float sendflags) { pm_so = pm_s; pm.seq = servercommandframe + 1; // server state includes move - pm.interp_t = time; + pm.interp_t = pstate_server.server_time; PM_SavePMS(&pm_s); // Pre-compute predicted movement for all locked frames (e.g. seq < @@ -535,6 +585,24 @@ static void PMD_UpdateImpulse(int seq) { if (!vlen(pv) && !vlen(sv)) return; +#if 0 + static vector last_sv, last_pv; + float p = FALSE; + if (vlen(sv - last_sv) > 200) { + printf("[%0.3f] S sf=%d st=%0.3f i=%0.3f\n", time, servercommandframe, pm_s.interp_t, vlen(sv-last_sv)); + p = TRUE; + } + last_sv = sv; + + if (vlen(pv - last_pv) > 200) { + printf("[%0.3f] C cf=%d ct=%0.3f i=%0.3f\n", time, clientcommandframe, + pm.interp_t, vlen(pv-last_pv)); + p = TRUE; + } + last_pv = pv; + if (p) printf("\n"); +#endif + PMD_AddPoint(SERVER, vlen(sv)); PMD_AddPoint(PMOVE, vlen(pv)); PMD_AddPoint(VIEW, vlen(pm.error) / 128 * 1200); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 8776cc0d..0d5d3bc0 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -2001,6 +2001,7 @@ static void WP_UpdatePredict() { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; PM_SyncTo(pframe); + Conc_Update(&pstate_pred.conc_state, world, pstate_pred.server_time); } else { pengine.is_effectframe = FALSE; } diff --git a/share/animate.qc b/share/animate.qc index a05ec931..466ba598 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -29,7 +29,6 @@ void player_asscan_fire(); void player_asscan_down1(); inline void *thinkindex() { return &self.client_thinkindex; } -static inline float *tf_state() { return &self.tfstate; } static inline float is_attacking() { return self.button0; } static inline float is_intermission() { return intermission_running; } static inline vector get_velocity() { return self.velocity; } @@ -149,7 +148,6 @@ void player_stand1() { }; #else /* CSQC */ static inline void *thinkindex() { return &pstate_pred.client_thinkindex; } -static inline float *tf_state() { return &pstate_pred.tfstate; } static inline float is_attacking() { return input_buttons & BUTTON0; } static inline float is_intermission() { return intermission; } static void SuperDamageSound() {} // TODO @@ -239,7 +237,7 @@ static float CheckNeedAssaultCannonDown() { void asscan_up_extra() { float tidx = *thinkindex() - 1; // Already incremented. - *tf_state() = (*tf_state() & ~TFSTATE_AC_MASK) | + *self_tf_state() = (*self_tf_state() & ~TFSTATE_AC_MASK) | (TFSTATE_AC_SPINUP | TFSTATE_AIMING); if (CheckNeedAssaultCannonDown()) @@ -259,7 +257,7 @@ void asscan_up_extra() { void W_FireAssaultCannon(); void asscan_fire_extra() { float tidx = *thinkindex() - 1; // Already incremented. - *tf_state() = (*tf_state() & ~TFSTATE_AC_MASK) | + *self_tf_state() = (*self_tf_state() & ~TFSTATE_AC_MASK) | (TFSTATE_AC_SPINNING | TFSTATE_AIMING); if (CheckNeedAssaultCannonDown()) @@ -267,7 +265,7 @@ void asscan_fire_extra() { FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - if (vlen(get_velocity()) <= 90 && !(*tf_state () & TFSTATE_LOCK)) { + if (vlen(get_velocity()) <= 90 && !(*self_tf_state () & TFSTATE_LOCK)) { if (tidx % 2 == 1) { // 1-based muzzleflash(); Pred_Sound(SND_ASSCAN_FIRE); @@ -289,14 +287,14 @@ void asscan_fire_extra() { void asscan_down_extra() { float tidx = *thinkindex() - 1; // Already incremented. FO_WeapInfo* wi = FO_GetWeapInfo(WEAP_ASSAULT_CANNON); - *tf_state() = (*tf_state() & ~TFSTATE_AC_MASK) | + *self_tf_state() = (*self_tf_state() & ~TFSTATE_AC_MASK) | TFSTATE_AIMING | TFSTATE_AC_SPINDOWN; if (tidx == 1) Pred_Sound(SND_ASSCAN_DOWN, 0.8); if (tidx >= 15) { // 1.5s down - *tf_state() &= ~(TFSTATE_AC_MASK | TFSTATE_AIMING); + *self_tf_state() &= ~(TFSTATE_AC_MASK | TFSTATE_AIMING); player_run(); if (self.ammo_cells < 7 || !FO_CheckForReload()) W_ChangeToBestWeapon(); diff --git a/share/classes.qc b/share/classes.qc index 89ea4d50..1d651b99 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -94,3 +94,67 @@ float Class_MaxSpeed(float playerclass) { default: return 0; } } + +static float NextToWall(entity ent) { + if ((pointcontents(ent.origin + [ent.maxs_x + 2, 0, 0]) == CONTENT_SOLID) || + (pointcontents(ent.origin + [ent.mins_x - 2, 0, 0]) == CONTENT_SOLID) || + (pointcontents(ent.origin + [0, ent.maxs_y + 2, 0]) == CONTENT_SOLID) || + (pointcontents(ent.origin + [0, ent.mins_y - 2, 0]) == CONTENT_SOLID)) + return TRUE; + return FALSE; +} + +const float CONC_P = 0.25; +const float CONC_HZ = 1/CONC_P; + +void Conc_Stumble(entity ent, float imp, float flip) { + if ((ent.flags & (FL_INWATER | FL_ONGROUND) == 0) || + (*self_tf_state() & TFSTATE_FEIGNED)) + return; + + if (NextToWall(ent) && ent.velocity == '0 0 0') + return; + + ent.velocity = [flip * ent.velocity_y + imp, flip * ent.velocity_x + imp, + ent.velocity_z]; +} + +#ifdef SSQC +void SpawnBubble(vector origin); +static inline void ConcAction(entity ent, float itime, float mag, float flip) { + Conc_Stumble(ent, mag, flip); +} +#else +void PM_AddConcNudge(float itime, float mag, float flip); + +static inline void ConcAction(entity ent, float itime, float mag, float flip) { + PM_AddConcNudge(itime, mag, flip); +} +#endif + +void Conc_Update(ConcState *cs, entity ent, float ctime) { + if (!cs->mag || ctime < cs->next) + return; + + while (ctime >= cs->next) { + cs->mag = max(cs->mag - 1, 0); + if (!cs->mag) { + *self_tf_state() &= ~TFSTATE_CONC; + break; + } + + float mag = shared_crandom(PRNG_CONC) * cs->mag * 10; + float flip = (shared_prng(PRNG_CONC) < 0.5) ? -1 : 1; + ConcAction(ent, cs->next, mag, flip); + cs->next += CONC_P; + } + +#ifdef SSQC + if (cs->mag) { + if (cs->mag % CONC_HZ == 0) + SpawnBubble(ent.origin); + } else { + sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); + } +#endif +} diff --git a/share/commondefs.qc b/share/commondefs.qc index 2aa65bfe..170a830e 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -16,6 +16,12 @@ struct FPPState { .FPPState fpp; +struct ConcState { + float next, mag; +}; +.ConcState conc_state; + + enumflags { FPF_NO_REWIND, FPF_FIXED_DYNAMIC, diff --git a/share/defs.h b/share/defs.h index d6d4e996..01baa576 100644 --- a/share/defs.h +++ b/share/defs.h @@ -283,6 +283,7 @@ enumflags { enum { PRNG_WEAP, PRNG_HWGUY, + PRNG_CONC, PRNG_NUM_STATES, }; diff --git a/share/prediction.qc b/share/prediction.qc index 5e075a34..7bdff8f6 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -14,6 +14,7 @@ enumflags { FOWP_IMPULSE, FOWP_TFSTATE, FOWP_LASTPRIME, + FOWP_CLASSIC_CONC, FOWP_CONCFINISH, FOWP_CLIP, FOWP_GREN, @@ -24,6 +25,7 @@ enumflags { FOWP_RELOAD, FOWP_RNG0, FOWP_RNG1, + FOWP_RNG2, FOWP_PREDICT_FLAGS, FOWP_LAST, }; @@ -58,6 +60,8 @@ struct predict_tf_state { int impulse; Slot current_slot, queue_slot, last_slot; + ConcState conc_state; + float tfstate; float last_prime; float csqc_maxspeed; @@ -65,7 +69,7 @@ struct predict_tf_state { float conc_amp; float conc_finished; - float client_time; + float client_time, server_time; float client_ping; float weaponframe; @@ -85,7 +89,6 @@ struct predict_tf_state { int seq; float ammo_used[AMMO_NUM_TYPES]; float buttons_down, buttons_up, buttons_held; - float server_time; #endif }; @@ -305,9 +308,14 @@ float FO_MaxRewindGrenWinDt() { .predict_tf_state predict_state; .entity predict_entity; +inline float *self_tf_state() { return &self.tfstate; } + #else predict_tf_state pstate_pred, pstate_server; + +inline float *self_tf_state() { return &pstate_pred.tfstate; } + #define MASK_PRED_ENT 256 #define MASK_PRED_PROJECTILE 512 #define MASK_OUTLINE 1024 @@ -337,6 +345,7 @@ static float Prediction_ChangedMask(entity player, entity src) { float mask = FOWP_CTIME; + player.predict_state.server_time = time; player.predict_state.client_time = src.client_time; player.predict_state.client_ping = src.client_ping; @@ -347,6 +356,7 @@ static float Prediction_ChangedMask(entity player, entity src) { M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); M2(FOWP_TFSTATE, tfstate, csqc_maxspeed); M1(FOWP_LASTPRIME, last_prime); + M2(FOWP_CLASSIC_CONC, conc_state.next, conc_state.mag); M2(FOWP_CONCFINISH, conc_finished, conc_amp); M1(FOWP_WF, weaponframe); M1(FOWP_AF, attack_finished); @@ -355,6 +365,7 @@ static float Prediction_ChangedMask(entity player, entity src) { M2(FOWP_RELOAD, reload_started, reload_finished); M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]); + M1(FOWP_RNG2, prng_base[PRNG_CONC]); M2(FOWP_PREDICT_FLAGS, predict_flags, effects); M4(FOWP_GREN, no_grenades_1, no_grenades_2, primed_gren_type, primed_gren_exp) @@ -477,6 +488,7 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_CTIME) { COMM(Float, client_time); + COMM(Float, server_time); COMM(Short, client_ping); } @@ -509,6 +521,11 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Float, last_prime); } + if (sendflags & FOWP_CLASSIC_CONC) { + COMM(Float, conc_state.next); + COMM(Byte, conc_state.mag); + } + if (sendflags & FOWP_CONCFINISH) { COMM(Byte, conc_amp); COMM(Float, conc_finished); @@ -543,6 +560,8 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Int, prng_base[PRNG_WEAP]); if (sendflags & FOWP_RNG1) COMM(Int, prng_base[PRNG_HWGUY]); + if (sendflags & FOWP_RNG2) + COMM(Int, prng_base[PRNG_CONC]); if (sendflags & FOWP_GREN) { COMM(Short, no_grenades_1); @@ -1013,4 +1032,3 @@ void AugmentGrenadeImpact() { self.SendFlags |= FOPP_MOVETYPE; #endif } - diff --git a/ssqc/client.qc b/ssqc/client.qc index e5bc03bf..ac4f030d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2052,14 +2052,14 @@ void () PutClientInServer = { self.display_tip = 0; self.tip_type = 0; self.feign_next_damage = 0; + self.conc_state.mag = 0; FO_InstantReloadAllWeapons(self); // Only need initial init here. - if (!self.prng_base[PRNG_WEAP]) - self.prng_base[PRNG_WEAP] = 65535 * random(); // For hwguy we rotate the seed value, each seed generates many random nums. - self.prng_base[PRNG_HWGUY] = 65535 * random(); + for (int i = 0; i < PRNG_NUM_STATES; i++) + self.prng_base[i] = 65535 * random(); self.primed_gren_exp = 0; self.immune_to_check = time + 10; @@ -2651,6 +2651,7 @@ void () CheckWaterJump = { void () PlayerPreThink = { FO_UpdateClientTime(); + Conc_Update(&self.conc_state, self, time); if (self.impulse) { if (self.impulse == TF_VOTENEXT) { diff --git a/ssqc/scout.qc b/ssqc/scout.qc index f37c0a7d..ea9645c9 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -19,14 +19,12 @@ void (entity inflictor, entity attacker, float bounce, entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; -void ClassicConcussionGrenadeTimer(); void OldConcussionGrenadeTimer(); void FoConcussionGrenadeTimer(); void ConcThink() { switch (GetConcMode()) { case CONC_IDLESCALE: return OldConcussionGrenadeTimer(); - case CONC_CLASSIC: return ClassicConcussionGrenadeTimer(); case CONC_AIM: return FoConcussionGrenadeTimer(); } } @@ -464,7 +462,7 @@ void () OldConcussionGrenadeTimer = { } }; -static void SpawnBubble(vector origin) { +void SpawnBubble(vector origin) { newmis = spawn(); FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, origin); @@ -480,60 +478,6 @@ static void SpawnBubble(vector origin) { setsize(newmis, '-8 -8 -8', '8 8 8'); } -void () ClassicConcussionGrenadeTimer = { - local vector src; - local float pos; - local float stumble; - - if (self.owner.invincible_finished > time) { - sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); - RemoveConc(self.owner, FALSE); - dremove(self); - return; - } - - if (self.health > 0 && self.health % 200 == 0) - SpawnBubble(self.owner.origin); - - self.health = self.health - 10; - if (self.owner.playerclass == PC_MEDIC) - self.health = self.health - 10; - - if (self.health < 0) - self.health = 0; - - self.nextthink = time + 0.25; - - pos = pointcontents(self.owner.origin); - src_x = self.owner.origin_x + self.owner.maxs_x + 2; - src_y = self.owner.origin_y + self.owner.maxs_y + 2; - src_z = self.owner.origin_z; - pos = pointcontents(src); - - if ((self.owner.flags & (FL_INWATER | FL_ONGROUND)) && !IsFeigned(self.owner)) { - makevectors(self.owner.v_angle); - stumble = crandom() * self.health; - if (!((pos == -2) && (self.owner.velocity == '0 0 0'))) { - if ((crandom() < 0)) { - self.owner.velocity_x = - self.owner.velocity_y + stumble; - self.owner.velocity_y = - self.owner.velocity_x + stumble; - } else { - self.owner.velocity_x = - -1 * self.owner.velocity_y + stumble; - self.owner.velocity_y = - -1 * self.owner.velocity_x + stumble; - } - } - } - if (self.health <= 0) { - sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); - RemoveConc(self.owner, FALSE); - dremove(self); - } -}; - void FoConcussionGrenadeTimer() { const float bubble_int = 1; float finished = self.owner.conc_finished; @@ -943,43 +887,52 @@ void (entity inflictor, entity attacker, float bounce, } head.tfstate |= TFSTATE_CONC; - if (fo_concuss) - UpdateClientConcussion(head, actual_cuss_time); - else // not used currently, but populate anyway - head.conc_finished = time + actual_cuss_time; - - entity te = FindConcTimer(head); - if (te != world) { - if (GetConcMode() == CONC_IDLESCALE) { - stuffcmd(head, "v_idlescale 100\n"); - stuffcmd(head, "fov 130\n"); - te.health = 100; - te.nextthink = time + 5; - } else { - te.health = 40 * cussgrentime; - te.nextthink = time + 0.25; - } - } else { - // LogEventAffliction(attacker, head, TFSTATE_CONCUSSED); - if (GetConcMode() == CONC_IDLESCALE) { - stuffcmd(head, "v_idlescale 100\n"); - stuffcmd(head, "fov 130\n"); - stuffcmd(head, "bf\n"); - te = spawn(); - te.nextthink = time + 5; - te.think = ConcThink; - te.team_no = attacker.team_no; - te.classname = "timer"; - te.owner = head; - te.health = 100; + + switch (GetConcMode()) { + case CONC_AIM: + UpdateClientConcussion(head, actual_cuss_time); + break; + case CONC_CLASSIC: + // Activate and/or extend + head.conc_state.next = time + CONC_P; + head.conc_state.mag = ceil(1/CONC_P) * actual_cuss_time; + break; + } + + if (GetConcMode() != CONC_CLASSIC) { + entity te = FindConcTimer(head); + if (te != world) { + if (GetConcMode() == CONC_IDLESCALE) { + stuffcmd(head, "v_idlescale 100\n"); + stuffcmd(head, "fov 130\n"); + te.health = 100; + te.nextthink = time + 5; + } else { + te.health = 40 * cussgrentime; + te.nextthink = time + 0.25; + } } else { - te = spawn(); - te.nextthink = time + 0.25; - te.think = ConcThink; - te.team_no = attacker.team_no; - te.classname = "timer"; - te.owner = head; - te.health = 40 * actual_cuss_time; + // LogEventAffliction(attacker, head, TFSTATE_CONCUSSED); + if (GetConcMode() == CONC_IDLESCALE) { + stuffcmd(head, "v_idlescale 100\n"); + stuffcmd(head, "fov 130\n"); + stuffcmd(head, "bf\n"); + te = spawn(); + te.nextthink = time + 5; + te.think = ConcThink; + te.team_no = attacker.team_no; + te.classname = "timer"; + te.owner = head; + te.health = 100; + } else { + te = spawn(); + te.nextthink = time + 0.25; + te.think = ConcThink; + te.team_no = attacker.team_no; + te.classname = "timer"; + te.owner = head; + te.health = 40 * actual_cuss_time; + } } } } From 95c5773bc4af16ba949ad0d3e4d16d0e0d646974 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 2 Oct 2023 02:51:06 -0700 Subject: [PATCH 2220/2474] pmove: add prediction for scout dash Still needs a little bit of tuning with physics ordering on gravity; but already feels much better. --- csqc/events.qc | 7 +++++-- csqc/pmove.qc | 21 +++++++++++++++++++-- csqc/weapon_predict.qc | 32 ++++++++++++++++++++++++++++++++ share/prediction.qc | 7 +++++++ ssqc/client.qc | 2 +- ssqc/pyro.qc | 4 ++-- ssqc/qw.qc | 3 +-- ssqc/scout.qc | 12 ++++++------ 8 files changed, 73 insertions(+), 15 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 5bb00d0c..b6d4a781 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -629,6 +629,10 @@ float(float ent_num, float channel, string soundname, float vol, float attenuati // Sounds below this line are conditionally filtered. switch(soundname) { + case "dash.wav": + if (PM_Enabled() & !CVARF(fopm_nonudge)) + return 1; + break; case "player/plyrjmp8.wav": case "player/land.wav": case "player/land2.wav": @@ -641,8 +645,7 @@ float(float ent_num, float channel, string soundname, float vol, float attenuati case "misc/outwater.wav": if (CSQC_JumpSounds_Active()) return 1; - else - break; + break; } return 0; diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 8198811d..a5d2e353 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -213,6 +213,7 @@ void PM_InputFrame(); enum { NT_CONC, + NT_DASH, }; struct PM_Nudge { @@ -244,6 +245,19 @@ static void PM_NudgeConc(PM_Nudge* nudge, entity ent) { Conc_Stumble(ent, nudge->nudge.x, nudge->nudge.y); } +static void PM_NudgeDash(PM_Nudge* nudge, entity ent) { + ent.velocity = nudge->nudge; +} + +void PM_AddDashNudge(float itime) { + PM_Nudge* n = &nudges[(num_nudges++) % nudges.length]; + n->type = NT_DASH; + n->itime = itime; + + n->nudge = v_forward * 540; + n->nudge.z = 181 + SERVER_FRAME_DT * 800; // TODO: fix this... +} + // TODO: This obviously wants to be smarter static void PM_ApplyNudges(entity ent, float sitime, float eitime) { for (float i = 0; i < nudges.length; i++) { @@ -253,6 +267,9 @@ static void PM_ApplyNudges(entity ent, float sitime, float eitime) { case NT_CONC: PM_NudgeConc(n, ent); break; + case NT_DASH: + PM_NudgeDash(n, ent); + break; } } } @@ -296,10 +313,10 @@ static void PM_RunMovement(float endframe) { if (pm.seq == clientcommandframe) PM_InputFrame(); - if (!CVARF(fopm_nonudge)) + pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing + if (!CVARF(fopm_nonudge) && pm.seq < clientcommandframe) PM_ApplyNudges(ent, pm.interp_t, pm.interp_t + input_timelength); - pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing runstandardplayerphysics(ent); pm.seq++; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 0d5d3bc0..df5fca48 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -891,6 +891,30 @@ void WP_HandleGrenadeInputs() { pstate_pred.impulse = 0; } +float PM_Enabled(); +void PM_AddDashNudge(float itime); + +static void WP_Special() { + if (pstate_pred.server_time < pstate_pred.special_next) + return; + + float cooldown = 0; + switch (WP_PlayerClass()) { + case PC_SCOUT: + cooldown = 1; + if (PM_Enabled() && IsEffectFrame()) { + // Want to land in this frame + PM_AddDashNudge(pstate_pred.server_time - 1 * MSEC); + localsound("dash.wav", CHAN_BODY, 1); + } + break; + // Note: hwguy handled by WP_HandleHeavyInputs + } + + if (cooldown) + pstate_pred.special_next = pstate_pred.server_time + cooldown; +} + void WP_Impulse() { float local_impulse; @@ -904,6 +928,11 @@ void WP_Impulse() { WPP_Dump(); break; + case TF_SPECIAL_SKILL: + case TF_DASH: // This could use a clean-up server side + WP_Special(); + break; + case TF_SLOT1: case TF_SLOT2: case TF_SLOT3: case TF_SLOT4: case 1: case 2: case 3: case 4: case 5: case 6: case 7: { Slot slot = FO_SlotByInput(pstate_pred.playerclass, local_impulse); @@ -939,6 +968,9 @@ void WP_Impulse() { break; } + if (input_buttons & BUTTON3) + WP_Special(); + // Impulses below this line depend on ready weapon. if (!WP_WeaponReady()) return; diff --git a/share/prediction.qc b/share/prediction.qc index 7bdff8f6..520d5716 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -23,6 +23,7 @@ enumflags { FOWP_AF, FOWP_CLASS, FOWP_RELOAD, + FOWP_SPECIAL, FOWP_RNG0, FOWP_RNG1, FOWP_RNG2, @@ -68,6 +69,7 @@ struct predict_tf_state { float conc_amp; float conc_finished; + float special_next; float client_time, server_time; float client_ping; @@ -363,6 +365,7 @@ static float Prediction_ChangedMask(entity player, entity src) { M2(FOWP_THINK, client_nextthink, client_thinkindex); M4(FOWP_CLIP, clip_fired[0], clip_fired[1], clip_fired[2], clip_fired[3]); M2(FOWP_RELOAD, reload_started, reload_finished); + M1(FOWP_SPECIAL, special_next); M1(FOWP_RNG0, prng_base[PRNG_WEAP]); M1(FOWP_RNG1, prng_base[PRNG_HWGUY]); M1(FOWP_RNG2, prng_base[PRNG_CONC]); @@ -556,6 +559,10 @@ void EntUpdate_WeaponPred(float isnew) { COMM(Float, reload_finished); } + if (sendflags & FOWP_SPECIAL) { + COMM(Float, special_next); + } + if (sendflags & FOWP_RNG0) COMM(Int, prng_base[PRNG_WEAP]); if (sendflags & FOWP_RNG1) diff --git a/ssqc/client.qc b/ssqc/client.qc index ac4f030d..89d9583d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2064,7 +2064,7 @@ void () PutClientInServer = { self.immune_to_check = time + 10; SetDimensions(TRUE); - self.special_cooldown = 0; + self.special_next = 0; setmodel(self, string_null); modelindex_null = self.modelindex; diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index 7be18786..d6036f47 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -629,11 +629,11 @@ void FO_Airblast() = { return; } - if (time < self.special_cooldown) + if (time < self.special_next) return; self.airblast_cooldown = 1; - self.special_cooldown = time + PC_PYRO_AIRBLAST_COOLDOWN; + self.special_next = time + PC_PYRO_AIRBLAST_COOLDOWN; entity timer = spawn(); timer.owner = self; timer.classname = "timer"; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index f09b2e5e..544393c4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -98,7 +98,6 @@ float remote_client_time(); .float regen_time; // Time when the medic last regenerated cells .float regen_cooldown; // Time to cooldown cell regeneration after using medikit heal .float saveme_time; // Time when player issued /saveme command -.float dash_cooldown; // Cooldown for Scout dash .float undercover_timer; // Seconds left until disguised .float power_time; // The time when sniper power in status bar was last updated .float sentry_ticks; // Used to indicate when engineer's sentry gun is finished building @@ -791,7 +790,7 @@ string goal_class_names[7] = { .string broadcast_high; -.float special_cooldown; +.float special_next; .float airblast_cooldown; float disable_resup_gren; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index ea9645c9..8205ea70 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -62,14 +62,14 @@ void () CF_Scout_Dash = { return; // check if dash is allowed in rules and if cooldown has ended - if (!scoutdash || time < self.dash_cooldown) + if (!scoutdash || time < self.special_next) return; - self.dash_cooldown = time + 1; - makevectors(self.angles); - self.velocity = v_forward * 540; - self.velocity_z = 181; - FO_Sound(self, CHAN_BODY, "dash.wav", 1, ATTN_NORM); + self.special_next = time + 1; + makevectors(self.angles); + self.velocity = v_forward * 540; + self.velocity_z = 181; + FO_Sound(self, CHAN_BODY, "dash.wav", 1, ATTN_NORM); } void () CanisterTouch = From 1ac3ae93e0f672b6dbf1cc4f3a95c51b4bfb2059 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 2 Oct 2023 11:16:09 -0700 Subject: [PATCH 2221/2474] pmove: add persistent enable pmove can now be turned on with a persistent enable: `fo_pmove 0/1`. Also smoothes out how much the view bounces around during transitions. --- csqc/main.qc | 6 +-- csqc/pmove.qc | 27 +++++++++----- csqc/weapon_predict.qc | 9 +++++ share/commondefs.qc | 17 +-------- share/prediction.qc | 85 +++++++++++++++++++++++++++++++++++++----- ssqc/client.qc | 52 +------------------------- ssqc/spect.qc | 2 +- ssqc/tfort.qc | 16 ++++++-- 8 files changed, 120 insertions(+), 94 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 2b5e4d89..a4015737 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -266,12 +266,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { Slot_Keyup(stof(argv(1))); break; - case "fopm_cmd": - PM_PmCmd(stof(argv(1))); - break; - case "fo_beta_pmove": - PM_PmCmd(!!stof(argv(1))); + printf("Please set `fo_pmove 1` instead.\n"); break; case "login": diff --git a/csqc/pmove.qc b/csqc/pmove.qc index a5d2e353..d33f870e 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -34,10 +34,6 @@ struct { vector vieworg; } pm; -void PM_PmCmd(float arg) { - sendevent("PmCmd", "f", arg); -} - vector PM_Org() { return PM_Enabled() ? pm.ent.origin : pmove_org; } vector PM_Vel() { return PM_Enabled() ? pm.ent.velocity : pmove_vel; } inline entity PM_Ent() { return pm.ent; } @@ -160,7 +156,7 @@ void PM_PredictJump_Engine() { enum { SERVER, PMOVE, - VIEW, + ERROR, NUM_DBG_GRAPH_TYPES, }; @@ -366,7 +362,13 @@ static void PM_UpdateError() { } else { // figure out the error amount, and add it to accumulated lerp pm.error *= max(pm.errortime - time, 0) / ERRORTIME; pm.error += err; - pm.errortime = vlen(pm.error) > 1 ? time + ERRORTIME : 0; + + if (vlen(pm.error) > 1) + pm.errortime = time + ERRORTIME; + else { + pm.error = '0 0 0'; + pm.errortime = 0; + } } } @@ -439,7 +441,8 @@ void PM_Update(float sendflags) { float was_enabled = PM_Enabled(); float enabled = pstate_server.predict_flags & PF_PMOVE; - if (enabled != was_enabled) + if (enabled != was_enabled || + game_state.is_player != prev_game_state.is_player) PM_SetEnabled(enabled); if (sendflags & FOWP_PMOVE == 0) @@ -622,7 +625,7 @@ static void PMD_UpdateImpulse(int seq) { PMD_AddPoint(SERVER, vlen(sv)); PMD_AddPoint(PMOVE, vlen(pv)); - PMD_AddPoint(VIEW, vlen(pm.error) / 128 * 1200); + PMD_AddPoint(ERROR, vlen(pm.error) / 128 * 1200); } static void PMD_Graph(int type, int offset, vector c1, vector c2, vector rgb) { @@ -656,6 +659,11 @@ static void PMD_Graph(int type, int offset, vector c1, vector c2, vector rgb) { } void PMD_DrawGraphs(float width) { + float pmove_on = pstate_server.predict_flags & PF_PMOVE; + if (pmove_on) + drawstring([width - 100, 20, 0], sprintf("PM err: %0.1f", vlen(pm.error)), + '8 8 0', '1 1 1', 1, 0); + if (!CVARF(fopmd_graph)) return; @@ -673,6 +681,7 @@ void PMD_DrawGraphs(float width) { offset = max(0, offset); PMD_Graph(PMOVE, 0, c1, c2, '0 0 1'); - PMD_Graph(VIEW, 0, c1, c2, '0 1 0'); PMD_Graph(SERVER, offset, c1, c2, '1 0 0'); + if (pstate_server.predict_flags & PF_PMOVE) + PMD_Graph(ERROR, 0, c1, c2, '0 1 0'); } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index df5fca48..ff704ec9 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -4,6 +4,9 @@ DEFCVAR_FLOAT(fo_wpp_beta, 0); DEFCVAR_FLOAT(fo_predict_weapons, 1); DEFCVAR_FLOAT(fo_predict_projectiles, 1); +DEFCVAR_FLOAT(fo_pmove, 0); +DEFCVAR_FLOAT(fopmd_force_pos, 0); + DEFCVAR_FLOAT(fo_client_sniper_sight, 1); DEFCVAR_FLOAT(wpp_min_ping, -1); @@ -361,6 +364,12 @@ void WPP_UpdateEnable(float force) { wpp_status |= CSQC_SNIPER_SIGHT; } + // Set this independently of init above so that it can come up faster. + if (CVARF(fo_pmove)) + wpp_status |= CSQC_PMOVE; + if (CVARF(fopmd_force_pos)) + wpp_status |= CSQC_FORCE_POS; + setlocaluserinfo(0, "fo_wpp_status", ftos(wpp_status)); // We always need to "render" the view model to trigger predraw compute. pengine.view_mask = MASK_PRED_ENT | MASK_VIEWMODEL | diff --git a/share/commondefs.qc b/share/commondefs.qc index 170a830e..e7a0108d 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -116,20 +116,6 @@ float TFxEnabled(float flag) { const float TFX_DEFAULT_FLAGS = 0; -enum CSQCFlags { - PREDICT_CSQC_SETSPEED, -}; - -string PREDICTF_DESC[] = { - "allow csqc to handle maxspeed" -}; - -inline float PredictEnabled(float flag) { - return fo_config.predict_flags & flag; -}; - -const float PREDICT_FLAGS_DEFAULT = 0; - enumflags { FOC_ON_DEF, // apply foc_defaults FOC_ON_NODEF, @@ -300,6 +286,7 @@ enumflags { enumflags { CSQC_WEAP_PRED, CSQC_PROJ_PRED, - CSQC_SETSPEED, + CSQC_PMOVE, + CSQC_FORCE_POS, CSQC_SNIPER_SIGHT, }; diff --git a/share/prediction.qc b/share/prediction.qc index 520d5716..c1d4ea8d 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -42,13 +42,6 @@ enumflags { }; -enumflags { - CSQC_WEAP_PRED, - CSQC_PROJ_PRED, - CSQC_SETSPEED, - CSQC_SNIPER_SIGHT, -}; - enumflags { PF_PMOVE, PF_POS, @@ -351,7 +344,7 @@ static float Prediction_ChangedMask(entity player, entity src) { player.predict_state.client_time = src.client_time; player.predict_state.client_ping = src.client_ping; - if (player.predict_flags & PF_POS) + if (player.predict_flags & (PF_PMOVE | PF_POS)) mask |= FOWP_PMOVE; M1(FOWP_CLASS, playerclass); @@ -388,7 +381,10 @@ static float Prediction_ChangedMask(entity player, entity src) { } void Predict_InitPlayer(entity player); -void Predict_Update() { +void Predict_SyncPmove(float is_player); + +void Predict_Update(float is_player) { + Predict_SyncPmove(is_player); Predict_InitPlayer(self); // When spectating, goalentity is our target. @@ -966,6 +962,77 @@ void FOProj_Finalize(entity mis, float use_ctime=0) { FO_Sound(target, CHAN_WEAPON, Snd_Get(SND_THROWGREN)->sound, 1, ATTN_NORM); } } + +.float pmt_nexttime; +.float pmt_nextstate; + +enum PmtState { + PMT_INACTIVE, + PMT_ACTIVE, + PMT_ACTIVATE1, + PMT_ACTIVATE2, + PMT_DEACTIVATE1, + PMT_DEACTIVATE2, +}; + +float PmtBlockMaxSpeed() { + return self.pmt_nexttime != 0; // When set, we're in transition edges. +} + +void TeamFortress_SetSpeed(entity ent); +void Predict_SyncPmove(float is_player) { + if (time < self.pmt_nexttime) + return; + + float active = self.predict_flags & PF_PMOVE; + float want_active = (ClientPred_Enabled(self, CSQC_PMOVE)) && is_player; + float state = self.pmt_nextstate; + + if (!active && want_active && state == PMT_INACTIVE) + state = PMT_ACTIVATE1; + else if (active && !want_active && state == PMT_ACTIVE) + state = PMT_DEACTIVATE1; + + if (state == PMT_ACTIVE || state == PMT_INACTIVE) { + self.pmt_nexttime = 0; + + if (state == PMT_INACTIVE) { + if (ClientPred_Enabled(self, CSQC_FORCE_POS)) + self.predict_flags |= PF_POS; + else + self.predict_flags &= ~PF_POS; + } + return; + } + + float next_step = 0.1; + switch (state) { + case PMT_ACTIVATE1: + self.predict_flags |= PF_POS; + self.maxspeed = SPEC_MAXSPEED; + self.pmt_nextstate = PMT_ACTIVATE2; + break; + case PMT_ACTIVATE2: + self.predict_flags |= PF_PMOVE; + self.nodrawtoclient = self; + TeamFortress_SetSpeed(self); + sprint(self, PRINT_HIGH, "*** PMOVE ACTIVATED\n"); + self.pmt_nextstate = PMT_ACTIVE; + break; + case PMT_DEACTIVATE1: + next_step = 2; + self.nodrawtoclient = world; + TeamFortress_SetSpeed(self); + self.pmt_nextstate = PMT_DEACTIVATE2; + break; + case PMT_DEACTIVATE2: + self.predict_flags &= ~(PF_PMOVE | PF_POS); + sprint(self, PRINT_HIGH, "*** PMOVE DEACTIVATED\n"); + self.pmt_nextstate = PMT_INACTIVE; + break; + } + self.pmt_nexttime = time + next_step; +} #endif struct ProjectResult { diff --git a/ssqc/client.qc b/ssqc/client.qc index 89d9583d..6646f84e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3010,7 +3010,7 @@ void () PlayerPostThink = { FOPlayer fop = (FOPlayer)self; fop.RewindUpdate(); - Predict_Update(); + Predict_Update(TRUE); }; void () UpdateAllClientsTeamScores = { @@ -3886,53 +3886,3 @@ void() SV_RunClientCommand = { self.jump_flag = self.velocity_z; } */ - -static void DeferredPmoveAction() { - entity player = self.owner; - player.predict_flags &= ~PF_PMOVE_ACTIVATING; - - if (self.heat) { - sprint(player, PRINT_HIGH, "*** PMOVE ACTIVATED\n"); - player.nodrawtoclient = player; - player.predict_flags |= PF_PMOVE; - TeamFortress_SetSpeed(player); - } else { - sprint(player, PRINT_HIGH, "*** PMOVE INACTIVE\n"); - player.predict_flags &= ~PF_PMOVE; - } - remove(self); -} - -void (float active) CSEv_PmCmd_f = { - if (self.predict_flags & PF_PMOVE_ACTIVATING) { - sprint(self, PRINT_HIGH, "Please wait for prior activation to complete...\n"); - return; - } - - if (active & PF_PMOVE) - active |= PF_POS; - - self.predict_flags &= ~PF_POS; - self.predict_flags |= (active & PF_POS); - - if ((active & PF_PMOVE) == (self.predict_flags & PF_PMOVE)) - return; - - float enable = active & PF_PMOVE; - if (enable) { - // This is messy; maxspeed exists only in hidden inband communication - // with the client. We need to push a high value to the client before - // we obscure the client since it won't see further updates (which might - // increase when changing classes). - self.maxspeed = SPEC_MAXSPEED; - } else { - self.nodrawtoclient = world; - } - - self.predict_flags |= PF_PMOVE_ACTIVATING; - entity defer = spawn(); - defer.owner = self; - defer.think = DeferredPmoveAction; - defer.heat = enable; - defer.nextthink = time + 0.1; -} diff --git a/ssqc/spect.qc b/ssqc/spect.qc index 8fa05197..d6e72f4b 100644 --- a/ssqc/spect.qc +++ b/ssqc/spect.qc @@ -162,5 +162,5 @@ void () SpectatorThink = { RefreshStatusBar(self); } - Predict_Update(); + Predict_Update(FALSE); }; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 4a01987c..4a5035e6 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -982,6 +982,14 @@ float (float pc) IsLegalClass = { return (TRUE); }; +float PmtBlockMaxSpeed(); + +static void SetMaxSpeed(entity p, float speed) { + p.csqc_maxspeed = speed; + if (!PmtBlockMaxSpeed()) + p.maxspeed = speed; +} + void (entity p) TeamFortress_SetSpeed = { string sp; float tf; @@ -989,14 +997,14 @@ void (entity p) TeamFortress_SetSpeed = { if (p.tfstate & TFSTATE_CANT_MOVE) { p.velocity = '0 0 0'; - p.csqc_maxspeed = p.maxspeed = 0; + SetMaxSpeed(p, 0); return; } if (p.playerclass == PC_UNDEFINED) { // Typically this hits spectators and then spec movetype --> maxspeed // actually ignored. - p.csqc_maxspeed = p.maxspeed = SPEC_MAXSPEED; + SetMaxSpeed(p, SPEC_MAXSPEED); stuffcmd(p, "cl_movespeedkey 1;cl_backspeed 500; cl_forwardspeed 500; cl_sidespeed 500;cl_upspeed 500;\n"); return; } @@ -1030,8 +1038,8 @@ void (entity p) TeamFortress_SetSpeed = { new_max = min(new_max, 80); #endif - p.maxspeed = p.csqc_maxspeed = new_max; -}; + SetMaxSpeed(p, new_max); +} void () TeamFortress_SetHealth = { if (self.playerclass == PC_SCOUT) { From 2eef1ce908f3e1d4ff15c963a7071d9018edde63 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 2 Oct 2023 13:07:26 -0700 Subject: [PATCH 2222/2474] pmove: quick fixes for water and missing pmove_vel --- csqc/pmove.qc | 2 ++ csqc/weapon_predict.qc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index d33f870e..3c59f1d1 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -490,6 +490,7 @@ void PM_InputFrame() { input_movevalues.z = 0; float max_speed = pstate_pred.csqc_maxspeed; +#if 0 // Quick fix // cl_smartjump replacement float type; if (input_buttons & BUTTON2) { @@ -500,6 +501,7 @@ void PM_InputFrame() { iz = min(CVARF(cl_upspeed), Class_MaxSpeed(WP_PlayerClass())); } } +#endif // Technically the sync with pstate_pred being on the right frame is loose.. if (pstate_pred.tfstate & TFSTATE_AIMING) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ff704ec9..ae4a085c 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -811,7 +811,7 @@ static float WP_Sniper_IsAttack() { if (pstate_pred.buttons_held & BUTTON0) { // Start charging when possible/necessary. - if (!aiming && pmove_onground && vlen(pmove_vel) <= 50) { + if (!aiming && pmove_onground && vlen(PM_Vel()) <= 50) { pstate_pred.tfstate |= TFSTATE_AIMING; SniperState.start_seq = pstate_pred.seq; } From 8ad21be62186afabdffa57dfbada06660e087949 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 4 Oct 2023 00:38:48 -0700 Subject: [PATCH 2223/2474] rewind: only bother with forwarding within antilag adjustment --- ssqc/weapons.qc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 5a7c13fa..48cadab6 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1048,6 +1048,10 @@ float AntilagKnock(entity e, float dmg) { if (!RewindFlagEnabled(REWIND_FORWARD_PROJ_SELFKNOCK) || e.s_time == 0) return FALSE; + // Only applies during initial antilag forward + if (e.flags & FL_FORWARD_KNOCK == 0) + return FALSE; + entity knock_e = spawn(); setorigin(knock_e, e.origin); @@ -1059,13 +1063,10 @@ float AntilagKnock(entity e, float dmg) { vector diff = e.origin - e.s_origin; float ttime = vlen(diff) / vlen(e.velocity); - float dtime = time - e.s_time; - - float delay = ttime - dtime; - if (delay > SERVER_FRAME_DT && dtime < 0.25) { + if (ttime > SERVER_FRAME_DT) { knock_e.think = T_Knock_Antilag; - knock_e.nextthink = time + delay; + knock_e.nextthink = time + ttime; } else { Antilag_Knock(knock_e); } From c882ef7037f2a0770ce9159e005b47e82a115ef5 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 5 Oct 2023 16:41:32 -0700 Subject: [PATCH 2224/2474] rewind: eliminate REWIND_KNOCKBACK We always use historical position for knockback. Simplify the distinction. --- share/commondefs.qc | 4 +-- ssqc/combat.qc | 88 +++++++-------------------------------------- ssqc/demoman.qc | 2 +- ssqc/weapons.qc | 3 -- 4 files changed, 15 insertions(+), 82 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index e7a0108d..69b7b361 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -57,7 +57,6 @@ var struct { enumflags { REWIND_PROJ_FIRE, REWIND_PROJ_TRAVEL, - REWIND_KNOCKBACK, REWIND_GRENADES, REWIND_SENDEVENT, REWIND_FORWARD_PROJ_SELFKNOCK, @@ -67,14 +66,13 @@ enumflags { string REWIND_DESC[] = { "rewind projectile on firing", "rewind on projectile travel", - "rewind pipe knockback", "rewind grenade throws", "use sendevent augmentation (allows race w/ death rewind)", "forward projectile self-knockback", "open doors earlier for hpbs [requires rfd=1]", }; -const float REWIND_DEFAULT_FLAGS = REWIND_KNOCKBACK | REWIND_PROJ_FIRE | +const float REWIND_DEFAULT_FLAGS = REWIND_PROJ_FIRE | REWIND_PROJ_TRAVEL | REWIND_FORWARD_PROJ_SELFKNOCK | REWIND_SENDEVENT; diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 1dfc8cf9..1925bee4 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -352,8 +352,7 @@ void BroadcastHitFlag(entity targ, entity inflictor, entity attacker, multicast('0 0 0', MULTICAST_ONE_R_NOSPECS); }; -void (entity targ, entity inflictor, entity attacker, - float damage, float knock_damage) T_DamageKnock = { +void (entity targ, entity inflictor, entity attacker, float damage) T_Damage = { local vector dir; local entity oldself, te; local float save; @@ -408,22 +407,22 @@ void (entity targ, entity inflictor, entity attacker, } if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK)) { - targ.immune_to_check = time + (knock_damage / 20); + targ.immune_to_check = time + (damage / 20); dir = targ.origin - ((inflictor.absmin + inflictor.absmax) * 0.5); dir = normalize(dir); - if (((knock_damage < 60) && + if (((damage < 60) && ((attacker.classname == "player") && (targ.classname == "player"))) && (attacker.netname != targ.netname)) - targ.velocity = targ.velocity + dir * knock_damage * 11; + targ.velocity = targ.velocity + dir * damage * 11; else - targ.velocity = targ.velocity + dir * knock_damage * 8; + targ.velocity = targ.velocity + dir * damage * 8; if (((rj > 1) && ((attacker.classname == "player") && (targ.classname == "player"))) && (attacker.netname == targ.netname)) - targ.velocity = (targ.velocity + ((dir * knock_damage) * rj)); + targ.velocity = (targ.velocity + ((dir * damage) * rj)); } if (targ.flags & FL_GODMODE) return; @@ -479,13 +478,8 @@ void (entity targ, entity inflictor, entity attacker, self = oldself; }; -void (entity targ, entity inflictor, entity attacker, - float damage) T_Damage = { - T_DamageKnock(targ, inflictor, attacker, damage, damage); -} - -void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, - float damage, float knock_damage, float T_flags, float T_AttackType) { +void TF_T_Damage(entity targ, entity inflictor, entity attacker, + float damage, float T_flags, float T_AttackType) { local vector dir; local entity oldself; local entity te; @@ -493,7 +487,6 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, local float take; local float olddmsg; local float no_damage; - local float moment; local float original_damage = damage; if (targ.takedamage == 0) @@ -613,14 +606,15 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, targ.dmg_inflictor = inflictor; } - knock_damage = floor(damage / original_damage * knock_damage); - if (!(T_AttackType & TF_TD_NOMOMENTUM) && knock_damage) { + damage = floor(damage); + + if (!(T_AttackType & TF_TD_NOMOMENTUM) && damage) { if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && !(targ.tfstate & TFSTATE_CANT_MOVE)) { if (deathmsg != DMSG_GREN_NAIL && deathmsg != DMSG_GREN_SHOCK && deathmsg != DMSG_GREN_BURST) { targ.immune_to_check = time + damage / 20; dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; dir = normalize(dir); - moment = knock_damage; + float moment = damage; if (targ.playerclass == PC_HVYWEAP) { moment = moment / 4; @@ -774,12 +768,6 @@ void TF_T_DamageKnock(entity targ, entity inflictor, entity attacker, self = oldself; }; -void TF_T_Damage(entity targ, entity inflictor, entity attacker, - float damage, float T_flags, float T_AttackType) { - TF_T_DamageKnock(targ, inflictor, attacker, damage, damage, - T_flags, T_AttackType); -} - void (entity inflictor, entity attacker, float damage, entity ignore1, entity ignore2 = __NULL__, entity only = __NULL__) T_RadiusDamage = { @@ -813,8 +801,7 @@ void (entity inflictor, entity attacker, float damage, T_Damage(e, inflictor, attacker, points * 0.5); else - TF_T_DamageKnock(e, inflictor, attacker, points, - points, + TF_T_Damage(e, inflictor, attacker, points, TF_TD_NOTTEAM, TF_TD_EXPLOSION); } } @@ -822,55 +809,6 @@ void (entity inflictor, entity attacker, float damage, }; -// Implements T_RadiusDamage but with awareness that the rewound player position -// for damage and the current player position for knockback may not be the -// same. -// -// Will merge with RadiusDamage in time. -void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, - entity ignore) { - float dmg[2]; - vector org[2]; - - int count; - entity* list = findradius_list(inflictor.origin, damage + 40, count); - for (int i = 0; i < count; i++) { - entity c = list[i]; - if (c == ignore || !c.takedamage || !CanDamage(c, inflictor)) - continue; - - FOPlayer fc = (FOPlayer)c; - - org[0] = c.origin + (c.mins + c.maxs) * 0.5; - if (RewindFlagEnabled(REWIND_KNOCKBACK)) - org[1] = org[0]; - else - org[1] = fc.UnrewoundOrigin() + (c.mins + c.maxs) * 0.5; - - for (int j = 0; j < 2; j++) { - float points = 0.5 * vlen(inflictor.origin - org[j]); - if (points < 0) - points = 0; - points = damage - points; - if (c == attacker) - points = points * 0.75; - dmg[j] = points; - } - - vector held_pos = c.origin; - if (!RewindFlagEnabled(REWIND_KNOCKBACK)) { - c.origin = fc.UnrewoundOrigin(); - dmg[1] = min(dmg[0], dmg[1]); // Limit Kerbal. - } - - if (dmg[0] > 0) - TF_T_DamageKnock(c, inflictor, attacker, dmg[0], dmg[1], - TF_TD_NOTTEAM, TF_TD_EXPLOSION); - - c.origin = held_pos; - } -} - void (entity attacker, float damage) T_BeamDamage = { local float points; local entity head; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 58584394..94575ceb 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -38,7 +38,7 @@ float (float force) TeamFortress_DetonatePipebombs = { deathmsg = pipes[i].flags & FL_ONGROUND ? pipes[i].weapon : DMSG_GREN_PIPE_AIR; - T_RadiusDamage_Antilag(pipes[i], pipes[i].owner, 120, world); + T_RadiusDamage(pipes[i], pipes[i].owner, 120, world); // This maintains some sort of awful hack that we'll remove. pipes[i].voided = 1; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 48cadab6..1878ac86 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1246,9 +1246,6 @@ void FO_T_GrenExplode() { dremove(self); } -void T_RadiusDamage_Antilag(entity inflictor, entity attacker, float damage, - entity ignore); - void () GrenadeExplode = { local entity te; float use_antilag = FALSE; From 1110edd5d21d43d0479e13782e388a187a8e8b91 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 5 Oct 2023 16:43:48 -0700 Subject: [PATCH 2225/2474] wp-explicit-offsets --- csqc/weapon_predict.qc | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ae4a085c..a422d164 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1379,6 +1379,8 @@ void FPP_Init(int fpp_type, entity proj) { proj.traileffectnum = FPP_FindTrail(proj); proj.movetype = desc->movetype; + + setsize(proj, [0,0,0], [0,0,0]); } DEFCVAR_FLOAT(r_rocketlight, 1); @@ -1433,7 +1435,7 @@ float PP_PredrawPredicted() { static float PP_EPS = 0.05; -entity PP_CreateProjectile(int fpp_type, vector offset) { +entity PP_CreateProjectile(int fpp_type, vector org) { PredProj_Sound(fpp_type); if (!PP_Enabled()) @@ -1442,6 +1444,7 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { entity proj = spawn(); proj.owner_entnum = player_localentnum; proj.owner = pengine.player_ent; + proj.origin = org; FPP_Init(fpp_type, proj); float ms_ahead = pstate_server.client_ping; @@ -1459,13 +1462,9 @@ entity PP_CreateProjectile(int fpp_type, vector offset) { proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; - setsize(proj, [0,0,0], [0,0,0]); - proj.origin = PM_Org() + offset; - float proj_speed = FPP_Get(fpp_type)->speed; if (!FPP_IsGrenade(fpp_type)) { proj.velocity = v_forward * proj_speed; - proj.origin[2] += 16; } else { if (!input_angles_x) { proj.velocity = v_forward * proj_speed; @@ -1511,7 +1510,7 @@ static void FPP_ApplyGrenadeProperties(entity proj) { } void W_FireGrenade(int gren_type) { - entity proj = PP_CreateProjectile(FPP_GRENADE, '0 0 0'); + entity proj = PP_CreateProjectile(FPP_GRENADE, PM_Org()); proj.fpp.gren_type = gren_type; FPP_ApplyGrenadeProperties(proj); } @@ -1541,9 +1540,9 @@ void (float ox) W_FireSpikes = { return; if (wi->weapon == WEAP_NAILGUN) - PP_CreateProjectile(FPP_NAIL, ox * v_right); + PP_CreateProjectile(FPP_NAIL, PM_Org() + ox * v_right + '0 0 16'); else - PP_CreateProjectile(FPP_SUPER_NAIL, '0 0 0'); + PP_CreateProjectile(FPP_SUPER_NAIL, PM_Org() + '0 0 16'); }; @@ -1626,8 +1625,7 @@ static void W_ThrowGren(float is_throw) { void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { - vector offset = org - PM_Org() - '0 0 16'; - entity proj = PP_CreateProjectile(FPP_ASSAULT_CANNON, offset); + entity proj = PP_CreateProjectile(FPP_ASSAULT_CANNON, org); if (proj == __NULL__) return; @@ -1671,21 +1669,21 @@ void WP_Attack() { float send_event = FALSE; switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: - PP_CreateProjectile(FPP_ROCKET, v_forward * 8); + PP_CreateProjectile(FPP_ROCKET, PM_Org() + v_forward * 8 + '0 0 16'); send_event = TRUE; break; case WEAP_INCENDIARY: - PP_CreateProjectile(FPP_INCENDIARY, v_forward * 8); + PP_CreateProjectile(FPP_INCENDIARY, PM_Org() + v_forward * 8 + '0 0 16'); send_event = TRUE; break; case WEAP_FLAMETHROWER: - PP_CreateProjectile(FPP_FLAMETHROWER, v_forward * 16); + PP_CreateProjectile(FPP_FLAMETHROWER, PM_Org() + v_forward * 16 + '0 0 16'); break; case WEAP_TRANQ: - PP_CreateProjectile(FPP_TRANQ, v_forward * 8); + PP_CreateProjectile(FPP_TRANQ, PM_Org() + v_forward * 8 + '0 0 16'); break; case WEAP_RAILGUN: - PP_CreateProjectile(FPP_RAILGUN, '0 0 0'); + PP_CreateProjectile(FPP_RAILGUN, PM_Org() + '0 0 16'); break; case WEAP_ASSAULT_CANNON: From 7f9ccd73014e77783062ad287e7c65e61fa9b57d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 6 Oct 2023 14:15:50 +1100 Subject: [PATCH 2226/2474] Don't send matches <= 4 players to #scrims anymore, scrim server is up --- ssqc/quadmode.qc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 1aea5d3e..5221e554 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -12,11 +12,6 @@ void () PostFOQuadStarted = { return; } - // Override 2v2 to go to scrim results for now. - string channel_id = discord_channel_id; - if (TeamFortress_TeamGetNoPlayersExcludingAllTime(1) <= 2) - channel_id = "1147341454851719219"; - local string data = ""; data = strcat(data, "{\n"); @@ -42,7 +37,7 @@ void () PostFOQuadStarted = { data = strcat(data, " \"address\": \"", cvar_string("sv_serverip"), "\"\n"); data = strcat(data, " },\n"); data = strcat(data, " \"discord_channel\": {\n"); - data = strcat(data, " \"channel_id\": \"", channel_id, "\"\n"); + data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); data = strcat(data, " },\n"); data = strcat(data, " \"teams\": {\n"); From 23543724de99b02f653c1b61976cd866c3fb76b8 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 6 Oct 2023 12:23:12 -0700 Subject: [PATCH 2227/2474] wp: fix direction on retrainsmit soujnd filtering --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index a422d164..56172d16 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1845,7 +1845,7 @@ void InitProjectileEnt(float sendflags) { else setorigin(self, self.origin); - if (self.created_at > time + 0.05) { + if (self.created_at < pstate_server.server_time - 0.05) { // Retransmit. Patch up trail, but no predicted / sound / etc. self.oldorigin = self.s_origin; return; From 58e6ecd7574d23e06906e05385de67ff78d7c2aa Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 6 Oct 2023 12:29:32 -0700 Subject: [PATCH 2228/2474] Revert "Don't send matches <= 4 players to #scrims anymore, scrim server is up" This reverts commit 7f9ccd73014e77783062ad287e7c65e61fa9b57d. Until we have a flag we can pass to ignore for rating instead. --- ssqc/quadmode.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 5221e554..1aea5d3e 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -12,6 +12,11 @@ void () PostFOQuadStarted = { return; } + // Override 2v2 to go to scrim results for now. + string channel_id = discord_channel_id; + if (TeamFortress_TeamGetNoPlayersExcludingAllTime(1) <= 2) + channel_id = "1147341454851719219"; + local string data = ""; data = strcat(data, "{\n"); @@ -37,7 +42,7 @@ void () PostFOQuadStarted = { data = strcat(data, " \"address\": \"", cvar_string("sv_serverip"), "\"\n"); data = strcat(data, " },\n"); data = strcat(data, " \"discord_channel\": {\n"); - data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); + data = strcat(data, " \"channel_id\": \"", channel_id, "\"\n"); data = strcat(data, " },\n"); data = strcat(data, " \"teams\": {\n"); From 39c6651ab057a4648becc81dc0f201deebdb0111 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 6 Oct 2023 11:26:25 -0700 Subject: [PATCH 2229/2474] pm: refactor state caching --- csqc/pmove.qc | 117 ++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 3c59f1d1..0d3a4733 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -17,13 +17,17 @@ enumflags { // constant for this frame. struct PMS_Data { vector org, vel; - float seq; + float seq, server_seq; float interp_t; } pm_s, pm_so, pm_c; struct { entity ent; - float seq; + float last_vel_z; + PMS_Data* active_pmsd; + + + float seq, server_seq; float interp_t; vector error; @@ -188,23 +192,33 @@ void PM_Init() { // Should be invoked immediately after RunMovement() to ensure correctness of // `seq` versus state. On server packets we manually set `seq` to sf + 1. -static inline void PM_SavePMS(PMS_Data *pms) { +static void PM_SavePMS(PMS_Data *pmsd) { entity ent = pm.ent; - pms->org = ent.origin; - pms->vel = ent.velocity; + pmsd->org = ent.origin; + pmsd->vel = ent.velocity; - pms->seq = pm.seq; - pms->interp_t = pm.interp_t; + pmsd->seq = pm.seq; + pmsd->server_seq = pm.server_seq; + pmsd->interp_t = pm.interp_t; } -static inline void PM_ActivatePMS(PMS_Data *pms) { +static void PM_ActivatePMS(PMS_Data *pmsd) { entity ent = pm.ent; - ent.origin = pms->org; - ent.velocity = pms->vel; - pm.seq = pms->seq; - pm.interp_t = pms->interp_t; + ent.origin = pmsd->org; + ent.velocity = pmsd->vel; + + pm.seq = pmsd->seq; + pm.server_seq = pmsd->server_seq; + pm.interp_t = pmsd->interp_t; + pm.active_pmsd = pmsd; + + pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing }; +static PMS_Data* SimPMSD() { + return CVARF(fopm_nocache) ? &pm_s : &pm_c; +} + void PM_InputFrame(); enum { @@ -271,24 +285,20 @@ static void PM_ApplyNudges(entity ent, float sitime, float eitime) { } } -static void PM_RunMovement(float endframe) { +static void RunPlayerPhysics() { entity ent = pm.ent; - if (servercommandframe >= pm_s.seq + 63) { - // We're meant to be updating the player faster than this - // hopefully its just that we're throttled... - // Uncommenting this block will result in the player continuing to be - // predicted rather than frozen. - pm_s.seq = servercommandframe - 63; - return; - } - if (endframe < pm.seq) { - if (endframe >= pm_c.seq && !CVARF(fopm_nocache)) - PM_ActivatePMS(&pm_c); - else - PM_ActivatePMS(&pm_s); - } + pm.last_vel_z = ent.velocity_z; + runstandardplayerphysics(ent); +} +static void PM_RunMovement(PMS_Data* pmsd, float endframe) { + entity ent = pm.ent; + + if (pm.active_pmsd != pmsd || endframe < pm.seq) { + ASSERTF_GT(endframe, pm.server_seq); + PM_ActivatePMS(pmsd); + } if (!game_state.is_spectator && !game_state.is_alive) { pm.seq = clientcommandframe; @@ -297,9 +307,6 @@ static void PM_RunMovement(float endframe) { return; } - if (pm.seq < clientcommandframe - 128) - pm.seq = clientcommandframe - 128; - while (pm.seq <= endframe) { if (!getinputstate(pm.seq)) break; @@ -309,12 +316,11 @@ static void PM_RunMovement(float endframe) { if (pm.seq == clientcommandframe) PM_InputFrame(); - pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing + RunPlayerPhysics(); + if (!CVARF(fopm_nonudge) && pm.seq < clientcommandframe) PM_ApplyNudges(ent, pm.interp_t, pm.interp_t + input_timelength); - runstandardplayerphysics(ent); - pm.seq++; pm.interp_t += input_timelength; } @@ -346,13 +352,11 @@ static void PM_UpdateError() { } // Run prior prediction to present. - PM_ActivatePMS(&pm_so); - PM_RunMovement(clientcommandframe); + PM_RunMovement(&pm_so, clientcommandframe); vector err = ent.origin; // Repeat with updated state. - PM_ActivatePMS(&pm_s); - PM_RunMovement(clientcommandframe); + PM_RunMovement(&pm_s, clientcommandframe); err -= ent.origin; float nerr = vlen(err); @@ -375,10 +379,9 @@ static void PM_UpdateError() { static void PM_UpdateLocalMovement() { entity ent = pm.ent; - PM_RunMovement(clientcommandframe); + PM_RunMovement(SimPMSD(), clientcommandframe); vector org = pm.ent.origin; - // Smooth stair stepping if (org_z > pm.step_oldz + 8 && org_z < pm.step_oldz + 24 && ent.velocity_z == 0) { // Evaluate out the remaining old step @@ -418,23 +421,14 @@ void PM_SyncTo(float seq) { return; entity ent = pm.ent; - - PM_RunMovement(seq - 1); - float of = ent.flags; - float last_vel_z = ent.velocity_z; - - PM_RunMovement(seq); - float nf = ent.flags; - - if (!CSQC_JumpSounds_Active()) - return; + PM_RunMovement(SimPMSD(), seq); // Note: ~FL_ONGROUND and jump occur in same frame, produces JUMP_HELD float jumping = input_buttons & BUTTON2; - float landing = (!(of & FL_ONGROUND) && (nf & FL_ONGROUND)); + float landing = pm.last_vel_z < 0 && (ent.flags & FL_ONGROUND); float jump_frame = ent.pmove_flags & PMF_JUMP_HELD; - PM_Sounds(jumping, jump_frame, landing, last_vel_z); + PM_Sounds(jumping, jump_frame, landing, pm.last_vel_z); } void PM_Update(float sendflags) { @@ -449,18 +443,21 @@ void PM_Update(float sendflags) { return; pm_so = pm_s; + pm.server_seq = servercommandframe; pm.seq = servercommandframe + 1; // server state includes move pm.interp_t = pstate_server.server_time; PM_SavePMS(&pm_s); - // Pre-compute predicted movement for all locked frames (e.g. seq < - // clientcommandframe) so that we can accelerate the common case of - // computation at clientcommandframe (which does require constant - // re-evaluation). In the case there's no separation (e.g. lan pings) then - // the server frame is directly used as the cache frame. - if (clientcommandframe > servercommandframe + 1) - PM_RunMovement(clientcommandframe - 1); - PM_SavePMS(&pm_c); + if (!CVARF(fopm_nocache)) { + // Pre-compute predicted movement for all locked frames (e.g. seq < + // clientcommandframe) so that we can accelerate the common case of + // computation at clientcommandframe (which does require constant + // re-evaluation). In the case there's no separation (e.g. lan pings) then + // the server frame is directly used as the cache frame. + if (clientcommandframe > servercommandframe + 1) + PM_RunMovement(&pm_s, clientcommandframe - 1); + PM_SavePMS(&pm_c); + } if (enabled && was_enabled) PM_UpdateError(); @@ -599,7 +596,7 @@ static void PMD_UpdateImpulse(int seq) { old_seq = seq; if (PM_Enabled()) - PM_RunMovement(clientcommandframe); + PM_RunMovement(SimPMSD(), clientcommandframe); vector sv = pm_s.vel; vector pv = PM_Vel(); From 7c93180aecc967d81b0a401f3c366d0ad36cedd2 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 6 Oct 2023 11:58:07 -0700 Subject: [PATCH 2230/2474] pm: add more detailed prediction error logging --- csqc/pmove.qc | 63 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 0d3a4733..257a21a3 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -160,7 +160,9 @@ void PM_PredictJump_Engine() { enum { SERVER, PMOVE, - ERROR, + ERROR_POS, + ERROR_VEL, + ERROR_VIEW, NUM_DBG_GRAPH_TYPES, }; @@ -179,11 +181,33 @@ DEFCVAR_FLOAT(fopmd_graph_h, 100); DEFCVAR_FLOAT(v_viewheight, 0); enumflags { - PMDG_ON, - PMDG_NO_ALIGN_INTERP, + PMDG_ON, // 1 for laziness.. + PMDG_NO_ALIGN_INTERP, // 2 + PMDG_ERROR_VEL, // 4 + PMDG_ERROR_POS, // 8 + PMDG_ERROR_VIEW, // 16 }; DEFCVAR_FLOAT(fopmd_graph, 0); +static const float NHIST = 21; +struct PM_History { + vector org, vel; + vector seq; +}; +static PM_History hist[NHIST]; + +void PMH_Log(float seq) { + PM_History* pmh = &hist[seq % NHIST]; + pmh->org = PM_Org(); + pmh->vel = PM_Vel(); + pmh->seq = seq; +} + +PM_History* PMH_Get(float seq) { + PM_History* pmh = &hist[seq % NHIST]; + return pmh->seq == seq ? pmh : 0; +} + void PM_Init() { pm.ent = spawn(); pm.ent.solid = SOLID_NOT; @@ -595,8 +619,11 @@ static void PMD_UpdateImpulse(int seq) { return; old_seq = seq; + float cseq = clientcommandframe - 1; if (PM_Enabled()) - PM_RunMovement(SimPMSD(), clientcommandframe); + PM_RunMovement(SimPMSD(), cseq); + + PMH_Log(cseq); vector sv = pm_s.vel; vector pv = PM_Vel(); @@ -604,6 +631,15 @@ static void PMD_UpdateImpulse(int seq) { if (!vlen(pv) && !vlen(sv)) return; + PMD_AddPoint(SERVER, vlen(sv)); + PMD_AddPoint(PMOVE, vlen(pv)); + + PMD_AddPoint(ERROR_VIEW, vlen(pm.error) / 128 * 1200); + + PM_History* hist = PMH_Get(servercommandframe); + PMD_AddPoint(ERROR_POS, hist ? vlen(pm_s.org - hist.org) : 0); + PMD_AddPoint(ERROR_VEL, hist ? vlen(pm_s.vel - hist.vel) : 0); + #if 0 static vector last_sv, last_pv; float p = FALSE; @@ -621,10 +657,6 @@ static void PMD_UpdateImpulse(int seq) { last_pv = pv; if (p) printf("\n"); #endif - - PMD_AddPoint(SERVER, vlen(sv)); - PMD_AddPoint(PMOVE, vlen(pv)); - PMD_AddPoint(ERROR, vlen(pm.error) / 128 * 1200); } static void PMD_Graph(int type, int offset, vector c1, vector c2, vector rgb) { @@ -676,11 +708,18 @@ void PMD_DrawGraphs(float width) { drawfill(c2, '5 5 5', '1 0 0', 1); float offset = (CVARF(fopmd_graph) & PMDG_NO_ALIGN_INTERP) ? 0 : - clientcommandframe - servercommandframe; + clientcommandframe - servercommandframe - 1; offset = max(0, offset); PMD_Graph(PMOVE, 0, c1, c2, '0 0 1'); - PMD_Graph(SERVER, offset, c1, c2, '1 0 0'); - if (pstate_server.predict_flags & PF_PMOVE) - PMD_Graph(ERROR, 0, c1, c2, '0 1 0'); + PMD_Graph(SERVER, offset, c1, c2, '0 1 0'); + + if ((CVARF(fopmd_graph) & PMDG_ERROR_VIEW) && + (pstate_server.predict_flags & PF_PMOVE)) + PMD_Graph(ERROR_VIEW, 0, c1, c2, '1 0 1'); + if ((CVARF(fopmd_graph) & PMDG_ERROR_VEL)) + PMD_Graph(ERROR_VEL, 0, c1, c2, '1 1 0'); + if ((CVARF(fopmd_graph) & PMDG_ERROR_POS)) + PMD_Graph(ERROR_POS, 0, c1, c2, '1 0 0'); + } From cf4cfb783cb6f6be8667ea88cc6e8c08da797e08 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 6 Oct 2023 13:14:10 -0700 Subject: [PATCH 2231/2474] pm: add knob for errortime --- csqc/pmove.qc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 257a21a3..897915a2 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -3,7 +3,6 @@ DEFCVAR_FLOAT(fo_jumpvolume, 1); static float pm_enabled; inline float PM_Enabled() { return pm_enabled; } -#define ERRORTIME 0.05 #define STEPTIME 0.125 enumflags { @@ -172,6 +171,7 @@ DEFCVAR_FLOAT(fopm_noerror, 0); DEFCVAR_FLOAT(fopm_nocache, 0); DEFCVAR_FLOAT(fopm_nostep, 0); DEFCVAR_FLOAT(fopm_nonudge, 0); +DEFCVAR_FLOAT(fopm_errortime, 0); DEFCVAR_FLOAT(fopmd_graph_x, -10); DEFCVAR_FLOAT(fopmd_graph_y, 100); @@ -365,6 +365,16 @@ static void PM_SetEnabled(float enabled) { pm.step_oldz = pm.ent.origin_z; } +static float ErrorTime() { + static float kDefault = 25 * MSEC; + static float kMax = 50 * MSEC; + + if (!CVARF(fopm_errortime)) + return kDefault; + + return min(CVARF(fopm_errortime), kMax); +} + static void PM_UpdateError() { entity ent = pm.ent; @@ -388,11 +398,11 @@ static void PM_UpdateError() { pm.error = '0 0 0'; pm.errortime = 0; } else { // figure out the error amount, and add it to accumulated lerp - pm.error *= max(pm.errortime - time, 0) / ERRORTIME; + pm.error *= max(pm.errortime - time, 0) / ErrorTime(); pm.error += err; if (vlen(pm.error) > 1) - pm.errortime = time + ERRORTIME; + pm.errortime = time + ErrorTime(); else { pm.error = '0 0 0'; pm.errortime = 0; @@ -429,9 +439,9 @@ static void PM_UpdateLocalMovement() { pm.vieworg = org; pm.vieworg.z += getstatf(STAT_VIEWHEIGHT) + viewheight; - // Correct view position over ERRORTIME + // Correct view position over ErrorTime() if (pm.errortime - time > 0) - pm.vieworg += (pm.errortime - time) * (1 / ERRORTIME) * pm.error; + pm.vieworg += (pm.errortime - time) * (1 / ErrorTime()) * pm.error; if (!CVARF(fopm_nostep)) if (pm.steptime - time > 0) From 390bce9e214690fb360b57da3dd5ce5304d74f7d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Oct 2023 02:32:03 +1100 Subject: [PATCH 2232/2474] Add fo_matchrated, also to admin menu --- README.md | 1 + csqc/csextradefs.qc | 1 + csqc/events.qc | 1 + csqc/menu.qc | 33 +++++++++++++++++++++++---------- ssqc/commands.qc | 18 ++++++++++++++++++ ssqc/csmenu.qc | 1 + ssqc/quadmode.qc | 21 ++++++++++++++------- ssqc/qw.qc | 1 + 8 files changed, 60 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 75d1d0a3..47f8e5c0 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * Website backend for match results, stats. Get a token at fortressone.org, connect to a FortressOne server, and `login `. * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. +* `localinfo fo_matchrated 2` whether match is rated / affects trueskill. 2 is false for 1v1 and 2v2 only. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ * All-time attack and all-time defence team options. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 3ae49762..f88c522c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -331,6 +331,7 @@ typedef struct { float quad_rounds; float quad_round_time; float fo_login_required; + float fo_matchrated; float captainmode; float timelimit; float fraglimit; diff --git a/csqc/events.qc b/csqc/events.qc index b6d4a781..4e55bcb9 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -266,6 +266,7 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.quad_rounds = readfloat(); SERVER_ADMIN.quad_round_time = readfloat(); SERVER_ADMIN.fo_login_required = readfloat(); + SERVER_ADMIN.fo_matchrated = readfloat(); SERVER_ADMIN.timelimit = readfloat(); SERVER_ADMIN.fraglimit = readfloat(); SERVER_ADMIN.clanmode = readfloat(); diff --git a/csqc/menu.qc b/csqc/menu.qc index bfb7152d..dc466776 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -6,7 +6,7 @@ void (float force) FO_Menu_Admin_Rounds; void (float force) FO_Menu_Admin_Timelimit; void (float force) FO_Menu_Admin_Fraglimit; void (float force) FO_Menu_Admin_QuadTimelimit; -void (float force) FO_Menu_Admin_FoLoginRequired; +void (float force) FO_Menu_Admin_FoMatchRated; void (float force) FO_Menu_Spy; void (float force) FO_Menu_Spy_Skin; void (float force) FO_Menu_Spy_Team; @@ -420,6 +420,18 @@ string (float m) modeStatus = { return ""; } +string (float m) ratedStatus = { + switch(m) { + case 0: + return "unrated"; + case 1: + return "rated"; + case 2: + return "default"; + } + return ""; +} + var fo_menu FO_MENU_ADMIN_MODES = { [0,0], [300,300], "Server Modes [2/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Pub Mode","","Public play, anything goes",FO_MENU_STATE_NORMAL,{localcmd("cmd pubmode\n");},MENU_BORDER_WARNING}, @@ -428,7 +440,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"4","Duel Mode","","Simplifies 1 on 1 action",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, {"5","Quad Rounds...","","Number of rounds in Quad mode. Usually 2",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, {"6","Quad Round Time...","","Round time for each quad round",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, - {"7","Login Required","","Require players to log in",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_FoLoginRequired(TRUE);},MENU_BORDER_WARNING}, + {"7","Rated/Unrated","","Will player ratings be affected?",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_FoMatchRated(TRUE);},MENU_BORDER_WARNING}, {"8","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BG_DARK}, {"9","Force Start","","Skip prematch and start the game\nPlease use sparingly",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, MenuSpacer, @@ -443,7 +455,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { FO_MENU_ADMIN_MODES.options[3].value = modeStatus(SERVER_ADMIN.duelmode); FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); - FO_MENU_ADMIN_MODES.options[6].value = modeStatus(SERVER_ADMIN.fo_login_required); + FO_MENU_ADMIN_MODES.options[6].value = ratedStatus(SERVER_ADMIN.fo_matchrated); FO_MENU_ADMIN_MODES.options[7].value = SERVER_ADMIN.captainmode?"on":"off"; } }; @@ -606,10 +618,11 @@ var fo_menu FO_MENU_ADMIN_QUAD_TIMELIMIT = { {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, }, 11, TRUE }; -var fo_menu FO_MENU_ADMIN_FO_LOGIN_REQUIRED = { - [0,0], [300,200], "Login Required?", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { - {"1","On","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fologinrequired 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, - {"2","Off (Match Not Reported)","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fologinrequired 0\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, +var fo_menu FO_MENU_ADMIN_MATCH_RATED = { + [0,0], [300,200], "Match Rated?", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { + {"1","Rated","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"2","Unrated","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 0\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"3","Default","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 2\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, }, 4, TRUE @@ -1195,10 +1208,10 @@ void FO_Menu_Admin_QuadTimelimit(float force) = { CurrentMenu = &FO_MENU_ADMIN_QUAD_TIMELIMIT; fo_hud_menu_active = TRUE; } -void FO_Menu_Admin_FoLoginRequired(float force) = { +void FO_Menu_Admin_FoMatchRated(float force) = { if(fo_hud_menu_active && !force) return; - CurrentMenu = &FO_MENU_ADMIN_FO_LOGIN_REQUIRED; + CurrentMenu = &FO_MENU_ADMIN_MATCH_RATED; fo_hud_menu_active = TRUE; } void FO_Menu_Admin_Timelimit(float force) = { @@ -1380,7 +1393,7 @@ void FO_Hud_Init() { INIT_MENU_IDS(FO_MENU_ADMIN_PLAYERS); INIT_MENU_IDS(FO_MENU_ADMIN_ROUNDS); INIT_MENU_IDS(FO_MENU_ADMIN_QUAD_TIMELIMIT); - INIT_MENU_IDS(FO_MENU_ADMIN_FO_LOGIN_REQUIRED); + INIT_MENU_IDS(FO_MENU_ADMIN_MATCH_RATED); INIT_MENU_IDS(FO_MENU_ADMIN_TIMELIMIT); INIT_MENU_IDS(FO_MENU_ADMIN_FRAGLIMIT); INIT_MENU_IDS(FO_MENU_VOTE); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index c6a753d9..481527fe 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1266,6 +1266,24 @@ float (string arg1, string arg2, string arg3) ParseCmds = { UpdateAllAdmins(); } break; + case "fo_matchrated": + processedCmd = TRUE; + if(arg2) { + localcmd ("localinfo fo_matchrated ",arg2,"\n"); + + switch(stof(arg2)) { + case 0: + bprint(PRINT_HIGH, "Next match will not be rated\n"); + break; + case 1: + bprint(PRINT_HIGH, "Next match will be rated\n"); + break; + case 2: + bprint(PRINT_HIGH, "Next match will only be rated if more there are than 2 players on each team\n"); + } + UpdateAllAdmins(); + } + break; case "captainmode": processedCmd = TRUE; if(arg2 && arg3) { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 645dfbc1..2dff5fc4 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -178,6 +178,7 @@ void Update_ServerAdminInfo(entity pl) = { WriteFloat(MSG_MULTICAST, infokeyf(world, "rounds")); WriteFloat(MSG_MULTICAST, infokeyf(world, "round_time")); WriteFloat(MSG_MULTICAST, (fo_login_required?1:0) + (flr?2:0)); + WriteFloat(MSG_MULTICAST, CF_GetSetting("mra", "fo_matchrated", "2")); WriteFloat(MSG_MULTICAST, infokeyf(world, "timelimit")); WriteFloat(MSG_MULTICAST, infokeyf(world, "fraglimit")); WriteFloat(MSG_MULTICAST, (clanbattle?1:0) + (cm?2:0)); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 1aea5d3e..3f673ad0 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -12,15 +12,20 @@ void () PostFOQuadStarted = { return; } - // Override 2v2 to go to scrim results for now. - string channel_id = discord_channel_id; - if (TeamFortress_TeamGetNoPlayersExcludingAllTime(1) <= 2) - channel_id = "1147341454851719219"; - local string data = ""; - data = strcat(data, "{\n"); data = strcat(data, " \"match\": {\n"); + + local float rated = CF_GetSetting("mra", "fo_matchrated", "2"); + if (rated == 2) { + if(TeamFortress_TeamGetNoPlayersExcludingAllTime(1) > 2) { + rated = 1; + } else { + rated = 0; + } + } + data = strcat(data, " \"rated\": \"", ftos(rated), "\",\n"); + data = strcat(data, " \"round\": \"", ftos(rounds), "\",\n"); data = strcat(data, " \"map\": \"", mapname, "\",\n"); @@ -41,9 +46,11 @@ void () PostFOQuadStarted = { data = strcat(data, " \"name\": \"", infokey(world, "hostname"), "\",\n"); data = strcat(data, " \"address\": \"", cvar_string("sv_serverip"), "\"\n"); data = strcat(data, " },\n"); + data = strcat(data, " \"discord_channel\": {\n"); - data = strcat(data, " \"channel_id\": \"", channel_id, "\"\n"); + data = strcat(data, " \"channel_id\": \"", discord_channel_id, "\"\n"); data = strcat(data, " },\n"); + data = strcat(data, " \"teams\": {\n"); local float tn; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 544393c4..65483512 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -621,6 +621,7 @@ float walls_block_emp; float new_emp; float fo_sentry_targeting; // new improved targeting for sentry guns float cb_keepteams; +float fo_matchrated; float fo_flashtime; float fo_repair_ratio; float solid_nailgren; From ce8f7a703491b656fc54f6c4f937caa99396f5b9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Oct 2023 02:46:48 +1100 Subject: [PATCH 2233/2474] Fix pre-existing styling issues with existing admin menu --- csqc/menu.qc | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index dc466776..d3bc6d53 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -441,13 +441,12 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"5","Quad Rounds...","","Number of rounds in Quad mode. Usually 2",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, {"6","Quad Round Time...","","Round time for each quad round",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, {"7","Rated/Unrated","","Will player ratings be affected?",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_FoMatchRated(TRUE);},MENU_BORDER_WARNING}, - {"8","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BG_DARK}, + {"8","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BORDER_WARNING}, {"9","Force Start","","Skip prematch and start the game\nPlease use sparingly",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, - MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, {"+","Next - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, {"-","Prev - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, - }, 14, TRUE, { + }, 12, TRUE, { updateAdminMenuInfo(); FO_MENU_ADMIN_MODES.options[0].value = modeStatus(SERVER_ADMIN.pubmode); FO_MENU_ADMIN_MODES.options[1].value = modeStatus(SERVER_ADMIN.clanmode); @@ -463,15 +462,17 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { [0,0], [300,300], "Settings [3/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Timelimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Timelimit(TRUE);},MENU_BORDER_WARNING}, {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Fraglimit(TRUE);},MENU_BORDER_WARNING}, -// {"3","Override Classes","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, -// {"4","Class Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, -// {"5","Spurs","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, -// {"6","Spur Settings...","","",FO_MENU_STATE_NORMAL,{print("not implemented\n");},MENU_BG_DARK}, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, {"+","Next - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, {"-","Prev - Modes","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, - }, 6, TRUE, { + }, 12, TRUE, { updateAdminMenuInfo(); FO_MENU_ADMIN_SETTINGS.options[0].value = ftos(SERVER_ADMIN.timelimit); FO_MENU_ADMIN_SETTINGS.options[1].value = ftos(SERVER_ADMIN.fraglimit); @@ -529,12 +530,10 @@ var fo_menu FO_MENU_ADMIN_PLAYERS = { {"7","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(6, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, {"8","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(7, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, {"9","","","",FO_MENU_STATE_NORMAL,{execute_admin_players(8, FO_MENU_ADMIN_PLAYERS.page);},MENU_BG_DARK}, - MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, - MenuSpacer, {"+","Next","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Players(TRUE, player_menu_type, FO_MENU_ADMIN_PLAYERS.page + 1);},MENU_BUTTON}, {"-","Prev","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Players(TRUE, player_menu_type, FO_MENU_ADMIN_PLAYERS.page - 1);},MENU_BUTTON}, - }, 14, TRUE + }, 12, TRUE }; void action_admin_players(float type) = { string n, team; @@ -620,12 +619,12 @@ var fo_menu FO_MENU_ADMIN_QUAD_TIMELIMIT = { }; var fo_menu FO_MENU_ADMIN_MATCH_RATED = { [0,0], [300,200], "Match Rated?", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { - {"1","Rated","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, - {"2","Unrated","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 0\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, - {"3","Default","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 2\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"1","Rated","","Match result will affect player ratings",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"2","Unrated","","Match result will not affect player ratings",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 0\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"3","Default","Only matches with a teamsize of three or more will be rated","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 2\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, - }, 4, TRUE + }, 5, TRUE }; var fo_menu FO_MENU_ADMIN_TIMELIMIT = { [0,0], [300,200], "Set Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { From 5129d9b2b832ad25f5a236bdfd66b84f8aa27eb6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 9 Oct 2023 02:53:57 +1100 Subject: [PATCH 2234/2474] More styling fixes --- csqc/menu.qc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index d3bc6d53..0c76534e 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -621,10 +621,15 @@ var fo_menu FO_MENU_ADMIN_MATCH_RATED = { [0,0], [300,200], "Match Rated?", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Rated","","Match result will affect player ratings",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, {"2","Unrated","","Match result will not affect player ratings",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 0\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, - {"3","Default","Only matches with a teamsize of three or more will be rated","",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 2\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + {"3","Default","","Only matches with a teams of three or more players will be rated",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 2\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, - }, 5, TRUE + }, 10, TRUE }; var fo_menu FO_MENU_ADMIN_TIMELIMIT = { [0,0], [300,200], "Set Timelimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { @@ -637,9 +642,8 @@ var fo_menu FO_MENU_ADMIN_TIMELIMIT = { {"7","45","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 45\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"8","60","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 60\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"9","120","","",FO_MENU_STATE_NORMAL,{localcmd("cmd timelimit 120\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, - MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, - }, 11, TRUE + }, 10, TRUE }; var fo_menu FO_MENU_ADMIN_FRAGLIMIT = { [0,0], [300,200], "Set Fraglimit", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { @@ -652,9 +656,8 @@ var fo_menu FO_MENU_ADMIN_FRAGLIMIT = { {"7","50","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 50\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"8","100","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 100\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, {"9","200","","",FO_MENU_STATE_NORMAL,{localcmd("cmd fraglimit 200\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, - MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, - }, 11, TRUE + }, 10, TRUE }; var fo_menu FO_MENU_VOTE = { [0,0], [300,200], "Map Vote", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES, { @@ -662,11 +665,14 @@ var fo_menu FO_MENU_VOTE = { {"2","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[1].name,"\n");Menu_Cancel();},MENU_BUTTON}, {"3","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[2].name,"\n");Menu_Cancel();},MENU_BUTTON}, {"4","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[3].name,"\n");Menu_Cancel();},MENU_BUTTON}, - MenuSpacer, {"5","","","",FO_MENU_STATE_NORMAL,{localcmd("cmd votemap ",FO_MENU_VOTE.options[5].name,"\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, - }, 8, TRUE, { + }, 10, TRUE, { FO_MENU_VOTE.title = strcat("Map Vote (", ftos(ceil(mapvote_expiry - time)), "s left)"); if((mapvote_expiry - time) < 0) { Menu_Cancel(); From cff8c0cfb763a638e140e3011247393cc2cf7a33 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 7 Oct 2023 00:43:15 -0700 Subject: [PATCH 2235/2474] pm: use only partial replay for error correction --- csqc/pmove.qc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 897915a2..3730f86d 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -384,17 +384,23 @@ static void PM_UpdateError() { pm.errortime = 0; return; } + static PMS_Data last; + + if (!last.seq) + last = pm_so; // Run prior prediction to present. - PM_RunMovement(&pm_so, clientcommandframe); + PM_RunMovement(&last, clientcommandframe); vector err = ent.origin; // Repeat with updated state. - PM_RunMovement(&pm_s, clientcommandframe); + PM_RunMovement(SimPMSD(), clientcommandframe - 1); + PM_SavePMS(&last); // Save at -1 since the construction for #cf will be partial + PM_RunMovement(SimPMSD(), clientcommandframe); err -= ent.origin; float nerr = vlen(err); - if (nerr > 128) { // teleport + if (nerr > 64) { // teleport pm.error = '0 0 0'; pm.errortime = 0; } else { // figure out the error amount, and add it to accumulated lerp @@ -629,7 +635,7 @@ static void PMD_UpdateImpulse(int seq) { return; old_seq = seq; - float cseq = clientcommandframe - 1; + float cseq = clientcommandframe; if (PM_Enabled()) PM_RunMovement(SimPMSD(), cseq); From 27b76022f99ec087e1e5f6502b42214445dccd99 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 5 Oct 2023 12:16:07 -0700 Subject: [PATCH 2236/2474] weapons: refactor damage and knock calculations Only (tiny) difference is take a floor out to make it slightly less discrete for when things don't line up to the decimal. --- share/classes.qc | 6 ++++ share/commondefs.qc | 1 + share/prediction.qc | 1 + share/weapons.qc | 37 ++++++++++++++++++++++ ssqc/combat.qc | 75 +++++++++++++-------------------------------- 5 files changed, 66 insertions(+), 54 deletions(-) diff --git a/share/classes.qc b/share/classes.qc index 1d651b99..25048ce2 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -158,3 +158,9 @@ void Conc_Update(ConcState *cs, entity ent, float ctime) { } #endif } + +float Class_ScaleMoment(float playerclass, float damage) { + if (playerclass != PC_HVYWEAP) + return damage; + return damage <= 50 ? 0 : damage / 4; +} diff --git a/share/commondefs.qc b/share/commondefs.qc index 69b7b361..a6bc12d4 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -52,6 +52,7 @@ var struct { float gren_beta_disable; float fo_concuss; + float rj; } fo_config; enumflags { diff --git a/share/prediction.qc b/share/prediction.qc index c1d4ea8d..f6165183 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -759,6 +759,7 @@ static void WeaponPred_CheckConfigUpdate() { CONFIG_UPDATE(TRUE, "tfx", tfx_flags); CONFIG_UPDATE(TRUE, "clown", clown_flags); CONFIG_UPDATE(FALSE, "clown_grav", clown_grav); + CONFIG_UPDATE(FALSE, "rj", rj); CLAMP_UPDATE(dynamic_newmis_ms, 0, fo_config.static_newmis_ms); CLAMP_UPDATE(max_rewind_ms, 0, 250); diff --git a/share/weapons.qc b/share/weapons.qc index abbd757f..dccb3480 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -829,3 +829,40 @@ void FO_Weapons_Init() { } } +enumflags { + KF_SRC_PLAYER, + KF_TARG_PLAYER, + KF_SELF, + KF_QUAD, +}; + +const float KF_BOTH_PLAYER = KF_SRC_PLAYER | KF_TARG_PLAYER; + +// (*) Unbelievably knock-direction and moment calculation use different origins +// (centroid vs origin). For now just preserve what I can only assume is an old +// terrible mistake. + +float CalcRadiusDamage(entity src, entity targ, float flags, float damage) { + vector targ_origin = (targ.absmin + targ.absmax) * 0.5; // (*) + damage -= vlen(src.origin - targ_origin) / 2; + + if (flags & KF_SELF) + damage *= 0.75; + + return damage; +} + +vector CalcKnock(entity src, entity targ, float flags, float moment) { + float mult = 8; + if (moment < 60 && (flags & (KF_BOTH_PLAYER | KF_SELF) == KF_BOTH_PLAYER)) + mult = 11; + + vector src_origin = (src.absmin + src.absmax) * 0.5; // (*) + vector dir = normalize(targ.origin - src_origin); + + vector result = dir * moment * mult; + if (fo_config.rj > 1) + result += dir * moment * fo_config.rj; + + return result; +} diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 1925bee4..e7fb3c2a 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -489,6 +489,7 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, local float no_damage; local float original_damage = damage; + if (targ.takedamage == 0) return; @@ -499,19 +500,26 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, if (cease_fire) return; + float fl = 0; + if (attacker.classname == "player") + fl |= KF_SRC_PLAYER; + if (targ.classname == "player") + fl |= KF_TARG_PLAYER; + if (targ == attacker) + fl |= KF_SELF; + no_damage = 0; if (targ.tfstate & TFSTATE_BURNING) damage *= PC_PYRO_BURN_DAMAGE_AMP; - if (attacker.classname == "player") { - + if (fl & KF_SRC_PLAYER) { damage = damage * 0.9; if (attacker.super_damage_finished > time) damage = damage * 4; - if ((targ.classname != "player") + if ((fl & KF_TARG_PLAYER == 0) && (targ.classname != "bot") && (targ.classname != "building_sentrygun") && (targ.classname != "building_dispenser") @@ -537,35 +545,24 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, damage = TeamEqualiseDamage(targ, attacker, damage); if ((targ.armorclass != 0) && (T_AttackType != 0)) { - - if ((targ.armorclass & AT_SAVESHOT) && (T_AttackType & TF_TD_SHOT)) { + if ((targ.armorclass & AT_SAVESHOT) && (T_AttackType & TF_TD_SHOT)) damage = floor(damage * 0.5); - } - if ((targ.armorclass & AT_SAVENAIL) && (T_AttackType & TF_TD_NAIL)) { + if ((targ.armorclass & AT_SAVENAIL) && (T_AttackType & TF_TD_NAIL)) damage = floor(damage * 0.5); - } - if ((targ.armorclass & AT_SAVEEXPLOSION) && - (T_AttackType & TF_TD_EXPLOSION)) { + if ((targ.armorclass & AT_SAVEEXPLOSION) && (T_AttackType & TF_TD_EXPLOSION)) damage = floor(damage * 0.5); - } - if ((targ.armorclass & AT_SAVEELECTRICITY) && - (T_AttackType & TF_TD_ELECTRICITY)) { + if ((targ.armorclass & AT_SAVEELECTRICITY) && (T_AttackType & TF_TD_ELECTRICITY)) damage = floor(damage * 0.5); - } - if ((targ.armorclass & AT_SAVEFIRE) && (T_AttackType & TF_TD_FIRE)) { + if ((targ.armorclass & AT_SAVEFIRE) && (T_AttackType & TF_TD_FIRE)) damage = floor(damage * 0.5); - } } if (T_flags & TF_TD_IGNOREARMOR) { - take = damage; save = 0; - } else { - save = ceil(targ.armortype * damage); - if ((attacker.classname == "player") + if ((fl & KF_SRC_PLAYER) && (targ.team_no > 0) && (targ.team_no == attacker.team_no) && (targ != attacker) @@ -606,39 +603,14 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, targ.dmg_inflictor = inflictor; } - damage = floor(damage); if (!(T_AttackType & TF_TD_NOMOMENTUM) && damage) { if ((inflictor != world) && (targ.movetype == MOVETYPE_WALK) && !(targ.tfstate & TFSTATE_CANT_MOVE)) { if (deathmsg != DMSG_GREN_NAIL && deathmsg != DMSG_GREN_SHOCK && deathmsg != DMSG_GREN_BURST) { targ.immune_to_check = time + damage / 20; - dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; - dir = normalize(dir); - float moment = damage; - - if (targ.playerclass == PC_HVYWEAP) { - moment = moment / 4; - - if (damage <= 50) - moment = 0; - } - if ((moment < 60) - && (attacker.classname == "player") - && (targ.classname == "player") - && (attacker.netname != targ.netname)) { - - targ.velocity = targ.velocity + dir * moment * 11; - - } else - targ.velocity = targ.velocity + dir * moment * 8; - - if ((rj > 1) && (attacker.classname == "player") - && (targ.classname == "player") - && (attacker.netname == targ.netname)) { - - targ.velocity = targ.velocity + dir * moment * rj; - } + float moment = Class_ScaleMoment(targ.playerclass, damage); + targ.velocity += CalcKnock(inflictor, targ, fl, moment); } } } @@ -786,13 +758,8 @@ void (entity inflictor, entity attacker, float damage, if (!e.takedamage) continue; - org = e.origin + (e.mins + e.maxs) * 0.5; - points = 0.5 * vlen(inflictor.origin - org); - if (points < 0) - points = 0; - points = damage - points; - if (e == attacker) - points = points * 0.75; + float fl = e == attacker ? KF_SELF : 0; + points = CalcRadiusDamage(inflictor, e, fl, damage); if (points > 0) { if (CanDamage(e, inflictor)) { From 76e278753f5c768a2308ee580fd6b832643e85e1 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 8 Oct 2023 02:40:40 -0700 Subject: [PATCH 2237/2474] pm: fix spectating player with pmove Future is to just integrate spec, but this is a quick fix. --- csqc/pmove.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 3730f86d..1fc7a30b 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -473,7 +473,8 @@ void PM_SyncTo(float seq) { void PM_Update(float sendflags) { float was_enabled = PM_Enabled(); - float enabled = pstate_server.predict_flags & PF_PMOVE; + float enabled = (pstate_server.predict_flags & PF_PMOVE) && + game_state.is_player; if (enabled != was_enabled || game_state.is_player != prev_game_state.is_player) From 5687c9193ba097666e386ac582c92b4f872dfa98 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 6 Oct 2023 23:59:00 -0700 Subject: [PATCH 2238/2474] pmove: initial framework for incorporating explosion nudges --- csqc/pmove.qc | 294 +++++++++++++++++++++++++++++++++-------- csqc/weapon_predict.qc | 21 ++- share/physics.qc | 14 +- share/prediction.qc | 45 ++++++- ssqc/combat.qc | 2 +- ssqc/qw.qc | 1 + ssqc/weapons.qc | 13 +- 7 files changed, 318 insertions(+), 72 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 1fc7a30b..76fff3cd 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -14,18 +14,17 @@ enumflags { // state. In the case that `seq == commandclientframe` this could only be // partially true since the input_*s (in particular, timelength) are not // constant for this frame. -struct PMS_Data { +static struct PMS_Data { vector org, vel; float seq, server_seq; float interp_t; } pm_s, pm_so, pm_c; -struct { +static struct { entity ent; float last_vel_z; PMS_Data* active_pmsd; - float seq, server_seq; float interp_t; @@ -172,6 +171,7 @@ DEFCVAR_FLOAT(fopm_nocache, 0); DEFCVAR_FLOAT(fopm_nostep, 0); DEFCVAR_FLOAT(fopm_nonudge, 0); DEFCVAR_FLOAT(fopm_errortime, 0); +DEFCVAR_FLOAT(fopm_debug, 0); DEFCVAR_FLOAT(fopmd_graph_x, -10); DEFCVAR_FLOAT(fopmd_graph_y, 100); @@ -192,7 +192,7 @@ DEFCVAR_FLOAT(fopmd_graph, 0); static const float NHIST = 21; struct PM_History { vector org, vel; - vector seq; + float seq; }; static PM_History hist[NHIST]; @@ -246,67 +246,236 @@ static PMS_Data* SimPMSD() { void PM_InputFrame(); enum { + NT_EMPTY, NT_CONC, NT_DASH, + NT_EXPLOSION, +}; + +enum { + NA_NONE, + NA_SEQ, + NA_SEQTIME, + NA_ITIME, }; struct PM_Nudge { - float itime, type; - vector nudge; + entity src; + float src_no; + + float nat; + float seq, itime, type; + float expire_frame; + + vector vec; + float aux; }; -static PM_Nudge nudges[10]; +static PM_Nudge nudges[5]; static float num_nudges; -void PM_AddConcNudge(float itime, float mag, float flip) { +static float nudge_expired(PM_Nudge* n) { + // Below all actually expire at <= so this is conservative. + if (n->expire_frame && n->expire_frame < servercommandframe) + return TRUE; + + switch (n->nat) { + case NA_NONE: return TRUE; + case NA_SEQ: return n->seq < servercommandframe; + case NA_SEQTIME: return n->seq + ceil(n->itime / SERVER_FRAME_DT) < servercommandframe; + case NA_ITIME: return n->itime < pstate_server.server_time; + } + + return TRUE; +} + +static PM_Nudge* find_nudge_slot() { + for (float i = 0; i < nudges.length; i++) { + PM_Nudge* n = &nudges[(num_nudges++) % nudges.length]; + + if (!nudge_expired(n)) + continue; + + n->nat = NA_NONE; + n->src_no = 0; + n->src = 0; + n->expire_frame = 0; + return n; + } + + if (CVARF(fopm_debug)) + printf("ERROR: no nudge slots!\n"); + return 0; +} + +.PM_Nudge* nudge; + +static void PM_RemoveSelfNudges() { + if (!self.nudge) + return; + + PM_Nudge* n = self.nudge; + n->expire_frame = -servercommandframe; +} + +void PM_AddNudgeConc(float itime, float mag, float flip) { // This is kind of painful but not much easier.. static float filter_itime; if (itime <= filter_itime) return; filter_itime = itime; - PM_Nudge* n = &nudges[(num_nudges++) % nudges.length]; + PM_Nudge* n = find_nudge_slot(); + if (!n) + return; n->type = NT_CONC; n->itime = itime; - n->nudge.x = mag; - n->nudge.y = flip; + n->vec.x = mag; + n->vec.y = flip; } static void PM_NudgeConc(PM_Nudge* nudge, entity ent) { if (pointcontents(ent.origin) == CONTENT_WATER) ent.flags |= FL_INWATER; // pmove doesn't usually maintain this. - Conc_Stumble(ent, nudge->nudge.x, nudge->nudge.y); + Conc_Stumble(ent, nudge->vec.x, nudge->vec.y); } static void PM_NudgeDash(PM_Nudge* nudge, entity ent) { - ent.velocity = nudge->nudge; + ent.velocity = nudge->vec; } -void PM_AddDashNudge(float itime) { - PM_Nudge* n = &nudges[(num_nudges++) % nudges.length]; +void PM_AddNudgeDash(float itime) { + PM_Nudge* n = find_nudge_slot(); + if (!n) + return; n->type = NT_DASH; n->itime = itime; - n->nudge = v_forward * 540; - n->nudge.z = 181 + SERVER_FRAME_DT * 800; // TODO: fix this... + n->vec = v_forward * 540; + n->vec.z = 181 + SERVER_FRAME_DT * 800; // TODO: fix this... +} + +float nudge_i(PM_Nudge* n) { + for (float i = 0; i < nudges.length; i++) + if (&nudges[i] == n) + return i; + return -1; +} + +static void PM_NudgeExplosion(PM_Nudge* nudge, entity ent) { + float dmg = nudge->aux; + if (vlen(ent.origin - nudge->vec) > dmg + 40) + return; + + float flg = KF_BOTH_PLAYER; + if (nudge->src.owner == pengine.player_ent) + flg |= KF_SELF; + + dmg *= 0.9; // Assume everything is from a player + float moment = CalcRadiusDamage(nudge->src, ent, flg, dmg); + vector knock = CalcKnock(nudge->src, ent, flg, moment); + + pm.ent.velocity += knock; +} + +// Can be either by {seq + itime} for predicted projectiles, or by {itime} for +// server projectiles. +void PM_AddNudgeExplosion(float nat, float seq, float itime, entity ent, float dmg) { + if (vlen(PM_Org() - ent.origin) > dmg * 3) // Fine tune this.. + return; + + PM_Nudge* n = find_nudge_slot(); + if (!n) + return; + + n->type = NT_EXPLOSION; + n->nat = nat; + n->seq = seq; + n->itime = itime; + n->vec = ent.origin; // We end up mostly using the ent here + n->aux = dmg; + + n->src = ent; + n->src_no = ent.entnum; + + ent.nudge = n; + + ent.removefunc = PM_RemoveSelfNudges; +} + +DEFCVAR_FLOAT(fo_beta_nudge_explosion, 0); +void PM_AddSimExplosion(float itime, entity ent) { + if (!PM_Enabled() || !CVARF(fo_beta_nudge_explosion)) + return; + + if (ent.owner != pengine.player_ent) // Just player ents in version 0 + return; + + float dmg = 0; + switch (ent.fpp.index) { + case FPP_ROCKET: + case FPP_INCENDIARY: + dmg = 92; + break; + default: + return; // Not recognized + } + + float seq = 0, nat = NA_ITIME; + if (ent.forward_knock && ent.owner == pengine.player_ent) { + if (ent.forward_knock == -1) + return; + itime = ent.forward_knock; + } else if (ent.created_seq && ent.entnum == 0) { + float dtime = 0; + if (ent.s_time) + dtime = max(itime - ent.s_time - SERVER_FRAME_DT, 0); + seq = ent.created_seq; + itime = dtime; + nat = NA_SEQTIME; // Same as NA_SEQ when itime == 0 + } + + PM_AddNudgeExplosion(nat, seq, itime, ent, dmg); +} + +float MatchNudge(PM_Nudge* n, float seq, float sitime, float eitime) { + if (n->expire_frame && n->expire_frame < pm.server_seq) { + return FALSE; + } + + switch (n->nat) { + case NA_SEQ: return n->seq == seq; + case NA_SEQTIME: return n->seq + floor(n->itime / SERVER_FRAME_DT) == seq; + case NA_ITIME: return n->itime > sitime && n->itime <= eitime; + default: + return FALSE; + } } // TODO: This obviously wants to be smarter -static void PM_ApplyNudges(entity ent, float sitime, float eitime) { +static vector PM_ApplyNudges(entity ent, float seq, float sitime, float eitime) { + vector result = '0 0 0'; for (float i = 0; i < nudges.length; i++) { PM_Nudge* n = &nudges[i]; - if (n->itime >= sitime && n->itime < eitime) { - switch (n->type) { - case NT_CONC: - PM_NudgeConc(n, ent); - break; - case NT_DASH: - PM_NudgeDash(n, ent); - break; - } + + if (!MatchNudge(n, seq, sitime, eitime)) + continue; + + switch (n->type) { + case NT_CONC: + PM_NudgeConc(n, ent); + break; + case NT_DASH: + PM_NudgeDash(n, ent); + break; + case NT_EXPLOSION: + PM_NudgeExplosion(n, ent); + break; } } + + return result; } static void RunPlayerPhysics() { @@ -316,10 +485,12 @@ static void RunPlayerPhysics() { runstandardplayerphysics(ent); } +// End state: +// pmsd.seq --> endframe + 1 static void PM_RunMovement(PMS_Data* pmsd, float endframe) { entity ent = pm.ent; - if (pm.active_pmsd != pmsd || endframe < pm.seq) { + if (pm.active_pmsd != pmsd || pm.seq > endframe) { ASSERTF_GT(endframe, pm.server_seq); PM_ActivatePMS(pmsd); } @@ -328,9 +499,12 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { pm.seq = clientcommandframe; //just update the angles if (!getinputstate(pm.seq-1)) { } - return; + return; } + ASSERTF_GT(pm.seq, 0); + + pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing while (pm.seq <= endframe) { if (!getinputstate(pm.seq)) break; @@ -342,8 +516,9 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { RunPlayerPhysics(); - if (!CVARF(fopm_nonudge) && pm.seq < clientcommandframe) - PM_ApplyNudges(ent, pm.interp_t, pm.interp_t + input_timelength); + if (!CVARF(fopm_nonudge)) { + PM_ApplyNudges(ent, pm.seq, pm.interp_t, pm.interp_t + input_timelength); + } pm.seq++; pm.interp_t += input_timelength; @@ -379,14 +554,15 @@ static void PM_UpdateError() { entity ent = pm.ent; ent.owner = edict_num(player_localentnum); - if (CVARF(fopm_noerror)) { + if (CVARF(fopm_noerror) || + (clientcommandframe == servercommandframe + 1)) { pm.error = '0 0 0'; pm.errortime = 0; return; } static PMS_Data last; - if (!last.seq) + if (last.server_seq != pm_s.server_seq - 1) last = pm_so; // Run prior prediction to present. @@ -400,6 +576,7 @@ static void PM_UpdateError() { err -= ent.origin; float nerr = vlen(err); + if (nerr > 64) { // teleport pm.error = '0 0 0'; pm.errortime = 0; @@ -407,9 +584,9 @@ static void PM_UpdateError() { pm.error *= max(pm.errortime - time, 0) / ErrorTime(); pm.error += err; - if (vlen(pm.error) > 1) + if (vlen(pm.error) > 1) { pm.errortime = time + ErrorTime(); - else { + } else { pm.error = '0 0 0'; pm.errortime = 0; } @@ -471,6 +648,24 @@ void PM_SyncTo(float seq) { PM_Sounds(jumping, jump_frame, landing, pm.last_vel_z); } +static void PM_HandleRemovedNudges() { + if (!pstate_server.num_filter_ents) + return; + + for (float i = 0; i < nudges.length; i++) { + PM_Nudge* n = &nudges[i]; + if (nudge_expired(n)) + continue; + + for (float j = 0; j < pstate_server.num_filter_ents; j++) { + if (n->src_no == pstate_server.filter_ents[j]) { + n->nat = NA_SEQ; + n->seq = n->expire_frame = pstate_server.seq; + } + } + } +} + void PM_Update(float sendflags) { float was_enabled = PM_Enabled(); float enabled = (pstate_server.predict_flags & PF_PMOVE) && @@ -483,6 +678,8 @@ void PM_Update(float sendflags) { if (sendflags & FOWP_PMOVE == 0) return; + PM_HandleRemovedNudges(); + pm_so = pm_s; pm.server_seq = servercommandframe; pm.seq = servercommandframe + 1; // server state includes move @@ -490,11 +687,10 @@ void PM_Update(float sendflags) { PM_SavePMS(&pm_s); if (!CVARF(fopm_nocache)) { - // Pre-compute predicted movement for all locked frames (e.g. seq < // clientcommandframe) so that we can accelerate the common case of // computation at clientcommandframe (which does require constant - // re-evaluation). In the case there's no separation (e.g. lan pings) then - // the server frame is directly used as the cache frame. + // re-evaluation). In the case there's no separation (e.g. lan pings) + // then the server frame is directly used as the cache frame. if (clientcommandframe > servercommandframe + 1) PM_RunMovement(&pm_s, clientcommandframe - 1); PM_SavePMS(&pm_c); @@ -502,7 +698,6 @@ void PM_Update(float sendflags) { if (enabled && was_enabled) PM_UpdateError(); - PMD_UpdateImpulse(servercommandframe); } @@ -654,26 +849,11 @@ static void PMD_UpdateImpulse(int seq) { PMD_AddPoint(ERROR_VIEW, vlen(pm.error) / 128 * 1200); PM_History* hist = PMH_Get(servercommandframe); + if (!hist) + return; + PMD_AddPoint(ERROR_POS, hist ? vlen(pm_s.org - hist.org) : 0); PMD_AddPoint(ERROR_VEL, hist ? vlen(pm_s.vel - hist.vel) : 0); - -#if 0 - static vector last_sv, last_pv; - float p = FALSE; - if (vlen(sv - last_sv) > 200) { - printf("[%0.3f] S sf=%d st=%0.3f i=%0.3f\n", time, servercommandframe, pm_s.interp_t, vlen(sv-last_sv)); - p = TRUE; - } - last_sv = sv; - - if (vlen(pv - last_pv) > 200) { - printf("[%0.3f] C cf=%d ct=%0.3f i=%0.3f\n", time, clientcommandframe, - pm.interp_t, vlen(pv-last_pv)); - p = TRUE; - } - last_pv = pv; - if (p) printf("\n"); -#endif } static void PMD_Graph(int type, int offset, vector c1, vector c2, vector rgb) { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 56172d16..62aed8c3 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -141,7 +141,6 @@ static void update_avg_ping() { static float fill_avg_ping(float* mean, float* variance) { return read_online_avg(&avg_ping, mean, variance); } - float csqc_get_user_setting(string s_short, string s_long, string def); // Order of preference: @@ -1264,6 +1263,7 @@ entity predicted_projectiles; .float starttime, endtime, p_time; .float traileffectnum; +.float created_seq; struct trail_table_entry { string eff_name[2]; @@ -1338,6 +1338,12 @@ void PP_Cleanup(entity proj) { if (proj.pred_next) proj.pred_next.pred_prev = proj.pred_prev; + if (proj.removefunc) { + entity tmp = self; + self = proj; + self.removefunc(); + self = tmp; + } remove(proj); } @@ -1455,7 +1461,6 @@ entity PP_CreateProjectile(int fpp_type, vector org) { // Note: We use true time here as created projectiles exist outside of pred. proj.starttime = time + uncorrected_dt; - proj.s_time = proj.starttime - static_dt; proj.endtime = proj.starttime + pstate_server.client_ping / 1000.0 + PP_EPS; proj.server_live_time = server_time(); @@ -1478,10 +1483,14 @@ entity PP_CreateProjectile(int fpp_type, vector org) { proj.angles = input_angles; proj.angles[0] *= -1; proj.s_origin = proj.origin; + proj.created_seq = pstate_pred.seq; // Trail starts at 0.05, we, split physics calcs longer than this. float sdt2 = max(static_dt - 0.05, 0); Phys_Init(proj, proj.starttime - sdt2, static_dt - sdt2, PHYSF_CONSUME_ALL); + + proj.s_time = proj.phys_time; // Set after static_dt processed. + proj.oldorigin = proj.origin; if (sdt2 > 0) Phys_Advance(proj, sdt2, PHYSF_CONSUME_ALL); @@ -1828,6 +1837,9 @@ void InitProjectileEnt(float sendflags) { self.fpp.index = FPP_RAILGUN; // Something people will notice. } + self.server_live_time = self.created_at; + self.created_seq = servercommandframe; + self.drawmask = MASK_ENGINE; self.predraw = PP_PredrawActive; if (sendflags & FOPP_ANGLES == 0) @@ -1839,6 +1851,11 @@ void InitProjectileEnt(float sendflags) { if (self.owner_entnum == pengine.player_entnum) self.owner = pengine.player_ent; + if (self.forward_knock) { + self.phys_sim_voided_at = self.forward_knock; + PM_AddSimExplosion(self.forward_knock, self); + } + float ptime = get_phys_time(self); if (ptime > self.phys_time /* from server */) Phys_Advance(self, ptime, PHYSF_CONSUME_ALL); diff --git a/share/physics.qc b/share/physics.qc index 8b46c592..66e887aa 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -67,15 +67,23 @@ DEFCVAR_FLOAT(fo_phys_debug, 0); .float aiment_num; .float voided; +.float phys_sim_last; +.float phys_sim_voided_at; +var float phys_sim_dt; + float get_phys_time(entity); +void PM_AddSimExplosion(float itime, entity ent); static void Phys_Impact(entity e, float dt, float phys_flags) { other = trace_ent; if (other.solid == SOLID_NOT) return; - if (e.movetype == MOVETYPE_FLYMISSILE) + if (e.movetype == MOVETYPE_FLYMISSILE) { e.voided = TRUE; + if (!e.phys_sim_voided_at) // want only one of sim or !sim + PM_AddSimExplosion(e.phys_time + dt, e); + } AugmentGrenadeImpact(); @@ -287,10 +295,6 @@ float Phys_Init(entity e, float target_time, float delta, float phys_flags) { } #ifdef CSQC -.float phys_sim_last; -.float phys_sim_voided_at; -var float phys_sim_dt; - void Phys_Sim(entity e) { // TODO: Unvoid+undo if we make it past the void point. if (phys_sim_dt < 0 || e.phys_sim_voided_at) diff --git a/share/prediction.qc b/share/prediction.qc index f6165183..94b00f9c 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -28,6 +28,7 @@ enumflags { FOWP_RNG1, FOWP_RNG2, FOWP_PREDICT_FLAGS, + FOWP_FILTER_ENTS, FOWP_LAST, }; const float FOWP_ALL = FOWP_LAST - 1; @@ -39,8 +40,10 @@ enumflags { FOPP_ANGLES, FOPP_MOVETYPE, FOPP_EXPIRY, + FOPP_FORWARDKNOCK, }; +.float forward_knock; enumflags { PF_PMOVE, @@ -79,6 +82,13 @@ struct predict_tf_state { float no_grenades_1, no_grenades_2, primed_gren_type, primed_gren_exp; + float num_filter_ents; +#ifdef SSQC + entity filter_ents[4]; +#else + float filter_ents[4]; +#endif + #ifdef CSQC // Used for prediction, not actually communicated. Reset each frame. int seq; @@ -347,6 +357,9 @@ static float Prediction_ChangedMask(entity player, entity src) { if (player.predict_flags & (PF_PMOVE | PF_POS)) mask |= FOWP_PMOVE; + if (player == src) + mask |= FOWP_FILTER_ENTS; + M1(FOWP_CLASS, playerclass); M4(FOWP_IMPULSE, impulse, current_slot.id, queue_slot.id, last_slot.id); M2(FOWP_TFSTATE, tfstate, csqc_maxspeed); @@ -373,13 +386,21 @@ static float Prediction_ChangedMask(entity player, entity src) { if (player.pred_forcebit >= FOWP_LAST) player.pred_forcebit = 1; - if (player.pred_forcebit != FOWP_PMOVE) + if (player.pred_forcebit & (FOWP_PMOVE | FOWP_FILTER_ENTS) == 0) mask |= player.pred_forcebit; } return mask; } +void Predict_AddFilterEnt(entity p, entity filter) { + if (p.predict_flags & PF_PMOVE == 0) + return; + + predict_tf_state* ps = &p.predict_state; + ps->filter_ents[ps->num_filter_ents++] = filter; +} + void Predict_InitPlayer(entity player); void Predict_SyncPmove(float is_player); @@ -464,7 +485,8 @@ void EntUpdate_Config() { #undef COMM #ifdef SSQC -#define COMM(_type, _field) Write##_type(MSG_ENTITY, self.owner.predict_state.##_field) +#define GETF(_field) self.owner.predict_state.##_field +#define COMM(_type, _field) Write##_type(MSG_ENTITY, GETF(_field)) #define COMM_PM(_type, _field) Write##_type(MSG_ENTITY, self.owner.##_field) float WP_SendEntity(entity to_player, float sendflags) { if (to_player != self.owner) @@ -474,7 +496,8 @@ float WP_SendEntity(entity to_player, float sendflags) { WriteFloat(MSG_ENTITY, sendflags); #else entity PM_Ent(); -#define COMM(_type, _field) pstate_server.##_field = Read##_type() +#define GETF(_field) pstate_server.##_field +#define COMM(_type, _field) GETF(_field) = Read##_type() #define COMM_PM(_type, _field) PM_Ent().##_field = Read##_type() void EntUpdate_WeaponPred(float isnew) { @@ -500,6 +523,15 @@ void EntUpdate_WeaponPred(float isnew) { COMM_PM(Short, velocity[2]); } + if (sendflags & FOWP_FILTER_ENTS) { + COMM(Byte, num_filter_ents); + for (float i = 0; i < GETF(num_filter_ents); i++) + COMM(Entity, filter_ents[i]); +#ifdef SSQC + GETF(num_filter_ents) = 0; // Destructive transmission +#endif + } + if (sendflags & FOWP_CLASS) { COMM(Byte, playerclass); } @@ -583,6 +615,8 @@ void EntUpdate_WeaponPred(float isnew) { #endif } #undef COMM +#undef COMM_PM +#undef GETF #ifdef SSQC #define COMM(_type, _field) Write##_type(MSG_ENTITY, self.##_field) @@ -599,6 +633,8 @@ float PP_SendEntity(entity to_player, float sendmask) { sendflags |= FOPP_EXPIRY; if (FPP_Get(self.fpp.index)->movetype != self.movetype) sendflags |= FOPP_MOVETYPE; + if (self.forward_knock) + sendflags |= FOPP_FORWARDKNOCK; } WriteByte(MSG_ENTITY, ENT_PROJECTILE); @@ -653,6 +689,9 @@ void EntUpdate_Projectile(float isnew) { COMMD(Entity, aiment_num, aiment); } + if (sendflags & FOPP_FORWARDKNOCK) + COMM(Float, forward_knock); + #ifdef SSQC return TRUE; #else diff --git a/ssqc/combat.qc b/ssqc/combat.qc index e7fb3c2a..b3541305 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -611,6 +611,7 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, float moment = Class_ScaleMoment(targ.playerclass, damage); targ.velocity += CalcKnock(inflictor, targ, fl, moment); + Predict_AddFilterEnt(targ, inflictor.filter_ent ?: inflictor); } } } @@ -760,7 +761,6 @@ void (entity inflictor, entity attacker, float damage, float fl = e == attacker ? KF_SELF : 0; points = CalcRadiusDamage(inflictor, e, fl, damage); - if (points > 0) { if (CanDamage(e, inflictor)) { // shambler takes half damage from all explosions diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 65483512..1c98aad5 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -799,3 +799,4 @@ float disable_resup_gren; string match_id; string backend_address; float fo_login_required; +.entity filter_ent; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 1878ac86..98d35398 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1033,10 +1033,8 @@ void () BecomeExplosion = { dremove(self); }; -.float al_dmg; - static void Antilag_Knock(entity e) { - T_RadiusDamage(e, e.owner, e.al_dmg, __NULL__, __NULL__, e.owner); + T_RadiusDamage(e, e.owner, e.heat, __NULL__, __NULL__, e.owner); dremove(e); } @@ -1055,11 +1053,13 @@ float AntilagKnock(entity e, float dmg) { entity knock_e = spawn(); setorigin(knock_e, e.origin); + setsize(knock_e, '0 0 0', '0 0 0'); knock_e.s_origin = e.s_origin; knock_e.owner = e.owner; knock_e.classname = e.classname; knock_e.oldenemy = other; - knock_e.al_dmg = dmg; + knock_e.heat = dmg; + knock_e.filter_ent = e; vector diff = e.origin - e.s_origin; float ttime = vlen(diff) / vlen(e.velocity); @@ -1067,8 +1067,10 @@ float AntilagKnock(entity e, float dmg) { if (ttime > SERVER_FRAME_DT) { knock_e.think = T_Knock_Antilag; knock_e.nextthink = time + ttime; + e.forward_knock = time + ttime; } else { Antilag_Knock(knock_e); + e.forward_knock = -1; } return TRUE; @@ -1093,6 +1095,9 @@ void () T_MissileTouch = { entity ignore_self = AntilagKnock(self, dmg) ? self.owner : __NULL__; T_RadiusDamage(self, self.owner, dmg, other, ignore_self); + if (!self.s_time) + self.forward_knock = -1; + self.origin = self.origin - 8 * normalize(self.velocity); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); From 32b1403a90081f87cf1a8314792847e49c2126a5 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 9 Oct 2023 15:19:21 -0700 Subject: [PATCH 2239/2474] pm: bound number of filter ents Quick fix --- share/prediction.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/prediction.qc b/share/prediction.qc index 94b00f9c..b623039e 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -397,6 +397,9 @@ void Predict_AddFilterEnt(entity p, entity filter) { if (p.predict_flags & PF_PMOVE == 0) return; + if (ps->num_filter_ents >= 4); + return + predict_tf_state* ps = &p.predict_state; ps->filter_ents[ps->num_filter_ents++] = filter; } From 15112f5131834553261f270d5482be8aa3c28869 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 9 Oct 2023 15:21:02 -0700 Subject: [PATCH 2240/2474] pm: quick fix disable conc effect --- csqc/weapon_predict.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 62aed8c3..4ae79879 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -2057,7 +2057,7 @@ static void WP_UpdatePredict() { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; PM_SyncTo(pframe); - Conc_Update(&pstate_pred.conc_state, world, pstate_pred.server_time); + /* Conc_Update(&pstate_pred.conc_state, world, pstate_pred.server_time); */ } else { pengine.is_effectframe = FALSE; } From 01ebb2b7169b2645e37e2ca86ed2665daf18fcab Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 9 Oct 2023 15:21:46 -0700 Subject: [PATCH 2241/2474] pm: filter ent quick fix tk2 --- share/prediction.qc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/share/prediction.qc b/share/prediction.qc index b623039e..bfa0d353 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -397,10 +397,9 @@ void Predict_AddFilterEnt(entity p, entity filter) { if (p.predict_flags & PF_PMOVE == 0) return; - if (ps->num_filter_ents >= 4); - return - predict_tf_state* ps = &p.predict_state; + if (ps->num_filter_ents >= 4) + return ps->filter_ents[ps->num_filter_ents++] = filter; } From d5ee5d91d8efec2a3fc2af6df1ae17b4f5e60626 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 9 Oct 2023 21:16:08 -0700 Subject: [PATCH 2242/2474] pm: add prediction for grenades (explosive and conc) --- csqc/pmove.qc | 76 ++++++++++++++++++++++++++++++++++++------ csqc/weapon_predict.qc | 6 ++-- share/physics.qc | 20 +++++++++-- share/weapons.qc | 4 +-- ssqc/scout.qc | 2 ++ ssqc/tfort.qc | 1 + 6 files changed, 91 insertions(+), 18 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 76fff3cd..0d4fcc96 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -239,8 +239,9 @@ static void PM_ActivatePMS(PMS_Data *pmsd) { pm.ent.pmove_flags = 0; // With auto-bunny we only care about clearing }; +static float cache_invalidated; static PMS_Data* SimPMSD() { - return CVARF(fopm_nocache) ? &pm_s : &pm_c; + return (cache_invalidated || CVARF(fopm_nocache)) ? &pm_s : &pm_c; } void PM_InputFrame(); @@ -250,6 +251,7 @@ enum { NT_CONC, NT_DASH, NT_EXPLOSION, + NT_BOUNCE, }; enum { @@ -271,6 +273,7 @@ struct PM_Nudge { float aux; }; +const static float NUDGE_EPS = 3 * SERVER_FRAME_DT; static PM_Nudge nudges[5]; static float num_nudges; @@ -281,9 +284,9 @@ static float nudge_expired(PM_Nudge* n) { switch (n->nat) { case NA_NONE: return TRUE; - case NA_SEQ: return n->seq < servercommandframe; - case NA_SEQTIME: return n->seq + ceil(n->itime / SERVER_FRAME_DT) < servercommandframe; - case NA_ITIME: return n->itime < pstate_server.server_time; + case NA_SEQ: return n->seq >= servercommandframe; + case NA_SEQTIME: return n->seq + ceil(n->itime / SERVER_FRAME_DT) >= servercommandframe; + case NA_ITIME: return n->itime >= pstate_server.server_time + NUDGE_EPS; // Slack } return TRUE; @@ -296,6 +299,7 @@ static PM_Nudge* find_nudge_slot() { if (!nudge_expired(n)) continue; + cache_invalidated = TRUE; n->nat = NA_NONE; n->src_no = 0; n->src = 0; @@ -381,7 +385,7 @@ static void PM_NudgeExplosion(PM_Nudge* nudge, entity ent) { // Can be either by {seq + itime} for predicted projectiles, or by {itime} for // server projectiles. -void PM_AddNudgeExplosion(float nat, float seq, float itime, entity ent, float dmg) { +static void PM_AddNudgeExplosion(float nat, float seq, float itime, entity ent, float dmg) { if (vlen(PM_Org() - ent.origin) > dmg * 3) // Fine tune this.. return; @@ -400,11 +404,58 @@ void PM_AddNudgeExplosion(float nat, float seq, float itime, entity ent, float d n->src_no = ent.entnum; ent.nudge = n; + ent.removefunc = PM_RemoveSelfNudges; +} + +static void PM_AddNudgeBounce(float itime, entity ent, float dmg) { + if (vlen(PM_Org() - ent.origin) > dmg * 3) // Fine tune this.. + return; + + PM_Nudge* n = find_nudge_slot(); + if (!n) + return; + n->type = NT_BOUNCE; + n->nat = NA_ITIME; + n->itime = itime; + n->aux = dmg; + + n->src = ent; + n->src_no = ent.entnum; + + ent.nudge = n; ent.removefunc = PM_RemoveSelfNudges; } -DEFCVAR_FLOAT(fo_beta_nudge_explosion, 0); +static void PM_NudgeBounce(PM_Nudge* nudge, entity ent) { + float dmg = nudge->aux; + entity src = nudge->src; + + if (vlen(ent.origin - src.origin) > dmg + 40) + return; + + vector targ_org = ent.origin + (ent.mins + ent.maxs) * 0.5; + float points = dmg - vlen(targ_org - src.origin) / 2; + + ent.velocity = (targ_org - src.origin) * points/20; +} + + +void PM_AddGrenadeExplosion(float itime, entity ent) { + if (!PM_Enabled() || !CVARF(fo_beta_nudge_explosion)) + return; + + FO_GrenExp exp; + FO_GrenGetExp(ent.fpp.gren_type, exp); + + float dmg = exp.dmg; + + if (exp.type == kRadiusDamage) + PM_AddNudgeExplosion(NA_ITIME, 0, itime, ent, dmg); + else + PM_AddNudgeBounce(itime, ent, dmg); +} + void PM_AddSimExplosion(float itime, entity ent) { if (!PM_Enabled() || !CVARF(fo_beta_nudge_explosion)) return; @@ -454,8 +505,7 @@ float MatchNudge(PM_Nudge* n, float seq, float sitime, float eitime) { } // TODO: This obviously wants to be smarter -static vector PM_ApplyNudges(entity ent, float seq, float sitime, float eitime) { - vector result = '0 0 0'; +static void PM_ApplyNudges(entity ent, float seq, float sitime, float eitime) { for (float i = 0; i < nudges.length; i++) { PM_Nudge* n = &nudges[i]; @@ -472,10 +522,11 @@ static vector PM_ApplyNudges(entity ent, float seq, float sitime, float eitime) case NT_EXPLOSION: PM_NudgeExplosion(n, ent); break; + case NT_BOUNCE: + PM_NudgeBounce(n, ent); + break; } } - - return result; } static void RunPlayerPhysics() { @@ -517,6 +568,9 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { RunPlayerPhysics(); if (!CVARF(fopm_nonudge)) { + float start_time = pm.interp_t; + if (pm.seq == pm.server_seq + 1) + start_time -= NUDGE_EPS; PM_ApplyNudges(ent, pm.seq, pm.interp_t, pm.interp_t + input_timelength); } @@ -576,7 +630,6 @@ static void PM_UpdateError() { err -= ent.origin; float nerr = vlen(err); - if (nerr > 64) { // teleport pm.error = '0 0 0'; pm.errortime = 0; @@ -694,6 +747,7 @@ void PM_Update(float sendflags) { if (clientcommandframe > servercommandframe + 1) PM_RunMovement(&pm_s, clientcommandframe - 1); PM_SavePMS(&pm_c); + cache_invalidated = FALSE; } if (enabled && was_enabled) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 4ae79879..26ce6a86 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -586,6 +586,8 @@ void PredProj_Sound(int proj_type, float vol = 1) { void PM_Update(float sendflags); +DEFCVAR_FLOAT(fo_beta_nudge_explosion, 0); + void WP_ServerUpdate(float sendflags) { pstate_server.seq = servercommandframe; @@ -604,8 +606,8 @@ void WP_ServerUpdate(float sendflags) { pstate_server.weaponframe += 1; } - if (CVARF(fo_wpp_beta) & 4) - phys_sim_dt = (pstate_server.client_ping + 2 * SERVER_FRAME_MS) / 1000.0; + if (CVARF(fo_beta_nudge_explosion)) + phys_sim_dt = (pstate_server.client_ping + 4 * SERVER_FRAME_MS) / 1000.0; else phys_sim_dt = -1; diff --git a/share/physics.qc b/share/physics.qc index 66e887aa..f4e54746 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -60,6 +60,8 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { static vector get_followed_origin() { return self.aiment.origin; } + +static void Phys_Expired(entity e, float phys_flags) {} #else DEFCVAR_FLOAT(fo_phys_debug, 0); @@ -93,7 +95,15 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { get_phys_time(e)); } -static void Phys_Expired(entity e, float phys_flags) {} +void PM_AddGrenadeExplosion(float itime, entity ent); + +static void Phys_Expired(entity e, float phys_flags) { + e.voided = TRUE; + if (e.phys_sim_voided_at) // Only one of sim or !sim + return; + + PM_AddGrenadeExplosion(e.fpp.expires_at, e); +} static vector get_followed_origin() { if (!(float)getentity(self.aiment_num, GE_ACTIVE)) @@ -224,7 +234,7 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { } // If there's an expiry, make sure we get to the exact position. - if (e.fpp.expires_at && target_time > e.fpp.expires_at) { + if (e.fpp.expires_at && target_time >= e.fpp.expires_at) { target_time = e.fpp.expires_at; phys_flags |= PHYSF_CONSUME_ALL; } @@ -280,6 +290,10 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { if (step > 0) // Origin can have moved. setorigin(e, e.origin); + + if (e.fpp.expires_at && e.phys_time >= e.fpp.expires_at) + Phys_Expired(e, phys_flags); + return total; } @@ -301,7 +315,7 @@ void Phys_Sim(entity e) { return; float ptime = time + phys_sim_dt; - if (ptime < self.phys_sim_last + SERVER_FRAME_MS) + if (ptime < self.phys_sim_last + SERVER_FRAME_DT) return; self.phys_sim_last = ptime; diff --git a/share/weapons.qc b/share/weapons.qc index dccb3480..8a0c09c6 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -843,7 +843,7 @@ const float KF_BOTH_PLAYER = KF_SRC_PLAYER | KF_TARG_PLAYER; // terrible mistake. float CalcRadiusDamage(entity src, entity targ, float flags, float damage) { - vector targ_origin = (targ.absmin + targ.absmax) * 0.5; // (*) + vector targ_origin = targ.origin + (targ.mins + targ.maxs) * 0.5; // (*) damage -= vlen(src.origin - targ_origin) / 2; if (flags & KF_SELF) @@ -857,7 +857,7 @@ vector CalcKnock(entity src, entity targ, float flags, float moment) { if (moment < 60 && (flags & (KF_BOTH_PLAYER | KF_SELF) == KF_BOTH_PLAYER)) mult = 11; - vector src_origin = (src.absmin + src.absmax) * 0.5; // (*) + vector src_origin = src.origin + (src.mins + src.maxs) * 0.5; // (*) vector dir = normalize(targ.origin - src_origin); vector result = dir * moment * mult; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 8205ea70..cd8ee594 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -858,6 +858,8 @@ void (entity inflictor, entity attacker, float bounce, && (points > 0)) { head.velocity = org - inflictor.origin; head.velocity = head.velocity * (points / 20); + Predict_AddFilterEnt(head, inflictor); + if (head.classname != "player") { if (head.flags & FL_ONGROUND) head.flags = head.flags - FL_ONGROUND; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 4a5035e6..8d061796 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2420,6 +2420,7 @@ void () TeamFortress_ExplodePerson = { proj.fpp.gren_type = gtype; proj.fpp.flags |= FPF_NO_REWIND; + proj.fpp.expires_at = expires; proj.skin = gdesc->skin; proj.avelocity = gdesc->avelocity; proj.touch = ste->touch; From c2a66bf01ab83750a97c2b8581d4ad057ef9dd1c Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 01:43:18 -0700 Subject: [PATCH 2243/2474] pm: re-enable conc prediction & improve accuracy --- csqc/pmove.qc | 9 +++++++++ csqc/weapon_predict.qc | 2 +- share/classes.qc | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 0d4fcc96..6a6edfdf 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -259,6 +259,7 @@ enum { NA_SEQ, NA_SEQTIME, NA_ITIME, + NA_CONC, // itime but with expiration driven by conc_state }; struct PM_Nudge { @@ -287,6 +288,7 @@ static float nudge_expired(PM_Nudge* n) { case NA_SEQ: return n->seq >= servercommandframe; case NA_SEQTIME: return n->seq + ceil(n->itime / SERVER_FRAME_DT) >= servercommandframe; case NA_ITIME: return n->itime >= pstate_server.server_time + NUDGE_EPS; // Slack + case NA_CONC: return n->itime <= pstate_server.conc_state.next; } return TRUE; @@ -334,6 +336,7 @@ void PM_AddNudgeConc(float itime, float mag, float flip) { return; n->type = NT_CONC; + n->nat = NA_CONC; n->itime = itime; n->vec.x = mag; n->vec.y = flip; @@ -498,6 +501,7 @@ float MatchNudge(PM_Nudge* n, float seq, float sitime, float eitime) { switch (n->nat) { case NA_SEQ: return n->seq == seq; case NA_SEQTIME: return n->seq + floor(n->itime / SERVER_FRAME_DT) == seq; + case NA_CONC: case NA_ITIME: return n->itime > sitime && n->itime <= eitime; default: return FALSE; @@ -710,6 +714,11 @@ static void PM_HandleRemovedNudges() { if (nudge_expired(n)) continue; + if (n->type == NT_CONC && n->itime < pstate_server.conc_state.next) { + n->expire_frame = -1; + continue; + } + for (float j = 0; j < pstate_server.num_filter_ents; j++) { if (n->src_no == pstate_server.filter_ents[j]) { n->nat = NA_SEQ; diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 26ce6a86..77468264 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -2059,7 +2059,7 @@ static void WP_UpdatePredict() { pengine.is_effectframe = TRUE; pengine.last_effectframe = pframe; PM_SyncTo(pframe); - /* Conc_Update(&pstate_pred.conc_state, world, pstate_pred.server_time); */ + Conc_Update(&pstate_pred.conc_state, world, pstate_pred.server_time); } else { pengine.is_effectframe = FALSE; } diff --git a/share/classes.qc b/share/classes.qc index 25048ce2..831dd0db 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -125,10 +125,10 @@ static inline void ConcAction(entity ent, float itime, float mag, float flip) { Conc_Stumble(ent, mag, flip); } #else -void PM_AddConcNudge(float itime, float mag, float flip); +void PM_AddNudgeConc(float itime, float mag, float flip); static inline void ConcAction(entity ent, float itime, float mag, float flip) { - PM_AddConcNudge(itime, mag, flip); + PM_AddNudgeConc(itime, mag, flip); } #endif From 887da6995688b3c2846fb0a06b005f495909fa07 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 01:50:03 -0700 Subject: [PATCH 2244/2474] pm: clean up filter-ent quickfix --- share/prediction.qc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/share/prediction.qc b/share/prediction.qc index bfa0d353..9aa81c13 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -51,6 +51,8 @@ enumflags { PF_PMOVE_ACTIVATING, }; +static float MAX_FILTER_ENTS = 4; + struct predict_tf_state { int playerclass; int predict_flags, effects; @@ -84,9 +86,9 @@ struct predict_tf_state { float num_filter_ents; #ifdef SSQC - entity filter_ents[4]; + entity filter_ents[MAX_FILTER_ENTS]; #else - float filter_ents[4]; + float filter_ents[MAX_FILTER_ENTS]; #endif #ifdef CSQC @@ -398,8 +400,8 @@ void Predict_AddFilterEnt(entity p, entity filter) { return; predict_tf_state* ps = &p.predict_state; - if (ps->num_filter_ents >= 4) - return + if (ps->num_filter_ents >= MAX_FILTER_ENTS) + return; ps->filter_ents[ps->num_filter_ents++] = filter; } From a71cde1fb5e27ce39e385956eaa9ac23bc7b554e Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 03:29:17 -0700 Subject: [PATCH 2245/2474] phys: fix stray selfs mostly harmless, but matters when called in future !self contexts --- share/physics.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/share/physics.qc b/share/physics.qc index f4e54746..8eca1583 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -32,8 +32,8 @@ static void Phys_Impact(entity e, float dt, float phys_flags) { if (other.solid == SOLID_NOT) return; - if (pointcontents(self.origin) == CONTENT_SKY) { - dremove_sent(self); + if (pointcontents(e.origin) == CONTENT_SKY) { + dremove_sent(e); return; } @@ -315,9 +315,9 @@ void Phys_Sim(entity e) { return; float ptime = time + phys_sim_dt; - if (ptime < self.phys_sim_last + SERVER_FRAME_DT) + if (ptime < e.phys_sim_last + SERVER_FRAME_DT) return; - self.phys_sim_last = ptime; + e.phys_sim_last = ptime; float held_phys_time = e.phys_time; vector held_org = e.origin; From f46cf64c8e8caf692ad1ce7562efca35a304c791 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 10:27:14 -0700 Subject: [PATCH 2246/2474] wp: ensure setsize always ordered after model updates --- csqc/weapon_predict.qc | 5 +++-- share/prediction.qc | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 77468264..6fcd37bb 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -773,6 +773,7 @@ static void WP_InitSniper() { sight.drawmask = 0; float index = getmodelindex("progs/sight.spr"); setmodelindex(sight, index); + setsize(sight, [0,0,0], [0,0,0]); SniperState.sight = sight; } @@ -1384,11 +1385,10 @@ void FPP_Init(int fpp_type, entity proj) { render_type = FPP_GRENADE; setmodelindex(proj, FPP_Get(render_type)->modelindex); + setsize(proj, [0,0,0], [0,0,0]); proj.traileffectnum = FPP_FindTrail(proj); proj.movetype = desc->movetype; - - setsize(proj, [0,0,0], [0,0,0]); } DEFCVAR_FLOAT(r_rocketlight, 1); @@ -1516,6 +1516,7 @@ static void FPP_ApplyGrenadeProperties(entity proj) { FO_GrenInfo* gdesc = FO_GrenDesc(proj.fpp.gren_type); setmodelindex(proj, gdesc->modelindex); + setsize(proj, [0,0,0], [0,0,0]); proj.skin = gdesc->skin; proj.avelocity = gdesc->avelocity; } diff --git a/share/prediction.qc b/share/prediction.qc index 9aa81c13..495bc7b8 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -988,6 +988,9 @@ void FOProj_Finalize(entity mis, float use_ctime=0) { csqc_networking = (csqc_networking && fo_config.qc_physics); } + // After any model updates have occurred + setsize(mis, '0 0 0', '0 0 0'); + // We always need to init some of the state here (e.g. phys_time) as we // always use the physics code client-side. if (fo_config.qc_physics) From 7f96e3a838842d3b228c69ab0d99f598ceb7b4e9 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 17:46:19 -0700 Subject: [PATCH 2247/2474] pm: fix judder with unhandled grenades This fixes EMPs shaking screen. --- csqc/pmove.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 6a6edfdf..7e4225fb 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -449,7 +449,8 @@ void PM_AddGrenadeExplosion(float itime, entity ent) { return; FO_GrenExp exp; - FO_GrenGetExp(ent.fpp.gren_type, exp); + if (!FO_GrenGetExp(ent.fpp.gren_type, exp)) + return; float dmg = exp.dmg; From 92cb2fc73988b09b097d2631d5cea57ca0a65a2a Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 17:48:07 -0700 Subject: [PATCH 2248/2474] pm: take self knockback prediction out of beta Now always enabled with `fo_pmove 1` --- csqc/pmove.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 7e4225fb..aa25da53 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -445,7 +445,7 @@ static void PM_NudgeBounce(PM_Nudge* nudge, entity ent) { void PM_AddGrenadeExplosion(float itime, entity ent) { - if (!PM_Enabled() || !CVARF(fo_beta_nudge_explosion)) + if (!PM_Enabled()) return; FO_GrenExp exp; @@ -461,7 +461,7 @@ void PM_AddGrenadeExplosion(float itime, entity ent) { } void PM_AddSimExplosion(float itime, entity ent) { - if (!PM_Enabled() || !CVARF(fo_beta_nudge_explosion)) + if (!PM_Enabled()) return; if (ent.owner != pengine.player_ent) // Just player ents in version 0 From 5c315d7dd62df069b9f55f08b70e7b59df339a38 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 21:18:45 -0700 Subject: [PATCH 2249/2474] pm: reconnect dash, change to seq-based addressing --- csqc/pmove.qc | 13 +++++++------ csqc/weapon_predict.qc | 5 ++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index aa25da53..5038168e 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -285,9 +285,9 @@ static float nudge_expired(PM_Nudge* n) { switch (n->nat) { case NA_NONE: return TRUE; - case NA_SEQ: return n->seq >= servercommandframe; - case NA_SEQTIME: return n->seq + ceil(n->itime / SERVER_FRAME_DT) >= servercommandframe; - case NA_ITIME: return n->itime >= pstate_server.server_time + NUDGE_EPS; // Slack + case NA_SEQ: return n->seq <= servercommandframe; + case NA_SEQTIME: return n->seq + ceil(n->itime / SERVER_FRAME_DT) <= servercommandframe; + case NA_ITIME: return n->itime - NUDGE_EPS <= pstate_server.server_time; // Slack case NA_CONC: return n->itime <= pstate_server.conc_state.next; } @@ -352,15 +352,16 @@ static void PM_NudgeDash(PM_Nudge* nudge, entity ent) { ent.velocity = nudge->vec; } -void PM_AddNudgeDash(float itime) { +void PM_AddNudgeDash(float cseq) { PM_Nudge* n = find_nudge_slot(); if (!n) return; n->type = NT_DASH; - n->itime = itime; + n->nat = NA_SEQ; + n->seq = cseq; n->vec = v_forward * 540; - n->vec.z = 181 + SERVER_FRAME_DT * 800; // TODO: fix this... + n->vec.z = 181; } float nudge_i(PM_Nudge* n) { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 6fcd37bb..f30bccbd 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -903,7 +903,7 @@ void WP_HandleGrenadeInputs() { } float PM_Enabled(); -void PM_AddDashNudge(float itime); +void PM_AddNudgeDash(float cseq); static void WP_Special() { if (pstate_pred.server_time < pstate_pred.special_next) @@ -914,8 +914,7 @@ static void WP_Special() { case PC_SCOUT: cooldown = 1; if (PM_Enabled() && IsEffectFrame()) { - // Want to land in this frame - PM_AddDashNudge(pstate_pred.server_time - 1 * MSEC); + PM_AddNudgeDash(pstate_pred.seq); localsound("dash.wav", CHAN_BODY, 1); } break; From 6269cd2e9714e716273181d1fdaf1b87bfa9598f Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 12 Oct 2023 23:15:30 -0700 Subject: [PATCH 2250/2474] pm: refactor NA_CONC to NA_ITIME_EXPLICT_EXPIRE Clean up and tighten matching, widen fuzzy-match slightly now that we have synch on removal --- csqc/pmove.qc | 108 +++++++++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 5038168e..344c5be3 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -27,6 +27,7 @@ static struct { float seq, server_seq; float interp_t; + float last_nudge; vector error; float errortime; @@ -259,7 +260,7 @@ enum { NA_SEQ, NA_SEQTIME, NA_ITIME, - NA_CONC, // itime but with expiration driven by conc_state + NA_ITIME_EXPLICIT_EXPIRE, }; struct PM_Nudge { @@ -268,27 +269,31 @@ struct PM_Nudge { float nat; float seq, itime, type; - float expire_frame; + float expire_frame, expire_time; vector vec; float aux; }; -const static float NUDGE_EPS = 3 * SERVER_FRAME_DT; -static PM_Nudge nudges[5]; +const static float NUDGE_SEQ = 3; +const static float NUDGE_EPS = NUDGE_SEQ * SERVER_FRAME_DT; +static PM_Nudge nudges[8]; static float num_nudges; static float nudge_expired(PM_Nudge* n) { - // Below all actually expire at <= so this is conservative. - if (n->expire_frame && n->expire_frame < servercommandframe) + if (n->expire_frame && n->expire_frame <= pstate_server.seq) + return TRUE; + + if (n->expire_time && n->expire_time <= pstate_server.server_time) return TRUE; switch (n->nat) { case NA_NONE: return TRUE; - case NA_SEQ: return n->seq <= servercommandframe; - case NA_SEQTIME: return n->seq + ceil(n->itime / SERVER_FRAME_DT) <= servercommandframe; - case NA_ITIME: return n->itime - NUDGE_EPS <= pstate_server.server_time; // Slack - case NA_CONC: return n->itime <= pstate_server.conc_state.next; + case NA_SEQ: return n->seq + NUDGE_SEQ <= pstate_server.seq; + case NA_SEQTIME: + return n->seq + ceil(n->itime / SERVER_FRAME_DT) + NUDGE_SEQ <= pstate_server.seq; + case NA_ITIME: return n->itime + NUDGE_EPS <= pstate_server.server_time; // Slack + case NA_ITIME_EXPLICIT_EXPIRE: return FALSE; // TRUE handled above } return TRUE; @@ -306,6 +311,7 @@ static PM_Nudge* find_nudge_slot() { n->src_no = 0; n->src = 0; n->expire_frame = 0; + n->expire_time = 0; return n; } @@ -321,7 +327,7 @@ static void PM_RemoveSelfNudges() { return; PM_Nudge* n = self.nudge; - n->expire_frame = -servercommandframe; + n->expire_frame = servercommandframe; } void PM_AddNudgeConc(float itime, float mag, float flip) { @@ -336,7 +342,9 @@ void PM_AddNudgeConc(float itime, float mag, float flip) { return; n->type = NT_CONC; - n->nat = NA_CONC; + n->nat = NA_ITIME_EXPLICIT_EXPIRE; + n->expire_time = itime; + n->itime = itime; n->vec.x = mag; n->vec.y = flip; @@ -376,26 +384,27 @@ static void PM_NudgeExplosion(PM_Nudge* nudge, entity ent) { if (vlen(ent.origin - nudge->vec) > dmg + 40) return; - float flg = KF_BOTH_PLAYER; + float flg = KF_BOTH_PLAYER; // Assumes everything is from a player for now if (nudge->src.owner == pengine.player_ent) flg |= KF_SELF; - dmg *= 0.9; // Assume everything is from a player - float moment = CalcRadiusDamage(nudge->src, ent, flg, dmg); - vector knock = CalcKnock(nudge->src, ent, flg, moment); + dmg = CalcRadiusDamage(nudge->src, ent, flg, dmg); + if (flg & KF_SRC_PLAYER) + dmg *= 0.9; + vector knock = CalcKnock(nudge->src, ent, flg, dmg); pm.ent.velocity += knock; } // Can be either by {seq + itime} for predicted projectiles, or by {itime} for // server projectiles. -static void PM_AddNudgeExplosion(float nat, float seq, float itime, entity ent, float dmg) { +static PM_Nudge* PM_AddNudgeExplosion(float nat, float seq, float itime, entity ent, float dmg) { if (vlen(PM_Org() - ent.origin) > dmg * 3) // Fine tune this.. - return; + return 0; PM_Nudge* n = find_nudge_slot(); if (!n) - return; + return 0; n->type = NT_EXPLOSION; n->nat = nat; @@ -409,15 +418,17 @@ static void PM_AddNudgeExplosion(float nat, float seq, float itime, entity ent, ent.nudge = n; ent.removefunc = PM_RemoveSelfNudges; + + return n; } -static void PM_AddNudgeBounce(float itime, entity ent, float dmg) { +static PM_Nudge* PM_AddNudgeBounce(float itime, entity ent, float dmg) { if (vlen(PM_Org() - ent.origin) > dmg * 3) // Fine tune this.. return; PM_Nudge* n = find_nudge_slot(); if (!n) - return; + return 0; n->type = NT_BOUNCE; n->nat = NA_ITIME; @@ -429,6 +440,8 @@ static void PM_AddNudgeBounce(float itime, entity ent, float dmg) { ent.nudge = n; ent.removefunc = PM_RemoveSelfNudges; + + return n; } static void PM_NudgeBounce(PM_Nudge* nudge, entity ent) { @@ -455,10 +468,16 @@ void PM_AddGrenadeExplosion(float itime, entity ent) { float dmg = exp.dmg; + PM_Nudge* n; if (exp.type == kRadiusDamage) - PM_AddNudgeExplosion(NA_ITIME, 0, itime, ent, dmg); + n = PM_AddNudgeExplosion(NA_ITIME, 0, itime, ent, dmg); else - PM_AddNudgeBounce(itime, ent, dmg); + n = PM_AddNudgeBounce(itime, ent, dmg); + + if (n) { + n->nat = NA_ITIME_EXPLICIT_EXPIRE; // Grenades are exact + n->expire_time = itime; + } } void PM_AddSimExplosion(float itime, entity ent) { @@ -482,11 +501,12 @@ void PM_AddSimExplosion(float itime, entity ent) { if (ent.forward_knock && ent.owner == pengine.player_ent) { if (ent.forward_knock == -1) return; + nat = NA_ITIME_EXPLICIT_EXPIRE; // Knock forwards are synchronized itime = ent.forward_knock; } else if (ent.created_seq && ent.entnum == 0) { float dtime = 0; if (ent.s_time) - dtime = max(itime - ent.s_time - SERVER_FRAME_DT, 0); + dtime = max(itime - ent.s_time, 0); seq = ent.created_seq; itime = dtime; nat = NA_SEQTIME; // Same as NA_SEQ when itime == 0 @@ -495,29 +515,29 @@ void PM_AddSimExplosion(float itime, entity ent) { PM_AddNudgeExplosion(nat, seq, itime, ent, dmg); } -float MatchNudge(PM_Nudge* n, float seq, float sitime, float eitime) { - if (n->expire_frame && n->expire_frame < pm.server_seq) { +float MatchNudge(PM_Nudge* n, float seq, float sitime, float eitime, float slack = 0) { + if (nudge_expired(n)) return FALSE; - } switch (n->nat) { - case NA_SEQ: return n->seq == seq; - case NA_SEQTIME: return n->seq + floor(n->itime / SERVER_FRAME_DT) == seq; - case NA_CONC: - case NA_ITIME: return n->itime > sitime && n->itime <= eitime; + case NA_SEQ: return seq == n->seq; + case NA_SEQTIME: return seq == n->seq + floor(n->itime / SERVER_FRAME_DT); + case NA_ITIME_EXPLICIT_EXPIRE: return n->itime > sitime && n->itime <= eitime; + case NA_ITIME: return (n->itime > sitime - slack) && (n->itime <= eitime); default: return FALSE; } } // TODO: This obviously wants to be smarter -static void PM_ApplyNudges(entity ent, float seq, float sitime, float eitime) { +static void PM_ApplyNudges(entity ent, float seq, float sitime, float eitime, float slack = 0) { for (float i = 0; i < nudges.length; i++) { PM_Nudge* n = &nudges[i]; - if (!MatchNudge(n, seq, sitime, eitime)) + if (!MatchNudge(n, seq, sitime, eitime, slack)) continue; + pm.last_nudge = seq; switch (n->type) { case NT_CONC: PM_NudgeConc(n, ent); @@ -574,10 +594,8 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { RunPlayerPhysics(); if (!CVARF(fopm_nonudge)) { - float start_time = pm.interp_t; - if (pm.seq == pm.server_seq + 1) - start_time -= NUDGE_EPS; - PM_ApplyNudges(ent, pm.seq, pm.interp_t, pm.interp_t + input_timelength); + float slack = (pm.seq == pm.server_seq + 1) ? NUDGE_EPS : 0; + PM_ApplyNudges(ent, pm.seq, pm.interp_t, pm.interp_t + input_timelength, slack); } pm.seq++; @@ -620,8 +638,8 @@ static void PM_UpdateError() { pm.errortime = 0; return; } - static PMS_Data last; + static PMS_Data last; if (last.server_seq != pm_s.server_seq - 1) last = pm_so; @@ -630,11 +648,18 @@ static void PM_UpdateError() { vector err = ent.origin; // Repeat with updated state. - PM_RunMovement(SimPMSD(), clientcommandframe - 1); - PM_SavePMS(&last); // Save at -1 since the construction for #cf will be partial + PM_RunMovement(SimPMSD(), clientcommandframe - 2); + PM_SavePMS(&last); // Save at -2 to replay nudges going into -1 PM_RunMovement(SimPMSD(), clientcommandframe); - err -= ent.origin; + // New nudges can result in small errors on replay due to timeshift, we + // could backdate all the nudges and recompute the world but as a first + // simpler pass let's just filter them out. + if (pm.last_nudge == clientcommandframe - 1) + err = '0 0 0'; + else + err -= ent.origin; + float nerr = vlen(err); if (nerr > 64) { // teleport pm.error = '0 0 0'; @@ -711,6 +736,7 @@ static void PM_HandleRemovedNudges() { if (!pstate_server.num_filter_ents) return; + float c = 0; for (float i = 0; i < nudges.length; i++) { PM_Nudge* n = &nudges[i]; if (nudge_expired(n)) From 6e14f70c98287ca72e0b5dbd67276d1dbf967c44 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 12 Oct 2023 17:57:49 -0700 Subject: [PATCH 2251/2474] pm: render death better --- csqc/pmove.qc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 344c5be3..2dafec9c 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -390,7 +390,7 @@ static void PM_NudgeExplosion(PM_Nudge* nudge, entity ent) { dmg = CalcRadiusDamage(nudge->src, ent, flg, dmg); if (flg & KF_SRC_PLAYER) - dmg *= 0.9; + dmg *= 0.9; vector knock = CalcKnock(nudge->src, ent, flg, dmg); pm.ent.velocity += knock; @@ -573,10 +573,8 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { } if (!game_state.is_spectator && !game_state.is_alive) { - pm.seq = clientcommandframe; - //just update the angles - if (!getinputstate(pm.seq-1)) { } - return; + pm.seq = clientcommandframe; // Dead, no prediction. + return; } ASSERTF_GT(pm.seq, 0); @@ -632,7 +630,7 @@ static void PM_UpdateError() { entity ent = pm.ent; ent.owner = edict_num(player_localentnum); - if (CVARF(fopm_noerror) || + if (CVARF(fopm_noerror) || !game_state.is_alive || (clientcommandframe == servercommandframe + 1)) { pm.error = '0 0 0'; pm.errortime = 0; @@ -677,6 +675,8 @@ static void PM_UpdateError() { } } +DEFCVAR_FLOAT(v_deathtilt, 1); + static void PM_UpdateLocalMovement() { entity ent = pm.ent; @@ -706,6 +706,9 @@ static void PM_UpdateLocalMovement() { pm.vieworg = org; pm.vieworg.z += getstatf(STAT_VIEWHEIGHT) + viewheight; + if (!game_state.is_alive && WP_PlayerClass()) + view_angles.z = CVARF(v_deathtilt) * 80; + // Correct view position over ErrorTime() if (pm.errortime - time > 0) pm.vieworg += (pm.errortime - time) * (1 / ErrorTime()) * pm.error; From 3f2c985b9c0c3f8e6722f46fc04bed099314040b Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 12 Oct 2023 23:24:33 -0700 Subject: [PATCH 2252/2474] pm: fix stair smoothing --- csqc/pmove.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 2dafec9c..8daec002 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -715,7 +715,7 @@ static void PM_UpdateLocalMovement() { if (!CVARF(fopm_nostep)) if (pm.steptime - time > 0) - pm.vieworg.z += (pm.steptime - time) * STEPTIME * pm.step; + pm.vieworg.z += (pm.steptime - time) * (1 / STEPTIME) * pm.step; } void PMD_UpdateImpulse(int seq); From c93570c0a026fe064a9f7fe2758578b5180b4861 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 13 Oct 2023 01:41:32 -0700 Subject: [PATCH 2253/2474] pm: capture explosion origins explicitly When we simulate ahead there are cases where the underlying entity may not be stable for replay. --- csqc/pmove.qc | 37 ++++++++++++++++++++----------------- share/weapons.qc | 11 +++++------ ssqc/combat.qc | 4 ++-- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 8daec002..7a8b602a 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -264,14 +264,15 @@ enum { }; struct PM_Nudge { + float type; + entity src; float src_no; - float nat; - float seq, itime, type; + float nat, seq, itime; float expire_frame, expire_time; - vector vec; + vector org; float aux; }; @@ -346,18 +347,18 @@ void PM_AddNudgeConc(float itime, float mag, float flip) { n->expire_time = itime; n->itime = itime; - n->vec.x = mag; - n->vec.y = flip; + n->org.x = mag; + n->org.y = flip; } static void PM_NudgeConc(PM_Nudge* nudge, entity ent) { if (pointcontents(ent.origin) == CONTENT_WATER) ent.flags |= FL_INWATER; // pmove doesn't usually maintain this. - Conc_Stumble(ent, nudge->vec.x, nudge->vec.y); + Conc_Stumble(ent, nudge->org.x, nudge->org.y); } static void PM_NudgeDash(PM_Nudge* nudge, entity ent) { - ent.velocity = nudge->vec; + ent.velocity = nudge->org; } void PM_AddNudgeDash(float cseq) { @@ -368,8 +369,8 @@ void PM_AddNudgeDash(float cseq) { n->nat = NA_SEQ; n->seq = cseq; - n->vec = v_forward * 540; - n->vec.z = 181; + n->org = v_forward * 540; + n->org.z = 181; } float nudge_i(PM_Nudge* n) { @@ -381,17 +382,17 @@ float nudge_i(PM_Nudge* n) { static void PM_NudgeExplosion(PM_Nudge* nudge, entity ent) { float dmg = nudge->aux; - if (vlen(ent.origin - nudge->vec) > dmg + 40) + if (vlen(ent.origin - nudge->org) > dmg + 40) return; float flg = KF_BOTH_PLAYER; // Assumes everything is from a player for now if (nudge->src.owner == pengine.player_ent) flg |= KF_SELF; - dmg = CalcRadiusDamage(nudge->src, ent, flg, dmg); + dmg = CalcRadiusDamage(nudge->org, ent, flg, dmg); if (flg & KF_SRC_PLAYER) dmg *= 0.9; - vector knock = CalcKnock(nudge->src, ent, flg, dmg); + vector knock = CalcKnock(nudge->org, ent, flg, dmg); pm.ent.velocity += knock; } @@ -410,7 +411,8 @@ static PM_Nudge* PM_AddNudgeExplosion(float nat, float seq, float itime, entity n->nat = nat; n->seq = seq; n->itime = itime; - n->vec = ent.origin; // We end up mostly using the ent here + + n->org = ent.origin; // We end up mostly using the ent here n->aux = dmg; n->src = ent; @@ -433,6 +435,8 @@ static PM_Nudge* PM_AddNudgeBounce(float itime, entity ent, float dmg) { n->type = NT_BOUNCE; n->nat = NA_ITIME; n->itime = itime; + + n->org = ent.origin; n->aux = dmg; n->src = ent; @@ -446,15 +450,14 @@ static PM_Nudge* PM_AddNudgeBounce(float itime, entity ent, float dmg) { static void PM_NudgeBounce(PM_Nudge* nudge, entity ent) { float dmg = nudge->aux; - entity src = nudge->src; - if (vlen(ent.origin - src.origin) > dmg + 40) + if (vlen(ent.origin - nudge->org) > dmg + 40) return; vector targ_org = ent.origin + (ent.mins + ent.maxs) * 0.5; - float points = dmg - vlen(targ_org - src.origin) / 2; + float points = dmg - vlen(targ_org - nudge->org) / 2; - ent.velocity = (targ_org - src.origin) * points/20; + ent.velocity = (targ_org - nudge->org) * points/20; } diff --git a/share/weapons.qc b/share/weapons.qc index 8a0c09c6..f0ca135f 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -840,11 +840,11 @@ const float KF_BOTH_PLAYER = KF_SRC_PLAYER | KF_TARG_PLAYER; // (*) Unbelievably knock-direction and moment calculation use different origins // (centroid vs origin). For now just preserve what I can only assume is an old -// terrible mistake. +// terrible mistake. We undo half of this by ignoring on src as mins/maxs==0. -float CalcRadiusDamage(entity src, entity targ, float flags, float damage) { +float CalcRadiusDamage(vector src, entity targ, float flags, float damage) { vector targ_origin = targ.origin + (targ.mins + targ.maxs) * 0.5; // (*) - damage -= vlen(src.origin - targ_origin) / 2; + damage -= vlen(src - targ_origin) / 2; if (flags & KF_SELF) damage *= 0.75; @@ -852,13 +852,12 @@ float CalcRadiusDamage(entity src, entity targ, float flags, float damage) { return damage; } -vector CalcKnock(entity src, entity targ, float flags, float moment) { +vector CalcKnock(vector src, entity targ, float flags, float moment) { float mult = 8; if (moment < 60 && (flags & (KF_BOTH_PLAYER | KF_SELF) == KF_BOTH_PLAYER)) mult = 11; - vector src_origin = src.origin + (src.mins + src.maxs) * 0.5; // (*) - vector dir = normalize(targ.origin - src_origin); + vector dir = normalize(targ.origin - src); vector result = dir * moment * mult; if (fo_config.rj > 1) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index b3541305..6915b9d3 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -610,7 +610,7 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, targ.immune_to_check = time + damage / 20; float moment = Class_ScaleMoment(targ.playerclass, damage); - targ.velocity += CalcKnock(inflictor, targ, fl, moment); + targ.velocity += CalcKnock(inflictor.origin, targ, fl, moment); Predict_AddFilterEnt(targ, inflictor.filter_ent ?: inflictor); } } @@ -760,7 +760,7 @@ void (entity inflictor, entity attacker, float damage, continue; float fl = e == attacker ? KF_SELF : 0; - points = CalcRadiusDamage(inflictor, e, fl, damage); + points = CalcRadiusDamage(inflictor.origin, e, fl, damage); if (points > 0) { if (CanDamage(e, inflictor)) { // shambler takes half damage from all explosions From 54263f1ff519bc32c240c45505561dfd2d12fdd5 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 10 Oct 2023 02:37:09 -0700 Subject: [PATCH 2254/2474] pm: prediction for held grenades This is actually interesting since the entity associated with the knock only exists for 100ms. Meaning for pings over 100ms the client never sees the grenade before it's exploded. Handle this by treating the held grenade like a locally fired projectile and piggy-backing on that infrastructure, allowing us to forward simulate the virtual projectile and emit a knock we'll later stitch up with the actual ent. --- csqc/pmove.qc | 9 ++------ csqc/weapon_predict.qc | 52 ++++++++++++++++++++++++++++++++++++------ share/physics.qc | 18 ++++++++++----- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 7a8b602a..1e7e6922 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -473,14 +473,9 @@ void PM_AddGrenadeExplosion(float itime, entity ent) { PM_Nudge* n; if (exp.type == kRadiusDamage) - n = PM_AddNudgeExplosion(NA_ITIME, 0, itime, ent, dmg); + PM_AddNudgeExplosion(NA_ITIME, 0, itime, ent, dmg); else - n = PM_AddNudgeBounce(itime, ent, dmg); - - if (n) { - n->nat = NA_ITIME_EXPLICIT_EXPIRE; // Grenades are exact - n->expire_time = itime; - } + PM_AddNudgeBounce(itime, ent, dmg); } void PM_AddSimExplosion(float itime, entity ent) { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f30bccbd..f9f5b037 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1217,7 +1217,7 @@ void WPP_Dump() { } void WP_Attack(); - +void WP_ExplodeGren(); DEFCVAR_FLOAT(cl_crossx, 0); void WP_Frame() { @@ -1238,6 +1238,7 @@ void WP_Frame() { WP_CheckReloadFinished(); WP_Impulse(); + WP_ExplodeGren(); W_ThrowGren(FALSE); float is_attack = 0; @@ -1442,7 +1443,11 @@ float PP_PredrawPredicted() { static float PP_EPS = 0.05; -entity PP_CreateProjectile(int fpp_type, vector org) { +enumflags { + CP_DROP +}; + +entity PP_CreateProjectile(int fpp_type, vector org, float cp_flags=0) { PredProj_Sound(fpp_type); if (!PP_Enabled()) @@ -1458,6 +1463,8 @@ entity PP_CreateProjectile(int fpp_type, vector org) { ProjectResult push_t = Forward_ProjectOffset(fpp_type, ms_ahead); float uncorrected_dt = max(ms_ahead - push_t.dynamic_ms, 0) / 1000.0; + if (cp_flags & CP_DROP) + uncorrected_dt = 0; float static_dt = push_t.static_ms / 1000.0; // Note: We use true time here as created projectiles exist outside of pred. @@ -1471,6 +1478,8 @@ entity PP_CreateProjectile(int fpp_type, vector org) { float proj_speed = FPP_Get(fpp_type)->speed; if (!FPP_IsGrenade(fpp_type)) { proj.velocity = v_forward * proj_speed; + } else if (cp_flags & CP_DROP) { + proj.velocity = '0 0 0'; } else { if (!input_angles_x) { proj.velocity = v_forward * proj_speed; @@ -1608,6 +1617,35 @@ static void W_PrimeGren(float index) { pstate_pred.primed_gren_exp = held_gren_exp; } +static void WP_ExplodeGren() { + if (pstate_pred.tfstate & TFSTATE_GREN_MASK_PRIMED == 0) + return; + + float explode_at = pstate_server.primed_gren_exp; + float tfstate = pstate_pred.tfstate; + + if (!explode_at || explode_at > pstate_pred.server_time) + return; + + pstate_pred.primed_gren_exp = 0; + pstate_pred.tfstate &= ~TFSTATE_GREN_MASK_ALL; + + if (!IsEffectFrame()) + return; + + int type_index = (tfstate & TFSTATE_GREN1_PRIMED) ? 0 : 1; + int gren_type = FO_ClassGren(pstate_pred.playerclass, type_index)->id; + entity gren = PP_CreateProjectile(FPP_HANDGRENADE, PM_Org(), CP_DROP); + gren.fpp.gren_type = gren_type; + FPP_ApplyGrenadeProperties(gren); + + gren.starttime = explode_at; + gren.phys_time = explode_at; + gren.fpp.expires_at = explode_at + 0.1; + + Phys_Sim(gren, explode_at + 0.1); +} + static void W_ThrowGren(float is_throw) { if (!QcPhysics() || !RewindFlagEnabled(REWIND_GRENADES) || getstatf(STAT_NOFIRE)) return; @@ -1853,17 +1891,17 @@ void InitProjectileEnt(float sendflags) { if (self.owner_entnum == pengine.player_entnum) self.owner = pengine.player_ent; - if (self.forward_knock) { - self.phys_sim_voided_at = self.forward_knock; - PM_AddSimExplosion(self.forward_knock, self); - } - float ptime = get_phys_time(self); if (ptime > self.phys_time /* from server */) Phys_Advance(self, ptime, PHYSF_CONSUME_ALL); else setorigin(self, self.origin); + float simto = max(self.forward_knock, self.fpp.expires_at); + if (PM_Enabled()) + Phys_Sim(self, simto); + + if (self.created_at < pstate_server.server_time - 0.05) { // Retransmit. Patch up trail, but no predicted / sound / etc. self.oldorigin = self.s_origin; diff --git a/share/physics.qc b/share/physics.qc index 8eca1583..ad11eeaa 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -233,16 +233,17 @@ float Phys_Advance(entity e, float target_time, float phys_flags) { return 0; } + static float limit_eps = 0.00001; // If there's an expiry, make sure we get to the exact position. if (e.fpp.expires_at && target_time >= e.fpp.expires_at) { target_time = e.fpp.expires_at; phys_flags |= PHYSF_CONSUME_ALL; } - static float limit_eps = 0.0005; float limit = (phys_flags & PHYSF_CONSUME_ALL) ? limit_eps : phys_tic; float total = 0, dt = 0, step = 0, delta; + target_time += limit_eps; while ((delta = target_time - e.phys_time) >= limit) { if (e.voided) { e.phys_time = target_time; @@ -309,15 +310,20 @@ float Phys_Init(entity e, float target_time, float delta, float phys_flags) { } #ifdef CSQC -void Phys_Sim(entity e) { +void Phys_Sim(entity e, float target_time = 0) { // TODO: Unvoid+undo if we make it past the void point. if (phys_sim_dt < 0 || e.phys_sim_voided_at) return; - float ptime = time + phys_sim_dt; - if (ptime < e.phys_sim_last + SERVER_FRAME_DT) + float min_gran = 0; + if (!target_time) { + target_time = time + phys_sim_dt; + min_gran = SERVER_FRAME_DT; + } + + if (target_time < e.phys_sim_last + min_gran) return; - e.phys_sim_last = ptime; + e.phys_sim_last = target_time; float held_phys_time = e.phys_time; vector held_org = e.origin; @@ -325,7 +331,7 @@ void Phys_Sim(entity e) { vector held_angles = e.angles; float held_flags = e.flags; - Phys_Advance(e, ptime, PHYSF_SIM | PHYSF_CONSUME_ALL); + Phys_Advance(e, target_time, PHYSF_SIM | PHYSF_CONSUME_ALL); if (e.voided) { e.phys_sim_voided_at = e.phys_time; From 00c74dfa06339db10fed6e128f0ddaaf93b62b85 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 13 Oct 2023 02:05:45 -0700 Subject: [PATCH 2255/2474] menu: fix team menu select nit --- csqc/main.qc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index a4015737..9f8e44f0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -175,10 +175,12 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { ClientSettings_Check(); SetupAliases(); + CurrentMenu = &FO_MENU_TEAM; + player_menu_type = 0; + FO_Menu_Game(TRUE); + pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. print("CSQC initialization finished\n"); - - FO_Menu_Game(TRUE); }; noref void() CSQC_WorldLoaded = { From 3e8bd1e554cbd97c39cf688825476a541c026e33 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 13 Oct 2023 02:07:50 -0700 Subject: [PATCH 2256/2474] pm: fix +jump -> +moveup translation as spec --- csqc/pmove.qc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 1e7e6922..33522f6d 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -827,6 +827,12 @@ void PM_InputFrame() { } } #endif + if (input_buttons & BUTTON2) { + if (game_state.is_spectator) { + input_buttons &= ~BUTTON2; + iz = CVARF(cl_upspeed); + } + } // Technically the sync with pstate_pred being on the right frame is loose.. if (pstate_pred.tfstate & TFSTATE_AIMING) From 4e3e4339ac37011bfeea711340f70e7b0bbf1068 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 13 Oct 2023 02:14:25 -0700 Subject: [PATCH 2257/2474] pm: skeleton for knockback from other players --- csqc/pmove.qc | 8 +++----- csqc/weapon_predict.qc | 9 +++++++-- share/physics.qc | 4 +++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 33522f6d..af38d9e0 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -1,8 +1,5 @@ DEFCVAR_FLOAT(fo_jumpvolume, 1); -static float pm_enabled; -inline float PM_Enabled() { return pm_enabled; } - #define STEPTIME 0.125 enumflags { @@ -482,7 +479,8 @@ void PM_AddSimExplosion(float itime, entity ent) { if (!PM_Enabled()) return; - if (ent.owner != pengine.player_ent) // Just player ents in version 0 + if ((CVARF(fo_beta_nudge_explosion) & 2 == 0) && + ent.owner != pengine.player_ent) return; float dmg = 0; @@ -603,7 +601,7 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { } static void PM_SetEnabled(float enabled) { - pm_enabled = enabled; + pengine.pm_enabled = enabled; PM_Refresh(); diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index f9f5b037..ab9e04f2 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -31,6 +31,7 @@ static float wp_ready; struct pengine_t { float pp_enabled; float wp_enabled; + float pm_enabled; float is_effectframe; float last_effectframe; @@ -52,6 +53,8 @@ inline float PP_Enabled() { return pengine.pp_enabled; } inline float WP_Enabled() { return pengine.wp_enabled; } inline float WPP_ViewModelMask() { return pengine.view_mask; } +inline float PM_Enabled() { return pengine.pm_enabled; } + float WP_PlayerClass() { return pstate_server.playerclass; } @@ -606,8 +609,8 @@ void WP_ServerUpdate(float sendflags) { pstate_server.weaponframe += 1; } - if (CVARF(fo_beta_nudge_explosion)) - phys_sim_dt = (pstate_server.client_ping + 4 * SERVER_FRAME_MS) / 1000.0; + if (PM_Enabled()) + phys_sim_dt = 3 * SERVER_FRAME_DT; else phys_sim_dt = -1; @@ -1299,6 +1302,8 @@ inline float get_phys_time(entity e) { // this will offset explosions in the short term). static float last_self_time; float dt = min(inst_ping_ms, CVARF(wpp_adv_otherp_ms)) / 1000.0; + if (PM_Enabled() && (CVARF(fo_beta_nudge_explosion) & 2)) + dt = (clientcommandframe - servercommandframe - 1) * SERVER_FRAME_DT; last_self_time = max(last_self_time, time + dt); return last_self_time; } diff --git a/share/physics.qc b/share/physics.qc index ad11eeaa..db6b4b02 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -312,11 +312,13 @@ float Phys_Init(entity e, float target_time, float delta, float phys_flags) { #ifdef CSQC void Phys_Sim(entity e, float target_time = 0) { // TODO: Unvoid+undo if we make it past the void point. - if (phys_sim_dt < 0 || e.phys_sim_voided_at) + if (e.phys_sim_voided_at) return; float min_gran = 0; if (!target_time) { + if (phys_sim_dt < 0) + return; target_time = time + phys_sim_dt; min_gran = SERVER_FRAME_DT; } From 091af5756dba92da0ad6c88f61c077601c37465c Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 13 Oct 2023 09:15:47 -0700 Subject: [PATCH 2258/2474] pm: center starttime and minor cleanup --- csqc/weapon_predict.qc | 4 +--- share/physics.qc | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ab9e04f2..ad6baabd 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1473,9 +1473,8 @@ entity PP_CreateProjectile(int fpp_type, vector org, float cp_flags=0) { float static_dt = push_t.static_ms / 1000.0; // Note: We use true time here as created projectiles exist outside of pred. - proj.starttime = time + uncorrected_dt; + proj.starttime = time + uncorrected_dt - input_timelength / 2; proj.endtime = proj.starttime + pstate_server.client_ping / 1000.0 + PP_EPS; - proj.server_live_time = server_time(); proj.predraw = PP_PredrawPredicted; proj.drawmask = MASK_PRED_PROJECTILE; @@ -1882,7 +1881,6 @@ void InitProjectileEnt(float sendflags) { self.fpp.index = FPP_RAILGUN; // Something people will notice. } - self.server_live_time = self.created_at; self.created_seq = servercommandframe; self.drawmask = MASK_ENGINE; diff --git a/share/physics.qc b/share/physics.qc index db6b4b02..35584b0a 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -3,8 +3,6 @@ static const float phys_tic = 0.005; .float phys_time; // Current physics time -.float server_live_time; // When an entity can first appear on server. 0 for - // server-side ents. enumflags { PHYSB_ENABLED, From 51bbddc8f3656eabfb2ca1663191bd6000f9c013 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 13 Oct 2023 09:32:06 -0700 Subject: [PATCH 2259/2474] menus: fix menus with pm, dont bring up disguise/build when not spy/eng --- csqc/main.qc | 6 ++++-- csqc/menu.qc | 13 ++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 9f8e44f0..671aaa7d 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -334,10 +334,12 @@ noref float(string cmd) CSQC_ConsoleCommand = { FO_Menu_Special(TRUE); break; case "fo_menu_disguise": - FO_Menu_Spy_Skin(TRUE); + if (WP_PlayerClass() == PC_SPY) + FO_Menu_Spy_Skin(TRUE); break; case "fo_menu_build": - FO_Menu_Build(TRUE); + if (WP_PlayerClass() == PC_ENGINEER) + FO_Menu_Build(TRUE); break; case "fo_menu_dropammo": FO_Menu_DropAmmo(TRUE); diff --git a/csqc/menu.qc b/csqc/menu.qc index 0c76534e..bf23d658 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -284,7 +284,7 @@ var fo_menu FO_MENU_BUILD = { } if(SBAR.HasSentry) { FO_MENU_BUILD.options[0].state = FO_MENU_STATE_HIDDEN; //Build - if(vlen(thisorigin - sentry_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { + if(vlen(PM_Org() - sentry_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { FO_MENU_BUILD.options[2].state = FO_MENU_STATE_HIDDEN; //Destroy FO_MENU_BUILD.options[3].state = FO_MENU_STATE_NORMAL; //Dismantle } else { @@ -302,7 +302,7 @@ var fo_menu FO_MENU_BUILD = { } if(SBAR.HasDispenser) { FO_MENU_BUILD.options[1].state = FO_MENU_STATE_HIDDEN; - if(vlen(thisorigin - dispenser_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { + if(vlen(PM_Org() - dispenser_pos) <= ENG_BUILDING_DISMANTLE_DISTANCE) { FO_MENU_BUILD.options[4].state = FO_MENU_STATE_HIDDEN; FO_MENU_BUILD.options[5].state = FO_MENU_STATE_NORMAL; } else { @@ -328,7 +328,7 @@ var fo_menu FO_MENU_SENTRY_MAINTAIN = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { - if(vlen(thisorigin - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } @@ -343,7 +343,7 @@ var fo_menu FO_MENU_SENTRY_ROTATE = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { - if(vlen(thisorigin - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } @@ -357,7 +357,7 @@ var fo_menu FO_MENU_DISPENSER_MAINTAIN = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { - if(vlen(thisorigin - dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(PM_Org() - dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } @@ -370,7 +370,7 @@ var fo_menu FO_MENU_DISPENSER_USE = { MenuSpacer, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 4, TRUE, { - if(vlen(thisorigin - touched_dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { + if(vlen(PM_Org() - touched_dispenser_pos) > ENG_BUILDING_MAINT_DISTANCE) { Menu_Cancel(); return; } @@ -697,7 +697,6 @@ vector fo_menu_draw(fo_menu * menu) = { FO_Hud_ShowPanel(HUDP_MENU_HINT); SBAR.Hint = ""; - thisorigin = (vector)getentity(player_localentnum, GE_ORIGIN); setcursormode(menu.flags & FO_MENU_FLAG_USE_MOUSE); if(menu.update) { From ab785335f759f57d4beb0d92ae7c9953864b08ea Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 13 Oct 2023 09:41:00 -0700 Subject: [PATCH 2260/2474] pm: scout: fix conc + dash during prematch --- csqc/weapon_predict.qc | 3 +++ share/classes.qc | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ad6baabd..abbddf85 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -909,6 +909,9 @@ float PM_Enabled(); void PM_AddNudgeDash(float cseq); static void WP_Special() { + if (prematch) + return; + if (pstate_pred.server_time < pstate_pred.special_next) return; diff --git a/share/classes.qc b/share/classes.qc index 831dd0db..a0125d42 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -133,6 +133,10 @@ static inline void ConcAction(entity ent, float itime, float mag, float flip) { #endif void Conc_Update(ConcState *cs, entity ent, float ctime) { +#ifdef SSQC + if (ent.invincible_finished > time) // TODO: Is this worth sharing? + cs->mag = 0; +#endif if (!cs->mag || ctime < cs->next) return; From 140826a2f4e52130a4c73840bcebee70b31458d1 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 18 Oct 2023 13:58:43 -0700 Subject: [PATCH 2261/2474] pmove: hwguy reduced knockback --- csqc/pmove.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index af38d9e0..375b364d 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -389,6 +389,7 @@ static void PM_NudgeExplosion(PM_Nudge* nudge, entity ent) { dmg = CalcRadiusDamage(nudge->org, ent, flg, dmg); if (flg & KF_SRC_PLAYER) dmg *= 0.9; + dmg = Class_ScaleMoment(WP_PlayerClass(), dmg); vector knock = CalcKnock(nudge->org, ent, flg, dmg); pm.ent.velocity += knock; From 58f82f324c046a256ee41bccaace735993a1eeab Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 20 Oct 2023 14:17:20 -0700 Subject: [PATCH 2262/2474] wp: fix ghost projectiles while priming detpack Make sure that predicted projectiles respect the no-attack mask, and put in a filter for when we expect one to be coming --- csqc/weapon_predict.qc | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index abbddf85..da91510a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -87,6 +87,10 @@ DEFCVAR_FLOAT(cl_predict_players_frac, 0.9); static float pred_time_dt; // delta-time that the world predicted forward by +// Allows temporarily disabling prediction around events that we do not yet +// fully implement a client-side state machine for, e.g. priming a detpack. +static float filter_pproj_time; + // Match up local interpolation of projectile position with that of players. static void update_interp_time_dt() { if (!CVARF(cl_predict_players)) { @@ -857,8 +861,11 @@ void WPP_Dump(); float WP_WeaponReady() { const float not_ready_mask = TFSTATE_RELOADING | TFSTATE_NO_WEAPON; - return pstate_pred.client_time >= pstate_pred.attack_finished && - (pstate_pred.tfstate & not_ready_mask) == 0; + if (pstate_pred.client_time < pstate_pred.attack_finished) + return FALSE; + if (pstate_pred.tfstate & not_ready_mask) + return FALSE; + return TRUE; } static void WP_ChangeIfQueued() { @@ -979,6 +986,13 @@ void WP_Impulse() { W_ThrowGren(TRUE); break; + case TF_DETPACK: + case TF_DETPACK_5: + case TF_DETPACK_20: + case TF_DETPACK_50: + filter_pproj_time = time + server_time_dt() + 3 * SERVER_FRAME_DT; + break; + default: pstate_pred.impulse = local_impulse; break; @@ -1250,9 +1264,7 @@ void WP_Frame() { float is_attack = 0; if (pstate_pred.playerclass != PC_SNIPER) - is_attack = ((input_buttons & BUTTON0) && - (pstate_pred.client_time >= pstate_pred.attack_finished) && - !WP_IsReloading()); + is_attack = ((input_buttons & BUTTON0) && WP_WeaponReady()); else is_attack = WP_Sniper_IsAttack(); @@ -1721,7 +1733,7 @@ void WP_Attack() { // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 1; - if (IsEffectFrame() && !in_anim) { + if (IsEffectFrame() && !in_anim && (time > filter_pproj_time)) { float send_event = FALSE; switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: From 9d1db5c086a4ef8b18adfa6f37026ab33817be37 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 20 Oct 2023 14:23:30 -0700 Subject: [PATCH 2263/2474] pmove: add prediction for dead body bounce Being dead felt jerky under pmove since it was effectively rendering movement at server 72fps, run prediction to smooth this out. --- csqc/pmove.qc | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 375b364d..8fad6856 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -559,6 +559,28 @@ static void RunPlayerPhysics() { runstandardplayerphysics(ent); } +static void RunDeadMovement(float endframe) { + entity ent = pm.ent; + float held_movetype = ent.movetype; + float held_solid = ent.solid; + float held_buttons = input_buttons; + vector held_movevalues = input_movevalues; + + ent.movetype = MOVETYPE_TOSS; + ent.solid = SOLID_NOT; + input_buttons = 0; + input_movevalues = '0 0 0'; + while (pm.seq <= endframe) { + runstandardplayerphysics(ent); + pm.seq++; + } + + ent.movetype = held_movetype; + ent.solid = held_solid; + input_buttons = held_buttons; + input_movevalues = held_movevalues; +} + // End state: // pmsd.seq --> endframe + 1 static void PM_RunMovement(PMS_Data* pmsd, float endframe) { @@ -570,7 +592,7 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { } if (!game_state.is_spectator && !game_state.is_alive) { - pm.seq = clientcommandframe; // Dead, no prediction. + RunDeadMovement(endframe); return; } From 9a0ce28bd499e0b5f0e61a78d445ddeae6dacb36 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 20 Oct 2023 15:13:38 -0700 Subject: [PATCH 2264/2474] pmove: hold prediction during ceasefire Similarly, freeze player on lost connection --- csqc/csextradefs.qc | 1 + csqc/main.qc | 1 + csqc/pmove.qc | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index f88c522c..9637187e 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -876,6 +876,7 @@ struct GameState { float is_player; float is_alive; float is_spectator; + float is_ceasefire; float spawn_gen; }; diff --git a/csqc/main.qc b/csqc/main.qc index 671aaa7d..0301c01e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -711,6 +711,7 @@ void _Sync_ServerCommandFrame() { game_state.is_alive = getstatf(STAT_HEALTH) > 0; game_state.spawn_gen = getstatf(STAT_SPAWN_GEN); + game_state.is_ceasefire = serverkeyfloat("pausestate"); WP_ServerFrame(); // Use an undocumented ezquake compat feature to figure out whether we diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 8fad6856..789a50f0 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -699,7 +699,12 @@ DEFCVAR_FLOAT(v_deathtilt, 1); static void PM_UpdateLocalMovement() { entity ent = pm.ent; - PM_RunMovement(SimPMSD(), clientcommandframe); + if (game_state.is_ceasefire || clientcommandframe > servercommandframe + 63) { + PM_ActivatePMS(&pm_s); + } else { + PM_RunMovement(SimPMSD(), clientcommandframe); + } + vector org = pm.ent.origin; // Smooth stair stepping From 0ad8a47e41ac3b34cbabcf2e87ee5a034a2010f7 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 20 Oct 2023 16:03:24 -0700 Subject: [PATCH 2265/2474] pmove: add life-associated expiry to nudges For example, dont allow conc nudges from previous life the lerp the next. This is a pretty narrow window but annoying when it does happen with high ping. --- csqc/pmove.qc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 789a50f0..8487a35d 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -267,7 +267,7 @@ struct PM_Nudge { float src_no; float nat, seq, itime; - float expire_frame, expire_time; + float expire_frame, expire_time, expire_spawnseq; vector org; float aux; @@ -285,6 +285,9 @@ static float nudge_expired(PM_Nudge* n) { if (n->expire_time && n->expire_time <= pstate_server.server_time) return TRUE; + if (n->expire_spawnseq && n->expire_spawnseq != game_state.spawn_gen) + return TRUE; + switch (n->nat) { case NA_NONE: return TRUE; case NA_SEQ: return n->seq + NUDGE_SEQ <= pstate_server.seq; @@ -310,6 +313,7 @@ static PM_Nudge* find_nudge_slot() { n->src = 0; n->expire_frame = 0; n->expire_time = 0; + n->expire_spawnseq = 0; return n; } @@ -342,6 +346,7 @@ void PM_AddNudgeConc(float itime, float mag, float flip) { n->type = NT_CONC; n->nat = NA_ITIME_EXPLICIT_EXPIRE; n->expire_time = itime; + n->expire_spawnseq = game_state.spawn_gen; n->itime = itime; n->org.x = mag; @@ -410,6 +415,12 @@ static PM_Nudge* PM_AddNudgeExplosion(float nat, float seq, float itime, entity n->seq = seq; n->itime = itime; + // This is slightly imprecise, since you could throw a grenade then spawn + // and jump on it, but it's more right than wrong; and the wrong cases lead + // to false lerps. + if (ent.owner == pengine.player_ent) + n->expire_spawnseq = game_state.spawn_gen; + n->org = ent.origin; // We end up mostly using the ent here n->aux = dmg; From bac05eda69b97f6dc562d439ed2df9f0b8b71a19 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 30 Oct 2023 11:14:16 -0700 Subject: [PATCH 2266/2474] gren: handle GREN_NONE properly (civilians) --- share/weapons.qc | 1 + ssqc/tfort.qc | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/share/weapons.qc b/share/weapons.qc index f0ca135f..3425a5ef 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -186,6 +186,7 @@ FO_GrenInfo fo_grenades[] = { { GREN_MIRVLET, "mirv", "grenade2.mdl", 1, ICON_GREN_NONE, '250 300 400'}, { GREN_RED, "gl", "grenade2.mdl", 1, ICON_GREN_NONE, '300 300 300'}, { GREN_PIPE, "pipe", "grenade2.mdl", 2, ICON_GREN_NONE, '300 300 300'}, + { GREN_NONE, "none", "none", 0, ICON_GREN_NONE, '0 0 0'}, }; string FO_GrenName(float gtype) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 8d061796..c9a9920c 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -808,6 +808,10 @@ void TeamFortress_PrimeGrenade(float inp, float is_player) { return; FO_GrenInfo* gdesc = FO_PlayerGren(self, inp - 1); + + if (gdesc->id == GREN_NONE) + return; + float *numg = (inp == 1) ? &self.no_grenades_1 : &self.no_grenades_2; string gs = FO_GrenName(gdesc->id); From 4ceb4860d3e496aab161916b7ee66efabe52283a Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 30 Oct 2023 11:08:37 -0700 Subject: [PATCH 2267/2474] pmove: conc updates --- csqc/pmove.qc | 3 +++ share/classes.qc | 36 +++++++++++++++++------------------- ssqc/client.qc | 48 ++++++++++++++++++++++++++++++------------------ ssqc/scout.qc | 1 + ssqc/tfortmap.qc | 11 ++++------- ssqc/weapons.qc | 10 +++++----- 6 files changed, 60 insertions(+), 49 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 8487a35d..be5ee863 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -624,6 +624,9 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { if (!CVARF(fopm_nonudge)) { float slack = (pm.seq == pm.server_seq + 1) ? NUDGE_EPS : 0; PM_ApplyNudges(ent, pm.seq, pm.interp_t, pm.interp_t + input_timelength, slack); + + if ((ent.pmove_flags & PMF_JUMP_HELD) && (pstate_pred.tfstate & TFSTATE_CONC)) + Conc_Jump(&pstate_pred.conc_state, ent); } pm.seq++; diff --git a/share/classes.qc b/share/classes.qc index a0125d42..b690274b 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -107,7 +107,7 @@ static float NextToWall(entity ent) { const float CONC_P = 0.25; const float CONC_HZ = 1/CONC_P; -void Conc_Stumble(entity ent, float imp, float flip) { +void Conc_Stumble(entity ent, float stumble, float flip) { if ((ent.flags & (FL_INWATER | FL_ONGROUND) == 0) || (*self_tf_state() & TFSTATE_FEIGNED)) return; @@ -115,30 +115,35 @@ void Conc_Stumble(entity ent, float imp, float flip) { if (NextToWall(ent) && ent.velocity == '0 0 0') return; - ent.velocity = [flip * ent.velocity_y + imp, flip * ent.velocity_x + imp, - ent.velocity_z]; + // [*]: This preserves what looks to be a long-standing bug where y-vel ends + // up propagating due to missed temporary to hold vel_x. + ent.velocity_x = flip * ent.velocity_y + stumble; + ent.velocity_y = flip * ent.velocity_x + stumble; +} + +void Conc_Jump(ConcState* cs, entity ent) { + float stumble = shared_crandom(PRNG_CONC) * cs->mag / 10; + float flip = (shared_prng(PRNG_CONC) < 0.5) ? -1 : 1; + + // See [*] above. + ent.velocity_x = flip * ent.velocity_y + stumble; + ent.velocity_y = flip * ent.velocity_x + stumble; } #ifdef SSQC -void SpawnBubble(vector origin); static inline void ConcAction(entity ent, float itime, float mag, float flip) { Conc_Stumble(ent, mag, flip); } #else void PM_AddNudgeConc(float itime, float mag, float flip); - static inline void ConcAction(entity ent, float itime, float mag, float flip) { PM_AddNudgeConc(itime, mag, flip); } #endif -void Conc_Update(ConcState *cs, entity ent, float ctime) { -#ifdef SSQC - if (ent.invincible_finished > time) // TODO: Is this worth sharing? - cs->mag = 0; -#endif +float Conc_Update(ConcState *cs, entity ent, float ctime) { if (!cs->mag || ctime < cs->next) - return; + return FALSE; while (ctime >= cs->next) { cs->mag = max(cs->mag - 1, 0); @@ -153,14 +158,7 @@ void Conc_Update(ConcState *cs, entity ent, float ctime) { cs->next += CONC_P; } -#ifdef SSQC - if (cs->mag) { - if (cs->mag % CONC_HZ == 0) - SpawnBubble(ent.origin); - } else { - sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); - } -#endif + return TRUE; } float Class_ScaleMoment(float playerclass, float damage) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 6646f84e..229fa0da 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2536,17 +2536,8 @@ void () PlayerJump = { StopAssCan(); } - if (GetConcMode() == CONC_CLASSIC && (self.tfstate & TFSTATE_CONC)) { - entity te = FindConcTimer(self); - stumble = crandom() * (te.health / 100); - if (crandom() < 0) { - self.velocity_x = self.velocity_y + stumble; - self.velocity_y = self.velocity_x + stumble; - } else { - self.velocity_x = (-1 * self.velocity_y) + stumble; - self.velocity_y = (-1 * self.velocity_x) + stumble; - } - } + if (GetConcMode() == CONC_CLASSIC && (self.tfstate & TFSTATE_CONC)) + Conc_Jump(&self.conc_state, self); }; .float dmgtime; @@ -2649,9 +2640,31 @@ void () CheckWaterJump = { } }; +void SpawnBubble(vector origin); + +static void ConcUpdate() { + if (self.tfstate & TFSTATE_CONC == 0) + return; + + if (self.invincible_finished > time) { + RemoveConc(self, FALSE); + return; + } + + if (!Conc_Update(&self.conc_state, self, time)) + return; + + if (self.conc_state.mag) { + if (self.conc_state.mag % CONC_HZ == 0) + SpawnBubble(self.origin); + } else { + sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); + } +} + void () PlayerPreThink = { FO_UpdateClientTime(); - Conc_Update(&self.conc_state, self, time); + ConcUpdate(); if (self.impulse) { if (self.impulse == TF_VOTENEXT) { @@ -2767,7 +2780,7 @@ void () CheckPowerups = { self.modelindex = modelindex_eyes; } else { if (self.invisible_finished) { - if (self.tfstate & 64) { + if (self.tfstate & TFSTATE_INVISIBLE) { if (self.invisible_finished < (time + 10)) { self.invisible_finished = time + 666; } @@ -2802,7 +2815,7 @@ void () CheckPowerups = { } } if (self.invincible_finished) { - if (self.tfstate & 32) { + if (self.tfstate & TFSTATE_INVINCIBLE) { if (self.invincible_finished < (time + 10)) { self.invincible_finished = time + 666; } @@ -2846,7 +2859,7 @@ void () CheckPowerups = { } } if (self.super_damage_finished) { - if (self.tfstate & 128) { + if (self.tfstate & TFSTATE_QUAD) { if (self.super_damage_finished == (time + 10)) { self.super_damage_finished = time + 666; } @@ -2869,8 +2882,7 @@ void () CheckPowerups = { self.super_time = 0; } if (self.super_damage_finished > time) { - self.effects = self.effects | 8; - self.effects = self.effects | 64; + self.effects |= EF_DIMLIGHT | EF_BLUE; } else { lighton = 0; te = find(world, classname, "item_tfgoal"); @@ -2889,7 +2901,7 @@ void () CheckPowerups = { } if (self.radsuit_finished) { self.air_finished = time + 12; - if (self.tfstate & 256) { + if (self.tfstate & TFSTATE_RADSUIT) { if (self.radsuit_finished == (time + 10)) { self.radsuit_finished = time + 666; } diff --git a/ssqc/scout.qc b/ssqc/scout.qc index cd8ee594..36f325e3 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -45,6 +45,7 @@ void RemoveConc(entity player, float remove_timer = TRUE) { return; player.tfstate &= ~TFSTATE_CONC; + player.conc_state.mag = 0; player.conc_finished = 0; if (GetConcMode() == CONC_IDLESCALE) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 67dd632c..7a058915 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -1179,28 +1179,25 @@ void (entity Goal, entity Player) RemoveResults = { te = find(te, classname, "item_tfgoal"); } if ((Goal.invincible_finished > 0) && !puinvin) { - Player.tfstate = - Player.tfstate - (Player.tfstate & TFSTATE_INVINCIBLE); + Player.tfstate &= ~TFSTATE_INVINCIBLE; Player.items = Player.items | IT_INVULNERABILITY; Player.invincible_time = 1; Player.invincible_finished = time + Goal.invincible_finished; } if ((Goal.invisible_finished > 0) && !puinvis) { - Player.tfstate = - Player.tfstate - (Player.tfstate & TFSTATE_INVISIBLE); + Player.tfstate &= ~TFSTATE_INVISIBLE; Player.items = Player.items | IT_INVISIBILITY; Player.invisible_time = 1; Player.invisible_finished = time + Goal.invisible_finished; } if ((Goal.super_damage_finished > 0) && !puquad) { - Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_QUAD); + Player.tfstate &= ~TFSTATE_QUAD; Player.items = Player.items | IT_QUAD; Player.super_time = 1; Player.super_damage_finished = time + Goal.super_damage_finished; } if ((Goal.radsuit_finished > 0) && !purad) { - Player.tfstate = - Player.tfstate - (Player.tfstate & TFSTATE_RADSUIT); + Player.tfstate &= ~TFSTATE_RADSUIT; Player.items = Player.items | IT_SUIT; Player.rad_time = 1; Player.radsuit_finished = time + Goal.radsuit_finished; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 98d35398..2c0a675b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2676,15 +2676,15 @@ void () SuperDamageSound = { void () ToggleInvincibility = { if(self.tfstate & TFSTATE_INVINCIBLE) { - self.items = self.items - (self.items & IT_INVULNERABILITY); + self.items &= ~IT_INVULNERABILITY; self.invincible_time = 0; self.invincible_finished = 0; - self.tfstate = self.tfstate - (self.tfstate & TFSTATE_INVINCIBLE); - self.effects = self.effects - (self.effects & (EF_RED + EF_DIMLIGHT + EF_BRIGHTLIGHT)); + self.tfstate &= ~TFSTATE_INVINCIBLE; + self.effects &= ~(EF_RED | EF_DIMLIGHT | EF_BRIGHTLIGHT); } else { - self.items = self.items | IT_INVULNERABILITY; + self.items |= IT_INVULNERABILITY; self.invincible_time = 1; - self.tfstate = self.tfstate | TFSTATE_INVINCIBLE; + self.tfstate |= TFSTATE_INVINCIBLE; self.invincible_finished = time + 666; } }; From 97f08277f731b33972a6d83cc61174c752f8f894 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 30 Oct 2023 14:16:54 -0700 Subject: [PATCH 2268/2474] pmove: more cleanup --- share/classes.qc | 6 ++---- ssqc/client.qc | 9 ++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/share/classes.qc b/share/classes.qc index b690274b..534e3f3d 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -141,9 +141,9 @@ static inline void ConcAction(entity ent, float itime, float mag, float flip) { } #endif -float Conc_Update(ConcState *cs, entity ent, float ctime) { +void Conc_Update(ConcState *cs, entity ent, float ctime) { if (!cs->mag || ctime < cs->next) - return FALSE; + return; while (ctime >= cs->next) { cs->mag = max(cs->mag - 1, 0); @@ -157,8 +157,6 @@ float Conc_Update(ConcState *cs, entity ent, float ctime) { ConcAction(ent, cs->next, mag, flip); cs->next += CONC_P; } - - return TRUE; } float Class_ScaleMoment(float playerclass, float damage) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 229fa0da..04507bd2 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2647,17 +2647,16 @@ static void ConcUpdate() { return; if (self.invincible_finished > time) { - RemoveConc(self, FALSE); - return; + self.conc_state.mag = 0; + } else { + Conc_Update(&self.conc_state, self, time); } - if (!Conc_Update(&self.conc_state, self, time)) - return; - if (self.conc_state.mag) { if (self.conc_state.mag % CONC_HZ == 0) SpawnBubble(self.origin); } else { + RemoveConc(self, FALSE); sprint(self.owner, PRINT_HIGH, "Your head feels better now\n"); } } From 2963d730163f4003375512b22c07337575e0b20f Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 30 Oct 2023 14:33:54 -0700 Subject: [PATCH 2269/2474] pmove: fix conc bubble spam --- share/classes.qc | 6 ++++-- ssqc/client.qc | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/share/classes.qc b/share/classes.qc index 534e3f3d..b690274b 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -141,9 +141,9 @@ static inline void ConcAction(entity ent, float itime, float mag, float flip) { } #endif -void Conc_Update(ConcState *cs, entity ent, float ctime) { +float Conc_Update(ConcState *cs, entity ent, float ctime) { if (!cs->mag || ctime < cs->next) - return; + return FALSE; while (ctime >= cs->next) { cs->mag = max(cs->mag - 1, 0); @@ -157,6 +157,8 @@ void Conc_Update(ConcState *cs, entity ent, float ctime) { ConcAction(ent, cs->next, mag, flip); cs->next += CONC_P; } + + return TRUE; } float Class_ScaleMoment(float playerclass, float damage) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 04507bd2..95755c2a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2649,7 +2649,8 @@ static void ConcUpdate() { if (self.invincible_finished > time) { self.conc_state.mag = 0; } else { - Conc_Update(&self.conc_state, self, time); + if (!Conc_Update(&self.conc_state, self, time)) + return; } if (self.conc_state.mag) { From dccf69d2f0fd2bf8acabe7728d548e8da53d1882 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 30 Oct 2023 14:36:25 -0700 Subject: [PATCH 2270/2474] pmove: don't predict sounds when dead --- csqc/pmove.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index be5ee863..83a0ceca 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -762,6 +762,9 @@ void PM_SyncTo(float seq) { if (!PM_Enabled()) return; + if (!game_state.is_alive) + return; + entity ent = pm.ent; PM_RunMovement(SimPMSD(), seq); From 55d3aa04e5b717b6dc3828454cf0812785e41424 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 13 Nov 2023 10:33:17 -0800 Subject: [PATCH 2271/2474] mdls: fix missing progs/none --- share/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/weapons.qc b/share/weapons.qc index 3425a5ef..1d44c5dc 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -186,7 +186,7 @@ FO_GrenInfo fo_grenades[] = { { GREN_MIRVLET, "mirv", "grenade2.mdl", 1, ICON_GREN_NONE, '250 300 400'}, { GREN_RED, "gl", "grenade2.mdl", 1, ICON_GREN_NONE, '300 300 300'}, { GREN_PIPE, "pipe", "grenade2.mdl", 2, ICON_GREN_NONE, '300 300 300'}, - { GREN_NONE, "none", "none", 0, ICON_GREN_NONE, '0 0 0'}, + { GREN_NONE, "none", "", 0, ICON_GREN_NONE, '0 0 0'}, }; string FO_GrenName(float gtype) { From 01959e4d4997f30ece23e1c94eb5bb57b8b2a644 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 13 Nov 2023 14:35:59 -0800 Subject: [PATCH 2272/2474] ent: fix triggers inadvertently adding grenades --- ssqc/tfortmap.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 7a058915..f682d517 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -874,10 +874,10 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { } if (disable_resup_gren & 1 == 0) - Player.no_grenades_1 = min(Player.no_grenades_1 + 1, + Player.no_grenades_1 = min(Player.no_grenades_1 + Goal.no_grenades_1, Player.max_grenades_1); if (disable_resup_gren & 2 == 0) - Player.no_grenades_2 = min(Player.no_grenades_2 + 1, + Player.no_grenades_2 = min(Player.no_grenades_2 + Goal.no_grenades_2, Player.max_grenades_2); if (Player.ammo_detpack > Player.maxammo_detpack) { From 60945c6fa63140a563630015a56e00f871ac0b5b Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 13 Nov 2023 14:40:00 -0800 Subject: [PATCH 2273/2474] misc: fix compile nits --- csqc/csextradefs.qc | 1 - csqc/pmove.qc | 6 ++---- csqc/weapon_predict.qc | 2 +- ssqc/status.qc | 8 ++++---- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 9637187e..6fb4449c 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -886,7 +886,6 @@ float team_no; float crosshair_team_no; float all_time; float painfinished; -vector thisorigin; float jump_counter; float last_id_time; diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 83a0ceca..fb975262 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -433,13 +433,13 @@ static PM_Nudge* PM_AddNudgeExplosion(float nat, float seq, float itime, entity return n; } -static PM_Nudge* PM_AddNudgeBounce(float itime, entity ent, float dmg) { +static void PM_AddNudgeBounce(float itime, entity ent, float dmg) { if (vlen(PM_Org() - ent.origin) > dmg * 3) // Fine tune this.. return; PM_Nudge* n = find_nudge_slot(); if (!n) - return 0; + return; n->type = NT_BOUNCE; n->nat = NA_ITIME; @@ -453,8 +453,6 @@ static PM_Nudge* PM_AddNudgeBounce(float itime, entity ent, float dmg) { ent.nudge = n; ent.removefunc = PM_RemoveSelfNudges; - - return n; } static void PM_NudgeBounce(PM_Nudge* nudge, entity ent) { diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index da91510a..96c549c5 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1785,7 +1785,7 @@ void WP_Attack() { // but this includes the ping adjustment that would occur at pred. // Tested both ways and this seems to be more stable. sendevent("Attack", "ifvv", - (float)wi->weapon, pstate_server.client_time, + wi->weapon, pstate_server.client_time, PM_Org(), input_angles); } } diff --git a/ssqc/status.qc b/ssqc/status.qc index ad3d9d36..85b9efae 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -775,8 +775,7 @@ void UpdateClientReloadSound(entity pl, float weapon) { } void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { - return; // Not needed until we re-enable TFX. - +#if 0 // Not needed until we re-enable TFX. msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENPRIMED); @@ -785,16 +784,17 @@ void UpdateClientGrenadePrimed(entity pl, float grentype, float explodes_at) = { WriteFloat(MSG_MULTICAST, explodes_at); multicast('0 0 0', MULTICAST_ALL); // Actual primer has reliable transport. +#endif } void UpdateClientGrenadeThrown(entity pl) = { - return; // Not needed until we re-enable TFX. - +#if 0 // Not needed until we re-enable TFX. msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_GRENTHROWN); WriteEntity(MSG_MULTICAST, pl); multicast('0 0 0', MULTICAST_ALL); +#endif } void UpdateClientIDString(entity pl) { From 01c3ffdfd276fb831dcbfbb671c26ae9c61f1063 Mon Sep 17 00:00:00 2001 From: newby Date: Tue, 14 Nov 2023 14:14:42 -0800 Subject: [PATCH 2274/2474] antilag: fix type-cast on passing weapon for on-death projectiles --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 2c0a675b..7f7574fb 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2691,7 +2691,7 @@ void () ToggleInvincibility = { // TODO: trust the client less, validate more. // TODO: Could support hitscan (e.g. sg/ssg) -void (float weap, float ctime, vector pos, vector angles) CSEv_Attack_ifvv = { +void (int weap, float ctime, vector pos, vector angles) CSEv_Attack_ifvv = { if (!RewindFlagEnabled(REWIND_SENDEVENT)) return; From b397cba7c68071d9c66b4219279890af243cf4e9 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 22 Dec 2023 23:20:05 -0800 Subject: [PATCH 2275/2474] new-balance: add menu option for enabling new balance tweaks --- csqc/csextradefs.qc | 9 +-------- csqc/events.qc | 1 + csqc/menu.qc | 15 +++++++++------ ssqc/client.qc | 7 +++++++ ssqc/commands.qc | 12 ++++++++++++ ssqc/csmenu.qc | 1 + ssqc/qw.qc | 2 ++ 7 files changed, 33 insertions(+), 14 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6fb4449c..32613e5a 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -328,6 +328,7 @@ typedef struct { float clanmode; float quadmode; float duelmode; + float new_balance; float quad_rounds; float quad_round_time; float fo_login_required; @@ -345,14 +346,6 @@ typedef struct { float class_limit_pyro; float class_limit_spy; float class_limit_engineer; - float spurs_on; - float spurs_scout; - float spurs_spy; - float spurs_engineer; - float spurs_duration; - float spurs_boost; - float spurs_consume; - float spurs_flag; } SERVER_SETTINGS; SERVER_SETTINGS SERVER_ADMIN; diff --git a/csqc/events.qc b/csqc/events.qc index 4e55bcb9..fb1fc752 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -272,6 +272,7 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.clanmode = readfloat(); SERVER_ADMIN.quadmode = readfloat(); SERVER_ADMIN.duelmode = readfloat(); + SERVER_ADMIN.new_balance = readfloat(); SERVER_ADMIN.pubmode = (((SERVER_ADMIN.clanmode & 1) || (SERVER_ADMIN.quadmode & 1) || (SERVER_ADMIN.duelmode & 1))?1:0) + (((SERVER_ADMIN.clanmode & 2) || (SERVER_ADMIN.quadmode & 2) || (SERVER_ADMIN.duelmode & 2))?2:0); SERVER_ADMIN.pubmode = 3 - SERVER_ADMIN.pubmode; //Invert diff --git a/csqc/menu.qc b/csqc/menu.qc index bf23d658..2f746daa 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -7,6 +7,7 @@ void (float force) FO_Menu_Admin_Timelimit; void (float force) FO_Menu_Admin_Fraglimit; void (float force) FO_Menu_Admin_QuadTimelimit; void (float force) FO_Menu_Admin_FoMatchRated; +void (float force) FO_Menu_Admin_NewBalance; void (float force) FO_Menu_Spy; void (float force) FO_Menu_Spy_Skin; void (float force) FO_Menu_Spy_Team; @@ -438,10 +439,9 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"2","Clan Mode","","Game has a prematch",FO_MENU_STATE_NORMAL,{localcmd("cmd clanmode\n");},MENU_BORDER_WARNING}, {"3","Quad Mode","","Play for a set number of rounds, designed for attack vs defence",FO_MENU_STATE_NORMAL,{localcmd("cmd quadmode\n");},MENU_BORDER_WARNING}, {"4","Duel Mode","","Simplifies 1 on 1 action",FO_MENU_STATE_NORMAL,{localcmd("cmd duelmode\n");},MENU_BORDER_WARNING}, - {"5","Quad Rounds...","","Number of rounds in Quad mode. Usually 2",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, - {"6","Quad Round Time...","","Round time for each quad round",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, + {"5","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BORDER_WARNING}, {"7","Rated/Unrated","","Will player ratings be affected?",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_FoMatchRated(TRUE);},MENU_BORDER_WARNING}, - {"8","Captains Mode","","Select captains who can then pick their teams",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Players(TRUE, CLIENT_MENU_CAPTAIN_1, 0);},MENU_BORDER_WARNING}, + {"8","New Balance","","New Balance Test",FO_MENU_STATE_NORMAL,{localcmd("cmd new_balance");},MENU_BORDER_WARNING}, {"9","Force Start","","Skip prematch and start the game\nPlease use sparingly",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, {"+","Next - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, @@ -452,16 +452,17 @@ var fo_menu FO_MENU_ADMIN_MODES = { FO_MENU_ADMIN_MODES.options[1].value = modeStatus(SERVER_ADMIN.clanmode); FO_MENU_ADMIN_MODES.options[2].value = modeStatus(SERVER_ADMIN.quadmode); FO_MENU_ADMIN_MODES.options[3].value = modeStatus(SERVER_ADMIN.duelmode); - FO_MENU_ADMIN_MODES.options[4].value = ftos(SERVER_ADMIN.quad_rounds); - FO_MENU_ADMIN_MODES.options[5].value = ftos(SERVER_ADMIN.quad_round_time); + FO_MENU_ADMIN_MODES.options[4].value = SERVER_ADMIN.captainmode?"on":"off"; FO_MENU_ADMIN_MODES.options[6].value = ratedStatus(SERVER_ADMIN.fo_matchrated); - FO_MENU_ADMIN_MODES.options[7].value = SERVER_ADMIN.captainmode?"on":"off"; + FO_MENU_ADMIN_MODES.options[6].value = modeStatus(SERVER_ADMIN.new_balance); } }; var fo_menu FO_MENU_ADMIN_SETTINGS = { [0,0], [300,300], "Settings [3/3]", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Timelimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Timelimit(TRUE);},MENU_BORDER_WARNING}, {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Fraglimit(TRUE);},MENU_BORDER_WARNING}, + {"3","Quad Rounds...","","Number of rounds in Quad mode. Usually 2",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, + {"4","Quad Round Time...","","Round time for each quad round",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, MenuSpacer, MenuSpacer, MenuSpacer, @@ -476,6 +477,8 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { updateAdminMenuInfo(); FO_MENU_ADMIN_SETTINGS.options[0].value = ftos(SERVER_ADMIN.timelimit); FO_MENU_ADMIN_SETTINGS.options[1].value = ftos(SERVER_ADMIN.fraglimit); + FO_MENU_ADMIN_SETTINGS.options[2].value = ftos(SERVER_ADMIN.quad_rounds); + FO_MENU_ADMIN_SETTINGS.options[3].value = ftos(SERVER_ADMIN.quad_round_time); } }; var void execute_admin_players(float choice, float page) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 95755c2a..f8b8fc75 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -328,6 +328,9 @@ void () DecodeLevelParms = { clanbattle = CF_GetSetting("c", "clan", "off"); quadmode = CF_GetSetting("quadmode", "quadmode", "off"); duelmode = CF_GetSetting("duelmode", "duelmode", "off"); + new_balance = CF_GetSetting("new_balance", "new_balance", "off"); + // mirror current state into desired state bit + new_balance |= (new_balance << 1); disable_voting = clanbattle || quadmode; @@ -1037,6 +1040,10 @@ void () DecodeLevelParms = { p = find(p, classname, "player"); } */ + + // Overrides other settings. + if (new_balance) { + } }; entity() FindIntermission = diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 481527fe..2cbcbf7d 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -123,6 +123,14 @@ void () DuelMode = bprint(PRINT_HIGH, "Map Restart needed to take effect!\n"); } +void new_balance_mode() { + new_balance ^= 2; + if (new_balance & 2) + localcmd("localinfo new_balance 1\n"); + else + localcmd("localinfo new_balance 0\n"); +} + void (entity pe) SetEquipmentForPlayer = { entity oldself = self; self = pe; @@ -1228,6 +1236,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { processedCmd = TRUE; DuelMode(); break; + case "new_balance": + processedCmd = TRUE; + new_balance_mode(); + break; case "forcestart": processedCmd = TRUE; ForceStartMatch(); diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 2dff5fc4..7f9988bc 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -184,6 +184,7 @@ void Update_ServerAdminInfo(entity pl) = { WriteFloat(MSG_MULTICAST, (clanbattle?1:0) + (cm?2:0)); WriteFloat(MSG_MULTICAST, (quadmode?1:0) + (qm?2:0)); WriteFloat(MSG_MULTICAST, (duelmode?1:0) + (dm?2:0)); + WriteFloat(MSG_MULTICAST, new_balance); WriteFloat(MSG_MULTICAST, captainmode); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 1c98aad5..47c3197b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -800,3 +800,5 @@ string match_id; string backend_address; float fo_login_required; .entity filter_ent; + +float new_balance; From 921f055e028494fce1d721239072b9f9b0339442 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 22 Dec 2023 23:36:57 -0800 Subject: [PATCH 2276/2474] new_balance: add helpers for server region and staging status --- ssqc/helpers.qc | 19 +++++++++++++++++++ ssqc/progs.src | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 ssqc/helpers.qc diff --git a/ssqc/helpers.qc b/ssqc/helpers.qc new file mode 100644 index 00000000..417d6552 --- /dev/null +++ b/ssqc/helpers.qc @@ -0,0 +1,19 @@ +enum { + kRegionUS, + kRegionOther, +}; + +const string kNorthAmericaChannel = "504171613793681408"; + +float ServerRegion() { + if (discord_channel_id == kNorthAmericaChannel) + return kRegionUS; + + return kRegionOther; +} + +float ServerIsStaging() { + string hostname = serverkey("hostname"); + + return strstrofs(hostname, "Staging") >= 0; +} diff --git a/ssqc/progs.src b/ssqc/progs.src index 33cf1839..e563dbaa 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -23,7 +23,8 @@ time.qc ../share/prediction.qc ../share/classes.qc ../share/animate.qc -../share/mcp_precache.qc +../share/mcp_precache.qc +helpers.qc events.qc roles.qc q3defs.qc From 79294f2311d19a8314e0162c19e91bcd82acecbb Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 22 Dec 2023 23:42:24 -0800 Subject: [PATCH 2277/2474] new_balance: default on for us-staging --- ssqc/client.qc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index f8b8fc75..f9acf158 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -328,7 +328,13 @@ void () DecodeLevelParms = { clanbattle = CF_GetSetting("c", "clan", "off"); quadmode = CF_GetSetting("quadmode", "quadmode", "off"); duelmode = CF_GetSetting("duelmode", "duelmode", "off"); - new_balance = CF_GetSetting("new_balance", "new_balance", "off"); + new_balance = CF_GetSetting("new_balance", "new_balance", "4"); + + + if (new_balance == 4) { + ServerIsStaging(); + new_balance = ((ServerRegion() == kRegionUS) && ServerIsStaging()) ? 1 : 0; + } // mirror current state into desired state bit new_balance |= (new_balance << 1); From b1adba9a6011de46e9a1b8fea9d16b92f27b4995 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 22 Dec 2023 23:57:33 -0800 Subject: [PATCH 2278/2474] new-balance: first experiments - max 3 gren1 - 1 mirv demo, 0 mirv heavy, no detpack - no gren1 pickups from packs - no gren2 pickups spawns - 20s airblast cooldown - 50 minping t --- share/defs.h | 1 - ssqc/client.qc | 21 +++++++++++++++++++-- ssqc/demoman.qc | 4 ++++ ssqc/qw.qc | 1 + 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/share/defs.h b/share/defs.h index 01baa576..10d29f1f 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1062,7 +1062,6 @@ enumflags { #define PC_PYRO_GRENADE_MAX_2 4 #define PC_PYRO_TF_ITEMS 0 #define PC_PYRO_AIRBLAST_RANGE 400 -#define PC_PYRO_AIRBLAST_COOLDOWN 5 #define PC_PYRO_AIRBLAST_CELLS 55 #define PC_PYRO_AIRBLASTJUMP_CELLS 75 #define PC_PYRO_LAVA_LIFETIME 3 diff --git a/ssqc/client.qc b/ssqc/client.qc index f9acf158..16bf4e2a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -223,6 +223,23 @@ void InitPrematch() } } +float ActivateNewBalance() { + disable_resup_gren = 2; // No gren2 pickups + if (fo_config.min_ping_ms < 50) // 50 min-ping + localcmd("localinfo mpm 50"); + + drop_gren1 = 0; // No grenades in backpacks + + int i; + for (i = 1; i <= 9; i++) // 3 gren spawn + Role_None.gren1_limits[i] = 3; + + Role_None.gren2_limits[4] = 1; // 1 mirv for demoman + Role_None.gren2_limits[6] = 0; // 0 mirv for heavy + + PC_PYRO_AIRBLAST_COOLDOWN = 20; +} + void () DecodeLevelParms = { local float fl; local string st; @@ -1048,8 +1065,8 @@ void () DecodeLevelParms = { */ // Overrides other settings. - if (new_balance) { - } + if (new_balance) + ActivateNewBalance(); }; entity() FindIntermission = diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 94575ceb..54d823f2 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -146,6 +146,10 @@ void (float timer) TeamFortress_SetDetpack = { self.impulse = 0; self.last_impulse = 0; + + if (new_balance & 1) // No detpacks + self.ammo_detpack = 0; + if (self.ammo_detpack <= 0) { sprint(self, PRINT_HIGH, "You don't have any detpacks left\n"); return; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 47c3197b..a96bd6ba 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -802,3 +802,4 @@ float fo_login_required; .entity filter_ent; float new_balance; +var float PC_PYRO_AIRBLAST_COOLDOWN = 5; From 64e4ca9bf58d8faa135ed5cbee0dfc9928f2ffc2 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 23 Dec 2023 00:01:44 -0800 Subject: [PATCH 2279/2474] pmove: possibly fix free flight in demos --- csqc/pmove.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index fb975262..068c5c4b 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -803,6 +803,9 @@ void PM_Update(float sendflags) { float enabled = (pstate_server.predict_flags & PF_PMOVE) && game_state.is_player; + if (isdemo()) + enabled = 0; + if (enabled != was_enabled || game_state.is_player != prev_game_state.is_player) PM_SetEnabled(enabled); From 92a7b9d98267e2c10c3ea5356bde18b9c20cf9ac Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 23 Dec 2023 00:08:44 -0800 Subject: [PATCH 2280/2474] pmove: no knockback prediction from occluded explosions --- csqc/pmove.qc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 068c5c4b..302950e0 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -387,6 +387,11 @@ static void PM_NudgeExplosion(PM_Nudge* nudge, entity ent) { if (vlen(ent.origin - nudge->org) > dmg + 40) return; + const float MOVE_WORLDONLY = 3; + traceline(ent.origin, nudge->org, MOVE_WORLDONLY, pm.ent); + if (trace_fraction < 1) // No knock from occluded explosions + return; + float flg = KF_BOTH_PLAYER; // Assumes everything is from a player for now if (nudge->src.owner == pengine.player_ent) flg |= KF_SELF; From 58c46694b5d422d1b22bda222b10a5e4dd5b79ef Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 23 Dec 2023 00:27:15 -0800 Subject: [PATCH 2281/2474] new-balance: move auto-init down We depend on discord_channel_id which is not initialized until later. Just move to end of init. --- ssqc/client.qc | 20 ++++++++++---------- ssqc/helpers.qc | 4 ++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 16bf4e2a..c27ad7ba 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -345,15 +345,6 @@ void () DecodeLevelParms = { clanbattle = CF_GetSetting("c", "clan", "off"); quadmode = CF_GetSetting("quadmode", "quadmode", "off"); duelmode = CF_GetSetting("duelmode", "duelmode", "off"); - new_balance = CF_GetSetting("new_balance", "new_balance", "4"); - - - if (new_balance == 4) { - ServerIsStaging(); - new_balance = ((ServerRegion() == kRegionUS) && ServerIsStaging()) ? 1 : 0; - } - // mirror current state into desired state bit - new_balance |= (new_balance << 1); disable_voting = clanbattle || quadmode; @@ -1065,7 +1056,16 @@ void () DecodeLevelParms = { */ // Overrides other settings. - if (new_balance) + new_balance = CF_GetSetting("new_balance", "new_balance", "4"); + + if (new_balance == 4) { + printf("Staging = %d\n", ServerIsStaging()); + new_balance = ((ServerRegion() == kRegionUS) && ServerIsStaging()) ? 1 : 0; + } + + // mirror current state into desired state bit + new_balance |= (new_balance << 1); + if (ServerIsNewBalance()) ActivateNewBalance(); }; diff --git a/ssqc/helpers.qc b/ssqc/helpers.qc index 417d6552..647a7cf7 100644 --- a/ssqc/helpers.qc +++ b/ssqc/helpers.qc @@ -17,3 +17,7 @@ float ServerIsStaging() { return strstrofs(hostname, "Staging") >= 0; } + +float ServerIsNewBalance() { + return new_balance & 1; +} From 75a4e495735b0a4bb0014acb95356647f5a68d33 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 23 Dec 2023 01:01:43 -0800 Subject: [PATCH 2282/2474] new-balance: fix debug print spam --- ssqc/client.qc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index c27ad7ba..a9a1b18a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1058,10 +1058,8 @@ void () DecodeLevelParms = { // Overrides other settings. new_balance = CF_GetSetting("new_balance", "new_balance", "4"); - if (new_balance == 4) { - printf("Staging = %d\n", ServerIsStaging()); + if (new_balance == 4) new_balance = ((ServerRegion() == kRegionUS) && ServerIsStaging()) ? 1 : 0; - } // mirror current state into desired state bit new_balance |= (new_balance << 1); From a737e9b2e6595b4b24d6eb0e4d99b9754931c02e Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 23 Dec 2023 21:30:09 -0800 Subject: [PATCH 2283/2474] new-balance: no knockback on napalm - airblast cooldown reduced from 20 -> 15 to compensate --- ssqc/client.qc | 2 +- ssqc/pyro.qc | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index a9a1b18a..fbb8dd6d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -237,7 +237,7 @@ float ActivateNewBalance() { Role_None.gren2_limits[4] = 1; // 1 mirv for demoman Role_None.gren2_limits[6] = 0; // 0 mirv for heavy - PC_PYRO_AIRBLAST_COOLDOWN = 20; + PC_PYRO_AIRBLAST_COOLDOWN = 15; } void () DecodeLevelParms = { diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index d6036f47..f1e144fd 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -169,8 +169,11 @@ void () NapalmGrenadeExplode2 = { if (head.takedamage) { deathmsg = DMSG_FLAME; - TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, - TF_TD_FIRE); + float aflags = TF_TD_FIRE; + if (ServerIsNewBalance()) + aflags |= TF_TD_NOMOMENTUM; + + TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, aflags); other = head; Napalm_touch(); if (other.classname == "player") { From 60693b24e5349a2dde5549039db97f97fc84e7c3 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 23 Dec 2023 21:31:53 -0800 Subject: [PATCH 2284/2474] new-balance: smaller emp blast radius --- share/defs.h | 1 - ssqc/client.qc | 1 + ssqc/qw.qc | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 10d29f1f..2a81d90e 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1125,7 +1125,6 @@ enumflags { #define PC_ENGINEER_GRENADE_MAX_1 4 #define PC_ENGINEER_GRENADE_MAX_2 4 #define PC_ENGINEER_TF_ITEMS 0 -#define PC_ENGINEER_GRENADE_TYPE_2_RANGE 240 #define PC_ENGINEER_RAILSPEED 1500 // Class Details for CIVILIAN diff --git a/ssqc/client.qc b/ssqc/client.qc index fbb8dd6d..7b289631 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -238,6 +238,7 @@ float ActivateNewBalance() { Role_None.gren2_limits[6] = 0; // 0 mirv for heavy PC_PYRO_AIRBLAST_COOLDOWN = 15; + PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; } void () DecodeLevelParms = { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a96bd6ba..01ca7c7f 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -803,3 +803,4 @@ float fo_login_required; float new_balance; var float PC_PYRO_AIRBLAST_COOLDOWN = 5; +var float PC_ENGINEER_GRENADE_TYPE_2_RANGE = 240; From 1fa763b557e6873a12fa05b3eaae2596ba763563 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 24 Dec 2023 13:46:35 -0800 Subject: [PATCH 2285/2474] new-balance: publish activation to client --- share/commondefs.qc | 2 ++ share/prediction.qc | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/share/commondefs.qc b/share/commondefs.qc index a6bc12d4..02d5a635 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -53,6 +53,8 @@ var struct { float fo_concuss; float rj; + + float new_balance; } fo_config; enumflags { diff --git a/share/prediction.qc b/share/prediction.qc index 495bc7b8..cdc735f9 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -479,6 +479,7 @@ void EntUpdate_Config() { COMM(Byte, gren_beta_disable); COMM(Byte, old_ng_rof); COMM(Short, fo_concuss); + COMM(Byte, new_balance); #ifdef SSQC return TRUE; @@ -724,6 +725,7 @@ void Predict_InitDefaultConfig() { fo_config.clown_flags = 0; fo_config.clown_grav = 400; fo_config.fo_concuss = 0; + fo_config.new_balance = 0; } #ifdef SSQC @@ -790,6 +792,11 @@ static void WeaponPred_CheckConfigUpdate() { update = TRUE; } + if ((new_balance & 1) != fo_config.new_balance) { + fo_config.new_balance = new_balance & 1; + update = TRUE; + } + // Not dynamically updatable. static float read_rof_once = FALSE; if (!read_rof_once) { From 269ee0e9bba54c57ef9d2f079dc9d721ab775fc8 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 27 Dec 2023 18:03:58 -0800 Subject: [PATCH 2286/2474] new-balance: fix quad mode grenades and ammobox pickups --- ssqc/client.qc | 18 +++++++++++++----- ssqc/items.qc | 9 ++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 7b289631..d845f1f3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -223,6 +223,15 @@ void InitPrematch() } } +static void SetAllRoles(float pc, float gren, float limit) { + if (gren == 1) + Role_None.gren1_limits[pc] = Role_Attack.gren1_limits[pc] = + Role_Defence.gren1_limits[pc] = limit; + else + Role_None.gren2_limits[pc] = Role_Attack.gren2_limits[pc] = + Role_Defence.gren2_limits[pc] = limit; +} + float ActivateNewBalance() { disable_resup_gren = 2; // No gren2 pickups if (fo_config.min_ping_ms < 50) // 50 min-ping @@ -231,11 +240,11 @@ float ActivateNewBalance() { drop_gren1 = 0; // No grenades in backpacks int i; - for (i = 1; i <= 9; i++) // 3 gren spawn - Role_None.gren1_limits[i] = 3; + for (i = 1; i <= 9; i++) // 3 gren spawn + SetAllRoles(i, 1, 3); - Role_None.gren2_limits[4] = 1; // 1 mirv for demoman - Role_None.gren2_limits[6] = 0; // 0 mirv for heavy + SetAllRoles(4, 2, 1); // 1 mirv for demoman + SetAllRoles(6, 2, 0); // 0 mirv for hwguy PC_PYRO_AIRBLAST_COOLDOWN = 15; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; @@ -262,7 +271,6 @@ void () DecodeLevelParms = { self.armortype = parm9 * 0.01; if (!(toggleflags & TFLAG_FIRSTENTRY)) { - toggleflags = parm10; flagem_checked = 0; invis_only = 0; diff --git a/ssqc/items.qc b/ssqc/items.qc index ed1875cb..c4857d0b 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -733,7 +733,14 @@ float () GetGrenadePossibility = { if (random() < 0.500) return 0; - float index = random() < 0.5 ? 0 : 1; + float index; + switch (disable_resup_gren) { + case 0: index = random() < 0.5 ? 0 : 1; break; + case 1: index = 1; break; + case 2: index = 0; break; + case 3: return 0; + } + FO_GrenInfo* gt = FO_PlayerGren(other, index); if (gt->id == GREN_NONE) return 0; From b79b913174bd7e63e1182fc15022862d95d6ac5f Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 27 Dec 2023 21:08:35 -0800 Subject: [PATCH 2287/2474] weapons: fix grenade pickup text --- share/weapons.qc | 4 +++- ssqc/items.qc | 25 ++++++------------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/share/weapons.qc b/share/weapons.qc index 1d44c5dc..6101212f 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -159,7 +159,7 @@ enum { struct FO_GrenInfo { int id; - string logname; + string name; string model; int skin; string icon; @@ -167,6 +167,7 @@ struct FO_GrenInfo { // Automatically initialized below this line. float modelindex; + string logname; }; FO_GrenInfo fo_grenades[] = { @@ -815,6 +816,7 @@ void FO_Weapons_Init() { FO_GrenInfo* gdesc = &fo_grenades[i]; ASSERTD_EQ(GREN_FIRST + i, gdesc->id); + gdesc->logname = gdesc->name; if (i < GREN_RED) gdesc->logname = strcat(strtolower(gdesc->logname), "grenade"); diff --git a/ssqc/items.qc b/ssqc/items.qc index c4857d0b..4d99d6c7 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -704,29 +704,16 @@ void () weapon_lightning = { StartItem(); }; -void (entity pl, float type) PrintGrenadeType = { - // TODO: this is still awful - string st = FO_GrenDesc(type)->logname; - sprint(pl, PRINT_HIGH, st); -}; - void (entity pe_player, float pf_grenade_type, float pf_grenade_count) PrintFoundGrenade = { if (!pf_grenade_count) return; - sprint(pe_player, PRINT_HIGH, "You found "); - if (pf_grenade_count > 1) - sprint(pe_player, PRINT_HIGH, ftos(pf_grenade_count), " "); - else - sprint(pe_player, PRINT_HIGH, "a "); - PrintGrenadeType(pe_player, pf_grenade_type); - if (pf_grenade_type == GREN_CALTROP) - sprint(pe_player, PRINT_HIGH, " canister"); - else - sprint(pe_player, PRINT_HIGH, " grenade"); - if (pf_grenade_count > 1) - sprint(pe_player, PRINT_HIGH, "s"); - sprint(pe_player, PRINT_HIGH, "\n"); + string buf = sprintf("You found %s%s %s%s\n", + pf_grenade_count > 1 ? " " : "a ", + FO_GrenDesc(pf_grenade_type)->name, + pf_grenade_type == GREN_CALTROP ? "cannister" : "grenade", + pf_grenade_count > 1 ? "s" : ""); + sprint(pe_player, PRINT_HIGH, buf); }; float () GetGrenadePossibility = { From b38200e31c403512569ccbbc9ad514841c3a80ad Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Dec 2023 03:49:39 -0800 Subject: [PATCH 2288/2474] clock: fix clock sync --- csqc/csextradefs.qc | 2 ++ csqc/status.qc | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 32613e5a..6aff7a82 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -918,3 +918,5 @@ void cvar_parse4(string s, __out veci target) { target.v[2] = stof(argv(2)); target.i = stof(argv(3)); } + +float servertime; diff --git a/csqc/status.qc b/csqc/status.qc index 16752c7e..6999f0d1 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -305,9 +305,9 @@ string gameClockString() { if (!end) end = timelimit * 60; - if (end) { - minutes = (end - time)/60; - seconds = (end - time)%60; + if (end && end > servertime) { + minutes = (end - servertime)/60; + seconds = (end - servertime)%60; } else { minutes = time/60; seconds = time%60; From a9d332df350d348a64c21fc8f54566a5c6bea632 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 29 Dec 2023 04:24:16 -0800 Subject: [PATCH 2289/2474] new-balance: long live the detpack bring back detpack but with a 30 second cooldown for defense only --- ssqc/demoman.qc | 15 ++++++++++++--- ssqc/quadmode.qc | 3 ++- ssqc/qw.qc | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 54d823f2..3ecca191 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -147,9 +147,6 @@ void (float timer) TeamFortress_SetDetpack = { self.impulse = 0; self.last_impulse = 0; - if (new_balance & 1) // No detpacks - self.ammo_detpack = 0; - if (self.ammo_detpack <= 0) { sprint(self, PRINT_HIGH, "You don't have any detpacks left\n"); return; @@ -206,6 +203,17 @@ void (float timer) TeamFortress_SetDetpack = { return; } + float quad_limit = quadmode && round_active && + (time < round_end_time) && (rounds % 2) != (self.team_no - 1); + if (ServerIsNewBalance() && quad_limit) { + float last = max(self.detpack_last, round_start_time); + float next = last + 30; // TODO: tunable if this sticks + if (next > time) { + sprint(self, PRINT_HIGH, sprintf("%0.1f seconds until next detpack\n", next - time)); + return; + } + } + self.is_detpacking = 3; self.detpack_left = timer; self.ammo_detpack = self.ammo_detpack - 1; @@ -221,6 +229,7 @@ void (float timer) TeamFortress_SetDetpack = { " seconds...\n"); Menu_Demoman_Cancel(); + self.detpack_last = time; newmis = spawn(); newmis.owner = self; newmis.classname = "timer"; diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 3f673ad0..8693e192 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -518,7 +518,8 @@ void () QuadRoundBegin = { if (rounds == 1) PostFOQuadFinalRoundStarted(); - round_end_time = time + round_time * 60 + 1; + round_start_time = time; + round_end_time = round_start_time + round_time * 60 + 1; UpdateClientQuadRoundBegin(te, round_time); if (!self.cnt) { diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 01ca7c7f..883a8652 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -468,6 +468,7 @@ float rounds; float round_active; float round_over; float round_delay_time; +float round_start_time; float round_end_time; float map_restart_time; float gametime; @@ -804,3 +805,4 @@ float fo_login_required; float new_balance; var float PC_PYRO_AIRBLAST_COOLDOWN = 5; var float PC_ENGINEER_GRENADE_TYPE_2_RANGE = 240; +.float detpack_last; From df08b2baaa75de64d6b7af411c8f558a65963785 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 6 Jan 2024 00:26:08 -0800 Subject: [PATCH 2290/2474] rewind: remove FPF_FIXED_DYNAMIC --- share/commondefs.qc | 1 - ssqc/rewind.qc | 2 -- ssqc/tfort.qc | 6 ------ 3 files changed, 9 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 02d5a635..252a488c 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -24,7 +24,6 @@ struct ConcState { enumflags { FPF_NO_REWIND, - FPF_FIXED_DYNAMIC, }; var struct { diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 58d4ea1b..62e16a8c 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -336,8 +336,6 @@ void Forward_Projectile(int fpp_type, entity proj, float use_ctime) { float static_dt = offset.static_ms / 1000.0; float dynamic_dt = offset.dynamic_ms / 1000.0; - if (proj.fpp.flags & FPF_FIXED_DYNAMIC) - dynamic_dt = proj.fpp.dynamic_dt; float stime = time - dynamic_dt; float no_rewind = proj.fpp.flags & FPF_NO_REWIND; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index c9a9920c..b145e1f2 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2398,12 +2398,6 @@ void () TeamFortress_ExplodePerson = { proj.angles = vectoangles(proj.velocity); proj.think = SUB_Null; float expires = time + 0.1; // Server generated, no client time here. - float rw_dt = FO_RewindGrenWinDt(gtype); - if (rw_dt > 0) { - proj.fpp.flags |= FPF_FIXED_DYNAMIC; - proj.fpp.dynamic_dt = rw_dt; - expires -= rw_dt; - } proj.nextthink = expires; if (self.weapon == GREN_FLARE) { From 156d1f140f7620d93cef27450847aa69ec200957 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 6 Jan 2024 00:24:21 -0800 Subject: [PATCH 2291/2474] rewind: improve accuracy, simplify forward knock, refactor --- ssqc/rewind.qc | 25 +++++++++++++------------ ssqc/weapons.qc | 8 +------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 62e16a8c..8208a00f 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -8,7 +8,7 @@ #define rw_printd(...) #endif -#define MAX_SNAPSHOTS 25 +#define MAX_SNAPSHOTS 50 inline int NextRewindIdx(int idx) { return (idx + 1) % MAX_SNAPSHOTS; @@ -111,7 +111,7 @@ RewindSnapshot* RewindLog(RewindState* target) { target->owner->client_lastupdate = time; RewindSnapshot* rs = &target->snapshot[target->cur]; - if (time > rs->time + 0.05) { + if (time > rs->time) { if (rs->time) { target->cur = NextRewindIdx(target->cur); rs = &target->snapshot[target->cur]; @@ -336,30 +336,31 @@ void Forward_Projectile(int fpp_type, entity proj, float use_ctime) { float static_dt = offset.static_ms / 1000.0; float dynamic_dt = offset.dynamic_ms / 1000.0; - float stime = time - dynamic_dt; - float no_rewind = proj.fpp.flags & FPF_NO_REWIND; - float rewind_hit = !no_rewind && RewindFlagEnabled(REWIND_PROJ_FIRE); + float rewind_hit = RewindFlagEnabled(REWIND_PROJ_FIRE) && + !(proj.fpp.flags & FPF_NO_REWIND) && + dynamic_dt > 0; + float phys_flags = PHYSF_CONSUME_ALL; + float stime = time; + if (rewind_hit) { + stime -= dynamic_dt; phys_flags |= PHYSF_REWIND_PLAYERS; RL_StashPositions(rewind_players); RL_RewindTo(rewind_players, proj.owner, stime); } - if (!no_rewind && RewindFlagEnabled(REWIND_FORWARD_PROJ_SELFKNOCK)) - phys_flags |= PHYSF_FORWARD_KNOCK; - // Static projection happens instantly. If rewind is active, we'll do it at // a prior point in time, but we don't advance time while stepping. - proj.s_origin = proj.origin; - proj.s_time = 0; float ft = Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); // We initialize s_origin/s_time after Phys_Init, they are used when // knockback forwarding is on to determine delay. - proj.s_origin = proj.origin; - proj.s_time = time; + if (rewind_hit && RewindFlagEnabled(REWIND_FORWARD_PROJ_SELFKNOCK)) { + phys_flags |= PHYSF_FORWARD_KNOCK; + proj.s_origin = proj.origin; + } if (!proj.voided) { RewindSyncTime = ProjRewindForPhys; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 7f7574fb..e22c15b2 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1043,9 +1043,7 @@ void T_Knock_Antilag() { } float AntilagKnock(entity e, float dmg) { - if (!RewindFlagEnabled(REWIND_FORWARD_PROJ_SELFKNOCK) || e.s_time == 0) - return FALSE; - + e.forward_knock = -1; // Only applies during initial antilag forward if (e.flags & FL_FORWARD_KNOCK == 0) return FALSE; @@ -1070,7 +1068,6 @@ float AntilagKnock(entity e, float dmg) { e.forward_knock = time + ttime; } else { Antilag_Knock(knock_e); - e.forward_knock = -1; } return TRUE; @@ -1095,9 +1092,6 @@ void () T_MissileTouch = { entity ignore_self = AntilagKnock(self, dmg) ? self.owner : __NULL__; T_RadiusDamage(self, self.owner, dmg, other, ignore_self); - if (!self.s_time) - self.forward_knock = -1; - self.origin = self.origin - 8 * normalize(self.velocity); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); From 3d6f12ec951694f4f7498f0a12158a2013c119a7 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 6 Jan 2024 01:28:53 -0800 Subject: [PATCH 2292/2474] rewind: double-check for collisions In some cases we seem to be missing qwsv generated collisions versus entities, possibly due to order of processing; add an explicit double check as part of rewind logging --- share/commondefs.qc | 5 ++++- ssqc/rewind.qc | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 252a488c..001c21c1 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -62,6 +62,7 @@ enumflags { REWIND_GRENADES, REWIND_SENDEVENT, REWIND_FORWARD_PROJ_SELFKNOCK, + REWIND_DOUBLE_COL, REWIND_FORWARD_DOORS, }; @@ -71,13 +72,15 @@ string REWIND_DESC[] = { "rewind grenade throws", "use sendevent augmentation (allows race w/ death rewind)", "forward projectile self-knockback", + "additional collision checks", "open doors earlier for hpbs [requires rfd=1]", }; const float REWIND_DEFAULT_FLAGS = REWIND_PROJ_FIRE | REWIND_PROJ_TRAVEL | REWIND_FORWARD_PROJ_SELFKNOCK | - REWIND_SENDEVENT; + REWIND_SENDEVENT | + REWIND_DOUBLE_COL; float RewindFlagEnabled(float flag) { diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 8208a00f..2407946e 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -104,6 +104,31 @@ static SeekResult RewindSeek(RewindState* rstate, float rtime) { return r; } +static void DoubleCheckCollision(entity player, + RewindSnapshot* a, + RewindSnapshot* b) { + + if (vlen(b->origin - a->origin) > 48) + return; // Teleport + + const vector PLAYER_MINS = [-16, -16, -24], PLAYER_MAXS = [16, 16, 32]; + tracebox(a->origin, PLAYER_MINS, PLAYER_MAXS, b->origin, 0, player); + if (trace_fraction == 1) + return; + + entity hit = trace_ent; + + if (!hit.voided && hit.fpp.index && hit.touch) { + setorigin(player, trace_endpos); + + entity held_self = self; + self = hit; + other = player; + self.touch(); + self = held_self; + } +} + RewindSnapshot* RewindLog(RewindState* target) { if (target->owner != self) error("Log mismatch\n"); @@ -111,6 +136,7 @@ RewindSnapshot* RewindLog(RewindState* target) { target->owner->client_lastupdate = time; RewindSnapshot* rs = &target->snapshot[target->cur]; + RewindSnapshot* last = rs; if (time > rs->time) { if (rs->time) { target->cur = NextRewindIdx(target->cur); @@ -125,6 +151,9 @@ RewindSnapshot* RewindLog(RewindState* target) { rs->origin = target->owner.origin; rs->velocity = target->owner.velocity; + if (RewindFlagEnabled(REWIND_DOUBLE_COL) && rs != last) + DoubleCheckCollision(target->owner, last, rs); + return rs; } From c34581da1b0509beaa1c4c61382e85db9415c70d Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 6 Jan 2024 01:30:29 -0800 Subject: [PATCH 2293/2474] nit: fix warning --- ssqc/items.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/items.qc b/ssqc/items.qc index 4d99d6c7..e0916a35 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -725,7 +725,10 @@ float () GetGrenadePossibility = { case 0: index = random() < 0.5 ? 0 : 1; break; case 1: index = 1; break; case 2: index = 0; break; - case 3: return 0; + + case 3: + default: + return 0; } FO_GrenInfo* gt = FO_PlayerGren(other, index); From 8c533c12a9683da26fbbecc9758bc7ea0cd4dc1a Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 6 Jan 2024 12:31:14 -0800 Subject: [PATCH 2294/2474] rewind: check deadflag in double-check --- ssqc/rewind.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index 2407946e..c31c2365 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -107,7 +107,8 @@ static SeekResult RewindSeek(RewindState* rstate, float rtime) { static void DoubleCheckCollision(entity player, RewindSnapshot* a, RewindSnapshot* b) { - + if (player.deadflag) + return; // Dead if (vlen(b->origin - a->origin) > 48) return; // Teleport From 2915db9750ba743a3a7d03f23bea6cd6bfe66074 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 09:08:44 -0800 Subject: [PATCH 2295/2474] new-balance: expand region matching --- ssqc/client.qc | 7 +++++-- ssqc/helpers.qc | 35 +++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index d845f1f3..13130a30 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -234,8 +234,6 @@ static void SetAllRoles(float pc, float gren, float limit) { float ActivateNewBalance() { disable_resup_gren = 2; // No gren2 pickups - if (fo_config.min_ping_ms < 50) // 50 min-ping - localcmd("localinfo mpm 50"); drop_gren1 = 0; // No grenades in backpacks @@ -248,6 +246,11 @@ float ActivateNewBalance() { PC_PYRO_AIRBLAST_COOLDOWN = 15; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; + + if (ServerRegion() == kRegionUS || ServerRegion() == kRegionEU) { + if (fo_config.min_ping_ms < 50) // 50 min-ping + localcmd("localinfo mpm 50"); + } } void () DecodeLevelParms = { diff --git a/ssqc/helpers.qc b/ssqc/helpers.qc index 647a7cf7..cda76aa0 100644 --- a/ssqc/helpers.qc +++ b/ssqc/helpers.qc @@ -1,15 +1,38 @@ enum { - kRegionUS, - kRegionOther, + kRegionUS = 1, + kRegionEU, + kRegionOCE, + kRegionUnknown, }; -const string kNorthAmericaChannel = "504171613793681408"; +struct RegionMatch { + string channel; + float region; +}; + +static RegionMatch region_matches[] = { + { "504171613793681408", kRegionUS }, // US pug + { "513699536846323712", kRegionEU }, // EU pug + { "542237808895459338", kRegionOCE }, // OCE pug +}; float ServerRegion() { - if (discord_channel_id == kNorthAmericaChannel) - return kRegionUS; + static float region; + + if (region) + return region; + + // Can also query FO_REGION env but that does not appear to be + // reliably/consistently set at the moment. + region = kRegionUnknown; + for (int i = 0; i < region_matches.length; i++) { + if (discord_channel_id == region_matches[i].channel) { + region = region_matches[i].region; + break; + } + } - return kRegionOther; + return region; } float ServerIsStaging() { From 18c5e04192bea820cbc58e241b19be330d970584 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 09:25:28 -0800 Subject: [PATCH 2296/2474] new-balance: more fuzzy matching for regions --- ssqc/client.qc | 13 +++++++++++-- ssqc/helpers.qc | 23 ++++++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 13130a30..d1bac75f 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -232,7 +232,16 @@ static void SetAllRoles(float pc, float gren, float limit) { Role_Defence.gren2_limits[pc] = limit; } -float ActivateNewBalance() { +static float NB_UseMinPing() { + if (ServerIsOCE()) + return FALSE; + + if (ServerRegion() == kRegionUnknown) + return FALSE; // e.g. random server, including LAN + return TRUE; +} + +void ActivateNewBalance() { disable_resup_gren = 2; // No gren2 pickups drop_gren1 = 0; // No grenades in backpacks @@ -247,7 +256,7 @@ float ActivateNewBalance() { PC_PYRO_AIRBLAST_COOLDOWN = 15; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; - if (ServerRegion() == kRegionUS || ServerRegion() == kRegionEU) { + if (NB_UseMinPing()) { if (fo_config.min_ping_ms < 50) // 50 min-ping localcmd("localinfo mpm 50"); } diff --git a/ssqc/helpers.qc b/ssqc/helpers.qc index cda76aa0..72c633c3 100644 --- a/ssqc/helpers.qc +++ b/ssqc/helpers.qc @@ -2,6 +2,7 @@ enum { kRegionUS = 1, kRegionEU, kRegionOCE, + kRegionLeague, kRegionUnknown, }; @@ -11,9 +12,11 @@ struct RegionMatch { }; static RegionMatch region_matches[] = { - { "504171613793681408", kRegionUS }, // US pug - { "513699536846323712", kRegionEU }, // EU pug - { "542237808895459338", kRegionOCE }, // OCE pug + { "504171613793681408", kRegionUS }, // US pug + { "513699536846323712", kRegionEU }, // EU pug + { "542237808895459338", kRegionOCE }, // OCE pug + { "1147341454851719219", kRegionLeague }, // Scrim + { "1026405619231625257", kRegionLeague }, // Tourney }; float ServerRegion() { @@ -35,6 +38,20 @@ float ServerRegion() { return region; } +float ServerIsOCE() { + if (ServerRegion() == kRegionOCE) + return TRUE; + + // Additional check beyond kRegion for picking up OCE Scrim/Tourney etc + // This is pretty awful, for at least these servers we should just fix FO_REGION + // to be consistent in the future. + string hostname = serverkey("hostname"); + + return strstrofs(hostname, "Sydney") >= 0 || + strstrofs(hostname, "Melbourne") >= 0 || + strstrofs(hostname, "New Zealand") >= 0; +} + float ServerIsStaging() { string hostname = serverkey("hostname"); From e6601ab20f1a229e9a036ed1118dc3f87e5a633c Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 10:05:24 -0800 Subject: [PATCH 2297/2474] core: finish removing s_time from server side, fix entity removal This fixes leaking ents with sky collisions. --- share/commondefs.qc | 1 - share/prediction.qc | 1 + ssqc/debug.qc | 16 ++++++++-------- ssqc/rewind.qc | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/share/commondefs.qc b/share/commondefs.qc index 001c21c1..4885c849 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -172,7 +172,6 @@ const float SERVER_FRAME_DT = 1/SERVER_FPS; const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; .vector s_origin; -.float s_time; #define MAX_FLAGINFO_LINES 10 #define ENG_BUILDING_DISMANTLE_DISTANCE 100 diff --git a/share/prediction.qc b/share/prediction.qc index cdc735f9..6e3c43b6 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -451,6 +451,7 @@ void InitProjectileEnt(float sendflags); void WPP_UpdateEnable(float force); .float owner_entnum; +.float s_time; #endif #ifdef SSQC diff --git a/ssqc/debug.qc b/ssqc/debug.qc index a5d81b51..4d9ccf4c 100644 --- a/ssqc/debug.qc +++ b/ssqc/debug.qc @@ -16,17 +16,17 @@ void (entity te) dremove = remove(te); }; +.float created_at; // Forward dec void dremove_sent(entity te) { - static const float epsilon = 3*SERVER_FRAME_DT; - float stime = te.s_time; - if (!stime) - stime = time; + static const float epsilon = 2*SERVER_FRAME_DT; - if (time > stime + epsilon) { - dremove(self); + float expires = te.created_at + epsilon; // In the past for 0 created at + + if (time > expires) { + dremove(te); } else { - self.nextthink = stime + epsilon; - self.think = SUB_Remove; + te.nextthink = expires; + te.think = SUB_Remove; } } diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index c31c2365..e4f8a43c 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -385,7 +385,7 @@ void Forward_Projectile(int fpp_type, entity proj, float use_ctime) { // a prior point in time, but we don't advance time while stepping. float ft = Phys_Init(proj, stime, static_dt, PHYSF_CONSUME_ALL); - // We initialize s_origin/s_time after Phys_Init, they are used when + // We initialize s_origin after Phys_Init, they are used when // knockback forwarding is on to determine delay. if (rewind_hit && RewindFlagEnabled(REWIND_FORWARD_PROJ_SELFKNOCK)) { phys_flags |= PHYSF_FORWARD_KNOCK; From 8fb2e03cd3aee202b2deb2ed28f122e1b93d6119 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 24 Dec 2023 13:41:20 -0800 Subject: [PATCH 2298/2474] new-balance: new take on engineer's rail gun A new attempt at railgun for the engineer, aims to add mobility to the class and add a better mechanism for catching escaping players. It still fires a rail, but it fires backwards -- from the aimed at wall, back to the engineer. This can be used to either intercept someone escape or for the engineer to gain additional mobility (jump higher, move faster). --- csqc/weapon_predict.qc | 16 ++++++++++-- share/physics.qc | 1 + ssqc/engineer.qc | 58 ++++++++++++++++++++++++++++++++++++++++++ ssqc/qw.qc | 2 ++ ssqc/tfortmap.qc | 3 +++ ssqc/weapons.qc | 3 +++ 6 files changed, 81 insertions(+), 2 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 96c549c5..75924b8a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1707,6 +1707,13 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { proj.fpp.ammo_index = WP_GetAmmo(AMMO_SHELLS) * 100 + index; } +float NB_RailCoolDown(FO_WeapInfo* wi) { + if (!fo_config.new_balance || wi->weapon != WEAP_RAILGUN) + return FALSE; + + return pstate_pred.client_time < pstate_pred.special_next; +} + void WP_Attack() { if (getstatf(STAT_NOFIRE)) return; @@ -1719,6 +1726,9 @@ void WP_Attack() { if (!WP_CheckAmmo(wi)) return; + if (NB_RailCoolDown(wi)) + return; + // Whether firing occurs here, or is embedded in the frame animation code // (because continuous fire). int in_anim = wi->weapon == WEAP_NAILGUN || @@ -1751,7 +1761,8 @@ void WP_Attack() { PP_CreateProjectile(FPP_TRANQ, PM_Org() + v_forward * 8 + '0 0 16'); break; case WEAP_RAILGUN: - PP_CreateProjectile(FPP_RAILGUN, PM_Org() + '0 0 16'); + if (!fo_config.new_balance) + PP_CreateProjectile(FPP_RAILGUN, PM_Org() + '0 0 16'); break; case WEAP_ASSAULT_CANNON: @@ -1974,7 +1985,8 @@ void WP_UpdateViewModel() { alph = CVARF(fo_reloadalpha); } else { alph = CVARF(r_drawviewmodel); - if (!WP_WeaponReady() && CVARF(fo_nofirealpha) != -1) + float ready = WP_WeaponReady() && !NB_RailCoolDown(wi); + if (!ready && CVARF(fo_nofirealpha) != -1) alph = CVARF(fo_nofirealpha); } diff --git a/share/physics.qc b/share/physics.qc index 35584b0a..8a3e6bb2 100644 --- a/share/physics.qc +++ b/share/physics.qc @@ -27,6 +27,7 @@ void AugmentGrenadeImpact(); static void Phys_Impact(entity e, float dt, float phys_flags) { other = trace_ent; + if (other.solid == SOLID_NOT) return; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 1255aa27..65797c70 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -78,7 +78,65 @@ void () LaserBolt_Touch = { dremove(self); }; +static void NBRailTouch() { + self.owner = self.real_owner; + + if (other.health) { + deathmsg = DMSG_LASERBOLT; + TF_T_Damage(other, self, self.enemy, 15, 2, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); + + float mag = 250; + if (other.has_flag) + mag *= 2; + other.velocity += normalize(self.velocity) * mag; + } + dremove(self); +} + +void W_FireNBRail() { + vector vec, org; + + makevectors(self.v_angle); + org = (self.absmin + self.absmax) / 2; + + traceline(org, org + 1500 * v_forward, MOVE_WORLDONLY, world); + + self.special_next = time + 3; + + if (trace_fraction == 1) + return; + + if (pointcontents(trace_endpos) == CONTENT_SKY) + return; + + vector term = trace_endpos; + vector vec = normalize(term - org); + + pointparticles(particleeffectnum("fo_airblast"), term); + + entity proj = FOProj_Create(FPP_RAILGUN); + proj.owner = proj; // Want collisions with everyone + proj.real_owner = self; + proj.enemy = self; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.solid = SOLID_BBOX; + + proj.velocity = -vec * 2250; + proj.angles = vectoangles(proj.velocity); + + proj.nextthink = time + 5; + proj.think = SUB_Remove; + proj.touch = NBRailTouch; + proj.classname = "railslug"; + + setorigin(proj, term); + FOProj_Finalize(proj); +} + void () W_FireRailgun = { + if (new_balance) + return W_FireNBRail(); + local vector vec, org; self.ammo_nails = self.ammo_nails - 1; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 883a8652..9a86053b 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -145,6 +145,8 @@ float remote_client_time(); .float menu_displaytime; .f_void_float menu_input; +.float has_flag; + float toggleflags; // toggleable flags string nextmap; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index f682d517..04cdbc1d 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2265,6 +2265,7 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { DoResults(Item, AP, 1); DoItemGroupWork(Item, AP); AP.goalrunningtime = gametime; + AP.has_flag = TRUE; LogEventPickupGoal(AP); }; @@ -2337,6 +2338,7 @@ void (entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer = { //Flag if ((Item.goal_activation & 1)) { local float timecarried = gametime - AP.goalrunningtime; + AP.has_flag = FALSE; RemoveFlagFollow(AP); LogEventFumble(AP, timecarried); } @@ -2928,6 +2930,7 @@ void () DropGoalItems = { //Always allow dropping 4096 else if (self.effects & EF_DIMLIGHT || te.goal_activation & TFGI_ALLOWTHROW) { timecarried = gametime - self.goalrunningtime; + self.has_flag = FALSE; RemoveFlagFollow(self); LogEventFumble(self, timecarried); te.angles = '0 0 0'; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e22c15b2..359f86aa 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1744,6 +1744,9 @@ void () W_Attack = { player_shot1(); W_FireTranq(); } else if (ws.weapon == WEAP_RAILGUN) { + if (new_balance && time < self.special_next) + return; + player_shot1(); W_FireRailgun(); } From 0d652e22bbe4800892b633be7b062d03a2f51a1c Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 14:19:25 -0800 Subject: [PATCH 2299/2474] new-balance: more trial limits - hwguy: 1 mirv (was 0) - engineer: 1 emp (was 2) 4 gren1 (was 3) - soldier: 4 gren1 (was 3) --- ssqc/client.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index d1bac75f..b53ebfd1 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -251,7 +251,10 @@ void ActivateNewBalance() { SetAllRoles(i, 1, 3); SetAllRoles(4, 2, 1); // 1 mirv for demoman - SetAllRoles(6, 2, 0); // 0 mirv for hwguy + SetAllRoles(6, 2, 1); // 1 mirv for hwguy + SetAllRoles(9, 2, 1); // 1 emp for engineer + SetAllRoles(9, 1, 4); // 4 gren1 for engineer + SetAllRoles(3, 1, 4); // 4 gren1 for soldier PC_PYRO_AIRBLAST_COOLDOWN = 15; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; From af052df6107aa51717561bc90743f12ecd7aacaa Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 17:56:46 -0800 Subject: [PATCH 2300/2474] weapons: remove legacy bitfield weapon representation no longer using bitfields for these so we can just use plain indices --- share/defs.h | 4 ++-- share/weapons.qc | 41 +++++------------------------------------ ssqc/tfort.qc | 1 - 3 files changed, 7 insertions(+), 39 deletions(-) diff --git a/share/defs.h b/share/defs.h index 2a81d90e..9eba59a5 100644 --- a/share/defs.h +++ b/share/defs.h @@ -733,8 +733,8 @@ struct Slot { int id; }; /*======================================================*/ #define WEAP_NONE 0 -enumflags { - WEAP_HOOK, +enum { + WEAP_HOOK = 1, WEAP_KNIFE, WEAP_MEDIKIT, WEAP_SPANNER, diff --git a/share/weapons.qc b/share/weapons.qc index 6101212f..cde432d7 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -37,18 +37,6 @@ float SlotIndex(Slot slot) { return slot.id - 1; } -// Convert a weapon-bit to a linear index. -static float WEAP_to_index(float weapon) { - float index = 0; - for (; weapon > 0; weapon >>= 1, index++) { - if (weapon >= 64) { - weapon >>= 6; - index += 6; - } - } - return index; -} - enum AmmoType { AMMO_NONE, AMMO_SHELLS, @@ -83,7 +71,6 @@ struct FO_WeapInfo { FO_WeapToItem* items; }; -// REQUIRES: weapon at index i == WEAP_to_index(weap) // -ve values are placeholders signifying conditional init based on game modes. FO_WeapInfo weapon_info[] = { { WEAP_NONE, NO_PREDICT, AMMO_NONE, 0, 0, 0.5, 0 }, @@ -111,7 +98,7 @@ FO_WeapInfo weapon_info[] = { }; inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { - return &weapon_info[WEAP_to_index(weapon)]; + return &weapon_info[weapon]; } struct FO_ClassWeapons { @@ -319,8 +306,8 @@ float IsHoldGrenades() { return csqc_get_user_setting("hg", "hold_grens", "off"); } #endif -// Indexed by WEAP_to_index(). We keep them out of the main table just to keep -// things a little more wieldly/readable. +// We keep these out of the main table just to keep things a little more +// wieldly/readable. static string weapon_names[] = { "None", "Hook", "Knife", "Medikit", "Spanner", "Axe", "Sniper Rifle", "Auto Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", @@ -330,11 +317,7 @@ static string weapon_names[] = { }; string FO_GetWeapName(float weapon) { - // Seeing a weird compiler bug here, passing WEAP_to_index directly to the - // array dereference will randomly cause OOB with length 13 limit, which is - // much smaller than `weapon_names`. - int index = WEAP_to_index(weapon); - return weapon_names[index]; + return weapon_names[weapon]; } @@ -347,7 +330,6 @@ struct FO_WeapModels { }; -// Indexed by WEAP_to_index() static FO_WeapModels weapon_models[] = { { WEAP_NONE, ""}, { WEAP_HOOK, "progs/v_grap.mdl" }, @@ -430,16 +412,6 @@ FO_WeapInfo* FO_SlotWeapInfo(float playerclass, Slot slot) { return class_weapons[playerclass]->info[idx] ?: FO_GetWeapInfo(WEAP_NONE); } -float FO_ClassWeapItemMask(float class) { - float result = 0; - for (int i = 1; i <= TF_NUM_SLOTS; i++) { - FO_WeapInfo* wi = FO_SlotWeapInfo(class, MakeSlot(i)); - if (wi) - result |= (wi->items)->it_weapon; - } - return result; -} - #ifndef CSQC float FO_WeaponsMask(entity player) { float mask = 0; @@ -752,7 +724,6 @@ void FO_Weapons_Init() { for (i = 0; i < weapon_info.length; i++) { FO_WeapInfo* wi = &weapon_info[i]; - ASSERTD_EQ(WEAP_to_index(wi->weapon), i); if (wi->weapon == WEAP_PIPE_LAUNCHER) { FO_WeapInfo* parent = FO_GetWeapInfo(WEAP_GRENADE_LAUNCHER); @@ -767,7 +738,6 @@ void FO_Weapons_Init() { } FO_WeapModels* wm = &weapon_models[i]; - ASSERTD_EQ(WEAP_to_index(wm->weapon), i); precache_model(wm->model); #ifdef CSQC wm->modelindex = getmodelindex(wm->model); @@ -775,7 +745,6 @@ void FO_Weapons_Init() { wi->models = wm; FO_WeapToItem* wti = &weapon_to_items[i]; - ASSERTD_EQ(WEAP_to_index(wti->weapon), i); wi->items = wti; switch (wi->ammo_type) { @@ -798,7 +767,7 @@ void FO_Weapons_Init() { FO_ClassWeapons* cw = &class_weapons[i]; if (cw->slots[j]) - cw->info[j] = &weapon_info[WEAP_to_index(cw->slots[j])]; + cw->info[j] = &weapon_info[cw->slots[j]]; else cw->info[j] = &weapon_info[0]; // WEAP_NONE } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index b145e1f2..3c0f1426 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1218,7 +1218,6 @@ void () TeamFortress_SetEquipment = { Team_Role * role = GetTeamRole(self.team_no); kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); - self.items = FO_ClassWeapItemMask(self.playerclass) | kept_items; if (!remember_weapon || self.last_playerclass != self.playerclass || (self.tfstate & TFSTATE_RANDOMPC)) { From ba3d8d5761f9a893c9d9ed5478312137dc5f47fa Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 21:32:25 -0800 Subject: [PATCH 2301/2474] new-balance: turn new railgun into "impeller', a new weapon on slot3 --- csqc/weapon_predict.qc | 26 +++++++++++++++++++++----- share/defs.h | 3 ++- share/weapons.qc | 38 +++++++++++++++++++++++++++++--------- ssqc/engineer.qc | 13 ++++++------- ssqc/weapons.qc | 10 +++++++--- 5 files changed, 65 insertions(+), 25 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 75924b8a..ce8d9721 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1115,6 +1115,22 @@ float WP_ReloadSlot(Slot slot) { return TRUE; } +void WP_CheckSpecialReady() { + if (!IsEffectFrame()) + return; + + if (pstate_pred.special_next > pstate_pred.server_time || + pstate_pred.special_next < pstate_pred.server_time - input_timelength) + return; + + switch (pstate_pred.playerclass) { + case PC_ENGINEER: + if (fo_config.new_balance) + printf("Impeller ready\n"); + break; + } +} + void WP_CheckReloadFinished() { if (WP_IsReloading() && pstate_pred.reload_finished && pstate_pred.client_time >= pstate_pred.reload_finished) { pstate_pred.tfstate &= ~TFSTATE_RELOADING; @@ -1707,11 +1723,11 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { proj.fpp.ammo_index = WP_GetAmmo(AMMO_SHELLS) * 100 + index; } -float NB_RailCoolDown(FO_WeapInfo* wi) { - if (!fo_config.new_balance || wi->weapon != WEAP_RAILGUN) +float NB_ImpellerCoolDown(FO_WeapInfo* wi) { + if (!fo_config.new_balance || wi->weapon != WEAP_IMPELLER) return FALSE; - return pstate_pred.client_time < pstate_pred.special_next; + return pstate_pred.server_time < pstate_pred.special_next; } void WP_Attack() { @@ -1726,7 +1742,7 @@ void WP_Attack() { if (!WP_CheckAmmo(wi)) return; - if (NB_RailCoolDown(wi)) + if (NB_ImpellerCoolDown(wi)) return; // Whether firing occurs here, or is embedded in the frame animation code @@ -1985,7 +2001,7 @@ void WP_UpdateViewModel() { alph = CVARF(fo_reloadalpha); } else { alph = CVARF(r_drawviewmodel); - float ready = WP_WeaponReady() && !NB_RailCoolDown(wi); + float ready = WP_WeaponReady() && !NB_ImpellerCoolDown(wi); if (!ready && CVARF(fo_nofirealpha) != -1) alph = CVARF(fo_nofirealpha); } diff --git a/share/defs.h b/share/defs.h index 9eba59a5..048caf84 100644 --- a/share/defs.h +++ b/share/defs.h @@ -755,7 +755,8 @@ enum { WEAP_DETPACK, WEAP_TRANQ, WEAP_RAILGUN, - WEAP_LAST = WEAP_RAILGUN, + WEAP_IMPELLER, + WEAP_LAST = WEAP_IMPELLER, }; // still room for 12 more weapons diff --git a/share/weapons.qc b/share/weapons.qc index cde432d7..729eac26 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -94,7 +94,8 @@ FO_WeapInfo weapon_info[] = { { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, PRED_PROJ, AMMO_SHELLS, 0, 1, 1.5, 0 }, - { WEAP_RAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.4, 0 }, + { WEAP_RAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.4, 0 }, + { WEAP_IMPELLER, PRED_PROJ, AMMO_NAILS, 0, 1, 0.6, 0 }, }; inline var FO_WeapInfo* FO_GetWeapInfo(float weapon) { @@ -118,7 +119,7 @@ FO_ClassWeapons class_weapons[] = { { PC_HVYWEAP, { WEAP_ASSAULT_CANNON, WEAP_SUPER_SHOTGUN, WEAP_SHOTGUN, WEAP_AXE } }, { PC_PYRO, { WEAP_INCENDIARY, WEAP_FLAMETHROWER, WEAP_SHOTGUN, WEAP_AXE } }, { PC_SPY, { WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN, WEAP_KNIFE } }, - { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, 0, WEAP_SPANNER } }, + { PC_ENGINEER, { WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, WEAP_IMPELLER, WEAP_SPANNER } }, { PC_RANDOM, { 0, 0, 0, WEAP_AXE } }, // TODO: Probably needs attention { PC_CIVILIAN, { 0, 0, 0, WEAP_AXE } }, }; @@ -313,7 +314,7 @@ static string weapon_names[] = { "Auto Rifle", "Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", "Grenade Launcher", "Pipebomb Launcher", "Flamethrower", "Rocket Launcher", "Incendiary Launcher", "Assault Cannon", "Lightning Gun", "Detpack", - "Tranquilizer", "Railgun" + "Tranquilizer", "Railgun", "Impeller" }; string FO_GetWeapName(float weapon) { @@ -353,6 +354,7 @@ static FO_WeapModels weapon_models[] = { { WEAP_DETPACK, "" }, { WEAP_TRANQ, "progs/v_tranq.mdl" }, { WEAP_RAILGUN, "progs/v_rail.mdl" }, + { WEAP_IMPELLER, "progs/v_rail.mdl" }, }; // REQUIRES: Order must match above. @@ -397,19 +399,35 @@ FO_WeapToItem weapon_to_items[] = { { WEAP_DETPACK, 0}, { WEAP_TRANQ, IT_SHOTGUN}, { WEAP_RAILGUN, IT_SHOTGUN}, + { WEAP_IMPELLER, IT_SHOTGUN}, }; +float FO_WeapAvailable(float weapon) { + if (weapon == WEAP_IMPELLER && !fo_config.new_balance) + return FALSE; + + return TRUE; +} + FO_WeapInfo* FO_SlotWeapInfo(float playerclass, Slot slot) { if (IsSlotNull(slot)) return FO_GetWeapInfo(WEAP_NONE); + float si = SlotIndex(slot); + if (playerclass == PC_ENGINEER && si == 2 && !fo_config.new_balance) + return FO_GetWeapInfo(WEAP_NONE); + float idx = SlotIndex(slot); float cf_pyro_impulses = IsPyroSlotSwapped(); - float si = SlotIndex(slot); if (playerclass == PC_PYRO && cf_pyro_impulses && (idx == 0 || idx == 1)) idx = 1 - idx; - return class_weapons[playerclass]->info[idx] ?: FO_GetWeapInfo(WEAP_NONE); + FO_WeapInfo* wi = class_weapons[playerclass]->info[idx]; + + if (!wi || !FO_WeapAvailable(wi->weapon)) + return FO_GetWeapInfo(WEAP_NONE); + + return wi; } #ifndef CSQC @@ -651,7 +669,7 @@ ImpulseWeapon impulse_weapons[] = { { PC_SPY, { WEAP_KNIFE, WEAP_TRANQ, WEAP_SUPER_SHOTGUN, WEAP_NAILGUN } }, { PC_ENGINEER, - { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN } }, + { WEAP_SPANNER, WEAP_RAILGUN, WEAP_SUPER_SHOTGUN, WEAP_IMPELLER } }, { PC_RANDOM, { WEAP_AXE } }, // Never instantiated { PC_CIVILIAN, { WEAP_AXE } }, }; @@ -679,7 +697,7 @@ Slot FO_FindPrevNextWeaponSlot(float playerclass, Slot slot, float is_prev) { float direction = is_prev ? -1 : 1; if (IsUsingOldImpulses()) { - Slot* impulse_table = impulse_weapons[playerclass].slots; + ImpulseWeapon* impulse_table = &impulse_weapons[playerclass]; // For reasons that seem to rhyme with -ompilerbug, reads from // impulse_table[offset] return junk so we use a pointer cursor. Slot* cur; @@ -687,13 +705,15 @@ Slot FO_FindPrevNextWeaponSlot(float playerclass, Slot slot, float is_prev) { direction = (direction + len) % len; for (i = 0; i < len; i++) { - cur = &impulse_table[i]; + cur = &impulse_table.slots[i]; if (IsSameSlot(*cur, slot)) break; } do { i = (i + direction) % len; - cur = &impulse_table[i]; + if (!FO_WeapAvailable(impulse_table.weapons[i])) + continue; + cur = &impulse_table.slots[i]; } while (IsSlotNull(*cur)); // Technically this will flip OWI+CFPI, but this is a nonsense combo. diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 65797c70..7436c4d9 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -78,12 +78,12 @@ void () LaserBolt_Touch = { dremove(self); }; -static void NBRailTouch() { +static void ImpellerTouch() { self.owner = self.real_owner; if (other.health) { deathmsg = DMSG_LASERBOLT; - TF_T_Damage(other, self, self.enemy, 15, 2, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); + TF_T_Damage(other, self, self.owner, 15, 2, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); float mag = 250; if (other.has_flag) @@ -93,7 +93,7 @@ static void NBRailTouch() { dremove(self); } -void W_FireNBRail() { +void W_FireImpeller() { vector vec, org; makevectors(self.v_angle); @@ -126,17 +126,16 @@ void W_FireNBRail() { proj.nextthink = time + 5; proj.think = SUB_Remove; - proj.touch = NBRailTouch; + proj.touch = ImpellerTouch; proj.classname = "railslug"; setorigin(proj, term); FOProj_Finalize(proj); + + Pred_Sound(SND_RAILGUN); } void () W_FireRailgun = { - if (new_balance) - return W_FireNBRail(); - local vector vec, org; self.ammo_nails = self.ammo_nails - 1; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 359f86aa..12946032 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -99,6 +99,7 @@ void () W_FireFlame; void W_FireIncendiaryCannon(vector org, vector angles, float use_ctime=0); void () W_FireTranq; void () W_FireRailgun; +void () W_FireImpeller; void () HallucinationTimer; void () TranquiliserTimer; @@ -1744,11 +1745,14 @@ void () W_Attack = { player_shot1(); W_FireTranq(); } else if (ws.weapon == WEAP_RAILGUN) { - if (new_balance && time < self.special_next) + player_shot1(); + W_FireRailgun(); + } else if (ws.weapon == WEAP_IMPELLER) { + if (!new_balance || time < self.special_next) return; player_shot1(); - W_FireRailgun(); + W_FireImpeller(); } if (ws.weapon != WEAP_FLAMETHROWER && // Variable @@ -1879,7 +1883,7 @@ void W_ChangeWeaponSlot(Slot slot) { FO_WeapState ws; FO_FillWeapState(self, slot, &ws); - if (ws.weapon == WEAP_NONE) + if (ws.weapon == WEAP_NONE || !FO_WeapAvailable(ws.weapon)) return; // queue next weapon if queue is not empty or has changed From 858555022843ae789c546066c33a50936ca14741 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 22:25:13 -0800 Subject: [PATCH 2302/2474] new-balance: unify ssqc/csqc active check --- csqc/weapon_predict.qc | 6 +++--- share/commondefs.qc | 12 ++++++++++++ share/prediction.qc | 1 + share/weapons.qc | 4 ++-- ssqc/client.qc | 2 +- ssqc/demoman.qc | 2 +- ssqc/helpers.qc | 4 ---- ssqc/pyro.qc | 2 +- ssqc/qw.qc | 1 - 9 files changed, 21 insertions(+), 13 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ce8d9721..9d366ad4 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1125,7 +1125,7 @@ void WP_CheckSpecialReady() { switch (pstate_pred.playerclass) { case PC_ENGINEER: - if (fo_config.new_balance) + if (NewBalanceActive()) printf("Impeller ready\n"); break; } @@ -1724,7 +1724,7 @@ void FO_FireAssCanPellet(vector org, vector dir, float proj_speed, int index) { } float NB_ImpellerCoolDown(FO_WeapInfo* wi) { - if (!fo_config.new_balance || wi->weapon != WEAP_IMPELLER) + if (!NewBalanceActive() || wi->weapon != WEAP_IMPELLER) return FALSE; return pstate_pred.server_time < pstate_pred.special_next; @@ -1777,7 +1777,7 @@ void WP_Attack() { PP_CreateProjectile(FPP_TRANQ, PM_Org() + v_forward * 8 + '0 0 16'); break; case WEAP_RAILGUN: - if (!fo_config.new_balance) + if (!NewBalanceActive()) PP_CreateProjectile(FPP_RAILGUN, PM_Org() + '0 0 16'); break; diff --git a/share/commondefs.qc b/share/commondefs.qc index 4885c849..34218402 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -292,3 +292,15 @@ enumflags { CSQC_FORCE_POS, CSQC_SNIPER_SIGHT, }; + +#ifdef SSQC +float new_balance; +#endif + +float NewBalanceActive() { +#ifdef CSQC + return fo_config.new_balance; +#else + return new_balance & 1; +#endif +} diff --git a/share/prediction.qc b/share/prediction.qc index 6e3c43b6..8e43fbb1 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -1161,3 +1161,4 @@ void AugmentGrenadeImpact() { self.SendFlags |= FOPP_MOVETYPE; #endif } + diff --git a/share/weapons.qc b/share/weapons.qc index 729eac26..b2f25f1d 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -403,7 +403,7 @@ FO_WeapToItem weapon_to_items[] = { }; float FO_WeapAvailable(float weapon) { - if (weapon == WEAP_IMPELLER && !fo_config.new_balance) + if (weapon == WEAP_IMPELLER && !NewBalanceActive()) return FALSE; return TRUE; @@ -414,7 +414,7 @@ FO_WeapInfo* FO_SlotWeapInfo(float playerclass, Slot slot) { return FO_GetWeapInfo(WEAP_NONE); float si = SlotIndex(slot); - if (playerclass == PC_ENGINEER && si == 2 && !fo_config.new_balance) + if (playerclass == PC_ENGINEER && si == 2 && !NewBalanceActive()) return FO_GetWeapInfo(WEAP_NONE); float idx = SlotIndex(slot); diff --git a/ssqc/client.qc b/ssqc/client.qc index b53ebfd1..93867709 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1087,7 +1087,7 @@ void () DecodeLevelParms = { // mirror current state into desired state bit new_balance |= (new_balance << 1); - if (ServerIsNewBalance()) + if (NewBalanceActive()) ActivateNewBalance(); }; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index 3ecca191..c996e18d 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -205,7 +205,7 @@ void (float timer) TeamFortress_SetDetpack = { float quad_limit = quadmode && round_active && (time < round_end_time) && (rounds % 2) != (self.team_no - 1); - if (ServerIsNewBalance() && quad_limit) { + if (NewBalanceActive() && quad_limit) { float last = max(self.detpack_last, round_start_time); float next = last + 30; // TODO: tunable if this sticks if (next > time) { diff --git a/ssqc/helpers.qc b/ssqc/helpers.qc index 72c633c3..2b85c437 100644 --- a/ssqc/helpers.qc +++ b/ssqc/helpers.qc @@ -57,7 +57,3 @@ float ServerIsStaging() { return strstrofs(hostname, "Staging") >= 0; } - -float ServerIsNewBalance() { - return new_balance & 1; -} diff --git a/ssqc/pyro.qc b/ssqc/pyro.qc index f1e144fd..e67e7b88 100644 --- a/ssqc/pyro.qc +++ b/ssqc/pyro.qc @@ -170,7 +170,7 @@ void () NapalmGrenadeExplode2 = { deathmsg = DMSG_FLAME; float aflags = TF_TD_FIRE; - if (ServerIsNewBalance()) + if (NewBalanceActive()) aflags |= TF_TD_NOMOMENTUM; TF_T_Damage(head, self, self.owner, explodeDam, TF_TD_NOTTEAM, aflags); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 9a86053b..20743614 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -804,7 +804,6 @@ string backend_address; float fo_login_required; .entity filter_ent; -float new_balance; var float PC_PYRO_AIRBLAST_COOLDOWN = 5; var float PC_ENGINEER_GRENADE_TYPE_2_RANGE = 240; .float detpack_last; From 018a52ed41dddb1d9bd284a290b069e20110924e Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 11 Jan 2024 23:05:19 -0800 Subject: [PATCH 2303/2474] nb: rebalance conc grenades - initial planar velocity cap of 1050 (down from 1400+) - caps immediately on first landing/jump to 950 planar (predicted by pmove) tldr: easier to det, no speed cap lerping, some longer slide setups now open to med --- csqc/pmove.qc | 8 ++++++++ share/classes.qc | 31 +++++++++++++++++++++++++++++++ share/defs.h | 4 ++++ ssqc/client.qc | 2 ++ ssqc/scout.qc | 7 +++++++ 5 files changed, 52 insertions(+) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 302950e0..32069b2e 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -470,6 +470,9 @@ static void PM_NudgeBounce(PM_Nudge* nudge, entity ent) { float points = dmg - vlen(targ_org - nudge->org) / 2; ent.velocity = (targ_org - nudge->org) * points/20; + + NB_ConcCapAction(ent, pstate_pred.playerclass, &pstate_pred.tfstate, + kLaunch); } @@ -630,6 +633,11 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { if ((ent.pmove_flags & PMF_JUMP_HELD) && (pstate_pred.tfstate & TFSTATE_CONC)) Conc_Jump(&pstate_pred.conc_state, ent); + + if ((ent.pmove_flags & PMF_JUMP_HELD) && (pstate_pred.tfstate & TFSTATE_CONC_CAP)) { + NB_ConcCapAction(ent, pstate_pred.playerclass, &pstate_pred.tfstate, + kLand); + } } pm.seq++; diff --git a/share/classes.qc b/share/classes.qc index b690274b..d4d80390 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -166,3 +166,34 @@ float Class_ScaleMoment(float playerclass, float damage) { return damage; return damage <= 50 ? 0 : damage / 4; } + +enum { + kLaunch, + kLand +}; + +void NB_ConcCap(entity ent, float speed) { + vector planar_vel = [ent.velocity_x, ent.velocity_y, 0]; + + if (vlen(planar_vel) > speed) { + planar_vel = normalize(planar_vel) * speed; + } + + ent.velocity_x = planar_vel.x; + ent.velocity_y = planar_vel.y; +} + +void NB_ConcCapAction(entity ent, float player_class, float* tfstate, float action) { + if (!NewBalanceActive()) + return; + + if (action == kLaunch) { + if (player_class = PC_MEDIC) + *tfstate |= TFSTATE_CONC_CAP; + + NB_ConcCap(ent, NB_CONC_CAP_AIR); + } else if (action == kLand && (*tfstate & TFSTATE_CONC_CAP)) { + *tfstate &= ~TFSTATE_CONC_CAP; + NB_ConcCap(ent, NB_CONC_CAP_LAND); + } +} diff --git a/share/defs.h b/share/defs.h index 048caf84..5a4b108e 100644 --- a/share/defs.h +++ b/share/defs.h @@ -249,6 +249,7 @@ enumflags { TFSTATE_AIMING, // is using the laser sight or spinning TFSTATE_CANT_MOVE, TFSTATE_CONC, + TFSTATE_CONC_CAP, // Speed-cap next jump TFSTATE_NO_WEAPON, // Weapon is disabled and not visible (e.g. detpack) // (Note: We don't use NO_WEAPON for reloading // as it could result in stacked no-weapon states.) @@ -1664,3 +1665,6 @@ TFAlias csqc_aliases[] = { {"+dropflag", 0, "+button7"}, {"-dropflag", 0, "-button7"}, }; + +#define NB_CONC_CAP_AIR 1050 +#define NB_CONC_CAP_LAND 950 diff --git a/ssqc/client.qc b/ssqc/client.qc index 93867709..518cdb19 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2547,6 +2547,7 @@ void () PlayerJump = { if (self.flags & FL_WATERJUMP) return; + if (self.waterlevel >= 2) { if (self.watertype == CONTENT_WATER) self.velocity_z = 100; @@ -2578,6 +2579,7 @@ void () PlayerJump = { self.flags = self.flags - (self.flags & FL_JUMPRELEASED); self.button2 = 0; + NB_ConcCapAction(self, self.playerclass, &self.tfstate, kLand); FO_Sound(self, CHAN_AUTO, "player/plyrjmp8.wav", 1, ATTN_NORM); if (!cannon_air && self.tfstate & TFSTATE_AC_FIRING) { diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 36f325e3..71f27756 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -861,12 +861,19 @@ void (entity inflictor, entity attacker, float bounce, head.velocity = head.velocity * (points / 20); Predict_AddFilterEnt(head, inflictor); + NB_ConcCapAction(head, head.playerclass, &head.tfstate, kLaunch); + if (head.classname != "player") { if (head.flags & FL_ONGROUND) head.flags = head.flags - FL_ONGROUND; } else { if (head.playerclass == PC_MEDIC) { + if (NewBalanceActive()) { + head = head.chain; + continue; + } + if (medicnocuss && (medic_type != MEDIC_TYPE_BLAST)) { entity speedbump; From f31197a05ebbc6c8866fe7014e5b26d84a8a1eb6 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 12 Jan 2024 16:49:02 -0800 Subject: [PATCH 2304/2474] new-balance: add a small lockout to conc-cap free hop in first 0.5s, initial cap moved to 1100, improve prediction sync --- csqc/pmove.qc | 3 ++- share/classes.qc | 14 +++++++++++--- share/defs.h | 2 +- share/prediction.qc | 5 ++++- ssqc/client.qc | 3 ++- ssqc/scout.qc | 3 ++- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 32069b2e..95db379e 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -472,7 +472,7 @@ static void PM_NudgeBounce(PM_Nudge* nudge, entity ent) { ent.velocity = (targ_org - nudge->org) * points/20; NB_ConcCapAction(ent, pstate_pred.playerclass, &pstate_pred.tfstate, - kLaunch); + pm.interp_t, &pstate_pred.conc_cap_time, kLaunch); } @@ -636,6 +636,7 @@ static void PM_RunMovement(PMS_Data* pmsd, float endframe) { if ((ent.pmove_flags & PMF_JUMP_HELD) && (pstate_pred.tfstate & TFSTATE_CONC_CAP)) { NB_ConcCapAction(ent, pstate_pred.playerclass, &pstate_pred.tfstate, + pm.interp_t, &pstate_pred.conc_cap_time, kLand); } } diff --git a/share/classes.qc b/share/classes.qc index d4d80390..7f368f35 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -183,16 +183,24 @@ void NB_ConcCap(entity ent, float speed) { ent.velocity_y = planar_vel.y; } -void NB_ConcCapAction(entity ent, float player_class, float* tfstate, float action) { +void NB_ConcCapAction(entity ent, float player_class, float* tfstate, + float gtime, float* cap_time, float action) { if (!NewBalanceActive()) return; + const float kLockout = 0.5; + if (action == kLaunch) { - if (player_class = PC_MEDIC) + if (player_class == PC_MEDIC) { *tfstate |= TFSTATE_CONC_CAP; + *cap_time = gtime + kLockout; + } NB_ConcCap(ent, NB_CONC_CAP_AIR); - } else if (action == kLand && (*tfstate & TFSTATE_CONC_CAP)) { + + } else if (action == kLand && (*tfstate & TFSTATE_CONC_CAP) && + gtime > *cap_time) { + float cap = *cap_time; *tfstate &= ~TFSTATE_CONC_CAP; NB_ConcCap(ent, NB_CONC_CAP_LAND); } diff --git a/share/defs.h b/share/defs.h index 5a4b108e..54d10de9 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1666,5 +1666,5 @@ TFAlias csqc_aliases[] = { {"-dropflag", 0, "-button7"}, }; -#define NB_CONC_CAP_AIR 1050 +#define NB_CONC_CAP_AIR 1100 #define NB_CONC_CAP_LAND 950 diff --git a/share/prediction.qc b/share/prediction.qc index 8e43fbb1..b5e77eca 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -67,6 +67,7 @@ struct predict_tf_state { float conc_amp; float conc_finished; + float conc_cap_time; float special_next; float client_time, server_time; @@ -314,6 +315,7 @@ float FO_MaxRewindGrenWinDt() { .predict_tf_state predict_state; .entity predict_entity; +.float conc_cap_time; inline float *self_tf_state() { return &self.tfstate; } @@ -367,7 +369,7 @@ static float Prediction_ChangedMask(entity player, entity src) { M2(FOWP_TFSTATE, tfstate, csqc_maxspeed); M1(FOWP_LASTPRIME, last_prime); M2(FOWP_CLASSIC_CONC, conc_state.next, conc_state.mag); - M2(FOWP_CONCFINISH, conc_finished, conc_amp); + M3(FOWP_CONCFINISH, conc_finished, conc_amp, conc_cap_time); M1(FOWP_WF, weaponframe); M1(FOWP_AF, attack_finished); M2(FOWP_THINK, client_nextthink, client_thinkindex); @@ -566,6 +568,7 @@ void EntUpdate_WeaponPred(float isnew) { if (sendflags & FOWP_CONCFINISH) { COMM(Byte, conc_amp); COMM(Float, conc_finished); + COMM(Float, conc_cap_time); } if (sendflags & FOWP_THINK) { diff --git a/ssqc/client.qc b/ssqc/client.qc index 518cdb19..da307d1c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2579,7 +2579,8 @@ void () PlayerJump = { self.flags = self.flags - (self.flags & FL_JUMPRELEASED); self.button2 = 0; - NB_ConcCapAction(self, self.playerclass, &self.tfstate, kLand); + NB_ConcCapAction(self, self.playerclass, &self.tfstate, + time, &self.conc_cap_time, kLand); FO_Sound(self, CHAN_AUTO, "player/plyrjmp8.wav", 1, ATTN_NORM); if (!cannon_air && self.tfstate & TFSTATE_AC_FIRING) { diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 71f27756..470f046f 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -861,7 +861,8 @@ void (entity inflictor, entity attacker, float bounce, head.velocity = head.velocity * (points / 20); Predict_AddFilterEnt(head, inflictor); - NB_ConcCapAction(head, head.playerclass, &head.tfstate, kLaunch); + NB_ConcCapAction(head, head.playerclass, &head.tfstate, + time, &head.conc_cap_time, kLaunch); if (head.classname != "player") { if (head.flags & FL_ONGROUND) From f6d24d623006ff40df10284441d895588eb3ca19 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 12 Jan 2024 17:00:40 -0800 Subject: [PATCH 2305/2474] new-balance: add command to disable conc change `localinfo nbc 0` is prior conc behavior. --- share/classes.qc | 14 +++++++++++--- share/commondefs.qc | 6 ++++++ share/prediction.qc | 2 ++ ssqc/client.qc | 7 +++++++ ssqc/scout.qc | 2 +- 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/share/classes.qc b/share/classes.qc index 7f368f35..55d0037b 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -172,6 +172,15 @@ enum { kLand }; +float NB_UseNewConc() { + return fo_config.new_balance_flags & NBF_OLD_CONC == 0; +} + +float NB_NoCap() { + return fo_config.new_balance_flags & NBF_NO_CAP; +} + + void NB_ConcCap(entity ent, float speed) { vector planar_vel = [ent.velocity_x, ent.velocity_y, 0]; @@ -185,19 +194,18 @@ void NB_ConcCap(entity ent, float speed) { void NB_ConcCapAction(entity ent, float player_class, float* tfstate, float gtime, float* cap_time, float action) { - if (!NewBalanceActive()) + if (!NewBalanceActive() || !NB_UseNewConc()) return; const float kLockout = 0.5; if (action == kLaunch) { - if (player_class == PC_MEDIC) { + if (player_class == PC_MEDIC && !NB_NoCap()) { *tfstate |= TFSTATE_CONC_CAP; *cap_time = gtime + kLockout; } NB_ConcCap(ent, NB_CONC_CAP_AIR); - } else if (action == kLand && (*tfstate & TFSTATE_CONC_CAP) && gtime > *cap_time) { float cap = *cap_time; diff --git a/share/commondefs.qc b/share/commondefs.qc index 34218402..3c232ca6 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -54,6 +54,7 @@ var struct { float rj; float new_balance; + float new_balance_flags; } fo_config; enumflags { @@ -304,3 +305,8 @@ float NewBalanceActive() { return new_balance & 1; #endif } + +enumflags { + NBF_OLD_CONC, + NBF_NO_CAP, +}; diff --git a/share/prediction.qc b/share/prediction.qc index b5e77eca..7cf0bee3 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -483,6 +483,7 @@ void EntUpdate_Config() { COMM(Byte, old_ng_rof); COMM(Short, fo_concuss); COMM(Byte, new_balance); + COMM(Byte, new_balance_flags); #ifdef SSQC return TRUE; @@ -730,6 +731,7 @@ void Predict_InitDefaultConfig() { fo_config.clown_grav = 400; fo_config.fo_concuss = 0; fo_config.new_balance = 0; + fo_config.new_balance_flags = 0; } #ifdef SSQC diff --git a/ssqc/client.qc b/ssqc/client.qc index da307d1c..9d5d1b88 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -259,6 +259,13 @@ void ActivateNewBalance() { PC_PYRO_AIRBLAST_COOLDOWN = 15; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; + float use_new_conc = CF_GetSetting("nbc", "new_balance_concs", "1"); + if (!use_new_conc) + fo_config.new_balance_flags |= NBF_OLD_CONC; + float no_cap = CF_GetSetting("nbnc", "new_balance_no_cap", "0"); + if (no_cap) + fo_config.new_balance_flags |= NBF_NO_CAP; + if (NB_UseMinPing()) { if (fo_config.min_ping_ms < 50) // 50 min-ping localcmd("localinfo mpm 50"); diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 470f046f..94b7c5a1 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -870,7 +870,7 @@ void (entity inflictor, entity attacker, float bounce, } else { if (head.playerclass == PC_MEDIC) { - if (NewBalanceActive()) { + if ((NewBalanceActive() && NB_UseNewConc()) || NB_NoCap()) { head = head.chain; continue; } From 7efef098de096a540e90fadf92bb570948dfb5bb Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 12 Jan 2024 17:08:52 -0800 Subject: [PATCH 2306/2474] new-balance: add impeller ready/not ready text to hud --- csqc/hud.qc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/csqc/hud.qc b/csqc/hud.qc index 0ab8b15f..ef32b274 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1001,6 +1001,15 @@ void Hud_DrawClassInfoPanel(float playerclass) } break; case PC_ENGINEER: + if (NewBalanceActive()) { + basepos = pos; + msg = pstate_pred.server_time >= pstate_pred.special_next ? + "Impeller charged" : "Impeller recharging"; + HRC_drawOffsetString(panel->Orientation, msg, size, fontSize, + pos, basepos, FALSE, colour); + + pos = [pos_x, pos_y + size_y + 4]; + } if (SBAR.HasSentry) { icon = ICON_ENGINEER_SG; //HudIcons[playerclass+6].icon; From deed7418ef07349decc7ab9051bd5475bee937df Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 17 Jan 2024 15:53:18 -0800 Subject: [PATCH 2307/2474] new-balance: change airblast cooldown to 10s --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 9d5d1b88..7322302a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -256,7 +256,7 @@ void ActivateNewBalance() { SetAllRoles(9, 1, 4); // 4 gren1 for engineer SetAllRoles(3, 1, 4); // 4 gren1 for soldier - PC_PYRO_AIRBLAST_COOLDOWN = 15; + PC_PYRO_AIRBLAST_COOLDOWN = 10; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; float use_new_conc = CF_GetSetting("nbc", "new_balance_concs", "1"); From 4fc9952e13a88c71bec1494d3d1679a447799313 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 17 Jan 2024 15:55:27 -0800 Subject: [PATCH 2308/2474] new-balance: reduce conc time on medic (not scout) grens to 2s --- ssqc/scout.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 94b7c5a1..aa2957b5 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -830,6 +830,9 @@ void (entity inflictor, entity attacker, float bounce, local entity te; local vector org; + if (NewBalanceActive() && inflictor.owner.playerclass == PC_MEDIC) + actual_cuss_time = 2; + head = findradius(inflictor.origin, bounce + 40); while (head) { if (head != ignore) { From 03069f99e56fde125fd8abc761d873d0bd0117d1 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 17 Jan 2024 16:13:15 -0800 Subject: [PATCH 2309/2474] new-balance: turn on by default for OCE --- ssqc/client.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 7322302a..6010e93c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1089,8 +1089,10 @@ void () DecodeLevelParms = { // Overrides other settings. new_balance = CF_GetSetting("new_balance", "new_balance", "4"); + float new_balance_region = (ServerRegion() == kRegionUS || + ServerRegion() == kRegionOCE); if (new_balance == 4) - new_balance = ((ServerRegion() == kRegionUS) && ServerIsStaging()) ? 1 : 0; + new_balance = (new_balance_region && ServerIsStaging()) ? 1 : 0; // mirror current state into desired state bit new_balance |= (new_balance << 1); From 0b04574904e616ed12adf77e2ef054c7cd12ca33 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 17 Jan 2024 17:07:18 -0800 Subject: [PATCH 2310/2474] hud: make ident expire --- csqc/hud.qc | 3 +++ ssqc/qw.qc | 1 - ssqc/status.qc | 4 ---- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/csqc/hud.qc b/csqc/hud.qc index ef32b274..94d154d3 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -1058,6 +1058,9 @@ void Hud_DrawIdentifyPanel(string identify) { // click event } + if (time > last_id_time + 3) + return; + vector fontSize = FO_Hud_Icon_Font_Size * panel->Scale; float count = tokenizebyseparator(identify, "\n"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 20743614..089e4ba8 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -117,7 +117,6 @@ float remote_client_time(); // Identify variables .string ident_string; // Status bar string for identify -.string last_ident_string; // Last Status bar string for identify .float ident_time; // The time when last identify found a player .float autoid_type; // 0 = ignore noone, 1 = ignore teammates, 2 = ignore enemies .float autoid_time; // Time when autoid settings were last checked diff --git a/ssqc/status.qc b/ssqc/status.qc index 85b9efae..1be22004 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -800,10 +800,6 @@ void UpdateClientGrenadeThrown(entity pl) = { void UpdateClientIDString(entity pl) { string ident = time < pl.ident_time ? pl.ident_string : ""; - if (ident == pl.last_ident_string) // only send updates - return; - pl.last_ident_string = ident; - if (ident == "") // No need to send null, we'll expire clientside. return; From b760afd0ba8a2e3ab626464ae5e689a7f010c2cf Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 17 Jan 2024 18:00:03 -0800 Subject: [PATCH 2311/2474] core: split tfstate into pstate size limits(?) on bitops dont play well with large enumflags values. Split tfstate into a second word, moving some of our less commonly used fields for now. This fixes issues like infinite tranq --- share/defs.h | 14 +++++++++----- ssqc/client.qc | 8 ++++---- ssqc/qw.qc | 1 + ssqc/tfortmap.qc | 16 ++++++++-------- ssqc/weapons.qc | 6 +++--- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/share/defs.h b/share/defs.h index 54d10de9..7b8b8af1 100644 --- a/share/defs.h +++ b/share/defs.h @@ -259,21 +259,25 @@ enumflags { TFSTATE_AC_SPINDOWN, TFSTATE_LOCK, // assault cannon locked TFSTATE_INFECTED, // set when player is infected by the bioweapon - TFSTATE_INVINCIBLE, // Player has permanent Invincibility (Usually by GoalItem) - TFSTATE_INVISIBLE, // Player has permanent Invisibility (Usually by GoalItem) - TFSTATE_QUAD, // Player has permanent Quad Damage (Usually by GoalItem) - TFSTATE_RADSUIT, // Player has permanent Radsuit (Usually by GoalItem) TFSTATE_BURNING, // Is on fire TFSTATE_FEIGNED, // Is feigned TFSTATE_AIMING, // is using the laser sight or spinning cannon TFSTATE_RESPAWN_READY, // is waiting for respawn, and has pressed fire, // as sentry gun,indicate it needs to die TFSTATE_HALLUCINATING, // set when player is hallucinating - TFSTATE_TRANQUILISED, // set when player is tranquilised + TFSTATE_FLAMES_MAX, // Peak burnination. + TFSTATE_TRANQUILISED, // set when player is tranquilised TFSTATE_RANDOMPC, + // QC/Compiler limitation: Bits past-24 unsafe with bitops }; +enumflags { + PSTATE_INVINCIBLE, // Player has permanent Invincibility (Usually by GoalItem) + PSTATE_INVISIBLE, // Player has permanent Invisibility (Usually by GoalItem) + PSTATE_QUAD, // Player has permanent Quad Damage (Usually by GoalItem) + PSTATE_RADSUIT, // Player has permanent Radsuit (Usually by GoalItem) +}; #define TFSTATE_GREN_MASK_PRIMED (TFSTATE_GREN1_PRIMED|TFSTATE_GREN2_PRIMED) #define TFSTATE_GREN_MASK_ALL (TFSTATE_GREN_MASK_PRIMED|TFSTATE_GRENTHROWING) diff --git a/ssqc/client.qc b/ssqc/client.qc index 6010e93c..b35d297d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2844,7 +2844,7 @@ void () CheckPowerups = { self.modelindex = modelindex_eyes; } else { if (self.invisible_finished) { - if (self.tfstate & TFSTATE_INVISIBLE) { + if (self.pstate & PSTATE_INVISIBLE) { if (self.invisible_finished < (time + 10)) { self.invisible_finished = time + 666; } @@ -2879,7 +2879,7 @@ void () CheckPowerups = { } } if (self.invincible_finished) { - if (self.tfstate & TFSTATE_INVINCIBLE) { + if (self.pstate & PSTATE_INVINCIBLE) { if (self.invincible_finished < (time + 10)) { self.invincible_finished = time + 666; } @@ -2923,7 +2923,7 @@ void () CheckPowerups = { } } if (self.super_damage_finished) { - if (self.tfstate & TFSTATE_QUAD) { + if (self.pstate & PSTATE_QUAD) { if (self.super_damage_finished == (time + 10)) { self.super_damage_finished = time + 666; } @@ -2965,7 +2965,7 @@ void () CheckPowerups = { } if (self.radsuit_finished) { self.air_finished = time + 12; - if (self.tfstate & TFSTATE_RADSUIT) { + if (self.pstate & PSTATE_RADSUIT) { if (self.radsuit_finished == (time + 10)) { self.radsuit_finished = time + 666; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 089e4ba8..3eac851a 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -108,6 +108,7 @@ float remote_client_time(); .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types +.float pstate; // Player state flags .float tfstate; // State flags for TeamFortress .float last_tfstate; // Internal cache of tfstate for detecting updates .entity linked_list; // Used just like chain. Has to be separate so diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 04cdbc1d..4a44d286 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -908,7 +908,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.invincible_finished = time + Goal.invincible_finished; if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_INVINCIBLE; + Player.pstate |= PSTATE_INVINCIBLE; Player.invincible_finished = time + 666; } } @@ -917,7 +917,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.invisible_time = 1; Player.invisible_finished = time + Goal.invisible_finished; if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_INVISIBLE; + Player.pstate |= PSTATE_INVISIBLE; Player.invisible_finished = time + 666; } } @@ -927,7 +927,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.super_damage_finished = time + Goal.super_damage_finished; if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_QUAD; + Player.pstate |= PSTATE_QUAD; Player.super_damage_finished = time + 666; } } @@ -936,7 +936,7 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { Player.rad_time = 1; Player.radsuit_finished = time + Goal.radsuit_finished; if (Goal.classname == "item_tfgoal") { - Player.tfstate = Player.tfstate | TFSTATE_RADSUIT; + Player.pstate |= PSTATE_RADSUIT; Player.radsuit_finished = time + 666; } } @@ -1179,25 +1179,25 @@ void (entity Goal, entity Player) RemoveResults = { te = find(te, classname, "item_tfgoal"); } if ((Goal.invincible_finished > 0) && !puinvin) { - Player.tfstate &= ~TFSTATE_INVINCIBLE; + Player.pstate &= ~PSTATE_INVINCIBLE; Player.items = Player.items | IT_INVULNERABILITY; Player.invincible_time = 1; Player.invincible_finished = time + Goal.invincible_finished; } if ((Goal.invisible_finished > 0) && !puinvis) { - Player.tfstate &= ~TFSTATE_INVISIBLE; + Player.pstate &= ~PSTATE_INVISIBLE; Player.items = Player.items | IT_INVISIBILITY; Player.invisible_time = 1; Player.invisible_finished = time + Goal.invisible_finished; } if ((Goal.super_damage_finished > 0) && !puquad) { - Player.tfstate &= ~TFSTATE_QUAD; + Player.pstate &= ~PSTATE_QUAD; Player.items = Player.items | IT_QUAD; Player.super_time = 1; Player.super_damage_finished = time + Goal.super_damage_finished; } if ((Goal.radsuit_finished > 0) && !purad) { - Player.tfstate &= ~TFSTATE_RADSUIT; + Player.pstate &= ~PSTATE_RADSUIT; Player.items = Player.items | IT_SUIT; Player.rad_time = 1; Player.radsuit_finished = time + Goal.radsuit_finished; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 12946032..7c32756d 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2676,16 +2676,16 @@ void () SuperDamageSound = { }; void () ToggleInvincibility = { - if(self.tfstate & TFSTATE_INVINCIBLE) { + if(self.pstate & PSTATE_INVINCIBLE) { self.items &= ~IT_INVULNERABILITY; self.invincible_time = 0; self.invincible_finished = 0; - self.tfstate &= ~TFSTATE_INVINCIBLE; + self.tfstate &= ~PSTATE_INVINCIBLE; self.effects &= ~(EF_RED | EF_DIMLIGHT | EF_BRIGHTLIGHT); } else { self.items |= IT_INVULNERABILITY; self.invincible_time = 1; - self.tfstate |= TFSTATE_INVINCIBLE; + self.pstate |= PSTATE_INVINCIBLE; self.invincible_finished = time + 666; } }; From 7017b4d6c106fc754aef51866ebc40e3c69a53a8 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 18 Jan 2024 00:24:46 -0800 Subject: [PATCH 2312/2474] new-balance: rework impeller - no more projectile - no cooldown during prematch, and target anyone -- spam away - different model to railgun - now only hits enemy team when carrying flag, but has some aim assist; knockback is reduced for non-direct hits - still gives mini-rj for eng - damage reduced --- csqc/weapon_predict.qc | 3 +- share/weapons.qc | 2 +- ssqc/engineer.qc | 145 +++++++++++++++++++++++++++++++++-------- 3 files changed, 119 insertions(+), 31 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 9d366ad4..68b94e73 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1777,8 +1777,7 @@ void WP_Attack() { PP_CreateProjectile(FPP_TRANQ, PM_Org() + v_forward * 8 + '0 0 16'); break; case WEAP_RAILGUN: - if (!NewBalanceActive()) - PP_CreateProjectile(FPP_RAILGUN, PM_Org() + '0 0 16'); + PP_CreateProjectile(FPP_RAILGUN, PM_Org() + '0 0 16'); break; case WEAP_ASSAULT_CANNON: diff --git a/share/weapons.qc b/share/weapons.qc index b2f25f1d..a8919e08 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -354,7 +354,7 @@ static FO_WeapModels weapon_models[] = { { WEAP_DETPACK, "" }, { WEAP_TRANQ, "progs/v_tranq.mdl" }, { WEAP_RAILGUN, "progs/v_rail.mdl" }, - { WEAP_IMPELLER, "progs/v_rail.mdl" }, + { WEAP_IMPELLER, "progs/v_light.mdl" }, }; // REQUIRES: Order must match above. diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 7436c4d9..224edb0f 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -93,46 +93,135 @@ static void ImpellerTouch() { dremove(self); } -void W_FireImpeller() { - vector vec, org; - makevectors(self.v_angle); - org = (self.absmin + self.absmax) / 2; +static float ValidImpellerTarget(entity t) { + if (t.classname != "player") + return FALSE; - traceline(org, org + 1500 * v_forward, MOVE_WORLDONLY, world); + if (cb_prematch) // Shoot anyone in prematch + return TRUE; - self.special_next = time + 3; + return (t.team_no != self.team_no && t.has_flag); +} - if (trace_fraction == 1) - return; +static entity FindImpellerTarget(vector org, float min_a, float* direct) { - if (pointcontents(trace_endpos) == CONTENT_SKY) - return; + traceline(org, org + 1500 * v_forward, MOVE_NORMAL, world); + if (trace_fraction != 1 && ValidImpellerTarget(trace_ent)) + return trace_ent; - vector term = trace_endpos; - vector vec = normalize(term - org); + int count; + entity* players; + float best_a = min_a; + entity best_p = world; - pointparticles(particleeffectnum("fo_airblast"), term); + players = find_list(classname, "player", EV_STRING, count); + for (int i = 0; i < count; i++) { + entity p = players[i]; - entity proj = FOProj_Create(FPP_RAILGUN); - proj.owner = proj; // Want collisions with everyone - proj.real_owner = self; - proj.enemy = self; - proj.movetype = MOVETYPE_FLYMISSILE; - proj.solid = SOLID_BBOX; + if (!ValidImpellerTarget(p)) + continue; - proj.velocity = -vec * 2250; - proj.angles = vectoangles(proj.velocity); + vector dir = normalize(p.origin - org); + float a = v_forward * dir; - proj.nextthink = time + 5; - proj.think = SUB_Remove; - proj.touch = ImpellerTouch; - proj.classname = "railslug"; + traceline(org, p.origin, MOVE_NORMAL, world); + if (trace_fraction < 1) { + if (trace_ent != p) { + continue; // Something in the way + } else { + *direct = TRUE; + return p; + } + } - setorigin(proj, term); - FOProj_Finalize(proj); + if (a < best_a) + continue; // Not in AA cone + + best_a = a; + best_p = p; + } + + return best_p; +} + +static vector find_closest(vector a, vector b, vector p) { + vector v = b - a, u = a - p; + float t = -(v * u) / (v * v); + + if (t >= 0 && t <= 1) + return (1 - t) * a + t * b; + return b; +} + +static void draw_beam(vector a, vector b, int effect) { + WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, effect); + WriteEntity(MSG_MULTICAST, world); + WriteCoord(MSG_MULTICAST, a_x); + WriteCoord(MSG_MULTICAST, a_y); + WriteCoord(MSG_MULTICAST, a_z); + WriteCoord(MSG_MULTICAST, b_x); + WriteCoord(MSG_MULTICAST, b_y); + WriteCoord(MSG_MULTICAST, b_z); + multicast(a, MULTICAST_PHS); +} + +void W_FireImpeller() { + if (!cb_prematch) { + self.special_next = time + 3; + } + + FO_Sound(self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); + makevectors(self.v_angle); + + vector org = self.origin + '0 0 16'; + float direct = FALSE, jump = FALSE; + entity t = FindImpellerTarget(org, 0.985, &direct); + vector end = t.origin; + vector imp; + + float mag = 250; + entity hit; + + if (t == world) { + traceline(org, org + 350 * v_forward, MOVE_WORLDONLY, world); + if (trace_fraction == 1) + return; + + end = trace_endpos; + hit = self; + draw_beam(org, trace_endpos, TE_LIGHTNING2); + } else { + hit = t; + + if (direct) { + end = t.origin; + draw_beam(org, t.origin, TE_LIGHTNING2); + } else { + vector a = org, b = org + 1000 * v_forward; + traceline(a, b, MOVE_WORLDONLY, world); + if (trace_fraction == 1) + return; + end = trace_endpos; + vector x = find_closest(a, end, t.origin); + + draw_beam(a, x, TE_LIGHTNING2); + draw_beam(x, t.origin, TE_LIGHTNING2); + + // Discount knockback by help given + mag -= max(10, vlen(t.origin - x)); + } + + hit = t; + end = t.origin; + } - Pred_Sound(SND_RAILGUN); + TF_T_Damage(hit, self, self, 5, 2, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); + hit.flags &= ~FL_ONGROUND; + hit.velocity -= mag * normalize(end - org); + if (other.has_flag) + mag *= 2; } void () W_FireRailgun = { From ad2f844c3668352f62692b3a90da0632e027e541 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 18 Jan 2024 00:26:38 -0800 Subject: [PATCH 2313/2474] new-balance: old concs outside of OCE --- ssqc/client.qc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index b35d297d..47fab406 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -259,7 +259,12 @@ void ActivateNewBalance() { PC_PYRO_AIRBLAST_COOLDOWN = 10; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; - float use_new_conc = CF_GetSetting("nbc", "new_balance_concs", "1"); + float use_new_conc = CF_GetSetting("nbc", "new_balance_concs", "4"); + if (use_new_conc == 4 && ServerRegion() == kRegionOCE) + use_new_conc = 1; + else + use_new_conc = 0; + if (!use_new_conc) fo_config.new_balance_flags |= NBF_OLD_CONC; float no_cap = CF_GetSetting("nbnc", "new_balance_no_cap", "0"); From 744c3ada0a43cf1dd237244ed6747d54621571d3 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 10:25:32 -0800 Subject: [PATCH 2314/2474] new-balance: add new-balance flags to wpp_status --- csqc/weapon_predict.qc | 4 ++++ share/classes.qc | 2 +- share/commondefs.qc | 7 ++++++- ssqc/client.qc | 16 ++++++++-------- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 68b94e73..b39a8c31 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -275,6 +275,7 @@ void WPP_Status() { PRINT_CONFIG(max_rewind_fast_projectile_ms); PRINT_CONFIG(max_rewind_grenade_ms); PRINT_CONFIG(rewind_fast_projectile_thresh); + PRINT_CONFIG(new_balance); printf("\n"); PrintFlagField("Rewind Settings [rewind_flags=%d]\n", @@ -286,6 +287,9 @@ void WPP_Status() { PrintFlagField("Clown mode [clown_flags=%d]\n", fo_config.clown_flags, CLOWN_DESC.length, CLOWN_DESC); + PrintFlagField("NewBalance Flags [newbalance_flags=%d]:\n", + fo_config.new_balance_flags, NBF_DESC.length, NBF_DESC); + PrintFlagField("Concs [fo_concuss=%d]\n", fo_config.fo_concuss, FO_CONC.length, FO_CONC); } diff --git a/share/classes.qc b/share/classes.qc index 55d0037b..49441d68 100644 --- a/share/classes.qc +++ b/share/classes.qc @@ -173,7 +173,7 @@ enum { }; float NB_UseNewConc() { - return fo_config.new_balance_flags & NBF_OLD_CONC == 0; + return fo_config.new_balance_flags & NBF_CONC_NEW_CAP; } float NB_NoCap() { diff --git a/share/commondefs.qc b/share/commondefs.qc index 3c232ca6..ea918842 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -307,6 +307,11 @@ float NewBalanceActive() { } enumflags { - NBF_OLD_CONC, + NBF_CONC_NEW_CAP, NBF_NO_CAP, }; + +string NBF_DESC[] = { + "Reworked conc speed cap", + "No conc speed cap", +}; diff --git a/ssqc/client.qc b/ssqc/client.qc index 47fab406..309c04c7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -259,16 +259,16 @@ void ActivateNewBalance() { PC_PYRO_AIRBLAST_COOLDOWN = 10; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; - float use_new_conc = CF_GetSetting("nbc", "new_balance_concs", "4"); - if (use_new_conc == 4 && ServerRegion() == kRegionOCE) - use_new_conc = 1; + float use_new_cap = CF_GetSetting("nbcc", "new_balance_conc_cap", "4"); + if (use_new_cap == 4 && ServerRegion() == kRegionOCE) + use_new_cap = 1; else - use_new_conc = 0; + use_new_cap = 0; - if (!use_new_conc) - fo_config.new_balance_flags |= NBF_OLD_CONC; - float no_cap = CF_GetSetting("nbnc", "new_balance_no_cap", "0"); - if (no_cap) + if (use_new_cap) + fo_config.new_balance_flags |= NBF_CONC_NEW_CAP; + + if (CF_GetSetting("nbnc", "new_balance_no_cap", "0")) fo_config.new_balance_flags |= NBF_NO_CAP; if (NB_UseMinPing()) { From e5d53f8b87d2b7b70baaf7a1356d8844cc9b869c Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 10:43:55 -0800 Subject: [PATCH 2315/2474] new-balance: add death messages for impeller, slightly expand range --- share/defs.h | 1 + ssqc/client.qc | 5 +++++ ssqc/engineer.qc | 25 ++++++++----------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/share/defs.h b/share/defs.h index 7b8b8af1..414687d7 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1312,6 +1312,7 @@ enum { #define DMSG_GREN_SHOCK 42 #define DMSG_GREN_BURST 43 #define DMSG_KNIFE 44 +#define DMSG_IMPELLER 45 /*======================================================*/ /* Menus */ diff --git a/ssqc/client.qc b/ssqc/client.qc index 309c04c7..2bba965a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3391,6 +3391,8 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage s_deathstring = " gets too friendly with his sentry gun\n"; else if (pf_deathmsg == DMSG_DISPENSER_EXPLODE) s_deathstring = " dispenses with himself\n"; + else if (pf_deathmsg == DMSG_IMPELLER) + s_deathstring = " couldn't resist their inner impelsions\n"; return strcat(pe_target.netname, s_deathstring); @@ -3658,6 +3660,9 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage } else if (pf_deathmsg == DMSG_LASERBOLT) { s_deathstring = " gets a hole in his heart from "; s_deathstring2 = "'s railgun\n"; + } else if (pf_deathmsg == DMSG_IMPELLER) { + s_deathstring = " gets pushed around by "; + s_deathstring2 = "\n"; } else if (pf_deathmsg == DMSG_INCENDIARY) { s_deathstring = " gets well done by "; s_deathstring2 = "'s incendiary rocket\n"; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 224edb0f..c4fff665 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -78,32 +78,22 @@ void () LaserBolt_Touch = { dremove(self); }; -static void ImpellerTouch() { - self.owner = self.real_owner; - - if (other.health) { - deathmsg = DMSG_LASERBOLT; - TF_T_Damage(other, self, self.owner, 15, 2, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); - - float mag = 250; - if (other.has_flag) - mag *= 2; - other.velocity += normalize(self.velocity) * mag; - } - dremove(self); -} - +static const float kImpellerTargetRange = 1500; static float ValidImpellerTarget(entity t) { if (t.classname != "player") return FALSE; + if (vlen(t.origin - self.origin) > kImpellerTargetRange) + return FALSE; + if (cb_prematch) // Shoot anyone in prematch return TRUE; return (t.team_no != self.team_no && t.has_flag); } + static entity FindImpellerTarget(vector org, float min_a, float* direct) { traceline(org, org + 1500 * v_forward, MOVE_NORMAL, world); @@ -199,7 +189,7 @@ void W_FireImpeller() { end = t.origin; draw_beam(org, t.origin, TE_LIGHTNING2); } else { - vector a = org, b = org + 1000 * v_forward; + vector a = org, b = org + kImpellerTargetRange * v_forward; traceline(a, b, MOVE_WORLDONLY, world); if (trace_fraction == 1) return; @@ -217,7 +207,8 @@ void W_FireImpeller() { end = t.origin; } - TF_T_Damage(hit, self, self, 5, 2, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); + deathmsg = DMSG_IMPELLER; + TF_T_Damage(hit, self, self, 5, TF_TD_NOTTEAM, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); hit.flags &= ~FL_ONGROUND; hit.velocity -= mag * normalize(end - org); if (other.has_flag) From dbf414308fa8d5d584c814499ad5abcff35f3e1b Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 10:52:20 -0800 Subject: [PATCH 2316/2474] weapons: fix firing after dead when gibbed Being gibbed does not reset some of the animation state and so weapons which fired in animation were able to continue firing. Prevent this. --- share/animate.qc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/animate.qc b/share/animate.qc index 466ba598..7345379e 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -46,6 +46,9 @@ void FO_SetClientThink(void() func, float offset, float override = TRUE) { } void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { + if (self.deadflag) + return; + float tidx = *thinkindex()++ - 1; int wfi = tidx % anim->num_wf; From 4ce67ff40b45bd225709c9a3442a2b0d23b8d590 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 11:55:46 -0800 Subject: [PATCH 2317/2474] misc: fix compile nits --- ssqc/engineer.qc | 1 - ssqc/items.qc | 4 +--- ssqc/qw.qc | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index c4fff665..c1b0eb3d 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -169,7 +169,6 @@ void W_FireImpeller() { float direct = FALSE, jump = FALSE; entity t = FindImpellerTarget(org, 0.985, &direct); vector end = t.origin; - vector imp; float mag = 250; entity hit; diff --git a/ssqc/items.qc b/ssqc/items.qc index e0916a35..75505f9b 100644 --- a/ssqc/items.qc +++ b/ssqc/items.qc @@ -720,13 +720,11 @@ float () GetGrenadePossibility = { if (random() < 0.500) return 0; - float index; + float index = -1; switch (disable_resup_gren) { case 0: index = random() < 0.5 ? 0 : 1; break; case 1: index = 1; break; case 2: index = 0; break; - - case 3: default: return 0; } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 3eac851a..b1253a51 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -624,7 +624,6 @@ float walls_block_emp; float new_emp; float fo_sentry_targeting; // new improved targeting for sentry guns float cb_keepteams; -float fo_matchrated; float fo_flashtime; float fo_repair_ratio; float solid_nailgren; From b0226a9b004ba62ed45b1fbf4c77b0b0910e9fc2 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 11:48:04 -0800 Subject: [PATCH 2318/2474] wp: add some more shared ssqc/csqc helpers for getting to clips/class/cslot --- csqc/weapon_predict.qc | 7 +++---- share/prediction.qc | 8 ++++++++ share/weapons.qc | 26 +++++++++++++++----------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index b39a8c31..0af9b842 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1031,11 +1031,10 @@ void WP_Impulse() { } static float* WP_ClipFired(Slot slot) { - float index = SlotIndex(slot); - if (pstate_pred.playerclass == PC_DEMOMAN && index == 1) - index = 0; // Special case: Pipebomb shares with Grenadel launcher. + if (self_class() == PC_DEMOMAN && SlotIndex(slot) == 1) + slot = MakeSlot(1); // Special case: pipebomb shares with grenade launcher. - return &pstate_pred.clip_fired[index]; + return self_clip_fired(slot); } float WP_CurrentClipFired() { diff --git a/share/prediction.qc b/share/prediction.qc index 7cf0bee3..0f1c0651 100644 --- a/share/prediction.qc +++ b/share/prediction.qc @@ -318,12 +318,20 @@ float FO_MaxRewindGrenWinDt() { .float conc_cap_time; inline float *self_tf_state() { return &self.tfstate; } +float self_class() { return self.playerclass; } +Slot self_current_slot() { return self.current_slot; } +Slot self_queue_slot() { return self.queue_slot; } +float* self_clip_fired(Slot slot) { return &self.clip_fired[SlotIndex(slot)]; } #else predict_tf_state pstate_pred, pstate_server; inline float *self_tf_state() { return &pstate_pred.tfstate; } +float self_class() { return pstate_pred.playerclass; } +Slot self_current_slot() { return pstate_pred.current_slot; } +Slot self_queue_slot() { return pstate_pred.queue_slot; } +float* self_clip_fired(Slot slot) { return &pstate_pred.clip_fired[SlotIndex(slot)]; } #define MASK_PRED_ENT 256 #define MASK_PRED_PROJECTILE 512 diff --git a/share/weapons.qc b/share/weapons.qc index a8919e08..f0f7f092 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -466,6 +466,21 @@ float FO_CanReloadMsg(FO_WeapInfo* wi, int ammo_remaining, int clip_fired, return FALSE; // msg filled in above. } +float self_class(); +Slot self_current_slot(); +float* self_clip_fired(Slot slot); + +float FO_PlayerCurrentWeapon(entity player) { + FO_WeapInfo* wi = FO_SlotWeapInfo(self_class(), self_current_slot()); + if (!wi) + return WEAP_NONE; + return wi->weapon; +} + +inline float FO_CurrentWeapon() { + return FO_PlayerCurrentWeapon(self); +} + #ifdef SSQC struct FO_WeapState { float weapon; @@ -502,17 +517,6 @@ void FO_FillWeapState(entity player, Slot slot, FO_WeapState* result) { } -float FO_PlayerCurrentWeapon(entity player) { - FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, player.current_slot); - if (!wi) - return WEAP_NONE; - return wi->weapon; -} - -inline float FO_CurrentWeapon() { - return FO_PlayerCurrentWeapon(self); -} - inline void FO_FillCurrentWeapState(FO_WeapState* result) { FO_FillWeapState(self, self.current_slot, result); } From e316399ebd1d081aa6b620231574d6163a69ab55 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 12:28:52 -0800 Subject: [PATCH 2319/2474] misc: fix prematch invincibility toggle --- ssqc/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 7c32756d..587470ce 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -2680,7 +2680,7 @@ void () ToggleInvincibility = { self.items &= ~IT_INVULNERABILITY; self.invincible_time = 0; self.invincible_finished = 0; - self.tfstate &= ~PSTATE_INVINCIBLE; + self.pstate &= ~PSTATE_INVINCIBLE; self.effects &= ~(EF_RED | EF_DIMLIGHT | EF_BRIGHTLIGHT); } else { self.items |= IT_INVULNERABILITY; From cd6a42b2886e92c9befdda099946f3d52754e56c Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 12:58:52 -0800 Subject: [PATCH 2320/2474] wp: unify fire_in_anim into weapon_info rather than it being a special case --- csqc/weapon_predict.qc | 12 +++--------- share/weapons.qc | 11 ++++++----- ssqc/weapons.qc | 13 +++++-------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 0af9b842..ac0eb1c3 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -1754,7 +1754,7 @@ void WP_Attack() { wi->weapon == WEAP_SUPER_NAILGUN || wi->weapon == WEAP_ASSAULT_CANNON; - if (!in_anim && !WP_ConsumeAmmo(CurrentSlot())) + if (!wi->fire_in_anim && !WP_ConsumeAmmo(CurrentSlot())) return; // OK. We're ready to pew. @@ -1762,7 +1762,7 @@ void WP_Attack() { // Must be set prior to animation code, which might internally modify. pstate_pred.client_thinkindex = 1; - if (IsEffectFrame() && !in_anim && (time > filter_pproj_time)) { + if (IsEffectFrame() && !wi->fire_in_anim && (time > filter_pproj_time)) { float send_event = FALSE; switch (wi->weapon) { case WEAP_ROCKET_LAUNCHER: @@ -1773,9 +1773,6 @@ void WP_Attack() { PP_CreateProjectile(FPP_INCENDIARY, PM_Org() + v_forward * 8 + '0 0 16'); send_event = TRUE; break; - case WEAP_FLAMETHROWER: - PP_CreateProjectile(FPP_FLAMETHROWER, PM_Org() + v_forward * 16 + '0 0 16'); - break; case WEAP_TRANQ: PP_CreateProjectile(FPP_TRANQ, PM_Org() + v_forward * 8 + '0 0 16'); break; @@ -1783,9 +1780,6 @@ void WP_Attack() { PP_CreateProjectile(FPP_RAILGUN, PM_Org() + '0 0 16'); break; - case WEAP_ASSAULT_CANNON: - break; - case WEAP_GRENADE_LAUNCHER: send_event = TRUE; case WEAP_PIPE_LAUNCHER: @@ -1819,7 +1813,7 @@ void WP_Attack() { } } - if (!in_anim) + if (!wi->fire_in_anim) Attack_Finished(wi->attack_time); // Start the AC state machine when necessary. diff --git a/share/weapons.qc b/share/weapons.qc index f0f7f092..1769f2e9 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -63,6 +63,7 @@ struct FO_WeapInfo { float ammo_per_shot; float attack_time; float full_reload_time; + float fire_in_anim; // firing triggered from animation (e.g. continuous fire) // Fields below this are automatically initialized by Init. // ** Do not include in table. ** @@ -80,17 +81,17 @@ FO_WeapInfo weapon_info[] = { { WEAP_SPANNER, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, { WEAP_AXE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_SNIPER_RIFLE, PRED_MODEL, AMMO_SHELLS, -9, 1, 1.5, 4 }, - { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0 }, + { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0, 1 }, { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, - { WEAP_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.2, 0 }, - { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 2, 0.2, 0 }, + { WEAP_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.2, 0, 1 }, + { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 2, 0.2, 0, 1 }, { WEAP_GRENADE_LAUNCHER , PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, { WEAP_PIPE_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, // Overlaps GL - { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0 }, + { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0, 1 }, { WEAP_ROCKET_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 4, 1, 0.8, 5 }, { WEAP_INCENDIARY, PRED_PROJ, AMMO_ROCKETS, 0, 3, 0.9, 0 }, - { WEAP_ASSAULT_CANNON, PRED_PROJ, AMMO_SHELLS, 100, 1, 0.2, 4 }, + { WEAP_ASSAULT_CANNON, PRED_PROJ, AMMO_SHELLS, 100, 1, 0.2, 4, 1 }, { WEAP_LIGHTNING, NO_PREDICT, AMMO_CELLS, 0, 1, 0.1, 0 }, { WEAP_DETPACK, NO_PREDICT, AMMO_NONE, 0, 0, 0, 0 }, { WEAP_TRANQ, PRED_PROJ, AMMO_SHELLS, 0, 1, 1.5, 0 }, diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 587470ce..fa8f1f3a 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1755,19 +1755,16 @@ void () W_Attack = { W_FireImpeller(); } - if (ws.weapon != WEAP_FLAMETHROWER && // Variable - ws.weapon != WEAP_ASSAULT_CANNON && // In animation - ws.weapon != WEAP_NAILGUN && // In animation - ws.weapon != WEAP_SUPER_NAILGUN) // In animation + if (!wi->fire_in_anim) { Attack_Finished(wi->attack_time); - - if (wi->needs_reload) { - if (ws.weapon != WEAP_ASSAULT_CANNON) // In animation + if (wi->needs_reload) { *ws->clip_fired += wi->ammo_per_shot; - FO_CheckForReload(); + FO_CheckForReload(); + } } //These weapons have to log each projectile launched/bullet fired + // TODO: probably equivalent to fire_in_anim... if (ws.weapon != WEAP_ASSAULT_CANNON || ws.weapon != WEAP_NAILGUN || ws.weapon != WEAP_SUPER_NAILGUN) LogEventAttack(self); From 9bc4cbaa1bda5cfad6103d7f7cba7017c3c4ae21 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 11:50:41 -0800 Subject: [PATCH 2321/2474] weapons: example of adding reload to in-animation weapon --- share/animate.qc | 6 ++++++ share/weapons.qc | 2 +- ssqc/weapons.qc | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/share/animate.qc b/share/animate.qc index 7345379e..f8f44fd5 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -219,6 +219,12 @@ void nail_extra_csqc_ssqc() { return; } + FO_WeapInfo* wi = FO_GetWeapInfo(FO_CurrentWeapon()); + if (wi->needs_reload && FO_CheckForReload()) { + player_run(); + return; + } + float tidx = *thinkindex() % 2; // 1 based, and incremented. if (tidx == 0 || !OldNgRof()) { SuperDamageSound(); diff --git a/share/weapons.qc b/share/weapons.qc index 1769f2e9..d5f24dc1 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -85,7 +85,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, { WEAP_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.2, 0, 1 }, - { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 2, 0.2, 0, 1 }, + { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 50, 2, 0.2, 1, 1 }, { WEAP_GRENADE_LAUNCHER , PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, { WEAP_PIPE_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0, 1 }, diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index fa8f1f3a..12726a34 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1407,6 +1407,9 @@ void (float ox) W_FireSpikes = { } *ws->ammo_remaining -= wi->ammo_per_shot; + if (wi->needs_reload) + *ws->clip_fired += wi->ammo_per_shot; + if (wi->weapon == WEAP_NAILGUN) W_FireNail(FPP_NAIL, v_right * ox); else From 247a65d5977b2541b647533364110d07432a8de1 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 13:10:21 -0800 Subject: [PATCH 2322/2474] wp: revert sng clip from previous example --- share/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/weapons.qc b/share/weapons.qc index d5f24dc1..1769f2e9 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -85,7 +85,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, { WEAP_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.2, 0, 1 }, - { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 50, 2, 0.2, 1, 1 }, + { WEAP_SUPER_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 2, 0.2, 0, 1 }, { WEAP_GRENADE_LAUNCHER , PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, { WEAP_PIPE_LAUNCHER, PRED_PROJ, AMMO_ROCKETS, 6, 1, 0.6, 4 }, // Overlaps GL { WEAP_FLAMETHROWER, PRED_PROJ, AMMO_CELLS, 0, 1, 0.15, 0, 1 }, From 9172e0dd767db3913bcb901b8e4aba09f5d030bf Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 13:13:07 -0800 Subject: [PATCH 2323/2474] weapons: allow changing from nailguns when firing allow weapon changes while firing the nailgun. this has been annoying since time began, it's also easy to config-script around; just fix it. --- share/animate.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/animate.qc b/share/animate.qc index f8f44fd5..6a4e63f1 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -214,7 +214,7 @@ static inline float FO_CheckForReload() { return WP_ReloadCurrentIfNeeded(); } void W_FireSpikes(float ox); // Shared by both client and server side. void nail_extra_csqc_ssqc() { - if (!is_attacking() || is_intermission()) { + if (!is_attacking() || is_intermission() || !IsSlotNull(self_queue_slot())) { player_run(); return; } From cab70113c57a22c8a8d031975788adc786d3384a Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 13:44:38 -0800 Subject: [PATCH 2324/2474] anim: fix respawn while dead --- share/animate.qc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/share/animate.qc b/share/animate.qc index 6a4e63f1..428c0169 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -46,8 +46,10 @@ void FO_SetClientThink(void() func, float offset, float override = TRUE) { } void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - if (self.deadflag) + if (self.deadflag) { + player_run(); return; + } float tidx = *thinkindex()++ - 1; From db7bb2d3abf0a20110a85c8c8eeadb419950c036 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 13:49:00 -0800 Subject: [PATCH 2325/2474] weapons: fix playercurrentweapon mistakenly made generic --- share/weapons.qc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/share/weapons.qc b/share/weapons.qc index 1769f2e9..b93fa43c 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -471,18 +471,21 @@ float self_class(); Slot self_current_slot(); float* self_clip_fired(Slot slot); -float FO_PlayerCurrentWeapon(entity player) { +float FO_CurrentWeapon() { FO_WeapInfo* wi = FO_SlotWeapInfo(self_class(), self_current_slot()); if (!wi) return WEAP_NONE; return wi->weapon; } -inline float FO_CurrentWeapon() { - return FO_PlayerCurrentWeapon(self); +#ifdef SSQC +float FO_PlayerCurrentWeapon(entity player) { + FO_WeapInfo* wi = FO_SlotWeapInfo(player.playerclass, player.current_slot); + if (!wi) + return WEAP_NONE; + return wi->weapon; } -#ifdef SSQC struct FO_WeapState { float weapon; Slot slot; From dc639a96c6db94f7dfc913aa13deea7ebd4d8f62 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 13:59:14 -0800 Subject: [PATCH 2326/2474] wp: remove fire_in_anim tag from autorifle, it just does many individual shots --- share/weapons.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/weapons.qc b/share/weapons.qc index b93fa43c..acc8ee22 100644 --- a/share/weapons.qc +++ b/share/weapons.qc @@ -81,7 +81,7 @@ FO_WeapInfo weapon_info[] = { { WEAP_SPANNER, PRED_MODEL, AMMO_CELLS, 0, 0, 0.5, 0 }, { WEAP_AXE, PRED_MODEL, AMMO_NONE, 0, 0, 0.5, 0 }, { WEAP_SNIPER_RIFLE, PRED_MODEL, AMMO_SHELLS, -9, 1, 1.5, 4 }, - { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0, 1 }, + { WEAP_AUTO_RIFLE, PRED_MODEL, AMMO_SHELLS, 0, 1, 0.1, 0 }, { WEAP_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 8, 1, 0.5, 2 }, { WEAP_SUPER_SHOTGUN, PRED_MODEL, AMMO_SHELLS, 16, 2, 0.7, 3 }, { WEAP_NAILGUN, PRED_PROJ, AMMO_NAILS, 0, 1, 0.2, 0, 1 }, From 79f5d518f7f832896f99fd69f5d6d62a8cca746a Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 19 Jan 2024 15:21:30 -0800 Subject: [PATCH 2327/2474] revert dead-player animation interpose, interactions with respawn still to fix --- share/animate.qc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/share/animate.qc b/share/animate.qc index 428c0169..3dbd8482 100644 --- a/share/animate.qc +++ b/share/animate.qc @@ -46,11 +46,6 @@ void FO_SetClientThink(void() func, float offset, float override = TRUE) { } void client_anim_frames(void() parent_thunk, void() extra, anim_t* anim) { - if (self.deadflag) { - player_run(); - return; - } - float tidx = *thinkindex()++ - 1; int wfi = tidx % anim->num_wf; From bc4de74f5668178df0e3fc9e75b780b97821154f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 21 Jan 2024 22:35:13 +1100 Subject: [PATCH 2328/2474] special2 should dismantle gun when in range --- ssqc/engineer.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 1255aa27..fd52233c 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -340,7 +340,7 @@ void () FO_Engineer_ToggleDispenser = { void () FO_Engineer_ToggleSentry = { if (self.has_sentry) { - DestroyBuilding(self, "building_sentrygun"); + Menu_Engineer_Input(3); } else { if (self.health <= 0) { sprint(self, PRINT_HIGH, "Can't build while dead.\n"); From 9ce06a36f1c7bfbfc619cbbf928fc5e23e56dee7 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 21 Jan 2024 21:23:04 -0800 Subject: [PATCH 2329/2474] rewind: remove localinfo to disable detpipe rewind --- ssqc/client.qc | 4 ---- ssqc/qw.qc | 5 ----- ssqc/rewind.qc | 3 --- 3 files changed, 12 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 2bba965a..a0bca49c 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -640,10 +640,6 @@ void () DecodeLevelParms = { asscanrange = CF_GetSetting("acr", "asscanrange", "0"); asscanrangedie = CF_GetSetting("acrd", "asscanrangedie", "0"); - // remote_client_time max delta - antilag_settings.rewind_detpipe = - CF_GetSetting("alrd", "al_rewind_detpipe", "on"); - // CSQC projectiles fo_projectiles = CF_GetSetting("focp", "fo_csqc_projectiles", "on"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index b1253a51..a7f5b256 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -9,11 +9,6 @@ enum { CT_FAST_PROJECTILE, // Fast proj => less judder (e.g. heavy bullet) }; -struct antilag_settings_t { - float rewind_detpipe; -} antilag_settings; - -.vector antilag_origin; .float last_death_ctime; .float last_attack_ctime; diff --git a/ssqc/rewind.qc b/ssqc/rewind.qc index e4f8a43c..0e5d6efa 100644 --- a/ssqc/rewind.qc +++ b/ssqc/rewind.qc @@ -322,9 +322,6 @@ void RW_RestoreAll() { float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; float RewindPlayersExceptSelf(float farthest_rewind_point) { - if (!antilag_settings.rewind_detpipe) - return FALSE; - float rewind_max_offset = (MAX_SNAPSHOTS - 1) * SERVER_FRAME_DT; farthest_rewind_point = max(farthest_rewind_point, time - rewind_max_offset); From 5234f4863080c9bf9a0a7c7bd7d8494fa7220e73 Mon Sep 17 00:00:00 2001 From: newby Date: Sun, 21 Jan 2024 21:27:03 -0800 Subject: [PATCH 2330/2474] nb: add antilag to impeller --- ssqc/engineer.qc | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index c1b0eb3d..bdb4e848 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -158,60 +158,57 @@ static void draw_beam(vector a, vector b, int effect) { } void W_FireImpeller() { - if (!cb_prematch) { - self.special_next = time + 3; - } - FO_Sound(self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); - makevectors(self.v_angle); + + float rewound = RewindPlayersExceptSelf(0); + + if (!cb_prematch) + self.special_next = time + 3; vector org = self.origin + '0 0 16'; - float direct = FALSE, jump = FALSE; - entity t = FindImpellerTarget(org, 0.985, &direct); - vector end = t.origin; + float direct = FALSE; + entity hit = FindImpellerTarget(org, 0.985, &direct); + + if (rewound) + FOPlayer::RestoreAll(); float mag = 250; - entity hit; + vector end; - if (t == world) { + if (hit == world) { traceline(org, org + 350 * v_forward, MOVE_WORLDONLY, world); if (trace_fraction == 1) return; end = trace_endpos; hit = self; - draw_beam(org, trace_endpos, TE_LIGHTNING2); + draw_beam(org, end, TE_LIGHTNING2); } else { - hit = t; - if (direct) { - end = t.origin; - draw_beam(org, t.origin, TE_LIGHTNING2); + end = hit.origin; + draw_beam(org, end, TE_LIGHTNING2); } else { vector a = org, b = org + kImpellerTargetRange * v_forward; traceline(a, b, MOVE_WORLDONLY, world); - if (trace_fraction == 1) - return; end = trace_endpos; - vector x = find_closest(a, end, t.origin); + vector x = find_closest(a, end, hit.origin); draw_beam(a, x, TE_LIGHTNING2); - draw_beam(x, t.origin, TE_LIGHTNING2); + draw_beam(x, hit.origin, TE_LIGHTNING2); // Discount knockback by help given - mag -= max(10, vlen(t.origin - x)); + mag -= max(10, vlen(hit.origin - x)); } - hit = t; - end = t.origin; + end = hit.origin; } deathmsg = DMSG_IMPELLER; TF_T_Damage(hit, self, self, 5, TF_TD_NOTTEAM, TF_TD_ELECTRICITY | TF_TD_NOMOMENTUM); hit.flags &= ~FL_ONGROUND; - hit.velocity -= mag * normalize(end - org); - if (other.has_flag) + if (hit.has_flag) mag *= 2; + hit.velocity -= mag * normalize(end - org); } void () W_FireRailgun = { From b66492f48d936b78bd43d1fb74f7499e5ea76263 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 22 Jan 2024 01:32:42 -0800 Subject: [PATCH 2331/2474] core: fix being able to fire after being gibbed in some cases --- ssqc/player.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index 1757e6bb..a934ed92 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -411,7 +411,7 @@ void () GibPlayer = { ThrowGib("progs/gib1.mdl", self.health); ThrowGib("progs/gib2.mdl", self.health); ThrowGib("progs/gib3.mdl", self.health); - if (deathmsg == 36) { + if (deathmsg == DMSG_TRIGGER) { newmis = spawn(); newmis.owner = self; newmis.think = KillPlayer; @@ -424,8 +424,7 @@ void () GibPlayer = { FO_Sound(self, CHAN_VOICE, "player/teledth1.wav", 1, 0); self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; - } - if (damage_attacker.classname == "teledeath2") { + } else if (damage_attacker.classname == "teledeath2") { FO_Sound(self, CHAN_VOICE, "player/teledth1.wav", 1, 0); self.respawn_time = (self.respawn_time + 2) + (random() * 2); return; @@ -435,6 +434,8 @@ void () GibPlayer = { } else { FO_Sound(self, CHAN_VOICE, "player/udeath.wav", 1, 0); } + + FO_SetClientThink(think_nop, 0); }; void () PlayerDie = { From ebbd2b62a6dc92b1b2ac599bb82ffc1e7a1a3d76 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 22 Jan 2024 22:26:00 +1100 Subject: [PATCH 2332/2474] Add debug logging to match reporting --- ssqc/quadmode.qc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 8693e192..87b96a07 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -95,6 +95,8 @@ void () PostFOQuadStarted = { data = strcat(data, "}\n"); local string uri = sprintf("%s/results/api/v1/matches", backend_address); + dprint("POST to ", uri, "\n"); + dprint(data); uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); }; From 1d5fa444f66ecf490304322746bbf1519ef72d33 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 23 Jan 2024 01:38:15 +1100 Subject: [PATCH 2333/2474] Add a bit more logging --- ssqc/quadmode.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 87b96a07..4e4be652 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -157,6 +157,8 @@ void () PostFOQuadFinalRoundStarted = { data = strcat(data, "}\n"); local string uri = sprintf("%s/results/api/v1/matches/%s", backend_address, match_id); + dprint("POST to ", uri, "\n"); + dprint(data); uri_post(uri, FO_QUAD_STARTED_REQUEST, "application/json", data); }; @@ -203,6 +205,8 @@ void (float winner) PostFOQuadFinished = { data = strcat(data, "}\n"); local string uri = sprintf("%s/results/api/v1/matches/%s", backend_address, match_id); + dprint("POST to ", uri, "\n"); + dprint(data); uri_post(uri, FO_QUAD_FINISHED_REQUEST, "application/json", data); }; From f5dbcd7a5c51f9ce30e16318629941ad4f9e2702 Mon Sep 17 00:00:00 2001 From: newby Date: Wed, 24 Jan 2024 14:01:55 -0800 Subject: [PATCH 2334/2474] weapons: more stringent server side check for whether ammo exists to fire Some oppotunities to tighten up client-side prediction here; but just fixing bug for now --- ssqc/weapons.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 12726a34..725fd56e 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1596,6 +1596,7 @@ Slot W_BestWeaponSlot() { for (float i = 1; i <= TF_NUM_SLOTS; i++) { Slot slot = MakeSlot(i); FO_FillWeapState(self, slot, &ws); + FO_WeapInfo* wi = ws->wi; // AC also takes cells to fire. if (ws->weapon == WEAP_ASSAULT_CANNON && self.ammo_cells < 7) @@ -1604,7 +1605,7 @@ Slot W_BestWeaponSlot() { // We don't need to handle out of ammo medi/spanner here because of // fallback below. if (ws.weapon != WEAP_NONE && - ((ws.wi)->ammo_type == AMMO_NONE || *ws.ammo_remaining)) + (wi->ammo_type == AMMO_NONE || (*ws.ammo_remaining >= wi->ammo_per_shot))) return slot; } return SlotMelee; From 233e0339940077a56784e083d228fb8f94c97070 Mon Sep 17 00:00:00 2001 From: newby Date: Sat, 27 Jan 2024 16:07:49 -0800 Subject: [PATCH 2335/2474] core: make haze-stats align better with in-game stats haze-stats currently behaves differently wrt over-damage (e.g. more damage than it takes to kill someone) than in-game stats. The in-game stats only log the damage actually done while haze-stats includes the "over" damage. Align this by logging true-damage for both. --- ssqc/events.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/events.qc b/ssqc/events.qc index 4090fec9..e4878402 100644 --- a/ssqc/events.qc +++ b/ssqc/events.qc @@ -195,7 +195,7 @@ void (entity attacker, entity target, entity inflictor, float damage, float true part2 = sprintf("\"inflictor\": \"%s\", \"damage\": %s, \"time\": %s, \"gameTimeStamp\": \"%s\"}", inflictorId, - ftos(damage), + ftos(truedam), ftos(gametime), gametimestamp ); From baa12ca4756c6504e0dd22c0a23dc5a8227bac81 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Mon, 29 Jan 2024 01:31:51 +1100 Subject: [PATCH 2336/2474] Make grenade lockout time configurable --- README.md | 1 + ssqc/client.qc | 1 + ssqc/qw.qc | 1 + ssqc/tfort.qc | 4 ++-- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 47f8e5c0..df3d7455 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * localinfo server_sbflaginfo : 0 - disables sbar flaginfo, 1 enables it [default: 1] * localinfo reverse_cap : 0 - normal gameplay, 1: you have to take your flag and capture in the enemy base [default: 0] * localinfo engineer_move / em : 0 - normal gameplay, 1: engineers can move while building [default: 1] +* localinfo grenade_lockout / gl : Time in seconds grenade throw is locked out [default: 0.1] * localinfo round_delay_time : interval time between rounds in quadmode - seconds [default: 30] * localinfo max_gren2_soldier : maximum number of active nail/shock grenades (TF 2.8 = 3, OzTF = 1) [default: 3] * localinfo distance_based_cuss_duration : on/off - enables cuss duration to be proportional to the distance from the explosion [default: off] diff --git a/ssqc/client.qc b/ssqc/client.qc index a0bca49c..e984a64e 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -859,6 +859,7 @@ void () DecodeLevelParms = { } engineer_move = CF_GetSetting("em","engineer_move", "1"); + grenade_lockout = CF_GetSetting("gl","grenade_lockout", "0.1"); max_active_gren2_soldier = CF_GetSetting("mg2s","max_active_gren2_soldier", "3"); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a7f5b256..258deab4 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -640,6 +640,7 @@ float deathammo_cells; //float server_sbflaginfo; float reverse_cap; float engineer_move; +float grenade_lockout; float fo_projectiles; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3c0f1426..c2b67fa8 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -922,11 +922,11 @@ void () FO_GrenadeThink = { void () FO_ThrowGrenade = { entity timer = self.grenade_timer; - float throwtime = time, lockout = 0.1; + float throwtime = time; if (RewindFlagEnabled(REWIND_GRENADES)) throwtime = bounded_remote_time(FO_RewindGrenDt(timer.fpp.gren_type)); - if ((timer.nextthink < timer.heat || throwtime > timer.heat - lockout) && + if ((timer.nextthink < timer.heat || throwtime > timer.heat - grenade_lockout) && !IsClownMode(CLOWN_SPAM_GRENADES)) { // We do not allow throwing within the 0.8s, or the last 0.1s. // The former is a priming time, the latter is so that client side From 868b80346d56f981b2f29dd602182f4b4831a061 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 29 Jan 2024 23:25:49 +1100 Subject: [PATCH 2337/2474] Options to configure pipe cooldown time and whether it applies to pipes individually or not. i.e. 'localinfo allpipes_cooldown off' allows demo to det previously laid pipes during cooldown --- README.md | 4 ++++ ssqc/client.qc | 11 +++++++---- ssqc/demoman.qc | 4 ++-- ssqc/qw.qc | 3 ++- ssqc/tfort.qc | 2 +- ssqc/weapons.qc | 5 +---- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 47f8e5c0..2c4c8b36 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,10 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc ------------------------------- * Website backend for match results, stats. Get a token at fortressone.org, connect to a FortressOne server, and `login `. + + +* `localinfo pipecooldown_time ` time in seconds for demo pipe cooldown +* `localinfo allpipes_cooldown on/off` whether cooldown is applied to individual pipes or all pipes. i.e. with this on the demo can not det any of his pipes immediately after firing. (default off) * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. * `localinfo fo_matchrated 2` whether match is rated / affects trueskill. 2 is false for 1v1 and 2v2 only. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ diff --git a/ssqc/client.qc b/ssqc/client.qc index a0bca49c..c5638941 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -516,8 +516,11 @@ void () DecodeLevelParms = { // maximum amount of pipebombs in game [unlimited] detpipe_limit_world = CF_GetSetting("dw", "detpipe_limit_world", "-1"); - // use old tf pipebomb cooldown (0.8 seconds) [off] - old_pipecooldown = CF_GetSetting("op", "old_pipecooldown", "off"); + // set pipe cooldown time [0.5] + pipecooldown_time = CF_GetSetting("pcdt", "pipecooldown_time", "0.5"); + + // cooldown applies to all pipes [off] + allpipes_cooldown = CF_GetSetting("apcd", "allpipes_cooldown", "off"); // allow medic aura [on] medicaura = CF_GetSetting("ma", "medicaura", "on"); @@ -879,7 +882,7 @@ void () DecodeLevelParms = { old_sniperrange = FALSE; Role_None.detpipe_limit = 6; detpipe_limit_world = -1; - old_pipecooldown = FALSE; + pipecooldown_time = 0.5; medicaura = TRUE; old_biodamage = FALSE; cannon_lock = TRUE; @@ -947,7 +950,7 @@ void () DecodeLevelParms = { old_sniperrange = TRUE; Role_None.detpipe_limit = 7; detpipe_limit_world = 7; - old_pipecooldown = TRUE; + pipecooldown_time = 0.8; medicaura = FALSE; old_biodamage = TRUE; cannon_lock = FALSE; diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index c996e18d..a9e4c737 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -17,7 +17,7 @@ void () TeamFortress_DetpackCountDown; void CheckStateQ3Goal(entity trig); float (float force) TeamFortress_DetonatePipebombs = { - if (time < self.pipecooldown && !force) + if (allpipes_cooldown && time < self.pipecooldown && !force) return impulse_queue ? FALSE : TRUE; if (self.detpipe_nesting > 0) @@ -34,7 +34,7 @@ float (float force) TeamFortress_DetonatePipebombs = { rewound = RewindPlayersExceptSelf(self.pipecooldown); for (float i = 0; i < count; i++) { - if (pipes[i].owner == self) { + if (pipes[i].owner == self && pipes[i].created_at < time - pipecooldown_time) { deathmsg = pipes[i].flags & FL_ONGROUND ? pipes[i].weapon : DMSG_GREN_PIPE_AIR; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index a7f5b256..ef30776d 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -558,7 +558,8 @@ float old_dropflag; float old_sniperrange; //float detpipe_limit; float detpipe_limit_world; -float old_pipecooldown; +float pipecooldown_time; +float allpipes_cooldown; float medicaura; float old_biodamage; float flame_knockback; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3c0f1426..d3e49bff 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -661,7 +661,7 @@ void () TeamFortress_ShowTF = { } else { sprint(self, PRINT_HIGH, "Pipebomb limit (team): unlimited\n"); } - CF_PrintSetting("Old pipebomb cooldown", old_pipecooldown, "", 1); + CF_PrintSetting("Pipebomb cooldown time", pipecooldown_time, "", 0.5); sprint(self, PRINT_HIGH, "\n== Combat Medic ==\n"); CF_PrintSetting("Medic aura ability", medicaura, "", 1); diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 12726a34..0050b711 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -1334,10 +1334,7 @@ void W_FireGrenade(vector org, vector v_ang, float use_ctime=0) { proj.nextthink = time + 2.5; proj.fpp.gren_type = GREN_RED; } else { - if (old_pipecooldown) - self.pipecooldown = time + 0.8; - else - self.pipecooldown = time + 0.5; + self.pipecooldown = time + pipecooldown_time; ExplodeOldestPipebomb(); proj.classname = "pipebomb"; proj.touch = PipebombTouch; From b6c5c55180017b86c22a5850bfccf624894f1d2e Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 29 Jan 2024 08:59:49 -0800 Subject: [PATCH 2338/2474] demoman: disable allpipes_cooldown by default To enable for testing: `rcon localinfo apcd 1` --- ssqc/client.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index d797ac84..60722c1d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -519,8 +519,8 @@ void () DecodeLevelParms = { // set pipe cooldown time [0.5] pipecooldown_time = CF_GetSetting("pcdt", "pipecooldown_time", "0.5"); - // cooldown applies to all pipes [off] - allpipes_cooldown = CF_GetSetting("apcd", "allpipes_cooldown", "off"); + // cooldown applies to all pipes [on] + allpipes_cooldown = CF_GetSetting("apcd", "allpipes_cooldown", "on"); // allow medic aura [on] medicaura = CF_GetSetting("ma", "medicaura", "on"); From e10d54ed4b08a9f9b2cde4547351caae9a12b341 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 29 Jan 2024 09:07:57 -0800 Subject: [PATCH 2339/2474] demoman: fix death bug with new allpipes_cooldown The cooldown check would allow a pipe thrown as a demoman was dying to survive past death. --- ssqc/demoman.qc | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ssqc/demoman.qc b/ssqc/demoman.qc index a9e4c737..3185760e 100644 --- a/ssqc/demoman.qc +++ b/ssqc/demoman.qc @@ -17,7 +17,7 @@ void () TeamFortress_DetpackCountDown; void CheckStateQ3Goal(entity trig); float (float force) TeamFortress_DetonatePipebombs = { - if (allpipes_cooldown && time < self.pipecooldown && !force) + if (!force && allpipes_cooldown && time < self.pipecooldown) return impulse_queue ? FALSE : TRUE; if (self.detpipe_nesting > 0) @@ -34,18 +34,21 @@ float (float force) TeamFortress_DetonatePipebombs = { rewound = RewindPlayersExceptSelf(self.pipecooldown); for (float i = 0; i < count; i++) { - if (pipes[i].owner == self && pipes[i].created_at < time - pipecooldown_time) { - deathmsg = pipes[i].flags & FL_ONGROUND ? pipes[i].weapon : - DMSG_GREN_PIPE_AIR; + if (pipes[i].owner != self) + continue; - T_RadiusDamage(pipes[i], pipes[i].owner, 120, world); + if (!force && pipes[i].created_at > time - pipecooldown_time) + continue; - // This maintains some sort of awful hack that we'll remove. - pipes[i].voided = 1; + deathmsg = pipes[i].flags & FL_ONGROUND ? pipes[i].weapon : + DMSG_GREN_PIPE_AIR; - RenderExplosion(pipes[i].origin); - dremove(pipes[i]); - } + T_RadiusDamage(pipes[i], pipes[i].owner, 120, world); + + // This maintains some sort of awful hack that we'll remove. + pipes[i].voided = 1; + RenderExplosion(pipes[i].origin); + dremove(pipes[i]); } // NOTE: nested death-dets would not trigger double unwind due to `force==1` From eeb9e37728aef81b5a8f86a589b77f7c2b8b45e9 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 29 Jan 2024 10:15:32 -0800 Subject: [PATCH 2340/2474] new-balance: enable in all regions by default --- ssqc/client.qc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 60722c1d..5d12ebbb 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -1092,12 +1092,7 @@ void () DecodeLevelParms = { */ // Overrides other settings. - new_balance = CF_GetSetting("new_balance", "new_balance", "4"); - - float new_balance_region = (ServerRegion() == kRegionUS || - ServerRegion() == kRegionOCE); - if (new_balance == 4) - new_balance = (new_balance_region && ServerIsStaging()) ? 1 : 0; + new_balance = CF_GetSetting("new_balance", "new_balance", "1"); // mirror current state into desired state bit new_balance |= (new_balance << 1); From afbcf619ce59542688691c5f2453a7ae35dbc947 Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 1 Feb 2024 21:59:16 -0800 Subject: [PATCH 2341/2474] slot_a: make slot_a work consistently with owi just always use slot indices to fix some edges --- csqc/weapon_predict.qc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ac0eb1c3..9821e53a 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -719,12 +719,9 @@ void W_ChangeToSlotAlternate(string opt1, string opt2) { if ((v1 < 1 || v1 > TF_NUM_SLOTS) || (v2 < 1 || v2 > TF_NUM_SLOTS)) return; - // The OWI/slot mess rears its head again here. We convert to a slot for - // comparison but use the naked input value which will then be converted per - // OWI if active. - Slot slot = FO_SlotByInput(pstate_pred.playerclass, v1); - float imp = IsSameSlot(pstate_pred.current_slot, slot) ? v2 : v1; - localcmd(sprintf("impulse %d\n", imp)); + Slot slot = MakeSlot(v1); + float si = IsSameSlot(pstate_pred.current_slot, slot) ? v2 : v1; + localcmd(sprintf("impulse %d\n", TF_SLOT1 + si - 1)); } Slot WP_BestWeaponSlot() { From 480ba84a1547b0336931f702dc532ec7612582be Mon Sep 17 00:00:00 2001 From: newby Date: Thu, 1 Feb 2024 22:10:03 -0800 Subject: [PATCH 2342/2474] slot_a: make slot_a work with up to 4 inputs --- csqc/main.qc | 4 ++-- csqc/weapon_predict.qc | 25 +++++++++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 0301c01e..f25a5d9e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -252,7 +252,7 @@ void Slot_Keyup(float slot) { localcmd("-attack\n"); } -void W_ChangeToSlotAlternate(string opt1, string opt2); +void W_ChangeToSlotAlternate(string opt1, string opt2, string opt3, string opt4); noref float(string cmd) CSQC_ConsoleCommand = { tokenize_console(cmd); @@ -452,7 +452,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { RemoveVoteMap(argv(1), TRUE); break; case "slot_a": // Alternate between passed options - W_ChangeToSlotAlternate(argv(1), argv(2)); + W_ChangeToSlotAlternate(argv(1), argv(2), argv(3), argv(4)); break; } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index 9821e53a..a5ca0a9b 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -712,16 +712,25 @@ void WP_ChangeWeapon(Slot slot) { // Alternate between opt1/opt2, activating opt1 if neither is active. // Useful for demoman to have red/yellows bound to 1 key. -void W_ChangeToSlotAlternate(string opt1, string opt2) { - float v1 = strlen(opt1) > 0 ? stof(opt1) : 0; - float v2 = strlen(opt2) > 0 ? stof(opt2) : v1; +void W_ChangeToSlotAlternate(string opt1, string opt2, string opt3, string opt4) { + float v[4], nv = 0, idx = -1; + string s[4] = {opt1, opt2, opt3, opt4}; - if ((v1 < 1 || v1 > TF_NUM_SLOTS) || (v2 < 1 || v2 > TF_NUM_SLOTS)) - return; + for (int i = 0; i < s.length; i++) { + if (strlen(s[i]) == 0) + break; + + float t = stof(s[i]); + if (t < 1 || t > TF_NUM_SLOTS) + return; + + if (SlotIndex(pstate_pred.current_slot) + 1 == t) + idx = nv; + v[nv++] = t; + } - Slot slot = MakeSlot(v1); - float si = IsSameSlot(pstate_pred.current_slot, slot) ? v2 : v1; - localcmd(sprintf("impulse %d\n", TF_SLOT1 + si - 1)); + idx = (idx + 1) % nv; + localcmd(sprintf("impulse %d\n", TF_SLOT1 + v[idx] - 1)); } Slot WP_BestWeaponSlot() { From 9ee041a8fed96238534a64c664e05bb4e9ee7c0d Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Mar 2024 09:55:15 -0700 Subject: [PATCH 2343/2474] misc: fix cmd break spam --- ssqc/commands.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 2cbcbf7d..f3f2c6f6 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -846,7 +846,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "break": processedCmd = TRUE; - if(self.vote_map) { + + if (disable_voting) { + // Do nothing + } else if (self.vote_map) { UnvoteForMap(self); } else { if(votemode) { From 60f605ff17049aa9d67227446782afaa26b84f27 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Mar 2024 12:26:08 -0700 Subject: [PATCH 2344/2474] new-balance: migrate updates away from new-balance control now that these are standardized for organized games, migrate them away from the tunable so that we can use it to control newer features --- ssqc/client.qc | 10 ++++++---- ssqc/qw.qc | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5d12ebbb..2fd1b79a 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -241,7 +241,7 @@ static float NB_UseMinPing() { return TRUE; } -void ActivateNewBalance() { +void ActivateOrgGame() { disable_resup_gren = 2; // No gren2 pickups drop_gren1 = 0; // No grenades in backpacks @@ -383,6 +383,7 @@ void () DecodeLevelParms = { duelmode = CF_GetSetting("duelmode", "duelmode", "off"); disable_voting = clanbattle || quadmode; + org_game = clanbattle || quadmode; rounds = CF_GetSetting("rounds","rounds","on"); if (!rounds) @@ -1093,11 +1094,12 @@ void () DecodeLevelParms = { // Overrides other settings. new_balance = CF_GetSetting("new_balance", "new_balance", "1"); - // mirror current state into desired state bit new_balance |= (new_balance << 1); - if (NewBalanceActive()) - ActivateNewBalance(); + + if (org_game) // This used to depend on new balance + ActivateOrgGame(); + }; entity() FindIntermission = diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 05befea3..b25d5fe1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -450,6 +450,7 @@ float clanbattle; float clan_scores_dumped; float cb_prematch; float disable_voting; +float org_game; float v_break; float v_ready; .float allowvote; From 8c40487c432a6ac63f505761333a51a861bd27bd Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Mar 2024 09:49:49 -0700 Subject: [PATCH 2345/2474] teamplay: add some new helpers --- ssqc/progs.src | 1 + ssqc/teamplay.qc | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 ssqc/teamplay.qc diff --git a/ssqc/progs.src b/ssqc/progs.src index e563dbaa..c4d080b9 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -29,6 +29,7 @@ events.qc roles.qc q3defs.qc status.qc +teamplay.qc functions.qc menu.qc csmenu.qc diff --git a/ssqc/teamplay.qc b/ssqc/teamplay.qc new file mode 100644 index 00000000..3b7da387 --- /dev/null +++ b/ssqc/teamplay.qc @@ -0,0 +1,88 @@ +static void Apply(entity* targets, int tcount, int(entity) filter_fn, + void(entity) apply_fn) { + for (int i = 0; i < tcount; i++) + if (filter_fn(targets[i])) + apply_fn(targets[i]); +} + +static void ApplyList(entity* targets, int count, + int(entity) player_filter_fn, void(entity) player_apply_fn, + int(entity) other_filter_fn, void(entity) other_apply_fn) { + for (int i = 0; i < count; i++) { + entity e = targets[i]; + + if (e.classname == "player") { + if (player_filter_fn(e)) + player_apply_fn(e); + } else if (e.owner.classname == "player") { + if (other_filter_fn(e)) + other_apply_fn(e); + } + } +} + +static void ApplyRadius(vector org, float rad, + int(entity) player_filter_fn, void(entity) player_apply_fn, + int(entity) other_filter_fn, void(entity) other_apply_fn) { + int count; + entity* ents = findradius_list(org, rad, count); + ApplyList(ents, count, + player_filter_fn, player_apply_fn, other_filter_fn, other_apply_fn); +} + +static void EffStrip(entity player) { + player.ammo_cells = 0; + player.ammo_rockets = 0; + player.ammo_shells = 0; + player.ammo_nails = 0; + + player.no_grenades_1 = player.no_grenades_2 = 0; + player.current_slot = player.queue_slot = MakeSlot(4); +} + +static void EffRemove(entity non_player) { + if (non_player.classname == "player") { + printf("ERROR! Tried to remove player [%s]\n", non_player.netname); + return; + } + + dremove(non_player); +} + +static int(entity p) FilTeamEQ[] = { + { return p.team_no == 1; }, + { return p.team_no == 2; }, + { return p.team_no == 3; }, + { return p.team_no == 4; }, +}; + +static int(entity p) FilTeamNEQ[] = { + { return p.team_no != 1; }, + { return p.team_no != 2; }, + { return p.team_no != 3; }, + { return p.team_no != 4; }, +}; + + +static void FilTrue(entity ignored) { return TRUE; } + +struct LocalFn { + union { + int(entity) int_fn_ent; + void(entity) void_fn_ent; + }; +}; + +void ApplyAll() { + entity* players; + int count; + + LocalFn foo = { .int_fn_ent = {return TRUE; } }; + + players = find_list(classname, "player", EV_STRING, count); + Apply(players, count, foo.int_fn_ent, EffStrip); +} + +void TeamPlay_Cap(vector origin, int cap_team) { + +} From 718363493c02052812bfc18c48ff566f66a60421 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Mar 2024 12:41:39 -0700 Subject: [PATCH 2346/2474] teamplay: strip defenders (and remove ents) near cap point after capture --- ssqc/engineer.qc | 48 +++++++++++++++++++++++++++++++----------------- ssqc/teamplay.qc | 48 +++++++++++++++++++++++++++--------------------- ssqc/tfortmap.qc | 2 ++ 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f1cf18cb..06c3785b 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1577,6 +1577,33 @@ void () CheckDistance = { self.nextthink = time + 0.3; }; +float IsEngEnt(entity ent) { + return ent.classname == "building_dispenser" || + ent.classname == "building_sentrygun"; + +} + +void RemoveEngEnt(entity bld, float explode) { + entity owner = bld.real_owner; + if (owner.building == bld) { + Menu_Close(owner); + owner.building = world; + } + + if (explode) { + TF_T_Damage(bld, world, world, 500, 0, 0); + } else { + if(bld.classname == "building_dispenser") + owner.has_dispenser = 0; + if(bld.classname == "building_sentrygun") { + owner.has_sentry = 0; + if (bld.trigger_field != world) + dremove (bld.trigger_field); + } + dremove (bld); + } +} + void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { local entity te; local entity oldself; @@ -1593,23 +1620,10 @@ void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { bound_other_ammo(self); self = oldself; } - if (te.real_owner.building == te) { - Menu_Close(te.real_owner); - te.real_owner.building = world; - } - if(explode) { - TF_T_Damage(te, world, world, 500, 0, 0); - } else { - if(bld == "building_dispenser") - te.real_owner.has_dispenser = 0; - if(bld == "building_sentrygun") { - te.real_owner.has_sentry = 0; - if (te.trigger_field != world) - dremove (te.trigger_field); - } - spawn_tfog(te.origin); - dremove (te); - } + + spawn_tfog(te.origin); + RemoveEngEnt(te, explode); + } te = find(te, classname, bld); } diff --git a/ssqc/teamplay.qc b/ssqc/teamplay.qc index 3b7da387..ba29fa91 100644 --- a/ssqc/teamplay.qc +++ b/ssqc/teamplay.qc @@ -5,6 +5,13 @@ static void Apply(entity* targets, int tcount, int(entity) filter_fn, apply_fn(targets[i]); } +static entity EntityOwner(entity e) { + if (e.real_owner != world) + return e.real_owner; + else + return e.owner; +} + static void ApplyList(entity* targets, int count, int(entity) player_filter_fn, void(entity) player_apply_fn, int(entity) other_filter_fn, void(entity) other_apply_fn) { @@ -14,7 +21,7 @@ static void ApplyList(entity* targets, int count, if (e.classname == "player") { if (player_filter_fn(e)) player_apply_fn(e); - } else if (e.owner.classname == "player") { + } else if (EntityOwner(e).classname == "player") { if (other_filter_fn(e)) other_apply_fn(e); } @@ -40,13 +47,20 @@ static void EffStrip(entity player) { player.current_slot = player.queue_slot = MakeSlot(4); } +float IsEngEnt(entity ent); +void RemoveEngEnt(entity bld, float explode); + static void EffRemove(entity non_player) { if (non_player.classname == "player") { printf("ERROR! Tried to remove player [%s]\n", non_player.netname); return; } - dremove(non_player); + pointparticles(particleeffectnum("fo_airblast"), non_player.origin); + if (IsEngEnt(non_player)) + RemoveEngEnt(non_player, FALSE); + else + dremove(non_player); } static int(entity p) FilTeamEQ[] = { @@ -63,26 +77,18 @@ static int(entity p) FilTeamNEQ[] = { { return p.team_no != 4; }, }; - -static void FilTrue(entity ignored) { return TRUE; } - -struct LocalFn { - union { - int(entity) int_fn_ent; - void(entity) void_fn_ent; - }; +static int(entity p) FilOwnerTeamNEQ[] = { + { return EntityOwner(p).team_no != 1; }, + { return EntityOwner(p).team_no != 2; }, + { return EntityOwner(p).team_no != 3; }, + { return EntityOwner(p).team_no != 4; }, }; -void ApplyAll() { - entity* players; - int count; - - LocalFn foo = { .int_fn_ent = {return TRUE; } }; - - players = find_list(classname, "player", EV_STRING, count); - Apply(players, count, foo.int_fn_ent, EffStrip); -} - -void TeamPlay_Cap(vector origin, int cap_team) { +void TeamPlay_Cap(vector origin, entity player) { + if (!org_game || !new_balance) + return; + ApplyRadius(origin, 1500, + FilTeamNEQ[player.team_no - 1], EffStrip, + FilOwnerTeamNEQ[player.team_no - 1], EffRemove); } diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 4a44d286..fa2037a3 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -951,6 +951,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (stock_on_cap) { if (Player == AP) { + TeamPlay_Cap(AP.origin, AP); + if (Player.health > 0) { T_Heal(Player, Player.max_health, 0); Player.armortype = Player.armor_allowed; From 28f7d5177c918a41c8375fef91d6a56ce8116ca5 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Mar 2024 13:41:36 -0700 Subject: [PATCH 2347/2474] teamplay: lower suicide delay to 4 seconds --- ssqc/tfort.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 08f352c2..cfb45daa 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2045,11 +2045,12 @@ void (float Suicided) TeamFortress_SetupRespawn = { if (Suicided) { if (self.lives > 0) self.lives = self.lives - 1; - - if(!allowpracspawns) - restime = restime + 7; + + if (!allowpracspawns) + restime = restime + (new_balance ? 4 : 7); } } + if (cb_prematch) { if (self.lives > 0) self.lives = self.lives - 1; From e63d927ac0bfbff54dd19b049dc73c9c16a80f38 Mon Sep 17 00:00:00 2001 From: newby Date: Fri, 15 Mar 2024 13:41:36 -0700 Subject: [PATCH 2348/2474] teamplay: just kidding, 5 seconds delay (4 too aggressive for first move) --- ssqc/tfort.qc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 08f352c2..91e88579 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2045,11 +2045,12 @@ void (float Suicided) TeamFortress_SetupRespawn = { if (Suicided) { if (self.lives > 0) self.lives = self.lives - 1; - - if(!allowpracspawns) - restime = restime + 7; + + if (!allowpracspawns) + restime = restime + (new_balance ? 5 : 7); } } + if (cb_prematch) { if (self.lives > 0) self.lives = self.lives - 1; From 5aa2f74358a80e82198c76c61802aad44750e654 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 16 Mar 2024 11:26:04 +1100 Subject: [PATCH 2349/2474] Fix hard to pick up flag after door closing on it --- ssqc/tfortmap.qc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 4a44d286..bf41a9e8 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -681,7 +681,6 @@ void DefaultGoalState (entity Goal) } void (entity Goal) RestoreGoal = { - if (Goal.goal_state == TFGS_REMOVED) { Goal.dimension_seen = DMN_NOFLASH; @@ -2076,7 +2075,12 @@ void () tfgoal_timer_tick = { }; void () item_tfgoal_touch = { - local entity te; + // I can't see where exactly, but when a flag ends up in a door it's min + // and maxs are set to (0, 0, -16) thus reducing it to a single point 16 + // units below origin. This restores the correct size. + if (self.classname == "item_tfgoal" && other.classname == "worldspawn") { + setsize(self, self.goal_min, self.goal_max); + } if (other.classname != "player") return; @@ -2089,6 +2093,7 @@ void () item_tfgoal_touch = { if (other == self.owner) return; + local entity te; // check if a wall or something is in the way of the flag traceline(other.origin, self.origin, TRUE, world); if (trace_fraction < 1) From f7924dc6b697856adc28392228fe3ef4e02d3715 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 17 Mar 2024 17:22:49 +1100 Subject: [PATCH 2350/2474] Set discard and ammobox sizes same as backpacks --- ssqc/actions.qc | 2 +- ssqc/tfort.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index d4c4be55..83fb7863 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -103,7 +103,7 @@ void () TeamFortress_Discard = { newmis.velocity_z = 200; } newmis.avelocity = '0 300 0'; - setsize(newmis, '0 0 0', '0 0 0'); + setsize(newmis, '-16 -16 0', '16 16 56'); setorigin(newmis, self.origin); newmis.nextthink = time + 30; newmis.think = SUB_Remove; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 08f352c2..e9bfbb3b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2252,7 +2252,7 @@ void (float type, float ammo) TeamFortress_DropAmmo = { newmis.velocity_z = 200; } newmis.avelocity = '0 300 0'; - setsize(newmis, '0 0 0', '0 0 0'); + setsize(newmis, '-16 -16 0', '16 16 56'); setorigin(newmis, self.origin); newmis.nextthink = time + 30; newmis.think = SUB_Remove; From c37775deb2945bff80d206f401c6a6c1fa5b92c4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 17 Mar 2024 21:07:33 +1100 Subject: [PATCH 2351/2474] Limit throwflag lockout to the thrower --- ssqc/actions.qc | 4 ++-- ssqc/qw.qc | 2 ++ ssqc/status.qc | 30 ++++++++++++------------------ ssqc/tfort.qc | 6 +++--- ssqc/tfortmap.qc | 28 +++++++++++++++++----------- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/ssqc/actions.qc b/ssqc/actions.qc index d4c4be55..7e9c1921 100644 --- a/ssqc/actions.qc +++ b/ssqc/actions.qc @@ -87,8 +87,8 @@ void () TeamFortress_Discard = { self.ammo_cells = 0; } FO_Sound(self, CHAN_AUTO, "weapons/lock4.wav", 1, ATTN_NORM); - newmis.enemy = self; - newmis.health = time; + newmis.dropped_by = self; + newmis.dropped_at = time; newmis.weapon = 0; newmis.movetype = MOVETYPE_TOSS; newmis.solid = SOLID_TRIGGER; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 05befea3..01778f4f 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -261,6 +261,8 @@ float coop; .float group_no; // Goal group this goal is in .float goal_state; // State of this goal .float owned_by; // The team this goal/item/whatever belongs to +.float dropped_at; // Time when item was dropped +.entity dropped_by; // Entity that last held item // Goal Activation details .float goal_activation; // Bitfields. Determines how this goal is activated diff --git a/ssqc/status.qc b/ssqc/status.qc index 1be22004..792044dd 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -17,7 +17,6 @@ string(entity pl) SentryDetailsToString; string(entity pl) BuildingToString; string(float pc) TeamFortress_GetClassName; entity(float ino) Finditem; -void () tfgoalitem_droptouch; void () tfgoalitem_dropthink; void () tfgoalitem_remove; float (entity ent, string ps_short, string ps_setting, string ps_default) FO_GetUserSetting; @@ -665,23 +664,18 @@ void (entity Player, entity Item) UpdateClientFlagStatus = { if (Item.origin != Item.oldorigin) { if((Item.nextthink - time) >= 0) { WriteFloat(MSG_MULTICAST, FLAGINFO_DROPPED); - if(Item.think != tfgoalitem_droptouch) { - if(noreturn) { - WriteFloat(MSG_MULTICAST, -1); - } else { - WriteFloat(MSG_MULTICAST, rint(Item.bubble_count - time)); - } - if((Item.think == tfgoalitem_dropthink || Item.think == tfgoalitem_remove) && !Item.owner) { - WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); - WriteCoord(MSG_MULTICAST, Item.origin_x); - WriteCoord(MSG_MULTICAST, Item.origin_y); - WriteCoord(MSG_MULTICAST, Item.origin_z); - WriteString(MSG_MULTICAST, getLocationName(Item.origin)); - } else { - WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); - } - } else { + if(noreturn) { WriteFloat(MSG_MULTICAST, -1); + } else { + WriteFloat(MSG_MULTICAST, rint(Item.bubble_count - time)); + } + if((Item.think == tfgoalitem_dropthink || Item.think == tfgoalitem_remove) && !Item.owner) { + WriteFloat(MSG_MULTICAST, FLAGINFO_LOCATION); + WriteCoord(MSG_MULTICAST, Item.origin_x); + WriteCoord(MSG_MULTICAST, Item.origin_y); + WriteCoord(MSG_MULTICAST, Item.origin_z); + WriteString(MSG_MULTICAST, getLocationName(Item.origin)); + } else { WriteFloat(MSG_MULTICAST, FLAGINFO_NOLOCATION); } } else { @@ -724,7 +718,7 @@ string (entity Player, entity Item, float teamno) GetItemStatus = { if (Item.origin != Item.oldorigin) { //When the item is thrown, there is a touch think with a pad of 4.25s before the normal timer kicks in if((Item.nextthink - time) >= 0) { - if(Item.think != tfgoalitem_droptouch && !noreturn) { + if(!noreturn) { st = strcat(st, Q"\s: Return: \s", ftos(rint(Item.bubble_count - time))); } else { st = strcat(st, Q"\s: Dropped\s"); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 08f352c2..8dcfe6bb 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -2237,8 +2237,8 @@ void (float type, float ammo) TeamFortress_DropAmmo = { newmis.ammo_rockets = ammo; else if (newmis.weapon == 4) newmis.ammo_cells = ammo; - newmis.enemy = self; - newmis.health = time; + newmis.dropped_by = self; + newmis.dropped_at = time; newmis.movetype = 6; newmis.solid = 1; newmis.classname = "ammobox"; @@ -2267,7 +2267,7 @@ void () TeamFortress_AmmoboxTouch = { local string quantity; took = 0; - if ((other == self.enemy) && (time < (self.health + 2))) + if ((other == self.dropped_by) && (time < (self.dropped_at + 2))) return; if ((other.tfstate & TFSTATE_CANT_MOVE) || (other.tfstate & TFSTATE_AIMING)) return; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 4a44d286..ade85f8a 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2076,7 +2076,13 @@ void () tfgoal_timer_tick = { }; void () item_tfgoal_touch = { - local entity te; + // I can't see where exactly, but when a flag ends up in a door it's min + // and maxs are set to (0, 0, -16) thus reducing it to a single point 16 + // units below origin. This restores the correct size. + if (self.classname == "item_tfgoal" && other.classname == "worldspawn") { + setsize(self, self.goal_min, self.goal_max); + return; + } if (other.classname != "player") return; @@ -2088,6 +2094,10 @@ void () item_tfgoal_touch = { return; if (other == self.owner) return; + if (other == self.dropped_by && time < self.dropped_at + 0.75) + return; + + local entity te; // check if a wall or something is in the way of the flag traceline(other.origin, self.origin, TRUE, world); @@ -2520,12 +2530,6 @@ void () tfgoalitem_dropthink = { } }; -void () tfgoalitem_droptouch = { - self.touch = item_tfgoal_touch; - self.nextthink = time + 4.25; - self.think = tfgoalitem_dropthink; -}; - void (entity Item, float PAlive, entity P) tfgoalitem_drop = { entity oldself; oldself = self; @@ -2560,10 +2564,12 @@ void (entity Item, float PAlive, entity P) tfgoalitem_drop = { Item.velocity = Item.velocity * 400; Item.velocity_z = 200; } - Item.touch = SUB_Null; - Item.nextthink = time + 0.75; + Item.touch = item_tfgoal_touch; + Item.dropped_by = Item.owner; + Item.dropped_at = time; + Item.nextthink = time + 4.25; Item.bubble_count = time + Item.pausetime + 0.75 + 4.25; //used by the return timer - Item.think = tfgoalitem_droptouch; + Item.think = tfgoalitem_dropthink; } else { Item.touch = item_tfgoal_touch; Item.nextthink = time + 5; @@ -2957,7 +2963,7 @@ void () DropGoalItems = { bprint(PRINT_HIGH, self.netname, Q" \sdropped the enemy's flag!\s\n"); } } - + Status_Print(self, "\n\n\n", "You dropped the flag!"); search = find(world, classname, "player"); while (search) { From 3cea3dcd92d7e721d3670652313ed12700f71c9f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 17 Mar 2024 22:10:07 +1100 Subject: [PATCH 2352/2474] Revmove duplicate local entity declaration --- ssqc/tfortmap.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 135b4b16..e244f92b 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2096,8 +2096,6 @@ void () item_tfgoal_touch = { if (other == self.dropped_by && time < self.dropped_at + 0.75) return; - local entity te; - local entity te; // check if a wall or something is in the way of the flag traceline(other.origin, self.origin, TRUE, world); From 2a8c980effa10c281b750119cc28fb6ca5523ad6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 18 Mar 2024 20:46:16 +1100 Subject: [PATCH 2353/2474] Fix freelook in demos --- csqc/pmove.qc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index 72f1d8da..0954ecf0 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -409,7 +409,13 @@ DEFCVAR_FLOAT(cl_upspeed, 400); void PM_InputFrame() { float iz = input_movevalues.z; input_movevalues.z = 0; - float max_speed = pstate_pred.csqc_maxspeed; + + float max_speed; + if (isdemo) { + max_speed = SPEC_MAXSPEED; + } else { + max_speed = pstate_pred.csqc_maxspeed; + } // cl_smartjump replacement float type; From b411bf41c034324ba0cc311934f3bb3920abd57f Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Mar 2024 09:40:32 -0700 Subject: [PATCH 2354/2474] core: make special act like +special +special has advantaged behavior over special because it expresses for more than a single frame, especially for actions such as detpipe. However, +special cannot be bound to keys that do not release, such as mwheel. Change special to express +special for 150ms to minimize this advantage. --- csqc/csextradefs.qc | 1 + csqc/main.qc | 8 ++++++++ share/defs.h | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6aff7a82..002b693d 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -920,3 +920,4 @@ void cvar_parse4(string s, __out veci target) { } float servertime; +float special_until; diff --git a/csqc/main.qc b/csqc/main.qc index f25a5d9e..c74966e9 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -140,6 +140,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-rj"); registercommand("slot_a"); + registercommand("special"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); @@ -454,6 +455,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "slot_a": // Alternate between passed options W_ChangeToSlotAlternate(argv(1), argv(2), argv(3), argv(4)); break; + case "special": + special_until = time + 0.150; + break; } return FALSE; @@ -653,6 +657,10 @@ noref void CSQC_Input_Frame() { (input_buttons & BUTTON4)) input_buttons |= BUTTON0 | BUTTON2; + // Set +special when special used + if (time < special_until) + input_buttons |= BUTTON3; + // Handle zoom float prev_zoomed_in = zoomed_in; if (WP_PlayerClass() == PC_SNIPER) diff --git a/share/defs.h b/share/defs.h index 414687d7..32098f40 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1574,7 +1574,7 @@ TFAlias client_aliases[] = { {"dropflag", TF_DROPFLAG}, {"dropitems", TF_DROPFLAG}, {"showloc", TF_DISPLAYLOCATION}, - {"special", TF_SPECIAL_SKILL}, + /* {"special", TF_SPECIAL_SKILL}, */ {"special2", TF_SPECIAL_SKILL_2}, {"saveme", TF_MEDIC_HELPME}, {"discard", TF_DISCARD}, From 470179b5e1e147f175925060820b6826e7924b61 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Mar 2024 09:58:46 -0700 Subject: [PATCH 2355/2474] teamplay: add message on strip and remove primed grenades --- ssqc/teamplay.qc | 9 +++++++++ ssqc/tfort.qc | 22 ++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ssqc/teamplay.qc b/ssqc/teamplay.qc index ba29fa91..288f4f4a 100644 --- a/ssqc/teamplay.qc +++ b/ssqc/teamplay.qc @@ -37,6 +37,8 @@ static void ApplyRadius(vector org, float rad, player_filter_fn, player_apply_fn, other_filter_fn, other_apply_fn); } +void RemovePrimedGrenades(entity player); + static void EffStrip(entity player) { player.ammo_cells = 0; player.ammo_rockets = 0; @@ -45,6 +47,13 @@ static void EffStrip(entity player) { player.no_grenades_1 = player.no_grenades_2 = 0; player.current_slot = player.queue_slot = MakeSlot(4); + + RemovePrimedGrenades(player); + + string msg = "The enemy captured! You are afflicted by the Curse of Isma!"; + stuffcmd(player, "bf\n"); + sprint(player, PRINT_HIGH, msg, "\n"); + centerprint(player, msg); } float IsEngEnt(entity ent); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 1ece31c5..2423a696 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -133,15 +133,21 @@ void () RemoveAutoIdTimer = { } }; +void RemovePrimedGrenades(entity player) { + entity* ents; + int count; + + ents = find_list(classname, "primetimer", EV_STRING, count); + for (int i = 0; i < count; i++) + if (ents[i].owner == player) + dremove(ents[i]); + + player.tfstate &= ~(TFSTATE_GREN1_PRIMED | TFSTATE_GREN2_PRIMED); +} + void () RemovePrimeTimers = { - if (!drop_grenades) { - local entity te = find(world, classname, "primetimer"); - while (te != world) { - if (te.owner == self) - dremove(te); - te = find(te, classname, "primetimer"); - } - } + if (!drop_grenades) + RemovePrimedGrenades(self); }; void () RemoveGasTimers = { From bf74d46769540076f5221b916e035e6ac8d8e067 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Mar 2024 13:33:14 -0700 Subject: [PATCH 2356/2474] pmove: fix maxspeed was using if (function_ptr) [always true] instead of calling function --- csqc/pmove.qc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index ba48f5f4..e23a9da5 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -872,12 +872,7 @@ void PM_InputFrame() { float iz = input_movevalues.z; input_movevalues.z = 0; - float max_speed; - if (isdemo) { - max_speed = SPEC_MAXSPEED; - } else { - max_speed = pstate_pred.csqc_maxspeed; - } + float max_speed = isdemo() ? SPEC_MAXSPEED : pstate_pred.csqc_maxspeed; #if 0 // Quick fix // cl_smartjump replacement From 2dfdd860e037180fc9aa6e342fd99cd5df7504db Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 20 Mar 2024 06:51:38 +1100 Subject: [PATCH 2357/2474] Revert "core: make special act like +special" This reverts commit b411bf41c034324ba0cc311934f3bb3920abd57f. --- csqc/csextradefs.qc | 1 - csqc/main.qc | 8 -------- share/defs.h | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 002b693d..6aff7a82 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -920,4 +920,3 @@ void cvar_parse4(string s, __out veci target) { } float servertime; -float special_until; diff --git a/csqc/main.qc b/csqc/main.qc index c74966e9..f25a5d9e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -140,7 +140,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("-rj"); registercommand("slot_a"); - registercommand("special"); registercommand("+fo_showscores"); registercommand("-fo_showscores"); @@ -455,9 +454,6 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "slot_a": // Alternate between passed options W_ChangeToSlotAlternate(argv(1), argv(2), argv(3), argv(4)); break; - case "special": - special_until = time + 0.150; - break; } return FALSE; @@ -657,10 +653,6 @@ noref void CSQC_Input_Frame() { (input_buttons & BUTTON4)) input_buttons |= BUTTON0 | BUTTON2; - // Set +special when special used - if (time < special_until) - input_buttons |= BUTTON3; - // Handle zoom float prev_zoomed_in = zoomed_in; if (WP_PlayerClass() == PC_SNIPER) diff --git a/share/defs.h b/share/defs.h index 32098f40..414687d7 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1574,7 +1574,7 @@ TFAlias client_aliases[] = { {"dropflag", TF_DROPFLAG}, {"dropitems", TF_DROPFLAG}, {"showloc", TF_DISPLAYLOCATION}, - /* {"special", TF_SPECIAL_SKILL}, */ + {"special", TF_SPECIAL_SKILL}, {"special2", TF_SPECIAL_SKILL_2}, {"saveme", TF_MEDIC_HELPME}, {"discard", TF_DISCARD}, From e06d9f0af385240ec2cea5e82fb72ae8e384ba55 Mon Sep 17 00:00:00 2001 From: newby Date: Mon, 18 Mar 2024 13:33:14 -0700 Subject: [PATCH 2358/2474] pmove: fix maxspeed was using if (function_ptr) [always true] instead of calling function --- csqc/pmove.qc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index ba48f5f4..e23a9da5 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -872,12 +872,7 @@ void PM_InputFrame() { float iz = input_movevalues.z; input_movevalues.z = 0; - float max_speed; - if (isdemo) { - max_speed = SPEC_MAXSPEED; - } else { - max_speed = pstate_pred.csqc_maxspeed; - } + float max_speed = isdemo() ? SPEC_MAXSPEED : pstate_pred.csqc_maxspeed; #if 0 // Quick fix // cl_smartjump replacement From c1a10b36bea450fa9c0363eb74903d025bf21cdb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 7 Apr 2024 20:08:31 +1000 Subject: [PATCH 2359/2474] Add play to completion admin option --- README.md | 1 + csqc/csextradefs.qc | 1 + csqc/events.qc | 1 + csqc/menu.qc | 28 +++++++++++++++++++++++++--- ssqc/client.qc | 3 +++ ssqc/commands.qc | 8 ++++++++ ssqc/csmenu.qc | 8 +++++--- ssqc/quadmode.qc | 2 +- ssqc/qw.qc | 1 + 9 files changed, 46 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f720e71f..506f3b04 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * Website backend for match results, stats. Get a token at fortressone.org, connect to a FortressOne server, and `login `. +* `localinfo play_to_completion 0` set to 1 to allow quad to continue to round end even after required score exceeded. * `localinfo pipecooldown_time ` time in seconds for demo pipe cooldown * `localinfo allpipes_cooldown on/off` whether cooldown is applied to individual pipes or all pipes. i.e. with this on the demo can not det any of his pipes immediately after firing. (default off) * `localinfo discord_channel_id ` to specify discord_channel. Required for autoreporting. diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 6aff7a82..e9027f88 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -333,6 +333,7 @@ typedef struct { float quad_round_time; float fo_login_required; float fo_matchrated; + float play_to_completion; float captainmode; float timelimit; float fraglimit; diff --git a/csqc/events.qc b/csqc/events.qc index fb1fc752..ce995b99 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -267,6 +267,7 @@ void() CSQC_Parse_Event = { SERVER_ADMIN.quad_round_time = readfloat(); SERVER_ADMIN.fo_login_required = readfloat(); SERVER_ADMIN.fo_matchrated = readfloat(); + SERVER_ADMIN.play_to_completion = readfloat(); SERVER_ADMIN.timelimit = readfloat(); SERVER_ADMIN.fraglimit = readfloat(); SERVER_ADMIN.clanmode = readfloat(); diff --git a/csqc/menu.qc b/csqc/menu.qc index 2f746daa..17b341d2 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -7,6 +7,7 @@ void (float force) FO_Menu_Admin_Timelimit; void (float force) FO_Menu_Admin_Fraglimit; void (float force) FO_Menu_Admin_QuadTimelimit; void (float force) FO_Menu_Admin_FoMatchRated; +void (float force) FO_Menu_Admin_PlayToCompletion; void (float force) FO_Menu_Admin_NewBalance; void (float force) FO_Menu_Spy; void (float force) FO_Menu_Spy_Skin; @@ -443,6 +444,7 @@ var fo_menu FO_MENU_ADMIN_MODES = { {"7","Rated/Unrated","","Will player ratings be affected?",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_FoMatchRated(TRUE);},MENU_BORDER_WARNING}, {"8","New Balance","","New Balance Test",FO_MENU_STATE_NORMAL,{localcmd("cmd new_balance");},MENU_BORDER_WARNING}, {"9","Force Start","","Skip prematch and start the game\nPlease use sparingly",FO_MENU_STATE_NORMAL,{localcmd("cmd forcestart\n");},MENU_BORDER_WARNING}, + MenuSpacer, {"0","Close Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, {"+","Next - Settings","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Settings(TRUE);},MENU_BUTTON}, {"-","Prev - Main","","",FO_MENU_STATE_NORMAL,{Menu_Cancel(); FO_Menu_Admin_Main(TRUE);},MENU_BUTTON}, @@ -463,9 +465,7 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { {"2","Fraglimit","","",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Fraglimit(TRUE);},MENU_BORDER_WARNING}, {"3","Quad Rounds...","","Number of rounds in Quad mode. Usually 2",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_Rounds(TRUE);},MENU_BORDER_WARNING}, {"4","Quad Round Time...","","Round time for each quad round",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_QuadTimelimit(TRUE);},MENU_BORDER_WARNING}, - MenuSpacer, - MenuSpacer, - MenuSpacer, + {"5","Play To Completion","","Play match to end of round even if result decided",FO_MENU_STATE_NORMAL,{FO_Menu_Admin_PlayToCompletion(TRUE);},MENU_BORDER_WARNING}, MenuSpacer, MenuSpacer, MenuSpacer, @@ -479,6 +479,7 @@ var fo_menu FO_MENU_ADMIN_SETTINGS = { FO_MENU_ADMIN_SETTINGS.options[1].value = ftos(SERVER_ADMIN.fraglimit); FO_MENU_ADMIN_SETTINGS.options[2].value = ftos(SERVER_ADMIN.quad_rounds); FO_MENU_ADMIN_SETTINGS.options[3].value = ftos(SERVER_ADMIN.quad_round_time); + FO_MENU_ADMIN_SETTINGS.options[4].value = modeStatus(SERVER_ADMIN.play_to_completion); } }; var void execute_admin_players(float choice, float page) { @@ -620,6 +621,20 @@ var fo_menu FO_MENU_ADMIN_QUAD_TIMELIMIT = { {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, }, 11, TRUE }; +var fo_menu FO_MENU_ADMIN_PLAY_TO_COMPLETION = { + [0,0], [300,200], "Play to completion?", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { + {"1","No","","Match will end as soon as the winner is known",FO_MENU_STATE_NORMAL,{localcmd("cmd play_to_completion 0\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + {"2","Yes","","Match will end at the end of the final round",FO_MENU_STATE_NORMAL,{localcmd("cmd play_to_completion 1\n");FO_Menu_Admin_Settings(TRUE);},MENU_BORDER_WARNING}, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + MenuSpacer, + {"0","Back to Main Menu","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();FO_Menu_Admin_Modes(TRUE);},MENU_BUTTON}, + }, 10, TRUE +}; var fo_menu FO_MENU_ADMIN_MATCH_RATED = { [0,0], [300,200], "Match Rated?", FO_MENU_FLAG_USE_MOUSE | FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS | FO_MENU_FLAG_SHOW_VALUES | FO_MENU_FLAG_WARNING | FO_MENU_FLAG_ALLOW_INTERMISSION, { {"1","Rated","","Match result will affect player ratings",FO_MENU_STATE_NORMAL,{localcmd("cmd fo_matchrated 1\n");FO_Menu_Admin_Modes(TRUE);},MENU_BORDER_WARNING}, @@ -1215,6 +1230,12 @@ void FO_Menu_Admin_QuadTimelimit(float force) = { CurrentMenu = &FO_MENU_ADMIN_QUAD_TIMELIMIT; fo_hud_menu_active = TRUE; } +void FO_Menu_Admin_PlayToCompletion(float force) = { + if(fo_hud_menu_active && !force) + return; + CurrentMenu = &FO_MENU_ADMIN_PLAY_TO_COMPLETION; + fo_hud_menu_active = TRUE; +} void FO_Menu_Admin_FoMatchRated(float force) = { if(fo_hud_menu_active && !force) return; @@ -1401,6 +1422,7 @@ void FO_Hud_Init() { INIT_MENU_IDS(FO_MENU_ADMIN_ROUNDS); INIT_MENU_IDS(FO_MENU_ADMIN_QUAD_TIMELIMIT); INIT_MENU_IDS(FO_MENU_ADMIN_MATCH_RATED); + INIT_MENU_IDS(FO_MENU_ADMIN_PLAY_TO_COMPLETION); INIT_MENU_IDS(FO_MENU_ADMIN_TIMELIMIT); INIT_MENU_IDS(FO_MENU_ADMIN_FRAGLIMIT); INIT_MENU_IDS(FO_MENU_VOTE); diff --git a/ssqc/client.qc b/ssqc/client.qc index 5d12ebbb..38f61bfc 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -779,6 +779,9 @@ void () DecodeLevelParms = { map_restart_time = CF_GetSetting("map_restart_Time", "mrt", "120"); + // if 1, quad round will not finish immediately if result is determined [off] + play_to_completion = CF_GetSetting("ptc", "play_to_completion", "0"); + // enforces login loginRequired = CF_GetSetting("loginrequired", "logreq", "0"); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 2cbcbf7d..a0e9451e 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1296,6 +1296,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { UpdateAllAdmins(); } break; + case "play_to_completion": + if(arg2 != "0" && arg2 != "1") + return; + + processedCmd = TRUE; + localcmd ("localinfo play_to_completion ",arg2,"\n"); + UpdateAllAdmins(); + break; case "captainmode": processedCmd = TRUE; if(arg2 && arg3) { diff --git a/ssqc/csmenu.qc b/ssqc/csmenu.qc index 7f9988bc..9d1816a7 100644 --- a/ssqc/csmenu.qc +++ b/ssqc/csmenu.qc @@ -168,10 +168,11 @@ void Update_ServerAdminInfo(entity pl) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; - local float cm = CF_GetSetting("c", "clan", "off"), - qm = CF_GetSetting("quadmode", "quadmode", "off"), + local float cm = CF_GetSetting("c", "clan", "off"), + qm = CF_GetSetting("quadmode", "quadmode", "off"), dm = CF_GetSetting("duelmode", "duelmode", "off"), - flr = CF_GetSetting("flr", "fologinrequired", "off"); + flr = CF_GetSetting("flr", "fologinrequired", "off"), + ptc = CF_GetSetting("ptc", "play_to_completion", "off"); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_SERVER_ADMIN_INFO); WriteByte(MSG_MULTICAST, is_paused || cease_fire); @@ -179,6 +180,7 @@ void Update_ServerAdminInfo(entity pl) = { WriteFloat(MSG_MULTICAST, infokeyf(world, "round_time")); WriteFloat(MSG_MULTICAST, (fo_login_required?1:0) + (flr?2:0)); WriteFloat(MSG_MULTICAST, CF_GetSetting("mra", "fo_matchrated", "2")); + WriteFloat(MSG_MULTICAST, (play_to_completion?1:0) + (ptc?2:0)); WriteFloat(MSG_MULTICAST, infokeyf(world, "timelimit")); WriteFloat(MSG_MULTICAST, infokeyf(world, "fraglimit")); WriteFloat(MSG_MULTICAST, (clanbattle?1:0) + (cm?2:0)); diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 4e4be652..1e430e87 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -388,7 +388,7 @@ void () QuadRoundThink = { local float fl; if (rounds < 2) { - if (CheckWinningTeam() != 0) { + if (CheckWinningTeam() != 0 && !play_to_completion) { if (quad_winner != CheckWinningTeam()) { quad_winner = CheckWinningTeam(); self.think = QuadRoundOver; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 01778f4f..07600659 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -470,6 +470,7 @@ float round_delay_time; float round_start_time; float round_end_time; float map_restart_time; +float play_to_completion; float gametime; float is_countdown; float duelmode; From 43959924f2a53fc665258cc74737239dae23409a Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 18 Apr 2024 22:44:01 +1000 Subject: [PATCH 2360/2474] Fix new_balance Undo Cap strip, Med Cuss duration and Med Speed cap changes --- ssqc/client.qc | 4 ++-- ssqc/scout.qc | 4 ++-- ssqc/teamplay.qc | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 6a926519..81841cb3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -259,8 +259,8 @@ void ActivateOrgGame() { PC_PYRO_AIRBLAST_COOLDOWN = 10; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; - float use_new_cap = CF_GetSetting("nbcc", "new_balance_conc_cap", "4"); - if (use_new_cap == 4 && ServerRegion() == kRegionOCE) + float use_new_cap = CF_GetSetting("nbcc", "new_balance_conc_cap", "0"); + if (use_new_cap == 4) use_new_cap = 1; else use_new_cap = 0; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index aa2957b5..019979b1 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -830,8 +830,8 @@ void (entity inflictor, entity attacker, float bounce, local entity te; local vector org; - if (NewBalanceActive() && inflictor.owner.playerclass == PC_MEDIC) - actual_cuss_time = 2; + //if (NewBalanceActive() && inflictor.owner.playerclass == PC_MEDIC) + // actual_cuss_time = 2; head = findradius(inflictor.origin, bounce + 40); while (head) { diff --git a/ssqc/teamplay.qc b/ssqc/teamplay.qc index 288f4f4a..bbdddf7e 100644 --- a/ssqc/teamplay.qc +++ b/ssqc/teamplay.qc @@ -97,7 +97,7 @@ void TeamPlay_Cap(vector origin, entity player) { if (!org_game || !new_balance) return; - ApplyRadius(origin, 1500, - FilTeamNEQ[player.team_no - 1], EffStrip, - FilOwnerTeamNEQ[player.team_no - 1], EffRemove); + //ApplyRadius(origin, 1500, + // FilTeamNEQ[player.team_no - 1], EffStrip, + // FilOwnerTeamNEQ[player.team_no - 1], EffRemove); } From bc0a51616bce06865db220a6d46a7490c30200a6 Mon Sep 17 00:00:00 2001 From: haze-au <91508911+haze-au@users.noreply.github.com> Date: Thu, 18 Apr 2024 22:49:12 +1000 Subject: [PATCH 2361/2474] Comment out effstrip - unused --- ssqc/teamplay.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/teamplay.qc b/ssqc/teamplay.qc index bbdddf7e..c3dbab63 100644 --- a/ssqc/teamplay.qc +++ b/ssqc/teamplay.qc @@ -39,6 +39,7 @@ static void ApplyRadius(vector org, float rad, void RemovePrimedGrenades(entity player); +/* Disabled new-balance remove chaser ammo mechanic static void EffStrip(entity player) { player.ammo_cells = 0; player.ammo_rockets = 0; @@ -54,7 +55,7 @@ static void EffStrip(entity player) { stuffcmd(player, "bf\n"); sprint(player, PRINT_HIGH, msg, "\n"); centerprint(player, msg); -} +}*/ float IsEngEnt(entity ent); void RemoveEngEnt(entity bld, float explode); From e289d2f52bb8530895a4a4f7e9f9a5c58a2d793e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 20 Apr 2024 22:15:37 +1000 Subject: [PATCH 2362/2474] Fix broken max_gren1_engineer setting --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 81841cb3..3f5074a7 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -719,7 +719,7 @@ void () DecodeLevelParms = { Role_None.gren1_limits[6] = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); Role_None.gren1_limits[7] = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); Role_None.gren1_limits[8] = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); - Role_None.gren1_limits[9] = CF_GetSetting("mg2_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); + Role_None.gren1_limits[9] = CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); // Maximum number of secondary grenades per class Role_None.gren2_limits[1] = CF_GetSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); From f565a797ae41dfc25c4c44e55cc9834c4976f2c2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 20 Apr 2024 22:22:29 +1000 Subject: [PATCH 2363/2474] Honour server max gren config --- ssqc/client.qc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 3f5074a7..1f8db602 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -250,11 +250,11 @@ void ActivateOrgGame() { for (i = 1; i <= 9; i++) // 3 gren spawn SetAllRoles(i, 1, 3); - SetAllRoles(4, 2, 1); // 1 mirv for demoman - SetAllRoles(6, 2, 1); // 1 mirv for hwguy - SetAllRoles(9, 2, 1); // 1 emp for engineer - SetAllRoles(9, 1, 4); // 4 gren1 for engineer - SetAllRoles(3, 1, 4); // 4 gren1 for soldier + SetAllRoles(4, 2, CF_GetSetting("mg2_4", "max_gren2_demoman", ftos(1))); // 1 mirv for demoman + SetAllRoles(6, 2, CF_GetSetting("mg2_6", "max_gren2_hwguy", ftos(1))); // 1 mirv for hwguy + SetAllRoles(9, 2, CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(1))); // 1 emp for engineer + SetAllRoles(9, 1, CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(4))); // 4 gren1 for engineer + SetAllRoles(3, 1, CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(4))); // 4 gren1 for soldier PC_PYRO_AIRBLAST_COOLDOWN = 10; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; @@ -712,14 +712,14 @@ void () DecodeLevelParms = { */ Role_None.gren1_limits[0] = 0; Role_None.gren1_limits[1] = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); - Role_None.gren1_limits[2] = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); - Role_None.gren1_limits[3] = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); - Role_None.gren1_limits[4] = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); - Role_None.gren1_limits[5] = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); - Role_None.gren1_limits[6] = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); - Role_None.gren1_limits[7] = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); - Role_None.gren1_limits[8] = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); - Role_None.gren1_limits[9] = CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); + Role_None.gren1_limits[2] = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); + Role_None.gren1_limits[3] = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); + Role_None.gren1_limits[4] = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); + Role_None.gren1_limits[5] = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); + Role_None.gren1_limits[6] = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); + Role_None.gren1_limits[7] = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); + Role_None.gren1_limits[8] = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); + Role_None.gren1_limits[9] = CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); // Maximum number of secondary grenades per class Role_None.gren2_limits[1] = CF_GetSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); From 28efcc04cfaf2a9e8187304a9f997b10296d94bc Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 22 Apr 2024 20:08:15 +1000 Subject: [PATCH 2364/2474] Move defaults from last four years server config to code --- share/defs.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/share/defs.h b/share/defs.h index 414687d7..5ad54854 100644 --- a/share/defs.h +++ b/share/defs.h @@ -976,7 +976,7 @@ enum { #define PC_DEMOMAN_GRENADE_INIT_1 4 #define PC_DEMOMAN_GRENADE_INIT_2 4 #define PC_DEMOMAN_GRENADE_MAX_1 4 -#define PC_DEMOMAN_GRENADE_MAX_2 4 +#define PC_DEMOMAN_GRENADE_MAX_2 1 #define PC_DEMOMAN_TF_ITEMS 0 // Class Details for COMBAT MEDIC @@ -1003,7 +1003,7 @@ enum { #define PC_MEDIC_GRENADE_INIT_1 3 #define PC_MEDIC_GRENADE_INIT_2 3 #define PC_MEDIC_GRENADE_MAX_1 4 -#define PC_MEDIC_GRENADE_MAX_2 3 +#define PC_MEDIC_GRENADE_MAX_2 2 #define PC_MEDIC_TF_ITEMS 0 #define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. #define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. @@ -1043,7 +1043,6 @@ enum { #define PC_HVYWEAP_TF_ITEMS 0 #define PC_HVYWEAP_CELL_FIRE 7 - // Class Details for PYRO #define PC_PYRO_SKIN 21 #define PC_PYRO_MAXHEALTH 100 @@ -1065,7 +1064,7 @@ enum { #define PC_PYRO_GRENADE_INIT_1 1 #define PC_PYRO_GRENADE_INIT_2 4 #define PC_PYRO_GRENADE_MAX_1 4 -#define PC_PYRO_GRENADE_MAX_2 4 +#define PC_PYRO_GRENADE_MAX_2 1 #define PC_PYRO_TF_ITEMS 0 #define PC_PYRO_AIRBLAST_RANGE 400 #define PC_PYRO_AIRBLAST_CELLS 55 @@ -1100,7 +1099,7 @@ enum { #define PC_SPY_GRENADE_INIT_1 2 #define PC_SPY_GRENADE_INIT_2 2 #define PC_SPY_GRENADE_MAX_1 4 -#define PC_SPY_GRENADE_MAX_2 2 +#define PC_SPY_GRENADE_MAX_2 1 #define PC_SPY_TF_ITEMS 0 #define PC_SPY_CELL_REGEN_TIME 5 #define PC_SPY_CELL_REGEN_AMOUNT 1 @@ -1129,7 +1128,7 @@ enum { #define PC_ENGINEER_GRENADE_INIT_1 2 #define PC_ENGINEER_GRENADE_INIT_2 2 #define PC_ENGINEER_GRENADE_MAX_1 4 -#define PC_ENGINEER_GRENADE_MAX_2 4 +#define PC_ENGINEER_GRENADE_MAX_2 2 #define PC_ENGINEER_TF_ITEMS 0 #define PC_ENGINEER_RAILSPEED 1500 From 2fdbecd494a07b9e4eb2eba9556663863035bd73 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 22 Apr 2024 22:08:36 +1000 Subject: [PATCH 2365/2474] Clean up max gren logic --- ssqc/client.qc | 58 +++++++++++++++++++++++++++++++++----------------- ssqc/qw.qc | 20 ----------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 1f8db602..c266d403 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -223,13 +223,45 @@ void InitPrematch() } } +typedef struct { + int player_class; + string short_max_gren1; + string setting_max_gren1; + float default_max_gren1; + string short_max_gren2; + string setting_max_gren2; + float default_max_gren2; +} GrenConfig; + +GrenConfig GrenConfigs[10] = { + {0, "", "", 0, "", "", 0}, + {1, "mg1_1", "max_gren1_scout", PC_SCOUT_GRENADE_MAX_1, "mg2_1", "max_gren2_scout", PC_SCOUT_GRENADE_MAX_2}, + {2, "mg1_2", "max_gren1_sniper", PC_SNIPER_GRENADE_MAX_1, "mg2_2", "max_gren2_sniper", PC_SNIPER_GRENADE_MAX_2}, + {3, "mg1_3", "max_gren1_soldier", PC_SOLDIER_GRENADE_MAX_1, "mg2_3", "max_gren2_soldier", PC_SOLDIER_GRENADE_MAX_2}, + {4, "mg1_4", "max_gren1_demoman", PC_DEMOMAN_GRENADE_MAX_1, "mg2_4", "max_gren2_demoman", PC_DEMOMAN_GRENADE_MAX_2}, + {5, "mg1_5", "max_gren1_medic", PC_MEDIC_GRENADE_MAX_1, "mg2_5", "max_gren2_medic", PC_MEDIC_GRENADE_MAX_2}, + {6, "mg1_6", "max_gren1_hwguy", PC_HVYWEAP_GRENADE_MAX_1, "mg2_6", "max_gren2_hwguy", PC_HVYWEAP_GRENADE_MAX_2}, + {7, "mg1_7", "max_gren1_pyro", PC_PYRO_GRENADE_MAX_1, "mg2_7", "max_gren2_pyro", PC_PYRO_GRENADE_MAX_2}, + {8, "mg1_8", "max_gren1_spy", PC_SPY_GRENADE_MAX_1, "mg2_8", "max_gren2_spy", PC_SPY_GRENADE_MAX_2}, + {9, "mg1_9", "max_gren1_engineer", PC_ENGINEER_GRENADE_MAX_1, "mg2_9", "max_gren2_engineer", PC_ENGINEER_GRENADE_MAX_2} +}; + static void SetAllRoles(float pc, float gren, float limit) { - if (gren == 1) + if (pc < 1 || pc > 9) return; + + GrenConfig config = GrenConfigs[pc]; + + if (gren == 1) { + limit = CF_GetSetting(config.short_max_gren1, config.setting_max_gren1, ftos(limit)); + Role_None.gren1_limits[pc] = Role_Attack.gren1_limits[pc] = Role_Defence.gren1_limits[pc] = limit; - else + } else if (gren == 2) { + limit = CF_GetSetting(config.short_max_gren2, config.setting_max_gren2, ftos(limit)); + Role_None.gren2_limits[pc] = Role_Attack.gren2_limits[pc] = Role_Defence.gren2_limits[pc] = limit; + } } static float NB_UseMinPing() { @@ -250,11 +282,11 @@ void ActivateOrgGame() { for (i = 1; i <= 9; i++) // 3 gren spawn SetAllRoles(i, 1, 3); - SetAllRoles(4, 2, CF_GetSetting("mg2_4", "max_gren2_demoman", ftos(1))); // 1 mirv for demoman - SetAllRoles(6, 2, CF_GetSetting("mg2_6", "max_gren2_hwguy", ftos(1))); // 1 mirv for hwguy - SetAllRoles(9, 2, CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(1))); // 1 emp for engineer - SetAllRoles(9, 1, CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(4))); // 4 gren1 for engineer - SetAllRoles(3, 1, CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(4))); // 4 gren1 for soldier + SetAllRoles(4, 2, 1); // 1 mirv for demoman + SetAllRoles(6, 2, 1); // 1 mirv for hwguy + SetAllRoles(9, 2, 1); // 1 emp for engineer + SetAllRoles(9, 1, 4); // 4 gren1 for engineer + SetAllRoles(3, 1, 4); // 4 gren1 for soldier PC_PYRO_AIRBLAST_COOLDOWN = 10; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; @@ -698,18 +730,6 @@ void () DecodeLevelParms = { // override map-set class restrictions [off] override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); - // Maximum number of primary grenades per class - /* - max_gren1_scout = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); - max_gren1_sniper = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); - max_gren1_soldier = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); - max_gren1_demoman = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); - max_gren1_medic = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); - max_gren1_hwguy = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); - max_gren1_pyro = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); - max_gren1_spy = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); - max_gren1_engineer = CF_GetSetting("mg2_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); - */ Role_None.gren1_limits[0] = 0; Role_None.gren1_limits[1] = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); Role_None.gren1_limits[2] = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 1453b2e8..2daccd1c 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -534,26 +534,6 @@ float drop_grenades; float drop_grenpack; float drop_gren1; float drop_gren2; -/* -float max_gren1_scout; -float max_gren1_sniper; -float max_gren1_soldier; -float max_gren1_demoman; -float max_gren1_medic; -float max_gren1_hwguy; -float max_gren1_pyro; -float max_gren1_spy; -float max_gren1_engineer; -float max_gren2_scout; -float max_gren2_sniper; -float max_gren2_soldier; -float max_gren2_demoman; -float max_gren2_medic; -float max_gren2_hwguy; -float max_gren2_pyro; -float max_gren2_spy; -float max_gren2_engineer; -*/ float max_active_gren2_soldier; float id_extended; float remember_weapon; From b38fe0227f045de53b384b16be93abe12d6c6f5a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 23 Apr 2024 23:39:55 +1000 Subject: [PATCH 2366/2474] Support localinfo max grens setting -1 for default --- README.md | 2 +- ssqc/client.qc | 53 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 506f3b04..c97a199b 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * Server option for making all walls block EMP. Off by default. `localinfo walls_block_emp 1` or `localinfo wbe 1`. (SPAWNFLAG_BLOCK_EMP 4096 will work regardless) * Server option for setting detpack to solid (blocking). Off by default. `localinfo solid_detpack 1` or `localinfo sdp 1`. * Server option for overriding map class restrictions (except civilian). `serverinfo override_mapclasses 1` or `serverinfo omc 1`. -* Option for maximum grenades for all classes. `localinfo max_gren1_ `, short `localinfo mg1_ `. Works for gren1s and gren2s. Eg `localinfo max_gren1_scout 0` to remove caltrops or `localinfo mg2_9 2` to reduce max EMPs to 2. +* Option for maximum grenades for all classes. `localinfo max_gren1_ `, short `localinfo mg1_ `. Works for gren1s and gren2s. Eg `localinfo max_gren1_scout 0` to remove caltrops or `localinfo mg2_9 2` to reduce max EMPs to 2. Set to -1 for default. * Option to fully restock player's clip and finish reload immediately if in progress. `localinfo stock_reload 1` (`localinfo srd 1`) will trigger only on flag capture (with stock_on_cap enabled). `2` will trigger whenever any tfgoal gives you the appropriate ammo. * Option for statusbar flaginfo. `setinfo sbflaginfo 1` (default). Setting it to `2` will skip the tf tips on respawn and show flag info all the time. * Admin system created to allow for easy setup of pub/clan/quad/duel games, kick players etc `localinfo adminpwd ` and `cmd adminpwd ; wait; adminmenu` diff --git a/ssqc/client.qc b/ssqc/client.qc index c266d403..e27341c3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -203,6 +203,15 @@ float CF_GetSetting(string ps_short, string ps_setting, string ps_default) { return FO_GetUserSetting(world, ps_short, ps_setting, ps_default); }; +float FO_GetGrenadeSetting(string ps_short, string ps_setting, string ps_default) { + local float max_gren_setting = CF_GetSetting(ps_short, ps_setting, ps_default); + + if (max_gren_setting == -1) + return stof(ps_default); + + return max_gren_setting; +}; + void InitPrematch() { localcmd ("serverinfo status Standby\n"); @@ -252,12 +261,14 @@ static void SetAllRoles(float pc, float gren, float limit) { GrenConfig config = GrenConfigs[pc]; if (gren == 1) { - limit = CF_GetSetting(config.short_max_gren1, config.setting_max_gren1, ftos(limit)); + limit = FO_GetGrenadeSetting(config.short_max_gren1, + config.setting_max_gren1, ftos(limit)); Role_None.gren1_limits[pc] = Role_Attack.gren1_limits[pc] = Role_Defence.gren1_limits[pc] = limit; } else if (gren == 2) { - limit = CF_GetSetting(config.short_max_gren2, config.setting_max_gren2, ftos(limit)); + limit = FO_GetGrenadeSetting(config.short_max_gren2, + config.setting_max_gren2, ftos(limit)); Role_None.gren2_limits[pc] = Role_Attack.gren2_limits[pc] = Role_Defence.gren2_limits[pc] = limit; @@ -730,27 +741,27 @@ void () DecodeLevelParms = { // override map-set class restrictions [off] override_mapclasses = CF_GetSetting("omc", "override_mapclasses", "off"); - Role_None.gren1_limits[0] = 0; - Role_None.gren1_limits[1] = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); - Role_None.gren1_limits[2] = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); - Role_None.gren1_limits[3] = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); - Role_None.gren1_limits[4] = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); - Role_None.gren1_limits[5] = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); - Role_None.gren1_limits[6] = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); - Role_None.gren1_limits[7] = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); - Role_None.gren1_limits[8] = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); - Role_None.gren1_limits[9] = CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); + Role_None.gren1_limits[0] = 0; + Role_None.gren1_limits[1] = FO_GetGrenadeSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); + Role_None.gren1_limits[2] = FO_GetGrenadeSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); + Role_None.gren1_limits[3] = FO_GetGrenadeSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); + Role_None.gren1_limits[4] = FO_GetGrenadeSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); + Role_None.gren1_limits[5] = FO_GetGrenadeSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); + Role_None.gren1_limits[6] = FO_GetGrenadeSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); + Role_None.gren1_limits[7] = FO_GetGrenadeSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); + Role_None.gren1_limits[8] = FO_GetGrenadeSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); + Role_None.gren1_limits[9] = FO_GetGrenadeSetting("mg1_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); // Maximum number of secondary grenades per class - Role_None.gren2_limits[1] = CF_GetSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); - Role_None.gren2_limits[2] = CF_GetSetting("mg2_2", "max_gren2_sniper", ftos(PC_SNIPER_GRENADE_MAX_2)); - Role_None.gren2_limits[3] = CF_GetSetting("mg2_3", "max_gren2_soldier", ftos(PC_SOLDIER_GRENADE_MAX_2)); - Role_None.gren2_limits[4] = CF_GetSetting("mg2_4", "max_gren2_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_2)); - Role_None.gren2_limits[5] = CF_GetSetting("mg2_5", "max_gren2_medic", ftos(PC_MEDIC_GRENADE_MAX_2)); - Role_None.gren2_limits[6] = CF_GetSetting("mg2_6", "max_gren2_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_2)); - Role_None.gren2_limits[7] = CF_GetSetting("mg2_7", "max_gren2_pyro", ftos(PC_PYRO_GRENADE_MAX_2)); - Role_None.gren2_limits[8] = CF_GetSetting("mg2_8", "max_gren2_spy", ftos(PC_SPY_GRENADE_MAX_2)); - Role_None.gren2_limits[9] = CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(PC_ENGINEER_GRENADE_MAX_2)); + Role_None.gren2_limits[1] = FO_GetGrenadeSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); + Role_None.gren2_limits[2] = FO_GetGrenadeSetting("mg2_2", "max_gren2_sniper", ftos(PC_SNIPER_GRENADE_MAX_2)); + Role_None.gren2_limits[3] = FO_GetGrenadeSetting("mg2_3", "max_gren2_soldier", ftos(PC_SOLDIER_GRENADE_MAX_2)); + Role_None.gren2_limits[4] = FO_GetGrenadeSetting("mg2_4", "max_gren2_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_2)); + Role_None.gren2_limits[5] = FO_GetGrenadeSetting("mg2_5", "max_gren2_medic", ftos(PC_MEDIC_GRENADE_MAX_2)); + Role_None.gren2_limits[6] = FO_GetGrenadeSetting("mg2_6", "max_gren2_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_2)); + Role_None.gren2_limits[7] = FO_GetGrenadeSetting("mg2_7", "max_gren2_pyro", ftos(PC_PYRO_GRENADE_MAX_2)); + Role_None.gren2_limits[8] = FO_GetGrenadeSetting("mg2_8", "max_gren2_spy", ftos(PC_SPY_GRENADE_MAX_2)); + Role_None.gren2_limits[9] = FO_GetGrenadeSetting("mg2_9", "max_gren2_engineer", ftos(PC_ENGINEER_GRENADE_MAX_2)); // disable resupply giving grenades (1-bit for gren1, 2-bit for gren2) disable_resup_gren = CF_GetSetting("drg", "disable_resup_gren", "0"); From 8fd378d7210aeb16a16152dfa381500a84b51def Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 25 Apr 2024 10:34:21 +1000 Subject: [PATCH 2367/2474] Put a flag on cap strip --- README.md | 1 + ssqc/client.qc | 10 ++++++++-- ssqc/qw.qc | 1 + ssqc/scout.qc | 3 --- ssqc/teamplay.qc | 11 +++++------ ssqc/tfort.qc | 1 + ssqc/tfortmap.qc | 3 ++- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c97a199b..2fb8efa0 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * Keys and flags glow their colour. * Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime`. * Option to fully restock player on cap. `localinfo stock_on_cap on`. +* Option to strip ammo and grens from defenders within 1500 units of cap point when flag is capped. `localinfo cap_strip 1`. * Option for packs to fully restock health and armor of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. * Map vote (4 random maps + current map) during last few minutes of game (shown for newly spawned or toggled with /togglevote). diff --git a/ssqc/client.qc b/ssqc/client.qc index e27341c3..5854eaa5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -642,13 +642,16 @@ void () DecodeLevelParms = { // stock on cap [on] stock_on_cap = CF_GetSetting("soc", "stock_on_cap", "on"); + // stock on cap [off] + cap_strip = CF_GetSetting("cs", "cap_strip", "off"); + // stock clip to full for reloading guns [on] stock_reload = CF_GetSetting("srd", "stock_reload", "on"); // display class tips [on] classtips = CF_GetSetting("ct", "classtips", "on"); - // concussion grenade effect time [19] + // concussion grenade effect time [10] cussgrentime = CF_GetSetting("cgt", "cussgrentime", "10"); // concussion grenade effect time proportional to distance from explosion @@ -936,6 +939,7 @@ void () DecodeLevelParms = { spawnfull = TRUE; stockfull = TRUE; stock_on_cap = TRUE; + cap_strip = FALSE; stock_reload = TRUE; classtips = TRUE; sniperpower = TRUE; @@ -1004,6 +1008,7 @@ void () DecodeLevelParms = { spawnfull = FALSE; stockfull = FALSE; stock_on_cap = FALSE; + cap_strip = FALSE; stock_reload = FALSE; classtips = FALSE; sniperpower = FALSE; @@ -1068,6 +1073,7 @@ void () DecodeLevelParms = { spawnfull = FALSE; stockfull = FALSE; stock_on_cap = FALSE; + cap_strip = FALSE; stock_reload = FALSE; classtips = FALSE; nohitsounds = TRUE; @@ -1643,7 +1649,7 @@ void () ResetPlayers = { // DuelWin(te); // return; //} - } + } RemovePlayerOwnedEnts(); setspawnparms(self); PutClientInServer(); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 2daccd1c..96e73c72 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -561,6 +561,7 @@ float scoutdash; float spawnfull; float stockfull; float stock_on_cap; +float cap_strip; float stock_reload; float classtips; float cussgrentime; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 019979b1..94b7c5a1 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -830,9 +830,6 @@ void (entity inflictor, entity attacker, float bounce, local entity te; local vector org; - //if (NewBalanceActive() && inflictor.owner.playerclass == PC_MEDIC) - // actual_cuss_time = 2; - head = findradius(inflictor.origin, bounce + 40); while (head) { if (head != ignore) { diff --git a/ssqc/teamplay.qc b/ssqc/teamplay.qc index c3dbab63..05fe9ae7 100644 --- a/ssqc/teamplay.qc +++ b/ssqc/teamplay.qc @@ -39,7 +39,6 @@ static void ApplyRadius(vector org, float rad, void RemovePrimedGrenades(entity player); -/* Disabled new-balance remove chaser ammo mechanic static void EffStrip(entity player) { player.ammo_cells = 0; player.ammo_rockets = 0; @@ -55,7 +54,7 @@ static void EffStrip(entity player) { stuffcmd(player, "bf\n"); sprint(player, PRINT_HIGH, msg, "\n"); centerprint(player, msg); -}*/ +} float IsEngEnt(entity ent); void RemoveEngEnt(entity bld, float explode); @@ -95,10 +94,10 @@ static int(entity p) FilOwnerTeamNEQ[] = { }; void TeamPlay_Cap(vector origin, entity player) { - if (!org_game || !new_balance) + if (!org_game || !new_balance || !cap_strip) return; - //ApplyRadius(origin, 1500, - // FilTeamNEQ[player.team_no - 1], EffStrip, - // FilOwnerTeamNEQ[player.team_no - 1], EffRemove); + ApplyRadius(origin, 1500, + FilTeamNEQ[player.team_no - 1], EffStrip, + FilOwnerTeamNEQ[player.team_no - 1], EffRemove); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 2423a696..359b828d 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -604,6 +604,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Spawn with full health/armor", spawnfull, "", 1); CF_PrintSetting("Stock players with full health/armor", stockfull, "", 1); CF_PrintSetting("Stock player on cap", stock_on_cap, "", 1); + CF_PrintSetting("Strip chasers on cap", cap_strip, "", 1); CF_PrintSetting("Stock reloadable clip", stock_reload, "", 1); CF_PrintSetting("Old dropflag behaviour", old_dropflag, "", 1); CF_PrintSetting("Remember weapon", remember_weapon, "", 1); diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 3a9eed67..7132fe06 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -950,7 +950,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (stock_on_cap) { if (Player == AP) { - TeamPlay_Cap(AP.origin, AP); + if (cap_strip) + TeamPlay_Cap(AP.origin, AP); if (Player.health > 0) { T_Heal(Player, Player.max_health, 0); From 23de49a0d79690aa34f4062ee3b400ef37330aff Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 25 Apr 2024 18:17:04 +1000 Subject: [PATCH 2368/2474] Make a much more obvious flag pick up notification --- csqc/csextradefs.qc | 1 + csqc/events.qc | 3 +++ csqc/status.qc | 20 ++++++++++++++++++++ share/commondefs.qc | 1 + ssqc/status.qc | 10 ++++++++++ ssqc/tfortmap.qc | 4 ++++ ssqc/world.qc | 2 +- 7 files changed, 40 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index e9027f88..1d720191 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -115,6 +115,7 @@ float vote_list_offset; entity current_vote; string vote_list_filter; float zoomed_in; +float pick_up_time; float slot_history[MAX_SLOT_HISTORY_SIZE]; float slot_history_top, slot_under_stack; diff --git a/csqc/events.qc b/csqc/events.qc index ce995b99..f4fafb51 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -355,6 +355,9 @@ void() CSQC_Parse_Event = { local float weapon = readfloat(); FO_ReloadSound(weapon); break; + case MSG_FLAG_PICKUP: + pick_up_time = time; + break; } } diff --git a/csqc/status.qc b/csqc/status.qc index 6999f0d1..84dd7b20 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -606,6 +606,26 @@ void(PanelID panelid, string text) drawReadyPanel = { } } } + } else if (pick_up_time && time < pick_up_time + 1.5) { + local vector alert_text_size = MENU_TEXT_MEDIUM * panel.Scale; + local vector alert_text_position; + alert_text_position.y = ScreenSize.y / 3; + alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); + local string alert_text_message = "You got the flag!"; + + pos_aligned = GetTextAlignOffset( + alert_text_position.x, + size.x, + padding, + alert_text_message, + alert_text_size.x, + panel.Orientation + ); + + HRC_drawstring( + [pos_aligned, alert_text_position.y], + alert_text_message, alert_text_size, MENU_TEXT_GREEN, 1, 0 + ); } } if(message) { diff --git a/share/commondefs.qc b/share/commondefs.qc index ea918842..e85fa2ad 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -213,6 +213,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_LOGIN 26 #define MSG_HITFLAG 27 #define MSG_RELOADSOUND 28 +#define MSG_FLAG_PICKUP 29 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/status.qc b/ssqc/status.qc index 792044dd..4929d9c0 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -964,6 +964,16 @@ void UpdateClientStatusBar(entity pl) multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void (entity pl) UpdateClientFlagPickUp = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAG_PICKUP); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void (entity pl) RefreshStatusBar = { local string pad; local string s1 = ""; // will be used for grenade timers diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 7132fe06..3f0010a9 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2106,7 +2106,9 @@ void () item_tfgoal_touch = { return; if (CTF_Map == 1) { + printf("CTF_Map: %f\n", CTF_Map); if (self.goal_no == 1) { + printf("self.goal_no: %f\n", self.goal_no); if (self.origin != self.oldorigin) { if (other.team_no == 1) { bprint(2, other.netname); @@ -2171,6 +2173,7 @@ void () item_tfgoal_touch = { } } if (Activated(self, other)) { + printf("activated\n"); tfgoalitem_GiveToPlayer(self, other, self); if (other.health > 0) { self.goal_state = 1; @@ -2277,6 +2280,7 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { DoItemGroupWork(Item, AP); AP.goalrunningtime = gametime; AP.has_flag = TRUE; + UpdateClientFlagPickUp(AP); LogEventPickupGoal(AP); }; diff --git a/ssqc/world.qc b/ssqc/world.qc index ab5f5dd4..e194f42a 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -332,7 +332,7 @@ void () worldspawn = { clientstat(STAT_TEAMNO, EV_FLOAT, team_no); clientstat(STAT_ALL_TIME, EV_FLOAT, all_time); clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); - clientstat(STAT_SPAWN_GEN,EV_FLOAT, spawn_gen); + clientstat(STAT_SPAWN_GEN, EV_FLOAT, spawn_gen); globalstat(STAT_ROUND_END, EV_FLOAT, "round_end_time"); globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused"); From e441bb735d552be3cd2eb9efae6f0f74879e03b0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 27 Apr 2024 00:40:06 +1000 Subject: [PATCH 2369/2474] Specify flag colour in pickup notification --- csqc/csextradefs.qc | 1 + csqc/events.qc | 1 + csqc/status.qc | 31 +++++++++++++++++++++++++++++-- ssqc/status.qc | 3 ++- ssqc/tfortmap.qc | 2 +- 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1d720191..35870090 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -116,6 +116,7 @@ entity current_vote; string vote_list_filter; float zoomed_in; float pick_up_time; +float flag_team; float slot_history[MAX_SLOT_HISTORY_SIZE]; float slot_history_top, slot_under_stack; diff --git a/csqc/events.qc b/csqc/events.qc index f4fafb51..b15e7733 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -356,6 +356,7 @@ void() CSQC_Parse_Event = { FO_ReloadSound(weapon); break; case MSG_FLAG_PICKUP: + flag_team = readfloat(); pick_up_time = time; break; } diff --git a/csqc/status.qc b/csqc/status.qc index 84dd7b20..5f2567c9 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -611,7 +611,34 @@ void(PanelID panelid, string text) drawReadyPanel = { local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); - local string alert_text_message = "You got the flag!"; + + local string flag_team_str; + local vector menu_text_color; + + switch(flag_team) { + case 1: + flag_team_str = "blue's"; + menu_text_color = MENU_TEXT_BLUE_FO; + break; + case 2: + flag_team_str = "red's"; + menu_text_color = MENU_TEXT_RED_FO; + break; + case 3: + flag_team_str = "yellow's"; + menu_text_color = MENU_TEXT_YELLOW_FO; + break; + case 4: + flag_team_str = "green's"; + menu_text_color = MENU_TEXT_GREEN_FO; + break; + default: + flag_team_str = "the"; + menu_text_color = MENU_TEXT_4; + break; + } + + local string alert_text_message = sprintf("You got %s flag!", flag_team_str); pos_aligned = GetTextAlignOffset( alert_text_position.x, @@ -624,7 +651,7 @@ void(PanelID panelid, string text) drawReadyPanel = { HRC_drawstring( [pos_aligned, alert_text_position.y], - alert_text_message, alert_text_size, MENU_TEXT_GREEN, 1, 0 + alert_text_message, alert_text_size, menu_text_color, 1, 0 ); } } diff --git a/ssqc/status.qc b/ssqc/status.qc index 4929d9c0..19d40cf9 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -964,13 +964,14 @@ void UpdateClientStatusBar(entity pl) multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -void (entity pl) UpdateClientFlagPickUp = { +void (entity pl, float flag_team) UpdateClientFlagPickUp = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_FLAG_PICKUP); + WriteFloat(MSG_MULTICAST, flag_team); multicast('0 0 0', MULTICAST_ONE_NOSPECS); } diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 3f0010a9..b066fa73 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2280,7 +2280,7 @@ void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer = { DoItemGroupWork(Item, AP); AP.goalrunningtime = gametime; AP.has_flag = TRUE; - UpdateClientFlagPickUp(AP); + UpdateClientFlagPickUp(AP, Item.skin); LogEventPickupGoal(AP); }; From 875623795b6b4325a4771013c31e54824a7a2bf9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 27 Apr 2024 00:48:08 +1000 Subject: [PATCH 2370/2474] Rename ready panel to notification panel --- csqc/csextradefs.qc | 2 +- csqc/hud.qc | 2 +- csqc/hud_helpers.qc | 2 +- csqc/status.qc | 6 +++--- share/defs.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 35870090..1e4db845 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -414,7 +414,7 @@ enum PanelID:float { HUDP_GRENTIMER, HUDP_MOTD, HUDP_GAME_MODE, - HUDP_READY, + HUDP_NOTIFICATION, HUDP_HEALTH, HUDP_FACE, HUDP_AMMO, diff --git a/csqc/hud.qc b/csqc/hud.qc index 94d154d3..01dd92bb 100644 --- a/csqc/hud.qc +++ b/csqc/hud.qc @@ -26,7 +26,7 @@ void FO_Hud_Editor_LoadDefaultSettings() getHudPanel(HUDP_GAME_MODE)->Position = [width - getHudPanel(HUDP_GAME_MODE)->FillSize.x, 30]; getHudPanel(HUDP_GAME_MODE)->Orientation = FO_HUD_INSERT_AFTER; getHudPanel(HUDP_MOTD)->Position = [(width / 2) - (getHudPanel(HUDP_MOTD)->FillSize.x / 2), 30]; - getHudPanel(HUDP_READY)->Position = [(width / 2) - (getHudPanel(HUDP_READY)->FillSize.x / 2), 30]; + getHudPanel(HUDP_NOTIFICATION)->Position = [(width / 2) - (getHudPanel(HUDP_NOTIFICATION)->FillSize.x / 2), 30]; getHudPanel(HUDP_MENU_HINT)->Position = [(width / 2) - (getHudPanel(HUDP_MENU)->FillSize.x / 2), 80]; getHudPanel(HUDP_MENU_HINT)->Orientation = FO_HUD_INSERT_MIDDLE; getHudPanel(HUDP_MENU)->Position = [(width / 2) - (getHudPanel(HUDP_MENU)->FillSize.x / 2), 120]; diff --git a/csqc/hud_helpers.qc b/csqc/hud_helpers.qc index 7f7afc23..fab0a72e 100644 --- a/csqc/hud_helpers.qc +++ b/csqc/hud_helpers.qc @@ -257,7 +257,7 @@ void FO_Hud_InitSystemPanels() { if (panel->System) { switch (panel->id) { case HUDP_MOTD: - case HUDP_READY: + case HUDP_NOTIFICATION: FO_Hud_ShowPanel(i); break; diff --git a/csqc/status.qc b/csqc/status.qc index 5f2567c9..3a119672 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -508,7 +508,7 @@ void(PanelID panelid, string text) drawGameModePanel = { } } -void(PanelID panelid, string text) drawReadyPanel = { +void(PanelID panelid, string text) drawNotificationPanel = { FO_Hud_Panel* panel = getHudPanel(panelid); vector position = getPanelPosition(panel); @@ -520,7 +520,7 @@ void(PanelID panelid, string text) drawReadyPanel = { local float pos_aligned; local string message = ""; if (fo_hud_editor) { - message = "Ready Status"; + message = "Notification panel"; if (hud_panel(panelid, position, size, 0.3, panel.Display)) { // click event } @@ -1157,7 +1157,7 @@ var FO_Hud_Panel Hud_Panels[] = { {HUDP_GRENTIMER, "grentimer", FO_HUD_GRENTIMER_NAME, '100 110', '26 26', 1,0,1,0,0, drawGrenTimerPanel, {return "";}}, {HUDP_MOTD, "motd", FO_HUD_MOTD_NAME, '150 100', '100 24', 1,0,1,0,0, drawMOTDPanel, {return SBAR.MOTD;}}, {HUDP_GAME_MODE, "gamemode", FO_HUD_GAME_MODE_NAME, '100 140', '100 10', 1,0,1,0,0, drawGameModePanel, {return "";}}, - {HUDP_READY, "ready", FO_HUD_READY_NAME, '10 100', '100 10', 2,0,1,FO_HUD_INSERT_MIDDLE, 1, drawReadyPanel, {return SBAR.Hint;}}, + {HUDP_NOTIFICATION, "notification", FO_HUD_NOTIFICATION_NAME, '10 100', '100 10', 2,0,1,FO_HUD_INSERT_MIDDLE, 1, drawNotificationPanel, {return SBAR.Hint;}}, {HUDP_HEALTH, "health", FO_HUD_HEALTH_NAME, '-22 -2', '72 24', 1,0,1,0,0, drawHealthArmourTextPanel, {return ftos(getstatf(STAT_HEALTH));}, 0, 34}, {HUDP_FACE, "face", FO_HUD_FACE_NAME, '-70 -2', '24 24', 1,0,1,0,0, drawFacePanel, {return "";}, 0, 34}, {HUDP_AMMO, "ammo", FO_HUD_AMMO_NAME, '90 -2', '72 24', 1,0,1,0,0, drawAmmoTextPanel, {return ftos(WP_CurrentAmmo());}, 0, 34}, diff --git a/share/defs.h b/share/defs.h index 5ad54854..a96d8bcd 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1395,7 +1395,7 @@ enum { #define FO_HUD_MOTD_NAME "MOTD" #define FO_HUD_MENU_HINT_NAME "Menu Hints" #define FO_HUD_GAME_MODE_NAME "Game Mode" -#define FO_HUD_READY_NAME "Ready Status" +#define FO_HUD_NOTIFICATION_NAME "Notification" #define FO_HUD_SHOWSCORES_NAME "Show Scores" #define FO_HUD_MAP_MENU_NAME "Map Menu" #define FO_HUD_HEALTH_NAME "Health" From 960ba31d6778c0935c74a4f4d714e92f6893a3e4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 27 Apr 2024 00:51:05 +1000 Subject: [PATCH 2371/2474] Warning go away --- csqc/status.qc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/csqc/status.qc b/csqc/status.qc index 3a119672..380e14f5 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -612,8 +612,8 @@ void(PanelID panelid, string text) drawNotificationPanel = { alert_text_position.y = ScreenSize.y / 3; alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); - local string flag_team_str; - local vector menu_text_color; + local string flag_team_str = "the"; + local vector menu_text_color = MENU_TEXT_4; switch(flag_team) { case 1: @@ -632,10 +632,6 @@ void(PanelID panelid, string text) drawNotificationPanel = { flag_team_str = "green's"; menu_text_color = MENU_TEXT_GREEN_FO; break; - default: - flag_team_str = "the"; - menu_text_color = MENU_TEXT_4; - break; } local string alert_text_message = sprintf("You got %s flag!", flag_team_str); From 791abccb430bfdb4eb7fed09aa825d05d3d88625 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 27 Apr 2024 00:53:25 +1000 Subject: [PATCH 2372/2474] Remove debug prints --- ssqc/tfortmap.qc | 3 --- 1 file changed, 3 deletions(-) diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index b066fa73..03b6763c 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -2106,9 +2106,7 @@ void () item_tfgoal_touch = { return; if (CTF_Map == 1) { - printf("CTF_Map: %f\n", CTF_Map); if (self.goal_no == 1) { - printf("self.goal_no: %f\n", self.goal_no); if (self.origin != self.oldorigin) { if (other.team_no == 1) { bprint(2, other.netname); @@ -2173,7 +2171,6 @@ void () item_tfgoal_touch = { } } if (Activated(self, other)) { - printf("activated\n"); tfgoalitem_GiveToPlayer(self, other, self); if (other.health > 0) { self.goal_state = 1; From 946e9067c641306d652183a0795ad604e4ffd8c6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 29 Apr 2024 10:44:03 +1000 Subject: [PATCH 2373/2474] WIP sentry preview --- csqc/csextradefs.qc | 1 + csqc/main.qc | 114 +++++++++++++++++++++++++++++++++++++++++++- ssqc/engineer.qc | 3 +- 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1e4db845..fa50037e 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -114,6 +114,7 @@ float vote_selected_index; float vote_list_offset; entity current_vote; string vote_list_filter; +float oldbuttons; float zoomed_in; float pick_up_time; float flag_team; diff --git a/csqc/main.qc b/csqc/main.qc index f25a5d9e..bd372ad0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -16,6 +16,68 @@ void FO_Hud_Init(); float InFluid(vector point); float CalculateWaterLevel(); void RenderHitTexts(); +entity sentry_preview; +entity temp_self; +float previewing_sentry; + +// taken direct from engineer.qc:537 +float (entity obj, entity builder) CheckArea = { + local vector src; + local vector end; + local float pos; + local entity te; + + pos = pointcontents(obj.origin); + if ((pos == -2) || (pos == -6)) { + return (0); + } + src_x = (obj.origin_x + obj.maxs_x) + 24; + src_y = (obj.origin_y + obj.maxs_y) + 24; + src_z = (obj.origin_z + obj.maxs_z) + 16; + pos = pointcontents(src); + if ((pos == -2) || (pos == -6)) { + return (0); + } + end_x = (obj.origin_x + obj.mins_x) - 16; + end_y = (obj.origin_y + obj.mins_y) - 16; + end_z = (obj.origin_z + obj.mins_z) - 16; + traceline(src, end, 1, obj); + if (trace_fraction != 1) { + return (0); + } + pos = pointcontents(end); + if ((pos == -2) || (pos == -6)) { + return (0); + } + src_x = (obj.origin_x + obj.mins_x) - 16; + src_y = (obj.origin_y + obj.maxs_y) + 16; + src_z = (obj.origin_z + obj.maxs_z) + 16; + pos = pointcontents(src); + if ((pos == -2) || (pos == -6)) { + return (0); + } + end_x = (obj.origin_x + obj.maxs_x) + 16; + end_y = (obj.origin_y + obj.mins_y) - 16; + end_z = (obj.origin_z + obj.mins_z) - 16; + traceline(src, end, 1, obj); + if (trace_fraction != 1) { + return (0); + } + pos = pointcontents(end); + if ((pos == -2) || (pos == -6)) { + return (0); + } + traceline(builder.origin, obj.origin, 1, builder); + if (trace_fraction != 1) { + return (0); + } + te = findradius(obj.origin, 64); + if (te != world) { + return (0); + } + return (1); +}; + void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -90,7 +152,6 @@ void ClientSettings_Check(); noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); - // precache_model("progs/weapons/v_rock.mdl"); // for (float i = 0; i < HudIcons.length; i++) { // precache_pic(HudIcons[i].icon); @@ -180,6 +241,13 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Menu_Game(TRUE); pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. + + precache_model("progs/turrbase.mdl"); + temp_self = spawn(); + sentry_preview = spawn(); + setmodel(sentry_preview, "progs/turrbase.mdl"); + sentry_preview.alpha = 0.5; + print("CSQC initialization finished\n"); }; @@ -221,6 +289,23 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (PM_Enabled()) PM_UpdateView(); + if (previewing_sentry) { + makevectors(input_angles); + v_forward_z = 0; + v_forward = normalize(v_forward) * 64; + + sentry_preview.origin = PM_Org() + v_forward; + sentry_preview.angles_y = anglemod(input_angles_y + 180); + + setorigin(temp_self, PM_Org()); + + if (!CheckArea(sentry_preview, temp_self)) { + sentry_preview.colormod = '1 0.5 0.5'; + } else { + sentry_preview.colormod = '0.5 1 0.5'; + } + } + renderscene(); FO_CussCrosshair(width, height); @@ -646,13 +731,38 @@ void FO_ApplyCussInput() { void PM_InputFrame(); noref void CSQC_Input_Frame() { + local float changed_buttons = input_buttons ^ oldbuttons; + oldbuttons = input_buttons; + + local float keydowns = changed_buttons & input_buttons; + local float keyups = changed_buttons & ~input_buttons; + Sync_GameState(); - // Intercept rocket jump; + // Intercept rocket jump if ((WP_PlayerClass() == PC_SOLDIER || WP_PlayerClass() == PC_PYRO) && (input_buttons & BUTTON4)) input_buttons |= BUTTON0 | BUTTON2; + // Intercept sentry build + if (WP_PlayerClass() == PC_ENGINEER && (input_buttons & BUTTON4)) { + if (keydowns & BUTTON4) { + if (!previewing_sentry) { + // preview sentry + sentry_preview.drawmask = MASK_ENGINE; + previewing_sentry = TRUE; + + input_buttons = input_buttons - BUTTON4; + } else { + sentry_preview.drawmask = 0; + previewing_sentry = FALSE; + } + } else { + // don't send held button for now + input_buttons = input_buttons - BUTTON4; + } + } + // Handle zoom float prev_zoomed_in = zoomed_in; if (WP_PlayerClass() == PC_SNIPER) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 06c3785b..0ce70265 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -591,12 +591,13 @@ float (entity obj, entity builder) CheckArea = { return (1); }; +// here void (float objtobuild) TeamFortress_Build = { if (cb_prematch) { sprint(self, PRINT_MEDIUM, "You cannot build during prematch\n"); return; } - + if(no_fire_mode) { sprint(self, PRINT_MEDIUM, "You cannot build right now\n"); return; From 6c1fd61aeb5f5e8a1a6b4742e16c219d3fa57daf Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 29 Apr 2024 23:30:58 +1000 Subject: [PATCH 2374/2474] Refactor --- csqc/csprogs.src | 1 + csqc/main.qc | 59 ----------------------------------------------- share/engineer.qc | 56 ++++++++++++++++++++++++++++++++++++++++++++ ssqc/engineer.qc | 58 ---------------------------------------------- ssqc/progs.src | 1 + 5 files changed, 58 insertions(+), 117 deletions(-) create mode 100644 share/engineer.qc diff --git a/csqc/csprogs.src b/csqc/csprogs.src index fcf7f83b..6870ce29 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -21,6 +21,7 @@ profile.qc ../share/classes.qc ../share/animate.qc ../share/mcp_precache.qc +../share/engineer.qc weapon_predict.qc pmove.qc tfx.qc diff --git a/csqc/main.qc b/csqc/main.qc index bd372ad0..48a54ca4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -20,65 +20,6 @@ entity sentry_preview; entity temp_self; float previewing_sentry; -// taken direct from engineer.qc:537 -float (entity obj, entity builder) CheckArea = { - local vector src; - local vector end; - local float pos; - local entity te; - - pos = pointcontents(obj.origin); - if ((pos == -2) || (pos == -6)) { - return (0); - } - src_x = (obj.origin_x + obj.maxs_x) + 24; - src_y = (obj.origin_y + obj.maxs_y) + 24; - src_z = (obj.origin_z + obj.maxs_z) + 16; - pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { - return (0); - } - end_x = (obj.origin_x + obj.mins_x) - 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { - return (0); - } - src_x = (obj.origin_x + obj.mins_x) - 16; - src_y = (obj.origin_y + obj.maxs_y) + 16; - src_z = (obj.origin_z + obj.maxs_z) + 16; - pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { - return (0); - } - end_x = (obj.origin_x + obj.maxs_x) + 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { - return (0); - } - traceline(builder.origin, obj.origin, 1, builder); - if (trace_fraction != 1) { - return (0); - } - te = findradius(obj.origin, 64); - if (te != world) { - return (0); - } - return (1); -}; - - void GetSelf() = { self = findfloat(world, entnum, player_localentnum); } diff --git a/share/engineer.qc b/share/engineer.qc new file mode 100644 index 00000000..46b9337c --- /dev/null +++ b/share/engineer.qc @@ -0,0 +1,56 @@ +float (entity obj, entity builder) CheckArea = { + local vector src; + local vector end; + local float pos; + local entity te; + + pos = pointcontents(obj.origin); + if ((pos == -2) || (pos == -6)) { + return (0); + } + src_x = (obj.origin_x + obj.maxs_x) + 24; + src_y = (obj.origin_y + obj.maxs_y) + 24; + src_z = (obj.origin_z + obj.maxs_z) + 16; + pos = pointcontents(src); + if ((pos == -2) || (pos == -6)) { + return (0); + } + end_x = (obj.origin_x + obj.mins_x) - 16; + end_y = (obj.origin_y + obj.mins_y) - 16; + end_z = (obj.origin_z + obj.mins_z) - 16; + traceline(src, end, 1, obj); + if (trace_fraction != 1) { + return (0); + } + pos = pointcontents(end); + if ((pos == -2) || (pos == -6)) { + return (0); + } + src_x = (obj.origin_x + obj.mins_x) - 16; + src_y = (obj.origin_y + obj.maxs_y) + 16; + src_z = (obj.origin_z + obj.maxs_z) + 16; + pos = pointcontents(src); + if ((pos == -2) || (pos == -6)) { + return (0); + } + end_x = (obj.origin_x + obj.maxs_x) + 16; + end_y = (obj.origin_y + obj.mins_y) - 16; + end_z = (obj.origin_z + obj.mins_z) - 16; + traceline(src, end, 1, obj); + if (trace_fraction != 1) { + return (0); + } + pos = pointcontents(end); + if ((pos == -2) || (pos == -6)) { + return (0); + } + traceline(builder.origin, obj.origin, 1, builder); + if (trace_fraction != 1) { + return (0); + } + te = findradius(obj.origin, 64); + if (te != world) { + return (0); + } + return (1); +}; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 0ce70265..4f85c936 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -18,7 +18,6 @@ void (entity disp) Engineer_SentryGun_Upgrade; void (entity disp) Engineer_SentryGun_Repair; void () Menu_Engineer_Cancel; void () CF_CheckBuilding; -float (entity obj, entity builder) CheckArea; void () LaserBolt_Think = { self.solid = SOLID_TRIGGER; @@ -534,63 +533,6 @@ void () TeamFortress_EngineerBuildStop = { } } -float (entity obj, entity builder) CheckArea = { - local vector src; - local vector end; - local float pos; - local entity te; - - pos = pointcontents(obj.origin); - if ((pos == -2) || (pos == -6)) { - return (0); - } - src_x = (obj.origin_x + obj.maxs_x) + 24; - src_y = (obj.origin_y + obj.maxs_y) + 24; - src_z = (obj.origin_z + obj.maxs_z) + 16; - pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { - return (0); - } - end_x = (obj.origin_x + obj.mins_x) - 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { - return (0); - } - src_x = (obj.origin_x + obj.mins_x) - 16; - src_y = (obj.origin_y + obj.maxs_y) + 16; - src_z = (obj.origin_z + obj.maxs_z) + 16; - pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { - return (0); - } - end_x = (obj.origin_x + obj.maxs_x) + 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { - return (0); - } - traceline(builder.origin, obj.origin, 1, builder); - if (trace_fraction != 1) { - return (0); - } - te = findradius(obj.origin, 64); - if (te != world) { - return (0); - } - return (1); -}; - // here void (float objtobuild) TeamFortress_Build = { if (cb_prematch) { diff --git a/ssqc/progs.src b/ssqc/progs.src index c4d080b9..f588d2f7 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -24,6 +24,7 @@ time.qc ../share/classes.qc ../share/animate.qc ../share/mcp_precache.qc +../share/engineer.qc helpers.qc events.qc roles.qc From dea4ba564332b437607e213343a1fdf9e3802808 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 00:06:47 +1000 Subject: [PATCH 2375/2474] Don't show crosshair while previewing sentry --- csqc/main.qc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 48a54ca4..ee89e5e4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -212,7 +212,10 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { float fts = perf_start_sample(&frame_timing); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! - setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + + if (!previewing_sentry) + setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + FO_CussView(); if (zoomed_in) From 6ac9d0ef3a123e17ced564c4d83f4f7be3f3c8fb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 01:23:03 +1000 Subject: [PATCH 2376/2474] Barely working but really naster sentry preview rotation --- csqc/input.qc | 10 +++++++++ csqc/main.qc | 59 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 92161688..651f8d72 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -117,6 +117,16 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; } break; + case IE_MOUSEDELTA: + if (rotating_sentry) { + sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * 0.25); + sentry_preview_offset = sentry_preview_offset + scanx * 0.25; + return TRUE; + } + + if (previewing_sentry) { + sentry_preview.angles_y = anglemod(input_angles_y + (180 - sentry_preview_offset)); + } default: } } diff --git a/csqc/main.qc b/csqc/main.qc index ee89e5e4..22ad2131 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -17,8 +17,10 @@ float InFluid(vector point); float CalculateWaterLevel(); void RenderHitTexts(); entity sentry_preview; +float sentry_preview_offset; entity temp_self; float previewing_sentry; +float rotating_sentry; void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -239,8 +241,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { v_forward = normalize(v_forward) * 64; sentry_preview.origin = PM_Org() + v_forward; - sentry_preview.angles_y = anglemod(input_angles_y + 180); - setorigin(temp_self, PM_Org()); if (!CheckArea(sentry_preview, temp_self)) { @@ -560,11 +560,11 @@ static vector FO_Conc_Offset() { float i, rot = 0; if (!IsClownMode(CLOWN_CONC)) { - table = conc_curve; - len = conc_curve.length; + table = conc_curve; + len = conc_curve.length; } else { - table = clown_curve; - len = clown_curve.length; + table = clown_curve; + len = clown_curve.length; } for (i = 0; i < len - 1; i++) { @@ -662,7 +662,7 @@ void FO_ApplyCussInput() { float modify_forward = TRUE; if ((!pmove_onground && (fo_config.fo_concuss & FOC_EASY_AIR)) || - (pmove_onground && (fo_config.fo_concuss & FOC_EASY_GROUND))) + (pmove_onground && (fo_config.fo_concuss & FOC_EASY_GROUND))) modify_forward = input_buttons & BUTTON0; if (modify_forward) { @@ -685,25 +685,40 @@ noref void CSQC_Input_Frame() { // Intercept rocket jump if ((WP_PlayerClass() == PC_SOLDIER || WP_PlayerClass() == PC_PYRO) && - (input_buttons & BUTTON4)) + (input_buttons & BUTTON4)) input_buttons |= BUTTON0 | BUTTON2; // Intercept sentry build - if (WP_PlayerClass() == PC_ENGINEER && (input_buttons & BUTTON4)) { - if (keydowns & BUTTON4) { - if (!previewing_sentry) { - // preview sentry - sentry_preview.drawmask = MASK_ENGINE; - previewing_sentry = TRUE; - - input_buttons = input_buttons - BUTTON4; + if (WP_PlayerClass() == PC_ENGINEER) { + if (input_buttons & BUTTON4) { + if (keydowns & BUTTON4) { + if (!previewing_sentry) { + // preview sentry + sentry_preview.angles_y = anglemod(input_angles_y + 180); + sentry_preview.drawmask = MASK_ENGINE; + previewing_sentry = TRUE; + + input_buttons = input_buttons - BUTTON4; // don't send build yet + } } else { - sentry_preview.drawmask = 0; - previewing_sentry = FALSE; + input_buttons = input_buttons - BUTTON4; // don't send build yet } - } else { - // don't send held button for now - input_buttons = input_buttons - BUTTON4; + } + + if ((input_buttons & BUTTON0) && previewing_sentry) { + input_buttons = input_buttons - BUTTON0; + + if (keydowns & BUTTON0) { + printf("rotating_sentry!\n"); + rotating_sentry = TRUE; + } + } + + if (keyups & BUTTON0) { + rotating_sentry = FALSE; + previewing_sentry = FALSE; + sentry_preview_offset = 0; + sentry_preview.drawmask = 0; } } @@ -807,7 +822,7 @@ float FoLogin(string token, float print_error) { } if (token == "") { - if (print_error) + if (print_error) print("Token required: Please sign-up at fortressone.org and follow the instructions to generate your login token.\n"); return FALSE; } From 77636fd2f17687134d3dd9ca486f9c10df48659e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 02:38:26 +1000 Subject: [PATCH 2377/2474] WIP pass sentry rotation offset to cmd build sentry --- csqc/input.qc | 5 +-- csqc/main.qc | 15 ++++++--- ssqc/commands.qc | 4 ++- ssqc/engineer.qc | 4 +-- ssqc/menu.qc | 87 +++++++++++++++++++++++++----------------------- 5 files changed, 65 insertions(+), 50 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 651f8d72..1f392a15 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -118,9 +118,10 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } break; case IE_MOUSEDELTA: + local float sensitivity = 0.25; if (rotating_sentry) { - sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * 0.25); - sentry_preview_offset = sentry_preview_offset + scanx * 0.25; + sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * sensitivity); + sentry_preview_offset = sentry_preview_offset + scanx * sensitivity; return TRUE; } diff --git a/csqc/main.qc b/csqc/main.qc index 22ad2131..754107b0 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -697,12 +697,16 @@ noref void CSQC_Input_Frame() { sentry_preview.angles_y = anglemod(input_angles_y + 180); sentry_preview.drawmask = MASK_ENGINE; previewing_sentry = TRUE; - - input_buttons = input_buttons - BUTTON4; // don't send build yet + } else { + // cancel preview sentry + rotating_sentry = FALSE; + previewing_sentry = FALSE; + sentry_preview_offset = 0; + sentry_preview.drawmask = 0; } - } else { - input_buttons = input_buttons - BUTTON4; // don't send build yet } + + input_buttons = input_buttons - BUTTON4; // don't send build yet } if ((input_buttons & BUTTON0) && previewing_sentry) { @@ -715,6 +719,9 @@ noref void CSQC_Input_Frame() { } if (keyups & BUTTON0) { + // cancel preview sentry + printf("sentry_preview_offset: %f\n", sentry_preview_offset); + localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); rotating_sentry = FALSE; previewing_sentry = FALSE; sentry_preview_offset = 0; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5a7bf0f2..49cafb01 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -698,7 +698,9 @@ float (string arg1, string arg2, string arg3) ParseCmds = { TeamFortress_EngineerBuildStop(); break; } - Menu_Engineer_Input(1); + + printf("arg3: %s\n", arg3); + TeamFortress_Build(2, stof(arg3)); break; } if(arg2 == "dispenser") { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 4f85c936..8a4e849e 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -534,7 +534,7 @@ void () TeamFortress_EngineerBuildStop = { } // here -void (float objtobuild) TeamFortress_Build = { +void (float objtobuild, float offset) TeamFortress_Build = { if (cb_prematch) { sprint(self, PRINT_MEDIUM, "You cannot build during prematch\n"); return; @@ -634,7 +634,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.think = TeamFortress_FinishedBuilding; newmis.colormap = self.colormap; newmis.weapon = objtobuild; - newmis.angles_y = anglemod(self.angles_y + 180); + newmis.angles_y = anglemod(self.angles_y + 180 + offset); newmis.velocity = '0 0 8'; newmis.movetype = 6; newmis.solid = 2; diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 9b0429fd..139ed5db 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -18,7 +18,7 @@ void (entity spy) Spy_RemoveDisguise; void (entity eng, string bld) DestroyBuilding; -void (float objtobuild) TeamFortress_Build; +void (float objtobuild, float offset) TeamFortress_Build; void () lvl1_sentry_stand; void () lvl2_sentry_stand; @@ -806,6 +806,15 @@ void () Menu_Demoman_Cancel = { Status_Menu(self, Menu_Demoman_Cancel_Input, s_detpack, s_cancel); } +void (float offset) TeamFortress_BuildSentry = { + if (self.has_sentry) return; + + if (self.ammo_cells >= ENG_SENTRY_COST) + TeamFortress_Build(2, 0); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST), " cells to build a sentry gun")); +} + void (float inp) Menu_Engineer_Input = { local float dismantle_sentrygun; local float dismantle_dispenser; @@ -826,16 +835,12 @@ void (float inp) Menu_Engineer_Input = { dismantle_sentrygun = 0; dismantle_dispenser = 0; - if (inp == 1 && !self.has_sentry) { - if (self.ammo_cells >= ENG_SENTRY_COST) - TeamFortress_Build(2); - else - Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST), " cells to build a sentry gun")); + if (inp == 1) { + TeamFortress_BuildSentry(0); } - if (inp == 2 && !self.has_dispenser) { if (self.ammo_cells >= ENG_DISPENSER_COST) - TeamFortress_Build(1); + TeamFortress_Build(1, 0); else Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); } @@ -922,7 +927,7 @@ void (entity player) Menu_Engineer = { te = te.chain; } } else if (player.ammo_cells >= 100) { - s_disp = Q"\s[2]\s Build dispenser \n"; + s_disp = Q"\s[2]\s Build dispenser \n"; } if ((player.has_dispenser || player.has_sentry) && !player.has_menutimer) { @@ -1021,10 +1026,10 @@ void () Menu_EngineerFix_SentryGun_Rotate = { if (!self.building.real_owner.has_sentry || self.building.real_owner != self - || self.classname != "player" || self.building == world) { + || self.classname != "player" || self.building == world) { return; } - + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { //fte+csqc has its own team menu //ask the client to activate it @@ -1032,13 +1037,13 @@ void () Menu_EngineerFix_SentryGun_Rotate = { UpdateClientMenu_FixSentry(self); return; } - + Status_Menu(self, Menu_EngineerFix_SentryGun_Rotate_Input, action, rotl, rot180, rotr, nothing); }; void (float inp) Menu_EngineerFix_SentryGun_Input = { if (!self.building.real_owner.has_sentry || self.building.real_owner != self - || self.classname != "player" || self.building == world) + || self.classname != "player" || self.building == world) return; if (inp == 1) { @@ -1095,9 +1100,9 @@ void (float inp) Menu_Dispenser_Input = { empty = FALSE; if (inp == 1) { if ((self.building.ammo_shells == 0) - && (self.building.ammo_nails == 0) - && (self.building.ammo_rockets == 0) - && (self.building.ammo_cells == 0)) { + && (self.building.ammo_nails == 0) + && (self.building.ammo_rockets == 0) + && (self.building.ammo_cells == 0)) { empty = TRUE; } else { am = self.maxammo_shells - self.ammo_shells; @@ -1324,7 +1329,7 @@ void () Menu_Admin = s_menu1 = "Round Time Input Menu: \n\n"; //s_menu1 = strcat(s_menu1, "Enter a number between 1 and 10 \n"); //s_menu1 = strcat(s_menu1, "\n\n"); - + s_menu1 = strcat(s_menu1, Q"\s[1]\s 1 minute \n"); s_menu1 = strcat(s_menu1, Q"\s[2]\s 5 minutes \n"); s_menu1 = strcat(s_menu1, Q"\s[3]\s 10 minutes \n"); @@ -1388,12 +1393,12 @@ void () Menu_Admin = Status_Menu(self, Menu_Admin_Input, s_menu1); break; } - + // jesus christ what is this, this should be separated out for the good of the people // or maybe made understandable if (self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) { f_tmp = 0; f_tmp2 = 0; @@ -1450,20 +1455,20 @@ void () Menu_Admin = } if (f_tmp == 0 && ( self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO ) ) { - bprint(2, "\x10\sCaptain Mode\s\x11\s:\s \sTeams are set, let's start the game!\s\n"); - temp = self; - te = find (world, classname, "player"); - while (te != world) { - te.captain = 0; - self = te; - Menu_Close(self); - self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 1; - te = find (te, classname, "player"); - } - self = temp; - captainmode = 0; - return; + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s \sTeams are set, let's start the game!\s\n"); + temp = self; + te = find (world, classname, "player"); + while (te != world) { + te.captain = 0; + self = te; + Menu_Close(self); + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + self.current_menu_page = 1; + te = find (te, classname, "player"); + } + self = temp; + captainmode = 0; + return; } s_menu2 = strcat( s_menu2, "\n"); s_menu7 = "\b[\b8\b]\b \bPrevious Page\b "; @@ -1471,13 +1476,13 @@ void () Menu_Admin = s_menu8 = "\b[\b9\b]\b \bNext Page\b "; s_menu8 = Menu_Indent_line(s_menu8, 30); if (self.is_admin || self.captain == 1) { - s_menu9 = "\b[\b0\b]\b \bBack to Main Menu\b "; - s_menu9 = Menu_Indent_line(s_menu9, 30); + s_menu9 = "\b[\b0\b]\b \bBack to Main Menu\b "; + s_menu9 = Menu_Indent_line(s_menu9, 30); } else { - s_menu9 = "\n"; + s_menu9 = "\n"; } if ((self.is_admin || self.captain == 1) && captainmode) { - s_menu9 = strcat(s_menu9, "Option 0 results in canceling captain mode.\n"); + s_menu9 = strcat(s_menu9, "Option 0 results in canceling captain mode.\n"); } s_menu1 = strcat(s_menu1, s_menu2); @@ -1638,7 +1643,7 @@ void (float inp) Menu_Admin_Input = } } else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) - && inp >= 1 && inp <= 7) + && inp >= 1 && inp <= 7) { // Kick / Ban Actions //bprint(PRINT_HIGH, "Getting player ", ftos(inp), "\n"); f_tmp = 1; @@ -1681,8 +1686,8 @@ void (float inp) Menu_Admin_Input = } } else if ((self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) { // Captain Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); From ad739386eb9f2152b9b09539995b326de874f0df Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 11:04:50 +1000 Subject: [PATCH 2378/2474] Remove green colormod for valid sentry --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 754107b0..84c9ce7b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -246,7 +246,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (!CheckArea(sentry_preview, temp_self)) { sentry_preview.colormod = '1 0.5 0.5'; } else { - sentry_preview.colormod = '0.5 1 0.5'; + sentry_preview.colormod = '1 1 1'; } } From 07dff8e112f729250c709e1d2694494ffc269997 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 11:04:59 +1000 Subject: [PATCH 2379/2474] Allow building in the air --- ssqc/engineer.qc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 8a4e849e..a4c2fdb2 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -612,10 +612,6 @@ void (float objtobuild, float offset) TeamFortress_Build = { sprint(self, PRINT_HIGH, "You cannot build in the water\n"); dremove(newmis); return; - } else if (!self.waterlevel) { - sprint(self, PRINT_HIGH, "You cannot build in the air\n"); - dremove(newmis); - return; } } self.is_building = 1; From d768db1b561f6a316bdbcb303382b27890d01498 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 11:41:52 +1000 Subject: [PATCH 2380/2474] Don't show sentry preview if player has sentry --- csqc/main.qc | 28 +++++++++++++++------------- share/defs.h | 1 + ssqc/world.qc | 1 + 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 84c9ce7b..30525e09 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -689,7 +689,7 @@ noref void CSQC_Input_Frame() { input_buttons |= BUTTON0 | BUTTON2; // Intercept sentry build - if (WP_PlayerClass() == PC_ENGINEER) { + if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY)) { if (input_buttons & BUTTON4) { if (keydowns & BUTTON4) { if (!previewing_sentry) { @@ -709,23 +709,25 @@ noref void CSQC_Input_Frame() { input_buttons = input_buttons - BUTTON4; // don't send build yet } - if ((input_buttons & BUTTON0) && previewing_sentry) { - input_buttons = input_buttons - BUTTON0; - + if (previewing_sentry) { if (keydowns & BUTTON0) { printf("rotating_sentry!\n"); rotating_sentry = TRUE; } - } - if (keyups & BUTTON0) { - // cancel preview sentry - printf("sentry_preview_offset: %f\n", sentry_preview_offset); - localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); - rotating_sentry = FALSE; - previewing_sentry = FALSE; - sentry_preview_offset = 0; - sentry_preview.drawmask = 0; + if (keyups & BUTTON0) { + // cancel preview sentry + printf("sentry_preview_offset: %f\n", sentry_preview_offset); + localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); + rotating_sentry = FALSE; + previewing_sentry = FALSE; + sentry_preview_offset = 0; + sentry_preview.drawmask = 0; + } + + if (input_buttons & BUTTON0) { + input_buttons = input_buttons - BUTTON0; + } } } diff --git a/share/defs.h b/share/defs.h index a96d8bcd..ebd8b3b0 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1460,6 +1460,7 @@ enum { #define STAT_ALL_TIME 38 #define STAT_SPAWN_GEN 39 #define STAT_ROUND_END 40 +#define STAT_HAS_SENTRY 41 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this diff --git a/ssqc/world.qc b/ssqc/world.qc index e194f42a..abe751a8 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -333,6 +333,7 @@ void () worldspawn = { clientstat(STAT_ALL_TIME, EV_FLOAT, all_time); clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); clientstat(STAT_SPAWN_GEN, EV_FLOAT, spawn_gen); + clientstat(STAT_HAS_SENTRY, EV_FLOAT, has_sentry); globalstat(STAT_ROUND_END, EV_FLOAT, "round_end_time"); globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused"); From 230abad106b1aebf34bbf3f600b6069bdda21f83 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 11:55:12 +1000 Subject: [PATCH 2381/2474] Fix unlimited sentries, don't show preview without enough ammo, remove debug statements --- csqc/main.qc | 7 ++----- ssqc/commands.qc | 2 +- ssqc/menu.qc | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 30525e09..e30e49fc 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -689,7 +689,7 @@ noref void CSQC_Input_Frame() { input_buttons |= BUTTON0 | BUTTON2; // Intercept sentry build - if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY)) { + if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130) { if (input_buttons & BUTTON4) { if (keydowns & BUTTON4) { if (!previewing_sentry) { @@ -706,19 +706,16 @@ noref void CSQC_Input_Frame() { } } - input_buttons = input_buttons - BUTTON4; // don't send build yet + input_buttons = input_buttons - BUTTON4; } if (previewing_sentry) { if (keydowns & BUTTON0) { - printf("rotating_sentry!\n"); rotating_sentry = TRUE; } if (keyups & BUTTON0) { // cancel preview sentry - printf("sentry_preview_offset: %f\n", sentry_preview_offset); - localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); rotating_sentry = FALSE; previewing_sentry = FALSE; sentry_preview_offset = 0; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 49cafb01..2f40b33f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -700,7 +700,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } printf("arg3: %s\n", arg3); - TeamFortress_Build(2, stof(arg3)); + TeamFortress_BuildSentry(stof(arg3)); break; } if(arg2 == "dispenser") { diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 139ed5db..eaeed206 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -810,7 +810,7 @@ void (float offset) TeamFortress_BuildSentry = { if (self.has_sentry) return; if (self.ammo_cells >= ENG_SENTRY_COST) - TeamFortress_Build(2, 0); + TeamFortress_Build(2, offset); else Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST), " cells to build a sentry gun")); } From befe34db5b615358b202ee4f6a2aff2178194edd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 12:05:51 +1000 Subject: [PATCH 2382/2474] Actually build the gun --- csqc/main.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/csqc/main.qc b/csqc/main.qc index e30e49fc..bd6a13ee 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -716,6 +716,7 @@ noref void CSQC_Input_Frame() { if (keyups & BUTTON0) { // cancel preview sentry + localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); rotating_sentry = FALSE; previewing_sentry = FALSE; sentry_preview_offset = 0; From 444259dd2df60f3c0f972025d44949b6a49ab00a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 12:16:37 +1000 Subject: [PATCH 2383/2474] No sentry preview in prematch --- csqc/main.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index bd6a13ee..24a2efcb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -689,7 +689,7 @@ noref void CSQC_Input_Frame() { input_buttons |= BUTTON0 | BUTTON2; // Intercept sentry build - if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130) { + if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && !prematch) { if (input_buttons & BUTTON4) { if (keydowns & BUTTON4) { if (!previewing_sentry) { From 35f2738c4df96ad0c0883c2107bc5855d7e03082 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 12:39:56 +1000 Subject: [PATCH 2384/2474] Stop sentry preview on death --- csqc/input.qc | 2 +- csqc/main.qc | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 1f392a15..40f5350a 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -96,7 +96,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } return TRUE; } - } + } case IE_KEYUP: switch (scanx) { case K_ESCAPE: diff --git a/csqc/main.qc b/csqc/main.qc index 24a2efcb..4883533e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -63,7 +63,6 @@ float RemoveFromSlotHistory(float slot) { } } - static void BindAlias(TFAlias* tfa) { if (tfa->impulse == 0 && tfa->cmd == "") // Some aliases are !csqc-only return; @@ -674,6 +673,13 @@ void FO_ApplyCussInput() { void PM_InputFrame(); +void SentryPreviewStop() { + rotating_sentry = FALSE; + previewing_sentry = FALSE; + sentry_preview_offset = 0; + sentry_preview.drawmask = 0; +} + noref void CSQC_Input_Frame() { local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; @@ -699,10 +705,7 @@ noref void CSQC_Input_Frame() { previewing_sentry = TRUE; } else { // cancel preview sentry - rotating_sentry = FALSE; - previewing_sentry = FALSE; - sentry_preview_offset = 0; - sentry_preview.drawmask = 0; + SentryPreviewStop(); } } @@ -717,10 +720,7 @@ noref void CSQC_Input_Frame() { if (keyups & BUTTON0) { // cancel preview sentry localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); - rotating_sentry = FALSE; - previewing_sentry = FALSE; - sentry_preview_offset = 0; - sentry_preview.drawmask = 0; + SentryPreviewStop(); } if (input_buttons & BUTTON0) { @@ -798,6 +798,10 @@ void _Sync_ServerCommandFrame() { CsGrenTimer::UpdateSoundStack(); UpdateTeamColorCrosshair(); + + if (!game_state.is_alive && previewing_sentry) { + SentryPreviewStop(); + } } From f2faaf154b3996df8d4d4f914d12dfb8330890de Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 12:40:05 +1000 Subject: [PATCH 2385/2474] Remove debug statement --- ssqc/commands.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 2f40b33f..27b3a2e2 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -699,7 +699,6 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; } - printf("arg3: %s\n", arg3); TeamFortress_BuildSentry(stof(arg3)); break; } From 00d6b9975dd000b642ec0c80409b96050668a013 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 12:45:51 +1000 Subject: [PATCH 2386/2474] Don't try to preview sentry when dead --- csqc/main.qc | 4 +--- ssqc/commands.qc | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 4883533e..12839680 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -695,7 +695,7 @@ noref void CSQC_Input_Frame() { input_buttons |= BUTTON0 | BUTTON2; // Intercept sentry build - if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && !prematch) { + if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { if (input_buttons & BUTTON4) { if (keydowns & BUTTON4) { if (!previewing_sentry) { @@ -704,7 +704,6 @@ noref void CSQC_Input_Frame() { sentry_preview.drawmask = MASK_ENGINE; previewing_sentry = TRUE; } else { - // cancel preview sentry SentryPreviewStop(); } } @@ -718,7 +717,6 @@ noref void CSQC_Input_Frame() { } if (keyups & BUTTON0) { - // cancel preview sentry localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); SentryPreviewStop(); } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 27b3a2e2..a261632b 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -692,7 +692,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if(arg2 == "cancel") { TeamFortress_EngineerBuildStop(); break; - } + } if(arg2 == "sentry") { if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); From ee979baf281f1beb7521555cfcc3b449a91f6514 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 13:21:43 +1000 Subject: [PATCH 2387/2474] Fix mismatch in CheckArea entity bounding boxes --- csqc/main.qc | 7 +++++-- ssqc/engineer.qc | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 12839680..492da6a5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -238,11 +238,14 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { makevectors(input_angles); v_forward_z = 0; v_forward = normalize(v_forward) * 64; - sentry_preview.origin = PM_Org() + v_forward; setorigin(temp_self, PM_Org()); - if (!CheckArea(sentry_preview, temp_self)) { + local entity newmis; + newmis = spawn(); + newmis.origin = sentry_preview.origin; + + if (!CheckArea(newmis, temp_self)) { sentry_preview.colormod = '1 0.5 0.5'; } else { sentry_preview.colormod = '1 1 1'; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index a4c2fdb2..2fd86a44 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -602,6 +602,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { btime = time + 5; self.sentry_ticks = 0; } + if (CheckArea(newmis, self) == 0) { sprint(self, PRINT_HIGH, "Not enough room to build here\n"); dremove(newmis); From 8779758d0d883dc820bece0113305ae5471df806 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 14:51:16 +1000 Subject: [PATCH 2388/2474] Dismantle at close range for still building sentry should return all cells just as hitting with spanner does --- ssqc/menu.qc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index eaeed206..063d5b13 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -823,6 +823,26 @@ void (float inp) Menu_Engineer_Input = { if (inp == 5) return; + if (inp == 3 && self.has_sentry) { + te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); + while (te) { + if (te.classname == "building_sentrygun") { + if (te.real_owner == self && te.weapon == 0){ + sprint (self, PRINT_HIGH, strcat("You stopped building a sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); + self.ammo_cells = self.ammo_cells + ENG_SENTRY_COST; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; + if (te.trigger_field != world) + dremove (te.trigger_field); + self = te.real_owner; + TeamFortress_EngineerBuildStop(); + return; + } + } + te = te.chain; + } + } + if (self.is_building) { if (engineer_move) { Status_Print(self, "\n\n\n\n\n\n\n", strcat("You are already building something")); From e16314f6ff4ea3344362765e21faff1640cb9505 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 14:54:37 +1000 Subject: [PATCH 2389/2474] Print how many more cells are needed --- ssqc/menu.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 063d5b13..e3ef9dc1 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -812,7 +812,7 @@ void (float offset) TeamFortress_BuildSentry = { if (self.ammo_cells >= ENG_SENTRY_COST) TeamFortress_Build(2, offset); else - Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST), " cells to build a sentry gun")); + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST - self.ammo_cells), " more cells to build a sentry gun")); } void (float inp) Menu_Engineer_Input = { From 59a07b257473da1739f168740d3a22bdca2e2a6d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 15:18:55 +1000 Subject: [PATCH 2390/2474] Don't immediately fire gun if cancelling sentry preview while rotating --- csqc/main.qc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index 492da6a5..909cd817 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -21,6 +21,7 @@ float sentry_preview_offset; entity temp_self; float previewing_sentry; float rotating_sentry; +float prevent_firing; void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -702,12 +703,15 @@ noref void CSQC_Input_Frame() { if (input_buttons & BUTTON4) { if (keydowns & BUTTON4) { if (!previewing_sentry) { - // preview sentry sentry_preview.angles_y = anglemod(input_angles_y + 180); sentry_preview.drawmask = MASK_ENGINE; previewing_sentry = TRUE; } else { SentryPreviewStop(); + + if (input_buttons & BUTTON0) { + prevent_firing = TRUE; + } } } @@ -728,6 +732,14 @@ noref void CSQC_Input_Frame() { input_buttons = input_buttons - BUTTON0; } } + + if (keyups & BUTTON0) { + prevent_firing = FALSE; + } + + if (prevent_firing) { + input_buttons &= ~BUTTON0; + } } // Handle zoom From 6f1fc4e110f74d190c4bc80dad95de5a56c62d0b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 15:23:54 +1000 Subject: [PATCH 2391/2474] Don't spawn entities every frame --- csqc/main.qc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 909cd817..f9562c88 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -17,8 +17,9 @@ float InFluid(vector point); float CalculateWaterLevel(); void RenderHitTexts(); entity sentry_preview; -float sentry_preview_offset; +entity temp_sentry; entity temp_self; +float sentry_preview_offset; float previewing_sentry; float rotating_sentry; float prevent_firing; @@ -186,6 +187,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. precache_model("progs/turrbase.mdl"); + temp_sentry = spawn(); temp_self = spawn(); sentry_preview = spawn(); setmodel(sentry_preview, "progs/turrbase.mdl"); @@ -241,12 +243,9 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { v_forward = normalize(v_forward) * 64; sentry_preview.origin = PM_Org() + v_forward; setorigin(temp_self, PM_Org()); + temp_sentry.origin = sentry_preview.origin; - local entity newmis; - newmis = spawn(); - newmis.origin = sentry_preview.origin; - - if (!CheckArea(newmis, temp_self)) { + if (!CheckArea(temp_sentry, temp_self)) { sentry_preview.colormod = '1 0.5 0.5'; } else { sentry_preview.colormod = '1 1 1'; From 829ed8cd9a3a2c2f7b33c1a3e8dc270096218608 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 16:27:50 +1000 Subject: [PATCH 2392/2474] Move sentry preview up in CSQC_UpdateView order --- csqc/main.qc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index f9562c88..fab7e7ad 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -225,18 +225,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (zoomed_in) setviewprop(VF_AFOV, CVARF(fov)/3); - // Draw original sbar, viewsize honoured automatically. - if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) - setproperty(VF_DRAWENGINESBAR, 1); - - float mask = MASK_ENGINE; - if (!intermission) - mask |= WPP_ViewModelMask(); - addentities(mask); - - if (PM_Enabled()) - PM_UpdateView(); - if (previewing_sentry) { makevectors(input_angles); v_forward_z = 0; @@ -252,6 +240,18 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { } } + // Draw original sbar, viewsize honoured automatically. + if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) + setproperty(VF_DRAWENGINESBAR, 1); + + float mask = MASK_ENGINE; + if (!intermission) + mask |= WPP_ViewModelMask(); + addentities(mask); + + if (PM_Enabled()) + PM_UpdateView(); + renderscene(); FO_CussCrosshair(width, height); From 15858a42e310d45c678b9f366486ae35c09b59bf Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 16:38:34 +1000 Subject: [PATCH 2393/2474] Don't close sentry if gun doesn't fit --- csqc/main.qc | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index fab7e7ad..b5c644cb 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -23,6 +23,7 @@ float sentry_preview_offset; float previewing_sentry; float rotating_sentry; float prevent_firing; +float sentry_fits; void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -217,14 +218,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! - if (!previewing_sentry) - setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! - - FO_CussView(); - - if (zoomed_in) - setviewprop(VF_AFOV, CVARF(fov)/3); - if (previewing_sentry) { makevectors(input_angles); v_forward_z = 0; @@ -232,14 +225,17 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { sentry_preview.origin = PM_Org() + v_forward; setorigin(temp_self, PM_Org()); temp_sentry.origin = sentry_preview.origin; - - if (!CheckArea(temp_sentry, temp_self)) { - sentry_preview.colormod = '1 0.5 0.5'; - } else { - sentry_preview.colormod = '1 1 1'; - } + sentry_fits = CheckArea(temp_sentry, temp_self); + sentry_preview.colormod = sentry_fits ? '1 1 1' : '1 0.5 0.5'; + } else { + setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! } + FO_CussView(); + + if (zoomed_in) + setviewprop(VF_AFOV, CVARF(fov)/3); + // Draw original sbar, viewsize honoured automatically. if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) setproperty(VF_DRAWENGINESBAR, 1); @@ -723,8 +719,13 @@ noref void CSQC_Input_Frame() { } if (keyups & BUTTON0) { - localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); - SentryPreviewStop(); + if (sentry_fits) { + localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); + SentryPreviewStop(); + } else { + print("Not enough room to build here\n"); + rotating_sentry = FALSE; + } } if (input_buttons & BUTTON0) { From 0d1785db275eef3e9170fcb049ac6636fdc529e8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 22:42:22 +1000 Subject: [PATCH 2394/2474] Stop preview if building --- csqc/events.qc | 3 +++ share/commondefs.qc | 1 + ssqc/engineer.qc | 2 ++ ssqc/status.qc | 10 ++++++++++ 4 files changed, 16 insertions(+) diff --git a/csqc/events.qc b/csqc/events.qc index b15e7733..bc2e30fb 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -359,6 +359,9 @@ void() CSQC_Parse_Event = { flag_team = readfloat(); pick_up_time = time; break; + case MSG_BUILDING: + SentryPreviewStop(); + break; } } diff --git a/share/commondefs.qc b/share/commondefs.qc index e85fa2ad..fe8aabdf 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -214,6 +214,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_HITFLAG 27 #define MSG_RELOADSOUND 28 #define MSG_FLAG_PICKUP 29 +#define MSG_BUILDING 30 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 2fd86a44..38c5ed09 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -615,6 +615,8 @@ void (float objtobuild, float offset) TeamFortress_Build = { return; } } + + UpdateClientBuilding(self); self.is_building = 1; if (!engineer_move) { self.immune_to_check = time + 5; diff --git a/ssqc/status.qc b/ssqc/status.qc index 19d40cf9..0038e6ff 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -757,6 +757,16 @@ string GetSBClassInfo(entity pl, float csqcactive) return st1; } +void UpdateClientBuilding(entity pl) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_BUILDING); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientReloadSound(entity pl, float weapon) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From 7d94ddaadbe03e063ce869cf21258e739ae496e2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 30 Apr 2024 23:06:55 +1000 Subject: [PATCH 2395/2474] Remove flag pickup notification when flag thrown --- csqc/events.qc | 3 +++ share/commondefs.qc | 1 + ssqc/status.qc | 10 ++++++++++ ssqc/tfortmap.qc | 2 ++ 4 files changed, 16 insertions(+) diff --git a/csqc/events.qc b/csqc/events.qc index b15e7733..8f4f6763 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -359,6 +359,9 @@ void() CSQC_Parse_Event = { flag_team = readfloat(); pick_up_time = time; break; + case MSG_FLAG_DROP: + pick_up_time = FALSE; + break; } } diff --git a/share/commondefs.qc b/share/commondefs.qc index e85fa2ad..f6b24f95 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -214,6 +214,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_HITFLAG 27 #define MSG_RELOADSOUND 28 #define MSG_FLAG_PICKUP 29 +#define MSG_FLAG_DROP 30 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/status.qc b/ssqc/status.qc index 19d40cf9..995cf016 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -975,6 +975,16 @@ void (entity pl, float flag_team) UpdateClientFlagPickUp = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void (entity pl) UpdateClientFlagDrop = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_FLAG_DROP); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void (entity pl) RefreshStatusBar = { local string pad; local string s1 = ""; // will be used for grenade timers diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index 03b6763c..1862b5d8 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -3003,4 +3003,6 @@ void () DropGoalItems = { break; } } + + UpdateClientFlagDrop(self); }; From 9ce0a43785bbfe1943e030f1d4c0d5e0d0261ec4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 2 May 2024 22:03:20 +1000 Subject: [PATCH 2396/2474] First pass at mouse rotate --- csqc/events.qc | 9 +++++ csqc/input.qc | 7 +++- csqc/main.qc | 89 +++++++++++++++++++++++++++------------------ csqc/menu.qc | 4 +- share/commondefs.qc | 1 + ssqc/commands.qc | 20 ++++++++-- ssqc/engineer.qc | 2 +- ssqc/mvdsv.qc | 5 ++- ssqc/status.qc | 23 ++++++++++++ 9 files changed, 115 insertions(+), 45 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index bc2e30fb..fe2df944 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -362,6 +362,15 @@ void() CSQC_Parse_Event = { case MSG_BUILDING: SentryPreviewStop(); break; + case MSG_ROTATE_SENTRY: + local vector origin = getentity(readentitynum(), GE_ORIGINANDVECTORS); + setmodel(sentry_rotate, readstring()); + sentry_rotate.frame = readfloat(); + setorigin(sentry_rotate, origin); + sentry_rotate.angles = vectoangles(v_forward); + sentry_rotate.drawmask = MASK_ENGINE; + rotating_sentry = TRUE; + break; } } diff --git a/csqc/input.qc b/csqc/input.qc index 40f5350a..4b5e70a5 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -120,8 +120,13 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { case IE_MOUSEDELTA: local float sensitivity = 0.25; if (rotating_sentry) { + sentry_rotate.angles_y = anglemod(sentry_rotate.angles_y + scanx * sensitivity * -1); + return TRUE; + } + + if (rotating_preview) { sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * sensitivity); - sentry_preview_offset = sentry_preview_offset + scanx * sensitivity; + sentry_preview_offset = (sentry_preview_offset + scanx * sensitivity); return TRUE; } diff --git a/csqc/main.qc b/csqc/main.qc index b5c644cb..5d6e192c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -17,10 +17,12 @@ float InFluid(vector point); float CalculateWaterLevel(); void RenderHitTexts(); entity sentry_preview; +entity sentry_rotate; entity temp_sentry; entity temp_self; float sentry_preview_offset; float previewing_sentry; +float rotating_preview; float rotating_sentry; float prevent_firing; float sentry_fits; @@ -188,9 +190,11 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. precache_model("progs/turrbase.mdl"); + precache_model("progs/turrgun.mdl"); temp_sentry = spawn(); temp_self = spawn(); sentry_preview = spawn(); + sentry_rotate = spawn(); setmodel(sentry_preview, "progs/turrbase.mdl"); sentry_preview.alpha = 0.5; @@ -672,8 +676,14 @@ void FO_ApplyCussInput() { void PM_InputFrame(); +void SentryPreviewStart() { + sentry_preview.angles_y = anglemod(input_angles_y + 180); + sentry_preview.drawmask = MASK_ENGINE; + previewing_sentry = TRUE; +} + void SentryPreviewStop() { - rotating_sentry = FALSE; + rotating_preview = FALSE; previewing_sentry = FALSE; sentry_preview_offset = 0; sentry_preview.drawmask = 0; @@ -693,52 +703,59 @@ noref void CSQC_Input_Frame() { (input_buttons & BUTTON4)) input_buttons |= BUTTON0 | BUTTON2; - // Intercept sentry build - if (WP_PlayerClass() == PC_ENGINEER && !getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { - if (input_buttons & BUTTON4) { - if (keydowns & BUTTON4) { - if (!previewing_sentry) { - sentry_preview.angles_y = anglemod(input_angles_y + 180); - sentry_preview.drawmask = MASK_ENGINE; - previewing_sentry = TRUE; - } else { - SentryPreviewStop(); - - if (input_buttons & BUTTON0) { - prevent_firing = TRUE; + if (WP_PlayerClass() == PC_ENGINEER) { + // Intercept sentry build + if (rotating_sentry) { + if (keyups & BUTTON0) { + rotating_sentry = FALSE; + localcmd(sprintf("cmd sentry rotate mouse %f\n", sentry_rotate.angles_y)); + sentry_rotate.drawmask = 0; + } + input_buttons &= ~BUTTON0; + } else if (!getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { + if (input_buttons & BUTTON4) { + if (keydowns & BUTTON4) { + if (!previewing_sentry) { + SentryPreviewStart(); + } else { + SentryPreviewStop(); + + if (input_buttons & BUTTON0) { + prevent_firing = TRUE; + } } } + + input_buttons = input_buttons - BUTTON4; } - input_buttons = input_buttons - BUTTON4; - } + if (previewing_sentry) { + if (keydowns & BUTTON0) { + rotating_preview = TRUE; + } - if (previewing_sentry) { - if (keydowns & BUTTON0) { - rotating_sentry = TRUE; - } + if (keyups & BUTTON0) { + if (sentry_fits) { + localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); + SentryPreviewStop(); + } else { + print("Not enough room to build here\n"); + rotating_preview = FALSE; + } + } - if (keyups & BUTTON0) { - if (sentry_fits) { - localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); - SentryPreviewStop(); - } else { - print("Not enough room to build here\n"); - rotating_sentry = FALSE; + if (input_buttons & BUTTON0) { + input_buttons = input_buttons - BUTTON0; } } - if (input_buttons & BUTTON0) { - input_buttons = input_buttons - BUTTON0; + if (keyups & BUTTON0) { + prevent_firing = FALSE; } - } - if (keyups & BUTTON0) { - prevent_firing = FALSE; - } - - if (prevent_firing) { - input_buttons &= ~BUTTON0; + if (prevent_firing) { + input_buttons &= ~BUTTON0; + } } } diff --git a/csqc/menu.qc b/csqc/menu.qc index 17b341d2..ade4d32a 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -327,7 +327,7 @@ var fo_menu FO_MENU_SENTRY_MAINTAIN = { {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, - MenuSpacer, + {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { @@ -342,7 +342,7 @@ var fo_menu FO_MENU_SENTRY_ROTATE = { {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, - MenuSpacer, + {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { diff --git a/share/commondefs.qc b/share/commondefs.qc index fe8aabdf..cc225d9b 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -215,6 +215,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_RELOADSOUND 28 #define MSG_FLAG_PICKUP 29 #define MSG_BUILDING 30 +#define MSG_ROTATE_SENTRY 31 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a261632b..367c4e9d 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -313,10 +313,10 @@ void (entity pl) PrintWho = { strunzone(msg); } -float (string arg1, string arg2, string arg3) ParseCmds = { +float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; - local float farg2, farg3; + local float farg2, farg3, farg4; local entity ent, pl; processedCmd = FALSE; @@ -757,6 +757,20 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); break; } + if (arg3 == "mouse") { + if (!arg4) { + ent.dimension_ghost = ent.dimension_seen; + UpdateClientRotateSentry(self, ent); + break; + } else { + farg4 = stof(arg4); + ent.dimension_ghost = FALSE; + ent.angles_y = farg4; + ent.waitmin = anglemod(farg4 - 50); + ent.waitmax = anglemod(farg4 + 50); + break; + } + } if(farg3 < 0) { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); } else { @@ -1377,7 +1391,7 @@ void (string cmd) SV_ParseClientCommand = { float isProcessed; tokenize(cmd); - isProcessed = ParseCmds(argv(0), argv(1), argv(2)); + isProcessed = ParseCmds(argv(0), argv(1), argv(2), argv(3)); if (!isProcessed) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 38c5ed09..7c9e9732 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -944,7 +944,6 @@ void UpdateClient_Dispenser(entity pl, entity disp) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } - void () TeamFortress_FinishedBuilding = { local entity oldself; if (engineer_move) { @@ -1040,6 +1039,7 @@ void () TeamFortress_FinishedBuilding = { newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.mdl = "progs/turrgun.mdl"; + newmis.dimension_ghost_alpha = 0.25; self.sentry_ent = newmis; FO_Sound(oldself, CHAN_ITEM, "weapons/turrset.wav", 1, 1); newmis.solid = SOLID_BBOX; diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index d77e8df5..11147cd9 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -1,12 +1,13 @@ float () UserCmd = { float isProcessed; - string arg1, arg2, arg3; + string arg1, arg2, arg3, arg4; arg1 = argv_mvdsv(0); arg2 = argv_mvdsv(1); arg3 = argv_mvdsv(2); + arg4 = argv_mvdsv(3); - isProcessed = ParseCmds(arg1, arg2, arg3); + isProcessed = ParseCmds(arg1, arg2, arg3, arg4); return (isProcessed); }; diff --git a/ssqc/status.qc b/ssqc/status.qc index 0038e6ff..4e9557fa 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -767,6 +767,29 @@ void UpdateClientBuilding(entity pl) { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientRotateSentry(entity pl, entity sentry) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_ROTATE_SENTRY); + WriteEntity(MSG_MULTICAST, sentry); + WriteString(MSG_MULTICAST, sentry.model); + + local float frame_no; + if (sentry.frame >= 6) { + frame_no = 6; + } else if (sentry.frame >= 3) { + frame_no = 3; + } else { + frame_no = 0; + } + + WriteFloat(MSG_MULTICAST, frame_no); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientReloadSound(entity pl, float weapon) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From 3bd8bb973486d4fbccf181228ba8f7aa232607ef Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 2 May 2024 22:05:54 +1000 Subject: [PATCH 2397/2474] Error go away --- ssqc/commands.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 367c4e9d..2f9a7134 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -1316,7 +1316,7 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { break; case "play_to_completion": if(arg2 != "0" && arg2 != "1") - return; + break; processedCmd = TRUE; localcmd ("localinfo play_to_completion ",arg2,"\n"); From b09d3b621924af8878dac846f07faba9d1aa9c20 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 3 May 2024 00:50:31 +1000 Subject: [PATCH 2398/2474] WIP do cool things with dimensions, don't send model string, it's already known --- csqc/events.qc | 2 +- csqc/main.qc | 17 +++++++++++++---- share/defs.h | 4 +++- ssqc/client.qc | 10 +++++----- ssqc/commands.qc | 37 +++++++++++++++++++++++-------------- ssqc/engineer.qc | 1 + ssqc/player.qc | 2 ++ ssqc/qw.qc | 3 ++- ssqc/status.qc | 1 - 9 files changed, 50 insertions(+), 27 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index fe2df944..cf8f9a75 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -364,8 +364,8 @@ void() CSQC_Parse_Event = { break; case MSG_ROTATE_SENTRY: local vector origin = getentity(readentitynum(), GE_ORIGINANDVECTORS); - setmodel(sentry_rotate, readstring()); sentry_rotate.frame = readfloat(); + setmodel(sentry_rotate, "progs/turrgun.mdl"); setorigin(sentry_rotate, origin); sentry_rotate.angles = vectoangles(v_forward); sentry_rotate.drawmask = MASK_ENGINE; diff --git a/csqc/main.qc b/csqc/main.qc index 5d6e192c..c943c1f2 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -689,6 +689,11 @@ void SentryPreviewStop() { sentry_preview.drawmask = 0; } +void SentryRotateStop() { + rotating_sentry = FALSE; + sentry_rotate.drawmask = 0; +} + noref void CSQC_Input_Frame() { local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; @@ -707,9 +712,8 @@ noref void CSQC_Input_Frame() { // Intercept sentry build if (rotating_sentry) { if (keyups & BUTTON0) { - rotating_sentry = FALSE; localcmd(sprintf("cmd sentry rotate mouse %f\n", sentry_rotate.angles_y)); - sentry_rotate.drawmask = 0; + SentryRotateStop(); } input_buttons &= ~BUTTON0; } else if (!getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { @@ -829,8 +833,13 @@ void _Sync_ServerCommandFrame() { CsGrenTimer::UpdateSoundStack(); UpdateTeamColorCrosshair(); - if (!game_state.is_alive && previewing_sentry) { - SentryPreviewStop(); + if (!game_state.is_alive) { + if (previewing_sentry) + SentryPreviewStop(); + + if (rotating_sentry) { + SentryRotateStop(); + } } } diff --git a/share/defs.h b/share/defs.h index ebd8b3b0..979dbe52 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1467,10 +1467,12 @@ enum { // all bits between 1 and 255 are reserved for flash #define DMN_NOFLASH 256 // see all the things #define DMN_TEAMBLUE 512 -#define DMN_TEAMRED 1024 +#define DMN_TEAMRED 1024 #define DMN_TEAMYELL 2048 #define DMN_TEAMGREN 4096 #define DMN_INVISIBLE 8192 // special dimension to hide stuff in +#define DMN_HIDDEN 16384 // put an entity here instead of noflash, then remove DMN_HIDDEN from a player's dimension_see to hide it from that player +#define DMN_GHOST 32768 // put ghosts in here // trigger_push #define PUSH_ONCE 1 diff --git a/ssqc/client.qc b/ssqc/client.qc index 5854eaa5..74b32ab3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2101,19 +2101,19 @@ void (float all_dimensions) SetDimensions = { switch (self.team_no) { case TEAM_BLUE: - self.dimension_see = DMN_NOFLASH | DMN_TEAMBLUE; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMBLUE; break; case TEAM_RED: - self.dimension_see = DMN_NOFLASH | DMN_TEAMRED; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMRED; break; case TEAM_YELL: - self.dimension_see = DMN_NOFLASH | DMN_TEAMYELL; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMYELL; break; case TEAM_GREN: - self.dimension_see = DMN_NOFLASH | DMN_TEAMGREN; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMGREN; break; default: - self.dimension_see = DMN_NOFLASH; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN; break; } } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 2f9a7134..b719bc6a 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -731,11 +731,25 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { sprint(self, PRINT_HIGH, "Only engineers can do that!\n"); break; } + if(self.health <= 0) { sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); break; } - + + if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mouse" && arg4) { + self.dimension_see = (self.dimension_see & ~DMN_GHOST) | DMN_HIDDEN; + + local entity rs = self.rotating_sentry; + farg4 = stof(arg4); + + rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; + rs.angles_y = farg4; + rs.waitmin = anglemod(farg4 - 50); + rs.waitmax = anglemod(farg4 + 50); + break; + } + //find sentry first ent = findradius(self.origin, ENG_BUILDING_MAINT_DISTANCE); while (ent) { @@ -745,10 +759,12 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { } ent = ent.chain; } + if (!ent) { sprint(self, PRINT_HIGH, "No sentry in range\n"); break; } + if (arg2 && arg3) { if(arg2 == "rotate") { farg3 = stof(arg3); @@ -757,19 +773,12 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); break; } - if (arg3 == "mouse") { - if (!arg4) { - ent.dimension_ghost = ent.dimension_seen; - UpdateClientRotateSentry(self, ent); - break; - } else { - farg4 = stof(arg4); - ent.dimension_ghost = FALSE; - ent.angles_y = farg4; - ent.waitmin = anglemod(farg4 - 50); - ent.waitmax = anglemod(farg4 + 50); - break; - } + if (arg3 == "mouse" && !arg4) { + self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; + ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; + UpdateClientRotateSentry(self, ent); + self.rotating_sentry = ent; + break; } if(farg3 < 0) { sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 7c9e9732..e3dc3e88 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1039,6 +1039,7 @@ void () TeamFortress_FinishedBuilding = { newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.mdl = "progs/turrgun.mdl"; + newmis.dimension_ghost = DMN_GHOST; newmis.dimension_ghost_alpha = 0.25; self.sentry_ent = newmis; FO_Sound(oldself, CHAN_ITEM, "weapons/turrset.wav", 1, 1); diff --git a/ssqc/player.qc b/ssqc/player.qc index a934ed92..444e7a94 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -439,6 +439,8 @@ void () GibPlayer = { }; void () PlayerDie = { + self.rotating_sentry.dimension_ghost = 0; + self.spawn_gen += 1; self.last_death_ctime = self.client_time; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 96e73c72..837fdf6e 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -202,7 +202,8 @@ float coop; .entity real_owner; .float has_dispenser; // TRUE for an ENGINEER if he has a dispenser .float has_sentry; // TRUE for an ENGINEER if he has a sentry -.entity sentry_ent; // Contains sentry gun entity +.entity sentry_ent; // Contains sentry gun entity +.entity rotating_sentry; // Contains sentry gun currently being rotated .float real_frags; // Used to store the players frags when TeamFrags is On diff --git a/ssqc/status.qc b/ssqc/status.qc index 4e9557fa..4a838d82 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -775,7 +775,6 @@ void UpdateClientRotateSentry(entity pl, entity sentry) { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, MSG_ROTATE_SENTRY); WriteEntity(MSG_MULTICAST, sentry); - WriteString(MSG_MULTICAST, sentry.model); local float frame_no; if (sentry.frame >= 6) { From e558f1be85933d4404dbcffe03058567d2874c99 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 3 May 2024 19:56:28 +1000 Subject: [PATCH 2399/2474] Play sound, don't allow rotate when already rotating --- csqc/events.qc | 5 ++++- share/commondefs.qc | 3 ++- ssqc/commands.qc | 13 ++++++++++--- ssqc/player.qc | 4 +++- ssqc/sentry.qc | 12 ++++++++---- ssqc/status.qc | 14 ++++++++++++-- 6 files changed, 39 insertions(+), 12 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index cf8f9a75..4afcd1b8 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -362,7 +362,7 @@ void() CSQC_Parse_Event = { case MSG_BUILDING: SentryPreviewStop(); break; - case MSG_ROTATE_SENTRY: + case MSG_SENTRY_ROTATE: local vector origin = getentity(readentitynum(), GE_ORIGINANDVECTORS); sentry_rotate.frame = readfloat(); setmodel(sentry_rotate, "progs/turrgun.mdl"); @@ -371,6 +371,9 @@ void() CSQC_Parse_Event = { sentry_rotate.drawmask = MASK_ENGINE; rotating_sentry = TRUE; break; + case MSG_SENTRY_DIE: + SentryRotateStop(); + break; } } diff --git a/share/commondefs.qc b/share/commondefs.qc index cc225d9b..cff132ab 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -215,7 +215,8 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_RELOADSOUND 28 #define MSG_FLAG_PICKUP 29 #define MSG_BUILDING 30 -#define MSG_ROTATE_SENTRY 31 +#define MSG_SENTRY_ROTATE 31 +#define MSG_SENTRY_DIE 32 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index b719bc6a..276a71e9 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -738,15 +738,19 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { } if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mouse" && arg4) { + if (self.rotating_sentry == world) + break; + self.dimension_see = (self.dimension_see & ~DMN_GHOST) | DMN_HIDDEN; local entity rs = self.rotating_sentry; - farg4 = stof(arg4); - rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; + farg4 = stof(arg4); rs.angles_y = farg4; rs.waitmin = anglemod(farg4 - 50); rs.waitmax = anglemod(farg4 + 50); + FO_Sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, ATTN_NORM); + self.rotating_sentry = world; break; } @@ -774,9 +778,12 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { break; } if (arg3 == "mouse" && !arg4) { + if (!self.rotating_sentry == world) + break; + self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; - UpdateClientRotateSentry(self, ent); + UpdateClientSentryRotate(self, ent); self.rotating_sentry = ent; break; } diff --git a/ssqc/player.qc b/ssqc/player.qc index 444e7a94..f2dedd1f 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -439,7 +439,9 @@ void () GibPlayer = { }; void () PlayerDie = { - self.rotating_sentry.dimension_ghost = 0; + local entity rs = self.rotating_sentry; + rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; + self.rotating_sentry == world; self.spawn_gen += 1; self.last_death_ctime = self.client_time; diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 78305792..3dc70e64 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -374,13 +374,17 @@ void () Sentry_Explode = { void () Sentry_Die = { sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); stuffcmd(self.real_owner, "play misc/chink.wav\n"); - self.real_owner.has_sentry = 0; - + local entity ro = self.real_owner; + ro.has_sentry = 0; + ro.dimension_see = (ro.dimension_see & ~DMN_GHOST) | DMN_HIDDEN; + UpdateClientSentryDie(ro); + ro.rotating_sentry = world; + self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; self.think = Sentry_Explode; self.nextthink = time + 0.1; - if (self.real_owner.is_building) { - self = self.real_owner; + if (ro.is_building) { + self = ro; TeamFortress_EngineerBuildStop(); } }; diff --git a/ssqc/status.qc b/ssqc/status.qc index 4a838d82..acab30da 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -767,13 +767,13 @@ void UpdateClientBuilding(entity pl) { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -void UpdateClientRotateSentry(entity pl, entity sentry) { +void UpdateClientSentryRotate(entity pl, entity sentry) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; msg_entity = pl; WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_ROTATE_SENTRY); + WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE); WriteEntity(MSG_MULTICAST, sentry); local float frame_no; @@ -789,6 +789,16 @@ void UpdateClientRotateSentry(entity pl, entity sentry) { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientSentryDie(entity pl) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_SENTRY_DIE); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientReloadSound(entity pl, float weapon) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From e589b9756a78e7a9090031fc2b8307f42d9839c4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 10 May 2024 00:12:50 +1000 Subject: [PATCH 2400/2474] Fix token exposure --- csqc/main.qc | 4 ++-- ssqc/commands.qc | 4 ++-- ssqc/login.qc | 3 +-- ssqc/quadmode.qc | 9 ++------- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index f25a5d9e..23cd0252 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -758,8 +758,8 @@ float FoLogin(string token, float print_error) { return FALSE; } - localcmd("setinfo _fo_token ", token, "\n"); - localcmd("cmd fo-login-silent\n"); + localcmd("setinfo _fo_token \"\"\n"); + localcmd(sprintf("cmd fo-login-silent %s\n", token)); return TRUE; } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 5a7bf0f2..908a2613 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -956,13 +956,13 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if (self.fo_login != string_null) { sprint (self, PRINT_HIGH, "You are logged in\n"); } else { - performFoLogin(self); + performFoLogin(self, arg2); } break; case "fo-login-silent": processedCmd = TRUE; if (self.fo_login == string_null) - performFoLogin(self); + performFoLogin(self, arg2); break; case "who": processedCmd = TRUE; diff --git a/ssqc/login.qc b/ssqc/login.qc index 2e2f472f..50c394aa 100644 --- a/ssqc/login.qc +++ b/ssqc/login.qc @@ -13,9 +13,8 @@ void (entity player, string login, string secret) performLogin = { dprint("\n"); } -void (entity player) performFoLogin = { +void (entity player, string token) performFoLogin = { local string uri = sprintf("%s/results/api/v1/fo_login", backend_address); - local string token = FO_GetUserSettingString(player, "_fo_token", "fo_token", ""); uri_get(uri, FO_LOGIN_REQUEST, "application/json", sprintf("{ \"auth_token\": \"%s\" }", token)); dprint(sprintf("%s [%s] logging in\n", infokey(player, "name"), infokey(player, "ip"))); } diff --git a/ssqc/quadmode.qc b/ssqc/quadmode.qc index 1e430e87..d222137a 100644 --- a/ssqc/quadmode.qc +++ b/ssqc/quadmode.qc @@ -56,7 +56,6 @@ void () PostFOQuadStarted = { local float tn; local float prefix_comma; local entity p; - local string token; for (tn = 1; tn <= number_of_teams; ++tn) { data = strcat(data, " \"", ftos(tn), "\": {\n"); @@ -70,9 +69,8 @@ void () PostFOQuadStarted = { if (prefix_comma) data = strcat(data, ","); - token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); data = strcat(data, " {\n"); - data = strcat(data, " \"auth_token\": \"", token, "\",\n"); + data = strcat(data, " \"id\": \"", p.fo_login, "\",\n"); data = strcat(data, " \"playerclass\": \"", ftos(p.playerclass), "\"\n"); data = strcat(data, " }\n"); prefix_comma = TRUE; @@ -115,7 +113,6 @@ void () PostFOQuadFinalRoundStarted = { local float tn; local float prefix_comma; local entity p; - local string token; for (tn = 1; tn <= number_of_teams; ++tn) { local float score = TeamFortress_TeamGetScore(tn); @@ -132,9 +129,8 @@ void () PostFOQuadFinalRoundStarted = { if (prefix_comma) data = strcat(data, ","); - token = FO_GetUserSettingString(p, "_fo_token", "fo_token", ""); data = strcat(data, " {\n"); - data = strcat(data, " \"auth_token\": \"", token, "\",\n"); + data = strcat(data, " \"id\": \"", p.fo_login, "\",\n"); data = strcat(data, " \"playerclass\": \"", ftos(p.playerclass), "\"\n"); data = strcat(data, " }\n"); prefix_comma = TRUE; @@ -187,7 +183,6 @@ void (float winner) PostFOQuadFinished = { local float tn; local float prefix_comma; local entity p; - local string token; for (tn = 1; tn <= number_of_teams; ++tn) { local float score = TeamFortress_TeamGetScore(tn); From 317c8562e4f4d3dd8569175e84f822af2d851a3d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 10 May 2024 01:23:03 +1000 Subject: [PATCH 2401/2474] Make flag pickup a little less obnoxious --- csqc/status.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csqc/status.qc b/csqc/status.qc index 380e14f5..00b40211 100644 --- a/csqc/status.qc +++ b/csqc/status.qc @@ -607,7 +607,7 @@ void(PanelID panelid, string text) drawNotificationPanel = { } } } else if (pick_up_time && time < pick_up_time + 1.5) { - local vector alert_text_size = MENU_TEXT_MEDIUM * panel.Scale; + local vector alert_text_size = MENU_TEXT_SMALL * panel.Scale; local vector alert_text_position; alert_text_position.y = ScreenSize.y / 3; alert_text_position.x = (ScreenSize.x / 2) - (size.x / 2); From d88b4d55f821de050df73d68561b69b21414c57b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 12 May 2024 01:35:05 +1000 Subject: [PATCH 2402/2474] Add sentry rotation options, range indicator --- csqc/events.qc | 21 ++++++++++++-- csqc/main.qc | 68 ++++++++++++++++++++++++++++++++++++++++----- share/commondefs.qc | 1 + ssqc/commands.qc | 15 +++++++++- ssqc/status.qc | 23 +++++++++++++++ 5 files changed, 117 insertions(+), 11 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 4afcd1b8..d1489c22 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -363,14 +363,29 @@ void() CSQC_Parse_Event = { SentryPreviewStop(); break; case MSG_SENTRY_ROTATE: + sentry_rotate.drawmask = MASK_ENGINE; + local vector origin = getentity(readentitynum(), GE_ORIGINANDVECTORS); - sentry_rotate.frame = readfloat(); - setmodel(sentry_rotate, "progs/turrgun.mdl"); setorigin(sentry_rotate, origin); sentry_rotate.angles = vectoangles(v_forward); - sentry_rotate.drawmask = MASK_ENGINE; + sentry_rotate.frame = readfloat(); rotating_sentry = TRUE; break; + case MSG_SENTRY_ROTATE_BY: + local vector origin = getentity(readentitynum(), GE_ORIGINANDVECTORS); + sentry_rotate.frame = readfloat(); + local float offset = readfloat() * -1; + + if (!rotating_sentry) { + rotating_sentry = TRUE; + setorigin(sentry_rotate, origin); + sentry_rotate.angles = vectoangles(v_forward); + sentry_rotate.angles_y += offset; + sentry_rotate.drawmask = MASK_ENGINE; + } + + sentry_rotate.angles_y += offset; + break; case MSG_SENTRY_DIE: SentryRotateStop(); break; diff --git a/csqc/main.qc b/csqc/main.qc index c943c1f2..50c610f5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -17,6 +17,7 @@ float InFluid(vector point); float CalculateWaterLevel(); void RenderHitTexts(); entity sentry_preview; +entity sentry_preview_range_sphere; entity sentry_rotate; entity temp_sentry; entity temp_self; @@ -31,6 +32,27 @@ void GetSelf() = { self = findfloat(world, entnum, player_localentnum); } +/* vector AnglesToVector(vector angles) { */ +/* float pitch, yaw, roll; */ +/* vector dir; */ + +/* pitch = angles_x * (M_PI / 180.0); */ +/* yaw = angles_y * (M_PI / 180.0); */ +/* roll = angles_z * (M_PI / 180.0); */ + +/* dir_x = cos(yaw) * cos(pitch); */ +/* dir_y = sin(yaw) * cos(pitch); */ +/* dir_z = -sin(pitch); */ + +/* return dir; */ +/* } */ + +/* vector GetNewPosition(entity ent, vector angle_offsets, float distance) { */ +/* vector dir = AnglesToVector(ent.angles + angle_offsets); */ +/* vector new_position = ent.origin + dir * distance; */ +/* return new_position; */ +/* } */ + void PushToSlotHistory(float value) { if (slot_history_top >= MAX_SLOT_HISTORY_SIZE) { // Stack is full @@ -189,15 +211,24 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. - precache_model("progs/turrbase.mdl"); - precache_model("progs/turrgun.mdl"); temp_sentry = spawn(); temp_self = spawn(); + + precache_model("progs/turrbase.mdl"); sentry_preview = spawn(); - sentry_rotate = spawn(); setmodel(sentry_preview, "progs/turrbase.mdl"); sentry_preview.alpha = 0.5; + precache_model("progs/sphere.mdl"); + sentry_preview_range_sphere = spawn(); + setmodel(sentry_preview_range_sphere, "progs/sphere.mdl"); + sentry_preview_range_sphere.scale = 1000; + sentry_preview_range_sphere.alpha = 0.02; + + precache_model("progs/turrgun.mdl"); + sentry_rotate = spawn(); + setmodel(sentry_rotate, "progs/turrgun.mdl"); + print("CSQC initialization finished\n"); }; @@ -225,12 +256,14 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (previewing_sentry) { makevectors(input_angles); v_forward_z = 0; - v_forward = normalize(v_forward) * 64; - sentry_preview.origin = PM_Org() + v_forward; + local vector v_forward_sentry = normalize(v_forward) * 64; + sentry_preview.origin = PM_Org() + v_forward_sentry; setorigin(temp_self, PM_Org()); temp_sentry.origin = sentry_preview.origin; sentry_fits = CheckArea(temp_sentry, temp_self); sentry_preview.colormod = sentry_fits ? '1 1 1' : '1 0.5 0.5'; + local vector v_forward_range = normalize(v_forward) * 1024; + sentry_preview_range_sphere.origin = sentry_preview.origin; } else { setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! } @@ -677,16 +710,37 @@ void FO_ApplyCussInput() { void PM_InputFrame(); void SentryPreviewStart() { - sentry_preview.angles_y = anglemod(input_angles_y + 180); + sentry_preview_offset = 180; + sentry_preview.angles_y = input_angles_y; sentry_preview.drawmask = MASK_ENGINE; + + local vector sphere_colormod = '1 1 1'; + switch (team_no) { + case 1: + sphere_colormod = '0 0.4 1'; + break; + case 2: + sphere_colormod = '1 0 0'; + break; + case 3: + sphere_colormod = '1 1 0'; + break; + case 4: + sphere_colormod = '0 1 0'; + break; + } + + sentry_preview_range_sphere.colormod = sphere_colormod * 4; + sentry_preview_range_sphere.drawmask = MASK_ENGINE; + previewing_sentry = TRUE; } void SentryPreviewStop() { rotating_preview = FALSE; previewing_sentry = FALSE; - sentry_preview_offset = 0; sentry_preview.drawmask = 0; + sentry_preview_range_sphere.drawmask = 0; } void SentryRotateStop() { diff --git a/share/commondefs.qc b/share/commondefs.qc index cff132ab..cc399d6c 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -217,6 +217,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_BUILDING 30 #define MSG_SENTRY_ROTATE 31 #define MSG_SENTRY_DIE 32 +#define MSG_SENTRY_ROTATE_BY 33 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 276a71e9..86e0b10e 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -764,6 +764,19 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { ent = ent.chain; } + if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mwheel" && arg4) { + if (!arg4) + break; + + farg4 = stof(arg4); + self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; + ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; + if (self.rotating_sentry == world) + self.rotating_sentry = ent; + UpdateClientSentryRotateBy(self, self.rotating_sentry, farg4); + break; + } + if (!ent) { sprint(self, PRINT_HIGH, "No sentry in range\n"); break; @@ -783,8 +796,8 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; - UpdateClientSentryRotate(self, ent); self.rotating_sentry = ent; + UpdateClientSentryRotate(self, ent); break; } if(farg3 < 0) { diff --git a/ssqc/status.qc b/ssqc/status.qc index acab30da..f7467747 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -789,6 +789,29 @@ void UpdateClientSentryRotate(entity pl, entity sentry) { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClientSentryRotateBy(entity pl, entity sentry, float offset) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE_BY); + WriteEntity(MSG_MULTICAST, sentry); + + local float frame_no; + if (sentry.frame >= 6) { + frame_no = 6; + } else if (sentry.frame >= 3) { + frame_no = 3; + } else { + frame_no = 0; + } + + WriteFloat(MSG_MULTICAST, frame_no); + WriteFloat(MSG_MULTICAST, offset); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientSentryDie(entity pl) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From 3cc82c87dc1647a42d7b791e0d4614de6042d4c6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 13 May 2024 20:06:10 +1000 Subject: [PATCH 2403/2474] refactor --- share/engineer.qc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/share/engineer.qc b/share/engineer.qc index 46b9337c..c7c5bdd7 100644 --- a/share/engineer.qc +++ b/share/engineer.qc @@ -5,43 +5,43 @@ float (entity obj, entity builder) CheckArea = { local entity te; pos = pointcontents(obj.origin); - if ((pos == -2) || (pos == -6)) { + if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } src_x = (obj.origin_x + obj.maxs_x) + 24; src_y = (obj.origin_y + obj.maxs_y) + 24; - src_z = (obj.origin_z + obj.maxs_z) + 16; + src_z = (obj.origin_z + obj.maxs_z); pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { + if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } end_x = (obj.origin_x + obj.mins_x) - 16; end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; + end_z = (obj.origin_z + obj.mins_z); traceline(src, end, 1, obj); if (trace_fraction != 1) { return (0); } pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { + if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } src_x = (obj.origin_x + obj.mins_x) - 16; src_y = (obj.origin_y + obj.maxs_y) + 16; - src_z = (obj.origin_z + obj.maxs_z) + 16; + src_z = (obj.origin_z + obj.maxs_z); pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { + if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } end_x = (obj.origin_x + obj.maxs_x) + 16; end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; + end_z = (obj.origin_z + obj.mins_z); traceline(src, end, 1, obj); if (trace_fraction != 1) { return (0); } pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { + if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } traceline(builder.origin, obj.origin, 1, builder); From d3580207028793282cd6db965eb86ec166cb99d9 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 13 May 2024 20:06:48 +1000 Subject: [PATCH 2404/2474] Allow gun placement on z axis, part 1: preview --- csqc/main.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index 50c610f5..9cec9f8c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -255,8 +255,11 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (previewing_sentry) { makevectors(input_angles); + local vector sentry_preview_pos; + sentry_preview_pos.z = (normalize(v_forward) * 64).z; v_forward_z = 0; local vector v_forward_sentry = normalize(v_forward) * 64; + v_forward_sentry.z = sentry_preview_pos.z; sentry_preview.origin = PM_Org() + v_forward_sentry; setorigin(temp_self, PM_Org()); temp_sentry.origin = sentry_preview.origin; @@ -268,6 +271,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! } + FO_CussView(); if (zoomed_in) From 54ea3f83c0db541ff9600ec189a31ca790eaaabd Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 14 May 2024 16:44:14 +1000 Subject: [PATCH 2405/2474] Lock only mouse y axis when rotating sentry --- csqc/input.qc | 2 -- csqc/main.qc | 13 +++++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 4b5e70a5..5b0764bd 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -121,13 +121,11 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { local float sensitivity = 0.25; if (rotating_sentry) { sentry_rotate.angles_y = anglemod(sentry_rotate.angles_y + scanx * sensitivity * -1); - return TRUE; } if (rotating_preview) { sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * sensitivity); sentry_preview_offset = (sentry_preview_offset + scanx * sensitivity); - return TRUE; } if (previewing_sentry) { diff --git a/csqc/main.qc b/csqc/main.qc index 9cec9f8c..60372643 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -24,7 +24,9 @@ entity temp_self; float sentry_preview_offset; float previewing_sentry; float rotating_preview; +float rotating_preview_y; float rotating_sentry; +float rotating_sentry_y; float prevent_firing; float sentry_fits; @@ -267,11 +269,14 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { sentry_preview.colormod = sentry_fits ? '1 1 1' : '1 0.5 0.5'; local vector v_forward_range = normalize(v_forward) * 1024; sentry_preview_range_sphere.origin = sentry_preview.origin; + + if (rotating_preview) { + setviewprop(VF_CL_VIEWANGLES_Y, rotating_preview_y); + } } else { setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! } - FO_CussView(); if (zoomed_in) @@ -742,6 +747,7 @@ void SentryPreviewStart() { void SentryPreviewStop() { rotating_preview = FALSE; + rotating_preview_y = 0; previewing_sentry = FALSE; sentry_preview.drawmask = 0; sentry_preview_range_sphere.drawmask = 0; @@ -749,6 +755,7 @@ void SentryPreviewStop() { void SentryRotateStop() { rotating_sentry = FALSE; + rotating_sentry_y = 0; sentry_rotate.drawmask = 0; } @@ -793,15 +800,17 @@ noref void CSQC_Input_Frame() { if (previewing_sentry) { if (keydowns & BUTTON0) { + rotating_preview_y = input_angles_y; rotating_preview = TRUE; } if (keyups & BUTTON0) { if (sentry_fits) { - localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); + localcmd(sprintf("cmd build sentry %f\n", -1 * sentry_preview_offset)); SentryPreviewStop(); } else { print("Not enough room to build here\n"); + rotating_preview_y = 0; rotating_preview = FALSE; } } From 8475cc8db83faeff7e57dcd7621b537a1c46ea4d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 May 2024 01:57:51 +1000 Subject: [PATCH 2406/2474] Allow player to build more intuitively --- csqc/input.qc | 7 +++---- csqc/main.qc | 53 ++++++++++++++++++++++++++++-------------------- ssqc/engineer.qc | 17 ++++++++++++++-- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 5b0764bd..1c16e44e 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -118,14 +118,13 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } break; case IE_MOUSEDELTA: - local float sensitivity = 0.25; if (rotating_sentry) { - sentry_rotate.angles_y = anglemod(sentry_rotate.angles_y + scanx * sensitivity * -1); + sentry_rotate.angles_y = anglemod(sentry_rotate.angles_y + scanx * rotating_sensitivity * -1); } if (rotating_preview) { - sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * sensitivity); - sentry_preview_offset = (sentry_preview_offset + scanx * sensitivity); + sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * rotating_sensitivity); + sentry_preview_offset = (sentry_preview_offset + scanx * rotating_sensitivity); } if (previewing_sentry) { diff --git a/csqc/main.qc b/csqc/main.qc index 130824fe..3d479f72 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -27,6 +27,7 @@ float rotating_preview; float rotating_preview_y; float rotating_sentry; float rotating_sentry_y; +float rotating_sensitivity = 0.25; float prevent_firing; float sentry_fits; @@ -255,28 +256,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! - if (previewing_sentry) { - makevectors(input_angles); - local vector sentry_preview_pos; - sentry_preview_pos.z = (normalize(v_forward) * 64).z; - v_forward_z = 0; - local vector v_forward_sentry = normalize(v_forward) * 64; - v_forward_sentry.z = sentry_preview_pos.z; - sentry_preview.origin = PM_Org() + v_forward_sentry; - setorigin(temp_self, PM_Org()); - temp_sentry.origin = sentry_preview.origin; - sentry_fits = CheckArea(temp_sentry, temp_self); - sentry_preview.colormod = sentry_fits ? '1 1 1' : '1 0.5 0.5'; - local vector v_forward_range = normalize(v_forward) * 1024; - sentry_preview_range_sphere.origin = sentry_preview.origin; - - if (rotating_preview) { - setviewprop(VF_CL_VIEWANGLES_Y, rotating_preview_y); - } - } else { - setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! - } - FO_CussView(); if (zoomed_in) @@ -294,6 +273,33 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (PM_Enabled()) PM_UpdateView(); + if (previewing_sentry) { + makevectors(view_angles); + + // can probably use trig here so we don't need to normalize twice + local vector z_pos; + z_pos.z = (normalize(v_forward) * 64).z; + v_forward_z = 0; + local vector xy_pos = normalize(v_forward) * 64; + + local vector v_forward_sentry; + v_forward_sentry.x = xy_pos.x; + v_forward_sentry.y = xy_pos.y; + v_forward_sentry.z = z_pos.z; + + sentry_preview.origin = PM_Org() + v_forward_sentry; + setorigin(temp_self, sentry_preview.origin); + temp_sentry.origin = sentry_preview.origin; + local vector v_forward_range = normalize(v_forward) * 1024; + sentry_preview_range_sphere.origin = sentry_preview.origin; + + if (rotating_preview) { + setviewprop(VF_CL_VIEWANGLES_Y, rotating_preview_y); + } + } else { + setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + } + renderscene(); FO_CussCrosshair(width, height); @@ -908,6 +914,9 @@ void _Sync_ServerCommandFrame() { SentryRotateStop(); } } + + sentry_fits = CheckArea(temp_sentry, temp_self); + sentry_preview.colormod = sentry_fits ? '1 1 1' : '1 0.5 0.5'; } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index e3dc3e88..9081e23e 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -554,10 +554,23 @@ void (float objtobuild, float offset) TeamFortress_Build = { tmp2 = '0 0 0'; newmis = spawn(); + makevectors(self.v_angle); + /* v_forward_z = 0; */ + /* v_forward = normalize(v_forward) * 64; */ + /* newmis.origin = self.origin + v_forward; */ + + local vector z_pos; + z_pos.z = (normalize(v_forward) * 64).z; v_forward_z = 0; - v_forward = normalize(v_forward) * 64; - newmis.origin = self.origin + v_forward; + local vector xy_pos = normalize(v_forward) * 64; + + local vector v_forward_sentry; + v_forward_sentry.x = xy_pos.x; + v_forward_sentry.y = xy_pos.y; + v_forward_sentry.z = z_pos.z; + + newmis.origin = self.origin + v_forward_sentry; tmp1 = newmis.origin; tmp2 = newmis.origin - normalize(v_up) * 128; From 4698bd72f839d2cf487b206c5a941f385298ded7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 15 May 2024 23:05:41 +1000 Subject: [PATCH 2407/2474] Refactor --- ssqc/menu.qc | 137 +++++++++++++++++++++++---------------------------- 1 file changed, 61 insertions(+), 76 deletions(-) diff --git a/ssqc/menu.qc b/ssqc/menu.qc index e3ef9dc1..875bd996 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -816,92 +816,77 @@ void (float offset) TeamFortress_BuildSentry = { } void (float inp) Menu_Engineer_Input = { - local float dismantle_sentrygun; - local float dismantle_dispenser; - local entity te; + switch (inp) { + case 5: + break; - if (inp == 5) - return; + // build dispenser + case 1: + TeamFortress_BuildSentry(0); + break; - if (inp == 3 && self.has_sentry) { - te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); - while (te) { - if (te.classname == "building_sentrygun") { - if (te.real_owner == self && te.weapon == 0){ - sprint (self, PRINT_HIGH, strcat("You stopped building a sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); - self.ammo_cells = self.ammo_cells + ENG_SENTRY_COST; - if (self.ammo_cells > self.maxammo_cells) - self.ammo_cells = self.maxammo_cells; - if (te.trigger_field != world) - dremove (te.trigger_field); - self = te.real_owner; - TeamFortress_EngineerBuildStop(); - return; - } + // build sentry + case 2: + if (!self.has_dispenser) { + if (self.ammo_cells >= ENG_DISPENSER_COST) + TeamFortress_Build(1, 0); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); } - te = te.chain; - } - } - - if (self.is_building) { - if (engineer_move) { - Status_Print(self, "\n\n\n\n\n\n\n", strcat("You are already building something")); - return; - } - Menu_Engineer(self); - return; - } - - dismantle_sentrygun = 0; - dismantle_dispenser = 0; - - if (inp == 1) { - TeamFortress_BuildSentry(0); - } - if (inp == 2 && !self.has_dispenser) { - if (self.ammo_cells >= ENG_DISPENSER_COST) - TeamFortress_Build(1, 0); - else - Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); - } + break; - if (inp == 3 && self.has_sentry) { - te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); - while (te) { - if (te.classname == "building_sentrygun") { - if (te.real_owner == self){ - sprint (self, PRINT_HIGH, "You dismantled the sentry gun and got 65 cells\n"); - self.ammo_cells = self.ammo_cells + 65; - dremove (te.trigger_field); - dremove (te); - self.has_sentry = 0; - dismantle_sentrygun = 1; + // dismantle or destroy sentry + case 3: + if (self.has_sentry) { + local float dismantle_sentrygun = 0; + local entity te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); + while (te) { + if (te.classname == "building_sentrygun" && te.real_owner == self) { + if (te.weapon == 0) { + sprint(self, PRINT_HIGH, strcat("You stopped building a sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); + self.ammo_cells += ENG_SENTRY_COST; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; + if (te.trigger_field != world) + dremove(te.trigger_field); + self = te.real_owner; + TeamFortress_EngineerBuildStop(); + } else { + sprint(self, PRINT_HIGH, "You dismantled the sentry gun and got 65 cells\n"); + self.ammo_cells += 65; + dremove(te.trigger_field); + dremove(te); + self.has_sentry = 0; + dismantle_sentrygun = 1; + } + } + te = te.chain; } + if (dismantle_sentrygun == 0) + DestroyBuilding(self, "building_sentrygun"); } - te = te.chain; - } - if (dismantle_sentrygun == 0) - DestroyBuilding(self, "building_sentrygun"); - } + break; - if (inp == 4 && self.has_dispenser) { - te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); - while (te) { - if (te.classname == "building_dispenser") { - if (te.real_owner == self) { - sprint (self, PRINT_HIGH, "You dismantled the dispenser and got 50 cells\n"); - self.ammo_cells = self.ammo_cells + 50; - dremove (te); - self.has_dispenser = 0; - dismantle_dispenser = 1; + // dismantle or destroy dispenser + case 4: + if (self.has_dispenser) { + local float dismantle_dispenser = 0; + local entity te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); + while (te) { + if (te.classname == "building_dispenser" && te.real_owner == self) { + sprint(self, PRINT_HIGH, "You dismantled the dispenser and got 50 cells\n"); + self.ammo_cells += 50; + dremove(te); + self.has_dispenser = 0; + dismantle_dispenser = 1; + } + te = te.chain; } + if (dismantle_dispenser == 0) + DestroyBuilding(self, "building_dispenser"); } - te = te.chain; - } - if (dismantle_dispenser == 0) - DestroyBuilding(self, "building_dispenser"); + break; } - }; void (entity player) Menu_Engineer = { From 56cd80eaef21360c3f22a8f6d878987d4bb0a79a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 16 May 2024 20:18:07 +1000 Subject: [PATCH 2408/2474] Default gren throw lockout 0 --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5854eaa5..7646ba4d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -900,7 +900,7 @@ void () DecodeLevelParms = { } engineer_move = CF_GetSetting("em","engineer_move", "1"); - grenade_lockout = CF_GetSetting("gl","grenade_lockout", "0.1"); + grenade_lockout = CF_GetSetting("gl","grenade_lockout", "0"); max_active_gren2_soldier = CF_GetSetting("mg2s","max_active_gren2_soldier", "3"); From 8ef1dfb1019f735e7045409c2333f52131f8468c Mon Sep 17 00:00:00 2001 From: enondev Date: Wed, 5 Jun 2024 14:12:04 -0700 Subject: [PATCH 2409/2474] Correct goal_results to goal_result Changing any references of "goal_results" to "goal_result". This resolves issue #696. --- docs/versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/versions.txt b/docs/versions.txt index bb71f2b0..c0c99cba 100644 --- a/docs/versions.txt +++ b/docs/versions.txt @@ -900,7 +900,7 @@ Map Code Enhancements: a particular group in it's criteria using "has_item_from_group". - Goals can use the "remove_item_group" to remove all the items in a particular group from any player affected by its activation. - - A new Bit was added to the "goal_results" variable for Goals/Items + - A new Bit was added to the "goal_result" variable for Goals/Items which allows them to remove a Spy's disguise. - A new Bit was added to the "goal_activation" of GoalItems. See the tfortmap.txt for details. From 6f4f58b4ee85940f666608fa9bbdb754a4143a31 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 10 Jul 2024 13:36:32 +1000 Subject: [PATCH 2410/2474] Fix init of sentry --- ssqc/player.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/player.qc b/ssqc/player.qc index f2dedd1f..f3c5ed83 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -441,7 +441,7 @@ void () GibPlayer = { void () PlayerDie = { local entity rs = self.rotating_sentry; rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; - self.rotating_sentry == world; + self.rotating_sentry = world; self.spawn_gen += 1; self.last_death_ctime = self.client_time; From c5fb5d60df01029c65df48daa876b8da6802c738 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 1 Aug 2024 01:04:37 +1000 Subject: [PATCH 2411/2474] First pass --- ssqc/spy.qc | 4 +-- ssqc/tfort.qc | 75 ++++++++++++++++++++++++++++++++++++++----------- ssqc/tforttm.qc | 4 +-- ssqc/world.qc | 2 ++ 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index f26e2205..20201e78 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -506,8 +506,8 @@ void (entity own) Spy_SetClientSkins = { color = ftos(TeamFortress_TeamGetColor(own.team_no) - 1); dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); - skin = TeamFortress_GetSkin(own.team_no, own.playerclass); - dskin = TeamFortress_GetSkin(dteam, dpc); + skin = TeamFortress_GetSkin(own.playerclass); + dskin = TeamFortress_GetSkin(dpc); pteam = GetTeamName(own.team_no); dsteam = GetTeamName(dteam); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 359b828d..f66a7f7c 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1132,44 +1132,41 @@ string (float tn) TeamFortress_GetColorSkin = { return s; } -string(float tn, float pc) TeamFortress_GetSkin = +string(float pc) TeamFortress_GetSkin = { local string skin = "base"; - string col; - col = TeamFortress_GetColorSkin(tn); - switch (pc) { case 1: - skin = strcat(col, "_sco"); + skin = "fo_scout"; break; case 2: - skin = strcat(col, "_sni"); + skin = "fo_snipe"; break; case 3: - skin = strcat(col, "_sol"); + skin = "fo_sold"; break; case 4: - skin = strcat(col, "_dem"); + skin = "fo_demo"; break; case 5: - skin = strcat(col, "_med"); + skin = "fo_medic"; break; case 6: - skin = strcat(col, "_hwg"); + skin = "fo_hwguy"; break; case 7: - skin = strcat(col, "_pyr"); + skin = "fo_pyro"; break; case 8: - skin = strcat(col, "_spy"); + skin = "fo_spy"; break; case 9: - skin = strcat(col, "_eng"); + skin = "fo_eng"; break; case 11: - skin = strcat(col, "_civ"); + skin = "fo_civ"; break; } @@ -1186,7 +1183,7 @@ void (entity p) TeamFortress_SetSkin = { if (!p.is_undercover) { stuffcmd(p, "skin "); - st = TeamFortress_GetSkin(p.team_no, p.playerclass); + st = TeamFortress_GetSkin(p.playerclass); stuffcmd(p, st); stuffcmd(p, "\n"); // please fix mvd recording @@ -1200,13 +1197,57 @@ void (entity p) TeamFortress_SetSkin = { if (p.skin != 0) { stuffcmd(p, "skin "); - st = TeamFortress_GetSkin(p.team_no, p.playerclass); + st = TeamFortress_GetSkin(p.playerclass); stuffcmd(p, st); stuffcmd(p, "\n"); // please fix mvd recording forceinfokey(p, "skin", st); - } + + local string color; + local entity te; + + te = find(world, classname, "player"); + while (te != world) { + msg_entity = te; + + if (te != p) { + switch (p.team_no) { + case 1: + color = infokey(te, "team_1_color"); + if (color == "") + color = "0x222299"; + break; + case 2: + color = infokey(te, "team_2_color"); + if (color == "") + color = "0x992222"; + break; + case 3: + color = infokey(te, "team_3_color"); + if (color == "") + color = "0x999922"; + break; + case 4: + color = infokey(te, "team_4_color"); + if (color == "") + color = "0x229922"; + break; + } + + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); + } + + te = find(te, classname, "player"); + } + } else { stuffcmd(p, "skin base\n"); diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index b73e83cd..89073957 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -9,7 +9,7 @@ float (float tno) TeamFortress_TeamGetLives; float (float tno) TeamFortress_TeamGetMaxPlayers; string(float tno) TeamFortress_TeamGetColorString; float (float tno) TeamFortress_TeamGetIllegalClasses; -string(float tn, float pc) TeamFortress_GetSkin; +string(float pc) TeamFortress_GetSkin; float () TeamFortress_TeamPutPlayerInTeam = { @@ -313,7 +313,7 @@ void () TeamFortress_CheckTeamCheats = { if (self.playerclass != 0) { st = infokey(self, "skin"); tc = 0; - sk = TeamFortress_GetSkin(self.team_no, self.playerclass); + sk = TeamFortress_GetSkin(self.playerclass); if (st != sk) { TeamFortress_SetSkin(self); bprint(PRINT_MEDIUM, self.netname, diff --git a/ssqc/world.qc b/ssqc/world.qc index e194f42a..f2d37546 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -86,6 +86,8 @@ void WorldSpawnPost() } void () worldspawn = { + whichpack("textures/skins/fo_scout.png", 1); // ensures that fo_skins.pk3 is sent + // Set this variable on connect so the client knows it has access to // FortressOne aliases. WriteByte(MSG_INIT, 9/*svc_stufftext*/); From 0ff8e0304eacd3be8d208fc470fdb46ee98d1fa1 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 1 Aug 2024 12:27:09 +1000 Subject: [PATCH 2412/2474] Trigger skin refresh on setinfo change --- ssqc/commands.qc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ ssqc/tfort.qc | 37 ++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 908a2613..8fdd474d 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -327,6 +327,50 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { + case "team1color": + forceinfokey(self, "team1color", arg2); + ent = find(world, classname, "player"); + while (ent != world) { + if (ent.team_no == 1) + TeamFortress_SetSkin(ent); + + ent = find(ent, classname, "player"); + } + + break; + case "team2color": + forceinfokey(self, "team2color", arg2); + ent = find(world, classname, "player"); + while (ent != world) { + if (ent.team_no == 2) + TeamFortress_SetSkin(ent); + + ent = find(ent, classname, "player"); + } + + break; + case "team3color": + forceinfokey(self, "team3color", arg2); + ent = find(world, classname, "player"); + while (ent != world) { + if (ent.team_no == 3) + TeamFortress_SetSkin(ent); + + ent = find(ent, classname, "player"); + } + + break; + case "team4color": + forceinfokey(self, "team4color", arg2); + ent = find(world, classname, "player"); + while (ent != world) { + if (ent.team_no == 4) + TeamFortress_SetSkin(ent); + + ent = find(ent, classname, "player"); + } + + break; case "impulse": if (arg_num == 2) { self.impulse = stof(arg2); @@ -354,6 +398,8 @@ float (string arg1, string arg2, string arg3) ParseCmds = { { if (arg2 == "topcolor" || arg2 == "bottomcolor") { + sprint(self, PRINT_HIGH, "TRYING TO CHANGE YOUR TOPCOLOR HRMMMMM?\n"); + float arg3f = stof(arg3); if ((self.team_no > 0) && (teamplay > 0)) { if (arg3f != (TeamFortress_TeamGetColor(self.team_no) - 1)) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index f66a7f7c..606b3471 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1194,7 +1194,7 @@ void (entity p) TeamFortress_SetSkin = { else { p.skin = p.playerclass; - + if (p.skin != 0) { stuffcmd(p, "skin "); st = TeamFortress_GetSkin(p.playerclass); @@ -1214,35 +1214,38 @@ void (entity p) TeamFortress_SetSkin = { if (te != p) { switch (p.team_no) { case 1: - color = infokey(te, "team_1_color"); + color = infokey(te, "team1color"); if (color == "") - color = "0x222299"; + color = "222299"; break; case 2: - color = infokey(te, "team_2_color"); + color = infokey(te, "team2color"); if (color == "") - color = "0x992222"; + color = "992222"; break; case 3: - color = infokey(te, "team_3_color"); + color = infokey(te, "team3color"); if (color == "") - color = "0x999922"; + color = "999922"; break; case 4: - color = infokey(te, "team_4_color"); + color = infokey(te, "team4color"); if (color == "") - color = "0x229922"; + color = "229922"; break; } - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); + if (color) { + color = strcat("0x", color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); + } } te = find(te, classname, "player"); From 561af5d15695dca8357cbbc0b9efa1a9ec824dce Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 6 Aug 2024 19:06:08 +1000 Subject: [PATCH 2413/2474] Update team colours, apply to all players on joining server --- ssqc/client.qc | 9 ++++++++- ssqc/tfort.qc | 46 ++++++++++++++++++++++------------------------ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 7646ba4d..52c6a0cf 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2257,7 +2257,14 @@ void () PutClientInServer = { TeamFortress_SetEquipment(); TeamFortress_SetHealth(); TeamFortress_SetSpeed(self); - TeamFortress_SetSkin(self); + + + te = find(world, classname, "player"); + while (te != world) { + TeamFortress_SetSkin(te); + te = find(te, classname, "player"); + } + TeamFortress_StartTimers(); if(quadmode && quad_roles) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 606b3471..cb45948a 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1211,29 +1211,28 @@ void (entity p) TeamFortress_SetSkin = { while (te != world) { msg_entity = te; - if (te != p) { - switch (p.team_no) { - case 1: - color = infokey(te, "team1color"); - if (color == "") - color = "222299"; - break; - case 2: - color = infokey(te, "team2color"); - if (color == "") - color = "992222"; - break; - case 3: - color = infokey(te, "team3color"); - if (color == "") - color = "999922"; - break; - case 4: - color = infokey(te, "team4color"); - if (color == "") - color = "229922"; - break; - } + switch (p.team_no) { + case 1: + color = infokey(te, "team1color"); + if (color == "") + color = "00AAFF"; + break; + case 2: + color = infokey(te, "team2color"); + if (color == "") + color = "FF3300"; + break; + case 3: + color = infokey(te, "team3color"); + if (color == "") + color = "FFBB00"; + break; + case 4: + color = infokey(te, "team4color"); + if (color == "") + color = "00FF44"; + break; + } if (color) { color = strcat("0x", color); @@ -1246,7 +1245,6 @@ void (entity p) TeamFortress_SetSkin = { WriteString(MSG_ONE, "bottomcolor"); WriteString(MSG_ONE, color); } - } te = find(te, classname, "player"); } From fff9b5619c0c5bd10b1c4b31a6ebe8772d24ed54 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 6 Aug 2024 23:21:34 +1000 Subject: [PATCH 2414/2474] Support spy --- ssqc/functions.qc | 1 + ssqc/spy.qc | 6 +++--- ssqc/tfort.qc | 22 +++++++++++++++++++++- ssqc/tforttm.qc | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/ssqc/functions.qc b/ssqc/functions.qc index 5e7f5b65..c0f7623d 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -1,5 +1,6 @@ float (float tno) TeamFortress_TeamSet; float (float tno) TeamFortress_TeamGetColor; +string (entity pov, float tno) TeamFortress_TeamGetColorFor; void (entity p) SetTeamName; void (entity pl) Menu_Close; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 20201e78..bc356ba0 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -495,7 +495,6 @@ void (entity player, float is_user) FO_Spy_DisguiseLastSpawned = { } }; - void (entity own) Spy_SetClientSkins = { entity te; string color, dcolor, skin, dskin, sendcolor, sendskin, pteam, dsteam, sendteam; @@ -503,6 +502,7 @@ void (entity own) Spy_SetClientSkins = { dteam = own.undercover_team == 0 ? own.team_no : own.undercover_team; dpc = own.undercover_skin == 0 ? own.playerclass : own.undercover_skin; + color = ftos(TeamFortress_TeamGetColor(own.team_no) - 1); dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); @@ -520,13 +520,13 @@ void (entity own) Spy_SetClientSkins = { if (te.team_no == own.team_no) { // on same team, send them spy/team (initial spawn etc) - sendcolor = color; + sendcolor = TeamFortress_TeamGetColorFor(te, own.team_no); sendskin = skin; sendteam = pteam; } else // not on same team, send them disguise { - sendcolor = dcolor; + sendcolor = TeamFortress_TeamGetColorFor(te, dteam); sendskin = dskin; sendteam = dsteam; } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index cb45948a..3885d1d3 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1177,7 +1177,7 @@ void (entity p) TeamFortress_SetSkin = { local string st; p.immune_to_check = time + 10; - + if (p.playerclass == PC_SPY || p.last_playerclass == PC_SPY) { if (!p.is_undercover) @@ -1188,6 +1188,26 @@ void (entity p) TeamFortress_SetSkin = { stuffcmd(p, "\n"); // please fix mvd recording forceinfokey(p, "skin", st); + + local string color; + local entity te; + + te = find(world, classname, "player"); + while (te != world) { + msg_entity = te; + color = TeamFortress_TeamGetColorFor(te, p.team_no); + + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); + + te = find(te, classname, "player"); + } } Spy_SetClientSkins(p); } diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 89073957..e9b26124 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -51,6 +51,39 @@ float (float tno) TeamFortress_TeamGetColor = { return (1); }; +string TeamFortress_TeamGetColorFor(entity pov, float tno) { + local string color; + + switch (tno) { + case 1: + color = infokey(pov, "team1color"); + if (color == "") + color = "00AAFF"; + break; + case 2: + color = infokey(pov, "team2color"); + if (color == "") + color = "FF3300"; + break; + case 3: + color = infokey(pov, "team3color"); + if (color == "") + color = "FFBB00"; + break; + case 4: + color = infokey(pov, "team4color"); + if (color == "") + color = "00FF44"; + break; + default: + color = "FFFFFF"; + break; + } + + return strcat("0x", color); +} + + void (float tno) TeamFortress_TeamSetColor = { if (tno == 1) { team1col = DARKBLUE; From fb41a833892030d82ebd1a638e0cbe8b5109def3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 6 Aug 2024 23:30:51 +1000 Subject: [PATCH 2415/2474] Refactor --- ssqc/commands.qc | 52 +++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 8fdd474d..6f56defe 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -313,6 +313,18 @@ void (entity pl) PrintWho = { strunzone(msg); } +void (entity pov, string command, string color, float tno) UpdateTeamColor = { + forceinfokey(pov, command, color); + + local entity te = find(world, classname, "player"); + while (te != world) { + if (te.team_no == tno) + TeamFortress_SetSkin(te); + + te = find(te, classname, "player"); + } +} + float (string arg1, string arg2, string arg3) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; @@ -328,48 +340,16 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { case "team1color": - forceinfokey(self, "team1color", arg2); - ent = find(world, classname, "player"); - while (ent != world) { - if (ent.team_no == 1) - TeamFortress_SetSkin(ent); - - ent = find(ent, classname, "player"); - } - + UpdateTeamColor(self, "team1color", arg2, 1); break; case "team2color": - forceinfokey(self, "team2color", arg2); - ent = find(world, classname, "player"); - while (ent != world) { - if (ent.team_no == 2) - TeamFortress_SetSkin(ent); - - ent = find(ent, classname, "player"); - } - + UpdateTeamColor(self, "team2color", arg2, 2); break; case "team3color": - forceinfokey(self, "team3color", arg2); - ent = find(world, classname, "player"); - while (ent != world) { - if (ent.team_no == 3) - TeamFortress_SetSkin(ent); - - ent = find(ent, classname, "player"); - } - + UpdateTeamColor(self, "team3color", arg2, 3); break; case "team4color": - forceinfokey(self, "team4color", arg2); - ent = find(world, classname, "player"); - while (ent != world) { - if (ent.team_no == 4) - TeamFortress_SetSkin(ent); - - ent = find(ent, classname, "player"); - } - + UpdateTeamColor(self, "team4color", arg2, 4); break; case "impulse": if (arg_num == 2) { From b9b8b768a4d38da94a63d2821d8e35ee5ead059e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 6 Aug 2024 23:31:20 +1000 Subject: [PATCH 2416/2474] Remove debug print --- ssqc/commands.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 6f56defe..c6809934 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -378,8 +378,6 @@ float (string arg1, string arg2, string arg3) ParseCmds = { { if (arg2 == "topcolor" || arg2 == "bottomcolor") { - sprint(self, PRINT_HIGH, "TRYING TO CHANGE YOUR TOPCOLOR HRMMMMM?\n"); - float arg3f = stof(arg3); if ((self.team_no > 0) && (teamplay > 0)) { if (arg3f != (TeamFortress_TeamGetColor(self.team_no) - 1)) { From de87681b3c517d5521cab2ed333fa590a85e90e6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 6 Aug 2024 23:38:34 +1000 Subject: [PATCH 2417/2474] Refactor --- ssqc/tfort.qc | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3885d1d3..ef1b232e 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1230,41 +1230,16 @@ void (entity p) TeamFortress_SetSkin = { te = find(world, classname, "player"); while (te != world) { msg_entity = te; + color = TeamFortress_TeamGetColorFor(te, p.team_no); - switch (p.team_no) { - case 1: - color = infokey(te, "team1color"); - if (color == "") - color = "00AAFF"; - break; - case 2: - color = infokey(te, "team2color"); - if (color == "") - color = "FF3300"; - break; - case 3: - color = infokey(te, "team3color"); - if (color == "") - color = "FFBB00"; - break; - case 4: - color = infokey(te, "team4color"); - if (color == "") - color = "00FF44"; - break; - } - - if (color) { - color = strcat("0x", color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); - } + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); te = find(te, classname, "player"); } From f6c978f0763725afd0722bf7c51cb8176f41162a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 7 Aug 2024 01:11:42 +1000 Subject: [PATCH 2418/2474] just use setinfos for team colours for now --- README.md | 4 ++++ ssqc/commands.qc | 59 ++++++++++++++++++++++++++---------------------- ssqc/tforttm.qc | 5 +--- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 2fb8efa0..f4faeedf 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,10 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * `localinfo fo_matchrated 2` whether match is rated / affects trueskill. 2 is false for 1v1 and 2v2 only. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ * All-time attack and all-time defence team options. +* `setinfo team1color ` to set the top and bottom colours for team 1. +* `setinfo team2color ` to set the top and bottom colours for team 2. +* `setinfo team3color ` to set the top and bottom colours for team 3. +* `setinfo team4color ` to set the top and bottom colours for team 4. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/ssqc/commands.qc b/ssqc/commands.qc index c6809934..914dd1c8 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -339,18 +339,6 @@ float (string arg1, string arg2, string arg3) ParseCmds = { switch (arg1) { - case "team1color": - UpdateTeamColor(self, "team1color", arg2, 1); - break; - case "team2color": - UpdateTeamColor(self, "team2color", arg2, 2); - break; - case "team3color": - UpdateTeamColor(self, "team3color", arg2, 3); - break; - case "team4color": - UpdateTeamColor(self, "team4color", arg2, 4); - break; case "impulse": if (arg_num == 2) { self.impulse = stof(arg2); @@ -374,22 +362,39 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "setinfo": - if (arg2) - { - if (arg2 == "topcolor" || arg2 == "bottomcolor") - { - float arg3f = stof(arg3); - if ((self.team_no > 0) && (teamplay > 0)) { - if (arg3f != (TeamFortress_TeamGetColor(self.team_no) - 1)) { - arg3f = TeamFortress_TeamGetColor(self.team_no) - 1; - string st; - st = ftos(arg3f); - stuffcmd(self, strcat("color ", st, "\n")); - sprint(self, PRINT_HIGH, - "Your color has been changed to your team color\n"); - processedCmd = TRUE; + if (arg2) { + switch(arg2) { + case "topcolor": + case "bottomcolor": + float arg3f = stof(arg3); + if ((self.team_no > 0) && (teamplay > 0)) { + if (arg3f != (TeamFortress_TeamGetColor(self.team_no) - 1)) { + arg3f = TeamFortress_TeamGetColor(self.team_no) - 1; + string st; + st = ftos(arg3f); + stuffcmd(self, strcat("color ", st, "\n")); + sprint(self, PRINT_HIGH, + "Your color has been changed to your team color\n"); + processedCmd = TRUE; + } } - } + break; + case "team1color": + UpdateTeamColor(self, "team1color", arg3, 1); + processedCmd = TRUE; + break; + case "team2color": + UpdateTeamColor(self, "team2color", arg3, 2); + processedCmd = TRUE; + break; + case "team3color": + UpdateTeamColor(self, "team3color", arg3, 3); + processedCmd = TRUE; + break; + case "team4color": + UpdateTeamColor(self, "team4color", arg3, 4); + processedCmd = TRUE; + break; } } break; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index e9b26124..cf3ef486 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -52,7 +52,7 @@ float (float tno) TeamFortress_TeamGetColor = { }; string TeamFortress_TeamGetColorFor(entity pov, float tno) { - local string color; + local string color = "FFFFFF"; switch (tno) { case 1: @@ -75,9 +75,6 @@ string TeamFortress_TeamGetColorFor(entity pov, float tno) { if (color == "") color = "00FF44"; break; - default: - color = "FFFFFF"; - break; } return strcat("0x", color); From d5c4e2a702798a98173d7db3d809cefca7b409c3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 7 Aug 2024 14:01:35 +1000 Subject: [PATCH 2419/2474] Tweak red skin colour --- ssqc/tforttm.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index cf3ef486..282cfcea 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -63,7 +63,7 @@ string TeamFortress_TeamGetColorFor(entity pov, float tno) { case 2: color = infokey(pov, "team2color"); if (color == "") - color = "FF3300"; + color = "FF2222"; break; case 3: color = infokey(pov, "team3color"); From 66ed8aedd170adcc57416d365af29f3eeb5c5bf5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 7 Aug 2024 21:06:43 +1000 Subject: [PATCH 2420/2474] Remove unneeded variables --- ssqc/spy.qc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ssqc/spy.qc b/ssqc/spy.qc index bc356ba0..b0a5820f 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -497,15 +497,12 @@ void (entity player, float is_user) FO_Spy_DisguiseLastSpawned = { void (entity own) Spy_SetClientSkins = { entity te; - string color, dcolor, skin, dskin, sendcolor, sendskin, pteam, dsteam, sendteam; + string skin, dskin, sendcolor, sendskin, pteam, dsteam, sendteam; float dteam, dpc; dteam = own.undercover_team == 0 ? own.team_no : own.undercover_team; dpc = own.undercover_skin == 0 ? own.playerclass : own.undercover_skin; - color = ftos(TeamFortress_TeamGetColor(own.team_no) - 1); - dcolor = ftos(TeamFortress_TeamGetColor(dteam) - 1); - skin = TeamFortress_GetSkin(own.playerclass); dskin = TeamFortress_GetSkin(dpc); From e53b6c1ccc3c010dd561d6e647f37ecbf17c20b0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 7 Aug 2024 21:31:25 +1000 Subject: [PATCH 2421/2474] Refactor, remove uneeded stuffcmds --- ssqc/tfort.qc | 144 +++++++++++++++++++++----------------------------- 1 file changed, 59 insertions(+), 85 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index ef1b232e..3ad4a7fe 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1173,79 +1173,53 @@ string(float pc) TeamFortress_GetSkin = return skin; }; + +void (entity player) TeamFortress_ResetSkins = { + local string st = TeamFortress_GetSkin(player.playerclass); + stuffcmd(player, "skin "); + stuffcmd(player, st); + stuffcmd(player, "\n"); + // please fix mvd recording + forceinfokey(player, "skin", st); + + local string color; + local entity te; + + te = find(world, classname, "player"); + while (te != world) { + msg_entity = te; + color = TeamFortress_TeamGetColorFor(te, player.team_no); + + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); + + te = find(te, classname, "player"); + } +} + void (entity p) TeamFortress_SetSkin = { local string st; p.immune_to_check = time + 10; - if (p.playerclass == PC_SPY || p.last_playerclass == PC_SPY) - { - if (!p.is_undercover) - { - stuffcmd(p, "skin "); - st = TeamFortress_GetSkin(p.playerclass); - stuffcmd(p, st); - stuffcmd(p, "\n"); - // please fix mvd recording - forceinfokey(p, "skin", st); - - local string color; - local entity te; - - te = find(world, classname, "player"); - while (te != world) { - msg_entity = te; - color = TeamFortress_TeamGetColorFor(te, p.team_no); - - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); - - te = find(te, classname, "player"); - } + if (p.playerclass == PC_SPY || p.last_playerclass == PC_SPY) { + if (!p.is_undercover) { + TeamFortress_ResetSkins(p); + } else { + Spy_SetClientSkins(p); } - Spy_SetClientSkins(p); - } - else - { + } else { p.skin = p.playerclass; if (p.skin != 0) { - stuffcmd(p, "skin "); - st = TeamFortress_GetSkin(p.playerclass); - stuffcmd(p, st); - stuffcmd(p, "\n"); - - // please fix mvd recording - forceinfokey(p, "skin", st); - - local string color; - local entity te; - - te = find(world, classname, "player"); - while (te != world) { - msg_entity = te; - color = TeamFortress_TeamGetColorFor(te, p.team_no); - - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, p.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); - - te = find(te, classname, "player"); - } - } - else - { + TeamFortress_ResetSkins(p); + } else { stuffcmd(p, "skin base\n"); } } @@ -1260,11 +1234,11 @@ void () TeamFortress_SetEquipment = { return; Team_Role * role = GetTeamRole(self.team_no); - + kept_items = self.tf_items & (IT_KEY1 | IT_KEY2); if (!remember_weapon || self.last_playerclass != self.playerclass || - (self.tfstate & TFSTATE_RANDOMPC)) { + (self.tfstate & TFSTATE_RANDOMPC)) { self.current_slot = SlotMelee; self.last_slot = SlotNull; } @@ -1769,7 +1743,7 @@ void () TeamFortress_SetEquipment = { self.maxammo_cells = PC_SPY_MAXAMMO_CELL; self.max_grenades_1 = role.gren1_limits[8]; self.max_grenades_2 = role.gren2_limits[8]; - + self.tf_items = PC_SPY_TF_ITEMS; self.armorclass = self.armorclass | PC_SPY_INITARMORCLASS; @@ -2030,16 +2004,16 @@ void () TeamFortress_RemoveTimers = { while (te) { if (te.owner == self) { if (!(te.goal_activation & TFGI_KEEP) || - (self.has_disconnected == 1)) { + (self.has_disconnected == 1)) { tfgoalitem_RemoveFromPlayer(te, self, 0); } if (CTF_Map == 1) { if (te.goal_no == 1) { bprint(PRINT_HIGH, self.netname, - Q" \stook\s the \sblue\s flag!\n"); + Q" \stook\s the \sblue\s flag!\n"); } else if (te.goal_no == 2) { bprint(PRINT_HIGH, self.netname, - Q" \stook\s the \sred\s flag!\n"); + Q" \stook\s the \sred\s flag!\n"); } } } @@ -2102,7 +2076,7 @@ void (float Suicided) TeamFortress_SetupRespawn = { if (self.lives != -1) { if (self.lives == 0) { sprint(self, PRINT_HIGH, - "No lives left, returning to observer mode\n"); + "No lives left, returning to observer mode\n"); self.playerclass = PC_UNDEFINED; self.tfstate = self.tfstate - (self.tfstate & TFSTATE_RANDOMPC); @@ -2179,7 +2153,7 @@ void () TeamFortress_CheckClassStats = { // Check health if ((self.health > self.max_health) && !(self.items & IT_SUPERHEALTH)) TF_T_Damage(self, world, world, self.max_health - self.health, 0, - TF_TD_NOSOUND); + TF_TD_NOSOUND); if (self.health < 0) T_Heal(self, self.health - self.health, 0); @@ -2203,11 +2177,11 @@ void (float type, float ammo) TeamFortress_DropAmmo = { if (self.ammo_shells < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_SHELLS) >= - (ammo - self.ammo_shells)) { + (ammo - self.ammo_shells)) { sprint(self, PRINT_HIGH, "You make some shells\n"); self.ammo_cells = self.ammo_cells - (ammo - - self.ammo_shells) * + self.ammo_shells) * AMMO_COST_SHELLS; self.ammo_shells = ammo; } @@ -2221,11 +2195,11 @@ void (float type, float ammo) TeamFortress_DropAmmo = { if (self.ammo_nails < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_NAILS) >= - (ammo - self.ammo_nails)) { + (ammo - self.ammo_nails)) { sprint(self, PRINT_HIGH, "You make some nails\n"); self.ammo_cells = self.ammo_cells - (ammo - - self.ammo_nails) * + self.ammo_nails) * AMMO_COST_NAILS; self.ammo_nails = ammo; } @@ -2239,11 +2213,11 @@ void (float type, float ammo) TeamFortress_DropAmmo = { if (self.ammo_rockets < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_ROCKETS) >= - (ammo - self.ammo_rockets)) { + (ammo - self.ammo_rockets)) { sprint(self, PRINT_HIGH, "You make some rockets\n"); self.ammo_cells = self.ammo_cells - (ammo - - self.ammo_rockets) * + self.ammo_rockets) * AMMO_COST_ROCKETS; self.ammo_rockets = ammo; } @@ -2257,11 +2231,11 @@ void (float type, float ammo) TeamFortress_DropAmmo = { if (self.ammo_cells < ammo) { if (self.playerclass == PC_ENGINEER) { if ((self.ammo_cells / AMMO_COST_CELLS) >= - (ammo - self.ammo_cells)) { + (ammo - self.ammo_cells)) { sprint(self, PRINT_HIGH, "You make some cells\n"); self.ammo_cells = self.ammo_cells - (ammo - - self.ammo_cells) * + self.ammo_cells) * AMMO_COST_CELLS; self.ammo_cells = ammo; } @@ -2336,7 +2310,7 @@ void () TeamFortress_AmmoboxTouch = { self = other; return; } else if ((other.playerclass == PC_SCOUT) - || (other.playerclass == PC_ENGINEER)) { + || (other.playerclass == PC_ENGINEER)) { if (!(self.ammo_shells + self.ammo_nails + self.ammo_cells)) { other.nopickup = self; return; @@ -2348,8 +2322,8 @@ void () TeamFortress_AmmoboxTouch = { other.ammo_cells = other.ammo_cells + self.ammo_cells; self.ammo_cells = 0; } else if ((other.playerclass == PC_SNIPER) - || (other.playerclass == PC_SPY) - || (other.playerclass == PC_MEDIC)) { + || (other.playerclass == PC_SPY) + || (other.playerclass == PC_MEDIC)) { if (!(self.ammo_shells + self.ammo_nails)) { other.nopickup = self; return; @@ -2359,7 +2333,7 @@ void () TeamFortress_AmmoboxTouch = { other.ammo_nails = other.ammo_nails + self.ammo_nails; self.ammo_nails = 0; } else if ((other.playerclass == PC_SOLDIER) - || (other.playerclass == PC_DEMOMAN)) { + || (other.playerclass == PC_DEMOMAN)) { if (!(self.ammo_shells + self.ammo_rockets)) { other.nopickup = self; return; @@ -2648,7 +2622,7 @@ void () TeamFortress_CheckforCheats = { bprint(PRINT_MEDIUM, self.owner.netname, " has been kicked for cheating\n"); sprint(self.owner, PRINT_HIGH, - "You have been kicked for cheating, because of your speed\n"); + "You have been kicked for cheating, because of your speed\n"); KickCheater(self.owner); } }; From a8b659d587dc0f81eb66cb9f7d760623c171b47c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 7 Aug 2024 21:34:36 +1000 Subject: [PATCH 2422/2474] Refactor --- ssqc/tfort.qc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3ad4a7fe..e1c74bc9 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1174,7 +1174,7 @@ string(float pc) TeamFortress_GetSkin = }; -void (entity player) TeamFortress_ResetSkins = { +void (entity player) TeamFortress_SetSkinInfos = { local string st = TeamFortress_GetSkin(player.playerclass); stuffcmd(player, "skin "); stuffcmd(player, st); @@ -1204,13 +1204,11 @@ void (entity player) TeamFortress_ResetSkins = { } void (entity p) TeamFortress_SetSkin = { - local string st; - p.immune_to_check = time + 10; if (p.playerclass == PC_SPY || p.last_playerclass == PC_SPY) { if (!p.is_undercover) { - TeamFortress_ResetSkins(p); + TeamFortress_SetSkinInfos(p); } else { Spy_SetClientSkins(p); } @@ -1218,7 +1216,7 @@ void (entity p) TeamFortress_SetSkin = { p.skin = p.playerclass; if (p.skin != 0) { - TeamFortress_ResetSkins(p); + TeamFortress_SetSkinInfos(p); } else { stuffcmd(p, "skin base\n"); } From 1052feb17bd3bad9db01536dc6d10773cca1d96c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 8 Aug 2024 00:14:28 +1000 Subject: [PATCH 2423/2474] Maybe fix wrong teamcolour on occasion, refactor --- ssqc/client.qc | 7 +++++-- ssqc/tfort.qc | 35 ++++++++++++++++------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 52c6a0cf..af202fd3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2257,11 +2257,14 @@ void () PutClientInServer = { TeamFortress_SetEquipment(); TeamFortress_SetHealth(); TeamFortress_SetSpeed(self); - + TeamFortress_SetSkin(self); te = find(world, classname, "player"); while (te != world) { - TeamFortress_SetSkin(te); + if (te != self) { + TeamFortress_SetSkin(te); + } + te = find(te, classname, "player"); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index e1c74bc9..99ab7a57 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1176,28 +1176,25 @@ string(float pc) TeamFortress_GetSkin = void (entity player) TeamFortress_SetSkinInfos = { local string st = TeamFortress_GetSkin(player.playerclass); - stuffcmd(player, "skin "); - stuffcmd(player, st); - stuffcmd(player, "\n"); - // please fix mvd recording - forceinfokey(player, "skin", st); + stuffcmd(player, sprintf("skin %s\n", st)); + forceinfokey(player, "skin", st); // please fix mvd recording local string color; - local entity te; - - te = find(world, classname, "player"); + local entity te = find(world, classname, "player"); while (te != world) { - msg_entity = te; - color = TeamFortress_TeamGetColorFor(te, player.team_no); - - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); + if (te != player) { + msg_entity = te; + color = TeamFortress_TeamGetColorFor(te, player.team_no); + + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); + } te = find(te, classname, "player"); } From 314f6eb08cac1d7e9d89dde8800384833201828d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 8 Aug 2024 02:22:47 +1000 Subject: [PATCH 2424/2474] Support teamcolor and enemycolor cvars --- ssqc/tforttm.qc | 50 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 282cfcea..c01f0c5d 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -54,30 +54,36 @@ float (float tno) TeamFortress_TeamGetColor = { string TeamFortress_TeamGetColorFor(entity pov, float tno) { local string color = "FFFFFF"; - switch (tno) { - case 1: - color = infokey(pov, "team1color"); - if (color == "") - color = "00AAFF"; - break; - case 2: - color = infokey(pov, "team2color"); - if (color == "") - color = "FF2222"; - break; - case 3: - color = infokey(pov, "team3color"); - if (color == "") - color = "FFBB00"; - break; - case 4: - color = infokey(pov, "team4color"); - if (color == "") - color = "00FF44"; - break; + if (pov.team_no == tno && cvar("teamcolor")) { + color = cvar_string("teamcolor"); + } else if (pov.team_no != tno && cvar("enemycolor")) { + color = cvar_string("enemycolor"); + } else { + switch (tno) { + case 1: + color = infokey(pov, "team1color"); + if (color == "") + color = "0x00AAFF"; + break; + case 2: + color = infokey(pov, "team2color"); + if (color == "") + color = "0xFF2222"; + break; + case 3: + color = infokey(pov, "team3color"); + if (color == "") + color = "0xFFBB00"; + break; + case 4: + color = infokey(pov, "team4color"); + if (color == "") + color = "0x00FF44"; + break; + } } - return strcat("0x", color); + return color; } From 402bb8b7a2d6ccc45b14aecb6889c19192a1967b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 8 Aug 2024 20:02:35 +1000 Subject: [PATCH 2425/2474] Refactor --- ssqc/commands.qc | 29 +++++++++++++++++++++++------ ssqc/tfort.qc | 3 ++- ssqc/tforttm.qc | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 914dd1c8..1645202f 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -313,13 +313,30 @@ void (entity pl) PrintWho = { strunzone(msg); } -void (entity pov, string command, string color, float tno) UpdateTeamColor = { +void (entity pov, string color, float tno) UpdateTeamColor = { + local string command = ""; + switch (tno) { + case 1: + command = "team1color"; + break; + case 2: + command = "team2color"; + break; + case 3: + command = "team3color"; + break; + case 4: + command = "team4color"; + break; + } + forceinfokey(pov, command, color); local entity te = find(world, classname, "player"); while (te != world) { - if (te.team_no == tno) + if (te.team_no == tno) { TeamFortress_SetSkin(te); + } te = find(te, classname, "player"); } @@ -380,19 +397,19 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } break; case "team1color": - UpdateTeamColor(self, "team1color", arg3, 1); + UpdateTeamColor(self, arg3, 1); processedCmd = TRUE; break; case "team2color": - UpdateTeamColor(self, "team2color", arg3, 2); + UpdateTeamColor(self, arg3, 2); processedCmd = TRUE; break; case "team3color": - UpdateTeamColor(self, "team3color", arg3, 3); + UpdateTeamColor(self, arg3, 3); processedCmd = TRUE; break; case "team4color": - UpdateTeamColor(self, "team4color", arg3, 4); + UpdateTeamColor(self, arg3, 4); processedCmd = TRUE; break; } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 99ab7a57..40b04273 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1176,7 +1176,8 @@ string(float pc) TeamFortress_GetSkin = void (entity player) TeamFortress_SetSkinInfos = { local string st = TeamFortress_GetSkin(player.playerclass); - stuffcmd(player, sprintf("skin %s\n", st)); + local string command = sprintf("skin %s\n", st); + stuffcmd(player, command); forceinfokey(player, "skin", st); // please fix mvd recording local string color; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index c01f0c5d..40201390 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -52,7 +52,7 @@ float (float tno) TeamFortress_TeamGetColor = { }; string TeamFortress_TeamGetColorFor(entity pov, float tno) { - local string color = "FFFFFF"; + local string color = "0xFFFFFF"; if (pov.team_no == tno && cvar("teamcolor")) { color = cvar_string("teamcolor"); From bb669299c61d7080d254e0684191e007b57ca702 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 11 Aug 2024 23:36:49 +1000 Subject: [PATCH 2426/2474] Don't send unneccessary setinfos --- ssqc/client.qc | 30 ++++++++++++++++++++---------- ssqc/engineer.qc | 1 + 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index af202fd3..ed9a13b8 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2258,16 +2258,6 @@ void () PutClientInServer = { TeamFortress_SetHealth(); TeamFortress_SetSpeed(self); TeamFortress_SetSkin(self); - - te = find(world, classname, "player"); - while (te != world) { - if (te != self) { - TeamFortress_SetSkin(te); - } - - te = find(te, classname, "player"); - } - TeamFortress_StartTimers(); if(quadmode && quad_roles) { @@ -3217,6 +3207,26 @@ void () ClientConnect = { UpdateClientPrematch(self, !cb_prematch); UpdateClient_VoteMap_AddAll(self); + local string color; + local entity te = find(world, classname, "player"); + while (te != world) { + if (te != self) { + msg_entity = self; + color = TeamFortress_TeamGetColorFor(self, te.team_no); + + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, te.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, te.colormap-1); // ???? Copied from spy.qc + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); + } + + te = find(te, classname, "player"); + } + if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); }; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 06c3785b..30a69f39 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1098,6 +1098,7 @@ void () TeamFortress_FinishedBuilding = { newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.mdl = "progs/turrgun.mdl"; + newmis.colormod = '0.5 0.5 0.5'; self.sentry_ent = newmis; FO_Sound(oldself, CHAN_ITEM, "weapons/turrset.wav", 1, 1); newmis.solid = SOLID_BBOX; From ec294f52339800673aebef1194382824caf1ed81 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 12 Aug 2024 00:08:28 +1000 Subject: [PATCH 2427/2474] Refactor --- ssqc/client.qc | 29 +++++++++++++++++------------ ssqc/tfort.qc | 14 +------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index ed9a13b8..c4fe5851 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3147,6 +3147,21 @@ void () UpdateAllClientsTeamScores = { } } +void (entity pov, entity target) SetSkinInfoFor = { + local float target_idx = target.colormap - 1; + local string color = TeamFortress_TeamGetColorFor(pov, target.team_no); + + msg_entity = pov; + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, target_idx); + WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, color); + WriteByte(MSG_ONE, SVC_SETINFO); + WriteByte(MSG_ONE, target_idx); + WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, color); +} + void () ClientConnect = { if (!infokeyf(self,INFOKEY_P_CSQCACTIVE)) { sprint(self, PRINT_HIGH, "FTE/CSQC is required for this server, please download the latest client package at www.fortressone.org\n"); @@ -3207,21 +3222,11 @@ void () ClientConnect = { UpdateClientPrematch(self, !cb_prematch); UpdateClient_VoteMap_AddAll(self); - local string color; + // Set skin colours local entity te = find(world, classname, "player"); while (te != world) { if (te != self) { - msg_entity = self; - color = TeamFortress_TeamGetColorFor(self, te.team_no); - - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, te.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, te.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); + SetSkinInfoFor(self, te); } te = find(te, classname, "player"); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 40b04273..ab1653db 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1173,28 +1173,16 @@ string(float pc) TeamFortress_GetSkin = return skin; }; - void (entity player) TeamFortress_SetSkinInfos = { local string st = TeamFortress_GetSkin(player.playerclass); local string command = sprintf("skin %s\n", st); stuffcmd(player, command); forceinfokey(player, "skin", st); // please fix mvd recording - local string color; local entity te = find(world, classname, "player"); while (te != world) { if (te != player) { - msg_entity = te; - color = TeamFortress_TeamGetColorFor(te, player.team_no); - - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "topcolor"); - WriteString(MSG_ONE, color); - WriteByte(MSG_ONE, SVC_SETINFO); - WriteByte(MSG_ONE, player.colormap-1); // ???? Copied from spy.qc - WriteString(MSG_ONE, "bottomcolor"); - WriteString(MSG_ONE, color); + SetSkinInfoFor(te, player); } te = find(te, classname, "player"); From e3a579a06e4e73417cb9c5f02b079069d1a36b61 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 12 Aug 2024 00:11:57 +1000 Subject: [PATCH 2428/2474] Remove accidentally committed --- ssqc/engineer.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 30a69f39..06c3785b 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1098,7 +1098,6 @@ void () TeamFortress_FinishedBuilding = { newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.mdl = "progs/turrgun.mdl"; - newmis.colormod = '0.5 0.5 0.5'; self.sentry_ent = newmis; FO_Sound(oldself, CHAN_ITEM, "weapons/turrset.wav", 1, 1); newmis.solid = SOLID_BBOX; From 0556818a9c4cced869b2bb6af28d13404e471568 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Aug 2024 15:37:26 +1000 Subject: [PATCH 2429/2474] Update readme --- README.md | 5 +---- csqc/main.qc | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f4faeedf..c07f4ec0 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * `localinfo fo_matchrated 2` whether match is rated / affects trueskill. 2 is false for 1v1 and 2v2 only. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ * All-time attack and all-time defence team options. -* `setinfo team1color ` to set the top and bottom colours for team 1. -* `setinfo team2color ` to set the top and bottom colours for team 2. -* `setinfo team3color ` to set the top and bottom colours for team 3. -* `setinfo team4color ` to set the top and bottom colours for team 4. +* `setinfo teamcolor ` sets player skins colours for team , where is quake palette 0-15 or hex code beginning with 0x. E.g. `setinfo team1colour 0` makes all team 1 players white, `setinfo team2color 0xFF8800` makes all team 2 players orange. `setinfo teamcolor ""` to restore defaults. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. diff --git a/csqc/main.qc b/csqc/main.qc index 23cd0252..122428c7 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -621,6 +621,7 @@ static void UpdateTeamColorCrosshair() { break; case 4: crosshair_color = "0x00ff00"; + break; } localcmd("crosshaircolor ", crosshair_color, "\n"); crosshair_team_no = team_no; From e7485413fa8664976d055f73212a5162a0b20b47 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 14 Aug 2024 16:22:10 +1000 Subject: [PATCH 2430/2474] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c07f4ec0..30eec0af 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * `localinfo fo_matchrated 2` whether match is rated / affects trueskill. 2 is false for 1v1 and 2v2 only. * `localinfo backend_address ` to specify backend API endpoint. Default: https://www.fortressone.org/ * All-time attack and all-time defence team options. -* `setinfo teamcolor ` sets player skins colours for team , where is quake palette 0-15 or hex code beginning with 0x. E.g. `setinfo team1colour 0` makes all team 1 players white, `setinfo team2color 0xFF8800` makes all team 2 players orange. `setinfo teamcolor ""` to restore defaults. +* `setinfo teamcolor ` sets player skins colours for team , where is quake palette 0-15 or hex code beginning with 0x. E.g. `setinfo team1colour 0` makes all team 1 players white, `setinfo team2color 0xFF8800` makes all team 2 players orange. `setinfo teamcolor ""` to restore defaults. Note that `teamcolor` and `enemycolor` cvars will take priority. * `setinfo precise_grenades on/off` to enable precise timing when throwing grenades. This removes a random, up to, 100ms input delay. (default on) * `localinfo forcereload 0/1` Option to prevent forced reloads. * `+grenade1` and `+grenade2` grenade buttons (more reliable than impulses), push to prime, again to throw. From b2d8d5cb26f4d7040d6b02b06f25d5e715c3f736 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Aug 2024 22:30:58 +1000 Subject: [PATCH 2431/2474] Refactor --- share/defs.h | 6 ++ ssqc/client.qc | 4 +- ssqc/commands.qc | 47 ++++++-------- ssqc/functions.qc | 4 +- ssqc/menu.qc | 2 +- ssqc/spy.qc | 4 +- ssqc/tfort.qc | 50 ++++++++------ ssqc/tforttm.qc | 162 ++++++++++++++++++++-------------------------- 8 files changed, 132 insertions(+), 147 deletions(-) diff --git a/share/defs.h b/share/defs.h index a96d8bcd..90db6749 100644 --- a/share/defs.h +++ b/share/defs.h @@ -679,6 +679,12 @@ struct Slot { int id; }; #define YELLOW 13 #define DARKBLUE 14 +#define NOTEAMCOLOR "0xffffff" +#define BLUETEAMCOLOR "0x00aaff" +#define REDTEAMCOLOR "0xff3333" +#define YELLOWTEAMCOLOR "0xffbb00" +#define GREENTEAMCOLOR "0x00ff44" + /*======================================================*/ /* Defines for the ENGINEER's Building ability */ /*======================================================*/ diff --git a/ssqc/client.qc b/ssqc/client.qc index c4fe5851..fd7653bd 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -10,7 +10,7 @@ float modelindex_null; float (entity pe_player) Spy_CheckArea; -void () TeamFortress_CheckTeamCheats; +void (entity player) TeamFortress_CheckTeamCheats; void () TeamFortress_CheckforCheats; void (entity Viewer, float pc, float rpc) TeamFortress_PrintClassName; void () TeamFortress_RemoveTimers; @@ -3102,7 +3102,7 @@ static void PlayerPostThinkAlive() { } } if (self.cheat_check <= time) { - TeamFortress_CheckTeamCheats(); + TeamFortress_CheckTeamCheats(self); self.cheat_check = time + 3; } } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1645202f..b1492fe8 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -138,7 +138,7 @@ void (entity pe) SetEquipmentForPlayer = { //self.immune_to_check = time + 10; //self.undercover_team = 0; stuffcmd(self, "color "); - string st = ftos(TeamFortress_TeamGetColor(self.team_no) - 1); + string st = TeamFortress_TeamGetColor(self.team_no); stuffcmd(self, st); stuffcmd(self, "\n"); @@ -381,37 +381,28 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "setinfo": if (arg2) { switch(arg2) { - case "topcolor": - case "bottomcolor": - float arg3f = stof(arg3); - if ((self.team_no > 0) && (teamplay > 0)) { - if (arg3f != (TeamFortress_TeamGetColor(self.team_no) - 1)) { - arg3f = TeamFortress_TeamGetColor(self.team_no) - 1; - string st; - st = ftos(arg3f); - stuffcmd(self, strcat("color ", st, "\n")); - sprint(self, PRINT_HIGH, - "Your color has been changed to your team color\n"); - processedCmd = TRUE; - } - } - break; + /* case "topcolor": */ + /* case "bottomcolor": */ + /* case "color": */ + /* TeamFortress_SetSkin(self); */ + /* processedCmd = TRUE; */ + /* break; */ case "team1color": - UpdateTeamColor(self, arg3, 1); - processedCmd = TRUE; - break; + UpdateTeamColor(self, arg3, 1); + processedCmd = TRUE; + break; case "team2color": - UpdateTeamColor(self, arg3, 2); - processedCmd = TRUE; - break; + UpdateTeamColor(self, arg3, 2); + processedCmd = TRUE; + break; case "team3color": - UpdateTeamColor(self, arg3, 3); - processedCmd = TRUE; - break; + UpdateTeamColor(self, arg3, 3); + processedCmd = TRUE; + break; case "team4color": - UpdateTeamColor(self, arg3, 4); - processedCmd = TRUE; - break; + UpdateTeamColor(self, arg3, 4); + processedCmd = TRUE; + break; } } break; diff --git a/ssqc/functions.qc b/ssqc/functions.qc index c0f7623d..1b8b2273 100644 --- a/ssqc/functions.qc +++ b/ssqc/functions.qc @@ -1,5 +1,5 @@ float (float tno) TeamFortress_TeamSet; -float (float tno) TeamFortress_TeamGetColor; +string (float tno) TeamFortress_TeamGetColor; string (entity pov, float tno) TeamFortress_TeamGetColorFor; void (entity p) SetTeamName; void (entity pl) Menu_Close; @@ -9,7 +9,7 @@ void (float tno) playerSetTeam = { TeamFortress_TeamSet(tno); self.team_no = tno; stuffcmd(self, "color "); - st = ftos(TeamFortress_TeamGetColor (tno) - 1); + st = TeamFortress_TeamGetColor(tno); stuffcmd(self, st); stuffcmd(self, "\n"); SetTeamName(self); diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 9b0429fd..24e57811 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -25,7 +25,7 @@ void () lvl2_sentry_stand; void () lvl3_sentry_stand; float (float tno) TeamFortress_TeamSet; -float (float tno) TeamFortress_TeamGetColor; +string (float tno) TeamFortress_TeamGetColor; float () TeamFortress_TeamPutPlayerInTeam; float (float tno) TeamFortress_TeamIsCivilian; float (float tno) TeamFortress_TeamGetNoPlayers; diff --git a/ssqc/spy.qc b/ssqc/spy.qc index b0a5820f..c8701ee0 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -698,7 +698,6 @@ void (entity pe_player, float pf_class, float is_user) CF_Spy_ChangeSkin = { void (entity pe_player, float pf_team_no, float is_user) CF_Spy_ChangeColor = { local entity e_timer; - local float f_team_color = TeamFortress_TeamGetColor(pf_team_no) - 1; // stop if you're already disguised as the requested skin if (pe_player.undercover_team == pf_team_no) @@ -1208,8 +1207,9 @@ void (entity spy) Spy_RemoveDisguise = { timer = find(timer, classname, "spytimer"); } - if (coverblown) + if (coverblown) { Status_Print(self, "\n\n\n\n\n\n\n", "You blew your cover!"); + } local float autodisguise = FO_GetUserSetting(self, "autodisguise", "ad", "off"); if (self.playerclass == PC_SPY) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index ab1653db..3a4d56d4 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1132,12 +1132,10 @@ string (float tn) TeamFortress_GetColorSkin = { return s; } -string(float pc) TeamFortress_GetSkin = -{ +string(float pc) TeamFortress_GetSkin = { local string skin = "base"; - switch (pc) - { + switch (pc) { case 1: skin = "fo_scout"; break; @@ -1168,23 +1166,26 @@ string(float pc) TeamFortress_GetSkin = case 11: skin = "fo_civ"; break; - } + return skin; }; void (entity player) TeamFortress_SetSkinInfos = { - local string st = TeamFortress_GetSkin(player.playerclass); - local string command = sprintf("skin %s\n", st); - stuffcmd(player, command); - forceinfokey(player, "skin", st); // please fix mvd recording + bprint(PRINT_HIGH, "Setting infokeys\n"); + local string sk = TeamFortress_GetSkin(player.playerclass); + forceinfokey(player, "skin", sk); + stuffcmd(player, sprintf("skin %s\n", sk)); + + local string col = TeamFortress_TeamGetColor(player.team_no); + forceinfokey(player, "bottomcolor", col); + stuffcmd(player, sprintf("setinfo bottomcolor %s\n", col)); + forceinfokey(player, "topcolor", col); + stuffcmd(player, sprintf("setinfo topcolor %s\n", col)); local entity te = find(world, classname, "player"); while (te != world) { - if (te != player) { - SetSkinInfoFor(te, player); - } - + SetSkinInfoFor(te, player); te = find(te, classname, "player"); } } @@ -1198,14 +1199,21 @@ void (entity p) TeamFortress_SetSkin = { } else { Spy_SetClientSkins(p); } - } else { - p.skin = p.playerclass; - if (p.skin != 0) { - TeamFortress_SetSkinInfos(p); - } else { - stuffcmd(p, "skin base\n"); - } + return; + } + + p.skin = p.playerclass; + + if (p.skin != 0) { + TeamFortress_SetSkinInfos(p); + } else { + forceinfokey(p, "skin", "base"); + stuffcmd(p, sprintf("skin %s\n", "base")); + forceinfokey(p, "bottomcolor", NOTEAMCOLOR); + stuffcmd(p, sprintf("bottomcolor %s\n", NOTEAMCOLOR)); + forceinfokey(p, "topcolor", NOTEAMCOLOR); + stuffcmd(p, sprintf("topcolor %s\n", NOTEAMCOLOR)); } }; @@ -1241,7 +1249,7 @@ void () TeamFortress_SetEquipment = { self.immune_to_check = time + 10; self.undercover_team = 0; stuffcmd(self, "color "); - st = ftos(TeamFortress_TeamGetColor(self.team_no) - 1); + st = TeamFortress_TeamGetColor(self.team_no); stuffcmd(self, st); stuffcmd(self, "\n"); } diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 40201390..0b41de62 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -39,20 +39,29 @@ float () TeamFortress_TeamPutPlayerInTeam = return (TeamFortress_TeamSet(likely_team)); }; -float (float tno) TeamFortress_TeamGetColor = { - if (tno == 1) - return (DARKBLUE); - if (tno == 2) - return (RED); - if (tno == 3) - return (YELLOW); - if (tno == 4) - return (DARKGREEN); - return (1); +string (float tno) TeamFortress_TeamGetColor = { + local string color = NOTEAMCOLOR; + + switch (tno) { + case 1: + color = BLUETEAMCOLOR; + break; + case 2: + color = REDTEAMCOLOR; + break; + case 3: + color = YELLOWTEAMCOLOR; + break; + case 4: + color = GREENTEAMCOLOR; + break; + } + + return color; }; string TeamFortress_TeamGetColorFor(entity pov, float tno) { - local string color = "0xFFFFFF"; + local string color = NOTEAMCOLOR; if (pov.team_no == tno && cvar("teamcolor")) { color = cvar_string("teamcolor"); @@ -63,22 +72,22 @@ string TeamFortress_TeamGetColorFor(entity pov, float tno) { case 1: color = infokey(pov, "team1color"); if (color == "") - color = "0x00AAFF"; + color = BLUETEAMCOLOR; break; case 2: color = infokey(pov, "team2color"); if (color == "") - color = "0xFF2222"; + color = REDTEAMCOLOR; break; case 3: color = infokey(pov, "team3color"); if (color == "") - color = "0xFFBB00"; + color = YELLOWTEAMCOLOR; break; case 4: color = infokey(pov, "team4color"); if (color == "") - color = "0x00FF44"; + color = GREENTEAMCOLOR; break; } } @@ -192,7 +201,6 @@ float (float tno) CF_TeamIsValid = { float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options = { local string st; - local float tc; local string team; if ((intermission_running != 0) || (intermission_exittime > time)) @@ -241,8 +249,7 @@ float (entity pe, float tno, float skipclasscheck) TeamFortress_TeamSet_Options bprint(PRINT_HIGH, pe.netname, " has joined the "); bprint(PRINT_HIGH, team, "\n"); stuffcmd(pe, "color "); - tc = TeamFortress_TeamGetColor(tno) - 1; - st = ftos(tc); + st = TeamFortress_TeamGetColor(tno); stuffcmd(pe, st); stuffcmd(pe, "\n"); @@ -312,63 +319,49 @@ float (float tno) TeamFortress_TeamSet = { return (tftso); } -void () TeamFortress_CheckTeamCheats = { +void (entity player) TeamFortress_CheckTeamCheats = { local string st; local string sk; - local float tc; - if (self.immune_to_check > time) + if (player.immune_to_check > time) return; - if (self.deadflag) + if (player.deadflag) return; - if (self.netname == string_null) { - KickCheater(self); + if (player.netname == string_null) { + KickCheater(player); } else { - if (((self.playerclass != 0) && (self.team_no == 0)) && + if (((player.playerclass != 0) && (player.team_no == 0)) && (teamplay > 0)) { - KickCheater(self); + KickCheater(player); } } - if ((self.team_no > 0) && (teamplay > 0)) { - st = infokey(self, "bottomcolor"); - tc = stof(st); - if (tc != (TeamFortress_TeamGetColor(self.team_no) - 1)) { - stuffcmd(self, "color "); - tc = TeamFortress_TeamGetColor(self.team_no) - 1; - st = ftos(tc); - stuffcmd(self, st); - stuffcmd(self, "\n"); - /*bprint2(PRINT_MEDIUM, self.netname, - " has been kicked for changing color\n"); - sprint(self, PRINT_HIGH, - "You have been kicked for changing your pants color\n"); - KickCheater(self);*/ - return; + if ((player.team_no > 0) && (teamplay > 0)) { + st = infokey(player, "bottomcolor"); + if (st != TeamFortress_TeamGetColor(player.team_no)) { + bprint(PRINT_HIGH, "INHERE!\n"); + TeamFortress_SetSkin(player); } - if (self.playerclass != 0) { - st = infokey(self, "skin"); - tc = 0; - sk = TeamFortress_GetSkin(self.playerclass); + if (player.playerclass != 0) { + st = infokey(player, "skin"); + sk = TeamFortress_GetSkin(player.playerclass); if (st != sk) { - TeamFortress_SetSkin(self); - bprint(PRINT_MEDIUM, self.netname, + TeamFortress_SetSkin(player); + bprint(PRINT_MEDIUM, player.netname, " has been kicked for changing skin\n"); - sprint(self, PRINT_HIGH, + sprint(player, PRINT_HIGH, "You have been kicked for changing your skin\n"); - KickCheater(self); + KickCheater(player); } - if (tc == 8) - self.playerclass = 8; } - st = GetTeamName(self.team_no); - if (st != infokey(self, "team")) { - SetTeamName(self); - bprint(PRINT_MEDIUM, self.netname, + st = GetTeamName(player.team_no); + if (st != infokey(player, "team")) { + SetTeamName(player); + bprint(PRINT_MEDIUM, player.netname, " has been kicked for changing team\n"); - sprint(self, PRINT_HIGH, + sprint(player, PRINT_HIGH, "You have been kicked for changing your team\n"); - KickCheater(self); + KickCheater(player); return; } } @@ -615,7 +608,7 @@ void (float all) TeamFortress_TeamShowScores = { i = 1; if (all == 2) { while (i <= number_of_teams) { - if (TeamFortress_TeamGetColor(i) > 0) { + if (TeamFortress_TeamGetColor(i) != NOTEAMCOLOR) { j = TeamFortress_TeamGetScore(i); st = TeamFortress_TeamGetColorString(i); bprint(PRINT_HIGH, st, ": "); @@ -628,7 +621,7 @@ void (float all) TeamFortress_TeamShowScores = { return; } while (i <= number_of_teams) { - if (TeamFortress_TeamGetColor(i) > 0) { + if (TeamFortress_TeamGetColor(i) != NOTEAMCOLOR) { if (all) { bprint(PRINT_HIGH, "Team "); } else { @@ -673,38 +666,25 @@ void (float all) TeamFortress_TeamShowScores = { } }; -string(float tno) TeamFortress_TeamGetColorString = -{ - local float col; - - col = TeamFortress_TeamGetColor(tno); - if (col == WHITE) - return ("White"); - if (col == BROWN) - return ("Brown"); - if (col == BLUE) - return ("Blue"); - if (col == GREEN) - return ("Green"); - if (col == RED) - return ("Red"); - if (col == TAN) - return ("Tan"); - if (col == PINK) - return ("Pink"); - if (col == ORANGE) - return ("Orange"); - if (col == PURPLE) - return ("Purple"); - if (col == DARKPURPLE) - return ("DarkPurple"); - if (col == GREY) - return ("Grey"); - if (col == DARKGREEN) - return ("DarkGreen"); - if (col == YELLOW) - return ("Yellow"); - return ("Blue"); +string(float tno) TeamFortress_TeamGetColorString = { + local string colour = "White"; + + switch(tno) { + case 1: + colour = "Blue"; + break; + case 2: + colour = "Red"; + break; + case 3: + colour = "Yellow"; + break; + case 4: + colour = "Green"; + break; + } + + return colour; }; void (entity Player) TeamFortress_TeamShowMemberClasses = { From 208012269ba7248f402fb0b1f7d22e4b86241d8d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 25 Aug 2024 22:50:26 +1000 Subject: [PATCH 2432/2474] Don't reveal spies by spamming teamxcolor setinfos --- ssqc/commands.qc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index b1492fe8..3644be10 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -334,9 +334,7 @@ void (entity pov, string color, float tno) UpdateTeamColor = { local entity te = find(world, classname, "player"); while (te != world) { - if (te.team_no == tno) { - TeamFortress_SetSkin(te); - } + TeamFortress_SetSkin(te); te = find(te, classname, "player"); } From 757c48b23f65867e4b3eeb855c8b30864d27f72a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 26 Aug 2024 21:36:06 +1000 Subject: [PATCH 2433/2474] Support off option for setxcolor like enemycolor and teamcolor --- ssqc/commands.qc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 3644be10..20f55be8 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -314,6 +314,10 @@ void (entity pl) PrintWho = { } void (entity pov, string color, float tno) UpdateTeamColor = { + if (color == "off"){ + color = ""; + } + local string command = ""; switch (tno) { case 1: From 07c48fc20668896f1b1a2afd799499c664a39687 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 28 Aug 2024 00:14:56 +1000 Subject: [PATCH 2434/2474] Remove debug statement --- ssqc/tfort.qc | 1 - 1 file changed, 1 deletion(-) diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3a4d56d4..cf92061a 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1172,7 +1172,6 @@ string(float pc) TeamFortress_GetSkin = { }; void (entity player) TeamFortress_SetSkinInfos = { - bprint(PRINT_HIGH, "Setting infokeys\n"); local string sk = TeamFortress_GetSkin(player.playerclass); forceinfokey(player, "skin", sk); stuffcmd(player, sprintf("skin %s\n", sk)); From 3b862549ea79bd9f453021c824d34eca59c82561 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 28 Aug 2024 00:17:03 +1000 Subject: [PATCH 2435/2474] Make yellow a bit more yellow --- share/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/defs.h b/share/defs.h index 90db6749..52397bfe 100644 --- a/share/defs.h +++ b/share/defs.h @@ -682,7 +682,7 @@ struct Slot { int id; }; #define NOTEAMCOLOR "0xffffff" #define BLUETEAMCOLOR "0x00aaff" #define REDTEAMCOLOR "0xff3333" -#define YELLOWTEAMCOLOR "0xffbb00" +#define YELLOWTEAMCOLOR "0xffdd00" #define GREENTEAMCOLOR "0x00ff44" /*======================================================*/ From 34b4920eea70e350f4b60ceb7aab8cc6f00a3fed Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 28 Aug 2024 12:21:55 +1000 Subject: [PATCH 2436/2474] Fix teamxcolor 'off' not respected on server join --- ssqc/commands.qc | 5 +---- ssqc/tforttm.qc | 8 ++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 20f55be8..b88ed70d 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -314,11 +314,8 @@ void (entity pl) PrintWho = { } void (entity pov, string color, float tno) UpdateTeamColor = { - if (color == "off"){ - color = ""; - } - local string command = ""; + switch (tno) { case 1: command = "team1color"; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index 0b41de62..e55f7921 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -71,22 +71,22 @@ string TeamFortress_TeamGetColorFor(entity pov, float tno) { switch (tno) { case 1: color = infokey(pov, "team1color"); - if (color == "") + if (color == "" || color == "off") color = BLUETEAMCOLOR; break; case 2: color = infokey(pov, "team2color"); - if (color == "") + if (color == "" || color == "off") color = REDTEAMCOLOR; break; case 3: color = infokey(pov, "team3color"); - if (color == "") + if (color == "" || color == "off") color = YELLOWTEAMCOLOR; break; case 4: color = infokey(pov, "team4color"); - if (color == "") + if (color == "" || color == "off") color = GREENTEAMCOLOR; break; } From e3c52d6df4981a8dbdd2c5a6882895547cf006ba Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 28 Aug 2024 12:34:16 +1000 Subject: [PATCH 2437/2474] Refactor --- ssqc/commands.qc | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/ssqc/commands.qc b/ssqc/commands.qc index b88ed70d..8ad3fe31 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -313,24 +313,7 @@ void (entity pl) PrintWho = { strunzone(msg); } -void (entity pov, string color, float tno) UpdateTeamColor = { - local string command = ""; - - switch (tno) { - case 1: - command = "team1color"; - break; - case 2: - command = "team2color"; - break; - case 3: - command = "team3color"; - break; - case 4: - command = "team4color"; - break; - } - +void (entity pov, string command, string color) UpdateTeamColor = { forceinfokey(pov, command, color); local entity te = find(world, classname, "player"); @@ -387,19 +370,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { /* processedCmd = TRUE; */ /* break; */ case "team1color": - UpdateTeamColor(self, arg3, 1); - processedCmd = TRUE; - break; case "team2color": - UpdateTeamColor(self, arg3, 2); - processedCmd = TRUE; - break; case "team3color": - UpdateTeamColor(self, arg3, 3); - processedCmd = TRUE; - break; case "team4color": - UpdateTeamColor(self, arg3, 4); + UpdateTeamColor(self, arg2, arg3); processedCmd = TRUE; break; } From eaecdce1c09e09e2f2142edfc996f135a7f6ee59 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 29 Aug 2024 00:16:52 +1000 Subject: [PATCH 2438/2474] don't send stuffs, remove debug --- ssqc/client.qc | 5 +---- ssqc/tfort.qc | 4 ++-- ssqc/tforttm.qc | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index fd7653bd..97490eee 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3225,10 +3225,7 @@ void () ClientConnect = { // Set skin colours local entity te = find(world, classname, "player"); while (te != world) { - if (te != self) { - SetSkinInfoFor(self, te); - } - + SetSkinInfoFor(self, te); te = find(te, classname, "player"); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index cf92061a..3d3bde5a 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1178,9 +1178,9 @@ void (entity player) TeamFortress_SetSkinInfos = { local string col = TeamFortress_TeamGetColor(player.team_no); forceinfokey(player, "bottomcolor", col); - stuffcmd(player, sprintf("setinfo bottomcolor %s\n", col)); + /* stuffcmd(player, sprintf("setinfo bottomcolor %s\n", col)); */ forceinfokey(player, "topcolor", col); - stuffcmd(player, sprintf("setinfo topcolor %s\n", col)); + /* stuffcmd(player, sprintf("setinfo topcolor %s\n", col)); */ local entity te = find(world, classname, "player"); while (te != world) { diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index e55f7921..d846c31e 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -339,7 +339,6 @@ void (entity player) TeamFortress_CheckTeamCheats = { if ((player.team_no > 0) && (teamplay > 0)) { st = infokey(player, "bottomcolor"); if (st != TeamFortress_TeamGetColor(player.team_no)) { - bprint(PRINT_HIGH, "INHERE!\n"); TeamFortress_SetSkin(player); } if (player.playerclass != 0) { From d45befc3c11e726a5b429211165835fb98b1ab6b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 11 Sep 2024 15:15:33 +1000 Subject: [PATCH 2439/2474] Do skin updates on next prethink --- ssqc/client.qc | 54 +++++++++++++++++++++++++++++++++++--------- ssqc/commands.qc | 15 ++++--------- ssqc/qw.qc | 1 + ssqc/tfort.qc | 58 ++++++++++++++++++------------------------------ ssqc/tforttm.qc | 3 +++ 5 files changed, 74 insertions(+), 57 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 97490eee..42b504f2 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -73,6 +73,8 @@ void StopAssCan(); void Predict_InitPlayer(entity player); void Predict_Destroy(entity player); +void SetSkinInfoFor(entity pov, entity target); + void () info_intermission = { if (CheckExistence() == 0) { @@ -2768,9 +2770,31 @@ static void ConcUpdate() { } } +// If a forceinfokey and a SVC_SETINFO are both set in the same frame, they +// will clobber each other. Thus we do skin setinfos like normal, and then +// per-player custom skin infos are immediately applied for those who need to +// update on the next frame. +void () UpdateAllSkins = { + local entity target = find(world, classname, "player"); + local entity pov; + + while (target != world) { + if (target.needs_skin_update) { + pov = find(world, classname, "player"); + while (pov != world) { + SetSkinInfoFor(pov, target); + pov = find(pov, classname, "player"); + } + target.needs_skin_update = 0; + } + target = find(target, classname, "player"); + } +} + void () PlayerPreThink = { FO_UpdateClientTime(); ConcUpdate(); + UpdateAllSkins(); if (self.impulse) { if (self.impulse == TF_VOTENEXT) { @@ -3147,21 +3171,37 @@ void () UpdateAllClientsTeamScores = { } } -void (entity pov, entity target) SetSkinInfoFor = { +void (entity pov, entity target) SetBottomColorInfoFor = { local float target_idx = target.colormap - 1; local string color = TeamFortress_TeamGetColorFor(pov, target.team_no); + bprint(PRINT_HIGH, sprintf("Setting bottomcolor %s on %s for %s\n", color, target.netname, pov.netname)); + msg_entity = pov; WriteByte(MSG_ONE, SVC_SETINFO); WriteByte(MSG_ONE, target_idx); - WriteString(MSG_ONE, "topcolor"); + WriteString(MSG_ONE, "bottomcolor"); WriteString(MSG_ONE, color); +} + +void (entity pov, entity target) SetTopColorInfoFor = { + local float target_idx = target.colormap - 1; + local string color = TeamFortress_TeamGetColorFor(pov, target.team_no); + + bprint(PRINT_HIGH, sprintf("Setting topcolor %s on %s for %s\n", color, target.netname, pov.netname)); + + msg_entity = pov; WriteByte(MSG_ONE, SVC_SETINFO); WriteByte(MSG_ONE, target_idx); - WriteString(MSG_ONE, "bottomcolor"); + WriteString(MSG_ONE, "topcolor"); WriteString(MSG_ONE, color); } +void (entity pov, entity target) SetSkinInfoFor = { + SetTopColorInfoFor(pov, target); + SetBottomColorInfoFor(pov, target); +} + void () ClientConnect = { if (!infokeyf(self,INFOKEY_P_CSQCACTIVE)) { sprint(self, PRINT_HIGH, "FTE/CSQC is required for this server, please download the latest client package at www.fortressone.org\n"); @@ -3221,13 +3261,7 @@ void () ClientConnect = { UpdateClientTeamScores(self); UpdateClientPrematch(self, !cb_prematch); UpdateClient_VoteMap_AddAll(self); - - // Set skin colours - local entity te = find(world, classname, "player"); - while (te != world) { - SetSkinInfoFor(self, te); - te = find(te, classname, "player"); - } + TeamFortress_SetSkin(self); if (cb_prematch) sprint(self, PRINT_HIGH, "Currently in \sprematch\s time\n"); diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 8ad3fe31..1ea3f23a 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -316,11 +316,10 @@ void (entity pl) PrintWho = { void (entity pov, string command, string color) UpdateTeamColor = { forceinfokey(pov, command, color); - local entity te = find(world, classname, "player"); - while (te != world) { - TeamFortress_SetSkin(te); - - te = find(te, classname, "player"); + local entity target = find(world, classname, "player"); + while (target != world) { + SetSkinInfoFor(pov, target); + target = find(target, classname, "player"); } } @@ -363,12 +362,6 @@ float (string arg1, string arg2, string arg3) ParseCmds = { case "setinfo": if (arg2) { switch(arg2) { - /* case "topcolor": */ - /* case "bottomcolor": */ - /* case "color": */ - /* TeamFortress_SetSkin(self); */ - /* processedCmd = TRUE; */ - /* break; */ case "team1color": case "team2color": case "team3color": diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 96e73c72..9e0f5c06 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -100,6 +100,7 @@ float remote_client_time(); .float building_percentage; // The building percentage shown in status bar .float fragstreak; // Frag streak .float caps; // Caps during this game +.float needs_skin_update; // Set true when per-player skins need updating .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 3d3bde5a..d2b62474 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1171,48 +1171,34 @@ string(float pc) TeamFortress_GetSkin = { return skin; }; -void (entity player) TeamFortress_SetSkinInfos = { - local string sk = TeamFortress_GetSkin(player.playerclass); - forceinfokey(player, "skin", sk); - stuffcmd(player, sprintf("skin %s\n", sk)); - - local string col = TeamFortress_TeamGetColor(player.team_no); - forceinfokey(player, "bottomcolor", col); - /* stuffcmd(player, sprintf("setinfo bottomcolor %s\n", col)); */ - forceinfokey(player, "topcolor", col); - /* stuffcmd(player, sprintf("setinfo topcolor %s\n", col)); */ - - local entity te = find(world, classname, "player"); - while (te != world) { - SetSkinInfoFor(te, player); - te = find(te, classname, "player"); - } -} - -void (entity p) TeamFortress_SetSkin = { - p.immune_to_check = time + 10; - - if (p.playerclass == PC_SPY || p.last_playerclass == PC_SPY) { - if (!p.is_undercover) { - TeamFortress_SetSkinInfos(p); - } else { - Spy_SetClientSkins(p); - } +void (entity player) TeamFortress_SetSkin = { + player.immune_to_check = time + 10; + if (player.playerclass == PC_SPY && player.is_undercover) { + Spy_SetClientSkins(player); return; } - p.skin = p.playerclass; + player.skin = player.playerclass; + + if (player.skin != 0) { + player.needs_skin_update = 1; + local string sk = TeamFortress_GetSkin(player.playerclass); + forceinfokey(player, "skin", sk); + stuffcmd(player, sprintf("skin %s\n", sk)); - if (p.skin != 0) { - TeamFortress_SetSkinInfos(p); + local string col = TeamFortress_TeamGetColor(player.team_no); + forceinfokey(player, "bottomcolor", col); + stuffcmd(player, sprintf("setinfo bottomcolor %s\n", col)); + forceinfokey(player, "topcolor", col); + stuffcmd(player, sprintf("setinfo topcolor %s\n", col)); } else { - forceinfokey(p, "skin", "base"); - stuffcmd(p, sprintf("skin %s\n", "base")); - forceinfokey(p, "bottomcolor", NOTEAMCOLOR); - stuffcmd(p, sprintf("bottomcolor %s\n", NOTEAMCOLOR)); - forceinfokey(p, "topcolor", NOTEAMCOLOR); - stuffcmd(p, sprintf("topcolor %s\n", NOTEAMCOLOR)); + forceinfokey(player, "skin", "base"); + stuffcmd(player, sprintf("skin %s\n", "base")); + forceinfokey(player, "bottomcolor", NOTEAMCOLOR); + stuffcmd(player, sprintf("bottomcolor %s\n", NOTEAMCOLOR)); + forceinfokey(player, "topcolor", NOTEAMCOLOR); + stuffcmd(player, sprintf("topcolor %s\n", NOTEAMCOLOR)); } }; diff --git a/ssqc/tforttm.qc b/ssqc/tforttm.qc index d846c31e..9d886e15 100644 --- a/ssqc/tforttm.qc +++ b/ssqc/tforttm.qc @@ -339,6 +339,9 @@ void (entity player) TeamFortress_CheckTeamCheats = { if ((player.team_no > 0) && (teamplay > 0)) { st = infokey(player, "bottomcolor"); if (st != TeamFortress_TeamGetColor(player.team_no)) { + bprint(PRINT_HIGH, sprintf("%s's bottomcolor is wrong\n", player.netname)); + bprint(PRINT_HIGH, sprintf("setinfo: %s\n", st)); + bprint(PRINT_HIGH, sprintf("TF_TGC: %s\n", TeamFortress_TeamGetColor(player.team_no))); TeamFortress_SetSkin(player); } if (player.playerclass != 0) { From 271497b483c0e68ca0afd9cd05ebb5226fc35362 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 12 Sep 2024 20:59:36 +1000 Subject: [PATCH 2440/2474] Remove debug statements --- ssqc/client.qc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 42b504f2..5021fc08 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -3175,8 +3175,6 @@ void (entity pov, entity target) SetBottomColorInfoFor = { local float target_idx = target.colormap - 1; local string color = TeamFortress_TeamGetColorFor(pov, target.team_no); - bprint(PRINT_HIGH, sprintf("Setting bottomcolor %s on %s for %s\n", color, target.netname, pov.netname)); - msg_entity = pov; WriteByte(MSG_ONE, SVC_SETINFO); WriteByte(MSG_ONE, target_idx); @@ -3188,8 +3186,6 @@ void (entity pov, entity target) SetTopColorInfoFor = { local float target_idx = target.colormap - 1; local string color = TeamFortress_TeamGetColorFor(pov, target.team_no); - bprint(PRINT_HIGH, sprintf("Setting topcolor %s on %s for %s\n", color, target.netname, pov.netname)); - msg_entity = pov; WriteByte(MSG_ONE, SVC_SETINFO); WriteByte(MSG_ONE, target_idx); From e2ccab3f5a98fda55c4c2b769d2cc9c76cec71d7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 12 Sep 2024 23:42:57 +1000 Subject: [PATCH 2441/2474] Use seperate preview model --- csqc/main.qc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3d479f72..58988cb4 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -217,9 +217,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { temp_sentry = spawn(); temp_self = spawn(); - precache_model("progs/turrbase.mdl"); + precache_model("progs/turrpreview.mdl"); sentry_preview = spawn(); - setmodel(sentry_preview, "progs/turrbase.mdl"); + setmodel(sentry_preview, "progs/turrpreview.mdl"); sentry_preview.alpha = 0.5; precache_model("progs/sphere.mdl"); From b8767696656334b702aa54797b8507e146a3e5e6 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 13 Sep 2024 00:17:27 +1000 Subject: [PATCH 2442/2474] Remove the traceline requirement of a sentry --- share/engineer.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/share/engineer.qc b/share/engineer.qc index c7c5bdd7..24067fca 100644 --- a/share/engineer.qc +++ b/share/engineer.qc @@ -44,10 +44,10 @@ float (entity obj, entity builder) CheckArea = { if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } - traceline(builder.origin, obj.origin, 1, builder); - if (trace_fraction != 1) { - return (0); - } + /* traceline(builder.origin, obj.origin, 1, builder); */ + /* if (trace_fraction != 1) { */ + /* return (0); */ + /* } */ te = findradius(obj.origin, 64); if (te != world) { return (0); From 98c394ed015d446c4dfa211505daaa2843c33b2e Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 13 Sep 2024 01:01:58 +1000 Subject: [PATCH 2443/2474] Comment out mouse rotate for now --- csqc/menu.qc | 6 ++-- ssqc/commands.qc | 74 +++++++++++++++++++--------------------- ssqc/status.qc | 88 ++++++++++++++++++++++++------------------------ 3 files changed, 83 insertions(+), 85 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index ade4d32a..9a546d4a 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -327,7 +327,8 @@ var fo_menu FO_MENU_SENTRY_MAINTAIN = { {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, - {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + /* {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, */ {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { @@ -342,7 +343,8 @@ var fo_menu FO_MENU_SENTRY_ROTATE = { {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, - {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, + MenuSpacer, + /* {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, */ {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1e760c31..f5477c1c 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -737,22 +737,22 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { break; } - if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mouse" && arg4) { - if (self.rotating_sentry == world) - break; + /* if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mouse" && arg4) { */ + /* if (self.rotating_sentry == world) */ + /* break; */ - self.dimension_see = (self.dimension_see & ~DMN_GHOST) | DMN_HIDDEN; + /* self.dimension_see = (self.dimension_see & ~DMN_GHOST) | DMN_HIDDEN; */ - local entity rs = self.rotating_sentry; - rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; - farg4 = stof(arg4); - rs.angles_y = farg4; - rs.waitmin = anglemod(farg4 - 50); - rs.waitmax = anglemod(farg4 + 50); - FO_Sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, ATTN_NORM); - self.rotating_sentry = world; - break; - } + /* local entity rs = self.rotating_sentry; */ + /* rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; */ + /* farg4 = stof(arg4); */ + /* rs.angles_y = farg4; */ + /* rs.waitmin = anglemod(farg4 - 50); */ + /* rs.waitmax = anglemod(farg4 + 50); */ + /* FO_Sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, ATTN_NORM); */ + /* self.rotating_sentry = world; */ + /* break; */ + /* } */ //find sentry first ent = findradius(self.origin, ENG_BUILDING_MAINT_DISTANCE); @@ -764,18 +764,18 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { ent = ent.chain; } - if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mwheel" && arg4) { - if (!arg4) - break; + /* if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mwheel" && arg4) { */ + /* if (!arg4) */ + /* break; */ - farg4 = stof(arg4); - self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; - ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; - if (self.rotating_sentry == world) - self.rotating_sentry = ent; - UpdateClientSentryRotateBy(self, self.rotating_sentry, farg4); - break; - } + /* farg4 = stof(arg4); */ + /* self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; */ + /* ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; */ + /* if (self.rotating_sentry == world) */ + /* self.rotating_sentry = ent; */ + /* UpdateClientSentryRotateBy(self, self.rotating_sentry, farg4); */ + /* break; */ + /* } */ if (!ent) { sprint(self, PRINT_HIGH, "No sentry in range\n"); @@ -790,23 +790,19 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); break; } - if (arg3 == "mouse" && !arg4) { - if (!self.rotating_sentry == world) - break; + /* if (arg3 == "mouse" && !arg4) { */ + /* if (!self.rotating_sentry == world) */ + /* break; */ - self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; - ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; - self.rotating_sentry = ent; - UpdateClientSentryRotate(self, ent); - break; - } - if(farg3 < 0) { - sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); - } else { - sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3)," degrees anticlockwise...\n"); - } + /* self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; */ + /* ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; */ + /* self.rotating_sentry = ent; */ + /* UpdateClientSentryRotate(self, ent); */ + /* break; */ + /* } */ ent.waitmin = anglemod(ent.waitmin + farg3); ent.waitmax = anglemod(ent.waitmax + farg3); + ent.angles_y += farg3; break; } sprint(self, PRINT_HIGH, "Invalid choice.\n"); diff --git a/ssqc/status.qc b/ssqc/status.qc index d84b203f..28a2856c 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -767,50 +767,50 @@ void UpdateClientBuilding(entity pl) { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -void UpdateClientSentryRotate(entity pl, entity sentry) { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE); - WriteEntity(MSG_MULTICAST, sentry); - - local float frame_no; - if (sentry.frame >= 6) { - frame_no = 6; - } else if (sentry.frame >= 3) { - frame_no = 3; - } else { - frame_no = 0; - } - - WriteFloat(MSG_MULTICAST, frame_no); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - -void UpdateClientSentryRotateBy(entity pl, entity sentry, float offset) { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE_BY); - WriteEntity(MSG_MULTICAST, sentry); - - local float frame_no; - if (sentry.frame >= 6) { - frame_no = 6; - } else if (sentry.frame >= 3) { - frame_no = 3; - } else { - frame_no = 0; - } - - WriteFloat(MSG_MULTICAST, frame_no); - WriteFloat(MSG_MULTICAST, offset); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} +/* void UpdateClientSentryRotate(entity pl, entity sentry) { */ +/* if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) */ +/* return; */ + +/* msg_entity = pl; */ +/* WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); */ +/* WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE); */ +/* WriteEntity(MSG_MULTICAST, sentry); */ + +/* local float frame_no; */ +/* if (sentry.frame >= 6) { */ +/* frame_no = 6; */ +/* } else if (sentry.frame >= 3) { */ +/* frame_no = 3; */ +/* } else { */ +/* frame_no = 0; */ +/* } */ + +/* WriteFloat(MSG_MULTICAST, frame_no); */ +/* multicast('0 0 0', MULTICAST_ONE_NOSPECS); */ +/* } */ + +/* void UpdateClientSentryRotateBy(entity pl, entity sentry, float offset) { */ +/* if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) */ +/* return; */ + +/* msg_entity = pl; */ +/* WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); */ +/* WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE_BY); */ +/* WriteEntity(MSG_MULTICAST, sentry); */ + +/* local float frame_no; */ +/* if (sentry.frame >= 6) { */ +/* frame_no = 6; */ +/* } else if (sentry.frame >= 3) { */ +/* frame_no = 3; */ +/* } else { */ +/* frame_no = 0; */ +/* } */ + +/* WriteFloat(MSG_MULTICAST, frame_no); */ +/* WriteFloat(MSG_MULTICAST, offset); */ +/* multicast('0 0 0', MULTICAST_ONE_NOSPECS); */ +/* } */ void UpdateClientSentryDie(entity pl) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) From e82717a56beb049db7faecb9a819160e51766748 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 14 Sep 2024 10:51:54 +1000 Subject: [PATCH 2444/2474] make sentry rotating feel nicer --- csqc/main.qc | 17 +++++++++++++++++ ssqc/commands.qc | 11 +++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 58988cb4..e45df40a 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -139,6 +139,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Predict_Init(); CsGrenTimer::Init(); + registercommand("specialup"); + registercommand("specialdown"); + registercommand("+slot"); registercommand("-slot"); @@ -340,6 +343,20 @@ noref float(string cmd) CSQC_ConsoleCommand = { local float grentype; switch(argv(0)) { + case "specialup": + switch (WP_PlayerClass()) { + case PC_ENGINEER: + break; + } + localcmd("specialup\n"); + break; + case "specialdown": + switch (WP_PlayerClass()) { + case PC_ENGINEER: + break; + } + localcmd("specialdown\n"); + break; case "+slot": Slot_Keydown(stof(argv(1))); break; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index f5477c1c..054fb5a9 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -800,9 +800,16 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { /* UpdateClientSentryRotate(self, ent); */ /* break; */ /* } */ - ent.waitmin = anglemod(ent.waitmin + farg3); - ent.waitmax = anglemod(ent.waitmax + farg3); ent.angles_y += farg3; + ent.waitmin = rint(ent.angles_y - 50); + ent.waitmin = anglemod(ent.waitmin); + ent.waitmax = rint(ent.angles_y + 50); + ent.waitmax = anglemod(ent.waitmax); + if (ent.waitmin > ent.waitmax) { + ent.waitmin = ent.waitmax; + ent.waitmax = anglemod(ent.angles_y - 50); + } + ent.nextthink = time + 0.5; break; } sprint(self, PRINT_HIGH, "Invalid choice.\n"); From bec58b3f23af25c270f7d0bb7412ba2c91244c0f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sat, 14 Sep 2024 23:17:31 +1000 Subject: [PATCH 2445/2474] Support mousewheel rotation of sentry preview --- csqc/input.qc | 2 +- csqc/main.qc | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 1c16e44e..60db71d6 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -128,7 +128,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } if (previewing_sentry) { - sentry_preview.angles_y = anglemod(input_angles_y + (180 - sentry_preview_offset)); + sentry_preview.angles_y = anglemod(input_angles_y + (sentry_preview_offset + 180)); } default: } diff --git a/csqc/main.qc b/csqc/main.qc index e45df40a..5631820e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -346,16 +346,22 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "specialup": switch (WP_PlayerClass()) { case PC_ENGINEER: + if (previewing_sentry) { + sentry_preview.angles_y -= 15; + sentry_preview_offset -= 15; + } break; } - localcmd("specialup\n"); break; case "specialdown": switch (WP_PlayerClass()) { case PC_ENGINEER: + if (previewing_sentry) { + sentry_preview.angles_y += 15; + sentry_preview_offset += 15; + } break; } - localcmd("specialdown\n"); break; case "+slot": Slot_Keydown(stof(argv(1))); @@ -829,7 +835,7 @@ noref void CSQC_Input_Frame() { if (keyups & BUTTON0) { if (sentry_fits) { - localcmd(sprintf("cmd build sentry %f\n", -1 * sentry_preview_offset)); + localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); SentryPreviewStop(); } else { print("Not enough room to build here\n"); From a40ff3602ff5a827f902535885593f173b43bc4b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Sep 2024 00:01:43 +1000 Subject: [PATCH 2446/2474] Clean up some old rotate stuff --- csqc/events.qc | 27 ------------------- csqc/input.qc | 9 ------- csqc/main.qc | 63 +++++++++------------------------------------ share/commondefs.qc | 3 --- ssqc/commands.qc | 40 ---------------------------- ssqc/player.qc | 4 --- ssqc/qw.qc | 1 - ssqc/sentry.qc | 3 --- ssqc/status.qc | 55 --------------------------------------- 9 files changed, 12 insertions(+), 193 deletions(-) diff --git a/csqc/events.qc b/csqc/events.qc index 7c0392c4..2c37aa9a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -362,33 +362,6 @@ void() CSQC_Parse_Event = { case MSG_BUILDING: SentryPreviewStop(); break; - case MSG_SENTRY_ROTATE: - sentry_rotate.drawmask = MASK_ENGINE; - - local vector origin = getentity(readentitynum(), GE_ORIGINANDVECTORS); - setorigin(sentry_rotate, origin); - sentry_rotate.angles = vectoangles(v_forward); - sentry_rotate.frame = readfloat(); - rotating_sentry = TRUE; - break; - case MSG_SENTRY_ROTATE_BY: - local vector origin = getentity(readentitynum(), GE_ORIGINANDVECTORS); - sentry_rotate.frame = readfloat(); - local float offset = readfloat() * -1; - - if (!rotating_sentry) { - rotating_sentry = TRUE; - setorigin(sentry_rotate, origin); - sentry_rotate.angles = vectoangles(v_forward); - sentry_rotate.angles_y += offset; - sentry_rotate.drawmask = MASK_ENGINE; - } - - sentry_rotate.angles_y += offset; - break; - case MSG_SENTRY_DIE: - SentryRotateStop(); - break; case MSG_FLAG_DROP: pick_up_time = FALSE; break; diff --git a/csqc/input.qc b/csqc/input.qc index 60db71d6..87579ccf 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -118,15 +118,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } break; case IE_MOUSEDELTA: - if (rotating_sentry) { - sentry_rotate.angles_y = anglemod(sentry_rotate.angles_y + scanx * rotating_sensitivity * -1); - } - - if (rotating_preview) { - sentry_preview.angles_y = anglemod(sentry_preview.angles_y + scanx * rotating_sensitivity); - sentry_preview_offset = (sentry_preview_offset + scanx * rotating_sensitivity); - } - if (previewing_sentry) { sentry_preview.angles_y = anglemod(input_angles_y + (sentry_preview_offset + 180)); } diff --git a/csqc/main.qc b/csqc/main.qc index 5631820e..8a1da486 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -18,16 +18,10 @@ float CalculateWaterLevel(); void RenderHitTexts(); entity sentry_preview; entity sentry_preview_range_sphere; -entity sentry_rotate; entity temp_sentry; entity temp_self; float sentry_preview_offset; float previewing_sentry; -float rotating_preview; -float rotating_preview_y; -float rotating_sentry; -float rotating_sentry_y; -float rotating_sensitivity = 0.25; float prevent_firing; float sentry_fits; @@ -231,10 +225,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { sentry_preview_range_sphere.scale = 1000; sentry_preview_range_sphere.alpha = 0.02; - precache_model("progs/turrgun.mdl"); - sentry_rotate = spawn(); - setmodel(sentry_rotate, "progs/turrgun.mdl"); - print("CSQC initialization finished\n"); }; @@ -295,10 +285,6 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { temp_sentry.origin = sentry_preview.origin; local vector v_forward_range = normalize(v_forward) * 1024; sentry_preview_range_sphere.origin = sentry_preview.origin; - - if (rotating_preview) { - setviewprop(VF_CL_VIEWANGLES_Y, rotating_preview_y); - } } else { setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! } @@ -772,22 +758,15 @@ void SentryPreviewStart() { sentry_preview_range_sphere.drawmask = MASK_ENGINE; previewing_sentry = TRUE; + prevent_firing = TRUE; } void SentryPreviewStop() { - rotating_preview = FALSE; - rotating_preview_y = 0; previewing_sentry = FALSE; sentry_preview.drawmask = 0; sentry_preview_range_sphere.drawmask = 0; } -void SentryRotateStop() { - rotating_sentry = FALSE; - rotating_sentry_y = 0; - sentry_rotate.drawmask = 0; -} - noref void CSQC_Input_Frame() { local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; @@ -804,23 +783,13 @@ noref void CSQC_Input_Frame() { if (WP_PlayerClass() == PC_ENGINEER) { // Intercept sentry build - if (rotating_sentry) { - if (keyups & BUTTON0) { - localcmd(sprintf("cmd sentry rotate mouse %f\n", sentry_rotate.angles_y)); - SentryRotateStop(); - } - input_buttons &= ~BUTTON0; - } else if (!getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { + if (!getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { if (input_buttons & BUTTON4) { if (keydowns & BUTTON4) { if (!previewing_sentry) { SentryPreviewStart(); } else { SentryPreviewStop(); - - if (input_buttons & BUTTON0) { - prevent_firing = TRUE; - } } } @@ -829,18 +798,11 @@ noref void CSQC_Input_Frame() { if (previewing_sentry) { if (keydowns & BUTTON0) { - rotating_preview_y = input_angles_y; - rotating_preview = TRUE; - } - - if (keyups & BUTTON0) { if (sentry_fits) { localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); SentryPreviewStop(); } else { - print("Not enough room to build here\n"); - rotating_preview_y = 0; - rotating_preview = FALSE; + print("Can't build here\n"); } } @@ -849,13 +811,16 @@ noref void CSQC_Input_Frame() { } } - if (keyups & BUTTON0) { - prevent_firing = FALSE; - } + } - if (prevent_firing) { - input_buttons &= ~BUTTON0; - } + if (prevent_firing && !previewing_sentry && (keyups & BUTTON0)) { + printf("disabling prevent_firing\n"); + prevent_firing = FALSE; + } + + if (prevent_firing) { + printf("prevent_firing is true\n"); + input_buttons &= ~BUTTON0; } } @@ -932,10 +897,6 @@ void _Sync_ServerCommandFrame() { if (!game_state.is_alive) { if (previewing_sentry) SentryPreviewStop(); - - if (rotating_sentry) { - SentryRotateStop(); - } } sentry_fits = CheckArea(temp_sentry, temp_self); diff --git a/share/commondefs.qc b/share/commondefs.qc index b82a5500..1a7162aa 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -216,9 +216,6 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_FLAG_PICKUP 29 #define MSG_FLAG_DROP 30 #define MSG_BUILDING 31 -#define MSG_SENTRY_ROTATE 32 -#define MSG_SENTRY_DIE 33 -#define MSG_SENTRY_ROTATE_BY 34 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 054fb5a9..e235dc4c 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -737,23 +737,6 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { break; } - /* if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mouse" && arg4) { */ - /* if (self.rotating_sentry == world) */ - /* break; */ - - /* self.dimension_see = (self.dimension_see & ~DMN_GHOST) | DMN_HIDDEN; */ - - /* local entity rs = self.rotating_sentry; */ - /* rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; */ - /* farg4 = stof(arg4); */ - /* rs.angles_y = farg4; */ - /* rs.waitmin = anglemod(farg4 - 50); */ - /* rs.waitmax = anglemod(farg4 + 50); */ - /* FO_Sound(self, CHAN_ITEM, "weapons/turridle.wav", 1, ATTN_NORM); */ - /* self.rotating_sentry = world; */ - /* break; */ - /* } */ - //find sentry first ent = findradius(self.origin, ENG_BUILDING_MAINT_DISTANCE); while (ent) { @@ -764,19 +747,6 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { ent = ent.chain; } - /* if (arg2 && arg2 == "rotate" && arg3 && arg3 == "mwheel" && arg4) { */ - /* if (!arg4) */ - /* break; */ - - /* farg4 = stof(arg4); */ - /* self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; */ - /* ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; */ - /* if (self.rotating_sentry == world) */ - /* self.rotating_sentry = ent; */ - /* UpdateClientSentryRotateBy(self, self.rotating_sentry, farg4); */ - /* break; */ - /* } */ - if (!ent) { sprint(self, PRINT_HIGH, "No sentry in range\n"); break; @@ -790,16 +760,6 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); break; } - /* if (arg3 == "mouse" && !arg4) { */ - /* if (!self.rotating_sentry == world) */ - /* break; */ - - /* self.dimension_see = (self.dimension_see & ~DMN_HIDDEN) | DMN_GHOST; */ - /* ent.dimension_seen = (ent.dimension_seen & ~DMN_NOFLASH) | DMN_HIDDEN | DMN_GHOST; */ - /* self.rotating_sentry = ent; */ - /* UpdateClientSentryRotate(self, ent); */ - /* break; */ - /* } */ ent.angles_y += farg3; ent.waitmin = rint(ent.angles_y - 50); ent.waitmin = anglemod(ent.waitmin); diff --git a/ssqc/player.qc b/ssqc/player.qc index f3c5ed83..a934ed92 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -439,10 +439,6 @@ void () GibPlayer = { }; void () PlayerDie = { - local entity rs = self.rotating_sentry; - rs.dimension_seen = (rs.dimension_seen & ~(DMN_HIDDEN | DMN_GHOST)) | DMN_NOFLASH; - self.rotating_sentry = world; - self.spawn_gen += 1; self.last_death_ctime = self.client_time; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 837fdf6e..3cc1f985 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -203,7 +203,6 @@ float coop; .float has_dispenser; // TRUE for an ENGINEER if he has a dispenser .float has_sentry; // TRUE for an ENGINEER if he has a sentry .entity sentry_ent; // Contains sentry gun entity -.entity rotating_sentry; // Contains sentry gun currently being rotated .float real_frags; // Used to store the players frags when TeamFrags is On diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 3dc70e64..c1498741 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -376,9 +376,6 @@ void () Sentry_Die = { stuffcmd(self.real_owner, "play misc/chink.wav\n"); local entity ro = self.real_owner; ro.has_sentry = 0; - ro.dimension_see = (ro.dimension_see & ~DMN_GHOST) | DMN_HIDDEN; - UpdateClientSentryDie(ro); - ro.rotating_sentry = world; self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; self.think = Sentry_Explode; diff --git a/ssqc/status.qc b/ssqc/status.qc index 28a2856c..ed822338 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -767,61 +767,6 @@ void UpdateClientBuilding(entity pl) { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } -/* void UpdateClientSentryRotate(entity pl, entity sentry) { */ -/* if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) */ -/* return; */ - -/* msg_entity = pl; */ -/* WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); */ -/* WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE); */ -/* WriteEntity(MSG_MULTICAST, sentry); */ - -/* local float frame_no; */ -/* if (sentry.frame >= 6) { */ -/* frame_no = 6; */ -/* } else if (sentry.frame >= 3) { */ -/* frame_no = 3; */ -/* } else { */ -/* frame_no = 0; */ -/* } */ - -/* WriteFloat(MSG_MULTICAST, frame_no); */ -/* multicast('0 0 0', MULTICAST_ONE_NOSPECS); */ -/* } */ - -/* void UpdateClientSentryRotateBy(entity pl, entity sentry, float offset) { */ -/* if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) */ -/* return; */ - -/* msg_entity = pl; */ -/* WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); */ -/* WriteByte(MSG_MULTICAST, MSG_SENTRY_ROTATE_BY); */ -/* WriteEntity(MSG_MULTICAST, sentry); */ - -/* local float frame_no; */ -/* if (sentry.frame >= 6) { */ -/* frame_no = 6; */ -/* } else if (sentry.frame >= 3) { */ -/* frame_no = 3; */ -/* } else { */ -/* frame_no = 0; */ -/* } */ - -/* WriteFloat(MSG_MULTICAST, frame_no); */ -/* WriteFloat(MSG_MULTICAST, offset); */ -/* multicast('0 0 0', MULTICAST_ONE_NOSPECS); */ -/* } */ - -void UpdateClientSentryDie(entity pl) { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_SENTRY_DIE); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - void UpdateClientReloadSound(entity pl, float weapon) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From da5c514500485cafc5ee9428554adfa6024f2530 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Sep 2024 00:02:22 +1000 Subject: [PATCH 2447/2474] Remove debug statements --- csqc/main.qc | 2 -- 1 file changed, 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 8a1da486..f7e590ff 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -814,12 +814,10 @@ noref void CSQC_Input_Frame() { } if (prevent_firing && !previewing_sentry && (keyups & BUTTON0)) { - printf("disabling prevent_firing\n"); prevent_firing = FALSE; } if (prevent_firing) { - printf("prevent_firing is true\n"); input_buttons &= ~BUTTON0; } } From db33eeaccc374da5213a96baf9407f29e6239f26 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Sep 2024 00:11:32 +1000 Subject: [PATCH 2448/2474] Send rotate commands to server if no preview --- csqc/main.qc | 4 ++++ ssqc/commands.qc | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/csqc/main.qc b/csqc/main.qc index f7e590ff..e01d98d5 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -335,6 +335,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { if (previewing_sentry) { sentry_preview.angles_y -= 15; sentry_preview_offset -= 15; + } else { + localcmd("cmd sentry rotate 15\n"); } break; } @@ -345,6 +347,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { if (previewing_sentry) { sentry_preview.angles_y += 15; sentry_preview_offset += 15; + } else { + localcmd("cmd sentry rotate -15\n"); } break; } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index e235dc4c..a5920c68 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -760,7 +760,7 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); break; } - ent.angles_y += farg3; + ent.angles_y -= farg3; ent.waitmin = rint(ent.angles_y - 50); ent.waitmin = anglemod(ent.waitmin); ent.waitmax = rint(ent.angles_y + 50); From 52a42c99f6ad75a2342609f232e918b2dd32b194 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Sep 2024 00:51:03 +1000 Subject: [PATCH 2449/2474] More encompassing message --- ssqc/engineer.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 9081e23e..a4877de1 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -617,7 +617,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { } if (CheckArea(newmis, self) == 0) { - sprint(self, PRINT_HIGH, "Not enough room to build here\n"); + sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; } From 6cb97a26a67cc9b3a95ed45f2bc761e34a8dd7bb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Sep 2024 01:05:54 +1000 Subject: [PATCH 2450/2474] You should still be able to rotate sentry while menu is up --- csqc/input.qc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 87579ccf..1c734008 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -4,6 +4,15 @@ void FO_Menu_Game(float); // TRUE --> capture input // FALSE --> pass input on float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { + switch (evtype) + { + case IE_MOUSEDELTA: + if (previewing_sentry) { + sentry_preview.angles_y = anglemod(input_angles_y + (sentry_preview_offset + 180)); + } + default: + } + if (fo_hud_editor || fo_hud_menu_active) { sui_input_event(evtype, scanx, chary, devid); float menu_mouse = (fo_hud_menu_active && (CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)); @@ -117,11 +126,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; } break; - case IE_MOUSEDELTA: - if (previewing_sentry) { - sentry_preview.angles_y = anglemod(input_angles_y + (sentry_preview_offset + 180)); - } - default: } } From e24f5fbd30f5055929aa8819a81521f63aa7c30b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Sep 2024 21:08:48 +1000 Subject: [PATCH 2451/2474] make sentry preview a bit more transparent --- csqc/main.qc | 2 +- ssqc/engineer.qc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index e01d98d5..99f4ac1f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -217,7 +217,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { precache_model("progs/turrpreview.mdl"); sentry_preview = spawn(); setmodel(sentry_preview, "progs/turrpreview.mdl"); - sentry_preview.alpha = 0.5; + sentry_preview.alpha = 0.25; precache_model("progs/sphere.mdl"); sentry_preview_range_sphere = spawn(); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index a4877de1..e0ff64da 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -576,7 +576,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { tmp2 = newmis.origin - normalize(v_up) * 128; traceline(tmp1, tmp2, 1, world); if (trace_ent != world) { - sprint(self, PRINT_HIGH, "You cannot build here\n"); + sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; } From c32243d2448ac7f44f1fa63b7ac0df3a259d54d4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 15 Sep 2024 22:45:22 +1000 Subject: [PATCH 2452/2474] First pass at disguise next --- csqc/main.qc | 10 ++++++++-- ssqc/commands.qc | 4 ++++ ssqc/qw.qc | 1 + ssqc/spy.qc | 31 +++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index dd117c41..96784ebc 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -331,6 +331,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { switch(argv(0)) { case "specialup": switch (WP_PlayerClass()) { + case PC_SPY: + localcmd("cmd disguise next\n"); + break; case PC_ENGINEER: if (previewing_sentry) { sentry_preview.angles_y -= 15; @@ -338,11 +341,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { } else { localcmd("cmd sentry rotate 15\n"); } - break; + break; } break; case "specialdown": switch (WP_PlayerClass()) { + case PC_SPY: + localcmd("cmd disguise next\n"); + break; case PC_ENGINEER: if (previewing_sentry) { sentry_preview.angles_y += 15; @@ -350,7 +356,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } else { localcmd("cmd sentry rotate -15\n"); } - break; + break; } break; case "+slot": diff --git a/ssqc/commands.qc b/ssqc/commands.qc index cacec326..1abe8118 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -518,6 +518,10 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { break; } if (arg2) { + if(arg2 == "next") { + FO_Spy_DisguiseNext(self); + break; + } if(arg2 == "last") { Menu_Spy_Input(2); break; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 8291a633..39359a79 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -103,6 +103,7 @@ float remote_client_time(); .float needs_skin_update; // Set true when per-player skins need updating .entity nopickup; // Don't pick up this backpack/ammobox because it doesn't contain any of your ammo types +.entity disguised_as; // Used when cycling through disguises .float pstate; // Player state flags .float tfstate; // State flags for TeamFortress diff --git a/ssqc/spy.qc b/ssqc/spy.qc index c8701ee0..8ba0609c 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -452,6 +452,37 @@ void (entity player, float is_user) FO_Spy_DisguiseLast = { CF_Spy_ChangeSkin(player, player.last_selected_skin, is_user); }; +void (entity spy) FO_Spy_DisguiseNext = { + local entity te; + + if (spy.disguised_as != world) { + te = self.disguised_as; + + while (te != world) { + if (te.team_no != spy.team_no && te.skin != spy.disguised_as.skin) { + CF_Spy_DisguiseStop(); + Menu_Spy_Skin_Input(te.skin); + spy.disguised_as = te; + return; + } + te = find(te, classname, "player"); + } + } + + te = find(world, classname, "player"); + while (te != world) { + if (te.team_no != spy.team_no && te.skin != spy.disguise_skin) { + CF_Spy_DisguiseStop(); + Menu_Spy_Skin_Input(te.skin); + spy.disguised_as = te; + return; + } + te = find(te, classname, "player"); + } + + spy.disguised_as = world; +} + void (entity player, float is_user) FO_Spy_DisguiseLastSpawned = { local entity te = find(world, classname, "player"); local float latest_spawn_time = 0; From 10ff5a4cde7e0e83602e09b398b9dbf7a23f4e25 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Sep 2024 00:13:50 +1000 Subject: [PATCH 2453/2474] Disguise next and previous --- README.md | 2 ++ csqc/main.qc | 2 +- ssqc/commands.qc | 6 +++++- ssqc/spy.qc | 44 ++++++++++++++++++++++++++++---------------- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 30eec0af..cd10eb70 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * New buttons (not impulses): * `+special` Scout: `dash`, Demoman: `detpipe`, Medic: `aura`, Hwguy: `lock`, Pyro: `airblast`, Spy: `+feign`, Engineer: `toggledispenser`. * `+special2` Same as `special2`, but also has `+rj` for Soldier and Pyro. +* `specialup` Engineer: `cmd sentry rotate -15`, Spy: `cmd disguise prev`. +* `specialdown` Engineer: `cmd sentry rotate 15`, Spy: `cmd disguise next`. * `setinfo hold_grens` for press and hold `+grenade1` and `+grenade2` * `setinfo hold_fiegn` for press and hold feigning * `setinfo hold_detpack` for press and hold detpack diff --git a/csqc/main.qc b/csqc/main.qc index 96784ebc..f2f8c66f 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -332,7 +332,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { case "specialup": switch (WP_PlayerClass()) { case PC_SPY: - localcmd("cmd disguise next\n"); + localcmd("cmd disguise prev\n"); break; case PC_ENGINEER: if (previewing_sentry) { diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 1abe8118..5e93e0cf 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -519,7 +519,11 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { } if (arg2) { if(arg2 == "next") { - FO_Spy_DisguiseNext(self); + FO_Spy_DisguiseCycle(self, 1); + break; + } + if(arg2 == "prev") { + FO_Spy_DisguiseCycle(self, -1); break; } if(arg2 == "last") { diff --git a/ssqc/spy.qc b/ssqc/spy.qc index 8ba0609c..22ad025c 100644 --- a/ssqc/spy.qc +++ b/ssqc/spy.qc @@ -452,35 +452,47 @@ void (entity player, float is_user) FO_Spy_DisguiseLast = { CF_Spy_ChangeSkin(player, player.last_selected_skin, is_user); }; -void (entity spy) FO_Spy_DisguiseNext = { +void FO_Spy_DisguiseCycle(entity spy, float direction) { + local float current_skin = spy.disguise_skin; local entity te; - if (spy.disguised_as != world) { - te = self.disguised_as; - + if (!current_skin) { + te = find(world, classname, "player"); while (te != world) { - if (te.team_no != spy.team_no && te.skin != spy.disguised_as.skin) { + if (te.team_no != spy.team_no && te.skin) { CF_Spy_DisguiseStop(); Menu_Spy_Skin_Input(te.skin); - spy.disguised_as = te; + spy.disguise_skin = te.skin; return; } te = find(te, classname, "player"); } - } + } else { + local float next_skin = current_skin + direction; - te = find(world, classname, "player"); - while (te != world) { - if (te.team_no != spy.team_no && te.skin != spy.disguise_skin) { - CF_Spy_DisguiseStop(); - Menu_Spy_Skin_Input(te.skin); - spy.disguised_as = te; - return; + while (next_skin != current_skin) { + te = find(world, classname, "player"); + while (te != world) { + if (te.skin == next_skin && te.team_no != spy.team_no) { + CF_Spy_DisguiseStop(); + Menu_Spy_Skin_Input(te.skin); + spy.disguise_skin = te.skin; + return; + } + te = find(te, classname, "player"); + } + + next_skin += direction; + + if (next_skin > 9) { + next_skin = 1; + } else if (next_skin < 1) { + next_skin = 9; + } } - te = find(te, classname, "player"); } - spy.disguised_as = world; + sprint(spy, PRINT_HIGH, "No enemies to disguise as!\n"); } void (entity player, float is_user) FO_Spy_DisguiseLastSpawned = { From d5f0cc5f1f092558fb4d1ff7f32af6e073e1204c Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Sep 2024 07:39:20 +1000 Subject: [PATCH 2454/2474] Clean up --- csqc/main.qc | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 99f4ac1f..458f87be 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -29,27 +29,6 @@ void GetSelf() = { self = findfloat(world, entnum, player_localentnum); } -/* vector AnglesToVector(vector angles) { */ -/* float pitch, yaw, roll; */ -/* vector dir; */ - -/* pitch = angles_x * (M_PI / 180.0); */ -/* yaw = angles_y * (M_PI / 180.0); */ -/* roll = angles_z * (M_PI / 180.0); */ - -/* dir_x = cos(yaw) * cos(pitch); */ -/* dir_y = sin(yaw) * cos(pitch); */ -/* dir_z = -sin(pitch); */ - -/* return dir; */ -/* } */ - -/* vector GetNewPosition(entity ent, vector angle_offsets, float distance) { */ -/* vector dir = AnglesToVector(ent.angles + angle_offsets); */ -/* vector new_position = ent.origin + dir * distance; */ -/* return new_position; */ -/* } */ - void PushToSlotHistory(float value) { if (slot_history_top >= MAX_SLOT_HISTORY_SIZE) { // Stack is full @@ -333,8 +312,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { switch (WP_PlayerClass()) { case PC_ENGINEER: if (previewing_sentry) { - sentry_preview.angles_y -= 15; - sentry_preview_offset -= 15; + anglemod(sentry_preview.angles_y -= 15); + anglemod(sentry_preview_offset -= 15); } else { localcmd("cmd sentry rotate 15\n"); } @@ -345,8 +324,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { switch (WP_PlayerClass()) { case PC_ENGINEER: if (previewing_sentry) { - sentry_preview.angles_y += 15; - sentry_preview_offset += 15; + anglemod(sentry_preview.angles_y += 15); + anglemod(sentry_preview_offset += 15); } else { localcmd("cmd sentry rotate -15\n"); } From b3b5016cecdb12cd9656d0d2a6fa3b6249c5b9e8 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Sep 2024 22:52:48 +1000 Subject: [PATCH 2455/2474] Refactor / remove unneeded temp ents --- csqc/input.qc | 9 --------- csqc/main.qc | 33 +++++++++++---------------------- share/engineer.qc | 27 ++++++++++++++------------- ssqc/engineer.qc | 10 +++------- 4 files changed, 28 insertions(+), 51 deletions(-) diff --git a/csqc/input.qc b/csqc/input.qc index 1c734008..19282cbe 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -4,15 +4,6 @@ void FO_Menu_Game(float); // TRUE --> capture input // FALSE --> pass input on float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { - switch (evtype) - { - case IE_MOUSEDELTA: - if (previewing_sentry) { - sentry_preview.angles_y = anglemod(input_angles_y + (sentry_preview_offset + 180)); - } - default: - } - if (fo_hud_editor || fo_hud_menu_active) { sui_input_event(evtype, scanx, chary, devid); float menu_mouse = (fo_hud_menu_active && (CurrentMenu.flags & FO_MENU_FLAG_USE_MOUSE)); diff --git a/csqc/main.qc b/csqc/main.qc index 458f87be..3d807164 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -18,8 +18,6 @@ float CalculateWaterLevel(); void RenderHitTexts(); entity sentry_preview; entity sentry_preview_range_sphere; -entity temp_sentry; -entity temp_self; float sentry_preview_offset; float previewing_sentry; float prevent_firing; @@ -190,9 +188,6 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. - temp_sentry = spawn(); - temp_self = spawn(); - precache_model("progs/turrpreview.mdl"); sentry_preview = spawn(); setmodel(sentry_preview, "progs/turrpreview.mdl"); @@ -247,23 +242,16 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (previewing_sentry) { makevectors(view_angles); - - // can probably use trig here so we don't need to normalize twice - local vector z_pos; - z_pos.z = (normalize(v_forward) * 64).z; + local vector v_forward_sentry; + v_forward_sentry.z = (normalize(v_forward) * 64).z; v_forward_z = 0; local vector xy_pos = normalize(v_forward) * 64; - - local vector v_forward_sentry; v_forward_sentry.x = xy_pos.x; v_forward_sentry.y = xy_pos.y; - v_forward_sentry.z = z_pos.z; sentry_preview.origin = PM_Org() + v_forward_sentry; - setorigin(temp_self, sentry_preview.origin); - temp_sentry.origin = sentry_preview.origin; - local vector v_forward_range = normalize(v_forward) * 1024; sentry_preview_range_sphere.origin = sentry_preview.origin; + sentry_preview.angles_y = anglemod(view_angles_y + sentry_preview_offset); } else { setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! } @@ -717,7 +705,7 @@ void FO_ApplyCussInput() { void PM_InputFrame(); void SentryPreviewStart() { - sentry_preview_offset = 180; + sentry_preview_offset = 0; sentry_preview.angles_y = input_angles_y; sentry_preview.drawmask = MASK_ENGINE; @@ -782,7 +770,7 @@ noref void CSQC_Input_Frame() { if (previewing_sentry) { if (keydowns & BUTTON0) { if (sentry_fits) { - localcmd(sprintf("cmd build sentry %f\n", sentry_preview_offset)); + localcmd(sprintf("cmd build sentry %f\n", anglemod(180 + sentry_preview_offset))); SentryPreviewStop(); } else { print("Can't build here\n"); @@ -875,13 +863,14 @@ void _Sync_ServerCommandFrame() { CsGrenTimer::UpdateSoundStack(); UpdateTeamColorCrosshair(); - if (!game_state.is_alive) { - if (previewing_sentry) + if (previewing_sentry) { + if (game_state.is_alive) { + sentry_fits = CheckArea(sentry_preview); + sentry_preview.colormod = sentry_fits ? '1 1 1' : '0.5 0.2 0.2'; + } else { SentryPreviewStop(); + } } - - sentry_fits = CheckArea(temp_sentry, temp_self); - sentry_preview.colormod = sentry_fits ? '1 1 1' : '1 0.5 0.5'; } diff --git a/share/engineer.qc b/share/engineer.qc index 24067fca..4df07e36 100644 --- a/share/engineer.qc +++ b/share/engineer.qc @@ -1,4 +1,4 @@ -float (entity obj, entity builder) CheckArea = { +float (entity obj) CheckArea = { local vector src; local vector end; local float pos; @@ -8,16 +8,16 @@ float (entity obj, entity builder) CheckArea = { if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } - src_x = (obj.origin_x + obj.maxs_x) + 24; - src_y = (obj.origin_y + obj.maxs_y) + 24; - src_z = (obj.origin_z + obj.maxs_z); + src_x = (obj.origin_x) + 24; + src_y = (obj.origin_y) + 24; + src_z = (obj.origin_z); pos = pointcontents(src); if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } - end_x = (obj.origin_x + obj.mins_x) - 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z); + end_x = (obj.origin_x) - 16; + end_y = (obj.origin_y) - 16; + end_z = (obj.origin_z); traceline(src, end, 1, obj); if (trace_fraction != 1) { return (0); @@ -26,16 +26,16 @@ float (entity obj, entity builder) CheckArea = { if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } - src_x = (obj.origin_x + obj.mins_x) - 16; - src_y = (obj.origin_y + obj.maxs_y) + 16; - src_z = (obj.origin_z + obj.maxs_z); + src_x = (obj.origin_x) - 16; + src_y = (obj.origin_y) + 16; + src_z = (obj.origin_z); pos = pointcontents(src); if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { return (0); } - end_x = (obj.origin_x + obj.maxs_x) + 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z); + end_x = (obj.origin_x) + 16; + end_y = (obj.origin_y) - 16; + end_z = (obj.origin_z); traceline(src, end, 1, obj); if (trace_fraction != 1) { return (0); @@ -48,6 +48,7 @@ float (entity obj, entity builder) CheckArea = { /* if (trace_fraction != 1) { */ /* return (0); */ /* } */ + te = findradius(obj.origin, 64); if (te != world) { return (0); diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index e0ff64da..b5ab6841 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -533,7 +533,6 @@ void () TeamFortress_EngineerBuildStop = { } } -// here void (float objtobuild, float offset) TeamFortress_Build = { if (cb_prematch) { sprint(self, PRINT_MEDIUM, "You cannot build during prematch\n"); @@ -560,15 +559,12 @@ void (float objtobuild, float offset) TeamFortress_Build = { /* v_forward = normalize(v_forward) * 64; */ /* newmis.origin = self.origin + v_forward; */ - local vector z_pos; - z_pos.z = (normalize(v_forward) * 64).z; + local vector v_forward_sentry; + v_forward_sentry.z = (normalize(v_forward) * 64).z; v_forward_z = 0; local vector xy_pos = normalize(v_forward) * 64; - - local vector v_forward_sentry; v_forward_sentry.x = xy_pos.x; v_forward_sentry.y = xy_pos.y; - v_forward_sentry.z = z_pos.z; newmis.origin = self.origin + v_forward_sentry; @@ -616,7 +612,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { self.sentry_ticks = 0; } - if (CheckArea(newmis, self) == 0) { + if (!CheckArea(newmis)) { sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; From 4f3da2675993ba49730014996a6926a5fef152c3 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 16 Sep 2024 22:59:19 +1000 Subject: [PATCH 2456/2474] Simplify --- csqc/main.qc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 3d807164..28693200 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -300,8 +300,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { switch (WP_PlayerClass()) { case PC_ENGINEER: if (previewing_sentry) { - anglemod(sentry_preview.angles_y -= 15); - anglemod(sentry_preview_offset -= 15); + sentry_preview_offset = anglemod(sentry_preview_offset - 15); } else { localcmd("cmd sentry rotate 15\n"); } @@ -312,8 +311,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { switch (WP_PlayerClass()) { case PC_ENGINEER: if (previewing_sentry) { - anglemod(sentry_preview.angles_y += 15); - anglemod(sentry_preview_offset += 15); + sentry_preview_offset = anglemod(sentry_preview_offset + 15); } else { localcmd("cmd sentry rotate -15\n"); } From 4257be960f1a7d3c7eb1d7f5370623bdcd6d6eae Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 17 Sep 2024 23:03:55 +1000 Subject: [PATCH 2457/2474] Don't det building sentry when detting disp --- ssqc/combat.qc | 4 ++-- ssqc/engineer.qc | 16 ++++++++-------- ssqc/tfort.qc | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 6915b9d3..e2e6fd3c 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -121,9 +121,10 @@ void (entity targ, entity attacker) Killed = { ClientObituary(self, attacker); self.takedamage = DAMAGE_NO; self.touch = SUB_Null; - monster_death_use(); + self.th_die(); + self = oself; if(duelmode && targ.classname == "player" && !cb_prematch) { //Already in no fire mode - implies you're not the first to die @@ -716,7 +717,6 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, BroadcastHitFlag(targ, inflictor, attacker, original_damage, damh); if (targ.health <= 0) { - if ((inflictor.classname == "detpack") && (inflictor.is_disarming) && (inflictor.enemy == targ)) deathmsg = DMSG_DETPACK_DIS; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index b5ab6841..f40de8e4 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -483,14 +483,14 @@ void () FO_Engineer_ToggleSentry = { } void () TeamFortress_EngineerBuild = { - if (self.is_building == 0) { + if (!self.is_building) { if (((self.ammo_cells < 100) && !self.has_dispenser) && !self.has_sentry) { Status_Print(self, "\n\n\n\n\n\n\n", "Not enough metal to build anything"); return; } Menu_Engineer(self); - } else if (self.is_building == 1) { + } else if (self.is_building) { TeamFortress_EngineerBuildStop(); } }; @@ -525,7 +525,7 @@ void () TeamFortress_EngineerBuildStop = { } Menu_Close(self); - self.is_building = 0; + self.is_building = FALSE; self.building_percentage = 0; if (!engineer_move) { self.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); @@ -626,7 +626,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { } UpdateClientBuilding(self); - self.is_building = 1; + self.is_building = objtobuild; if (!engineer_move) { self.immune_to_check = time + 5; self.tfstate |= TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON; @@ -694,7 +694,7 @@ void () CF_CheckBuilding = { local entity building = self.enemy; self = self.owner; - if (self.is_building == 0) { + if (!self.is_building) { dremove(timer); return; } @@ -956,12 +956,12 @@ void UpdateClient_Dispenser(entity pl, entity disp) = { void () TeamFortress_FinishedBuilding = { local entity oldself; if (engineer_move) { - if (self.real_owner.is_building != 1) { + if (!self.real_owner.is_building) { return; } } else { - if (self.owner.is_building != 1) { + if (!self.owner.is_building) { return; } } @@ -1152,7 +1152,7 @@ void () Dispenser_Die = { self.real_owner.has_dispenser = 0; self.think = Dispenser_Explode; self.nextthink = time + 0.1; - if (self.real_owner.is_building) { + if (self.real_owner.is_building == 1) { self = self.real_owner; TeamFortress_EngineerBuildStop(); } diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 359b828d..121fd664 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1250,7 +1250,7 @@ void () TeamFortress_SetEquipment = { stuffcmd(self, st); stuffcmd(self, "\n"); } - self.is_building = 0; + self.is_building = FALSE; self.is_detpacking = 0; self.airblast_cooldown = 0; self.is_undercover = 0; @@ -1963,7 +1963,7 @@ void () TeamFortress_RemoveTimers = { TeamFortress_EngineerBuildStop(); } - self.is_building = 0; + self.is_building = FALSE; self.building = world; if (self.tfstate & TFSTATE_AIMING) { self.tfstate &= ~TFSTATE_AIMING; From 56e910fae227a228ca27fb24fc536d5f4eee98b2 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 17 Sep 2024 23:56:57 +1000 Subject: [PATCH 2458/2474] Use pre-existing Engy BUILD_ defines --- ssqc/engineer.qc | 14 +++++++------- ssqc/menu.qc | 8 ++++---- ssqc/qw.qc | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f40de8e4..fc4922a9 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -586,7 +586,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { return; } - if (objtobuild == 1) { + if (objtobuild == BUILD_DISPENSER) { if (self.has_dispenser) { sprint(self, PRINT_HIGH, "You can only have one dispenser\n"); dremove(newmis); @@ -598,7 +598,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { newmis.netname = "dispenser"; btime = time + 2; self.dispenser_ticks = 0; - } else if (objtobuild == 2) { + } else if (objtobuild == BUILD_SENTRYGUN) { if (self.has_sentry) { sprint(self, PRINT_HIGH, "You can only have one sentry gun\n"); dremove(newmis); @@ -658,15 +658,15 @@ void (float objtobuild, float offset) TeamFortress_Build = { newmis.team_no = self.team_no; newmis.max_health = newmis.health; newmis.takedamage = DAMAGE_AIM; - if (objtobuild == 1) { - self.has_dispenser = TRUE; + if (objtobuild == BUILD_DISPENSER) { + self.has_dispenser = TRUE; newmis.th_die = Dispenser_Die; self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; newmis.classname = "building_dispenser"; } - if (objtobuild == 2) { + if (objtobuild == BUILD_SENTRYGUN) { self.sentry_ent = newmis; - self.has_sentry = TRUE; + self.has_sentry = TRUE; newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.takedamage = DAMAGE_AIM; @@ -1152,7 +1152,7 @@ void () Dispenser_Die = { self.real_owner.has_dispenser = 0; self.think = Dispenser_Explode; self.nextthink = time + 0.1; - if (self.real_owner.is_building == 1) { + if (self.real_owner.is_building == BUILD_DISPENSER) { self = self.real_owner; TeamFortress_EngineerBuildStop(); } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 875bd996..44e69bcc 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -810,7 +810,7 @@ void (float offset) TeamFortress_BuildSentry = { if (self.has_sentry) return; if (self.ammo_cells >= ENG_SENTRY_COST) - TeamFortress_Build(2, offset); + TeamFortress_Build(BUILD_SENTRYGUN, offset); else Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST - self.ammo_cells), " more cells to build a sentry gun")); } @@ -820,16 +820,16 @@ void (float inp) Menu_Engineer_Input = { case 5: break; - // build dispenser + // build sentry case 1: TeamFortress_BuildSentry(0); break; - // build sentry + // build dispenser case 2: if (!self.has_dispenser) { if (self.ammo_cells >= ENG_DISPENSER_COST) - TeamFortress_Build(1, 0); + TeamFortress_Build(BUILD_DISPENSER, 0); else Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); } diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 3cc1f985..566baae1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -48,7 +48,7 @@ float remote_client_time(); .float cheat_check; // Time when we'll next check for team cheats .float is_removed; // TRUE if the entity has been removed .float is_undercover; // TRUE for a SPY if they're undercover -.float is_building; // TRUE for an ENGINEER if they're building something +.float is_building; // BUILD_DISPENSER, BUILD_SENTRYGUN or FALSE for an ENGINEER .float is_detpacking; // TRUE for a DEMOMAN if they're setting a detpack .float is_button_feigning; // TRUE for a SPY if they're feigning death with +feign or +special .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage From 43d37710c0a7d947ca3c415c764b8429db16d8b7 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 18 Sep 2024 21:31:29 +1000 Subject: [PATCH 2459/2474] Add zoom to specialup/down --- csqc/csextradefs.qc | 2 +- csqc/events.qc | 6 +++ csqc/main.qc | 102 ++++++++++++++++++++++++-------------------- share/commondefs.qc | 62 ++++++++++++++------------- ssqc/client.qc | 2 + ssqc/player.qc | 2 + ssqc/status.qc | 20 +++++++++ 7 files changed, 119 insertions(+), 77 deletions(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index fa50037e..f4b4e9fa 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -115,7 +115,7 @@ float vote_list_offset; entity current_vote; string vote_list_filter; float oldbuttons; -float zoomed_in; +float zoom_scale; float pick_up_time; float flag_team; diff --git a/csqc/events.qc b/csqc/events.qc index 2c37aa9a..0af4acc4 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -103,6 +103,12 @@ void() CSQC_Parse_Event = { last_id_time = time; SBAR.Identify = readstring(); break; + case MSG_PLAYER_DIE: + zoom_scale = 1; + break; + case MSG_PLAYER_SPAWN: + zoom_scale = 1; + break; case MSG_GRENPRIMED: float entno = readentitynum(); float grentype = readbyte(); diff --git a/csqc/main.qc b/csqc/main.qc index 01b29860..ae77096c 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -199,6 +199,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { sentry_preview_range_sphere.scale = 1000; sentry_preview_range_sphere.alpha = 0.02; + zoom_scale = 1; + print("CSQC initialization finished\n"); }; @@ -225,8 +227,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { FO_CussView(); - if (zoomed_in) - setviewprop(VF_AFOV, CVARF(fov)/3); + setviewprop(VF_AFOV, CVARF(fov)/zoom_scale); + setsensitivityscaler(1/zoom_scale); // Draw original sbar, viewsize honoured automatically. if (!CVARF(fo_fte_hud) || CVARF(fo_legacy_sbar)) @@ -308,6 +310,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd sentry rotate 15\n"); } break; + default: + zoom_scale = min(zoom_scale + 1, 5); + break; } break; case "specialdown": @@ -322,6 +327,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd sentry rotate -15\n"); } break; + default: + zoom_scale = max(zoom_scale - 1, 1); + break; } break; case "+slot": @@ -752,61 +760,63 @@ noref void CSQC_Input_Frame() { Sync_GameState(); - // Intercept rocket jump - if ((WP_PlayerClass() == PC_SOLDIER || WP_PlayerClass() == PC_PYRO) && - (input_buttons & BUTTON4)) - input_buttons |= BUTTON0 | BUTTON2; - - if (WP_PlayerClass() == PC_ENGINEER) { - // Intercept sentry build - if (!getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { + switch (WP_PlayerClass()) { + case PC_SNIPER: + if (keydowns & BUTTON3) { + if (zoom_scale == 1) { + zoom_scale = 3; + } else { + zoom_scale = 1; + } + } + break; + case PC_SOLDIER: + case PC_PYRO: + // Intercept rocket jump if (input_buttons & BUTTON4) { - if (keydowns & BUTTON4) { - if (!previewing_sentry) { - SentryPreviewStart(); - } else { - SentryPreviewStop(); + input_buttons |= BUTTON0 | BUTTON2; + } + break; + case PC_ENGINEER: + // Intercept sentry build + if (!getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { + if (input_buttons & BUTTON4) { + if (keydowns & BUTTON4) { + if (!previewing_sentry) { + SentryPreviewStart(); + } else { + SentryPreviewStop(); + } } - } - input_buttons = input_buttons - BUTTON4; - } + input_buttons = input_buttons - BUTTON4; + } - if (previewing_sentry) { - if (keydowns & BUTTON0) { - if (sentry_fits) { - localcmd(sprintf("cmd build sentry %f\n", anglemod(180 + sentry_preview_offset))); - SentryPreviewStop(); - } else { - print("Can't build here\n"); + if (previewing_sentry) { + if (keydowns & BUTTON0) { + if (sentry_fits) { + localcmd(sprintf("cmd build sentry %f\n", anglemod(180 + sentry_preview_offset))); + SentryPreviewStop(); + } else { + print("Can't build here\n"); + } } - } - if (input_buttons & BUTTON0) { - input_buttons = input_buttons - BUTTON0; + if (input_buttons & BUTTON0) { + input_buttons = input_buttons - BUTTON0; + } } } - - } - - if (prevent_firing && !previewing_sentry && (keyups & BUTTON0)) { - prevent_firing = FALSE; - } - - if (prevent_firing) { - input_buttons &= ~BUTTON0; - } + break; } - // Handle zoom - float prev_zoomed_in = zoomed_in; - if (WP_PlayerClass() == PC_SNIPER) - zoomed_in = input_buttons & BUTTON3; - else - zoomed_in = 0; + if (prevent_firing && !previewing_sentry && (keyups & BUTTON0)) { + prevent_firing = FALSE; + } - if (prev_zoomed_in != zoomed_in) - setsensitivityscaler(zoomed_in ? 1/3 : 1); + if (prevent_firing) { + input_buttons &= ~BUTTON0; + } PM_InputFrame(); FO_ApplyCussInput(); diff --git a/share/commondefs.qc b/share/commondefs.qc index 1a7162aa..59129bb3 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -185,37 +185,39 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define GAMEMODE_DUEL 4 #define GAMEMODE_VOTE 8 -#define MSG_FLAGINFOINIT 1 -#define MSG_FLAGINFO 2 - -#define MSG_SBAR 4 -#define MSG_GRENPRIMED 5 -#define MSG_CLIENT_MENU 6 -#define MSG_TEAMS_UPDATE 7 -#define MSG_CLASSES_UPDATE 8 -#define MSG_SENTRY_POS 9 -#define MSG_DISPENSER_POS 10 +#define MSG_FLAGINFOINIT 1 +#define MSG_FLAGINFO 2 +// 3 +#define MSG_SBAR 4 +#define MSG_GRENPRIMED 5 +#define MSG_CLIENT_MENU 6 +#define MSG_TEAMS_UPDATE 7 +#define MSG_CLASSES_UPDATE 8 +#define MSG_SENTRY_POS 9 +#define MSG_DISPENSER_POS 10 #define MSG_SERVER_ADMIN_INFO 11 -#define MSG_CAPTAINS 12 -#define MSG_MOTD 13 -#define MSG_PREMATCH 14 -#define MSG_GRENTHROWN 15 -#define MSG_ID 16 -#define MSG_TEAM_SCORES 17 -#define MSG_VOTE_MAPS 18 -#define MSG_VOTE_UPDATE 19 -#define MSG_VOTE_MAP_ADD 20 -#define MSG_VOTE_MAP_DELETE 21 -#define MSG_PAUSE 22 -#define MSG_UNPAUSE 23 -#define MSG_TFX_GRENTIMER 24 -#define MSG_QUAD_ROUND_BEGIN 25 -#define MSG_LOGIN 26 -#define MSG_HITFLAG 27 -#define MSG_RELOADSOUND 28 -#define MSG_FLAG_PICKUP 29 -#define MSG_FLAG_DROP 30 -#define MSG_BUILDING 31 +#define MSG_CAPTAINS 12 +#define MSG_MOTD 13 +#define MSG_PREMATCH 14 +#define MSG_GRENTHROWN 15 +#define MSG_ID 16 +#define MSG_TEAM_SCORES 17 +#define MSG_VOTE_MAPS 18 +#define MSG_VOTE_UPDATE 19 +#define MSG_VOTE_MAP_ADD 20 +#define MSG_VOTE_MAP_DELETE 21 +#define MSG_PAUSE 22 +#define MSG_UNPAUSE 23 +#define MSG_TFX_GRENTIMER 24 +#define MSG_QUAD_ROUND_BEGIN 25 +#define MSG_LOGIN 26 +#define MSG_HITFLAG 27 +#define MSG_RELOADSOUND 28 +#define MSG_FLAG_PICKUP 29 +#define MSG_FLAG_DROP 30 +#define MSG_BUILDING 31 +#define MSG_PLAYER_DIE 32 +#define MSG_PLAYER_SPAWN 33 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/ssqc/client.qc b/ssqc/client.qc index 36ef5dfd..c2dd7c79 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2122,6 +2122,8 @@ void (float all_dimensions) SetDimensions = { }; void () PutClientInServer = { + UpdateClientPlayerSpawn(self); + if (fo_login_required && self.fo_login == string_null) UpdateClient_Login(self); diff --git a/ssqc/player.qc b/ssqc/player.qc index a934ed92..e5e8762a 100644 --- a/ssqc/player.qc +++ b/ssqc/player.qc @@ -439,6 +439,8 @@ void () GibPlayer = { }; void () PlayerDie = { + UpdateClientPlayerDie(self); + self.spawn_gen += 1; self.last_death_ctime = self.client_time; diff --git a/ssqc/status.qc b/ssqc/status.qc index ed822338..01dfd262 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -757,6 +757,26 @@ string GetSBClassInfo(entity pl, float csqcactive) return st1; } +void UpdateClientPlayerDie(entity pl) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_PLAYER_DIE); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClientPlayerSpawn(entity pl) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_PLAYER_SPAWN); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientBuilding(entity pl) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From 223e64a1b9faca990895def292eab625d2daa456 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 18 Sep 2024 22:31:06 +1000 Subject: [PATCH 2460/2474] Add transparency to your own team flags when close by --- csqc/tfx.qc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 1de72c02..43550a41 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -252,13 +252,18 @@ static void UpdateFlagOutline(entity flag) { } float UpdateFlag(float isnew) { - if (isnew) { - float mindex = self.modelindex; - AddOutline(self); - // Flags have their own shader already, just make them shiny for now. - } + /* if (isnew) { */ + /* float mindex = self.modelindex; */ + /* AddOutline(self); */ + /* // Flags have their own shader already, just make them shiny for now. */ + /* } */ + + /* UpdateFlagOutline(self); */ - UpdateFlagOutline(self); + if (self.skin == team_no) { + local float distance = vlen(self.origin - PM_Org()); + self.alpha = min(0.25 + (distance / 200), 1); + } return TRUE; } @@ -309,4 +314,8 @@ void TF_Init() { shader_over_outline = shaderforname(rnds("over_outline"), "{ sort 7 }"); #endif + + deltalisten("progs/ff_flag.mdl", UpdateFlag, 0); + deltalisten("progs/tf_flag.mdl", UpdateFlag, 0); + deltalisten("progs/tf_stan.mdl", UpdateFlag, 0); } From 8c34c5a7ece805027ef0ba499f274226448e9fd0 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Wed, 18 Sep 2024 23:18:56 +1000 Subject: [PATCH 2461/2474] Replace serverside zoom commands with client side --- README.md | 1 + csqc/main.qc | 29 ++++++++++--- share/defs.h | 9 ++-- ssqc/client.qc | 7 --- ssqc/help.qc | 4 -- ssqc/qw.qc | 7 --- ssqc/sniper.qc | 113 ------------------------------------------------ ssqc/tfort.qc | 3 -- ssqc/weapons.qc | 20 --------- 9 files changed, 27 insertions(+), 166 deletions(-) diff --git a/README.md b/README.md index cd10eb70..884f6770 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ sound files are found in `fortress/sound/hitaudio/` and `fortress/sound/announc * `+special2` Same as `special2`, but also has `+rj` for Soldier and Pyro. * `specialup` Engineer: `cmd sentry rotate -15`, Spy: `cmd disguise prev`. * `specialdown` Engineer: `cmd sentry rotate 15`, Spy: `cmd disguise next`. +* `zoomin` and `zoomout` commands that adjust sens with zoom. 5 levels. * `setinfo hold_grens` for press and hold `+grenade1` and `+grenade2` * `setinfo hold_fiegn` for press and hold feigning * `setinfo hold_detpack` for press and hold detpack diff --git a/csqc/main.qc b/csqc/main.qc index ae77096c..3fa6161b 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -113,6 +113,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { registercommand("specialup"); registercommand("specialdown"); + registercommand("zoomin"); + registercommand("zoomout"); + registercommand("+slot"); registercommand("-slot"); @@ -289,6 +292,14 @@ void Slot_Keyup(float slot) { localcmd("-attack\n"); } +void ZoomIn() { + zoom_scale = min(zoom_scale + 1, 5); +} + +void ZoomOut() { + zoom_scale = max(zoom_scale - 1, 1); +} + void W_ChangeToSlotAlternate(string opt1, string opt2, string opt3, string opt4); noref float(string cmd) CSQC_ConsoleCommand = { @@ -300,6 +311,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { switch(argv(0)) { case "specialup": switch (WP_PlayerClass()) { + case PC_SNIPER: + ZoomIn(); + break; case PC_SPY: localcmd("cmd disguise prev\n"); break; @@ -310,13 +324,13 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd sentry rotate 15\n"); } break; - default: - zoom_scale = min(zoom_scale + 1, 5); - break; } break; case "specialdown": switch (WP_PlayerClass()) { + case PC_SNIPER: + ZoomOut(); + break; case PC_SPY: localcmd("cmd disguise next\n"); break; @@ -327,11 +341,14 @@ noref float(string cmd) CSQC_ConsoleCommand = { localcmd("cmd sentry rotate -15\n"); } break; - default: - zoom_scale = max(zoom_scale - 1, 1); - break; } break; + case "zoomin": + ZoomIn(); + break; + case "zoomout": + ZoomOut(); + break; case "+slot": Slot_Keydown(stof(argv(1))); break; diff --git a/share/defs.h b/share/defs.h index 5b25e9da..d56dbd4b 100644 --- a/share/defs.h +++ b/share/defs.h @@ -446,9 +446,9 @@ struct Slot { int id; }; #define TF_SCAN_ENEMY 43 // Scout: Toggle scanning of enemies #define TF_SCAN_FRIENDLY 44 // Scout: Toggle scanning of friendlies #define TF_SCAN_SOUND 45 // Scout: Toggle scanner sound -#define TF_ZOOMTOGGLE 46 // Sniper: Toggle zoom mode on/off -#define TF_ZOOMIN 47 // Sniper: Zoom in (while zoom mode is on) -#define TF_ZOOMOUT 48 // Sniper: Zoom out (while zoom mode is on) +// 46 +// 47 +// 48 #define TF_DEMOMAN_DETPACK 49 // Demoman: Bring up detpack menu #define TF_DETPACK 50 // Demoman: Detpack Pre-Impulse #define TF_DETPACK_STOP 51 // Demoman: Impulse to stop setting detpack @@ -1609,9 +1609,6 @@ TFAlias client_aliases[] = { {"scansound", TF_SCAN_SOUND}, {"scanf", TF_SCAN_FRIENDLY}, {"scane", TF_SCAN_ENEMY}, - {"zoomtoggle", TF_ZOOMTOGGLE}, - {"zoomin", TF_ZOOMIN}, - {"zoomout", TF_ZOOMOUT}, {"detpipe", TF_PB_DETONATE}, {"+det5", TF_DETPACK_5}, {"-det5", TF_DETPACK_STOP}, diff --git a/ssqc/client.qc b/ssqc/client.qc index c2dd7c79..ae14da9d 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -50,7 +50,6 @@ entity(float ino) Finditem; void (entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer; void () CTF_FlagCheck; -void (entity pl) Sniper_ZoomReset; void () StartTimer; void () StopTimer; void () StartQuadRound; @@ -1759,8 +1758,6 @@ void () ClientKill = { } } - Sniper_ZoomReset(self); - set_suicide_frame(); self.modelindex = modelindex_player; @@ -2042,7 +2039,6 @@ void (entity p) SetVoteParams = { p.th_pain = player_pain; p.th_die = PlayerDie; p.height = 0; - Sniper_ZoomReset(p); p.deadflag = 0; p.pausetime = 0; @@ -2276,7 +2272,6 @@ void () PutClientInServer = { self.th_pain = player_pain; self.th_die = PlayerDie; self.height = 0; - Sniper_ZoomReset(self); self.deadflag = 0; self.pausetime = 0; @@ -3875,8 +3870,6 @@ string (entity pe_target, entity pe_attacker, float pf_deathmsg) GetDeathMessage void (entity targ, entity attacker) ClientObituary = { local string deathstring; - Sniper_ZoomReset(targ); - if (cb_prematch) return; diff --git a/ssqc/help.qc b/ssqc/help.qc index 9b59e9ec..97394308 100644 --- a/ssqc/help.qc +++ b/ssqc/help.qc @@ -67,12 +67,8 @@ void () Help_ShowSniper = { sprint(self, PRINT_HIGH, Q"\sf\s - Throw Flare\n"); sprint(self, PRINT_HIGH, Q"\smouse2\s - Prime/throw Hand Grenade\n"); sprint(self, PRINT_HIGH, "\nClass aliases for Sniper:\n"); - sprint(self, PRINT_HIGH, Q"\szoomtoggle\s - Toggle zoom mode\n"); sprint(self, PRINT_HIGH, Q"\szoomin\s - Zoom in (for adjusting zoom while in zoom mode)\n"); sprint(self, PRINT_HIGH, Q"\szoomout\s - Zoom out (for adjusting zoom while in zoom mode)\n"); - sprint(self, PRINT_HIGH, "\nSettings for Sniper:\n"); - sprint(self, PRINT_HIGH, Q"\szf \"fov\"\s - The default zoom fov which zoomtoggle zooms to (default 30)\n"); - sprint(self, PRINT_HIGH, Q"\szs \"fov\"\s - The fov increments/decrements used by zoomin/zoomout (default 20)\n"); sprint(self, PRINT_HIGH, "Usage: setinfo \n"); }; diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 1b0378c3..c3522e61 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -53,18 +53,11 @@ float remote_client_time(); .float is_button_feigning; // TRUE for a SPY if they're feigning death with +feign or +special .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage .float is_unabletospy; // TRUE for a SPY if they can't go undercover -.float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team .float has_changedclass; // TRUE for a player that has changed class .float has_disconnected; // TRUE if the player has disconnected .float has_menutimer; // TRUE if the player has an active menu timer -.float default_sensitivity; // Player's default (non-zoomed) sensitivity -.float default_fov; // Player's default (non-zoomed) fov -.float current_fov; // Player's current field of view -.float zoom_level; // Start zooming to this fov next frame -.float zoom_fov; // The default fov to zoom in to when pressing special button -.float zoom_last; // The last used zoom fov by the player - zoom to this when toggling zoom .float has_voted_map; // Map option that player voted for .float spawn_time; // Time when player spawned .float menu_time; // Time when vote map menu was first issued diff --git a/ssqc/sniper.qc b/ssqc/sniper.qc index e7d1ab7d..c1a3dbf7 100644 --- a/ssqc/sniper.qc +++ b/ssqc/sniper.qc @@ -2,119 +2,6 @@ // Functions for the SNIPER class and associated weaponry //======================================================== -void (float zoom_to) Sniper_Zoom = { - self.default_fov = stof(infokey(self, "df")); - self.default_sensitivity = stof(infokey(self, "ds")); - self.zoom_fov = stof(infokey(self, "zf")); - - if (self.default_fov == 0) - return; - - if (zoom_to >= self.default_fov) - Sniper_ZoomReset(self); - else if (zoom_to != self.current_fov) { - if (zoom_to < self.default_fov) - self.zoom_last = zoom_to; - self.current_fov = zoom_to; - stuffcmd(self, "fov "); - stuffcmd(self, ftos(zoom_to)); - stuffcmd(self, "\n"); - - if (self.default_sensitivity > 0) { - stuffcmd(self, "sensitivity "); - stuffcmd(self, ftos(self.default_sensitivity * zoom_to / self.default_fov)); - stuffcmd(self, "\n"); - } - } -}; - -void (entity pl) Sniper_ZoomReset = { - pl.default_sensitivity = stof(infokey(pl, "ds")); - pl.default_fov = stof(infokey(pl, "df")); - - pl.is_zooming = 0; - - if (pl.default_fov > 0) { - pl.current_fov = pl.default_fov; - stuffcmd(pl, "fov "); - stuffcmd(pl, ftos(pl.default_fov)); - stuffcmd(pl, "\n"); - } - - if (pl.default_sensitivity > 0) { - stuffcmd(pl, "sensitivity "); - stuffcmd(pl, ftos(pl.default_sensitivity)); - stuffcmd(pl, "\n"); - } -}; - -void () Sniper_ZoomToggle = { - local float magnification = 0; - local float zoom_to = 0; - - if (self.playerclass != PC_SNIPER) - return; - - self.default_fov = stof(infokey(self, "df")); - self.default_sensitivity = stof(infokey(self, "ds")); - self.zoom_fov = stof(infokey(self, "zf")); - - if (self.default_fov == 0) { - sprint(self, PRINT_HIGH, "Use \"setinfo df \" to set default fov to use sniper zoom. Use \"setinfo ds \" to set default sensitivity for sensitivity scaling.\n"); - return; - } - - if (self.is_zooming) { - self.is_zooming = 0; - zoom_to = self.default_fov; - sprint(self, PRINT_HIGH, "Zoomed out\n"); - } else { - self.is_zooming = 1; - if (self.zoom_last && self.zoom_last < self.default_fov) - zoom_to = self.zoom_last; - else if (self.zoom_fov) - zoom_to = self.zoom_fov; - else - zoom_to = 30; - - magnification = floor(self.default_fov / zoom_to); - sprint(self, PRINT_HIGH, ftos(magnification), "x zoom\n"); - } - - Sniper_Zoom(zoom_to); -}; - -void (float zoom_in) Sniper_ZoomAdjust = { - local float zoom_to = 0; - local float zoom_steps = 0; - - if (self.playerclass != PC_SNIPER || !self.is_zooming) - return; - - zoom_steps = stof(infokey(self, "zs")); - if (!zoom_steps) - zoom_steps = 5; - - if (self.default_fov == 0) { - sprint(self, PRINT_HIGH, "Use \"setinfo df \" to set default fov to use sniper zoom. Use \"setinfo ds \" to set default sensitivity for sensitivity scaling.\n"); - return; - } - - if (zoom_in) - zoom_to = self.current_fov - zoom_steps; - else - zoom_to = self.current_fov + zoom_steps; - - if (zoom_to <= 10) - zoom_to = 10; - else if (zoom_to >= self.default_fov) - zoom_to = self.default_fov; - - self.zoom_last = zoom_to; - - Sniper_Zoom(zoom_to); -}; - void () SniperSight_Update = { local vector org; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 6aa8d7e5..8c9707e1 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -48,9 +48,6 @@ void () UseSpecialSkill = { case PC_SCOUT: self.impulse = TF_DASH; break; - case PC_SNIPER: - self.impulse = TF_ZOOMTOGGLE; - break; case PC_DEMOMAN: self.impulse = TF_PB_DETONATE; break; diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index 57ae1b6b..5bb9ebdf 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -30,15 +30,11 @@ void () PipebombTouch; void () SniperSight_Create; -void (float zoom_to) Sniper_Zoom; - void () Help_Show; void () TeamFortress_Inventory; void () TeamFortress_SaveMe; void (entity pe_player, float f_type) CF_Identify; void () TeamFortress_ReloadNext; -void () Sniper_ZoomToggle; -void (float zoom_in) Sniper_ZoomAdjust; void () TeamFortress_StatusQuery; void () CF_Scout_Dash; void () CF_Spy_DisguiseStop; @@ -2552,22 +2548,6 @@ void () W_WeaponFrame = { } } - if (self.playerclass == PC_SNIPER) { - if (self.impulse == TF_SPECIAL_SKILL || self.impulse == TF_ZOOMTOGGLE) { - Sniper_ZoomToggle(); - self.impulse = 0; - return; - } else if (self.impulse == TF_ZOOMIN || (self.is_zooming && self.impulse == TF_WEAPPREV)) { - Sniper_ZoomAdjust(1); - self.impulse = 0; - return; - } else if (self.impulse == TF_ZOOMOUT || (self.is_zooming && self.impulse == TF_WEAPNEXT)) { - Sniper_ZoomAdjust(0); - self.impulse = 0; - return; - } - } - // whitelist of commands that can be used even when reloading switch (self.impulse) { From 5990a5d69b27937f326ae50828c24355b25c39eb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 29 Sep 2024 10:38:06 +1000 Subject: [PATCH 2462/2474] Predicted player shouldn't prevent gun build --- csqc/main.qc | 2 +- share/engineer.qc | 6 ++++-- ssqc/engineer.qc | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 28693200..fd78ce31 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -863,7 +863,7 @@ void _Sync_ServerCommandFrame() { if (previewing_sentry) { if (game_state.is_alive) { - sentry_fits = CheckArea(sentry_preview); + sentry_fits = CheckArea(sentry_preview, player_localentnum); sentry_preview.colormod = sentry_fits ? '1 1 1' : '0.5 0.2 0.2'; } else { SentryPreviewStop(); diff --git a/share/engineer.qc b/share/engineer.qc index 4df07e36..0bb2e0b1 100644 --- a/share/engineer.qc +++ b/share/engineer.qc @@ -1,4 +1,4 @@ -float (entity obj) CheckArea = { +float (entity obj, float builder) CheckArea = { local vector src; local vector end; local float pos; @@ -51,7 +51,9 @@ float (entity obj) CheckArea = { te = findradius(obj.origin, 64); if (te != world) { - return (0); + if !(te.movetype == MOVETYPE_WALK && builder && num_for_edict(te.owner) == builder) { + return (0); + } } return (1); }; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index fc4922a9..b3e83dc4 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -612,7 +612,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { self.sentry_ticks = 0; } - if (!CheckArea(newmis)) { + if (!CheckArea(newmis, 0)) { sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; From 8e5da39ad7250b8fcd600acef1a3afce9c2b4ade Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Sun, 13 Oct 2024 23:22:18 +1100 Subject: [PATCH 2463/2474] WIP --- csqc/main.qc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/csqc/main.qc b/csqc/main.qc index fd78ce31..dc431cb1 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -191,6 +191,7 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { precache_model("progs/turrpreview.mdl"); sentry_preview = spawn(); setmodel(sentry_preview, "progs/turrpreview.mdl"); + setsize(sentry_preview, '-16 -16 0', '16 16 48'); sentry_preview.alpha = 0.25; precache_model("progs/sphere.mdl"); @@ -218,6 +219,20 @@ void PMD_DrawGraphs(float width); DEFCVAR_FLOAT(fov, 90); +void adjustEntityAboveGround(entity ent) { + vector startPos, endPos; + + // Define start and end points for the trace downwards + startPos = ent.origin + '0 0 100'; // Start 100 units above the entity's origin + endPos = ent.origin - '0 0 1000'; // Trace downwards a sufficient distance + + // Perform the tracebox from startPos to endPos + tracebox(startPos, ent.mins, ent.maxs, endPos, MOVE_NORMAL, ent); + + // Move the entity up to be 1 unit above the ground + ent.origin[2] = trace_endpos[2] - (ent.mins[2] - ent.maxs[2]) + 1; // 1 unit above the ground +} + noref void(float width, float height, float menushown) CSQC_UpdateView = { float fts = perf_start_sample(&frame_timing); clearscene(); @@ -250,6 +265,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { v_forward_sentry.y = xy_pos.y; sentry_preview.origin = PM_Org() + v_forward_sentry; + adjustEntityAboveGround(sentry_preview); sentry_preview_range_sphere.origin = sentry_preview.origin; sentry_preview.angles_y = anglemod(view_angles_y + sentry_preview_offset); } else { From 221ad539ca764d60cae04ef18e521f982ebb421f Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Mon, 14 Oct 2024 01:15:52 +1100 Subject: [PATCH 2464/2474] Fix missing glow on client side flag models --- csqc/pmove.qc | 8 ++++---- csqc/tfx.qc | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/csqc/pmove.qc b/csqc/pmove.qc index e23a9da5..8db34cec 100644 --- a/csqc/pmove.qc +++ b/csqc/pmove.qc @@ -928,8 +928,8 @@ static void ParseCvars() { #define MUX_IN(ef, bit, src) \ do { if ((ef) & (bit)) { rad = max(rad, src.i); col += src.v; } } while (0) -static void LocalEffects() { - float effects = pstate_server.effects; + +void LocalEffects(float effects, vector org) { float rad = 0; vector col = '0 0 0'; @@ -946,7 +946,7 @@ static void LocalEffects() { MUX_IN(effects, EF_BLUE, bluelight_l); rad = min(rad, 400); - dynamiclight_add(pm.vieworg, rad, col); + dynamiclight_add(org, rad, col, 0, "", 0); } #undef MUX_IN @@ -958,7 +958,7 @@ void PM_UpdateView() { makevectors(view_angles); SetListener(pm.vieworg, v_forward, v_right, v_up); - LocalEffects(); + LocalEffects(pstate_server.effects, pm.vieworg); } //////////////////////////////////////////////////////////////////////////////// diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 43550a41..4fc44980 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -260,6 +260,8 @@ float UpdateFlag(float isnew) { /* UpdateFlagOutline(self); */ + LocalEffects(self.effects, self.origin); + if (self.skin == team_no) { local float distance = vlen(self.origin - PM_Org()); self.alpha = min(0.25 + (distance / 200), 1); From f5d9d48e20cd29c8875137535c85ef2e4a6278ad Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 17 Oct 2024 00:59:35 +1100 Subject: [PATCH 2465/2474] Use a tracebox to simplify sentry location --- csqc/main.qc | 6 ++--- share/engineer.qc | 63 ++++++----------------------------------------- ssqc/engineer.qc | 2 +- 3 files changed, 12 insertions(+), 59 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index dc431cb1..d7ced5da 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -230,7 +230,7 @@ void adjustEntityAboveGround(entity ent) { tracebox(startPos, ent.mins, ent.maxs, endPos, MOVE_NORMAL, ent); // Move the entity up to be 1 unit above the ground - ent.origin[2] = trace_endpos[2] - (ent.mins[2] - ent.maxs[2]) + 1; // 1 unit above the ground + ent.origin[2] = trace_endpos[2] + 1; // 1 unit above the ground } noref void(float width, float height, float menushown) CSQC_UpdateView = { @@ -265,7 +265,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { v_forward_sentry.y = xy_pos.y; sentry_preview.origin = PM_Org() + v_forward_sentry; - adjustEntityAboveGround(sentry_preview); + /* adjustEntityAboveGround(sentry_preview); */ sentry_preview_range_sphere.origin = sentry_preview.origin; sentry_preview.angles_y = anglemod(view_angles_y + sentry_preview_offset); } else { @@ -879,7 +879,7 @@ void _Sync_ServerCommandFrame() { if (previewing_sentry) { if (game_state.is_alive) { - sentry_fits = CheckArea(sentry_preview, player_localentnum); + sentry_fits = CheckArea(sentry_preview, edict_num(player_localentnum)); sentry_preview.colormod = sentry_fits ? '1 1 1' : '0.5 0.2 0.2'; } else { SentryPreviewStop(); diff --git a/share/engineer.qc b/share/engineer.qc index 0bb2e0b1..04cbd525 100644 --- a/share/engineer.qc +++ b/share/engineer.qc @@ -1,59 +1,12 @@ -float (entity obj, float builder) CheckArea = { - local vector src; - local vector end; - local float pos; - local entity te; +float (entity obj, entity builder) CheckArea = { + vector start, end; + start = obj.origin; + end = start; + tracebox(start, obj.mins, obj.maxs, end, MOVE_NORMAL, builder); - pos = pointcontents(obj.origin); - if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { + if (trace_inopen) { + return (1); + } else { return (0); } - src_x = (obj.origin_x) + 24; - src_y = (obj.origin_y) + 24; - src_z = (obj.origin_z); - pos = pointcontents(src); - if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { - return (0); - } - end_x = (obj.origin_x) - 16; - end_y = (obj.origin_y) - 16; - end_z = (obj.origin_z); - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { - return (0); - } - src_x = (obj.origin_x) - 16; - src_y = (obj.origin_y) + 16; - src_z = (obj.origin_z); - pos = pointcontents(src); - if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { - return (0); - } - end_x = (obj.origin_x) + 16; - end_y = (obj.origin_y) - 16; - end_z = (obj.origin_z); - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == CONTENT_SOLID) || (pos == CONTENT_SKY)) { - return (0); - } - /* traceline(builder.origin, obj.origin, 1, builder); */ - /* if (trace_fraction != 1) { */ - /* return (0); */ - /* } */ - - te = findradius(obj.origin, 64); - if (te != world) { - if !(te.movetype == MOVETYPE_WALK && builder && num_for_edict(te.owner) == builder) { - return (0); - } - } - return (1); }; diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index b3e83dc4..4d71d9d1 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -612,7 +612,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { self.sentry_ticks = 0; } - if (!CheckArea(newmis, 0)) { + if (!CheckArea(newmis, self)) { sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; From 6a1753a34be0cbd3dee287deb215784399cc39e5 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 17 Oct 2024 20:30:44 +1100 Subject: [PATCH 2466/2474] Make building more flexible --- csqc/main.qc | 98 +++++++++++++++++++++-------------------------- share/engineer.qc | 28 +++++++++----- ssqc/engineer.qc | 2 +- 3 files changed, 63 insertions(+), 65 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index d7ced5da..522be676 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -219,18 +219,38 @@ void PMD_DrawGraphs(float width); DEFCVAR_FLOAT(fov, 90); -void adjustEntityAboveGround(entity ent) { - vector startPos, endPos; +void SentryPreviewStart() { + sentry_preview_offset = 0; + sentry_preview.angles_y = input_angles_y; + sentry_preview.drawmask = MASK_ENGINE; + + local vector sphere_colormod = '1 1 1'; + switch (team_no) { + case 1: + sphere_colormod = '0 0.4 1'; + break; + case 2: + sphere_colormod = '1 0 0'; + break; + case 3: + sphere_colormod = '1 1 0'; + break; + case 4: + sphere_colormod = '0 1 0'; + break; + } - // Define start and end points for the trace downwards - startPos = ent.origin + '0 0 100'; // Start 100 units above the entity's origin - endPos = ent.origin - '0 0 1000'; // Trace downwards a sufficient distance + sentry_preview_range_sphere.colormod = sphere_colormod * 4; + sentry_preview_range_sphere.drawmask = MASK_ENGINE; - // Perform the tracebox from startPos to endPos - tracebox(startPos, ent.mins, ent.maxs, endPos, MOVE_NORMAL, ent); + previewing_sentry = TRUE; + prevent_firing = TRUE; +} - // Move the entity up to be 1 unit above the ground - ent.origin[2] = trace_endpos[2] + 1; // 1 unit above the ground +void SentryPreviewStop() { + previewing_sentry = FALSE; + sentry_preview.drawmask = 0; + sentry_preview_range_sphere.drawmask = 0; } noref void(float width, float height, float menushown) CSQC_UpdateView = { @@ -256,6 +276,16 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { PM_UpdateView(); if (previewing_sentry) { + if (game_state.is_alive) { + } else { + } + } + + if (previewing_sentry) { + if (!game_state.is_alive) { + SentryPreviewStop(); + } else { + } makevectors(view_angles); local vector v_forward_sentry; v_forward_sentry.z = (normalize(v_forward) * 64).z; @@ -265,7 +295,8 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { v_forward_sentry.y = xy_pos.y; sentry_preview.origin = PM_Org() + v_forward_sentry; - /* adjustEntityAboveGround(sentry_preview); */ + sentry_fits = PlaceSentry(sentry_preview, PM_Org()); + sentry_preview.colormod = sentry_fits ? '1 1 1' : '0.5 0.2 0.2'; sentry_preview_range_sphere.origin = sentry_preview.origin; sentry_preview.angles_y = anglemod(view_angles_y + sentry_preview_offset); } else { @@ -320,7 +351,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } else { localcmd("cmd sentry rotate 15\n"); } - break; + break; } break; case "specialdown": @@ -331,7 +362,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { } else { localcmd("cmd sentry rotate -15\n"); } - break; + break; } break; case "+slot": @@ -718,40 +749,6 @@ void FO_ApplyCussInput() { void PM_InputFrame(); -void SentryPreviewStart() { - sentry_preview_offset = 0; - sentry_preview.angles_y = input_angles_y; - sentry_preview.drawmask = MASK_ENGINE; - - local vector sphere_colormod = '1 1 1'; - switch (team_no) { - case 1: - sphere_colormod = '0 0.4 1'; - break; - case 2: - sphere_colormod = '1 0 0'; - break; - case 3: - sphere_colormod = '1 1 0'; - break; - case 4: - sphere_colormod = '0 1 0'; - break; - } - - sentry_preview_range_sphere.colormod = sphere_colormod * 4; - sentry_preview_range_sphere.drawmask = MASK_ENGINE; - - previewing_sentry = TRUE; - prevent_firing = TRUE; -} - -void SentryPreviewStop() { - previewing_sentry = FALSE; - sentry_preview.drawmask = 0; - sentry_preview_range_sphere.drawmask = 0; -} - noref void CSQC_Input_Frame() { local float changed_buttons = input_buttons ^ oldbuttons; oldbuttons = input_buttons; @@ -876,15 +873,6 @@ void _Sync_ServerCommandFrame() { CsGrenTimer::UpdateSoundStack(); UpdateTeamColorCrosshair(); - - if (previewing_sentry) { - if (game_state.is_alive) { - sentry_fits = CheckArea(sentry_preview, edict_num(player_localentnum)); - sentry_preview.colormod = sentry_fits ? '1 1 1' : '0.5 0.2 0.2'; - } else { - SentryPreviewStop(); - } - } } diff --git a/share/engineer.qc b/share/engineer.qc index 04cbd525..01bb7083 100644 --- a/share/engineer.qc +++ b/share/engineer.qc @@ -1,12 +1,22 @@ -float (entity obj, entity builder) CheckArea = { - vector start, end; - start = obj.origin; - end = start; - tracebox(start, obj.mins, obj.maxs, end, MOVE_NORMAL, builder); +float PlaceSentry(entity sentry, vector builder_org) { + tracebox(sentry.origin, sentry.mins, sentry.maxs, sentry.origin, MOVE_NORMAL, sentry); - if (trace_inopen) { + if (trace_inopen) return (1); - } else { - return (0); + + local vector start = sentry.origin; + start_z = builder_org_z + 64; + + tracebox(start, sentry.mins, sentry.maxs, sentry.origin, MOVE_NORMAL, sentry); + + if (trace_fraction < 1.0) { + tracebox(trace_endpos, sentry.mins, sentry.maxs, trace_endpos, MOVE_NORMAL, sentry); + + if (trace_inopen) { + sentry.origin = trace_endpos; + return (1); + } } -}; + + return (0); +} diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 4d71d9d1..0a8b3bac 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -612,7 +612,7 @@ void (float objtobuild, float offset) TeamFortress_Build = { self.sentry_ticks = 0; } - if (!CheckArea(newmis, self)) { + if (!PlaceSentry(newmis, self.origin)) { sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; From 83004244675e5cf082280159803ac874d544c818 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 17 Oct 2024 23:30:55 +1100 Subject: [PATCH 2467/2474] Smooth rotation with high ping --- csqc/main.qc | 8 ++++++-- csqc/tfx.qc | 17 +++++++++++++++++ ssqc/commands.qc | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 522be676..1491b876 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -349,7 +349,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { if (previewing_sentry) { sentry_preview_offset = anglemod(sentry_preview_offset - 15); } else { - localcmd("cmd sentry rotate 15\n"); + update_sentry_angles = time + 0.5; + sentry_angles_y = anglemod(sentry_angles_y - 15); + localcmd(sprintf("cmd sentry angle %f\n", sentry_angles_y)); } break; } @@ -360,7 +362,9 @@ noref float(string cmd) CSQC_ConsoleCommand = { if (previewing_sentry) { sentry_preview_offset = anglemod(sentry_preview_offset + 15); } else { - localcmd("cmd sentry rotate -15\n"); + update_sentry_angles = time + 0.5; + sentry_angles_y = anglemod(sentry_angles_y + 15); + localcmd(sprintf("cmd sentry angle %f\n", sentry_angles_y)); } break; } diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 1de72c02..14fc90ee 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -3,6 +3,8 @@ .float teamno; static entity local_player; static float shader_team[2], shader_flag, shader_over_outline; +float update_sentry_angles; +float sentry_angles_y; enum { TeamNone = 0, @@ -263,6 +265,20 @@ float UpdateFlag(float isnew) { return TRUE; } +float UpdateTurret(float isnew) { + if (isnew) { + sentry_angles_y = self.angles_y; + } else { + if (update_sentry_angles > time) { + self.angles_y = sentry_angles_y; + } else { + sentry_angles_y = self.angles_y; + } + } + + return TRUE; +} + void TFxGrenTimerUpdate(float ent_num, float expiry) { EntHash* he = EntGet(ent_num); he->grentimer_expires = expiry; @@ -309,4 +325,5 @@ void TF_Init() { shader_over_outline = shaderforname(rnds("over_outline"), "{ sort 7 }"); #endif + deltalisten("progs/turrgun.mdl", UpdateTurret, 0); } diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a5920c68..b705dc0c 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -771,6 +771,24 @@ float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { } ent.nextthink = time + 0.5; break; + } else if (arg2 == "angle") { + farg3 = stof(arg3); + if (!ent.real_owner.has_sentry || ent.real_owner != self + || self.classname != "player" || ent == world) { + sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); + break; + } + ent.angles_y = farg3; + ent.waitmin = rint(ent.angles_y - 50); + ent.waitmin = anglemod(ent.waitmin); + ent.waitmax = rint(ent.angles_y + 50); + ent.waitmax = anglemod(ent.waitmax); + if (ent.waitmin > ent.waitmax) { + ent.waitmin = ent.waitmax; + ent.waitmax = anglemod(ent.angles_y - 50); + } + ent.nextthink = time + 0.5; + break; } sprint(self, PRINT_HIGH, "Invalid choice.\n"); } else { From 6d6b301d77031fcd08dbb71527481d8685ba0650 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 17 Oct 2024 23:51:41 +1100 Subject: [PATCH 2468/2474] Handle rotating sentry base --- csqc/tfx.qc | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 14fc90ee..c69366ee 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -265,7 +265,7 @@ float UpdateFlag(float isnew) { return TRUE; } -float UpdateTurret(float isnew) { +float UpdateSentry(float isnew) { if (isnew) { sentry_angles_y = self.angles_y; } else { @@ -279,6 +279,22 @@ float UpdateTurret(float isnew) { return TRUE; } +float UpdateSentryBase(float isnew) { + if (isnew) { + sentry_angles_y = self.angles_y; + } else { + if (!SBAR.SentryLevel && SBAR.IsBuilding) { + if (update_sentry_angles > time) { + self.angles_y = sentry_angles_y; + } else { + sentry_angles_y = self.angles_y; + } + } + } + + return TRUE; +} + void TFxGrenTimerUpdate(float ent_num, float expiry) { EntHash* he = EntGet(ent_num); he->grentimer_expires = expiry; @@ -325,5 +341,6 @@ void TF_Init() { shader_over_outline = shaderforname(rnds("over_outline"), "{ sort 7 }"); #endif - deltalisten("progs/turrgun.mdl", UpdateTurret, 0); + deltalisten("progs/turrgun.mdl", UpdateSentry, 0); + deltalisten("progs/turrbase.mdl", UpdateSentryBase, 0); } From 83f58ab8f71296049d7771957538db3eb7f3be4d Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Fri, 18 Oct 2024 00:15:58 +1100 Subject: [PATCH 2469/2474] Don't allow client side rotation when not in range --- csqc/main.qc | 8 ++++---- ssqc/engineer.qc | 17 +++++------------ ssqc/status.qc | 12 ++++++++++++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/csqc/main.qc b/csqc/main.qc index 1491b876..eef59b32 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -348,8 +348,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { case PC_ENGINEER: if (previewing_sentry) { sentry_preview_offset = anglemod(sentry_preview_offset - 15); - } else { - update_sentry_angles = time + 0.5; + } else if (vlen(PM_Org() - sentry_pos) < ENG_BUILDING_DISMANTLE_DISTANCE) { + update_sentry_angles = time + 0.55; sentry_angles_y = anglemod(sentry_angles_y - 15); localcmd(sprintf("cmd sentry angle %f\n", sentry_angles_y)); } @@ -361,8 +361,8 @@ noref float(string cmd) CSQC_ConsoleCommand = { case PC_ENGINEER: if (previewing_sentry) { sentry_preview_offset = anglemod(sentry_preview_offset + 15); - } else { - update_sentry_angles = time + 0.5; + } else if (vlen(PM_Org() - sentry_pos) < ENG_BUILDING_DISMANTLE_DISTANCE) { + update_sentry_angles = time + 0.55; sentry_angles_y = anglemod(sentry_angles_y + 15); localcmd(sprintf("cmd sentry angle %f\n", sentry_angles_y)); } diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 0a8b3bac..0337e170 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -626,6 +626,11 @@ void (float objtobuild, float offset) TeamFortress_Build = { } UpdateClientBuilding(self); + + if (objtobuild == BUILD_SENTRYGUN) { + UpdateClient_Sentry(self, newmis); + } + self.is_building = objtobuild; if (!engineer_move) { self.immune_to_check = time + 5; @@ -929,18 +934,6 @@ void () DispenserThink = { self.nextthink = time + 0.3; }; -void UpdateClient_Sentry(entity pl, entity sent) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_SENTRY_POS); - WriteFloat(MSG_MULTICAST, sent.origin.x); - WriteFloat(MSG_MULTICAST, sent.origin.y); - WriteFloat(MSG_MULTICAST, sent.origin.z); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - void UpdateClient_Dispenser(entity pl, entity disp) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; diff --git a/ssqc/status.qc b/ssqc/status.qc index ed822338..26ba4705 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -767,6 +767,18 @@ void UpdateClientBuilding(entity pl) { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } +void UpdateClient_Sentry(entity pl, entity sent) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_SENTRY_POS); + WriteFloat(MSG_MULTICAST, sent.origin.x); + WriteFloat(MSG_MULTICAST, sent.origin.y); + WriteFloat(MSG_MULTICAST, sent.origin.z); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientReloadSound(entity pl, float weapon) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; From 4d9e7b751eee20f872cae1fe7597254497d7e65a Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 31 Oct 2024 20:54:42 +1100 Subject: [PATCH 2470/2474] Put a gren back in packs --- ssqc/client.qc | 2 -- ssqc/tfort.qc | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 5021fc08..533989f5 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -289,8 +289,6 @@ static float NB_UseMinPing() { void ActivateOrgGame() { disable_resup_gren = 2; // No gren2 pickups - drop_gren1 = 0; // No grenades in backpacks - int i; for (i = 1; i <= 9; i++) // 3 gren spawn SetAllRoles(i, 1, 3); diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index d2b62474..dcd079d5 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -614,6 +614,7 @@ void () TeamFortress_ShowTF = { CF_PrintSetting("Old grenades", old_grens, "", 1); CF_PrintSetting("Drop grenades on ground", drop_grenades, "", 1); CF_PrintSetting("Drop grenades in pack", drop_grenpack, "", 1); + if (drop_grenpack) { CF_PrintSetting("- Grenades type 1", drop_gren1, "", 0); CF_PrintSetting("- Grenades type 2", drop_gren2, "", 0); From 41c2dddbe31dfa186cf3c7861b0859440020c0bb Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Thu, 31 Oct 2024 20:55:42 +1100 Subject: [PATCH 2471/2474] Detpipe cooldown only applies to last fired pipe --- ssqc/client.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssqc/client.qc b/ssqc/client.qc index 533989f5..385469c3 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -564,7 +564,7 @@ void () DecodeLevelParms = { pipecooldown_time = CF_GetSetting("pcdt", "pipecooldown_time", "0.5"); // cooldown applies to all pipes [on] - allpipes_cooldown = CF_GetSetting("apcd", "allpipes_cooldown", "on"); + allpipes_cooldown = CF_GetSetting("apcd", "allpipes_cooldown", "off"); // allow medic aura [on] medicaura = CF_GetSetting("ma", "medicaura", "on"); From 457ed6c0e67bdb20c333769f3db3568ebb029497 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 12 Nov 2024 19:36:10 +1100 Subject: [PATCH 2472/2474] Temp fix for sentry falling into world before proper fix --- ssqc/engineer.qc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 0337e170..7cea347b 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -612,6 +612,8 @@ void (float objtobuild, float offset) TeamFortress_Build = { self.sentry_ticks = 0; } + setsize(newmis, tmp1, tmp2); + if (!PlaceSentry(newmis, self.origin)) { sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); @@ -652,7 +654,6 @@ void (float objtobuild, float offset) TeamFortress_Build = { newmis.movetype = 6; newmis.solid = 2; FO_SetModel(newmis, newmis.mdl); - setsize(newmis, tmp1, tmp2); setorigin(newmis, newmis.origin); newmis.flags = newmis.flags - (newmis.flags & 512); From cdf011baf5b66b12fb825c5230176643783b019b Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 12 Nov 2024 20:11:04 +1100 Subject: [PATCH 2473/2474] fo_forward_facing_sentry option --- csqc/csextradefs.qc | 1 + csqc/main.qc | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index fa50037e..6e56721b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -867,6 +867,7 @@ struct { DEFCVAR_FLOAT(fo_fte_hud, 0); DEFCVAR_FLOAT(fo_legacy_sbar, 0); DEFCVAR_FLOAT(fo_csjumpsounds, 1); +DEFCVAR_FLOAT(fo_forward_facing_sentry, 0); struct GameState { float localentnum; diff --git a/csqc/main.qc b/csqc/main.qc index eef59b32..f6892653 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -220,7 +220,12 @@ void PMD_DrawGraphs(float width); DEFCVAR_FLOAT(fov, 90); void SentryPreviewStart() { - sentry_preview_offset = 0; + if (CVARF(fo_forward_facing_sentry)) { + sentry_preview_offset = 0; + } else { + sentry_preview_offset = 180; + } + sentry_preview.angles_y = input_angles_y; sentry_preview.drawmask = MASK_ENGINE; From 70ab88f1dc8524a226b85c8cac241a99a42798c4 Mon Sep 17 00:00:00 2001 From: Sheldon Johnson Date: Tue, 12 Nov 2024 20:16:01 +1100 Subject: [PATCH 2474/2474] Fix clockwise/anticlockwise --- csqc/menu.qc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csqc/menu.qc b/csqc/menu.qc index 9a546d4a..d901afae 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -324,9 +324,9 @@ var fo_menu FO_MENU_BUILD = { }; var fo_menu FO_MENU_SENTRY_MAINTAIN = { [0,0], [300,200], "Sentry Gun", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, /* {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, */ {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, @@ -340,9 +340,9 @@ var fo_menu FO_MENU_SENTRY_MAINTAIN = { var fo_menu FO_MENU_SENTRY_ROTATE = { [0,0], [300,200], "Rotate Sentry Gun", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, /* {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, */ {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON},